]> git.proxmox.com Git - qemu.git/commitdiff
Merge branch 'tcg-s390' of git://github.com/rth7680/qemu
authorAurelien Jarno <aurelien@aurel32.net>
Sat, 13 Apr 2013 11:49:20 +0000 (13:49 +0200)
committerAurelien Jarno <aurelien@aurel32.net>
Sat, 13 Apr 2013 11:49:20 +0000 (13:49 +0200)
* 'tcg-s390' of git://github.com/rth7680/qemu:
  tcg-s390: Fix merge error in tgen_brcond
  tcg-s390: Use all 20 bits of the offset in tcg_out_mem
  tcg-s390: Use load-address for addition
  tcg-s390: Cleanup argument shuffling fixme in softmmu code
  tcg-s390: Use risbgz for andi
  tcg-s390: Remove constraint letters for and
  tcg-s390: Implement deposit opcodes
  tcg-s390: Implement movcond opcodes
  tcg-s390: Implement mulu2_i64 opcode
  tcg-s390: Implement add2/sub2 opcodes
  tcg-s390: Remove useless preprocessor conditions
  tcg-s390: Properly allocate a stack frame.
  tcg-s390: Fix movi

1340 files changed:
MAINTAINERS
Makefile
Makefile.objs
arch_init.c
block.c
block/iscsi.c
block/qcow2-refcount.c
blockdev-nbd.c
blockdev.c
configure
default-configs/alpha-softmmu.mak
default-configs/arm-softmmu.mak
default-configs/cris-softmmu.mak
default-configs/i386-softmmu.mak
default-configs/lm32-softmmu.mak
default-configs/m68k-softmmu.mak
default-configs/microblaze-softmmu.mak
default-configs/microblazeel-softmmu.mak
default-configs/mips-softmmu.mak
default-configs/mips64-softmmu.mak
default-configs/mips64el-softmmu.mak
default-configs/mipsel-softmmu.mak
default-configs/moxie-softmmu.mak
default-configs/pci.mak
default-configs/ppc-softmmu.mak
default-configs/ppc64-softmmu.mak
default-configs/ppcemb-softmmu.mak
default-configs/s390x-softmmu.mak
default-configs/sh4-softmmu.mak
default-configs/sh4eb-softmmu.mak
default-configs/sparc-softmmu.mak
default-configs/sparc64-softmmu.mak
default-configs/x86_64-softmmu.mak
docs/usb2.txt
exec.c
gdbstub.c
hw/9pfs/virtio-9p-device.c
hw/9pfs/virtio-9p-device.h [deleted file]
hw/9pfs/virtio-9p-handle.c
hw/9pfs/virtio-9p-local.c
hw/9pfs/virtio-9p-posix-acl.c
hw/9pfs/virtio-9p-proxy.c
hw/9pfs/virtio-9p-synth.c
hw/9pfs/virtio-9p-xattr-user.c
hw/9pfs/virtio-9p-xattr.c
hw/9pfs/virtio-9p.c
hw/9pfs/virtio-9p.h
hw/Makefile.objs
hw/a15mpcore.c [deleted file]
hw/a9mpcore.c [deleted file]
hw/a9scu.c [deleted file]
hw/ac97.c [deleted file]
hw/acpi.c [deleted file]
hw/acpi.h [deleted file]
hw/acpi/Makefile.objs [new file with mode: 0644]
hw/acpi/core.c [new file with mode: 0644]
hw/acpi/ich9.c [new file with mode: 0644]
hw/acpi/piix4.c [new file with mode: 0644]
hw/acpi_ich9.c [deleted file]
hw/acpi_ich9.h [deleted file]
hw/acpi_piix4.c [deleted file]
hw/adb.c [deleted file]
hw/adb.h [deleted file]
hw/adlib.c [deleted file]
hw/ads7846.c [deleted file]
hw/alpha/Makefile.objs
hw/alpha/alpha_sys.h [new file with mode: 0644]
hw/alpha/dp264.c
hw/alpha/pci.c
hw/alpha/typhoon.c [new file with mode: 0644]
hw/alpha_sys.h [deleted file]
hw/alpha_typhoon.c [deleted file]
hw/apb_pci.c [deleted file]
hw/apb_pci.h [deleted file]
hw/apic-msidef.h [deleted file]
hw/apic.c [deleted file]
hw/apic.h [deleted file]
hw/apic_common.c [deleted file]
hw/apic_internal.h [deleted file]
hw/apm.c [deleted file]
hw/apm.h [deleted file]
hw/applesmc.c [deleted file]
hw/arm-misc.h [deleted file]
hw/arm/Makefile.objs
hw/arm/armv7m.c
hw/arm/boot.c
hw/arm/collie.c
hw/arm/exynos4210.c
hw/arm/exynos4_boards.c
hw/arm/gumstix.c
hw/arm/highbank.c
hw/arm/integratorcp.c
hw/arm/kzm.c
hw/arm/mainstone.c
hw/arm/musicpal.c
hw/arm/nseries.c
hw/arm/omap1.c
hw/arm/omap2.c
hw/arm/omap_sx1.c
hw/arm/palm.c
hw/arm/pic_cpu.c
hw/arm/pxa2xx.c
hw/arm/pxa2xx_gpio.c
hw/arm/pxa2xx_pic.c
hw/arm/realview.c
hw/arm/spitz.c
hw/arm/stellaris.c
hw/arm/strongarm.c [new file with mode: 0644]
hw/arm/strongarm.h [new file with mode: 0644]
hw/arm/tosa.c
hw/arm/versatilepb.c
hw/arm/vexpress.c
hw/arm/xilinx_zynq.c
hw/arm/z2.c
hw/arm11mpcore.c [deleted file]
hw/arm_gic.c [deleted file]
hw/arm_gic_common.c [deleted file]
hw/arm_gic_internal.h [deleted file]
hw/arm_l2x0.c [deleted file]
hw/arm_mptimer.c [deleted file]
hw/arm_sysctl.c [deleted file]
hw/arm_timer.c [deleted file]
hw/armv7m_nvic.c [deleted file]
hw/audio/Makefile.objs [new file with mode: 0644]
hw/audio/ac97.c [new file with mode: 0644]
hw/audio/adlib.c [new file with mode: 0644]
hw/audio/cs4231.c [new file with mode: 0644]
hw/audio/cs4231a.c [new file with mode: 0644]
hw/audio/es1370.c [new file with mode: 0644]
hw/audio/fmopl.c [new file with mode: 0644]
hw/audio/fmopl.h [new file with mode: 0644]
hw/audio/gus.c [new file with mode: 0644]
hw/audio/gusemu.h [new file with mode: 0644]
hw/audio/gusemu_hal.c [new file with mode: 0644]
hw/audio/gusemu_mixer.c [new file with mode: 0644]
hw/audio/gustate.h [new file with mode: 0644]
hw/audio/hda-codec.c [new file with mode: 0644]
hw/audio/intel-hda-defs.h [new file with mode: 0644]
hw/audio/intel-hda.c [new file with mode: 0644]
hw/audio/intel-hda.h [new file with mode: 0644]
hw/audio/lm4549.c [new file with mode: 0644]
hw/audio/lm4549.h [new file with mode: 0644]
hw/audio/marvell_88w8618.c [new file with mode: 0644]
hw/audio/milkymist-ac97.c [new file with mode: 0644]
hw/audio/pcspk.c [new file with mode: 0644]
hw/audio/pl041.c [new file with mode: 0644]
hw/audio/pl041.h [new file with mode: 0644]
hw/audio/pl041.hx [new file with mode: 0644]
hw/audio/sb16.c [new file with mode: 0644]
hw/audio/wm8750.c [new file with mode: 0644]
hw/audiodev.h [deleted file]
hw/bitbang_i2c.c [deleted file]
hw/bitbang_i2c.h [deleted file]
hw/blizzard.c [deleted file]
hw/blizzard_template.h [deleted file]
hw/block-common.c [deleted file]
hw/block-common.h [deleted file]
hw/block/Makefile.objs [new file with mode: 0644]
hw/block/block.c [new file with mode: 0644]
hw/block/cdrom.c [new file with mode: 0644]
hw/block/dataplane/Makefile.objs [new file with mode: 0644]
hw/block/dataplane/ioq.c [new file with mode: 0644]
hw/block/dataplane/ioq.h [new file with mode: 0644]
hw/block/dataplane/virtio-blk.c [new file with mode: 0644]
hw/block/dataplane/virtio-blk.h [new file with mode: 0644]
hw/block/ecc.c [new file with mode: 0644]
hw/block/fdc.c [new file with mode: 0644]
hw/block/hd-geometry.c [new file with mode: 0644]
hw/block/m25p80.c [new file with mode: 0644]
hw/block/nand.c [new file with mode: 0644]
hw/block/onenand.c [new file with mode: 0644]
hw/block/pc_sysfw.c [new file with mode: 0644]
hw/block/pflash_cfi01.c [new file with mode: 0644]
hw/block/pflash_cfi02.c [new file with mode: 0644]
hw/block/tc58128.c [new file with mode: 0644]
hw/block/virtio-blk.c [new file with mode: 0644]
hw/block/xen_blkif.h [new file with mode: 0644]
hw/block/xen_disk.c [new file with mode: 0644]
hw/boards.h [deleted file]
hw/bonito.c [deleted file]
hw/bt-hci-csr.c [deleted file]
hw/bt-hci.c [deleted file]
hw/bt-hid.c [deleted file]
hw/bt-l2cap.c [deleted file]
hw/bt-sdp.c [deleted file]
hw/bt.c [deleted file]
hw/bt.h [deleted file]
hw/bt/Makefile.objs [new file with mode: 0644]
hw/bt/core.c [new file with mode: 0644]
hw/bt/hci-csr.c [new file with mode: 0644]
hw/bt/hci.c [new file with mode: 0644]
hw/bt/hid.c [new file with mode: 0644]
hw/bt/l2cap.c [new file with mode: 0644]
hw/bt/sdp.c [new file with mode: 0644]
hw/cadence_gem.c [deleted file]
hw/cadence_ttc.c [deleted file]
hw/cadence_uart.c [deleted file]
hw/cbus.c [deleted file]
hw/ccid-card-emulated.c [deleted file]
hw/ccid-card-passthru.c [deleted file]
hw/ccid.h [deleted file]
hw/cdrom.c [deleted file]
hw/char/Makefile.objs [new file with mode: 0644]
hw/char/cadence_uart.c [new file with mode: 0644]
hw/char/debugcon.c [new file with mode: 0644]
hw/char/escc.c [new file with mode: 0644]
hw/char/etraxfs_ser.c [new file with mode: 0644]
hw/char/exynos4210_uart.c [new file with mode: 0644]
hw/char/grlib_apbuart.c [new file with mode: 0644]
hw/char/imx_serial.c [new file with mode: 0644]
hw/char/ipack.c [new file with mode: 0644]
hw/char/ipack.h [new file with mode: 0644]
hw/char/ipoctal232.c [new file with mode: 0644]
hw/char/lm32_juart.c [new file with mode: 0644]
hw/char/lm32_uart.c [new file with mode: 0644]
hw/char/mcf_uart.c [new file with mode: 0644]
hw/char/milkymist-uart.c [new file with mode: 0644]
hw/char/omap_uart.c [new file with mode: 0644]
hw/char/parallel.c [new file with mode: 0644]
hw/char/pl011.c [new file with mode: 0644]
hw/char/sclpconsole.c [new file with mode: 0644]
hw/char/serial-isa.c [new file with mode: 0644]
hw/char/serial-pci.c [new file with mode: 0644]
hw/char/serial.c [new file with mode: 0644]
hw/char/sh_serial.c [new file with mode: 0644]
hw/char/spapr_vty.c [new file with mode: 0644]
hw/char/tpci200.c [new file with mode: 0644]
hw/char/virtio-console.c [new file with mode: 0644]
hw/char/virtio-serial-bus.c [new file with mode: 0644]
hw/char/xen_console.c [new file with mode: 0644]
hw/char/xilinx_uartlite.c [new file with mode: 0644]
hw/cirrus_vga.c [deleted file]
hw/cirrus_vga_rop.h [deleted file]
hw/cirrus_vga_rop2.h [deleted file]
hw/cirrus_vga_template.h [deleted file]
hw/core/Makefile.objs [new file with mode: 0644]
hw/core/empty_slot.c [new file with mode: 0644]
hw/core/irq.c [new file with mode: 0644]
hw/core/loader.c [new file with mode: 0644]
hw/core/null-machine.c [new file with mode: 0644]
hw/core/ptimer.c [new file with mode: 0644]
hw/core/qdev-addr.c [new file with mode: 0644]
hw/core/qdev-properties-system.c [new file with mode: 0644]
hw/core/qdev-properties.c [new file with mode: 0644]
hw/core/qdev.c [new file with mode: 0644]
hw/core/stream.c [new file with mode: 0644]
hw/core/sysbus.c [new file with mode: 0644]
hw/core/uboot_image.h [new file with mode: 0644]
hw/cpu/Makefile.objs [new file with mode: 0644]
hw/cpu/a15mpcore.c [new file with mode: 0644]
hw/cpu/a9mpcore.c [new file with mode: 0644]
hw/cpu/arm11mpcore.c [new file with mode: 0644]
hw/cris-boot.h [deleted file]
hw/cris/Makefile.objs
hw/cris/axis_dev88.c
hw/cris/boot.c
hw/cris/boot.h [new file with mode: 0644]
hw/cris/pic_cpu.c
hw/cs4231.c [deleted file]
hw/cs4231a.c [deleted file]
hw/cuda.c [deleted file]
hw/dataplane/Makefile.objs [deleted file]
hw/dataplane/hostmem.c [deleted file]
hw/dataplane/hostmem.h [deleted file]
hw/dataplane/ioq.c [deleted file]
hw/dataplane/ioq.h [deleted file]
hw/dataplane/virtio-blk.c [deleted file]
hw/dataplane/virtio-blk.h [deleted file]
hw/dataplane/vring.c [deleted file]
hw/dataplane/vring.h [deleted file]
hw/debugcon.c [deleted file]
hw/debugexit.c [deleted file]
hw/dec_pci.c [deleted file]
hw/dec_pci.h [deleted file]
hw/devices.h [deleted file]
hw/display/Makefile.objs [new file with mode: 0644]
hw/display/ads7846.c [new file with mode: 0644]
hw/display/blizzard.c [new file with mode: 0644]
hw/display/blizzard_template.h [new file with mode: 0644]
hw/display/cirrus_vga.c [new file with mode: 0644]
hw/display/cirrus_vga_rop.h [new file with mode: 0644]
hw/display/cirrus_vga_rop2.h [new file with mode: 0644]
hw/display/cirrus_vga_template.h [new file with mode: 0644]
hw/display/exynos4210_fimd.c [new file with mode: 0644]
hw/display/framebuffer.c [new file with mode: 0644]
hw/display/framebuffer.h [new file with mode: 0644]
hw/display/g364fb.c [new file with mode: 0644]
hw/display/jazz_led.c [new file with mode: 0644]
hw/display/milkymist-tmu2.c [new file with mode: 0644]
hw/display/milkymist-vgafb.c [new file with mode: 0644]
hw/display/milkymist-vgafb_template.h [new file with mode: 0644]
hw/display/omap_dss.c [new file with mode: 0644]
hw/display/omap_lcd_template.h [new file with mode: 0644]
hw/display/omap_lcdc.c [new file with mode: 0644]
hw/display/pl110.c [new file with mode: 0644]
hw/display/pl110_template.h [new file with mode: 0644]
hw/display/pxa2xx_lcd.c [new file with mode: 0644]
hw/display/pxa2xx_template.h [new file with mode: 0644]
hw/display/qxl-logger.c [new file with mode: 0644]
hw/display/qxl-render.c [new file with mode: 0644]
hw/display/qxl.c [new file with mode: 0644]
hw/display/qxl.h [new file with mode: 0644]
hw/display/sm501.c [new file with mode: 0644]
hw/display/sm501_template.h [new file with mode: 0644]
hw/display/ssd0303.c [new file with mode: 0644]
hw/display/ssd0323.c [new file with mode: 0644]
hw/display/tc6393xb.c [new file with mode: 0644]
hw/display/tc6393xb_template.h [new file with mode: 0644]
hw/display/tcx.c [new file with mode: 0644]
hw/display/vga-isa-mm.c [new file with mode: 0644]
hw/display/vga-isa.c [new file with mode: 0644]
hw/display/vga-pci.c [new file with mode: 0644]
hw/display/vga.c [new file with mode: 0644]
hw/display/vga.h [new file with mode: 0644]
hw/display/vga_int.h [new file with mode: 0644]
hw/display/vga_template.h [new file with mode: 0644]
hw/display/vmware_vga.c [new file with mode: 0644]
hw/display/xenfb.c [new file with mode: 0644]
hw/dma.c [deleted file]
hw/dma/Makefile.objs [new file with mode: 0644]
hw/dma/etraxfs_dma.c [new file with mode: 0644]
hw/dma/i82374.c [new file with mode: 0644]
hw/dma/i8257.c [new file with mode: 0644]
hw/dma/omap_dma.c [new file with mode: 0644]
hw/dma/pl080.c [new file with mode: 0644]
hw/dma/pl330.c [new file with mode: 0644]
hw/dma/puv3_dma.c [new file with mode: 0644]
hw/dma/pxa2xx_dma.c [new file with mode: 0644]
hw/dma/rc4030.c [new file with mode: 0644]
hw/dma/soc_dma.c [new file with mode: 0644]
hw/dma/sparc32_dma.c [new file with mode: 0644]
hw/dma/sun4m_iommu.c [new file with mode: 0644]
hw/dma/xilinx_axidma.c [new file with mode: 0644]
hw/dp8393x.c [deleted file]
hw/ds1225y.c [deleted file]
hw/ds1338.c [deleted file]
hw/e1000.c [deleted file]
hw/e1000_hw.h [deleted file]
hw/ecc.c [deleted file]
hw/eccmemctl.c [deleted file]
hw/eepro100.c [deleted file]
hw/eeprom93xx.c [deleted file]
hw/eeprom93xx.h [deleted file]
hw/elf_ops.h [deleted file]
hw/empty_slot.c [deleted file]
hw/empty_slot.h [deleted file]
hw/es1370.c [deleted file]
hw/escc.c [deleted file]
hw/escc.h [deleted file]
hw/esp-pci.c [deleted file]
hw/esp.c [deleted file]
hw/esp.h [deleted file]
hw/etraxfs.h [deleted file]
hw/etraxfs_dma.c [deleted file]
hw/etraxfs_dma.h [deleted file]
hw/etraxfs_eth.c [deleted file]
hw/etraxfs_pic.c [deleted file]
hw/etraxfs_ser.c [deleted file]
hw/etraxfs_timer.c [deleted file]
hw/exynos4210.h [deleted file]
hw/exynos4210_combiner.c [deleted file]
hw/exynos4210_fimd.c [deleted file]
hw/exynos4210_gic.c [deleted file]
hw/exynos4210_i2c.c [deleted file]
hw/exynos4210_mct.c [deleted file]
hw/exynos4210_pmu.c [deleted file]
hw/exynos4210_pwm.c [deleted file]
hw/exynos4210_rtc.c [deleted file]
hw/exynos4210_uart.c [deleted file]
hw/fdc.c [deleted file]
hw/fdc.h [deleted file]
hw/firmware_abi.h [deleted file]
hw/flash.h [deleted file]
hw/fmopl.c [deleted file]
hw/fmopl.h [deleted file]
hw/framebuffer.c [deleted file]
hw/framebuffer.h [deleted file]
hw/fw_cfg.c [deleted file]
hw/fw_cfg.h [deleted file]
hw/g364fb.c [deleted file]
hw/gpio/Makefile.objs [new file with mode: 0644]
hw/gpio/max7310.c [new file with mode: 0644]
hw/gpio/omap_gpio.c [new file with mode: 0644]
hw/gpio/pl061.c [new file with mode: 0644]
hw/gpio/puv3_gpio.c [new file with mode: 0644]
hw/gpio/zaurus.c [new file with mode: 0644]
hw/grackle_pci.c [deleted file]
hw/grlib.h [deleted file]
hw/grlib_apbuart.c [deleted file]
hw/grlib_gptimer.c [deleted file]
hw/grlib_irqmp.c [deleted file]
hw/gt64xxx.c [deleted file]
hw/gus.c [deleted file]
hw/gusemu.h [deleted file]
hw/gusemu_hal.c [deleted file]
hw/gusemu_mixer.c [deleted file]
hw/gustate.h [deleted file]
hw/hd-geometry.c [deleted file]
hw/hda-audio.c [deleted file]
hw/heathrow_pic.c [deleted file]
hw/hid.c [deleted file]
hw/hid.h [deleted file]
hw/hpet.c [deleted file]
hw/hpet_emul.h [deleted file]
hw/hw.h [deleted file]
hw/i2c.c [deleted file]
hw/i2c.h [deleted file]
hw/i2c/Makefile.objs [new file with mode: 0644]
hw/i2c/bitbang_i2c.c [new file with mode: 0644]
hw/i2c/bitbang_i2c.h [new file with mode: 0644]
hw/i2c/core.c [new file with mode: 0644]
hw/i2c/exynos4210_i2c.c [new file with mode: 0644]
hw/i2c/omap_i2c.c [new file with mode: 0644]
hw/i2c/pm_smbus.c [new file with mode: 0644]
hw/i2c/smbus.c [new file with mode: 0644]
hw/i2c/smbus_eeprom.c [new file with mode: 0644]
hw/i2c/smbus_ich9.c [new file with mode: 0644]
hw/i2c/versatile_i2c.c [new file with mode: 0644]
hw/i386/Makefile.objs
hw/i386/kvm/Makefile.objs [new file with mode: 0644]
hw/i386/kvm/apic.c [new file with mode: 0644]
hw/i386/kvm/clock.c [new file with mode: 0644]
hw/i386/kvm/i8254.c [new file with mode: 0644]
hw/i386/kvm/i8259.c [new file with mode: 0644]
hw/i386/kvm/ioapic.c [new file with mode: 0644]
hw/i386/kvm/pci-assign.c [new file with mode: 0644]
hw/i386/kvmvapic.c
hw/i386/multiboot.c
hw/i386/multiboot.h [new file with mode: 0644]
hw/i386/pc.c
hw/i386/pc_piix.c
hw/i386/pc_q35.c
hw/i386/smbios.c
hw/i386/xen_domainbuild.c
hw/i386/xen_domainbuild.h [new file with mode: 0644]
hw/i386/xen_machine_pv.c
hw/i82374.c [deleted file]
hw/i82378.c [deleted file]
hw/i8254.c [deleted file]
hw/i8254.h [deleted file]
hw/i8254_common.c [deleted file]
hw/i8254_internal.h [deleted file]
hw/i8259.c [deleted file]
hw/i8259_common.c [deleted file]
hw/i8259_internal.h [deleted file]
hw/i82801b11.c [deleted file]
hw/ich9.h [deleted file]
hw/ide.h [deleted file]
hw/ide/Makefile.objs
hw/ide/ahci.c
hw/ide/atapi.c
hw/ide/cmd646.c
hw/ide/core.c
hw/ide/ich.c
hw/ide/internal.h
hw/ide/isa.c
hw/ide/macio.c
hw/ide/microdrive.c
hw/ide/pci.c
hw/ide/piix.c
hw/ide/qdev.c
hw/ide/via.c
hw/imx.h [deleted file]
hw/imx_avic.c [deleted file]
hw/imx_ccm.c [deleted file]
hw/imx_serial.c [deleted file]
hw/imx_timer.c [deleted file]
hw/input/Makefile.objs [new file with mode: 0644]
hw/input/adb.c [new file with mode: 0644]
hw/input/hid.c [new file with mode: 0644]
hw/input/lm832x.c [new file with mode: 0644]
hw/input/milkymist-softusb.c [new file with mode: 0644]
hw/input/pckbd.c [new file with mode: 0644]
hw/input/pl050.c [new file with mode: 0644]
hw/input/ps2.c [new file with mode: 0644]
hw/input/pxa2xx_keypad.c [new file with mode: 0644]
hw/input/stellaris_input.c [new file with mode: 0644]
hw/input/tsc2005.c [new file with mode: 0644]
hw/input/tsc210x.c [new file with mode: 0644]
hw/input/vmmouse.c [new file with mode: 0644]
hw/intc/Makefile.objs [new file with mode: 0644]
hw/intc/apic.c [new file with mode: 0644]
hw/intc/apic_common.c [new file with mode: 0644]
hw/intc/arm_gic.c [new file with mode: 0644]
hw/intc/arm_gic_common.c [new file with mode: 0644]
hw/intc/arm_gic_kvm.c [new file with mode: 0644]
hw/intc/armv7m_nvic.c [new file with mode: 0644]
hw/intc/etraxfs_pic.c [new file with mode: 0644]
hw/intc/exynos4210_combiner.c [new file with mode: 0644]
hw/intc/exynos4210_gic.c [new file with mode: 0644]
hw/intc/gic_internal.h [new file with mode: 0644]
hw/intc/grlib_irqmp.c [new file with mode: 0644]
hw/intc/heathrow_pic.c [new file with mode: 0644]
hw/intc/i8259.c [new file with mode: 0644]
hw/intc/i8259_common.c [new file with mode: 0644]
hw/intc/imx_avic.c [new file with mode: 0644]
hw/intc/ioapic.c [new file with mode: 0644]
hw/intc/ioapic_common.c [new file with mode: 0644]
hw/intc/lm32_pic.c [new file with mode: 0644]
hw/intc/omap_intc.c [new file with mode: 0644]
hw/intc/openpic.c [new file with mode: 0644]
hw/intc/pl190.c [new file with mode: 0644]
hw/intc/puv3_intc.c [new file with mode: 0644]
hw/intc/realview_gic.c [new file with mode: 0644]
hw/intc/sbi.c [new file with mode: 0644]
hw/intc/sh_intc.c [new file with mode: 0644]
hw/intc/slavio_intctl.c [new file with mode: 0644]
hw/intc/sun4c_intctl.c [new file with mode: 0644]
hw/intc/xilinx_intc.c [new file with mode: 0644]
hw/intel-hda-defs.h [deleted file]
hw/intel-hda.c [deleted file]
hw/intel-hda.h [deleted file]
hw/ioapic.c [deleted file]
hw/ioapic.h [deleted file]
hw/ioapic_common.c [deleted file]
hw/ioapic_internal.h [deleted file]
hw/ioh3420.c [deleted file]
hw/ioh3420.h [deleted file]
hw/ipack.c [deleted file]
hw/ipack.h [deleted file]
hw/ipoctal232.c [deleted file]
hw/irq.c [deleted file]
hw/irq.h [deleted file]
hw/isa-bus.c [deleted file]
hw/isa.h [deleted file]
hw/isa/Makefile.objs [new file with mode: 0644]
hw/isa/apm.c [new file with mode: 0644]
hw/isa/i82378.c [new file with mode: 0644]
hw/isa/isa-bus.c [new file with mode: 0644]
hw/isa/isa_mmio.c [new file with mode: 0644]
hw/isa/lpc_ich9.c [new file with mode: 0644]
hw/isa/pc87312.c [new file with mode: 0644]
hw/isa/piix4.c [new file with mode: 0644]
hw/isa/vt82c686.c [new file with mode: 0644]
hw/isa_mmio.c [deleted file]
hw/ivshmem.c [deleted file]
hw/jazz_led.c [deleted file]
hw/kvm/Makefile.objs [deleted file]
hw/kvm/apic.c [deleted file]
hw/kvm/arm_gic.c [deleted file]
hw/kvm/clock.c [deleted file]
hw/kvm/clock.h [deleted file]
hw/kvm/i8254.c [deleted file]
hw/kvm/i8259.c [deleted file]
hw/kvm/ioapic.c [deleted file]
hw/kvm/pci-assign.c [deleted file]
hw/lan9118.c [deleted file]
hw/lance.c [deleted file]
hw/lm32.h [deleted file]
hw/lm32/Makefile.objs
hw/lm32/lm32.h [new file with mode: 0644]
hw/lm32/lm32_boards.c
hw/lm32/lm32_hwsetup.h [new file with mode: 0644]
hw/lm32/milkymist-hw.h [new file with mode: 0644]
hw/lm32/milkymist.c
hw/lm32_hwsetup.h [deleted file]
hw/lm32_juart.c [deleted file]
hw/lm32_juart.h [deleted file]
hw/lm32_pic.c [deleted file]
hw/lm32_pic.h [deleted file]
hw/lm32_sys.c [deleted file]
hw/lm32_timer.c [deleted file]
hw/lm32_uart.c [deleted file]
hw/lm4549.c [deleted file]
hw/lm4549.h [deleted file]
hw/lm832x.c [deleted file]
hw/loader.c [deleted file]
hw/loader.h [deleted file]
hw/lpc_ich9.c [deleted file]
hw/lsi53c895a.c [deleted file]
hw/m25p80.c [deleted file]
hw/m48t59.c [deleted file]
hw/m68k/Makefile.objs
hw/m68k/an5206.c
hw/m68k/mcf5206.c
hw/m68k/mcf5208.c
hw/m68k/mcf_intc.c
hw/mac_dbdma.c [deleted file]
hw/mac_dbdma.h [deleted file]
hw/mac_nvram.c [deleted file]
hw/macio.c [deleted file]
hw/marvell_88w8618_audio.c [deleted file]
hw/max111x.c [deleted file]
hw/max7310.c [deleted file]
hw/mc146818rtc.c [deleted file]
hw/mc146818rtc.h [deleted file]
hw/mc146818rtc_regs.h [deleted file]
hw/mcf.h [deleted file]
hw/mcf_fec.c [deleted file]
hw/mcf_uart.c [deleted file]
hw/megasas.c [deleted file]
hw/mfi.h [deleted file]
hw/microblaze/Makefile.objs
hw/microblaze/boot.c
hw/microblaze/boot.h [new file with mode: 0644]
hw/microblaze/petalogix_ml605_mmu.c
hw/microblaze/petalogix_s3adsp1800_mmu.c
hw/microblaze/pic_cpu.c
hw/microblaze/pic_cpu.h [new file with mode: 0644]
hw/microblaze_boot.h [deleted file]
hw/microblaze_pic_cpu.h [deleted file]
hw/milkymist-ac97.c [deleted file]
hw/milkymist-hpdmc.c [deleted file]
hw/milkymist-hw.h [deleted file]
hw/milkymist-memcard.c [deleted file]
hw/milkymist-minimac2.c [deleted file]
hw/milkymist-pfpu.c [deleted file]
hw/milkymist-softusb.c [deleted file]
hw/milkymist-sysctl.c [deleted file]
hw/milkymist-tmu2.c [deleted file]
hw/milkymist-uart.c [deleted file]
hw/milkymist-vgafb.c [deleted file]
hw/milkymist-vgafb_template.h [deleted file]
hw/mips-bios.h [deleted file]
hw/mips.h [deleted file]
hw/mips/Makefile.objs
hw/mips/addr.c
hw/mips/cputimer.c
hw/mips/gt64xxx_pci.c [new file with mode: 0644]
hw/mips/mips_fulong2e.c
hw/mips/mips_int.c
hw/mips/mips_jazz.c
hw/mips/mips_malta.c
hw/mips/mips_mipssim.c
hw/mips/mips_r4k.c
hw/mips_cpudevs.h [deleted file]
hw/mipsnet.c [deleted file]
hw/misc/Makefile.objs [new file with mode: 0644]
hw/misc/a9scu.c [new file with mode: 0644]
hw/misc/applesmc.c [new file with mode: 0644]
hw/misc/arm_l2x0.c [new file with mode: 0644]
hw/misc/arm_sysctl.c [new file with mode: 0644]
hw/misc/cbus.c [new file with mode: 0644]
hw/misc/debugexit.c [new file with mode: 0644]
hw/misc/eccmemctl.c [new file with mode: 0644]
hw/misc/exynos4210_pmu.c [new file with mode: 0644]
hw/misc/imx_ccm.c [new file with mode: 0644]
hw/misc/ivshmem.c [new file with mode: 0644]
hw/misc/lm32_sys.c [new file with mode: 0644]
hw/misc/macio/Makefile.objs [new file with mode: 0644]
hw/misc/macio/cuda.c [new file with mode: 0644]
hw/misc/macio/mac_dbdma.c [new file with mode: 0644]
hw/misc/macio/macio.c [new file with mode: 0644]
hw/misc/max111x.c [new file with mode: 0644]
hw/misc/milkymist-hpdmc.c [new file with mode: 0644]
hw/misc/milkymist-pfpu.c [new file with mode: 0644]
hw/misc/mst_fpga.c [new file with mode: 0644]
hw/misc/omap_clk.c [new file with mode: 0644]
hw/misc/omap_gpmc.c [new file with mode: 0644]
hw/misc/omap_l4.c [new file with mode: 0644]
hw/misc/omap_sdrc.c [new file with mode: 0644]
hw/misc/omap_tap.c [new file with mode: 0644]
hw/misc/pc-testdev.c [new file with mode: 0644]
hw/misc/puv3_pm.c [new file with mode: 0644]
hw/misc/pxa2xx_pcmcia.c [new file with mode: 0644]
hw/misc/sga.c [new file with mode: 0644]
hw/misc/slavio_misc.c [new file with mode: 0644]
hw/misc/tmp105.c [new file with mode: 0644]
hw/misc/tmp105.h [new file with mode: 0644]
hw/misc/vfio.c [new file with mode: 0644]
hw/misc/vmport.c [new file with mode: 0644]
hw/misc/zynq_slcr.c [new file with mode: 0644]
hw/moxie/Makefile.objs
hw/moxie/moxiesim.c
hw/mst_fpga.c [deleted file]
hw/multiboot.h [deleted file]
hw/nand.c [deleted file]
hw/ne2000-isa.c [deleted file]
hw/ne2000.c [deleted file]
hw/ne2000.h [deleted file]
hw/net/Makefile.objs [new file with mode: 0644]
hw/net/cadence_gem.c [new file with mode: 0644]
hw/net/dp8393x.c [new file with mode: 0644]
hw/net/e1000.c [new file with mode: 0644]
hw/net/e1000_regs.h [new file with mode: 0644]
hw/net/eepro100.c [new file with mode: 0644]
hw/net/etraxfs_eth.c [new file with mode: 0644]
hw/net/lan9118.c [new file with mode: 0644]
hw/net/lance.c [new file with mode: 0644]
hw/net/mcf_fec.c [new file with mode: 0644]
hw/net/milkymist-minimac2.c [new file with mode: 0644]
hw/net/mipsnet.c [new file with mode: 0644]
hw/net/ne2000-isa.c [new file with mode: 0644]
hw/net/ne2000.c [new file with mode: 0644]
hw/net/ne2000.h [new file with mode: 0644]
hw/net/opencores_eth.c [new file with mode: 0644]
hw/net/pcnet-pci.c [new file with mode: 0644]
hw/net/pcnet.c [new file with mode: 0644]
hw/net/pcnet.h [new file with mode: 0644]
hw/net/rtl8139.c [new file with mode: 0644]
hw/net/smc91c111.c [new file with mode: 0644]
hw/net/spapr_llan.c [new file with mode: 0644]
hw/net/stellaris_enet.c [new file with mode: 0644]
hw/net/vhost_net.c [new file with mode: 0644]
hw/net/virtio-net.c [new file with mode: 0644]
hw/net/vmware_utils.h [new file with mode: 0644]
hw/net/vmxnet3.c [new file with mode: 0644]
hw/net/vmxnet3.h [new file with mode: 0644]
hw/net/vmxnet_debug.h [new file with mode: 0644]
hw/net/vmxnet_rx_pkt.c [new file with mode: 0644]
hw/net/vmxnet_rx_pkt.h [new file with mode: 0644]
hw/net/vmxnet_tx_pkt.c [new file with mode: 0644]
hw/net/vmxnet_tx_pkt.h [new file with mode: 0644]
hw/net/xen_nic.c [new file with mode: 0644]
hw/net/xgmac.c [new file with mode: 0644]
hw/net/xilinx_axienet.c [new file with mode: 0644]
hw/net/xilinx_ethlite.c [new file with mode: 0644]
hw/null-machine.c [deleted file]
hw/nvram.h [deleted file]
hw/nvram/Makefile.objs [new file with mode: 0644]
hw/nvram/ds1225y.c [new file with mode: 0644]
hw/nvram/eeprom93xx.c [new file with mode: 0644]
hw/nvram/fw_cfg.c [new file with mode: 0644]
hw/nvram/mac_nvram.c [new file with mode: 0644]
hw/nvram/spapr_nvram.c [new file with mode: 0644]
hw/omap.h [deleted file]
hw/omap_clk.c [deleted file]
hw/omap_dma.c [deleted file]
hw/omap_dss.c [deleted file]
hw/omap_gpio.c [deleted file]
hw/omap_gpmc.c [deleted file]
hw/omap_gptimer.c [deleted file]
hw/omap_i2c.c [deleted file]
hw/omap_intc.c [deleted file]
hw/omap_l4.c [deleted file]
hw/omap_lcd_template.h [deleted file]
hw/omap_lcdc.c [deleted file]
hw/omap_mmc.c [deleted file]
hw/omap_sdrc.c [deleted file]
hw/omap_spi.c [deleted file]
hw/omap_synctimer.c [deleted file]
hw/omap_tap.c [deleted file]
hw/omap_uart.c [deleted file]
hw/onenand.c [deleted file]
hw/opencores_eth.c [deleted file]
hw/openpic.c [deleted file]
hw/openpic.h [deleted file]
hw/openrisc/openrisc_sim.c
hw/pam.c [deleted file]
hw/pam.h [deleted file]
hw/parallel.c [deleted file]
hw/pc-testdev.c [deleted file]
hw/pc.h [deleted file]
hw/pc87312.c [deleted file]
hw/pc87312.h [deleted file]
hw/pc_sysfw.c [deleted file]
hw/pci-bridge/Makefile.objs [new file with mode: 0644]
hw/pci-bridge/i82801b11.c [new file with mode: 0644]
hw/pci-bridge/ioh3420.c [new file with mode: 0644]
hw/pci-bridge/ioh3420.h [new file with mode: 0644]
hw/pci-bridge/pci_bridge_dev.c [new file with mode: 0644]
hw/pci-bridge/xio3130_downstream.c [new file with mode: 0644]
hw/pci-bridge/xio3130_downstream.h [new file with mode: 0644]
hw/pci-bridge/xio3130_upstream.c [new file with mode: 0644]
hw/pci-bridge/xio3130_upstream.h [new file with mode: 0644]
hw/pci-host/Makefile.objs [new file with mode: 0644]
hw/pci-host/apb.c [new file with mode: 0644]
hw/pci-host/bonito.c [new file with mode: 0644]
hw/pci-host/dec.c [new file with mode: 0644]
hw/pci-host/dec.h [new file with mode: 0644]
hw/pci-host/grackle.c [new file with mode: 0644]
hw/pci-host/pam.c [new file with mode: 0644]
hw/pci-host/piix.c [new file with mode: 0644]
hw/pci-host/ppce500.c [new file with mode: 0644]
hw/pci-host/prep.c [new file with mode: 0644]
hw/pci-host/q35.c [new file with mode: 0644]
hw/pci-host/uninorth.c [new file with mode: 0644]
hw/pci-host/versatile.c [new file with mode: 0644]
hw/pci/Makefile.objs
hw/pci/msi.h [deleted file]
hw/pci/msix.h [deleted file]
hw/pci/pci-hotplug.c
hw/pci/pci.h [deleted file]
hw/pci/pci_bridge.h [deleted file]
hw/pci/pci_bus.h [deleted file]
hw/pci/pci_host.h [deleted file]
hw/pci/pci_ids.h [deleted file]
hw/pci/pci_regs.h [deleted file]
hw/pci/pcie.h [deleted file]
hw/pci/pcie_aer.h [deleted file]
hw/pci/pcie_host.h [deleted file]
hw/pci/pcie_port.h [deleted file]
hw/pci/pcie_regs.h [deleted file]
hw/pci/shpc.h [deleted file]
hw/pci/slotid_cap.h [deleted file]
hw/pci_bridge_dev.c [deleted file]
hw/pckbd.c [deleted file]
hw/pcmcia.h [deleted file]
hw/pcnet-pci.c [deleted file]
hw/pcnet.c [deleted file]
hw/pcnet.h [deleted file]
hw/pcspk.c [deleted file]
hw/pcspk.h [deleted file]
hw/pflash_cfi01.c [deleted file]
hw/pflash_cfi02.c [deleted file]
hw/piix4.c [deleted file]
hw/piix_pci.c [deleted file]
hw/pl011.c [deleted file]
hw/pl022.c [deleted file]
hw/pl031.c [deleted file]
hw/pl041.c [deleted file]
hw/pl041.h [deleted file]
hw/pl041.hx [deleted file]
hw/pl050.c [deleted file]
hw/pl061.c [deleted file]
hw/pl080.c [deleted file]
hw/pl110.c [deleted file]
hw/pl110_template.h [deleted file]
hw/pl181.c [deleted file]
hw/pl190.c [deleted file]
hw/pl330.c [deleted file]
hw/pm_smbus.c [deleted file]
hw/pm_smbus.h [deleted file]
hw/ppc-viosrp.h [deleted file]
hw/ppc.h [deleted file]
hw/ppc/Makefile.objs
hw/ppc/e500.c
hw/ppc/e500plat.c
hw/ppc/mac.h
hw/ppc/mac_newworld.c
hw/ppc/mac_oldworld.c
hw/ppc/mpc8544ds.c
hw/ppc/ppc.c
hw/ppc/ppc405.h [new file with mode: 0644]
hw/ppc/ppc405_boards.c
hw/ppc/ppc405_uc.c
hw/ppc/ppc440_bamboo.c
hw/ppc/ppc4xx_devs.c
hw/ppc/ppc4xx_pci.c [new file with mode: 0644]
hw/ppc/ppc_booke.c
hw/ppc/prep.c
hw/ppc/spapr.c
hw/ppc/spapr_events.c
hw/ppc/spapr_hcall.c
hw/ppc/spapr_iommu.c
hw/ppc/spapr_pci.c [new file with mode: 0644]
hw/ppc/spapr_rtas.c
hw/ppc/spapr_vio.c
hw/ppc/virtex_ml507.c
hw/ppc/xics.c
hw/ppc405.h [deleted file]
hw/ppc4xx.h [deleted file]
hw/ppc4xx_pci.c [deleted file]
hw/ppce500_pci.c [deleted file]
hw/ppce500_pci.h [deleted file]
hw/prep_pci.c [deleted file]
hw/primecell.h [deleted file]
hw/ps2.c [deleted file]
hw/ps2.h [deleted file]
hw/ptimer.c [deleted file]
hw/ptimer.h [deleted file]
hw/puv3.h [deleted file]
hw/puv3_dma.c [deleted file]
hw/puv3_gpio.c [deleted file]
hw/puv3_intc.c [deleted file]
hw/puv3_ost.c [deleted file]
hw/puv3_pm.c [deleted file]
hw/pxa.h [deleted file]
hw/pxa2xx_dma.c [deleted file]
hw/pxa2xx_keypad.c [deleted file]
hw/pxa2xx_lcd.c [deleted file]
hw/pxa2xx_mmci.c [deleted file]
hw/pxa2xx_pcmcia.c [deleted file]
hw/pxa2xx_template.h [deleted file]
hw/pxa2xx_timer.c [deleted file]
hw/q35.c [deleted file]
hw/q35.h [deleted file]
hw/qdev-addr.c [deleted file]
hw/qdev-addr.h [deleted file]
hw/qdev-core.h [deleted file]
hw/qdev-dma.h [deleted file]
hw/qdev-properties-system.c [deleted file]
hw/qdev-properties.c [deleted file]
hw/qdev-properties.h [deleted file]
hw/qdev.c [deleted file]
hw/qdev.h [deleted file]
hw/qxl-logger.c [deleted file]
hw/qxl-render.c [deleted file]
hw/qxl.c [deleted file]
hw/qxl.h [deleted file]
hw/rc4030.c [deleted file]
hw/realview_gic.c [deleted file]
hw/rtl8139.c [deleted file]
hw/s390x/Makefile.objs
hw/s390x/event-facility.h [deleted file]
hw/s390x/s390-virtio-bus.c
hw/s390x/s390-virtio-bus.h
hw/s390x/s390-virtio.c
hw/s390x/sclp.h [deleted file]
hw/s390x/sclpconsole.c [deleted file]
hw/s390x/virtio-ccw.c
hw/s390x/virtio-ccw.h
hw/sb16.c [deleted file]
hw/sbi.c [deleted file]
hw/scsi-bus.c [deleted file]
hw/scsi-defs.h [deleted file]
hw/scsi-disk.c [deleted file]
hw/scsi-generic.c [deleted file]
hw/scsi.h [deleted file]
hw/scsi/Makefile.objs [new file with mode: 0644]
hw/scsi/esp-pci.c [new file with mode: 0644]
hw/scsi/esp.c [new file with mode: 0644]
hw/scsi/lsi53c895a.c [new file with mode: 0644]
hw/scsi/megasas.c [new file with mode: 0644]
hw/scsi/mfi.h [new file with mode: 0644]
hw/scsi/scsi-bus.c [new file with mode: 0644]
hw/scsi/scsi-disk.c [new file with mode: 0644]
hw/scsi/scsi-generic.c [new file with mode: 0644]
hw/scsi/spapr_vscsi.c [new file with mode: 0644]
hw/scsi/srp.h [new file with mode: 0644]
hw/scsi/viosrp.h [new file with mode: 0644]
hw/scsi/virtio-scsi.c [new file with mode: 0644]
hw/sd.c [deleted file]
hw/sd.h [deleted file]
hw/sd/Makefile.objs [new file with mode: 0644]
hw/sd/milkymist-memcard.c [new file with mode: 0644]
hw/sd/omap_mmc.c [new file with mode: 0644]
hw/sd/pl181.c [new file with mode: 0644]
hw/sd/pxa2xx_mmci.c [new file with mode: 0644]
hw/sd/sd.c [new file with mode: 0644]
hw/sd/sdhci.c [new file with mode: 0644]
hw/sd/sdhci.h [new file with mode: 0644]
hw/sd/ssi-sd.c [new file with mode: 0644]
hw/sdhci.c [deleted file]
hw/sdhci.h [deleted file]
hw/serial-isa.c [deleted file]
hw/serial-pci.c [deleted file]
hw/serial.c [deleted file]
hw/serial.h [deleted file]
hw/sga.c [deleted file]
hw/sh.h [deleted file]
hw/sh4/Makefile.objs
hw/sh4/r2d.c
hw/sh4/sh7750.c
hw/sh4/sh7750_regnames.c
hw/sh4/sh7750_regnames.h [new file with mode: 0644]
hw/sh4/sh7750_regs.h [new file with mode: 0644]
hw/sh4/sh_pci.c [new file with mode: 0644]
hw/sh4/shix.c
hw/sh7750_regnames.h [deleted file]
hw/sh7750_regs.h [deleted file]
hw/sh_intc.c [deleted file]
hw/sh_intc.h [deleted file]
hw/sh_pci.c [deleted file]
hw/sh_serial.c [deleted file]
hw/sh_timer.c [deleted file]
hw/sharpsl.h [deleted file]
hw/slavio_intctl.c [deleted file]
hw/slavio_misc.c [deleted file]
hw/slavio_timer.c [deleted file]
hw/sm501.c [deleted file]
hw/sm501_template.h [deleted file]
hw/smbios.h [deleted file]
hw/smbus.c [deleted file]
hw/smbus.h [deleted file]
hw/smbus_eeprom.c [deleted file]
hw/smbus_ich9.c [deleted file]
hw/smc91c111.c [deleted file]
hw/soc_dma.c [deleted file]
hw/soc_dma.h [deleted file]
hw/spapr.h [deleted file]
hw/spapr_llan.c [deleted file]
hw/spapr_nvram.c [deleted file]
hw/spapr_pci.c [deleted file]
hw/spapr_pci.h [deleted file]
hw/spapr_vio.h [deleted file]
hw/spapr_vscsi.c [deleted file]
hw/spapr_vty.c [deleted file]
hw/sparc/Makefile.objs
hw/sparc/leon3.c
hw/sparc/sun4m.c
hw/sparc32_dma.c [deleted file]
hw/sparc32_dma.h [deleted file]
hw/sparc64/Makefile.objs
hw/sparc64/sun4u.c
hw/srp.h [deleted file]
hw/ssd0303.c [deleted file]
hw/ssd0323.c [deleted file]
hw/ssi-sd.c [deleted file]
hw/ssi.c [deleted file]
hw/ssi.h [deleted file]
hw/ssi/Makefile.objs [new file with mode: 0644]
hw/ssi/omap_spi.c [new file with mode: 0644]
hw/ssi/pl022.c [new file with mode: 0644]
hw/ssi/ssi.c [new file with mode: 0644]
hw/ssi/xilinx_spi.c [new file with mode: 0644]
hw/ssi/xilinx_spips.c [new file with mode: 0644]
hw/stellaris_enet.c [deleted file]
hw/stellaris_input.c [deleted file]
hw/stream.c [deleted file]
hw/stream.h [deleted file]
hw/strongarm.c [deleted file]
hw/strongarm.h [deleted file]
hw/sun4c_intctl.c [deleted file]
hw/sun4m.h [deleted file]
hw/sun4m_iommu.c [deleted file]
hw/sysbus.c [deleted file]
hw/sysbus.h [deleted file]
hw/tc58128.c [deleted file]
hw/tc6393xb.c [deleted file]
hw/tc6393xb_template.h [deleted file]
hw/tcx.c [deleted file]
hw/timer/Makefile.objs [new file with mode: 0644]
hw/timer/arm_mptimer.c [new file with mode: 0644]
hw/timer/arm_timer.c [new file with mode: 0644]
hw/timer/cadence_ttc.c [new file with mode: 0644]
hw/timer/ds1338.c [new file with mode: 0644]
hw/timer/etraxfs_timer.c [new file with mode: 0644]
hw/timer/exynos4210_mct.c [new file with mode: 0644]
hw/timer/exynos4210_pwm.c [new file with mode: 0644]
hw/timer/exynos4210_rtc.c [new file with mode: 0644]
hw/timer/grlib_gptimer.c [new file with mode: 0644]
hw/timer/hpet.c [new file with mode: 0644]
hw/timer/i8254.c [new file with mode: 0644]
hw/timer/i8254_common.c [new file with mode: 0644]
hw/timer/imx_timer.c [new file with mode: 0644]
hw/timer/lm32_timer.c [new file with mode: 0644]
hw/timer/m48t59.c [new file with mode: 0644]
hw/timer/mc146818rtc.c [new file with mode: 0644]
hw/timer/milkymist-sysctl.c [new file with mode: 0644]
hw/timer/omap_gptimer.c [new file with mode: 0644]
hw/timer/omap_synctimer.c [new file with mode: 0644]
hw/timer/pl031.c [new file with mode: 0644]
hw/timer/puv3_ost.c [new file with mode: 0644]
hw/timer/pxa2xx_timer.c [new file with mode: 0644]
hw/timer/sh_timer.c [new file with mode: 0644]
hw/timer/slavio_timer.c [new file with mode: 0644]
hw/timer/tusb6010.c [new file with mode: 0644]
hw/timer/twl92230.c [new file with mode: 0644]
hw/timer/xilinx_timer.c [new file with mode: 0644]
hw/tmp105.c [deleted file]
hw/tmp105.h [deleted file]
hw/tmp105_regs.h [deleted file]
hw/tpci200.c [deleted file]
hw/tsc2005.c [deleted file]
hw/tsc210x.c [deleted file]
hw/tusb6010.c [deleted file]
hw/twl92230.c [deleted file]
hw/uboot_image.h [deleted file]
hw/unicore32/puv3.c
hw/unin_pci.c [deleted file]
hw/usb.h [deleted file]
hw/usb/Makefile.objs
hw/usb/bus.c
hw/usb/ccid-card-emulated.c [new file with mode: 0644]
hw/usb/ccid-card-passthru.c [new file with mode: 0644]
hw/usb/ccid.h [new file with mode: 0644]
hw/usb/dev-audio.c
hw/usb/dev-hid.c
hw/usb/dev-hub.c
hw/usb/dev-smartcard-reader.c
hw/usb/dev-storage.c
hw/usb/dev-uas.c
hw/usb/hcd-xhci.c
hw/usb/redirect.c
hw/versatile_i2c.c [deleted file]
hw/versatile_pci.c [deleted file]
hw/vfio_pci.c [deleted file]
hw/vga-isa-mm.c [deleted file]
hw/vga-isa.c [deleted file]
hw/vga-pci.c [deleted file]
hw/vga.c [deleted file]
hw/vga.h [deleted file]
hw/vga_int.h [deleted file]
hw/vga_template.h [deleted file]
hw/vhost.c [deleted file]
hw/vhost.h [deleted file]
hw/vhost_net.c [deleted file]
hw/vhost_net.h [deleted file]
hw/virtio-balloon.c [deleted file]
hw/virtio-balloon.h [deleted file]
hw/virtio-blk.c [deleted file]
hw/virtio-blk.h [deleted file]
hw/virtio-bus.c [deleted file]
hw/virtio-bus.h [deleted file]
hw/virtio-console.c [deleted file]
hw/virtio-net.c [deleted file]
hw/virtio-net.h [deleted file]
hw/virtio-pci.c [deleted file]
hw/virtio-pci.h [deleted file]
hw/virtio-rng.c [deleted file]
hw/virtio-rng.h [deleted file]
hw/virtio-scsi.c [deleted file]
hw/virtio-scsi.h [deleted file]
hw/virtio-serial-bus.c [deleted file]
hw/virtio-serial.h [deleted file]
hw/virtio.c [deleted file]
hw/virtio.h [deleted file]
hw/virtio/Makefile.objs [new file with mode: 0644]
hw/virtio/dataplane/Makefile.objs [new file with mode: 0644]
hw/virtio/dataplane/hostmem.c [new file with mode: 0644]
hw/virtio/dataplane/vring.c [new file with mode: 0644]
hw/virtio/vhost.c [new file with mode: 0644]
hw/virtio/virtio-balloon.c [new file with mode: 0644]
hw/virtio/virtio-bus.c [new file with mode: 0644]
hw/virtio/virtio-pci.c [new file with mode: 0644]
hw/virtio/virtio-pci.h [new file with mode: 0644]
hw/virtio/virtio-rng.c [new file with mode: 0644]
hw/virtio/virtio.c [new file with mode: 0644]
hw/vmmouse.c [deleted file]
hw/vmport.c [deleted file]
hw/vmware_utils.h [deleted file]
hw/vmware_vga.c [deleted file]
hw/vmxnet3.c [deleted file]
hw/vmxnet3.h [deleted file]
hw/vmxnet_debug.h [deleted file]
hw/vmxnet_rx_pkt.c [deleted file]
hw/vmxnet_rx_pkt.h [deleted file]
hw/vmxnet_tx_pkt.c [deleted file]
hw/vmxnet_tx_pkt.h [deleted file]
hw/vt82c686.c [deleted file]
hw/vt82c686.h [deleted file]
hw/watchdog.c [deleted file]
hw/watchdog.h [deleted file]
hw/watchdog/Makefile.objs [new file with mode: 0644]
hw/watchdog/watchdog.c [new file with mode: 0644]
hw/watchdog/wdt_i6300esb.c [new file with mode: 0644]
hw/watchdog/wdt_ib700.c [new file with mode: 0644]
hw/wdt_i6300esb.c [deleted file]
hw/wdt_ib700.c [deleted file]
hw/wm8750.c [deleted file]
hw/xen-host-pci-device.c [deleted file]
hw/xen-host-pci-device.h [deleted file]
hw/xen.h [deleted file]
hw/xen/Makefile.objs [new file with mode: 0644]
hw/xen/xen-host-pci-device.c [new file with mode: 0644]
hw/xen/xen-host-pci-device.h [new file with mode: 0644]
hw/xen/xen_apic.c [new file with mode: 0644]
hw/xen/xen_backend.c [new file with mode: 0644]
hw/xen/xen_devconfig.c [new file with mode: 0644]
hw/xen/xen_platform.c [new file with mode: 0644]
hw/xen/xen_pt.c [new file with mode: 0644]
hw/xen/xen_pt.h [new file with mode: 0644]
hw/xen/xen_pt_config_init.c [new file with mode: 0644]
hw/xen/xen_pt_msi.c [new file with mode: 0644]
hw/xen_apic.c [deleted file]
hw/xen_backend.c [deleted file]
hw/xen_backend.h [deleted file]
hw/xen_blkif.h [deleted file]
hw/xen_common.h [deleted file]
hw/xen_console.c [deleted file]
hw/xen_devconfig.c [deleted file]
hw/xen_disk.c [deleted file]
hw/xen_domainbuild.h [deleted file]
hw/xen_nic.c [deleted file]
hw/xen_platform.c [deleted file]
hw/xen_pt.c [deleted file]
hw/xen_pt.h [deleted file]
hw/xen_pt_config_init.c [deleted file]
hw/xen_pt_msi.c [deleted file]
hw/xenfb.c [deleted file]
hw/xgmac.c [deleted file]
hw/xics.h [deleted file]
hw/xilinx.h [deleted file]
hw/xilinx_axidma.c [deleted file]
hw/xilinx_axienet.c [deleted file]
hw/xilinx_ethlite.c [deleted file]
hw/xilinx_intc.c [deleted file]
hw/xilinx_spi.c [deleted file]
hw/xilinx_spips.c [deleted file]
hw/xilinx_timer.c [deleted file]
hw/xilinx_uartlite.c [deleted file]
hw/xio3130_downstream.c [deleted file]
hw/xio3130_downstream.h [deleted file]
hw/xio3130_upstream.c [deleted file]
hw/xio3130_upstream.h [deleted file]
hw/xtensa/xtensa_bootparam.h [new file with mode: 0644]
hw/xtensa/xtensa_lx60.c
hw/xtensa_bootparam.h [deleted file]
hw/zaurus.c [deleted file]
hw/zynq_slcr.c [deleted file]
include/block/block_int.h
include/block/scsi.h [new file with mode: 0644]
include/exec/memory-internal.h
include/hw/acpi/acpi.h [new file with mode: 0644]
include/hw/acpi/ich9.h [new file with mode: 0644]
include/hw/arm.h [new file with mode: 0644]
include/hw/arm/devices.h [new file with mode: 0644]
include/hw/arm/exynos4210.h [new file with mode: 0644]
include/hw/arm/imx.h [new file with mode: 0644]
include/hw/arm/omap.h [new file with mode: 0644]
include/hw/arm/primecell.h [new file with mode: 0644]
include/hw/arm/pxa.h [new file with mode: 0644]
include/hw/arm/sharpsl.h [new file with mode: 0644]
include/hw/arm/soc_dma.h [new file with mode: 0644]
include/hw/audio/audio.h [new file with mode: 0644]
include/hw/audio/pcspk.h [new file with mode: 0644]
include/hw/block/block.h [new file with mode: 0644]
include/hw/block/fdc.h [new file with mode: 0644]
include/hw/block/flash.h [new file with mode: 0644]
include/hw/boards.h [new file with mode: 0644]
include/hw/bt.h [new file with mode: 0644]
include/hw/char/escc.h [new file with mode: 0644]
include/hw/char/serial.h [new file with mode: 0644]
include/hw/cris/etraxfs.h [new file with mode: 0644]
include/hw/cris/etraxfs_dma.h [new file with mode: 0644]
include/hw/elf_ops.h [new file with mode: 0644]
include/hw/empty_slot.h [new file with mode: 0644]
include/hw/hw.h [new file with mode: 0644]
include/hw/i2c/i2c.h [new file with mode: 0644]
include/hw/i2c/pm_smbus.h [new file with mode: 0644]
include/hw/i2c/smbus.h [new file with mode: 0644]
include/hw/i386/apic-msidef.h [new file with mode: 0644]
include/hw/i386/apic.h [new file with mode: 0644]
include/hw/i386/apic_internal.h [new file with mode: 0644]
include/hw/i386/ich9.h [new file with mode: 0644]
include/hw/i386/ioapic.h [new file with mode: 0644]
include/hw/i386/ioapic_internal.h [new file with mode: 0644]
include/hw/i386/pc.h [new file with mode: 0644]
include/hw/i386/smbios.h [new file with mode: 0644]
include/hw/ide.h [new file with mode: 0644]
include/hw/input/adb.h [new file with mode: 0644]
include/hw/input/hid.h [new file with mode: 0644]
include/hw/input/ps2.h [new file with mode: 0644]
include/hw/irq.h [new file with mode: 0644]
include/hw/isa/apm.h [new file with mode: 0644]
include/hw/isa/i8259_internal.h [new file with mode: 0644]
include/hw/isa/isa.h [new file with mode: 0644]
include/hw/isa/pc87312.h [new file with mode: 0644]
include/hw/isa/vt82c686.h [new file with mode: 0644]
include/hw/kvm/clock.h [new file with mode: 0644]
include/hw/lm32/lm32_juart.h [new file with mode: 0644]
include/hw/lm32/lm32_pic.h [new file with mode: 0644]
include/hw/loader.h [new file with mode: 0644]
include/hw/m68k/mcf.h [new file with mode: 0644]
include/hw/mips/bios.h [new file with mode: 0644]
include/hw/mips/cpudevs.h [new file with mode: 0644]
include/hw/mips/mips.h [new file with mode: 0644]
include/hw/misc/tmp105_regs.h [new file with mode: 0644]
include/hw/nvram/eeprom93xx.h [new file with mode: 0644]
include/hw/nvram/fw_cfg.h [new file with mode: 0644]
include/hw/pci-host/apb.h [new file with mode: 0644]
include/hw/pci-host/pam.h [new file with mode: 0644]
include/hw/pci-host/ppce500.h [new file with mode: 0644]
include/hw/pci-host/q35.h [new file with mode: 0644]
include/hw/pci-host/spapr.h [new file with mode: 0644]
include/hw/pci/msi.h [new file with mode: 0644]
include/hw/pci/msix.h [new file with mode: 0644]
include/hw/pci/pci.h [new file with mode: 0644]
include/hw/pci/pci_bridge.h [new file with mode: 0644]
include/hw/pci/pci_bus.h [new file with mode: 0644]
include/hw/pci/pci_host.h [new file with mode: 0644]
include/hw/pci/pci_ids.h [new file with mode: 0644]
include/hw/pci/pci_regs.h [new file with mode: 0644]
include/hw/pci/pcie.h [new file with mode: 0644]
include/hw/pci/pcie_aer.h [new file with mode: 0644]
include/hw/pci/pcie_host.h [new file with mode: 0644]
include/hw/pci/pcie_port.h [new file with mode: 0644]
include/hw/pci/pcie_regs.h [new file with mode: 0644]
include/hw/pci/shpc.h [new file with mode: 0644]
include/hw/pci/slotid_cap.h [new file with mode: 0644]
include/hw/pcmcia.h [new file with mode: 0644]
include/hw/ppc/mac_dbdma.h [new file with mode: 0644]
include/hw/ppc/openpic.h [new file with mode: 0644]
include/hw/ppc/ppc.h [new file with mode: 0644]
include/hw/ppc/ppc4xx.h [new file with mode: 0644]
include/hw/ppc/spapr.h [new file with mode: 0644]
include/hw/ppc/spapr_vio.h [new file with mode: 0644]
include/hw/ppc/xics.h [new file with mode: 0644]
include/hw/ptimer.h [new file with mode: 0644]
include/hw/qdev-addr.h [new file with mode: 0644]
include/hw/qdev-core.h [new file with mode: 0644]
include/hw/qdev-dma.h [new file with mode: 0644]
include/hw/qdev-properties.h [new file with mode: 0644]
include/hw/qdev.h [new file with mode: 0644]
include/hw/s390x/event-facility.h [new file with mode: 0644]
include/hw/s390x/sclp.h [new file with mode: 0644]
include/hw/scsi/esp.h [new file with mode: 0644]
include/hw/scsi/scsi.h [new file with mode: 0644]
include/hw/sd.h [new file with mode: 0644]
include/hw/sh4/sh.h [new file with mode: 0644]
include/hw/sh4/sh_intc.h [new file with mode: 0644]
include/hw/sparc/firmware_abi.h [new file with mode: 0644]
include/hw/sparc/grlib.h [new file with mode: 0644]
include/hw/sparc/sparc32_dma.h [new file with mode: 0644]
include/hw/sparc/sun4m.h [new file with mode: 0644]
include/hw/ssi.h [new file with mode: 0644]
include/hw/stream.h [new file with mode: 0644]
include/hw/sysbus.h [new file with mode: 0644]
include/hw/timer/hpet.h [new file with mode: 0644]
include/hw/timer/i8254.h [new file with mode: 0644]
include/hw/timer/i8254_internal.h [new file with mode: 0644]
include/hw/timer/m48t59.h [new file with mode: 0644]
include/hw/timer/mc146818rtc.h [new file with mode: 0644]
include/hw/timer/mc146818rtc_regs.h [new file with mode: 0644]
include/hw/unicore32/puv3.h [new file with mode: 0644]
include/hw/usb.h [new file with mode: 0644]
include/hw/virtio/dataplane/hostmem.h [new file with mode: 0644]
include/hw/virtio/dataplane/vring.h [new file with mode: 0644]
include/hw/virtio/vhost.h [new file with mode: 0644]
include/hw/virtio/virtio-9p.h [new file with mode: 0644]
include/hw/virtio/virtio-balloon.h [new file with mode: 0644]
include/hw/virtio/virtio-blk.h [new file with mode: 0644]
include/hw/virtio/virtio-bus.h [new file with mode: 0644]
include/hw/virtio/virtio-net.h [new file with mode: 0644]
include/hw/virtio/virtio-rng.h [new file with mode: 0644]
include/hw/virtio/virtio-scsi.h [new file with mode: 0644]
include/hw/virtio/virtio-serial.h [new file with mode: 0644]
include/hw/virtio/virtio.h [new file with mode: 0644]
include/hw/xen/xen.h [new file with mode: 0644]
include/hw/xen/xen_backend.h [new file with mode: 0644]
include/hw/xen/xen_common.h [new file with mode: 0644]
include/hw/xilinx.h [new file with mode: 0644]
include/migration/vmstate.h
include/net/vhost_net.h [new file with mode: 0644]
include/qapi/qmp/qstring.h
include/sysemu/watchdog.h [new file with mode: 0644]
linux-user/strace.c
main-loop.c
monitor.c
net/tap.c
pc-bios/optionrom/optionrom.h
qemu-char.c
qga/commands-win32.c
qga/main.c
qga/qapi-schema.json
qobject/qstring.c
target-arm/arm-semi.c
target-arm/kvm.c
target-i386/cpu.c
target-i386/cpu.h
target-i386/kvm.c
target-i386/machine.c
target-lm32/op_helper.c
target-lm32/translate.c
target-ppc/kvm.c
target-s390x/translate.c
target-sh4/helper.c
tests/Makefile
tests/rtc-test.c
tests/test-visitor-serialization.c
tests/tmp105-test.c
tpm/tpm_passthrough.c
tpm/tpm_tis.c
tpm/tpm_tis.h
trace-events
vl.c
xen-all.c
xen-mapcache.c
xen-stub.c

index db14ffc16cb3a8875578ffbc50fdcbd00f4bb765..4dfd8bf7abc502311f175fe874f8b8968e12744a 100644 (file)
@@ -59,37 +59,45 @@ Alpha
 M: Richard Henderson <rth@twiddle.net>
 S: Maintained
 F: target-alpha/
+F: hw/alpha/
 
 ARM
 M: Paul Brook <paul@codesourcery.com>
 M: Peter Maydell <peter.maydell@linaro.org>
 S: Maintained
 F: target-arm/
+F: hw/arm/
+F: hw/cpu/a*mpcore.c
 
 CRIS
 M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
 S: Maintained
 F: target-cris/
+F: hw/cris/
 
 LM32
 M: Michael Walle <michael@walle.cc>
 S: Maintained
 F: target-lm32/
+F: hw/lm32/
 
 M68K
 M: Paul Brook <paul@codesourcery.com>
 S: Odd Fixes
 F: target-m68k/
+F: hw/m68k/
 
 MicroBlaze
 M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
 S: Maintained
 F: target-microblaze/
+F: hw/microblaze/
 
 MIPS
 M: Aurelien Jarno <aurelien@aurel32.net>
 S: Odd Fixes
 F: target-mips/
+F: hw/mips/
 
 Moxie
 M: Anthony Green <green@moxielogic.com>
@@ -101,38 +109,46 @@ M: Alexander Graf <agraf@suse.de>
 L: qemu-ppc@nongnu.org
 S: Maintained
 F: target-ppc/
+F: hw/ppc/
 
 S390
 M: Richard Henderson <rth@twiddle.net>
 M: Alexander Graf <agraf@suse.de>
 S: Maintained
 F: target-s390x/
+F: hw/s390x/
 
 SH4
 M: Aurelien Jarno <aurelien@aurel32.net>
 S: Odd Fixes
 F: target-sh4/
+F: hw/sh4/
 
 SPARC
 M: Blue Swirl <blauwirbel@gmail.com>
 S: Maintained
 F: target-sparc/
+F: hw/sparc/
+F: hw/sparc64/
 
 UniCore32
 M: Guan Xuetao <gxt@mprc.pku.edu.cn>
 S: Maintained
 F: target-unicore32/
+F: hw/unicore32/
 
 X86
 M: qemu-devel@nongnu.org
 S: Odd Fixes
 F: target-i386/
+F: hw/i386/
 
 Xtensa
 M: Max Filippov <jcmvbkbc@gmail.com>
 W: http://wiki.osll.spb.ru/doku.php?id=etc:users:jcmvbkbc:qemu-target-xtensa
 S: Maintained
 F: target-xtensa/
+F: hw/xtensa/
 
 Guest CPU Cores (KVM):
 ----------------------
@@ -205,156 +221,156 @@ M: Maksim Kozlov <m.kozlov@samsung.com>
 M: Igor Mitsyanko <i.mitsyanko@samsung.com>
 M: Dmitry Solodkiy <d.solodkiy@samsung.com>
 S: Maintained
-F: hw/exynos*
+F: hw/*/exynos*
 
 Calxeda Highbank
 M: Mark Langsdorf <mark.langsdorf@calxeda.com>
 S: Supported
-F: hw/highbank.c
-F: hw/xgmac.c
+F: hw/arm/highbank.c
+F: hw/net/xgmac.c
 
 Gumstix
 M: qemu-devel@nongnu.org
 S: Orphan
-F: hw/gumstix.c
+F: hw/arm/gumstix.c
 
 i.MX31
 M: Peter Chubb <peter.chubb@nicta.com.au>
 S: Odd fixes
-F: hw/imx*
-F: hw/kzm.c
+F: hw/*/imx*
+F: hw/arm/kzm.c
 
 Integrator CP
 M: Paul Brook <paul@codesourcery.com>
 M: Peter Maydell <peter.maydell@linaro.org>
 S: Maintained
-F: hw/integratorcp.c
+F: hw/arm/integratorcp.c
 
 Mainstone
 M: qemu-devel@nongnu.org
 S: Orphan
-F: hw/mainstone.c
+F: hw/arm/mainstone.c
 
 Musicpal
 M: Jan Kiszka <jan.kiszka@web.de>
 S: Maintained
-F: hw/musicpal.c
+F: hw/arm/musicpal.c
 
 nSeries
 M: Andrzej Zaborowski <balrogg@gmail.com>
 S: Maintained
-F: hw/nseries.c
+F: hw/arm/nseries.c
 
 Palm
 M: Andrzej Zaborowski <balrogg@gmail.com>
 S: Maintained
-F: hw/palm.c
+F: hw/arm/palm.c
 
 Real View
 M: Paul Brook <paul@codesourcery.com>
 M: Peter Maydell <peter.maydell@linaro.org>
 S: Maintained
-F: hw/realview*
+F: hw/arm/realview*
 
 Spitz
 M: Andrzej Zaborowski <balrogg@gmail.com>
 S: Maintained
-F: hw/spitz.c
+F: hw/arm/spitz.c
 
 Stellaris
 M: Paul Brook <paul@codesourcery.com>
 M: Peter Maydell <peter.maydell@linaro.org>
 S: Maintained
-F: hw/stellaris.c
+F: hw/*/stellaris*
 
 Versatile PB
 M: Paul Brook <paul@codesourcery.com>
 M: Peter Maydell <peter.maydell@linaro.org>
 S: Maintained
-F: hw/versatilepb.c
+F: hw/*/versatile*
 
 Xilinx Zynq
 M: Peter Crosthwaite <peter.crosthwaite@petalogix.com>
 S: Maintained
-F: hw/xilinx_zynq.c
-F: hw/zynq_slcr.c
-F: hw/cadence_*
-F: hw/xilinx_spips.c
+F: hw/arm/xilinx_zynq.c
+F: hw/misc/zynq_slcr.c
+F: hw/*/cadence_*
+F: hw/ssi/xilinx_spips.c
 
 CRIS Machines
 -------------
 Axis Dev88
 M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
 S: Maintained
-F: hw/axis_dev88.c
+F: hw/cris/axis_dev88.c
 
 etraxfs
 M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
 S: Maintained
-F: hw/etraxfs.c
+F: hw/cris/etraxfs.c
 
 LM32 Machines
 -------------
 EVR32 and uclinux BSP
 M: Michael Walle <michael@walle.cc>
 S: Maintained
-F: hw/lm32_boards.c
+F: hw/lm32/lm32_boards.c
 
 milkymist
 M: Michael Walle <michael@walle.cc>
 S: Maintained
-F: hw/milkymist.c
+F: hw/lm32/milkymist.c
 
 M68K Machines
 -------------
 an5206
 M: Paul Brook <paul@codesourcery.com>
 S: Maintained
-F: hw/an5206.c
+F: hw/m68k/an5206.c
 
 dummy_m68k
 M: Paul Brook <paul@codesourcery.com>
 S: Maintained
-F: hw/dummy_m68k.c
+F: hw/m68k/dummy_m68k.c
 
 mcf5208
 M: Paul Brook <paul@codesourcery.com>
 S: Maintained
-F: hw/mcf5208.c
+F: hw/m68k/mcf5208.c
 
 MicroBlaze Machines
 -------------------
 petalogix_s3adsp1800
 M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
 S: Maintained
-F: hw/petalogix_s3adsp1800.c
+F: hw/microblaze/petalogix_s3adsp1800.c
 
 petalogix_ml605
 M: Peter Crosthwaite <peter.crosthwaite@petalogix.com>
 S: Maintained
-F: hw/petalogix_ml605_mmu.c
+F: hw/microblaze/petalogix_ml605_mmu.c
 
 MIPS Machines
 -------------
 Jazz
 M: Hervé Poussineau <hpoussin@reactos.org>
 S: Maintained
-F: hw/mips_jazz.c
+F: hw/mips/mips_jazz.c
 
 Malta
 M: Aurelien Jarno <aurelien@aurel32.net>
 S: Maintained
-F: hw/mips_malta.c
+F: hw/mips/mips_malta.c
 
 Mipssim
 M: qemu-devel@nongnu.org
 S: Orphan
-F: hw/mips_mipssim.c
+F: hw/mips/mips_mipssim.c
 
 R4000
 M: Aurelien Jarno <aurelien@aurel32.net>
 S: Maintained
-F: hw/mips_r4k.c
+F: hw/mips/mips_r4k.c
 
 PowerPC Machines
 ----------------
@@ -362,13 +378,13 @@ PowerPC Machines
 M: Alexander Graf <agraf@suse.de>
 L: qemu-ppc@nongnu.org
 S: Odd Fixes
-F: hw/ppc405_boards.c
+F: hw/ppc/ppc405_boards.c
 
 Bamboo
 M: Alexander Graf <agraf@suse.de>
 L: qemu-ppc@nongnu.org
 S: Odd Fixes
-F: hw/ppc440_bamboo.c
+F: hw/ppc/ppc440_bamboo.c
 
 e500
 M: Alexander Graf <agraf@suse.de>
@@ -384,80 +400,82 @@ M: Scott Wood <scottwood@freescale.com>
 L: qemu-ppc@nongnu.org
 S: Supported
 F: hw/ppc/mpc8544ds.c
-F: hw/mpc8544_guts.c
+F: hw/ppc/mpc8544_guts.c
 
 New World
 M: Alexander Graf <agraf@suse.de>
 L: qemu-ppc@nongnu.org
 S: Maintained
 F: hw/ppc/mac_newworld.c
-F: hw/unin_pci.c
-F: hw/dec_pci.[hc]
+F: hw/pci/devices/host-uninorth.c
+F: hw/pci/devices/host-dec.[hc]
+F: hw/misc/macio/
 
 Old World
 M: Alexander Graf <agraf@suse.de>
 L: qemu-ppc@nongnu.org
 S: Maintained
 F: hw/ppc/mac_oldworld.c
-F: hw/grackle_pci.c
+F: hw/pci/devices/host-grackle.c
+F: hw/misc/macio/
 
 PReP
 M: Andreas Färber <andreas.faerber@web.de>
 L: qemu-ppc@nongnu.org
 S: Odd Fixes
 F: hw/ppc/prep.c
-F: hw/prep_pci.[hc]
-F: hw/pc87312.[hc]
+F: hw/pci/devices/host-prep.[hc]
+F: hw/isa/pc87312.[hc]
 
 sPAPR
 M: David Gibson <david@gibson.dropbear.id.au>
 M: Alexander Graf <agraf@suse.de>
 L: qemu-ppc@nongnu.org
 S: Supported
-F: hw/spapr*
+F: hw/*/spapr*
 
 virtex_ml507
 M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
 L: qemu-ppc@nongnu.org
 S: Odd Fixes
-F: hw/virtex_ml507.c
+F: hw/pci/virtex_ml507.c
 
 SH4 Machines
 ------------
 R2D
 M: Magnus Damm <magnus.damm@gmail.com>
 S: Maintained
-F: hw/r2d.c
+F: hw/sh/r2d.c
 
 Shix
 M: Magnus Damm <magnus.damm@gmail.com>
 S: Orphan
-F: hw/shix.c
+F: hw/sh/shix.c
 
 SPARC Machines
 --------------
 Sun4m
 M: Blue Swirl <blauwirbel@gmail.com>
 S: Maintained
-F: hw/sun4m.c
+F: hw/sparc/sun4m.c
 
 Sun4u
 M: Blue Swirl <blauwirbel@gmail.com>
 S: Maintained
-F: hw/sun4u.c
+F: hw/sparc64/sun4u.c
 
 Leon3
 M: Fabien Chouteau <chouteau@adacore.com>
 S: Maintained
-F: hw/leon3.c
-F: hw/grlib*
+F: hw/sparc/leon3.c
+F: hw/*/grlib*
 
 S390 Machines
 -------------
 S390 Virtio
 M: Alexander Graf <agraf@suse.de>
 S: Maintained
-F: hw/s390-*.c
+F: hw/s390/s390-*.c
 
 S390 Virtio-ccw
 M: Cornelia Huck <cornelia.huck@de.ibm.com>
@@ -472,7 +490,7 @@ UniCore32 Machines
 PKUnity-3 SoC initramfs-with-busybox
 M: Guan Xuetao <gxt@mprc.pku.edu.cn>
 S: Maintained
-F: hw/puv3*
+F: hw/*/puv3*
 F: hw/unicore32/
 
 X86 Machines
@@ -480,90 +498,91 @@ X86 Machines
 PC
 M: Anthony Liguori <aliguori@us.ibm.com>
 S: Supported
-F: hw/pc.[ch]
-F: hw/pc_piix.c
+F: hw/i386/pc.[ch]
+F: hw/i386/pc_piix.c
 
 Xtensa Machines
 ---------------
 sim
 M: Max Filippov <jcmvbkbc@gmail.com>
 S: Maintained
-F: hw/xtensa_sim.c
+F: hw/xtensa/xtensa_sim.c
 
 Avnet LX60
 M: Max Filippov <jcmvbkbc@gmail.com>
 S: Maintained
-F: hw/xtensa_lx60.c
+F: hw/xtensa/xtensa_lx60.c
 
 Devices
 -------
 IDE
 M: Kevin Wolf <kwolf@redhat.com>
 S: Odd Fixes
+F: include/hw/ide.h
 F: hw/ide/
 
 OMAP
 M: Peter Maydell <peter.maydell@linaro.org>
 S: Maintained
-F: hw/omap*
+F: hw/*/omap*
 
 PCI
 M: Michael S. Tsirkin <mst@redhat.com>
 S: Supported
+F: include/hw/pci/*
 F: hw/pci/*
-F: hw/pci*
-F: hw/piix*
+F: hw/acpi/*
 
 ppc4xx
 M: Alexander Graf <agraf@suse.de>
 L: qemu-ppc@nongnu.org
 S: Odd Fixes
-F: hw/ppc4xx*.[hc]
+F: hw/ppc/ppc4*.c
 
 ppce500
 M: Alexander Graf <agraf@suse.de>
 M: Scott Wood <scottwood@freescale.com>
 L: qemu-ppc@nongnu.org
 S: Supported
-F: hw/ppce500_*
+F: hw/ppc/e500_*
 
 SCSI
 M: Paolo Bonzini <pbonzini@redhat.com>
 S: Supported
-F: hw/virtio-scsi.*
-F: hw/scsi*
+F: include/hw/scsi*
+F: hw/scsi/*
 T: git git://github.com/bonzini/qemu.git scsi-next
 
 LSI53C895A
 M: Paul Brook <paul@codesourcery.com>
 S: Odd Fixes
-F: hw/lsi53c895a.c
+F: hw/scsi/lsi53c895a.c
 
 SSI
 M: Peter Crosthwaite <peter.crosthwaite@petalogix.com>
 S: Maintained
-F: hw/ssi.*
-F: hw/m25p80.c
+F: hw/ssi/*
+F: hw/block/m25p80.c
 
 USB
 M: Gerd Hoffmann <kraxel@redhat.com>
 S: Maintained
-F: hw/usb*
+F: hw/usb/*
 
 VFIO
 M: Alex Williamson <alex.williamson@redhat.com>
 S: Supported
-F: hw/vfio*
+F: hw/pci/vfio.c
 
 vhost
 M: Michael S. Tsirkin <mst@redhat.com>
 S: Supported
-F: hw/vhost*
+F: hw/*/*vhost*
 
 virtio
 M: Anthony Liguori <aliguori@us.ibm.com>
 S: Supported
-F: hw/virtio*
+F: hw/*/virtio*
 
 virtio-9p
 M: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
@@ -576,7 +595,7 @@ virtio-blk
 M: Kevin Wolf <kwolf@redhat.com>
 M: Stefan Hajnoczi <stefanha@redhat.com>
 S: Supported
-F: hw/virtio-blk*
+F: hw/block/virtio-blk.c
 
 virtio-ccw
 M: Cornelia Huck <cornelia.huck@de.ibm.com>
@@ -587,20 +606,15 @@ T: git git://github.com/cohuck/qemu virtio-ccw-upstr
 virtio-serial
 M: Amit Shah <amit.shah@redhat.com>
 S: Supported
-F: hw/virtio-serial*
-F: hw/virtio-console*
+F: hw/char/virtio-serial-bus.c
+F: hw/char/virtio-console.c
 
 Xilinx EDK
 M: Peter Crosthwaite <peter.crosthwaite@petalogix.com>
 M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
 S: Maintained
-F: hw/xilinx_axi*
-F: hw/xilinx_uartlite.c
-F: hw/xilinx_intc.c
-F: hw/xilinx_ethlite.c
-F: hw/xilinx_timer.c
-F: hw/xilinx.h
-F: hw/xilinx_spi.c
+F: hw/*/xilinx_*
+F: include/hw/xilinx.h
 
 Subsystems
 ----------
@@ -608,6 +622,7 @@ Audio
 M: Vassili Karpov (malc) <av1474@comtv.ru>
 S: Maintained
 F: audio/
+F: hw/audio/
 
 Block
 M: Kevin Wolf <kwolf@redhat.com>
@@ -615,6 +630,7 @@ M: Stefan Hajnoczi <stefanha@redhat.com>
 S: Supported
 F: block*
 F: block/
+F: hw/block/
 
 Character Devices
 M: Anthony Liguori <aliguori@us.ibm.com>
@@ -646,7 +662,7 @@ S: Supported
 F: ui/qemu-spice.h
 F: ui/spice-*.c
 F: audio/spiceaudio.c
-F: hw/qxl*
+F: hw/display/qxl*
 
 Graphics
 M: Anthony Liguori <aliguori@us.ibm.com>
index 80344d9436c5b4613e7e14fb5b57480efc3019d0..0b6e6a137fbd5831c0e65b4294d6e46136f453d4 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -76,7 +76,10 @@ config-all-devices.mak:
        $(call quiet-command,echo '# no devices' > $@,"  GEN   $@")
 else
 config-all-devices.mak: $(SUBDIR_DEVICES_MAK)
-       $(call quiet-command,cat $(SUBDIR_DEVICES_MAK) | grep =y | sort -u > $@,"  GEN   $@")
+       $(call quiet-command, sed -n \
+             's|^\([^=]*\)=\(.*\)$$|\1:=$$(findstring y,$$(\1)\2)|p' \
+             $(SUBDIR_DEVICES_MAK) | sort -u > $@, \
+             "  GEN   $@")
 endif
 
 -include $(SUBDIR_DEVICES_MAK_DEP)
index f99841ce5495e0b8360f73d17a2d502adeb54b04..e568c018b33fb23db709df73d7b55507cb449bdb 100644 (file)
@@ -16,16 +16,7 @@ block-obj-y += qapi-types.o qapi-visit.o
 
 block-obj-y += qemu-coroutine.o qemu-coroutine-lock.o qemu-coroutine-io.o
 block-obj-y += qemu-coroutine-sleep.o
-ifeq ($(CONFIG_UCONTEXT_COROUTINE),y)
-block-obj-$(CONFIG_POSIX) += coroutine-ucontext.o
-else
-ifeq ($(CONFIG_SIGALTSTACK_COROUTINE),y)
-block-obj-$(CONFIG_POSIX) += coroutine-sigaltstack.o
-else
-block-obj-$(CONFIG_POSIX) += coroutine-gthread.o
-endif
-endif
-block-obj-$(CONFIG_WIN32) += coroutine-win32.o
+block-obj-y += coroutine-$(CONFIG_COROUTINE_BACKEND).o
 
 ifeq ($(CONFIG_VIRTIO)$(CONFIG_VIRTFS)$(CONFIG_PCI),yyy)
 # Lots of the fsdev/9pcode is pulled in by vl.c via qemu_fsdev_add.
index c2cbc71c31cf3be31ed6e0b9480f9cf001507655..769ce77e61dc826b7037dc12ee1f1e30419bc8dd 100644 (file)
 #include "qemu/bitmap.h"
 #include "sysemu/arch_init.h"
 #include "audio/audio.h"
-#include "hw/pc.h"
+#include "hw/i386/pc.h"
 #include "hw/pci/pci.h"
-#include "hw/audiodev.h"
+#include "hw/audio/audio.h"
 #include "sysemu/kvm.h"
 #include "migration/migration.h"
 #include "exec/gdbstub.h"
-#include "hw/smbios.h"
+#include "hw/i386/smbios.h"
 #include "exec/address-spaces.h"
-#include "hw/pcspk.h"
+#include "hw/audio/pcspk.h"
 #include "migration/page_cache.h"
 #include "qemu/config-file.h"
 #include "qmp-commands.h"
diff --git a/block.c b/block.c
index 0ae2e93982f6dcc3cd94e7e56eefb901227891ec..602d8a443ef6aecdf7273741792c1ba06065c390 100644 (file)
--- a/block.c
+++ b/block.c
@@ -140,8 +140,6 @@ void bdrv_io_limits_disable(BlockDriverState *bs)
 
     bs->slice_start = 0;
     bs->slice_end   = 0;
-    bs->slice_time  = 0;
-    memset(&bs->io_base, 0, sizeof(bs->io_base));
 }
 
 static void bdrv_block_timer(void *opaque)
@@ -1433,11 +1431,10 @@ static void bdrv_move_feature_fields(BlockDriverState *bs_dest,
     bs_dest->enable_write_cache = bs_src->enable_write_cache;
 
     /* i/o timing parameters */
-    bs_dest->slice_time         = bs_src->slice_time;
     bs_dest->slice_start        = bs_src->slice_start;
     bs_dest->slice_end          = bs_src->slice_end;
+    bs_dest->slice_submitted    = bs_src->slice_submitted;
     bs_dest->io_limits          = bs_src->io_limits;
-    bs_dest->io_base            = bs_src->io_base;
     bs_dest->throttled_reqs     = bs_src->throttled_reqs;
     bs_dest->block_timer        = bs_src->block_timer;
     bs_dest->io_limits_enabled  = bs_src->io_limits_enabled;
@@ -3750,6 +3747,7 @@ static bool bdrv_exceed_bps_limits(BlockDriverState *bs, int nb_sectors,
                  bool is_write, double elapsed_time, uint64_t *wait)
 {
     uint64_t bps_limit = 0;
+    uint64_t extension;
     double   bytes_limit, bytes_base, bytes_res;
     double   slice_time, wait_time;
 
@@ -3768,9 +3766,9 @@ static bool bdrv_exceed_bps_limits(BlockDriverState *bs, int nb_sectors,
     slice_time = bs->slice_end - bs->slice_start;
     slice_time /= (NANOSECONDS_PER_SECOND);
     bytes_limit = bps_limit * slice_time;
-    bytes_base  = bs->nr_bytes[is_write] - bs->io_base.bytes[is_write];
+    bytes_base  = bs->slice_submitted.bytes[is_write];
     if (bs->io_limits.bps[BLOCK_IO_LIMIT_TOTAL]) {
-        bytes_base += bs->nr_bytes[!is_write] - bs->io_base.bytes[!is_write];
+        bytes_base += bs->slice_submitted.bytes[!is_write];
     }
 
     /* bytes_base: the bytes of data which have been read/written; and
@@ -3797,10 +3795,12 @@ static bool bdrv_exceed_bps_limits(BlockDriverState *bs, int nb_sectors,
      * info can be kept until the timer fire, so it is increased and tuned
      * based on the result of experiment.
      */
-    bs->slice_time = wait_time * BLOCK_IO_SLICE_TIME * 10;
-    bs->slice_end += bs->slice_time - 3 * BLOCK_IO_SLICE_TIME;
+    extension = wait_time * NANOSECONDS_PER_SECOND;
+    extension = DIV_ROUND_UP(extension, BLOCK_IO_SLICE_TIME) *
+                BLOCK_IO_SLICE_TIME;
+    bs->slice_end += extension;
     if (wait) {
-        *wait = wait_time * BLOCK_IO_SLICE_TIME * 10;
+        *wait = wait_time * NANOSECONDS_PER_SECOND;
     }
 
     return true;
@@ -3828,9 +3828,9 @@ static bool bdrv_exceed_iops_limits(BlockDriverState *bs, bool is_write,
     slice_time = bs->slice_end - bs->slice_start;
     slice_time /= (NANOSECONDS_PER_SECOND);
     ios_limit  = iops_limit * slice_time;
-    ios_base   = bs->nr_ops[is_write] - bs->io_base.ios[is_write];
+    ios_base   = bs->slice_submitted.ios[is_write];
     if (bs->io_limits.iops[BLOCK_IO_LIMIT_TOTAL]) {
-        ios_base += bs->nr_ops[!is_write] - bs->io_base.ios[!is_write];
+        ios_base += bs->slice_submitted.ios[!is_write];
     }
 
     if (ios_base + 1 <= ios_limit) {
@@ -3841,7 +3841,7 @@ static bool bdrv_exceed_iops_limits(BlockDriverState *bs, bool is_write,
         return false;
     }
 
-    /* Calc approx time to dispatch */
+    /* Calc approx time to dispatch, in seconds */
     wait_time = (ios_base + 1) / iops_limit;
     if (wait_time > elapsed_time) {
         wait_time = wait_time - elapsed_time;
@@ -3849,10 +3849,10 @@ static bool bdrv_exceed_iops_limits(BlockDriverState *bs, bool is_write,
         wait_time = 0;
     }
 
-    bs->slice_time = wait_time * BLOCK_IO_SLICE_TIME * 10;
-    bs->slice_end += bs->slice_time - 3 * BLOCK_IO_SLICE_TIME;
+    /* Exceeded current slice, extend it by another slice time */
+    bs->slice_end += BLOCK_IO_SLICE_TIME;
     if (wait) {
-        *wait = wait_time * BLOCK_IO_SLICE_TIME * 10;
+        *wait = wait_time * NANOSECONDS_PER_SECOND;
     }
 
     return true;
@@ -3867,19 +3867,10 @@ static bool bdrv_exceed_io_limits(BlockDriverState *bs, int nb_sectors,
     int      bps_ret, iops_ret;
 
     now = qemu_get_clock_ns(vm_clock);
-    if ((bs->slice_start < now)
-        && (bs->slice_end > now)) {
-        bs->slice_end = now + bs->slice_time;
-    } else {
-        bs->slice_time  =  5 * BLOCK_IO_SLICE_TIME;
+    if (now > bs->slice_end) {
         bs->slice_start = now;
-        bs->slice_end   = now + bs->slice_time;
-
-        bs->io_base.bytes[is_write]  = bs->nr_bytes[is_write];
-        bs->io_base.bytes[!is_write] = bs->nr_bytes[!is_write];
-
-        bs->io_base.ios[is_write]    = bs->nr_ops[is_write];
-        bs->io_base.ios[!is_write]   = bs->nr_ops[!is_write];
+        bs->slice_end   = now + BLOCK_IO_SLICE_TIME;
+        memset(&bs->slice_submitted, 0, sizeof(bs->slice_submitted));
     }
 
     elapsed_time  = now - bs->slice_start;
@@ -3907,6 +3898,10 @@ static bool bdrv_exceed_io_limits(BlockDriverState *bs, int nb_sectors,
         *wait = 0;
     }
 
+    bs->slice_submitted.bytes[is_write] += (int64_t)nb_sectors *
+                                           BDRV_SECTOR_SIZE;
+    bs->slice_submitted.ios[is_write]++;
+
     return false;
 }
 
index 51a28894522a94b992bfbd1473e3788d3b40aa4c..92d6eae76f2f5b61e7aec9c6f08f375bdd38f1c4 100644 (file)
 #include "qemu/error-report.h"
 #include "block/block_int.h"
 #include "trace.h"
-#include "hw/scsi-defs.h"
+#include "block/scsi.h"
 
 #include <iscsi/iscsi.h>
 #include <iscsi/scsi-lowlevel.h>
 
 #ifdef __linux__
 #include <scsi/sg.h>
-#include <hw/scsi-defs.h>
+#include <block/scsi.h>
 #endif
 
 typedef struct IscsiLun {
index c38e970bf2adc58c9158daa3d51e0957dcbb9233..b32738f8d9ce6a8f34d2550759699ac9487a48a3 100644 (file)
@@ -747,10 +747,9 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
     if (l1_table_offset != s->l1_table_offset) {
         l1_table = g_malloc0(align_offset(l1_size2, 512));
         l1_allocated = 1;
-        if (bdrv_pread(bs->file, l1_table_offset,
-                       l1_table, l1_size2) != l1_size2)
-        {
-            ret = -EIO;
+
+        ret = bdrv_pread(bs->file, l1_table_offset, l1_table, l1_size2);
+        if (ret < 0) {
             goto fail;
         }
 
@@ -802,7 +801,7 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
                         }
 
                         if (refcount < 0) {
-                            ret = -EIO;
+                            ret = refcount;
                             goto fail;
                         }
                     }
@@ -833,7 +832,7 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
                 refcount = get_refcount(bs, l2_offset >> s->cluster_bits);
             }
             if (refcount < 0) {
-                ret = -EIO;
+                ret = refcount;
                 goto fail;
             } else if (refcount == 1) {
                 l2_offset |= QCOW_OFLAG_COPIED;
@@ -852,14 +851,16 @@ fail:
     }
 
     /* Update L1 only if it isn't deleted anyway (addend = -1) */
-    if (addend >= 0 && l1_modified) {
-        for(i = 0; i < l1_size; i++)
+    if (ret == 0 && addend >= 0 && l1_modified) {
+        for (i = 0; i < l1_size; i++) {
             cpu_to_be64s(&l1_table[i]);
-        if (bdrv_pwrite_sync(bs->file, l1_table_offset, l1_table,
-                        l1_size2) < 0)
-            goto fail;
-        for(i = 0; i < l1_size; i++)
+        }
+
+        ret = bdrv_pwrite_sync(bs->file, l1_table_offset, l1_table, l1_size2);
+
+        for (i = 0; i < l1_size; i++) {
             be64_to_cpus(&l1_table[i]);
+        }
     }
     if (l1_allocated)
         g_free(l1_table);
index dc4e9a2462c0909b23853257adde7ee2968cf896..95f10c81e3faae3cf16c4f405e44e763e2e4df52 100644 (file)
@@ -10,7 +10,7 @@
  */
 
 #include "sysemu/blockdev.h"
-#include "hw/block-common.h"
+#include "hw/block/block.h"
 #include "monitor/monitor.h"
 #include "qapi/qmp/qerror.h"
 #include "sysemu/sysemu.h"
index 8cdc9ce16ae5f50e35af226c5e07ea7241606117..8a1652b7224ee3a756e1a453f5f196de62ee2f2b 100644 (file)
@@ -31,7 +31,7 @@
  */
 
 #include "sysemu/blockdev.h"
-#include "hw/block-common.h"
+#include "hw/block/block.h"
 #include "block/blockjob.h"
 #include "monitor/monitor.h"
 #include "qapi/qmp/qerror.h"
@@ -1069,7 +1069,6 @@ void qmp_block_set_io_throttle(const char *device, int64_t bps, int64_t bps_rd,
     }
 
     bs->io_limits = io_limits;
-    bs->slice_time = BLOCK_IO_SLICE_TIME;
 
     if (!bs->io_limits_enabled && bdrv_io_limits_enabled(bs)) {
         bdrv_io_limits_enable(bs);
index d685275c61fe88a0e70bed35b82544b9d59e1c10..1ed939a3ac9f9344795ba884827694b75af61b4a 100755 (executable)
--- a/configure
+++ b/configure
@@ -27,6 +27,17 @@ printf " '%s'" "$0" "$@" >> config.log
 echo >> config.log
 echo "#" >> config.log
 
+error_exit() {
+    echo
+    echo "ERROR: $1"
+    while test -n "$2"; do
+        echo "       $2"
+        shift
+    done
+    echo
+    exit 1
+}
+
 do_cc() {
     # Run the compiler, capturing its output to the log.
     echo $cc "$@" >> config.log
@@ -46,11 +57,10 @@ do_cc() {
     esac
     echo $cc -Werror "$@" >> config.log
     $cc -Werror "$@" >> config.log 2>&1 && return $?
-    echo "ERROR: configure test passed without -Werror but failed with -Werror."
-    echo "This is probably a bug in the configure script. The failing command"
-    echo "will be at the bottom of config.log."
-    echo "You can run configure with --disable-werror to bypass this check."
-    exit 1
+    error_exit "configure test passed without -Werror but failed with -Werror." \
+        "This is probably a bug in the configure script. The failing command" \
+        "will be at the bottom of config.log." \
+        "You can run configure with --disable-werror to bypass this check."
 }
 
 compile_object() {
@@ -494,11 +504,10 @@ SunOS)
         LDFLAGS="-L/opt/SUNWspro/prod/lib -R/opt/SUNWspro/prod/lib $LDFLAGS"
         LIBS="-lsunmath $LIBS"
       else
-        echo "QEMU will not link correctly on Solaris 8/X86 or 9/x86 without"
-        echo "libsunmath from the Sun Studio compilers tools, due to a lack of"
-        echo "C99 math features in libm.so in Solaris 8/x86 and Solaris 9/x86"
-        echo "Studio 11 can be downloaded from www.sun.com."
-        exit 1
+        error_exit "QEMU will not link correctly on Solaris 8/X86 or 9/x86 without" \
+            "libsunmath from the Sun Studio compilers tools, due to a lack of" \
+            "C99 math features in libm.so in Solaris 8/x86 and Solaris 9/x86" \
+            "Studio 11 can be downloaded from www.sun.com."
       fi
     fi
   fi
@@ -1185,8 +1194,7 @@ if test "$ARCH" = "unknown"; then
         echo "Unsupported CPU = $cpu, will use TCG with TCI (experimental)"
         ARCH=tci
     else
-        echo "Unsupported CPU = $cpu, try --enable-tcg-interpreter"
-        exit 1
+        error_exit "Unsupported CPU = $cpu, try --enable-tcg-interpreter"
     fi
 fi
 
@@ -1198,8 +1206,7 @@ EOF
 if compile_object ; then
   : C compiler works ok
 else
-    echo "ERROR: \"$cc\" either does not exist or does not work"
-    exit 1
+    error_exit "\"$cc\" either does not exist or does not work"
 fi
 
 # Consult white-list to determine whether to enable werror
@@ -1254,8 +1261,7 @@ fi
 
 if test "$static" = "yes" ; then
   if test "$pie" = "yes" ; then
-    echo "static and pie are mutually incompatible"
-    exit 1
+    error_exit "static and pie are mutually incompatible"
   else
     pie="no"
   fi
@@ -1294,8 +1300,7 @@ EOF
     fi
   else
     if test "$pie" = "yes"; then
-      echo "PIE not available due to missing toolchain support"
-      exit 1
+      error_exit "PIE not available due to missing toolchain support"
     else
       echo "Disabling PIE due to missing toolchain support"
       pie="no"
@@ -1310,40 +1315,36 @@ if test "$solaris" = "yes" ; then
   if has $install; then
     :
   else
-    echo "Solaris install program not found. Use --install=/usr/ucb/install or"
-    echo "install fileutils from www.blastwave.org using pkg-get -i fileutils"
-    echo "to get ginstall which is used by default (which lives in /opt/csw/bin)"
-    exit 1
+    error_exit "Solaris install program not found. Use --install=/usr/ucb/install or" \
+        "install fileutils from www.blastwave.org using pkg-get -i fileutils" \
+        "to get ginstall which is used by default (which lives in /opt/csw/bin)"
   fi
   if test "`path_of $install`" = "/usr/sbin/install" ; then
-    echo "Error: Solaris /usr/sbin/install is not an appropriate install program."
-    echo "try ginstall from the GNU fileutils available from www.blastwave.org"
-    echo "using pkg-get -i fileutils, or use --install=/usr/ucb/install"
-    exit 1
+    error_exit "Solaris /usr/sbin/install is not an appropriate install program." \
+        "try ginstall from the GNU fileutils available from www.blastwave.org" \
+        "using pkg-get -i fileutils, or use --install=/usr/ucb/install"
   fi
   if has ar; then
     :
   else
-    echo "Error: No path includes ar"
     if test -f /usr/ccs/bin/ar ; then
-      echo "Add /usr/ccs/bin to your path and rerun configure"
+      error_exit "No path includes ar" \
+          "Add /usr/ccs/bin to your path and rerun configure"
     fi
-    exit 1
+    error_exit "No path includes ar"
   fi
 fi
 
 if ! has $python; then
-  echo "Python not found. Use --python=/path/to/python"
-  exit 1
+  error_exit "Python not found. Use --python=/path/to/python"
 fi
 
 # Note that if the Python conditional here evaluates True we will exit
 # with status 1 which is a shell 'false' value.
 if ! "$python" -c 'import sys; sys.exit(sys.version_info < (2,4) or sys.version_info >= (3,))'; then
-  echo "Cannot use '$python', Python 2.4 or later is required."
-  echo "Note that Python 3 or later is not yet supported."
-  echo "Use --python=/path/to/python to specify a supported Python."
-  exit 1
+  error_exit "Cannot use '$python', Python 2.4 or later is required." \
+      "Note that Python 3 or later is not yet supported." \
+      "Use --python=/path/to/python to specify a supported Python."
 fi
 
 if test -z "${target_list+xxx}" ; then
@@ -1362,11 +1363,8 @@ esac
 feature_not_found() {
   feature=$1
 
-  echo "ERROR"
-  echo "ERROR: User requested feature $feature"
-  echo "ERROR: configure was not able to find it"
-  echo "ERROR"
-  exit 1;
+  error_exit "User requested feature $feature" \
+      "configure was not able to find it"
 }
 
 if test -z "$cross_prefix" ; then
@@ -1408,8 +1406,7 @@ fi
 # pkg-config probe
 
 if ! has "$pkg_config_exe"; then
-  echo "Error: pkg-config binary '$pkg_config_exe' not found"
-  exit 1
+  error_exit "pkg-config binary '$pkg_config_exe' not found"
 fi
 
 ##########################################
@@ -1448,11 +1445,8 @@ EOF
     if compile_prog "" "-lz" ; then
         :
     else
-        echo
-        echo "Error: zlib check failed"
-        echo "Make sure to have the zlib libs and headers installed."
-        echo
-        exit 1
+        error_exit "zlib check failed" \
+            "Make sure to have the zlib libs and headers installed."
     fi
 fi
 
@@ -1629,14 +1623,12 @@ if test "$xen_pci_passthrough" != "no"; then
     xen_pci_passthrough=yes
   else
     if test "$xen_pci_passthrough" = "yes"; then
-      echo "ERROR"
-      echo "ERROR: User requested feature Xen PCI Passthrough"
-      echo "ERROR: but this feature require /sys from Linux"
       if test "$xen_ctrl_version" -lt 340; then
-        echo "ERROR: This feature does not work with Xen 3.3"
+        error_exit "User requested feature Xen PCI Passthrough" \
+            "This feature does not work with Xen 3.3"
       fi
-      echo "ERROR"
-      exit 1;
+      error_exit "User requested feature Xen PCI Passthrough" \
+          " but this feature requires /sys from Linux"
     fi
     xen_pci_passthrough=no
   fi
@@ -2010,11 +2002,8 @@ EOF
     if compile_prog "$cfl" "$lib" ; then
         :
     else
-        echo
-        echo "Error: $drv check failed"
-        echo "Make sure to have the $drv libs and headers installed."
-        echo
-        exit 1
+        error_exit "$drv check failed" \
+            "Make sure to have the $drv libs and headers installed."
     fi
 }
 
@@ -2029,11 +2018,8 @@ for drv in $audio_drv_list; do
 
     fmod)
     if test -z $fmod_lib || test -z $fmod_inc; then
-        echo
-        echo "Error: You must specify path to FMOD library and headers"
-        echo "Example: --fmod-inc=/path/include/fmod --fmod-lib=/path/lib/libfmod-3.74.so"
-        echo
-        exit 1
+        error_exit "You must specify path to FMOD library and headers" \
+            "Example: --fmod-inc=/path/include/fmod --fmod-lib=/path/lib/libfmod-3.74.so"
     fi
     audio_drv_probe $drv fmod.h $fmod_lib "return FSOUND_GetVersion();" "-I $fmod_inc"
     libs_softmmu="$fmod_lib $libs_softmmu"
@@ -2076,11 +2062,8 @@ for drv in $audio_drv_list; do
 
     *)
     echo "$audio_possible_drivers" | grep -q "\<$drv\>" || {
-        echo
-        echo "Error: Unknown driver '$drv' selected"
-        echo "Possible drivers are: $audio_possible_drivers"
-        echo
-        exit 1
+        error_exit "Unknown driver '$drv' selected" \
+            "Possible drivers are: $audio_possible_drivers"
     }
     ;;
     esac
@@ -2209,8 +2192,7 @@ then
     LIBS="$glib_libs $LIBS"
     libs_qga="$glib_libs $libs_qga"
 else
-    echo "glib-$glib_req_ver required to compile QEMU"
-    exit 1
+    error_exit "glib-$glib_req_ver required to compile QEMU"
 fi
 
 ##########################################
@@ -2227,11 +2209,10 @@ if test "$pixman" = ""; then
 fi
 if test "$pixman" = "none"; then
   if test "$want_tools" != "no" -o "$softmmu" != "no"; then
-    echo "ERROR: pixman disabled but system emulation or tools build"
-    echo "       enabled.  You can turn off pixman only if you also"
-    echo "       disable all system emulation targets and the tools"
-    echo "       build with '--disable-tools --disable-system'."
-    exit 1
+    error_exit "pixman disabled but system emulation or tools build" \
+        "enabled.  You can turn off pixman only if you also" \
+        "disable all system emulation targets and the tools" \
+        "build with '--disable-tools --disable-system'."
   fi
   pixman_cflags=
   pixman_libs=
@@ -2240,12 +2221,11 @@ elif test "$pixman" = "system"; then
   pixman_libs=`$pkg_config --libs pixman-1 2>/dev/null`
 else
   if test ! -d ${source_path}/pixman/pixman; then
-    echo "ERROR: pixman not present. Your options:"
-    echo "  (1) Preferred: Install the pixman devel package (any recent"
-    echo "      distro should have packages as Xorg needs pixman too)."
-    echo "  (2) Fetch the pixman submodule, using:"
-    echo "      git submodule update --init pixman"
-    exit 1
+    error_exit "pixman not present. Your options:" \
+        "  (1) Preferred: Install the pixman devel package (any recent" \
+        "      distro should have packages as Xorg needs pixman too)." \
+        "  (2) Fetch the pixman submodule, using:" \
+        "      git submodule update --init pixman"
   fi
   mkdir -p pixman/pixman
   pixman_cflags="-I\$(SRC_PATH)/pixman/pixman -I\$(BUILD_DIR)/pixman/pixman"
@@ -2304,11 +2284,8 @@ else
 fi
 
 if test "$mingw32" != yes -a "$pthread" = no; then
-  echo
-  echo "Error: pthread check failed"
-  echo "Make sure to have the pthread libs and headers installed."
-  echo
-  exit 1
+  error_exit "pthread check failed" \
+      "Make sure to have the pthread libs and headers installed."
 fi
 
 ##########################################
@@ -2363,8 +2340,7 @@ fi
 
 if test "$virtio_blk_data_plane" = "yes" -a \
        "$linux_aio" != "yes" ; then
-  echo "Error: virtio-blk-data-plane requires Linux AIO, please try --enable-linux-aio"
-  exit 1
+  error_exit "virtio-blk-data-plane requires Linux AIO, please try --enable-linux-aio"
 elif test -z "$virtio_blk_data_plane" ; then
   virtio_blk_data_plane=$linux_aio
 fi
@@ -2861,10 +2837,7 @@ elif compile_prog "" "-lm" ; then
   LIBS="-lm $LIBS"
   libs_qga="-lm $libs_qga"
 else
-  echo
-  echo "Error: libm check failed"
-  echo
-  exit 1
+  error_exit "libm check failed"
 fi
 
 ##########################################
@@ -3040,11 +3013,8 @@ fi
 
 $python "$source_path/scripts/tracetool.py" "--backend=$trace_backend" --check-backend  > /dev/null 2> /dev/null
 if test "$?" -ne 0 ; then
-  echo
-  echo "Error: invalid trace backend"
-  echo "Please choose a supported trace backend."
-  echo
-  exit 1
+  error_exit "invalid trace backend" \
+      "Please choose a supported trace backend."
 fi
 
 ##########################################
@@ -3059,10 +3029,7 @@ EOF
     LIBS="-lust -lurcu-bp $LIBS"
     libs_qga="-lust -lurcu-bp $libs_qga"
   else
-    echo
-    echo "Error: Trace backend 'ust' missing libust header files"
-    echo
-    exit 1
+    error_exit "Trace backend 'ust' missing libust header files"
   fi
 fi
 
@@ -3070,10 +3037,7 @@ fi
 # For 'dtrace' backend, test if 'dtrace' command is present
 if test "$trace_backend" = "dtrace"; then
   if ! has 'dtrace' ; then
-    echo
-    echo "Error: dtrace command is not found in PATH $PATH"
-    echo
-    exit 1
+    error_exit "dtrace command is not found in PATH $PATH"
   fi
   trace_backend_stap="no"
   if has 'stap' ; then
@@ -3107,34 +3071,58 @@ fi
 ##########################################
 # check and set a backend for coroutine
 
-# default is ucontext, but always fallback to gthread
-# windows autodetected by make
-if test "$coroutine" = "" -o "$coroutine" = "ucontext"; then
-  if test "$darwin" != "yes"; then
-    cat > $TMPC << EOF
+# We prefer ucontext, but it's not always possible. The fallback
+# is sigcontext. gthread is not selectable except explicitly, because
+# it is not functional enough to run QEMU proper. (It is occasionally
+# useful for debugging purposes.)  On Windows the only valid backend
+# is the Windows-specific one.
+
+ucontext_works=no
+if test "$darwin" != "yes"; then
+  cat > $TMPC << EOF
 #include <ucontext.h>
 #ifdef __stub_makecontext
 #error Ignoring glibc stub makecontext which will always fail
 #endif
 int main(void) { makecontext(0, 0, 0); return 0; }
 EOF
-    if compile_prog "" "" ; then
-        coroutine_backend=ucontext
-    else
-       coroutine_backend=gthread
-    fi
+  if compile_prog "" "" ; then
+    ucontext_works=yes
+  fi
+fi
+
+if test "$coroutine" = ""; then
+  if test "$mingw32" = "yes"; then
+    coroutine=win32
+  elif test "$ucontext_works" = "yes"; then
+    coroutine=ucontext
+  else
+    coroutine=sigaltstack
   fi
-elif test "$coroutine" = "gthread" ; then
-  coroutine_backend=gthread
-elif test "$coroutine" = "windows" ; then
-  coroutine_backend=windows
-elif test "$coroutine" = "sigaltstack" ; then
-  coroutine_backend=sigaltstack
 else
-  echo
-  echo "Error: unknown coroutine backend $coroutine"
-  echo
-  exit 1
+  case $coroutine in
+  windows)
+    if test "$mingw32" != "yes"; then
+      error_exit "'windows' coroutine backend only valid for Windows"
+    fi
+    # Unfortunately the user visible backend name doesn't match the
+    # coroutine-*.c filename for this case, so we have to adjust it here.
+    coroutine=win32
+    ;;
+  ucontext)
+    if test "$ucontext_works" != "yes"; then
+      feature_not_found "ucontext"
+    fi
+    ;;
+  gthread|sigaltstack)
+    if test "$mingw32" = "yes"; then
+      error_exit "only the 'windows' coroutine backend is valid for Windows"
+    fi
+    ;;
+  *)
+    error_exit "unknown coroutine backend $coroutine"
+    ;;
+  esac
 fi
 
 ##########################################
@@ -3319,8 +3307,7 @@ if test "$softmmu" = yes ; then
       tools="$tools fsdev/virtfs-proxy-helper\$(EXESUF)"
     else
       if test "$virtfs" = yes; then
-        echo "VirtFS is supported only on Linux and requires libcap-devel and libattr-devel"
-        exit 1
+        error_exit "VirtFS is supported only on Linux and requires libcap-devel and libattr-devel"
       fi
       virtfs=no
     fi
@@ -3442,7 +3429,7 @@ echo "GLX support       $glx"
 echo "libiscsi support  $libiscsi"
 echo "build guest agent $guest_agent"
 echo "seccomp support   $seccomp"
-echo "coroutine backend $coroutine_backend"
+echo "coroutine backend $coroutine"
 echo "GlusterFS support $glusterfs"
 echo "virtio-blk-data-plane $virtio_blk_data_plane"
 echo "gcov              $gcov_tool"
@@ -3775,11 +3762,7 @@ if test "$rbd" = "yes" ; then
   echo "CONFIG_RBD=y" >> $config_host_mak
 fi
 
-if test "$coroutine_backend" = "ucontext" ; then
-  echo "CONFIG_UCONTEXT_COROUTINE=y" >> $config_host_mak
-elif test "$coroutine_backend" = "sigaltstack" ; then
-  echo "CONFIG_SIGALTSTACK_COROUTINE=y" >> $config_host_mak
-fi
+echo "CONFIG_COROUTINE_BACKEND=$coroutine" >> $config_host_mak
 
 if test "$open_by_handle_at" = "yes" ; then
   echo "CONFIG_OPEN_BY_HANDLE=y" >> $config_host_mak
@@ -3814,7 +3797,7 @@ if test "$glusterfs" = "yes" ; then
 fi
 
 if test "$virtio_blk_data_plane" = "yes" ; then
-  echo "CONFIG_VIRTIO_BLK_DATA_PLANE=y" >> $config_host_mak
+  echo 'CONFIG_VIRTIO_BLK_DATA_PLANE=$(CONFIG_VIRTIO)' >> $config_host_mak
 fi
 
 # USB host support
@@ -3967,22 +3950,20 @@ case "$target" in
     ;;
   ${target_arch2}-linux-user)
     if test "$linux" != "yes" ; then
-      echo "ERROR: Target '$target' is only available on a Linux host"
-      exit 1
+      error_exit "Target '$target' is only available on a Linux host"
     fi
     target_user_only="yes"
     target_linux_user="yes"
     ;;
   ${target_arch2}-bsd-user)
     if test "$bsd" != "yes" ; then
-      echo "ERROR: Target '$target' is only available on a BSD host"
-      exit 1
+      error_exit "Target '$target' is only available on a BSD host"
     fi
     target_user_only="yes"
     target_bsd_user="yes"
     ;;
   *)
-    echo "ERROR: Target '$target' not recognised"
+    error_exit "Target '$target' not recognised"
     exit 1
     ;;
 esac
@@ -4113,8 +4094,7 @@ case "$target_arch2" in
     TARGET_ARCH=xtensa
   ;;
   *)
-    echo "Unsupported target CPU"
-    exit 1
+    error_exit "Unsupported target CPU"
   ;;
 esac
 # TARGET_BASE_ARCH needs to be defined after TARGET_ARCH
index 2dbee94c89d8fb26077754d886866a4ba6ccf582..18e5337a774d466c92f09a636934b86e5f4bf739 100644 (file)
@@ -13,3 +13,4 @@ CONFIG_IDE_QDEV=y
 CONFIG_VMWARE_VGA=y
 CONFIG_IDE_CMD646=y
 CONFIG_I8259=y
+CONFIG_MC146818RTC=y
index ab8703578e6b11ec94a7bfdd5b479a29a5e2c28a..31725a97f91193ccdcce5bcce95fa7421a49ccfd 100644 (file)
@@ -16,7 +16,9 @@ CONFIG_TWL92230=y
 CONFIG_TSC2005=y
 CONFIG_LM832X=y
 CONFIG_TMP105=y
+CONFIG_STELLARIS=y
 CONFIG_STELLARIS_INPUT=y
+CONFIG_STELLARIS_ENET=y
 CONFIG_SSD0303=y
 CONFIG_SSD0323=y
 CONFIG_ADS7846=y
@@ -29,8 +31,17 @@ CONFIG_SMC91C111=y
 CONFIG_DS1338=y
 CONFIG_PFLASH_CFI01=y
 CONFIG_PFLASH_CFI02=y
+CONFIG_MICRODRIVE=y
+CONFIG_USB_MUSB=y
 
+CONFIG_ARM5MPCORE=y
+CONFIG_ARM9MPCORE=y
+CONFIG_ARM15MPCORE=y
+
+CONFIG_ARM_GIC=y
+CONFIG_ARM_GIC_KVM=$(CONFIG_KVM)
 CONFIG_ARM_TIMER=y
+CONFIG_ARM_MPTIMER=y
 CONFIG_PL011=y
 CONFIG_PL022=y
 CONFIG_PL031=y
@@ -45,6 +56,25 @@ CONFIG_PL310=y
 CONFIG_PL330=y
 CONFIG_CADENCE=y
 CONFIG_XGMAC=y
+CONFIG_EXYNOS4=y
+CONFIG_PXA2XX=y
+CONFIG_BITBANG_I2C=y
+CONFIG_FRAMEBUFFER=y
+CONFIG_XILINX_SPIPS=y
+
+CONFIG_A9SCU=y
+CONFIG_MARVELL_88W8618=y
+CONFIG_OMAP=y
+CONFIG_TSC210X=y
+CONFIG_BLIZZARD=y
+CONFIG_ONENAND=y
+CONFIG_TUSB6010=y
+CONFIG_IMX=y
+CONFIG_MAINSTONE=y
+CONFIG_NSERIES=y
+CONFIG_REALVIEW=y
+CONFIG_ZAURUS=y
+CONFIG_ZYNQ=y
 
 CONFIG_VERSATILE_PCI=y
 CONFIG_VERSATILE_I2C=y
index 1a479cd8d3ea4b39e9e78dd2fd0294ada830ce24..d970d50158b7429f6209f9d4b71db3e730424545 100644 (file)
@@ -1,5 +1,6 @@
 # Default configuration for cris-softmmu
 
+CONFIG_ETRAXFS=y
 CONFIG_NAND=y
 CONFIG_PTIMER=y
 CONFIG_PFLASH_CFI02=y
index df9e126c1f240093d1a3ac1d5d05ca7828423986..4ac06944706169b9be29e7ae0b5e4a0ec6550c44 100644 (file)
@@ -3,6 +3,7 @@
 include pci.mak
 include usb.mak
 CONFIG_VGA=y
+CONFIG_QXL=$(CONFIG_SPICE)
 CONFIG_VGA_PCI=y
 CONFIG_VGA_ISA=y
 CONFIG_VGA_CIRRUS=y
@@ -16,7 +17,7 @@ CONFIG_PCKBD=y
 CONFIG_FDC=y
 CONFIG_ACPI=y
 CONFIG_APM=y
-CONFIG_DMA=y
+CONFIG_I8257=y
 CONFIG_IDE_ISA=y
 CONFIG_IDE_PIIX=y
 CONFIG_NE2000_ISA=y
@@ -28,3 +29,19 @@ CONFIG_I8259=y
 CONFIG_PFLASH_CFI01=y
 CONFIG_TPM_TIS=y
 CONFIG_TPM_PASSTHROUGH=y
+CONFIG_PCI_HOTPLUG=y
+CONFIG_MC146818RTC=y
+CONFIG_PAM=y
+CONFIG_PCI_PIIX=y
+CONFIG_PCI_HOTPLUG=y
+CONFIG_WDT_IB700=y
+CONFIG_PC_SYSFW=y
+CONFIG_XEN_I386=$(CONFIG_XEN)
+CONFIG_ISA_DEBUG=y
+CONFIG_ISA_TESTDEV=y
+CONFIG_VMPORT=y
+CONFIG_SGA=y
+CONFIG_LPC_ICH9=y
+CONFIG_Q35=y
+CONFIG_APIC=y
+CONFIG_IOAPIC=y
index 0d19974b40b290878201e612e54147b9e3c9f4e8..ef0f4bae72d1776718ad7f522dbab5a37c448327 100644 (file)
@@ -1,5 +1,8 @@
 # Default configuration for lm32-softmmu
 
+CONFIG_LM32=y
+CONFIG_MILKYMIST=y
+CONFIG_FRAMEBUFFER=y
 CONFIG_PTIMER=y
 CONFIG_PFLASH_CFI01=y
 CONFIG_PFLASH_CFI02=y
index 778ea82a10fb7311252c54a84223c13c5bd1ec9a..51fe5bb3215016b32546413db3db8b1f4d35828b 100644 (file)
@@ -2,5 +2,6 @@
 
 include pci.mak
 include usb.mak
+CONFIG_COLDFIRE=y
 CONFIG_GDBSTUB_XML=y
 CONFIG_PTIMER=y
index 2f442e5aea0def706f36f1aa9e5a544d5662d6da..ce2630818ae511fc883a37798d544c84f08f66cd 100644 (file)
@@ -5,5 +5,7 @@ CONFIG_PFLASH_CFI01=y
 CONFIG_SERIAL=y
 CONFIG_XILINX=y
 CONFIG_XILINX_AXI=y
+CONFIG_XILINX_SPI=y
+CONFIG_XILINX_ETHLITE=y
 CONFIG_SSI=y
 CONFIG_SSI_M25P80=y
index af9a3cde0d8e899e96d10ec9ddb978e0e66bb10a..acf22c5bb3175496fc4dcb1596c53212260fcee7 100644 (file)
@@ -5,5 +5,7 @@ CONFIG_PFLASH_CFI01=y
 CONFIG_SERIAL=y
 CONFIG_XILINX=y
 CONFIG_XILINX_AXI=y
+CONFIG_XILINX_SPI=y
+CONFIG_XILINX_ETHLITE=y
 CONFIG_SSI=y
 CONFIG_SSI_M25P80=y
index 4f04a337324f89fe37c30323c9bc4d3da64a0f97..b764360a555c8ae82c819253078a03901200f524 100644 (file)
@@ -18,7 +18,7 @@ CONFIG_PCKBD=y
 CONFIG_FDC=y
 CONFIG_ACPI=y
 CONFIG_APM=y
-CONFIG_DMA=y
+CONFIG_I8257=y
 CONFIG_PIIX4=y
 CONFIG_IDE_ISA=y
 CONFIG_IDE_PIIX=y
@@ -32,3 +32,5 @@ CONFIG_PFLASH_CFI01=y
 CONFIG_G364FB=y
 CONFIG_I8259=y
 CONFIG_JAZZ_LED=y
+CONFIG_MC146818RTC=y
+CONFIG_VT82C686=y
index a5b6c3c36a4fbff34bae61fb8af706d8b9393575..0e4e65d5ebe544d40ec31fdf8bce3aabcb88f510 100644 (file)
@@ -18,7 +18,7 @@ CONFIG_PCKBD=y
 CONFIG_FDC=y
 CONFIG_ACPI=y
 CONFIG_APM=y
-CONFIG_DMA=y
+CONFIG_I8257=y
 CONFIG_PIIX4=y
 CONFIG_IDE_ISA=y
 CONFIG_IDE_PIIX=y
@@ -32,3 +32,5 @@ CONFIG_PFLASH_CFI01=y
 CONFIG_G364FB=y
 CONFIG_I8259=y
 CONFIG_JAZZ_LED=y
+CONFIG_MC146818RTC=y
+CONFIG_VT82C686=y
index a0e6de8e68db02da5c93c532c01d72a369520df8..0a6c4f7ba23ff4b4cadb4c830cbacdc21f277a0d 100644 (file)
@@ -18,7 +18,7 @@ CONFIG_PCKBD=y
 CONFIG_FDC=y
 CONFIG_ACPI=y
 CONFIG_APM=y
-CONFIG_DMA=y
+CONFIG_I8257=y
 CONFIG_PIIX4=y
 CONFIG_IDE_ISA=y
 CONFIG_IDE_PIIX=y
@@ -34,3 +34,5 @@ CONFIG_FULONG=y
 CONFIG_G364FB=y
 CONFIG_I8259=y
 CONFIG_JAZZ_LED=y
+CONFIG_MC146818RTC=y
+CONFIG_VT82C686=y
index 753dd76a218da6272e05ea5aa1be533df3a6d1d3..9f9c6daa562a8f91a01aefe17ebd1de0382d3ecc 100644 (file)
@@ -18,7 +18,7 @@ CONFIG_PCKBD=y
 CONFIG_FDC=y
 CONFIG_ACPI=y
 CONFIG_APM=y
-CONFIG_DMA=y
+CONFIG_I8257=y
 CONFIG_PIIX4=y
 CONFIG_IDE_ISA=y
 CONFIG_IDE_PIIX=y
@@ -32,3 +32,5 @@ CONFIG_PFLASH_CFI01=y
 CONFIG_G364FB=y
 CONFIG_I8259=y
 CONFIG_JAZZ_LED=y
+CONFIG_MC146818RTC=y
+CONFIG_VT82C686=y
index 8ede8d5b2358b5d74f1ec066612af73de49483db..1a954764f36668142d6f876e38a9bab202ae6af8 100644 (file)
@@ -1 +1,5 @@
 # Default configuration for moxie-softmmu
+
+CONFIG_MC146818RTC=y
+CONFIG_SERIAL=y
+CONFIG_VGA=y
index ce56d580558114f612b29d479f304b345c708343..f5f100ecb0d5361ef11c6a9aea5cd666aa8dcdff 100644 (file)
@@ -23,3 +23,4 @@ CONFIG_ESP_PCI=y
 CONFIG_SERIAL=y
 CONFIG_SERIAL_PCI=y
 CONFIG_IPACK=y
+CONFIG_WDT_IB6300ESB=y
index c209a8da65b17bbd04cc8f6fe80d25a8226e5500..50034fc87f157e1d6f066a2dbca9eea51798ce6e 100644 (file)
@@ -13,7 +13,7 @@ CONFIG_PARALLEL=y
 CONFIG_I8254=y
 CONFIG_PCKBD=y
 CONFIG_FDC=y
-CONFIG_DMA=y
+CONFIG_I8257=y
 CONFIG_I82374=y
 CONFIG_OPENPIC=y
 CONFIG_PREP_PCI=y
@@ -40,4 +40,8 @@ CONFIG_PFLASH_CFI02=y
 CONFIG_PTIMER=y
 CONFIG_I8259=y
 CONFIG_XILINX=y
+CONFIG_XILINX_ETHLITE=y
+CONFIG_OPENPIC=y
 CONFIG_E500=$(CONFIG_FDT)
+# For PReP
+CONFIG_MC146818RTC=y
index 8d490bd72eea60c1f5137f6f7596d465c890a1c3..6398d60362e72413e09dacd5f38913b433243346 100644 (file)
@@ -13,7 +13,7 @@ CONFIG_PARALLEL=y
 CONFIG_I8254=y
 CONFIG_PCKBD=y
 CONFIG_FDC=y
-CONFIG_DMA=y
+CONFIG_I8257=y
 CONFIG_I82374=y
 CONFIG_OPENPIC=y
 CONFIG_PREP_PCI=y
@@ -40,5 +40,11 @@ CONFIG_PFLASH_CFI02=y
 CONFIG_PTIMER=y
 CONFIG_I8259=y
 CONFIG_XILINX=y
+CONFIG_XILINX_ETHLITE=y
+CONFIG_OPENPIC=y
 CONFIG_PSERIES=$(CONFIG_FDT)
 CONFIG_E500=$(CONFIG_FDT)
+# For pSeries
+CONFIG_PCI_HOTPLUG=y
+# For PReP
+CONFIG_MC146818RTC=y
index 7f13421d93f59fec373e78d47d09fcffdc3a86f9..05b50d6f00029a33c38ad2a8cc1fc227c61a42ab 100644 (file)
@@ -12,7 +12,7 @@ CONFIG_SERIAL=y
 CONFIG_I8254=y
 CONFIG_PCKBD=y
 CONFIG_FDC=y
-CONFIG_DMA=y
+CONFIG_I8257=y
 CONFIG_OPENPIC=y
 CONFIG_PREP_PCI=y
 CONFIG_MACIO=y
@@ -35,4 +35,8 @@ CONFIG_PFLASH_CFI02=y
 CONFIG_PTIMER=y
 CONFIG_I8259=y
 CONFIG_XILINX=y
+CONFIG_XILINX_ETHLITE=y
+CONFIG_OPENPIC=y
 CONFIG_E500=$(CONFIG_FDT)
+# For PReP
+CONFIG_MC146818RTC=y
index 30057292047c1a905095f0ba2172ea78362a26aa..81fbc6865491bda5494b697efd7c221f7d3c2a7f 100644 (file)
@@ -1 +1,2 @@
 CONFIG_VIRTIO=y
+CONFIG_SCLPCONSOLE=y
index e08b2ee1064ca3a56d1187022f7f9f174a025115..f6bf62d1c22a3f8bd3c904a7e76129e12ddeab12 100644 (file)
@@ -6,3 +6,6 @@ CONFIG_SERIAL=y
 CONFIG_PTIMER=y
 CONFIG_PFLASH_CFI02=y
 CONFIG_ISA_MMIO=y
+CONFIG_SH4=y
+CONFIG_IDE_MMIO=y
+CONFIG_SM501=y
index 3a8453552bdc10342841405cc1ec06f5089e76cf..c1d513d099becb76ab5fb1958fce75a19c846a2a 100644 (file)
@@ -6,3 +6,6 @@ CONFIG_SERIAL=y
 CONFIG_PTIMER=y
 CONFIG_PFLASH_CFI02=y
 CONFIG_ISA_MMIO=y
+CONFIG_SH4=y
+CONFIG_IDE_MMIO=y
+CONFIG_SM501=y
index b0310c51e20c59ba4af9e7b7f5caef5296ddc39d..8fc93dd643322961649a1f6d4fd8531c62bf4f0a 100644 (file)
@@ -8,3 +8,11 @@ CONFIG_PTIMER=y
 CONFIG_FDC=y
 CONFIG_EMPTY_SLOT=y
 CONFIG_PCNET_COMMON=y
+CONFIG_LANCE=y
+CONFIG_TCX=y
+CONFIG_SLAVIO=y
+CONFIG_CS4231=y
+CONFIG_GRLIB=y
+CONFIG_STP2000=y
+CONFIG_ECCMEMCTL=y
+CONFIG_SUN4M=y
index 2145b6b29f4232e066ada1ecb79f4c15e096b8b9..9b08ee8a20568cb3d0483c074e669d9cbf97b9b6 100644 (file)
@@ -13,3 +13,5 @@ CONFIG_PCKBD=y
 CONFIG_FDC=y
 CONFIG_IDE_ISA=y
 CONFIG_IDE_CMD646=y
+CONFIG_PCI_APB=y
+CONFIG_MC146818RTC=y
index ab3cd5fc350be9267d05be9bf6d671d866255459..bf4091c4dda47768fb2f3b5779671a554af7d0e6 100644 (file)
@@ -3,6 +3,7 @@
 include pci.mak
 include usb.mak
 CONFIG_VGA=y
+CONFIG_QXL=$(CONFIG_SPICE)
 CONFIG_VGA_PCI=y
 CONFIG_VGA_ISA=y
 CONFIG_VGA_CIRRUS=y
@@ -16,7 +17,7 @@ CONFIG_PCKBD=y
 CONFIG_FDC=y
 CONFIG_ACPI=y
 CONFIG_APM=y
-CONFIG_DMA=y
+CONFIG_I8257=y
 CONFIG_IDE_ISA=y
 CONFIG_IDE_PIIX=y
 CONFIG_NE2000_ISA=y
@@ -28,3 +29,19 @@ CONFIG_I8259=y
 CONFIG_PFLASH_CFI01=y
 CONFIG_TPM_TIS=y
 CONFIG_TPM_PASSTHROUGH=y
+CONFIG_PCI_HOTPLUG=y
+CONFIG_MC146818RTC=y
+CONFIG_PAM=y
+CONFIG_PCI_PIIX=y
+CONFIG_PCI_HOTPLUG=y
+CONFIG_WDT_IB700=y
+CONFIG_PC_SYSFW=y
+CONFIG_XEN_I386=$(CONFIG_XEN)
+CONFIG_ISA_DEBUG=y
+CONFIG_ISA_TESTDEV=y
+CONFIG_VMPORT=y
+CONFIG_SGA=y
+CONFIG_LPC_ICH9=y
+CONFIG_Q35=y
+CONFIG_APIC=y
+CONFIG_IOAPIC=y
index 43dacdec2833ce2c304e3d344bac05f8b8439b92..c7a445afcd55fe1f12033d529d668a1306d5a9f4 100644 (file)
@@ -11,7 +11,7 @@ one USB 2.0 bus driven by the EHCI controller.  Devices must be
 attached to the correct controller manually.
 
 The '-usb' switch will make qemu create the UHCI controller as part of
-the PIIX3 chipset.  The USB 1.1 bus will carry the name "usb.0".
+the PIIX3 chipset.  The USB 1.1 bus will carry the name "usb-bus.0".
 
 You can use the standard -device switch to add a EHCI controller to
 your virtual machine.  It is strongly recommended to specify an ID for
@@ -27,7 +27,7 @@ a complete example:
         -drive if=none,id=usbstick,file=/path/to/image   \
         -usb                                             \
         -device usb-ehci,id=ehci                         \
-        -device usb-tablet,bus=usb.0                     \
+        -device usb-tablet,bus=usb-bus.0                 \
         -device usb-storage,bus=ehci.0,drive=usbstick
 
 This attaches a usb tablet to the UHCI adapter and a usb mass storage
@@ -88,22 +88,22 @@ ports (1-4), the emulated (1.1) USB hub has eight ports.
 
 Plugging a tablet into UHCI port 1 works like this:
 
-        -device usb-tablet,bus=usb.0,port=1
+        -device usb-tablet,bus=usb-bus.0,port=1
 
 Plugging a hub into UHCI port 2 works like this:
 
-        -device usb-hub,bus=usb.0,port=2
+        -device usb-hub,bus=usb-bus.0,port=2
 
 Plugging a virtual usb stick into port 4 of the hub just plugged works
 this way:
 
-        -device usb-storage,bus=usb.0,port=2.4,drive=...
+        -device usb-storage,bus=usb-bus.0,port=2.4,drive=...
 
 You can do basically the same in the monitor using the device_add
 command.  If you want to unplug devices too you should specify some
 unique id which you can use to refer to the device ...
 
-        (qemu) device_add usb-tablet,bus=usb.0,port=1,id=my-tablet
+        (qemu) device_add usb-tablet,bus=usb-bus.0,port=1,id=my-tablet
         (qemu) device_del my-tablet
 
 ... when unplugging it with device_del.
@@ -148,10 +148,10 @@ using for testing is bus 1 + port 1 for 2.0 devices and bus 3 + port 1
 for 1.1 devices.  Passing through any device plugged into that port
 and also assign them to the correct bus can be done this way:
 
-    qemu -M pc ${otheroptions}                           \
-        -usb                                             \
-        -device usb-ehci,id=ehci                         \
-        -device usb-host,bus=usb.0,hostbus=3,hostport=1  \
+    qemu -M pc ${otheroptions}                               \
+        -usb                                                 \
+        -device usb-ehci,id=ehci                             \
+        -device usb-host,bus=usb-bus.0,hostbus=3,hostport=1  \
         -device usb-host,bus=ehci.0,hostbus=1,hostport=1
 
 enjoy,
diff --git a/exec.c b/exec.c
index 786987a0165dd6acc01a6677957d7019e648d5a7..fa1e0c3d7365d2787eb3908e4cdb25c3d577aff6 100644 (file)
--- a/exec.c
+++ b/exec.c
@@ -31,7 +31,7 @@
 #include "hw/qdev.h"
 #include "qemu/osdep.h"
 #include "sysemu/kvm.h"
-#include "hw/xen.h"
+#include "hw/xen/xen.h"
 #include "qemu/timer.h"
 #include "qemu/config-file.h"
 #include "exec/memory.h"
index a0288a77fb219af89cb8eac1594ce17d8dcb0d6b..22ab12c68cea3d6015a7d65da8fc7c2dc6f3b64c 100644 (file)
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1607,7 +1607,7 @@ static int cpu_gdb_write_register(CPUS390XState *env, uint8_t *mem_buf, int n)
 }
 #elif defined (TARGET_LM32)
 
-#include "hw/lm32_pic.h"
+#include "hw/lm32/lm32_pic.h"
 #define NUM_CORE_REGS (32 + 7)
 
 static int cpu_gdb_read_register(CPULM32State *env, uint8_t *mem_buf, int n)
index d321c802f24745b4c314f9ddc453fded75b894e6..b476b810c57f6a006746121878a0f02fa8cce67d 100644 (file)
  *
  */
 
-#include "hw/virtio.h"
-#include "hw/pc.h"
+#include "hw/virtio/virtio.h"
+#include "hw/virtio/virtio-9p.h"
+#include "hw/i386/pc.h"
 #include "qemu/sockets.h"
 #include "virtio-9p.h"
 #include "fsdev/qemu-fsdev.h"
-#include "virtio-9p-device.h"
 #include "virtio-9p-xattr.h"
 #include "virtio-9p-coth.h"
 
diff --git a/hw/9pfs/virtio-9p-device.h b/hw/9pfs/virtio-9p-device.h
deleted file mode 100644 (file)
index 65789db..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Virtio 9p
- *
- * Copyright IBM, Corp. 2010
- *
- * Authors:
- *  Aneesh Kumar K.V <aneesh.kumar@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.
- *
- */
-
-#ifndef QEMU_VIRTIO_9P_DEVICE_H
-#define QEMU_VIRTIO_9P_DEVICE_H
-
-typedef struct V9fsConf
-{
-    /* tag name for the device */
-    char *tag;
-    char *fsdev_id;
-} V9fsConf;
-
-#endif
index e30fdb6730e68dbf651d5b305446900a3103f7ae..fe8e0ed19dcc9933c60f42792f3bf9ab61ef47cb 100644 (file)
@@ -11,7 +11,7 @@
  *
  */
 
-#include "hw/virtio.h"
+#include "hw/virtio/virtio.h"
 #include "virtio-9p.h"
 #include "virtio-9p-xattr.h"
 #include <arpa/inet.h>
index f1b1c83a2269977ed20f797dc6f1008c30814346..be898eccd91278a0b3f84a1a849eb2aa8338316d 100644 (file)
@@ -11,7 +11,7 @@
  *
  */
 
-#include "hw/virtio.h"
+#include "hw/virtio/virtio.h"
 #include "virtio-9p.h"
 #include "virtio-9p-xattr.h"
 #include <arpa/inet.h>
index 08bb0e8bcaf91105783165aa1d7fd869f93e4ebb..339c5ecae441edf564a09cc4a9af91a14434122f 100644 (file)
@@ -13,7 +13,7 @@
 
 #include <sys/types.h>
 #include "qemu/xattr.h"
-#include "hw/virtio.h"
+#include "hw/virtio/virtio.h"
 #include "virtio-9p.h"
 #include "fsdev/file-op-9p.h"
 #include "virtio-9p-xattr.h"
index 730027900e7fcbc15c4db327dd1c18c5fa854ee8..8ba2959dbb3af1e82a980389ce1a35e873c40e89 100644 (file)
@@ -11,7 +11,7 @@
  */
 #include <sys/socket.h>
 #include <sys/un.h>
-#include "hw/virtio.h"
+#include "hw/virtio/virtio.h"
 #include "virtio-9p.h"
 #include "qemu/error-report.h"
 #include "fsdev/qemu-fsdev.h"
index e95a856d25e80745322d61ab175e94ffe7882e71..840e4ebb5aeb09459959b7c5bbbfd51209c0b05c 100644 (file)
@@ -12,7 +12,7 @@
  *
  */
 
-#include "hw/virtio.h"
+#include "hw/virtio/virtio.h"
 #include "virtio-9p.h"
 #include "virtio-9p-xattr.h"
 #include "fsdev/qemu-fsdev.h"
index 5bb602007096baad89316a10282f01de2233baf3..e0c92ebf9e5dcd3ed99da4d951d34bbddfee3a42 100644 (file)
@@ -12,7 +12,7 @@
  */
 
 #include <sys/types.h>
-#include "hw/virtio.h"
+#include "hw/virtio/virtio.h"
 #include "virtio-9p.h"
 #include "fsdev/file-op-9p.h"
 #include "virtio-9p-xattr.h"
index a83960676d16c74cbfd919ddeaca766dcb337494..90ae565c1914b897b651faf6358f507ebccab154 100644 (file)
@@ -11,7 +11,7 @@
  *
  */
 
-#include "hw/virtio.h"
+#include "hw/virtio/virtio.h"
 #include "virtio-9p.h"
 #include "fsdev/file-op-9p.h"
 #include "virtio-9p-xattr.h"
index 5cc4c92012a3c9d8ad74c4dd62496ece6536f2e2..db2ae32fe8c3130d46a8253628937f5d4590d37d 100644 (file)
@@ -11,8 +11,8 @@
  *
  */
 
-#include "hw/virtio.h"
-#include "hw/pc.h"
+#include "hw/virtio/virtio.h"
+#include "hw/i386/pc.h"
 #include "qemu/sockets.h"
 #include "virtio-9p.h"
 #include "fsdev/qemu-fsdev.h"
index 52b1c6997f1f4d8e02fbf48061b606ea9f2049bb..95a8ec3ba9ea31855b669d646b5aec463ed9e025 100644 (file)
@@ -6,7 +6,7 @@
 #include <sys/time.h>
 #include <utime.h>
 #include <sys/resource.h>
-#include "hw/virtio.h"
+#include "hw/virtio/virtio.h"
 #include "fsdev/file-op-9p.h"
 #include "fsdev/virtio-9p-marshal.h"
 #include "qemu/thread.h"
index d0b2ecb97f4ad6dbc9212a8e5ea0a36ad73e7220..1cb86fa323b91ee0ee7e80e77b2822466d8bcd1b 100644 (file)
-# core qdev-related obj files, also used by *-user:
-common-obj-y += qdev.o qdev-properties.o
-# irq.o needed for qdev GPIO handling:
-common-obj-y += irq.o
-
-ifeq ($(CONFIG_SOFTMMU),y)
-common-obj-y += usb/ ide/ pci/
-common-obj-y += loader.o
-common-obj-$(CONFIG_VIRTIO) += virtio-console.o
-common-obj-$(CONFIG_VIRTIO) += virtio-rng.o
-common-obj-$(CONFIG_VIRTIO_PCI) += virtio-pci.o
-common-obj-$(CONFIG_VIRTIO) += virtio-bus.o
-common-obj-y += fw_cfg.o
-common-obj-$(CONFIG_PCI) += pci_bridge_dev.o
-common-obj-$(CONFIG_PCI) += ioh3420.o xio3130_upstream.o xio3130_downstream.o
-common-obj-$(CONFIG_PCI) += i82801b11.o
-common-obj-y += watchdog.o
-common-obj-$(CONFIG_ISA_MMIO) += isa_mmio.o
-common-obj-$(CONFIG_ECC) += ecc.o
-common-obj-$(CONFIG_NAND) += nand.o
-common-obj-$(CONFIG_PFLASH_CFI01) += pflash_cfi01.o
-common-obj-$(CONFIG_PFLASH_CFI02) += pflash_cfi02.o
-
-common-obj-$(CONFIG_M48T59) += m48t59.o
-common-obj-$(CONFIG_ESCC) += escc.o
-common-obj-$(CONFIG_EMPTY_SLOT) += empty_slot.o
-
-common-obj-$(CONFIG_SERIAL) += serial.o serial-isa.o
-common-obj-$(CONFIG_SERIAL_PCI) += serial-pci.o
-common-obj-$(CONFIG_PARALLEL) += parallel.o
-common-obj-$(CONFIG_I8254) += i8254_common.o i8254.o
-common-obj-$(CONFIG_PCSPK) += pcspk.o
-common-obj-$(CONFIG_PCKBD) += pckbd.o
-common-obj-$(CONFIG_FDC) += fdc.o
-common-obj-$(CONFIG_ACPI) += acpi.o acpi_piix4.o acpi_ich9.o smbus_ich9.o
-common-obj-$(CONFIG_APM) += pm_smbus.o apm.o
-common-obj-$(CONFIG_DMA) += dma.o
-common-obj-$(CONFIG_I82374) += i82374.o
-common-obj-$(CONFIG_HPET) += hpet.o
-common-obj-$(CONFIG_APPLESMC) += applesmc.o
-ifeq ($(CONFIG_USB_SMARTCARD),y)
-common-obj-y += ccid-card-passthru.o
-common-obj-$(CONFIG_SMARTCARD_NSS) += ccid-card-emulated.o
-endif
-common-obj-$(CONFIG_I8259) += i8259_common.o i8259.o
-common-obj-$(CONFIG_SDHCI) += sdhci.o
-common-obj-y += pam.o
-
-# PPC devices
-common-obj-$(CONFIG_PREP_PCI) += prep_pci.o
-common-obj-$(CONFIG_I82378) += i82378.o
-common-obj-$(CONFIG_PC87312) += pc87312.o
-# Mac shared devices
-common-obj-$(CONFIG_MACIO) += macio.o
-common-obj-$(CONFIG_CUDA) += cuda.o
-common-obj-$(CONFIG_ADB) += adb.o
-common-obj-$(CONFIG_MAC_NVRAM) += mac_nvram.o
-common-obj-$(CONFIG_MAC_DBDMA) += mac_dbdma.o
-# OldWorld PowerMac
-common-obj-$(CONFIG_HEATHROW_PIC) += heathrow_pic.o
-common-obj-$(CONFIG_GRACKLE_PCI) += grackle_pci.o
-# NewWorld PowerMac
-common-obj-$(CONFIG_UNIN_PCI) += unin_pci.o
-common-obj-$(CONFIG_DEC_PCI) += dec_pci.o
-# PowerPC E500 boards
-common-obj-$(CONFIG_PPCE500_PCI) += ppce500_pci.o
-
-# MIPS devices
-common-obj-$(CONFIG_PIIX4) += piix4.o
-common-obj-$(CONFIG_G364FB) += g364fb.o
-common-obj-$(CONFIG_JAZZ_LED) += jazz_led.o
-
-# Xilinx devices
-common-obj-$(CONFIG_XILINX) += xilinx_intc.o
-common-obj-$(CONFIG_XILINX) += xilinx_timer.o
-common-obj-$(CONFIG_XILINX) += xilinx_uartlite.o
-common-obj-$(CONFIG_XILINX_AXI) += xilinx_axidma.o
-common-obj-$(CONFIG_XILINX_AXI) += xilinx_axienet.o
-common-obj-$(CONFIG_XILINX_AXI) += stream.o
-
-# PKUnity SoC devices
-common-obj-$(CONFIG_PUV3) += puv3_intc.o
-common-obj-$(CONFIG_PUV3) += puv3_ost.o
-common-obj-$(CONFIG_PUV3) += puv3_gpio.o
-common-obj-$(CONFIG_PUV3) += puv3_pm.o
-common-obj-$(CONFIG_PUV3) += puv3_dma.o
-
-# ARM devices
-common-obj-$(CONFIG_ARM_TIMER) += arm_timer.o
-common-obj-$(CONFIG_PL011) += pl011.o
-common-obj-$(CONFIG_PL022) += pl022.o
-common-obj-$(CONFIG_PL031) += pl031.o
-common-obj-$(CONFIG_PL041) += pl041.o lm4549.o
-common-obj-$(CONFIG_PL050) += pl050.o
-common-obj-$(CONFIG_PL061) += pl061.o
-common-obj-$(CONFIG_PL080) += pl080.o
-common-obj-$(CONFIG_PL110) += pl110.o
-common-obj-$(CONFIG_PL181) += pl181.o
-common-obj-$(CONFIG_PL190) += pl190.o
-common-obj-$(CONFIG_PL310) += arm_l2x0.o
-common-obj-$(CONFIG_PL330) += pl330.o
-common-obj-$(CONFIG_VERSATILE_PCI) += versatile_pci.o
-common-obj-$(CONFIG_VERSATILE_I2C) += versatile_i2c.o
-common-obj-$(CONFIG_CADENCE) += cadence_uart.o
-common-obj-$(CONFIG_CADENCE) += cadence_ttc.o
-common-obj-$(CONFIG_CADENCE) += cadence_gem.o
-common-obj-$(CONFIG_XGMAC) += xgmac.o
-
-# PCI watchdog devices
-common-obj-$(CONFIG_PCI) += wdt_i6300esb.o
-
-# IndustryPack
-common-obj-$(CONFIG_IPACK) += tpci200.o ipoctal232.o ipack.o
-
-# PCI network cards
-common-obj-$(CONFIG_NE2000_PCI) += ne2000.o
-common-obj-$(CONFIG_EEPRO100_PCI) += eepro100.o
-common-obj-$(CONFIG_PCNET_PCI) += pcnet-pci.o
-common-obj-$(CONFIG_PCNET_COMMON) += pcnet.o
-common-obj-$(CONFIG_E1000_PCI) += e1000.o
-common-obj-$(CONFIG_RTL8139_PCI) += rtl8139.o
-common-obj-$(CONFIG_VMXNET3_PCI) += vmxnet_tx_pkt.o vmxnet_rx_pkt.o
-common-obj-$(CONFIG_VMXNET3_PCI) += vmxnet3.o
-
-common-obj-$(CONFIG_SMC91C111) += smc91c111.o
-common-obj-$(CONFIG_LAN9118) += lan9118.o
-common-obj-$(CONFIG_NE2000_ISA) += ne2000-isa.o
-common-obj-$(CONFIG_OPENCORES_ETH) += opencores_eth.o
-
-# SCSI layer
-common-obj-$(CONFIG_LSI_SCSI_PCI) += lsi53c895a.o
-common-obj-$(CONFIG_MEGASAS_SCSI_PCI) += megasas.o
-common-obj-$(CONFIG_ESP) += esp.o
-common-obj-$(CONFIG_ESP_PCI) += esp-pci.o
-
-common-obj-y += sysbus.o isa-bus.o
-common-obj-y += qdev-addr.o
-
-# VGA
-common-obj-$(CONFIG_VGA_PCI) += vga-pci.o
-common-obj-$(CONFIG_VGA_ISA) += vga-isa.o
-common-obj-$(CONFIG_VGA_ISA_MM) += vga-isa-mm.o
-common-obj-$(CONFIG_VMWARE_VGA) += vmware_vga.o
-common-obj-$(CONFIG_VMMOUSE) += vmmouse.o
-common-obj-$(CONFIG_VGA_CIRRUS) += cirrus_vga.o
-
-common-obj-$(CONFIG_RC4030) += rc4030.o
-common-obj-$(CONFIG_DP8393X) += dp8393x.o
-common-obj-$(CONFIG_DS1225Y) += ds1225y.o
-common-obj-$(CONFIG_MIPSNET) += mipsnet.o
-
-common-obj-y += null-machine.o
-
-# Sound
-sound-obj-y =
-sound-obj-$(CONFIG_SB16) += sb16.o
-sound-obj-$(CONFIG_ES1370) += es1370.o
-sound-obj-$(CONFIG_AC97) += ac97.o
-sound-obj-$(CONFIG_ADLIB) += fmopl.o adlib.o
-sound-obj-$(CONFIG_GUS) += gus.o gusemu_hal.o gusemu_mixer.o
-sound-obj-$(CONFIG_CS4231A) += cs4231a.o
-sound-obj-$(CONFIG_HDA) += intel-hda.o hda-audio.o
-
-$(obj)/adlib.o $(obj)/fmopl.o: QEMU_CFLAGS += -DBUILD_Y8950=0
-
-common-obj-$(CONFIG_SOUND) += $(sound-obj-y)
-
-common-obj-$(CONFIG_REALLY_VIRTFS) += 9pfs/
-
-common-obj-y += usb/
-common-obj-$(CONFIG_PTIMER) += ptimer.o
-common-obj-$(CONFIG_MAX7310) += max7310.o
-common-obj-$(CONFIG_WM8750) += wm8750.o
-common-obj-$(CONFIG_TWL92230) += twl92230.o
-common-obj-$(CONFIG_TSC2005) += tsc2005.o
-common-obj-$(CONFIG_LM832X) += lm832x.o
-common-obj-$(CONFIG_TMP105) += tmp105.o
-common-obj-$(CONFIG_STELLARIS_INPUT) += stellaris_input.o
-common-obj-$(CONFIG_SSD0303) += ssd0303.o
-common-obj-$(CONFIG_SSD0323) += ssd0323.o
-common-obj-$(CONFIG_ADS7846) += ads7846.o
-common-obj-$(CONFIG_MAX111X) += max111x.o
-common-obj-$(CONFIG_DS1338) += ds1338.o
-common-obj-y += i2c.o smbus.o smbus_eeprom.o
-common-obj-y += eeprom93xx.o
-common-obj-y += scsi-disk.o cdrom.o hd-geometry.o block-common.o
-common-obj-y += scsi-generic.o scsi-bus.o
-common-obj-y += hid.o
-common-obj-$(CONFIG_SSI) += ssi.o
-common-obj-$(CONFIG_SSI_M25P80) += m25p80.o
-common-obj-$(CONFIG_SSI_SD) += ssi-sd.o
-common-obj-$(CONFIG_SD) += sd.o
-common-obj-y += bt.o bt-l2cap.o bt-sdp.o bt-hci.o bt-hid.o
-common-obj-y += bt-hci-csr.o
-common-obj-y += ps2.o
-common-obj-y += qdev-properties-system.o
-
-# xen backend driver support
-common-obj-$(CONFIG_XEN_BACKEND) += xen_backend.o xen_devconfig.o
-common-obj-$(CONFIG_XEN_BACKEND) += xen_console.o xenfb.o xen_disk.o xen_nic.o
-
-# Per-target files
-# virtio has to be here due to weird dependency between PCI and virtio-net.
-# need to fix this properly
-obj-$(CONFIG_VIRTIO) += dataplane/
-obj-$(CONFIG_VIRTIO) += virtio.o virtio-blk.o virtio-balloon.o virtio-net.o
-obj-$(CONFIG_VIRTIO) += virtio-serial-bus.o virtio-scsi.o
-obj-$(CONFIG_SOFTMMU) += vhost_net.o
-obj-$(CONFIG_VHOST_NET) += vhost.o
-obj-$(CONFIG_REALLY_VIRTFS) += 9pfs/
-obj-$(CONFIG_VGA) += vga.o
-
-# Inter-VM PCI shared memory & VFIO PCI device assignment
-ifeq ($(CONFIG_PCI), y)
-obj-$(CONFIG_KVM) += ivshmem.o
-obj-$(CONFIG_LINUX) += vfio_pci.o
-endif
-
-endif
+devices-dirs-$(CONFIG_REALLY_VIRTFS) += 9pfs/
+devices-dirs-$(CONFIG_ACPI) += acpi/
+devices-dirs-$(CONFIG_SOFTMMU) += audio/
+devices-dirs-$(CONFIG_SOFTMMU) += block/
+devices-dirs-$(CONFIG_SOFTMMU) += bt/
+devices-dirs-$(CONFIG_SOFTMMU) += char/
+devices-dirs-$(CONFIG_SOFTMMU) += cpu/
+devices-dirs-$(CONFIG_SOFTMMU) += display/
+devices-dirs-$(CONFIG_SOFTMMU) += dma/
+devices-dirs-$(CONFIG_SOFTMMU) += gpio/
+devices-dirs-$(CONFIG_SOFTMMU) += i2c/
+devices-dirs-$(CONFIG_SOFTMMU) += ide/
+devices-dirs-$(CONFIG_SOFTMMU) += input/
+devices-dirs-$(CONFIG_SOFTMMU) += intc/
+devices-dirs-$(CONFIG_SOFTMMU) += isa/
+devices-dirs-$(CONFIG_SOFTMMU) += misc/
+devices-dirs-$(CONFIG_SOFTMMU) += net/
+devices-dirs-$(CONFIG_SOFTMMU) += nvram/
+devices-dirs-$(CONFIG_SOFTMMU) += pci/
+devices-dirs-$(CONFIG_PCI) += pci-bridge/ pci-host/
+devices-dirs-$(CONFIG_SOFTMMU) += scsi/
+devices-dirs-$(CONFIG_SOFTMMU) += sd/
+devices-dirs-$(CONFIG_SOFTMMU) += ssi/
+devices-dirs-$(CONFIG_SOFTMMU) += timer/
+devices-dirs-$(CONFIG_SOFTMMU) += usb/
+devices-dirs-$(CONFIG_SOFTMMU) += virtio/
+devices-dirs-$(CONFIG_SOFTMMU) += watchdog/
+devices-dirs-$(CONFIG_SOFTMMU) += xen/
+devices-dirs-y += core/
+common-obj-y += $(devices-dirs-y)
+obj-y += $(devices-dirs-y)
diff --git a/hw/a15mpcore.c b/hw/a15mpcore.c
deleted file mode 100644 (file)
index 648656d..0000000
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * 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 "hw/sysbus.h"
-#include "sysemu/kvm.h"
-
-/* A15MP private memory region.  */
-
-typedef struct A15MPPrivState {
-    SysBusDevice busdev;
-    uint32_t num_cpu;
-    uint32_t num_irq;
-    MemoryRegion container;
-    DeviceState *gic;
-} A15MPPrivState;
-
-static void a15mp_priv_set_irq(void *opaque, int irq, int level)
-{
-    A15MPPrivState *s = (A15MPPrivState *)opaque;
-    qemu_set_irq(qdev_get_gpio_in(s->gic, irq), level);
-}
-
-static int a15mp_priv_init(SysBusDevice *dev)
-{
-    A15MPPrivState *s = FROM_SYSBUS(A15MPPrivState, dev);
-    SysBusDevice *busdev;
-    const char *gictype = "arm_gic";
-
-    if (kvm_irqchip_in_kernel()) {
-        gictype = "kvm-arm-gic";
-    }
-
-    s->gic = qdev_create(NULL, gictype);
-    qdev_prop_set_uint32(s->gic, "num-cpu", s->num_cpu);
-    qdev_prop_set_uint32(s->gic, "num-irq", s->num_irq);
-    qdev_prop_set_uint32(s->gic, "revision", 2);
-    qdev_init_nofail(s->gic);
-    busdev = SYS_BUS_DEVICE(s->gic);
-
-    /* Pass through outbound IRQ lines from the GIC */
-    sysbus_pass_irq(dev, busdev);
-
-    /* Pass through inbound GPIO lines to the GIC */
-    qdev_init_gpio_in(&s->busdev.qdev, a15mp_priv_set_irq, s->num_irq - 32);
-
-    /* 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,
-                                sysbus_mmio_get_region(busdev, 0));
-    memory_region_add_subregion(&s->container, 0x2000,
-                                sysbus_mmio_get_region(busdev, 1));
-
-    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 */
-}
-
-static const 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)
diff --git a/hw/a9mpcore.c b/hw/a9mpcore.c
deleted file mode 100644 (file)
index 0a1a10f..0000000
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Cortex-A9MPCore internal peripheral emulation.
- *
- * Copyright (c) 2009 CodeSourcery.
- * Copyright (c) 2011 Linaro Limited.
- * Written by Paul Brook, Peter Maydell.
- *
- * This code is licensed under the GPL.
- */
-
-#include "hw/sysbus.h"
-
-typedef struct A9MPPrivState {
-    SysBusDevice busdev;
-    uint32_t num_cpu;
-    MemoryRegion container;
-    DeviceState *mptimer;
-    DeviceState *wdt;
-    DeviceState *gic;
-    DeviceState *scu;
-    uint32_t num_irq;
-} A9MPPrivState;
-
-static void a9mp_priv_set_irq(void *opaque, int irq, int level)
-{
-    A9MPPrivState *s = (A9MPPrivState *)opaque;
-    qemu_set_irq(qdev_get_gpio_in(s->gic, irq), level);
-}
-
-static int a9mp_priv_init(SysBusDevice *dev)
-{
-    A9MPPrivState *s = FROM_SYSBUS(A9MPPrivState, dev);
-    SysBusDevice *timerbusdev, *wdtbusdev, *gicbusdev, *scubusdev;
-    int i;
-
-    s->gic = qdev_create(NULL, "arm_gic");
-    qdev_prop_set_uint32(s->gic, "num-cpu", s->num_cpu);
-    qdev_prop_set_uint32(s->gic, "num-irq", s->num_irq);
-    qdev_init_nofail(s->gic);
-    gicbusdev = SYS_BUS_DEVICE(s->gic);
-
-    /* Pass through outbound IRQ lines from the GIC */
-    sysbus_pass_irq(dev, gicbusdev);
-
-    /* Pass through inbound GPIO lines to the GIC */
-    qdev_init_gpio_in(&s->busdev.qdev, a9mp_priv_set_irq, s->num_irq - 32);
-
-    s->scu = qdev_create(NULL, "a9-scu");
-    qdev_prop_set_uint32(s->scu, "num-cpu", s->num_cpu);
-    qdev_init_nofail(s->scu);
-    scubusdev = SYS_BUS_DEVICE(s->scu);
-
-    s->mptimer = qdev_create(NULL, "arm_mptimer");
-    qdev_prop_set_uint32(s->mptimer, "num-cpu", s->num_cpu);
-    qdev_init_nofail(s->mptimer);
-    timerbusdev = SYS_BUS_DEVICE(s->mptimer);
-
-    s->wdt = qdev_create(NULL, "arm_mptimer");
-    qdev_prop_set_uint32(s->wdt, "num-cpu", s->num_cpu);
-    qdev_init_nofail(s->wdt);
-    wdtbusdev = SYS_BUS_DEVICE(s->wdt);
-
-    /* Memory map (addresses are offsets from PERIPHBASE):
-     *  0x0000-0x00ff -- Snoop Control Unit
-     *  0x0100-0x01ff -- GIC CPU interface
-     *  0x0200-0x02ff -- Global Timer
-     *  0x0300-0x05ff -- nothing
-     *  0x0600-0x06ff -- private timers and watchdogs
-     *  0x0700-0x0fff -- nothing
-     *  0x1000-0x1fff -- GIC Distributor
-     *
-     * We should implement the global timer but don't currently do so.
-     */
-    memory_region_init(&s->container, "a9mp-priv-container", 0x2000);
-    memory_region_add_subregion(&s->container, 0,
-                                sysbus_mmio_get_region(scubusdev, 0));
-    /* GIC CPU interface */
-    memory_region_add_subregion(&s->container, 0x100,
-                                sysbus_mmio_get_region(gicbusdev, 1));
-    /* Note that the A9 exposes only the "timer/watchdog for this core"
-     * memory region, not the "timer/watchdog for core X" ones 11MPcore has.
-     */
-    memory_region_add_subregion(&s->container, 0x600,
-                                sysbus_mmio_get_region(timerbusdev, 0));
-    memory_region_add_subregion(&s->container, 0x620,
-                                sysbus_mmio_get_region(wdtbusdev, 0));
-    memory_region_add_subregion(&s->container, 0x1000,
-                                sysbus_mmio_get_region(gicbusdev, 0));
-
-    sysbus_init_mmio(dev, &s->container);
-
-    /* Wire up the interrupt from each watchdog and timer.
-     * For each core the timer is PPI 29 and the watchdog PPI 30.
-     */
-    for (i = 0; i < s->num_cpu; i++) {
-        int ppibase = (s->num_irq - 32) + i * 32;
-        sysbus_connect_irq(timerbusdev, i,
-                           qdev_get_gpio_in(s->gic, ppibase + 29));
-        sysbus_connect_irq(wdtbusdev, i,
-                           qdev_get_gpio_in(s->gic, ppibase + 30));
-    }
-    return 0;
-}
-
-static Property a9mp_priv_properties[] = {
-    DEFINE_PROP_UINT32("num-cpu", A9MPPrivState, 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", A9MPPrivState, 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;
-}
-
-static const TypeInfo a9mp_priv_info = {
-    .name          = "a9mpcore_priv",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(A9MPPrivState),
-    .class_init    = a9mp_priv_class_init,
-};
-
-static void a9mp_register_types(void)
-{
-    type_register_static(&a9mp_priv_info);
-}
-
-type_init(a9mp_register_types)
diff --git a/hw/a9scu.c b/hw/a9scu.c
deleted file mode 100644 (file)
index 05897c2..0000000
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * Cortex-A9MPCore Snoop Control Unit (SCU) emulation.
- *
- * Copyright (c) 2009 CodeSourcery.
- * Copyright (c) 2011 Linaro Limited.
- * Written by Paul Brook, Peter Maydell.
- *
- * This code is licensed under the GPL.
- */
-
-#include "hw/sysbus.h"
-
-/* A9MP private memory region.  */
-
-typedef struct A9SCUState {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-    uint32_t control;
-    uint32_t status;
-    uint32_t num_cpu;
-} A9SCUState;
-
-#define TYPE_A9_SCU "a9-scu"
-#define A9_SCU(obj) OBJECT_CHECK(A9SCUState, (obj), TYPE_A9_SCU)
-
-static uint64_t a9_scu_read(void *opaque, hwaddr offset,
-                            unsigned size)
-{
-    A9SCUState *s = (A9SCUState *)opaque;
-    switch (offset) {
-    case 0x00: /* Control */
-        return s->control;
-    case 0x04: /* Configuration */
-        return (((1 << s->num_cpu) - 1) << 4) | (s->num_cpu - 1);
-    case 0x08: /* CPU Power Status */
-        return s->status;
-    case 0x09: /* CPU status.  */
-        return s->status >> 8;
-    case 0x0a: /* CPU status.  */
-        return s->status >> 16;
-    case 0x0b: /* CPU status.  */
-        return s->status >> 24;
-    case 0x0c: /* Invalidate All Registers In Secure State */
-        return 0;
-    case 0x40: /* Filtering Start Address Register */
-    case 0x44: /* Filtering End Address Register */
-        /* RAZ/WI, like an implementation with only one AXI master */
-        return 0;
-    case 0x50: /* SCU Access Control Register */
-    case 0x54: /* SCU Non-secure Access Control Register */
-        /* unimplemented, fall through */
-    default:
-        return 0;
-    }
-}
-
-static void a9_scu_write(void *opaque, hwaddr offset,
-                         uint64_t value, unsigned size)
-{
-    A9SCUState *s = (A9SCUState *)opaque;
-    uint32_t mask;
-    uint32_t shift;
-    switch (size) {
-    case 1:
-        mask = 0xff;
-        break;
-    case 2:
-        mask = 0xffff;
-        break;
-    case 4:
-        mask = 0xffffffff;
-        break;
-    default:
-        fprintf(stderr, "Invalid size %u in write to a9 scu register %x\n",
-                size, (unsigned)offset);
-        return;
-    }
-
-    switch (offset) {
-    case 0x00: /* Control */
-        s->control = value & 1;
-        break;
-    case 0x4: /* Configuration: RO */
-        break;
-    case 0x08: case 0x09: case 0x0A: case 0x0B: /* Power Control */
-        shift = (offset - 0x8) * 8;
-        s->status &= ~(mask << shift);
-        s->status |= ((value & mask) << shift);
-        break;
-    case 0x0c: /* Invalidate All Registers In Secure State */
-        /* no-op as we do not implement caches */
-        break;
-    case 0x40: /* Filtering Start Address Register */
-    case 0x44: /* Filtering End Address Register */
-        /* RAZ/WI, like an implementation with only one AXI master */
-        break;
-    case 0x50: /* SCU Access Control Register */
-    case 0x54: /* SCU Non-secure Access Control Register */
-        /* unimplemented, fall through */
-    default:
-        break;
-    }
-}
-
-static const MemoryRegionOps a9_scu_ops = {
-    .read = a9_scu_read,
-    .write = a9_scu_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void a9_scu_reset(DeviceState *dev)
-{
-    A9SCUState *s = A9_SCU(dev);
-    s->control = 0;
-}
-
-static void a9_scu_realize(DeviceState *dev, Error ** errp)
-{
-    A9SCUState *s = A9_SCU(dev);
-    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
-
-    memory_region_init_io(&s->iomem, &a9_scu_ops, s, "a9-scu", 0x100);
-    sysbus_init_mmio(sbd, &s->iomem);
-}
-
-static const VMStateDescription vmstate_a9_scu = {
-    .name = "a9-scu",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT32(control, A9SCUState),
-        VMSTATE_UINT32(status, A9SCUState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static Property a9_scu_properties[] = {
-    DEFINE_PROP_UINT32("num-cpu", A9SCUState, num_cpu, 1),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void a9_scu_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-
-    dc->realize = a9_scu_realize;
-    dc->props = a9_scu_properties;
-    dc->vmsd = &vmstate_a9_scu;
-    dc->reset = a9_scu_reset;
-}
-
-static const TypeInfo a9_scu_info = {
-    .name          = TYPE_A9_SCU,
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(A9SCUState),
-    .class_init    = a9_scu_class_init,
-};
-
-static void a9mp_register_types(void)
-{
-    type_register_static(&a9_scu_info);
-}
-
-type_init(a9mp_register_types)
diff --git a/hw/ac97.c b/hw/ac97.c
deleted file mode 100644 (file)
index c7d601f..0000000
--- a/hw/ac97.c
+++ /dev/null
@@ -1,1438 +0,0 @@
-/*
- * Copyright (C) 2006 InnoTek Systemberatung GmbH
- *
- * This file is part of VirtualBox Open Source Edition (OSE), as
- * available from http://www.virtualbox.org. This file 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,
- * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
- * distribution. VirtualBox OSE is distributed in the hope that it will
- * be useful, but WITHOUT ANY WARRANTY of any kind.
- *
- * 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/hw.h"
-#include "hw/audiodev.h"
-#include "audio/audio.h"
-#include "hw/pci/pci.h"
-#include "sysemu/dma.h"
-
-enum {
-    AC97_Reset                     = 0x00,
-    AC97_Master_Volume_Mute        = 0x02,
-    AC97_Headphone_Volume_Mute     = 0x04,
-    AC97_Master_Volume_Mono_Mute   = 0x06,
-    AC97_Master_Tone_RL            = 0x08,
-    AC97_PC_BEEP_Volume_Mute       = 0x0A,
-    AC97_Phone_Volume_Mute         = 0x0C,
-    AC97_Mic_Volume_Mute           = 0x0E,
-    AC97_Line_In_Volume_Mute       = 0x10,
-    AC97_CD_Volume_Mute            = 0x12,
-    AC97_Video_Volume_Mute         = 0x14,
-    AC97_Aux_Volume_Mute           = 0x16,
-    AC97_PCM_Out_Volume_Mute       = 0x18,
-    AC97_Record_Select             = 0x1A,
-    AC97_Record_Gain_Mute          = 0x1C,
-    AC97_Record_Gain_Mic_Mute      = 0x1E,
-    AC97_General_Purpose           = 0x20,
-    AC97_3D_Control                = 0x22,
-    AC97_AC_97_RESERVED            = 0x24,
-    AC97_Powerdown_Ctrl_Stat       = 0x26,
-    AC97_Extended_Audio_ID         = 0x28,
-    AC97_Extended_Audio_Ctrl_Stat  = 0x2A,
-    AC97_PCM_Front_DAC_Rate        = 0x2C,
-    AC97_PCM_Surround_DAC_Rate     = 0x2E,
-    AC97_PCM_LFE_DAC_Rate          = 0x30,
-    AC97_PCM_LR_ADC_Rate           = 0x32,
-    AC97_MIC_ADC_Rate              = 0x34,
-    AC97_6Ch_Vol_C_LFE_Mute        = 0x36,
-    AC97_6Ch_Vol_L_R_Surround_Mute = 0x38,
-    AC97_Vendor_Reserved           = 0x58,
-    AC97_Sigmatel_Analog           = 0x6c, /* We emulate a Sigmatel codec */
-    AC97_Sigmatel_Dac2Invert       = 0x6e, /* We emulate a Sigmatel codec */
-    AC97_Vendor_ID1                = 0x7c,
-    AC97_Vendor_ID2                = 0x7e
-};
-
-#define SOFT_VOLUME
-#define SR_FIFOE 16             /* rwc */
-#define SR_BCIS  8              /* rwc */
-#define SR_LVBCI 4              /* rwc */
-#define SR_CELV  2              /* ro */
-#define SR_DCH   1              /* ro */
-#define SR_VALID_MASK ((1 << 5) - 1)
-#define SR_WCLEAR_MASK (SR_FIFOE | SR_BCIS | SR_LVBCI)
-#define SR_RO_MASK (SR_DCH | SR_CELV)
-#define SR_INT_MASK (SR_FIFOE | SR_BCIS | SR_LVBCI)
-
-#define CR_IOCE  16             /* rw */
-#define CR_FEIE  8              /* rw */
-#define CR_LVBIE 4              /* rw */
-#define CR_RR    2              /* rw */
-#define CR_RPBM  1              /* rw */
-#define CR_VALID_MASK ((1 << 5) - 1)
-#define CR_DONT_CLEAR_MASK (CR_IOCE | CR_FEIE | CR_LVBIE)
-
-#define GC_WR    4              /* rw */
-#define GC_CR    2              /* rw */
-#define GC_VALID_MASK ((1 << 6) - 1)
-
-#define GS_MD3   (1<<17)        /* rw */
-#define GS_AD3   (1<<16)        /* rw */
-#define GS_RCS   (1<<15)        /* rwc */
-#define GS_B3S12 (1<<14)        /* ro */
-#define GS_B2S12 (1<<13)        /* ro */
-#define GS_B1S12 (1<<12)        /* ro */
-#define GS_S1R1  (1<<11)        /* rwc */
-#define GS_S0R1  (1<<10)        /* rwc */
-#define GS_S1CR  (1<<9)         /* ro */
-#define GS_S0CR  (1<<8)         /* ro */
-#define GS_MINT  (1<<7)         /* ro */
-#define GS_POINT (1<<6)         /* ro */
-#define GS_PIINT (1<<5)         /* ro */
-#define GS_RSRVD ((1<<4)|(1<<3))
-#define GS_MOINT (1<<2)         /* ro */
-#define GS_MIINT (1<<1)         /* ro */
-#define GS_GSCI  1              /* rwc */
-#define GS_RO_MASK (GS_B3S12|                   \
-                    GS_B2S12|                   \
-                    GS_B1S12|                   \
-                    GS_S1CR|                    \
-                    GS_S0CR|                    \
-                    GS_MINT|                    \
-                    GS_POINT|                   \
-                    GS_PIINT|                   \
-                    GS_RSRVD|                   \
-                    GS_MOINT|                   \
-                    GS_MIINT)
-#define GS_VALID_MASK ((1 << 18) - 1)
-#define GS_WCLEAR_MASK (GS_RCS|GS_S1R1|GS_S0R1|GS_GSCI)
-
-#define BD_IOC (1<<31)
-#define BD_BUP (1<<30)
-
-#define EACS_VRA 1
-#define EACS_VRM 8
-
-#define MUTE_SHIFT 15
-
-#define REC_MASK 7
-enum {
-    REC_MIC = 0,
-    REC_CD,
-    REC_VIDEO,
-    REC_AUX,
-    REC_LINE_IN,
-    REC_STEREO_MIX,
-    REC_MONO_MIX,
-    REC_PHONE
-};
-
-typedef struct BD {
-    uint32_t addr;
-    uint32_t ctl_len;
-} BD;
-
-typedef struct AC97BusMasterRegs {
-    uint32_t bdbar;             /* rw 0 */
-    uint8_t civ;                /* ro 0 */
-    uint8_t lvi;                /* rw 0 */
-    uint16_t sr;                /* rw 1 */
-    uint16_t picb;              /* ro 0 */
-    uint8_t piv;                /* ro 0 */
-    uint8_t cr;                 /* rw 0 */
-    unsigned int bd_valid;
-    BD bd;
-} AC97BusMasterRegs;
-
-typedef struct AC97LinkState {
-    PCIDevice dev;
-    QEMUSoundCard card;
-    uint32_t use_broken_id;
-    uint32_t glob_cnt;
-    uint32_t glob_sta;
-    uint32_t cas;
-    uint32_t last_samp;
-    AC97BusMasterRegs bm_regs[3];
-    uint8_t mixer_data[256];
-    SWVoiceIn *voice_pi;
-    SWVoiceOut *voice_po;
-    SWVoiceIn *voice_mc;
-    int invalid_freq[3];
-    uint8_t silence[128];
-    int bup_flag;
-    MemoryRegion io_nam;
-    MemoryRegion io_nabm;
-} AC97LinkState;
-
-enum {
-    BUP_SET = 1,
-    BUP_LAST = 2
-};
-
-#ifdef DEBUG_AC97
-#define dolog(...) AUD_log ("ac97", __VA_ARGS__)
-#else
-#define dolog(...)
-#endif
-
-#define MKREGS(prefix, start)                   \
-enum {                                          \
-    prefix ## _BDBAR = start,                   \
-    prefix ## _CIV = start + 4,                 \
-    prefix ## _LVI = start + 5,                 \
-    prefix ## _SR = start + 6,                  \
-    prefix ## _PICB = start + 8,                \
-    prefix ## _PIV = start + 10,                \
-    prefix ## _CR = start + 11                  \
-}
-
-enum {
-    PI_INDEX = 0,
-    PO_INDEX,
-    MC_INDEX,
-    LAST_INDEX
-};
-
-MKREGS (PI, PI_INDEX * 16);
-MKREGS (PO, PO_INDEX * 16);
-MKREGS (MC, MC_INDEX * 16);
-
-enum {
-    GLOB_CNT = 0x2c,
-    GLOB_STA = 0x30,
-    CAS      = 0x34
-};
-
-#define GET_BM(index) (((index) >> 4) & 3)
-
-static void po_callback (void *opaque, int free);
-static void pi_callback (void *opaque, int avail);
-static void mc_callback (void *opaque, int avail);
-
-static void warm_reset (AC97LinkState *s)
-{
-    (void) s;
-}
-
-static void cold_reset (AC97LinkState * s)
-{
-    (void) s;
-}
-
-static void fetch_bd (AC97LinkState *s, AC97BusMasterRegs *r)
-{
-    uint8_t b[8];
-
-    pci_dma_read (&s->dev, r->bdbar + r->civ * 8, b, 8);
-    r->bd_valid = 1;
-    r->bd.addr = le32_to_cpu (*(uint32_t *) &b[0]) & ~3;
-    r->bd.ctl_len = le32_to_cpu (*(uint32_t *) &b[4]);
-    r->picb = r->bd.ctl_len & 0xffff;
-    dolog ("bd %2d addr=%#x ctl=%#06x len=%#x(%d bytes)\n",
-           r->civ, r->bd.addr, r->bd.ctl_len >> 16,
-           r->bd.ctl_len & 0xffff,
-           (r->bd.ctl_len & 0xffff) << 1);
-}
-
-static void update_sr (AC97LinkState *s, AC97BusMasterRegs *r, uint32_t new_sr)
-{
-    int event = 0;
-    int level = 0;
-    uint32_t new_mask = new_sr & SR_INT_MASK;
-    uint32_t old_mask = r->sr & SR_INT_MASK;
-    uint32_t masks[] = {GS_PIINT, GS_POINT, GS_MINT};
-
-    if (new_mask ^ old_mask) {
-        /** @todo is IRQ deasserted when only one of status bits is cleared? */
-        if (!new_mask) {
-            event = 1;
-            level = 0;
-        }
-        else {
-            if ((new_mask & SR_LVBCI) && (r->cr & CR_LVBIE)) {
-                event = 1;
-                level = 1;
-            }
-            if ((new_mask & SR_BCIS) && (r->cr & CR_IOCE)) {
-                event = 1;
-                level = 1;
-            }
-        }
-    }
-
-    r->sr = new_sr;
-
-    dolog ("IOC%d LVB%d sr=%#x event=%d level=%d\n",
-           r->sr & SR_BCIS, r->sr & SR_LVBCI,
-           r->sr,
-           event, level);
-
-    if (!event)
-        return;
-
-    if (level) {
-        s->glob_sta |= masks[r - s->bm_regs];
-        dolog ("set irq level=1\n");
-        qemu_set_irq (s->dev.irq[0], 1);
-    }
-    else {
-        s->glob_sta &= ~masks[r - s->bm_regs];
-        dolog ("set irq level=0\n");
-        qemu_set_irq (s->dev.irq[0], 0);
-    }
-}
-
-static void voice_set_active (AC97LinkState *s, int bm_index, int on)
-{
-    switch (bm_index) {
-    case PI_INDEX:
-        AUD_set_active_in (s->voice_pi, on);
-        break;
-
-    case PO_INDEX:
-        AUD_set_active_out (s->voice_po, on);
-        break;
-
-    case MC_INDEX:
-        AUD_set_active_in (s->voice_mc, on);
-        break;
-
-    default:
-        AUD_log ("ac97", "invalid bm_index(%d) in voice_set_active", bm_index);
-        break;
-    }
-}
-
-static void reset_bm_regs (AC97LinkState *s, AC97BusMasterRegs *r)
-{
-    dolog ("reset_bm_regs\n");
-    r->bdbar = 0;
-    r->civ = 0;
-    r->lvi = 0;
-    /** todo do we need to do that? */
-    update_sr (s, r, SR_DCH);
-    r->picb = 0;
-    r->piv = 0;
-    r->cr = r->cr & CR_DONT_CLEAR_MASK;
-    r->bd_valid = 0;
-
-    voice_set_active (s, r - s->bm_regs, 0);
-    memset (s->silence, 0, sizeof (s->silence));
-}
-
-static void mixer_store (AC97LinkState *s, uint32_t i, uint16_t v)
-{
-    if (i + 2 > sizeof (s->mixer_data)) {
-        dolog ("mixer_store: index %d out of bounds %zd\n",
-               i, sizeof (s->mixer_data));
-        return;
-    }
-
-    s->mixer_data[i + 0] = v & 0xff;
-    s->mixer_data[i + 1] = v >> 8;
-}
-
-static uint16_t mixer_load (AC97LinkState *s, uint32_t i)
-{
-    uint16_t val = 0xffff;
-
-    if (i + 2 > sizeof (s->mixer_data)) {
-        dolog ("mixer_load: index %d out of bounds %zd\n",
-               i, sizeof (s->mixer_data));
-    }
-    else {
-        val = s->mixer_data[i + 0] | (s->mixer_data[i + 1] << 8);
-    }
-
-    return val;
-}
-
-static void open_voice (AC97LinkState *s, int index, int freq)
-{
-    struct audsettings as;
-
-    as.freq = freq;
-    as.nchannels = 2;
-    as.fmt = AUD_FMT_S16;
-    as.endianness = 0;
-
-    if (freq > 0) {
-        s->invalid_freq[index] = 0;
-        switch (index) {
-        case PI_INDEX:
-            s->voice_pi = AUD_open_in (
-                &s->card,
-                s->voice_pi,
-                "ac97.pi",
-                s,
-                pi_callback,
-                &as
-                );
-            break;
-
-        case PO_INDEX:
-            s->voice_po = AUD_open_out (
-                &s->card,
-                s->voice_po,
-                "ac97.po",
-                s,
-                po_callback,
-                &as
-                );
-            break;
-
-        case MC_INDEX:
-            s->voice_mc = AUD_open_in (
-                &s->card,
-                s->voice_mc,
-                "ac97.mc",
-                s,
-                mc_callback,
-                &as
-                );
-            break;
-        }
-    }
-    else {
-        s->invalid_freq[index] = freq;
-        switch (index) {
-        case PI_INDEX:
-            AUD_close_in (&s->card, s->voice_pi);
-            s->voice_pi = NULL;
-            break;
-
-        case PO_INDEX:
-            AUD_close_out (&s->card, s->voice_po);
-            s->voice_po = NULL;
-            break;
-
-        case MC_INDEX:
-            AUD_close_in (&s->card, s->voice_mc);
-            s->voice_mc = NULL;
-            break;
-        }
-    }
-}
-
-static void reset_voices (AC97LinkState *s, uint8_t active[LAST_INDEX])
-{
-    uint16_t freq;
-
-    freq = mixer_load (s, AC97_PCM_LR_ADC_Rate);
-    open_voice (s, PI_INDEX, freq);
-    AUD_set_active_in (s->voice_pi, active[PI_INDEX]);
-
-    freq = mixer_load (s, AC97_PCM_Front_DAC_Rate);
-    open_voice (s, PO_INDEX, freq);
-    AUD_set_active_out (s->voice_po, active[PO_INDEX]);
-
-    freq = mixer_load (s, AC97_MIC_ADC_Rate);
-    open_voice (s, MC_INDEX, freq);
-    AUD_set_active_in (s->voice_mc, active[MC_INDEX]);
-}
-
-static void get_volume (uint16_t vol, uint16_t mask, int inverse,
-                        int *mute, uint8_t *lvol, uint8_t *rvol)
-{
-    *mute = (vol >> MUTE_SHIFT) & 1;
-    *rvol = (255 * (vol & mask)) / mask;
-    *lvol = (255 * ((vol >> 8) & mask)) / mask;
-
-    if (inverse) {
-        *rvol = 255 - *rvol;
-        *lvol = 255 - *lvol;
-    }
-}
-
-static void update_combined_volume_out (AC97LinkState *s)
-{
-    uint8_t lvol, rvol, plvol, prvol;
-    int mute, pmute;
-
-    get_volume (mixer_load (s, AC97_Master_Volume_Mute), 0x3f, 1,
-                &mute, &lvol, &rvol);
-    get_volume (mixer_load (s, AC97_PCM_Out_Volume_Mute), 0x1f, 1,
-                &pmute, &plvol, &prvol);
-
-    mute = mute | pmute;
-    lvol = (lvol * plvol) / 255;
-    rvol = (rvol * prvol) / 255;
-
-    AUD_set_volume_out (s->voice_po, mute, lvol, rvol);
-}
-
-static void update_volume_in (AC97LinkState *s)
-{
-    uint8_t lvol, rvol;
-    int mute;
-
-    get_volume (mixer_load (s, AC97_Record_Gain_Mute), 0x0f, 0,
-                &mute, &lvol, &rvol);
-
-    AUD_set_volume_in (s->voice_pi, mute, lvol, rvol);
-}
-
-static void set_volume (AC97LinkState *s, int index, uint32_t val)
-{
-    switch (index) {
-    case AC97_Master_Volume_Mute:
-        val &= 0xbf3f;
-        mixer_store (s, index, val);
-        update_combined_volume_out (s);
-        break;
-    case AC97_PCM_Out_Volume_Mute:
-        val &= 0x9f1f;
-        mixer_store (s, index, val);
-        update_combined_volume_out (s);
-        break;
-    case AC97_Record_Gain_Mute:
-        val &= 0x8f0f;
-        mixer_store (s, index, val);
-        update_volume_in (s);
-        break;
-    }
-}
-
-static void record_select (AC97LinkState *s, uint32_t val)
-{
-    uint8_t rs = val & REC_MASK;
-    uint8_t ls = (val >> 8) & REC_MASK;
-    mixer_store (s, AC97_Record_Select, rs | (ls << 8));
-}
-
-static void mixer_reset (AC97LinkState *s)
-{
-    uint8_t active[LAST_INDEX];
-
-    dolog ("mixer_reset\n");
-    memset (s->mixer_data, 0, sizeof (s->mixer_data));
-    memset (active, 0, sizeof (active));
-    mixer_store (s, AC97_Reset                   , 0x0000); /* 6940 */
-    mixer_store (s, AC97_Headphone_Volume_Mute   , 0x0000);
-    mixer_store (s, AC97_Master_Volume_Mono_Mute , 0x0000);
-    mixer_store (s, AC97_Master_Tone_RL,           0x0000);
-    mixer_store (s, AC97_PC_BEEP_Volume_Mute     , 0x0000);
-    mixer_store (s, AC97_Phone_Volume_Mute       , 0x0000);
-    mixer_store (s, AC97_Mic_Volume_Mute         , 0x0000);
-    mixer_store (s, AC97_Line_In_Volume_Mute     , 0x0000);
-    mixer_store (s, AC97_CD_Volume_Mute          , 0x0000);
-    mixer_store (s, AC97_Video_Volume_Mute       , 0x0000);
-    mixer_store (s, AC97_Aux_Volume_Mute         , 0x0000);
-    mixer_store (s, AC97_Record_Gain_Mic_Mute    , 0x0000);
-    mixer_store (s, AC97_General_Purpose         , 0x0000);
-    mixer_store (s, AC97_3D_Control              , 0x0000);
-    mixer_store (s, AC97_Powerdown_Ctrl_Stat     , 0x000f);
-
-    /*
-     * Sigmatel 9700 (STAC9700)
-     */
-    mixer_store (s, AC97_Vendor_ID1              , 0x8384);
-    mixer_store (s, AC97_Vendor_ID2              , 0x7600); /* 7608 */
-
-    mixer_store (s, AC97_Extended_Audio_ID       , 0x0809);
-    mixer_store (s, AC97_Extended_Audio_Ctrl_Stat, 0x0009);
-    mixer_store (s, AC97_PCM_Front_DAC_Rate      , 0xbb80);
-    mixer_store (s, AC97_PCM_Surround_DAC_Rate   , 0xbb80);
-    mixer_store (s, AC97_PCM_LFE_DAC_Rate        , 0xbb80);
-    mixer_store (s, AC97_PCM_LR_ADC_Rate         , 0xbb80);
-    mixer_store (s, AC97_MIC_ADC_Rate            , 0xbb80);
-
-    record_select (s, 0);
-    set_volume (s, AC97_Master_Volume_Mute, 0x8000);
-    set_volume (s, AC97_PCM_Out_Volume_Mute, 0x8808);
-    set_volume (s, AC97_Record_Gain_Mute, 0x8808);
-
-    reset_voices (s, active);
-}
-
-/**
- * Native audio mixer
- * I/O Reads
- */
-static uint32_t nam_readb (void *opaque, uint32_t addr)
-{
-    AC97LinkState *s = opaque;
-    dolog ("U nam readb %#x\n", addr);
-    s->cas = 0;
-    return ~0U;
-}
-
-static uint32_t nam_readw (void *opaque, uint32_t addr)
-{
-    AC97LinkState *s = opaque;
-    uint32_t val = ~0U;
-    uint32_t index = addr;
-    s->cas = 0;
-    val = mixer_load (s, index);
-    return val;
-}
-
-static uint32_t nam_readl (void *opaque, uint32_t addr)
-{
-    AC97LinkState *s = opaque;
-    dolog ("U nam readl %#x\n", addr);
-    s->cas = 0;
-    return ~0U;
-}
-
-/**
- * Native audio mixer
- * I/O Writes
- */
-static void nam_writeb (void *opaque, uint32_t addr, uint32_t val)
-{
-    AC97LinkState *s = opaque;
-    dolog ("U nam writeb %#x <- %#x\n", addr, val);
-    s->cas = 0;
-}
-
-static void nam_writew (void *opaque, uint32_t addr, uint32_t val)
-{
-    AC97LinkState *s = opaque;
-    uint32_t index = addr;
-    s->cas = 0;
-    switch (index) {
-    case AC97_Reset:
-        mixer_reset (s);
-        break;
-    case AC97_Powerdown_Ctrl_Stat:
-        val &= ~0x800f;
-        val |= mixer_load (s, index) & 0xf;
-        mixer_store (s, index, val);
-        break;
-    case AC97_PCM_Out_Volume_Mute:
-    case AC97_Master_Volume_Mute:
-    case AC97_Record_Gain_Mute:
-        set_volume (s, index, val);
-        break;
-    case AC97_Record_Select:
-        record_select (s, val);
-        break;
-    case AC97_Vendor_ID1:
-    case AC97_Vendor_ID2:
-        dolog ("Attempt to write vendor ID to %#x\n", val);
-        break;
-    case AC97_Extended_Audio_ID:
-        dolog ("Attempt to write extended audio ID to %#x\n", val);
-        break;
-    case AC97_Extended_Audio_Ctrl_Stat:
-        if (!(val & EACS_VRA)) {
-            mixer_store (s, AC97_PCM_Front_DAC_Rate, 0xbb80);
-            mixer_store (s, AC97_PCM_LR_ADC_Rate,    0xbb80);
-            open_voice (s, PI_INDEX, 48000);
-            open_voice (s, PO_INDEX, 48000);
-        }
-        if (!(val & EACS_VRM)) {
-            mixer_store (s, AC97_MIC_ADC_Rate, 0xbb80);
-            open_voice (s, MC_INDEX, 48000);
-        }
-        dolog ("Setting extended audio control to %#x\n", val);
-        mixer_store (s, AC97_Extended_Audio_Ctrl_Stat, val);
-        break;
-    case AC97_PCM_Front_DAC_Rate:
-        if (mixer_load (s, AC97_Extended_Audio_Ctrl_Stat) & EACS_VRA) {
-            mixer_store (s, index, val);
-            dolog ("Set front DAC rate to %d\n", val);
-            open_voice (s, PO_INDEX, val);
-        }
-        else {
-            dolog ("Attempt to set front DAC rate to %d, "
-                   "but VRA is not set\n",
-                   val);
-        }
-        break;
-    case AC97_MIC_ADC_Rate:
-        if (mixer_load (s, AC97_Extended_Audio_Ctrl_Stat) & EACS_VRM) {
-            mixer_store (s, index, val);
-            dolog ("Set MIC ADC rate to %d\n", val);
-            open_voice (s, MC_INDEX, val);
-        }
-        else {
-            dolog ("Attempt to set MIC ADC rate to %d, "
-                   "but VRM is not set\n",
-                   val);
-        }
-        break;
-    case AC97_PCM_LR_ADC_Rate:
-        if (mixer_load (s, AC97_Extended_Audio_Ctrl_Stat) & EACS_VRA) {
-            mixer_store (s, index, val);
-            dolog ("Set front LR ADC rate to %d\n", val);
-            open_voice (s, PI_INDEX, val);
-        }
-        else {
-            dolog ("Attempt to set LR ADC rate to %d, but VRA is not set\n",
-                    val);
-        }
-        break;
-    case AC97_Headphone_Volume_Mute:
-    case AC97_Master_Volume_Mono_Mute:
-    case AC97_Master_Tone_RL:
-    case AC97_PC_BEEP_Volume_Mute:
-    case AC97_Phone_Volume_Mute:
-    case AC97_Mic_Volume_Mute:
-    case AC97_Line_In_Volume_Mute:
-    case AC97_CD_Volume_Mute:
-    case AC97_Video_Volume_Mute:
-    case AC97_Aux_Volume_Mute:
-    case AC97_Record_Gain_Mic_Mute:
-    case AC97_General_Purpose:
-    case AC97_3D_Control:
-    case AC97_Sigmatel_Analog:
-    case AC97_Sigmatel_Dac2Invert:
-        /* None of the features in these regs are emulated, so they are RO */
-        break;
-    default:
-        dolog ("U nam writew %#x <- %#x\n", addr, val);
-        mixer_store (s, index, val);
-        break;
-    }
-}
-
-static void nam_writel (void *opaque, uint32_t addr, uint32_t val)
-{
-    AC97LinkState *s = opaque;
-    dolog ("U nam writel %#x <- %#x\n", addr, val);
-    s->cas = 0;
-}
-
-/**
- * Native audio bus master
- * I/O Reads
- */
-static uint32_t nabm_readb (void *opaque, uint32_t addr)
-{
-    AC97LinkState *s = opaque;
-    AC97BusMasterRegs *r = NULL;
-    uint32_t index = addr;
-    uint32_t val = ~0U;
-
-    switch (index) {
-    case CAS:
-        dolog ("CAS %d\n", s->cas);
-        val = s->cas;
-        s->cas = 1;
-        break;
-    case PI_CIV:
-    case PO_CIV:
-    case MC_CIV:
-        r = &s->bm_regs[GET_BM (index)];
-        val = r->civ;
-        dolog ("CIV[%d] -> %#x\n", GET_BM (index), val);
-        break;
-    case PI_LVI:
-    case PO_LVI:
-    case MC_LVI:
-        r = &s->bm_regs[GET_BM (index)];
-        val = r->lvi;
-        dolog ("LVI[%d] -> %#x\n", GET_BM (index), val);
-        break;
-    case PI_PIV:
-    case PO_PIV:
-    case MC_PIV:
-        r = &s->bm_regs[GET_BM (index)];
-        val = r->piv;
-        dolog ("PIV[%d] -> %#x\n", GET_BM (index), val);
-        break;
-    case PI_CR:
-    case PO_CR:
-    case MC_CR:
-        r = &s->bm_regs[GET_BM (index)];
-        val = r->cr;
-        dolog ("CR[%d] -> %#x\n", GET_BM (index), val);
-        break;
-    case PI_SR:
-    case PO_SR:
-    case MC_SR:
-        r = &s->bm_regs[GET_BM (index)];
-        val = r->sr & 0xff;
-        dolog ("SRb[%d] -> %#x\n", GET_BM (index), val);
-        break;
-    default:
-        dolog ("U nabm readb %#x -> %#x\n", addr, val);
-        break;
-    }
-    return val;
-}
-
-static uint32_t nabm_readw (void *opaque, uint32_t addr)
-{
-    AC97LinkState *s = opaque;
-    AC97BusMasterRegs *r = NULL;
-    uint32_t index = addr;
-    uint32_t val = ~0U;
-
-    switch (index) {
-    case PI_SR:
-    case PO_SR:
-    case MC_SR:
-        r = &s->bm_regs[GET_BM (index)];
-        val = r->sr;
-        dolog ("SR[%d] -> %#x\n", GET_BM (index), val);
-        break;
-    case PI_PICB:
-    case PO_PICB:
-    case MC_PICB:
-        r = &s->bm_regs[GET_BM (index)];
-        val = r->picb;
-        dolog ("PICB[%d] -> %#x\n", GET_BM (index), val);
-        break;
-    default:
-        dolog ("U nabm readw %#x -> %#x\n", addr, val);
-        break;
-    }
-    return val;
-}
-
-static uint32_t nabm_readl (void *opaque, uint32_t addr)
-{
-    AC97LinkState *s = opaque;
-    AC97BusMasterRegs *r = NULL;
-    uint32_t index = addr;
-    uint32_t val = ~0U;
-
-    switch (index) {
-    case PI_BDBAR:
-    case PO_BDBAR:
-    case MC_BDBAR:
-        r = &s->bm_regs[GET_BM (index)];
-        val = r->bdbar;
-        dolog ("BMADDR[%d] -> %#x\n", GET_BM (index), val);
-        break;
-    case PI_CIV:
-    case PO_CIV:
-    case MC_CIV:
-        r = &s->bm_regs[GET_BM (index)];
-        val = r->civ | (r->lvi << 8) | (r->sr << 16);
-        dolog ("CIV LVI SR[%d] -> %#x, %#x, %#x\n", GET_BM (index),
-               r->civ, r->lvi, r->sr);
-        break;
-    case PI_PICB:
-    case PO_PICB:
-    case MC_PICB:
-        r = &s->bm_regs[GET_BM (index)];
-        val = r->picb | (r->piv << 16) | (r->cr << 24);
-        dolog ("PICB PIV CR[%d] -> %#x %#x %#x %#x\n", GET_BM (index),
-               val, r->picb, r->piv, r->cr);
-        break;
-    case GLOB_CNT:
-        val = s->glob_cnt;
-        dolog ("glob_cnt -> %#x\n", val);
-        break;
-    case GLOB_STA:
-        val = s->glob_sta | GS_S0CR;
-        dolog ("glob_sta -> %#x\n", val);
-        break;
-    default:
-        dolog ("U nabm readl %#x -> %#x\n", addr, val);
-        break;
-    }
-    return val;
-}
-
-/**
- * Native audio bus master
- * I/O Writes
- */
-static void nabm_writeb (void *opaque, uint32_t addr, uint32_t val)
-{
-    AC97LinkState *s = opaque;
-    AC97BusMasterRegs *r = NULL;
-    uint32_t index = addr;
-    switch (index) {
-    case PI_LVI:
-    case PO_LVI:
-    case MC_LVI:
-        r = &s->bm_regs[GET_BM (index)];
-        if ((r->cr & CR_RPBM) && (r->sr & SR_DCH)) {
-            r->sr &= ~(SR_DCH | SR_CELV);
-            r->civ = r->piv;
-            r->piv = (r->piv + 1) % 32;
-            fetch_bd (s, r);
-        }
-        r->lvi = val % 32;
-        dolog ("LVI[%d] <- %#x\n", GET_BM (index), val);
-        break;
-    case PI_CR:
-    case PO_CR:
-    case MC_CR:
-        r = &s->bm_regs[GET_BM (index)];
-        if (val & CR_RR) {
-            reset_bm_regs (s, r);
-        }
-        else {
-            r->cr = val & CR_VALID_MASK;
-            if (!(r->cr & CR_RPBM)) {
-                voice_set_active (s, r - s->bm_regs, 0);
-                r->sr |= SR_DCH;
-            }
-            else {
-                r->civ = r->piv;
-                r->piv = (r->piv + 1) % 32;
-                fetch_bd (s, r);
-                r->sr &= ~SR_DCH;
-                voice_set_active (s, r - s->bm_regs, 1);
-            }
-        }
-        dolog ("CR[%d] <- %#x (cr %#x)\n", GET_BM (index), val, r->cr);
-        break;
-    case PI_SR:
-    case PO_SR:
-    case MC_SR:
-        r = &s->bm_regs[GET_BM (index)];
-        r->sr |= val & ~(SR_RO_MASK | SR_WCLEAR_MASK);
-        update_sr (s, r, r->sr & ~(val & SR_WCLEAR_MASK));
-        dolog ("SR[%d] <- %#x (sr %#x)\n", GET_BM (index), val, r->sr);
-        break;
-    default:
-        dolog ("U nabm writeb %#x <- %#x\n", addr, val);
-        break;
-    }
-}
-
-static void nabm_writew (void *opaque, uint32_t addr, uint32_t val)
-{
-    AC97LinkState *s = opaque;
-    AC97BusMasterRegs *r = NULL;
-    uint32_t index = addr;
-    switch (index) {
-    case PI_SR:
-    case PO_SR:
-    case MC_SR:
-        r = &s->bm_regs[GET_BM (index)];
-        r->sr |= val & ~(SR_RO_MASK | SR_WCLEAR_MASK);
-        update_sr (s, r, r->sr & ~(val & SR_WCLEAR_MASK));
-        dolog ("SR[%d] <- %#x (sr %#x)\n", GET_BM (index), val, r->sr);
-        break;
-    default:
-        dolog ("U nabm writew %#x <- %#x\n", addr, val);
-        break;
-    }
-}
-
-static void nabm_writel (void *opaque, uint32_t addr, uint32_t val)
-{
-    AC97LinkState *s = opaque;
-    AC97BusMasterRegs *r = NULL;
-    uint32_t index = addr;
-    switch (index) {
-    case PI_BDBAR:
-    case PO_BDBAR:
-    case MC_BDBAR:
-        r = &s->bm_regs[GET_BM (index)];
-        r->bdbar = val & ~3;
-        dolog ("BDBAR[%d] <- %#x (bdbar %#x)\n",
-               GET_BM (index), val, r->bdbar);
-        break;
-    case GLOB_CNT:
-        if (val & GC_WR)
-            warm_reset (s);
-        if (val & GC_CR)
-            cold_reset (s);
-        if (!(val & (GC_WR | GC_CR)))
-            s->glob_cnt = val & GC_VALID_MASK;
-        dolog ("glob_cnt <- %#x (glob_cnt %#x)\n", val, s->glob_cnt);
-        break;
-    case GLOB_STA:
-        s->glob_sta &= ~(val & GS_WCLEAR_MASK);
-        s->glob_sta |= (val & ~(GS_WCLEAR_MASK | GS_RO_MASK)) & GS_VALID_MASK;
-        dolog ("glob_sta <- %#x (glob_sta %#x)\n", val, s->glob_sta);
-        break;
-    default:
-        dolog ("U nabm writel %#x <- %#x\n", addr, val);
-        break;
-    }
-}
-
-static int write_audio (AC97LinkState *s, AC97BusMasterRegs *r,
-                        int max, int *stop)
-{
-    uint8_t tmpbuf[4096];
-    uint32_t addr = r->bd.addr;
-    uint32_t temp = r->picb << 1;
-    uint32_t written = 0;
-    int to_copy = 0;
-    temp = audio_MIN (temp, max);
-
-    if (!temp) {
-        *stop = 1;
-        return 0;
-    }
-
-    while (temp) {
-        int copied;
-        to_copy = audio_MIN (temp, sizeof (tmpbuf));
-        pci_dma_read (&s->dev, addr, tmpbuf, to_copy);
-        copied = AUD_write (s->voice_po, tmpbuf, to_copy);
-        dolog ("write_audio max=%x to_copy=%x copied=%x\n",
-               max, to_copy, copied);
-        if (!copied) {
-            *stop = 1;
-            break;
-        }
-        temp -= copied;
-        addr += copied;
-        written += copied;
-    }
-
-    if (!temp) {
-        if (to_copy < 4) {
-            dolog ("whoops\n");
-            s->last_samp = 0;
-        }
-        else {
-            s->last_samp = *(uint32_t *) &tmpbuf[to_copy - 4];
-        }
-    }
-
-    r->bd.addr = addr;
-    return written;
-}
-
-static void write_bup (AC97LinkState *s, int elapsed)
-{
-    dolog ("write_bup\n");
-    if (!(s->bup_flag & BUP_SET)) {
-        if (s->bup_flag & BUP_LAST) {
-            int i;
-            uint8_t *p = s->silence;
-            for (i = 0; i < sizeof (s->silence) / 4; i++, p += 4) {
-                *(uint32_t *) p = s->last_samp;
-            }
-        }
-        else {
-            memset (s->silence, 0, sizeof (s->silence));
-        }
-        s->bup_flag |= BUP_SET;
-    }
-
-    while (elapsed) {
-        int temp = audio_MIN (elapsed, sizeof (s->silence));
-        while (temp) {
-            int copied = AUD_write (s->voice_po, s->silence, temp);
-            if (!copied)
-                return;
-            temp -= copied;
-            elapsed -= copied;
-        }
-    }
-}
-
-static int read_audio (AC97LinkState *s, AC97BusMasterRegs *r,
-                       int max, int *stop)
-{
-    uint8_t tmpbuf[4096];
-    uint32_t addr = r->bd.addr;
-    uint32_t temp = r->picb << 1;
-    uint32_t nread = 0;
-    int to_copy = 0;
-    SWVoiceIn *voice = (r - s->bm_regs) == MC_INDEX ? s->voice_mc : s->voice_pi;
-
-    temp = audio_MIN (temp, max);
-
-    if (!temp) {
-        *stop = 1;
-        return 0;
-    }
-
-    while (temp) {
-        int acquired;
-        to_copy = audio_MIN (temp, sizeof (tmpbuf));
-        acquired = AUD_read (voice, tmpbuf, to_copy);
-        if (!acquired) {
-            *stop = 1;
-            break;
-        }
-        pci_dma_write (&s->dev, addr, tmpbuf, acquired);
-        temp -= acquired;
-        addr += acquired;
-        nread += acquired;
-    }
-
-    r->bd.addr = addr;
-    return nread;
-}
-
-static void transfer_audio (AC97LinkState *s, int index, int elapsed)
-{
-    AC97BusMasterRegs *r = &s->bm_regs[index];
-    int stop = 0;
-
-    if (s->invalid_freq[index]) {
-        AUD_log ("ac97", "attempt to use voice %d with invalid frequency %d\n",
-                 index, s->invalid_freq[index]);
-        return;
-    }
-
-    if (r->sr & SR_DCH) {
-        if (r->cr & CR_RPBM) {
-            switch (index) {
-            case PO_INDEX:
-                write_bup (s, elapsed);
-                break;
-            }
-        }
-        return;
-    }
-
-    while ((elapsed >> 1) && !stop) {
-        int temp;
-
-        if (!r->bd_valid) {
-            dolog ("invalid bd\n");
-            fetch_bd (s, r);
-        }
-
-        if (!r->picb) {
-            dolog ("fresh bd %d is empty %#x %#x\n",
-                   r->civ, r->bd.addr, r->bd.ctl_len);
-            if (r->civ == r->lvi) {
-                r->sr |= SR_DCH; /* CELV? */
-                s->bup_flag = 0;
-                break;
-            }
-            r->sr &= ~SR_CELV;
-            r->civ = r->piv;
-            r->piv = (r->piv + 1) % 32;
-            fetch_bd (s, r);
-            return;
-        }
-
-        switch (index) {
-        case PO_INDEX:
-            temp = write_audio (s, r, elapsed, &stop);
-            elapsed -= temp;
-            r->picb -= (temp >> 1);
-            break;
-
-        case PI_INDEX:
-        case MC_INDEX:
-            temp = read_audio (s, r, elapsed, &stop);
-            elapsed -= temp;
-            r->picb -= (temp >> 1);
-            break;
-        }
-
-        if (!r->picb) {
-            uint32_t new_sr = r->sr & ~SR_CELV;
-
-            if (r->bd.ctl_len & BD_IOC) {
-                new_sr |= SR_BCIS;
-            }
-
-            if (r->civ == r->lvi) {
-                dolog ("Underrun civ (%d) == lvi (%d)\n", r->civ, r->lvi);
-
-                new_sr |= SR_LVBCI | SR_DCH | SR_CELV;
-                stop = 1;
-                s->bup_flag = (r->bd.ctl_len & BD_BUP) ? BUP_LAST : 0;
-            }
-            else {
-                r->civ = r->piv;
-                r->piv = (r->piv + 1) % 32;
-                fetch_bd (s, r);
-            }
-
-            update_sr (s, r, new_sr);
-        }
-    }
-}
-
-static void pi_callback (void *opaque, int avail)
-{
-    transfer_audio (opaque, PI_INDEX, avail);
-}
-
-static void mc_callback (void *opaque, int avail)
-{
-    transfer_audio (opaque, MC_INDEX, avail);
-}
-
-static void po_callback (void *opaque, int free)
-{
-    transfer_audio (opaque, PO_INDEX, free);
-}
-
-static const VMStateDescription vmstate_ac97_bm_regs = {
-    .name = "ac97_bm_regs",
-    .version_id = 1,
-    .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 ()
-    }
-};
-
-static int ac97_post_load (void *opaque, int version_id)
-{
-    uint8_t active[LAST_INDEX];
-    AC97LinkState *s = opaque;
-
-    record_select (s, mixer_load (s, AC97_Record_Select));
-    set_volume (s, AC97_Master_Volume_Mute,
-                mixer_load (s, AC97_Master_Volume_Mute));
-    set_volume (s, AC97_PCM_Out_Volume_Mute,
-                mixer_load (s, AC97_PCM_Out_Volume_Mute));
-    set_volume (s, AC97_Record_Gain_Mute,
-                mixer_load (s, AC97_Record_Gain_Mute));
-
-    active[PI_INDEX] = !!(s->bm_regs[PI_INDEX].cr & CR_RPBM);
-    active[PO_INDEX] = !!(s->bm_regs[PO_INDEX].cr & CR_RPBM);
-    active[MC_INDEX] = !!(s->bm_regs[MC_INDEX].cr & CR_RPBM);
-    reset_voices (s, active);
-
-    s->bup_flag = 0;
-    s->last_samp = 0;
-    return 0;
-}
-
-static bool is_version_2 (void *opaque, int version_id)
-{
-    return version_id == 2;
-}
-
-static const VMStateDescription vmstate_ac97 = {
-    .name = "ac97",
-    .version_id = 3,
-    .minimum_version_id = 2,
-    .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 ()
-    }
-};
-
-static uint64_t nam_read(void *opaque, hwaddr addr, unsigned size)
-{
-    if ((addr / size) > 256) {
-        return -1;
-    }
-
-    switch (size) {
-    case 1:
-        return nam_readb(opaque, addr);
-    case 2:
-        return nam_readw(opaque, addr);
-    case 4:
-        return nam_readl(opaque, addr);
-    default:
-        return -1;
-    }
-}
-
-static void nam_write(void *opaque, hwaddr addr, uint64_t val,
-                      unsigned size)
-{
-    if ((addr / size) > 256) {
-        return;
-    }
-
-    switch (size) {
-    case 1:
-        nam_writeb(opaque, addr, val);
-        break;
-    case 2:
-        nam_writew(opaque, addr, val);
-        break;
-    case 4:
-        nam_writel(opaque, addr, val);
-        break;
-    }
-}
-
-static const MemoryRegionOps ac97_io_nam_ops = {
-    .read = nam_read,
-    .write = nam_write,
-    .impl = {
-        .min_access_size = 1,
-        .max_access_size = 4,
-    },
-    .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static uint64_t nabm_read(void *opaque, hwaddr addr, unsigned size)
-{
-    if ((addr / size) > 64) {
-        return -1;
-    }
-
-    switch (size) {
-    case 1:
-        return nabm_readb(opaque, addr);
-    case 2:
-        return nabm_readw(opaque, addr);
-    case 4:
-        return nabm_readl(opaque, addr);
-    default:
-        return -1;
-    }
-}
-
-static void nabm_write(void *opaque, hwaddr addr, uint64_t val,
-                      unsigned size)
-{
-    if ((addr / size) > 64) {
-        return;
-    }
-
-    switch (size) {
-    case 1:
-        nabm_writeb(opaque, addr, val);
-        break;
-    case 2:
-        nabm_writew(opaque, addr, val);
-        break;
-    case 4:
-        nabm_writel(opaque, addr, val);
-        break;
-    }
-}
-
-
-static const MemoryRegionOps ac97_io_nabm_ops = {
-    .read = nabm_read,
-    .write = nabm_write,
-    .impl = {
-        .min_access_size = 1,
-        .max_access_size = 4,
-    },
-    .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static void ac97_on_reset (void *opaque)
-{
-    AC97LinkState *s = opaque;
-
-    reset_bm_regs (s, &s->bm_regs[0]);
-    reset_bm_regs (s, &s->bm_regs[1]);
-    reset_bm_regs (s, &s->bm_regs[2]);
-
-    /*
-     * Reset the mixer too. The Windows XP driver seems to rely on
-     * this. At least it wants to read the vendor id before it resets
-     * the codec manually.
-     */
-    mixer_reset (s);
-}
-
-static int ac97_initfn (PCIDevice *dev)
-{
-    AC97LinkState *s = DO_UPCAST (AC97LinkState, dev, dev);
-    uint8_t *c = s->dev.config;
-
-    /* TODO: no need to override */
-    c[PCI_COMMAND] = 0x00;      /* pcicmd pci command rw, ro */
-    c[PCI_COMMAND + 1] = 0x00;
-
-    /* TODO: */
-    c[PCI_STATUS] = PCI_STATUS_FAST_BACK;      /* pcists pci status rwc, ro */
-    c[PCI_STATUS + 1] = PCI_STATUS_DEVSEL_MEDIUM >> 8;
-
-    c[PCI_CLASS_PROG] = 0x00;      /* pi programming interface ro */
-
-    /* TODO set when bar is registered. no need to override. */
-    /* nabmar native audio mixer base address rw */
-    c[PCI_BASE_ADDRESS_0] = PCI_BASE_ADDRESS_SPACE_IO;
-    c[PCI_BASE_ADDRESS_0 + 1] = 0x00;
-    c[PCI_BASE_ADDRESS_0 + 2] = 0x00;
-    c[PCI_BASE_ADDRESS_0 + 3] = 0x00;
-
-    /* TODO set when bar is registered. no need to override. */
-      /* nabmbar native audio bus mastering base address rw */
-    c[PCI_BASE_ADDRESS_0 + 4] = PCI_BASE_ADDRESS_SPACE_IO;
-    c[PCI_BASE_ADDRESS_0 + 5] = 0x00;
-    c[PCI_BASE_ADDRESS_0 + 6] = 0x00;
-    c[PCI_BASE_ADDRESS_0 + 7] = 0x00;
-
-    if (s->use_broken_id) {
-        c[PCI_SUBSYSTEM_VENDOR_ID] = 0x86;
-        c[PCI_SUBSYSTEM_VENDOR_ID + 1] = 0x80;
-        c[PCI_SUBSYSTEM_ID] = 0x00;
-        c[PCI_SUBSYSTEM_ID + 1] = 0x00;
-    }
-
-    c[PCI_INTERRUPT_LINE] = 0x00;      /* intr_ln interrupt line rw */
-    c[PCI_INTERRUPT_PIN] = 0x01;      /* intr_pn interrupt pin ro */
-
-    memory_region_init_io (&s->io_nam, &ac97_io_nam_ops, s, "ac97-nam", 1024);
-    memory_region_init_io (&s->io_nabm, &ac97_io_nabm_ops, s, "ac97-nabm", 256);
-    pci_register_bar (&s->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io_nam);
-    pci_register_bar (&s->dev, 1, PCI_BASE_ADDRESS_SPACE_IO, &s->io_nabm);
-    qemu_register_reset (ac97_on_reset, s);
-    AUD_register_card ("ac97", &s->card);
-    ac97_on_reset (s);
-    return 0;
-}
-
-static void ac97_exitfn (PCIDevice *dev)
-{
-    AC97LinkState *s = DO_UPCAST (AC97LinkState, dev, dev);
-
-    memory_region_destroy (&s->io_nam);
-    memory_region_destroy (&s->io_nabm);
-}
-
-int ac97_init (PCIBus *bus)
-{
-    pci_create_simple (bus, -1, "AC97");
-    return 0;
-}
-
-static Property ac97_properties[] = {
-    DEFINE_PROP_UINT32 ("use_broken_id", AC97LinkState, use_broken_id, 0),
-    DEFINE_PROP_END_OF_LIST (),
-};
-
-static void ac97_class_init (ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS (klass);
-    PCIDeviceClass *k = PCI_DEVICE_CLASS (klass);
-
-    k->init = ac97_initfn;
-    k->exit = ac97_exitfn;
-    k->vendor_id = PCI_VENDOR_ID_INTEL;
-    k->device_id = PCI_DEVICE_ID_INTEL_82801AA_5;
-    k->revision = 0x01;
-    k->class_id = PCI_CLASS_MULTIMEDIA_AUDIO;
-    dc->desc = "Intel 82801AA AC97 Audio";
-    dc->vmsd = &vmstate_ac97;
-    dc->props = ac97_properties;
-}
-
-static const TypeInfo ac97_info = {
-    .name          = "AC97",
-    .parent        = TYPE_PCI_DEVICE,
-    .instance_size = sizeof (AC97LinkState),
-    .class_init    = ac97_class_init,
-};
-
-static void ac97_register_types (void)
-{
-    type_register_static (&ac97_info);
-}
-
-type_init (ac97_register_types)
diff --git a/hw/acpi.c b/hw/acpi.c
deleted file mode 100644 (file)
index 856da81..0000000
--- a/hw/acpi.c
+++ /dev/null
@@ -1,614 +0,0 @@
-/*
- * ACPI implementation
- *
- * Copyright (c) 2006 Fabrice Bellard
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License version 2 as published by the Free Software Foundation.
- *
- * 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/>
- *
- * 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/sysemu.h"
-#include "hw/hw.h"
-#include "hw/pc.h"
-#include "hw/acpi.h"
-#include "monitor/monitor.h"
-#include "qemu/config-file.h"
-#include "qapi/opts-visitor.h"
-#include "qapi/dealloc-visitor.h"
-#include "qapi-visit.h"
-
-struct acpi_table_header {
-    uint16_t _length;         /* our length, not actual part of the hdr */
-                              /* allows easier parsing for fw_cfg clients */
-    char sig[4];              /* ACPI signature (4 ASCII characters) */
-    uint32_t length;          /* Length of table, in bytes, including header */
-    uint8_t revision;         /* ACPI Specification minor version # */
-    uint8_t checksum;         /* To make sum of entire table == 0 */
-    char oem_id[6];           /* OEM identification */
-    char oem_table_id[8];     /* OEM table identification */
-    uint32_t oem_revision;    /* OEM revision number */
-    char asl_compiler_id[4];  /* ASL compiler vendor ID */
-    uint32_t asl_compiler_revision; /* ASL compiler revision number */
-} QEMU_PACKED;
-
-#define ACPI_TABLE_HDR_SIZE sizeof(struct acpi_table_header)
-#define ACPI_TABLE_PFX_SIZE sizeof(uint16_t)  /* size of the extra prefix */
-
-static const char unsigned dfl_hdr[ACPI_TABLE_HDR_SIZE - ACPI_TABLE_PFX_SIZE] =
-    "QEMU\0\0\0\0\1\0"       /* sig (4), len(4), revno (1), csum (1) */
-    "QEMUQEQEMUQEMU\1\0\0\0" /* OEM id (6), table (8), revno (4) */
-    "QEMU\1\0\0\0"           /* ASL compiler ID (4), version (4) */
-    ;
-
-char unsigned *acpi_tables;
-size_t acpi_tables_len;
-
-static QemuOptsList qemu_acpi_opts = {
-    .name = "acpi",
-    .implied_opt_name = "data",
-    .head = QTAILQ_HEAD_INITIALIZER(qemu_acpi_opts.head),
-    .desc = { { 0 } } /* validated with OptsVisitor */
-};
-
-static void acpi_register_config(void)
-{
-    qemu_add_opts(&qemu_acpi_opts);
-}
-
-machine_init(acpi_register_config);
-
-static int acpi_checksum(const uint8_t *data, int len)
-{
-    int sum, i;
-    sum = 0;
-    for (i = 0; i < len; i++) {
-        sum += data[i];
-    }
-    return (-sum) & 0xff;
-}
-
-
-/* Install a copy of the ACPI table specified in @blob.
- *
- * If @has_header is set, @blob starts with the System Description Table Header
- * structure. Otherwise, "dfl_hdr" is prepended. In any case, each header field
- * is optionally overwritten from @hdrs.
- *
- * It is valid to call this function with
- * (@blob == NULL && bloblen == 0 && !has_header).
- *
- * @hdrs->file and @hdrs->data are ignored.
- *
- * SIZE_MAX is considered "infinity" in this function.
- *
- * The number of tables that can be installed is not limited, but the 16-bit
- * counter at the beginning of "acpi_tables" wraps around after UINT16_MAX.
- */
-static void acpi_table_install(const char unsigned *blob, size_t bloblen,
-                               bool has_header,
-                               const struct AcpiTableOptions *hdrs,
-                               Error **errp)
-{
-    size_t body_start;
-    const char unsigned *hdr_src;
-    size_t body_size, acpi_payload_size;
-    struct acpi_table_header *ext_hdr;
-    unsigned changed_fields;
-
-    /* Calculate where the ACPI table body starts within the blob, plus where
-     * to copy the ACPI table header from.
-     */
-    if (has_header) {
-        /*   _length             | ACPI header in blob | blob body
-         *   ^^^^^^^^^^^^^^^^^^^   ^^^^^^^^^^^^^^^^^^^   ^^^^^^^^^
-         *   ACPI_TABLE_PFX_SIZE     sizeof dfl_hdr      body_size
-         *                           == body_start
-         *
-         *                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-         *                           acpi_payload_size == bloblen
-         */
-        body_start = sizeof dfl_hdr;
-
-        if (bloblen < body_start) {
-            error_setg(errp, "ACPI table claiming to have header is too "
-                       "short, available: %zu, expected: %zu", bloblen,
-                       body_start);
-            return;
-        }
-        hdr_src = blob;
-    } else {
-        /*   _length             | ACPI header in template | blob body
-         *   ^^^^^^^^^^^^^^^^^^^   ^^^^^^^^^^^^^^^^^^^^^^^   ^^^^^^^^^^
-         *   ACPI_TABLE_PFX_SIZE       sizeof dfl_hdr        body_size
-         *                                                   == bloblen
-         *
-         *                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-         *                                  acpi_payload_size
-         */
-        body_start = 0;
-        hdr_src = dfl_hdr;
-    }
-    body_size = bloblen - body_start;
-    acpi_payload_size = sizeof dfl_hdr + body_size;
-
-    if (acpi_payload_size > UINT16_MAX) {
-        error_setg(errp, "ACPI table too big, requested: %zu, max: %u",
-                   acpi_payload_size, (unsigned)UINT16_MAX);
-        return;
-    }
-
-    /* We won't fail from here on. Initialize / extend the globals. */
-    if (acpi_tables == NULL) {
-        acpi_tables_len = sizeof(uint16_t);
-        acpi_tables = g_malloc0(acpi_tables_len);
-    }
-
-    acpi_tables = g_realloc(acpi_tables, acpi_tables_len +
-                                         ACPI_TABLE_PFX_SIZE +
-                                         sizeof dfl_hdr + body_size);
-
-    ext_hdr = (struct acpi_table_header *)(acpi_tables + acpi_tables_len);
-    acpi_tables_len += ACPI_TABLE_PFX_SIZE;
-
-    memcpy(acpi_tables + acpi_tables_len, hdr_src, sizeof dfl_hdr);
-    acpi_tables_len += sizeof dfl_hdr;
-
-    if (blob != NULL) {
-        memcpy(acpi_tables + acpi_tables_len, blob + body_start, body_size);
-        acpi_tables_len += body_size;
-    }
-
-    /* increase number of tables */
-    cpu_to_le16wu((uint16_t *)acpi_tables,
-                  le16_to_cpupu((uint16_t *)acpi_tables) + 1u);
-
-    /* Update the header fields. The strings need not be NUL-terminated. */
-    changed_fields = 0;
-    ext_hdr->_length = cpu_to_le16(acpi_payload_size);
-
-    if (hdrs->has_sig) {
-        strncpy(ext_hdr->sig, hdrs->sig, sizeof ext_hdr->sig);
-        ++changed_fields;
-    }
-
-    if (has_header && le32_to_cpu(ext_hdr->length) != acpi_payload_size) {
-        fprintf(stderr,
-                "warning: ACPI table has wrong length, header says "
-                "%" PRIu32 ", actual size %zu bytes\n",
-                le32_to_cpu(ext_hdr->length), acpi_payload_size);
-    }
-    ext_hdr->length = cpu_to_le32(acpi_payload_size);
-
-    if (hdrs->has_rev) {
-        ext_hdr->revision = hdrs->rev;
-        ++changed_fields;
-    }
-
-    ext_hdr->checksum = 0;
-
-    if (hdrs->has_oem_id) {
-        strncpy(ext_hdr->oem_id, hdrs->oem_id, sizeof ext_hdr->oem_id);
-        ++changed_fields;
-    }
-    if (hdrs->has_oem_table_id) {
-        strncpy(ext_hdr->oem_table_id, hdrs->oem_table_id,
-                sizeof ext_hdr->oem_table_id);
-        ++changed_fields;
-    }
-    if (hdrs->has_oem_rev) {
-        ext_hdr->oem_revision = cpu_to_le32(hdrs->oem_rev);
-        ++changed_fields;
-    }
-    if (hdrs->has_asl_compiler_id) {
-        strncpy(ext_hdr->asl_compiler_id, hdrs->asl_compiler_id,
-                sizeof ext_hdr->asl_compiler_id);
-        ++changed_fields;
-    }
-    if (hdrs->has_asl_compiler_rev) {
-        ext_hdr->asl_compiler_revision = cpu_to_le32(hdrs->asl_compiler_rev);
-        ++changed_fields;
-    }
-
-    if (!has_header && changed_fields == 0) {
-        fprintf(stderr, "warning: ACPI table: no headers are specified\n");
-    }
-
-    /* recalculate checksum */
-    ext_hdr->checksum = acpi_checksum((const char unsigned *)ext_hdr +
-                                      ACPI_TABLE_PFX_SIZE, acpi_payload_size);
-}
-
-void acpi_table_add(const QemuOpts *opts, Error **errp)
-{
-    AcpiTableOptions *hdrs = NULL;
-    Error *err = NULL;
-    char **pathnames = NULL;
-    char **cur;
-    size_t bloblen = 0;
-    char unsigned *blob = NULL;
-
-    {
-        OptsVisitor *ov;
-
-        ov = opts_visitor_new(opts);
-        visit_type_AcpiTableOptions(opts_get_visitor(ov), &hdrs, NULL, &err);
-        opts_visitor_cleanup(ov);
-    }
-
-    if (err) {
-        goto out;
-    }
-    if (hdrs->has_file == hdrs->has_data) {
-        error_setg(&err, "'-acpitable' requires one of 'data' or 'file'");
-        goto out;
-    }
-
-    pathnames = g_strsplit(hdrs->has_file ? hdrs->file : hdrs->data, ":", 0);
-    if (pathnames == NULL || pathnames[0] == NULL) {
-        error_setg(&err, "'-acpitable' requires at least one pathname");
-        goto out;
-    }
-
-    /* now read in the data files, reallocating buffer as needed */
-    for (cur = pathnames; *cur; ++cur) {
-        int fd = open(*cur, O_RDONLY | O_BINARY);
-
-        if (fd < 0) {
-            error_setg(&err, "can't open file %s: %s", *cur, strerror(errno));
-            goto out;
-        }
-
-        for (;;) {
-            char unsigned data[8192];
-            ssize_t r;
-
-            r = read(fd, data, sizeof data);
-            if (r == 0) {
-                break;
-            } else if (r > 0) {
-                blob = g_realloc(blob, bloblen + r);
-                memcpy(blob + bloblen, data, r);
-                bloblen += r;
-            } else if (errno != EINTR) {
-                error_setg(&err, "can't read file %s: %s",
-                           *cur, strerror(errno));
-                close(fd);
-                goto out;
-            }
-        }
-
-        close(fd);
-    }
-
-    acpi_table_install(blob, bloblen, hdrs->has_file, hdrs, &err);
-
-out:
-    g_free(blob);
-    g_strfreev(pathnames);
-
-    if (hdrs != NULL) {
-        QapiDeallocVisitor *dv;
-
-        dv = qapi_dealloc_visitor_new();
-        visit_type_AcpiTableOptions(qapi_dealloc_get_visitor(dv), &hdrs, NULL,
-                                    NULL);
-        qapi_dealloc_visitor_cleanup(dv);
-    }
-
-    error_propagate(errp, err);
-}
-
-static void acpi_notify_wakeup(Notifier *notifier, void *data)
-{
-    ACPIREGS *ar = container_of(notifier, ACPIREGS, wakeup);
-    WakeupReason *reason = data;
-
-    switch (*reason) {
-    case QEMU_WAKEUP_REASON_RTC:
-        ar->pm1.evt.sts |=
-            (ACPI_BITMASK_WAKE_STATUS | ACPI_BITMASK_RT_CLOCK_STATUS);
-        break;
-    case QEMU_WAKEUP_REASON_PMTIMER:
-        ar->pm1.evt.sts |=
-            (ACPI_BITMASK_WAKE_STATUS | ACPI_BITMASK_TIMER_STATUS);
-        break;
-    case QEMU_WAKEUP_REASON_OTHER:
-    default:
-        /* ACPI_BITMASK_WAKE_STATUS should be set on resume.
-           Pretend that resume was caused by power button */
-        ar->pm1.evt.sts |=
-            (ACPI_BITMASK_WAKE_STATUS | ACPI_BITMASK_POWER_BUTTON_STATUS);
-        break;
-    }
-}
-
-/* ACPI PM1a EVT */
-uint16_t acpi_pm1_evt_get_sts(ACPIREGS *ar)
-{
-    int64_t d = acpi_pm_tmr_get_clock();
-    if (d >= ar->tmr.overflow_time) {
-        ar->pm1.evt.sts |= ACPI_BITMASK_TIMER_STATUS;
-    }
-    return ar->pm1.evt.sts;
-}
-
-static void acpi_pm1_evt_write_sts(ACPIREGS *ar, uint16_t val)
-{
-    uint16_t pm1_sts = acpi_pm1_evt_get_sts(ar);
-    if (pm1_sts & val & ACPI_BITMASK_TIMER_STATUS) {
-        /* if TMRSTS is reset, then compute the new overflow time */
-        acpi_pm_tmr_calc_overflow_time(ar);
-    }
-    ar->pm1.evt.sts &= ~val;
-}
-
-static void acpi_pm1_evt_write_en(ACPIREGS *ar, uint16_t val)
-{
-    ar->pm1.evt.en = val;
-    qemu_system_wakeup_enable(QEMU_WAKEUP_REASON_RTC,
-                              val & ACPI_BITMASK_RT_CLOCK_ENABLE);
-    qemu_system_wakeup_enable(QEMU_WAKEUP_REASON_PMTIMER,
-                              val & ACPI_BITMASK_TIMER_ENABLE);
-}
-
-void acpi_pm1_evt_power_down(ACPIREGS *ar)
-{
-    if (ar->pm1.evt.en & ACPI_BITMASK_POWER_BUTTON_ENABLE) {
-        ar->pm1.evt.sts |= ACPI_BITMASK_POWER_BUTTON_STATUS;
-        ar->tmr.update_sci(ar);
-    }
-}
-
-void acpi_pm1_evt_reset(ACPIREGS *ar)
-{
-    ar->pm1.evt.sts = 0;
-    ar->pm1.evt.en = 0;
-    qemu_system_wakeup_enable(QEMU_WAKEUP_REASON_RTC, 0);
-    qemu_system_wakeup_enable(QEMU_WAKEUP_REASON_PMTIMER, 0);
-}
-
-static uint64_t acpi_pm_evt_read(void *opaque, hwaddr addr, unsigned width)
-{
-    ACPIREGS *ar = opaque;
-    switch (addr) {
-    case 0:
-        return acpi_pm1_evt_get_sts(ar);
-    case 2:
-        return ar->pm1.evt.en;
-    default:
-        return 0;
-    }
-}
-
-static void acpi_pm_evt_write(void *opaque, hwaddr addr, uint64_t val,
-                              unsigned width)
-{
-    ACPIREGS *ar = opaque;
-    switch (addr) {
-    case 0:
-        acpi_pm1_evt_write_sts(ar, val);
-        ar->pm1.evt.update_sci(ar);
-        break;
-    case 2:
-        acpi_pm1_evt_write_en(ar, val);
-        ar->pm1.evt.update_sci(ar);
-        break;
-    }
-}
-
-static const MemoryRegionOps acpi_pm_evt_ops = {
-    .read = acpi_pm_evt_read,
-    .write = acpi_pm_evt_write,
-    .valid.min_access_size = 2,
-    .valid.max_access_size = 2,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-void acpi_pm1_evt_init(ACPIREGS *ar, acpi_update_sci_fn update_sci,
-                       MemoryRegion *parent)
-{
-    ar->pm1.evt.update_sci = update_sci;
-    memory_region_init_io(&ar->pm1.evt.io, &acpi_pm_evt_ops, ar, "acpi-evt", 4);
-    memory_region_add_subregion(parent, 0, &ar->pm1.evt.io);
-}
-
-/* ACPI PM_TMR */
-void acpi_pm_tmr_update(ACPIREGS *ar, bool enable)
-{
-    int64_t expire_time;
-
-    /* schedule a timer interruption if needed */
-    if (enable) {
-        expire_time = muldiv64(ar->tmr.overflow_time, get_ticks_per_sec(),
-                               PM_TIMER_FREQUENCY);
-        qemu_mod_timer(ar->tmr.timer, expire_time);
-    } else {
-        qemu_del_timer(ar->tmr.timer);
-    }
-}
-
-void acpi_pm_tmr_calc_overflow_time(ACPIREGS *ar)
-{
-    int64_t d = acpi_pm_tmr_get_clock();
-    ar->tmr.overflow_time = (d + 0x800000LL) & ~0x7fffffLL;
-}
-
-static uint32_t acpi_pm_tmr_get(ACPIREGS *ar)
-{
-    uint32_t d = acpi_pm_tmr_get_clock();
-    return d & 0xffffff;
-}
-
-static void acpi_pm_tmr_timer(void *opaque)
-{
-    ACPIREGS *ar = opaque;
-    qemu_system_wakeup_request(QEMU_WAKEUP_REASON_PMTIMER);
-    ar->tmr.update_sci(ar);
-}
-
-static uint64_t acpi_pm_tmr_read(void *opaque, hwaddr addr, unsigned width)
-{
-    return acpi_pm_tmr_get(opaque);
-}
-
-static const MemoryRegionOps acpi_pm_tmr_ops = {
-    .read = acpi_pm_tmr_read,
-    .valid.min_access_size = 4,
-    .valid.max_access_size = 4,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-void acpi_pm_tmr_init(ACPIREGS *ar, acpi_update_sci_fn update_sci,
-                      MemoryRegion *parent)
-{
-    ar->tmr.update_sci = update_sci;
-    ar->tmr.timer = qemu_new_timer_ns(vm_clock, acpi_pm_tmr_timer, ar);
-    memory_region_init_io(&ar->tmr.io, &acpi_pm_tmr_ops, ar, "acpi-tmr", 4);
-    memory_region_add_subregion(parent, 8, &ar->tmr.io);
-}
-
-void acpi_pm_tmr_reset(ACPIREGS *ar)
-{
-    ar->tmr.overflow_time = 0;
-    qemu_del_timer(ar->tmr.timer);
-}
-
-/* ACPI PM1aCNT */
-static void acpi_pm1_cnt_write(ACPIREGS *ar, uint16_t val)
-{
-    ar->pm1.cnt.cnt = val & ~(ACPI_BITMASK_SLEEP_ENABLE);
-
-    if (val & ACPI_BITMASK_SLEEP_ENABLE) {
-        /* change suspend type */
-        uint16_t sus_typ = (val >> 10) & 7;
-        switch(sus_typ) {
-        case 0: /* soft power off */
-            qemu_system_shutdown_request();
-            break;
-        case 1:
-            qemu_system_suspend_request();
-            break;
-        default:
-            if (sus_typ == ar->pm1.cnt.s4_val) { /* S4 request */
-                monitor_protocol_event(QEVENT_SUSPEND_DISK, NULL);
-                qemu_system_shutdown_request();
-            }
-            break;
-        }
-    }
-}
-
-void acpi_pm1_cnt_update(ACPIREGS *ar,
-                         bool sci_enable, bool sci_disable)
-{
-    /* ACPI specs 3.0, 4.7.2.5 */
-    if (sci_enable) {
-        ar->pm1.cnt.cnt |= ACPI_BITMASK_SCI_ENABLE;
-    } else if (sci_disable) {
-        ar->pm1.cnt.cnt &= ~ACPI_BITMASK_SCI_ENABLE;
-    }
-}
-
-static uint64_t acpi_pm_cnt_read(void *opaque, hwaddr addr, unsigned width)
-{
-    ACPIREGS *ar = opaque;
-    return ar->pm1.cnt.cnt;
-}
-
-static void acpi_pm_cnt_write(void *opaque, hwaddr addr, uint64_t val,
-                              unsigned width)
-{
-    acpi_pm1_cnt_write(opaque, val);
-}
-
-static const MemoryRegionOps acpi_pm_cnt_ops = {
-    .read = acpi_pm_cnt_read,
-    .write = acpi_pm_cnt_write,
-    .valid.min_access_size = 2,
-    .valid.max_access_size = 2,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-void acpi_pm1_cnt_init(ACPIREGS *ar, MemoryRegion *parent, uint8_t s4_val)
-{
-    ar->pm1.cnt.s4_val = s4_val;
-    ar->wakeup.notify = acpi_notify_wakeup;
-    qemu_register_wakeup_notifier(&ar->wakeup);
-    memory_region_init_io(&ar->pm1.cnt.io, &acpi_pm_cnt_ops, ar, "acpi-cnt", 2);
-    memory_region_add_subregion(parent, 4, &ar->pm1.cnt.io);
-}
-
-void acpi_pm1_cnt_reset(ACPIREGS *ar)
-{
-    ar->pm1.cnt.cnt = 0;
-}
-
-/* ACPI GPE */
-void acpi_gpe_init(ACPIREGS *ar, uint8_t len)
-{
-    ar->gpe.len = len;
-    ar->gpe.sts = g_malloc0(len / 2);
-    ar->gpe.en = g_malloc0(len / 2);
-}
-
-void acpi_gpe_reset(ACPIREGS *ar)
-{
-    memset(ar->gpe.sts, 0, ar->gpe.len / 2);
-    memset(ar->gpe.en, 0, ar->gpe.len / 2);
-}
-
-static uint8_t *acpi_gpe_ioport_get_ptr(ACPIREGS *ar, uint32_t addr)
-{
-    uint8_t *cur = NULL;
-
-    if (addr < ar->gpe.len / 2) {
-        cur = ar->gpe.sts + addr;
-    } else if (addr < ar->gpe.len) {
-        cur = ar->gpe.en + addr - ar->gpe.len / 2;
-    } else {
-        abort();
-    }
-
-    return cur;
-}
-
-void acpi_gpe_ioport_writeb(ACPIREGS *ar, uint32_t addr, uint32_t val)
-{
-    uint8_t *cur;
-
-    cur = acpi_gpe_ioport_get_ptr(ar, addr);
-    if (addr < ar->gpe.len / 2) {
-        /* GPE_STS */
-        *cur = (*cur) & ~val;
-    } else if (addr < ar->gpe.len) {
-        /* GPE_EN */
-        *cur = val;
-    } else {
-        abort();
-    }
-}
-
-uint32_t acpi_gpe_ioport_readb(ACPIREGS *ar, uint32_t addr)
-{
-    uint8_t *cur;
-    uint32_t val;
-
-    cur = acpi_gpe_ioport_get_ptr(ar, addr);
-    val = 0;
-    if (cur != NULL) {
-        val = *cur;
-    }
-
-    return val;
-}
diff --git a/hw/acpi.h b/hw/acpi.h
deleted file mode 100644 (file)
index e18ef28..0000000
--- a/hw/acpi.h
+++ /dev/null
@@ -1,157 +0,0 @@
-#ifndef QEMU_HW_ACPI_H
-#define QEMU_HW_ACPI_H
-/*
- *  Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp>
- *                     VA Linux Systems Japan K.K.
- *
- * 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/>.
- */
-
-/* from linux include/acpi/actype.h */
-/* Default ACPI register widths */
-
-#define ACPI_GPE_REGISTER_WIDTH         8
-#define ACPI_PM1_REGISTER_WIDTH         16
-#define ACPI_PM2_REGISTER_WIDTH         8
-#define ACPI_PM_TIMER_WIDTH             32
-
-/* PM Timer ticks per second (HZ) */
-#define PM_TIMER_FREQUENCY  3579545
-
-
-/* ACPI fixed hardware registers */
-
-/* from linux/drivers/acpi/acpica/aclocal.h */
-/* Masks used to access the bit_registers */
-
-/* PM1x_STS */
-#define ACPI_BITMASK_TIMER_STATUS               0x0001
-#define ACPI_BITMASK_BUS_MASTER_STATUS          0x0010
-#define ACPI_BITMASK_GLOBAL_LOCK_STATUS         0x0020
-#define ACPI_BITMASK_POWER_BUTTON_STATUS        0x0100
-#define ACPI_BITMASK_SLEEP_BUTTON_STATUS        0x0200
-#define ACPI_BITMASK_RT_CLOCK_STATUS            0x0400
-#define ACPI_BITMASK_PCIEXP_WAKE_STATUS         0x4000 /* ACPI 3.0 */
-#define ACPI_BITMASK_WAKE_STATUS                0x8000
-
-#define ACPI_BITMASK_ALL_FIXED_STATUS           (\
-       ACPI_BITMASK_TIMER_STATUS          | \
-       ACPI_BITMASK_BUS_MASTER_STATUS     | \
-       ACPI_BITMASK_GLOBAL_LOCK_STATUS    | \
-       ACPI_BITMASK_POWER_BUTTON_STATUS   | \
-       ACPI_BITMASK_SLEEP_BUTTON_STATUS   | \
-       ACPI_BITMASK_RT_CLOCK_STATUS       | \
-       ACPI_BITMASK_WAKE_STATUS)
-
-/* PM1x_EN */
-#define ACPI_BITMASK_TIMER_ENABLE               0x0001
-#define ACPI_BITMASK_GLOBAL_LOCK_ENABLE         0x0020
-#define ACPI_BITMASK_POWER_BUTTON_ENABLE        0x0100
-#define ACPI_BITMASK_SLEEP_BUTTON_ENABLE        0x0200
-#define ACPI_BITMASK_RT_CLOCK_ENABLE            0x0400
-#define ACPI_BITMASK_PCIEXP_WAKE_DISABLE        0x4000 /* ACPI 3.0 */
-
-/* PM1x_CNT */
-#define ACPI_BITMASK_SCI_ENABLE                 0x0001
-#define ACPI_BITMASK_BUS_MASTER_RLD             0x0002
-#define ACPI_BITMASK_GLOBAL_LOCK_RELEASE        0x0004
-#define ACPI_BITMASK_SLEEP_TYPE                 0x1C00
-#define ACPI_BITMASK_SLEEP_ENABLE               0x2000
-
-/* PM2_CNT */
-#define ACPI_BITMASK_ARB_DISABLE                0x0001
-
-/* structs */
-typedef struct ACPIPMTimer ACPIPMTimer;
-typedef struct ACPIPM1EVT ACPIPM1EVT;
-typedef struct ACPIPM1CNT ACPIPM1CNT;
-typedef struct ACPIGPE ACPIGPE;
-typedef struct ACPIREGS ACPIREGS;
-
-typedef void (*acpi_update_sci_fn)(ACPIREGS *ar);
-
-struct ACPIPMTimer {
-    QEMUTimer *timer;
-    MemoryRegion io;
-    int64_t overflow_time;
-
-    acpi_update_sci_fn update_sci;
-};
-
-struct ACPIPM1EVT {
-    MemoryRegion io;
-    uint16_t sts;
-    uint16_t en;
-    acpi_update_sci_fn update_sci;
-};
-
-struct ACPIPM1CNT {
-    MemoryRegion io;
-    uint16_t cnt;
-    uint8_t s4_val;
-};
-
-struct ACPIGPE {
-    uint8_t len;
-
-    uint8_t *sts;
-    uint8_t *en;
-};
-
-struct ACPIREGS {
-    ACPIPMTimer     tmr;
-    ACPIGPE         gpe;
-    struct {
-        ACPIPM1EVT  evt;
-        ACPIPM1CNT  cnt;
-    } pm1;
-    Notifier wakeup;
-};
-
-/* PM_TMR */
-void acpi_pm_tmr_update(ACPIREGS *ar, bool enable);
-void acpi_pm_tmr_calc_overflow_time(ACPIREGS *ar);
-void acpi_pm_tmr_init(ACPIREGS *ar, acpi_update_sci_fn update_sci,
-                      MemoryRegion *parent);
-void acpi_pm_tmr_reset(ACPIREGS *ar);
-
-#include "qemu/timer.h"
-static inline int64_t acpi_pm_tmr_get_clock(void)
-{
-    return muldiv64(qemu_get_clock_ns(vm_clock), PM_TIMER_FREQUENCY,
-                    get_ticks_per_sec());
-}
-
-/* PM1a_EVT: piix and ich9 don't implement PM1b. */
-uint16_t acpi_pm1_evt_get_sts(ACPIREGS *ar);
-void acpi_pm1_evt_power_down(ACPIREGS *ar);
-void acpi_pm1_evt_reset(ACPIREGS *ar);
-void acpi_pm1_evt_init(ACPIREGS *ar, acpi_update_sci_fn update_sci,
-                       MemoryRegion *parent);
-
-/* PM1a_CNT: piix and ich9 don't implement PM1b CNT. */
-void acpi_pm1_cnt_init(ACPIREGS *ar, MemoryRegion *parent, uint8_t s4_val);
-void acpi_pm1_cnt_update(ACPIREGS *ar,
-                         bool sci_enable, bool sci_disable);
-void acpi_pm1_cnt_reset(ACPIREGS *ar);
-
-/* GPE0 */
-void acpi_gpe_init(ACPIREGS *ar, uint8_t len);
-void acpi_gpe_reset(ACPIREGS *ar);
-
-void acpi_gpe_ioport_writeb(ACPIREGS *ar, uint32_t addr, uint32_t val);
-uint32_t acpi_gpe_ioport_readb(ACPIREGS *ar, uint32_t addr);
-
-#endif /* !QEMU_HW_ACPI_H */
diff --git a/hw/acpi/Makefile.objs b/hw/acpi/Makefile.objs
new file mode 100644 (file)
index 0000000..a0b63b5
--- /dev/null
@@ -0,0 +1,2 @@
+common-obj-$(CONFIG_ACPI) += core.o piix4.o ich9.o
+
diff --git a/hw/acpi/core.c b/hw/acpi/core.c
new file mode 100644 (file)
index 0000000..64b8718
--- /dev/null
@@ -0,0 +1,614 @@
+/*
+ * ACPI implementation
+ *
+ * Copyright (c) 2006 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * 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/>
+ *
+ * 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/sysemu.h"
+#include "hw/hw.h"
+#include "hw/i386/pc.h"
+#include "hw/acpi/acpi.h"
+#include "monitor/monitor.h"
+#include "qemu/config-file.h"
+#include "qapi/opts-visitor.h"
+#include "qapi/dealloc-visitor.h"
+#include "qapi-visit.h"
+
+struct acpi_table_header {
+    uint16_t _length;         /* our length, not actual part of the hdr */
+                              /* allows easier parsing for fw_cfg clients */
+    char sig[4];              /* ACPI signature (4 ASCII characters) */
+    uint32_t length;          /* Length of table, in bytes, including header */
+    uint8_t revision;         /* ACPI Specification minor version # */
+    uint8_t checksum;         /* To make sum of entire table == 0 */
+    char oem_id[6];           /* OEM identification */
+    char oem_table_id[8];     /* OEM table identification */
+    uint32_t oem_revision;    /* OEM revision number */
+    char asl_compiler_id[4];  /* ASL compiler vendor ID */
+    uint32_t asl_compiler_revision; /* ASL compiler revision number */
+} QEMU_PACKED;
+
+#define ACPI_TABLE_HDR_SIZE sizeof(struct acpi_table_header)
+#define ACPI_TABLE_PFX_SIZE sizeof(uint16_t)  /* size of the extra prefix */
+
+static const char unsigned dfl_hdr[ACPI_TABLE_HDR_SIZE - ACPI_TABLE_PFX_SIZE] =
+    "QEMU\0\0\0\0\1\0"       /* sig (4), len(4), revno (1), csum (1) */
+    "QEMUQEQEMUQEMU\1\0\0\0" /* OEM id (6), table (8), revno (4) */
+    "QEMU\1\0\0\0"           /* ASL compiler ID (4), version (4) */
+    ;
+
+char unsigned *acpi_tables;
+size_t acpi_tables_len;
+
+static QemuOptsList qemu_acpi_opts = {
+    .name = "acpi",
+    .implied_opt_name = "data",
+    .head = QTAILQ_HEAD_INITIALIZER(qemu_acpi_opts.head),
+    .desc = { { 0 } } /* validated with OptsVisitor */
+};
+
+static void acpi_register_config(void)
+{
+    qemu_add_opts(&qemu_acpi_opts);
+}
+
+machine_init(acpi_register_config);
+
+static int acpi_checksum(const uint8_t *data, int len)
+{
+    int sum, i;
+    sum = 0;
+    for (i = 0; i < len; i++) {
+        sum += data[i];
+    }
+    return (-sum) & 0xff;
+}
+
+
+/* Install a copy of the ACPI table specified in @blob.
+ *
+ * If @has_header is set, @blob starts with the System Description Table Header
+ * structure. Otherwise, "dfl_hdr" is prepended. In any case, each header field
+ * is optionally overwritten from @hdrs.
+ *
+ * It is valid to call this function with
+ * (@blob == NULL && bloblen == 0 && !has_header).
+ *
+ * @hdrs->file and @hdrs->data are ignored.
+ *
+ * SIZE_MAX is considered "infinity" in this function.
+ *
+ * The number of tables that can be installed is not limited, but the 16-bit
+ * counter at the beginning of "acpi_tables" wraps around after UINT16_MAX.
+ */
+static void acpi_table_install(const char unsigned *blob, size_t bloblen,
+                               bool has_header,
+                               const struct AcpiTableOptions *hdrs,
+                               Error **errp)
+{
+    size_t body_start;
+    const char unsigned *hdr_src;
+    size_t body_size, acpi_payload_size;
+    struct acpi_table_header *ext_hdr;
+    unsigned changed_fields;
+
+    /* Calculate where the ACPI table body starts within the blob, plus where
+     * to copy the ACPI table header from.
+     */
+    if (has_header) {
+        /*   _length             | ACPI header in blob | blob body
+         *   ^^^^^^^^^^^^^^^^^^^   ^^^^^^^^^^^^^^^^^^^   ^^^^^^^^^
+         *   ACPI_TABLE_PFX_SIZE     sizeof dfl_hdr      body_size
+         *                           == body_start
+         *
+         *                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+         *                           acpi_payload_size == bloblen
+         */
+        body_start = sizeof dfl_hdr;
+
+        if (bloblen < body_start) {
+            error_setg(errp, "ACPI table claiming to have header is too "
+                       "short, available: %zu, expected: %zu", bloblen,
+                       body_start);
+            return;
+        }
+        hdr_src = blob;
+    } else {
+        /*   _length             | ACPI header in template | blob body
+         *   ^^^^^^^^^^^^^^^^^^^   ^^^^^^^^^^^^^^^^^^^^^^^   ^^^^^^^^^^
+         *   ACPI_TABLE_PFX_SIZE       sizeof dfl_hdr        body_size
+         *                                                   == bloblen
+         *
+         *                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+         *                                  acpi_payload_size
+         */
+        body_start = 0;
+        hdr_src = dfl_hdr;
+    }
+    body_size = bloblen - body_start;
+    acpi_payload_size = sizeof dfl_hdr + body_size;
+
+    if (acpi_payload_size > UINT16_MAX) {
+        error_setg(errp, "ACPI table too big, requested: %zu, max: %u",
+                   acpi_payload_size, (unsigned)UINT16_MAX);
+        return;
+    }
+
+    /* We won't fail from here on. Initialize / extend the globals. */
+    if (acpi_tables == NULL) {
+        acpi_tables_len = sizeof(uint16_t);
+        acpi_tables = g_malloc0(acpi_tables_len);
+    }
+
+    acpi_tables = g_realloc(acpi_tables, acpi_tables_len +
+                                         ACPI_TABLE_PFX_SIZE +
+                                         sizeof dfl_hdr + body_size);
+
+    ext_hdr = (struct acpi_table_header *)(acpi_tables + acpi_tables_len);
+    acpi_tables_len += ACPI_TABLE_PFX_SIZE;
+
+    memcpy(acpi_tables + acpi_tables_len, hdr_src, sizeof dfl_hdr);
+    acpi_tables_len += sizeof dfl_hdr;
+
+    if (blob != NULL) {
+        memcpy(acpi_tables + acpi_tables_len, blob + body_start, body_size);
+        acpi_tables_len += body_size;
+    }
+
+    /* increase number of tables */
+    cpu_to_le16wu((uint16_t *)acpi_tables,
+                  le16_to_cpupu((uint16_t *)acpi_tables) + 1u);
+
+    /* Update the header fields. The strings need not be NUL-terminated. */
+    changed_fields = 0;
+    ext_hdr->_length = cpu_to_le16(acpi_payload_size);
+
+    if (hdrs->has_sig) {
+        strncpy(ext_hdr->sig, hdrs->sig, sizeof ext_hdr->sig);
+        ++changed_fields;
+    }
+
+    if (has_header && le32_to_cpu(ext_hdr->length) != acpi_payload_size) {
+        fprintf(stderr,
+                "warning: ACPI table has wrong length, header says "
+                "%" PRIu32 ", actual size %zu bytes\n",
+                le32_to_cpu(ext_hdr->length), acpi_payload_size);
+    }
+    ext_hdr->length = cpu_to_le32(acpi_payload_size);
+
+    if (hdrs->has_rev) {
+        ext_hdr->revision = hdrs->rev;
+        ++changed_fields;
+    }
+
+    ext_hdr->checksum = 0;
+
+    if (hdrs->has_oem_id) {
+        strncpy(ext_hdr->oem_id, hdrs->oem_id, sizeof ext_hdr->oem_id);
+        ++changed_fields;
+    }
+    if (hdrs->has_oem_table_id) {
+        strncpy(ext_hdr->oem_table_id, hdrs->oem_table_id,
+                sizeof ext_hdr->oem_table_id);
+        ++changed_fields;
+    }
+    if (hdrs->has_oem_rev) {
+        ext_hdr->oem_revision = cpu_to_le32(hdrs->oem_rev);
+        ++changed_fields;
+    }
+    if (hdrs->has_asl_compiler_id) {
+        strncpy(ext_hdr->asl_compiler_id, hdrs->asl_compiler_id,
+                sizeof ext_hdr->asl_compiler_id);
+        ++changed_fields;
+    }
+    if (hdrs->has_asl_compiler_rev) {
+        ext_hdr->asl_compiler_revision = cpu_to_le32(hdrs->asl_compiler_rev);
+        ++changed_fields;
+    }
+
+    if (!has_header && changed_fields == 0) {
+        fprintf(stderr, "warning: ACPI table: no headers are specified\n");
+    }
+
+    /* recalculate checksum */
+    ext_hdr->checksum = acpi_checksum((const char unsigned *)ext_hdr +
+                                      ACPI_TABLE_PFX_SIZE, acpi_payload_size);
+}
+
+void acpi_table_add(const QemuOpts *opts, Error **errp)
+{
+    AcpiTableOptions *hdrs = NULL;
+    Error *err = NULL;
+    char **pathnames = NULL;
+    char **cur;
+    size_t bloblen = 0;
+    char unsigned *blob = NULL;
+
+    {
+        OptsVisitor *ov;
+
+        ov = opts_visitor_new(opts);
+        visit_type_AcpiTableOptions(opts_get_visitor(ov), &hdrs, NULL, &err);
+        opts_visitor_cleanup(ov);
+    }
+
+    if (err) {
+        goto out;
+    }
+    if (hdrs->has_file == hdrs->has_data) {
+        error_setg(&err, "'-acpitable' requires one of 'data' or 'file'");
+        goto out;
+    }
+
+    pathnames = g_strsplit(hdrs->has_file ? hdrs->file : hdrs->data, ":", 0);
+    if (pathnames == NULL || pathnames[0] == NULL) {
+        error_setg(&err, "'-acpitable' requires at least one pathname");
+        goto out;
+    }
+
+    /* now read in the data files, reallocating buffer as needed */
+    for (cur = pathnames; *cur; ++cur) {
+        int fd = open(*cur, O_RDONLY | O_BINARY);
+
+        if (fd < 0) {
+            error_setg(&err, "can't open file %s: %s", *cur, strerror(errno));
+            goto out;
+        }
+
+        for (;;) {
+            char unsigned data[8192];
+            ssize_t r;
+
+            r = read(fd, data, sizeof data);
+            if (r == 0) {
+                break;
+            } else if (r > 0) {
+                blob = g_realloc(blob, bloblen + r);
+                memcpy(blob + bloblen, data, r);
+                bloblen += r;
+            } else if (errno != EINTR) {
+                error_setg(&err, "can't read file %s: %s",
+                           *cur, strerror(errno));
+                close(fd);
+                goto out;
+            }
+        }
+
+        close(fd);
+    }
+
+    acpi_table_install(blob, bloblen, hdrs->has_file, hdrs, &err);
+
+out:
+    g_free(blob);
+    g_strfreev(pathnames);
+
+    if (hdrs != NULL) {
+        QapiDeallocVisitor *dv;
+
+        dv = qapi_dealloc_visitor_new();
+        visit_type_AcpiTableOptions(qapi_dealloc_get_visitor(dv), &hdrs, NULL,
+                                    NULL);
+        qapi_dealloc_visitor_cleanup(dv);
+    }
+
+    error_propagate(errp, err);
+}
+
+static void acpi_notify_wakeup(Notifier *notifier, void *data)
+{
+    ACPIREGS *ar = container_of(notifier, ACPIREGS, wakeup);
+    WakeupReason *reason = data;
+
+    switch (*reason) {
+    case QEMU_WAKEUP_REASON_RTC:
+        ar->pm1.evt.sts |=
+            (ACPI_BITMASK_WAKE_STATUS | ACPI_BITMASK_RT_CLOCK_STATUS);
+        break;
+    case QEMU_WAKEUP_REASON_PMTIMER:
+        ar->pm1.evt.sts |=
+            (ACPI_BITMASK_WAKE_STATUS | ACPI_BITMASK_TIMER_STATUS);
+        break;
+    case QEMU_WAKEUP_REASON_OTHER:
+    default:
+        /* ACPI_BITMASK_WAKE_STATUS should be set on resume.
+           Pretend that resume was caused by power button */
+        ar->pm1.evt.sts |=
+            (ACPI_BITMASK_WAKE_STATUS | ACPI_BITMASK_POWER_BUTTON_STATUS);
+        break;
+    }
+}
+
+/* ACPI PM1a EVT */
+uint16_t acpi_pm1_evt_get_sts(ACPIREGS *ar)
+{
+    int64_t d = acpi_pm_tmr_get_clock();
+    if (d >= ar->tmr.overflow_time) {
+        ar->pm1.evt.sts |= ACPI_BITMASK_TIMER_STATUS;
+    }
+    return ar->pm1.evt.sts;
+}
+
+static void acpi_pm1_evt_write_sts(ACPIREGS *ar, uint16_t val)
+{
+    uint16_t pm1_sts = acpi_pm1_evt_get_sts(ar);
+    if (pm1_sts & val & ACPI_BITMASK_TIMER_STATUS) {
+        /* if TMRSTS is reset, then compute the new overflow time */
+        acpi_pm_tmr_calc_overflow_time(ar);
+    }
+    ar->pm1.evt.sts &= ~val;
+}
+
+static void acpi_pm1_evt_write_en(ACPIREGS *ar, uint16_t val)
+{
+    ar->pm1.evt.en = val;
+    qemu_system_wakeup_enable(QEMU_WAKEUP_REASON_RTC,
+                              val & ACPI_BITMASK_RT_CLOCK_ENABLE);
+    qemu_system_wakeup_enable(QEMU_WAKEUP_REASON_PMTIMER,
+                              val & ACPI_BITMASK_TIMER_ENABLE);
+}
+
+void acpi_pm1_evt_power_down(ACPIREGS *ar)
+{
+    if (ar->pm1.evt.en & ACPI_BITMASK_POWER_BUTTON_ENABLE) {
+        ar->pm1.evt.sts |= ACPI_BITMASK_POWER_BUTTON_STATUS;
+        ar->tmr.update_sci(ar);
+    }
+}
+
+void acpi_pm1_evt_reset(ACPIREGS *ar)
+{
+    ar->pm1.evt.sts = 0;
+    ar->pm1.evt.en = 0;
+    qemu_system_wakeup_enable(QEMU_WAKEUP_REASON_RTC, 0);
+    qemu_system_wakeup_enable(QEMU_WAKEUP_REASON_PMTIMER, 0);
+}
+
+static uint64_t acpi_pm_evt_read(void *opaque, hwaddr addr, unsigned width)
+{
+    ACPIREGS *ar = opaque;
+    switch (addr) {
+    case 0:
+        return acpi_pm1_evt_get_sts(ar);
+    case 2:
+        return ar->pm1.evt.en;
+    default:
+        return 0;
+    }
+}
+
+static void acpi_pm_evt_write(void *opaque, hwaddr addr, uint64_t val,
+                              unsigned width)
+{
+    ACPIREGS *ar = opaque;
+    switch (addr) {
+    case 0:
+        acpi_pm1_evt_write_sts(ar, val);
+        ar->pm1.evt.update_sci(ar);
+        break;
+    case 2:
+        acpi_pm1_evt_write_en(ar, val);
+        ar->pm1.evt.update_sci(ar);
+        break;
+    }
+}
+
+static const MemoryRegionOps acpi_pm_evt_ops = {
+    .read = acpi_pm_evt_read,
+    .write = acpi_pm_evt_write,
+    .valid.min_access_size = 2,
+    .valid.max_access_size = 2,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+void acpi_pm1_evt_init(ACPIREGS *ar, acpi_update_sci_fn update_sci,
+                       MemoryRegion *parent)
+{
+    ar->pm1.evt.update_sci = update_sci;
+    memory_region_init_io(&ar->pm1.evt.io, &acpi_pm_evt_ops, ar, "acpi-evt", 4);
+    memory_region_add_subregion(parent, 0, &ar->pm1.evt.io);
+}
+
+/* ACPI PM_TMR */
+void acpi_pm_tmr_update(ACPIREGS *ar, bool enable)
+{
+    int64_t expire_time;
+
+    /* schedule a timer interruption if needed */
+    if (enable) {
+        expire_time = muldiv64(ar->tmr.overflow_time, get_ticks_per_sec(),
+                               PM_TIMER_FREQUENCY);
+        qemu_mod_timer(ar->tmr.timer, expire_time);
+    } else {
+        qemu_del_timer(ar->tmr.timer);
+    }
+}
+
+void acpi_pm_tmr_calc_overflow_time(ACPIREGS *ar)
+{
+    int64_t d = acpi_pm_tmr_get_clock();
+    ar->tmr.overflow_time = (d + 0x800000LL) & ~0x7fffffLL;
+}
+
+static uint32_t acpi_pm_tmr_get(ACPIREGS *ar)
+{
+    uint32_t d = acpi_pm_tmr_get_clock();
+    return d & 0xffffff;
+}
+
+static void acpi_pm_tmr_timer(void *opaque)
+{
+    ACPIREGS *ar = opaque;
+    qemu_system_wakeup_request(QEMU_WAKEUP_REASON_PMTIMER);
+    ar->tmr.update_sci(ar);
+}
+
+static uint64_t acpi_pm_tmr_read(void *opaque, hwaddr addr, unsigned width)
+{
+    return acpi_pm_tmr_get(opaque);
+}
+
+static const MemoryRegionOps acpi_pm_tmr_ops = {
+    .read = acpi_pm_tmr_read,
+    .valid.min_access_size = 4,
+    .valid.max_access_size = 4,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+void acpi_pm_tmr_init(ACPIREGS *ar, acpi_update_sci_fn update_sci,
+                      MemoryRegion *parent)
+{
+    ar->tmr.update_sci = update_sci;
+    ar->tmr.timer = qemu_new_timer_ns(vm_clock, acpi_pm_tmr_timer, ar);
+    memory_region_init_io(&ar->tmr.io, &acpi_pm_tmr_ops, ar, "acpi-tmr", 4);
+    memory_region_add_subregion(parent, 8, &ar->tmr.io);
+}
+
+void acpi_pm_tmr_reset(ACPIREGS *ar)
+{
+    ar->tmr.overflow_time = 0;
+    qemu_del_timer(ar->tmr.timer);
+}
+
+/* ACPI PM1aCNT */
+static void acpi_pm1_cnt_write(ACPIREGS *ar, uint16_t val)
+{
+    ar->pm1.cnt.cnt = val & ~(ACPI_BITMASK_SLEEP_ENABLE);
+
+    if (val & ACPI_BITMASK_SLEEP_ENABLE) {
+        /* change suspend type */
+        uint16_t sus_typ = (val >> 10) & 7;
+        switch(sus_typ) {
+        case 0: /* soft power off */
+            qemu_system_shutdown_request();
+            break;
+        case 1:
+            qemu_system_suspend_request();
+            break;
+        default:
+            if (sus_typ == ar->pm1.cnt.s4_val) { /* S4 request */
+                monitor_protocol_event(QEVENT_SUSPEND_DISK, NULL);
+                qemu_system_shutdown_request();
+            }
+            break;
+        }
+    }
+}
+
+void acpi_pm1_cnt_update(ACPIREGS *ar,
+                         bool sci_enable, bool sci_disable)
+{
+    /* ACPI specs 3.0, 4.7.2.5 */
+    if (sci_enable) {
+        ar->pm1.cnt.cnt |= ACPI_BITMASK_SCI_ENABLE;
+    } else if (sci_disable) {
+        ar->pm1.cnt.cnt &= ~ACPI_BITMASK_SCI_ENABLE;
+    }
+}
+
+static uint64_t acpi_pm_cnt_read(void *opaque, hwaddr addr, unsigned width)
+{
+    ACPIREGS *ar = opaque;
+    return ar->pm1.cnt.cnt;
+}
+
+static void acpi_pm_cnt_write(void *opaque, hwaddr addr, uint64_t val,
+                              unsigned width)
+{
+    acpi_pm1_cnt_write(opaque, val);
+}
+
+static const MemoryRegionOps acpi_pm_cnt_ops = {
+    .read = acpi_pm_cnt_read,
+    .write = acpi_pm_cnt_write,
+    .valid.min_access_size = 2,
+    .valid.max_access_size = 2,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+void acpi_pm1_cnt_init(ACPIREGS *ar, MemoryRegion *parent, uint8_t s4_val)
+{
+    ar->pm1.cnt.s4_val = s4_val;
+    ar->wakeup.notify = acpi_notify_wakeup;
+    qemu_register_wakeup_notifier(&ar->wakeup);
+    memory_region_init_io(&ar->pm1.cnt.io, &acpi_pm_cnt_ops, ar, "acpi-cnt", 2);
+    memory_region_add_subregion(parent, 4, &ar->pm1.cnt.io);
+}
+
+void acpi_pm1_cnt_reset(ACPIREGS *ar)
+{
+    ar->pm1.cnt.cnt = 0;
+}
+
+/* ACPI GPE */
+void acpi_gpe_init(ACPIREGS *ar, uint8_t len)
+{
+    ar->gpe.len = len;
+    ar->gpe.sts = g_malloc0(len / 2);
+    ar->gpe.en = g_malloc0(len / 2);
+}
+
+void acpi_gpe_reset(ACPIREGS *ar)
+{
+    memset(ar->gpe.sts, 0, ar->gpe.len / 2);
+    memset(ar->gpe.en, 0, ar->gpe.len / 2);
+}
+
+static uint8_t *acpi_gpe_ioport_get_ptr(ACPIREGS *ar, uint32_t addr)
+{
+    uint8_t *cur = NULL;
+
+    if (addr < ar->gpe.len / 2) {
+        cur = ar->gpe.sts + addr;
+    } else if (addr < ar->gpe.len) {
+        cur = ar->gpe.en + addr - ar->gpe.len / 2;
+    } else {
+        abort();
+    }
+
+    return cur;
+}
+
+void acpi_gpe_ioport_writeb(ACPIREGS *ar, uint32_t addr, uint32_t val)
+{
+    uint8_t *cur;
+
+    cur = acpi_gpe_ioport_get_ptr(ar, addr);
+    if (addr < ar->gpe.len / 2) {
+        /* GPE_STS */
+        *cur = (*cur) & ~val;
+    } else if (addr < ar->gpe.len) {
+        /* GPE_EN */
+        *cur = val;
+    } else {
+        abort();
+    }
+}
+
+uint32_t acpi_gpe_ioport_readb(ACPIREGS *ar, uint32_t addr)
+{
+    uint8_t *cur;
+    uint32_t val;
+
+    cur = acpi_gpe_ioport_get_ptr(ar, addr);
+    val = 0;
+    if (cur != NULL) {
+        val = *cur;
+    }
+
+    return val;
+}
diff --git a/hw/acpi/ich9.c b/hw/acpi/ich9.c
new file mode 100644 (file)
index 0000000..e663d29
--- /dev/null
@@ -0,0 +1,230 @@
+/*
+ * ACPI implementation
+ *
+ * Copyright (c) 2006 Fabrice Bellard
+ * Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp>
+ *                    VA Linux Systems Japan K.K.
+ * Copyright (C) 2012 Jason Baron <jbaron@redhat.com>
+ *
+ * This is based on acpi.c.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * 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/>
+ *
+ * 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/hw.h"
+#include "hw/i386/pc.h"
+#include "hw/pci/pci.h"
+#include "qemu/timer.h"
+#include "sysemu/sysemu.h"
+#include "hw/acpi/acpi.h"
+#include "sysemu/kvm.h"
+#include "exec/address-spaces.h"
+
+#include "hw/i386/ich9.h"
+
+//#define DEBUG
+
+#ifdef DEBUG
+#define ICH9_DEBUG(fmt, ...) \
+do { printf("%s "fmt, __func__, ## __VA_ARGS__); } while (0)
+#else
+#define ICH9_DEBUG(fmt, ...)    do { } while (0)
+#endif
+
+static void pm_update_sci(ICH9LPCPMRegs *pm)
+{
+    int sci_level, pm1a_sts;
+
+    pm1a_sts = acpi_pm1_evt_get_sts(&pm->acpi_regs);
+
+    sci_level = (((pm1a_sts & pm->acpi_regs.pm1.evt.en) &
+                  (ACPI_BITMASK_RT_CLOCK_ENABLE |
+                   ACPI_BITMASK_POWER_BUTTON_ENABLE |
+                   ACPI_BITMASK_GLOBAL_LOCK_ENABLE |
+                   ACPI_BITMASK_TIMER_ENABLE)) != 0);
+    qemu_set_irq(pm->irq, sci_level);
+
+    /* schedule a timer interruption if needed */
+    acpi_pm_tmr_update(&pm->acpi_regs,
+                       (pm->acpi_regs.pm1.evt.en & ACPI_BITMASK_TIMER_ENABLE) &&
+                       !(pm1a_sts & ACPI_BITMASK_TIMER_STATUS));
+}
+
+static void ich9_pm_update_sci_fn(ACPIREGS *regs)
+{
+    ICH9LPCPMRegs *pm = container_of(regs, ICH9LPCPMRegs, acpi_regs);
+    pm_update_sci(pm);
+}
+
+static uint64_t ich9_gpe_readb(void *opaque, hwaddr addr, unsigned width)
+{
+    ICH9LPCPMRegs *pm = opaque;
+    return acpi_gpe_ioport_readb(&pm->acpi_regs, addr);
+}
+
+static void ich9_gpe_writeb(void *opaque, hwaddr addr, uint64_t val,
+                            unsigned width)
+{
+    ICH9LPCPMRegs *pm = opaque;
+    acpi_gpe_ioport_writeb(&pm->acpi_regs, addr, val);
+}
+
+static const MemoryRegionOps ich9_gpe_ops = {
+    .read = ich9_gpe_readb,
+    .write = ich9_gpe_writeb,
+    .valid.min_access_size = 1,
+    .valid.max_access_size = 4,
+    .impl.min_access_size = 1,
+    .impl.max_access_size = 1,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static uint64_t ich9_smi_readl(void *opaque, hwaddr addr, unsigned width)
+{
+    ICH9LPCPMRegs *pm = opaque;
+    switch (addr) {
+    case 0:
+        return pm->smi_en;
+    case 4:
+        return pm->smi_sts;
+    default:
+        return 0;
+    }
+}
+
+static void ich9_smi_writel(void *opaque, hwaddr addr, uint64_t val,
+                            unsigned width)
+{
+    ICH9LPCPMRegs *pm = opaque;
+    switch (addr) {
+    case 0:
+        pm->smi_en = val;
+        break;
+    }
+}
+
+static const MemoryRegionOps ich9_smi_ops = {
+    .read = ich9_smi_readl,
+    .write = ich9_smi_writel,
+    .valid.min_access_size = 4,
+    .valid.max_access_size = 4,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+void ich9_pm_iospace_update(ICH9LPCPMRegs *pm, uint32_t pm_io_base)
+{
+    ICH9_DEBUG("to 0x%x\n", pm_io_base);
+
+    assert((pm_io_base & ICH9_PMIO_MASK) == 0);
+
+    pm->pm_io_base = pm_io_base;
+    memory_region_transaction_begin();
+    memory_region_set_enabled(&pm->io, pm->pm_io_base != 0);
+    memory_region_set_address(&pm->io, pm->pm_io_base);
+    memory_region_transaction_commit();
+}
+
+static int ich9_pm_post_load(void *opaque, int version_id)
+{
+    ICH9LPCPMRegs *pm = opaque;
+    uint32_t pm_io_base = pm->pm_io_base;
+    pm->pm_io_base = 0;
+    ich9_pm_iospace_update(pm, pm_io_base);
+    return 0;
+}
+
+#define VMSTATE_GPE_ARRAY(_field, _state)                            \
+ {                                                                   \
+     .name       = (stringify(_field)),                              \
+     .version_id = 0,                                                \
+     .num        = ICH9_PMIO_GPE0_LEN,                               \
+     .info       = &vmstate_info_uint8,                              \
+     .size       = sizeof(uint8_t),                                  \
+     .flags      = VMS_ARRAY | VMS_POINTER,                          \
+     .offset     = vmstate_offset_pointer(_state, _field, uint8_t),  \
+ }
+
+const VMStateDescription vmstate_ich9_pm = {
+    .name = "ich9_pm",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .post_load = ich9_pm_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT16(acpi_regs.pm1.evt.sts, ICH9LPCPMRegs),
+        VMSTATE_UINT16(acpi_regs.pm1.evt.en, ICH9LPCPMRegs),
+        VMSTATE_UINT16(acpi_regs.pm1.cnt.cnt, ICH9LPCPMRegs),
+        VMSTATE_TIMER(acpi_regs.tmr.timer, ICH9LPCPMRegs),
+        VMSTATE_INT64(acpi_regs.tmr.overflow_time, ICH9LPCPMRegs),
+        VMSTATE_GPE_ARRAY(acpi_regs.gpe.sts, ICH9LPCPMRegs),
+        VMSTATE_GPE_ARRAY(acpi_regs.gpe.en, ICH9LPCPMRegs),
+        VMSTATE_UINT32(smi_en, ICH9LPCPMRegs),
+        VMSTATE_UINT32(smi_sts, ICH9LPCPMRegs),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void pm_reset(void *opaque)
+{
+    ICH9LPCPMRegs *pm = opaque;
+    ich9_pm_iospace_update(pm, 0);
+
+    acpi_pm1_evt_reset(&pm->acpi_regs);
+    acpi_pm1_cnt_reset(&pm->acpi_regs);
+    acpi_pm_tmr_reset(&pm->acpi_regs);
+    acpi_gpe_reset(&pm->acpi_regs);
+
+    if (kvm_enabled()) {
+        /* Mark SMM as already inited to prevent SMM from running. KVM does not
+         * support SMM mode. */
+        pm->smi_en |= ICH9_PMIO_SMI_EN_APMC_EN;
+    }
+
+    pm_update_sci(pm);
+}
+
+static void pm_powerdown_req(Notifier *n, void *opaque)
+{
+    ICH9LPCPMRegs *pm = container_of(n, ICH9LPCPMRegs, powerdown_notifier);
+
+    acpi_pm1_evt_power_down(&pm->acpi_regs);
+}
+
+void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs *pm,
+                  qemu_irq sci_irq, qemu_irq cmos_s3)
+{
+    memory_region_init(&pm->io, "ich9-pm", ICH9_PMIO_SIZE);
+    memory_region_set_enabled(&pm->io, false);
+    memory_region_add_subregion(pci_address_space_io(lpc_pci),
+                                0, &pm->io);
+
+    acpi_pm_tmr_init(&pm->acpi_regs, ich9_pm_update_sci_fn, &pm->io);
+    acpi_pm1_evt_init(&pm->acpi_regs, ich9_pm_update_sci_fn, &pm->io);
+    acpi_pm1_cnt_init(&pm->acpi_regs, &pm->io, 2);
+
+    acpi_gpe_init(&pm->acpi_regs, ICH9_PMIO_GPE0_LEN);
+    memory_region_init_io(&pm->io_gpe, &ich9_gpe_ops, pm, "apci-gpe0",
+                          ICH9_PMIO_GPE0_LEN);
+    memory_region_add_subregion(&pm->io, ICH9_PMIO_GPE0_STS, &pm->io_gpe);
+
+    memory_region_init_io(&pm->io_smi, &ich9_smi_ops, pm, "apci-smi",
+                          8);
+    memory_region_add_subregion(&pm->io, ICH9_PMIO_SMI_EN, &pm->io_smi);
+
+    pm->irq = sci_irq;
+    qemu_register_reset(pm_reset, pm);
+    pm->powerdown_notifier.notify = pm_powerdown_req;
+    qemu_register_powerdown_notifier(&pm->powerdown_notifier);
+}
diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c
new file mode 100644 (file)
index 0000000..88386d7
--- /dev/null
@@ -0,0 +1,641 @@
+/*
+ * ACPI implementation
+ *
+ * Copyright (c) 2006 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * 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/>
+ *
+ * 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/hw.h"
+#include "hw/i386/pc.h"
+#include "hw/isa/apm.h"
+#include "hw/i2c/pm_smbus.h"
+#include "hw/pci/pci.h"
+#include "hw/acpi/acpi.h"
+#include "sysemu/sysemu.h"
+#include "qemu/range.h"
+#include "exec/ioport.h"
+#include "hw/nvram/fw_cfg.h"
+#include "exec/address-spaces.h"
+
+//#define DEBUG
+
+#ifdef DEBUG
+# define PIIX4_DPRINTF(format, ...)     printf(format, ## __VA_ARGS__)
+#else
+# define PIIX4_DPRINTF(format, ...)     do { } while (0)
+#endif
+
+#define GPE_BASE 0xafe0
+#define GPE_LEN 4
+
+#define PCI_HOTPLUG_ADDR 0xae00
+#define PCI_HOTPLUG_SIZE 0x000f
+#define PCI_UP_BASE 0xae00
+#define PCI_DOWN_BASE 0xae04
+#define PCI_EJ_BASE 0xae08
+#define PCI_RMV_BASE 0xae0c
+
+#define PIIX4_PCI_HOTPLUG_STATUS 2
+
+struct pci_status {
+    uint32_t up; /* deprecated, maintained for migration compatibility */
+    uint32_t down;
+};
+
+typedef struct PIIX4PMState {
+    PCIDevice dev;
+
+    MemoryRegion io;
+    MemoryRegion io_gpe;
+    MemoryRegion io_pci;
+    ACPIREGS ar;
+
+    APMState apm;
+
+    PMSMBus smb;
+    uint32_t smb_io_base;
+
+    qemu_irq irq;
+    qemu_irq smi_irq;
+    int kvm_enabled;
+    Notifier machine_ready;
+    Notifier powerdown_notifier;
+
+    /* for pci hotplug */
+    struct pci_status pci0_status;
+    uint32_t pci0_hotplug_enable;
+    uint32_t pci0_slot_device_present;
+
+    uint8_t disable_s3;
+    uint8_t disable_s4;
+    uint8_t s4_val;
+} PIIX4PMState;
+
+static void piix4_acpi_system_hot_add_init(MemoryRegion *parent,
+                                           PCIBus *bus, PIIX4PMState *s);
+
+#define ACPI_ENABLE 0xf1
+#define ACPI_DISABLE 0xf0
+
+static void pm_update_sci(PIIX4PMState *s)
+{
+    int sci_level, pmsts;
+
+    pmsts = acpi_pm1_evt_get_sts(&s->ar);
+    sci_level = (((pmsts & s->ar.pm1.evt.en) &
+                  (ACPI_BITMASK_RT_CLOCK_ENABLE |
+                   ACPI_BITMASK_POWER_BUTTON_ENABLE |
+                   ACPI_BITMASK_GLOBAL_LOCK_ENABLE |
+                   ACPI_BITMASK_TIMER_ENABLE)) != 0) ||
+        (((s->ar.gpe.sts[0] & s->ar.gpe.en[0])
+          & PIIX4_PCI_HOTPLUG_STATUS) != 0);
+
+    qemu_set_irq(s->irq, sci_level);
+    /* schedule a timer interruption if needed */
+    acpi_pm_tmr_update(&s->ar, (s->ar.pm1.evt.en & ACPI_BITMASK_TIMER_ENABLE) &&
+                       !(pmsts & ACPI_BITMASK_TIMER_STATUS));
+}
+
+static void pm_tmr_timer(ACPIREGS *ar)
+{
+    PIIX4PMState *s = container_of(ar, PIIX4PMState, ar);
+    pm_update_sci(s);
+}
+
+static void apm_ctrl_changed(uint32_t val, void *arg)
+{
+    PIIX4PMState *s = arg;
+
+    /* ACPI specs 3.0, 4.7.2.5 */
+    acpi_pm1_cnt_update(&s->ar, val == ACPI_ENABLE, val == ACPI_DISABLE);
+
+    if (s->dev.config[0x5b] & (1 << 1)) {
+        if (s->smi_irq) {
+            qemu_irq_raise(s->smi_irq);
+        }
+    }
+}
+
+static void pm_io_space_update(PIIX4PMState *s)
+{
+    uint32_t pm_io_base;
+
+    pm_io_base = le32_to_cpu(*(uint32_t *)(s->dev.config + 0x40));
+    pm_io_base &= 0xffc0;
+
+    memory_region_transaction_begin();
+    memory_region_set_enabled(&s->io, s->dev.config[0x80] & 1);
+    memory_region_set_address(&s->io, pm_io_base);
+    memory_region_transaction_commit();
+}
+
+static void smbus_io_space_update(PIIX4PMState *s)
+{
+    s->smb_io_base = le32_to_cpu(*(uint32_t *)(s->dev.config + 0x90));
+    s->smb_io_base &= 0xffc0;
+
+    memory_region_transaction_begin();
+    memory_region_set_enabled(&s->smb.io, s->dev.config[0xd2] & 1);
+    memory_region_set_address(&s->smb.io, s->smb_io_base);
+    memory_region_transaction_commit();
+}
+
+static void pm_write_config(PCIDevice *d,
+                            uint32_t address, uint32_t val, int len)
+{
+    pci_default_write_config(d, address, val, len);
+    if (range_covers_byte(address, len, 0x80) ||
+        ranges_overlap(address, len, 0x40, 4)) {
+        pm_io_space_update((PIIX4PMState *)d);
+    }
+    if (range_covers_byte(address, len, 0xd2) ||
+        ranges_overlap(address, len, 0x90, 4)) {
+        smbus_io_space_update((PIIX4PMState *)d);
+    }
+}
+
+static void vmstate_pci_status_pre_save(void *opaque)
+{
+    struct pci_status *pci0_status = opaque;
+    PIIX4PMState *s = container_of(pci0_status, PIIX4PMState, pci0_status);
+
+    /* We no longer track up, so build a safe value for migrating
+     * to a version that still does... of course these might get lost
+     * by an old buggy implementation, but we try. */
+    pci0_status->up = s->pci0_slot_device_present & s->pci0_hotplug_enable;
+}
+
+static int vmstate_acpi_post_load(void *opaque, int version_id)
+{
+    PIIX4PMState *s = opaque;
+
+    pm_io_space_update(s);
+    return 0;
+}
+
+#define VMSTATE_GPE_ARRAY(_field, _state)                            \
+ {                                                                   \
+     .name       = (stringify(_field)),                              \
+     .version_id = 0,                                                \
+     .info       = &vmstate_info_uint16,                             \
+     .size       = sizeof(uint16_t),                                 \
+     .flags      = VMS_SINGLE | VMS_POINTER,                         \
+     .offset     = vmstate_offset_pointer(_state, _field, uint8_t),  \
+ }
+
+static const VMStateDescription vmstate_gpe = {
+    .name = "gpe",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_GPE_ARRAY(sts, ACPIGPE),
+        VMSTATE_GPE_ARRAY(en, ACPIGPE),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_pci_status = {
+    .name = "pci_status",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .pre_save = vmstate_pci_status_pre_save,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT32(up, struct pci_status),
+        VMSTATE_UINT32(down, struct pci_status),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int acpi_load_old(QEMUFile *f, void *opaque, int version_id)
+{
+    PIIX4PMState *s = opaque;
+    int ret, i;
+    uint16_t temp;
+
+    ret = pci_device_load(&s->dev, f);
+    if (ret < 0) {
+        return ret;
+    }
+    qemu_get_be16s(f, &s->ar.pm1.evt.sts);
+    qemu_get_be16s(f, &s->ar.pm1.evt.en);
+    qemu_get_be16s(f, &s->ar.pm1.cnt.cnt);
+
+    ret = vmstate_load_state(f, &vmstate_apm, &s->apm, 1);
+    if (ret) {
+        return ret;
+    }
+
+    qemu_get_timer(f, s->ar.tmr.timer);
+    qemu_get_sbe64s(f, &s->ar.tmr.overflow_time);
+
+    qemu_get_be16s(f, (uint16_t *)s->ar.gpe.sts);
+    for (i = 0; i < 3; i++) {
+        qemu_get_be16s(f, &temp);
+    }
+
+    qemu_get_be16s(f, (uint16_t *)s->ar.gpe.en);
+    for (i = 0; i < 3; i++) {
+        qemu_get_be16s(f, &temp);
+    }
+
+    ret = vmstate_load_state(f, &vmstate_pci_status, &s->pci0_status, 1);
+    return ret;
+}
+
+/* qemu-kvm 1.2 uses version 3 but advertised as 2
+ * To support incoming qemu-kvm 1.2 migration, change version_id
+ * and minimum_version_id to 2 below (which breaks migration from
+ * qemu 1.2).
+ *
+ */
+static const VMStateDescription vmstate_acpi = {
+    .name = "piix4_pm",
+    .version_id = 3,
+    .minimum_version_id = 3,
+    .minimum_version_id_old = 1,
+    .load_state_old = acpi_load_old,
+    .post_load = vmstate_acpi_post_load,
+    .fields      = (VMStateField []) {
+        VMSTATE_PCI_DEVICE(dev, PIIX4PMState),
+        VMSTATE_UINT16(ar.pm1.evt.sts, PIIX4PMState),
+        VMSTATE_UINT16(ar.pm1.evt.en, PIIX4PMState),
+        VMSTATE_UINT16(ar.pm1.cnt.cnt, PIIX4PMState),
+        VMSTATE_STRUCT(apm, PIIX4PMState, 0, vmstate_apm, APMState),
+        VMSTATE_TIMER(ar.tmr.timer, PIIX4PMState),
+        VMSTATE_INT64(ar.tmr.overflow_time, PIIX4PMState),
+        VMSTATE_STRUCT(ar.gpe, PIIX4PMState, 2, vmstate_gpe, ACPIGPE),
+        VMSTATE_STRUCT(pci0_status, PIIX4PMState, 2, vmstate_pci_status,
+                       struct pci_status),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void acpi_piix_eject_slot(PIIX4PMState *s, unsigned slots)
+{
+    BusChild *kid, *next;
+    BusState *bus = qdev_get_parent_bus(&s->dev.qdev);
+    int slot = ffs(slots) - 1;
+    bool slot_free = true;
+
+    /* Mark request as complete */
+    s->pci0_status.down &= ~(1U << slot);
+
+    QTAILQ_FOREACH_SAFE(kid, &bus->children, sibling, next) {
+        DeviceState *qdev = kid->child;
+        PCIDevice *dev = PCI_DEVICE(qdev);
+        PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev);
+        if (PCI_SLOT(dev->devfn) == slot) {
+            if (pc->no_hotplug) {
+                slot_free = false;
+            } else {
+                qdev_free(qdev);
+            }
+        }
+    }
+    if (slot_free) {
+        s->pci0_slot_device_present &= ~(1U << slot);
+    }
+}
+
+static void piix4_update_hotplug(PIIX4PMState *s)
+{
+    PCIDevice *dev = &s->dev;
+    BusState *bus = qdev_get_parent_bus(&dev->qdev);
+    BusChild *kid, *next;
+
+    /* Execute any pending removes during reset */
+    while (s->pci0_status.down) {
+        acpi_piix_eject_slot(s, s->pci0_status.down);
+    }
+
+    s->pci0_hotplug_enable = ~0;
+    s->pci0_slot_device_present = 0;
+
+    QTAILQ_FOREACH_SAFE(kid, &bus->children, sibling, next) {
+        DeviceState *qdev = kid->child;
+        PCIDevice *pdev = PCI_DEVICE(qdev);
+        PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(pdev);
+        int slot = PCI_SLOT(pdev->devfn);
+
+        if (pc->no_hotplug) {
+            s->pci0_hotplug_enable &= ~(1U << slot);
+        }
+
+        s->pci0_slot_device_present |= (1U << slot);
+    }
+}
+
+static void piix4_reset(void *opaque)
+{
+    PIIX4PMState *s = opaque;
+    uint8_t *pci_conf = s->dev.config;
+
+    pci_conf[0x58] = 0;
+    pci_conf[0x59] = 0;
+    pci_conf[0x5a] = 0;
+    pci_conf[0x5b] = 0;
+
+    pci_conf[0x40] = 0x01; /* PM io base read only bit */
+    pci_conf[0x80] = 0;
+
+    if (s->kvm_enabled) {
+        /* Mark SMM as already inited (until KVM supports SMM). */
+        pci_conf[0x5B] = 0x02;
+    }
+    piix4_update_hotplug(s);
+}
+
+static void piix4_pm_powerdown_req(Notifier *n, void *opaque)
+{
+    PIIX4PMState *s = container_of(n, PIIX4PMState, powerdown_notifier);
+
+    assert(s != NULL);
+    acpi_pm1_evt_power_down(&s->ar);
+}
+
+static void piix4_pm_machine_ready(Notifier *n, void *opaque)
+{
+    PIIX4PMState *s = container_of(n, PIIX4PMState, machine_ready);
+    uint8_t *pci_conf;
+
+    pci_conf = s->dev.config;
+    pci_conf[0x5f] = (isa_is_ioport_assigned(0x378) ? 0x80 : 0) | 0x10;
+    pci_conf[0x63] = 0x60;
+    pci_conf[0x67] = (isa_is_ioport_assigned(0x3f8) ? 0x08 : 0) |
+       (isa_is_ioport_assigned(0x2f8) ? 0x90 : 0);
+
+}
+
+static int piix4_pm_initfn(PCIDevice *dev)
+{
+    PIIX4PMState *s = DO_UPCAST(PIIX4PMState, dev, dev);
+    uint8_t *pci_conf;
+
+    pci_conf = s->dev.config;
+    pci_conf[0x06] = 0x80;
+    pci_conf[0x07] = 0x02;
+    pci_conf[0x09] = 0x00;
+    pci_conf[0x3d] = 0x01; // interrupt pin 1
+
+    /* APM */
+    apm_init(dev, &s->apm, apm_ctrl_changed, s);
+
+    if (s->kvm_enabled) {
+        /* Mark SMM as already inited to prevent SMM from running.  KVM does not
+         * support SMM mode. */
+        pci_conf[0x5B] = 0x02;
+    }
+
+    /* XXX: which specification is used ? The i82731AB has different
+       mappings */
+    pci_conf[0x90] = s->smb_io_base | 1;
+    pci_conf[0x91] = s->smb_io_base >> 8;
+    pci_conf[0xd2] = 0x09;
+    pm_smbus_init(&s->dev.qdev, &s->smb);
+    memory_region_set_enabled(&s->smb.io, pci_conf[0xd2] & 1);
+    memory_region_add_subregion(pci_address_space_io(dev),
+                                s->smb_io_base, &s->smb.io);
+
+    memory_region_init(&s->io, "piix4-pm", 64);
+    memory_region_set_enabled(&s->io, false);
+    memory_region_add_subregion(pci_address_space_io(dev),
+                                0, &s->io);
+
+    acpi_pm_tmr_init(&s->ar, pm_tmr_timer, &s->io);
+    acpi_pm1_evt_init(&s->ar, pm_tmr_timer, &s->io);
+    acpi_pm1_cnt_init(&s->ar, &s->io, s->s4_val);
+    acpi_gpe_init(&s->ar, GPE_LEN);
+
+    s->powerdown_notifier.notify = piix4_pm_powerdown_req;
+    qemu_register_powerdown_notifier(&s->powerdown_notifier);
+
+    s->machine_ready.notify = piix4_pm_machine_ready;
+    qemu_add_machine_init_done_notifier(&s->machine_ready);
+    qemu_register_reset(piix4_reset, s);
+
+    piix4_acpi_system_hot_add_init(pci_address_space_io(dev), dev->bus, s);
+
+    return 0;
+}
+
+i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
+                       qemu_irq sci_irq, qemu_irq smi_irq,
+                       int kvm_enabled, void *fw_cfg)
+{
+    PCIDevice *dev;
+    PIIX4PMState *s;
+
+    dev = pci_create(bus, devfn, "PIIX4_PM");
+    qdev_prop_set_uint32(&dev->qdev, "smb_io_base", smb_io_base);
+
+    s = DO_UPCAST(PIIX4PMState, dev, dev);
+    s->irq = sci_irq;
+    s->smi_irq = smi_irq;
+    s->kvm_enabled = kvm_enabled;
+
+    qdev_init_nofail(&dev->qdev);
+
+    if (fw_cfg) {
+        uint8_t suspend[6] = {128, 0, 0, 129, 128, 128};
+        suspend[3] = 1 | ((!s->disable_s3) << 7);
+        suspend[4] = s->s4_val | ((!s->disable_s4) << 7);
+
+        fw_cfg_add_file(fw_cfg, "etc/system-states", g_memdup(suspend, 6), 6);
+    }
+
+    return s->smb.smbus;
+}
+
+static Property piix4_pm_properties[] = {
+    DEFINE_PROP_UINT32("smb_io_base", PIIX4PMState, smb_io_base, 0),
+    DEFINE_PROP_UINT8("disable_s3", PIIX4PMState, disable_s3, 0),
+    DEFINE_PROP_UINT8("disable_s4", PIIX4PMState, disable_s4, 0),
+    DEFINE_PROP_UINT8("s4_val", PIIX4PMState, s4_val, 2),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void piix4_pm_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->no_hotplug = 1;
+    k->init = piix4_pm_initfn;
+    k->config_write = pm_write_config;
+    k->vendor_id = PCI_VENDOR_ID_INTEL;
+    k->device_id = PCI_DEVICE_ID_INTEL_82371AB_3;
+    k->revision = 0x03;
+    k->class_id = PCI_CLASS_BRIDGE_OTHER;
+    dc->desc = "PM";
+    dc->no_user = 1;
+    dc->vmsd = &vmstate_acpi;
+    dc->props = piix4_pm_properties;
+}
+
+static const 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_types(void)
+{
+    type_register_static(&piix4_pm_info);
+}
+
+type_init(piix4_pm_register_types)
+
+static uint64_t gpe_readb(void *opaque, hwaddr addr, unsigned width)
+{
+    PIIX4PMState *s = opaque;
+    uint32_t val = acpi_gpe_ioport_readb(&s->ar, addr);
+
+    PIIX4_DPRINTF("gpe read %x == %x\n", addr, val);
+    return val;
+}
+
+static void gpe_writeb(void *opaque, hwaddr addr, uint64_t val,
+                       unsigned width)
+{
+    PIIX4PMState *s = opaque;
+
+    acpi_gpe_ioport_writeb(&s->ar, addr, val);
+    pm_update_sci(s);
+
+    PIIX4_DPRINTF("gpe write %x <== %d\n", addr, val);
+}
+
+static const MemoryRegionOps piix4_gpe_ops = {
+    .read = gpe_readb,
+    .write = gpe_writeb,
+    .valid.min_access_size = 1,
+    .valid.max_access_size = 4,
+    .impl.min_access_size = 1,
+    .impl.max_access_size = 1,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static uint64_t pci_read(void *opaque, hwaddr addr, unsigned int size)
+{
+    PIIX4PMState *s = opaque;
+    uint32_t val = 0;
+
+    switch (addr) {
+    case PCI_UP_BASE - PCI_HOTPLUG_ADDR:
+        /* Manufacture an "up" value to cause a device check on any hotplug
+         * slot with a device.  Extra device checks are harmless. */
+        val = s->pci0_slot_device_present & s->pci0_hotplug_enable;
+        PIIX4_DPRINTF("pci_up_read %x\n", val);
+        break;
+    case PCI_DOWN_BASE - PCI_HOTPLUG_ADDR:
+        val = s->pci0_status.down;
+        PIIX4_DPRINTF("pci_down_read %x\n", val);
+        break;
+    case PCI_EJ_BASE - PCI_HOTPLUG_ADDR:
+        /* No feature defined yet */
+        PIIX4_DPRINTF("pci_features_read %x\n", val);
+        break;
+    case PCI_RMV_BASE - PCI_HOTPLUG_ADDR:
+        val = s->pci0_hotplug_enable;
+        break;
+    default:
+        break;
+    }
+
+    return val;
+}
+
+static void pci_write(void *opaque, hwaddr addr, uint64_t data,
+                      unsigned int size)
+{
+    switch (addr) {
+    case PCI_EJ_BASE - PCI_HOTPLUG_ADDR:
+        acpi_piix_eject_slot(opaque, (uint32_t)data);
+        PIIX4_DPRINTF("pciej write %" HWADDR_PRIx " <== % " PRIu64 "\n",
+                      addr, data);
+        break;
+    default:
+        break;
+    }
+}
+
+static const MemoryRegionOps piix4_pci_ops = {
+    .read = pci_read,
+    .write = pci_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev,
+                                PCIHotplugState state);
+
+static void piix4_acpi_system_hot_add_init(MemoryRegion *parent,
+                                           PCIBus *bus, PIIX4PMState *s)
+{
+    memory_region_init_io(&s->io_gpe, &piix4_gpe_ops, s, "apci-gpe0",
+                          GPE_LEN);
+    memory_region_add_subregion(parent, GPE_BASE, &s->io_gpe);
+
+    memory_region_init_io(&s->io_pci, &piix4_pci_ops, s, "apci-pci-hotplug",
+                          PCI_HOTPLUG_SIZE);
+    memory_region_add_subregion(parent, PCI_HOTPLUG_ADDR,
+                                &s->io_pci);
+    pci_bus_hotplug(bus, piix4_device_hotplug, &s->dev.qdev);
+}
+
+static void enable_device(PIIX4PMState *s, int slot)
+{
+    s->ar.gpe.sts[0] |= PIIX4_PCI_HOTPLUG_STATUS;
+    s->pci0_slot_device_present |= (1U << slot);
+}
+
+static void disable_device(PIIX4PMState *s, int slot)
+{
+    s->ar.gpe.sts[0] |= PIIX4_PCI_HOTPLUG_STATUS;
+    s->pci0_status.down |= (1U << slot);
+}
+
+static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev,
+                               PCIHotplugState state)
+{
+    int slot = PCI_SLOT(dev->devfn);
+    PIIX4PMState *s = DO_UPCAST(PIIX4PMState, dev,
+                                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
+     * event when the device is disabled later. */
+    if (state == PCI_COLDPLUG_ENABLED) {
+        s->pci0_slot_device_present |= (1U << slot);
+        return 0;
+    }
+
+    if (state == PCI_HOTPLUG_ENABLED) {
+        enable_device(s, slot);
+    } else {
+        disable_device(s, slot);
+    }
+
+    pm_update_sci(s);
+
+    return 0;
+}
diff --git a/hw/acpi_ich9.c b/hw/acpi_ich9.c
deleted file mode 100644 (file)
index 7b34a03..0000000
+++ /dev/null
@@ -1,230 +0,0 @@
-/*
- * ACPI implementation
- *
- * Copyright (c) 2006 Fabrice Bellard
- * Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp>
- *                    VA Linux Systems Japan K.K.
- * Copyright (C) 2012 Jason Baron <jbaron@redhat.com>
- *
- * This is based on acpi.c.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License version 2 as published by the Free Software Foundation.
- *
- * 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/>
- *
- * 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/hw.h"
-#include "hw/pc.h"
-#include "hw/pci/pci.h"
-#include "qemu/timer.h"
-#include "sysemu/sysemu.h"
-#include "hw/acpi.h"
-#include "sysemu/kvm.h"
-#include "exec/address-spaces.h"
-
-#include "hw/ich9.h"
-
-//#define DEBUG
-
-#ifdef DEBUG
-#define ICH9_DEBUG(fmt, ...) \
-do { printf("%s "fmt, __func__, ## __VA_ARGS__); } while (0)
-#else
-#define ICH9_DEBUG(fmt, ...)    do { } while (0)
-#endif
-
-static void pm_update_sci(ICH9LPCPMRegs *pm)
-{
-    int sci_level, pm1a_sts;
-
-    pm1a_sts = acpi_pm1_evt_get_sts(&pm->acpi_regs);
-
-    sci_level = (((pm1a_sts & pm->acpi_regs.pm1.evt.en) &
-                  (ACPI_BITMASK_RT_CLOCK_ENABLE |
-                   ACPI_BITMASK_POWER_BUTTON_ENABLE |
-                   ACPI_BITMASK_GLOBAL_LOCK_ENABLE |
-                   ACPI_BITMASK_TIMER_ENABLE)) != 0);
-    qemu_set_irq(pm->irq, sci_level);
-
-    /* schedule a timer interruption if needed */
-    acpi_pm_tmr_update(&pm->acpi_regs,
-                       (pm->acpi_regs.pm1.evt.en & ACPI_BITMASK_TIMER_ENABLE) &&
-                       !(pm1a_sts & ACPI_BITMASK_TIMER_STATUS));
-}
-
-static void ich9_pm_update_sci_fn(ACPIREGS *regs)
-{
-    ICH9LPCPMRegs *pm = container_of(regs, ICH9LPCPMRegs, acpi_regs);
-    pm_update_sci(pm);
-}
-
-static uint64_t ich9_gpe_readb(void *opaque, hwaddr addr, unsigned width)
-{
-    ICH9LPCPMRegs *pm = opaque;
-    return acpi_gpe_ioport_readb(&pm->acpi_regs, addr);
-}
-
-static void ich9_gpe_writeb(void *opaque, hwaddr addr, uint64_t val,
-                            unsigned width)
-{
-    ICH9LPCPMRegs *pm = opaque;
-    acpi_gpe_ioport_writeb(&pm->acpi_regs, addr, val);
-}
-
-static const MemoryRegionOps ich9_gpe_ops = {
-    .read = ich9_gpe_readb,
-    .write = ich9_gpe_writeb,
-    .valid.min_access_size = 1,
-    .valid.max_access_size = 4,
-    .impl.min_access_size = 1,
-    .impl.max_access_size = 1,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static uint64_t ich9_smi_readl(void *opaque, hwaddr addr, unsigned width)
-{
-    ICH9LPCPMRegs *pm = opaque;
-    switch (addr) {
-    case 0:
-        return pm->smi_en;
-    case 4:
-        return pm->smi_sts;
-    default:
-        return 0;
-    }
-}
-
-static void ich9_smi_writel(void *opaque, hwaddr addr, uint64_t val,
-                            unsigned width)
-{
-    ICH9LPCPMRegs *pm = opaque;
-    switch (addr) {
-    case 0:
-        pm->smi_en = val;
-        break;
-    }
-}
-
-static const MemoryRegionOps ich9_smi_ops = {
-    .read = ich9_smi_readl,
-    .write = ich9_smi_writel,
-    .valid.min_access_size = 4,
-    .valid.max_access_size = 4,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-void ich9_pm_iospace_update(ICH9LPCPMRegs *pm, uint32_t pm_io_base)
-{
-    ICH9_DEBUG("to 0x%x\n", pm_io_base);
-
-    assert((pm_io_base & ICH9_PMIO_MASK) == 0);
-
-    pm->pm_io_base = pm_io_base;
-    memory_region_transaction_begin();
-    memory_region_set_enabled(&pm->io, pm->pm_io_base != 0);
-    memory_region_set_address(&pm->io, pm->pm_io_base);
-    memory_region_transaction_commit();
-}
-
-static int ich9_pm_post_load(void *opaque, int version_id)
-{
-    ICH9LPCPMRegs *pm = opaque;
-    uint32_t pm_io_base = pm->pm_io_base;
-    pm->pm_io_base = 0;
-    ich9_pm_iospace_update(pm, pm_io_base);
-    return 0;
-}
-
-#define VMSTATE_GPE_ARRAY(_field, _state)                            \
- {                                                                   \
-     .name       = (stringify(_field)),                              \
-     .version_id = 0,                                                \
-     .num        = ICH9_PMIO_GPE0_LEN,                               \
-     .info       = &vmstate_info_uint8,                              \
-     .size       = sizeof(uint8_t),                                  \
-     .flags      = VMS_ARRAY | VMS_POINTER,                          \
-     .offset     = vmstate_offset_pointer(_state, _field, uint8_t),  \
- }
-
-const VMStateDescription vmstate_ich9_pm = {
-    .name = "ich9_pm",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .post_load = ich9_pm_post_load,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT16(acpi_regs.pm1.evt.sts, ICH9LPCPMRegs),
-        VMSTATE_UINT16(acpi_regs.pm1.evt.en, ICH9LPCPMRegs),
-        VMSTATE_UINT16(acpi_regs.pm1.cnt.cnt, ICH9LPCPMRegs),
-        VMSTATE_TIMER(acpi_regs.tmr.timer, ICH9LPCPMRegs),
-        VMSTATE_INT64(acpi_regs.tmr.overflow_time, ICH9LPCPMRegs),
-        VMSTATE_GPE_ARRAY(acpi_regs.gpe.sts, ICH9LPCPMRegs),
-        VMSTATE_GPE_ARRAY(acpi_regs.gpe.en, ICH9LPCPMRegs),
-        VMSTATE_UINT32(smi_en, ICH9LPCPMRegs),
-        VMSTATE_UINT32(smi_sts, ICH9LPCPMRegs),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void pm_reset(void *opaque)
-{
-    ICH9LPCPMRegs *pm = opaque;
-    ich9_pm_iospace_update(pm, 0);
-
-    acpi_pm1_evt_reset(&pm->acpi_regs);
-    acpi_pm1_cnt_reset(&pm->acpi_regs);
-    acpi_pm_tmr_reset(&pm->acpi_regs);
-    acpi_gpe_reset(&pm->acpi_regs);
-
-    if (kvm_enabled()) {
-        /* Mark SMM as already inited to prevent SMM from running. KVM does not
-         * support SMM mode. */
-        pm->smi_en |= ICH9_PMIO_SMI_EN_APMC_EN;
-    }
-
-    pm_update_sci(pm);
-}
-
-static void pm_powerdown_req(Notifier *n, void *opaque)
-{
-    ICH9LPCPMRegs *pm = container_of(n, ICH9LPCPMRegs, powerdown_notifier);
-
-    acpi_pm1_evt_power_down(&pm->acpi_regs);
-}
-
-void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs *pm,
-                  qemu_irq sci_irq, qemu_irq cmos_s3)
-{
-    memory_region_init(&pm->io, "ich9-pm", ICH9_PMIO_SIZE);
-    memory_region_set_enabled(&pm->io, false);
-    memory_region_add_subregion(pci_address_space_io(lpc_pci),
-                                0, &pm->io);
-
-    acpi_pm_tmr_init(&pm->acpi_regs, ich9_pm_update_sci_fn, &pm->io);
-    acpi_pm1_evt_init(&pm->acpi_regs, ich9_pm_update_sci_fn, &pm->io);
-    acpi_pm1_cnt_init(&pm->acpi_regs, &pm->io, 2);
-
-    acpi_gpe_init(&pm->acpi_regs, ICH9_PMIO_GPE0_LEN);
-    memory_region_init_io(&pm->io_gpe, &ich9_gpe_ops, pm, "apci-gpe0",
-                          ICH9_PMIO_GPE0_LEN);
-    memory_region_add_subregion(&pm->io, ICH9_PMIO_GPE0_STS, &pm->io_gpe);
-
-    memory_region_init_io(&pm->io_smi, &ich9_smi_ops, pm, "apci-smi",
-                          8);
-    memory_region_add_subregion(&pm->io, ICH9_PMIO_SMI_EN, &pm->io_smi);
-
-    pm->irq = sci_irq;
-    qemu_register_reset(pm_reset, pm);
-    pm->powerdown_notifier.notify = pm_powerdown_req;
-    qemu_register_powerdown_notifier(&pm->powerdown_notifier);
-}
diff --git a/hw/acpi_ich9.h b/hw/acpi_ich9.h
deleted file mode 100644 (file)
index 91c3aeb..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * QEMU GMCH/ICH9 LPC PM Emulation
- *
- *  Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp>
- *                     VA Linux Systems Japan K.K.
- *
- * 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 HW_ACPI_ICH9_H
-#define HW_ACPI_ICH9_H
-
-#include "hw/acpi.h"
-
-typedef struct ICH9LPCPMRegs {
-    /*
-     * In ich9 spec says that pm1_cnt register is 32bit width and
-     * that the upper 16bits are reserved and unused.
-     * PM1a_CNT_BLK = 2 in FADT so it is defined as uint16_t.
-     */
-    ACPIREGS acpi_regs;
-
-    MemoryRegion io;
-    MemoryRegion io_gpe;
-    MemoryRegion io_smi;
-
-    uint32_t smi_en;
-    uint32_t smi_sts;
-
-    qemu_irq irq;      /* SCI */
-
-    uint32_t pm_io_base;
-    Notifier powerdown_notifier;
-} ICH9LPCPMRegs;
-
-void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs *pm,
-                  qemu_irq sci_irq, qemu_irq cmos_s3_resume);
-void ich9_pm_iospace_update(ICH9LPCPMRegs *pm, uint32_t pm_io_base);
-extern const VMStateDescription vmstate_ich9_pm;
-
-#endif /* HW_ACPI_ICH9_H */
diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c
deleted file mode 100644 (file)
index 48a32b5..0000000
+++ /dev/null
@@ -1,641 +0,0 @@
-/*
- * ACPI implementation
- *
- * Copyright (c) 2006 Fabrice Bellard
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License version 2 as published by the Free Software Foundation.
- *
- * 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/>
- *
- * 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/hw.h"
-#include "hw/pc.h"
-#include "hw/apm.h"
-#include "hw/pm_smbus.h"
-#include "hw/pci/pci.h"
-#include "hw/acpi.h"
-#include "sysemu/sysemu.h"
-#include "qemu/range.h"
-#include "exec/ioport.h"
-#include "hw/fw_cfg.h"
-#include "exec/address-spaces.h"
-
-//#define DEBUG
-
-#ifdef DEBUG
-# define PIIX4_DPRINTF(format, ...)     printf(format, ## __VA_ARGS__)
-#else
-# define PIIX4_DPRINTF(format, ...)     do { } while (0)
-#endif
-
-#define GPE_BASE 0xafe0
-#define GPE_LEN 4
-
-#define PCI_HOTPLUG_ADDR 0xae00
-#define PCI_HOTPLUG_SIZE 0x000f
-#define PCI_UP_BASE 0xae00
-#define PCI_DOWN_BASE 0xae04
-#define PCI_EJ_BASE 0xae08
-#define PCI_RMV_BASE 0xae0c
-
-#define PIIX4_PCI_HOTPLUG_STATUS 2
-
-struct pci_status {
-    uint32_t up; /* deprecated, maintained for migration compatibility */
-    uint32_t down;
-};
-
-typedef struct PIIX4PMState {
-    PCIDevice dev;
-
-    MemoryRegion io;
-    MemoryRegion io_gpe;
-    MemoryRegion io_pci;
-    ACPIREGS ar;
-
-    APMState apm;
-
-    PMSMBus smb;
-    uint32_t smb_io_base;
-
-    qemu_irq irq;
-    qemu_irq smi_irq;
-    int kvm_enabled;
-    Notifier machine_ready;
-    Notifier powerdown_notifier;
-
-    /* for pci hotplug */
-    struct pci_status pci0_status;
-    uint32_t pci0_hotplug_enable;
-    uint32_t pci0_slot_device_present;
-
-    uint8_t disable_s3;
-    uint8_t disable_s4;
-    uint8_t s4_val;
-} PIIX4PMState;
-
-static void piix4_acpi_system_hot_add_init(MemoryRegion *parent,
-                                           PCIBus *bus, PIIX4PMState *s);
-
-#define ACPI_ENABLE 0xf1
-#define ACPI_DISABLE 0xf0
-
-static void pm_update_sci(PIIX4PMState *s)
-{
-    int sci_level, pmsts;
-
-    pmsts = acpi_pm1_evt_get_sts(&s->ar);
-    sci_level = (((pmsts & s->ar.pm1.evt.en) &
-                  (ACPI_BITMASK_RT_CLOCK_ENABLE |
-                   ACPI_BITMASK_POWER_BUTTON_ENABLE |
-                   ACPI_BITMASK_GLOBAL_LOCK_ENABLE |
-                   ACPI_BITMASK_TIMER_ENABLE)) != 0) ||
-        (((s->ar.gpe.sts[0] & s->ar.gpe.en[0])
-          & PIIX4_PCI_HOTPLUG_STATUS) != 0);
-
-    qemu_set_irq(s->irq, sci_level);
-    /* schedule a timer interruption if needed */
-    acpi_pm_tmr_update(&s->ar, (s->ar.pm1.evt.en & ACPI_BITMASK_TIMER_ENABLE) &&
-                       !(pmsts & ACPI_BITMASK_TIMER_STATUS));
-}
-
-static void pm_tmr_timer(ACPIREGS *ar)
-{
-    PIIX4PMState *s = container_of(ar, PIIX4PMState, ar);
-    pm_update_sci(s);
-}
-
-static void apm_ctrl_changed(uint32_t val, void *arg)
-{
-    PIIX4PMState *s = arg;
-
-    /* ACPI specs 3.0, 4.7.2.5 */
-    acpi_pm1_cnt_update(&s->ar, val == ACPI_ENABLE, val == ACPI_DISABLE);
-
-    if (s->dev.config[0x5b] & (1 << 1)) {
-        if (s->smi_irq) {
-            qemu_irq_raise(s->smi_irq);
-        }
-    }
-}
-
-static void pm_io_space_update(PIIX4PMState *s)
-{
-    uint32_t pm_io_base;
-
-    pm_io_base = le32_to_cpu(*(uint32_t *)(s->dev.config + 0x40));
-    pm_io_base &= 0xffc0;
-
-    memory_region_transaction_begin();
-    memory_region_set_enabled(&s->io, s->dev.config[0x80] & 1);
-    memory_region_set_address(&s->io, pm_io_base);
-    memory_region_transaction_commit();
-}
-
-static void smbus_io_space_update(PIIX4PMState *s)
-{
-    s->smb_io_base = le32_to_cpu(*(uint32_t *)(s->dev.config + 0x90));
-    s->smb_io_base &= 0xffc0;
-
-    memory_region_transaction_begin();
-    memory_region_set_enabled(&s->smb.io, s->dev.config[0xd2] & 1);
-    memory_region_set_address(&s->smb.io, s->smb_io_base);
-    memory_region_transaction_commit();
-}
-
-static void pm_write_config(PCIDevice *d,
-                            uint32_t address, uint32_t val, int len)
-{
-    pci_default_write_config(d, address, val, len);
-    if (range_covers_byte(address, len, 0x80) ||
-        ranges_overlap(address, len, 0x40, 4)) {
-        pm_io_space_update((PIIX4PMState *)d);
-    }
-    if (range_covers_byte(address, len, 0xd2) ||
-        ranges_overlap(address, len, 0x90, 4)) {
-        smbus_io_space_update((PIIX4PMState *)d);
-    }
-}
-
-static void vmstate_pci_status_pre_save(void *opaque)
-{
-    struct pci_status *pci0_status = opaque;
-    PIIX4PMState *s = container_of(pci0_status, PIIX4PMState, pci0_status);
-
-    /* We no longer track up, so build a safe value for migrating
-     * to a version that still does... of course these might get lost
-     * by an old buggy implementation, but we try. */
-    pci0_status->up = s->pci0_slot_device_present & s->pci0_hotplug_enable;
-}
-
-static int vmstate_acpi_post_load(void *opaque, int version_id)
-{
-    PIIX4PMState *s = opaque;
-
-    pm_io_space_update(s);
-    return 0;
-}
-
-#define VMSTATE_GPE_ARRAY(_field, _state)                            \
- {                                                                   \
-     .name       = (stringify(_field)),                              \
-     .version_id = 0,                                                \
-     .info       = &vmstate_info_uint16,                             \
-     .size       = sizeof(uint16_t),                                 \
-     .flags      = VMS_SINGLE | VMS_POINTER,                         \
-     .offset     = vmstate_offset_pointer(_state, _field, uint8_t),  \
- }
-
-static const VMStateDescription vmstate_gpe = {
-    .name = "gpe",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField []) {
-        VMSTATE_GPE_ARRAY(sts, ACPIGPE),
-        VMSTATE_GPE_ARRAY(en, ACPIGPE),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static const VMStateDescription vmstate_pci_status = {
-    .name = "pci_status",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .pre_save = vmstate_pci_status_pre_save,
-    .fields      = (VMStateField []) {
-        VMSTATE_UINT32(up, struct pci_status),
-        VMSTATE_UINT32(down, struct pci_status),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static int acpi_load_old(QEMUFile *f, void *opaque, int version_id)
-{
-    PIIX4PMState *s = opaque;
-    int ret, i;
-    uint16_t temp;
-
-    ret = pci_device_load(&s->dev, f);
-    if (ret < 0) {
-        return ret;
-    }
-    qemu_get_be16s(f, &s->ar.pm1.evt.sts);
-    qemu_get_be16s(f, &s->ar.pm1.evt.en);
-    qemu_get_be16s(f, &s->ar.pm1.cnt.cnt);
-
-    ret = vmstate_load_state(f, &vmstate_apm, &s->apm, 1);
-    if (ret) {
-        return ret;
-    }
-
-    qemu_get_timer(f, s->ar.tmr.timer);
-    qemu_get_sbe64s(f, &s->ar.tmr.overflow_time);
-
-    qemu_get_be16s(f, (uint16_t *)s->ar.gpe.sts);
-    for (i = 0; i < 3; i++) {
-        qemu_get_be16s(f, &temp);
-    }
-
-    qemu_get_be16s(f, (uint16_t *)s->ar.gpe.en);
-    for (i = 0; i < 3; i++) {
-        qemu_get_be16s(f, &temp);
-    }
-
-    ret = vmstate_load_state(f, &vmstate_pci_status, &s->pci0_status, 1);
-    return ret;
-}
-
-/* qemu-kvm 1.2 uses version 3 but advertised as 2
- * To support incoming qemu-kvm 1.2 migration, change version_id
- * and minimum_version_id to 2 below (which breaks migration from
- * qemu 1.2).
- *
- */
-static const VMStateDescription vmstate_acpi = {
-    .name = "piix4_pm",
-    .version_id = 3,
-    .minimum_version_id = 3,
-    .minimum_version_id_old = 1,
-    .load_state_old = acpi_load_old,
-    .post_load = vmstate_acpi_post_load,
-    .fields      = (VMStateField []) {
-        VMSTATE_PCI_DEVICE(dev, PIIX4PMState),
-        VMSTATE_UINT16(ar.pm1.evt.sts, PIIX4PMState),
-        VMSTATE_UINT16(ar.pm1.evt.en, PIIX4PMState),
-        VMSTATE_UINT16(ar.pm1.cnt.cnt, PIIX4PMState),
-        VMSTATE_STRUCT(apm, PIIX4PMState, 0, vmstate_apm, APMState),
-        VMSTATE_TIMER(ar.tmr.timer, PIIX4PMState),
-        VMSTATE_INT64(ar.tmr.overflow_time, PIIX4PMState),
-        VMSTATE_STRUCT(ar.gpe, PIIX4PMState, 2, vmstate_gpe, ACPIGPE),
-        VMSTATE_STRUCT(pci0_status, PIIX4PMState, 2, vmstate_pci_status,
-                       struct pci_status),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void acpi_piix_eject_slot(PIIX4PMState *s, unsigned slots)
-{
-    BusChild *kid, *next;
-    BusState *bus = qdev_get_parent_bus(&s->dev.qdev);
-    int slot = ffs(slots) - 1;
-    bool slot_free = true;
-
-    /* Mark request as complete */
-    s->pci0_status.down &= ~(1U << slot);
-
-    QTAILQ_FOREACH_SAFE(kid, &bus->children, sibling, next) {
-        DeviceState *qdev = kid->child;
-        PCIDevice *dev = PCI_DEVICE(qdev);
-        PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev);
-        if (PCI_SLOT(dev->devfn) == slot) {
-            if (pc->no_hotplug) {
-                slot_free = false;
-            } else {
-                qdev_free(qdev);
-            }
-        }
-    }
-    if (slot_free) {
-        s->pci0_slot_device_present &= ~(1U << slot);
-    }
-}
-
-static void piix4_update_hotplug(PIIX4PMState *s)
-{
-    PCIDevice *dev = &s->dev;
-    BusState *bus = qdev_get_parent_bus(&dev->qdev);
-    BusChild *kid, *next;
-
-    /* Execute any pending removes during reset */
-    while (s->pci0_status.down) {
-        acpi_piix_eject_slot(s, s->pci0_status.down);
-    }
-
-    s->pci0_hotplug_enable = ~0;
-    s->pci0_slot_device_present = 0;
-
-    QTAILQ_FOREACH_SAFE(kid, &bus->children, sibling, next) {
-        DeviceState *qdev = kid->child;
-        PCIDevice *pdev = PCI_DEVICE(qdev);
-        PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(pdev);
-        int slot = PCI_SLOT(pdev->devfn);
-
-        if (pc->no_hotplug) {
-            s->pci0_hotplug_enable &= ~(1U << slot);
-        }
-
-        s->pci0_slot_device_present |= (1U << slot);
-    }
-}
-
-static void piix4_reset(void *opaque)
-{
-    PIIX4PMState *s = opaque;
-    uint8_t *pci_conf = s->dev.config;
-
-    pci_conf[0x58] = 0;
-    pci_conf[0x59] = 0;
-    pci_conf[0x5a] = 0;
-    pci_conf[0x5b] = 0;
-
-    pci_conf[0x40] = 0x01; /* PM io base read only bit */
-    pci_conf[0x80] = 0;
-
-    if (s->kvm_enabled) {
-        /* Mark SMM as already inited (until KVM supports SMM). */
-        pci_conf[0x5B] = 0x02;
-    }
-    piix4_update_hotplug(s);
-}
-
-static void piix4_pm_powerdown_req(Notifier *n, void *opaque)
-{
-    PIIX4PMState *s = container_of(n, PIIX4PMState, powerdown_notifier);
-
-    assert(s != NULL);
-    acpi_pm1_evt_power_down(&s->ar);
-}
-
-static void piix4_pm_machine_ready(Notifier *n, void *opaque)
-{
-    PIIX4PMState *s = container_of(n, PIIX4PMState, machine_ready);
-    uint8_t *pci_conf;
-
-    pci_conf = s->dev.config;
-    pci_conf[0x5f] = (isa_is_ioport_assigned(0x378) ? 0x80 : 0) | 0x10;
-    pci_conf[0x63] = 0x60;
-    pci_conf[0x67] = (isa_is_ioport_assigned(0x3f8) ? 0x08 : 0) |
-       (isa_is_ioport_assigned(0x2f8) ? 0x90 : 0);
-
-}
-
-static int piix4_pm_initfn(PCIDevice *dev)
-{
-    PIIX4PMState *s = DO_UPCAST(PIIX4PMState, dev, dev);
-    uint8_t *pci_conf;
-
-    pci_conf = s->dev.config;
-    pci_conf[0x06] = 0x80;
-    pci_conf[0x07] = 0x02;
-    pci_conf[0x09] = 0x00;
-    pci_conf[0x3d] = 0x01; // interrupt pin 1
-
-    /* APM */
-    apm_init(dev, &s->apm, apm_ctrl_changed, s);
-
-    if (s->kvm_enabled) {
-        /* Mark SMM as already inited to prevent SMM from running.  KVM does not
-         * support SMM mode. */
-        pci_conf[0x5B] = 0x02;
-    }
-
-    /* XXX: which specification is used ? The i82731AB has different
-       mappings */
-    pci_conf[0x90] = s->smb_io_base | 1;
-    pci_conf[0x91] = s->smb_io_base >> 8;
-    pci_conf[0xd2] = 0x09;
-    pm_smbus_init(&s->dev.qdev, &s->smb);
-    memory_region_set_enabled(&s->smb.io, pci_conf[0xd2] & 1);
-    memory_region_add_subregion(pci_address_space_io(dev),
-                                s->smb_io_base, &s->smb.io);
-
-    memory_region_init(&s->io, "piix4-pm", 64);
-    memory_region_set_enabled(&s->io, false);
-    memory_region_add_subregion(pci_address_space_io(dev),
-                                0, &s->io);
-
-    acpi_pm_tmr_init(&s->ar, pm_tmr_timer, &s->io);
-    acpi_pm1_evt_init(&s->ar, pm_tmr_timer, &s->io);
-    acpi_pm1_cnt_init(&s->ar, &s->io, s->s4_val);
-    acpi_gpe_init(&s->ar, GPE_LEN);
-
-    s->powerdown_notifier.notify = piix4_pm_powerdown_req;
-    qemu_register_powerdown_notifier(&s->powerdown_notifier);
-
-    s->machine_ready.notify = piix4_pm_machine_ready;
-    qemu_add_machine_init_done_notifier(&s->machine_ready);
-    qemu_register_reset(piix4_reset, s);
-
-    piix4_acpi_system_hot_add_init(pci_address_space_io(dev), dev->bus, s);
-
-    return 0;
-}
-
-i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
-                       qemu_irq sci_irq, qemu_irq smi_irq,
-                       int kvm_enabled, void *fw_cfg)
-{
-    PCIDevice *dev;
-    PIIX4PMState *s;
-
-    dev = pci_create(bus, devfn, "PIIX4_PM");
-    qdev_prop_set_uint32(&dev->qdev, "smb_io_base", smb_io_base);
-
-    s = DO_UPCAST(PIIX4PMState, dev, dev);
-    s->irq = sci_irq;
-    s->smi_irq = smi_irq;
-    s->kvm_enabled = kvm_enabled;
-
-    qdev_init_nofail(&dev->qdev);
-
-    if (fw_cfg) {
-        uint8_t suspend[6] = {128, 0, 0, 129, 128, 128};
-        suspend[3] = 1 | ((!s->disable_s3) << 7);
-        suspend[4] = s->s4_val | ((!s->disable_s4) << 7);
-
-        fw_cfg_add_file(fw_cfg, "etc/system-states", g_memdup(suspend, 6), 6);
-    }
-
-    return s->smb.smbus;
-}
-
-static Property piix4_pm_properties[] = {
-    DEFINE_PROP_UINT32("smb_io_base", PIIX4PMState, smb_io_base, 0),
-    DEFINE_PROP_UINT8("disable_s3", PIIX4PMState, disable_s3, 0),
-    DEFINE_PROP_UINT8("disable_s4", PIIX4PMState, disable_s4, 0),
-    DEFINE_PROP_UINT8("s4_val", PIIX4PMState, s4_val, 2),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void piix4_pm_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
-    k->no_hotplug = 1;
-    k->init = piix4_pm_initfn;
-    k->config_write = pm_write_config;
-    k->vendor_id = PCI_VENDOR_ID_INTEL;
-    k->device_id = PCI_DEVICE_ID_INTEL_82371AB_3;
-    k->revision = 0x03;
-    k->class_id = PCI_CLASS_BRIDGE_OTHER;
-    dc->desc = "PM";
-    dc->no_user = 1;
-    dc->vmsd = &vmstate_acpi;
-    dc->props = piix4_pm_properties;
-}
-
-static const 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_types(void)
-{
-    type_register_static(&piix4_pm_info);
-}
-
-type_init(piix4_pm_register_types)
-
-static uint64_t gpe_readb(void *opaque, hwaddr addr, unsigned width)
-{
-    PIIX4PMState *s = opaque;
-    uint32_t val = acpi_gpe_ioport_readb(&s->ar, addr);
-
-    PIIX4_DPRINTF("gpe read %x == %x\n", addr, val);
-    return val;
-}
-
-static void gpe_writeb(void *opaque, hwaddr addr, uint64_t val,
-                       unsigned width)
-{
-    PIIX4PMState *s = opaque;
-
-    acpi_gpe_ioport_writeb(&s->ar, addr, val);
-    pm_update_sci(s);
-
-    PIIX4_DPRINTF("gpe write %x <== %d\n", addr, val);
-}
-
-static const MemoryRegionOps piix4_gpe_ops = {
-    .read = gpe_readb,
-    .write = gpe_writeb,
-    .valid.min_access_size = 1,
-    .valid.max_access_size = 4,
-    .impl.min_access_size = 1,
-    .impl.max_access_size = 1,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static uint64_t pci_read(void *opaque, hwaddr addr, unsigned int size)
-{
-    PIIX4PMState *s = opaque;
-    uint32_t val = 0;
-
-    switch (addr) {
-    case PCI_UP_BASE - PCI_HOTPLUG_ADDR:
-        /* Manufacture an "up" value to cause a device check on any hotplug
-         * slot with a device.  Extra device checks are harmless. */
-        val = s->pci0_slot_device_present & s->pci0_hotplug_enable;
-        PIIX4_DPRINTF("pci_up_read %x\n", val);
-        break;
-    case PCI_DOWN_BASE - PCI_HOTPLUG_ADDR:
-        val = s->pci0_status.down;
-        PIIX4_DPRINTF("pci_down_read %x\n", val);
-        break;
-    case PCI_EJ_BASE - PCI_HOTPLUG_ADDR:
-        /* No feature defined yet */
-        PIIX4_DPRINTF("pci_features_read %x\n", val);
-        break;
-    case PCI_RMV_BASE - PCI_HOTPLUG_ADDR:
-        val = s->pci0_hotplug_enable;
-        break;
-    default:
-        break;
-    }
-
-    return val;
-}
-
-static void pci_write(void *opaque, hwaddr addr, uint64_t data,
-                      unsigned int size)
-{
-    switch (addr) {
-    case PCI_EJ_BASE - PCI_HOTPLUG_ADDR:
-        acpi_piix_eject_slot(opaque, (uint32_t)data);
-        PIIX4_DPRINTF("pciej write %" HWADDR_PRIx " <== % " PRIu64 "\n",
-                      addr, data);
-        break;
-    default:
-        break;
-    }
-}
-
-static const MemoryRegionOps piix4_pci_ops = {
-    .read = pci_read,
-    .write = pci_write,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-};
-
-static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev,
-                                PCIHotplugState state);
-
-static void piix4_acpi_system_hot_add_init(MemoryRegion *parent,
-                                           PCIBus *bus, PIIX4PMState *s)
-{
-    memory_region_init_io(&s->io_gpe, &piix4_gpe_ops, s, "apci-gpe0",
-                          GPE_LEN);
-    memory_region_add_subregion(parent, GPE_BASE, &s->io_gpe);
-
-    memory_region_init_io(&s->io_pci, &piix4_pci_ops, s, "apci-pci-hotplug",
-                          PCI_HOTPLUG_SIZE);
-    memory_region_add_subregion(parent, PCI_HOTPLUG_ADDR,
-                                &s->io_pci);
-    pci_bus_hotplug(bus, piix4_device_hotplug, &s->dev.qdev);
-}
-
-static void enable_device(PIIX4PMState *s, int slot)
-{
-    s->ar.gpe.sts[0] |= PIIX4_PCI_HOTPLUG_STATUS;
-    s->pci0_slot_device_present |= (1U << slot);
-}
-
-static void disable_device(PIIX4PMState *s, int slot)
-{
-    s->ar.gpe.sts[0] |= PIIX4_PCI_HOTPLUG_STATUS;
-    s->pci0_status.down |= (1U << slot);
-}
-
-static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev,
-                               PCIHotplugState state)
-{
-    int slot = PCI_SLOT(dev->devfn);
-    PIIX4PMState *s = DO_UPCAST(PIIX4PMState, dev,
-                                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
-     * event when the device is disabled later. */
-    if (state == PCI_COLDPLUG_ENABLED) {
-        s->pci0_slot_device_present |= (1U << slot);
-        return 0;
-    }
-
-    if (state == PCI_HOTPLUG_ENABLED) {
-        enable_device(s, slot);
-    } else {
-        disable_device(s, slot);
-    }
-
-    pm_update_sci(s);
-
-    return 0;
-}
diff --git a/hw/adb.c b/hw/adb.c
deleted file mode 100644 (file)
index fd9052c..0000000
--- a/hw/adb.c
+++ /dev/null
@@ -1,581 +0,0 @@
-/*
- * QEMU ADB support
- *
- * Copyright (c) 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.
- */
-#include "hw/hw.h"
-#include "hw/adb.h"
-#include "ui/console.h"
-
-/* debug ADB */
-//#define DEBUG_ADB
-
-#ifdef DEBUG_ADB
-#define ADB_DPRINTF(fmt, ...) \
-do { printf("ADB: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define ADB_DPRINTF(fmt, ...)
-#endif
-
-/* ADB commands */
-#define ADB_BUSRESET           0x00
-#define ADB_FLUSH               0x01
-#define ADB_WRITEREG           0x08
-#define ADB_READREG            0x0c
-
-/* ADB device commands */
-#define ADB_CMD_SELF_TEST              0xff
-#define ADB_CMD_CHANGE_ID              0xfe
-#define ADB_CMD_CHANGE_ID_AND_ACT      0xfd
-#define ADB_CMD_CHANGE_ID_AND_ENABLE   0x00
-
-/* ADB default device IDs (upper 4 bits of ADB command byte) */
-#define ADB_DEVID_DONGLE   1
-#define ADB_DEVID_KEYBOARD 2
-#define ADB_DEVID_MOUSE    3
-#define ADB_DEVID_TABLET   4
-#define ADB_DEVID_MODEM    5
-#define ADB_DEVID_MISC     7
-
-/* error codes */
-#define ADB_RET_NOTPRESENT (-2)
-
-static void adb_device_reset(ADBDevice *d)
-{
-    qdev_reset_all(DEVICE(d));
-}
-
-int adb_request(ADBBusState *s, uint8_t *obuf, const uint8_t *buf, int len)
-{
-    ADBDevice *d;
-    int devaddr, cmd, i;
-
-    cmd = buf[0] & 0xf;
-    if (cmd == ADB_BUSRESET) {
-        for(i = 0; i < s->nb_devices; i++) {
-            d = s->devices[i];
-            adb_device_reset(d);
-        }
-        return 0;
-    }
-    devaddr = buf[0] >> 4;
-    for(i = 0; i < s->nb_devices; i++) {
-        d = s->devices[i];
-        if (d->devaddr == devaddr) {
-            ADBDeviceClass *adc = ADB_DEVICE_GET_CLASS(d);
-            return adc->devreq(d, obuf, buf, len);
-        }
-    }
-    return ADB_RET_NOTPRESENT;
-}
-
-/* XXX: move that to cuda ? */
-int adb_poll(ADBBusState *s, uint8_t *obuf)
-{
-    ADBDevice *d;
-    int olen, i;
-    uint8_t buf[1];
-
-    olen = 0;
-    for(i = 0; i < s->nb_devices; i++) {
-        if (s->poll_index >= s->nb_devices)
-            s->poll_index = 0;
-        d = s->devices[s->poll_index];
-        buf[0] = ADB_READREG | (d->devaddr << 4);
-        olen = adb_request(s, obuf + 1, buf, 1);
-        /* if there is data, we poll again the same device */
-        if (olen > 0) {
-            obuf[0] = buf[0];
-            olen++;
-            break;
-        }
-        s->poll_index++;
-    }
-    return olen;
-}
-
-static const TypeInfo adb_bus_type_info = {
-    .name = TYPE_ADB_BUS,
-    .parent = TYPE_BUS,
-    .instance_size = sizeof(ADBBusState),
-};
-
-static void adb_device_realizefn(DeviceState *dev, Error **errp)
-{
-    ADBDevice *d = ADB_DEVICE(dev);
-    ADBBusState *bus = ADB_BUS(qdev_get_parent_bus(dev));
-
-    if (bus->nb_devices >= MAX_ADB_DEVICES) {
-        return;
-    }
-
-    bus->devices[bus->nb_devices++] = d;
-}
-
-static void adb_device_class_init(ObjectClass *oc, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(oc);
-
-    dc->realize = adb_device_realizefn;
-    dc->bus_type = TYPE_ADB_BUS;
-}
-
-static const TypeInfo adb_device_type_info = {
-    .name = TYPE_ADB_DEVICE,
-    .parent = TYPE_DEVICE,
-    .instance_size = sizeof(ADBDevice),
-    .abstract = true,
-    .class_init = adb_device_class_init,
-};
-
-/***************************************************************/
-/* Keyboard ADB device */
-
-#define ADB_KEYBOARD(obj) OBJECT_CHECK(KBDState, (obj), TYPE_ADB_KEYBOARD)
-
-typedef struct KBDState {
-    /*< private >*/
-    ADBDevice parent_obj;
-    /*< public >*/
-
-    uint8_t data[128];
-    int rptr, wptr, count;
-} KBDState;
-
-#define ADB_KEYBOARD_CLASS(class) \
-    OBJECT_CLASS_CHECK(ADBKeyboardClass, (class), TYPE_ADB_KEYBOARD)
-#define ADB_KEYBOARD_GET_CLASS(obj) \
-    OBJECT_GET_CLASS(ADBKeyboardClass, (obj), TYPE_ADB_KEYBOARD)
-
-typedef struct ADBKeyboardClass {
-    /*< private >*/
-    ADBDeviceClass parent_class;
-    /*< public >*/
-
-    DeviceRealize parent_realize;
-} ADBKeyboardClass;
-
-static const uint8_t pc_to_adb_keycode[256] = {
-  0, 53, 18, 19, 20, 21, 23, 22, 26, 28, 25, 29, 27, 24, 51, 48,
- 12, 13, 14, 15, 17, 16, 32, 34, 31, 35, 33, 30, 36, 54,  0,  1,
-  2,  3,  5,  4, 38, 40, 37, 41, 39, 50, 56, 42,  6,  7,  8,  9,
- 11, 45, 46, 43, 47, 44,123, 67, 58, 49, 57,122,120, 99,118, 96,
- 97, 98,100,101,109, 71,107, 89, 91, 92, 78, 86, 87, 88, 69, 83,
- 84, 85, 82, 65,  0,  0, 10,103,111,  0,  0,110, 81,  0,  0,  0,
-  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-  0,  0,  0, 94,  0, 93,  0,  0,  0,  0,  0,  0,104,102,  0,  0,
-  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 76,125,  0,  0,
-  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,105,  0,  0,  0,  0,  0,
-  0,  0,  0,  0,  0, 75,  0,  0,124,  0,  0,  0,  0,  0,  0,  0,
-  0,  0,  0,  0,  0,  0,  0,115, 62,116,  0, 59,  0, 60,  0,119,
- 61,121,114,117,  0,  0,  0,  0,  0,  0,  0, 55,126,  0,127,  0,
-  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-  0,  0,  0,  0,  0, 95,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-};
-
-static void adb_kbd_put_keycode(void *opaque, int keycode)
-{
-    KBDState *s = opaque;
-
-    if (s->count < sizeof(s->data)) {
-        s->data[s->wptr] = keycode;
-        if (++s->wptr == sizeof(s->data))
-            s->wptr = 0;
-        s->count++;
-    }
-}
-
-static int adb_kbd_poll(ADBDevice *d, uint8_t *obuf)
-{
-    static int ext_keycode;
-    KBDState *s = ADB_KEYBOARD(d);
-    int adb_keycode, keycode;
-    int olen;
-
-    olen = 0;
-    for(;;) {
-        if (s->count == 0)
-            break;
-        keycode = s->data[s->rptr];
-        if (++s->rptr == sizeof(s->data))
-            s->rptr = 0;
-        s->count--;
-
-        if (keycode == 0xe0) {
-            ext_keycode = 1;
-        } else {
-            if (ext_keycode)
-                adb_keycode =  pc_to_adb_keycode[keycode | 0x80];
-            else
-                adb_keycode =  pc_to_adb_keycode[keycode & 0x7f];
-            obuf[0] = adb_keycode | (keycode & 0x80);
-            /* NOTE: could put a second keycode if needed */
-            obuf[1] = 0xff;
-            olen = 2;
-            ext_keycode = 0;
-            break;
-        }
-    }
-    return olen;
-}
-
-static int adb_kbd_request(ADBDevice *d, uint8_t *obuf,
-                           const uint8_t *buf, int len)
-{
-    KBDState *s = ADB_KEYBOARD(d);
-    int cmd, reg, olen;
-
-    if ((buf[0] & 0x0f) == ADB_FLUSH) {
-        /* flush keyboard fifo */
-        s->wptr = s->rptr = s->count = 0;
-        return 0;
-    }
-
-    cmd = buf[0] & 0xc;
-    reg = buf[0] & 0x3;
-    olen = 0;
-    switch(cmd) {
-    case ADB_WRITEREG:
-        switch(reg) {
-        case 2:
-            /* LED status */
-            break;
-        case 3:
-            switch(buf[2]) {
-            case ADB_CMD_SELF_TEST:
-                break;
-            case ADB_CMD_CHANGE_ID:
-            case ADB_CMD_CHANGE_ID_AND_ACT:
-            case ADB_CMD_CHANGE_ID_AND_ENABLE:
-                d->devaddr = buf[1] & 0xf;
-                break;
-            default:
-                /* XXX: check this */
-                d->devaddr = buf[1] & 0xf;
-                d->handler = buf[2];
-                break;
-            }
-        }
-        break;
-    case ADB_READREG:
-        switch(reg) {
-        case 0:
-            olen = adb_kbd_poll(d, obuf);
-            break;
-        case 1:
-            break;
-        case 2:
-            obuf[0] = 0x00; /* XXX: check this */
-            obuf[1] = 0x07; /* led status */
-            olen = 2;
-            break;
-        case 3:
-            obuf[0] = d->handler;
-            obuf[1] = d->devaddr;
-            olen = 2;
-            break;
-        }
-        break;
-    }
-    return olen;
-}
-
-static const VMStateDescription vmstate_adb_kbd = {
-    .name = "adb_kbd",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField[]) {
-        VMSTATE_BUFFER(data, KBDState),
-        VMSTATE_INT32(rptr, KBDState),
-        VMSTATE_INT32(wptr, KBDState),
-        VMSTATE_INT32(count, KBDState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void adb_kbd_reset(DeviceState *dev)
-{
-    ADBDevice *d = ADB_DEVICE(dev);
-    KBDState *s = ADB_KEYBOARD(dev);
-
-    d->handler = 1;
-    d->devaddr = ADB_DEVID_KEYBOARD;
-    memset(s->data, 0, sizeof(s->data));
-    s->rptr = 0;
-    s->wptr = 0;
-    s->count = 0;
-}
-
-static void adb_kbd_realizefn(DeviceState *dev, Error **errp)
-{
-    ADBDevice *d = ADB_DEVICE(dev);
-    ADBKeyboardClass *akc = ADB_KEYBOARD_GET_CLASS(dev);
-
-    akc->parent_realize(dev, errp);
-
-    qemu_add_kbd_event_handler(adb_kbd_put_keycode, d);
-}
-
-static void adb_kbd_initfn(Object *obj)
-{
-    ADBDevice *d = ADB_DEVICE(obj);
-
-    d->devaddr = ADB_DEVID_KEYBOARD;
-}
-
-static void adb_kbd_class_init(ObjectClass *oc, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(oc);
-    ADBDeviceClass *adc = ADB_DEVICE_CLASS(oc);
-    ADBKeyboardClass *akc = ADB_KEYBOARD_CLASS(oc);
-
-    akc->parent_realize = dc->realize;
-    dc->realize = adb_kbd_realizefn;
-
-    adc->devreq = adb_kbd_request;
-    dc->reset = adb_kbd_reset;
-    dc->vmsd = &vmstate_adb_kbd;
-}
-
-static const TypeInfo adb_kbd_type_info = {
-    .name = TYPE_ADB_KEYBOARD,
-    .parent = TYPE_ADB_DEVICE,
-    .instance_size = sizeof(KBDState),
-    .instance_init = adb_kbd_initfn,
-    .class_init = adb_kbd_class_init,
-    .class_size = sizeof(ADBKeyboardClass),
-};
-
-/***************************************************************/
-/* Mouse ADB device */
-
-#define ADB_MOUSE(obj) OBJECT_CHECK(MouseState, (obj), TYPE_ADB_MOUSE)
-
-typedef struct MouseState {
-    /*< public >*/
-    ADBDevice parent_obj;
-    /*< private >*/
-
-    int buttons_state, last_buttons_state;
-    int dx, dy, dz;
-} MouseState;
-
-#define ADB_MOUSE_CLASS(class) \
-    OBJECT_CLASS_CHECK(ADBMouseClass, (class), TYPE_ADB_MOUSE)
-#define ADB_MOUSE_GET_CLASS(obj) \
-    OBJECT_GET_CLASS(ADBMouseClass, (obj), TYPE_ADB_MOUSE)
-
-typedef struct ADBMouseClass {
-    /*< public >*/
-    ADBDeviceClass parent_class;
-    /*< private >*/
-
-    DeviceRealize parent_realize;
-} ADBMouseClass;
-
-static void adb_mouse_event(void *opaque,
-                            int dx1, int dy1, int dz1, int buttons_state)
-{
-    MouseState *s = opaque;
-
-    s->dx += dx1;
-    s->dy += dy1;
-    s->dz += dz1;
-    s->buttons_state = buttons_state;
-}
-
-
-static int adb_mouse_poll(ADBDevice *d, uint8_t *obuf)
-{
-    MouseState *s = ADB_MOUSE(d);
-    int dx, dy;
-
-    if (s->last_buttons_state == s->buttons_state &&
-        s->dx == 0 && s->dy == 0)
-        return 0;
-
-    dx = s->dx;
-    if (dx < -63)
-        dx = -63;
-    else if (dx > 63)
-        dx = 63;
-
-    dy = s->dy;
-    if (dy < -63)
-        dy = -63;
-    else if (dy > 63)
-        dy = 63;
-
-    s->dx -= dx;
-    s->dy -= dy;
-    s->last_buttons_state = s->buttons_state;
-
-    dx &= 0x7f;
-    dy &= 0x7f;
-
-    if (!(s->buttons_state & MOUSE_EVENT_LBUTTON))
-        dy |= 0x80;
-    if (!(s->buttons_state & MOUSE_EVENT_RBUTTON))
-        dx |= 0x80;
-
-    obuf[0] = dy;
-    obuf[1] = dx;
-    return 2;
-}
-
-static int adb_mouse_request(ADBDevice *d, uint8_t *obuf,
-                             const uint8_t *buf, int len)
-{
-    MouseState *s = ADB_MOUSE(d);
-    int cmd, reg, olen;
-
-    if ((buf[0] & 0x0f) == ADB_FLUSH) {
-        /* flush mouse fifo */
-        s->buttons_state = s->last_buttons_state;
-        s->dx = 0;
-        s->dy = 0;
-        s->dz = 0;
-        return 0;
-    }
-
-    cmd = buf[0] & 0xc;
-    reg = buf[0] & 0x3;
-    olen = 0;
-    switch(cmd) {
-    case ADB_WRITEREG:
-        ADB_DPRINTF("write reg %d val 0x%2.2x\n", reg, buf[1]);
-        switch(reg) {
-        case 2:
-            break;
-        case 3:
-            switch(buf[2]) {
-            case ADB_CMD_SELF_TEST:
-                break;
-            case ADB_CMD_CHANGE_ID:
-            case ADB_CMD_CHANGE_ID_AND_ACT:
-            case ADB_CMD_CHANGE_ID_AND_ENABLE:
-                d->devaddr = buf[1] & 0xf;
-                break;
-            default:
-                /* XXX: check this */
-                d->devaddr = buf[1] & 0xf;
-                break;
-            }
-        }
-        break;
-    case ADB_READREG:
-        switch(reg) {
-        case 0:
-            olen = adb_mouse_poll(d, obuf);
-            break;
-        case 1:
-            break;
-        case 3:
-            obuf[0] = d->handler;
-            obuf[1] = d->devaddr;
-            olen = 2;
-            break;
-        }
-        ADB_DPRINTF("read reg %d obuf[0] 0x%2.2x obuf[1] 0x%2.2x\n", reg,
-                    obuf[0], obuf[1]);
-        break;
-    }
-    return olen;
-}
-
-static void adb_mouse_reset(DeviceState *dev)
-{
-    ADBDevice *d = ADB_DEVICE(dev);
-    MouseState *s = ADB_MOUSE(dev);
-
-    d->handler = 2;
-    d->devaddr = ADB_DEVID_MOUSE;
-    s->last_buttons_state = s->buttons_state = 0;
-    s->dx = s->dy = s->dz = 0;
-}
-
-static const VMStateDescription vmstate_adb_mouse = {
-    .name = "adb_mouse",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField[]) {
-        VMSTATE_INT32(buttons_state, MouseState),
-        VMSTATE_INT32(last_buttons_state, MouseState),
-        VMSTATE_INT32(dx, MouseState),
-        VMSTATE_INT32(dy, MouseState),
-        VMSTATE_INT32(dz, MouseState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void adb_mouse_realizefn(DeviceState *dev, Error **errp)
-{
-    MouseState *s = ADB_MOUSE(dev);
-    ADBMouseClass *amc = ADB_MOUSE_GET_CLASS(dev);
-
-    amc->parent_realize(dev, errp);
-
-    qemu_add_mouse_event_handler(adb_mouse_event, s, 0, "QEMU ADB Mouse");
-}
-
-static void adb_mouse_initfn(Object *obj)
-{
-    ADBDevice *d = ADB_DEVICE(obj);
-
-    d->devaddr = ADB_DEVID_MOUSE;
-}
-
-static void adb_mouse_class_init(ObjectClass *oc, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(oc);
-    ADBDeviceClass *adc = ADB_DEVICE_CLASS(oc);
-    ADBMouseClass *amc = ADB_MOUSE_CLASS(oc);
-
-    amc->parent_realize = dc->realize;
-    dc->realize = adb_mouse_realizefn;
-
-    adc->devreq = adb_mouse_request;
-    dc->reset = adb_mouse_reset;
-    dc->vmsd = &vmstate_adb_mouse;
-}
-
-static const TypeInfo adb_mouse_type_info = {
-    .name = TYPE_ADB_MOUSE,
-    .parent = TYPE_ADB_DEVICE,
-    .instance_size = sizeof(MouseState),
-    .instance_init = adb_mouse_initfn,
-    .class_init = adb_mouse_class_init,
-    .class_size = sizeof(ADBMouseClass),
-};
-
-
-static void adb_register_types(void)
-{
-    type_register_static(&adb_bus_type_info);
-    type_register_static(&adb_device_type_info);
-    type_register_static(&adb_kbd_type_info);
-    type_register_static(&adb_mouse_type_info);
-}
-
-type_init(adb_register_types)
diff --git a/hw/adb.h b/hw/adb.h
deleted file mode 100644 (file)
index bdfccd4..0000000
--- a/hw/adb.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * QEMU ADB emulation shared definitions and prototypes
- *
- * Copyright (c) 2004-2007 Fabrice Bellard
- * Copyright (c) 2007 Jocelyn Mayer
- *
- * 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 !defined(__ADB_H__)
-#define __ADB_H__
-
-#include "hw/qdev.h"
-
-#define MAX_ADB_DEVICES 16
-
-#define ADB_MAX_OUT_LEN 16
-
-typedef struct ADBBusState ADBBusState;
-typedef struct ADBDevice ADBDevice;
-
-/* buf = NULL means polling */
-typedef int ADBDeviceRequest(ADBDevice *d, uint8_t *buf_out,
-                              const uint8_t *buf, int len);
-
-#define TYPE_ADB_DEVICE "adb-device"
-#define ADB_DEVICE(obj) OBJECT_CHECK(ADBDevice, (obj), TYPE_ADB_DEVICE)
-
-struct ADBDevice {
-    /*< private >*/
-    DeviceState parent_obj;
-    /*< public >*/
-
-    int devaddr;
-    int handler;
-};
-
-#define ADB_DEVICE_CLASS(cls) \
-    OBJECT_CLASS_CHECK(ADBDeviceClass, (cls), TYPE_ADB_DEVICE)
-#define ADB_DEVICE_GET_CLASS(obj) \
-    OBJECT_GET_CLASS(ADBDeviceClass, (obj), TYPE_ADB_DEVICE)
-
-typedef struct ADBDeviceClass {
-    /*< private >*/
-    DeviceClass parent_class;
-    /*< public >*/
-
-    ADBDeviceRequest *devreq;
-} ADBDeviceClass;
-
-#define TYPE_ADB_BUS "apple-desktop-bus"
-#define ADB_BUS(obj) OBJECT_CHECK(ADBBusState, (obj), TYPE_ADB_BUS)
-
-struct ADBBusState {
-    /*< private >*/
-    BusState parent_obj;
-    /*< public >*/
-
-    ADBDevice *devices[MAX_ADB_DEVICES];
-    int nb_devices;
-    int poll_index;
-};
-
-int adb_request(ADBBusState *s, uint8_t *buf_out,
-                const uint8_t *buf, int len);
-int adb_poll(ADBBusState *s, uint8_t *buf_out);
-
-#define TYPE_ADB_KEYBOARD "adb-keyboard"
-#define TYPE_ADB_MOUSE "adb-mouse"
-
-#endif /* !defined(__ADB_H__) */
diff --git a/hw/adlib.c b/hw/adlib.c
deleted file mode 100644 (file)
index e6bce59..0000000
+++ /dev/null
@@ -1,337 +0,0 @@
-/*
- * QEMU Proxy for OPL2/3 emulation by MAME team
- *
- * Copyright (c) 2004-2005 Vassili Karpov (malc)
- *
- * 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 "hw/hw.h"
-#include "hw/audiodev.h"
-#include "audio/audio.h"
-#include "hw/isa.h"
-
-//#define DEBUG
-
-#define ADLIB_KILL_TIMERS 1
-
-#ifdef DEBUG
-#include "qemu/timer.h"
-#endif
-
-#define dolog(...) AUD_log ("adlib", __VA_ARGS__)
-#ifdef DEBUG
-#define ldebug(...) dolog (__VA_ARGS__)
-#else
-#define ldebug(...)
-#endif
-
-#ifdef HAS_YMF262
-#include "ymf262.h"
-void YMF262UpdateOneQEMU (int which, INT16 *dst, int length);
-#define SHIFT 2
-#else
-#include "hw/fmopl.h"
-#define SHIFT 1
-#endif
-
-#define IO_READ_PROTO(name) \
-    uint32_t name (void *opaque, uint32_t nport)
-#define IO_WRITE_PROTO(name) \
-    void name (void *opaque, uint32_t nport, uint32_t val)
-
-static struct {
-    int port;
-    int freq;
-} conf = {0x220, 44100};
-
-typedef struct {
-    QEMUSoundCard card;
-    int ticking[2];
-    int enabled;
-    int active;
-    int bufpos;
-#ifdef DEBUG
-    int64_t exp[2];
-#endif
-    int16_t *mixbuf;
-    uint64_t dexp[2];
-    SWVoiceOut *voice;
-    int left, pos, samples;
-    QEMUAudioTimeStamp ats;
-#ifndef HAS_YMF262
-    FM_OPL *opl;
-#endif
-} AdlibState;
-
-static AdlibState glob_adlib;
-
-static void adlib_stop_opl_timer (AdlibState *s, size_t n)
-{
-#ifdef HAS_YMF262
-    YMF262TimerOver (0, n);
-#else
-    OPLTimerOver (s->opl, n);
-#endif
-    s->ticking[n] = 0;
-}
-
-static void adlib_kill_timers (AdlibState *s)
-{
-    size_t i;
-
-    for (i = 0; i < 2; ++i) {
-        if (s->ticking[i]) {
-            uint64_t delta;
-
-            delta = AUD_get_elapsed_usec_out (s->voice, &s->ats);
-            ldebug (
-                "delta = %f dexp = %f expired => %d\n",
-                delta / 1000000.0,
-                s->dexp[i] / 1000000.0,
-                delta >= s->dexp[i]
-                );
-            if (ADLIB_KILL_TIMERS || delta >= s->dexp[i]) {
-                adlib_stop_opl_timer (s, i);
-                AUD_init_time_stamp_out (s->voice, &s->ats);
-            }
-        }
-    }
-}
-
-static IO_WRITE_PROTO (adlib_write)
-{
-    AdlibState *s = opaque;
-    int a = nport & 3;
-
-    s->active = 1;
-    AUD_set_active_out (s->voice, 1);
-
-    adlib_kill_timers (s);
-
-#ifdef HAS_YMF262
-    YMF262Write (0, a, val);
-#else
-    OPLWrite (s->opl, a, val);
-#endif
-}
-
-static IO_READ_PROTO (adlib_read)
-{
-    AdlibState *s = opaque;
-    uint8_t data;
-    int a = nport & 3;
-
-    adlib_kill_timers (s);
-
-#ifdef HAS_YMF262
-    data = YMF262Read (0, a);
-#else
-    data = OPLRead (s->opl, a);
-#endif
-    return data;
-}
-
-static void timer_handler (int c, double interval_Sec)
-{
-    AdlibState *s = &glob_adlib;
-    unsigned n = c & 1;
-#ifdef DEBUG
-    double interval;
-    int64_t exp;
-#endif
-
-    if (interval_Sec == 0.0) {
-        s->ticking[n] = 0;
-        return;
-    }
-
-    s->ticking[n] = 1;
-#ifdef DEBUG
-    interval = get_ticks_per_sec () * interval_Sec;
-    exp = qemu_get_clock_ns (vm_clock) + interval;
-    s->exp[n] = exp;
-#endif
-
-    s->dexp[n] = interval_Sec * 1000000.0;
-    AUD_init_time_stamp_out (s->voice, &s->ats);
-}
-
-static int write_audio (AdlibState *s, int samples)
-{
-    int net = 0;
-    int pos = s->pos;
-
-    while (samples) {
-        int nbytes, wbytes, wsampl;
-
-        nbytes = samples << SHIFT;
-        wbytes = AUD_write (
-            s->voice,
-            s->mixbuf + (pos << (SHIFT - 1)),
-            nbytes
-            );
-
-        if (wbytes) {
-            wsampl = wbytes >> SHIFT;
-
-            samples -= wsampl;
-            pos = (pos + wsampl) % s->samples;
-
-            net += wsampl;
-        }
-        else {
-            break;
-        }
-    }
-
-    return net;
-}
-
-static void adlib_callback (void *opaque, int free)
-{
-    AdlibState *s = opaque;
-    int samples, net = 0, to_play, written;
-
-    samples = free >> SHIFT;
-    if (!(s->active && s->enabled) || !samples) {
-        return;
-    }
-
-    to_play = audio_MIN (s->left, samples);
-    while (to_play) {
-        written = write_audio (s, to_play);
-
-        if (written) {
-            s->left -= written;
-            samples -= written;
-            to_play -= written;
-            s->pos = (s->pos + written) % s->samples;
-        }
-        else {
-            return;
-        }
-    }
-
-    samples = audio_MIN (samples, s->samples - s->pos);
-    if (!samples) {
-        return;
-    }
-
-#ifdef HAS_YMF262
-    YMF262UpdateOneQEMU (0, s->mixbuf + s->pos * 2, samples);
-#else
-    YM3812UpdateOne (s->opl, s->mixbuf + s->pos, samples);
-#endif
-
-    while (samples) {
-        written = write_audio (s, samples);
-
-        if (written) {
-            net += written;
-            samples -= written;
-            s->pos = (s->pos + written) % s->samples;
-        }
-        else {
-            s->left = samples;
-            return;
-        }
-    }
-}
-
-static void Adlib_fini (AdlibState *s)
-{
-#ifdef HAS_YMF262
-    YMF262Shutdown ();
-#else
-    if (s->opl) {
-        OPLDestroy (s->opl);
-        s->opl = NULL;
-    }
-#endif
-
-    if (s->mixbuf) {
-        g_free (s->mixbuf);
-    }
-
-    s->active = 0;
-    s->enabled = 0;
-    AUD_remove_card (&s->card);
-}
-
-int Adlib_init (ISABus *bus)
-{
-    AdlibState *s = &glob_adlib;
-    struct audsettings as;
-
-#ifdef HAS_YMF262
-    if (YMF262Init (1, 14318180, conf.freq)) {
-        dolog ("YMF262Init %d failed\n", conf.freq);
-        return -1;
-    }
-    else {
-        YMF262SetTimerHandler (0, timer_handler, 0);
-        s->enabled = 1;
-    }
-#else
-    s->opl = OPLCreate (OPL_TYPE_YM3812, 3579545, conf.freq);
-    if (!s->opl) {
-        dolog ("OPLCreate %d failed\n", conf.freq);
-        return -1;
-    }
-    else {
-        OPLSetTimerHandler (s->opl, timer_handler, 0);
-        s->enabled = 1;
-    }
-#endif
-
-    as.freq = conf.freq;
-    as.nchannels = SHIFT;
-    as.fmt = AUD_FMT_S16;
-    as.endianness = AUDIO_HOST_ENDIANNESS;
-
-    AUD_register_card ("adlib", &s->card);
-
-    s->voice = AUD_open_out (
-        &s->card,
-        s->voice,
-        "adlib",
-        s,
-        adlib_callback,
-        &as
-        );
-    if (!s->voice) {
-        Adlib_fini (s);
-        return -1;
-    }
-
-    s->samples = AUD_get_buffer_size_out (s->voice) >> SHIFT;
-    s->mixbuf = g_malloc0 (s->samples << SHIFT);
-
-    register_ioport_read (0x388, 4, 1, adlib_read, s);
-    register_ioport_write (0x388, 4, 1, adlib_write, s);
-
-    register_ioport_read (conf.port, 4, 1, adlib_read, s);
-    register_ioport_write (conf.port, 4, 1, adlib_write, s);
-
-    register_ioport_read (conf.port + 8, 2, 1, adlib_read, s);
-    register_ioport_write (conf.port + 8, 2, 1, adlib_write, s);
-
-    return 0;
-}
diff --git a/hw/ads7846.c b/hw/ads7846.c
deleted file mode 100644 (file)
index 5da3dc5..0000000
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * TI ADS7846 / TSC2046 chip emulation.
- *
- * Copyright (c) 2006 Openedhand Ltd.
- * Written by Andrzej Zaborowski <balrog@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/ssi.h"
-#include "ui/console.h"
-
-typedef struct {
-    SSISlave ssidev;
-    qemu_irq interrupt;
-
-    int input[8];
-    int pressure;
-    int noise;
-
-    int cycle;
-    int output;
-} ADS7846State;
-
-/* Control-byte bitfields */
-#define CB_PD0         (1 << 0)
-#define CB_PD1         (1 << 1)
-#define CB_SER         (1 << 2)
-#define CB_MODE                (1 << 3)
-#define CB_A0          (1 << 4)
-#define CB_A1          (1 << 5)
-#define CB_A2          (1 << 6)
-#define CB_START       (1 << 7)
-
-#define X_AXIS_DMAX    3470
-#define X_AXIS_MIN     290
-#define Y_AXIS_DMAX    3450
-#define Y_AXIS_MIN     200
-
-#define ADS_VBAT       2000
-#define ADS_VAUX       2000
-#define ADS_TEMP0      2000
-#define ADS_TEMP1      3000
-#define ADS_XPOS(x, y) (X_AXIS_MIN + ((X_AXIS_DMAX * (x)) >> 15))
-#define ADS_YPOS(x, y) (Y_AXIS_MIN + ((Y_AXIS_DMAX * (y)) >> 15))
-#define ADS_Z1POS(x, y)        600
-#define ADS_Z2POS(x, y)        (600 + 6000 / ADS_XPOS(x, y))
-
-static void ads7846_int_update(ADS7846State *s)
-{
-    if (s->interrupt)
-        qemu_set_irq(s->interrupt, s->pressure == 0);
-}
-
-static uint32_t ads7846_transfer(SSISlave *dev, uint32_t value)
-{
-    ADS7846State *s = FROM_SSI_SLAVE(ADS7846State, dev);
-
-    switch (s->cycle ++) {
-    case 0:
-        if (!(value & CB_START)) {
-            s->cycle = 0;
-            break;
-        }
-
-        s->output = s->input[(value >> 4) & 7];
-
-        /* Imitate the ADC noise, some drivers expect this.  */
-        s->noise = (s->noise + 3) & 7;
-        switch ((value >> 4) & 7) {
-        case 1: s->output += s->noise ^ 2; break;
-        case 3: s->output += s->noise ^ 0; break;
-        case 4: s->output += s->noise ^ 7; break;
-        case 5: s->output += s->noise ^ 5; break;
-        }
-
-        if (value & CB_MODE)
-            s->output >>= 4;   /* 8 bits instead of 12 */
-
-        break;
-    case 1:
-        s->cycle = 0;
-        break;
-    }
-    return s->output;
-}
-
-static void ads7846_ts_event(void *opaque,
-                int x, int y, int z, int buttons_state)
-{
-    ADS7846State *s = opaque;
-
-    if (buttons_state) {
-        x = 0x7fff - x;
-        s->input[1] = ADS_XPOS(x, y);
-        s->input[3] = ADS_Z1POS(x, y);
-        s->input[4] = ADS_Z2POS(x, y);
-        s->input[5] = ADS_YPOS(x, y);
-    }
-
-    if (s->pressure == !buttons_state) {
-        s->pressure = !!buttons_state;
-
-        ads7846_int_update(s);
-    }
-}
-
-static int ads7856_post_load(void *opaque, int version_id)
-{
-    ADS7846State *s = opaque;
-
-    s->pressure = 0;
-    ads7846_int_update(s);
-    return 0;
-}
-
-static const VMStateDescription vmstate_ads7846 = {
-    .name = "ads7846",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .post_load = ads7856_post_load,
-    .fields      = (VMStateField[]) {
-        VMSTATE_SSI_SLAVE(ssidev, ADS7846State),
-        VMSTATE_INT32_ARRAY(input, ADS7846State, 8),
-        VMSTATE_INT32(noise, ADS7846State),
-        VMSTATE_INT32(cycle, ADS7846State),
-        VMSTATE_INT32(output, ADS7846State),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static int ads7846_init(SSISlave *dev)
-{
-    ADS7846State *s = FROM_SSI_SLAVE(ADS7846State, dev);
-
-    qdev_init_gpio_out(&dev->qdev, &s->interrupt, 1);
-
-    s->input[0] = ADS_TEMP0;   /* TEMP0 */
-    s->input[2] = ADS_VBAT;    /* VBAT */
-    s->input[6] = ADS_VAUX;    /* VAUX */
-    s->input[7] = ADS_TEMP1;   /* TEMP1 */
-
-    /* We want absolute coordinates */
-    qemu_add_mouse_event_handler(ads7846_ts_event, s, 1,
-                    "QEMU ADS7846-driven Touchscreen");
-
-    ads7846_int_update(s);
-
-    vmstate_register(NULL, -1, &vmstate_ads7846, s);
-    return 0;
-}
-
-static void ads7846_class_init(ObjectClass *klass, void *data)
-{
-    SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
-
-    k->init = ads7846_init;
-    k->transfer = ads7846_transfer;
-}
-
-static const TypeInfo ads7846_info = {
-    .name          = "ads7846",
-    .parent        = TYPE_SSI_SLAVE,
-    .instance_size = sizeof(ADS7846State),
-    .class_init    = ads7846_class_init,
-};
-
-static void ads7846_register_types(void)
-{
-    type_register_static(&ads7846_info);
-}
-
-type_init(ads7846_register_types)
index db868d2ea69fc64be34f58127b82994729ed6d7b..5c742756f016401178e6676946a35af5ec875ab7 100644 (file)
@@ -1,6 +1 @@
-obj-y = mc146818rtc.o
-obj-y += alpha_typhoon.o
-
-obj-y := $(addprefix ../,$(obj-y))
-
-obj-y += dp264.o pci.o
+obj-y += dp264.o pci.o typhoon.o
diff --git a/hw/alpha/alpha_sys.h b/hw/alpha/alpha_sys.h
new file mode 100644 (file)
index 0000000..50e7730
--- /dev/null
@@ -0,0 +1,21 @@
+/* Alpha cores and system support chips.  */
+
+#ifndef HW_ALPHA_H
+#define HW_ALPHA_H 1
+
+#include "hw/pci/pci.h"
+#include "hw/pci/pci_host.h"
+#include "hw/ide.h"
+#include "hw/i386/pc.h"
+#include "hw/irq.h"
+
+
+PCIBus *typhoon_init(ram_addr_t, ISABus **, qemu_irq *, AlphaCPU *[4],
+                     pci_map_irq_fn);
+
+/* alpha_pci.c.  */
+extern const MemoryRegionOps alpha_pci_bw_io_ops;
+extern const MemoryRegionOps alpha_pci_conf1_ops;
+extern const MemoryRegionOps alpha_pci_iack_ops;
+
+#endif
index 13aaa57b9034eb0c59f3e46f0f4c494b6f3d23cd..8695efb8efe05adc45bfd04331853ef674cdbdf7 100644 (file)
 #include "elf.h"
 #include "hw/loader.h"
 #include "hw/boards.h"
-#include "hw/alpha_sys.h"
+#include "alpha_sys.h"
 #include "sysemu/sysemu.h"
-#include "hw/mc146818rtc.h"
+#include "hw/timer/mc146818rtc.h"
 #include "hw/ide.h"
-#include "hw/i8254.h"
-#include "hw/serial.h"
+#include "hw/timer/i8254.h"
+#include "hw/char/serial.h"
 
 #define MAX_IDE_BUS 2
 
index 84628686ad71c12cf0bef52676016adfdf88807c..7327d488fdb3bbdf7b6dee148c84e24320f55d14 100644 (file)
@@ -7,7 +7,7 @@
  */
 
 #include "config.h"
-#include "hw/alpha_sys.h"
+#include "alpha_sys.h"
 #include "qemu/log.h"
 #include "sysemu/sysemu.h"
 
diff --git a/hw/alpha/typhoon.c b/hw/alpha/typhoon.c
new file mode 100644 (file)
index 0000000..faec8dc
--- /dev/null
@@ -0,0 +1,842 @@
+/*
+ * DEC 21272 (TSUNAMI/TYPHOON) chipset emulation.
+ *
+ * Written by Richard Henderson.
+ *
+ * This work is licensed under the GNU GPL license version 2 or later.
+ */
+
+#include "cpu.h"
+#include "exec/exec-all.h"
+#include "hw/hw.h"
+#include "hw/arm/devices.h"
+#include "sysemu/sysemu.h"
+#include "alpha_sys.h"
+#include "exec/address-spaces.h"
+
+
+#define TYPE_TYPHOON_PCI_HOST_BRIDGE "typhoon-pcihost"
+
+typedef struct TyphoonCchip {
+    MemoryRegion region;
+    uint64_t misc;
+    uint64_t drir;
+    uint64_t dim[4];
+    uint32_t iic[4];
+    AlphaCPU *cpu[4];
+} TyphoonCchip;
+
+typedef struct TyphoonWindow {
+    uint32_t base_addr;
+    uint32_t mask;
+    uint32_t translated_base_pfn;
+} TyphoonWindow;
+typedef struct TyphoonPchip {
+    MemoryRegion region;
+    MemoryRegion reg_iack;
+    MemoryRegion reg_mem;
+    MemoryRegion reg_io;
+    MemoryRegion reg_conf;
+    uint64_t ctl;
+    TyphoonWindow win[4];
+} TyphoonPchip;
+
+#define TYPHOON_PCI_HOST_BRIDGE(obj) \
+    OBJECT_CHECK(TyphoonState, (obj), TYPE_TYPHOON_PCI_HOST_BRIDGE)
+
+typedef struct TyphoonState {
+    PCIHostState parent_obj;
+
+    TyphoonCchip cchip;
+    TyphoonPchip pchip;
+    MemoryRegion dchip_region;
+    MemoryRegion ram_region;
+
+    /* QEMU emulation state.  */
+    uint32_t latch_tmp;
+} TyphoonState;
+
+/* Called when one of DRIR or DIM changes.  */
+static void cpu_irq_change(AlphaCPU *cpu, uint64_t req)
+{
+    /* If there are any non-masked interrupts, tell the cpu.  */
+    if (cpu != NULL) {
+        CPUState *cs = CPU(cpu);
+        if (req) {
+            cpu_interrupt(cs, CPU_INTERRUPT_HARD);
+        } else {
+            cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
+        }
+    }
+}
+
+static uint64_t cchip_read(void *opaque, hwaddr addr, unsigned size)
+{
+    CPUAlphaState *env = cpu_single_env;
+    TyphoonState *s = opaque;
+    CPUState *cpu;
+    uint64_t ret = 0;
+
+    if (addr & 4) {
+        return s->latch_tmp;
+    }
+
+    switch (addr) {
+    case 0x0000:
+        /* CSC: Cchip System Configuration Register.  */
+        /* All sorts of data here; probably the only thing relevant is
+           PIP<14> Pchip 1 Present = 0.  */
+        break;
+
+    case 0x0040:
+        /* MTR: Memory Timing Register.  */
+        /* All sorts of stuff related to real DRAM.  */
+        break;
+
+    case 0x0080:
+        /* MISC: Miscellaneous Register.  */
+        cpu = ENV_GET_CPU(env);
+        ret = s->cchip.misc | (cpu->cpu_index & 3);
+        break;
+
+    case 0x00c0:
+        /* MPD: Memory Presence Detect Register.  */
+        break;
+
+    case 0x0100: /* AAR0 */
+    case 0x0140: /* AAR1 */
+    case 0x0180: /* AAR2 */
+    case 0x01c0: /* AAR3 */
+        /* AAR: Array Address Register.  */
+        /* All sorts of information about DRAM.  */
+        break;
+
+    case 0x0200:
+        /* DIM0: Device Interrupt Mask Register, CPU0.  */
+        ret = s->cchip.dim[0];
+        break;
+    case 0x0240:
+        /* DIM1: Device Interrupt Mask Register, CPU1.  */
+        ret = s->cchip.dim[1];
+        break;
+    case 0x0280:
+        /* DIR0: Device Interrupt Request Register, CPU0.  */
+        ret = s->cchip.dim[0] & s->cchip.drir;
+        break;
+    case 0x02c0:
+        /* DIR1: Device Interrupt Request Register, CPU1.  */
+        ret = s->cchip.dim[1] & s->cchip.drir;
+        break;
+    case 0x0300:
+        /* DRIR: Device Raw Interrupt Request Register.  */
+        ret = s->cchip.drir;
+        break;
+
+    case 0x0340:
+        /* PRBEN: Probe Enable Register.  */
+        break;
+
+    case 0x0380:
+        /* IIC0: Interval Ignore Count Register, CPU0.  */
+        ret = s->cchip.iic[0];
+        break;
+    case 0x03c0:
+        /* IIC1: Interval Ignore Count Register, CPU1.  */
+        ret = s->cchip.iic[1];
+        break;
+
+    case 0x0400: /* MPR0 */
+    case 0x0440: /* MPR1 */
+    case 0x0480: /* MPR2 */
+    case 0x04c0: /* MPR3 */
+        /* MPR: Memory Programming Register.  */
+        break;
+
+    case 0x0580:
+        /* TTR: TIGbus Timing Register.  */
+        /* All sorts of stuff related to interrupt delivery timings.  */
+        break;
+    case 0x05c0:
+        /* TDR: TIGbug Device Timing Register.  */
+        break;
+
+    case 0x0600:
+        /* DIM2: Device Interrupt Mask Register, CPU2.  */
+        ret = s->cchip.dim[2];
+        break;
+    case 0x0640:
+        /* DIM3: Device Interrupt Mask Register, CPU3.  */
+        ret = s->cchip.dim[3];
+        break;
+    case 0x0680:
+        /* DIR2: Device Interrupt Request Register, CPU2.  */
+        ret = s->cchip.dim[2] & s->cchip.drir;
+        break;
+    case 0x06c0:
+        /* DIR3: Device Interrupt Request Register, CPU3.  */
+        ret = s->cchip.dim[3] & s->cchip.drir;
+        break;
+
+    case 0x0700:
+        /* IIC2: Interval Ignore Count Register, CPU2.  */
+        ret = s->cchip.iic[2];
+        break;
+    case 0x0740:
+        /* IIC3: Interval Ignore Count Register, CPU3.  */
+        ret = s->cchip.iic[3];
+        break;
+
+    case 0x0780:
+        /* PWR: Power Management Control.   */
+        break;
+    
+    case 0x0c00: /* CMONCTLA */
+    case 0x0c40: /* CMONCTLB */
+    case 0x0c80: /* CMONCNT01 */
+    case 0x0cc0: /* CMONCNT23 */
+        break;
+
+    default:
+        cpu_unassigned_access(cpu_single_env, addr, 0, 0, 0, size);
+        return -1;
+    }
+
+    s->latch_tmp = ret >> 32;
+    return ret;
+}
+
+static uint64_t dchip_read(void *opaque, hwaddr addr, unsigned size)
+{
+    /* Skip this.  It's all related to DRAM timing and setup.  */
+    return 0;
+}
+
+static uint64_t pchip_read(void *opaque, hwaddr addr, unsigned size)
+{
+    TyphoonState *s = opaque;
+    uint64_t ret = 0;
+
+    if (addr & 4) {
+        return s->latch_tmp;
+    }
+
+    switch (addr) {
+    case 0x0000:
+        /* WSBA0: Window Space Base Address Register.  */
+        ret = s->pchip.win[0].base_addr;
+        break;
+    case 0x0040:
+        /* WSBA1 */
+        ret = s->pchip.win[1].base_addr;
+        break;
+    case 0x0080:
+        /* WSBA2 */
+        ret = s->pchip.win[2].base_addr;
+        break;
+    case 0x00c0:
+        /* WSBA3 */
+        ret = s->pchip.win[3].base_addr;
+        break;
+
+    case 0x0100:
+        /* WSM0: Window Space Mask Register.  */
+        ret = s->pchip.win[0].mask;
+        break;
+    case 0x0140:
+        /* WSM1 */
+        ret = s->pchip.win[1].mask;
+        break;
+    case 0x0180:
+        /* WSM2 */
+        ret = s->pchip.win[2].mask;
+        break;
+    case 0x01c0:
+        /* WSM3 */
+        ret = s->pchip.win[3].mask;
+        break;
+
+    case 0x0200:
+        /* TBA0: Translated Base Address Register.  */
+        ret = (uint64_t)s->pchip.win[0].translated_base_pfn << 10;
+        break;
+    case 0x0240:
+        /* TBA1 */
+        ret = (uint64_t)s->pchip.win[1].translated_base_pfn << 10;
+        break;
+    case 0x0280:
+        /* TBA2 */
+        ret = (uint64_t)s->pchip.win[2].translated_base_pfn << 10;
+        break;
+    case 0x02c0:
+        /* TBA3 */
+        ret = (uint64_t)s->pchip.win[3].translated_base_pfn << 10;
+        break;
+
+    case 0x0300:
+        /* PCTL: Pchip Control Register.  */
+        ret = s->pchip.ctl;
+        break;
+    case 0x0340:
+        /* PLAT: Pchip Master Latency Register.  */
+        break;
+    case 0x03c0:
+        /* PERROR: Pchip Error Register.  */
+        break;
+    case 0x0400:
+        /* PERRMASK: Pchip Error Mask Register.  */
+        break;
+    case 0x0440:
+        /* PERRSET: Pchip Error Set Register.  */
+        break;
+    case 0x0480:
+        /* TLBIV: Translation Buffer Invalidate Virtual Register (WO).  */
+        break;
+    case 0x04c0:
+        /* TLBIA: Translation Buffer Invalidate All Register (WO).  */
+        break;
+    case 0x0500: /* PMONCTL */
+    case 0x0540: /* PMONCNT */
+    case 0x0800: /* SPRST */
+        break;
+
+    default:
+        cpu_unassigned_access(cpu_single_env, addr, 0, 0, 0, size);
+        return -1;
+    }
+
+    s->latch_tmp = ret >> 32;
+    return ret;
+}
+
+static void cchip_write(void *opaque, hwaddr addr,
+                        uint64_t v32, unsigned size)
+{
+    TyphoonState *s = opaque;
+    uint64_t val, oldval, newval;
+
+    if (addr & 4) {
+        val = v32 << 32 | s->latch_tmp;
+        addr ^= 4;
+    } else {
+        s->latch_tmp = v32;
+        return;
+    }
+
+    switch (addr) {
+    case 0x0000:
+        /* CSC: Cchip System Configuration Register.  */
+        /* All sorts of data here; nothing relevant RW.  */
+        break;
+
+    case 0x0040:
+        /* MTR: Memory Timing Register.  */
+        /* All sorts of stuff related to real DRAM.  */
+        break;
+
+    case 0x0080:
+        /* MISC: Miscellaneous Register.  */
+        newval = oldval = s->cchip.misc;
+        newval &= ~(val & 0x10000ff0);     /* W1C fields */
+        if (val & 0x100000) {
+            newval &= ~0xff0000ull;        /* ACL clears ABT and ABW */
+        } else {
+            newval |= val & 0x00f00000;    /* ABT field is W1S */
+            if ((newval & 0xf0000) == 0) {
+                newval |= val & 0xf0000;   /* ABW field is W1S iff zero */
+            }
+        }
+        newval |= (val & 0xf000) >> 4;     /* IPREQ field sets IPINTR.  */
+
+        newval &= ~0xf0000000000ull;       /* WO and RW fields */
+        newval |= val & 0xf0000000000ull;
+        s->cchip.misc = newval;
+
+        /* Pass on changes to IPI and ITI state.  */
+        if ((newval ^ oldval) & 0xff0) {
+            int i;
+            for (i = 0; i < 4; ++i) {
+                AlphaCPU *cpu = s->cchip.cpu[i];
+                if (cpu != NULL) {
+                    CPUState *cs = CPU(cpu);
+                    /* IPI can be either cleared or set by the write.  */
+                    if (newval & (1 << (i + 8))) {
+                        cpu_interrupt(cs, CPU_INTERRUPT_SMP);
+                    } else {
+                        cpu_reset_interrupt(cs, CPU_INTERRUPT_SMP);
+                    }
+
+                    /* ITI can only be cleared by the write.  */
+                    if ((newval & (1 << (i + 4))) == 0) {
+                        cpu_reset_interrupt(cs, CPU_INTERRUPT_TIMER);
+                    }
+                }
+            }
+        }
+        break;
+
+    case 0x00c0:
+        /* MPD: Memory Presence Detect Register.  */
+        break;
+
+    case 0x0100: /* AAR0 */
+    case 0x0140: /* AAR1 */
+    case 0x0180: /* AAR2 */
+    case 0x01c0: /* AAR3 */
+        /* AAR: Array Address Register.  */
+        /* All sorts of information about DRAM.  */
+        break;
+
+    case 0x0200: /* DIM0 */
+        /* DIM: Device Interrupt Mask Register, CPU0.  */
+        s->cchip.dim[0] = val;
+        cpu_irq_change(s->cchip.cpu[0], val & s->cchip.drir);
+        break;
+    case 0x0240: /* DIM1 */
+        /* DIM: Device Interrupt Mask Register, CPU1.  */
+        s->cchip.dim[0] = val;
+        cpu_irq_change(s->cchip.cpu[1], val & s->cchip.drir);
+        break;
+
+    case 0x0280: /* DIR0 (RO) */
+    case 0x02c0: /* DIR1 (RO) */
+    case 0x0300: /* DRIR (RO) */
+        break;
+
+    case 0x0340:
+        /* PRBEN: Probe Enable Register.  */
+        break;
+
+    case 0x0380: /* IIC0 */
+        s->cchip.iic[0] = val & 0xffffff;
+        break;
+    case 0x03c0: /* IIC1 */
+        s->cchip.iic[1] = val & 0xffffff;
+        break;
+
+    case 0x0400: /* MPR0 */
+    case 0x0440: /* MPR1 */
+    case 0x0480: /* MPR2 */
+    case 0x04c0: /* MPR3 */
+        /* MPR: Memory Programming Register.  */
+        break;
+
+    case 0x0580:
+        /* TTR: TIGbus Timing Register.  */
+        /* All sorts of stuff related to interrupt delivery timings.  */
+        break;
+    case 0x05c0:
+        /* TDR: TIGbug Device Timing Register.  */
+        break;
+
+    case 0x0600:
+        /* DIM2: Device Interrupt Mask Register, CPU2.  */
+        s->cchip.dim[2] = val;
+        cpu_irq_change(s->cchip.cpu[2], val & s->cchip.drir);
+        break;
+    case 0x0640:
+        /* DIM3: Device Interrupt Mask Register, CPU3.  */
+        s->cchip.dim[3] = val;
+        cpu_irq_change(s->cchip.cpu[3], val & s->cchip.drir);
+        break;
+
+    case 0x0680: /* DIR2 (RO) */
+    case 0x06c0: /* DIR3 (RO) */
+        break;
+
+    case 0x0700: /* IIC2 */
+        s->cchip.iic[2] = val & 0xffffff;
+        break;
+    case 0x0740: /* IIC3 */
+        s->cchip.iic[3] = val & 0xffffff;
+        break;
+
+    case 0x0780:
+        /* PWR: Power Management Control.   */
+        break;
+    
+    case 0x0c00: /* CMONCTLA */
+    case 0x0c40: /* CMONCTLB */
+    case 0x0c80: /* CMONCNT01 */
+    case 0x0cc0: /* CMONCNT23 */
+        break;
+
+    default:
+        cpu_unassigned_access(cpu_single_env, addr, 1, 0, 0, size);
+        return;
+    }
+}
+
+static void dchip_write(void *opaque, hwaddr addr,
+                        uint64_t val, unsigned size)
+{
+    /* Skip this.  It's all related to DRAM timing and setup.  */
+}
+
+static void pchip_write(void *opaque, hwaddr addr,
+                        uint64_t v32, unsigned size)
+{
+    TyphoonState *s = opaque;
+    uint64_t val, oldval;
+
+    if (addr & 4) {
+        val = v32 << 32 | s->latch_tmp;
+        addr ^= 4;
+    } else {
+        s->latch_tmp = v32;
+        return;
+    }
+
+    switch (addr) {
+    case 0x0000:
+        /* WSBA0: Window Space Base Address Register.  */
+        s->pchip.win[0].base_addr = val;
+        break;
+    case 0x0040:
+        /* WSBA1 */
+        s->pchip.win[1].base_addr = val;
+        break;
+    case 0x0080:
+        /* WSBA2 */
+        s->pchip.win[2].base_addr = val;
+        break;
+    case 0x00c0:
+        /* WSBA3 */
+        s->pchip.win[3].base_addr = val;
+        break;
+
+    case 0x0100:
+        /* WSM0: Window Space Mask Register.  */
+        s->pchip.win[0].mask = val;
+        break;
+    case 0x0140:
+        /* WSM1 */
+        s->pchip.win[1].mask = val;
+        break;
+    case 0x0180:
+        /* WSM2 */
+        s->pchip.win[2].mask = val;
+        break;
+    case 0x01c0:
+        /* WSM3 */
+        s->pchip.win[3].mask = val;
+        break;
+
+    case 0x0200:
+        /* TBA0: Translated Base Address Register.  */
+        s->pchip.win[0].translated_base_pfn = val >> 10;
+        break;
+    case 0x0240:
+        /* TBA1 */
+        s->pchip.win[1].translated_base_pfn = val >> 10;
+        break;
+    case 0x0280:
+        /* TBA2 */
+        s->pchip.win[2].translated_base_pfn = val >> 10;
+        break;
+    case 0x02c0:
+        /* TBA3 */
+        s->pchip.win[3].translated_base_pfn = val >> 10;
+        break;
+
+    case 0x0300:
+        /* PCTL: Pchip Control Register.  */
+        oldval = s->pchip.ctl;
+        oldval &= ~0x00001cff0fc7ffull;       /* RW fields */
+        oldval |= val & 0x00001cff0fc7ffull;
+
+        s->pchip.ctl = oldval;
+        break;
+
+    case 0x0340:
+        /* PLAT: Pchip Master Latency Register.  */
+        break;
+    case 0x03c0:
+        /* PERROR: Pchip Error Register.  */
+        break;
+    case 0x0400:
+        /* PERRMASK: Pchip Error Mask Register.  */
+        break;
+    case 0x0440:
+        /* PERRSET: Pchip Error Set Register.  */
+        break;
+
+    case 0x0480:
+        /* TLBIV: Translation Buffer Invalidate Virtual Register.  */
+        break;
+
+    case 0x04c0:
+        /* TLBIA: Translation Buffer Invalidate All Register (WO).  */
+        break;
+
+    case 0x0500:
+        /* PMONCTL */
+    case 0x0540:
+        /* PMONCNT */
+    case 0x0800:
+        /* SPRST */
+        break;
+
+    default:
+        cpu_unassigned_access(cpu_single_env, addr, 1, 0, 0, size);
+        return;
+    }
+}
+
+static const MemoryRegionOps cchip_ops = {
+    .read = cchip_read,
+    .write = cchip_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,  /* ??? Should be 8.  */
+        .max_access_size = 8,
+    },
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static const MemoryRegionOps dchip_ops = {
+    .read = dchip_read,
+    .write = dchip_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,  /* ??? Should be 8.  */
+        .max_access_size = 8,
+    },
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 8,
+    },
+};
+
+static const MemoryRegionOps pchip_ops = {
+    .read = pchip_read,
+    .write = pchip_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,  /* ??? Should be 8.  */
+        .max_access_size = 8,
+    },
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static void typhoon_set_irq(void *opaque, int irq, int level)
+{
+    TyphoonState *s = opaque;
+    uint64_t drir;
+    int i;
+
+    /* Set/Reset the bit in CCHIP.DRIR based on IRQ+LEVEL.  */
+    drir = s->cchip.drir;
+    if (level) {
+        drir |= 1ull << irq;
+    } else {
+        drir &= ~(1ull << irq);
+    }
+    s->cchip.drir = drir;
+
+    for (i = 0; i < 4; ++i) {
+        cpu_irq_change(s->cchip.cpu[i], s->cchip.dim[i] & drir);
+    }
+}
+
+static void typhoon_set_isa_irq(void *opaque, int irq, int level)
+{
+    typhoon_set_irq(opaque, 55, level);
+}
+
+static void typhoon_set_timer_irq(void *opaque, int irq, int level)
+{
+    TyphoonState *s = opaque;
+    int i;
+
+    /* Thankfully, the mc146818rtc code doesn't track the IRQ state,
+       and so we don't have to worry about missing interrupts just
+       because we never actually ACK the interrupt.  Just ignore any
+       case of the interrupt level going low.  */
+    if (level == 0) {
+        return;
+    }
+
+    /* Deliver the interrupt to each CPU, considering each CPU's IIC.  */
+    for (i = 0; i < 4; ++i) {
+        AlphaCPU *cpu = s->cchip.cpu[i];
+        if (cpu != NULL) {
+            uint32_t iic = s->cchip.iic[i];
+
+            /* ??? The verbage in Section 10.2.2.10 isn't 100% clear.
+               Bit 24 is the OverFlow bit, RO, and set when the count
+               decrements past 0.  When is OF cleared?  My guess is that
+               OF is actually cleared when the IIC is written, and that
+               the ICNT field always decrements.  At least, that's an
+               interpretation that makes sense, and "allows the CPU to
+               determine exactly how mant interval timer ticks were
+               skipped".  At least within the next 4M ticks...  */
+
+            iic = ((iic - 1) & 0x1ffffff) | (iic & 0x1000000);
+            s->cchip.iic[i] = iic;
+
+            if (iic & 0x1000000) {
+                /* Set the ITI bit for this cpu.  */
+                s->cchip.misc |= 1 << (i + 4);
+                /* And signal the interrupt.  */
+                cpu_interrupt(CPU(cpu), CPU_INTERRUPT_TIMER);
+            }
+        }
+    }
+}
+
+static void typhoon_alarm_timer(void *opaque)
+{
+    TyphoonState *s = (TyphoonState *)((uintptr_t)opaque & ~3);
+    int cpu = (uintptr_t)opaque & 3;
+
+    /* Set the ITI bit for this cpu.  */
+    s->cchip.misc |= 1 << (cpu + 4);
+    cpu_interrupt(CPU(s->cchip.cpu[cpu]), CPU_INTERRUPT_TIMER);
+}
+
+PCIBus *typhoon_init(ram_addr_t ram_size, ISABus **isa_bus,
+                     qemu_irq *p_rtc_irq,
+                     AlphaCPU *cpus[4], pci_map_irq_fn sys_map_irq)
+{
+    const uint64_t MB = 1024 * 1024;
+    const uint64_t GB = 1024 * MB;
+    MemoryRegion *addr_space = get_system_memory();
+    MemoryRegion *addr_space_io = get_system_io();
+    DeviceState *dev;
+    TyphoonState *s;
+    PCIHostState *phb;
+    PCIBus *b;
+    int i;
+
+    dev = qdev_create(NULL, TYPE_TYPHOON_PCI_HOST_BRIDGE);
+    qdev_init_nofail(dev);
+
+    s = TYPHOON_PCI_HOST_BRIDGE(dev);
+    phb = PCI_HOST_BRIDGE(dev);
+
+    /* Remember the CPUs so that we can deliver interrupts to them.  */
+    for (i = 0; i < 4; i++) {
+        AlphaCPU *cpu = cpus[i];
+        s->cchip.cpu[i] = cpu;
+        if (cpu != NULL) {
+            cpu->alarm_timer = qemu_new_timer_ns(rtc_clock,
+                                                 typhoon_alarm_timer,
+                                                 (void *)((uintptr_t)s + i));
+        }
+    }
+
+    *p_rtc_irq = *qemu_allocate_irqs(typhoon_set_timer_irq, s, 1);
+
+    /* Main memory region, 0x00.0000.0000.  Real hardware supports 32GB,
+       but the address space hole reserved at this point is 8TB.  */
+    memory_region_init_ram(&s->ram_region, "ram", ram_size);
+    vmstate_register_ram_global(&s->ram_region);
+    memory_region_add_subregion(addr_space, 0, &s->ram_region);
+
+    /* TIGbus, 0x801.0000.0000, 1GB.  */
+    /* ??? The TIGbus is used for delivering interrupts, and access to
+       the flash ROM.  I'm not sure that we need to implement it at all.  */
+
+    /* Pchip0 CSRs, 0x801.8000.0000, 256MB.  */
+    memory_region_init_io(&s->pchip.region, &pchip_ops, s, "pchip0", 256*MB);
+    memory_region_add_subregion(addr_space, 0x80180000000ULL,
+                                &s->pchip.region);
+
+    /* Cchip CSRs, 0x801.A000.0000, 256MB.  */
+    memory_region_init_io(&s->cchip.region, &cchip_ops, s, "cchip0", 256*MB);
+    memory_region_add_subregion(addr_space, 0x801a0000000ULL,
+                                &s->cchip.region);
+
+    /* Dchip CSRs, 0x801.B000.0000, 256MB.  */
+    memory_region_init_io(&s->dchip_region, &dchip_ops, s, "dchip0", 256*MB);
+    memory_region_add_subregion(addr_space, 0x801b0000000ULL,
+                                &s->dchip_region);
+
+    /* Pchip0 PCI memory, 0x800.0000.0000, 4GB.  */
+    memory_region_init(&s->pchip.reg_mem, "pci0-mem", 4*GB);
+    memory_region_add_subregion(addr_space, 0x80000000000ULL,
+                                &s->pchip.reg_mem);
+
+    /* Pchip0 PCI I/O, 0x801.FC00.0000, 32MB.  */
+    /* ??? Ideally we drop the "system" i/o space on the floor and give the
+       PCI subsystem the full address space reserved by the chipset.
+       We can't do that until the MEM and IO paths in memory.c are unified.  */
+    memory_region_init_io(&s->pchip.reg_io, &alpha_pci_bw_io_ops, NULL,
+                          "pci0-io", 32*MB);
+    memory_region_add_subregion(addr_space, 0x801fc000000ULL,
+                                &s->pchip.reg_io);
+
+    b = pci_register_bus(dev, "pci",
+                         typhoon_set_irq, sys_map_irq, s,
+                         &s->pchip.reg_mem, addr_space_io, 0, 64, TYPE_PCI_BUS);
+    phb->bus = b;
+
+    /* Pchip0 PCI special/interrupt acknowledge, 0x801.F800.0000, 64MB.  */
+    memory_region_init_io(&s->pchip.reg_iack, &alpha_pci_iack_ops, b,
+                          "pci0-iack", 64*MB);
+    memory_region_add_subregion(addr_space, 0x801f8000000ULL,
+                                &s->pchip.reg_iack);
+
+    /* Pchip0 PCI configuration, 0x801.FE00.0000, 16MB.  */
+    memory_region_init_io(&s->pchip.reg_conf, &alpha_pci_conf1_ops, b,
+                          "pci0-conf", 16*MB);
+    memory_region_add_subregion(addr_space, 0x801fe000000ULL,
+                                &s->pchip.reg_conf);
+
+    /* For the record, these are the mappings for the second PCI bus.
+       We can get away with not implementing them because we indicate
+       via the Cchip.CSC<PIP> bit that Pchip1 is not present.  */
+    /* Pchip1 PCI memory, 0x802.0000.0000, 4GB.  */
+    /* Pchip1 CSRs, 0x802.8000.0000, 256MB.  */
+    /* Pchip1 PCI special/interrupt acknowledge, 0x802.F800.0000, 64MB.  */
+    /* Pchip1 PCI I/O, 0x802.FC00.0000, 32MB.  */
+    /* Pchip1 PCI configuration, 0x802.FE00.0000, 16MB.  */
+
+    /* Init the ISA bus.  */
+    /* ??? Technically there should be a cy82c693ub pci-isa bridge.  */
+    {
+        qemu_irq isa_pci_irq, *isa_irqs;
+
+        *isa_bus = isa_bus_new(NULL, addr_space_io);
+        isa_pci_irq = *qemu_allocate_irqs(typhoon_set_isa_irq, s, 1);
+        isa_irqs = i8259_init(*isa_bus, isa_pci_irq);
+        isa_bus_irqs(*isa_bus, isa_irqs);
+    }
+
+    return b;
+}
+
+static int typhoon_pcihost_init(SysBusDevice *dev)
+{
+    return 0;
+}
+
+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 const TypeInfo typhoon_pcihost_info = {
+    .name          = TYPE_TYPHOON_PCI_HOST_BRIDGE,
+    .parent        = TYPE_PCI_HOST_BRIDGE,
+    .instance_size = sizeof(TyphoonState),
+    .class_init    = typhoon_pcihost_class_init,
+};
+
+static void typhoon_register_types(void)
+{
+    type_register_static(&typhoon_pcihost_info);
+}
+
+type_init(typhoon_register_types)
diff --git a/hw/alpha_sys.h b/hw/alpha_sys.h
deleted file mode 100644 (file)
index b4ebd2a..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-/* Alpha cores and system support chips.  */
-
-#ifndef HW_ALPHA_H
-#define HW_ALPHA_H 1
-
-#include "hw/pci/pci.h"
-#include "hw/pci/pci_host.h"
-#include "hw/ide.h"
-#include "hw/pc.h"
-#include "hw/irq.h"
-
-
-PCIBus *typhoon_init(ram_addr_t, ISABus **, qemu_irq *, AlphaCPU *[4],
-                     pci_map_irq_fn);
-
-/* alpha_pci.c.  */
-extern const MemoryRegionOps alpha_pci_bw_io_ops;
-extern const MemoryRegionOps alpha_pci_conf1_ops;
-extern const MemoryRegionOps alpha_pci_iack_ops;
-
-#endif
diff --git a/hw/alpha_typhoon.c b/hw/alpha_typhoon.c
deleted file mode 100644 (file)
index b1e0044..0000000
+++ /dev/null
@@ -1,842 +0,0 @@
-/*
- * DEC 21272 (TSUNAMI/TYPHOON) chipset emulation.
- *
- * Written by Richard Henderson.
- *
- * This work is licensed under the GNU GPL license version 2 or later.
- */
-
-#include "cpu.h"
-#include "exec/exec-all.h"
-#include "hw/hw.h"
-#include "hw/devices.h"
-#include "sysemu/sysemu.h"
-#include "hw/alpha_sys.h"
-#include "exec/address-spaces.h"
-
-
-#define TYPE_TYPHOON_PCI_HOST_BRIDGE "typhoon-pcihost"
-
-typedef struct TyphoonCchip {
-    MemoryRegion region;
-    uint64_t misc;
-    uint64_t drir;
-    uint64_t dim[4];
-    uint32_t iic[4];
-    AlphaCPU *cpu[4];
-} TyphoonCchip;
-
-typedef struct TyphoonWindow {
-    uint32_t base_addr;
-    uint32_t mask;
-    uint32_t translated_base_pfn;
-} TyphoonWindow;
-typedef struct TyphoonPchip {
-    MemoryRegion region;
-    MemoryRegion reg_iack;
-    MemoryRegion reg_mem;
-    MemoryRegion reg_io;
-    MemoryRegion reg_conf;
-    uint64_t ctl;
-    TyphoonWindow win[4];
-} TyphoonPchip;
-
-#define TYPHOON_PCI_HOST_BRIDGE(obj) \
-    OBJECT_CHECK(TyphoonState, (obj), TYPE_TYPHOON_PCI_HOST_BRIDGE)
-
-typedef struct TyphoonState {
-    PCIHostState parent_obj;
-
-    TyphoonCchip cchip;
-    TyphoonPchip pchip;
-    MemoryRegion dchip_region;
-    MemoryRegion ram_region;
-
-    /* QEMU emulation state.  */
-    uint32_t latch_tmp;
-} TyphoonState;
-
-/* Called when one of DRIR or DIM changes.  */
-static void cpu_irq_change(AlphaCPU *cpu, uint64_t req)
-{
-    /* If there are any non-masked interrupts, tell the cpu.  */
-    if (cpu != NULL) {
-        CPUState *cs = CPU(cpu);
-        if (req) {
-            cpu_interrupt(cs, CPU_INTERRUPT_HARD);
-        } else {
-            cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
-        }
-    }
-}
-
-static uint64_t cchip_read(void *opaque, hwaddr addr, unsigned size)
-{
-    CPUAlphaState *env = cpu_single_env;
-    TyphoonState *s = opaque;
-    CPUState *cpu;
-    uint64_t ret = 0;
-
-    if (addr & 4) {
-        return s->latch_tmp;
-    }
-
-    switch (addr) {
-    case 0x0000:
-        /* CSC: Cchip System Configuration Register.  */
-        /* All sorts of data here; probably the only thing relevant is
-           PIP<14> Pchip 1 Present = 0.  */
-        break;
-
-    case 0x0040:
-        /* MTR: Memory Timing Register.  */
-        /* All sorts of stuff related to real DRAM.  */
-        break;
-
-    case 0x0080:
-        /* MISC: Miscellaneous Register.  */
-        cpu = ENV_GET_CPU(env);
-        ret = s->cchip.misc | (cpu->cpu_index & 3);
-        break;
-
-    case 0x00c0:
-        /* MPD: Memory Presence Detect Register.  */
-        break;
-
-    case 0x0100: /* AAR0 */
-    case 0x0140: /* AAR1 */
-    case 0x0180: /* AAR2 */
-    case 0x01c0: /* AAR3 */
-        /* AAR: Array Address Register.  */
-        /* All sorts of information about DRAM.  */
-        break;
-
-    case 0x0200:
-        /* DIM0: Device Interrupt Mask Register, CPU0.  */
-        ret = s->cchip.dim[0];
-        break;
-    case 0x0240:
-        /* DIM1: Device Interrupt Mask Register, CPU1.  */
-        ret = s->cchip.dim[1];
-        break;
-    case 0x0280:
-        /* DIR0: Device Interrupt Request Register, CPU0.  */
-        ret = s->cchip.dim[0] & s->cchip.drir;
-        break;
-    case 0x02c0:
-        /* DIR1: Device Interrupt Request Register, CPU1.  */
-        ret = s->cchip.dim[1] & s->cchip.drir;
-        break;
-    case 0x0300:
-        /* DRIR: Device Raw Interrupt Request Register.  */
-        ret = s->cchip.drir;
-        break;
-
-    case 0x0340:
-        /* PRBEN: Probe Enable Register.  */
-        break;
-
-    case 0x0380:
-        /* IIC0: Interval Ignore Count Register, CPU0.  */
-        ret = s->cchip.iic[0];
-        break;
-    case 0x03c0:
-        /* IIC1: Interval Ignore Count Register, CPU1.  */
-        ret = s->cchip.iic[1];
-        break;
-
-    case 0x0400: /* MPR0 */
-    case 0x0440: /* MPR1 */
-    case 0x0480: /* MPR2 */
-    case 0x04c0: /* MPR3 */
-        /* MPR: Memory Programming Register.  */
-        break;
-
-    case 0x0580:
-        /* TTR: TIGbus Timing Register.  */
-        /* All sorts of stuff related to interrupt delivery timings.  */
-        break;
-    case 0x05c0:
-        /* TDR: TIGbug Device Timing Register.  */
-        break;
-
-    case 0x0600:
-        /* DIM2: Device Interrupt Mask Register, CPU2.  */
-        ret = s->cchip.dim[2];
-        break;
-    case 0x0640:
-        /* DIM3: Device Interrupt Mask Register, CPU3.  */
-        ret = s->cchip.dim[3];
-        break;
-    case 0x0680:
-        /* DIR2: Device Interrupt Request Register, CPU2.  */
-        ret = s->cchip.dim[2] & s->cchip.drir;
-        break;
-    case 0x06c0:
-        /* DIR3: Device Interrupt Request Register, CPU3.  */
-        ret = s->cchip.dim[3] & s->cchip.drir;
-        break;
-
-    case 0x0700:
-        /* IIC2: Interval Ignore Count Register, CPU2.  */
-        ret = s->cchip.iic[2];
-        break;
-    case 0x0740:
-        /* IIC3: Interval Ignore Count Register, CPU3.  */
-        ret = s->cchip.iic[3];
-        break;
-
-    case 0x0780:
-        /* PWR: Power Management Control.   */
-        break;
-    
-    case 0x0c00: /* CMONCTLA */
-    case 0x0c40: /* CMONCTLB */
-    case 0x0c80: /* CMONCNT01 */
-    case 0x0cc0: /* CMONCNT23 */
-        break;
-
-    default:
-        cpu_unassigned_access(cpu_single_env, addr, 0, 0, 0, size);
-        return -1;
-    }
-
-    s->latch_tmp = ret >> 32;
-    return ret;
-}
-
-static uint64_t dchip_read(void *opaque, hwaddr addr, unsigned size)
-{
-    /* Skip this.  It's all related to DRAM timing and setup.  */
-    return 0;
-}
-
-static uint64_t pchip_read(void *opaque, hwaddr addr, unsigned size)
-{
-    TyphoonState *s = opaque;
-    uint64_t ret = 0;
-
-    if (addr & 4) {
-        return s->latch_tmp;
-    }
-
-    switch (addr) {
-    case 0x0000:
-        /* WSBA0: Window Space Base Address Register.  */
-        ret = s->pchip.win[0].base_addr;
-        break;
-    case 0x0040:
-        /* WSBA1 */
-        ret = s->pchip.win[1].base_addr;
-        break;
-    case 0x0080:
-        /* WSBA2 */
-        ret = s->pchip.win[2].base_addr;
-        break;
-    case 0x00c0:
-        /* WSBA3 */
-        ret = s->pchip.win[3].base_addr;
-        break;
-
-    case 0x0100:
-        /* WSM0: Window Space Mask Register.  */
-        ret = s->pchip.win[0].mask;
-        break;
-    case 0x0140:
-        /* WSM1 */
-        ret = s->pchip.win[1].mask;
-        break;
-    case 0x0180:
-        /* WSM2 */
-        ret = s->pchip.win[2].mask;
-        break;
-    case 0x01c0:
-        /* WSM3 */
-        ret = s->pchip.win[3].mask;
-        break;
-
-    case 0x0200:
-        /* TBA0: Translated Base Address Register.  */
-        ret = (uint64_t)s->pchip.win[0].translated_base_pfn << 10;
-        break;
-    case 0x0240:
-        /* TBA1 */
-        ret = (uint64_t)s->pchip.win[1].translated_base_pfn << 10;
-        break;
-    case 0x0280:
-        /* TBA2 */
-        ret = (uint64_t)s->pchip.win[2].translated_base_pfn << 10;
-        break;
-    case 0x02c0:
-        /* TBA3 */
-        ret = (uint64_t)s->pchip.win[3].translated_base_pfn << 10;
-        break;
-
-    case 0x0300:
-        /* PCTL: Pchip Control Register.  */
-        ret = s->pchip.ctl;
-        break;
-    case 0x0340:
-        /* PLAT: Pchip Master Latency Register.  */
-        break;
-    case 0x03c0:
-        /* PERROR: Pchip Error Register.  */
-        break;
-    case 0x0400:
-        /* PERRMASK: Pchip Error Mask Register.  */
-        break;
-    case 0x0440:
-        /* PERRSET: Pchip Error Set Register.  */
-        break;
-    case 0x0480:
-        /* TLBIV: Translation Buffer Invalidate Virtual Register (WO).  */
-        break;
-    case 0x04c0:
-        /* TLBIA: Translation Buffer Invalidate All Register (WO).  */
-        break;
-    case 0x0500: /* PMONCTL */
-    case 0x0540: /* PMONCNT */
-    case 0x0800: /* SPRST */
-        break;
-
-    default:
-        cpu_unassigned_access(cpu_single_env, addr, 0, 0, 0, size);
-        return -1;
-    }
-
-    s->latch_tmp = ret >> 32;
-    return ret;
-}
-
-static void cchip_write(void *opaque, hwaddr addr,
-                        uint64_t v32, unsigned size)
-{
-    TyphoonState *s = opaque;
-    uint64_t val, oldval, newval;
-
-    if (addr & 4) {
-        val = v32 << 32 | s->latch_tmp;
-        addr ^= 4;
-    } else {
-        s->latch_tmp = v32;
-        return;
-    }
-
-    switch (addr) {
-    case 0x0000:
-        /* CSC: Cchip System Configuration Register.  */
-        /* All sorts of data here; nothing relevant RW.  */
-        break;
-
-    case 0x0040:
-        /* MTR: Memory Timing Register.  */
-        /* All sorts of stuff related to real DRAM.  */
-        break;
-
-    case 0x0080:
-        /* MISC: Miscellaneous Register.  */
-        newval = oldval = s->cchip.misc;
-        newval &= ~(val & 0x10000ff0);     /* W1C fields */
-        if (val & 0x100000) {
-            newval &= ~0xff0000ull;        /* ACL clears ABT and ABW */
-        } else {
-            newval |= val & 0x00f00000;    /* ABT field is W1S */
-            if ((newval & 0xf0000) == 0) {
-                newval |= val & 0xf0000;   /* ABW field is W1S iff zero */
-            }
-        }
-        newval |= (val & 0xf000) >> 4;     /* IPREQ field sets IPINTR.  */
-
-        newval &= ~0xf0000000000ull;       /* WO and RW fields */
-        newval |= val & 0xf0000000000ull;
-        s->cchip.misc = newval;
-
-        /* Pass on changes to IPI and ITI state.  */
-        if ((newval ^ oldval) & 0xff0) {
-            int i;
-            for (i = 0; i < 4; ++i) {
-                AlphaCPU *cpu = s->cchip.cpu[i];
-                if (cpu != NULL) {
-                    CPUState *cs = CPU(cpu);
-                    /* IPI can be either cleared or set by the write.  */
-                    if (newval & (1 << (i + 8))) {
-                        cpu_interrupt(cs, CPU_INTERRUPT_SMP);
-                    } else {
-                        cpu_reset_interrupt(cs, CPU_INTERRUPT_SMP);
-                    }
-
-                    /* ITI can only be cleared by the write.  */
-                    if ((newval & (1 << (i + 4))) == 0) {
-                        cpu_reset_interrupt(cs, CPU_INTERRUPT_TIMER);
-                    }
-                }
-            }
-        }
-        break;
-
-    case 0x00c0:
-        /* MPD: Memory Presence Detect Register.  */
-        break;
-
-    case 0x0100: /* AAR0 */
-    case 0x0140: /* AAR1 */
-    case 0x0180: /* AAR2 */
-    case 0x01c0: /* AAR3 */
-        /* AAR: Array Address Register.  */
-        /* All sorts of information about DRAM.  */
-        break;
-
-    case 0x0200: /* DIM0 */
-        /* DIM: Device Interrupt Mask Register, CPU0.  */
-        s->cchip.dim[0] = val;
-        cpu_irq_change(s->cchip.cpu[0], val & s->cchip.drir);
-        break;
-    case 0x0240: /* DIM1 */
-        /* DIM: Device Interrupt Mask Register, CPU1.  */
-        s->cchip.dim[0] = val;
-        cpu_irq_change(s->cchip.cpu[1], val & s->cchip.drir);
-        break;
-
-    case 0x0280: /* DIR0 (RO) */
-    case 0x02c0: /* DIR1 (RO) */
-    case 0x0300: /* DRIR (RO) */
-        break;
-
-    case 0x0340:
-        /* PRBEN: Probe Enable Register.  */
-        break;
-
-    case 0x0380: /* IIC0 */
-        s->cchip.iic[0] = val & 0xffffff;
-        break;
-    case 0x03c0: /* IIC1 */
-        s->cchip.iic[1] = val & 0xffffff;
-        break;
-
-    case 0x0400: /* MPR0 */
-    case 0x0440: /* MPR1 */
-    case 0x0480: /* MPR2 */
-    case 0x04c0: /* MPR3 */
-        /* MPR: Memory Programming Register.  */
-        break;
-
-    case 0x0580:
-        /* TTR: TIGbus Timing Register.  */
-        /* All sorts of stuff related to interrupt delivery timings.  */
-        break;
-    case 0x05c0:
-        /* TDR: TIGbug Device Timing Register.  */
-        break;
-
-    case 0x0600:
-        /* DIM2: Device Interrupt Mask Register, CPU2.  */
-        s->cchip.dim[2] = val;
-        cpu_irq_change(s->cchip.cpu[2], val & s->cchip.drir);
-        break;
-    case 0x0640:
-        /* DIM3: Device Interrupt Mask Register, CPU3.  */
-        s->cchip.dim[3] = val;
-        cpu_irq_change(s->cchip.cpu[3], val & s->cchip.drir);
-        break;
-
-    case 0x0680: /* DIR2 (RO) */
-    case 0x06c0: /* DIR3 (RO) */
-        break;
-
-    case 0x0700: /* IIC2 */
-        s->cchip.iic[2] = val & 0xffffff;
-        break;
-    case 0x0740: /* IIC3 */
-        s->cchip.iic[3] = val & 0xffffff;
-        break;
-
-    case 0x0780:
-        /* PWR: Power Management Control.   */
-        break;
-    
-    case 0x0c00: /* CMONCTLA */
-    case 0x0c40: /* CMONCTLB */
-    case 0x0c80: /* CMONCNT01 */
-    case 0x0cc0: /* CMONCNT23 */
-        break;
-
-    default:
-        cpu_unassigned_access(cpu_single_env, addr, 1, 0, 0, size);
-        return;
-    }
-}
-
-static void dchip_write(void *opaque, hwaddr addr,
-                        uint64_t val, unsigned size)
-{
-    /* Skip this.  It's all related to DRAM timing and setup.  */
-}
-
-static void pchip_write(void *opaque, hwaddr addr,
-                        uint64_t v32, unsigned size)
-{
-    TyphoonState *s = opaque;
-    uint64_t val, oldval;
-
-    if (addr & 4) {
-        val = v32 << 32 | s->latch_tmp;
-        addr ^= 4;
-    } else {
-        s->latch_tmp = v32;
-        return;
-    }
-
-    switch (addr) {
-    case 0x0000:
-        /* WSBA0: Window Space Base Address Register.  */
-        s->pchip.win[0].base_addr = val;
-        break;
-    case 0x0040:
-        /* WSBA1 */
-        s->pchip.win[1].base_addr = val;
-        break;
-    case 0x0080:
-        /* WSBA2 */
-        s->pchip.win[2].base_addr = val;
-        break;
-    case 0x00c0:
-        /* WSBA3 */
-        s->pchip.win[3].base_addr = val;
-        break;
-
-    case 0x0100:
-        /* WSM0: Window Space Mask Register.  */
-        s->pchip.win[0].mask = val;
-        break;
-    case 0x0140:
-        /* WSM1 */
-        s->pchip.win[1].mask = val;
-        break;
-    case 0x0180:
-        /* WSM2 */
-        s->pchip.win[2].mask = val;
-        break;
-    case 0x01c0:
-        /* WSM3 */
-        s->pchip.win[3].mask = val;
-        break;
-
-    case 0x0200:
-        /* TBA0: Translated Base Address Register.  */
-        s->pchip.win[0].translated_base_pfn = val >> 10;
-        break;
-    case 0x0240:
-        /* TBA1 */
-        s->pchip.win[1].translated_base_pfn = val >> 10;
-        break;
-    case 0x0280:
-        /* TBA2 */
-        s->pchip.win[2].translated_base_pfn = val >> 10;
-        break;
-    case 0x02c0:
-        /* TBA3 */
-        s->pchip.win[3].translated_base_pfn = val >> 10;
-        break;
-
-    case 0x0300:
-        /* PCTL: Pchip Control Register.  */
-        oldval = s->pchip.ctl;
-        oldval &= ~0x00001cff0fc7ffull;       /* RW fields */
-        oldval |= val & 0x00001cff0fc7ffull;
-
-        s->pchip.ctl = oldval;
-        break;
-
-    case 0x0340:
-        /* PLAT: Pchip Master Latency Register.  */
-        break;
-    case 0x03c0:
-        /* PERROR: Pchip Error Register.  */
-        break;
-    case 0x0400:
-        /* PERRMASK: Pchip Error Mask Register.  */
-        break;
-    case 0x0440:
-        /* PERRSET: Pchip Error Set Register.  */
-        break;
-
-    case 0x0480:
-        /* TLBIV: Translation Buffer Invalidate Virtual Register.  */
-        break;
-
-    case 0x04c0:
-        /* TLBIA: Translation Buffer Invalidate All Register (WO).  */
-        break;
-
-    case 0x0500:
-        /* PMONCTL */
-    case 0x0540:
-        /* PMONCNT */
-    case 0x0800:
-        /* SPRST */
-        break;
-
-    default:
-        cpu_unassigned_access(cpu_single_env, addr, 1, 0, 0, size);
-        return;
-    }
-}
-
-static const MemoryRegionOps cchip_ops = {
-    .read = cchip_read,
-    .write = cchip_write,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-    .valid = {
-        .min_access_size = 4,  /* ??? Should be 8.  */
-        .max_access_size = 8,
-    },
-    .impl = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-};
-
-static const MemoryRegionOps dchip_ops = {
-    .read = dchip_read,
-    .write = dchip_write,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-    .valid = {
-        .min_access_size = 4,  /* ??? Should be 8.  */
-        .max_access_size = 8,
-    },
-    .impl = {
-        .min_access_size = 4,
-        .max_access_size = 8,
-    },
-};
-
-static const MemoryRegionOps pchip_ops = {
-    .read = pchip_read,
-    .write = pchip_write,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-    .valid = {
-        .min_access_size = 4,  /* ??? Should be 8.  */
-        .max_access_size = 8,
-    },
-    .impl = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-};
-
-static void typhoon_set_irq(void *opaque, int irq, int level)
-{
-    TyphoonState *s = opaque;
-    uint64_t drir;
-    int i;
-
-    /* Set/Reset the bit in CCHIP.DRIR based on IRQ+LEVEL.  */
-    drir = s->cchip.drir;
-    if (level) {
-        drir |= 1ull << irq;
-    } else {
-        drir &= ~(1ull << irq);
-    }
-    s->cchip.drir = drir;
-
-    for (i = 0; i < 4; ++i) {
-        cpu_irq_change(s->cchip.cpu[i], s->cchip.dim[i] & drir);
-    }
-}
-
-static void typhoon_set_isa_irq(void *opaque, int irq, int level)
-{
-    typhoon_set_irq(opaque, 55, level);
-}
-
-static void typhoon_set_timer_irq(void *opaque, int irq, int level)
-{
-    TyphoonState *s = opaque;
-    int i;
-
-    /* Thankfully, the mc146818rtc code doesn't track the IRQ state,
-       and so we don't have to worry about missing interrupts just
-       because we never actually ACK the interrupt.  Just ignore any
-       case of the interrupt level going low.  */
-    if (level == 0) {
-        return;
-    }
-
-    /* Deliver the interrupt to each CPU, considering each CPU's IIC.  */
-    for (i = 0; i < 4; ++i) {
-        AlphaCPU *cpu = s->cchip.cpu[i];
-        if (cpu != NULL) {
-            uint32_t iic = s->cchip.iic[i];
-
-            /* ??? The verbage in Section 10.2.2.10 isn't 100% clear.
-               Bit 24 is the OverFlow bit, RO, and set when the count
-               decrements past 0.  When is OF cleared?  My guess is that
-               OF is actually cleared when the IIC is written, and that
-               the ICNT field always decrements.  At least, that's an
-               interpretation that makes sense, and "allows the CPU to
-               determine exactly how mant interval timer ticks were
-               skipped".  At least within the next 4M ticks...  */
-
-            iic = ((iic - 1) & 0x1ffffff) | (iic & 0x1000000);
-            s->cchip.iic[i] = iic;
-
-            if (iic & 0x1000000) {
-                /* Set the ITI bit for this cpu.  */
-                s->cchip.misc |= 1 << (i + 4);
-                /* And signal the interrupt.  */
-                cpu_interrupt(CPU(cpu), CPU_INTERRUPT_TIMER);
-            }
-        }
-    }
-}
-
-static void typhoon_alarm_timer(void *opaque)
-{
-    TyphoonState *s = (TyphoonState *)((uintptr_t)opaque & ~3);
-    int cpu = (uintptr_t)opaque & 3;
-
-    /* Set the ITI bit for this cpu.  */
-    s->cchip.misc |= 1 << (cpu + 4);
-    cpu_interrupt(CPU(s->cchip.cpu[cpu]), CPU_INTERRUPT_TIMER);
-}
-
-PCIBus *typhoon_init(ram_addr_t ram_size, ISABus **isa_bus,
-                     qemu_irq *p_rtc_irq,
-                     AlphaCPU *cpus[4], pci_map_irq_fn sys_map_irq)
-{
-    const uint64_t MB = 1024 * 1024;
-    const uint64_t GB = 1024 * MB;
-    MemoryRegion *addr_space = get_system_memory();
-    MemoryRegion *addr_space_io = get_system_io();
-    DeviceState *dev;
-    TyphoonState *s;
-    PCIHostState *phb;
-    PCIBus *b;
-    int i;
-
-    dev = qdev_create(NULL, TYPE_TYPHOON_PCI_HOST_BRIDGE);
-    qdev_init_nofail(dev);
-
-    s = TYPHOON_PCI_HOST_BRIDGE(dev);
-    phb = PCI_HOST_BRIDGE(dev);
-
-    /* Remember the CPUs so that we can deliver interrupts to them.  */
-    for (i = 0; i < 4; i++) {
-        AlphaCPU *cpu = cpus[i];
-        s->cchip.cpu[i] = cpu;
-        if (cpu != NULL) {
-            cpu->alarm_timer = qemu_new_timer_ns(rtc_clock,
-                                                 typhoon_alarm_timer,
-                                                 (void *)((uintptr_t)s + i));
-        }
-    }
-
-    *p_rtc_irq = *qemu_allocate_irqs(typhoon_set_timer_irq, s, 1);
-
-    /* Main memory region, 0x00.0000.0000.  Real hardware supports 32GB,
-       but the address space hole reserved at this point is 8TB.  */
-    memory_region_init_ram(&s->ram_region, "ram", ram_size);
-    vmstate_register_ram_global(&s->ram_region);
-    memory_region_add_subregion(addr_space, 0, &s->ram_region);
-
-    /* TIGbus, 0x801.0000.0000, 1GB.  */
-    /* ??? The TIGbus is used for delivering interrupts, and access to
-       the flash ROM.  I'm not sure that we need to implement it at all.  */
-
-    /* Pchip0 CSRs, 0x801.8000.0000, 256MB.  */
-    memory_region_init_io(&s->pchip.region, &pchip_ops, s, "pchip0", 256*MB);
-    memory_region_add_subregion(addr_space, 0x80180000000ULL,
-                                &s->pchip.region);
-
-    /* Cchip CSRs, 0x801.A000.0000, 256MB.  */
-    memory_region_init_io(&s->cchip.region, &cchip_ops, s, "cchip0", 256*MB);
-    memory_region_add_subregion(addr_space, 0x801a0000000ULL,
-                                &s->cchip.region);
-
-    /* Dchip CSRs, 0x801.B000.0000, 256MB.  */
-    memory_region_init_io(&s->dchip_region, &dchip_ops, s, "dchip0", 256*MB);
-    memory_region_add_subregion(addr_space, 0x801b0000000ULL,
-                                &s->dchip_region);
-
-    /* Pchip0 PCI memory, 0x800.0000.0000, 4GB.  */
-    memory_region_init(&s->pchip.reg_mem, "pci0-mem", 4*GB);
-    memory_region_add_subregion(addr_space, 0x80000000000ULL,
-                                &s->pchip.reg_mem);
-
-    /* Pchip0 PCI I/O, 0x801.FC00.0000, 32MB.  */
-    /* ??? Ideally we drop the "system" i/o space on the floor and give the
-       PCI subsystem the full address space reserved by the chipset.
-       We can't do that until the MEM and IO paths in memory.c are unified.  */
-    memory_region_init_io(&s->pchip.reg_io, &alpha_pci_bw_io_ops, NULL,
-                          "pci0-io", 32*MB);
-    memory_region_add_subregion(addr_space, 0x801fc000000ULL,
-                                &s->pchip.reg_io);
-
-    b = pci_register_bus(dev, "pci",
-                         typhoon_set_irq, sys_map_irq, s,
-                         &s->pchip.reg_mem, addr_space_io, 0, 64, TYPE_PCI_BUS);
-    phb->bus = b;
-
-    /* Pchip0 PCI special/interrupt acknowledge, 0x801.F800.0000, 64MB.  */
-    memory_region_init_io(&s->pchip.reg_iack, &alpha_pci_iack_ops, b,
-                          "pci0-iack", 64*MB);
-    memory_region_add_subregion(addr_space, 0x801f8000000ULL,
-                                &s->pchip.reg_iack);
-
-    /* Pchip0 PCI configuration, 0x801.FE00.0000, 16MB.  */
-    memory_region_init_io(&s->pchip.reg_conf, &alpha_pci_conf1_ops, b,
-                          "pci0-conf", 16*MB);
-    memory_region_add_subregion(addr_space, 0x801fe000000ULL,
-                                &s->pchip.reg_conf);
-
-    /* For the record, these are the mappings for the second PCI bus.
-       We can get away with not implementing them because we indicate
-       via the Cchip.CSC<PIP> bit that Pchip1 is not present.  */
-    /* Pchip1 PCI memory, 0x802.0000.0000, 4GB.  */
-    /* Pchip1 CSRs, 0x802.8000.0000, 256MB.  */
-    /* Pchip1 PCI special/interrupt acknowledge, 0x802.F800.0000, 64MB.  */
-    /* Pchip1 PCI I/O, 0x802.FC00.0000, 32MB.  */
-    /* Pchip1 PCI configuration, 0x802.FE00.0000, 16MB.  */
-
-    /* Init the ISA bus.  */
-    /* ??? Technically there should be a cy82c693ub pci-isa bridge.  */
-    {
-        qemu_irq isa_pci_irq, *isa_irqs;
-
-        *isa_bus = isa_bus_new(NULL, addr_space_io);
-        isa_pci_irq = *qemu_allocate_irqs(typhoon_set_isa_irq, s, 1);
-        isa_irqs = i8259_init(*isa_bus, isa_pci_irq);
-        isa_bus_irqs(*isa_bus, isa_irqs);
-    }
-
-    return b;
-}
-
-static int typhoon_pcihost_init(SysBusDevice *dev)
-{
-    return 0;
-}
-
-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 const TypeInfo typhoon_pcihost_info = {
-    .name          = TYPE_TYPHOON_PCI_HOST_BRIDGE,
-    .parent        = TYPE_PCI_HOST_BRIDGE,
-    .instance_size = sizeof(TyphoonState),
-    .class_init    = typhoon_pcihost_class_init,
-};
-
-static void typhoon_register_types(void)
-{
-    type_register_static(&typhoon_pcihost_info);
-}
-
-type_init(typhoon_register_types)
diff --git a/hw/apb_pci.c b/hw/apb_pci.c
deleted file mode 100644 (file)
index 754ca6c..0000000
+++ /dev/null
@@ -1,542 +0,0 @@
-/*
- * QEMU Ultrasparc APB PCI host
- *
- * Copyright (c) 2006 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.
- */
-
-/* XXX This file and most of its contents are somewhat misnamed.  The
-   Ultrasparc PCI host is called the PCI Bus Module (PBM).  The APB is
-   the secondary PCI bridge.  */
-
-#include "hw/sysbus.h"
-#include "hw/pci/pci.h"
-#include "hw/pci/pci_host.h"
-#include "hw/pci/pci_bridge.h"
-#include "hw/pci/pci_bus.h"
-#include "hw/apb_pci.h"
-#include "sysemu/sysemu.h"
-#include "exec/address-spaces.h"
-
-/* debug APB */
-//#define DEBUG_APB
-
-#ifdef DEBUG_APB
-#define APB_DPRINTF(fmt, ...) \
-do { printf("APB: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define APB_DPRINTF(fmt, ...)
-#endif
-
-/*
- * Chipset docs:
- * PBM: "UltraSPARC IIi User's Manual",
- * http://www.sun.com/processors/manuals/805-0087.pdf
- *
- * APB: "Advanced PCI Bridge (APB) User's Manual",
- * http://www.sun.com/processors/manuals/805-1251.pdf
- */
-
-#define PBM_PCI_IMR_MASK    0x7fffffff
-#define PBM_PCI_IMR_ENABLED 0x80000000
-
-#define POR          (1 << 31)
-#define SOFT_POR     (1 << 30)
-#define SOFT_XIR     (1 << 29)
-#define BTN_POR      (1 << 28)
-#define BTN_XIR      (1 << 27)
-#define RESET_MASK   0xf8000000
-#define RESET_WCMASK 0x98000000
-#define RESET_WMASK  0x60000000
-
-#define MAX_IVEC 0x30
-
-typedef struct APBState {
-    SysBusDevice busdev;
-    PCIBus      *bus;
-    MemoryRegion apb_config;
-    MemoryRegion pci_config;
-    MemoryRegion pci_mmio;
-    MemoryRegion pci_ioport;
-    uint32_t iommu[4];
-    uint32_t pci_control[16];
-    uint32_t pci_irq_map[8];
-    uint32_t obio_irq_map[32];
-    qemu_irq *pbm_irqs;
-    qemu_irq *ivec_irqs;
-    uint32_t reset_control;
-    unsigned int nr_resets;
-} APBState;
-
-static void pci_apb_set_irq(void *opaque, int irq_num, int level);
-
-static void apb_config_writel (void *opaque, hwaddr addr,
-                               uint64_t val, unsigned size)
-{
-    APBState *s = opaque;
-
-    APB_DPRINTF("%s: addr " TARGET_FMT_lx " val %" PRIx64 "\n", __func__, addr, val);
-
-    switch (addr & 0xffff) {
-    case 0x30 ... 0x4f: /* DMA error registers */
-        /* XXX: not implemented yet */
-        break;
-    case 0x200 ... 0x20b: /* IOMMU */
-        s->iommu[(addr & 0xf) >> 2] = val;
-        break;
-    case 0x20c ... 0x3ff: /* IOMMU flush */
-        break;
-    case 0xc00 ... 0xc3f: /* PCI interrupt control */
-        if (addr & 4) {
-            s->pci_irq_map[(addr & 0x3f) >> 3] &= PBM_PCI_IMR_MASK;
-            s->pci_irq_map[(addr & 0x3f) >> 3] |= val & ~PBM_PCI_IMR_MASK;
-        }
-        break;
-    case 0x1000 ... 0x1080: /* OBIO interrupt control */
-        if (addr & 4) {
-            s->obio_irq_map[(addr & 0xff) >> 3] &= PBM_PCI_IMR_MASK;
-            s->obio_irq_map[(addr & 0xff) >> 3] |= val & ~PBM_PCI_IMR_MASK;
-        }
-        break;
-    case 0x1400 ... 0x143f: /* PCI interrupt clear */
-        if (addr & 4) {
-            pci_apb_set_irq(s, (addr & 0x3f) >> 3, 0);
-        }
-        break;
-    case 0x1800 ... 0x1860: /* OBIO interrupt clear */
-        if (addr & 4) {
-            pci_apb_set_irq(s, 0x20 | ((addr & 0xff) >> 3), 0);
-        }
-        break;
-    case 0x2000 ... 0x202f: /* PCI control */
-        s->pci_control[(addr & 0x3f) >> 2] = val;
-        break;
-    case 0xf020 ... 0xf027: /* Reset control */
-        if (addr & 4) {
-            val &= RESET_MASK;
-            s->reset_control &= ~(val & RESET_WCMASK);
-            s->reset_control |= val & RESET_WMASK;
-            if (val & SOFT_POR) {
-                s->nr_resets = 0;
-                qemu_system_reset_request();
-            } else if (val & SOFT_XIR) {
-                qemu_system_reset_request();
-            }
-        }
-        break;
-    case 0x5000 ... 0x51cf: /* PIO/DMA diagnostics */
-    case 0xa400 ... 0xa67f: /* IOMMU diagnostics */
-    case 0xa800 ... 0xa80f: /* Interrupt diagnostics */
-    case 0xf000 ... 0xf01f: /* FFB config, memory control */
-        /* we don't care */
-    default:
-        break;
-    }
-}
-
-static uint64_t apb_config_readl (void *opaque,
-                                  hwaddr addr, unsigned size)
-{
-    APBState *s = opaque;
-    uint32_t val;
-
-    switch (addr & 0xffff) {
-    case 0x30 ... 0x4f: /* DMA error registers */
-        val = 0;
-        /* XXX: not implemented yet */
-        break;
-    case 0x200 ... 0x20b: /* IOMMU */
-        val = s->iommu[(addr & 0xf) >> 2];
-        break;
-    case 0x20c ... 0x3ff: /* IOMMU flush */
-        val = 0;
-        break;
-    case 0xc00 ... 0xc3f: /* PCI interrupt control */
-        if (addr & 4) {
-            val = s->pci_irq_map[(addr & 0x3f) >> 3];
-        } else {
-            val = 0;
-        }
-        break;
-    case 0x1000 ... 0x1080: /* OBIO interrupt control */
-        if (addr & 4) {
-            val = s->obio_irq_map[(addr & 0xff) >> 3];
-        } else {
-            val = 0;
-        }
-        break;
-    case 0x2000 ... 0x202f: /* PCI control */
-        val = s->pci_control[(addr & 0x3f) >> 2];
-        break;
-    case 0xf020 ... 0xf027: /* Reset control */
-        if (addr & 4) {
-            val = s->reset_control;
-        } else {
-            val = 0;
-        }
-        break;
-    case 0x5000 ... 0x51cf: /* PIO/DMA diagnostics */
-    case 0xa400 ... 0xa67f: /* IOMMU diagnostics */
-    case 0xa800 ... 0xa80f: /* Interrupt diagnostics */
-    case 0xf000 ... 0xf01f: /* FFB config, memory control */
-        /* we don't care */
-    default:
-        val = 0;
-        break;
-    }
-    APB_DPRINTF("%s: addr " TARGET_FMT_lx " -> %x\n", __func__, addr, val);
-
-    return val;
-}
-
-static const MemoryRegionOps apb_config_ops = {
-    .read = apb_config_readl,
-    .write = apb_config_writel,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void apb_pci_config_write(void *opaque, hwaddr addr,
-                                 uint64_t val, unsigned size)
-{
-    APBState *s = opaque;
-
-    val = qemu_bswap_len(val, size);
-    APB_DPRINTF("%s: addr " TARGET_FMT_lx " val %" PRIx64 "\n", __func__, addr, val);
-    pci_data_write(s->bus, addr, val, size);
-}
-
-static uint64_t apb_pci_config_read(void *opaque, hwaddr addr,
-                                    unsigned size)
-{
-    uint32_t ret;
-    APBState *s = opaque;
-
-    ret = pci_data_read(s->bus, addr, size);
-    ret = qemu_bswap_len(ret, size);
-    APB_DPRINTF("%s: addr " TARGET_FMT_lx " -> %x\n", __func__, addr, ret);
-    return ret;
-}
-
-static void pci_apb_iowriteb (void *opaque, hwaddr addr,
-                                  uint32_t val)
-{
-    cpu_outb(addr & IOPORTS_MASK, val);
-}
-
-static void pci_apb_iowritew (void *opaque, hwaddr addr,
-                                  uint32_t val)
-{
-    cpu_outw(addr & IOPORTS_MASK, bswap16(val));
-}
-
-static void pci_apb_iowritel (void *opaque, hwaddr addr,
-                                uint32_t val)
-{
-    cpu_outl(addr & IOPORTS_MASK, bswap32(val));
-}
-
-static uint32_t pci_apb_ioreadb (void *opaque, hwaddr addr)
-{
-    uint32_t val;
-
-    val = cpu_inb(addr & IOPORTS_MASK);
-    return val;
-}
-
-static uint32_t pci_apb_ioreadw (void *opaque, hwaddr addr)
-{
-    uint32_t val;
-
-    val = bswap16(cpu_inw(addr & IOPORTS_MASK));
-    return val;
-}
-
-static uint32_t pci_apb_ioreadl (void *opaque, hwaddr addr)
-{
-    uint32_t val;
-
-    val = bswap32(cpu_inl(addr & IOPORTS_MASK));
-    return val;
-}
-
-static const MemoryRegionOps pci_ioport_ops = {
-    .old_mmio = {
-        .read = { pci_apb_ioreadb, pci_apb_ioreadw, pci_apb_ioreadl },
-        .write = { pci_apb_iowriteb, pci_apb_iowritew, pci_apb_iowritel, },
-    },
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-/* The APB host has an IRQ line for each IRQ line of each slot.  */
-static int pci_apb_map_irq(PCIDevice *pci_dev, int irq_num)
-{
-    return ((pci_dev->devfn & 0x18) >> 1) + irq_num;
-}
-
-static int pci_pbm_map_irq(PCIDevice *pci_dev, int irq_num)
-{
-    int bus_offset;
-    if (pci_dev->devfn & 1)
-        bus_offset = 16;
-    else
-        bus_offset = 0;
-    return bus_offset + irq_num;
-}
-
-static void pci_apb_set_irq(void *opaque, int irq_num, int level)
-{
-    APBState *s = opaque;
-
-    /* PCI IRQ map onto the first 32 INO.  */
-    if (irq_num < 32) {
-        if (s->pci_irq_map[irq_num >> 2] & PBM_PCI_IMR_ENABLED) {
-            APB_DPRINTF("%s: set irq %d level %d\n", __func__, irq_num, level);
-            qemu_set_irq(s->ivec_irqs[irq_num], level);
-        } else {
-            APB_DPRINTF("%s: not enabled: lower irq %d\n", __func__, irq_num);
-            qemu_irq_lower(s->ivec_irqs[irq_num]);
-        }
-    } else {
-        /* OBIO IRQ map onto the next 16 INO.  */
-        if (s->obio_irq_map[irq_num - 32] & PBM_PCI_IMR_ENABLED) {
-            APB_DPRINTF("%s: set irq %d level %d\n", __func__, irq_num, level);
-            qemu_set_irq(s->ivec_irqs[irq_num], level);
-        } else {
-            APB_DPRINTF("%s: not enabled: lower irq %d\n", __func__, irq_num);
-            qemu_irq_lower(s->ivec_irqs[irq_num]);
-        }
-    }
-}
-
-static int apb_pci_bridge_initfn(PCIDevice *dev)
-{
-    int rc;
-
-    rc = pci_bridge_initfn(dev, TYPE_PCI_BUS);
-    if (rc < 0) {
-        return rc;
-    }
-
-    /*
-     * command register:
-     * According to PCI bridge spec, after reset
-     *   bus master bit is off
-     *   memory space enable bit is off
-     * According to manual (805-1251.pdf).
-     *   the reset value should be zero unless the boot pin is tied high
-     *   (which is true) and thus it should be PCI_COMMAND_MEMORY.
-     */
-    pci_set_word(dev->config + PCI_COMMAND,
-                 PCI_COMMAND_MEMORY);
-    pci_set_word(dev->config + PCI_STATUS,
-                 PCI_STATUS_FAST_BACK | PCI_STATUS_66MHZ |
-                 PCI_STATUS_DEVSEL_MEDIUM);
-    return 0;
-}
-
-PCIBus *pci_apb_init(hwaddr special_base,
-                     hwaddr mem_base,
-                     qemu_irq *ivec_irqs, PCIBus **bus2, PCIBus **bus3,
-                     qemu_irq **pbm_irqs)
-{
-    DeviceState *dev;
-    SysBusDevice *s;
-    APBState *d;
-    PCIDevice *pci_dev;
-    PCIBridge *br;
-
-    /* Ultrasparc PBM main bus */
-    dev = qdev_create(NULL, "pbm");
-    qdev_init_nofail(dev);
-    s = SYS_BUS_DEVICE(dev);
-    /* apb_config */
-    sysbus_mmio_map(s, 0, special_base);
-    /* PCI configuration space */
-    sysbus_mmio_map(s, 1, special_base + 0x1000000ULL);
-    /* pci_ioport */
-    sysbus_mmio_map(s, 2, special_base + 0x2000000ULL);
-    d = FROM_SYSBUS(APBState, s);
-
-    memory_region_init(&d->pci_mmio, "pci-mmio", 0x100000000ULL);
-    memory_region_add_subregion(get_system_memory(), mem_base, &d->pci_mmio);
-
-    d->bus = pci_register_bus(&d->busdev.qdev, "pci",
-                              pci_apb_set_irq, pci_pbm_map_irq, d,
-                              &d->pci_mmio,
-                              get_system_io(),
-                              0, 32, TYPE_PCI_BUS);
-
-    *pbm_irqs = d->pbm_irqs;
-    d->ivec_irqs = ivec_irqs;
-
-    pci_create_simple(d->bus, 0, "pbm-pci");
-
-    /* APB secondary busses */
-    pci_dev = pci_create_multifunction(d->bus, PCI_DEVFN(1, 0), true,
-                                   "pbm-bridge");
-    br = DO_UPCAST(PCIBridge, dev, pci_dev);
-    pci_bridge_map_irq(br, "Advanced PCI Bus secondary bridge 1",
-                       pci_apb_map_irq);
-    qdev_init_nofail(&pci_dev->qdev);
-    *bus2 = pci_bridge_get_sec_bus(br);
-
-    pci_dev = pci_create_multifunction(d->bus, PCI_DEVFN(1, 1), true,
-                                   "pbm-bridge");
-    br = DO_UPCAST(PCIBridge, dev, pci_dev);
-    pci_bridge_map_irq(br, "Advanced PCI Bus secondary bridge 2",
-                       pci_apb_map_irq);
-    qdev_init_nofail(&pci_dev->qdev);
-    *bus3 = pci_bridge_get_sec_bus(br);
-
-    return d->bus;
-}
-
-static void pci_pbm_reset(DeviceState *d)
-{
-    unsigned int i;
-    APBState *s = container_of(d, APBState, busdev.qdev);
-
-    for (i = 0; i < 8; i++) {
-        s->pci_irq_map[i] &= PBM_PCI_IMR_MASK;
-    }
-    for (i = 0; i < 32; i++) {
-        s->obio_irq_map[i] &= PBM_PCI_IMR_MASK;
-    }
-
-    if (s->nr_resets++ == 0) {
-        /* Power on reset */
-        s->reset_control = POR;
-    }
-}
-
-static const MemoryRegionOps pci_config_ops = {
-    .read = apb_pci_config_read,
-    .write = apb_pci_config_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int pci_pbm_init_device(SysBusDevice *dev)
-{
-    APBState *s;
-    unsigned int i;
-
-    s = FROM_SYSBUS(APBState, dev);
-    for (i = 0; i < 8; i++) {
-        s->pci_irq_map[i] = (0x1f << 6) | (i << 2);
-    }
-    for (i = 0; i < 32; i++) {
-        s->obio_irq_map[i] = ((0x1f << 6) | 0x20) + i;
-    }
-    s->pbm_irqs = qemu_allocate_irqs(pci_apb_set_irq, s, MAX_IVEC);
-
-    /* apb_config */
-    memory_region_init_io(&s->apb_config, &apb_config_ops, s, "apb-config",
-                          0x10000);
-    /* at region 0 */
-    sysbus_init_mmio(dev, &s->apb_config);
-
-    memory_region_init_io(&s->pci_config, &pci_config_ops, s, "apb-pci-config",
-                          0x1000000);
-    /* at region 1 */
-    sysbus_init_mmio(dev, &s->pci_config);
-
-    /* pci_ioport */
-    memory_region_init_io(&s->pci_ioport, &pci_ioport_ops, s,
-                          "apb-pci-ioport", 0x10000);
-    /* at region 2 */
-    sysbus_init_mmio(dev, &s->pci_ioport);
-
-    return 0;
-}
-
-static int pbm_pci_host_init(PCIDevice *d)
-{
-    pci_set_word(d->config + PCI_COMMAND,
-                 PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
-    pci_set_word(d->config + PCI_STATUS,
-                 PCI_STATUS_FAST_BACK | PCI_STATUS_66MHZ |
-                 PCI_STATUS_DEVSEL_MEDIUM);
-    return 0;
-}
-
-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;
-}
-
-static const 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 const 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;
-    k->exit = pci_bridge_exitfn;
-    k->vendor_id = PCI_VENDOR_ID_SUN;
-    k->device_id = PCI_DEVICE_ID_SUN_SIMBA;
-    k->revision = 0x11;
-    k->config_write = pci_bridge_write_config;
-    k->is_bridge = 1;
-    dc->reset = pci_bridge_reset;
-    dc->vmsd = &vmstate_pci_device;
-}
-
-static const 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_types(void)
-{
-    type_register_static(&pbm_host_info);
-    type_register_static(&pbm_pci_host_info);
-    type_register_static(&pbm_pci_bridge_info);
-}
-
-type_init(pbm_register_types)
diff --git a/hw/apb_pci.h b/hw/apb_pci.h
deleted file mode 100644 (file)
index 736db61..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef APB_PCI_H
-#define APB_PCI_H
-
-#include "qemu-common.h"
-
-PCIBus *pci_apb_init(hwaddr special_base,
-                     hwaddr mem_base,
-                     qemu_irq *ivec_irqs, PCIBus **bus2, PCIBus **bus3,
-                     qemu_irq **pbm_irqs);
-#endif
diff --git a/hw/apic-msidef.h b/hw/apic-msidef.h
deleted file mode 100644 (file)
index 6e2eb71..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-#ifndef HW_APIC_MSIDEF_H
-#define HW_APIC_MSIDEF_H
-
-/*
- * Intel APIC constants: from include/asm/msidef.h
- */
-
-/*
- * Shifts for MSI data
- */
-
-#define MSI_DATA_VECTOR_SHIFT           0
-#define  MSI_DATA_VECTOR_MASK           0x000000ff
-
-#define MSI_DATA_DELIVERY_MODE_SHIFT    8
-#define MSI_DATA_LEVEL_SHIFT            14
-#define MSI_DATA_TRIGGER_SHIFT          15
-
-/*
- * Shift/mask fields for msi address
- */
-
-#define MSI_ADDR_DEST_MODE_SHIFT        2
-
-#define MSI_ADDR_REDIRECTION_SHIFT      3
-
-#define MSI_ADDR_DEST_ID_SHIFT          12
-#define  MSI_ADDR_DEST_ID_MASK          0x00ffff0
-
-#endif /* HW_APIC_MSIDEF_H */
diff --git a/hw/apic.c b/hw/apic.c
deleted file mode 100644 (file)
index d2395f0..0000000
--- a/hw/apic.c
+++ /dev/null
@@ -1,911 +0,0 @@
-/*
- *  APIC support
- *
- *  Copyright (c) 2004-2005 Fabrice Bellard
- *
- * 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 "qemu/thread.h"
-#include "hw/apic_internal.h"
-#include "hw/apic.h"
-#include "hw/ioapic.h"
-#include "hw/pci/msi.h"
-#include "qemu/host-utils.h"
-#include "trace.h"
-#include "hw/pc.h"
-#include "hw/apic-msidef.h"
-
-#define MAX_APIC_WORDS 8
-
-#define SYNC_FROM_VAPIC                 0x1
-#define SYNC_TO_VAPIC                   0x2
-#define SYNC_ISR_IRR_TO_VAPIC           0x4
-
-static APICCommonState *local_apics[MAX_APICS + 1];
-
-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);
-
-/* Find first bit starting from msb */
-static int fls_bit(uint32_t value)
-{
-    return 31 - clz32(value);
-}
-
-/* Find first bit starting from lsb */
-static int ffs_bit(uint32_t value)
-{
-    return ctz32(value);
-}
-
-static inline void set_bit(uint32_t *tab, int index)
-{
-    int i, mask;
-    i = index >> 5;
-    mask = 1 << (index & 0x1f);
-    tab[i] |= mask;
-}
-
-static inline void reset_bit(uint32_t *tab, int index)
-{
-    int i, mask;
-    i = index >> 5;
-    mask = 1 << (index & 0x1f);
-    tab[i] &= ~mask;
-}
-
-static inline int get_bit(uint32_t *tab, int index)
-{
-    int i, mask;
-    i = index >> 5;
-    mask = 1 << (index & 0x1f);
-    return !!(tab[i] & mask);
-}
-
-/* return -1 if no bit is set */
-static int get_highest_priority_int(uint32_t *tab)
-{
-    int i;
-    for (i = 7; i >= 0; i--) {
-        if (tab[i] != 0) {
-            return i * 32 + fls_bit(tab[i]);
-        }
-    }
-    return -1;
-}
-
-static void apic_sync_vapic(APICCommonState *s, int sync_type)
-{
-    VAPICState vapic_state;
-    size_t length;
-    off_t start;
-    int vector;
-
-    if (!s->vapic_paddr) {
-        return;
-    }
-    if (sync_type & SYNC_FROM_VAPIC) {
-        cpu_physical_memory_rw(s->vapic_paddr, (void *)&vapic_state,
-                               sizeof(vapic_state), 0);
-        s->tpr = vapic_state.tpr;
-    }
-    if (sync_type & (SYNC_TO_VAPIC | SYNC_ISR_IRR_TO_VAPIC)) {
-        start = offsetof(VAPICState, isr);
-        length = offsetof(VAPICState, enabled) - offsetof(VAPICState, isr);
-
-        if (sync_type & SYNC_TO_VAPIC) {
-            assert(qemu_cpu_is_self(CPU(s->cpu)));
-
-            vapic_state.tpr = s->tpr;
-            vapic_state.enabled = 1;
-            start = 0;
-            length = sizeof(VAPICState);
-        }
-
-        vector = get_highest_priority_int(s->isr);
-        if (vector < 0) {
-            vector = 0;
-        }
-        vapic_state.isr = vector & 0xf0;
-
-        vapic_state.zero = 0;
-
-        vector = get_highest_priority_int(s->irr);
-        if (vector < 0) {
-            vector = 0;
-        }
-        vapic_state.irr = vector & 0xff;
-
-        cpu_physical_memory_write_rom(s->vapic_paddr + start,
-                                      ((void *)&vapic_state) + start, length);
-    }
-}
-
-static void apic_vapic_base_update(APICCommonState *s)
-{
-    apic_sync_vapic(s, SYNC_TO_VAPIC);
-}
-
-static void apic_local_deliver(APICCommonState *s, int vector)
-{
-    uint32_t lvt = s->lvt[vector];
-    int trigger_mode;
-
-    trace_apic_local_deliver(vector, (lvt >> 8) & 7);
-
-    if (lvt & APIC_LVT_MASKED)
-        return;
-
-    switch ((lvt >> 8) & 7) {
-    case APIC_DM_SMI:
-        cpu_interrupt(CPU(s->cpu), CPU_INTERRUPT_SMI);
-        break;
-
-    case APIC_DM_NMI:
-        cpu_interrupt(CPU(s->cpu), CPU_INTERRUPT_NMI);
-        break;
-
-    case APIC_DM_EXTINT:
-        cpu_interrupt(CPU(s->cpu), CPU_INTERRUPT_HARD);
-        break;
-
-    case APIC_DM_FIXED:
-        trigger_mode = APIC_TRIGGER_EDGE;
-        if ((vector == APIC_LVT_LINT0 || vector == APIC_LVT_LINT1) &&
-            (lvt & APIC_LVT_LEVEL_TRIGGER))
-            trigger_mode = APIC_TRIGGER_LEVEL;
-        apic_set_irq(s, lvt & 0xff, trigger_mode);
-    }
-}
-
-void apic_deliver_pic_intr(DeviceState *d, int level)
-{
-    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
-
-    if (level) {
-        apic_local_deliver(s, APIC_LVT_LINT0);
-    } else {
-        uint32_t lvt = s->lvt[APIC_LVT_LINT0];
-
-        switch ((lvt >> 8) & 7) {
-        case APIC_DM_FIXED:
-            if (!(lvt & APIC_LVT_LEVEL_TRIGGER))
-                break;
-            reset_bit(s->irr, lvt & 0xff);
-            /* fall through */
-        case APIC_DM_EXTINT:
-            cpu_reset_interrupt(CPU(s->cpu), CPU_INTERRUPT_HARD);
-            break;
-        }
-    }
-}
-
-static void apic_external_nmi(APICCommonState *s)
-{
-    apic_local_deliver(s, APIC_LVT_LINT1);
-}
-
-#define foreach_apic(apic, deliver_bitmask, code) \
-{\
-    int __i, __j, __mask;\
-    for(__i = 0; __i < MAX_APIC_WORDS; __i++) {\
-        __mask = deliver_bitmask[__i];\
-        if (__mask) {\
-            for(__j = 0; __j < 32; __j++) {\
-                if (__mask & (1 << __j)) {\
-                    apic = local_apics[__i * 32 + __j];\
-                    if (apic) {\
-                        code;\
-                    }\
-                }\
-            }\
-        }\
-    }\
-}
-
-static void apic_bus_deliver(const uint32_t *deliver_bitmask,
-                             uint8_t delivery_mode, uint8_t vector_num,
-                             uint8_t trigger_mode)
-{
-    APICCommonState *apic_iter;
-
-    switch (delivery_mode) {
-        case APIC_DM_LOWPRI:
-            /* XXX: search for focus processor, arbitration */
-            {
-                int i, d;
-                d = -1;
-                for(i = 0; i < MAX_APIC_WORDS; i++) {
-                    if (deliver_bitmask[i]) {
-                        d = i * 32 + ffs_bit(deliver_bitmask[i]);
-                        break;
-                    }
-                }
-                if (d >= 0) {
-                    apic_iter = local_apics[d];
-                    if (apic_iter) {
-                        apic_set_irq(apic_iter, vector_num, trigger_mode);
-                    }
-                }
-            }
-            return;
-
-        case APIC_DM_FIXED:
-            break;
-
-        case APIC_DM_SMI:
-            foreach_apic(apic_iter, deliver_bitmask,
-                cpu_interrupt(CPU(apic_iter->cpu), CPU_INTERRUPT_SMI)
-            );
-            return;
-
-        case APIC_DM_NMI:
-            foreach_apic(apic_iter, deliver_bitmask,
-                cpu_interrupt(CPU(apic_iter->cpu), CPU_INTERRUPT_NMI)
-            );
-            return;
-
-        case APIC_DM_INIT:
-            /* normal INIT IPI sent to processors */
-            foreach_apic(apic_iter, deliver_bitmask,
-                         cpu_interrupt(CPU(apic_iter->cpu),
-                                       CPU_INTERRUPT_INIT)
-            );
-            return;
-
-        case APIC_DM_EXTINT:
-            /* handled in I/O APIC code */
-            break;
-
-        default:
-            return;
-    }
-
-    foreach_apic(apic_iter, deliver_bitmask,
-                 apic_set_irq(apic_iter, vector_num, trigger_mode) );
-}
-
-void apic_deliver_irq(uint8_t dest, uint8_t dest_mode, uint8_t delivery_mode,
-                      uint8_t vector_num, uint8_t trigger_mode)
-{
-    uint32_t deliver_bitmask[MAX_APIC_WORDS];
-
-    trace_apic_deliver_irq(dest, dest_mode, delivery_mode, vector_num,
-                           trigger_mode);
-
-    apic_get_delivery_bitmask(deliver_bitmask, dest, dest_mode);
-    apic_bus_deliver(deliver_bitmask, delivery_mode, vector_num, trigger_mode);
-}
-
-static void apic_set_base(APICCommonState *s, uint64_t val)
-{
-    s->apicbase = (val & 0xfffff000) |
-        (s->apicbase & (MSR_IA32_APICBASE_BSP | MSR_IA32_APICBASE_ENABLE));
-    /* if disabled, cannot be enabled again */
-    if (!(val & MSR_IA32_APICBASE_ENABLE)) {
-        s->apicbase &= ~MSR_IA32_APICBASE_ENABLE;
-        cpu_clear_apic_feature(&s->cpu->env);
-        s->spurious_vec &= ~APIC_SV_ENABLE;
-    }
-}
-
-static void apic_set_tpr(APICCommonState *s, uint8_t val)
-{
-    /* Updates from cr8 are ignored while the VAPIC is active */
-    if (!s->vapic_paddr) {
-        s->tpr = val << 4;
-        apic_update_irq(s);
-    }
-}
-
-static uint8_t apic_get_tpr(APICCommonState *s)
-{
-    apic_sync_vapic(s, SYNC_FROM_VAPIC);
-    return s->tpr >> 4;
-}
-
-static int apic_get_ppr(APICCommonState *s)
-{
-    int tpr, isrv, ppr;
-
-    tpr = (s->tpr >> 4);
-    isrv = get_highest_priority_int(s->isr);
-    if (isrv < 0)
-        isrv = 0;
-    isrv >>= 4;
-    if (tpr >= isrv)
-        ppr = s->tpr;
-    else
-        ppr = isrv << 4;
-    return ppr;
-}
-
-static int apic_get_arb_pri(APICCommonState *s)
-{
-    /* XXX: arbitration */
-    return 0;
-}
-
-
-/*
- * <0 - low prio interrupt,
- * 0  - no interrupt,
- * >0 - interrupt number
- */
-static int apic_irq_pending(APICCommonState *s)
-{
-    int irrv, ppr;
-    irrv = get_highest_priority_int(s->irr);
-    if (irrv < 0) {
-        return 0;
-    }
-    ppr = apic_get_ppr(s);
-    if (ppr && (irrv & 0xf0) <= (ppr & 0xf0)) {
-        return -1;
-    }
-
-    return irrv;
-}
-
-/* signal the CPU if an irq is pending */
-static void apic_update_irq(APICCommonState *s)
-{
-    CPUState *cpu;
-
-    if (!(s->spurious_vec & APIC_SV_ENABLE)) {
-        return;
-    }
-    cpu = CPU(s->cpu);
-    if (!qemu_cpu_is_self(cpu)) {
-        cpu_interrupt(cpu, CPU_INTERRUPT_POLL);
-    } else if (apic_irq_pending(s) > 0) {
-        cpu_interrupt(cpu, CPU_INTERRUPT_HARD);
-    }
-}
-
-void apic_poll_irq(DeviceState *d)
-{
-    APICCommonState *s = APIC_COMMON(d);
-
-    apic_sync_vapic(s, SYNC_FROM_VAPIC);
-    apic_update_irq(s);
-}
-
-static void apic_set_irq(APICCommonState *s, int vector_num, int trigger_mode)
-{
-    apic_report_irq_delivered(!get_bit(s->irr, vector_num));
-
-    set_bit(s->irr, vector_num);
-    if (trigger_mode)
-        set_bit(s->tmr, vector_num);
-    else
-        reset_bit(s->tmr, vector_num);
-    if (s->vapic_paddr) {
-        apic_sync_vapic(s, SYNC_ISR_IRR_TO_VAPIC);
-        /*
-         * The vcpu thread needs to see the new IRR before we pull its current
-         * TPR value. That way, if we miss a lowering of the TRP, the guest
-         * has the chance to notice the new IRR and poll for IRQs on its own.
-         */
-        smp_wmb();
-        apic_sync_vapic(s, SYNC_FROM_VAPIC);
-    }
-    apic_update_irq(s);
-}
-
-static void apic_eoi(APICCommonState *s)
-{
-    int isrv;
-    isrv = get_highest_priority_int(s->isr);
-    if (isrv < 0)
-        return;
-    reset_bit(s->isr, isrv);
-    if (!(s->spurious_vec & APIC_SV_DIRECTED_IO) && get_bit(s->tmr, isrv)) {
-        ioapic_eoi_broadcast(isrv);
-    }
-    apic_sync_vapic(s, SYNC_FROM_VAPIC | SYNC_TO_VAPIC);
-    apic_update_irq(s);
-}
-
-static int apic_find_dest(uint8_t dest)
-{
-    APICCommonState *apic = local_apics[dest];
-    int i;
-
-    if (apic && apic->id == dest)
-        return dest;  /* shortcut in case apic->id == apic->idx */
-
-    for (i = 0; i < MAX_APICS; i++) {
-        apic = local_apics[i];
-       if (apic && apic->id == dest)
-            return i;
-        if (!apic)
-            break;
-    }
-
-    return -1;
-}
-
-static void apic_get_delivery_bitmask(uint32_t *deliver_bitmask,
-                                      uint8_t dest, uint8_t dest_mode)
-{
-    APICCommonState *apic_iter;
-    int i;
-
-    if (dest_mode == 0) {
-        if (dest == 0xff) {
-            memset(deliver_bitmask, 0xff, MAX_APIC_WORDS * sizeof(uint32_t));
-        } else {
-            int idx = apic_find_dest(dest);
-            memset(deliver_bitmask, 0x00, MAX_APIC_WORDS * sizeof(uint32_t));
-            if (idx >= 0)
-                set_bit(deliver_bitmask, idx);
-        }
-    } else {
-        /* XXX: cluster mode */
-        memset(deliver_bitmask, 0x00, MAX_APIC_WORDS * sizeof(uint32_t));
-        for(i = 0; i < MAX_APICS; i++) {
-            apic_iter = local_apics[i];
-            if (apic_iter) {
-                if (apic_iter->dest_mode == 0xf) {
-                    if (dest & apic_iter->log_dest)
-                        set_bit(deliver_bitmask, i);
-                } else if (apic_iter->dest_mode == 0x0) {
-                    if ((dest & 0xf0) == (apic_iter->log_dest & 0xf0) &&
-                        (dest & apic_iter->log_dest & 0x0f)) {
-                        set_bit(deliver_bitmask, i);
-                    }
-                }
-            } else {
-                break;
-            }
-        }
-    }
-}
-
-static void apic_startup(APICCommonState *s, int vector_num)
-{
-    s->sipi_vector = vector_num;
-    cpu_interrupt(CPU(s->cpu), CPU_INTERRUPT_SIPI);
-}
-
-void apic_sipi(DeviceState *d)
-{
-    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
-
-    cpu_reset_interrupt(CPU(s->cpu), CPU_INTERRUPT_SIPI);
-
-    if (!s->wait_for_sipi)
-        return;
-    cpu_x86_load_seg_cache_sipi(s->cpu, s->sipi_vector);
-    s->wait_for_sipi = 0;
-}
-
-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)
-{
-    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
-    uint32_t deliver_bitmask[MAX_APIC_WORDS];
-    int dest_shorthand = (s->icr[0] >> 18) & 3;
-    APICCommonState *apic_iter;
-
-    switch (dest_shorthand) {
-    case 0:
-        apic_get_delivery_bitmask(deliver_bitmask, dest, dest_mode);
-        break;
-    case 1:
-        memset(deliver_bitmask, 0x00, sizeof(deliver_bitmask));
-        set_bit(deliver_bitmask, s->idx);
-        break;
-    case 2:
-        memset(deliver_bitmask, 0xff, sizeof(deliver_bitmask));
-        break;
-    case 3:
-        memset(deliver_bitmask, 0xff, sizeof(deliver_bitmask));
-        reset_bit(deliver_bitmask, s->idx);
-        break;
-    }
-
-    switch (delivery_mode) {
-        case APIC_DM_INIT:
-            {
-                int trig_mode = (s->icr[0] >> 15) & 1;
-                int level = (s->icr[0] >> 14) & 1;
-                if (level == 0 && trig_mode == 1) {
-                    foreach_apic(apic_iter, deliver_bitmask,
-                                 apic_iter->arb_id = apic_iter->id );
-                    return;
-                }
-            }
-            break;
-
-        case APIC_DM_SIPI:
-            foreach_apic(apic_iter, deliver_bitmask,
-                         apic_startup(apic_iter, vector_num) );
-            return;
-    }
-
-    apic_bus_deliver(deliver_bitmask, delivery_mode, vector_num, trigger_mode);
-}
-
-static bool apic_check_pic(APICCommonState *s)
-{
-    if (!apic_accept_pic_intr(&s->busdev.qdev) || !pic_get_output(isa_pic)) {
-        return false;
-    }
-    apic_deliver_pic_intr(&s->busdev.qdev, 1);
-    return true;
-}
-
-int apic_get_interrupt(DeviceState *d)
-{
-    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
-    int intno;
-
-    /* if the APIC is installed or enabled, we let the 8259 handle the
-       IRQs */
-    if (!s)
-        return -1;
-    if (!(s->spurious_vec & APIC_SV_ENABLE))
-        return -1;
-
-    apic_sync_vapic(s, SYNC_FROM_VAPIC);
-    intno = apic_irq_pending(s);
-
-    if (intno == 0) {
-        apic_sync_vapic(s, SYNC_TO_VAPIC);
-        return -1;
-    } else if (intno < 0) {
-        apic_sync_vapic(s, SYNC_TO_VAPIC);
-        return s->spurious_vec & 0xff;
-    }
-    reset_bit(s->irr, intno);
-    set_bit(s->isr, intno);
-    apic_sync_vapic(s, SYNC_TO_VAPIC);
-
-    /* re-inject if there is still a pending PIC interrupt */
-    apic_check_pic(s);
-
-    apic_update_irq(s);
-
-    return intno;
-}
-
-int apic_accept_pic_intr(DeviceState *d)
-{
-    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
-    uint32_t lvt0;
-
-    if (!s)
-        return -1;
-
-    lvt0 = s->lvt[APIC_LVT_LINT0];
-
-    if ((s->apicbase & MSR_IA32_APICBASE_ENABLE) == 0 ||
-        (lvt0 & APIC_LVT_MASKED) == 0)
-        return 1;
-
-    return 0;
-}
-
-static uint32_t apic_get_current_count(APICCommonState *s)
-{
-    int64_t d;
-    uint32_t val;
-    d = (qemu_get_clock_ns(vm_clock) - s->initial_count_load_time) >>
-        s->count_shift;
-    if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) {
-        /* periodic */
-        val = s->initial_count - (d % ((uint64_t)s->initial_count + 1));
-    } else {
-        if (d >= s->initial_count)
-            val = 0;
-        else
-            val = s->initial_count - d;
-    }
-    return val;
-}
-
-static void apic_timer_update(APICCommonState *s, int64_t current_time)
-{
-    if (apic_next_timer(s, current_time)) {
-        qemu_mod_timer(s->timer, s->next_time);
-    } else {
-        qemu_del_timer(s->timer);
-    }
-}
-
-static void apic_timer(void *opaque)
-{
-    APICCommonState *s = opaque;
-
-    apic_local_deliver(s, APIC_LVT_TIMER);
-    apic_timer_update(s, s->next_time);
-}
-
-static uint32_t apic_mem_readb(void *opaque, hwaddr addr)
-{
-    return 0;
-}
-
-static uint32_t apic_mem_readw(void *opaque, hwaddr addr)
-{
-    return 0;
-}
-
-static void apic_mem_writeb(void *opaque, hwaddr addr, uint32_t val)
-{
-}
-
-static void apic_mem_writew(void *opaque, hwaddr addr, uint32_t val)
-{
-}
-
-static uint32_t apic_mem_readl(void *opaque, hwaddr addr)
-{
-    DeviceState *d;
-    APICCommonState *s;
-    uint32_t val;
-    int index;
-
-    d = cpu_get_current_apic();
-    if (!d) {
-        return 0;
-    }
-    s = DO_UPCAST(APICCommonState, busdev.qdev, d);
-
-    index = (addr >> 4) & 0xff;
-    switch(index) {
-    case 0x02: /* id */
-        val = s->id << 24;
-        break;
-    case 0x03: /* version */
-        val = 0x11 | ((APIC_LVT_NB - 1) << 16); /* version 0x11 */
-        break;
-    case 0x08:
-        apic_sync_vapic(s, SYNC_FROM_VAPIC);
-        if (apic_report_tpr_access) {
-            cpu_report_tpr_access(&s->cpu->env, TPR_ACCESS_READ);
-        }
-        val = s->tpr;
-        break;
-    case 0x09:
-        val = apic_get_arb_pri(s);
-        break;
-    case 0x0a:
-        /* ppr */
-        val = apic_get_ppr(s);
-        break;
-    case 0x0b:
-        val = 0;
-        break;
-    case 0x0d:
-        val = s->log_dest << 24;
-        break;
-    case 0x0e:
-        val = s->dest_mode << 28;
-        break;
-    case 0x0f:
-        val = s->spurious_vec;
-        break;
-    case 0x10 ... 0x17:
-        val = s->isr[index & 7];
-        break;
-    case 0x18 ... 0x1f:
-        val = s->tmr[index & 7];
-        break;
-    case 0x20 ... 0x27:
-        val = s->irr[index & 7];
-        break;
-    case 0x28:
-        val = s->esr;
-        break;
-    case 0x30:
-    case 0x31:
-        val = s->icr[index & 1];
-        break;
-    case 0x32 ... 0x37:
-        val = s->lvt[index - 0x32];
-        break;
-    case 0x38:
-        val = s->initial_count;
-        break;
-    case 0x39:
-        val = apic_get_current_count(s);
-        break;
-    case 0x3e:
-        val = s->divide_conf;
-        break;
-    default:
-        s->esr |= ESR_ILLEGAL_ADDRESS;
-        val = 0;
-        break;
-    }
-    trace_apic_mem_readl(addr, val);
-    return val;
-}
-
-static void apic_send_msi(hwaddr addr, uint32_t data)
-{
-    uint8_t dest = (addr & MSI_ADDR_DEST_ID_MASK) >> MSI_ADDR_DEST_ID_SHIFT;
-    uint8_t vector = (data & MSI_DATA_VECTOR_MASK) >> MSI_DATA_VECTOR_SHIFT;
-    uint8_t dest_mode = (addr >> MSI_ADDR_DEST_MODE_SHIFT) & 0x1;
-    uint8_t trigger_mode = (data >> MSI_DATA_TRIGGER_SHIFT) & 0x1;
-    uint8_t delivery = (data >> MSI_DATA_DELIVERY_MODE_SHIFT) & 0x7;
-    /* XXX: Ignore redirection hint. */
-    apic_deliver_irq(dest, dest_mode, delivery, vector, trigger_mode);
-}
-
-static void apic_mem_writel(void *opaque, hwaddr addr, uint32_t val)
-{
-    DeviceState *d;
-    APICCommonState *s;
-    int index = (addr >> 4) & 0xff;
-    if (addr > 0xfff || !index) {
-        /* MSI and MMIO APIC are at the same memory location,
-         * but actually not on the global bus: MSI is on PCI bus
-         * APIC is connected directly to the CPU.
-         * Mapping them on the global bus happens to work because
-         * MSI registers are reserved in APIC MMIO and vice versa. */
-        apic_send_msi(addr, val);
-        return;
-    }
-
-    d = cpu_get_current_apic();
-    if (!d) {
-        return;
-    }
-    s = DO_UPCAST(APICCommonState, busdev.qdev, d);
-
-    trace_apic_mem_writel(addr, val);
-
-    switch(index) {
-    case 0x02:
-        s->id = (val >> 24);
-        break;
-    case 0x03:
-        break;
-    case 0x08:
-        if (apic_report_tpr_access) {
-            cpu_report_tpr_access(&s->cpu->env, TPR_ACCESS_WRITE);
-        }
-        s->tpr = val;
-        apic_sync_vapic(s, SYNC_TO_VAPIC);
-        apic_update_irq(s);
-        break;
-    case 0x09:
-    case 0x0a:
-        break;
-    case 0x0b: /* EOI */
-        apic_eoi(s);
-        break;
-    case 0x0d:
-        s->log_dest = val >> 24;
-        break;
-    case 0x0e:
-        s->dest_mode = val >> 28;
-        break;
-    case 0x0f:
-        s->spurious_vec = val & 0x1ff;
-        apic_update_irq(s);
-        break;
-    case 0x10 ... 0x17:
-    case 0x18 ... 0x1f:
-    case 0x20 ... 0x27:
-    case 0x28:
-        break;
-    case 0x30:
-        s->icr[0] = val;
-        apic_deliver(d, (s->icr[1] >> 24) & 0xff, (s->icr[0] >> 11) & 1,
-                     (s->icr[0] >> 8) & 7, (s->icr[0] & 0xff),
-                     (s->icr[0] >> 15) & 1);
-        break;
-    case 0x31:
-        s->icr[1] = val;
-        break;
-    case 0x32 ... 0x37:
-        {
-            int n = index - 0x32;
-            s->lvt[n] = val;
-            if (n == APIC_LVT_TIMER) {
-                apic_timer_update(s, qemu_get_clock_ns(vm_clock));
-            } else if (n == APIC_LVT_LINT0 && apic_check_pic(s)) {
-                apic_update_irq(s);
-            }
-        }
-        break;
-    case 0x38:
-        s->initial_count = val;
-        s->initial_count_load_time = qemu_get_clock_ns(vm_clock);
-        apic_timer_update(s, s->initial_count_load_time);
-        break;
-    case 0x39:
-        break;
-    case 0x3e:
-        {
-            int v;
-            s->divide_conf = val & 0xb;
-            v = (s->divide_conf & 3) | ((s->divide_conf >> 1) & 4);
-            s->count_shift = (v + 1) & 7;
-        }
-        break;
-    default:
-        s->esr |= ESR_ILLEGAL_ADDRESS;
-        break;
-    }
-}
-
-static void apic_pre_save(APICCommonState *s)
-{
-    apic_sync_vapic(s, SYNC_FROM_VAPIC);
-}
-
-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, },
-        .write = { apic_mem_writeb, apic_mem_writew, apic_mem_writel, },
-    },
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void apic_init(APICCommonState *s)
-{
-    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);
-    local_apics[s->idx] = s;
-
-    msi_supported = true;
-}
-
-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->get_tpr = apic_get_tpr;
-    k->vapic_base_update = apic_vapic_base_update;
-    k->external_nmi = apic_external_nmi;
-    k->pre_save = apic_pre_save;
-    k->post_load = apic_post_load;
-}
-
-static const TypeInfo apic_info = {
-    .name          = "apic",
-    .instance_size = sizeof(APICCommonState),
-    .parent        = TYPE_APIC_COMMON,
-    .class_init    = apic_class_init,
-};
-
-static void apic_register_types(void)
-{
-    type_register_static(&apic_info);
-}
-
-type_init(apic_register_types)
diff --git a/hw/apic.h b/hw/apic.h
deleted file mode 100644 (file)
index 1d48e02..0000000
--- a/hw/apic.h
+++ /dev/null
@@ -1,32 +0,0 @@
-#ifndef APIC_H
-#define APIC_H
-
-#include "qemu-common.h"
-
-/* apic.c */
-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);
-void cpu_set_apic_base(DeviceState *s, uint64_t val);
-uint64_t cpu_get_apic_base(DeviceState *s);
-void cpu_set_apic_tpr(DeviceState *s, uint8_t val);
-uint8_t cpu_get_apic_tpr(DeviceState *s);
-void apic_init_reset(DeviceState *s);
-void apic_sipi(DeviceState *s);
-void apic_handle_tpr_access_report(DeviceState *d, target_ulong ip,
-                                   TPRAccess access);
-void apic_poll_irq(DeviceState *d);
-void apic_designate_bsp(DeviceState *d);
-
-/* pc.c */
-DeviceState *cpu_get_current_apic(void);
-
-/* cpu.c */
-bool cpu_is_bsp(X86CPU *cpu);
-
-#endif
diff --git a/hw/apic_common.c b/hw/apic_common.c
deleted file mode 100644 (file)
index 3798509..0000000
+++ /dev/null
@@ -1,402 +0,0 @@
-/*
- *  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 "hw/apic.h"
-#include "hw/apic_internal.h"
-#include "trace.h"
-#include "sysemu/kvm.h"
-
-static int apic_irq_delivered;
-bool apic_report_tpr_access;
-
-void cpu_set_apic_base(DeviceState *d, uint64_t val)
-{
-    trace_cpu_set_apic_base(val);
-
-    if (d) {
-        APICCommonState *s = APIC_COMMON(d);
-        APICCommonClass *info = APIC_COMMON_GET_CLASS(s);
-        info->set_base(s, val);
-    }
-}
-
-uint64_t cpu_get_apic_base(DeviceState *d)
-{
-    if (d) {
-        APICCommonState *s = APIC_COMMON(d);
-        trace_cpu_get_apic_base((uint64_t)s->apicbase);
-        return s->apicbase;
-    } else {
-        trace_cpu_get_apic_base(MSR_IA32_APICBASE_BSP);
-        return MSR_IA32_APICBASE_BSP;
-    }
-}
-
-void cpu_set_apic_tpr(DeviceState *d, uint8_t val)
-{
-    APICCommonState *s;
-    APICCommonClass *info;
-
-    if (!d) {
-        return;
-    }
-
-    s = APIC_COMMON(d);
-    info = APIC_COMMON_GET_CLASS(s);
-
-    info->set_tpr(s, val);
-}
-
-uint8_t cpu_get_apic_tpr(DeviceState *d)
-{
-    APICCommonState *s;
-    APICCommonClass *info;
-
-    if (!d) {
-        return 0;
-    }
-
-    s = APIC_COMMON(d);
-    info = APIC_COMMON_GET_CLASS(s);
-
-    return info->get_tpr(s);
-}
-
-void apic_enable_tpr_access_reporting(DeviceState *d, bool enable)
-{
-    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
-    APICCommonClass *info = APIC_COMMON_GET_CLASS(s);
-
-    apic_report_tpr_access = enable;
-    if (info->enable_tpr_reporting) {
-        info->enable_tpr_reporting(s, enable);
-    }
-}
-
-void apic_enable_vapic(DeviceState *d, hwaddr paddr)
-{
-    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
-    APICCommonClass *info = APIC_COMMON_GET_CLASS(s);
-
-    s->vapic_paddr = paddr;
-    info->vapic_base_update(s);
-}
-
-void apic_handle_tpr_access_report(DeviceState *d, target_ulong ip,
-                                   TPRAccess access)
-{
-    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
-
-    vapic_report_tpr_access(s->vapic, CPU(s->cpu), ip, access);
-}
-
-void apic_report_irq_delivered(int delivered)
-{
-    apic_irq_delivered += delivered;
-
-    trace_apic_report_irq_delivered(apic_irq_delivered);
-}
-
-void apic_reset_irq_delivered(void)
-{
-    trace_apic_reset_irq_delivered(apic_irq_delivered);
-
-    apic_irq_delivered = 0;
-}
-
-int apic_get_irq_delivered(void)
-{
-    trace_apic_get_irq_delivered(apic_irq_delivered);
-
-    return apic_irq_delivered;
-}
-
-void apic_deliver_nmi(DeviceState *d)
-{
-    APICCommonState *s = APIC_COMMON(d);
-    APICCommonClass *info = APIC_COMMON_GET_CLASS(s);
-
-    info->external_nmi(s);
-}
-
-bool apic_next_timer(APICCommonState *s, int64_t current_time)
-{
-    int64_t d;
-
-    /* We need to store the timer state separately to support APIC
-     * implementations that maintain a non-QEMU timer, e.g. inside the
-     * host kernel. This open-coded state allows us to migrate between
-     * both models. */
-    s->timer_expiry = -1;
-
-    if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_MASKED) {
-        return false;
-    }
-
-    d = (current_time - s->initial_count_load_time) >> s->count_shift;
-
-    if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) {
-        if (!s->initial_count) {
-            return false;
-        }
-        d = ((d / ((uint64_t)s->initial_count + 1)) + 1) *
-            ((uint64_t)s->initial_count + 1);
-    } else {
-        if (d >= s->initial_count) {
-            return false;
-        }
-        d = (uint64_t)s->initial_count + 1;
-    }
-    s->next_time = s->initial_count_load_time + (d << s->count_shift);
-    s->timer_expiry = s->next_time;
-    return true;
-}
-
-void apic_init_reset(DeviceState *d)
-{
-    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
-    int i;
-
-    if (!s) {
-        return;
-    }
-    s->tpr = 0;
-    s->spurious_vec = 0xff;
-    s->log_dest = 0;
-    s->dest_mode = 0xf;
-    memset(s->isr, 0, sizeof(s->isr));
-    memset(s->tmr, 0, sizeof(s->tmr));
-    memset(s->irr, 0, sizeof(s->irr));
-    for (i = 0; i < APIC_LVT_NB; i++) {
-        s->lvt[i] = APIC_LVT_MASKED;
-    }
-    s->esr = 0;
-    memset(s->icr, 0, sizeof(s->icr));
-    s->divide_conf = 0;
-    s->count_shift = 0;
-    s->initial_count = 0;
-    s->initial_count_load_time = 0;
-    s->next_time = 0;
-    s->wait_for_sipi = 1;
-
-    if (s->timer) {
-        qemu_del_timer(s->timer);
-    }
-    s->timer_expiry = -1;
-}
-
-void apic_designate_bsp(DeviceState *d)
-{
-    if (d == NULL) {
-        return;
-    }
-
-    APICCommonState *s = APIC_COMMON(d);
-    s->apicbase |= MSR_IA32_APICBASE_BSP;
-}
-
-static void apic_reset_common(DeviceState *d)
-{
-    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
-    APICCommonClass *info = APIC_COMMON_GET_CLASS(s);
-    bool bsp;
-
-    bsp = cpu_is_bsp(s->cpu);
-    s->apicbase = APIC_DEFAULT_ADDRESS |
-        (bsp ? MSR_IA32_APICBASE_BSP : 0) | MSR_IA32_APICBASE_ENABLE;
-
-    s->vapic_paddr = 0;
-    info->vapic_base_update(s);
-
-    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;
-    APICCommonClass *info = APIC_COMMON_GET_CLASS(s);
-    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) {
-        s->timer_expiry = qemu_get_be64(f);
-    }
-
-    if (info->post_load) {
-        info->post_load(s);
-    }
-    return 0;
-}
-
-static int apic_init_common(SysBusDevice *dev)
-{
-    APICCommonState *s = APIC_COMMON(dev);
-    APICCommonClass *info;
-    static DeviceState *vapic;
-    static int apic_no;
-
-    if (apic_no >= MAX_APICS) {
-        return -1;
-    }
-    s->idx = apic_no++;
-
-    info = APIC_COMMON_GET_CLASS(s);
-    info->init(s);
-
-    sysbus_init_mmio(dev, &s->io_memory);
-
-    /* Note: We need at least 1M to map the VAPIC option ROM */
-    if (!vapic && s->vapic_control & VAPIC_ENABLE_MASK &&
-        ram_size >= 1024 * 1024) {
-        vapic = sysbus_create_simple("kvmvapic", -1, NULL);
-    }
-    s->vapic = vapic;
-    if (apic_report_tpr_access && info->enable_tpr_reporting) {
-        info->enable_tpr_reporting(s, true);
-    }
-
-    return 0;
-}
-
-static void apic_dispatch_pre_save(void *opaque)
-{
-    APICCommonState *s = APIC_COMMON(opaque);
-    APICCommonClass *info = APIC_COMMON_GET_CLASS(s);
-
-    if (info->pre_save) {
-        info->pre_save(s);
-    }
-}
-
-static int apic_dispatch_post_load(void *opaque, int version_id)
-{
-    APICCommonState *s = APIC_COMMON(opaque);
-    APICCommonClass *info = APIC_COMMON_GET_CLASS(s);
-
-    if (info->post_load) {
-        info->post_load(s);
-    }
-    return 0;
-}
-
-static const VMStateDescription vmstate_apic_common = {
-    .name = "apic",
-    .version_id = 3,
-    .minimum_version_id = 3,
-    .minimum_version_id_old = 1,
-    .load_state_old = apic_load_old,
-    .pre_save = apic_dispatch_pre_save,
-    .post_load = apic_dispatch_post_load,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT32(apicbase, APICCommonState),
-        VMSTATE_UINT8(id, APICCommonState),
-        VMSTATE_UINT8(arb_id, APICCommonState),
-        VMSTATE_UINT8(tpr, APICCommonState),
-        VMSTATE_UINT32(spurious_vec, APICCommonState),
-        VMSTATE_UINT8(log_dest, APICCommonState),
-        VMSTATE_UINT8(dest_mode, APICCommonState),
-        VMSTATE_UINT32_ARRAY(isr, APICCommonState, 8),
-        VMSTATE_UINT32_ARRAY(tmr, APICCommonState, 8),
-        VMSTATE_UINT32_ARRAY(irr, APICCommonState, 8),
-        VMSTATE_UINT32_ARRAY(lvt, APICCommonState, APIC_LVT_NB),
-        VMSTATE_UINT32(esr, APICCommonState),
-        VMSTATE_UINT32_ARRAY(icr, APICCommonState, 2),
-        VMSTATE_UINT32(divide_conf, APICCommonState),
-        VMSTATE_INT32(count_shift, APICCommonState),
-        VMSTATE_UINT32(initial_count, APICCommonState),
-        VMSTATE_INT64(initial_count_load_time, APICCommonState),
-        VMSTATE_INT64(next_time, APICCommonState),
-        VMSTATE_INT64(timer_expiry,
-                      APICCommonState), /* open-coded timer state */
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static Property apic_properties_common[] = {
-    DEFINE_PROP_UINT8("id", APICCommonState, id, -1),
-    DEFINE_PROP_BIT("vapic", APICCommonState, vapic_control, VAPIC_ENABLE_BIT,
-                    true),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void apic_common_class_init(ObjectClass *klass, void *data)
-{
-    SysBusDeviceClass *sc = SYS_BUS_DEVICE_CLASS(klass);
-    DeviceClass *dc = DEVICE_CLASS(klass);
-
-    dc->vmsd = &vmstate_apic_common;
-    dc->reset = apic_reset_common;
-    dc->no_user = 1;
-    dc->props = apic_properties_common;
-    sc->init = apic_init_common;
-}
-
-static const TypeInfo apic_common_type = {
-    .name = TYPE_APIC_COMMON,
-    .parent = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(APICCommonState),
-    .class_size = sizeof(APICCommonClass),
-    .class_init = apic_common_class_init,
-    .abstract = true,
-};
-
-static void register_types(void)
-{
-    type_register_static(&apic_common_type);
-}
-
-type_init(register_types)
diff --git a/hw/apic_internal.h b/hw/apic_internal.h
deleted file mode 100644 (file)
index 578241f..0000000
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- *  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 "exec/memory.h"
-#include "hw/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 VAPIC_ENABLE_BIT                0
-#define VAPIC_ENABLE_MASK               (1 << VAPIC_ENABLE_BIT)
-
-#define MAX_APICS 255
-
-#define MSI_SPACE_SIZE                  0x100000
-
-typedef struct APICCommonState APICCommonState;
-
-#define TYPE_APIC_COMMON "apic-common"
-#define APIC_COMMON(obj) \
-     OBJECT_CHECK(APICCommonState, (obj), TYPE_APIC_COMMON)
-#define APIC_COMMON_CLASS(klass) \
-     OBJECT_CLASS_CHECK(APICCommonClass, (klass), TYPE_APIC_COMMON)
-#define APIC_COMMON_GET_CLASS(obj) \
-     OBJECT_GET_CLASS(APICCommonClass, (obj), TYPE_APIC_COMMON)
-
-typedef struct APICCommonClass
-{
-    SysBusDeviceClass parent_class;
-
-    void (*init)(APICCommonState *s);
-    void (*set_base)(APICCommonState *s, uint64_t val);
-    void (*set_tpr)(APICCommonState *s, uint8_t val);
-    uint8_t (*get_tpr)(APICCommonState *s);
-    void (*enable_tpr_reporting)(APICCommonState *s, bool enable);
-    void (*vapic_base_update)(APICCommonState *s);
-    void (*external_nmi)(APICCommonState *s);
-    void (*pre_save)(APICCommonState *s);
-    void (*post_load)(APICCommonState *s);
-} APICCommonClass;
-
-struct APICCommonState {
-    SysBusDevice busdev;
-
-    MemoryRegion io_memory;
-    X86CPU *cpu;
-    uint32_t apicbase;
-    uint8_t id;
-    uint8_t arb_id;
-    uint8_t tpr;
-    uint32_t spurious_vec;
-    uint8_t log_dest;
-    uint8_t dest_mode;
-    uint32_t isr[8];  /* in service register */
-    uint32_t tmr[8];  /* trigger mode register */
-    uint32_t irr[8]; /* interrupt request register */
-    uint32_t lvt[APIC_LVT_NB];
-    uint32_t esr; /* error register */
-    uint32_t icr[2];
-
-    uint32_t divide_conf;
-    int count_shift;
-    uint32_t initial_count;
-    int64_t initial_count_load_time;
-    int64_t next_time;
-    int idx;
-    QEMUTimer *timer;
-    int64_t timer_expiry;
-    int sipi_vector;
-    int wait_for_sipi;
-
-    uint32_t vapic_control;
-    DeviceState *vapic;
-    hwaddr vapic_paddr; /* note: persistence via kvmvapic */
-};
-
-typedef struct VAPICState {
-    uint8_t tpr;
-    uint8_t isr;
-    uint8_t zero;
-    uint8_t irr;
-    uint8_t enabled;
-} QEMU_PACKED VAPICState;
-
-extern bool apic_report_tpr_access;
-
-void apic_report_irq_delivered(int delivered);
-bool apic_next_timer(APICCommonState *s, int64_t current_time);
-void apic_enable_tpr_access_reporting(DeviceState *d, bool enable);
-void apic_enable_vapic(DeviceState *d, hwaddr paddr);
-
-void vapic_report_tpr_access(DeviceState *dev, CPUState *cpu, target_ulong ip,
-                             TPRAccess access);
-
-#endif /* !QEMU_APIC_INTERNAL_H */
diff --git a/hw/apm.c b/hw/apm.c
deleted file mode 100644 (file)
index e2846f9..0000000
--- a/hw/apm.c
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * QEMU PC APM controller Emulation
- * This is split out from acpi.c
- *
- * Copyright (c) 2006 Fabrice Bellard
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License version 2 as published by the Free Software Foundation.
- *
- * 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/>
- *
- * 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/apm.h"
-#include "hw/hw.h"
-#include "hw/pci/pci.h"
-
-//#define DEBUG
-
-#ifdef DEBUG
-# define APM_DPRINTF(format, ...)       printf(format, ## __VA_ARGS__)
-#else
-# define APM_DPRINTF(format, ...)       do { } while (0)
-#endif
-
-/* fixed I/O location */
-#define APM_CNT_IOPORT  0xb2
-#define APM_STS_IOPORT  0xb3
-
-static void apm_ioport_writeb(void *opaque, hwaddr addr, uint64_t val,
-                              unsigned size)
-{
-    APMState *apm = opaque;
-    addr &= 1;
-    APM_DPRINTF("apm_ioport_writeb addr=0x%x val=0x%02x\n", addr, val);
-    if (addr == 0) {
-        apm->apmc = val;
-
-        if (apm->callback) {
-            (apm->callback)(val, apm->arg);
-        }
-    } else {
-        apm->apms = val;
-    }
-}
-
-static uint64_t apm_ioport_readb(void *opaque, hwaddr addr, unsigned size)
-{
-    APMState *apm = opaque;
-    uint32_t val;
-
-    addr &= 1;
-    if (addr == 0) {
-        val = apm->apmc;
-    } else {
-        val = apm->apms;
-    }
-    APM_DPRINTF("apm_ioport_readb addr=0x%x val=0x%02x\n", addr, val);
-    return val;
-}
-
-const VMStateDescription vmstate_apm = {
-    .name = "APM State",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT8(apmc, APMState),
-        VMSTATE_UINT8(apms, APMState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static const MemoryRegionOps apm_ops = {
-    .read = apm_ioport_readb,
-    .write = apm_ioport_writeb,
-    .impl = {
-        .min_access_size = 1,
-        .max_access_size = 1,
-    },
-};
-
-void apm_init(PCIDevice *dev, APMState *apm, apm_ctrl_changed_t callback,
-              void *arg)
-{
-    apm->callback = callback;
-    apm->arg = arg;
-
-    /* ioport 0xb2, 0xb3 */
-    memory_region_init_io(&apm->io, &apm_ops, apm, "apm-io", 2);
-    memory_region_add_subregion(pci_address_space_io(dev), APM_CNT_IOPORT,
-                                &apm->io);
-}
diff --git a/hw/apm.h b/hw/apm.h
deleted file mode 100644 (file)
index 3edea5f..0000000
--- a/hw/apm.h
+++ /dev/null
@@ -1,25 +0,0 @@
-#ifndef APM_H
-#define APM_H
-
-#include <stdint.h>
-#include "qemu-common.h"
-#include "hw/hw.h"
-#include "exec/memory.h"
-
-typedef void (*apm_ctrl_changed_t)(uint32_t val, void *arg);
-
-typedef struct APMState {
-    uint8_t apmc;
-    uint8_t apms;
-
-    apm_ctrl_changed_t callback;
-    void *arg;
-    MemoryRegion io;
-} APMState;
-
-void apm_init(PCIDevice *dev, APMState *s, apm_ctrl_changed_t callback,
-              void *arg);
-
-extern const VMStateDescription vmstate_apm;
-
-#endif /* APM_H */
diff --git a/hw/applesmc.c b/hw/applesmc.c
deleted file mode 100644 (file)
index 44b9bac..0000000
+++ /dev/null
@@ -1,251 +0,0 @@
-/*
- *  Apple SMC controller
- *
- *  Copyright (c) 2007 Alexander Graf
- *
- *  Authors: Alexander Graf <agraf@suse.de>
- *           Susanne Graf <suse@csgraf.de>
- *
- * 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/>.
- *
- * *****************************************************************
- *
- * In all Intel-based Apple hardware there is an SMC chip to control the
- * backlight, fans and several other generic device parameters. It also
- * contains the magic keys used to dongle Mac OS X to the device.
- *
- * This driver was mostly created by looking at the Linux AppleSMC driver
- * implementation and does not support IRQ.
- *
- */
-
-#include "hw/hw.h"
-#include "hw/isa.h"
-#include "ui/console.h"
-#include "qemu/timer.h"
-
-/* #define DEBUG_SMC */
-
-#define APPLESMC_DEFAULT_IOBASE        0x300
-/* data port used by Apple SMC */
-#define APPLESMC_DATA_PORT             0x0
-/* command/status port used by Apple SMC */
-#define APPLESMC_CMD_PORT              0x4
-#define APPLESMC_NR_PORTS              32
-#define APPLESMC_MAX_DATA_LENGTH       32
-
-#define APPLESMC_READ_CMD              0x10
-#define APPLESMC_WRITE_CMD             0x11
-#define APPLESMC_GET_KEY_BY_INDEX_CMD  0x12
-#define APPLESMC_GET_KEY_TYPE_CMD      0x13
-
-#ifdef DEBUG_SMC
-#define smc_debug(...) fprintf(stderr, "AppleSMC: " __VA_ARGS__)
-#else
-#define smc_debug(...) do { } while(0)
-#endif
-
-static char default_osk[64] = "This is a dummy key. Enter the real key "
-                              "using the -osk parameter";
-
-struct AppleSMCData {
-    uint8_t len;
-    const char *key;
-    const char *data;
-    QLIST_ENTRY(AppleSMCData) node;
-};
-
-struct AppleSMCStatus {
-    ISADevice dev;
-    uint32_t iobase;
-    uint8_t cmd;
-    uint8_t status;
-    uint8_t key[4];
-    uint8_t read_pos;
-    uint8_t data_len;
-    uint8_t data_pos;
-    uint8_t data[255];
-    uint8_t charactic[4];
-    char *osk;
-    QLIST_HEAD(, AppleSMCData) data_def;
-};
-
-static void applesmc_io_cmd_writeb(void *opaque, uint32_t addr, uint32_t val)
-{
-    struct AppleSMCStatus *s = opaque;
-
-    smc_debug("CMD Write B: %#x = %#x\n", addr, val);
-    switch(val) {
-        case APPLESMC_READ_CMD:
-            s->status = 0x0c;
-            break;
-    }
-    s->cmd = val;
-    s->read_pos = 0;
-    s->data_pos = 0;
-}
-
-static void applesmc_fill_data(struct AppleSMCStatus *s)
-{
-    struct AppleSMCData *d;
-
-    QLIST_FOREACH(d, &s->data_def, node) {
-        if (!memcmp(d->key, s->key, 4)) {
-            smc_debug("Key matched (%s Len=%d Data=%s)\n", d->key,
-                      d->len, d->data);
-            memcpy(s->data, d->data, d->len);
-            return;
-        }
-    }
-}
-
-static void applesmc_io_data_writeb(void *opaque, uint32_t addr, uint32_t val)
-{
-    struct AppleSMCStatus *s = opaque;
-
-    smc_debug("DATA Write B: %#x = %#x\n", addr, val);
-    switch(s->cmd) {
-        case APPLESMC_READ_CMD:
-            if(s->read_pos < 4) {
-                s->key[s->read_pos] = val;
-                s->status = 0x04;
-            } else if(s->read_pos == 4) {
-                s->data_len = val;
-                s->status = 0x05;
-                s->data_pos = 0;
-                smc_debug("Key = %c%c%c%c Len = %d\n", s->key[0],
-                          s->key[1], s->key[2], s->key[3], val);
-                applesmc_fill_data(s);
-            }
-            s->read_pos++;
-            break;
-    }
-}
-
-static uint32_t applesmc_io_data_readb(void *opaque, uint32_t addr1)
-{
-    struct AppleSMCStatus *s = opaque;
-    uint8_t retval = 0;
-
-    switch(s->cmd) {
-        case APPLESMC_READ_CMD:
-            if(s->data_pos < s->data_len) {
-                retval = s->data[s->data_pos];
-                smc_debug("READ_DATA[%d] = %#hhx\n", s->data_pos,
-                          retval);
-                s->data_pos++;
-                if(s->data_pos == s->data_len) {
-                    s->status = 0x00;
-                    smc_debug("EOF\n");
-                } else
-                    s->status = 0x05;
-            }
-    }
-    smc_debug("DATA Read b: %#x = %#x\n", addr1, retval);
-
-    return retval;
-}
-
-static uint32_t applesmc_io_cmd_readb(void *opaque, uint32_t addr1)
-{
-    struct AppleSMCStatus *s = opaque;
-
-    smc_debug("CMD Read B: %#x\n", addr1);
-    return s->status;
-}
-
-static void applesmc_add_key(struct AppleSMCStatus *s, const char *key,
-                             int len, const char *data)
-{
-    struct AppleSMCData *def;
-
-    def = g_malloc0(sizeof(struct AppleSMCData));
-    def->key = key;
-    def->len = len;
-    def->data = data;
-
-    QLIST_INSERT_HEAD(&s->data_def, def, node);
-}
-
-static void qdev_applesmc_isa_reset(DeviceState *dev)
-{
-    struct AppleSMCStatus *s = DO_UPCAST(struct AppleSMCStatus, dev.qdev, dev);
-    struct AppleSMCData *d, *next;
-
-    /* Remove existing entries */
-    QLIST_FOREACH_SAFE(d, &s->data_def, node, next) {
-        QLIST_REMOVE(d, node);
-    }
-
-    applesmc_add_key(s, "REV ", 6, "\x01\x13\x0f\x00\x00\x03");
-    applesmc_add_key(s, "OSK0", 32, s->osk);
-    applesmc_add_key(s, "OSK1", 32, s->osk + 32);
-    applesmc_add_key(s, "NATJ", 1, "\0");
-    applesmc_add_key(s, "MSSP", 1, "\0");
-    applesmc_add_key(s, "MSSD", 1, "\0x3");
-}
-
-static int applesmc_isa_init(ISADevice *dev)
-{
-    struct AppleSMCStatus *s = DO_UPCAST(struct AppleSMCStatus, dev, dev);
-
-    register_ioport_read(s->iobase + APPLESMC_DATA_PORT, 4, 1,
-                         applesmc_io_data_readb, s);
-    register_ioport_read(s->iobase + APPLESMC_CMD_PORT, 4, 1,
-                         applesmc_io_cmd_readb, s);
-    register_ioport_write(s->iobase + APPLESMC_DATA_PORT, 4, 1,
-                          applesmc_io_data_writeb, s);
-    register_ioport_write(s->iobase + APPLESMC_CMD_PORT, 4, 1,
-                          applesmc_io_cmd_writeb, s);
-
-    if (!s->osk || (strlen(s->osk) != 64)) {
-        fprintf(stderr, "WARNING: Using AppleSMC with invalid key\n");
-        s->osk = default_osk;
-    }
-
-    QLIST_INIT(&s->data_def);
-    qdev_applesmc_isa_reset(&dev->qdev);
-
-    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 const 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_types(void)
-{
-    type_register_static(&applesmc_isa_info);
-}
-
-type_init(applesmc_register_types)
diff --git a/hw/arm-misc.h b/hw/arm-misc.h
deleted file mode 100644 (file)
index 7b2b02d..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Misc ARM declarations
- *
- * Copyright (c) 2006 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the LGPL.
- *
- */
-
-#ifndef ARM_MISC_H
-#define ARM_MISC_H 1
-
-#include "exec/memory.h"
-#include "hw/irq.h"
-
-/* The CPU is also modelled as an interrupt controller.  */
-#define ARM_PIC_CPU_IRQ 0
-#define ARM_PIC_CPU_FIQ 1
-qemu_irq *arm_pic_init_cpu(ARMCPU *cpu);
-
-/* armv7m.c */
-qemu_irq *armv7m_init(MemoryRegion *address_space_mem,
-                      int flash_size, int sram_size,
-                      const char *kernel_filename, const char *cpu_model);
-
-/* arm_boot.c */
-struct arm_boot_info {
-    uint64_t ram_size;
-    const char *kernel_filename;
-    const char *kernel_cmdline;
-    const char *initrd_filename;
-    const char *dtb_filename;
-    hwaddr 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.
-     */
-    hwaddr smp_loader_start;
-    hwaddr smp_bootreg_addr;
-    hwaddr gic_cpu_if_addr;
-    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 mimicking 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 the
-     * secondary CPUs to point at this boot blob.
-     */
-    void (*write_secondary_boot)(ARMCPU *cpu,
-                                 const struct arm_boot_info *info);
-    void (*secondary_cpu_reset_hook)(ARMCPU *cpu,
-                                     const struct arm_boot_info *info);
-    /* Used internally by arm_boot.c */
-    int is_linux;
-    hwaddr initrd_start;
-    hwaddr initrd_size;
-    hwaddr entry;
-};
-void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info);
-
-/* Multiplication factor to convert from system clock ticks to qemu timer
-   ticks.  */
-extern int system_clock_scale;
-
-#endif /* !ARM_MISC_H */
index f5f7d0e53920c5adc86a101b85fa81d028de9938..9e3a06fc185c9445bb4a2a65e5a5907854e473e0 100644 (file)
@@ -1,36 +1,7 @@
-obj-y += zynq_slcr.o
-obj-y += xilinx_spips.o
-obj-y += arm_gic.o arm_gic_common.o
-obj-y += a9scu.o
-obj-y += realview_gic.o arm_sysctl.o arm11mpcore.o a9mpcore.o
-obj-y += exynos4210_gic.o exynos4210_combiner.o
-obj-y += exynos4210_uart.o exynos4210_pwm.o
-obj-y += exynos4210_pmu.o exynos4210_mct.o exynos4210_fimd.o
-obj-y += exynos4210_rtc.o exynos4210_i2c.o
-obj-y += arm_mptimer.o a15mpcore.o
-obj-y += armv7m_nvic.o stellaris_enet.o
-obj-y += pxa2xx_timer.o pxa2xx_dma.o
-obj-y += pxa2xx_lcd.o pxa2xx_mmci.o pxa2xx_pcmcia.o pxa2xx_keypad.o
-obj-y += zaurus.o ide/microdrive.o tc6393xb.o
-obj-y += omap_lcdc.o omap_dma.o omap_clk.o omap_mmc.o omap_i2c.o \
-                omap_gpio.o omap_intc.o omap_uart.o
-obj-y += 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-y += tsc210x.o
-obj-y += blizzard.o onenand.o cbus.o tusb6010.o usb/hcd-musb.o
-obj-y += mst_fpga.o
-obj-y += bitbang_i2c.o marvell_88w8618_audio.o
-obj-y += framebuffer.o
-obj-y += strongarm.o
-obj-y += imx_serial.o imx_ccm.o imx_timer.o imx_avic.o
-obj-$(CONFIG_KVM) += kvm/arm_gic.o
-
-obj-y := $(addprefix ../,$(obj-y))
-
 obj-y += boot.o collie.o exynos4_boards.o gumstix.o highbank.o
 obj-y += integratorcp.o kzm.o mainstone.o musicpal.o nseries.o
 obj-y += omap_sx1.o palm.o pic_cpu.o realview.o spitz.o stellaris.o
 obj-y += tosa.o versatilepb.o vexpress.o xilinx_zynq.o z2.o
 
 obj-y += armv7m.o exynos4210.o pxa2xx.o pxa2xx_gpio.o pxa2xx_pic.o
-obj-y += omap1.o omap2.o
+obj-y += omap1.o omap2.o strongarm.o
index 1d5bb592c49a81e24a6aae2a2b5a6e96d006b309..a4bdd5f30f387524b61f2701cf86e1724e05cdc2 100644 (file)
@@ -8,7 +8,7 @@
  */
 
 #include "hw/sysbus.h"
-#include "hw/arm-misc.h"
+#include "hw/arm.h"
 #include "hw/loader.h"
 #include "elf.h"
 
index 43253fd34a2d4844bc513df1d2e0a6761ba547c6..c79c590171af2e51953ad710c9735c03e7c3e40e 100644 (file)
@@ -9,7 +9,7 @@
 
 #include "config.h"
 #include "hw/hw.h"
-#include "hw/arm-misc.h"
+#include "hw/arm.h"
 #include "sysemu/sysemu.h"
 #include "hw/boards.h"
 #include "hw/loader.h"
index 17fddc8d5b08a4df102a325e71149723260de135..5420bb4ba819b53f9c4b98f6839a864aa45fcf7d 100644 (file)
 #include "hw/hw.h"
 #include "hw/sysbus.h"
 #include "hw/boards.h"
-#include "hw/devices.h"
-#include "hw/strongarm.h"
-#include "hw/arm-misc.h"
-#include "hw/flash.h"
+#include "hw/arm/devices.h"
+#include "strongarm.h"
+#include "hw/arm.h"
+#include "hw/block/flash.h"
 #include "sysemu/blockdev.h"
 #include "exec/address-spaces.h"
 
index 4592514bb26a8aaedbfd8ca35bf19a8c61071636..78b8b7407a450feab70af3d6f5887794e379e89c 100644 (file)
@@ -24,9 +24,9 @@
 #include "hw/boards.h"
 #include "sysemu/sysemu.h"
 #include "hw/sysbus.h"
-#include "hw/arm-misc.h"
+#include "hw/arm.h"
 #include "hw/loader.h"
-#include "hw/exynos4210.h"
+#include "hw/arm/exynos4210.h"
 #include "hw/usb/hcd-ehci.h"
 
 #define EXYNOS4210_CHIPID_ADDR         0x10000000
index 473da349bd1d4df8878489f4fc897aa3831bd693..ba14a1fd09999f3254a08e30961283788abd7d99 100644 (file)
@@ -24,9 +24,9 @@
 #include "sysemu/sysemu.h"
 #include "hw/sysbus.h"
 #include "net/net.h"
-#include "hw/arm-misc.h"
+#include "hw/arm.h"
 #include "exec/address-spaces.h"
-#include "hw/exynos4210.h"
+#include "hw/arm/exynos4210.h"
 #include "hw/boards.h"
 
 #undef DEBUG
index 8859b7392fe70d9bc381338da83b3291705d3da9..4d800c9547d0c082f897569c9b9dce157971fb49 100644 (file)
  */
 
 #include "hw/hw.h"
-#include "hw/pxa.h"
+#include "hw/arm/pxa.h"
 #include "net/net.h"
-#include "hw/flash.h"
-#include "hw/devices.h"
+#include "hw/block/flash.h"
+#include "hw/arm/devices.h"
 #include "hw/boards.h"
 #include "sysemu/blockdev.h"
 #include "exec/address-spaces.h"
index a622224dccedda7b589f7fbde28d73b9f00cf05a..58f73c1bd30c058ccf16cd12eebdcfbae335573e 100644 (file)
@@ -18,8 +18,8 @@
  */
 
 #include "hw/sysbus.h"
-#include "hw/arm-misc.h"
-#include "hw/devices.h"
+#include "hw/arm.h"
+#include "hw/arm/devices.h"
 #include "hw/loader.h"
 #include "net/net.h"
 #include "sysemu/sysemu.h"
index e0ba327a5545d249eee94ec03afff9725fe38c26..8d0fb7584abda5f9909fb2ce0dacf3cbcafa0592 100644 (file)
@@ -8,9 +8,9 @@
  */
 
 #include "hw/sysbus.h"
-#include "hw/devices.h"
+#include "hw/arm/devices.h"
 #include "hw/boards.h"
-#include "hw/arm-misc.h"
+#include "hw/arm.h"
 #include "net/net.h"
 #include "exec/address-spaces.h"
 #include "sysemu/sysemu.h"
index ec50a319acb97ea1b32d0c5edec9ac038398c446..46264cdeacb0067962b0be1d8d0df1ed2128bef0 100644 (file)
 #include "hw/sysbus.h"
 #include "exec/address-spaces.h"
 #include "hw/hw.h"
-#include "hw/arm-misc.h"
-#include "hw/devices.h"
+#include "hw/arm.h"
+#include "hw/arm/devices.h"
 #include "net/net.h"
 #include "sysemu/sysemu.h"
 #include "hw/boards.h"
-#include "hw/serial.h"
-#include "hw/imx.h"
+#include "hw/char/serial.h"
+#include "hw/arm/imx.h"
 
     /* Memory map for Kzm Emulation Baseboard:
      * 0x00000000-0x00003fff 16k secure ROM       IGNORED
index aea908f0365f175cc14c4b13a785cc6d577f5c92..b78e6f00d30706ef1b266db4c5f70c6f48e33e01 100644 (file)
  * GNU GPL, version 2 or (at your option) any later version.
  */
 #include "hw/hw.h"
-#include "hw/pxa.h"
-#include "hw/arm-misc.h"
+#include "hw/arm/pxa.h"
+#include "hw/arm.h"
 #include "net/net.h"
-#include "hw/devices.h"
+#include "hw/arm/devices.h"
 #include "hw/boards.h"
-#include "hw/flash.h"
+#include "hw/block/flash.h"
 #include "sysemu/blockdev.h"
 #include "hw/sysbus.h"
 #include "exec/address-spaces.h"
index ea8473db3ecefdb0b038ab269f2737be0cdea949..97b13405e652f242edb5bb23cad679b36c53eca9 100644 (file)
  */
 
 #include "hw/sysbus.h"
-#include "hw/arm-misc.h"
-#include "hw/devices.h"
+#include "hw/arm.h"
+#include "hw/arm/devices.h"
 #include "net/net.h"
 #include "sysemu/sysemu.h"
 #include "hw/boards.h"
-#include "hw/serial.h"
+#include "hw/char/serial.h"
 #include "qemu/timer.h"
 #include "hw/ptimer.h"
 #include "block/block.h"
-#include "hw/flash.h"
+#include "hw/block/flash.h"
 #include "ui/console.h"
-#include "hw/i2c.h"
+#include "hw/i2c/i2c.h"
 #include "sysemu/blockdev.h"
 #include "exec/address-spaces.h"
 #include "ui/pixel_ops.h"
index 6747c1c5472568c9d7b65e6a0c08515b472cc122..ba8dc3e01ad85f98613a9a7e34da63472d6d65a4 100644 (file)
 
 #include "qemu-common.h"
 #include "sysemu/sysemu.h"
-#include "hw/omap.h"
-#include "hw/arm-misc.h"
+#include "hw/arm/omap.h"
+#include "hw/arm.h"
 #include "hw/irq.h"
 #include "ui/console.h"
 #include "hw/boards.h"
-#include "hw/i2c.h"
-#include "hw/devices.h"
-#include "hw/flash.h"
+#include "hw/i2c/i2c.h"
+#include "hw/arm/devices.h"
+#include "hw/block/flash.h"
 #include "hw/hw.h"
 #include "hw/bt.h"
 #include "hw/loader.h"
@@ -129,8 +129,6 @@ static void n800_mmc_cs_cb(void *opaque, int line, int level)
     /* TODO: this seems to actually be connected to the menelaus, to
      * which also both MMC slots connect.  */
     omap_mmc_enable((struct omap_mmc_s *) opaque, !level);
-
-    printf("%s: MMC slot %i active\n", __FUNCTION__, level + 1);
 }
 
 static void n8x0_gpio_setup(struct n800_s *s)
@@ -428,9 +426,6 @@ struct mipid_s {
 
 static void mipid_reset(struct mipid_s *s)
 {
-    if (!s->sleep)
-        fprintf(stderr, "%s: Display off\n", __FUNCTION__);
-
     s->pm = 0;
     s->cmd = 0;
 
@@ -578,11 +573,9 @@ static uint32_t mipid_txrx(void *opaque, uint32_t cmd, int len)
 
     case 0x28: /* DISPOFF */
         s->onoff = 0;
-        fprintf(stderr, "%s: Display off\n", __FUNCTION__);
         break;
     case 0x29: /* DISPON */
         s->onoff = 1;
-        fprintf(stderr, "%s: Display on\n", __FUNCTION__);
         break;
 
     case 0x2a: /* CASET */
@@ -669,7 +662,8 @@ static uint32_t mipid_txrx(void *opaque, uint32_t cmd, int len)
 
     default:
     bad_cmd:
-        fprintf(stderr, "%s: unknown command %02x\n", __FUNCTION__, s->cmd);
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: unknown command %02x\n", __func__, s->cmd);
         break;
     }
 
@@ -1347,7 +1341,6 @@ static void n8x0_init(QEMUMachineInitArgs *args,
 
     if (option_rom[0].name &&
         (args->boot_device[0] == 'n' || !args->kernel_filename)) {
-        int rom_size;
         uint8_t nolo_tags[0x10000];
         /* No, wait, better start at the ROM.  */
         s->mpu->cpu->env.regs[15] = OMAP2_Q2_BASE + 0x400000;
@@ -1361,10 +1354,9 @@ static void n8x0_init(QEMUMachineInitArgs *args,
          *
          * The code above is for loading the `zImage' file from Nokia
          * images.  */
-        rom_size = load_image_targphys(option_rom[0].name,
-                                       OMAP2_Q2_BASE + 0x400000,
-                                       sdram_size - 0x400000);
-        printf("%i bytes of image loaded\n", rom_size);
+        load_image_targphys(option_rom[0].name,
+                            OMAP2_Q2_BASE + 0x400000,
+                            sdram_size - 0x400000);
 
         n800_setup_nolo_tags(nolo_tags);
         cpu_physical_memory_write(OMAP2_SRAM_BASE, nolo_tags, 0x10000);
index 3245c62e68fc8db581cda441e554511012bcb28d..17caa618221819c58e3d5a2d7ec84d2357810e05 100644 (file)
  * with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 #include "hw/hw.h"
-#include "hw/arm-misc.h"
-#include "hw/omap.h"
+#include "hw/arm.h"
+#include "hw/arm/omap.h"
 #include "sysemu/sysemu.h"
-#include "hw/soc_dma.h"
+#include "hw/arm/soc_dma.h"
 #include "sysemu/blockdev.h"
 #include "qemu/range.h"
 #include "hw/sysbus.h"
index 0a2cd7bab668cb768c86dac43c22124f07b5d6b7..010c483e8ce70c9df4f5d68e5a5295fe815f2ecc 100644 (file)
 
 #include "sysemu/blockdev.h"
 #include "hw/hw.h"
-#include "hw/arm-misc.h"
-#include "hw/omap.h"
+#include "hw/arm.h"
+#include "hw/arm/omap.h"
 #include "sysemu/sysemu.h"
 #include "qemu/timer.h"
 #include "char/char.h"
-#include "hw/flash.h"
-#include "hw/soc_dma.h"
+#include "hw/block/flash.h"
+#include "hw/arm/soc_dma.h"
 #include "hw/sysbus.h"
 #include "audio/audio.h"
 
index 85982334bdbda4eba0d6f4a6718b5929a064c5e5..aa85602aa6e01ae38bcc1587174a1e97e42e6f70 100644 (file)
  */
 #include "hw/hw.h"
 #include "ui/console.h"
-#include "hw/omap.h"
+#include "hw/arm/omap.h"
 #include "hw/boards.h"
-#include "hw/arm-misc.h"
-#include "hw/flash.h"
+#include "hw/arm.h"
+#include "hw/block/flash.h"
 #include "sysemu/blockdev.h"
 #include "exec/address-spaces.h"
 
index baeb5850673f9f4e96fcef651c44a7fde82d9023..0bc11aed2bdea317274df9459ce409957990de19 100644 (file)
 #include "audio/audio.h"
 #include "sysemu/sysemu.h"
 #include "ui/console.h"
-#include "hw/omap.h"
+#include "hw/arm/omap.h"
 #include "hw/boards.h"
-#include "hw/arm-misc.h"
-#include "hw/devices.h"
+#include "hw/arm.h"
+#include "hw/arm/devices.h"
 #include "hw/loader.h"
 #include "exec/address-spaces.h"
 
index 3a3f06566b0b545d5fe8849f0f962487f44f0948..787767f51f66b11fb100bf4572264099fb8ccb8d 100644 (file)
@@ -8,7 +8,7 @@
  */
 
 #include "hw/hw.h"
-#include "hw/arm-misc.h"
+#include "hw/arm.h"
 #include "sysemu/kvm.h"
 
 /* Input 0 is IRQ and input 1 is FIQ.  */
index b7ca511d45c04d3a5312ef0602ce5ee9f48adc04..bbecc770ed8f7bcefadd4b1d4f8eb624a6f34fd0 100644 (file)
@@ -8,10 +8,10 @@
  */
 
 #include "hw/sysbus.h"
-#include "hw/pxa.h"
+#include "hw/arm/pxa.h"
 #include "sysemu/sysemu.h"
-#include "hw/serial.h"
-#include "hw/i2c.h"
+#include "hw/char/serial.h"
+#include "hw/i2c/i2c.h"
 #include "hw/ssi.h"
 #include "char/char.h"
 #include "sysemu/blockdev.h"
index 55ebcd724a873cf0059de95a4672517ebaa9a9b2..fa31575edd3730800a9a60cba23a20f983344ba6 100644 (file)
@@ -9,7 +9,7 @@
 
 #include "hw/hw.h"
 #include "hw/sysbus.h"
-#include "hw/pxa.h"
+#include "hw/arm/pxa.h"
 
 #define PXA2XX_GPIO_BANKS      4
 
index 25e90895e1ddf0ecbc25a909e8d78975a2e21899..835d07c3410b1b416cce08ec4057cd6f9263322a 100644 (file)
@@ -9,7 +9,7 @@
  */
 
 #include "hw/hw.h"
-#include "hw/pxa.h"
+#include "hw/arm/pxa.h"
 #include "hw/sysbus.h"
 
 #define ICIP   0x00    /* Interrupt Controller IRQ Pending register */
index 5fb490c832a37aa2ae7c16d9e765464670803273..afd52d31befd82b586ebaa44c6f4f2c6b73a1683 100644 (file)
@@ -8,14 +8,14 @@
  */
 
 #include "hw/sysbus.h"
-#include "hw/arm-misc.h"
-#include "hw/primecell.h"
-#include "hw/devices.h"
+#include "hw/arm.h"
+#include "hw/arm/primecell.h"
+#include "hw/arm/devices.h"
 #include "hw/pci/pci.h"
 #include "net/net.h"
 #include "sysemu/sysemu.h"
 #include "hw/boards.h"
-#include "hw/i2c.h"
+#include "hw/i2c/i2c.h"
 #include "sysemu/blockdev.h"
 #include "exec/address-spaces.h"
 
index f5832bea935f10a58f465e00d0539b6a70360d9e..fa434dc68eb64c715d8063a942f0653fded438e1 100644 (file)
  */
 
 #include "hw/hw.h"
-#include "hw/pxa.h"
-#include "hw/arm-misc.h"
+#include "hw/arm/pxa.h"
+#include "hw/arm.h"
 #include "sysemu/sysemu.h"
 #include "hw/pcmcia.h"
-#include "hw/i2c.h"
+#include "hw/i2c/i2c.h"
 #include "hw/ssi.h"
-#include "hw/flash.h"
+#include "hw/block/flash.h"
 #include "qemu/timer.h"
-#include "hw/devices.h"
-#include "hw/sharpsl.h"
+#include "hw/arm/devices.h"
+#include "hw/arm/sharpsl.h"
 #include "ui/console.h"
 #include "block/block.h"
 #include "audio/audio.h"
index f4ce7945f39a1d9a1cc4ca987867c8f5295286c7..952087ce2dd0409707b226347462399cc5e97188 100644 (file)
@@ -9,10 +9,10 @@
 
 #include "hw/sysbus.h"
 #include "hw/ssi.h"
-#include "hw/arm-misc.h"
-#include "hw/devices.h"
+#include "hw/arm.h"
+#include "hw/arm/devices.h"
 #include "qemu/timer.h"
-#include "hw/i2c.h"
+#include "hw/i2c/i2c.h"
 #include "net/net.h"
 #include "hw/boards.h"
 #include "exec/address-spaces.h"
diff --git a/hw/arm/strongarm.c b/hw/arm/strongarm.c
new file mode 100644 (file)
index 0000000..5873a3c
--- /dev/null
@@ -0,0 +1,1623 @@
+/*
+ * StrongARM SA-1100/SA-1110 emulation
+ *
+ * Copyright (C) 2011 Dmitry Eremin-Solenikov
+ *
+ * Largely based on StrongARM emulation:
+ * Copyright (c) 2006 Openedhand Ltd.
+ * Written by Andrzej Zaborowski <balrog@zabor.org>
+ *
+ * UART code based on QEMU 16550A UART emulation
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ * Copyright (c) 2008 Citrix Systems, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  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/>.
+ *
+ *  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/sysbus.h"
+#include "strongarm.h"
+#include "qemu/error-report.h"
+#include "hw/arm.h"
+#include "char/char.h"
+#include "sysemu/sysemu.h"
+#include "hw/ssi.h"
+
+//#define DEBUG
+
+/*
+ TODO
+ - Implement cp15, c14 ?
+ - Implement cp15, c15 !!! (idle used in L)
+ - Implement idle mode handling/DIM
+ - Implement sleep mode/Wake sources
+ - Implement reset control
+ - Implement memory control regs
+ - PCMCIA handling
+ - Maybe support MBGNT/MBREQ
+ - DMA channels
+ - GPCLK
+ - IrDA
+ - MCP
+ - Enhance UART with modem signals
+ */
+
+#ifdef DEBUG
+# define DPRINTF(format, ...) printf(format , ## __VA_ARGS__)
+#else
+# define DPRINTF(format, ...) do { } while (0)
+#endif
+
+static struct {
+    hwaddr io_base;
+    int irq;
+} sa_serial[] = {
+    { 0x80010000, SA_PIC_UART1 },
+    { 0x80030000, SA_PIC_UART2 },
+    { 0x80050000, SA_PIC_UART3 },
+    { 0, 0 }
+};
+
+/* Interrupt Controller */
+typedef struct {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    qemu_irq    irq;
+    qemu_irq    fiq;
+
+    uint32_t pending;
+    uint32_t enabled;
+    uint32_t is_fiq;
+    uint32_t int_idle;
+} StrongARMPICState;
+
+#define ICIP    0x00
+#define ICMR    0x04
+#define ICLR    0x08
+#define ICFP    0x10
+#define ICPR    0x20
+#define ICCR    0x0c
+
+#define SA_PIC_SRCS     32
+
+
+static void strongarm_pic_update(void *opaque)
+{
+    StrongARMPICState *s = opaque;
+
+    /* FIXME: reflect DIM */
+    qemu_set_irq(s->fiq, s->pending & s->enabled &  s->is_fiq);
+    qemu_set_irq(s->irq, s->pending & s->enabled & ~s->is_fiq);
+}
+
+static void strongarm_pic_set_irq(void *opaque, int irq, int level)
+{
+    StrongARMPICState *s = opaque;
+
+    if (level) {
+        s->pending |= 1 << irq;
+    } else {
+        s->pending &= ~(1 << irq);
+    }
+
+    strongarm_pic_update(s);
+}
+
+static uint64_t strongarm_pic_mem_read(void *opaque, hwaddr offset,
+                                       unsigned size)
+{
+    StrongARMPICState *s = opaque;
+
+    switch (offset) {
+    case ICIP:
+        return s->pending & ~s->is_fiq & s->enabled;
+    case ICMR:
+        return s->enabled;
+    case ICLR:
+        return s->is_fiq;
+    case ICCR:
+        return s->int_idle == 0;
+    case ICFP:
+        return s->pending & s->is_fiq & s->enabled;
+    case ICPR:
+        return s->pending;
+    default:
+        printf("%s: Bad register offset 0x" TARGET_FMT_plx "\n",
+                        __func__, offset);
+        return 0;
+    }
+}
+
+static void strongarm_pic_mem_write(void *opaque, hwaddr offset,
+                                    uint64_t value, unsigned size)
+{
+    StrongARMPICState *s = opaque;
+
+    switch (offset) {
+    case ICMR:
+        s->enabled = value;
+        break;
+    case ICLR:
+        s->is_fiq = value;
+        break;
+    case ICCR:
+        s->int_idle = (value & 1) ? 0 : ~0;
+        break;
+    default:
+        printf("%s: Bad register offset 0x" TARGET_FMT_plx "\n",
+                        __func__, offset);
+        break;
+    }
+    strongarm_pic_update(s);
+}
+
+static const MemoryRegionOps strongarm_pic_ops = {
+    .read = strongarm_pic_mem_read,
+    .write = strongarm_pic_mem_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int strongarm_pic_initfn(SysBusDevice *dev)
+{
+    StrongARMPICState *s = FROM_SYSBUS(StrongARMPICState, dev);
+
+    qdev_init_gpio_in(&dev->qdev, strongarm_pic_set_irq, SA_PIC_SRCS);
+    memory_region_init_io(&s->iomem, &strongarm_pic_ops, s, "pic", 0x1000);
+    sysbus_init_mmio(dev, &s->iomem);
+    sysbus_init_irq(dev, &s->irq);
+    sysbus_init_irq(dev, &s->fiq);
+
+    return 0;
+}
+
+static int strongarm_pic_post_load(void *opaque, int version_id)
+{
+    strongarm_pic_update(opaque);
+    return 0;
+}
+
+static VMStateDescription vmstate_strongarm_pic_regs = {
+    .name = "strongarm_pic",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .post_load = strongarm_pic_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(pending, StrongARMPICState),
+        VMSTATE_UINT32(enabled, StrongARMPICState),
+        VMSTATE_UINT32(is_fiq, StrongARMPICState),
+        VMSTATE_UINT32(int_idle, StrongARMPICState),
+        VMSTATE_END_OF_LIST(),
+    },
+};
+
+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 const 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 */
+#define RTAR 0x00 /* RTC Alarm register */
+#define RCNR 0x04 /* RTC Counter register */
+#define RTTR 0x08 /* RTC Timer Trim register */
+#define RTSR 0x10 /* RTC Status register */
+
+#define RTSR_AL (1 << 0) /* RTC Alarm detected */
+#define RTSR_HZ (1 << 1) /* RTC 1Hz detected */
+#define RTSR_ALE (1 << 2) /* RTC Alarm enable */
+#define RTSR_HZE (1 << 3) /* RTC 1Hz enable */
+
+/* 16 LSB of RTTR are clockdiv for internal trim logic,
+ * trim delete isn't emulated, so
+ * f = 32 768 / (RTTR_trim + 1) */
+
+typedef struct {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    uint32_t rttr;
+    uint32_t rtsr;
+    uint32_t rtar;
+    uint32_t last_rcnr;
+    int64_t last_hz;
+    QEMUTimer *rtc_alarm;
+    QEMUTimer *rtc_hz;
+    qemu_irq rtc_irq;
+    qemu_irq rtc_hz_irq;
+} StrongARMRTCState;
+
+static inline void strongarm_rtc_int_update(StrongARMRTCState *s)
+{
+    qemu_set_irq(s->rtc_irq, s->rtsr & RTSR_AL);
+    qemu_set_irq(s->rtc_hz_irq, s->rtsr & RTSR_HZ);
+}
+
+static void strongarm_rtc_hzupdate(StrongARMRTCState *s)
+{
+    int64_t rt = qemu_get_clock_ms(rtc_clock);
+    s->last_rcnr += ((rt - s->last_hz) << 15) /
+            (1000 * ((s->rttr & 0xffff) + 1));
+    s->last_hz = rt;
+}
+
+static inline void strongarm_rtc_timer_update(StrongARMRTCState *s)
+{
+    if ((s->rtsr & RTSR_HZE) && !(s->rtsr & RTSR_HZ)) {
+        qemu_mod_timer(s->rtc_hz, s->last_hz + 1000);
+    } else {
+        qemu_del_timer(s->rtc_hz);
+    }
+
+    if ((s->rtsr & RTSR_ALE) && !(s->rtsr & RTSR_AL)) {
+        qemu_mod_timer(s->rtc_alarm, s->last_hz +
+                (((s->rtar - s->last_rcnr) * 1000 *
+                  ((s->rttr & 0xffff) + 1)) >> 15));
+    } else {
+        qemu_del_timer(s->rtc_alarm);
+    }
+}
+
+static inline void strongarm_rtc_alarm_tick(void *opaque)
+{
+    StrongARMRTCState *s = opaque;
+    s->rtsr |= RTSR_AL;
+    strongarm_rtc_timer_update(s);
+    strongarm_rtc_int_update(s);
+}
+
+static inline void strongarm_rtc_hz_tick(void *opaque)
+{
+    StrongARMRTCState *s = opaque;
+    s->rtsr |= RTSR_HZ;
+    strongarm_rtc_timer_update(s);
+    strongarm_rtc_int_update(s);
+}
+
+static uint64_t strongarm_rtc_read(void *opaque, hwaddr addr,
+                                   unsigned size)
+{
+    StrongARMRTCState *s = opaque;
+
+    switch (addr) {
+    case RTTR:
+        return s->rttr;
+    case RTSR:
+        return s->rtsr;
+    case RTAR:
+        return s->rtar;
+    case RCNR:
+        return s->last_rcnr +
+                ((qemu_get_clock_ms(rtc_clock) - s->last_hz) << 15) /
+                (1000 * ((s->rttr & 0xffff) + 1));
+    default:
+        printf("%s: Bad register 0x" TARGET_FMT_plx "\n", __func__, addr);
+        return 0;
+    }
+}
+
+static void strongarm_rtc_write(void *opaque, hwaddr addr,
+                                uint64_t value, unsigned size)
+{
+    StrongARMRTCState *s = opaque;
+    uint32_t old_rtsr;
+
+    switch (addr) {
+    case RTTR:
+        strongarm_rtc_hzupdate(s);
+        s->rttr = value;
+        strongarm_rtc_timer_update(s);
+        break;
+
+    case RTSR:
+        old_rtsr = s->rtsr;
+        s->rtsr = (value & (RTSR_ALE | RTSR_HZE)) |
+                  (s->rtsr & ~(value & (RTSR_AL | RTSR_HZ)));
+
+        if (s->rtsr != old_rtsr) {
+            strongarm_rtc_timer_update(s);
+        }
+
+        strongarm_rtc_int_update(s);
+        break;
+
+    case RTAR:
+        s->rtar = value;
+        strongarm_rtc_timer_update(s);
+        break;
+
+    case RCNR:
+        strongarm_rtc_hzupdate(s);
+        s->last_rcnr = value;
+        strongarm_rtc_timer_update(s);
+        break;
+
+    default:
+        printf("%s: Bad register 0x" TARGET_FMT_plx "\n", __func__, addr);
+    }
+}
+
+static const MemoryRegionOps strongarm_rtc_ops = {
+    .read = strongarm_rtc_read,
+    .write = strongarm_rtc_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int strongarm_rtc_init(SysBusDevice *dev)
+{
+    StrongARMRTCState *s = FROM_SYSBUS(StrongARMRTCState, dev);
+    struct tm tm;
+
+    s->rttr = 0x0;
+    s->rtsr = 0;
+
+    qemu_get_timedate(&tm, 0);
+
+    s->last_rcnr = (uint32_t) mktimegm(&tm);
+    s->last_hz = qemu_get_clock_ms(rtc_clock);
+
+    s->rtc_alarm = qemu_new_timer_ms(rtc_clock, strongarm_rtc_alarm_tick, s);
+    s->rtc_hz = qemu_new_timer_ms(rtc_clock, strongarm_rtc_hz_tick, s);
+
+    sysbus_init_irq(dev, &s->rtc_irq);
+    sysbus_init_irq(dev, &s->rtc_hz_irq);
+
+    memory_region_init_io(&s->iomem, &strongarm_rtc_ops, s, "rtc", 0x10000);
+    sysbus_init_mmio(dev, &s->iomem);
+
+    return 0;
+}
+
+static void strongarm_rtc_pre_save(void *opaque)
+{
+    StrongARMRTCState *s = opaque;
+
+    strongarm_rtc_hzupdate(s);
+}
+
+static int strongarm_rtc_post_load(void *opaque, int version_id)
+{
+    StrongARMRTCState *s = opaque;
+
+    strongarm_rtc_timer_update(s);
+    strongarm_rtc_int_update(s);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_strongarm_rtc_regs = {
+    .name = "strongarm-rtc",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .pre_save = strongarm_rtc_pre_save,
+    .post_load = strongarm_rtc_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(rttr, StrongARMRTCState),
+        VMSTATE_UINT32(rtsr, StrongARMRTCState),
+        VMSTATE_UINT32(rtar, StrongARMRTCState),
+        VMSTATE_UINT32(last_rcnr, StrongARMRTCState),
+        VMSTATE_INT64(last_hz, StrongARMRTCState),
+        VMSTATE_END_OF_LIST(),
+    },
+};
+
+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 const 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 */
+#define GPLR 0x00
+#define GPDR 0x04
+#define GPSR 0x08
+#define GPCR 0x0c
+#define GRER 0x10
+#define GFER 0x14
+#define GEDR 0x18
+#define GAFR 0x1c
+
+typedef struct StrongARMGPIOInfo StrongARMGPIOInfo;
+struct StrongARMGPIOInfo {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    qemu_irq handler[28];
+    qemu_irq irqs[11];
+    qemu_irq irqX;
+
+    uint32_t ilevel;
+    uint32_t olevel;
+    uint32_t dir;
+    uint32_t rising;
+    uint32_t falling;
+    uint32_t status;
+    uint32_t gpsr;
+    uint32_t gafr;
+
+    uint32_t prev_level;
+};
+
+
+static void strongarm_gpio_irq_update(StrongARMGPIOInfo *s)
+{
+    int i;
+    for (i = 0; i < 11; i++) {
+        qemu_set_irq(s->irqs[i], s->status & (1 << i));
+    }
+
+    qemu_set_irq(s->irqX, (s->status & ~0x7ff));
+}
+
+static void strongarm_gpio_set(void *opaque, int line, int level)
+{
+    StrongARMGPIOInfo *s = opaque;
+    uint32_t mask;
+
+    mask = 1 << line;
+
+    if (level) {
+        s->status |= s->rising & mask &
+                ~s->ilevel & ~s->dir;
+        s->ilevel |= mask;
+    } else {
+        s->status |= s->falling & mask &
+                s->ilevel & ~s->dir;
+        s->ilevel &= ~mask;
+    }
+
+    if (s->status & mask) {
+        strongarm_gpio_irq_update(s);
+    }
+}
+
+static void strongarm_gpio_handler_update(StrongARMGPIOInfo *s)
+{
+    uint32_t level, diff;
+    int bit;
+
+    level = s->olevel & s->dir;
+
+    for (diff = s->prev_level ^ level; diff; diff ^= 1 << bit) {
+        bit = ffs(diff) - 1;
+        qemu_set_irq(s->handler[bit], (level >> bit) & 1);
+    }
+
+    s->prev_level = level;
+}
+
+static uint64_t strongarm_gpio_read(void *opaque, hwaddr offset,
+                                    unsigned size)
+{
+    StrongARMGPIOInfo *s = opaque;
+
+    switch (offset) {
+    case GPDR:        /* GPIO Pin-Direction registers */
+        return s->dir;
+
+    case GPSR:        /* GPIO Pin-Output Set registers */
+        DPRINTF("%s: Read from a write-only register 0x" TARGET_FMT_plx "\n",
+                        __func__, offset);
+        return s->gpsr;    /* Return last written value.  */
+
+    case GPCR:        /* GPIO Pin-Output Clear registers */
+        DPRINTF("%s: Read from a write-only register 0x" TARGET_FMT_plx "\n",
+                        __func__, offset);
+        return 31337;        /* Specified as unpredictable in the docs.  */
+
+    case GRER:        /* GPIO Rising-Edge Detect Enable registers */
+        return s->rising;
+
+    case GFER:        /* GPIO Falling-Edge Detect Enable registers */
+        return s->falling;
+
+    case GAFR:        /* GPIO Alternate Function registers */
+        return s->gafr;
+
+    case GPLR:        /* GPIO Pin-Level registers */
+        return (s->olevel & s->dir) |
+               (s->ilevel & ~s->dir);
+
+    case GEDR:        /* GPIO Edge Detect Status registers */
+        return s->status;
+
+    default:
+        printf("%s: Bad offset 0x" TARGET_FMT_plx "\n", __func__, offset);
+    }
+
+    return 0;
+}
+
+static void strongarm_gpio_write(void *opaque, hwaddr offset,
+                                 uint64_t value, unsigned size)
+{
+    StrongARMGPIOInfo *s = opaque;
+
+    switch (offset) {
+    case GPDR:        /* GPIO Pin-Direction registers */
+        s->dir = value;
+        strongarm_gpio_handler_update(s);
+        break;
+
+    case GPSR:        /* GPIO Pin-Output Set registers */
+        s->olevel |= value;
+        strongarm_gpio_handler_update(s);
+        s->gpsr = value;
+        break;
+
+    case GPCR:        /* GPIO Pin-Output Clear registers */
+        s->olevel &= ~value;
+        strongarm_gpio_handler_update(s);
+        break;
+
+    case GRER:        /* GPIO Rising-Edge Detect Enable registers */
+        s->rising = value;
+        break;
+
+    case GFER:        /* GPIO Falling-Edge Detect Enable registers */
+        s->falling = value;
+        break;
+
+    case GAFR:        /* GPIO Alternate Function registers */
+        s->gafr = value;
+        break;
+
+    case GEDR:        /* GPIO Edge Detect Status registers */
+        s->status &= ~value;
+        strongarm_gpio_irq_update(s);
+        break;
+
+    default:
+        printf("%s: Bad offset 0x" TARGET_FMT_plx "\n", __func__, offset);
+    }
+}
+
+static const MemoryRegionOps strongarm_gpio_ops = {
+    .read = strongarm_gpio_read,
+    .write = strongarm_gpio_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static DeviceState *strongarm_gpio_init(hwaddr base,
+                DeviceState *pic)
+{
+    DeviceState *dev;
+    int i;
+
+    dev = qdev_create(NULL, "strongarm-gpio");
+    qdev_init_nofail(dev);
+
+    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
+    for (i = 0; i < 12; i++)
+        sysbus_connect_irq(SYS_BUS_DEVICE(dev), i,
+                    qdev_get_gpio_in(pic, SA_PIC_GPIO0_EDGE + i));
+
+    return dev;
+}
+
+static int strongarm_gpio_initfn(SysBusDevice *dev)
+{
+    StrongARMGPIOInfo *s;
+    int i;
+
+    s = FROM_SYSBUS(StrongARMGPIOInfo, dev);
+
+    qdev_init_gpio_in(&dev->qdev, strongarm_gpio_set, 28);
+    qdev_init_gpio_out(&dev->qdev, s->handler, 28);
+
+    memory_region_init_io(&s->iomem, &strongarm_gpio_ops, s, "gpio", 0x1000);
+
+    sysbus_init_mmio(dev, &s->iomem);
+    for (i = 0; i < 11; i++) {
+        sysbus_init_irq(dev, &s->irqs[i]);
+    }
+    sysbus_init_irq(dev, &s->irqX);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_strongarm_gpio_regs = {
+    .name = "strongarm-gpio",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(ilevel, StrongARMGPIOInfo),
+        VMSTATE_UINT32(olevel, StrongARMGPIOInfo),
+        VMSTATE_UINT32(dir, StrongARMGPIOInfo),
+        VMSTATE_UINT32(rising, StrongARMGPIOInfo),
+        VMSTATE_UINT32(falling, StrongARMGPIOInfo),
+        VMSTATE_UINT32(status, StrongARMGPIOInfo),
+        VMSTATE_UINT32(gafr, StrongARMGPIOInfo),
+        VMSTATE_END_OF_LIST(),
+    },
+};
+
+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 const 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 */
+#define PPDR 0x00
+#define PPSR 0x04
+#define PPAR 0x08
+#define PSDR 0x0c
+#define PPFR 0x10
+
+typedef struct StrongARMPPCInfo StrongARMPPCInfo;
+struct StrongARMPPCInfo {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    qemu_irq handler[28];
+
+    uint32_t ilevel;
+    uint32_t olevel;
+    uint32_t dir;
+    uint32_t ppar;
+    uint32_t psdr;
+    uint32_t ppfr;
+
+    uint32_t prev_level;
+};
+
+static void strongarm_ppc_set(void *opaque, int line, int level)
+{
+    StrongARMPPCInfo *s = opaque;
+
+    if (level) {
+        s->ilevel |= 1 << line;
+    } else {
+        s->ilevel &= ~(1 << line);
+    }
+}
+
+static void strongarm_ppc_handler_update(StrongARMPPCInfo *s)
+{
+    uint32_t level, diff;
+    int bit;
+
+    level = s->olevel & s->dir;
+
+    for (diff = s->prev_level ^ level; diff; diff ^= 1 << bit) {
+        bit = ffs(diff) - 1;
+        qemu_set_irq(s->handler[bit], (level >> bit) & 1);
+    }
+
+    s->prev_level = level;
+}
+
+static uint64_t strongarm_ppc_read(void *opaque, hwaddr offset,
+                                   unsigned size)
+{
+    StrongARMPPCInfo *s = opaque;
+
+    switch (offset) {
+    case PPDR:        /* PPC Pin Direction registers */
+        return s->dir | ~0x3fffff;
+
+    case PPSR:        /* PPC Pin State registers */
+        return (s->olevel & s->dir) |
+               (s->ilevel & ~s->dir) |
+               ~0x3fffff;
+
+    case PPAR:
+        return s->ppar | ~0x41000;
+
+    case PSDR:
+        return s->psdr;
+
+    case PPFR:
+        return s->ppfr | ~0x7f001;
+
+    default:
+        printf("%s: Bad offset 0x" TARGET_FMT_plx "\n", __func__, offset);
+    }
+
+    return 0;
+}
+
+static void strongarm_ppc_write(void *opaque, hwaddr offset,
+                                uint64_t value, unsigned size)
+{
+    StrongARMPPCInfo *s = opaque;
+
+    switch (offset) {
+    case PPDR:        /* PPC Pin Direction registers */
+        s->dir = value & 0x3fffff;
+        strongarm_ppc_handler_update(s);
+        break;
+
+    case PPSR:        /* PPC Pin State registers */
+        s->olevel = value & s->dir & 0x3fffff;
+        strongarm_ppc_handler_update(s);
+        break;
+
+    case PPAR:
+        s->ppar = value & 0x41000;
+        break;
+
+    case PSDR:
+        s->psdr = value & 0x3fffff;
+        break;
+
+    case PPFR:
+        s->ppfr = value & 0x7f001;
+        break;
+
+    default:
+        printf("%s: Bad offset 0x" TARGET_FMT_plx "\n", __func__, offset);
+    }
+}
+
+static const MemoryRegionOps strongarm_ppc_ops = {
+    .read = strongarm_ppc_read,
+    .write = strongarm_ppc_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int strongarm_ppc_init(SysBusDevice *dev)
+{
+    StrongARMPPCInfo *s;
+
+    s = FROM_SYSBUS(StrongARMPPCInfo, dev);
+
+    qdev_init_gpio_in(&dev->qdev, strongarm_ppc_set, 22);
+    qdev_init_gpio_out(&dev->qdev, s->handler, 22);
+
+    memory_region_init_io(&s->iomem, &strongarm_ppc_ops, s, "ppc", 0x1000);
+
+    sysbus_init_mmio(dev, &s->iomem);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_strongarm_ppc_regs = {
+    .name = "strongarm-ppc",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(ilevel, StrongARMPPCInfo),
+        VMSTATE_UINT32(olevel, StrongARMPPCInfo),
+        VMSTATE_UINT32(dir, StrongARMPPCInfo),
+        VMSTATE_UINT32(ppar, StrongARMPPCInfo),
+        VMSTATE_UINT32(psdr, StrongARMPPCInfo),
+        VMSTATE_UINT32(ppfr, StrongARMPPCInfo),
+        VMSTATE_END_OF_LIST(),
+    },
+};
+
+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 const TypeInfo strongarm_ppc_info = {
+    .name          = "strongarm-ppc",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(StrongARMPPCInfo),
+    .class_init    = strongarm_ppc_class_init,
+};
+
+/* UART Ports */
+#define UTCR0 0x00
+#define UTCR1 0x04
+#define UTCR2 0x08
+#define UTCR3 0x0c
+#define UTDR  0x14
+#define UTSR0 0x1c
+#define UTSR1 0x20
+
+#define UTCR0_PE  (1 << 0) /* Parity enable */
+#define UTCR0_OES (1 << 1) /* Even parity */
+#define UTCR0_SBS (1 << 2) /* 2 stop bits */
+#define UTCR0_DSS (1 << 3) /* 8-bit data */
+
+#define UTCR3_RXE (1 << 0) /* Rx enable */
+#define UTCR3_TXE (1 << 1) /* Tx enable */
+#define UTCR3_BRK (1 << 2) /* Force Break */
+#define UTCR3_RIE (1 << 3) /* Rx int enable */
+#define UTCR3_TIE (1 << 4) /* Tx int enable */
+#define UTCR3_LBM (1 << 5) /* Loopback */
+
+#define UTSR0_TFS (1 << 0) /* Tx FIFO nearly empty */
+#define UTSR0_RFS (1 << 1) /* Rx FIFO nearly full */
+#define UTSR0_RID (1 << 2) /* Receiver Idle */
+#define UTSR0_RBB (1 << 3) /* Receiver begin break */
+#define UTSR0_REB (1 << 4) /* Receiver end break */
+#define UTSR0_EIF (1 << 5) /* Error in FIFO */
+
+#define UTSR1_RNE (1 << 1) /* Receive FIFO not empty */
+#define UTSR1_TNF (1 << 2) /* Transmit FIFO not full */
+#define UTSR1_PRE (1 << 3) /* Parity error */
+#define UTSR1_FRE (1 << 4) /* Frame error */
+#define UTSR1_ROR (1 << 5) /* Receive Over Run */
+
+#define RX_FIFO_PRE (1 << 8)
+#define RX_FIFO_FRE (1 << 9)
+#define RX_FIFO_ROR (1 << 10)
+
+typedef struct {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    CharDriverState *chr;
+    qemu_irq irq;
+
+    uint8_t utcr0;
+    uint16_t brd;
+    uint8_t utcr3;
+    uint8_t utsr0;
+    uint8_t utsr1;
+
+    uint8_t tx_fifo[8];
+    uint8_t tx_start;
+    uint8_t tx_len;
+    uint16_t rx_fifo[12]; /* value + error flags in high bits */
+    uint8_t rx_start;
+    uint8_t rx_len;
+
+    uint64_t char_transmit_time; /* time to transmit a char in ticks*/
+    bool wait_break_end;
+    QEMUTimer *rx_timeout_timer;
+    QEMUTimer *tx_timer;
+} StrongARMUARTState;
+
+static void strongarm_uart_update_status(StrongARMUARTState *s)
+{
+    uint16_t utsr1 = 0;
+
+    if (s->tx_len != 8) {
+        utsr1 |= UTSR1_TNF;
+    }
+
+    if (s->rx_len != 0) {
+        uint16_t ent = s->rx_fifo[s->rx_start];
+
+        utsr1 |= UTSR1_RNE;
+        if (ent & RX_FIFO_PRE) {
+            s->utsr1 |= UTSR1_PRE;
+        }
+        if (ent & RX_FIFO_FRE) {
+            s->utsr1 |= UTSR1_FRE;
+        }
+        if (ent & RX_FIFO_ROR) {
+            s->utsr1 |= UTSR1_ROR;
+        }
+    }
+
+    s->utsr1 = utsr1;
+}
+
+static void strongarm_uart_update_int_status(StrongARMUARTState *s)
+{
+    uint16_t utsr0 = s->utsr0 &
+            (UTSR0_REB | UTSR0_RBB | UTSR0_RID);
+    int i;
+
+    if ((s->utcr3 & UTCR3_TXE) &&
+                (s->utcr3 & UTCR3_TIE) &&
+                s->tx_len <= 4) {
+        utsr0 |= UTSR0_TFS;
+    }
+
+    if ((s->utcr3 & UTCR3_RXE) &&
+                (s->utcr3 & UTCR3_RIE) &&
+                s->rx_len > 4) {
+        utsr0 |= UTSR0_RFS;
+    }
+
+    for (i = 0; i < s->rx_len && i < 4; i++)
+        if (s->rx_fifo[(s->rx_start + i) % 12] & ~0xff) {
+            utsr0 |= UTSR0_EIF;
+            break;
+        }
+
+    s->utsr0 = utsr0;
+    qemu_set_irq(s->irq, utsr0);
+}
+
+static void strongarm_uart_update_parameters(StrongARMUARTState *s)
+{
+    int speed, parity, data_bits, stop_bits, frame_size;
+    QEMUSerialSetParams ssp;
+
+    /* Start bit. */
+    frame_size = 1;
+    if (s->utcr0 & UTCR0_PE) {
+        /* Parity bit. */
+        frame_size++;
+        if (s->utcr0 & UTCR0_OES) {
+            parity = 'E';
+        } else {
+            parity = 'O';
+        }
+    } else {
+            parity = 'N';
+    }
+    if (s->utcr0 & UTCR0_SBS) {
+        stop_bits = 2;
+    } else {
+        stop_bits = 1;
+    }
+
+    data_bits = (s->utcr0 & UTCR0_DSS) ? 8 : 7;
+    frame_size += data_bits + stop_bits;
+    speed = 3686400 / 16 / (s->brd + 1);
+    ssp.speed = speed;
+    ssp.parity = parity;
+    ssp.data_bits = data_bits;
+    ssp.stop_bits = stop_bits;
+    s->char_transmit_time =  (get_ticks_per_sec() / speed) * frame_size;
+    if (s->chr) {
+        qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
+    }
+
+    DPRINTF(stderr, "%s speed=%d parity=%c data=%d stop=%d\n", s->chr->label,
+            speed, parity, data_bits, stop_bits);
+}
+
+static void strongarm_uart_rx_to(void *opaque)
+{
+    StrongARMUARTState *s = opaque;
+
+    if (s->rx_len) {
+        s->utsr0 |= UTSR0_RID;
+        strongarm_uart_update_int_status(s);
+    }
+}
+
+static void strongarm_uart_rx_push(StrongARMUARTState *s, uint16_t c)
+{
+    if ((s->utcr3 & UTCR3_RXE) == 0) {
+        /* rx disabled */
+        return;
+    }
+
+    if (s->wait_break_end) {
+        s->utsr0 |= UTSR0_REB;
+        s->wait_break_end = false;
+    }
+
+    if (s->rx_len < 12) {
+        s->rx_fifo[(s->rx_start + s->rx_len) % 12] = c;
+        s->rx_len++;
+    } else
+        s->rx_fifo[(s->rx_start + 11) % 12] |= RX_FIFO_ROR;
+}
+
+static int strongarm_uart_can_receive(void *opaque)
+{
+    StrongARMUARTState *s = opaque;
+
+    if (s->rx_len == 12) {
+        return 0;
+    }
+    /* It's best not to get more than 2/3 of RX FIFO, so advertise that much */
+    if (s->rx_len < 8) {
+        return 8 - s->rx_len;
+    }
+    return 1;
+}
+
+static void strongarm_uart_receive(void *opaque, const uint8_t *buf, int size)
+{
+    StrongARMUARTState *s = opaque;
+    int i;
+
+    for (i = 0; i < size; i++) {
+        strongarm_uart_rx_push(s, buf[i]);
+    }
+
+    /* call the timeout receive callback in 3 char transmit time */
+    qemu_mod_timer(s->rx_timeout_timer,
+                    qemu_get_clock_ns(vm_clock) + s->char_transmit_time * 3);
+
+    strongarm_uart_update_status(s);
+    strongarm_uart_update_int_status(s);
+}
+
+static void strongarm_uart_event(void *opaque, int event)
+{
+    StrongARMUARTState *s = opaque;
+    if (event == CHR_EVENT_BREAK) {
+        s->utsr0 |= UTSR0_RBB;
+        strongarm_uart_rx_push(s, RX_FIFO_FRE);
+        s->wait_break_end = true;
+        strongarm_uart_update_status(s);
+        strongarm_uart_update_int_status(s);
+    }
+}
+
+static void strongarm_uart_tx(void *opaque)
+{
+    StrongARMUARTState *s = opaque;
+    uint64_t new_xmit_ts = qemu_get_clock_ns(vm_clock);
+
+    if (s->utcr3 & UTCR3_LBM) /* loopback */ {
+        strongarm_uart_receive(s, &s->tx_fifo[s->tx_start], 1);
+    } else if (s->chr) {
+        qemu_chr_fe_write(s->chr, &s->tx_fifo[s->tx_start], 1);
+    }
+
+    s->tx_start = (s->tx_start + 1) % 8;
+    s->tx_len--;
+    if (s->tx_len) {
+        qemu_mod_timer(s->tx_timer, new_xmit_ts + s->char_transmit_time);
+    }
+    strongarm_uart_update_status(s);
+    strongarm_uart_update_int_status(s);
+}
+
+static uint64_t strongarm_uart_read(void *opaque, hwaddr addr,
+                                    unsigned size)
+{
+    StrongARMUARTState *s = opaque;
+    uint16_t ret;
+
+    switch (addr) {
+    case UTCR0:
+        return s->utcr0;
+
+    case UTCR1:
+        return s->brd >> 8;
+
+    case UTCR2:
+        return s->brd & 0xff;
+
+    case UTCR3:
+        return s->utcr3;
+
+    case UTDR:
+        if (s->rx_len != 0) {
+            ret = s->rx_fifo[s->rx_start];
+            s->rx_start = (s->rx_start + 1) % 12;
+            s->rx_len--;
+            strongarm_uart_update_status(s);
+            strongarm_uart_update_int_status(s);
+            return ret;
+        }
+        return 0;
+
+    case UTSR0:
+        return s->utsr0;
+
+    case UTSR1:
+        return s->utsr1;
+
+    default:
+        printf("%s: Bad register 0x" TARGET_FMT_plx "\n", __func__, addr);
+        return 0;
+    }
+}
+
+static void strongarm_uart_write(void *opaque, hwaddr addr,
+                                 uint64_t value, unsigned size)
+{
+    StrongARMUARTState *s = opaque;
+
+    switch (addr) {
+    case UTCR0:
+        s->utcr0 = value & 0x7f;
+        strongarm_uart_update_parameters(s);
+        break;
+
+    case UTCR1:
+        s->brd = (s->brd & 0xff) | ((value & 0xf) << 8);
+        strongarm_uart_update_parameters(s);
+        break;
+
+    case UTCR2:
+        s->brd = (s->brd & 0xf00) | (value & 0xff);
+        strongarm_uart_update_parameters(s);
+        break;
+
+    case UTCR3:
+        s->utcr3 = value & 0x3f;
+        if ((s->utcr3 & UTCR3_RXE) == 0) {
+            s->rx_len = 0;
+        }
+        if ((s->utcr3 & UTCR3_TXE) == 0) {
+            s->tx_len = 0;
+        }
+        strongarm_uart_update_status(s);
+        strongarm_uart_update_int_status(s);
+        break;
+
+    case UTDR:
+        if ((s->utcr3 & UTCR3_TXE) && s->tx_len != 8) {
+            s->tx_fifo[(s->tx_start + s->tx_len) % 8] = value;
+            s->tx_len++;
+            strongarm_uart_update_status(s);
+            strongarm_uart_update_int_status(s);
+            if (s->tx_len == 1) {
+                strongarm_uart_tx(s);
+            }
+        }
+        break;
+
+    case UTSR0:
+        s->utsr0 = s->utsr0 & ~(value &
+                (UTSR0_REB | UTSR0_RBB | UTSR0_RID));
+        strongarm_uart_update_int_status(s);
+        break;
+
+    default:
+        printf("%s: Bad register 0x" TARGET_FMT_plx "\n", __func__, addr);
+    }
+}
+
+static const MemoryRegionOps strongarm_uart_ops = {
+    .read = strongarm_uart_read,
+    .write = strongarm_uart_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int strongarm_uart_init(SysBusDevice *dev)
+{
+    StrongARMUARTState *s = FROM_SYSBUS(StrongARMUARTState, dev);
+
+    memory_region_init_io(&s->iomem, &strongarm_uart_ops, s, "uart", 0x10000);
+    sysbus_init_mmio(dev, &s->iomem);
+    sysbus_init_irq(dev, &s->irq);
+
+    s->rx_timeout_timer = qemu_new_timer_ns(vm_clock, strongarm_uart_rx_to, s);
+    s->tx_timer = qemu_new_timer_ns(vm_clock, strongarm_uart_tx, s);
+
+    if (s->chr) {
+        qemu_chr_add_handlers(s->chr,
+                        strongarm_uart_can_receive,
+                        strongarm_uart_receive,
+                        strongarm_uart_event,
+                        s);
+    }
+
+    return 0;
+}
+
+static void strongarm_uart_reset(DeviceState *dev)
+{
+    StrongARMUARTState *s = DO_UPCAST(StrongARMUARTState, busdev.qdev, dev);
+
+    s->utcr0 = UTCR0_DSS; /* 8 data, no parity */
+    s->brd = 23;    /* 9600 */
+    /* enable send & recv - this actually violates spec */
+    s->utcr3 = UTCR3_TXE | UTCR3_RXE;
+
+    s->rx_len = s->tx_len = 0;
+
+    strongarm_uart_update_parameters(s);
+    strongarm_uart_update_status(s);
+    strongarm_uart_update_int_status(s);
+}
+
+static int strongarm_uart_post_load(void *opaque, int version_id)
+{
+    StrongARMUARTState *s = opaque;
+
+    strongarm_uart_update_parameters(s);
+    strongarm_uart_update_status(s);
+    strongarm_uart_update_int_status(s);
+
+    /* tx and restart timer */
+    if (s->tx_len) {
+        strongarm_uart_tx(s);
+    }
+
+    /* restart rx timeout timer */
+    if (s->rx_len) {
+        qemu_mod_timer(s->rx_timeout_timer,
+                qemu_get_clock_ns(vm_clock) + s->char_transmit_time * 3);
+    }
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_strongarm_uart_regs = {
+    .name = "strongarm-uart",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .post_load = strongarm_uart_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT8(utcr0, StrongARMUARTState),
+        VMSTATE_UINT16(brd, StrongARMUARTState),
+        VMSTATE_UINT8(utcr3, StrongARMUARTState),
+        VMSTATE_UINT8(utsr0, StrongARMUARTState),
+        VMSTATE_UINT8_ARRAY(tx_fifo, StrongARMUARTState, 8),
+        VMSTATE_UINT8(tx_start, StrongARMUARTState),
+        VMSTATE_UINT8(tx_len, StrongARMUARTState),
+        VMSTATE_UINT16_ARRAY(rx_fifo, StrongARMUARTState, 12),
+        VMSTATE_UINT8(rx_start, StrongARMUARTState),
+        VMSTATE_UINT8(rx_len, StrongARMUARTState),
+        VMSTATE_BOOL(wait_break_end, StrongARMUARTState),
+        VMSTATE_END_OF_LIST(),
+    },
+};
+
+static Property strongarm_uart_properties[] = {
+    DEFINE_PROP_CHR("chardev", StrongARMUARTState, chr),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void strongarm_uart_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = strongarm_uart_init;
+    dc->desc = "StrongARM UART controller";
+    dc->reset = strongarm_uart_reset;
+    dc->vmsd = &vmstate_strongarm_uart_regs;
+    dc->props = strongarm_uart_properties;
+}
+
+static const 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 */
+typedef struct {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    qemu_irq irq;
+    SSIBus *bus;
+
+    uint16_t sscr[2];
+    uint16_t sssr;
+
+    uint16_t rx_fifo[8];
+    uint8_t rx_level;
+    uint8_t rx_start;
+} StrongARMSSPState;
+
+#define SSCR0 0x60 /* SSP Control register 0 */
+#define SSCR1 0x64 /* SSP Control register 1 */
+#define SSDR  0x6c /* SSP Data register */
+#define SSSR  0x74 /* SSP Status register */
+
+/* Bitfields for above registers */
+#define SSCR0_SPI(x)    (((x) & 0x30) == 0x00)
+#define SSCR0_SSP(x)    (((x) & 0x30) == 0x10)
+#define SSCR0_UWIRE(x)  (((x) & 0x30) == 0x20)
+#define SSCR0_PSP(x)    (((x) & 0x30) == 0x30)
+#define SSCR0_SSE       (1 << 7)
+#define SSCR0_DSS(x)    (((x) & 0xf) + 1)
+#define SSCR1_RIE       (1 << 0)
+#define SSCR1_TIE       (1 << 1)
+#define SSCR1_LBM       (1 << 2)
+#define SSSR_TNF        (1 << 2)
+#define SSSR_RNE        (1 << 3)
+#define SSSR_TFS        (1 << 5)
+#define SSSR_RFS        (1 << 6)
+#define SSSR_ROR        (1 << 7)
+#define SSSR_RW         0x0080
+
+static void strongarm_ssp_int_update(StrongARMSSPState *s)
+{
+    int level = 0;
+
+    level |= (s->sssr & SSSR_ROR);
+    level |= (s->sssr & SSSR_RFS)  &&  (s->sscr[1] & SSCR1_RIE);
+    level |= (s->sssr & SSSR_TFS)  &&  (s->sscr[1] & SSCR1_TIE);
+    qemu_set_irq(s->irq, level);
+}
+
+static void strongarm_ssp_fifo_update(StrongARMSSPState *s)
+{
+    s->sssr &= ~SSSR_TFS;
+    s->sssr &= ~SSSR_TNF;
+    if (s->sscr[0] & SSCR0_SSE) {
+        if (s->rx_level >= 4) {
+            s->sssr |= SSSR_RFS;
+        } else {
+            s->sssr &= ~SSSR_RFS;
+        }
+        if (s->rx_level) {
+            s->sssr |= SSSR_RNE;
+        } else {
+            s->sssr &= ~SSSR_RNE;
+        }
+        /* TX FIFO is never filled, so it is always in underrun
+           condition if SSP is enabled */
+        s->sssr |= SSSR_TFS;
+        s->sssr |= SSSR_TNF;
+    }
+
+    strongarm_ssp_int_update(s);
+}
+
+static uint64_t strongarm_ssp_read(void *opaque, hwaddr addr,
+                                   unsigned size)
+{
+    StrongARMSSPState *s = opaque;
+    uint32_t retval;
+
+    switch (addr) {
+    case SSCR0:
+        return s->sscr[0];
+    case SSCR1:
+        return s->sscr[1];
+    case SSSR:
+        return s->sssr;
+    case SSDR:
+        if (~s->sscr[0] & SSCR0_SSE) {
+            return 0xffffffff;
+        }
+        if (s->rx_level < 1) {
+            printf("%s: SSP Rx Underrun\n", __func__);
+            return 0xffffffff;
+        }
+        s->rx_level--;
+        retval = s->rx_fifo[s->rx_start++];
+        s->rx_start &= 0x7;
+        strongarm_ssp_fifo_update(s);
+        return retval;
+    default:
+        printf("%s: Bad register 0x" TARGET_FMT_plx "\n", __func__, addr);
+        break;
+    }
+    return 0;
+}
+
+static void strongarm_ssp_write(void *opaque, hwaddr addr,
+                                uint64_t value, unsigned size)
+{
+    StrongARMSSPState *s = opaque;
+
+    switch (addr) {
+    case SSCR0:
+        s->sscr[0] = value & 0xffbf;
+        if ((s->sscr[0] & SSCR0_SSE) && SSCR0_DSS(value) < 4) {
+            printf("%s: Wrong data size: %i bits\n", __func__,
+                   (int)SSCR0_DSS(value));
+        }
+        if (!(value & SSCR0_SSE)) {
+            s->sssr = 0;
+            s->rx_level = 0;
+        }
+        strongarm_ssp_fifo_update(s);
+        break;
+
+    case SSCR1:
+        s->sscr[1] = value & 0x2f;
+        if (value & SSCR1_LBM) {
+            printf("%s: Attempt to use SSP LBM mode\n", __func__);
+        }
+        strongarm_ssp_fifo_update(s);
+        break;
+
+    case SSSR:
+        s->sssr &= ~(value & SSSR_RW);
+        strongarm_ssp_int_update(s);
+        break;
+
+    case SSDR:
+        if (SSCR0_UWIRE(s->sscr[0])) {
+            value &= 0xff;
+        } else
+            /* Note how 32bits overflow does no harm here */
+            value &= (1 << SSCR0_DSS(s->sscr[0])) - 1;
+
+        /* Data goes from here to the Tx FIFO and is shifted out from
+         * there directly to the slave, no need to buffer it.
+         */
+        if (s->sscr[0] & SSCR0_SSE) {
+            uint32_t readval;
+            if (s->sscr[1] & SSCR1_LBM) {
+                readval = value;
+            } else {
+                readval = ssi_transfer(s->bus, value);
+            }
+
+            if (s->rx_level < 0x08) {
+                s->rx_fifo[(s->rx_start + s->rx_level++) & 0x7] = readval;
+            } else {
+                s->sssr |= SSSR_ROR;
+            }
+        }
+        strongarm_ssp_fifo_update(s);
+        break;
+
+    default:
+        printf("%s: Bad register 0x" TARGET_FMT_plx "\n", __func__, addr);
+        break;
+    }
+}
+
+static const MemoryRegionOps strongarm_ssp_ops = {
+    .read = strongarm_ssp_read,
+    .write = strongarm_ssp_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int strongarm_ssp_post_load(void *opaque, int version_id)
+{
+    StrongARMSSPState *s = opaque;
+
+    strongarm_ssp_fifo_update(s);
+
+    return 0;
+}
+
+static int strongarm_ssp_init(SysBusDevice *dev)
+{
+    StrongARMSSPState *s = FROM_SYSBUS(StrongARMSSPState, dev);
+
+    sysbus_init_irq(dev, &s->irq);
+
+    memory_region_init_io(&s->iomem, &strongarm_ssp_ops, s, "ssp", 0x1000);
+    sysbus_init_mmio(dev, &s->iomem);
+
+    s->bus = ssi_create_bus(&dev->qdev, "ssi");
+    return 0;
+}
+
+static void strongarm_ssp_reset(DeviceState *dev)
+{
+    StrongARMSSPState *s = DO_UPCAST(StrongARMSSPState, busdev.qdev, dev);
+    s->sssr = 0x03; /* 3 bit data, SPI, disabled */
+    s->rx_start = 0;
+    s->rx_level = 0;
+}
+
+static const VMStateDescription vmstate_strongarm_ssp_regs = {
+    .name = "strongarm-ssp",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .post_load = strongarm_ssp_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT16_ARRAY(sscr, StrongARMSSPState, 2),
+        VMSTATE_UINT16(sssr, StrongARMSSPState),
+        VMSTATE_UINT16_ARRAY(rx_fifo, StrongARMSSPState, 8),
+        VMSTATE_UINT8(rx_start, StrongARMSSPState),
+        VMSTATE_UINT8(rx_level, StrongARMSSPState),
+        VMSTATE_END_OF_LIST(),
+    },
+};
+
+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 const 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 */
+StrongARMState *sa1110_init(MemoryRegion *sysmem,
+                            unsigned int sdram_size, const char *rev)
+{
+    StrongARMState *s;
+    qemu_irq *pic;
+    int i;
+
+    s = g_malloc0(sizeof(StrongARMState));
+
+    if (!rev) {
+        rev = "sa1110-b5";
+    }
+
+    if (strncmp(rev, "sa1110", 6)) {
+        error_report("Machine requires a SA1110 processor.");
+        exit(1);
+    }
+
+    s->cpu = cpu_arm_init(rev);
+
+    if (!s->cpu) {
+        error_report("Unable to find CPU definition");
+        exit(1);
+    }
+
+    memory_region_init_ram(&s->sdram, "strongarm.sdram", sdram_size);
+    vmstate_register_ram_global(&s->sdram);
+    memory_region_add_subregion(sysmem, SA_SDCS0, &s->sdram);
+
+    pic = arm_pic_init_cpu(s->cpu);
+    s->pic = sysbus_create_varargs("strongarm_pic", 0x90050000,
+                    pic[ARM_PIC_CPU_IRQ], pic[ARM_PIC_CPU_FIQ], NULL);
+
+    sysbus_create_varargs("pxa25x-timer", 0x90000000,
+                    qdev_get_gpio_in(s->pic, SA_PIC_OSTC0),
+                    qdev_get_gpio_in(s->pic, SA_PIC_OSTC1),
+                    qdev_get_gpio_in(s->pic, SA_PIC_OSTC2),
+                    qdev_get_gpio_in(s->pic, SA_PIC_OSTC3),
+                    NULL);
+
+    sysbus_create_simple("strongarm-rtc", 0x90010000,
+                    qdev_get_gpio_in(s->pic, SA_PIC_RTC_ALARM));
+
+    s->gpio = strongarm_gpio_init(0x90040000, s->pic);
+
+    s->ppc = sysbus_create_varargs("strongarm-ppc", 0x90060000, NULL);
+
+    for (i = 0; sa_serial[i].io_base; i++) {
+        DeviceState *dev = qdev_create(NULL, "strongarm-uart");
+        qdev_prop_set_chr(dev, "chardev", serial_hds[i]);
+        qdev_init_nofail(dev);
+        sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0,
+                sa_serial[i].io_base);
+        sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0,
+                qdev_get_gpio_in(s->pic, sa_serial[i].irq));
+    }
+
+    s->ssp = sysbus_create_varargs("strongarm-ssp", 0x80070000,
+                qdev_get_gpio_in(s->pic, SA_PIC_SSP), NULL);
+    s->ssp_bus = (SSIBus *)qdev_get_child_bus(s->ssp, "ssi");
+
+    return s;
+}
+
+static void strongarm_register_types(void)
+{
+    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);
+}
+
+type_init(strongarm_register_types)
diff --git a/hw/arm/strongarm.h b/hw/arm/strongarm.h
new file mode 100644 (file)
index 0000000..2893f94
--- /dev/null
@@ -0,0 +1,68 @@
+#ifndef _STRONGARM_H
+#define _STRONGARM_H
+
+#include "exec/memory.h"
+
+#define SA_CS0          0x00000000
+#define SA_CS1          0x08000000
+#define SA_CS2          0x10000000
+#define SA_CS3          0x18000000
+#define SA_PCMCIA_CS0   0x20000000
+#define SA_PCMCIA_CS1   0x30000000
+#define SA_CS4          0x40000000
+#define SA_CS5          0x48000000
+/* system registers here */
+#define SA_SDCS0        0xc0000000
+#define SA_SDCS1        0xc8000000
+#define SA_SDCS2        0xd0000000
+#define SA_SDCS3        0xd8000000
+
+enum {
+    SA_PIC_GPIO0_EDGE = 0,
+    SA_PIC_GPIO1_EDGE,
+    SA_PIC_GPIO2_EDGE,
+    SA_PIC_GPIO3_EDGE,
+    SA_PIC_GPIO4_EDGE,
+    SA_PIC_GPIO5_EDGE,
+    SA_PIC_GPIO6_EDGE,
+    SA_PIC_GPIO7_EDGE,
+    SA_PIC_GPIO8_EDGE,
+    SA_PIC_GPIO9_EDGE,
+    SA_PIC_GPIO10_EDGE,
+    SA_PIC_GPIOX_EDGE,
+    SA_PIC_LCD,
+    SA_PIC_UDC,
+    SA_PIC_RSVD1,
+    SA_PIC_UART1,
+    SA_PIC_UART2,
+    SA_PIC_UART3,
+    SA_PIC_MCP,
+    SA_PIC_SSP,
+    SA_PIC_DMA_CH0,
+    SA_PIC_DMA_CH1,
+    SA_PIC_DMA_CH2,
+    SA_PIC_DMA_CH3,
+    SA_PIC_DMA_CH4,
+    SA_PIC_DMA_CH5,
+    SA_PIC_OSTC0,
+    SA_PIC_OSTC1,
+    SA_PIC_OSTC2,
+    SA_PIC_OSTC3,
+    SA_PIC_RTC_HZ,
+    SA_PIC_RTC_ALARM,
+};
+
+typedef struct {
+    ARMCPU *cpu;
+    MemoryRegion sdram;
+    DeviceState *pic;
+    DeviceState *gpio;
+    DeviceState *ppc;
+    DeviceState *ssp;
+    SSIBus *ssp_bus;
+} StrongARMState;
+
+StrongARMState *sa1110_init(MemoryRegion *sysmem,
+                            unsigned int sdram_size, const char *rev);
+
+#endif
index 747888c64e16fecec5e31d3f98285094eab0fbc6..c4362d4313441ffcdd6ae2793bcd50112a33e6a1 100644 (file)
  */
 
 #include "hw/hw.h"
-#include "hw/pxa.h"
-#include "hw/arm-misc.h"
-#include "hw/devices.h"
-#include "hw/sharpsl.h"
+#include "hw/arm/pxa.h"
+#include "hw/arm.h"
+#include "hw/arm/devices.h"
+#include "hw/arm/sharpsl.h"
 #include "hw/pcmcia.h"
 #include "block/block.h"
 #include "hw/boards.h"
-#include "hw/i2c.h"
+#include "hw/i2c/i2c.h"
 #include "hw/ssi.h"
 #include "sysemu/blockdev.h"
 #include "hw/sysbus.h"
index baaa265888a5ba3932dc7fff9a942dc5ee89d83d..d9be6044818dae98aa05f55314cc9742c266d381 100644 (file)
@@ -8,16 +8,16 @@
  */
 
 #include "hw/sysbus.h"
-#include "hw/arm-misc.h"
-#include "hw/devices.h"
+#include "hw/arm.h"
+#include "hw/arm/devices.h"
 #include "net/net.h"
 #include "sysemu/sysemu.h"
 #include "hw/pci/pci.h"
-#include "hw/i2c.h"
+#include "hw/i2c/i2c.h"
 #include "hw/boards.h"
 #include "sysemu/blockdev.h"
 #include "exec/address-spaces.h"
-#include "hw/flash.h"
+#include "hw/block/flash.h"
 
 #define VERSATILE_FLASH_ADDR 0x34000000
 #define VERSATILE_FLASH_SIZE (64 * 1024 * 1024)
index 2e1a5d0e5b53aa6445a5eb11d78c9bf08418d449..96e098579f89500882edc30e42e83b771fccb35d 100644 (file)
  */
 
 #include "hw/sysbus.h"
-#include "hw/arm-misc.h"
-#include "hw/primecell.h"
-#include "hw/devices.h"
+#include "hw/arm.h"
+#include "hw/arm/primecell.h"
+#include "hw/arm/devices.h"
 #include "net/net.h"
 #include "sysemu/sysemu.h"
 #include "hw/boards.h"
 #include "exec/address-spaces.h"
 #include "sysemu/blockdev.h"
-#include "hw/flash.h"
+#include "hw/block/flash.h"
 
 #define VEXPRESS_BOARD_ID 0x8e0
 #define VEXPRESS_FLASH_SIZE (64 * 1024 * 1024)
index 6f362865f97f331f078fde22b97727389d8662e9..8d65f796f99e292cd66b7a5066773382945407a0 100644 (file)
  */
 
 #include "hw/sysbus.h"
-#include "hw/arm-misc.h"
+#include "hw/arm.h"
 #include "net/net.h"
 #include "exec/address-spaces.h"
 #include "sysemu/sysemu.h"
 #include "hw/boards.h"
-#include "hw/flash.h"
+#include "hw/block/flash.h"
 #include "sysemu/blockdev.h"
 #include "hw/loader.h"
 #include "hw/ssi.h"
@@ -86,8 +86,7 @@ static inline void zynq_init_spi_flashes(uint32_t base_addr, qemu_irq irq,
         spi = (SSIBus *)qdev_get_child_bus(dev, bus_name);
 
         for (j = 0; j < num_ss; ++j) {
-            flash_dev = ssi_create_slave_no_init(spi, "n25q128");
-            qdev_init_nofail(flash_dev);
+            flash_dev = ssi_create_slave(spi, "n25q128");
 
             cs_line = qdev_get_gpio_in(flash_dev, 0);
             sysbus_connect_irq(busdev, i * num_ss + j + 1, cs_line);
index cbb6d8085e10d52ce75dd03551d7a3f821b5bba0..3e272088f5329cdab5d42500d8745eb44d8a7bea 100644 (file)
  */
 
 #include "hw/hw.h"
-#include "hw/pxa.h"
-#include "hw/arm-misc.h"
-#include "hw/devices.h"
-#include "hw/i2c.h"
+#include "hw/arm/pxa.h"
+#include "hw/arm.h"
+#include "hw/arm/devices.h"
+#include "hw/i2c/i2c.h"
 #include "hw/ssi.h"
 #include "hw/boards.h"
 #include "sysemu/sysemu.h"
-#include "hw/flash.h"
+#include "hw/block/flash.h"
 #include "sysemu/blockdev.h"
 #include "ui/console.h"
 #include "audio/audio.h"
diff --git a/hw/arm11mpcore.c b/hw/arm11mpcore.c
deleted file mode 100644 (file)
index 90dcead..0000000
+++ /dev/null
@@ -1,277 +0,0 @@
-/*
- * ARM11MPCore internal peripheral emulation.
- *
- * Copyright (c) 2006-2007 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the GPL.
- */
-
-#include "hw/sysbus.h"
-#include "qemu/timer.h"
-
-/* MPCore private memory region.  */
-
-typedef struct ARM11MPCorePriveState {
-    SysBusDevice busdev;
-    uint32_t scu_control;
-    int iomemtype;
-    uint32_t old_timer_status[8];
-    uint32_t num_cpu;
-    MemoryRegion iomem;
-    MemoryRegion container;
-    DeviceState *mptimer;
-    DeviceState *wdtimer;
-    DeviceState *gic;
-    uint32_t num_irq;
-} ARM11MPCorePriveState;
-
-/* Per-CPU private memory mapped IO.  */
-
-static uint64_t mpcore_scu_read(void *opaque, hwaddr offset,
-                                unsigned size)
-{
-    ARM11MPCorePriveState *s = (ARM11MPCorePriveState *)opaque;
-    int id;
-    /* SCU */
-    switch (offset) {
-    case 0x00: /* Control.  */
-        return s->scu_control;
-    case 0x04: /* Configuration.  */
-        id = ((1 << s->num_cpu) - 1) << 4;
-        return id | (s->num_cpu - 1);
-    case 0x08: /* CPU status.  */
-        return 0;
-    case 0x0c: /* Invalidate all.  */
-        return 0;
-    default:
-        qemu_log_mask(LOG_GUEST_ERROR,
-                      "mpcore_priv_read: Bad offset %x\n", (int)offset);
-        return 0;
-    }
-}
-
-static void mpcore_scu_write(void *opaque, hwaddr offset,
-                             uint64_t value, unsigned size)
-{
-    ARM11MPCorePriveState *s = (ARM11MPCorePriveState *)opaque;
-    /* SCU */
-    switch (offset) {
-    case 0: /* Control register.  */
-        s->scu_control = value & 1;
-        break;
-    case 0x0c: /* Invalidate all.  */
-        /* This is a no-op as cache is not emulated.  */
-        break;
-    default:
-        qemu_log_mask(LOG_GUEST_ERROR,
-                      "mpcore_priv_read: Bad offset %x\n", (int)offset);
-    }
-}
-
-static const MemoryRegionOps mpcore_scu_ops = {
-    .read = mpcore_scu_read,
-    .write = mpcore_scu_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void mpcore_priv_set_irq(void *opaque, int irq, int level)
-{
-    ARM11MPCorePriveState *s = (ARM11MPCorePriveState *)opaque;
-    qemu_set_irq(qdev_get_gpio_in(s->gic, irq), level);
-}
-
-static void mpcore_priv_map_setup(ARM11MPCorePriveState *s)
-{
-    int i;
-    SysBusDevice *gicbusdev = SYS_BUS_DEVICE(s->gic);
-    SysBusDevice *timerbusdev = SYS_BUS_DEVICE(s->mptimer);
-    SysBusDevice *wdtbusdev = SYS_BUS_DEVICE(s->wdtimer);
-    memory_region_init(&s->container, "mpcode-priv-container", 0x2000);
-    memory_region_init_io(&s->iomem, &mpcore_scu_ops, s, "mpcore-scu", 0x100);
-    memory_region_add_subregion(&s->container, 0, &s->iomem);
-    /* GIC CPU interfaces: "current CPU" at 0x100, then specific CPUs
-     * at 0x200, 0x300...
-     */
-    for (i = 0; i < (s->num_cpu + 1); i++) {
-        hwaddr offset = 0x100 + (i * 0x100);
-        memory_region_add_subregion(&s->container, offset,
-                                    sysbus_mmio_get_region(gicbusdev, i + 1));
-    }
-    /* Add the regions for timer and watchdog for "current CPU" and
-     * for each specific CPU.
-     */
-    for (i = 0; i < (s->num_cpu + 1); i++) {
-        /* Timers at 0x600, 0x700, ...; watchdogs at 0x620, 0x720, ... */
-        hwaddr offset = 0x600 + i * 0x100;
-        memory_region_add_subregion(&s->container, offset,
-                                    sysbus_mmio_get_region(timerbusdev, i));
-        memory_region_add_subregion(&s->container, offset + 0x20,
-                                    sysbus_mmio_get_region(wdtbusdev, i));
-    }
-    memory_region_add_subregion(&s->container, 0x1000,
-                                sysbus_mmio_get_region(gicbusdev, 0));
-    /* Wire up the interrupt from each watchdog and timer.
-     * For each core the timer is PPI 29 and the watchdog PPI 30.
-     */
-    for (i = 0; i < s->num_cpu; i++) {
-        int ppibase = (s->num_irq - 32) + i * 32;
-        sysbus_connect_irq(timerbusdev, i,
-                           qdev_get_gpio_in(s->gic, ppibase + 29));
-        sysbus_connect_irq(wdtbusdev, i,
-                           qdev_get_gpio_in(s->gic, ppibase + 30));
-    }
-}
-
-static int mpcore_priv_init(SysBusDevice *dev)
-{
-    ARM11MPCorePriveState *s = FROM_SYSBUS(ARM11MPCorePriveState, dev);
-
-    s->gic = qdev_create(NULL, "arm_gic");
-    qdev_prop_set_uint32(s->gic, "num-cpu", s->num_cpu);
-    qdev_prop_set_uint32(s->gic, "num-irq", s->num_irq);
-    /* Request the legacy 11MPCore GIC behaviour: */
-    qdev_prop_set_uint32(s->gic, "revision", 0);
-    qdev_init_nofail(s->gic);
-
-    /* Pass through outbound IRQ lines from the GIC */
-    sysbus_pass_irq(dev, SYS_BUS_DEVICE(s->gic));
-
-    /* Pass through inbound GPIO lines to the GIC */
-    qdev_init_gpio_in(&s->busdev.qdev, mpcore_priv_set_irq, s->num_irq - 32);
-
-    s->mptimer = qdev_create(NULL, "arm_mptimer");
-    qdev_prop_set_uint32(s->mptimer, "num-cpu", s->num_cpu);
-    qdev_init_nofail(s->mptimer);
-
-    s->wdtimer = qdev_create(NULL, "arm_mptimer");
-    qdev_prop_set_uint32(s->wdtimer, "num-cpu", s->num_cpu);
-    qdev_init_nofail(s->wdtimer);
-
-    mpcore_priv_map_setup(s);
-    sysbus_init_mmio(dev, &s->container);
-    return 0;
-}
-
-/* Dummy PIC to route IRQ lines.  The baseboard has 4 independent IRQ
-   controllers.  The output of these, plus some of the raw input lines
-   are fed into a single SMP-aware interrupt controller on the CPU.  */
-typedef struct {
-    SysBusDevice busdev;
-    SysBusDevice *priv;
-    qemu_irq cpuic[32];
-    qemu_irq rvic[4][64];
-    uint32_t num_cpu;
-} mpcore_rirq_state;
-
-/* Map baseboard IRQs onto CPU IRQ lines.  */
-static const int mpcore_irq_map[32] = {
-    -1, -1, -1, -1,  1,  2, -1, -1,
-    -1, -1,  6, -1,  4,  5, -1, -1,
-    -1, 14, 15,  0,  7,  8, -1, -1,
-    -1, -1, -1, -1,  9,  3, -1, -1,
-};
-
-static void mpcore_rirq_set_irq(void *opaque, int irq, int level)
-{
-    mpcore_rirq_state *s = (mpcore_rirq_state *)opaque;
-    int i;
-
-    for (i = 0; i < 4; i++) {
-        qemu_set_irq(s->rvic[i][irq], level);
-    }
-    if (irq < 32) {
-        irq = mpcore_irq_map[irq];
-        if (irq >= 0) {
-            qemu_set_irq(s->cpuic[irq], level);
-        }
-    }
-}
-
-static int realview_mpcore_init(SysBusDevice *dev)
-{
-    mpcore_rirq_state *s = FROM_SYSBUS(mpcore_rirq_state, dev);
-    DeviceState *gic;
-    DeviceState *priv;
-    int n;
-    int i;
-
-    priv = qdev_create(NULL, "arm11mpcore_priv");
-    qdev_prop_set_uint32(priv, "num-cpu", s->num_cpu);
-    qdev_init_nofail(priv);
-    s->priv = SYS_BUS_DEVICE(priv);
-    sysbus_pass_irq(dev, s->priv);
-    for (i = 0; i < 32; i++) {
-        s->cpuic[i] = qdev_get_gpio_in(priv, i);
-    }
-    /* ??? IRQ routing is hardcoded to "normal" mode.  */
-    for (n = 0; n < 4; n++) {
-        gic = sysbus_create_simple("realview_gic", 0x10040000 + n * 0x10000,
-                                   s->cpuic[10 + n]);
-        for (i = 0; i < 64; i++) {
-            s->rvic[n][i] = qdev_get_gpio_in(gic, i);
-        }
-    }
-    qdev_init_gpio_in(&dev->qdev, mpcore_rirq_set_irq, 64);
-    sysbus_init_mmio(dev, sysbus_mmio_get_region(s->priv, 0));
-    return 0;
-}
-
-static Property mpcore_rirq_properties[] = {
-    DEFINE_PROP_UINT32("num-cpu", mpcore_rirq_state, num_cpu, 1),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void mpcore_rirq_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = realview_mpcore_init;
-    dc->props = mpcore_rirq_properties;
-}
-
-static const TypeInfo mpcore_rirq_info = {
-    .name          = "realview_mpcore",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(mpcore_rirq_state),
-    .class_init    = mpcore_rirq_class_init,
-};
-
-static Property mpcore_priv_properties[] = {
-    DEFINE_PROP_UINT32("num-cpu", ARM11MPCorePriveState, 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", ARM11MPCorePriveState, num_irq, 64),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void mpcore_priv_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = mpcore_priv_init;
-    dc->props = mpcore_priv_properties;
-}
-
-static const TypeInfo mpcore_priv_info = {
-    .name          = "arm11mpcore_priv",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(ARM11MPCorePriveState),
-    .class_init    = mpcore_priv_class_init,
-};
-
-static void arm11mpcore_register_types(void)
-{
-    type_register_static(&mpcore_rirq_info);
-    type_register_static(&mpcore_priv_info);
-}
-
-type_init(arm11mpcore_register_types)
diff --git a/hw/arm_gic.c b/hw/arm_gic.c
deleted file mode 100644 (file)
index bcb072b..0000000
+++ /dev/null
@@ -1,723 +0,0 @@
-/*
- * ARM Generic/Distributed Interrupt Controller
- *
- * Copyright (c) 2006-2007 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the GPL.
- */
-
-/* This file contains implementation code for the RealView EB interrupt
- * controller, MPCore distributed interrupt controller and ARMv7-M
- * Nested Vectored Interrupt Controller.
- * It is compiled in two ways:
- *  (1) as a standalone file to produce a sysbus device which is a GIC
- *  that can be used on the realview board and as one of the builtin
- *  private peripherals for the ARM MP CPUs (11MPCore, A9, etc)
- *  (2) by being directly #included into armv7m_nvic.c to produce the
- *  armv7m_nvic device.
- */
-
-#include "hw/sysbus.h"
-#include "hw/arm_gic_internal.h"
-
-//#define DEBUG_GIC
-
-#ifdef DEBUG_GIC
-#define DPRINTF(fmt, ...) \
-do { fprintf(stderr, "arm_gic: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...) do {} while(0)
-#endif
-
-static const uint8_t gic_id[] = {
-    0x90, 0x13, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1
-};
-
-#define NUM_CPU(s) ((s)->num_cpu)
-
-static inline int gic_get_current_cpu(GICState *s)
-{
-    if (s->num_cpu > 1) {
-        CPUState *cpu = ENV_GET_CPU(cpu_single_env);
-        return cpu->cpu_index;
-    }
-    return 0;
-}
-
-/* TODO: Many places that call this routine could be optimized.  */
-/* Update interrupt status after enabled or pending bits have been changed.  */
-void gic_update(GICState *s)
-{
-    int best_irq;
-    int best_prio;
-    int irq;
-    int level;
-    int cpu;
-    int cm;
-
-    for (cpu = 0; cpu < NUM_CPU(s); cpu++) {
-        cm = 1 << cpu;
-        s->current_pending[cpu] = 1023;
-        if (!s->enabled || !s->cpu_enabled[cpu]) {
-            qemu_irq_lower(s->parent_irq[cpu]);
-            return;
-        }
-        best_prio = 0x100;
-        best_irq = 1023;
-        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);
-                    best_irq = irq;
-                }
-            }
-        }
-        level = 0;
-        if (best_prio < s->priority_mask[cpu]) {
-            s->current_pending[cpu] = best_irq;
-            if (best_prio < s->running_priority[cpu]) {
-                DPRINTF("Raised pending IRQ %d (cpu %d)\n", best_irq, cpu);
-                level = 1;
-            }
-        }
-        qemu_set_irq(s->parent_irq[cpu], level);
-    }
-}
-
-void gic_set_pending_private(GICState *s, int cpu, int irq)
-{
-    int cm = 1 << cpu;
-
-    if (GIC_TEST_PENDING(irq, cm))
-        return;
-
-    DPRINTF("Set %d pending cpu %d\n", irq, cpu);
-    GIC_SET_PENDING(irq, cm);
-    gic_update(s);
-}
-
-/* Process a change in an external IRQ input.  */
-static void gic_set_irq(void *opaque, int irq, int level)
-{
-    /* Meaning of the 'irq' parameter:
-     *  [0..N-1] : external interrupts
-     *  [N..N+31] : PPI (internal) interrupts for CPU 0
-     *  [N+32..N+63] : PPI (internal interrupts for CPU 1
-     *  ...
-     */
-    GICState *s = (GICState *)opaque;
-    int cm, target;
-    if (irq < (s->num_irq - GIC_INTERNAL)) {
-        /* The first external input line is internal interrupt 32.  */
-        cm = ALL_CPU_MASK;
-        irq += GIC_INTERNAL;
-        target = GIC_TARGET(irq);
-    } else {
-        int cpu;
-        irq -= (s->num_irq - GIC_INTERNAL);
-        cpu = irq / GIC_INTERNAL;
-        irq %= GIC_INTERNAL;
-        cm = 1 << cpu;
-        target = cm;
-    }
-
-    if (level == GIC_TEST_LEVEL(irq, cm)) {
-        return;
-    }
-
-    if (level) {
-        GIC_SET_LEVEL(irq, cm);
-        if (GIC_TEST_TRIGGER(irq) || GIC_TEST_ENABLED(irq, cm)) {
-            DPRINTF("Set %d pending mask %x\n", irq, target);
-            GIC_SET_PENDING(irq, target);
-        }
-    } else {
-        GIC_CLEAR_LEVEL(irq, cm);
-    }
-    gic_update(s);
-}
-
-static void gic_set_running_irq(GICState *s, int cpu, int irq)
-{
-    s->running_irq[cpu] = irq;
-    if (irq == 1023) {
-        s->running_priority[cpu] = 0x100;
-    } else {
-        s->running_priority[cpu] = GIC_GET_PRIORITY(irq, cpu);
-    }
-    gic_update(s);
-}
-
-uint32_t gic_acknowledge_irq(GICState *s, int cpu)
-{
-    int new_irq;
-    int cm = 1 << cpu;
-    new_irq = s->current_pending[cpu];
-    if (new_irq == 1023
-            || GIC_GET_PRIORITY(new_irq, cpu) >= s->running_priority[cpu]) {
-        DPRINTF("ACK no pending IRQ\n");
-        return 1023;
-    }
-    s->last_active[new_irq][cpu] = s->running_irq[cpu];
-    /* Clear pending flags for both level and edge triggered interrupts.
-       Level triggered IRQs will be reasserted once they become inactive.  */
-    GIC_CLEAR_PENDING(new_irq, GIC_TEST_MODEL(new_irq) ? ALL_CPU_MASK : cm);
-    gic_set_running_irq(s, cpu, new_irq);
-    DPRINTF("ACK %d\n", new_irq);
-    return new_irq;
-}
-
-void gic_complete_irq(GICState *s, int cpu, int irq)
-{
-    int update = 0;
-    int cm = 1 << cpu;
-    DPRINTF("EOI %d\n", irq);
-    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.
-         * 2. If software writes the number of a non-existent interrupt
-         * this must be a subcase of "value written does not match the last
-         * valid interrupt value read from the Interrupt Acknowledge
-         * register" and so this is UNPREDICTABLE. We choose to ignore it.
-         */
-        return;
-    }
-    if (s->running_irq[cpu] == 1023)
-        return; /* No active IRQ.  */
-    /* Mark level triggered interrupts as pending if they are still
-       raised.  */
-    if (!GIC_TEST_TRIGGER(irq) && GIC_TEST_ENABLED(irq, cm)
-        && GIC_TEST_LEVEL(irq, cm) && (GIC_TARGET(irq) & cm) != 0) {
-        DPRINTF("Set %d pending mask %x\n", irq, cm);
-        GIC_SET_PENDING(irq, cm);
-        update = 1;
-    }
-    if (irq != s->running_irq[cpu]) {
-        /* Complete an IRQ that is not currently running.  */
-        int tmp = s->running_irq[cpu];
-        while (s->last_active[tmp][cpu] != 1023) {
-            if (s->last_active[tmp][cpu] == irq) {
-                s->last_active[tmp][cpu] = s->last_active[irq][cpu];
-                break;
-            }
-            tmp = s->last_active[tmp][cpu];
-        }
-        if (update) {
-            gic_update(s);
-        }
-    } else {
-        /* Complete the current running IRQ.  */
-        gic_set_running_irq(s, cpu, s->last_active[s->running_irq[cpu]][cpu]);
-    }
-}
-
-static uint32_t gic_dist_readb(void *opaque, hwaddr offset)
-{
-    GICState *s = (GICState *)opaque;
-    uint32_t res;
-    int irq;
-    int i;
-    int cpu;
-    int cm;
-    int mask;
-
-    cpu = gic_get_current_cpu(s);
-    cm = 1 << cpu;
-    if (offset < 0x100) {
-        if (offset == 0)
-            return s->enabled;
-        if (offset == 4)
-            return ((s->num_irq / 32) - 1) | ((NUM_CPU(s) - 1) << 5);
-        if (offset < 0x08)
-            return 0;
-        if (offset >= 0x80) {
-            /* Interrupt Security , RAZ/WI */
-            return 0;
-        }
-        goto bad_reg;
-    } else if (offset < 0x200) {
-        /* Interrupt Set/Clear Enable.  */
-        if (offset < 0x180)
-            irq = (offset - 0x100) * 8;
-        else
-            irq = (offset - 0x180) * 8;
-        irq += GIC_BASE_IRQ;
-        if (irq >= s->num_irq)
-            goto bad_reg;
-        res = 0;
-        for (i = 0; i < 8; i++) {
-            if (GIC_TEST_ENABLED(irq + i, cm)) {
-                res |= (1 << i);
-            }
-        }
-    } else if (offset < 0x300) {
-        /* Interrupt Set/Clear Pending.  */
-        if (offset < 0x280)
-            irq = (offset - 0x200) * 8;
-        else
-            irq = (offset - 0x280) * 8;
-        irq += GIC_BASE_IRQ;
-        if (irq >= s->num_irq)
-            goto bad_reg;
-        res = 0;
-        mask = (irq < GIC_INTERNAL) ?  cm : ALL_CPU_MASK;
-        for (i = 0; i < 8; i++) {
-            if (GIC_TEST_PENDING(irq + i, mask)) {
-                res |= (1 << i);
-            }
-        }
-    } else if (offset < 0x400) {
-        /* Interrupt Active.  */
-        irq = (offset - 0x300) * 8 + GIC_BASE_IRQ;
-        if (irq >= s->num_irq)
-            goto bad_reg;
-        res = 0;
-        mask = (irq < GIC_INTERNAL) ?  cm : ALL_CPU_MASK;
-        for (i = 0; i < 8; i++) {
-            if (GIC_TEST_ACTIVE(irq + i, mask)) {
-                res |= (1 << i);
-            }
-        }
-    } else if (offset < 0x800) {
-        /* Interrupt Priority.  */
-        irq = (offset - 0x400) + GIC_BASE_IRQ;
-        if (irq >= s->num_irq)
-            goto bad_reg;
-        res = GIC_GET_PRIORITY(irq, cpu);
-    } else if (offset < 0xc00) {
-        /* Interrupt CPU Target.  */
-        if (s->num_cpu == 1 && s->revision != REV_11MPCORE) {
-            /* For uniprocessor GICs these RAZ/WI */
-            res = 0;
-        } else {
-            irq = (offset - 0x800) + GIC_BASE_IRQ;
-            if (irq >= s->num_irq) {
-                goto bad_reg;
-            }
-            if (irq >= 29 && irq <= 31) {
-                res = cm;
-            } else {
-                res = GIC_TARGET(irq);
-            }
-        }
-    } else if (offset < 0xf00) {
-        /* Interrupt Configuration.  */
-        irq = (offset - 0xc00) * 2 + GIC_BASE_IRQ;
-        if (irq >= s->num_irq)
-            goto bad_reg;
-        res = 0;
-        for (i = 0; i < 4; i++) {
-            if (GIC_TEST_MODEL(irq + i))
-                res |= (1 << (i * 2));
-            if (GIC_TEST_TRIGGER(irq + i))
-                res |= (2 << (i * 2));
-        }
-    } else if (offset < 0xfe0) {
-        goto bad_reg;
-    } else /* offset >= 0xfe0 */ {
-        if (offset & 3) {
-            res = 0;
-        } else {
-            res = gic_id[(offset - 0xfe0) >> 2];
-        }
-    }
-    return res;
-bad_reg:
-    qemu_log_mask(LOG_GUEST_ERROR,
-                  "gic_dist_readb: Bad offset %x\n", (int)offset);
-    return 0;
-}
-
-static uint32_t gic_dist_readw(void *opaque, hwaddr offset)
-{
-    uint32_t val;
-    val = gic_dist_readb(opaque, offset);
-    val |= gic_dist_readb(opaque, offset + 1) << 8;
-    return val;
-}
-
-static uint32_t gic_dist_readl(void *opaque, hwaddr offset)
-{
-    uint32_t val;
-    val = gic_dist_readw(opaque, offset);
-    val |= gic_dist_readw(opaque, offset + 2) << 16;
-    return val;
-}
-
-static void gic_dist_writeb(void *opaque, hwaddr offset,
-                            uint32_t value)
-{
-    GICState *s = (GICState *)opaque;
-    int irq;
-    int i;
-    int cpu;
-
-    cpu = gic_get_current_cpu(s);
-    if (offset < 0x100) {
-        if (offset == 0) {
-            s->enabled = (value & 1);
-            DPRINTF("Distribution %sabled\n", s->enabled ? "En" : "Dis");
-        } else if (offset < 4) {
-            /* ignored.  */
-        } else if (offset >= 0x80) {
-            /* Interrupt Security Registers, RAZ/WI */
-        } else {
-            goto bad_reg;
-        }
-    } else if (offset < 0x180) {
-        /* Interrupt Set Enable.  */
-        irq = (offset - 0x100) * 8 + GIC_BASE_IRQ;
-        if (irq >= s->num_irq)
-            goto bad_reg;
-        if (irq < 16)
-          value = 0xff;
-        for (i = 0; i < 8; i++) {
-            if (value & (1 << i)) {
-                int mask =
-                    (irq < GIC_INTERNAL) ? (1 << cpu) : GIC_TARGET(irq + i);
-                int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK;
-
-                if (!GIC_TEST_ENABLED(irq + i, cm)) {
-                    DPRINTF("Enabled IRQ %d\n", irq + i);
-                }
-                GIC_SET_ENABLED(irq + i, cm);
-                /* If a raised level triggered IRQ enabled then mark
-                   is as pending.  */
-                if (GIC_TEST_LEVEL(irq + i, mask)
-                        && !GIC_TEST_TRIGGER(irq + i)) {
-                    DPRINTF("Set %d pending mask %x\n", irq + i, mask);
-                    GIC_SET_PENDING(irq + i, mask);
-                }
-            }
-        }
-    } else if (offset < 0x200) {
-        /* Interrupt Clear Enable.  */
-        irq = (offset - 0x180) * 8 + GIC_BASE_IRQ;
-        if (irq >= s->num_irq)
-            goto bad_reg;
-        if (irq < 16)
-          value = 0;
-        for (i = 0; i < 8; i++) {
-            if (value & (1 << i)) {
-                int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK;
-
-                if (GIC_TEST_ENABLED(irq + i, cm)) {
-                    DPRINTF("Disabled IRQ %d\n", irq + i);
-                }
-                GIC_CLEAR_ENABLED(irq + i, cm);
-            }
-        }
-    } else if (offset < 0x280) {
-        /* Interrupt Set Pending.  */
-        irq = (offset - 0x200) * 8 + GIC_BASE_IRQ;
-        if (irq >= s->num_irq)
-            goto bad_reg;
-        if (irq < 16)
-          irq = 0;
-
-        for (i = 0; i < 8; i++) {
-            if (value & (1 << i)) {
-                GIC_SET_PENDING(irq + i, GIC_TARGET(irq + i));
-            }
-        }
-    } else if (offset < 0x300) {
-        /* Interrupt Clear Pending.  */
-        irq = (offset - 0x280) * 8 + GIC_BASE_IRQ;
-        if (irq >= s->num_irq)
-            goto bad_reg;
-        for (i = 0; i < 8; i++) {
-            /* ??? This currently clears the pending bit for all CPUs, even
-               for per-CPU interrupts.  It's unclear whether this is the
-               corect behavior.  */
-            if (value & (1 << i)) {
-                GIC_CLEAR_PENDING(irq + i, ALL_CPU_MASK);
-            }
-        }
-    } else if (offset < 0x400) {
-        /* Interrupt Active.  */
-        goto bad_reg;
-    } else if (offset < 0x800) {
-        /* Interrupt Priority.  */
-        irq = (offset - 0x400) + GIC_BASE_IRQ;
-        if (irq >= s->num_irq)
-            goto bad_reg;
-        if (irq < GIC_INTERNAL) {
-            s->priority1[irq][cpu] = value;
-        } else {
-            s->priority2[irq - GIC_INTERNAL] = value;
-        }
-    } else if (offset < 0xc00) {
-        /* Interrupt CPU Target. RAZ/WI on uniprocessor GICs, with the
-         * annoying exception of the 11MPCore's GIC.
-         */
-        if (s->num_cpu != 1 || s->revision == REV_11MPCORE) {
-            irq = (offset - 0x800) + GIC_BASE_IRQ;
-            if (irq >= s->num_irq) {
-                goto bad_reg;
-            }
-            if (irq < 29) {
-                value = 0;
-            } else if (irq < GIC_INTERNAL) {
-                value = ALL_CPU_MASK;
-            }
-            s->irq_target[irq] = value & ALL_CPU_MASK;
-        }
-    } else if (offset < 0xf00) {
-        /* Interrupt Configuration.  */
-        irq = (offset - 0xc00) * 4 + GIC_BASE_IRQ;
-        if (irq >= s->num_irq)
-            goto bad_reg;
-        if (irq < GIC_INTERNAL)
-            value |= 0xaa;
-        for (i = 0; i < 4; i++) {
-            if (value & (1 << (i * 2))) {
-                GIC_SET_MODEL(irq + i);
-            } else {
-                GIC_CLEAR_MODEL(irq + i);
-            }
-            if (value & (2 << (i * 2))) {
-                GIC_SET_TRIGGER(irq + i);
-            } else {
-                GIC_CLEAR_TRIGGER(irq + i);
-            }
-        }
-    } else {
-        /* 0xf00 is only handled for 32-bit writes.  */
-        goto bad_reg;
-    }
-    gic_update(s);
-    return;
-bad_reg:
-    qemu_log_mask(LOG_GUEST_ERROR,
-                  "gic_dist_writeb: Bad offset %x\n", (int)offset);
-}
-
-static void gic_dist_writew(void *opaque, hwaddr offset,
-                            uint32_t value)
-{
-    gic_dist_writeb(opaque, offset, value & 0xff);
-    gic_dist_writeb(opaque, offset + 1, value >> 8);
-}
-
-static void gic_dist_writel(void *opaque, hwaddr offset,
-                            uint32_t value)
-{
-    GICState *s = (GICState *)opaque;
-    if (offset == 0xf00) {
-        int cpu;
-        int irq;
-        int mask;
-
-        cpu = gic_get_current_cpu(s);
-        irq = value & 0x3ff;
-        switch ((value >> 24) & 3) {
-        case 0:
-            mask = (value >> 16) & ALL_CPU_MASK;
-            break;
-        case 1:
-            mask = ALL_CPU_MASK ^ (1 << cpu);
-            break;
-        case 2:
-            mask = 1 << cpu;
-            break;
-        default:
-            DPRINTF("Bad Soft Int target filter\n");
-            mask = ALL_CPU_MASK;
-            break;
-        }
-        GIC_SET_PENDING(irq, mask);
-        gic_update(s);
-        return;
-    }
-    gic_dist_writew(opaque, offset, value & 0xffff);
-    gic_dist_writew(opaque, offset + 2, value >> 16);
-}
-
-static const MemoryRegionOps gic_dist_ops = {
-    .old_mmio = {
-        .read = { gic_dist_readb, gic_dist_readw, gic_dist_readl, },
-        .write = { gic_dist_writeb, gic_dist_writew, gic_dist_writel, },
-    },
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static uint32_t gic_cpu_read(GICState *s, int cpu, int offset)
-{
-    switch (offset) {
-    case 0x00: /* Control */
-        return s->cpu_enabled[cpu];
-    case 0x04: /* Priority mask */
-        return s->priority_mask[cpu];
-    case 0x08: /* Binary Point */
-        /* ??? Not implemented.  */
-        return 0;
-    case 0x0c: /* Acknowledge */
-        return gic_acknowledge_irq(s, cpu);
-    case 0x14: /* Running Priority */
-        return s->running_priority[cpu];
-    case 0x18: /* Highest Pending Interrupt */
-        return s->current_pending[cpu];
-    default:
-        qemu_log_mask(LOG_GUEST_ERROR,
-                      "gic_cpu_read: Bad offset %x\n", (int)offset);
-        return 0;
-    }
-}
-
-static void gic_cpu_write(GICState *s, int cpu, int offset, uint32_t value)
-{
-    switch (offset) {
-    case 0x00: /* Control */
-        s->cpu_enabled[cpu] = (value & 1);
-        DPRINTF("CPU %d %sabled\n", cpu, s->cpu_enabled[cpu] ? "En" : "Dis");
-        break;
-    case 0x04: /* Priority mask */
-        s->priority_mask[cpu] = (value & 0xff);
-        break;
-    case 0x08: /* Binary Point */
-        /* ??? Not implemented.  */
-        break;
-    case 0x10: /* End Of Interrupt */
-        return gic_complete_irq(s, cpu, value & 0x3ff);
-    default:
-        qemu_log_mask(LOG_GUEST_ERROR,
-                      "gic_cpu_write: Bad offset %x\n", (int)offset);
-        return;
-    }
-    gic_update(s);
-}
-
-/* Wrappers to read/write the GIC CPU interface for the current CPU */
-static uint64_t gic_thiscpu_read(void *opaque, hwaddr addr,
-                                 unsigned size)
-{
-    GICState *s = (GICState *)opaque;
-    return gic_cpu_read(s, gic_get_current_cpu(s), addr);
-}
-
-static void gic_thiscpu_write(void *opaque, hwaddr addr,
-                              uint64_t value, unsigned size)
-{
-    GICState *s = (GICState *)opaque;
-    gic_cpu_write(s, gic_get_current_cpu(s), addr, value);
-}
-
-/* Wrappers to read/write the GIC CPU interface for a specific CPU.
- * These just decode the opaque pointer into GICState* + cpu id.
- */
-static uint64_t gic_do_cpu_read(void *opaque, hwaddr addr,
-                                unsigned size)
-{
-    GICState **backref = (GICState **)opaque;
-    GICState *s = *backref;
-    int id = (backref - s->backref);
-    return gic_cpu_read(s, id, addr);
-}
-
-static void gic_do_cpu_write(void *opaque, hwaddr addr,
-                             uint64_t value, unsigned size)
-{
-    GICState **backref = (GICState **)opaque;
-    GICState *s = *backref;
-    int id = (backref - s->backref);
-    gic_cpu_write(s, id, addr, value);
-}
-
-static const MemoryRegionOps gic_thiscpu_ops = {
-    .read = gic_thiscpu_read,
-    .write = gic_thiscpu_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static const MemoryRegionOps gic_cpu_ops = {
-    .read = gic_do_cpu_read,
-    .write = gic_do_cpu_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-void gic_init_irqs_and_distributor(GICState *s, int num_irq)
-{
-    int i;
-
-    i = s->num_irq - GIC_INTERNAL;
-    /* For the GIC, also expose incoming GPIO lines for PPIs for each CPU.
-     * GPIO array layout is thus:
-     *  [0..N-1] SPIs
-     *  [N..N+31] PPIs for CPU 0
-     *  [N+32..N+63] PPIs for CPU 1
-     *   ...
-     */
-    if (s->revision != REV_NVIC) {
-        i += (GIC_INTERNAL * s->num_cpu);
-    }
-    qdev_init_gpio_in(&s->busdev.qdev, gic_set_irq, i);
-    for (i = 0; i < NUM_CPU(s); i++) {
-        sysbus_init_irq(&s->busdev, &s->parent_irq[i]);
-    }
-    memory_region_init_io(&s->iomem, &gic_dist_ops, s, "gic_dist", 0x1000);
-}
-
-static void arm_gic_realize(DeviceState *dev, Error **errp)
-{
-    /* Device instance realize function for the GIC sysbus device */
-    int i;
-    GICState *s = ARM_GIC(dev);
-    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
-    ARMGICClass *agc = ARM_GIC_GET_CLASS(s);
-
-    agc->parent_realize(dev, errp);
-    if (error_is_set(errp)) {
-        return;
-    }
-
-    gic_init_irqs_and_distributor(s, s->num_irq);
-
-    /* Memory regions for the CPU interfaces (NVIC doesn't have these):
-     * a region for "CPU interface for this core", then a region for
-     * "CPU interface for core 0", "for core 1", ...
-     * NB that the memory region size of 0x100 applies for the 11MPCore
-     * and also cores following the GIC v1 spec (ie A9).
-     * GIC v2 defines a larger memory region (0x1000) so this will need
-     * to be extended when we implement A15.
-     */
-    memory_region_init_io(&s->cpuiomem[0], &gic_thiscpu_ops, s,
-                          "gic_cpu", 0x100);
-    for (i = 0; i < NUM_CPU(s); i++) {
-        s->backref[i] = s;
-        memory_region_init_io(&s->cpuiomem[i+1], &gic_cpu_ops, &s->backref[i],
-                              "gic_cpu", 0x100);
-    }
-    /* Distributor */
-    sysbus_init_mmio(sbd, &s->iomem);
-    /* cpu interfaces (one for "current cpu" plus one per cpu) */
-    for (i = 0; i <= NUM_CPU(s); i++) {
-        sysbus_init_mmio(sbd, &s->cpuiomem[i]);
-    }
-}
-
-static void arm_gic_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    ARMGICClass *agc = ARM_GIC_CLASS(klass);
-
-    dc->no_user = 1;
-    agc->parent_realize = dc->realize;
-    dc->realize = arm_gic_realize;
-}
-
-static const TypeInfo arm_gic_info = {
-    .name = TYPE_ARM_GIC,
-    .parent = TYPE_ARM_GIC_COMMON,
-    .instance_size = sizeof(GICState),
-    .class_init = arm_gic_class_init,
-    .class_size = sizeof(ARMGICClass),
-};
-
-static void arm_gic_register_types(void)
-{
-    type_register_static(&arm_gic_info);
-}
-
-type_init(arm_gic_register_types)
diff --git a/hw/arm_gic_common.c b/hw/arm_gic_common.c
deleted file mode 100644 (file)
index f2dc8bf..0000000
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * ARM GIC support - common bits of emulated and KVM kernel model
- *
- * 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 "hw/arm_gic_internal.h"
-
-static void gic_save(QEMUFile *f, void *opaque)
-{
-    GICState *s = (GICState *)opaque;
-    ARMGICCommonClass *c = ARM_GIC_COMMON_GET_CLASS(s);
-    int i;
-    int j;
-
-    if (c->pre_save) {
-        c->pre_save(s);
-    }
-
-    qemu_put_be32(f, s->enabled);
-    for (i = 0; i < s->num_cpu; i++) {
-        qemu_put_be32(f, s->cpu_enabled[i]);
-        for (j = 0; j < GIC_INTERNAL; j++) {
-            qemu_put_be32(f, s->priority1[j][i]);
-        }
-        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 < s->num_irq - GIC_INTERNAL; i++) {
-        qemu_put_be32(f, s->priority2[i]);
-    }
-    for (i = 0; i < s->num_irq; i++) {
-        qemu_put_be32(f, s->irq_target[i]);
-        qemu_put_byte(f, s->irq_state[i].enabled);
-        qemu_put_byte(f, s->irq_state[i].pending);
-        qemu_put_byte(f, s->irq_state[i].active);
-        qemu_put_byte(f, s->irq_state[i].level);
-        qemu_put_byte(f, s->irq_state[i].model);
-        qemu_put_byte(f, s->irq_state[i].trigger);
-    }
-}
-
-static int gic_load(QEMUFile *f, void *opaque, int version_id)
-{
-    GICState *s = (GICState *)opaque;
-    ARMGICCommonClass *c = ARM_GIC_COMMON_GET_CLASS(s);
-    int i;
-    int j;
-
-    if (version_id != 3) {
-        return -EINVAL;
-    }
-
-    s->enabled = qemu_get_be32(f);
-    for (i = 0; i < s->num_cpu; i++) {
-        s->cpu_enabled[i] = qemu_get_be32(f);
-        for (j = 0; j < GIC_INTERNAL; j++) {
-            s->priority1[j][i] = qemu_get_be32(f);
-        }
-        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 < s->num_irq - GIC_INTERNAL; i++) {
-        s->priority2[i] = qemu_get_be32(f);
-    }
-    for (i = 0; i < s->num_irq; i++) {
-        s->irq_target[i] = qemu_get_be32(f);
-        s->irq_state[i].enabled = qemu_get_byte(f);
-        s->irq_state[i].pending = qemu_get_byte(f);
-        s->irq_state[i].active = qemu_get_byte(f);
-        s->irq_state[i].level = qemu_get_byte(f);
-        s->irq_state[i].model = qemu_get_byte(f);
-        s->irq_state[i].trigger = qemu_get_byte(f);
-    }
-
-    if (c->post_load) {
-        c->post_load(s);
-    }
-
-    return 0;
-}
-
-static void arm_gic_common_realize(DeviceState *dev, Error **errp)
-{
-    GICState *s = ARM_GIC_COMMON(dev);
-    int num_irq = s->num_irq;
-
-    if (s->num_cpu > NCPU) {
-        error_setg(errp, "requested %u CPUs exceeds GIC maximum %d",
-                   s->num_cpu, NCPU);
-        return;
-    }
-    s->num_irq += GIC_BASE_IRQ;
-    if (s->num_irq > GIC_MAXIRQ) {
-        error_setg(errp,
-                   "requested %u interrupt lines exceeds GIC maximum %d",
-                   num_irq, GIC_MAXIRQ);
-        return;
-    }
-    /* ITLinesNumber is represented as (N / 32) - 1 (see
-     * gic_dist_readb) so this is an implementation imposed
-     * restriction, not an architectural one:
-     */
-    if (s->num_irq < 32 || (s->num_irq % 32)) {
-        error_setg(errp,
-                   "%d interrupt lines unsupported: not divisible by 32",
-                   num_irq);
-        return;
-    }
-
-    register_savevm(NULL, "arm_gic", -1, 3, gic_save, gic_load, s);
-}
-
-static void arm_gic_common_reset(DeviceState *dev)
-{
-    GICState *s = FROM_SYSBUS(GICState, SYS_BUS_DEVICE(dev));
-    int i;
-    memset(s->irq_state, 0, GIC_MAXIRQ * sizeof(gic_irq_state));
-    for (i = 0 ; i < s->num_cpu; i++) {
-        if (s->revision == REV_11MPCORE) {
-            s->priority_mask[i] = 0xf0;
-        } else {
-            s->priority_mask[i] = 0;
-        }
-        s->current_pending[i] = 1023;
-        s->running_irq[i] = 1023;
-        s->running_priority[i] = 0x100;
-        s->cpu_enabled[i] = 0;
-    }
-    for (i = 0; i < 16; i++) {
-        GIC_SET_ENABLED(i, ALL_CPU_MASK);
-        GIC_SET_TRIGGER(i);
-    }
-    if (s->num_cpu == 1) {
-        /* For uniprocessor GICs all interrupts always target the sole CPU */
-        for (i = 0; i < GIC_MAXIRQ; i++) {
-            s->irq_target[i] = 1;
-        }
-    }
-    s->enabled = 0;
-}
-
-static Property arm_gic_common_properties[] = {
-    DEFINE_PROP_UINT32("num-cpu", GICState, num_cpu, 1),
-    DEFINE_PROP_UINT32("num-irq", GICState, num_irq, 32),
-    /* Revision can be 1 or 2 for GIC architecture specification
-     * versions 1 or 2, or 0 to indicate the legacy 11MPCore GIC.
-     * (Internally, 0xffffffff also indicates "not a GIC but an NVIC".)
-     */
-    DEFINE_PROP_UINT32("revision", GICState, revision, 1),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void arm_gic_common_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-
-    dc->reset = arm_gic_common_reset;
-    dc->realize = arm_gic_common_realize;
-    dc->props = arm_gic_common_properties;
-    dc->no_user = 1;
-}
-
-static const TypeInfo arm_gic_common_type = {
-    .name = TYPE_ARM_GIC_COMMON,
-    .parent = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(GICState),
-    .class_size = sizeof(ARMGICCommonClass),
-    .class_init = arm_gic_common_class_init,
-    .abstract = true,
-};
-
-static void register_types(void)
-{
-    type_register_static(&arm_gic_common_type);
-}
-
-type_init(register_types)
diff --git a/hw/arm_gic_internal.h b/hw/arm_gic_internal.h
deleted file mode 100644 (file)
index 3e1928b..0000000
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * ARM GIC support - internal interfaces
- *
- * 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/>.
- */
-
-#ifndef QEMU_ARM_GIC_INTERNAL_H
-#define QEMU_ARM_GIC_INTERNAL_H
-
-#include "hw/sysbus.h"
-
-/* Maximum number of possible interrupts, determined by the GIC architecture */
-#define GIC_MAXIRQ 1020
-/* First 32 are private to each CPU (SGIs and PPIs). */
-#define GIC_INTERNAL 32
-/* Maximum number of possible CPU interfaces, determined by GIC architecture */
-#define NCPU 8
-
-#define ALL_CPU_MASK ((unsigned)(((1 << NCPU) - 1)))
-
-/* The NVIC has 16 internal vectors.  However these are not exposed
-   through the normal GIC interface.  */
-#define GIC_BASE_IRQ ((s->revision == REV_NVIC) ? 32 : 0)
-
-#define GIC_SET_ENABLED(irq, cm) s->irq_state[irq].enabled |= (cm)
-#define GIC_CLEAR_ENABLED(irq, cm) s->irq_state[irq].enabled &= ~(cm)
-#define GIC_TEST_ENABLED(irq, cm) ((s->irq_state[irq].enabled & (cm)) != 0)
-#define GIC_SET_PENDING(irq, cm) s->irq_state[irq].pending |= (cm)
-#define GIC_CLEAR_PENDING(irq, cm) s->irq_state[irq].pending &= ~(cm)
-#define GIC_TEST_PENDING(irq, cm) ((s->irq_state[irq].pending & (cm)) != 0)
-#define GIC_SET_ACTIVE(irq, cm) s->irq_state[irq].active |= (cm)
-#define GIC_CLEAR_ACTIVE(irq, cm) s->irq_state[irq].active &= ~(cm)
-#define GIC_TEST_ACTIVE(irq, cm) ((s->irq_state[irq].active & (cm)) != 0)
-#define GIC_SET_MODEL(irq) s->irq_state[irq].model = 1
-#define GIC_CLEAR_MODEL(irq) s->irq_state[irq].model = 0
-#define GIC_TEST_MODEL(irq) s->irq_state[irq].model
-#define GIC_SET_LEVEL(irq, cm) s->irq_state[irq].level = (cm)
-#define GIC_CLEAR_LEVEL(irq, cm) s->irq_state[irq].level &= ~(cm)
-#define GIC_TEST_LEVEL(irq, cm) ((s->irq_state[irq].level & (cm)) != 0)
-#define GIC_SET_TRIGGER(irq) s->irq_state[irq].trigger = 1
-#define GIC_CLEAR_TRIGGER(irq) s->irq_state[irq].trigger = 0
-#define GIC_TEST_TRIGGER(irq) s->irq_state[irq].trigger
-#define GIC_GET_PRIORITY(irq, cpu) (((irq) < GIC_INTERNAL) ?            \
-                                    s->priority1[irq][cpu] :            \
-                                    s->priority2[(irq) - GIC_INTERNAL])
-#define GIC_TARGET(irq) s->irq_target[irq]
-
-typedef struct gic_irq_state {
-    /* The enable bits are only banked for per-cpu interrupts.  */
-    unsigned enabled:NCPU;
-    unsigned pending:NCPU;
-    unsigned active:NCPU;
-    unsigned level:NCPU;
-    unsigned model:1; /* 0 = N:N, 1 = 1:N */
-    unsigned trigger:1; /* nonzero = edge triggered.  */
-} gic_irq_state;
-
-typedef struct GICState {
-    SysBusDevice busdev;
-    qemu_irq parent_irq[NCPU];
-    int enabled;
-    int cpu_enabled[NCPU];
-
-    gic_irq_state irq_state[GIC_MAXIRQ];
-    int irq_target[GIC_MAXIRQ];
-    int priority1[GIC_INTERNAL][NCPU];
-    int priority2[GIC_MAXIRQ - GIC_INTERNAL];
-    int last_active[GIC_MAXIRQ][NCPU];
-
-    int priority_mask[NCPU];
-    int running_irq[NCPU];
-    int running_priority[NCPU];
-    int current_pending[NCPU];
-
-    uint32_t num_cpu;
-
-    MemoryRegion iomem; /* Distributor */
-    /* This is just so we can have an opaque pointer which identifies
-     * both this GIC and which CPU interface we should be accessing.
-     */
-    struct GICState *backref[NCPU];
-    MemoryRegion cpuiomem[NCPU+1]; /* CPU interfaces */
-    uint32_t num_irq;
-    uint32_t revision;
-} GICState;
-
-/* The special cases for the revision property: */
-#define REV_11MPCORE 0
-#define REV_NVIC 0xffffffff
-
-void gic_set_pending_private(GICState *s, int cpu, int irq);
-uint32_t gic_acknowledge_irq(GICState *s, int cpu);
-void gic_complete_irq(GICState *s, int cpu, int irq);
-void gic_update(GICState *s);
-void gic_init_irqs_and_distributor(GICState *s, int num_irq);
-
-#define TYPE_ARM_GIC_COMMON "arm_gic_common"
-#define ARM_GIC_COMMON(obj) \
-     OBJECT_CHECK(GICState, (obj), TYPE_ARM_GIC_COMMON)
-#define ARM_GIC_COMMON_CLASS(klass) \
-     OBJECT_CLASS_CHECK(ARMGICCommonClass, (klass), TYPE_ARM_GIC_COMMON)
-#define ARM_GIC_COMMON_GET_CLASS(obj) \
-     OBJECT_GET_CLASS(ARMGICCommonClass, (obj), TYPE_ARM_GIC_COMMON)
-
-typedef struct ARMGICCommonClass {
-    SysBusDeviceClass parent_class;
-    void (*pre_save)(GICState *s);
-    void (*post_load)(GICState *s);
-} ARMGICCommonClass;
-
-#define TYPE_ARM_GIC "arm_gic"
-#define ARM_GIC(obj) \
-     OBJECT_CHECK(GICState, (obj), TYPE_ARM_GIC)
-#define ARM_GIC_CLASS(klass) \
-     OBJECT_CLASS_CHECK(ARMGICClass, (klass), TYPE_ARM_GIC)
-#define ARM_GIC_GET_CLASS(obj) \
-     OBJECT_GET_CLASS(ARMGICClass, (obj), TYPE_ARM_GIC)
-
-typedef struct ARMGICClass {
-    ARMGICCommonClass parent_class;
-    DeviceRealize parent_realize;
-} ARMGICClass;
-
-#endif /* !QEMU_ARM_GIC_INTERNAL_H */
diff --git a/hw/arm_l2x0.c b/hw/arm_l2x0.c
deleted file mode 100644 (file)
index eb4427d..0000000
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
- * ARM dummy L210, L220, PL310 cache controller.
- *
- * 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 any later version, 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 "hw/sysbus.h"
-
-/* L2C-310 r3p2 */
-#define CACHE_ID 0x410000c8
-
-typedef struct l2x0_state {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-    uint32_t cache_type;
-    uint32_t ctrl;
-    uint32_t aux_ctrl;
-    uint32_t data_ctrl;
-    uint32_t tag_ctrl;
-    uint32_t filter_start;
-    uint32_t filter_end;
-} l2x0_state;
-
-static const VMStateDescription vmstate_l2x0 = {
-    .name = "l2x0",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT32(ctrl, l2x0_state),
-        VMSTATE_UINT32(aux_ctrl, l2x0_state),
-        VMSTATE_UINT32(data_ctrl, l2x0_state),
-        VMSTATE_UINT32(tag_ctrl, l2x0_state),
-        VMSTATE_UINT32(filter_start, l2x0_state),
-        VMSTATE_UINT32(filter_end, l2x0_state),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-
-static uint64_t l2x0_priv_read(void *opaque, hwaddr offset,
-                               unsigned size)
-{
-    uint32_t cache_data;
-    l2x0_state *s = (l2x0_state *)opaque;
-    offset &= 0xfff;
-    if (offset >= 0x730 && offset < 0x800) {
-        return 0; /* cache ops complete */
-    }
-    switch (offset) {
-    case 0:
-        return CACHE_ID;
-    case 0x4:
-        /* aux_ctrl values affect cache_type values */
-        cache_data = (s->aux_ctrl & (7 << 17)) >> 15;
-        cache_data |= (s->aux_ctrl & (1 << 16)) >> 16;
-        return s->cache_type |= (cache_data << 18) | (cache_data << 6);
-    case 0x100:
-        return s->ctrl;
-    case 0x104:
-        return s->aux_ctrl;
-    case 0x108:
-        return s->tag_ctrl;
-    case 0x10C:
-        return s->data_ctrl;
-    case 0xC00:
-        return s->filter_start;
-    case 0xC04:
-        return s->filter_end;
-    case 0xF40:
-        return 0;
-    case 0xF60:
-        return 0;
-    case 0xF80:
-        return 0;
-    default:
-        qemu_log_mask(LOG_GUEST_ERROR,
-                      "l2x0_priv_read: Bad offset %x\n", (int)offset);
-        break;
-    }
-    return 0;
-}
-
-static void l2x0_priv_write(void *opaque, hwaddr offset,
-                            uint64_t value, unsigned size)
-{
-    l2x0_state *s = (l2x0_state *)opaque;
-    offset &= 0xfff;
-    if (offset >= 0x730 && offset < 0x800) {
-        /* ignore */
-        return;
-    }
-    switch (offset) {
-    case 0x100:
-        s->ctrl = value & 1;
-        break;
-    case 0x104:
-        s->aux_ctrl = value;
-        break;
-    case 0x108:
-        s->tag_ctrl = value;
-        break;
-    case 0x10C:
-        s->data_ctrl = value;
-        break;
-    case 0xC00:
-        s->filter_start = value;
-        break;
-    case 0xC04:
-        s->filter_end = value;
-        break;
-    case 0xF40:
-        return;
-    case 0xF60:
-        return;
-    case 0xF80:
-        return;
-    default:
-        qemu_log_mask(LOG_GUEST_ERROR,
-                      "l2x0_priv_write: Bad offset %x\n", (int)offset);
-        break;
-    }
-}
-
-static void l2x0_priv_reset(DeviceState *dev)
-{
-    l2x0_state *s = DO_UPCAST(l2x0_state, busdev.qdev, dev);
-
-    s->ctrl = 0;
-    s->aux_ctrl = 0x02020000;
-    s->tag_ctrl = 0;
-    s->data_ctrl = 0;
-    s->filter_start = 0;
-    s->filter_end = 0;
-}
-
-static const MemoryRegionOps l2x0_mem_ops = {
-    .read = l2x0_priv_read,
-    .write = l2x0_priv_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
- };
-
-static int l2x0_priv_init(SysBusDevice *dev)
-{
-    l2x0_state *s = FROM_SYSBUS(l2x0_state, dev);
-
-    memory_region_init_io(&s->iomem, &l2x0_mem_ops, s, "l2x0_cc", 0x1000);
-    sysbus_init_mmio(dev, &s->iomem);
-    return 0;
-}
-
-static Property l2x0_properties[] = {
-    DEFINE_PROP_UINT32("cache-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 const TypeInfo l2x0_info = {
-    .name = "l2x0",
-    .parent = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(l2x0_state),
-    .class_init = l2x0_class_init,
-};
-
-static void l2x0_register_types(void)
-{
-    type_register_static(&l2x0_info);
-}
-
-type_init(l2x0_register_types)
diff --git a/hw/arm_mptimer.c b/hw/arm_mptimer.c
deleted file mode 100644 (file)
index f59a9f1..0000000
+++ /dev/null
@@ -1,308 +0,0 @@
-/*
- * Private peripheral timer/watchdog blocks for ARM 11MPCore and A9MP
- *
- * Copyright (c) 2006-2007 CodeSourcery.
- * Copyright (c) 2011 Linaro Limited
- * Written by Paul Brook, 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 "hw/sysbus.h"
-#include "qemu/timer.h"
-
-/* This device implements the per-cpu private timer and watchdog block
- * which is used in both the ARM11MPCore and Cortex-A9MP.
- */
-
-#define MAX_CPUS 4
-
-/* State of a single timer or watchdog block */
-typedef struct {
-    uint32_t count;
-    uint32_t load;
-    uint32_t control;
-    uint32_t status;
-    int64_t tick;
-    QEMUTimer *timer;
-    qemu_irq irq;
-    MemoryRegion iomem;
-} TimerBlock;
-
-typedef struct {
-    SysBusDevice busdev;
-    uint32_t num_cpu;
-    TimerBlock timerblock[MAX_CPUS];
-    MemoryRegion iomem;
-} ARMMPTimerState;
-
-static inline int get_current_cpu(ARMMPTimerState *s)
-{
-    CPUState *cpu_single_cpu = ENV_GET_CPU(cpu_single_env);
-
-    if (cpu_single_cpu->cpu_index >= s->num_cpu) {
-        hw_error("arm_mptimer: num-cpu %d but this cpu is %d!\n",
-                 s->num_cpu, cpu_single_cpu->cpu_index);
-    }
-    return cpu_single_cpu->cpu_index;
-}
-
-static inline void timerblock_update_irq(TimerBlock *tb)
-{
-    qemu_set_irq(tb->irq, tb->status);
-}
-
-/* Return conversion factor from mpcore timer ticks to qemu timer ticks.  */
-static inline uint32_t timerblock_scale(TimerBlock *tb)
-{
-    return (((tb->control >> 8) & 0xff) + 1) * 10;
-}
-
-static void timerblock_reload(TimerBlock *tb, int restart)
-{
-    if (tb->count == 0) {
-        return;
-    }
-    if (restart) {
-        tb->tick = qemu_get_clock_ns(vm_clock);
-    }
-    tb->tick += (int64_t)tb->count * timerblock_scale(tb);
-    qemu_mod_timer(tb->timer, tb->tick);
-}
-
-static void timerblock_tick(void *opaque)
-{
-    TimerBlock *tb = (TimerBlock *)opaque;
-    tb->status = 1;
-    if (tb->control & 2) {
-        tb->count = tb->load;
-        timerblock_reload(tb, 0);
-    } else {
-        tb->count = 0;
-    }
-    timerblock_update_irq(tb);
-}
-
-static uint64_t timerblock_read(void *opaque, hwaddr addr,
-                                unsigned size)
-{
-    TimerBlock *tb = (TimerBlock *)opaque;
-    int64_t val;
-    switch (addr) {
-    case 0: /* Load */
-        return tb->load;
-    case 4: /* Counter.  */
-        if (((tb->control & 1) == 0) || (tb->count == 0)) {
-            return 0;
-        }
-        /* Slow and ugly, but hopefully won't happen too often.  */
-        val = tb->tick - qemu_get_clock_ns(vm_clock);
-        val /= timerblock_scale(tb);
-        if (val < 0) {
-            val = 0;
-        }
-        return val;
-    case 8: /* Control.  */
-        return tb->control;
-    case 12: /* Interrupt status.  */
-        return tb->status;
-    default:
-        return 0;
-    }
-}
-
-static void timerblock_write(void *opaque, hwaddr addr,
-                             uint64_t value, unsigned size)
-{
-    TimerBlock *tb = (TimerBlock *)opaque;
-    int64_t old;
-    switch (addr) {
-    case 0: /* Load */
-        tb->load = value;
-        /* Fall through.  */
-    case 4: /* Counter.  */
-        if ((tb->control & 1) && tb->count) {
-            /* Cancel the previous timer.  */
-            qemu_del_timer(tb->timer);
-        }
-        tb->count = value;
-        if (tb->control & 1) {
-            timerblock_reload(tb, 1);
-        }
-        break;
-    case 8: /* Control.  */
-        old = tb->control;
-        tb->control = value;
-        if (((old & 1) == 0) && (value & 1)) {
-            if (tb->count == 0 && (tb->control & 2)) {
-                tb->count = tb->load;
-            }
-            timerblock_reload(tb, 1);
-        }
-        break;
-    case 12: /* Interrupt status.  */
-        tb->status &= ~value;
-        timerblock_update_irq(tb);
-        break;
-    }
-}
-
-/* Wrapper functions to implement the "read timer/watchdog for
- * the current CPU" memory regions.
- */
-static uint64_t arm_thistimer_read(void *opaque, hwaddr addr,
-                                   unsigned size)
-{
-    ARMMPTimerState *s = (ARMMPTimerState *)opaque;
-    int id = get_current_cpu(s);
-    return timerblock_read(&s->timerblock[id], addr, size);
-}
-
-static void arm_thistimer_write(void *opaque, hwaddr addr,
-                                uint64_t value, unsigned size)
-{
-    ARMMPTimerState *s = (ARMMPTimerState *)opaque;
-    int id = get_current_cpu(s);
-    timerblock_write(&s->timerblock[id], addr, value, size);
-}
-
-static const MemoryRegionOps arm_thistimer_ops = {
-    .read = arm_thistimer_read,
-    .write = arm_thistimer_write,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static const MemoryRegionOps timerblock_ops = {
-    .read = timerblock_read,
-    .write = timerblock_write,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void timerblock_reset(TimerBlock *tb)
-{
-    tb->count = 0;
-    tb->load = 0;
-    tb->control = 0;
-    tb->status = 0;
-    tb->tick = 0;
-    if (tb->timer) {
-        qemu_del_timer(tb->timer);
-    }
-}
-
-static void arm_mptimer_reset(DeviceState *dev)
-{
-    ARMMPTimerState *s =
-        FROM_SYSBUS(ARMMPTimerState, SYS_BUS_DEVICE(dev));
-    int i;
-    for (i = 0; i < ARRAY_SIZE(s->timerblock); i++) {
-        timerblock_reset(&s->timerblock[i]);
-    }
-}
-
-static int arm_mptimer_init(SysBusDevice *dev)
-{
-    ARMMPTimerState *s = FROM_SYSBUS(ARMMPTimerState, dev);
-    int i;
-    if (s->num_cpu < 1 || s->num_cpu > MAX_CPUS) {
-        hw_error("%s: num-cpu must be between 1 and %d\n", __func__, MAX_CPUS);
-    }
-    /* We implement one timer block per CPU, and expose multiple MMIO regions:
-     *  * region 0 is "timer for this core"
-     *  * region 1 is "timer for core 0"
-     *  * region 2 is "timer for core 1"
-     * and so on.
-     * The outgoing interrupt lines are
-     *  * timer for core 0
-     *  * timer for core 1
-     * and so on.
-     */
-    memory_region_init_io(&s->iomem, &arm_thistimer_ops, s,
-                          "arm_mptimer_timer", 0x20);
-    sysbus_init_mmio(dev, &s->iomem);
-    for (i = 0; i < s->num_cpu; i++) {
-        TimerBlock *tb = &s->timerblock[i];
-        tb->timer = qemu_new_timer_ns(vm_clock, timerblock_tick, tb);
-        sysbus_init_irq(dev, &tb->irq);
-        memory_region_init_io(&tb->iomem, &timerblock_ops, tb,
-                              "arm_mptimer_timerblock", 0x20);
-        sysbus_init_mmio(dev, &tb->iomem);
-    }
-
-    return 0;
-}
-
-static const VMStateDescription vmstate_timerblock = {
-    .name = "arm_mptimer_timerblock",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT32(count, TimerBlock),
-        VMSTATE_UINT32(load, TimerBlock),
-        VMSTATE_UINT32(control, TimerBlock),
-        VMSTATE_UINT32(status, TimerBlock),
-        VMSTATE_INT64(tick, TimerBlock),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static const VMStateDescription vmstate_arm_mptimer = {
-    .name = "arm_mptimer",
-    .version_id = 2,
-    .minimum_version_id = 2,
-    .fields = (VMStateField[]) {
-        VMSTATE_STRUCT_VARRAY_UINT32(timerblock, ARMMPTimerState, num_cpu,
-                                     2, vmstate_timerblock, TimerBlock),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static Property arm_mptimer_properties[] = {
-    DEFINE_PROP_UINT32("num-cpu", ARMMPTimerState, 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 const TypeInfo arm_mptimer_info = {
-    .name          = "arm_mptimer",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(ARMMPTimerState),
-    .class_init    = arm_mptimer_class_init,
-};
-
-static void arm_mptimer_register_types(void)
-{
-    type_register_static(&arm_mptimer_info);
-}
-
-type_init(arm_mptimer_register_types)
diff --git a/hw/arm_sysctl.c b/hw/arm_sysctl.c
deleted file mode 100644 (file)
index 25fc6ea..0000000
+++ /dev/null
@@ -1,649 +0,0 @@
-/*
- * Status and system control registers for ARM RealView/Versatile boards.
- *
- * Copyright (c) 2006-2007 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the GPL.
- */
-
-#include "hw/hw.h"
-#include "qemu/timer.h"
-#include "qemu/bitops.h"
-#include "hw/sysbus.h"
-#include "hw/primecell.h"
-#include "sysemu/sysemu.h"
-
-#define LOCK_VALUE 0xa05f
-
-typedef struct {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-    qemu_irq pl110_mux_ctrl;
-
-    uint32_t sys_id;
-    uint32_t leds;
-    uint16_t lockval;
-    uint32_t cfgdata1;
-    uint32_t cfgdata2;
-    uint32_t flags;
-    uint32_t nvflags;
-    uint32_t resetlevel;
-    uint32_t proc_id;
-    uint32_t sys_mci;
-    uint32_t sys_cfgdata;
-    uint32_t sys_cfgctrl;
-    uint32_t sys_cfgstat;
-    uint32_t sys_clcd;
-    uint32_t mb_clock[6];
-    uint32_t *db_clock;
-    uint32_t db_num_vsensors;
-    uint32_t *db_voltage;
-    uint32_t db_num_clocks;
-    uint32_t *db_clock_reset;
-} arm_sysctl_state;
-
-static const VMStateDescription vmstate_arm_sysctl = {
-    .name = "realview_sysctl",
-    .version_id = 4,
-    .minimum_version_id = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT32(leds, arm_sysctl_state),
-        VMSTATE_UINT16(lockval, arm_sysctl_state),
-        VMSTATE_UINT32(cfgdata1, arm_sysctl_state),
-        VMSTATE_UINT32(cfgdata2, arm_sysctl_state),
-        VMSTATE_UINT32(flags, arm_sysctl_state),
-        VMSTATE_UINT32(nvflags, arm_sysctl_state),
-        VMSTATE_UINT32(resetlevel, arm_sysctl_state),
-        VMSTATE_UINT32_V(sys_mci, arm_sysctl_state, 2),
-        VMSTATE_UINT32_V(sys_cfgdata, arm_sysctl_state, 2),
-        VMSTATE_UINT32_V(sys_cfgctrl, arm_sysctl_state, 2),
-        VMSTATE_UINT32_V(sys_cfgstat, arm_sysctl_state, 2),
-        VMSTATE_UINT32_V(sys_clcd, arm_sysctl_state, 3),
-        VMSTATE_UINT32_ARRAY_V(mb_clock, arm_sysctl_state, 6, 4),
-        VMSTATE_VARRAY_UINT32(db_clock, arm_sysctl_state, db_num_clocks,
-                              4, vmstate_info_uint32, uint32_t),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-/* The PB926 actually uses a different format for
- * its SYS_ID register. Fortunately the bits which are
- * board type on later boards are distinct.
- */
-#define BOARD_ID_PB926 0x100
-#define BOARD_ID_EB 0x140
-#define BOARD_ID_PBA8 0x178
-#define BOARD_ID_PBX 0x182
-#define BOARD_ID_VEXPRESS 0x190
-
-static int board_id(arm_sysctl_state *s)
-{
-    /* Extract the board ID field from the SYS_ID register value */
-    return (s->sys_id >> 16) & 0xfff;
-}
-
-static void arm_sysctl_reset(DeviceState *d)
-{
-    arm_sysctl_state *s = FROM_SYSBUS(arm_sysctl_state, SYS_BUS_DEVICE(d));
-    int i;
-
-    s->leds = 0;
-    s->lockval = 0;
-    s->cfgdata1 = 0;
-    s->cfgdata2 = 0;
-    s->flags = 0;
-    s->resetlevel = 0;
-    /* Motherboard oscillators (in Hz) */
-    s->mb_clock[0] = 50000000; /* Static memory clock: 50MHz */
-    s->mb_clock[1] = 23750000; /* motherboard CLCD clock: 23.75MHz */
-    s->mb_clock[2] = 24000000; /* IO FPGA peripheral clock: 24MHz */
-    s->mb_clock[3] = 24000000; /* IO FPGA reserved clock: 24MHz */
-    s->mb_clock[4] = 24000000; /* System bus global clock: 24MHz */
-    s->mb_clock[5] = 24000000; /* IO FPGA reserved clock: 24MHz */
-    /* Daughterboard oscillators: reset from property values */
-    for (i = 0; i < s->db_num_clocks; i++) {
-        s->db_clock[i] = s->db_clock_reset[i];
-    }
-    if (board_id(s) == BOARD_ID_VEXPRESS) {
-        /* On VExpress this register will RAZ/WI */
-        s->sys_clcd = 0;
-    } else {
-        /* All others: CLCDID 0x1f, indicating VGA */
-        s->sys_clcd = 0x1f00;
-    }
-}
-
-static uint64_t arm_sysctl_read(void *opaque, hwaddr offset,
-                                unsigned size)
-{
-    arm_sysctl_state *s = (arm_sysctl_state *)opaque;
-
-    switch (offset) {
-    case 0x00: /* ID */
-        return s->sys_id;
-    case 0x04: /* SW */
-        /* General purpose hardware switches.
-           We don't have a useful way of exposing these to the user.  */
-        return 0;
-    case 0x08: /* LED */
-        return s->leds;
-    case 0x20: /* LOCK */
-        return s->lockval;
-    case 0x0c: /* OSC0 */
-    case 0x10: /* OSC1 */
-    case 0x14: /* OSC2 */
-    case 0x18: /* OSC3 */
-    case 0x1c: /* OSC4 */
-    case 0x24: /* 100HZ */
-        /* ??? Implement these.  */
-        return 0;
-    case 0x28: /* CFGDATA1 */
-        return s->cfgdata1;
-    case 0x2c: /* CFGDATA2 */
-        return s->cfgdata2;
-    case 0x30: /* FLAGS */
-        return s->flags;
-    case 0x38: /* NVFLAGS */
-        return s->nvflags;
-    case 0x40: /* RESETCTL */
-        if (board_id(s) == BOARD_ID_VEXPRESS) {
-            /* reserved: RAZ/WI */
-            return 0;
-        }
-        return s->resetlevel;
-    case 0x44: /* PCICTL */
-        return 1;
-    case 0x48: /* MCI */
-        return s->sys_mci;
-    case 0x4c: /* FLASH */
-        return 0;
-    case 0x50: /* CLCD */
-        return s->sys_clcd;
-    case 0x54: /* CLCDSER */
-        return 0;
-    case 0x58: /* BOOTCS */
-        return 0;
-    case 0x5c: /* 24MHz */
-        return muldiv64(qemu_get_clock_ns(vm_clock), 24000000, get_ticks_per_sec());
-    case 0x60: /* MISC */
-        return 0;
-    case 0x84: /* PROCID0 */
-        return s->proc_id;
-    case 0x88: /* PROCID1 */
-        return 0xff000000;
-    case 0x64: /* DMAPSR0 */
-    case 0x68: /* DMAPSR1 */
-    case 0x6c: /* DMAPSR2 */
-    case 0x70: /* IOSEL */
-    case 0x74: /* PLDCTL */
-    case 0x80: /* BUSID */
-    case 0x8c: /* OSCRESET0 */
-    case 0x90: /* OSCRESET1 */
-    case 0x94: /* OSCRESET2 */
-    case 0x98: /* OSCRESET3 */
-    case 0x9c: /* OSCRESET4 */
-    case 0xc0: /* SYS_TEST_OSC0 */
-    case 0xc4: /* SYS_TEST_OSC1 */
-    case 0xc8: /* SYS_TEST_OSC2 */
-    case 0xcc: /* SYS_TEST_OSC3 */
-    case 0xd0: /* SYS_TEST_OSC4 */
-        return 0;
-    case 0xa0: /* SYS_CFGDATA */
-        if (board_id(s) != BOARD_ID_VEXPRESS) {
-            goto bad_reg;
-        }
-        return s->sys_cfgdata;
-    case 0xa4: /* SYS_CFGCTRL */
-        if (board_id(s) != BOARD_ID_VEXPRESS) {
-            goto bad_reg;
-        }
-        return s->sys_cfgctrl;
-    case 0xa8: /* SYS_CFGSTAT */
-        if (board_id(s) != BOARD_ID_VEXPRESS) {
-            goto bad_reg;
-        }
-        return s->sys_cfgstat;
-    default:
-    bad_reg:
-        qemu_log_mask(LOG_GUEST_ERROR,
-                      "arm_sysctl_read: Bad register offset 0x%x\n",
-                      (int)offset);
-        return 0;
-    }
-}
-
-/* SYS_CFGCTRL functions */
-#define SYS_CFG_OSC 1
-#define SYS_CFG_VOLT 2
-#define SYS_CFG_AMP 3
-#define SYS_CFG_TEMP 4
-#define SYS_CFG_RESET 5
-#define SYS_CFG_SCC 6
-#define SYS_CFG_MUXFPGA 7
-#define SYS_CFG_SHUTDOWN 8
-#define SYS_CFG_REBOOT 9
-#define SYS_CFG_DVIMODE 11
-#define SYS_CFG_POWER 12
-#define SYS_CFG_ENERGY 13
-
-/* SYS_CFGCTRL site field values */
-#define SYS_CFG_SITE_MB 0
-#define SYS_CFG_SITE_DB1 1
-#define SYS_CFG_SITE_DB2 2
-
-/**
- * vexpress_cfgctrl_read:
- * @s: arm_sysctl_state pointer
- * @dcc, @function, @site, @position, @device: split out values from
- * SYS_CFGCTRL register
- * @val: pointer to where to put the read data on success
- *
- * Handle a VExpress SYS_CFGCTRL register read. On success, return true and
- * write the read value to *val. On failure, return false (and val may
- * or may not be written to).
- */
-static bool vexpress_cfgctrl_read(arm_sysctl_state *s, unsigned int dcc,
-                                  unsigned int function, unsigned int site,
-                                  unsigned int position, unsigned int device,
-                                  uint32_t *val)
-{
-    /* We don't support anything other than DCC 0, board stack position 0
-     * or sites other than motherboard/daughterboard:
-     */
-    if (dcc != 0 || position != 0 ||
-        (site != SYS_CFG_SITE_MB && site != SYS_CFG_SITE_DB1)) {
-        goto cfgctrl_unimp;
-    }
-
-    switch (function) {
-    case SYS_CFG_VOLT:
-        if (site == SYS_CFG_SITE_DB1 && device < s->db_num_vsensors) {
-            *val = s->db_voltage[device];
-            return true;
-        }
-        if (site == SYS_CFG_SITE_MB && device == 0) {
-            /* There is only one motherboard voltage sensor:
-             * VIO : 3.3V : bus voltage between mother and daughterboard
-             */
-            *val = 3300000;
-            return true;
-        }
-        break;
-    case SYS_CFG_OSC:
-        if (site == SYS_CFG_SITE_MB && device < sizeof(s->mb_clock)) {
-            /* motherboard clock */
-            *val = s->mb_clock[device];
-            return true;
-        }
-        if (site == SYS_CFG_SITE_DB1 && device < s->db_num_clocks) {
-            /* daughterboard clock */
-            *val = s->db_clock[device];
-            return true;
-        }
-        break;
-    default:
-        break;
-    }
-
-cfgctrl_unimp:
-    qemu_log_mask(LOG_UNIMP,
-                  "arm_sysctl: Unimplemented SYS_CFGCTRL read of function "
-                  "0x%x DCC 0x%x site 0x%x position 0x%x device 0x%x\n",
-                  function, dcc, site, position, device);
-    return false;
-}
-
-/**
- * vexpress_cfgctrl_write:
- * @s: arm_sysctl_state pointer
- * @dcc, @function, @site, @position, @device: split out values from
- * SYS_CFGCTRL register
- * @val: data to write
- *
- * Handle a VExpress SYS_CFGCTRL register write. On success, return true.
- * On failure, return false.
- */
-static bool vexpress_cfgctrl_write(arm_sysctl_state *s, unsigned int dcc,
-                                   unsigned int function, unsigned int site,
-                                   unsigned int position, unsigned int device,
-                                   uint32_t val)
-{
-    /* We don't support anything other than DCC 0, board stack position 0
-     * or sites other than motherboard/daughterboard:
-     */
-    if (dcc != 0 || position != 0 ||
-        (site != SYS_CFG_SITE_MB && site != SYS_CFG_SITE_DB1)) {
-        goto cfgctrl_unimp;
-    }
-
-    switch (function) {
-    case SYS_CFG_OSC:
-        if (site == SYS_CFG_SITE_MB && device < sizeof(s->mb_clock)) {
-            /* motherboard clock */
-            s->mb_clock[device] = val;
-            return true;
-        }
-        if (site == SYS_CFG_SITE_DB1 && device < s->db_num_clocks) {
-            /* daughterboard clock */
-            s->db_clock[device] = val;
-            return true;
-        }
-        break;
-    case SYS_CFG_MUXFPGA:
-        if (site == SYS_CFG_SITE_MB && device == 0) {
-            /* Select whether video output comes from motherboard
-             * or daughterboard: log and ignore as QEMU doesn't
-             * support this.
-             */
-            qemu_log_mask(LOG_UNIMP, "arm_sysctl: selection of video output "
-                          "not supported, ignoring\n");
-            return true;
-        }
-        break;
-    case SYS_CFG_SHUTDOWN:
-        if (site == SYS_CFG_SITE_MB && device == 0) {
-            qemu_system_shutdown_request();
-            return true;
-        }
-        break;
-    case SYS_CFG_REBOOT:
-        if (site == SYS_CFG_SITE_MB && device == 0) {
-            qemu_system_reset_request();
-            return true;
-        }
-        break;
-    case SYS_CFG_DVIMODE:
-        if (site == SYS_CFG_SITE_MB && device == 0) {
-            /* Selecting DVI mode is meaningless for QEMU: we will
-             * always display the output correctly according to the
-             * pixel height/width programmed into the CLCD controller.
-             */
-            return true;
-        }
-    default:
-        break;
-    }
-
-cfgctrl_unimp:
-    qemu_log_mask(LOG_UNIMP,
-                  "arm_sysctl: Unimplemented SYS_CFGCTRL write of function "
-                  "0x%x DCC 0x%x site 0x%x position 0x%x device 0x%x\n",
-                  function, dcc, site, position, device);
-    return false;
-}
-
-static void arm_sysctl_write(void *opaque, hwaddr offset,
-                             uint64_t val, unsigned size)
-{
-    arm_sysctl_state *s = (arm_sysctl_state *)opaque;
-
-    switch (offset) {
-    case 0x08: /* LED */
-        s->leds = val;
-        break;
-    case 0x0c: /* OSC0 */
-    case 0x10: /* OSC1 */
-    case 0x14: /* OSC2 */
-    case 0x18: /* OSC3 */
-    case 0x1c: /* OSC4 */
-        /* ??? */
-        break;
-    case 0x20: /* LOCK */
-        if (val == LOCK_VALUE)
-            s->lockval = val;
-        else
-            s->lockval = val & 0x7fff;
-        break;
-    case 0x28: /* CFGDATA1 */
-        /* ??? Need to implement this.  */
-        s->cfgdata1 = val;
-        break;
-    case 0x2c: /* CFGDATA2 */
-        /* ??? Need to implement this.  */
-        s->cfgdata2 = val;
-        break;
-    case 0x30: /* FLAGSSET */
-        s->flags |= val;
-        break;
-    case 0x34: /* FLAGSCLR */
-        s->flags &= ~val;
-        break;
-    case 0x38: /* NVFLAGSSET */
-        s->nvflags |= val;
-        break;
-    case 0x3c: /* NVFLAGSCLR */
-        s->nvflags &= ~val;
-        break;
-    case 0x40: /* RESETCTL */
-        switch (board_id(s)) {
-        case BOARD_ID_PB926:
-            if (s->lockval == LOCK_VALUE) {
-                s->resetlevel = val;
-                if (val & 0x100) {
-                    qemu_system_reset_request();
-                }
-            }
-            break;
-        case BOARD_ID_PBX:
-        case BOARD_ID_PBA8:
-            if (s->lockval == LOCK_VALUE) {
-                s->resetlevel = val;
-                if (val & 0x04) {
-                    qemu_system_reset_request();
-                }
-            }
-            break;
-        case BOARD_ID_VEXPRESS:
-        case BOARD_ID_EB:
-        default:
-            /* reserved: RAZ/WI */
-            break;
-        }
-        break;
-    case 0x44: /* PCICTL */
-        /* nothing to do.  */
-        break;
-    case 0x4c: /* FLASH */
-        break;
-    case 0x50: /* CLCD */
-        switch (board_id(s)) {
-        case BOARD_ID_PB926:
-            /* On 926 bits 13:8 are R/O, bits 1:0 control
-             * the mux that defines how to interpret the PL110
-             * graphics format, and other bits are r/w but we
-             * don't implement them to do anything.
-             */
-            s->sys_clcd &= 0x3f00;
-            s->sys_clcd |= val & ~0x3f00;
-            qemu_set_irq(s->pl110_mux_ctrl, val & 3);
-            break;
-        case BOARD_ID_EB:
-            /* The EB is the same except that there is no mux since
-             * the EB has a PL111.
-             */
-            s->sys_clcd &= 0x3f00;
-            s->sys_clcd |= val & ~0x3f00;
-            break;
-        case BOARD_ID_PBA8:
-        case BOARD_ID_PBX:
-            /* On PBA8 and PBX bit 7 is r/w and all other bits
-             * are either r/o or RAZ/WI.
-             */
-            s->sys_clcd &= (1 << 7);
-            s->sys_clcd |= val & ~(1 << 7);
-            break;
-        case BOARD_ID_VEXPRESS:
-        default:
-            /* On VExpress this register is unimplemented and will RAZ/WI */
-            break;
-        }
-        break;
-    case 0x54: /* CLCDSER */
-    case 0x64: /* DMAPSR0 */
-    case 0x68: /* DMAPSR1 */
-    case 0x6c: /* DMAPSR2 */
-    case 0x70: /* IOSEL */
-    case 0x74: /* PLDCTL */
-    case 0x80: /* BUSID */
-    case 0x84: /* PROCID0 */
-    case 0x88: /* PROCID1 */
-    case 0x8c: /* OSCRESET0 */
-    case 0x90: /* OSCRESET1 */
-    case 0x94: /* OSCRESET2 */
-    case 0x98: /* OSCRESET3 */
-    case 0x9c: /* OSCRESET4 */
-        break;
-    case 0xa0: /* SYS_CFGDATA */
-        if (board_id(s) != BOARD_ID_VEXPRESS) {
-            goto bad_reg;
-        }
-        s->sys_cfgdata = val;
-        return;
-    case 0xa4: /* SYS_CFGCTRL */
-        if (board_id(s) != BOARD_ID_VEXPRESS) {
-            goto bad_reg;
-        }
-        /* Undefined bits [19:18] are RAZ/WI, and writing to
-         * the start bit just triggers the action; it always reads
-         * as zero.
-         */
-        s->sys_cfgctrl = val & ~((3 << 18) | (1 << 31));
-        if (val & (1 << 31)) {
-            /* Start bit set -- actually do something */
-            unsigned int dcc = extract32(s->sys_cfgctrl, 26, 4);
-            unsigned int function = extract32(s->sys_cfgctrl, 20, 6);
-            unsigned int site = extract32(s->sys_cfgctrl, 16, 2);
-            unsigned int position = extract32(s->sys_cfgctrl, 12, 4);
-            unsigned int device = extract32(s->sys_cfgctrl, 0, 12);
-            s->sys_cfgstat = 1;            /* complete */
-            if (s->sys_cfgctrl & (1 << 30)) {
-                if (!vexpress_cfgctrl_write(s, dcc, function, site, position,
-                                            device, s->sys_cfgdata)) {
-                    s->sys_cfgstat |= 2;        /* error */
-                }
-            } else {
-                uint32_t val;
-                if (!vexpress_cfgctrl_read(s, dcc, function, site, position,
-                                           device, &val)) {
-                    s->sys_cfgstat |= 2;        /* error */
-                } else {
-                    s->sys_cfgdata = val;
-                }
-            }
-        }
-        s->sys_cfgctrl &= ~(1 << 31);
-        return;
-    case 0xa8: /* SYS_CFGSTAT */
-        if (board_id(s) != BOARD_ID_VEXPRESS) {
-            goto bad_reg;
-        }
-        s->sys_cfgstat = val & 3;
-        return;
-    default:
-    bad_reg:
-        qemu_log_mask(LOG_GUEST_ERROR,
-                      "arm_sysctl_write: Bad register offset 0x%x\n",
-                      (int)offset);
-        return;
-    }
-}
-
-static const MemoryRegionOps arm_sysctl_ops = {
-    .read = arm_sysctl_read,
-    .write = arm_sysctl_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void arm_sysctl_gpio_set(void *opaque, int line, int level)
-{
-    arm_sysctl_state *s = (arm_sysctl_state *)opaque;
-    switch (line) {
-    case ARM_SYSCTL_GPIO_MMC_WPROT:
-    {
-        /* For PB926 and EB write-protect is bit 2 of SYS_MCI;
-         * for all later boards it is bit 1.
-         */
-        int bit = 2;
-        if ((board_id(s) == BOARD_ID_PB926) || (board_id(s) == BOARD_ID_EB)) {
-            bit = 4;
-        }
-        s->sys_mci &= ~bit;
-        if (level) {
-            s->sys_mci |= bit;
-        }
-        break;
-    }
-    case ARM_SYSCTL_GPIO_MMC_CARDIN:
-        s->sys_mci &= ~1;
-        if (level) {
-            s->sys_mci |= 1;
-        }
-        break;
-    }
-}
-
-static void arm_sysctl_init(Object *obj)
-{
-    DeviceState *dev = DEVICE(obj);
-    SysBusDevice *sd = SYS_BUS_DEVICE(obj);
-    arm_sysctl_state *s = FROM_SYSBUS(arm_sysctl_state, sd);
-
-    memory_region_init_io(&s->iomem, &arm_sysctl_ops, s, "arm-sysctl", 0x1000);
-    sysbus_init_mmio(sd, &s->iomem);
-    qdev_init_gpio_in(dev, arm_sysctl_gpio_set, 2);
-    qdev_init_gpio_out(dev, &s->pl110_mux_ctrl, 1);
-}
-
-static void arm_sysctl_realize(DeviceState *d, Error **errp)
-{
-    arm_sysctl_state *s = FROM_SYSBUS(arm_sysctl_state, SYS_BUS_DEVICE(d));
-    s->db_clock = g_new0(uint32_t, s->db_num_clocks);
-}
-
-static void arm_sysctl_finalize(Object *obj)
-{
-    SysBusDevice *dev = SYS_BUS_DEVICE(obj);
-    arm_sysctl_state *s = FROM_SYSBUS(arm_sysctl_state, dev);
-    g_free(s->db_voltage);
-    g_free(s->db_clock);
-    g_free(s->db_clock_reset);
-}
-
-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),
-    /* Daughterboard power supply voltages (as reported via SYS_CFG) */
-    DEFINE_PROP_ARRAY("db-voltage", arm_sysctl_state, db_num_vsensors,
-                      db_voltage, qdev_prop_uint32, uint32_t),
-    /* Daughterboard clock reset values (as reported via SYS_CFG) */
-    DEFINE_PROP_ARRAY("db-clock", arm_sysctl_state, db_num_clocks,
-                      db_clock_reset, qdev_prop_uint32, uint32_t),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void arm_sysctl_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-
-    dc->realize = arm_sysctl_realize;
-    dc->reset = arm_sysctl_reset;
-    dc->vmsd = &vmstate_arm_sysctl;
-    dc->props = arm_sysctl_properties;
-}
-
-static const TypeInfo arm_sysctl_info = {
-    .name          = "realview_sysctl",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(arm_sysctl_state),
-    .instance_init = arm_sysctl_init,
-    .instance_finalize = arm_sysctl_finalize,
-    .class_init    = arm_sysctl_class_init,
-};
-
-static void arm_sysctl_register_types(void)
-{
-    type_register_static(&arm_sysctl_info);
-}
-
-type_init(arm_sysctl_register_types)
diff --git a/hw/arm_timer.c b/hw/arm_timer.c
deleted file mode 100644 (file)
index 6449870..0000000
+++ /dev/null
@@ -1,399 +0,0 @@
-/*
- * ARM PrimeCell Timer modules.
- *
- * Copyright (c) 2005-2006 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the GPL.
- */
-
-#include "hw/sysbus.h"
-#include "qemu/timer.h"
-#include "qemu-common.h"
-#include "hw/qdev.h"
-#include "hw/ptimer.h"
-
-/* Common timer implementation.  */
-
-#define TIMER_CTRL_ONESHOT      (1 << 0)
-#define TIMER_CTRL_32BIT        (1 << 1)
-#define TIMER_CTRL_DIV1         (0 << 2)
-#define TIMER_CTRL_DIV16        (1 << 2)
-#define TIMER_CTRL_DIV256       (2 << 2)
-#define TIMER_CTRL_IE           (1 << 5)
-#define TIMER_CTRL_PERIODIC     (1 << 6)
-#define TIMER_CTRL_ENABLE       (1 << 7)
-
-typedef struct {
-    ptimer_state *timer;
-    uint32_t control;
-    uint32_t limit;
-    int freq;
-    int int_level;
-    qemu_irq irq;
-} arm_timer_state;
-
-/* Check all active timers, and schedule the next timer interrupt.  */
-
-static void arm_timer_update(arm_timer_state *s)
-{
-    /* Update interrupts.  */
-    if (s->int_level && (s->control & TIMER_CTRL_IE)) {
-        qemu_irq_raise(s->irq);
-    } else {
-        qemu_irq_lower(s->irq);
-    }
-}
-
-static uint32_t arm_timer_read(void *opaque, hwaddr offset)
-{
-    arm_timer_state *s = (arm_timer_state *)opaque;
-
-    switch (offset >> 2) {
-    case 0: /* TimerLoad */
-    case 6: /* TimerBGLoad */
-        return s->limit;
-    case 1: /* TimerValue */
-        return ptimer_get_count(s->timer);
-    case 2: /* TimerControl */
-        return s->control;
-    case 4: /* TimerRIS */
-        return s->int_level;
-    case 5: /* TimerMIS */
-        if ((s->control & TIMER_CTRL_IE) == 0)
-            return 0;
-        return s->int_level;
-    default:
-        qemu_log_mask(LOG_GUEST_ERROR,
-                      "%s: Bad offset %x\n", __func__, (int)offset);
-        return 0;
-    }
-}
-
-/* Reset the timer limit after settings have changed.  */
-static void arm_timer_recalibrate(arm_timer_state *s, int reload)
-{
-    uint32_t limit;
-
-    if ((s->control & (TIMER_CTRL_PERIODIC | TIMER_CTRL_ONESHOT)) == 0) {
-        /* Free running.  */
-        if (s->control & TIMER_CTRL_32BIT)
-            limit = 0xffffffff;
-        else
-            limit = 0xffff;
-    } else {
-          /* Periodic.  */
-          limit = s->limit;
-    }
-    ptimer_set_limit(s->timer, limit, reload);
-}
-
-static void arm_timer_write(void *opaque, hwaddr offset,
-                            uint32_t value)
-{
-    arm_timer_state *s = (arm_timer_state *)opaque;
-    int freq;
-
-    switch (offset >> 2) {
-    case 0: /* TimerLoad */
-        s->limit = value;
-        arm_timer_recalibrate(s, 1);
-        break;
-    case 1: /* TimerValue */
-        /* ??? Linux seems to want to write to this readonly register.
-           Ignore it.  */
-        break;
-    case 2: /* TimerControl */
-        if (s->control & TIMER_CTRL_ENABLE) {
-            /* Pause the timer if it is running.  This may cause some
-               inaccuracy dure to rounding, but avoids a whole lot of other
-               messyness.  */
-            ptimer_stop(s->timer);
-        }
-        s->control = value;
-        freq = s->freq;
-        /* ??? Need to recalculate expiry time after changing divisor.  */
-        switch ((value >> 2) & 3) {
-        case 1: freq >>= 4; break;
-        case 2: freq >>= 8; break;
-        }
-        arm_timer_recalibrate(s, s->control & TIMER_CTRL_ENABLE);
-        ptimer_set_freq(s->timer, freq);
-        if (s->control & TIMER_CTRL_ENABLE) {
-            /* Restart the timer if still enabled.  */
-            ptimer_run(s->timer, (s->control & TIMER_CTRL_ONESHOT) != 0);
-        }
-        break;
-    case 3: /* TimerIntClr */
-        s->int_level = 0;
-        break;
-    case 6: /* TimerBGLoad */
-        s->limit = value;
-        arm_timer_recalibrate(s, 0);
-        break;
-    default:
-        qemu_log_mask(LOG_GUEST_ERROR,
-                      "%s: Bad offset %x\n", __func__, (int)offset);
-    }
-    arm_timer_update(s);
-}
-
-static void arm_timer_tick(void *opaque)
-{
-    arm_timer_state *s = (arm_timer_state *)opaque;
-    s->int_level = 1;
-    arm_timer_update(s);
-}
-
-static const VMStateDescription vmstate_arm_timer = {
-    .name = "arm_timer",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField[]) {
-        VMSTATE_UINT32(control, arm_timer_state),
-        VMSTATE_UINT32(limit, arm_timer_state),
-        VMSTATE_INT32(int_level, arm_timer_state),
-        VMSTATE_PTIMER(timer, arm_timer_state),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static arm_timer_state *arm_timer_init(uint32_t freq)
-{
-    arm_timer_state *s;
-    QEMUBH *bh;
-
-    s = (arm_timer_state *)g_malloc0(sizeof(arm_timer_state));
-    s->freq = freq;
-    s->control = TIMER_CTRL_IE;
-
-    bh = qemu_bh_new(arm_timer_tick, s);
-    s->timer = ptimer_init(bh);
-    vmstate_register(NULL, -1, &vmstate_arm_timer, s);
-    return s;
-}
-
-/* ARM PrimeCell SP804 dual timer module.
- * Docs at
- * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0271d/index.html
-*/
-
-typedef struct {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-    arm_timer_state *timer[2];
-    uint32_t freq0, freq1;
-    int level[2];
-    qemu_irq irq;
-} sp804_state;
-
-static const uint8_t sp804_ids[] = {
-    /* Timer ID */
-    0x04, 0x18, 0x14, 0,
-    /* PrimeCell ID */
-    0xd, 0xf0, 0x05, 0xb1
-};
-
-/* Merge the IRQs from the two component devices.  */
-static void sp804_set_irq(void *opaque, int irq, int level)
-{
-    sp804_state *s = (sp804_state *)opaque;
-
-    s->level[irq] = level;
-    qemu_set_irq(s->irq, s->level[0] || s->level[1]);
-}
-
-static uint64_t sp804_read(void *opaque, hwaddr offset,
-                           unsigned size)
-{
-    sp804_state *s = (sp804_state *)opaque;
-
-    if (offset < 0x20) {
-        return arm_timer_read(s->timer[0], offset);
-    }
-    if (offset < 0x40) {
-        return arm_timer_read(s->timer[1], offset - 0x20);
-    }
-
-    /* TimerPeriphID */
-    if (offset >= 0xfe0 && offset <= 0xffc) {
-        return sp804_ids[(offset - 0xfe0) >> 2];
-    }
-
-    switch (offset) {
-    /* Integration Test control registers, which we won't support */
-    case 0xf00: /* TimerITCR */
-    case 0xf04: /* TimerITOP (strictly write only but..) */
-        qemu_log_mask(LOG_UNIMP,
-                      "%s: integration test registers unimplemented\n",
-                      __func__);
-        return 0;
-    }
-
-    qemu_log_mask(LOG_GUEST_ERROR,
-                  "%s: Bad offset %x\n", __func__, (int)offset);
-    return 0;
-}
-
-static void sp804_write(void *opaque, hwaddr offset,
-                        uint64_t value, unsigned size)
-{
-    sp804_state *s = (sp804_state *)opaque;
-
-    if (offset < 0x20) {
-        arm_timer_write(s->timer[0], offset, value);
-        return;
-    }
-
-    if (offset < 0x40) {
-        arm_timer_write(s->timer[1], offset - 0x20, value);
-        return;
-    }
-
-    /* Technically we could be writing to the Test Registers, but not likely */
-    qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %x\n",
-                  __func__, (int)offset);
-}
-
-static const MemoryRegionOps sp804_ops = {
-    .read = sp804_read,
-    .write = sp804_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static const VMStateDescription vmstate_sp804 = {
-    .name = "sp804",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField[]) {
-        VMSTATE_INT32_ARRAY(level, sp804_state, 2),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static int sp804_init(SysBusDevice *dev)
-{
-    sp804_state *s = FROM_SYSBUS(sp804_state, dev);
-    qemu_irq *qi;
-
-    qi = qemu_allocate_irqs(sp804_set_irq, s, 2);
-    sysbus_init_irq(dev, &s->irq);
-    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);
-    sysbus_init_mmio(dev, &s->iomem);
-    vmstate_register(&dev->qdev, -1, &vmstate_sp804, s);
-    return 0;
-}
-
-/* Integrator/CP timer module.  */
-
-typedef struct {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-    arm_timer_state *timer[3];
-} icp_pit_state;
-
-static uint64_t icp_pit_read(void *opaque, hwaddr offset,
-                             unsigned size)
-{
-    icp_pit_state *s = (icp_pit_state *)opaque;
-    int n;
-
-    /* ??? Don't know the PrimeCell ID for this device.  */
-    n = offset >> 8;
-    if (n > 2) {
-        qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad timer %d\n", __func__, n);
-    }
-
-    return arm_timer_read(s->timer[n], offset & 0xff);
-}
-
-static void icp_pit_write(void *opaque, hwaddr offset,
-                          uint64_t value, unsigned size)
-{
-    icp_pit_state *s = (icp_pit_state *)opaque;
-    int n;
-
-    n = offset >> 8;
-    if (n > 2) {
-        qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad timer %d\n", __func__, n);
-    }
-
-    arm_timer_write(s->timer[n], offset & 0xff, value);
-}
-
-static const MemoryRegionOps icp_pit_ops = {
-    .read = icp_pit_read,
-    .write = icp_pit_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int icp_pit_init(SysBusDevice *dev)
-{
-    icp_pit_state *s = FROM_SYSBUS(icp_pit_state, dev);
-
-    /* Timer 0 runs at the system clock speed (40MHz).  */
-    s->timer[0] = arm_timer_init(40000000);
-    /* The other two timers run at 1MHz.  */
-    s->timer[1] = arm_timer_init(1000000);
-    s->timer[2] = arm_timer_init(1000000);
-
-    sysbus_init_irq(dev, &s->timer[0]->irq);
-    sysbus_init_irq(dev, &s->timer[1]->irq);
-    sysbus_init_irq(dev, &s->timer[2]->irq);
-
-    memory_region_init_io(&s->iomem, &icp_pit_ops, s, "icp_pit", 0x1000);
-    sysbus_init_mmio(dev, &s->iomem);
-    /* This device has no state to save/restore.  The component timers will
-       save themselves.  */
-    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 const 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 const 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_types(void)
-{
-    type_register_static(&icp_pit_info);
-    type_register_static(&sp804_info);
-}
-
-type_init(arm_timer_register_types)
diff --git a/hw/armv7m_nvic.c b/hw/armv7m_nvic.c
deleted file mode 100644 (file)
index d198cfd..0000000
+++ /dev/null
@@ -1,553 +0,0 @@
-/*
- * ARM Nested Vectored Interrupt Controller
- *
- * Copyright (c) 2006-2007 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the GPL.
- *
- * The ARMv7M System controller is fairly tightly tied in with the
- * NVIC.  Much of that is also implemented here.
- */
-
-#include "hw/sysbus.h"
-#include "qemu/timer.h"
-#include "hw/arm-misc.h"
-#include "exec/address-spaces.h"
-#include "hw/arm_gic_internal.h"
-
-typedef struct {
-    GICState gic;
-    struct {
-        uint32_t control;
-        uint32_t reload;
-        int64_t tick;
-        QEMUTimer *timer;
-    } systick;
-    MemoryRegion sysregmem;
-    MemoryRegion gic_iomem_alias;
-    MemoryRegion container;
-    uint32_t num_irq;
-} nvic_state;
-
-#define TYPE_NVIC "armv7m_nvic"
-/**
- * NVICClass:
- * @parent_reset: the parent class' reset handler.
- *
- * A model of the v7M NVIC and System Controller
- */
-typedef struct NVICClass {
-    /*< private >*/
-    ARMGICClass parent_class;
-    /*< public >*/
-    DeviceRealize parent_realize;
-    void (*parent_reset)(DeviceState *dev);
-} NVICClass;
-
-#define NVIC_CLASS(klass) \
-    OBJECT_CLASS_CHECK(NVICClass, (klass), TYPE_NVIC)
-#define NVIC_GET_CLASS(obj) \
-    OBJECT_GET_CLASS(NVICClass, (obj), TYPE_NVIC)
-#define NVIC(obj) \
-    OBJECT_CHECK(nvic_state, (obj), TYPE_NVIC)
-
-static const uint8_t nvic_id[] = {
-    0x00, 0xb0, 0x1b, 0x00, 0x0d, 0xe0, 0x05, 0xb1
-};
-
-/* qemu timers run at 1GHz.   We want something closer to 1MHz.  */
-#define SYSTICK_SCALE 1000ULL
-
-#define SYSTICK_ENABLE    (1 << 0)
-#define SYSTICK_TICKINT   (1 << 1)
-#define SYSTICK_CLKSOURCE (1 << 2)
-#define SYSTICK_COUNTFLAG (1 << 16)
-
-int system_clock_scale;
-
-/* Conversion factor from qemu timer to SysTick frequencies.  */
-static inline int64_t systick_scale(nvic_state *s)
-{
-    if (s->systick.control & SYSTICK_CLKSOURCE)
-        return system_clock_scale;
-    else
-        return 1000;
-}
-
-static void systick_reload(nvic_state *s, int reset)
-{
-    if (reset)
-        s->systick.tick = qemu_get_clock_ns(vm_clock);
-    s->systick.tick += (s->systick.reload + 1) * systick_scale(s);
-    qemu_mod_timer(s->systick.timer, s->systick.tick);
-}
-
-static void systick_timer_tick(void * opaque)
-{
-    nvic_state *s = (nvic_state *)opaque;
-    s->systick.control |= SYSTICK_COUNTFLAG;
-    if (s->systick.control & SYSTICK_TICKINT) {
-        /* Trigger the interrupt.  */
-        armv7m_nvic_set_pending(s, ARMV7M_EXCP_SYSTICK);
-    }
-    if (s->systick.reload == 0) {
-        s->systick.control &= ~SYSTICK_ENABLE;
-    } else {
-        systick_reload(s, 0);
-    }
-}
-
-static void systick_reset(nvic_state *s)
-{
-    s->systick.control = 0;
-    s->systick.reload = 0;
-    s->systick.tick = 0;
-    qemu_del_timer(s->systick.timer);
-}
-
-/* The external routines use the hardware vector numbering, ie. the first
-   IRQ is #16.  The internal GIC routines use #32 as the first IRQ.  */
-void armv7m_nvic_set_pending(void *opaque, int irq)
-{
-    nvic_state *s = (nvic_state *)opaque;
-    if (irq >= 16)
-        irq += 16;
-    gic_set_pending_private(&s->gic, 0, irq);
-}
-
-/* Make pending IRQ active.  */
-int armv7m_nvic_acknowledge_irq(void *opaque)
-{
-    nvic_state *s = (nvic_state *)opaque;
-    uint32_t irq;
-
-    irq = gic_acknowledge_irq(&s->gic, 0);
-    if (irq == 1023)
-        hw_error("Interrupt but no vector\n");
-    if (irq >= 32)
-        irq -= 16;
-    return irq;
-}
-
-void armv7m_nvic_complete_irq(void *opaque, int irq)
-{
-    nvic_state *s = (nvic_state *)opaque;
-    if (irq >= 16)
-        irq += 16;
-    gic_complete_irq(&s->gic, 0, irq);
-}
-
-static uint32_t nvic_readl(nvic_state *s, uint32_t offset)
-{
-    uint32_t val;
-    int irq;
-
-    switch (offset) {
-    case 4: /* Interrupt Control Type.  */
-        return (s->num_irq / 32) - 1;
-    case 0x10: /* SysTick Control and Status.  */
-        val = s->systick.control;
-        s->systick.control &= ~SYSTICK_COUNTFLAG;
-        return val;
-    case 0x14: /* SysTick Reload Value.  */
-        return s->systick.reload;
-    case 0x18: /* SysTick Current Value.  */
-        {
-            int64_t t;
-            if ((s->systick.control & SYSTICK_ENABLE) == 0)
-                return 0;
-            t = qemu_get_clock_ns(vm_clock);
-            if (t >= s->systick.tick)
-                return 0;
-            val = ((s->systick.tick - (t + 1)) / systick_scale(s)) + 1;
-            /* The interrupt in triggered when the timer reaches zero.
-               However the counter is not reloaded until the next clock
-               tick.  This is a hack to return zero during the first tick.  */
-            if (val > s->systick.reload)
-                val = 0;
-            return val;
-        }
-    case 0x1c: /* SysTick Calibration Value.  */
-        return 10000;
-    case 0xd00: /* CPUID Base.  */
-        return cpu_single_env->cp15.c0_cpuid;
-    case 0xd04: /* Interrypt Control State.  */
-        /* VECTACTIVE */
-        val = s->gic.running_irq[0];
-        if (val == 1023) {
-            val = 0;
-        } else if (val >= 32) {
-            val -= 16;
-        }
-        /* RETTOBASE */
-        if (s->gic.running_irq[0] == 1023
-                || s->gic.last_active[s->gic.running_irq[0]][0] == 1023) {
-            val |= (1 << 11);
-        }
-        /* VECTPENDING */
-        if (s->gic.current_pending[0] != 1023)
-            val |= (s->gic.current_pending[0] << 12);
-        /* ISRPENDING */
-        for (irq = 32; irq < s->num_irq; irq++) {
-            if (s->gic.irq_state[irq].pending) {
-                val |= (1 << 22);
-                break;
-            }
-        }
-        /* PENDSTSET */
-        if (s->gic.irq_state[ARMV7M_EXCP_SYSTICK].pending)
-            val |= (1 << 26);
-        /* PENDSVSET */
-        if (s->gic.irq_state[ARMV7M_EXCP_PENDSV].pending)
-            val |= (1 << 28);
-        /* NMIPENDSET */
-        if (s->gic.irq_state[ARMV7M_EXCP_NMI].pending)
-            val |= (1 << 31);
-        return val;
-    case 0xd08: /* Vector Table Offset.  */
-        return cpu_single_env->v7m.vecbase;
-    case 0xd0c: /* Application Interrupt/Reset Control.  */
-        return 0xfa05000;
-    case 0xd10: /* System Control.  */
-        /* TODO: Implement SLEEPONEXIT.  */
-        return 0;
-    case 0xd14: /* Configuration Control.  */
-        /* TODO: Implement Configuration Control bits.  */
-        return 0;
-    case 0xd24: /* System Handler Status.  */
-        val = 0;
-        if (s->gic.irq_state[ARMV7M_EXCP_MEM].active) val |= (1 << 0);
-        if (s->gic.irq_state[ARMV7M_EXCP_BUS].active) val |= (1 << 1);
-        if (s->gic.irq_state[ARMV7M_EXCP_USAGE].active) val |= (1 << 3);
-        if (s->gic.irq_state[ARMV7M_EXCP_SVC].active) val |= (1 << 7);
-        if (s->gic.irq_state[ARMV7M_EXCP_DEBUG].active) val |= (1 << 8);
-        if (s->gic.irq_state[ARMV7M_EXCP_PENDSV].active) val |= (1 << 10);
-        if (s->gic.irq_state[ARMV7M_EXCP_SYSTICK].active) val |= (1 << 11);
-        if (s->gic.irq_state[ARMV7M_EXCP_USAGE].pending) val |= (1 << 12);
-        if (s->gic.irq_state[ARMV7M_EXCP_MEM].pending) val |= (1 << 13);
-        if (s->gic.irq_state[ARMV7M_EXCP_BUS].pending) val |= (1 << 14);
-        if (s->gic.irq_state[ARMV7M_EXCP_SVC].pending) val |= (1 << 15);
-        if (s->gic.irq_state[ARMV7M_EXCP_MEM].enabled) val |= (1 << 16);
-        if (s->gic.irq_state[ARMV7M_EXCP_BUS].enabled) val |= (1 << 17);
-        if (s->gic.irq_state[ARMV7M_EXCP_USAGE].enabled) val |= (1 << 18);
-        return val;
-    case 0xd28: /* Configurable Fault Status.  */
-        /* TODO: Implement Fault Status.  */
-        qemu_log_mask(LOG_UNIMP, "Configurable Fault Status unimplemented\n");
-        return 0;
-    case 0xd2c: /* Hard Fault Status.  */
-    case 0xd30: /* Debug Fault Status.  */
-    case 0xd34: /* Mem Manage Address.  */
-    case 0xd38: /* Bus Fault Address.  */
-    case 0xd3c: /* Aux Fault Status.  */
-        /* TODO: Implement fault status registers.  */
-        qemu_log_mask(LOG_UNIMP, "Fault status registers unimplemented\n");
-        return 0;
-    case 0xd40: /* PFR0.  */
-        return 0x00000030;
-    case 0xd44: /* PRF1.  */
-        return 0x00000200;
-    case 0xd48: /* DFR0.  */
-        return 0x00100000;
-    case 0xd4c: /* AFR0.  */
-        return 0x00000000;
-    case 0xd50: /* MMFR0.  */
-        return 0x00000030;
-    case 0xd54: /* MMFR1.  */
-        return 0x00000000;
-    case 0xd58: /* MMFR2.  */
-        return 0x00000000;
-    case 0xd5c: /* MMFR3.  */
-        return 0x00000000;
-    case 0xd60: /* ISAR0.  */
-        return 0x01141110;
-    case 0xd64: /* ISAR1.  */
-        return 0x02111000;
-    case 0xd68: /* ISAR2.  */
-        return 0x21112231;
-    case 0xd6c: /* ISAR3.  */
-        return 0x01111110;
-    case 0xd70: /* ISAR4.  */
-        return 0x01310102;
-    /* TODO: Implement debug registers.  */
-    default:
-        qemu_log_mask(LOG_GUEST_ERROR, "NVIC: Bad read offset 0x%x\n", offset);
-        return 0;
-    }
-}
-
-static void nvic_writel(nvic_state *s, uint32_t offset, uint32_t value)
-{
-    uint32_t oldval;
-    switch (offset) {
-    case 0x10: /* SysTick Control and Status.  */
-        oldval = s->systick.control;
-        s->systick.control &= 0xfffffff8;
-        s->systick.control |= value & 7;
-        if ((oldval ^ value) & SYSTICK_ENABLE) {
-            int64_t now = qemu_get_clock_ns(vm_clock);
-            if (value & SYSTICK_ENABLE) {
-                if (s->systick.tick) {
-                    s->systick.tick += now;
-                    qemu_mod_timer(s->systick.timer, s->systick.tick);
-                } else {
-                    systick_reload(s, 1);
-                }
-            } else {
-                qemu_del_timer(s->systick.timer);
-                s->systick.tick -= now;
-                if (s->systick.tick < 0)
-                  s->systick.tick = 0;
-            }
-        } else if ((oldval ^ value) & SYSTICK_CLKSOURCE) {
-            /* This is a hack. Force the timer to be reloaded
-               when the reference clock is changed.  */
-            systick_reload(s, 1);
-        }
-        break;
-    case 0x14: /* SysTick Reload Value.  */
-        s->systick.reload = value;
-        break;
-    case 0x18: /* SysTick Current Value.  Writes reload the timer.  */
-        systick_reload(s, 1);
-        s->systick.control &= ~SYSTICK_COUNTFLAG;
-        break;
-    case 0xd04: /* Interrupt Control State.  */
-        if (value & (1 << 31)) {
-            armv7m_nvic_set_pending(s, ARMV7M_EXCP_NMI);
-        }
-        if (value & (1 << 28)) {
-            armv7m_nvic_set_pending(s, ARMV7M_EXCP_PENDSV);
-        } else if (value & (1 << 27)) {
-            s->gic.irq_state[ARMV7M_EXCP_PENDSV].pending = 0;
-            gic_update(&s->gic);
-        }
-        if (value & (1 << 26)) {
-            armv7m_nvic_set_pending(s, ARMV7M_EXCP_SYSTICK);
-        } else if (value & (1 << 25)) {
-            s->gic.irq_state[ARMV7M_EXCP_SYSTICK].pending = 0;
-            gic_update(&s->gic);
-        }
-        break;
-    case 0xd08: /* Vector Table Offset.  */
-        cpu_single_env->v7m.vecbase = value & 0xffffff80;
-        break;
-    case 0xd0c: /* Application Interrupt/Reset Control.  */
-        if ((value >> 16) == 0x05fa) {
-            if (value & 2) {
-                qemu_log_mask(LOG_UNIMP, "VECTCLRACTIVE unimplemented\n");
-            }
-            if (value & 5) {
-                qemu_log_mask(LOG_UNIMP, "AIRCR system reset unimplemented\n");
-            }
-        }
-        break;
-    case 0xd10: /* System Control.  */
-    case 0xd14: /* Configuration Control.  */
-        /* TODO: Implement control registers.  */
-        qemu_log_mask(LOG_UNIMP, "NVIC: SCR and CCR unimplemented\n");
-        break;
-    case 0xd24: /* System Handler Control.  */
-        /* TODO: Real hardware allows you to set/clear the active bits
-           under some circumstances.  We don't implement this.  */
-        s->gic.irq_state[ARMV7M_EXCP_MEM].enabled = (value & (1 << 16)) != 0;
-        s->gic.irq_state[ARMV7M_EXCP_BUS].enabled = (value & (1 << 17)) != 0;
-        s->gic.irq_state[ARMV7M_EXCP_USAGE].enabled = (value & (1 << 18)) != 0;
-        break;
-    case 0xd28: /* Configurable Fault Status.  */
-    case 0xd2c: /* Hard Fault Status.  */
-    case 0xd30: /* Debug Fault Status.  */
-    case 0xd34: /* Mem Manage Address.  */
-    case 0xd38: /* Bus Fault Address.  */
-    case 0xd3c: /* Aux Fault Status.  */
-        qemu_log_mask(LOG_UNIMP,
-                      "NVIC: fault status registers unimplemented\n");
-        break;
-    case 0xf00: /* Software Triggered Interrupt Register */
-        if ((value & 0x1ff) < s->num_irq) {
-            gic_set_pending_private(&s->gic, 0, value & 0x1ff);
-        }
-        break;
-    default:
-        qemu_log_mask(LOG_GUEST_ERROR,
-                      "NVIC: Bad write offset 0x%x\n", offset);
-    }
-}
-
-static uint64_t nvic_sysreg_read(void *opaque, hwaddr addr,
-                                 unsigned size)
-{
-    nvic_state *s = (nvic_state *)opaque;
-    uint32_t offset = addr;
-    int i;
-    uint32_t val;
-
-    switch (offset) {
-    case 0xd18 ... 0xd23: /* System Handler Priority.  */
-        val = 0;
-        for (i = 0; i < size; i++) {
-            val |= s->gic.priority1[(offset - 0xd14) + i][0] << (i * 8);
-        }
-        return val;
-    case 0xfe0 ... 0xfff: /* ID.  */
-        if (offset & 3) {
-            return 0;
-        }
-        return nvic_id[(offset - 0xfe0) >> 2];
-    }
-    if (size == 4) {
-        return nvic_readl(s, offset);
-    }
-    qemu_log_mask(LOG_GUEST_ERROR,
-                  "NVIC: Bad read of size %d at offset 0x%x\n", size, offset);
-    return 0;
-}
-
-static void nvic_sysreg_write(void *opaque, hwaddr addr,
-                              uint64_t value, unsigned size)
-{
-    nvic_state *s = (nvic_state *)opaque;
-    uint32_t offset = addr;
-    int i;
-
-    switch (offset) {
-    case 0xd18 ... 0xd23: /* System Handler Priority.  */
-        for (i = 0; i < size; i++) {
-            s->gic.priority1[(offset - 0xd14) + i][0] =
-                (value >> (i * 8)) & 0xff;
-        }
-        gic_update(&s->gic);
-        return;
-    }
-    if (size == 4) {
-        nvic_writel(s, offset, value);
-        return;
-    }
-    qemu_log_mask(LOG_GUEST_ERROR,
-                  "NVIC: Bad write of size %d at offset 0x%x\n", size, offset);
-}
-
-static const MemoryRegionOps nvic_sysreg_ops = {
-    .read = nvic_sysreg_read,
-    .write = nvic_sysreg_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static const VMStateDescription vmstate_nvic = {
-    .name = "armv7m_nvic",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField[]) {
-        VMSTATE_UINT32(systick.control, nvic_state),
-        VMSTATE_UINT32(systick.reload, nvic_state),
-        VMSTATE_INT64(systick.tick, nvic_state),
-        VMSTATE_TIMER(systick.timer, nvic_state),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void armv7m_nvic_reset(DeviceState *dev)
-{
-    nvic_state *s = NVIC(dev);
-    NVICClass *nc = NVIC_GET_CLASS(s);
-    nc->parent_reset(dev);
-    /* Common GIC reset resets to disabled; the NVIC doesn't have
-     * per-CPU interfaces so mark our non-existent CPU interface
-     * as enabled by default, and with a priority mask which allows
-     * all interrupts through.
-     */
-    s->gic.cpu_enabled[0] = 1;
-    s->gic.priority_mask[0] = 0x100;
-    /* The NVIC as a whole is always enabled. */
-    s->gic.enabled = 1;
-    systick_reset(s);
-}
-
-static void armv7m_nvic_realize(DeviceState *dev, Error **errp)
-{
-    nvic_state *s = NVIC(dev);
-    NVICClass *nc = NVIC_GET_CLASS(s);
-
-    /* The NVIC always has only one CPU */
-    s->gic.num_cpu = 1;
-    /* Tell the common code we're an NVIC */
-    s->gic.revision = 0xffffffff;
-    s->num_irq = s->gic.num_irq;
-    nc->parent_realize(dev, errp);
-    if (error_is_set(errp)) {
-        return;
-    }
-    gic_init_irqs_and_distributor(&s->gic, s->num_irq);
-    /* The NVIC and system controller register area looks like this:
-     *  0..0xff : system control registers, including systick
-     *  0x100..0xcff : GIC-like registers
-     *  0xd00..0xfff : system control registers
-     * We use overlaying to put the GIC like registers
-     * over the top of the system control register region.
-     */
-    memory_region_init(&s->container, "nvic", 0x1000);
-    /* The system register region goes at the bottom of the priority
-     * stack as it covers the whole page.
-     */
-    memory_region_init_io(&s->sysregmem, &nvic_sysreg_ops, s,
-                          "nvic_sysregs", 0x1000);
-    memory_region_add_subregion(&s->container, 0, &s->sysregmem);
-    /* Alias the GIC region so we can get only the section of it
-     * we need, and layer it on top of the system register region.
-     */
-    memory_region_init_alias(&s->gic_iomem_alias, "nvic-gic", &s->gic.iomem,
-                             0x100, 0xc00);
-    memory_region_add_subregion_overlap(&s->container, 0x100,
-                                        &s->gic_iomem_alias, 1);
-    /* Map the whole thing into system memory at the location required
-     * by the v7M architecture.
-     */
-    memory_region_add_subregion(get_system_memory(), 0xe000e000, &s->container);
-    s->systick.timer = qemu_new_timer_ns(vm_clock, systick_timer_tick, s);
-}
-
-static void armv7m_nvic_instance_init(Object *obj)
-{
-    /* We have a different default value for the num-irq property
-     * than our superclass. This function runs after qdev init
-     * has set the defaults from the Property array and before
-     * any user-specified property setting, so just modify the
-     * value in the GICState struct.
-     */
-    GICState *s = ARM_GIC_COMMON(obj);
-    /* 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 the num-irq property appropriately.
-     */
-    s->num_irq = 64;
-}
-
-static void armv7m_nvic_class_init(ObjectClass *klass, void *data)
-{
-    NVICClass *nc = NVIC_CLASS(klass);
-    DeviceClass *dc = DEVICE_CLASS(klass);
-
-    nc->parent_reset = dc->reset;
-    nc->parent_realize = dc->realize;
-    dc->vmsd  = &vmstate_nvic;
-    dc->reset = armv7m_nvic_reset;
-    dc->realize = armv7m_nvic_realize;
-}
-
-static const TypeInfo armv7m_nvic_info = {
-    .name          = TYPE_NVIC,
-    .parent        = TYPE_ARM_GIC_COMMON,
-    .instance_init = armv7m_nvic_instance_init,
-    .instance_size = sizeof(nvic_state),
-    .class_init    = armv7m_nvic_class_init,
-    .class_size    = sizeof(NVICClass),
-};
-
-static void armv7m_nvic_register_types(void)
-{
-    type_register_static(&armv7m_nvic_info);
-}
-
-type_init(armv7m_nvic_register_types)
diff --git a/hw/audio/Makefile.objs b/hw/audio/Makefile.objs
new file mode 100644 (file)
index 0000000..2375102
--- /dev/null
@@ -0,0 +1,20 @@
+# Sound
+sound-obj-y =
+sound-obj-$(CONFIG_SB16) += sb16.o
+sound-obj-$(CONFIG_ES1370) += es1370.o
+sound-obj-$(CONFIG_AC97) += ac97.o
+sound-obj-$(CONFIG_ADLIB) += fmopl.o adlib.o
+sound-obj-$(CONFIG_GUS) += gus.o gusemu_hal.o gusemu_mixer.o
+sound-obj-$(CONFIG_CS4231A) += cs4231a.o
+sound-obj-$(CONFIG_HDA) += intel-hda.o hda-codec.o
+
+common-obj-$(CONFIG_SOUND) += $(sound-obj-y)
+common-obj-$(CONFIG_PCSPK) += pcspk.o
+common-obj-$(CONFIG_WM8750) += wm8750.o
+common-obj-$(CONFIG_PL041) += pl041.o lm4549.o
+
+common-obj-$(CONFIG_CS4231) += cs4231.o
+common-obj-$(CONFIG_MARVELL_88W8618) += marvell_88w8618.o
+common-obj-$(CONFIG_MILKYMIST) += milkymist-ac97.o
+
+$(obj)/adlib.o $(obj)/fmopl.o: QEMU_CFLAGS += -DBUILD_Y8950=0
diff --git a/hw/audio/ac97.c b/hw/audio/ac97.c
new file mode 100644 (file)
index 0000000..ab68ec6
--- /dev/null
@@ -0,0 +1,1438 @@
+/*
+ * Copyright (C) 2006 InnoTek Systemberatung GmbH
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file 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,
+ * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
+ * distribution. VirtualBox OSE is distributed in the hope that it will
+ * be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * 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/hw.h"
+#include "hw/audio/audio.h"
+#include "audio/audio.h"
+#include "hw/pci/pci.h"
+#include "sysemu/dma.h"
+
+enum {
+    AC97_Reset                     = 0x00,
+    AC97_Master_Volume_Mute        = 0x02,
+    AC97_Headphone_Volume_Mute     = 0x04,
+    AC97_Master_Volume_Mono_Mute   = 0x06,
+    AC97_Master_Tone_RL            = 0x08,
+    AC97_PC_BEEP_Volume_Mute       = 0x0A,
+    AC97_Phone_Volume_Mute         = 0x0C,
+    AC97_Mic_Volume_Mute           = 0x0E,
+    AC97_Line_In_Volume_Mute       = 0x10,
+    AC97_CD_Volume_Mute            = 0x12,
+    AC97_Video_Volume_Mute         = 0x14,
+    AC97_Aux_Volume_Mute           = 0x16,
+    AC97_PCM_Out_Volume_Mute       = 0x18,
+    AC97_Record_Select             = 0x1A,
+    AC97_Record_Gain_Mute          = 0x1C,
+    AC97_Record_Gain_Mic_Mute      = 0x1E,
+    AC97_General_Purpose           = 0x20,
+    AC97_3D_Control                = 0x22,
+    AC97_AC_97_RESERVED            = 0x24,
+    AC97_Powerdown_Ctrl_Stat       = 0x26,
+    AC97_Extended_Audio_ID         = 0x28,
+    AC97_Extended_Audio_Ctrl_Stat  = 0x2A,
+    AC97_PCM_Front_DAC_Rate        = 0x2C,
+    AC97_PCM_Surround_DAC_Rate     = 0x2E,
+    AC97_PCM_LFE_DAC_Rate          = 0x30,
+    AC97_PCM_LR_ADC_Rate           = 0x32,
+    AC97_MIC_ADC_Rate              = 0x34,
+    AC97_6Ch_Vol_C_LFE_Mute        = 0x36,
+    AC97_6Ch_Vol_L_R_Surround_Mute = 0x38,
+    AC97_Vendor_Reserved           = 0x58,
+    AC97_Sigmatel_Analog           = 0x6c, /* We emulate a Sigmatel codec */
+    AC97_Sigmatel_Dac2Invert       = 0x6e, /* We emulate a Sigmatel codec */
+    AC97_Vendor_ID1                = 0x7c,
+    AC97_Vendor_ID2                = 0x7e
+};
+
+#define SOFT_VOLUME
+#define SR_FIFOE 16             /* rwc */
+#define SR_BCIS  8              /* rwc */
+#define SR_LVBCI 4              /* rwc */
+#define SR_CELV  2              /* ro */
+#define SR_DCH   1              /* ro */
+#define SR_VALID_MASK ((1 << 5) - 1)
+#define SR_WCLEAR_MASK (SR_FIFOE | SR_BCIS | SR_LVBCI)
+#define SR_RO_MASK (SR_DCH | SR_CELV)
+#define SR_INT_MASK (SR_FIFOE | SR_BCIS | SR_LVBCI)
+
+#define CR_IOCE  16             /* rw */
+#define CR_FEIE  8              /* rw */
+#define CR_LVBIE 4              /* rw */
+#define CR_RR    2              /* rw */
+#define CR_RPBM  1              /* rw */
+#define CR_VALID_MASK ((1 << 5) - 1)
+#define CR_DONT_CLEAR_MASK (CR_IOCE | CR_FEIE | CR_LVBIE)
+
+#define GC_WR    4              /* rw */
+#define GC_CR    2              /* rw */
+#define GC_VALID_MASK ((1 << 6) - 1)
+
+#define GS_MD3   (1<<17)        /* rw */
+#define GS_AD3   (1<<16)        /* rw */
+#define GS_RCS   (1<<15)        /* rwc */
+#define GS_B3S12 (1<<14)        /* ro */
+#define GS_B2S12 (1<<13)        /* ro */
+#define GS_B1S12 (1<<12)        /* ro */
+#define GS_S1R1  (1<<11)        /* rwc */
+#define GS_S0R1  (1<<10)        /* rwc */
+#define GS_S1CR  (1<<9)         /* ro */
+#define GS_S0CR  (1<<8)         /* ro */
+#define GS_MINT  (1<<7)         /* ro */
+#define GS_POINT (1<<6)         /* ro */
+#define GS_PIINT (1<<5)         /* ro */
+#define GS_RSRVD ((1<<4)|(1<<3))
+#define GS_MOINT (1<<2)         /* ro */
+#define GS_MIINT (1<<1)         /* ro */
+#define GS_GSCI  1              /* rwc */
+#define GS_RO_MASK (GS_B3S12|                   \
+                    GS_B2S12|                   \
+                    GS_B1S12|                   \
+                    GS_S1CR|                    \
+                    GS_S0CR|                    \
+                    GS_MINT|                    \
+                    GS_POINT|                   \
+                    GS_PIINT|                   \
+                    GS_RSRVD|                   \
+                    GS_MOINT|                   \
+                    GS_MIINT)
+#define GS_VALID_MASK ((1 << 18) - 1)
+#define GS_WCLEAR_MASK (GS_RCS|GS_S1R1|GS_S0R1|GS_GSCI)
+
+#define BD_IOC (1<<31)
+#define BD_BUP (1<<30)
+
+#define EACS_VRA 1
+#define EACS_VRM 8
+
+#define MUTE_SHIFT 15
+
+#define REC_MASK 7
+enum {
+    REC_MIC = 0,
+    REC_CD,
+    REC_VIDEO,
+    REC_AUX,
+    REC_LINE_IN,
+    REC_STEREO_MIX,
+    REC_MONO_MIX,
+    REC_PHONE
+};
+
+typedef struct BD {
+    uint32_t addr;
+    uint32_t ctl_len;
+} BD;
+
+typedef struct AC97BusMasterRegs {
+    uint32_t bdbar;             /* rw 0 */
+    uint8_t civ;                /* ro 0 */
+    uint8_t lvi;                /* rw 0 */
+    uint16_t sr;                /* rw 1 */
+    uint16_t picb;              /* ro 0 */
+    uint8_t piv;                /* ro 0 */
+    uint8_t cr;                 /* rw 0 */
+    unsigned int bd_valid;
+    BD bd;
+} AC97BusMasterRegs;
+
+typedef struct AC97LinkState {
+    PCIDevice dev;
+    QEMUSoundCard card;
+    uint32_t use_broken_id;
+    uint32_t glob_cnt;
+    uint32_t glob_sta;
+    uint32_t cas;
+    uint32_t last_samp;
+    AC97BusMasterRegs bm_regs[3];
+    uint8_t mixer_data[256];
+    SWVoiceIn *voice_pi;
+    SWVoiceOut *voice_po;
+    SWVoiceIn *voice_mc;
+    int invalid_freq[3];
+    uint8_t silence[128];
+    int bup_flag;
+    MemoryRegion io_nam;
+    MemoryRegion io_nabm;
+} AC97LinkState;
+
+enum {
+    BUP_SET = 1,
+    BUP_LAST = 2
+};
+
+#ifdef DEBUG_AC97
+#define dolog(...) AUD_log ("ac97", __VA_ARGS__)
+#else
+#define dolog(...)
+#endif
+
+#define MKREGS(prefix, start)                   \
+enum {                                          \
+    prefix ## _BDBAR = start,                   \
+    prefix ## _CIV = start + 4,                 \
+    prefix ## _LVI = start + 5,                 \
+    prefix ## _SR = start + 6,                  \
+    prefix ## _PICB = start + 8,                \
+    prefix ## _PIV = start + 10,                \
+    prefix ## _CR = start + 11                  \
+}
+
+enum {
+    PI_INDEX = 0,
+    PO_INDEX,
+    MC_INDEX,
+    LAST_INDEX
+};
+
+MKREGS (PI, PI_INDEX * 16);
+MKREGS (PO, PO_INDEX * 16);
+MKREGS (MC, MC_INDEX * 16);
+
+enum {
+    GLOB_CNT = 0x2c,
+    GLOB_STA = 0x30,
+    CAS      = 0x34
+};
+
+#define GET_BM(index) (((index) >> 4) & 3)
+
+static void po_callback (void *opaque, int free);
+static void pi_callback (void *opaque, int avail);
+static void mc_callback (void *opaque, int avail);
+
+static void warm_reset (AC97LinkState *s)
+{
+    (void) s;
+}
+
+static void cold_reset (AC97LinkState * s)
+{
+    (void) s;
+}
+
+static void fetch_bd (AC97LinkState *s, AC97BusMasterRegs *r)
+{
+    uint8_t b[8];
+
+    pci_dma_read (&s->dev, r->bdbar + r->civ * 8, b, 8);
+    r->bd_valid = 1;
+    r->bd.addr = le32_to_cpu (*(uint32_t *) &b[0]) & ~3;
+    r->bd.ctl_len = le32_to_cpu (*(uint32_t *) &b[4]);
+    r->picb = r->bd.ctl_len & 0xffff;
+    dolog ("bd %2d addr=%#x ctl=%#06x len=%#x(%d bytes)\n",
+           r->civ, r->bd.addr, r->bd.ctl_len >> 16,
+           r->bd.ctl_len & 0xffff,
+           (r->bd.ctl_len & 0xffff) << 1);
+}
+
+static void update_sr (AC97LinkState *s, AC97BusMasterRegs *r, uint32_t new_sr)
+{
+    int event = 0;
+    int level = 0;
+    uint32_t new_mask = new_sr & SR_INT_MASK;
+    uint32_t old_mask = r->sr & SR_INT_MASK;
+    uint32_t masks[] = {GS_PIINT, GS_POINT, GS_MINT};
+
+    if (new_mask ^ old_mask) {
+        /** @todo is IRQ deasserted when only one of status bits is cleared? */
+        if (!new_mask) {
+            event = 1;
+            level = 0;
+        }
+        else {
+            if ((new_mask & SR_LVBCI) && (r->cr & CR_LVBIE)) {
+                event = 1;
+                level = 1;
+            }
+            if ((new_mask & SR_BCIS) && (r->cr & CR_IOCE)) {
+                event = 1;
+                level = 1;
+            }
+        }
+    }
+
+    r->sr = new_sr;
+
+    dolog ("IOC%d LVB%d sr=%#x event=%d level=%d\n",
+           r->sr & SR_BCIS, r->sr & SR_LVBCI,
+           r->sr,
+           event, level);
+
+    if (!event)
+        return;
+
+    if (level) {
+        s->glob_sta |= masks[r - s->bm_regs];
+        dolog ("set irq level=1\n");
+        qemu_set_irq (s->dev.irq[0], 1);
+    }
+    else {
+        s->glob_sta &= ~masks[r - s->bm_regs];
+        dolog ("set irq level=0\n");
+        qemu_set_irq (s->dev.irq[0], 0);
+    }
+}
+
+static void voice_set_active (AC97LinkState *s, int bm_index, int on)
+{
+    switch (bm_index) {
+    case PI_INDEX:
+        AUD_set_active_in (s->voice_pi, on);
+        break;
+
+    case PO_INDEX:
+        AUD_set_active_out (s->voice_po, on);
+        break;
+
+    case MC_INDEX:
+        AUD_set_active_in (s->voice_mc, on);
+        break;
+
+    default:
+        AUD_log ("ac97", "invalid bm_index(%d) in voice_set_active", bm_index);
+        break;
+    }
+}
+
+static void reset_bm_regs (AC97LinkState *s, AC97BusMasterRegs *r)
+{
+    dolog ("reset_bm_regs\n");
+    r->bdbar = 0;
+    r->civ = 0;
+    r->lvi = 0;
+    /** todo do we need to do that? */
+    update_sr (s, r, SR_DCH);
+    r->picb = 0;
+    r->piv = 0;
+    r->cr = r->cr & CR_DONT_CLEAR_MASK;
+    r->bd_valid = 0;
+
+    voice_set_active (s, r - s->bm_regs, 0);
+    memset (s->silence, 0, sizeof (s->silence));
+}
+
+static void mixer_store (AC97LinkState *s, uint32_t i, uint16_t v)
+{
+    if (i + 2 > sizeof (s->mixer_data)) {
+        dolog ("mixer_store: index %d out of bounds %zd\n",
+               i, sizeof (s->mixer_data));
+        return;
+    }
+
+    s->mixer_data[i + 0] = v & 0xff;
+    s->mixer_data[i + 1] = v >> 8;
+}
+
+static uint16_t mixer_load (AC97LinkState *s, uint32_t i)
+{
+    uint16_t val = 0xffff;
+
+    if (i + 2 > sizeof (s->mixer_data)) {
+        dolog ("mixer_load: index %d out of bounds %zd\n",
+               i, sizeof (s->mixer_data));
+    }
+    else {
+        val = s->mixer_data[i + 0] | (s->mixer_data[i + 1] << 8);
+    }
+
+    return val;
+}
+
+static void open_voice (AC97LinkState *s, int index, int freq)
+{
+    struct audsettings as;
+
+    as.freq = freq;
+    as.nchannels = 2;
+    as.fmt = AUD_FMT_S16;
+    as.endianness = 0;
+
+    if (freq > 0) {
+        s->invalid_freq[index] = 0;
+        switch (index) {
+        case PI_INDEX:
+            s->voice_pi = AUD_open_in (
+                &s->card,
+                s->voice_pi,
+                "ac97.pi",
+                s,
+                pi_callback,
+                &as
+                );
+            break;
+
+        case PO_INDEX:
+            s->voice_po = AUD_open_out (
+                &s->card,
+                s->voice_po,
+                "ac97.po",
+                s,
+                po_callback,
+                &as
+                );
+            break;
+
+        case MC_INDEX:
+            s->voice_mc = AUD_open_in (
+                &s->card,
+                s->voice_mc,
+                "ac97.mc",
+                s,
+                mc_callback,
+                &as
+                );
+            break;
+        }
+    }
+    else {
+        s->invalid_freq[index] = freq;
+        switch (index) {
+        case PI_INDEX:
+            AUD_close_in (&s->card, s->voice_pi);
+            s->voice_pi = NULL;
+            break;
+
+        case PO_INDEX:
+            AUD_close_out (&s->card, s->voice_po);
+            s->voice_po = NULL;
+            break;
+
+        case MC_INDEX:
+            AUD_close_in (&s->card, s->voice_mc);
+            s->voice_mc = NULL;
+            break;
+        }
+    }
+}
+
+static void reset_voices (AC97LinkState *s, uint8_t active[LAST_INDEX])
+{
+    uint16_t freq;
+
+    freq = mixer_load (s, AC97_PCM_LR_ADC_Rate);
+    open_voice (s, PI_INDEX, freq);
+    AUD_set_active_in (s->voice_pi, active[PI_INDEX]);
+
+    freq = mixer_load (s, AC97_PCM_Front_DAC_Rate);
+    open_voice (s, PO_INDEX, freq);
+    AUD_set_active_out (s->voice_po, active[PO_INDEX]);
+
+    freq = mixer_load (s, AC97_MIC_ADC_Rate);
+    open_voice (s, MC_INDEX, freq);
+    AUD_set_active_in (s->voice_mc, active[MC_INDEX]);
+}
+
+static void get_volume (uint16_t vol, uint16_t mask, int inverse,
+                        int *mute, uint8_t *lvol, uint8_t *rvol)
+{
+    *mute = (vol >> MUTE_SHIFT) & 1;
+    *rvol = (255 * (vol & mask)) / mask;
+    *lvol = (255 * ((vol >> 8) & mask)) / mask;
+
+    if (inverse) {
+        *rvol = 255 - *rvol;
+        *lvol = 255 - *lvol;
+    }
+}
+
+static void update_combined_volume_out (AC97LinkState *s)
+{
+    uint8_t lvol, rvol, plvol, prvol;
+    int mute, pmute;
+
+    get_volume (mixer_load (s, AC97_Master_Volume_Mute), 0x3f, 1,
+                &mute, &lvol, &rvol);
+    get_volume (mixer_load (s, AC97_PCM_Out_Volume_Mute), 0x1f, 1,
+                &pmute, &plvol, &prvol);
+
+    mute = mute | pmute;
+    lvol = (lvol * plvol) / 255;
+    rvol = (rvol * prvol) / 255;
+
+    AUD_set_volume_out (s->voice_po, mute, lvol, rvol);
+}
+
+static void update_volume_in (AC97LinkState *s)
+{
+    uint8_t lvol, rvol;
+    int mute;
+
+    get_volume (mixer_load (s, AC97_Record_Gain_Mute), 0x0f, 0,
+                &mute, &lvol, &rvol);
+
+    AUD_set_volume_in (s->voice_pi, mute, lvol, rvol);
+}
+
+static void set_volume (AC97LinkState *s, int index, uint32_t val)
+{
+    switch (index) {
+    case AC97_Master_Volume_Mute:
+        val &= 0xbf3f;
+        mixer_store (s, index, val);
+        update_combined_volume_out (s);
+        break;
+    case AC97_PCM_Out_Volume_Mute:
+        val &= 0x9f1f;
+        mixer_store (s, index, val);
+        update_combined_volume_out (s);
+        break;
+    case AC97_Record_Gain_Mute:
+        val &= 0x8f0f;
+        mixer_store (s, index, val);
+        update_volume_in (s);
+        break;
+    }
+}
+
+static void record_select (AC97LinkState *s, uint32_t val)
+{
+    uint8_t rs = val & REC_MASK;
+    uint8_t ls = (val >> 8) & REC_MASK;
+    mixer_store (s, AC97_Record_Select, rs | (ls << 8));
+}
+
+static void mixer_reset (AC97LinkState *s)
+{
+    uint8_t active[LAST_INDEX];
+
+    dolog ("mixer_reset\n");
+    memset (s->mixer_data, 0, sizeof (s->mixer_data));
+    memset (active, 0, sizeof (active));
+    mixer_store (s, AC97_Reset                   , 0x0000); /* 6940 */
+    mixer_store (s, AC97_Headphone_Volume_Mute   , 0x0000);
+    mixer_store (s, AC97_Master_Volume_Mono_Mute , 0x0000);
+    mixer_store (s, AC97_Master_Tone_RL,           0x0000);
+    mixer_store (s, AC97_PC_BEEP_Volume_Mute     , 0x0000);
+    mixer_store (s, AC97_Phone_Volume_Mute       , 0x0000);
+    mixer_store (s, AC97_Mic_Volume_Mute         , 0x0000);
+    mixer_store (s, AC97_Line_In_Volume_Mute     , 0x0000);
+    mixer_store (s, AC97_CD_Volume_Mute          , 0x0000);
+    mixer_store (s, AC97_Video_Volume_Mute       , 0x0000);
+    mixer_store (s, AC97_Aux_Volume_Mute         , 0x0000);
+    mixer_store (s, AC97_Record_Gain_Mic_Mute    , 0x0000);
+    mixer_store (s, AC97_General_Purpose         , 0x0000);
+    mixer_store (s, AC97_3D_Control              , 0x0000);
+    mixer_store (s, AC97_Powerdown_Ctrl_Stat     , 0x000f);
+
+    /*
+     * Sigmatel 9700 (STAC9700)
+     */
+    mixer_store (s, AC97_Vendor_ID1              , 0x8384);
+    mixer_store (s, AC97_Vendor_ID2              , 0x7600); /* 7608 */
+
+    mixer_store (s, AC97_Extended_Audio_ID       , 0x0809);
+    mixer_store (s, AC97_Extended_Audio_Ctrl_Stat, 0x0009);
+    mixer_store (s, AC97_PCM_Front_DAC_Rate      , 0xbb80);
+    mixer_store (s, AC97_PCM_Surround_DAC_Rate   , 0xbb80);
+    mixer_store (s, AC97_PCM_LFE_DAC_Rate        , 0xbb80);
+    mixer_store (s, AC97_PCM_LR_ADC_Rate         , 0xbb80);
+    mixer_store (s, AC97_MIC_ADC_Rate            , 0xbb80);
+
+    record_select (s, 0);
+    set_volume (s, AC97_Master_Volume_Mute, 0x8000);
+    set_volume (s, AC97_PCM_Out_Volume_Mute, 0x8808);
+    set_volume (s, AC97_Record_Gain_Mute, 0x8808);
+
+    reset_voices (s, active);
+}
+
+/**
+ * Native audio mixer
+ * I/O Reads
+ */
+static uint32_t nam_readb (void *opaque, uint32_t addr)
+{
+    AC97LinkState *s = opaque;
+    dolog ("U nam readb %#x\n", addr);
+    s->cas = 0;
+    return ~0U;
+}
+
+static uint32_t nam_readw (void *opaque, uint32_t addr)
+{
+    AC97LinkState *s = opaque;
+    uint32_t val = ~0U;
+    uint32_t index = addr;
+    s->cas = 0;
+    val = mixer_load (s, index);
+    return val;
+}
+
+static uint32_t nam_readl (void *opaque, uint32_t addr)
+{
+    AC97LinkState *s = opaque;
+    dolog ("U nam readl %#x\n", addr);
+    s->cas = 0;
+    return ~0U;
+}
+
+/**
+ * Native audio mixer
+ * I/O Writes
+ */
+static void nam_writeb (void *opaque, uint32_t addr, uint32_t val)
+{
+    AC97LinkState *s = opaque;
+    dolog ("U nam writeb %#x <- %#x\n", addr, val);
+    s->cas = 0;
+}
+
+static void nam_writew (void *opaque, uint32_t addr, uint32_t val)
+{
+    AC97LinkState *s = opaque;
+    uint32_t index = addr;
+    s->cas = 0;
+    switch (index) {
+    case AC97_Reset:
+        mixer_reset (s);
+        break;
+    case AC97_Powerdown_Ctrl_Stat:
+        val &= ~0x800f;
+        val |= mixer_load (s, index) & 0xf;
+        mixer_store (s, index, val);
+        break;
+    case AC97_PCM_Out_Volume_Mute:
+    case AC97_Master_Volume_Mute:
+    case AC97_Record_Gain_Mute:
+        set_volume (s, index, val);
+        break;
+    case AC97_Record_Select:
+        record_select (s, val);
+        break;
+    case AC97_Vendor_ID1:
+    case AC97_Vendor_ID2:
+        dolog ("Attempt to write vendor ID to %#x\n", val);
+        break;
+    case AC97_Extended_Audio_ID:
+        dolog ("Attempt to write extended audio ID to %#x\n", val);
+        break;
+    case AC97_Extended_Audio_Ctrl_Stat:
+        if (!(val & EACS_VRA)) {
+            mixer_store (s, AC97_PCM_Front_DAC_Rate, 0xbb80);
+            mixer_store (s, AC97_PCM_LR_ADC_Rate,    0xbb80);
+            open_voice (s, PI_INDEX, 48000);
+            open_voice (s, PO_INDEX, 48000);
+        }
+        if (!(val & EACS_VRM)) {
+            mixer_store (s, AC97_MIC_ADC_Rate, 0xbb80);
+            open_voice (s, MC_INDEX, 48000);
+        }
+        dolog ("Setting extended audio control to %#x\n", val);
+        mixer_store (s, AC97_Extended_Audio_Ctrl_Stat, val);
+        break;
+    case AC97_PCM_Front_DAC_Rate:
+        if (mixer_load (s, AC97_Extended_Audio_Ctrl_Stat) & EACS_VRA) {
+            mixer_store (s, index, val);
+            dolog ("Set front DAC rate to %d\n", val);
+            open_voice (s, PO_INDEX, val);
+        }
+        else {
+            dolog ("Attempt to set front DAC rate to %d, "
+                   "but VRA is not set\n",
+                   val);
+        }
+        break;
+    case AC97_MIC_ADC_Rate:
+        if (mixer_load (s, AC97_Extended_Audio_Ctrl_Stat) & EACS_VRM) {
+            mixer_store (s, index, val);
+            dolog ("Set MIC ADC rate to %d\n", val);
+            open_voice (s, MC_INDEX, val);
+        }
+        else {
+            dolog ("Attempt to set MIC ADC rate to %d, "
+                   "but VRM is not set\n",
+                   val);
+        }
+        break;
+    case AC97_PCM_LR_ADC_Rate:
+        if (mixer_load (s, AC97_Extended_Audio_Ctrl_Stat) & EACS_VRA) {
+            mixer_store (s, index, val);
+            dolog ("Set front LR ADC rate to %d\n", val);
+            open_voice (s, PI_INDEX, val);
+        }
+        else {
+            dolog ("Attempt to set LR ADC rate to %d, but VRA is not set\n",
+                    val);
+        }
+        break;
+    case AC97_Headphone_Volume_Mute:
+    case AC97_Master_Volume_Mono_Mute:
+    case AC97_Master_Tone_RL:
+    case AC97_PC_BEEP_Volume_Mute:
+    case AC97_Phone_Volume_Mute:
+    case AC97_Mic_Volume_Mute:
+    case AC97_Line_In_Volume_Mute:
+    case AC97_CD_Volume_Mute:
+    case AC97_Video_Volume_Mute:
+    case AC97_Aux_Volume_Mute:
+    case AC97_Record_Gain_Mic_Mute:
+    case AC97_General_Purpose:
+    case AC97_3D_Control:
+    case AC97_Sigmatel_Analog:
+    case AC97_Sigmatel_Dac2Invert:
+        /* None of the features in these regs are emulated, so they are RO */
+        break;
+    default:
+        dolog ("U nam writew %#x <- %#x\n", addr, val);
+        mixer_store (s, index, val);
+        break;
+    }
+}
+
+static void nam_writel (void *opaque, uint32_t addr, uint32_t val)
+{
+    AC97LinkState *s = opaque;
+    dolog ("U nam writel %#x <- %#x\n", addr, val);
+    s->cas = 0;
+}
+
+/**
+ * Native audio bus master
+ * I/O Reads
+ */
+static uint32_t nabm_readb (void *opaque, uint32_t addr)
+{
+    AC97LinkState *s = opaque;
+    AC97BusMasterRegs *r = NULL;
+    uint32_t index = addr;
+    uint32_t val = ~0U;
+
+    switch (index) {
+    case CAS:
+        dolog ("CAS %d\n", s->cas);
+        val = s->cas;
+        s->cas = 1;
+        break;
+    case PI_CIV:
+    case PO_CIV:
+    case MC_CIV:
+        r = &s->bm_regs[GET_BM (index)];
+        val = r->civ;
+        dolog ("CIV[%d] -> %#x\n", GET_BM (index), val);
+        break;
+    case PI_LVI:
+    case PO_LVI:
+    case MC_LVI:
+        r = &s->bm_regs[GET_BM (index)];
+        val = r->lvi;
+        dolog ("LVI[%d] -> %#x\n", GET_BM (index), val);
+        break;
+    case PI_PIV:
+    case PO_PIV:
+    case MC_PIV:
+        r = &s->bm_regs[GET_BM (index)];
+        val = r->piv;
+        dolog ("PIV[%d] -> %#x\n", GET_BM (index), val);
+        break;
+    case PI_CR:
+    case PO_CR:
+    case MC_CR:
+        r = &s->bm_regs[GET_BM (index)];
+        val = r->cr;
+        dolog ("CR[%d] -> %#x\n", GET_BM (index), val);
+        break;
+    case PI_SR:
+    case PO_SR:
+    case MC_SR:
+        r = &s->bm_regs[GET_BM (index)];
+        val = r->sr & 0xff;
+        dolog ("SRb[%d] -> %#x\n", GET_BM (index), val);
+        break;
+    default:
+        dolog ("U nabm readb %#x -> %#x\n", addr, val);
+        break;
+    }
+    return val;
+}
+
+static uint32_t nabm_readw (void *opaque, uint32_t addr)
+{
+    AC97LinkState *s = opaque;
+    AC97BusMasterRegs *r = NULL;
+    uint32_t index = addr;
+    uint32_t val = ~0U;
+
+    switch (index) {
+    case PI_SR:
+    case PO_SR:
+    case MC_SR:
+        r = &s->bm_regs[GET_BM (index)];
+        val = r->sr;
+        dolog ("SR[%d] -> %#x\n", GET_BM (index), val);
+        break;
+    case PI_PICB:
+    case PO_PICB:
+    case MC_PICB:
+        r = &s->bm_regs[GET_BM (index)];
+        val = r->picb;
+        dolog ("PICB[%d] -> %#x\n", GET_BM (index), val);
+        break;
+    default:
+        dolog ("U nabm readw %#x -> %#x\n", addr, val);
+        break;
+    }
+    return val;
+}
+
+static uint32_t nabm_readl (void *opaque, uint32_t addr)
+{
+    AC97LinkState *s = opaque;
+    AC97BusMasterRegs *r = NULL;
+    uint32_t index = addr;
+    uint32_t val = ~0U;
+
+    switch (index) {
+    case PI_BDBAR:
+    case PO_BDBAR:
+    case MC_BDBAR:
+        r = &s->bm_regs[GET_BM (index)];
+        val = r->bdbar;
+        dolog ("BMADDR[%d] -> %#x\n", GET_BM (index), val);
+        break;
+    case PI_CIV:
+    case PO_CIV:
+    case MC_CIV:
+        r = &s->bm_regs[GET_BM (index)];
+        val = r->civ | (r->lvi << 8) | (r->sr << 16);
+        dolog ("CIV LVI SR[%d] -> %#x, %#x, %#x\n", GET_BM (index),
+               r->civ, r->lvi, r->sr);
+        break;
+    case PI_PICB:
+    case PO_PICB:
+    case MC_PICB:
+        r = &s->bm_regs[GET_BM (index)];
+        val = r->picb | (r->piv << 16) | (r->cr << 24);
+        dolog ("PICB PIV CR[%d] -> %#x %#x %#x %#x\n", GET_BM (index),
+               val, r->picb, r->piv, r->cr);
+        break;
+    case GLOB_CNT:
+        val = s->glob_cnt;
+        dolog ("glob_cnt -> %#x\n", val);
+        break;
+    case GLOB_STA:
+        val = s->glob_sta | GS_S0CR;
+        dolog ("glob_sta -> %#x\n", val);
+        break;
+    default:
+        dolog ("U nabm readl %#x -> %#x\n", addr, val);
+        break;
+    }
+    return val;
+}
+
+/**
+ * Native audio bus master
+ * I/O Writes
+ */
+static void nabm_writeb (void *opaque, uint32_t addr, uint32_t val)
+{
+    AC97LinkState *s = opaque;
+    AC97BusMasterRegs *r = NULL;
+    uint32_t index = addr;
+    switch (index) {
+    case PI_LVI:
+    case PO_LVI:
+    case MC_LVI:
+        r = &s->bm_regs[GET_BM (index)];
+        if ((r->cr & CR_RPBM) && (r->sr & SR_DCH)) {
+            r->sr &= ~(SR_DCH | SR_CELV);
+            r->civ = r->piv;
+            r->piv = (r->piv + 1) % 32;
+            fetch_bd (s, r);
+        }
+        r->lvi = val % 32;
+        dolog ("LVI[%d] <- %#x\n", GET_BM (index), val);
+        break;
+    case PI_CR:
+    case PO_CR:
+    case MC_CR:
+        r = &s->bm_regs[GET_BM (index)];
+        if (val & CR_RR) {
+            reset_bm_regs (s, r);
+        }
+        else {
+            r->cr = val & CR_VALID_MASK;
+            if (!(r->cr & CR_RPBM)) {
+                voice_set_active (s, r - s->bm_regs, 0);
+                r->sr |= SR_DCH;
+            }
+            else {
+                r->civ = r->piv;
+                r->piv = (r->piv + 1) % 32;
+                fetch_bd (s, r);
+                r->sr &= ~SR_DCH;
+                voice_set_active (s, r - s->bm_regs, 1);
+            }
+        }
+        dolog ("CR[%d] <- %#x (cr %#x)\n", GET_BM (index), val, r->cr);
+        break;
+    case PI_SR:
+    case PO_SR:
+    case MC_SR:
+        r = &s->bm_regs[GET_BM (index)];
+        r->sr |= val & ~(SR_RO_MASK | SR_WCLEAR_MASK);
+        update_sr (s, r, r->sr & ~(val & SR_WCLEAR_MASK));
+        dolog ("SR[%d] <- %#x (sr %#x)\n", GET_BM (index), val, r->sr);
+        break;
+    default:
+        dolog ("U nabm writeb %#x <- %#x\n", addr, val);
+        break;
+    }
+}
+
+static void nabm_writew (void *opaque, uint32_t addr, uint32_t val)
+{
+    AC97LinkState *s = opaque;
+    AC97BusMasterRegs *r = NULL;
+    uint32_t index = addr;
+    switch (index) {
+    case PI_SR:
+    case PO_SR:
+    case MC_SR:
+        r = &s->bm_regs[GET_BM (index)];
+        r->sr |= val & ~(SR_RO_MASK | SR_WCLEAR_MASK);
+        update_sr (s, r, r->sr & ~(val & SR_WCLEAR_MASK));
+        dolog ("SR[%d] <- %#x (sr %#x)\n", GET_BM (index), val, r->sr);
+        break;
+    default:
+        dolog ("U nabm writew %#x <- %#x\n", addr, val);
+        break;
+    }
+}
+
+static void nabm_writel (void *opaque, uint32_t addr, uint32_t val)
+{
+    AC97LinkState *s = opaque;
+    AC97BusMasterRegs *r = NULL;
+    uint32_t index = addr;
+    switch (index) {
+    case PI_BDBAR:
+    case PO_BDBAR:
+    case MC_BDBAR:
+        r = &s->bm_regs[GET_BM (index)];
+        r->bdbar = val & ~3;
+        dolog ("BDBAR[%d] <- %#x (bdbar %#x)\n",
+               GET_BM (index), val, r->bdbar);
+        break;
+    case GLOB_CNT:
+        if (val & GC_WR)
+            warm_reset (s);
+        if (val & GC_CR)
+            cold_reset (s);
+        if (!(val & (GC_WR | GC_CR)))
+            s->glob_cnt = val & GC_VALID_MASK;
+        dolog ("glob_cnt <- %#x (glob_cnt %#x)\n", val, s->glob_cnt);
+        break;
+    case GLOB_STA:
+        s->glob_sta &= ~(val & GS_WCLEAR_MASK);
+        s->glob_sta |= (val & ~(GS_WCLEAR_MASK | GS_RO_MASK)) & GS_VALID_MASK;
+        dolog ("glob_sta <- %#x (glob_sta %#x)\n", val, s->glob_sta);
+        break;
+    default:
+        dolog ("U nabm writel %#x <- %#x\n", addr, val);
+        break;
+    }
+}
+
+static int write_audio (AC97LinkState *s, AC97BusMasterRegs *r,
+                        int max, int *stop)
+{
+    uint8_t tmpbuf[4096];
+    uint32_t addr = r->bd.addr;
+    uint32_t temp = r->picb << 1;
+    uint32_t written = 0;
+    int to_copy = 0;
+    temp = audio_MIN (temp, max);
+
+    if (!temp) {
+        *stop = 1;
+        return 0;
+    }
+
+    while (temp) {
+        int copied;
+        to_copy = audio_MIN (temp, sizeof (tmpbuf));
+        pci_dma_read (&s->dev, addr, tmpbuf, to_copy);
+        copied = AUD_write (s->voice_po, tmpbuf, to_copy);
+        dolog ("write_audio max=%x to_copy=%x copied=%x\n",
+               max, to_copy, copied);
+        if (!copied) {
+            *stop = 1;
+            break;
+        }
+        temp -= copied;
+        addr += copied;
+        written += copied;
+    }
+
+    if (!temp) {
+        if (to_copy < 4) {
+            dolog ("whoops\n");
+            s->last_samp = 0;
+        }
+        else {
+            s->last_samp = *(uint32_t *) &tmpbuf[to_copy - 4];
+        }
+    }
+
+    r->bd.addr = addr;
+    return written;
+}
+
+static void write_bup (AC97LinkState *s, int elapsed)
+{
+    dolog ("write_bup\n");
+    if (!(s->bup_flag & BUP_SET)) {
+        if (s->bup_flag & BUP_LAST) {
+            int i;
+            uint8_t *p = s->silence;
+            for (i = 0; i < sizeof (s->silence) / 4; i++, p += 4) {
+                *(uint32_t *) p = s->last_samp;
+            }
+        }
+        else {
+            memset (s->silence, 0, sizeof (s->silence));
+        }
+        s->bup_flag |= BUP_SET;
+    }
+
+    while (elapsed) {
+        int temp = audio_MIN (elapsed, sizeof (s->silence));
+        while (temp) {
+            int copied = AUD_write (s->voice_po, s->silence, temp);
+            if (!copied)
+                return;
+            temp -= copied;
+            elapsed -= copied;
+        }
+    }
+}
+
+static int read_audio (AC97LinkState *s, AC97BusMasterRegs *r,
+                       int max, int *stop)
+{
+    uint8_t tmpbuf[4096];
+    uint32_t addr = r->bd.addr;
+    uint32_t temp = r->picb << 1;
+    uint32_t nread = 0;
+    int to_copy = 0;
+    SWVoiceIn *voice = (r - s->bm_regs) == MC_INDEX ? s->voice_mc : s->voice_pi;
+
+    temp = audio_MIN (temp, max);
+
+    if (!temp) {
+        *stop = 1;
+        return 0;
+    }
+
+    while (temp) {
+        int acquired;
+        to_copy = audio_MIN (temp, sizeof (tmpbuf));
+        acquired = AUD_read (voice, tmpbuf, to_copy);
+        if (!acquired) {
+            *stop = 1;
+            break;
+        }
+        pci_dma_write (&s->dev, addr, tmpbuf, acquired);
+        temp -= acquired;
+        addr += acquired;
+        nread += acquired;
+    }
+
+    r->bd.addr = addr;
+    return nread;
+}
+
+static void transfer_audio (AC97LinkState *s, int index, int elapsed)
+{
+    AC97BusMasterRegs *r = &s->bm_regs[index];
+    int stop = 0;
+
+    if (s->invalid_freq[index]) {
+        AUD_log ("ac97", "attempt to use voice %d with invalid frequency %d\n",
+                 index, s->invalid_freq[index]);
+        return;
+    }
+
+    if (r->sr & SR_DCH) {
+        if (r->cr & CR_RPBM) {
+            switch (index) {
+            case PO_INDEX:
+                write_bup (s, elapsed);
+                break;
+            }
+        }
+        return;
+    }
+
+    while ((elapsed >> 1) && !stop) {
+        int temp;
+
+        if (!r->bd_valid) {
+            dolog ("invalid bd\n");
+            fetch_bd (s, r);
+        }
+
+        if (!r->picb) {
+            dolog ("fresh bd %d is empty %#x %#x\n",
+                   r->civ, r->bd.addr, r->bd.ctl_len);
+            if (r->civ == r->lvi) {
+                r->sr |= SR_DCH; /* CELV? */
+                s->bup_flag = 0;
+                break;
+            }
+            r->sr &= ~SR_CELV;
+            r->civ = r->piv;
+            r->piv = (r->piv + 1) % 32;
+            fetch_bd (s, r);
+            return;
+        }
+
+        switch (index) {
+        case PO_INDEX:
+            temp = write_audio (s, r, elapsed, &stop);
+            elapsed -= temp;
+            r->picb -= (temp >> 1);
+            break;
+
+        case PI_INDEX:
+        case MC_INDEX:
+            temp = read_audio (s, r, elapsed, &stop);
+            elapsed -= temp;
+            r->picb -= (temp >> 1);
+            break;
+        }
+
+        if (!r->picb) {
+            uint32_t new_sr = r->sr & ~SR_CELV;
+
+            if (r->bd.ctl_len & BD_IOC) {
+                new_sr |= SR_BCIS;
+            }
+
+            if (r->civ == r->lvi) {
+                dolog ("Underrun civ (%d) == lvi (%d)\n", r->civ, r->lvi);
+
+                new_sr |= SR_LVBCI | SR_DCH | SR_CELV;
+                stop = 1;
+                s->bup_flag = (r->bd.ctl_len & BD_BUP) ? BUP_LAST : 0;
+            }
+            else {
+                r->civ = r->piv;
+                r->piv = (r->piv + 1) % 32;
+                fetch_bd (s, r);
+            }
+
+            update_sr (s, r, new_sr);
+        }
+    }
+}
+
+static void pi_callback (void *opaque, int avail)
+{
+    transfer_audio (opaque, PI_INDEX, avail);
+}
+
+static void mc_callback (void *opaque, int avail)
+{
+    transfer_audio (opaque, MC_INDEX, avail);
+}
+
+static void po_callback (void *opaque, int free)
+{
+    transfer_audio (opaque, PO_INDEX, free);
+}
+
+static const VMStateDescription vmstate_ac97_bm_regs = {
+    .name = "ac97_bm_regs",
+    .version_id = 1,
+    .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 ()
+    }
+};
+
+static int ac97_post_load (void *opaque, int version_id)
+{
+    uint8_t active[LAST_INDEX];
+    AC97LinkState *s = opaque;
+
+    record_select (s, mixer_load (s, AC97_Record_Select));
+    set_volume (s, AC97_Master_Volume_Mute,
+                mixer_load (s, AC97_Master_Volume_Mute));
+    set_volume (s, AC97_PCM_Out_Volume_Mute,
+                mixer_load (s, AC97_PCM_Out_Volume_Mute));
+    set_volume (s, AC97_Record_Gain_Mute,
+                mixer_load (s, AC97_Record_Gain_Mute));
+
+    active[PI_INDEX] = !!(s->bm_regs[PI_INDEX].cr & CR_RPBM);
+    active[PO_INDEX] = !!(s->bm_regs[PO_INDEX].cr & CR_RPBM);
+    active[MC_INDEX] = !!(s->bm_regs[MC_INDEX].cr & CR_RPBM);
+    reset_voices (s, active);
+
+    s->bup_flag = 0;
+    s->last_samp = 0;
+    return 0;
+}
+
+static bool is_version_2 (void *opaque, int version_id)
+{
+    return version_id == 2;
+}
+
+static const VMStateDescription vmstate_ac97 = {
+    .name = "ac97",
+    .version_id = 3,
+    .minimum_version_id = 2,
+    .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 ()
+    }
+};
+
+static uint64_t nam_read(void *opaque, hwaddr addr, unsigned size)
+{
+    if ((addr / size) > 256) {
+        return -1;
+    }
+
+    switch (size) {
+    case 1:
+        return nam_readb(opaque, addr);
+    case 2:
+        return nam_readw(opaque, addr);
+    case 4:
+        return nam_readl(opaque, addr);
+    default:
+        return -1;
+    }
+}
+
+static void nam_write(void *opaque, hwaddr addr, uint64_t val,
+                      unsigned size)
+{
+    if ((addr / size) > 256) {
+        return;
+    }
+
+    switch (size) {
+    case 1:
+        nam_writeb(opaque, addr, val);
+        break;
+    case 2:
+        nam_writew(opaque, addr, val);
+        break;
+    case 4:
+        nam_writel(opaque, addr, val);
+        break;
+    }
+}
+
+static const MemoryRegionOps ac97_io_nam_ops = {
+    .read = nam_read,
+    .write = nam_write,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 4,
+    },
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static uint64_t nabm_read(void *opaque, hwaddr addr, unsigned size)
+{
+    if ((addr / size) > 64) {
+        return -1;
+    }
+
+    switch (size) {
+    case 1:
+        return nabm_readb(opaque, addr);
+    case 2:
+        return nabm_readw(opaque, addr);
+    case 4:
+        return nabm_readl(opaque, addr);
+    default:
+        return -1;
+    }
+}
+
+static void nabm_write(void *opaque, hwaddr addr, uint64_t val,
+                      unsigned size)
+{
+    if ((addr / size) > 64) {
+        return;
+    }
+
+    switch (size) {
+    case 1:
+        nabm_writeb(opaque, addr, val);
+        break;
+    case 2:
+        nabm_writew(opaque, addr, val);
+        break;
+    case 4:
+        nabm_writel(opaque, addr, val);
+        break;
+    }
+}
+
+
+static const MemoryRegionOps ac97_io_nabm_ops = {
+    .read = nabm_read,
+    .write = nabm_write,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 4,
+    },
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void ac97_on_reset (void *opaque)
+{
+    AC97LinkState *s = opaque;
+
+    reset_bm_regs (s, &s->bm_regs[0]);
+    reset_bm_regs (s, &s->bm_regs[1]);
+    reset_bm_regs (s, &s->bm_regs[2]);
+
+    /*
+     * Reset the mixer too. The Windows XP driver seems to rely on
+     * this. At least it wants to read the vendor id before it resets
+     * the codec manually.
+     */
+    mixer_reset (s);
+}
+
+static int ac97_initfn (PCIDevice *dev)
+{
+    AC97LinkState *s = DO_UPCAST (AC97LinkState, dev, dev);
+    uint8_t *c = s->dev.config;
+
+    /* TODO: no need to override */
+    c[PCI_COMMAND] = 0x00;      /* pcicmd pci command rw, ro */
+    c[PCI_COMMAND + 1] = 0x00;
+
+    /* TODO: */
+    c[PCI_STATUS] = PCI_STATUS_FAST_BACK;      /* pcists pci status rwc, ro */
+    c[PCI_STATUS + 1] = PCI_STATUS_DEVSEL_MEDIUM >> 8;
+
+    c[PCI_CLASS_PROG] = 0x00;      /* pi programming interface ro */
+
+    /* TODO set when bar is registered. no need to override. */
+    /* nabmar native audio mixer base address rw */
+    c[PCI_BASE_ADDRESS_0] = PCI_BASE_ADDRESS_SPACE_IO;
+    c[PCI_BASE_ADDRESS_0 + 1] = 0x00;
+    c[PCI_BASE_ADDRESS_0 + 2] = 0x00;
+    c[PCI_BASE_ADDRESS_0 + 3] = 0x00;
+
+    /* TODO set when bar is registered. no need to override. */
+      /* nabmbar native audio bus mastering base address rw */
+    c[PCI_BASE_ADDRESS_0 + 4] = PCI_BASE_ADDRESS_SPACE_IO;
+    c[PCI_BASE_ADDRESS_0 + 5] = 0x00;
+    c[PCI_BASE_ADDRESS_0 + 6] = 0x00;
+    c[PCI_BASE_ADDRESS_0 + 7] = 0x00;
+
+    if (s->use_broken_id) {
+        c[PCI_SUBSYSTEM_VENDOR_ID] = 0x86;
+        c[PCI_SUBSYSTEM_VENDOR_ID + 1] = 0x80;
+        c[PCI_SUBSYSTEM_ID] = 0x00;
+        c[PCI_SUBSYSTEM_ID + 1] = 0x00;
+    }
+
+    c[PCI_INTERRUPT_LINE] = 0x00;      /* intr_ln interrupt line rw */
+    c[PCI_INTERRUPT_PIN] = 0x01;      /* intr_pn interrupt pin ro */
+
+    memory_region_init_io (&s->io_nam, &ac97_io_nam_ops, s, "ac97-nam", 1024);
+    memory_region_init_io (&s->io_nabm, &ac97_io_nabm_ops, s, "ac97-nabm", 256);
+    pci_register_bar (&s->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io_nam);
+    pci_register_bar (&s->dev, 1, PCI_BASE_ADDRESS_SPACE_IO, &s->io_nabm);
+    qemu_register_reset (ac97_on_reset, s);
+    AUD_register_card ("ac97", &s->card);
+    ac97_on_reset (s);
+    return 0;
+}
+
+static void ac97_exitfn (PCIDevice *dev)
+{
+    AC97LinkState *s = DO_UPCAST (AC97LinkState, dev, dev);
+
+    memory_region_destroy (&s->io_nam);
+    memory_region_destroy (&s->io_nabm);
+}
+
+int ac97_init (PCIBus *bus)
+{
+    pci_create_simple (bus, -1, "AC97");
+    return 0;
+}
+
+static Property ac97_properties[] = {
+    DEFINE_PROP_UINT32 ("use_broken_id", AC97LinkState, use_broken_id, 0),
+    DEFINE_PROP_END_OF_LIST (),
+};
+
+static void ac97_class_init (ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS (klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS (klass);
+
+    k->init = ac97_initfn;
+    k->exit = ac97_exitfn;
+    k->vendor_id = PCI_VENDOR_ID_INTEL;
+    k->device_id = PCI_DEVICE_ID_INTEL_82801AA_5;
+    k->revision = 0x01;
+    k->class_id = PCI_CLASS_MULTIMEDIA_AUDIO;
+    dc->desc = "Intel 82801AA AC97 Audio";
+    dc->vmsd = &vmstate_ac97;
+    dc->props = ac97_properties;
+}
+
+static const TypeInfo ac97_info = {
+    .name          = "AC97",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof (AC97LinkState),
+    .class_init    = ac97_class_init,
+};
+
+static void ac97_register_types (void)
+{
+    type_register_static (&ac97_info);
+}
+
+type_init (ac97_register_types)
diff --git a/hw/audio/adlib.c b/hw/audio/adlib.c
new file mode 100644 (file)
index 0000000..4a58e6e
--- /dev/null
@@ -0,0 +1,337 @@
+/*
+ * QEMU Proxy for OPL2/3 emulation by MAME team
+ *
+ * Copyright (c) 2004-2005 Vassili Karpov (malc)
+ *
+ * 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 "hw/hw.h"
+#include "hw/audio/audio.h"
+#include "audio/audio.h"
+#include "hw/isa/isa.h"
+
+//#define DEBUG
+
+#define ADLIB_KILL_TIMERS 1
+
+#ifdef DEBUG
+#include "qemu/timer.h"
+#endif
+
+#define dolog(...) AUD_log ("adlib", __VA_ARGS__)
+#ifdef DEBUG
+#define ldebug(...) dolog (__VA_ARGS__)
+#else
+#define ldebug(...)
+#endif
+
+#ifdef HAS_YMF262
+#include "ymf262.h"
+void YMF262UpdateOneQEMU (int which, INT16 *dst, int length);
+#define SHIFT 2
+#else
+#include "fmopl.h"
+#define SHIFT 1
+#endif
+
+#define IO_READ_PROTO(name) \
+    uint32_t name (void *opaque, uint32_t nport)
+#define IO_WRITE_PROTO(name) \
+    void name (void *opaque, uint32_t nport, uint32_t val)
+
+static struct {
+    int port;
+    int freq;
+} conf = {0x220, 44100};
+
+typedef struct {
+    QEMUSoundCard card;
+    int ticking[2];
+    int enabled;
+    int active;
+    int bufpos;
+#ifdef DEBUG
+    int64_t exp[2];
+#endif
+    int16_t *mixbuf;
+    uint64_t dexp[2];
+    SWVoiceOut *voice;
+    int left, pos, samples;
+    QEMUAudioTimeStamp ats;
+#ifndef HAS_YMF262
+    FM_OPL *opl;
+#endif
+} AdlibState;
+
+static AdlibState glob_adlib;
+
+static void adlib_stop_opl_timer (AdlibState *s, size_t n)
+{
+#ifdef HAS_YMF262
+    YMF262TimerOver (0, n);
+#else
+    OPLTimerOver (s->opl, n);
+#endif
+    s->ticking[n] = 0;
+}
+
+static void adlib_kill_timers (AdlibState *s)
+{
+    size_t i;
+
+    for (i = 0; i < 2; ++i) {
+        if (s->ticking[i]) {
+            uint64_t delta;
+
+            delta = AUD_get_elapsed_usec_out (s->voice, &s->ats);
+            ldebug (
+                "delta = %f dexp = %f expired => %d\n",
+                delta / 1000000.0,
+                s->dexp[i] / 1000000.0,
+                delta >= s->dexp[i]
+                );
+            if (ADLIB_KILL_TIMERS || delta >= s->dexp[i]) {
+                adlib_stop_opl_timer (s, i);
+                AUD_init_time_stamp_out (s->voice, &s->ats);
+            }
+        }
+    }
+}
+
+static IO_WRITE_PROTO (adlib_write)
+{
+    AdlibState *s = opaque;
+    int a = nport & 3;
+
+    s->active = 1;
+    AUD_set_active_out (s->voice, 1);
+
+    adlib_kill_timers (s);
+
+#ifdef HAS_YMF262
+    YMF262Write (0, a, val);
+#else
+    OPLWrite (s->opl, a, val);
+#endif
+}
+
+static IO_READ_PROTO (adlib_read)
+{
+    AdlibState *s = opaque;
+    uint8_t data;
+    int a = nport & 3;
+
+    adlib_kill_timers (s);
+
+#ifdef HAS_YMF262
+    data = YMF262Read (0, a);
+#else
+    data = OPLRead (s->opl, a);
+#endif
+    return data;
+}
+
+static void timer_handler (int c, double interval_Sec)
+{
+    AdlibState *s = &glob_adlib;
+    unsigned n = c & 1;
+#ifdef DEBUG
+    double interval;
+    int64_t exp;
+#endif
+
+    if (interval_Sec == 0.0) {
+        s->ticking[n] = 0;
+        return;
+    }
+
+    s->ticking[n] = 1;
+#ifdef DEBUG
+    interval = get_ticks_per_sec () * interval_Sec;
+    exp = qemu_get_clock_ns (vm_clock) + interval;
+    s->exp[n] = exp;
+#endif
+
+    s->dexp[n] = interval_Sec * 1000000.0;
+    AUD_init_time_stamp_out (s->voice, &s->ats);
+}
+
+static int write_audio (AdlibState *s, int samples)
+{
+    int net = 0;
+    int pos = s->pos;
+
+    while (samples) {
+        int nbytes, wbytes, wsampl;
+
+        nbytes = samples << SHIFT;
+        wbytes = AUD_write (
+            s->voice,
+            s->mixbuf + (pos << (SHIFT - 1)),
+            nbytes
+            );
+
+        if (wbytes) {
+            wsampl = wbytes >> SHIFT;
+
+            samples -= wsampl;
+            pos = (pos + wsampl) % s->samples;
+
+            net += wsampl;
+        }
+        else {
+            break;
+        }
+    }
+
+    return net;
+}
+
+static void adlib_callback (void *opaque, int free)
+{
+    AdlibState *s = opaque;
+    int samples, net = 0, to_play, written;
+
+    samples = free >> SHIFT;
+    if (!(s->active && s->enabled) || !samples) {
+        return;
+    }
+
+    to_play = audio_MIN (s->left, samples);
+    while (to_play) {
+        written = write_audio (s, to_play);
+
+        if (written) {
+            s->left -= written;
+            samples -= written;
+            to_play -= written;
+            s->pos = (s->pos + written) % s->samples;
+        }
+        else {
+            return;
+        }
+    }
+
+    samples = audio_MIN (samples, s->samples - s->pos);
+    if (!samples) {
+        return;
+    }
+
+#ifdef HAS_YMF262
+    YMF262UpdateOneQEMU (0, s->mixbuf + s->pos * 2, samples);
+#else
+    YM3812UpdateOne (s->opl, s->mixbuf + s->pos, samples);
+#endif
+
+    while (samples) {
+        written = write_audio (s, samples);
+
+        if (written) {
+            net += written;
+            samples -= written;
+            s->pos = (s->pos + written) % s->samples;
+        }
+        else {
+            s->left = samples;
+            return;
+        }
+    }
+}
+
+static void Adlib_fini (AdlibState *s)
+{
+#ifdef HAS_YMF262
+    YMF262Shutdown ();
+#else
+    if (s->opl) {
+        OPLDestroy (s->opl);
+        s->opl = NULL;
+    }
+#endif
+
+    if (s->mixbuf) {
+        g_free (s->mixbuf);
+    }
+
+    s->active = 0;
+    s->enabled = 0;
+    AUD_remove_card (&s->card);
+}
+
+int Adlib_init (ISABus *bus)
+{
+    AdlibState *s = &glob_adlib;
+    struct audsettings as;
+
+#ifdef HAS_YMF262
+    if (YMF262Init (1, 14318180, conf.freq)) {
+        dolog ("YMF262Init %d failed\n", conf.freq);
+        return -1;
+    }
+    else {
+        YMF262SetTimerHandler (0, timer_handler, 0);
+        s->enabled = 1;
+    }
+#else
+    s->opl = OPLCreate (OPL_TYPE_YM3812, 3579545, conf.freq);
+    if (!s->opl) {
+        dolog ("OPLCreate %d failed\n", conf.freq);
+        return -1;
+    }
+    else {
+        OPLSetTimerHandler (s->opl, timer_handler, 0);
+        s->enabled = 1;
+    }
+#endif
+
+    as.freq = conf.freq;
+    as.nchannels = SHIFT;
+    as.fmt = AUD_FMT_S16;
+    as.endianness = AUDIO_HOST_ENDIANNESS;
+
+    AUD_register_card ("adlib", &s->card);
+
+    s->voice = AUD_open_out (
+        &s->card,
+        s->voice,
+        "adlib",
+        s,
+        adlib_callback,
+        &as
+        );
+    if (!s->voice) {
+        Adlib_fini (s);
+        return -1;
+    }
+
+    s->samples = AUD_get_buffer_size_out (s->voice) >> SHIFT;
+    s->mixbuf = g_malloc0 (s->samples << SHIFT);
+
+    register_ioport_read (0x388, 4, 1, adlib_read, s);
+    register_ioport_write (0x388, 4, 1, adlib_write, s);
+
+    register_ioport_read (conf.port, 4, 1, adlib_read, s);
+    register_ioport_write (conf.port, 4, 1, adlib_write, s);
+
+    register_ioport_read (conf.port + 8, 2, 1, adlib_read, s);
+    register_ioport_write (conf.port + 8, 2, 1, adlib_write, s);
+
+    return 0;
+}
diff --git a/hw/audio/cs4231.c b/hw/audio/cs4231.c
new file mode 100644 (file)
index 0000000..2975336
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+ * QEMU Crystal CS4231 audio chip emulation
+ *
+ * Copyright (c) 2006 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.
+ */
+
+#include "hw/sysbus.h"
+#include "trace.h"
+
+/*
+ * In addition to Crystal CS4231 there is a DMA controller on Sparc.
+ */
+#define CS_SIZE 0x40
+#define CS_REGS 16
+#define CS_DREGS 32
+#define CS_MAXDREG (CS_DREGS - 1)
+
+typedef struct CSState {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    qemu_irq irq;
+    uint32_t regs[CS_REGS];
+    uint8_t dregs[CS_DREGS];
+} CSState;
+
+#define CS_RAP(s) ((s)->regs[0] & CS_MAXDREG)
+#define CS_VER 0xa0
+#define CS_CDC_VER 0x8a
+
+static void cs_reset(DeviceState *d)
+{
+    CSState *s = container_of(d, CSState, busdev.qdev);
+
+    memset(s->regs, 0, CS_REGS * 4);
+    memset(s->dregs, 0, CS_DREGS);
+    s->dregs[12] = CS_CDC_VER;
+    s->dregs[25] = CS_VER;
+}
+
+static uint64_t cs_mem_read(void *opaque, hwaddr addr,
+                            unsigned size)
+{
+    CSState *s = opaque;
+    uint32_t saddr, ret;
+
+    saddr = addr >> 2;
+    switch (saddr) {
+    case 1:
+        switch (CS_RAP(s)) {
+        case 3: // Write only
+            ret = 0;
+            break;
+        default:
+            ret = s->dregs[CS_RAP(s)];
+            break;
+        }
+        trace_cs4231_mem_readl_dreg(CS_RAP(s), ret);
+        break;
+    default:
+        ret = s->regs[saddr];
+        trace_cs4231_mem_readl_reg(saddr, ret);
+        break;
+    }
+    return ret;
+}
+
+static void cs_mem_write(void *opaque, hwaddr addr,
+                         uint64_t val, unsigned size)
+{
+    CSState *s = opaque;
+    uint32_t saddr;
+
+    saddr = addr >> 2;
+    trace_cs4231_mem_writel_reg(saddr, s->regs[saddr], val);
+    switch (saddr) {
+    case 1:
+        trace_cs4231_mem_writel_dreg(CS_RAP(s), s->dregs[CS_RAP(s)], val);
+        switch(CS_RAP(s)) {
+        case 11:
+        case 25: // Read only
+            break;
+        case 12:
+            val &= 0x40;
+            val |= CS_CDC_VER; // Codec version
+            s->dregs[CS_RAP(s)] = val;
+            break;
+        default:
+            s->dregs[CS_RAP(s)] = val;
+            break;
+        }
+        break;
+    case 2: // Read only
+        break;
+    case 4:
+        if (val & 1) {
+            cs_reset(&s->busdev.qdev);
+        }
+        val &= 0x7f;
+        s->regs[saddr] = val;
+        break;
+    default:
+        s->regs[saddr] = val;
+        break;
+    }
+}
+
+static const MemoryRegionOps cs_mem_ops = {
+    .read = cs_mem_read,
+    .write = cs_mem_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static const VMStateDescription vmstate_cs4231 = {
+    .name ="cs4231",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT32_ARRAY(regs, CSState, CS_REGS),
+        VMSTATE_UINT8_ARRAY(dregs, CSState, CS_DREGS),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int cs4231_init1(SysBusDevice *dev)
+{
+    CSState *s = FROM_SYSBUS(CSState, dev);
+
+    memory_region_init_io(&s->iomem, &cs_mem_ops, s, "cs4321", CS_SIZE);
+    sysbus_init_mmio(dev, &s->iomem);
+    sysbus_init_irq(dev, &s->irq);
+
+    return 0;
+}
+
+static Property cs4231_properties[] = {
+    {.name = NULL},
+};
+
+static void cs4231_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = cs4231_init1;
+    dc->reset = cs_reset;
+    dc->vmsd = &vmstate_cs4231;
+    dc->props = cs4231_properties;
+}
+
+static const TypeInfo cs4231_info = {
+    .name          = "SUNW,CS4231",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(CSState),
+    .class_init    = cs4231_class_init,
+};
+
+static void cs4231_register_types(void)
+{
+    type_register_static(&cs4231_info);
+}
+
+type_init(cs4231_register_types)
diff --git a/hw/audio/cs4231a.c b/hw/audio/cs4231a.c
new file mode 100644 (file)
index 0000000..5711b62
--- /dev/null
@@ -0,0 +1,697 @@
+/*
+ * QEMU Crystal CS4231 audio chip emulation
+ *
+ * Copyright (c) 2006 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.
+ */
+#include "hw/hw.h"
+#include "hw/audio/audio.h"
+#include "audio/audio.h"
+#include "hw/isa/isa.h"
+#include "hw/qdev.h"
+#include "qemu/timer.h"
+
+/*
+  Missing features:
+  ADC
+  Loopback
+  Timer
+  ADPCM
+  More...
+*/
+
+/* #define DEBUG */
+/* #define DEBUG_XLAW */
+
+static struct {
+    int aci_counter;
+} conf = {1};
+
+#ifdef DEBUG
+#define dolog(...) AUD_log ("cs4231a", __VA_ARGS__)
+#else
+#define dolog(...)
+#endif
+
+#define lwarn(...) AUD_log ("cs4231a", "warning: " __VA_ARGS__)
+#define lerr(...) AUD_log ("cs4231a", "error: " __VA_ARGS__)
+
+#define CS_REGS 16
+#define CS_DREGS 32
+
+typedef struct CSState {
+    ISADevice dev;
+    QEMUSoundCard card;
+    MemoryRegion ioports;
+    qemu_irq pic;
+    uint32_t regs[CS_REGS];
+    uint8_t dregs[CS_DREGS];
+    uint32_t irq;
+    uint32_t dma;
+    uint32_t port;
+    int shift;
+    int dma_running;
+    int audio_free;
+    int transferred;
+    int aci_counter;
+    SWVoiceOut *voice;
+    int16_t *tab;
+} CSState;
+
+#define MODE2 (1 << 6)
+#define MCE (1 << 6)
+#define PMCE (1 << 4)
+#define CMCE (1 << 5)
+#define TE (1 << 6)
+#define PEN (1 << 0)
+#define INT (1 << 0)
+#define IEN (1 << 1)
+#define PPIO (1 << 6)
+#define PI (1 << 4)
+#define CI (1 << 5)
+#define TI (1 << 6)
+
+enum {
+    Index_Address,
+    Index_Data,
+    Status,
+    PIO_Data
+};
+
+enum {
+    Left_ADC_Input_Control,
+    Right_ADC_Input_Control,
+    Left_AUX1_Input_Control,
+    Right_AUX1_Input_Control,
+    Left_AUX2_Input_Control,
+    Right_AUX2_Input_Control,
+    Left_DAC_Output_Control,
+    Right_DAC_Output_Control,
+    FS_And_Playback_Data_Format,
+    Interface_Configuration,
+    Pin_Control,
+    Error_Status_And_Initialization,
+    MODE_And_ID,
+    Loopback_Control,
+    Playback_Upper_Base_Count,
+    Playback_Lower_Base_Count,
+    Alternate_Feature_Enable_I,
+    Alternate_Feature_Enable_II,
+    Left_Line_Input_Control,
+    Right_Line_Input_Control,
+    Timer_Low_Base,
+    Timer_High_Base,
+    RESERVED,
+    Alternate_Feature_Enable_III,
+    Alternate_Feature_Status,
+    Version_Chip_ID,
+    Mono_Input_And_Output_Control,
+    RESERVED_2,
+    Capture_Data_Format,
+    RESERVED_3,
+    Capture_Upper_Base_Count,
+    Capture_Lower_Base_Count
+};
+
+static int freqs[2][8] = {
+    { 8000, 16000, 27420, 32000,    -1,    -1, 48000, 9000 },
+    { 5510, 11025, 18900, 22050, 37800, 44100, 33075, 6620 }
+};
+
+/* Tables courtesy http://hazelware.luggle.com/tutorials/mulawcompression.html */
+static int16_t MuLawDecompressTable[256] =
+{
+     -32124,-31100,-30076,-29052,-28028,-27004,-25980,-24956,
+     -23932,-22908,-21884,-20860,-19836,-18812,-17788,-16764,
+     -15996,-15484,-14972,-14460,-13948,-13436,-12924,-12412,
+     -11900,-11388,-10876,-10364, -9852, -9340, -8828, -8316,
+      -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140,
+      -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092,
+      -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004,
+      -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980,
+      -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436,
+      -1372, -1308, -1244, -1180, -1116, -1052,  -988,  -924,
+       -876,  -844,  -812,  -780,  -748,  -716,  -684,  -652,
+       -620,  -588,  -556,  -524,  -492,  -460,  -428,  -396,
+       -372,  -356,  -340,  -324,  -308,  -292,  -276,  -260,
+       -244,  -228,  -212,  -196,  -180,  -164,  -148,  -132,
+       -120,  -112,  -104,   -96,   -88,   -80,   -72,   -64,
+        -56,   -48,   -40,   -32,   -24,   -16,    -8,     0,
+      32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956,
+      23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764,
+      15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412,
+      11900, 11388, 10876, 10364,  9852,  9340,  8828,  8316,
+       7932,  7676,  7420,  7164,  6908,  6652,  6396,  6140,
+       5884,  5628,  5372,  5116,  4860,  4604,  4348,  4092,
+       3900,  3772,  3644,  3516,  3388,  3260,  3132,  3004,
+       2876,  2748,  2620,  2492,  2364,  2236,  2108,  1980,
+       1884,  1820,  1756,  1692,  1628,  1564,  1500,  1436,
+       1372,  1308,  1244,  1180,  1116,  1052,   988,   924,
+        876,   844,   812,   780,   748,   716,   684,   652,
+        620,   588,   556,   524,   492,   460,   428,   396,
+        372,   356,   340,   324,   308,   292,   276,   260,
+        244,   228,   212,   196,   180,   164,   148,   132,
+        120,   112,   104,    96,    88,    80,    72,    64,
+         56,    48,    40,    32,    24,    16,     8,     0
+};
+
+static int16_t ALawDecompressTable[256] =
+{
+     -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736,
+     -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784,
+     -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368,
+     -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392,
+     -22016,-20992,-24064,-23040,-17920,-16896,-19968,-18944,
+     -30208,-29184,-32256,-31232,-26112,-25088,-28160,-27136,
+     -11008,-10496,-12032,-11520,-8960, -8448, -9984, -9472,
+     -15104,-14592,-16128,-15616,-13056,-12544,-14080,-13568,
+     -344,  -328,  -376,  -360,  -280,  -264,  -312,  -296,
+     -472,  -456,  -504,  -488,  -408,  -392,  -440,  -424,
+     -88,   -72,   -120,  -104,  -24,   -8,    -56,   -40,
+     -216,  -200,  -248,  -232,  -152,  -136,  -184,  -168,
+     -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184,
+     -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696,
+     -688,  -656,  -752,  -720,  -560,  -528,  -624,  -592,
+     -944,  -912,  -1008, -976,  -816,  -784,  -880,  -848,
+      5504,  5248,  6016,  5760,  4480,  4224,  4992,  4736,
+      7552,  7296,  8064,  7808,  6528,  6272,  7040,  6784,
+      2752,  2624,  3008,  2880,  2240,  2112,  2496,  2368,
+      3776,  3648,  4032,  3904,  3264,  3136,  3520,  3392,
+      22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944,
+      30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136,
+      11008, 10496, 12032, 11520, 8960,  8448,  9984,  9472,
+      15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568,
+      344,   328,   376,   360,   280,   264,   312,   296,
+      472,   456,   504,   488,   408,   392,   440,   424,
+      88,    72,   120,   104,    24,     8,    56,    40,
+      216,   200,   248,   232,   152,   136,   184,   168,
+      1376,  1312,  1504,  1440,  1120,  1056,  1248,  1184,
+      1888,  1824,  2016,  1952,  1632,  1568,  1760,  1696,
+      688,   656,   752,   720,   560,   528,   624,   592,
+      944,   912,  1008,   976,   816,   784,   880,   848
+};
+
+static void cs_reset (void *opaque)
+{
+    CSState *s = opaque;
+
+    s->regs[Index_Address] = 0x40;
+    s->regs[Index_Data]    = 0x00;
+    s->regs[Status]        = 0x00;
+    s->regs[PIO_Data]      = 0x00;
+
+    s->dregs[Left_ADC_Input_Control]          = 0x00;
+    s->dregs[Right_ADC_Input_Control]         = 0x00;
+    s->dregs[Left_AUX1_Input_Control]         = 0x88;
+    s->dregs[Right_AUX1_Input_Control]        = 0x88;
+    s->dregs[Left_AUX2_Input_Control]         = 0x88;
+    s->dregs[Right_AUX2_Input_Control]        = 0x88;
+    s->dregs[Left_DAC_Output_Control]         = 0x80;
+    s->dregs[Right_DAC_Output_Control]        = 0x80;
+    s->dregs[FS_And_Playback_Data_Format]     = 0x00;
+    s->dregs[Interface_Configuration]         = 0x08;
+    s->dregs[Pin_Control]                     = 0x00;
+    s->dregs[Error_Status_And_Initialization] = 0x00;
+    s->dregs[MODE_And_ID]                     = 0x8a;
+    s->dregs[Loopback_Control]                = 0x00;
+    s->dregs[Playback_Upper_Base_Count]       = 0x00;
+    s->dregs[Playback_Lower_Base_Count]       = 0x00;
+    s->dregs[Alternate_Feature_Enable_I]      = 0x00;
+    s->dregs[Alternate_Feature_Enable_II]     = 0x00;
+    s->dregs[Left_Line_Input_Control]         = 0x88;
+    s->dregs[Right_Line_Input_Control]        = 0x88;
+    s->dregs[Timer_Low_Base]                  = 0x00;
+    s->dregs[Timer_High_Base]                 = 0x00;
+    s->dregs[RESERVED]                        = 0x00;
+    s->dregs[Alternate_Feature_Enable_III]    = 0x00;
+    s->dregs[Alternate_Feature_Status]        = 0x00;
+    s->dregs[Version_Chip_ID]                 = 0xa0;
+    s->dregs[Mono_Input_And_Output_Control]   = 0xa0;
+    s->dregs[RESERVED_2]                      = 0x00;
+    s->dregs[Capture_Data_Format]             = 0x00;
+    s->dregs[RESERVED_3]                      = 0x00;
+    s->dregs[Capture_Upper_Base_Count]        = 0x00;
+    s->dregs[Capture_Lower_Base_Count]        = 0x00;
+}
+
+static void cs_audio_callback (void *opaque, int free)
+{
+    CSState *s = opaque;
+    s->audio_free = free;
+}
+
+static void cs_reset_voices (CSState *s, uint32_t val)
+{
+    int xtal;
+    struct audsettings as;
+
+#ifdef DEBUG_XLAW
+    if (val == 0 || val == 32)
+        val = (1 << 4) | (1 << 5);
+#endif
+
+    xtal = val & 1;
+    as.freq = freqs[xtal][(val >> 1) & 7];
+
+    if (as.freq == -1) {
+        lerr ("unsupported frequency (val=%#x)\n", val);
+        goto error;
+    }
+
+    as.nchannels = (val & (1 << 4)) ? 2 : 1;
+    as.endianness = 0;
+    s->tab = NULL;
+
+    switch ((val >> 5) & ((s->dregs[MODE_And_ID] & MODE2) ? 7 : 3)) {
+    case 0:
+        as.fmt = AUD_FMT_U8;
+        s->shift = as.nchannels == 2;
+        break;
+
+    case 1:
+        s->tab = MuLawDecompressTable;
+        goto x_law;
+    case 3:
+        s->tab = ALawDecompressTable;
+    x_law:
+        as.fmt = AUD_FMT_S16;
+        as.endianness = AUDIO_HOST_ENDIANNESS;
+        s->shift = as.nchannels == 2;
+        break;
+
+    case 6:
+        as.endianness = 1;
+    case 2:
+        as.fmt = AUD_FMT_S16;
+        s->shift = as.nchannels;
+        break;
+
+    case 7:
+    case 4:
+        lerr ("attempt to use reserved format value (%#x)\n", val);
+        goto error;
+
+    case 5:
+        lerr ("ADPCM 4 bit IMA compatible format is not supported\n");
+        goto error;
+    }
+
+    s->voice = AUD_open_out (
+        &s->card,
+        s->voice,
+        "cs4231a",
+        s,
+        cs_audio_callback,
+        &as
+        );
+
+    if (s->dregs[Interface_Configuration] & PEN) {
+        if (!s->dma_running) {
+            DMA_hold_DREQ (s->dma);
+            AUD_set_active_out (s->voice, 1);
+            s->transferred = 0;
+        }
+        s->dma_running = 1;
+    }
+    else {
+        if (s->dma_running) {
+            DMA_release_DREQ (s->dma);
+            AUD_set_active_out (s->voice, 0);
+        }
+        s->dma_running = 0;
+    }
+    return;
+
+ error:
+    if (s->dma_running) {
+        DMA_release_DREQ (s->dma);
+        AUD_set_active_out (s->voice, 0);
+    }
+}
+
+static uint64_t cs_read (void *opaque, hwaddr addr, unsigned size)
+{
+    CSState *s = opaque;
+    uint32_t saddr, iaddr, ret;
+
+    saddr = addr;
+    iaddr = ~0U;
+
+    switch (saddr) {
+    case Index_Address:
+        ret = s->regs[saddr] & ~0x80;
+        break;
+
+    case Index_Data:
+        if (!(s->dregs[MODE_And_ID] & MODE2))
+            iaddr = s->regs[Index_Address] & 0x0f;
+        else
+            iaddr = s->regs[Index_Address] & 0x1f;
+
+        ret = s->dregs[iaddr];
+        if (iaddr == Error_Status_And_Initialization) {
+            /* keep SEAL happy */
+            if (s->aci_counter) {
+                ret |= 1 << 5;
+                s->aci_counter -= 1;
+            }
+        }
+        break;
+
+    default:
+        ret = s->regs[saddr];
+        break;
+    }
+    dolog ("read %d:%d -> %d\n", saddr, iaddr, ret);
+    return ret;
+}
+
+static void cs_write (void *opaque, hwaddr addr,
+                      uint64_t val64, unsigned size)
+{
+    CSState *s = opaque;
+    uint32_t saddr, iaddr, val;
+
+    saddr = addr;
+    val = val64;
+
+    switch (saddr) {
+    case Index_Address:
+        if (!(s->regs[Index_Address] & MCE) && (val & MCE)
+            && (s->dregs[Interface_Configuration] & (3 << 3)))
+            s->aci_counter = conf.aci_counter;
+
+        s->regs[Index_Address] = val & ~(1 << 7);
+        break;
+
+    case Index_Data:
+        if (!(s->dregs[MODE_And_ID] & MODE2))
+            iaddr = s->regs[Index_Address] & 0x0f;
+        else
+            iaddr = s->regs[Index_Address] & 0x1f;
+
+        switch (iaddr) {
+        case RESERVED:
+        case RESERVED_2:
+        case RESERVED_3:
+            lwarn ("attempt to write %#x to reserved indirect register %d\n",
+                   val, iaddr);
+            break;
+
+        case FS_And_Playback_Data_Format:
+            if (s->regs[Index_Address] & MCE) {
+                cs_reset_voices (s, val);
+            }
+            else {
+                if (s->dregs[Alternate_Feature_Status] & PMCE) {
+                    val = (val & ~0x0f) | (s->dregs[iaddr] & 0x0f);
+                    cs_reset_voices (s, val);
+                }
+                else {
+                    lwarn ("[P]MCE(%#x, %#x) is not set, val=%#x\n",
+                           s->regs[Index_Address],
+                           s->dregs[Alternate_Feature_Status],
+                           val);
+                    break;
+                }
+            }
+            s->dregs[iaddr] = val;
+            break;
+
+        case Interface_Configuration:
+            val &= ~(1 << 5);   /* D5 is reserved */
+            s->dregs[iaddr] = val;
+            if (val & PPIO) {
+                lwarn ("PIO is not supported (%#x)\n", val);
+                break;
+            }
+            if (val & PEN) {
+                if (!s->dma_running) {
+                    cs_reset_voices (s, s->dregs[FS_And_Playback_Data_Format]);
+                }
+            }
+            else {
+                if (s->dma_running) {
+                    DMA_release_DREQ (s->dma);
+                    AUD_set_active_out (s->voice, 0);
+                    s->dma_running = 0;
+                }
+            }
+            break;
+
+        case Error_Status_And_Initialization:
+            lwarn ("attempt to write to read only register %d\n", iaddr);
+            break;
+
+        case MODE_And_ID:
+            dolog ("val=%#x\n", val);
+            if (val & MODE2)
+                s->dregs[iaddr] |= MODE2;
+            else
+                s->dregs[iaddr] &= ~MODE2;
+            break;
+
+        case Alternate_Feature_Enable_I:
+            if (val & TE)
+                lerr ("timer is not yet supported\n");
+            s->dregs[iaddr] = val;
+            break;
+
+        case Alternate_Feature_Status:
+            if ((s->dregs[iaddr] & PI) && !(val & PI)) {
+                /* XXX: TI CI */
+                qemu_irq_lower (s->pic);
+                s->regs[Status] &= ~INT;
+            }
+            s->dregs[iaddr] = val;
+            break;
+
+        case Version_Chip_ID:
+            lwarn ("write to Version_Chip_ID register %#x\n", val);
+            s->dregs[iaddr] = val;
+            break;
+
+        default:
+            s->dregs[iaddr] = val;
+            break;
+        }
+        dolog ("written value %#x to indirect register %d\n", val, iaddr);
+        break;
+
+    case Status:
+        if (s->regs[Status] & INT) {
+            qemu_irq_lower (s->pic);
+        }
+        s->regs[Status] &= ~INT;
+        s->dregs[Alternate_Feature_Status] &= ~(PI | CI | TI);
+        break;
+
+    case PIO_Data:
+        lwarn ("attempt to write value %#x to PIO register\n", val);
+        break;
+    }
+}
+
+static int cs_write_audio (CSState *s, int nchan, int dma_pos,
+                           int dma_len, int len)
+{
+    int temp, net;
+    uint8_t tmpbuf[4096];
+
+    temp = len;
+    net = 0;
+
+    while (temp) {
+        int left = dma_len - dma_pos;
+        int copied;
+        size_t to_copy;
+
+        to_copy = audio_MIN (temp, left);
+        if (to_copy > sizeof (tmpbuf)) {
+            to_copy = sizeof (tmpbuf);
+        }
+
+        copied = DMA_read_memory (nchan, tmpbuf, dma_pos, to_copy);
+        if (s->tab) {
+            int i;
+            int16_t linbuf[4096];
+
+            for (i = 0; i < copied; ++i)
+                linbuf[i] = s->tab[tmpbuf[i]];
+            copied = AUD_write (s->voice, linbuf, copied << 1);
+            copied >>= 1;
+        }
+        else {
+            copied = AUD_write (s->voice, tmpbuf, copied);
+        }
+
+        temp -= copied;
+        dma_pos = (dma_pos + copied) % dma_len;
+        net += copied;
+
+        if (!copied) {
+            break;
+        }
+    }
+
+    return net;
+}
+
+static int cs_dma_read (void *opaque, int nchan, int dma_pos, int dma_len)
+{
+    CSState *s = opaque;
+    int copy, written;
+    int till = -1;
+
+    copy = s->voice ? (s->audio_free >> (s->tab != NULL)) : dma_len;
+
+    if (s->dregs[Pin_Control] & IEN) {
+        till = (s->dregs[Playback_Lower_Base_Count]
+            | (s->dregs[Playback_Upper_Base_Count] << 8)) << s->shift;
+        till -= s->transferred;
+        copy = audio_MIN (till, copy);
+    }
+
+    if ((copy <= 0) || (dma_len <= 0)) {
+        return dma_pos;
+    }
+
+    written = cs_write_audio (s, nchan, dma_pos, dma_len, copy);
+
+    dma_pos = (dma_pos + written) % dma_len;
+    s->audio_free -= (written << (s->tab != NULL));
+
+    if (written == till) {
+        s->regs[Status] |= INT;
+        s->dregs[Alternate_Feature_Status] |= PI;
+        s->transferred = 0;
+        qemu_irq_raise (s->pic);
+    }
+    else {
+        s->transferred += written;
+    }
+
+    return dma_pos;
+}
+
+static int cs4231a_pre_load (void *opaque)
+{
+    CSState *s = opaque;
+
+    if (s->dma_running) {
+        DMA_release_DREQ (s->dma);
+        AUD_set_active_out (s->voice, 0);
+    }
+    s->dma_running = 0;
+    return 0;
+}
+
+static int cs4231a_post_load (void *opaque, int version_id)
+{
+    CSState *s = opaque;
+
+    if (s->dma_running && (s->dregs[Interface_Configuration] & PEN)) {
+        s->dma_running = 0;
+        cs_reset_voices (s, s->dregs[FS_And_Playback_Data_Format]);
+    }
+    return 0;
+}
+
+static const VMStateDescription vmstate_cs4231a = {
+    .name = "cs4231a",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .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 ()
+    }
+};
+
+static const MemoryRegionOps cs_ioport_ops = {
+    .read = cs_read,
+    .write = cs_write,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    }
+};
+
+static int cs4231a_initfn (ISADevice *dev)
+{
+    CSState *s = DO_UPCAST (CSState, dev, dev);
+
+    isa_init_irq (dev, &s->pic, s->irq);
+
+    memory_region_init_io (&s->ioports, &cs_ioport_ops, s, "cs4231a", 4);
+    isa_register_ioport (dev, &s->ioports, s->port);
+
+    DMA_register_channel (s->dma, cs_dma_read, s);
+
+    qemu_register_reset (cs_reset, s);
+    cs_reset (s);
+
+    AUD_register_card ("cs4231a", &s->card);
+    return 0;
+}
+
+int cs4231a_init (ISABus *bus)
+{
+    isa_create_simple (bus, "cs4231a");
+    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 const TypeInfo cs4231a_info = {
+    .name          = "cs4231a",
+    .parent        = TYPE_ISA_DEVICE,
+    .instance_size = sizeof (CSState),
+    .class_init    = cs4231a_class_initfn,
+};
+
+static void cs4231a_register_types (void)
+{
+    type_register_static (&cs4231a_info);
+}
+
+type_init (cs4231a_register_types)
diff --git a/hw/audio/es1370.c b/hw/audio/es1370.c
new file mode 100644 (file)
index 0000000..9fe5708
--- /dev/null
@@ -0,0 +1,1089 @@
+/*
+ * QEMU ES1370 emulation
+ *
+ * Copyright (c) 2005 Vassili Karpov (malc)
+ *
+ * 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.
+ */
+
+/* #define DEBUG_ES1370 */
+/* #define VERBOSE_ES1370 */
+#define SILENT_ES1370
+
+#include "hw/hw.h"
+#include "hw/audio/audio.h"
+#include "audio/audio.h"
+#include "hw/pci/pci.h"
+#include "sysemu/dma.h"
+
+/* Missing stuff:
+   SCTRL_P[12](END|ST)INC
+   SCTRL_P1SCTRLD
+   SCTRL_P2DACSEN
+   CTRL_DAC_SYNC
+   MIDI
+   non looped mode
+   surely more
+*/
+
+/*
+  Following macros and samplerate array were copied verbatim from
+  Linux kernel 2.4.30: drivers/sound/es1370.c
+
+  Copyright (C) 1998-2001, 2003 Thomas Sailer (t.sailer@alumni.ethz.ch)
+*/
+
+/* Start blatant GPL violation */
+
+#define ES1370_REG_CONTROL        0x00
+#define ES1370_REG_STATUS         0x04
+#define ES1370_REG_UART_DATA      0x08
+#define ES1370_REG_UART_STATUS    0x09
+#define ES1370_REG_UART_CONTROL   0x09
+#define ES1370_REG_UART_TEST      0x0a
+#define ES1370_REG_MEMPAGE        0x0c
+#define ES1370_REG_CODEC          0x10
+#define ES1370_REG_SERIAL_CONTROL 0x20
+#define ES1370_REG_DAC1_SCOUNT    0x24
+#define ES1370_REG_DAC2_SCOUNT    0x28
+#define ES1370_REG_ADC_SCOUNT     0x2c
+
+#define ES1370_REG_DAC1_FRAMEADR    0xc30
+#define ES1370_REG_DAC1_FRAMECNT    0xc34
+#define ES1370_REG_DAC2_FRAMEADR    0xc38
+#define ES1370_REG_DAC2_FRAMECNT    0xc3c
+#define ES1370_REG_ADC_FRAMEADR     0xd30
+#define ES1370_REG_ADC_FRAMECNT     0xd34
+#define ES1370_REG_PHANTOM_FRAMEADR 0xd38
+#define ES1370_REG_PHANTOM_FRAMECNT 0xd3c
+
+static const unsigned dac1_samplerate[] = { 5512, 11025, 22050, 44100 };
+
+#define DAC2_SRTODIV(x) (((1411200+(x)/2)/(x))-2)
+#define DAC2_DIVTOSR(x) (1411200/((x)+2))
+
+#define CTRL_ADC_STOP   0x80000000  /* 1 = ADC stopped */
+#define CTRL_XCTL1      0x40000000  /* electret mic bias */
+#define CTRL_OPEN       0x20000000  /* no function, can be read and written */
+#define CTRL_PCLKDIV    0x1fff0000  /* ADC/DAC2 clock divider */
+#define CTRL_SH_PCLKDIV 16
+#define CTRL_MSFMTSEL   0x00008000  /* MPEG serial data fmt: 0 = Sony, 1 = I2S */
+#define CTRL_M_SBB      0x00004000  /* DAC2 clock: 0 = PCLKDIV, 1 = MPEG */
+#define CTRL_WTSRSEL    0x00003000  /* DAC1 clock freq: 0=5512, 1=11025, 2=22050, 3=44100 */
+#define CTRL_SH_WTSRSEL 12
+#define CTRL_DAC_SYNC   0x00000800  /* 1 = DAC2 runs off DAC1 clock */
+#define CTRL_CCB_INTRM  0x00000400  /* 1 = CCB "voice" ints enabled */
+#define CTRL_M_CB       0x00000200  /* recording source: 0 = ADC, 1 = MPEG */
+#define CTRL_XCTL0      0x00000100  /* 0 = Line in, 1 = Line out */
+#define CTRL_BREQ       0x00000080  /* 1 = test mode (internal mem test) */
+#define CTRL_DAC1_EN    0x00000040  /* enable DAC1 */
+#define CTRL_DAC2_EN    0x00000020  /* enable DAC2 */
+#define CTRL_ADC_EN     0x00000010  /* enable ADC */
+#define CTRL_UART_EN    0x00000008  /* enable MIDI uart */
+#define CTRL_JYSTK_EN   0x00000004  /* enable Joystick port (presumably at address 0x200) */
+#define CTRL_CDC_EN     0x00000002  /* enable serial (CODEC) interface */
+#define CTRL_SERR_DIS   0x00000001  /* 1 = disable PCI SERR signal */
+
+#define STAT_INTR       0x80000000  /* wired or of all interrupt bits */
+#define STAT_CSTAT      0x00000400  /* 1 = codec busy or codec write in progress */
+#define STAT_CBUSY      0x00000200  /* 1 = codec busy */
+#define STAT_CWRIP      0x00000100  /* 1 = codec write in progress */
+#define STAT_VC         0x00000060  /* CCB int source, 0=DAC1, 1=DAC2, 2=ADC, 3=undef */
+#define STAT_SH_VC      5
+#define STAT_MCCB       0x00000010  /* CCB int pending */
+#define STAT_UART       0x00000008  /* UART int pending */
+#define STAT_DAC1       0x00000004  /* DAC1 int pending */
+#define STAT_DAC2       0x00000002  /* DAC2 int pending */
+#define STAT_ADC        0x00000001  /* ADC int pending */
+
+#define USTAT_RXINT     0x80        /* UART rx int pending */
+#define USTAT_TXINT     0x04        /* UART tx int pending */
+#define USTAT_TXRDY     0x02        /* UART tx ready */
+#define USTAT_RXRDY     0x01        /* UART rx ready */
+
+#define UCTRL_RXINTEN   0x80        /* 1 = enable RX ints */
+#define UCTRL_TXINTEN   0x60        /* TX int enable field mask */
+#define UCTRL_ENA_TXINT 0x20        /* enable TX int */
+#define UCTRL_CNTRL     0x03        /* control field */
+#define UCTRL_CNTRL_SWR 0x03        /* software reset command */
+
+#define SCTRL_P2ENDINC    0x00380000  /*  */
+#define SCTRL_SH_P2ENDINC 19
+#define SCTRL_P2STINC     0x00070000  /*  */
+#define SCTRL_SH_P2STINC  16
+#define SCTRL_R1LOOPSEL   0x00008000  /* 0 = loop mode */
+#define SCTRL_P2LOOPSEL   0x00004000  /* 0 = loop mode */
+#define SCTRL_P1LOOPSEL   0x00002000  /* 0 = loop mode */
+#define SCTRL_P2PAUSE     0x00001000  /* 1 = pause mode */
+#define SCTRL_P1PAUSE     0x00000800  /* 1 = pause mode */
+#define SCTRL_R1INTEN     0x00000400  /* enable interrupt */
+#define SCTRL_P2INTEN     0x00000200  /* enable interrupt */
+#define SCTRL_P1INTEN     0x00000100  /* enable interrupt */
+#define SCTRL_P1SCTRLD    0x00000080  /* reload sample count register for DAC1 */
+#define SCTRL_P2DACSEN    0x00000040  /* 1 = DAC2 play back last sample when disabled */
+#define SCTRL_R1SEB       0x00000020  /* 1 = 16bit */
+#define SCTRL_R1SMB       0x00000010  /* 1 = stereo */
+#define SCTRL_R1FMT       0x00000030  /* format mask */
+#define SCTRL_SH_R1FMT    4
+#define SCTRL_P2SEB       0x00000008  /* 1 = 16bit */
+#define SCTRL_P2SMB       0x00000004  /* 1 = stereo */
+#define SCTRL_P2FMT       0x0000000c  /* format mask */
+#define SCTRL_SH_P2FMT    2
+#define SCTRL_P1SEB       0x00000002  /* 1 = 16bit */
+#define SCTRL_P1SMB       0x00000001  /* 1 = stereo */
+#define SCTRL_P1FMT       0x00000003  /* format mask */
+#define SCTRL_SH_P1FMT    0
+
+/* End blatant GPL violation */
+
+#define NB_CHANNELS 3
+#define DAC1_CHANNEL 0
+#define DAC2_CHANNEL 1
+#define ADC_CHANNEL 2
+
+#define IO_READ_PROTO(n) \
+static uint32_t n (void *opaque, uint32_t addr)
+#define IO_WRITE_PROTO(n) \
+static void n (void *opaque, uint32_t addr, uint32_t val)
+
+static void es1370_dac1_callback (void *opaque, int free);
+static void es1370_dac2_callback (void *opaque, int free);
+static void es1370_adc_callback (void *opaque, int avail);
+
+#ifdef DEBUG_ES1370
+
+#define ldebug(...) AUD_log ("es1370", __VA_ARGS__)
+
+static void print_ctl (uint32_t val)
+{
+    char buf[1024];
+
+    buf[0] = '\0';
+#define a(n) if (val & CTRL_##n) strcat (buf, " "#n)
+    a (ADC_STOP);
+    a (XCTL1);
+    a (OPEN);
+    a (MSFMTSEL);
+    a (M_SBB);
+    a (DAC_SYNC);
+    a (CCB_INTRM);
+    a (M_CB);
+    a (XCTL0);
+    a (BREQ);
+    a (DAC1_EN);
+    a (DAC2_EN);
+    a (ADC_EN);
+    a (UART_EN);
+    a (JYSTK_EN);
+    a (CDC_EN);
+    a (SERR_DIS);
+#undef a
+    AUD_log ("es1370", "ctl - PCLKDIV %d(DAC2 freq %d), freq %d,%s\n",
+             (val & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV,
+             DAC2_DIVTOSR ((val & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV),
+             dac1_samplerate[(val & CTRL_WTSRSEL) >> CTRL_SH_WTSRSEL],
+             buf);
+}
+
+static void print_sctl (uint32_t val)
+{
+    static const char *fmt_names[] = {"8M", "8S", "16M", "16S"};
+    char buf[1024];
+
+    buf[0] = '\0';
+
+#define a(n) if (val & SCTRL_##n) strcat (buf, " "#n)
+#define b(n) if (!(val & SCTRL_##n)) strcat (buf, " "#n)
+    b (R1LOOPSEL);
+    b (P2LOOPSEL);
+    b (P1LOOPSEL);
+    a (P2PAUSE);
+    a (P1PAUSE);
+    a (R1INTEN);
+    a (P2INTEN);
+    a (P1INTEN);
+    a (P1SCTRLD);
+    a (P2DACSEN);
+    if (buf[0]) {
+        strcat (buf, "\n        ");
+    }
+    else {
+        buf[0] = ' ';
+        buf[1] = '\0';
+    }
+#undef b
+#undef a
+    AUD_log ("es1370",
+             "%s"
+             "p2_end_inc %d, p2_st_inc %d, r1_fmt %s, p2_fmt %s, p1_fmt %s\n",
+             buf,
+             (val & SCTRL_P2ENDINC) >> SCTRL_SH_P2ENDINC,
+             (val & SCTRL_P2STINC) >> SCTRL_SH_P2STINC,
+             fmt_names [(val >> SCTRL_SH_R1FMT) & 3],
+             fmt_names [(val >> SCTRL_SH_P2FMT) & 3],
+             fmt_names [(val >> SCTRL_SH_P1FMT) & 3]
+        );
+}
+#else
+#define ldebug(...)
+#define print_ctl(...)
+#define print_sctl(...)
+#endif
+
+#ifdef VERBOSE_ES1370
+#define dolog(...) AUD_log ("es1370", __VA_ARGS__)
+#else
+#define dolog(...)
+#endif
+
+#ifndef SILENT_ES1370
+#define lwarn(...) AUD_log ("es1370: warning", __VA_ARGS__)
+#else
+#define lwarn(...)
+#endif
+
+struct chan {
+    uint32_t shift;
+    uint32_t leftover;
+    uint32_t scount;
+    uint32_t frame_addr;
+    uint32_t frame_cnt;
+};
+
+typedef struct ES1370State {
+    PCIDevice dev;
+    QEMUSoundCard card;
+    MemoryRegion io;
+    struct chan chan[NB_CHANNELS];
+    SWVoiceOut *dac_voice[2];
+    SWVoiceIn *adc_voice;
+
+    uint32_t ctl;
+    uint32_t status;
+    uint32_t mempage;
+    uint32_t codec;
+    uint32_t sctl;
+} ES1370State;
+
+struct chan_bits {
+    uint32_t ctl_en;
+    uint32_t stat_int;
+    uint32_t sctl_pause;
+    uint32_t sctl_inten;
+    uint32_t sctl_fmt;
+    uint32_t sctl_sh_fmt;
+    uint32_t sctl_loopsel;
+    void (*calc_freq) (ES1370State *s, uint32_t ctl,
+                       uint32_t *old_freq, uint32_t *new_freq);
+};
+
+static void es1370_dac1_calc_freq (ES1370State *s, uint32_t ctl,
+                                   uint32_t *old_freq, uint32_t *new_freq);
+static void es1370_dac2_and_adc_calc_freq (ES1370State *s, uint32_t ctl,
+                                           uint32_t *old_freq,
+                                           uint32_t *new_freq);
+
+static const struct chan_bits es1370_chan_bits[] = {
+    {CTRL_DAC1_EN, STAT_DAC1, SCTRL_P1PAUSE, SCTRL_P1INTEN,
+     SCTRL_P1FMT, SCTRL_SH_P1FMT, SCTRL_P1LOOPSEL,
+     es1370_dac1_calc_freq},
+
+    {CTRL_DAC2_EN, STAT_DAC2, SCTRL_P2PAUSE, SCTRL_P2INTEN,
+     SCTRL_P2FMT, SCTRL_SH_P2FMT, SCTRL_P2LOOPSEL,
+     es1370_dac2_and_adc_calc_freq},
+
+    {CTRL_ADC_EN, STAT_ADC, 0, SCTRL_R1INTEN,
+     SCTRL_R1FMT, SCTRL_SH_R1FMT, SCTRL_R1LOOPSEL,
+     es1370_dac2_and_adc_calc_freq}
+};
+
+static void es1370_update_status (ES1370State *s, uint32_t new_status)
+{
+    uint32_t level = new_status & (STAT_DAC1 | STAT_DAC2 | STAT_ADC);
+
+    if (level) {
+        s->status = new_status | STAT_INTR;
+    }
+    else {
+        s->status = new_status & ~STAT_INTR;
+    }
+    qemu_set_irq (s->dev.irq[0], !!level);
+}
+
+static void es1370_reset (ES1370State *s)
+{
+    size_t i;
+
+    s->ctl = 1;
+    s->status = 0x60;
+    s->mempage = 0;
+    s->codec = 0;
+    s->sctl = 0;
+
+    for (i = 0; i < NB_CHANNELS; ++i) {
+        struct chan *d = &s->chan[i];
+        d->scount = 0;
+        d->leftover = 0;
+        if (i == ADC_CHANNEL) {
+            AUD_close_in (&s->card, s->adc_voice);
+            s->adc_voice = NULL;
+        }
+        else {
+            AUD_close_out (&s->card, s->dac_voice[i]);
+            s->dac_voice[i] = NULL;
+        }
+    }
+    qemu_irq_lower (s->dev.irq[0]);
+}
+
+static void es1370_maybe_lower_irq (ES1370State *s, uint32_t sctl)
+{
+    uint32_t new_status = s->status;
+
+    if (!(sctl & SCTRL_P1INTEN) && (s->sctl & SCTRL_P1INTEN)) {
+        new_status &= ~STAT_DAC1;
+    }
+
+    if (!(sctl & SCTRL_P2INTEN) && (s->sctl & SCTRL_P2INTEN)) {
+        new_status &= ~STAT_DAC2;
+    }
+
+    if (!(sctl & SCTRL_R1INTEN) && (s->sctl & SCTRL_R1INTEN)) {
+        new_status &= ~STAT_ADC;
+    }
+
+    if (new_status != s->status) {
+        es1370_update_status (s, new_status);
+    }
+}
+
+static void es1370_dac1_calc_freq (ES1370State *s, uint32_t ctl,
+                                   uint32_t *old_freq, uint32_t *new_freq)
+
+{
+    *old_freq = dac1_samplerate[(s->ctl & CTRL_WTSRSEL) >> CTRL_SH_WTSRSEL];
+    *new_freq = dac1_samplerate[(ctl & CTRL_WTSRSEL) >> CTRL_SH_WTSRSEL];
+}
+
+static void es1370_dac2_and_adc_calc_freq (ES1370State *s, uint32_t ctl,
+                                           uint32_t *old_freq,
+                                           uint32_t *new_freq)
+
+{
+    uint32_t old_pclkdiv, new_pclkdiv;
+
+    new_pclkdiv = (ctl & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV;
+    old_pclkdiv = (s->ctl & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV;
+    *new_freq = DAC2_DIVTOSR (new_pclkdiv);
+    *old_freq = DAC2_DIVTOSR (old_pclkdiv);
+}
+
+static void es1370_update_voices (ES1370State *s, uint32_t ctl, uint32_t sctl)
+{
+    size_t i;
+    uint32_t old_freq, new_freq, old_fmt, new_fmt;
+
+    for (i = 0; i < NB_CHANNELS; ++i) {
+        struct chan *d = &s->chan[i];
+        const struct chan_bits *b = &es1370_chan_bits[i];
+
+        new_fmt = (sctl & b->sctl_fmt) >> b->sctl_sh_fmt;
+        old_fmt = (s->sctl & b->sctl_fmt) >> b->sctl_sh_fmt;
+
+        b->calc_freq (s, ctl, &old_freq, &new_freq);
+
+        if ((old_fmt != new_fmt) || (old_freq != new_freq)) {
+            d->shift = (new_fmt & 1) + (new_fmt >> 1);
+            ldebug ("channel %zu, freq = %d, nchannels %d, fmt %d, shift %d\n",
+                    i,
+                    new_freq,
+                    1 << (new_fmt & 1),
+                    (new_fmt & 2) ? AUD_FMT_S16 : AUD_FMT_U8,
+                    d->shift);
+            if (new_freq) {
+                struct audsettings as;
+
+                as.freq = new_freq;
+                as.nchannels = 1 << (new_fmt & 1);
+                as.fmt = (new_fmt & 2) ? AUD_FMT_S16 : AUD_FMT_U8;
+                as.endianness = 0;
+
+                if (i == ADC_CHANNEL) {
+                    s->adc_voice =
+                        AUD_open_in (
+                            &s->card,
+                            s->adc_voice,
+                            "es1370.adc",
+                            s,
+                            es1370_adc_callback,
+                            &as
+                            );
+                }
+                else {
+                    s->dac_voice[i] =
+                        AUD_open_out (
+                            &s->card,
+                            s->dac_voice[i],
+                            i ? "es1370.dac2" : "es1370.dac1",
+                            s,
+                            i ? es1370_dac2_callback : es1370_dac1_callback,
+                            &as
+                            );
+                }
+            }
+        }
+
+        if (((ctl ^ s->ctl) & b->ctl_en)
+            || ((sctl ^ s->sctl) & b->sctl_pause)) {
+            int on = (ctl & b->ctl_en) && !(sctl & b->sctl_pause);
+
+            if (i == ADC_CHANNEL) {
+                AUD_set_active_in (s->adc_voice, on);
+            }
+            else {
+                AUD_set_active_out (s->dac_voice[i], on);
+            }
+        }
+    }
+
+    s->ctl = ctl;
+    s->sctl = sctl;
+}
+
+static inline uint32_t es1370_fixup (ES1370State *s, uint32_t addr)
+{
+    addr &= 0xff;
+    if (addr >= 0x30 && addr <= 0x3f)
+        addr |= s->mempage << 8;
+    return addr;
+}
+
+IO_WRITE_PROTO (es1370_writeb)
+{
+    ES1370State *s = opaque;
+    uint32_t shift, mask;
+
+    addr = es1370_fixup (s, addr);
+
+    switch (addr) {
+    case ES1370_REG_CONTROL:
+    case ES1370_REG_CONTROL + 1:
+    case ES1370_REG_CONTROL + 2:
+    case ES1370_REG_CONTROL + 3:
+        shift = (addr - ES1370_REG_CONTROL) << 3;
+        mask = 0xff << shift;
+        val = (s->ctl & ~mask) | ((val & 0xff) << shift);
+        es1370_update_voices (s, val, s->sctl);
+        print_ctl (val);
+        break;
+    case ES1370_REG_MEMPAGE:
+        s->mempage = val;
+        break;
+    case ES1370_REG_SERIAL_CONTROL:
+    case ES1370_REG_SERIAL_CONTROL + 1:
+    case ES1370_REG_SERIAL_CONTROL + 2:
+    case ES1370_REG_SERIAL_CONTROL + 3:
+        shift = (addr - ES1370_REG_SERIAL_CONTROL) << 3;
+        mask = 0xff << shift;
+        val = (s->sctl & ~mask) | ((val & 0xff) << shift);
+        es1370_maybe_lower_irq (s, val);
+        es1370_update_voices (s, s->ctl, val);
+        print_sctl (val);
+        break;
+    default:
+        lwarn ("writeb %#x <- %#x\n", addr, val);
+        break;
+    }
+}
+
+IO_WRITE_PROTO (es1370_writew)
+{
+    ES1370State *s = opaque;
+    addr = es1370_fixup (s, addr);
+    uint32_t shift, mask;
+    struct chan *d = &s->chan[0];
+
+    switch (addr) {
+    case ES1370_REG_CODEC:
+        dolog ("ignored codec write address %#x, data %#x\n",
+               (val >> 8) & 0xff, val & 0xff);
+        s->codec = val;
+        break;
+
+    case ES1370_REG_CONTROL:
+    case ES1370_REG_CONTROL + 2:
+        shift = (addr != ES1370_REG_CONTROL) << 4;
+        mask = 0xffff << shift;
+        val = (s->ctl & ~mask) | ((val & 0xffff) << shift);
+        es1370_update_voices (s, val, s->sctl);
+        print_ctl (val);
+        break;
+
+    case ES1370_REG_ADC_SCOUNT:
+        d++;
+    case ES1370_REG_DAC2_SCOUNT:
+        d++;
+    case ES1370_REG_DAC1_SCOUNT:
+        d->scount = (d->scount & ~0xffff) | (val & 0xffff);
+        break;
+
+    default:
+        lwarn ("writew %#x <- %#x\n", addr, val);
+        break;
+    }
+}
+
+IO_WRITE_PROTO (es1370_writel)
+{
+    ES1370State *s = opaque;
+    struct chan *d = &s->chan[0];
+
+    addr = es1370_fixup (s, addr);
+
+    switch (addr) {
+    case ES1370_REG_CONTROL:
+        es1370_update_voices (s, val, s->sctl);
+        print_ctl (val);
+        break;
+
+    case ES1370_REG_MEMPAGE:
+        s->mempage = val & 0xf;
+        break;
+
+    case ES1370_REG_SERIAL_CONTROL:
+        es1370_maybe_lower_irq (s, val);
+        es1370_update_voices (s, s->ctl, val);
+        print_sctl (val);
+        break;
+
+    case ES1370_REG_ADC_SCOUNT:
+        d++;
+    case ES1370_REG_DAC2_SCOUNT:
+        d++;
+    case ES1370_REG_DAC1_SCOUNT:
+        d->scount = (val & 0xffff) | (d->scount & ~0xffff);
+        ldebug ("chan %td CURR_SAMP_CT %d, SAMP_CT %d\n",
+                d - &s->chan[0], val >> 16, (val & 0xffff));
+        break;
+
+    case ES1370_REG_ADC_FRAMEADR:
+        d++;
+    case ES1370_REG_DAC2_FRAMEADR:
+        d++;
+    case ES1370_REG_DAC1_FRAMEADR:
+        d->frame_addr = val;
+        ldebug ("chan %td frame address %#x\n", d - &s->chan[0], val);
+        break;
+
+    case ES1370_REG_PHANTOM_FRAMECNT:
+        lwarn ("writing to phantom frame count %#x\n", val);
+        break;
+    case ES1370_REG_PHANTOM_FRAMEADR:
+        lwarn ("writing to phantom frame address %#x\n", val);
+        break;
+
+    case ES1370_REG_ADC_FRAMECNT:
+        d++;
+    case ES1370_REG_DAC2_FRAMECNT:
+        d++;
+    case ES1370_REG_DAC1_FRAMECNT:
+        d->frame_cnt = val;
+        d->leftover = 0;
+        ldebug ("chan %td frame count %d, buffer size %d\n",
+                d - &s->chan[0], val >> 16, val & 0xffff);
+        break;
+
+    default:
+        lwarn ("writel %#x <- %#x\n", addr, val);
+        break;
+    }
+}
+
+IO_READ_PROTO (es1370_readb)
+{
+    ES1370State *s = opaque;
+    uint32_t val;
+
+    addr = es1370_fixup (s, addr);
+
+    switch (addr) {
+    case 0x1b:                  /* Legacy */
+        lwarn ("Attempt to read from legacy register\n");
+        val = 5;
+        break;
+    case ES1370_REG_MEMPAGE:
+        val = s->mempage;
+        break;
+    case ES1370_REG_CONTROL + 0:
+    case ES1370_REG_CONTROL + 1:
+    case ES1370_REG_CONTROL + 2:
+    case ES1370_REG_CONTROL + 3:
+        val = s->ctl >> ((addr - ES1370_REG_CONTROL) << 3);
+        break;
+    case ES1370_REG_STATUS + 0:
+    case ES1370_REG_STATUS + 1:
+    case ES1370_REG_STATUS + 2:
+    case ES1370_REG_STATUS + 3:
+        val = s->status >> ((addr - ES1370_REG_STATUS) << 3);
+        break;
+    default:
+        val = ~0;
+        lwarn ("readb %#x -> %#x\n", addr, val);
+        break;
+    }
+    return val;
+}
+
+IO_READ_PROTO (es1370_readw)
+{
+    ES1370State *s = opaque;
+    struct chan *d = &s->chan[0];
+    uint32_t val;
+
+    addr = es1370_fixup (s, addr);
+
+    switch (addr) {
+    case ES1370_REG_ADC_SCOUNT + 2:
+        d++;
+    case ES1370_REG_DAC2_SCOUNT + 2:
+        d++;
+    case ES1370_REG_DAC1_SCOUNT + 2:
+        val = d->scount >> 16;
+        break;
+
+    case ES1370_REG_ADC_FRAMECNT:
+        d++;
+    case ES1370_REG_DAC2_FRAMECNT:
+        d++;
+    case ES1370_REG_DAC1_FRAMECNT:
+        val = d->frame_cnt & 0xffff;
+        break;
+
+    case ES1370_REG_ADC_FRAMECNT + 2:
+        d++;
+    case ES1370_REG_DAC2_FRAMECNT + 2:
+        d++;
+    case ES1370_REG_DAC1_FRAMECNT + 2:
+        val = d->frame_cnt >> 16;
+        break;
+
+    default:
+        val = ~0;
+        lwarn ("readw %#x -> %#x\n", addr, val);
+        break;
+    }
+
+    return val;
+}
+
+IO_READ_PROTO (es1370_readl)
+{
+    ES1370State *s = opaque;
+    uint32_t val;
+    struct chan *d = &s->chan[0];
+
+    addr = es1370_fixup (s, addr);
+
+    switch (addr) {
+    case ES1370_REG_CONTROL:
+        val = s->ctl;
+        break;
+    case ES1370_REG_STATUS:
+        val = s->status;
+        break;
+    case ES1370_REG_MEMPAGE:
+        val = s->mempage;
+        break;
+    case ES1370_REG_CODEC:
+        val = s->codec;
+        break;
+    case ES1370_REG_SERIAL_CONTROL:
+        val = s->sctl;
+        break;
+
+    case ES1370_REG_ADC_SCOUNT:
+        d++;
+    case ES1370_REG_DAC2_SCOUNT:
+        d++;
+    case ES1370_REG_DAC1_SCOUNT:
+        val = d->scount;
+#ifdef DEBUG_ES1370
+        {
+            uint32_t curr_count = d->scount >> 16;
+            uint32_t count = d->scount & 0xffff;
+
+            curr_count <<= d->shift;
+            count <<= d->shift;
+            dolog ("read scount curr %d, total %d\n", curr_count, count);
+        }
+#endif
+        break;
+
+    case ES1370_REG_ADC_FRAMECNT:
+        d++;
+    case ES1370_REG_DAC2_FRAMECNT:
+        d++;
+    case ES1370_REG_DAC1_FRAMECNT:
+        val = d->frame_cnt;
+#ifdef DEBUG_ES1370
+        {
+            uint32_t size = ((d->frame_cnt & 0xffff) + 1) << 2;
+            uint32_t curr = ((d->frame_cnt >> 16) + 1) << 2;
+            if (curr > size) {
+                dolog ("read framecnt curr %d, size %d %d\n", curr, size,
+                       curr > size);
+            }
+        }
+#endif
+        break;
+
+    case ES1370_REG_ADC_FRAMEADR:
+        d++;
+    case ES1370_REG_DAC2_FRAMEADR:
+        d++;
+    case ES1370_REG_DAC1_FRAMEADR:
+        val = d->frame_addr;
+        break;
+
+    case ES1370_REG_PHANTOM_FRAMECNT:
+        val = ~0U;
+        lwarn ("reading from phantom frame count\n");
+        break;
+    case ES1370_REG_PHANTOM_FRAMEADR:
+        val = ~0U;
+        lwarn ("reading from phantom frame address\n");
+        break;
+
+    default:
+        val = ~0U;
+        lwarn ("readl %#x -> %#x\n", addr, val);
+        break;
+    }
+    return val;
+}
+
+static void es1370_transfer_audio (ES1370State *s, struct chan *d, int loop_sel,
+                                   int max, int *irq)
+{
+    uint8_t tmpbuf[4096];
+    uint32_t addr = d->frame_addr;
+    int sc = d->scount & 0xffff;
+    int csc = d->scount >> 16;
+    int csc_bytes = (csc + 1) << d->shift;
+    int cnt = d->frame_cnt >> 16;
+    int size = d->frame_cnt & 0xffff;
+    int left = ((size - cnt + 1) << 2) + d->leftover;
+    int transferred = 0;
+    int temp = audio_MIN (max, audio_MIN (left, csc_bytes));
+    int index = d - &s->chan[0];
+
+    addr += (cnt << 2) + d->leftover;
+
+    if (index == ADC_CHANNEL) {
+        while (temp) {
+            int acquired, to_copy;
+
+            to_copy = audio_MIN ((size_t) temp, sizeof (tmpbuf));
+            acquired = AUD_read (s->adc_voice, tmpbuf, to_copy);
+            if (!acquired)
+                break;
+
+            pci_dma_write (&s->dev, addr, tmpbuf, acquired);
+
+            temp -= acquired;
+            addr += acquired;
+            transferred += acquired;
+        }
+    }
+    else {
+        SWVoiceOut *voice = s->dac_voice[index];
+
+        while (temp) {
+            int copied, to_copy;
+
+            to_copy = audio_MIN ((size_t) temp, sizeof (tmpbuf));
+            pci_dma_read (&s->dev, addr, tmpbuf, to_copy);
+            copied = AUD_write (voice, tmpbuf, to_copy);
+            if (!copied)
+                break;
+            temp -= copied;
+            addr += copied;
+            transferred += copied;
+        }
+    }
+
+    if (csc_bytes == transferred) {
+        *irq = 1;
+        d->scount = sc | (sc << 16);
+        ldebug ("sc = %d, rate = %f\n",
+                (sc + 1) << d->shift,
+                (sc + 1) / (double) 44100);
+    }
+    else {
+        *irq = 0;
+        d->scount = sc | (((csc_bytes - transferred - 1) >> d->shift) << 16);
+    }
+
+    cnt += (transferred + d->leftover) >> 2;
+
+    if (s->sctl & loop_sel) {
+        /* Bah, how stupid is that having a 0 represent true value?
+           i just spent few hours on this shit */
+        AUD_log ("es1370: warning", "non looping mode\n");
+    }
+    else {
+        d->frame_cnt = size;
+
+        if ((uint32_t) cnt <= d->frame_cnt)
+            d->frame_cnt |= cnt << 16;
+    }
+
+    d->leftover = (transferred + d->leftover) & 3;
+}
+
+static void es1370_run_channel (ES1370State *s, size_t chan, int free_or_avail)
+{
+    uint32_t new_status = s->status;
+    int max_bytes, irq;
+    struct chan *d = &s->chan[chan];
+    const struct chan_bits *b = &es1370_chan_bits[chan];
+
+    if (!(s->ctl & b->ctl_en) || (s->sctl & b->sctl_pause)) {
+        return;
+    }
+
+    max_bytes = free_or_avail;
+    max_bytes &= ~((1 << d->shift) - 1);
+    if (!max_bytes) {
+        return;
+    }
+
+    es1370_transfer_audio (s, d, b->sctl_loopsel, max_bytes, &irq);
+
+    if (irq) {
+        if (s->sctl & b->sctl_inten) {
+            new_status |= b->stat_int;
+        }
+    }
+
+    if (new_status != s->status) {
+        es1370_update_status (s, new_status);
+    }
+}
+
+static void es1370_dac1_callback (void *opaque, int free)
+{
+    ES1370State *s = opaque;
+
+    es1370_run_channel (s, DAC1_CHANNEL, free);
+}
+
+static void es1370_dac2_callback (void *opaque, int free)
+{
+    ES1370State *s = opaque;
+
+    es1370_run_channel (s, DAC2_CHANNEL, free);
+}
+
+static void es1370_adc_callback (void *opaque, int avail)
+{
+    ES1370State *s = opaque;
+
+    es1370_run_channel (s, ADC_CHANNEL, avail);
+}
+
+static uint64_t es1370_read(void *opaque, hwaddr addr,
+                            unsigned size)
+{
+    switch (size) {
+    case 1:
+        return es1370_readb(opaque, addr);
+    case 2:
+        return es1370_readw(opaque, addr);
+    case 4:
+        return es1370_readl(opaque, addr);
+    default:
+        return -1;
+    }
+}
+
+static void es1370_write(void *opaque, hwaddr addr, uint64_t val,
+                      unsigned size)
+{
+    switch (size) {
+    case 1:
+        es1370_writeb(opaque, addr, val);
+        break;
+    case 2:
+        es1370_writew(opaque, addr, val);
+        break;
+    case 4:
+        es1370_writel(opaque, addr, val);
+        break;
+    }
+}
+
+static const MemoryRegionOps es1370_io_ops = {
+    .read = es1370_read,
+    .write = es1370_write,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 4,
+    },
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static const VMStateDescription vmstate_es1370_channel = {
+    .name = "es1370_channel",
+    .version_id = 2,
+    .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 ()
+    }
+};
+
+static int es1370_post_load (void *opaque, int version_id)
+{
+    uint32_t ctl, sctl;
+    ES1370State *s = opaque;
+    size_t i;
+
+    for (i = 0; i < NB_CHANNELS; ++i) {
+        if (i == ADC_CHANNEL) {
+            if (s->adc_voice) {
+                AUD_close_in (&s->card, s->adc_voice);
+                s->adc_voice = NULL;
+            }
+        }
+        else {
+            if (s->dac_voice[i]) {
+                AUD_close_out (&s->card, s->dac_voice[i]);
+                s->dac_voice[i] = NULL;
+            }
+        }
+    }
+
+    ctl = s->ctl;
+    sctl = s->sctl;
+    s->ctl = 0;
+    s->sctl = 0;
+    es1370_update_voices (s, ctl, sctl);
+    return 0;
+}
+
+static const VMStateDescription vmstate_es1370 = {
+    .name = "es1370",
+    .version_id = 2,
+    .minimum_version_id = 2,
+    .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 ()
+    }
+};
+
+static void es1370_on_reset (void *opaque)
+{
+    ES1370State *s = opaque;
+    es1370_reset (s);
+}
+
+static int es1370_initfn (PCIDevice *dev)
+{
+    ES1370State *s = DO_UPCAST (ES1370State, dev, dev);
+    uint8_t *c = s->dev.config;
+
+    c[PCI_STATUS + 1] = PCI_STATUS_DEVSEL_SLOW >> 8;
+
+#if 0
+    c[PCI_CAPABILITY_LIST] = 0xdc;
+    c[PCI_INTERRUPT_LINE] = 10;
+    c[0xdc] = 0x00;
+#endif
+
+    c[PCI_INTERRUPT_PIN] = 1;
+    c[PCI_MIN_GNT] = 0x0c;
+    c[PCI_MAX_LAT] = 0x80;
+
+    memory_region_init_io (&s->io, &es1370_io_ops, s, "es1370", 256);
+    pci_register_bar (&s->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io);
+    qemu_register_reset (es1370_on_reset, s);
+
+    AUD_register_card ("es1370", &s->card);
+    es1370_reset (s);
+    return 0;
+}
+
+static void es1370_exitfn (PCIDevice *dev)
+{
+    ES1370State *s = DO_UPCAST (ES1370State, dev, dev);
+
+    memory_region_destroy (&s->io);
+}
+
+int es1370_init (PCIBus *bus)
+{
+    pci_create_simple (bus, -1, "ES1370");
+    return 0;
+}
+
+static void es1370_class_init (ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS (klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS (klass);
+
+    k->init = es1370_initfn;
+    k->exit = es1370_exitfn;
+    k->vendor_id = PCI_VENDOR_ID_ENSONIQ;
+    k->device_id = PCI_DEVICE_ID_ENSONIQ_ES1370;
+    k->class_id = PCI_CLASS_MULTIMEDIA_AUDIO;
+    k->subsystem_vendor_id = 0x4942;
+    k->subsystem_id = 0x4c4c;
+    dc->desc = "ENSONIQ AudioPCI ES1370";
+    dc->vmsd = &vmstate_es1370;
+}
+
+static const TypeInfo es1370_info = {
+    .name          = "ES1370",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof (ES1370State),
+    .class_init    = es1370_class_init,
+};
+
+static void es1370_register_types (void)
+{
+    type_register_static (&es1370_info);
+}
+
+type_init (es1370_register_types)
+
diff --git a/hw/audio/fmopl.c b/hw/audio/fmopl.c
new file mode 100644 (file)
index 0000000..f0a0234
--- /dev/null
@@ -0,0 +1,1395 @@
+/*
+**
+** File: fmopl.c -- software implementation of FM sound generator
+**
+** Copyright (C) 1999,2000 Tatsuyuki Satoh , MultiArcadeMachineEmurator development
+**
+** Version 0.37a
+**
+*/
+
+/*
+       preliminary :
+       Problem :
+       note:
+*/
+
+/* This version of fmopl.c is a fork of the MAME one, relicensed under the LGPL.
+ *
+ * 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.1 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/>.
+ */
+
+#define INLINE         static inline
+#define HAS_YM3812     1
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <math.h>
+//#include "driver.h"          /* use M.A.M.E. */
+#include "fmopl.h"
+
+#ifndef PI
+#define PI 3.14159265358979323846
+#endif
+
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+#endif
+
+/* -------------------- for debug --------------------- */
+/* #define OPL_OUTPUT_LOG */
+#ifdef OPL_OUTPUT_LOG
+static FILE *opl_dbg_fp = NULL;
+static FM_OPL *opl_dbg_opl[16];
+static int opl_dbg_maxchip,opl_dbg_chip;
+#endif
+
+/* -------------------- preliminary define section --------------------- */
+/* attack/decay rate time rate */
+#define OPL_ARRATE     141280  /* RATE 4 =  2826.24ms @ 3.6MHz */
+#define OPL_DRRATE    1956000  /* RATE 4 = 39280.64ms @ 3.6MHz */
+
+#define DELTAT_MIXING_LEVEL (1) /* DELTA-T ADPCM MIXING LEVEL */
+
+#define FREQ_BITS 24                   /* frequency turn          */
+
+/* counter bits = 20 , octerve 7 */
+#define FREQ_RATE   (1<<(FREQ_BITS-20))
+#define TL_BITS    (FREQ_BITS+2)
+
+/* final output shift , limit minimum and maximum */
+#define OPL_OUTSB   (TL_BITS+3-16)             /* OPL output final shift 16bit */
+#define OPL_MAXOUT (0x7fff<<OPL_OUTSB)
+#define OPL_MINOUT (-0x8000<<OPL_OUTSB)
+
+/* -------------------- quality selection --------------------- */
+
+/* sinwave entries */
+/* used static memory = SIN_ENT * 4 (byte) */
+#define SIN_ENT 2048
+
+/* output level entries (envelope,sinwave) */
+/* envelope counter lower bits */
+#define ENV_BITS 16
+/* envelope output entries */
+#define EG_ENT   4096
+/* used dynamic memory = EG_ENT*4*4(byte)or EG_ENT*6*4(byte) */
+/* used static  memory = EG_ENT*4 (byte)                     */
+
+#define EG_OFF   ((2*EG_ENT)<<ENV_BITS)  /* OFF          */
+#define EG_DED   EG_OFF
+#define EG_DST   (EG_ENT<<ENV_BITS)      /* DECAY  START */
+#define EG_AED   EG_DST
+#define EG_AST   0                       /* ATTACK START */
+
+#define EG_STEP (96.0/EG_ENT) /* OPL is 0.1875 dB step  */
+
+/* LFO table entries */
+#define VIB_ENT 512
+#define VIB_SHIFT (32-9)
+#define AMS_ENT 512
+#define AMS_SHIFT (32-9)
+
+#define VIB_RATE 256
+
+/* -------------------- local defines , macros --------------------- */
+
+/* register number to channel number , slot offset */
+#define SLOT1 0
+#define SLOT2 1
+
+/* envelope phase */
+#define ENV_MOD_RR  0x00
+#define ENV_MOD_DR  0x01
+#define ENV_MOD_AR  0x02
+
+/* -------------------- tables --------------------- */
+static const int slot_array[32]=
+{
+        0, 2, 4, 1, 3, 5,-1,-1,
+        6, 8,10, 7, 9,11,-1,-1,
+       12,14,16,13,15,17,-1,-1,
+       -1,-1,-1,-1,-1,-1,-1,-1
+};
+
+/* key scale level */
+/* table is 3dB/OCT , DV converts this in TL step at 6dB/OCT */
+#define DV (EG_STEP/2)
+static const UINT32 KSL_TABLE[8*16]=
+{
+       /* OCT 0 */
+        0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV,
+        0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV,
+        0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV,
+        0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV,
+       /* OCT 1 */
+        0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV,
+        0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV,
+        0.000/DV, 0.750/DV, 1.125/DV, 1.500/DV,
+        1.875/DV, 2.250/DV, 2.625/DV, 3.000/DV,
+       /* OCT 2 */
+        0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV,
+        0.000/DV, 1.125/DV, 1.875/DV, 2.625/DV,
+        3.000/DV, 3.750/DV, 4.125/DV, 4.500/DV,
+        4.875/DV, 5.250/DV, 5.625/DV, 6.000/DV,
+       /* OCT 3 */
+        0.000/DV, 0.000/DV, 0.000/DV, 1.875/DV,
+        3.000/DV, 4.125/DV, 4.875/DV, 5.625/DV,
+        6.000/DV, 6.750/DV, 7.125/DV, 7.500/DV,
+        7.875/DV, 8.250/DV, 8.625/DV, 9.000/DV,
+       /* OCT 4 */
+        0.000/DV, 0.000/DV, 3.000/DV, 4.875/DV,
+        6.000/DV, 7.125/DV, 7.875/DV, 8.625/DV,
+        9.000/DV, 9.750/DV,10.125/DV,10.500/DV,
+       10.875/DV,11.250/DV,11.625/DV,12.000/DV,
+       /* OCT 5 */
+        0.000/DV, 3.000/DV, 6.000/DV, 7.875/DV,
+        9.000/DV,10.125/DV,10.875/DV,11.625/DV,
+       12.000/DV,12.750/DV,13.125/DV,13.500/DV,
+       13.875/DV,14.250/DV,14.625/DV,15.000/DV,
+       /* OCT 6 */
+        0.000/DV, 6.000/DV, 9.000/DV,10.875/DV,
+       12.000/DV,13.125/DV,13.875/DV,14.625/DV,
+       15.000/DV,15.750/DV,16.125/DV,16.500/DV,
+       16.875/DV,17.250/DV,17.625/DV,18.000/DV,
+       /* OCT 7 */
+        0.000/DV, 9.000/DV,12.000/DV,13.875/DV,
+       15.000/DV,16.125/DV,16.875/DV,17.625/DV,
+       18.000/DV,18.750/DV,19.125/DV,19.500/DV,
+       19.875/DV,20.250/DV,20.625/DV,21.000/DV
+};
+#undef DV
+
+/* sustain lebel table (3db per step) */
+/* 0 - 15: 0, 3, 6, 9,12,15,18,21,24,27,30,33,36,39,42,93 (dB)*/
+#define SC(db) (db*((3/EG_STEP)*(1<<ENV_BITS)))+EG_DST
+static const INT32 SL_TABLE[16]={
+ SC( 0),SC( 1),SC( 2),SC(3 ),SC(4 ),SC(5 ),SC(6 ),SC( 7),
+ SC( 8),SC( 9),SC(10),SC(11),SC(12),SC(13),SC(14),SC(31)
+};
+#undef SC
+
+#define TL_MAX (EG_ENT*2) /* limit(tl + ksr + envelope) + sinwave */
+/* TotalLevel : 48 24 12  6  3 1.5 0.75 (dB) */
+/* TL_TABLE[ 0      to TL_MAX          ] : plus  section */
+/* TL_TABLE[ TL_MAX to TL_MAX+TL_MAX-1 ] : minus section */
+static INT32 *TL_TABLE;
+
+/* pointers to TL_TABLE with sinwave output offset */
+static INT32 **SIN_TABLE;
+
+/* LFO table */
+static INT32 *AMS_TABLE;
+static INT32 *VIB_TABLE;
+
+/* envelope output curve table */
+/* attack + decay + OFF */
+static INT32 ENV_CURVE[2*EG_ENT+1];
+
+/* multiple table */
+#define ML 2
+static const UINT32 MUL_TABLE[16]= {
+/* 1/2, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15 */
+   0.50*ML, 1.00*ML, 2.00*ML, 3.00*ML, 4.00*ML, 5.00*ML, 6.00*ML, 7.00*ML,
+   8.00*ML, 9.00*ML,10.00*ML,10.00*ML,12.00*ML,12.00*ML,15.00*ML,15.00*ML
+};
+#undef ML
+
+/* dummy attack / decay rate ( when rate == 0 ) */
+static INT32 RATE_0[16]=
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+
+/* -------------------- static state --------------------- */
+
+/* lock level of common table */
+static int num_lock = 0;
+
+/* work table */
+static void *cur_chip = NULL;  /* current chip point */
+/* currenct chip state */
+/* static OPLSAMPLE  *bufL,*bufR; */
+static OPL_CH *S_CH;
+static OPL_CH *E_CH;
+OPL_SLOT *SLOT7_1,*SLOT7_2,*SLOT8_1,*SLOT8_2;
+
+static INT32 outd[1];
+static INT32 ams;
+static INT32 vib;
+INT32  *ams_table;
+INT32  *vib_table;
+static INT32 amsIncr;
+static INT32 vibIncr;
+static INT32 feedback2;                /* connect for SLOT 2 */
+
+/* log output level */
+#define LOG_ERR  3      /* ERROR       */
+#define LOG_WAR  2      /* WARNING     */
+#define LOG_INF  1      /* INFORMATION */
+
+//#define LOG_LEVEL LOG_INF
+#define LOG_LEVEL      LOG_ERR
+
+//#define LOG(n,x) if( (n)>=LOG_LEVEL ) logerror x
+#define LOG(n,x)
+
+/* --------------------- subroutines  --------------------- */
+
+INLINE int Limit( int val, int max, int min ) {
+       if ( val > max )
+               val = max;
+       else if ( val < min )
+               val = min;
+
+       return val;
+}
+
+/* status set and IRQ handling */
+INLINE void OPL_STATUS_SET(FM_OPL *OPL,int flag)
+{
+       /* set status flag */
+       OPL->status |= flag;
+       if(!(OPL->status & 0x80))
+       {
+               if(OPL->status & OPL->statusmask)
+               {       /* IRQ on */
+                       OPL->status |= 0x80;
+                       /* callback user interrupt handler (IRQ is OFF to ON) */
+                       if(OPL->IRQHandler) (OPL->IRQHandler)(OPL->IRQParam,1);
+               }
+       }
+}
+
+/* status reset and IRQ handling */
+INLINE void OPL_STATUS_RESET(FM_OPL *OPL,int flag)
+{
+       /* reset status flag */
+       OPL->status &=~flag;
+       if((OPL->status & 0x80))
+       {
+               if (!(OPL->status & OPL->statusmask) )
+               {
+                       OPL->status &= 0x7f;
+                       /* callback user interrupt handler (IRQ is ON to OFF) */
+                       if(OPL->IRQHandler) (OPL->IRQHandler)(OPL->IRQParam,0);
+               }
+       }
+}
+
+/* IRQ mask set */
+INLINE void OPL_STATUSMASK_SET(FM_OPL *OPL,int flag)
+{
+       OPL->statusmask = flag;
+       /* IRQ handling check */
+       OPL_STATUS_SET(OPL,0);
+       OPL_STATUS_RESET(OPL,0);
+}
+
+/* ----- key on  ----- */
+INLINE void OPL_KEYON(OPL_SLOT *SLOT)
+{
+       /* sin wave restart */
+       SLOT->Cnt = 0;
+       /* set attack */
+       SLOT->evm = ENV_MOD_AR;
+       SLOT->evs = SLOT->evsa;
+       SLOT->evc = EG_AST;
+       SLOT->eve = EG_AED;
+}
+/* ----- key off ----- */
+INLINE void OPL_KEYOFF(OPL_SLOT *SLOT)
+{
+       if( SLOT->evm > ENV_MOD_RR)
+       {
+               /* set envelope counter from envleope output */
+               SLOT->evm = ENV_MOD_RR;
+               if( !(SLOT->evc&EG_DST) )
+                       //SLOT->evc = (ENV_CURVE[SLOT->evc>>ENV_BITS]<<ENV_BITS) + EG_DST;
+                       SLOT->evc = EG_DST;
+               SLOT->eve = EG_DED;
+               SLOT->evs = SLOT->evsr;
+       }
+}
+
+/* ---------- calcrate Envelope Generator & Phase Generator ---------- */
+/* return : envelope output */
+INLINE UINT32 OPL_CALC_SLOT( OPL_SLOT *SLOT )
+{
+       /* calcrate envelope generator */
+       if( (SLOT->evc+=SLOT->evs) >= SLOT->eve )
+       {
+               switch( SLOT->evm ){
+               case ENV_MOD_AR: /* ATTACK -> DECAY1 */
+                       /* next DR */
+                       SLOT->evm = ENV_MOD_DR;
+                       SLOT->evc = EG_DST;
+                       SLOT->eve = SLOT->SL;
+                       SLOT->evs = SLOT->evsd;
+                       break;
+               case ENV_MOD_DR: /* DECAY -> SL or RR */
+                       SLOT->evc = SLOT->SL;
+                       SLOT->eve = EG_DED;
+                       if(SLOT->eg_typ)
+                       {
+                               SLOT->evs = 0;
+                       }
+                       else
+                       {
+                               SLOT->evm = ENV_MOD_RR;
+                               SLOT->evs = SLOT->evsr;
+                       }
+                       break;
+               case ENV_MOD_RR: /* RR -> OFF */
+                       SLOT->evc = EG_OFF;
+                       SLOT->eve = EG_OFF+1;
+                       SLOT->evs = 0;
+                       break;
+               }
+       }
+       /* calcrate envelope */
+       return SLOT->TLL+ENV_CURVE[SLOT->evc>>ENV_BITS]+(SLOT->ams ? ams : 0);
+}
+
+/* set algorithm connection */
+static void set_algorithm( OPL_CH *CH)
+{
+       INT32 *carrier = &outd[0];
+       CH->connect1 = CH->CON ? carrier : &feedback2;
+       CH->connect2 = carrier;
+}
+
+/* ---------- frequency counter for operater update ---------- */
+INLINE void CALC_FCSLOT(OPL_CH *CH,OPL_SLOT *SLOT)
+{
+       int ksr;
+
+       /* frequency step counter */
+       SLOT->Incr = CH->fc * SLOT->mul;
+       ksr = CH->kcode >> SLOT->KSR;
+
+       if( SLOT->ksr != ksr )
+       {
+               SLOT->ksr = ksr;
+               /* attack , decay rate recalcration */
+               SLOT->evsa = SLOT->AR[ksr];
+               SLOT->evsd = SLOT->DR[ksr];
+               SLOT->evsr = SLOT->RR[ksr];
+       }
+       SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl);
+}
+
+/* set multi,am,vib,EG-TYP,KSR,mul */
+INLINE void set_mul(FM_OPL *OPL,int slot,int v)
+{
+       OPL_CH   *CH   = &OPL->P_CH[slot/2];
+       OPL_SLOT *SLOT = &CH->SLOT[slot&1];
+
+       SLOT->mul    = MUL_TABLE[v&0x0f];
+       SLOT->KSR    = (v&0x10) ? 0 : 2;
+       SLOT->eg_typ = (v&0x20)>>5;
+       SLOT->vib    = (v&0x40);
+       SLOT->ams    = (v&0x80);
+       CALC_FCSLOT(CH,SLOT);
+}
+
+/* set ksl & tl */
+INLINE void set_ksl_tl(FM_OPL *OPL,int slot,int v)
+{
+       OPL_CH   *CH   = &OPL->P_CH[slot/2];
+       OPL_SLOT *SLOT = &CH->SLOT[slot&1];
+       int ksl = v>>6; /* 0 / 1.5 / 3 / 6 db/OCT */
+
+       SLOT->ksl = ksl ? 3-ksl : 31;
+       SLOT->TL  = (v&0x3f)*(0.75/EG_STEP); /* 0.75db step */
+
+       if( !(OPL->mode&0x80) )
+       {       /* not CSM latch total level */
+               SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl);
+       }
+}
+
+/* set attack rate & decay rate  */
+INLINE void set_ar_dr(FM_OPL *OPL,int slot,int v)
+{
+       OPL_CH   *CH   = &OPL->P_CH[slot/2];
+       OPL_SLOT *SLOT = &CH->SLOT[slot&1];
+       int ar = v>>4;
+       int dr = v&0x0f;
+
+       SLOT->AR = ar ? &OPL->AR_TABLE[ar<<2] : RATE_0;
+       SLOT->evsa = SLOT->AR[SLOT->ksr];
+       if( SLOT->evm == ENV_MOD_AR ) SLOT->evs = SLOT->evsa;
+
+       SLOT->DR = dr ? &OPL->DR_TABLE[dr<<2] : RATE_0;
+       SLOT->evsd = SLOT->DR[SLOT->ksr];
+       if( SLOT->evm == ENV_MOD_DR ) SLOT->evs = SLOT->evsd;
+}
+
+/* set sustain level & release rate */
+INLINE void set_sl_rr(FM_OPL *OPL,int slot,int v)
+{
+       OPL_CH   *CH   = &OPL->P_CH[slot/2];
+       OPL_SLOT *SLOT = &CH->SLOT[slot&1];
+       int sl = v>>4;
+       int rr = v & 0x0f;
+
+       SLOT->SL = SL_TABLE[sl];
+       if( SLOT->evm == ENV_MOD_DR ) SLOT->eve = SLOT->SL;
+       SLOT->RR = &OPL->DR_TABLE[rr<<2];
+       SLOT->evsr = SLOT->RR[SLOT->ksr];
+       if( SLOT->evm == ENV_MOD_RR ) SLOT->evs = SLOT->evsr;
+}
+
+/* operator output calcrator */
+#define OP_OUT(slot,env,con)   slot->wavetable[((slot->Cnt+con)/(0x1000000/SIN_ENT))&(SIN_ENT-1)][env]
+/* ---------- calcrate one of channel ---------- */
+INLINE void OPL_CALC_CH( OPL_CH *CH )
+{
+       UINT32 env_out;
+       OPL_SLOT *SLOT;
+
+       feedback2 = 0;
+       /* SLOT 1 */
+       SLOT = &CH->SLOT[SLOT1];
+       env_out=OPL_CALC_SLOT(SLOT);
+       if( env_out < EG_ENT-1 )
+       {
+               /* PG */
+               if(SLOT->vib) SLOT->Cnt += (SLOT->Incr*vib/VIB_RATE);
+               else          SLOT->Cnt += SLOT->Incr;
+               /* connectoion */
+               if(CH->FB)
+               {
+                       int feedback1 = (CH->op1_out[0]+CH->op1_out[1])>>CH->FB;
+                       CH->op1_out[1] = CH->op1_out[0];
+                       *CH->connect1 += CH->op1_out[0] = OP_OUT(SLOT,env_out,feedback1);
+               }
+               else
+               {
+                       *CH->connect1 += OP_OUT(SLOT,env_out,0);
+               }
+       }else
+       {
+               CH->op1_out[1] = CH->op1_out[0];
+               CH->op1_out[0] = 0;
+       }
+       /* SLOT 2 */
+       SLOT = &CH->SLOT[SLOT2];
+       env_out=OPL_CALC_SLOT(SLOT);
+       if( env_out < EG_ENT-1 )
+       {
+               /* PG */
+               if(SLOT->vib) SLOT->Cnt += (SLOT->Incr*vib/VIB_RATE);
+               else          SLOT->Cnt += SLOT->Incr;
+               /* connectoion */
+               outd[0] += OP_OUT(SLOT,env_out, feedback2);
+       }
+}
+
+/* ---------- calcrate rhythm block ---------- */
+#define WHITE_NOISE_db 6.0
+INLINE void OPL_CALC_RH( OPL_CH *CH )
+{
+       UINT32 env_tam,env_sd,env_top,env_hh;
+       int whitenoise = (rand()&1)*(WHITE_NOISE_db/EG_STEP);
+       INT32 tone8;
+
+       OPL_SLOT *SLOT;
+       int env_out;
+
+       /* BD : same as FM serial mode and output level is large */
+       feedback2 = 0;
+       /* SLOT 1 */
+       SLOT = &CH[6].SLOT[SLOT1];
+       env_out=OPL_CALC_SLOT(SLOT);
+       if( env_out < EG_ENT-1 )
+       {
+               /* PG */
+               if(SLOT->vib) SLOT->Cnt += (SLOT->Incr*vib/VIB_RATE);
+               else          SLOT->Cnt += SLOT->Incr;
+               /* connectoion */
+               if(CH[6].FB)
+               {
+                       int feedback1 = (CH[6].op1_out[0]+CH[6].op1_out[1])>>CH[6].FB;
+                       CH[6].op1_out[1] = CH[6].op1_out[0];
+                       feedback2 = CH[6].op1_out[0] = OP_OUT(SLOT,env_out,feedback1);
+               }
+               else
+               {
+                       feedback2 = OP_OUT(SLOT,env_out,0);
+               }
+       }else
+       {
+               feedback2 = 0;
+               CH[6].op1_out[1] = CH[6].op1_out[0];
+               CH[6].op1_out[0] = 0;
+       }
+       /* SLOT 2 */
+       SLOT = &CH[6].SLOT[SLOT2];
+       env_out=OPL_CALC_SLOT(SLOT);
+       if( env_out < EG_ENT-1 )
+       {
+               /* PG */
+               if(SLOT->vib) SLOT->Cnt += (SLOT->Incr*vib/VIB_RATE);
+               else          SLOT->Cnt += SLOT->Incr;
+               /* connectoion */
+               outd[0] += OP_OUT(SLOT,env_out, feedback2)*2;
+       }
+
+       // SD  (17) = mul14[fnum7] + white noise
+       // TAM (15) = mul15[fnum8]
+       // TOP (18) = fnum6(mul18[fnum8]+whitenoise)
+       // HH  (14) = fnum7(mul18[fnum8]+whitenoise) + white noise
+       env_sd =OPL_CALC_SLOT(SLOT7_2) + whitenoise;
+       env_tam=OPL_CALC_SLOT(SLOT8_1);
+       env_top=OPL_CALC_SLOT(SLOT8_2);
+       env_hh =OPL_CALC_SLOT(SLOT7_1) + whitenoise;
+
+       /* PG */
+       if(SLOT7_1->vib) SLOT7_1->Cnt += (2*SLOT7_1->Incr*vib/VIB_RATE);
+       else             SLOT7_1->Cnt += 2*SLOT7_1->Incr;
+       if(SLOT7_2->vib) SLOT7_2->Cnt += ((CH[7].fc*8)*vib/VIB_RATE);
+       else             SLOT7_2->Cnt += (CH[7].fc*8);
+       if(SLOT8_1->vib) SLOT8_1->Cnt += (SLOT8_1->Incr*vib/VIB_RATE);
+       else             SLOT8_1->Cnt += SLOT8_1->Incr;
+       if(SLOT8_2->vib) SLOT8_2->Cnt += ((CH[8].fc*48)*vib/VIB_RATE);
+       else             SLOT8_2->Cnt += (CH[8].fc*48);
+
+       tone8 = OP_OUT(SLOT8_2,whitenoise,0 );
+
+       /* SD */
+       if( env_sd < EG_ENT-1 )
+               outd[0] += OP_OUT(SLOT7_1,env_sd, 0)*8;
+       /* TAM */
+       if( env_tam < EG_ENT-1 )
+               outd[0] += OP_OUT(SLOT8_1,env_tam, 0)*2;
+       /* TOP-CY */
+       if( env_top < EG_ENT-1 )
+               outd[0] += OP_OUT(SLOT7_2,env_top,tone8)*2;
+       /* HH */
+       if( env_hh  < EG_ENT-1 )
+               outd[0] += OP_OUT(SLOT7_2,env_hh,tone8)*2;
+}
+
+/* ----------- initialize time tabls ----------- */
+static void init_timetables( FM_OPL *OPL , int ARRATE , int DRRATE )
+{
+       int i;
+       double rate;
+
+       /* make attack rate & decay rate tables */
+       for (i = 0;i < 4;i++) OPL->AR_TABLE[i] = OPL->DR_TABLE[i] = 0;
+       for (i = 4;i <= 60;i++){
+               rate  = OPL->freqbase;                                          /* frequency rate */
+               if( i < 60 ) rate *= 1.0+(i&3)*0.25;            /* b0-1 : x1 , x1.25 , x1.5 , x1.75 */
+               rate *= 1<<((i>>2)-1);                                          /* b2-5 : shift bit */
+               rate *= (double)(EG_ENT<<ENV_BITS);
+               OPL->AR_TABLE[i] = rate / ARRATE;
+               OPL->DR_TABLE[i] = rate / DRRATE;
+       }
+       for (i = 60; i < ARRAY_SIZE(OPL->AR_TABLE); i++)
+       {
+               OPL->AR_TABLE[i] = EG_AED-1;
+               OPL->DR_TABLE[i] = OPL->DR_TABLE[60];
+       }
+#if 0
+       for (i = 0;i < 64 ;i++){        /* make for overflow area */
+               LOG(LOG_WAR, ("rate %2d , ar %f ms , dr %f ms\n", i,
+                       ((double)(EG_ENT<<ENV_BITS) / OPL->AR_TABLE[i]) * (1000.0 / OPL->rate),
+                       ((double)(EG_ENT<<ENV_BITS) / OPL->DR_TABLE[i]) * (1000.0 / OPL->rate) ));
+       }
+#endif
+}
+
+/* ---------- generic table initialize ---------- */
+static int OPLOpenTable( void )
+{
+       int s,t;
+       double rate;
+       int i,j;
+       double pom;
+
+       /* allocate dynamic tables */
+       if( (TL_TABLE = malloc(TL_MAX*2*sizeof(INT32))) == NULL)
+               return 0;
+       if( (SIN_TABLE = malloc(SIN_ENT*4 *sizeof(INT32 *))) == NULL)
+       {
+               free(TL_TABLE);
+               return 0;
+       }
+       if( (AMS_TABLE = malloc(AMS_ENT*2 *sizeof(INT32))) == NULL)
+       {
+               free(TL_TABLE);
+               free(SIN_TABLE);
+               return 0;
+       }
+       if( (VIB_TABLE = malloc(VIB_ENT*2 *sizeof(INT32))) == NULL)
+       {
+               free(TL_TABLE);
+               free(SIN_TABLE);
+               free(AMS_TABLE);
+               return 0;
+       }
+       /* make total level table */
+       for (t = 0;t < EG_ENT-1 ;t++){
+               rate = ((1<<TL_BITS)-1)/pow(10,EG_STEP*t/20);   /* dB -> voltage */
+               TL_TABLE[       t] =  (int)rate;
+               TL_TABLE[TL_MAX+t] = -TL_TABLE[t];
+/*             LOG(LOG_INF,("TotalLevel(%3d) = %x\n",t,TL_TABLE[t]));*/
+       }
+       /* fill volume off area */
+       for ( t = EG_ENT-1; t < TL_MAX ;t++){
+               TL_TABLE[t] = TL_TABLE[TL_MAX+t] = 0;
+       }
+
+       /* make sinwave table (total level offet) */
+       /* degree 0 = degree 180                   = off */
+       SIN_TABLE[0] = SIN_TABLE[SIN_ENT/2]         = &TL_TABLE[EG_ENT-1];
+       for (s = 1;s <= SIN_ENT/4;s++){
+               pom = sin(2*PI*s/SIN_ENT); /* sin     */
+               pom = 20*log10(1/pom);     /* decibel */
+               j = pom / EG_STEP;         /* TL_TABLE steps */
+
+        /* degree 0   -  90    , degree 180 -  90 : plus section */
+               SIN_TABLE[          s] = SIN_TABLE[SIN_ENT/2-s] = &TL_TABLE[j];
+        /* degree 180 - 270    , degree 360 - 270 : minus section */
+               SIN_TABLE[SIN_ENT/2+s] = SIN_TABLE[SIN_ENT  -s] = &TL_TABLE[TL_MAX+j];
+/*             LOG(LOG_INF,("sin(%3d) = %f:%f db\n",s,pom,(double)j * EG_STEP));*/
+       }
+       for (s = 0;s < SIN_ENT;s++)
+       {
+               SIN_TABLE[SIN_ENT*1+s] = s<(SIN_ENT/2) ? SIN_TABLE[s] : &TL_TABLE[EG_ENT];
+               SIN_TABLE[SIN_ENT*2+s] = SIN_TABLE[s % (SIN_ENT/2)];
+               SIN_TABLE[SIN_ENT*3+s] = (s/(SIN_ENT/4))&1 ? &TL_TABLE[EG_ENT] : SIN_TABLE[SIN_ENT*2+s];
+       }
+
+       /* envelope counter -> envelope output table */
+       for (i=0; i<EG_ENT; i++)
+       {
+               /* ATTACK curve */
+               pom = pow( ((double)(EG_ENT-1-i)/EG_ENT) , 8 ) * EG_ENT;
+               /* if( pom >= EG_ENT ) pom = EG_ENT-1; */
+               ENV_CURVE[i] = (int)pom;
+               /* DECAY ,RELEASE curve */
+               ENV_CURVE[(EG_DST>>ENV_BITS)+i]= i;
+       }
+       /* off */
+       ENV_CURVE[EG_OFF>>ENV_BITS]= EG_ENT-1;
+       /* make LFO ams table */
+       for (i=0; i<AMS_ENT; i++)
+       {
+               pom = (1.0+sin(2*PI*i/AMS_ENT))/2; /* sin */
+               AMS_TABLE[i]         = (1.0/EG_STEP)*pom; /* 1dB   */
+               AMS_TABLE[AMS_ENT+i] = (4.8/EG_STEP)*pom; /* 4.8dB */
+       }
+       /* make LFO vibrate table */
+       for (i=0; i<VIB_ENT; i++)
+       {
+               /* 100cent = 1seminote = 6% ?? */
+               pom = (double)VIB_RATE*0.06*sin(2*PI*i/VIB_ENT); /* +-100sect step */
+               VIB_TABLE[i]         = VIB_RATE + (pom*0.07); /* +- 7cent */
+               VIB_TABLE[VIB_ENT+i] = VIB_RATE + (pom*0.14); /* +-14cent */
+               /* LOG(LOG_INF,("vib %d=%d\n",i,VIB_TABLE[VIB_ENT+i])); */
+       }
+       return 1;
+}
+
+
+static void OPLCloseTable( void )
+{
+       free(TL_TABLE);
+       free(SIN_TABLE);
+       free(AMS_TABLE);
+       free(VIB_TABLE);
+}
+
+/* CSM Key Control */
+INLINE void CSMKeyControll(OPL_CH *CH)
+{
+       OPL_SLOT *slot1 = &CH->SLOT[SLOT1];
+       OPL_SLOT *slot2 = &CH->SLOT[SLOT2];
+       /* all key off */
+       OPL_KEYOFF(slot1);
+       OPL_KEYOFF(slot2);
+       /* total level latch */
+       slot1->TLL = slot1->TL + (CH->ksl_base>>slot1->ksl);
+       slot1->TLL = slot1->TL + (CH->ksl_base>>slot1->ksl);
+       /* key on */
+       CH->op1_out[0] = CH->op1_out[1] = 0;
+       OPL_KEYON(slot1);
+       OPL_KEYON(slot2);
+}
+
+/* ---------- opl initialize ---------- */
+static void OPL_initialize(FM_OPL *OPL)
+{
+       int fn;
+
+       /* frequency base */
+       OPL->freqbase = (OPL->rate) ? ((double)OPL->clock / OPL->rate) / 72  : 0;
+       /* Timer base time */
+       OPL->TimerBase = 1.0/((double)OPL->clock / 72.0 );
+       /* make time tables */
+       init_timetables( OPL , OPL_ARRATE , OPL_DRRATE );
+       /* make fnumber -> increment counter table */
+       for( fn=0 ; fn < 1024 ; fn++ )
+       {
+               OPL->FN_TABLE[fn] = OPL->freqbase * fn * FREQ_RATE * (1<<7) / 2;
+       }
+       /* LFO freq.table */
+       OPL->amsIncr = OPL->rate ? (double)AMS_ENT*(1<<AMS_SHIFT) / OPL->rate * 3.7 * ((double)OPL->clock/3600000) : 0;
+       OPL->vibIncr = OPL->rate ? (double)VIB_ENT*(1<<VIB_SHIFT) / OPL->rate * 6.4 * ((double)OPL->clock/3600000) : 0;
+}
+
+/* ---------- write a OPL registers ---------- */
+static void OPLWriteReg(FM_OPL *OPL, int r, int v)
+{
+       OPL_CH *CH;
+       int slot;
+       int block_fnum;
+
+       switch(r&0xe0)
+       {
+       case 0x00: /* 00-1f:control */
+               switch(r&0x1f)
+               {
+               case 0x01:
+                       /* wave selector enable */
+                       if(OPL->type&OPL_TYPE_WAVESEL)
+                       {
+                               OPL->wavesel = v&0x20;
+                               if(!OPL->wavesel)
+                               {
+                                       /* preset compatible mode */
+                                       int c;
+                                       for(c=0;c<OPL->max_ch;c++)
+                                       {
+                                               OPL->P_CH[c].SLOT[SLOT1].wavetable = &SIN_TABLE[0];
+                                               OPL->P_CH[c].SLOT[SLOT2].wavetable = &SIN_TABLE[0];
+                                       }
+                               }
+                       }
+                       return;
+               case 0x02:      /* Timer 1 */
+                       OPL->T[0] = (256-v)*4;
+                       break;
+               case 0x03:      /* Timer 2 */
+                       OPL->T[1] = (256-v)*16;
+                       return;
+               case 0x04:      /* IRQ clear / mask and Timer enable */
+                       if(v&0x80)
+                       {       /* IRQ flag clear */
+                               OPL_STATUS_RESET(OPL,0x7f);
+                       }
+                       else
+                       {       /* set IRQ mask ,timer enable*/
+                               UINT8 st1 = v&1;
+                               UINT8 st2 = (v>>1)&1;
+                               /* IRQRST,T1MSK,t2MSK,EOSMSK,BRMSK,x,ST2,ST1 */
+                               OPL_STATUS_RESET(OPL,v&0x78);
+                               OPL_STATUSMASK_SET(OPL,((~v)&0x78)|0x01);
+                               /* timer 2 */
+                               if(OPL->st[1] != st2)
+                               {
+                                       double interval = st2 ? (double)OPL->T[1]*OPL->TimerBase : 0.0;
+                                       OPL->st[1] = st2;
+                                       if (OPL->TimerHandler) (OPL->TimerHandler)(OPL->TimerParam+1,interval);
+                               }
+                               /* timer 1 */
+                               if(OPL->st[0] != st1)
+                               {
+                                       double interval = st1 ? (double)OPL->T[0]*OPL->TimerBase : 0.0;
+                                       OPL->st[0] = st1;
+                                       if (OPL->TimerHandler) (OPL->TimerHandler)(OPL->TimerParam+0,interval);
+                               }
+                       }
+                       return;
+#if BUILD_Y8950
+               case 0x06:              /* Key Board OUT */
+                       if(OPL->type&OPL_TYPE_KEYBOARD)
+                       {
+                               if(OPL->keyboardhandler_w)
+                                       OPL->keyboardhandler_w(OPL->keyboard_param,v);
+                               else
+                                       LOG(LOG_WAR,("OPL:write unmapped KEYBOARD port\n"));
+                       }
+                       return;
+               case 0x07:      /* DELTA-T control : START,REC,MEMDATA,REPT,SPOFF,x,x,RST */
+                       if(OPL->type&OPL_TYPE_ADPCM)
+                               YM_DELTAT_ADPCM_Write(OPL->deltat,r-0x07,v);
+                       return;
+               case 0x08:      /* MODE,DELTA-T : CSM,NOTESEL,x,x,smpl,da/ad,64k,rom */
+                       OPL->mode = v;
+                       v&=0x1f;        /* for DELTA-T unit */
+               case 0x09:              /* START ADD */
+               case 0x0a:
+               case 0x0b:              /* STOP ADD  */
+               case 0x0c:
+               case 0x0d:              /* PRESCALE   */
+               case 0x0e:
+               case 0x0f:              /* ADPCM data */
+               case 0x10:              /* DELTA-N    */
+               case 0x11:              /* DELTA-N    */
+               case 0x12:              /* EG-CTRL    */
+                       if(OPL->type&OPL_TYPE_ADPCM)
+                               YM_DELTAT_ADPCM_Write(OPL->deltat,r-0x07,v);
+                       return;
+#if 0
+               case 0x15:              /* DAC data    */
+               case 0x16:
+               case 0x17:              /* SHIFT    */
+                       return;
+               case 0x18:              /* I/O CTRL (Direction) */
+                       if(OPL->type&OPL_TYPE_IO)
+                               OPL->portDirection = v&0x0f;
+                       return;
+               case 0x19:              /* I/O DATA */
+                       if(OPL->type&OPL_TYPE_IO)
+                       {
+                               OPL->portLatch = v;
+                               if(OPL->porthandler_w)
+                                       OPL->porthandler_w(OPL->port_param,v&OPL->portDirection);
+                       }
+                       return;
+               case 0x1a:              /* PCM data */
+                       return;
+#endif
+#endif
+               }
+               break;
+       case 0x20:      /* am,vib,ksr,eg type,mul */
+               slot = slot_array[r&0x1f];
+               if(slot == -1) return;
+               set_mul(OPL,slot,v);
+               return;
+       case 0x40:
+               slot = slot_array[r&0x1f];
+               if(slot == -1) return;
+               set_ksl_tl(OPL,slot,v);
+               return;
+       case 0x60:
+               slot = slot_array[r&0x1f];
+               if(slot == -1) return;
+               set_ar_dr(OPL,slot,v);
+               return;
+       case 0x80:
+               slot = slot_array[r&0x1f];
+               if(slot == -1) return;
+               set_sl_rr(OPL,slot,v);
+               return;
+       case 0xa0:
+               switch(r)
+               {
+               case 0xbd:
+                       /* amsep,vibdep,r,bd,sd,tom,tc,hh */
+                       {
+                       UINT8 rkey = OPL->rhythm^v;
+                       OPL->ams_table = &AMS_TABLE[v&0x80 ? AMS_ENT : 0];
+                       OPL->vib_table = &VIB_TABLE[v&0x40 ? VIB_ENT : 0];
+                       OPL->rhythm  = v&0x3f;
+                       if(OPL->rhythm&0x20)
+                       {
+#if 0
+                               usrintf_showmessage("OPL Rhythm mode select");
+#endif
+                               /* BD key on/off */
+                               if(rkey&0x10)
+                               {
+                                       if(v&0x10)
+                                       {
+                                               OPL->P_CH[6].op1_out[0] = OPL->P_CH[6].op1_out[1] = 0;
+                                               OPL_KEYON(&OPL->P_CH[6].SLOT[SLOT1]);
+                                               OPL_KEYON(&OPL->P_CH[6].SLOT[SLOT2]);
+                                       }
+                                       else
+                                       {
+                                               OPL_KEYOFF(&OPL->P_CH[6].SLOT[SLOT1]);
+                                               OPL_KEYOFF(&OPL->P_CH[6].SLOT[SLOT2]);
+                                       }
+                               }
+                               /* SD key on/off */
+                               if(rkey&0x08)
+                               {
+                                       if(v&0x08) OPL_KEYON(&OPL->P_CH[7].SLOT[SLOT2]);
+                                       else       OPL_KEYOFF(&OPL->P_CH[7].SLOT[SLOT2]);
+                               }/* TAM key on/off */
+                               if(rkey&0x04)
+                               {
+                                       if(v&0x04) OPL_KEYON(&OPL->P_CH[8].SLOT[SLOT1]);
+                                       else       OPL_KEYOFF(&OPL->P_CH[8].SLOT[SLOT1]);
+                               }
+                               /* TOP-CY key on/off */
+                               if(rkey&0x02)
+                               {
+                                       if(v&0x02) OPL_KEYON(&OPL->P_CH[8].SLOT[SLOT2]);
+                                       else       OPL_KEYOFF(&OPL->P_CH[8].SLOT[SLOT2]);
+                               }
+                               /* HH key on/off */
+                               if(rkey&0x01)
+                               {
+                                       if(v&0x01) OPL_KEYON(&OPL->P_CH[7].SLOT[SLOT1]);
+                                       else       OPL_KEYOFF(&OPL->P_CH[7].SLOT[SLOT1]);
+                               }
+                       }
+                       }
+                       return;
+               }
+               /* keyon,block,fnum */
+               if( (r&0x0f) > 8) return;
+               CH = &OPL->P_CH[r&0x0f];
+               if(!(r&0x10))
+               {       /* a0-a8 */
+                       block_fnum  = (CH->block_fnum&0x1f00) | v;
+               }
+               else
+               {       /* b0-b8 */
+                       int keyon = (v>>5)&1;
+                       block_fnum = ((v&0x1f)<<8) | (CH->block_fnum&0xff);
+                       if(CH->keyon != keyon)
+                       {
+                               if( (CH->keyon=keyon) )
+                               {
+                                       CH->op1_out[0] = CH->op1_out[1] = 0;
+                                       OPL_KEYON(&CH->SLOT[SLOT1]);
+                                       OPL_KEYON(&CH->SLOT[SLOT2]);
+                               }
+                               else
+                               {
+                                       OPL_KEYOFF(&CH->SLOT[SLOT1]);
+                                       OPL_KEYOFF(&CH->SLOT[SLOT2]);
+                               }
+                       }
+               }
+               /* update */
+               if(CH->block_fnum != block_fnum)
+               {
+                       int blockRv = 7-(block_fnum>>10);
+                       int fnum   = block_fnum&0x3ff;
+                       CH->block_fnum = block_fnum;
+
+                       CH->ksl_base = KSL_TABLE[block_fnum>>6];
+                       CH->fc = OPL->FN_TABLE[fnum]>>blockRv;
+                       CH->kcode = CH->block_fnum>>9;
+                       if( (OPL->mode&0x40) && CH->block_fnum&0x100) CH->kcode |=1;
+                       CALC_FCSLOT(CH,&CH->SLOT[SLOT1]);
+                       CALC_FCSLOT(CH,&CH->SLOT[SLOT2]);
+               }
+               return;
+       case 0xc0:
+               /* FB,C */
+               if( (r&0x0f) > 8) return;
+               CH = &OPL->P_CH[r&0x0f];
+               {
+               int feedback = (v>>1)&7;
+               CH->FB   = feedback ? (8+1) - feedback : 0;
+               CH->CON = v&1;
+               set_algorithm(CH);
+               }
+               return;
+       case 0xe0: /* wave type */
+               slot = slot_array[r&0x1f];
+               if(slot == -1) return;
+               CH = &OPL->P_CH[slot/2];
+               if(OPL->wavesel)
+               {
+                       /* LOG(LOG_INF,("OPL SLOT %d wave select %d\n",slot,v&3)); */
+                       CH->SLOT[slot&1].wavetable = &SIN_TABLE[(v&0x03)*SIN_ENT];
+               }
+               return;
+       }
+}
+
+/* lock/unlock for common table */
+static int OPL_LockTable(void)
+{
+       num_lock++;
+       if(num_lock>1) return 0;
+       /* first time */
+       cur_chip = NULL;
+       /* allocate total level table (128kb space) */
+       if( !OPLOpenTable() )
+       {
+               num_lock--;
+               return -1;
+       }
+       return 0;
+}
+
+static void OPL_UnLockTable(void)
+{
+       if(num_lock) num_lock--;
+       if(num_lock) return;
+       /* last time */
+       cur_chip = NULL;
+       OPLCloseTable();
+}
+
+#if (BUILD_YM3812 || BUILD_YM3526)
+/*******************************************************************************/
+/*             YM3812 local section                                                   */
+/*******************************************************************************/
+
+/* ---------- update one of chip ----------- */
+void YM3812UpdateOne(FM_OPL *OPL, INT16 *buffer, int length)
+{
+    int i;
+       int data;
+       OPLSAMPLE *buf = buffer;
+       UINT32 amsCnt  = OPL->amsCnt;
+       UINT32 vibCnt  = OPL->vibCnt;
+       UINT8 rhythm = OPL->rhythm&0x20;
+       OPL_CH *CH,*R_CH;
+
+       if( (void *)OPL != cur_chip ){
+               cur_chip = (void *)OPL;
+               /* channel pointers */
+               S_CH = OPL->P_CH;
+               E_CH = &S_CH[9];
+               /* rhythm slot */
+               SLOT7_1 = &S_CH[7].SLOT[SLOT1];
+               SLOT7_2 = &S_CH[7].SLOT[SLOT2];
+               SLOT8_1 = &S_CH[8].SLOT[SLOT1];
+               SLOT8_2 = &S_CH[8].SLOT[SLOT2];
+               /* LFO state */
+               amsIncr = OPL->amsIncr;
+               vibIncr = OPL->vibIncr;
+               ams_table = OPL->ams_table;
+               vib_table = OPL->vib_table;
+       }
+       R_CH = rhythm ? &S_CH[6] : E_CH;
+    for( i=0; i < length ; i++ )
+       {
+               /*            channel A         channel B         channel C      */
+               /* LFO */
+               ams = ams_table[(amsCnt+=amsIncr)>>AMS_SHIFT];
+               vib = vib_table[(vibCnt+=vibIncr)>>VIB_SHIFT];
+               outd[0] = 0;
+               /* FM part */
+               for(CH=S_CH ; CH < R_CH ; CH++)
+                       OPL_CALC_CH(CH);
+               /* Rythn part */
+               if(rhythm)
+                       OPL_CALC_RH(S_CH);
+               /* limit check */
+               data = Limit( outd[0] , OPL_MAXOUT, OPL_MINOUT );
+               /* store to sound buffer */
+               buf[i] = data >> OPL_OUTSB;
+       }
+
+       OPL->amsCnt = amsCnt;
+       OPL->vibCnt = vibCnt;
+#ifdef OPL_OUTPUT_LOG
+       if(opl_dbg_fp)
+       {
+               for(opl_dbg_chip=0;opl_dbg_chip<opl_dbg_maxchip;opl_dbg_chip++)
+                       if( opl_dbg_opl[opl_dbg_chip] == OPL) break;
+               fprintf(opl_dbg_fp,"%c%c%c",0x20+opl_dbg_chip,length&0xff,length/256);
+       }
+#endif
+}
+#endif /* (BUILD_YM3812 || BUILD_YM3526) */
+
+#if BUILD_Y8950
+
+void Y8950UpdateOne(FM_OPL *OPL, INT16 *buffer, int length)
+{
+    int i;
+       int data;
+       OPLSAMPLE *buf = buffer;
+       UINT32 amsCnt  = OPL->amsCnt;
+       UINT32 vibCnt  = OPL->vibCnt;
+       UINT8 rhythm = OPL->rhythm&0x20;
+       OPL_CH *CH,*R_CH;
+       YM_DELTAT *DELTAT = OPL->deltat;
+
+       /* setup DELTA-T unit */
+       YM_DELTAT_DECODE_PRESET(DELTAT);
+
+       if( (void *)OPL != cur_chip ){
+               cur_chip = (void *)OPL;
+               /* channel pointers */
+               S_CH = OPL->P_CH;
+               E_CH = &S_CH[9];
+               /* rhythm slot */
+               SLOT7_1 = &S_CH[7].SLOT[SLOT1];
+               SLOT7_2 = &S_CH[7].SLOT[SLOT2];
+               SLOT8_1 = &S_CH[8].SLOT[SLOT1];
+               SLOT8_2 = &S_CH[8].SLOT[SLOT2];
+               /* LFO state */
+               amsIncr = OPL->amsIncr;
+               vibIncr = OPL->vibIncr;
+               ams_table = OPL->ams_table;
+               vib_table = OPL->vib_table;
+       }
+       R_CH = rhythm ? &S_CH[6] : E_CH;
+    for( i=0; i < length ; i++ )
+       {
+               /*            channel A         channel B         channel C      */
+               /* LFO */
+               ams = ams_table[(amsCnt+=amsIncr)>>AMS_SHIFT];
+               vib = vib_table[(vibCnt+=vibIncr)>>VIB_SHIFT];
+               outd[0] = 0;
+               /* deltaT ADPCM */
+               if( DELTAT->portstate )
+                       YM_DELTAT_ADPCM_CALC(DELTAT);
+               /* FM part */
+               for(CH=S_CH ; CH < R_CH ; CH++)
+                       OPL_CALC_CH(CH);
+               /* Rythn part */
+               if(rhythm)
+                       OPL_CALC_RH(S_CH);
+               /* limit check */
+               data = Limit( outd[0] , OPL_MAXOUT, OPL_MINOUT );
+               /* store to sound buffer */
+               buf[i] = data >> OPL_OUTSB;
+       }
+       OPL->amsCnt = amsCnt;
+       OPL->vibCnt = vibCnt;
+       /* deltaT START flag */
+       if( !DELTAT->portstate )
+               OPL->status &= 0xfe;
+}
+#endif
+
+/* ---------- reset one of chip ---------- */
+void OPLResetChip(FM_OPL *OPL)
+{
+       int c,s;
+       int i;
+
+       /* reset chip */
+       OPL->mode   = 0;        /* normal mode */
+       OPL_STATUS_RESET(OPL,0x7f);
+       /* reset with register write */
+       OPLWriteReg(OPL,0x01,0); /* wabesel disable */
+       OPLWriteReg(OPL,0x02,0); /* Timer1 */
+       OPLWriteReg(OPL,0x03,0); /* Timer2 */
+       OPLWriteReg(OPL,0x04,0); /* IRQ mask clear */
+       for(i = 0xff ; i >= 0x20 ; i-- ) OPLWriteReg(OPL,i,0);
+       /* reset OPerator paramater */
+       for( c = 0 ; c < OPL->max_ch ; c++ )
+       {
+               OPL_CH *CH = &OPL->P_CH[c];
+               /* OPL->P_CH[c].PAN = OPN_CENTER; */
+               for(s = 0 ; s < 2 ; s++ )
+               {
+                       /* wave table */
+                       CH->SLOT[s].wavetable = &SIN_TABLE[0];
+                       /* CH->SLOT[s].evm = ENV_MOD_RR; */
+                       CH->SLOT[s].evc = EG_OFF;
+                       CH->SLOT[s].eve = EG_OFF+1;
+                       CH->SLOT[s].evs = 0;
+               }
+       }
+#if BUILD_Y8950
+       if(OPL->type&OPL_TYPE_ADPCM)
+       {
+               YM_DELTAT *DELTAT = OPL->deltat;
+
+               DELTAT->freqbase = OPL->freqbase;
+               DELTAT->output_pointer = outd;
+               DELTAT->portshift = 5;
+               DELTAT->output_range = DELTAT_MIXING_LEVEL<<TL_BITS;
+               YM_DELTAT_ADPCM_Reset(DELTAT,0);
+       }
+#endif
+}
+
+/* ----------  Create one of vietual YM3812 ----------       */
+/* 'rate'  is sampling rate and 'bufsiz' is the size of the  */
+FM_OPL *OPLCreate(int type, int clock, int rate)
+{
+       char *ptr;
+       FM_OPL *OPL;
+       int state_size;
+       int max_ch = 9; /* normaly 9 channels */
+
+       if( OPL_LockTable() ==-1) return NULL;
+       /* allocate OPL state space */
+       state_size  = sizeof(FM_OPL);
+       state_size += sizeof(OPL_CH)*max_ch;
+#if BUILD_Y8950
+       if(type&OPL_TYPE_ADPCM) state_size+= sizeof(YM_DELTAT);
+#endif
+       /* allocate memory block */
+       ptr = malloc(state_size);
+       if(ptr==NULL) return NULL;
+       /* clear */
+       memset(ptr,0,state_size);
+       OPL        = (FM_OPL *)ptr; ptr+=sizeof(FM_OPL);
+       OPL->P_CH  = (OPL_CH *)ptr; ptr+=sizeof(OPL_CH)*max_ch;
+#if BUILD_Y8950
+       if(type&OPL_TYPE_ADPCM) OPL->deltat = (YM_DELTAT *)ptr; ptr+=sizeof(YM_DELTAT);
+#endif
+       /* set channel state pointer */
+       OPL->type  = type;
+       OPL->clock = clock;
+       OPL->rate  = rate;
+       OPL->max_ch = max_ch;
+       /* init grobal tables */
+       OPL_initialize(OPL);
+       /* reset chip */
+       OPLResetChip(OPL);
+#ifdef OPL_OUTPUT_LOG
+       if(!opl_dbg_fp)
+       {
+               opl_dbg_fp = fopen("opllog.opl","wb");
+               opl_dbg_maxchip = 0;
+       }
+       if(opl_dbg_fp)
+       {
+               opl_dbg_opl[opl_dbg_maxchip] = OPL;
+               fprintf(opl_dbg_fp,"%c%c%c%c%c%c",0x00+opl_dbg_maxchip,
+                       type,
+                       clock&0xff,
+                       (clock/0x100)&0xff,
+                       (clock/0x10000)&0xff,
+                       (clock/0x1000000)&0xff);
+               opl_dbg_maxchip++;
+       }
+#endif
+       return OPL;
+}
+
+/* ----------  Destroy one of vietual YM3812 ----------       */
+void OPLDestroy(FM_OPL *OPL)
+{
+#ifdef OPL_OUTPUT_LOG
+       if(opl_dbg_fp)
+       {
+               fclose(opl_dbg_fp);
+               opl_dbg_fp = NULL;
+       }
+#endif
+       OPL_UnLockTable();
+       free(OPL);
+}
+
+/* ----------  Option handlers ----------       */
+
+void OPLSetTimerHandler(FM_OPL *OPL,OPL_TIMERHANDLER TimerHandler,int channelOffset)
+{
+       OPL->TimerHandler   = TimerHandler;
+       OPL->TimerParam = channelOffset;
+}
+void OPLSetIRQHandler(FM_OPL *OPL,OPL_IRQHANDLER IRQHandler,int param)
+{
+       OPL->IRQHandler     = IRQHandler;
+       OPL->IRQParam = param;
+}
+void OPLSetUpdateHandler(FM_OPL *OPL,OPL_UPDATEHANDLER UpdateHandler,int param)
+{
+       OPL->UpdateHandler = UpdateHandler;
+       OPL->UpdateParam = param;
+}
+#if BUILD_Y8950
+void OPLSetPortHandler(FM_OPL *OPL,OPL_PORTHANDLER_W PortHandler_w,OPL_PORTHANDLER_R PortHandler_r,int param)
+{
+       OPL->porthandler_w = PortHandler_w;
+       OPL->porthandler_r = PortHandler_r;
+       OPL->port_param = param;
+}
+
+void OPLSetKeyboardHandler(FM_OPL *OPL,OPL_PORTHANDLER_W KeyboardHandler_w,OPL_PORTHANDLER_R KeyboardHandler_r,int param)
+{
+       OPL->keyboardhandler_w = KeyboardHandler_w;
+       OPL->keyboardhandler_r = KeyboardHandler_r;
+       OPL->keyboard_param = param;
+}
+#endif
+/* ---------- YM3812 I/O interface ---------- */
+int OPLWrite(FM_OPL *OPL,int a,int v)
+{
+       if( !(a&1) )
+       {       /* address port */
+               OPL->address = v & 0xff;
+       }
+       else
+       {       /* data port */
+               if(OPL->UpdateHandler) OPL->UpdateHandler(OPL->UpdateParam,0);
+#ifdef OPL_OUTPUT_LOG
+       if(opl_dbg_fp)
+       {
+               for(opl_dbg_chip=0;opl_dbg_chip<opl_dbg_maxchip;opl_dbg_chip++)
+                       if( opl_dbg_opl[opl_dbg_chip] == OPL) break;
+               fprintf(opl_dbg_fp,"%c%c%c",0x10+opl_dbg_chip,OPL->address,v);
+       }
+#endif
+               OPLWriteReg(OPL,OPL->address,v);
+       }
+       return OPL->status>>7;
+}
+
+unsigned char OPLRead(FM_OPL *OPL,int a)
+{
+       if( !(a&1) )
+       {       /* status port */
+               return OPL->status & (OPL->statusmask|0x80);
+       }
+       /* data port */
+       switch(OPL->address)
+       {
+       case 0x05: /* KeyBoard IN */
+               if(OPL->type&OPL_TYPE_KEYBOARD)
+               {
+                       if(OPL->keyboardhandler_r)
+                               return OPL->keyboardhandler_r(OPL->keyboard_param);
+                       else {
+                               LOG(LOG_WAR,("OPL:read unmapped KEYBOARD port\n"));
+                       }
+               }
+               return 0;
+#if 0
+       case 0x0f: /* ADPCM-DATA  */
+               return 0;
+#endif
+       case 0x19: /* I/O DATA    */
+               if(OPL->type&OPL_TYPE_IO)
+               {
+                       if(OPL->porthandler_r)
+                               return OPL->porthandler_r(OPL->port_param);
+                       else {
+                               LOG(LOG_WAR,("OPL:read unmapped I/O port\n"));
+                       }
+               }
+               return 0;
+       case 0x1a: /* PCM-DATA    */
+               return 0;
+       }
+       return 0;
+}
+
+int OPLTimerOver(FM_OPL *OPL,int c)
+{
+       if( c )
+       {       /* Timer B */
+               OPL_STATUS_SET(OPL,0x20);
+       }
+       else
+       {       /* Timer A */
+               OPL_STATUS_SET(OPL,0x40);
+               /* CSM mode key,TL control */
+               if( OPL->mode & 0x80 )
+               {       /* CSM mode total level latch and auto key on */
+                       int ch;
+                       if(OPL->UpdateHandler) OPL->UpdateHandler(OPL->UpdateParam,0);
+                       for(ch=0;ch<9;ch++)
+                               CSMKeyControll( &OPL->P_CH[ch] );
+               }
+       }
+       /* reload timer */
+       if (OPL->TimerHandler) (OPL->TimerHandler)(OPL->TimerParam+c,(double)OPL->T[c]*OPL->TimerBase);
+       return OPL->status>>7;
+}
diff --git a/hw/audio/fmopl.h b/hw/audio/fmopl.h
new file mode 100644 (file)
index 0000000..24ba5f4
--- /dev/null
@@ -0,0 +1,174 @@
+#ifndef __FMOPL_H_
+#define __FMOPL_H_
+
+/* --- select emulation chips --- */
+#define BUILD_YM3812 (HAS_YM3812)
+//#define BUILD_YM3526 (HAS_YM3526)
+//#define BUILD_Y8950  (HAS_Y8950)
+
+/* --- system optimize --- */
+/* select bit size of output : 8 or 16 */
+#define OPL_OUTPUT_BIT 16
+
+/* compiler dependence */
+#ifndef OSD_CPU_H
+#define OSD_CPU_H
+typedef unsigned char  UINT8;   /* unsigned  8bit */
+typedef unsigned short UINT16;  /* unsigned 16bit */
+typedef unsigned int   UINT32;  /* unsigned 32bit */
+typedef signed char            INT8;    /* signed  8bit   */
+typedef signed short   INT16;   /* signed 16bit   */
+typedef signed int             INT32;   /* signed 32bit   */
+#endif
+
+#if (OPL_OUTPUT_BIT==16)
+typedef INT16 OPLSAMPLE;
+#endif
+#if (OPL_OUTPUT_BIT==8)
+typedef unsigned char  OPLSAMPLE;
+#endif
+
+
+#if BUILD_Y8950
+#include "ymdeltat.h"
+#endif
+
+typedef void (*OPL_TIMERHANDLER)(int channel,double interval_Sec);
+typedef void (*OPL_IRQHANDLER)(int param,int irq);
+typedef void (*OPL_UPDATEHANDLER)(int param,int min_interval_us);
+typedef void (*OPL_PORTHANDLER_W)(int param,unsigned char data);
+typedef unsigned char (*OPL_PORTHANDLER_R)(int param);
+
+/* !!!!! here is private section , do not access there member direct !!!!! */
+
+#define OPL_TYPE_WAVESEL   0x01  /* waveform select    */
+#define OPL_TYPE_ADPCM     0x02  /* DELTA-T ADPCM unit */
+#define OPL_TYPE_KEYBOARD  0x04  /* keyboard interface */
+#define OPL_TYPE_IO        0x08  /* I/O port */
+
+/* Saving is necessary for member of the 'R' mark for suspend/resume */
+/* ---------- OPL one of slot  ---------- */
+typedef struct fm_opl_slot {
+       INT32 TL;               /* total level     :TL << 8            */
+       INT32 TLL;              /* adjusted now TL                     */
+       UINT8  KSR;             /* key scale rate  :(shift down bit)   */
+       INT32 *AR;              /* attack rate     :&AR_TABLE[AR<<2]   */
+       INT32 *DR;              /* decay rate      :&DR_TALBE[DR<<2]   */
+       INT32 SL;               /* sustin level    :SL_TALBE[SL]       */
+       INT32 *RR;              /* release rate    :&DR_TABLE[RR<<2]   */
+       UINT8 ksl;              /* keyscale level  :(shift down bits)  */
+       UINT8 ksr;              /* key scale rate  :kcode>>KSR         */
+       UINT32 mul;             /* multiple        :ML_TABLE[ML]       */
+       UINT32 Cnt;             /* frequency count :                   */
+       UINT32 Incr;    /* frequency step  :                   */
+       /* envelope generator state */
+       UINT8 eg_typ;   /* envelope type flag                  */
+       UINT8 evm;              /* envelope phase                      */
+       INT32 evc;              /* envelope counter                    */
+       INT32 eve;              /* envelope counter end point          */
+       INT32 evs;              /* envelope counter step               */
+       INT32 evsa;     /* envelope step for AR :AR[ksr]           */
+       INT32 evsd;     /* envelope step for DR :DR[ksr]           */
+       INT32 evsr;     /* envelope step for RR :RR[ksr]           */
+       /* LFO */
+       UINT8 ams;              /* ams flag                            */
+       UINT8 vib;              /* vibrate flag                        */
+       /* wave selector */
+       INT32 **wavetable;
+}OPL_SLOT;
+
+/* ---------- OPL one of channel  ---------- */
+typedef struct fm_opl_channel {
+       OPL_SLOT SLOT[2];
+       UINT8 CON;                      /* connection type                     */
+       UINT8 FB;                       /* feed back       :(shift down bit)   */
+       INT32 *connect1;        /* slot1 output pointer                */
+       INT32 *connect2;        /* slot2 output pointer                */
+       INT32 op1_out[2];       /* slot1 output for selfeedback        */
+       /* phase generator state */
+       UINT32  block_fnum;     /* block+fnum      :                   */
+       UINT8 kcode;            /* key code        : KeyScaleCode      */
+       UINT32  fc;                     /* Freq. Increment base                */
+       UINT32  ksl_base;       /* KeyScaleLevel Base step             */
+       UINT8 keyon;            /* key on/off flag                     */
+} OPL_CH;
+
+/* OPL state */
+typedef struct fm_opl_f {
+       UINT8 type;                     /* chip type                         */
+       int clock;                      /* master clock  (Hz)                */
+       int rate;                       /* sampling rate (Hz)                */
+       double freqbase;        /* frequency base                    */
+       double TimerBase;       /* Timer base time (==sampling time) */
+       UINT8 address;          /* address register                  */
+       UINT8 status;           /* status flag                       */
+       UINT8 statusmask;       /* status mask                       */
+       UINT32 mode;            /* Reg.08 : CSM , notesel,etc.       */
+       /* Timer */
+       int T[2];                       /* timer counter                     */
+       UINT8 st[2];            /* timer enable                      */
+       /* FM channel slots */
+       OPL_CH *P_CH;           /* pointer of CH                     */
+       int     max_ch;                 /* maximum channel                   */
+       /* Rhythm sention */
+       UINT8 rhythm;           /* Rhythm mode , key flag */
+#if BUILD_Y8950
+       /* Delta-T ADPCM unit (Y8950) */
+       YM_DELTAT *deltat;                      /* DELTA-T ADPCM       */
+#endif
+       /* Keyboard / I/O interface unit (Y8950) */
+       UINT8 portDirection;
+       UINT8 portLatch;
+       OPL_PORTHANDLER_R porthandler_r;
+       OPL_PORTHANDLER_W porthandler_w;
+       int port_param;
+       OPL_PORTHANDLER_R keyboardhandler_r;
+       OPL_PORTHANDLER_W keyboardhandler_w;
+       int keyboard_param;
+       /* time tables */
+       INT32 AR_TABLE[75];     /* atttack rate tables */
+       INT32 DR_TABLE[75];     /* decay rate tables   */
+       UINT32 FN_TABLE[1024];  /* fnumber -> increment counter */
+       /* LFO */
+       INT32 *ams_table;
+       INT32 *vib_table;
+       INT32 amsCnt;
+       INT32 amsIncr;
+       INT32 vibCnt;
+       INT32 vibIncr;
+       /* wave selector enable flag */
+       UINT8 wavesel;
+       /* external event callback handler */
+       OPL_TIMERHANDLER  TimerHandler;         /* TIMER handler   */
+       int TimerParam;                                         /* TIMER parameter */
+       OPL_IRQHANDLER    IRQHandler;           /* IRQ handler    */
+       int IRQParam;                                           /* IRQ parameter  */
+       OPL_UPDATEHANDLER UpdateHandler;        /* stream update handler   */
+       int UpdateParam;                                        /* stream update parameter */
+} FM_OPL;
+
+/* ---------- Generic interface section ---------- */
+#define OPL_TYPE_YM3526 (0)
+#define OPL_TYPE_YM3812 (OPL_TYPE_WAVESEL)
+#define OPL_TYPE_Y8950  (OPL_TYPE_ADPCM|OPL_TYPE_KEYBOARD|OPL_TYPE_IO)
+
+FM_OPL *OPLCreate(int type, int clock, int rate);
+void OPLDestroy(FM_OPL *OPL);
+void OPLSetTimerHandler(FM_OPL *OPL,OPL_TIMERHANDLER TimerHandler,int channelOffset);
+void OPLSetIRQHandler(FM_OPL *OPL,OPL_IRQHANDLER IRQHandler,int param);
+void OPLSetUpdateHandler(FM_OPL *OPL,OPL_UPDATEHANDLER UpdateHandler,int param);
+/* Y8950 port handlers */
+void OPLSetPortHandler(FM_OPL *OPL,OPL_PORTHANDLER_W PortHandler_w,OPL_PORTHANDLER_R PortHandler_r,int param);
+void OPLSetKeyboardHandler(FM_OPL *OPL,OPL_PORTHANDLER_W KeyboardHandler_w,OPL_PORTHANDLER_R KeyboardHandler_r,int param);
+
+void OPLResetChip(FM_OPL *OPL);
+int OPLWrite(FM_OPL *OPL,int a,int v);
+unsigned char OPLRead(FM_OPL *OPL,int a);
+int OPLTimerOver(FM_OPL *OPL,int c);
+
+/* YM3626/YM3812 local section */
+void YM3812UpdateOne(FM_OPL *OPL, INT16 *buffer, int length);
+
+void Y8950UpdateOne(FM_OPL *OPL, INT16 *buffer, int length);
+
+#endif
diff --git a/hw/audio/gus.c b/hw/audio/gus.c
new file mode 100644 (file)
index 0000000..0604d6e
--- /dev/null
@@ -0,0 +1,332 @@
+/*
+ * QEMU Proxy for Gravis Ultrasound GF1 emulation by Tibor "TS" Schütz
+ *
+ * Copyright (c) 2002-2005 Vassili Karpov (malc)
+ *
+ * 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 "hw/hw.h"
+#include "hw/audio/audio.h"
+#include "audio/audio.h"
+#include "hw/isa/isa.h"
+#include "gusemu.h"
+#include "gustate.h"
+
+#define dolog(...) AUD_log ("audio", __VA_ARGS__)
+#ifdef DEBUG
+#define ldebug(...) dolog (__VA_ARGS__)
+#else
+#define ldebug(...)
+#endif
+
+#ifdef HOST_WORDS_BIGENDIAN
+#define GUS_ENDIANNESS 1
+#else
+#define GUS_ENDIANNESS 0
+#endif
+
+#define IO_READ_PROTO(name) \
+    static uint32_t name (void *opaque, uint32_t nport)
+#define IO_WRITE_PROTO(name) \
+    static void name (void *opaque, uint32_t nport, uint32_t val)
+
+typedef struct GUSState {
+    ISADevice dev;
+    GUSEmuState emu;
+    QEMUSoundCard card;
+    uint32_t freq;
+    uint32_t port;
+    int pos, left, shift, irqs;
+    GUSsample *mixbuf;
+    uint8_t himem[1024 * 1024 + 32 + 4096];
+    int samples;
+    SWVoiceOut *voice;
+    int64_t last_ticks;
+    qemu_irq pic;
+} GUSState;
+
+IO_READ_PROTO (gus_readb)
+{
+    GUSState *s = opaque;
+
+    return gus_read (&s->emu, nport, 1);
+}
+
+IO_READ_PROTO (gus_readw)
+{
+    GUSState *s = opaque;
+
+    return gus_read (&s->emu, nport, 2);
+}
+
+IO_WRITE_PROTO (gus_writeb)
+{
+    GUSState *s = opaque;
+
+    gus_write (&s->emu, nport, 1, val);
+}
+
+IO_WRITE_PROTO (gus_writew)
+{
+    GUSState *s = opaque;
+
+    gus_write (&s->emu, nport, 2, val);
+}
+
+static int write_audio (GUSState *s, int samples)
+{
+    int net = 0;
+    int pos = s->pos;
+
+    while (samples) {
+        int nbytes, wbytes, wsampl;
+
+        nbytes = samples << s->shift;
+        wbytes = AUD_write (
+            s->voice,
+            s->mixbuf + (pos << (s->shift - 1)),
+            nbytes
+            );
+
+        if (wbytes) {
+            wsampl = wbytes >> s->shift;
+
+            samples -= wsampl;
+            pos = (pos + wsampl) % s->samples;
+
+            net += wsampl;
+        }
+        else {
+            break;
+        }
+    }
+
+    return net;
+}
+
+static void GUS_callback (void *opaque, int free)
+{
+    int samples, to_play, net = 0;
+    GUSState *s = opaque;
+
+    samples = free >> s->shift;
+    to_play = audio_MIN (samples, s->left);
+
+    while (to_play) {
+        int written = write_audio (s, to_play);
+
+        if (!written) {
+            goto reset;
+        }
+
+        s->left -= written;
+        to_play -= written;
+        samples -= written;
+        net += written;
+    }
+
+    samples = audio_MIN (samples, s->samples);
+    if (samples) {
+        gus_mixvoices (&s->emu, s->freq, samples, s->mixbuf);
+
+        while (samples) {
+            int written = write_audio (s, samples);
+            if (!written) {
+                break;
+            }
+            samples -= written;
+            net += written;
+        }
+    }
+    s->left = samples;
+
+ reset:
+    gus_irqgen (&s->emu, muldiv64 (net, 1000000, s->freq));
+}
+
+int GUS_irqrequest (GUSEmuState *emu, int hwirq, int n)
+{
+    GUSState *s = emu->opaque;
+    /* qemu_irq_lower (s->pic); */
+    qemu_irq_raise (s->pic);
+    s->irqs += n;
+    ldebug ("irqrequest %d %d %d\n", hwirq, n, s->irqs);
+    return n;
+}
+
+void GUS_irqclear (GUSEmuState *emu, int hwirq)
+{
+    GUSState *s = emu->opaque;
+    ldebug ("irqclear %d %d\n", hwirq, s->irqs);
+    qemu_irq_lower (s->pic);
+    s->irqs -= 1;
+#ifdef IRQ_STORM
+    if (s->irqs > 0) {
+        qemu_irq_raise (s->pic[hwirq]);
+    }
+#endif
+}
+
+void GUS_dmarequest (GUSEmuState *der)
+{
+    /* GUSState *s = (GUSState *) der; */
+    ldebug ("dma request %d\n", der->gusdma);
+    DMA_hold_DREQ (der->gusdma);
+}
+
+static int GUS_read_DMA (void *opaque, int nchan, int dma_pos, int dma_len)
+{
+    GUSState *s = opaque;
+    char tmpbuf[4096];
+    int pos = dma_pos, mode, left = dma_len - dma_pos;
+
+    ldebug ("read DMA %#x %d\n", dma_pos, dma_len);
+    mode = DMA_get_channel_mode (s->emu.gusdma);
+    while (left) {
+        int to_copy = audio_MIN ((size_t) left, sizeof (tmpbuf));
+        int copied;
+
+        ldebug ("left=%d to_copy=%d pos=%d\n", left, to_copy, pos);
+        copied = DMA_read_memory (nchan, tmpbuf, pos, to_copy);
+        gus_dma_transferdata (&s->emu, tmpbuf, copied, left == copied);
+        left -= copied;
+        pos += copied;
+    }
+
+    if (0 == ((mode >> 4) & 1)) {
+        DMA_release_DREQ (s->emu.gusdma);
+    }
+    return dma_len;
+}
+
+static const VMStateDescription vmstate_gus = {
+    .name = "gus",
+    .version_id = 2,
+    .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 ()
+    }
+};
+
+static const MemoryRegionPortio gus_portio_list1[] = {
+    {0x000,  1, 1, .write = gus_writeb },
+    {0x000,  1, 2, .write = gus_writew },
+    {0x006, 10, 1, .read = gus_readb, .write = gus_writeb },
+    {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 (),
+};
+
+static const MemoryRegionPortio gus_portio_list2[] = {
+    {0, 1, 1, .read = gus_readb },
+    {0, 1, 2, .read = gus_readw },
+    PORTIO_END_OF_LIST (),
+};
+
+static int gus_initfn (ISADevice *dev)
+{
+    GUSState *s = DO_UPCAST (GUSState, dev, dev);
+    struct audsettings as;
+
+    AUD_register_card ("gus", &s->card);
+
+    as.freq = s->freq;
+    as.nchannels = 2;
+    as.fmt = AUD_FMT_S16;
+    as.endianness = GUS_ENDIANNESS;
+
+    s->voice = AUD_open_out (
+        &s->card,
+        NULL,
+        "gus",
+        s,
+        GUS_callback,
+        &as
+        );
+
+    if (!s->voice) {
+        AUD_remove_card (&s->card);
+        return -1;
+    }
+
+    s->shift = 2;
+    s->samples = AUD_get_buffer_size_out (s->voice) >> s->shift;
+    s->mixbuf = g_malloc0 (s->samples << s->shift);
+
+    isa_register_portio_list (dev, s->port, gus_portio_list1, s, "gus");
+    isa_register_portio_list (dev, (s->port + 0x100) & 0xf00,
+                              gus_portio_list2, s, "gus");
+
+    DMA_register_channel (s->emu.gusdma, GUS_read_DMA, s);
+    s->emu.himemaddr = s->himem;
+    s->emu.gusdatapos = s->emu.himemaddr + 1024 * 1024 + 32;
+    s->emu.opaque = s;
+    isa_init_irq (dev, &s->pic, s->emu.gusirq);
+
+    AUD_set_active_out (s->voice, 1);
+
+    return 0;
+}
+
+int GUS_init (ISABus *bus)
+{
+    isa_create_simple (bus, "gus");
+    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 const TypeInfo gus_info = {
+    .name          = "gus",
+    .parent        = TYPE_ISA_DEVICE,
+    .instance_size = sizeof (GUSState),
+    .class_init    = gus_class_initfn,
+};
+
+static void gus_register_types (void)
+{
+    type_register_static (&gus_info);
+}
+
+type_init (gus_register_types)
diff --git a/hw/audio/gusemu.h b/hw/audio/gusemu.h
new file mode 100644 (file)
index 0000000..331bb6f
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * GUSEMU32 - API
+ *
+ * Copyright (C) 2000-2007 Tibor "TS" Schütz
+ *
+ * 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 GUSEMU_H
+#define GUSEMU_H
+
+/* data types (need to be adjusted if neither a VC6 nor a C99 compatible compiler is used) */
+
+#if defined _WIN32 && defined _MSC_VER /* doesn't support other win32 compilers yet, do it yourself... */
+ typedef unsigned char GUSbyte;
+ typedef unsigned short GUSword;
+ typedef unsigned int GUSdword;
+ typedef signed char GUSchar;
+ typedef signed short GUSsample;
+#else
+ #include <stdint.h>
+ typedef int8_t GUSchar;
+ typedef uint8_t GUSbyte;
+ typedef uint16_t GUSword;
+ typedef uint32_t GUSdword;
+ typedef int16_t GUSsample;
+#endif
+
+typedef struct _GUSEmuState
+{
+ GUSbyte *himemaddr; /* 1024*1024 bytes used for storing uploaded samples (+32 additional bytes for read padding) */
+ GUSbyte *gusdatapos; /* (gusdataend-gusdata) bytes used for storing emulated GF1/mixer register states (32*32+4 bytes in initial GUSemu32 version) */
+ uint32_t gusirq;
+ uint32_t gusdma;
+ unsigned int timer1fraction;
+ unsigned int timer2fraction;
+ void *opaque;
+} GUSEmuState;
+
+/* ** Callback functions needed: */
+/* NMI is defined as hwirq=-1 (not supported (yet?)) */
+/* GUS_irqrequest returns the number of IRQs actually scheduled into the virtual machine */
+/* Level triggered IRQ simulations normally return 1 */
+/* Event triggered IRQ simulation can safely ignore GUS_irqclear calls */
+int  GUS_irqrequest(GUSEmuState *state, int hwirq, int num);/* needed in both mixer and bus emulation functions. */
+void GUS_irqclear(  GUSEmuState *state, int hwirq); /* used by gus_write() only - can be left empty for mixer functions */
+void GUS_dmarequest(GUSEmuState *state);            /* used by gus_write() only - can be left empty for mixer functions */
+
+/* ** ISA bus interface functions: */
+
+/* Port I/O handlers */
+/* support the following ports: */
+/* 2x0,2x6,2x8...2xF,3x0...3x7;  */
+/* optional: 388,389 (at least writes should be forwarded or some GUS detection algorithms will fail) */
+/* data is passed in host byte order */
+unsigned int gus_read( GUSEmuState *state, int port, int size);
+void         gus_write(GUSEmuState *state, int port, int size, unsigned int data);
+/* size is given in bytes (1 for byte, 2 for word) */
+
+/* DMA data transfer function */
+/* data pointed to is passed in native x86 order */
+void gus_dma_transferdata(GUSEmuState *state, char *dma_addr, unsigned int count, int TC);
+/* Called back by GUS_start_DMA as soon as the emulated DMA controller is ready for a transfer to or from GUS */
+/* (might be immediately if the DMA controller was programmed first) */
+/* dma_addr is an already translated address directly pointing to the beginning of the memory block */
+/* do not forget to update DMA states after the call, including the DREQ and TC flags */
+/* it is possible to break down a single transfer into multiple ones, but take care that: */
+/* -dma_count is actually count-1 */
+/* -before and during a transfer, DREQ is set and TC cleared */
+/* -when calling gus_dma_transferdata(), TC is only set true for call transferring the last byte */
+/* -after the last transfer, DREQ is cleared and TC is set */
+
+/* ** GF1 mixer emulation functions: */
+/* Usually, gus_irqgen should be called directly after gus_mixvoices if you can meet the recommended ranges. */
+/* If the interrupts are executed immediately (i.e., are synchronous), it may be useful to break this */
+/* down into a sequence of gus_mixvoice();gus_irqgen(); calls while mixing an audio block. */
+/* If the interrupts are asynchronous, it may be needed to use a separate thread mixing into a temporary */
+/* audio buffer in order to avoid quality loss caused by large numsamples and elapsed_time values. */
+
+void gus_mixvoices(GUSEmuState *state, unsigned int playback_freq, unsigned int numsamples, GUSsample *bufferpos);
+/* recommended range: 10 < numsamples < 100 */
+/* lower values may result in increased rounding error, higher values often cause audible timing delays */
+
+void gus_irqgen(GUSEmuState *state, unsigned int elapsed_time);
+/* recommended range: 80us < elapsed_time < max(1000us, numsamples/playback_freq) */
+/* lower values won´t provide any benefit at all, higher values can cause audible timing delays */
+/* note: masked timers are also calculated by this function, thus it might be needed even without any IRQs in use! */
+
+#endif  /* gusemu.h */
diff --git a/hw/audio/gusemu_hal.c b/hw/audio/gusemu_hal.c
new file mode 100644 (file)
index 0000000..6096690
--- /dev/null
@@ -0,0 +1,554 @@
+/*
+ * GUSEMU32 - bus interface part
+ *
+ * Copyright (C) 2000-2007 Tibor "TS" Schütz
+ *
+ * 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.
+ */
+
+/*
+ * TODO: check mixer: see 7.20 of sdk for panning pos (applies to all gus models?)?
+ */
+
+#include "gustate.h"
+#include "gusemu.h"
+
+#define GUSregb(position) (*            (gusptr+(position)))
+#define GUSregw(position) (*(GUSword *) (gusptr+(position)))
+#define GUSregd(position) (*(GUSdword *)(gusptr+(position)))
+
+/* size given in bytes */
+unsigned int gus_read(GUSEmuState * state, int port, int size)
+{
+    int             value_read = 0;
+
+    GUSbyte        *gusptr;
+    gusptr = state->gusdatapos;
+    GUSregd(portaccesses)++;
+
+    switch (port & 0xff0f)
+    {
+        /* MixerCtrlReg (read not supported on GUS classic) */
+        /* case 0x200: return GUSregb(MixerCtrlReg2x0); */
+    case 0x206:                          /* IRQstatReg / SB2x6IRQ */
+        /* adlib/sb bits set in port handlers */
+        /* timer/voice bits set in gus_irqgen() */
+        /* dma bit set in gus_dma_transferdata */
+        /* midi not implemented yet */
+        return GUSregb(IRQStatReg2x6);
+    /* case 0x308:                       */ /* AdLib388 */
+    case 0x208:
+        if (GUSregb(GUS45TimerCtrl) & 1)
+            return GUSregb(TimerStatus2x8);
+        return GUSregb(AdLibStatus2x8);  /* AdLibStatus */
+    case 0x309:                          /* AdLib389 */
+    case 0x209:
+        return GUSregb(AdLibData2x9);    /* AdLibData */
+    case 0x20A:
+        return GUSregb(AdLibCommand2xA); /* AdLib2x8_2xA */
+
+#if 0
+    case 0x20B:                          /* GUS hidden registers (read not supported on GUS classic) */
+        switch (GUSregb(RegCtrl_2xF) & 0x07)
+        {
+        case 0:                                 /* IRQ/DMA select */
+            if (GUSregb(MixerCtrlReg2x0) & 0x40)
+                return GUSregb(IRQ_2xB);        /* control register select bit */
+            else
+                return GUSregb(DMA_2xB);
+            /* case 1-5:                        */ /* general purpose emulation regs  */
+            /*  return ...                      */ /* + status reset reg (write only) */
+        case 6:
+            return GUSregb(Jumper_2xB);         /* Joystick/MIDI enable (JumperReg) */
+        default:;
+        }
+        break;
+#endif
+
+    case 0x20C:                          /* SB2xCd */
+        value_read = GUSregb(SB2xCd);
+        if (GUSregb(StatRead_2xF) & 0x20)
+            GUSregb(SB2xCd) ^= 0x80; /* toggle MSB on read */
+        return value_read;
+        /* case 0x20D:                   */ /* SB2xD is write only -> 2xE writes to it*/
+    case 0x20E:
+        if (GUSregb(RegCtrl_2xF) & 0x80) /* 2xE read IRQ enabled? */
+        {
+            GUSregb(StatRead_2xF) |= 0x80;
+            GUS_irqrequest(state, state->gusirq, 1);
+        }
+        return GUSregb(SB2xE);           /* SB2xE */
+    case 0x20F:                          /* StatRead_2xF */
+        /*set/clear fixed bits */
+        /*value_read = (GUSregb(StatRead_2xF) & 0xf9)|1; */ /*(LSB not set on GUS classic!)*/
+        value_read = (GUSregb(StatRead_2xF) & 0xf9);
+        if (GUSregb(MixerCtrlReg2x0) & 0x08)
+            value_read |= 2;    /* DMA/IRQ enabled flag */
+        return value_read;
+    /* case 0x300:                      */ /* MIDI (not implemented) */
+    /* case 0x301:                      */ /* MIDI (not implemented) */
+    case 0x302:
+        return GUSregb(VoiceSelReg3x2); /* VoiceSelReg */
+    case 0x303:
+        return GUSregb(FunkSelReg3x3);  /* FunkSelReg */
+    case 0x304:                         /* DataRegLoByte3x4 + DataRegWord3x4 */
+    case 0x305:                         /* DataRegHiByte3x5 */
+        switch (GUSregb(FunkSelReg3x3))
+        {
+    /* common functions */
+        case 0x41:                      /* DramDMAContrReg */
+            value_read = GUSregb(GUS41DMACtrl); /* &0xfb */
+            GUSregb(GUS41DMACtrl) &= 0xbb;
+            if (state->gusdma >= 4)
+                value_read |= 0x04;
+            if (GUSregb(IRQStatReg2x6) & 0x80)
+            {
+                value_read |= 0x40;
+                GUSregb(IRQStatReg2x6) &= 0x7f;
+                if (!GUSregb(IRQStatReg2x6))
+                    GUS_irqclear(state, state->gusirq);
+            }
+            return (GUSbyte) value_read;
+            /* DramDMAmemPosReg */
+            /* case 0x42: value_read=GUSregw(GUS42DMAStart); break;*/
+            /* 43h+44h write only */
+        case 0x45:
+            return GUSregb(GUS45TimerCtrl);         /* TimerCtrlReg */
+            /* 46h+47h write only */
+            /* 48h: samp freq - write only */
+        case 0x49:
+            return GUSregb(GUS49SampCtrl) & 0xbf;   /* SampCtrlReg */
+        /* case 4bh:                                */ /* joystick trim not supported */
+        /* case 0x4c: return GUSregb(GUS4cReset);   */ /* GUSreset: write only*/
+    /* voice specific functions */
+        case 0x80:
+        case 0x81:
+        case 0x82:
+        case 0x83:
+        case 0x84:
+        case 0x85:
+        case 0x86:
+        case 0x87:
+        case 0x88:
+        case 0x89:
+        case 0x8a:
+        case 0x8b:
+        case 0x8c:
+        case 0x8d:
+            {
+                int             offset = 2 * (GUSregb(FunkSelReg3x3) & 0x0f);
+                offset += ((int) GUSregb(VoiceSelReg3x2) & 0x1f) << 5; /* = Voice*32 + Funktion*2 */
+                value_read = GUSregw(offset);
+            }
+            break;
+    /* voice unspecific functions */
+        case 0x8e:                                  /* NumVoice */
+            return GUSregb(NumVoices);
+        case 0x8f:                                  /* irqstatreg */
+            /* (pseudo IRQ-FIFO is processed during a gus_write(0x3X3,0x8f)) */
+            return GUSregb(SynVoiceIRQ8f);
+        default:
+            return 0xffff;
+        }
+        if (size == 1)
+        {
+            if ((port & 0xff0f) == 0x305)
+                value_read = value_read >> 8;
+            value_read &= 0xff;
+        }
+        return (GUSword) value_read;
+    /* case 0x306:                                  */ /* Mixer/Version info */
+        /*  return 0xff; */ /* Pre 3.6 boards, ICS mixer NOT present */
+    case 0x307:                                     /* DRAMaccess */
+        {
+            GUSbyte        *adr;
+            adr = state->himemaddr + (GUSregd(GUSDRAMPOS24bit) & 0xfffff);
+            return *adr;
+        }
+    default:;
+    }
+    return 0xffff;
+}
+
+void gus_write(GUSEmuState * state, int port, int size, unsigned int data)
+{
+    GUSbyte        *gusptr;
+    gusptr = state->gusdatapos;
+    GUSregd(portaccesses)++;
+
+    switch (port & 0xff0f)
+    {
+    case 0x200:                 /* MixerCtrlReg */
+        GUSregb(MixerCtrlReg2x0) = (GUSbyte) data;
+        break;
+    case 0x206:                 /* IRQstatReg / SB2x6IRQ */
+        if (GUSregb(GUS45TimerCtrl) & 0x20) /* SB IRQ enabled? -> set 2x6IRQ bit */
+        {
+            GUSregb(TimerStatus2x8) |= 0x08;
+            GUSregb(IRQStatReg2x6) = 0x10;
+            GUS_irqrequest(state, state->gusirq, 1);
+        }
+        break;
+    case 0x308:                /* AdLib 388h */
+    case 0x208:                /* AdLibCommandReg */
+        GUSregb(AdLibCommand2xA) = (GUSbyte) data;
+        break;
+    case 0x309:                /* AdLib 389h */
+    case 0x209:                /* AdLibDataReg */
+        if ((GUSregb(AdLibCommand2xA) == 0x04) && (!(GUSregb(GUS45TimerCtrl) & 1))) /* GUS auto timer mode enabled? */
+        {
+            if (data & 0x80)
+                GUSregb(TimerStatus2x8) &= 0x1f; /* AdLib IRQ reset? -> clear maskable adl. timer int regs */
+            else
+                GUSregb(TimerDataReg2x9) = (GUSbyte) data;
+        }
+        else
+        {
+            GUSregb(AdLibData2x9) = (GUSbyte) data;
+            if (GUSregb(GUS45TimerCtrl) & 0x02)
+            {
+                GUSregb(TimerStatus2x8) |= 0x01;
+                GUSregb(IRQStatReg2x6) = 0x10;
+                GUS_irqrequest(state, state->gusirq, 1);
+            }
+        }
+        break;
+    case 0x20A:
+        GUSregb(AdLibStatus2x8) = (GUSbyte) data;
+        break;                 /* AdLibStatus2x8 */
+    case 0x20B:                /* GUS hidden registers */
+        switch (GUSregb(RegCtrl_2xF) & 0x7)
+        {
+        case 0:
+            if (GUSregb(MixerCtrlReg2x0) & 0x40)
+                GUSregb(IRQ_2xB) = (GUSbyte) data; /* control register select bit */
+            else
+                GUSregb(DMA_2xB) = (GUSbyte) data;
+            break;
+            /* case 1-4: general purpose emulation regs */
+        case 5:                                    /* clear stat reg 2xF */
+            GUSregb(StatRead_2xF) = 0; /* ToDo: is this identical with GUS classic? */
+            if (!GUSregb(IRQStatReg2x6))
+                GUS_irqclear(state, state->gusirq);
+            break;
+        case 6:                                    /* Jumper reg (Joystick/MIDI enable) */
+            GUSregb(Jumper_2xB) = (GUSbyte) data;
+            break;
+        default:;
+        }
+        break;
+    case 0x20C:                /* SB2xCd */
+        if (GUSregb(GUS45TimerCtrl) & 0x20)
+        {
+            GUSregb(TimerStatus2x8) |= 0x10; /* SB IRQ enabled? -> set 2xCIRQ bit */
+            GUSregb(IRQStatReg2x6) = 0x10;
+            GUS_irqrequest(state, state->gusirq, 1);
+        }
+    case 0x20D:                /* SB2xCd no IRQ */
+        GUSregb(SB2xCd) = (GUSbyte) data;
+        break;
+    case 0x20E:                /* SB2xE */
+        GUSregb(SB2xE) = (GUSbyte) data;
+        break;
+    case 0x20F:
+        GUSregb(RegCtrl_2xF) = (GUSbyte) data;
+        break;                 /* CtrlReg2xF */
+    case 0x302:                /* VoiceSelReg */
+        GUSregb(VoiceSelReg3x2) = (GUSbyte) data;
+        break;
+    case 0x303:                /* FunkSelReg */
+        GUSregb(FunkSelReg3x3) = (GUSbyte) data;
+        if ((GUSbyte) data == 0x8f) /* set irqstatreg, get voicereg and clear IRQ */
+        {
+            int             voice;
+            if (GUSregd(voicewavetableirq)) /* WavetableIRQ */
+            {
+                for (voice = 0; voice < 31; voice++)
+                {
+                    if (GUSregd(voicewavetableirq) & (1 << voice))
+                    {
+                        GUSregd(voicewavetableirq) ^= (1 << voice); /* clear IRQ bit */
+                        GUSregb(voice << 5) &= 0x7f; /* clear voice reg irq bit */
+                        if (!GUSregd(voicewavetableirq))
+                            GUSregb(IRQStatReg2x6) &= 0xdf;
+                        if (!GUSregb(IRQStatReg2x6))
+                            GUS_irqclear(state, state->gusirq);
+                        GUSregb(SynVoiceIRQ8f) = voice | 0x60; /* (bit==0 => IRQ wartend) */
+                        return;
+                    }
+                }
+            }
+            else if (GUSregd(voicevolrampirq)) /* VolRamp IRQ */
+            {
+                for (voice = 0; voice < 31; voice++)
+                {
+                    if (GUSregd(voicevolrampirq) & (1 << voice))
+                    {
+                        GUSregd(voicevolrampirq) ^= (1 << voice); /* clear IRQ bit */
+                        GUSregb((voice << 5) + VSRVolRampControl) &= 0x7f; /* clear voice volume reg irq bit */
+                        if (!GUSregd(voicevolrampirq))
+                            GUSregb(IRQStatReg2x6) &= 0xbf;
+                        if (!GUSregb(IRQStatReg2x6))
+                            GUS_irqclear(state, state->gusirq);
+                        GUSregb(SynVoiceIRQ8f) = voice | 0x80; /* (bit==0 => IRQ wartend) */
+                        return;
+                    }
+                }
+            }
+            GUSregb(SynVoiceIRQ8f) = 0xe8; /* kein IRQ wartet */
+        }
+        break;
+    case 0x304:
+    case 0x305:
+        {
+            GUSword         writedata = (GUSword) data;
+            GUSword         readmask = 0x0000;
+            if (size == 1)
+            {
+                readmask = 0xff00;
+                writedata &= 0xff;
+                if ((port & 0xff0f) == 0x305)
+                {
+                    writedata = (GUSword) (writedata << 8);
+                    readmask = 0x00ff;
+                }
+            }
+            switch (GUSregb(FunkSelReg3x3))
+            {
+                /* voice specific functions */
+            case 0x00:
+            case 0x01:
+            case 0x02:
+            case 0x03:
+            case 0x04:
+            case 0x05:
+            case 0x06:
+            case 0x07:
+            case 0x08:
+            case 0x09:
+            case 0x0a:
+            case 0x0b:
+            case 0x0c:
+            case 0x0d:
+                {
+                    int             offset;
+                    if (!(GUSregb(GUS4cReset) & 0x01))
+                        break;  /* reset flag active? */
+                    offset = 2 * (GUSregb(FunkSelReg3x3) & 0x0f);
+                    offset += (GUSregb(VoiceSelReg3x2) & 0x1f) << 5; /*  = Voice*32 + Funktion*2 */
+                    GUSregw(offset) = (GUSword) ((GUSregw(offset) & readmask) | writedata);
+                }
+                break;
+                /* voice unspecific functions */
+            case 0x0e:         /* NumVoices */
+                GUSregb(NumVoices) = (GUSbyte) data;
+                break;
+            /* case 0x0f:      */ /* read only */
+                /* common functions */
+            case 0x41:         /* DramDMAContrReg */
+                GUSregb(GUS41DMACtrl) = (GUSbyte) data;
+                if (data & 0x01)
+                    GUS_dmarequest(state);
+                break;
+            case 0x42:         /* DramDMAmemPosReg */
+                GUSregw(GUS42DMAStart) = (GUSregw(GUS42DMAStart) & readmask) | writedata;
+                GUSregb(GUS50DMAHigh) &= 0xf; /* compatibility stuff... */
+                break;
+            case 0x43:         /* DRAMaddrLo */
+                GUSregd(GUSDRAMPOS24bit) =
+                    (GUSregd(GUSDRAMPOS24bit) & (readmask | 0xff0000)) | writedata;
+                break;
+            case 0x44:         /* DRAMaddrHi */
+                GUSregd(GUSDRAMPOS24bit) =
+                    (GUSregd(GUSDRAMPOS24bit) & 0xffff) | ((data & 0x0f) << 16);
+                break;
+            case 0x45:         /* TCtrlReg */
+                GUSregb(GUS45TimerCtrl) = (GUSbyte) data;
+                if (!(data & 0x20))
+                    GUSregb(TimerStatus2x8) &= 0xe7;    /* sb IRQ dis? -> clear 2x8/2xC sb IRQ flags */
+                if (!(data & 0x02))
+                    GUSregb(TimerStatus2x8) &= 0xfe;    /* adlib data IRQ dis? -> clear 2x8 adlib IRQ flag */
+                if (!(GUSregb(TimerStatus2x8) & 0x19))
+                    GUSregb(IRQStatReg2x6) &= 0xef;     /* 0xe6; $$clear IRQ if both IRQ bits are inactive or cleared */
+                /* catch up delayed timer IRQs: */
+                if ((GUSregw(TimerIRQs) > 1) && (GUSregb(TimerDataReg2x9) & 3))
+                {
+                    if (GUSregb(TimerDataReg2x9) & 1)   /* start timer 1 (80us decrement rate) */
+                    {
+                        if (!(GUSregb(TimerDataReg2x9) & 0x40))
+                            GUSregb(TimerStatus2x8) |= 0xc0;    /* maskable bits */
+                        if (data & 4) /* timer1 irq enable */
+                        {
+                            GUSregb(TimerStatus2x8) |= 4;       /* nonmaskable bit */
+                            GUSregb(IRQStatReg2x6) |= 4;        /* timer 1 irq pending */
+                        }
+                    }
+                    if (GUSregb(TimerDataReg2x9) & 2)   /* start timer 2 (320us decrement rate) */
+                    {
+                        if (!(GUSregb(TimerDataReg2x9) & 0x20))
+                            GUSregb(TimerStatus2x8) |= 0xa0;    /* maskable bits */
+                        if (data & 8) /* timer2 irq enable */
+                        {
+                            GUSregb(TimerStatus2x8) |= 2;       /* nonmaskable bit */
+                            GUSregb(IRQStatReg2x6) |= 8;        /* timer 2 irq pending */
+                        }
+                    }
+                    GUSregw(TimerIRQs)--;
+                    if (GUSregw(BusyTimerIRQs) > 1)
+                        GUSregw(BusyTimerIRQs)--;
+                    else
+                        GUSregw(BusyTimerIRQs) =
+                            GUS_irqrequest(state, state->gusirq, GUSregw(TimerIRQs));
+                }
+                else
+                    GUSregw(TimerIRQs) = 0;
+
+                if (!(data & 0x04))
+                {
+                    GUSregb(TimerStatus2x8) &= 0xfb; /* clear non-maskable timer1 bit */
+                    GUSregb(IRQStatReg2x6)  &= 0xfb;
+                }
+                if (!(data & 0x08))
+                {
+                    GUSregb(TimerStatus2x8) &= 0xfd; /* clear non-maskable timer2 bit */
+                    GUSregb(IRQStatReg2x6)  &= 0xf7;
+                }
+                if (!GUSregb(IRQStatReg2x6))
+                    GUS_irqclear(state, state->gusirq);
+                break;
+            case 0x46:          /* Counter1 */
+                GUSregb(GUS46Counter1) = (GUSbyte) data;
+                break;
+            case 0x47:          /* Counter2 */
+                GUSregb(GUS47Counter2) = (GUSbyte) data;
+                break;
+            /* case 0x48:       */ /* sampling freq reg not emulated (same as interwave) */
+            case 0x49:          /* SampCtrlReg */
+                GUSregb(GUS49SampCtrl) = (GUSbyte) data;
+                break;
+            /* case 0x4b:       */ /* joystick trim not emulated */
+            case 0x4c:          /* GUSreset */
+                GUSregb(GUS4cReset) = (GUSbyte) data;
+                if (!(GUSregb(GUS4cReset) & 1)) /* reset... */
+                {
+                    GUSregd(voicewavetableirq) = 0;
+                    GUSregd(voicevolrampirq) = 0;
+                    GUSregw(TimerIRQs) = 0;
+                    GUSregw(BusyTimerIRQs) = 0;
+                    GUSregb(NumVoices) = 0xcd;
+                    GUSregb(IRQStatReg2x6) = 0;
+                    GUSregb(TimerStatus2x8) = 0;
+                    GUSregb(AdLibData2x9) = 0;
+                    GUSregb(TimerDataReg2x9) = 0;
+                    GUSregb(GUS41DMACtrl) = 0;
+                    GUSregb(GUS45TimerCtrl) = 0;
+                    GUSregb(GUS49SampCtrl) = 0;
+                    GUSregb(GUS4cReset) &= 0xf9; /* clear IRQ and DAC enable bits */
+                    GUS_irqclear(state, state->gusirq);
+                }
+                /* IRQ enable bit checked elsewhere */
+                /* EnableDAC bit may be used by external callers */
+                break;
+            }
+        }
+        break;
+    case 0x307:                /* DRAMaccess */
+        {
+            GUSbyte        *adr;
+            adr = state->himemaddr + (GUSregd(GUSDRAMPOS24bit) & 0xfffff);
+            *adr = (GUSbyte) data;
+        }
+        break;
+    }
+}
+
+/* Attention when breaking up a single DMA transfer to multiple ones:
+ * it may lead to multiple terminal count interrupts and broken transfers:
+ *
+ * 1. Whenever you transfer a piece of data, the gusemu callback is invoked
+ * 2. The callback may generate a TC irq (if the register was set up to do so)
+ * 3. The irq may result in the program using the GUS to reprogram the GUS
+ *
+ * Some programs also decide to upload by just checking if TC occurs
+ * (via interrupt or a cleared GUS dma flag)
+ * and then start the next transfer, without checking DMA state
+ *
+ * Thus: Always make sure to set the TC flag correctly!
+ *
+ * Note that the genuine GUS had a granularity of 16 bytes/words for low/high DMA
+ * while later cards had atomic granularity provided by an additional GUS50DMAHigh register
+ * GUSemu also uses this register to support byte-granular transfers for better compatibility
+ * with emulators other than GUSemu32
+ */
+
+void gus_dma_transferdata(GUSEmuState * state, char *dma_addr, unsigned int count, int TC)
+{
+    /* this function gets called by the callback function as soon as a DMA transfer is about to start
+     * dma_addr is a translated address within accessible memory, not the physical one,
+     * count is (real dma count register)+1
+     * note that the amount of bytes transferred is fully determined by values in the DMA registers
+     * do not forget to update DMA states after transferring the entire block:
+     * DREQ cleared & TC asserted after the _whole_ transfer */
+
+    char           *srcaddr;
+    char           *destaddr;
+    char            msbmask = 0;
+    GUSbyte        *gusptr;
+    gusptr = state->gusdatapos;
+
+    srcaddr = dma_addr; /* system memory address */
+    {
+        int             offset = (GUSregw(GUS42DMAStart) << 4) + (GUSregb(GUS50DMAHigh) & 0xf);
+        if (state->gusdma >= 4)
+            offset = (offset & 0xc0000) + (2 * (offset & 0x1fff0)); /* 16 bit address translation */
+        destaddr = (char *) state->himemaddr + offset; /* wavetable RAM address */
+    }
+
+    GUSregw(GUS42DMAStart) += (GUSword)  (count >> 4);                           /* ToDo: add 16bit GUS page limit? */
+    GUSregb(GUS50DMAHigh)   = (GUSbyte) ((count + GUSregb(GUS50DMAHigh)) & 0xf); /* ToDo: add 16bit GUS page limit? */
+
+    if (GUSregb(GUS41DMACtrl) & 0x02)   /* direction, 0 := sysram->gusram */
+    {
+        char           *tmpaddr = destaddr;
+        destaddr = srcaddr;
+        srcaddr = tmpaddr;
+    }
+
+    if ((GUSregb(GUS41DMACtrl) & 0x80) && (!(GUSregb(GUS41DMACtrl) & 0x02)))
+        msbmask = (const char) 0x80;    /* invert MSB */
+    for (; count > 0; count--)
+    {
+        if (GUSregb(GUS41DMACtrl) & 0x40)
+            *(destaddr++) = *(srcaddr++);               /* 16 bit lobyte */
+        else
+            *(destaddr++) = (msbmask ^ (*(srcaddr++))); /* 8 bit */
+        if (state->gusdma >= 4)
+            *(destaddr++) = (msbmask ^ (*(srcaddr++))); /* 16 bit hibyte */
+    }
+
+    if (TC)
+    {
+        (GUSregb(GUS41DMACtrl)) &= 0xfe;        /* clear DMA request bit */
+        if (GUSregb(GUS41DMACtrl) & 0x20)       /* DMA terminal count IRQ */
+        {
+            GUSregb(IRQStatReg2x6) |= 0x80;
+            GUS_irqrequest(state, state->gusirq, 1);
+        }
+    }
+}
diff --git a/hw/audio/gusemu_mixer.c b/hw/audio/gusemu_mixer.c
new file mode 100644 (file)
index 0000000..6d8d9ce
--- /dev/null
@@ -0,0 +1,240 @@
+/*
+ * GUSEMU32 - mixing engine (similar to Interwave GF1 compatibility)
+ *
+ * Copyright (C) 2000-2007 Tibor "TS" Schütz
+ *
+ * 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 "gusemu.h"
+#include "gustate.h"
+
+#define GUSregb(position)  (*            (gusptr+(position)))
+#define GUSregw(position)  (*(GUSword *) (gusptr+(position)))
+#define GUSregd(position)  (*(GUSdword *)(gusptr+(position)))
+
+#define GUSvoice(position) (*(GUSword *)(voiceptr+(position)))
+
+/* samples are always 16bit stereo (4 bytes each, first right then left interleaved) */
+void gus_mixvoices(GUSEmuState * state, unsigned int playback_freq, unsigned int numsamples,
+                   GUSsample *bufferpos)
+{
+    /* note that byte registers are stored in the upper half of each voice register! */
+    GUSbyte        *gusptr;
+    int             Voice;
+    GUSword        *voiceptr;
+
+    unsigned int    count;
+    for (count = 0; count < numsamples * 2; count++)
+        *(bufferpos + count) = 0;       /* clear */
+
+    gusptr = state->gusdatapos;
+    voiceptr = (GUSword *) gusptr;
+    if (!(GUSregb(GUS4cReset) & 0x01))  /* reset flag active? */
+        return;
+
+    for (Voice = 0; Voice <= (GUSregb(NumVoices) & 31); Voice++)
+    {
+        if (GUSvoice(wVSRControl)        &  0x200)
+            GUSvoice(wVSRControl)        |= 0x100; /* voice stop request */
+        if (GUSvoice(wVSRVolRampControl) &  0x200)
+            GUSvoice(wVSRVolRampControl) |= 0x100; /* Volume ramp stop request */
+        if (!(GUSvoice(wVSRControl) & GUSvoice(wVSRVolRampControl) & 0x100)) /* neither voice nor volume calculation active - save some time here ;) */
+        {
+            unsigned int    sample;
+
+            unsigned int    LoopStart = (GUSvoice(wVSRLoopStartHi) << 16) | GUSvoice(wVSRLoopStartLo); /* 23.9 format */
+            unsigned int    LoopEnd   = (GUSvoice(wVSRLoopEndHi)   << 16) | GUSvoice(wVSRLoopEndLo);   /* 23.9 format */
+            unsigned int    CurrPos   = (GUSvoice(wVSRCurrPosHi)   << 16) | GUSvoice(wVSRCurrPosLo);   /* 23.9 format */
+            int             VoiceIncrement = ((((unsigned long) GUSvoice(wVSRFreq) * 44100) / playback_freq) * (14 >> 1)) /
+                                             ((GUSregb(NumVoices) & 31) + 1); /* 6.10 increment/frame to 23.9 increment/sample */
+
+            int             PanningPos = (GUSvoice(wVSRPanning) >> 8) & 0xf;
+
+            unsigned int    Volume32   = 32 * GUSvoice(wVSRCurrVol); /* 32 times larger than original gus for maintaining precision while ramping */
+            unsigned int    StartVol32 = (GUSvoice(wVSRVolRampStartVol) & 0xff00) * 32;
+            unsigned int    EndVol32   = (GUSvoice(wVSRVolRampEndVol)   & 0xff00) * 32;
+            int             VolumeIncrement32 = (32 * 16 * (GUSvoice(wVSRVolRampRate) & 0x3f00) >> 8) >> ((((GUSvoice(wVSRVolRampRate) & 0xc000) >> 8) >> 6) * 3); /* including 1/8/64/512 volume speed divisor */
+            VolumeIncrement32 = (((VolumeIncrement32 * 44100 / 2) / playback_freq) * 14) / ((GUSregb(NumVoices) & 31) + 1); /* adjust ramping speed to playback speed */
+
+            if (GUSvoice(wVSRControl) & 0x4000)
+                VoiceIncrement    = -VoiceIncrement;    /* reverse playback */
+            if (GUSvoice(wVSRVolRampControl) & 0x4000)
+                VolumeIncrement32 = -VolumeIncrement32; /* reverse ramping */
+
+            for (sample = 0; sample < numsamples; sample++)
+            {
+                int             sample1, sample2, Volume;
+                if (GUSvoice(wVSRControl) & 0x400)      /* 16bit */
+                {
+                    int offset = ((CurrPos >> 9) & 0xc0000) + (((CurrPos >> 9) & 0x1ffff) << 1);
+                    GUSchar *adr;
+                    adr = (GUSchar *) state->himemaddr + offset;
+                    sample1 = (*adr & 0xff) + (*(adr + 1) * 256);
+                    sample2 = (*(adr + 2) & 0xff) + (*(adr + 2 + 1) * 256);
+                }
+                else            /* 8bit */
+                {
+                    int offset = (CurrPos >> 9) & 0xfffff;
+                    GUSchar *adr;
+                    adr = (GUSchar *) state->himemaddr + offset;
+                    sample1 = (*adr) * 256;
+                    sample2 = (*(adr + 1)) * 256;
+                }
+
+                Volume = ((((Volume32 >> (4 + 5)) & 0xff) + 256) << (Volume32 >> ((4 + 8) + 5))) / 512; /* semi-logarithmic volume, +5 due to additional precision */
+                sample1 = (((sample1 * Volume) >> 16) * (512 - (CurrPos % 512))) / 512;
+                sample2 = (((sample2 * Volume) >> 16) * (CurrPos % 512)) / 512;
+                sample1 += sample2;
+
+                if (!(GUSvoice(wVSRVolRampControl) & 0x100))
+                {
+                    Volume32 += VolumeIncrement32;
+                    if ((GUSvoice(wVSRVolRampControl) & 0x4000) ? (Volume32 <= StartVol32) : (Volume32 >= EndVol32)) /* ramp up boundary cross */
+                    {
+                        if (GUSvoice(wVSRVolRampControl) & 0x2000)
+                            GUSvoice(wVSRVolRampControl) |= 0x8000;     /* volramp IRQ enabled? -> IRQ wait flag */
+                        if (GUSvoice(wVSRVolRampControl) & 0x800)       /* loop enabled */
+                        {
+                            if (GUSvoice(wVSRVolRampControl) & 0x1000)  /* bidir. loop */
+                            {
+                                GUSvoice(wVSRVolRampControl) ^= 0x4000; /* toggle dir */
+                                VolumeIncrement32 = -VolumeIncrement32;
+                            }
+                            else
+                                Volume32 = (GUSvoice(wVSRVolRampControl) & 0x4000) ? EndVol32 : StartVol32; /* unidir. loop ramp */
+                        }
+                        else
+                        {
+                            GUSvoice(wVSRVolRampControl) |= 0x100;
+                            Volume32 =
+                                (GUSvoice(wVSRVolRampControl) & 0x4000) ? StartVol32 : EndVol32;
+                        }
+                    }
+                }
+                if ((GUSvoice(wVSRVolRampControl) & 0xa000) == 0xa000)  /* volramp IRQ set and enabled? */
+                {
+                    GUSregd(voicevolrampirq) |= 1 << Voice;             /* set irq slot */
+                }
+                else
+                {
+                    GUSregd(voicevolrampirq) &= (~(1 << Voice));        /* clear irq slot */
+                    GUSvoice(wVSRVolRampControl) &= 0x7f00;
+                }
+
+                if (!(GUSvoice(wVSRControl) & 0x100))
+                {
+                    CurrPos += VoiceIncrement;
+                    if ((GUSvoice(wVSRControl) & 0x4000) ? (CurrPos <= LoopStart) : (CurrPos >= LoopEnd)) /* playback boundary cross */
+                    {
+                        if (GUSvoice(wVSRControl) & 0x2000)
+                            GUSvoice(wVSRControl) |= 0x8000;       /* voice IRQ enabled -> IRQ wait flag */
+                        if (GUSvoice(wVSRControl) & 0x800)         /* loop enabled */
+                        {
+                            if (GUSvoice(wVSRControl) & 0x1000)    /* pingpong loop */
+                            {
+                                GUSvoice(wVSRControl) ^= 0x4000;   /* toggle dir */
+                                VoiceIncrement = -VoiceIncrement;
+                            }
+                            else
+                                CurrPos = (GUSvoice(wVSRControl) & 0x4000) ? LoopEnd : LoopStart; /* unidir. loop */
+                        }
+                        else if (!(GUSvoice(wVSRVolRampControl) & 0x400))
+                            GUSvoice(wVSRControl) |= 0x100;        /* loop disabled, rollover check */
+                    }
+                }
+                if ((GUSvoice(wVSRControl) & 0xa000) == 0xa000)    /* wavetable IRQ set and enabled? */
+                {
+                    GUSregd(voicewavetableirq) |= 1 << Voice;      /* set irq slot */
+                }
+                else
+                {
+                    GUSregd(voicewavetableirq) &= (~(1 << Voice)); /* clear irq slot */
+                    GUSvoice(wVSRControl) &= 0x7f00;
+                }
+
+                /* mix samples into buffer */
+                *(bufferpos + 2 * sample)     += (GUSsample) ((sample1 * PanningPos) >> 4);        /* right */
+                *(bufferpos + 2 * sample + 1) += (GUSsample) ((sample1 * (15 - PanningPos)) >> 4); /* left */
+            }
+            /* write back voice and volume */
+            GUSvoice(wVSRCurrVol)   = Volume32 / 32;
+            GUSvoice(wVSRCurrPosHi) = CurrPos >> 16;
+            GUSvoice(wVSRCurrPosLo) = CurrPos & 0xffff;
+        }
+        voiceptr += 16; /* next voice */
+    }
+}
+
+void gus_irqgen(GUSEmuState * state, unsigned int elapsed_time)
+/* time given in microseconds */
+{
+    int             requestedIRQs = 0;
+    GUSbyte        *gusptr;
+    gusptr = state->gusdatapos;
+    if (GUSregb(TimerDataReg2x9) & 1) /* start timer 1 (80us decrement rate) */
+    {
+        unsigned int    timer1fraction = state->timer1fraction;
+        int             newtimerirqs;
+        newtimerirqs          = (elapsed_time + timer1fraction) / (80 * (256 - GUSregb(GUS46Counter1)));
+        state->timer1fraction = (elapsed_time + timer1fraction) % (80 * (256 - GUSregb(GUS46Counter1)));
+        if (newtimerirqs)
+        {
+            if (!(GUSregb(TimerDataReg2x9) & 0x40))
+                GUSregb(TimerStatus2x8) |= 0xc0; /* maskable bits */
+            if (GUSregb(GUS45TimerCtrl) & 4)     /* timer1 irq enable */
+            {
+                GUSregb(TimerStatus2x8) |= 4;    /* nonmaskable bit */
+                GUSregb(IRQStatReg2x6)  |= 4;    /* timer 1 irq pending */
+                GUSregw(TimerIRQs) += newtimerirqs;
+                requestedIRQs += newtimerirqs;
+            }
+        }
+    }
+    if (GUSregb(TimerDataReg2x9) & 2) /* start timer 2 (320us decrement rate) */
+    {
+        unsigned int timer2fraction = state->timer2fraction;
+        int             newtimerirqs;
+        newtimerirqs          = (elapsed_time + timer2fraction) / (320 * (256 - GUSregb(GUS47Counter2)));
+        state->timer2fraction = (elapsed_time + timer2fraction) % (320 * (256 - GUSregb(GUS47Counter2)));
+        if (newtimerirqs)
+        {
+            if (!(GUSregb(TimerDataReg2x9) & 0x20))
+                GUSregb(TimerStatus2x8) |= 0xa0; /* maskable bits */
+            if (GUSregb(GUS45TimerCtrl) & 8)     /* timer2 irq enable */
+            {
+                GUSregb(TimerStatus2x8) |= 2;    /* nonmaskable bit */
+                GUSregb(IRQStatReg2x6)  |= 8;    /* timer 2 irq pending */
+                GUSregw(TimerIRQs) += newtimerirqs;
+                requestedIRQs += newtimerirqs;
+            }
+        }
+    }
+    if (GUSregb(GUS4cReset) & 0x4) /* synth IRQ enable */
+    {
+        if (GUSregd(voicewavetableirq))
+            GUSregb(IRQStatReg2x6) |= 0x20;
+        if (GUSregd(voicevolrampirq))
+            GUSregb(IRQStatReg2x6) |= 0x40;
+    }
+    if ((!requestedIRQs) && GUSregb(IRQStatReg2x6))
+        requestedIRQs++;
+    if (GUSregb(IRQStatReg2x6))
+        GUSregw(BusyTimerIRQs) = GUS_irqrequest(state, state->gusirq, requestedIRQs);
+}
diff --git a/hw/audio/gustate.h b/hw/audio/gustate.h
new file mode 100644 (file)
index 0000000..ece903a
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * GUSEMU32 - persistent GUS register state
+ *
+ * Copyright (C) 2000-2007 Tibor "TS" Schütz
+ *
+ * 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 GUSTATE_H
+#define GUSTATE_H
+
+/*state block offset*/
+#define gusdata (0)
+
+/* data stored using this structure is in host byte order! */
+
+/*access type*/
+#define PortRead  (0)
+#define PortWrite (1)
+
+#define Port8Bitacc  (0)
+#define Port16Bitacc (1)
+
+/*voice register offsets (in bytes)*/
+#define VSRegs (0)
+#define VSRControl          (0)
+#define VSRegsEnd (VSRControl+VSRegs + 32*(16*2))
+#define VSRFreq             (2)
+#define VSRLoopStartHi      (4)
+#define VSRLoopStartLo      (6)
+#define VSRLoopEndHi        (8)
+#define VSRLoopEndLo       (10)
+#define VSRVolRampRate     (12)
+#define VSRVolRampStartVol (14)
+#define VSRVolRampEndVol   (16)
+#define VSRCurrVol         (18)
+#define VSRCurrPosHi       (20)
+#define VSRCurrPosLo       (22)
+#define VSRPanning         (24)
+#define VSRVolRampControl  (26)
+
+/*voice register offsets (in words)*/
+#define wVSRegs (0)
+#define wVSRControl         (0)
+#define wVSRegsEnd (wVSRControl+wVSRegs + 32*(16))
+#define wVSRFreq            (1)
+#define wVSRLoopStartHi     (2)
+#define wVSRLoopStartLo     (3)
+#define wVSRLoopEndHi       (4)
+#define wVSRLoopEndLo       (5)
+#define wVSRVolRampRate     (6)
+#define wVSRVolRampStartVol (7)
+#define wVSRVolRampEndVol   (8)
+#define wVSRCurrVol         (9)
+#define wVSRCurrPosHi      (10)
+#define wVSRCurrPosLo      (11)
+#define wVSRPanning        (12)
+#define wVSRVolRampControl (13)
+
+/*GUS register state block: 32 voices, padding filled with remaining registers*/
+#define DataRegLoByte3x4  (VSRVolRampControl+2)
+#define  DataRegWord3x4 (DataRegLoByte3x4)
+#define DataRegHiByte3x5  (VSRVolRampControl+2       +1)
+#define DMA_2xB (VSRVolRampControl+2+2)
+#define IRQ_2xB (VSRVolRampControl+2+3)
+
+#define RegCtrl_2xF       (VSRVolRampControl+2+(16*2))
+#define Jumper_2xB        (VSRVolRampControl+2+(16*2)+1)
+#define GUS42DMAStart     (VSRVolRampControl+2+(16*2)+2)
+
+#define GUS43DRAMIOlo     (VSRVolRampControl+2+(16*2)*2)
+#define  GUSDRAMPOS24bit (GUS43DRAMIOlo)
+#define GUS44DRAMIOhi     (VSRVolRampControl+2+(16*2)*2+2)
+
+#define voicewavetableirq (VSRVolRampControl+2+(16*2)*3) /* voice IRQ pseudoqueue: 1 bit per voice */
+
+#define voicevolrampirq   (VSRVolRampControl+2+(16*2)*4) /* voice IRQ pseudoqueue: 1 bit per voice */
+
+#define startvoices       (VSRVolRampControl+2+(16*2)*5) /* statistics / optimizations */
+
+#define IRQStatReg2x6     (VSRVolRampControl+2+(16*2)*6)
+#define TimerStatus2x8    (VSRVolRampControl+2+(16*2)*6+1)
+#define TimerDataReg2x9   (VSRVolRampControl+2+(16*2)*6+2)
+#define MixerCtrlReg2x0   (VSRVolRampControl+2+(16*2)*6+3)
+
+#define VoiceSelReg3x2    (VSRVolRampControl+2+(16*2)*7)
+#define FunkSelReg3x3     (VSRVolRampControl+2+(16*2)*7+1)
+#define AdLibStatus2x8    (VSRVolRampControl+2+(16*2)*7+2)
+#define StatRead_2xF      (VSRVolRampControl+2+(16*2)*7+3)
+
+#define GUS48SampSpeed    (VSRVolRampControl+2+(16*2)*8)
+#define GUS41DMACtrl      (VSRVolRampControl+2+(16*2)*8+1)
+#define GUS45TimerCtrl    (VSRVolRampControl+2+(16*2)*8+2)
+#define GUS46Counter1     (VSRVolRampControl+2+(16*2)*8+3)
+
+#define GUS47Counter2     (VSRVolRampControl+2+(16*2)*9)
+#define GUS49SampCtrl     (VSRVolRampControl+2+(16*2)*9+1)
+#define GUS4cReset        (VSRVolRampControl+2+(16*2)*9+2)
+#define NumVoices         (VSRVolRampControl+2+(16*2)*9+3)
+
+#define TimerIRQs         (VSRVolRampControl+2+(16*2)*10)   /* delayed IRQ, statistics */
+#define BusyTimerIRQs     (VSRVolRampControl+2+(16*2)*10+2) /* delayed IRQ, statistics */
+
+#define AdLibCommand2xA   (VSRVolRampControl+2+(16*2)*11)
+#define AdLibData2x9      (VSRVolRampControl+2+(16*2)*11+1)
+#define SB2xCd            (VSRVolRampControl+2+(16*2)*11+2)
+#define SB2xE             (VSRVolRampControl+2+(16*2)*11+3)
+
+#define SynVoiceIRQ8f     (VSRVolRampControl+2+(16*2)*12)
+#define GUS50DMAHigh      (VSRVolRampControl+2+(16*2)*12+1)
+
+#define portaccesses (VSRegsEnd) /* statistics / suspend mode */
+
+#define gusdataend (VSRegsEnd+4)
+
+#endif  /* gustate.h */
diff --git a/hw/audio/hda-codec.c b/hw/audio/hda-codec.c
new file mode 100644 (file)
index 0000000..362d8c0
--- /dev/null
@@ -0,0 +1,1098 @@
+/*
+ * Copyright (C) 2010 Red Hat, Inc.
+ *
+ * written by Gerd Hoffmann <kraxel@redhat.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 or
+ * (at your option) version 3 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
+ * 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 "hw/hw.h"
+#include "hw/pci/pci.h"
+#include "intel-hda.h"
+#include "intel-hda-defs.h"
+#include "audio/audio.h"
+
+/* -------------------------------------------------------------------------- */
+
+typedef struct desc_param {
+    uint32_t id;
+    uint32_t val;
+} desc_param;
+
+typedef struct desc_node {
+    uint32_t nid;
+    const char *name;
+    const desc_param *params;
+    uint32_t nparams;
+    uint32_t config;
+    uint32_t pinctl;
+    uint32_t *conn;
+    uint32_t stindex;
+} desc_node;
+
+typedef struct desc_codec {
+    const char *name;
+    uint32_t iid;
+    const desc_node *nodes;
+    uint32_t nnodes;
+} desc_codec;
+
+static const desc_param* hda_codec_find_param(const desc_node *node, uint32_t id)
+{
+    int i;
+
+    for (i = 0; i < node->nparams; i++) {
+        if (node->params[i].id == id) {
+            return &node->params[i];
+        }
+    }
+    return NULL;
+}
+
+static const desc_node* hda_codec_find_node(const desc_codec *codec, uint32_t nid)
+{
+    int i;
+
+    for (i = 0; i < codec->nnodes; i++) {
+        if (codec->nodes[i].nid == nid) {
+            return &codec->nodes[i];
+        }
+    }
+    return NULL;
+}
+
+static void hda_codec_parse_fmt(uint32_t format, struct audsettings *as)
+{
+    if (format & AC_FMT_TYPE_NON_PCM) {
+        return;
+    }
+
+    as->freq = (format & AC_FMT_BASE_44K) ? 44100 : 48000;
+
+    switch ((format & AC_FMT_MULT_MASK) >> AC_FMT_MULT_SHIFT) {
+    case 1: as->freq *= 2; break;
+    case 2: as->freq *= 3; break;
+    case 3: as->freq *= 4; break;
+    }
+
+    switch ((format & AC_FMT_DIV_MASK) >> AC_FMT_DIV_SHIFT) {
+    case 1: as->freq /= 2; break;
+    case 2: as->freq /= 3; break;
+    case 3: as->freq /= 4; break;
+    case 4: as->freq /= 5; break;
+    case 5: as->freq /= 6; break;
+    case 6: as->freq /= 7; break;
+    case 7: as->freq /= 8; break;
+    }
+
+    switch (format & AC_FMT_BITS_MASK) {
+    case AC_FMT_BITS_8:  as->fmt = AUD_FMT_S8;  break;
+    case AC_FMT_BITS_16: as->fmt = AUD_FMT_S16; break;
+    case AC_FMT_BITS_32: as->fmt = AUD_FMT_S32; break;
+    }
+
+    as->nchannels = ((format & AC_FMT_CHAN_MASK) >> AC_FMT_CHAN_SHIFT) + 1;
+}
+
+/* -------------------------------------------------------------------------- */
+/*
+ * HDA codec descriptions
+ */
+
+/* some defines */
+
+#define QEMU_HDA_ID_VENDOR  0x1af4
+#define QEMU_HDA_PCM_FORMATS (AC_SUPPCM_BITS_16 |       \
+                              0x1fc /* 16 -> 96 kHz */)
+#define QEMU_HDA_AMP_NONE    (0)
+#define QEMU_HDA_AMP_STEPS   0x4a
+
+#ifdef CONFIG_MIXEMU
+# define QEMU_HDA_ID_OUTPUT  ((QEMU_HDA_ID_VENDOR << 16) | 0x12)
+# define QEMU_HDA_ID_DUPLEX  ((QEMU_HDA_ID_VENDOR << 16) | 0x22)
+# define QEMU_HDA_ID_MICRO   ((QEMU_HDA_ID_VENDOR << 16) | 0x32)
+# define QEMU_HDA_AMP_CAPS                                              \
+    (AC_AMPCAP_MUTE |                                                   \
+     (QEMU_HDA_AMP_STEPS << AC_AMPCAP_OFFSET_SHIFT)    |                \
+     (QEMU_HDA_AMP_STEPS << AC_AMPCAP_NUM_STEPS_SHIFT) |                \
+     (3                  << AC_AMPCAP_STEP_SIZE_SHIFT))
+#else
+# define QEMU_HDA_ID_OUTPUT  ((QEMU_HDA_ID_VENDOR << 16) | 0x11)
+# define QEMU_HDA_ID_DUPLEX  ((QEMU_HDA_ID_VENDOR << 16) | 0x21)
+# define QEMU_HDA_ID_MICRO   ((QEMU_HDA_ID_VENDOR << 16) | 0x31)
+# define QEMU_HDA_AMP_CAPS   QEMU_HDA_AMP_NONE
+#endif
+
+/* common: audio output widget */
+static const desc_param common_params_audio_dac[] = {
+    {
+        .id  = AC_PAR_AUDIO_WIDGET_CAP,
+        .val = ((AC_WID_AUD_OUT << AC_WCAP_TYPE_SHIFT) |
+                AC_WCAP_FORMAT_OVRD |
+                AC_WCAP_AMP_OVRD |
+                AC_WCAP_OUT_AMP |
+                AC_WCAP_STEREO),
+    },{
+        .id  = AC_PAR_PCM,
+        .val = QEMU_HDA_PCM_FORMATS,
+    },{
+        .id  = AC_PAR_STREAM,
+        .val = AC_SUPFMT_PCM,
+    },{
+        .id  = AC_PAR_AMP_IN_CAP,
+        .val = QEMU_HDA_AMP_NONE,
+    },{
+        .id  = AC_PAR_AMP_OUT_CAP,
+        .val = QEMU_HDA_AMP_CAPS,
+    },
+};
+
+/* common: audio input widget */
+static const desc_param common_params_audio_adc[] = {
+    {
+        .id  = AC_PAR_AUDIO_WIDGET_CAP,
+        .val = ((AC_WID_AUD_IN << AC_WCAP_TYPE_SHIFT) |
+                AC_WCAP_CONN_LIST |
+                AC_WCAP_FORMAT_OVRD |
+                AC_WCAP_AMP_OVRD |
+                AC_WCAP_IN_AMP |
+                AC_WCAP_STEREO),
+    },{
+        .id  = AC_PAR_CONNLIST_LEN,
+        .val = 1,
+    },{
+        .id  = AC_PAR_PCM,
+        .val = QEMU_HDA_PCM_FORMATS,
+    },{
+        .id  = AC_PAR_STREAM,
+        .val = AC_SUPFMT_PCM,
+    },{
+        .id  = AC_PAR_AMP_IN_CAP,
+        .val = QEMU_HDA_AMP_CAPS,
+    },{
+        .id  = AC_PAR_AMP_OUT_CAP,
+        .val = QEMU_HDA_AMP_NONE,
+    },
+};
+
+/* common: pin widget (line-out) */
+static const desc_param common_params_audio_lineout[] = {
+    {
+        .id  = AC_PAR_AUDIO_WIDGET_CAP,
+        .val = ((AC_WID_PIN << AC_WCAP_TYPE_SHIFT) |
+                AC_WCAP_CONN_LIST |
+                AC_WCAP_STEREO),
+    },{
+        .id  = AC_PAR_PIN_CAP,
+        .val = AC_PINCAP_OUT,
+    },{
+        .id  = AC_PAR_CONNLIST_LEN,
+        .val = 1,
+    },{
+        .id  = AC_PAR_AMP_IN_CAP,
+        .val = QEMU_HDA_AMP_NONE,
+    },{
+        .id  = AC_PAR_AMP_OUT_CAP,
+        .val = QEMU_HDA_AMP_NONE,
+    },
+};
+
+/* common: pin widget (line-in) */
+static const desc_param common_params_audio_linein[] = {
+    {
+        .id  = AC_PAR_AUDIO_WIDGET_CAP,
+        .val = ((AC_WID_PIN << AC_WCAP_TYPE_SHIFT) |
+                AC_WCAP_STEREO),
+    },{
+        .id  = AC_PAR_PIN_CAP,
+        .val = AC_PINCAP_IN,
+    },{
+        .id  = AC_PAR_AMP_IN_CAP,
+        .val = QEMU_HDA_AMP_NONE,
+    },{
+        .id  = AC_PAR_AMP_OUT_CAP,
+        .val = QEMU_HDA_AMP_NONE,
+    },
+};
+
+/* output: root node */
+static const desc_param output_params_root[] = {
+    {
+        .id  = AC_PAR_VENDOR_ID,
+        .val = QEMU_HDA_ID_OUTPUT,
+    },{
+        .id  = AC_PAR_SUBSYSTEM_ID,
+        .val = QEMU_HDA_ID_OUTPUT,
+    },{
+        .id  = AC_PAR_REV_ID,
+        .val = 0x00100101,
+    },{
+        .id  = AC_PAR_NODE_COUNT,
+        .val = 0x00010001,
+    },
+};
+
+/* output: audio function */
+static const desc_param output_params_audio_func[] = {
+    {
+        .id  = AC_PAR_FUNCTION_TYPE,
+        .val = AC_GRP_AUDIO_FUNCTION,
+    },{
+        .id  = AC_PAR_SUBSYSTEM_ID,
+        .val = QEMU_HDA_ID_OUTPUT,
+    },{
+        .id  = AC_PAR_NODE_COUNT,
+        .val = 0x00020002,
+    },{
+        .id  = AC_PAR_PCM,
+        .val = QEMU_HDA_PCM_FORMATS,
+    },{
+        .id  = AC_PAR_STREAM,
+        .val = AC_SUPFMT_PCM,
+    },{
+        .id  = AC_PAR_AMP_IN_CAP,
+        .val = QEMU_HDA_AMP_NONE,
+    },{
+        .id  = AC_PAR_AMP_OUT_CAP,
+        .val = QEMU_HDA_AMP_NONE,
+    },{
+        .id  = AC_PAR_GPIO_CAP,
+        .val = 0,
+    },{
+        .id  = AC_PAR_AUDIO_FG_CAP,
+        .val = 0x00000808,
+    },{
+        .id  = AC_PAR_POWER_STATE,
+        .val = 0,
+    },
+};
+
+/* output: nodes */
+static const desc_node output_nodes[] = {
+    {
+        .nid     = AC_NODE_ROOT,
+        .name    = "root",
+        .params  = output_params_root,
+        .nparams = ARRAY_SIZE(output_params_root),
+    },{
+        .nid     = 1,
+        .name    = "func",
+        .params  = output_params_audio_func,
+        .nparams = ARRAY_SIZE(output_params_audio_func),
+    },{
+        .nid     = 2,
+        .name    = "dac",
+        .params  = common_params_audio_dac,
+        .nparams = ARRAY_SIZE(common_params_audio_dac),
+        .stindex = 0,
+    },{
+        .nid     = 3,
+        .name    = "out",
+        .params  = common_params_audio_lineout,
+        .nparams = ARRAY_SIZE(common_params_audio_lineout),
+        .config  = ((AC_JACK_PORT_COMPLEX << AC_DEFCFG_PORT_CONN_SHIFT) |
+                    (AC_JACK_LINE_OUT     << AC_DEFCFG_DEVICE_SHIFT)    |
+                    (AC_JACK_CONN_UNKNOWN << AC_DEFCFG_CONN_TYPE_SHIFT) |
+                    (AC_JACK_COLOR_GREEN  << AC_DEFCFG_COLOR_SHIFT)     |
+                    0x10),
+        .pinctl  = AC_PINCTL_OUT_EN,
+        .conn    = (uint32_t[]) { 2 },
+    }
+};
+
+/* output: codec */
+static const desc_codec output = {
+    .name   = "output",
+    .iid    = QEMU_HDA_ID_OUTPUT,
+    .nodes  = output_nodes,
+    .nnodes = ARRAY_SIZE(output_nodes),
+};
+
+/* duplex: root node */
+static const desc_param duplex_params_root[] = {
+    {
+        .id  = AC_PAR_VENDOR_ID,
+        .val = QEMU_HDA_ID_DUPLEX,
+    },{
+        .id  = AC_PAR_SUBSYSTEM_ID,
+        .val = QEMU_HDA_ID_DUPLEX,
+    },{
+        .id  = AC_PAR_REV_ID,
+        .val = 0x00100101,
+    },{
+        .id  = AC_PAR_NODE_COUNT,
+        .val = 0x00010001,
+    },
+};
+
+/* duplex: audio function */
+static const desc_param duplex_params_audio_func[] = {
+    {
+        .id  = AC_PAR_FUNCTION_TYPE,
+        .val = AC_GRP_AUDIO_FUNCTION,
+    },{
+        .id  = AC_PAR_SUBSYSTEM_ID,
+        .val = QEMU_HDA_ID_DUPLEX,
+    },{
+        .id  = AC_PAR_NODE_COUNT,
+        .val = 0x00020004,
+    },{
+        .id  = AC_PAR_PCM,
+        .val = QEMU_HDA_PCM_FORMATS,
+    },{
+        .id  = AC_PAR_STREAM,
+        .val = AC_SUPFMT_PCM,
+    },{
+        .id  = AC_PAR_AMP_IN_CAP,
+        .val = QEMU_HDA_AMP_NONE,
+    },{
+        .id  = AC_PAR_AMP_OUT_CAP,
+        .val = QEMU_HDA_AMP_NONE,
+    },{
+        .id  = AC_PAR_GPIO_CAP,
+        .val = 0,
+    },{
+        .id  = AC_PAR_AUDIO_FG_CAP,
+        .val = 0x00000808,
+    },{
+        .id  = AC_PAR_POWER_STATE,
+        .val = 0,
+    },
+};
+
+/* duplex: nodes */
+static const desc_node duplex_nodes[] = {
+    {
+        .nid     = AC_NODE_ROOT,
+        .name    = "root",
+        .params  = duplex_params_root,
+        .nparams = ARRAY_SIZE(duplex_params_root),
+    },{
+        .nid     = 1,
+        .name    = "func",
+        .params  = duplex_params_audio_func,
+        .nparams = ARRAY_SIZE(duplex_params_audio_func),
+    },{
+        .nid     = 2,
+        .name    = "dac",
+        .params  = common_params_audio_dac,
+        .nparams = ARRAY_SIZE(common_params_audio_dac),
+        .stindex = 0,
+    },{
+        .nid     = 3,
+        .name    = "out",
+        .params  = common_params_audio_lineout,
+        .nparams = ARRAY_SIZE(common_params_audio_lineout),
+        .config  = ((AC_JACK_PORT_COMPLEX << AC_DEFCFG_PORT_CONN_SHIFT) |
+                    (AC_JACK_LINE_OUT     << AC_DEFCFG_DEVICE_SHIFT)    |
+                    (AC_JACK_CONN_UNKNOWN << AC_DEFCFG_CONN_TYPE_SHIFT) |
+                    (AC_JACK_COLOR_GREEN  << AC_DEFCFG_COLOR_SHIFT)     |
+                    0x10),
+        .pinctl  = AC_PINCTL_OUT_EN,
+        .conn    = (uint32_t[]) { 2 },
+    },{
+        .nid     = 4,
+        .name    = "adc",
+        .params  = common_params_audio_adc,
+        .nparams = ARRAY_SIZE(common_params_audio_adc),
+        .stindex = 1,
+        .conn    = (uint32_t[]) { 5 },
+    },{
+        .nid     = 5,
+        .name    = "in",
+        .params  = common_params_audio_linein,
+        .nparams = ARRAY_SIZE(common_params_audio_linein),
+        .config  = ((AC_JACK_PORT_COMPLEX << AC_DEFCFG_PORT_CONN_SHIFT) |
+                    (AC_JACK_LINE_IN      << AC_DEFCFG_DEVICE_SHIFT)    |
+                    (AC_JACK_CONN_UNKNOWN << AC_DEFCFG_CONN_TYPE_SHIFT) |
+                    (AC_JACK_COLOR_RED    << AC_DEFCFG_COLOR_SHIFT)     |
+                    0x20),
+        .pinctl  = AC_PINCTL_IN_EN,
+    }
+};
+
+/* duplex: codec */
+static const desc_codec duplex = {
+    .name   = "duplex",
+    .iid    = QEMU_HDA_ID_DUPLEX,
+    .nodes  = duplex_nodes,
+    .nnodes = ARRAY_SIZE(duplex_nodes),
+};
+
+/* micro: root node */
+static const desc_param micro_params_root[] = {
+    {
+        .id  = AC_PAR_VENDOR_ID,
+        .val = QEMU_HDA_ID_MICRO,
+    },{
+        .id  = AC_PAR_SUBSYSTEM_ID,
+        .val = QEMU_HDA_ID_MICRO,
+    },{
+        .id  = AC_PAR_REV_ID,
+        .val = 0x00100101,
+    },{
+        .id  = AC_PAR_NODE_COUNT,
+        .val = 0x00010001,
+    },
+};
+
+/* micro: audio function */
+static const desc_param micro_params_audio_func[] = {
+    {
+        .id  = AC_PAR_FUNCTION_TYPE,
+        .val = AC_GRP_AUDIO_FUNCTION,
+    },{
+        .id  = AC_PAR_SUBSYSTEM_ID,
+        .val = QEMU_HDA_ID_MICRO,
+    },{
+        .id  = AC_PAR_NODE_COUNT,
+        .val = 0x00020004,
+    },{
+        .id  = AC_PAR_PCM,
+        .val = QEMU_HDA_PCM_FORMATS,
+    },{
+        .id  = AC_PAR_STREAM,
+        .val = AC_SUPFMT_PCM,
+    },{
+        .id  = AC_PAR_AMP_IN_CAP,
+        .val = QEMU_HDA_AMP_NONE,
+    },{
+        .id  = AC_PAR_AMP_OUT_CAP,
+        .val = QEMU_HDA_AMP_NONE,
+    },{
+        .id  = AC_PAR_GPIO_CAP,
+        .val = 0,
+    },{
+        .id  = AC_PAR_AUDIO_FG_CAP,
+        .val = 0x00000808,
+    },{
+        .id  = AC_PAR_POWER_STATE,
+        .val = 0,
+    },
+};
+
+/* micro: nodes */
+static const desc_node micro_nodes[] = {
+    {
+        .nid     = AC_NODE_ROOT,
+        .name    = "root",
+        .params  = micro_params_root,
+        .nparams = ARRAY_SIZE(micro_params_root),
+    },{
+        .nid     = 1,
+        .name    = "func",
+        .params  = micro_params_audio_func,
+        .nparams = ARRAY_SIZE(micro_params_audio_func),
+    },{
+        .nid     = 2,
+        .name    = "dac",
+        .params  = common_params_audio_dac,
+        .nparams = ARRAY_SIZE(common_params_audio_dac),
+        .stindex = 0,
+    },{
+        .nid     = 3,
+        .name    = "out",
+        .params  = common_params_audio_lineout,
+        .nparams = ARRAY_SIZE(common_params_audio_lineout),
+        .config  = ((AC_JACK_PORT_COMPLEX << AC_DEFCFG_PORT_CONN_SHIFT) |
+                    (AC_JACK_SPEAKER      << AC_DEFCFG_DEVICE_SHIFT)    |
+                    (AC_JACK_CONN_UNKNOWN << AC_DEFCFG_CONN_TYPE_SHIFT) |
+                    (AC_JACK_COLOR_GREEN  << AC_DEFCFG_COLOR_SHIFT)     |
+                    0x10),
+        .pinctl  = AC_PINCTL_OUT_EN,
+        .conn    = (uint32_t[]) { 2 },
+    },{
+        .nid     = 4,
+        .name    = "adc",
+        .params  = common_params_audio_adc,
+        .nparams = ARRAY_SIZE(common_params_audio_adc),
+        .stindex = 1,
+        .conn    = (uint32_t[]) { 5 },
+    },{
+        .nid     = 5,
+        .name    = "in",
+        .params  = common_params_audio_linein,
+        .nparams = ARRAY_SIZE(common_params_audio_linein),
+        .config  = ((AC_JACK_PORT_COMPLEX << AC_DEFCFG_PORT_CONN_SHIFT) |
+                    (AC_JACK_MIC_IN       << AC_DEFCFG_DEVICE_SHIFT)    |
+                    (AC_JACK_CONN_UNKNOWN << AC_DEFCFG_CONN_TYPE_SHIFT) |
+                    (AC_JACK_COLOR_RED    << AC_DEFCFG_COLOR_SHIFT)     |
+                    0x20),
+        .pinctl  = AC_PINCTL_IN_EN,
+    }
+};
+
+/* micro: codec */
+static const desc_codec micro = {
+    .name   = "micro",
+    .iid    = QEMU_HDA_ID_MICRO,
+    .nodes  = micro_nodes,
+    .nnodes = ARRAY_SIZE(micro_nodes),
+};
+
+/* -------------------------------------------------------------------------- */
+
+static const char *fmt2name[] = {
+    [ AUD_FMT_U8  ] = "PCM-U8",
+    [ AUD_FMT_S8  ] = "PCM-S8",
+    [ AUD_FMT_U16 ] = "PCM-U16",
+    [ AUD_FMT_S16 ] = "PCM-S16",
+    [ AUD_FMT_U32 ] = "PCM-U32",
+    [ AUD_FMT_S32 ] = "PCM-S32",
+};
+
+typedef struct HDAAudioState HDAAudioState;
+typedef struct HDAAudioStream HDAAudioStream;
+
+struct HDAAudioStream {
+    HDAAudioState *state;
+    const desc_node *node;
+    bool output, running;
+    uint32_t stream;
+    uint32_t channel;
+    uint32_t format;
+    uint32_t gain_left, gain_right;
+    bool mute_left, mute_right;
+    struct audsettings as;
+    union {
+        SWVoiceIn *in;
+        SWVoiceOut *out;
+    } voice;
+    uint8_t buf[HDA_BUFFER_SIZE];
+    uint32_t bpos;
+};
+
+struct HDAAudioState {
+    HDACodecDevice hda;
+    const char *name;
+
+    QEMUSoundCard card;
+    const desc_codec *desc;
+    HDAAudioStream st[4];
+    bool running_compat[16];
+    bool running_real[2 * 16];
+
+    /* properties */
+    uint32_t debug;
+};
+
+static void hda_audio_input_cb(void *opaque, int avail)
+{
+    HDAAudioStream *st = opaque;
+    int recv = 0;
+    int len;
+    bool rc;
+
+    while (avail - recv >= sizeof(st->buf)) {
+        if (st->bpos != sizeof(st->buf)) {
+            len = AUD_read(st->voice.in, st->buf + st->bpos,
+                           sizeof(st->buf) - st->bpos);
+            st->bpos += len;
+            recv += len;
+            if (st->bpos != sizeof(st->buf)) {
+                break;
+            }
+        }
+        rc = hda_codec_xfer(&st->state->hda, st->stream, false,
+                            st->buf, sizeof(st->buf));
+        if (!rc) {
+            break;
+        }
+        st->bpos = 0;
+    }
+}
+
+static void hda_audio_output_cb(void *opaque, int avail)
+{
+    HDAAudioStream *st = opaque;
+    int sent = 0;
+    int len;
+    bool rc;
+
+    while (avail - sent >= sizeof(st->buf)) {
+        if (st->bpos == sizeof(st->buf)) {
+            rc = hda_codec_xfer(&st->state->hda, st->stream, true,
+                                st->buf, sizeof(st->buf));
+            if (!rc) {
+                break;
+            }
+            st->bpos = 0;
+        }
+        len = AUD_write(st->voice.out, st->buf + st->bpos,
+                        sizeof(st->buf) - st->bpos);
+        st->bpos += len;
+        sent += len;
+        if (st->bpos != sizeof(st->buf)) {
+            break;
+        }
+    }
+}
+
+static void hda_audio_set_running(HDAAudioStream *st, bool running)
+{
+    if (st->node == NULL) {
+        return;
+    }
+    if (st->running == running) {
+        return;
+    }
+    st->running = running;
+    dprint(st->state, 1, "%s: %s (stream %d)\n", st->node->name,
+           st->running ? "on" : "off", st->stream);
+    if (st->output) {
+        AUD_set_active_out(st->voice.out, st->running);
+    } else {
+        AUD_set_active_in(st->voice.in, st->running);
+    }
+}
+
+static void hda_audio_set_amp(HDAAudioStream *st)
+{
+    bool muted;
+    uint32_t left, right;
+
+    if (st->node == NULL) {
+        return;
+    }
+
+    muted = st->mute_left && st->mute_right;
+    left  = st->mute_left  ? 0 : st->gain_left;
+    right = st->mute_right ? 0 : st->gain_right;
+
+    left = left * 255 / QEMU_HDA_AMP_STEPS;
+    right = right * 255 / QEMU_HDA_AMP_STEPS;
+
+    if (st->output) {
+        AUD_set_volume_out(st->voice.out, muted, left, right);
+    } else {
+        AUD_set_volume_in(st->voice.in, muted, left, right);
+    }
+}
+
+static void hda_audio_setup(HDAAudioStream *st)
+{
+    if (st->node == NULL) {
+        return;
+    }
+
+    dprint(st->state, 1, "%s: format: %d x %s @ %d Hz\n",
+           st->node->name, st->as.nchannels,
+           fmt2name[st->as.fmt], st->as.freq);
+
+    if (st->output) {
+        st->voice.out = AUD_open_out(&st->state->card, st->voice.out,
+                                     st->node->name, st,
+                                     hda_audio_output_cb, &st->as);
+    } else {
+        st->voice.in = AUD_open_in(&st->state->card, st->voice.in,
+                                   st->node->name, st,
+                                   hda_audio_input_cb, &st->as);
+    }
+}
+
+static void hda_audio_command(HDACodecDevice *hda, uint32_t nid, uint32_t data)
+{
+    HDAAudioState *a = DO_UPCAST(HDAAudioState, hda, hda);
+    HDAAudioStream *st;
+    const desc_node *node = NULL;
+    const desc_param *param;
+    uint32_t verb, payload, response, count, shift;
+
+    if ((data & 0x70000) == 0x70000) {
+        /* 12/8 id/payload */
+        verb = (data >> 8) & 0xfff;
+        payload = data & 0x00ff;
+    } else {
+        /* 4/16 id/payload */
+        verb = (data >> 8) & 0xf00;
+        payload = data & 0xffff;
+    }
+
+    node = hda_codec_find_node(a->desc, nid);
+    if (node == NULL) {
+        goto fail;
+    }
+    dprint(a, 2, "%s: nid %d (%s), verb 0x%x, payload 0x%x\n",
+           __FUNCTION__, nid, node->name, verb, payload);
+
+    switch (verb) {
+    /* all nodes */
+    case AC_VERB_PARAMETERS:
+        param = hda_codec_find_param(node, payload);
+        if (param == NULL) {
+            goto fail;
+        }
+        hda_codec_response(hda, true, param->val);
+        break;
+    case AC_VERB_GET_SUBSYSTEM_ID:
+        hda_codec_response(hda, true, a->desc->iid);
+        break;
+
+    /* all functions */
+    case AC_VERB_GET_CONNECT_LIST:
+        param = hda_codec_find_param(node, AC_PAR_CONNLIST_LEN);
+        count = param ? param->val : 0;
+        response = 0;
+        shift = 0;
+        while (payload < count && shift < 32) {
+            response |= node->conn[payload] << shift;
+            payload++;
+            shift += 8;
+        }
+        hda_codec_response(hda, true, response);
+        break;
+
+    /* pin widget */
+    case AC_VERB_GET_CONFIG_DEFAULT:
+        hda_codec_response(hda, true, node->config);
+        break;
+    case AC_VERB_GET_PIN_WIDGET_CONTROL:
+        hda_codec_response(hda, true, node->pinctl);
+        break;
+    case AC_VERB_SET_PIN_WIDGET_CONTROL:
+        if (node->pinctl != payload) {
+            dprint(a, 1, "unhandled pin control bit\n");
+        }
+        hda_codec_response(hda, true, 0);
+        break;
+
+    /* audio in/out widget */
+    case AC_VERB_SET_CHANNEL_STREAMID:
+        st = a->st + node->stindex;
+        if (st->node == NULL) {
+            goto fail;
+        }
+        hda_audio_set_running(st, false);
+        st->stream = (payload >> 4) & 0x0f;
+        st->channel = payload & 0x0f;
+        dprint(a, 2, "%s: stream %d, channel %d\n",
+               st->node->name, st->stream, st->channel);
+        hda_audio_set_running(st, a->running_real[st->output * 16 + st->stream]);
+        hda_codec_response(hda, true, 0);
+        break;
+    case AC_VERB_GET_CONV:
+        st = a->st + node->stindex;
+        if (st->node == NULL) {
+            goto fail;
+        }
+        response = st->stream << 4 | st->channel;
+        hda_codec_response(hda, true, response);
+        break;
+    case AC_VERB_SET_STREAM_FORMAT:
+        st = a->st + node->stindex;
+        if (st->node == NULL) {
+            goto fail;
+        }
+        st->format = payload;
+        hda_codec_parse_fmt(st->format, &st->as);
+        hda_audio_setup(st);
+        hda_codec_response(hda, true, 0);
+        break;
+    case AC_VERB_GET_STREAM_FORMAT:
+        st = a->st + node->stindex;
+        if (st->node == NULL) {
+            goto fail;
+        }
+        hda_codec_response(hda, true, st->format);
+        break;
+    case AC_VERB_GET_AMP_GAIN_MUTE:
+        st = a->st + node->stindex;
+        if (st->node == NULL) {
+            goto fail;
+        }
+        if (payload & AC_AMP_GET_LEFT) {
+            response = st->gain_left | (st->mute_left ? AC_AMP_MUTE : 0);
+        } else {
+            response = st->gain_right | (st->mute_right ? AC_AMP_MUTE : 0);
+        }
+        hda_codec_response(hda, true, response);
+        break;
+    case AC_VERB_SET_AMP_GAIN_MUTE:
+        st = a->st + node->stindex;
+        if (st->node == NULL) {
+            goto fail;
+        }
+        dprint(a, 1, "amp (%s): %s%s%s%s index %d  gain %3d %s\n",
+               st->node->name,
+               (payload & AC_AMP_SET_OUTPUT) ? "o" : "-",
+               (payload & AC_AMP_SET_INPUT)  ? "i" : "-",
+               (payload & AC_AMP_SET_LEFT)   ? "l" : "-",
+               (payload & AC_AMP_SET_RIGHT)  ? "r" : "-",
+               (payload & AC_AMP_SET_INDEX) >> AC_AMP_SET_INDEX_SHIFT,
+               (payload & AC_AMP_GAIN),
+               (payload & AC_AMP_MUTE) ? "muted" : "");
+        if (payload & AC_AMP_SET_LEFT) {
+            st->gain_left = payload & AC_AMP_GAIN;
+            st->mute_left = payload & AC_AMP_MUTE;
+        }
+        if (payload & AC_AMP_SET_RIGHT) {
+            st->gain_right = payload & AC_AMP_GAIN;
+            st->mute_right = payload & AC_AMP_MUTE;
+        }
+        hda_audio_set_amp(st);
+        hda_codec_response(hda, true, 0);
+        break;
+
+    /* not supported */
+    case AC_VERB_SET_POWER_STATE:
+    case AC_VERB_GET_POWER_STATE:
+    case AC_VERB_GET_SDI_SELECT:
+        hda_codec_response(hda, true, 0);
+        break;
+    default:
+        goto fail;
+    }
+    return;
+
+fail:
+    dprint(a, 1, "%s: not handled: nid %d (%s), verb 0x%x, payload 0x%x\n",
+           __FUNCTION__, nid, node ? node->name : "?", verb, payload);
+    hda_codec_response(hda, true, 0);
+}
+
+static void hda_audio_stream(HDACodecDevice *hda, uint32_t stnr, bool running, bool output)
+{
+    HDAAudioState *a = DO_UPCAST(HDAAudioState, hda, hda);
+    int s;
+
+    a->running_compat[stnr] = running;
+    a->running_real[output * 16 + stnr] = running;
+    for (s = 0; s < ARRAY_SIZE(a->st); s++) {
+        if (a->st[s].node == NULL) {
+            continue;
+        }
+        if (a->st[s].output != output) {
+            continue;
+        }
+        if (a->st[s].stream != stnr) {
+            continue;
+        }
+        hda_audio_set_running(&a->st[s], running);
+    }
+}
+
+static int hda_audio_init(HDACodecDevice *hda, const struct desc_codec *desc)
+{
+    HDAAudioState *a = DO_UPCAST(HDAAudioState, hda, hda);
+    HDAAudioStream *st;
+    const desc_node *node;
+    const desc_param *param;
+    uint32_t i, type;
+
+    a->desc = desc;
+    a->name = object_get_typename(OBJECT(a));
+    dprint(a, 1, "%s: cad %d\n", __FUNCTION__, a->hda.cad);
+
+    AUD_register_card("hda", &a->card);
+    for (i = 0; i < a->desc->nnodes; i++) {
+        node = a->desc->nodes + i;
+        param = hda_codec_find_param(node, AC_PAR_AUDIO_WIDGET_CAP);
+        if (NULL == param)
+            continue;
+        type = (param->val & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
+        switch (type) {
+        case AC_WID_AUD_OUT:
+        case AC_WID_AUD_IN:
+            assert(node->stindex < ARRAY_SIZE(a->st));
+            st = a->st + node->stindex;
+            st->state = a;
+            st->node = node;
+            if (type == AC_WID_AUD_OUT) {
+                /* unmute output by default */
+                st->gain_left = QEMU_HDA_AMP_STEPS;
+                st->gain_right = QEMU_HDA_AMP_STEPS;
+                st->bpos = sizeof(st->buf);
+                st->output = true;
+            } else {
+                st->output = false;
+            }
+            st->format = AC_FMT_TYPE_PCM | AC_FMT_BITS_16 |
+                (1 << AC_FMT_CHAN_SHIFT);
+            hda_codec_parse_fmt(st->format, &st->as);
+            hda_audio_setup(st);
+            break;
+        }
+    }
+    return 0;
+}
+
+static int hda_audio_exit(HDACodecDevice *hda)
+{
+    HDAAudioState *a = DO_UPCAST(HDAAudioState, hda, hda);
+    HDAAudioStream *st;
+    int i;
+
+    dprint(a, 1, "%s\n", __FUNCTION__);
+    for (i = 0; i < ARRAY_SIZE(a->st); i++) {
+        st = a->st + i;
+        if (st->node == NULL) {
+            continue;
+        }
+        if (st->output) {
+            AUD_close_out(&a->card, st->voice.out);
+        } else {
+            AUD_close_in(&a->card, st->voice.in);
+        }
+    }
+    AUD_remove_card(&a->card);
+    return 0;
+}
+
+static int hda_audio_post_load(void *opaque, int version)
+{
+    HDAAudioState *a = opaque;
+    HDAAudioStream *st;
+    int i;
+
+    dprint(a, 1, "%s\n", __FUNCTION__);
+    if (version == 1) {
+        /* assume running_compat[] is for output streams */
+        for (i = 0; i < ARRAY_SIZE(a->running_compat); i++)
+            a->running_real[16 + i] = a->running_compat[i];
+    }
+
+    for (i = 0; i < ARRAY_SIZE(a->st); i++) {
+        st = a->st + i;
+        if (st->node == NULL)
+            continue;
+        hda_codec_parse_fmt(st->format, &st->as);
+        hda_audio_setup(st);
+        hda_audio_set_amp(st);
+        hda_audio_set_running(st, a->running_real[st->output * 16 + st->stream]);
+    }
+    return 0;
+}
+
+static const VMStateDescription vmstate_hda_audio_stream = {
+    .name = "hda-audio-stream",
+    .version_id = 1,
+    .fields = (VMStateField []) {
+        VMSTATE_UINT32(stream, HDAAudioStream),
+        VMSTATE_UINT32(channel, HDAAudioStream),
+        VMSTATE_UINT32(format, HDAAudioStream),
+        VMSTATE_UINT32(gain_left, HDAAudioStream),
+        VMSTATE_UINT32(gain_right, HDAAudioStream),
+        VMSTATE_BOOL(mute_left, HDAAudioStream),
+        VMSTATE_BOOL(mute_right, HDAAudioStream),
+        VMSTATE_UINT32(bpos, HDAAudioStream),
+        VMSTATE_BUFFER(buf, HDAAudioStream),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_hda_audio = {
+    .name = "hda-audio",
+    .version_id = 2,
+    .post_load = hda_audio_post_load,
+    .fields = (VMStateField []) {
+        VMSTATE_STRUCT_ARRAY(st, HDAAudioState, 4, 0,
+                             vmstate_hda_audio_stream,
+                             HDAAudioStream),
+        VMSTATE_BOOL_ARRAY(running_compat, HDAAudioState, 16),
+        VMSTATE_BOOL_ARRAY_V(running_real, HDAAudioState, 2 * 16, 2),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static Property hda_audio_properties[] = {
+    DEFINE_PROP_UINT32("debug", HDAAudioState, debug, 0),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static int hda_audio_init_output(HDACodecDevice *hda)
+{
+    return hda_audio_init(hda, &output);
+}
+
+static int hda_audio_init_duplex(HDACodecDevice *hda)
+{
+    return hda_audio_init(hda, &duplex);
+}
+
+static int hda_audio_init_micro(HDACodecDevice *hda)
+{
+    return hda_audio_init(hda, &micro);
+}
+
+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 (line-out)";
+    dc->vmsd = &vmstate_hda_audio;
+    dc->props = hda_audio_properties;
+}
+
+static const 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 (line-out, line-in)";
+    dc->vmsd = &vmstate_hda_audio;
+    dc->props = hda_audio_properties;
+}
+
+static const 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_micro_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    HDACodecDeviceClass *k = HDA_CODEC_DEVICE_CLASS(klass);
+
+    k->init = hda_audio_init_micro;
+    k->exit = hda_audio_exit;
+    k->command = hda_audio_command;
+    k->stream = hda_audio_stream;
+    dc->desc = "HDA Audio Codec, duplex (speaker, microphone)";
+    dc->vmsd = &vmstate_hda_audio;
+    dc->props = hda_audio_properties;
+}
+
+static const TypeInfo hda_audio_micro_info = {
+    .name          = "hda-micro",
+    .parent        = TYPE_HDA_CODEC_DEVICE,
+    .instance_size = sizeof(HDAAudioState),
+    .class_init    = hda_audio_micro_class_init,
+};
+
+static void hda_audio_register_types(void)
+{
+    type_register_static(&hda_audio_output_info);
+    type_register_static(&hda_audio_duplex_info);
+    type_register_static(&hda_audio_micro_info);
+}
+
+type_init(hda_audio_register_types)
diff --git a/hw/audio/intel-hda-defs.h b/hw/audio/intel-hda-defs.h
new file mode 100644 (file)
index 0000000..2e37e5b
--- /dev/null
@@ -0,0 +1,717 @@
+#ifndef HW_INTEL_HDA_DEFS_H
+#define HW_INTEL_HDA_DEFS_H
+
+/* qemu */
+#define HDA_BUFFER_SIZE 256
+
+/* --------------------------------------------------------------------- */
+/* from linux/sound/pci/hda/hda_intel.c                                  */
+
+/*
+ * registers
+ */
+#define ICH6_REG_GCAP                  0x00
+#define   ICH6_GCAP_64OK       (1 << 0)   /* 64bit address support */
+#define   ICH6_GCAP_NSDO       (3 << 1)   /* # of serial data out signals */
+#define   ICH6_GCAP_BSS                (31 << 3)  /* # of bidirectional streams */
+#define   ICH6_GCAP_ISS                (15 << 8)  /* # of input streams */
+#define   ICH6_GCAP_OSS                (15 << 12) /* # of output streams */
+#define ICH6_REG_VMIN                  0x02
+#define ICH6_REG_VMAJ                  0x03
+#define ICH6_REG_OUTPAY                        0x04
+#define ICH6_REG_INPAY                 0x06
+#define ICH6_REG_GCTL                  0x08
+#define   ICH6_GCTL_RESET      (1 << 0)   /* controller reset */
+#define   ICH6_GCTL_FCNTRL     (1 << 1)   /* flush control */
+#define   ICH6_GCTL_UNSOL      (1 << 8)   /* accept unsol. response enable */
+#define ICH6_REG_WAKEEN                        0x0c
+#define ICH6_REG_STATESTS              0x0e
+#define ICH6_REG_GSTS                  0x10
+#define   ICH6_GSTS_FSTS       (1 << 1)   /* flush status */
+#define ICH6_REG_INTCTL                        0x20
+#define ICH6_REG_INTSTS                        0x24
+#define ICH6_REG_WALLCLK               0x30    /* 24Mhz source */
+#define ICH6_REG_SYNC                  0x34
+#define ICH6_REG_CORBLBASE             0x40
+#define ICH6_REG_CORBUBASE             0x44
+#define ICH6_REG_CORBWP                        0x48
+#define ICH6_REG_CORBRP                        0x4a
+#define   ICH6_CORBRP_RST      (1 << 15)  /* read pointer reset */
+#define ICH6_REG_CORBCTL               0x4c
+#define   ICH6_CORBCTL_RUN     (1 << 1)   /* enable DMA */
+#define   ICH6_CORBCTL_CMEIE   (1 << 0)   /* enable memory error irq */
+#define ICH6_REG_CORBSTS               0x4d
+#define   ICH6_CORBSTS_CMEI    (1 << 0)   /* memory error indication */
+#define ICH6_REG_CORBSIZE              0x4e
+
+#define ICH6_REG_RIRBLBASE             0x50
+#define ICH6_REG_RIRBUBASE             0x54
+#define ICH6_REG_RIRBWP                        0x58
+#define   ICH6_RIRBWP_RST      (1 << 15)  /* write pointer reset */
+#define ICH6_REG_RINTCNT               0x5a
+#define ICH6_REG_RIRBCTL               0x5c
+#define   ICH6_RBCTL_IRQ_EN    (1 << 0)   /* enable IRQ */
+#define   ICH6_RBCTL_DMA_EN    (1 << 1)   /* enable DMA */
+#define   ICH6_RBCTL_OVERRUN_EN        (1 << 2)   /* enable overrun irq */
+#define ICH6_REG_RIRBSTS               0x5d
+#define   ICH6_RBSTS_IRQ       (1 << 0)   /* response irq */
+#define   ICH6_RBSTS_OVERRUN   (1 << 2)   /* overrun irq */
+#define ICH6_REG_RIRBSIZE              0x5e
+
+#define ICH6_REG_IC                    0x60
+#define ICH6_REG_IR                    0x64
+#define ICH6_REG_IRS                   0x68
+#define   ICH6_IRS_VALID       (1<<1)
+#define   ICH6_IRS_BUSY                (1<<0)
+
+#define ICH6_REG_DPLBASE               0x70
+#define ICH6_REG_DPUBASE               0x74
+#define   ICH6_DPLBASE_ENABLE  0x1     /* Enable position buffer */
+
+/* SD offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */
+enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
+
+/* stream register offsets from stream base */
+#define ICH6_REG_SD_CTL                        0x00
+#define ICH6_REG_SD_STS                        0x03
+#define ICH6_REG_SD_LPIB               0x04
+#define ICH6_REG_SD_CBL                        0x08
+#define ICH6_REG_SD_LVI                        0x0c
+#define ICH6_REG_SD_FIFOW              0x0e
+#define ICH6_REG_SD_FIFOSIZE           0x10
+#define ICH6_REG_SD_FORMAT             0x12
+#define ICH6_REG_SD_BDLPL              0x18
+#define ICH6_REG_SD_BDLPU              0x1c
+
+/* PCI space */
+#define ICH6_PCIREG_TCSEL      0x44
+
+/*
+ * other constants
+ */
+
+/* max number of SDs */
+/* ICH, ATI and VIA have 4 playback and 4 capture */
+#define ICH6_NUM_CAPTURE       4
+#define ICH6_NUM_PLAYBACK      4
+
+/* ULI has 6 playback and 5 capture */
+#define ULI_NUM_CAPTURE                5
+#define ULI_NUM_PLAYBACK       6
+
+/* ATI HDMI has 1 playback and 0 capture */
+#define ATIHDMI_NUM_CAPTURE    0
+#define ATIHDMI_NUM_PLAYBACK   1
+
+/* TERA has 4 playback and 3 capture */
+#define TERA_NUM_CAPTURE       3
+#define TERA_NUM_PLAYBACK      4
+
+/* this number is statically defined for simplicity */
+#define MAX_AZX_DEV            16
+
+/* max number of fragments - we may use more if allocating more pages for BDL */
+#define BDL_SIZE               4096
+#define AZX_MAX_BDL_ENTRIES    (BDL_SIZE / 16)
+#define AZX_MAX_FRAG           32
+/* max buffer size - no h/w limit, you can increase as you like */
+#define AZX_MAX_BUF_SIZE       (1024*1024*1024)
+
+/* RIRB int mask: overrun[2], response[0] */
+#define RIRB_INT_RESPONSE      0x01
+#define RIRB_INT_OVERRUN       0x04
+#define RIRB_INT_MASK          0x05
+
+/* STATESTS int mask: S3,SD2,SD1,SD0 */
+#define AZX_MAX_CODECS         8
+#define AZX_DEFAULT_CODECS     4
+#define STATESTS_INT_MASK      ((1 << AZX_MAX_CODECS) - 1)
+
+/* SD_CTL bits */
+#define SD_CTL_STREAM_RESET    0x01    /* stream reset bit */
+#define SD_CTL_DMA_START       0x02    /* stream DMA start bit */
+#define SD_CTL_STRIPE          (3 << 16)       /* stripe control */
+#define SD_CTL_TRAFFIC_PRIO    (1 << 18)       /* traffic priority */
+#define SD_CTL_DIR             (1 << 19)       /* bi-directional stream */
+#define SD_CTL_STREAM_TAG_MASK (0xf << 20)
+#define SD_CTL_STREAM_TAG_SHIFT        20
+
+/* SD_CTL and SD_STS */
+#define SD_INT_DESC_ERR                0x10    /* descriptor error interrupt */
+#define SD_INT_FIFO_ERR                0x08    /* FIFO error interrupt */
+#define SD_INT_COMPLETE                0x04    /* completion interrupt */
+#define SD_INT_MASK            (SD_INT_DESC_ERR|SD_INT_FIFO_ERR|\
+                                SD_INT_COMPLETE)
+
+/* SD_STS */
+#define SD_STS_FIFO_READY      0x20    /* FIFO ready */
+
+/* INTCTL and INTSTS */
+#define ICH6_INT_ALL_STREAM    0xff       /* all stream interrupts */
+#define ICH6_INT_CTRL_EN       0x40000000 /* controller interrupt enable bit */
+#define ICH6_INT_GLOBAL_EN     0x80000000 /* global interrupt enable bit */
+
+/* below are so far hardcoded - should read registers in future */
+#define ICH6_MAX_CORB_ENTRIES  256
+#define ICH6_MAX_RIRB_ENTRIES  256
+
+/* position fix mode */
+enum {
+       POS_FIX_AUTO,
+       POS_FIX_LPIB,
+       POS_FIX_POSBUF,
+};
+
+/* Defines for ATI HD Audio support in SB450 south bridge */
+#define ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR   0x42
+#define ATI_SB450_HDAUDIO_ENABLE_SNOOP      0x02
+
+/* Defines for Nvidia HDA support */
+#define NVIDIA_HDA_TRANSREG_ADDR      0x4e
+#define NVIDIA_HDA_ENABLE_COHBITS     0x0f
+#define NVIDIA_HDA_ISTRM_COH          0x4d
+#define NVIDIA_HDA_OSTRM_COH          0x4c
+#define NVIDIA_HDA_ENABLE_COHBIT      0x01
+
+/* Defines for Intel SCH HDA snoop control */
+#define INTEL_SCH_HDA_DEVC      0x78
+#define INTEL_SCH_HDA_DEVC_NOSNOOP       (0x1<<11)
+
+/* Define IN stream 0 FIFO size offset in VIA controller */
+#define VIA_IN_STREAM0_FIFO_SIZE_OFFSET        0x90
+/* Define VIA HD Audio Device ID*/
+#define VIA_HDAC_DEVICE_ID             0x3288
+
+/* HD Audio class code */
+#define PCI_CLASS_MULTIMEDIA_HD_AUDIO  0x0403
+
+/* --------------------------------------------------------------------- */
+/* from linux/sound/pci/hda/hda_codec.h                                  */
+
+/*
+ * nodes
+ */
+#define        AC_NODE_ROOT            0x00
+
+/*
+ * function group types
+ */
+enum {
+       AC_GRP_AUDIO_FUNCTION = 0x01,
+       AC_GRP_MODEM_FUNCTION = 0x02,
+};
+       
+/*
+ * widget types
+ */
+enum {
+       AC_WID_AUD_OUT,         /* Audio Out */
+       AC_WID_AUD_IN,          /* Audio In */
+       AC_WID_AUD_MIX,         /* Audio Mixer */
+       AC_WID_AUD_SEL,         /* Audio Selector */
+       AC_WID_PIN,             /* Pin Complex */
+       AC_WID_POWER,           /* Power */
+       AC_WID_VOL_KNB,         /* Volume Knob */
+       AC_WID_BEEP,            /* Beep Generator */
+       AC_WID_VENDOR = 0x0f    /* Vendor specific */
+};
+
+/*
+ * GET verbs
+ */
+#define AC_VERB_GET_STREAM_FORMAT              0x0a00
+#define AC_VERB_GET_AMP_GAIN_MUTE              0x0b00
+#define AC_VERB_GET_PROC_COEF                  0x0c00
+#define AC_VERB_GET_COEF_INDEX                 0x0d00
+#define AC_VERB_PARAMETERS                     0x0f00
+#define AC_VERB_GET_CONNECT_SEL                        0x0f01
+#define AC_VERB_GET_CONNECT_LIST               0x0f02
+#define AC_VERB_GET_PROC_STATE                 0x0f03
+#define AC_VERB_GET_SDI_SELECT                 0x0f04
+#define AC_VERB_GET_POWER_STATE                        0x0f05
+#define AC_VERB_GET_CONV                       0x0f06
+#define AC_VERB_GET_PIN_WIDGET_CONTROL         0x0f07
+#define AC_VERB_GET_UNSOLICITED_RESPONSE       0x0f08
+#define AC_VERB_GET_PIN_SENSE                  0x0f09
+#define AC_VERB_GET_BEEP_CONTROL               0x0f0a
+#define AC_VERB_GET_EAPD_BTLENABLE             0x0f0c
+#define AC_VERB_GET_DIGI_CONVERT_1             0x0f0d
+#define AC_VERB_GET_DIGI_CONVERT_2             0x0f0e /* unused */
+#define AC_VERB_GET_VOLUME_KNOB_CONTROL                0x0f0f
+/* f10-f1a: GPIO */
+#define AC_VERB_GET_GPIO_DATA                  0x0f15
+#define AC_VERB_GET_GPIO_MASK                  0x0f16
+#define AC_VERB_GET_GPIO_DIRECTION             0x0f17
+#define AC_VERB_GET_GPIO_WAKE_MASK             0x0f18
+#define AC_VERB_GET_GPIO_UNSOLICITED_RSP_MASK  0x0f19
+#define AC_VERB_GET_GPIO_STICKY_MASK           0x0f1a
+#define AC_VERB_GET_CONFIG_DEFAULT             0x0f1c
+/* f20: AFG/MFG */
+#define AC_VERB_GET_SUBSYSTEM_ID               0x0f20
+#define AC_VERB_GET_CVT_CHAN_COUNT             0x0f2d
+#define AC_VERB_GET_HDMI_DIP_SIZE              0x0f2e
+#define AC_VERB_GET_HDMI_ELDD                  0x0f2f
+#define AC_VERB_GET_HDMI_DIP_INDEX             0x0f30
+#define AC_VERB_GET_HDMI_DIP_DATA              0x0f31
+#define AC_VERB_GET_HDMI_DIP_XMIT              0x0f32
+#define AC_VERB_GET_HDMI_CP_CTRL               0x0f33
+#define AC_VERB_GET_HDMI_CHAN_SLOT             0x0f34
+
+/*
+ * SET verbs
+ */
+#define AC_VERB_SET_STREAM_FORMAT              0x200
+#define AC_VERB_SET_AMP_GAIN_MUTE              0x300
+#define AC_VERB_SET_PROC_COEF                  0x400
+#define AC_VERB_SET_COEF_INDEX                 0x500
+#define AC_VERB_SET_CONNECT_SEL                        0x701
+#define AC_VERB_SET_PROC_STATE                 0x703
+#define AC_VERB_SET_SDI_SELECT                 0x704
+#define AC_VERB_SET_POWER_STATE                        0x705
+#define AC_VERB_SET_CHANNEL_STREAMID           0x706
+#define AC_VERB_SET_PIN_WIDGET_CONTROL         0x707
+#define AC_VERB_SET_UNSOLICITED_ENABLE         0x708
+#define AC_VERB_SET_PIN_SENSE                  0x709
+#define AC_VERB_SET_BEEP_CONTROL               0x70a
+#define AC_VERB_SET_EAPD_BTLENABLE             0x70c
+#define AC_VERB_SET_DIGI_CONVERT_1             0x70d
+#define AC_VERB_SET_DIGI_CONVERT_2             0x70e
+#define AC_VERB_SET_VOLUME_KNOB_CONTROL                0x70f
+#define AC_VERB_SET_GPIO_DATA                  0x715
+#define AC_VERB_SET_GPIO_MASK                  0x716
+#define AC_VERB_SET_GPIO_DIRECTION             0x717
+#define AC_VERB_SET_GPIO_WAKE_MASK             0x718
+#define AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK  0x719
+#define AC_VERB_SET_GPIO_STICKY_MASK           0x71a
+#define AC_VERB_SET_CONFIG_DEFAULT_BYTES_0     0x71c
+#define AC_VERB_SET_CONFIG_DEFAULT_BYTES_1     0x71d
+#define AC_VERB_SET_CONFIG_DEFAULT_BYTES_2     0x71e
+#define AC_VERB_SET_CONFIG_DEFAULT_BYTES_3     0x71f
+#define AC_VERB_SET_EAPD                               0x788
+#define AC_VERB_SET_CODEC_RESET                        0x7ff
+#define AC_VERB_SET_CVT_CHAN_COUNT             0x72d
+#define AC_VERB_SET_HDMI_DIP_INDEX             0x730
+#define AC_VERB_SET_HDMI_DIP_DATA              0x731
+#define AC_VERB_SET_HDMI_DIP_XMIT              0x732
+#define AC_VERB_SET_HDMI_CP_CTRL               0x733
+#define AC_VERB_SET_HDMI_CHAN_SLOT             0x734
+
+/*
+ * Parameter IDs
+ */
+#define AC_PAR_VENDOR_ID               0x00
+#define AC_PAR_SUBSYSTEM_ID            0x01
+#define AC_PAR_REV_ID                  0x02
+#define AC_PAR_NODE_COUNT              0x04
+#define AC_PAR_FUNCTION_TYPE           0x05
+#define AC_PAR_AUDIO_FG_CAP            0x08
+#define AC_PAR_AUDIO_WIDGET_CAP                0x09
+#define AC_PAR_PCM                     0x0a
+#define AC_PAR_STREAM                  0x0b
+#define AC_PAR_PIN_CAP                 0x0c
+#define AC_PAR_AMP_IN_CAP              0x0d
+#define AC_PAR_CONNLIST_LEN            0x0e
+#define AC_PAR_POWER_STATE             0x0f
+#define AC_PAR_PROC_CAP                        0x10
+#define AC_PAR_GPIO_CAP                        0x11
+#define AC_PAR_AMP_OUT_CAP             0x12
+#define AC_PAR_VOL_KNB_CAP             0x13
+#define AC_PAR_HDMI_LPCM_CAP           0x20
+
+/*
+ * AC_VERB_PARAMETERS results (32bit)
+ */
+
+/* Function Group Type */
+#define AC_FGT_TYPE                    (0xff<<0)
+#define AC_FGT_TYPE_SHIFT              0
+#define AC_FGT_UNSOL_CAP               (1<<8)
+
+/* Audio Function Group Capabilities */
+#define AC_AFG_OUT_DELAY               (0xf<<0)
+#define AC_AFG_IN_DELAY                        (0xf<<8)
+#define AC_AFG_BEEP_GEN                        (1<<16)
+
+/* Audio Widget Capabilities */
+#define AC_WCAP_STEREO                 (1<<0)  /* stereo I/O */
+#define AC_WCAP_IN_AMP                 (1<<1)  /* AMP-in present */
+#define AC_WCAP_OUT_AMP                        (1<<2)  /* AMP-out present */
+#define AC_WCAP_AMP_OVRD               (1<<3)  /* AMP-parameter override */
+#define AC_WCAP_FORMAT_OVRD            (1<<4)  /* format override */
+#define AC_WCAP_STRIPE                 (1<<5)  /* stripe */
+#define AC_WCAP_PROC_WID               (1<<6)  /* Proc Widget */
+#define AC_WCAP_UNSOL_CAP              (1<<7)  /* Unsol capable */
+#define AC_WCAP_CONN_LIST              (1<<8)  /* connection list */
+#define AC_WCAP_DIGITAL                        (1<<9)  /* digital I/O */
+#define AC_WCAP_POWER                  (1<<10) /* power control */
+#define AC_WCAP_LR_SWAP                        (1<<11) /* L/R swap */
+#define AC_WCAP_CP_CAPS                        (1<<12) /* content protection */
+#define AC_WCAP_CHAN_CNT_EXT           (7<<13) /* channel count ext */
+#define AC_WCAP_DELAY                  (0xf<<16)
+#define AC_WCAP_DELAY_SHIFT            16
+#define AC_WCAP_TYPE                   (0xf<<20)
+#define AC_WCAP_TYPE_SHIFT             20
+
+/* supported PCM rates and bits */
+#define AC_SUPPCM_RATES                        (0xfff << 0)
+#define AC_SUPPCM_BITS_8               (1<<16)
+#define AC_SUPPCM_BITS_16              (1<<17)
+#define AC_SUPPCM_BITS_20              (1<<18)
+#define AC_SUPPCM_BITS_24              (1<<19)
+#define AC_SUPPCM_BITS_32              (1<<20)
+
+/* supported PCM stream format */
+#define AC_SUPFMT_PCM                  (1<<0)
+#define AC_SUPFMT_FLOAT32              (1<<1)
+#define AC_SUPFMT_AC3                  (1<<2)
+
+/* GP I/O count */
+#define AC_GPIO_IO_COUNT               (0xff<<0)
+#define AC_GPIO_O_COUNT                        (0xff<<8)
+#define AC_GPIO_O_COUNT_SHIFT          8
+#define AC_GPIO_I_COUNT                        (0xff<<16)
+#define AC_GPIO_I_COUNT_SHIFT          16
+#define AC_GPIO_UNSOLICITED            (1<<30)
+#define AC_GPIO_WAKE                   (1<<31)
+
+/* Converter stream, channel */
+#define AC_CONV_CHANNEL                        (0xf<<0)
+#define AC_CONV_STREAM                 (0xf<<4)
+#define AC_CONV_STREAM_SHIFT           4
+
+/* Input converter SDI select */
+#define AC_SDI_SELECT                  (0xf<<0)
+
+/* stream format id */
+#define AC_FMT_CHAN_SHIFT              0
+#define AC_FMT_CHAN_MASK               (0x0f << 0)
+#define AC_FMT_BITS_SHIFT              4
+#define AC_FMT_BITS_MASK               (7 << 4)
+#define AC_FMT_BITS_8                  (0 << 4)
+#define AC_FMT_BITS_16                 (1 << 4)
+#define AC_FMT_BITS_20                 (2 << 4)
+#define AC_FMT_BITS_24                 (3 << 4)
+#define AC_FMT_BITS_32                 (4 << 4)
+#define AC_FMT_DIV_SHIFT               8
+#define AC_FMT_DIV_MASK                        (7 << 8)
+#define AC_FMT_MULT_SHIFT              11
+#define AC_FMT_MULT_MASK               (7 << 11)
+#define AC_FMT_BASE_SHIFT              14
+#define AC_FMT_BASE_48K                        (0 << 14)
+#define AC_FMT_BASE_44K                        (1 << 14)
+#define AC_FMT_TYPE_SHIFT              15
+#define AC_FMT_TYPE_PCM                        (0 << 15)
+#define AC_FMT_TYPE_NON_PCM            (1 << 15)
+
+/* Unsolicited response control */
+#define AC_UNSOL_TAG                   (0x3f<<0)
+#define AC_UNSOL_ENABLED               (1<<7)
+#define AC_USRSP_EN                    AC_UNSOL_ENABLED
+
+/* Unsolicited responses */
+#define AC_UNSOL_RES_TAG               (0x3f<<26)
+#define AC_UNSOL_RES_TAG_SHIFT         26
+#define AC_UNSOL_RES_SUBTAG            (0x1f<<21)
+#define AC_UNSOL_RES_SUBTAG_SHIFT      21
+#define AC_UNSOL_RES_ELDV              (1<<1)  /* ELD Data valid (for HDMI) */
+#define AC_UNSOL_RES_PD                        (1<<0)  /* pinsense detect */
+#define AC_UNSOL_RES_CP_STATE          (1<<1)  /* content protection */
+#define AC_UNSOL_RES_CP_READY          (1<<0)  /* content protection */
+
+/* Pin widget capabilies */
+#define AC_PINCAP_IMP_SENSE            (1<<0)  /* impedance sense capable */
+#define AC_PINCAP_TRIG_REQ             (1<<1)  /* trigger required */
+#define AC_PINCAP_PRES_DETECT          (1<<2)  /* presence detect capable */
+#define AC_PINCAP_HP_DRV               (1<<3)  /* headphone drive capable */
+#define AC_PINCAP_OUT                  (1<<4)  /* output capable */
+#define AC_PINCAP_IN                   (1<<5)  /* input capable */
+#define AC_PINCAP_BALANCE              (1<<6)  /* balanced I/O capable */
+/* Note: This LR_SWAP pincap is defined in the Realtek ALC883 specification,
+ *       but is marked reserved in the Intel HDA specification.
+ */
+#define AC_PINCAP_LR_SWAP              (1<<7)  /* L/R swap */
+/* Note: The same bit as LR_SWAP is newly defined as HDMI capability
+ *       in HD-audio specification
+ */
+#define AC_PINCAP_HDMI                 (1<<7)  /* HDMI pin */
+#define AC_PINCAP_DP                   (1<<24) /* DisplayPort pin, can
+                                                * coexist with AC_PINCAP_HDMI
+                                                */
+#define AC_PINCAP_VREF                 (0x37<<8)
+#define AC_PINCAP_VREF_SHIFT           8
+#define AC_PINCAP_EAPD                 (1<<16) /* EAPD capable */
+#define AC_PINCAP_HBR                  (1<<27) /* High Bit Rate */
+/* Vref status (used in pin cap) */
+#define AC_PINCAP_VREF_HIZ             (1<<0)  /* Hi-Z */
+#define AC_PINCAP_VREF_50              (1<<1)  /* 50% */
+#define AC_PINCAP_VREF_GRD             (1<<2)  /* ground */
+#define AC_PINCAP_VREF_80              (1<<4)  /* 80% */
+#define AC_PINCAP_VREF_100             (1<<5)  /* 100% */
+
+/* Amplifier capabilities */
+#define AC_AMPCAP_OFFSET               (0x7f<<0)  /* 0dB offset */
+#define AC_AMPCAP_OFFSET_SHIFT         0
+#define AC_AMPCAP_NUM_STEPS            (0x7f<<8)  /* number of steps */
+#define AC_AMPCAP_NUM_STEPS_SHIFT      8
+#define AC_AMPCAP_STEP_SIZE            (0x7f<<16) /* step size 0-32dB
+                                                   * in 0.25dB
+                                                   */
+#define AC_AMPCAP_STEP_SIZE_SHIFT      16
+#define AC_AMPCAP_MUTE                 (1<<31)    /* mute capable */
+#define AC_AMPCAP_MUTE_SHIFT           31
+
+/* Connection list */
+#define AC_CLIST_LENGTH                        (0x7f<<0)
+#define AC_CLIST_LONG                  (1<<7)
+
+/* Supported power status */
+#define AC_PWRST_D0SUP                 (1<<0)
+#define AC_PWRST_D1SUP                 (1<<1)
+#define AC_PWRST_D2SUP                 (1<<2)
+#define AC_PWRST_D3SUP                 (1<<3)
+#define AC_PWRST_D3COLDSUP             (1<<4)
+#define AC_PWRST_S3D3COLDSUP           (1<<29)
+#define AC_PWRST_CLKSTOP               (1<<30)
+#define AC_PWRST_EPSS                  (1U<<31)
+
+/* Power state values */
+#define AC_PWRST_SETTING               (0xf<<0)
+#define AC_PWRST_ACTUAL                        (0xf<<4)
+#define AC_PWRST_ACTUAL_SHIFT          4
+#define AC_PWRST_D0                    0x00
+#define AC_PWRST_D1                    0x01
+#define AC_PWRST_D2                    0x02
+#define AC_PWRST_D3                    0x03
+
+/* Processing capabilies */
+#define AC_PCAP_BENIGN                 (1<<0)
+#define AC_PCAP_NUM_COEF               (0xff<<8)
+#define AC_PCAP_NUM_COEF_SHIFT         8
+
+/* Volume knobs capabilities */
+#define AC_KNBCAP_NUM_STEPS            (0x7f<<0)
+#define AC_KNBCAP_DELTA                        (1<<7)
+
+/* HDMI LPCM capabilities */
+#define AC_LPCMCAP_48K_CP_CHNS         (0x0f<<0) /* max channels w/ CP-on */   
+#define AC_LPCMCAP_48K_NO_CHNS         (0x0f<<4) /* max channels w/o CP-on */
+#define AC_LPCMCAP_48K_20BIT           (1<<8)  /* 20b bitrate supported */
+#define AC_LPCMCAP_48K_24BIT           (1<<9)  /* 24b bitrate supported */
+#define AC_LPCMCAP_96K_CP_CHNS         (0x0f<<10) /* max channels w/ CP-on */  
+#define AC_LPCMCAP_96K_NO_CHNS         (0x0f<<14) /* max channels w/o CP-on */
+#define AC_LPCMCAP_96K_20BIT           (1<<18) /* 20b bitrate supported */
+#define AC_LPCMCAP_96K_24BIT           (1<<19) /* 24b bitrate supported */
+#define AC_LPCMCAP_192K_CP_CHNS                (0x0f<<20) /* max channels w/ CP-on */  
+#define AC_LPCMCAP_192K_NO_CHNS                (0x0f<<24) /* max channels w/o CP-on */
+#define AC_LPCMCAP_192K_20BIT          (1<<28) /* 20b bitrate supported */
+#define AC_LPCMCAP_192K_24BIT          (1<<29) /* 24b bitrate supported */
+#define AC_LPCMCAP_44K                 (1<<30) /* 44.1kHz support */
+#define AC_LPCMCAP_44K_MS              (1<<31) /* 44.1kHz-multiplies support */
+
+/*
+ * Control Parameters
+ */
+
+/* Amp gain/mute */
+#define AC_AMP_MUTE                    (1<<7)
+#define AC_AMP_GAIN                    (0x7f)
+#define AC_AMP_GET_INDEX               (0xf<<0)
+
+#define AC_AMP_GET_LEFT                        (1<<13)
+#define AC_AMP_GET_RIGHT               (0<<13)
+#define AC_AMP_GET_OUTPUT              (1<<15)
+#define AC_AMP_GET_INPUT               (0<<15)
+
+#define AC_AMP_SET_INDEX               (0xf<<8)
+#define AC_AMP_SET_INDEX_SHIFT         8
+#define AC_AMP_SET_RIGHT               (1<<12)
+#define AC_AMP_SET_LEFT                        (1<<13)
+#define AC_AMP_SET_INPUT               (1<<14)
+#define AC_AMP_SET_OUTPUT              (1<<15)
+
+/* DIGITAL1 bits */
+#define AC_DIG1_ENABLE                 (1<<0)
+#define AC_DIG1_V                      (1<<1)
+#define AC_DIG1_VCFG                   (1<<2)
+#define AC_DIG1_EMPHASIS               (1<<3)
+#define AC_DIG1_COPYRIGHT              (1<<4)
+#define AC_DIG1_NONAUDIO               (1<<5)
+#define AC_DIG1_PROFESSIONAL           (1<<6)
+#define AC_DIG1_LEVEL                  (1<<7)
+
+/* DIGITAL2 bits */
+#define AC_DIG2_CC                     (0x7f<<0)
+
+/* Pin widget control - 8bit */
+#define AC_PINCTL_EPT                  (0x3<<0)
+#define AC_PINCTL_EPT_NATIVE           0
+#define AC_PINCTL_EPT_HBR              3
+#define AC_PINCTL_VREFEN               (0x7<<0)
+#define AC_PINCTL_VREF_HIZ             0       /* Hi-Z */
+#define AC_PINCTL_VREF_50              1       /* 50% */
+#define AC_PINCTL_VREF_GRD             2       /* ground */
+#define AC_PINCTL_VREF_80              4       /* 80% */
+#define AC_PINCTL_VREF_100             5       /* 100% */
+#define AC_PINCTL_IN_EN                        (1<<5)
+#define AC_PINCTL_OUT_EN               (1<<6)
+#define AC_PINCTL_HP_EN                        (1<<7)
+
+/* Pin sense - 32bit */
+#define AC_PINSENSE_IMPEDANCE_MASK     (0x7fffffff)
+#define AC_PINSENSE_PRESENCE           (1<<31)
+#define AC_PINSENSE_ELDV               (1<<30) /* ELD valid (HDMI) */
+
+/* EAPD/BTL enable - 32bit */
+#define AC_EAPDBTL_BALANCED            (1<<0)
+#define AC_EAPDBTL_EAPD                        (1<<1)
+#define AC_EAPDBTL_LR_SWAP             (1<<2)
+
+/* HDMI ELD data */
+#define AC_ELDD_ELD_VALID              (1<<31)
+#define AC_ELDD_ELD_DATA               0xff
+
+/* HDMI DIP size */
+#define AC_DIPSIZE_ELD_BUF             (1<<3) /* ELD buf size of packet size */
+#define AC_DIPSIZE_PACK_IDX            (0x07<<0) /* packet index */
+
+/* HDMI DIP index */
+#define AC_DIPIDX_PACK_IDX             (0x07<<5) /* packet idnex */
+#define AC_DIPIDX_BYTE_IDX             (0x1f<<0) /* byte index */
+
+/* HDMI DIP xmit (transmit) control */
+#define AC_DIPXMIT_MASK                        (0x3<<6)
+#define AC_DIPXMIT_DISABLE             (0x0<<6) /* disable xmit */
+#define AC_DIPXMIT_ONCE                        (0x2<<6) /* xmit once then disable */
+#define AC_DIPXMIT_BEST                        (0x3<<6) /* best effort */
+
+/* HDMI content protection (CP) control */
+#define AC_CPCTRL_CES                  (1<<9) /* current encryption state */
+#define AC_CPCTRL_READY                        (1<<8) /* ready bit */
+#define AC_CPCTRL_SUBTAG               (0x1f<<3) /* subtag for unsol-resp */
+#define AC_CPCTRL_STATE                        (3<<0) /* current CP request state */
+
+/* Converter channel <-> HDMI slot mapping */
+#define AC_CVTMAP_HDMI_SLOT            (0xf<<0) /* HDMI slot number */
+#define AC_CVTMAP_CHAN                 (0xf<<4) /* converter channel number */
+
+/* configuration default - 32bit */
+#define AC_DEFCFG_SEQUENCE             (0xf<<0)
+#define AC_DEFCFG_DEF_ASSOC            (0xf<<4)
+#define AC_DEFCFG_ASSOC_SHIFT          4
+#define AC_DEFCFG_MISC                 (0xf<<8)
+#define AC_DEFCFG_MISC_SHIFT           8
+#define AC_DEFCFG_MISC_NO_PRESENCE     (1<<0)
+#define AC_DEFCFG_COLOR                        (0xf<<12)
+#define AC_DEFCFG_COLOR_SHIFT          12
+#define AC_DEFCFG_CONN_TYPE            (0xf<<16)
+#define AC_DEFCFG_CONN_TYPE_SHIFT      16
+#define AC_DEFCFG_DEVICE               (0xf<<20)
+#define AC_DEFCFG_DEVICE_SHIFT         20
+#define AC_DEFCFG_LOCATION             (0x3f<<24)
+#define AC_DEFCFG_LOCATION_SHIFT       24
+#define AC_DEFCFG_PORT_CONN            (0x3<<30)
+#define AC_DEFCFG_PORT_CONN_SHIFT      30
+
+/* device device types (0x0-0xf) */
+enum {
+       AC_JACK_LINE_OUT,
+       AC_JACK_SPEAKER,
+       AC_JACK_HP_OUT,
+       AC_JACK_CD,
+       AC_JACK_SPDIF_OUT,
+       AC_JACK_DIG_OTHER_OUT,
+       AC_JACK_MODEM_LINE_SIDE,
+       AC_JACK_MODEM_HAND_SIDE,
+       AC_JACK_LINE_IN,
+       AC_JACK_AUX,
+       AC_JACK_MIC_IN,
+       AC_JACK_TELEPHONY,
+       AC_JACK_SPDIF_IN,
+       AC_JACK_DIG_OTHER_IN,
+       AC_JACK_OTHER = 0xf,
+};
+
+/* jack connection types (0x0-0xf) */
+enum {
+       AC_JACK_CONN_UNKNOWN,
+       AC_JACK_CONN_1_8,
+       AC_JACK_CONN_1_4,
+       AC_JACK_CONN_ATAPI,
+       AC_JACK_CONN_RCA,
+       AC_JACK_CONN_OPTICAL,
+       AC_JACK_CONN_OTHER_DIGITAL,
+       AC_JACK_CONN_OTHER_ANALOG,
+       AC_JACK_CONN_DIN,
+       AC_JACK_CONN_XLR,
+       AC_JACK_CONN_RJ11,
+       AC_JACK_CONN_COMB,
+       AC_JACK_CONN_OTHER = 0xf,
+};
+
+/* jack colors (0x0-0xf) */
+enum {
+       AC_JACK_COLOR_UNKNOWN,
+       AC_JACK_COLOR_BLACK,
+       AC_JACK_COLOR_GREY,
+       AC_JACK_COLOR_BLUE,
+       AC_JACK_COLOR_GREEN,
+       AC_JACK_COLOR_RED,
+       AC_JACK_COLOR_ORANGE,
+       AC_JACK_COLOR_YELLOW,
+       AC_JACK_COLOR_PURPLE,
+       AC_JACK_COLOR_PINK,
+       AC_JACK_COLOR_WHITE = 0xe,
+       AC_JACK_COLOR_OTHER,
+};
+
+/* Jack location (0x0-0x3f) */
+/* common case */
+enum {
+       AC_JACK_LOC_NONE,
+       AC_JACK_LOC_REAR,
+       AC_JACK_LOC_FRONT,
+       AC_JACK_LOC_LEFT,
+       AC_JACK_LOC_RIGHT,
+       AC_JACK_LOC_TOP,
+       AC_JACK_LOC_BOTTOM,
+};
+/* bits 4-5 */
+enum {
+       AC_JACK_LOC_EXTERNAL = 0x00,
+       AC_JACK_LOC_INTERNAL = 0x10,
+       AC_JACK_LOC_SEPARATE = 0x20,
+       AC_JACK_LOC_OTHER    = 0x30,
+};
+enum {
+       /* external on primary chasis */
+       AC_JACK_LOC_REAR_PANEL = 0x07,
+       AC_JACK_LOC_DRIVE_BAY,
+       /* internal */
+       AC_JACK_LOC_RISER = 0x17,
+       AC_JACK_LOC_HDMI,
+       AC_JACK_LOC_ATAPI,
+       /* others */
+       AC_JACK_LOC_MOBILE_IN = 0x37,
+       AC_JACK_LOC_MOBILE_OUT,
+};
+
+/* Port connectivity (0-3) */
+enum {
+       AC_JACK_PORT_COMPLEX,
+       AC_JACK_PORT_NONE,
+       AC_JACK_PORT_FIXED,
+       AC_JACK_PORT_BOTH,
+};
+
+/* max. connections to a widget */
+#define HDA_MAX_CONNECTIONS    32
+
+/* max. codec address */
+#define HDA_MAX_CODEC_ADDRESS  0x0f
+
+/* max number of PCM devics per card */
+#define HDA_MAX_PCMS           10
+
+/* --------------------------------------------------------------------- */
+
+#endif
diff --git a/hw/audio/intel-hda.c b/hw/audio/intel-hda.c
new file mode 100644 (file)
index 0000000..3d8077a
--- /dev/null
@@ -0,0 +1,1329 @@
+/*
+ * Copyright (C) 2010 Red Hat, Inc.
+ *
+ * written by Gerd Hoffmann <kraxel@redhat.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 or
+ * (at your option) version 3 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
+ * 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 "hw/hw.h"
+#include "hw/pci/pci.h"
+#include "hw/pci/msi.h"
+#include "qemu/timer.h"
+#include "hw/audio/audio.h"
+#include "intel-hda.h"
+#include "intel-hda-defs.h"
+#include "sysemu/dma.h"
+
+/* --------------------------------------------------------------------- */
+/* hda bus                                                               */
+
+static Property hda_props[] = {
+    DEFINE_PROP_UINT32("cad", HDACodecDevice, cad, -1),
+    DEFINE_PROP_END_OF_LIST()
+};
+
+static const TypeInfo hda_codec_bus_info = {
+    .name = TYPE_HDA_BUS,
+    .parent = TYPE_BUS,
+    .instance_size = sizeof(HDACodecBus),
+};
+
+void hda_codec_bus_init(DeviceState *dev, HDACodecBus *bus,
+                        hda_codec_response_func response,
+                        hda_codec_xfer_func xfer)
+{
+    qbus_create_inplace(&bus->qbus, TYPE_HDA_BUS, dev, NULL);
+    bus->response = response;
+    bus->xfer = xfer;
+}
+
+static int hda_codec_dev_init(DeviceState *qdev)
+{
+    HDACodecBus *bus = DO_UPCAST(HDACodecBus, qbus, qdev->parent_bus);
+    HDACodecDevice *dev = DO_UPCAST(HDACodecDevice, qdev, qdev);
+    HDACodecDeviceClass *cdc = HDA_CODEC_DEVICE_GET_CLASS(dev);
+
+    if (dev->cad == -1) {
+        dev->cad = bus->next_cad;
+    }
+    if (dev->cad >= 15) {
+        return -1;
+    }
+    bus->next_cad = dev->cad + 1;
+    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 (cdc->exit) {
+        cdc->exit(dev);
+    }
+    return 0;
+}
+
+HDACodecDevice *hda_codec_find(HDACodecBus *bus, uint32_t cad)
+{
+    BusChild *kid;
+    HDACodecDevice *cdev;
+
+    QTAILQ_FOREACH(kid, &bus->qbus.children, sibling) {
+        DeviceState *qdev = kid->child;
+        cdev = DO_UPCAST(HDACodecDevice, qdev, qdev);
+        if (cdev->cad == cad) {
+            return cdev;
+        }
+    }
+    return NULL;
+}
+
+void hda_codec_response(HDACodecDevice *dev, bool solicited, uint32_t response)
+{
+    HDACodecBus *bus = DO_UPCAST(HDACodecBus, qbus, dev->qdev.parent_bus);
+    bus->response(dev, solicited, response);
+}
+
+bool hda_codec_xfer(HDACodecDevice *dev, uint32_t stnr, bool output,
+                    uint8_t *buf, uint32_t len)
+{
+    HDACodecBus *bus = DO_UPCAST(HDACodecBus, qbus, dev->qdev.parent_bus);
+    return bus->xfer(dev, stnr, output, buf, len);
+}
+
+/* --------------------------------------------------------------------- */
+/* intel hda emulation                                                   */
+
+typedef struct IntelHDAStream IntelHDAStream;
+typedef struct IntelHDAState IntelHDAState;
+typedef struct IntelHDAReg IntelHDAReg;
+
+typedef struct bpl {
+    uint64_t addr;
+    uint32_t len;
+    uint32_t flags;
+} bpl;
+
+struct IntelHDAStream {
+    /* registers */
+    uint32_t ctl;
+    uint32_t lpib;
+    uint32_t cbl;
+    uint32_t lvi;
+    uint32_t fmt;
+    uint32_t bdlp_lbase;
+    uint32_t bdlp_ubase;
+
+    /* state */
+    bpl      *bpl;
+    uint32_t bentries;
+    uint32_t bsize, be, bp;
+};
+
+struct IntelHDAState {
+    PCIDevice pci;
+    const char *name;
+    HDACodecBus codecs;
+
+    /* registers */
+    uint32_t g_ctl;
+    uint32_t wake_en;
+    uint32_t state_sts;
+    uint32_t int_ctl;
+    uint32_t int_sts;
+    uint32_t wall_clk;
+
+    uint32_t corb_lbase;
+    uint32_t corb_ubase;
+    uint32_t corb_rp;
+    uint32_t corb_wp;
+    uint32_t corb_ctl;
+    uint32_t corb_sts;
+    uint32_t corb_size;
+
+    uint32_t rirb_lbase;
+    uint32_t rirb_ubase;
+    uint32_t rirb_wp;
+    uint32_t rirb_cnt;
+    uint32_t rirb_ctl;
+    uint32_t rirb_sts;
+    uint32_t rirb_size;
+
+    uint32_t dp_lbase;
+    uint32_t dp_ubase;
+
+    uint32_t icw;
+    uint32_t irr;
+    uint32_t ics;
+
+    /* streams */
+    IntelHDAStream st[8];
+
+    /* state */
+    MemoryRegion mmio;
+    uint32_t rirb_count;
+    int64_t wall_base_ns;
+
+    /* debug logging */
+    const IntelHDAReg *last_reg;
+    uint32_t last_val;
+    uint32_t last_write;
+    uint32_t last_sec;
+    uint32_t repeat_count;
+
+    /* properties */
+    uint32_t debug;
+    uint32_t msi;
+};
+
+struct IntelHDAReg {
+    const char *name;      /* register name */
+    uint32_t   size;       /* size in bytes */
+    uint32_t   reset;      /* reset value */
+    uint32_t   wmask;      /* write mask */
+    uint32_t   wclear;     /* write 1 to clear bits */
+    uint32_t   offset;     /* location in IntelHDAState */
+    uint32_t   shift;      /* byte access entries for dwords */
+    uint32_t   stream;
+    void       (*whandler)(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old);
+    void       (*rhandler)(IntelHDAState *d, const IntelHDAReg *reg);
+};
+
+static void intel_hda_reset(DeviceState *dev);
+
+/* --------------------------------------------------------------------- */
+
+static hwaddr intel_hda_addr(uint32_t lbase, uint32_t ubase)
+{
+    hwaddr addr;
+
+    addr = ((uint64_t)ubase << 32) | lbase;
+    return addr;
+}
+
+static void intel_hda_update_int_sts(IntelHDAState *d)
+{
+    uint32_t sts = 0;
+    uint32_t i;
+
+    /* update controller status */
+    if (d->rirb_sts & ICH6_RBSTS_IRQ) {
+        sts |= (1 << 30);
+    }
+    if (d->rirb_sts & ICH6_RBSTS_OVERRUN) {
+        sts |= (1 << 30);
+    }
+    if (d->state_sts & d->wake_en) {
+        sts |= (1 << 30);
+    }
+
+    /* update stream status */
+    for (i = 0; i < 8; i++) {
+        /* buffer completion interrupt */
+        if (d->st[i].ctl & (1 << 26)) {
+            sts |= (1 << i);
+        }
+    }
+
+    /* update global status */
+    if (sts & d->int_ctl) {
+        sts |= (1 << 31);
+    }
+
+    d->int_sts = sts;
+}
+
+static void intel_hda_update_irq(IntelHDAState *d)
+{
+    int msi = d->msi && msi_enabled(&d->pci);
+    int level;
+
+    intel_hda_update_int_sts(d);
+    if (d->int_sts & (1 << 31) && d->int_ctl & (1 << 31)) {
+        level = 1;
+    } else {
+        level = 0;
+    }
+    dprint(d, 2, "%s: level %d [%s]\n", __FUNCTION__,
+           level, msi ? "msi" : "intx");
+    if (msi) {
+        if (level) {
+            msi_notify(&d->pci, 0);
+        }
+    } else {
+        qemu_set_irq(d->pci.irq[0], level);
+    }
+}
+
+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)) {
+        /* indirect node addressing, not specified in HDA 1.0 */
+        dprint(d, 1, "%s: indirect node addressing (guest bug?)\n", __FUNCTION__);
+        return -1;
+    }
+    nid = (verb >> 20) & 0x7f;
+    data = verb & 0xfffff;
+
+    codec = hda_codec_find(&d->codecs, cad);
+    if (codec == NULL) {
+        dprint(d, 1, "%s: addressed non-existing codec\n", __FUNCTION__);
+        return -1;
+    }
+    cdc = HDA_CODEC_DEVICE_GET_CLASS(codec);
+    cdc->command(codec, nid, data);
+    return 0;
+}
+
+static void intel_hda_corb_run(IntelHDAState *d)
+{
+    hwaddr addr;
+    uint32_t rp, verb;
+
+    if (d->ics & ICH6_IRS_BUSY) {
+        dprint(d, 2, "%s: [icw] verb 0x%08x\n", __FUNCTION__, d->icw);
+        intel_hda_send_command(d, d->icw);
+        return;
+    }
+
+    for (;;) {
+        if (!(d->corb_ctl & ICH6_CORBCTL_RUN)) {
+            dprint(d, 2, "%s: !run\n", __FUNCTION__);
+            return;
+        }
+        if ((d->corb_rp & 0xff) == d->corb_wp) {
+            dprint(d, 2, "%s: corb ring empty\n", __FUNCTION__);
+            return;
+        }
+        if (d->rirb_count == d->rirb_cnt) {
+            dprint(d, 2, "%s: rirb count reached\n", __FUNCTION__);
+            return;
+        }
+
+        rp = (d->corb_rp + 1) & 0xff;
+        addr = intel_hda_addr(d->corb_lbase, d->corb_ubase);
+        verb = ldl_le_pci_dma(&d->pci, addr + 4*rp);
+        d->corb_rp = rp;
+
+        dprint(d, 2, "%s: [rp 0x%x] verb 0x%08x\n", __FUNCTION__, rp, verb);
+        intel_hda_send_command(d, verb);
+    }
+}
+
+static void intel_hda_response(HDACodecDevice *dev, bool solicited, uint32_t response)
+{
+    HDACodecBus *bus = DO_UPCAST(HDACodecBus, qbus, dev->qdev.parent_bus);
+    IntelHDAState *d = container_of(bus, IntelHDAState, codecs);
+    hwaddr addr;
+    uint32_t wp, ex;
+
+    if (d->ics & ICH6_IRS_BUSY) {
+        dprint(d, 2, "%s: [irr] response 0x%x, cad 0x%x\n",
+               __FUNCTION__, response, dev->cad);
+        d->irr = response;
+        d->ics &= ~(ICH6_IRS_BUSY | 0xf0);
+        d->ics |= (ICH6_IRS_VALID | (dev->cad << 4));
+        return;
+    }
+
+    if (!(d->rirb_ctl & ICH6_RBCTL_DMA_EN)) {
+        dprint(d, 1, "%s: rirb dma disabled, drop codec response\n", __FUNCTION__);
+        return;
+    }
+
+    ex = (solicited ? 0 : (1 << 4)) | dev->cad;
+    wp = (d->rirb_wp + 1) & 0xff;
+    addr = intel_hda_addr(d->rirb_lbase, d->rirb_ubase);
+    stl_le_pci_dma(&d->pci, addr + 8*wp, response);
+    stl_le_pci_dma(&d->pci, addr + 8*wp + 4, ex);
+    d->rirb_wp = wp;
+
+    dprint(d, 2, "%s: [wp 0x%x] response 0x%x, extra 0x%x\n",
+           __FUNCTION__, wp, response, ex);
+
+    d->rirb_count++;
+    if (d->rirb_count == d->rirb_cnt) {
+        dprint(d, 2, "%s: rirb count reached (%d)\n", __FUNCTION__, d->rirb_count);
+        if (d->rirb_ctl & ICH6_RBCTL_IRQ_EN) {
+            d->rirb_sts |= ICH6_RBSTS_IRQ;
+            intel_hda_update_irq(d);
+        }
+    } else if ((d->corb_rp & 0xff) == d->corb_wp) {
+        dprint(d, 2, "%s: corb ring empty (%d/%d)\n", __FUNCTION__,
+               d->rirb_count, d->rirb_cnt);
+        if (d->rirb_ctl & ICH6_RBCTL_IRQ_EN) {
+            d->rirb_sts |= ICH6_RBSTS_IRQ;
+            intel_hda_update_irq(d);
+        }
+    }
+}
+
+static bool intel_hda_xfer(HDACodecDevice *dev, uint32_t stnr, bool output,
+                           uint8_t *buf, uint32_t len)
+{
+    HDACodecBus *bus = DO_UPCAST(HDACodecBus, qbus, dev->qdev.parent_bus);
+    IntelHDAState *d = container_of(bus, IntelHDAState, codecs);
+    hwaddr addr;
+    uint32_t s, copy, left;
+    IntelHDAStream *st;
+    bool irq = false;
+
+    st = output ? d->st + 4 : d->st;
+    for (s = 0; s < 4; s++) {
+        if (stnr == ((st[s].ctl >> 20) & 0x0f)) {
+            st = st + s;
+            break;
+        }
+    }
+    if (s == 4) {
+        return false;
+    }
+    if (st->bpl == NULL) {
+        return false;
+    }
+    if (st->ctl & (1 << 26)) {
+        /*
+         * Wait with the next DMA xfer until the guest
+         * has acked the buffer completion interrupt
+         */
+        return false;
+    }
+
+    left = len;
+    while (left > 0) {
+        copy = left;
+        if (copy > st->bsize - st->lpib)
+            copy = st->bsize - st->lpib;
+        if (copy > st->bpl[st->be].len - st->bp)
+            copy = st->bpl[st->be].len - st->bp;
+
+        dprint(d, 3, "dma: entry %d, pos %d/%d, copy %d\n",
+               st->be, st->bp, st->bpl[st->be].len, copy);
+
+        pci_dma_rw(&d->pci, st->bpl[st->be].addr + st->bp, buf, copy, !output);
+        st->lpib += copy;
+        st->bp += copy;
+        buf += copy;
+        left -= copy;
+
+        if (st->bpl[st->be].len == st->bp) {
+            /* bpl entry filled */
+            if (st->bpl[st->be].flags & 0x01) {
+                irq = true;
+            }
+            st->bp = 0;
+            st->be++;
+            if (st->be == st->bentries) {
+                /* bpl wrap around */
+                st->be = 0;
+                st->lpib = 0;
+            }
+        }
+    }
+    if (d->dp_lbase & 0x01) {
+        addr = intel_hda_addr(d->dp_lbase & ~0x01, d->dp_ubase);
+        stl_le_pci_dma(&d->pci, addr + 8*s, st->lpib);
+    }
+    dprint(d, 3, "dma: --\n");
+
+    if (irq) {
+        st->ctl |= (1 << 26); /* buffer completion interrupt */
+        intel_hda_update_irq(d);
+    }
+    return true;
+}
+
+static void intel_hda_parse_bdl(IntelHDAState *d, IntelHDAStream *st)
+{
+    hwaddr addr;
+    uint8_t buf[16];
+    uint32_t i;
+
+    addr = intel_hda_addr(st->bdlp_lbase, st->bdlp_ubase);
+    st->bentries = st->lvi +1;
+    g_free(st->bpl);
+    st->bpl = g_malloc(sizeof(bpl) * st->bentries);
+    for (i = 0; i < st->bentries; i++, addr += 16) {
+        pci_dma_read(&d->pci, addr, buf, 16);
+        st->bpl[i].addr  = le64_to_cpu(*(uint64_t *)buf);
+        st->bpl[i].len   = le32_to_cpu(*(uint32_t *)(buf + 8));
+        st->bpl[i].flags = le32_to_cpu(*(uint32_t *)(buf + 12));
+        dprint(d, 1, "bdl/%d: 0x%" PRIx64 " +0x%x, 0x%x\n",
+               i, st->bpl[i].addr, st->bpl[i].len, st->bpl[i].flags);
+    }
+
+    st->bsize = st->cbl;
+    st->lpib  = 0;
+    st->be    = 0;
+    st->bp    = 0;
+}
+
+static void intel_hda_notify_codecs(IntelHDAState *d, uint32_t stream, bool running, bool output)
+{
+    BusChild *kid;
+    HDACodecDevice *cdev;
+
+    QTAILQ_FOREACH(kid, &d->codecs.qbus.children, sibling) {
+        DeviceState *qdev = kid->child;
+        HDACodecDeviceClass *cdc;
+
+        cdev = DO_UPCAST(HDACodecDevice, qdev, qdev);
+        cdc = HDA_CODEC_DEVICE_GET_CLASS(cdev);
+        if (cdc->stream) {
+            cdc->stream(cdev, stream, running, output);
+        }
+    }
+}
+
+/* --------------------------------------------------------------------- */
+
+static void intel_hda_set_g_ctl(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
+{
+    if ((d->g_ctl & ICH6_GCTL_RESET) == 0) {
+        intel_hda_reset(&d->pci.qdev);
+    }
+}
+
+static void intel_hda_set_wake_en(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
+{
+    intel_hda_update_irq(d);
+}
+
+static void intel_hda_set_state_sts(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
+{
+    intel_hda_update_irq(d);
+}
+
+static void intel_hda_set_int_ctl(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
+{
+    intel_hda_update_irq(d);
+}
+
+static void intel_hda_get_wall_clk(IntelHDAState *d, const IntelHDAReg *reg)
+{
+    int64_t ns;
+
+    ns = qemu_get_clock_ns(vm_clock) - d->wall_base_ns;
+    d->wall_clk = (uint32_t)(ns * 24 / 1000);  /* 24 MHz */
+}
+
+static void intel_hda_set_corb_wp(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
+{
+    intel_hda_corb_run(d);
+}
+
+static void intel_hda_set_corb_ctl(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
+{
+    intel_hda_corb_run(d);
+}
+
+static void intel_hda_set_rirb_wp(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
+{
+    if (d->rirb_wp & ICH6_RIRBWP_RST) {
+        d->rirb_wp = 0;
+    }
+}
+
+static void intel_hda_set_rirb_sts(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
+{
+    intel_hda_update_irq(d);
+
+    if ((old & ICH6_RBSTS_IRQ) && !(d->rirb_sts & ICH6_RBSTS_IRQ)) {
+        /* cleared ICH6_RBSTS_IRQ */
+        d->rirb_count = 0;
+        intel_hda_corb_run(d);
+    }
+}
+
+static void intel_hda_set_ics(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
+{
+    if (d->ics & ICH6_IRS_BUSY) {
+        intel_hda_corb_run(d);
+    }
+}
+
+static void intel_hda_set_st_ctl(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
+{
+    bool output = reg->stream >= 4;
+    IntelHDAStream *st = d->st + reg->stream;
+
+    if (st->ctl & 0x01) {
+        /* reset */
+        dprint(d, 1, "st #%d: reset\n", reg->stream);
+        st->ctl = 0;
+    }
+    if ((st->ctl & 0x02) != (old & 0x02)) {
+        uint32_t stnr = (st->ctl >> 20) & 0x0f;
+        /* run bit flipped */
+        if (st->ctl & 0x02) {
+            /* start */
+            dprint(d, 1, "st #%d: start %d (ring buf %d bytes)\n",
+                   reg->stream, stnr, st->cbl);
+            intel_hda_parse_bdl(d, st);
+            intel_hda_notify_codecs(d, stnr, true, output);
+        } else {
+            /* stop */
+            dprint(d, 1, "st #%d: stop %d\n", reg->stream, stnr);
+            intel_hda_notify_codecs(d, stnr, false, output);
+        }
+    }
+    intel_hda_update_irq(d);
+}
+
+/* --------------------------------------------------------------------- */
+
+#define ST_REG(_n, _o) (0x80 + (_n) * 0x20 + (_o))
+
+static const struct IntelHDAReg regtab[] = {
+    /* global */
+    [ ICH6_REG_GCAP ] = {
+        .name     = "GCAP",
+        .size     = 2,
+        .reset    = 0x4401,
+    },
+    [ ICH6_REG_VMIN ] = {
+        .name     = "VMIN",
+        .size     = 1,
+    },
+    [ ICH6_REG_VMAJ ] = {
+        .name     = "VMAJ",
+        .size     = 1,
+        .reset    = 1,
+    },
+    [ ICH6_REG_OUTPAY ] = {
+        .name     = "OUTPAY",
+        .size     = 2,
+        .reset    = 0x3c,
+    },
+    [ ICH6_REG_INPAY ] = {
+        .name     = "INPAY",
+        .size     = 2,
+        .reset    = 0x1d,
+    },
+    [ ICH6_REG_GCTL ] = {
+        .name     = "GCTL",
+        .size     = 4,
+        .wmask    = 0x0103,
+        .offset   = offsetof(IntelHDAState, g_ctl),
+        .whandler = intel_hda_set_g_ctl,
+    },
+    [ ICH6_REG_WAKEEN ] = {
+        .name     = "WAKEEN",
+        .size     = 2,
+        .wmask    = 0x7fff,
+        .offset   = offsetof(IntelHDAState, wake_en),
+        .whandler = intel_hda_set_wake_en,
+    },
+    [ ICH6_REG_STATESTS ] = {
+        .name     = "STATESTS",
+        .size     = 2,
+        .wmask    = 0x7fff,
+        .wclear   = 0x7fff,
+        .offset   = offsetof(IntelHDAState, state_sts),
+        .whandler = intel_hda_set_state_sts,
+    },
+
+    /* interrupts */
+    [ ICH6_REG_INTCTL ] = {
+        .name     = "INTCTL",
+        .size     = 4,
+        .wmask    = 0xc00000ff,
+        .offset   = offsetof(IntelHDAState, int_ctl),
+        .whandler = intel_hda_set_int_ctl,
+    },
+    [ ICH6_REG_INTSTS ] = {
+        .name     = "INTSTS",
+        .size     = 4,
+        .wmask    = 0xc00000ff,
+        .wclear   = 0xc00000ff,
+        .offset   = offsetof(IntelHDAState, int_sts),
+    },
+
+    /* misc */
+    [ ICH6_REG_WALLCLK ] = {
+        .name     = "WALLCLK",
+        .size     = 4,
+        .offset   = offsetof(IntelHDAState, wall_clk),
+        .rhandler = intel_hda_get_wall_clk,
+    },
+    [ ICH6_REG_WALLCLK + 0x2000 ] = {
+        .name     = "WALLCLK(alias)",
+        .size     = 4,
+        .offset   = offsetof(IntelHDAState, wall_clk),
+        .rhandler = intel_hda_get_wall_clk,
+    },
+
+    /* dma engine */
+    [ ICH6_REG_CORBLBASE ] = {
+        .name     = "CORBLBASE",
+        .size     = 4,
+        .wmask    = 0xffffff80,
+        .offset   = offsetof(IntelHDAState, corb_lbase),
+    },
+    [ ICH6_REG_CORBUBASE ] = {
+        .name     = "CORBUBASE",
+        .size     = 4,
+        .wmask    = 0xffffffff,
+        .offset   = offsetof(IntelHDAState, corb_ubase),
+    },
+    [ ICH6_REG_CORBWP ] = {
+        .name     = "CORBWP",
+        .size     = 2,
+        .wmask    = 0xff,
+        .offset   = offsetof(IntelHDAState, corb_wp),
+        .whandler = intel_hda_set_corb_wp,
+    },
+    [ ICH6_REG_CORBRP ] = {
+        .name     = "CORBRP",
+        .size     = 2,
+        .wmask    = 0x80ff,
+        .offset   = offsetof(IntelHDAState, corb_rp),
+    },
+    [ ICH6_REG_CORBCTL ] = {
+        .name     = "CORBCTL",
+        .size     = 1,
+        .wmask    = 0x03,
+        .offset   = offsetof(IntelHDAState, corb_ctl),
+        .whandler = intel_hda_set_corb_ctl,
+    },
+    [ ICH6_REG_CORBSTS ] = {
+        .name     = "CORBSTS",
+        .size     = 1,
+        .wmask    = 0x01,
+        .wclear   = 0x01,
+        .offset   = offsetof(IntelHDAState, corb_sts),
+    },
+    [ ICH6_REG_CORBSIZE ] = {
+        .name     = "CORBSIZE",
+        .size     = 1,
+        .reset    = 0x42,
+        .offset   = offsetof(IntelHDAState, corb_size),
+    },
+    [ ICH6_REG_RIRBLBASE ] = {
+        .name     = "RIRBLBASE",
+        .size     = 4,
+        .wmask    = 0xffffff80,
+        .offset   = offsetof(IntelHDAState, rirb_lbase),
+    },
+    [ ICH6_REG_RIRBUBASE ] = {
+        .name     = "RIRBUBASE",
+        .size     = 4,
+        .wmask    = 0xffffffff,
+        .offset   = offsetof(IntelHDAState, rirb_ubase),
+    },
+    [ ICH6_REG_RIRBWP ] = {
+        .name     = "RIRBWP",
+        .size     = 2,
+        .wmask    = 0x8000,
+        .offset   = offsetof(IntelHDAState, rirb_wp),
+        .whandler = intel_hda_set_rirb_wp,
+    },
+    [ ICH6_REG_RINTCNT ] = {
+        .name     = "RINTCNT",
+        .size     = 2,
+        .wmask    = 0xff,
+        .offset   = offsetof(IntelHDAState, rirb_cnt),
+    },
+    [ ICH6_REG_RIRBCTL ] = {
+        .name     = "RIRBCTL",
+        .size     = 1,
+        .wmask    = 0x07,
+        .offset   = offsetof(IntelHDAState, rirb_ctl),
+    },
+    [ ICH6_REG_RIRBSTS ] = {
+        .name     = "RIRBSTS",
+        .size     = 1,
+        .wmask    = 0x05,
+        .wclear   = 0x05,
+        .offset   = offsetof(IntelHDAState, rirb_sts),
+        .whandler = intel_hda_set_rirb_sts,
+    },
+    [ ICH6_REG_RIRBSIZE ] = {
+        .name     = "RIRBSIZE",
+        .size     = 1,
+        .reset    = 0x42,
+        .offset   = offsetof(IntelHDAState, rirb_size),
+    },
+
+    [ ICH6_REG_DPLBASE ] = {
+        .name     = "DPLBASE",
+        .size     = 4,
+        .wmask    = 0xffffff81,
+        .offset   = offsetof(IntelHDAState, dp_lbase),
+    },
+    [ ICH6_REG_DPUBASE ] = {
+        .name     = "DPUBASE",
+        .size     = 4,
+        .wmask    = 0xffffffff,
+        .offset   = offsetof(IntelHDAState, dp_ubase),
+    },
+
+    [ ICH6_REG_IC ] = {
+        .name     = "ICW",
+        .size     = 4,
+        .wmask    = 0xffffffff,
+        .offset   = offsetof(IntelHDAState, icw),
+    },
+    [ ICH6_REG_IR ] = {
+        .name     = "IRR",
+        .size     = 4,
+        .offset   = offsetof(IntelHDAState, irr),
+    },
+    [ ICH6_REG_IRS ] = {
+        .name     = "ICS",
+        .size     = 2,
+        .wmask    = 0x0003,
+        .wclear   = 0x0002,
+        .offset   = offsetof(IntelHDAState, ics),
+        .whandler = intel_hda_set_ics,
+    },
+
+#define HDA_STREAM(_t, _i)                                            \
+    [ ST_REG(_i, ICH6_REG_SD_CTL) ] = {                               \
+        .stream   = _i,                                               \
+        .name     = _t stringify(_i) " CTL",                          \
+        .size     = 4,                                                \
+        .wmask    = 0x1cff001f,                                       \
+        .offset   = offsetof(IntelHDAState, st[_i].ctl),              \
+        .whandler = intel_hda_set_st_ctl,                             \
+    },                                                                \
+    [ ST_REG(_i, ICH6_REG_SD_CTL) + 2] = {                            \
+        .stream   = _i,                                               \
+        .name     = _t stringify(_i) " CTL(stnr)",                    \
+        .size     = 1,                                                \
+        .shift    = 16,                                               \
+        .wmask    = 0x00ff0000,                                       \
+        .offset   = offsetof(IntelHDAState, st[_i].ctl),              \
+        .whandler = intel_hda_set_st_ctl,                             \
+    },                                                                \
+    [ ST_REG(_i, ICH6_REG_SD_STS)] = {                                \
+        .stream   = _i,                                               \
+        .name     = _t stringify(_i) " CTL(sts)",                     \
+        .size     = 1,                                                \
+        .shift    = 24,                                               \
+        .wmask    = 0x1c000000,                                       \
+        .wclear   = 0x1c000000,                                       \
+        .offset   = offsetof(IntelHDAState, st[_i].ctl),              \
+        .whandler = intel_hda_set_st_ctl,                             \
+    },                                                                \
+    [ ST_REG(_i, ICH6_REG_SD_LPIB) ] = {                              \
+        .stream   = _i,                                               \
+        .name     = _t stringify(_i) " LPIB",                         \
+        .size     = 4,                                                \
+        .offset   = offsetof(IntelHDAState, st[_i].lpib),             \
+    },                                                                \
+    [ ST_REG(_i, ICH6_REG_SD_LPIB) + 0x2000 ] = {                     \
+        .stream   = _i,                                               \
+        .name     = _t stringify(_i) " LPIB(alias)",                  \
+        .size     = 4,                                                \
+        .offset   = offsetof(IntelHDAState, st[_i].lpib),             \
+    },                                                                \
+    [ ST_REG(_i, ICH6_REG_SD_CBL) ] = {                               \
+        .stream   = _i,                                               \
+        .name     = _t stringify(_i) " CBL",                          \
+        .size     = 4,                                                \
+        .wmask    = 0xffffffff,                                       \
+        .offset   = offsetof(IntelHDAState, st[_i].cbl),              \
+    },                                                                \
+    [ ST_REG(_i, ICH6_REG_SD_LVI) ] = {                               \
+        .stream   = _i,                                               \
+        .name     = _t stringify(_i) " LVI",                          \
+        .size     = 2,                                                \
+        .wmask    = 0x00ff,                                           \
+        .offset   = offsetof(IntelHDAState, st[_i].lvi),              \
+    },                                                                \
+    [ ST_REG(_i, ICH6_REG_SD_FIFOSIZE) ] = {                          \
+        .stream   = _i,                                               \
+        .name     = _t stringify(_i) " FIFOS",                        \
+        .size     = 2,                                                \
+        .reset    = HDA_BUFFER_SIZE,                                  \
+    },                                                                \
+    [ ST_REG(_i, ICH6_REG_SD_FORMAT) ] = {                            \
+        .stream   = _i,                                               \
+        .name     = _t stringify(_i) " FMT",                          \
+        .size     = 2,                                                \
+        .wmask    = 0x7f7f,                                           \
+        .offset   = offsetof(IntelHDAState, st[_i].fmt),              \
+    },                                                                \
+    [ ST_REG(_i, ICH6_REG_SD_BDLPL) ] = {                             \
+        .stream   = _i,                                               \
+        .name     = _t stringify(_i) " BDLPL",                        \
+        .size     = 4,                                                \
+        .wmask    = 0xffffff80,                                       \
+        .offset   = offsetof(IntelHDAState, st[_i].bdlp_lbase),       \
+    },                                                                \
+    [ ST_REG(_i, ICH6_REG_SD_BDLPU) ] = {                             \
+        .stream   = _i,                                               \
+        .name     = _t stringify(_i) " BDLPU",                        \
+        .size     = 4,                                                \
+        .wmask    = 0xffffffff,                                       \
+        .offset   = offsetof(IntelHDAState, st[_i].bdlp_ubase),       \
+    },                                                                \
+
+    HDA_STREAM("IN", 0)
+    HDA_STREAM("IN", 1)
+    HDA_STREAM("IN", 2)
+    HDA_STREAM("IN", 3)
+
+    HDA_STREAM("OUT", 4)
+    HDA_STREAM("OUT", 5)
+    HDA_STREAM("OUT", 6)
+    HDA_STREAM("OUT", 7)
+
+};
+
+static const IntelHDAReg *intel_hda_reg_find(IntelHDAState *d, hwaddr addr)
+{
+    const IntelHDAReg *reg;
+
+    if (addr >= sizeof(regtab)/sizeof(regtab[0])) {
+        goto noreg;
+    }
+    reg = regtab+addr;
+    if (reg->name == NULL) {
+        goto noreg;
+    }
+    return reg;
+
+noreg:
+    dprint(d, 1, "unknown register, addr 0x%x\n", (int) addr);
+    return NULL;
+}
+
+static uint32_t *intel_hda_reg_addr(IntelHDAState *d, const IntelHDAReg *reg)
+{
+    uint8_t *addr = (void*)d;
+
+    addr += reg->offset;
+    return (uint32_t*)addr;
+}
+
+static void intel_hda_reg_write(IntelHDAState *d, const IntelHDAReg *reg, uint32_t val,
+                                uint32_t wmask)
+{
+    uint32_t *addr;
+    uint32_t old;
+
+    if (!reg) {
+        return;
+    }
+
+    if (d->debug) {
+        time_t now = time(NULL);
+        if (d->last_write && d->last_reg == reg && d->last_val == val) {
+            d->repeat_count++;
+            if (d->last_sec != now) {
+                dprint(d, 2, "previous register op repeated %d times\n", d->repeat_count);
+                d->last_sec = now;
+                d->repeat_count = 0;
+            }
+        } else {
+            if (d->repeat_count) {
+                dprint(d, 2, "previous register op repeated %d times\n", d->repeat_count);
+            }
+            dprint(d, 2, "write %-16s: 0x%x (%x)\n", reg->name, val, wmask);
+            d->last_write = 1;
+            d->last_reg   = reg;
+            d->last_val   = val;
+            d->last_sec   = now;
+            d->repeat_count = 0;
+        }
+    }
+    assert(reg->offset != 0);
+
+    addr = intel_hda_reg_addr(d, reg);
+    old = *addr;
+
+    if (reg->shift) {
+        val <<= reg->shift;
+        wmask <<= reg->shift;
+    }
+    wmask &= reg->wmask;
+    *addr &= ~wmask;
+    *addr |= wmask & val;
+    *addr &= ~(val & reg->wclear);
+
+    if (reg->whandler) {
+        reg->whandler(d, reg, old);
+    }
+}
+
+static uint32_t intel_hda_reg_read(IntelHDAState *d, const IntelHDAReg *reg,
+                                   uint32_t rmask)
+{
+    uint32_t *addr, ret;
+
+    if (!reg) {
+        return 0;
+    }
+
+    if (reg->rhandler) {
+        reg->rhandler(d, reg);
+    }
+
+    if (reg->offset == 0) {
+        /* constant read-only register */
+        ret = reg->reset;
+    } else {
+        addr = intel_hda_reg_addr(d, reg);
+        ret = *addr;
+        if (reg->shift) {
+            ret >>= reg->shift;
+        }
+        ret &= rmask;
+    }
+    if (d->debug) {
+        time_t now = time(NULL);
+        if (!d->last_write && d->last_reg == reg && d->last_val == ret) {
+            d->repeat_count++;
+            if (d->last_sec != now) {
+                dprint(d, 2, "previous register op repeated %d times\n", d->repeat_count);
+                d->last_sec = now;
+                d->repeat_count = 0;
+            }
+        } else {
+            if (d->repeat_count) {
+                dprint(d, 2, "previous register op repeated %d times\n", d->repeat_count);
+            }
+            dprint(d, 2, "read  %-16s: 0x%x (%x)\n", reg->name, ret, rmask);
+            d->last_write = 0;
+            d->last_reg   = reg;
+            d->last_val   = ret;
+            d->last_sec   = now;
+            d->repeat_count = 0;
+        }
+    }
+    return ret;
+}
+
+static void intel_hda_regs_reset(IntelHDAState *d)
+{
+    uint32_t *addr;
+    int i;
+
+    for (i = 0; i < sizeof(regtab)/sizeof(regtab[0]); i++) {
+        if (regtab[i].name == NULL) {
+            continue;
+        }
+        if (regtab[i].offset == 0) {
+            continue;
+        }
+        addr = intel_hda_reg_addr(d, regtab + i);
+        *addr = regtab[i].reset;
+    }
+}
+
+/* --------------------------------------------------------------------- */
+
+static void intel_hda_mmio_writeb(void *opaque, hwaddr addr, uint32_t val)
+{
+    IntelHDAState *d = opaque;
+    const IntelHDAReg *reg = intel_hda_reg_find(d, addr);
+
+    intel_hda_reg_write(d, reg, val, 0xff);
+}
+
+static void intel_hda_mmio_writew(void *opaque, hwaddr addr, uint32_t val)
+{
+    IntelHDAState *d = opaque;
+    const IntelHDAReg *reg = intel_hda_reg_find(d, addr);
+
+    intel_hda_reg_write(d, reg, val, 0xffff);
+}
+
+static void intel_hda_mmio_writel(void *opaque, hwaddr addr, uint32_t val)
+{
+    IntelHDAState *d = opaque;
+    const IntelHDAReg *reg = intel_hda_reg_find(d, addr);
+
+    intel_hda_reg_write(d, reg, val, 0xffffffff);
+}
+
+static uint32_t intel_hda_mmio_readb(void *opaque, hwaddr addr)
+{
+    IntelHDAState *d = opaque;
+    const IntelHDAReg *reg = intel_hda_reg_find(d, addr);
+
+    return intel_hda_reg_read(d, reg, 0xff);
+}
+
+static uint32_t intel_hda_mmio_readw(void *opaque, hwaddr addr)
+{
+    IntelHDAState *d = opaque;
+    const IntelHDAReg *reg = intel_hda_reg_find(d, addr);
+
+    return intel_hda_reg_read(d, reg, 0xffff);
+}
+
+static uint32_t intel_hda_mmio_readl(void *opaque, hwaddr addr)
+{
+    IntelHDAState *d = opaque;
+    const IntelHDAReg *reg = intel_hda_reg_find(d, addr);
+
+    return intel_hda_reg_read(d, reg, 0xffffffff);
+}
+
+static const MemoryRegionOps intel_hda_mmio_ops = {
+    .old_mmio = {
+        .read = {
+            intel_hda_mmio_readb,
+            intel_hda_mmio_readw,
+            intel_hda_mmio_readl,
+        },
+        .write = {
+            intel_hda_mmio_writeb,
+            intel_hda_mmio_writew,
+            intel_hda_mmio_writel,
+        },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+/* --------------------------------------------------------------------- */
+
+static void intel_hda_reset(DeviceState *dev)
+{
+    BusChild *kid;
+    IntelHDAState *d = DO_UPCAST(IntelHDAState, pci.qdev, dev);
+    HDACodecDevice *cdev;
+
+    intel_hda_regs_reset(d);
+    d->wall_base_ns = qemu_get_clock_ns(vm_clock);
+
+    /* reset codecs */
+    QTAILQ_FOREACH(kid, &d->codecs.qbus.children, sibling) {
+        DeviceState *qdev = kid->child;
+        cdev = DO_UPCAST(HDACodecDevice, qdev, qdev);
+        device_reset(DEVICE(cdev));
+        d->state_sts |= (1 << cdev->cad);
+    }
+    intel_hda_update_irq(d);
+}
+
+static int intel_hda_init(PCIDevice *pci)
+{
+    IntelHDAState *d = DO_UPCAST(IntelHDAState, pci, pci);
+    uint8_t *conf = d->pci.config;
+
+    d->name = object_get_typename(OBJECT(d));
+
+    pci_config_set_interrupt_pin(conf, 1);
+
+    /* HDCTL off 0x40 bit 0 selects signaling mode (1-HDA, 0 - Ac97) 18.1.19 */
+    conf[0x40] = 0x01;
+
+    memory_region_init_io(&d->mmio, &intel_hda_mmio_ops, d,
+                          "intel-hda", 0x4000);
+    pci_register_bar(&d->pci, 0, 0, &d->mmio);
+    if (d->msi) {
+        msi_init(&d->pci, 0x50, 1, true, false);
+    }
+
+    hda_codec_bus_init(&d->pci.qdev, &d->codecs,
+                       intel_hda_response, intel_hda_xfer);
+
+    return 0;
+}
+
+static void intel_hda_exit(PCIDevice *pci)
+{
+    IntelHDAState *d = DO_UPCAST(IntelHDAState, pci, pci);
+
+    msi_uninit(&d->pci);
+    memory_region_destroy(&d->mmio);
+}
+
+static int intel_hda_post_load(void *opaque, int version)
+{
+    IntelHDAState* d = opaque;
+    int i;
+
+    dprint(d, 1, "%s\n", __FUNCTION__);
+    for (i = 0; i < ARRAY_SIZE(d->st); i++) {
+        if (d->st[i].ctl & 0x02) {
+            intel_hda_parse_bdl(d, &d->st[i]);
+        }
+    }
+    intel_hda_update_irq(d);
+    return 0;
+}
+
+static const VMStateDescription vmstate_intel_hda_stream = {
+    .name = "intel-hda-stream",
+    .version_id = 1,
+    .fields = (VMStateField []) {
+        VMSTATE_UINT32(ctl, IntelHDAStream),
+        VMSTATE_UINT32(lpib, IntelHDAStream),
+        VMSTATE_UINT32(cbl, IntelHDAStream),
+        VMSTATE_UINT32(lvi, IntelHDAStream),
+        VMSTATE_UINT32(fmt, IntelHDAStream),
+        VMSTATE_UINT32(bdlp_lbase, IntelHDAStream),
+        VMSTATE_UINT32(bdlp_ubase, IntelHDAStream),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_intel_hda = {
+    .name = "intel-hda",
+    .version_id = 1,
+    .post_load = intel_hda_post_load,
+    .fields = (VMStateField []) {
+        VMSTATE_PCI_DEVICE(pci, IntelHDAState),
+
+        /* registers */
+        VMSTATE_UINT32(g_ctl, IntelHDAState),
+        VMSTATE_UINT32(wake_en, IntelHDAState),
+        VMSTATE_UINT32(state_sts, IntelHDAState),
+        VMSTATE_UINT32(int_ctl, IntelHDAState),
+        VMSTATE_UINT32(int_sts, IntelHDAState),
+        VMSTATE_UINT32(wall_clk, IntelHDAState),
+        VMSTATE_UINT32(corb_lbase, IntelHDAState),
+        VMSTATE_UINT32(corb_ubase, IntelHDAState),
+        VMSTATE_UINT32(corb_rp, IntelHDAState),
+        VMSTATE_UINT32(corb_wp, IntelHDAState),
+        VMSTATE_UINT32(corb_ctl, IntelHDAState),
+        VMSTATE_UINT32(corb_sts, IntelHDAState),
+        VMSTATE_UINT32(corb_size, IntelHDAState),
+        VMSTATE_UINT32(rirb_lbase, IntelHDAState),
+        VMSTATE_UINT32(rirb_ubase, IntelHDAState),
+        VMSTATE_UINT32(rirb_wp, IntelHDAState),
+        VMSTATE_UINT32(rirb_cnt, IntelHDAState),
+        VMSTATE_UINT32(rirb_ctl, IntelHDAState),
+        VMSTATE_UINT32(rirb_sts, IntelHDAState),
+        VMSTATE_UINT32(rirb_size, IntelHDAState),
+        VMSTATE_UINT32(dp_lbase, IntelHDAState),
+        VMSTATE_UINT32(dp_ubase, IntelHDAState),
+        VMSTATE_UINT32(icw, IntelHDAState),
+        VMSTATE_UINT32(irr, IntelHDAState),
+        VMSTATE_UINT32(ics, IntelHDAState),
+        VMSTATE_STRUCT_ARRAY(st, IntelHDAState, 8, 0,
+                             vmstate_intel_hda_stream,
+                             IntelHDAStream),
+
+        /* additional state info */
+        VMSTATE_UINT32(rirb_count, IntelHDAState),
+        VMSTATE_INT64(wall_base_ns, IntelHDAState),
+
+        VMSTATE_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_common(ObjectClass *klass)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = intel_hda_init;
+    k->exit = intel_hda_exit;
+    k->vendor_id = PCI_VENDOR_ID_INTEL;
+    k->class_id = PCI_CLASS_MULTIMEDIA_HD_AUDIO;
+    dc->reset = intel_hda_reset;
+    dc->vmsd = &vmstate_intel_hda;
+    dc->props = intel_hda_properties;
+}
+
+static void intel_hda_class_init_ich6(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    intel_hda_class_init_common(klass);
+    k->device_id = 0x2668;
+    k->revision = 1;
+    dc->desc = "Intel HD Audio Controller (ich6)";
+}
+
+static void intel_hda_class_init_ich9(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    intel_hda_class_init_common(klass);
+    k->device_id = 0x293e;
+    k->revision = 3;
+    dc->desc = "Intel HD Audio Controller (ich9)";
+}
+
+static const TypeInfo intel_hda_info_ich6 = {
+    .name          = "intel-hda",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(IntelHDAState),
+    .class_init    = intel_hda_class_init_ich6,
+};
+
+static const TypeInfo intel_hda_info_ich9 = {
+    .name          = "ich9-intel-hda",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(IntelHDAState),
+    .class_init    = intel_hda_class_init_ich9,
+};
+
+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_type = TYPE_HDA_BUS;
+    k->props = hda_props;
+}
+
+static const 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_types(void)
+{
+    type_register_static(&hda_codec_bus_info);
+    type_register_static(&intel_hda_info_ich6);
+    type_register_static(&intel_hda_info_ich9);
+    type_register_static(&hda_codec_device_type_info);
+}
+
+type_init(intel_hda_register_types)
+
+/*
+ * create intel hda controller with codec attached to it,
+ * so '-soundhw hda' works.
+ */
+int intel_hda_and_codec_init(PCIBus *bus)
+{
+    PCIDevice *controller;
+    BusState *hdabus;
+    DeviceState *codec;
+
+    controller = pci_create_simple(bus, -1, "intel-hda");
+    hdabus = QLIST_FIRST(&controller->qdev.child_bus);
+    codec = qdev_create(hdabus, "hda-duplex");
+    qdev_init_nofail(codec);
+    return 0;
+}
+
diff --git a/hw/audio/intel-hda.h b/hw/audio/intel-hda.h
new file mode 100644 (file)
index 0000000..2544f0a
--- /dev/null
@@ -0,0 +1,72 @@
+#ifndef HW_INTEL_HDA_H
+#define HW_INTEL_HDA_H
+
+#include "hw/qdev.h"
+
+/* --------------------------------------------------------------------- */
+/* 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)
+
+#define TYPE_HDA_BUS "HDA"
+#define HDA_BUS(obj) OBJECT_CHECK(HDACodecBus, (obj), TYPE_HDA_BUS)
+
+typedef struct HDACodecBus HDACodecBus;
+typedef struct HDACodecDevice HDACodecDevice;
+
+typedef void (*hda_codec_response_func)(HDACodecDevice *dev,
+                                        bool solicited, uint32_t response);
+typedef bool (*hda_codec_xfer_func)(HDACodecDevice *dev,
+                                    uint32_t stnr, bool output,
+                                    uint8_t *buf, uint32_t len);
+
+struct HDACodecBus {
+    BusState qbus;
+    uint32_t next_cad;
+    hda_codec_response_func response;
+    hda_codec_xfer_func xfer;
+};
+
+typedef struct HDACodecDeviceClass
+{
+    DeviceClass parent_class;
+
+    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);
+HDACodecDevice *hda_codec_find(HDACodecBus *bus, uint32_t cad);
+
+void hda_codec_response(HDACodecDevice *dev, bool solicited, uint32_t response);
+bool hda_codec_xfer(HDACodecDevice *dev, uint32_t stnr, bool output,
+                    uint8_t *buf, uint32_t len);
+
+/* --------------------------------------------------------------------- */
+
+#define dprint(_dev, _level, _fmt, ...)                                 \
+    do {                                                                \
+        if (_dev->debug >= _level) {                                    \
+            fprintf(stderr, "%s: ", _dev->name);                        \
+            fprintf(stderr, _fmt, ## __VA_ARGS__);                      \
+        }                                                               \
+    } while (0)
+
+/* --------------------------------------------------------------------- */
+
+#endif
diff --git a/hw/audio/lm4549.c b/hw/audio/lm4549.c
new file mode 100644 (file)
index 0000000..d75f7ec
--- /dev/null
@@ -0,0 +1,336 @@
+/*
+ * LM4549 Audio Codec Interface
+ *
+ * Copyright (c) 2011
+ * Written by Mathieu Sonet - www.elasticsheep.com
+ *
+ * This code is licensed under the GPL.
+ *
+ * *****************************************************************
+ *
+ * This driver emulates the LM4549 codec.
+ *
+ * It supports only one playback voice and no record voice.
+ */
+
+#include "hw/hw.h"
+#include "audio/audio.h"
+#include "lm4549.h"
+
+#if 0
+#define LM4549_DEBUG  1
+#endif
+
+#if 0
+#define LM4549_DUMP_DAC_INPUT 1
+#endif
+
+#ifdef LM4549_DEBUG
+#define DPRINTF(fmt, ...) \
+do { printf("lm4549: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while (0)
+#endif
+
+#if defined(LM4549_DUMP_DAC_INPUT)
+#include <stdio.h>
+static FILE *fp_dac_input;
+#endif
+
+/* LM4549 register list */
+enum {
+    LM4549_Reset                    = 0x00,
+    LM4549_Master_Volume            = 0x02,
+    LM4549_Line_Out_Volume          = 0x04,
+    LM4549_Master_Volume_Mono       = 0x06,
+    LM4549_PC_Beep_Volume           = 0x0A,
+    LM4549_Phone_Volume             = 0x0C,
+    LM4549_Mic_Volume               = 0x0E,
+    LM4549_Line_In_Volume           = 0x10,
+    LM4549_CD_Volume                = 0x12,
+    LM4549_Video_Volume             = 0x14,
+    LM4549_Aux_Volume               = 0x16,
+    LM4549_PCM_Out_Volume           = 0x18,
+    LM4549_Record_Select            = 0x1A,
+    LM4549_Record_Gain              = 0x1C,
+    LM4549_General_Purpose          = 0x20,
+    LM4549_3D_Control               = 0x22,
+    LM4549_Powerdown_Ctrl_Stat      = 0x26,
+    LM4549_Ext_Audio_ID             = 0x28,
+    LM4549_Ext_Audio_Stat_Ctrl      = 0x2A,
+    LM4549_PCM_Front_DAC_Rate       = 0x2C,
+    LM4549_PCM_ADC_Rate             = 0x32,
+    LM4549_Vendor_ID1               = 0x7C,
+    LM4549_Vendor_ID2               = 0x7E
+};
+
+static void lm4549_reset(lm4549_state *s)
+{
+    uint16_t *regfile = s->regfile;
+
+    regfile[LM4549_Reset]               = 0x0d50;
+    regfile[LM4549_Master_Volume]       = 0x8008;
+    regfile[LM4549_Line_Out_Volume]     = 0x8000;
+    regfile[LM4549_Master_Volume_Mono]  = 0x8000;
+    regfile[LM4549_PC_Beep_Volume]      = 0x0000;
+    regfile[LM4549_Phone_Volume]        = 0x8008;
+    regfile[LM4549_Mic_Volume]          = 0x8008;
+    regfile[LM4549_Line_In_Volume]      = 0x8808;
+    regfile[LM4549_CD_Volume]           = 0x8808;
+    regfile[LM4549_Video_Volume]        = 0x8808;
+    regfile[LM4549_Aux_Volume]          = 0x8808;
+    regfile[LM4549_PCM_Out_Volume]      = 0x8808;
+    regfile[LM4549_Record_Select]       = 0x0000;
+    regfile[LM4549_Record_Gain]         = 0x8000;
+    regfile[LM4549_General_Purpose]     = 0x0000;
+    regfile[LM4549_3D_Control]          = 0x0101;
+    regfile[LM4549_Powerdown_Ctrl_Stat] = 0x000f;
+    regfile[LM4549_Ext_Audio_ID]        = 0x0001;
+    regfile[LM4549_Ext_Audio_Stat_Ctrl] = 0x0000;
+    regfile[LM4549_PCM_Front_DAC_Rate]  = 0xbb80;
+    regfile[LM4549_PCM_ADC_Rate]        = 0xbb80;
+    regfile[LM4549_Vendor_ID1]          = 0x4e53;
+    regfile[LM4549_Vendor_ID2]          = 0x4331;
+}
+
+static void lm4549_audio_transfer(lm4549_state *s)
+{
+    uint32_t written_bytes, written_samples;
+    uint32_t i;
+
+    /* Activate the voice */
+    AUD_set_active_out(s->voice, 1);
+    s->voice_is_active = 1;
+
+    /* Try to write the buffer content */
+    written_bytes = AUD_write(s->voice, s->buffer,
+                              s->buffer_level * sizeof(uint16_t));
+    written_samples = written_bytes >> 1;
+
+#if defined(LM4549_DUMP_DAC_INPUT)
+    fwrite(s->buffer, sizeof(uint8_t), written_bytes, fp_dac_input);
+#endif
+
+    s->buffer_level -= written_samples;
+
+    if (s->buffer_level > 0) {
+        /* Move the data back to the start of the buffer */
+        for (i = 0; i < s->buffer_level; i++) {
+            s->buffer[i] = s->buffer[i + written_samples];
+        }
+    }
+}
+
+static void lm4549_audio_out_callback(void *opaque, int free)
+{
+    lm4549_state *s = (lm4549_state *)opaque;
+    static uint32_t prev_buffer_level;
+
+#ifdef LM4549_DEBUG
+    int size = AUD_get_buffer_size_out(s->voice);
+    DPRINTF("audio_out_callback size = %i free = %i\n", size, free);
+#endif
+
+    /* Detect that no data are consumed
+       => disable the voice */
+    if (s->buffer_level == prev_buffer_level) {
+        AUD_set_active_out(s->voice, 0);
+        s->voice_is_active = 0;
+    }
+    prev_buffer_level = s->buffer_level;
+
+    /* Check if a buffer transfer is pending */
+    if (s->buffer_level == LM4549_BUFFER_SIZE) {
+        lm4549_audio_transfer(s);
+
+        /* Request more data */
+        if (s->data_req_cb != NULL) {
+            (s->data_req_cb)(s->opaque);
+        }
+    }
+}
+
+uint32_t lm4549_read(lm4549_state *s, hwaddr offset)
+{
+    uint16_t *regfile = s->regfile;
+    uint32_t value = 0;
+
+    /* Read the stored value */
+    assert(offset < 128);
+    value = regfile[offset];
+
+    DPRINTF("read [0x%02x] = 0x%04x\n", offset, value);
+
+    return value;
+}
+
+void lm4549_write(lm4549_state *s,
+                  hwaddr offset, uint32_t value)
+{
+    uint16_t *regfile = s->regfile;
+
+    assert(offset < 128);
+    DPRINTF("write [0x%02x] = 0x%04x\n", offset, value);
+
+    switch (offset) {
+    case LM4549_Reset:
+        lm4549_reset(s);
+        break;
+
+    case LM4549_PCM_Front_DAC_Rate:
+        regfile[LM4549_PCM_Front_DAC_Rate] = value;
+        DPRINTF("DAC rate change = %i\n", value);
+
+        /* Re-open a voice with the new sample rate */
+        struct audsettings as;
+        as.freq = value;
+        as.nchannels = 2;
+        as.fmt = AUD_FMT_S16;
+        as.endianness = 0;
+
+        s->voice = AUD_open_out(
+            &s->card,
+            s->voice,
+            "lm4549.out",
+            s,
+            lm4549_audio_out_callback,
+            &as
+        );
+        break;
+
+    case LM4549_Powerdown_Ctrl_Stat:
+        value &= ~0xf;
+        value |= regfile[LM4549_Powerdown_Ctrl_Stat] & 0xf;
+        regfile[LM4549_Powerdown_Ctrl_Stat] = value;
+        break;
+
+    case LM4549_Ext_Audio_ID:
+    case LM4549_Vendor_ID1:
+    case LM4549_Vendor_ID2:
+        DPRINTF("Write to read-only register 0x%x\n", (int)offset);
+        break;
+
+    default:
+        /* Store the new value */
+        regfile[offset] = value;
+        break;
+    }
+}
+
+uint32_t lm4549_write_samples(lm4549_state *s, uint32_t left, uint32_t right)
+{
+    /* The left and right samples are in 20-bit resolution.
+       The LM4549 has 18-bit resolution and only uses the bits [19:2].
+       This model supports 16-bit playback.
+    */
+
+    if (s->buffer_level > LM4549_BUFFER_SIZE - 2) {
+        DPRINTF("write_sample Buffer full\n");
+        return 0;
+    }
+
+    /* Store 16-bit samples in the buffer */
+    s->buffer[s->buffer_level++] = (left >> 4);
+    s->buffer[s->buffer_level++] = (right >> 4);
+
+    if (s->buffer_level == LM4549_BUFFER_SIZE) {
+        /* Trigger the transfer of the buffer to the audio host */
+        lm4549_audio_transfer(s);
+    }
+
+    return 1;
+}
+
+static int lm4549_post_load(void *opaque, int version_id)
+{
+    lm4549_state *s = (lm4549_state *)opaque;
+    uint16_t *regfile = s->regfile;
+
+    /* Re-open a voice with the current sample rate */
+    uint32_t freq = regfile[LM4549_PCM_Front_DAC_Rate];
+
+    DPRINTF("post_load freq = %i\n", freq);
+    DPRINTF("post_load voice_is_active = %i\n", s->voice_is_active);
+
+    struct audsettings as;
+    as.freq = freq;
+    as.nchannels = 2;
+    as.fmt = AUD_FMT_S16;
+    as.endianness = 0;
+
+    s->voice = AUD_open_out(
+        &s->card,
+        s->voice,
+        "lm4549.out",
+        s,
+        lm4549_audio_out_callback,
+        &as
+    );
+
+    /* Request data */
+    if (s->voice_is_active == 1) {
+        lm4549_audio_out_callback(s, AUD_get_buffer_size_out(s->voice));
+    }
+
+    return 0;
+}
+
+void lm4549_init(lm4549_state *s, lm4549_callback data_req_cb, void* opaque)
+{
+    struct audsettings as;
+
+    /* Store the callback and opaque pointer */
+    s->data_req_cb = data_req_cb;
+    s->opaque = opaque;
+
+    /* Init the registers */
+    lm4549_reset(s);
+
+    /* Register an audio card */
+    AUD_register_card("lm4549", &s->card);
+
+    /* Open a default voice */
+    as.freq = 48000;
+    as.nchannels = 2;
+    as.fmt = AUD_FMT_S16;
+    as.endianness = 0;
+
+    s->voice = AUD_open_out(
+        &s->card,
+        s->voice,
+        "lm4549.out",
+        s,
+        lm4549_audio_out_callback,
+        &as
+    );
+
+    AUD_set_volume_out(s->voice, 0, 255, 255);
+
+    s->voice_is_active = 0;
+
+    /* Reset the input buffer */
+    memset(s->buffer, 0x00, sizeof(s->buffer));
+    s->buffer_level = 0;
+
+#if defined(LM4549_DUMP_DAC_INPUT)
+    fp_dac_input = fopen("lm4549_dac_input.pcm", "wb");
+    if (!fp_dac_input) {
+        hw_error("Unable to open lm4549_dac_input.pcm for writing\n");
+    }
+#endif
+}
+
+const VMStateDescription vmstate_lm4549_state = {
+    .name = "lm4549_state",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .post_load = &lm4549_post_load,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32(voice_is_active, lm4549_state),
+        VMSTATE_UINT16_ARRAY(regfile, lm4549_state, 128),
+        VMSTATE_UINT16_ARRAY(buffer, lm4549_state, LM4549_BUFFER_SIZE),
+        VMSTATE_UINT32(buffer_level, lm4549_state),
+        VMSTATE_END_OF_LIST()
+    }
+};
diff --git a/hw/audio/lm4549.h b/hw/audio/lm4549.h
new file mode 100644 (file)
index 0000000..812a7a4
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * LM4549 Audio Codec Interface
+ *
+ * Copyright (c) 2011
+ * Written by Mathieu Sonet - www.elasticsheep.com
+ *
+ * This code is licensed under the GPL.
+ *
+ * *****************************************************************
+ */
+
+#ifndef HW_LM4549_H
+#define HW_LM4549_H
+
+#include "audio/audio.h"
+
+typedef void (*lm4549_callback)(void *opaque);
+
+#define LM4549_BUFFER_SIZE (512 * 2) /* 512 16-bit stereo samples */
+
+
+typedef struct {
+    QEMUSoundCard card;
+    SWVoiceOut *voice;
+    uint32_t voice_is_active;
+
+    uint16_t regfile[128];
+    lm4549_callback data_req_cb;
+    void *opaque;
+
+    uint16_t buffer[LM4549_BUFFER_SIZE];
+    uint32_t buffer_level;
+} lm4549_state;
+
+extern const VMStateDescription vmstate_lm4549_state;
+
+
+void lm4549_init(lm4549_state *s, lm4549_callback data_req, void *opaque);
+uint32_t lm4549_read(lm4549_state *s, hwaddr offset);
+void lm4549_write(lm4549_state *s, hwaddr offset, uint32_t value);
+uint32_t lm4549_write_samples(lm4549_state *s, uint32_t left, uint32_t right);
+
+#endif /* #ifndef HW_LM4549_H */
diff --git a/hw/audio/marvell_88w8618.c b/hw/audio/marvell_88w8618.c
new file mode 100644 (file)
index 0000000..f9b68fd
--- /dev/null
@@ -0,0 +1,303 @@
+/*
+ * Marvell 88w8618 audio emulation extracted from
+ * Marvell MV88w8618 / Freecom MusicPal emulation.
+ *
+ * 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/sysbus.h"
+#include "hw/hw.h"
+#include "hw/i2c/i2c.h"
+#include "hw/sysbus.h"
+#include "audio/audio.h"
+
+#define MP_AUDIO_SIZE           0x00001000
+
+/* Audio register offsets */
+#define MP_AUDIO_PLAYBACK_MODE  0x00
+#define MP_AUDIO_CLOCK_DIV      0x18
+#define MP_AUDIO_IRQ_STATUS     0x20
+#define MP_AUDIO_IRQ_ENABLE     0x24
+#define MP_AUDIO_TX_START_LO    0x28
+#define MP_AUDIO_TX_THRESHOLD   0x2C
+#define MP_AUDIO_TX_STATUS      0x38
+#define MP_AUDIO_TX_START_HI    0x40
+
+/* Status register and IRQ enable bits */
+#define MP_AUDIO_TX_HALF        (1 << 6)
+#define MP_AUDIO_TX_FULL        (1 << 7)
+
+/* Playback mode bits */
+#define MP_AUDIO_16BIT_SAMPLE   (1 << 0)
+#define MP_AUDIO_PLAYBACK_EN    (1 << 7)
+#define MP_AUDIO_CLOCK_24MHZ    (1 << 9)
+#define MP_AUDIO_MONO           (1 << 14)
+
+typedef struct mv88w8618_audio_state {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    qemu_irq irq;
+    uint32_t playback_mode;
+    uint32_t status;
+    uint32_t irq_enable;
+    uint32_t phys_buf;
+    uint32_t target_buffer;
+    uint32_t threshold;
+    uint32_t play_pos;
+    uint32_t last_free;
+    uint32_t clock_div;
+    void *wm;
+} mv88w8618_audio_state;
+
+static void mv88w8618_audio_callback(void *opaque, int free_out, int free_in)
+{
+    mv88w8618_audio_state *s = opaque;
+    int16_t *codec_buffer;
+    int8_t buf[4096];
+    int8_t *mem_buffer;
+    int pos, block_size;
+
+    if (!(s->playback_mode & MP_AUDIO_PLAYBACK_EN)) {
+        return;
+    }
+    if (s->playback_mode & MP_AUDIO_16BIT_SAMPLE) {
+        free_out <<= 1;
+    }
+    if (!(s->playback_mode & MP_AUDIO_MONO)) {
+        free_out <<= 1;
+    }
+    block_size = s->threshold / 2;
+    if (free_out - s->last_free < block_size) {
+        return;
+    }
+    if (block_size > 4096) {
+        return;
+    }
+    cpu_physical_memory_read(s->target_buffer + s->play_pos, (void *)buf,
+                             block_size);
+    mem_buffer = buf;
+    if (s->playback_mode & MP_AUDIO_16BIT_SAMPLE) {
+        if (s->playback_mode & MP_AUDIO_MONO) {
+            codec_buffer = wm8750_dac_buffer(s->wm, block_size >> 1);
+            for (pos = 0; pos < block_size; pos += 2) {
+                *codec_buffer++ = *(int16_t *)mem_buffer;
+                *codec_buffer++ = *(int16_t *)mem_buffer;
+                mem_buffer += 2;
+            }
+        } else {
+            memcpy(wm8750_dac_buffer(s->wm, block_size >> 2),
+                   (uint32_t *)mem_buffer, block_size);
+        }
+    } else {
+        if (s->playback_mode & MP_AUDIO_MONO) {
+            codec_buffer = wm8750_dac_buffer(s->wm, block_size);
+            for (pos = 0; pos < block_size; pos++) {
+                *codec_buffer++ = cpu_to_le16(256 * *mem_buffer);
+                *codec_buffer++ = cpu_to_le16(256 * *mem_buffer++);
+            }
+        } else {
+            codec_buffer = wm8750_dac_buffer(s->wm, block_size >> 1);
+            for (pos = 0; pos < block_size; pos += 2) {
+                *codec_buffer++ = cpu_to_le16(256 * *mem_buffer++);
+                *codec_buffer++ = cpu_to_le16(256 * *mem_buffer++);
+            }
+        }
+    }
+    wm8750_dac_commit(s->wm);
+
+    s->last_free = free_out - block_size;
+
+    if (s->play_pos == 0) {
+        s->status |= MP_AUDIO_TX_HALF;
+        s->play_pos = block_size;
+    } else {
+        s->status |= MP_AUDIO_TX_FULL;
+        s->play_pos = 0;
+    }
+
+    if (s->status & s->irq_enable) {
+        qemu_irq_raise(s->irq);
+    }
+}
+
+static void mv88w8618_audio_clock_update(mv88w8618_audio_state *s)
+{
+    int rate;
+
+    if (s->playback_mode & MP_AUDIO_CLOCK_24MHZ) {
+        rate = 24576000 / 64; /* 24.576MHz */
+    } else {
+        rate = 11289600 / 64; /* 11.2896MHz */
+    }
+    rate /= ((s->clock_div >> 8) & 0xff) + 1;
+
+    wm8750_set_bclk_in(s->wm, rate);
+}
+
+static uint64_t mv88w8618_audio_read(void *opaque, hwaddr offset,
+                                    unsigned size)
+{
+    mv88w8618_audio_state *s = opaque;
+
+    switch (offset) {
+    case MP_AUDIO_PLAYBACK_MODE:
+        return s->playback_mode;
+
+    case MP_AUDIO_CLOCK_DIV:
+        return s->clock_div;
+
+    case MP_AUDIO_IRQ_STATUS:
+        return s->status;
+
+    case MP_AUDIO_IRQ_ENABLE:
+        return s->irq_enable;
+
+    case MP_AUDIO_TX_STATUS:
+        return s->play_pos >> 2;
+
+    default:
+        return 0;
+    }
+}
+
+static void mv88w8618_audio_write(void *opaque, hwaddr offset,
+                                  uint64_t value, unsigned size)
+{
+    mv88w8618_audio_state *s = opaque;
+
+    switch (offset) {
+    case MP_AUDIO_PLAYBACK_MODE:
+        if (value & MP_AUDIO_PLAYBACK_EN &&
+            !(s->playback_mode & MP_AUDIO_PLAYBACK_EN)) {
+            s->status = 0;
+            s->last_free = 0;
+            s->play_pos = 0;
+        }
+        s->playback_mode = value;
+        mv88w8618_audio_clock_update(s);
+        break;
+
+    case MP_AUDIO_CLOCK_DIV:
+        s->clock_div = value;
+        s->last_free = 0;
+        s->play_pos = 0;
+        mv88w8618_audio_clock_update(s);
+        break;
+
+    case MP_AUDIO_IRQ_STATUS:
+        s->status &= ~value;
+        break;
+
+    case MP_AUDIO_IRQ_ENABLE:
+        s->irq_enable = value;
+        if (s->status & s->irq_enable) {
+            qemu_irq_raise(s->irq);
+        }
+        break;
+
+    case MP_AUDIO_TX_START_LO:
+        s->phys_buf = (s->phys_buf & 0xFFFF0000) | (value & 0xFFFF);
+        s->target_buffer = s->phys_buf;
+        s->play_pos = 0;
+        s->last_free = 0;
+        break;
+
+    case MP_AUDIO_TX_THRESHOLD:
+        s->threshold = (value + 1) * 4;
+        break;
+
+    case MP_AUDIO_TX_START_HI:
+        s->phys_buf = (s->phys_buf & 0xFFFF) | (value << 16);
+        s->target_buffer = s->phys_buf;
+        s->play_pos = 0;
+        s->last_free = 0;
+        break;
+    }
+}
+
+static void mv88w8618_audio_reset(DeviceState *d)
+{
+    mv88w8618_audio_state *s = FROM_SYSBUS(mv88w8618_audio_state,
+                                           SYS_BUS_DEVICE(d));
+
+    s->playback_mode = 0;
+    s->status = 0;
+    s->irq_enable = 0;
+    s->clock_div = 0;
+    s->threshold = 0;
+    s->phys_buf = 0;
+}
+
+static const MemoryRegionOps mv88w8618_audio_ops = {
+    .read = mv88w8618_audio_read,
+    .write = mv88w8618_audio_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int mv88w8618_audio_init(SysBusDevice *dev)
+{
+    mv88w8618_audio_state *s = FROM_SYSBUS(mv88w8618_audio_state, dev);
+
+    sysbus_init_irq(dev, &s->irq);
+
+    wm8750_data_req_set(s->wm, mv88w8618_audio_callback, s);
+
+    memory_region_init_io(&s->iomem, &mv88w8618_audio_ops, s,
+                          "audio", MP_AUDIO_SIZE);
+    sysbus_init_mmio(dev, &s->iomem);
+
+    return 0;
+}
+
+static const VMStateDescription mv88w8618_audio_vmsd = {
+    .name = "mv88w8618_audio",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(playback_mode, mv88w8618_audio_state),
+        VMSTATE_UINT32(status, mv88w8618_audio_state),
+        VMSTATE_UINT32(irq_enable, mv88w8618_audio_state),
+        VMSTATE_UINT32(phys_buf, mv88w8618_audio_state),
+        VMSTATE_UINT32(target_buffer, mv88w8618_audio_state),
+        VMSTATE_UINT32(threshold, mv88w8618_audio_state),
+        VMSTATE_UINT32(play_pos, mv88w8618_audio_state),
+        VMSTATE_UINT32(last_free, mv88w8618_audio_state),
+        VMSTATE_UINT32(clock_div, mv88w8618_audio_state),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static Property mv88w8618_audio_properties[] = {
+    DEFINE_PROP_PTR("wm8750", mv88w8618_audio_state, wm),
+    {/* end of list */},
+};
+
+static void mv88w8618_audio_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = mv88w8618_audio_init;
+    dc->reset = mv88w8618_audio_reset;
+    dc->vmsd = &mv88w8618_audio_vmsd;
+    dc->props = mv88w8618_audio_properties;
+}
+
+static const 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_types(void)
+{
+    type_register_static(&mv88w8618_audio_info);
+}
+
+type_init(mv88w8618_register_types)
diff --git a/hw/audio/milkymist-ac97.c b/hw/audio/milkymist-ac97.c
new file mode 100644 (file)
index 0000000..e08e9dc
--- /dev/null
@@ -0,0 +1,344 @@
+/*
+ *  QEMU model of the Milkymist System Controller.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
+ *
+ * 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/>.
+ *
+ *
+ * Specification available at:
+ *   http://www.milkymist.org/socdoc/ac97.pdf
+ */
+
+#include "hw/hw.h"
+#include "hw/sysbus.h"
+#include "trace.h"
+#include "audio/audio.h"
+#include "qemu/error-report.h"
+
+enum {
+    R_AC97_CTRL = 0,
+    R_AC97_ADDR,
+    R_AC97_DATAOUT,
+    R_AC97_DATAIN,
+    R_D_CTRL,
+    R_D_ADDR,
+    R_D_REMAINING,
+    R_RESERVED,
+    R_U_CTRL,
+    R_U_ADDR,
+    R_U_REMAINING,
+    R_MAX
+};
+
+enum {
+    AC97_CTRL_RQEN  = (1<<0),
+    AC97_CTRL_WRITE = (1<<1),
+};
+
+enum {
+    CTRL_EN = (1<<0),
+};
+
+struct MilkymistAC97State {
+    SysBusDevice busdev;
+    MemoryRegion regs_region;
+
+    QEMUSoundCard card;
+    SWVoiceIn *voice_in;
+    SWVoiceOut *voice_out;
+
+    uint32_t regs[R_MAX];
+
+    qemu_irq crrequest_irq;
+    qemu_irq crreply_irq;
+    qemu_irq dmar_irq;
+    qemu_irq dmaw_irq;
+};
+typedef struct MilkymistAC97State MilkymistAC97State;
+
+static void update_voices(MilkymistAC97State *s)
+{
+    if (s->regs[R_D_CTRL] & CTRL_EN) {
+        AUD_set_active_out(s->voice_out, 1);
+    } else {
+        AUD_set_active_out(s->voice_out, 0);
+    }
+
+    if (s->regs[R_U_CTRL] & CTRL_EN) {
+        AUD_set_active_in(s->voice_in, 1);
+    } else {
+        AUD_set_active_in(s->voice_in, 0);
+    }
+}
+
+static uint64_t ac97_read(void *opaque, hwaddr addr,
+                          unsigned size)
+{
+    MilkymistAC97State *s = opaque;
+    uint32_t r = 0;
+
+    addr >>= 2;
+    switch (addr) {
+    case R_AC97_CTRL:
+    case R_AC97_ADDR:
+    case R_AC97_DATAOUT:
+    case R_AC97_DATAIN:
+    case R_D_CTRL:
+    case R_D_ADDR:
+    case R_D_REMAINING:
+    case R_U_CTRL:
+    case R_U_ADDR:
+    case R_U_REMAINING:
+        r = s->regs[addr];
+        break;
+
+    default:
+        error_report("milkymist_ac97: read access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+
+    trace_milkymist_ac97_memory_read(addr << 2, r);
+
+    return r;
+}
+
+static void ac97_write(void *opaque, hwaddr addr, uint64_t value,
+                       unsigned size)
+{
+    MilkymistAC97State *s = opaque;
+
+    trace_milkymist_ac97_memory_write(addr, value);
+
+    addr >>= 2;
+    switch (addr) {
+    case R_AC97_CTRL:
+        /* always raise an IRQ according to the direction */
+        if (value & AC97_CTRL_RQEN) {
+            if (value & AC97_CTRL_WRITE) {
+                trace_milkymist_ac97_pulse_irq_crrequest();
+                qemu_irq_pulse(s->crrequest_irq);
+            } else {
+                trace_milkymist_ac97_pulse_irq_crreply();
+                qemu_irq_pulse(s->crreply_irq);
+            }
+        }
+
+        /* RQEN is self clearing */
+        s->regs[addr] = value & ~AC97_CTRL_RQEN;
+        break;
+    case R_D_CTRL:
+    case R_U_CTRL:
+        s->regs[addr] = value;
+        update_voices(s);
+        break;
+    case R_AC97_ADDR:
+    case R_AC97_DATAOUT:
+    case R_AC97_DATAIN:
+    case R_D_ADDR:
+    case R_D_REMAINING:
+    case R_U_ADDR:
+    case R_U_REMAINING:
+        s->regs[addr] = value;
+        break;
+
+    default:
+        error_report("milkymist_ac97: write access to unknown register 0x"
+                TARGET_FMT_plx, addr);
+        break;
+    }
+
+}
+
+static const MemoryRegionOps ac97_mmio_ops = {
+    .read = ac97_read,
+    .write = ac97_write,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void ac97_in_cb(void *opaque, int avail_b)
+{
+    MilkymistAC97State *s = opaque;
+    uint8_t buf[4096];
+    uint32_t remaining = s->regs[R_U_REMAINING];
+    int temp = audio_MIN(remaining, avail_b);
+    uint32_t addr = s->regs[R_U_ADDR];
+    int transferred = 0;
+
+    trace_milkymist_ac97_in_cb(avail_b, remaining);
+
+    /* prevent from raising an IRQ */
+    if (temp == 0) {
+        return;
+    }
+
+    while (temp) {
+        int acquired, to_copy;
+
+        to_copy = audio_MIN(temp, sizeof(buf));
+        acquired = AUD_read(s->voice_in, buf, to_copy);
+        if (!acquired) {
+            break;
+        }
+
+        cpu_physical_memory_write(addr, buf, acquired);
+
+        temp -= acquired;
+        addr += acquired;
+        transferred += acquired;
+    }
+
+    trace_milkymist_ac97_in_cb_transferred(transferred);
+
+    s->regs[R_U_ADDR] = addr;
+    s->regs[R_U_REMAINING] -= transferred;
+
+    if ((s->regs[R_U_CTRL] & CTRL_EN) && (s->regs[R_U_REMAINING] == 0)) {
+        trace_milkymist_ac97_pulse_irq_dmaw();
+        qemu_irq_pulse(s->dmaw_irq);
+    }
+}
+
+static void ac97_out_cb(void *opaque, int free_b)
+{
+    MilkymistAC97State *s = opaque;
+    uint8_t buf[4096];
+    uint32_t remaining = s->regs[R_D_REMAINING];
+    int temp = audio_MIN(remaining, free_b);
+    uint32_t addr = s->regs[R_D_ADDR];
+    int transferred = 0;
+
+    trace_milkymist_ac97_out_cb(free_b, remaining);
+
+    /* prevent from raising an IRQ */
+    if (temp == 0) {
+        return;
+    }
+
+    while (temp) {
+        int copied, to_copy;
+
+        to_copy = audio_MIN(temp, sizeof(buf));
+        cpu_physical_memory_read(addr, buf, to_copy);
+        copied = AUD_write(s->voice_out, buf, to_copy);
+        if (!copied) {
+            break;
+        }
+        temp -= copied;
+        addr += copied;
+        transferred += copied;
+    }
+
+    trace_milkymist_ac97_out_cb_transferred(transferred);
+
+    s->regs[R_D_ADDR] = addr;
+    s->regs[R_D_REMAINING] -= transferred;
+
+    if ((s->regs[R_D_CTRL] & CTRL_EN) && (s->regs[R_D_REMAINING] == 0)) {
+        trace_milkymist_ac97_pulse_irq_dmar();
+        qemu_irq_pulse(s->dmar_irq);
+    }
+}
+
+static void milkymist_ac97_reset(DeviceState *d)
+{
+    MilkymistAC97State *s = container_of(d, MilkymistAC97State, busdev.qdev);
+    int i;
+
+    for (i = 0; i < R_MAX; i++) {
+        s->regs[i] = 0;
+    }
+
+    AUD_set_active_in(s->voice_in, 0);
+    AUD_set_active_out(s->voice_out, 0);
+}
+
+static int ac97_post_load(void *opaque, int version_id)
+{
+    MilkymistAC97State *s = opaque;
+
+    update_voices(s);
+
+    return 0;
+}
+
+static int milkymist_ac97_init(SysBusDevice *dev)
+{
+    MilkymistAC97State *s = FROM_SYSBUS(typeof(*s), dev);
+
+    struct audsettings as;
+    sysbus_init_irq(dev, &s->crrequest_irq);
+    sysbus_init_irq(dev, &s->crreply_irq);
+    sysbus_init_irq(dev, &s->dmar_irq);
+    sysbus_init_irq(dev, &s->dmaw_irq);
+
+    AUD_register_card("Milkymist AC'97", &s->card);
+
+    as.freq = 48000;
+    as.nchannels = 2;
+    as.fmt = AUD_FMT_S16;
+    as.endianness = 1;
+
+    s->voice_in = AUD_open_in(&s->card, s->voice_in,
+            "mm_ac97.in", s, ac97_in_cb, &as);
+    s->voice_out = AUD_open_out(&s->card, s->voice_out,
+            "mm_ac97.out", s, ac97_out_cb, &as);
+
+    memory_region_init_io(&s->regs_region, &ac97_mmio_ops, s,
+            "milkymist-ac97", R_MAX * 4);
+    sysbus_init_mmio(dev, &s->regs_region);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_milkymist_ac97 = {
+    .name = "milkymist-ac97",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .post_load = ac97_post_load,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(regs, MilkymistAC97State, R_MAX),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+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 const 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_types(void)
+{
+    type_register_static(&milkymist_ac97_info);
+}
+
+type_init(milkymist_ac97_register_types)
diff --git a/hw/audio/pcspk.c b/hw/audio/pcspk.c
new file mode 100644 (file)
index 0000000..34e0df7
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+ * 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.
+ */
+
+#include "hw/hw.h"
+#include "hw/i386/pc.h"
+#include "hw/isa/isa.h"
+#include "audio/audio.h"
+#include "qemu/timer.h"
+#include "hw/timer/i8254.h"
+#include "hw/audio/pcspk.h"
+
+#define PCSPK_BUF_LEN 1792
+#define PCSPK_SAMPLE_RATE 32000
+#define PCSPK_MAX_FREQ (PCSPK_SAMPLE_RATE >> 1)
+#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;
+    void *pit;
+    unsigned int pit_count;
+    unsigned int samples;
+    unsigned int play_pos;
+    int data_on;
+    int dummy_refresh_clock;
+} PCSpkState;
+
+static const char *s_spk = "pcspk";
+static PCSpkState *pcspk_state;
+
+static inline void generate_samples(PCSpkState *s)
+{
+    unsigned int i;
+
+    if (s->pit_count) {
+        const uint32_t m = PCSPK_SAMPLE_RATE * s->pit_count;
+        const uint32_t n = ((uint64_t)PIT_FREQ << 32) / m;
+
+        /* multiple of wavelength for gapless looping */
+        s->samples = (PCSPK_BUF_LEN * PIT_FREQ / m * m / (PIT_FREQ >> 1) + 1) >> 1;
+        for (i = 0; i < s->samples; ++i)
+            s->sample_buf[i] = (64 & (n * i >> 25)) - 32;
+    } else {
+        s->samples = PCSPK_BUF_LEN;
+        for (i = 0; i < PCSPK_BUF_LEN; ++i)
+            s->sample_buf[i] = 128; /* silence */
+    }
+}
+
+static void pcspk_callback(void *opaque, int free)
+{
+    PCSpkState *s = opaque;
+    PITChannelInfo ch;
+    unsigned int n;
+
+    pit_get_channel_info(s->pit, 2, &ch);
+
+    if (ch.mode != 3) {
+        return;
+    }
+
+    n = ch.initial_count;
+    /* avoid frequencies that are not reproducible with sample rate */
+    if (n < PCSPK_MIN_COUNT)
+        n = 0;
+
+    if (s->pit_count != n) {
+        s->pit_count = n;
+        s->play_pos = 0;
+        generate_samples(s);
+    }
+
+    while (free > 0) {
+        n = audio_MIN(s->samples - s->play_pos, (unsigned int)free);
+        n = AUD_write(s->voice, &s->sample_buf[s->play_pos], n);
+        if (!n)
+            break;
+        s->play_pos = (s->play_pos + n) % s->samples;
+        free -= n;
+    }
+}
+
+int pcspk_audio_init(ISABus *bus)
+{
+    PCSpkState *s = pcspk_state;
+    struct audsettings as = {PCSPK_SAMPLE_RATE, 1, AUD_FMT_U8, 0};
+
+    AUD_register_card(s_spk, &s->card);
+
+    s->voice = AUD_open_out(&s->card, s->voice, s_spk, s, pcspk_callback, &as);
+    if (!s->voice) {
+        AUD_log(s_spk, "Could not open voice\n");
+        return -1;
+    }
+
+    return 0;
+}
+
+static uint64_t pcspk_io_read(void *opaque, hwaddr addr,
+                              unsigned size)
+{
+    PCSpkState *s = opaque;
+    PITChannelInfo ch;
+
+    pit_get_channel_info(s->pit, 2, &ch);
+
+    s->dummy_refresh_clock ^= (1 << 4);
+
+    return ch.gate | (s->data_on << 1) | s->dummy_refresh_clock |
+       (ch.out << 5);
+}
+
+static void pcspk_io_write(void *opaque, hwaddr addr, uint64_t val,
+                           unsigned size)
+{
+    PCSpkState *s = opaque;
+    const int gate = val & 1;
+
+    s->data_on = (val >> 1) & 1;
+    pit_set_gate(s->pit, 2, gate);
+    if (s->voice) {
+        if (gate) /* restart */
+            s->play_pos = 0;
+        AUD_set_active_out(s->voice, gate & s->data_on);
+    }
+}
+
+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 = 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(),
+};
+
+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 const 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/audio/pl041.c b/hw/audio/pl041.c
new file mode 100644 (file)
index 0000000..653ab4f
--- /dev/null
@@ -0,0 +1,647 @@
+/*
+ * Arm PrimeCell PL041 Advanced Audio Codec Interface
+ *
+ * Copyright (c) 2011
+ * Written by Mathieu Sonet - www.elasticsheep.com
+ *
+ * This code is licensed under the GPL.
+ *
+ * *****************************************************************
+ *
+ * This driver emulates the ARM AACI interface
+ * connected to a LM4549 codec.
+ *
+ * Limitations:
+ * - Supports only a playback on one channel (Versatile/Vexpress)
+ * - Supports only one TX FIFO in compact-mode or non-compact mode.
+ * - Supports playback of 12, 16, 18 and 20 bits samples.
+ * - Record is not supported.
+ * - The PL041 is hardwired to a LM4549 codec.
+ *
+ */
+
+#include "hw/sysbus.h"
+
+#include "pl041.h"
+#include "lm4549.h"
+
+#if 0
+#define PL041_DEBUG_LEVEL 1
+#endif
+
+#if defined(PL041_DEBUG_LEVEL) && (PL041_DEBUG_LEVEL >= 1)
+#define DBG_L1(fmt, ...) \
+do { printf("pl041: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DBG_L1(fmt, ...) \
+do { } while (0)
+#endif
+
+#if defined(PL041_DEBUG_LEVEL) && (PL041_DEBUG_LEVEL >= 2)
+#define DBG_L2(fmt, ...) \
+do { printf("pl041: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DBG_L2(fmt, ...) \
+do { } while (0)
+#endif
+
+
+#define MAX_FIFO_DEPTH      (1024)
+#define DEFAULT_FIFO_DEPTH  (8)
+
+#define SLOT1_RW    (1 << 19)
+
+/* This FIFO only stores 20-bit samples on 32-bit words.
+   So its level is independent of the selected mode */
+typedef struct {
+    uint32_t level;
+    uint32_t data[MAX_FIFO_DEPTH];
+} pl041_fifo;
+
+typedef struct {
+    pl041_fifo tx_fifo;
+    uint8_t tx_enabled;
+    uint8_t tx_compact_mode;
+    uint8_t tx_sample_size;
+
+    pl041_fifo rx_fifo;
+    uint8_t rx_enabled;
+    uint8_t rx_compact_mode;
+    uint8_t rx_sample_size;
+} pl041_channel;
+
+typedef struct {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    qemu_irq irq;
+
+    uint32_t fifo_depth; /* FIFO depth in non-compact mode */
+
+    pl041_regfile regs;
+    pl041_channel fifo1;
+    lm4549_state codec;
+} pl041_state;
+
+
+static const unsigned char pl041_default_id[8] = {
+    0x41, 0x10, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1
+};
+
+#if defined(PL041_DEBUG_LEVEL)
+#define REGISTER(name, offset) #name,
+static const char *pl041_regs_name[] = {
+    #include "pl041.hx"
+};
+#undef REGISTER
+#endif
+
+
+#if defined(PL041_DEBUG_LEVEL)
+static const char *get_reg_name(hwaddr offset)
+{
+    if (offset <= PL041_dr1_7) {
+        return pl041_regs_name[offset >> 2];
+    }
+
+    return "unknown";
+}
+#endif
+
+static uint8_t pl041_compute_periphid3(pl041_state *s)
+{
+    uint8_t id3 = 1; /* One channel */
+
+    /* Add the fifo depth information */
+    switch (s->fifo_depth) {
+    case 8:
+        id3 |= 0 << 3;
+        break;
+    case 32:
+        id3 |= 1 << 3;
+        break;
+    case 64:
+        id3 |= 2 << 3;
+        break;
+    case 128:
+        id3 |= 3 << 3;
+        break;
+    case 256:
+        id3 |= 4 << 3;
+        break;
+    case 512:
+        id3 |= 5 << 3;
+        break;
+    case 1024:
+        id3 |= 6 << 3;
+        break;
+    case 2048:
+        id3 |= 7 << 3;
+        break;
+    }
+
+    return id3;
+}
+
+static void pl041_reset(pl041_state *s)
+{
+    DBG_L1("pl041_reset\n");
+
+    memset(&s->regs, 0x00, sizeof(pl041_regfile));
+
+    s->regs.slfr = SL1TXEMPTY | SL2TXEMPTY | SL12TXEMPTY;
+    s->regs.sr1 = TXFE | RXFE | TXHE;
+    s->regs.isr1 = 0;
+
+    memset(&s->fifo1, 0x00, sizeof(s->fifo1));
+}
+
+
+static void pl041_fifo1_write(pl041_state *s, uint32_t value)
+{
+    pl041_channel *channel = &s->fifo1;
+    pl041_fifo *fifo = &s->fifo1.tx_fifo;
+
+    /* Push the value in the FIFO */
+    if (channel->tx_compact_mode == 0) {
+        /* Non-compact mode */
+
+        if (fifo->level < s->fifo_depth) {
+            /* Pad the value with 0 to obtain a 20-bit sample */
+            switch (channel->tx_sample_size) {
+            case 12:
+                value = (value << 8) & 0xFFFFF;
+                break;
+            case 16:
+                value = (value << 4) & 0xFFFFF;
+                break;
+            case 18:
+                value = (value << 2) & 0xFFFFF;
+                break;
+            case 20:
+            default:
+                break;
+            }
+
+            /* Store the sample in the FIFO */
+            fifo->data[fifo->level++] = value;
+        }
+#if defined(PL041_DEBUG_LEVEL)
+        else {
+            DBG_L1("fifo1 write: overrun\n");
+        }
+#endif
+    } else {
+        /* Compact mode */
+
+        if ((fifo->level + 2) < s->fifo_depth) {
+            uint32_t i = 0;
+            uint32_t sample = 0;
+
+            for (i = 0; i < 2; i++) {
+                sample = value & 0xFFFF;
+                value = value >> 16;
+
+                /* Pad each sample with 0 to obtain a 20-bit sample */
+                switch (channel->tx_sample_size) {
+                case 12:
+                    sample = sample << 8;
+                    break;
+                case 16:
+                default:
+                    sample = sample << 4;
+                    break;
+                }
+
+                /* Store the sample in the FIFO */
+                fifo->data[fifo->level++] = sample;
+            }
+        }
+#if defined(PL041_DEBUG_LEVEL)
+        else {
+            DBG_L1("fifo1 write: overrun\n");
+        }
+#endif
+    }
+
+    /* Update the status register */
+    if (fifo->level > 0) {
+        s->regs.sr1 &= ~(TXUNDERRUN | TXFE);
+    }
+
+    if (fifo->level >= (s->fifo_depth / 2)) {
+        s->regs.sr1 &= ~TXHE;
+    }
+
+    if (fifo->level >= s->fifo_depth) {
+        s->regs.sr1 |= TXFF;
+    }
+
+    DBG_L2("fifo1_push sr1 = 0x%08x\n", s->regs.sr1);
+}
+
+static void pl041_fifo1_transmit(pl041_state *s)
+{
+    pl041_channel *channel = &s->fifo1;
+    pl041_fifo *fifo = &s->fifo1.tx_fifo;
+    uint32_t slots = s->regs.txcr1 & TXSLOT_MASK;
+    uint32_t written_samples;
+
+    /* Check if FIFO1 transmit is enabled */
+    if ((channel->tx_enabled) && (slots & (TXSLOT3 | TXSLOT4))) {
+        if (fifo->level >= (s->fifo_depth / 2)) {
+            int i;
+
+            DBG_L1("Transfer FIFO level = %i\n", fifo->level);
+
+            /* Try to transfer the whole FIFO */
+            for (i = 0; i < (fifo->level / 2); i++) {
+                uint32_t left = fifo->data[i * 2];
+                uint32_t right = fifo->data[i * 2 + 1];
+
+                 /* Transmit two 20-bit samples to the codec */
+                if (lm4549_write_samples(&s->codec, left, right) == 0) {
+                    DBG_L1("Codec buffer full\n");
+                    break;
+                }
+            }
+
+            written_samples = i * 2;
+            if (written_samples > 0) {
+                /* Update the FIFO level */
+                fifo->level -= written_samples;
+
+                /* Move back the pending samples to the start of the FIFO */
+                for (i = 0; i < fifo->level; i++) {
+                    fifo->data[i] = fifo->data[written_samples + i];
+                }
+
+                /* Update the status register */
+                s->regs.sr1 &= ~TXFF;
+
+                if (fifo->level <= (s->fifo_depth / 2)) {
+                    s->regs.sr1 |= TXHE;
+                }
+
+                if (fifo->level == 0) {
+                    s->regs.sr1 |= TXFE | TXUNDERRUN;
+                    DBG_L1("Empty FIFO\n");
+                }
+            }
+        }
+    }
+}
+
+static void pl041_isr1_update(pl041_state *s)
+{
+    /* Update ISR1 */
+    if (s->regs.sr1 & TXUNDERRUN) {
+        s->regs.isr1 |= URINTR;
+    } else {
+        s->regs.isr1 &= ~URINTR;
+    }
+
+    if (s->regs.sr1 & TXHE) {
+        s->regs.isr1 |= TXINTR;
+    } else {
+        s->regs.isr1 &= ~TXINTR;
+    }
+
+    if (!(s->regs.sr1 & TXBUSY) && (s->regs.sr1 & TXFE)) {
+        s->regs.isr1 |= TXCINTR;
+    } else {
+        s->regs.isr1 &= ~TXCINTR;
+    }
+
+    /* Update the irq state */
+    qemu_set_irq(s->irq, ((s->regs.isr1 & s->regs.ie1) > 0) ? 1 : 0);
+    DBG_L2("Set interrupt sr1 = 0x%08x isr1 = 0x%08x masked = 0x%08x\n",
+           s->regs.sr1, s->regs.isr1, s->regs.isr1 & s->regs.ie1);
+}
+
+static void pl041_request_data(void *opaque)
+{
+    pl041_state *s = (pl041_state *)opaque;
+
+    /* Trigger pending transfers */
+    pl041_fifo1_transmit(s);
+    pl041_isr1_update(s);
+}
+
+static uint64_t pl041_read(void *opaque, hwaddr offset,
+                                unsigned size)
+{
+    pl041_state *s = (pl041_state *)opaque;
+    int value;
+
+    if ((offset >= PL041_periphid0) && (offset <= PL041_pcellid3)) {
+        if (offset == PL041_periphid3) {
+            value = pl041_compute_periphid3(s);
+        } else {
+            value = pl041_default_id[(offset - PL041_periphid0) >> 2];
+        }
+
+        DBG_L1("pl041_read [0x%08x] => 0x%08x\n", offset, value);
+        return value;
+    } else if (offset <= PL041_dr4_7) {
+        value = *((uint32_t *)&s->regs + (offset >> 2));
+    } else {
+        DBG_L1("pl041_read: Reserved offset %x\n", (int)offset);
+        return 0;
+    }
+
+    switch (offset) {
+    case PL041_allints:
+        value = s->regs.isr1 & 0x7F;
+        break;
+    }
+
+    DBG_L1("pl041_read [0x%08x] %s => 0x%08x\n", offset,
+           get_reg_name(offset), value);
+
+    return value;
+}
+
+static void pl041_write(void *opaque, hwaddr offset,
+                             uint64_t value, unsigned size)
+{
+    pl041_state *s = (pl041_state *)opaque;
+    uint16_t control, data;
+    uint32_t result;
+
+    DBG_L1("pl041_write [0x%08x] %s <= 0x%08x\n", offset,
+           get_reg_name(offset), (unsigned int)value);
+
+    /* Write the register */
+    if (offset <= PL041_dr4_7) {
+        *((uint32_t *)&s->regs + (offset >> 2)) = value;
+    } else {
+        DBG_L1("pl041_write: Reserved offset %x\n", (int)offset);
+        return;
+    }
+
+    /* Execute the actions */
+    switch (offset) {
+    case PL041_txcr1:
+    {
+        pl041_channel *channel = &s->fifo1;
+
+        uint32_t txen = s->regs.txcr1 & TXEN;
+        uint32_t tsize = (s->regs.txcr1 & TSIZE_MASK) >> TSIZE_MASK_BIT;
+        uint32_t compact_mode = (s->regs.txcr1 & TXCOMPACT) ? 1 : 0;
+#if defined(PL041_DEBUG_LEVEL)
+        uint32_t slots = (s->regs.txcr1 & TXSLOT_MASK) >> TXSLOT_MASK_BIT;
+        uint32_t txfen = (s->regs.txcr1 & TXFEN) > 0 ? 1 : 0;
+#endif
+
+        DBG_L1("=> txen = %i slots = 0x%01x tsize = %i compact = %i "
+               "txfen = %i\n", txen, slots,  tsize, compact_mode, txfen);
+
+        channel->tx_enabled = txen;
+        channel->tx_compact_mode = compact_mode;
+
+        switch (tsize) {
+        case 0:
+            channel->tx_sample_size = 16;
+            break;
+        case 1:
+            channel->tx_sample_size = 18;
+            break;
+        case 2:
+            channel->tx_sample_size = 20;
+            break;
+        case 3:
+            channel->tx_sample_size = 12;
+            break;
+        }
+
+        DBG_L1("TX enabled = %i\n", channel->tx_enabled);
+        DBG_L1("TX compact mode = %i\n", channel->tx_compact_mode);
+        DBG_L1("TX sample width = %i\n", channel->tx_sample_size);
+
+        /* Check if compact mode is allowed with selected tsize */
+        if (channel->tx_compact_mode == 1) {
+            if ((channel->tx_sample_size == 18) ||
+                (channel->tx_sample_size == 20)) {
+                channel->tx_compact_mode = 0;
+                DBG_L1("Compact mode not allowed with 18/20-bit sample size\n");
+            }
+        }
+
+        break;
+    }
+    case PL041_sl1tx:
+        s->regs.slfr &= ~SL1TXEMPTY;
+
+        control = (s->regs.sl1tx >> 12) & 0x7F;
+        data = (s->regs.sl2tx >> 4) & 0xFFFF;
+
+        if ((s->regs.sl1tx & SLOT1_RW) == 0) {
+            /* Write operation */
+            lm4549_write(&s->codec, control, data);
+        } else {
+            /* Read operation */
+            result = lm4549_read(&s->codec, control);
+
+            /* Store the returned value */
+            s->regs.sl1rx = s->regs.sl1tx & ~SLOT1_RW;
+            s->regs.sl2rx = result << 4;
+
+            s->regs.slfr &= ~(SL1RXBUSY | SL2RXBUSY);
+            s->regs.slfr |= SL1RXVALID | SL2RXVALID;
+        }
+        break;
+
+    case PL041_sl2tx:
+        s->regs.sl2tx = value;
+        s->regs.slfr &= ~SL2TXEMPTY;
+        break;
+
+    case PL041_intclr:
+        DBG_L1("=> Clear interrupt intclr = 0x%08x isr1 = 0x%08x\n",
+               s->regs.intclr, s->regs.isr1);
+
+        if (s->regs.intclr & TXUEC1) {
+            s->regs.sr1 &= ~TXUNDERRUN;
+        }
+        break;
+
+    case PL041_maincr:
+    {
+#if defined(PL041_DEBUG_LEVEL)
+        char debug[] = " AACIFE  SL1RXEN  SL1TXEN";
+        if (!(value & AACIFE)) {
+            debug[0] = '!';
+        }
+        if (!(value & SL1RXEN)) {
+            debug[8] = '!';
+        }
+        if (!(value & SL1TXEN)) {
+            debug[17] = '!';
+        }
+        DBG_L1("%s\n", debug);
+#endif
+
+        if ((s->regs.maincr & AACIFE) == 0) {
+            pl041_reset(s);
+        }
+        break;
+    }
+
+    case PL041_dr1_0:
+    case PL041_dr1_1:
+    case PL041_dr1_2:
+    case PL041_dr1_3:
+        pl041_fifo1_write(s, value);
+        break;
+    }
+
+    /* Transmit the FIFO content */
+    pl041_fifo1_transmit(s);
+
+    /* Update the ISR1 register */
+    pl041_isr1_update(s);
+}
+
+static void pl041_device_reset(DeviceState *d)
+{
+    pl041_state *s = DO_UPCAST(pl041_state, busdev.qdev, d);
+
+    pl041_reset(s);
+}
+
+static const MemoryRegionOps pl041_ops = {
+    .read = pl041_read,
+    .write = pl041_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int pl041_init(SysBusDevice *dev)
+{
+    pl041_state *s = FROM_SYSBUS(pl041_state, dev);
+
+    DBG_L1("pl041_init 0x%08x\n", (uint32_t)s);
+
+    /* Check the device properties */
+    switch (s->fifo_depth) {
+    case 8:
+    case 32:
+    case 64:
+    case 128:
+    case 256:
+    case 512:
+    case 1024:
+    case 2048:
+        break;
+    case 16:
+    default:
+        /* NC FIFO depth of 16 is not allowed because its id bits in
+           AACIPERIPHID3 overlap with the id for the default NC FIFO depth */
+        qemu_log_mask(LOG_UNIMP,
+                      "pl041: unsupported non-compact fifo depth [%i]\n",
+                      s->fifo_depth);
+        return -1;
+    }
+
+    /* Connect the device to the sysbus */
+    memory_region_init_io(&s->iomem, &pl041_ops, s, "pl041", 0x1000);
+    sysbus_init_mmio(dev, &s->iomem);
+    sysbus_init_irq(dev, &s->irq);
+
+    /* Init the codec */
+    lm4549_init(&s->codec, &pl041_request_data, (void *)s);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_pl041_regfile = {
+    .name = "pl041_regfile",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+#define REGISTER(name, offset) VMSTATE_UINT32(name, pl041_regfile),
+        #include "pl041.hx"
+#undef REGISTER
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_pl041_fifo = {
+    .name = "pl041_fifo",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32(level, pl041_fifo),
+        VMSTATE_UINT32_ARRAY(data, pl041_fifo, MAX_FIFO_DEPTH),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_pl041_channel = {
+    .name = "pl041_channel",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_STRUCT(tx_fifo, pl041_channel, 0,
+                       vmstate_pl041_fifo, pl041_fifo),
+        VMSTATE_UINT8(tx_enabled, pl041_channel),
+        VMSTATE_UINT8(tx_compact_mode, pl041_channel),
+        VMSTATE_UINT8(tx_sample_size, pl041_channel),
+        VMSTATE_STRUCT(rx_fifo, pl041_channel, 0,
+                       vmstate_pl041_fifo, pl041_fifo),
+        VMSTATE_UINT8(rx_enabled, pl041_channel),
+        VMSTATE_UINT8(rx_compact_mode, pl041_channel),
+        VMSTATE_UINT8(rx_sample_size, pl041_channel),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_pl041 = {
+    .name = "pl041",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(fifo_depth, pl041_state),
+        VMSTATE_STRUCT(regs, pl041_state, 0,
+                       vmstate_pl041_regfile, pl041_regfile),
+        VMSTATE_STRUCT(fifo1, pl041_state, 0,
+                       vmstate_pl041_channel, pl041_channel),
+        VMSTATE_STRUCT(codec, pl041_state, 0,
+                       vmstate_lm4549_state, lm4549_state),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static Property pl041_device_properties[] = {
+    /* Non-compact FIFO depth property */
+    DEFINE_PROP_UINT32("nc_fifo_depth", pl041_state, fifo_depth, DEFAULT_FIFO_DEPTH),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void pl041_device_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = pl041_init;
+    dc->no_user = 1;
+    dc->reset = pl041_device_reset;
+    dc->vmsd = &vmstate_pl041;
+    dc->props = pl041_device_properties;
+}
+
+static const 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_types(void)
+{
+    type_register_static(&pl041_device_info);
+}
+
+type_init(pl041_register_types)
diff --git a/hw/audio/pl041.h b/hw/audio/pl041.h
new file mode 100644 (file)
index 0000000..427ab6d
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * Arm PrimeCell PL041 Advanced Audio Codec Interface
+ *
+ * Copyright (c) 2011
+ * Written by Mathieu Sonet - www.elasticsheep.com
+ *
+ * This code is licensed under the GPL.
+ *
+ * *****************************************************************
+ */
+
+#ifndef HW_PL041_H
+#define HW_PL041_H
+
+/* Register file */
+#define REGISTER(name, offset) uint32_t name;
+typedef struct {
+    #include "pl041.hx"
+} pl041_regfile;
+#undef REGISTER
+
+/* Register addresses */
+#define REGISTER(name, offset) PL041_##name = offset,
+enum {
+    #include "pl041.hx"
+
+    PL041_periphid0 = 0xFE0,
+    PL041_periphid1 = 0xFE4,
+    PL041_periphid2 = 0xFE8,
+    PL041_periphid3 = 0xFEC,
+    PL041_pcellid0  = 0xFF0,
+    PL041_pcellid1  = 0xFF4,
+    PL041_pcellid2  = 0xFF8,
+    PL041_pcellid3  = 0xFFC,
+};
+#undef REGISTER
+
+/* Register bits */
+
+/* IEx */
+#define TXCIE           (1 << 0)
+#define RXTIE           (1 << 1)
+#define TXIE            (1 << 2)
+#define RXIE            (1 << 3)
+#define RXOIE           (1 << 4)
+#define TXUIE           (1 << 5)
+#define RXTOIE          (1 << 6)
+
+/* TXCRx */
+#define TXEN            (1 << 0)
+#define TXSLOT1         (1 << 1)
+#define TXSLOT2         (1 << 2)
+#define TXSLOT3         (1 << 3)
+#define TXSLOT4         (1 << 4)
+#define TXCOMPACT       (1 << 15)
+#define TXFEN           (1 << 16)
+
+#define TXSLOT_MASK_BIT (1)
+#define TXSLOT_MASK     (0xFFF << TXSLOT_MASK_BIT)
+
+#define TSIZE_MASK_BIT  (13)
+#define TSIZE_MASK      (0x3 << TSIZE_MASK_BIT)
+
+#define TSIZE_16BITS    (0x0 << TSIZE_MASK_BIT)
+#define TSIZE_18BITS    (0x1 << TSIZE_MASK_BIT)
+#define TSIZE_20BITS    (0x2 << TSIZE_MASK_BIT)
+#define TSIZE_12BITS    (0x3 << TSIZE_MASK_BIT)
+
+/* SRx */
+#define RXFE         (1 << 0)
+#define TXFE         (1 << 1)
+#define RXHF         (1 << 2)
+#define TXHE         (1 << 3)
+#define RXFF         (1 << 4)
+#define TXFF         (1 << 5)
+#define RXBUSY       (1 << 6)
+#define TXBUSY       (1 << 7)
+#define RXOVERRUN    (1 << 8)
+#define TXUNDERRUN   (1 << 9)
+#define RXTIMEOUT    (1 << 10)
+#define RXTOFE       (1 << 11)
+
+/* ISRx */
+#define TXCINTR      (1 << 0)
+#define RXTOINTR     (1 << 1)
+#define TXINTR       (1 << 2)
+#define RXINTR       (1 << 3)
+#define ORINTR       (1 << 4)
+#define URINTR       (1 << 5)
+#define RXTOFEINTR   (1 << 6)
+
+/* SLFR */
+#define SL1RXBUSY    (1 << 0)
+#define SL1TXBUSY    (1 << 1)
+#define SL2RXBUSY    (1 << 2)
+#define SL2TXBUSY    (1 << 3)
+#define SL12RXBUSY   (1 << 4)
+#define SL12TXBUSY   (1 << 5)
+#define SL1RXVALID   (1 << 6)
+#define SL1TXEMPTY   (1 << 7)
+#define SL2RXVALID   (1 << 8)
+#define SL2TXEMPTY   (1 << 9)
+#define SL12RXVALID  (1 << 10)
+#define SL12TXEMPTY  (1 << 11)
+#define RAWGPIOINT   (1 << 12)
+#define RWIS         (1 << 13)
+
+/* MAINCR */
+#define AACIFE       (1 << 0)
+#define LOOPBACK     (1 << 1)
+#define LOWPOWER     (1 << 2)
+#define SL1RXEN      (1 << 3)
+#define SL1TXEN      (1 << 4)
+#define SL2RXEN      (1 << 5)
+#define SL2TXEN      (1 << 6)
+#define SL12RXEN     (1 << 7)
+#define SL12TXEN     (1 << 8)
+#define DMAENABLE    (1 << 9)
+
+/* INTCLR */
+#define WISC         (1 << 0)
+#define RXOEC1       (1 << 1)
+#define RXOEC2       (1 << 2)
+#define RXOEC3       (1 << 3)
+#define RXOEC4       (1 << 4)
+#define TXUEC1       (1 << 5)
+#define TXUEC2       (1 << 6)
+#define TXUEC3       (1 << 7)
+#define TXUEC4       (1 << 8)
+#define RXTOFEC1     (1 << 9)
+#define RXTOFEC2     (1 << 10)
+#define RXTOFEC3     (1 << 11)
+#define RXTOFEC4     (1 << 12)
+
+#endif /* #ifndef HW_PL041_H */
diff --git a/hw/audio/pl041.hx b/hw/audio/pl041.hx
new file mode 100644 (file)
index 0000000..dd7188c
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Arm PrimeCell PL041 Advanced Audio Codec Interface
+ *
+ * Copyright (c) 2011
+ * Written by Mathieu Sonet - www.elasticsheep.com
+ *
+ * This code is licensed under the GPL.
+ *
+ * *****************************************************************
+ */
+
+/* PL041 register file description */
+
+REGISTER( rxcr1,   0x00 )
+REGISTER( txcr1,   0x04 )
+REGISTER( sr1,     0x08 )
+REGISTER( isr1,    0x0C )
+REGISTER( ie1,     0x10 )
+REGISTER( rxcr2,   0x14 )
+REGISTER( txcr2,   0x18 )
+REGISTER( sr2,     0x1C )
+REGISTER( isr2,    0x20 )
+REGISTER( ie2,     0x24 )
+REGISTER( rxcr3,   0x28 )
+REGISTER( txcr3,   0x2C )
+REGISTER( sr3,     0x30 )
+REGISTER( isr3,    0x34 )
+REGISTER( ie3,     0x38 )
+REGISTER( rxcr4,   0x3C )
+REGISTER( txcr4,   0x40 )
+REGISTER( sr4,     0x44 )
+REGISTER( isr4,    0x48 )
+REGISTER( ie4,     0x4C )
+REGISTER( sl1rx,   0x50 )
+REGISTER( sl1tx,   0x54 )
+REGISTER( sl2rx,   0x58 )
+REGISTER( sl2tx,   0x5C )
+REGISTER( sl12rx,  0x60 )
+REGISTER( sl12tx,  0x64 )
+REGISTER( slfr,    0x68 )
+REGISTER( slistat, 0x6C )
+REGISTER( slien,   0x70 )
+REGISTER( intclr,  0x74 )
+REGISTER( maincr,  0x78 )
+REGISTER( reset,   0x7C )
+REGISTER( sync,    0x80 )
+REGISTER( allints, 0x84 )
+REGISTER( mainfr,  0x88 )
+REGISTER( unused,  0x8C )
+REGISTER( dr1_0,   0x90 )
+REGISTER( dr1_1,   0x94 )
+REGISTER( dr1_2,   0x98 )
+REGISTER( dr1_3,   0x9C )
+REGISTER( dr1_4,   0xA0 )
+REGISTER( dr1_5,   0xA4 )
+REGISTER( dr1_6,   0xA8 )
+REGISTER( dr1_7,   0xAC )
+REGISTER( dr2_0,   0xB0 )
+REGISTER( dr2_1,   0xB4 )
+REGISTER( dr2_2,   0xB8 )
+REGISTER( dr2_3,   0xBC )
+REGISTER( dr2_4,   0xC0 )
+REGISTER( dr2_5,   0xC4 )
+REGISTER( dr2_6,   0xC8 )
+REGISTER( dr2_7,   0xCC )
+REGISTER( dr3_0,   0xD0 )
+REGISTER( dr3_1,   0xD4 )
+REGISTER( dr3_2,   0xD8 )
+REGISTER( dr3_3,   0xDC )
+REGISTER( dr3_4,   0xE0 )
+REGISTER( dr3_5,   0xE4 )
+REGISTER( dr3_6,   0xE8 )
+REGISTER( dr3_7,   0xEC )
+REGISTER( dr4_0,   0xF0 )
+REGISTER( dr4_1,   0xF4 )
+REGISTER( dr4_2,   0xF8 )
+REGISTER( dr4_3,   0xFC )
+REGISTER( dr4_4,   0x100 )
+REGISTER( dr4_5,   0x104 )
+REGISTER( dr4_6,   0x108 )
+REGISTER( dr4_7,   0x10C )
diff --git a/hw/audio/sb16.c b/hw/audio/sb16.c
new file mode 100644 (file)
index 0000000..783b6b4
--- /dev/null
@@ -0,0 +1,1424 @@
+/*
+ * QEMU Soundblaster 16 emulation
+ *
+ * Copyright (c) 2003-2005 Vassili Karpov (malc)
+ *
+ * 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 "hw/hw.h"
+#include "hw/audio/audio.h"
+#include "audio/audio.h"
+#include "hw/isa/isa.h"
+#include "hw/qdev.h"
+#include "qemu/timer.h"
+#include "qemu/host-utils.h"
+
+#define dolog(...) AUD_log ("sb16", __VA_ARGS__)
+
+/* #define DEBUG */
+/* #define DEBUG_SB16_MOST */
+
+#ifdef DEBUG
+#define ldebug(...) dolog (__VA_ARGS__)
+#else
+#define ldebug(...)
+#endif
+
+#define IO_READ_PROTO(name)                             \
+    uint32_t name (void *opaque, uint32_t nport)
+#define IO_WRITE_PROTO(name)                                    \
+    void name (void *opaque, uint32_t nport, uint32_t val)
+
+static const char e3[] = "COPYRIGHT (C) CREATIVE TECHNOLOGY LTD, 1992.";
+
+typedef struct SB16State {
+    ISADevice dev;
+    QEMUSoundCard card;
+    qemu_irq pic;
+    uint32_t irq;
+    uint32_t dma;
+    uint32_t hdma;
+    uint32_t port;
+    uint32_t ver;
+
+    int in_index;
+    int out_data_len;
+    int fmt_stereo;
+    int fmt_signed;
+    int fmt_bits;
+    audfmt_e fmt;
+    int dma_auto;
+    int block_size;
+    int fifo;
+    int freq;
+    int time_const;
+    int speaker;
+    int needed_bytes;
+    int cmd;
+    int use_hdma;
+    int highspeed;
+    int can_write;
+
+    int v2x6;
+
+    uint8_t csp_param;
+    uint8_t csp_value;
+    uint8_t csp_mode;
+    uint8_t csp_regs[256];
+    uint8_t csp_index;
+    uint8_t csp_reg83[4];
+    int csp_reg83r;
+    int csp_reg83w;
+
+    uint8_t in2_data[10];
+    uint8_t out_data[50];
+    uint8_t test_reg;
+    uint8_t last_read_byte;
+    int nzero;
+
+    int left_till_irq;
+
+    int dma_running;
+    int bytes_per_second;
+    int align;
+    int audio_free;
+    SWVoiceOut *voice;
+
+    QEMUTimer *aux_ts;
+    /* mixer state */
+    int mixer_nreg;
+    uint8_t mixer_regs[256];
+} SB16State;
+
+static void SB_audio_callback (void *opaque, int free);
+
+static int magic_of_irq (int irq)
+{
+    switch (irq) {
+    case 5:
+        return 2;
+    case 7:
+        return 4;
+    case 9:
+        return 1;
+    case 10:
+        return 8;
+    default:
+        dolog ("bad irq %d\n", irq);
+        return 2;
+    }
+}
+
+static int irq_of_magic (int magic)
+{
+    switch (magic) {
+    case 1:
+        return 9;
+    case 2:
+        return 5;
+    case 4:
+        return 7;
+    case 8:
+        return 10;
+    default:
+        dolog ("bad irq magic %d\n", magic);
+        return -1;
+    }
+}
+
+#if 0
+static void log_dsp (SB16State *dsp)
+{
+    ldebug ("%s:%s:%d:%s:dmasize=%d:freq=%d:const=%d:speaker=%d\n",
+            dsp->fmt_stereo ? "Stereo" : "Mono",
+            dsp->fmt_signed ? "Signed" : "Unsigned",
+            dsp->fmt_bits,
+            dsp->dma_auto ? "Auto" : "Single",
+            dsp->block_size,
+            dsp->freq,
+            dsp->time_const,
+            dsp->speaker);
+}
+#endif
+
+static void speaker (SB16State *s, int on)
+{
+    s->speaker = on;
+    /* AUD_enable (s->voice, on); */
+}
+
+static void control (SB16State *s, int hold)
+{
+    int dma = s->use_hdma ? s->hdma : s->dma;
+    s->dma_running = hold;
+
+    ldebug ("hold %d high %d dma %d\n", hold, s->use_hdma, dma);
+
+    if (hold) {
+        DMA_hold_DREQ (dma);
+        AUD_set_active_out (s->voice, 1);
+    }
+    else {
+        DMA_release_DREQ (dma);
+        AUD_set_active_out (s->voice, 0);
+    }
+}
+
+static void aux_timer (void *opaque)
+{
+    SB16State *s = opaque;
+    s->can_write = 1;
+    qemu_irq_raise (s->pic);
+}
+
+#define DMA8_AUTO 1
+#define DMA8_HIGH 2
+
+static void continue_dma8 (SB16State *s)
+{
+    if (s->freq > 0) {
+        struct audsettings as;
+
+        s->audio_free = 0;
+
+        as.freq = s->freq;
+        as.nchannels = 1 << s->fmt_stereo;
+        as.fmt = s->fmt;
+        as.endianness = 0;
+
+        s->voice = AUD_open_out (
+            &s->card,
+            s->voice,
+            "sb16",
+            s,
+            SB_audio_callback,
+            &as
+            );
+    }
+
+    control (s, 1);
+}
+
+static void dma_cmd8 (SB16State *s, int mask, int dma_len)
+{
+    s->fmt = AUD_FMT_U8;
+    s->use_hdma = 0;
+    s->fmt_bits = 8;
+    s->fmt_signed = 0;
+    s->fmt_stereo = (s->mixer_regs[0x0e] & 2) != 0;
+    if (-1 == s->time_const) {
+        if (s->freq <= 0)
+            s->freq = 11025;
+    }
+    else {
+        int tmp = (256 - s->time_const);
+        s->freq = (1000000 + (tmp / 2)) / tmp;
+    }
+
+    if (dma_len != -1) {
+        s->block_size = dma_len << s->fmt_stereo;
+    }
+    else {
+        /* This is apparently the only way to make both Act1/PL
+           and SecondReality/FC work
+
+           Act1 sets block size via command 0x48 and it's an odd number
+           SR does the same with even number
+           Both use stereo, and Creatives own documentation states that
+           0x48 sets block size in bytes less one.. go figure */
+        s->block_size &= ~s->fmt_stereo;
+    }
+
+    s->freq >>= s->fmt_stereo;
+    s->left_till_irq = s->block_size;
+    s->bytes_per_second = (s->freq << s->fmt_stereo);
+    /* s->highspeed = (mask & DMA8_HIGH) != 0; */
+    s->dma_auto = (mask & DMA8_AUTO) != 0;
+    s->align = (1 << s->fmt_stereo) - 1;
+
+    if (s->block_size & s->align) {
+        dolog ("warning: misaligned block size %d, alignment %d\n",
+               s->block_size, s->align + 1);
+    }
+
+    ldebug ("freq %d, stereo %d, sign %d, bits %d, "
+            "dma %d, auto %d, fifo %d, high %d\n",
+            s->freq, s->fmt_stereo, s->fmt_signed, s->fmt_bits,
+            s->block_size, s->dma_auto, s->fifo, s->highspeed);
+
+    continue_dma8 (s);
+    speaker (s, 1);
+}
+
+static void dma_cmd (SB16State *s, uint8_t cmd, uint8_t d0, int dma_len)
+{
+    s->use_hdma = cmd < 0xc0;
+    s->fifo = (cmd >> 1) & 1;
+    s->dma_auto = (cmd >> 2) & 1;
+    s->fmt_signed = (d0 >> 4) & 1;
+    s->fmt_stereo = (d0 >> 5) & 1;
+
+    switch (cmd >> 4) {
+    case 11:
+        s->fmt_bits = 16;
+        break;
+
+    case 12:
+        s->fmt_bits = 8;
+        break;
+    }
+
+    if (-1 != s->time_const) {
+#if 1
+        int tmp = 256 - s->time_const;
+        s->freq = (1000000 + (tmp / 2)) / tmp;
+#else
+        /* s->freq = 1000000 / ((255 - s->time_const) << s->fmt_stereo); */
+        s->freq = 1000000 / ((255 - s->time_const));
+#endif
+        s->time_const = -1;
+    }
+
+    s->block_size = dma_len + 1;
+    s->block_size <<= (s->fmt_bits == 16);
+    if (!s->dma_auto) {
+        /* It is clear that for DOOM and auto-init this value
+           shouldn't take stereo into account, while Miles Sound Systems
+           setsound.exe with single transfer mode wouldn't work without it
+           wonders of SB16 yet again */
+        s->block_size <<= s->fmt_stereo;
+    }
+
+    ldebug ("freq %d, stereo %d, sign %d, bits %d, "
+            "dma %d, auto %d, fifo %d, high %d\n",
+            s->freq, s->fmt_stereo, s->fmt_signed, s->fmt_bits,
+            s->block_size, s->dma_auto, s->fifo, s->highspeed);
+
+    if (16 == s->fmt_bits) {
+        if (s->fmt_signed) {
+            s->fmt = AUD_FMT_S16;
+        }
+        else {
+            s->fmt = AUD_FMT_U16;
+        }
+    }
+    else {
+        if (s->fmt_signed) {
+            s->fmt = AUD_FMT_S8;
+        }
+        else {
+            s->fmt = AUD_FMT_U8;
+        }
+    }
+
+    s->left_till_irq = s->block_size;
+
+    s->bytes_per_second = (s->freq << s->fmt_stereo) << (s->fmt_bits == 16);
+    s->highspeed = 0;
+    s->align = (1 << (s->fmt_stereo + (s->fmt_bits == 16))) - 1;
+    if (s->block_size & s->align) {
+        dolog ("warning: misaligned block size %d, alignment %d\n",
+               s->block_size, s->align + 1);
+    }
+
+    if (s->freq) {
+        struct audsettings as;
+
+        s->audio_free = 0;
+
+        as.freq = s->freq;
+        as.nchannels = 1 << s->fmt_stereo;
+        as.fmt = s->fmt;
+        as.endianness = 0;
+
+        s->voice = AUD_open_out (
+            &s->card,
+            s->voice,
+            "sb16",
+            s,
+            SB_audio_callback,
+            &as
+            );
+    }
+
+    control (s, 1);
+    speaker (s, 1);
+}
+
+static inline void dsp_out_data (SB16State *s, uint8_t val)
+{
+    ldebug ("outdata %#x\n", val);
+    if ((size_t) s->out_data_len < sizeof (s->out_data)) {
+        s->out_data[s->out_data_len++] = val;
+    }
+}
+
+static inline uint8_t dsp_get_data (SB16State *s)
+{
+    if (s->in_index) {
+        return s->in2_data[--s->in_index];
+    }
+    else {
+        dolog ("buffer underflow\n");
+        return 0;
+    }
+}
+
+static void command (SB16State *s, uint8_t cmd)
+{
+    ldebug ("command %#x\n", cmd);
+
+    if (cmd > 0xaf && cmd < 0xd0) {
+        if (cmd & 8) {
+            dolog ("ADC not yet supported (command %#x)\n", cmd);
+        }
+
+        switch (cmd >> 4) {
+        case 11:
+        case 12:
+            break;
+        default:
+            dolog ("%#x wrong bits\n", cmd);
+        }
+        s->needed_bytes = 3;
+    }
+    else {
+        s->needed_bytes = 0;
+
+        switch (cmd) {
+        case 0x03:
+            dsp_out_data (s, 0x10); /* s->csp_param); */
+            goto warn;
+
+        case 0x04:
+            s->needed_bytes = 1;
+            goto warn;
+
+        case 0x05:
+            s->needed_bytes = 2;
+            goto warn;
+
+        case 0x08:
+            /* __asm__ ("int3"); */
+            goto warn;
+
+        case 0x0e:
+            s->needed_bytes = 2;
+            goto warn;
+
+        case 0x09:
+            dsp_out_data (s, 0xf8);
+            goto warn;
+
+        case 0x0f:
+            s->needed_bytes = 1;
+            goto warn;
+
+        case 0x10:
+            s->needed_bytes = 1;
+            goto warn;
+
+        case 0x14:
+            s->needed_bytes = 2;
+            s->block_size = 0;
+            break;
+
+        case 0x1c:              /* Auto-Initialize DMA DAC, 8-bit */
+            dma_cmd8 (s, DMA8_AUTO, -1);
+            break;
+
+        case 0x20:              /* Direct ADC, Juice/PL */
+            dsp_out_data (s, 0xff);
+            goto warn;
+
+        case 0x35:
+            dolog ("0x35 - MIDI command not implemented\n");
+            break;
+
+        case 0x40:
+            s->freq = -1;
+            s->time_const = -1;
+            s->needed_bytes = 1;
+            break;
+
+        case 0x41:
+            s->freq = -1;
+            s->time_const = -1;
+            s->needed_bytes = 2;
+            break;
+
+        case 0x42:
+            s->freq = -1;
+            s->time_const = -1;
+            s->needed_bytes = 2;
+            goto warn;
+
+        case 0x45:
+            dsp_out_data (s, 0xaa);
+            goto warn;
+
+        case 0x47:                /* Continue Auto-Initialize DMA 16bit */
+            break;
+
+        case 0x48:
+            s->needed_bytes = 2;
+            break;
+
+        case 0x74:
+            s->needed_bytes = 2; /* DMA DAC, 4-bit ADPCM */
+            dolog ("0x75 - DMA DAC, 4-bit ADPCM not implemented\n");
+            break;
+
+        case 0x75:              /* DMA DAC, 4-bit ADPCM Reference */
+            s->needed_bytes = 2;
+            dolog ("0x74 - DMA DAC, 4-bit ADPCM Reference not implemented\n");
+            break;
+
+        case 0x76:              /* DMA DAC, 2.6-bit ADPCM */
+            s->needed_bytes = 2;
+            dolog ("0x74 - DMA DAC, 2.6-bit ADPCM not implemented\n");
+            break;
+
+        case 0x77:              /* DMA DAC, 2.6-bit ADPCM Reference */
+            s->needed_bytes = 2;
+            dolog ("0x74 - DMA DAC, 2.6-bit ADPCM Reference not implemented\n");
+            break;
+
+        case 0x7d:
+            dolog ("0x7d - Autio-Initialize DMA DAC, 4-bit ADPCM Reference\n");
+            dolog ("not implemented\n");
+            break;
+
+        case 0x7f:
+            dolog (
+                "0x7d - Autio-Initialize DMA DAC, 2.6-bit ADPCM Reference\n"
+                );
+            dolog ("not implemented\n");
+            break;
+
+        case 0x80:
+            s->needed_bytes = 2;
+            break;
+
+        case 0x90:
+        case 0x91:
+            dma_cmd8 (s, ((cmd & 1) == 0) | DMA8_HIGH, -1);
+            break;
+
+        case 0xd0:              /* halt DMA operation. 8bit */
+            control (s, 0);
+            break;
+
+        case 0xd1:              /* speaker on */
+            speaker (s, 1);
+            break;
+
+        case 0xd3:              /* speaker off */
+            speaker (s, 0);
+            break;
+
+        case 0xd4:              /* continue DMA operation. 8bit */
+            /* KQ6 (or maybe Sierras audblst.drv in general) resets
+               the frequency between halt/continue */
+            continue_dma8 (s);
+            break;
+
+        case 0xd5:              /* halt DMA operation. 16bit */
+            control (s, 0);
+            break;
+
+        case 0xd6:              /* continue DMA operation. 16bit */
+            control (s, 1);
+            break;
+
+        case 0xd9:              /* exit auto-init DMA after this block. 16bit */
+            s->dma_auto = 0;
+            break;
+
+        case 0xda:              /* exit auto-init DMA after this block. 8bit */
+            s->dma_auto = 0;
+            break;
+
+        case 0xe0:              /* DSP identification */
+            s->needed_bytes = 1;
+            break;
+
+        case 0xe1:
+            dsp_out_data (s, s->ver & 0xff);
+            dsp_out_data (s, s->ver >> 8);
+            break;
+
+        case 0xe2:
+            s->needed_bytes = 1;
+            goto warn;
+
+        case 0xe3:
+            {
+                int i;
+                for (i = sizeof (e3) - 1; i >= 0; --i)
+                    dsp_out_data (s, e3[i]);
+            }
+            break;
+
+        case 0xe4:              /* write test reg */
+            s->needed_bytes = 1;
+            break;
+
+        case 0xe7:
+            dolog ("Attempt to probe for ESS (0xe7)?\n");
+            break;
+
+        case 0xe8:              /* read test reg */
+            dsp_out_data (s, s->test_reg);
+            break;
+
+        case 0xf2:
+        case 0xf3:
+            dsp_out_data (s, 0xaa);
+            s->mixer_regs[0x82] |= (cmd == 0xf2) ? 1 : 2;
+            qemu_irq_raise (s->pic);
+            break;
+
+        case 0xf9:
+            s->needed_bytes = 1;
+            goto warn;
+
+        case 0xfa:
+            dsp_out_data (s, 0);
+            goto warn;
+
+        case 0xfc:              /* FIXME */
+            dsp_out_data (s, 0);
+            goto warn;
+
+        default:
+            dolog ("Unrecognized command %#x\n", cmd);
+            break;
+        }
+    }
+
+    if (!s->needed_bytes) {
+        ldebug ("\n");
+    }
+
+ exit:
+    if (!s->needed_bytes) {
+        s->cmd = -1;
+    }
+    else {
+        s->cmd = cmd;
+    }
+    return;
+
+ warn:
+    dolog ("warning: command %#x,%d is not truly understood yet\n",
+           cmd, s->needed_bytes);
+    goto exit;
+
+}
+
+static uint16_t dsp_get_lohi (SB16State *s)
+{
+    uint8_t hi = dsp_get_data (s);
+    uint8_t lo = dsp_get_data (s);
+    return (hi << 8) | lo;
+}
+
+static uint16_t dsp_get_hilo (SB16State *s)
+{
+    uint8_t lo = dsp_get_data (s);
+    uint8_t hi = dsp_get_data (s);
+    return (hi << 8) | lo;
+}
+
+static void complete (SB16State *s)
+{
+    int d0, d1, d2;
+    ldebug ("complete command %#x, in_index %d, needed_bytes %d\n",
+            s->cmd, s->in_index, s->needed_bytes);
+
+    if (s->cmd > 0xaf && s->cmd < 0xd0) {
+        d2 = dsp_get_data (s);
+        d1 = dsp_get_data (s);
+        d0 = dsp_get_data (s);
+
+        if (s->cmd & 8) {
+            dolog ("ADC params cmd = %#x d0 = %d, d1 = %d, d2 = %d\n",
+                   s->cmd, d0, d1, d2);
+        }
+        else {
+            ldebug ("cmd = %#x d0 = %d, d1 = %d, d2 = %d\n",
+                    s->cmd, d0, d1, d2);
+            dma_cmd (s, s->cmd, d0, d1 + (d2 << 8));
+        }
+    }
+    else {
+        switch (s->cmd) {
+        case 0x04:
+            s->csp_mode = dsp_get_data (s);
+            s->csp_reg83r = 0;
+            s->csp_reg83w = 0;
+            ldebug ("CSP command 0x04: mode=%#x\n", s->csp_mode);
+            break;
+
+        case 0x05:
+            s->csp_param = dsp_get_data (s);
+            s->csp_value = dsp_get_data (s);
+            ldebug ("CSP command 0x05: param=%#x value=%#x\n",
+                    s->csp_param,
+                    s->csp_value);
+            break;
+
+        case 0x0e:
+            d0 = dsp_get_data (s);
+            d1 = dsp_get_data (s);
+            ldebug ("write CSP register %d <- %#x\n", d1, d0);
+            if (d1 == 0x83) {
+                ldebug ("0x83[%d] <- %#x\n", s->csp_reg83r, d0);
+                s->csp_reg83[s->csp_reg83r % 4] = d0;
+                s->csp_reg83r += 1;
+            }
+            else {
+                s->csp_regs[d1] = d0;
+            }
+            break;
+
+        case 0x0f:
+            d0 = dsp_get_data (s);
+            ldebug ("read CSP register %#x -> %#x, mode=%#x\n",
+                    d0, s->csp_regs[d0], s->csp_mode);
+            if (d0 == 0x83) {
+                ldebug ("0x83[%d] -> %#x\n",
+                        s->csp_reg83w,
+                        s->csp_reg83[s->csp_reg83w % 4]);
+                dsp_out_data (s, s->csp_reg83[s->csp_reg83w % 4]);
+                s->csp_reg83w += 1;
+            }
+            else {
+                dsp_out_data (s, s->csp_regs[d0]);
+            }
+            break;
+
+        case 0x10:
+            d0 = dsp_get_data (s);
+            dolog ("cmd 0x10 d0=%#x\n", d0);
+            break;
+
+        case 0x14:
+            dma_cmd8 (s, 0, dsp_get_lohi (s) + 1);
+            break;
+
+        case 0x40:
+            s->time_const = dsp_get_data (s);
+            ldebug ("set time const %d\n", s->time_const);
+            break;
+
+        case 0x42:              /* FT2 sets output freq with this, go figure */
+#if 0
+            dolog ("cmd 0x42 might not do what it think it should\n");
+#endif
+        case 0x41:
+            s->freq = dsp_get_hilo (s);
+            ldebug ("set freq %d\n", s->freq);
+            break;
+
+        case 0x48:
+            s->block_size = dsp_get_lohi (s) + 1;
+            ldebug ("set dma block len %d\n", s->block_size);
+            break;
+
+        case 0x74:
+        case 0x75:
+        case 0x76:
+        case 0x77:
+            /* ADPCM stuff, ignore */
+            break;
+
+        case 0x80:
+            {
+                int freq, samples, bytes;
+                int64_t ticks;
+
+                freq = s->freq > 0 ? s->freq : 11025;
+                samples = dsp_get_lohi (s) + 1;
+                bytes = samples << s->fmt_stereo << (s->fmt_bits == 16);
+                ticks = muldiv64 (bytes, get_ticks_per_sec (), freq);
+                if (ticks < get_ticks_per_sec () / 1024) {
+                    qemu_irq_raise (s->pic);
+                }
+                else {
+                    if (s->aux_ts) {
+                        qemu_mod_timer (
+                            s->aux_ts,
+                            qemu_get_clock_ns (vm_clock) + ticks
+                            );
+                    }
+                }
+                ldebug ("mix silence %d %d %" PRId64 "\n", samples, bytes, ticks);
+            }
+            break;
+
+        case 0xe0:
+            d0 = dsp_get_data (s);
+            s->out_data_len = 0;
+            ldebug ("E0 data = %#x\n", d0);
+            dsp_out_data (s, ~d0);
+            break;
+
+        case 0xe2:
+#ifdef DEBUG
+            d0 = dsp_get_data (s);
+            dolog ("E2 = %#x\n", d0);
+#endif
+            break;
+
+        case 0xe4:
+            s->test_reg = dsp_get_data (s);
+            break;
+
+        case 0xf9:
+            d0 = dsp_get_data (s);
+            ldebug ("command 0xf9 with %#x\n", d0);
+            switch (d0) {
+            case 0x0e:
+                dsp_out_data (s, 0xff);
+                break;
+
+            case 0x0f:
+                dsp_out_data (s, 0x07);
+                break;
+
+            case 0x37:
+                dsp_out_data (s, 0x38);
+                break;
+
+            default:
+                dsp_out_data (s, 0x00);
+                break;
+            }
+            break;
+
+        default:
+            dolog ("complete: unrecognized command %#x\n", s->cmd);
+            return;
+        }
+    }
+
+    ldebug ("\n");
+    s->cmd = -1;
+}
+
+static void legacy_reset (SB16State *s)
+{
+    struct audsettings as;
+
+    s->freq = 11025;
+    s->fmt_signed = 0;
+    s->fmt_bits = 8;
+    s->fmt_stereo = 0;
+
+    as.freq = s->freq;
+    as.nchannels = 1;
+    as.fmt = AUD_FMT_U8;
+    as.endianness = 0;
+
+    s->voice = AUD_open_out (
+        &s->card,
+        s->voice,
+        "sb16",
+        s,
+        SB_audio_callback,
+        &as
+        );
+
+    /* Not sure about that... */
+    /* AUD_set_active_out (s->voice, 1); */
+}
+
+static void reset (SB16State *s)
+{
+    qemu_irq_lower (s->pic);
+    if (s->dma_auto) {
+        qemu_irq_raise (s->pic);
+        qemu_irq_lower (s->pic);
+    }
+
+    s->mixer_regs[0x82] = 0;
+    s->dma_auto = 0;
+    s->in_index = 0;
+    s->out_data_len = 0;
+    s->left_till_irq = 0;
+    s->needed_bytes = 0;
+    s->block_size = -1;
+    s->nzero = 0;
+    s->highspeed = 0;
+    s->v2x6 = 0;
+    s->cmd = -1;
+
+    dsp_out_data (s, 0xaa);
+    speaker (s, 0);
+    control (s, 0);
+    legacy_reset (s);
+}
+
+static IO_WRITE_PROTO (dsp_write)
+{
+    SB16State *s = opaque;
+    int iport;
+
+    iport = nport - s->port;
+
+    ldebug ("write %#x <- %#x\n", nport, val);
+    switch (iport) {
+    case 0x06:
+        switch (val) {
+        case 0x00:
+            if (s->v2x6 == 1) {
+                reset (s);
+            }
+            s->v2x6 = 0;
+            break;
+
+        case 0x01:
+        case 0x03:              /* FreeBSD kludge */
+            s->v2x6 = 1;
+            break;
+
+        case 0xc6:
+            s->v2x6 = 0;        /* Prince of Persia, csp.sys, diagnose.exe */
+            break;
+
+        case 0xb8:              /* Panic */
+            reset (s);
+            break;
+
+        case 0x39:
+            dsp_out_data (s, 0x38);
+            reset (s);
+            s->v2x6 = 0x39;
+            break;
+
+        default:
+            s->v2x6 = val;
+            break;
+        }
+        break;
+
+    case 0x0c:                  /* write data or command | write status */
+/*         if (s->highspeed) */
+/*             break; */
+
+        if (0 == s->needed_bytes) {
+            command (s, val);
+#if 0
+            if (0 == s->needed_bytes) {
+                log_dsp (s);
+            }
+#endif
+        }
+        else {
+            if (s->in_index == sizeof (s->in2_data)) {
+                dolog ("in data overrun\n");
+            }
+            else {
+                s->in2_data[s->in_index++] = val;
+                if (s->in_index == s->needed_bytes) {
+                    s->needed_bytes = 0;
+                    complete (s);
+#if 0
+                    log_dsp (s);
+#endif
+                }
+            }
+        }
+        break;
+
+    default:
+        ldebug ("(nport=%#x, val=%#x)\n", nport, val);
+        break;
+    }
+}
+
+static IO_READ_PROTO (dsp_read)
+{
+    SB16State *s = opaque;
+    int iport, retval, ack = 0;
+
+    iport = nport - s->port;
+
+    switch (iport) {
+    case 0x06:                  /* reset */
+        retval = 0xff;
+        break;
+
+    case 0x0a:                  /* read data */
+        if (s->out_data_len) {
+            retval = s->out_data[--s->out_data_len];
+            s->last_read_byte = retval;
+        }
+        else {
+            if (s->cmd != -1) {
+                dolog ("empty output buffer for command %#x\n",
+                       s->cmd);
+            }
+            retval = s->last_read_byte;
+            /* goto error; */
+        }
+        break;
+
+    case 0x0c:                  /* 0 can write */
+        retval = s->can_write ? 0 : 0x80;
+        break;
+
+    case 0x0d:                  /* timer interrupt clear */
+        /* dolog ("timer interrupt clear\n"); */
+        retval = 0;
+        break;
+
+    case 0x0e:                  /* data available status | irq 8 ack */
+        retval = (!s->out_data_len || s->highspeed) ? 0 : 0x80;
+        if (s->mixer_regs[0x82] & 1) {
+            ack = 1;
+            s->mixer_regs[0x82] &= 1;
+            qemu_irq_lower (s->pic);
+        }
+        break;
+
+    case 0x0f:                  /* irq 16 ack */
+        retval = 0xff;
+        if (s->mixer_regs[0x82] & 2) {
+            ack = 1;
+            s->mixer_regs[0x82] &= 2;
+            qemu_irq_lower (s->pic);
+        }
+        break;
+
+    default:
+        goto error;
+    }
+
+    if (!ack) {
+        ldebug ("read %#x -> %#x\n", nport, retval);
+    }
+
+    return retval;
+
+ error:
+    dolog ("warning: dsp_read %#x error\n", nport);
+    return 0xff;
+}
+
+static void reset_mixer (SB16State *s)
+{
+    int i;
+
+    memset (s->mixer_regs, 0xff, 0x7f);
+    memset (s->mixer_regs + 0x83, 0xff, sizeof (s->mixer_regs) - 0x83);
+
+    s->mixer_regs[0x02] = 4;    /* master volume 3bits */
+    s->mixer_regs[0x06] = 4;    /* MIDI volume 3bits */
+    s->mixer_regs[0x08] = 0;    /* CD volume 3bits */
+    s->mixer_regs[0x0a] = 0;    /* voice volume 2bits */
+
+    /* d5=input filt, d3=lowpass filt, d1,d2=input source */
+    s->mixer_regs[0x0c] = 0;
+
+    /* d5=output filt, d1=stereo switch */
+    s->mixer_regs[0x0e] = 0;
+
+    /* voice volume L d5,d7, R d1,d3 */
+    s->mixer_regs[0x04] = (4 << 5) | (4 << 1);
+    /* master ... */
+    s->mixer_regs[0x22] = (4 << 5) | (4 << 1);
+    /* MIDI ... */
+    s->mixer_regs[0x26] = (4 << 5) | (4 << 1);
+
+    for (i = 0x30; i < 0x48; i++) {
+        s->mixer_regs[i] = 0x20;
+    }
+}
+
+static IO_WRITE_PROTO (mixer_write_indexb)
+{
+    SB16State *s = opaque;
+    (void) nport;
+    s->mixer_nreg = val;
+}
+
+static IO_WRITE_PROTO (mixer_write_datab)
+{
+    SB16State *s = opaque;
+
+    (void) nport;
+    ldebug ("mixer_write [%#x] <- %#x\n", s->mixer_nreg, val);
+
+    switch (s->mixer_nreg) {
+    case 0x00:
+        reset_mixer (s);
+        break;
+
+    case 0x80:
+        {
+            int irq = irq_of_magic (val);
+            ldebug ("setting irq to %d (val=%#x)\n", irq, val);
+            if (irq > 0) {
+                s->irq = irq;
+            }
+        }
+        break;
+
+    case 0x81:
+        {
+            int dma, hdma;
+
+            dma = ctz32 (val & 0xf);
+            hdma = ctz32 (val & 0xf0);
+            if (dma != s->dma || hdma != s->hdma) {
+                dolog (
+                    "attempt to change DMA "
+                    "8bit %d(%d), 16bit %d(%d) (val=%#x)\n",
+                    dma, s->dma, hdma, s->hdma, val);
+            }
+#if 0
+            s->dma = dma;
+            s->hdma = hdma;
+#endif
+        }
+        break;
+
+    case 0x82:
+        dolog ("attempt to write into IRQ status register (val=%#x)\n",
+               val);
+        return;
+
+    default:
+        if (s->mixer_nreg >= 0x80) {
+            ldebug ("attempt to write mixer[%#x] <- %#x\n", s->mixer_nreg, val);
+        }
+        break;
+    }
+
+    s->mixer_regs[s->mixer_nreg] = val;
+}
+
+static IO_WRITE_PROTO (mixer_write_indexw)
+{
+    mixer_write_indexb (opaque, nport, val & 0xff);
+    mixer_write_datab (opaque, nport, (val >> 8) & 0xff);
+}
+
+static IO_READ_PROTO (mixer_read)
+{
+    SB16State *s = opaque;
+
+    (void) nport;
+#ifndef DEBUG_SB16_MOST
+    if (s->mixer_nreg != 0x82) {
+        ldebug ("mixer_read[%#x] -> %#x\n",
+                s->mixer_nreg, s->mixer_regs[s->mixer_nreg]);
+    }
+#else
+    ldebug ("mixer_read[%#x] -> %#x\n",
+            s->mixer_nreg, s->mixer_regs[s->mixer_nreg]);
+#endif
+    return s->mixer_regs[s->mixer_nreg];
+}
+
+static int write_audio (SB16State *s, int nchan, int dma_pos,
+                        int dma_len, int len)
+{
+    int temp, net;
+    uint8_t tmpbuf[4096];
+
+    temp = len;
+    net = 0;
+
+    while (temp) {
+        int left = dma_len - dma_pos;
+        int copied;
+        size_t to_copy;
+
+        to_copy = audio_MIN (temp, left);
+        if (to_copy > sizeof (tmpbuf)) {
+            to_copy = sizeof (tmpbuf);
+        }
+
+        copied = DMA_read_memory (nchan, tmpbuf, dma_pos, to_copy);
+        copied = AUD_write (s->voice, tmpbuf, copied);
+
+        temp -= copied;
+        dma_pos = (dma_pos + copied) % dma_len;
+        net += copied;
+
+        if (!copied) {
+            break;
+        }
+    }
+
+    return net;
+}
+
+static int SB_read_DMA (void *opaque, int nchan, int dma_pos, int dma_len)
+{
+    SB16State *s = opaque;
+    int till, copy, written, free;
+
+    if (s->block_size <= 0) {
+        dolog ("invalid block size=%d nchan=%d dma_pos=%d dma_len=%d\n",
+               s->block_size, nchan, dma_pos, dma_len);
+        return dma_pos;
+    }
+
+    if (s->left_till_irq < 0) {
+        s->left_till_irq = s->block_size;
+    }
+
+    if (s->voice) {
+        free = s->audio_free & ~s->align;
+        if ((free <= 0) || !dma_len) {
+            return dma_pos;
+        }
+    }
+    else {
+        free = dma_len;
+    }
+
+    copy = free;
+    till = s->left_till_irq;
+
+#ifdef DEBUG_SB16_MOST
+    dolog ("pos:%06d %d till:%d len:%d\n",
+           dma_pos, free, till, dma_len);
+#endif
+
+    if (till <= copy) {
+        if (0 == s->dma_auto) {
+            copy = till;
+        }
+    }
+
+    written = write_audio (s, nchan, dma_pos, dma_len, copy);
+    dma_pos = (dma_pos + written) % dma_len;
+    s->left_till_irq -= written;
+
+    if (s->left_till_irq <= 0) {
+        s->mixer_regs[0x82] |= (nchan & 4) ? 2 : 1;
+        qemu_irq_raise (s->pic);
+        if (0 == s->dma_auto) {
+            control (s, 0);
+            speaker (s, 0);
+        }
+    }
+
+#ifdef DEBUG_SB16_MOST
+    ldebug ("pos %5d free %5d size %5d till % 5d copy %5d written %5d size %5d\n",
+            dma_pos, free, dma_len, s->left_till_irq, copy, written,
+            s->block_size);
+#endif
+
+    while (s->left_till_irq <= 0) {
+        s->left_till_irq = s->block_size + s->left_till_irq;
+    }
+
+    return dma_pos;
+}
+
+static void SB_audio_callback (void *opaque, int free)
+{
+    SB16State *s = opaque;
+    s->audio_free = free;
+}
+
+static int sb16_post_load (void *opaque, int version_id)
+{
+    SB16State *s = opaque;
+
+    if (s->voice) {
+        AUD_close_out (&s->card, s->voice);
+        s->voice = NULL;
+    }
+
+    if (s->dma_running) {
+        if (s->freq) {
+            struct audsettings as;
+
+            s->audio_free = 0;
+
+            as.freq = s->freq;
+            as.nchannels = 1 << s->fmt_stereo;
+            as.fmt = s->fmt;
+            as.endianness = 0;
+
+            s->voice = AUD_open_out (
+                &s->card,
+                s->voice,
+                "sb16",
+                s,
+                SB_audio_callback,
+                &as
+                );
+        }
+
+        control (s, 1);
+        speaker (s, s->speaker);
+    }
+    return 0;
+}
+
+static const VMStateDescription vmstate_sb16 = {
+    .name = "sb16",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .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 ()
+    }
+};
+
+static const MemoryRegionPortio sb16_ioport_list[] = {
+    {  4, 1, 1, .write = mixer_write_indexb },
+    {  4, 1, 2, .write = mixer_write_indexw },
+    {  5, 1, 1, .read = mixer_read, .write = mixer_write_datab },
+    {  6, 1, 1, .read = dsp_read, .write = dsp_write },
+    { 10, 1, 1, .read = dsp_read },
+    { 12, 1, 1, .write = dsp_write },
+    { 12, 4, 1, .read = dsp_read },
+    PORTIO_END_OF_LIST (),
+};
+
+
+static int sb16_initfn (ISADevice *dev)
+{
+    SB16State *s;
+
+    s = DO_UPCAST (SB16State, dev, dev);
+
+    s->cmd = -1;
+    isa_init_irq (dev, &s->pic, s->irq);
+
+    s->mixer_regs[0x80] = magic_of_irq (s->irq);
+    s->mixer_regs[0x81] = (1 << s->dma) | (1 << s->hdma);
+    s->mixer_regs[0x82] = 2 << 5;
+
+    s->csp_regs[5] = 1;
+    s->csp_regs[9] = 0xf8;
+
+    reset_mixer (s);
+    s->aux_ts = qemu_new_timer_ns (vm_clock, aux_timer, s);
+    if (!s->aux_ts) {
+        dolog ("warning: Could not create auxiliary timer\n");
+    }
+
+    isa_register_portio_list (dev, s->port, sb16_ioport_list, s, "sb16");
+
+    DMA_register_channel (s->hdma, SB_read_DMA, s);
+    DMA_register_channel (s->dma, SB_read_DMA, s);
+    s->can_write = 1;
+
+    AUD_register_card ("sb16", &s->card);
+    return 0;
+}
+
+int SB16_init (ISABus *bus)
+{
+    isa_create_simple (bus, "sb16");
+    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 const TypeInfo sb16_info = {
+    .name          = "sb16",
+    .parent        = TYPE_ISA_DEVICE,
+    .instance_size = sizeof (SB16State),
+    .class_init    = sb16_class_initfn,
+};
+
+static void sb16_register_types (void)
+{
+    type_register_static (&sb16_info);
+}
+
+type_init (sb16_register_types)
diff --git a/hw/audio/wm8750.c b/hw/audio/wm8750.c
new file mode 100644 (file)
index 0000000..6b5a349
--- /dev/null
@@ -0,0 +1,716 @@
+/*
+ * WM8750 audio CODEC.
+ *
+ * Copyright (c) 2006 Openedhand Ltd.
+ * Written by Andrzej Zaborowski <balrog@zabor.org>
+ *
+ * This file is licensed under GNU GPL.
+ */
+
+#include "hw/hw.h"
+#include "hw/i2c/i2c.h"
+#include "audio/audio.h"
+
+#define IN_PORT_N      3
+#define OUT_PORT_N     3
+
+#define CODEC          "wm8750"
+
+typedef struct {
+    int adc;
+    int adc_hz;
+    int dac;
+    int dac_hz;
+} WMRate;
+
+typedef struct {
+    I2CSlave i2c;
+    uint8_t i2c_data[2];
+    int i2c_len;
+    QEMUSoundCard card;
+    SWVoiceIn *adc_voice[IN_PORT_N];
+    SWVoiceOut *dac_voice[OUT_PORT_N];
+    int enable;
+    void (*data_req)(void *, int, int);
+    void *opaque;
+    uint8_t data_in[4096];
+    uint8_t data_out[4096];
+    int idx_in, req_in;
+    int idx_out, req_out;
+
+    SWVoiceOut **out[2];
+    uint8_t outvol[7], outmute[2];
+    SWVoiceIn **in[2];
+    uint8_t invol[4], inmute[2];
+
+    uint8_t diff[2], pol, ds, monomix[2], alc, mute;
+    uint8_t path[4], mpath[2], power, format;
+    const WMRate *rate;
+    uint8_t rate_vmstate;
+    int adc_hz, dac_hz, ext_adc_hz, ext_dac_hz, master;
+} WM8750State;
+
+/* pow(10.0, -i / 20.0) * 255, i = 0..42 */
+static const uint8_t wm8750_vol_db_table[] = {
+    255, 227, 203, 181, 161, 143, 128, 114, 102, 90, 81, 72, 64, 57, 51, 45,
+    40, 36, 32, 29, 26, 23, 20, 18, 16, 14, 13, 11, 10, 9, 8, 7, 6, 6, 5, 5,
+    4, 4, 3, 3, 3, 2, 2
+};
+
+#define WM8750_OUTVOL_TRANSFORM(x)     wm8750_vol_db_table[(0x7f - x) / 3]
+#define WM8750_INVOL_TRANSFORM(x)      (x << 2)
+
+static inline void wm8750_in_load(WM8750State *s)
+{
+    if (s->idx_in + s->req_in <= sizeof(s->data_in))
+        return;
+    s->idx_in = audio_MAX(0, (int) sizeof(s->data_in) - s->req_in);
+    AUD_read(*s->in[0], s->data_in + s->idx_in,
+             sizeof(s->data_in) - s->idx_in);
+}
+
+static inline void wm8750_out_flush(WM8750State *s)
+{
+    int sent = 0;
+    while (sent < s->idx_out)
+        sent += AUD_write(*s->out[0], s->data_out + sent, s->idx_out - sent)
+                ?: s->idx_out;
+    s->idx_out = 0;
+}
+
+static void wm8750_audio_in_cb(void *opaque, int avail_b)
+{
+    WM8750State *s = (WM8750State *) opaque;
+    s->req_in = avail_b;
+    s->data_req(s->opaque, s->req_out >> 2, avail_b >> 2);
+}
+
+static void wm8750_audio_out_cb(void *opaque, int free_b)
+{
+    WM8750State *s = (WM8750State *) opaque;
+
+    if (s->idx_out >= free_b) {
+        s->idx_out = free_b;
+        s->req_out = 0;
+        wm8750_out_flush(s);
+    } else
+        s->req_out = free_b - s->idx_out;
+    s->data_req(s->opaque, s->req_out >> 2, s->req_in >> 2);
+}
+
+static const WMRate wm_rate_table[] = {
+    {  256, 48000,  256, 48000 },      /* SR: 00000 */
+    {  384, 48000,  384, 48000 },      /* SR: 00001 */
+    {  256, 48000, 1536,  8000 },      /* SR: 00010 */
+    {  384, 48000, 2304,  8000 },      /* SR: 00011 */
+    { 1536,  8000,  256, 48000 },      /* SR: 00100 */
+    { 2304,  8000,  384, 48000 },      /* SR: 00101 */
+    { 1536,  8000, 1536,  8000 },      /* SR: 00110 */
+    { 2304,  8000, 2304,  8000 },      /* SR: 00111 */
+    { 1024, 12000, 1024, 12000 },      /* SR: 01000 */
+    { 1526, 12000, 1536, 12000 },      /* SR: 01001 */
+    {  768, 16000,  768, 16000 },      /* SR: 01010 */
+    { 1152, 16000, 1152, 16000 },      /* SR: 01011 */
+    {  384, 32000,  384, 32000 },      /* SR: 01100 */
+    {  576, 32000,  576, 32000 },      /* SR: 01101 */
+    {  128, 96000,  128, 96000 },      /* SR: 01110 */
+    {  192, 96000,  192, 96000 },      /* SR: 01111 */
+    {  256, 44100,  256, 44100 },      /* SR: 10000 */
+    {  384, 44100,  384, 44100 },      /* SR: 10001 */
+    {  256, 44100, 1408,  8018 },      /* SR: 10010 */
+    {  384, 44100, 2112,  8018 },      /* SR: 10011 */
+    { 1408,  8018,  256, 44100 },      /* SR: 10100 */
+    { 2112,  8018,  384, 44100 },      /* SR: 10101 */
+    { 1408,  8018, 1408,  8018 },      /* SR: 10110 */
+    { 2112,  8018, 2112,  8018 },      /* SR: 10111 */
+    { 1024, 11025, 1024, 11025 },      /* SR: 11000 */
+    { 1536, 11025, 1536, 11025 },      /* SR: 11001 */
+    {  512, 22050,  512, 22050 },      /* SR: 11010 */
+    {  768, 22050,  768, 22050 },      /* SR: 11011 */
+    {  512, 24000,  512, 24000 },      /* SR: 11100 */
+    {  768, 24000,  768, 24000 },      /* SR: 11101 */
+    {  128, 88200,  128, 88200 },      /* SR: 11110 */
+    {  192, 88200,  192, 88200 },      /* SR: 11111 */
+};
+
+static void wm8750_vol_update(WM8750State *s)
+{
+    /* FIXME: multiply all volumes by s->invol[2], s->invol[3] */
+
+    AUD_set_volume_in(s->adc_voice[0], s->mute,
+                    s->inmute[0] ? 0 : WM8750_INVOL_TRANSFORM(s->invol[0]),
+                    s->inmute[1] ? 0 : WM8750_INVOL_TRANSFORM(s->invol[1]));
+    AUD_set_volume_in(s->adc_voice[1], s->mute,
+                    s->inmute[0] ? 0 : WM8750_INVOL_TRANSFORM(s->invol[0]),
+                    s->inmute[1] ? 0 : WM8750_INVOL_TRANSFORM(s->invol[1]));
+    AUD_set_volume_in(s->adc_voice[2], s->mute,
+                    s->inmute[0] ? 0 : WM8750_INVOL_TRANSFORM(s->invol[0]),
+                    s->inmute[1] ? 0 : WM8750_INVOL_TRANSFORM(s->invol[1]));
+
+    /* FIXME: multiply all volumes by s->outvol[0], s->outvol[1] */
+
+    /* Speaker: LOUT2VOL ROUT2VOL */
+    AUD_set_volume_out(s->dac_voice[0], s->mute,
+                    s->outmute[0] ? 0 : WM8750_OUTVOL_TRANSFORM(s->outvol[4]),
+                    s->outmute[1] ? 0 : WM8750_OUTVOL_TRANSFORM(s->outvol[5]));
+
+    /* Headphone: LOUT1VOL ROUT1VOL */
+    AUD_set_volume_out(s->dac_voice[1], s->mute,
+                    s->outmute[0] ? 0 : WM8750_OUTVOL_TRANSFORM(s->outvol[2]),
+                    s->outmute[1] ? 0 : WM8750_OUTVOL_TRANSFORM(s->outvol[3]));
+
+    /* MONOOUT: MONOVOL MONOVOL */
+    AUD_set_volume_out(s->dac_voice[2], s->mute,
+                    s->outmute[0] ? 0 : WM8750_OUTVOL_TRANSFORM(s->outvol[6]),
+                    s->outmute[1] ? 0 : WM8750_OUTVOL_TRANSFORM(s->outvol[6]));
+}
+
+static void wm8750_set_format(WM8750State *s)
+{
+    int i;
+    struct audsettings in_fmt;
+    struct audsettings out_fmt;
+
+    wm8750_out_flush(s);
+
+    if (s->in[0] && *s->in[0])
+        AUD_set_active_in(*s->in[0], 0);
+    if (s->out[0] && *s->out[0])
+        AUD_set_active_out(*s->out[0], 0);
+
+    for (i = 0; i < IN_PORT_N; i ++)
+        if (s->adc_voice[i]) {
+            AUD_close_in(&s->card, s->adc_voice[i]);
+            s->adc_voice[i] = NULL;
+        }
+    for (i = 0; i < OUT_PORT_N; i ++)
+        if (s->dac_voice[i]) {
+            AUD_close_out(&s->card, s->dac_voice[i]);
+            s->dac_voice[i] = NULL;
+        }
+
+    if (!s->enable)
+        return;
+
+    /* Setup input */
+    in_fmt.endianness = 0;
+    in_fmt.nchannels = 2;
+    in_fmt.freq = s->adc_hz;
+    in_fmt.fmt = AUD_FMT_S16;
+
+    s->adc_voice[0] = AUD_open_in(&s->card, s->adc_voice[0],
+                    CODEC ".input1", s, wm8750_audio_in_cb, &in_fmt);
+    s->adc_voice[1] = AUD_open_in(&s->card, s->adc_voice[1],
+                    CODEC ".input2", s, wm8750_audio_in_cb, &in_fmt);
+    s->adc_voice[2] = AUD_open_in(&s->card, s->adc_voice[2],
+                    CODEC ".input3", s, wm8750_audio_in_cb, &in_fmt);
+
+    /* Setup output */
+    out_fmt.endianness = 0;
+    out_fmt.nchannels = 2;
+    out_fmt.freq = s->dac_hz;
+    out_fmt.fmt = AUD_FMT_S16;
+
+    s->dac_voice[0] = AUD_open_out(&s->card, s->dac_voice[0],
+                    CODEC ".speaker", s, wm8750_audio_out_cb, &out_fmt);
+    s->dac_voice[1] = AUD_open_out(&s->card, s->dac_voice[1],
+                    CODEC ".headphone", s, wm8750_audio_out_cb, &out_fmt);
+    /* MONOMIX is also in stereo for simplicity */
+    s->dac_voice[2] = AUD_open_out(&s->card, s->dac_voice[2],
+                    CODEC ".monomix", s, wm8750_audio_out_cb, &out_fmt);
+    /* no sense emulating OUT3 which is a mix of other outputs */
+
+    wm8750_vol_update(s);
+
+    /* We should connect the left and right channels to their
+     * respective inputs/outputs but we have completely no need
+     * for mixing or combining paths to different ports, so we
+     * connect both channels to where the left channel is routed.  */
+    if (s->in[0] && *s->in[0])
+        AUD_set_active_in(*s->in[0], 1);
+    if (s->out[0] && *s->out[0])
+        AUD_set_active_out(*s->out[0], 1);
+}
+
+static void wm8750_clk_update(WM8750State *s, int ext)
+{
+    if (s->master || !s->ext_dac_hz)
+        s->dac_hz = s->rate->dac_hz;
+    else
+        s->dac_hz = s->ext_dac_hz;
+
+    if (s->master || !s->ext_adc_hz)
+        s->adc_hz = s->rate->adc_hz;
+    else
+        s->adc_hz = s->ext_adc_hz;
+
+    if (s->master || (!s->ext_dac_hz && !s->ext_adc_hz)) {
+        if (!ext)
+            wm8750_set_format(s);
+    } else {
+        if (ext)
+            wm8750_set_format(s);
+    }
+}
+
+static void wm8750_reset(I2CSlave *i2c)
+{
+    WM8750State *s = (WM8750State *) i2c;
+    s->rate = &wm_rate_table[0];
+    s->enable = 0;
+    wm8750_clk_update(s, 1);
+    s->diff[0] = 0;
+    s->diff[1] = 0;
+    s->ds = 0;
+    s->alc = 0;
+    s->in[0] = &s->adc_voice[0];
+    s->invol[0] = 0x17;
+    s->invol[1] = 0x17;
+    s->invol[2] = 0xc3;
+    s->invol[3] = 0xc3;
+    s->out[0] = &s->dac_voice[0];
+    s->outvol[0] = 0xff;
+    s->outvol[1] = 0xff;
+    s->outvol[2] = 0x79;
+    s->outvol[3] = 0x79;
+    s->outvol[4] = 0x79;
+    s->outvol[5] = 0x79;
+    s->outvol[6] = 0x79;
+    s->inmute[0] = 0;
+    s->inmute[1] = 0;
+    s->outmute[0] = 0;
+    s->outmute[1] = 0;
+    s->mute = 1;
+    s->path[0] = 0;
+    s->path[1] = 0;
+    s->path[2] = 0;
+    s->path[3] = 0;
+    s->mpath[0] = 0;
+    s->mpath[1] = 0;
+    s->format = 0x0a;
+    s->idx_in = sizeof(s->data_in);
+    s->req_in = 0;
+    s->idx_out = 0;
+    s->req_out = 0;
+    wm8750_vol_update(s);
+    s->i2c_len = 0;
+}
+
+static void wm8750_event(I2CSlave *i2c, enum i2c_event event)
+{
+    WM8750State *s = (WM8750State *) i2c;
+
+    switch (event) {
+    case I2C_START_SEND:
+        s->i2c_len = 0;
+        break;
+    case I2C_FINISH:
+#ifdef VERBOSE
+        if (s->i2c_len < 2)
+            printf("%s: message too short (%i bytes)\n",
+                            __FUNCTION__, s->i2c_len);
+#endif
+        break;
+    default:
+        break;
+    }
+}
+
+#define WM8750_LINVOL  0x00
+#define WM8750_RINVOL  0x01
+#define WM8750_LOUT1V  0x02
+#define WM8750_ROUT1V  0x03
+#define WM8750_ADCDAC  0x05
+#define WM8750_IFACE   0x07
+#define WM8750_SRATE   0x08
+#define WM8750_LDAC    0x0a
+#define WM8750_RDAC    0x0b
+#define WM8750_BASS    0x0c
+#define WM8750_TREBLE  0x0d
+#define WM8750_RESET   0x0f
+#define WM8750_3D      0x10
+#define WM8750_ALC1    0x11
+#define WM8750_ALC2    0x12
+#define WM8750_ALC3    0x13
+#define WM8750_NGATE   0x14
+#define WM8750_LADC    0x15
+#define WM8750_RADC    0x16
+#define WM8750_ADCTL1  0x17
+#define WM8750_ADCTL2  0x18
+#define WM8750_PWR1    0x19
+#define WM8750_PWR2    0x1a
+#define WM8750_ADCTL3  0x1b
+#define WM8750_ADCIN   0x1f
+#define WM8750_LADCIN  0x20
+#define WM8750_RADCIN  0x21
+#define WM8750_LOUTM1  0x22
+#define WM8750_LOUTM2  0x23
+#define WM8750_ROUTM1  0x24
+#define WM8750_ROUTM2  0x25
+#define WM8750_MOUTM1  0x26
+#define WM8750_MOUTM2  0x27
+#define WM8750_LOUT2V  0x28
+#define WM8750_ROUT2V  0x29
+#define WM8750_MOUTV   0x2a
+
+static int wm8750_tx(I2CSlave *i2c, uint8_t data)
+{
+    WM8750State *s = (WM8750State *) i2c;
+    uint8_t cmd;
+    uint16_t value;
+
+    if (s->i2c_len >= 2) {
+#ifdef VERBOSE
+        printf("%s: long message (%i bytes)\n", __func__, s->i2c_len);
+#endif
+        return 1;
+    }
+    s->i2c_data[s->i2c_len ++] = data;
+    if (s->i2c_len != 2)
+        return 0;
+
+    cmd = s->i2c_data[0] >> 1;
+    value = ((s->i2c_data[0] << 8) | s->i2c_data[1]) & 0x1ff;
+
+    switch (cmd) {
+    case WM8750_LADCIN:        /* ADC Signal Path Control (Left) */
+        s->diff[0] = (((value >> 6) & 3) == 3);        /* LINSEL */
+        if (s->diff[0])
+            s->in[0] = &s->adc_voice[0 + s->ds * 1];
+        else
+            s->in[0] = &s->adc_voice[((value >> 6) & 3) * 1 + 0];
+        break;
+
+    case WM8750_RADCIN:        /* ADC Signal Path Control (Right) */
+        s->diff[1] = (((value >> 6) & 3) == 3);        /* RINSEL */
+        if (s->diff[1])
+            s->in[1] = &s->adc_voice[0 + s->ds * 1];
+        else
+            s->in[1] = &s->adc_voice[((value >> 6) & 3) * 1 + 0];
+        break;
+
+    case WM8750_ADCIN: /* ADC Input Mode */
+        s->ds = (value >> 8) & 1;      /* DS */
+        if (s->diff[0])
+            s->in[0] = &s->adc_voice[0 + s->ds * 1];
+        if (s->diff[1])
+            s->in[1] = &s->adc_voice[0 + s->ds * 1];
+        s->monomix[0] = (value >> 6) & 3;      /* MONOMIX */
+        break;
+
+    case WM8750_ADCTL1:        /* Additional Control (1) */
+        s->monomix[1] = (value >> 1) & 1;      /* DMONOMIX */
+        break;
+
+    case WM8750_PWR1:  /* Power Management (1) */
+        s->enable = ((value >> 6) & 7) == 3;   /* VMIDSEL, VREF */
+        wm8750_set_format(s);
+        break;
+
+    case WM8750_LINVOL:        /* Left Channel PGA */
+        s->invol[0] = value & 0x3f;            /* LINVOL */
+        s->inmute[0] = (value >> 7) & 1;       /* LINMUTE */
+        wm8750_vol_update(s);
+        break;
+
+    case WM8750_RINVOL:        /* Right Channel PGA */
+        s->invol[1] = value & 0x3f;            /* RINVOL */
+        s->inmute[1] = (value >> 7) & 1;       /* RINMUTE */
+        wm8750_vol_update(s);
+        break;
+
+    case WM8750_ADCDAC:        /* ADC and DAC Control */
+        s->pol = (value >> 5) & 3;             /* ADCPOL */
+        s->mute = (value >> 3) & 1;            /* DACMU */
+        wm8750_vol_update(s);
+        break;
+
+    case WM8750_ADCTL3:        /* Additional Control (3) */
+        break;
+
+    case WM8750_LADC:  /* Left ADC Digital Volume */
+        s->invol[2] = value & 0xff;            /* LADCVOL */
+        wm8750_vol_update(s);
+        break;
+
+    case WM8750_RADC:  /* Right ADC Digital Volume */
+        s->invol[3] = value & 0xff;            /* RADCVOL */
+        wm8750_vol_update(s);
+        break;
+
+    case WM8750_ALC1:  /* ALC Control (1) */
+        s->alc = (value >> 7) & 3;             /* ALCSEL */
+        break;
+
+    case WM8750_NGATE: /* Noise Gate Control */
+    case WM8750_3D:    /* 3D enhance */
+        break;
+
+    case WM8750_LDAC:  /* Left Channel Digital Volume */
+        s->outvol[0] = value & 0xff;           /* LDACVOL */
+        wm8750_vol_update(s);
+        break;
+
+    case WM8750_RDAC:  /* Right Channel Digital Volume */
+        s->outvol[1] = value & 0xff;           /* RDACVOL */
+        wm8750_vol_update(s);
+        break;
+
+    case WM8750_BASS:  /* Bass Control */
+        break;
+
+    case WM8750_LOUTM1:        /* Left Mixer Control (1) */
+        s->path[0] = (value >> 8) & 1;         /* LD2LO */
+        /* TODO: mute/unmute respective paths */
+        wm8750_vol_update(s);
+        break;
+
+    case WM8750_LOUTM2:        /* Left Mixer Control (2) */
+        s->path[1] = (value >> 8) & 1;         /* RD2LO */
+        /* TODO: mute/unmute respective paths */
+        wm8750_vol_update(s);
+        break;
+
+    case WM8750_ROUTM1:        /* Right Mixer Control (1) */
+        s->path[2] = (value >> 8) & 1;         /* LD2RO */
+        /* TODO: mute/unmute respective paths */
+        wm8750_vol_update(s);
+        break;
+
+    case WM8750_ROUTM2:        /* Right Mixer Control (2) */
+        s->path[3] = (value >> 8) & 1;         /* RD2RO */
+        /* TODO: mute/unmute respective paths */
+        wm8750_vol_update(s);
+        break;
+
+    case WM8750_MOUTM1:        /* Mono Mixer Control (1) */
+        s->mpath[0] = (value >> 8) & 1;                /* LD2MO */
+        /* TODO: mute/unmute respective paths */
+        wm8750_vol_update(s);
+        break;
+
+    case WM8750_MOUTM2:        /* Mono Mixer Control (2) */
+        s->mpath[1] = (value >> 8) & 1;                /* RD2MO */
+        /* TODO: mute/unmute respective paths */
+        wm8750_vol_update(s);
+        break;
+
+    case WM8750_LOUT1V:        /* LOUT1 Volume */
+        s->outvol[2] = value & 0x7f;           /* LOUT1VOL */
+        wm8750_vol_update(s);
+        break;
+
+    case WM8750_LOUT2V:        /* LOUT2 Volume */
+        s->outvol[4] = value & 0x7f;           /* LOUT2VOL */
+        wm8750_vol_update(s);
+        break;
+
+    case WM8750_ROUT1V:        /* ROUT1 Volume */
+        s->outvol[3] = value & 0x7f;           /* ROUT1VOL */
+        wm8750_vol_update(s);
+        break;
+
+    case WM8750_ROUT2V:        /* ROUT2 Volume */
+        s->outvol[5] = value & 0x7f;           /* ROUT2VOL */
+        wm8750_vol_update(s);
+        break;
+
+    case WM8750_MOUTV: /* MONOOUT Volume */
+        s->outvol[6] = value & 0x7f;           /* MONOOUTVOL */
+        wm8750_vol_update(s);
+        break;
+
+    case WM8750_ADCTL2:        /* Additional Control (2) */
+        break;
+
+    case WM8750_PWR2:  /* Power Management (2) */
+        s->power = value & 0x7e;
+        /* TODO: mute/unmute respective paths */
+        wm8750_vol_update(s);
+        break;
+
+    case WM8750_IFACE: /* Digital Audio Interface Format */
+        s->format = value;
+        s->master = (value >> 6) & 1;                  /* MS */
+        wm8750_clk_update(s, s->master);
+        break;
+
+    case WM8750_SRATE: /* Clocking and Sample Rate Control */
+        s->rate = &wm_rate_table[(value >> 1) & 0x1f];
+        wm8750_clk_update(s, 0);
+        break;
+
+    case WM8750_RESET: /* Reset */
+        wm8750_reset(&s->i2c);
+        break;
+
+#ifdef VERBOSE
+    default:
+        printf("%s: unknown register %02x\n", __FUNCTION__, cmd);
+#endif
+    }
+
+    return 0;
+}
+
+static int wm8750_rx(I2CSlave *i2c)
+{
+    return 0x00;
+}
+
+static void wm8750_pre_save(void *opaque)
+{
+    WM8750State *s = opaque;
+
+    s->rate_vmstate = s->rate - wm_rate_table;
+}
+
+static int wm8750_post_load(void *opaque, int version_id)
+{
+    WM8750State *s = opaque;
+
+    s->rate = &wm_rate_table[s->rate_vmstate & 0x1f];
+    return 0;
+}
+
+static const VMStateDescription vmstate_wm8750 = {
+    .name = CODEC,
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .pre_save = wm8750_pre_save,
+    .post_load = wm8750_post_load,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT8_ARRAY(i2c_data, WM8750State, 2),
+        VMSTATE_INT32(i2c_len, WM8750State),
+        VMSTATE_INT32(enable, WM8750State),
+        VMSTATE_INT32(idx_in, WM8750State),
+        VMSTATE_INT32(req_in, WM8750State),
+        VMSTATE_INT32(idx_out, WM8750State),
+        VMSTATE_INT32(req_out, WM8750State),
+        VMSTATE_UINT8_ARRAY(outvol, WM8750State, 7),
+        VMSTATE_UINT8_ARRAY(outmute, WM8750State, 2),
+        VMSTATE_UINT8_ARRAY(invol, WM8750State, 4),
+        VMSTATE_UINT8_ARRAY(inmute, WM8750State, 2),
+        VMSTATE_UINT8_ARRAY(diff, WM8750State, 2),
+        VMSTATE_UINT8(pol, WM8750State),
+        VMSTATE_UINT8(ds, WM8750State),
+        VMSTATE_UINT8_ARRAY(monomix, WM8750State, 2),
+        VMSTATE_UINT8(alc, WM8750State),
+        VMSTATE_UINT8(mute, WM8750State),
+        VMSTATE_UINT8_ARRAY(path, WM8750State, 4),
+        VMSTATE_UINT8_ARRAY(mpath, WM8750State, 2),
+        VMSTATE_UINT8(format, WM8750State),
+        VMSTATE_UINT8(power, WM8750State),
+        VMSTATE_UINT8(rate_vmstate, WM8750State),
+        VMSTATE_I2C_SLAVE(i2c, WM8750State),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int wm8750_init(I2CSlave *i2c)
+{
+    WM8750State *s = FROM_I2C_SLAVE(WM8750State, i2c);
+
+    AUD_register_card(CODEC, &s->card);
+    wm8750_reset(&s->i2c);
+
+    return 0;
+}
+
+#if 0
+static void wm8750_fini(I2CSlave *i2c)
+{
+    WM8750State *s = (WM8750State *) i2c;
+    wm8750_reset(&s->i2c);
+    AUD_remove_card(&s->card);
+    g_free(s);
+}
+#endif
+
+void wm8750_data_req_set(DeviceState *dev,
+                void (*data_req)(void *, int, int), void *opaque)
+{
+    WM8750State *s = FROM_I2C_SLAVE(WM8750State, I2C_SLAVE(dev));
+    s->data_req = data_req;
+    s->opaque = opaque;
+}
+
+void wm8750_dac_dat(void *opaque, uint32_t sample)
+{
+    WM8750State *s = (WM8750State *) opaque;
+
+    *(uint32_t *) &s->data_out[s->idx_out] = sample;
+    s->req_out -= 4;
+    s->idx_out += 4;
+    if (s->idx_out >= sizeof(s->data_out) || s->req_out <= 0)
+        wm8750_out_flush(s);
+}
+
+void *wm8750_dac_buffer(void *opaque, int samples)
+{
+    WM8750State *s = (WM8750State *) opaque;
+    /* XXX: Should check if there are <i>samples</i> free samples available */
+    void *ret = s->data_out + s->idx_out;
+
+    s->idx_out += samples << 2;
+    s->req_out -= samples << 2;
+    return ret;
+}
+
+void wm8750_dac_commit(void *opaque)
+{
+    WM8750State *s = (WM8750State *) opaque;
+
+    wm8750_out_flush(s);
+}
+
+uint32_t wm8750_adc_dat(void *opaque)
+{
+    WM8750State *s = (WM8750State *) opaque;
+    uint32_t *data;
+
+    if (s->idx_in >= sizeof(s->data_in))
+        wm8750_in_load(s);
+
+    data = (uint32_t *) &s->data_in[s->idx_in];
+    s->req_in -= 4;
+    s->idx_in += 4;
+    return *data;
+}
+
+void wm8750_set_bclk_in(void *opaque, int new_hz)
+{
+    WM8750State *s = (WM8750State *) opaque;
+
+    s->ext_adc_hz = new_hz;
+    s->ext_dac_hz = new_hz;
+    wm8750_clk_update(s, 1);
+}
+
+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 const TypeInfo wm8750_info = {
+    .name          = "wm8750",
+    .parent        = TYPE_I2C_SLAVE,
+    .instance_size = sizeof(WM8750State),
+    .class_init    = wm8750_class_init,
+};
+
+static void wm8750_register_types(void)
+{
+    type_register_static(&wm8750_info);
+}
+
+type_init(wm8750_register_types)
diff --git a/hw/audiodev.h b/hw/audiodev.h
deleted file mode 100644 (file)
index 428274f..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-#ifndef HW_AUDIODEV_H
-#define HW_AUDIODEV_H 1
-
-/* es1370.c */
-int es1370_init(PCIBus *bus);
-
-/* sb16.c */
-int SB16_init(ISABus *bus);
-
-/* adlib.c */
-int Adlib_init(ISABus *bus);
-
-/* gus.c */
-int GUS_init(ISABus *bus);
-
-/* ac97.c */
-int ac97_init(PCIBus *bus);
-
-/* cs4231a.c */
-int cs4231a_init(ISABus *bus);
-
-/* intel-hda.c + hda-audio.c */
-int intel_hda_and_codec_init(PCIBus *bus);
-
-#endif
diff --git a/hw/bitbang_i2c.c b/hw/bitbang_i2c.c
deleted file mode 100644 (file)
index b8e6d3a..0000000
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- * Bit-Bang i2c emulation extracted from
- * Marvell MV88W8618 / Freecom MusicPal emulation.
- *
- * 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/hw.h"
-#include "hw/bitbang_i2c.h"
-#include "hw/sysbus.h"
-
-//#define DEBUG_BITBANG_I2C
-
-#ifdef DEBUG_BITBANG_I2C
-#define DPRINTF(fmt, ...) \
-do { printf("bitbang_i2c: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...) do {} while(0)
-#endif
-
-typedef enum bitbang_i2c_state {
-    STOPPED = 0,
-    SENDING_BIT7,
-    SENDING_BIT6,
-    SENDING_BIT5,
-    SENDING_BIT4,
-    SENDING_BIT3,
-    SENDING_BIT2,
-    SENDING_BIT1,
-    SENDING_BIT0,
-    WAITING_FOR_ACK,
-    RECEIVING_BIT7,
-    RECEIVING_BIT6,
-    RECEIVING_BIT5,
-    RECEIVING_BIT4,
-    RECEIVING_BIT3,
-    RECEIVING_BIT2,
-    RECEIVING_BIT1,
-    RECEIVING_BIT0,
-    SENDING_ACK,
-    SENT_NACK
-} bitbang_i2c_state;
-
-struct bitbang_i2c_interface {
-    i2c_bus *bus;
-    bitbang_i2c_state state;
-    int last_data;
-    int last_clock;
-    int device_out;
-    uint8_t buffer;
-    int current_addr;
-};
-
-static void bitbang_i2c_enter_stop(bitbang_i2c_interface *i2c)
-{
-    DPRINTF("STOP\n");
-    if (i2c->current_addr >= 0)
-        i2c_end_transfer(i2c->bus);
-    i2c->current_addr = -1;
-    i2c->state = STOPPED;
-}
-
-/* Set device data pin.  */
-static int bitbang_i2c_ret(bitbang_i2c_interface *i2c, int level)
-{
-    i2c->device_out = level;
-    //DPRINTF("%d %d %d\n", i2c->last_clock, i2c->last_data, i2c->device_out);
-    return level & i2c->last_data;
-}
-
-/* Leave device data pin unodified.  */
-static int bitbang_i2c_nop(bitbang_i2c_interface *i2c)
-{
-    return bitbang_i2c_ret(i2c, i2c->device_out);
-}
-
-/* Returns data line level.  */
-int bitbang_i2c_set(bitbang_i2c_interface *i2c, int line, int level)
-{
-    int data;
-
-    if (level != 0 && level != 1) {
-        abort();
-    }
-
-    if (line == BITBANG_I2C_SDA) {
-        if (level == i2c->last_data) {
-            return bitbang_i2c_nop(i2c);
-        }
-        i2c->last_data = level;
-        if (i2c->last_clock == 0) {
-            return bitbang_i2c_nop(i2c);
-        }
-        if (level == 0) {
-            DPRINTF("START\n");
-            /* START condition.  */
-            i2c->state = SENDING_BIT7;
-            i2c->current_addr = -1;
-        } else {
-            /* STOP condition.  */
-            bitbang_i2c_enter_stop(i2c);
-        }
-        return bitbang_i2c_ret(i2c, 1);
-    }
-
-    data = i2c->last_data;
-    if (i2c->last_clock == level) {
-        return bitbang_i2c_nop(i2c);
-    }
-    i2c->last_clock = level;
-    if (level == 0) {
-        /* State is set/read at the start of the clock pulse.
-           release the data line at the end.  */
-        return bitbang_i2c_ret(i2c, 1);
-    }
-    switch (i2c->state) {
-    case STOPPED:
-    case SENT_NACK:
-        return bitbang_i2c_ret(i2c, 1);
-
-    case SENDING_BIT7 ... SENDING_BIT0:
-        i2c->buffer = (i2c->buffer << 1) | data;
-        /* will end up in WAITING_FOR_ACK */
-        i2c->state++; 
-        return bitbang_i2c_ret(i2c, 1);
-
-    case WAITING_FOR_ACK:
-        if (i2c->current_addr < 0) {
-            i2c->current_addr = i2c->buffer;
-            DPRINTF("Address 0x%02x\n", i2c->current_addr);
-            i2c_start_transfer(i2c->bus, i2c->current_addr >> 1,
-                               i2c->current_addr & 1);
-        } else {
-            DPRINTF("Sent 0x%02x\n", i2c->buffer);
-            i2c_send(i2c->bus, i2c->buffer);
-        }
-        if (i2c->current_addr & 1) {
-            i2c->state = RECEIVING_BIT7;
-        } else {
-            i2c->state = SENDING_BIT7;
-        }
-        return bitbang_i2c_ret(i2c, 0);
-
-    case RECEIVING_BIT7:
-        i2c->buffer = i2c_recv(i2c->bus);
-        DPRINTF("RX byte 0x%02x\n", i2c->buffer);
-        /* Fall through... */
-    case RECEIVING_BIT6 ... RECEIVING_BIT0:
-        data = i2c->buffer >> 7;
-        /* will end up in SENDING_ACK */
-        i2c->state++;
-        i2c->buffer <<= 1;
-        return bitbang_i2c_ret(i2c, data);
-
-    case SENDING_ACK:
-        i2c->state = RECEIVING_BIT7;
-        if (data != 0) {
-            DPRINTF("NACKED\n");
-            i2c->state = SENT_NACK;
-            i2c_nack(i2c->bus);
-        } else {
-            DPRINTF("ACKED\n");
-        }
-        return bitbang_i2c_ret(i2c, 1);
-    }
-    abort();
-}
-
-bitbang_i2c_interface *bitbang_i2c_init(i2c_bus *bus)
-{
-    bitbang_i2c_interface *s;
-
-    s = g_malloc0(sizeof(bitbang_i2c_interface));
-
-    s->bus = bus;
-    s->last_data = 1;
-    s->last_clock = 1;
-    s->device_out = 1;
-
-    return s;
-}
-
-/* GPIO interface.  */
-typedef struct {
-    SysBusDevice busdev;
-    MemoryRegion dummy_iomem;
-    bitbang_i2c_interface *bitbang;
-    int last_level;
-    qemu_irq out;
-} GPIOI2CState;
-
-static void bitbang_i2c_gpio_set(void *opaque, int irq, int level)
-{
-    GPIOI2CState *s = opaque;
-
-    level = bitbang_i2c_set(s->bitbang, irq, level);
-    if (level != s->last_level) {
-        s->last_level = level;
-        qemu_set_irq(s->out, level);
-    }
-}
-
-static int gpio_i2c_init(SysBusDevice *dev)
-{
-    GPIOI2CState *s = FROM_SYSBUS(GPIOI2CState, dev);
-    i2c_bus *bus;
-
-    memory_region_init(&s->dummy_iomem, "gpio_i2c", 0);
-    sysbus_init_mmio(dev, &s->dummy_iomem);
-
-    bus = i2c_init_bus(&dev->qdev, "i2c");
-    s->bitbang = bitbang_i2c_init(bus);
-
-    qdev_init_gpio_in(&dev->qdev, bitbang_i2c_gpio_set, 2);
-    qdev_init_gpio_out(&dev->qdev, &s->out, 1);
-
-    return 0;
-}
-
-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 const 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_types(void)
-{
-    type_register_static(&gpio_i2c_info);
-}
-
-type_init(bitbang_i2c_register_types)
diff --git a/hw/bitbang_i2c.h b/hw/bitbang_i2c.h
deleted file mode 100644 (file)
index e860627..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-#ifndef BITBANG_I2C_H
-#define BITBANG_I2C_H
-
-#include "hw/i2c.h"
-
-typedef struct bitbang_i2c_interface bitbang_i2c_interface;
-
-#define BITBANG_I2C_SDA 0
-#define BITBANG_I2C_SCL 1
-
-bitbang_i2c_interface *bitbang_i2c_init(i2c_bus *bus);
-int bitbang_i2c_set(bitbang_i2c_interface *i2c, int line, int level);
-
-#endif
diff --git a/hw/blizzard.c b/hw/blizzard.c
deleted file mode 100644 (file)
index 020d3de..0000000
+++ /dev/null
@@ -1,1004 +0,0 @@
-/*
- * Epson S1D13744/S1D13745 (Blizzard/Hailstorm/Tornado) LCD/TV controller.
- *
- * Copyright (C) 2008 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.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 or
- * (at your option) version 3 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
- * 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 "ui/console.h"
-#include "hw/devices.h"
-#include "hw/vga_int.h"
-#include "ui/pixel_ops.h"
-
-typedef void (*blizzard_fn_t)(uint8_t *, const uint8_t *, unsigned int);
-
-typedef struct {
-    uint8_t reg;
-    uint32_t addr;
-    int swallow;
-
-    int pll;
-    int pll_range;
-    int pll_ctrl;
-    uint8_t pll_mode;
-    uint8_t clksel;
-    int memenable;
-    int memrefresh;
-    uint8_t timing[3];
-    int priority;
-
-    uint8_t lcd_config;
-    int x;
-    int y;
-    int skipx;
-    int skipy;
-    uint8_t hndp;
-    uint8_t vndp;
-    uint8_t hsync;
-    uint8_t vsync;
-    uint8_t pclk;
-    uint8_t u;
-    uint8_t v;
-    uint8_t yrc[2];
-    int ix[2];
-    int iy[2];
-    int ox[2];
-    int oy[2];
-
-    int enable;
-    int blank;
-    int bpp;
-    int invalidate;
-    int mx[2];
-    int my[2];
-    uint8_t mode;
-    uint8_t effect;
-    uint8_t iformat;
-    uint8_t source;
-    QemuConsole *con;
-    blizzard_fn_t *line_fn_tab[2];
-    void *fb;
-
-    uint8_t hssi_config[3];
-    uint8_t tv_config;
-    uint8_t tv_timing[4];
-    uint8_t vbi;
-    uint8_t tv_x;
-    uint8_t tv_y;
-    uint8_t tv_test;
-    uint8_t tv_filter_config;
-    uint8_t tv_filter_idx;
-    uint8_t tv_filter_coeff[0x20];
-    uint8_t border_r;
-    uint8_t border_g;
-    uint8_t border_b;
-    uint8_t gamma_config;
-    uint8_t gamma_idx;
-    uint8_t gamma_lut[0x100];
-    uint8_t matrix_ena;
-    uint8_t matrix_coeff[0x12];
-    uint8_t matrix_r;
-    uint8_t matrix_g;
-    uint8_t matrix_b;
-    uint8_t pm;
-    uint8_t status;
-    uint8_t rgbgpio_dir;
-    uint8_t rgbgpio;
-    uint8_t gpio_dir;
-    uint8_t gpio;
-    uint8_t gpio_edge[2];
-    uint8_t gpio_irq;
-    uint8_t gpio_pdown;
-
-    struct {
-        int x;
-        int y;
-        int dx;
-        int dy;
-        int len;
-        int buflen;
-        void *buf;
-        void *data;
-        uint16_t *ptr;
-        int angle;
-        int pitch;
-        blizzard_fn_t line_fn;
-    } data;
-} BlizzardState;
-
-/* Bytes(!) per pixel */
-static const int blizzard_iformat_bpp[0x10] = {
-    0,
-    2, /* RGB 5:6:5*/
-    3, /* RGB 6:6:6 mode 1 */
-    3, /* RGB 8:8:8 mode 1 */
-    0, 0,
-    4, /* RGB 6:6:6 mode 2 */
-    4, /* RGB 8:8:8 mode 2 */
-    0, /* YUV 4:2:2 */
-    0, /* YUV 4:2:0 */
-    0, 0, 0, 0, 0, 0,
-};
-
-static inline void blizzard_rgb2yuv(int r, int g, int b,
-                int *y, int *u, int *v)
-{
-    *y = 0x10 + ((0x838 * r + 0x1022 * g + 0x322 * b) >> 13);
-    *u = 0x80 + ((0xe0e * b - 0x04c1 * r - 0x94e * g) >> 13);
-    *v = 0x80 + ((0xe0e * r - 0x0bc7 * g - 0x247 * b) >> 13);
-}
-
-static void blizzard_window(BlizzardState *s)
-{
-    DisplaySurface *surface = qemu_console_surface(s->con);
-    uint8_t *src, *dst;
-    int bypp[2];
-    int bypl[3];
-    int y;
-    blizzard_fn_t fn = s->data.line_fn;
-
-    if (!fn)
-        return;
-    if (s->mx[0] > s->data.x)
-        s->mx[0] = s->data.x;
-    if (s->my[0] > s->data.y)
-        s->my[0] = s->data.y;
-    if (s->mx[1] < s->data.x + s->data.dx)
-        s->mx[1] = s->data.x + s->data.dx;
-    if (s->my[1] < s->data.y + s->data.dy)
-        s->my[1] = s->data.y + s->data.dy;
-
-    bypp[0] = s->bpp;
-    bypp[1] = surface_bytes_per_pixel(surface);
-    bypl[0] = bypp[0] * s->data.pitch;
-    bypl[1] = bypp[1] * s->x;
-    bypl[2] = bypp[0] * s->data.dx;
-
-    src = s->data.data;
-    dst = s->fb + bypl[1] * s->data.y + bypp[1] * s->data.x;
-    for (y = s->data.dy; y > 0; y --, src += bypl[0], dst += bypl[1])
-        fn(dst, src, bypl[2]);
-}
-
-static int blizzard_transfer_setup(BlizzardState *s)
-{
-    if (s->source > 3 || !s->bpp ||
-                    s->ix[1] < s->ix[0] || s->iy[1] < s->iy[0])
-        return 0;
-
-    s->data.angle = s->effect & 3;
-    s->data.line_fn = s->line_fn_tab[!!s->data.angle][s->iformat];
-    s->data.x = s->ix[0];
-    s->data.y = s->iy[0];
-    s->data.dx = s->ix[1] - s->ix[0] + 1;
-    s->data.dy = s->iy[1] - s->iy[0] + 1;
-    s->data.len = s->bpp * s->data.dx * s->data.dy;
-    s->data.pitch = s->data.dx;
-    if (s->data.len > s->data.buflen) {
-        s->data.buf = g_realloc(s->data.buf, s->data.len);
-        s->data.buflen = s->data.len;
-    }
-    s->data.ptr = s->data.buf;
-    s->data.data = s->data.buf;
-    s->data.len /= 2;
-    return 1;
-}
-
-static void blizzard_reset(BlizzardState *s)
-{
-    s->reg = 0;
-    s->swallow = 0;
-
-    s->pll = 9;
-    s->pll_range = 1;
-    s->pll_ctrl = 0x14;
-    s->pll_mode = 0x32;
-    s->clksel = 0x00;
-    s->memenable = 0;
-    s->memrefresh = 0x25c;
-    s->timing[0] = 0x3f;
-    s->timing[1] = 0x13;
-    s->timing[2] = 0x21;
-    s->priority = 0;
-
-    s->lcd_config = 0x74;
-    s->x = 8;
-    s->y = 1;
-    s->skipx = 0;
-    s->skipy = 0;
-    s->hndp = 3;
-    s->vndp = 2;
-    s->hsync = 1;
-    s->vsync = 1;
-    s->pclk = 0x80;
-
-    s->ix[0] = 0;
-    s->ix[1] = 0;
-    s->iy[0] = 0;
-    s->iy[1] = 0;
-    s->ox[0] = 0;
-    s->ox[1] = 0;
-    s->oy[0] = 0;
-    s->oy[1] = 0;
-
-    s->yrc[0] = 0x00;
-    s->yrc[1] = 0x30;
-    s->u = 0;
-    s->v = 0;
-
-    s->iformat = 3;
-    s->source = 0;
-    s->bpp = blizzard_iformat_bpp[s->iformat];
-
-    s->hssi_config[0] = 0x00;
-    s->hssi_config[1] = 0x00;
-    s->hssi_config[2] = 0x01;
-    s->tv_config = 0x00;
-    s->tv_timing[0] = 0x00;
-    s->tv_timing[1] = 0x00;
-    s->tv_timing[2] = 0x00;
-    s->tv_timing[3] = 0x00;
-    s->vbi = 0x10;
-    s->tv_x = 0x14;
-    s->tv_y = 0x03;
-    s->tv_test = 0x00;
-    s->tv_filter_config = 0x80;
-    s->tv_filter_idx = 0x00;
-    s->border_r = 0x10;
-    s->border_g = 0x80;
-    s->border_b = 0x80;
-    s->gamma_config = 0x00;
-    s->gamma_idx = 0x00;
-    s->matrix_ena = 0x00;
-    memset(&s->matrix_coeff, 0, sizeof(s->matrix_coeff));
-    s->matrix_r = 0x00;
-    s->matrix_g = 0x00;
-    s->matrix_b = 0x00;
-    s->pm = 0x02;
-    s->status = 0x00;
-    s->rgbgpio_dir = 0x00;
-    s->gpio_dir = 0x00;
-    s->gpio_edge[0] = 0x00;
-    s->gpio_edge[1] = 0x00;
-    s->gpio_irq = 0x00;
-    s->gpio_pdown = 0xff;
-}
-
-static inline void blizzard_invalidate_display(void *opaque) {
-    BlizzardState *s = (BlizzardState *) opaque;
-
-    s->invalidate = 1;
-}
-
-static uint16_t blizzard_reg_read(void *opaque, uint8_t reg)
-{
-    BlizzardState *s = (BlizzardState *) opaque;
-
-    switch (reg) {
-    case 0x00: /* Revision Code */
-        return 0xa5;
-
-    case 0x02: /* Configuration Readback */
-        return 0x83;   /* Macrovision OK, CNF[2:0] = 3 */
-
-    case 0x04: /* PLL M-Divider */
-        return (s->pll - 1) | (1 << 7);
-    case 0x06: /* PLL Lock Range Control */
-        return s->pll_range;
-    case 0x08: /* PLL Lock Synthesis Control 0 */
-        return s->pll_ctrl & 0xff;
-    case 0x0a: /* PLL Lock Synthesis Control 1 */
-        return s->pll_ctrl >> 8;
-    case 0x0c: /* PLL Mode Control 0 */
-        return s->pll_mode;
-
-    case 0x0e: /* Clock-Source Select */
-        return s->clksel;
-
-    case 0x10: /* Memory Controller Activate */
-    case 0x14: /* Memory Controller Bank 0 Status Flag */
-        return s->memenable;
-
-    case 0x18: /* Auto-Refresh Interval Setting 0 */
-        return s->memrefresh & 0xff;
-    case 0x1a: /* Auto-Refresh Interval Setting 1 */
-        return s->memrefresh >> 8;
-
-    case 0x1c: /* Power-On Sequence Timing Control */
-        return s->timing[0];
-    case 0x1e: /* Timing Control 0 */
-        return s->timing[1];
-    case 0x20: /* Timing Control 1 */
-        return s->timing[2];
-
-    case 0x24: /* Arbitration Priority Control */
-        return s->priority;
-
-    case 0x28: /* LCD Panel Configuration */
-        return s->lcd_config;
-
-    case 0x2a: /* LCD Horizontal Display Width */
-        return s->x >> 3;
-    case 0x2c: /* LCD Horizontal Non-display Period */
-        return s->hndp;
-    case 0x2e: /* LCD Vertical Display Height 0 */
-        return s->y & 0xff;
-    case 0x30: /* LCD Vertical Display Height 1 */
-        return s->y >> 8;
-    case 0x32: /* LCD Vertical Non-display Period */
-        return s->vndp;
-    case 0x34: /* LCD HS Pulse-width */
-        return s->hsync;
-    case 0x36: /* LCd HS Pulse Start Position */
-        return s->skipx >> 3;
-    case 0x38: /* LCD VS Pulse-width */
-        return s->vsync;
-    case 0x3a: /* LCD VS Pulse Start Position */
-        return s->skipy;
-
-    case 0x3c: /* PCLK Polarity */
-        return s->pclk;
-
-    case 0x3e: /* High-speed Serial Interface Tx Configuration Port 0 */
-        return s->hssi_config[0];
-    case 0x40: /* High-speed Serial Interface Tx Configuration Port 1 */
-        return s->hssi_config[1];
-    case 0x42: /* High-speed Serial Interface Tx Mode */
-        return s->hssi_config[2];
-    case 0x44: /* TV Display Configuration */
-        return s->tv_config;
-    case 0x46 ... 0x4c:        /* TV Vertical Blanking Interval Data bits */
-        return s->tv_timing[(reg - 0x46) >> 1];
-    case 0x4e: /* VBI: Closed Caption / XDS Control / Status */
-        return s->vbi;
-    case 0x50: /* TV Horizontal Start Position */
-        return s->tv_x;
-    case 0x52: /* TV Vertical Start Position */
-        return s->tv_y;
-    case 0x54: /* TV Test Pattern Setting */
-        return s->tv_test;
-    case 0x56: /* TV Filter Setting */
-        return s->tv_filter_config;
-    case 0x58: /* TV Filter Coefficient Index */
-        return s->tv_filter_idx;
-    case 0x5a: /* TV Filter Coefficient Data */
-        if (s->tv_filter_idx < 0x20)
-            return s->tv_filter_coeff[s->tv_filter_idx ++];
-        return 0;
-
-    case 0x60: /* Input YUV/RGB Translate Mode 0 */
-        return s->yrc[0];
-    case 0x62: /* Input YUV/RGB Translate Mode 1 */
-        return s->yrc[1];
-    case 0x64: /* U Data Fix */
-        return s->u;
-    case 0x66: /* V Data Fix */
-        return s->v;
-
-    case 0x68: /* Display Mode */
-        return s->mode;
-
-    case 0x6a: /* Special Effects */
-        return s->effect;
-
-    case 0x6c: /* Input Window X Start Position 0 */
-        return s->ix[0] & 0xff;
-    case 0x6e: /* Input Window X Start Position 1 */
-        return s->ix[0] >> 3;
-    case 0x70: /* Input Window Y Start Position 0 */
-        return s->ix[0] & 0xff;
-    case 0x72: /* Input Window Y Start Position 1 */
-        return s->ix[0] >> 3;
-    case 0x74: /* Input Window X End Position 0 */
-        return s->ix[1] & 0xff;
-    case 0x76: /* Input Window X End Position 1 */
-        return s->ix[1] >> 3;
-    case 0x78: /* Input Window Y End Position 0 */
-        return s->ix[1] & 0xff;
-    case 0x7a: /* Input Window Y End Position 1 */
-        return s->ix[1] >> 3;
-    case 0x7c: /* Output Window X Start Position 0 */
-        return s->ox[0] & 0xff;
-    case 0x7e: /* Output Window X Start Position 1 */
-        return s->ox[0] >> 3;
-    case 0x80: /* Output Window Y Start Position 0 */
-        return s->oy[0] & 0xff;
-    case 0x82: /* Output Window Y Start Position 1 */
-        return s->oy[0] >> 3;
-    case 0x84: /* Output Window X End Position 0 */
-        return s->ox[1] & 0xff;
-    case 0x86: /* Output Window X End Position 1 */
-        return s->ox[1] >> 3;
-    case 0x88: /* Output Window Y End Position 0 */
-        return s->oy[1] & 0xff;
-    case 0x8a: /* Output Window Y End Position 1 */
-        return s->oy[1] >> 3;
-
-    case 0x8c: /* Input Data Format */
-        return s->iformat;
-    case 0x8e: /* Data Source Select */
-        return s->source;
-    case 0x90: /* Display Memory Data Port */
-        return 0;
-
-    case 0xa8: /* Border Color 0 */
-        return s->border_r;
-    case 0xaa: /* Border Color 1 */
-        return s->border_g;
-    case 0xac: /* Border Color 2 */
-        return s->border_b;
-
-    case 0xb4: /* Gamma Correction Enable */
-        return s->gamma_config;
-    case 0xb6: /* Gamma Correction Table Index */
-        return s->gamma_idx;
-    case 0xb8: /* Gamma Correction Table Data */
-        return s->gamma_lut[s->gamma_idx ++];
-
-    case 0xba: /* 3x3 Matrix Enable */
-        return s->matrix_ena;
-    case 0xbc ... 0xde:        /* Coefficient Registers */
-        return s->matrix_coeff[(reg - 0xbc) >> 1];
-    case 0xe0: /* 3x3 Matrix Red Offset */
-        return s->matrix_r;
-    case 0xe2: /* 3x3 Matrix Green Offset */
-        return s->matrix_g;
-    case 0xe4: /* 3x3 Matrix Blue Offset */
-        return s->matrix_b;
-
-    case 0xe6: /* Power-save */
-        return s->pm;
-    case 0xe8: /* Non-display Period Control / Status */
-        return s->status | (1 << 5);
-    case 0xea: /* RGB Interface Control */
-        return s->rgbgpio_dir;
-    case 0xec: /* RGB Interface Status */
-        return s->rgbgpio;
-    case 0xee: /* General-purpose IO Pins Configuration */
-        return s->gpio_dir;
-    case 0xf0: /* General-purpose IO Pins Status / Control */
-        return s->gpio;
-    case 0xf2: /* GPIO Positive Edge Interrupt Trigger */
-        return s->gpio_edge[0];
-    case 0xf4: /* GPIO Negative Edge Interrupt Trigger */
-        return s->gpio_edge[1];
-    case 0xf6: /* GPIO Interrupt Status */
-        return s->gpio_irq;
-    case 0xf8: /* GPIO Pull-down Control */
-        return s->gpio_pdown;
-
-    default:
-        fprintf(stderr, "%s: unknown register %02x\n", __FUNCTION__, reg);
-        return 0;
-    }
-}
-
-static void blizzard_reg_write(void *opaque, uint8_t reg, uint16_t value)
-{
-    BlizzardState *s = (BlizzardState *) opaque;
-
-    switch (reg) {
-    case 0x04: /* PLL M-Divider */
-        s->pll = (value & 0x3f) + 1;
-        break;
-    case 0x06: /* PLL Lock Range Control */
-        s->pll_range = value & 3;
-        break;
-    case 0x08: /* PLL Lock Synthesis Control 0 */
-        s->pll_ctrl &= 0xf00;
-        s->pll_ctrl |= (value << 0) & 0x0ff;
-        break;
-    case 0x0a: /* PLL Lock Synthesis Control 1 */
-        s->pll_ctrl &= 0x0ff;
-        s->pll_ctrl |= (value << 8) & 0xf00;
-        break;
-    case 0x0c: /* PLL Mode Control 0 */
-        s->pll_mode = value & 0x77;
-        if ((value & 3) == 0 || (value & 3) == 3)
-            fprintf(stderr, "%s: wrong PLL Control bits (%i)\n",
-                    __FUNCTION__, value & 3);
-        break;
-
-    case 0x0e: /* Clock-Source Select */
-        s->clksel = value & 0xff;
-        break;
-
-    case 0x10: /* Memory Controller Activate */
-        s->memenable = value & 1;
-        break;
-    case 0x14: /* Memory Controller Bank 0 Status Flag */
-        break;
-
-    case 0x18: /* Auto-Refresh Interval Setting 0 */
-        s->memrefresh &= 0xf00;
-        s->memrefresh |= (value << 0) & 0x0ff;
-        break;
-    case 0x1a: /* Auto-Refresh Interval Setting 1 */
-        s->memrefresh &= 0x0ff;
-        s->memrefresh |= (value << 8) & 0xf00;
-        break;
-
-    case 0x1c: /* Power-On Sequence Timing Control */
-        s->timing[0] = value & 0x7f;
-        break;
-    case 0x1e: /* Timing Control 0 */
-        s->timing[1] = value & 0x17;
-        break;
-    case 0x20: /* Timing Control 1 */
-        s->timing[2] = value & 0x35;
-        break;
-
-    case 0x24: /* Arbitration Priority Control */
-        s->priority = value & 1;
-        break;
-
-    case 0x28: /* LCD Panel Configuration */
-        s->lcd_config = value & 0xff;
-        if (value & (1 << 7))
-            fprintf(stderr, "%s: data swap not supported!\n", __FUNCTION__);
-        break;
-
-    case 0x2a: /* LCD Horizontal Display Width */
-        s->x = value << 3;
-        break;
-    case 0x2c: /* LCD Horizontal Non-display Period */
-        s->hndp = value & 0xff;
-        break;
-    case 0x2e: /* LCD Vertical Display Height 0 */
-        s->y &= 0x300;
-        s->y |= (value << 0) & 0x0ff;
-        break;
-    case 0x30: /* LCD Vertical Display Height 1 */
-        s->y &= 0x0ff;
-        s->y |= (value << 8) & 0x300;
-        break;
-    case 0x32: /* LCD Vertical Non-display Period */
-        s->vndp = value & 0xff;
-        break;
-    case 0x34: /* LCD HS Pulse-width */
-        s->hsync = value & 0xff;
-        break;
-    case 0x36: /* LCD HS Pulse Start Position */
-        s->skipx = value & 0xff;
-        break;
-    case 0x38: /* LCD VS Pulse-width */
-        s->vsync = value & 0xbf;
-        break;
-    case 0x3a: /* LCD VS Pulse Start Position */
-        s->skipy = value & 0xff;
-        break;
-
-    case 0x3c: /* PCLK Polarity */
-        s->pclk = value & 0x82;
-        /* Affects calculation of s->hndp, s->hsync and s->skipx.  */
-        break;
-
-    case 0x3e: /* High-speed Serial Interface Tx Configuration Port 0 */
-        s->hssi_config[0] = value;
-        break;
-    case 0x40: /* High-speed Serial Interface Tx Configuration Port 1 */
-        s->hssi_config[1] = value;
-        if (((value >> 4) & 3) == 3)
-            fprintf(stderr, "%s: Illegal active-data-links value\n",
-                            __FUNCTION__);
-        break;
-    case 0x42: /* High-speed Serial Interface Tx Mode */
-        s->hssi_config[2] = value & 0xbd;
-        break;
-
-    case 0x44: /* TV Display Configuration */
-        s->tv_config = value & 0xfe;
-        break;
-    case 0x46 ... 0x4c:        /* TV Vertical Blanking Interval Data bits 0 */
-        s->tv_timing[(reg - 0x46) >> 1] = value;
-        break;
-    case 0x4e: /* VBI: Closed Caption / XDS Control / Status */
-        s->vbi = value;
-        break;
-    case 0x50: /* TV Horizontal Start Position */
-        s->tv_x = value;
-        break;
-    case 0x52: /* TV Vertical Start Position */
-        s->tv_y = value & 0x7f;
-        break;
-    case 0x54: /* TV Test Pattern Setting */
-        s->tv_test = value;
-        break;
-    case 0x56: /* TV Filter Setting */
-        s->tv_filter_config = value & 0xbf;
-        break;
-    case 0x58: /* TV Filter Coefficient Index */
-        s->tv_filter_idx = value & 0x1f;
-        break;
-    case 0x5a: /* TV Filter Coefficient Data */
-        if (s->tv_filter_idx < 0x20)
-            s->tv_filter_coeff[s->tv_filter_idx ++] = value;
-        break;
-
-    case 0x60: /* Input YUV/RGB Translate Mode 0 */
-        s->yrc[0] = value & 0xb0;
-        break;
-    case 0x62: /* Input YUV/RGB Translate Mode 1 */
-        s->yrc[1] = value & 0x30;
-        break;
-    case 0x64: /* U Data Fix */
-        s->u = value & 0xff;
-        break;
-    case 0x66: /* V Data Fix */
-        s->v = value & 0xff;
-        break;
-
-    case 0x68: /* Display Mode */
-        if ((s->mode ^ value) & 3)
-            s->invalidate = 1;
-        s->mode = value & 0xb7;
-        s->enable = value & 1;
-        s->blank = (value >> 1) & 1;
-        if (value & (1 << 4))
-            fprintf(stderr, "%s: Macrovision enable attempt!\n", __FUNCTION__);
-        break;
-
-    case 0x6a: /* Special Effects */
-        s->effect = value & 0xfb;
-        break;
-
-    case 0x6c: /* Input Window X Start Position 0 */
-        s->ix[0] &= 0x300;
-        s->ix[0] |= (value << 0) & 0x0ff;
-        break;
-    case 0x6e: /* Input Window X Start Position 1 */
-        s->ix[0] &= 0x0ff;
-        s->ix[0] |= (value << 8) & 0x300;
-        break;
-    case 0x70: /* Input Window Y Start Position 0 */
-        s->iy[0] &= 0x300;
-        s->iy[0] |= (value << 0) & 0x0ff;
-        break;
-    case 0x72: /* Input Window Y Start Position 1 */
-        s->iy[0] &= 0x0ff;
-        s->iy[0] |= (value << 8) & 0x300;
-        break;
-    case 0x74: /* Input Window X End Position 0 */
-        s->ix[1] &= 0x300;
-        s->ix[1] |= (value << 0) & 0x0ff;
-        break;
-    case 0x76: /* Input Window X End Position 1 */
-        s->ix[1] &= 0x0ff;
-        s->ix[1] |= (value << 8) & 0x300;
-        break;
-    case 0x78: /* Input Window Y End Position 0 */
-        s->iy[1] &= 0x300;
-        s->iy[1] |= (value << 0) & 0x0ff;
-        break;
-    case 0x7a: /* Input Window Y End Position 1 */
-        s->iy[1] &= 0x0ff;
-        s->iy[1] |= (value << 8) & 0x300;
-        break;
-    case 0x7c: /* Output Window X Start Position 0 */
-        s->ox[0] &= 0x300;
-        s->ox[0] |= (value << 0) & 0x0ff;
-        break;
-    case 0x7e: /* Output Window X Start Position 1 */
-        s->ox[0] &= 0x0ff;
-        s->ox[0] |= (value << 8) & 0x300;
-        break;
-    case 0x80: /* Output Window Y Start Position 0 */
-        s->oy[0] &= 0x300;
-        s->oy[0] |= (value << 0) & 0x0ff;
-        break;
-    case 0x82: /* Output Window Y Start Position 1 */
-        s->oy[0] &= 0x0ff;
-        s->oy[0] |= (value << 8) & 0x300;
-        break;
-    case 0x84: /* Output Window X End Position 0 */
-        s->ox[1] &= 0x300;
-        s->ox[1] |= (value << 0) & 0x0ff;
-        break;
-    case 0x86: /* Output Window X End Position 1 */
-        s->ox[1] &= 0x0ff;
-        s->ox[1] |= (value << 8) & 0x300;
-        break;
-    case 0x88: /* Output Window Y End Position 0 */
-        s->oy[1] &= 0x300;
-        s->oy[1] |= (value << 0) & 0x0ff;
-        break;
-    case 0x8a: /* Output Window Y End Position 1 */
-        s->oy[1] &= 0x0ff;
-        s->oy[1] |= (value << 8) & 0x300;
-        break;
-
-    case 0x8c: /* Input Data Format */
-        s->iformat = value & 0xf;
-        s->bpp = blizzard_iformat_bpp[s->iformat];
-        if (!s->bpp)
-            fprintf(stderr, "%s: Illegal or unsupported input format %x\n",
-                            __FUNCTION__, s->iformat);
-        break;
-    case 0x8e: /* Data Source Select */
-        s->source = value & 7;
-        /* Currently all windows will be "destructive overlays".  */
-        if ((!(s->effect & (1 << 3)) && (s->ix[0] != s->ox[0] ||
-                                        s->iy[0] != s->oy[0] ||
-                                        s->ix[1] != s->ox[1] ||
-                                        s->iy[1] != s->oy[1])) ||
-                        !((s->ix[1] - s->ix[0]) & (s->iy[1] - s->iy[0]) &
-                          (s->ox[1] - s->ox[0]) & (s->oy[1] - s->oy[0]) & 1))
-            fprintf(stderr, "%s: Illegal input/output window positions\n",
-                            __FUNCTION__);
-
-        blizzard_transfer_setup(s);
-        break;
-
-    case 0x90: /* Display Memory Data Port */
-        if (!s->data.len && !blizzard_transfer_setup(s))
-            break;
-
-        *s->data.ptr ++ = value;
-        if (-- s->data.len == 0)
-            blizzard_window(s);
-        break;
-
-    case 0xa8: /* Border Color 0 */
-        s->border_r = value;
-        break;
-    case 0xaa: /* Border Color 1 */
-        s->border_g = value;
-        break;
-    case 0xac: /* Border Color 2 */
-        s->border_b = value;
-        break;
-
-    case 0xb4: /* Gamma Correction Enable */
-        s->gamma_config = value & 0x87;
-        break;
-    case 0xb6: /* Gamma Correction Table Index */
-        s->gamma_idx = value;
-        break;
-    case 0xb8: /* Gamma Correction Table Data */
-        s->gamma_lut[s->gamma_idx ++] = value;
-        break;
-
-    case 0xba: /* 3x3 Matrix Enable */
-        s->matrix_ena = value & 1;
-        break;
-    case 0xbc ... 0xde:        /* Coefficient Registers */
-        s->matrix_coeff[(reg - 0xbc) >> 1] = value & ((reg & 2) ? 0x80 : 0xff);
-        break;
-    case 0xe0: /* 3x3 Matrix Red Offset */
-        s->matrix_r = value;
-        break;
-    case 0xe2: /* 3x3 Matrix Green Offset */
-        s->matrix_g = value;
-        break;
-    case 0xe4: /* 3x3 Matrix Blue Offset */
-        s->matrix_b = value;
-        break;
-
-    case 0xe6: /* Power-save */
-        s->pm = value & 0x83;
-        if (value & s->mode & 1)
-            fprintf(stderr, "%s: The display must be disabled before entering "
-                            "Standby Mode\n", __FUNCTION__);
-        break;
-    case 0xe8: /* Non-display Period Control / Status */
-        s->status = value & 0x1b;
-        break;
-    case 0xea: /* RGB Interface Control */
-        s->rgbgpio_dir = value & 0x8f;
-        break;
-    case 0xec: /* RGB Interface Status */
-        s->rgbgpio = value & 0xcf;
-        break;
-    case 0xee: /* General-purpose IO Pins Configuration */
-        s->gpio_dir = value;
-        break;
-    case 0xf0: /* General-purpose IO Pins Status / Control */
-        s->gpio = value;
-        break;
-    case 0xf2: /* GPIO Positive Edge Interrupt Trigger */
-        s->gpio_edge[0] = value;
-        break;
-    case 0xf4: /* GPIO Negative Edge Interrupt Trigger */
-        s->gpio_edge[1] = value;
-        break;
-    case 0xf6: /* GPIO Interrupt Status */
-        s->gpio_irq &= value;
-        break;
-    case 0xf8: /* GPIO Pull-down Control */
-        s->gpio_pdown = value;
-        break;
-
-    default:
-        fprintf(stderr, "%s: unknown register %02x\n", __FUNCTION__, reg);
-        break;
-    }
-}
-
-uint16_t s1d13745_read(void *opaque, int dc)
-{
-    BlizzardState *s = (BlizzardState *) opaque;
-    uint16_t value = blizzard_reg_read(s, s->reg);
-
-    if (s->swallow -- > 0)
-        return 0;
-    if (dc)
-        s->reg ++;
-
-    return value;
-}
-
-void s1d13745_write(void *opaque, int dc, uint16_t value)
-{
-    BlizzardState *s = (BlizzardState *) opaque;
-
-    if (s->swallow -- > 0)
-        return;
-    if (dc) {
-        blizzard_reg_write(s, s->reg, value);
-
-        if (s->reg != 0x90 && s->reg != 0x5a && s->reg != 0xb8)
-            s->reg += 2;
-    } else
-        s->reg = value & 0xff;
-}
-
-void s1d13745_write_block(void *opaque, int dc,
-                void *buf, size_t len, int pitch)
-{
-    BlizzardState *s = (BlizzardState *) opaque;
-
-    while (len > 0) {
-        if (s->reg == 0x90 && dc &&
-                        (s->data.len || blizzard_transfer_setup(s)) &&
-                        len >= (s->data.len << 1)) {
-            len -= s->data.len << 1;
-            s->data.len = 0;
-            s->data.data = buf;
-            if (pitch)
-                s->data.pitch = pitch;
-            blizzard_window(s);
-            s->data.data = s->data.buf;
-            continue;
-        }
-
-        s1d13745_write(opaque, dc, *(uint16_t *) buf);
-        len -= 2;
-        buf += 2;
-    }
-}
-
-static void blizzard_update_display(void *opaque)
-{
-    BlizzardState *s = (BlizzardState *) opaque;
-    DisplaySurface *surface = qemu_console_surface(s->con);
-    int y, bypp, bypl, bwidth;
-    uint8_t *src, *dst;
-
-    if (!s->enable)
-        return;
-
-    if (s->x != surface_width(surface) || s->y != surface_height(surface)) {
-        s->invalidate = 1;
-        qemu_console_resize(s->con, s->x, s->y);
-        surface = qemu_console_surface(s->con);
-    }
-
-    if (s->invalidate) {
-        s->invalidate = 0;
-
-        if (s->blank) {
-            bypp = surface_bytes_per_pixel(surface);
-            memset(surface_data(surface), 0, bypp * s->x * s->y);
-            return;
-        }
-
-        s->mx[0] = 0;
-        s->mx[1] = s->x;
-        s->my[0] = 0;
-        s->my[1] = s->y;
-    }
-
-    if (s->mx[1] <= s->mx[0])
-        return;
-
-    bypp = surface_bytes_per_pixel(surface);
-    bypl = bypp * s->x;
-    bwidth = bypp * (s->mx[1] - s->mx[0]);
-    y = s->my[0];
-    src = s->fb + bypl * y + bypp * s->mx[0];
-    dst = surface_data(surface) + bypl * y + bypp * s->mx[0];
-    for (; y < s->my[1]; y ++, src += bypl, dst += bypl)
-        memcpy(dst, src, bwidth);
-
-    dpy_gfx_update(s->con, s->mx[0], s->my[0],
-                   s->mx[1] - s->mx[0], y - s->my[0]);
-
-    s->mx[0] = s->x;
-    s->mx[1] = 0;
-    s->my[0] = s->y;
-    s->my[1] = 0;
-}
-
-static void blizzard_screen_dump(void *opaque, const char *filename,
-                                 bool cswitch, Error **errp)
-{
-    BlizzardState *s = (BlizzardState *) opaque;
-    DisplaySurface *surface = qemu_console_surface(s->con);
-
-    blizzard_update_display(opaque);
-    if (s && surface_data(surface)) {
-        ppm_save(filename, surface, errp);
-    }
-}
-
-#define DEPTH 8
-#include "hw/blizzard_template.h"
-#define DEPTH 15
-#include "hw/blizzard_template.h"
-#define DEPTH 16
-#include "hw/blizzard_template.h"
-#define DEPTH 24
-#include "hw/blizzard_template.h"
-#define DEPTH 32
-#include "hw/blizzard_template.h"
-
-void *s1d13745_init(qemu_irq gpio_int)
-{
-    BlizzardState *s = (BlizzardState *) g_malloc0(sizeof(*s));
-    DisplaySurface *surface;
-
-    s->fb = g_malloc(0x180000);
-
-    s->con = graphic_console_init(blizzard_update_display,
-                                  blizzard_invalidate_display,
-                                  blizzard_screen_dump, NULL, s);
-    surface = qemu_console_surface(s->con);
-
-    switch (surface_bits_per_pixel(surface)) {
-    case 0:
-        s->line_fn_tab[0] = s->line_fn_tab[1] =
-                g_malloc0(sizeof(blizzard_fn_t) * 0x10);
-        break;
-    case 8:
-        s->line_fn_tab[0] = blizzard_draw_fn_8;
-        s->line_fn_tab[1] = blizzard_draw_fn_r_8;
-        break;
-    case 15:
-        s->line_fn_tab[0] = blizzard_draw_fn_15;
-        s->line_fn_tab[1] = blizzard_draw_fn_r_15;
-        break;
-    case 16:
-        s->line_fn_tab[0] = blizzard_draw_fn_16;
-        s->line_fn_tab[1] = blizzard_draw_fn_r_16;
-        break;
-    case 24:
-        s->line_fn_tab[0] = blizzard_draw_fn_24;
-        s->line_fn_tab[1] = blizzard_draw_fn_r_24;
-        break;
-    case 32:
-        s->line_fn_tab[0] = blizzard_draw_fn_32;
-        s->line_fn_tab[1] = blizzard_draw_fn_r_32;
-        break;
-    default:
-        fprintf(stderr, "%s: Bad color depth\n", __FUNCTION__);
-        exit(1);
-    }
-
-    blizzard_reset(s);
-
-    return s;
-}
diff --git a/hw/blizzard_template.h b/hw/blizzard_template.h
deleted file mode 100644 (file)
index 42f4e90..0000000
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * QEMU Epson S1D13744/S1D13745 templates
- *
- * Copyright (C) 2008 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.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 or
- * (at your option) version 3 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
- * 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/>.
- */
-
-#define SKIP_PIXEL(to)         to += deststep
-#if DEPTH == 8
-# define PIXEL_TYPE            uint8_t
-# define COPY_PIXEL(to, from)  *to = from; SKIP_PIXEL(to)
-# define COPY_PIXEL1(to, from) *to ++ = from
-#elif DEPTH == 15 || DEPTH == 16
-# define PIXEL_TYPE            uint16_t
-# define COPY_PIXEL(to, from)  *to = from; SKIP_PIXEL(to)
-# define COPY_PIXEL1(to, from) *to ++ = from
-#elif DEPTH == 24
-# define PIXEL_TYPE            uint8_t
-# define COPY_PIXEL(to, from)  \
-    to[0] = from; to[1] = (from) >> 8; to[2] = (from) >> 16; SKIP_PIXEL(to)
-# define COPY_PIXEL1(to, from) \
-    *to ++ = from; *to ++ = (from) >> 8; *to ++ = (from) >> 16
-#elif DEPTH == 32
-# define PIXEL_TYPE            uint32_t
-# define COPY_PIXEL(to, from)  *to = from; SKIP_PIXEL(to)
-# define COPY_PIXEL1(to, from) *to ++ = from
-#else
-# error unknown bit depth
-#endif
-
-#ifdef HOST_WORDS_BIGENDIAN
-# define SWAP_WORDS    1
-#endif
-
-static void glue(blizzard_draw_line16_, DEPTH)(PIXEL_TYPE *dest,
-                const uint16_t *src, unsigned int width)
-{
-#if !defined(SWAP_WORDS) && DEPTH == 16
-    memcpy(dest, src, width);
-#else
-    uint16_t data;
-    unsigned int r, g, b;
-    const uint16_t *end = (const void *) src + width;
-    while (src < end) {
-        data = lduw_raw(src ++);
-        b = (data & 0x1f) << 3;
-        data >>= 5;
-        g = (data & 0x3f) << 2;
-        data >>= 6;
-        r = (data & 0x1f) << 3;
-        data >>= 5;
-        COPY_PIXEL1(dest, glue(rgb_to_pixel, DEPTH)(r, g, b));
-    }
-#endif
-}
-
-static void glue(blizzard_draw_line24mode1_, DEPTH)(PIXEL_TYPE *dest,
-                const uint8_t *src, unsigned int width)
-{
-    /* TODO: check if SDL 24-bit planes are not in the same format and
-     * if so, use memcpy */
-    unsigned int r[2], g[2], b[2];
-    const uint8_t *end = src + width;
-    while (src < end) {
-        g[0] = *src ++;
-        r[0] = *src ++;
-        r[1] = *src ++;
-        b[0] = *src ++;
-        COPY_PIXEL1(dest, glue(rgb_to_pixel, DEPTH)(r[0], g[0], b[0]));
-        b[1] = *src ++;
-        g[1] = *src ++;
-        COPY_PIXEL1(dest, glue(rgb_to_pixel, DEPTH)(r[1], g[1], b[1]));
-    }
-}
-
-static void glue(blizzard_draw_line24mode2_, DEPTH)(PIXEL_TYPE *dest,
-                const uint8_t *src, unsigned int width)
-{
-    unsigned int r, g, b;
-    const uint8_t *end = src + width;
-    while (src < end) {
-        r = *src ++;
-        src ++;
-        b = *src ++;
-        g = *src ++;
-        COPY_PIXEL1(dest, glue(rgb_to_pixel, DEPTH)(r, g, b));
-    }
-}
-
-/* No rotation */
-static blizzard_fn_t glue(blizzard_draw_fn_, DEPTH)[0x10] = {
-    NULL,
-    /* RGB 5:6:5*/
-    (blizzard_fn_t) glue(blizzard_draw_line16_, DEPTH),
-    /* RGB 6:6:6 mode 1 */
-    (blizzard_fn_t) glue(blizzard_draw_line24mode1_, DEPTH),
-    /* RGB 8:8:8 mode 1 */
-    (blizzard_fn_t) glue(blizzard_draw_line24mode1_, DEPTH),
-    NULL, NULL,
-    /* RGB 6:6:6 mode 2 */
-    (blizzard_fn_t) glue(blizzard_draw_line24mode2_, DEPTH),
-    /* RGB 8:8:8 mode 2 */
-    (blizzard_fn_t) glue(blizzard_draw_line24mode2_, DEPTH),
-    /* YUV 4:2:2 */
-    NULL,
-    /* YUV 4:2:0 */
-    NULL,
-    NULL, NULL, NULL, NULL, NULL, NULL,
-};
-
-/* 90deg, 180deg and 270deg rotation */
-static blizzard_fn_t glue(blizzard_draw_fn_r_, DEPTH)[0x10] = {
-    /* TODO */
-    [0 ... 0xf] = NULL,
-};
-
-#undef DEPTH
-#undef SKIP_PIXEL
-#undef COPY_PIXEL
-#undef COPY_PIXEL1
-#undef PIXEL_TYPE
-
-#undef SWAP_WORDS
diff --git a/hw/block-common.c b/hw/block-common.c
deleted file mode 100644 (file)
index d21ec3a..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Common code for block device models
- *
- * Copyright (C) 2012 Red Hat, Inc.
- *
- * 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 "sysemu/blockdev.h"
-#include "hw/block-common.h"
-#include "qemu/error-report.h"
-
-void blkconf_serial(BlockConf *conf, char **serial)
-{
-    DriveInfo *dinfo;
-
-    if (!*serial) {
-        /* try to fall back to value set with legacy -drive serial=... */
-        dinfo = drive_get_by_blockdev(conf->bs);
-        *serial = g_strdup(dinfo->serial);
-    }
-}
-
-int blkconf_geometry(BlockConf *conf, int *ptrans,
-                     unsigned cyls_max, unsigned heads_max, unsigned secs_max)
-{
-    DriveInfo *dinfo;
-
-    if (!conf->cyls && !conf->heads && !conf->secs) {
-        /* try to fall back to value set with legacy -drive cyls=... */
-        dinfo = drive_get_by_blockdev(conf->bs);
-        conf->cyls  = dinfo->cyls;
-        conf->heads = dinfo->heads;
-        conf->secs  = dinfo->secs;
-        if (ptrans) {
-            *ptrans = dinfo->trans;
-        }
-    }
-    if (!conf->cyls && !conf->heads && !conf->secs) {
-        hd_geometry_guess(conf->bs,
-                          &conf->cyls, &conf->heads, &conf->secs,
-                          ptrans);
-    } else if (ptrans && *ptrans == BIOS_ATA_TRANSLATION_AUTO) {
-        *ptrans = hd_bios_chs_auto_trans(conf->cyls, conf->heads, conf->secs);
-    }
-    if (conf->cyls || conf->heads || conf->secs) {
-        if (conf->cyls < 1 || conf->cyls > cyls_max) {
-            error_report("cyls must be between 1 and %u", cyls_max);
-            return -1;
-        }
-        if (conf->heads < 1 || conf->heads > heads_max) {
-            error_report("heads must be between 1 and %u", heads_max);
-            return -1;
-        }
-        if (conf->secs < 1 || conf->secs > secs_max) {
-            error_report("secs must be between 1 and %u", secs_max);
-            return -1;
-        }
-    }
-    return 0;
-}
diff --git a/hw/block-common.h b/hw/block-common.h
deleted file mode 100644 (file)
index dd11532..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Common code for block device models
- *
- * Copyright (C) 2012 Red Hat, Inc.
- * Copyright (c) 2003-2008 Fabrice Bellard
- *
- * 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 HW_BLOCK_COMMON_H
-#define HW_BLOCK_COMMON_H
-
-#include "qemu-common.h"
-
-/* Configuration */
-
-typedef struct BlockConf {
-    BlockDriverState *bs;
-    uint16_t physical_block_size;
-    uint16_t logical_block_size;
-    uint16_t min_io_size;
-    uint32_t opt_io_size;
-    int32_t bootindex;
-    uint32_t discard_granularity;
-    /* geometry, not all devices use this */
-    uint32_t cyls, heads, secs;
-} BlockConf;
-
-static inline unsigned int get_physical_block_exp(BlockConf *conf)
-{
-    unsigned int exp = 0, size;
-
-    for (size = conf->physical_block_size;
-        size > conf->logical_block_size;
-        size >>= 1) {
-        exp++;
-    }
-
-    return exp;
-}
-
-#define DEFINE_BLOCK_PROPERTIES(_state, _conf)                          \
-    DEFINE_PROP_DRIVE("drive", _state, _conf.bs),                       \
-    DEFINE_PROP_BLOCKSIZE("logical_block_size", _state,                 \
-                          _conf.logical_block_size, 512),               \
-    DEFINE_PROP_BLOCKSIZE("physical_block_size", _state,                \
-                          _conf.physical_block_size, 512),              \
-    DEFINE_PROP_UINT16("min_io_size", _state, _conf.min_io_size, 0),  \
-    DEFINE_PROP_UINT32("opt_io_size", _state, _conf.opt_io_size, 0),    \
-    DEFINE_PROP_INT32("bootindex", _state, _conf.bootindex, -1),        \
-    DEFINE_PROP_UINT32("discard_granularity", _state, \
-                       _conf.discard_granularity, -1)
-
-#define DEFINE_BLOCK_CHS_PROPERTIES(_state, _conf)      \
-    DEFINE_PROP_UINT32("cyls", _state, _conf.cyls, 0),  \
-    DEFINE_PROP_UINT32("heads", _state, _conf.heads, 0), \
-    DEFINE_PROP_UINT32("secs", _state, _conf.secs, 0)
-
-/* Configuration helpers */
-
-void blkconf_serial(BlockConf *conf, char **serial);
-int blkconf_geometry(BlockConf *conf, int *trans,
-                     unsigned cyls_max, unsigned heads_max, unsigned secs_max);
-
-/* Hard disk geometry */
-
-#define BIOS_ATA_TRANSLATION_AUTO   0
-#define BIOS_ATA_TRANSLATION_NONE   1
-#define BIOS_ATA_TRANSLATION_LBA    2
-#define BIOS_ATA_TRANSLATION_LARGE  3
-#define BIOS_ATA_TRANSLATION_RECHS  4
-
-void hd_geometry_guess(BlockDriverState *bs,
-                       uint32_t *pcyls, uint32_t *pheads, uint32_t *psecs,
-                       int *ptrans);
-int hd_bios_chs_auto_trans(uint32_t cyls, uint32_t heads, uint32_t secs);
-
-#endif
diff --git a/hw/block/Makefile.objs b/hw/block/Makefile.objs
new file mode 100644 (file)
index 0000000..e4329a0
--- /dev/null
@@ -0,0 +1,15 @@
+common-obj-y += block.o cdrom.o hd-geometry.o
+common-obj-$(CONFIG_FDC) += fdc.o
+common-obj-$(CONFIG_SSI_M25P80) += m25p80.o
+common-obj-$(CONFIG_NAND) += nand.o
+common-obj-$(CONFIG_PFLASH_CFI01) += pflash_cfi01.o
+common-obj-$(CONFIG_PFLASH_CFI02) += pflash_cfi02.o
+common-obj-$(CONFIG_XEN_BACKEND) += xen_disk.o
+common-obj-$(CONFIG_ECC) += ecc.o
+common-obj-$(CONFIG_ONENAND) += onenand.o
+common-obj-$(CONFIG_PC_SYSFW) += pc_sysfw.o
+
+obj-$(CONFIG_SH4) += tc58128.o
+
+obj-$(CONFIG_VIRTIO) += virtio-blk.o
+obj-$(CONFIG_VIRTIO_BLK_DATA_PLANE) += dataplane/
diff --git a/hw/block/block.c b/hw/block/block.c
new file mode 100644 (file)
index 0000000..33dd3f3
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Common code for block device models
+ *
+ * Copyright (C) 2012 Red Hat, Inc.
+ *
+ * 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 "sysemu/blockdev.h"
+#include "hw/block/block.h"
+#include "qemu/error-report.h"
+
+void blkconf_serial(BlockConf *conf, char **serial)
+{
+    DriveInfo *dinfo;
+
+    if (!*serial) {
+        /* try to fall back to value set with legacy -drive serial=... */
+        dinfo = drive_get_by_blockdev(conf->bs);
+        *serial = g_strdup(dinfo->serial);
+    }
+}
+
+int blkconf_geometry(BlockConf *conf, int *ptrans,
+                     unsigned cyls_max, unsigned heads_max, unsigned secs_max)
+{
+    DriveInfo *dinfo;
+
+    if (!conf->cyls && !conf->heads && !conf->secs) {
+        /* try to fall back to value set with legacy -drive cyls=... */
+        dinfo = drive_get_by_blockdev(conf->bs);
+        conf->cyls  = dinfo->cyls;
+        conf->heads = dinfo->heads;
+        conf->secs  = dinfo->secs;
+        if (ptrans) {
+            *ptrans = dinfo->trans;
+        }
+    }
+    if (!conf->cyls && !conf->heads && !conf->secs) {
+        hd_geometry_guess(conf->bs,
+                          &conf->cyls, &conf->heads, &conf->secs,
+                          ptrans);
+    } else if (ptrans && *ptrans == BIOS_ATA_TRANSLATION_AUTO) {
+        *ptrans = hd_bios_chs_auto_trans(conf->cyls, conf->heads, conf->secs);
+    }
+    if (conf->cyls || conf->heads || conf->secs) {
+        if (conf->cyls < 1 || conf->cyls > cyls_max) {
+            error_report("cyls must be between 1 and %u", cyls_max);
+            return -1;
+        }
+        if (conf->heads < 1 || conf->heads > heads_max) {
+            error_report("heads must be between 1 and %u", heads_max);
+            return -1;
+        }
+        if (conf->secs < 1 || conf->secs > secs_max) {
+            error_report("secs must be between 1 and %u", secs_max);
+            return -1;
+        }
+    }
+    return 0;
+}
diff --git a/hw/block/cdrom.c b/hw/block/cdrom.c
new file mode 100644 (file)
index 0000000..38469fa
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ * QEMU ATAPI CD-ROM Emulator
+ *
+ * Copyright (c) 2006 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.
+ */
+
+/* ??? Most of the ATAPI emulation is still in ide.c.  It should be moved
+   here.  */
+
+#include "qemu-common.h"
+#include "hw/scsi/scsi.h"
+
+static void lba_to_msf(uint8_t *buf, int lba)
+{
+    lba += 150;
+    buf[0] = (lba / 75) / 60;
+    buf[1] = (lba / 75) % 60;
+    buf[2] = lba % 75;
+}
+
+/* same toc as bochs. Return -1 if error or the toc length */
+/* XXX: check this */
+int cdrom_read_toc(int nb_sectors, uint8_t *buf, int msf, int start_track)
+{
+    uint8_t *q;
+    int len;
+
+    if (start_track > 1 && start_track != 0xaa)
+        return -1;
+    q = buf + 2;
+    *q++ = 1; /* first session */
+    *q++ = 1; /* last session */
+    if (start_track <= 1) {
+        *q++ = 0; /* reserved */
+        *q++ = 0x14; /* ADR, control */
+        *q++ = 1;    /* track number */
+        *q++ = 0; /* reserved */
+        if (msf) {
+            *q++ = 0; /* reserved */
+            lba_to_msf(q, 0);
+            q += 3;
+        } else {
+            /* sector 0 */
+            cpu_to_be32wu((uint32_t *)q, 0);
+            q += 4;
+        }
+    }
+    /* lead out track */
+    *q++ = 0; /* reserved */
+    *q++ = 0x16; /* ADR, control */
+    *q++ = 0xaa; /* track number */
+    *q++ = 0; /* reserved */
+    if (msf) {
+        *q++ = 0; /* reserved */
+        lba_to_msf(q, nb_sectors);
+        q += 3;
+    } else {
+        cpu_to_be32wu((uint32_t *)q, nb_sectors);
+        q += 4;
+    }
+    len = q - buf;
+    cpu_to_be16wu((uint16_t *)buf, len - 2);
+    return len;
+}
+
+/* mostly same info as PearPc */
+int cdrom_read_toc_raw(int nb_sectors, uint8_t *buf, int msf, int session_num)
+{
+    uint8_t *q;
+    int len;
+
+    q = buf + 2;
+    *q++ = 1; /* first session */
+    *q++ = 1; /* last session */
+
+    *q++ = 1; /* session number */
+    *q++ = 0x14; /* data track */
+    *q++ = 0; /* track number */
+    *q++ = 0xa0; /* lead-in */
+    *q++ = 0; /* min */
+    *q++ = 0; /* sec */
+    *q++ = 0; /* frame */
+    *q++ = 0;
+    *q++ = 1; /* first track */
+    *q++ = 0x00; /* disk type */
+    *q++ = 0x00;
+
+    *q++ = 1; /* session number */
+    *q++ = 0x14; /* data track */
+    *q++ = 0; /* track number */
+    *q++ = 0xa1;
+    *q++ = 0; /* min */
+    *q++ = 0; /* sec */
+    *q++ = 0; /* frame */
+    *q++ = 0;
+    *q++ = 1; /* last track */
+    *q++ = 0x00;
+    *q++ = 0x00;
+
+    *q++ = 1; /* session number */
+    *q++ = 0x14; /* data track */
+    *q++ = 0; /* track number */
+    *q++ = 0xa2; /* lead-out */
+    *q++ = 0; /* min */
+    *q++ = 0; /* sec */
+    *q++ = 0; /* frame */
+    if (msf) {
+        *q++ = 0; /* reserved */
+        lba_to_msf(q, nb_sectors);
+        q += 3;
+    } else {
+        cpu_to_be32wu((uint32_t *)q, nb_sectors);
+        q += 4;
+    }
+
+    *q++ = 1; /* session number */
+    *q++ = 0x14; /* ADR, control */
+    *q++ = 0;    /* track number */
+    *q++ = 1;    /* point */
+    *q++ = 0; /* min */
+    *q++ = 0; /* sec */
+    *q++ = 0; /* frame */
+    if (msf) {
+        *q++ = 0;
+        lba_to_msf(q, 0);
+        q += 3;
+    } else {
+        *q++ = 0;
+        *q++ = 0;
+        *q++ = 0;
+        *q++ = 0;
+    }
+
+    len = q - buf;
+    cpu_to_be16wu((uint16_t *)buf, len - 2);
+    return len;
+}
diff --git a/hw/block/dataplane/Makefile.objs b/hw/block/dataplane/Makefile.objs
new file mode 100644 (file)
index 0000000..9da2eb8
--- /dev/null
@@ -0,0 +1 @@
+obj-y += ioq.o virtio-blk.o
diff --git a/hw/block/dataplane/ioq.c b/hw/block/dataplane/ioq.c
new file mode 100644 (file)
index 0000000..f709f87
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * Linux AIO request queue
+ *
+ * Copyright 2012 IBM, Corp.
+ * Copyright 2012 Red Hat, Inc. and/or its affiliates
+ *
+ * Authors:
+ *   Stefan Hajnoczi <stefanha@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 "ioq.h"
+
+void ioq_init(IOQueue *ioq, int fd, unsigned int max_reqs)
+{
+    int rc;
+
+    ioq->fd = fd;
+    ioq->max_reqs = max_reqs;
+
+    memset(&ioq->io_ctx, 0, sizeof ioq->io_ctx);
+    rc = io_setup(max_reqs, &ioq->io_ctx);
+    if (rc != 0) {
+        fprintf(stderr, "ioq io_setup failed %d\n", rc);
+        exit(1);
+    }
+
+    rc = event_notifier_init(&ioq->io_notifier, 0);
+    if (rc != 0) {
+        fprintf(stderr, "ioq io event notifier creation failed %d\n", rc);
+        exit(1);
+    }
+
+    ioq->freelist = g_malloc0(sizeof ioq->freelist[0] * max_reqs);
+    ioq->freelist_idx = 0;
+
+    ioq->queue = g_malloc0(sizeof ioq->queue[0] * max_reqs);
+    ioq->queue_idx = 0;
+}
+
+void ioq_cleanup(IOQueue *ioq)
+{
+    g_free(ioq->freelist);
+    g_free(ioq->queue);
+
+    event_notifier_cleanup(&ioq->io_notifier);
+    io_destroy(ioq->io_ctx);
+}
+
+EventNotifier *ioq_get_notifier(IOQueue *ioq)
+{
+    return &ioq->io_notifier;
+}
+
+struct iocb *ioq_get_iocb(IOQueue *ioq)
+{
+    /* Underflow cannot happen since ioq is sized for max_reqs */
+    assert(ioq->freelist_idx != 0);
+
+    struct iocb *iocb = ioq->freelist[--ioq->freelist_idx];
+    ioq->queue[ioq->queue_idx++] = iocb;
+    return iocb;
+}
+
+void ioq_put_iocb(IOQueue *ioq, struct iocb *iocb)
+{
+    /* Overflow cannot happen since ioq is sized for max_reqs */
+    assert(ioq->freelist_idx != ioq->max_reqs);
+
+    ioq->freelist[ioq->freelist_idx++] = iocb;
+}
+
+struct iocb *ioq_rdwr(IOQueue *ioq, bool read, struct iovec *iov,
+                      unsigned int count, long long offset)
+{
+    struct iocb *iocb = ioq_get_iocb(ioq);
+
+    if (read) {
+        io_prep_preadv(iocb, ioq->fd, iov, count, offset);
+    } else {
+        io_prep_pwritev(iocb, ioq->fd, iov, count, offset);
+    }
+    io_set_eventfd(iocb, event_notifier_get_fd(&ioq->io_notifier));
+    return iocb;
+}
+
+int ioq_submit(IOQueue *ioq)
+{
+    int rc = io_submit(ioq->io_ctx, ioq->queue_idx, ioq->queue);
+    ioq->queue_idx = 0; /* reset */
+    return rc;
+}
+
+int ioq_run_completion(IOQueue *ioq, IOQueueCompletion *completion,
+                       void *opaque)
+{
+    struct io_event events[ioq->max_reqs];
+    int nevents, i;
+
+    do {
+        nevents = io_getevents(ioq->io_ctx, 0, ioq->max_reqs, events, NULL);
+    } while (nevents < 0 && errno == EINTR);
+    if (nevents < 0) {
+        return nevents;
+    }
+
+    for (i = 0; i < nevents; i++) {
+        ssize_t ret = ((uint64_t)events[i].res2 << 32) | events[i].res;
+
+        completion(events[i].obj, ret, opaque);
+        ioq_put_iocb(ioq, events[i].obj);
+    }
+    return nevents;
+}
diff --git a/hw/block/dataplane/ioq.h b/hw/block/dataplane/ioq.h
new file mode 100644 (file)
index 0000000..b49b5de
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Linux AIO request queue
+ *
+ * Copyright 2012 IBM, Corp.
+ * Copyright 2012 Red Hat, Inc. and/or its affiliates
+ *
+ * Authors:
+ *   Stefan Hajnoczi <stefanha@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 IOQ_H
+#define IOQ_H
+
+#include <libaio.h>
+#include "qemu/event_notifier.h"
+
+typedef struct {
+    int fd;                         /* file descriptor */
+    unsigned int max_reqs;          /* max length of freelist and queue */
+
+    io_context_t io_ctx;            /* Linux AIO context */
+    EventNotifier io_notifier;      /* Linux AIO eventfd */
+
+    /* Requests can complete in any order so a free list is necessary to manage
+     * available iocbs.
+     */
+    struct iocb **freelist;         /* free iocbs */
+    unsigned int freelist_idx;
+
+    /* Multiple requests are queued up before submitting them all in one go */
+    struct iocb **queue;            /* queued iocbs */
+    unsigned int queue_idx;
+} IOQueue;
+
+void ioq_init(IOQueue *ioq, int fd, unsigned int max_reqs);
+void ioq_cleanup(IOQueue *ioq);
+EventNotifier *ioq_get_notifier(IOQueue *ioq);
+struct iocb *ioq_get_iocb(IOQueue *ioq);
+void ioq_put_iocb(IOQueue *ioq, struct iocb *iocb);
+struct iocb *ioq_rdwr(IOQueue *ioq, bool read, struct iovec *iov,
+                      unsigned int count, long long offset);
+int ioq_submit(IOQueue *ioq);
+
+static inline unsigned int ioq_num_queued(IOQueue *ioq)
+{
+    return ioq->queue_idx;
+}
+
+typedef void IOQueueCompletion(struct iocb *iocb, ssize_t ret, void *opaque);
+int ioq_run_completion(IOQueue *ioq, IOQueueCompletion *completion,
+                       void *opaque);
+
+#endif /* IOQ_H */
diff --git a/hw/block/dataplane/virtio-blk.c b/hw/block/dataplane/virtio-blk.c
new file mode 100644 (file)
index 0000000..5baef23
--- /dev/null
@@ -0,0 +1,540 @@
+/*
+ * Dedicated thread for virtio-blk I/O processing
+ *
+ * Copyright 2012 IBM, Corp.
+ * Copyright 2012 Red Hat, Inc. and/or its affiliates
+ *
+ * Authors:
+ *   Stefan Hajnoczi <stefanha@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 "trace.h"
+#include "qemu/iov.h"
+#include "qemu/thread.h"
+#include "qemu/error-report.h"
+#include "hw/virtio/dataplane/vring.h"
+#include "ioq.h"
+#include "migration/migration.h"
+#include "block/block.h"
+#include "hw/virtio/virtio-blk.h"
+#include "virtio-blk.h"
+#include "block/aio.h"
+
+enum {
+    SEG_MAX = 126,                  /* maximum number of I/O segments */
+    VRING_MAX = SEG_MAX + 2,        /* maximum number of vring descriptors */
+    REQ_MAX = VRING_MAX,            /* maximum number of requests in the vring,
+                                     * is VRING_MAX / 2 with traditional and
+                                     * VRING_MAX with indirect descriptors */
+};
+
+typedef struct {
+    struct iocb iocb;               /* Linux AIO control block */
+    QEMUIOVector *inhdr;            /* iovecs for virtio_blk_inhdr */
+    unsigned int head;              /* vring descriptor index */
+    struct iovec *bounce_iov;       /* used if guest buffers are unaligned */
+    QEMUIOVector *read_qiov;        /* for read completion /w bounce buffer */
+} VirtIOBlockRequest;
+
+struct VirtIOBlockDataPlane {
+    bool started;
+    bool stopping;
+    QEMUBH *start_bh;
+    QemuThread thread;
+
+    VirtIOBlkConf *blk;
+    int fd;                         /* image file descriptor */
+
+    VirtIODevice *vdev;
+    Vring vring;                    /* virtqueue vring */
+    EventNotifier *guest_notifier;  /* irq */
+
+    /* Note that these EventNotifiers are assigned by value.  This is
+     * fine as long as you do not call event_notifier_cleanup on them
+     * (because you don't own the file descriptor or handle; you just
+     * use it).
+     */
+    AioContext *ctx;
+    EventNotifier io_notifier;      /* Linux AIO completion */
+    EventNotifier host_notifier;    /* doorbell */
+
+    IOQueue ioqueue;                /* Linux AIO queue (should really be per
+                                       dataplane thread) */
+    VirtIOBlockRequest requests[REQ_MAX]; /* pool of requests, managed by the
+                                             queue */
+
+    unsigned int num_reqs;
+
+    Error *migration_blocker;
+};
+
+/* Raise an interrupt to signal guest, if necessary */
+static void notify_guest(VirtIOBlockDataPlane *s)
+{
+    if (!vring_should_notify(s->vdev, &s->vring)) {
+        return;
+    }
+
+    event_notifier_set(s->guest_notifier);
+}
+
+static void complete_request(struct iocb *iocb, ssize_t ret, void *opaque)
+{
+    VirtIOBlockDataPlane *s = opaque;
+    VirtIOBlockRequest *req = container_of(iocb, VirtIOBlockRequest, iocb);
+    struct virtio_blk_inhdr hdr;
+    int len;
+
+    if (likely(ret >= 0)) {
+        hdr.status = VIRTIO_BLK_S_OK;
+        len = ret;
+    } else {
+        hdr.status = VIRTIO_BLK_S_IOERR;
+        len = 0;
+    }
+
+    trace_virtio_blk_data_plane_complete_request(s, req->head, ret);
+
+    if (req->read_qiov) {
+        assert(req->bounce_iov);
+        qemu_iovec_from_buf(req->read_qiov, 0, req->bounce_iov->iov_base, len);
+        qemu_iovec_destroy(req->read_qiov);
+        g_slice_free(QEMUIOVector, req->read_qiov);
+    }
+
+    if (req->bounce_iov) {
+        qemu_vfree(req->bounce_iov->iov_base);
+        g_slice_free(struct iovec, req->bounce_iov);
+    }
+
+    qemu_iovec_from_buf(req->inhdr, 0, &hdr, sizeof(hdr));
+    qemu_iovec_destroy(req->inhdr);
+    g_slice_free(QEMUIOVector, req->inhdr);
+
+    /* According to the virtio specification len should be the number of bytes
+     * written to, but for virtio-blk it seems to be the number of bytes
+     * transferred plus the status bytes.
+     */
+    vring_push(&s->vring, req->head, len + sizeof(hdr));
+
+    s->num_reqs--;
+}
+
+static void complete_request_early(VirtIOBlockDataPlane *s, unsigned int head,
+                                   QEMUIOVector *inhdr, unsigned char status)
+{
+    struct virtio_blk_inhdr hdr = {
+        .status = status,
+    };
+
+    qemu_iovec_from_buf(inhdr, 0, &hdr, sizeof(hdr));
+    qemu_iovec_destroy(inhdr);
+    g_slice_free(QEMUIOVector, inhdr);
+
+    vring_push(&s->vring, head, sizeof(hdr));
+    notify_guest(s);
+}
+
+/* Get disk serial number */
+static void do_get_id_cmd(VirtIOBlockDataPlane *s,
+                          struct iovec *iov, unsigned int iov_cnt,
+                          unsigned int head, QEMUIOVector *inhdr)
+{
+    char id[VIRTIO_BLK_ID_BYTES];
+
+    /* Serial number not NUL-terminated when shorter than buffer */
+    strncpy(id, s->blk->serial ? s->blk->serial : "", sizeof(id));
+    iov_from_buf(iov, iov_cnt, 0, id, sizeof(id));
+    complete_request_early(s, head, inhdr, VIRTIO_BLK_S_OK);
+}
+
+static int do_rdwr_cmd(VirtIOBlockDataPlane *s, bool read,
+                       struct iovec *iov, unsigned int iov_cnt,
+                       long long offset, unsigned int head,
+                       QEMUIOVector *inhdr)
+{
+    struct iocb *iocb;
+    QEMUIOVector qiov;
+    struct iovec *bounce_iov = NULL;
+    QEMUIOVector *read_qiov = NULL;
+
+    qemu_iovec_init_external(&qiov, iov, iov_cnt);
+    if (!bdrv_qiov_is_aligned(s->blk->conf.bs, &qiov)) {
+        void *bounce_buffer = qemu_blockalign(s->blk->conf.bs, qiov.size);
+
+        if (read) {
+            /* Need to copy back from bounce buffer on completion */
+            read_qiov = g_slice_new(QEMUIOVector);
+            qemu_iovec_init(read_qiov, iov_cnt);
+            qemu_iovec_concat_iov(read_qiov, iov, iov_cnt, 0, qiov.size);
+        } else {
+            qemu_iovec_to_buf(&qiov, 0, bounce_buffer, qiov.size);
+        }
+
+        /* Redirect I/O to aligned bounce buffer */
+        bounce_iov = g_slice_new(struct iovec);
+        bounce_iov->iov_base = bounce_buffer;
+        bounce_iov->iov_len = qiov.size;
+        iov = bounce_iov;
+        iov_cnt = 1;
+    }
+
+    iocb = ioq_rdwr(&s->ioqueue, read, iov, iov_cnt, offset);
+
+    /* Fill in virtio block metadata needed for completion */
+    VirtIOBlockRequest *req = container_of(iocb, VirtIOBlockRequest, iocb);
+    req->head = head;
+    req->inhdr = inhdr;
+    req->bounce_iov = bounce_iov;
+    req->read_qiov = read_qiov;
+    return 0;
+}
+
+static int process_request(IOQueue *ioq, struct iovec iov[],
+                           unsigned int out_num, unsigned int in_num,
+                           unsigned int head)
+{
+    VirtIOBlockDataPlane *s = container_of(ioq, VirtIOBlockDataPlane, ioqueue);
+    struct iovec *in_iov = &iov[out_num];
+    struct virtio_blk_outhdr outhdr;
+    QEMUIOVector *inhdr;
+    size_t in_size;
+
+    /* Copy in outhdr */
+    if (unlikely(iov_to_buf(iov, out_num, 0, &outhdr,
+                            sizeof(outhdr)) != sizeof(outhdr))) {
+        error_report("virtio-blk request outhdr too short");
+        return -EFAULT;
+    }
+    iov_discard_front(&iov, &out_num, sizeof(outhdr));
+
+    /* Grab inhdr for later */
+    in_size = iov_size(in_iov, in_num);
+    if (in_size < sizeof(struct virtio_blk_inhdr)) {
+        error_report("virtio_blk request inhdr too short");
+        return -EFAULT;
+    }
+    inhdr = g_slice_new(QEMUIOVector);
+    qemu_iovec_init(inhdr, 1);
+    qemu_iovec_concat_iov(inhdr, in_iov, in_num,
+            in_size - sizeof(struct virtio_blk_inhdr),
+            sizeof(struct virtio_blk_inhdr));
+    iov_discard_back(in_iov, &in_num, sizeof(struct virtio_blk_inhdr));
+
+    /* TODO Linux sets the barrier bit even when not advertised! */
+    outhdr.type &= ~VIRTIO_BLK_T_BARRIER;
+
+    switch (outhdr.type) {
+    case VIRTIO_BLK_T_IN:
+        do_rdwr_cmd(s, true, in_iov, in_num, outhdr.sector * 512, head, inhdr);
+        return 0;
+
+    case VIRTIO_BLK_T_OUT:
+        do_rdwr_cmd(s, false, iov, out_num, outhdr.sector * 512, head, inhdr);
+        return 0;
+
+    case VIRTIO_BLK_T_SCSI_CMD:
+        /* TODO support SCSI commands */
+        complete_request_early(s, head, inhdr, VIRTIO_BLK_S_UNSUPP);
+        return 0;
+
+    case VIRTIO_BLK_T_FLUSH:
+        /* TODO fdsync not supported by Linux AIO, do it synchronously here! */
+        if (qemu_fdatasync(s->fd) < 0) {
+            complete_request_early(s, head, inhdr, VIRTIO_BLK_S_IOERR);
+        } else {
+            complete_request_early(s, head, inhdr, VIRTIO_BLK_S_OK);
+        }
+        return 0;
+
+    case VIRTIO_BLK_T_GET_ID:
+        do_get_id_cmd(s, in_iov, in_num, head, inhdr);
+        return 0;
+
+    default:
+        error_report("virtio-blk unsupported request type %#x", outhdr.type);
+        qemu_iovec_destroy(inhdr);
+        g_slice_free(QEMUIOVector, inhdr);
+        return -EFAULT;
+    }
+}
+
+static int flush_true(EventNotifier *e)
+{
+    return true;
+}
+
+static void handle_notify(EventNotifier *e)
+{
+    VirtIOBlockDataPlane *s = container_of(e, VirtIOBlockDataPlane,
+                                           host_notifier);
+
+    /* There is one array of iovecs into which all new requests are extracted
+     * from the vring.  Requests are read from the vring and the translated
+     * descriptors are written to the iovecs array.  The iovecs do not have to
+     * persist across handle_notify() calls because the kernel copies the
+     * iovecs on io_submit().
+     *
+     * Handling io_submit() EAGAIN may require storing the requests across
+     * handle_notify() calls until the kernel has sufficient resources to
+     * accept more I/O.  This is not implemented yet.
+     */
+    struct iovec iovec[VRING_MAX];
+    struct iovec *end = &iovec[VRING_MAX];
+    struct iovec *iov = iovec;
+
+    /* When a request is read from the vring, the index of the first descriptor
+     * (aka head) is returned so that the completed request can be pushed onto
+     * the vring later.
+     *
+     * The number of hypervisor read-only iovecs is out_num.  The number of
+     * hypervisor write-only iovecs is in_num.
+     */
+    int head;
+    unsigned int out_num = 0, in_num = 0;
+    unsigned int num_queued;
+
+    event_notifier_test_and_clear(&s->host_notifier);
+    for (;;) {
+        /* Disable guest->host notifies to avoid unnecessary vmexits */
+        vring_disable_notification(s->vdev, &s->vring);
+
+        for (;;) {
+            head = vring_pop(s->vdev, &s->vring, iov, end, &out_num, &in_num);
+            if (head < 0) {
+                break; /* no more requests */
+            }
+
+            trace_virtio_blk_data_plane_process_request(s, out_num, in_num,
+                                                        head);
+
+            if (process_request(&s->ioqueue, iov, out_num, in_num, head) < 0) {
+                vring_set_broken(&s->vring);
+                break;
+            }
+            iov += out_num + in_num;
+        }
+
+        if (likely(head == -EAGAIN)) { /* vring emptied */
+            /* Re-enable guest->host notifies and stop processing the vring.
+             * But if the guest has snuck in more descriptors, keep processing.
+             */
+            if (vring_enable_notification(s->vdev, &s->vring)) {
+                break;
+            }
+        } else { /* head == -ENOBUFS or fatal error, iovecs[] is depleted */
+            /* Since there are no iovecs[] left, stop processing for now.  Do
+             * not re-enable guest->host notifies since the I/O completion
+             * handler knows to check for more vring descriptors anyway.
+             */
+            break;
+        }
+    }
+
+    num_queued = ioq_num_queued(&s->ioqueue);
+    if (num_queued > 0) {
+        s->num_reqs += num_queued;
+
+        int rc = ioq_submit(&s->ioqueue);
+        if (unlikely(rc < 0)) {
+            fprintf(stderr, "ioq_submit failed %d\n", rc);
+            exit(1);
+        }
+    }
+}
+
+static int flush_io(EventNotifier *e)
+{
+    VirtIOBlockDataPlane *s = container_of(e, VirtIOBlockDataPlane,
+                                           io_notifier);
+
+    return s->num_reqs > 0;
+}
+
+static void handle_io(EventNotifier *e)
+{
+    VirtIOBlockDataPlane *s = container_of(e, VirtIOBlockDataPlane,
+                                           io_notifier);
+
+    event_notifier_test_and_clear(&s->io_notifier);
+    if (ioq_run_completion(&s->ioqueue, complete_request, s) > 0) {
+        notify_guest(s);
+    }
+
+    /* If there were more requests than iovecs, the vring will not be empty yet
+     * so check again.  There should now be enough resources to process more
+     * requests.
+     */
+    if (unlikely(vring_more_avail(&s->vring))) {
+        handle_notify(&s->host_notifier);
+    }
+}
+
+static void *data_plane_thread(void *opaque)
+{
+    VirtIOBlockDataPlane *s = opaque;
+
+    do {
+        aio_poll(s->ctx, true);
+    } while (!s->stopping || s->num_reqs > 0);
+    return NULL;
+}
+
+static void start_data_plane_bh(void *opaque)
+{
+    VirtIOBlockDataPlane *s = opaque;
+
+    qemu_bh_delete(s->start_bh);
+    s->start_bh = NULL;
+    qemu_thread_create(&s->thread, data_plane_thread,
+                       s, QEMU_THREAD_JOINABLE);
+}
+
+bool virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *blk,
+                                  VirtIOBlockDataPlane **dataplane)
+{
+    VirtIOBlockDataPlane *s;
+    int fd;
+
+    *dataplane = NULL;
+
+    if (!blk->data_plane) {
+        return true;
+    }
+
+    if (blk->scsi) {
+        error_report("device is incompatible with x-data-plane, use scsi=off");
+        return false;
+    }
+
+    if (blk->config_wce) {
+        error_report("device is incompatible with x-data-plane, "
+                     "use config-wce=off");
+        return false;
+    }
+
+    fd = raw_get_aio_fd(blk->conf.bs);
+    if (fd < 0) {
+        error_report("drive is incompatible with x-data-plane, "
+                     "use format=raw,cache=none,aio=native");
+        return false;
+    }
+
+    s = g_new0(VirtIOBlockDataPlane, 1);
+    s->vdev = vdev;
+    s->fd = fd;
+    s->blk = blk;
+
+    /* Prevent block operations that conflict with data plane thread */
+    bdrv_set_in_use(blk->conf.bs, 1);
+
+    error_setg(&s->migration_blocker,
+            "x-data-plane does not support migration");
+    migrate_add_blocker(s->migration_blocker);
+
+    *dataplane = s;
+    return true;
+}
+
+void virtio_blk_data_plane_destroy(VirtIOBlockDataPlane *s)
+{
+    if (!s) {
+        return;
+    }
+
+    virtio_blk_data_plane_stop(s);
+    migrate_del_blocker(s->migration_blocker);
+    error_free(s->migration_blocker);
+    bdrv_set_in_use(s->blk->conf.bs, 0);
+    g_free(s);
+}
+
+void virtio_blk_data_plane_start(VirtIOBlockDataPlane *s)
+{
+    VirtQueue *vq;
+    int i;
+
+    if (s->started) {
+        return;
+    }
+
+    vq = virtio_get_queue(s->vdev, 0);
+    if (!vring_setup(&s->vring, s->vdev, 0)) {
+        return;
+    }
+
+    s->ctx = aio_context_new();
+
+    /* Set up guest notifier (irq) */
+    if (s->vdev->binding->set_guest_notifiers(s->vdev->binding_opaque, 1,
+                                              true) != 0) {
+        fprintf(stderr, "virtio-blk failed to set guest notifier, "
+                "ensure -enable-kvm is set\n");
+        exit(1);
+    }
+    s->guest_notifier = virtio_queue_get_guest_notifier(vq);
+
+    /* Set up virtqueue notify */
+    if (s->vdev->binding->set_host_notifier(s->vdev->binding_opaque,
+                                            0, true) != 0) {
+        fprintf(stderr, "virtio-blk failed to set host notifier\n");
+        exit(1);
+    }
+    s->host_notifier = *virtio_queue_get_host_notifier(vq);
+    aio_set_event_notifier(s->ctx, &s->host_notifier, handle_notify, flush_true);
+
+    /* Set up ioqueue */
+    ioq_init(&s->ioqueue, s->fd, REQ_MAX);
+    for (i = 0; i < ARRAY_SIZE(s->requests); i++) {
+        ioq_put_iocb(&s->ioqueue, &s->requests[i].iocb);
+    }
+    s->io_notifier = *ioq_get_notifier(&s->ioqueue);
+    aio_set_event_notifier(s->ctx, &s->io_notifier, handle_io, flush_io);
+
+    s->started = true;
+    trace_virtio_blk_data_plane_start(s);
+
+    /* Kick right away to begin processing requests already in vring */
+    event_notifier_set(virtio_queue_get_host_notifier(vq));
+
+    /* Spawn thread in BH so it inherits iothread cpusets */
+    s->start_bh = qemu_bh_new(start_data_plane_bh, s);
+    qemu_bh_schedule(s->start_bh);
+}
+
+void virtio_blk_data_plane_stop(VirtIOBlockDataPlane *s)
+{
+    if (!s->started || s->stopping) {
+        return;
+    }
+    s->stopping = true;
+    trace_virtio_blk_data_plane_stop(s);
+
+    /* Stop thread or cancel pending thread creation BH */
+    if (s->start_bh) {
+        qemu_bh_delete(s->start_bh);
+        s->start_bh = NULL;
+    } else {
+        aio_notify(s->ctx);
+        qemu_thread_join(&s->thread);
+    }
+
+    aio_set_event_notifier(s->ctx, &s->io_notifier, NULL, NULL);
+    ioq_cleanup(&s->ioqueue);
+
+    aio_set_event_notifier(s->ctx, &s->host_notifier, NULL, NULL);
+    s->vdev->binding->set_host_notifier(s->vdev->binding_opaque, 0, false);
+
+    aio_context_unref(s->ctx);
+
+    /* Clean up guest notifier (irq) */
+    s->vdev->binding->set_guest_notifiers(s->vdev->binding_opaque, 1, false);
+
+    vring_teardown(&s->vring);
+    s->started = false;
+    s->stopping = false;
+}
diff --git a/hw/block/dataplane/virtio-blk.h b/hw/block/dataplane/virtio-blk.h
new file mode 100644 (file)
index 0000000..c90e99f
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Dedicated thread for virtio-blk I/O processing
+ *
+ * Copyright 2012 IBM, Corp.
+ * Copyright 2012 Red Hat, Inc. and/or its affiliates
+ *
+ * Authors:
+ *   Stefan Hajnoczi <stefanha@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 HW_DATAPLANE_VIRTIO_BLK_H
+#define HW_DATAPLANE_VIRTIO_BLK_H
+
+#include "hw/virtio/virtio.h"
+
+typedef struct VirtIOBlockDataPlane VirtIOBlockDataPlane;
+
+bool virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *blk,
+                                  VirtIOBlockDataPlane **dataplane);
+void virtio_blk_data_plane_destroy(VirtIOBlockDataPlane *s);
+void virtio_blk_data_plane_start(VirtIOBlockDataPlane *s);
+void virtio_blk_data_plane_stop(VirtIOBlockDataPlane *s);
+void virtio_blk_data_plane_drain(VirtIOBlockDataPlane *s);
+
+#endif /* HW_DATAPLANE_VIRTIO_BLK_H */
diff --git a/hw/block/ecc.c b/hw/block/ecc.c
new file mode 100644 (file)
index 0000000..8c888cc
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Calculate Error-correcting Codes. Used by NAND Flash controllers
+ * (not by NAND chips).
+ *
+ * Copyright (c) 2006 Openedhand Ltd.
+ * Written by Andrzej Zaborowski <balrog@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/hw.h"
+#include "hw/block/flash.h"
+
+/*
+ * Pre-calculated 256-way 1 byte column parity.  Table borrowed from Linux.
+ */
+static const uint8_t nand_ecc_precalc_table[] = {
+    0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a,
+    0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00,
+    0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f,
+    0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
+    0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c,
+    0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
+    0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59,
+    0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
+    0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33,
+    0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
+    0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56,
+    0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
+    0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55,
+    0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
+    0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30,
+    0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
+    0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30,
+    0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
+    0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55,
+    0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
+    0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56,
+    0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
+    0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33,
+    0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
+    0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59,
+    0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
+    0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c,
+    0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
+    0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f,
+    0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
+    0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a,
+    0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00,
+};
+
+/* Update ECC parity count.  */
+uint8_t ecc_digest(ECCState *s, uint8_t sample)
+{
+    uint8_t idx = nand_ecc_precalc_table[sample];
+
+    s->cp ^= idx & 0x3f;
+    if (idx & 0x40) {
+        s->lp[0] ^= ~s->count;
+        s->lp[1] ^= s->count;
+    }
+    s->count ++;
+
+    return sample;
+}
+
+/* Reinitialise the counters.  */
+void ecc_reset(ECCState *s)
+{
+    s->lp[0] = 0x0000;
+    s->lp[1] = 0x0000;
+    s->cp = 0x00;
+    s->count = 0;
+}
+
+/* Save/restore */
+VMStateDescription vmstate_ecc_state = {
+    .name = "ecc-state",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields = (VMStateField []) {
+        VMSTATE_UINT8(cp, ECCState),
+        VMSTATE_UINT16_ARRAY(lp, ECCState, 2),
+        VMSTATE_UINT16(count, ECCState),
+        VMSTATE_END_OF_LIST(),
+    },
+};
diff --git a/hw/block/fdc.c b/hw/block/fdc.c
new file mode 100644 (file)
index 0000000..1ed874f
--- /dev/null
@@ -0,0 +1,2284 @@
+/*
+ * QEMU Floppy disk emulator (Intel 82078)
+ *
+ * Copyright (c) 2003, 2007 Jocelyn Mayer
+ * Copyright (c) 2008 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.
+ */
+/*
+ * The controller is used in Sun4m systems in a slightly different
+ * way. There are changes in DOR register and DMA is not available.
+ */
+
+#include "hw/hw.h"
+#include "hw/block/fdc.h"
+#include "qemu/error-report.h"
+#include "qemu/timer.h"
+#include "hw/isa/isa.h"
+#include "hw/sysbus.h"
+#include "hw/qdev-addr.h"
+#include "sysemu/blockdev.h"
+#include "sysemu/sysemu.h"
+#include "qemu/log.h"
+
+/********************************************************/
+/* debug Floppy devices */
+//#define DEBUG_FLOPPY
+
+#ifdef DEBUG_FLOPPY
+#define FLOPPY_DPRINTF(fmt, ...)                                \
+    do { printf("FLOPPY: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define FLOPPY_DPRINTF(fmt, ...)
+#endif
+
+/********************************************************/
+/* Floppy drive emulation                               */
+
+typedef enum FDriveRate {
+    FDRIVE_RATE_500K = 0x00,  /* 500 Kbps */
+    FDRIVE_RATE_300K = 0x01,  /* 300 Kbps */
+    FDRIVE_RATE_250K = 0x02,  /* 250 Kbps */
+    FDRIVE_RATE_1M   = 0x03,  /*   1 Mbps */
+} FDriveRate;
+
+typedef struct FDFormat {
+    FDriveType drive;
+    uint8_t last_sect;
+    uint8_t max_track;
+    uint8_t max_head;
+    FDriveRate rate;
+} FDFormat;
+
+static const FDFormat fd_formats[] = {
+    /* First entry is default format */
+    /* 1.44 MB 3"1/2 floppy disks */
+    { FDRIVE_DRV_144, 18, 80, 1, FDRIVE_RATE_500K, },
+    { FDRIVE_DRV_144, 20, 80, 1, FDRIVE_RATE_500K, },
+    { FDRIVE_DRV_144, 21, 80, 1, FDRIVE_RATE_500K, },
+    { FDRIVE_DRV_144, 21, 82, 1, FDRIVE_RATE_500K, },
+    { FDRIVE_DRV_144, 21, 83, 1, FDRIVE_RATE_500K, },
+    { FDRIVE_DRV_144, 22, 80, 1, FDRIVE_RATE_500K, },
+    { FDRIVE_DRV_144, 23, 80, 1, FDRIVE_RATE_500K, },
+    { FDRIVE_DRV_144, 24, 80, 1, FDRIVE_RATE_500K, },
+    /* 2.88 MB 3"1/2 floppy disks */
+    { FDRIVE_DRV_288, 36, 80, 1, FDRIVE_RATE_1M, },
+    { FDRIVE_DRV_288, 39, 80, 1, FDRIVE_RATE_1M, },
+    { FDRIVE_DRV_288, 40, 80, 1, FDRIVE_RATE_1M, },
+    { FDRIVE_DRV_288, 44, 80, 1, FDRIVE_RATE_1M, },
+    { FDRIVE_DRV_288, 48, 80, 1, FDRIVE_RATE_1M, },
+    /* 720 kB 3"1/2 floppy disks */
+    { FDRIVE_DRV_144,  9, 80, 1, FDRIVE_RATE_250K, },
+    { FDRIVE_DRV_144, 10, 80, 1, FDRIVE_RATE_250K, },
+    { FDRIVE_DRV_144, 10, 82, 1, FDRIVE_RATE_250K, },
+    { FDRIVE_DRV_144, 10, 83, 1, FDRIVE_RATE_250K, },
+    { FDRIVE_DRV_144, 13, 80, 1, FDRIVE_RATE_250K, },
+    { FDRIVE_DRV_144, 14, 80, 1, FDRIVE_RATE_250K, },
+    /* 1.2 MB 5"1/4 floppy disks */
+    { FDRIVE_DRV_120, 15, 80, 1, FDRIVE_RATE_500K, },
+    { FDRIVE_DRV_120, 18, 80, 1, FDRIVE_RATE_500K, },
+    { FDRIVE_DRV_120, 18, 82, 1, FDRIVE_RATE_500K, },
+    { FDRIVE_DRV_120, 18, 83, 1, FDRIVE_RATE_500K, },
+    { FDRIVE_DRV_120, 20, 80, 1, FDRIVE_RATE_500K, },
+    /* 720 kB 5"1/4 floppy disks */
+    { FDRIVE_DRV_120,  9, 80, 1, FDRIVE_RATE_250K, },
+    { FDRIVE_DRV_120, 11, 80, 1, FDRIVE_RATE_250K, },
+    /* 360 kB 5"1/4 floppy disks */
+    { FDRIVE_DRV_120,  9, 40, 1, FDRIVE_RATE_300K, },
+    { FDRIVE_DRV_120,  9, 40, 0, FDRIVE_RATE_300K, },
+    { FDRIVE_DRV_120, 10, 41, 1, FDRIVE_RATE_300K, },
+    { FDRIVE_DRV_120, 10, 42, 1, FDRIVE_RATE_300K, },
+    /* 320 kB 5"1/4 floppy disks */
+    { FDRIVE_DRV_120,  8, 40, 1, FDRIVE_RATE_250K, },
+    { FDRIVE_DRV_120,  8, 40, 0, FDRIVE_RATE_250K, },
+    /* 360 kB must match 5"1/4 better than 3"1/2... */
+    { FDRIVE_DRV_144,  9, 80, 0, FDRIVE_RATE_250K, },
+    /* end */
+    { FDRIVE_DRV_NONE, -1, -1, 0, 0, },
+};
+
+static void pick_geometry(BlockDriverState *bs, int *nb_heads,
+                          int *max_track, int *last_sect,
+                          FDriveType drive_in, FDriveType *drive,
+                          FDriveRate *rate)
+{
+    const FDFormat *parse;
+    uint64_t nb_sectors, size;
+    int i, first_match, match;
+
+    bdrv_get_geometry(bs, &nb_sectors);
+    match = -1;
+    first_match = -1;
+    for (i = 0; ; i++) {
+        parse = &fd_formats[i];
+        if (parse->drive == FDRIVE_DRV_NONE) {
+            break;
+        }
+        if (drive_in == parse->drive ||
+            drive_in == FDRIVE_DRV_NONE) {
+            size = (parse->max_head + 1) * parse->max_track *
+                parse->last_sect;
+            if (nb_sectors == size) {
+                match = i;
+                break;
+            }
+            if (first_match == -1) {
+                first_match = i;
+            }
+        }
+    }
+    if (match == -1) {
+        if (first_match == -1) {
+            match = 1;
+        } else {
+            match = first_match;
+        }
+        parse = &fd_formats[match];
+    }
+    *nb_heads = parse->max_head + 1;
+    *max_track = parse->max_track;
+    *last_sect = parse->last_sect;
+    *drive = parse->drive;
+    *rate = parse->rate;
+}
+
+#define GET_CUR_DRV(fdctrl) ((fdctrl)->cur_drv)
+#define SET_CUR_DRV(fdctrl, drive) ((fdctrl)->cur_drv = (drive))
+
+/* Will always be a fixed parameter for us */
+#define FD_SECTOR_LEN          512
+#define FD_SECTOR_SC           2   /* Sector size code */
+#define FD_RESET_SENSEI_COUNT  4   /* Number of sense interrupts on RESET */
+
+typedef struct FDCtrl FDCtrl;
+
+/* Floppy disk drive emulation */
+typedef enum FDiskFlags {
+    FDISK_DBL_SIDES  = 0x01,
+} FDiskFlags;
+
+typedef struct FDrive {
+    FDCtrl *fdctrl;
+    BlockDriverState *bs;
+    /* Drive status */
+    FDriveType drive;
+    uint8_t perpendicular;    /* 2.88 MB access mode    */
+    /* Position */
+    uint8_t head;
+    uint8_t track;
+    uint8_t sect;
+    /* Media */
+    FDiskFlags flags;
+    uint8_t last_sect;        /* Nb sector per track    */
+    uint8_t max_track;        /* Nb of tracks           */
+    uint16_t bps;             /* Bytes per sector       */
+    uint8_t ro;               /* Is read-only           */
+    uint8_t media_changed;    /* Is media changed       */
+    uint8_t media_rate;       /* Data rate of medium    */
+} FDrive;
+
+static void fd_init(FDrive *drv)
+{
+    /* Drive */
+    drv->drive = FDRIVE_DRV_NONE;
+    drv->perpendicular = 0;
+    /* Disk */
+    drv->last_sect = 0;
+    drv->max_track = 0;
+}
+
+#define NUM_SIDES(drv) ((drv)->flags & FDISK_DBL_SIDES ? 2 : 1)
+
+static int fd_sector_calc(uint8_t head, uint8_t track, uint8_t sect,
+                          uint8_t last_sect, uint8_t num_sides)
+{
+    return (((track * num_sides) + head) * last_sect) + sect - 1;
+}
+
+/* Returns current position, in sectors, for given drive */
+static int fd_sector(FDrive *drv)
+{
+    return fd_sector_calc(drv->head, drv->track, drv->sect, drv->last_sect,
+                          NUM_SIDES(drv));
+}
+
+/* Seek to a new position:
+ * returns 0 if already on right track
+ * returns 1 if track changed
+ * returns 2 if track is invalid
+ * returns 3 if sector is invalid
+ * returns 4 if seek is disabled
+ */
+static int fd_seek(FDrive *drv, uint8_t head, uint8_t track, uint8_t sect,
+                   int enable_seek)
+{
+    uint32_t sector;
+    int ret;
+
+    if (track > drv->max_track ||
+        (head != 0 && (drv->flags & FDISK_DBL_SIDES) == 0)) {
+        FLOPPY_DPRINTF("try to read %d %02x %02x (max=%d %d %02x %02x)\n",
+                       head, track, sect, 1,
+                       (drv->flags & FDISK_DBL_SIDES) == 0 ? 0 : 1,
+                       drv->max_track, drv->last_sect);
+        return 2;
+    }
+    if (sect > drv->last_sect) {
+        FLOPPY_DPRINTF("try to read %d %02x %02x (max=%d %d %02x %02x)\n",
+                       head, track, sect, 1,
+                       (drv->flags & FDISK_DBL_SIDES) == 0 ? 0 : 1,
+                       drv->max_track, drv->last_sect);
+        return 3;
+    }
+    sector = fd_sector_calc(head, track, sect, drv->last_sect, NUM_SIDES(drv));
+    ret = 0;
+    if (sector != fd_sector(drv)) {
+#if 0
+        if (!enable_seek) {
+            FLOPPY_DPRINTF("error: no implicit seek %d %02x %02x"
+                           " (max=%d %02x %02x)\n",
+                           head, track, sect, 1, drv->max_track,
+                           drv->last_sect);
+            return 4;
+        }
+#endif
+        drv->head = head;
+        if (drv->track != track) {
+            if (drv->bs != NULL && bdrv_is_inserted(drv->bs)) {
+                drv->media_changed = 0;
+            }
+            ret = 1;
+        }
+        drv->track = track;
+        drv->sect = sect;
+    }
+
+    if (drv->bs == NULL || !bdrv_is_inserted(drv->bs)) {
+        ret = 2;
+    }
+
+    return ret;
+}
+
+/* Set drive back to track 0 */
+static void fd_recalibrate(FDrive *drv)
+{
+    FLOPPY_DPRINTF("recalibrate\n");
+    fd_seek(drv, 0, 0, 1, 1);
+}
+
+/* Revalidate a disk drive after a disk change */
+static void fd_revalidate(FDrive *drv)
+{
+    int nb_heads, max_track, last_sect, ro;
+    FDriveType drive;
+    FDriveRate rate;
+
+    FLOPPY_DPRINTF("revalidate\n");
+    if (drv->bs != NULL) {
+        ro = bdrv_is_read_only(drv->bs);
+        pick_geometry(drv->bs, &nb_heads, &max_track,
+                      &last_sect, drv->drive, &drive, &rate);
+        if (!bdrv_is_inserted(drv->bs)) {
+            FLOPPY_DPRINTF("No disk in drive\n");
+        } else {
+            FLOPPY_DPRINTF("Floppy disk (%d h %d t %d s) %s\n", nb_heads,
+                           max_track, last_sect, ro ? "ro" : "rw");
+        }
+        if (nb_heads == 1) {
+            drv->flags &= ~FDISK_DBL_SIDES;
+        } else {
+            drv->flags |= FDISK_DBL_SIDES;
+        }
+        drv->max_track = max_track;
+        drv->last_sect = last_sect;
+        drv->ro = ro;
+        drv->drive = drive;
+        drv->media_rate = rate;
+    } else {
+        FLOPPY_DPRINTF("No drive connected\n");
+        drv->last_sect = 0;
+        drv->max_track = 0;
+        drv->flags &= ~FDISK_DBL_SIDES;
+    }
+}
+
+/********************************************************/
+/* Intel 82078 floppy disk controller emulation          */
+
+static void fdctrl_reset(FDCtrl *fdctrl, int do_irq);
+static void fdctrl_reset_fifo(FDCtrl *fdctrl);
+static int fdctrl_transfer_handler (void *opaque, int nchan,
+                                    int dma_pos, int dma_len);
+static void fdctrl_raise_irq(FDCtrl *fdctrl);
+static FDrive *get_cur_drv(FDCtrl *fdctrl);
+
+static uint32_t fdctrl_read_statusA(FDCtrl *fdctrl);
+static uint32_t fdctrl_read_statusB(FDCtrl *fdctrl);
+static uint32_t fdctrl_read_dor(FDCtrl *fdctrl);
+static void fdctrl_write_dor(FDCtrl *fdctrl, uint32_t value);
+static uint32_t fdctrl_read_tape(FDCtrl *fdctrl);
+static void fdctrl_write_tape(FDCtrl *fdctrl, uint32_t value);
+static uint32_t fdctrl_read_main_status(FDCtrl *fdctrl);
+static void fdctrl_write_rate(FDCtrl *fdctrl, uint32_t value);
+static uint32_t fdctrl_read_data(FDCtrl *fdctrl);
+static void fdctrl_write_data(FDCtrl *fdctrl, uint32_t value);
+static uint32_t fdctrl_read_dir(FDCtrl *fdctrl);
+static void fdctrl_write_ccr(FDCtrl *fdctrl, uint32_t value);
+
+enum {
+    FD_DIR_WRITE   = 0,
+    FD_DIR_READ    = 1,
+    FD_DIR_SCANE   = 2,
+    FD_DIR_SCANL   = 3,
+    FD_DIR_SCANH   = 4,
+    FD_DIR_VERIFY  = 5,
+};
+
+enum {
+    FD_STATE_MULTI  = 0x01,    /* multi track flag */
+    FD_STATE_FORMAT = 0x02,    /* format flag */
+};
+
+enum {
+    FD_REG_SRA = 0x00,
+    FD_REG_SRB = 0x01,
+    FD_REG_DOR = 0x02,
+    FD_REG_TDR = 0x03,
+    FD_REG_MSR = 0x04,
+    FD_REG_DSR = 0x04,
+    FD_REG_FIFO = 0x05,
+    FD_REG_DIR = 0x07,
+    FD_REG_CCR = 0x07,
+};
+
+enum {
+    FD_CMD_READ_TRACK = 0x02,
+    FD_CMD_SPECIFY = 0x03,
+    FD_CMD_SENSE_DRIVE_STATUS = 0x04,
+    FD_CMD_WRITE = 0x05,
+    FD_CMD_READ = 0x06,
+    FD_CMD_RECALIBRATE = 0x07,
+    FD_CMD_SENSE_INTERRUPT_STATUS = 0x08,
+    FD_CMD_WRITE_DELETED = 0x09,
+    FD_CMD_READ_ID = 0x0a,
+    FD_CMD_READ_DELETED = 0x0c,
+    FD_CMD_FORMAT_TRACK = 0x0d,
+    FD_CMD_DUMPREG = 0x0e,
+    FD_CMD_SEEK = 0x0f,
+    FD_CMD_VERSION = 0x10,
+    FD_CMD_SCAN_EQUAL = 0x11,
+    FD_CMD_PERPENDICULAR_MODE = 0x12,
+    FD_CMD_CONFIGURE = 0x13,
+    FD_CMD_LOCK = 0x14,
+    FD_CMD_VERIFY = 0x16,
+    FD_CMD_POWERDOWN_MODE = 0x17,
+    FD_CMD_PART_ID = 0x18,
+    FD_CMD_SCAN_LOW_OR_EQUAL = 0x19,
+    FD_CMD_SCAN_HIGH_OR_EQUAL = 0x1d,
+    FD_CMD_SAVE = 0x2e,
+    FD_CMD_OPTION = 0x33,
+    FD_CMD_RESTORE = 0x4e,
+    FD_CMD_DRIVE_SPECIFICATION_COMMAND = 0x8e,
+    FD_CMD_RELATIVE_SEEK_OUT = 0x8f,
+    FD_CMD_FORMAT_AND_WRITE = 0xcd,
+    FD_CMD_RELATIVE_SEEK_IN = 0xcf,
+};
+
+enum {
+    FD_CONFIG_PRETRK = 0xff, /* Pre-compensation set to track 0 */
+    FD_CONFIG_FIFOTHR = 0x0f, /* FIFO threshold set to 1 byte */
+    FD_CONFIG_POLL  = 0x10, /* Poll enabled */
+    FD_CONFIG_EFIFO = 0x20, /* FIFO disabled */
+    FD_CONFIG_EIS   = 0x40, /* No implied seeks */
+};
+
+enum {
+    FD_SR0_DS0      = 0x01,
+    FD_SR0_DS1      = 0x02,
+    FD_SR0_HEAD     = 0x04,
+    FD_SR0_EQPMT    = 0x10,
+    FD_SR0_SEEK     = 0x20,
+    FD_SR0_ABNTERM  = 0x40,
+    FD_SR0_INVCMD   = 0x80,
+    FD_SR0_RDYCHG   = 0xc0,
+};
+
+enum {
+    FD_SR1_MA       = 0x01, /* Missing address mark */
+    FD_SR1_NW       = 0x02, /* Not writable */
+    FD_SR1_EC       = 0x80, /* End of cylinder */
+};
+
+enum {
+    FD_SR2_SNS      = 0x04, /* Scan not satisfied */
+    FD_SR2_SEH      = 0x08, /* Scan equal hit */
+};
+
+enum {
+    FD_SRA_DIR      = 0x01,
+    FD_SRA_nWP      = 0x02,
+    FD_SRA_nINDX    = 0x04,
+    FD_SRA_HDSEL    = 0x08,
+    FD_SRA_nTRK0    = 0x10,
+    FD_SRA_STEP     = 0x20,
+    FD_SRA_nDRV2    = 0x40,
+    FD_SRA_INTPEND  = 0x80,
+};
+
+enum {
+    FD_SRB_MTR0     = 0x01,
+    FD_SRB_MTR1     = 0x02,
+    FD_SRB_WGATE    = 0x04,
+    FD_SRB_RDATA    = 0x08,
+    FD_SRB_WDATA    = 0x10,
+    FD_SRB_DR0      = 0x20,
+};
+
+enum {
+#if MAX_FD == 4
+    FD_DOR_SELMASK  = 0x03,
+#else
+    FD_DOR_SELMASK  = 0x01,
+#endif
+    FD_DOR_nRESET   = 0x04,
+    FD_DOR_DMAEN    = 0x08,
+    FD_DOR_MOTEN0   = 0x10,
+    FD_DOR_MOTEN1   = 0x20,
+    FD_DOR_MOTEN2   = 0x40,
+    FD_DOR_MOTEN3   = 0x80,
+};
+
+enum {
+#if MAX_FD == 4
+    FD_TDR_BOOTSEL  = 0x0c,
+#else
+    FD_TDR_BOOTSEL  = 0x04,
+#endif
+};
+
+enum {
+    FD_DSR_DRATEMASK= 0x03,
+    FD_DSR_PWRDOWN  = 0x40,
+    FD_DSR_SWRESET  = 0x80,
+};
+
+enum {
+    FD_MSR_DRV0BUSY = 0x01,
+    FD_MSR_DRV1BUSY = 0x02,
+    FD_MSR_DRV2BUSY = 0x04,
+    FD_MSR_DRV3BUSY = 0x08,
+    FD_MSR_CMDBUSY  = 0x10,
+    FD_MSR_NONDMA   = 0x20,
+    FD_MSR_DIO      = 0x40,
+    FD_MSR_RQM      = 0x80,
+};
+
+enum {
+    FD_DIR_DSKCHG   = 0x80,
+};
+
+#define FD_MULTI_TRACK(state) ((state) & FD_STATE_MULTI)
+#define FD_FORMAT_CMD(state) ((state) & FD_STATE_FORMAT)
+
+struct FDCtrl {
+    MemoryRegion iomem;
+    qemu_irq irq;
+    /* Controller state */
+    QEMUTimer *result_timer;
+    int dma_chann;
+    /* Controller's identification */
+    uint8_t version;
+    /* HW */
+    uint8_t sra;
+    uint8_t srb;
+    uint8_t dor;
+    uint8_t dor_vmstate; /* only used as temp during vmstate */
+    uint8_t tdr;
+    uint8_t dsr;
+    uint8_t msr;
+    uint8_t cur_drv;
+    uint8_t status0;
+    uint8_t status1;
+    uint8_t status2;
+    /* Command FIFO */
+    uint8_t *fifo;
+    int32_t fifo_size;
+    uint32_t data_pos;
+    uint32_t data_len;
+    uint8_t data_state;
+    uint8_t data_dir;
+    uint8_t eot; /* last wanted sector */
+    /* States kept only to be returned back */
+    /* precompensation */
+    uint8_t precomp_trk;
+    uint8_t config;
+    uint8_t lock;
+    /* Power down config (also with status regB access mode */
+    uint8_t pwrd;
+    /* Floppy drives */
+    uint8_t num_floppies;
+    /* Sun4m quirks? */
+    int sun4m;
+    FDrive drives[MAX_FD];
+    int reset_sensei;
+    uint32_t check_media_rate;
+    /* Timers state */
+    uint8_t timer0;
+    uint8_t timer1;
+};
+
+typedef struct FDCtrlSysBus {
+    SysBusDevice busdev;
+    struct FDCtrl state;
+} FDCtrlSysBus;
+
+typedef struct FDCtrlISABus {
+    ISADevice busdev;
+    uint32_t iobase;
+    uint32_t irq;
+    uint32_t dma;
+    struct FDCtrl state;
+    int32_t bootindexA;
+    int32_t bootindexB;
+} FDCtrlISABus;
+
+static uint32_t fdctrl_read (void *opaque, uint32_t reg)
+{
+    FDCtrl *fdctrl = opaque;
+    uint32_t retval;
+
+    reg &= 7;
+    switch (reg) {
+    case FD_REG_SRA:
+        retval = fdctrl_read_statusA(fdctrl);
+        break;
+    case FD_REG_SRB:
+        retval = fdctrl_read_statusB(fdctrl);
+        break;
+    case FD_REG_DOR:
+        retval = fdctrl_read_dor(fdctrl);
+        break;
+    case FD_REG_TDR:
+        retval = fdctrl_read_tape(fdctrl);
+        break;
+    case FD_REG_MSR:
+        retval = fdctrl_read_main_status(fdctrl);
+        break;
+    case FD_REG_FIFO:
+        retval = fdctrl_read_data(fdctrl);
+        break;
+    case FD_REG_DIR:
+        retval = fdctrl_read_dir(fdctrl);
+        break;
+    default:
+        retval = (uint32_t)(-1);
+        break;
+    }
+    FLOPPY_DPRINTF("read reg%d: 0x%02x\n", reg & 7, retval);
+
+    return retval;
+}
+
+static void fdctrl_write (void *opaque, uint32_t reg, uint32_t value)
+{
+    FDCtrl *fdctrl = opaque;
+
+    FLOPPY_DPRINTF("write reg%d: 0x%02x\n", reg & 7, value);
+
+    reg &= 7;
+    switch (reg) {
+    case FD_REG_DOR:
+        fdctrl_write_dor(fdctrl, value);
+        break;
+    case FD_REG_TDR:
+        fdctrl_write_tape(fdctrl, value);
+        break;
+    case FD_REG_DSR:
+        fdctrl_write_rate(fdctrl, value);
+        break;
+    case FD_REG_FIFO:
+        fdctrl_write_data(fdctrl, value);
+        break;
+    case FD_REG_CCR:
+        fdctrl_write_ccr(fdctrl, value);
+        break;
+    default:
+        break;
+    }
+}
+
+static uint64_t fdctrl_read_mem (void *opaque, hwaddr reg,
+                                 unsigned ize)
+{
+    return fdctrl_read(opaque, (uint32_t)reg);
+}
+
+static void fdctrl_write_mem (void *opaque, hwaddr reg,
+                              uint64_t value, unsigned size)
+{
+    fdctrl_write(opaque, (uint32_t)reg, value);
+}
+
+static const MemoryRegionOps fdctrl_mem_ops = {
+    .read = fdctrl_read_mem,
+    .write = fdctrl_write_mem,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static const MemoryRegionOps fdctrl_mem_strict_ops = {
+    .read = fdctrl_read_mem,
+    .write = fdctrl_write_mem,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+};
+
+static bool fdrive_media_changed_needed(void *opaque)
+{
+    FDrive *drive = opaque;
+
+    return (drive->bs != NULL && drive->media_changed != 1);
+}
+
+static const VMStateDescription vmstate_fdrive_media_changed = {
+    .name = "fdrive/media_changed",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT8(media_changed, FDrive),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static bool fdrive_media_rate_needed(void *opaque)
+{
+    FDrive *drive = opaque;
+
+    return drive->fdctrl->check_media_rate;
+}
+
+static const VMStateDescription vmstate_fdrive_media_rate = {
+    .name = "fdrive/media_rate",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT8(media_rate, FDrive),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_fdrive = {
+    .name = "fdrive",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT8(head, FDrive),
+        VMSTATE_UINT8(track, FDrive),
+        VMSTATE_UINT8(sect, FDrive),
+        VMSTATE_END_OF_LIST()
+    },
+    .subsections = (VMStateSubsection[]) {
+        {
+            .vmsd = &vmstate_fdrive_media_changed,
+            .needed = &fdrive_media_changed_needed,
+        } , {
+            .vmsd = &vmstate_fdrive_media_rate,
+            .needed = &fdrive_media_rate_needed,
+        } , {
+            /* empty */
+        }
+    }
+};
+
+static void fdc_pre_save(void *opaque)
+{
+    FDCtrl *s = opaque;
+
+    s->dor_vmstate = s->dor | GET_CUR_DRV(s);
+}
+
+static int fdc_post_load(void *opaque, int version_id)
+{
+    FDCtrl *s = opaque;
+
+    SET_CUR_DRV(s, s->dor_vmstate & FD_DOR_SELMASK);
+    s->dor = s->dor_vmstate & ~FD_DOR_SELMASK;
+    return 0;
+}
+
+static const VMStateDescription vmstate_fdc = {
+    .name = "fdc",
+    .version_id = 2,
+    .minimum_version_id = 2,
+    .minimum_version_id_old = 2,
+    .pre_save = fdc_pre_save,
+    .post_load = fdc_post_load,
+    .fields      = (VMStateField []) {
+        /* Controller State */
+        VMSTATE_UINT8(sra, FDCtrl),
+        VMSTATE_UINT8(srb, FDCtrl),
+        VMSTATE_UINT8(dor_vmstate, FDCtrl),
+        VMSTATE_UINT8(tdr, FDCtrl),
+        VMSTATE_UINT8(dsr, FDCtrl),
+        VMSTATE_UINT8(msr, FDCtrl),
+        VMSTATE_UINT8(status0, FDCtrl),
+        VMSTATE_UINT8(status1, FDCtrl),
+        VMSTATE_UINT8(status2, FDCtrl),
+        /* Command FIFO */
+        VMSTATE_VARRAY_INT32(fifo, FDCtrl, fifo_size, 0, vmstate_info_uint8,
+                             uint8_t),
+        VMSTATE_UINT32(data_pos, FDCtrl),
+        VMSTATE_UINT32(data_len, FDCtrl),
+        VMSTATE_UINT8(data_state, FDCtrl),
+        VMSTATE_UINT8(data_dir, FDCtrl),
+        VMSTATE_UINT8(eot, FDCtrl),
+        /* States kept only to be returned back */
+        VMSTATE_UINT8(timer0, FDCtrl),
+        VMSTATE_UINT8(timer1, FDCtrl),
+        VMSTATE_UINT8(precomp_trk, FDCtrl),
+        VMSTATE_UINT8(config, FDCtrl),
+        VMSTATE_UINT8(lock, FDCtrl),
+        VMSTATE_UINT8(pwrd, FDCtrl),
+        VMSTATE_UINT8_EQUAL(num_floppies, FDCtrl),
+        VMSTATE_STRUCT_ARRAY(drives, FDCtrl, MAX_FD, 1,
+                             vmstate_fdrive, FDrive),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void fdctrl_external_reset_sysbus(DeviceState *d)
+{
+    FDCtrlSysBus *sys = container_of(d, FDCtrlSysBus, busdev.qdev);
+    FDCtrl *s = &sys->state;
+
+    fdctrl_reset(s, 0);
+}
+
+static void fdctrl_external_reset_isa(DeviceState *d)
+{
+    FDCtrlISABus *isa = container_of(d, FDCtrlISABus, busdev.qdev);
+    FDCtrl *s = &isa->state;
+
+    fdctrl_reset(s, 0);
+}
+
+static void fdctrl_handle_tc(void *opaque, int irq, int level)
+{
+    //FDCtrl *s = opaque;
+
+    if (level) {
+        // XXX
+        FLOPPY_DPRINTF("TC pulsed\n");
+    }
+}
+
+/* Change IRQ state */
+static void fdctrl_reset_irq(FDCtrl *fdctrl)
+{
+    fdctrl->status0 = 0;
+    if (!(fdctrl->sra & FD_SRA_INTPEND))
+        return;
+    FLOPPY_DPRINTF("Reset interrupt\n");
+    qemu_set_irq(fdctrl->irq, 0);
+    fdctrl->sra &= ~FD_SRA_INTPEND;
+}
+
+static void fdctrl_raise_irq(FDCtrl *fdctrl)
+{
+    /* Sparc mutation */
+    if (fdctrl->sun4m && (fdctrl->msr & FD_MSR_CMDBUSY)) {
+        /* XXX: not sure */
+        fdctrl->msr &= ~FD_MSR_CMDBUSY;
+        fdctrl->msr |= FD_MSR_RQM | FD_MSR_DIO;
+        return;
+    }
+    if (!(fdctrl->sra & FD_SRA_INTPEND)) {
+        qemu_set_irq(fdctrl->irq, 1);
+        fdctrl->sra |= FD_SRA_INTPEND;
+    }
+
+    fdctrl->reset_sensei = 0;
+    FLOPPY_DPRINTF("Set interrupt status to 0x%02x\n", fdctrl->status0);
+}
+
+/* Reset controller */
+static void fdctrl_reset(FDCtrl *fdctrl, int do_irq)
+{
+    int i;
+
+    FLOPPY_DPRINTF("reset controller\n");
+    fdctrl_reset_irq(fdctrl);
+    /* Initialise controller */
+    fdctrl->sra = 0;
+    fdctrl->srb = 0xc0;
+    if (!fdctrl->drives[1].bs)
+        fdctrl->sra |= FD_SRA_nDRV2;
+    fdctrl->cur_drv = 0;
+    fdctrl->dor = FD_DOR_nRESET;
+    fdctrl->dor |= (fdctrl->dma_chann != -1) ? FD_DOR_DMAEN : 0;
+    fdctrl->msr = FD_MSR_RQM;
+    /* FIFO state */
+    fdctrl->data_pos = 0;
+    fdctrl->data_len = 0;
+    fdctrl->data_state = 0;
+    fdctrl->data_dir = FD_DIR_WRITE;
+    for (i = 0; i < MAX_FD; i++)
+        fd_recalibrate(&fdctrl->drives[i]);
+    fdctrl_reset_fifo(fdctrl);
+    if (do_irq) {
+        fdctrl->status0 |= FD_SR0_RDYCHG;
+        fdctrl_raise_irq(fdctrl);
+        fdctrl->reset_sensei = FD_RESET_SENSEI_COUNT;
+    }
+}
+
+static inline FDrive *drv0(FDCtrl *fdctrl)
+{
+    return &fdctrl->drives[(fdctrl->tdr & FD_TDR_BOOTSEL) >> 2];
+}
+
+static inline FDrive *drv1(FDCtrl *fdctrl)
+{
+    if ((fdctrl->tdr & FD_TDR_BOOTSEL) < (1 << 2))
+        return &fdctrl->drives[1];
+    else
+        return &fdctrl->drives[0];
+}
+
+#if MAX_FD == 4
+static inline FDrive *drv2(FDCtrl *fdctrl)
+{
+    if ((fdctrl->tdr & FD_TDR_BOOTSEL) < (2 << 2))
+        return &fdctrl->drives[2];
+    else
+        return &fdctrl->drives[1];
+}
+
+static inline FDrive *drv3(FDCtrl *fdctrl)
+{
+    if ((fdctrl->tdr & FD_TDR_BOOTSEL) < (3 << 2))
+        return &fdctrl->drives[3];
+    else
+        return &fdctrl->drives[2];
+}
+#endif
+
+static FDrive *get_cur_drv(FDCtrl *fdctrl)
+{
+    switch (fdctrl->cur_drv) {
+        case 0: return drv0(fdctrl);
+        case 1: return drv1(fdctrl);
+#if MAX_FD == 4
+        case 2: return drv2(fdctrl);
+        case 3: return drv3(fdctrl);
+#endif
+        default: return NULL;
+    }
+}
+
+/* Status A register : 0x00 (read-only) */
+static uint32_t fdctrl_read_statusA(FDCtrl *fdctrl)
+{
+    uint32_t retval = fdctrl->sra;
+
+    FLOPPY_DPRINTF("status register A: 0x%02x\n", retval);
+
+    return retval;
+}
+
+/* Status B register : 0x01 (read-only) */
+static uint32_t fdctrl_read_statusB(FDCtrl *fdctrl)
+{
+    uint32_t retval = fdctrl->srb;
+
+    FLOPPY_DPRINTF("status register B: 0x%02x\n", retval);
+
+    return retval;
+}
+
+/* Digital output register : 0x02 */
+static uint32_t fdctrl_read_dor(FDCtrl *fdctrl)
+{
+    uint32_t retval = fdctrl->dor;
+
+    /* Selected drive */
+    retval |= fdctrl->cur_drv;
+    FLOPPY_DPRINTF("digital output register: 0x%02x\n", retval);
+
+    return retval;
+}
+
+static void fdctrl_write_dor(FDCtrl *fdctrl, uint32_t value)
+{
+    FLOPPY_DPRINTF("digital output register set to 0x%02x\n", value);
+
+    /* Motors */
+    if (value & FD_DOR_MOTEN0)
+        fdctrl->srb |= FD_SRB_MTR0;
+    else
+        fdctrl->srb &= ~FD_SRB_MTR0;
+    if (value & FD_DOR_MOTEN1)
+        fdctrl->srb |= FD_SRB_MTR1;
+    else
+        fdctrl->srb &= ~FD_SRB_MTR1;
+
+    /* Drive */
+    if (value & 1)
+        fdctrl->srb |= FD_SRB_DR0;
+    else
+        fdctrl->srb &= ~FD_SRB_DR0;
+
+    /* Reset */
+    if (!(value & FD_DOR_nRESET)) {
+        if (fdctrl->dor & FD_DOR_nRESET) {
+            FLOPPY_DPRINTF("controller enter RESET state\n");
+        }
+    } else {
+        if (!(fdctrl->dor & FD_DOR_nRESET)) {
+            FLOPPY_DPRINTF("controller out of RESET state\n");
+            fdctrl_reset(fdctrl, 1);
+            fdctrl->dsr &= ~FD_DSR_PWRDOWN;
+        }
+    }
+    /* Selected drive */
+    fdctrl->cur_drv = value & FD_DOR_SELMASK;
+
+    fdctrl->dor = value;
+}
+
+/* Tape drive register : 0x03 */
+static uint32_t fdctrl_read_tape(FDCtrl *fdctrl)
+{
+    uint32_t retval = fdctrl->tdr;
+
+    FLOPPY_DPRINTF("tape drive register: 0x%02x\n", retval);
+
+    return retval;
+}
+
+static void fdctrl_write_tape(FDCtrl *fdctrl, uint32_t value)
+{
+    /* Reset mode */
+    if (!(fdctrl->dor & FD_DOR_nRESET)) {
+        FLOPPY_DPRINTF("Floppy controller in RESET state !\n");
+        return;
+    }
+    FLOPPY_DPRINTF("tape drive register set to 0x%02x\n", value);
+    /* Disk boot selection indicator */
+    fdctrl->tdr = value & FD_TDR_BOOTSEL;
+    /* Tape indicators: never allow */
+}
+
+/* Main status register : 0x04 (read) */
+static uint32_t fdctrl_read_main_status(FDCtrl *fdctrl)
+{
+    uint32_t retval = fdctrl->msr;
+
+    fdctrl->dsr &= ~FD_DSR_PWRDOWN;
+    fdctrl->dor |= FD_DOR_nRESET;
+
+    /* Sparc mutation */
+    if (fdctrl->sun4m) {
+        retval |= FD_MSR_DIO;
+        fdctrl_reset_irq(fdctrl);
+    };
+
+    FLOPPY_DPRINTF("main status register: 0x%02x\n", retval);
+
+    return retval;
+}
+
+/* Data select rate register : 0x04 (write) */
+static void fdctrl_write_rate(FDCtrl *fdctrl, uint32_t value)
+{
+    /* Reset mode */
+    if (!(fdctrl->dor & FD_DOR_nRESET)) {
+        FLOPPY_DPRINTF("Floppy controller in RESET state !\n");
+        return;
+    }
+    FLOPPY_DPRINTF("select rate register set to 0x%02x\n", value);
+    /* Reset: autoclear */
+    if (value & FD_DSR_SWRESET) {
+        fdctrl->dor &= ~FD_DOR_nRESET;
+        fdctrl_reset(fdctrl, 1);
+        fdctrl->dor |= FD_DOR_nRESET;
+    }
+    if (value & FD_DSR_PWRDOWN) {
+        fdctrl_reset(fdctrl, 1);
+    }
+    fdctrl->dsr = value;
+}
+
+/* Configuration control register: 0x07 (write) */
+static void fdctrl_write_ccr(FDCtrl *fdctrl, uint32_t value)
+{
+    /* Reset mode */
+    if (!(fdctrl->dor & FD_DOR_nRESET)) {
+        FLOPPY_DPRINTF("Floppy controller in RESET state !\n");
+        return;
+    }
+    FLOPPY_DPRINTF("configuration control register set to 0x%02x\n", value);
+
+    /* Only the rate selection bits used in AT mode, and we
+     * store those in the DSR.
+     */
+    fdctrl->dsr = (fdctrl->dsr & ~FD_DSR_DRATEMASK) |
+                  (value & FD_DSR_DRATEMASK);
+}
+
+static int fdctrl_media_changed(FDrive *drv)
+{
+    return drv->media_changed;
+}
+
+/* Digital input register : 0x07 (read-only) */
+static uint32_t fdctrl_read_dir(FDCtrl *fdctrl)
+{
+    uint32_t retval = 0;
+
+    if (fdctrl_media_changed(get_cur_drv(fdctrl))) {
+        retval |= FD_DIR_DSKCHG;
+    }
+    if (retval != 0) {
+        FLOPPY_DPRINTF("Floppy digital input register: 0x%02x\n", retval);
+    }
+
+    return retval;
+}
+
+/* FIFO state control */
+static void fdctrl_reset_fifo(FDCtrl *fdctrl)
+{
+    fdctrl->data_dir = FD_DIR_WRITE;
+    fdctrl->data_pos = 0;
+    fdctrl->msr &= ~(FD_MSR_CMDBUSY | FD_MSR_DIO);
+}
+
+/* Set FIFO status for the host to read */
+static void fdctrl_set_fifo(FDCtrl *fdctrl, int fifo_len)
+{
+    fdctrl->data_dir = FD_DIR_READ;
+    fdctrl->data_len = fifo_len;
+    fdctrl->data_pos = 0;
+    fdctrl->msr |= FD_MSR_CMDBUSY | FD_MSR_RQM | FD_MSR_DIO;
+}
+
+/* Set an error: unimplemented/unknown command */
+static void fdctrl_unimplemented(FDCtrl *fdctrl, int direction)
+{
+    qemu_log_mask(LOG_UNIMP, "fdc: unimplemented command 0x%02x\n",
+                  fdctrl->fifo[0]);
+    fdctrl->fifo[0] = FD_SR0_INVCMD;
+    fdctrl_set_fifo(fdctrl, 1);
+}
+
+/* Seek to next sector
+ * returns 0 when end of track reached (for DBL_SIDES on head 1)
+ * otherwise returns 1
+ */
+static int fdctrl_seek_to_next_sect(FDCtrl *fdctrl, FDrive *cur_drv)
+{
+    FLOPPY_DPRINTF("seek to next sector (%d %02x %02x => %d)\n",
+                   cur_drv->head, cur_drv->track, cur_drv->sect,
+                   fd_sector(cur_drv));
+    /* XXX: cur_drv->sect >= cur_drv->last_sect should be an
+       error in fact */
+    uint8_t new_head = cur_drv->head;
+    uint8_t new_track = cur_drv->track;
+    uint8_t new_sect = cur_drv->sect;
+
+    int ret = 1;
+
+    if (new_sect >= cur_drv->last_sect ||
+        new_sect == fdctrl->eot) {
+        new_sect = 1;
+        if (FD_MULTI_TRACK(fdctrl->data_state)) {
+            if (new_head == 0 &&
+                (cur_drv->flags & FDISK_DBL_SIDES) != 0) {
+                new_head = 1;
+            } else {
+                new_head = 0;
+                new_track++;
+                fdctrl->status0 |= FD_SR0_SEEK;
+                if ((cur_drv->flags & FDISK_DBL_SIDES) == 0) {
+                    ret = 0;
+                }
+            }
+        } else {
+            fdctrl->status0 |= FD_SR0_SEEK;
+            new_track++;
+            ret = 0;
+        }
+        if (ret == 1) {
+            FLOPPY_DPRINTF("seek to next track (%d %02x %02x => %d)\n",
+                    new_head, new_track, new_sect, fd_sector(cur_drv));
+        }
+    } else {
+        new_sect++;
+    }
+    fd_seek(cur_drv, new_head, new_track, new_sect, 1);
+    return ret;
+}
+
+/* Callback for transfer end (stop or abort) */
+static void fdctrl_stop_transfer(FDCtrl *fdctrl, uint8_t status0,
+                                 uint8_t status1, uint8_t status2)
+{
+    FDrive *cur_drv;
+    cur_drv = get_cur_drv(fdctrl);
+
+    fdctrl->status0 &= ~(FD_SR0_DS0 | FD_SR0_DS1 | FD_SR0_HEAD);
+    fdctrl->status0 |= GET_CUR_DRV(fdctrl);
+    if (cur_drv->head) {
+        fdctrl->status0 |= FD_SR0_HEAD;
+    }
+    fdctrl->status0 |= status0;
+
+    FLOPPY_DPRINTF("transfer status: %02x %02x %02x (%02x)\n",
+                   status0, status1, status2, fdctrl->status0);
+    fdctrl->fifo[0] = fdctrl->status0;
+    fdctrl->fifo[1] = status1;
+    fdctrl->fifo[2] = status2;
+    fdctrl->fifo[3] = cur_drv->track;
+    fdctrl->fifo[4] = cur_drv->head;
+    fdctrl->fifo[5] = cur_drv->sect;
+    fdctrl->fifo[6] = FD_SECTOR_SC;
+    fdctrl->data_dir = FD_DIR_READ;
+    if (!(fdctrl->msr & FD_MSR_NONDMA)) {
+        DMA_release_DREQ(fdctrl->dma_chann);
+    }
+    fdctrl->msr |= FD_MSR_RQM | FD_MSR_DIO;
+    fdctrl->msr &= ~FD_MSR_NONDMA;
+
+    fdctrl_set_fifo(fdctrl, 7);
+    fdctrl_raise_irq(fdctrl);
+}
+
+/* Prepare a data transfer (either DMA or FIFO) */
+static void fdctrl_start_transfer(FDCtrl *fdctrl, int direction)
+{
+    FDrive *cur_drv;
+    uint8_t kh, kt, ks;
+
+    SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
+    cur_drv = get_cur_drv(fdctrl);
+    kt = fdctrl->fifo[2];
+    kh = fdctrl->fifo[3];
+    ks = fdctrl->fifo[4];
+    FLOPPY_DPRINTF("Start transfer at %d %d %02x %02x (%d)\n",
+                   GET_CUR_DRV(fdctrl), kh, kt, ks,
+                   fd_sector_calc(kh, kt, ks, cur_drv->last_sect,
+                                  NUM_SIDES(cur_drv)));
+    switch (fd_seek(cur_drv, kh, kt, ks, fdctrl->config & FD_CONFIG_EIS)) {
+    case 2:
+        /* sect too big */
+        fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, 0x00, 0x00);
+        fdctrl->fifo[3] = kt;
+        fdctrl->fifo[4] = kh;
+        fdctrl->fifo[5] = ks;
+        return;
+    case 3:
+        /* track too big */
+        fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, FD_SR1_EC, 0x00);
+        fdctrl->fifo[3] = kt;
+        fdctrl->fifo[4] = kh;
+        fdctrl->fifo[5] = ks;
+        return;
+    case 4:
+        /* No seek enabled */
+        fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, 0x00, 0x00);
+        fdctrl->fifo[3] = kt;
+        fdctrl->fifo[4] = kh;
+        fdctrl->fifo[5] = ks;
+        return;
+    case 1:
+        fdctrl->status0 |= FD_SR0_SEEK;
+        break;
+    default:
+        break;
+    }
+
+    /* Check the data rate. If the programmed data rate does not match
+     * the currently inserted medium, the operation has to fail. */
+    if (fdctrl->check_media_rate &&
+        (fdctrl->dsr & FD_DSR_DRATEMASK) != cur_drv->media_rate) {
+        FLOPPY_DPRINTF("data rate mismatch (fdc=%d, media=%d)\n",
+                       fdctrl->dsr & FD_DSR_DRATEMASK, cur_drv->media_rate);
+        fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, FD_SR1_MA, 0x00);
+        fdctrl->fifo[3] = kt;
+        fdctrl->fifo[4] = kh;
+        fdctrl->fifo[5] = ks;
+        return;
+    }
+
+    /* Set the FIFO state */
+    fdctrl->data_dir = direction;
+    fdctrl->data_pos = 0;
+    assert(fdctrl->msr & FD_MSR_CMDBUSY);
+    if (fdctrl->fifo[0] & 0x80)
+        fdctrl->data_state |= FD_STATE_MULTI;
+    else
+        fdctrl->data_state &= ~FD_STATE_MULTI;
+    if (fdctrl->fifo[5] == 0) {
+        fdctrl->data_len = fdctrl->fifo[8];
+    } else {
+        int tmp;
+        fdctrl->data_len = 128 << (fdctrl->fifo[5] > 7 ? 7 : fdctrl->fifo[5]);
+        tmp = (fdctrl->fifo[6] - ks + 1);
+        if (fdctrl->fifo[0] & 0x80)
+            tmp += fdctrl->fifo[6];
+        fdctrl->data_len *= tmp;
+    }
+    fdctrl->eot = fdctrl->fifo[6];
+    if (fdctrl->dor & FD_DOR_DMAEN) {
+        int dma_mode;
+        /* DMA transfer are enabled. Check if DMA channel is well programmed */
+        dma_mode = DMA_get_channel_mode(fdctrl->dma_chann);
+        dma_mode = (dma_mode >> 2) & 3;
+        FLOPPY_DPRINTF("dma_mode=%d direction=%d (%d - %d)\n",
+                       dma_mode, direction,
+                       (128 << fdctrl->fifo[5]) *
+                       (cur_drv->last_sect - ks + 1), fdctrl->data_len);
+        if (((direction == FD_DIR_SCANE || direction == FD_DIR_SCANL ||
+              direction == FD_DIR_SCANH) && dma_mode == 0) ||
+            (direction == FD_DIR_WRITE && dma_mode == 2) ||
+            (direction == FD_DIR_READ && dma_mode == 1) ||
+            (direction == FD_DIR_VERIFY)) {
+            /* No access is allowed until DMA transfer has completed */
+            fdctrl->msr &= ~FD_MSR_RQM;
+            if (direction != FD_DIR_VERIFY) {
+                /* Now, we just have to wait for the DMA controller to
+                 * recall us...
+                 */
+                DMA_hold_DREQ(fdctrl->dma_chann);
+                DMA_schedule(fdctrl->dma_chann);
+            } else {
+                /* Start transfer */
+                fdctrl_transfer_handler(fdctrl, fdctrl->dma_chann, 0,
+                                        fdctrl->data_len);
+            }
+            return;
+        } else {
+            FLOPPY_DPRINTF("bad dma_mode=%d direction=%d\n", dma_mode,
+                           direction);
+        }
+    }
+    FLOPPY_DPRINTF("start non-DMA transfer\n");
+    fdctrl->msr |= FD_MSR_NONDMA;
+    if (direction != FD_DIR_WRITE)
+        fdctrl->msr |= FD_MSR_DIO;
+    /* IO based transfer: calculate len */
+    fdctrl_raise_irq(fdctrl);
+}
+
+/* Prepare a transfer of deleted data */
+static void fdctrl_start_transfer_del(FDCtrl *fdctrl, int direction)
+{
+    qemu_log_mask(LOG_UNIMP, "fdctrl_start_transfer_del() unimplemented\n");
+
+    /* We don't handle deleted data,
+     * so we don't return *ANYTHING*
+     */
+    fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM | FD_SR0_SEEK, 0x00, 0x00);
+}
+
+/* handlers for DMA transfers */
+static int fdctrl_transfer_handler (void *opaque, int nchan,
+                                    int dma_pos, int dma_len)
+{
+    FDCtrl *fdctrl;
+    FDrive *cur_drv;
+    int len, start_pos, rel_pos;
+    uint8_t status0 = 0x00, status1 = 0x00, status2 = 0x00;
+
+    fdctrl = opaque;
+    if (fdctrl->msr & FD_MSR_RQM) {
+        FLOPPY_DPRINTF("Not in DMA transfer mode !\n");
+        return 0;
+    }
+    cur_drv = get_cur_drv(fdctrl);
+    if (fdctrl->data_dir == FD_DIR_SCANE || fdctrl->data_dir == FD_DIR_SCANL ||
+        fdctrl->data_dir == FD_DIR_SCANH)
+        status2 = FD_SR2_SNS;
+    if (dma_len > fdctrl->data_len)
+        dma_len = fdctrl->data_len;
+    if (cur_drv->bs == NULL) {
+        if (fdctrl->data_dir == FD_DIR_WRITE)
+            fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM | FD_SR0_SEEK, 0x00, 0x00);
+        else
+            fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, 0x00, 0x00);
+        len = 0;
+        goto transfer_error;
+    }
+    rel_pos = fdctrl->data_pos % FD_SECTOR_LEN;
+    for (start_pos = fdctrl->data_pos; fdctrl->data_pos < dma_len;) {
+        len = dma_len - fdctrl->data_pos;
+        if (len + rel_pos > FD_SECTOR_LEN)
+            len = FD_SECTOR_LEN - rel_pos;
+        FLOPPY_DPRINTF("copy %d bytes (%d %d %d) %d pos %d %02x "
+                       "(%d-0x%08x 0x%08x)\n", len, dma_len, fdctrl->data_pos,
+                       fdctrl->data_len, GET_CUR_DRV(fdctrl), cur_drv->head,
+                       cur_drv->track, cur_drv->sect, fd_sector(cur_drv),
+                       fd_sector(cur_drv) * FD_SECTOR_LEN);
+        if (fdctrl->data_dir != FD_DIR_WRITE ||
+            len < FD_SECTOR_LEN || rel_pos != 0) {
+            /* READ & SCAN commands and realign to a sector for WRITE */
+            if (bdrv_read(cur_drv->bs, fd_sector(cur_drv),
+                          fdctrl->fifo, 1) < 0) {
+                FLOPPY_DPRINTF("Floppy: error getting sector %d\n",
+                               fd_sector(cur_drv));
+                /* Sure, image size is too small... */
+                memset(fdctrl->fifo, 0, FD_SECTOR_LEN);
+            }
+        }
+        switch (fdctrl->data_dir) {
+        case FD_DIR_READ:
+            /* READ commands */
+            DMA_write_memory (nchan, fdctrl->fifo + rel_pos,
+                              fdctrl->data_pos, len);
+            break;
+        case FD_DIR_WRITE:
+            /* WRITE commands */
+            if (cur_drv->ro) {
+                /* Handle readonly medium early, no need to do DMA, touch the
+                 * LED or attempt any writes. A real floppy doesn't attempt
+                 * to write to readonly media either. */
+                fdctrl_stop_transfer(fdctrl,
+                                     FD_SR0_ABNTERM | FD_SR0_SEEK, FD_SR1_NW,
+                                     0x00);
+                goto transfer_error;
+            }
+
+            DMA_read_memory (nchan, fdctrl->fifo + rel_pos,
+                             fdctrl->data_pos, len);
+            if (bdrv_write(cur_drv->bs, fd_sector(cur_drv),
+                           fdctrl->fifo, 1) < 0) {
+                FLOPPY_DPRINTF("error writing sector %d\n",
+                               fd_sector(cur_drv));
+                fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM | FD_SR0_SEEK, 0x00, 0x00);
+                goto transfer_error;
+            }
+            break;
+        case FD_DIR_VERIFY:
+            /* VERIFY commands */
+            break;
+        default:
+            /* SCAN commands */
+            {
+                uint8_t tmpbuf[FD_SECTOR_LEN];
+                int ret;
+                DMA_read_memory (nchan, tmpbuf, fdctrl->data_pos, len);
+                ret = memcmp(tmpbuf, fdctrl->fifo + rel_pos, len);
+                if (ret == 0) {
+                    status2 = FD_SR2_SEH;
+                    goto end_transfer;
+                }
+                if ((ret < 0 && fdctrl->data_dir == FD_DIR_SCANL) ||
+                    (ret > 0 && fdctrl->data_dir == FD_DIR_SCANH)) {
+                    status2 = 0x00;
+                    goto end_transfer;
+                }
+            }
+            break;
+        }
+        fdctrl->data_pos += len;
+        rel_pos = fdctrl->data_pos % FD_SECTOR_LEN;
+        if (rel_pos == 0) {
+            /* Seek to next sector */
+            if (!fdctrl_seek_to_next_sect(fdctrl, cur_drv))
+                break;
+        }
+    }
+ end_transfer:
+    len = fdctrl->data_pos - start_pos;
+    FLOPPY_DPRINTF("end transfer %d %d %d\n",
+                   fdctrl->data_pos, len, fdctrl->data_len);
+    if (fdctrl->data_dir == FD_DIR_SCANE ||
+        fdctrl->data_dir == FD_DIR_SCANL ||
+        fdctrl->data_dir == FD_DIR_SCANH)
+        status2 = FD_SR2_SEH;
+    fdctrl->data_len -= len;
+    fdctrl_stop_transfer(fdctrl, status0, status1, status2);
+ transfer_error:
+
+    return len;
+}
+
+/* Data register : 0x05 */
+static uint32_t fdctrl_read_data(FDCtrl *fdctrl)
+{
+    FDrive *cur_drv;
+    uint32_t retval = 0;
+    int pos;
+
+    cur_drv = get_cur_drv(fdctrl);
+    fdctrl->dsr &= ~FD_DSR_PWRDOWN;
+    if (!(fdctrl->msr & FD_MSR_RQM) || !(fdctrl->msr & FD_MSR_DIO)) {
+        FLOPPY_DPRINTF("error: controller not ready for reading\n");
+        return 0;
+    }
+    pos = fdctrl->data_pos;
+    if (fdctrl->msr & FD_MSR_NONDMA) {
+        pos %= FD_SECTOR_LEN;
+        if (pos == 0) {
+            if (fdctrl->data_pos != 0)
+                if (!fdctrl_seek_to_next_sect(fdctrl, cur_drv)) {
+                    FLOPPY_DPRINTF("error seeking to next sector %d\n",
+                                   fd_sector(cur_drv));
+                    return 0;
+                }
+            if (bdrv_read(cur_drv->bs, fd_sector(cur_drv), fdctrl->fifo, 1) < 0) {
+                FLOPPY_DPRINTF("error getting sector %d\n",
+                               fd_sector(cur_drv));
+                /* Sure, image size is too small... */
+                memset(fdctrl->fifo, 0, FD_SECTOR_LEN);
+            }
+        }
+    }
+    retval = fdctrl->fifo[pos];
+    if (++fdctrl->data_pos == fdctrl->data_len) {
+        fdctrl->data_pos = 0;
+        /* Switch from transfer mode to status mode
+         * then from status mode to command mode
+         */
+        if (fdctrl->msr & FD_MSR_NONDMA) {
+            fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
+        } else {
+            fdctrl_reset_fifo(fdctrl);
+            fdctrl_reset_irq(fdctrl);
+        }
+    }
+    FLOPPY_DPRINTF("data register: 0x%02x\n", retval);
+
+    return retval;
+}
+
+static void fdctrl_format_sector(FDCtrl *fdctrl)
+{
+    FDrive *cur_drv;
+    uint8_t kh, kt, ks;
+
+    SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
+    cur_drv = get_cur_drv(fdctrl);
+    kt = fdctrl->fifo[6];
+    kh = fdctrl->fifo[7];
+    ks = fdctrl->fifo[8];
+    FLOPPY_DPRINTF("format sector at %d %d %02x %02x (%d)\n",
+                   GET_CUR_DRV(fdctrl), kh, kt, ks,
+                   fd_sector_calc(kh, kt, ks, cur_drv->last_sect,
+                                  NUM_SIDES(cur_drv)));
+    switch (fd_seek(cur_drv, kh, kt, ks, fdctrl->config & FD_CONFIG_EIS)) {
+    case 2:
+        /* sect too big */
+        fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, 0x00, 0x00);
+        fdctrl->fifo[3] = kt;
+        fdctrl->fifo[4] = kh;
+        fdctrl->fifo[5] = ks;
+        return;
+    case 3:
+        /* track too big */
+        fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, FD_SR1_EC, 0x00);
+        fdctrl->fifo[3] = kt;
+        fdctrl->fifo[4] = kh;
+        fdctrl->fifo[5] = ks;
+        return;
+    case 4:
+        /* No seek enabled */
+        fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, 0x00, 0x00);
+        fdctrl->fifo[3] = kt;
+        fdctrl->fifo[4] = kh;
+        fdctrl->fifo[5] = ks;
+        return;
+    case 1:
+        fdctrl->status0 |= FD_SR0_SEEK;
+        break;
+    default:
+        break;
+    }
+    memset(fdctrl->fifo, 0, FD_SECTOR_LEN);
+    if (cur_drv->bs == NULL ||
+        bdrv_write(cur_drv->bs, fd_sector(cur_drv), fdctrl->fifo, 1) < 0) {
+        FLOPPY_DPRINTF("error formatting sector %d\n", fd_sector(cur_drv));
+        fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM | FD_SR0_SEEK, 0x00, 0x00);
+    } else {
+        if (cur_drv->sect == cur_drv->last_sect) {
+            fdctrl->data_state &= ~FD_STATE_FORMAT;
+            /* Last sector done */
+            fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
+        } else {
+            /* More to do */
+            fdctrl->data_pos = 0;
+            fdctrl->data_len = 4;
+        }
+    }
+}
+
+static void fdctrl_handle_lock(FDCtrl *fdctrl, int direction)
+{
+    fdctrl->lock = (fdctrl->fifo[0] & 0x80) ? 1 : 0;
+    fdctrl->fifo[0] = fdctrl->lock << 4;
+    fdctrl_set_fifo(fdctrl, 1);
+}
+
+static void fdctrl_handle_dumpreg(FDCtrl *fdctrl, int direction)
+{
+    FDrive *cur_drv = get_cur_drv(fdctrl);
+
+    /* Drives position */
+    fdctrl->fifo[0] = drv0(fdctrl)->track;
+    fdctrl->fifo[1] = drv1(fdctrl)->track;
+#if MAX_FD == 4
+    fdctrl->fifo[2] = drv2(fdctrl)->track;
+    fdctrl->fifo[3] = drv3(fdctrl)->track;
+#else
+    fdctrl->fifo[2] = 0;
+    fdctrl->fifo[3] = 0;
+#endif
+    /* timers */
+    fdctrl->fifo[4] = fdctrl->timer0;
+    fdctrl->fifo[5] = (fdctrl->timer1 << 1) | (fdctrl->dor & FD_DOR_DMAEN ? 1 : 0);
+    fdctrl->fifo[6] = cur_drv->last_sect;
+    fdctrl->fifo[7] = (fdctrl->lock << 7) |
+        (cur_drv->perpendicular << 2);
+    fdctrl->fifo[8] = fdctrl->config;
+    fdctrl->fifo[9] = fdctrl->precomp_trk;
+    fdctrl_set_fifo(fdctrl, 10);
+}
+
+static void fdctrl_handle_version(FDCtrl *fdctrl, int direction)
+{
+    /* Controller's version */
+    fdctrl->fifo[0] = fdctrl->version;
+    fdctrl_set_fifo(fdctrl, 1);
+}
+
+static void fdctrl_handle_partid(FDCtrl *fdctrl, int direction)
+{
+    fdctrl->fifo[0] = 0x41; /* Stepping 1 */
+    fdctrl_set_fifo(fdctrl, 1);
+}
+
+static void fdctrl_handle_restore(FDCtrl *fdctrl, int direction)
+{
+    FDrive *cur_drv = get_cur_drv(fdctrl);
+
+    /* Drives position */
+    drv0(fdctrl)->track = fdctrl->fifo[3];
+    drv1(fdctrl)->track = fdctrl->fifo[4];
+#if MAX_FD == 4
+    drv2(fdctrl)->track = fdctrl->fifo[5];
+    drv3(fdctrl)->track = fdctrl->fifo[6];
+#endif
+    /* timers */
+    fdctrl->timer0 = fdctrl->fifo[7];
+    fdctrl->timer1 = fdctrl->fifo[8];
+    cur_drv->last_sect = fdctrl->fifo[9];
+    fdctrl->lock = fdctrl->fifo[10] >> 7;
+    cur_drv->perpendicular = (fdctrl->fifo[10] >> 2) & 0xF;
+    fdctrl->config = fdctrl->fifo[11];
+    fdctrl->precomp_trk = fdctrl->fifo[12];
+    fdctrl->pwrd = fdctrl->fifo[13];
+    fdctrl_reset_fifo(fdctrl);
+}
+
+static void fdctrl_handle_save(FDCtrl *fdctrl, int direction)
+{
+    FDrive *cur_drv = get_cur_drv(fdctrl);
+
+    fdctrl->fifo[0] = 0;
+    fdctrl->fifo[1] = 0;
+    /* Drives position */
+    fdctrl->fifo[2] = drv0(fdctrl)->track;
+    fdctrl->fifo[3] = drv1(fdctrl)->track;
+#if MAX_FD == 4
+    fdctrl->fifo[4] = drv2(fdctrl)->track;
+    fdctrl->fifo[5] = drv3(fdctrl)->track;
+#else
+    fdctrl->fifo[4] = 0;
+    fdctrl->fifo[5] = 0;
+#endif
+    /* timers */
+    fdctrl->fifo[6] = fdctrl->timer0;
+    fdctrl->fifo[7] = fdctrl->timer1;
+    fdctrl->fifo[8] = cur_drv->last_sect;
+    fdctrl->fifo[9] = (fdctrl->lock << 7) |
+        (cur_drv->perpendicular << 2);
+    fdctrl->fifo[10] = fdctrl->config;
+    fdctrl->fifo[11] = fdctrl->precomp_trk;
+    fdctrl->fifo[12] = fdctrl->pwrd;
+    fdctrl->fifo[13] = 0;
+    fdctrl->fifo[14] = 0;
+    fdctrl_set_fifo(fdctrl, 15);
+}
+
+static void fdctrl_handle_readid(FDCtrl *fdctrl, int direction)
+{
+    FDrive *cur_drv = get_cur_drv(fdctrl);
+
+    cur_drv->head = (fdctrl->fifo[1] >> 2) & 1;
+    qemu_mod_timer(fdctrl->result_timer,
+                   qemu_get_clock_ns(vm_clock) + (get_ticks_per_sec() / 50));
+}
+
+static void fdctrl_handle_format_track(FDCtrl *fdctrl, int direction)
+{
+    FDrive *cur_drv;
+
+    SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
+    cur_drv = get_cur_drv(fdctrl);
+    fdctrl->data_state |= FD_STATE_FORMAT;
+    if (fdctrl->fifo[0] & 0x80)
+        fdctrl->data_state |= FD_STATE_MULTI;
+    else
+        fdctrl->data_state &= ~FD_STATE_MULTI;
+    cur_drv->bps =
+        fdctrl->fifo[2] > 7 ? 16384 : 128 << fdctrl->fifo[2];
+#if 0
+    cur_drv->last_sect =
+        cur_drv->flags & FDISK_DBL_SIDES ? fdctrl->fifo[3] :
+        fdctrl->fifo[3] / 2;
+#else
+    cur_drv->last_sect = fdctrl->fifo[3];
+#endif
+    /* TODO: implement format using DMA expected by the Bochs BIOS
+     * and Linux fdformat (read 3 bytes per sector via DMA and fill
+     * the sector with the specified fill byte
+     */
+    fdctrl->data_state &= ~FD_STATE_FORMAT;
+    fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
+}
+
+static void fdctrl_handle_specify(FDCtrl *fdctrl, int direction)
+{
+    fdctrl->timer0 = (fdctrl->fifo[1] >> 4) & 0xF;
+    fdctrl->timer1 = fdctrl->fifo[2] >> 1;
+    if (fdctrl->fifo[2] & 1)
+        fdctrl->dor &= ~FD_DOR_DMAEN;
+    else
+        fdctrl->dor |= FD_DOR_DMAEN;
+    /* No result back */
+    fdctrl_reset_fifo(fdctrl);
+}
+
+static void fdctrl_handle_sense_drive_status(FDCtrl *fdctrl, int direction)
+{
+    FDrive *cur_drv;
+
+    SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
+    cur_drv = get_cur_drv(fdctrl);
+    cur_drv->head = (fdctrl->fifo[1] >> 2) & 1;
+    /* 1 Byte status back */
+    fdctrl->fifo[0] = (cur_drv->ro << 6) |
+        (cur_drv->track == 0 ? 0x10 : 0x00) |
+        (cur_drv->head << 2) |
+        GET_CUR_DRV(fdctrl) |
+        0x28;
+    fdctrl_set_fifo(fdctrl, 1);
+}
+
+static void fdctrl_handle_recalibrate(FDCtrl *fdctrl, int direction)
+{
+    FDrive *cur_drv;
+
+    SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
+    cur_drv = get_cur_drv(fdctrl);
+    fd_recalibrate(cur_drv);
+    fdctrl_reset_fifo(fdctrl);
+    /* Raise Interrupt */
+    fdctrl->status0 |= FD_SR0_SEEK;
+    fdctrl_raise_irq(fdctrl);
+}
+
+static void fdctrl_handle_sense_interrupt_status(FDCtrl *fdctrl, int direction)
+{
+    FDrive *cur_drv = get_cur_drv(fdctrl);
+
+    if (fdctrl->reset_sensei > 0) {
+        fdctrl->fifo[0] =
+            FD_SR0_RDYCHG + FD_RESET_SENSEI_COUNT - fdctrl->reset_sensei;
+        fdctrl->reset_sensei--;
+    } else if (!(fdctrl->sra & FD_SRA_INTPEND)) {
+        fdctrl->fifo[0] = FD_SR0_INVCMD;
+        fdctrl_set_fifo(fdctrl, 1);
+        return;
+    } else {
+        fdctrl->fifo[0] =
+                (fdctrl->status0 & ~(FD_SR0_HEAD | FD_SR0_DS1 | FD_SR0_DS0))
+                | GET_CUR_DRV(fdctrl);
+    }
+
+    fdctrl->fifo[1] = cur_drv->track;
+    fdctrl_set_fifo(fdctrl, 2);
+    fdctrl_reset_irq(fdctrl);
+    fdctrl->status0 = FD_SR0_RDYCHG;
+}
+
+static void fdctrl_handle_seek(FDCtrl *fdctrl, int direction)
+{
+    FDrive *cur_drv;
+
+    SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
+    cur_drv = get_cur_drv(fdctrl);
+    fdctrl_reset_fifo(fdctrl);
+    /* The seek command just sends step pulses to the drive and doesn't care if
+     * there is a medium inserted of if it's banging the head against the drive.
+     */
+    fd_seek(cur_drv, cur_drv->head, fdctrl->fifo[2], cur_drv->sect, 1);
+    /* Raise Interrupt */
+    fdctrl->status0 |= FD_SR0_SEEK;
+    fdctrl_raise_irq(fdctrl);
+}
+
+static void fdctrl_handle_perpendicular_mode(FDCtrl *fdctrl, int direction)
+{
+    FDrive *cur_drv = get_cur_drv(fdctrl);
+
+    if (fdctrl->fifo[1] & 0x80)
+        cur_drv->perpendicular = fdctrl->fifo[1] & 0x7;
+    /* No result back */
+    fdctrl_reset_fifo(fdctrl);
+}
+
+static void fdctrl_handle_configure(FDCtrl *fdctrl, int direction)
+{
+    fdctrl->config = fdctrl->fifo[2];
+    fdctrl->precomp_trk =  fdctrl->fifo[3];
+    /* No result back */
+    fdctrl_reset_fifo(fdctrl);
+}
+
+static void fdctrl_handle_powerdown_mode(FDCtrl *fdctrl, int direction)
+{
+    fdctrl->pwrd = fdctrl->fifo[1];
+    fdctrl->fifo[0] = fdctrl->fifo[1];
+    fdctrl_set_fifo(fdctrl, 1);
+}
+
+static void fdctrl_handle_option(FDCtrl *fdctrl, int direction)
+{
+    /* No result back */
+    fdctrl_reset_fifo(fdctrl);
+}
+
+static void fdctrl_handle_drive_specification_command(FDCtrl *fdctrl, int direction)
+{
+    FDrive *cur_drv = get_cur_drv(fdctrl);
+
+    if (fdctrl->fifo[fdctrl->data_pos - 1] & 0x80) {
+        /* Command parameters done */
+        if (fdctrl->fifo[fdctrl->data_pos - 1] & 0x40) {
+            fdctrl->fifo[0] = fdctrl->fifo[1];
+            fdctrl->fifo[2] = 0;
+            fdctrl->fifo[3] = 0;
+            fdctrl_set_fifo(fdctrl, 4);
+        } else {
+            fdctrl_reset_fifo(fdctrl);
+        }
+    } else if (fdctrl->data_len > 7) {
+        /* ERROR */
+        fdctrl->fifo[0] = 0x80 |
+            (cur_drv->head << 2) | GET_CUR_DRV(fdctrl);
+        fdctrl_set_fifo(fdctrl, 1);
+    }
+}
+
+static void fdctrl_handle_relative_seek_in(FDCtrl *fdctrl, int direction)
+{
+    FDrive *cur_drv;
+
+    SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
+    cur_drv = get_cur_drv(fdctrl);
+    if (fdctrl->fifo[2] + cur_drv->track >= cur_drv->max_track) {
+        fd_seek(cur_drv, cur_drv->head, cur_drv->max_track - 1,
+                cur_drv->sect, 1);
+    } else {
+        fd_seek(cur_drv, cur_drv->head,
+                cur_drv->track + fdctrl->fifo[2], cur_drv->sect, 1);
+    }
+    fdctrl_reset_fifo(fdctrl);
+    /* Raise Interrupt */
+    fdctrl->status0 |= FD_SR0_SEEK;
+    fdctrl_raise_irq(fdctrl);
+}
+
+static void fdctrl_handle_relative_seek_out(FDCtrl *fdctrl, int direction)
+{
+    FDrive *cur_drv;
+
+    SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
+    cur_drv = get_cur_drv(fdctrl);
+    if (fdctrl->fifo[2] > cur_drv->track) {
+        fd_seek(cur_drv, cur_drv->head, 0, cur_drv->sect, 1);
+    } else {
+        fd_seek(cur_drv, cur_drv->head,
+                cur_drv->track - fdctrl->fifo[2], cur_drv->sect, 1);
+    }
+    fdctrl_reset_fifo(fdctrl);
+    /* Raise Interrupt */
+    fdctrl->status0 |= FD_SR0_SEEK;
+    fdctrl_raise_irq(fdctrl);
+}
+
+static const struct {
+    uint8_t value;
+    uint8_t mask;
+    const char* name;
+    int parameters;
+    void (*handler)(FDCtrl *fdctrl, int direction);
+    int direction;
+} handlers[] = {
+    { FD_CMD_READ, 0x1f, "READ", 8, fdctrl_start_transfer, FD_DIR_READ },
+    { FD_CMD_WRITE, 0x3f, "WRITE", 8, fdctrl_start_transfer, FD_DIR_WRITE },
+    { FD_CMD_SEEK, 0xff, "SEEK", 2, fdctrl_handle_seek },
+    { FD_CMD_SENSE_INTERRUPT_STATUS, 0xff, "SENSE INTERRUPT STATUS", 0, fdctrl_handle_sense_interrupt_status },
+    { FD_CMD_RECALIBRATE, 0xff, "RECALIBRATE", 1, fdctrl_handle_recalibrate },
+    { FD_CMD_FORMAT_TRACK, 0xbf, "FORMAT TRACK", 5, fdctrl_handle_format_track },
+    { FD_CMD_READ_TRACK, 0xbf, "READ TRACK", 8, fdctrl_start_transfer, FD_DIR_READ },
+    { FD_CMD_RESTORE, 0xff, "RESTORE", 17, fdctrl_handle_restore }, /* part of READ DELETED DATA */
+    { FD_CMD_SAVE, 0xff, "SAVE", 0, fdctrl_handle_save }, /* part of READ DELETED DATA */
+    { FD_CMD_READ_DELETED, 0x1f, "READ DELETED DATA", 8, fdctrl_start_transfer_del, FD_DIR_READ },
+    { FD_CMD_SCAN_EQUAL, 0x1f, "SCAN EQUAL", 8, fdctrl_start_transfer, FD_DIR_SCANE },
+    { FD_CMD_VERIFY, 0x1f, "VERIFY", 8, fdctrl_start_transfer, FD_DIR_VERIFY },
+    { FD_CMD_SCAN_LOW_OR_EQUAL, 0x1f, "SCAN LOW OR EQUAL", 8, fdctrl_start_transfer, FD_DIR_SCANL },
+    { FD_CMD_SCAN_HIGH_OR_EQUAL, 0x1f, "SCAN HIGH OR EQUAL", 8, fdctrl_start_transfer, FD_DIR_SCANH },
+    { FD_CMD_WRITE_DELETED, 0x3f, "WRITE DELETED DATA", 8, fdctrl_start_transfer_del, FD_DIR_WRITE },
+    { FD_CMD_READ_ID, 0xbf, "READ ID", 1, fdctrl_handle_readid },
+    { FD_CMD_SPECIFY, 0xff, "SPECIFY", 2, fdctrl_handle_specify },
+    { FD_CMD_SENSE_DRIVE_STATUS, 0xff, "SENSE DRIVE STATUS", 1, fdctrl_handle_sense_drive_status },
+    { FD_CMD_PERPENDICULAR_MODE, 0xff, "PERPENDICULAR MODE", 1, fdctrl_handle_perpendicular_mode },
+    { FD_CMD_CONFIGURE, 0xff, "CONFIGURE", 3, fdctrl_handle_configure },
+    { FD_CMD_POWERDOWN_MODE, 0xff, "POWERDOWN MODE", 2, fdctrl_handle_powerdown_mode },
+    { FD_CMD_OPTION, 0xff, "OPTION", 1, fdctrl_handle_option },
+    { FD_CMD_DRIVE_SPECIFICATION_COMMAND, 0xff, "DRIVE SPECIFICATION COMMAND", 5, fdctrl_handle_drive_specification_command },
+    { FD_CMD_RELATIVE_SEEK_OUT, 0xff, "RELATIVE SEEK OUT", 2, fdctrl_handle_relative_seek_out },
+    { FD_CMD_FORMAT_AND_WRITE, 0xff, "FORMAT AND WRITE", 10, fdctrl_unimplemented },
+    { FD_CMD_RELATIVE_SEEK_IN, 0xff, "RELATIVE SEEK IN", 2, fdctrl_handle_relative_seek_in },
+    { FD_CMD_LOCK, 0x7f, "LOCK", 0, fdctrl_handle_lock },
+    { FD_CMD_DUMPREG, 0xff, "DUMPREG", 0, fdctrl_handle_dumpreg },
+    { FD_CMD_VERSION, 0xff, "VERSION", 0, fdctrl_handle_version },
+    { FD_CMD_PART_ID, 0xff, "PART ID", 0, fdctrl_handle_partid },
+    { FD_CMD_WRITE, 0x1f, "WRITE (BeOS)", 8, fdctrl_start_transfer, FD_DIR_WRITE }, /* not in specification ; BeOS 4.5 bug */
+    { 0, 0, "unknown", 0, fdctrl_unimplemented }, /* default handler */
+};
+/* Associate command to an index in the 'handlers' array */
+static uint8_t command_to_handler[256];
+
+static void fdctrl_write_data(FDCtrl *fdctrl, uint32_t value)
+{
+    FDrive *cur_drv;
+    int pos;
+
+    /* Reset mode */
+    if (!(fdctrl->dor & FD_DOR_nRESET)) {
+        FLOPPY_DPRINTF("Floppy controller in RESET state !\n");
+        return;
+    }
+    if (!(fdctrl->msr & FD_MSR_RQM) || (fdctrl->msr & FD_MSR_DIO)) {
+        FLOPPY_DPRINTF("error: controller not ready for writing\n");
+        return;
+    }
+    fdctrl->dsr &= ~FD_DSR_PWRDOWN;
+    /* Is it write command time ? */
+    if (fdctrl->msr & FD_MSR_NONDMA) {
+        /* FIFO data write */
+        pos = fdctrl->data_pos++;
+        pos %= FD_SECTOR_LEN;
+        fdctrl->fifo[pos] = value;
+        if (pos == FD_SECTOR_LEN - 1 ||
+            fdctrl->data_pos == fdctrl->data_len) {
+            cur_drv = get_cur_drv(fdctrl);
+            if (bdrv_write(cur_drv->bs, fd_sector(cur_drv), fdctrl->fifo, 1) < 0) {
+                FLOPPY_DPRINTF("error writing sector %d\n",
+                               fd_sector(cur_drv));
+                return;
+            }
+            if (!fdctrl_seek_to_next_sect(fdctrl, cur_drv)) {
+                FLOPPY_DPRINTF("error seeking to next sector %d\n",
+                               fd_sector(cur_drv));
+                return;
+            }
+        }
+        /* Switch from transfer mode to status mode
+         * then from status mode to command mode
+         */
+        if (fdctrl->data_pos == fdctrl->data_len)
+            fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
+        return;
+    }
+    if (fdctrl->data_pos == 0) {
+        /* Command */
+        pos = command_to_handler[value & 0xff];
+        FLOPPY_DPRINTF("%s command\n", handlers[pos].name);
+        fdctrl->data_len = handlers[pos].parameters + 1;
+        fdctrl->msr |= FD_MSR_CMDBUSY;
+    }
+
+    FLOPPY_DPRINTF("%s: %02x\n", __func__, value);
+    fdctrl->fifo[fdctrl->data_pos++] = value;
+    if (fdctrl->data_pos == fdctrl->data_len) {
+        /* We now have all parameters
+         * and will be able to treat the command
+         */
+        if (fdctrl->data_state & FD_STATE_FORMAT) {
+            fdctrl_format_sector(fdctrl);
+            return;
+        }
+
+        pos = command_to_handler[fdctrl->fifo[0] & 0xff];
+        FLOPPY_DPRINTF("treat %s command\n", handlers[pos].name);
+        (*handlers[pos].handler)(fdctrl, handlers[pos].direction);
+    }
+}
+
+static void fdctrl_result_timer(void *opaque)
+{
+    FDCtrl *fdctrl = opaque;
+    FDrive *cur_drv = get_cur_drv(fdctrl);
+
+    /* Pretend we are spinning.
+     * This is needed for Coherent, which uses READ ID to check for
+     * sector interleaving.
+     */
+    if (cur_drv->last_sect != 0) {
+        cur_drv->sect = (cur_drv->sect % cur_drv->last_sect) + 1;
+    }
+    /* READ_ID can't automatically succeed! */
+    if (fdctrl->check_media_rate &&
+        (fdctrl->dsr & FD_DSR_DRATEMASK) != cur_drv->media_rate) {
+        FLOPPY_DPRINTF("read id rate mismatch (fdc=%d, media=%d)\n",
+                       fdctrl->dsr & FD_DSR_DRATEMASK, cur_drv->media_rate);
+        fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, FD_SR1_MA, 0x00);
+    } else {
+        fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
+    }
+}
+
+static void fdctrl_change_cb(void *opaque, bool load)
+{
+    FDrive *drive = opaque;
+
+    drive->media_changed = 1;
+    fd_revalidate(drive);
+}
+
+static const BlockDevOps fdctrl_block_ops = {
+    .change_media_cb = fdctrl_change_cb,
+};
+
+/* Init functions */
+static int fdctrl_connect_drives(FDCtrl *fdctrl)
+{
+    unsigned int i;
+    FDrive *drive;
+
+    for (i = 0; i < MAX_FD; i++) {
+        drive = &fdctrl->drives[i];
+        drive->fdctrl = fdctrl;
+
+        if (drive->bs) {
+            if (bdrv_get_on_error(drive->bs, 0) != BLOCKDEV_ON_ERROR_ENOSPC) {
+                error_report("fdc doesn't support drive option werror");
+                return -1;
+            }
+            if (bdrv_get_on_error(drive->bs, 1) != BLOCKDEV_ON_ERROR_REPORT) {
+                error_report("fdc doesn't support drive option rerror");
+                return -1;
+            }
+        }
+
+        fd_init(drive);
+        fdctrl_change_cb(drive, 0);
+        if (drive->bs) {
+            bdrv_set_dev_ops(drive->bs, &fdctrl_block_ops, drive);
+        }
+    }
+    return 0;
+}
+
+ISADevice *fdctrl_init_isa(ISABus *bus, DriveInfo **fds)
+{
+    ISADevice *dev;
+
+    dev = isa_try_create(bus, "isa-fdc");
+    if (!dev) {
+        return NULL;
+    }
+
+    if (fds[0]) {
+        qdev_prop_set_drive_nofail(&dev->qdev, "driveA", fds[0]->bdrv);
+    }
+    if (fds[1]) {
+        qdev_prop_set_drive_nofail(&dev->qdev, "driveB", fds[1]->bdrv);
+    }
+    qdev_init_nofail(&dev->qdev);
+
+    return dev;
+}
+
+void fdctrl_init_sysbus(qemu_irq irq, int dma_chann,
+                        hwaddr mmio_base, DriveInfo **fds)
+{
+    FDCtrl *fdctrl;
+    DeviceState *dev;
+    FDCtrlSysBus *sys;
+
+    dev = qdev_create(NULL, "sysbus-fdc");
+    sys = DO_UPCAST(FDCtrlSysBus, busdev.qdev, dev);
+    fdctrl = &sys->state;
+    fdctrl->dma_chann = dma_chann; /* FIXME */
+    if (fds[0]) {
+        qdev_prop_set_drive_nofail(dev, "driveA", fds[0]->bdrv);
+    }
+    if (fds[1]) {
+        qdev_prop_set_drive_nofail(dev, "driveB", fds[1]->bdrv);
+    }
+    qdev_init_nofail(dev);
+    sysbus_connect_irq(&sys->busdev, 0, irq);
+    sysbus_mmio_map(&sys->busdev, 0, mmio_base);
+}
+
+void sun4m_fdctrl_init(qemu_irq irq, hwaddr io_base,
+                       DriveInfo **fds, qemu_irq *fdc_tc)
+{
+    DeviceState *dev;
+    FDCtrlSysBus *sys;
+
+    dev = qdev_create(NULL, "SUNW,fdtwo");
+    if (fds[0]) {
+        qdev_prop_set_drive_nofail(dev, "drive", fds[0]->bdrv);
+    }
+    qdev_init_nofail(dev);
+    sys = DO_UPCAST(FDCtrlSysBus, busdev.qdev, dev);
+    sysbus_connect_irq(&sys->busdev, 0, irq);
+    sysbus_mmio_map(&sys->busdev, 0, io_base);
+    *fdc_tc = qdev_get_gpio_in(dev, 0);
+}
+
+static int fdctrl_init_common(FDCtrl *fdctrl)
+{
+    int i, j;
+    static int command_tables_inited = 0;
+
+    /* Fill 'command_to_handler' lookup table */
+    if (!command_tables_inited) {
+        command_tables_inited = 1;
+        for (i = ARRAY_SIZE(handlers) - 1; i >= 0; i--) {
+            for (j = 0; j < sizeof(command_to_handler); j++) {
+                if ((j & handlers[i].mask) == handlers[i].value) {
+                    command_to_handler[j] = i;
+                }
+            }
+        }
+    }
+
+    FLOPPY_DPRINTF("init controller\n");
+    fdctrl->fifo = qemu_memalign(512, FD_SECTOR_LEN);
+    fdctrl->fifo_size = 512;
+    fdctrl->result_timer = qemu_new_timer_ns(vm_clock,
+                                          fdctrl_result_timer, fdctrl);
+
+    fdctrl->version = 0x90; /* Intel 82078 controller */
+    fdctrl->config = FD_CONFIG_EIS | FD_CONFIG_EFIFO; /* Implicit seek, polling & FIFO enabled */
+    fdctrl->num_floppies = MAX_FD;
+
+    if (fdctrl->dma_chann != -1)
+        DMA_register_channel(fdctrl->dma_chann, &fdctrl_transfer_handler, fdctrl);
+    return fdctrl_connect_drives(fdctrl);
+}
+
+static const MemoryRegionPortio fdc_portio_list[] = {
+    { 1, 5, 1, .read = fdctrl_read, .write = fdctrl_write },
+    { 7, 1, 1, .read = fdctrl_read, .write = fdctrl_write },
+    PORTIO_END_OF_LIST(),
+};
+
+static int isabus_fdc_init1(ISADevice *dev)
+{
+    FDCtrlISABus *isa = DO_UPCAST(FDCtrlISABus, busdev, dev);
+    FDCtrl *fdctrl = &isa->state;
+    int ret;
+
+    isa_register_portio_list(dev, isa->iobase, fdc_portio_list, fdctrl, "fdc");
+
+    isa_init_irq(&isa->busdev, &fdctrl->irq, isa->irq);
+    fdctrl->dma_chann = isa->dma;
+
+    qdev_set_legacy_instance_id(&dev->qdev, isa->iobase, 2);
+    ret = fdctrl_init_common(fdctrl);
+
+    add_boot_device_path(isa->bootindexA, &dev->qdev, "/floppy@0");
+    add_boot_device_path(isa->bootindexB, &dev->qdev, "/floppy@1");
+
+    return ret;
+}
+
+static int sysbus_fdc_init1(SysBusDevice *dev)
+{
+    FDCtrlSysBus *sys = DO_UPCAST(FDCtrlSysBus, busdev, dev);
+    FDCtrl *fdctrl = &sys->state;
+    int ret;
+
+    memory_region_init_io(&fdctrl->iomem, &fdctrl_mem_ops, fdctrl, "fdc", 0x08);
+    sysbus_init_mmio(dev, &fdctrl->iomem);
+    sysbus_init_irq(dev, &fdctrl->irq);
+    qdev_init_gpio_in(&dev->qdev, fdctrl_handle_tc, 1);
+    fdctrl->dma_chann = -1;
+
+    qdev_set_legacy_instance_id(&dev->qdev, 0 /* io */, 2); /* FIXME */
+    ret = fdctrl_init_common(fdctrl);
+
+    return ret;
+}
+
+static int sun4m_fdc_init1(SysBusDevice *dev)
+{
+    FDCtrl *fdctrl = &(FROM_SYSBUS(FDCtrlSysBus, dev)->state);
+
+    memory_region_init_io(&fdctrl->iomem, &fdctrl_mem_strict_ops, fdctrl,
+                          "fdctrl", 0x08);
+    sysbus_init_mmio(dev, &fdctrl->iomem);
+    sysbus_init_irq(dev, &fdctrl->irq);
+    qdev_init_gpio_in(&dev->qdev, fdctrl_handle_tc, 1);
+
+    fdctrl->sun4m = 1;
+    qdev_set_legacy_instance_id(&dev->qdev, 0 /* io */, 2); /* FIXME */
+    return fdctrl_init_common(fdctrl);
+}
+
+FDriveType isa_fdc_get_drive_type(ISADevice *fdc, int i)
+{
+    FDCtrlISABus *isa = DO_UPCAST(FDCtrlISABus, busdev, fdc);
+
+    return isa->state.drives[i].drive;
+}
+
+static const VMStateDescription vmstate_isa_fdc ={
+    .name = "fdc",
+    .version_id = 2,
+    .minimum_version_id = 2,
+    .fields = (VMStateField []) {
+        VMSTATE_STRUCT(state, FDCtrlISABus, 0, vmstate_fdc, FDCtrl),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static Property isa_fdc_properties[] = {
+    DEFINE_PROP_HEX32("iobase", FDCtrlISABus, iobase, 0x3f0),
+    DEFINE_PROP_UINT32("irq", FDCtrlISABus, irq, 6),
+    DEFINE_PROP_UINT32("dma", FDCtrlISABus, dma, 2),
+    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_BIT("check_media_rate", FDCtrlISABus, state.check_media_rate,
+                    0, true),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void isabus_fdc_class_init1(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+    ic->init = isabus_fdc_init1;
+    dc->fw_name = "fdc";
+    dc->no_user = 1;
+    dc->reset = fdctrl_external_reset_isa;
+    dc->vmsd = &vmstate_isa_fdc;
+    dc->props = isa_fdc_properties;
+}
+
+static const 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 ={
+    .name = "fdc",
+    .version_id = 2,
+    .minimum_version_id = 2,
+    .fields = (VMStateField []) {
+        VMSTATE_STRUCT(state, FDCtrlSysBus, 0, vmstate_fdc, FDCtrl),
+        VMSTATE_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 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 const TypeInfo sysbus_fdc_info = {
+    .name          = "sysbus-fdc",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(FDCtrlSysBus),
+    .class_init    = sysbus_fdc_class_init,
+};
+
+static Property sun4m_fdc_properties[] = {
+    DEFINE_PROP_DRIVE("drive", FDCtrlSysBus, state.drives[0].bs),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void sun4m_fdc_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = sun4m_fdc_init1;
+    dc->reset = fdctrl_external_reset_sysbus;
+    dc->vmsd = &vmstate_sysbus_fdc;
+    dc->props = sun4m_fdc_properties;
+}
+
+static const 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_types(void)
+{
+    type_register_static(&isa_fdc_info);
+    type_register_static(&sysbus_fdc_info);
+    type_register_static(&sun4m_fdc_info);
+}
+
+type_init(fdc_register_types)
diff --git a/hw/block/hd-geometry.c b/hw/block/hd-geometry.c
new file mode 100644 (file)
index 0000000..6feb4f8
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * Hard disk geometry utilities
+ *
+ * Copyright (C) 2012 Red Hat, Inc.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ *
+ * 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.
+ */
+
+#include "block/block.h"
+#include "hw/block/block.h"
+#include "trace.h"
+
+struct partition {
+        uint8_t boot_ind;           /* 0x80 - active */
+        uint8_t head;               /* starting head */
+        uint8_t sector;             /* starting sector */
+        uint8_t cyl;                /* starting cylinder */
+        uint8_t sys_ind;            /* What partition type */
+        uint8_t end_head;           /* end head */
+        uint8_t end_sector;         /* end sector */
+        uint8_t end_cyl;            /* end cylinder */
+        uint32_t start_sect;        /* starting sector counting from 0 */
+        uint32_t nr_sects;          /* nr of sectors in partition */
+} QEMU_PACKED;
+
+/* try to guess the disk logical geometry from the MSDOS partition table.
+   Return 0 if OK, -1 if could not guess */
+static int guess_disk_lchs(BlockDriverState *bs,
+                           int *pcylinders, int *pheads, int *psectors)
+{
+    uint8_t buf[BDRV_SECTOR_SIZE];
+    int i, heads, sectors, cylinders;
+    struct partition *p;
+    uint32_t nr_sects;
+    uint64_t nb_sectors;
+
+    bdrv_get_geometry(bs, &nb_sectors);
+
+    /**
+     * The function will be invoked during startup not only in sync I/O mode,
+     * but also in async I/O mode. So the I/O throttling function has to
+     * be disabled temporarily here, not permanently.
+     */
+    if (bdrv_read_unthrottled(bs, 0, buf, 1) < 0) {
+        return -1;
+    }
+    /* test msdos magic */
+    if (buf[510] != 0x55 || buf[511] != 0xaa) {
+        return -1;
+    }
+    for (i = 0; i < 4; i++) {
+        p = ((struct partition *)(buf + 0x1be)) + i;
+        nr_sects = le32_to_cpu(p->nr_sects);
+        if (nr_sects && p->end_head) {
+            /* We make the assumption that the partition terminates on
+               a cylinder boundary */
+            heads = p->end_head + 1;
+            sectors = p->end_sector & 63;
+            if (sectors == 0) {
+                continue;
+            }
+            cylinders = nb_sectors / (heads * sectors);
+            if (cylinders < 1 || cylinders > 16383) {
+                continue;
+            }
+            *pheads = heads;
+            *psectors = sectors;
+            *pcylinders = cylinders;
+            trace_hd_geometry_lchs_guess(bs, cylinders, heads, sectors);
+            return 0;
+        }
+    }
+    return -1;
+}
+
+static void guess_chs_for_size(BlockDriverState *bs,
+                uint32_t *pcyls, uint32_t *pheads, uint32_t *psecs)
+{
+    uint64_t nb_sectors;
+    int cylinders;
+
+    bdrv_get_geometry(bs, &nb_sectors);
+
+    cylinders = nb_sectors / (16 * 63);
+    if (cylinders > 16383) {
+        cylinders = 16383;
+    } else if (cylinders < 2) {
+        cylinders = 2;
+    }
+    *pcyls = cylinders;
+    *pheads = 16;
+    *psecs = 63;
+}
+
+void hd_geometry_guess(BlockDriverState *bs,
+                       uint32_t *pcyls, uint32_t *pheads, uint32_t *psecs,
+                       int *ptrans)
+{
+    int cylinders, heads, secs, translation;
+
+    if (guess_disk_lchs(bs, &cylinders, &heads, &secs) < 0) {
+        /* no LCHS guess: use a standard physical disk geometry  */
+        guess_chs_for_size(bs, pcyls, pheads, psecs);
+        translation = hd_bios_chs_auto_trans(*pcyls, *pheads, *psecs);
+    } else if (heads > 16) {
+        /* LCHS guess with heads > 16 means that a BIOS LBA
+           translation was active, so a standard physical disk
+           geometry is OK */
+        guess_chs_for_size(bs, pcyls, pheads, psecs);
+        translation = *pcyls * *pheads <= 131072
+            ? BIOS_ATA_TRANSLATION_LARGE
+            : BIOS_ATA_TRANSLATION_LBA;
+    } else {
+        /* LCHS guess with heads <= 16: use as physical geometry */
+        *pcyls = cylinders;
+        *pheads = heads;
+        *psecs = secs;
+        /* disable any translation to be in sync with
+           the logical geometry */
+        translation = BIOS_ATA_TRANSLATION_NONE;
+    }
+    if (ptrans) {
+        *ptrans = translation;
+    }
+    trace_hd_geometry_guess(bs, *pcyls, *pheads, *psecs, translation);
+}
+
+int hd_bios_chs_auto_trans(uint32_t cyls, uint32_t heads, uint32_t secs)
+{
+    return cyls <= 1024 && heads <= 16 && secs <= 63
+        ? BIOS_ATA_TRANSLATION_NONE
+        : BIOS_ATA_TRANSLATION_LBA;
+}
diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c
new file mode 100644 (file)
index 0000000..cd560e3
--- /dev/null
@@ -0,0 +1,672 @@
+/*
+ * ST M25P80 emulator. Emulate all SPI flash devices based on the m25p80 command
+ * set. Known devices table current as of Jun/2012 and taken from linux.
+ * See drivers/mtd/devices/m25p80.c.
+ *
+ * Copyright (C) 2011 Edgar E. Iglesias <edgar.iglesias@gmail.com>
+ * Copyright (C) 2012 Peter A. G. Crosthwaite <peter.crosthwaite@petalogix.com>
+ * Copyright (C) 2012 PetaLogix
+ *
+ * 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 or
+ * (at your option) a later version 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
+ * 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 "hw/hw.h"
+#include "sysemu/blockdev.h"
+#include "hw/ssi.h"
+#include "hw/arm/devices.h"
+
+#ifdef M25P80_ERR_DEBUG
+#define DB_PRINT(...) do { \
+    fprintf(stderr,  ": %s: ", __func__); \
+    fprintf(stderr, ## __VA_ARGS__); \
+    } while (0);
+#else
+    #define DB_PRINT(...)
+#endif
+
+/* Fields for FlashPartInfo->flags */
+
+/* erase capabilities */
+#define ER_4K 1
+#define ER_32K 2
+/* set to allow the page program command to write 0s back to 1. Useful for
+ * modelling EEPROM with SPI flash command set
+ */
+#define WR_1 0x100
+
+typedef struct FlashPartInfo {
+    const char *part_name;
+    /* jedec code. (jedec >> 16) & 0xff is the 1st byte, >> 8 the 2nd etc */
+    uint32_t jedec;
+    /* extended jedec code */
+    uint16_t ext_jedec;
+    /* there is confusion between manufacturers as to what a sector is. In this
+     * device model, a "sector" is the size that is erased by the ERASE_SECTOR
+     * command (opcode 0xd8).
+     */
+    uint32_t sector_size;
+    uint32_t n_sectors;
+    uint32_t page_size;
+    uint8_t flags;
+} FlashPartInfo;
+
+/* adapted from linux */
+
+#define INFO(_part_name, _jedec, _ext_jedec, _sector_size, _n_sectors, _flags)\
+    .part_name = (_part_name),\
+    .jedec = (_jedec),\
+    .ext_jedec = (_ext_jedec),\
+    .sector_size = (_sector_size),\
+    .n_sectors = (_n_sectors),\
+    .page_size = 256,\
+    .flags = (_flags),\
+
+#define JEDEC_NUMONYX 0x20
+#define JEDEC_WINBOND 0xEF
+#define JEDEC_SPANSION 0x01
+
+static const FlashPartInfo known_devices[] = {
+    /* Atmel -- some are (confusingly) marketed as "DataFlash" */
+    { INFO("at25fs010",   0x1f6601,      0,  32 << 10,   4, ER_4K) },
+    { INFO("at25fs040",   0x1f6604,      0,  64 << 10,   8, ER_4K) },
+
+    { INFO("at25df041a",  0x1f4401,      0,  64 << 10,   8, ER_4K) },
+    { INFO("at25df321a",  0x1f4701,      0,  64 << 10,  64, ER_4K) },
+    { INFO("at25df641",   0x1f4800,      0,  64 << 10, 128, ER_4K) },
+
+    { INFO("at26f004",    0x1f0400,      0,  64 << 10,   8, ER_4K) },
+    { INFO("at26df081a",  0x1f4501,      0,  64 << 10,  16, ER_4K) },
+    { INFO("at26df161a",  0x1f4601,      0,  64 << 10,  32, ER_4K) },
+    { INFO("at26df321",   0x1f4700,      0,  64 << 10,  64, ER_4K) },
+
+    /* EON -- en25xxx */
+    { INFO("en25f32",     0x1c3116,      0,  64 << 10,  64, ER_4K) },
+    { INFO("en25p32",     0x1c2016,      0,  64 << 10,  64, 0) },
+    { INFO("en25q32b",    0x1c3016,      0,  64 << 10,  64, 0) },
+    { INFO("en25p64",     0x1c2017,      0,  64 << 10, 128, 0) },
+
+    /* Intel/Numonyx -- xxxs33b */
+    { INFO("160s33b",     0x898911,      0,  64 << 10,  32, 0) },
+    { INFO("320s33b",     0x898912,      0,  64 << 10,  64, 0) },
+    { INFO("640s33b",     0x898913,      0,  64 << 10, 128, 0) },
+
+    /* Macronix */
+    { INFO("mx25l4005a",  0xc22013,      0,  64 << 10,   8, ER_4K) },
+    { INFO("mx25l8005",   0xc22014,      0,  64 << 10,  16, 0) },
+    { INFO("mx25l1606e",  0xc22015,      0,  64 << 10,  32, ER_4K) },
+    { INFO("mx25l3205d",  0xc22016,      0,  64 << 10,  64, 0) },
+    { INFO("mx25l6405d",  0xc22017,      0,  64 << 10, 128, 0) },
+    { INFO("mx25l12805d", 0xc22018,      0,  64 << 10, 256, 0) },
+    { INFO("mx25l12855e", 0xc22618,      0,  64 << 10, 256, 0) },
+    { INFO("mx25l25635e", 0xc22019,      0,  64 << 10, 512, 0) },
+    { INFO("mx25l25655e", 0xc22619,      0,  64 << 10, 512, 0) },
+
+    /* Spansion -- single (large) sector size only, at least
+     * for the chips listed here (without boot sectors).
+     */
+    { INFO("s25sl004a",   0x010212,      0,  64 << 10,   8, 0) },
+    { INFO("s25sl008a",   0x010213,      0,  64 << 10,  16, 0) },
+    { INFO("s25sl016a",   0x010214,      0,  64 << 10,  32, 0) },
+    { INFO("s25sl032a",   0x010215,      0,  64 << 10,  64, 0) },
+    { INFO("s25sl032p",   0x010215, 0x4d00,  64 << 10,  64, ER_4K) },
+    { INFO("s25sl064a",   0x010216,      0,  64 << 10, 128, 0) },
+    { INFO("s25fl256s0",  0x010219, 0x4d00, 256 << 10, 128, 0) },
+    { INFO("s25fl256s1",  0x010219, 0x4d01,  64 << 10, 512, 0) },
+    { INFO("s25fl512s",   0x010220, 0x4d00, 256 << 10, 256, 0) },
+    { INFO("s70fl01gs",   0x010221, 0x4d00, 256 << 10, 256, 0) },
+    { INFO("s25sl12800",  0x012018, 0x0300, 256 << 10,  64, 0) },
+    { INFO("s25sl12801",  0x012018, 0x0301,  64 << 10, 256, 0) },
+    { INFO("s25fl129p0",  0x012018, 0x4d00, 256 << 10,  64, 0) },
+    { INFO("s25fl129p1",  0x012018, 0x4d01,  64 << 10, 256, 0) },
+    { INFO("s25fl016k",   0xef4015,      0,  64 << 10,  32, ER_4K | ER_32K) },
+    { INFO("s25fl064k",   0xef4017,      0,  64 << 10, 128, ER_4K | ER_32K) },
+
+    /* SST -- large erase sizes are "overlays", "sectors" are 4<< 10 */
+    { INFO("sst25vf040b", 0xbf258d,      0,  64 << 10,   8, ER_4K) },
+    { INFO("sst25vf080b", 0xbf258e,      0,  64 << 10,  16, ER_4K) },
+    { INFO("sst25vf016b", 0xbf2541,      0,  64 << 10,  32, ER_4K) },
+    { INFO("sst25vf032b", 0xbf254a,      0,  64 << 10,  64, ER_4K) },
+    { INFO("sst25wf512",  0xbf2501,      0,  64 << 10,   1, ER_4K) },
+    { INFO("sst25wf010",  0xbf2502,      0,  64 << 10,   2, ER_4K) },
+    { INFO("sst25wf020",  0xbf2503,      0,  64 << 10,   4, ER_4K) },
+    { INFO("sst25wf040",  0xbf2504,      0,  64 << 10,   8, ER_4K) },
+
+    /* ST Microelectronics -- newer production may have feature updates */
+    { INFO("m25p05",      0x202010,      0,  32 << 10,   2, 0) },
+    { INFO("m25p10",      0x202011,      0,  32 << 10,   4, 0) },
+    { INFO("m25p20",      0x202012,      0,  64 << 10,   4, 0) },
+    { INFO("m25p40",      0x202013,      0,  64 << 10,   8, 0) },
+    { INFO("m25p80",      0x202014,      0,  64 << 10,  16, 0) },
+    { INFO("m25p16",      0x202015,      0,  64 << 10,  32, 0) },
+    { INFO("m25p32",      0x202016,      0,  64 << 10,  64, 0) },
+    { INFO("m25p64",      0x202017,      0,  64 << 10, 128, 0) },
+    { INFO("m25p128",     0x202018,      0, 256 << 10,  64, 0) },
+
+    { INFO("m45pe10",     0x204011,      0,  64 << 10,   2, 0) },
+    { INFO("m45pe80",     0x204014,      0,  64 << 10,  16, 0) },
+    { INFO("m45pe16",     0x204015,      0,  64 << 10,  32, 0) },
+
+    { INFO("m25pe80",     0x208014,      0,  64 << 10,  16, 0) },
+    { INFO("m25pe16",     0x208015,      0,  64 << 10,  32, ER_4K) },
+
+    { INFO("m25px32",     0x207116,      0,  64 << 10,  64, ER_4K) },
+    { INFO("m25px32-s0",  0x207316,      0,  64 << 10,  64, ER_4K) },
+    { INFO("m25px32-s1",  0x206316,      0,  64 << 10,  64, ER_4K) },
+    { INFO("m25px64",     0x207117,      0,  64 << 10, 128, 0) },
+
+    /* Winbond -- w25x "blocks" are 64k, "sectors" are 4KiB */
+    { INFO("w25x10",      0xef3011,      0,  64 << 10,   2, ER_4K) },
+    { INFO("w25x20",      0xef3012,      0,  64 << 10,   4, ER_4K) },
+    { INFO("w25x40",      0xef3013,      0,  64 << 10,   8, ER_4K) },
+    { INFO("w25x80",      0xef3014,      0,  64 << 10,  16, ER_4K) },
+    { INFO("w25x16",      0xef3015,      0,  64 << 10,  32, ER_4K) },
+    { INFO("w25x32",      0xef3016,      0,  64 << 10,  64, ER_4K) },
+    { INFO("w25q32",      0xef4016,      0,  64 << 10,  64, ER_4K) },
+    { INFO("w25x64",      0xef3017,      0,  64 << 10, 128, ER_4K) },
+    { INFO("w25q64",      0xef4017,      0,  64 << 10, 128, ER_4K) },
+
+    /* Numonyx -- n25q128 */
+    { INFO("n25q128",      0x20ba18,      0,  64 << 10, 256, 0) },
+};
+
+typedef enum {
+    NOP = 0,
+    WRSR = 0x1,
+    WRDI = 0x4,
+    RDSR = 0x5,
+    WREN = 0x6,
+    JEDEC_READ = 0x9f,
+    BULK_ERASE = 0xc7,
+
+    READ = 0x3,
+    FAST_READ = 0xb,
+    DOR = 0x3b,
+    QOR = 0x6b,
+    DIOR = 0xbb,
+    QIOR = 0xeb,
+
+    PP = 0x2,
+    DPP = 0xa2,
+    QPP = 0x32,
+
+    ERASE_4K = 0x20,
+    ERASE_32K = 0x52,
+    ERASE_SECTOR = 0xd8,
+} FlashCMD;
+
+typedef enum {
+    STATE_IDLE,
+    STATE_PAGE_PROGRAM,
+    STATE_READ,
+    STATE_COLLECTING_DATA,
+    STATE_READING_DATA,
+} CMDState;
+
+typedef struct Flash {
+    SSISlave ssidev;
+    uint32_t r;
+
+    BlockDriverState *bdrv;
+
+    uint8_t *storage;
+    uint32_t size;
+    int page_size;
+
+    uint8_t state;
+    uint8_t data[16];
+    uint32_t len;
+    uint32_t pos;
+    uint8_t needed_bytes;
+    uint8_t cmd_in_progress;
+    uint64_t cur_addr;
+    bool write_enable;
+
+    int64_t dirty_page;
+
+    const FlashPartInfo *pi;
+
+} Flash;
+
+typedef struct M25P80Class {
+    SSISlaveClass parent_class;
+    FlashPartInfo *pi;
+} M25P80Class;
+
+#define TYPE_M25P80 "m25p80-generic"
+#define M25P80(obj) \
+     OBJECT_CHECK(Flash, (obj), TYPE_M25P80)
+#define M25P80_CLASS(klass) \
+     OBJECT_CLASS_CHECK(M25P80Class, (klass), TYPE_M25P80)
+#define M25P80_GET_CLASS(obj) \
+     OBJECT_GET_CLASS(M25P80Class, (obj), TYPE_M25P80)
+
+static void bdrv_sync_complete(void *opaque, int ret)
+{
+    /* do nothing. Masters do not directly interact with the backing store,
+     * only the working copy so no mutexing required.
+     */
+}
+
+static void flash_sync_page(Flash *s, int page)
+{
+    if (s->bdrv) {
+        int bdrv_sector, nb_sectors;
+        QEMUIOVector iov;
+
+        bdrv_sector = (page * s->pi->page_size) / BDRV_SECTOR_SIZE;
+        nb_sectors = DIV_ROUND_UP(s->pi->page_size, BDRV_SECTOR_SIZE);
+        qemu_iovec_init(&iov, 1);
+        qemu_iovec_add(&iov, s->storage + bdrv_sector * BDRV_SECTOR_SIZE,
+                                                nb_sectors * BDRV_SECTOR_SIZE);
+        bdrv_aio_writev(s->bdrv, bdrv_sector, &iov, nb_sectors,
+                                                bdrv_sync_complete, NULL);
+    }
+}
+
+static inline void flash_sync_area(Flash *s, int64_t off, int64_t len)
+{
+    int64_t start, end, nb_sectors;
+    QEMUIOVector iov;
+
+    if (!s->bdrv) {
+        return;
+    }
+
+    assert(!(len % BDRV_SECTOR_SIZE));
+    start = off / BDRV_SECTOR_SIZE;
+    end = (off + len) / BDRV_SECTOR_SIZE;
+    nb_sectors = end - start;
+    qemu_iovec_init(&iov, 1);
+    qemu_iovec_add(&iov, s->storage + (start * BDRV_SECTOR_SIZE),
+                                        nb_sectors * BDRV_SECTOR_SIZE);
+    bdrv_aio_writev(s->bdrv, start, &iov, nb_sectors, bdrv_sync_complete, NULL);
+}
+
+static void flash_erase(Flash *s, int offset, FlashCMD cmd)
+{
+    uint32_t len;
+    uint8_t capa_to_assert = 0;
+
+    switch (cmd) {
+    case ERASE_4K:
+        len = 4 << 10;
+        capa_to_assert = ER_4K;
+        break;
+    case ERASE_32K:
+        len = 32 << 10;
+        capa_to_assert = ER_32K;
+        break;
+    case ERASE_SECTOR:
+        len = s->pi->sector_size;
+        break;
+    case BULK_ERASE:
+        len = s->size;
+        break;
+    default:
+        abort();
+    }
+
+    DB_PRINT("offset = %#x, len = %d\n", offset, len);
+    if ((s->pi->flags & capa_to_assert) != capa_to_assert) {
+        hw_error("m25p80: %dk erase size not supported by device\n", len);
+    }
+
+    if (!s->write_enable) {
+        DB_PRINT("erase with write protect!\n");
+        return;
+    }
+    memset(s->storage + offset, 0xff, len);
+    flash_sync_area(s, offset, len);
+}
+
+static inline void flash_sync_dirty(Flash *s, int64_t newpage)
+{
+    if (s->dirty_page >= 0 && s->dirty_page != newpage) {
+        flash_sync_page(s, s->dirty_page);
+        s->dirty_page = newpage;
+    }
+}
+
+static inline
+void flash_write8(Flash *s, uint64_t addr, uint8_t data)
+{
+    int64_t page = addr / s->pi->page_size;
+    uint8_t prev = s->storage[s->cur_addr];
+
+    if (!s->write_enable) {
+        DB_PRINT("write with write protect!\n");
+    }
+
+    if ((prev ^ data) & data) {
+        DB_PRINT("programming zero to one! addr=%lx  %x -> %x\n",
+                  addr, prev, data);
+    }
+
+    if (s->pi->flags & WR_1) {
+        s->storage[s->cur_addr] = data;
+    } else {
+        s->storage[s->cur_addr] &= data;
+    }
+
+    flash_sync_dirty(s, page);
+    s->dirty_page = page;
+}
+
+static void complete_collecting_data(Flash *s)
+{
+    s->cur_addr = s->data[0] << 16;
+    s->cur_addr |= s->data[1] << 8;
+    s->cur_addr |= s->data[2];
+
+    s->state = STATE_IDLE;
+
+    switch (s->cmd_in_progress) {
+    case DPP:
+    case QPP:
+    case PP:
+        s->state = STATE_PAGE_PROGRAM;
+        break;
+    case READ:
+    case FAST_READ:
+    case DOR:
+    case QOR:
+    case DIOR:
+    case QIOR:
+        s->state = STATE_READ;
+        break;
+    case ERASE_4K:
+    case ERASE_32K:
+    case ERASE_SECTOR:
+        flash_erase(s, s->cur_addr, s->cmd_in_progress);
+        break;
+    case WRSR:
+        if (s->write_enable) {
+            s->write_enable = false;
+        }
+        break;
+    default:
+        break;
+    }
+}
+
+static void decode_new_cmd(Flash *s, uint32_t value)
+{
+    s->cmd_in_progress = value;
+    DB_PRINT("decoded new command:%x\n", value);
+
+    switch (value) {
+
+    case ERASE_4K:
+    case ERASE_32K:
+    case ERASE_SECTOR:
+    case READ:
+    case DPP:
+    case QPP:
+    case PP:
+        s->needed_bytes = 3;
+        s->pos = 0;
+        s->len = 0;
+        s->state = STATE_COLLECTING_DATA;
+        break;
+
+    case FAST_READ:
+    case DOR:
+    case QOR:
+        s->needed_bytes = 4;
+        s->pos = 0;
+        s->len = 0;
+        s->state = STATE_COLLECTING_DATA;
+        break;
+
+    case DIOR:
+        switch ((s->pi->jedec >> 16) & 0xFF) {
+        case JEDEC_WINBOND:
+        case JEDEC_SPANSION:
+            s->needed_bytes = 4;
+            break;
+        case JEDEC_NUMONYX:
+        default:
+            s->needed_bytes = 5;
+        }
+        s->pos = 0;
+        s->len = 0;
+        s->state = STATE_COLLECTING_DATA;
+        break;
+
+    case QIOR:
+        switch ((s->pi->jedec >> 16) & 0xFF) {
+        case JEDEC_WINBOND:
+        case JEDEC_SPANSION:
+            s->needed_bytes = 6;
+            break;
+        case JEDEC_NUMONYX:
+        default:
+            s->needed_bytes = 8;
+        }
+        s->pos = 0;
+        s->len = 0;
+        s->state = STATE_COLLECTING_DATA;
+        break;
+
+    case WRSR:
+        if (s->write_enable) {
+            s->needed_bytes = 1;
+            s->pos = 0;
+            s->len = 0;
+            s->state = STATE_COLLECTING_DATA;
+        }
+        break;
+
+    case WRDI:
+        s->write_enable = false;
+        break;
+    case WREN:
+        s->write_enable = true;
+        break;
+
+    case RDSR:
+        s->data[0] = (!!s->write_enable) << 1;
+        s->pos = 0;
+        s->len = 1;
+        s->state = STATE_READING_DATA;
+        break;
+
+    case JEDEC_READ:
+        DB_PRINT("populated jedec code\n");
+        s->data[0] = (s->pi->jedec >> 16) & 0xff;
+        s->data[1] = (s->pi->jedec >> 8) & 0xff;
+        s->data[2] = s->pi->jedec & 0xff;
+        if (s->pi->ext_jedec) {
+            s->data[3] = (s->pi->ext_jedec >> 8) & 0xff;
+            s->data[4] = s->pi->ext_jedec & 0xff;
+            s->len = 5;
+        } else {
+            s->len = 3;
+        }
+        s->pos = 0;
+        s->state = STATE_READING_DATA;
+        break;
+
+    case BULK_ERASE:
+        if (s->write_enable) {
+            DB_PRINT("chip erase\n");
+            flash_erase(s, 0, BULK_ERASE);
+        } else {
+            DB_PRINT("chip erase with write protect!\n");
+        }
+        break;
+    case NOP:
+        break;
+    default:
+        DB_PRINT("Unknown cmd %x\n", value);
+        break;
+    }
+}
+
+static int m25p80_cs(SSISlave *ss, bool select)
+{
+    Flash *s = FROM_SSI_SLAVE(Flash, ss);
+
+    if (select) {
+        s->len = 0;
+        s->pos = 0;
+        s->state = STATE_IDLE;
+        flash_sync_dirty(s, -1);
+    }
+
+    DB_PRINT("%sselect\n", select ? "de" : "");
+
+    return 0;
+}
+
+static uint32_t m25p80_transfer8(SSISlave *ss, uint32_t tx)
+{
+    Flash *s = FROM_SSI_SLAVE(Flash, ss);
+    uint32_t r = 0;
+
+    switch (s->state) {
+
+    case STATE_PAGE_PROGRAM:
+        DB_PRINT("page program cur_addr=%lx data=%x\n", s->cur_addr,
+                 (uint8_t)tx);
+        flash_write8(s, s->cur_addr, (uint8_t)tx);
+        s->cur_addr++;
+        break;
+
+    case STATE_READ:
+        r = s->storage[s->cur_addr];
+        DB_PRINT("READ 0x%lx=%x\n", s->cur_addr, r);
+        s->cur_addr = (s->cur_addr + 1) % s->size;
+        break;
+
+    case STATE_COLLECTING_DATA:
+        s->data[s->len] = (uint8_t)tx;
+        s->len++;
+
+        if (s->len == s->needed_bytes) {
+            complete_collecting_data(s);
+        }
+        break;
+
+    case STATE_READING_DATA:
+        r = s->data[s->pos];
+        s->pos++;
+        if (s->pos == s->len) {
+            s->pos = 0;
+            s->state = STATE_IDLE;
+        }
+        break;
+
+    default:
+    case STATE_IDLE:
+        decode_new_cmd(s, (uint8_t)tx);
+        break;
+    }
+
+    return r;
+}
+
+static int m25p80_init(SSISlave *ss)
+{
+    DriveInfo *dinfo;
+    Flash *s = FROM_SSI_SLAVE(Flash, ss);
+    M25P80Class *mc = M25P80_GET_CLASS(s);
+
+    s->pi = mc->pi;
+
+    s->size = s->pi->sector_size * s->pi->n_sectors;
+    s->dirty_page = -1;
+    s->storage = qemu_blockalign(s->bdrv, s->size);
+
+    dinfo = drive_get_next(IF_MTD);
+
+    if (dinfo && dinfo->bdrv) {
+        DB_PRINT("Binding to IF_MTD drive\n");
+        s->bdrv = dinfo->bdrv;
+        /* FIXME: Move to late init */
+        if (bdrv_read(s->bdrv, 0, s->storage, DIV_ROUND_UP(s->size,
+                                                    BDRV_SECTOR_SIZE))) {
+            fprintf(stderr, "Failed to initialize SPI flash!\n");
+            return 1;
+        }
+    } else {
+        memset(s->storage, 0xFF, s->size);
+    }
+
+    return 0;
+}
+
+static void m25p80_pre_save(void *opaque)
+{
+    flash_sync_dirty((Flash *)opaque, -1);
+}
+
+static const VMStateDescription vmstate_m25p80 = {
+    .name = "xilinx_spi",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .pre_save = m25p80_pre_save,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT8(state, Flash),
+        VMSTATE_UINT8_ARRAY(data, Flash, 16),
+        VMSTATE_UINT32(len, Flash),
+        VMSTATE_UINT32(pos, Flash),
+        VMSTATE_UINT8(needed_bytes, Flash),
+        VMSTATE_UINT8(cmd_in_progress, Flash),
+        VMSTATE_UINT64(cur_addr, Flash),
+        VMSTATE_BOOL(write_enable, Flash),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void m25p80_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
+    M25P80Class *mc = M25P80_CLASS(klass);
+
+    k->init = m25p80_init;
+    k->transfer = m25p80_transfer8;
+    k->set_cs = m25p80_cs;
+    k->cs_polarity = SSI_CS_LOW;
+    dc->vmsd = &vmstate_m25p80;
+    mc->pi = data;
+}
+
+static const TypeInfo m25p80_info = {
+    .name           = TYPE_M25P80,
+    .parent         = TYPE_SSI_SLAVE,
+    .instance_size  = sizeof(Flash),
+    .class_size     = sizeof(M25P80Class),
+    .abstract       = true,
+};
+
+static void m25p80_register_types(void)
+{
+    int i;
+
+    type_register_static(&m25p80_info);
+    for (i = 0; i < ARRAY_SIZE(known_devices); ++i) {
+        TypeInfo ti = {
+            .name       = known_devices[i].part_name,
+            .parent     = TYPE_M25P80,
+            .class_init = m25p80_class_init,
+            .class_data = (void *)&known_devices[i],
+        };
+        type_register(&ti);
+    }
+}
+
+type_init(m25p80_register_types)
diff --git a/hw/block/nand.c b/hw/block/nand.c
new file mode 100644 (file)
index 0000000..087ca14
--- /dev/null
@@ -0,0 +1,791 @@
+/*
+ * Flash NAND memory emulation.  Based on "16M x 8 Bit NAND Flash
+ * Memory" datasheet for the KM29U128AT / K9F2808U0A chips from
+ * Samsung Electronic.
+ *
+ * Copyright (c) 2006 Openedhand Ltd.
+ * Written by Andrzej Zaborowski <balrog@zabor.org>
+ *
+ * Support for additional features based on "MT29F2G16ABCWP 2Gx16"
+ * datasheet from Micron Technology and "NAND02G-B2C" datasheet
+ * 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
+
+# include "hw/hw.h"
+# include "hw/block/flash.h"
+# include "sysemu/blockdev.h"
+# include "hw/sysbus.h"
+#include "qemu/error-report.h"
+
+# define NAND_CMD_READ0                0x00
+# define NAND_CMD_READ1                0x01
+# define NAND_CMD_READ2                0x50
+# define NAND_CMD_LPREAD2      0x30
+# define NAND_CMD_NOSERIALREAD2        0x35
+# define NAND_CMD_RANDOMREAD1  0x05
+# define NAND_CMD_RANDOMREAD2  0xe0
+# define NAND_CMD_READID       0x90
+# define NAND_CMD_RESET                0xff
+# define NAND_CMD_PAGEPROGRAM1 0x80
+# define NAND_CMD_PAGEPROGRAM2 0x10
+# define NAND_CMD_CACHEPROGRAM2        0x15
+# define NAND_CMD_BLOCKERASE1  0x60
+# define NAND_CMD_BLOCKERASE2  0xd0
+# define NAND_CMD_READSTATUS   0x70
+# define NAND_CMD_COPYBACKPRG1 0x85
+
+# define NAND_IOSTATUS_ERROR   (1 << 0)
+# define NAND_IOSTATUS_PLANE0  (1 << 1)
+# define NAND_IOSTATUS_PLANE1  (1 << 2)
+# define NAND_IOSTATUS_PLANE2  (1 << 3)
+# define NAND_IOSTATUS_PLANE3  (1 << 4)
+# define NAND_IOSTATUS_READY    (1 << 6)
+# define NAND_IOSTATUS_UNPROTCT        (1 << 7)
+
+# define MAX_PAGE              0x800
+# define MAX_OOB               0x40
+
+typedef struct NANDFlashState NANDFlashState;
+struct NANDFlashState {
+    SysBusDevice busdev;
+    uint8_t manf_id, chip_id;
+    uint8_t buswidth; /* in BYTES */
+    int size, pages;
+    int page_shift, oob_shift, erase_shift, addr_shift;
+    uint8_t *storage;
+    BlockDriverState *bdrv;
+    int mem_oob;
+
+    uint8_t cle, ale, ce, wp, gnd;
+
+    uint8_t io[MAX_PAGE + MAX_OOB + 0x400];
+    uint8_t *ioaddr;
+    int iolen;
+
+    uint32_t cmd;
+    uint64_t addr;
+    int addrlen;
+    int status;
+    int offset;
+
+    void (*blk_write)(NANDFlashState *s);
+    void (*blk_erase)(NANDFlashState *s);
+    void (*blk_load)(NANDFlashState *s, uint64_t addr, int offset);
+
+    uint32_t ioaddr_vmstate;
+};
+
+static void mem_and(uint8_t *dest, const uint8_t *src, size_t n)
+{
+    /* Like memcpy() but we logical-AND the data into the destination */
+    int i;
+    for (i = 0; i < n; i++) {
+        dest[i] &= src[i];
+    }
+}
+
+# define NAND_NO_AUTOINCR      0x00000001
+# define NAND_BUSWIDTH_16      0x00000002
+# define NAND_NO_PADDING       0x00000004
+# define NAND_CACHEPRG         0x00000008
+# define NAND_COPYBACK         0x00000010
+# define NAND_IS_AND           0x00000020
+# define NAND_4PAGE_ARRAY      0x00000040
+# define NAND_NO_READRDY       0x00000100
+# define NAND_SAMSUNG_LP       (NAND_NO_PADDING | NAND_COPYBACK)
+
+# define NAND_IO
+
+# define PAGE(addr)            ((addr) >> ADDR_SHIFT)
+# define PAGE_START(page)      (PAGE(page) * (PAGE_SIZE + OOB_SIZE))
+# define PAGE_MASK             ((1 << ADDR_SHIFT) - 1)
+# define OOB_SHIFT             (PAGE_SHIFT - 5)
+# define OOB_SIZE              (1 << OOB_SHIFT)
+# define SECTOR(addr)          ((addr) >> (9 + ADDR_SHIFT - PAGE_SHIFT))
+# define SECTOR_OFFSET(addr)   ((addr) & ((511 >> PAGE_SHIFT) << 8))
+
+# define PAGE_SIZE             256
+# define PAGE_SHIFT            8
+# define PAGE_SECTORS          1
+# define ADDR_SHIFT            8
+# include "nand.c"
+# define PAGE_SIZE             512
+# define PAGE_SHIFT            9
+# define PAGE_SECTORS          1
+# define ADDR_SHIFT            8
+# include "nand.c"
+# define PAGE_SIZE             2048
+# define PAGE_SHIFT            11
+# define PAGE_SECTORS          4
+# define ADDR_SHIFT            16
+# include "nand.c"
+
+/* Information based on Linux drivers/mtd/nand/nand_ids.c */
+static const struct {
+    int size;
+    int width;
+    int page_shift;
+    int erase_shift;
+    uint32_t options;
+} nand_flash_ids[0x100] = {
+    [0 ... 0xff] = { 0 },
+
+    [0x6e] = { 1,      8,      8, 4, 0 },
+    [0x64] = { 2,      8,      8, 4, 0 },
+    [0x6b] = { 4,      8,      9, 4, 0 },
+    [0xe8] = { 1,      8,      8, 4, 0 },
+    [0xec] = { 1,      8,      8, 4, 0 },
+    [0xea] = { 2,      8,      8, 4, 0 },
+    [0xd5] = { 4,      8,      9, 4, 0 },
+    [0xe3] = { 4,      8,      9, 4, 0 },
+    [0xe5] = { 4,      8,      9, 4, 0 },
+    [0xd6] = { 8,      8,      9, 4, 0 },
+
+    [0x39] = { 8,      8,      9, 4, 0 },
+    [0xe6] = { 8,      8,      9, 4, 0 },
+    [0x49] = { 8,      16,     9, 4, NAND_BUSWIDTH_16 },
+    [0x59] = { 8,      16,     9, 4, NAND_BUSWIDTH_16 },
+
+    [0x33] = { 16,     8,      9, 5, 0 },
+    [0x73] = { 16,     8,      9, 5, 0 },
+    [0x43] = { 16,     16,     9, 5, NAND_BUSWIDTH_16 },
+    [0x53] = { 16,     16,     9, 5, NAND_BUSWIDTH_16 },
+
+    [0x35] = { 32,     8,      9, 5, 0 },
+    [0x75] = { 32,     8,      9, 5, 0 },
+    [0x45] = { 32,     16,     9, 5, NAND_BUSWIDTH_16 },
+    [0x55] = { 32,     16,     9, 5, NAND_BUSWIDTH_16 },
+
+    [0x36] = { 64,     8,      9, 5, 0 },
+    [0x76] = { 64,     8,      9, 5, 0 },
+    [0x46] = { 64,     16,     9, 5, NAND_BUSWIDTH_16 },
+    [0x56] = { 64,     16,     9, 5, NAND_BUSWIDTH_16 },
+
+    [0x78] = { 128,    8,      9, 5, 0 },
+    [0x39] = { 128,    8,      9, 5, 0 },
+    [0x79] = { 128,    8,      9, 5, 0 },
+    [0x72] = { 128,    16,     9, 5, NAND_BUSWIDTH_16 },
+    [0x49] = { 128,    16,     9, 5, NAND_BUSWIDTH_16 },
+    [0x74] = { 128,    16,     9, 5, NAND_BUSWIDTH_16 },
+    [0x59] = { 128,    16,     9, 5, NAND_BUSWIDTH_16 },
+
+    [0x71] = { 256,    8,      9, 5, 0 },
+
+    /*
+     * These are the new chips with large page size. The pagesize and the
+     * erasesize is determined from the extended id bytes
+     */
+# define LP_OPTIONS    (NAND_SAMSUNG_LP | NAND_NO_READRDY | NAND_NO_AUTOINCR)
+# define LP_OPTIONS16  (LP_OPTIONS | NAND_BUSWIDTH_16)
+
+    /* 512 Megabit */
+    [0xa2] = { 64,     8,      0, 0, LP_OPTIONS },
+    [0xf2] = { 64,     8,      0, 0, LP_OPTIONS },
+    [0xb2] = { 64,     16,     0, 0, LP_OPTIONS16 },
+    [0xc2] = { 64,     16,     0, 0, LP_OPTIONS16 },
+
+    /* 1 Gigabit */
+    [0xa1] = { 128,    8,      0, 0, LP_OPTIONS },
+    [0xf1] = { 128,    8,      0, 0, LP_OPTIONS },
+    [0xb1] = { 128,    16,     0, 0, LP_OPTIONS16 },
+    [0xc1] = { 128,    16,     0, 0, LP_OPTIONS16 },
+
+    /* 2 Gigabit */
+    [0xaa] = { 256,    8,      0, 0, LP_OPTIONS },
+    [0xda] = { 256,    8,      0, 0, LP_OPTIONS },
+    [0xba] = { 256,    16,     0, 0, LP_OPTIONS16 },
+    [0xca] = { 256,    16,     0, 0, LP_OPTIONS16 },
+
+    /* 4 Gigabit */
+    [0xac] = { 512,    8,      0, 0, LP_OPTIONS },
+    [0xdc] = { 512,    8,      0, 0, LP_OPTIONS },
+    [0xbc] = { 512,    16,     0, 0, LP_OPTIONS16 },
+    [0xcc] = { 512,    16,     0, 0, LP_OPTIONS16 },
+
+    /* 8 Gigabit */
+    [0xa3] = { 1024,   8,      0, 0, LP_OPTIONS },
+    [0xd3] = { 1024,   8,      0, 0, LP_OPTIONS },
+    [0xb3] = { 1024,   16,     0, 0, LP_OPTIONS16 },
+    [0xc3] = { 1024,   16,     0, 0, LP_OPTIONS16 },
+
+    /* 16 Gigabit */
+    [0xa5] = { 2048,   8,      0, 0, LP_OPTIONS },
+    [0xd5] = { 2048,   8,      0, 0, LP_OPTIONS },
+    [0xb5] = { 2048,   16,     0, 0, LP_OPTIONS16 },
+    [0xc5] = { 2048,   16,     0, 0, LP_OPTIONS16 },
+};
+
+static void nand_reset(DeviceState *dev)
+{
+    NANDFlashState *s = FROM_SYSBUS(NANDFlashState, SYS_BUS_DEVICE(dev));
+    s->cmd = NAND_CMD_READ0;
+    s->addr = 0;
+    s->addrlen = 0;
+    s->iolen = 0;
+    s->offset = 0;
+    s->status &= NAND_IOSTATUS_UNPROTCT;
+    s->status |= NAND_IOSTATUS_READY;
+}
+
+static inline void nand_pushio_byte(NANDFlashState *s, uint8_t value)
+{
+    s->ioaddr[s->iolen++] = value;
+    for (value = s->buswidth; --value;) {
+        s->ioaddr[s->iolen++] = 0;
+    }
+}
+
+static void nand_command(NANDFlashState *s)
+{
+    unsigned int offset;
+    switch (s->cmd) {
+    case NAND_CMD_READ0:
+        s->iolen = 0;
+        break;
+
+    case NAND_CMD_READID:
+        s->ioaddr = s->io;
+        s->iolen = 0;
+        nand_pushio_byte(s, s->manf_id);
+        nand_pushio_byte(s, s->chip_id);
+        nand_pushio_byte(s, 'Q'); /* Don't-care byte (often 0xa5) */
+        if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) {
+            /* Page Size, Block Size, Spare Size; bit 6 indicates
+             * 8 vs 16 bit width NAND.
+             */
+            nand_pushio_byte(s, (s->buswidth == 2) ? 0x55 : 0x15);
+        } else {
+            nand_pushio_byte(s, 0xc0); /* Multi-plane */
+        }
+        break;
+
+    case NAND_CMD_RANDOMREAD2:
+    case NAND_CMD_NOSERIALREAD2:
+        if (!(nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP))
+            break;
+        offset = s->addr & ((1 << s->addr_shift) - 1);
+        s->blk_load(s, s->addr, offset);
+        if (s->gnd)
+            s->iolen = (1 << s->page_shift) - offset;
+        else
+            s->iolen = (1 << s->page_shift) + (1 << s->oob_shift) - offset;
+        break;
+
+    case NAND_CMD_RESET:
+        nand_reset(&s->busdev.qdev);
+        break;
+
+    case NAND_CMD_PAGEPROGRAM1:
+        s->ioaddr = s->io;
+        s->iolen = 0;
+        break;
+
+    case NAND_CMD_PAGEPROGRAM2:
+        if (s->wp) {
+            s->blk_write(s);
+        }
+        break;
+
+    case NAND_CMD_BLOCKERASE1:
+        break;
+
+    case NAND_CMD_BLOCKERASE2:
+        s->addr &= (1ull << s->addrlen * 8) - 1;
+        if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP)
+            s->addr <<= 16;
+        else
+            s->addr <<= 8;
+
+        if (s->wp) {
+            s->blk_erase(s);
+        }
+        break;
+
+    case NAND_CMD_READSTATUS:
+        s->ioaddr = s->io;
+        s->iolen = 0;
+        nand_pushio_byte(s, s->status);
+        break;
+
+    default:
+        printf("%s: Unknown NAND command 0x%02x\n", __FUNCTION__, s->cmd);
+    }
+}
+
+static void nand_pre_save(void *opaque)
+{
+    NANDFlashState *s = opaque;
+
+    s->ioaddr_vmstate = s->ioaddr - s->io;
+}
+
+static int nand_post_load(void *opaque, int version_id)
+{
+    NANDFlashState *s = opaque;
+
+    if (s->ioaddr_vmstate > sizeof(s->io)) {
+        return -EINVAL;
+    }
+    s->ioaddr = s->io + s->ioaddr_vmstate;
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_nand = {
+    .name = "nand",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .pre_save = nand_pre_save,
+    .post_load = nand_post_load,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT8(cle, NANDFlashState),
+        VMSTATE_UINT8(ale, NANDFlashState),
+        VMSTATE_UINT8(ce, NANDFlashState),
+        VMSTATE_UINT8(wp, NANDFlashState),
+        VMSTATE_UINT8(gnd, NANDFlashState),
+        VMSTATE_BUFFER(io, NANDFlashState),
+        VMSTATE_UINT32(ioaddr_vmstate, NANDFlashState),
+        VMSTATE_INT32(iolen, NANDFlashState),
+        VMSTATE_UINT32(cmd, NANDFlashState),
+        VMSTATE_UINT64(addr, NANDFlashState),
+        VMSTATE_INT32(addrlen, NANDFlashState),
+        VMSTATE_INT32(status, NANDFlashState),
+        VMSTATE_INT32(offset, NANDFlashState),
+        /* XXX: do we want to save s->storage too? */
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int nand_device_init(SysBusDevice *dev)
+{
+    int pagesize;
+    NANDFlashState *s = FROM_SYSBUS(NANDFlashState, dev);
+
+    s->buswidth = nand_flash_ids[s->chip_id].width >> 3;
+    s->size = nand_flash_ids[s->chip_id].size << 20;
+    if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) {
+        s->page_shift = 11;
+        s->erase_shift = 6;
+    } else {
+        s->page_shift = nand_flash_ids[s->chip_id].page_shift;
+        s->erase_shift = nand_flash_ids[s->chip_id].erase_shift;
+    }
+
+    switch (1 << s->page_shift) {
+    case 256:
+        nand_init_256(s);
+        break;
+    case 512:
+        nand_init_512(s);
+        break;
+    case 2048:
+        nand_init_2048(s);
+        break;
+    default:
+        error_report("Unsupported NAND block size");
+        return -1;
+    }
+
+    pagesize = 1 << s->oob_shift;
+    s->mem_oob = 1;
+    if (s->bdrv) {
+        if (bdrv_is_read_only(s->bdrv)) {
+            error_report("Can't use a read-only drive");
+            return -1;
+        }
+        if (bdrv_getlength(s->bdrv) >=
+                (s->pages << s->page_shift) + (s->pages << s->oob_shift)) {
+            pagesize = 0;
+            s->mem_oob = 0;
+        }
+    } else {
+        pagesize += 1 << s->page_shift;
+    }
+    if (pagesize) {
+        s->storage = (uint8_t *) memset(g_malloc(s->pages * pagesize),
+                        0xff, s->pages * pagesize);
+    }
+    /* Give s->ioaddr a sane value in case we save state before it is used. */
+    s->ioaddr = s->io;
+
+    return 0;
+}
+
+static Property nand_properties[] = {
+    DEFINE_PROP_UINT8("manufacturer_id", NANDFlashState, manf_id, 0),
+    DEFINE_PROP_UINT8("chip_id", NANDFlashState, chip_id, 0),
+    DEFINE_PROP_DRIVE("drive", NANDFlashState, bdrv),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void nand_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = nand_device_init;
+    dc->reset = nand_reset;
+    dc->vmsd = &vmstate_nand;
+    dc->props = nand_properties;
+}
+
+static const TypeInfo nand_info = {
+    .name          = "nand",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(NANDFlashState),
+    .class_init    = nand_class_init,
+};
+
+static void nand_register_types(void)
+{
+    type_register_static(&nand_info);
+}
+
+/*
+ * Chip inputs are CLE, ALE, CE, WP, GND and eight I/O pins.  Chip
+ * outputs are R/B and eight I/O pins.
+ *
+ * CE, WP and R/B are active low.
+ */
+void nand_setpins(DeviceState *dev, uint8_t cle, uint8_t ale,
+                  uint8_t ce, uint8_t wp, uint8_t gnd)
+{
+    NANDFlashState *s = (NANDFlashState *) dev;
+    s->cle = cle;
+    s->ale = ale;
+    s->ce = ce;
+    s->wp = wp;
+    s->gnd = gnd;
+    if (wp)
+        s->status |= NAND_IOSTATUS_UNPROTCT;
+    else
+        s->status &= ~NAND_IOSTATUS_UNPROTCT;
+}
+
+void nand_getpins(DeviceState *dev, int *rb)
+{
+    *rb = 1;
+}
+
+void nand_setio(DeviceState *dev, uint32_t value)
+{
+    int i;
+    NANDFlashState *s = (NANDFlashState *) dev;
+    if (!s->ce && s->cle) {
+        if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) {
+            if (s->cmd == NAND_CMD_READ0 && value == NAND_CMD_LPREAD2)
+                return;
+            if (value == NAND_CMD_RANDOMREAD1) {
+                s->addr &= ~((1 << s->addr_shift) - 1);
+                s->addrlen = 0;
+                return;
+            }
+        }
+        if (value == NAND_CMD_READ0)
+            s->offset = 0;
+       else if (value == NAND_CMD_READ1) {
+            s->offset = 0x100;
+            value = NAND_CMD_READ0;
+        }
+       else if (value == NAND_CMD_READ2) {
+            s->offset = 1 << s->page_shift;
+            value = NAND_CMD_READ0;
+        }
+
+        s->cmd = value;
+
+        if (s->cmd == NAND_CMD_READSTATUS ||
+                s->cmd == NAND_CMD_PAGEPROGRAM2 ||
+                s->cmd == NAND_CMD_BLOCKERASE1 ||
+                s->cmd == NAND_CMD_BLOCKERASE2 ||
+                s->cmd == NAND_CMD_NOSERIALREAD2 ||
+                s->cmd == NAND_CMD_RANDOMREAD2 ||
+                s->cmd == NAND_CMD_RESET)
+            nand_command(s);
+
+        if (s->cmd != NAND_CMD_RANDOMREAD2) {
+            s->addrlen = 0;
+        }
+    }
+
+    if (s->ale) {
+        unsigned int shift = s->addrlen * 8;
+        unsigned int mask = ~(0xff << shift);
+        unsigned int v = value << shift;
+
+        s->addr = (s->addr & mask) | v;
+        s->addrlen ++;
+
+        switch (s->addrlen) {
+        case 1:
+            if (s->cmd == NAND_CMD_READID) {
+                nand_command(s);
+            }
+            break;
+        case 2: /* fix cache address as a byte address */
+            s->addr <<= (s->buswidth - 1);
+            break;
+        case 3:
+            if (!(nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) &&
+                    (s->cmd == NAND_CMD_READ0 ||
+                     s->cmd == NAND_CMD_PAGEPROGRAM1)) {
+                nand_command(s);
+            }
+            break;
+        case 4:
+            if ((nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) &&
+                    nand_flash_ids[s->chip_id].size < 256 && /* 1Gb or less */
+                    (s->cmd == NAND_CMD_READ0 ||
+                     s->cmd == NAND_CMD_PAGEPROGRAM1)) {
+                nand_command(s);
+            }
+            break;
+        case 5:
+            if ((nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) &&
+                    nand_flash_ids[s->chip_id].size >= 256 && /* 2Gb or more */
+                    (s->cmd == NAND_CMD_READ0 ||
+                     s->cmd == NAND_CMD_PAGEPROGRAM1)) {
+                nand_command(s);
+            }
+            break;
+        default:
+            break;
+        }
+    }
+
+    if (!s->cle && !s->ale && s->cmd == NAND_CMD_PAGEPROGRAM1) {
+        if (s->iolen < (1 << s->page_shift) + (1 << s->oob_shift)) {
+            for (i = s->buswidth; i--; value >>= 8) {
+                s->io[s->iolen ++] = (uint8_t) (value & 0xff);
+            }
+        }
+    } else if (!s->cle && !s->ale && s->cmd == NAND_CMD_COPYBACKPRG1) {
+        if ((s->addr & ((1 << s->addr_shift) - 1)) <
+                (1 << s->page_shift) + (1 << s->oob_shift)) {
+            for (i = s->buswidth; i--; s->addr++, value >>= 8) {
+                s->io[s->iolen + (s->addr & ((1 << s->addr_shift) - 1))] =
+                    (uint8_t) (value & 0xff);
+            }
+        }
+    }
+}
+
+uint32_t nand_getio(DeviceState *dev)
+{
+    int offset;
+    uint32_t x = 0;
+    NANDFlashState *s = (NANDFlashState *) dev;
+
+    /* Allow sequential reading */
+    if (!s->iolen && s->cmd == NAND_CMD_READ0) {
+        offset = (int) (s->addr & ((1 << s->addr_shift) - 1)) + s->offset;
+        s->offset = 0;
+
+        s->blk_load(s, s->addr, offset);
+        if (s->gnd)
+            s->iolen = (1 << s->page_shift) - offset;
+        else
+            s->iolen = (1 << s->page_shift) + (1 << s->oob_shift) - offset;
+    }
+
+    if (s->ce || s->iolen <= 0)
+        return 0;
+
+    for (offset = s->buswidth; offset--;) {
+        x |= s->ioaddr[offset] << (offset << 3);
+    }
+    /* after receiving READ STATUS command all subsequent reads will
+     * return the status register value until another command is issued
+     */
+    if (s->cmd != NAND_CMD_READSTATUS) {
+        s->addr   += s->buswidth;
+        s->ioaddr += s->buswidth;
+        s->iolen  -= s->buswidth;
+    }
+    return x;
+}
+
+uint32_t nand_getbuswidth(DeviceState *dev)
+{
+    NANDFlashState *s = (NANDFlashState *) dev;
+    return s->buswidth << 3;
+}
+
+DeviceState *nand_init(BlockDriverState *bdrv, int manf_id, int chip_id)
+{
+    DeviceState *dev;
+
+    if (nand_flash_ids[chip_id].size == 0) {
+        hw_error("%s: Unsupported NAND chip ID.\n", __FUNCTION__);
+    }
+    dev = qdev_create(NULL, "nand");
+    qdev_prop_set_uint8(dev, "manufacturer_id", manf_id);
+    qdev_prop_set_uint8(dev, "chip_id", chip_id);
+    if (bdrv) {
+        qdev_prop_set_drive_nofail(dev, "drive", bdrv);
+    }
+
+    qdev_init_nofail(dev);
+    return dev;
+}
+
+type_init(nand_register_types)
+
+#else
+
+/* Program a single page */
+static void glue(nand_blk_write_, PAGE_SIZE)(NANDFlashState *s)
+{
+    uint64_t off, page, sector, soff;
+    uint8_t iobuf[(PAGE_SECTORS + 2) * 0x200];
+    if (PAGE(s->addr) >= s->pages)
+        return;
+
+    if (!s->bdrv) {
+        mem_and(s->storage + PAGE_START(s->addr) + (s->addr & PAGE_MASK) +
+                        s->offset, s->io, s->iolen);
+    } else if (s->mem_oob) {
+        sector = SECTOR(s->addr);
+        off = (s->addr & PAGE_MASK) + s->offset;
+        soff = SECTOR_OFFSET(s->addr);
+        if (bdrv_read(s->bdrv, sector, iobuf, PAGE_SECTORS) < 0) {
+            printf("%s: read error in sector %" PRIu64 "\n", __func__, sector);
+            return;
+        }
+
+        mem_and(iobuf + (soff | off), s->io, MIN(s->iolen, PAGE_SIZE - off));
+        if (off + s->iolen > PAGE_SIZE) {
+            page = PAGE(s->addr);
+            mem_and(s->storage + (page << OOB_SHIFT), s->io + PAGE_SIZE - off,
+                            MIN(OOB_SIZE, off + s->iolen - PAGE_SIZE));
+        }
+
+        if (bdrv_write(s->bdrv, sector, iobuf, PAGE_SECTORS) < 0) {
+            printf("%s: write error in sector %" PRIu64 "\n", __func__, sector);
+        }
+    } else {
+        off = PAGE_START(s->addr) + (s->addr & PAGE_MASK) + s->offset;
+        sector = off >> 9;
+        soff = off & 0x1ff;
+        if (bdrv_read(s->bdrv, sector, iobuf, PAGE_SECTORS + 2) < 0) {
+            printf("%s: read error in sector %" PRIu64 "\n", __func__, sector);
+            return;
+        }
+
+        mem_and(iobuf + soff, s->io, s->iolen);
+
+        if (bdrv_write(s->bdrv, sector, iobuf, PAGE_SECTORS + 2) < 0) {
+            printf("%s: write error in sector %" PRIu64 "\n", __func__, sector);
+        }
+    }
+    s->offset = 0;
+}
+
+/* Erase a single block */
+static void glue(nand_blk_erase_, PAGE_SIZE)(NANDFlashState *s)
+{
+    uint64_t i, page, addr;
+    uint8_t iobuf[0x200] = { [0 ... 0x1ff] = 0xff, };
+    addr = s->addr & ~((1 << (ADDR_SHIFT + s->erase_shift)) - 1);
+
+    if (PAGE(addr) >= s->pages)
+        return;
+
+    if (!s->bdrv) {
+        memset(s->storage + PAGE_START(addr),
+                        0xff, (PAGE_SIZE + OOB_SIZE) << s->erase_shift);
+    } else if (s->mem_oob) {
+        memset(s->storage + (PAGE(addr) << OOB_SHIFT),
+                        0xff, OOB_SIZE << s->erase_shift);
+        i = SECTOR(addr);
+        page = SECTOR(addr + (ADDR_SHIFT + s->erase_shift));
+        for (; i < page; i ++)
+            if (bdrv_write(s->bdrv, i, iobuf, 1) < 0) {
+                printf("%s: write error in sector %" PRIu64 "\n", __func__, i);
+            }
+    } else {
+        addr = PAGE_START(addr);
+        page = addr >> 9;
+        if (bdrv_read(s->bdrv, page, iobuf, 1) < 0) {
+            printf("%s: read error in sector %" PRIu64 "\n", __func__, page);
+        }
+        memset(iobuf + (addr & 0x1ff), 0xff, (~addr & 0x1ff) + 1);
+        if (bdrv_write(s->bdrv, page, iobuf, 1) < 0) {
+            printf("%s: write error in sector %" PRIu64 "\n", __func__, page);
+        }
+
+        memset(iobuf, 0xff, 0x200);
+        i = (addr & ~0x1ff) + 0x200;
+        for (addr += ((PAGE_SIZE + OOB_SIZE) << s->erase_shift) - 0x200;
+                        i < addr; i += 0x200)
+            if (bdrv_write(s->bdrv, i >> 9, iobuf, 1) < 0) {
+                printf("%s: write error in sector %" PRIu64 "\n",
+                       __func__, i >> 9);
+            }
+
+        page = i >> 9;
+        if (bdrv_read(s->bdrv, page, iobuf, 1) < 0) {
+            printf("%s: read error in sector %" PRIu64 "\n", __func__, page);
+        }
+        memset(iobuf, 0xff, ((addr - 1) & 0x1ff) + 1);
+        if (bdrv_write(s->bdrv, page, iobuf, 1) < 0) {
+            printf("%s: write error in sector %" PRIu64 "\n", __func__, page);
+        }
+    }
+}
+
+static void glue(nand_blk_load_, PAGE_SIZE)(NANDFlashState *s,
+                uint64_t addr, int offset)
+{
+    if (PAGE(addr) >= s->pages)
+        return;
+
+    if (s->bdrv) {
+        if (s->mem_oob) {
+            if (bdrv_read(s->bdrv, SECTOR(addr), s->io, PAGE_SECTORS) < 0) {
+                printf("%s: read error in sector %" PRIu64 "\n",
+                                __func__, SECTOR(addr));
+            }
+            memcpy(s->io + SECTOR_OFFSET(s->addr) + PAGE_SIZE,
+                            s->storage + (PAGE(s->addr) << OOB_SHIFT),
+                            OOB_SIZE);
+            s->ioaddr = s->io + SECTOR_OFFSET(s->addr) + offset;
+        } else {
+            if (bdrv_read(s->bdrv, PAGE_START(addr) >> 9,
+                                    s->io, (PAGE_SECTORS + 2)) < 0) {
+                printf("%s: read error in sector %" PRIu64 "\n",
+                                __func__, PAGE_START(addr) >> 9);
+            }
+            s->ioaddr = s->io + (PAGE_START(addr) & 0x1ff) + offset;
+        }
+    } else {
+        memcpy(s->io, s->storage + PAGE_START(s->addr) +
+                        offset, PAGE_SIZE + OOB_SIZE - offset);
+        s->ioaddr = s->io;
+    }
+}
+
+static void glue(nand_init_, PAGE_SIZE)(NANDFlashState *s)
+{
+    s->oob_shift = PAGE_SHIFT - 5;
+    s->pages = s->size >> PAGE_SHIFT;
+    s->addr_shift = ADDR_SHIFT;
+
+    s->blk_erase = glue(nand_blk_erase_, PAGE_SIZE);
+    s->blk_write = glue(nand_blk_write_, PAGE_SIZE);
+    s->blk_load = glue(nand_blk_load_, PAGE_SIZE);
+}
+
+# undef PAGE_SIZE
+# undef PAGE_SHIFT
+# undef PAGE_SECTORS
+# undef ADDR_SHIFT
+#endif /* NAND_IO */
diff --git a/hw/block/onenand.c b/hw/block/onenand.c
new file mode 100644 (file)
index 0000000..8b511a7
--- /dev/null
@@ -0,0 +1,842 @@
+/*
+ * OneNAND flash memories emulation.
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ * Written by Andrzej Zaborowski <andrew@openedhand.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 or
+ * (at your option) version 3 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
+ * 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 "hw/hw.h"
+#include "hw/block/flash.h"
+#include "hw/irq.h"
+#include "sysemu/blockdev.h"
+#include "exec/memory.h"
+#include "exec/address-spaces.h"
+#include "hw/sysbus.h"
+#include "qemu/error-report.h"
+
+/* 11 for 2kB-page OneNAND ("2nd generation") and 10 for 1kB-page chips */
+#define PAGE_SHIFT     11
+
+/* Fixed */
+#define BLOCK_SHIFT    (PAGE_SHIFT + 6)
+
+typedef struct {
+    SysBusDevice busdev;
+    struct {
+        uint16_t man;
+        uint16_t dev;
+        uint16_t ver;
+    } id;
+    int shift;
+    hwaddr base;
+    qemu_irq intr;
+    qemu_irq rdy;
+    BlockDriverState *bdrv;
+    BlockDriverState *bdrv_cur;
+    uint8_t *image;
+    uint8_t *otp;
+    uint8_t *current;
+    MemoryRegion ram;
+    MemoryRegion mapped_ram;
+    uint8_t current_direction;
+    uint8_t *boot[2];
+    uint8_t *data[2][2];
+    MemoryRegion iomem;
+    MemoryRegion container;
+    int cycle;
+    int otpmode;
+
+    uint16_t addr[8];
+    uint16_t unladdr[8];
+    int bufaddr;
+    int count;
+    uint16_t command;
+    uint16_t config[2];
+    uint16_t status;
+    uint16_t intstatus;
+    uint16_t wpstatus;
+
+    ECCState ecc;
+
+    int density_mask;
+    int secs;
+    int secs_cur;
+    int blocks;
+    uint8_t *blockwp;
+} OneNANDState;
+
+enum {
+    ONEN_BUF_BLOCK = 0,
+    ONEN_BUF_BLOCK2 = 1,
+    ONEN_BUF_DEST_BLOCK = 2,
+    ONEN_BUF_DEST_PAGE = 3,
+    ONEN_BUF_PAGE = 7,
+};
+
+enum {
+    ONEN_ERR_CMD = 1 << 10,
+    ONEN_ERR_ERASE = 1 << 11,
+    ONEN_ERR_PROG = 1 << 12,
+    ONEN_ERR_LOAD = 1 << 13,
+};
+
+enum {
+    ONEN_INT_RESET = 1 << 4,
+    ONEN_INT_ERASE = 1 << 5,
+    ONEN_INT_PROG = 1 << 6,
+    ONEN_INT_LOAD = 1 << 7,
+    ONEN_INT = 1 << 15,
+};
+
+enum {
+    ONEN_LOCK_LOCKTIGHTEN = 1 << 0,
+    ONEN_LOCK_LOCKED = 1 << 1,
+    ONEN_LOCK_UNLOCKED = 1 << 2,
+};
+
+static void onenand_mem_setup(OneNANDState *s)
+{
+    /* XXX: We should use IO_MEM_ROMD but we broke it earlier...
+     * Both 0x0000 ... 0x01ff and 0x8000 ... 0x800f can be used to
+     * write boot commands.  Also take note of the BWPS bit.  */
+    memory_region_init(&s->container, "onenand", 0x10000 << s->shift);
+    memory_region_add_subregion(&s->container, 0, &s->iomem);
+    memory_region_init_alias(&s->mapped_ram, "onenand-mapped-ram",
+                             &s->ram, 0x0200 << s->shift,
+                             0xbe00 << s->shift);
+    memory_region_add_subregion_overlap(&s->container,
+                                        0x0200 << s->shift,
+                                        &s->mapped_ram,
+                                        1);
+}
+
+static void onenand_intr_update(OneNANDState *s)
+{
+    qemu_set_irq(s->intr, ((s->intstatus >> 15) ^ (~s->config[0] >> 6)) & 1);
+}
+
+static void onenand_pre_save(void *opaque)
+{
+    OneNANDState *s = opaque;
+    if (s->current == s->otp) {
+        s->current_direction = 1;
+    } else if (s->current == s->image) {
+        s->current_direction = 2;
+    } else {
+        s->current_direction = 0;
+    }
+}
+
+static int onenand_post_load(void *opaque, int version_id)
+{
+    OneNANDState *s = opaque;
+    switch (s->current_direction) {
+    case 0:
+        break;
+    case 1:
+        s->current = s->otp;
+        break;
+    case 2:
+        s->current = s->image;
+        break;
+    default:
+        return -1;
+    }
+    onenand_intr_update(s);
+    return 0;
+}
+
+static const VMStateDescription vmstate_onenand = {
+    .name = "onenand",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .pre_save = onenand_pre_save,
+    .post_load = onenand_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT8(current_direction, OneNANDState),
+        VMSTATE_INT32(cycle, OneNANDState),
+        VMSTATE_INT32(otpmode, OneNANDState),
+        VMSTATE_UINT16_ARRAY(addr, OneNANDState, 8),
+        VMSTATE_UINT16_ARRAY(unladdr, OneNANDState, 8),
+        VMSTATE_INT32(bufaddr, OneNANDState),
+        VMSTATE_INT32(count, OneNANDState),
+        VMSTATE_UINT16(command, OneNANDState),
+        VMSTATE_UINT16_ARRAY(config, OneNANDState, 2),
+        VMSTATE_UINT16(status, OneNANDState),
+        VMSTATE_UINT16(intstatus, OneNANDState),
+        VMSTATE_UINT16(wpstatus, OneNANDState),
+        VMSTATE_INT32(secs_cur, OneNANDState),
+        VMSTATE_PARTIAL_VBUFFER(blockwp, OneNANDState, blocks),
+        VMSTATE_UINT8(ecc.cp, OneNANDState),
+        VMSTATE_UINT16_ARRAY(ecc.lp, OneNANDState, 2),
+        VMSTATE_UINT16(ecc.count, OneNANDState),
+        VMSTATE_BUFFER_POINTER_UNSAFE(otp, OneNANDState, 0,
+            ((64 + 2) << PAGE_SHIFT)),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+/* Hot reset (Reset OneNAND command) or warm reset (RP pin low) */
+static void onenand_reset(OneNANDState *s, int cold)
+{
+    memset(&s->addr, 0, sizeof(s->addr));
+    s->command = 0;
+    s->count = 1;
+    s->bufaddr = 0;
+    s->config[0] = 0x40c0;
+    s->config[1] = 0x0000;
+    onenand_intr_update(s);
+    qemu_irq_raise(s->rdy);
+    s->status = 0x0000;
+    s->intstatus = cold ? 0x8080 : 0x8010;
+    s->unladdr[0] = 0;
+    s->unladdr[1] = 0;
+    s->wpstatus = 0x0002;
+    s->cycle = 0;
+    s->otpmode = 0;
+    s->bdrv_cur = s->bdrv;
+    s->current = s->image;
+    s->secs_cur = s->secs;
+
+    if (cold) {
+        /* Lock the whole flash */
+        memset(s->blockwp, ONEN_LOCK_LOCKED, s->blocks);
+
+        if (s->bdrv_cur && bdrv_read(s->bdrv_cur, 0, s->boot[0], 8) < 0) {
+            hw_error("%s: Loading the BootRAM failed.\n", __func__);
+        }
+    }
+}
+
+static void onenand_system_reset(DeviceState *dev)
+{
+    onenand_reset(FROM_SYSBUS(OneNANDState, SYS_BUS_DEVICE(dev)), 1);
+}
+
+static inline int onenand_load_main(OneNANDState *s, int sec, int secn,
+                void *dest)
+{
+    if (s->bdrv_cur)
+        return bdrv_read(s->bdrv_cur, sec, dest, secn) < 0;
+    else if (sec + secn > s->secs_cur)
+        return 1;
+
+    memcpy(dest, s->current + (sec << 9), secn << 9);
+
+    return 0;
+}
+
+static inline int onenand_prog_main(OneNANDState *s, int sec, int secn,
+                void *src)
+{
+    int result = 0;
+
+    if (secn > 0) {
+        uint32_t size = (uint32_t)secn * 512;
+        const uint8_t *sp = (const uint8_t *)src;
+        uint8_t *dp = 0;
+        if (s->bdrv_cur) {
+            dp = g_malloc(size);
+            if (!dp || bdrv_read(s->bdrv_cur, sec, dp, secn) < 0) {
+                result = 1;
+            }
+        } else {
+            if (sec + secn > s->secs_cur) {
+                result = 1;
+            } else {
+                dp = (uint8_t *)s->current + (sec << 9);
+            }
+        }
+        if (!result) {
+            uint32_t i;
+            for (i = 0; i < size; i++) {
+                dp[i] &= sp[i];
+            }
+            if (s->bdrv_cur) {
+                result = bdrv_write(s->bdrv_cur, sec, dp, secn) < 0;
+            }
+        }
+        if (dp && s->bdrv_cur) {
+            g_free(dp);
+        }
+    }
+
+    return result;
+}
+
+static inline int onenand_load_spare(OneNANDState *s, int sec, int secn,
+                void *dest)
+{
+    uint8_t buf[512];
+
+    if (s->bdrv_cur) {
+        if (bdrv_read(s->bdrv_cur, s->secs_cur + (sec >> 5), buf, 1) < 0)
+            return 1;
+        memcpy(dest, buf + ((sec & 31) << 4), secn << 4);
+    } else if (sec + secn > s->secs_cur)
+        return 1;
+    else
+        memcpy(dest, s->current + (s->secs_cur << 9) + (sec << 4), secn << 4);
+    return 0;
+}
+
+static inline int onenand_prog_spare(OneNANDState *s, int sec, int secn,
+                void *src)
+{
+    int result = 0;
+    if (secn > 0) {
+        const uint8_t *sp = (const uint8_t *)src;
+        uint8_t *dp = 0, *dpp = 0;
+        if (s->bdrv_cur) {
+            dp = g_malloc(512);
+            if (!dp || bdrv_read(s->bdrv_cur,
+                                 s->secs_cur + (sec >> 5),
+                                 dp, 1) < 0) {
+                result = 1;
+            } else {
+                dpp = dp + ((sec & 31) << 4);
+            }
+        } else {
+            if (sec + secn > s->secs_cur) {
+                result = 1;
+            } else {
+                dpp = s->current + (s->secs_cur << 9) + (sec << 4);
+            }
+        }
+        if (!result) {
+            uint32_t i;
+            for (i = 0; i < (secn << 4); i++) {
+                dpp[i] &= sp[i];
+            }
+            if (s->bdrv_cur) {
+                result = bdrv_write(s->bdrv_cur, s->secs_cur + (sec >> 5),
+                                    dp, 1) < 0;
+            }
+        }
+        if (dp) {
+            g_free(dp);
+        }
+    }
+    return result;
+}
+
+static inline int onenand_erase(OneNANDState *s, int sec, int num)
+{
+    uint8_t *blankbuf, *tmpbuf;
+    blankbuf = g_malloc(512);
+    if (!blankbuf) {
+        return 1;
+    }
+    tmpbuf = g_malloc(512);
+    if (!tmpbuf) {
+        g_free(blankbuf);
+        return 1;
+    }
+    memset(blankbuf, 0xff, 512);
+    for (; num > 0; num--, sec++) {
+        if (s->bdrv_cur) {
+            int erasesec = s->secs_cur + (sec >> 5);
+            if (bdrv_write(s->bdrv_cur, sec, blankbuf, 1) < 0) {
+                goto fail;
+            }
+            if (bdrv_read(s->bdrv_cur, erasesec, tmpbuf, 1) < 0) {
+                goto fail;
+            }
+            memcpy(tmpbuf + ((sec & 31) << 4), blankbuf, 1 << 4);
+            if (bdrv_write(s->bdrv_cur, erasesec, tmpbuf, 1) < 0) {
+                goto fail;
+            }
+        } else {
+            if (sec + 1 > s->secs_cur) {
+                goto fail;
+            }
+            memcpy(s->current + (sec << 9), blankbuf, 512);
+            memcpy(s->current + (s->secs_cur << 9) + (sec << 4),
+                   blankbuf, 1 << 4);
+        }
+    }
+
+    g_free(tmpbuf);
+    g_free(blankbuf);
+    return 0;
+
+fail:
+    g_free(tmpbuf);
+    g_free(blankbuf);
+    return 1;
+}
+
+static void onenand_command(OneNANDState *s)
+{
+    int b;
+    int sec;
+    void *buf;
+#define SETADDR(block, page)                   \
+    sec = (s->addr[page] & 3) +                        \
+            ((((s->addr[page] >> 2) & 0x3f) +  \
+              (((s->addr[block] & 0xfff) |     \
+                (s->addr[block] >> 15 ?                \
+                 s->density_mask : 0)) << 6)) << (PAGE_SHIFT - 9));
+#define SETBUF_M()                             \
+    buf = (s->bufaddr & 8) ?                   \
+            s->data[(s->bufaddr >> 2) & 1][0] : s->boot[0];    \
+    buf += (s->bufaddr & 3) << 9;
+#define SETBUF_S()                             \
+    buf = (s->bufaddr & 8) ?                   \
+            s->data[(s->bufaddr >> 2) & 1][1] : s->boot[1];    \
+    buf += (s->bufaddr & 3) << 4;
+
+    switch (s->command) {
+    case 0x00: /* Load single/multiple sector data unit into buffer */
+        SETADDR(ONEN_BUF_BLOCK, ONEN_BUF_PAGE)
+
+        SETBUF_M()
+        if (onenand_load_main(s, sec, s->count, buf))
+            s->status |= ONEN_ERR_CMD | ONEN_ERR_LOAD;
+
+#if 0
+        SETBUF_S()
+        if (onenand_load_spare(s, sec, s->count, buf))
+            s->status |= ONEN_ERR_CMD | ONEN_ERR_LOAD;
+#endif
+
+        /* TODO: if (s->bufaddr & 3) + s->count was > 4 (2k-pages)
+         * or    if (s->bufaddr & 1) + s->count was > 2 (1k-pages)
+         * then we need two split the read/write into two chunks.
+         */
+        s->intstatus |= ONEN_INT | ONEN_INT_LOAD;
+        break;
+    case 0x13: /* Load single/multiple spare sector into buffer */
+        SETADDR(ONEN_BUF_BLOCK, ONEN_BUF_PAGE)
+
+        SETBUF_S()
+        if (onenand_load_spare(s, sec, s->count, buf))
+            s->status |= ONEN_ERR_CMD | ONEN_ERR_LOAD;
+
+        /* TODO: if (s->bufaddr & 3) + s->count was > 4 (2k-pages)
+         * or    if (s->bufaddr & 1) + s->count was > 2 (1k-pages)
+         * then we need two split the read/write into two chunks.
+         */
+        s->intstatus |= ONEN_INT | ONEN_INT_LOAD;
+        break;
+    case 0x80: /* Program single/multiple sector data unit from buffer */
+        SETADDR(ONEN_BUF_BLOCK, ONEN_BUF_PAGE)
+
+        SETBUF_M()
+        if (onenand_prog_main(s, sec, s->count, buf))
+            s->status |= ONEN_ERR_CMD | ONEN_ERR_PROG;
+
+#if 0
+        SETBUF_S()
+        if (onenand_prog_spare(s, sec, s->count, buf))
+            s->status |= ONEN_ERR_CMD | ONEN_ERR_PROG;
+#endif
+
+        /* TODO: if (s->bufaddr & 3) + s->count was > 4 (2k-pages)
+         * or    if (s->bufaddr & 1) + s->count was > 2 (1k-pages)
+         * then we need two split the read/write into two chunks.
+         */
+        s->intstatus |= ONEN_INT | ONEN_INT_PROG;
+        break;
+    case 0x1a: /* Program single/multiple spare area sector from buffer */
+        SETADDR(ONEN_BUF_BLOCK, ONEN_BUF_PAGE)
+
+        SETBUF_S()
+        if (onenand_prog_spare(s, sec, s->count, buf))
+            s->status |= ONEN_ERR_CMD | ONEN_ERR_PROG;
+
+        /* TODO: if (s->bufaddr & 3) + s->count was > 4 (2k-pages)
+         * or    if (s->bufaddr & 1) + s->count was > 2 (1k-pages)
+         * then we need two split the read/write into two chunks.
+         */
+        s->intstatus |= ONEN_INT | ONEN_INT_PROG;
+        break;
+    case 0x1b: /* Copy-back program */
+        SETBUF_S()
+
+        SETADDR(ONEN_BUF_BLOCK, ONEN_BUF_PAGE)
+        if (onenand_load_main(s, sec, s->count, buf))
+            s->status |= ONEN_ERR_CMD | ONEN_ERR_PROG;
+
+        SETADDR(ONEN_BUF_DEST_BLOCK, ONEN_BUF_DEST_PAGE)
+        if (onenand_prog_main(s, sec, s->count, buf))
+            s->status |= ONEN_ERR_CMD | ONEN_ERR_PROG;
+
+        /* TODO: spare areas */
+
+        s->intstatus |= ONEN_INT | ONEN_INT_PROG;
+        break;
+
+    case 0x23: /* Unlock NAND array block(s) */
+        s->intstatus |= ONEN_INT;
+
+        /* XXX the previous (?) area should be locked automatically */
+        for (b = s->unladdr[0]; b <= s->unladdr[1]; b ++) {
+            if (b >= s->blocks) {
+                s->status |= ONEN_ERR_CMD;
+                break;
+            }
+            if (s->blockwp[b] == ONEN_LOCK_LOCKTIGHTEN)
+                break;
+
+            s->wpstatus = s->blockwp[b] = ONEN_LOCK_UNLOCKED;
+        }
+        break;
+    case 0x27: /* Unlock All NAND array blocks */
+        s->intstatus |= ONEN_INT;
+
+        for (b = 0; b < s->blocks; b ++) {
+            if (b >= s->blocks) {
+                s->status |= ONEN_ERR_CMD;
+                break;
+            }
+            if (s->blockwp[b] == ONEN_LOCK_LOCKTIGHTEN)
+                break;
+
+            s->wpstatus = s->blockwp[b] = ONEN_LOCK_UNLOCKED;
+        }
+        break;
+
+    case 0x2a: /* Lock NAND array block(s) */
+        s->intstatus |= ONEN_INT;
+
+        for (b = s->unladdr[0]; b <= s->unladdr[1]; b ++) {
+            if (b >= s->blocks) {
+                s->status |= ONEN_ERR_CMD;
+                break;
+            }
+            if (s->blockwp[b] == ONEN_LOCK_LOCKTIGHTEN)
+                break;
+
+            s->wpstatus = s->blockwp[b] = ONEN_LOCK_LOCKED;
+        }
+        break;
+    case 0x2c: /* Lock-tight NAND array block(s) */
+        s->intstatus |= ONEN_INT;
+
+        for (b = s->unladdr[0]; b <= s->unladdr[1]; b ++) {
+            if (b >= s->blocks) {
+                s->status |= ONEN_ERR_CMD;
+                break;
+            }
+            if (s->blockwp[b] == ONEN_LOCK_UNLOCKED)
+                continue;
+
+            s->wpstatus = s->blockwp[b] = ONEN_LOCK_LOCKTIGHTEN;
+        }
+        break;
+
+    case 0x71: /* Erase-Verify-Read */
+        s->intstatus |= ONEN_INT;
+        break;
+    case 0x95: /* Multi-block erase */
+        qemu_irq_pulse(s->intr);
+        /* Fall through.  */
+    case 0x94: /* Block erase */
+        sec = ((s->addr[ONEN_BUF_BLOCK] & 0xfff) |
+                        (s->addr[ONEN_BUF_BLOCK] >> 15 ? s->density_mask : 0))
+                << (BLOCK_SHIFT - 9);
+        if (onenand_erase(s, sec, 1 << (BLOCK_SHIFT - 9)))
+            s->status |= ONEN_ERR_CMD | ONEN_ERR_ERASE;
+
+        s->intstatus |= ONEN_INT | ONEN_INT_ERASE;
+        break;
+    case 0xb0: /* Erase suspend */
+        break;
+    case 0x30: /* Erase resume */
+        s->intstatus |= ONEN_INT | ONEN_INT_ERASE;
+        break;
+
+    case 0xf0: /* Reset NAND Flash core */
+        onenand_reset(s, 0);
+        break;
+    case 0xf3: /* Reset OneNAND */
+        onenand_reset(s, 0);
+        break;
+
+    case 0x65: /* OTP Access */
+        s->intstatus |= ONEN_INT;
+        s->bdrv_cur = NULL;
+        s->current = s->otp;
+        s->secs_cur = 1 << (BLOCK_SHIFT - 9);
+        s->addr[ONEN_BUF_BLOCK] = 0;
+        s->otpmode = 1;
+        break;
+
+    default:
+        s->status |= ONEN_ERR_CMD;
+        s->intstatus |= ONEN_INT;
+        fprintf(stderr, "%s: unknown OneNAND command %x\n",
+                        __func__, s->command);
+    }
+
+    onenand_intr_update(s);
+}
+
+static uint64_t onenand_read(void *opaque, hwaddr addr,
+                             unsigned size)
+{
+    OneNANDState *s = (OneNANDState *) opaque;
+    int offset = addr >> s->shift;
+
+    switch (offset) {
+    case 0x0000 ... 0xc000:
+        return lduw_le_p(s->boot[0] + addr);
+
+    case 0xf000:       /* Manufacturer ID */
+        return s->id.man;
+    case 0xf001:       /* Device ID */
+        return s->id.dev;
+    case 0xf002:       /* Version ID */
+        return s->id.ver;
+    /* TODO: get the following values from a real chip!  */
+    case 0xf003:       /* Data Buffer size */
+        return 1 << PAGE_SHIFT;
+    case 0xf004:       /* Boot Buffer size */
+        return 0x200;
+    case 0xf005:       /* Amount of buffers */
+        return 1 | (2 << 8);
+    case 0xf006:       /* Technology */
+        return 0;
+
+    case 0xf100 ... 0xf107:    /* Start addresses */
+        return s->addr[offset - 0xf100];
+
+    case 0xf200:       /* Start buffer */
+        return (s->bufaddr << 8) | ((s->count - 1) & (1 << (PAGE_SHIFT - 10)));
+
+    case 0xf220:       /* Command */
+        return s->command;
+    case 0xf221:       /* System Configuration 1 */
+        return s->config[0] & 0xffe0;
+    case 0xf222:       /* System Configuration 2 */
+        return s->config[1];
+
+    case 0xf240:       /* Controller Status */
+        return s->status;
+    case 0xf241:       /* Interrupt */
+        return s->intstatus;
+    case 0xf24c:       /* Unlock Start Block Address */
+        return s->unladdr[0];
+    case 0xf24d:       /* Unlock End Block Address */
+        return s->unladdr[1];
+    case 0xf24e:       /* Write Protection Status */
+        return s->wpstatus;
+
+    case 0xff00:       /* ECC Status */
+        return 0x00;
+    case 0xff01:       /* ECC Result of main area data */
+    case 0xff02:       /* ECC Result of spare area data */
+    case 0xff03:       /* ECC Result of main area data */
+    case 0xff04:       /* ECC Result of spare area data */
+        hw_error("%s: imeplement ECC\n", __FUNCTION__);
+        return 0x0000;
+    }
+
+    fprintf(stderr, "%s: unknown OneNAND register %x\n",
+                    __FUNCTION__, offset);
+    return 0;
+}
+
+static void onenand_write(void *opaque, hwaddr addr,
+                          uint64_t value, unsigned size)
+{
+    OneNANDState *s = (OneNANDState *) opaque;
+    int offset = addr >> s->shift;
+    int sec;
+
+    switch (offset) {
+    case 0x0000 ... 0x01ff:
+    case 0x8000 ... 0x800f:
+        if (s->cycle) {
+            s->cycle = 0;
+
+            if (value == 0x0000) {
+                SETADDR(ONEN_BUF_BLOCK, ONEN_BUF_PAGE)
+                onenand_load_main(s, sec,
+                                1 << (PAGE_SHIFT - 9), s->data[0][0]);
+                s->addr[ONEN_BUF_PAGE] += 4;
+                s->addr[ONEN_BUF_PAGE] &= 0xff;
+            }
+            break;
+        }
+
+        switch (value) {
+        case 0x00f0:   /* Reset OneNAND */
+            onenand_reset(s, 0);
+            break;
+
+        case 0x00e0:   /* Load Data into Buffer */
+            s->cycle = 1;
+            break;
+
+        case 0x0090:   /* Read Identification Data */
+            memset(s->boot[0], 0, 3 << s->shift);
+            s->boot[0][0 << s->shift] = s->id.man & 0xff;
+            s->boot[0][1 << s->shift] = s->id.dev & 0xff;
+            s->boot[0][2 << s->shift] = s->wpstatus & 0xff;
+            break;
+
+        default:
+            fprintf(stderr, "%s: unknown OneNAND boot command %"PRIx64"\n",
+                            __FUNCTION__, value);
+        }
+        break;
+
+    case 0xf100 ... 0xf107:    /* Start addresses */
+        s->addr[offset - 0xf100] = value;
+        break;
+
+    case 0xf200:       /* Start buffer */
+        s->bufaddr = (value >> 8) & 0xf;
+        if (PAGE_SHIFT == 11)
+            s->count = (value & 3) ?: 4;
+        else if (PAGE_SHIFT == 10)
+            s->count = (value & 1) ?: 2;
+        break;
+
+    case 0xf220:       /* Command */
+        if (s->intstatus & (1 << 15))
+            break;
+        s->command = value;
+        onenand_command(s);
+        break;
+    case 0xf221:       /* System Configuration 1 */
+        s->config[0] = value;
+        onenand_intr_update(s);
+        qemu_set_irq(s->rdy, (s->config[0] >> 7) & 1);
+        break;
+    case 0xf222:       /* System Configuration 2 */
+        s->config[1] = value;
+        break;
+
+    case 0xf241:       /* Interrupt */
+        s->intstatus &= value;
+        if ((1 << 15) & ~s->intstatus)
+            s->status &= ~(ONEN_ERR_CMD | ONEN_ERR_ERASE |
+                            ONEN_ERR_PROG | ONEN_ERR_LOAD);
+        onenand_intr_update(s);
+        break;
+    case 0xf24c:       /* Unlock Start Block Address */
+        s->unladdr[0] = value & (s->blocks - 1);
+        /* For some reason we have to set the end address to by default
+         * be same as start because the software forgets to write anything
+         * in there.  */
+        s->unladdr[1] = value & (s->blocks - 1);
+        break;
+    case 0xf24d:       /* Unlock End Block Address */
+        s->unladdr[1] = value & (s->blocks - 1);
+        break;
+
+    default:
+        fprintf(stderr, "%s: unknown OneNAND register %x\n",
+                        __FUNCTION__, offset);
+    }
+}
+
+static const MemoryRegionOps onenand_ops = {
+    .read = onenand_read,
+    .write = onenand_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int onenand_initfn(SysBusDevice *dev)
+{
+    OneNANDState *s = (OneNANDState *)dev;
+    uint32_t size = 1 << (24 + ((s->id.dev >> 4) & 7));
+    void *ram;
+    s->base = (hwaddr)-1;
+    s->rdy = NULL;
+    s->blocks = size >> BLOCK_SHIFT;
+    s->secs = size >> 9;
+    s->blockwp = g_malloc(s->blocks);
+    s->density_mask = (s->id.dev & 0x08)
+        ? (1 << (6 + ((s->id.dev >> 4) & 7))) : 0;
+    memory_region_init_io(&s->iomem, &onenand_ops, s, "onenand",
+                          0x10000 << s->shift);
+    if (!s->bdrv) {
+        s->image = memset(g_malloc(size + (size >> 5)),
+                          0xff, size + (size >> 5));
+    } else {
+        if (bdrv_is_read_only(s->bdrv)) {
+            error_report("Can't use a read-only drive");
+            return -1;
+        }
+        s->bdrv_cur = s->bdrv;
+    }
+    s->otp = memset(g_malloc((64 + 2) << PAGE_SHIFT),
+                    0xff, (64 + 2) << PAGE_SHIFT);
+    memory_region_init_ram(&s->ram, "onenand.ram", 0xc000 << s->shift);
+    vmstate_register_ram_global(&s->ram);
+    ram = memory_region_get_ram_ptr(&s->ram);
+    s->boot[0] = ram + (0x0000 << s->shift);
+    s->boot[1] = ram + (0x8000 << s->shift);
+    s->data[0][0] = ram + ((0x0200 + (0 << (PAGE_SHIFT - 1))) << s->shift);
+    s->data[0][1] = ram + ((0x8010 + (0 << (PAGE_SHIFT - 6))) << s->shift);
+    s->data[1][0] = ram + ((0x0200 + (1 << (PAGE_SHIFT - 1))) << s->shift);
+    s->data[1][1] = ram + ((0x8010 + (1 << (PAGE_SHIFT - 6))) << s->shift);
+    onenand_mem_setup(s);
+    sysbus_init_irq(dev, &s->intr);
+    sysbus_init_mmio(dev, &s->container);
+    vmstate_register(&dev->qdev,
+                     ((s->shift & 0x7f) << 24)
+                     | ((s->id.man & 0xff) << 16)
+                     | ((s->id.dev & 0xff) << 8)
+                     | (s->id.ver & 0xff),
+                     &vmstate_onenand, s);
+    return 0;
+}
+
+static Property onenand_properties[] = {
+    DEFINE_PROP_UINT16("manufacturer_id", OneNANDState, id.man, 0),
+    DEFINE_PROP_UINT16("device_id", OneNANDState, id.dev, 0),
+    DEFINE_PROP_UINT16("version_id", OneNANDState, id.ver, 0),
+    DEFINE_PROP_INT32("shift", OneNANDState, shift, 0),
+    DEFINE_PROP_DRIVE("drive", OneNANDState, bdrv),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void onenand_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = onenand_initfn;
+    dc->reset = onenand_system_reset;
+    dc->props = onenand_properties;
+}
+
+static const TypeInfo onenand_info = {
+    .name          = "onenand",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(OneNANDState),
+    .class_init    = onenand_class_init,
+};
+
+static void onenand_register_types(void)
+{
+    type_register_static(&onenand_info);
+}
+
+void *onenand_raw_otp(DeviceState *onenand_device)
+{
+    return FROM_SYSBUS(OneNANDState, SYS_BUS_DEVICE(onenand_device))->otp;
+}
+
+type_init(onenand_register_types)
diff --git a/hw/block/pc_sysfw.c b/hw/block/pc_sysfw.c
new file mode 100644 (file)
index 0000000..0d95c8a
--- /dev/null
@@ -0,0 +1,273 @@
+/*
+ * QEMU PC System Firmware
+ *
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ * Copyright (c) 2011-2012 Intel Corporation
+ *
+ * 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 "sysemu/blockdev.h"
+#include "qemu/error-report.h"
+#include "hw/sysbus.h"
+#include "hw/hw.h"
+#include "hw/i386/pc.h"
+#include "hw/boards.h"
+#include "hw/loader.h"
+#include "sysemu/sysemu.h"
+#include "hw/block/flash.h"
+#include "sysemu/kvm.h"
+
+#define BIOS_FILENAME "bios.bin"
+
+typedef struct PcSysFwDevice {
+    SysBusDevice busdev;
+    uint8_t rom_only;
+} PcSysFwDevice;
+
+static void pc_isa_bios_init(MemoryRegion *rom_memory,
+                             MemoryRegion *flash_mem,
+                             int ram_size)
+{
+    int isa_bios_size;
+    MemoryRegion *isa_bios;
+    uint64_t flash_size;
+    void *flash_ptr, *isa_bios_ptr;
+
+    flash_size = memory_region_size(flash_mem);
+
+    /* map the last 128KB of the BIOS in ISA space */
+    isa_bios_size = flash_size;
+    if (isa_bios_size > (128 * 1024)) {
+        isa_bios_size = 128 * 1024;
+    }
+    isa_bios = g_malloc(sizeof(*isa_bios));
+    memory_region_init_ram(isa_bios, "isa-bios", isa_bios_size);
+    vmstate_register_ram_global(isa_bios);
+    memory_region_add_subregion_overlap(rom_memory,
+                                        0x100000 - isa_bios_size,
+                                        isa_bios,
+                                        1);
+
+    /* copy ISA rom image from top of flash memory */
+    flash_ptr = memory_region_get_ram_ptr(flash_mem);
+    isa_bios_ptr = memory_region_get_ram_ptr(isa_bios);
+    memcpy(isa_bios_ptr,
+           ((uint8_t*)flash_ptr) + (flash_size - isa_bios_size),
+           isa_bios_size);
+
+    memory_region_set_readonly(isa_bios, true);
+}
+
+static void pc_fw_add_pflash_drv(void)
+{
+    QemuOpts *opts;
+    QEMUMachine *machine;
+    char *filename;
+
+    if (bios_name == NULL) {
+        bios_name = BIOS_FILENAME;
+    }
+    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
+    if (!filename) {
+        error_report("Can't open BIOS image %s", bios_name);
+        exit(1);
+    }
+
+    opts = drive_add(IF_PFLASH, -1, filename, "readonly=on");
+
+    g_free(filename);
+
+    if (opts == NULL) {
+      return;
+    }
+
+    machine = find_default_machine();
+    if (machine == NULL) {
+      return;
+    }
+
+    if (!drive_init(opts, machine->block_default_type)) {
+        qemu_opts_del(opts);
+    }
+}
+
+static void pc_system_flash_init(MemoryRegion *rom_memory,
+                                 DriveInfo *pflash_drv)
+{
+    BlockDriverState *bdrv;
+    int64_t size;
+    hwaddr phys_addr;
+    int sector_bits, sector_size;
+    pflash_t *system_flash;
+    MemoryRegion *flash_mem;
+
+    bdrv = pflash_drv->bdrv;
+    size = bdrv_getlength(pflash_drv->bdrv);
+    sector_bits = 12;
+    sector_size = 1 << sector_bits;
+
+    if ((size % sector_size) != 0) {
+        fprintf(stderr,
+                "qemu: PC system firmware (pflash) must be a multiple of 0x%x\n",
+                sector_size);
+        exit(1);
+    }
+
+    phys_addr = 0x100000000ULL - size;
+    system_flash = pflash_cfi01_register(phys_addr, NULL, "system.flash", size,
+                                         bdrv, sector_size, size >> sector_bits,
+                                         1, 0x0000, 0x0000, 0x0000, 0x0000, 0);
+    flash_mem = pflash_cfi01_get_memory(system_flash);
+
+    pc_isa_bios_init(rom_memory, flash_mem, size);
+}
+
+static void old_pc_system_rom_init(MemoryRegion *rom_memory)
+{
+    char *filename;
+    MemoryRegion *bios, *isa_bios;
+    int bios_size, isa_bios_size;
+    int ret;
+
+    /* BIOS load */
+    if (bios_name == NULL) {
+        bios_name = BIOS_FILENAME;
+    }
+    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
+    if (filename) {
+        bios_size = get_image_size(filename);
+    } else {
+        bios_size = -1;
+    }
+    if (bios_size <= 0 ||
+        (bios_size % 65536) != 0) {
+        goto bios_error;
+    }
+    bios = g_malloc(sizeof(*bios));
+    memory_region_init_ram(bios, "pc.bios", bios_size);
+    vmstate_register_ram_global(bios);
+    memory_region_set_readonly(bios, true);
+    ret = rom_add_file_fixed(bios_name, (uint32_t)(-bios_size), -1);
+    if (ret != 0) {
+    bios_error:
+        fprintf(stderr, "qemu: could not load PC BIOS '%s'\n", bios_name);
+        exit(1);
+    }
+    if (filename) {
+        g_free(filename);
+    }
+
+    /* map the last 128KB of the BIOS in ISA space */
+    isa_bios_size = bios_size;
+    if (isa_bios_size > (128 * 1024)) {
+        isa_bios_size = 128 * 1024;
+    }
+    isa_bios = g_malloc(sizeof(*isa_bios));
+    memory_region_init_alias(isa_bios, "isa-bios", bios,
+                             bios_size - isa_bios_size, isa_bios_size);
+    memory_region_add_subregion_overlap(rom_memory,
+                                        0x100000 - isa_bios_size,
+                                        isa_bios,
+                                        1);
+    memory_region_set_readonly(isa_bios, true);
+
+    /* map all the bios at the top of memory */
+    memory_region_add_subregion(rom_memory,
+                                (uint32_t)(-bios_size),
+                                bios);
+}
+
+void pc_system_firmware_init(MemoryRegion *rom_memory)
+{
+    DriveInfo *pflash_drv;
+    PcSysFwDevice *sysfw_dev;
+
+    sysfw_dev = (PcSysFwDevice*) qdev_create(NULL, "pc-sysfw");
+
+    qdev_init_nofail(DEVICE(sysfw_dev));
+
+    if (sysfw_dev->rom_only) {
+        old_pc_system_rom_init(rom_memory);
+        return;
+    }
+
+    pflash_drv = drive_get(IF_PFLASH, 0, 0);
+
+    /* Currently KVM cannot execute from device memory.
+       Use old rom based firmware initialization for KVM. */
+    if (kvm_enabled()) {
+        if (pflash_drv != NULL) {
+            fprintf(stderr, "qemu: pflash cannot be used with kvm enabled\n");
+            exit(1);
+        } else {
+            sysfw_dev->rom_only = 1;
+            old_pc_system_rom_init(rom_memory);
+            return;
+        }
+    }
+
+    /* If a pflash drive is not found, then create one using
+       the bios filename. */
+    if (pflash_drv == NULL) {
+        pc_fw_add_pflash_drv();
+        pflash_drv = drive_get(IF_PFLASH, 0, 0);
+    }
+
+    if (pflash_drv != NULL) {
+        pc_system_flash_init(rom_memory, pflash_drv);
+    } else {
+        fprintf(stderr, "qemu: PC system firmware (pflash) not available\n");
+        exit(1);
+    }
+}
+
+static Property pcsysfw_properties[] = {
+    DEFINE_PROP_UINT8("rom_only", PcSysFwDevice, rom_only, 0),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static int pcsysfw_init(DeviceState *dev)
+{
+    return 0;
+}
+
+static void pcsysfw_class_init (ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS (klass);
+
+    dc->desc = "PC System Firmware";
+    dc->init = pcsysfw_init;
+    dc->props = pcsysfw_properties;
+}
+
+static const TypeInfo pcsysfw_info = {
+    .name          = "pc-sysfw",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof (PcSysFwDevice),
+    .class_init    = pcsysfw_class_init,
+};
+
+static void pcsysfw_register (void)
+{
+    type_register_static (&pcsysfw_info);
+}
+
+type_init (pcsysfw_register);
+
diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c
new file mode 100644 (file)
index 0000000..3ff20e0
--- /dev/null
@@ -0,0 +1,769 @@
+/*
+ *  CFI parallel flash with Intel command set emulation
+ *
+ *  Copyright (c) 2006 Thorsten Zitterell
+ *  Copyright (c) 2005 Jocelyn Mayer
+ *
+ * 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/>.
+ */
+
+/*
+ * For now, this code can emulate flashes of 1, 2 or 4 bytes width.
+ * Supported commands/modes are:
+ * - flash read
+ * - flash write
+ * - flash ID read
+ * - sector erase
+ * - CFI queries
+ *
+ * It does not support timings
+ * It does not support flash interleaving
+ * It does not implement software data protection as found in many real chips
+ * It does not implement erase suspend/resume commands
+ * It does not implement multiple sectors erase
+ *
+ * It does not implement much more ...
+ */
+
+#include "hw/hw.h"
+#include "hw/block/flash.h"
+#include "block/block.h"
+#include "qemu/timer.h"
+#include "exec/address-spaces.h"
+#include "qemu/host-utils.h"
+#include "hw/sysbus.h"
+
+#define PFLASH_BUG(fmt, ...) \
+do { \
+    fprintf(stderr, "PFLASH: Possible BUG - " fmt, ## __VA_ARGS__); \
+    exit(1); \
+} while(0)
+
+/* #define PFLASH_DEBUG */
+#ifdef PFLASH_DEBUG
+#define DPRINTF(fmt, ...)                                   \
+do {                                                        \
+    fprintf(stderr, "PFLASH: " fmt , ## __VA_ARGS__);       \
+} while (0)
+#else
+#define DPRINTF(fmt, ...) do { } while (0)
+#endif
+
+struct pflash_t {
+    SysBusDevice busdev;
+    BlockDriverState *bs;
+    uint32_t nb_blocs;
+    uint64_t sector_len;
+    uint8_t width;
+    uint8_t be;
+    uint8_t wcycle; /* if 0, the flash is read normally */
+    int ro;
+    uint8_t cmd;
+    uint8_t status;
+    uint16_t ident0;
+    uint16_t ident1;
+    uint16_t ident2;
+    uint16_t ident3;
+    uint8_t cfi_len;
+    uint8_t cfi_table[0x52];
+    uint64_t counter;
+    unsigned int writeblock_size;
+    QEMUTimer *timer;
+    MemoryRegion mem;
+    char *name;
+    void *storage;
+};
+
+static const VMStateDescription vmstate_pflash = {
+    .name = "pflash_cfi01",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT8(wcycle, pflash_t),
+        VMSTATE_UINT8(cmd, pflash_t),
+        VMSTATE_UINT8(status, pflash_t),
+        VMSTATE_UINT64(counter, pflash_t),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void pflash_timer (void *opaque)
+{
+    pflash_t *pfl = opaque;
+
+    DPRINTF("%s: command %02x done\n", __func__, pfl->cmd);
+    /* Reset flash */
+    pfl->status ^= 0x80;
+    memory_region_rom_device_set_readable(&pfl->mem, true);
+    pfl->wcycle = 0;
+    pfl->cmd = 0;
+}
+
+static uint32_t pflash_read (pflash_t *pfl, hwaddr offset,
+                             int width, int be)
+{
+    hwaddr boff;
+    uint32_t ret;
+    uint8_t *p;
+
+    ret = -1;
+    boff = offset & 0xFF; /* why this here ?? */
+
+    if (pfl->width == 2)
+        boff = boff >> 1;
+    else if (pfl->width == 4)
+        boff = boff >> 2;
+
+#if 0
+    DPRINTF("%s: reading offset " TARGET_FMT_plx " under cmd %02x width %d\n",
+            __func__, offset, pfl->cmd, width);
+#endif
+    switch (pfl->cmd) {
+    default:
+        /* This should never happen : reset state & treat it as a read */
+        DPRINTF("%s: unknown command state: %x\n", __func__, pfl->cmd);
+        pfl->wcycle = 0;
+        pfl->cmd = 0;
+        /* fall through to read code */
+    case 0x00:
+        /* Flash area read */
+        p = pfl->storage;
+        switch (width) {
+        case 1:
+            ret = p[offset];
+            DPRINTF("%s: data offset " TARGET_FMT_plx " %02x\n",
+                    __func__, offset, ret);
+            break;
+        case 2:
+            if (be) {
+                ret = p[offset] << 8;
+                ret |= p[offset + 1];
+            } else {
+                ret = p[offset];
+                ret |= p[offset + 1] << 8;
+            }
+            DPRINTF("%s: data offset " TARGET_FMT_plx " %04x\n",
+                    __func__, offset, ret);
+            break;
+        case 4:
+            if (be) {
+                ret = p[offset] << 24;
+                ret |= p[offset + 1] << 16;
+                ret |= p[offset + 2] << 8;
+                ret |= p[offset + 3];
+            } else {
+                ret = p[offset];
+                ret |= p[offset + 1] << 8;
+                ret |= p[offset + 2] << 16;
+                ret |= p[offset + 3] << 24;
+            }
+            DPRINTF("%s: data offset " TARGET_FMT_plx " %08x\n",
+                    __func__, offset, ret);
+            break;
+        default:
+            DPRINTF("BUG in %s\n", __func__);
+        }
+
+        break;
+    case 0x10: /* Single byte program */
+    case 0x20: /* Block erase */
+    case 0x28: /* Block erase */
+    case 0x40: /* single byte program */
+    case 0x50: /* Clear status register */
+    case 0x60: /* Block /un)lock */
+    case 0x70: /* Status Register */
+    case 0xe8: /* Write block */
+        /* Status register read */
+        ret = pfl->status;
+        DPRINTF("%s: status %x\n", __func__, ret);
+        break;
+    case 0x90:
+        switch (boff) {
+        case 0:
+            ret = pfl->ident0 << 8 | pfl->ident1;
+            DPRINTF("%s: Manufacturer Code %04x\n", __func__, ret);
+            break;
+        case 1:
+            ret = pfl->ident2 << 8 | pfl->ident3;
+            DPRINTF("%s: Device ID Code %04x\n", __func__, ret);
+            break;
+        default:
+            DPRINTF("%s: Read Device Information boff=%x\n", __func__,
+                    (unsigned)boff);
+            ret = 0;
+            break;
+        }
+        break;
+    case 0x98: /* Query mode */
+        if (boff > pfl->cfi_len)
+            ret = 0;
+        else
+            ret = pfl->cfi_table[boff];
+        break;
+    }
+    return ret;
+}
+
+/* update flash content on disk */
+static void pflash_update(pflash_t *pfl, int offset,
+                          int size)
+{
+    int offset_end;
+    if (pfl->bs) {
+        offset_end = offset + size;
+        /* round to sectors */
+        offset = offset >> 9;
+        offset_end = (offset_end + 511) >> 9;
+        bdrv_write(pfl->bs, offset, pfl->storage + (offset << 9),
+                   offset_end - offset);
+    }
+}
+
+static inline void pflash_data_write(pflash_t *pfl, hwaddr offset,
+                                     uint32_t value, int width, int be)
+{
+    uint8_t *p = pfl->storage;
+
+    DPRINTF("%s: block write offset " TARGET_FMT_plx
+            " value %x counter %016" PRIx64 "\n",
+            __func__, offset, value, pfl->counter);
+    switch (width) {
+    case 1:
+        p[offset] = value;
+        break;
+    case 2:
+        if (be) {
+            p[offset] = value >> 8;
+            p[offset + 1] = value;
+        } else {
+            p[offset] = value;
+            p[offset + 1] = value >> 8;
+        }
+        break;
+    case 4:
+        if (be) {
+            p[offset] = value >> 24;
+            p[offset + 1] = value >> 16;
+            p[offset + 2] = value >> 8;
+            p[offset + 3] = value;
+        } else {
+            p[offset] = value;
+            p[offset + 1] = value >> 8;
+            p[offset + 2] = value >> 16;
+            p[offset + 3] = value >> 24;
+        }
+        break;
+    }
+
+}
+
+static void pflash_write(pflash_t *pfl, hwaddr offset,
+                         uint32_t value, int width, int be)
+{
+    uint8_t *p;
+    uint8_t cmd;
+
+    cmd = value;
+
+    DPRINTF("%s: writing offset " TARGET_FMT_plx " value %08x width %d wcycle 0x%x\n",
+            __func__, offset, value, width, pfl->wcycle);
+
+    if (!pfl->wcycle) {
+        /* Set the device in I/O access mode */
+        memory_region_rom_device_set_readable(&pfl->mem, false);
+    }
+
+    switch (pfl->wcycle) {
+    case 0:
+        /* read mode */
+        switch (cmd) {
+        case 0x00: /* ??? */
+            goto reset_flash;
+        case 0x10: /* Single Byte Program */
+        case 0x40: /* Single Byte Program */
+            DPRINTF("%s: Single Byte Program\n", __func__);
+            break;
+        case 0x20: /* Block erase */
+            p = pfl->storage;
+            offset &= ~(pfl->sector_len - 1);
+
+            DPRINTF("%s: block erase at " TARGET_FMT_plx " bytes %x\n",
+                    __func__, offset, (unsigned)pfl->sector_len);
+
+            if (!pfl->ro) {
+                memset(p + offset, 0xff, pfl->sector_len);
+                pflash_update(pfl, offset, pfl->sector_len);
+            } else {
+                pfl->status |= 0x20; /* Block erase error */
+            }
+            pfl->status |= 0x80; /* Ready! */
+            break;
+        case 0x50: /* Clear status bits */
+            DPRINTF("%s: Clear status bits\n", __func__);
+            pfl->status = 0x0;
+            goto reset_flash;
+        case 0x60: /* Block (un)lock */
+            DPRINTF("%s: Block unlock\n", __func__);
+            break;
+        case 0x70: /* Status Register */
+            DPRINTF("%s: Read status register\n", __func__);
+            pfl->cmd = cmd;
+            return;
+        case 0x90: /* Read Device ID */
+            DPRINTF("%s: Read Device information\n", __func__);
+            pfl->cmd = cmd;
+            return;
+        case 0x98: /* CFI query */
+            DPRINTF("%s: CFI query\n", __func__);
+            break;
+        case 0xe8: /* Write to buffer */
+            DPRINTF("%s: Write to buffer\n", __func__);
+            pfl->status |= 0x80; /* Ready! */
+            break;
+        case 0xf0: /* Probe for AMD flash */
+            DPRINTF("%s: Probe for AMD flash\n", __func__);
+            goto reset_flash;
+        case 0xff: /* Read array mode */
+            DPRINTF("%s: Read array mode\n", __func__);
+            goto reset_flash;
+        default:
+            goto error_flash;
+        }
+        pfl->wcycle++;
+        pfl->cmd = cmd;
+        break;
+    case 1:
+        switch (pfl->cmd) {
+        case 0x10: /* Single Byte Program */
+        case 0x40: /* Single Byte Program */
+            DPRINTF("%s: Single Byte Program\n", __func__);
+            if (!pfl->ro) {
+                pflash_data_write(pfl, offset, value, width, be);
+                pflash_update(pfl, offset, width);
+            } else {
+                pfl->status |= 0x10; /* Programming error */
+            }
+            pfl->status |= 0x80; /* Ready! */
+            pfl->wcycle = 0;
+        break;
+        case 0x20: /* Block erase */
+        case 0x28:
+            if (cmd == 0xd0) { /* confirm */
+                pfl->wcycle = 0;
+                pfl->status |= 0x80;
+            } else if (cmd == 0xff) { /* read array mode */
+                goto reset_flash;
+            } else
+                goto error_flash;
+
+            break;
+        case 0xe8:
+            DPRINTF("%s: block write of %x bytes\n", __func__, value);
+            pfl->counter = value;
+            pfl->wcycle++;
+            break;
+        case 0x60:
+            if (cmd == 0xd0) {
+                pfl->wcycle = 0;
+                pfl->status |= 0x80;
+            } else if (cmd == 0x01) {
+                pfl->wcycle = 0;
+                pfl->status |= 0x80;
+            } else if (cmd == 0xff) {
+                goto reset_flash;
+            } else {
+                DPRINTF("%s: Unknown (un)locking command\n", __func__);
+                goto reset_flash;
+            }
+            break;
+        case 0x98:
+            if (cmd == 0xff) {
+                goto reset_flash;
+            } else {
+                DPRINTF("%s: leaving query mode\n", __func__);
+            }
+            break;
+        default:
+            goto error_flash;
+        }
+        break;
+    case 2:
+        switch (pfl->cmd) {
+        case 0xe8: /* Block write */
+            if (!pfl->ro) {
+                pflash_data_write(pfl, offset, value, width, be);
+            } else {
+                pfl->status |= 0x10; /* Programming error */
+            }
+
+            pfl->status |= 0x80;
+
+            if (!pfl->counter) {
+                hwaddr mask = pfl->writeblock_size - 1;
+                mask = ~mask;
+
+                DPRINTF("%s: block write finished\n", __func__);
+                pfl->wcycle++;
+                if (!pfl->ro) {
+                    /* Flush the entire write buffer onto backing storage.  */
+                    pflash_update(pfl, offset & mask, pfl->writeblock_size);
+                } else {
+                    pfl->status |= 0x10; /* Programming error */
+                }
+            }
+
+            pfl->counter--;
+            break;
+        default:
+            goto error_flash;
+        }
+        break;
+    case 3: /* Confirm mode */
+        switch (pfl->cmd) {
+        case 0xe8: /* Block write */
+            if (cmd == 0xd0) {
+                pfl->wcycle = 0;
+                pfl->status |= 0x80;
+            } else {
+                DPRINTF("%s: unknown command for \"write block\"\n", __func__);
+                PFLASH_BUG("Write block confirm");
+                goto reset_flash;
+            }
+            break;
+        default:
+            goto error_flash;
+        }
+        break;
+    default:
+        /* Should never happen */
+        DPRINTF("%s: invalid write state\n",  __func__);
+        goto reset_flash;
+    }
+    return;
+
+ error_flash:
+    qemu_log_mask(LOG_UNIMP, "%s: Unimplemented flash cmd sequence "
+                  "(offset " TARGET_FMT_plx ", wcycle 0x%x cmd 0x%x value 0x%x)"
+                  "\n", __func__, offset, pfl->wcycle, pfl->cmd, value);
+
+ reset_flash:
+    memory_region_rom_device_set_readable(&pfl->mem, true);
+
+    pfl->wcycle = 0;
+    pfl->cmd = 0;
+}
+
+
+static uint32_t pflash_readb_be(void *opaque, hwaddr addr)
+{
+    return pflash_read(opaque, addr, 1, 1);
+}
+
+static uint32_t pflash_readb_le(void *opaque, hwaddr addr)
+{
+    return pflash_read(opaque, addr, 1, 0);
+}
+
+static uint32_t pflash_readw_be(void *opaque, hwaddr addr)
+{
+    pflash_t *pfl = opaque;
+
+    return pflash_read(pfl, addr, 2, 1);
+}
+
+static uint32_t pflash_readw_le(void *opaque, hwaddr addr)
+{
+    pflash_t *pfl = opaque;
+
+    return pflash_read(pfl, addr, 2, 0);
+}
+
+static uint32_t pflash_readl_be(void *opaque, hwaddr addr)
+{
+    pflash_t *pfl = opaque;
+
+    return pflash_read(pfl, addr, 4, 1);
+}
+
+static uint32_t pflash_readl_le(void *opaque, hwaddr addr)
+{
+    pflash_t *pfl = opaque;
+
+    return pflash_read(pfl, addr, 4, 0);
+}
+
+static void pflash_writeb_be(void *opaque, hwaddr addr,
+                             uint32_t value)
+{
+    pflash_write(opaque, addr, value, 1, 1);
+}
+
+static void pflash_writeb_le(void *opaque, hwaddr addr,
+                             uint32_t value)
+{
+    pflash_write(opaque, addr, value, 1, 0);
+}
+
+static void pflash_writew_be(void *opaque, hwaddr addr,
+                             uint32_t value)
+{
+    pflash_t *pfl = opaque;
+
+    pflash_write(pfl, addr, value, 2, 1);
+}
+
+static void pflash_writew_le(void *opaque, hwaddr addr,
+                             uint32_t value)
+{
+    pflash_t *pfl = opaque;
+
+    pflash_write(pfl, addr, value, 2, 0);
+}
+
+static void pflash_writel_be(void *opaque, hwaddr addr,
+                             uint32_t value)
+{
+    pflash_t *pfl = opaque;
+
+    pflash_write(pfl, addr, value, 4, 1);
+}
+
+static void pflash_writel_le(void *opaque, hwaddr addr,
+                             uint32_t value)
+{
+    pflash_t *pfl = opaque;
+
+    pflash_write(pfl, addr, value, 4, 0);
+}
+
+static const MemoryRegionOps pflash_cfi01_ops_be = {
+    .old_mmio = {
+        .read = { pflash_readb_be, pflash_readw_be, pflash_readl_be, },
+        .write = { pflash_writeb_be, pflash_writew_be, pflash_writel_be, },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static const MemoryRegionOps pflash_cfi01_ops_le = {
+    .old_mmio = {
+        .read = { pflash_readb_le, pflash_readw_le, pflash_readl_le, },
+        .write = { pflash_writeb_le, pflash_writew_le, pflash_writel_le, },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int pflash_cfi01_init(SysBusDevice *dev)
+{
+    pflash_t *pfl = FROM_SYSBUS(typeof(*pfl), dev);
+    uint64_t total_len;
+    int ret;
+
+    total_len = pfl->sector_len * pfl->nb_blocs;
+
+    /* XXX: to be fixed */
+#if 0
+    if (total_len != (8 * 1024 * 1024) && total_len != (16 * 1024 * 1024) &&
+        total_len != (32 * 1024 * 1024) && total_len != (64 * 1024 * 1024))
+        return NULL;
+#endif
+
+    memory_region_init_rom_device(
+        &pfl->mem, pfl->be ? &pflash_cfi01_ops_be : &pflash_cfi01_ops_le, pfl,
+        pfl->name, total_len);
+    vmstate_register_ram(&pfl->mem, DEVICE(pfl));
+    pfl->storage = memory_region_get_ram_ptr(&pfl->mem);
+    sysbus_init_mmio(dev, &pfl->mem);
+
+    if (pfl->bs) {
+        /* read the initial flash content */
+        ret = bdrv_read(pfl->bs, 0, pfl->storage, total_len >> 9);
+
+        if (ret < 0) {
+            vmstate_unregister_ram(&pfl->mem, DEVICE(pfl));
+            memory_region_destroy(&pfl->mem);
+            return 1;
+        }
+    }
+
+    if (pfl->bs) {
+        pfl->ro = bdrv_is_read_only(pfl->bs);
+    } else {
+        pfl->ro = 0;
+    }
+
+    pfl->timer = qemu_new_timer_ns(vm_clock, pflash_timer, pfl);
+    pfl->wcycle = 0;
+    pfl->cmd = 0;
+    pfl->status = 0;
+    /* Hardcoded CFI table */
+    pfl->cfi_len = 0x52;
+    /* Standard "QRY" string */
+    pfl->cfi_table[0x10] = 'Q';
+    pfl->cfi_table[0x11] = 'R';
+    pfl->cfi_table[0x12] = 'Y';
+    /* Command set (Intel) */
+    pfl->cfi_table[0x13] = 0x01;
+    pfl->cfi_table[0x14] = 0x00;
+    /* Primary extended table address (none) */
+    pfl->cfi_table[0x15] = 0x31;
+    pfl->cfi_table[0x16] = 0x00;
+    /* Alternate command set (none) */
+    pfl->cfi_table[0x17] = 0x00;
+    pfl->cfi_table[0x18] = 0x00;
+    /* Alternate extended table (none) */
+    pfl->cfi_table[0x19] = 0x00;
+    pfl->cfi_table[0x1A] = 0x00;
+    /* Vcc min */
+    pfl->cfi_table[0x1B] = 0x45;
+    /* Vcc max */
+    pfl->cfi_table[0x1C] = 0x55;
+    /* Vpp min (no Vpp pin) */
+    pfl->cfi_table[0x1D] = 0x00;
+    /* Vpp max (no Vpp pin) */
+    pfl->cfi_table[0x1E] = 0x00;
+    /* Reserved */
+    pfl->cfi_table[0x1F] = 0x07;
+    /* Timeout for min size buffer write */
+    pfl->cfi_table[0x20] = 0x07;
+    /* Typical timeout for block erase */
+    pfl->cfi_table[0x21] = 0x0a;
+    /* Typical timeout for full chip erase (4096 ms) */
+    pfl->cfi_table[0x22] = 0x00;
+    /* Reserved */
+    pfl->cfi_table[0x23] = 0x04;
+    /* Max timeout for buffer write */
+    pfl->cfi_table[0x24] = 0x04;
+    /* Max timeout for block erase */
+    pfl->cfi_table[0x25] = 0x04;
+    /* Max timeout for chip erase */
+    pfl->cfi_table[0x26] = 0x00;
+    /* Device size */
+    pfl->cfi_table[0x27] = ctz32(total_len); // + 1;
+    /* Flash device interface (8 & 16 bits) */
+    pfl->cfi_table[0x28] = 0x02;
+    pfl->cfi_table[0x29] = 0x00;
+    /* Max number of bytes in multi-bytes write */
+    if (pfl->width == 1) {
+        pfl->cfi_table[0x2A] = 0x08;
+    } else {
+        pfl->cfi_table[0x2A] = 0x0B;
+    }
+    pfl->writeblock_size = 1 << pfl->cfi_table[0x2A];
+
+    pfl->cfi_table[0x2B] = 0x00;
+    /* Number of erase block regions (uniform) */
+    pfl->cfi_table[0x2C] = 0x01;
+    /* Erase block region 1 */
+    pfl->cfi_table[0x2D] = pfl->nb_blocs - 1;
+    pfl->cfi_table[0x2E] = (pfl->nb_blocs - 1) >> 8;
+    pfl->cfi_table[0x2F] = pfl->sector_len >> 8;
+    pfl->cfi_table[0x30] = pfl->sector_len >> 16;
+
+    /* Extended */
+    pfl->cfi_table[0x31] = 'P';
+    pfl->cfi_table[0x32] = 'R';
+    pfl->cfi_table[0x33] = 'I';
+
+    pfl->cfi_table[0x34] = '1';
+    pfl->cfi_table[0x35] = '0';
+
+    pfl->cfi_table[0x36] = 0x00;
+    pfl->cfi_table[0x37] = 0x00;
+    pfl->cfi_table[0x38] = 0x00;
+    pfl->cfi_table[0x39] = 0x00;
+
+    pfl->cfi_table[0x3a] = 0x00;
+
+    pfl->cfi_table[0x3b] = 0x00;
+    pfl->cfi_table[0x3c] = 0x00;
+
+    pfl->cfi_table[0x3f] = 0x01; /* Number of protection fields */
+
+    return 0;
+}
+
+static Property pflash_cfi01_properties[] = {
+    DEFINE_PROP_DRIVE("drive", struct pflash_t, bs),
+    DEFINE_PROP_UINT32("num-blocks", struct pflash_t, nb_blocs, 0),
+    DEFINE_PROP_UINT64("sector-length", struct pflash_t, sector_len, 0),
+    DEFINE_PROP_UINT8("width", struct pflash_t, width, 0),
+    DEFINE_PROP_UINT8("big-endian", struct pflash_t, be, 0),
+    DEFINE_PROP_UINT16("id0", struct pflash_t, ident0, 0),
+    DEFINE_PROP_UINT16("id1", struct pflash_t, ident1, 0),
+    DEFINE_PROP_UINT16("id2", struct pflash_t, ident2, 0),
+    DEFINE_PROP_UINT16("id3", struct pflash_t, ident3, 0),
+    DEFINE_PROP_STRING("name", struct pflash_t, name),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void pflash_cfi01_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = pflash_cfi01_init;
+    dc->props = pflash_cfi01_properties;
+    dc->vmsd = &vmstate_pflash;
+}
+
+
+static const TypeInfo pflash_cfi01_info = {
+    .name           = "cfi.pflash01",
+    .parent         = TYPE_SYS_BUS_DEVICE,
+    .instance_size  = sizeof(struct pflash_t),
+    .class_init     = pflash_cfi01_class_init,
+};
+
+static void pflash_cfi01_register_types(void)
+{
+    type_register_static(&pflash_cfi01_info);
+}
+
+type_init(pflash_cfi01_register_types)
+
+pflash_t *pflash_cfi01_register(hwaddr base,
+                                DeviceState *qdev, const char *name,
+                                hwaddr size,
+                                BlockDriverState *bs,
+                                uint32_t sector_len, int nb_blocs, int width,
+                                uint16_t id0, uint16_t id1,
+                                uint16_t id2, uint16_t id3, int be)
+{
+    DeviceState *dev = qdev_create(NULL, "cfi.pflash01");
+    SysBusDevice *busdev = SYS_BUS_DEVICE(dev);
+    pflash_t *pfl = (pflash_t *)object_dynamic_cast(OBJECT(dev),
+                                                    "cfi.pflash01");
+
+    if (bs && qdev_prop_set_drive(dev, "drive", bs)) {
+        abort();
+    }
+    qdev_prop_set_uint32(dev, "num-blocks", nb_blocs);
+    qdev_prop_set_uint64(dev, "sector-length", sector_len);
+    qdev_prop_set_uint8(dev, "width", width);
+    qdev_prop_set_uint8(dev, "big-endian", !!be);
+    qdev_prop_set_uint16(dev, "id0", id0);
+    qdev_prop_set_uint16(dev, "id1", id1);
+    qdev_prop_set_uint16(dev, "id2", id2);
+    qdev_prop_set_uint16(dev, "id3", id3);
+    qdev_prop_set_string(dev, "name", name);
+    qdev_init_nofail(dev);
+
+    sysbus_mmio_map(busdev, 0, base);
+    return pfl;
+}
+
+MemoryRegion *pflash_cfi01_get_memory(pflash_t *fl)
+{
+    return &fl->mem;
+}
diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c
new file mode 100644 (file)
index 0000000..9a7fa70
--- /dev/null
@@ -0,0 +1,787 @@
+/*
+ *  CFI parallel flash with AMD command set emulation
+ *
+ *  Copyright (c) 2005 Jocelyn Mayer
+ *
+ * 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/>.
+ */
+
+/*
+ * For now, this code can emulate flashes of 1, 2 or 4 bytes width.
+ * Supported commands/modes are:
+ * - flash read
+ * - flash write
+ * - flash ID read
+ * - sector erase
+ * - chip erase
+ * - unlock bypass command
+ * - CFI queries
+ *
+ * It does not support flash interleaving.
+ * It does not implement boot blocs with reduced size
+ * It does not implement software data protection as found in many real chips
+ * It does not implement erase suspend/resume commands
+ * It does not implement multiple sectors erase
+ */
+
+#include "hw/hw.h"
+#include "hw/block/flash.h"
+#include "qemu/timer.h"
+#include "block/block.h"
+#include "exec/address-spaces.h"
+#include "qemu/host-utils.h"
+#include "hw/sysbus.h"
+
+//#define PFLASH_DEBUG
+#ifdef PFLASH_DEBUG
+#define DPRINTF(fmt, ...)                                  \
+do {                                                       \
+    fprintf(stderr "PFLASH: " fmt , ## __VA_ARGS__);       \
+} while (0)
+#else
+#define DPRINTF(fmt, ...) do { } while (0)
+#endif
+
+#define PFLASH_LAZY_ROMD_THRESHOLD 42
+
+struct pflash_t {
+    SysBusDevice busdev;
+    BlockDriverState *bs;
+    uint32_t sector_len;
+    uint32_t nb_blocs;
+    uint32_t chip_len;
+    uint8_t mappings;
+    uint8_t width;
+    uint8_t be;
+    int wcycle; /* if 0, the flash is read normally */
+    int bypass;
+    int ro;
+    uint8_t cmd;
+    uint8_t status;
+    /* FIXME: implement array device properties */
+    uint16_t ident0;
+    uint16_t ident1;
+    uint16_t ident2;
+    uint16_t ident3;
+    uint16_t unlock_addr0;
+    uint16_t unlock_addr1;
+    uint8_t cfi_len;
+    uint8_t cfi_table[0x52];
+    QEMUTimer *timer;
+    /* The device replicates the flash memory across its memory space.  Emulate
+     * that by having a container (.mem) filled with an array of aliases
+     * (.mem_mappings) pointing to the flash memory (.orig_mem).
+     */
+    MemoryRegion mem;
+    MemoryRegion *mem_mappings;    /* array; one per mapping */
+    MemoryRegion orig_mem;
+    int rom_mode;
+    int read_counter; /* used for lazy switch-back to rom mode */
+    char *name;
+    void *storage;
+};
+
+/*
+ * Set up replicated mappings of the same region.
+ */
+static void pflash_setup_mappings(pflash_t *pfl)
+{
+    unsigned i;
+    hwaddr size = memory_region_size(&pfl->orig_mem);
+
+    memory_region_init(&pfl->mem, "pflash", pfl->mappings * size);
+    pfl->mem_mappings = g_new(MemoryRegion, pfl->mappings);
+    for (i = 0; i < pfl->mappings; ++i) {
+        memory_region_init_alias(&pfl->mem_mappings[i], "pflash-alias",
+                                 &pfl->orig_mem, 0, size);
+        memory_region_add_subregion(&pfl->mem, i * size, &pfl->mem_mappings[i]);
+    }
+}
+
+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)
+{
+    pflash_t *pfl = opaque;
+
+    DPRINTF("%s: command %02x done\n", __func__, pfl->cmd);
+    /* Reset flash */
+    pfl->status ^= 0x80;
+    if (pfl->bypass) {
+        pfl->wcycle = 2;
+    } else {
+        pflash_register_memory(pfl, 1);
+        pfl->wcycle = 0;
+    }
+    pfl->cmd = 0;
+}
+
+static uint32_t pflash_read (pflash_t *pfl, hwaddr offset,
+                             int width, int be)
+{
+    hwaddr boff;
+    uint32_t ret;
+    uint8_t *p;
+
+    DPRINTF("%s: offset " TARGET_FMT_plx "\n", __func__, offset);
+    ret = -1;
+    /* Lazy reset to ROMD mode after a certain amount of read accesses */
+    if (!pfl->rom_mode && pfl->wcycle == 0 &&
+        ++pfl->read_counter > PFLASH_LAZY_ROMD_THRESHOLD) {
+        pflash_register_memory(pfl, 1);
+    }
+    offset &= pfl->chip_len - 1;
+    boff = offset & 0xFF;
+    if (pfl->width == 2)
+        boff = boff >> 1;
+    else if (pfl->width == 4)
+        boff = boff >> 2;
+    switch (pfl->cmd) {
+    default:
+        /* This should never happen : reset state & treat it as a read*/
+        DPRINTF("%s: unknown command state: %x\n", __func__, pfl->cmd);
+        pfl->wcycle = 0;
+        pfl->cmd = 0;
+        /* fall through to the read code */
+    case 0x80:
+        /* We accept reads during second unlock sequence... */
+    case 0x00:
+    flash_read:
+        /* Flash area read */
+        p = pfl->storage;
+        switch (width) {
+        case 1:
+            ret = p[offset];
+//            DPRINTF("%s: data offset %08x %02x\n", __func__, offset, ret);
+            break;
+        case 2:
+            if (be) {
+                ret = p[offset] << 8;
+                ret |= p[offset + 1];
+            } else {
+                ret = p[offset];
+                ret |= p[offset + 1] << 8;
+            }
+//            DPRINTF("%s: data offset %08x %04x\n", __func__, offset, ret);
+            break;
+        case 4:
+            if (be) {
+                ret = p[offset] << 24;
+                ret |= p[offset + 1] << 16;
+                ret |= p[offset + 2] << 8;
+                ret |= p[offset + 3];
+            } else {
+                ret = p[offset];
+                ret |= p[offset + 1] << 8;
+                ret |= p[offset + 2] << 16;
+                ret |= p[offset + 3] << 24;
+            }
+//            DPRINTF("%s: data offset %08x %08x\n", __func__, offset, ret);
+            break;
+        }
+        break;
+    case 0x90:
+        /* flash ID read */
+        switch (boff) {
+        case 0x00:
+        case 0x01:
+            ret = boff & 0x01 ? pfl->ident1 : pfl->ident0;
+            break;
+        case 0x02:
+            ret = 0x00; /* Pretend all sectors are unprotected */
+            break;
+        case 0x0E:
+        case 0x0F:
+            ret = boff & 0x01 ? pfl->ident3 : pfl->ident2;
+            if (ret == (uint8_t)-1) {
+                goto flash_read;
+            }
+            break;
+        default:
+            goto flash_read;
+        }
+        DPRINTF("%s: ID " TARGET_FMT_plx " %x\n", __func__, boff, ret);
+        break;
+    case 0xA0:
+    case 0x10:
+    case 0x30:
+        /* Status register read */
+        ret = pfl->status;
+        DPRINTF("%s: status %x\n", __func__, ret);
+        /* Toggle bit 6 */
+        pfl->status ^= 0x40;
+        break;
+    case 0x98:
+        /* CFI query mode */
+        if (boff > pfl->cfi_len)
+            ret = 0;
+        else
+            ret = pfl->cfi_table[boff];
+        break;
+    }
+
+    return ret;
+}
+
+/* update flash content on disk */
+static void pflash_update(pflash_t *pfl, int offset,
+                          int size)
+{
+    int offset_end;
+    if (pfl->bs) {
+        offset_end = offset + size;
+        /* round to sectors */
+        offset = offset >> 9;
+        offset_end = (offset_end + 511) >> 9;
+        bdrv_write(pfl->bs, offset, pfl->storage + (offset << 9),
+                   offset_end - offset);
+    }
+}
+
+static void pflash_write (pflash_t *pfl, hwaddr offset,
+                          uint32_t value, int width, int be)
+{
+    hwaddr boff;
+    uint8_t *p;
+    uint8_t cmd;
+
+    cmd = value;
+    if (pfl->cmd != 0xA0 && cmd == 0xF0) {
+#if 0
+        DPRINTF("%s: flash reset asked (%02x %02x)\n",
+                __func__, pfl->cmd, cmd);
+#endif
+        goto reset_flash;
+    }
+    DPRINTF("%s: offset " TARGET_FMT_plx " %08x %d %d\n", __func__,
+            offset, value, width, pfl->wcycle);
+    offset &= pfl->chip_len - 1;
+
+    DPRINTF("%s: offset " TARGET_FMT_plx " %08x %d\n", __func__,
+            offset, value, width);
+    boff = offset & (pfl->sector_len - 1);
+    if (pfl->width == 2)
+        boff = boff >> 1;
+    else if (pfl->width == 4)
+        boff = boff >> 2;
+    switch (pfl->wcycle) {
+    case 0:
+        /* Set the device in I/O access mode if required */
+        if (pfl->rom_mode)
+            pflash_register_memory(pfl, 0);
+        pfl->read_counter = 0;
+        /* We're in read mode */
+    check_unlock0:
+        if (boff == 0x55 && cmd == 0x98) {
+        enter_CFI_mode:
+            /* Enter CFI query mode */
+            pfl->wcycle = 7;
+            pfl->cmd = 0x98;
+            return;
+        }
+        if (boff != pfl->unlock_addr0 || cmd != 0xAA) {
+            DPRINTF("%s: unlock0 failed " TARGET_FMT_plx " %02x %04x\n",
+                    __func__, boff, cmd, pfl->unlock_addr0);
+            goto reset_flash;
+        }
+        DPRINTF("%s: unlock sequence started\n", __func__);
+        break;
+    case 1:
+        /* We started an unlock sequence */
+    check_unlock1:
+        if (boff != pfl->unlock_addr1 || cmd != 0x55) {
+            DPRINTF("%s: unlock1 failed " TARGET_FMT_plx " %02x\n", __func__,
+                    boff, cmd);
+            goto reset_flash;
+        }
+        DPRINTF("%s: unlock sequence done\n", __func__);
+        break;
+    case 2:
+        /* We finished an unlock sequence */
+        if (!pfl->bypass && boff != pfl->unlock_addr0) {
+            DPRINTF("%s: command failed " TARGET_FMT_plx " %02x\n", __func__,
+                    boff, cmd);
+            goto reset_flash;
+        }
+        switch (cmd) {
+        case 0x20:
+            pfl->bypass = 1;
+            goto do_bypass;
+        case 0x80:
+        case 0x90:
+        case 0xA0:
+            pfl->cmd = cmd;
+            DPRINTF("%s: starting command %02x\n", __func__, cmd);
+            break;
+        default:
+            DPRINTF("%s: unknown command %02x\n", __func__, cmd);
+            goto reset_flash;
+        }
+        break;
+    case 3:
+        switch (pfl->cmd) {
+        case 0x80:
+            /* We need another unlock sequence */
+            goto check_unlock0;
+        case 0xA0:
+            DPRINTF("%s: write data offset " TARGET_FMT_plx " %08x %d\n",
+                    __func__, offset, value, width);
+            p = pfl->storage;
+            if (!pfl->ro) {
+                switch (width) {
+                case 1:
+                    p[offset] &= value;
+                    pflash_update(pfl, offset, 1);
+                    break;
+                case 2:
+                    if (be) {
+                        p[offset] &= value >> 8;
+                        p[offset + 1] &= value;
+                    } else {
+                        p[offset] &= value;
+                        p[offset + 1] &= value >> 8;
+                    }
+                    pflash_update(pfl, offset, 2);
+                    break;
+                case 4:
+                    if (be) {
+                        p[offset] &= value >> 24;
+                        p[offset + 1] &= value >> 16;
+                        p[offset + 2] &= value >> 8;
+                        p[offset + 3] &= value;
+                    } else {
+                        p[offset] &= value;
+                        p[offset + 1] &= value >> 8;
+                        p[offset + 2] &= value >> 16;
+                        p[offset + 3] &= value >> 24;
+                    }
+                    pflash_update(pfl, offset, 4);
+                    break;
+                }
+            }
+            pfl->status = 0x00 | ~(value & 0x80);
+            /* Let's pretend write is immediate */
+            if (pfl->bypass)
+                goto do_bypass;
+            goto reset_flash;
+        case 0x90:
+            if (pfl->bypass && cmd == 0x00) {
+                /* Unlock bypass reset */
+                goto reset_flash;
+            }
+            /* We can enter CFI query mode from autoselect mode */
+            if (boff == 0x55 && cmd == 0x98)
+                goto enter_CFI_mode;
+            /* No break here */
+        default:
+            DPRINTF("%s: invalid write for command %02x\n",
+                    __func__, pfl->cmd);
+            goto reset_flash;
+        }
+    case 4:
+        switch (pfl->cmd) {
+        case 0xA0:
+            /* Ignore writes while flash data write is occurring */
+            /* As we suppose write is immediate, this should never happen */
+            return;
+        case 0x80:
+            goto check_unlock1;
+        default:
+            /* Should never happen */
+            DPRINTF("%s: invalid command state %02x (wc 4)\n",
+                    __func__, pfl->cmd);
+            goto reset_flash;
+        }
+        break;
+    case 5:
+        switch (cmd) {
+        case 0x10:
+            if (boff != pfl->unlock_addr0) {
+                DPRINTF("%s: chip erase: invalid address " TARGET_FMT_plx "\n",
+                        __func__, offset);
+                goto reset_flash;
+            }
+            /* Chip erase */
+            DPRINTF("%s: start chip erase\n", __func__);
+            if (!pfl->ro) {
+                memset(pfl->storage, 0xFF, pfl->chip_len);
+                pflash_update(pfl, 0, pfl->chip_len);
+            }
+            pfl->status = 0x00;
+            /* Let's wait 5 seconds before chip erase is done */
+            qemu_mod_timer(pfl->timer,
+                           qemu_get_clock_ns(vm_clock) + (get_ticks_per_sec() * 5));
+            break;
+        case 0x30:
+            /* Sector erase */
+            p = pfl->storage;
+            offset &= ~(pfl->sector_len - 1);
+            DPRINTF("%s: start sector erase at " TARGET_FMT_plx "\n", __func__,
+                    offset);
+            if (!pfl->ro) {
+                memset(p + offset, 0xFF, pfl->sector_len);
+                pflash_update(pfl, offset, pfl->sector_len);
+            }
+            pfl->status = 0x00;
+            /* Let's wait 1/2 second before sector erase is done */
+            qemu_mod_timer(pfl->timer,
+                           qemu_get_clock_ns(vm_clock) + (get_ticks_per_sec() / 2));
+            break;
+        default:
+            DPRINTF("%s: invalid command %02x (wc 5)\n", __func__, cmd);
+            goto reset_flash;
+        }
+        pfl->cmd = cmd;
+        break;
+    case 6:
+        switch (pfl->cmd) {
+        case 0x10:
+            /* Ignore writes during chip erase */
+            return;
+        case 0x30:
+            /* Ignore writes during sector erase */
+            return;
+        default:
+            /* Should never happen */
+            DPRINTF("%s: invalid command state %02x (wc 6)\n",
+                    __func__, pfl->cmd);
+            goto reset_flash;
+        }
+        break;
+    case 7: /* Special value for CFI queries */
+        DPRINTF("%s: invalid write in CFI query mode\n", __func__);
+        goto reset_flash;
+    default:
+        /* Should never happen */
+        DPRINTF("%s: invalid write state (wc 7)\n",  __func__);
+        goto reset_flash;
+    }
+    pfl->wcycle++;
+
+    return;
+
+    /* Reset flash */
+ reset_flash:
+    pfl->bypass = 0;
+    pfl->wcycle = 0;
+    pfl->cmd = 0;
+    return;
+
+ do_bypass:
+    pfl->wcycle = 2;
+    pfl->cmd = 0;
+}
+
+
+static uint32_t pflash_readb_be(void *opaque, hwaddr addr)
+{
+    return pflash_read(opaque, addr, 1, 1);
+}
+
+static uint32_t pflash_readb_le(void *opaque, hwaddr addr)
+{
+    return pflash_read(opaque, addr, 1, 0);
+}
+
+static uint32_t pflash_readw_be(void *opaque, hwaddr addr)
+{
+    pflash_t *pfl = opaque;
+
+    return pflash_read(pfl, addr, 2, 1);
+}
+
+static uint32_t pflash_readw_le(void *opaque, hwaddr addr)
+{
+    pflash_t *pfl = opaque;
+
+    return pflash_read(pfl, addr, 2, 0);
+}
+
+static uint32_t pflash_readl_be(void *opaque, hwaddr addr)
+{
+    pflash_t *pfl = opaque;
+
+    return pflash_read(pfl, addr, 4, 1);
+}
+
+static uint32_t pflash_readl_le(void *opaque, hwaddr addr)
+{
+    pflash_t *pfl = opaque;
+
+    return pflash_read(pfl, addr, 4, 0);
+}
+
+static void pflash_writeb_be(void *opaque, hwaddr addr,
+                             uint32_t value)
+{
+    pflash_write(opaque, addr, value, 1, 1);
+}
+
+static void pflash_writeb_le(void *opaque, hwaddr addr,
+                             uint32_t value)
+{
+    pflash_write(opaque, addr, value, 1, 0);
+}
+
+static void pflash_writew_be(void *opaque, hwaddr addr,
+                             uint32_t value)
+{
+    pflash_t *pfl = opaque;
+
+    pflash_write(pfl, addr, value, 2, 1);
+}
+
+static void pflash_writew_le(void *opaque, hwaddr addr,
+                             uint32_t value)
+{
+    pflash_t *pfl = opaque;
+
+    pflash_write(pfl, addr, value, 2, 0);
+}
+
+static void pflash_writel_be(void *opaque, hwaddr addr,
+                             uint32_t value)
+{
+    pflash_t *pfl = opaque;
+
+    pflash_write(pfl, addr, value, 4, 1);
+}
+
+static void pflash_writel_le(void *opaque, hwaddr addr,
+                             uint32_t value)
+{
+    pflash_t *pfl = opaque;
+
+    pflash_write(pfl, addr, value, 4, 0);
+}
+
+static const MemoryRegionOps pflash_cfi02_ops_be = {
+    .old_mmio = {
+        .read = { pflash_readb_be, pflash_readw_be, pflash_readl_be, },
+        .write = { pflash_writeb_be, pflash_writew_be, pflash_writel_be, },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static const MemoryRegionOps pflash_cfi02_ops_le = {
+    .old_mmio = {
+        .read = { pflash_readb_le, pflash_readw_le, pflash_readl_le, },
+        .write = { pflash_writeb_le, pflash_writew_le, pflash_writel_le, },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int pflash_cfi02_init(SysBusDevice *dev)
+{
+    pflash_t *pfl = FROM_SYSBUS(typeof(*pfl), dev);
+    uint32_t chip_len;
+    int ret;
+
+    chip_len = pfl->sector_len * pfl->nb_blocs;
+    /* XXX: to be fixed */
+#if 0
+    if (total_len != (8 * 1024 * 1024) && total_len != (16 * 1024 * 1024) &&
+        total_len != (32 * 1024 * 1024) && total_len != (64 * 1024 * 1024))
+        return NULL;
+#endif
+
+    memory_region_init_rom_device(&pfl->orig_mem, pfl->be ?
+                                  &pflash_cfi02_ops_be : &pflash_cfi02_ops_le,
+                                  pfl, pfl->name, chip_len);
+    vmstate_register_ram(&pfl->orig_mem, DEVICE(pfl));
+    pfl->storage = memory_region_get_ram_ptr(&pfl->orig_mem);
+    pfl->chip_len = chip_len;
+    if (pfl->bs) {
+        /* read the initial flash content */
+        ret = bdrv_read(pfl->bs, 0, pfl->storage, chip_len >> 9);
+        if (ret < 0) {
+            g_free(pfl);
+            return 1;
+        }
+    }
+
+    pflash_setup_mappings(pfl);
+    pfl->rom_mode = 1;
+    sysbus_init_mmio(dev, &pfl->mem);
+
+    if (pfl->bs) {
+        pfl->ro = bdrv_is_read_only(pfl->bs);
+    } else {
+        pfl->ro = 0;
+    }
+
+    pfl->timer = qemu_new_timer_ns(vm_clock, pflash_timer, pfl);
+    pfl->wcycle = 0;
+    pfl->cmd = 0;
+    pfl->status = 0;
+    /* Hardcoded CFI table (mostly from SG29 Spansion flash) */
+    pfl->cfi_len = 0x52;
+    /* Standard "QRY" string */
+    pfl->cfi_table[0x10] = 'Q';
+    pfl->cfi_table[0x11] = 'R';
+    pfl->cfi_table[0x12] = 'Y';
+    /* Command set (AMD/Fujitsu) */
+    pfl->cfi_table[0x13] = 0x02;
+    pfl->cfi_table[0x14] = 0x00;
+    /* Primary extended table address */
+    pfl->cfi_table[0x15] = 0x31;
+    pfl->cfi_table[0x16] = 0x00;
+    /* Alternate command set (none) */
+    pfl->cfi_table[0x17] = 0x00;
+    pfl->cfi_table[0x18] = 0x00;
+    /* Alternate extended table (none) */
+    pfl->cfi_table[0x19] = 0x00;
+    pfl->cfi_table[0x1A] = 0x00;
+    /* Vcc min */
+    pfl->cfi_table[0x1B] = 0x27;
+    /* Vcc max */
+    pfl->cfi_table[0x1C] = 0x36;
+    /* Vpp min (no Vpp pin) */
+    pfl->cfi_table[0x1D] = 0x00;
+    /* Vpp max (no Vpp pin) */
+    pfl->cfi_table[0x1E] = 0x00;
+    /* Reserved */
+    pfl->cfi_table[0x1F] = 0x07;
+    /* Timeout for min size buffer write (NA) */
+    pfl->cfi_table[0x20] = 0x00;
+    /* Typical timeout for block erase (512 ms) */
+    pfl->cfi_table[0x21] = 0x09;
+    /* Typical timeout for full chip erase (4096 ms) */
+    pfl->cfi_table[0x22] = 0x0C;
+    /* Reserved */
+    pfl->cfi_table[0x23] = 0x01;
+    /* Max timeout for buffer write (NA) */
+    pfl->cfi_table[0x24] = 0x00;
+    /* Max timeout for block erase */
+    pfl->cfi_table[0x25] = 0x0A;
+    /* Max timeout for chip erase */
+    pfl->cfi_table[0x26] = 0x0D;
+    /* Device size */
+    pfl->cfi_table[0x27] = ctz32(chip_len);
+    /* Flash device interface (8 & 16 bits) */
+    pfl->cfi_table[0x28] = 0x02;
+    pfl->cfi_table[0x29] = 0x00;
+    /* Max number of bytes in multi-bytes write */
+    /* XXX: disable buffered write as it's not supported */
+    //    pfl->cfi_table[0x2A] = 0x05;
+    pfl->cfi_table[0x2A] = 0x00;
+    pfl->cfi_table[0x2B] = 0x00;
+    /* Number of erase block regions (uniform) */
+    pfl->cfi_table[0x2C] = 0x01;
+    /* Erase block region 1 */
+    pfl->cfi_table[0x2D] = pfl->nb_blocs - 1;
+    pfl->cfi_table[0x2E] = (pfl->nb_blocs - 1) >> 8;
+    pfl->cfi_table[0x2F] = pfl->sector_len >> 8;
+    pfl->cfi_table[0x30] = pfl->sector_len >> 16;
+
+    /* Extended */
+    pfl->cfi_table[0x31] = 'P';
+    pfl->cfi_table[0x32] = 'R';
+    pfl->cfi_table[0x33] = 'I';
+
+    pfl->cfi_table[0x34] = '1';
+    pfl->cfi_table[0x35] = '0';
+
+    pfl->cfi_table[0x36] = 0x00;
+    pfl->cfi_table[0x37] = 0x00;
+    pfl->cfi_table[0x38] = 0x00;
+    pfl->cfi_table[0x39] = 0x00;
+
+    pfl->cfi_table[0x3a] = 0x00;
+
+    pfl->cfi_table[0x3b] = 0x00;
+    pfl->cfi_table[0x3c] = 0x00;
+
+    return 0;
+}
+
+static Property pflash_cfi02_properties[] = {
+    DEFINE_PROP_DRIVE("drive", struct pflash_t, bs),
+    DEFINE_PROP_UINT32("num-blocks", struct pflash_t, nb_blocs, 0),
+    DEFINE_PROP_UINT32("sector-length", struct pflash_t, sector_len, 0),
+    DEFINE_PROP_UINT8("width", struct pflash_t, width, 0),
+    DEFINE_PROP_UINT8("mappings", struct pflash_t, mappings, 0),
+    DEFINE_PROP_UINT8("big-endian", struct pflash_t, be, 0),
+    DEFINE_PROP_UINT16("id0", struct pflash_t, ident0, 0),
+    DEFINE_PROP_UINT16("id1", struct pflash_t, ident1, 0),
+    DEFINE_PROP_UINT16("id2", struct pflash_t, ident2, 0),
+    DEFINE_PROP_UINT16("id3", struct pflash_t, ident3, 0),
+    DEFINE_PROP_UINT16("unlock-addr0", struct pflash_t, unlock_addr0, 0),
+    DEFINE_PROP_UINT16("unlock-addr1", struct pflash_t, unlock_addr1, 0),
+    DEFINE_PROP_STRING("name", struct pflash_t, name),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void pflash_cfi02_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = pflash_cfi02_init;
+    dc->props = pflash_cfi02_properties;
+}
+
+static const TypeInfo pflash_cfi02_info = {
+    .name           = "cfi.pflash02",
+    .parent         = TYPE_SYS_BUS_DEVICE,
+    .instance_size  = sizeof(struct pflash_t),
+    .class_init     = pflash_cfi02_class_init,
+};
+
+static void pflash_cfi02_register_types(void)
+{
+    type_register_static(&pflash_cfi02_info);
+}
+
+type_init(pflash_cfi02_register_types)
+
+pflash_t *pflash_cfi02_register(hwaddr base,
+                                DeviceState *qdev, const char *name,
+                                hwaddr size,
+                                BlockDriverState *bs, uint32_t sector_len,
+                                int nb_blocs, int nb_mappings, int width,
+                                uint16_t id0, uint16_t id1,
+                                uint16_t id2, uint16_t id3,
+                                uint16_t unlock_addr0, uint16_t unlock_addr1,
+                                int be)
+{
+    DeviceState *dev = qdev_create(NULL, "cfi.pflash02");
+    SysBusDevice *busdev = SYS_BUS_DEVICE(dev);
+    pflash_t *pfl = (pflash_t *)object_dynamic_cast(OBJECT(dev),
+                                                    "cfi.pflash02");
+
+    if (bs && qdev_prop_set_drive(dev, "drive", bs)) {
+        abort();
+    }
+    qdev_prop_set_uint32(dev, "num-blocks", nb_blocs);
+    qdev_prop_set_uint32(dev, "sector-length", sector_len);
+    qdev_prop_set_uint8(dev, "width", width);
+    qdev_prop_set_uint8(dev, "mappings", nb_mappings);
+    qdev_prop_set_uint8(dev, "big-endian", !!be);
+    qdev_prop_set_uint16(dev, "id0", id0);
+    qdev_prop_set_uint16(dev, "id1", id1);
+    qdev_prop_set_uint16(dev, "id2", id2);
+    qdev_prop_set_uint16(dev, "id3", id3);
+    qdev_prop_set_uint16(dev, "unlock-addr0", unlock_addr0);
+    qdev_prop_set_uint16(dev, "unlock-addr1", unlock_addr1);
+    qdev_prop_set_string(dev, "name", name);
+    qdev_init_nofail(dev);
+
+    sysbus_mmio_map(busdev, 0, base);
+    return pfl;
+}
diff --git a/hw/block/tc58128.c b/hw/block/tc58128.c
new file mode 100644 (file)
index 0000000..a3929d4
--- /dev/null
@@ -0,0 +1,178 @@
+#include "hw/hw.h"
+#include "hw/sh4/sh.h"
+#include "hw/loader.h"
+
+#define CE1  0x0100
+#define CE2  0x0200
+#define RE   0x0400
+#define WE   0x0800
+#define ALE  0x1000
+#define CLE  0x2000
+#define RDY1 0x4000
+#define RDY2 0x8000
+#define RDY(n) ((n) == 0 ? RDY1 : RDY2)
+
+typedef enum { WAIT, READ1, READ2, READ3 } state_t;
+
+typedef struct {
+    uint8_t *flash_contents;
+    state_t state;
+    uint32_t address;
+    uint8_t address_cycle;
+} tc58128_dev;
+
+static tc58128_dev tc58128_devs[2];
+
+#define FLASH_SIZE (16*1024*1024)
+
+static void init_dev(tc58128_dev * dev, const char *filename)
+{
+    int ret, blocks;
+
+    dev->state = WAIT;
+    dev->flash_contents = g_malloc(FLASH_SIZE);
+    memset(dev->flash_contents, 0xff, FLASH_SIZE);
+    if (filename) {
+       /* Load flash image skipping the first block */
+       ret = load_image(filename, dev->flash_contents + 528 * 32);
+       if (ret < 0) {
+           fprintf(stderr, "ret=%d\n", ret);
+           fprintf(stderr, "qemu: could not load flash image %s\n",
+                   filename);
+           exit(1);
+       } else {
+           /* Build first block with number of blocks */
+           blocks = (ret + 528 * 32 - 1) / (528 * 32);
+           dev->flash_contents[0] = blocks & 0xff;
+           dev->flash_contents[1] = (blocks >> 8) & 0xff;
+           dev->flash_contents[2] = (blocks >> 16) & 0xff;
+           dev->flash_contents[3] = (blocks >> 24) & 0xff;
+           fprintf(stderr, "loaded %d bytes for %s into flash\n", ret,
+                   filename);
+       }
+    }
+}
+
+static void handle_command(tc58128_dev * dev, uint8_t command)
+{
+    switch (command) {
+    case 0xff:
+       fprintf(stderr, "reset flash device\n");
+       dev->state = WAIT;
+       break;
+    case 0x00:
+       fprintf(stderr, "read mode 1\n");
+       dev->state = READ1;
+       dev->address_cycle = 0;
+       break;
+    case 0x01:
+       fprintf(stderr, "read mode 2\n");
+       dev->state = READ2;
+       dev->address_cycle = 0;
+       break;
+    case 0x50:
+       fprintf(stderr, "read mode 3\n");
+       dev->state = READ3;
+       dev->address_cycle = 0;
+       break;
+    default:
+       fprintf(stderr, "unknown flash command 0x%02x\n", command);
+        abort();
+    }
+}
+
+static void handle_address(tc58128_dev * dev, uint8_t data)
+{
+    switch (dev->state) {
+    case READ1:
+    case READ2:
+    case READ3:
+       switch (dev->address_cycle) {
+       case 0:
+           dev->address = data;
+           if (dev->state == READ2)
+               dev->address |= 0x100;
+           else if (dev->state == READ3)
+               dev->address |= 0x200;
+           break;
+       case 1:
+           dev->address += data * 528 * 0x100;
+           break;
+       case 2:
+           dev->address += data * 528;
+           fprintf(stderr, "address pointer in flash: 0x%08x\n",
+                   dev->address);
+           break;
+       default:
+           /* Invalid data */
+            abort();
+       }
+       dev->address_cycle++;
+       break;
+    default:
+        abort();
+    }
+}
+
+static uint8_t handle_read(tc58128_dev * dev)
+{
+#if 0
+    if (dev->address % 0x100000 == 0)
+       fprintf(stderr, "reading flash at address 0x%08x\n", dev->address);
+#endif
+    return dev->flash_contents[dev->address++];
+}
+
+/* We never mark the device as busy, so interrupts cannot be triggered
+   XXXXX */
+
+static int tc58128_cb(uint16_t porta, uint16_t portb,
+                      uint16_t * periph_pdtra, uint16_t * periph_portadir,
+                      uint16_t * periph_pdtrb, uint16_t * periph_portbdir)
+{
+    int dev;
+
+    if ((porta & CE1) == 0)
+       dev = 0;
+    else if ((porta & CE2) == 0)
+       dev = 1;
+    else
+       return 0;               /* No device selected */
+
+    if ((porta & RE) && (porta & WE)) {
+       /* Nothing to do, assert ready and return to input state */
+       *periph_portadir &= 0xff00;
+       *periph_portadir |= RDY(dev);
+       *periph_pdtra |= RDY(dev);
+       return 1;
+    }
+
+    if (porta & CLE) {
+       /* Command */
+       assert((porta & WE) == 0);
+       handle_command(&tc58128_devs[dev], porta & 0x00ff);
+    } else if (porta & ALE) {
+       assert((porta & WE) == 0);
+       handle_address(&tc58128_devs[dev], porta & 0x00ff);
+    } else if ((porta & RE) == 0) {
+       *periph_portadir |= 0x00ff;
+       *periph_pdtra &= 0xff00;
+       *periph_pdtra |= handle_read(&tc58128_devs[dev]);
+    } else {
+        abort();
+    }
+    return 1;
+}
+
+static sh7750_io_device tc58128 = {
+    RE | WE,                   /* Port A triggers */
+    0,                         /* Port B triggers */
+    tc58128_cb                 /* Callback */
+};
+
+int tc58128_init(struct SH7750State *s, const char *zone1, const char *zone2)
+{
+    init_dev(&tc58128_devs[0], zone1);
+    init_dev(&tc58128_devs[1], zone2);
+    return sh7750_register_io_device(s, &tc58128);
+}
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
new file mode 100644 (file)
index 0000000..6efb2f0
--- /dev/null
@@ -0,0 +1,732 @@
+/*
+ * Virtio Block Device
+ *
+ * Copyright IBM, Corp. 2007
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.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 "qemu-common.h"
+#include "qemu/error-report.h"
+#include "trace.h"
+#include "hw/block/block.h"
+#include "sysemu/blockdev.h"
+#include "hw/virtio/virtio-blk.h"
+#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE
+# include "dataplane/virtio-blk.h"
+#endif
+#include "block/scsi.h"
+#ifdef __linux__
+# include <scsi/sg.h>
+#endif
+#include "hw/virtio/virtio-bus.h"
+
+typedef struct VirtIOBlockReq
+{
+    VirtIOBlock *dev;
+    VirtQueueElement elem;
+    struct virtio_blk_inhdr *in;
+    struct virtio_blk_outhdr *out;
+    struct virtio_scsi_inhdr *scsi;
+    QEMUIOVector qiov;
+    struct VirtIOBlockReq *next;
+    BlockAcctCookie acct;
+} VirtIOBlockReq;
+
+static void virtio_blk_req_complete(VirtIOBlockReq *req, int status)
+{
+    VirtIOBlock *s = req->dev;
+    VirtIODevice *vdev = VIRTIO_DEVICE(s);
+
+    trace_virtio_blk_req_complete(req, status);
+
+    stb_p(&req->in->status, status);
+    virtqueue_push(s->vq, &req->elem, req->qiov.size + sizeof(*req->in));
+    virtio_notify(vdev, s->vq);
+}
+
+static int virtio_blk_handle_rw_error(VirtIOBlockReq *req, int error,
+    bool is_read)
+{
+    BlockErrorAction action = bdrv_get_error_action(req->dev->bs, is_read, error);
+    VirtIOBlock *s = req->dev;
+
+    if (action == BDRV_ACTION_STOP) {
+        req->next = s->rq;
+        s->rq = req;
+    } else if (action == BDRV_ACTION_REPORT) {
+        virtio_blk_req_complete(req, VIRTIO_BLK_S_IOERR);
+        bdrv_acct_done(s->bs, &req->acct);
+        g_free(req);
+    }
+
+    bdrv_error_action(s->bs, action, is_read, error);
+    return action != BDRV_ACTION_IGNORE;
+}
+
+static void virtio_blk_rw_complete(void *opaque, int ret)
+{
+    VirtIOBlockReq *req = opaque;
+
+    trace_virtio_blk_rw_complete(req, ret);
+
+    if (ret) {
+        bool is_read = !(ldl_p(&req->out->type) & VIRTIO_BLK_T_OUT);
+        if (virtio_blk_handle_rw_error(req, -ret, is_read))
+            return;
+    }
+
+    virtio_blk_req_complete(req, VIRTIO_BLK_S_OK);
+    bdrv_acct_done(req->dev->bs, &req->acct);
+    g_free(req);
+}
+
+static void virtio_blk_flush_complete(void *opaque, int ret)
+{
+    VirtIOBlockReq *req = opaque;
+
+    if (ret) {
+        if (virtio_blk_handle_rw_error(req, -ret, 0)) {
+            return;
+        }
+    }
+
+    virtio_blk_req_complete(req, VIRTIO_BLK_S_OK);
+    bdrv_acct_done(req->dev->bs, &req->acct);
+    g_free(req);
+}
+
+static VirtIOBlockReq *virtio_blk_alloc_request(VirtIOBlock *s)
+{
+    VirtIOBlockReq *req = g_malloc(sizeof(*req));
+    req->dev = s;
+    req->qiov.size = 0;
+    req->next = NULL;
+    return req;
+}
+
+static VirtIOBlockReq *virtio_blk_get_request(VirtIOBlock *s)
+{
+    VirtIOBlockReq *req = virtio_blk_alloc_request(s);
+
+    if (req != NULL) {
+        if (!virtqueue_pop(s->vq, &req->elem)) {
+            g_free(req);
+            return NULL;
+        }
+    }
+
+    return req;
+}
+
+static void virtio_blk_handle_scsi(VirtIOBlockReq *req)
+{
+#ifdef __linux__
+    int ret;
+    int i;
+#endif
+    int status = VIRTIO_BLK_S_OK;
+
+    /*
+     * We require at least one output segment each for the virtio_blk_outhdr
+     * and the SCSI command block.
+     *
+     * We also at least require the virtio_blk_inhdr, the virtio_scsi_inhdr
+     * and the sense buffer pointer in the input segments.
+     */
+    if (req->elem.out_num < 2 || req->elem.in_num < 3) {
+        virtio_blk_req_complete(req, VIRTIO_BLK_S_IOERR);
+        g_free(req);
+        return;
+    }
+
+    /*
+     * The scsi inhdr is placed in the second-to-last input segment, just
+     * before the regular inhdr.
+     */
+    req->scsi = (void *)req->elem.in_sg[req->elem.in_num - 2].iov_base;
+
+    if (!req->dev->blk.scsi) {
+        status = VIRTIO_BLK_S_UNSUPP;
+        goto fail;
+    }
+
+    /*
+     * No support for bidirection commands yet.
+     */
+    if (req->elem.out_num > 2 && req->elem.in_num > 3) {
+        status = VIRTIO_BLK_S_UNSUPP;
+        goto fail;
+    }
+
+#ifdef __linux__
+    struct sg_io_hdr hdr;
+    memset(&hdr, 0, sizeof(struct sg_io_hdr));
+    hdr.interface_id = 'S';
+    hdr.cmd_len = req->elem.out_sg[1].iov_len;
+    hdr.cmdp = req->elem.out_sg[1].iov_base;
+    hdr.dxfer_len = 0;
+
+    if (req->elem.out_num > 2) {
+        /*
+         * If there are more than the minimally required 2 output segments
+         * there is write payload starting from the third iovec.
+         */
+        hdr.dxfer_direction = SG_DXFER_TO_DEV;
+        hdr.iovec_count = req->elem.out_num - 2;
+
+        for (i = 0; i < hdr.iovec_count; i++)
+            hdr.dxfer_len += req->elem.out_sg[i + 2].iov_len;
+
+        hdr.dxferp = req->elem.out_sg + 2;
+
+    } else if (req->elem.in_num > 3) {
+        /*
+         * If we have more than 3 input segments the guest wants to actually
+         * read data.
+         */
+        hdr.dxfer_direction = SG_DXFER_FROM_DEV;
+        hdr.iovec_count = req->elem.in_num - 3;
+        for (i = 0; i < hdr.iovec_count; i++)
+            hdr.dxfer_len += req->elem.in_sg[i].iov_len;
+
+        hdr.dxferp = req->elem.in_sg;
+    } else {
+        /*
+         * Some SCSI commands don't actually transfer any data.
+         */
+        hdr.dxfer_direction = SG_DXFER_NONE;
+    }
+
+    hdr.sbp = req->elem.in_sg[req->elem.in_num - 3].iov_base;
+    hdr.mx_sb_len = req->elem.in_sg[req->elem.in_num - 3].iov_len;
+
+    ret = bdrv_ioctl(req->dev->bs, SG_IO, &hdr);
+    if (ret) {
+        status = VIRTIO_BLK_S_UNSUPP;
+        goto fail;
+    }
+
+    /*
+     * From SCSI-Generic-HOWTO: "Some lower level drivers (e.g. ide-scsi)
+     * clear the masked_status field [hence status gets cleared too, see
+     * block/scsi_ioctl.c] even when a CHECK_CONDITION or COMMAND_TERMINATED
+     * status has occurred.  However they do set DRIVER_SENSE in driver_status
+     * field. Also a (sb_len_wr > 0) indicates there is a sense buffer.
+     */
+    if (hdr.status == 0 && hdr.sb_len_wr > 0) {
+        hdr.status = CHECK_CONDITION;
+    }
+
+    stl_p(&req->scsi->errors,
+          hdr.status | (hdr.msg_status << 8) |
+          (hdr.host_status << 16) | (hdr.driver_status << 24));
+    stl_p(&req->scsi->residual, hdr.resid);
+    stl_p(&req->scsi->sense_len, hdr.sb_len_wr);
+    stl_p(&req->scsi->data_len, hdr.dxfer_len);
+
+    virtio_blk_req_complete(req, status);
+    g_free(req);
+    return;
+#else
+    abort();
+#endif
+
+fail:
+    /* Just put anything nonzero so that the ioctl fails in the guest.  */
+    stl_p(&req->scsi->errors, 255);
+    virtio_blk_req_complete(req, status);
+    g_free(req);
+}
+
+typedef struct MultiReqBuffer {
+    BlockRequest        blkreq[32];
+    unsigned int        num_writes;
+} MultiReqBuffer;
+
+static void virtio_submit_multiwrite(BlockDriverState *bs, MultiReqBuffer *mrb)
+{
+    int i, ret;
+
+    if (!mrb->num_writes) {
+        return;
+    }
+
+    ret = bdrv_aio_multiwrite(bs, mrb->blkreq, mrb->num_writes);
+    if (ret != 0) {
+        for (i = 0; i < mrb->num_writes; i++) {
+            if (mrb->blkreq[i].error) {
+                virtio_blk_rw_complete(mrb->blkreq[i].opaque, -EIO);
+            }
+        }
+    }
+
+    mrb->num_writes = 0;
+}
+
+static void virtio_blk_handle_flush(VirtIOBlockReq *req, MultiReqBuffer *mrb)
+{
+    bdrv_acct_start(req->dev->bs, &req->acct, 0, BDRV_ACCT_FLUSH);
+
+    /*
+     * Make sure all outstanding writes are posted to the backing device.
+     */
+    virtio_submit_multiwrite(req->dev->bs, mrb);
+    bdrv_aio_flush(req->dev->bs, virtio_blk_flush_complete, req);
+}
+
+static void virtio_blk_handle_write(VirtIOBlockReq *req, MultiReqBuffer *mrb)
+{
+    BlockRequest *blkreq;
+    uint64_t sector;
+
+    sector = ldq_p(&req->out->sector);
+
+    bdrv_acct_start(req->dev->bs, &req->acct, req->qiov.size, BDRV_ACCT_WRITE);
+
+    trace_virtio_blk_handle_write(req, sector, req->qiov.size / 512);
+
+    if (sector & req->dev->sector_mask) {
+        virtio_blk_rw_complete(req, -EIO);
+        return;
+    }
+    if (req->qiov.size % req->dev->conf->logical_block_size) {
+        virtio_blk_rw_complete(req, -EIO);
+        return;
+    }
+
+    if (mrb->num_writes == 32) {
+        virtio_submit_multiwrite(req->dev->bs, mrb);
+    }
+
+    blkreq = &mrb->blkreq[mrb->num_writes];
+    blkreq->sector = sector;
+    blkreq->nb_sectors = req->qiov.size / BDRV_SECTOR_SIZE;
+    blkreq->qiov = &req->qiov;
+    blkreq->cb = virtio_blk_rw_complete;
+    blkreq->opaque = req;
+    blkreq->error = 0;
+
+    mrb->num_writes++;
+}
+
+static void virtio_blk_handle_read(VirtIOBlockReq *req)
+{
+    uint64_t sector;
+
+    sector = ldq_p(&req->out->sector);
+
+    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;
+    }
+    if (req->qiov.size % req->dev->conf->logical_block_size) {
+        virtio_blk_rw_complete(req, -EIO);
+        return;
+    }
+    bdrv_aio_readv(req->dev->bs, sector, &req->qiov,
+                   req->qiov.size / BDRV_SECTOR_SIZE,
+                   virtio_blk_rw_complete, req);
+}
+
+static void virtio_blk_handle_request(VirtIOBlockReq *req,
+    MultiReqBuffer *mrb)
+{
+    uint32_t type;
+
+    if (req->elem.out_num < 1 || req->elem.in_num < 1) {
+        error_report("virtio-blk missing headers");
+        exit(1);
+    }
+
+    if (req->elem.out_sg[0].iov_len < sizeof(*req->out) ||
+        req->elem.in_sg[req->elem.in_num - 1].iov_len < sizeof(*req->in)) {
+        error_report("virtio-blk header not in correct element");
+        exit(1);
+    }
+
+    req->out = (void *)req->elem.out_sg[0].iov_base;
+    req->in = (void *)req->elem.in_sg[req->elem.in_num - 1].iov_base;
+
+    type = ldl_p(&req->out->type);
+
+    if (type & VIRTIO_BLK_T_FLUSH) {
+        virtio_blk_handle_flush(req, mrb);
+    } else if (type & VIRTIO_BLK_T_SCSI_CMD) {
+        virtio_blk_handle_scsi(req);
+    } else if (type & VIRTIO_BLK_T_GET_ID) {
+        VirtIOBlock *s = req->dev;
+
+        /*
+         * NB: per existing s/n string convention the string is
+         * terminated by '\0' only when shorter than buffer.
+         */
+        strncpy(req->elem.in_sg[0].iov_base,
+                s->blk.serial ? s->blk.serial : "",
+                MIN(req->elem.in_sg[0].iov_len, VIRTIO_BLK_ID_BYTES));
+        virtio_blk_req_complete(req, VIRTIO_BLK_S_OK);
+        g_free(req);
+    } else if (type & VIRTIO_BLK_T_OUT) {
+        qemu_iovec_init_external(&req->qiov, &req->elem.out_sg[1],
+                                 req->elem.out_num - 1);
+        virtio_blk_handle_write(req, mrb);
+    } else if (type == VIRTIO_BLK_T_IN || type == VIRTIO_BLK_T_BARRIER) {
+        /* VIRTIO_BLK_T_IN is 0, so we can't just & it. */
+        qemu_iovec_init_external(&req->qiov, &req->elem.in_sg[0],
+                                 req->elem.in_num - 1);
+        virtio_blk_handle_read(req);
+    } else {
+        virtio_blk_req_complete(req, VIRTIO_BLK_S_UNSUPP);
+        g_free(req);
+    }
+}
+
+static void virtio_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq)
+{
+    VirtIOBlock *s = VIRTIO_BLK(vdev);
+    VirtIOBlockReq *req;
+    MultiReqBuffer mrb = {
+        .num_writes = 0,
+    };
+
+#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE
+    /* Some guests kick before setting VIRTIO_CONFIG_S_DRIVER_OK so start
+     * dataplane here instead of waiting for .set_status().
+     */
+    if (s->dataplane) {
+        virtio_blk_data_plane_start(s->dataplane);
+        return;
+    }
+#endif
+
+    while ((req = virtio_blk_get_request(s))) {
+        virtio_blk_handle_request(req, &mrb);
+    }
+
+    virtio_submit_multiwrite(s->bs, &mrb);
+
+    /*
+     * FIXME: Want to check for completions before returning to guest mode,
+     * so cached reads and writes are reported as quickly as possible. But
+     * that should be done in the generic block layer.
+     */
+}
+
+static void virtio_blk_dma_restart_bh(void *opaque)
+{
+    VirtIOBlock *s = opaque;
+    VirtIOBlockReq *req = s->rq;
+    MultiReqBuffer mrb = {
+        .num_writes = 0,
+    };
+
+    qemu_bh_delete(s->bh);
+    s->bh = NULL;
+
+    s->rq = NULL;
+
+    while (req) {
+        virtio_blk_handle_request(req, &mrb);
+        req = req->next;
+    }
+
+    virtio_submit_multiwrite(s->bs, &mrb);
+}
+
+static void virtio_blk_dma_restart_cb(void *opaque, int running,
+                                      RunState state)
+{
+    VirtIOBlock *s = opaque;
+
+    if (!running) {
+        return;
+    }
+
+    if (!s->bh) {
+        s->bh = qemu_bh_new(virtio_blk_dma_restart_bh, s);
+        qemu_bh_schedule(s->bh);
+    }
+}
+
+static void virtio_blk_reset(VirtIODevice *vdev)
+{
+#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE
+    VirtIOBlock *s = VIRTIO_BLK(vdev);
+
+    if (s->dataplane) {
+        virtio_blk_data_plane_stop(s->dataplane);
+    }
+#endif
+
+    /*
+     * This should cancel pending requests, but can't do nicely until there
+     * are per-device request lists.
+     */
+    bdrv_drain_all();
+}
+
+/* coalesce internal state, copy to pci i/o region 0
+ */
+static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config)
+{
+    VirtIOBlock *s = VIRTIO_BLK(vdev);
+    struct virtio_blk_config blkcfg;
+    uint64_t capacity;
+    int blk_size = s->conf->logical_block_size;
+
+    bdrv_get_geometry(s->bs, &capacity);
+    memset(&blkcfg, 0, sizeof(blkcfg));
+    stq_raw(&blkcfg.capacity, capacity);
+    stl_raw(&blkcfg.seg_max, 128 - 2);
+    stw_raw(&blkcfg.cylinders, s->conf->cyls);
+    stl_raw(&blkcfg.blk_size, blk_size);
+    stw_raw(&blkcfg.min_io_size, s->conf->min_io_size / blk_size);
+    stw_raw(&blkcfg.opt_io_size, s->conf->opt_io_size / blk_size);
+    blkcfg.heads = s->conf->heads;
+    /*
+     * We must ensure that the block device capacity is a multiple of
+     * the logical block size. If that is not the case, lets use
+     * sector_mask to adopt the geometry to have a correct picture.
+     * For those devices where the capacity is ok for the given geometry
+     * we dont touch the sector value of the geometry, since some devices
+     * (like s390 dasd) need a specific value. Here the capacity is already
+     * cyls*heads*secs*blk_size and the sector value is not block size
+     * divided by 512 - instead it is the amount of blk_size blocks
+     * per track (cylinder).
+     */
+    if (bdrv_getlength(s->bs) /  s->conf->heads / s->conf->secs % blk_size) {
+        blkcfg.sectors = s->conf->secs & ~s->sector_mask;
+    } else {
+        blkcfg.sectors = s->conf->secs;
+    }
+    blkcfg.size_max = 0;
+    blkcfg.physical_block_exp = get_physical_block_exp(s->conf);
+    blkcfg.alignment_offset = 0;
+    blkcfg.wce = bdrv_enable_write_cache(s->bs);
+    memcpy(config, &blkcfg, sizeof(struct virtio_blk_config));
+}
+
+static void virtio_blk_set_config(VirtIODevice *vdev, const uint8_t *config)
+{
+    VirtIOBlock *s = VIRTIO_BLK(vdev);
+    struct virtio_blk_config blkcfg;
+
+    memcpy(&blkcfg, config, sizeof(blkcfg));
+    bdrv_set_enable_write_cache(s->bs, blkcfg.wce != 0);
+}
+
+static uint32_t virtio_blk_get_features(VirtIODevice *vdev, uint32_t features)
+{
+    VirtIOBlock *s = VIRTIO_BLK(vdev);
+
+    features |= (1 << VIRTIO_BLK_F_SEG_MAX);
+    features |= (1 << VIRTIO_BLK_F_GEOMETRY);
+    features |= (1 << VIRTIO_BLK_F_TOPOLOGY);
+    features |= (1 << VIRTIO_BLK_F_BLK_SIZE);
+    features |= (1 << VIRTIO_BLK_F_SCSI);
+
+    if (s->blk.config_wce) {
+        features |= (1 << VIRTIO_BLK_F_CONFIG_WCE);
+    }
+    if (bdrv_enable_write_cache(s->bs))
+        features |= (1 << VIRTIO_BLK_F_WCE);
+
+    if (bdrv_is_read_only(s->bs))
+        features |= 1 << VIRTIO_BLK_F_RO;
+
+    return features;
+}
+
+static void virtio_blk_set_status(VirtIODevice *vdev, uint8_t status)
+{
+    VirtIOBlock *s = VIRTIO_BLK(vdev);
+    uint32_t features;
+
+#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE
+    if (s->dataplane && !(status & (VIRTIO_CONFIG_S_DRIVER |
+                                    VIRTIO_CONFIG_S_DRIVER_OK))) {
+        virtio_blk_data_plane_stop(s->dataplane);
+    }
+#endif
+
+    if (!(status & VIRTIO_CONFIG_S_DRIVER_OK)) {
+        return;
+    }
+
+    features = vdev->guest_features;
+    bdrv_set_enable_write_cache(s->bs, !!(features & (1 << VIRTIO_BLK_F_WCE)));
+}
+
+static void virtio_blk_save(QEMUFile *f, void *opaque)
+{
+    VirtIOBlock *s = opaque;
+    VirtIODevice *vdev = VIRTIO_DEVICE(s);
+    VirtIOBlockReq *req = s->rq;
+
+    virtio_save(vdev, f);
+    
+    while (req) {
+        qemu_put_sbyte(f, 1);
+        qemu_put_buffer(f, (unsigned char*)&req->elem, sizeof(req->elem));
+        req = req->next;
+    }
+    qemu_put_sbyte(f, 0);
+}
+
+static int virtio_blk_load(QEMUFile *f, void *opaque, int version_id)
+{
+    VirtIOBlock *s = opaque;
+    VirtIODevice *vdev = VIRTIO_DEVICE(s);
+    int ret;
+
+    if (version_id != 2)
+        return -EINVAL;
+
+    ret = virtio_load(vdev, f);
+    if (ret) {
+        return ret;
+    }
+
+    while (qemu_get_sbyte(f)) {
+        VirtIOBlockReq *req = virtio_blk_alloc_request(s);
+        qemu_get_buffer(f, (unsigned char*)&req->elem, sizeof(req->elem));
+        req->next = s->rq;
+        s->rq = req;
+
+        virtqueue_map_sg(req->elem.in_sg, req->elem.in_addr,
+            req->elem.in_num, 1);
+        virtqueue_map_sg(req->elem.out_sg, req->elem.out_addr,
+            req->elem.out_num, 0);
+    }
+
+    return 0;
+}
+
+static void virtio_blk_resize(void *opaque)
+{
+    VirtIODevice *vdev = VIRTIO_DEVICE(opaque);
+
+    virtio_notify_config(vdev);
+}
+
+static const BlockDevOps virtio_block_ops = {
+    .resize_cb = virtio_blk_resize,
+};
+
+void virtio_blk_set_conf(DeviceState *dev, VirtIOBlkConf *blk)
+{
+    VirtIOBlock *s = VIRTIO_BLK(dev);
+    memcpy(&(s->blk), blk, sizeof(struct VirtIOBlkConf));
+}
+
+static int virtio_blk_device_init(VirtIODevice *vdev)
+{
+    DeviceState *qdev = DEVICE(vdev);
+    VirtIOBlock *s = VIRTIO_BLK(vdev);
+    VirtIOBlkConf *blk = &(s->blk);
+    static int virtio_blk_id;
+
+    if (!blk->conf.bs) {
+        error_report("drive property not set");
+        return -1;
+    }
+    if (!bdrv_is_inserted(blk->conf.bs)) {
+        error_report("Device needs media, but drive is empty");
+        return -1;
+    }
+
+    blkconf_serial(&blk->conf, &blk->serial);
+    if (blkconf_geometry(&blk->conf, NULL, 65535, 255, 255) < 0) {
+        return -1;
+    }
+
+    virtio_init(vdev, "virtio-blk", VIRTIO_ID_BLOCK,
+                sizeof(struct virtio_blk_config));
+
+    vdev->get_config = virtio_blk_update_config;
+    vdev->set_config = virtio_blk_set_config;
+    vdev->get_features = virtio_blk_get_features;
+    vdev->set_status = virtio_blk_set_status;
+    vdev->reset = virtio_blk_reset;
+    s->bs = blk->conf.bs;
+    s->conf = &blk->conf;
+    memcpy(&(s->blk), blk, sizeof(struct VirtIOBlkConf));
+    s->rq = NULL;
+    s->sector_mask = (s->conf->logical_block_size / BDRV_SECTOR_SIZE) - 1;
+
+    s->vq = virtio_add_queue(vdev, 128, virtio_blk_handle_output);
+#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE
+    if (!virtio_blk_data_plane_create(vdev, blk, &s->dataplane)) {
+        virtio_common_cleanup(vdev);
+        return -1;
+    }
+#endif
+
+    s->change = qemu_add_vm_change_state_handler(virtio_blk_dma_restart_cb, s);
+    register_savevm(qdev, "virtio-blk", virtio_blk_id++, 2,
+                    virtio_blk_save, virtio_blk_load, s);
+    bdrv_set_dev_ops(s->bs, &virtio_block_ops, s);
+    bdrv_set_buffer_alignment(s->bs, s->conf->logical_block_size);
+
+    bdrv_iostatus_enable(s->bs);
+
+    add_boot_device_path(s->conf->bootindex, qdev, "/disk@0,0");
+    return 0;
+}
+
+static int virtio_blk_device_exit(DeviceState *dev)
+{
+    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+    VirtIOBlock *s = VIRTIO_BLK(dev);
+#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE
+    virtio_blk_data_plane_destroy(s->dataplane);
+    s->dataplane = NULL;
+#endif
+    qemu_del_vm_change_state_handler(s->change);
+    unregister_savevm(dev, "virtio-blk", s);
+    blockdev_mark_auto_del(s->bs);
+    virtio_common_cleanup(vdev);
+    return 0;
+}
+
+static Property virtio_blk_properties[] = {
+    DEFINE_VIRTIO_BLK_PROPERTIES(VirtIOBlock, blk),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void virtio_blk_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
+    dc->exit = virtio_blk_device_exit;
+    dc->props = virtio_blk_properties;
+    vdc->init = virtio_blk_device_init;
+    vdc->get_config = virtio_blk_update_config;
+    vdc->set_config = virtio_blk_set_config;
+    vdc->get_features = virtio_blk_get_features;
+    vdc->set_status = virtio_blk_set_status;
+    vdc->reset = virtio_blk_reset;
+}
+
+static const TypeInfo virtio_device_info = {
+    .name = TYPE_VIRTIO_BLK,
+    .parent = TYPE_VIRTIO_DEVICE,
+    .instance_size = sizeof(VirtIOBlock),
+    .class_init = virtio_blk_class_init,
+};
+
+static void virtio_register_types(void)
+{
+    type_register_static(&virtio_device_info);
+}
+
+type_init(virtio_register_types)
diff --git a/hw/block/xen_blkif.h b/hw/block/xen_blkif.h
new file mode 100644 (file)
index 0000000..c0f4136
--- /dev/null
@@ -0,0 +1,103 @@
+#ifndef __XEN_BLKIF_H__
+#define __XEN_BLKIF_H__
+
+#include <xen/io/ring.h>
+#include <xen/io/blkif.h>
+#include <xen/io/protocols.h>
+
+/* Not a real protocol.  Used to generate ring structs which contain
+ * the elements common to all protocols only.  This way we get a
+ * compiler-checkable way to use common struct elements, so we can
+ * avoid using switch(protocol) in a number of places.  */
+struct blkif_common_request {
+       char dummy;
+};
+struct blkif_common_response {
+       char dummy;
+};
+
+/* i386 protocol version */
+#pragma pack(push, 4)
+struct blkif_x86_32_request {
+       uint8_t        operation;    /* BLKIF_OP_???                         */
+       uint8_t        nr_segments;  /* number of segments                   */
+       blkif_vdev_t   handle;       /* only for read/write requests         */
+       uint64_t       id;           /* private guest value, echoed in resp  */
+       blkif_sector_t sector_number;/* start sector idx on disk (r/w only)  */
+       struct blkif_request_segment seg[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+};
+struct blkif_x86_32_response {
+       uint64_t        id;              /* copied from request */
+       uint8_t         operation;       /* copied from request */
+       int16_t         status;          /* BLKIF_RSP_???       */
+};
+typedef struct blkif_x86_32_request blkif_x86_32_request_t;
+typedef struct blkif_x86_32_response blkif_x86_32_response_t;
+#pragma pack(pop)
+
+/* x86_64 protocol version */
+struct blkif_x86_64_request {
+       uint8_t        operation;    /* BLKIF_OP_???                         */
+       uint8_t        nr_segments;  /* number of segments                   */
+       blkif_vdev_t   handle;       /* only for read/write requests         */
+       uint64_t       __attribute__((__aligned__(8))) id;
+       blkif_sector_t sector_number;/* start sector idx on disk (r/w only)  */
+       struct blkif_request_segment seg[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+};
+struct blkif_x86_64_response {
+       uint64_t       __attribute__((__aligned__(8))) id;
+       uint8_t         operation;       /* copied from request */
+       int16_t         status;          /* BLKIF_RSP_???       */
+};
+typedef struct blkif_x86_64_request blkif_x86_64_request_t;
+typedef struct blkif_x86_64_response blkif_x86_64_response_t;
+
+DEFINE_RING_TYPES(blkif_common, struct blkif_common_request, struct blkif_common_response);
+DEFINE_RING_TYPES(blkif_x86_32, struct blkif_x86_32_request, struct blkif_x86_32_response);
+DEFINE_RING_TYPES(blkif_x86_64, struct blkif_x86_64_request, struct blkif_x86_64_response);
+
+union blkif_back_rings {
+       blkif_back_ring_t        native;
+       blkif_common_back_ring_t common;
+        blkif_x86_32_back_ring_t x86_32_part;
+        blkif_x86_64_back_ring_t x86_64_part;
+};
+typedef union blkif_back_rings blkif_back_rings_t;
+
+enum blkif_protocol {
+       BLKIF_PROTOCOL_NATIVE = 1,
+       BLKIF_PROTOCOL_X86_32 = 2,
+       BLKIF_PROTOCOL_X86_64 = 3,
+};
+
+static inline void blkif_get_x86_32_req(blkif_request_t *dst, blkif_x86_32_request_t *src)
+{
+       int i, n = BLKIF_MAX_SEGMENTS_PER_REQUEST;
+
+       dst->operation = src->operation;
+       dst->nr_segments = src->nr_segments;
+       dst->handle = src->handle;
+       dst->id = src->id;
+       dst->sector_number = src->sector_number;
+       if (n > src->nr_segments)
+               n = src->nr_segments;
+       for (i = 0; i < n; i++)
+               dst->seg[i] = src->seg[i];
+}
+
+static inline void blkif_get_x86_64_req(blkif_request_t *dst, blkif_x86_64_request_t *src)
+{
+       int i, n = BLKIF_MAX_SEGMENTS_PER_REQUEST;
+
+       dst->operation = src->operation;
+       dst->nr_segments = src->nr_segments;
+       dst->handle = src->handle;
+       dst->id = src->id;
+       dst->sector_number = src->sector_number;
+       if (n > src->nr_segments)
+               n = src->nr_segments;
+       for (i = 0; i < n; i++)
+               dst->seg[i] = src->seg[i];
+}
+
+#endif /* __XEN_BLKIF_H__ */
diff --git a/hw/block/xen_disk.c b/hw/block/xen_disk.c
new file mode 100644 (file)
index 0000000..0ac65d4
--- /dev/null
@@ -0,0 +1,972 @@
+/*
+ *  xen paravirt block device backend
+ *
+ *  (c) Gerd Hoffmann <kraxel@redhat.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; under version 2 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
+ *  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/>.
+ *
+ *  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>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+#include <inttypes.h>
+#include <time.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/uio.h>
+
+#include "hw/hw.h"
+#include "hw/xen/xen_backend.h"
+#include "xen_blkif.h"
+#include "sysemu/blockdev.h"
+
+/* ------------------------------------------------------------- */
+
+static int batch_maps   = 0;
+
+static int max_requests = 32;
+
+/* ------------------------------------------------------------- */
+
+#define BLOCK_SIZE  512
+#define IOCB_COUNT  (BLKIF_MAX_SEGMENTS_PER_REQUEST + 2)
+
+struct PersistentGrant {
+    void *page;
+    struct XenBlkDev *blkdev;
+};
+
+typedef struct PersistentGrant PersistentGrant;
+
+struct ioreq {
+    blkif_request_t     req;
+    int16_t             status;
+
+    /* parsed request */
+    off_t               start;
+    QEMUIOVector        v;
+    int                 presync;
+    int                 postsync;
+    uint8_t             mapped;
+
+    /* grant mapping */
+    uint32_t            domids[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+    uint32_t            refs[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+    int                 prot;
+    void                *page[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+    void                *pages;
+    int                 num_unmap;
+
+    /* aio status */
+    int                 aio_inflight;
+    int                 aio_errors;
+
+    struct XenBlkDev    *blkdev;
+    QLIST_ENTRY(ioreq)   list;
+    BlockAcctCookie     acct;
+};
+
+struct XenBlkDev {
+    struct XenDevice    xendev;  /* must be first */
+    char                *params;
+    char                *mode;
+    char                *type;
+    char                *dev;
+    char                *devtype;
+    const char          *fileproto;
+    const char          *filename;
+    int                 ring_ref;
+    void                *sring;
+    int64_t             file_blk;
+    int64_t             file_size;
+    int                 protocol;
+    blkif_back_rings_t  rings;
+    int                 more_work;
+    int                 cnt_map;
+
+    /* request lists */
+    QLIST_HEAD(inflight_head, ioreq) inflight;
+    QLIST_HEAD(finished_head, ioreq) finished;
+    QLIST_HEAD(freelist_head, ioreq) freelist;
+    int                 requests_total;
+    int                 requests_inflight;
+    int                 requests_finished;
+
+    /* Persistent grants extension */
+    gboolean            feature_persistent;
+    GTree               *persistent_gnts;
+    unsigned int        persistent_gnt_count;
+    unsigned int        max_grants;
+
+    /* qemu block driver */
+    DriveInfo           *dinfo;
+    BlockDriverState    *bs;
+    QEMUBH              *bh;
+};
+
+/* ------------------------------------------------------------- */
+
+static void ioreq_reset(struct ioreq *ioreq)
+{
+    memset(&ioreq->req, 0, sizeof(ioreq->req));
+    ioreq->status = 0;
+    ioreq->start = 0;
+    ioreq->presync = 0;
+    ioreq->postsync = 0;
+    ioreq->mapped = 0;
+
+    memset(ioreq->domids, 0, sizeof(ioreq->domids));
+    memset(ioreq->refs, 0, sizeof(ioreq->refs));
+    ioreq->prot = 0;
+    memset(ioreq->page, 0, sizeof(ioreq->page));
+    ioreq->pages = NULL;
+
+    ioreq->aio_inflight = 0;
+    ioreq->aio_errors = 0;
+
+    ioreq->blkdev = NULL;
+    memset(&ioreq->list, 0, sizeof(ioreq->list));
+    memset(&ioreq->acct, 0, sizeof(ioreq->acct));
+
+    qemu_iovec_reset(&ioreq->v);
+}
+
+static gint int_cmp(gconstpointer a, gconstpointer b, gpointer user_data)
+{
+    uint ua = GPOINTER_TO_UINT(a);
+    uint ub = GPOINTER_TO_UINT(b);
+    return (ua > ub) - (ua < ub);
+}
+
+static void destroy_grant(gpointer pgnt)
+{
+    PersistentGrant *grant = pgnt;
+    XenGnttab gnt = grant->blkdev->xendev.gnttabdev;
+
+    if (xc_gnttab_munmap(gnt, grant->page, 1) != 0) {
+        xen_be_printf(&grant->blkdev->xendev, 0,
+                      "xc_gnttab_munmap failed: %s\n",
+                      strerror(errno));
+    }
+    grant->blkdev->persistent_gnt_count--;
+    xen_be_printf(&grant->blkdev->xendev, 3,
+                  "unmapped grant %p\n", grant->page);
+    g_free(grant);
+}
+
+static struct ioreq *ioreq_start(struct XenBlkDev *blkdev)
+{
+    struct ioreq *ioreq = NULL;
+
+    if (QLIST_EMPTY(&blkdev->freelist)) {
+        if (blkdev->requests_total >= max_requests) {
+            goto out;
+        }
+        /* allocate new struct */
+        ioreq = g_malloc0(sizeof(*ioreq));
+        ioreq->blkdev = blkdev;
+        blkdev->requests_total++;
+        qemu_iovec_init(&ioreq->v, BLKIF_MAX_SEGMENTS_PER_REQUEST);
+    } else {
+        /* get one from freelist */
+        ioreq = QLIST_FIRST(&blkdev->freelist);
+        QLIST_REMOVE(ioreq, list);
+    }
+    QLIST_INSERT_HEAD(&blkdev->inflight, ioreq, list);
+    blkdev->requests_inflight++;
+
+out:
+    return ioreq;
+}
+
+static void ioreq_finish(struct ioreq *ioreq)
+{
+    struct XenBlkDev *blkdev = ioreq->blkdev;
+
+    QLIST_REMOVE(ioreq, list);
+    QLIST_INSERT_HEAD(&blkdev->finished, ioreq, list);
+    blkdev->requests_inflight--;
+    blkdev->requests_finished++;
+}
+
+static void ioreq_release(struct ioreq *ioreq, bool finish)
+{
+    struct XenBlkDev *blkdev = ioreq->blkdev;
+
+    QLIST_REMOVE(ioreq, list);
+    ioreq_reset(ioreq);
+    ioreq->blkdev = blkdev;
+    QLIST_INSERT_HEAD(&blkdev->freelist, ioreq, list);
+    if (finish) {
+        blkdev->requests_finished--;
+    } else {
+        blkdev->requests_inflight--;
+    }
+}
+
+/*
+ * translate request into iovec + start offset
+ * do sanity checks along the way
+ */
+static int ioreq_parse(struct ioreq *ioreq)
+{
+    struct XenBlkDev *blkdev = ioreq->blkdev;
+    uintptr_t mem;
+    size_t len;
+    int i;
+
+    xen_be_printf(&blkdev->xendev, 3,
+                  "op %d, nr %d, handle %d, id %" PRId64 ", sector %" PRId64 "\n",
+                  ioreq->req.operation, ioreq->req.nr_segments,
+                  ioreq->req.handle, ioreq->req.id, ioreq->req.sector_number);
+    switch (ioreq->req.operation) {
+    case BLKIF_OP_READ:
+        ioreq->prot = PROT_WRITE; /* to memory */
+        break;
+    case BLKIF_OP_FLUSH_DISKCACHE:
+        ioreq->presync = 1;
+        if (!ioreq->req.nr_segments) {
+            return 0;
+        }
+        /* fall through */
+    case BLKIF_OP_WRITE:
+        ioreq->prot = PROT_READ; /* from memory */
+        break;
+    default:
+        xen_be_printf(&blkdev->xendev, 0, "error: unknown operation (%d)\n",
+                      ioreq->req.operation);
+        goto err;
+    };
+
+    if (ioreq->req.operation != BLKIF_OP_READ && blkdev->mode[0] != 'w') {
+        xen_be_printf(&blkdev->xendev, 0, "error: write req for ro device\n");
+        goto err;
+    }
+
+    ioreq->start = ioreq->req.sector_number * blkdev->file_blk;
+    for (i = 0; i < ioreq->req.nr_segments; i++) {
+        if (i == BLKIF_MAX_SEGMENTS_PER_REQUEST) {
+            xen_be_printf(&blkdev->xendev, 0, "error: nr_segments too big\n");
+            goto err;
+        }
+        if (ioreq->req.seg[i].first_sect > ioreq->req.seg[i].last_sect) {
+            xen_be_printf(&blkdev->xendev, 0, "error: first > last sector\n");
+            goto err;
+        }
+        if (ioreq->req.seg[i].last_sect * BLOCK_SIZE >= XC_PAGE_SIZE) {
+            xen_be_printf(&blkdev->xendev, 0, "error: page crossing\n");
+            goto err;
+        }
+
+        ioreq->domids[i] = blkdev->xendev.dom;
+        ioreq->refs[i]   = ioreq->req.seg[i].gref;
+
+        mem = ioreq->req.seg[i].first_sect * blkdev->file_blk;
+        len = (ioreq->req.seg[i].last_sect - ioreq->req.seg[i].first_sect + 1) * blkdev->file_blk;
+        qemu_iovec_add(&ioreq->v, (void*)mem, len);
+    }
+    if (ioreq->start + ioreq->v.size > blkdev->file_size) {
+        xen_be_printf(&blkdev->xendev, 0, "error: access beyond end of file\n");
+        goto err;
+    }
+    return 0;
+
+err:
+    ioreq->status = BLKIF_RSP_ERROR;
+    return -1;
+}
+
+static void ioreq_unmap(struct ioreq *ioreq)
+{
+    XenGnttab gnt = ioreq->blkdev->xendev.gnttabdev;
+    int i;
+
+    if (ioreq->num_unmap == 0 || ioreq->mapped == 0) {
+        return;
+    }
+    if (batch_maps) {
+        if (!ioreq->pages) {
+            return;
+        }
+        if (xc_gnttab_munmap(gnt, ioreq->pages, ioreq->num_unmap) != 0) {
+            xen_be_printf(&ioreq->blkdev->xendev, 0, "xc_gnttab_munmap failed: %s\n",
+                          strerror(errno));
+        }
+        ioreq->blkdev->cnt_map -= ioreq->num_unmap;
+        ioreq->pages = NULL;
+    } else {
+        for (i = 0; i < ioreq->num_unmap; i++) {
+            if (!ioreq->page[i]) {
+                continue;
+            }
+            if (xc_gnttab_munmap(gnt, ioreq->page[i], 1) != 0) {
+                xen_be_printf(&ioreq->blkdev->xendev, 0, "xc_gnttab_munmap failed: %s\n",
+                              strerror(errno));
+            }
+            ioreq->blkdev->cnt_map--;
+            ioreq->page[i] = NULL;
+        }
+    }
+    ioreq->mapped = 0;
+}
+
+static int ioreq_map(struct ioreq *ioreq)
+{
+    XenGnttab gnt = ioreq->blkdev->xendev.gnttabdev;
+    uint32_t domids[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+    uint32_t refs[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+    void *page[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+    int i, j, new_maps = 0;
+    PersistentGrant *grant;
+    /* domids and refs variables will contain the information necessary
+     * to map the grants that are needed to fulfill this request.
+     *
+     * After mapping the needed grants, the page array will contain the
+     * memory address of each granted page in the order specified in ioreq
+     * (disregarding if it's a persistent grant or not).
+     */
+
+    if (ioreq->v.niov == 0 || ioreq->mapped == 1) {
+        return 0;
+    }
+    if (ioreq->blkdev->feature_persistent) {
+        for (i = 0; i < ioreq->v.niov; i++) {
+            grant = g_tree_lookup(ioreq->blkdev->persistent_gnts,
+                                    GUINT_TO_POINTER(ioreq->refs[i]));
+
+            if (grant != NULL) {
+                page[i] = grant->page;
+                xen_be_printf(&ioreq->blkdev->xendev, 3,
+                              "using persistent-grant %" PRIu32 "\n",
+                              ioreq->refs[i]);
+            } else {
+                    /* Add the grant to the list of grants that
+                     * should be mapped
+                     */
+                    domids[new_maps] = ioreq->domids[i];
+                    refs[new_maps] = ioreq->refs[i];
+                    page[i] = NULL;
+                    new_maps++;
+            }
+        }
+        /* Set the protection to RW, since grants may be reused later
+         * with a different protection than the one needed for this request
+         */
+        ioreq->prot = PROT_WRITE | PROT_READ;
+    } else {
+        /* All grants in the request should be mapped */
+        memcpy(refs, ioreq->refs, sizeof(refs));
+        memcpy(domids, ioreq->domids, sizeof(domids));
+        memset(page, 0, sizeof(page));
+        new_maps = ioreq->v.niov;
+    }
+
+    if (batch_maps && new_maps) {
+        ioreq->pages = xc_gnttab_map_grant_refs
+            (gnt, new_maps, domids, refs, ioreq->prot);
+        if (ioreq->pages == NULL) {
+            xen_be_printf(&ioreq->blkdev->xendev, 0,
+                          "can't map %d grant refs (%s, %d maps)\n",
+                          new_maps, strerror(errno), ioreq->blkdev->cnt_map);
+            return -1;
+        }
+        for (i = 0, j = 0; i < ioreq->v.niov; i++) {
+            if (page[i] == NULL) {
+                page[i] = ioreq->pages + (j++) * XC_PAGE_SIZE;
+            }
+        }
+        ioreq->blkdev->cnt_map += new_maps;
+    } else if (new_maps)  {
+        for (i = 0; i < new_maps; i++) {
+            ioreq->page[i] = xc_gnttab_map_grant_ref
+                (gnt, domids[i], refs[i], ioreq->prot);
+            if (ioreq->page[i] == NULL) {
+                xen_be_printf(&ioreq->blkdev->xendev, 0,
+                              "can't map grant ref %d (%s, %d maps)\n",
+                              refs[i], strerror(errno), ioreq->blkdev->cnt_map);
+                ioreq_unmap(ioreq);
+                return -1;
+            }
+            ioreq->blkdev->cnt_map++;
+        }
+        for (i = 0, j = 0; i < ioreq->v.niov; i++) {
+            if (page[i] == NULL) {
+                page[i] = ioreq->page[j++];
+            }
+        }
+    }
+    if (ioreq->blkdev->feature_persistent) {
+        while ((ioreq->blkdev->persistent_gnt_count < ioreq->blkdev->max_grants)
+              && new_maps) {
+            /* Go through the list of newly mapped grants and add as many
+             * as possible to the list of persistently mapped grants.
+             *
+             * Since we start at the end of ioreq->page(s), we only need
+             * to decrease new_maps to prevent this granted pages from
+             * being unmapped in ioreq_unmap.
+             */
+            grant = g_malloc0(sizeof(*grant));
+            new_maps--;
+            if (batch_maps) {
+                grant->page = ioreq->pages + (new_maps) * XC_PAGE_SIZE;
+            } else {
+                grant->page = ioreq->page[new_maps];
+            }
+            grant->blkdev = ioreq->blkdev;
+            xen_be_printf(&ioreq->blkdev->xendev, 3,
+                          "adding grant %" PRIu32 " page: %p\n",
+                          refs[new_maps], grant->page);
+            g_tree_insert(ioreq->blkdev->persistent_gnts,
+                          GUINT_TO_POINTER(refs[new_maps]),
+                          grant);
+            ioreq->blkdev->persistent_gnt_count++;
+        }
+    }
+    for (i = 0; i < ioreq->v.niov; i++) {
+        ioreq->v.iov[i].iov_base += (uintptr_t)page[i];
+    }
+    ioreq->mapped = 1;
+    ioreq->num_unmap = new_maps;
+    return 0;
+}
+
+static int ioreq_runio_qemu_aio(struct ioreq *ioreq);
+
+static void qemu_aio_complete(void *opaque, int ret)
+{
+    struct ioreq *ioreq = opaque;
+
+    if (ret != 0) {
+        xen_be_printf(&ioreq->blkdev->xendev, 0, "%s I/O error\n",
+                      ioreq->req.operation == BLKIF_OP_READ ? "read" : "write");
+        ioreq->aio_errors++;
+    }
+
+    ioreq->aio_inflight--;
+    if (ioreq->presync) {
+        ioreq->presync = 0;
+        ioreq_runio_qemu_aio(ioreq);
+        return;
+    }
+    if (ioreq->aio_inflight > 0) {
+        return;
+    }
+    if (ioreq->postsync) {
+        ioreq->postsync = 0;
+        ioreq->aio_inflight++;
+        bdrv_aio_flush(ioreq->blkdev->bs, qemu_aio_complete, ioreq);
+        return;
+    }
+
+    ioreq->status = ioreq->aio_errors ? BLKIF_RSP_ERROR : BLKIF_RSP_OKAY;
+    ioreq_unmap(ioreq);
+    ioreq_finish(ioreq);
+    bdrv_acct_done(ioreq->blkdev->bs, &ioreq->acct);
+    qemu_bh_schedule(ioreq->blkdev->bh);
+}
+
+static int ioreq_runio_qemu_aio(struct ioreq *ioreq)
+{
+    struct XenBlkDev *blkdev = ioreq->blkdev;
+
+    if (ioreq->req.nr_segments && ioreq_map(ioreq) == -1) {
+        goto err_no_map;
+    }
+
+    ioreq->aio_inflight++;
+    if (ioreq->presync) {
+        bdrv_aio_flush(ioreq->blkdev->bs, qemu_aio_complete, ioreq);
+        return 0;
+    }
+
+    switch (ioreq->req.operation) {
+    case BLKIF_OP_READ:
+        bdrv_acct_start(blkdev->bs, &ioreq->acct, ioreq->v.size, BDRV_ACCT_READ);
+        ioreq->aio_inflight++;
+        bdrv_aio_readv(blkdev->bs, ioreq->start / BLOCK_SIZE,
+                       &ioreq->v, ioreq->v.size / BLOCK_SIZE,
+                       qemu_aio_complete, ioreq);
+        break;
+    case BLKIF_OP_WRITE:
+    case BLKIF_OP_FLUSH_DISKCACHE:
+        if (!ioreq->req.nr_segments) {
+            break;
+        }
+
+        bdrv_acct_start(blkdev->bs, &ioreq->acct, ioreq->v.size, BDRV_ACCT_WRITE);
+        ioreq->aio_inflight++;
+        bdrv_aio_writev(blkdev->bs, ioreq->start / BLOCK_SIZE,
+                        &ioreq->v, ioreq->v.size / BLOCK_SIZE,
+                        qemu_aio_complete, ioreq);
+        break;
+    default:
+        /* unknown operation (shouldn't happen -- parse catches this) */
+        goto err;
+    }
+
+    qemu_aio_complete(ioreq, 0);
+
+    return 0;
+
+err:
+    ioreq_unmap(ioreq);
+err_no_map:
+    ioreq_finish(ioreq);
+    ioreq->status = BLKIF_RSP_ERROR;
+    return -1;
+}
+
+static int blk_send_response_one(struct ioreq *ioreq)
+{
+    struct XenBlkDev  *blkdev = ioreq->blkdev;
+    int               send_notify   = 0;
+    int               have_requests = 0;
+    blkif_response_t  resp;
+    void              *dst;
+
+    resp.id        = ioreq->req.id;
+    resp.operation = ioreq->req.operation;
+    resp.status    = ioreq->status;
+
+    /* Place on the response ring for the relevant domain. */
+    switch (blkdev->protocol) {
+    case BLKIF_PROTOCOL_NATIVE:
+        dst = RING_GET_RESPONSE(&blkdev->rings.native, blkdev->rings.native.rsp_prod_pvt);
+        break;
+    case BLKIF_PROTOCOL_X86_32:
+        dst = RING_GET_RESPONSE(&blkdev->rings.x86_32_part,
+                                blkdev->rings.x86_32_part.rsp_prod_pvt);
+        break;
+    case BLKIF_PROTOCOL_X86_64:
+        dst = RING_GET_RESPONSE(&blkdev->rings.x86_64_part,
+                                blkdev->rings.x86_64_part.rsp_prod_pvt);
+        break;
+    default:
+        dst = NULL;
+    }
+    memcpy(dst, &resp, sizeof(resp));
+    blkdev->rings.common.rsp_prod_pvt++;
+
+    RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&blkdev->rings.common, send_notify);
+    if (blkdev->rings.common.rsp_prod_pvt == blkdev->rings.common.req_cons) {
+        /*
+         * Tail check for pending requests. Allows frontend to avoid
+         * notifications if requests are already in flight (lower
+         * overheads and promotes batching).
+         */
+        RING_FINAL_CHECK_FOR_REQUESTS(&blkdev->rings.common, have_requests);
+    } else if (RING_HAS_UNCONSUMED_REQUESTS(&blkdev->rings.common)) {
+        have_requests = 1;
+    }
+
+    if (have_requests) {
+        blkdev->more_work++;
+    }
+    return send_notify;
+}
+
+/* walk finished list, send outstanding responses, free requests */
+static void blk_send_response_all(struct XenBlkDev *blkdev)
+{
+    struct ioreq *ioreq;
+    int send_notify = 0;
+
+    while (!QLIST_EMPTY(&blkdev->finished)) {
+        ioreq = QLIST_FIRST(&blkdev->finished);
+        send_notify += blk_send_response_one(ioreq);
+        ioreq_release(ioreq, true);
+    }
+    if (send_notify) {
+        xen_be_send_notify(&blkdev->xendev);
+    }
+}
+
+static int blk_get_request(struct XenBlkDev *blkdev, struct ioreq *ioreq, RING_IDX rc)
+{
+    switch (blkdev->protocol) {
+    case BLKIF_PROTOCOL_NATIVE:
+        memcpy(&ioreq->req, RING_GET_REQUEST(&blkdev->rings.native, rc),
+               sizeof(ioreq->req));
+        break;
+    case BLKIF_PROTOCOL_X86_32:
+        blkif_get_x86_32_req(&ioreq->req,
+                             RING_GET_REQUEST(&blkdev->rings.x86_32_part, rc));
+        break;
+    case BLKIF_PROTOCOL_X86_64:
+        blkif_get_x86_64_req(&ioreq->req,
+                             RING_GET_REQUEST(&blkdev->rings.x86_64_part, rc));
+        break;
+    }
+    return 0;
+}
+
+static void blk_handle_requests(struct XenBlkDev *blkdev)
+{
+    RING_IDX rc, rp;
+    struct ioreq *ioreq;
+
+    blkdev->more_work = 0;
+
+    rc = blkdev->rings.common.req_cons;
+    rp = blkdev->rings.common.sring->req_prod;
+    xen_rmb(); /* Ensure we see queued requests up to 'rp'. */
+
+    blk_send_response_all(blkdev);
+    while (rc != rp) {
+        /* pull request from ring */
+        if (RING_REQUEST_CONS_OVERFLOW(&blkdev->rings.common, rc)) {
+            break;
+        }
+        ioreq = ioreq_start(blkdev);
+        if (ioreq == NULL) {
+            blkdev->more_work++;
+            break;
+        }
+        blk_get_request(blkdev, ioreq, rc);
+        blkdev->rings.common.req_cons = ++rc;
+
+        /* parse them */
+        if (ioreq_parse(ioreq) != 0) {
+            if (blk_send_response_one(ioreq)) {
+                xen_be_send_notify(&blkdev->xendev);
+            }
+            ioreq_release(ioreq, false);
+            continue;
+        }
+
+        ioreq_runio_qemu_aio(ioreq);
+    }
+
+    if (blkdev->more_work && blkdev->requests_inflight < max_requests) {
+        qemu_bh_schedule(blkdev->bh);
+    }
+}
+
+/* ------------------------------------------------------------- */
+
+static void blk_bh(void *opaque)
+{
+    struct XenBlkDev *blkdev = opaque;
+    blk_handle_requests(blkdev);
+}
+
+/*
+ * We need to account for the grant allocations requiring contiguous
+ * chunks; the worst case number would be
+ *     max_req * max_seg + (max_req - 1) * (max_seg - 1) + 1,
+ * but in order to keep things simple just use
+ *     2 * max_req * max_seg.
+ */
+#define MAX_GRANTS(max_req, max_seg) (2 * (max_req) * (max_seg))
+
+static void blk_alloc(struct XenDevice *xendev)
+{
+    struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
+
+    QLIST_INIT(&blkdev->inflight);
+    QLIST_INIT(&blkdev->finished);
+    QLIST_INIT(&blkdev->freelist);
+    blkdev->bh = qemu_bh_new(blk_bh, blkdev);
+    if (xen_mode != XEN_EMULATE) {
+        batch_maps = 1;
+    }
+    if (xc_gnttab_set_max_grants(xendev->gnttabdev,
+            MAX_GRANTS(max_requests, BLKIF_MAX_SEGMENTS_PER_REQUEST)) < 0) {
+        xen_be_printf(xendev, 0, "xc_gnttab_set_max_grants failed: %s\n",
+                      strerror(errno));
+    }
+}
+
+static int blk_init(struct XenDevice *xendev)
+{
+    struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
+    int info = 0;
+
+    /* read xenstore entries */
+    if (blkdev->params == NULL) {
+        char *h = NULL;
+        blkdev->params = xenstore_read_be_str(&blkdev->xendev, "params");
+        if (blkdev->params != NULL) {
+            h = strchr(blkdev->params, ':');
+        }
+        if (h != NULL) {
+            blkdev->fileproto = blkdev->params;
+            blkdev->filename  = h+1;
+            *h = 0;
+        } else {
+            blkdev->fileproto = "<unset>";
+            blkdev->filename  = blkdev->params;
+        }
+    }
+    if (!strcmp("aio", blkdev->fileproto)) {
+        blkdev->fileproto = "raw";
+    }
+    if (blkdev->mode == NULL) {
+        blkdev->mode = xenstore_read_be_str(&blkdev->xendev, "mode");
+    }
+    if (blkdev->type == NULL) {
+        blkdev->type = xenstore_read_be_str(&blkdev->xendev, "type");
+    }
+    if (blkdev->dev == NULL) {
+        blkdev->dev = xenstore_read_be_str(&blkdev->xendev, "dev");
+    }
+    if (blkdev->devtype == NULL) {
+        blkdev->devtype = xenstore_read_be_str(&blkdev->xendev, "device-type");
+    }
+
+    /* do we have all we need? */
+    if (blkdev->params == NULL ||
+        blkdev->mode == NULL   ||
+        blkdev->type == NULL   ||
+        blkdev->dev == NULL) {
+        goto out_error;
+    }
+
+    /* read-only ? */
+    if (strcmp(blkdev->mode, "w")) {
+        info  |= VDISK_READONLY;
+    }
+
+    /* cdrom ? */
+    if (blkdev->devtype && !strcmp(blkdev->devtype, "cdrom")) {
+        info  |= VDISK_CDROM;
+    }
+
+    blkdev->file_blk  = BLOCK_SIZE;
+
+    /* fill info
+     * blk_connect supplies sector-size and sectors
+     */
+    xenstore_write_be_int(&blkdev->xendev, "feature-flush-cache", 1);
+    xenstore_write_be_int(&blkdev->xendev, "feature-persistent", 1);
+    xenstore_write_be_int(&blkdev->xendev, "info", info);
+    return 0;
+
+out_error:
+    g_free(blkdev->params);
+    blkdev->params = NULL;
+    g_free(blkdev->mode);
+    blkdev->mode = NULL;
+    g_free(blkdev->type);
+    blkdev->type = NULL;
+    g_free(blkdev->dev);
+    blkdev->dev = NULL;
+    g_free(blkdev->devtype);
+    blkdev->devtype = NULL;
+    return -1;
+}
+
+static int blk_connect(struct XenDevice *xendev)
+{
+    struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
+    int pers, index, qflags;
+
+    /* read-only ? */
+    qflags = BDRV_O_CACHE_WB | BDRV_O_NATIVE_AIO;
+    if (strcmp(blkdev->mode, "w") == 0) {
+        qflags |= BDRV_O_RDWR;
+    }
+
+    /* init qemu block driver */
+    index = (blkdev->xendev.dev - 202 * 256) / 16;
+    blkdev->dinfo = drive_get(IF_XEN, 0, index);
+    if (!blkdev->dinfo) {
+        /* setup via xenbus -> create new block driver instance */
+        xen_be_printf(&blkdev->xendev, 2, "create new bdrv (xenbus setup)\n");
+        blkdev->bs = bdrv_new(blkdev->dev);
+        if (blkdev->bs) {
+            if (bdrv_open(blkdev->bs, blkdev->filename, NULL, qflags,
+                        bdrv_find_whitelisted_format(blkdev->fileproto)) != 0) {
+                bdrv_delete(blkdev->bs);
+                blkdev->bs = NULL;
+            }
+        }
+        if (!blkdev->bs) {
+            return -1;
+        }
+    } else {
+        /* setup via qemu cmdline -> already setup for us */
+        xen_be_printf(&blkdev->xendev, 2, "get configured bdrv (cmdline setup)\n");
+        blkdev->bs = blkdev->dinfo->bdrv;
+    }
+    bdrv_attach_dev_nofail(blkdev->bs, blkdev);
+    blkdev->file_size = bdrv_getlength(blkdev->bs);
+    if (blkdev->file_size < 0) {
+        xen_be_printf(&blkdev->xendev, 1, "bdrv_getlength: %d (%s) | drv %s\n",
+                      (int)blkdev->file_size, strerror(-blkdev->file_size),
+                      bdrv_get_format_name(blkdev->bs) ?: "-");
+        blkdev->file_size = 0;
+    }
+
+    xen_be_printf(xendev, 1, "type \"%s\", fileproto \"%s\", filename \"%s\","
+                  " size %" PRId64 " (%" PRId64 " MB)\n",
+                  blkdev->type, blkdev->fileproto, blkdev->filename,
+                  blkdev->file_size, blkdev->file_size >> 20);
+
+    /* Fill in number of sector size and number of sectors */
+    xenstore_write_be_int(&blkdev->xendev, "sector-size", blkdev->file_blk);
+    xenstore_write_be_int64(&blkdev->xendev, "sectors",
+                            blkdev->file_size / blkdev->file_blk);
+
+    if (xenstore_read_fe_int(&blkdev->xendev, "ring-ref", &blkdev->ring_ref) == -1) {
+        return -1;
+    }
+    if (xenstore_read_fe_int(&blkdev->xendev, "event-channel",
+                             &blkdev->xendev.remote_port) == -1) {
+        return -1;
+    }
+    if (xenstore_read_fe_int(&blkdev->xendev, "feature-persistent", &pers)) {
+        blkdev->feature_persistent = FALSE;
+    } else {
+        blkdev->feature_persistent = !!pers;
+    }
+
+    blkdev->protocol = BLKIF_PROTOCOL_NATIVE;
+    if (blkdev->xendev.protocol) {
+        if (strcmp(blkdev->xendev.protocol, XEN_IO_PROTO_ABI_X86_32) == 0) {
+            blkdev->protocol = BLKIF_PROTOCOL_X86_32;
+        }
+        if (strcmp(blkdev->xendev.protocol, XEN_IO_PROTO_ABI_X86_64) == 0) {
+            blkdev->protocol = BLKIF_PROTOCOL_X86_64;
+        }
+    }
+
+    blkdev->sring = xc_gnttab_map_grant_ref(blkdev->xendev.gnttabdev,
+                                            blkdev->xendev.dom,
+                                            blkdev->ring_ref,
+                                            PROT_READ | PROT_WRITE);
+    if (!blkdev->sring) {
+        return -1;
+    }
+    blkdev->cnt_map++;
+
+    switch (blkdev->protocol) {
+    case BLKIF_PROTOCOL_NATIVE:
+    {
+        blkif_sring_t *sring_native = blkdev->sring;
+        BACK_RING_INIT(&blkdev->rings.native, sring_native, XC_PAGE_SIZE);
+        break;
+    }
+    case BLKIF_PROTOCOL_X86_32:
+    {
+        blkif_x86_32_sring_t *sring_x86_32 = blkdev->sring;
+
+        BACK_RING_INIT(&blkdev->rings.x86_32_part, sring_x86_32, XC_PAGE_SIZE);
+        break;
+    }
+    case BLKIF_PROTOCOL_X86_64:
+    {
+        blkif_x86_64_sring_t *sring_x86_64 = blkdev->sring;
+
+        BACK_RING_INIT(&blkdev->rings.x86_64_part, sring_x86_64, XC_PAGE_SIZE);
+        break;
+    }
+    }
+
+    if (blkdev->feature_persistent) {
+        /* Init persistent grants */
+        blkdev->max_grants = max_requests * BLKIF_MAX_SEGMENTS_PER_REQUEST;
+        blkdev->persistent_gnts = g_tree_new_full((GCompareDataFunc)int_cmp,
+                                             NULL, NULL,
+                                             (GDestroyNotify)destroy_grant);
+        blkdev->persistent_gnt_count = 0;
+    }
+
+    xen_be_bind_evtchn(&blkdev->xendev);
+
+    xen_be_printf(&blkdev->xendev, 1, "ok: proto %s, ring-ref %d, "
+                  "remote port %d, local port %d\n",
+                  blkdev->xendev.protocol, blkdev->ring_ref,
+                  blkdev->xendev.remote_port, blkdev->xendev.local_port);
+    return 0;
+}
+
+static void blk_disconnect(struct XenDevice *xendev)
+{
+    struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
+
+    if (blkdev->bs) {
+        if (!blkdev->dinfo) {
+            /* close/delete only if we created it ourself */
+            bdrv_close(blkdev->bs);
+            bdrv_detach_dev(blkdev->bs, blkdev);
+            bdrv_delete(blkdev->bs);
+        }
+        blkdev->bs = NULL;
+    }
+    xen_be_unbind_evtchn(&blkdev->xendev);
+
+    if (blkdev->sring) {
+        xc_gnttab_munmap(blkdev->xendev.gnttabdev, blkdev->sring, 1);
+        blkdev->cnt_map--;
+        blkdev->sring = NULL;
+    }
+}
+
+static int blk_free(struct XenDevice *xendev)
+{
+    struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
+    struct ioreq *ioreq;
+
+    if (blkdev->bs || blkdev->sring) {
+        blk_disconnect(xendev);
+    }
+
+    /* Free persistent grants */
+    if (blkdev->feature_persistent) {
+        g_tree_destroy(blkdev->persistent_gnts);
+    }
+
+    while (!QLIST_EMPTY(&blkdev->freelist)) {
+        ioreq = QLIST_FIRST(&blkdev->freelist);
+        QLIST_REMOVE(ioreq, list);
+        qemu_iovec_destroy(&ioreq->v);
+        g_free(ioreq);
+    }
+
+    g_free(blkdev->params);
+    g_free(blkdev->mode);
+    g_free(blkdev->type);
+    g_free(blkdev->dev);
+    g_free(blkdev->devtype);
+    qemu_bh_delete(blkdev->bh);
+    return 0;
+}
+
+static void blk_event(struct XenDevice *xendev)
+{
+    struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
+
+    qemu_bh_schedule(blkdev->bh);
+}
+
+struct XenDevOps xen_blkdev_ops = {
+    .size       = sizeof(struct XenBlkDev),
+    .flags      = DEVOPS_FLAG_NEED_GNTDEV,
+    .alloc      = blk_alloc,
+    .init       = blk_init,
+    .initialise    = blk_connect,
+    .disconnect = blk_disconnect,
+    .event      = blk_event,
+    .free       = blk_free,
+};
diff --git a/hw/boards.h b/hw/boards.h
deleted file mode 100644 (file)
index 425bdc7..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/* Declarations for use by board files for creating devices.  */
-
-#ifndef HW_BOARDS_H
-#define HW_BOARDS_H
-
-#include "sysemu/blockdev.h"
-#include "hw/qdev.h"
-
-#define DEFAULT_MACHINE_OPTIONS \
-    .boot_order = "cad"
-
-typedef struct QEMUMachineInitArgs {
-    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;
-} QEMUMachineInitArgs;
-
-typedef void QEMUMachineInitFunc(QEMUMachineInitArgs *args);
-
-typedef void QEMUMachineResetFunc(void);
-
-typedef struct QEMUMachine {
-    const char *name;
-    const char *alias;
-    const char *desc;
-    QEMUMachineInitFunc *init;
-    QEMUMachineResetFunc *reset;
-    BlockInterfaceType block_default_type;
-    int max_cpus;
-    unsigned int no_serial:1,
-        no_parallel:1,
-        use_virtcon:1,
-        use_sclp:1,
-        no_floppy:1,
-        no_cdrom:1,
-        no_sdcard:1;
-    int is_default;
-    const char *default_machine_opts;
-    const char *boot_order;
-    GlobalProperty *compat_props;
-    struct QEMUMachine *next;
-    const char *hw_version;
-} QEMUMachine;
-
-int qemu_register_machine(QEMUMachine *m);
-QEMUMachine *find_default_machine(void);
-
-extern QEMUMachine *current_machine;
-
-#endif
diff --git a/hw/bonito.c b/hw/bonito.c
deleted file mode 100644 (file)
index e58655a..0000000
+++ /dev/null
@@ -1,847 +0,0 @@
-/*
- * bonito north bridge support
- *
- * Copyright (c) 2008 yajin (yajin@vm-kernel.org)
- * Copyright (c) 2010 Huacai Chen (zltjiangshi@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.
- */
-
-/*
- * fulong 2e mini pc has a bonito north bridge.
- */
-
-/* what is the meaning of devfn in qemu and IDSEL in bonito northbridge?
- *
- * devfn   pci_slot<<3  + funno
- * one pci bus can have 32 devices and each device can have 8 functions.
- *
- * In bonito north bridge, pci slot = IDSEL bit - 12.
- * For example, PCI_IDSEL_VIA686B = 17,
- * pci slot = 17-12=5
- *
- * so
- * VT686B_FUN0's devfn = (5<<3)+0
- * VT686B_FUN1's devfn = (5<<3)+1
- *
- * qemu also uses pci address for north bridge to access pci config register.
- * bus_no   [23:16]
- * dev_no   [15:11]
- * fun_no   [10:8]
- * reg_no   [7:2]
- *
- * so function bonito_sbridge_pciaddr for the translation from
- * north bridge address to pci address.
- */
-
-#include <assert.h>
-
-#include "hw/hw.h"
-#include "hw/pci/pci.h"
-#include "hw/pc.h"
-#include "hw/mips.h"
-#include "hw/pci/pci_host.h"
-#include "sysemu/sysemu.h"
-#include "exec/address-spaces.h"
-
-//#define DEBUG_BONITO
-
-#ifdef DEBUG_BONITO
-#define DPRINTF(fmt, ...) fprintf(stderr, "%s: " fmt, __FUNCTION__, ##__VA_ARGS__)
-#else
-#define DPRINTF(fmt, ...)
-#endif
-
-/* from linux soure code. include/asm-mips/mips-boards/bonito64.h*/
-#define BONITO_BOOT_BASE        0x1fc00000
-#define BONITO_BOOT_SIZE        0x00100000
-#define BONITO_BOOT_TOP         (BONITO_BOOT_BASE+BONITO_BOOT_SIZE-1)
-#define BONITO_FLASH_BASE       0x1c000000
-#define BONITO_FLASH_SIZE       0x03000000
-#define BONITO_FLASH_TOP        (BONITO_FLASH_BASE+BONITO_FLASH_SIZE-1)
-#define BONITO_SOCKET_BASE      0x1f800000
-#define BONITO_SOCKET_SIZE      0x00400000
-#define BONITO_SOCKET_TOP       (BONITO_SOCKET_BASE+BONITO_SOCKET_SIZE-1)
-#define BONITO_REG_BASE         0x1fe00000
-#define BONITO_REG_SIZE         0x00040000
-#define BONITO_REG_TOP          (BONITO_REG_BASE+BONITO_REG_SIZE-1)
-#define BONITO_DEV_BASE         0x1ff00000
-#define BONITO_DEV_SIZE         0x00100000
-#define BONITO_DEV_TOP          (BONITO_DEV_BASE+BONITO_DEV_SIZE-1)
-#define BONITO_PCILO_BASE       0x10000000
-#define BONITO_PCILO_BASE_VA    0xb0000000
-#define BONITO_PCILO_SIZE       0x0c000000
-#define BONITO_PCILO_TOP        (BONITO_PCILO_BASE+BONITO_PCILO_SIZE-1)
-#define BONITO_PCILO0_BASE      0x10000000
-#define BONITO_PCILO1_BASE      0x14000000
-#define BONITO_PCILO2_BASE      0x18000000
-#define BONITO_PCIHI_BASE       0x20000000
-#define BONITO_PCIHI_SIZE       0x20000000
-#define BONITO_PCIHI_TOP        (BONITO_PCIHI_BASE+BONITO_PCIHI_SIZE-1)
-#define BONITO_PCIIO_BASE       0x1fd00000
-#define BONITO_PCIIO_BASE_VA    0xbfd00000
-#define BONITO_PCIIO_SIZE       0x00010000
-#define BONITO_PCIIO_TOP        (BONITO_PCIIO_BASE+BONITO_PCIIO_SIZE-1)
-#define BONITO_PCICFG_BASE      0x1fe80000
-#define BONITO_PCICFG_SIZE      0x00080000
-#define BONITO_PCICFG_TOP       (BONITO_PCICFG_BASE+BONITO_PCICFG_SIZE-1)
-
-
-#define BONITO_PCICONFIGBASE    0x00
-#define BONITO_REGBASE          0x100
-
-#define BONITO_PCICONFIG_BASE   (BONITO_PCICONFIGBASE+BONITO_REG_BASE)
-#define BONITO_PCICONFIG_SIZE   (0x100)
-
-#define BONITO_INTERNAL_REG_BASE  (BONITO_REGBASE+BONITO_REG_BASE)
-#define BONITO_INTERNAL_REG_SIZE  (0x70)
-
-#define BONITO_SPCICONFIG_BASE  (BONITO_PCICFG_BASE)
-#define BONITO_SPCICONFIG_SIZE  (BONITO_PCICFG_SIZE)
-
-
-
-/* 1. Bonito h/w Configuration */
-/* Power on register */
-
-#define BONITO_BONPONCFG        (0x00 >> 2)      /* 0x100 */
-#define BONITO_BONGENCFG_OFFSET 0x4
-#define BONITO_BONGENCFG        (BONITO_BONGENCFG_OFFSET>>2)   /*0x104 */
-
-/* 2. IO & IDE configuration */
-#define BONITO_IODEVCFG         (0x08 >> 2)      /* 0x108 */
-
-/* 3. IO & IDE configuration */
-#define BONITO_SDCFG            (0x0c >> 2)      /* 0x10c */
-
-/* 4. PCI address map control */
-#define BONITO_PCIMAP           (0x10 >> 2)      /* 0x110 */
-#define BONITO_PCIMEMBASECFG    (0x14 >> 2)      /* 0x114 */
-#define BONITO_PCIMAP_CFG       (0x18 >> 2)      /* 0x118 */
-
-/* 5. ICU & GPIO regs */
-/* GPIO Regs - r/w */
-#define BONITO_GPIODATA_OFFSET  0x1c
-#define BONITO_GPIODATA         (BONITO_GPIODATA_OFFSET >> 2)   /* 0x11c */
-#define BONITO_GPIOIE           (0x20 >> 2)      /* 0x120 */
-
-/* ICU Configuration Regs - r/w */
-#define BONITO_INTEDGE          (0x24 >> 2)      /* 0x124 */
-#define BONITO_INTSTEER         (0x28 >> 2)      /* 0x128 */
-#define BONITO_INTPOL           (0x2c >> 2)      /* 0x12c */
-
-/* ICU Enable Regs - IntEn & IntISR are r/o. */
-#define BONITO_INTENSET         (0x30 >> 2)      /* 0x130 */
-#define BONITO_INTENCLR         (0x34 >> 2)      /* 0x134 */
-#define BONITO_INTEN            (0x38 >> 2)      /* 0x138 */
-#define BONITO_INTISR           (0x3c >> 2)      /* 0x13c */
-
-/* PCI mail boxes */
-#define BONITO_PCIMAIL0_OFFSET    0x40
-#define BONITO_PCIMAIL1_OFFSET    0x44
-#define BONITO_PCIMAIL2_OFFSET    0x48
-#define BONITO_PCIMAIL3_OFFSET    0x4c
-#define BONITO_PCIMAIL0         (0x40 >> 2)      /* 0x140 */
-#define BONITO_PCIMAIL1         (0x44 >> 2)      /* 0x144 */
-#define BONITO_PCIMAIL2         (0x48 >> 2)      /* 0x148 */
-#define BONITO_PCIMAIL3         (0x4c >> 2)      /* 0x14c */
-
-/* 6. PCI cache */
-#define BONITO_PCICACHECTRL     (0x50 >> 2)      /* 0x150 */
-#define BONITO_PCICACHETAG      (0x54 >> 2)      /* 0x154 */
-#define BONITO_PCIBADADDR       (0x58 >> 2)      /* 0x158 */
-#define BONITO_PCIMSTAT         (0x5c >> 2)      /* 0x15c */
-
-/* 7. other*/
-#define BONITO_TIMECFG          (0x60 >> 2)      /* 0x160 */
-#define BONITO_CPUCFG           (0x64 >> 2)      /* 0x164 */
-#define BONITO_DQCFG            (0x68 >> 2)      /* 0x168 */
-#define BONITO_MEMSIZE          (0x6C >> 2)      /* 0x16c */
-
-#define BONITO_REGS             (0x70 >> 2)
-
-/* PCI config for south bridge. type 0 */
-#define BONITO_PCICONF_IDSEL_MASK      0xfffff800     /* [31:11] */
-#define BONITO_PCICONF_IDSEL_OFFSET    11
-#define BONITO_PCICONF_FUN_MASK        0x700    /* [10:8] */
-#define BONITO_PCICONF_FUN_OFFSET      8
-#define BONITO_PCICONF_REG_MASK        0xFC
-#define BONITO_PCICONF_REG_OFFSET      0
-
-
-/* idsel BIT = pci slot number +12 */
-#define PCI_SLOT_BASE              12
-#define PCI_IDSEL_VIA686B_BIT      (17)
-#define PCI_IDSEL_VIA686B          (1<<PCI_IDSEL_VIA686B_BIT)
-
-#define PCI_ADDR(busno,devno,funno,regno)  \
-    ((((busno)<<16)&0xff0000) + (((devno)<<11)&0xf800) + (((funno)<<8)&0x700) + (regno))
-
-#define TYPE_BONITO_PCI_HOST_BRIDGE "Bonito-pcihost"
-
-typedef struct BonitoState BonitoState;
-
-typedef struct PCIBonitoState
-{
-    PCIDevice dev;
-
-    BonitoState *pcihost;
-    uint32_t regs[BONITO_REGS];
-
-    struct bonldma {
-        uint32_t ldmactrl;
-        uint32_t ldmastat;
-        uint32_t ldmaaddr;
-        uint32_t ldmago;
-    } bonldma;
-
-    /* Based at 1fe00300, bonito Copier */
-    struct boncop {
-        uint32_t copctrl;
-        uint32_t copstat;
-        uint32_t coppaddr;
-        uint32_t copgo;
-    } boncop;
-
-    /* Bonito registers */
-    MemoryRegion iomem;
-    MemoryRegion iomem_ldma;
-    MemoryRegion iomem_cop;
-
-    hwaddr bonito_pciio_start;
-    hwaddr bonito_pciio_length;
-    int bonito_pciio_handle;
-
-    hwaddr bonito_localio_start;
-    hwaddr bonito_localio_length;
-    int bonito_localio_handle;
-
-} PCIBonitoState;
-
-#define BONITO_PCI_HOST_BRIDGE(obj) \
-    OBJECT_CHECK(BonitoState, (obj), TYPE_BONITO_PCI_HOST_BRIDGE)
-
-struct BonitoState {
-    PCIHostState parent_obj;
-
-    qemu_irq *pic;
-
-    PCIBonitoState *pci_dev;
-};
-
-static void bonito_writel(void *opaque, hwaddr addr,
-                          uint64_t val, unsigned size)
-{
-    PCIBonitoState *s = opaque;
-    uint32_t saddr;
-    int reset = 0;
-
-    saddr = (addr - BONITO_REGBASE) >> 2;
-
-    DPRINTF("bonito_writel "TARGET_FMT_plx" val %x saddr %x\n", addr, val, saddr);
-    switch (saddr) {
-    case BONITO_BONPONCFG:
-    case BONITO_IODEVCFG:
-    case BONITO_SDCFG:
-    case BONITO_PCIMAP:
-    case BONITO_PCIMEMBASECFG:
-    case BONITO_PCIMAP_CFG:
-    case BONITO_GPIODATA:
-    case BONITO_GPIOIE:
-    case BONITO_INTEDGE:
-    case BONITO_INTSTEER:
-    case BONITO_INTPOL:
-    case BONITO_PCIMAIL0:
-    case BONITO_PCIMAIL1:
-    case BONITO_PCIMAIL2:
-    case BONITO_PCIMAIL3:
-    case BONITO_PCICACHECTRL:
-    case BONITO_PCICACHETAG:
-    case BONITO_PCIBADADDR:
-    case BONITO_PCIMSTAT:
-    case BONITO_TIMECFG:
-    case BONITO_CPUCFG:
-    case BONITO_DQCFG:
-    case BONITO_MEMSIZE:
-        s->regs[saddr] = val;
-        break;
-    case BONITO_BONGENCFG:
-        if (!(s->regs[saddr] & 0x04) && (val & 0x04)) {
-            reset = 1; /* bit 2 jump from 0 to 1 cause reset */
-        }
-        s->regs[saddr] = val;
-        if (reset) {
-            qemu_system_reset_request();
-        }
-        break;
-    case BONITO_INTENSET:
-        s->regs[BONITO_INTENSET] = val;
-        s->regs[BONITO_INTEN] |= val;
-        break;
-    case BONITO_INTENCLR:
-        s->regs[BONITO_INTENCLR] = val;
-        s->regs[BONITO_INTEN] &= ~val;
-        break;
-    case BONITO_INTEN:
-    case BONITO_INTISR:
-        DPRINTF("write to readonly bonito register %x\n", saddr);
-        break;
-    default:
-        DPRINTF("write to unknown bonito register %x\n", saddr);
-        break;
-    }
-}
-
-static uint64_t bonito_readl(void *opaque, hwaddr addr,
-                             unsigned size)
-{
-    PCIBonitoState *s = opaque;
-    uint32_t saddr;
-
-    saddr = (addr - BONITO_REGBASE) >> 2;
-
-    DPRINTF("bonito_readl "TARGET_FMT_plx"\n", addr);
-    switch (saddr) {
-    case BONITO_INTISR:
-        return s->regs[saddr];
-    default:
-        return s->regs[saddr];
-    }
-}
-
-static const MemoryRegionOps bonito_ops = {
-    .read = bonito_readl,
-    .write = bonito_writel,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-};
-
-static void bonito_pciconf_writel(void *opaque, hwaddr addr,
-                                  uint64_t val, unsigned size)
-{
-    PCIBonitoState *s = opaque;
-    PCIDevice *d = PCI_DEVICE(s);
-
-    DPRINTF("bonito_pciconf_writel "TARGET_FMT_plx" val %x\n", addr, val);
-    d->config_write(d, addr, val, 4);
-}
-
-static uint64_t bonito_pciconf_readl(void *opaque, hwaddr addr,
-                                     unsigned size)
-{
-
-    PCIBonitoState *s = opaque;
-    PCIDevice *d = PCI_DEVICE(s);
-
-    DPRINTF("bonito_pciconf_readl "TARGET_FMT_plx"\n", addr);
-    return d->config_read(d, addr, 4);
-}
-
-/* north bridge PCI configure space. 0x1fe0 0000 - 0x1fe0 00ff */
-
-static const MemoryRegionOps bonito_pciconf_ops = {
-    .read = bonito_pciconf_readl,
-    .write = bonito_pciconf_writel,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-};
-
-static uint64_t bonito_ldma_readl(void *opaque, hwaddr addr,
-                                  unsigned size)
-{
-    uint32_t val;
-    PCIBonitoState *s = opaque;
-
-    val = ((uint32_t *)(&s->bonldma))[addr/sizeof(uint32_t)];
-
-    return val;
-}
-
-static void bonito_ldma_writel(void *opaque, hwaddr addr,
-                               uint64_t val, unsigned size)
-{
-    PCIBonitoState *s = opaque;
-
-    ((uint32_t *)(&s->bonldma))[addr/sizeof(uint32_t)] = val & 0xffffffff;
-}
-
-static const MemoryRegionOps bonito_ldma_ops = {
-    .read = bonito_ldma_readl,
-    .write = bonito_ldma_writel,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-};
-
-static uint64_t bonito_cop_readl(void *opaque, hwaddr addr,
-                                 unsigned size)
-{
-    uint32_t val;
-    PCIBonitoState *s = opaque;
-
-    val = ((uint32_t *)(&s->boncop))[addr/sizeof(uint32_t)];
-
-    return val;
-}
-
-static void bonito_cop_writel(void *opaque, hwaddr addr,
-                              uint64_t val, unsigned size)
-{
-    PCIBonitoState *s = opaque;
-
-    ((uint32_t *)(&s->boncop))[addr/sizeof(uint32_t)] = val & 0xffffffff;
-}
-
-static const MemoryRegionOps bonito_cop_ops = {
-    .read = bonito_cop_readl,
-    .write = bonito_cop_writel,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-};
-
-static uint32_t bonito_sbridge_pciaddr(void *opaque, hwaddr addr)
-{
-    PCIBonitoState *s = opaque;
-    PCIHostState *phb = PCI_HOST_BRIDGE(s->pcihost);
-    uint32_t cfgaddr;
-    uint32_t idsel;
-    uint32_t devno;
-    uint32_t funno;
-    uint32_t regno;
-    uint32_t pciaddr;
-
-    /* support type0 pci config */
-    if ((s->regs[BONITO_PCIMAP_CFG] & 0x10000) != 0x0) {
-        return 0xffffffff;
-    }
-
-    cfgaddr = addr & 0xffff;
-    cfgaddr |= (s->regs[BONITO_PCIMAP_CFG] & 0xffff) << 16;
-
-    idsel = (cfgaddr & BONITO_PCICONF_IDSEL_MASK) >> BONITO_PCICONF_IDSEL_OFFSET;
-    devno = ffs(idsel) - 1;
-    funno = (cfgaddr & BONITO_PCICONF_FUN_MASK) >> BONITO_PCICONF_FUN_OFFSET;
-    regno = (cfgaddr & BONITO_PCICONF_REG_MASK) >> BONITO_PCICONF_REG_OFFSET;
-
-    if (idsel == 0) {
-        fprintf(stderr, "error in bonito pci config address " TARGET_FMT_plx
-            ",pcimap_cfg=%x\n", addr, s->regs[BONITO_PCIMAP_CFG]);
-        exit(1);
-    }
-    pciaddr = PCI_ADDR(pci_bus_num(phb->bus), devno, funno, regno);
-    DPRINTF("cfgaddr %x pciaddr %x busno %x devno %d funno %d regno %d\n",
-        cfgaddr, pciaddr, pci_bus_num(phb->bus), devno, funno, regno);
-
-    return pciaddr;
-}
-
-static void bonito_spciconf_writeb(void *opaque, hwaddr addr,
-                                   uint32_t val)
-{
-    PCIBonitoState *s = opaque;
-    PCIDevice *d = PCI_DEVICE(s);
-    PCIHostState *phb = PCI_HOST_BRIDGE(s->pcihost);
-    uint32_t pciaddr;
-    uint16_t status;
-
-    DPRINTF("bonito_spciconf_writeb "TARGET_FMT_plx" val %x\n", addr, val);
-    pciaddr = bonito_sbridge_pciaddr(s, addr);
-
-    if (pciaddr == 0xffffffff) {
-        return;
-    }
-
-    /* set the pci address in s->config_reg */
-    phb->config_reg = (pciaddr) | (1u << 31);
-    pci_data_write(phb->bus, phb->config_reg, val & 0xff, 1);
-
-    /* clear PCI_STATUS_REC_MASTER_ABORT and PCI_STATUS_REC_TARGET_ABORT */
-    status = pci_get_word(d->config + PCI_STATUS);
-    status &= ~(PCI_STATUS_REC_MASTER_ABORT | PCI_STATUS_REC_TARGET_ABORT);
-    pci_set_word(d->config + PCI_STATUS, status);
-}
-
-static void bonito_spciconf_writew(void *opaque, hwaddr addr,
-                                   uint32_t val)
-{
-    PCIBonitoState *s = opaque;
-    PCIDevice *d = PCI_DEVICE(s);
-    PCIHostState *phb = PCI_HOST_BRIDGE(s->pcihost);
-    uint32_t pciaddr;
-    uint16_t status;
-
-    DPRINTF("bonito_spciconf_writew "TARGET_FMT_plx" val %x\n", addr, val);
-    assert((addr & 0x1) == 0);
-
-    pciaddr = bonito_sbridge_pciaddr(s, addr);
-
-    if (pciaddr == 0xffffffff) {
-        return;
-    }
-
-    /* set the pci address in s->config_reg */
-    phb->config_reg = (pciaddr) | (1u << 31);
-    pci_data_write(phb->bus, phb->config_reg, val, 2);
-
-    /* clear PCI_STATUS_REC_MASTER_ABORT and PCI_STATUS_REC_TARGET_ABORT */
-    status = pci_get_word(d->config + PCI_STATUS);
-    status &= ~(PCI_STATUS_REC_MASTER_ABORT | PCI_STATUS_REC_TARGET_ABORT);
-    pci_set_word(d->config + PCI_STATUS, status);
-}
-
-static void bonito_spciconf_writel(void *opaque, hwaddr addr,
-                                   uint32_t val)
-{
-    PCIBonitoState *s = opaque;
-    PCIDevice *d = PCI_DEVICE(s);
-    PCIHostState *phb = PCI_HOST_BRIDGE(s->pcihost);
-    uint32_t pciaddr;
-    uint16_t status;
-
-    DPRINTF("bonito_spciconf_writel "TARGET_FMT_plx" val %x\n", addr, val);
-    assert((addr & 0x3) == 0);
-
-    pciaddr = bonito_sbridge_pciaddr(s, addr);
-
-    if (pciaddr == 0xffffffff) {
-        return;
-    }
-
-    /* set the pci address in s->config_reg */
-    phb->config_reg = (pciaddr) | (1u << 31);
-    pci_data_write(phb->bus, phb->config_reg, val, 4);
-
-    /* clear PCI_STATUS_REC_MASTER_ABORT and PCI_STATUS_REC_TARGET_ABORT */
-    status = pci_get_word(d->config + PCI_STATUS);
-    status &= ~(PCI_STATUS_REC_MASTER_ABORT | PCI_STATUS_REC_TARGET_ABORT);
-    pci_set_word(d->config + PCI_STATUS, status);
-}
-
-static uint32_t bonito_spciconf_readb(void *opaque, hwaddr addr)
-{
-    PCIBonitoState *s = opaque;
-    PCIDevice *d = PCI_DEVICE(s);
-    PCIHostState *phb = PCI_HOST_BRIDGE(s->pcihost);
-    uint32_t pciaddr;
-    uint16_t status;
-
-    DPRINTF("bonito_spciconf_readb "TARGET_FMT_plx"\n", addr);
-    pciaddr = bonito_sbridge_pciaddr(s, addr);
-
-    if (pciaddr == 0xffffffff) {
-        return 0xff;
-    }
-
-    /* set the pci address in s->config_reg */
-    phb->config_reg = (pciaddr) | (1u << 31);
-
-    /* clear PCI_STATUS_REC_MASTER_ABORT and PCI_STATUS_REC_TARGET_ABORT */
-    status = pci_get_word(d->config + PCI_STATUS);
-    status &= ~(PCI_STATUS_REC_MASTER_ABORT | PCI_STATUS_REC_TARGET_ABORT);
-    pci_set_word(d->config + PCI_STATUS, status);
-
-    return pci_data_read(phb->bus, phb->config_reg, 1);
-}
-
-static uint32_t bonito_spciconf_readw(void *opaque, hwaddr addr)
-{
-    PCIBonitoState *s = opaque;
-    PCIDevice *d = PCI_DEVICE(s);
-    PCIHostState *phb = PCI_HOST_BRIDGE(s->pcihost);
-    uint32_t pciaddr;
-    uint16_t status;
-
-    DPRINTF("bonito_spciconf_readw "TARGET_FMT_plx"\n", addr);
-    assert((addr & 0x1) == 0);
-
-    pciaddr = bonito_sbridge_pciaddr(s, addr);
-
-    if (pciaddr == 0xffffffff) {
-        return 0xffff;
-    }
-
-    /* set the pci address in s->config_reg */
-    phb->config_reg = (pciaddr) | (1u << 31);
-
-    /* clear PCI_STATUS_REC_MASTER_ABORT and PCI_STATUS_REC_TARGET_ABORT */
-    status = pci_get_word(d->config + PCI_STATUS);
-    status &= ~(PCI_STATUS_REC_MASTER_ABORT | PCI_STATUS_REC_TARGET_ABORT);
-    pci_set_word(d->config + PCI_STATUS, status);
-
-    return pci_data_read(phb->bus, phb->config_reg, 2);
-}
-
-static uint32_t bonito_spciconf_readl(void *opaque, hwaddr addr)
-{
-    PCIBonitoState *s = opaque;
-    PCIDevice *d = PCI_DEVICE(s);
-    PCIHostState *phb = PCI_HOST_BRIDGE(s->pcihost);
-    uint32_t pciaddr;
-    uint16_t status;
-
-    DPRINTF("bonito_spciconf_readl "TARGET_FMT_plx"\n", addr);
-    assert((addr & 0x3) == 0);
-
-    pciaddr = bonito_sbridge_pciaddr(s, addr);
-
-    if (pciaddr == 0xffffffff) {
-        return 0xffffffff;
-    }
-
-    /* set the pci address in s->config_reg */
-    phb->config_reg = (pciaddr) | (1u << 31);
-
-    /* clear PCI_STATUS_REC_MASTER_ABORT and PCI_STATUS_REC_TARGET_ABORT */
-    status = pci_get_word(d->config + PCI_STATUS);
-    status &= ~(PCI_STATUS_REC_MASTER_ABORT | PCI_STATUS_REC_TARGET_ABORT);
-    pci_set_word(d->config + PCI_STATUS, status);
-
-    return pci_data_read(phb->bus, phb->config_reg, 4);
-}
-
-/* south bridge PCI configure space. 0x1fe8 0000 - 0x1fef ffff */
-static const MemoryRegionOps bonito_spciconf_ops = {
-    .old_mmio = {
-        .read = {
-            bonito_spciconf_readb,
-            bonito_spciconf_readw,
-            bonito_spciconf_readl,
-        },
-        .write = {
-            bonito_spciconf_writeb,
-            bonito_spciconf_writew,
-            bonito_spciconf_writel,
-        },
-    },
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-#define BONITO_IRQ_BASE 32
-
-static void pci_bonito_set_irq(void *opaque, int irq_num, int level)
-{
-    BonitoState *s = opaque;
-    qemu_irq *pic = s->pic;
-    PCIBonitoState *bonito_state = s->pci_dev;
-    int internal_irq = irq_num - BONITO_IRQ_BASE;
-
-    if (bonito_state->regs[BONITO_INTEDGE] & (1 << internal_irq)) {
-        qemu_irq_pulse(*pic);
-    } else {   /* level triggered */
-        if (bonito_state->regs[BONITO_INTPOL] & (1 << internal_irq)) {
-            qemu_irq_raise(*pic);
-        } else {
-            qemu_irq_lower(*pic);
-        }
-    }
-}
-
-/* map the original irq (0~3) to bonito irq (16~47, but 16~31 are unused) */
-static int pci_bonito_map_irq(PCIDevice * pci_dev, int irq_num)
-{
-    int slot;
-
-    slot = (pci_dev->devfn >> 3);
-
-    switch (slot) {
-    case 5:   /* FULONG2E_VIA_SLOT, SouthBridge, IDE, USB, ACPI, AC97, MC97 */
-        return irq_num % 4 + BONITO_IRQ_BASE;
-    case 6:   /* FULONG2E_ATI_SLOT, VGA */
-        return 4 + BONITO_IRQ_BASE;
-    case 7:   /* FULONG2E_RTL_SLOT, RTL8139 */
-        return 5 + BONITO_IRQ_BASE;
-    case 8 ... 12: /* PCI slot 1 to 4 */
-        return (slot - 8 + irq_num) + 6 + BONITO_IRQ_BASE;
-    default:  /* Unknown device, don't do any translation */
-        return irq_num;
-    }
-}
-
-static void bonito_reset(void *opaque)
-{
-    PCIBonitoState *s = opaque;
-
-    /* set the default value of north bridge registers */
-
-    s->regs[BONITO_BONPONCFG] = 0xc40;
-    s->regs[BONITO_BONGENCFG] = 0x1384;
-    s->regs[BONITO_IODEVCFG] = 0x2bff8010;
-    s->regs[BONITO_SDCFG] = 0x255e0091;
-
-    s->regs[BONITO_GPIODATA] = 0x1ff;
-    s->regs[BONITO_GPIOIE] = 0x1ff;
-    s->regs[BONITO_DQCFG] = 0x8;
-    s->regs[BONITO_MEMSIZE] = 0x10000000;
-    s->regs[BONITO_PCIMAP] = 0x6140;
-}
-
-static const VMStateDescription vmstate_bonito = {
-    .name = "Bonito",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField []) {
-        VMSTATE_PCI_DEVICE(dev, PCIBonitoState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static int bonito_pcihost_initfn(SysBusDevice *dev)
-{
-    PCIHostState *phb = PCI_HOST_BRIDGE(dev);
-
-    phb->bus = pci_register_bus(DEVICE(dev), "pci",
-                                pci_bonito_set_irq, pci_bonito_map_irq, dev,
-                                get_system_memory(), get_system_io(),
-                                0x28, 32, TYPE_PCI_BUS);
-
-    return 0;
-}
-
-static int bonito_initfn(PCIDevice *dev)
-{
-    PCIBonitoState *s = DO_UPCAST(PCIBonitoState, dev, dev);
-    SysBusDevice *sysbus = SYS_BUS_DEVICE(s->pcihost);
-    PCIHostState *phb = PCI_HOST_BRIDGE(s->pcihost);
-
-    /* Bonito North Bridge, built on FPGA, VENDOR_ID/DEVICE_ID are "undefined" */
-    pci_config_set_prog_interface(dev->config, 0x00);
-
-    /* set the north bridge register mapping */
-    memory_region_init_io(&s->iomem, &bonito_ops, s,
-                          "north-bridge-register", BONITO_INTERNAL_REG_SIZE);
-    sysbus_init_mmio(sysbus, &s->iomem);
-    sysbus_mmio_map(sysbus, 0, BONITO_INTERNAL_REG_BASE);
-
-    /* set the north bridge pci configure  mapping */
-    memory_region_init_io(&phb->conf_mem, &bonito_pciconf_ops, s,
-                          "north-bridge-pci-config", BONITO_PCICONFIG_SIZE);
-    sysbus_init_mmio(sysbus, &phb->conf_mem);
-    sysbus_mmio_map(sysbus, 1, BONITO_PCICONFIG_BASE);
-
-    /* set the south bridge pci configure  mapping */
-    memory_region_init_io(&phb->data_mem, &bonito_spciconf_ops, s,
-                          "south-bridge-pci-config", BONITO_SPCICONFIG_SIZE);
-    sysbus_init_mmio(sysbus, &phb->data_mem);
-    sysbus_mmio_map(sysbus, 2, BONITO_SPCICONFIG_BASE);
-
-    memory_region_init_io(&s->iomem_ldma, &bonito_ldma_ops, s,
-                          "ldma", 0x100);
-    sysbus_init_mmio(sysbus, &s->iomem_ldma);
-    sysbus_mmio_map(sysbus, 3, 0xbfe00200);
-
-    memory_region_init_io(&s->iomem_cop, &bonito_cop_ops, s,
-                          "cop", 0x100);
-    sysbus_init_mmio(sysbus, &s->iomem_cop);
-    sysbus_mmio_map(sysbus, 4, 0xbfe00300);
-
-    /* Map PCI IO Space  0x1fd0 0000 - 0x1fd1 0000 */
-    s->bonito_pciio_start = BONITO_PCIIO_BASE;
-    s->bonito_pciio_length = BONITO_PCIIO_SIZE;
-    isa_mem_base = s->bonito_pciio_start;
-    isa_mmio_init(s->bonito_pciio_start, s->bonito_pciio_length);
-
-    /* add pci local io mapping */
-    s->bonito_localio_start = BONITO_DEV_BASE;
-    s->bonito_localio_length = BONITO_DEV_SIZE;
-    isa_mmio_init(s->bonito_localio_start, s->bonito_localio_length);
-
-    /* set the default value of north bridge pci config */
-    pci_set_word(dev->config + PCI_COMMAND, 0x0000);
-    pci_set_word(dev->config + PCI_STATUS, 0x0000);
-    pci_set_word(dev->config + PCI_SUBSYSTEM_VENDOR_ID, 0x0000);
-    pci_set_word(dev->config + PCI_SUBSYSTEM_ID, 0x0000);
-
-    pci_set_byte(dev->config + PCI_INTERRUPT_LINE, 0x00);
-    pci_set_byte(dev->config + PCI_INTERRUPT_PIN, 0x01);
-    pci_set_byte(dev->config + PCI_MIN_GNT, 0x3c);
-    pci_set_byte(dev->config + PCI_MAX_LAT, 0x00);
-
-    qemu_register_reset(bonito_reset, s);
-
-    return 0;
-}
-
-PCIBus *bonito_init(qemu_irq *pic)
-{
-    DeviceState *dev;
-    BonitoState *pcihost;
-    PCIHostState *phb;
-    PCIBonitoState *s;
-    PCIDevice *d;
-
-    dev = qdev_create(NULL, TYPE_BONITO_PCI_HOST_BRIDGE);
-    phb = PCI_HOST_BRIDGE(dev);
-    pcihost = BONITO_PCI_HOST_BRIDGE(dev);
-    pcihost->pic = pic;
-    qdev_init_nofail(dev);
-
-    /* set the pcihost pointer before bonito_initfn is called */
-    d = pci_create(phb->bus, PCI_DEVFN(0, 0), "Bonito");
-    s = DO_UPCAST(PCIBonitoState, dev, d);
-    s->pcihost = pcihost;
-    pcihost->pci_dev = s;
-    qdev_init_nofail(DEVICE(d));
-
-    return phb->bus;
-}
-
-static void bonito_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
-    k->init = bonito_initfn;
-    k->vendor_id = 0xdf53;
-    k->device_id = 0x00d5;
-    k->revision = 0x01;
-    k->class_id = PCI_CLASS_BRIDGE_HOST;
-    dc->desc = "Host bridge";
-    dc->no_user = 1;
-    dc->vmsd = &vmstate_bonito;
-}
-
-static const 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 const TypeInfo bonito_pcihost_info = {
-    .name          = TYPE_BONITO_PCI_HOST_BRIDGE,
-    .parent        = TYPE_PCI_HOST_BRIDGE,
-    .instance_size = sizeof(BonitoState),
-    .class_init    = bonito_pcihost_class_init,
-};
-
-static void bonito_register_types(void)
-{
-    type_register_static(&bonito_pcihost_info);
-    type_register_static(&bonito_info);
-}
-
-type_init(bonito_register_types)
diff --git a/hw/bt-hci-csr.c b/hw/bt-hci-csr.c
deleted file mode 100644 (file)
index 55c819b..0000000
+++ /dev/null
@@ -1,454 +0,0 @@
-/*
- * Bluetooth serial HCI transport.
- * CSR41814 HCI with H4p vendor extensions.
- *
- * Copyright (C) 2008 Andrzej Zaborowski  <balrog@zabor.org>
- *
- * 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 or
- * (at your option) version 3 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
- * 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 "char/char.h"
-#include "qemu/timer.h"
-#include "hw/irq.h"
-#include "bt/bt.h"
-#include "hw/bt.h"
-
-struct csrhci_s {
-    int enable;
-    qemu_irq *pins;
-    int pin_state;
-    int modem_state;
-    CharDriverState chr;
-#define FIFO_LEN       4096
-    int out_start;
-    int out_len;
-    int out_size;
-    uint8_t outfifo[FIFO_LEN * 2];
-    uint8_t inpkt[FIFO_LEN];
-    int in_len;
-    int in_hdr;
-    int in_data;
-    QEMUTimer *out_tm;
-    int64_t baud_delay;
-
-    bdaddr_t bd_addr;
-    struct HCIInfo *hci;
-};
-
-/* H4+ packet types */
-enum {
-    H4_CMD_PKT   = 1,
-    H4_ACL_PKT   = 2,
-    H4_SCO_PKT   = 3,
-    H4_EVT_PKT   = 4,
-    H4_NEG_PKT   = 6,
-    H4_ALIVE_PKT = 7,
-};
-
-/* CSR41814 negotiation start magic packet */
-static const uint8_t csrhci_neg_packet[] = {
-    H4_NEG_PKT, 10,
-    0x00, 0xa0, 0x01, 0x00, 0x00,
-    0x4c, 0x00, 0x96, 0x00, 0x00,
-};
-
-/* CSR41814 vendor-specific command OCFs */
-enum {
-    OCF_CSR_SEND_FIRMWARE = 0x000,
-};
-
-static inline void csrhci_fifo_wake(struct csrhci_s *s)
-{
-    if (!s->enable || !s->out_len)
-        return;
-
-    /* XXX: Should wait for s->modem_state & CHR_TIOCM_RTS? */
-    if (s->chr.chr_can_read && s->chr.chr_can_read(s->chr.handler_opaque) &&
-                    s->chr.chr_read) {
-        s->chr.chr_read(s->chr.handler_opaque,
-                        s->outfifo + s->out_start ++, 1);
-        s->out_len --;
-        if (s->out_start >= s->out_size) {
-            s->out_start = 0;
-            s->out_size = FIFO_LEN;
-        }
-    }
-
-    if (s->out_len)
-        qemu_mod_timer(s->out_tm, qemu_get_clock_ns(vm_clock) + s->baud_delay);
-}
-
-#define csrhci_out_packetz(s, len) memset(csrhci_out_packet(s, len), 0, len)
-static uint8_t *csrhci_out_packet(struct csrhci_s *s, int len)
-{
-    int off = s->out_start + s->out_len;
-
-    /* TODO: do the padding here, i.e. align len */
-    s->out_len += len;
-
-    if (off < FIFO_LEN) {
-        if (off + len > FIFO_LEN && (s->out_size = off + len) > FIFO_LEN * 2) {
-            fprintf(stderr, "%s: can't alloc %i bytes\n", __FUNCTION__, len);
-            exit(-1);
-        }
-        return s->outfifo + off;
-    }
-
-    if (s->out_len > s->out_size) {
-        fprintf(stderr, "%s: can't alloc %i bytes\n", __FUNCTION__, len);
-        exit(-1);
-    }
-
-    return s->outfifo + off - s->out_size;
-}
-
-static inline uint8_t *csrhci_out_packet_csr(struct csrhci_s *s,
-                int type, int len)
-{
-    uint8_t *ret = csrhci_out_packetz(s, len + 2);
-
-    *ret ++ = type;
-    *ret ++ = len;
-
-    return ret;
-}
-
-static inline uint8_t *csrhci_out_packet_event(struct csrhci_s *s,
-                int evt, int len)
-{
-    uint8_t *ret = csrhci_out_packetz(s,
-                    len + 1 + sizeof(struct hci_event_hdr));
-
-    *ret ++ = H4_EVT_PKT;
-    ((struct hci_event_hdr *) ret)->evt = evt;
-    ((struct hci_event_hdr *) ret)->plen = len;
-
-    return ret + sizeof(struct hci_event_hdr);
-}
-
-static void csrhci_in_packet_vendor(struct csrhci_s *s, int ocf,
-                uint8_t *data, int len)
-{
-    int offset;
-    uint8_t *rpkt;
-
-    switch (ocf) {
-    case OCF_CSR_SEND_FIRMWARE:
-        /* Check if this is the bd_address packet */
-        if (len >= 18 + 8 && data[12] == 0x01 && data[13] == 0x00) {
-            offset = 18;
-            s->bd_addr.b[0] = data[offset + 7];        /* Beyond cmd packet end(!?) */
-            s->bd_addr.b[1] = data[offset + 6];
-            s->bd_addr.b[2] = data[offset + 4];
-            s->bd_addr.b[3] = data[offset + 0];
-            s->bd_addr.b[4] = data[offset + 3];
-            s->bd_addr.b[5] = data[offset + 2];
-
-            s->hci->bdaddr_set(s->hci, s->bd_addr.b);
-            fprintf(stderr, "%s: bd_address loaded from firmware: "
-                            "%02x:%02x:%02x:%02x:%02x:%02x\n", __FUNCTION__,
-                            s->bd_addr.b[0], s->bd_addr.b[1], s->bd_addr.b[2],
-                            s->bd_addr.b[3], s->bd_addr.b[4], s->bd_addr.b[5]);
-        }
-
-        rpkt = csrhci_out_packet_event(s, EVT_VENDOR, 11);
-        /* Status bytes: no error */
-        rpkt[9] = 0x00;
-        rpkt[10] = 0x00;
-        break;
-
-    default:
-        fprintf(stderr, "%s: got a bad CMD packet\n", __FUNCTION__);
-        return;
-    }
-
-    csrhci_fifo_wake(s);
-}
-
-static void csrhci_in_packet(struct csrhci_s *s, uint8_t *pkt)
-{
-    uint8_t *rpkt;
-    int opc;
-
-    switch (*pkt ++) {
-    case H4_CMD_PKT:
-        opc = le16_to_cpu(((struct hci_command_hdr *) pkt)->opcode);
-        if (cmd_opcode_ogf(opc) == OGF_VENDOR_CMD) {
-            csrhci_in_packet_vendor(s, cmd_opcode_ocf(opc),
-                            pkt + sizeof(struct hci_command_hdr),
-                            s->in_len - sizeof(struct hci_command_hdr) - 1);
-            return;
-        }
-
-        /* TODO: if the command is OCF_READ_LOCAL_COMMANDS or the likes,
-         * we need to send it to the HCI layer and then add our supported
-         * commands to the returned mask (such as OGF_VENDOR_CMD).  With
-         * bt-hci.c we could just have hooks for this kind of commands but
-         * we can't with bt-host.c.  */
-
-        s->hci->cmd_send(s->hci, pkt, s->in_len - 1);
-        break;
-
-    case H4_EVT_PKT:
-        goto bad_pkt;
-
-    case H4_ACL_PKT:
-        s->hci->acl_send(s->hci, pkt, s->in_len - 1);
-        break;
-
-    case H4_SCO_PKT:
-        s->hci->sco_send(s->hci, pkt, s->in_len - 1);
-        break;
-
-    case H4_NEG_PKT:
-        if (s->in_hdr != sizeof(csrhci_neg_packet) ||
-                        memcmp(pkt - 1, csrhci_neg_packet, s->in_hdr)) {
-            fprintf(stderr, "%s: got a bad NEG packet\n", __FUNCTION__);
-            return;
-        }
-        pkt += 2;
-
-        rpkt = csrhci_out_packet_csr(s, H4_NEG_PKT, 10);
-
-        *rpkt ++ = 0x20;       /* Operational settings negotiation Ok */
-        memcpy(rpkt, pkt, 7); rpkt += 7;
-        *rpkt ++ = 0xff;
-        *rpkt = 0xff;
-        break;
-
-    case H4_ALIVE_PKT:
-        if (s->in_hdr != 4 || pkt[1] != 0x55 || pkt[2] != 0x00) {
-            fprintf(stderr, "%s: got a bad ALIVE packet\n", __FUNCTION__);
-            return;
-        }
-
-        rpkt = csrhci_out_packet_csr(s, H4_ALIVE_PKT, 2);
-
-        *rpkt ++ = 0xcc;
-        *rpkt = 0x00;
-        break;
-
-    default:
-    bad_pkt:
-        /* TODO: error out */
-        fprintf(stderr, "%s: got a bad packet\n", __FUNCTION__);
-        break;
-    }
-
-    csrhci_fifo_wake(s);
-}
-
-static int csrhci_header_len(const uint8_t *pkt)
-{
-    switch (pkt[0]) {
-    case H4_CMD_PKT:
-        return HCI_COMMAND_HDR_SIZE;
-    case H4_EVT_PKT:
-        return HCI_EVENT_HDR_SIZE;
-    case H4_ACL_PKT:
-        return HCI_ACL_HDR_SIZE;
-    case H4_SCO_PKT:
-        return HCI_SCO_HDR_SIZE;
-    case H4_NEG_PKT:
-        return pkt[1] + 1;
-    case H4_ALIVE_PKT:
-        return 3;
-    }
-
-    exit(-1);
-}
-
-static int csrhci_data_len(const uint8_t *pkt)
-{
-    switch (*pkt ++) {
-    case H4_CMD_PKT:
-        /* It seems that vendor-specific command packets for H4+ are all
-         * one byte longer than indicated in the standard header.  */
-        if (le16_to_cpu(((struct hci_command_hdr *) pkt)->opcode) == 0xfc00)
-            return (((struct hci_command_hdr *) pkt)->plen + 1) & ~1;
-
-        return ((struct hci_command_hdr *) pkt)->plen;
-    case H4_EVT_PKT:
-        return ((struct hci_event_hdr *) pkt)->plen;
-    case H4_ACL_PKT:
-        return le16_to_cpu(((struct hci_acl_hdr *) pkt)->dlen);
-    case H4_SCO_PKT:
-        return ((struct hci_sco_hdr *) pkt)->dlen;
-    case H4_NEG_PKT:
-    case H4_ALIVE_PKT:
-        return 0;
-    }
-
-    exit(-1);
-}
-
-static int csrhci_write(struct CharDriverState *chr,
-                const uint8_t *buf, int len)
-{
-    struct csrhci_s *s = (struct csrhci_s *) chr->opaque;
-    int plen = s->in_len;
-
-    if (!s->enable)
-        return 0;
-
-    s->in_len += len;
-    memcpy(s->inpkt + plen, buf, len);
-
-    while (1) {
-        if (s->in_len >= 2 && plen < 2)
-            s->in_hdr = csrhci_header_len(s->inpkt) + 1;
-
-        if (s->in_len >= s->in_hdr && plen < s->in_hdr)
-            s->in_data = csrhci_data_len(s->inpkt) + s->in_hdr;
-
-        if (s->in_len >= s->in_data) {
-            csrhci_in_packet(s, s->inpkt);
-
-            memmove(s->inpkt, s->inpkt + s->in_len, s->in_len - s->in_data);
-            s->in_len -= s->in_data;
-            s->in_hdr = INT_MAX;
-            s->in_data = INT_MAX;
-            plen = 0;
-        } else
-            break;
-    }
-
-    return len;
-}
-
-static void csrhci_out_hci_packet_event(void *opaque,
-                const uint8_t *data, int len)
-{
-    struct csrhci_s *s = (struct csrhci_s *) opaque;
-    uint8_t *pkt = csrhci_out_packet(s, (len + 2) & ~1);       /* Align */
-
-    *pkt ++ = H4_EVT_PKT;
-    memcpy(pkt, data, len);
-
-    csrhci_fifo_wake(s);
-}
-
-static void csrhci_out_hci_packet_acl(void *opaque,
-                const uint8_t *data, int len)
-{
-    struct csrhci_s *s = (struct csrhci_s *) opaque;
-    uint8_t *pkt = csrhci_out_packet(s, (len + 2) & ~1);       /* Align */
-
-    *pkt ++ = H4_ACL_PKT;
-    pkt[len & ~1] = 0;
-    memcpy(pkt, data, len);
-
-    csrhci_fifo_wake(s);
-}
-
-static int csrhci_ioctl(struct CharDriverState *chr, int cmd, void *arg)
-{
-    QEMUSerialSetParams *ssp;
-    struct csrhci_s *s = (struct csrhci_s *) chr->opaque;
-    int prev_state = s->modem_state;
-
-    switch (cmd) {
-    case CHR_IOCTL_SERIAL_SET_PARAMS:
-        ssp = (QEMUSerialSetParams *) arg;
-        s->baud_delay = get_ticks_per_sec() / ssp->speed;
-        /* Moments later... (but shorter than 100ms) */
-        s->modem_state |= CHR_TIOCM_CTS;
-        break;
-
-    case CHR_IOCTL_SERIAL_GET_TIOCM:
-        *(int *) arg = s->modem_state;
-        break;
-
-    case CHR_IOCTL_SERIAL_SET_TIOCM:
-        s->modem_state = *(int *) arg;
-        if (~s->modem_state & prev_state & CHR_TIOCM_RTS)
-            s->modem_state &= ~CHR_TIOCM_CTS;
-        break;
-
-    default:
-        return -ENOTSUP;
-    }
-    return 0;
-}
-
-static void csrhci_reset(struct csrhci_s *s)
-{
-    s->out_len = 0;
-    s->out_size = FIFO_LEN;
-    s->in_len = 0;
-    s->baud_delay = get_ticks_per_sec();
-    s->enable = 0;
-    s->in_hdr = INT_MAX;
-    s->in_data = INT_MAX;
-
-    s->modem_state = 0;
-    /* After a while... (but sooner than 10ms) */
-    s->modem_state |= CHR_TIOCM_CTS;
-
-    memset(&s->bd_addr, 0, sizeof(bdaddr_t));
-}
-
-static void csrhci_out_tick(void *opaque)
-{
-    csrhci_fifo_wake((struct csrhci_s *) opaque);
-}
-
-static void csrhci_pins(void *opaque, int line, int level)
-{
-    struct csrhci_s *s = (struct csrhci_s *) opaque;
-    int state = s->pin_state;
-
-    s->pin_state &= ~(1 << line);
-    s->pin_state |= (!!level) << line;
-
-    if ((state & ~s->pin_state) & (1 << csrhci_pin_reset)) {
-        /* TODO: Disappear from lower layers */
-        csrhci_reset(s);
-    }
-
-    if (s->pin_state == 3 && state != 3) {
-        s->enable = 1;
-        /* TODO: Wake lower layers up */
-    }
-}
-
-qemu_irq *csrhci_pins_get(CharDriverState *chr)
-{
-    struct csrhci_s *s = (struct csrhci_s *) chr->opaque;
-
-    return s->pins;
-}
-
-CharDriverState *uart_hci_init(qemu_irq wakeup)
-{
-    struct csrhci_s *s = (struct csrhci_s *)
-            g_malloc0(sizeof(struct csrhci_s));
-
-    s->chr.opaque = s;
-    s->chr.chr_write = csrhci_write;
-    s->chr.chr_ioctl = csrhci_ioctl;
-    s->chr.avail_connections = 1;
-
-    s->hci = qemu_next_hci();
-    s->hci->opaque = s;
-    s->hci->evt_recv = csrhci_out_hci_packet_event;
-    s->hci->acl_recv = csrhci_out_hci_packet_acl;
-
-    s->out_tm = qemu_new_timer_ns(vm_clock, csrhci_out_tick, s);
-    s->pins = qemu_allocate_irqs(csrhci_pins, s, __csrhci_pins);
-    csrhci_reset(s);
-
-    return &s->chr;
-}
diff --git a/hw/bt-hci.c b/hw/bt-hci.c
deleted file mode 100644 (file)
index a76edea..0000000
+++ /dev/null
@@ -1,2217 +0,0 @@
-/*
- * QEMU Bluetooth HCI logic.
- *
- * Copyright (C) 2007 OpenMoko, Inc.
- * Copyright (C) 2008 Andrzej Zaborowski  <balrog@zabor.org>
- *
- * 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 "qemu/timer.h"
-#include "hw/usb.h"
-#include "bt/bt.h"
-#include "hw/bt.h"
-
-struct bt_hci_s {
-    uint8_t *(*evt_packet)(void *opaque);
-    void (*evt_submit)(void *opaque, int len);
-    void *opaque;
-    uint8_t evt_buf[256];
-
-    uint8_t acl_buf[4096];
-    int acl_len;
-
-    uint16_t asb_handle;
-    uint16_t psb_handle;
-
-    int last_cmd;      /* Note: Always little-endian */
-
-    struct bt_device_s *conn_req_host;
-
-    struct {
-        int inquire;
-        int periodic;
-        int responses_left;
-        int responses;
-        QEMUTimer *inquiry_done;
-        QEMUTimer *inquiry_next;
-        int inquiry_length;
-        int inquiry_period;
-        int inquiry_mode;
-
-#define HCI_HANDLE_OFFSET      0x20
-#define HCI_HANDLES_MAX                0x10
-        struct bt_hci_master_link_s {
-            struct bt_link_s *link;
-            void (*lmp_acl_data)(struct bt_link_s *link,
-                            const uint8_t *data, int start, int len);
-            QEMUTimer *acl_mode_timer;
-        } handle[HCI_HANDLES_MAX];
-        uint32_t role_bmp;
-        int last_handle;
-        int connecting;
-        bdaddr_t awaiting_bdaddr[HCI_HANDLES_MAX];
-    } lm;
-
-    uint8_t event_mask[8];
-    uint16_t voice_setting;    /* Notw: Always little-endian */
-    uint16_t conn_accept_tout;
-    QEMUTimer *conn_accept_timer;
-
-    struct HCIInfo info;
-    struct bt_device_s device;
-};
-
-#define DEFAULT_RSSI_DBM       20
-
-#define hci_from_info(ptr)     container_of((ptr), struct bt_hci_s, info)
-#define hci_from_device(ptr)   container_of((ptr), struct bt_hci_s, device)
-
-struct bt_hci_link_s {
-    struct bt_link_s btlink;
-    uint16_t handle;   /* Local */
-};
-
-/* LMP layer emulation */
-#if 0
-static void bt_submit_lmp(struct bt_device_s *bt, int length, uint8_t *data)
-{
-    int resp, resplen, error, op, tr;
-    uint8_t respdata[17];
-
-    if (length < 1)
-        return;
-
-    tr = *data & 1;
-    op = *(data ++) >> 1;
-    resp = LMP_ACCEPTED;
-    resplen = 2;
-    respdata[1] = op;
-    error = 0;
-    length --;
-
-    if (op >= 0x7c) {  /* Extended opcode */
-        op |= *(data ++) << 8;
-        resp = LMP_ACCEPTED_EXT;
-        resplen = 4;
-        respdata[0] = op >> 8;
-        respdata[1] = op & 0xff;
-        length --;
-    }
-
-    switch (op) {
-    case LMP_ACCEPTED:
-        /* data[0]     Op code
-         */
-        if (length < 1) {
-            error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
-            goto not_accepted;
-        }
-        resp = 0;
-        break;
-
-    case LMP_ACCEPTED_EXT:
-        /* data[0]     Escape op code
-         * data[1]     Extended op code
-         */
-        if (length < 2) {
-            error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
-            goto not_accepted;
-        }
-        resp = 0;
-        break;
-
-    case LMP_NOT_ACCEPTED:
-        /* data[0]     Op code
-         * data[1]     Error code
-         */
-        if (length < 2) {
-            error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
-            goto not_accepted;
-        }
-        resp = 0;
-        break;
-
-    case LMP_NOT_ACCEPTED_EXT:
-        /* data[0]     Op code
-         * data[1]     Extended op code
-         * data[2]     Error code
-         */
-        if (length < 3) {
-            error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
-            goto not_accepted;
-        }
-        resp = 0;
-        break;
-
-    case LMP_HOST_CONNECTION_REQ:
-        break;
-
-    case LMP_SETUP_COMPLETE:
-        resp = LMP_SETUP_COMPLETE;
-        resplen = 1;
-        bt->setup = 1;
-        break;
-
-    case LMP_DETACH:
-        /* data[0]     Error code
-         */
-        if (length < 1) {
-            error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
-            goto not_accepted;
-        }
-        bt->setup = 0;
-        resp = 0;
-        break;
-
-    case LMP_SUPERVISION_TIMEOUT:
-        /* data[0,1]   Supervision timeout
-         */
-        if (length < 2) {
-            error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
-            goto not_accepted;
-        }
-        resp = 0;
-        break;
-
-    case LMP_QUALITY_OF_SERVICE:
-        resp = 0;
-        /* Fall through */
-    case LMP_QOS_REQ:
-        /* data[0,1]   Poll interval
-         * data[2]     N(BC)
-         */
-        if (length < 3) {
-            error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
-            goto not_accepted;
-        }
-        break;
-
-    case LMP_MAX_SLOT:
-        resp = 0;
-        /* Fall through */
-    case LMP_MAX_SLOT_REQ:
-        /* data[0]     Max slots
-         */
-        if (length < 1) {
-            error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
-            goto not_accepted;
-        }
-        break;
-
-    case LMP_AU_RAND:
-    case LMP_IN_RAND:
-    case LMP_COMB_KEY:
-        /* data[0-15]  Random number
-         */
-        if (length < 16) {
-            error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
-            goto not_accepted;
-        }
-        if (op == LMP_AU_RAND) {
-            if (bt->key_present) {
-                resp = LMP_SRES;
-                resplen = 5;
-                /* XXX: [Part H] Section 6.1 on page 801 */
-            } else {
-                error = HCI_PIN_OR_KEY_MISSING;
-                goto not_accepted;
-            }
-        } else if (op == LMP_IN_RAND) {
-            error = HCI_PAIRING_NOT_ALLOWED;
-            goto not_accepted;
-        } else {
-            /* XXX: [Part H] Section 3.2 on page 779 */
-            resp = LMP_UNIT_KEY;
-            resplen = 17;
-            memcpy(respdata + 1, bt->key, 16);
-
-            error = HCI_UNIT_LINK_KEY_USED;
-            goto not_accepted;
-        }
-        break;
-
-    case LMP_UNIT_KEY:
-        /* data[0-15]  Key
-         */
-        if (length < 16) {
-            error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
-            goto not_accepted;
-        }
-        memcpy(bt->key, data, 16);
-        bt->key_present = 1;
-        break;
-
-    case LMP_SRES:
-        /* data[0-3]   Authentication response
-         */
-        if (length < 4) {
-            error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
-            goto not_accepted;
-        }
-        break;
-
-    case LMP_CLKOFFSET_REQ:
-        resp = LMP_CLKOFFSET_RES;
-        resplen = 3;
-        respdata[1] = 0x33;
-        respdata[2] = 0x33;
-        break;
-
-    case LMP_CLKOFFSET_RES:
-        /* data[0,1]   Clock offset
-         * (Slave to master only)
-         */
-        if (length < 2) {
-            error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
-            goto not_accepted;
-        }
-        break;
-
-    case LMP_VERSION_REQ:
-    case LMP_VERSION_RES:
-        /* data[0]     VersNr
-         * data[1,2]   CompId
-         * data[3,4]   SubVersNr
-         */
-        if (length < 5) {
-            error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
-            goto not_accepted;
-        }
-        if (op == LMP_VERSION_REQ) {
-            resp = LMP_VERSION_RES;
-            resplen = 6;
-            respdata[1] = 0x20;
-            respdata[2] = 0xff;
-            respdata[3] = 0xff;
-            respdata[4] = 0xff;
-            respdata[5] = 0xff;
-        } else
-            resp = 0;
-        break;
-
-    case LMP_FEATURES_REQ:
-    case LMP_FEATURES_RES:
-        /* data[0-7]   Features
-         */
-        if (length < 8) {
-            error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
-            goto not_accepted;
-        }
-        if (op == LMP_FEATURES_REQ) {
-            resp = LMP_FEATURES_RES;
-            resplen = 9;
-            respdata[1] = (bt->lmp_caps >> 0) & 0xff;
-            respdata[2] = (bt->lmp_caps >> 8) & 0xff;
-            respdata[3] = (bt->lmp_caps >> 16) & 0xff;
-            respdata[4] = (bt->lmp_caps >> 24) & 0xff;
-            respdata[5] = (bt->lmp_caps >> 32) & 0xff;
-            respdata[6] = (bt->lmp_caps >> 40) & 0xff;
-            respdata[7] = (bt->lmp_caps >> 48) & 0xff;
-            respdata[8] = (bt->lmp_caps >> 56) & 0xff;
-        } else
-            resp = 0;
-        break;
-
-    case LMP_NAME_REQ:
-        /* data[0]     Name offset
-         */
-        if (length < 1) {
-            error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
-            goto not_accepted;
-        }
-        resp = LMP_NAME_RES;
-        resplen = 17;
-        respdata[1] = data[0];
-        respdata[2] = strlen(bt->lmp_name);
-        memset(respdata + 3, 0x00, 14);
-        if (respdata[2] > respdata[1])
-            memcpy(respdata + 3, bt->lmp_name + respdata[1],
-                            respdata[2] - respdata[1]);
-        break;
-
-    case LMP_NAME_RES:
-        /* data[0]     Name offset
-         * data[1]     Name length
-         * data[2-15]  Name fragment
-         */
-        if (length < 16) {
-            error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
-            goto not_accepted;
-        }
-        resp = 0;
-        break;
-
-    default:
-        error = HCI_UNKNOWN_LMP_PDU;
-        /* Fall through */
-    not_accepted:
-        if (op >> 8) {
-            resp = LMP_NOT_ACCEPTED_EXT;
-            resplen = 5;
-            respdata[0] = op >> 8;
-            respdata[1] = op & 0xff;
-            respdata[2] = error;
-        } else {
-            resp = LMP_NOT_ACCEPTED;
-            resplen = 3;
-            respdata[0] = op & 0xff;
-            respdata[1] = error;
-        }
-    }
-
-    if (resp == 0)
-        return;
-
-    if (resp >> 8) {
-        respdata[0] = resp >> 8;
-        respdata[1] = resp & 0xff;
-    } else
-        respdata[0] = resp & 0xff;
-
-    respdata[0] <<= 1;
-    respdata[0] |= tr;
-}
-
-static void bt_submit_raw_acl(struct bt_piconet_s *net, int length, uint8_t *data)
-{
-    struct bt_device_s *slave;
-    if (length < 1)
-        return;
-
-    slave = 0;
-#if 0
-    slave = net->slave;
-#endif
-
-    switch (data[0] & 3) {
-    case LLID_ACLC:
-        bt_submit_lmp(slave, length - 1, data + 1);
-        break;
-    case LLID_ACLU_START:
-#if 0
-        bt_sumbit_l2cap(slave, length - 1, data + 1, (data[0] >> 2) & 1);
-        breka;
-#endif
-    default:
-    case LLID_ACLU_CONT:
-        break;
-    }
-}
-#endif
-
-/* HCI layer emulation */
-
-/* Note: we could ignore endiannes because unswapped handles will still
- * be valid as connection identifiers for the guest - they don't have to
- * be continuously allocated.  We do it though, to preserve similar
- * behaviour between hosts.  Some things, like the BD_ADDR cannot be
- * preserved though (for example if a real hci is used).  */
-#ifdef HOST_WORDS_BIGENDIAN
-# define HNDL(raw)     bswap16(raw)
-#else
-# define HNDL(raw)     (raw)
-#endif
-
-static const uint8_t bt_event_reserved_mask[8] = {
-    0xff, 0x9f, 0xfb, 0xff, 0x07, 0x18, 0x00, 0x00,
-};
-
-static inline uint8_t *bt_hci_event_start(struct bt_hci_s *hci,
-                int evt, int len)
-{
-    uint8_t *packet, mask;
-    int mask_byte;
-
-    if (len > 255) {
-        fprintf(stderr, "%s: HCI event params too long (%ib)\n",
-                        __FUNCTION__, len);
-        exit(-1);
-    }
-
-    mask_byte = (evt - 1) >> 3;
-    mask = 1 << ((evt - 1) & 3);
-    if (mask & bt_event_reserved_mask[mask_byte] & ~hci->event_mask[mask_byte])
-        return NULL;
-
-    packet = hci->evt_packet(hci->opaque);
-    packet[0] = evt;
-    packet[1] = len;
-
-    return &packet[2];
-}
-
-static inline void bt_hci_event(struct bt_hci_s *hci, int evt,
-                void *params, int len)
-{
-    uint8_t *packet = bt_hci_event_start(hci, evt, len);
-
-    if (!packet)
-        return;
-
-    if (len)
-        memcpy(packet, params, len);
-
-    hci->evt_submit(hci->opaque, len + 2);
-}
-
-static inline void bt_hci_event_status(struct bt_hci_s *hci, int status)
-{
-    evt_cmd_status params = {
-        .status        = status,
-        .ncmd  = 1,
-        .opcode        = hci->last_cmd,
-    };
-
-    bt_hci_event(hci, EVT_CMD_STATUS, &params, EVT_CMD_STATUS_SIZE);
-}
-
-static inline void bt_hci_event_complete(struct bt_hci_s *hci,
-                void *ret, int len)
-{
-    uint8_t *packet = bt_hci_event_start(hci, EVT_CMD_COMPLETE,
-                    len + EVT_CMD_COMPLETE_SIZE);
-    evt_cmd_complete *params = (evt_cmd_complete *) packet;
-
-    if (!packet)
-        return;
-
-    params->ncmd       = 1;
-    params->opcode     = hci->last_cmd;
-    if (len)
-        memcpy(&packet[EVT_CMD_COMPLETE_SIZE], ret, len);
-
-    hci->evt_submit(hci->opaque, len + EVT_CMD_COMPLETE_SIZE + 2);
-}
-
-static void bt_hci_inquiry_done(void *opaque)
-{
-    struct bt_hci_s *hci = (struct bt_hci_s *) opaque;
-    uint8_t status = HCI_SUCCESS;
-
-    if (!hci->lm.periodic)
-        hci->lm.inquire = 0;
-
-    /* The specification is inconsistent about this one.  Page 565 reads
-     * "The event parameters of Inquiry Complete event will have a summary
-     * of the result from the Inquiry process, which reports the number of
-     * nearby Bluetooth devices that responded [so hci->responses].", but
-     * Event Parameters (see page 729) has only Status.  */
-    bt_hci_event(hci, EVT_INQUIRY_COMPLETE, &status, 1);
-}
-
-static void bt_hci_inquiry_result_standard(struct bt_hci_s *hci,
-                struct bt_device_s *slave)
-{
-    inquiry_info params = {
-        .num_responses         = 1,
-        .bdaddr                        = BAINIT(&slave->bd_addr),
-        .pscan_rep_mode                = 0x00, /* R0 */
-        .pscan_period_mode     = 0x00, /* P0 - deprecated */
-        .pscan_mode            = 0x00, /* Standard scan - deprecated */
-        .dev_class[0]          = slave->class[0],
-        .dev_class[1]          = slave->class[1],
-        .dev_class[2]          = slave->class[2],
-        /* TODO: return the clkoff *differenece* */
-        .clock_offset          = slave->clkoff,        /* Note: no swapping */
-    };
-
-    bt_hci_event(hci, EVT_INQUIRY_RESULT, &params, INQUIRY_INFO_SIZE);
-}
-
-static void bt_hci_inquiry_result_with_rssi(struct bt_hci_s *hci,
-                struct bt_device_s *slave)
-{
-    inquiry_info_with_rssi params = {
-        .num_responses         = 1,
-        .bdaddr                        = BAINIT(&slave->bd_addr),
-        .pscan_rep_mode                = 0x00, /* R0 */
-        .pscan_period_mode     = 0x00, /* P0 - deprecated */
-        .dev_class[0]          = slave->class[0],
-        .dev_class[1]          = slave->class[1],
-        .dev_class[2]          = slave->class[2],
-        /* TODO: return the clkoff *differenece* */
-        .clock_offset          = slave->clkoff,        /* Note: no swapping */
-        .rssi                  = DEFAULT_RSSI_DBM,
-    };
-
-    bt_hci_event(hci, EVT_INQUIRY_RESULT_WITH_RSSI,
-                    &params, INQUIRY_INFO_WITH_RSSI_SIZE);
-}
-
-static void bt_hci_inquiry_result(struct bt_hci_s *hci,
-                struct bt_device_s *slave)
-{
-    if (!slave->inquiry_scan || !hci->lm.responses_left)
-        return;
-
-    hci->lm.responses_left --;
-    hci->lm.responses ++;
-
-    switch (hci->lm.inquiry_mode) {
-    case 0x00:
-        bt_hci_inquiry_result_standard(hci, slave);
-        return;
-    case 0x01:
-        bt_hci_inquiry_result_with_rssi(hci, slave);
-        return;
-    default:
-        fprintf(stderr, "%s: bad inquiry mode %02x\n", __FUNCTION__,
-                        hci->lm.inquiry_mode);
-        exit(-1);
-    }
-}
-
-static void bt_hci_mod_timer_1280ms(QEMUTimer *timer, int period)
-{
-    qemu_mod_timer(timer, qemu_get_clock_ns(vm_clock) +
-                   muldiv64(period << 7, get_ticks_per_sec(), 100));
-}
-
-static void bt_hci_inquiry_start(struct bt_hci_s *hci, int length)
-{
-    struct bt_device_s *slave;
-
-    hci->lm.inquiry_length = length;
-    for (slave = hci->device.net->slave; slave; slave = slave->next)
-        /* Don't uncover ourselves.  */
-        if (slave != &hci->device)
-            bt_hci_inquiry_result(hci, slave);
-
-    /* TODO: register for a callback on a new device's addition to the
-     * scatternet so that if it's added before inquiry_length expires,
-     * an Inquiry Result is generated immediately.  Alternatively re-loop
-     * through the devices on the inquiry_length expiration and report
-     * devices not seen before.  */
-    if (hci->lm.responses_left)
-        bt_hci_mod_timer_1280ms(hci->lm.inquiry_done, hci->lm.inquiry_length);
-    else
-        bt_hci_inquiry_done(hci);
-
-    if (hci->lm.periodic)
-        bt_hci_mod_timer_1280ms(hci->lm.inquiry_next, hci->lm.inquiry_period);
-}
-
-static void bt_hci_inquiry_next(void *opaque)
-{
-    struct bt_hci_s *hci = (struct bt_hci_s *) opaque;
-
-    hci->lm.responses_left += hci->lm.responses;
-    hci->lm.responses = 0;
-    bt_hci_inquiry_start(hci,  hci->lm.inquiry_length);
-}
-
-static inline int bt_hci_handle_bad(struct bt_hci_s *hci, uint16_t handle)
-{
-    return !(handle & HCI_HANDLE_OFFSET) ||
-            handle >= (HCI_HANDLE_OFFSET | HCI_HANDLES_MAX) ||
-            !hci->lm.handle[handle & ~HCI_HANDLE_OFFSET].link;
-}
-
-static inline int bt_hci_role_master(struct bt_hci_s *hci, uint16_t handle)
-{
-    return !!(hci->lm.role_bmp & (1 << (handle & ~HCI_HANDLE_OFFSET)));
-}
-
-static inline struct bt_device_s *bt_hci_remote_dev(struct bt_hci_s *hci,
-                uint16_t handle)
-{
-    struct bt_link_s *link = hci->lm.handle[handle & ~HCI_HANDLE_OFFSET].link;
-
-    return bt_hci_role_master(hci, handle) ? link->slave : link->host;
-}
-
-static void bt_hci_mode_tick(void *opaque);
-static void bt_hci_lmp_link_establish(struct bt_hci_s *hci,
-                struct bt_link_s *link, int master)
-{
-    hci->lm.handle[hci->lm.last_handle].link = link;
-
-    if (master) {
-        /* We are the master side of an ACL link */
-        hci->lm.role_bmp |= 1 << hci->lm.last_handle;
-
-        hci->lm.handle[hci->lm.last_handle].lmp_acl_data =
-                link->slave->lmp_acl_data;
-    } else {
-        /* We are the slave side of an ACL link */
-        hci->lm.role_bmp &= ~(1 << hci->lm.last_handle);
-
-        hci->lm.handle[hci->lm.last_handle].lmp_acl_data =
-                link->host->lmp_acl_resp;
-    }
-
-    /* Mode */
-    if (master) {
-        link->acl_mode = acl_active;
-        hci->lm.handle[hci->lm.last_handle].acl_mode_timer =
-                qemu_new_timer_ns(vm_clock, bt_hci_mode_tick, link);
-    }
-}
-
-static void bt_hci_lmp_link_teardown(struct bt_hci_s *hci, uint16_t handle)
-{
-    handle &= ~HCI_HANDLE_OFFSET;
-    hci->lm.handle[handle].link = NULL;
-
-    if (bt_hci_role_master(hci, handle)) {
-        qemu_del_timer(hci->lm.handle[handle].acl_mode_timer);
-        qemu_free_timer(hci->lm.handle[handle].acl_mode_timer);
-    }
-}
-
-static int bt_hci_connect(struct bt_hci_s *hci, bdaddr_t *bdaddr)
-{
-    struct bt_device_s *slave;
-    struct bt_link_s link;
-
-    for (slave = hci->device.net->slave; slave; slave = slave->next)
-        if (slave->page_scan && !bacmp(&slave->bd_addr, bdaddr))
-            break;
-    if (!slave || slave == &hci->device)
-        return -ENODEV;
-
-    bacpy(&hci->lm.awaiting_bdaddr[hci->lm.connecting ++], &slave->bd_addr);
-
-    link.slave = slave;
-    link.host = &hci->device;
-    link.slave->lmp_connection_request(&link); /* Always last */
-
-    return 0;
-}
-
-static void bt_hci_connection_reject(struct bt_hci_s *hci,
-                struct bt_device_s *host, uint8_t because)
-{
-    struct bt_link_s link = {
-        .slave = &hci->device,
-        .host  = host,
-        /* Rest uninitialised */
-    };
-
-    host->reject_reason = because;
-    host->lmp_connection_complete(&link);
-}
-
-static void bt_hci_connection_reject_event(struct bt_hci_s *hci,
-                bdaddr_t *bdaddr)
-{
-    evt_conn_complete params;
-
-    params.status      = HCI_NO_CONNECTION;
-    params.handle      = 0;
-    bacpy(&params.bdaddr, bdaddr);
-    params.link_type   = ACL_LINK;
-    params.encr_mode   = 0x00;         /* Encryption not required */
-    bt_hci_event(hci, EVT_CONN_COMPLETE, &params, EVT_CONN_COMPLETE_SIZE);
-}
-
-static void bt_hci_connection_accept(struct bt_hci_s *hci,
-                struct bt_device_s *host)
-{
-    struct bt_hci_link_s *link = g_malloc0(sizeof(struct bt_hci_link_s));
-    evt_conn_complete params;
-    uint16_t handle;
-    uint8_t status = HCI_SUCCESS;
-    int tries = HCI_HANDLES_MAX;
-
-    /* Make a connection handle */
-    do {
-        while (hci->lm.handle[++ hci->lm.last_handle].link && -- tries)
-            hci->lm.last_handle &= HCI_HANDLES_MAX - 1;
-        handle = hci->lm.last_handle | HCI_HANDLE_OFFSET;
-    } while ((handle == hci->asb_handle || handle == hci->psb_handle) &&
-            tries);
-
-    if (!tries) {
-        g_free(link);
-        bt_hci_connection_reject(hci, host, HCI_REJECTED_LIMITED_RESOURCES);
-        status = HCI_NO_CONNECTION;
-        goto complete;
-    }
-
-    link->btlink.slave = &hci->device;
-    link->btlink.host  = host;
-    link->handle = handle;
-
-    /* Link established */
-    bt_hci_lmp_link_establish(hci, &link->btlink, 0);
-
-complete:
-    params.status      = status;
-    params.handle      = HNDL(handle);
-    bacpy(&params.bdaddr, &host->bd_addr);
-    params.link_type   = ACL_LINK;
-    params.encr_mode   = 0x00;         /* Encryption not required */
-    bt_hci_event(hci, EVT_CONN_COMPLETE, &params, EVT_CONN_COMPLETE_SIZE);
-
-    /* Neets to be done at the very end because it can trigger a (nested)
-     * disconnected, in case the other and had cancelled the request
-     * locally.  */
-    if (status == HCI_SUCCESS) {
-        host->reject_reason = 0;
-        host->lmp_connection_complete(&link->btlink);
-    }
-}
-
-static void bt_hci_lmp_connection_request(struct bt_link_s *link)
-{
-    struct bt_hci_s *hci = hci_from_device(link->slave);
-    evt_conn_request params;
-
-    if (hci->conn_req_host) {
-        bt_hci_connection_reject(hci, link->host,
-                                 HCI_REJECTED_LIMITED_RESOURCES);
-        return;
-    }
-    hci->conn_req_host = link->host;
-    /* TODO: if masked and auto-accept, then auto-accept,
-     * if masked and not auto-accept, then auto-reject */
-    /* TODO: kick the hci->conn_accept_timer, timeout after
-     * hci->conn_accept_tout * 0.625 msec */
-
-    bacpy(&params.bdaddr, &link->host->bd_addr);
-    memcpy(&params.dev_class, &link->host->class, sizeof(params.dev_class));
-    params.link_type   = ACL_LINK;
-    bt_hci_event(hci, EVT_CONN_REQUEST, &params, EVT_CONN_REQUEST_SIZE);
-}
-
-static void bt_hci_conn_accept_timeout(void *opaque)
-{
-    struct bt_hci_s *hci = (struct bt_hci_s *) opaque;
-
-    if (!hci->conn_req_host)
-        /* Already accepted or rejected.  If the other end cancelled the
-         * connection request then we still have to reject or accept it
-         * and then we'll get a disconnect.  */
-        return;
-
-    /* TODO */
-}
-
-/* Remove from the list of devices which we wanted to connect to and
- * are awaiting a response from.  If the callback sees a response from
- * a device which is not on the list it will assume it's a connection
- * that's been cancelled by the host in the meantime and immediately
- * try to detach the link and send a Connection Complete.  */
-static int bt_hci_lmp_connection_ready(struct bt_hci_s *hci,
-                bdaddr_t *bdaddr)
-{
-    int i;
-
-    for (i = 0; i < hci->lm.connecting; i ++)
-        if (!bacmp(&hci->lm.awaiting_bdaddr[i], bdaddr)) {
-            if (i < -- hci->lm.connecting)
-                bacpy(&hci->lm.awaiting_bdaddr[i],
-                                &hci->lm.awaiting_bdaddr[hci->lm.connecting]);
-            return 0;
-        }
-
-    return 1;
-}
-
-static void bt_hci_lmp_connection_complete(struct bt_link_s *link)
-{
-    struct bt_hci_s *hci = hci_from_device(link->host);
-    evt_conn_complete params;
-    uint16_t handle;
-    uint8_t status = HCI_SUCCESS;
-    int tries = HCI_HANDLES_MAX;
-
-    if (bt_hci_lmp_connection_ready(hci, &link->slave->bd_addr)) {
-        if (!hci->device.reject_reason)
-            link->slave->lmp_disconnect_slave(link);
-        handle = 0;
-        status = HCI_NO_CONNECTION;
-        goto complete;
-    }
-
-    if (hci->device.reject_reason) {
-        handle = 0;
-        status = hci->device.reject_reason;
-        goto complete;
-    }
-
-    /* Make a connection handle */
-    do {
-        while (hci->lm.handle[++ hci->lm.last_handle].link && -- tries)
-            hci->lm.last_handle &= HCI_HANDLES_MAX - 1;
-        handle = hci->lm.last_handle | HCI_HANDLE_OFFSET;
-    } while ((handle == hci->asb_handle || handle == hci->psb_handle) &&
-            tries);
-
-    if (!tries) {
-        link->slave->lmp_disconnect_slave(link);
-        status = HCI_NO_CONNECTION;
-        goto complete;
-    }
-
-    /* Link established */
-    link->handle = handle;
-    bt_hci_lmp_link_establish(hci, link, 1);
-
-complete:
-    params.status      = status;
-    params.handle      = HNDL(handle);
-    params.link_type   = ACL_LINK;
-    bacpy(&params.bdaddr, &link->slave->bd_addr);
-    params.encr_mode   = 0x00;         /* Encryption not required */
-    bt_hci_event(hci, EVT_CONN_COMPLETE, &params, EVT_CONN_COMPLETE_SIZE);
-}
-
-static void bt_hci_disconnect(struct bt_hci_s *hci,
-                uint16_t handle, int reason)
-{
-    struct bt_link_s *btlink =
-            hci->lm.handle[handle & ~HCI_HANDLE_OFFSET].link;
-    struct bt_hci_link_s *link;
-    evt_disconn_complete params;
-
-    if (bt_hci_role_master(hci, handle)) {
-        btlink->slave->reject_reason = reason;
-        btlink->slave->lmp_disconnect_slave(btlink);
-        /* The link pointer is invalid from now on */
-
-        goto complete;
-    }
-
-    btlink->host->reject_reason = reason;
-    btlink->host->lmp_disconnect_master(btlink);
-
-    /* We are the slave, we get to clean this burden */
-    link = (struct bt_hci_link_s *) btlink;
-    g_free(link);
-
-complete:
-    bt_hci_lmp_link_teardown(hci, handle);
-
-    params.status      = HCI_SUCCESS;
-    params.handle      = HNDL(handle);
-    params.reason      = HCI_CONNECTION_TERMINATED;
-    bt_hci_event(hci, EVT_DISCONN_COMPLETE,
-                    &params, EVT_DISCONN_COMPLETE_SIZE);
-}
-
-/* TODO: use only one function */
-static void bt_hci_lmp_disconnect_host(struct bt_link_s *link)
-{
-    struct bt_hci_s *hci = hci_from_device(link->host);
-    uint16_t handle = link->handle;
-    evt_disconn_complete params;
-
-    bt_hci_lmp_link_teardown(hci, handle);
-
-    params.status      = HCI_SUCCESS;
-    params.handle      = HNDL(handle);
-    params.reason      = hci->device.reject_reason;
-    bt_hci_event(hci, EVT_DISCONN_COMPLETE,
-                    &params, EVT_DISCONN_COMPLETE_SIZE);
-}
-
-static void bt_hci_lmp_disconnect_slave(struct bt_link_s *btlink)
-{
-    struct bt_hci_link_s *link = (struct bt_hci_link_s *) btlink;
-    struct bt_hci_s *hci = hci_from_device(btlink->slave);
-    uint16_t handle = link->handle;
-    evt_disconn_complete params;
-
-    g_free(link);
-
-    bt_hci_lmp_link_teardown(hci, handle);
-
-    params.status      = HCI_SUCCESS;
-    params.handle      = HNDL(handle);
-    params.reason      = hci->device.reject_reason;
-    bt_hci_event(hci, EVT_DISCONN_COMPLETE,
-                    &params, EVT_DISCONN_COMPLETE_SIZE);
-}
-
-static int bt_hci_name_req(struct bt_hci_s *hci, bdaddr_t *bdaddr)
-{
-    struct bt_device_s *slave;
-    evt_remote_name_req_complete params;
-
-    for (slave = hci->device.net->slave; slave; slave = slave->next)
-        if (slave->page_scan && !bacmp(&slave->bd_addr, bdaddr))
-            break;
-    if (!slave)
-        return -ENODEV;
-
-    bt_hci_event_status(hci, HCI_SUCCESS);
-
-    params.status       = HCI_SUCCESS;
-    bacpy(&params.bdaddr, &slave->bd_addr);
-    pstrcpy(params.name, sizeof(params.name), slave->lmp_name ?: "");
-    bt_hci_event(hci, EVT_REMOTE_NAME_REQ_COMPLETE,
-                    &params, EVT_REMOTE_NAME_REQ_COMPLETE_SIZE);
-
-    return 0;
-}
-
-static int bt_hci_features_req(struct bt_hci_s *hci, uint16_t handle)
-{
-    struct bt_device_s *slave;
-    evt_read_remote_features_complete params;
-
-    if (bt_hci_handle_bad(hci, handle))
-        return -ENODEV;
-
-    slave = bt_hci_remote_dev(hci, handle);
-
-    bt_hci_event_status(hci, HCI_SUCCESS);
-
-    params.status      = HCI_SUCCESS;
-    params.handle      = HNDL(handle);
-    params.features[0] = (slave->lmp_caps >>  0) & 0xff;
-    params.features[1] = (slave->lmp_caps >>  8) & 0xff;
-    params.features[2] = (slave->lmp_caps >> 16) & 0xff;
-    params.features[3] = (slave->lmp_caps >> 24) & 0xff;
-    params.features[4] = (slave->lmp_caps >> 32) & 0xff;
-    params.features[5] = (slave->lmp_caps >> 40) & 0xff;
-    params.features[6] = (slave->lmp_caps >> 48) & 0xff;
-    params.features[7] = (slave->lmp_caps >> 56) & 0xff;
-    bt_hci_event(hci, EVT_READ_REMOTE_FEATURES_COMPLETE,
-                    &params, EVT_READ_REMOTE_FEATURES_COMPLETE_SIZE);
-
-    return 0;
-}
-
-static int bt_hci_version_req(struct bt_hci_s *hci, uint16_t handle)
-{
-    evt_read_remote_version_complete params;
-
-    if (bt_hci_handle_bad(hci, handle))
-        return -ENODEV;
-
-    bt_hci_remote_dev(hci, handle);
-
-    bt_hci_event_status(hci, HCI_SUCCESS);
-
-    params.status      = HCI_SUCCESS;
-    params.handle      = HNDL(handle);
-    params.lmp_ver     = 0x03;
-    params.manufacturer        = cpu_to_le16(0xa000);
-    params.lmp_subver  = cpu_to_le16(0xa607);
-    bt_hci_event(hci, EVT_READ_REMOTE_VERSION_COMPLETE,
-                    &params, EVT_READ_REMOTE_VERSION_COMPLETE_SIZE);
-
-    return 0;
-}
-
-static int bt_hci_clkoffset_req(struct bt_hci_s *hci, uint16_t handle)
-{
-    struct bt_device_s *slave;
-    evt_read_clock_offset_complete params;
-
-    if (bt_hci_handle_bad(hci, handle))
-        return -ENODEV;
-
-    slave = bt_hci_remote_dev(hci, handle);
-
-    bt_hci_event_status(hci, HCI_SUCCESS);
-
-    params.status      = HCI_SUCCESS;
-    params.handle      = HNDL(handle);
-    /* TODO: return the clkoff *differenece* */
-    params.clock_offset        = slave->clkoff;        /* Note: no swapping */
-    bt_hci_event(hci, EVT_READ_CLOCK_OFFSET_COMPLETE,
-                    &params, EVT_READ_CLOCK_OFFSET_COMPLETE_SIZE);
-
-    return 0;
-}
-
-static void bt_hci_event_mode(struct bt_hci_s *hci, struct bt_link_s *link,
-                uint16_t handle)
-{
-    evt_mode_change params = {
-        .status                = HCI_SUCCESS,
-        .handle                = HNDL(handle),
-        .mode          = link->acl_mode,
-        .interval      = cpu_to_le16(link->acl_interval),
-    };
-
-    bt_hci_event(hci, EVT_MODE_CHANGE, &params, EVT_MODE_CHANGE_SIZE);
-}
-
-static void bt_hci_lmp_mode_change_master(struct bt_hci_s *hci,
-                struct bt_link_s *link, int mode, uint16_t interval)
-{
-    link->acl_mode = mode;
-    link->acl_interval = interval;
-
-    bt_hci_event_mode(hci, link, link->handle);
-
-    link->slave->lmp_mode_change(link);
-}
-
-static void bt_hci_lmp_mode_change_slave(struct bt_link_s *btlink)
-{
-    struct bt_hci_link_s *link = (struct bt_hci_link_s *) btlink;
-    struct bt_hci_s *hci = hci_from_device(btlink->slave);
-
-    bt_hci_event_mode(hci, btlink, link->handle);
-}
-
-static int bt_hci_mode_change(struct bt_hci_s *hci, uint16_t handle,
-                int interval, int mode)
-{
-    struct bt_hci_master_link_s *link;
-
-    if (bt_hci_handle_bad(hci, handle) || !bt_hci_role_master(hci, handle))
-        return -ENODEV;
-
-    link = &hci->lm.handle[handle & ~HCI_HANDLE_OFFSET];
-    if (link->link->acl_mode != acl_active) {
-        bt_hci_event_status(hci, HCI_COMMAND_DISALLOWED);
-        return 0;
-    }
-
-    bt_hci_event_status(hci, HCI_SUCCESS);
-
-    qemu_mod_timer(link->acl_mode_timer, qemu_get_clock_ns(vm_clock) +
-                   muldiv64(interval * 625, get_ticks_per_sec(), 1000000));
-    bt_hci_lmp_mode_change_master(hci, link->link, mode, interval);
-
-    return 0;
-}
-
-static int bt_hci_mode_cancel(struct bt_hci_s *hci, uint16_t handle, int mode)
-{
-    struct bt_hci_master_link_s *link;
-
-    if (bt_hci_handle_bad(hci, handle) || !bt_hci_role_master(hci, handle))
-        return -ENODEV;
-
-    link = &hci->lm.handle[handle & ~HCI_HANDLE_OFFSET];
-    if (link->link->acl_mode != mode) {
-        bt_hci_event_status(hci, HCI_COMMAND_DISALLOWED);
-
-        return 0;
-    }
-
-    bt_hci_event_status(hci, HCI_SUCCESS);
-
-    qemu_del_timer(link->acl_mode_timer);
-    bt_hci_lmp_mode_change_master(hci, link->link, acl_active, 0);
-
-    return 0;
-}
-
-static void bt_hci_mode_tick(void *opaque)
-{
-    struct bt_link_s *link = opaque;
-    struct bt_hci_s *hci = hci_from_device(link->host);
-
-    bt_hci_lmp_mode_change_master(hci, link, acl_active, 0);
-}
-
-static void bt_hci_reset(struct bt_hci_s *hci)
-{
-    hci->acl_len = 0;
-    hci->last_cmd = 0;
-    hci->lm.connecting = 0;
-
-    hci->event_mask[0] = 0xff;
-    hci->event_mask[1] = 0xff;
-    hci->event_mask[2] = 0xff;
-    hci->event_mask[3] = 0xff;
-    hci->event_mask[4] = 0xff;
-    hci->event_mask[5] = 0x1f;
-    hci->event_mask[6] = 0x00;
-    hci->event_mask[7] = 0x00;
-    hci->device.inquiry_scan = 0;
-    hci->device.page_scan = 0;
-    if (hci->device.lmp_name)
-        g_free((void *) hci->device.lmp_name);
-    hci->device.lmp_name = NULL;
-    hci->device.class[0] = 0x00;
-    hci->device.class[1] = 0x00;
-    hci->device.class[2] = 0x00;
-    hci->voice_setting = 0x0000;
-    hci->conn_accept_tout = 0x1f40;
-    hci->lm.inquiry_mode = 0x00;
-
-    hci->psb_handle = 0x000;
-    hci->asb_handle = 0x000;
-
-    /* XXX: qemu_del_timer(sl->acl_mode_timer); for all links */
-    qemu_del_timer(hci->lm.inquiry_done);
-    qemu_del_timer(hci->lm.inquiry_next);
-    qemu_del_timer(hci->conn_accept_timer);
-}
-
-static void bt_hci_read_local_version_rp(struct bt_hci_s *hci)
-{
-    read_local_version_rp lv = {
-        .status                = HCI_SUCCESS,
-        .hci_ver       = 0x03,
-        .hci_rev       = cpu_to_le16(0xa607),
-        .lmp_ver       = 0x03,
-        .manufacturer  = cpu_to_le16(0xa000),
-        .lmp_subver    = cpu_to_le16(0xa607),
-    };
-
-    bt_hci_event_complete(hci, &lv, READ_LOCAL_VERSION_RP_SIZE);
-}
-
-static void bt_hci_read_local_commands_rp(struct bt_hci_s *hci)
-{
-    read_local_commands_rp lc = {
-        .status                = HCI_SUCCESS,
-        .commands      = {
-            /* Keep updated! */
-            /* Also, keep in sync with hci->device.lmp_caps in bt_new_hci */
-            0xbf, 0x80, 0xf9, 0x03, 0xb2, 0xc0, 0x03, 0xc3,
-            0x00, 0x0f, 0x80, 0x00, 0xc0, 0x00, 0xe8, 0x13,
-            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        },
-    };
-
-    bt_hci_event_complete(hci, &lc, READ_LOCAL_COMMANDS_RP_SIZE);
-}
-
-static void bt_hci_read_local_features_rp(struct bt_hci_s *hci)
-{
-    read_local_features_rp lf = {
-        .status                = HCI_SUCCESS,
-        .features      = {
-            (hci->device.lmp_caps >>  0) & 0xff,
-            (hci->device.lmp_caps >>  8) & 0xff,
-            (hci->device.lmp_caps >> 16) & 0xff,
-            (hci->device.lmp_caps >> 24) & 0xff,
-            (hci->device.lmp_caps >> 32) & 0xff,
-            (hci->device.lmp_caps >> 40) & 0xff,
-            (hci->device.lmp_caps >> 48) & 0xff,
-            (hci->device.lmp_caps >> 56) & 0xff,
-        },
-    };
-
-    bt_hci_event_complete(hci, &lf, READ_LOCAL_FEATURES_RP_SIZE);
-}
-
-static void bt_hci_read_local_ext_features_rp(struct bt_hci_s *hci, int page)
-{
-    read_local_ext_features_rp lef = {
-        .status                = HCI_SUCCESS,
-        .page_num      = page,
-        .max_page_num  = 0x00,
-        .features      = {
-            /* Keep updated! */
-            0x5f, 0x35, 0x85, 0x7e, 0x9b, 0x19, 0x00, 0x80,
-        },
-    };
-    if (page)
-        memset(lef.features, 0, sizeof(lef.features));
-
-    bt_hci_event_complete(hci, &lef, READ_LOCAL_EXT_FEATURES_RP_SIZE);
-}
-
-static void bt_hci_read_buffer_size_rp(struct bt_hci_s *hci)
-{
-    read_buffer_size_rp bs = {
-        /* This can be made configurable, for one standard USB dongle HCI
-         * the four values are cpu_to_le16(0x0180), 0x40,
-         * cpu_to_le16(0x0008), cpu_to_le16(0x0008).  */
-        .status                = HCI_SUCCESS,
-        .acl_mtu       = cpu_to_le16(0x0200),
-        .sco_mtu       = 0,
-        .acl_max_pkt   = cpu_to_le16(0x0001),
-        .sco_max_pkt   = cpu_to_le16(0x0000),
-    };
-
-    bt_hci_event_complete(hci, &bs, READ_BUFFER_SIZE_RP_SIZE);
-}
-
-/* Deprecated in V2.0 (page 661) */
-static void bt_hci_read_country_code_rp(struct bt_hci_s *hci)
-{
-    read_country_code_rp cc ={
-        .status                = HCI_SUCCESS,
-        .country_code  = 0x00, /* North America & Europe^1 and Japan */
-    };
-
-    bt_hci_event_complete(hci, &cc, READ_COUNTRY_CODE_RP_SIZE);
-
-    /* ^1. Except France, sorry */
-}
-
-static void bt_hci_read_bd_addr_rp(struct bt_hci_s *hci)
-{
-    read_bd_addr_rp ba = {
-        .status = HCI_SUCCESS,
-        .bdaddr = BAINIT(&hci->device.bd_addr),
-    };
-
-    bt_hci_event_complete(hci, &ba, READ_BD_ADDR_RP_SIZE);
-}
-
-static int bt_hci_link_quality_rp(struct bt_hci_s *hci, uint16_t handle)
-{
-    read_link_quality_rp lq = {
-        .status                = HCI_SUCCESS,
-        .handle                = HNDL(handle),
-        .link_quality  = 0xff,
-    };
-
-    if (bt_hci_handle_bad(hci, handle))
-        lq.status = HCI_NO_CONNECTION;
-
-    bt_hci_event_complete(hci, &lq, READ_LINK_QUALITY_RP_SIZE);
-    return 0;
-}
-
-/* Generate a Command Complete event with only the Status parameter */
-static inline void bt_hci_event_complete_status(struct bt_hci_s *hci,
-                uint8_t status)
-{
-    bt_hci_event_complete(hci, &status, 1);
-}
-
-static inline void bt_hci_event_complete_conn_cancel(struct bt_hci_s *hci,
-                uint8_t status, bdaddr_t *bd_addr)
-{
-    create_conn_cancel_rp params = {
-        .status = status,
-        .bdaddr = BAINIT(bd_addr),
-    };
-
-    bt_hci_event_complete(hci, &params, CREATE_CONN_CANCEL_RP_SIZE);
-}
-
-static inline void bt_hci_event_auth_complete(struct bt_hci_s *hci,
-                uint16_t handle)
-{
-    evt_auth_complete params = {
-        .status = HCI_SUCCESS,
-        .handle = HNDL(handle),
-    };
-
-    bt_hci_event(hci, EVT_AUTH_COMPLETE, &params, EVT_AUTH_COMPLETE_SIZE);
-}
-
-static inline void bt_hci_event_encrypt_change(struct bt_hci_s *hci,
-                uint16_t handle, uint8_t mode)
-{
-    evt_encrypt_change params = {
-        .status                = HCI_SUCCESS,
-        .handle                = HNDL(handle),
-        .encrypt       = mode,
-    };
-
-    bt_hci_event(hci, EVT_ENCRYPT_CHANGE, &params, EVT_ENCRYPT_CHANGE_SIZE);
-}
-
-static inline void bt_hci_event_complete_name_cancel(struct bt_hci_s *hci,
-                bdaddr_t *bd_addr)
-{
-    remote_name_req_cancel_rp params = {
-        .status = HCI_INVALID_PARAMETERS,
-        .bdaddr = BAINIT(bd_addr),
-    };
-
-    bt_hci_event_complete(hci, &params, REMOTE_NAME_REQ_CANCEL_RP_SIZE);
-}
-
-static inline void bt_hci_event_read_remote_ext_features(struct bt_hci_s *hci,
-                uint16_t handle)
-{
-    evt_read_remote_ext_features_complete params = {
-        .status = HCI_UNSUPPORTED_FEATURE,
-        .handle = HNDL(handle),
-        /* Rest uninitialised */
-    };
-
-    bt_hci_event(hci, EVT_READ_REMOTE_EXT_FEATURES_COMPLETE,
-                    &params, EVT_READ_REMOTE_EXT_FEATURES_COMPLETE_SIZE);
-}
-
-static inline void bt_hci_event_complete_lmp_handle(struct bt_hci_s *hci,
-                uint16_t handle)
-{
-    read_lmp_handle_rp params = {
-        .status                = HCI_NO_CONNECTION,
-        .handle                = HNDL(handle),
-        .reserved      = 0,
-        /* Rest uninitialised */
-    };
-
-    bt_hci_event_complete(hci, &params, READ_LMP_HANDLE_RP_SIZE);
-}
-
-static inline void bt_hci_event_complete_role_discovery(struct bt_hci_s *hci,
-                int status, uint16_t handle, int master)
-{
-    role_discovery_rp params = {
-        .status                = status,
-        .handle                = HNDL(handle),
-        .role          = master ? 0x00 : 0x01,
-    };
-
-    bt_hci_event_complete(hci, &params, ROLE_DISCOVERY_RP_SIZE);
-}
-
-static inline void bt_hci_event_complete_flush(struct bt_hci_s *hci,
-                int status, uint16_t handle)
-{
-    flush_rp params = {
-        .status                = status,
-        .handle                = HNDL(handle),
-    };
-
-    bt_hci_event_complete(hci, &params, FLUSH_RP_SIZE);
-}
-
-static inline void bt_hci_event_complete_read_local_name(struct bt_hci_s *hci)
-{
-    read_local_name_rp params;
-    params.status = HCI_SUCCESS;
-    memset(params.name, 0, sizeof(params.name));
-    if (hci->device.lmp_name)
-        pstrcpy(params.name, sizeof(params.name), hci->device.lmp_name);
-
-    bt_hci_event_complete(hci, &params, READ_LOCAL_NAME_RP_SIZE);
-}
-
-static inline void bt_hci_event_complete_read_conn_accept_timeout(
-                struct bt_hci_s *hci)
-{
-    read_conn_accept_timeout_rp params = {
-        .status                = HCI_SUCCESS,
-        .timeout       = cpu_to_le16(hci->conn_accept_tout),
-    };
-
-    bt_hci_event_complete(hci, &params, READ_CONN_ACCEPT_TIMEOUT_RP_SIZE);
-}
-
-static inline void bt_hci_event_complete_read_scan_enable(struct bt_hci_s *hci)
-{
-    read_scan_enable_rp params = {
-        .status = HCI_SUCCESS,
-        .enable =
-                (hci->device.inquiry_scan ? SCAN_INQUIRY : 0) |
-                (hci->device.page_scan ? SCAN_PAGE : 0),
-    };
-
-    bt_hci_event_complete(hci, &params, READ_SCAN_ENABLE_RP_SIZE);
-}
-
-static inline void bt_hci_event_complete_read_local_class(struct bt_hci_s *hci)
-{
-    read_class_of_dev_rp params;
-
-    params.status = HCI_SUCCESS;
-    memcpy(params.dev_class, hci->device.class, sizeof(params.dev_class));
-
-    bt_hci_event_complete(hci, &params, READ_CLASS_OF_DEV_RP_SIZE);
-}
-
-static inline void bt_hci_event_complete_voice_setting(struct bt_hci_s *hci)
-{
-    read_voice_setting_rp params = {
-        .status                = HCI_SUCCESS,
-        .voice_setting = hci->voice_setting,   /* Note: no swapping */
-    };
-
-    bt_hci_event_complete(hci, &params, READ_VOICE_SETTING_RP_SIZE);
-}
-
-static inline void bt_hci_event_complete_read_inquiry_mode(
-                struct bt_hci_s *hci)
-{
-    read_inquiry_mode_rp params = {
-        .status                = HCI_SUCCESS,
-        .mode          = hci->lm.inquiry_mode,
-    };
-
-    bt_hci_event_complete(hci, &params, READ_INQUIRY_MODE_RP_SIZE);
-}
-
-static inline void bt_hci_event_num_comp_pkts(struct bt_hci_s *hci,
-                uint16_t handle, int packets)
-{
-    uint16_t buf[EVT_NUM_COMP_PKTS_SIZE(1) / 2 + 1];
-    evt_num_comp_pkts *params = (void *) ((uint8_t *) buf + 1);
-
-    params->num_hndl                   = 1;
-    params->connection->handle         = HNDL(handle);
-    params->connection->num_packets    = cpu_to_le16(packets);
-
-    bt_hci_event(hci, EVT_NUM_COMP_PKTS, params, EVT_NUM_COMP_PKTS_SIZE(1));
-}
-
-static void bt_submit_hci(struct HCIInfo *info,
-                const uint8_t *data, int length)
-{
-    struct bt_hci_s *hci = hci_from_info(info);
-    uint16_t cmd;
-    int paramlen, i;
-
-    if (length < HCI_COMMAND_HDR_SIZE)
-        goto short_hci;
-
-    memcpy(&hci->last_cmd, data, 2);
-
-    cmd = (data[1] << 8) | data[0];
-    paramlen = data[2];
-    if (cmd_opcode_ogf(cmd) == 0 || cmd_opcode_ocf(cmd) == 0)  /* NOP */
-        return;
-
-    data += HCI_COMMAND_HDR_SIZE;
-    length -= HCI_COMMAND_HDR_SIZE;
-
-    if (paramlen > length)
-        return;
-
-#define PARAM(cmd, param)      (((cmd##_cp *) data)->param)
-#define PARAM16(cmd, param)    le16_to_cpup(&PARAM(cmd, param))
-#define PARAMHANDLE(cmd)       HNDL(PARAM(cmd, handle))
-#define LENGTH_CHECK(cmd)      if (length < sizeof(cmd##_cp)) goto short_hci
-    /* Note: the supported commands bitmask in bt_hci_read_local_commands_rp
-     * needs to be updated every time a command is implemented here!  */
-    switch (cmd) {
-    case cmd_opcode_pack(OGF_LINK_CTL, OCF_INQUIRY):
-        LENGTH_CHECK(inquiry);
-
-        if (PARAM(inquiry, length) < 1) {
-            bt_hci_event_complete_status(hci, HCI_INVALID_PARAMETERS);
-            break;
-        }
-
-        hci->lm.inquire = 1;
-        hci->lm.periodic = 0;
-        hci->lm.responses_left = PARAM(inquiry, num_rsp) ?: INT_MAX;
-        hci->lm.responses = 0;
-        bt_hci_event_status(hci, HCI_SUCCESS);
-        bt_hci_inquiry_start(hci, PARAM(inquiry, length));
-        break;
-
-    case cmd_opcode_pack(OGF_LINK_CTL, OCF_INQUIRY_CANCEL):
-        if (!hci->lm.inquire || hci->lm.periodic) {
-            fprintf(stderr, "%s: Inquiry Cancel should only be issued after "
-                            "the Inquiry command has been issued, a Command "
-                            "Status event has been received for the Inquiry "
-                            "command, and before the Inquiry Complete event "
-                            "occurs", __FUNCTION__);
-            bt_hci_event_complete_status(hci, HCI_COMMAND_DISALLOWED);
-            break;
-        }
-
-        hci->lm.inquire = 0;
-        qemu_del_timer(hci->lm.inquiry_done);
-        bt_hci_event_complete_status(hci, HCI_SUCCESS);
-        break;
-
-    case cmd_opcode_pack(OGF_LINK_CTL, OCF_PERIODIC_INQUIRY):
-        LENGTH_CHECK(periodic_inquiry);
-
-        if (!(PARAM(periodic_inquiry, length) <
-                                PARAM16(periodic_inquiry, min_period) &&
-                                PARAM16(periodic_inquiry, min_period) <
-                                PARAM16(periodic_inquiry, max_period)) ||
-                        PARAM(periodic_inquiry, length) < 1 ||
-                        PARAM16(periodic_inquiry, min_period) < 2 ||
-                        PARAM16(periodic_inquiry, max_period) < 3) {
-            bt_hci_event_complete_status(hci, HCI_INVALID_PARAMETERS);
-            break;
-        }
-
-        hci->lm.inquire = 1;
-        hci->lm.periodic = 1;
-        hci->lm.responses_left = PARAM(periodic_inquiry, num_rsp);
-        hci->lm.responses = 0;
-        hci->lm.inquiry_period = PARAM16(periodic_inquiry, max_period);
-        bt_hci_event_complete_status(hci, HCI_SUCCESS);
-        bt_hci_inquiry_start(hci, PARAM(periodic_inquiry, length));
-        break;
-
-    case cmd_opcode_pack(OGF_LINK_CTL, OCF_EXIT_PERIODIC_INQUIRY):
-        if (!hci->lm.inquire || !hci->lm.periodic) {
-            fprintf(stderr, "%s: Inquiry Cancel should only be issued after "
-                            "the Inquiry command has been issued, a Command "
-                            "Status event has been received for the Inquiry "
-                            "command, and before the Inquiry Complete event "
-                            "occurs", __FUNCTION__);
-            bt_hci_event_complete_status(hci, HCI_COMMAND_DISALLOWED);
-            break;
-        }
-        hci->lm.inquire = 0;
-        qemu_del_timer(hci->lm.inquiry_done);
-        qemu_del_timer(hci->lm.inquiry_next);
-        bt_hci_event_complete_status(hci, HCI_SUCCESS);
-        break;
-
-    case cmd_opcode_pack(OGF_LINK_CTL, OCF_CREATE_CONN):
-        LENGTH_CHECK(create_conn);
-
-        if (hci->lm.connecting >= HCI_HANDLES_MAX) {
-            bt_hci_event_status(hci, HCI_REJECTED_LIMITED_RESOURCES);
-            break;
-        }
-        bt_hci_event_status(hci, HCI_SUCCESS);
-
-        if (bt_hci_connect(hci, &PARAM(create_conn, bdaddr)))
-            bt_hci_connection_reject_event(hci, &PARAM(create_conn, bdaddr));
-        break;
-
-    case cmd_opcode_pack(OGF_LINK_CTL, OCF_DISCONNECT):
-        LENGTH_CHECK(disconnect);
-
-        if (bt_hci_handle_bad(hci, PARAMHANDLE(disconnect))) {
-            bt_hci_event_status(hci, HCI_NO_CONNECTION);
-            break;
-        }
-
-        bt_hci_event_status(hci, HCI_SUCCESS);
-        bt_hci_disconnect(hci, PARAMHANDLE(disconnect),
-                        PARAM(disconnect, reason));
-        break;
-
-    case cmd_opcode_pack(OGF_LINK_CTL, OCF_CREATE_CONN_CANCEL):
-        LENGTH_CHECK(create_conn_cancel);
-
-        if (bt_hci_lmp_connection_ready(hci,
-                                &PARAM(create_conn_cancel, bdaddr))) {
-            for (i = 0; i < HCI_HANDLES_MAX; i ++)
-                if (bt_hci_role_master(hci, i) && hci->lm.handle[i].link &&
-                                !bacmp(&hci->lm.handle[i].link->slave->bd_addr,
-                                        &PARAM(create_conn_cancel, bdaddr)))
-                   break;
-
-            bt_hci_event_complete_conn_cancel(hci, i < HCI_HANDLES_MAX ?
-                            HCI_ACL_CONNECTION_EXISTS : HCI_NO_CONNECTION,
-                            &PARAM(create_conn_cancel, bdaddr));
-        } else
-            bt_hci_event_complete_conn_cancel(hci, HCI_SUCCESS,
-                            &PARAM(create_conn_cancel, bdaddr));
-        break;
-
-    case cmd_opcode_pack(OGF_LINK_CTL, OCF_ACCEPT_CONN_REQ):
-        LENGTH_CHECK(accept_conn_req);
-
-        if (!hci->conn_req_host ||
-                        bacmp(&PARAM(accept_conn_req, bdaddr),
-                                &hci->conn_req_host->bd_addr)) {
-            bt_hci_event_status(hci, HCI_INVALID_PARAMETERS);
-            break;
-        }
-
-        bt_hci_event_status(hci, HCI_SUCCESS);
-        bt_hci_connection_accept(hci, hci->conn_req_host);
-        hci->conn_req_host = NULL;
-        break;
-
-    case cmd_opcode_pack(OGF_LINK_CTL, OCF_REJECT_CONN_REQ):
-        LENGTH_CHECK(reject_conn_req);
-
-        if (!hci->conn_req_host ||
-                        bacmp(&PARAM(reject_conn_req, bdaddr),
-                                &hci->conn_req_host->bd_addr)) {
-            bt_hci_event_status(hci, HCI_INVALID_PARAMETERS);
-            break;
-        }
-
-        bt_hci_event_status(hci, HCI_SUCCESS);
-        bt_hci_connection_reject(hci, hci->conn_req_host,
-                        PARAM(reject_conn_req, reason));
-        bt_hci_connection_reject_event(hci, &hci->conn_req_host->bd_addr);
-        hci->conn_req_host = NULL;
-        break;
-
-    case cmd_opcode_pack(OGF_LINK_CTL, OCF_AUTH_REQUESTED):
-        LENGTH_CHECK(auth_requested);
-
-        if (bt_hci_handle_bad(hci, PARAMHANDLE(auth_requested)))
-            bt_hci_event_status(hci, HCI_NO_CONNECTION);
-        else {
-            bt_hci_event_status(hci, HCI_SUCCESS);
-            bt_hci_event_auth_complete(hci, PARAMHANDLE(auth_requested));
-        }
-        break;
-
-    case cmd_opcode_pack(OGF_LINK_CTL, OCF_SET_CONN_ENCRYPT):
-        LENGTH_CHECK(set_conn_encrypt);
-
-        if (bt_hci_handle_bad(hci, PARAMHANDLE(set_conn_encrypt)))
-            bt_hci_event_status(hci, HCI_NO_CONNECTION);
-        else {
-            bt_hci_event_status(hci, HCI_SUCCESS);
-            bt_hci_event_encrypt_change(hci,
-                            PARAMHANDLE(set_conn_encrypt),
-                            PARAM(set_conn_encrypt, encrypt));
-        }
-        break;
-
-    case cmd_opcode_pack(OGF_LINK_CTL, OCF_REMOTE_NAME_REQ):
-        LENGTH_CHECK(remote_name_req);
-
-        if (bt_hci_name_req(hci, &PARAM(remote_name_req, bdaddr)))
-            bt_hci_event_status(hci, HCI_NO_CONNECTION);
-        break;
-
-    case cmd_opcode_pack(OGF_LINK_CTL, OCF_REMOTE_NAME_REQ_CANCEL):
-        LENGTH_CHECK(remote_name_req_cancel);
-
-        bt_hci_event_complete_name_cancel(hci,
-                        &PARAM(remote_name_req_cancel, bdaddr));
-        break;
-
-    case cmd_opcode_pack(OGF_LINK_CTL, OCF_READ_REMOTE_FEATURES):
-        LENGTH_CHECK(read_remote_features);
-
-        if (bt_hci_features_req(hci, PARAMHANDLE(read_remote_features)))
-            bt_hci_event_status(hci, HCI_NO_CONNECTION);
-        break;
-
-    case cmd_opcode_pack(OGF_LINK_CTL, OCF_READ_REMOTE_EXT_FEATURES):
-        LENGTH_CHECK(read_remote_ext_features);
-
-        if (bt_hci_handle_bad(hci, PARAMHANDLE(read_remote_ext_features)))
-            bt_hci_event_status(hci, HCI_NO_CONNECTION);
-        else {
-            bt_hci_event_status(hci, HCI_SUCCESS);
-            bt_hci_event_read_remote_ext_features(hci,
-                            PARAMHANDLE(read_remote_ext_features));
-        }
-        break;
-
-    case cmd_opcode_pack(OGF_LINK_CTL, OCF_READ_REMOTE_VERSION):
-        LENGTH_CHECK(read_remote_version);
-
-        if (bt_hci_version_req(hci, PARAMHANDLE(read_remote_version)))
-            bt_hci_event_status(hci, HCI_NO_CONNECTION);
-        break;
-
-    case cmd_opcode_pack(OGF_LINK_CTL, OCF_READ_CLOCK_OFFSET):
-        LENGTH_CHECK(read_clock_offset);
-
-        if (bt_hci_clkoffset_req(hci, PARAMHANDLE(read_clock_offset)))
-            bt_hci_event_status(hci, HCI_NO_CONNECTION);
-        break;
-
-    case cmd_opcode_pack(OGF_LINK_CTL, OCF_READ_LMP_HANDLE):
-        LENGTH_CHECK(read_lmp_handle);
-
-        /* TODO: */
-        bt_hci_event_complete_lmp_handle(hci, PARAMHANDLE(read_lmp_handle));
-        break;
-
-    case cmd_opcode_pack(OGF_LINK_POLICY, OCF_HOLD_MODE):
-        LENGTH_CHECK(hold_mode);
-
-        if (PARAM16(hold_mode, min_interval) >
-                        PARAM16(hold_mode, max_interval) ||
-                        PARAM16(hold_mode, min_interval) < 0x0002 ||
-                        PARAM16(hold_mode, max_interval) > 0xff00 ||
-                        (PARAM16(hold_mode, min_interval) & 1) ||
-                        (PARAM16(hold_mode, max_interval) & 1)) {
-            bt_hci_event_status(hci, HCI_INVALID_PARAMETERS);
-            break;
-        }
-
-        if (bt_hci_mode_change(hci, PARAMHANDLE(hold_mode),
-                                PARAM16(hold_mode, max_interval),
-                                acl_hold))
-            bt_hci_event_status(hci, HCI_NO_CONNECTION);
-        break;
-
-    case cmd_opcode_pack(OGF_LINK_POLICY, OCF_PARK_MODE):
-        LENGTH_CHECK(park_mode);
-
-        if (PARAM16(park_mode, min_interval) >
-                        PARAM16(park_mode, max_interval) ||
-                        PARAM16(park_mode, min_interval) < 0x000e ||
-                        (PARAM16(park_mode, min_interval) & 1) ||
-                        (PARAM16(park_mode, max_interval) & 1)) {
-            bt_hci_event_status(hci, HCI_INVALID_PARAMETERS);
-            break;
-        }
-
-        if (bt_hci_mode_change(hci, PARAMHANDLE(park_mode),
-                                PARAM16(park_mode, max_interval),
-                                acl_parked))
-            bt_hci_event_status(hci, HCI_NO_CONNECTION);
-        break;
-
-    case cmd_opcode_pack(OGF_LINK_POLICY, OCF_EXIT_PARK_MODE):
-        LENGTH_CHECK(exit_park_mode);
-
-        if (bt_hci_mode_cancel(hci, PARAMHANDLE(exit_park_mode),
-                                acl_parked))
-            bt_hci_event_status(hci, HCI_NO_CONNECTION);
-        break;
-
-    case cmd_opcode_pack(OGF_LINK_POLICY, OCF_ROLE_DISCOVERY):
-        LENGTH_CHECK(role_discovery);
-
-        if (bt_hci_handle_bad(hci, PARAMHANDLE(role_discovery)))
-            bt_hci_event_complete_role_discovery(hci,
-                            HCI_NO_CONNECTION, PARAMHANDLE(role_discovery), 0);
-        else
-            bt_hci_event_complete_role_discovery(hci,
-                            HCI_SUCCESS, PARAMHANDLE(role_discovery),
-                            bt_hci_role_master(hci,
-                                    PARAMHANDLE(role_discovery)));
-        break;
-
-    case cmd_opcode_pack(OGF_HOST_CTL, OCF_SET_EVENT_MASK):
-        LENGTH_CHECK(set_event_mask);
-
-        memcpy(hci->event_mask, PARAM(set_event_mask, mask), 8);
-        bt_hci_event_complete_status(hci, HCI_SUCCESS);
-        break;
-
-    case cmd_opcode_pack(OGF_HOST_CTL, OCF_RESET):
-        bt_hci_reset(hci);
-        bt_hci_event_status(hci, HCI_SUCCESS);
-        break;
-
-    case cmd_opcode_pack(OGF_HOST_CTL, OCF_SET_EVENT_FLT):
-        if (length >= 1 && PARAM(set_event_flt, flt_type) == FLT_CLEAR_ALL)
-            /* No length check */;
-        else
-            LENGTH_CHECK(set_event_flt);
-
-        /* Filters are not implemented */
-        bt_hci_event_complete_status(hci, HCI_SUCCESS);
-        break;
-
-    case cmd_opcode_pack(OGF_HOST_CTL, OCF_FLUSH):
-        LENGTH_CHECK(flush);
-
-        if (bt_hci_handle_bad(hci, PARAMHANDLE(flush)))
-            bt_hci_event_complete_flush(hci,
-                            HCI_NO_CONNECTION, PARAMHANDLE(flush));
-        else {
-            /* TODO: ordering? */
-            bt_hci_event(hci, EVT_FLUSH_OCCURRED,
-                            &PARAM(flush, handle),
-                            EVT_FLUSH_OCCURRED_SIZE);
-            bt_hci_event_complete_flush(hci,
-                            HCI_SUCCESS, PARAMHANDLE(flush));
-        }
-        break;
-
-    case cmd_opcode_pack(OGF_HOST_CTL, OCF_CHANGE_LOCAL_NAME):
-        LENGTH_CHECK(change_local_name);
-
-        if (hci->device.lmp_name)
-            g_free((void *) hci->device.lmp_name);
-        hci->device.lmp_name = g_strndup(PARAM(change_local_name, name),
-                        sizeof(PARAM(change_local_name, name)));
-        bt_hci_event_complete_status(hci, HCI_SUCCESS);
-        break;
-
-    case cmd_opcode_pack(OGF_HOST_CTL, OCF_READ_LOCAL_NAME):
-        bt_hci_event_complete_read_local_name(hci);
-        break;
-
-    case cmd_opcode_pack(OGF_HOST_CTL, OCF_READ_CONN_ACCEPT_TIMEOUT):
-        bt_hci_event_complete_read_conn_accept_timeout(hci);
-        break;
-
-    case cmd_opcode_pack(OGF_HOST_CTL, OCF_WRITE_CONN_ACCEPT_TIMEOUT):
-        /* TODO */
-        LENGTH_CHECK(write_conn_accept_timeout);
-
-        if (PARAM16(write_conn_accept_timeout, timeout) < 0x0001 ||
-                        PARAM16(write_conn_accept_timeout, timeout) > 0xb540) {
-            bt_hci_event_complete_status(hci, HCI_INVALID_PARAMETERS);
-            break;
-        }
-
-        hci->conn_accept_tout = PARAM16(write_conn_accept_timeout, timeout);
-        bt_hci_event_complete_status(hci, HCI_SUCCESS);
-        break;
-
-    case cmd_opcode_pack(OGF_HOST_CTL, OCF_READ_SCAN_ENABLE):
-        bt_hci_event_complete_read_scan_enable(hci);
-        break;
-
-    case cmd_opcode_pack(OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE):
-        LENGTH_CHECK(write_scan_enable);
-
-        /* TODO: check that the remaining bits are all 0 */
-        hci->device.inquiry_scan =
-                !!(PARAM(write_scan_enable, scan_enable) & SCAN_INQUIRY);
-        hci->device.page_scan =
-                !!(PARAM(write_scan_enable, scan_enable) & SCAN_PAGE);
-        bt_hci_event_complete_status(hci, HCI_SUCCESS);
-        break;
-
-    case cmd_opcode_pack(OGF_HOST_CTL, OCF_READ_CLASS_OF_DEV):
-        bt_hci_event_complete_read_local_class(hci);
-        break;
-
-    case cmd_opcode_pack(OGF_HOST_CTL, OCF_WRITE_CLASS_OF_DEV):
-        LENGTH_CHECK(write_class_of_dev);
-
-        memcpy(hci->device.class, PARAM(write_class_of_dev, dev_class),
-                        sizeof(PARAM(write_class_of_dev, dev_class)));
-        bt_hci_event_complete_status(hci, HCI_SUCCESS);
-        break;
-
-    case cmd_opcode_pack(OGF_HOST_CTL, OCF_READ_VOICE_SETTING):
-        bt_hci_event_complete_voice_setting(hci);
-        break;
-
-    case cmd_opcode_pack(OGF_HOST_CTL, OCF_WRITE_VOICE_SETTING):
-        LENGTH_CHECK(write_voice_setting);
-
-        hci->voice_setting = PARAM(write_voice_setting, voice_setting);
-        bt_hci_event_complete_status(hci, HCI_SUCCESS);
-        break;
-
-    case cmd_opcode_pack(OGF_HOST_CTL, OCF_HOST_NUMBER_OF_COMPLETED_PACKETS):
-        if (length < data[0] * 2 + 1)
-            goto short_hci;
-
-        for (i = 0; i < data[0]; i ++)
-            if (bt_hci_handle_bad(hci,
-                                    data[i * 2 + 1] | (data[i * 2 + 2] << 8)))
-                bt_hci_event_complete_status(hci, HCI_INVALID_PARAMETERS);
-        break;
-
-    case cmd_opcode_pack(OGF_HOST_CTL, OCF_READ_INQUIRY_MODE):
-        /* Only if (local_features[3] & 0x40) && (local_commands[12] & 0x40)
-         * else
-         *     goto unknown_command */
-        bt_hci_event_complete_read_inquiry_mode(hci);
-        break;
-
-    case cmd_opcode_pack(OGF_HOST_CTL, OCF_WRITE_INQUIRY_MODE):
-        /* Only if (local_features[3] & 0x40) && (local_commands[12] & 0x80)
-         * else
-         *     goto unknown_command */
-        LENGTH_CHECK(write_inquiry_mode);
-
-        if (PARAM(write_inquiry_mode, mode) > 0x01) {
-            bt_hci_event_complete_status(hci, HCI_INVALID_PARAMETERS);
-            break;
-        }
-
-        hci->lm.inquiry_mode = PARAM(write_inquiry_mode, mode);
-        bt_hci_event_complete_status(hci, HCI_SUCCESS);
-        break;
-
-    case cmd_opcode_pack(OGF_INFO_PARAM, OCF_READ_LOCAL_VERSION):
-        bt_hci_read_local_version_rp(hci);
-        break;
-
-    case cmd_opcode_pack(OGF_INFO_PARAM, OCF_READ_LOCAL_COMMANDS):
-        bt_hci_read_local_commands_rp(hci);
-        break;
-
-    case cmd_opcode_pack(OGF_INFO_PARAM, OCF_READ_LOCAL_FEATURES):
-        bt_hci_read_local_features_rp(hci);
-        break;
-
-    case cmd_opcode_pack(OGF_INFO_PARAM, OCF_READ_LOCAL_EXT_FEATURES):
-        LENGTH_CHECK(read_local_ext_features);
-
-        bt_hci_read_local_ext_features_rp(hci,
-                        PARAM(read_local_ext_features, page_num));
-        break;
-
-    case cmd_opcode_pack(OGF_INFO_PARAM, OCF_READ_BUFFER_SIZE):
-        bt_hci_read_buffer_size_rp(hci);
-        break;
-
-    case cmd_opcode_pack(OGF_INFO_PARAM, OCF_READ_COUNTRY_CODE):
-        bt_hci_read_country_code_rp(hci);
-        break;
-
-    case cmd_opcode_pack(OGF_INFO_PARAM, OCF_READ_BD_ADDR):
-        bt_hci_read_bd_addr_rp(hci);
-        break;
-
-    case cmd_opcode_pack(OGF_STATUS_PARAM, OCF_READ_LINK_QUALITY):
-        LENGTH_CHECK(read_link_quality);
-
-        bt_hci_link_quality_rp(hci, PARAMHANDLE(read_link_quality));
-        break;
-
-    default:
-        bt_hci_event_status(hci, HCI_UNKNOWN_COMMAND);
-        break;
-
-    short_hci:
-        fprintf(stderr, "%s: HCI packet too short (%iB)\n",
-                        __FUNCTION__, length);
-        bt_hci_event_status(hci, HCI_INVALID_PARAMETERS);
-        break;
-    }
-}
-
-/* We could perform fragmentation here, we can't do "recombination" because
- * at this layer the length of the payload is not know ahead, so we only
- * know that a packet contained the last fragment of the SDU when the next
- * SDU starts.  */
-static inline void bt_hci_lmp_acl_data(struct bt_hci_s *hci, uint16_t handle,
-                const uint8_t *data, int start, int len)
-{
-    struct hci_acl_hdr *pkt = (void *) hci->acl_buf;
-
-    /* TODO: packet flags */
-    /* TODO: avoid memcpy'ing */
-
-    if (len + HCI_ACL_HDR_SIZE > sizeof(hci->acl_buf)) {
-        fprintf(stderr, "%s: can't take ACL packets %i bytes long\n",
-                        __FUNCTION__, len);
-        return;
-    }
-    memcpy(hci->acl_buf + HCI_ACL_HDR_SIZE, data, len);
-
-    pkt->handle = cpu_to_le16(
-                    acl_handle_pack(handle, start ? ACL_START : ACL_CONT));
-    pkt->dlen = cpu_to_le16(len);
-    hci->info.acl_recv(hci->info.opaque,
-                    hci->acl_buf, len + HCI_ACL_HDR_SIZE);
-}
-
-static void bt_hci_lmp_acl_data_slave(struct bt_link_s *btlink,
-                const uint8_t *data, int start, int len)
-{
-    struct bt_hci_link_s *link = (struct bt_hci_link_s *) btlink;
-
-    bt_hci_lmp_acl_data(hci_from_device(btlink->slave),
-                    link->handle, data, start, len);
-}
-
-static void bt_hci_lmp_acl_data_host(struct bt_link_s *link,
-                const uint8_t *data, int start, int len)
-{
-    bt_hci_lmp_acl_data(hci_from_device(link->host),
-                    link->handle, data, start, len);
-}
-
-static void bt_submit_acl(struct HCIInfo *info,
-                const uint8_t *data, int length)
-{
-    struct bt_hci_s *hci = hci_from_info(info);
-    uint16_t handle;
-    int datalen, flags;
-    struct bt_link_s *link;
-
-    if (length < HCI_ACL_HDR_SIZE) {
-        fprintf(stderr, "%s: ACL packet too short (%iB)\n",
-                        __FUNCTION__, length);
-        return;
-    }
-
-    handle = acl_handle((data[1] << 8) | data[0]);
-    flags = acl_flags((data[1] << 8) | data[0]);
-    datalen = (data[3] << 8) | data[2];
-    data += HCI_ACL_HDR_SIZE;
-    length -= HCI_ACL_HDR_SIZE;
-
-    if (bt_hci_handle_bad(hci, handle)) {
-        fprintf(stderr, "%s: invalid ACL handle %03x\n",
-                        __FUNCTION__, handle);
-        /* TODO: signal an error */
-        return;
-    }
-    handle &= ~HCI_HANDLE_OFFSET;
-
-    if (datalen > length) {
-        fprintf(stderr, "%s: ACL packet too short (%iB < %iB)\n",
-                        __FUNCTION__, length, datalen);
-        return;
-    }
-
-    link = hci->lm.handle[handle].link;
-
-    if ((flags & ~3) == ACL_ACTIVE_BCAST) {
-        if (!hci->asb_handle)
-            hci->asb_handle = handle;
-        else if (handle != hci->asb_handle) {
-            fprintf(stderr, "%s: Bad handle %03x in Active Slave Broadcast\n",
-                            __FUNCTION__, handle);
-            /* TODO: signal an error */
-            return;
-        }
-
-        /* TODO */
-    }
-
-    if ((flags & ~3) == ACL_PICO_BCAST) {
-        if (!hci->psb_handle)
-            hci->psb_handle = handle;
-        else if (handle != hci->psb_handle) {
-            fprintf(stderr, "%s: Bad handle %03x in Parked Slave Broadcast\n",
-                            __FUNCTION__, handle);
-            /* TODO: signal an error */
-            return;
-        }
-
-        /* TODO */
-    }
-
-    /* TODO: increase counter and send EVT_NUM_COMP_PKTS */
-    bt_hci_event_num_comp_pkts(hci, handle | HCI_HANDLE_OFFSET, 1);
-
-    /* Do this last as it can trigger further events even in this HCI */
-    hci->lm.handle[handle].lmp_acl_data(link, data,
-                    (flags & 3) == ACL_START, length);
-}
-
-static void bt_submit_sco(struct HCIInfo *info,
-                const uint8_t *data, int length)
-{
-    struct bt_hci_s *hci = hci_from_info(info);
-    uint16_t handle;
-    int datalen;
-
-    if (length < 3)
-        return;
-
-    handle = acl_handle((data[1] << 8) | data[0]);
-    datalen = data[2];
-    length -= 3;
-
-    if (bt_hci_handle_bad(hci, handle)) {
-        fprintf(stderr, "%s: invalid SCO handle %03x\n",
-                        __FUNCTION__, handle);
-        return;
-    }
-
-    if (datalen > length) {
-        fprintf(stderr, "%s: SCO packet too short (%iB < %iB)\n",
-                        __FUNCTION__, length, datalen);
-        return;
-    }
-
-    /* TODO */
-
-    /* TODO: increase counter and send EVT_NUM_COMP_PKTS if synchronous
-     * Flow Control is enabled.
-     * (See Read/Write_Synchronous_Flow_Control_Enable on page 513 and
-     * page 514.)  */
-}
-
-static uint8_t *bt_hci_evt_packet(void *opaque)
-{
-    /* TODO: allocate a packet from upper layer */
-    struct bt_hci_s *s = opaque;
-
-    return s->evt_buf;
-}
-
-static void bt_hci_evt_submit(void *opaque, int len)
-{
-    /* TODO: notify upper layer */
-    struct bt_hci_s *s = opaque;
-
-    s->info.evt_recv(s->info.opaque, s->evt_buf, len);
-}
-
-static int bt_hci_bdaddr_set(struct HCIInfo *info, const uint8_t *bd_addr)
-{
-    struct bt_hci_s *hci = hci_from_info(info);
-
-    bacpy(&hci->device.bd_addr, (const bdaddr_t *) bd_addr);
-    return 0;
-}
-
-static void bt_hci_done(struct HCIInfo *info);
-static void bt_hci_destroy(struct bt_device_s *dev)
-{
-    struct bt_hci_s *hci = hci_from_device(dev);
-
-    bt_hci_done(&hci->info);
-}
-
-struct HCIInfo *bt_new_hci(struct bt_scatternet_s *net)
-{
-    struct bt_hci_s *s = g_malloc0(sizeof(struct bt_hci_s));
-
-    s->lm.inquiry_done = qemu_new_timer_ns(vm_clock, bt_hci_inquiry_done, s);
-    s->lm.inquiry_next = qemu_new_timer_ns(vm_clock, bt_hci_inquiry_next, s);
-    s->conn_accept_timer =
-            qemu_new_timer_ns(vm_clock, bt_hci_conn_accept_timeout, s);
-
-    s->evt_packet = bt_hci_evt_packet;
-    s->evt_submit = bt_hci_evt_submit;
-    s->opaque = s;
-
-    bt_device_init(&s->device, net);
-    s->device.lmp_connection_request = bt_hci_lmp_connection_request;
-    s->device.lmp_connection_complete = bt_hci_lmp_connection_complete;
-    s->device.lmp_disconnect_master = bt_hci_lmp_disconnect_host;
-    s->device.lmp_disconnect_slave = bt_hci_lmp_disconnect_slave;
-    s->device.lmp_acl_data = bt_hci_lmp_acl_data_slave;
-    s->device.lmp_acl_resp = bt_hci_lmp_acl_data_host;
-    s->device.lmp_mode_change = bt_hci_lmp_mode_change_slave;
-
-    /* Keep updated! */
-    /* Also keep in sync with supported commands bitmask in
-     * bt_hci_read_local_commands_rp */
-    s->device.lmp_caps = 0x8000199b7e85355fll;
-
-    bt_hci_reset(s);
-
-    s->info.cmd_send = bt_submit_hci;
-    s->info.sco_send = bt_submit_sco;
-    s->info.acl_send = bt_submit_acl;
-    s->info.bdaddr_set = bt_hci_bdaddr_set;
-
-    s->device.handle_destroy = bt_hci_destroy;
-
-    return &s->info;
-}
-
-static void bt_hci_done(struct HCIInfo *info)
-{
-    struct bt_hci_s *hci = hci_from_info(info);
-    int handle;
-
-    bt_device_done(&hci->device);
-
-    if (hci->device.lmp_name)
-        g_free((void *) hci->device.lmp_name);
-
-    /* Be gentle and send DISCONNECT to all connected peers and those
-     * currently waiting for us to accept or reject a connection request.
-     * This frees the links.  */
-    if (hci->conn_req_host) {
-        bt_hci_connection_reject(hci,
-                                 hci->conn_req_host, HCI_OE_POWER_OFF);
-        return;
-    }
-
-    for (handle = HCI_HANDLE_OFFSET;
-                    handle < (HCI_HANDLE_OFFSET | HCI_HANDLES_MAX); handle ++)
-        if (!bt_hci_handle_bad(hci, handle))
-            bt_hci_disconnect(hci, handle, HCI_OE_POWER_OFF);
-
-    /* TODO: this is not enough actually, there may be slaves from whom
-     * we have requested a connection who will soon (or not) respond with
-     * an accept or a reject, so we should also check if hci->lm.connecting
-     * is non-zero and if so, avoid freeing the hci but otherwise disappear
-     * from all qemu social life (e.g. stop scanning and request to be
-     * removed from s->device.net) and arrange for
-     * s->device.lmp_connection_complete to free the remaining bits once
-     * hci->lm.awaiting_bdaddr[] is empty.  */
-
-    qemu_free_timer(hci->lm.inquiry_done);
-    qemu_free_timer(hci->lm.inquiry_next);
-    qemu_free_timer(hci->conn_accept_timer);
-
-    g_free(hci);
-}
diff --git a/hw/bt-hid.c b/hw/bt-hid.c
deleted file mode 100644 (file)
index 69ccf9b..0000000
+++ /dev/null
@@ -1,553 +0,0 @@
-/*
- * QEMU Bluetooth HID Profile wrapper for USB HID.
- *
- * Copyright (C) 2007-2008 OpenMoko, Inc.
- * Written by Andrzej Zaborowski <andrew@openedhand.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 or
- * (at your option) version 3 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
- * 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, if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu-common.h"
-#include "qemu/timer.h"
-#include "ui/console.h"
-#include "hw/hid.h"
-#include "hw/bt.h"
-
-enum hid_transaction_req {
-    BT_HANDSHAKE                       = 0x0,
-    BT_HID_CONTROL                     = 0x1,
-    BT_GET_REPORT                      = 0x4,
-    BT_SET_REPORT                      = 0x5,
-    BT_GET_PROTOCOL                    = 0x6,
-    BT_SET_PROTOCOL                    = 0x7,
-    BT_GET_IDLE                                = 0x8,
-    BT_SET_IDLE                                = 0x9,
-    BT_DATA                            = 0xa,
-    BT_DATC                            = 0xb,
-};
-
-enum hid_transaction_handshake {
-    BT_HS_SUCCESSFUL                   = 0x0,
-    BT_HS_NOT_READY                    = 0x1,
-    BT_HS_ERR_INVALID_REPORT_ID                = 0x2,
-    BT_HS_ERR_UNSUPPORTED_REQUEST      = 0x3,
-    BT_HS_ERR_INVALID_PARAMETER                = 0x4,
-    BT_HS_ERR_UNKNOWN                  = 0xe,
-    BT_HS_ERR_FATAL                    = 0xf,
-};
-
-enum hid_transaction_control {
-    BT_HC_NOP                          = 0x0,
-    BT_HC_HARD_RESET                   = 0x1,
-    BT_HC_SOFT_RESET                   = 0x2,
-    BT_HC_SUSPEND                      = 0x3,
-    BT_HC_EXIT_SUSPEND                 = 0x4,
-    BT_HC_VIRTUAL_CABLE_UNPLUG         = 0x5,
-};
-
-enum hid_protocol {
-    BT_HID_PROTO_BOOT                  = 0,
-    BT_HID_PROTO_REPORT                        = 1,
-};
-
-enum hid_boot_reportid {
-    BT_HID_BOOT_INVALID                        = 0,
-    BT_HID_BOOT_KEYBOARD,
-    BT_HID_BOOT_MOUSE,
-};
-
-enum hid_data_pkt {
-    BT_DATA_OTHER                      = 0,
-    BT_DATA_INPUT,
-    BT_DATA_OUTPUT,
-    BT_DATA_FEATURE,
-};
-
-#define BT_HID_MTU                     48
-
-/* HID interface requests */
-#define GET_REPORT                     0xa101
-#define GET_IDLE                       0xa102
-#define GET_PROTOCOL                   0xa103
-#define SET_REPORT                     0x2109
-#define SET_IDLE                       0x210a
-#define SET_PROTOCOL                   0x210b
-
-struct bt_hid_device_s {
-    struct bt_l2cap_device_s btdev;
-    struct bt_l2cap_conn_params_s *control;
-    struct bt_l2cap_conn_params_s *interrupt;
-    HIDState hid;
-
-    int proto;
-    int connected;
-    int data_type;
-    int intr_state;
-    struct {
-        int len;
-        uint8_t buffer[1024];
-    } dataother, datain, dataout, feature, intrdataout;
-    enum {
-        bt_state_ready,
-        bt_state_transaction,
-        bt_state_suspend,
-    } state;
-};
-
-static void bt_hid_reset(struct bt_hid_device_s *s)
-{
-    struct bt_scatternet_s *net = s->btdev.device.net;
-
-    /* Go as far as... */
-    bt_l2cap_device_done(&s->btdev);
-    bt_l2cap_device_init(&s->btdev, net);
-
-    hid_reset(&s->hid);
-    s->proto = BT_HID_PROTO_REPORT;
-    s->state = bt_state_ready;
-    s->dataother.len = 0;
-    s->datain.len = 0;
-    s->dataout.len = 0;
-    s->feature.len = 0;
-    s->intrdataout.len = 0;
-    s->intr_state = 0;
-}
-
-static int bt_hid_out(struct bt_hid_device_s *s)
-{
-    if (s->data_type == BT_DATA_OUTPUT) {
-        /* nothing */
-        ;
-    }
-
-    if (s->data_type == BT_DATA_FEATURE) {
-        /* XXX:
-         * does this send a USB_REQ_CLEAR_FEATURE/USB_REQ_SET_FEATURE
-         * or a SET_REPORT? */
-        ;
-    }
-
-    return -1;
-}
-
-static int bt_hid_in(struct bt_hid_device_s *s)
-{
-    s->datain.len = hid_keyboard_poll(&s->hid, s->datain.buffer,
-                                      sizeof(s->datain.buffer));
-    return s->datain.len;
-}
-
-static void bt_hid_send_handshake(struct bt_hid_device_s *s, int result)
-{
-    *s->control->sdu_out(s->control, 1) =
-            (BT_HANDSHAKE << 4) | result;
-    s->control->sdu_submit(s->control);
-}
-
-static void bt_hid_send_control(struct bt_hid_device_s *s, int operation)
-{
-    *s->control->sdu_out(s->control, 1) =
-            (BT_HID_CONTROL << 4) | operation;
-    s->control->sdu_submit(s->control);
-}
-
-static void bt_hid_disconnect(struct bt_hid_device_s *s)
-{
-    /* Disconnect s->control and s->interrupt */
-}
-
-static void bt_hid_send_data(struct bt_l2cap_conn_params_s *ch, int type,
-                const uint8_t *data, int len)
-{
-    uint8_t *pkt, hdr = (BT_DATA << 4) | type;
-    int plen;
-
-    do {
-        plen = MIN(len, ch->remote_mtu - 1);
-        pkt = ch->sdu_out(ch, plen + 1);
-
-        pkt[0] = hdr;
-        if (plen)
-            memcpy(pkt + 1, data, plen);
-        ch->sdu_submit(ch);
-
-        len -= plen;
-        data += plen;
-        hdr = (BT_DATC << 4) | type;
-    } while (plen == ch->remote_mtu - 1);
-}
-
-static void bt_hid_control_transaction(struct bt_hid_device_s *s,
-                const uint8_t *data, int len)
-{
-    uint8_t type, parameter;
-    int rlen, ret = -1;
-    if (len < 1)
-        return;
-
-    type = data[0] >> 4;
-    parameter = data[0] & 0xf;
-
-    switch (type) {
-    case BT_HANDSHAKE:
-    case BT_DATA:
-        switch (parameter) {
-        default:
-            /* These are not expected to be sent this direction.  */
-            ret = BT_HS_ERR_INVALID_PARAMETER;
-        }
-        break;
-
-    case BT_HID_CONTROL:
-        if (len != 1 || (parameter != BT_HC_VIRTUAL_CABLE_UNPLUG &&
-                                s->state == bt_state_transaction)) {
-            ret = BT_HS_ERR_INVALID_PARAMETER;
-            break;
-        }
-        switch (parameter) {
-        case BT_HC_NOP:
-            break;
-        case BT_HC_HARD_RESET:
-        case BT_HC_SOFT_RESET:
-            bt_hid_reset(s);
-            break;
-        case BT_HC_SUSPEND:
-            if (s->state == bt_state_ready)
-                s->state = bt_state_suspend;
-            else
-                ret = BT_HS_ERR_INVALID_PARAMETER;
-            break;
-        case BT_HC_EXIT_SUSPEND:
-            if (s->state == bt_state_suspend)
-                s->state = bt_state_ready;
-            else
-                ret = BT_HS_ERR_INVALID_PARAMETER;
-            break;
-        case BT_HC_VIRTUAL_CABLE_UNPLUG:
-            bt_hid_disconnect(s);
-            break;
-        default:
-            ret = BT_HS_ERR_INVALID_PARAMETER;
-        }
-        break;
-
-    case BT_GET_REPORT:
-        /* No ReportIDs declared.  */
-        if (((parameter & 8) && len != 3) ||
-                        (!(parameter & 8) && len != 1) ||
-                        s->state != bt_state_ready) {
-            ret = BT_HS_ERR_INVALID_PARAMETER;
-            break;
-        }
-        if (parameter & 8)
-            rlen = data[2] | (data[3] << 8);
-        else
-            rlen = INT_MAX;
-        switch (parameter & 3) {
-        case BT_DATA_OTHER:
-            ret = BT_HS_ERR_INVALID_PARAMETER;
-            break;
-        case BT_DATA_INPUT:
-            /* Here we can as well poll s->usbdev */
-            bt_hid_send_data(s->control, BT_DATA_INPUT,
-                            s->datain.buffer, MIN(rlen, s->datain.len));
-            break;
-        case BT_DATA_OUTPUT:
-            bt_hid_send_data(s->control, BT_DATA_OUTPUT,
-                            s->dataout.buffer, MIN(rlen, s->dataout.len));
-            break;
-        case BT_DATA_FEATURE:
-            bt_hid_send_data(s->control, BT_DATA_FEATURE,
-                            s->feature.buffer, MIN(rlen, s->feature.len));
-            break;
-        }
-        break;
-
-    case BT_SET_REPORT:
-        if (len < 2 || len > BT_HID_MTU || s->state != bt_state_ready ||
-                        (parameter & 3) == BT_DATA_OTHER ||
-                        (parameter & 3) == BT_DATA_INPUT) {
-            ret = BT_HS_ERR_INVALID_PARAMETER;
-            break;
-        }
-        s->data_type = parameter & 3;
-        if (s->data_type == BT_DATA_OUTPUT) {
-            s->dataout.len = len - 1;
-            memcpy(s->dataout.buffer, data + 1, s->dataout.len);
-        } else {
-            s->feature.len = len - 1;
-            memcpy(s->feature.buffer, data + 1, s->feature.len);
-        }
-        if (len == BT_HID_MTU)
-            s->state = bt_state_transaction;
-        else
-            bt_hid_out(s);
-        break;
-
-    case BT_GET_PROTOCOL:
-        if (len != 1 || s->state == bt_state_transaction) {
-            ret = BT_HS_ERR_INVALID_PARAMETER;
-            break;
-        }
-        *s->control->sdu_out(s->control, 1) = s->proto;
-        s->control->sdu_submit(s->control);
-        break;
-
-    case BT_SET_PROTOCOL:
-        if (len != 1 || s->state == bt_state_transaction ||
-                        (parameter != BT_HID_PROTO_BOOT &&
-                         parameter != BT_HID_PROTO_REPORT)) {
-            ret = BT_HS_ERR_INVALID_PARAMETER;
-            break;
-        }
-        s->proto = parameter;
-        s->hid.protocol = parameter;
-        ret = BT_HS_SUCCESSFUL;
-        break;
-
-    case BT_GET_IDLE:
-        if (len != 1 || s->state == bt_state_transaction) {
-            ret = BT_HS_ERR_INVALID_PARAMETER;
-            break;
-        }
-        *s->control->sdu_out(s->control, 1) = s->hid.idle;
-        s->control->sdu_submit(s->control);
-        break;
-
-    case BT_SET_IDLE:
-        if (len != 2 || s->state == bt_state_transaction) {
-            ret = BT_HS_ERR_INVALID_PARAMETER;
-            break;
-        }
-
-        s->hid.idle = data[1];
-        /* XXX: Does this generate a handshake? */
-        break;
-
-    case BT_DATC:
-        if (len > BT_HID_MTU || s->state != bt_state_transaction) {
-            ret = BT_HS_ERR_INVALID_PARAMETER;
-            break;
-        }
-        if (s->data_type == BT_DATA_OUTPUT) {
-            memcpy(s->dataout.buffer + s->dataout.len, data + 1, len - 1);
-            s->dataout.len += len - 1;
-        } else {
-            memcpy(s->feature.buffer + s->feature.len, data + 1, len - 1);
-            s->feature.len += len - 1;
-        }
-        if (len < BT_HID_MTU) {
-            bt_hid_out(s);
-            s->state = bt_state_ready;
-        }
-        break;
-
-    default:
-        ret = BT_HS_ERR_UNSUPPORTED_REQUEST;
-    }
-
-    if (ret != -1)
-        bt_hid_send_handshake(s, ret);
-}
-
-static void bt_hid_control_sdu(void *opaque, const uint8_t *data, int len)
-{
-    struct bt_hid_device_s *hid = opaque;
-
-    bt_hid_control_transaction(hid, data, len);
-}
-
-static void bt_hid_datain(HIDState *hs)
-{
-    struct bt_hid_device_s *hid =
-        container_of(hs, struct bt_hid_device_s, hid);
-
-    /* If suspended, wake-up and send a wake-up event first.  We might
-     * want to also inspect the input report and ignore event like
-     * mouse movements until a button event occurs.  */
-    if (hid->state == bt_state_suspend) {
-        hid->state = bt_state_ready;
-    }
-
-    if (bt_hid_in(hid) > 0)
-        /* TODO: when in boot-mode precede any Input reports with the ReportID
-         * byte, here and in GetReport/SetReport on the Control channel.  */
-        bt_hid_send_data(hid->interrupt, BT_DATA_INPUT,
-                        hid->datain.buffer, hid->datain.len);
-}
-
-static void bt_hid_interrupt_sdu(void *opaque, const uint8_t *data, int len)
-{
-    struct bt_hid_device_s *hid = opaque;
-
-    if (len > BT_HID_MTU || len < 1)
-        goto bad;
-    if ((data[0] & 3) != BT_DATA_OUTPUT)
-        goto bad;
-    if ((data[0] >> 4) == BT_DATA) {
-        if (hid->intr_state)
-            goto bad;
-
-        hid->data_type = BT_DATA_OUTPUT;
-        hid->intrdataout.len = 0;
-    } else if ((data[0] >> 4) == BT_DATC) {
-        if (!hid->intr_state)
-            goto bad;
-    } else
-        goto bad;
-
-    memcpy(hid->intrdataout.buffer + hid->intrdataout.len, data + 1, len - 1);
-    hid->intrdataout.len += len - 1;
-    hid->intr_state = (len == BT_HID_MTU);
-    if (!hid->intr_state) {
-        memcpy(hid->dataout.buffer, hid->intrdataout.buffer,
-                        hid->dataout.len = hid->intrdataout.len);
-        bt_hid_out(hid);
-    }
-
-    return;
-bad:
-    fprintf(stderr, "%s: bad transaction on Interrupt channel.\n",
-                    __FUNCTION__);
-}
-
-/* "Virtual cable" plug/unplug event.  */
-static void bt_hid_connected_update(struct bt_hid_device_s *hid)
-{
-    int prev = hid->connected;
-
-    hid->connected = hid->control && hid->interrupt;
-
-    /* Stop page-/inquiry-scanning when a host is connected.  */
-    hid->btdev.device.page_scan = !hid->connected;
-    hid->btdev.device.inquiry_scan = !hid->connected;
-
-    if (hid->connected && !prev) {
-        hid_reset(&hid->hid);
-        hid->proto = BT_HID_PROTO_REPORT;
-    }
-
-    /* Should set HIDVirtualCable in SDP (possibly need to check that SDP
-     * isn't destroyed yet, in case we're being called from handle_destroy) */
-}
-
-static void bt_hid_close_control(void *opaque)
-{
-    struct bt_hid_device_s *hid = opaque;
-
-    hid->control = NULL;
-    bt_hid_connected_update(hid);
-}
-
-static void bt_hid_close_interrupt(void *opaque)
-{
-    struct bt_hid_device_s *hid = opaque;
-
-    hid->interrupt = NULL;
-    bt_hid_connected_update(hid);
-}
-
-static int bt_hid_new_control_ch(struct bt_l2cap_device_s *dev,
-                struct bt_l2cap_conn_params_s *params)
-{
-    struct bt_hid_device_s *hid = (struct bt_hid_device_s *) dev;
-
-    if (hid->control)
-        return 1;
-
-    hid->control = params;
-    hid->control->opaque = hid;
-    hid->control->close = bt_hid_close_control;
-    hid->control->sdu_in = bt_hid_control_sdu;
-
-    bt_hid_connected_update(hid);
-
-    return 0;
-}
-
-static int bt_hid_new_interrupt_ch(struct bt_l2cap_device_s *dev,
-                struct bt_l2cap_conn_params_s *params)
-{
-    struct bt_hid_device_s *hid = (struct bt_hid_device_s *) dev;
-
-    if (hid->interrupt)
-        return 1;
-
-    hid->interrupt = params;
-    hid->interrupt->opaque = hid;
-    hid->interrupt->close = bt_hid_close_interrupt;
-    hid->interrupt->sdu_in = bt_hid_interrupt_sdu;
-
-    bt_hid_connected_update(hid);
-
-    return 0;
-}
-
-static void bt_hid_destroy(struct bt_device_s *dev)
-{
-    struct bt_hid_device_s *hid = (struct bt_hid_device_s *) dev;
-
-    if (hid->connected)
-        bt_hid_send_control(hid, BT_HC_VIRTUAL_CABLE_UNPLUG);
-    bt_l2cap_device_done(&hid->btdev);
-
-    hid_free(&hid->hid);
-
-    g_free(hid);
-}
-
-enum peripheral_minor_class {
-    class_other                = 0 << 4,
-    class_keyboard     = 1 << 4,
-    class_pointing     = 2 << 4,
-    class_combo                = 3 << 4,
-};
-
-static struct bt_device_s *bt_hid_init(struct bt_scatternet_s *net,
-                                       enum peripheral_minor_class minor)
-{
-    struct bt_hid_device_s *s = g_malloc0(sizeof(*s));
-    uint32_t class =
-            /* Format type */
-            (0 << 0) |
-            /* Device class */
-            (minor << 2) |
-            (5 << 8) |  /* "Peripheral" */
-            /* Service classes */
-            (1 << 13) | /* Limited discoverable mode */
-            (1 << 19);  /* Capturing device (?) */
-
-    bt_l2cap_device_init(&s->btdev, net);
-    bt_l2cap_sdp_init(&s->btdev);
-    bt_l2cap_psm_register(&s->btdev, BT_PSM_HID_CTRL,
-                    BT_HID_MTU, bt_hid_new_control_ch);
-    bt_l2cap_psm_register(&s->btdev, BT_PSM_HID_INTR,
-                    BT_HID_MTU, bt_hid_new_interrupt_ch);
-
-    hid_init(&s->hid, HID_KEYBOARD, bt_hid_datain);
-    s->btdev.device.lmp_name = "BT Keyboard";
-
-    s->btdev.device.handle_destroy = bt_hid_destroy;
-
-    s->btdev.device.class[0] = (class >>  0) & 0xff;
-    s->btdev.device.class[1] = (class >>  8) & 0xff;
-    s->btdev.device.class[2] = (class >> 16) & 0xff;
-
-    return &s->btdev.device;
-}
-
-struct bt_device_s *bt_keyboard_init(struct bt_scatternet_s *net)
-{
-    return bt_hid_init(net, class_keyboard);
-}
diff --git a/hw/bt-l2cap.c b/hw/bt-l2cap.c
deleted file mode 100644 (file)
index 521587a..0000000
+++ /dev/null
@@ -1,1365 +0,0 @@
-/*
- * QEMU Bluetooth L2CAP logic.
- *
- * Copyright (C) 2008 Andrzej Zaborowski  <balrog@zabor.org>
- *
- * 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 "qemu/timer.h"
-#include "hw/bt.h"
-
-#define L2CAP_CID_MAX  0x100   /* Between 0x40 and 0x10000 */
-
-struct l2cap_instance_s {
-    struct bt_link_s *link;
-    struct bt_l2cap_device_s *dev;
-    int role;
-
-    uint8_t frame_in[65535 + L2CAP_HDR_SIZE] __attribute__ ((aligned (4)));
-    int frame_in_len;
-
-    uint8_t frame_out[65535 + L2CAP_HDR_SIZE] __attribute__ ((aligned (4)));
-    int frame_out_len;
-
-    /* Signalling channel timers.  They exist per-request but we can make
-     * sure we have no more than one outstanding request at any time.  */
-    QEMUTimer *rtx;
-    QEMUTimer *ertx;
-
-    int last_id;
-    int next_id;
-
-    struct l2cap_chan_s {
-        struct bt_l2cap_conn_params_s params;
-
-        void (*frame_in)(struct l2cap_chan_s *chan, uint16_t cid,
-                        const l2cap_hdr *hdr, int len);
-        int mps;
-        int min_mtu;
-
-        struct l2cap_instance_s *l2cap;
-
-        /* Only allocated channels */
-        uint16_t remote_cid;
-#define L2CAP_CFG_INIT 2
-#define L2CAP_CFG_ACC  1
-        int config_req_id; /* TODO: handle outgoing requests generically */
-        int config;
-
-        /* Only connection-oriented channels.  Note: if we allow the tx and
-         * rx traffic to be in different modes at any time, we need two.  */
-        int mode;
-
-        /* Only flow-controlled, connection-oriented channels */
-        uint8_t sdu[65536]; /* TODO: dynamically allocate */
-        int len_cur, len_total;
-        int rexmit;
-        int monitor_timeout;
-        QEMUTimer *monitor_timer;
-        QEMUTimer *retransmission_timer;
-    } *cid[L2CAP_CID_MAX];
-    /* The channel state machine states map as following:
-     * CLOSED           -> !cid[N]
-     * WAIT_CONNECT     -> never occurs
-     * WAIT_CONNECT_RSP -> never occurs
-     * CONFIG           -> cid[N] && config < 3
-     *   WAIT_CONFIG         -> never occurs, cid[N] && config == 0 && !config_r
-     *   WAIT_SEND_CONFIG    -> never occurs, cid[N] && config == 1 && !config_r
-     *   WAIT_CONFIG_REQ_RSP -> cid[N] && config == 0 && config_req_id
-     *   WAIT_CONFIG_RSP     -> cid[N] && config == 1 && config_req_id
-     *   WAIT_CONFIG_REQ     -> cid[N] && config == 2
-     * OPEN             -> cid[N] && config == 3
-     * WAIT_DISCONNECT  -> never occurs
-     */
-
-    struct l2cap_chan_s signalling_ch;
-    struct l2cap_chan_s group_ch;
-};
-
-struct slave_l2cap_instance_s {
-    struct bt_link_s link;     /* Underlying logical link (ACL) */
-    struct l2cap_instance_s l2cap;
-};
-
-struct bt_l2cap_psm_s {
-    int psm;
-    int min_mtu;
-    int (*new_channel)(struct bt_l2cap_device_s *device,
-                    struct bt_l2cap_conn_params_s *params);
-    struct bt_l2cap_psm_s *next;
-};
-
-static const uint16_t l2cap_fcs16_table[256] = {
-    0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241,
-    0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440,
-    0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40,
-    0x0a00, 0xcac1, 0xcb81, 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841,
-    0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40,
-    0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41,
-    0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641,
-    0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040,
-    0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240,
-    0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441,
-    0x3c00, 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41,
-    0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840,
-    0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41,
-    0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40,
-    0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640,
-    0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041,
-    0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240,
-    0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441,
-    0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41,
-    0xaa01, 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840,
-    0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41,
-    0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40,
-    0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640,
-    0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041,
-    0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241,
-    0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440,
-    0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40,
-    0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841,
-    0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40,
-    0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41,
-    0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641,
-    0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040,
-};
-
-static uint16_t l2cap_fcs16(const uint8_t *message, int len)
-{
-    uint16_t fcs = 0x0000;
-
-    while (len --)
-#if 0
-    {
-        int i;
-
-        fcs ^= *message ++;
-        for (i = 8; i; -- i)
-            if (fcs & 1)
-                fcs = (fcs >> 1) ^ 0xa001;
-            else
-                fcs = (fcs >> 1);
-    }
-#else
-        fcs = (fcs >> 8) ^ l2cap_fcs16_table[(fcs ^ *message ++) & 0xff];
-#endif
-
-    return fcs;
-}
-
-/* L2CAP layer logic (protocol) */
-
-static void l2cap_retransmission_timer_update(struct l2cap_chan_s *ch)
-{
-#if 0
-    if (ch->mode != L2CAP_MODE_BASIC && ch->rexmit)
-        qemu_mod_timer(ch->retransmission_timer);
-    else
-        qemu_del_timer(ch->retransmission_timer);
-#endif
-}
-
-static void l2cap_monitor_timer_update(struct l2cap_chan_s *ch)
-{
-#if 0
-    if (ch->mode != L2CAP_MODE_BASIC && !ch->rexmit)
-        qemu_mod_timer(ch->monitor_timer);
-    else
-        qemu_del_timer(ch->monitor_timer);
-#endif
-}
-
-static void l2cap_command_reject(struct l2cap_instance_s *l2cap, int id,
-                uint16_t reason, const void *data, int plen)
-{
-    uint8_t *pkt;
-    l2cap_cmd_hdr *hdr;
-    l2cap_cmd_rej *params;
-    uint16_t len;
-
-    reason = cpu_to_le16(reason);
-    len = cpu_to_le16(L2CAP_CMD_REJ_SIZE + plen);
-
-    pkt = l2cap->signalling_ch.params.sdu_out(&l2cap->signalling_ch.params,
-                    L2CAP_CMD_HDR_SIZE + L2CAP_CMD_REJ_SIZE + plen);
-    hdr = (void *) (pkt + 0);
-    params = (void *) (pkt + L2CAP_CMD_HDR_SIZE);
-
-    hdr->code = L2CAP_COMMAND_REJ;
-    hdr->ident = id;
-    memcpy(&hdr->len, &len, sizeof(hdr->len));
-    memcpy(&params->reason, &reason, sizeof(reason));
-    if (plen)
-       memcpy(pkt + L2CAP_CMD_HDR_SIZE + L2CAP_CMD_REJ_SIZE, data, plen);
-
-    l2cap->signalling_ch.params.sdu_submit(&l2cap->signalling_ch.params);
-}
-
-static void l2cap_command_reject_cid(struct l2cap_instance_s *l2cap, int id,
-                uint16_t reason, uint16_t dcid, uint16_t scid)
-{
-    l2cap_cmd_rej_cid params = {
-        .dcid = dcid,
-        .scid = scid,
-    };
-
-    l2cap_command_reject(l2cap, id, reason, &params, L2CAP_CMD_REJ_CID_SIZE);
-}
-
-static void l2cap_connection_response(struct l2cap_instance_s *l2cap,
-                int dcid, int scid, int result, int status)
-{
-    uint8_t *pkt;
-    l2cap_cmd_hdr *hdr;
-    l2cap_conn_rsp *params;
-
-    pkt = l2cap->signalling_ch.params.sdu_out(&l2cap->signalling_ch.params,
-                    L2CAP_CMD_HDR_SIZE + L2CAP_CONN_RSP_SIZE);
-    hdr = (void *) (pkt + 0);
-    params = (void *) (pkt + L2CAP_CMD_HDR_SIZE);
-
-    hdr->code = L2CAP_CONN_RSP;
-    hdr->ident = l2cap->last_id;
-    hdr->len = cpu_to_le16(L2CAP_CONN_RSP_SIZE);
-
-    params->dcid = cpu_to_le16(dcid);
-    params->scid = cpu_to_le16(scid);
-    params->result = cpu_to_le16(result);
-    params->status = cpu_to_le16(status);
-
-    l2cap->signalling_ch.params.sdu_submit(&l2cap->signalling_ch.params);
-}
-
-static void l2cap_configuration_request(struct l2cap_instance_s *l2cap,
-                int dcid, int flag, const uint8_t *data, int len)
-{
-    uint8_t *pkt;
-    l2cap_cmd_hdr *hdr;
-    l2cap_conf_req *params;
-
-    pkt = l2cap->signalling_ch.params.sdu_out(&l2cap->signalling_ch.params,
-                    L2CAP_CMD_HDR_SIZE + L2CAP_CONF_REQ_SIZE(len));
-    hdr = (void *) (pkt + 0);
-    params = (void *) (pkt + L2CAP_CMD_HDR_SIZE);
-
-    /* TODO: unify the id sequencing */
-    l2cap->last_id = l2cap->next_id;
-    l2cap->next_id = l2cap->next_id == 255 ? 1 : l2cap->next_id + 1;
-
-    hdr->code = L2CAP_CONF_REQ;
-    hdr->ident = l2cap->last_id;
-    hdr->len = cpu_to_le16(L2CAP_CONF_REQ_SIZE(len));
-
-    params->dcid = cpu_to_le16(dcid);
-    params->flags = cpu_to_le16(flag);
-    if (len)
-        memcpy(params->data, data, len);
-
-    l2cap->signalling_ch.params.sdu_submit(&l2cap->signalling_ch.params);
-}
-
-static void l2cap_configuration_response(struct l2cap_instance_s *l2cap,
-                int scid, int flag, int result, const uint8_t *data, int len)
-{
-    uint8_t *pkt;
-    l2cap_cmd_hdr *hdr;
-    l2cap_conf_rsp *params;
-
-    pkt = l2cap->signalling_ch.params.sdu_out(&l2cap->signalling_ch.params,
-                    L2CAP_CMD_HDR_SIZE + L2CAP_CONF_RSP_SIZE(len));
-    hdr = (void *) (pkt + 0);
-    params = (void *) (pkt + L2CAP_CMD_HDR_SIZE);
-
-    hdr->code = L2CAP_CONF_RSP;
-    hdr->ident = l2cap->last_id;
-    hdr->len = cpu_to_le16(L2CAP_CONF_RSP_SIZE(len));
-
-    params->scid = cpu_to_le16(scid);
-    params->flags = cpu_to_le16(flag);
-    params->result = cpu_to_le16(result);
-    if (len)
-        memcpy(params->data, data, len);
-
-    l2cap->signalling_ch.params.sdu_submit(&l2cap->signalling_ch.params);
-}
-
-static void l2cap_disconnection_response(struct l2cap_instance_s *l2cap,
-                int dcid, int scid)
-{
-    uint8_t *pkt;
-    l2cap_cmd_hdr *hdr;
-    l2cap_disconn_rsp *params;
-
-    pkt = l2cap->signalling_ch.params.sdu_out(&l2cap->signalling_ch.params,
-                    L2CAP_CMD_HDR_SIZE + L2CAP_DISCONN_RSP_SIZE);
-    hdr = (void *) (pkt + 0);
-    params = (void *) (pkt + L2CAP_CMD_HDR_SIZE);
-
-    hdr->code = L2CAP_DISCONN_RSP;
-    hdr->ident = l2cap->last_id;
-    hdr->len = cpu_to_le16(L2CAP_DISCONN_RSP_SIZE);
-
-    params->dcid = cpu_to_le16(dcid);
-    params->scid = cpu_to_le16(scid);
-
-    l2cap->signalling_ch.params.sdu_submit(&l2cap->signalling_ch.params);
-}
-
-static void l2cap_echo_response(struct l2cap_instance_s *l2cap,
-                const uint8_t *data, int len)
-{
-    uint8_t *pkt;
-    l2cap_cmd_hdr *hdr;
-    uint8_t *params;
-
-    pkt = l2cap->signalling_ch.params.sdu_out(&l2cap->signalling_ch.params,
-                    L2CAP_CMD_HDR_SIZE + len);
-    hdr = (void *) (pkt + 0);
-    params = (void *) (pkt + L2CAP_CMD_HDR_SIZE);
-
-    hdr->code = L2CAP_ECHO_RSP;
-    hdr->ident = l2cap->last_id;
-    hdr->len = cpu_to_le16(len);
-
-    memcpy(params, data, len);
-
-    l2cap->signalling_ch.params.sdu_submit(&l2cap->signalling_ch.params);
-}
-
-static void l2cap_info_response(struct l2cap_instance_s *l2cap, int type,
-                int result, const uint8_t *data, int len)
-{
-    uint8_t *pkt;
-    l2cap_cmd_hdr *hdr;
-    l2cap_info_rsp *params;
-
-    pkt = l2cap->signalling_ch.params.sdu_out(&l2cap->signalling_ch.params,
-                    L2CAP_CMD_HDR_SIZE + L2CAP_INFO_RSP_SIZE + len);
-    hdr = (void *) (pkt + 0);
-    params = (void *) (pkt + L2CAP_CMD_HDR_SIZE);
-
-    hdr->code = L2CAP_INFO_RSP;
-    hdr->ident = l2cap->last_id;
-    hdr->len = cpu_to_le16(L2CAP_INFO_RSP_SIZE + len);
-
-    params->type = cpu_to_le16(type);
-    params->result = cpu_to_le16(result);
-    if (len)
-       memcpy(params->data, data, len);
-
-    l2cap->signalling_ch.params.sdu_submit(&l2cap->signalling_ch.params);
-}
-
-static uint8_t *l2cap_bframe_out(struct bt_l2cap_conn_params_s *parm, int len);
-static void l2cap_bframe_submit(struct bt_l2cap_conn_params_s *parms);
-#if 0
-static uint8_t *l2cap_iframe_out(struct bt_l2cap_conn_params_s *parm, int len);
-static void l2cap_iframe_submit(struct bt_l2cap_conn_params_s *parm);
-#endif
-static void l2cap_bframe_in(struct l2cap_chan_s *ch, uint16_t cid,
-                const l2cap_hdr *hdr, int len);
-static void l2cap_iframe_in(struct l2cap_chan_s *ch, uint16_t cid,
-                const l2cap_hdr *hdr, int len);
-
-static int l2cap_cid_new(struct l2cap_instance_s *l2cap)
-{
-    int i;
-
-    for (i = L2CAP_CID_ALLOC; i < L2CAP_CID_MAX; i ++)
-        if (!l2cap->cid[i])
-            return i;
-
-    return L2CAP_CID_INVALID;
-}
-
-static inline struct bt_l2cap_psm_s *l2cap_psm(
-                struct bt_l2cap_device_s *device, int psm)
-{
-    struct bt_l2cap_psm_s *ret = device->first_psm;
-
-    while (ret && ret->psm != psm)
-        ret = ret->next;
-
-    return ret;
-}
-
-static struct l2cap_chan_s *l2cap_channel_open(struct l2cap_instance_s *l2cap,
-                int psm, int source_cid)
-{
-    struct l2cap_chan_s *ch = NULL;
-    struct bt_l2cap_psm_s *psm_info;
-    int result, status;
-    int cid = l2cap_cid_new(l2cap);
-
-    if (cid) {
-        /* See what the channel is to be used for.. */
-        psm_info = l2cap_psm(l2cap->dev, psm);
-
-        if (psm_info) {
-            /* Device supports this use-case.  */
-            ch = g_malloc0(sizeof(*ch));
-            ch->params.sdu_out = l2cap_bframe_out;
-            ch->params.sdu_submit = l2cap_bframe_submit;
-            ch->frame_in = l2cap_bframe_in;
-            ch->mps = 65536;
-            ch->min_mtu = MAX(48, psm_info->min_mtu);
-            ch->params.remote_mtu = MAX(672, ch->min_mtu);
-            ch->remote_cid = source_cid;
-            ch->mode = L2CAP_MODE_BASIC;
-            ch->l2cap = l2cap;
-
-            /* Does it feel like opening yet another channel though?  */
-            if (!psm_info->new_channel(l2cap->dev, &ch->params)) {
-                l2cap->cid[cid] = ch;
-
-                result = L2CAP_CR_SUCCESS;
-                status = L2CAP_CS_NO_INFO;
-            } else {
-                g_free(ch);
-
-                result = L2CAP_CR_NO_MEM;
-                status = L2CAP_CS_NO_INFO;
-            }
-        } else {
-            result = L2CAP_CR_BAD_PSM;
-            status = L2CAP_CS_NO_INFO;
-        }
-    } else {
-        result = L2CAP_CR_NO_MEM;
-        status = L2CAP_CS_NO_INFO;
-    }
-
-    l2cap_connection_response(l2cap, cid, source_cid, result, status);
-
-    return ch;
-}
-
-static void l2cap_channel_close(struct l2cap_instance_s *l2cap,
-                int cid, int source_cid)
-{
-    struct l2cap_chan_s *ch = NULL;
-
-    /* According to Volume 3, section 6.1.1, pg 1048 of BT Core V2.0, a
-     * connection in CLOSED state still responds with a L2CAP_DisconnectRsp
-     * message on an L2CAP_DisconnectReq event.  */
-    if (unlikely(cid < L2CAP_CID_ALLOC)) {
-        l2cap_command_reject_cid(l2cap, l2cap->last_id, L2CAP_REJ_CID_INVAL,
-                        cid, source_cid);
-        return;
-    }
-    if (likely(cid >= L2CAP_CID_ALLOC && cid < L2CAP_CID_MAX))
-        ch = l2cap->cid[cid];
-
-    if (likely(ch)) {
-        if (ch->remote_cid != source_cid) {
-            fprintf(stderr, "%s: Ignoring a Disconnection Request with the "
-                            "invalid SCID %04x.\n", __FUNCTION__, source_cid);
-            return;
-        }
-
-        l2cap->cid[cid] = NULL;
-
-        ch->params.close(ch->params.opaque);
-        g_free(ch);
-    }
-
-    l2cap_disconnection_response(l2cap, cid, source_cid);
-}
-
-static void l2cap_channel_config_null(struct l2cap_instance_s *l2cap,
-                struct l2cap_chan_s *ch)
-{
-    l2cap_configuration_request(l2cap, ch->remote_cid, 0, NULL, 0);
-    ch->config_req_id = l2cap->last_id;
-    ch->config &= ~L2CAP_CFG_INIT;
-}
-
-static void l2cap_channel_config_req_event(struct l2cap_instance_s *l2cap,
-                struct l2cap_chan_s *ch)
-{
-    /* Use all default channel options and terminate negotiation.  */
-    l2cap_channel_config_null(l2cap, ch);
-}
-
-static int l2cap_channel_config(struct l2cap_instance_s *l2cap,
-                struct l2cap_chan_s *ch, int flag,
-                const uint8_t *data, int len)
-{
-    l2cap_conf_opt *opt;
-    l2cap_conf_opt_qos *qos;
-    uint32_t val;
-    uint8_t rsp[len];
-    int result = L2CAP_CONF_SUCCESS;
-
-    data = memcpy(rsp, data, len);
-    while (len) {
-        opt = (void *) data;
-
-        if (len < L2CAP_CONF_OPT_SIZE ||
-                        len < L2CAP_CONF_OPT_SIZE + opt->len) {
-            result = L2CAP_CONF_REJECT;
-            break;
-        }
-        data += L2CAP_CONF_OPT_SIZE + opt->len;
-        len -= L2CAP_CONF_OPT_SIZE + opt->len;
-
-        switch (opt->type & 0x7f) {
-        case L2CAP_CONF_MTU:
-            if (opt->len != 2) {
-                result = L2CAP_CONF_REJECT;
-                break;
-            }
-
-            /* MTU */
-            val = le16_to_cpup((void *) opt->val);
-            if (val < ch->min_mtu) {
-                cpu_to_le16w((void *) opt->val, ch->min_mtu);
-                result = L2CAP_CONF_UNACCEPT;
-                break;
-            }
-
-            ch->params.remote_mtu = val;
-            break;
-
-        case L2CAP_CONF_FLUSH_TO:
-            if (opt->len != 2) {
-                result = L2CAP_CONF_REJECT;
-                break;
-            }
-
-            /* Flush Timeout */
-            val = le16_to_cpup((void *) opt->val);
-            if (val < 0x0001) {
-                opt->val[0] = 0xff;
-                opt->val[1] = 0xff;
-                result = L2CAP_CONF_UNACCEPT;
-                break;
-            }
-            break;
-
-        case L2CAP_CONF_QOS:
-            if (opt->len != L2CAP_CONF_OPT_QOS_SIZE) {
-                result = L2CAP_CONF_REJECT;
-                break;
-            }
-            qos = (void *) opt->val;
-
-            /* Flags */
-            val = qos->flags;
-            if (val) {
-                qos->flags = 0;
-                result = L2CAP_CONF_UNACCEPT;
-            }
-
-            /* Service type */
-            val = qos->service_type;
-            if (val != L2CAP_CONF_QOS_BEST_EFFORT &&
-                            val != L2CAP_CONF_QOS_NO_TRAFFIC) {
-                qos->service_type = L2CAP_CONF_QOS_BEST_EFFORT;
-                result = L2CAP_CONF_UNACCEPT;
-            }
-
-            if (val != L2CAP_CONF_QOS_NO_TRAFFIC) {
-                /* XXX: These values should possibly be calculated
-                 * based on LM / baseband properties also.  */
-
-                /* Token rate */
-                val = le32_to_cpu(qos->token_rate);
-                if (val == L2CAP_CONF_QOS_WILDCARD)
-                    qos->token_rate = cpu_to_le32(0x100000);
-
-                /* Token bucket size */
-                val = le32_to_cpu(qos->token_bucket_size);
-                if (val == L2CAP_CONF_QOS_WILDCARD)
-                    qos->token_bucket_size = cpu_to_le32(65500);
-
-                /* Any Peak bandwidth value is correct to return as-is */
-                /* Any Access latency value is correct to return as-is */
-                /* Any Delay variation value is correct to return as-is */
-            }
-            break;
-
-        case L2CAP_CONF_RFC:
-            if (opt->len != 9) {
-                result = L2CAP_CONF_REJECT;
-                break;
-            }
-
-            /* Mode */
-            val = opt->val[0];
-            switch (val) {
-            case L2CAP_MODE_BASIC:
-                ch->mode = val;
-                ch->frame_in = l2cap_bframe_in;
-
-                /* All other parameters shall be ignored */
-                break;
-
-            case L2CAP_MODE_RETRANS:
-            case L2CAP_MODE_FLOWCTL:
-                ch->mode = val;
-                ch->frame_in = l2cap_iframe_in;
-                /* Note: most of these parameters refer to incoming traffic
-                 * so we don't need to save them as long as we can accept
-                 * incoming PDUs at any values of the parameters.  */
-
-                /* TxWindow size */
-                val = opt->val[1];
-                if (val < 1 || val > 32) {
-                    opt->val[1] = 32;
-                    result = L2CAP_CONF_UNACCEPT;
-                    break;
-                }
-
-                /* MaxTransmit */
-                val = opt->val[2];
-                if (val < 1) {
-                    opt->val[2] = 1;
-                    result = L2CAP_CONF_UNACCEPT;
-                    break;
-                }
-
-                /* Remote Retransmission time-out shouldn't affect local
-                 * operation (?) */
-
-                /* The Monitor time-out drives the local Monitor timer (?),
-                 * so save the value.  */
-                val = (opt->val[6] << 8) | opt->val[5];
-                if (val < 30) {
-                    opt->val[5] = 100 & 0xff;
-                    opt->val[6] = 100 >> 8;
-                    result = L2CAP_CONF_UNACCEPT;
-                    break;
-                }
-                ch->monitor_timeout = val;
-                l2cap_monitor_timer_update(ch);
-
-                /* MPS */
-                val = (opt->val[8] << 8) | opt->val[7];
-                if (val < ch->min_mtu) {
-                    opt->val[7] = ch->min_mtu & 0xff;
-                    opt->val[8] = ch->min_mtu >> 8;
-                    result = L2CAP_CONF_UNACCEPT;
-                    break;
-                }
-                ch->mps = val;
-                break;
-
-            default:
-                result = L2CAP_CONF_UNACCEPT;
-                break;
-            }
-            break;
-
-        default:
-            if (!(opt->type >> 7))
-                result = L2CAP_CONF_UNKNOWN;
-            break;
-        }
-
-        if (result != L2CAP_CONF_SUCCESS)
-            break;     /* XXX: should continue? */
-    }
-
-    l2cap_configuration_response(l2cap, ch->remote_cid,
-                    flag, result, rsp, len);
-
-    return result == L2CAP_CONF_SUCCESS && !flag;
-}
-
-static void l2cap_channel_config_req_msg(struct l2cap_instance_s *l2cap,
-                int flag, int cid, const uint8_t *data, int len)
-{
-    struct l2cap_chan_s *ch;
-
-    if (unlikely(cid >= L2CAP_CID_MAX || !l2cap->cid[cid])) {
-        l2cap_command_reject_cid(l2cap, l2cap->last_id, L2CAP_REJ_CID_INVAL,
-                        cid, 0x0000);
-        return;
-    }
-    ch = l2cap->cid[cid];
-
-    /* From OPEN go to WAIT_CONFIG_REQ and from WAIT_CONFIG_REQ_RSP to
-     * WAIT_CONFIG_REQ_RSP.  This is assuming the transition chart for OPEN
-     * on pg 1053, section 6.1.5, volume 3 of BT Core V2.0 has a mistake
-     * and on options-acceptable we go back to OPEN and otherwise to
-     * WAIT_CONFIG_REQ and not the other way.  */
-    ch->config &= ~L2CAP_CFG_ACC;
-
-    if (l2cap_channel_config(l2cap, ch, flag, data, len))
-        /* Go to OPEN or WAIT_CONFIG_RSP */
-        ch->config |= L2CAP_CFG_ACC;
-
-    /* TODO: if the incoming traffic flow control or retransmission mode
-     * changed then we probably need to also generate the
-     * ConfigureChannel_Req event and set the outgoing traffic to the same
-     * mode.  */
-    if (!(ch->config & L2CAP_CFG_INIT) && (ch->config & L2CAP_CFG_ACC) &&
-                    !ch->config_req_id)
-        l2cap_channel_config_req_event(l2cap, ch);
-}
-
-static int l2cap_channel_config_rsp_msg(struct l2cap_instance_s *l2cap,
-                int result, int flag, int cid, const uint8_t *data, int len)
-{
-    struct l2cap_chan_s *ch;
-
-    if (unlikely(cid >= L2CAP_CID_MAX || !l2cap->cid[cid])) {
-        l2cap_command_reject_cid(l2cap, l2cap->last_id, L2CAP_REJ_CID_INVAL,
-                        cid, 0x0000);
-        return 0;
-    }
-    ch = l2cap->cid[cid];
-
-    if (ch->config_req_id != l2cap->last_id)
-        return 1;
-    ch->config_req_id = 0;
-
-    if (result == L2CAP_CONF_SUCCESS) {
-        if (!flag)
-            ch->config |= L2CAP_CFG_INIT;
-        else
-            l2cap_channel_config_null(l2cap, ch);
-    } else
-        /* Retry until we succeed */
-        l2cap_channel_config_req_event(l2cap, ch);
-
-    return 0;
-}
-
-static void l2cap_channel_open_req_msg(struct l2cap_instance_s *l2cap,
-                int psm, int source_cid)
-{
-    struct l2cap_chan_s *ch = l2cap_channel_open(l2cap, psm, source_cid);
-
-    if (!ch)
-        return;
-
-    /* Optional */
-    if (!(ch->config & L2CAP_CFG_INIT) && !ch->config_req_id)
-        l2cap_channel_config_req_event(l2cap, ch);
-}
-
-static void l2cap_info(struct l2cap_instance_s *l2cap, int type)
-{
-    uint8_t data[4];
-    int len = 0;
-    int result = L2CAP_IR_SUCCESS;
-
-    switch (type) {
-    case L2CAP_IT_CL_MTU:
-        data[len ++] = l2cap->group_ch.mps & 0xff;
-        data[len ++] = l2cap->group_ch.mps >> 8;
-        break;
-
-    case L2CAP_IT_FEAT_MASK:
-        /* (Prematurely) report Flow control and Retransmission modes.  */
-        data[len ++] = 0x03;
-        data[len ++] = 0x00;
-        data[len ++] = 0x00;
-        data[len ++] = 0x00;
-        break;
-
-    default:
-        result = L2CAP_IR_NOTSUPP;
-    }
-
-    l2cap_info_response(l2cap, type, result, data, len);
-}
-
-static void l2cap_command(struct l2cap_instance_s *l2cap, int code, int id,
-                const uint8_t *params, int len)
-{
-    int err;
-
-#if 0
-    /* TODO: do the IDs really have to be in sequence?  */
-    if (!id || (id != l2cap->last_id && id != l2cap->next_id)) {
-        fprintf(stderr, "%s: out of sequence command packet ignored.\n",
-                        __FUNCTION__);
-        return;
-    }
-#else
-    l2cap->next_id = id;
-#endif
-    if (id == l2cap->next_id) {
-        l2cap->last_id = l2cap->next_id;
-        l2cap->next_id = l2cap->next_id == 255 ? 1 : l2cap->next_id + 1;
-    } else {
-        /* TODO: Need to re-send the same response, without re-executing
-         * the corresponding command!  */
-    }
-
-    switch (code) {
-    case L2CAP_COMMAND_REJ:
-        if (unlikely(len != 2 && len != 4 && len != 6)) {
-            err = L2CAP_REJ_CMD_NOT_UNDERSTOOD;
-            goto reject;
-        }
-
-        /* We never issue commands other than Command Reject currently.  */
-        fprintf(stderr, "%s: stray Command Reject (%02x, %04x) "
-                        "packet, ignoring.\n", __FUNCTION__, id,
-                        le16_to_cpu(((l2cap_cmd_rej *) params)->reason));
-        break;
-
-    case L2CAP_CONN_REQ:
-        if (unlikely(len != L2CAP_CONN_REQ_SIZE)) {
-            err = L2CAP_REJ_CMD_NOT_UNDERSTOOD;
-            goto reject;
-        }
-
-        l2cap_channel_open_req_msg(l2cap,
-                        le16_to_cpu(((l2cap_conn_req *) params)->psm),
-                        le16_to_cpu(((l2cap_conn_req *) params)->scid));
-        break;
-
-    case L2CAP_CONN_RSP:
-        if (unlikely(len != L2CAP_CONN_RSP_SIZE)) {
-            err = L2CAP_REJ_CMD_NOT_UNDERSTOOD;
-            goto reject;
-        }
-
-        /* We never issue Connection Requests currently. TODO  */
-        fprintf(stderr, "%s: unexpected Connection Response (%02x) "
-                        "packet, ignoring.\n", __FUNCTION__, id);
-        break;
-
-    case L2CAP_CONF_REQ:
-        if (unlikely(len < L2CAP_CONF_REQ_SIZE(0))) {
-            err = L2CAP_REJ_CMD_NOT_UNDERSTOOD;
-            goto reject;
-        }
-
-        l2cap_channel_config_req_msg(l2cap,
-                        le16_to_cpu(((l2cap_conf_req *) params)->flags) & 1,
-                        le16_to_cpu(((l2cap_conf_req *) params)->dcid),
-                        ((l2cap_conf_req *) params)->data,
-                        len - L2CAP_CONF_REQ_SIZE(0));
-        break;
-
-    case L2CAP_CONF_RSP:
-        if (unlikely(len < L2CAP_CONF_RSP_SIZE(0))) {
-            err = L2CAP_REJ_CMD_NOT_UNDERSTOOD;
-            goto reject;
-        }
-
-        if (l2cap_channel_config_rsp_msg(l2cap,
-                        le16_to_cpu(((l2cap_conf_rsp *) params)->result),
-                        le16_to_cpu(((l2cap_conf_rsp *) params)->flags) & 1,
-                        le16_to_cpu(((l2cap_conf_rsp *) params)->scid),
-                        ((l2cap_conf_rsp *) params)->data,
-                        len - L2CAP_CONF_RSP_SIZE(0)))
-            fprintf(stderr, "%s: unexpected Configure Response (%02x) "
-                            "packet, ignoring.\n", __FUNCTION__, id);
-        break;
-
-    case L2CAP_DISCONN_REQ:
-        if (unlikely(len != L2CAP_DISCONN_REQ_SIZE)) {
-            err = L2CAP_REJ_CMD_NOT_UNDERSTOOD;
-            goto reject;
-        }
-
-        l2cap_channel_close(l2cap,
-                        le16_to_cpu(((l2cap_disconn_req *) params)->dcid),
-                        le16_to_cpu(((l2cap_disconn_req *) params)->scid));
-        break;
-
-    case L2CAP_DISCONN_RSP:
-        if (unlikely(len != L2CAP_DISCONN_RSP_SIZE)) {
-            err = L2CAP_REJ_CMD_NOT_UNDERSTOOD;
-            goto reject;
-        }
-
-        /* We never issue Disconnection Requests currently. TODO  */
-        fprintf(stderr, "%s: unexpected Disconnection Response (%02x) "
-                        "packet, ignoring.\n", __FUNCTION__, id);
-        break;
-
-    case L2CAP_ECHO_REQ:
-        l2cap_echo_response(l2cap, params, len);
-        break;
-
-    case L2CAP_ECHO_RSP:
-        /* We never issue Echo Requests currently. TODO  */
-        fprintf(stderr, "%s: unexpected Echo Response (%02x) "
-                        "packet, ignoring.\n", __FUNCTION__, id);
-        break;
-
-    case L2CAP_INFO_REQ:
-        if (unlikely(len != L2CAP_INFO_REQ_SIZE)) {
-            err = L2CAP_REJ_CMD_NOT_UNDERSTOOD;
-            goto reject;
-        }
-
-        l2cap_info(l2cap, le16_to_cpu(((l2cap_info_req *) params)->type));
-        break;
-
-    case L2CAP_INFO_RSP:
-        if (unlikely(len != L2CAP_INFO_RSP_SIZE)) {
-            err = L2CAP_REJ_CMD_NOT_UNDERSTOOD;
-            goto reject;
-        }
-
-        /* We never issue Information Requests currently. TODO  */
-        fprintf(stderr, "%s: unexpected Information Response (%02x) "
-                        "packet, ignoring.\n", __FUNCTION__, id);
-        break;
-
-    default:
-        err = L2CAP_REJ_CMD_NOT_UNDERSTOOD;
-    reject:
-        l2cap_command_reject(l2cap, id, err, 0, 0);
-        break;
-    }
-}
-
-static void l2cap_rexmit_enable(struct l2cap_chan_s *ch, int enable)
-{
-    ch->rexmit = enable;
-
-    l2cap_retransmission_timer_update(ch);
-    l2cap_monitor_timer_update(ch);
-}
-
-/* Command frame SDU */
-static void l2cap_cframe_in(void *opaque, const uint8_t *data, int len)
-{
-    struct l2cap_instance_s *l2cap = opaque;
-    const l2cap_cmd_hdr *hdr;
-    int clen;
-
-    while (len) {
-        hdr = (void *) data;
-        if (len < L2CAP_CMD_HDR_SIZE)
-            /* TODO: signal an error */
-            return;
-        len -= L2CAP_CMD_HDR_SIZE;
-        data += L2CAP_CMD_HDR_SIZE;
-
-        clen = le16_to_cpu(hdr->len);
-        if (len < clen) {
-            l2cap_command_reject(l2cap, hdr->ident,
-                            L2CAP_REJ_CMD_NOT_UNDERSTOOD, 0, 0);
-            break;
-        }
-
-        l2cap_command(l2cap, hdr->code, hdr->ident, data, clen);
-        len -= clen;
-        data += clen;
-    }
-}
-
-/* Group frame SDU */
-static void l2cap_gframe_in(void *opaque, const uint8_t *data, int len)
-{
-}
-
-/* Supervisory frame */
-static void l2cap_sframe_in(struct l2cap_chan_s *ch, uint16_t ctrl)
-{
-}
-
-/* Basic L2CAP mode Information frame */
-static void l2cap_bframe_in(struct l2cap_chan_s *ch, uint16_t cid,
-                const l2cap_hdr *hdr, int len)
-{
-    /* We have a full SDU, no further processing */
-    ch->params.sdu_in(ch->params.opaque, hdr->data, len);
-}
-
-/* Flow Control and Retransmission mode frame */
-static void l2cap_iframe_in(struct l2cap_chan_s *ch, uint16_t cid,
-                const l2cap_hdr *hdr, int len)
-{
-    uint16_t fcs = le16_to_cpup((void *) (hdr->data + len - 2));
-
-    if (len < 4)
-        goto len_error;
-    if (l2cap_fcs16((const uint8_t *) hdr, L2CAP_HDR_SIZE + len - 2) != fcs)
-        goto fcs_error;
-
-    if ((hdr->data[0] >> 7) == ch->rexmit)
-        l2cap_rexmit_enable(ch, !(hdr->data[0] >> 7));
-
-    if (hdr->data[0] & 1) {
-        if (len != 4) {
-            /* TODO: Signal an error? */
-            return;
-        }
-        l2cap_sframe_in(ch, le16_to_cpup((void *) hdr->data));
-        return;
-    }
-
-    switch (hdr->data[1] >> 6) {       /* SAR */
-    case L2CAP_SAR_NO_SEG:
-        if (ch->len_total)
-            goto seg_error;
-        if (len - 4 > ch->mps)
-            goto len_error;
-
-        ch->params.sdu_in(ch->params.opaque, hdr->data + 2, len - 4);
-        break;
-
-    case L2CAP_SAR_START:
-        if (ch->len_total || len < 6)
-            goto seg_error;
-        if (len - 6 > ch->mps)
-            goto len_error;
-
-        ch->len_total = le16_to_cpup((void *) (hdr->data + 2));
-        if (len >= 6 + ch->len_total)
-            goto seg_error;
-
-        ch->len_cur = len - 6;
-        memcpy(ch->sdu, hdr->data + 4, ch->len_cur);
-        break;
-
-    case L2CAP_SAR_END:
-        if (!ch->len_total || ch->len_cur + len - 4 < ch->len_total)
-            goto seg_error;
-        if (len - 4 > ch->mps)
-            goto len_error;
-
-        memcpy(ch->sdu + ch->len_cur, hdr->data + 2, len - 4);
-        ch->params.sdu_in(ch->params.opaque, ch->sdu, ch->len_total);
-        break;
-
-    case L2CAP_SAR_CONT:
-        if (!ch->len_total || ch->len_cur + len - 4 >= ch->len_total)
-            goto seg_error;
-        if (len - 4 > ch->mps)
-            goto len_error;
-
-        memcpy(ch->sdu + ch->len_cur, hdr->data + 2, len - 4);
-        ch->len_cur += len - 4;
-        break;
-
-    seg_error:
-    len_error: /* TODO */
-    fcs_error: /* TODO */
-        ch->len_cur = 0;
-        ch->len_total = 0;
-        break;
-    }
-}
-
-static void l2cap_frame_in(struct l2cap_instance_s *l2cap,
-                const l2cap_hdr *frame)
-{
-    uint16_t cid = le16_to_cpu(frame->cid);
-    uint16_t len = le16_to_cpu(frame->len);
-
-    if (unlikely(cid >= L2CAP_CID_MAX || !l2cap->cid[cid])) {
-        fprintf(stderr, "%s: frame addressed to a non-existent L2CAP "
-                        "channel %04x received.\n", __FUNCTION__, cid);
-        return;
-    }
-
-    l2cap->cid[cid]->frame_in(l2cap->cid[cid], cid, frame, len);
-}
-
-/* "Recombination" */
-static void l2cap_pdu_in(struct l2cap_instance_s *l2cap,
-                const uint8_t *data, int len)
-{
-    const l2cap_hdr *hdr = (void *) l2cap->frame_in;
-
-    if (unlikely(len + l2cap->frame_in_len > sizeof(l2cap->frame_in))) {
-        if (l2cap->frame_in_len < sizeof(l2cap->frame_in)) {
-            memcpy(l2cap->frame_in + l2cap->frame_in_len, data,
-                            sizeof(l2cap->frame_in) - l2cap->frame_in_len);
-            l2cap->frame_in_len = sizeof(l2cap->frame_in);
-            /* TODO: truncate */
-            l2cap_frame_in(l2cap, hdr);
-        }
-
-        return;
-    }
-
-    memcpy(l2cap->frame_in + l2cap->frame_in_len, data, len);
-    l2cap->frame_in_len += len;
-
-    if (len >= L2CAP_HDR_SIZE)
-        if (len >= L2CAP_HDR_SIZE + le16_to_cpu(hdr->len))
-            l2cap_frame_in(l2cap, hdr);
-            /* There is never a start of a new PDU in the same ACL packet, so
-             * no need to memmove the remaining payload and loop.  */
-}
-
-static inline uint8_t *l2cap_pdu_out(struct l2cap_instance_s *l2cap,
-                uint16_t cid, uint16_t len)
-{
-    l2cap_hdr *hdr = (void *) l2cap->frame_out;
-
-    l2cap->frame_out_len = len + L2CAP_HDR_SIZE;
-
-    hdr->cid = cpu_to_le16(cid);
-    hdr->len = cpu_to_le16(len);
-
-    return l2cap->frame_out + L2CAP_HDR_SIZE;
-}
-
-static inline void l2cap_pdu_submit(struct l2cap_instance_s *l2cap)
-{
-    /* TODO: Fragmentation */
-    (l2cap->role ?
-     l2cap->link->slave->lmp_acl_data : l2cap->link->host->lmp_acl_resp)
-            (l2cap->link, l2cap->frame_out, 1, l2cap->frame_out_len);
-}
-
-static uint8_t *l2cap_bframe_out(struct bt_l2cap_conn_params_s *parm, int len)
-{
-    struct l2cap_chan_s *chan = (struct l2cap_chan_s *) parm;
-
-    if (len > chan->params.remote_mtu) {
-        fprintf(stderr, "%s: B-Frame for CID %04x longer than %i octets.\n",
-                        __FUNCTION__,
-                        chan->remote_cid, chan->params.remote_mtu);
-        exit(-1);
-    }
-
-    return l2cap_pdu_out(chan->l2cap, chan->remote_cid, len);
-}
-
-static void l2cap_bframe_submit(struct bt_l2cap_conn_params_s *parms)
-{
-    struct l2cap_chan_s *chan = (struct l2cap_chan_s *) parms;
-
-    l2cap_pdu_submit(chan->l2cap);
-}
-
-#if 0
-/* Stub: Only used if an emulated device requests outgoing flow control */
-static uint8_t *l2cap_iframe_out(struct bt_l2cap_conn_params_s *parm, int len)
-{
-    struct l2cap_chan_s *chan = (struct l2cap_chan_s *) parm;
-
-    if (len > chan->params.remote_mtu) {
-        /* TODO: slice into segments and queue each segment as a separate
-         * I-Frame in a FIFO of I-Frames, local to the CID.  */
-    } else {
-        /* TODO: add to the FIFO of I-Frames, local to the CID.  */
-        /* Possibly we need to return a pointer to a contiguous buffer
-         * for now and then memcpy from it into FIFOs in l2cap_iframe_submit
-         * while segmenting at the same time.  */
-    }
-    return 0;
-}
-
-static void l2cap_iframe_submit(struct bt_l2cap_conn_params_s *parm)
-{
-    /* TODO: If flow control indicates clear to send, start submitting the
-     * invidual I-Frames from the FIFO, but don't remove them from there.
-     * Kick the appropriate timer until we get an S-Frame, and only then
-     * remove from FIFO or resubmit and re-kick the timer if the timer
-     * expired.  */
-}
-#endif
-
-static void l2cap_init(struct l2cap_instance_s *l2cap,
-                struct bt_link_s *link, int role)
-{
-    l2cap->link = link;
-    l2cap->role = role;
-    l2cap->dev = (struct bt_l2cap_device_s *)
-            (role ? link->host : link->slave);
-
-    l2cap->next_id = 1;
-
-    /* Establish the signalling channel */
-    l2cap->signalling_ch.params.sdu_in = l2cap_cframe_in;
-    l2cap->signalling_ch.params.sdu_out = l2cap_bframe_out;
-    l2cap->signalling_ch.params.sdu_submit = l2cap_bframe_submit;
-    l2cap->signalling_ch.params.opaque = l2cap;
-    l2cap->signalling_ch.params.remote_mtu = 48;
-    l2cap->signalling_ch.remote_cid = L2CAP_CID_SIGNALLING;
-    l2cap->signalling_ch.frame_in = l2cap_bframe_in;
-    l2cap->signalling_ch.mps = 65536;
-    l2cap->signalling_ch.min_mtu = 48;
-    l2cap->signalling_ch.mode = L2CAP_MODE_BASIC;
-    l2cap->signalling_ch.l2cap = l2cap;
-    l2cap->cid[L2CAP_CID_SIGNALLING] = &l2cap->signalling_ch;
-
-    /* Establish the connection-less data channel */
-    l2cap->group_ch.params.sdu_in = l2cap_gframe_in;
-    l2cap->group_ch.params.opaque = l2cap;
-    l2cap->group_ch.frame_in = l2cap_bframe_in;
-    l2cap->group_ch.mps = 65533;
-    l2cap->group_ch.l2cap = l2cap;
-    l2cap->group_ch.remote_cid = L2CAP_CID_INVALID;
-    l2cap->cid[L2CAP_CID_GROUP] = &l2cap->group_ch;
-}
-
-static void l2cap_teardown(struct l2cap_instance_s *l2cap, int send_disconnect)
-{
-    int cid;
-
-    /* Don't send DISCONNECT if we are currently handling a DISCONNECT
-     * sent from the other side.  */
-    if (send_disconnect) {
-        if (l2cap->role)
-            l2cap->dev->device.lmp_disconnect_slave(l2cap->link);
-            /* l2cap->link is invalid from now on.  */
-        else
-            l2cap->dev->device.lmp_disconnect_master(l2cap->link);
-    }
-
-    for (cid = L2CAP_CID_ALLOC; cid < L2CAP_CID_MAX; cid ++)
-        if (l2cap->cid[cid]) {
-            l2cap->cid[cid]->params.close(l2cap->cid[cid]->params.opaque);
-            g_free(l2cap->cid[cid]);
-        }
-
-    if (l2cap->role)
-        g_free(l2cap);
-    else
-        g_free(l2cap->link);
-}
-
-/* L2CAP glue to lower layers in bluetooth stack (LMP) */
-
-static void l2cap_lmp_connection_request(struct bt_link_s *link)
-{
-    struct bt_l2cap_device_s *dev = (struct bt_l2cap_device_s *) link->slave;
-    struct slave_l2cap_instance_s *l2cap;
-
-    /* Always accept - we only get called if (dev->device->page_scan).  */
-
-    l2cap = g_malloc0(sizeof(struct slave_l2cap_instance_s));
-    l2cap->link.slave = &dev->device;
-    l2cap->link.host = link->host;
-    l2cap_init(&l2cap->l2cap, &l2cap->link, 0);
-
-    /* Always at the end */
-    link->host->reject_reason = 0;
-    link->host->lmp_connection_complete(&l2cap->link);
-}
-
-/* Stub */
-static void l2cap_lmp_connection_complete(struct bt_link_s *link)
-{
-    struct bt_l2cap_device_s *dev = (struct bt_l2cap_device_s *) link->host;
-    struct l2cap_instance_s *l2cap;
-
-    if (dev->device.reject_reason) {
-        /* Signal to upper layer */
-        return;
-    }
-
-    l2cap = g_malloc0(sizeof(struct l2cap_instance_s));
-    l2cap_init(l2cap, link, 1);
-
-    link->acl_mode = acl_active;
-
-    /* Signal to upper layer */
-}
-
-/* Stub */
-static void l2cap_lmp_disconnect_host(struct bt_link_s *link)
-{
-    struct bt_l2cap_device_s *dev = (struct bt_l2cap_device_s *) link->host;
-    struct l2cap_instance_s *l2cap =
-            /* TODO: Retrieve from upper layer */ (void *) dev;
-
-    /* Signal to upper layer */
-
-    l2cap_teardown(l2cap, 0);
-}
-
-static void l2cap_lmp_disconnect_slave(struct bt_link_s *link)
-{
-    struct slave_l2cap_instance_s *l2cap =
-            (struct slave_l2cap_instance_s *) link;
-
-    l2cap_teardown(&l2cap->l2cap, 0);
-}
-
-static void l2cap_lmp_acl_data_slave(struct bt_link_s *link,
-                const uint8_t *data, int start, int len)
-{
-    struct slave_l2cap_instance_s *l2cap =
-            (struct slave_l2cap_instance_s *) link;
-
-    if (start)
-        l2cap->l2cap.frame_in_len = 0;
-
-    l2cap_pdu_in(&l2cap->l2cap, data, len);
-}
-
-/* Stub */
-static void l2cap_lmp_acl_data_host(struct bt_link_s *link,
-                const uint8_t *data, int start, int len)
-{
-    struct bt_l2cap_device_s *dev = (struct bt_l2cap_device_s *) link->host;
-    struct l2cap_instance_s *l2cap =
-            /* TODO: Retrieve from upper layer */ (void *) dev;
-
-    if (start)
-        l2cap->frame_in_len = 0;
-
-    l2cap_pdu_in(l2cap, data, len);
-}
-
-static void l2cap_dummy_destroy(struct bt_device_s *dev)
-{
-    struct bt_l2cap_device_s *l2cap_dev = (struct bt_l2cap_device_s *) dev;
-
-    bt_l2cap_device_done(l2cap_dev);
-}
-
-void bt_l2cap_device_init(struct bt_l2cap_device_s *dev,
-                struct bt_scatternet_s *net)
-{
-    bt_device_init(&dev->device, net);
-
-    dev->device.lmp_connection_request = l2cap_lmp_connection_request;
-    dev->device.lmp_connection_complete = l2cap_lmp_connection_complete;
-    dev->device.lmp_disconnect_master = l2cap_lmp_disconnect_host;
-    dev->device.lmp_disconnect_slave = l2cap_lmp_disconnect_slave;
-    dev->device.lmp_acl_data = l2cap_lmp_acl_data_slave;
-    dev->device.lmp_acl_resp = l2cap_lmp_acl_data_host;
-
-    dev->device.handle_destroy = l2cap_dummy_destroy;
-}
-
-void bt_l2cap_device_done(struct bt_l2cap_device_s *dev)
-{
-    bt_device_done(&dev->device);
-
-    /* Should keep a list of all instances and go through it and
-     * invoke l2cap_teardown() for each.  */
-}
-
-void bt_l2cap_psm_register(struct bt_l2cap_device_s *dev, int psm, int min_mtu,
-                int (*new_channel)(struct bt_l2cap_device_s *dev,
-                        struct bt_l2cap_conn_params_s *params))
-{
-    struct bt_l2cap_psm_s *new_psm = l2cap_psm(dev, psm);
-
-    if (new_psm) {
-        fprintf(stderr, "%s: PSM %04x already registered for device `%s'.\n",
-                        __FUNCTION__, psm, dev->device.lmp_name);
-        exit(-1);
-    }
-
-    new_psm = g_malloc0(sizeof(*new_psm));
-    new_psm->psm = psm;
-    new_psm->min_mtu = min_mtu;
-    new_psm->new_channel = new_channel;
-    new_psm->next = dev->first_psm;
-    dev->first_psm = new_psm;
-}
diff --git a/hw/bt-sdp.c b/hw/bt-sdp.c
deleted file mode 100644 (file)
index 218e075..0000000
+++ /dev/null
@@ -1,967 +0,0 @@
-/*
- * Service Discover Protocol server for QEMU L2CAP devices
- *
- * Copyright (C) 2008 Andrzej Zaborowski  <balrog@zabor.org>
- *
- * 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 "hw/bt.h"
-
-struct bt_l2cap_sdp_state_s {
-    struct bt_l2cap_conn_params_s *channel;
-
-    struct sdp_service_record_s {
-        int match;
-
-        int *uuid;
-        int uuids;
-        struct sdp_service_attribute_s {
-            int match;
-
-            int attribute_id;
-            int len;
-            void *pair;
-        } *attribute_list;
-        int attributes;
-    } *service_list;
-    int services;
-};
-
-static ssize_t sdp_datalen(const uint8_t **element, ssize_t *left)
-{
-    size_t len = *(*element) ++ & SDP_DSIZE_MASK;
-
-    if (!*left)
-        return -1;
-    (*left) --;
-
-    if (len < SDP_DSIZE_NEXT1)
-        return 1 << len;
-    else if (len == SDP_DSIZE_NEXT1) {
-        if (*left < 1)
-            return -1;
-        (*left) --;
-
-        return *(*element) ++;
-    } else if (len == SDP_DSIZE_NEXT2) {
-        if (*left < 2)
-            return -1;
-        (*left) -= 2;
-
-        len = (*(*element) ++) << 8;
-        return len | (*(*element) ++);
-    } else {
-        if (*left < 4)
-            return -1;
-        (*left) -= 4;
-
-        len = (*(*element) ++) << 24;
-        len |= (*(*element) ++) << 16;
-        len |= (*(*element) ++) << 8;
-        return len | (*(*element) ++);
-    }
-}
-
-static const uint8_t bt_base_uuid[12] = {
-    0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
-};
-
-static int sdp_uuid_match(struct sdp_service_record_s *record,
-                const uint8_t *uuid, ssize_t datalen)
-{
-    int *lo, hi, val;
-
-    if (datalen == 16 || datalen == 4) {
-        if (datalen == 16 && memcmp(uuid + 4, bt_base_uuid, 12))
-            return 0;
-
-        if (uuid[0] | uuid[1])
-            return 0;
-        uuid += 2;
-    }
-
-    val = (uuid[0] << 8) | uuid[1];
-    lo = record->uuid;
-    hi = record->uuids;
-    while (hi >>= 1)
-        if (lo[hi] <= val)
-            lo += hi;
-
-    return *lo == val;
-}
-
-#define CONTINUATION_PARAM_SIZE        (1 + sizeof(int))
-#define MAX_PDU_OUT_SIZE       96      /* Arbitrary */
-#define PDU_HEADER_SIZE                5
-#define MAX_RSP_PARAM_SIZE     (MAX_PDU_OUT_SIZE - PDU_HEADER_SIZE - \
-                CONTINUATION_PARAM_SIZE)
-
-static int sdp_svc_match(struct bt_l2cap_sdp_state_s *sdp,
-                const uint8_t **req, ssize_t *len)
-{
-    size_t datalen;
-    int i;
-
-    if ((**req & ~SDP_DSIZE_MASK) != SDP_DTYPE_UUID)
-        return 1;
-
-    datalen = sdp_datalen(req, len);
-    if (datalen != 2 && datalen != 4 && datalen != 16)
-        return 1;
-
-    for (i = 0; i < sdp->services; i ++)
-        if (sdp_uuid_match(&sdp->service_list[i], *req, datalen))
-            sdp->service_list[i].match = 1;
-
-    (*req) += datalen;
-    (*len) -= datalen;
-
-    return 0;
-}
-
-static ssize_t sdp_svc_search(struct bt_l2cap_sdp_state_s *sdp,
-                uint8_t *rsp, const uint8_t *req, ssize_t len)
-{
-    ssize_t seqlen;
-    int i, count, start, end, max;
-    int32_t handle;
-
-    /* Perform the search */
-    for (i = 0; i < sdp->services; i ++)
-        sdp->service_list[i].match = 0;
-
-    if (len < 1)
-        return -SDP_INVALID_SYNTAX;
-    if ((*req & ~SDP_DSIZE_MASK) == SDP_DTYPE_SEQ) {
-        seqlen = sdp_datalen(&req, &len);
-        if (seqlen < 3 || len < seqlen)
-            return -SDP_INVALID_SYNTAX;
-        len -= seqlen;
-
-        while (seqlen)
-            if (sdp_svc_match(sdp, &req, &seqlen))
-                return -SDP_INVALID_SYNTAX;
-    } else if (sdp_svc_match(sdp, &req, &seqlen))
-        return -SDP_INVALID_SYNTAX;
-
-    if (len < 3)
-        return -SDP_INVALID_SYNTAX;
-    max = (req[0] << 8) | req[1];
-    req += 2;
-    len -= 2;
-
-    if (*req) {
-        if (len <= sizeof(int))
-            return -SDP_INVALID_SYNTAX;
-        len -= sizeof(int);
-        memcpy(&start, req + 1, sizeof(int));
-    } else
-        start = 0;
-
-    if (len > 1)
-        return -SDP_INVALID_SYNTAX;
-
-    /* Output the results */
-    len = 4;
-    count = 0;
-    end = start;
-    for (i = 0; i < sdp->services; i ++)
-        if (sdp->service_list[i].match) {
-            if (count >= start && count < max && len + 4 < MAX_RSP_PARAM_SIZE) {
-                handle = i;
-                memcpy(rsp + len, &handle, 4);
-                len += 4;
-                end = count + 1;
-            }
-
-            count ++;
-        }
-
-    rsp[0] = count >> 8;
-    rsp[1] = count & 0xff;
-    rsp[2] = (end - start) >> 8;
-    rsp[3] = (end - start) & 0xff;
-
-    if (end < count) {
-        rsp[len ++] = sizeof(int);
-        memcpy(rsp + len, &end, sizeof(int));
-        len += 4;
-    } else
-        rsp[len ++] = 0;
-
-    return len;
-}
-
-static int sdp_attr_match(struct sdp_service_record_s *record,
-                const uint8_t **req, ssize_t *len)
-{
-    int i, start, end;
-
-    if (**req == (SDP_DTYPE_UINT | SDP_DSIZE_2)) {
-        (*req) ++;
-        if (*len < 3)
-            return 1;
-
-        start = (*(*req) ++) << 8;
-        start |= *(*req) ++;
-        end = start;
-        *len -= 3;
-    } else if (**req == (SDP_DTYPE_UINT | SDP_DSIZE_4)) {
-        (*req) ++;
-        if (*len < 5)
-            return 1;
-
-        start = (*(*req) ++) << 8;
-        start |= *(*req) ++;
-        end = (*(*req) ++) << 8;
-        end |= *(*req) ++;
-        *len -= 5;
-    } else
-        return 1;
-
-    for (i = 0; i < record->attributes; i ++)
-        if (record->attribute_list[i].attribute_id >= start &&
-                        record->attribute_list[i].attribute_id <= end)
-            record->attribute_list[i].match = 1;
-
-    return 0;
-}
-
-static ssize_t sdp_attr_get(struct bt_l2cap_sdp_state_s *sdp,
-                uint8_t *rsp, const uint8_t *req, ssize_t len)
-{
-    ssize_t seqlen;
-    int i, start, end, max;
-    int32_t handle;
-    struct sdp_service_record_s *record;
-    uint8_t *lst;
-
-    /* Perform the search */
-    if (len < 7)
-        return -SDP_INVALID_SYNTAX;
-    memcpy(&handle, req, 4);
-    req += 4;
-    len -= 4;
-
-    if (handle < 0 || handle > sdp->services)
-        return -SDP_INVALID_RECORD_HANDLE;
-    record = &sdp->service_list[handle];
-
-    for (i = 0; i < record->attributes; i ++)
-        record->attribute_list[i].match = 0;
-
-    max = (req[0] << 8) | req[1];
-    req += 2;
-    len -= 2;
-    if (max < 0x0007)
-        return -SDP_INVALID_SYNTAX;
-
-    if ((*req & ~SDP_DSIZE_MASK) == SDP_DTYPE_SEQ) {
-        seqlen = sdp_datalen(&req, &len);
-        if (seqlen < 3 || len < seqlen)
-            return -SDP_INVALID_SYNTAX;
-        len -= seqlen;
-
-        while (seqlen)
-            if (sdp_attr_match(record, &req, &seqlen))
-                return -SDP_INVALID_SYNTAX;
-    } else if (sdp_attr_match(record, &req, &seqlen))
-        return -SDP_INVALID_SYNTAX;
-
-    if (len < 1)
-        return -SDP_INVALID_SYNTAX;
-
-    if (*req) {
-        if (len <= sizeof(int))
-            return -SDP_INVALID_SYNTAX;
-        len -= sizeof(int);
-        memcpy(&start, req + 1, sizeof(int));
-    } else
-        start = 0;
-
-    if (len > 1)
-        return -SDP_INVALID_SYNTAX;
-
-    /* Output the results */
-    lst = rsp + 2;
-    max = MIN(max, MAX_RSP_PARAM_SIZE);
-    len = 3 - start;
-    end = 0;
-    for (i = 0; i < record->attributes; i ++)
-        if (record->attribute_list[i].match) {
-            if (len >= 0 && len + record->attribute_list[i].len < max) {
-                memcpy(lst + len, record->attribute_list[i].pair,
-                                record->attribute_list[i].len);
-                end = len + record->attribute_list[i].len;
-            }
-            len += record->attribute_list[i].len;
-        }
-    if (0 >= start) {
-       lst[0] = SDP_DTYPE_SEQ | SDP_DSIZE_NEXT2;
-       lst[1] = (len + start - 3) >> 8;
-       lst[2] = (len + start - 3) & 0xff;
-    }
-
-    rsp[0] = end >> 8;
-    rsp[1] = end & 0xff;
-
-    if (end < len) {
-        len = end + start;
-        lst[end ++] = sizeof(int);
-        memcpy(lst + end, &len, sizeof(int));
-        end += sizeof(int);
-    } else
-        lst[end ++] = 0;
-
-    return end + 2;
-}
-
-static int sdp_svc_attr_match(struct bt_l2cap_sdp_state_s *sdp,
-                const uint8_t **req, ssize_t *len)
-{
-    int i, j, start, end;
-    struct sdp_service_record_s *record;
-
-    if (**req == (SDP_DTYPE_UINT | SDP_DSIZE_2)) {
-        (*req) ++;
-        if (*len < 3)
-            return 1;
-
-        start = (*(*req) ++) << 8;
-        start |= *(*req) ++;
-        end = start;
-        *len -= 3;
-    } else if (**req == (SDP_DTYPE_UINT | SDP_DSIZE_4)) {
-        (*req) ++;
-        if (*len < 5)
-            return 1;
-
-        start = (*(*req) ++) << 8;
-        start |= *(*req) ++;
-        end = (*(*req) ++) << 8;
-        end |= *(*req) ++;
-        *len -= 5;
-    } else
-        return 1;
-
-    for (i = 0; i < sdp->services; i ++)
-        if ((record = &sdp->service_list[i])->match)
-            for (j = 0; j < record->attributes; j ++)
-                if (record->attribute_list[j].attribute_id >= start &&
-                                record->attribute_list[j].attribute_id <= end)
-                    record->attribute_list[j].match = 1;
-
-    return 0;
-}
-
-static ssize_t sdp_svc_search_attr_get(struct bt_l2cap_sdp_state_s *sdp,
-                uint8_t *rsp, const uint8_t *req, ssize_t len)
-{
-    ssize_t seqlen;
-    int i, j, start, end, max;
-    struct sdp_service_record_s *record;
-    uint8_t *lst;
-
-    /* Perform the search */
-    for (i = 0; i < sdp->services; i ++) {
-        sdp->service_list[i].match = 0;
-            for (j = 0; j < sdp->service_list[i].attributes; j ++)
-                sdp->service_list[i].attribute_list[j].match = 0;
-    }
-
-    if (len < 1)
-        return -SDP_INVALID_SYNTAX;
-    if ((*req & ~SDP_DSIZE_MASK) == SDP_DTYPE_SEQ) {
-        seqlen = sdp_datalen(&req, &len);
-        if (seqlen < 3 || len < seqlen)
-            return -SDP_INVALID_SYNTAX;
-        len -= seqlen;
-
-        while (seqlen)
-            if (sdp_svc_match(sdp, &req, &seqlen))
-                return -SDP_INVALID_SYNTAX;
-    } else if (sdp_svc_match(sdp, &req, &seqlen))
-        return -SDP_INVALID_SYNTAX;
-
-    if (len < 3)
-        return -SDP_INVALID_SYNTAX;
-    max = (req[0] << 8) | req[1];
-    req += 2;
-    len -= 2;
-    if (max < 0x0007)
-        return -SDP_INVALID_SYNTAX;
-
-    if ((*req & ~SDP_DSIZE_MASK) == SDP_DTYPE_SEQ) {
-        seqlen = sdp_datalen(&req, &len);
-        if (seqlen < 3 || len < seqlen)
-            return -SDP_INVALID_SYNTAX;
-        len -= seqlen;
-
-        while (seqlen)
-            if (sdp_svc_attr_match(sdp, &req, &seqlen))
-                return -SDP_INVALID_SYNTAX;
-    } else if (sdp_svc_attr_match(sdp, &req, &seqlen))
-        return -SDP_INVALID_SYNTAX;
-
-    if (len < 1)
-        return -SDP_INVALID_SYNTAX;
-
-    if (*req) {
-        if (len <= sizeof(int))
-            return -SDP_INVALID_SYNTAX;
-        len -= sizeof(int);
-        memcpy(&start, req + 1, sizeof(int));
-    } else
-        start = 0;
-
-    if (len > 1)
-        return -SDP_INVALID_SYNTAX;
-
-    /* Output the results */
-    /* This assumes empty attribute lists are never to be returned even
-     * for matching Service Records.  In practice this shouldn't happen
-     * as the requestor will usually include the always present
-     * ServiceRecordHandle AttributeID in AttributeIDList.  */
-    lst = rsp + 2;
-    max = MIN(max, MAX_RSP_PARAM_SIZE);
-    len = 3 - start;
-    end = 0;
-    for (i = 0; i < sdp->services; i ++)
-        if ((record = &sdp->service_list[i])->match) {
-            len += 3;
-            seqlen = len;
-            for (j = 0; j < record->attributes; j ++)
-                if (record->attribute_list[j].match) {
-                    if (len >= 0)
-                        if (len + record->attribute_list[j].len < max) {
-                            memcpy(lst + len, record->attribute_list[j].pair,
-                                            record->attribute_list[j].len);
-                            end = len + record->attribute_list[j].len;
-                        }
-                    len += record->attribute_list[j].len;
-                }
-            if (seqlen == len)
-                len -= 3;
-            else if (seqlen >= 3 && seqlen < max) {
-                lst[seqlen - 3] = SDP_DTYPE_SEQ | SDP_DSIZE_NEXT2;
-                lst[seqlen - 2] = (len - seqlen) >> 8;
-                lst[seqlen - 1] = (len - seqlen) & 0xff;
-            }
-        }
-    if (len == 3 - start)
-        len -= 3;
-    else if (0 >= start) {
-       lst[0] = SDP_DTYPE_SEQ | SDP_DSIZE_NEXT2;
-       lst[1] = (len + start - 3) >> 8;
-       lst[2] = (len + start - 3) & 0xff;
-    }
-
-    rsp[0] = end >> 8;
-    rsp[1] = end & 0xff;
-
-    if (end < len) {
-        len = end + start;
-        lst[end ++] = sizeof(int);
-        memcpy(lst + end, &len, sizeof(int));
-        end += sizeof(int);
-    } else
-        lst[end ++] = 0;
-
-    return end + 2;
-}
-
-static void bt_l2cap_sdp_sdu_in(void *opaque, const uint8_t *data, int len)
-{
-    struct bt_l2cap_sdp_state_s *sdp = opaque;
-    enum bt_sdp_cmd pdu_id;
-    uint8_t rsp[MAX_PDU_OUT_SIZE - PDU_HEADER_SIZE], *sdu_out;
-    int transaction_id, plen;
-    int err = 0;
-    int rsp_len = 0;
-
-    if (len < 5) {
-        fprintf(stderr, "%s: short SDP PDU (%iB).\n", __FUNCTION__, len);
-        return;
-    }
-
-    pdu_id = *data ++;
-    transaction_id = (data[0] << 8) | data[1];
-    plen = (data[2] << 8) | data[3];
-    data += 4;
-    len -= 5;
-
-    if (len != plen) {
-        fprintf(stderr, "%s: wrong SDP PDU length (%iB != %iB).\n",
-                        __FUNCTION__, plen, len);
-        err = SDP_INVALID_PDU_SIZE;
-        goto respond;
-    }
-
-    switch (pdu_id) {
-    case SDP_SVC_SEARCH_REQ:
-        rsp_len = sdp_svc_search(sdp, rsp, data, len);
-        pdu_id = SDP_SVC_SEARCH_RSP;
-        break;
-
-    case SDP_SVC_ATTR_REQ:
-        rsp_len = sdp_attr_get(sdp, rsp, data, len);
-        pdu_id = SDP_SVC_ATTR_RSP;
-        break;
-
-    case SDP_SVC_SEARCH_ATTR_REQ:
-        rsp_len = sdp_svc_search_attr_get(sdp, rsp, data, len);
-        pdu_id = SDP_SVC_SEARCH_ATTR_RSP;
-        break;
-
-    case SDP_ERROR_RSP:
-    case SDP_SVC_ATTR_RSP:
-    case SDP_SVC_SEARCH_RSP:
-    case SDP_SVC_SEARCH_ATTR_RSP:
-    default:
-        fprintf(stderr, "%s: unexpected SDP PDU ID %02x.\n",
-                        __FUNCTION__, pdu_id);
-        err = SDP_INVALID_SYNTAX;
-        break;
-    }
-
-    if (rsp_len < 0) {
-        err = -rsp_len;
-        rsp_len = 0;
-    }
-
-respond:
-    if (err) {
-        pdu_id = SDP_ERROR_RSP;
-        rsp[rsp_len ++] = err >> 8;
-        rsp[rsp_len ++] = err & 0xff;
-    }
-
-    sdu_out = sdp->channel->sdu_out(sdp->channel, rsp_len + PDU_HEADER_SIZE);
-
-    sdu_out[0] = pdu_id;
-    sdu_out[1] = transaction_id >> 8;
-    sdu_out[2] = transaction_id & 0xff;
-    sdu_out[3] = rsp_len >> 8;
-    sdu_out[4] = rsp_len & 0xff;
-    memcpy(sdu_out + PDU_HEADER_SIZE, rsp, rsp_len);
-
-    sdp->channel->sdu_submit(sdp->channel);
-}
-
-static void bt_l2cap_sdp_close_ch(void *opaque)
-{
-    struct bt_l2cap_sdp_state_s *sdp = opaque;
-    int i;
-
-    for (i = 0; i < sdp->services; i ++) {
-        g_free(sdp->service_list[i].attribute_list->pair);
-        g_free(sdp->service_list[i].attribute_list);
-        g_free(sdp->service_list[i].uuid);
-    }
-    g_free(sdp->service_list);
-    g_free(sdp);
-}
-
-struct sdp_def_service_s {
-    uint16_t class_uuid;
-    struct sdp_def_attribute_s {
-        uint16_t id;
-        struct sdp_def_data_element_s {
-            uint8_t type;
-            union {
-                uint32_t uint;
-                const char *str;
-                struct sdp_def_data_element_s *list;
-            } value;
-        } data;
-    } attributes[];
-};
-
-/* Calculate a safe byte count to allocate that will store the given
- * element, at the same time count elements of a UUID type.  */
-static int sdp_attr_max_size(struct sdp_def_data_element_s *element,
-                int *uuids)
-{
-    int type = element->type & ~SDP_DSIZE_MASK;
-    int len;
-
-    if (type == SDP_DTYPE_UINT || type == SDP_DTYPE_UUID ||
-                    type == SDP_DTYPE_BOOL) {
-        if (type == SDP_DTYPE_UUID)
-            (*uuids) ++;
-        return 1 + (1 << (element->type & SDP_DSIZE_MASK));
-    }
-
-    if (type == SDP_DTYPE_STRING || type == SDP_DTYPE_URL) {
-        if (element->type & SDP_DSIZE_MASK) {
-            for (len = 0; element->value.str[len] |
-                            element->value.str[len + 1]; len ++);
-            return len;
-        } else
-            return 2 + strlen(element->value.str);
-    }
-
-    if (type != SDP_DTYPE_SEQ)
-        exit(-1);
-    len = 2;
-    element = element->value.list;
-    while (element->type)
-        len += sdp_attr_max_size(element ++, uuids);
-    if (len > 255)
-        exit (-1);
-
-    return len;
-}
-
-static int sdp_attr_write(uint8_t *data,
-                struct sdp_def_data_element_s *element, int **uuid)
-{
-    int type = element->type & ~SDP_DSIZE_MASK;
-    int len = 0;
-
-    if (type == SDP_DTYPE_UINT || type == SDP_DTYPE_BOOL) {
-        data[len ++] = element->type;
-        if ((element->type & SDP_DSIZE_MASK) == SDP_DSIZE_1)
-            data[len ++] = (element->value.uint >>  0) & 0xff;
-        else if ((element->type & SDP_DSIZE_MASK) == SDP_DSIZE_2) {
-            data[len ++] = (element->value.uint >>  8) & 0xff;
-            data[len ++] = (element->value.uint >>  0) & 0xff;
-        } else if ((element->type & SDP_DSIZE_MASK) == SDP_DSIZE_4) {
-            data[len ++] = (element->value.uint >>  24) & 0xff;
-            data[len ++] = (element->value.uint >>  16) & 0xff;
-            data[len ++] = (element->value.uint >>  8) & 0xff;
-            data[len ++] = (element->value.uint >>  0) & 0xff;
-        }
-
-        return len;
-    }
-
-    if (type == SDP_DTYPE_UUID) {
-        *(*uuid) ++ = element->value.uint;
-
-        data[len ++] = element->type;
-        data[len ++] = (element->value.uint >>  24) & 0xff;
-        data[len ++] = (element->value.uint >>  16) & 0xff;
-        data[len ++] = (element->value.uint >>  8) & 0xff;
-        data[len ++] = (element->value.uint >>  0) & 0xff;
-        memcpy(data + len, bt_base_uuid, 12);
-
-        return len + 12;
-    }
-
-    data[0] = type | SDP_DSIZE_NEXT1;
-    if (type == SDP_DTYPE_STRING || type == SDP_DTYPE_URL) {
-        if (element->type & SDP_DSIZE_MASK)
-            for (len = 0; element->value.str[len] |
-                            element->value.str[len + 1]; len ++);
-        else
-            len = strlen(element->value.str);
-        memcpy(data + 2, element->value.str, data[1] = len);
-
-        return len + 2;
-    }
-
-    len = 2;
-    element = element->value.list;
-    while (element->type)
-        len += sdp_attr_write(data + len, element ++, uuid);
-    data[1] = len - 2;
-
-    return len;
-}
-
-static int sdp_attributeid_compare(const struct sdp_service_attribute_s *a,
-                const struct sdp_service_attribute_s *b)
-{
-    return (int) b->attribute_id - a->attribute_id;
-}
-
-static int sdp_uuid_compare(const int *a, const int *b)
-{
-    return *a - *b;
-}
-
-static void sdp_service_record_build(struct sdp_service_record_s *record,
-                struct sdp_def_service_s *def, int handle)
-{
-    int len = 0;
-    uint8_t *data;
-    int *uuid;
-
-    record->uuids = 0;
-    while (def->attributes[record->attributes].data.type) {
-        len += 3;
-        len += sdp_attr_max_size(&def->attributes[record->attributes ++].data,
-                        &record->uuids);
-    }
-    record->uuids = 1 << ffs(record->uuids - 1);
-    record->attribute_list =
-            g_malloc0(record->attributes * sizeof(*record->attribute_list));
-    record->uuid =
-            g_malloc0(record->uuids * sizeof(*record->uuid));
-    data = g_malloc(len);
-
-    record->attributes = 0;
-    uuid = record->uuid;
-    while (def->attributes[record->attributes].data.type) {
-        record->attribute_list[record->attributes].pair = data;
-
-        len = 0;
-        data[len ++] = SDP_DTYPE_UINT | SDP_DSIZE_2;
-        data[len ++] = def->attributes[record->attributes].id >> 8;
-        data[len ++] = def->attributes[record->attributes].id & 0xff;
-        len += sdp_attr_write(data + len,
-                        &def->attributes[record->attributes].data, &uuid);
-
-        /* Special case: assign a ServiceRecordHandle in sequence */
-        if (def->attributes[record->attributes].id == SDP_ATTR_RECORD_HANDLE)
-            def->attributes[record->attributes].data.value.uint = handle;
-        /* Note: we could also assign a ServiceDescription based on
-         * sdp->device.device->lmp_name.  */
-
-        record->attribute_list[record->attributes ++].len = len;
-        data += len;
-    }
-
-    /* Sort the attribute list by the AttributeID */
-    qsort(record->attribute_list, record->attributes,
-                    sizeof(*record->attribute_list),
-                    (void *) sdp_attributeid_compare);
-    /* Sort the searchable UUIDs list for bisection */
-    qsort(record->uuid, record->uuids,
-                    sizeof(*record->uuid),
-                    (void *) sdp_uuid_compare);
-}
-
-static void sdp_service_db_build(struct bt_l2cap_sdp_state_s *sdp,
-                struct sdp_def_service_s **service)
-{
-    sdp->services = 0;
-    while (service[sdp->services])
-        sdp->services ++;
-    sdp->service_list =
-            g_malloc0(sdp->services * sizeof(*sdp->service_list));
-
-    sdp->services = 0;
-    while (*service) {
-        sdp_service_record_build(&sdp->service_list[sdp->services],
-                        *service, sdp->services);
-        service ++;
-        sdp->services ++;
-    }
-}
-
-#define LAST { .type = 0 }
-#define SERVICE(name, attrs)                           \
-    static struct sdp_def_service_s glue(glue(sdp_service_, name), _s) = { \
-        .attributes = { attrs { .data = LAST } },      \
-    };
-#define ATTRIBUTE(attrid, val) { .id = glue(SDP_ATTR_, attrid), .data = val },
-#define UINT8(val)     {                               \
-        .type       = SDP_DTYPE_UINT | SDP_DSIZE_1,    \
-        .value.uint = val,                             \
-    },
-#define UINT16(val)    {                               \
-        .type       = SDP_DTYPE_UINT | SDP_DSIZE_2,    \
-        .value.uint = val,                             \
-    },
-#define UINT32(val)    {                               \
-        .type       = SDP_DTYPE_UINT | SDP_DSIZE_4,    \
-        .value.uint = val,                             \
-    },
-#define UUID128(val)   {                               \
-        .type       = SDP_DTYPE_UUID | SDP_DSIZE_16,   \
-        .value.uint = val,                             \
-    },
-#define SDP_TRUE       {                               \
-        .type       = SDP_DTYPE_BOOL | SDP_DSIZE_1,    \
-        .value.uint = 1,                               \
-    },
-#define SDP_FALSE      {                               \
-        .type       = SDP_DTYPE_BOOL | SDP_DSIZE_1,    \
-        .value.uint = 0,                               \
-    },
-#define STRING(val)    {                               \
-        .type       = SDP_DTYPE_STRING,                        \
-        .value.str  = val,                             \
-    },
-#define ARRAY(...)     {                               \
-        .type       = SDP_DTYPE_STRING | SDP_DSIZE_2,  \
-        .value.str  = (char []) { __VA_ARGS__, 0, 0 }, \
-    },
-#define URL(val)       {                               \
-        .type       = SDP_DTYPE_URL,                   \
-        .value.str  = val,                             \
-    },
-#if 1
-#define LIST(val)      {                               \
-        .type       = SDP_DTYPE_SEQ,                   \
-        .value.list = (struct sdp_def_data_element_s []) { val LAST }, \
-    },
-#endif
-
-/* Try to keep each single attribute below MAX_PDU_OUT_SIZE bytes
- * in resulting SDP data representation size.  */
-
-SERVICE(hid,
-    ATTRIBUTE(RECORD_HANDLE,   UINT32(0))      /* Filled in later */
-    ATTRIBUTE(SVCLASS_ID_LIST, LIST(UUID128(HID_SVCLASS_ID)))
-    ATTRIBUTE(RECORD_STATE,    UINT32(1))
-    ATTRIBUTE(PROTO_DESC_LIST, LIST(
-        LIST(UUID128(L2CAP_UUID) UINT16(BT_PSM_HID_CTRL))
-        LIST(UUID128(HIDP_UUID))
-    ))
-    ATTRIBUTE(BROWSE_GRP_LIST, LIST(UUID128(0x1002)))
-    ATTRIBUTE(LANG_BASE_ATTR_ID_LIST, LIST(
-        UINT16(0x656e) UINT16(0x006a) UINT16(0x0100)
-    ))
-    ATTRIBUTE(PFILE_DESC_LIST, LIST(
-        LIST(UUID128(HID_PROFILE_ID) UINT16(0x0100))
-    ))
-    ATTRIBUTE(DOC_URL,         URL("http://bellard.org/qemu/user-doc.html"))
-    ATTRIBUTE(SVCNAME_PRIMARY, STRING("QEMU Bluetooth HID"))
-    ATTRIBUTE(SVCDESC_PRIMARY, STRING("QEMU Keyboard/Mouse"))
-    ATTRIBUTE(SVCPROV_PRIMARY, STRING("QEMU"))
-
-    /* Profile specific */
-    ATTRIBUTE(DEVICE_RELEASE_NUMBER,   UINT16(0x0091)) /* Deprecated, remove */
-    ATTRIBUTE(PARSER_VERSION,          UINT16(0x0111))
-    /* TODO: extract from l2cap_device->device.class[0] */
-    ATTRIBUTE(DEVICE_SUBCLASS,         UINT8(0x40))
-    ATTRIBUTE(COUNTRY_CODE,            UINT8(0x15))
-    ATTRIBUTE(VIRTUAL_CABLE,           SDP_TRUE)
-    ATTRIBUTE(RECONNECT_INITIATE,      SDP_FALSE)
-    /* TODO: extract from hid->usbdev->report_desc */
-    ATTRIBUTE(DESCRIPTOR_LIST,         LIST(
-        LIST(UINT8(0x22) ARRAY(
-            0x05, 0x01,        /* Usage Page (Generic Desktop) */
-            0x09, 0x06,        /* Usage (Keyboard) */
-            0xa1, 0x01,        /* Collection (Application) */
-            0x75, 0x01,        /*   Report Size (1) */
-            0x95, 0x08,        /*   Report Count (8) */
-            0x05, 0x07,        /*   Usage Page (Key Codes) */
-            0x19, 0xe0,        /*   Usage Minimum (224) */
-            0x29, 0xe7,        /*   Usage Maximum (231) */
-            0x15, 0x00,        /*   Logical Minimum (0) */
-            0x25, 0x01,        /*   Logical Maximum (1) */
-            0x81, 0x02,        /*   Input (Data, Variable, Absolute) */
-            0x95, 0x01,        /*   Report Count (1) */
-            0x75, 0x08,        /*   Report Size (8) */
-            0x81, 0x01,        /*   Input (Constant) */
-            0x95, 0x05,        /*   Report Count (5) */
-            0x75, 0x01,        /*   Report Size (1) */
-            0x05, 0x08,        /*   Usage Page (LEDs) */
-            0x19, 0x01,        /*   Usage Minimum (1) */
-            0x29, 0x05,        /*   Usage Maximum (5) */
-            0x91, 0x02,        /*   Output (Data, Variable, Absolute) */
-            0x95, 0x01,        /*   Report Count (1) */
-            0x75, 0x03,        /*   Report Size (3) */
-            0x91, 0x01,        /*   Output (Constant) */
-            0x95, 0x06,        /*   Report Count (6) */
-            0x75, 0x08,        /*   Report Size (8) */
-            0x15, 0x00,        /*   Logical Minimum (0) */
-            0x25, 0xff,        /*   Logical Maximum (255) */
-            0x05, 0x07,        /*   Usage Page (Key Codes) */
-            0x19, 0x00,        /*   Usage Minimum (0) */
-            0x29, 0xff,        /*   Usage Maximum (255) */
-            0x81, 0x00,        /*   Input (Data, Array) */
-            0xc0       /* End Collection */
-    ))))
-    ATTRIBUTE(LANG_ID_BASE_LIST,       LIST(
-        LIST(UINT16(0x0409) UINT16(0x0100))
-    ))
-    ATTRIBUTE(SDP_DISABLE,             SDP_FALSE)
-    ATTRIBUTE(BATTERY_POWER,           SDP_TRUE)
-    ATTRIBUTE(REMOTE_WAKEUP,           SDP_TRUE)
-    ATTRIBUTE(BOOT_DEVICE,             SDP_TRUE)       /* XXX: untested */
-    ATTRIBUTE(SUPERVISION_TIMEOUT,     UINT16(0x0c80))
-    ATTRIBUTE(NORMALLY_CONNECTABLE,    SDP_TRUE)
-    ATTRIBUTE(PROFILE_VERSION,         UINT16(0x0100))
-)
-
-SERVICE(sdp,
-    ATTRIBUTE(RECORD_HANDLE,   UINT32(0))      /* Filled in later */
-    ATTRIBUTE(SVCLASS_ID_LIST, LIST(UUID128(SDP_SERVER_SVCLASS_ID)))
-    ATTRIBUTE(RECORD_STATE,    UINT32(1))
-    ATTRIBUTE(PROTO_DESC_LIST, LIST(
-        LIST(UUID128(L2CAP_UUID) UINT16(BT_PSM_SDP))
-        LIST(UUID128(SDP_UUID))
-    ))
-    ATTRIBUTE(BROWSE_GRP_LIST, LIST(UUID128(0x1002)))
-    ATTRIBUTE(LANG_BASE_ATTR_ID_LIST, LIST(
-        UINT16(0x656e) UINT16(0x006a) UINT16(0x0100)
-    ))
-    ATTRIBUTE(PFILE_DESC_LIST, LIST(
-        LIST(UUID128(SDP_SERVER_PROFILE_ID) UINT16(0x0100))
-    ))
-    ATTRIBUTE(DOC_URL,         URL("http://bellard.org/qemu/user-doc.html"))
-    ATTRIBUTE(SVCPROV_PRIMARY, STRING("QEMU"))
-
-    /* Profile specific */
-    ATTRIBUTE(VERSION_NUM_LIST, LIST(UINT16(0x0100)))
-    ATTRIBUTE(SVCDB_STATE    , UINT32(1))
-)
-
-SERVICE(pnp,
-    ATTRIBUTE(RECORD_HANDLE,   UINT32(0))      /* Filled in later */
-    ATTRIBUTE(SVCLASS_ID_LIST, LIST(UUID128(PNP_INFO_SVCLASS_ID)))
-    ATTRIBUTE(RECORD_STATE,    UINT32(1))
-    ATTRIBUTE(PROTO_DESC_LIST, LIST(
-        LIST(UUID128(L2CAP_UUID) UINT16(BT_PSM_SDP))
-        LIST(UUID128(SDP_UUID))
-    ))
-    ATTRIBUTE(BROWSE_GRP_LIST, LIST(UUID128(0x1002)))
-    ATTRIBUTE(LANG_BASE_ATTR_ID_LIST, LIST(
-        UINT16(0x656e) UINT16(0x006a) UINT16(0x0100)
-    ))
-    ATTRIBUTE(PFILE_DESC_LIST, LIST(
-        LIST(UUID128(PNP_INFO_PROFILE_ID) UINT16(0x0100))
-    ))
-    ATTRIBUTE(DOC_URL,         URL("http://bellard.org/qemu/user-doc.html"))
-    ATTRIBUTE(SVCPROV_PRIMARY, STRING("QEMU"))
-
-    /* Profile specific */
-    ATTRIBUTE(SPECIFICATION_ID, UINT16(0x0100))
-    ATTRIBUTE(VERSION,         UINT16(0x0100))
-    ATTRIBUTE(PRIMARY_RECORD,  SDP_TRUE)
-)
-
-static int bt_l2cap_sdp_new_ch(struct bt_l2cap_device_s *dev,
-                struct bt_l2cap_conn_params_s *params)
-{
-    struct bt_l2cap_sdp_state_s *sdp = g_malloc0(sizeof(*sdp));
-    struct sdp_def_service_s *services[] = {
-        &sdp_service_sdp_s,
-        &sdp_service_hid_s,
-        &sdp_service_pnp_s,
-        NULL,
-    };
-
-    sdp->channel = params;
-    sdp->channel->opaque = sdp;
-    sdp->channel->close = bt_l2cap_sdp_close_ch;
-    sdp->channel->sdu_in = bt_l2cap_sdp_sdu_in;
-
-    sdp_service_db_build(sdp, services);
-
-    return 0;
-}
-
-void bt_l2cap_sdp_init(struct bt_l2cap_device_s *dev)
-{
-    bt_l2cap_psm_register(dev, BT_PSM_SDP,
-                    MAX_PDU_OUT_SIZE, bt_l2cap_sdp_new_ch);
-}
diff --git a/hw/bt.c b/hw/bt.c
deleted file mode 100644 (file)
index 24ef4de..0000000
--- a/hw/bt.c
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Convenience functions for bluetooth.
- *
- * Copyright (C) 2008 Andrzej Zaborowski  <balrog@zabor.org>
- *
- * 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 or
- * (at your option) version 3 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
- * 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 "bt/bt.h"
-#include "hw/bt.h"
-
-/* Slave implementations can ignore this */
-static void bt_dummy_lmp_mode_change(struct bt_link_s *link)
-{
-}
-
-/* Slaves should never receive these PDUs */
-static void bt_dummy_lmp_connection_complete(struct bt_link_s *link)
-{
-    if (link->slave->reject_reason)
-        fprintf(stderr, "%s: stray LMP_not_accepted received, fixme\n",
-                        __FUNCTION__);
-    else
-        fprintf(stderr, "%s: stray LMP_accepted received, fixme\n",
-                        __FUNCTION__);
-    exit(-1);
-}
-
-static void bt_dummy_lmp_disconnect_master(struct bt_link_s *link)
-{
-    fprintf(stderr, "%s: stray LMP_detach received, fixme\n", __FUNCTION__);
-    exit(-1);
-}
-
-static void bt_dummy_lmp_acl_resp(struct bt_link_s *link,
-                const uint8_t *data, int start, int len)
-{
-    fprintf(stderr, "%s: stray ACL response PDU, fixme\n", __FUNCTION__);
-    exit(-1);
-}
-
-/* Slaves that don't hold any additional per link state can use these */
-static void bt_dummy_lmp_connection_request(struct bt_link_s *req)
-{
-    struct bt_link_s *link = g_malloc0(sizeof(struct bt_link_s));
-
-    link->slave = req->slave;
-    link->host = req->host;
-
-    req->host->reject_reason = 0;
-    req->host->lmp_connection_complete(link);
-}
-
-static void bt_dummy_lmp_disconnect_slave(struct bt_link_s *link)
-{
-    g_free(link);
-}
-
-static void bt_dummy_destroy(struct bt_device_s *device)
-{
-    bt_device_done(device);
-    g_free(device);
-}
-
-static int bt_dev_idx = 0;
-
-void bt_device_init(struct bt_device_s *dev, struct bt_scatternet_s *net)
-{
-    memset(dev, 0, sizeof(*dev));
-    dev->inquiry_scan = 1;
-    dev->page_scan = 1;
-
-    dev->bd_addr.b[0] = bt_dev_idx & 0xff;
-    dev->bd_addr.b[1] = bt_dev_idx >> 8;
-    dev->bd_addr.b[2] = 0xd0;
-    dev->bd_addr.b[3] = 0xba;
-    dev->bd_addr.b[4] = 0xbe;
-    dev->bd_addr.b[5] = 0xba;
-    bt_dev_idx ++;
-
-    /* Simple slave-only devices need to implement only .lmp_acl_data */
-    dev->lmp_connection_complete = bt_dummy_lmp_connection_complete;
-    dev->lmp_disconnect_master = bt_dummy_lmp_disconnect_master;
-    dev->lmp_acl_resp = bt_dummy_lmp_acl_resp;
-    dev->lmp_mode_change = bt_dummy_lmp_mode_change;
-    dev->lmp_connection_request = bt_dummy_lmp_connection_request;
-    dev->lmp_disconnect_slave = bt_dummy_lmp_disconnect_slave;
-
-    dev->handle_destroy = bt_dummy_destroy;
-
-    dev->net = net;
-    dev->next = net->slave;
-    net->slave = dev;
-}
-
-void bt_device_done(struct bt_device_s *dev)
-{
-    struct bt_device_s **p = &dev->net->slave;
-
-    while (*p && *p != dev)
-        p = &(*p)->next;
-    if (*p != dev) {
-        fprintf(stderr, "%s: bad bt device \"%s\"\n", __FUNCTION__,
-                        dev->lmp_name ?: "(null)");
-        exit(-1);
-    }
-
-    *p = dev->next;
-}
diff --git a/hw/bt.h b/hw/bt.h
deleted file mode 100644 (file)
index 830af94..0000000
--- a/hw/bt.h
+++ /dev/null
@@ -1,2190 +0,0 @@
-/*
- * QEMU Bluetooth HCI helpers.
- *
- * Copyright (C) 2007 OpenMoko, Inc.
- * Written by Andrzej Zaborowski <andrew@openedhand.com>
- *
- * Useful definitions taken from BlueZ project's headers.
- * Copyright (C) 2000-2001  Qualcomm Incorporated
- * Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com>
- * Copyright (C) 2002-2006  Marcel Holtmann <marcel@holtmann.org>
- *
- * 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 HW_BT_H
-#define HW_BT_H 1
-
-#include "hw/irq.h"
-
-/* BD Address */
-typedef struct {
-    uint8_t b[6];
-} QEMU_PACKED bdaddr_t;
-
-#define BDADDR_ANY     (&(bdaddr_t) {{0, 0, 0, 0, 0, 0}})
-#define BDADDR_ALL     (&(bdaddr_t) {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}})
-#define BDADDR_LOCAL   (&(bdaddr_t) {{0, 0, 0, 0xff, 0xff, 0xff}})
-
-/* Copy, swap, convert BD Address */
-static inline int bacmp(const bdaddr_t *ba1, const bdaddr_t *ba2)
-{
-    return memcmp(ba1, ba2, sizeof(bdaddr_t));
-}
-static inline void bacpy(bdaddr_t *dst, const bdaddr_t *src)
-{
-    memcpy(dst, src, sizeof(bdaddr_t));
-}
-
-#define BAINIT(orig)   { .b = {                \
-    (orig)->b[0], (orig)->b[1], (orig)->b[2],  \
-    (orig)->b[3], (orig)->b[4], (orig)->b[5],  \
-}, }
-
-/* The twisted structures of a bluetooth environment */
-struct bt_device_s;
-struct bt_scatternet_s;
-struct bt_piconet_s;
-struct bt_link_s;
-
-struct bt_scatternet_s {
-    struct bt_device_s *slave;
-};
-
-struct bt_link_s {
-    struct bt_device_s *slave, *host;
-    uint16_t handle;           /* Master (host) side handle */
-    uint16_t acl_interval;
-    enum {
-        acl_active,
-        acl_hold,
-        acl_sniff,
-        acl_parked,
-    } acl_mode;
-};
-
-struct bt_device_s {
-    int lt_addr;
-    bdaddr_t bd_addr;
-    int mtu;
-    int setup;
-    struct bt_scatternet_s *net;
-
-    uint8_t key[16];
-    int key_present;
-    uint8_t class[3];
-
-    uint8_t reject_reason;
-
-    uint64_t lmp_caps;
-    const char *lmp_name;
-    void (*lmp_connection_request)(struct bt_link_s *link);
-    void (*lmp_connection_complete)(struct bt_link_s *link);
-    void (*lmp_disconnect_master)(struct bt_link_s *link);
-    void (*lmp_disconnect_slave)(struct bt_link_s *link);
-    void (*lmp_acl_data)(struct bt_link_s *link, const uint8_t *data,
-                    int start, int len);
-    void (*lmp_acl_resp)(struct bt_link_s *link, const uint8_t *data,
-                    int start, int len);
-    void (*lmp_mode_change)(struct bt_link_s *link);
-
-    void (*handle_destroy)(struct bt_device_s *device);
-    struct bt_device_s *next;  /* Next in the piconet/scatternet */
-
-    int inquiry_scan;
-    int page_scan;
-
-    uint16_t clkoff;   /* Note: Always little-endian */
-};
-
-/* bt.c */
-void bt_device_init(struct bt_device_s *dev, struct bt_scatternet_s *net);
-void bt_device_done(struct bt_device_s *dev);
-
-/* bt-hci.c */
-struct HCIInfo *bt_new_hci(struct bt_scatternet_s *net);
-
-/* bt-vhci.c */
-void bt_vhci_init(struct HCIInfo *info);
-
-/* bt-hci-csr.c */
-enum {
-    csrhci_pin_reset,
-    csrhci_pin_wakeup,
-    __csrhci_pins,
-};
-qemu_irq *csrhci_pins_get(CharDriverState *chr);
-CharDriverState *uart_hci_init(qemu_irq wakeup);
-
-/* bt-l2cap.c */
-struct bt_l2cap_device_s;
-struct bt_l2cap_conn_params_s;
-struct bt_l2cap_psm_s;
-void bt_l2cap_device_init(struct bt_l2cap_device_s *dev,
-                struct bt_scatternet_s *net);
-void bt_l2cap_device_done(struct bt_l2cap_device_s *dev);
-void bt_l2cap_psm_register(struct bt_l2cap_device_s *dev, int psm,
-                int min_mtu, int (*new_channel)(struct bt_l2cap_device_s *dev,
-                        struct bt_l2cap_conn_params_s *params));
-
-struct bt_l2cap_device_s {
-    struct bt_device_s device;
-    struct bt_l2cap_psm_s *first_psm;
-};
-
-struct bt_l2cap_conn_params_s {
-    /* Input */
-    uint8_t *(*sdu_out)(struct bt_l2cap_conn_params_s *chan, int len);
-    void (*sdu_submit)(struct bt_l2cap_conn_params_s *chan);
-    int remote_mtu;
-    /* Output */
-    void *opaque;
-    void (*sdu_in)(void *opaque, const uint8_t *data, int len);
-    void (*close)(void *opaque);
-};
-
-enum bt_l2cap_psm_predef {
-    BT_PSM_SDP         = 0x0001,
-    BT_PSM_RFCOMM      = 0x0003,
-    BT_PSM_TELEPHONY   = 0x0005,
-    BT_PSM_TCS         = 0x0007,
-    BT_PSM_BNEP                = 0x000f,
-    BT_PSM_HID_CTRL    = 0x0011,
-    BT_PSM_HID_INTR    = 0x0013,
-    BT_PSM_UPNP                = 0x0015,
-    BT_PSM_AVCTP       = 0x0017,
-    BT_PSM_AVDTP       = 0x0019,
-};
-
-/* bt-sdp.c */
-void bt_l2cap_sdp_init(struct bt_l2cap_device_s *dev);
-
-/* bt-hid.c */
-struct bt_device_s *bt_mouse_init(struct bt_scatternet_s *net);
-struct bt_device_s *bt_tablet_init(struct bt_scatternet_s *net);
-struct bt_device_s *bt_keyboard_init(struct bt_scatternet_s *net);
-
-/* Link Management Protocol layer defines */
-
-#define LLID_ACLU_CONT         0x1
-#define LLID_ACLU_START                0x2
-#define LLID_ACLC              0x3
-
-enum lmp_pdu_type {
-    LMP_NAME_REQ               = 0x0001,
-    LMP_NAME_RES               = 0x0002,
-    LMP_ACCEPTED               = 0x0003,
-    LMP_NOT_ACCEPTED           = 0x0004,
-    LMP_CLKOFFSET_REQ          = 0x0005,
-    LMP_CLKOFFSET_RES          = 0x0006,
-    LMP_DETACH                 = 0x0007,
-    LMP_IN_RAND                        = 0x0008,
-    LMP_COMB_KEY               = 0x0009,
-    LMP_UNIT_KEY               = 0x000a,
-    LMP_AU_RAND                        = 0x000b,
-    LMP_SRES                   = 0x000c,
-    LMP_TEMP_RAND              = 0x000d,
-    LMP_TEMP_KEY               = 0x000e,
-    LMP_CRYPT_MODE_REQ         = 0x000f,
-    LMP_CRYPT_KEY_SIZE_REQ     = 0x0010,
-    LMP_START_ENCRYPT_REQ      = 0x0011,
-    LMP_STOP_ENCRYPT_REQ       = 0x0012,
-    LMP_SWITCH_REQ             = 0x0013,
-    LMP_HOLD                   = 0x0014,
-    LMP_HOLD_REQ               = 0x0015,
-    LMP_SNIFF_REQ              = 0x0017,
-    LMP_UNSNIFF_REQ            = 0x0018,
-    LMP_LMP_PARK_REQ           = 0x0019,
-    LMP_SET_BCAST_SCAN_WND     = 0x001b,
-    LMP_MODIFY_BEACON          = 0x001c,
-    LMP_UNPARK_BD_ADDR_REQ     = 0x001d,
-    LMP_UNPARK_PM_ADDR_REQ     = 0x001e,
-    LMP_INCR_POWER_REQ         = 0x001f,
-    LMP_DECR_POWER_REQ         = 0x0020,
-    LMP_MAX_POWER              = 0x0021,
-    LMP_MIN_POWER              = 0x0022,
-    LMP_AUTO_RATE              = 0x0023,
-    LMP_PREFERRED_RATE         = 0x0024,
-    LMP_VERSION_REQ            = 0x0025,
-    LMP_VERSION_RES            = 0x0026,
-    LMP_FEATURES_REQ           = 0x0027,
-    LMP_FEATURES_RES           = 0x0028,
-    LMP_QUALITY_OF_SERVICE     = 0x0029,
-    LMP_QOS_REQ                        = 0x002a,
-    LMP_RM_SCO_LINK_REQ                = 0x002b,
-    LMP_SCO_LINK_REQ           = 0x002c,
-    LMP_MAX_SLOT               = 0x002d,
-    LMP_MAX_SLOT_REQ           = 0x002e,
-    LMP_TIMING_ACCURACY_REQ    = 0x002f,
-    LMP_TIMING_ACCURACY_RES    = 0x0030,
-    LMP_SETUP_COMPLETE         = 0x0031,
-    LMP_USE_SEMIPERM_KEY       = 0x0032,
-    LMP_HOST_CONNECTION_REQ    = 0x0033,
-    LMP_SLOT_OFFSET            = 0x0034,
-    LMP_PAGE_MODE_REQ          = 0x0035,
-    LMP_PAGE_SCAN_MODE_REQ     = 0x0036,
-    LMP_SUPERVISION_TIMEOUT    = 0x0037,
-    LMP_TEST_ACTIVATE          = 0x0038,
-    LMP_TEST_CONTROL           = 0x0039,
-    LMP_CRYPT_KEY_MASK_REQ     = 0x003a,
-    LMP_CRYPT_KEY_MASK_RES     = 0x003b,
-    LMP_SET_AFH                        = 0x003c,
-    LMP_ACCEPTED_EXT           = 0x7f01,
-    LMP_NOT_ACCEPTED_EXT       = 0x7f02,
-    LMP_FEATURES_REQ_EXT       = 0x7f03,
-    LMP_FEATURES_RES_EXT       = 0x7f04,
-    LMP_PACKET_TYPE_TBL_REQ    = 0x7f0b,
-    LMP_ESCO_LINK_REQ          = 0x7f0c,
-    LMP_RM_ESCO_LINK_REQ       = 0x7f0d,
-    LMP_CHANNEL_CLASS_REQ      = 0x7f10,
-    LMP_CHANNEL_CLASS          = 0x7f11,
-};
-
-/* Host Controller Interface layer defines */
-
-enum hci_packet_type {
-    HCI_COMMAND_PKT            = 0x01,
-    HCI_ACLDATA_PKT            = 0x02,
-    HCI_SCODATA_PKT            = 0x03,
-    HCI_EVENT_PKT              = 0x04,
-    HCI_VENDOR_PKT             = 0xff,
-};
-
-enum bt_packet_type {
-    HCI_2DH1   = 1 << 1,
-    HCI_3DH1   = 1 << 2,
-    HCI_DM1    = 1 << 3,
-    HCI_DH1    = 1 << 4,
-    HCI_2DH3   = 1 << 8,
-    HCI_3DH3   = 1 << 9,
-    HCI_DM3    = 1 << 10,
-    HCI_DH3    = 1 << 11,
-    HCI_2DH5   = 1 << 12,
-    HCI_3DH5   = 1 << 13,
-    HCI_DM5    = 1 << 14,
-    HCI_DH5    = 1 << 15,
-};
-
-enum sco_packet_type {
-    HCI_HV1    = 1 << 5,
-    HCI_HV2    = 1 << 6,
-    HCI_HV3    = 1 << 7,
-};
-
-enum ev_packet_type {
-    HCI_EV3    = 1 << 3,
-    HCI_EV4    = 1 << 4,
-    HCI_EV5    = 1 << 5,
-    HCI_2EV3   = 1 << 6,
-    HCI_3EV3   = 1 << 7,
-    HCI_2EV5   = 1 << 8,
-    HCI_3EV5   = 1 << 9,
-};
-
-enum hci_error_code {
-    HCI_SUCCESS                                = 0x00,
-    HCI_UNKNOWN_COMMAND                        = 0x01,
-    HCI_NO_CONNECTION                  = 0x02,
-    HCI_HARDWARE_FAILURE               = 0x03,
-    HCI_PAGE_TIMEOUT                   = 0x04,
-    HCI_AUTHENTICATION_FAILURE         = 0x05,
-    HCI_PIN_OR_KEY_MISSING             = 0x06,
-    HCI_MEMORY_FULL                    = 0x07,
-    HCI_CONNECTION_TIMEOUT             = 0x08,
-    HCI_MAX_NUMBER_OF_CONNECTIONS      = 0x09,
-    HCI_MAX_NUMBER_OF_SCO_CONNECTIONS  = 0x0a,
-    HCI_ACL_CONNECTION_EXISTS          = 0x0b,
-    HCI_COMMAND_DISALLOWED             = 0x0c,
-    HCI_REJECTED_LIMITED_RESOURCES     = 0x0d,
-    HCI_REJECTED_SECURITY              = 0x0e,
-    HCI_REJECTED_PERSONAL              = 0x0f,
-    HCI_HOST_TIMEOUT                   = 0x10,
-    HCI_UNSUPPORTED_FEATURE            = 0x11,
-    HCI_INVALID_PARAMETERS             = 0x12,
-    HCI_OE_USER_ENDED_CONNECTION       = 0x13,
-    HCI_OE_LOW_RESOURCES               = 0x14,
-    HCI_OE_POWER_OFF                   = 0x15,
-    HCI_CONNECTION_TERMINATED          = 0x16,
-    HCI_REPEATED_ATTEMPTS              = 0x17,
-    HCI_PAIRING_NOT_ALLOWED            = 0x18,
-    HCI_UNKNOWN_LMP_PDU                        = 0x19,
-    HCI_UNSUPPORTED_REMOTE_FEATURE     = 0x1a,
-    HCI_SCO_OFFSET_REJECTED            = 0x1b,
-    HCI_SCO_INTERVAL_REJECTED          = 0x1c,
-    HCI_AIR_MODE_REJECTED              = 0x1d,
-    HCI_INVALID_LMP_PARAMETERS         = 0x1e,
-    HCI_UNSPECIFIED_ERROR              = 0x1f,
-    HCI_UNSUPPORTED_LMP_PARAMETER_VALUE        = 0x20,
-    HCI_ROLE_CHANGE_NOT_ALLOWED                = 0x21,
-    HCI_LMP_RESPONSE_TIMEOUT           = 0x22,
-    HCI_LMP_ERROR_TRANSACTION_COLLISION        = 0x23,
-    HCI_LMP_PDU_NOT_ALLOWED            = 0x24,
-    HCI_ENCRYPTION_MODE_NOT_ACCEPTED   = 0x25,
-    HCI_UNIT_LINK_KEY_USED             = 0x26,
-    HCI_QOS_NOT_SUPPORTED              = 0x27,
-    HCI_INSTANT_PASSED                 = 0x28,
-    HCI_PAIRING_NOT_SUPPORTED          = 0x29,
-    HCI_TRANSACTION_COLLISION          = 0x2a,
-    HCI_QOS_UNACCEPTABLE_PARAMETER     = 0x2c,
-    HCI_QOS_REJECTED                   = 0x2d,
-    HCI_CLASSIFICATION_NOT_SUPPORTED   = 0x2e,
-    HCI_INSUFFICIENT_SECURITY          = 0x2f,
-    HCI_PARAMETER_OUT_OF_RANGE         = 0x30,
-    HCI_ROLE_SWITCH_PENDING            = 0x32,
-    HCI_SLOT_VIOLATION                 = 0x34,
-    HCI_ROLE_SWITCH_FAILED             = 0x35,
-};
-
-enum acl_flag_bits {
-    ACL_CONT           = 1 << 0,
-    ACL_START          = 1 << 1,
-    ACL_ACTIVE_BCAST   = 1 << 2,
-    ACL_PICO_BCAST     = 1 << 3,
-};
-
-enum baseband_link_type {
-    SCO_LINK           = 0x00,
-    ACL_LINK           = 0x01,
-};
-
-enum lmp_feature_bits0 {
-    LMP_3SLOT          = 1 << 0,
-    LMP_5SLOT          = 1 << 1,
-    LMP_ENCRYPT                = 1 << 2,
-    LMP_SOFFSET                = 1 << 3,
-    LMP_TACCURACY      = 1 << 4,
-    LMP_RSWITCH                = 1 << 5,
-    LMP_HOLD_MODE      = 1 << 6,
-    LMP_SNIFF_MODE     = 1 << 7,
-};
-
-enum lmp_feature_bits1 {
-    LMP_PARK           = 1 << 0,
-    LMP_RSSI           = 1 << 1,
-    LMP_QUALITY                = 1 << 2,
-    LMP_SCO            = 1 << 3,
-    LMP_HV2            = 1 << 4,
-    LMP_HV3            = 1 << 5,
-    LMP_ULAW           = 1 << 6,
-    LMP_ALAW           = 1 << 7,
-};
-
-enum lmp_feature_bits2 {
-    LMP_CVSD           = 1 << 0,
-    LMP_PSCHEME                = 1 << 1,
-    LMP_PCONTROL       = 1 << 2,
-    LMP_TRSP_SCO       = 1 << 3,
-    LMP_BCAST_ENC      = 1 << 7,
-};
-
-enum lmp_feature_bits3 {
-    LMP_EDR_ACL_2M     = 1 << 1,
-    LMP_EDR_ACL_3M     = 1 << 2,
-    LMP_ENH_ISCAN      = 1 << 3,
-    LMP_ILACE_ISCAN    = 1 << 4,
-    LMP_ILACE_PSCAN    = 1 << 5,
-    LMP_RSSI_INQ       = 1 << 6,
-    LMP_ESCO           = 1 << 7,
-};
-
-enum lmp_feature_bits4 {
-    LMP_EV4            = 1 << 0,
-    LMP_EV5            = 1 << 1,
-    LMP_AFH_CAP_SLV    = 1 << 3,
-    LMP_AFH_CLS_SLV    = 1 << 4,
-    LMP_EDR_3SLOT      = 1 << 7,
-};
-
-enum lmp_feature_bits5 {
-    LMP_EDR_5SLOT      = 1 << 0,
-    LMP_SNIFF_SUBR     = 1 << 1,
-    LMP_AFH_CAP_MST    = 1 << 3,
-    LMP_AFH_CLS_MST    = 1 << 4,
-    LMP_EDR_ESCO_2M    = 1 << 5,
-    LMP_EDR_ESCO_3M    = 1 << 6,
-    LMP_EDR_3S_ESCO    = 1 << 7,
-};
-
-enum lmp_feature_bits6 {
-    LMP_EXT_INQ                = 1 << 0,
-};
-
-enum lmp_feature_bits7 {
-    LMP_EXT_FEAT       = 1 << 7,
-};
-
-enum hci_link_policy {
-    HCI_LP_RSWITCH     = 1 << 0,
-    HCI_LP_HOLD                = 1 << 1,
-    HCI_LP_SNIFF       = 1 << 2,
-    HCI_LP_PARK                = 1 << 3,
-};
-
-enum hci_link_mode {
-    HCI_LM_ACCEPT      = 1 << 15,
-    HCI_LM_MASTER      = 1 << 0,
-    HCI_LM_AUTH                = 1 << 1,
-    HCI_LM_ENCRYPT     = 1 << 2,
-    HCI_LM_TRUSTED     = 1 << 3,
-    HCI_LM_RELIABLE    = 1 << 4,
-    HCI_LM_SECURE      = 1 << 5,
-};
-
-/* HCI Commands */
-
-/* Link Control */
-#define OGF_LINK_CTL           0x01
-
-#define OCF_INQUIRY                    0x0001
-typedef struct {
-    uint8_t    lap[3];
-    uint8_t    length;         /* 1.28s units */
-    uint8_t    num_rsp;
-} QEMU_PACKED inquiry_cp;
-#define INQUIRY_CP_SIZE 5
-
-typedef struct {
-    uint8_t            status;
-    bdaddr_t   bdaddr;
-} QEMU_PACKED status_bdaddr_rp;
-#define STATUS_BDADDR_RP_SIZE 7
-
-#define OCF_INQUIRY_CANCEL             0x0002
-
-#define OCF_PERIODIC_INQUIRY           0x0003
-typedef struct {
-    uint16_t   max_period;     /* 1.28s units */
-    uint16_t   min_period;     /* 1.28s units */
-    uint8_t    lap[3];
-    uint8_t    length;         /* 1.28s units */
-    uint8_t    num_rsp;
-} QEMU_PACKED periodic_inquiry_cp;
-#define PERIODIC_INQUIRY_CP_SIZE 9
-
-#define OCF_EXIT_PERIODIC_INQUIRY      0x0004
-
-#define OCF_CREATE_CONN                        0x0005
-typedef struct {
-    bdaddr_t   bdaddr;
-    uint16_t   pkt_type;
-    uint8_t    pscan_rep_mode;
-    uint8_t    pscan_mode;
-    uint16_t   clock_offset;
-    uint8_t    role_switch;
-} QEMU_PACKED create_conn_cp;
-#define CREATE_CONN_CP_SIZE 13
-
-#define OCF_DISCONNECT                 0x0006
-typedef struct {
-    uint16_t   handle;
-    uint8_t    reason;
-} QEMU_PACKED disconnect_cp;
-#define DISCONNECT_CP_SIZE 3
-
-#define OCF_ADD_SCO                    0x0007
-typedef struct {
-    uint16_t   handle;
-    uint16_t   pkt_type;
-} QEMU_PACKED add_sco_cp;
-#define ADD_SCO_CP_SIZE 4
-
-#define OCF_CREATE_CONN_CANCEL         0x0008
-typedef struct {
-    uint8_t    status;
-    bdaddr_t   bdaddr;
-} QEMU_PACKED create_conn_cancel_cp;
-#define CREATE_CONN_CANCEL_CP_SIZE 6
-
-typedef struct {
-    uint8_t    status;
-    bdaddr_t   bdaddr;
-} QEMU_PACKED create_conn_cancel_rp;
-#define CREATE_CONN_CANCEL_RP_SIZE 7
-
-#define OCF_ACCEPT_CONN_REQ            0x0009
-typedef struct {
-    bdaddr_t   bdaddr;
-    uint8_t    role;
-} QEMU_PACKED accept_conn_req_cp;
-#define ACCEPT_CONN_REQ_CP_SIZE        7
-
-#define OCF_REJECT_CONN_REQ            0x000A
-typedef struct {
-    bdaddr_t   bdaddr;
-    uint8_t    reason;
-} QEMU_PACKED reject_conn_req_cp;
-#define REJECT_CONN_REQ_CP_SIZE        7
-
-#define OCF_LINK_KEY_REPLY             0x000B
-typedef struct {
-    bdaddr_t   bdaddr;
-    uint8_t    link_key[16];
-} QEMU_PACKED link_key_reply_cp;
-#define LINK_KEY_REPLY_CP_SIZE 22
-
-#define OCF_LINK_KEY_NEG_REPLY         0x000C
-
-#define OCF_PIN_CODE_REPLY             0x000D
-typedef struct {
-    bdaddr_t   bdaddr;
-    uint8_t    pin_len;
-    uint8_t    pin_code[16];
-} QEMU_PACKED pin_code_reply_cp;
-#define PIN_CODE_REPLY_CP_SIZE 23
-
-#define OCF_PIN_CODE_NEG_REPLY         0x000E
-
-#define OCF_SET_CONN_PTYPE             0x000F
-typedef struct {
-    uint16_t    handle;
-    uint16_t    pkt_type;
-} QEMU_PACKED set_conn_ptype_cp;
-#define SET_CONN_PTYPE_CP_SIZE 4
-
-#define OCF_AUTH_REQUESTED             0x0011
-typedef struct {
-    uint16_t    handle;
-} QEMU_PACKED auth_requested_cp;
-#define AUTH_REQUESTED_CP_SIZE 2
-
-#define OCF_SET_CONN_ENCRYPT           0x0013
-typedef struct {
-    uint16_t   handle;
-    uint8_t    encrypt;
-} QEMU_PACKED set_conn_encrypt_cp;
-#define SET_CONN_ENCRYPT_CP_SIZE 3
-
-#define OCF_CHANGE_CONN_LINK_KEY       0x0015
-typedef struct {
-    uint16_t   handle;
-} QEMU_PACKED change_conn_link_key_cp;
-#define CHANGE_CONN_LINK_KEY_CP_SIZE 2
-
-#define OCF_MASTER_LINK_KEY            0x0017
-typedef struct {
-    uint8_t    key_flag;
-} QEMU_PACKED master_link_key_cp;
-#define MASTER_LINK_KEY_CP_SIZE 1
-
-#define OCF_REMOTE_NAME_REQ            0x0019
-typedef struct {
-    bdaddr_t   bdaddr;
-    uint8_t    pscan_rep_mode;
-    uint8_t    pscan_mode;
-    uint16_t   clock_offset;
-} QEMU_PACKED remote_name_req_cp;
-#define REMOTE_NAME_REQ_CP_SIZE 10
-
-#define OCF_REMOTE_NAME_REQ_CANCEL     0x001A
-typedef struct {
-    bdaddr_t   bdaddr;
-} QEMU_PACKED remote_name_req_cancel_cp;
-#define REMOTE_NAME_REQ_CANCEL_CP_SIZE 6
-
-typedef struct {
-    uint8_t            status;
-    bdaddr_t   bdaddr;
-} QEMU_PACKED remote_name_req_cancel_rp;
-#define REMOTE_NAME_REQ_CANCEL_RP_SIZE 7
-
-#define OCF_READ_REMOTE_FEATURES       0x001B
-typedef struct {
-    uint16_t   handle;
-} QEMU_PACKED read_remote_features_cp;
-#define READ_REMOTE_FEATURES_CP_SIZE 2
-
-#define OCF_READ_REMOTE_EXT_FEATURES   0x001C
-typedef struct {
-    uint16_t   handle;
-    uint8_t    page_num;
-} QEMU_PACKED read_remote_ext_features_cp;
-#define READ_REMOTE_EXT_FEATURES_CP_SIZE 3
-
-#define OCF_READ_REMOTE_VERSION                0x001D
-typedef struct {
-    uint16_t   handle;
-} QEMU_PACKED read_remote_version_cp;
-#define READ_REMOTE_VERSION_CP_SIZE 2
-
-#define OCF_READ_CLOCK_OFFSET          0x001F
-typedef struct {
-    uint16_t   handle;
-} QEMU_PACKED read_clock_offset_cp;
-#define READ_CLOCK_OFFSET_CP_SIZE 2
-
-#define OCF_READ_LMP_HANDLE            0x0020
-typedef struct {
-    uint16_t   handle;
-} QEMU_PACKED read_lmp_handle_cp;
-#define READ_LMP_HANDLE_CP_SIZE 2
-
-typedef struct {
-    uint8_t    status;
-    uint16_t   handle;
-    uint8_t    lmp_handle;
-    uint32_t   reserved;
-} QEMU_PACKED read_lmp_handle_rp;
-#define READ_LMP_HANDLE_RP_SIZE 8
-
-#define OCF_SETUP_SYNC_CONN            0x0028
-typedef struct {
-    uint16_t   handle;
-    uint32_t   tx_bandwith;
-    uint32_t   rx_bandwith;
-    uint16_t   max_latency;
-    uint16_t   voice_setting;
-    uint8_t    retrans_effort;
-    uint16_t   pkt_type;
-} QEMU_PACKED setup_sync_conn_cp;
-#define SETUP_SYNC_CONN_CP_SIZE 17
-
-#define OCF_ACCEPT_SYNC_CONN_REQ       0x0029
-typedef struct {
-    bdaddr_t   bdaddr;
-    uint32_t   tx_bandwith;
-    uint32_t   rx_bandwith;
-    uint16_t   max_latency;
-    uint16_t   voice_setting;
-    uint8_t    retrans_effort;
-    uint16_t   pkt_type;
-} QEMU_PACKED accept_sync_conn_req_cp;
-#define ACCEPT_SYNC_CONN_REQ_CP_SIZE 21
-
-#define OCF_REJECT_SYNC_CONN_REQ       0x002A
-typedef struct {
-    bdaddr_t   bdaddr;
-    uint8_t    reason;
-} QEMU_PACKED reject_sync_conn_req_cp;
-#define REJECT_SYNC_CONN_REQ_CP_SIZE 7
-
-/* Link Policy */
-#define OGF_LINK_POLICY                0x02
-
-#define OCF_HOLD_MODE                  0x0001
-typedef struct {
-    uint16_t   handle;
-    uint16_t   max_interval;
-    uint16_t   min_interval;
-} QEMU_PACKED hold_mode_cp;
-#define HOLD_MODE_CP_SIZE 6
-
-#define OCF_SNIFF_MODE                 0x0003
-typedef struct {
-    uint16_t   handle;
-    uint16_t   max_interval;
-    uint16_t   min_interval;
-    uint16_t   attempt;
-    uint16_t   timeout;
-} QEMU_PACKED sniff_mode_cp;
-#define SNIFF_MODE_CP_SIZE 10
-
-#define OCF_EXIT_SNIFF_MODE            0x0004
-typedef struct {
-    uint16_t   handle;
-} QEMU_PACKED exit_sniff_mode_cp;
-#define EXIT_SNIFF_MODE_CP_SIZE 2
-
-#define OCF_PARK_MODE                  0x0005
-typedef struct {
-    uint16_t   handle;
-    uint16_t   max_interval;
-    uint16_t   min_interval;
-} QEMU_PACKED park_mode_cp;
-#define PARK_MODE_CP_SIZE 6
-
-#define OCF_EXIT_PARK_MODE             0x0006
-typedef struct {
-    uint16_t   handle;
-} QEMU_PACKED exit_park_mode_cp;
-#define EXIT_PARK_MODE_CP_SIZE 2
-
-#define OCF_QOS_SETUP                  0x0007
-typedef struct {
-    uint8_t    service_type;           /* 1 = best effort */
-    uint32_t   token_rate;             /* Byte per seconds */
-    uint32_t   peak_bandwidth;         /* Byte per seconds */
-    uint32_t   latency;                /* Microseconds */
-    uint32_t   delay_variation;        /* Microseconds */
-} QEMU_PACKED hci_qos;
-#define HCI_QOS_CP_SIZE 17
-typedef struct {
-    uint16_t   handle;
-    uint8_t    flags;                  /* Reserved */
-    hci_qos    qos;
-} QEMU_PACKED qos_setup_cp;
-#define QOS_SETUP_CP_SIZE (3 + HCI_QOS_CP_SIZE)
-
-#define OCF_ROLE_DISCOVERY             0x0009
-typedef struct {
-    uint16_t   handle;
-} QEMU_PACKED role_discovery_cp;
-#define ROLE_DISCOVERY_CP_SIZE 2
-typedef struct {
-    uint8_t    status;
-    uint16_t   handle;
-    uint8_t    role;
-} QEMU_PACKED role_discovery_rp;
-#define ROLE_DISCOVERY_RP_SIZE 4
-
-#define OCF_SWITCH_ROLE                        0x000B
-typedef struct {
-    bdaddr_t   bdaddr;
-    uint8_t    role;
-} QEMU_PACKED switch_role_cp;
-#define SWITCH_ROLE_CP_SIZE 7
-
-#define OCF_READ_LINK_POLICY           0x000C
-typedef struct {
-    uint16_t   handle;
-} QEMU_PACKED read_link_policy_cp;
-#define READ_LINK_POLICY_CP_SIZE 2
-typedef struct {
-    uint8_t    status;
-    uint16_t   handle;
-    uint16_t   policy;
-} QEMU_PACKED read_link_policy_rp;
-#define READ_LINK_POLICY_RP_SIZE 5
-
-#define OCF_WRITE_LINK_POLICY          0x000D
-typedef struct {
-    uint16_t   handle;
-    uint16_t   policy;
-} QEMU_PACKED write_link_policy_cp;
-#define WRITE_LINK_POLICY_CP_SIZE 4
-typedef struct {
-    uint8_t    status;
-    uint16_t   handle;
-} QEMU_PACKED write_link_policy_rp;
-#define WRITE_LINK_POLICY_RP_SIZE 3
-
-#define OCF_READ_DEFAULT_LINK_POLICY   0x000E
-
-#define OCF_WRITE_DEFAULT_LINK_POLICY  0x000F
-
-#define OCF_FLOW_SPECIFICATION         0x0010
-
-#define OCF_SNIFF_SUBRATE              0x0011
-typedef struct {
-    uint16_t   handle;
-    uint16_t   max_remote_latency;
-    uint16_t   max_local_latency;
-    uint16_t   min_remote_timeout;
-    uint16_t   min_local_timeout;
-} QEMU_PACKED sniff_subrate_cp;
-#define SNIFF_SUBRATE_CP_SIZE 10
-
-/* Host Controller and Baseband */
-#define OGF_HOST_CTL           0x03
-
-#define OCF_SET_EVENT_MASK             0x0001
-typedef struct {
-    uint8_t    mask[8];
-} QEMU_PACKED set_event_mask_cp;
-#define SET_EVENT_MASK_CP_SIZE 8
-
-#define OCF_RESET                      0x0003
-
-#define OCF_SET_EVENT_FLT              0x0005
-typedef struct {
-    uint8_t    flt_type;
-    uint8_t    cond_type;
-    uint8_t    condition[0];
-} QEMU_PACKED set_event_flt_cp;
-#define SET_EVENT_FLT_CP_SIZE 2
-
-enum bt_filter_type {
-    FLT_CLEAR_ALL              = 0x00,
-    FLT_INQ_RESULT             = 0x01,
-    FLT_CONN_SETUP             = 0x02,
-};
-enum inq_result_cond_type {
-    INQ_RESULT_RETURN_ALL      = 0x00,
-    INQ_RESULT_RETURN_CLASS    = 0x01,
-    INQ_RESULT_RETURN_BDADDR   = 0x02,
-};
-enum conn_setup_cond_type {
-    CONN_SETUP_ALLOW_ALL       = 0x00,
-    CONN_SETUP_ALLOW_CLASS     = 0x01,
-    CONN_SETUP_ALLOW_BDADDR    = 0x02,
-};
-enum conn_setup_cond {
-    CONN_SETUP_AUTO_OFF                = 0x01,
-    CONN_SETUP_AUTO_ON         = 0x02,
-};
-
-#define OCF_FLUSH                      0x0008
-typedef struct {
-    uint16_t   handle;
-} QEMU_PACKED flush_cp;
-#define FLUSH_CP_SIZE 2
-
-typedef struct {
-    uint8_t    status;
-    uint16_t   handle;
-} QEMU_PACKED flush_rp;
-#define FLUSH_RP_SIZE 3
-
-#define OCF_READ_PIN_TYPE              0x0009
-typedef struct {
-    uint8_t    status;
-    uint8_t    pin_type;
-} QEMU_PACKED read_pin_type_rp;
-#define READ_PIN_TYPE_RP_SIZE 2
-
-#define OCF_WRITE_PIN_TYPE             0x000A
-typedef struct {
-    uint8_t    pin_type;
-} QEMU_PACKED write_pin_type_cp;
-#define WRITE_PIN_TYPE_CP_SIZE 1
-
-#define OCF_CREATE_NEW_UNIT_KEY                0x000B
-
-#define OCF_READ_STORED_LINK_KEY       0x000D
-typedef struct {
-    bdaddr_t   bdaddr;
-    uint8_t    read_all;
-} QEMU_PACKED read_stored_link_key_cp;
-#define READ_STORED_LINK_KEY_CP_SIZE 7
-typedef struct {
-    uint8_t    status;
-    uint16_t   max_keys;
-    uint16_t   num_keys;
-} QEMU_PACKED read_stored_link_key_rp;
-#define READ_STORED_LINK_KEY_RP_SIZE 5
-
-#define OCF_WRITE_STORED_LINK_KEY      0x0011
-typedef struct {
-    uint8_t    num_keys;
-    /* variable length part */
-} QEMU_PACKED write_stored_link_key_cp;
-#define WRITE_STORED_LINK_KEY_CP_SIZE 1
-typedef struct {
-    uint8_t    status;
-    uint8_t    num_keys;
-} QEMU_PACKED write_stored_link_key_rp;
-#define READ_WRITE_LINK_KEY_RP_SIZE 2
-
-#define OCF_DELETE_STORED_LINK_KEY     0x0012
-typedef struct {
-    bdaddr_t   bdaddr;
-    uint8_t    delete_all;
-} QEMU_PACKED delete_stored_link_key_cp;
-#define DELETE_STORED_LINK_KEY_CP_SIZE 7
-typedef struct {
-    uint8_t    status;
-    uint16_t   num_keys;
-} QEMU_PACKED delete_stored_link_key_rp;
-#define DELETE_STORED_LINK_KEY_RP_SIZE 3
-
-#define OCF_CHANGE_LOCAL_NAME          0x0013
-typedef struct {
-    char       name[248];
-} QEMU_PACKED change_local_name_cp;
-#define CHANGE_LOCAL_NAME_CP_SIZE 248 
-
-#define OCF_READ_LOCAL_NAME            0x0014
-typedef struct {
-    uint8_t    status;
-    char       name[248];
-} QEMU_PACKED read_local_name_rp;
-#define READ_LOCAL_NAME_RP_SIZE 249 
-
-#define OCF_READ_CONN_ACCEPT_TIMEOUT   0x0015
-typedef struct {
-    uint8_t    status;
-    uint16_t   timeout;
-} QEMU_PACKED read_conn_accept_timeout_rp;
-#define READ_CONN_ACCEPT_TIMEOUT_RP_SIZE 3
-
-#define OCF_WRITE_CONN_ACCEPT_TIMEOUT  0x0016
-typedef struct {
-    uint16_t   timeout;
-} QEMU_PACKED write_conn_accept_timeout_cp;
-#define WRITE_CONN_ACCEPT_TIMEOUT_CP_SIZE 2
-
-#define OCF_READ_PAGE_TIMEOUT          0x0017
-typedef struct {
-    uint8_t    status;
-    uint16_t   timeout;
-} QEMU_PACKED read_page_timeout_rp;
-#define READ_PAGE_TIMEOUT_RP_SIZE 3
-
-#define OCF_WRITE_PAGE_TIMEOUT         0x0018
-typedef struct {
-    uint16_t   timeout;
-} QEMU_PACKED write_page_timeout_cp;
-#define WRITE_PAGE_TIMEOUT_CP_SIZE 2
-
-#define OCF_READ_SCAN_ENABLE           0x0019
-typedef struct {
-    uint8_t    status;
-    uint8_t    enable;
-} QEMU_PACKED read_scan_enable_rp;
-#define READ_SCAN_ENABLE_RP_SIZE 2
-
-#define OCF_WRITE_SCAN_ENABLE          0x001A
-typedef struct {
-    uint8_t    scan_enable;
-} QEMU_PACKED write_scan_enable_cp;
-#define WRITE_SCAN_ENABLE_CP_SIZE 1
-
-enum scan_enable_bits {
-    SCAN_DISABLED              = 0,
-    SCAN_INQUIRY               = 1 << 0,
-    SCAN_PAGE                  = 1 << 1,
-};
-
-#define OCF_READ_PAGE_ACTIVITY         0x001B
-typedef struct {
-    uint8_t    status;
-    uint16_t   interval;
-    uint16_t   window;
-} QEMU_PACKED read_page_activity_rp;
-#define READ_PAGE_ACTIVITY_RP_SIZE 5
-
-#define OCF_WRITE_PAGE_ACTIVITY                0x001C
-typedef struct {
-    uint16_t   interval;
-    uint16_t   window;
-} QEMU_PACKED write_page_activity_cp;
-#define WRITE_PAGE_ACTIVITY_CP_SIZE 4
-
-#define OCF_READ_INQ_ACTIVITY          0x001D
-typedef struct {
-    uint8_t    status;
-    uint16_t   interval;
-    uint16_t   window;
-} QEMU_PACKED read_inq_activity_rp;
-#define READ_INQ_ACTIVITY_RP_SIZE 5
-
-#define OCF_WRITE_INQ_ACTIVITY         0x001E
-typedef struct {
-    uint16_t   interval;
-    uint16_t   window;
-} QEMU_PACKED write_inq_activity_cp;
-#define WRITE_INQ_ACTIVITY_CP_SIZE 4
-
-#define OCF_READ_AUTH_ENABLE           0x001F
-
-#define OCF_WRITE_AUTH_ENABLE          0x0020
-
-#define AUTH_DISABLED          0x00
-#define AUTH_ENABLED           0x01
-
-#define OCF_READ_ENCRYPT_MODE          0x0021
-
-#define OCF_WRITE_ENCRYPT_MODE         0x0022
-
-#define ENCRYPT_DISABLED       0x00
-#define ENCRYPT_P2P            0x01
-#define ENCRYPT_BOTH           0x02
-
-#define OCF_READ_CLASS_OF_DEV          0x0023
-typedef struct {
-    uint8_t    status;
-    uint8_t    dev_class[3];
-} QEMU_PACKED read_class_of_dev_rp;
-#define READ_CLASS_OF_DEV_RP_SIZE 4 
-
-#define OCF_WRITE_CLASS_OF_DEV         0x0024
-typedef struct {
-    uint8_t    dev_class[3];
-} QEMU_PACKED write_class_of_dev_cp;
-#define WRITE_CLASS_OF_DEV_CP_SIZE 3
-
-#define OCF_READ_VOICE_SETTING         0x0025
-typedef struct {
-    uint8_t    status;
-    uint16_t   voice_setting;
-} QEMU_PACKED read_voice_setting_rp;
-#define READ_VOICE_SETTING_RP_SIZE 3
-
-#define OCF_WRITE_VOICE_SETTING                0x0026
-typedef struct {
-    uint16_t   voice_setting;
-} QEMU_PACKED write_voice_setting_cp;
-#define WRITE_VOICE_SETTING_CP_SIZE 2
-
-#define OCF_READ_AUTOMATIC_FLUSH_TIMEOUT       0x0027
-
-#define OCF_WRITE_AUTOMATIC_FLUSH_TIMEOUT      0x0028
-
-#define OCF_READ_NUM_BROADCAST_RETRANS 0x0029
-
-#define OCF_WRITE_NUM_BROADCAST_RETRANS        0x002A
-
-#define OCF_READ_HOLD_MODE_ACTIVITY    0x002B
-
-#define OCF_WRITE_HOLD_MODE_ACTIVITY   0x002C
-
-#define OCF_READ_TRANSMIT_POWER_LEVEL  0x002D
-typedef struct {
-    uint16_t   handle;
-    uint8_t    type;
-} QEMU_PACKED read_transmit_power_level_cp;
-#define READ_TRANSMIT_POWER_LEVEL_CP_SIZE 3
-typedef struct {
-    uint8_t    status;
-    uint16_t   handle;
-    int8_t     level;
-} QEMU_PACKED read_transmit_power_level_rp;
-#define READ_TRANSMIT_POWER_LEVEL_RP_SIZE 4
-
-#define OCF_HOST_BUFFER_SIZE           0x0033
-typedef struct {
-    uint16_t   acl_mtu;
-    uint8_t    sco_mtu;
-    uint16_t   acl_max_pkt;
-    uint16_t   sco_max_pkt;
-} QEMU_PACKED host_buffer_size_cp;
-#define HOST_BUFFER_SIZE_CP_SIZE 7
-
-#define OCF_HOST_NUMBER_OF_COMPLETED_PACKETS   0x0035
-
-#define OCF_READ_LINK_SUPERVISION_TIMEOUT      0x0036
-typedef struct {
-    uint8_t    status;
-    uint16_t   handle;
-    uint16_t   link_sup_to;
-} QEMU_PACKED read_link_supervision_timeout_rp;
-#define READ_LINK_SUPERVISION_TIMEOUT_RP_SIZE 5
-
-#define OCF_WRITE_LINK_SUPERVISION_TIMEOUT     0x0037
-typedef struct {
-    uint16_t   handle;
-    uint16_t   link_sup_to;
-} QEMU_PACKED write_link_supervision_timeout_cp;
-#define WRITE_LINK_SUPERVISION_TIMEOUT_CP_SIZE 4
-typedef struct {
-    uint8_t    status;
-    uint16_t   handle;
-} QEMU_PACKED write_link_supervision_timeout_rp;
-#define WRITE_LINK_SUPERVISION_TIMEOUT_RP_SIZE 3
-
-#define OCF_READ_NUM_SUPPORTED_IAC     0x0038
-
-#define MAX_IAC_LAP 0x40
-#define OCF_READ_CURRENT_IAC_LAP       0x0039
-typedef struct {
-    uint8_t    status;
-    uint8_t    num_current_iac;
-    uint8_t    lap[MAX_IAC_LAP][3];
-} QEMU_PACKED read_current_iac_lap_rp;
-#define READ_CURRENT_IAC_LAP_RP_SIZE 2+3*MAX_IAC_LAP
-
-#define OCF_WRITE_CURRENT_IAC_LAP      0x003A
-typedef struct {
-    uint8_t    num_current_iac;
-    uint8_t    lap[MAX_IAC_LAP][3];
-} QEMU_PACKED write_current_iac_lap_cp;
-#define WRITE_CURRENT_IAC_LAP_CP_SIZE 1+3*MAX_IAC_LAP
-
-#define OCF_READ_PAGE_SCAN_PERIOD_MODE 0x003B
-
-#define OCF_WRITE_PAGE_SCAN_PERIOD_MODE        0x003C
-
-#define OCF_READ_PAGE_SCAN_MODE                0x003D
-
-#define OCF_WRITE_PAGE_SCAN_MODE       0x003E
-
-#define OCF_SET_AFH_CLASSIFICATION     0x003F
-typedef struct {
-    uint8_t    map[10];
-} QEMU_PACKED set_afh_classification_cp;
-#define SET_AFH_CLASSIFICATION_CP_SIZE 10
-typedef struct {
-    uint8_t    status;
-} QEMU_PACKED set_afh_classification_rp;
-#define SET_AFH_CLASSIFICATION_RP_SIZE 1
-
-#define OCF_READ_INQUIRY_SCAN_TYPE     0x0042
-typedef struct {
-    uint8_t    status;
-    uint8_t    type;
-} QEMU_PACKED read_inquiry_scan_type_rp;
-#define READ_INQUIRY_SCAN_TYPE_RP_SIZE 2
-
-#define OCF_WRITE_INQUIRY_SCAN_TYPE    0x0043
-typedef struct {
-    uint8_t    type;
-} QEMU_PACKED write_inquiry_scan_type_cp;
-#define WRITE_INQUIRY_SCAN_TYPE_CP_SIZE 1
-typedef struct {
-    uint8_t    status;
-} QEMU_PACKED write_inquiry_scan_type_rp;
-#define WRITE_INQUIRY_SCAN_TYPE_RP_SIZE 1
-
-#define OCF_READ_INQUIRY_MODE          0x0044
-typedef struct {
-    uint8_t    status;
-    uint8_t    mode;
-} QEMU_PACKED read_inquiry_mode_rp;
-#define READ_INQUIRY_MODE_RP_SIZE 2
-
-#define OCF_WRITE_INQUIRY_MODE         0x0045
-typedef struct {
-    uint8_t    mode;
-} QEMU_PACKED write_inquiry_mode_cp;
-#define WRITE_INQUIRY_MODE_CP_SIZE 1
-typedef struct {
-    uint8_t    status;
-} QEMU_PACKED write_inquiry_mode_rp;
-#define WRITE_INQUIRY_MODE_RP_SIZE 1
-
-#define OCF_READ_PAGE_SCAN_TYPE                0x0046
-
-#define OCF_WRITE_PAGE_SCAN_TYPE       0x0047
-
-#define OCF_READ_AFH_MODE              0x0048
-typedef struct {
-    uint8_t    status;
-    uint8_t    mode;
-} QEMU_PACKED read_afh_mode_rp;
-#define READ_AFH_MODE_RP_SIZE 2
-
-#define OCF_WRITE_AFH_MODE             0x0049
-typedef struct {
-    uint8_t    mode;
-} QEMU_PACKED write_afh_mode_cp;
-#define WRITE_AFH_MODE_CP_SIZE 1
-typedef struct {
-    uint8_t    status;
-} QEMU_PACKED write_afh_mode_rp;
-#define WRITE_AFH_MODE_RP_SIZE 1
-
-#define OCF_READ_EXT_INQUIRY_RESPONSE  0x0051
-typedef struct {
-    uint8_t    status;
-    uint8_t    fec;
-    uint8_t    data[240];
-} QEMU_PACKED read_ext_inquiry_response_rp;
-#define READ_EXT_INQUIRY_RESPONSE_RP_SIZE 242
-
-#define OCF_WRITE_EXT_INQUIRY_RESPONSE 0x0052
-typedef struct {
-    uint8_t    fec;
-    uint8_t    data[240];
-} QEMU_PACKED write_ext_inquiry_response_cp;
-#define WRITE_EXT_INQUIRY_RESPONSE_CP_SIZE 241
-typedef struct {
-    uint8_t    status;
-} QEMU_PACKED write_ext_inquiry_response_rp;
-#define WRITE_EXT_INQUIRY_RESPONSE_RP_SIZE 1
-
-/* Informational Parameters */
-#define OGF_INFO_PARAM         0x04
-
-#define OCF_READ_LOCAL_VERSION         0x0001
-typedef struct {
-    uint8_t    status;
-    uint8_t    hci_ver;
-    uint16_t   hci_rev;
-    uint8_t    lmp_ver;
-    uint16_t   manufacturer;
-    uint16_t   lmp_subver;
-} QEMU_PACKED read_local_version_rp;
-#define READ_LOCAL_VERSION_RP_SIZE 9
-
-#define OCF_READ_LOCAL_COMMANDS                0x0002
-typedef struct {
-    uint8_t    status;
-    uint8_t    commands[64];
-} QEMU_PACKED read_local_commands_rp;
-#define READ_LOCAL_COMMANDS_RP_SIZE 65
-
-#define OCF_READ_LOCAL_FEATURES                0x0003
-typedef struct {
-    uint8_t    status;
-    uint8_t    features[8];
-} QEMU_PACKED read_local_features_rp;
-#define READ_LOCAL_FEATURES_RP_SIZE 9
-
-#define OCF_READ_LOCAL_EXT_FEATURES    0x0004
-typedef struct {
-    uint8_t    page_num;
-} QEMU_PACKED read_local_ext_features_cp;
-#define READ_LOCAL_EXT_FEATURES_CP_SIZE 1
-typedef struct {
-    uint8_t    status;
-    uint8_t    page_num;
-    uint8_t    max_page_num;
-    uint8_t    features[8];
-} QEMU_PACKED read_local_ext_features_rp;
-#define READ_LOCAL_EXT_FEATURES_RP_SIZE 11
-
-#define OCF_READ_BUFFER_SIZE           0x0005
-typedef struct {
-    uint8_t    status;
-    uint16_t   acl_mtu;
-    uint8_t    sco_mtu;
-    uint16_t   acl_max_pkt;
-    uint16_t   sco_max_pkt;
-} QEMU_PACKED read_buffer_size_rp;
-#define READ_BUFFER_SIZE_RP_SIZE 8
-
-#define OCF_READ_COUNTRY_CODE          0x0007
-typedef struct {
-    uint8_t    status;
-    uint8_t    country_code;
-} QEMU_PACKED read_country_code_rp;
-#define READ_COUNTRY_CODE_RP_SIZE 2
-
-#define OCF_READ_BD_ADDR               0x0009
-typedef struct {
-    uint8_t    status;
-    bdaddr_t   bdaddr;
-} QEMU_PACKED read_bd_addr_rp;
-#define READ_BD_ADDR_RP_SIZE 7
-
-/* Status params */
-#define OGF_STATUS_PARAM       0x05
-
-#define OCF_READ_FAILED_CONTACT_COUNTER                0x0001
-typedef struct {
-    uint8_t    status;
-    uint16_t   handle;
-    uint8_t    counter;
-} QEMU_PACKED read_failed_contact_counter_rp;
-#define READ_FAILED_CONTACT_COUNTER_RP_SIZE 4
-
-#define OCF_RESET_FAILED_CONTACT_COUNTER       0x0002
-typedef struct {
-    uint8_t    status;
-    uint16_t   handle;
-} QEMU_PACKED reset_failed_contact_counter_rp;
-#define RESET_FAILED_CONTACT_COUNTER_RP_SIZE 4
-
-#define OCF_READ_LINK_QUALITY          0x0003
-typedef struct {
-    uint16_t   handle;
-} QEMU_PACKED read_link_quality_cp;
-#define READ_LINK_QUALITY_CP_SIZE 4
-
-typedef struct {
-    uint8_t    status;
-    uint16_t   handle;
-    uint8_t    link_quality;
-} QEMU_PACKED read_link_quality_rp;
-#define READ_LINK_QUALITY_RP_SIZE 4
-
-#define OCF_READ_RSSI                  0x0005
-typedef struct {
-    uint8_t    status;
-    uint16_t   handle;
-    int8_t     rssi;
-} QEMU_PACKED read_rssi_rp;
-#define READ_RSSI_RP_SIZE 4
-
-#define OCF_READ_AFH_MAP               0x0006
-typedef struct {
-    uint8_t    status;
-    uint16_t   handle;
-    uint8_t    mode;
-    uint8_t    map[10];
-} QEMU_PACKED read_afh_map_rp;
-#define READ_AFH_MAP_RP_SIZE 14
-
-#define OCF_READ_CLOCK                 0x0007
-typedef struct {
-    uint16_t   handle;
-    uint8_t    which_clock;
-} QEMU_PACKED read_clock_cp;
-#define READ_CLOCK_CP_SIZE 3
-typedef struct {
-    uint8_t    status;
-    uint16_t   handle;
-    uint32_t   clock;
-    uint16_t   accuracy;
-} QEMU_PACKED read_clock_rp;
-#define READ_CLOCK_RP_SIZE 9
-
-/* Testing commands */
-#define OGF_TESTING_CMD                0x3e
-
-/* Vendor specific commands */
-#define OGF_VENDOR_CMD         0x3f
-
-/* HCI Events */
-
-#define EVT_INQUIRY_COMPLETE           0x01
-
-#define EVT_INQUIRY_RESULT             0x02
-typedef struct {
-    uint8_t    num_responses;
-    bdaddr_t   bdaddr;
-    uint8_t    pscan_rep_mode;
-    uint8_t    pscan_period_mode;
-    uint8_t    pscan_mode;
-    uint8_t    dev_class[3];
-    uint16_t   clock_offset;
-} QEMU_PACKED inquiry_info;
-#define INQUIRY_INFO_SIZE 14
-
-#define EVT_CONN_COMPLETE              0x03
-typedef struct {
-    uint8_t    status;
-    uint16_t   handle;
-    bdaddr_t   bdaddr;
-    uint8_t    link_type;
-    uint8_t    encr_mode;
-} QEMU_PACKED evt_conn_complete;
-#define EVT_CONN_COMPLETE_SIZE 11
-
-#define EVT_CONN_REQUEST               0x04
-typedef struct {
-    bdaddr_t   bdaddr;
-    uint8_t    dev_class[3];
-    uint8_t    link_type;
-} QEMU_PACKED evt_conn_request;
-#define EVT_CONN_REQUEST_SIZE 10
-
-#define EVT_DISCONN_COMPLETE           0x05
-typedef struct {
-    uint8_t    status;
-    uint16_t   handle;
-    uint8_t    reason;
-} QEMU_PACKED evt_disconn_complete;
-#define EVT_DISCONN_COMPLETE_SIZE 4
-
-#define EVT_AUTH_COMPLETE              0x06
-typedef struct {
-    uint8_t    status;
-    uint16_t   handle;
-} QEMU_PACKED evt_auth_complete;
-#define EVT_AUTH_COMPLETE_SIZE 3
-
-#define EVT_REMOTE_NAME_REQ_COMPLETE   0x07
-typedef struct {
-    uint8_t    status;
-    bdaddr_t   bdaddr;
-    char       name[248];
-} QEMU_PACKED evt_remote_name_req_complete;
-#define EVT_REMOTE_NAME_REQ_COMPLETE_SIZE 255
-
-#define EVT_ENCRYPT_CHANGE             0x08
-typedef struct {
-    uint8_t    status;
-    uint16_t   handle;
-    uint8_t    encrypt;
-} QEMU_PACKED evt_encrypt_change;
-#define EVT_ENCRYPT_CHANGE_SIZE 5
-
-#define EVT_CHANGE_CONN_LINK_KEY_COMPLETE      0x09
-typedef struct {
-    uint8_t    status;
-    uint16_t   handle;
-}  QEMU_PACKED evt_change_conn_link_key_complete;
-#define EVT_CHANGE_CONN_LINK_KEY_COMPLETE_SIZE 3
-
-#define EVT_MASTER_LINK_KEY_COMPLETE           0x0A
-typedef struct {
-    uint8_t    status;
-    uint16_t   handle;
-    uint8_t    key_flag;
-} QEMU_PACKED evt_master_link_key_complete;
-#define EVT_MASTER_LINK_KEY_COMPLETE_SIZE 4
-
-#define EVT_READ_REMOTE_FEATURES_COMPLETE      0x0B
-typedef struct {
-    uint8_t    status;
-    uint16_t   handle;
-    uint8_t    features[8];
-} QEMU_PACKED evt_read_remote_features_complete;
-#define EVT_READ_REMOTE_FEATURES_COMPLETE_SIZE 11
-
-#define EVT_READ_REMOTE_VERSION_COMPLETE       0x0C
-typedef struct {
-    uint8_t    status;
-    uint16_t   handle;
-    uint8_t    lmp_ver;
-    uint16_t   manufacturer;
-    uint16_t   lmp_subver;
-} QEMU_PACKED evt_read_remote_version_complete;
-#define EVT_READ_REMOTE_VERSION_COMPLETE_SIZE 8
-
-#define EVT_QOS_SETUP_COMPLETE         0x0D
-typedef struct {
-    uint8_t    status;
-    uint16_t   handle;
-    uint8_t    flags;                  /* Reserved */
-    hci_qos    qos;
-} QEMU_PACKED evt_qos_setup_complete;
-#define EVT_QOS_SETUP_COMPLETE_SIZE (4 + HCI_QOS_CP_SIZE)
-
-#define EVT_CMD_COMPLETE               0x0E
-typedef struct {
-    uint8_t    ncmd;
-    uint16_t   opcode;
-} QEMU_PACKED evt_cmd_complete;
-#define EVT_CMD_COMPLETE_SIZE 3
-
-#define EVT_CMD_STATUS                         0x0F
-typedef struct {
-    uint8_t    status;
-    uint8_t    ncmd;
-    uint16_t   opcode;
-} QEMU_PACKED evt_cmd_status;
-#define EVT_CMD_STATUS_SIZE 4
-
-#define EVT_HARDWARE_ERROR             0x10
-typedef struct {
-    uint8_t    code;
-} QEMU_PACKED evt_hardware_error;
-#define EVT_HARDWARE_ERROR_SIZE 1
-
-#define EVT_FLUSH_OCCURRED             0x11
-typedef struct {
-    uint16_t   handle;
-} QEMU_PACKED evt_flush_occurred;
-#define EVT_FLUSH_OCCURRED_SIZE 2
-
-#define EVT_ROLE_CHANGE                        0x12
-typedef struct {
-    uint8_t    status;
-    bdaddr_t   bdaddr;
-    uint8_t    role;
-} QEMU_PACKED evt_role_change;
-#define EVT_ROLE_CHANGE_SIZE 8
-
-#define EVT_NUM_COMP_PKTS              0x13
-typedef struct {
-    uint8_t    num_hndl;
-    struct {
-        uint16_t handle;
-        uint16_t num_packets;
-    } connection[0];
-} QEMU_PACKED evt_num_comp_pkts;
-#define EVT_NUM_COMP_PKTS_SIZE(num_hndl) (1 + 4 * (num_hndl))
-
-#define EVT_MODE_CHANGE                        0x14
-typedef struct {
-    uint8_t    status;
-    uint16_t   handle;
-    uint8_t    mode;
-    uint16_t   interval;
-} QEMU_PACKED evt_mode_change;
-#define EVT_MODE_CHANGE_SIZE 6
-
-#define EVT_RETURN_LINK_KEYS           0x15
-typedef struct {
-    uint8_t    num_keys;
-    /* variable length part */
-} QEMU_PACKED evt_return_link_keys;
-#define EVT_RETURN_LINK_KEYS_SIZE 1
-
-#define EVT_PIN_CODE_REQ               0x16
-typedef struct {
-    bdaddr_t   bdaddr;
-} QEMU_PACKED evt_pin_code_req;
-#define EVT_PIN_CODE_REQ_SIZE 6
-
-#define EVT_LINK_KEY_REQ               0x17
-typedef struct {
-    bdaddr_t   bdaddr;
-} QEMU_PACKED evt_link_key_req;
-#define EVT_LINK_KEY_REQ_SIZE 6
-
-#define EVT_LINK_KEY_NOTIFY            0x18
-typedef struct {
-    bdaddr_t   bdaddr;
-    uint8_t    link_key[16];
-    uint8_t    key_type;
-} QEMU_PACKED evt_link_key_notify;
-#define EVT_LINK_KEY_NOTIFY_SIZE 23
-
-#define EVT_LOOPBACK_COMMAND           0x19
-
-#define EVT_DATA_BUFFER_OVERFLOW       0x1A
-typedef struct {
-    uint8_t    link_type;
-} QEMU_PACKED evt_data_buffer_overflow;
-#define EVT_DATA_BUFFER_OVERFLOW_SIZE 1
-
-#define EVT_MAX_SLOTS_CHANGE           0x1B
-typedef struct {
-    uint16_t   handle;
-    uint8_t    max_slots;
-} QEMU_PACKED evt_max_slots_change;
-#define EVT_MAX_SLOTS_CHANGE_SIZE 3
-
-#define EVT_READ_CLOCK_OFFSET_COMPLETE 0x1C
-typedef struct {
-    uint8_t    status;
-    uint16_t   handle;
-    uint16_t   clock_offset;
-} QEMU_PACKED evt_read_clock_offset_complete;
-#define EVT_READ_CLOCK_OFFSET_COMPLETE_SIZE 5
-
-#define EVT_CONN_PTYPE_CHANGED         0x1D
-typedef struct {
-    uint8_t    status;
-    uint16_t   handle;
-    uint16_t   ptype;
-} QEMU_PACKED evt_conn_ptype_changed;
-#define EVT_CONN_PTYPE_CHANGED_SIZE 5
-
-#define EVT_QOS_VIOLATION              0x1E
-typedef struct {
-    uint16_t   handle;
-} QEMU_PACKED evt_qos_violation;
-#define EVT_QOS_VIOLATION_SIZE 2
-
-#define EVT_PSCAN_REP_MODE_CHANGE      0x20
-typedef struct {
-    bdaddr_t   bdaddr;
-    uint8_t    pscan_rep_mode;
-} QEMU_PACKED evt_pscan_rep_mode_change;
-#define EVT_PSCAN_REP_MODE_CHANGE_SIZE 7
-
-#define EVT_FLOW_SPEC_COMPLETE         0x21
-typedef struct {
-    uint8_t    status;
-    uint16_t   handle;
-    uint8_t    flags;
-    uint8_t    direction;
-    hci_qos    qos;
-} QEMU_PACKED evt_flow_spec_complete;
-#define EVT_FLOW_SPEC_COMPLETE_SIZE (5 + HCI_QOS_CP_SIZE)
-
-#define EVT_INQUIRY_RESULT_WITH_RSSI   0x22
-typedef struct {
-    uint8_t    num_responses;
-    bdaddr_t   bdaddr;
-    uint8_t    pscan_rep_mode;
-    uint8_t    pscan_period_mode;
-    uint8_t    dev_class[3];
-    uint16_t   clock_offset;
-    int8_t     rssi;
-} QEMU_PACKED inquiry_info_with_rssi;
-#define INQUIRY_INFO_WITH_RSSI_SIZE 15
-typedef struct {
-    uint8_t    num_responses;
-    bdaddr_t   bdaddr;
-    uint8_t    pscan_rep_mode;
-    uint8_t    pscan_period_mode;
-    uint8_t    pscan_mode;
-    uint8_t    dev_class[3];
-    uint16_t   clock_offset;
-    int8_t     rssi;
-} QEMU_PACKED inquiry_info_with_rssi_and_pscan_mode;
-#define INQUIRY_INFO_WITH_RSSI_AND_PSCAN_MODE_SIZE 16
-
-#define EVT_READ_REMOTE_EXT_FEATURES_COMPLETE  0x23
-typedef struct {
-    uint8_t    status;
-    uint16_t   handle;
-    uint8_t    page_num;
-    uint8_t    max_page_num;
-    uint8_t    features[8];
-} QEMU_PACKED evt_read_remote_ext_features_complete;
-#define EVT_READ_REMOTE_EXT_FEATURES_COMPLETE_SIZE 13
-
-#define EVT_SYNC_CONN_COMPLETE         0x2C
-typedef struct {
-    uint8_t    status;
-    uint16_t   handle;
-    bdaddr_t   bdaddr;
-    uint8_t    link_type;
-    uint8_t    trans_interval;
-    uint8_t    retrans_window;
-    uint16_t   rx_pkt_len;
-    uint16_t   tx_pkt_len;
-    uint8_t    air_mode;
-} QEMU_PACKED evt_sync_conn_complete;
-#define EVT_SYNC_CONN_COMPLETE_SIZE 17
-
-#define EVT_SYNC_CONN_CHANGED          0x2D
-typedef struct {
-    uint8_t    status;
-    uint16_t   handle;
-    uint8_t    trans_interval;
-    uint8_t    retrans_window;
-    uint16_t   rx_pkt_len;
-    uint16_t   tx_pkt_len;
-} QEMU_PACKED evt_sync_conn_changed;
-#define EVT_SYNC_CONN_CHANGED_SIZE 9
-
-#define EVT_SNIFF_SUBRATE              0x2E
-typedef struct {
-    uint8_t    status;
-    uint16_t   handle;
-    uint16_t   max_remote_latency;
-    uint16_t   max_local_latency;
-    uint16_t   min_remote_timeout;
-    uint16_t   min_local_timeout;
-} QEMU_PACKED evt_sniff_subrate;
-#define EVT_SNIFF_SUBRATE_SIZE 11
-
-#define EVT_EXTENDED_INQUIRY_RESULT    0x2F
-typedef struct {
-    bdaddr_t   bdaddr;
-    uint8_t    pscan_rep_mode;
-    uint8_t    pscan_period_mode;
-    uint8_t    dev_class[3];
-    uint16_t   clock_offset;
-    int8_t     rssi;
-    uint8_t    data[240];
-} QEMU_PACKED extended_inquiry_info;
-#define EXTENDED_INQUIRY_INFO_SIZE 254
-
-#define EVT_TESTING                    0xFE
-
-#define EVT_VENDOR                     0xFF
-
-/* Command opcode pack/unpack */
-#define cmd_opcode_pack(ogf, ocf)      (uint16_t)((ocf & 0x03ff)|(ogf << 10))
-#define cmd_opcode_ogf(op)             (op >> 10)
-#define cmd_opcode_ocf(op)             (op & 0x03ff)
-
-/* ACL handle and flags pack/unpack */
-#define acl_handle_pack(h, f)  (uint16_t)(((h) & 0x0fff)|((f) << 12))
-#define acl_handle(h)          ((h) & 0x0fff)
-#define acl_flags(h)           ((h) >> 12)
-
-/* HCI Packet structures */
-#define HCI_COMMAND_HDR_SIZE   3
-#define HCI_EVENT_HDR_SIZE     2
-#define HCI_ACL_HDR_SIZE       4
-#define HCI_SCO_HDR_SIZE       3
-
-struct hci_command_hdr {
-    uint16_t   opcode;         /* OCF & OGF */
-    uint8_t    plen;
-} QEMU_PACKED;
-
-struct hci_event_hdr {
-    uint8_t    evt;
-    uint8_t    plen;
-} QEMU_PACKED;
-
-struct hci_acl_hdr {
-    uint16_t   handle;         /* Handle & Flags(PB, BC) */
-    uint16_t   dlen;
-} QEMU_PACKED;
-
-struct hci_sco_hdr {
-    uint16_t   handle;
-    uint8_t    dlen;
-} QEMU_PACKED;
-
-/* L2CAP layer defines */
-
-enum bt_l2cap_lm_bits {
-    L2CAP_LM_MASTER    = 1 << 0,
-    L2CAP_LM_AUTH      = 1 << 1,
-    L2CAP_LM_ENCRYPT   = 1 << 2,
-    L2CAP_LM_TRUSTED   = 1 << 3,
-    L2CAP_LM_RELIABLE  = 1 << 4,
-    L2CAP_LM_SECURE    = 1 << 5,
-};
-
-enum bt_l2cap_cid_predef {
-    L2CAP_CID_INVALID  = 0x0000,
-    L2CAP_CID_SIGNALLING= 0x0001,
-    L2CAP_CID_GROUP    = 0x0002,
-    L2CAP_CID_ALLOC    = 0x0040,
-};
-
-/* L2CAP command codes */
-enum bt_l2cap_cmd {
-    L2CAP_COMMAND_REJ  = 1,
-    L2CAP_CONN_REQ,
-    L2CAP_CONN_RSP,
-    L2CAP_CONF_REQ,
-    L2CAP_CONF_RSP,
-    L2CAP_DISCONN_REQ,
-    L2CAP_DISCONN_RSP,
-    L2CAP_ECHO_REQ,
-    L2CAP_ECHO_RSP,
-    L2CAP_INFO_REQ,
-    L2CAP_INFO_RSP,
-};
-
-enum bt_l2cap_sar_bits {
-    L2CAP_SAR_NO_SEG   = 0,
-    L2CAP_SAR_START,
-    L2CAP_SAR_END,
-    L2CAP_SAR_CONT,
-};
-
-/* L2CAP structures */
-typedef struct {
-    uint16_t   len;
-    uint16_t   cid;
-    uint8_t    data[0];
-} QEMU_PACKED l2cap_hdr;
-#define L2CAP_HDR_SIZE 4
-
-typedef struct {
-    uint8_t    code;
-    uint8_t    ident;
-    uint16_t   len;
-} QEMU_PACKED l2cap_cmd_hdr;
-#define L2CAP_CMD_HDR_SIZE 4
-
-typedef struct {
-    uint16_t   reason;
-} QEMU_PACKED l2cap_cmd_rej;
-#define L2CAP_CMD_REJ_SIZE 2
-
-typedef struct {
-    uint16_t   dcid;
-    uint16_t   scid;
-} QEMU_PACKED l2cap_cmd_rej_cid;
-#define L2CAP_CMD_REJ_CID_SIZE 4
-
-/* reject reason */
-enum bt_l2cap_rej_reason {
-    L2CAP_REJ_CMD_NOT_UNDERSTOOD = 0,
-    L2CAP_REJ_SIG_TOOBIG,
-    L2CAP_REJ_CID_INVAL,
-};
-
-typedef struct {
-    uint16_t   psm;
-    uint16_t   scid;
-} QEMU_PACKED l2cap_conn_req;
-#define L2CAP_CONN_REQ_SIZE 4
-
-typedef struct {
-    uint16_t   dcid;
-    uint16_t   scid;
-    uint16_t   result;
-    uint16_t   status;
-} QEMU_PACKED l2cap_conn_rsp;
-#define L2CAP_CONN_RSP_SIZE 8
-
-/* connect result */
-enum bt_l2cap_conn_res {
-    L2CAP_CR_SUCCESS   = 0,
-    L2CAP_CR_PEND,
-    L2CAP_CR_BAD_PSM,
-    L2CAP_CR_SEC_BLOCK,
-    L2CAP_CR_NO_MEM,
-};
-
-/* connect status */
-enum bt_l2cap_conn_stat {
-    L2CAP_CS_NO_INFO   = 0,
-    L2CAP_CS_AUTHEN_PEND,
-    L2CAP_CS_AUTHOR_PEND,
-};
-
-typedef struct {
-    uint16_t   dcid;
-    uint16_t   flags;
-    uint8_t    data[0];
-} QEMU_PACKED l2cap_conf_req;
-#define L2CAP_CONF_REQ_SIZE(datalen) (4 + (datalen))
-
-typedef struct {
-    uint16_t   scid;
-    uint16_t   flags;
-    uint16_t   result;
-    uint8_t    data[0];
-} QEMU_PACKED l2cap_conf_rsp;
-#define L2CAP_CONF_RSP_SIZE(datalen) (6 + datalen)
-
-enum bt_l2cap_conf_res {
-    L2CAP_CONF_SUCCESS = 0,
-    L2CAP_CONF_UNACCEPT,
-    L2CAP_CONF_REJECT,
-    L2CAP_CONF_UNKNOWN,
-};
-
-typedef struct {
-    uint8_t    type;
-    uint8_t    len;
-    uint8_t    val[0];
-} QEMU_PACKED l2cap_conf_opt;
-#define L2CAP_CONF_OPT_SIZE 2
-
-enum bt_l2cap_conf_val {
-    L2CAP_CONF_MTU     = 1,
-    L2CAP_CONF_FLUSH_TO,
-    L2CAP_CONF_QOS,
-    L2CAP_CONF_RFC,
-    L2CAP_CONF_RFC_MODE        = L2CAP_CONF_RFC,
-};
-
-typedef struct {
-    uint8_t    flags;
-    uint8_t    service_type;
-    uint32_t   token_rate;
-    uint32_t   token_bucket_size;
-    uint32_t   peak_bandwidth;
-    uint32_t   latency;
-    uint32_t   delay_variation;
-} QEMU_PACKED l2cap_conf_opt_qos;
-#define L2CAP_CONF_OPT_QOS_SIZE 22
-
-enum bt_l2cap_conf_opt_qos_st {
-    L2CAP_CONF_QOS_NO_TRAFFIC = 0x00,
-    L2CAP_CONF_QOS_BEST_EFFORT,
-    L2CAP_CONF_QOS_GUARANTEED,
-};
-
-#define L2CAP_CONF_QOS_WILDCARD        0xffffffff
-
-enum bt_l2cap_mode {
-    L2CAP_MODE_BASIC   = 0,
-    L2CAP_MODE_RETRANS = 1,
-    L2CAP_MODE_FLOWCTL = 2,
-};
-
-typedef struct {
-    uint16_t   dcid;
-    uint16_t   scid;
-} QEMU_PACKED l2cap_disconn_req;
-#define L2CAP_DISCONN_REQ_SIZE 4
-
-typedef struct {
-    uint16_t   dcid;
-    uint16_t   scid;
-} QEMU_PACKED l2cap_disconn_rsp;
-#define L2CAP_DISCONN_RSP_SIZE 4
-
-typedef struct {
-    uint16_t   type;
-} QEMU_PACKED l2cap_info_req;
-#define L2CAP_INFO_REQ_SIZE 2
-
-typedef struct {
-    uint16_t   type;
-    uint16_t   result;
-    uint8_t    data[0];
-} QEMU_PACKED l2cap_info_rsp;
-#define L2CAP_INFO_RSP_SIZE 4
-
-/* info type */
-enum bt_l2cap_info_type {
-    L2CAP_IT_CL_MTU    = 1,
-    L2CAP_IT_FEAT_MASK,
-};
-
-/* info result */
-enum bt_l2cap_info_result {
-    L2CAP_IR_SUCCESS   = 0,
-    L2CAP_IR_NOTSUPP,
-};
-
-/* Service Discovery Protocol defines */
-/* Note that all multibyte values in lower layer protocols (above in this file)
- * are little-endian while SDP is big-endian.  */
-
-/* Protocol UUIDs */
-enum sdp_proto_uuid {
-    SDP_UUID           = 0x0001,
-    UDP_UUID           = 0x0002,
-    RFCOMM_UUID                = 0x0003,
-    TCP_UUID           = 0x0004,
-    TCS_BIN_UUID       = 0x0005,
-    TCS_AT_UUID                = 0x0006,
-    OBEX_UUID          = 0x0008,
-    IP_UUID            = 0x0009,
-    FTP_UUID           = 0x000a,
-    HTTP_UUID          = 0x000c,
-    WSP_UUID           = 0x000e,
-    BNEP_UUID          = 0x000f,
-    UPNP_UUID          = 0x0010,
-    HIDP_UUID          = 0x0011,
-    HCRP_CTRL_UUID     = 0x0012,
-    HCRP_DATA_UUID     = 0x0014,
-    HCRP_NOTE_UUID     = 0x0016,
-    AVCTP_UUID         = 0x0017,
-    AVDTP_UUID         = 0x0019,
-    CMTP_UUID          = 0x001b,
-    UDI_UUID           = 0x001d,
-    MCAP_CTRL_UUID     = 0x001e,
-    MCAP_DATA_UUID     = 0x001f,
-    L2CAP_UUID         = 0x0100,
-};
-
-/*
- * Service class identifiers of standard services and service groups
- */
-enum service_class_id {
-    SDP_SERVER_SVCLASS_ID              = 0x1000,
-    BROWSE_GRP_DESC_SVCLASS_ID         = 0x1001,
-    PUBLIC_BROWSE_GROUP                        = 0x1002,
-    SERIAL_PORT_SVCLASS_ID             = 0x1101,
-    LAN_ACCESS_SVCLASS_ID              = 0x1102,
-    DIALUP_NET_SVCLASS_ID              = 0x1103,
-    IRMC_SYNC_SVCLASS_ID               = 0x1104,
-    OBEX_OBJPUSH_SVCLASS_ID            = 0x1105,
-    OBEX_FILETRANS_SVCLASS_ID          = 0x1106,
-    IRMC_SYNC_CMD_SVCLASS_ID           = 0x1107,
-    HEADSET_SVCLASS_ID                 = 0x1108,
-    CORDLESS_TELEPHONY_SVCLASS_ID      = 0x1109,
-    AUDIO_SOURCE_SVCLASS_ID            = 0x110a,
-    AUDIO_SINK_SVCLASS_ID              = 0x110b,
-    AV_REMOTE_TARGET_SVCLASS_ID                = 0x110c,
-    ADVANCED_AUDIO_SVCLASS_ID          = 0x110d,
-    AV_REMOTE_SVCLASS_ID               = 0x110e,
-    VIDEO_CONF_SVCLASS_ID              = 0x110f,
-    INTERCOM_SVCLASS_ID                        = 0x1110,
-    FAX_SVCLASS_ID                     = 0x1111,
-    HEADSET_AGW_SVCLASS_ID             = 0x1112,
-    WAP_SVCLASS_ID                     = 0x1113,
-    WAP_CLIENT_SVCLASS_ID              = 0x1114,
-    PANU_SVCLASS_ID                    = 0x1115,
-    NAP_SVCLASS_ID                     = 0x1116,
-    GN_SVCLASS_ID                      = 0x1117,
-    DIRECT_PRINTING_SVCLASS_ID         = 0x1118,
-    REFERENCE_PRINTING_SVCLASS_ID      = 0x1119,
-    IMAGING_SVCLASS_ID                 = 0x111a,
-    IMAGING_RESPONDER_SVCLASS_ID       = 0x111b,
-    IMAGING_ARCHIVE_SVCLASS_ID         = 0x111c,
-    IMAGING_REFOBJS_SVCLASS_ID         = 0x111d,
-    HANDSFREE_SVCLASS_ID               = 0x111e,
-    HANDSFREE_AGW_SVCLASS_ID           = 0x111f,
-    DIRECT_PRT_REFOBJS_SVCLASS_ID      = 0x1120,
-    REFLECTED_UI_SVCLASS_ID            = 0x1121,
-    BASIC_PRINTING_SVCLASS_ID          = 0x1122,
-    PRINTING_STATUS_SVCLASS_ID         = 0x1123,
-    HID_SVCLASS_ID                     = 0x1124,
-    HCR_SVCLASS_ID                     = 0x1125,
-    HCR_PRINT_SVCLASS_ID               = 0x1126,
-    HCR_SCAN_SVCLASS_ID                        = 0x1127,
-    CIP_SVCLASS_ID                     = 0x1128,
-    VIDEO_CONF_GW_SVCLASS_ID           = 0x1129,
-    UDI_MT_SVCLASS_ID                  = 0x112a,
-    UDI_TA_SVCLASS_ID                  = 0x112b,
-    AV_SVCLASS_ID                      = 0x112c,
-    SAP_SVCLASS_ID                     = 0x112d,
-    PBAP_PCE_SVCLASS_ID                        = 0x112e,
-    PBAP_PSE_SVCLASS_ID                        = 0x112f,
-    PBAP_SVCLASS_ID                    = 0x1130,
-    PNP_INFO_SVCLASS_ID                        = 0x1200,
-    GENERIC_NETWORKING_SVCLASS_ID      = 0x1201,
-    GENERIC_FILETRANS_SVCLASS_ID       = 0x1202,
-    GENERIC_AUDIO_SVCLASS_ID           = 0x1203,
-    GENERIC_TELEPHONY_SVCLASS_ID       = 0x1204,
-    UPNP_SVCLASS_ID                    = 0x1205,
-    UPNP_IP_SVCLASS_ID                 = 0x1206,
-    UPNP_PAN_SVCLASS_ID                        = 0x1300,
-    UPNP_LAP_SVCLASS_ID                        = 0x1301,
-    UPNP_L2CAP_SVCLASS_ID              = 0x1302,
-    VIDEO_SOURCE_SVCLASS_ID            = 0x1303,
-    VIDEO_SINK_SVCLASS_ID              = 0x1304,
-    VIDEO_DISTRIBUTION_SVCLASS_ID      = 0x1305,
-    MDP_SVCLASS_ID                     = 0x1400,
-    MDP_SOURCE_SVCLASS_ID              = 0x1401,
-    MDP_SINK_SVCLASS_ID                        = 0x1402,
-    APPLE_AGENT_SVCLASS_ID             = 0x2112,
-};
-
-/*
- * Standard profile descriptor identifiers; note these
- * may be identical to some of the service classes defined above
- */
-#define SDP_SERVER_PROFILE_ID          SDP_SERVER_SVCLASS_ID
-#define BROWSE_GRP_DESC_PROFILE_ID     BROWSE_GRP_DESC_SVCLASS_ID
-#define SERIAL_PORT_PROFILE_ID         SERIAL_PORT_SVCLASS_ID
-#define LAN_ACCESS_PROFILE_ID          LAN_ACCESS_SVCLASS_ID
-#define DIALUP_NET_PROFILE_ID          DIALUP_NET_SVCLASS_ID
-#define IRMC_SYNC_PROFILE_ID           IRMC_SYNC_SVCLASS_ID
-#define OBEX_OBJPUSH_PROFILE_ID                OBEX_OBJPUSH_SVCLASS_ID
-#define OBEX_FILETRANS_PROFILE_ID      OBEX_FILETRANS_SVCLASS_ID
-#define IRMC_SYNC_CMD_PROFILE_ID       IRMC_SYNC_CMD_SVCLASS_ID
-#define HEADSET_PROFILE_ID             HEADSET_SVCLASS_ID
-#define CORDLESS_TELEPHONY_PROFILE_ID  CORDLESS_TELEPHONY_SVCLASS_ID
-#define AUDIO_SOURCE_PROFILE_ID                AUDIO_SOURCE_SVCLASS_ID
-#define AUDIO_SINK_PROFILE_ID          AUDIO_SINK_SVCLASS_ID
-#define AV_REMOTE_TARGET_PROFILE_ID    AV_REMOTE_TARGET_SVCLASS_ID
-#define ADVANCED_AUDIO_PROFILE_ID      ADVANCED_AUDIO_SVCLASS_ID
-#define AV_REMOTE_PROFILE_ID           AV_REMOTE_SVCLASS_ID
-#define VIDEO_CONF_PROFILE_ID          VIDEO_CONF_SVCLASS_ID
-#define INTERCOM_PROFILE_ID            INTERCOM_SVCLASS_ID
-#define FAX_PROFILE_ID                 FAX_SVCLASS_ID
-#define HEADSET_AGW_PROFILE_ID         HEADSET_AGW_SVCLASS_ID
-#define WAP_PROFILE_ID                 WAP_SVCLASS_ID
-#define WAP_CLIENT_PROFILE_ID          WAP_CLIENT_SVCLASS_ID
-#define PANU_PROFILE_ID                        PANU_SVCLASS_ID
-#define NAP_PROFILE_ID                 NAP_SVCLASS_ID
-#define GN_PROFILE_ID                  GN_SVCLASS_ID
-#define DIRECT_PRINTING_PROFILE_ID     DIRECT_PRINTING_SVCLASS_ID
-#define REFERENCE_PRINTING_PROFILE_ID  REFERENCE_PRINTING_SVCLASS_ID
-#define IMAGING_PROFILE_ID             IMAGING_SVCLASS_ID
-#define IMAGING_RESPONDER_PROFILE_ID   IMAGING_RESPONDER_SVCLASS_ID
-#define IMAGING_ARCHIVE_PROFILE_ID     IMAGING_ARCHIVE_SVCLASS_ID
-#define IMAGING_REFOBJS_PROFILE_ID     IMAGING_REFOBJS_SVCLASS_ID
-#define HANDSFREE_PROFILE_ID           HANDSFREE_SVCLASS_ID
-#define HANDSFREE_AGW_PROFILE_ID       HANDSFREE_AGW_SVCLASS_ID
-#define DIRECT_PRT_REFOBJS_PROFILE_ID  DIRECT_PRT_REFOBJS_SVCLASS_ID
-#define REFLECTED_UI_PROFILE_ID                REFLECTED_UI_SVCLASS_ID
-#define BASIC_PRINTING_PROFILE_ID      BASIC_PRINTING_SVCLASS_ID
-#define PRINTING_STATUS_PROFILE_ID     PRINTING_STATUS_SVCLASS_ID
-#define HID_PROFILE_ID                 HID_SVCLASS_ID
-#define HCR_PROFILE_ID                 HCR_SCAN_SVCLASS_ID
-#define HCR_PRINT_PROFILE_ID           HCR_PRINT_SVCLASS_ID
-#define HCR_SCAN_PROFILE_ID            HCR_SCAN_SVCLASS_ID
-#define CIP_PROFILE_ID                 CIP_SVCLASS_ID
-#define VIDEO_CONF_GW_PROFILE_ID       VIDEO_CONF_GW_SVCLASS_ID
-#define UDI_MT_PROFILE_ID              UDI_MT_SVCLASS_ID
-#define UDI_TA_PROFILE_ID              UDI_TA_SVCLASS_ID
-#define AV_PROFILE_ID                  AV_SVCLASS_ID
-#define SAP_PROFILE_ID                 SAP_SVCLASS_ID
-#define PBAP_PCE_PROFILE_ID            PBAP_PCE_SVCLASS_ID
-#define PBAP_PSE_PROFILE_ID            PBAP_PSE_SVCLASS_ID
-#define PBAP_PROFILE_ID                        PBAP_SVCLASS_ID
-#define PNP_INFO_PROFILE_ID            PNP_INFO_SVCLASS_ID
-#define GENERIC_NETWORKING_PROFILE_ID  GENERIC_NETWORKING_SVCLASS_ID
-#define GENERIC_FILETRANS_PROFILE_ID   GENERIC_FILETRANS_SVCLASS_ID
-#define GENERIC_AUDIO_PROFILE_ID       GENERIC_AUDIO_SVCLASS_ID
-#define GENERIC_TELEPHONY_PROFILE_ID   GENERIC_TELEPHONY_SVCLASS_ID
-#define UPNP_PROFILE_ID                        UPNP_SVCLASS_ID
-#define UPNP_IP_PROFILE_ID             UPNP_IP_SVCLASS_ID
-#define UPNP_PAN_PROFILE_ID            UPNP_PAN_SVCLASS_ID
-#define UPNP_LAP_PROFILE_ID            UPNP_LAP_SVCLASS_ID
-#define UPNP_L2CAP_PROFILE_ID          UPNP_L2CAP_SVCLASS_ID
-#define VIDEO_SOURCE_PROFILE_ID                VIDEO_SOURCE_SVCLASS_ID
-#define VIDEO_SINK_PROFILE_ID          VIDEO_SINK_SVCLASS_ID
-#define VIDEO_DISTRIBUTION_PROFILE_ID  VIDEO_DISTRIBUTION_SVCLASS_ID
-#define MDP_PROFILE_ID                 MDP_SVCLASS_ID
-#define MDP_SOURCE_PROFILE_ID          MDP_SROUCE_SVCLASS_ID
-#define MDP_SINK_PROFILE_ID            MDP_SINK_SVCLASS_ID
-#define APPLE_AGENT_PROFILE_ID         APPLE_AGENT_SVCLASS_ID
-
-/* Data Representation */
-enum bt_sdp_data_type {
-    SDP_DTYPE_NIL      = 0 << 3,
-    SDP_DTYPE_UINT     = 1 << 3,
-    SDP_DTYPE_SINT     = 2 << 3,
-    SDP_DTYPE_UUID     = 3 << 3,
-    SDP_DTYPE_STRING   = 4 << 3,
-    SDP_DTYPE_BOOL     = 5 << 3,
-    SDP_DTYPE_SEQ      = 6 << 3,
-    SDP_DTYPE_ALT      = 7 << 3,
-    SDP_DTYPE_URL      = 8 << 3,
-};
-
-enum bt_sdp_data_size {
-    SDP_DSIZE_1                = 0,
-    SDP_DSIZE_2,
-    SDP_DSIZE_4,
-    SDP_DSIZE_8,
-    SDP_DSIZE_16,
-    SDP_DSIZE_NEXT1,
-    SDP_DSIZE_NEXT2,
-    SDP_DSIZE_NEXT4,
-    SDP_DSIZE_MASK = SDP_DSIZE_NEXT4,
-};
-
-enum bt_sdp_cmd {
-    SDP_ERROR_RSP              = 0x01,
-    SDP_SVC_SEARCH_REQ         = 0x02,
-    SDP_SVC_SEARCH_RSP         = 0x03,
-    SDP_SVC_ATTR_REQ           = 0x04,
-    SDP_SVC_ATTR_RSP           = 0x05,
-    SDP_SVC_SEARCH_ATTR_REQ    = 0x06,
-    SDP_SVC_SEARCH_ATTR_RSP    = 0x07,
-};
-
-enum bt_sdp_errorcode {
-    SDP_INVALID_VERSION                = 0x0001,
-    SDP_INVALID_RECORD_HANDLE  = 0x0002,
-    SDP_INVALID_SYNTAX         = 0x0003,
-    SDP_INVALID_PDU_SIZE       = 0x0004,
-    SDP_INVALID_CSTATE         = 0x0005,
-};
-
-/*
- * String identifiers are based on the SDP spec stating that
- * "base attribute id of the primary (universal) language must be 0x0100"
- *
- * Other languages should have their own offset; e.g.:
- * #define XXXLangBase yyyy
- * #define AttrServiceName_XXX 0x0000+XXXLangBase
- */
-#define SDP_PRIMARY_LANG_BASE          0x0100
-
-enum bt_sdp_attribute_id {
-    SDP_ATTR_RECORD_HANDLE                     = 0x0000,
-    SDP_ATTR_SVCLASS_ID_LIST                   = 0x0001,
-    SDP_ATTR_RECORD_STATE                      = 0x0002,
-    SDP_ATTR_SERVICE_ID                                = 0x0003,
-    SDP_ATTR_PROTO_DESC_LIST                   = 0x0004,
-    SDP_ATTR_BROWSE_GRP_LIST                   = 0x0005,
-    SDP_ATTR_LANG_BASE_ATTR_ID_LIST            = 0x0006,
-    SDP_ATTR_SVCINFO_TTL                       = 0x0007,
-    SDP_ATTR_SERVICE_AVAILABILITY              = 0x0008,
-    SDP_ATTR_PFILE_DESC_LIST                   = 0x0009,
-    SDP_ATTR_DOC_URL                           = 0x000a,
-    SDP_ATTR_CLNT_EXEC_URL                     = 0x000b,
-    SDP_ATTR_ICON_URL                          = 0x000c,
-    SDP_ATTR_ADD_PROTO_DESC_LIST               = 0x000d,
-
-    SDP_ATTR_SVCNAME_PRIMARY                   = SDP_PRIMARY_LANG_BASE + 0,
-    SDP_ATTR_SVCDESC_PRIMARY                   = SDP_PRIMARY_LANG_BASE + 1,
-    SDP_ATTR_SVCPROV_PRIMARY                   = SDP_PRIMARY_LANG_BASE + 2,
-
-    SDP_ATTR_GROUP_ID                          = 0x0200,
-    SDP_ATTR_IP_SUBNET                         = 0x0200,
-
-    /* SDP */
-    SDP_ATTR_VERSION_NUM_LIST                  = 0x0200,
-    SDP_ATTR_SVCDB_STATE                       = 0x0201,
-
-    SDP_ATTR_SERVICE_VERSION                   = 0x0300,
-    SDP_ATTR_EXTERNAL_NETWORK                  = 0x0301,
-    SDP_ATTR_SUPPORTED_DATA_STORES_LIST                = 0x0301,
-    SDP_ATTR_FAX_CLASS1_SUPPORT                        = 0x0302,
-    SDP_ATTR_REMOTE_AUDIO_VOLUME_CONTROL       = 0x0302,
-    SDP_ATTR_FAX_CLASS20_SUPPORT               = 0x0303,
-    SDP_ATTR_SUPPORTED_FORMATS_LIST            = 0x0303,
-    SDP_ATTR_FAX_CLASS2_SUPPORT                        = 0x0304,
-    SDP_ATTR_AUDIO_FEEDBACK_SUPPORT            = 0x0305,
-    SDP_ATTR_NETWORK_ADDRESS                   = 0x0306,
-    SDP_ATTR_WAP_GATEWAY                       = 0x0307,
-    SDP_ATTR_HOMEPAGE_URL                      = 0x0308,
-    SDP_ATTR_WAP_STACK_TYPE                    = 0x0309,
-    SDP_ATTR_SECURITY_DESC                     = 0x030a,
-    SDP_ATTR_NET_ACCESS_TYPE                   = 0x030b,
-    SDP_ATTR_MAX_NET_ACCESSRATE                        = 0x030c,
-    SDP_ATTR_IP4_SUBNET                                = 0x030d,
-    SDP_ATTR_IP6_SUBNET                                = 0x030e,
-    SDP_ATTR_SUPPORTED_CAPABILITIES            = 0x0310,
-    SDP_ATTR_SUPPORTED_FEATURES                        = 0x0311,
-    SDP_ATTR_SUPPORTED_FUNCTIONS               = 0x0312,
-    SDP_ATTR_TOTAL_IMAGING_DATA_CAPACITY       = 0x0313,
-    SDP_ATTR_SUPPORTED_REPOSITORIES            = 0x0314,
-
-    /* PnP Information */
-    SDP_ATTR_SPECIFICATION_ID                  = 0x0200,
-    SDP_ATTR_VENDOR_ID                         = 0x0201,
-    SDP_ATTR_PRODUCT_ID                                = 0x0202,
-    SDP_ATTR_VERSION                           = 0x0203,
-    SDP_ATTR_PRIMARY_RECORD                    = 0x0204,
-    SDP_ATTR_VENDOR_ID_SOURCE                  = 0x0205,
-
-    /* BT HID */
-    SDP_ATTR_DEVICE_RELEASE_NUMBER             = 0x0200,
-    SDP_ATTR_PARSER_VERSION                    = 0x0201,
-    SDP_ATTR_DEVICE_SUBCLASS                   = 0x0202,
-    SDP_ATTR_COUNTRY_CODE                      = 0x0203,
-    SDP_ATTR_VIRTUAL_CABLE                     = 0x0204,
-    SDP_ATTR_RECONNECT_INITIATE                        = 0x0205,
-    SDP_ATTR_DESCRIPTOR_LIST                   = 0x0206,
-    SDP_ATTR_LANG_ID_BASE_LIST                 = 0x0207,
-    SDP_ATTR_SDP_DISABLE                       = 0x0208,
-    SDP_ATTR_BATTERY_POWER                     = 0x0209,
-    SDP_ATTR_REMOTE_WAKEUP                     = 0x020a,
-    SDP_ATTR_PROFILE_VERSION                   = 0x020b,
-    SDP_ATTR_SUPERVISION_TIMEOUT               = 0x020c,
-    SDP_ATTR_NORMALLY_CONNECTABLE              = 0x020d,
-    SDP_ATTR_BOOT_DEVICE                       = 0x020e,
-};
-
-#endif
diff --git a/hw/bt/Makefile.objs b/hw/bt/Makefile.objs
new file mode 100644 (file)
index 0000000..867a7d2
--- /dev/null
@@ -0,0 +1,3 @@
+common-obj-y += core.o l2cap.o sdp.o hci.o hid.o
+common-obj-y += hci-csr.o
+
diff --git a/hw/bt/core.c b/hw/bt/core.c
new file mode 100644 (file)
index 0000000..24ef4de
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * Convenience functions for bluetooth.
+ *
+ * Copyright (C) 2008 Andrzej Zaborowski  <balrog@zabor.org>
+ *
+ * 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 or
+ * (at your option) version 3 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
+ * 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 "bt/bt.h"
+#include "hw/bt.h"
+
+/* Slave implementations can ignore this */
+static void bt_dummy_lmp_mode_change(struct bt_link_s *link)
+{
+}
+
+/* Slaves should never receive these PDUs */
+static void bt_dummy_lmp_connection_complete(struct bt_link_s *link)
+{
+    if (link->slave->reject_reason)
+        fprintf(stderr, "%s: stray LMP_not_accepted received, fixme\n",
+                        __FUNCTION__);
+    else
+        fprintf(stderr, "%s: stray LMP_accepted received, fixme\n",
+                        __FUNCTION__);
+    exit(-1);
+}
+
+static void bt_dummy_lmp_disconnect_master(struct bt_link_s *link)
+{
+    fprintf(stderr, "%s: stray LMP_detach received, fixme\n", __FUNCTION__);
+    exit(-1);
+}
+
+static void bt_dummy_lmp_acl_resp(struct bt_link_s *link,
+                const uint8_t *data, int start, int len)
+{
+    fprintf(stderr, "%s: stray ACL response PDU, fixme\n", __FUNCTION__);
+    exit(-1);
+}
+
+/* Slaves that don't hold any additional per link state can use these */
+static void bt_dummy_lmp_connection_request(struct bt_link_s *req)
+{
+    struct bt_link_s *link = g_malloc0(sizeof(struct bt_link_s));
+
+    link->slave = req->slave;
+    link->host = req->host;
+
+    req->host->reject_reason = 0;
+    req->host->lmp_connection_complete(link);
+}
+
+static void bt_dummy_lmp_disconnect_slave(struct bt_link_s *link)
+{
+    g_free(link);
+}
+
+static void bt_dummy_destroy(struct bt_device_s *device)
+{
+    bt_device_done(device);
+    g_free(device);
+}
+
+static int bt_dev_idx = 0;
+
+void bt_device_init(struct bt_device_s *dev, struct bt_scatternet_s *net)
+{
+    memset(dev, 0, sizeof(*dev));
+    dev->inquiry_scan = 1;
+    dev->page_scan = 1;
+
+    dev->bd_addr.b[0] = bt_dev_idx & 0xff;
+    dev->bd_addr.b[1] = bt_dev_idx >> 8;
+    dev->bd_addr.b[2] = 0xd0;
+    dev->bd_addr.b[3] = 0xba;
+    dev->bd_addr.b[4] = 0xbe;
+    dev->bd_addr.b[5] = 0xba;
+    bt_dev_idx ++;
+
+    /* Simple slave-only devices need to implement only .lmp_acl_data */
+    dev->lmp_connection_complete = bt_dummy_lmp_connection_complete;
+    dev->lmp_disconnect_master = bt_dummy_lmp_disconnect_master;
+    dev->lmp_acl_resp = bt_dummy_lmp_acl_resp;
+    dev->lmp_mode_change = bt_dummy_lmp_mode_change;
+    dev->lmp_connection_request = bt_dummy_lmp_connection_request;
+    dev->lmp_disconnect_slave = bt_dummy_lmp_disconnect_slave;
+
+    dev->handle_destroy = bt_dummy_destroy;
+
+    dev->net = net;
+    dev->next = net->slave;
+    net->slave = dev;
+}
+
+void bt_device_done(struct bt_device_s *dev)
+{
+    struct bt_device_s **p = &dev->net->slave;
+
+    while (*p && *p != dev)
+        p = &(*p)->next;
+    if (*p != dev) {
+        fprintf(stderr, "%s: bad bt device \"%s\"\n", __FUNCTION__,
+                        dev->lmp_name ?: "(null)");
+        exit(-1);
+    }
+
+    *p = dev->next;
+}
diff --git a/hw/bt/hci-csr.c b/hw/bt/hci-csr.c
new file mode 100644 (file)
index 0000000..55c819b
--- /dev/null
@@ -0,0 +1,454 @@
+/*
+ * Bluetooth serial HCI transport.
+ * CSR41814 HCI with H4p vendor extensions.
+ *
+ * Copyright (C) 2008 Andrzej Zaborowski  <balrog@zabor.org>
+ *
+ * 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 or
+ * (at your option) version 3 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
+ * 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 "char/char.h"
+#include "qemu/timer.h"
+#include "hw/irq.h"
+#include "bt/bt.h"
+#include "hw/bt.h"
+
+struct csrhci_s {
+    int enable;
+    qemu_irq *pins;
+    int pin_state;
+    int modem_state;
+    CharDriverState chr;
+#define FIFO_LEN       4096
+    int out_start;
+    int out_len;
+    int out_size;
+    uint8_t outfifo[FIFO_LEN * 2];
+    uint8_t inpkt[FIFO_LEN];
+    int in_len;
+    int in_hdr;
+    int in_data;
+    QEMUTimer *out_tm;
+    int64_t baud_delay;
+
+    bdaddr_t bd_addr;
+    struct HCIInfo *hci;
+};
+
+/* H4+ packet types */
+enum {
+    H4_CMD_PKT   = 1,
+    H4_ACL_PKT   = 2,
+    H4_SCO_PKT   = 3,
+    H4_EVT_PKT   = 4,
+    H4_NEG_PKT   = 6,
+    H4_ALIVE_PKT = 7,
+};
+
+/* CSR41814 negotiation start magic packet */
+static const uint8_t csrhci_neg_packet[] = {
+    H4_NEG_PKT, 10,
+    0x00, 0xa0, 0x01, 0x00, 0x00,
+    0x4c, 0x00, 0x96, 0x00, 0x00,
+};
+
+/* CSR41814 vendor-specific command OCFs */
+enum {
+    OCF_CSR_SEND_FIRMWARE = 0x000,
+};
+
+static inline void csrhci_fifo_wake(struct csrhci_s *s)
+{
+    if (!s->enable || !s->out_len)
+        return;
+
+    /* XXX: Should wait for s->modem_state & CHR_TIOCM_RTS? */
+    if (s->chr.chr_can_read && s->chr.chr_can_read(s->chr.handler_opaque) &&
+                    s->chr.chr_read) {
+        s->chr.chr_read(s->chr.handler_opaque,
+                        s->outfifo + s->out_start ++, 1);
+        s->out_len --;
+        if (s->out_start >= s->out_size) {
+            s->out_start = 0;
+            s->out_size = FIFO_LEN;
+        }
+    }
+
+    if (s->out_len)
+        qemu_mod_timer(s->out_tm, qemu_get_clock_ns(vm_clock) + s->baud_delay);
+}
+
+#define csrhci_out_packetz(s, len) memset(csrhci_out_packet(s, len), 0, len)
+static uint8_t *csrhci_out_packet(struct csrhci_s *s, int len)
+{
+    int off = s->out_start + s->out_len;
+
+    /* TODO: do the padding here, i.e. align len */
+    s->out_len += len;
+
+    if (off < FIFO_LEN) {
+        if (off + len > FIFO_LEN && (s->out_size = off + len) > FIFO_LEN * 2) {
+            fprintf(stderr, "%s: can't alloc %i bytes\n", __FUNCTION__, len);
+            exit(-1);
+        }
+        return s->outfifo + off;
+    }
+
+    if (s->out_len > s->out_size) {
+        fprintf(stderr, "%s: can't alloc %i bytes\n", __FUNCTION__, len);
+        exit(-1);
+    }
+
+    return s->outfifo + off - s->out_size;
+}
+
+static inline uint8_t *csrhci_out_packet_csr(struct csrhci_s *s,
+                int type, int len)
+{
+    uint8_t *ret = csrhci_out_packetz(s, len + 2);
+
+    *ret ++ = type;
+    *ret ++ = len;
+
+    return ret;
+}
+
+static inline uint8_t *csrhci_out_packet_event(struct csrhci_s *s,
+                int evt, int len)
+{
+    uint8_t *ret = csrhci_out_packetz(s,
+                    len + 1 + sizeof(struct hci_event_hdr));
+
+    *ret ++ = H4_EVT_PKT;
+    ((struct hci_event_hdr *) ret)->evt = evt;
+    ((struct hci_event_hdr *) ret)->plen = len;
+
+    return ret + sizeof(struct hci_event_hdr);
+}
+
+static void csrhci_in_packet_vendor(struct csrhci_s *s, int ocf,
+                uint8_t *data, int len)
+{
+    int offset;
+    uint8_t *rpkt;
+
+    switch (ocf) {
+    case OCF_CSR_SEND_FIRMWARE:
+        /* Check if this is the bd_address packet */
+        if (len >= 18 + 8 && data[12] == 0x01 && data[13] == 0x00) {
+            offset = 18;
+            s->bd_addr.b[0] = data[offset + 7];        /* Beyond cmd packet end(!?) */
+            s->bd_addr.b[1] = data[offset + 6];
+            s->bd_addr.b[2] = data[offset + 4];
+            s->bd_addr.b[3] = data[offset + 0];
+            s->bd_addr.b[4] = data[offset + 3];
+            s->bd_addr.b[5] = data[offset + 2];
+
+            s->hci->bdaddr_set(s->hci, s->bd_addr.b);
+            fprintf(stderr, "%s: bd_address loaded from firmware: "
+                            "%02x:%02x:%02x:%02x:%02x:%02x\n", __FUNCTION__,
+                            s->bd_addr.b[0], s->bd_addr.b[1], s->bd_addr.b[2],
+                            s->bd_addr.b[3], s->bd_addr.b[4], s->bd_addr.b[5]);
+        }
+
+        rpkt = csrhci_out_packet_event(s, EVT_VENDOR, 11);
+        /* Status bytes: no error */
+        rpkt[9] = 0x00;
+        rpkt[10] = 0x00;
+        break;
+
+    default:
+        fprintf(stderr, "%s: got a bad CMD packet\n", __FUNCTION__);
+        return;
+    }
+
+    csrhci_fifo_wake(s);
+}
+
+static void csrhci_in_packet(struct csrhci_s *s, uint8_t *pkt)
+{
+    uint8_t *rpkt;
+    int opc;
+
+    switch (*pkt ++) {
+    case H4_CMD_PKT:
+        opc = le16_to_cpu(((struct hci_command_hdr *) pkt)->opcode);
+        if (cmd_opcode_ogf(opc) == OGF_VENDOR_CMD) {
+            csrhci_in_packet_vendor(s, cmd_opcode_ocf(opc),
+                            pkt + sizeof(struct hci_command_hdr),
+                            s->in_len - sizeof(struct hci_command_hdr) - 1);
+            return;
+        }
+
+        /* TODO: if the command is OCF_READ_LOCAL_COMMANDS or the likes,
+         * we need to send it to the HCI layer and then add our supported
+         * commands to the returned mask (such as OGF_VENDOR_CMD).  With
+         * bt-hci.c we could just have hooks for this kind of commands but
+         * we can't with bt-host.c.  */
+
+        s->hci->cmd_send(s->hci, pkt, s->in_len - 1);
+        break;
+
+    case H4_EVT_PKT:
+        goto bad_pkt;
+
+    case H4_ACL_PKT:
+        s->hci->acl_send(s->hci, pkt, s->in_len - 1);
+        break;
+
+    case H4_SCO_PKT:
+        s->hci->sco_send(s->hci, pkt, s->in_len - 1);
+        break;
+
+    case H4_NEG_PKT:
+        if (s->in_hdr != sizeof(csrhci_neg_packet) ||
+                        memcmp(pkt - 1, csrhci_neg_packet, s->in_hdr)) {
+            fprintf(stderr, "%s: got a bad NEG packet\n", __FUNCTION__);
+            return;
+        }
+        pkt += 2;
+
+        rpkt = csrhci_out_packet_csr(s, H4_NEG_PKT, 10);
+
+        *rpkt ++ = 0x20;       /* Operational settings negotiation Ok */
+        memcpy(rpkt, pkt, 7); rpkt += 7;
+        *rpkt ++ = 0xff;
+        *rpkt = 0xff;
+        break;
+
+    case H4_ALIVE_PKT:
+        if (s->in_hdr != 4 || pkt[1] != 0x55 || pkt[2] != 0x00) {
+            fprintf(stderr, "%s: got a bad ALIVE packet\n", __FUNCTION__);
+            return;
+        }
+
+        rpkt = csrhci_out_packet_csr(s, H4_ALIVE_PKT, 2);
+
+        *rpkt ++ = 0xcc;
+        *rpkt = 0x00;
+        break;
+
+    default:
+    bad_pkt:
+        /* TODO: error out */
+        fprintf(stderr, "%s: got a bad packet\n", __FUNCTION__);
+        break;
+    }
+
+    csrhci_fifo_wake(s);
+}
+
+static int csrhci_header_len(const uint8_t *pkt)
+{
+    switch (pkt[0]) {
+    case H4_CMD_PKT:
+        return HCI_COMMAND_HDR_SIZE;
+    case H4_EVT_PKT:
+        return HCI_EVENT_HDR_SIZE;
+    case H4_ACL_PKT:
+        return HCI_ACL_HDR_SIZE;
+    case H4_SCO_PKT:
+        return HCI_SCO_HDR_SIZE;
+    case H4_NEG_PKT:
+        return pkt[1] + 1;
+    case H4_ALIVE_PKT:
+        return 3;
+    }
+
+    exit(-1);
+}
+
+static int csrhci_data_len(const uint8_t *pkt)
+{
+    switch (*pkt ++) {
+    case H4_CMD_PKT:
+        /* It seems that vendor-specific command packets for H4+ are all
+         * one byte longer than indicated in the standard header.  */
+        if (le16_to_cpu(((struct hci_command_hdr *) pkt)->opcode) == 0xfc00)
+            return (((struct hci_command_hdr *) pkt)->plen + 1) & ~1;
+
+        return ((struct hci_command_hdr *) pkt)->plen;
+    case H4_EVT_PKT:
+        return ((struct hci_event_hdr *) pkt)->plen;
+    case H4_ACL_PKT:
+        return le16_to_cpu(((struct hci_acl_hdr *) pkt)->dlen);
+    case H4_SCO_PKT:
+        return ((struct hci_sco_hdr *) pkt)->dlen;
+    case H4_NEG_PKT:
+    case H4_ALIVE_PKT:
+        return 0;
+    }
+
+    exit(-1);
+}
+
+static int csrhci_write(struct CharDriverState *chr,
+                const uint8_t *buf, int len)
+{
+    struct csrhci_s *s = (struct csrhci_s *) chr->opaque;
+    int plen = s->in_len;
+
+    if (!s->enable)
+        return 0;
+
+    s->in_len += len;
+    memcpy(s->inpkt + plen, buf, len);
+
+    while (1) {
+        if (s->in_len >= 2 && plen < 2)
+            s->in_hdr = csrhci_header_len(s->inpkt) + 1;
+
+        if (s->in_len >= s->in_hdr && plen < s->in_hdr)
+            s->in_data = csrhci_data_len(s->inpkt) + s->in_hdr;
+
+        if (s->in_len >= s->in_data) {
+            csrhci_in_packet(s, s->inpkt);
+
+            memmove(s->inpkt, s->inpkt + s->in_len, s->in_len - s->in_data);
+            s->in_len -= s->in_data;
+            s->in_hdr = INT_MAX;
+            s->in_data = INT_MAX;
+            plen = 0;
+        } else
+            break;
+    }
+
+    return len;
+}
+
+static void csrhci_out_hci_packet_event(void *opaque,
+                const uint8_t *data, int len)
+{
+    struct csrhci_s *s = (struct csrhci_s *) opaque;
+    uint8_t *pkt = csrhci_out_packet(s, (len + 2) & ~1);       /* Align */
+
+    *pkt ++ = H4_EVT_PKT;
+    memcpy(pkt, data, len);
+
+    csrhci_fifo_wake(s);
+}
+
+static void csrhci_out_hci_packet_acl(void *opaque,
+                const uint8_t *data, int len)
+{
+    struct csrhci_s *s = (struct csrhci_s *) opaque;
+    uint8_t *pkt = csrhci_out_packet(s, (len + 2) & ~1);       /* Align */
+
+    *pkt ++ = H4_ACL_PKT;
+    pkt[len & ~1] = 0;
+    memcpy(pkt, data, len);
+
+    csrhci_fifo_wake(s);
+}
+
+static int csrhci_ioctl(struct CharDriverState *chr, int cmd, void *arg)
+{
+    QEMUSerialSetParams *ssp;
+    struct csrhci_s *s = (struct csrhci_s *) chr->opaque;
+    int prev_state = s->modem_state;
+
+    switch (cmd) {
+    case CHR_IOCTL_SERIAL_SET_PARAMS:
+        ssp = (QEMUSerialSetParams *) arg;
+        s->baud_delay = get_ticks_per_sec() / ssp->speed;
+        /* Moments later... (but shorter than 100ms) */
+        s->modem_state |= CHR_TIOCM_CTS;
+        break;
+
+    case CHR_IOCTL_SERIAL_GET_TIOCM:
+        *(int *) arg = s->modem_state;
+        break;
+
+    case CHR_IOCTL_SERIAL_SET_TIOCM:
+        s->modem_state = *(int *) arg;
+        if (~s->modem_state & prev_state & CHR_TIOCM_RTS)
+            s->modem_state &= ~CHR_TIOCM_CTS;
+        break;
+
+    default:
+        return -ENOTSUP;
+    }
+    return 0;
+}
+
+static void csrhci_reset(struct csrhci_s *s)
+{
+    s->out_len = 0;
+    s->out_size = FIFO_LEN;
+    s->in_len = 0;
+    s->baud_delay = get_ticks_per_sec();
+    s->enable = 0;
+    s->in_hdr = INT_MAX;
+    s->in_data = INT_MAX;
+
+    s->modem_state = 0;
+    /* After a while... (but sooner than 10ms) */
+    s->modem_state |= CHR_TIOCM_CTS;
+
+    memset(&s->bd_addr, 0, sizeof(bdaddr_t));
+}
+
+static void csrhci_out_tick(void *opaque)
+{
+    csrhci_fifo_wake((struct csrhci_s *) opaque);
+}
+
+static void csrhci_pins(void *opaque, int line, int level)
+{
+    struct csrhci_s *s = (struct csrhci_s *) opaque;
+    int state = s->pin_state;
+
+    s->pin_state &= ~(1 << line);
+    s->pin_state |= (!!level) << line;
+
+    if ((state & ~s->pin_state) & (1 << csrhci_pin_reset)) {
+        /* TODO: Disappear from lower layers */
+        csrhci_reset(s);
+    }
+
+    if (s->pin_state == 3 && state != 3) {
+        s->enable = 1;
+        /* TODO: Wake lower layers up */
+    }
+}
+
+qemu_irq *csrhci_pins_get(CharDriverState *chr)
+{
+    struct csrhci_s *s = (struct csrhci_s *) chr->opaque;
+
+    return s->pins;
+}
+
+CharDriverState *uart_hci_init(qemu_irq wakeup)
+{
+    struct csrhci_s *s = (struct csrhci_s *)
+            g_malloc0(sizeof(struct csrhci_s));
+
+    s->chr.opaque = s;
+    s->chr.chr_write = csrhci_write;
+    s->chr.chr_ioctl = csrhci_ioctl;
+    s->chr.avail_connections = 1;
+
+    s->hci = qemu_next_hci();
+    s->hci->opaque = s;
+    s->hci->evt_recv = csrhci_out_hci_packet_event;
+    s->hci->acl_recv = csrhci_out_hci_packet_acl;
+
+    s->out_tm = qemu_new_timer_ns(vm_clock, csrhci_out_tick, s);
+    s->pins = qemu_allocate_irqs(csrhci_pins, s, __csrhci_pins);
+    csrhci_reset(s);
+
+    return &s->chr;
+}
diff --git a/hw/bt/hci.c b/hw/bt/hci.c
new file mode 100644 (file)
index 0000000..a76edea
--- /dev/null
@@ -0,0 +1,2217 @@
+/*
+ * QEMU Bluetooth HCI logic.
+ *
+ * Copyright (C) 2007 OpenMoko, Inc.
+ * Copyright (C) 2008 Andrzej Zaborowski  <balrog@zabor.org>
+ *
+ * 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 "qemu/timer.h"
+#include "hw/usb.h"
+#include "bt/bt.h"
+#include "hw/bt.h"
+
+struct bt_hci_s {
+    uint8_t *(*evt_packet)(void *opaque);
+    void (*evt_submit)(void *opaque, int len);
+    void *opaque;
+    uint8_t evt_buf[256];
+
+    uint8_t acl_buf[4096];
+    int acl_len;
+
+    uint16_t asb_handle;
+    uint16_t psb_handle;
+
+    int last_cmd;      /* Note: Always little-endian */
+
+    struct bt_device_s *conn_req_host;
+
+    struct {
+        int inquire;
+        int periodic;
+        int responses_left;
+        int responses;
+        QEMUTimer *inquiry_done;
+        QEMUTimer *inquiry_next;
+        int inquiry_length;
+        int inquiry_period;
+        int inquiry_mode;
+
+#define HCI_HANDLE_OFFSET      0x20
+#define HCI_HANDLES_MAX                0x10
+        struct bt_hci_master_link_s {
+            struct bt_link_s *link;
+            void (*lmp_acl_data)(struct bt_link_s *link,
+                            const uint8_t *data, int start, int len);
+            QEMUTimer *acl_mode_timer;
+        } handle[HCI_HANDLES_MAX];
+        uint32_t role_bmp;
+        int last_handle;
+        int connecting;
+        bdaddr_t awaiting_bdaddr[HCI_HANDLES_MAX];
+    } lm;
+
+    uint8_t event_mask[8];
+    uint16_t voice_setting;    /* Notw: Always little-endian */
+    uint16_t conn_accept_tout;
+    QEMUTimer *conn_accept_timer;
+
+    struct HCIInfo info;
+    struct bt_device_s device;
+};
+
+#define DEFAULT_RSSI_DBM       20
+
+#define hci_from_info(ptr)     container_of((ptr), struct bt_hci_s, info)
+#define hci_from_device(ptr)   container_of((ptr), struct bt_hci_s, device)
+
+struct bt_hci_link_s {
+    struct bt_link_s btlink;
+    uint16_t handle;   /* Local */
+};
+
+/* LMP layer emulation */
+#if 0
+static void bt_submit_lmp(struct bt_device_s *bt, int length, uint8_t *data)
+{
+    int resp, resplen, error, op, tr;
+    uint8_t respdata[17];
+
+    if (length < 1)
+        return;
+
+    tr = *data & 1;
+    op = *(data ++) >> 1;
+    resp = LMP_ACCEPTED;
+    resplen = 2;
+    respdata[1] = op;
+    error = 0;
+    length --;
+
+    if (op >= 0x7c) {  /* Extended opcode */
+        op |= *(data ++) << 8;
+        resp = LMP_ACCEPTED_EXT;
+        resplen = 4;
+        respdata[0] = op >> 8;
+        respdata[1] = op & 0xff;
+        length --;
+    }
+
+    switch (op) {
+    case LMP_ACCEPTED:
+        /* data[0]     Op code
+         */
+        if (length < 1) {
+            error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
+            goto not_accepted;
+        }
+        resp = 0;
+        break;
+
+    case LMP_ACCEPTED_EXT:
+        /* data[0]     Escape op code
+         * data[1]     Extended op code
+         */
+        if (length < 2) {
+            error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
+            goto not_accepted;
+        }
+        resp = 0;
+        break;
+
+    case LMP_NOT_ACCEPTED:
+        /* data[0]     Op code
+         * data[1]     Error code
+         */
+        if (length < 2) {
+            error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
+            goto not_accepted;
+        }
+        resp = 0;
+        break;
+
+    case LMP_NOT_ACCEPTED_EXT:
+        /* data[0]     Op code
+         * data[1]     Extended op code
+         * data[2]     Error code
+         */
+        if (length < 3) {
+            error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
+            goto not_accepted;
+        }
+        resp = 0;
+        break;
+
+    case LMP_HOST_CONNECTION_REQ:
+        break;
+
+    case LMP_SETUP_COMPLETE:
+        resp = LMP_SETUP_COMPLETE;
+        resplen = 1;
+        bt->setup = 1;
+        break;
+
+    case LMP_DETACH:
+        /* data[0]     Error code
+         */
+        if (length < 1) {
+            error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
+            goto not_accepted;
+        }
+        bt->setup = 0;
+        resp = 0;
+        break;
+
+    case LMP_SUPERVISION_TIMEOUT:
+        /* data[0,1]   Supervision timeout
+         */
+        if (length < 2) {
+            error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
+            goto not_accepted;
+        }
+        resp = 0;
+        break;
+
+    case LMP_QUALITY_OF_SERVICE:
+        resp = 0;
+        /* Fall through */
+    case LMP_QOS_REQ:
+        /* data[0,1]   Poll interval
+         * data[2]     N(BC)
+         */
+        if (length < 3) {
+            error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
+            goto not_accepted;
+        }
+        break;
+
+    case LMP_MAX_SLOT:
+        resp = 0;
+        /* Fall through */
+    case LMP_MAX_SLOT_REQ:
+        /* data[0]     Max slots
+         */
+        if (length < 1) {
+            error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
+            goto not_accepted;
+        }
+        break;
+
+    case LMP_AU_RAND:
+    case LMP_IN_RAND:
+    case LMP_COMB_KEY:
+        /* data[0-15]  Random number
+         */
+        if (length < 16) {
+            error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
+            goto not_accepted;
+        }
+        if (op == LMP_AU_RAND) {
+            if (bt->key_present) {
+                resp = LMP_SRES;
+                resplen = 5;
+                /* XXX: [Part H] Section 6.1 on page 801 */
+            } else {
+                error = HCI_PIN_OR_KEY_MISSING;
+                goto not_accepted;
+            }
+        } else if (op == LMP_IN_RAND) {
+            error = HCI_PAIRING_NOT_ALLOWED;
+            goto not_accepted;
+        } else {
+            /* XXX: [Part H] Section 3.2 on page 779 */
+            resp = LMP_UNIT_KEY;
+            resplen = 17;
+            memcpy(respdata + 1, bt->key, 16);
+
+            error = HCI_UNIT_LINK_KEY_USED;
+            goto not_accepted;
+        }
+        break;
+
+    case LMP_UNIT_KEY:
+        /* data[0-15]  Key
+         */
+        if (length < 16) {
+            error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
+            goto not_accepted;
+        }
+        memcpy(bt->key, data, 16);
+        bt->key_present = 1;
+        break;
+
+    case LMP_SRES:
+        /* data[0-3]   Authentication response
+         */
+        if (length < 4) {
+            error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
+            goto not_accepted;
+        }
+        break;
+
+    case LMP_CLKOFFSET_REQ:
+        resp = LMP_CLKOFFSET_RES;
+        resplen = 3;
+        respdata[1] = 0x33;
+        respdata[2] = 0x33;
+        break;
+
+    case LMP_CLKOFFSET_RES:
+        /* data[0,1]   Clock offset
+         * (Slave to master only)
+         */
+        if (length < 2) {
+            error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
+            goto not_accepted;
+        }
+        break;
+
+    case LMP_VERSION_REQ:
+    case LMP_VERSION_RES:
+        /* data[0]     VersNr
+         * data[1,2]   CompId
+         * data[3,4]   SubVersNr
+         */
+        if (length < 5) {
+            error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
+            goto not_accepted;
+        }
+        if (op == LMP_VERSION_REQ) {
+            resp = LMP_VERSION_RES;
+            resplen = 6;
+            respdata[1] = 0x20;
+            respdata[2] = 0xff;
+            respdata[3] = 0xff;
+            respdata[4] = 0xff;
+            respdata[5] = 0xff;
+        } else
+            resp = 0;
+        break;
+
+    case LMP_FEATURES_REQ:
+    case LMP_FEATURES_RES:
+        /* data[0-7]   Features
+         */
+        if (length < 8) {
+            error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
+            goto not_accepted;
+        }
+        if (op == LMP_FEATURES_REQ) {
+            resp = LMP_FEATURES_RES;
+            resplen = 9;
+            respdata[1] = (bt->lmp_caps >> 0) & 0xff;
+            respdata[2] = (bt->lmp_caps >> 8) & 0xff;
+            respdata[3] = (bt->lmp_caps >> 16) & 0xff;
+            respdata[4] = (bt->lmp_caps >> 24) & 0xff;
+            respdata[5] = (bt->lmp_caps >> 32) & 0xff;
+            respdata[6] = (bt->lmp_caps >> 40) & 0xff;
+            respdata[7] = (bt->lmp_caps >> 48) & 0xff;
+            respdata[8] = (bt->lmp_caps >> 56) & 0xff;
+        } else
+            resp = 0;
+        break;
+
+    case LMP_NAME_REQ:
+        /* data[0]     Name offset
+         */
+        if (length < 1) {
+            error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
+            goto not_accepted;
+        }
+        resp = LMP_NAME_RES;
+        resplen = 17;
+        respdata[1] = data[0];
+        respdata[2] = strlen(bt->lmp_name);
+        memset(respdata + 3, 0x00, 14);
+        if (respdata[2] > respdata[1])
+            memcpy(respdata + 3, bt->lmp_name + respdata[1],
+                            respdata[2] - respdata[1]);
+        break;
+
+    case LMP_NAME_RES:
+        /* data[0]     Name offset
+         * data[1]     Name length
+         * data[2-15]  Name fragment
+         */
+        if (length < 16) {
+            error = HCI_UNSUPPORTED_LMP_PARAMETER_VALUE;
+            goto not_accepted;
+        }
+        resp = 0;
+        break;
+
+    default:
+        error = HCI_UNKNOWN_LMP_PDU;
+        /* Fall through */
+    not_accepted:
+        if (op >> 8) {
+            resp = LMP_NOT_ACCEPTED_EXT;
+            resplen = 5;
+            respdata[0] = op >> 8;
+            respdata[1] = op & 0xff;
+            respdata[2] = error;
+        } else {
+            resp = LMP_NOT_ACCEPTED;
+            resplen = 3;
+            respdata[0] = op & 0xff;
+            respdata[1] = error;
+        }
+    }
+
+    if (resp == 0)
+        return;
+
+    if (resp >> 8) {
+        respdata[0] = resp >> 8;
+        respdata[1] = resp & 0xff;
+    } else
+        respdata[0] = resp & 0xff;
+
+    respdata[0] <<= 1;
+    respdata[0] |= tr;
+}
+
+static void bt_submit_raw_acl(struct bt_piconet_s *net, int length, uint8_t *data)
+{
+    struct bt_device_s *slave;
+    if (length < 1)
+        return;
+
+    slave = 0;
+#if 0
+    slave = net->slave;
+#endif
+
+    switch (data[0] & 3) {
+    case LLID_ACLC:
+        bt_submit_lmp(slave, length - 1, data + 1);
+        break;
+    case LLID_ACLU_START:
+#if 0
+        bt_sumbit_l2cap(slave, length - 1, data + 1, (data[0] >> 2) & 1);
+        breka;
+#endif
+    default:
+    case LLID_ACLU_CONT:
+        break;
+    }
+}
+#endif
+
+/* HCI layer emulation */
+
+/* Note: we could ignore endiannes because unswapped handles will still
+ * be valid as connection identifiers for the guest - they don't have to
+ * be continuously allocated.  We do it though, to preserve similar
+ * behaviour between hosts.  Some things, like the BD_ADDR cannot be
+ * preserved though (for example if a real hci is used).  */
+#ifdef HOST_WORDS_BIGENDIAN
+# define HNDL(raw)     bswap16(raw)
+#else
+# define HNDL(raw)     (raw)
+#endif
+
+static const uint8_t bt_event_reserved_mask[8] = {
+    0xff, 0x9f, 0xfb, 0xff, 0x07, 0x18, 0x00, 0x00,
+};
+
+static inline uint8_t *bt_hci_event_start(struct bt_hci_s *hci,
+                int evt, int len)
+{
+    uint8_t *packet, mask;
+    int mask_byte;
+
+    if (len > 255) {
+        fprintf(stderr, "%s: HCI event params too long (%ib)\n",
+                        __FUNCTION__, len);
+        exit(-1);
+    }
+
+    mask_byte = (evt - 1) >> 3;
+    mask = 1 << ((evt - 1) & 3);
+    if (mask & bt_event_reserved_mask[mask_byte] & ~hci->event_mask[mask_byte])
+        return NULL;
+
+    packet = hci->evt_packet(hci->opaque);
+    packet[0] = evt;
+    packet[1] = len;
+
+    return &packet[2];
+}
+
+static inline void bt_hci_event(struct bt_hci_s *hci, int evt,
+                void *params, int len)
+{
+    uint8_t *packet = bt_hci_event_start(hci, evt, len);
+
+    if (!packet)
+        return;
+
+    if (len)
+        memcpy(packet, params, len);
+
+    hci->evt_submit(hci->opaque, len + 2);
+}
+
+static inline void bt_hci_event_status(struct bt_hci_s *hci, int status)
+{
+    evt_cmd_status params = {
+        .status        = status,
+        .ncmd  = 1,
+        .opcode        = hci->last_cmd,
+    };
+
+    bt_hci_event(hci, EVT_CMD_STATUS, &params, EVT_CMD_STATUS_SIZE);
+}
+
+static inline void bt_hci_event_complete(struct bt_hci_s *hci,
+                void *ret, int len)
+{
+    uint8_t *packet = bt_hci_event_start(hci, EVT_CMD_COMPLETE,
+                    len + EVT_CMD_COMPLETE_SIZE);
+    evt_cmd_complete *params = (evt_cmd_complete *) packet;
+
+    if (!packet)
+        return;
+
+    params->ncmd       = 1;
+    params->opcode     = hci->last_cmd;
+    if (len)
+        memcpy(&packet[EVT_CMD_COMPLETE_SIZE], ret, len);
+
+    hci->evt_submit(hci->opaque, len + EVT_CMD_COMPLETE_SIZE + 2);
+}
+
+static void bt_hci_inquiry_done(void *opaque)
+{
+    struct bt_hci_s *hci = (struct bt_hci_s *) opaque;
+    uint8_t status = HCI_SUCCESS;
+
+    if (!hci->lm.periodic)
+        hci->lm.inquire = 0;
+
+    /* The specification is inconsistent about this one.  Page 565 reads
+     * "The event parameters of Inquiry Complete event will have a summary
+     * of the result from the Inquiry process, which reports the number of
+     * nearby Bluetooth devices that responded [so hci->responses].", but
+     * Event Parameters (see page 729) has only Status.  */
+    bt_hci_event(hci, EVT_INQUIRY_COMPLETE, &status, 1);
+}
+
+static void bt_hci_inquiry_result_standard(struct bt_hci_s *hci,
+                struct bt_device_s *slave)
+{
+    inquiry_info params = {
+        .num_responses         = 1,
+        .bdaddr                        = BAINIT(&slave->bd_addr),
+        .pscan_rep_mode                = 0x00, /* R0 */
+        .pscan_period_mode     = 0x00, /* P0 - deprecated */
+        .pscan_mode            = 0x00, /* Standard scan - deprecated */
+        .dev_class[0]          = slave->class[0],
+        .dev_class[1]          = slave->class[1],
+        .dev_class[2]          = slave->class[2],
+        /* TODO: return the clkoff *differenece* */
+        .clock_offset          = slave->clkoff,        /* Note: no swapping */
+    };
+
+    bt_hci_event(hci, EVT_INQUIRY_RESULT, &params, INQUIRY_INFO_SIZE);
+}
+
+static void bt_hci_inquiry_result_with_rssi(struct bt_hci_s *hci,
+                struct bt_device_s *slave)
+{
+    inquiry_info_with_rssi params = {
+        .num_responses         = 1,
+        .bdaddr                        = BAINIT(&slave->bd_addr),
+        .pscan_rep_mode                = 0x00, /* R0 */
+        .pscan_period_mode     = 0x00, /* P0 - deprecated */
+        .dev_class[0]          = slave->class[0],
+        .dev_class[1]          = slave->class[1],
+        .dev_class[2]          = slave->class[2],
+        /* TODO: return the clkoff *differenece* */
+        .clock_offset          = slave->clkoff,        /* Note: no swapping */
+        .rssi                  = DEFAULT_RSSI_DBM,
+    };
+
+    bt_hci_event(hci, EVT_INQUIRY_RESULT_WITH_RSSI,
+                    &params, INQUIRY_INFO_WITH_RSSI_SIZE);
+}
+
+static void bt_hci_inquiry_result(struct bt_hci_s *hci,
+                struct bt_device_s *slave)
+{
+    if (!slave->inquiry_scan || !hci->lm.responses_left)
+        return;
+
+    hci->lm.responses_left --;
+    hci->lm.responses ++;
+
+    switch (hci->lm.inquiry_mode) {
+    case 0x00:
+        bt_hci_inquiry_result_standard(hci, slave);
+        return;
+    case 0x01:
+        bt_hci_inquiry_result_with_rssi(hci, slave);
+        return;
+    default:
+        fprintf(stderr, "%s: bad inquiry mode %02x\n", __FUNCTION__,
+                        hci->lm.inquiry_mode);
+        exit(-1);
+    }
+}
+
+static void bt_hci_mod_timer_1280ms(QEMUTimer *timer, int period)
+{
+    qemu_mod_timer(timer, qemu_get_clock_ns(vm_clock) +
+                   muldiv64(period << 7, get_ticks_per_sec(), 100));
+}
+
+static void bt_hci_inquiry_start(struct bt_hci_s *hci, int length)
+{
+    struct bt_device_s *slave;
+
+    hci->lm.inquiry_length = length;
+    for (slave = hci->device.net->slave; slave; slave = slave->next)
+        /* Don't uncover ourselves.  */
+        if (slave != &hci->device)
+            bt_hci_inquiry_result(hci, slave);
+
+    /* TODO: register for a callback on a new device's addition to the
+     * scatternet so that if it's added before inquiry_length expires,
+     * an Inquiry Result is generated immediately.  Alternatively re-loop
+     * through the devices on the inquiry_length expiration and report
+     * devices not seen before.  */
+    if (hci->lm.responses_left)
+        bt_hci_mod_timer_1280ms(hci->lm.inquiry_done, hci->lm.inquiry_length);
+    else
+        bt_hci_inquiry_done(hci);
+
+    if (hci->lm.periodic)
+        bt_hci_mod_timer_1280ms(hci->lm.inquiry_next, hci->lm.inquiry_period);
+}
+
+static void bt_hci_inquiry_next(void *opaque)
+{
+    struct bt_hci_s *hci = (struct bt_hci_s *) opaque;
+
+    hci->lm.responses_left += hci->lm.responses;
+    hci->lm.responses = 0;
+    bt_hci_inquiry_start(hci,  hci->lm.inquiry_length);
+}
+
+static inline int bt_hci_handle_bad(struct bt_hci_s *hci, uint16_t handle)
+{
+    return !(handle & HCI_HANDLE_OFFSET) ||
+            handle >= (HCI_HANDLE_OFFSET | HCI_HANDLES_MAX) ||
+            !hci->lm.handle[handle & ~HCI_HANDLE_OFFSET].link;
+}
+
+static inline int bt_hci_role_master(struct bt_hci_s *hci, uint16_t handle)
+{
+    return !!(hci->lm.role_bmp & (1 << (handle & ~HCI_HANDLE_OFFSET)));
+}
+
+static inline struct bt_device_s *bt_hci_remote_dev(struct bt_hci_s *hci,
+                uint16_t handle)
+{
+    struct bt_link_s *link = hci->lm.handle[handle & ~HCI_HANDLE_OFFSET].link;
+
+    return bt_hci_role_master(hci, handle) ? link->slave : link->host;
+}
+
+static void bt_hci_mode_tick(void *opaque);
+static void bt_hci_lmp_link_establish(struct bt_hci_s *hci,
+                struct bt_link_s *link, int master)
+{
+    hci->lm.handle[hci->lm.last_handle].link = link;
+
+    if (master) {
+        /* We are the master side of an ACL link */
+        hci->lm.role_bmp |= 1 << hci->lm.last_handle;
+
+        hci->lm.handle[hci->lm.last_handle].lmp_acl_data =
+                link->slave->lmp_acl_data;
+    } else {
+        /* We are the slave side of an ACL link */
+        hci->lm.role_bmp &= ~(1 << hci->lm.last_handle);
+
+        hci->lm.handle[hci->lm.last_handle].lmp_acl_data =
+                link->host->lmp_acl_resp;
+    }
+
+    /* Mode */
+    if (master) {
+        link->acl_mode = acl_active;
+        hci->lm.handle[hci->lm.last_handle].acl_mode_timer =
+                qemu_new_timer_ns(vm_clock, bt_hci_mode_tick, link);
+    }
+}
+
+static void bt_hci_lmp_link_teardown(struct bt_hci_s *hci, uint16_t handle)
+{
+    handle &= ~HCI_HANDLE_OFFSET;
+    hci->lm.handle[handle].link = NULL;
+
+    if (bt_hci_role_master(hci, handle)) {
+        qemu_del_timer(hci->lm.handle[handle].acl_mode_timer);
+        qemu_free_timer(hci->lm.handle[handle].acl_mode_timer);
+    }
+}
+
+static int bt_hci_connect(struct bt_hci_s *hci, bdaddr_t *bdaddr)
+{
+    struct bt_device_s *slave;
+    struct bt_link_s link;
+
+    for (slave = hci->device.net->slave; slave; slave = slave->next)
+        if (slave->page_scan && !bacmp(&slave->bd_addr, bdaddr))
+            break;
+    if (!slave || slave == &hci->device)
+        return -ENODEV;
+
+    bacpy(&hci->lm.awaiting_bdaddr[hci->lm.connecting ++], &slave->bd_addr);
+
+    link.slave = slave;
+    link.host = &hci->device;
+    link.slave->lmp_connection_request(&link); /* Always last */
+
+    return 0;
+}
+
+static void bt_hci_connection_reject(struct bt_hci_s *hci,
+                struct bt_device_s *host, uint8_t because)
+{
+    struct bt_link_s link = {
+        .slave = &hci->device,
+        .host  = host,
+        /* Rest uninitialised */
+    };
+
+    host->reject_reason = because;
+    host->lmp_connection_complete(&link);
+}
+
+static void bt_hci_connection_reject_event(struct bt_hci_s *hci,
+                bdaddr_t *bdaddr)
+{
+    evt_conn_complete params;
+
+    params.status      = HCI_NO_CONNECTION;
+    params.handle      = 0;
+    bacpy(&params.bdaddr, bdaddr);
+    params.link_type   = ACL_LINK;
+    params.encr_mode   = 0x00;         /* Encryption not required */
+    bt_hci_event(hci, EVT_CONN_COMPLETE, &params, EVT_CONN_COMPLETE_SIZE);
+}
+
+static void bt_hci_connection_accept(struct bt_hci_s *hci,
+                struct bt_device_s *host)
+{
+    struct bt_hci_link_s *link = g_malloc0(sizeof(struct bt_hci_link_s));
+    evt_conn_complete params;
+    uint16_t handle;
+    uint8_t status = HCI_SUCCESS;
+    int tries = HCI_HANDLES_MAX;
+
+    /* Make a connection handle */
+    do {
+        while (hci->lm.handle[++ hci->lm.last_handle].link && -- tries)
+            hci->lm.last_handle &= HCI_HANDLES_MAX - 1;
+        handle = hci->lm.last_handle | HCI_HANDLE_OFFSET;
+    } while ((handle == hci->asb_handle || handle == hci->psb_handle) &&
+            tries);
+
+    if (!tries) {
+        g_free(link);
+        bt_hci_connection_reject(hci, host, HCI_REJECTED_LIMITED_RESOURCES);
+        status = HCI_NO_CONNECTION;
+        goto complete;
+    }
+
+    link->btlink.slave = &hci->device;
+    link->btlink.host  = host;
+    link->handle = handle;
+
+    /* Link established */
+    bt_hci_lmp_link_establish(hci, &link->btlink, 0);
+
+complete:
+    params.status      = status;
+    params.handle      = HNDL(handle);
+    bacpy(&params.bdaddr, &host->bd_addr);
+    params.link_type   = ACL_LINK;
+    params.encr_mode   = 0x00;         /* Encryption not required */
+    bt_hci_event(hci, EVT_CONN_COMPLETE, &params, EVT_CONN_COMPLETE_SIZE);
+
+    /* Neets to be done at the very end because it can trigger a (nested)
+     * disconnected, in case the other and had cancelled the request
+     * locally.  */
+    if (status == HCI_SUCCESS) {
+        host->reject_reason = 0;
+        host->lmp_connection_complete(&link->btlink);
+    }
+}
+
+static void bt_hci_lmp_connection_request(struct bt_link_s *link)
+{
+    struct bt_hci_s *hci = hci_from_device(link->slave);
+    evt_conn_request params;
+
+    if (hci->conn_req_host) {
+        bt_hci_connection_reject(hci, link->host,
+                                 HCI_REJECTED_LIMITED_RESOURCES);
+        return;
+    }
+    hci->conn_req_host = link->host;
+    /* TODO: if masked and auto-accept, then auto-accept,
+     * if masked and not auto-accept, then auto-reject */
+    /* TODO: kick the hci->conn_accept_timer, timeout after
+     * hci->conn_accept_tout * 0.625 msec */
+
+    bacpy(&params.bdaddr, &link->host->bd_addr);
+    memcpy(&params.dev_class, &link->host->class, sizeof(params.dev_class));
+    params.link_type   = ACL_LINK;
+    bt_hci_event(hci, EVT_CONN_REQUEST, &params, EVT_CONN_REQUEST_SIZE);
+}
+
+static void bt_hci_conn_accept_timeout(void *opaque)
+{
+    struct bt_hci_s *hci = (struct bt_hci_s *) opaque;
+
+    if (!hci->conn_req_host)
+        /* Already accepted or rejected.  If the other end cancelled the
+         * connection request then we still have to reject or accept it
+         * and then we'll get a disconnect.  */
+        return;
+
+    /* TODO */
+}
+
+/* Remove from the list of devices which we wanted to connect to and
+ * are awaiting a response from.  If the callback sees a response from
+ * a device which is not on the list it will assume it's a connection
+ * that's been cancelled by the host in the meantime and immediately
+ * try to detach the link and send a Connection Complete.  */
+static int bt_hci_lmp_connection_ready(struct bt_hci_s *hci,
+                bdaddr_t *bdaddr)
+{
+    int i;
+
+    for (i = 0; i < hci->lm.connecting; i ++)
+        if (!bacmp(&hci->lm.awaiting_bdaddr[i], bdaddr)) {
+            if (i < -- hci->lm.connecting)
+                bacpy(&hci->lm.awaiting_bdaddr[i],
+                                &hci->lm.awaiting_bdaddr[hci->lm.connecting]);
+            return 0;
+        }
+
+    return 1;
+}
+
+static void bt_hci_lmp_connection_complete(struct bt_link_s *link)
+{
+    struct bt_hci_s *hci = hci_from_device(link->host);
+    evt_conn_complete params;
+    uint16_t handle;
+    uint8_t status = HCI_SUCCESS;
+    int tries = HCI_HANDLES_MAX;
+
+    if (bt_hci_lmp_connection_ready(hci, &link->slave->bd_addr)) {
+        if (!hci->device.reject_reason)
+            link->slave->lmp_disconnect_slave(link);
+        handle = 0;
+        status = HCI_NO_CONNECTION;
+        goto complete;
+    }
+
+    if (hci->device.reject_reason) {
+        handle = 0;
+        status = hci->device.reject_reason;
+        goto complete;
+    }
+
+    /* Make a connection handle */
+    do {
+        while (hci->lm.handle[++ hci->lm.last_handle].link && -- tries)
+            hci->lm.last_handle &= HCI_HANDLES_MAX - 1;
+        handle = hci->lm.last_handle | HCI_HANDLE_OFFSET;
+    } while ((handle == hci->asb_handle || handle == hci->psb_handle) &&
+            tries);
+
+    if (!tries) {
+        link->slave->lmp_disconnect_slave(link);
+        status = HCI_NO_CONNECTION;
+        goto complete;
+    }
+
+    /* Link established */
+    link->handle = handle;
+    bt_hci_lmp_link_establish(hci, link, 1);
+
+complete:
+    params.status      = status;
+    params.handle      = HNDL(handle);
+    params.link_type   = ACL_LINK;
+    bacpy(&params.bdaddr, &link->slave->bd_addr);
+    params.encr_mode   = 0x00;         /* Encryption not required */
+    bt_hci_event(hci, EVT_CONN_COMPLETE, &params, EVT_CONN_COMPLETE_SIZE);
+}
+
+static void bt_hci_disconnect(struct bt_hci_s *hci,
+                uint16_t handle, int reason)
+{
+    struct bt_link_s *btlink =
+            hci->lm.handle[handle & ~HCI_HANDLE_OFFSET].link;
+    struct bt_hci_link_s *link;
+    evt_disconn_complete params;
+
+    if (bt_hci_role_master(hci, handle)) {
+        btlink->slave->reject_reason = reason;
+        btlink->slave->lmp_disconnect_slave(btlink);
+        /* The link pointer is invalid from now on */
+
+        goto complete;
+    }
+
+    btlink->host->reject_reason = reason;
+    btlink->host->lmp_disconnect_master(btlink);
+
+    /* We are the slave, we get to clean this burden */
+    link = (struct bt_hci_link_s *) btlink;
+    g_free(link);
+
+complete:
+    bt_hci_lmp_link_teardown(hci, handle);
+
+    params.status      = HCI_SUCCESS;
+    params.handle      = HNDL(handle);
+    params.reason      = HCI_CONNECTION_TERMINATED;
+    bt_hci_event(hci, EVT_DISCONN_COMPLETE,
+                    &params, EVT_DISCONN_COMPLETE_SIZE);
+}
+
+/* TODO: use only one function */
+static void bt_hci_lmp_disconnect_host(struct bt_link_s *link)
+{
+    struct bt_hci_s *hci = hci_from_device(link->host);
+    uint16_t handle = link->handle;
+    evt_disconn_complete params;
+
+    bt_hci_lmp_link_teardown(hci, handle);
+
+    params.status      = HCI_SUCCESS;
+    params.handle      = HNDL(handle);
+    params.reason      = hci->device.reject_reason;
+    bt_hci_event(hci, EVT_DISCONN_COMPLETE,
+                    &params, EVT_DISCONN_COMPLETE_SIZE);
+}
+
+static void bt_hci_lmp_disconnect_slave(struct bt_link_s *btlink)
+{
+    struct bt_hci_link_s *link = (struct bt_hci_link_s *) btlink;
+    struct bt_hci_s *hci = hci_from_device(btlink->slave);
+    uint16_t handle = link->handle;
+    evt_disconn_complete params;
+
+    g_free(link);
+
+    bt_hci_lmp_link_teardown(hci, handle);
+
+    params.status      = HCI_SUCCESS;
+    params.handle      = HNDL(handle);
+    params.reason      = hci->device.reject_reason;
+    bt_hci_event(hci, EVT_DISCONN_COMPLETE,
+                    &params, EVT_DISCONN_COMPLETE_SIZE);
+}
+
+static int bt_hci_name_req(struct bt_hci_s *hci, bdaddr_t *bdaddr)
+{
+    struct bt_device_s *slave;
+    evt_remote_name_req_complete params;
+
+    for (slave = hci->device.net->slave; slave; slave = slave->next)
+        if (slave->page_scan && !bacmp(&slave->bd_addr, bdaddr))
+            break;
+    if (!slave)
+        return -ENODEV;
+
+    bt_hci_event_status(hci, HCI_SUCCESS);
+
+    params.status       = HCI_SUCCESS;
+    bacpy(&params.bdaddr, &slave->bd_addr);
+    pstrcpy(params.name, sizeof(params.name), slave->lmp_name ?: "");
+    bt_hci_event(hci, EVT_REMOTE_NAME_REQ_COMPLETE,
+                    &params, EVT_REMOTE_NAME_REQ_COMPLETE_SIZE);
+
+    return 0;
+}
+
+static int bt_hci_features_req(struct bt_hci_s *hci, uint16_t handle)
+{
+    struct bt_device_s *slave;
+    evt_read_remote_features_complete params;
+
+    if (bt_hci_handle_bad(hci, handle))
+        return -ENODEV;
+
+    slave = bt_hci_remote_dev(hci, handle);
+
+    bt_hci_event_status(hci, HCI_SUCCESS);
+
+    params.status      = HCI_SUCCESS;
+    params.handle      = HNDL(handle);
+    params.features[0] = (slave->lmp_caps >>  0) & 0xff;
+    params.features[1] = (slave->lmp_caps >>  8) & 0xff;
+    params.features[2] = (slave->lmp_caps >> 16) & 0xff;
+    params.features[3] = (slave->lmp_caps >> 24) & 0xff;
+    params.features[4] = (slave->lmp_caps >> 32) & 0xff;
+    params.features[5] = (slave->lmp_caps >> 40) & 0xff;
+    params.features[6] = (slave->lmp_caps >> 48) & 0xff;
+    params.features[7] = (slave->lmp_caps >> 56) & 0xff;
+    bt_hci_event(hci, EVT_READ_REMOTE_FEATURES_COMPLETE,
+                    &params, EVT_READ_REMOTE_FEATURES_COMPLETE_SIZE);
+
+    return 0;
+}
+
+static int bt_hci_version_req(struct bt_hci_s *hci, uint16_t handle)
+{
+    evt_read_remote_version_complete params;
+
+    if (bt_hci_handle_bad(hci, handle))
+        return -ENODEV;
+
+    bt_hci_remote_dev(hci, handle);
+
+    bt_hci_event_status(hci, HCI_SUCCESS);
+
+    params.status      = HCI_SUCCESS;
+    params.handle      = HNDL(handle);
+    params.lmp_ver     = 0x03;
+    params.manufacturer        = cpu_to_le16(0xa000);
+    params.lmp_subver  = cpu_to_le16(0xa607);
+    bt_hci_event(hci, EVT_READ_REMOTE_VERSION_COMPLETE,
+                    &params, EVT_READ_REMOTE_VERSION_COMPLETE_SIZE);
+
+    return 0;
+}
+
+static int bt_hci_clkoffset_req(struct bt_hci_s *hci, uint16_t handle)
+{
+    struct bt_device_s *slave;
+    evt_read_clock_offset_complete params;
+
+    if (bt_hci_handle_bad(hci, handle))
+        return -ENODEV;
+
+    slave = bt_hci_remote_dev(hci, handle);
+
+    bt_hci_event_status(hci, HCI_SUCCESS);
+
+    params.status      = HCI_SUCCESS;
+    params.handle      = HNDL(handle);
+    /* TODO: return the clkoff *differenece* */
+    params.clock_offset        = slave->clkoff;        /* Note: no swapping */
+    bt_hci_event(hci, EVT_READ_CLOCK_OFFSET_COMPLETE,
+                    &params, EVT_READ_CLOCK_OFFSET_COMPLETE_SIZE);
+
+    return 0;
+}
+
+static void bt_hci_event_mode(struct bt_hci_s *hci, struct bt_link_s *link,
+                uint16_t handle)
+{
+    evt_mode_change params = {
+        .status                = HCI_SUCCESS,
+        .handle                = HNDL(handle),
+        .mode          = link->acl_mode,
+        .interval      = cpu_to_le16(link->acl_interval),
+    };
+
+    bt_hci_event(hci, EVT_MODE_CHANGE, &params, EVT_MODE_CHANGE_SIZE);
+}
+
+static void bt_hci_lmp_mode_change_master(struct bt_hci_s *hci,
+                struct bt_link_s *link, int mode, uint16_t interval)
+{
+    link->acl_mode = mode;
+    link->acl_interval = interval;
+
+    bt_hci_event_mode(hci, link, link->handle);
+
+    link->slave->lmp_mode_change(link);
+}
+
+static void bt_hci_lmp_mode_change_slave(struct bt_link_s *btlink)
+{
+    struct bt_hci_link_s *link = (struct bt_hci_link_s *) btlink;
+    struct bt_hci_s *hci = hci_from_device(btlink->slave);
+
+    bt_hci_event_mode(hci, btlink, link->handle);
+}
+
+static int bt_hci_mode_change(struct bt_hci_s *hci, uint16_t handle,
+                int interval, int mode)
+{
+    struct bt_hci_master_link_s *link;
+
+    if (bt_hci_handle_bad(hci, handle) || !bt_hci_role_master(hci, handle))
+        return -ENODEV;
+
+    link = &hci->lm.handle[handle & ~HCI_HANDLE_OFFSET];
+    if (link->link->acl_mode != acl_active) {
+        bt_hci_event_status(hci, HCI_COMMAND_DISALLOWED);
+        return 0;
+    }
+
+    bt_hci_event_status(hci, HCI_SUCCESS);
+
+    qemu_mod_timer(link->acl_mode_timer, qemu_get_clock_ns(vm_clock) +
+                   muldiv64(interval * 625, get_ticks_per_sec(), 1000000));
+    bt_hci_lmp_mode_change_master(hci, link->link, mode, interval);
+
+    return 0;
+}
+
+static int bt_hci_mode_cancel(struct bt_hci_s *hci, uint16_t handle, int mode)
+{
+    struct bt_hci_master_link_s *link;
+
+    if (bt_hci_handle_bad(hci, handle) || !bt_hci_role_master(hci, handle))
+        return -ENODEV;
+
+    link = &hci->lm.handle[handle & ~HCI_HANDLE_OFFSET];
+    if (link->link->acl_mode != mode) {
+        bt_hci_event_status(hci, HCI_COMMAND_DISALLOWED);
+
+        return 0;
+    }
+
+    bt_hci_event_status(hci, HCI_SUCCESS);
+
+    qemu_del_timer(link->acl_mode_timer);
+    bt_hci_lmp_mode_change_master(hci, link->link, acl_active, 0);
+
+    return 0;
+}
+
+static void bt_hci_mode_tick(void *opaque)
+{
+    struct bt_link_s *link = opaque;
+    struct bt_hci_s *hci = hci_from_device(link->host);
+
+    bt_hci_lmp_mode_change_master(hci, link, acl_active, 0);
+}
+
+static void bt_hci_reset(struct bt_hci_s *hci)
+{
+    hci->acl_len = 0;
+    hci->last_cmd = 0;
+    hci->lm.connecting = 0;
+
+    hci->event_mask[0] = 0xff;
+    hci->event_mask[1] = 0xff;
+    hci->event_mask[2] = 0xff;
+    hci->event_mask[3] = 0xff;
+    hci->event_mask[4] = 0xff;
+    hci->event_mask[5] = 0x1f;
+    hci->event_mask[6] = 0x00;
+    hci->event_mask[7] = 0x00;
+    hci->device.inquiry_scan = 0;
+    hci->device.page_scan = 0;
+    if (hci->device.lmp_name)
+        g_free((void *) hci->device.lmp_name);
+    hci->device.lmp_name = NULL;
+    hci->device.class[0] = 0x00;
+    hci->device.class[1] = 0x00;
+    hci->device.class[2] = 0x00;
+    hci->voice_setting = 0x0000;
+    hci->conn_accept_tout = 0x1f40;
+    hci->lm.inquiry_mode = 0x00;
+
+    hci->psb_handle = 0x000;
+    hci->asb_handle = 0x000;
+
+    /* XXX: qemu_del_timer(sl->acl_mode_timer); for all links */
+    qemu_del_timer(hci->lm.inquiry_done);
+    qemu_del_timer(hci->lm.inquiry_next);
+    qemu_del_timer(hci->conn_accept_timer);
+}
+
+static void bt_hci_read_local_version_rp(struct bt_hci_s *hci)
+{
+    read_local_version_rp lv = {
+        .status                = HCI_SUCCESS,
+        .hci_ver       = 0x03,
+        .hci_rev       = cpu_to_le16(0xa607),
+        .lmp_ver       = 0x03,
+        .manufacturer  = cpu_to_le16(0xa000),
+        .lmp_subver    = cpu_to_le16(0xa607),
+    };
+
+    bt_hci_event_complete(hci, &lv, READ_LOCAL_VERSION_RP_SIZE);
+}
+
+static void bt_hci_read_local_commands_rp(struct bt_hci_s *hci)
+{
+    read_local_commands_rp lc = {
+        .status                = HCI_SUCCESS,
+        .commands      = {
+            /* Keep updated! */
+            /* Also, keep in sync with hci->device.lmp_caps in bt_new_hci */
+            0xbf, 0x80, 0xf9, 0x03, 0xb2, 0xc0, 0x03, 0xc3,
+            0x00, 0x0f, 0x80, 0x00, 0xc0, 0x00, 0xe8, 0x13,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        },
+    };
+
+    bt_hci_event_complete(hci, &lc, READ_LOCAL_COMMANDS_RP_SIZE);
+}
+
+static void bt_hci_read_local_features_rp(struct bt_hci_s *hci)
+{
+    read_local_features_rp lf = {
+        .status                = HCI_SUCCESS,
+        .features      = {
+            (hci->device.lmp_caps >>  0) & 0xff,
+            (hci->device.lmp_caps >>  8) & 0xff,
+            (hci->device.lmp_caps >> 16) & 0xff,
+            (hci->device.lmp_caps >> 24) & 0xff,
+            (hci->device.lmp_caps >> 32) & 0xff,
+            (hci->device.lmp_caps >> 40) & 0xff,
+            (hci->device.lmp_caps >> 48) & 0xff,
+            (hci->device.lmp_caps >> 56) & 0xff,
+        },
+    };
+
+    bt_hci_event_complete(hci, &lf, READ_LOCAL_FEATURES_RP_SIZE);
+}
+
+static void bt_hci_read_local_ext_features_rp(struct bt_hci_s *hci, int page)
+{
+    read_local_ext_features_rp lef = {
+        .status                = HCI_SUCCESS,
+        .page_num      = page,
+        .max_page_num  = 0x00,
+        .features      = {
+            /* Keep updated! */
+            0x5f, 0x35, 0x85, 0x7e, 0x9b, 0x19, 0x00, 0x80,
+        },
+    };
+    if (page)
+        memset(lef.features, 0, sizeof(lef.features));
+
+    bt_hci_event_complete(hci, &lef, READ_LOCAL_EXT_FEATURES_RP_SIZE);
+}
+
+static void bt_hci_read_buffer_size_rp(struct bt_hci_s *hci)
+{
+    read_buffer_size_rp bs = {
+        /* This can be made configurable, for one standard USB dongle HCI
+         * the four values are cpu_to_le16(0x0180), 0x40,
+         * cpu_to_le16(0x0008), cpu_to_le16(0x0008).  */
+        .status                = HCI_SUCCESS,
+        .acl_mtu       = cpu_to_le16(0x0200),
+        .sco_mtu       = 0,
+        .acl_max_pkt   = cpu_to_le16(0x0001),
+        .sco_max_pkt   = cpu_to_le16(0x0000),
+    };
+
+    bt_hci_event_complete(hci, &bs, READ_BUFFER_SIZE_RP_SIZE);
+}
+
+/* Deprecated in V2.0 (page 661) */
+static void bt_hci_read_country_code_rp(struct bt_hci_s *hci)
+{
+    read_country_code_rp cc ={
+        .status                = HCI_SUCCESS,
+        .country_code  = 0x00, /* North America & Europe^1 and Japan */
+    };
+
+    bt_hci_event_complete(hci, &cc, READ_COUNTRY_CODE_RP_SIZE);
+
+    /* ^1. Except France, sorry */
+}
+
+static void bt_hci_read_bd_addr_rp(struct bt_hci_s *hci)
+{
+    read_bd_addr_rp ba = {
+        .status = HCI_SUCCESS,
+        .bdaddr = BAINIT(&hci->device.bd_addr),
+    };
+
+    bt_hci_event_complete(hci, &ba, READ_BD_ADDR_RP_SIZE);
+}
+
+static int bt_hci_link_quality_rp(struct bt_hci_s *hci, uint16_t handle)
+{
+    read_link_quality_rp lq = {
+        .status                = HCI_SUCCESS,
+        .handle                = HNDL(handle),
+        .link_quality  = 0xff,
+    };
+
+    if (bt_hci_handle_bad(hci, handle))
+        lq.status = HCI_NO_CONNECTION;
+
+    bt_hci_event_complete(hci, &lq, READ_LINK_QUALITY_RP_SIZE);
+    return 0;
+}
+
+/* Generate a Command Complete event with only the Status parameter */
+static inline void bt_hci_event_complete_status(struct bt_hci_s *hci,
+                uint8_t status)
+{
+    bt_hci_event_complete(hci, &status, 1);
+}
+
+static inline void bt_hci_event_complete_conn_cancel(struct bt_hci_s *hci,
+                uint8_t status, bdaddr_t *bd_addr)
+{
+    create_conn_cancel_rp params = {
+        .status = status,
+        .bdaddr = BAINIT(bd_addr),
+    };
+
+    bt_hci_event_complete(hci, &params, CREATE_CONN_CANCEL_RP_SIZE);
+}
+
+static inline void bt_hci_event_auth_complete(struct bt_hci_s *hci,
+                uint16_t handle)
+{
+    evt_auth_complete params = {
+        .status = HCI_SUCCESS,
+        .handle = HNDL(handle),
+    };
+
+    bt_hci_event(hci, EVT_AUTH_COMPLETE, &params, EVT_AUTH_COMPLETE_SIZE);
+}
+
+static inline void bt_hci_event_encrypt_change(struct bt_hci_s *hci,
+                uint16_t handle, uint8_t mode)
+{
+    evt_encrypt_change params = {
+        .status                = HCI_SUCCESS,
+        .handle                = HNDL(handle),
+        .encrypt       = mode,
+    };
+
+    bt_hci_event(hci, EVT_ENCRYPT_CHANGE, &params, EVT_ENCRYPT_CHANGE_SIZE);
+}
+
+static inline void bt_hci_event_complete_name_cancel(struct bt_hci_s *hci,
+                bdaddr_t *bd_addr)
+{
+    remote_name_req_cancel_rp params = {
+        .status = HCI_INVALID_PARAMETERS,
+        .bdaddr = BAINIT(bd_addr),
+    };
+
+    bt_hci_event_complete(hci, &params, REMOTE_NAME_REQ_CANCEL_RP_SIZE);
+}
+
+static inline void bt_hci_event_read_remote_ext_features(struct bt_hci_s *hci,
+                uint16_t handle)
+{
+    evt_read_remote_ext_features_complete params = {
+        .status = HCI_UNSUPPORTED_FEATURE,
+        .handle = HNDL(handle),
+        /* Rest uninitialised */
+    };
+
+    bt_hci_event(hci, EVT_READ_REMOTE_EXT_FEATURES_COMPLETE,
+                    &params, EVT_READ_REMOTE_EXT_FEATURES_COMPLETE_SIZE);
+}
+
+static inline void bt_hci_event_complete_lmp_handle(struct bt_hci_s *hci,
+                uint16_t handle)
+{
+    read_lmp_handle_rp params = {
+        .status                = HCI_NO_CONNECTION,
+        .handle                = HNDL(handle),
+        .reserved      = 0,
+        /* Rest uninitialised */
+    };
+
+    bt_hci_event_complete(hci, &params, READ_LMP_HANDLE_RP_SIZE);
+}
+
+static inline void bt_hci_event_complete_role_discovery(struct bt_hci_s *hci,
+                int status, uint16_t handle, int master)
+{
+    role_discovery_rp params = {
+        .status                = status,
+        .handle                = HNDL(handle),
+        .role          = master ? 0x00 : 0x01,
+    };
+
+    bt_hci_event_complete(hci, &params, ROLE_DISCOVERY_RP_SIZE);
+}
+
+static inline void bt_hci_event_complete_flush(struct bt_hci_s *hci,
+                int status, uint16_t handle)
+{
+    flush_rp params = {
+        .status                = status,
+        .handle                = HNDL(handle),
+    };
+
+    bt_hci_event_complete(hci, &params, FLUSH_RP_SIZE);
+}
+
+static inline void bt_hci_event_complete_read_local_name(struct bt_hci_s *hci)
+{
+    read_local_name_rp params;
+    params.status = HCI_SUCCESS;
+    memset(params.name, 0, sizeof(params.name));
+    if (hci->device.lmp_name)
+        pstrcpy(params.name, sizeof(params.name), hci->device.lmp_name);
+
+    bt_hci_event_complete(hci, &params, READ_LOCAL_NAME_RP_SIZE);
+}
+
+static inline void bt_hci_event_complete_read_conn_accept_timeout(
+                struct bt_hci_s *hci)
+{
+    read_conn_accept_timeout_rp params = {
+        .status                = HCI_SUCCESS,
+        .timeout       = cpu_to_le16(hci->conn_accept_tout),
+    };
+
+    bt_hci_event_complete(hci, &params, READ_CONN_ACCEPT_TIMEOUT_RP_SIZE);
+}
+
+static inline void bt_hci_event_complete_read_scan_enable(struct bt_hci_s *hci)
+{
+    read_scan_enable_rp params = {
+        .status = HCI_SUCCESS,
+        .enable =
+                (hci->device.inquiry_scan ? SCAN_INQUIRY : 0) |
+                (hci->device.page_scan ? SCAN_PAGE : 0),
+    };
+
+    bt_hci_event_complete(hci, &params, READ_SCAN_ENABLE_RP_SIZE);
+}
+
+static inline void bt_hci_event_complete_read_local_class(struct bt_hci_s *hci)
+{
+    read_class_of_dev_rp params;
+
+    params.status = HCI_SUCCESS;
+    memcpy(params.dev_class, hci->device.class, sizeof(params.dev_class));
+
+    bt_hci_event_complete(hci, &params, READ_CLASS_OF_DEV_RP_SIZE);
+}
+
+static inline void bt_hci_event_complete_voice_setting(struct bt_hci_s *hci)
+{
+    read_voice_setting_rp params = {
+        .status                = HCI_SUCCESS,
+        .voice_setting = hci->voice_setting,   /* Note: no swapping */
+    };
+
+    bt_hci_event_complete(hci, &params, READ_VOICE_SETTING_RP_SIZE);
+}
+
+static inline void bt_hci_event_complete_read_inquiry_mode(
+                struct bt_hci_s *hci)
+{
+    read_inquiry_mode_rp params = {
+        .status                = HCI_SUCCESS,
+        .mode          = hci->lm.inquiry_mode,
+    };
+
+    bt_hci_event_complete(hci, &params, READ_INQUIRY_MODE_RP_SIZE);
+}
+
+static inline void bt_hci_event_num_comp_pkts(struct bt_hci_s *hci,
+                uint16_t handle, int packets)
+{
+    uint16_t buf[EVT_NUM_COMP_PKTS_SIZE(1) / 2 + 1];
+    evt_num_comp_pkts *params = (void *) ((uint8_t *) buf + 1);
+
+    params->num_hndl                   = 1;
+    params->connection->handle         = HNDL(handle);
+    params->connection->num_packets    = cpu_to_le16(packets);
+
+    bt_hci_event(hci, EVT_NUM_COMP_PKTS, params, EVT_NUM_COMP_PKTS_SIZE(1));
+}
+
+static void bt_submit_hci(struct HCIInfo *info,
+                const uint8_t *data, int length)
+{
+    struct bt_hci_s *hci = hci_from_info(info);
+    uint16_t cmd;
+    int paramlen, i;
+
+    if (length < HCI_COMMAND_HDR_SIZE)
+        goto short_hci;
+
+    memcpy(&hci->last_cmd, data, 2);
+
+    cmd = (data[1] << 8) | data[0];
+    paramlen = data[2];
+    if (cmd_opcode_ogf(cmd) == 0 || cmd_opcode_ocf(cmd) == 0)  /* NOP */
+        return;
+
+    data += HCI_COMMAND_HDR_SIZE;
+    length -= HCI_COMMAND_HDR_SIZE;
+
+    if (paramlen > length)
+        return;
+
+#define PARAM(cmd, param)      (((cmd##_cp *) data)->param)
+#define PARAM16(cmd, param)    le16_to_cpup(&PARAM(cmd, param))
+#define PARAMHANDLE(cmd)       HNDL(PARAM(cmd, handle))
+#define LENGTH_CHECK(cmd)      if (length < sizeof(cmd##_cp)) goto short_hci
+    /* Note: the supported commands bitmask in bt_hci_read_local_commands_rp
+     * needs to be updated every time a command is implemented here!  */
+    switch (cmd) {
+    case cmd_opcode_pack(OGF_LINK_CTL, OCF_INQUIRY):
+        LENGTH_CHECK(inquiry);
+
+        if (PARAM(inquiry, length) < 1) {
+            bt_hci_event_complete_status(hci, HCI_INVALID_PARAMETERS);
+            break;
+        }
+
+        hci->lm.inquire = 1;
+        hci->lm.periodic = 0;
+        hci->lm.responses_left = PARAM(inquiry, num_rsp) ?: INT_MAX;
+        hci->lm.responses = 0;
+        bt_hci_event_status(hci, HCI_SUCCESS);
+        bt_hci_inquiry_start(hci, PARAM(inquiry, length));
+        break;
+
+    case cmd_opcode_pack(OGF_LINK_CTL, OCF_INQUIRY_CANCEL):
+        if (!hci->lm.inquire || hci->lm.periodic) {
+            fprintf(stderr, "%s: Inquiry Cancel should only be issued after "
+                            "the Inquiry command has been issued, a Command "
+                            "Status event has been received for the Inquiry "
+                            "command, and before the Inquiry Complete event "
+                            "occurs", __FUNCTION__);
+            bt_hci_event_complete_status(hci, HCI_COMMAND_DISALLOWED);
+            break;
+        }
+
+        hci->lm.inquire = 0;
+        qemu_del_timer(hci->lm.inquiry_done);
+        bt_hci_event_complete_status(hci, HCI_SUCCESS);
+        break;
+
+    case cmd_opcode_pack(OGF_LINK_CTL, OCF_PERIODIC_INQUIRY):
+        LENGTH_CHECK(periodic_inquiry);
+
+        if (!(PARAM(periodic_inquiry, length) <
+                                PARAM16(periodic_inquiry, min_period) &&
+                                PARAM16(periodic_inquiry, min_period) <
+                                PARAM16(periodic_inquiry, max_period)) ||
+                        PARAM(periodic_inquiry, length) < 1 ||
+                        PARAM16(periodic_inquiry, min_period) < 2 ||
+                        PARAM16(periodic_inquiry, max_period) < 3) {
+            bt_hci_event_complete_status(hci, HCI_INVALID_PARAMETERS);
+            break;
+        }
+
+        hci->lm.inquire = 1;
+        hci->lm.periodic = 1;
+        hci->lm.responses_left = PARAM(periodic_inquiry, num_rsp);
+        hci->lm.responses = 0;
+        hci->lm.inquiry_period = PARAM16(periodic_inquiry, max_period);
+        bt_hci_event_complete_status(hci, HCI_SUCCESS);
+        bt_hci_inquiry_start(hci, PARAM(periodic_inquiry, length));
+        break;
+
+    case cmd_opcode_pack(OGF_LINK_CTL, OCF_EXIT_PERIODIC_INQUIRY):
+        if (!hci->lm.inquire || !hci->lm.periodic) {
+            fprintf(stderr, "%s: Inquiry Cancel should only be issued after "
+                            "the Inquiry command has been issued, a Command "
+                            "Status event has been received for the Inquiry "
+                            "command, and before the Inquiry Complete event "
+                            "occurs", __FUNCTION__);
+            bt_hci_event_complete_status(hci, HCI_COMMAND_DISALLOWED);
+            break;
+        }
+        hci->lm.inquire = 0;
+        qemu_del_timer(hci->lm.inquiry_done);
+        qemu_del_timer(hci->lm.inquiry_next);
+        bt_hci_event_complete_status(hci, HCI_SUCCESS);
+        break;
+
+    case cmd_opcode_pack(OGF_LINK_CTL, OCF_CREATE_CONN):
+        LENGTH_CHECK(create_conn);
+
+        if (hci->lm.connecting >= HCI_HANDLES_MAX) {
+            bt_hci_event_status(hci, HCI_REJECTED_LIMITED_RESOURCES);
+            break;
+        }
+        bt_hci_event_status(hci, HCI_SUCCESS);
+
+        if (bt_hci_connect(hci, &PARAM(create_conn, bdaddr)))
+            bt_hci_connection_reject_event(hci, &PARAM(create_conn, bdaddr));
+        break;
+
+    case cmd_opcode_pack(OGF_LINK_CTL, OCF_DISCONNECT):
+        LENGTH_CHECK(disconnect);
+
+        if (bt_hci_handle_bad(hci, PARAMHANDLE(disconnect))) {
+            bt_hci_event_status(hci, HCI_NO_CONNECTION);
+            break;
+        }
+
+        bt_hci_event_status(hci, HCI_SUCCESS);
+        bt_hci_disconnect(hci, PARAMHANDLE(disconnect),
+                        PARAM(disconnect, reason));
+        break;
+
+    case cmd_opcode_pack(OGF_LINK_CTL, OCF_CREATE_CONN_CANCEL):
+        LENGTH_CHECK(create_conn_cancel);
+
+        if (bt_hci_lmp_connection_ready(hci,
+                                &PARAM(create_conn_cancel, bdaddr))) {
+            for (i = 0; i < HCI_HANDLES_MAX; i ++)
+                if (bt_hci_role_master(hci, i) && hci->lm.handle[i].link &&
+                                !bacmp(&hci->lm.handle[i].link->slave->bd_addr,
+                                        &PARAM(create_conn_cancel, bdaddr)))
+                   break;
+
+            bt_hci_event_complete_conn_cancel(hci, i < HCI_HANDLES_MAX ?
+                            HCI_ACL_CONNECTION_EXISTS : HCI_NO_CONNECTION,
+                            &PARAM(create_conn_cancel, bdaddr));
+        } else
+            bt_hci_event_complete_conn_cancel(hci, HCI_SUCCESS,
+                            &PARAM(create_conn_cancel, bdaddr));
+        break;
+
+    case cmd_opcode_pack(OGF_LINK_CTL, OCF_ACCEPT_CONN_REQ):
+        LENGTH_CHECK(accept_conn_req);
+
+        if (!hci->conn_req_host ||
+                        bacmp(&PARAM(accept_conn_req, bdaddr),
+                                &hci->conn_req_host->bd_addr)) {
+            bt_hci_event_status(hci, HCI_INVALID_PARAMETERS);
+            break;
+        }
+
+        bt_hci_event_status(hci, HCI_SUCCESS);
+        bt_hci_connection_accept(hci, hci->conn_req_host);
+        hci->conn_req_host = NULL;
+        break;
+
+    case cmd_opcode_pack(OGF_LINK_CTL, OCF_REJECT_CONN_REQ):
+        LENGTH_CHECK(reject_conn_req);
+
+        if (!hci->conn_req_host ||
+                        bacmp(&PARAM(reject_conn_req, bdaddr),
+                                &hci->conn_req_host->bd_addr)) {
+            bt_hci_event_status(hci, HCI_INVALID_PARAMETERS);
+            break;
+        }
+
+        bt_hci_event_status(hci, HCI_SUCCESS);
+        bt_hci_connection_reject(hci, hci->conn_req_host,
+                        PARAM(reject_conn_req, reason));
+        bt_hci_connection_reject_event(hci, &hci->conn_req_host->bd_addr);
+        hci->conn_req_host = NULL;
+        break;
+
+    case cmd_opcode_pack(OGF_LINK_CTL, OCF_AUTH_REQUESTED):
+        LENGTH_CHECK(auth_requested);
+
+        if (bt_hci_handle_bad(hci, PARAMHANDLE(auth_requested)))
+            bt_hci_event_status(hci, HCI_NO_CONNECTION);
+        else {
+            bt_hci_event_status(hci, HCI_SUCCESS);
+            bt_hci_event_auth_complete(hci, PARAMHANDLE(auth_requested));
+        }
+        break;
+
+    case cmd_opcode_pack(OGF_LINK_CTL, OCF_SET_CONN_ENCRYPT):
+        LENGTH_CHECK(set_conn_encrypt);
+
+        if (bt_hci_handle_bad(hci, PARAMHANDLE(set_conn_encrypt)))
+            bt_hci_event_status(hci, HCI_NO_CONNECTION);
+        else {
+            bt_hci_event_status(hci, HCI_SUCCESS);
+            bt_hci_event_encrypt_change(hci,
+                            PARAMHANDLE(set_conn_encrypt),
+                            PARAM(set_conn_encrypt, encrypt));
+        }
+        break;
+
+    case cmd_opcode_pack(OGF_LINK_CTL, OCF_REMOTE_NAME_REQ):
+        LENGTH_CHECK(remote_name_req);
+
+        if (bt_hci_name_req(hci, &PARAM(remote_name_req, bdaddr)))
+            bt_hci_event_status(hci, HCI_NO_CONNECTION);
+        break;
+
+    case cmd_opcode_pack(OGF_LINK_CTL, OCF_REMOTE_NAME_REQ_CANCEL):
+        LENGTH_CHECK(remote_name_req_cancel);
+
+        bt_hci_event_complete_name_cancel(hci,
+                        &PARAM(remote_name_req_cancel, bdaddr));
+        break;
+
+    case cmd_opcode_pack(OGF_LINK_CTL, OCF_READ_REMOTE_FEATURES):
+        LENGTH_CHECK(read_remote_features);
+
+        if (bt_hci_features_req(hci, PARAMHANDLE(read_remote_features)))
+            bt_hci_event_status(hci, HCI_NO_CONNECTION);
+        break;
+
+    case cmd_opcode_pack(OGF_LINK_CTL, OCF_READ_REMOTE_EXT_FEATURES):
+        LENGTH_CHECK(read_remote_ext_features);
+
+        if (bt_hci_handle_bad(hci, PARAMHANDLE(read_remote_ext_features)))
+            bt_hci_event_status(hci, HCI_NO_CONNECTION);
+        else {
+            bt_hci_event_status(hci, HCI_SUCCESS);
+            bt_hci_event_read_remote_ext_features(hci,
+                            PARAMHANDLE(read_remote_ext_features));
+        }
+        break;
+
+    case cmd_opcode_pack(OGF_LINK_CTL, OCF_READ_REMOTE_VERSION):
+        LENGTH_CHECK(read_remote_version);
+
+        if (bt_hci_version_req(hci, PARAMHANDLE(read_remote_version)))
+            bt_hci_event_status(hci, HCI_NO_CONNECTION);
+        break;
+
+    case cmd_opcode_pack(OGF_LINK_CTL, OCF_READ_CLOCK_OFFSET):
+        LENGTH_CHECK(read_clock_offset);
+
+        if (bt_hci_clkoffset_req(hci, PARAMHANDLE(read_clock_offset)))
+            bt_hci_event_status(hci, HCI_NO_CONNECTION);
+        break;
+
+    case cmd_opcode_pack(OGF_LINK_CTL, OCF_READ_LMP_HANDLE):
+        LENGTH_CHECK(read_lmp_handle);
+
+        /* TODO: */
+        bt_hci_event_complete_lmp_handle(hci, PARAMHANDLE(read_lmp_handle));
+        break;
+
+    case cmd_opcode_pack(OGF_LINK_POLICY, OCF_HOLD_MODE):
+        LENGTH_CHECK(hold_mode);
+
+        if (PARAM16(hold_mode, min_interval) >
+                        PARAM16(hold_mode, max_interval) ||
+                        PARAM16(hold_mode, min_interval) < 0x0002 ||
+                        PARAM16(hold_mode, max_interval) > 0xff00 ||
+                        (PARAM16(hold_mode, min_interval) & 1) ||
+                        (PARAM16(hold_mode, max_interval) & 1)) {
+            bt_hci_event_status(hci, HCI_INVALID_PARAMETERS);
+            break;
+        }
+
+        if (bt_hci_mode_change(hci, PARAMHANDLE(hold_mode),
+                                PARAM16(hold_mode, max_interval),
+                                acl_hold))
+            bt_hci_event_status(hci, HCI_NO_CONNECTION);
+        break;
+
+    case cmd_opcode_pack(OGF_LINK_POLICY, OCF_PARK_MODE):
+        LENGTH_CHECK(park_mode);
+
+        if (PARAM16(park_mode, min_interval) >
+                        PARAM16(park_mode, max_interval) ||
+                        PARAM16(park_mode, min_interval) < 0x000e ||
+                        (PARAM16(park_mode, min_interval) & 1) ||
+                        (PARAM16(park_mode, max_interval) & 1)) {
+            bt_hci_event_status(hci, HCI_INVALID_PARAMETERS);
+            break;
+        }
+
+        if (bt_hci_mode_change(hci, PARAMHANDLE(park_mode),
+                                PARAM16(park_mode, max_interval),
+                                acl_parked))
+            bt_hci_event_status(hci, HCI_NO_CONNECTION);
+        break;
+
+    case cmd_opcode_pack(OGF_LINK_POLICY, OCF_EXIT_PARK_MODE):
+        LENGTH_CHECK(exit_park_mode);
+
+        if (bt_hci_mode_cancel(hci, PARAMHANDLE(exit_park_mode),
+                                acl_parked))
+            bt_hci_event_status(hci, HCI_NO_CONNECTION);
+        break;
+
+    case cmd_opcode_pack(OGF_LINK_POLICY, OCF_ROLE_DISCOVERY):
+        LENGTH_CHECK(role_discovery);
+
+        if (bt_hci_handle_bad(hci, PARAMHANDLE(role_discovery)))
+            bt_hci_event_complete_role_discovery(hci,
+                            HCI_NO_CONNECTION, PARAMHANDLE(role_discovery), 0);
+        else
+            bt_hci_event_complete_role_discovery(hci,
+                            HCI_SUCCESS, PARAMHANDLE(role_discovery),
+                            bt_hci_role_master(hci,
+                                    PARAMHANDLE(role_discovery)));
+        break;
+
+    case cmd_opcode_pack(OGF_HOST_CTL, OCF_SET_EVENT_MASK):
+        LENGTH_CHECK(set_event_mask);
+
+        memcpy(hci->event_mask, PARAM(set_event_mask, mask), 8);
+        bt_hci_event_complete_status(hci, HCI_SUCCESS);
+        break;
+
+    case cmd_opcode_pack(OGF_HOST_CTL, OCF_RESET):
+        bt_hci_reset(hci);
+        bt_hci_event_status(hci, HCI_SUCCESS);
+        break;
+
+    case cmd_opcode_pack(OGF_HOST_CTL, OCF_SET_EVENT_FLT):
+        if (length >= 1 && PARAM(set_event_flt, flt_type) == FLT_CLEAR_ALL)
+            /* No length check */;
+        else
+            LENGTH_CHECK(set_event_flt);
+
+        /* Filters are not implemented */
+        bt_hci_event_complete_status(hci, HCI_SUCCESS);
+        break;
+
+    case cmd_opcode_pack(OGF_HOST_CTL, OCF_FLUSH):
+        LENGTH_CHECK(flush);
+
+        if (bt_hci_handle_bad(hci, PARAMHANDLE(flush)))
+            bt_hci_event_complete_flush(hci,
+                            HCI_NO_CONNECTION, PARAMHANDLE(flush));
+        else {
+            /* TODO: ordering? */
+            bt_hci_event(hci, EVT_FLUSH_OCCURRED,
+                            &PARAM(flush, handle),
+                            EVT_FLUSH_OCCURRED_SIZE);
+            bt_hci_event_complete_flush(hci,
+                            HCI_SUCCESS, PARAMHANDLE(flush));
+        }
+        break;
+
+    case cmd_opcode_pack(OGF_HOST_CTL, OCF_CHANGE_LOCAL_NAME):
+        LENGTH_CHECK(change_local_name);
+
+        if (hci->device.lmp_name)
+            g_free((void *) hci->device.lmp_name);
+        hci->device.lmp_name = g_strndup(PARAM(change_local_name, name),
+                        sizeof(PARAM(change_local_name, name)));
+        bt_hci_event_complete_status(hci, HCI_SUCCESS);
+        break;
+
+    case cmd_opcode_pack(OGF_HOST_CTL, OCF_READ_LOCAL_NAME):
+        bt_hci_event_complete_read_local_name(hci);
+        break;
+
+    case cmd_opcode_pack(OGF_HOST_CTL, OCF_READ_CONN_ACCEPT_TIMEOUT):
+        bt_hci_event_complete_read_conn_accept_timeout(hci);
+        break;
+
+    case cmd_opcode_pack(OGF_HOST_CTL, OCF_WRITE_CONN_ACCEPT_TIMEOUT):
+        /* TODO */
+        LENGTH_CHECK(write_conn_accept_timeout);
+
+        if (PARAM16(write_conn_accept_timeout, timeout) < 0x0001 ||
+                        PARAM16(write_conn_accept_timeout, timeout) > 0xb540) {
+            bt_hci_event_complete_status(hci, HCI_INVALID_PARAMETERS);
+            break;
+        }
+
+        hci->conn_accept_tout = PARAM16(write_conn_accept_timeout, timeout);
+        bt_hci_event_complete_status(hci, HCI_SUCCESS);
+        break;
+
+    case cmd_opcode_pack(OGF_HOST_CTL, OCF_READ_SCAN_ENABLE):
+        bt_hci_event_complete_read_scan_enable(hci);
+        break;
+
+    case cmd_opcode_pack(OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE):
+        LENGTH_CHECK(write_scan_enable);
+
+        /* TODO: check that the remaining bits are all 0 */
+        hci->device.inquiry_scan =
+                !!(PARAM(write_scan_enable, scan_enable) & SCAN_INQUIRY);
+        hci->device.page_scan =
+                !!(PARAM(write_scan_enable, scan_enable) & SCAN_PAGE);
+        bt_hci_event_complete_status(hci, HCI_SUCCESS);
+        break;
+
+    case cmd_opcode_pack(OGF_HOST_CTL, OCF_READ_CLASS_OF_DEV):
+        bt_hci_event_complete_read_local_class(hci);
+        break;
+
+    case cmd_opcode_pack(OGF_HOST_CTL, OCF_WRITE_CLASS_OF_DEV):
+        LENGTH_CHECK(write_class_of_dev);
+
+        memcpy(hci->device.class, PARAM(write_class_of_dev, dev_class),
+                        sizeof(PARAM(write_class_of_dev, dev_class)));
+        bt_hci_event_complete_status(hci, HCI_SUCCESS);
+        break;
+
+    case cmd_opcode_pack(OGF_HOST_CTL, OCF_READ_VOICE_SETTING):
+        bt_hci_event_complete_voice_setting(hci);
+        break;
+
+    case cmd_opcode_pack(OGF_HOST_CTL, OCF_WRITE_VOICE_SETTING):
+        LENGTH_CHECK(write_voice_setting);
+
+        hci->voice_setting = PARAM(write_voice_setting, voice_setting);
+        bt_hci_event_complete_status(hci, HCI_SUCCESS);
+        break;
+
+    case cmd_opcode_pack(OGF_HOST_CTL, OCF_HOST_NUMBER_OF_COMPLETED_PACKETS):
+        if (length < data[0] * 2 + 1)
+            goto short_hci;
+
+        for (i = 0; i < data[0]; i ++)
+            if (bt_hci_handle_bad(hci,
+                                    data[i * 2 + 1] | (data[i * 2 + 2] << 8)))
+                bt_hci_event_complete_status(hci, HCI_INVALID_PARAMETERS);
+        break;
+
+    case cmd_opcode_pack(OGF_HOST_CTL, OCF_READ_INQUIRY_MODE):
+        /* Only if (local_features[3] & 0x40) && (local_commands[12] & 0x40)
+         * else
+         *     goto unknown_command */
+        bt_hci_event_complete_read_inquiry_mode(hci);
+        break;
+
+    case cmd_opcode_pack(OGF_HOST_CTL, OCF_WRITE_INQUIRY_MODE):
+        /* Only if (local_features[3] & 0x40) && (local_commands[12] & 0x80)
+         * else
+         *     goto unknown_command */
+        LENGTH_CHECK(write_inquiry_mode);
+
+        if (PARAM(write_inquiry_mode, mode) > 0x01) {
+            bt_hci_event_complete_status(hci, HCI_INVALID_PARAMETERS);
+            break;
+        }
+
+        hci->lm.inquiry_mode = PARAM(write_inquiry_mode, mode);
+        bt_hci_event_complete_status(hci, HCI_SUCCESS);
+        break;
+
+    case cmd_opcode_pack(OGF_INFO_PARAM, OCF_READ_LOCAL_VERSION):
+        bt_hci_read_local_version_rp(hci);
+        break;
+
+    case cmd_opcode_pack(OGF_INFO_PARAM, OCF_READ_LOCAL_COMMANDS):
+        bt_hci_read_local_commands_rp(hci);
+        break;
+
+    case cmd_opcode_pack(OGF_INFO_PARAM, OCF_READ_LOCAL_FEATURES):
+        bt_hci_read_local_features_rp(hci);
+        break;
+
+    case cmd_opcode_pack(OGF_INFO_PARAM, OCF_READ_LOCAL_EXT_FEATURES):
+        LENGTH_CHECK(read_local_ext_features);
+
+        bt_hci_read_local_ext_features_rp(hci,
+                        PARAM(read_local_ext_features, page_num));
+        break;
+
+    case cmd_opcode_pack(OGF_INFO_PARAM, OCF_READ_BUFFER_SIZE):
+        bt_hci_read_buffer_size_rp(hci);
+        break;
+
+    case cmd_opcode_pack(OGF_INFO_PARAM, OCF_READ_COUNTRY_CODE):
+        bt_hci_read_country_code_rp(hci);
+        break;
+
+    case cmd_opcode_pack(OGF_INFO_PARAM, OCF_READ_BD_ADDR):
+        bt_hci_read_bd_addr_rp(hci);
+        break;
+
+    case cmd_opcode_pack(OGF_STATUS_PARAM, OCF_READ_LINK_QUALITY):
+        LENGTH_CHECK(read_link_quality);
+
+        bt_hci_link_quality_rp(hci, PARAMHANDLE(read_link_quality));
+        break;
+
+    default:
+        bt_hci_event_status(hci, HCI_UNKNOWN_COMMAND);
+        break;
+
+    short_hci:
+        fprintf(stderr, "%s: HCI packet too short (%iB)\n",
+                        __FUNCTION__, length);
+        bt_hci_event_status(hci, HCI_INVALID_PARAMETERS);
+        break;
+    }
+}
+
+/* We could perform fragmentation here, we can't do "recombination" because
+ * at this layer the length of the payload is not know ahead, so we only
+ * know that a packet contained the last fragment of the SDU when the next
+ * SDU starts.  */
+static inline void bt_hci_lmp_acl_data(struct bt_hci_s *hci, uint16_t handle,
+                const uint8_t *data, int start, int len)
+{
+    struct hci_acl_hdr *pkt = (void *) hci->acl_buf;
+
+    /* TODO: packet flags */
+    /* TODO: avoid memcpy'ing */
+
+    if (len + HCI_ACL_HDR_SIZE > sizeof(hci->acl_buf)) {
+        fprintf(stderr, "%s: can't take ACL packets %i bytes long\n",
+                        __FUNCTION__, len);
+        return;
+    }
+    memcpy(hci->acl_buf + HCI_ACL_HDR_SIZE, data, len);
+
+    pkt->handle = cpu_to_le16(
+                    acl_handle_pack(handle, start ? ACL_START : ACL_CONT));
+    pkt->dlen = cpu_to_le16(len);
+    hci->info.acl_recv(hci->info.opaque,
+                    hci->acl_buf, len + HCI_ACL_HDR_SIZE);
+}
+
+static void bt_hci_lmp_acl_data_slave(struct bt_link_s *btlink,
+                const uint8_t *data, int start, int len)
+{
+    struct bt_hci_link_s *link = (struct bt_hci_link_s *) btlink;
+
+    bt_hci_lmp_acl_data(hci_from_device(btlink->slave),
+                    link->handle, data, start, len);
+}
+
+static void bt_hci_lmp_acl_data_host(struct bt_link_s *link,
+                const uint8_t *data, int start, int len)
+{
+    bt_hci_lmp_acl_data(hci_from_device(link->host),
+                    link->handle, data, start, len);
+}
+
+static void bt_submit_acl(struct HCIInfo *info,
+                const uint8_t *data, int length)
+{
+    struct bt_hci_s *hci = hci_from_info(info);
+    uint16_t handle;
+    int datalen, flags;
+    struct bt_link_s *link;
+
+    if (length < HCI_ACL_HDR_SIZE) {
+        fprintf(stderr, "%s: ACL packet too short (%iB)\n",
+                        __FUNCTION__, length);
+        return;
+    }
+
+    handle = acl_handle((data[1] << 8) | data[0]);
+    flags = acl_flags((data[1] << 8) | data[0]);
+    datalen = (data[3] << 8) | data[2];
+    data += HCI_ACL_HDR_SIZE;
+    length -= HCI_ACL_HDR_SIZE;
+
+    if (bt_hci_handle_bad(hci, handle)) {
+        fprintf(stderr, "%s: invalid ACL handle %03x\n",
+                        __FUNCTION__, handle);
+        /* TODO: signal an error */
+        return;
+    }
+    handle &= ~HCI_HANDLE_OFFSET;
+
+    if (datalen > length) {
+        fprintf(stderr, "%s: ACL packet too short (%iB < %iB)\n",
+                        __FUNCTION__, length, datalen);
+        return;
+    }
+
+    link = hci->lm.handle[handle].link;
+
+    if ((flags & ~3) == ACL_ACTIVE_BCAST) {
+        if (!hci->asb_handle)
+            hci->asb_handle = handle;
+        else if (handle != hci->asb_handle) {
+            fprintf(stderr, "%s: Bad handle %03x in Active Slave Broadcast\n",
+                            __FUNCTION__, handle);
+            /* TODO: signal an error */
+            return;
+        }
+
+        /* TODO */
+    }
+
+    if ((flags & ~3) == ACL_PICO_BCAST) {
+        if (!hci->psb_handle)
+            hci->psb_handle = handle;
+        else if (handle != hci->psb_handle) {
+            fprintf(stderr, "%s: Bad handle %03x in Parked Slave Broadcast\n",
+                            __FUNCTION__, handle);
+            /* TODO: signal an error */
+            return;
+        }
+
+        /* TODO */
+    }
+
+    /* TODO: increase counter and send EVT_NUM_COMP_PKTS */
+    bt_hci_event_num_comp_pkts(hci, handle | HCI_HANDLE_OFFSET, 1);
+
+    /* Do this last as it can trigger further events even in this HCI */
+    hci->lm.handle[handle].lmp_acl_data(link, data,
+                    (flags & 3) == ACL_START, length);
+}
+
+static void bt_submit_sco(struct HCIInfo *info,
+                const uint8_t *data, int length)
+{
+    struct bt_hci_s *hci = hci_from_info(info);
+    uint16_t handle;
+    int datalen;
+
+    if (length < 3)
+        return;
+
+    handle = acl_handle((data[1] << 8) | data[0]);
+    datalen = data[2];
+    length -= 3;
+
+    if (bt_hci_handle_bad(hci, handle)) {
+        fprintf(stderr, "%s: invalid SCO handle %03x\n",
+                        __FUNCTION__, handle);
+        return;
+    }
+
+    if (datalen > length) {
+        fprintf(stderr, "%s: SCO packet too short (%iB < %iB)\n",
+                        __FUNCTION__, length, datalen);
+        return;
+    }
+
+    /* TODO */
+
+    /* TODO: increase counter and send EVT_NUM_COMP_PKTS if synchronous
+     * Flow Control is enabled.
+     * (See Read/Write_Synchronous_Flow_Control_Enable on page 513 and
+     * page 514.)  */
+}
+
+static uint8_t *bt_hci_evt_packet(void *opaque)
+{
+    /* TODO: allocate a packet from upper layer */
+    struct bt_hci_s *s = opaque;
+
+    return s->evt_buf;
+}
+
+static void bt_hci_evt_submit(void *opaque, int len)
+{
+    /* TODO: notify upper layer */
+    struct bt_hci_s *s = opaque;
+
+    s->info.evt_recv(s->info.opaque, s->evt_buf, len);
+}
+
+static int bt_hci_bdaddr_set(struct HCIInfo *info, const uint8_t *bd_addr)
+{
+    struct bt_hci_s *hci = hci_from_info(info);
+
+    bacpy(&hci->device.bd_addr, (const bdaddr_t *) bd_addr);
+    return 0;
+}
+
+static void bt_hci_done(struct HCIInfo *info);
+static void bt_hci_destroy(struct bt_device_s *dev)
+{
+    struct bt_hci_s *hci = hci_from_device(dev);
+
+    bt_hci_done(&hci->info);
+}
+
+struct HCIInfo *bt_new_hci(struct bt_scatternet_s *net)
+{
+    struct bt_hci_s *s = g_malloc0(sizeof(struct bt_hci_s));
+
+    s->lm.inquiry_done = qemu_new_timer_ns(vm_clock, bt_hci_inquiry_done, s);
+    s->lm.inquiry_next = qemu_new_timer_ns(vm_clock, bt_hci_inquiry_next, s);
+    s->conn_accept_timer =
+            qemu_new_timer_ns(vm_clock, bt_hci_conn_accept_timeout, s);
+
+    s->evt_packet = bt_hci_evt_packet;
+    s->evt_submit = bt_hci_evt_submit;
+    s->opaque = s;
+
+    bt_device_init(&s->device, net);
+    s->device.lmp_connection_request = bt_hci_lmp_connection_request;
+    s->device.lmp_connection_complete = bt_hci_lmp_connection_complete;
+    s->device.lmp_disconnect_master = bt_hci_lmp_disconnect_host;
+    s->device.lmp_disconnect_slave = bt_hci_lmp_disconnect_slave;
+    s->device.lmp_acl_data = bt_hci_lmp_acl_data_slave;
+    s->device.lmp_acl_resp = bt_hci_lmp_acl_data_host;
+    s->device.lmp_mode_change = bt_hci_lmp_mode_change_slave;
+
+    /* Keep updated! */
+    /* Also keep in sync with supported commands bitmask in
+     * bt_hci_read_local_commands_rp */
+    s->device.lmp_caps = 0x8000199b7e85355fll;
+
+    bt_hci_reset(s);
+
+    s->info.cmd_send = bt_submit_hci;
+    s->info.sco_send = bt_submit_sco;
+    s->info.acl_send = bt_submit_acl;
+    s->info.bdaddr_set = bt_hci_bdaddr_set;
+
+    s->device.handle_destroy = bt_hci_destroy;
+
+    return &s->info;
+}
+
+static void bt_hci_done(struct HCIInfo *info)
+{
+    struct bt_hci_s *hci = hci_from_info(info);
+    int handle;
+
+    bt_device_done(&hci->device);
+
+    if (hci->device.lmp_name)
+        g_free((void *) hci->device.lmp_name);
+
+    /* Be gentle and send DISCONNECT to all connected peers and those
+     * currently waiting for us to accept or reject a connection request.
+     * This frees the links.  */
+    if (hci->conn_req_host) {
+        bt_hci_connection_reject(hci,
+                                 hci->conn_req_host, HCI_OE_POWER_OFF);
+        return;
+    }
+
+    for (handle = HCI_HANDLE_OFFSET;
+                    handle < (HCI_HANDLE_OFFSET | HCI_HANDLES_MAX); handle ++)
+        if (!bt_hci_handle_bad(hci, handle))
+            bt_hci_disconnect(hci, handle, HCI_OE_POWER_OFF);
+
+    /* TODO: this is not enough actually, there may be slaves from whom
+     * we have requested a connection who will soon (or not) respond with
+     * an accept or a reject, so we should also check if hci->lm.connecting
+     * is non-zero and if so, avoid freeing the hci but otherwise disappear
+     * from all qemu social life (e.g. stop scanning and request to be
+     * removed from s->device.net) and arrange for
+     * s->device.lmp_connection_complete to free the remaining bits once
+     * hci->lm.awaiting_bdaddr[] is empty.  */
+
+    qemu_free_timer(hci->lm.inquiry_done);
+    qemu_free_timer(hci->lm.inquiry_next);
+    qemu_free_timer(hci->conn_accept_timer);
+
+    g_free(hci);
+}
diff --git a/hw/bt/hid.c b/hw/bt/hid.c
new file mode 100644 (file)
index 0000000..af494e1
--- /dev/null
@@ -0,0 +1,553 @@
+/*
+ * QEMU Bluetooth HID Profile wrapper for USB HID.
+ *
+ * Copyright (C) 2007-2008 OpenMoko, Inc.
+ * Written by Andrzej Zaborowski <andrew@openedhand.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 or
+ * (at your option) version 3 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
+ * 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, if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu-common.h"
+#include "qemu/timer.h"
+#include "ui/console.h"
+#include "hw/input/hid.h"
+#include "hw/bt.h"
+
+enum hid_transaction_req {
+    BT_HANDSHAKE                       = 0x0,
+    BT_HID_CONTROL                     = 0x1,
+    BT_GET_REPORT                      = 0x4,
+    BT_SET_REPORT                      = 0x5,
+    BT_GET_PROTOCOL                    = 0x6,
+    BT_SET_PROTOCOL                    = 0x7,
+    BT_GET_IDLE                                = 0x8,
+    BT_SET_IDLE                                = 0x9,
+    BT_DATA                            = 0xa,
+    BT_DATC                            = 0xb,
+};
+
+enum hid_transaction_handshake {
+    BT_HS_SUCCESSFUL                   = 0x0,
+    BT_HS_NOT_READY                    = 0x1,
+    BT_HS_ERR_INVALID_REPORT_ID                = 0x2,
+    BT_HS_ERR_UNSUPPORTED_REQUEST      = 0x3,
+    BT_HS_ERR_INVALID_PARAMETER                = 0x4,
+    BT_HS_ERR_UNKNOWN                  = 0xe,
+    BT_HS_ERR_FATAL                    = 0xf,
+};
+
+enum hid_transaction_control {
+    BT_HC_NOP                          = 0x0,
+    BT_HC_HARD_RESET                   = 0x1,
+    BT_HC_SOFT_RESET                   = 0x2,
+    BT_HC_SUSPEND                      = 0x3,
+    BT_HC_EXIT_SUSPEND                 = 0x4,
+    BT_HC_VIRTUAL_CABLE_UNPLUG         = 0x5,
+};
+
+enum hid_protocol {
+    BT_HID_PROTO_BOOT                  = 0,
+    BT_HID_PROTO_REPORT                        = 1,
+};
+
+enum hid_boot_reportid {
+    BT_HID_BOOT_INVALID                        = 0,
+    BT_HID_BOOT_KEYBOARD,
+    BT_HID_BOOT_MOUSE,
+};
+
+enum hid_data_pkt {
+    BT_DATA_OTHER                      = 0,
+    BT_DATA_INPUT,
+    BT_DATA_OUTPUT,
+    BT_DATA_FEATURE,
+};
+
+#define BT_HID_MTU                     48
+
+/* HID interface requests */
+#define GET_REPORT                     0xa101
+#define GET_IDLE                       0xa102
+#define GET_PROTOCOL                   0xa103
+#define SET_REPORT                     0x2109
+#define SET_IDLE                       0x210a
+#define SET_PROTOCOL                   0x210b
+
+struct bt_hid_device_s {
+    struct bt_l2cap_device_s btdev;
+    struct bt_l2cap_conn_params_s *control;
+    struct bt_l2cap_conn_params_s *interrupt;
+    HIDState hid;
+
+    int proto;
+    int connected;
+    int data_type;
+    int intr_state;
+    struct {
+        int len;
+        uint8_t buffer[1024];
+    } dataother, datain, dataout, feature, intrdataout;
+    enum {
+        bt_state_ready,
+        bt_state_transaction,
+        bt_state_suspend,
+    } state;
+};
+
+static void bt_hid_reset(struct bt_hid_device_s *s)
+{
+    struct bt_scatternet_s *net = s->btdev.device.net;
+
+    /* Go as far as... */
+    bt_l2cap_device_done(&s->btdev);
+    bt_l2cap_device_init(&s->btdev, net);
+
+    hid_reset(&s->hid);
+    s->proto = BT_HID_PROTO_REPORT;
+    s->state = bt_state_ready;
+    s->dataother.len = 0;
+    s->datain.len = 0;
+    s->dataout.len = 0;
+    s->feature.len = 0;
+    s->intrdataout.len = 0;
+    s->intr_state = 0;
+}
+
+static int bt_hid_out(struct bt_hid_device_s *s)
+{
+    if (s->data_type == BT_DATA_OUTPUT) {
+        /* nothing */
+        ;
+    }
+
+    if (s->data_type == BT_DATA_FEATURE) {
+        /* XXX:
+         * does this send a USB_REQ_CLEAR_FEATURE/USB_REQ_SET_FEATURE
+         * or a SET_REPORT? */
+        ;
+    }
+
+    return -1;
+}
+
+static int bt_hid_in(struct bt_hid_device_s *s)
+{
+    s->datain.len = hid_keyboard_poll(&s->hid, s->datain.buffer,
+                                      sizeof(s->datain.buffer));
+    return s->datain.len;
+}
+
+static void bt_hid_send_handshake(struct bt_hid_device_s *s, int result)
+{
+    *s->control->sdu_out(s->control, 1) =
+            (BT_HANDSHAKE << 4) | result;
+    s->control->sdu_submit(s->control);
+}
+
+static void bt_hid_send_control(struct bt_hid_device_s *s, int operation)
+{
+    *s->control->sdu_out(s->control, 1) =
+            (BT_HID_CONTROL << 4) | operation;
+    s->control->sdu_submit(s->control);
+}
+
+static void bt_hid_disconnect(struct bt_hid_device_s *s)
+{
+    /* Disconnect s->control and s->interrupt */
+}
+
+static void bt_hid_send_data(struct bt_l2cap_conn_params_s *ch, int type,
+                const uint8_t *data, int len)
+{
+    uint8_t *pkt, hdr = (BT_DATA << 4) | type;
+    int plen;
+
+    do {
+        plen = MIN(len, ch->remote_mtu - 1);
+        pkt = ch->sdu_out(ch, plen + 1);
+
+        pkt[0] = hdr;
+        if (plen)
+            memcpy(pkt + 1, data, plen);
+        ch->sdu_submit(ch);
+
+        len -= plen;
+        data += plen;
+        hdr = (BT_DATC << 4) | type;
+    } while (plen == ch->remote_mtu - 1);
+}
+
+static void bt_hid_control_transaction(struct bt_hid_device_s *s,
+                const uint8_t *data, int len)
+{
+    uint8_t type, parameter;
+    int rlen, ret = -1;
+    if (len < 1)
+        return;
+
+    type = data[0] >> 4;
+    parameter = data[0] & 0xf;
+
+    switch (type) {
+    case BT_HANDSHAKE:
+    case BT_DATA:
+        switch (parameter) {
+        default:
+            /* These are not expected to be sent this direction.  */
+            ret = BT_HS_ERR_INVALID_PARAMETER;
+        }
+        break;
+
+    case BT_HID_CONTROL:
+        if (len != 1 || (parameter != BT_HC_VIRTUAL_CABLE_UNPLUG &&
+                                s->state == bt_state_transaction)) {
+            ret = BT_HS_ERR_INVALID_PARAMETER;
+            break;
+        }
+        switch (parameter) {
+        case BT_HC_NOP:
+            break;
+        case BT_HC_HARD_RESET:
+        case BT_HC_SOFT_RESET:
+            bt_hid_reset(s);
+            break;
+        case BT_HC_SUSPEND:
+            if (s->state == bt_state_ready)
+                s->state = bt_state_suspend;
+            else
+                ret = BT_HS_ERR_INVALID_PARAMETER;
+            break;
+        case BT_HC_EXIT_SUSPEND:
+            if (s->state == bt_state_suspend)
+                s->state = bt_state_ready;
+            else
+                ret = BT_HS_ERR_INVALID_PARAMETER;
+            break;
+        case BT_HC_VIRTUAL_CABLE_UNPLUG:
+            bt_hid_disconnect(s);
+            break;
+        default:
+            ret = BT_HS_ERR_INVALID_PARAMETER;
+        }
+        break;
+
+    case BT_GET_REPORT:
+        /* No ReportIDs declared.  */
+        if (((parameter & 8) && len != 3) ||
+                        (!(parameter & 8) && len != 1) ||
+                        s->state != bt_state_ready) {
+            ret = BT_HS_ERR_INVALID_PARAMETER;
+            break;
+        }
+        if (parameter & 8)
+            rlen = data[2] | (data[3] << 8);
+        else
+            rlen = INT_MAX;
+        switch (parameter & 3) {
+        case BT_DATA_OTHER:
+            ret = BT_HS_ERR_INVALID_PARAMETER;
+            break;
+        case BT_DATA_INPUT:
+            /* Here we can as well poll s->usbdev */
+            bt_hid_send_data(s->control, BT_DATA_INPUT,
+                            s->datain.buffer, MIN(rlen, s->datain.len));
+            break;
+        case BT_DATA_OUTPUT:
+            bt_hid_send_data(s->control, BT_DATA_OUTPUT,
+                            s->dataout.buffer, MIN(rlen, s->dataout.len));
+            break;
+        case BT_DATA_FEATURE:
+            bt_hid_send_data(s->control, BT_DATA_FEATURE,
+                            s->feature.buffer, MIN(rlen, s->feature.len));
+            break;
+        }
+        break;
+
+    case BT_SET_REPORT:
+        if (len < 2 || len > BT_HID_MTU || s->state != bt_state_ready ||
+                        (parameter & 3) == BT_DATA_OTHER ||
+                        (parameter & 3) == BT_DATA_INPUT) {
+            ret = BT_HS_ERR_INVALID_PARAMETER;
+            break;
+        }
+        s->data_type = parameter & 3;
+        if (s->data_type == BT_DATA_OUTPUT) {
+            s->dataout.len = len - 1;
+            memcpy(s->dataout.buffer, data + 1, s->dataout.len);
+        } else {
+            s->feature.len = len - 1;
+            memcpy(s->feature.buffer, data + 1, s->feature.len);
+        }
+        if (len == BT_HID_MTU)
+            s->state = bt_state_transaction;
+        else
+            bt_hid_out(s);
+        break;
+
+    case BT_GET_PROTOCOL:
+        if (len != 1 || s->state == bt_state_transaction) {
+            ret = BT_HS_ERR_INVALID_PARAMETER;
+            break;
+        }
+        *s->control->sdu_out(s->control, 1) = s->proto;
+        s->control->sdu_submit(s->control);
+        break;
+
+    case BT_SET_PROTOCOL:
+        if (len != 1 || s->state == bt_state_transaction ||
+                        (parameter != BT_HID_PROTO_BOOT &&
+                         parameter != BT_HID_PROTO_REPORT)) {
+            ret = BT_HS_ERR_INVALID_PARAMETER;
+            break;
+        }
+        s->proto = parameter;
+        s->hid.protocol = parameter;
+        ret = BT_HS_SUCCESSFUL;
+        break;
+
+    case BT_GET_IDLE:
+        if (len != 1 || s->state == bt_state_transaction) {
+            ret = BT_HS_ERR_INVALID_PARAMETER;
+            break;
+        }
+        *s->control->sdu_out(s->control, 1) = s->hid.idle;
+        s->control->sdu_submit(s->control);
+        break;
+
+    case BT_SET_IDLE:
+        if (len != 2 || s->state == bt_state_transaction) {
+            ret = BT_HS_ERR_INVALID_PARAMETER;
+            break;
+        }
+
+        s->hid.idle = data[1];
+        /* XXX: Does this generate a handshake? */
+        break;
+
+    case BT_DATC:
+        if (len > BT_HID_MTU || s->state != bt_state_transaction) {
+            ret = BT_HS_ERR_INVALID_PARAMETER;
+            break;
+        }
+        if (s->data_type == BT_DATA_OUTPUT) {
+            memcpy(s->dataout.buffer + s->dataout.len, data + 1, len - 1);
+            s->dataout.len += len - 1;
+        } else {
+            memcpy(s->feature.buffer + s->feature.len, data + 1, len - 1);
+            s->feature.len += len - 1;
+        }
+        if (len < BT_HID_MTU) {
+            bt_hid_out(s);
+            s->state = bt_state_ready;
+        }
+        break;
+
+    default:
+        ret = BT_HS_ERR_UNSUPPORTED_REQUEST;
+    }
+
+    if (ret != -1)
+        bt_hid_send_handshake(s, ret);
+}
+
+static void bt_hid_control_sdu(void *opaque, const uint8_t *data, int len)
+{
+    struct bt_hid_device_s *hid = opaque;
+
+    bt_hid_control_transaction(hid, data, len);
+}
+
+static void bt_hid_datain(HIDState *hs)
+{
+    struct bt_hid_device_s *hid =
+        container_of(hs, struct bt_hid_device_s, hid);
+
+    /* If suspended, wake-up and send a wake-up event first.  We might
+     * want to also inspect the input report and ignore event like
+     * mouse movements until a button event occurs.  */
+    if (hid->state == bt_state_suspend) {
+        hid->state = bt_state_ready;
+    }
+
+    if (bt_hid_in(hid) > 0)
+        /* TODO: when in boot-mode precede any Input reports with the ReportID
+         * byte, here and in GetReport/SetReport on the Control channel.  */
+        bt_hid_send_data(hid->interrupt, BT_DATA_INPUT,
+                        hid->datain.buffer, hid->datain.len);
+}
+
+static void bt_hid_interrupt_sdu(void *opaque, const uint8_t *data, int len)
+{
+    struct bt_hid_device_s *hid = opaque;
+
+    if (len > BT_HID_MTU || len < 1)
+        goto bad;
+    if ((data[0] & 3) != BT_DATA_OUTPUT)
+        goto bad;
+    if ((data[0] >> 4) == BT_DATA) {
+        if (hid->intr_state)
+            goto bad;
+
+        hid->data_type = BT_DATA_OUTPUT;
+        hid->intrdataout.len = 0;
+    } else if ((data[0] >> 4) == BT_DATC) {
+        if (!hid->intr_state)
+            goto bad;
+    } else
+        goto bad;
+
+    memcpy(hid->intrdataout.buffer + hid->intrdataout.len, data + 1, len - 1);
+    hid->intrdataout.len += len - 1;
+    hid->intr_state = (len == BT_HID_MTU);
+    if (!hid->intr_state) {
+        memcpy(hid->dataout.buffer, hid->intrdataout.buffer,
+                        hid->dataout.len = hid->intrdataout.len);
+        bt_hid_out(hid);
+    }
+
+    return;
+bad:
+    fprintf(stderr, "%s: bad transaction on Interrupt channel.\n",
+                    __FUNCTION__);
+}
+
+/* "Virtual cable" plug/unplug event.  */
+static void bt_hid_connected_update(struct bt_hid_device_s *hid)
+{
+    int prev = hid->connected;
+
+    hid->connected = hid->control && hid->interrupt;
+
+    /* Stop page-/inquiry-scanning when a host is connected.  */
+    hid->btdev.device.page_scan = !hid->connected;
+    hid->btdev.device.inquiry_scan = !hid->connected;
+
+    if (hid->connected && !prev) {
+        hid_reset(&hid->hid);
+        hid->proto = BT_HID_PROTO_REPORT;
+    }
+
+    /* Should set HIDVirtualCable in SDP (possibly need to check that SDP
+     * isn't destroyed yet, in case we're being called from handle_destroy) */
+}
+
+static void bt_hid_close_control(void *opaque)
+{
+    struct bt_hid_device_s *hid = opaque;
+
+    hid->control = NULL;
+    bt_hid_connected_update(hid);
+}
+
+static void bt_hid_close_interrupt(void *opaque)
+{
+    struct bt_hid_device_s *hid = opaque;
+
+    hid->interrupt = NULL;
+    bt_hid_connected_update(hid);
+}
+
+static int bt_hid_new_control_ch(struct bt_l2cap_device_s *dev,
+                struct bt_l2cap_conn_params_s *params)
+{
+    struct bt_hid_device_s *hid = (struct bt_hid_device_s *) dev;
+
+    if (hid->control)
+        return 1;
+
+    hid->control = params;
+    hid->control->opaque = hid;
+    hid->control->close = bt_hid_close_control;
+    hid->control->sdu_in = bt_hid_control_sdu;
+
+    bt_hid_connected_update(hid);
+
+    return 0;
+}
+
+static int bt_hid_new_interrupt_ch(struct bt_l2cap_device_s *dev,
+                struct bt_l2cap_conn_params_s *params)
+{
+    struct bt_hid_device_s *hid = (struct bt_hid_device_s *) dev;
+
+    if (hid->interrupt)
+        return 1;
+
+    hid->interrupt = params;
+    hid->interrupt->opaque = hid;
+    hid->interrupt->close = bt_hid_close_interrupt;
+    hid->interrupt->sdu_in = bt_hid_interrupt_sdu;
+
+    bt_hid_connected_update(hid);
+
+    return 0;
+}
+
+static void bt_hid_destroy(struct bt_device_s *dev)
+{
+    struct bt_hid_device_s *hid = (struct bt_hid_device_s *) dev;
+
+    if (hid->connected)
+        bt_hid_send_control(hid, BT_HC_VIRTUAL_CABLE_UNPLUG);
+    bt_l2cap_device_done(&hid->btdev);
+
+    hid_free(&hid->hid);
+
+    g_free(hid);
+}
+
+enum peripheral_minor_class {
+    class_other                = 0 << 4,
+    class_keyboard     = 1 << 4,
+    class_pointing     = 2 << 4,
+    class_combo                = 3 << 4,
+};
+
+static struct bt_device_s *bt_hid_init(struct bt_scatternet_s *net,
+                                       enum peripheral_minor_class minor)
+{
+    struct bt_hid_device_s *s = g_malloc0(sizeof(*s));
+    uint32_t class =
+            /* Format type */
+            (0 << 0) |
+            /* Device class */
+            (minor << 2) |
+            (5 << 8) |  /* "Peripheral" */
+            /* Service classes */
+            (1 << 13) | /* Limited discoverable mode */
+            (1 << 19);  /* Capturing device (?) */
+
+    bt_l2cap_device_init(&s->btdev, net);
+    bt_l2cap_sdp_init(&s->btdev);
+    bt_l2cap_psm_register(&s->btdev, BT_PSM_HID_CTRL,
+                    BT_HID_MTU, bt_hid_new_control_ch);
+    bt_l2cap_psm_register(&s->btdev, BT_PSM_HID_INTR,
+                    BT_HID_MTU, bt_hid_new_interrupt_ch);
+
+    hid_init(&s->hid, HID_KEYBOARD, bt_hid_datain);
+    s->btdev.device.lmp_name = "BT Keyboard";
+
+    s->btdev.device.handle_destroy = bt_hid_destroy;
+
+    s->btdev.device.class[0] = (class >>  0) & 0xff;
+    s->btdev.device.class[1] = (class >>  8) & 0xff;
+    s->btdev.device.class[2] = (class >> 16) & 0xff;
+
+    return &s->btdev.device;
+}
+
+struct bt_device_s *bt_keyboard_init(struct bt_scatternet_s *net)
+{
+    return bt_hid_init(net, class_keyboard);
+}
diff --git a/hw/bt/l2cap.c b/hw/bt/l2cap.c
new file mode 100644 (file)
index 0000000..521587a
--- /dev/null
@@ -0,0 +1,1365 @@
+/*
+ * QEMU Bluetooth L2CAP logic.
+ *
+ * Copyright (C) 2008 Andrzej Zaborowski  <balrog@zabor.org>
+ *
+ * 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 "qemu/timer.h"
+#include "hw/bt.h"
+
+#define L2CAP_CID_MAX  0x100   /* Between 0x40 and 0x10000 */
+
+struct l2cap_instance_s {
+    struct bt_link_s *link;
+    struct bt_l2cap_device_s *dev;
+    int role;
+
+    uint8_t frame_in[65535 + L2CAP_HDR_SIZE] __attribute__ ((aligned (4)));
+    int frame_in_len;
+
+    uint8_t frame_out[65535 + L2CAP_HDR_SIZE] __attribute__ ((aligned (4)));
+    int frame_out_len;
+
+    /* Signalling channel timers.  They exist per-request but we can make
+     * sure we have no more than one outstanding request at any time.  */
+    QEMUTimer *rtx;
+    QEMUTimer *ertx;
+
+    int last_id;
+    int next_id;
+
+    struct l2cap_chan_s {
+        struct bt_l2cap_conn_params_s params;
+
+        void (*frame_in)(struct l2cap_chan_s *chan, uint16_t cid,
+                        const l2cap_hdr *hdr, int len);
+        int mps;
+        int min_mtu;
+
+        struct l2cap_instance_s *l2cap;
+
+        /* Only allocated channels */
+        uint16_t remote_cid;
+#define L2CAP_CFG_INIT 2
+#define L2CAP_CFG_ACC  1
+        int config_req_id; /* TODO: handle outgoing requests generically */
+        int config;
+
+        /* Only connection-oriented channels.  Note: if we allow the tx and
+         * rx traffic to be in different modes at any time, we need two.  */
+        int mode;
+
+        /* Only flow-controlled, connection-oriented channels */
+        uint8_t sdu[65536]; /* TODO: dynamically allocate */
+        int len_cur, len_total;
+        int rexmit;
+        int monitor_timeout;
+        QEMUTimer *monitor_timer;
+        QEMUTimer *retransmission_timer;
+    } *cid[L2CAP_CID_MAX];
+    /* The channel state machine states map as following:
+     * CLOSED           -> !cid[N]
+     * WAIT_CONNECT     -> never occurs
+     * WAIT_CONNECT_RSP -> never occurs
+     * CONFIG           -> cid[N] && config < 3
+     *   WAIT_CONFIG         -> never occurs, cid[N] && config == 0 && !config_r
+     *   WAIT_SEND_CONFIG    -> never occurs, cid[N] && config == 1 && !config_r
+     *   WAIT_CONFIG_REQ_RSP -> cid[N] && config == 0 && config_req_id
+     *   WAIT_CONFIG_RSP     -> cid[N] && config == 1 && config_req_id
+     *   WAIT_CONFIG_REQ     -> cid[N] && config == 2
+     * OPEN             -> cid[N] && config == 3
+     * WAIT_DISCONNECT  -> never occurs
+     */
+
+    struct l2cap_chan_s signalling_ch;
+    struct l2cap_chan_s group_ch;
+};
+
+struct slave_l2cap_instance_s {
+    struct bt_link_s link;     /* Underlying logical link (ACL) */
+    struct l2cap_instance_s l2cap;
+};
+
+struct bt_l2cap_psm_s {
+    int psm;
+    int min_mtu;
+    int (*new_channel)(struct bt_l2cap_device_s *device,
+                    struct bt_l2cap_conn_params_s *params);
+    struct bt_l2cap_psm_s *next;
+};
+
+static const uint16_t l2cap_fcs16_table[256] = {
+    0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241,
+    0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440,
+    0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40,
+    0x0a00, 0xcac1, 0xcb81, 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841,
+    0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40,
+    0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41,
+    0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641,
+    0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040,
+    0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240,
+    0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441,
+    0x3c00, 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41,
+    0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840,
+    0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41,
+    0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40,
+    0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640,
+    0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041,
+    0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240,
+    0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441,
+    0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41,
+    0xaa01, 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840,
+    0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41,
+    0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40,
+    0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640,
+    0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041,
+    0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241,
+    0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440,
+    0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40,
+    0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841,
+    0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40,
+    0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41,
+    0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641,
+    0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040,
+};
+
+static uint16_t l2cap_fcs16(const uint8_t *message, int len)
+{
+    uint16_t fcs = 0x0000;
+
+    while (len --)
+#if 0
+    {
+        int i;
+
+        fcs ^= *message ++;
+        for (i = 8; i; -- i)
+            if (fcs & 1)
+                fcs = (fcs >> 1) ^ 0xa001;
+            else
+                fcs = (fcs >> 1);
+    }
+#else
+        fcs = (fcs >> 8) ^ l2cap_fcs16_table[(fcs ^ *message ++) & 0xff];
+#endif
+
+    return fcs;
+}
+
+/* L2CAP layer logic (protocol) */
+
+static void l2cap_retransmission_timer_update(struct l2cap_chan_s *ch)
+{
+#if 0
+    if (ch->mode != L2CAP_MODE_BASIC && ch->rexmit)
+        qemu_mod_timer(ch->retransmission_timer);
+    else
+        qemu_del_timer(ch->retransmission_timer);
+#endif
+}
+
+static void l2cap_monitor_timer_update(struct l2cap_chan_s *ch)
+{
+#if 0
+    if (ch->mode != L2CAP_MODE_BASIC && !ch->rexmit)
+        qemu_mod_timer(ch->monitor_timer);
+    else
+        qemu_del_timer(ch->monitor_timer);
+#endif
+}
+
+static void l2cap_command_reject(struct l2cap_instance_s *l2cap, int id,
+                uint16_t reason, const void *data, int plen)
+{
+    uint8_t *pkt;
+    l2cap_cmd_hdr *hdr;
+    l2cap_cmd_rej *params;
+    uint16_t len;
+
+    reason = cpu_to_le16(reason);
+    len = cpu_to_le16(L2CAP_CMD_REJ_SIZE + plen);
+
+    pkt = l2cap->signalling_ch.params.sdu_out(&l2cap->signalling_ch.params,
+                    L2CAP_CMD_HDR_SIZE + L2CAP_CMD_REJ_SIZE + plen);
+    hdr = (void *) (pkt + 0);
+    params = (void *) (pkt + L2CAP_CMD_HDR_SIZE);
+
+    hdr->code = L2CAP_COMMAND_REJ;
+    hdr->ident = id;
+    memcpy(&hdr->len, &len, sizeof(hdr->len));
+    memcpy(&params->reason, &reason, sizeof(reason));
+    if (plen)
+       memcpy(pkt + L2CAP_CMD_HDR_SIZE + L2CAP_CMD_REJ_SIZE, data, plen);
+
+    l2cap->signalling_ch.params.sdu_submit(&l2cap->signalling_ch.params);
+}
+
+static void l2cap_command_reject_cid(struct l2cap_instance_s *l2cap, int id,
+                uint16_t reason, uint16_t dcid, uint16_t scid)
+{
+    l2cap_cmd_rej_cid params = {
+        .dcid = dcid,
+        .scid = scid,
+    };
+
+    l2cap_command_reject(l2cap, id, reason, &params, L2CAP_CMD_REJ_CID_SIZE);
+}
+
+static void l2cap_connection_response(struct l2cap_instance_s *l2cap,
+                int dcid, int scid, int result, int status)
+{
+    uint8_t *pkt;
+    l2cap_cmd_hdr *hdr;
+    l2cap_conn_rsp *params;
+
+    pkt = l2cap->signalling_ch.params.sdu_out(&l2cap->signalling_ch.params,
+                    L2CAP_CMD_HDR_SIZE + L2CAP_CONN_RSP_SIZE);
+    hdr = (void *) (pkt + 0);
+    params = (void *) (pkt + L2CAP_CMD_HDR_SIZE);
+
+    hdr->code = L2CAP_CONN_RSP;
+    hdr->ident = l2cap->last_id;
+    hdr->len = cpu_to_le16(L2CAP_CONN_RSP_SIZE);
+
+    params->dcid = cpu_to_le16(dcid);
+    params->scid = cpu_to_le16(scid);
+    params->result = cpu_to_le16(result);
+    params->status = cpu_to_le16(status);
+
+    l2cap->signalling_ch.params.sdu_submit(&l2cap->signalling_ch.params);
+}
+
+static void l2cap_configuration_request(struct l2cap_instance_s *l2cap,
+                int dcid, int flag, const uint8_t *data, int len)
+{
+    uint8_t *pkt;
+    l2cap_cmd_hdr *hdr;
+    l2cap_conf_req *params;
+
+    pkt = l2cap->signalling_ch.params.sdu_out(&l2cap->signalling_ch.params,
+                    L2CAP_CMD_HDR_SIZE + L2CAP_CONF_REQ_SIZE(len));
+    hdr = (void *) (pkt + 0);
+    params = (void *) (pkt + L2CAP_CMD_HDR_SIZE);
+
+    /* TODO: unify the id sequencing */
+    l2cap->last_id = l2cap->next_id;
+    l2cap->next_id = l2cap->next_id == 255 ? 1 : l2cap->next_id + 1;
+
+    hdr->code = L2CAP_CONF_REQ;
+    hdr->ident = l2cap->last_id;
+    hdr->len = cpu_to_le16(L2CAP_CONF_REQ_SIZE(len));
+
+    params->dcid = cpu_to_le16(dcid);
+    params->flags = cpu_to_le16(flag);
+    if (len)
+        memcpy(params->data, data, len);
+
+    l2cap->signalling_ch.params.sdu_submit(&l2cap->signalling_ch.params);
+}
+
+static void l2cap_configuration_response(struct l2cap_instance_s *l2cap,
+                int scid, int flag, int result, const uint8_t *data, int len)
+{
+    uint8_t *pkt;
+    l2cap_cmd_hdr *hdr;
+    l2cap_conf_rsp *params;
+
+    pkt = l2cap->signalling_ch.params.sdu_out(&l2cap->signalling_ch.params,
+                    L2CAP_CMD_HDR_SIZE + L2CAP_CONF_RSP_SIZE(len));
+    hdr = (void *) (pkt + 0);
+    params = (void *) (pkt + L2CAP_CMD_HDR_SIZE);
+
+    hdr->code = L2CAP_CONF_RSP;
+    hdr->ident = l2cap->last_id;
+    hdr->len = cpu_to_le16(L2CAP_CONF_RSP_SIZE(len));
+
+    params->scid = cpu_to_le16(scid);
+    params->flags = cpu_to_le16(flag);
+    params->result = cpu_to_le16(result);
+    if (len)
+        memcpy(params->data, data, len);
+
+    l2cap->signalling_ch.params.sdu_submit(&l2cap->signalling_ch.params);
+}
+
+static void l2cap_disconnection_response(struct l2cap_instance_s *l2cap,
+                int dcid, int scid)
+{
+    uint8_t *pkt;
+    l2cap_cmd_hdr *hdr;
+    l2cap_disconn_rsp *params;
+
+    pkt = l2cap->signalling_ch.params.sdu_out(&l2cap->signalling_ch.params,
+                    L2CAP_CMD_HDR_SIZE + L2CAP_DISCONN_RSP_SIZE);
+    hdr = (void *) (pkt + 0);
+    params = (void *) (pkt + L2CAP_CMD_HDR_SIZE);
+
+    hdr->code = L2CAP_DISCONN_RSP;
+    hdr->ident = l2cap->last_id;
+    hdr->len = cpu_to_le16(L2CAP_DISCONN_RSP_SIZE);
+
+    params->dcid = cpu_to_le16(dcid);
+    params->scid = cpu_to_le16(scid);
+
+    l2cap->signalling_ch.params.sdu_submit(&l2cap->signalling_ch.params);
+}
+
+static void l2cap_echo_response(struct l2cap_instance_s *l2cap,
+                const uint8_t *data, int len)
+{
+    uint8_t *pkt;
+    l2cap_cmd_hdr *hdr;
+    uint8_t *params;
+
+    pkt = l2cap->signalling_ch.params.sdu_out(&l2cap->signalling_ch.params,
+                    L2CAP_CMD_HDR_SIZE + len);
+    hdr = (void *) (pkt + 0);
+    params = (void *) (pkt + L2CAP_CMD_HDR_SIZE);
+
+    hdr->code = L2CAP_ECHO_RSP;
+    hdr->ident = l2cap->last_id;
+    hdr->len = cpu_to_le16(len);
+
+    memcpy(params, data, len);
+
+    l2cap->signalling_ch.params.sdu_submit(&l2cap->signalling_ch.params);
+}
+
+static void l2cap_info_response(struct l2cap_instance_s *l2cap, int type,
+                int result, const uint8_t *data, int len)
+{
+    uint8_t *pkt;
+    l2cap_cmd_hdr *hdr;
+    l2cap_info_rsp *params;
+
+    pkt = l2cap->signalling_ch.params.sdu_out(&l2cap->signalling_ch.params,
+                    L2CAP_CMD_HDR_SIZE + L2CAP_INFO_RSP_SIZE + len);
+    hdr = (void *) (pkt + 0);
+    params = (void *) (pkt + L2CAP_CMD_HDR_SIZE);
+
+    hdr->code = L2CAP_INFO_RSP;
+    hdr->ident = l2cap->last_id;
+    hdr->len = cpu_to_le16(L2CAP_INFO_RSP_SIZE + len);
+
+    params->type = cpu_to_le16(type);
+    params->result = cpu_to_le16(result);
+    if (len)
+       memcpy(params->data, data, len);
+
+    l2cap->signalling_ch.params.sdu_submit(&l2cap->signalling_ch.params);
+}
+
+static uint8_t *l2cap_bframe_out(struct bt_l2cap_conn_params_s *parm, int len);
+static void l2cap_bframe_submit(struct bt_l2cap_conn_params_s *parms);
+#if 0
+static uint8_t *l2cap_iframe_out(struct bt_l2cap_conn_params_s *parm, int len);
+static void l2cap_iframe_submit(struct bt_l2cap_conn_params_s *parm);
+#endif
+static void l2cap_bframe_in(struct l2cap_chan_s *ch, uint16_t cid,
+                const l2cap_hdr *hdr, int len);
+static void l2cap_iframe_in(struct l2cap_chan_s *ch, uint16_t cid,
+                const l2cap_hdr *hdr, int len);
+
+static int l2cap_cid_new(struct l2cap_instance_s *l2cap)
+{
+    int i;
+
+    for (i = L2CAP_CID_ALLOC; i < L2CAP_CID_MAX; i ++)
+        if (!l2cap->cid[i])
+            return i;
+
+    return L2CAP_CID_INVALID;
+}
+
+static inline struct bt_l2cap_psm_s *l2cap_psm(
+                struct bt_l2cap_device_s *device, int psm)
+{
+    struct bt_l2cap_psm_s *ret = device->first_psm;
+
+    while (ret && ret->psm != psm)
+        ret = ret->next;
+
+    return ret;
+}
+
+static struct l2cap_chan_s *l2cap_channel_open(struct l2cap_instance_s *l2cap,
+                int psm, int source_cid)
+{
+    struct l2cap_chan_s *ch = NULL;
+    struct bt_l2cap_psm_s *psm_info;
+    int result, status;
+    int cid = l2cap_cid_new(l2cap);
+
+    if (cid) {
+        /* See what the channel is to be used for.. */
+        psm_info = l2cap_psm(l2cap->dev, psm);
+
+        if (psm_info) {
+            /* Device supports this use-case.  */
+            ch = g_malloc0(sizeof(*ch));
+            ch->params.sdu_out = l2cap_bframe_out;
+            ch->params.sdu_submit = l2cap_bframe_submit;
+            ch->frame_in = l2cap_bframe_in;
+            ch->mps = 65536;
+            ch->min_mtu = MAX(48, psm_info->min_mtu);
+            ch->params.remote_mtu = MAX(672, ch->min_mtu);
+            ch->remote_cid = source_cid;
+            ch->mode = L2CAP_MODE_BASIC;
+            ch->l2cap = l2cap;
+
+            /* Does it feel like opening yet another channel though?  */
+            if (!psm_info->new_channel(l2cap->dev, &ch->params)) {
+                l2cap->cid[cid] = ch;
+
+                result = L2CAP_CR_SUCCESS;
+                status = L2CAP_CS_NO_INFO;
+            } else {
+                g_free(ch);
+
+                result = L2CAP_CR_NO_MEM;
+                status = L2CAP_CS_NO_INFO;
+            }
+        } else {
+            result = L2CAP_CR_BAD_PSM;
+            status = L2CAP_CS_NO_INFO;
+        }
+    } else {
+        result = L2CAP_CR_NO_MEM;
+        status = L2CAP_CS_NO_INFO;
+    }
+
+    l2cap_connection_response(l2cap, cid, source_cid, result, status);
+
+    return ch;
+}
+
+static void l2cap_channel_close(struct l2cap_instance_s *l2cap,
+                int cid, int source_cid)
+{
+    struct l2cap_chan_s *ch = NULL;
+
+    /* According to Volume 3, section 6.1.1, pg 1048 of BT Core V2.0, a
+     * connection in CLOSED state still responds with a L2CAP_DisconnectRsp
+     * message on an L2CAP_DisconnectReq event.  */
+    if (unlikely(cid < L2CAP_CID_ALLOC)) {
+        l2cap_command_reject_cid(l2cap, l2cap->last_id, L2CAP_REJ_CID_INVAL,
+                        cid, source_cid);
+        return;
+    }
+    if (likely(cid >= L2CAP_CID_ALLOC && cid < L2CAP_CID_MAX))
+        ch = l2cap->cid[cid];
+
+    if (likely(ch)) {
+        if (ch->remote_cid != source_cid) {
+            fprintf(stderr, "%s: Ignoring a Disconnection Request with the "
+                            "invalid SCID %04x.\n", __FUNCTION__, source_cid);
+            return;
+        }
+
+        l2cap->cid[cid] = NULL;
+
+        ch->params.close(ch->params.opaque);
+        g_free(ch);
+    }
+
+    l2cap_disconnection_response(l2cap, cid, source_cid);
+}
+
+static void l2cap_channel_config_null(struct l2cap_instance_s *l2cap,
+                struct l2cap_chan_s *ch)
+{
+    l2cap_configuration_request(l2cap, ch->remote_cid, 0, NULL, 0);
+    ch->config_req_id = l2cap->last_id;
+    ch->config &= ~L2CAP_CFG_INIT;
+}
+
+static void l2cap_channel_config_req_event(struct l2cap_instance_s *l2cap,
+                struct l2cap_chan_s *ch)
+{
+    /* Use all default channel options and terminate negotiation.  */
+    l2cap_channel_config_null(l2cap, ch);
+}
+
+static int l2cap_channel_config(struct l2cap_instance_s *l2cap,
+                struct l2cap_chan_s *ch, int flag,
+                const uint8_t *data, int len)
+{
+    l2cap_conf_opt *opt;
+    l2cap_conf_opt_qos *qos;
+    uint32_t val;
+    uint8_t rsp[len];
+    int result = L2CAP_CONF_SUCCESS;
+
+    data = memcpy(rsp, data, len);
+    while (len) {
+        opt = (void *) data;
+
+        if (len < L2CAP_CONF_OPT_SIZE ||
+                        len < L2CAP_CONF_OPT_SIZE + opt->len) {
+            result = L2CAP_CONF_REJECT;
+            break;
+        }
+        data += L2CAP_CONF_OPT_SIZE + opt->len;
+        len -= L2CAP_CONF_OPT_SIZE + opt->len;
+
+        switch (opt->type & 0x7f) {
+        case L2CAP_CONF_MTU:
+            if (opt->len != 2) {
+                result = L2CAP_CONF_REJECT;
+                break;
+            }
+
+            /* MTU */
+            val = le16_to_cpup((void *) opt->val);
+            if (val < ch->min_mtu) {
+                cpu_to_le16w((void *) opt->val, ch->min_mtu);
+                result = L2CAP_CONF_UNACCEPT;
+                break;
+            }
+
+            ch->params.remote_mtu = val;
+            break;
+
+        case L2CAP_CONF_FLUSH_TO:
+            if (opt->len != 2) {
+                result = L2CAP_CONF_REJECT;
+                break;
+            }
+
+            /* Flush Timeout */
+            val = le16_to_cpup((void *) opt->val);
+            if (val < 0x0001) {
+                opt->val[0] = 0xff;
+                opt->val[1] = 0xff;
+                result = L2CAP_CONF_UNACCEPT;
+                break;
+            }
+            break;
+
+        case L2CAP_CONF_QOS:
+            if (opt->len != L2CAP_CONF_OPT_QOS_SIZE) {
+                result = L2CAP_CONF_REJECT;
+                break;
+            }
+            qos = (void *) opt->val;
+
+            /* Flags */
+            val = qos->flags;
+            if (val) {
+                qos->flags = 0;
+                result = L2CAP_CONF_UNACCEPT;
+            }
+
+            /* Service type */
+            val = qos->service_type;
+            if (val != L2CAP_CONF_QOS_BEST_EFFORT &&
+                            val != L2CAP_CONF_QOS_NO_TRAFFIC) {
+                qos->service_type = L2CAP_CONF_QOS_BEST_EFFORT;
+                result = L2CAP_CONF_UNACCEPT;
+            }
+
+            if (val != L2CAP_CONF_QOS_NO_TRAFFIC) {
+                /* XXX: These values should possibly be calculated
+                 * based on LM / baseband properties also.  */
+
+                /* Token rate */
+                val = le32_to_cpu(qos->token_rate);
+                if (val == L2CAP_CONF_QOS_WILDCARD)
+                    qos->token_rate = cpu_to_le32(0x100000);
+
+                /* Token bucket size */
+                val = le32_to_cpu(qos->token_bucket_size);
+                if (val == L2CAP_CONF_QOS_WILDCARD)
+                    qos->token_bucket_size = cpu_to_le32(65500);
+
+                /* Any Peak bandwidth value is correct to return as-is */
+                /* Any Access latency value is correct to return as-is */
+                /* Any Delay variation value is correct to return as-is */
+            }
+            break;
+
+        case L2CAP_CONF_RFC:
+            if (opt->len != 9) {
+                result = L2CAP_CONF_REJECT;
+                break;
+            }
+
+            /* Mode */
+            val = opt->val[0];
+            switch (val) {
+            case L2CAP_MODE_BASIC:
+                ch->mode = val;
+                ch->frame_in = l2cap_bframe_in;
+
+                /* All other parameters shall be ignored */
+                break;
+
+            case L2CAP_MODE_RETRANS:
+            case L2CAP_MODE_FLOWCTL:
+                ch->mode = val;
+                ch->frame_in = l2cap_iframe_in;
+                /* Note: most of these parameters refer to incoming traffic
+                 * so we don't need to save them as long as we can accept
+                 * incoming PDUs at any values of the parameters.  */
+
+                /* TxWindow size */
+                val = opt->val[1];
+                if (val < 1 || val > 32) {
+                    opt->val[1] = 32;
+                    result = L2CAP_CONF_UNACCEPT;
+                    break;
+                }
+
+                /* MaxTransmit */
+                val = opt->val[2];
+                if (val < 1) {
+                    opt->val[2] = 1;
+                    result = L2CAP_CONF_UNACCEPT;
+                    break;
+                }
+
+                /* Remote Retransmission time-out shouldn't affect local
+                 * operation (?) */
+
+                /* The Monitor time-out drives the local Monitor timer (?),
+                 * so save the value.  */
+                val = (opt->val[6] << 8) | opt->val[5];
+                if (val < 30) {
+                    opt->val[5] = 100 & 0xff;
+                    opt->val[6] = 100 >> 8;
+                    result = L2CAP_CONF_UNACCEPT;
+                    break;
+                }
+                ch->monitor_timeout = val;
+                l2cap_monitor_timer_update(ch);
+
+                /* MPS */
+                val = (opt->val[8] << 8) | opt->val[7];
+                if (val < ch->min_mtu) {
+                    opt->val[7] = ch->min_mtu & 0xff;
+                    opt->val[8] = ch->min_mtu >> 8;
+                    result = L2CAP_CONF_UNACCEPT;
+                    break;
+                }
+                ch->mps = val;
+                break;
+
+            default:
+                result = L2CAP_CONF_UNACCEPT;
+                break;
+            }
+            break;
+
+        default:
+            if (!(opt->type >> 7))
+                result = L2CAP_CONF_UNKNOWN;
+            break;
+        }
+
+        if (result != L2CAP_CONF_SUCCESS)
+            break;     /* XXX: should continue? */
+    }
+
+    l2cap_configuration_response(l2cap, ch->remote_cid,
+                    flag, result, rsp, len);
+
+    return result == L2CAP_CONF_SUCCESS && !flag;
+}
+
+static void l2cap_channel_config_req_msg(struct l2cap_instance_s *l2cap,
+                int flag, int cid, const uint8_t *data, int len)
+{
+    struct l2cap_chan_s *ch;
+
+    if (unlikely(cid >= L2CAP_CID_MAX || !l2cap->cid[cid])) {
+        l2cap_command_reject_cid(l2cap, l2cap->last_id, L2CAP_REJ_CID_INVAL,
+                        cid, 0x0000);
+        return;
+    }
+    ch = l2cap->cid[cid];
+
+    /* From OPEN go to WAIT_CONFIG_REQ and from WAIT_CONFIG_REQ_RSP to
+     * WAIT_CONFIG_REQ_RSP.  This is assuming the transition chart for OPEN
+     * on pg 1053, section 6.1.5, volume 3 of BT Core V2.0 has a mistake
+     * and on options-acceptable we go back to OPEN and otherwise to
+     * WAIT_CONFIG_REQ and not the other way.  */
+    ch->config &= ~L2CAP_CFG_ACC;
+
+    if (l2cap_channel_config(l2cap, ch, flag, data, len))
+        /* Go to OPEN or WAIT_CONFIG_RSP */
+        ch->config |= L2CAP_CFG_ACC;
+
+    /* TODO: if the incoming traffic flow control or retransmission mode
+     * changed then we probably need to also generate the
+     * ConfigureChannel_Req event and set the outgoing traffic to the same
+     * mode.  */
+    if (!(ch->config & L2CAP_CFG_INIT) && (ch->config & L2CAP_CFG_ACC) &&
+                    !ch->config_req_id)
+        l2cap_channel_config_req_event(l2cap, ch);
+}
+
+static int l2cap_channel_config_rsp_msg(struct l2cap_instance_s *l2cap,
+                int result, int flag, int cid, const uint8_t *data, int len)
+{
+    struct l2cap_chan_s *ch;
+
+    if (unlikely(cid >= L2CAP_CID_MAX || !l2cap->cid[cid])) {
+        l2cap_command_reject_cid(l2cap, l2cap->last_id, L2CAP_REJ_CID_INVAL,
+                        cid, 0x0000);
+        return 0;
+    }
+    ch = l2cap->cid[cid];
+
+    if (ch->config_req_id != l2cap->last_id)
+        return 1;
+    ch->config_req_id = 0;
+
+    if (result == L2CAP_CONF_SUCCESS) {
+        if (!flag)
+            ch->config |= L2CAP_CFG_INIT;
+        else
+            l2cap_channel_config_null(l2cap, ch);
+    } else
+        /* Retry until we succeed */
+        l2cap_channel_config_req_event(l2cap, ch);
+
+    return 0;
+}
+
+static void l2cap_channel_open_req_msg(struct l2cap_instance_s *l2cap,
+                int psm, int source_cid)
+{
+    struct l2cap_chan_s *ch = l2cap_channel_open(l2cap, psm, source_cid);
+
+    if (!ch)
+        return;
+
+    /* Optional */
+    if (!(ch->config & L2CAP_CFG_INIT) && !ch->config_req_id)
+        l2cap_channel_config_req_event(l2cap, ch);
+}
+
+static void l2cap_info(struct l2cap_instance_s *l2cap, int type)
+{
+    uint8_t data[4];
+    int len = 0;
+    int result = L2CAP_IR_SUCCESS;
+
+    switch (type) {
+    case L2CAP_IT_CL_MTU:
+        data[len ++] = l2cap->group_ch.mps & 0xff;
+        data[len ++] = l2cap->group_ch.mps >> 8;
+        break;
+
+    case L2CAP_IT_FEAT_MASK:
+        /* (Prematurely) report Flow control and Retransmission modes.  */
+        data[len ++] = 0x03;
+        data[len ++] = 0x00;
+        data[len ++] = 0x00;
+        data[len ++] = 0x00;
+        break;
+
+    default:
+        result = L2CAP_IR_NOTSUPP;
+    }
+
+    l2cap_info_response(l2cap, type, result, data, len);
+}
+
+static void l2cap_command(struct l2cap_instance_s *l2cap, int code, int id,
+                const uint8_t *params, int len)
+{
+    int err;
+
+#if 0
+    /* TODO: do the IDs really have to be in sequence?  */
+    if (!id || (id != l2cap->last_id && id != l2cap->next_id)) {
+        fprintf(stderr, "%s: out of sequence command packet ignored.\n",
+                        __FUNCTION__);
+        return;
+    }
+#else
+    l2cap->next_id = id;
+#endif
+    if (id == l2cap->next_id) {
+        l2cap->last_id = l2cap->next_id;
+        l2cap->next_id = l2cap->next_id == 255 ? 1 : l2cap->next_id + 1;
+    } else {
+        /* TODO: Need to re-send the same response, without re-executing
+         * the corresponding command!  */
+    }
+
+    switch (code) {
+    case L2CAP_COMMAND_REJ:
+        if (unlikely(len != 2 && len != 4 && len != 6)) {
+            err = L2CAP_REJ_CMD_NOT_UNDERSTOOD;
+            goto reject;
+        }
+
+        /* We never issue commands other than Command Reject currently.  */
+        fprintf(stderr, "%s: stray Command Reject (%02x, %04x) "
+                        "packet, ignoring.\n", __FUNCTION__, id,
+                        le16_to_cpu(((l2cap_cmd_rej *) params)->reason));
+        break;
+
+    case L2CAP_CONN_REQ:
+        if (unlikely(len != L2CAP_CONN_REQ_SIZE)) {
+            err = L2CAP_REJ_CMD_NOT_UNDERSTOOD;
+            goto reject;
+        }
+
+        l2cap_channel_open_req_msg(l2cap,
+                        le16_to_cpu(((l2cap_conn_req *) params)->psm),
+                        le16_to_cpu(((l2cap_conn_req *) params)->scid));
+        break;
+
+    case L2CAP_CONN_RSP:
+        if (unlikely(len != L2CAP_CONN_RSP_SIZE)) {
+            err = L2CAP_REJ_CMD_NOT_UNDERSTOOD;
+            goto reject;
+        }
+
+        /* We never issue Connection Requests currently. TODO  */
+        fprintf(stderr, "%s: unexpected Connection Response (%02x) "
+                        "packet, ignoring.\n", __FUNCTION__, id);
+        break;
+
+    case L2CAP_CONF_REQ:
+        if (unlikely(len < L2CAP_CONF_REQ_SIZE(0))) {
+            err = L2CAP_REJ_CMD_NOT_UNDERSTOOD;
+            goto reject;
+        }
+
+        l2cap_channel_config_req_msg(l2cap,
+                        le16_to_cpu(((l2cap_conf_req *) params)->flags) & 1,
+                        le16_to_cpu(((l2cap_conf_req *) params)->dcid),
+                        ((l2cap_conf_req *) params)->data,
+                        len - L2CAP_CONF_REQ_SIZE(0));
+        break;
+
+    case L2CAP_CONF_RSP:
+        if (unlikely(len < L2CAP_CONF_RSP_SIZE(0))) {
+            err = L2CAP_REJ_CMD_NOT_UNDERSTOOD;
+            goto reject;
+        }
+
+        if (l2cap_channel_config_rsp_msg(l2cap,
+                        le16_to_cpu(((l2cap_conf_rsp *) params)->result),
+                        le16_to_cpu(((l2cap_conf_rsp *) params)->flags) & 1,
+                        le16_to_cpu(((l2cap_conf_rsp *) params)->scid),
+                        ((l2cap_conf_rsp *) params)->data,
+                        len - L2CAP_CONF_RSP_SIZE(0)))
+            fprintf(stderr, "%s: unexpected Configure Response (%02x) "
+                            "packet, ignoring.\n", __FUNCTION__, id);
+        break;
+
+    case L2CAP_DISCONN_REQ:
+        if (unlikely(len != L2CAP_DISCONN_REQ_SIZE)) {
+            err = L2CAP_REJ_CMD_NOT_UNDERSTOOD;
+            goto reject;
+        }
+
+        l2cap_channel_close(l2cap,
+                        le16_to_cpu(((l2cap_disconn_req *) params)->dcid),
+                        le16_to_cpu(((l2cap_disconn_req *) params)->scid));
+        break;
+
+    case L2CAP_DISCONN_RSP:
+        if (unlikely(len != L2CAP_DISCONN_RSP_SIZE)) {
+            err = L2CAP_REJ_CMD_NOT_UNDERSTOOD;
+            goto reject;
+        }
+
+        /* We never issue Disconnection Requests currently. TODO  */
+        fprintf(stderr, "%s: unexpected Disconnection Response (%02x) "
+                        "packet, ignoring.\n", __FUNCTION__, id);
+        break;
+
+    case L2CAP_ECHO_REQ:
+        l2cap_echo_response(l2cap, params, len);
+        break;
+
+    case L2CAP_ECHO_RSP:
+        /* We never issue Echo Requests currently. TODO  */
+        fprintf(stderr, "%s: unexpected Echo Response (%02x) "
+                        "packet, ignoring.\n", __FUNCTION__, id);
+        break;
+
+    case L2CAP_INFO_REQ:
+        if (unlikely(len != L2CAP_INFO_REQ_SIZE)) {
+            err = L2CAP_REJ_CMD_NOT_UNDERSTOOD;
+            goto reject;
+        }
+
+        l2cap_info(l2cap, le16_to_cpu(((l2cap_info_req *) params)->type));
+        break;
+
+    case L2CAP_INFO_RSP:
+        if (unlikely(len != L2CAP_INFO_RSP_SIZE)) {
+            err = L2CAP_REJ_CMD_NOT_UNDERSTOOD;
+            goto reject;
+        }
+
+        /* We never issue Information Requests currently. TODO  */
+        fprintf(stderr, "%s: unexpected Information Response (%02x) "
+                        "packet, ignoring.\n", __FUNCTION__, id);
+        break;
+
+    default:
+        err = L2CAP_REJ_CMD_NOT_UNDERSTOOD;
+    reject:
+        l2cap_command_reject(l2cap, id, err, 0, 0);
+        break;
+    }
+}
+
+static void l2cap_rexmit_enable(struct l2cap_chan_s *ch, int enable)
+{
+    ch->rexmit = enable;
+
+    l2cap_retransmission_timer_update(ch);
+    l2cap_monitor_timer_update(ch);
+}
+
+/* Command frame SDU */
+static void l2cap_cframe_in(void *opaque, const uint8_t *data, int len)
+{
+    struct l2cap_instance_s *l2cap = opaque;
+    const l2cap_cmd_hdr *hdr;
+    int clen;
+
+    while (len) {
+        hdr = (void *) data;
+        if (len < L2CAP_CMD_HDR_SIZE)
+            /* TODO: signal an error */
+            return;
+        len -= L2CAP_CMD_HDR_SIZE;
+        data += L2CAP_CMD_HDR_SIZE;
+
+        clen = le16_to_cpu(hdr->len);
+        if (len < clen) {
+            l2cap_command_reject(l2cap, hdr->ident,
+                            L2CAP_REJ_CMD_NOT_UNDERSTOOD, 0, 0);
+            break;
+        }
+
+        l2cap_command(l2cap, hdr->code, hdr->ident, data, clen);
+        len -= clen;
+        data += clen;
+    }
+}
+
+/* Group frame SDU */
+static void l2cap_gframe_in(void *opaque, const uint8_t *data, int len)
+{
+}
+
+/* Supervisory frame */
+static void l2cap_sframe_in(struct l2cap_chan_s *ch, uint16_t ctrl)
+{
+}
+
+/* Basic L2CAP mode Information frame */
+static void l2cap_bframe_in(struct l2cap_chan_s *ch, uint16_t cid,
+                const l2cap_hdr *hdr, int len)
+{
+    /* We have a full SDU, no further processing */
+    ch->params.sdu_in(ch->params.opaque, hdr->data, len);
+}
+
+/* Flow Control and Retransmission mode frame */
+static void l2cap_iframe_in(struct l2cap_chan_s *ch, uint16_t cid,
+                const l2cap_hdr *hdr, int len)
+{
+    uint16_t fcs = le16_to_cpup((void *) (hdr->data + len - 2));
+
+    if (len < 4)
+        goto len_error;
+    if (l2cap_fcs16((const uint8_t *) hdr, L2CAP_HDR_SIZE + len - 2) != fcs)
+        goto fcs_error;
+
+    if ((hdr->data[0] >> 7) == ch->rexmit)
+        l2cap_rexmit_enable(ch, !(hdr->data[0] >> 7));
+
+    if (hdr->data[0] & 1) {
+        if (len != 4) {
+            /* TODO: Signal an error? */
+            return;
+        }
+        l2cap_sframe_in(ch, le16_to_cpup((void *) hdr->data));
+        return;
+    }
+
+    switch (hdr->data[1] >> 6) {       /* SAR */
+    case L2CAP_SAR_NO_SEG:
+        if (ch->len_total)
+            goto seg_error;
+        if (len - 4 > ch->mps)
+            goto len_error;
+
+        ch->params.sdu_in(ch->params.opaque, hdr->data + 2, len - 4);
+        break;
+
+    case L2CAP_SAR_START:
+        if (ch->len_total || len < 6)
+            goto seg_error;
+        if (len - 6 > ch->mps)
+            goto len_error;
+
+        ch->len_total = le16_to_cpup((void *) (hdr->data + 2));
+        if (len >= 6 + ch->len_total)
+            goto seg_error;
+
+        ch->len_cur = len - 6;
+        memcpy(ch->sdu, hdr->data + 4, ch->len_cur);
+        break;
+
+    case L2CAP_SAR_END:
+        if (!ch->len_total || ch->len_cur + len - 4 < ch->len_total)
+            goto seg_error;
+        if (len - 4 > ch->mps)
+            goto len_error;
+
+        memcpy(ch->sdu + ch->len_cur, hdr->data + 2, len - 4);
+        ch->params.sdu_in(ch->params.opaque, ch->sdu, ch->len_total);
+        break;
+
+    case L2CAP_SAR_CONT:
+        if (!ch->len_total || ch->len_cur + len - 4 >= ch->len_total)
+            goto seg_error;
+        if (len - 4 > ch->mps)
+            goto len_error;
+
+        memcpy(ch->sdu + ch->len_cur, hdr->data + 2, len - 4);
+        ch->len_cur += len - 4;
+        break;
+
+    seg_error:
+    len_error: /* TODO */
+    fcs_error: /* TODO */
+        ch->len_cur = 0;
+        ch->len_total = 0;
+        break;
+    }
+}
+
+static void l2cap_frame_in(struct l2cap_instance_s *l2cap,
+                const l2cap_hdr *frame)
+{
+    uint16_t cid = le16_to_cpu(frame->cid);
+    uint16_t len = le16_to_cpu(frame->len);
+
+    if (unlikely(cid >= L2CAP_CID_MAX || !l2cap->cid[cid])) {
+        fprintf(stderr, "%s: frame addressed to a non-existent L2CAP "
+                        "channel %04x received.\n", __FUNCTION__, cid);
+        return;
+    }
+
+    l2cap->cid[cid]->frame_in(l2cap->cid[cid], cid, frame, len);
+}
+
+/* "Recombination" */
+static void l2cap_pdu_in(struct l2cap_instance_s *l2cap,
+                const uint8_t *data, int len)
+{
+    const l2cap_hdr *hdr = (void *) l2cap->frame_in;
+
+    if (unlikely(len + l2cap->frame_in_len > sizeof(l2cap->frame_in))) {
+        if (l2cap->frame_in_len < sizeof(l2cap->frame_in)) {
+            memcpy(l2cap->frame_in + l2cap->frame_in_len, data,
+                            sizeof(l2cap->frame_in) - l2cap->frame_in_len);
+            l2cap->frame_in_len = sizeof(l2cap->frame_in);
+            /* TODO: truncate */
+            l2cap_frame_in(l2cap, hdr);
+        }
+
+        return;
+    }
+
+    memcpy(l2cap->frame_in + l2cap->frame_in_len, data, len);
+    l2cap->frame_in_len += len;
+
+    if (len >= L2CAP_HDR_SIZE)
+        if (len >= L2CAP_HDR_SIZE + le16_to_cpu(hdr->len))
+            l2cap_frame_in(l2cap, hdr);
+            /* There is never a start of a new PDU in the same ACL packet, so
+             * no need to memmove the remaining payload and loop.  */
+}
+
+static inline uint8_t *l2cap_pdu_out(struct l2cap_instance_s *l2cap,
+                uint16_t cid, uint16_t len)
+{
+    l2cap_hdr *hdr = (void *) l2cap->frame_out;
+
+    l2cap->frame_out_len = len + L2CAP_HDR_SIZE;
+
+    hdr->cid = cpu_to_le16(cid);
+    hdr->len = cpu_to_le16(len);
+
+    return l2cap->frame_out + L2CAP_HDR_SIZE;
+}
+
+static inline void l2cap_pdu_submit(struct l2cap_instance_s *l2cap)
+{
+    /* TODO: Fragmentation */
+    (l2cap->role ?
+     l2cap->link->slave->lmp_acl_data : l2cap->link->host->lmp_acl_resp)
+            (l2cap->link, l2cap->frame_out, 1, l2cap->frame_out_len);
+}
+
+static uint8_t *l2cap_bframe_out(struct bt_l2cap_conn_params_s *parm, int len)
+{
+    struct l2cap_chan_s *chan = (struct l2cap_chan_s *) parm;
+
+    if (len > chan->params.remote_mtu) {
+        fprintf(stderr, "%s: B-Frame for CID %04x longer than %i octets.\n",
+                        __FUNCTION__,
+                        chan->remote_cid, chan->params.remote_mtu);
+        exit(-1);
+    }
+
+    return l2cap_pdu_out(chan->l2cap, chan->remote_cid, len);
+}
+
+static void l2cap_bframe_submit(struct bt_l2cap_conn_params_s *parms)
+{
+    struct l2cap_chan_s *chan = (struct l2cap_chan_s *) parms;
+
+    l2cap_pdu_submit(chan->l2cap);
+}
+
+#if 0
+/* Stub: Only used if an emulated device requests outgoing flow control */
+static uint8_t *l2cap_iframe_out(struct bt_l2cap_conn_params_s *parm, int len)
+{
+    struct l2cap_chan_s *chan = (struct l2cap_chan_s *) parm;
+
+    if (len > chan->params.remote_mtu) {
+        /* TODO: slice into segments and queue each segment as a separate
+         * I-Frame in a FIFO of I-Frames, local to the CID.  */
+    } else {
+        /* TODO: add to the FIFO of I-Frames, local to the CID.  */
+        /* Possibly we need to return a pointer to a contiguous buffer
+         * for now and then memcpy from it into FIFOs in l2cap_iframe_submit
+         * while segmenting at the same time.  */
+    }
+    return 0;
+}
+
+static void l2cap_iframe_submit(struct bt_l2cap_conn_params_s *parm)
+{
+    /* TODO: If flow control indicates clear to send, start submitting the
+     * invidual I-Frames from the FIFO, but don't remove them from there.
+     * Kick the appropriate timer until we get an S-Frame, and only then
+     * remove from FIFO or resubmit and re-kick the timer if the timer
+     * expired.  */
+}
+#endif
+
+static void l2cap_init(struct l2cap_instance_s *l2cap,
+                struct bt_link_s *link, int role)
+{
+    l2cap->link = link;
+    l2cap->role = role;
+    l2cap->dev = (struct bt_l2cap_device_s *)
+            (role ? link->host : link->slave);
+
+    l2cap->next_id = 1;
+
+    /* Establish the signalling channel */
+    l2cap->signalling_ch.params.sdu_in = l2cap_cframe_in;
+    l2cap->signalling_ch.params.sdu_out = l2cap_bframe_out;
+    l2cap->signalling_ch.params.sdu_submit = l2cap_bframe_submit;
+    l2cap->signalling_ch.params.opaque = l2cap;
+    l2cap->signalling_ch.params.remote_mtu = 48;
+    l2cap->signalling_ch.remote_cid = L2CAP_CID_SIGNALLING;
+    l2cap->signalling_ch.frame_in = l2cap_bframe_in;
+    l2cap->signalling_ch.mps = 65536;
+    l2cap->signalling_ch.min_mtu = 48;
+    l2cap->signalling_ch.mode = L2CAP_MODE_BASIC;
+    l2cap->signalling_ch.l2cap = l2cap;
+    l2cap->cid[L2CAP_CID_SIGNALLING] = &l2cap->signalling_ch;
+
+    /* Establish the connection-less data channel */
+    l2cap->group_ch.params.sdu_in = l2cap_gframe_in;
+    l2cap->group_ch.params.opaque = l2cap;
+    l2cap->group_ch.frame_in = l2cap_bframe_in;
+    l2cap->group_ch.mps = 65533;
+    l2cap->group_ch.l2cap = l2cap;
+    l2cap->group_ch.remote_cid = L2CAP_CID_INVALID;
+    l2cap->cid[L2CAP_CID_GROUP] = &l2cap->group_ch;
+}
+
+static void l2cap_teardown(struct l2cap_instance_s *l2cap, int send_disconnect)
+{
+    int cid;
+
+    /* Don't send DISCONNECT if we are currently handling a DISCONNECT
+     * sent from the other side.  */
+    if (send_disconnect) {
+        if (l2cap->role)
+            l2cap->dev->device.lmp_disconnect_slave(l2cap->link);
+            /* l2cap->link is invalid from now on.  */
+        else
+            l2cap->dev->device.lmp_disconnect_master(l2cap->link);
+    }
+
+    for (cid = L2CAP_CID_ALLOC; cid < L2CAP_CID_MAX; cid ++)
+        if (l2cap->cid[cid]) {
+            l2cap->cid[cid]->params.close(l2cap->cid[cid]->params.opaque);
+            g_free(l2cap->cid[cid]);
+        }
+
+    if (l2cap->role)
+        g_free(l2cap);
+    else
+        g_free(l2cap->link);
+}
+
+/* L2CAP glue to lower layers in bluetooth stack (LMP) */
+
+static void l2cap_lmp_connection_request(struct bt_link_s *link)
+{
+    struct bt_l2cap_device_s *dev = (struct bt_l2cap_device_s *) link->slave;
+    struct slave_l2cap_instance_s *l2cap;
+
+    /* Always accept - we only get called if (dev->device->page_scan).  */
+
+    l2cap = g_malloc0(sizeof(struct slave_l2cap_instance_s));
+    l2cap->link.slave = &dev->device;
+    l2cap->link.host = link->host;
+    l2cap_init(&l2cap->l2cap, &l2cap->link, 0);
+
+    /* Always at the end */
+    link->host->reject_reason = 0;
+    link->host->lmp_connection_complete(&l2cap->link);
+}
+
+/* Stub */
+static void l2cap_lmp_connection_complete(struct bt_link_s *link)
+{
+    struct bt_l2cap_device_s *dev = (struct bt_l2cap_device_s *) link->host;
+    struct l2cap_instance_s *l2cap;
+
+    if (dev->device.reject_reason) {
+        /* Signal to upper layer */
+        return;
+    }
+
+    l2cap = g_malloc0(sizeof(struct l2cap_instance_s));
+    l2cap_init(l2cap, link, 1);
+
+    link->acl_mode = acl_active;
+
+    /* Signal to upper layer */
+}
+
+/* Stub */
+static void l2cap_lmp_disconnect_host(struct bt_link_s *link)
+{
+    struct bt_l2cap_device_s *dev = (struct bt_l2cap_device_s *) link->host;
+    struct l2cap_instance_s *l2cap =
+            /* TODO: Retrieve from upper layer */ (void *) dev;
+
+    /* Signal to upper layer */
+
+    l2cap_teardown(l2cap, 0);
+}
+
+static void l2cap_lmp_disconnect_slave(struct bt_link_s *link)
+{
+    struct slave_l2cap_instance_s *l2cap =
+            (struct slave_l2cap_instance_s *) link;
+
+    l2cap_teardown(&l2cap->l2cap, 0);
+}
+
+static void l2cap_lmp_acl_data_slave(struct bt_link_s *link,
+                const uint8_t *data, int start, int len)
+{
+    struct slave_l2cap_instance_s *l2cap =
+            (struct slave_l2cap_instance_s *) link;
+
+    if (start)
+        l2cap->l2cap.frame_in_len = 0;
+
+    l2cap_pdu_in(&l2cap->l2cap, data, len);
+}
+
+/* Stub */
+static void l2cap_lmp_acl_data_host(struct bt_link_s *link,
+                const uint8_t *data, int start, int len)
+{
+    struct bt_l2cap_device_s *dev = (struct bt_l2cap_device_s *) link->host;
+    struct l2cap_instance_s *l2cap =
+            /* TODO: Retrieve from upper layer */ (void *) dev;
+
+    if (start)
+        l2cap->frame_in_len = 0;
+
+    l2cap_pdu_in(l2cap, data, len);
+}
+
+static void l2cap_dummy_destroy(struct bt_device_s *dev)
+{
+    struct bt_l2cap_device_s *l2cap_dev = (struct bt_l2cap_device_s *) dev;
+
+    bt_l2cap_device_done(l2cap_dev);
+}
+
+void bt_l2cap_device_init(struct bt_l2cap_device_s *dev,
+                struct bt_scatternet_s *net)
+{
+    bt_device_init(&dev->device, net);
+
+    dev->device.lmp_connection_request = l2cap_lmp_connection_request;
+    dev->device.lmp_connection_complete = l2cap_lmp_connection_complete;
+    dev->device.lmp_disconnect_master = l2cap_lmp_disconnect_host;
+    dev->device.lmp_disconnect_slave = l2cap_lmp_disconnect_slave;
+    dev->device.lmp_acl_data = l2cap_lmp_acl_data_slave;
+    dev->device.lmp_acl_resp = l2cap_lmp_acl_data_host;
+
+    dev->device.handle_destroy = l2cap_dummy_destroy;
+}
+
+void bt_l2cap_device_done(struct bt_l2cap_device_s *dev)
+{
+    bt_device_done(&dev->device);
+
+    /* Should keep a list of all instances and go through it and
+     * invoke l2cap_teardown() for each.  */
+}
+
+void bt_l2cap_psm_register(struct bt_l2cap_device_s *dev, int psm, int min_mtu,
+                int (*new_channel)(struct bt_l2cap_device_s *dev,
+                        struct bt_l2cap_conn_params_s *params))
+{
+    struct bt_l2cap_psm_s *new_psm = l2cap_psm(dev, psm);
+
+    if (new_psm) {
+        fprintf(stderr, "%s: PSM %04x already registered for device `%s'.\n",
+                        __FUNCTION__, psm, dev->device.lmp_name);
+        exit(-1);
+    }
+
+    new_psm = g_malloc0(sizeof(*new_psm));
+    new_psm->psm = psm;
+    new_psm->min_mtu = min_mtu;
+    new_psm->new_channel = new_channel;
+    new_psm->next = dev->first_psm;
+    dev->first_psm = new_psm;
+}
diff --git a/hw/bt/sdp.c b/hw/bt/sdp.c
new file mode 100644 (file)
index 0000000..218e075
--- /dev/null
@@ -0,0 +1,967 @@
+/*
+ * Service Discover Protocol server for QEMU L2CAP devices
+ *
+ * Copyright (C) 2008 Andrzej Zaborowski  <balrog@zabor.org>
+ *
+ * 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 "hw/bt.h"
+
+struct bt_l2cap_sdp_state_s {
+    struct bt_l2cap_conn_params_s *channel;
+
+    struct sdp_service_record_s {
+        int match;
+
+        int *uuid;
+        int uuids;
+        struct sdp_service_attribute_s {
+            int match;
+
+            int attribute_id;
+            int len;
+            void *pair;
+        } *attribute_list;
+        int attributes;
+    } *service_list;
+    int services;
+};
+
+static ssize_t sdp_datalen(const uint8_t **element, ssize_t *left)
+{
+    size_t len = *(*element) ++ & SDP_DSIZE_MASK;
+
+    if (!*left)
+        return -1;
+    (*left) --;
+
+    if (len < SDP_DSIZE_NEXT1)
+        return 1 << len;
+    else if (len == SDP_DSIZE_NEXT1) {
+        if (*left < 1)
+            return -1;
+        (*left) --;
+
+        return *(*element) ++;
+    } else if (len == SDP_DSIZE_NEXT2) {
+        if (*left < 2)
+            return -1;
+        (*left) -= 2;
+
+        len = (*(*element) ++) << 8;
+        return len | (*(*element) ++);
+    } else {
+        if (*left < 4)
+            return -1;
+        (*left) -= 4;
+
+        len = (*(*element) ++) << 24;
+        len |= (*(*element) ++) << 16;
+        len |= (*(*element) ++) << 8;
+        return len | (*(*element) ++);
+    }
+}
+
+static const uint8_t bt_base_uuid[12] = {
+    0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
+};
+
+static int sdp_uuid_match(struct sdp_service_record_s *record,
+                const uint8_t *uuid, ssize_t datalen)
+{
+    int *lo, hi, val;
+
+    if (datalen == 16 || datalen == 4) {
+        if (datalen == 16 && memcmp(uuid + 4, bt_base_uuid, 12))
+            return 0;
+
+        if (uuid[0] | uuid[1])
+            return 0;
+        uuid += 2;
+    }
+
+    val = (uuid[0] << 8) | uuid[1];
+    lo = record->uuid;
+    hi = record->uuids;
+    while (hi >>= 1)
+        if (lo[hi] <= val)
+            lo += hi;
+
+    return *lo == val;
+}
+
+#define CONTINUATION_PARAM_SIZE        (1 + sizeof(int))
+#define MAX_PDU_OUT_SIZE       96      /* Arbitrary */
+#define PDU_HEADER_SIZE                5
+#define MAX_RSP_PARAM_SIZE     (MAX_PDU_OUT_SIZE - PDU_HEADER_SIZE - \
+                CONTINUATION_PARAM_SIZE)
+
+static int sdp_svc_match(struct bt_l2cap_sdp_state_s *sdp,
+                const uint8_t **req, ssize_t *len)
+{
+    size_t datalen;
+    int i;
+
+    if ((**req & ~SDP_DSIZE_MASK) != SDP_DTYPE_UUID)
+        return 1;
+
+    datalen = sdp_datalen(req, len);
+    if (datalen != 2 && datalen != 4 && datalen != 16)
+        return 1;
+
+    for (i = 0; i < sdp->services; i ++)
+        if (sdp_uuid_match(&sdp->service_list[i], *req, datalen))
+            sdp->service_list[i].match = 1;
+
+    (*req) += datalen;
+    (*len) -= datalen;
+
+    return 0;
+}
+
+static ssize_t sdp_svc_search(struct bt_l2cap_sdp_state_s *sdp,
+                uint8_t *rsp, const uint8_t *req, ssize_t len)
+{
+    ssize_t seqlen;
+    int i, count, start, end, max;
+    int32_t handle;
+
+    /* Perform the search */
+    for (i = 0; i < sdp->services; i ++)
+        sdp->service_list[i].match = 0;
+
+    if (len < 1)
+        return -SDP_INVALID_SYNTAX;
+    if ((*req & ~SDP_DSIZE_MASK) == SDP_DTYPE_SEQ) {
+        seqlen = sdp_datalen(&req, &len);
+        if (seqlen < 3 || len < seqlen)
+            return -SDP_INVALID_SYNTAX;
+        len -= seqlen;
+
+        while (seqlen)
+            if (sdp_svc_match(sdp, &req, &seqlen))
+                return -SDP_INVALID_SYNTAX;
+    } else if (sdp_svc_match(sdp, &req, &seqlen))
+        return -SDP_INVALID_SYNTAX;
+
+    if (len < 3)
+        return -SDP_INVALID_SYNTAX;
+    max = (req[0] << 8) | req[1];
+    req += 2;
+    len -= 2;
+
+    if (*req) {
+        if (len <= sizeof(int))
+            return -SDP_INVALID_SYNTAX;
+        len -= sizeof(int);
+        memcpy(&start, req + 1, sizeof(int));
+    } else
+        start = 0;
+
+    if (len > 1)
+        return -SDP_INVALID_SYNTAX;
+
+    /* Output the results */
+    len = 4;
+    count = 0;
+    end = start;
+    for (i = 0; i < sdp->services; i ++)
+        if (sdp->service_list[i].match) {
+            if (count >= start && count < max && len + 4 < MAX_RSP_PARAM_SIZE) {
+                handle = i;
+                memcpy(rsp + len, &handle, 4);
+                len += 4;
+                end = count + 1;
+            }
+
+            count ++;
+        }
+
+    rsp[0] = count >> 8;
+    rsp[1] = count & 0xff;
+    rsp[2] = (end - start) >> 8;
+    rsp[3] = (end - start) & 0xff;
+
+    if (end < count) {
+        rsp[len ++] = sizeof(int);
+        memcpy(rsp + len, &end, sizeof(int));
+        len += 4;
+    } else
+        rsp[len ++] = 0;
+
+    return len;
+}
+
+static int sdp_attr_match(struct sdp_service_record_s *record,
+                const uint8_t **req, ssize_t *len)
+{
+    int i, start, end;
+
+    if (**req == (SDP_DTYPE_UINT | SDP_DSIZE_2)) {
+        (*req) ++;
+        if (*len < 3)
+            return 1;
+
+        start = (*(*req) ++) << 8;
+        start |= *(*req) ++;
+        end = start;
+        *len -= 3;
+    } else if (**req == (SDP_DTYPE_UINT | SDP_DSIZE_4)) {
+        (*req) ++;
+        if (*len < 5)
+            return 1;
+
+        start = (*(*req) ++) << 8;
+        start |= *(*req) ++;
+        end = (*(*req) ++) << 8;
+        end |= *(*req) ++;
+        *len -= 5;
+    } else
+        return 1;
+
+    for (i = 0; i < record->attributes; i ++)
+        if (record->attribute_list[i].attribute_id >= start &&
+                        record->attribute_list[i].attribute_id <= end)
+            record->attribute_list[i].match = 1;
+
+    return 0;
+}
+
+static ssize_t sdp_attr_get(struct bt_l2cap_sdp_state_s *sdp,
+                uint8_t *rsp, const uint8_t *req, ssize_t len)
+{
+    ssize_t seqlen;
+    int i, start, end, max;
+    int32_t handle;
+    struct sdp_service_record_s *record;
+    uint8_t *lst;
+
+    /* Perform the search */
+    if (len < 7)
+        return -SDP_INVALID_SYNTAX;
+    memcpy(&handle, req, 4);
+    req += 4;
+    len -= 4;
+
+    if (handle < 0 || handle > sdp->services)
+        return -SDP_INVALID_RECORD_HANDLE;
+    record = &sdp->service_list[handle];
+
+    for (i = 0; i < record->attributes; i ++)
+        record->attribute_list[i].match = 0;
+
+    max = (req[0] << 8) | req[1];
+    req += 2;
+    len -= 2;
+    if (max < 0x0007)
+        return -SDP_INVALID_SYNTAX;
+
+    if ((*req & ~SDP_DSIZE_MASK) == SDP_DTYPE_SEQ) {
+        seqlen = sdp_datalen(&req, &len);
+        if (seqlen < 3 || len < seqlen)
+            return -SDP_INVALID_SYNTAX;
+        len -= seqlen;
+
+        while (seqlen)
+            if (sdp_attr_match(record, &req, &seqlen))
+                return -SDP_INVALID_SYNTAX;
+    } else if (sdp_attr_match(record, &req, &seqlen))
+        return -SDP_INVALID_SYNTAX;
+
+    if (len < 1)
+        return -SDP_INVALID_SYNTAX;
+
+    if (*req) {
+        if (len <= sizeof(int))
+            return -SDP_INVALID_SYNTAX;
+        len -= sizeof(int);
+        memcpy(&start, req + 1, sizeof(int));
+    } else
+        start = 0;
+
+    if (len > 1)
+        return -SDP_INVALID_SYNTAX;
+
+    /* Output the results */
+    lst = rsp + 2;
+    max = MIN(max, MAX_RSP_PARAM_SIZE);
+    len = 3 - start;
+    end = 0;
+    for (i = 0; i < record->attributes; i ++)
+        if (record->attribute_list[i].match) {
+            if (len >= 0 && len + record->attribute_list[i].len < max) {
+                memcpy(lst + len, record->attribute_list[i].pair,
+                                record->attribute_list[i].len);
+                end = len + record->attribute_list[i].len;
+            }
+            len += record->attribute_list[i].len;
+        }
+    if (0 >= start) {
+       lst[0] = SDP_DTYPE_SEQ | SDP_DSIZE_NEXT2;
+       lst[1] = (len + start - 3) >> 8;
+       lst[2] = (len + start - 3) & 0xff;
+    }
+
+    rsp[0] = end >> 8;
+    rsp[1] = end & 0xff;
+
+    if (end < len) {
+        len = end + start;
+        lst[end ++] = sizeof(int);
+        memcpy(lst + end, &len, sizeof(int));
+        end += sizeof(int);
+    } else
+        lst[end ++] = 0;
+
+    return end + 2;
+}
+
+static int sdp_svc_attr_match(struct bt_l2cap_sdp_state_s *sdp,
+                const uint8_t **req, ssize_t *len)
+{
+    int i, j, start, end;
+    struct sdp_service_record_s *record;
+
+    if (**req == (SDP_DTYPE_UINT | SDP_DSIZE_2)) {
+        (*req) ++;
+        if (*len < 3)
+            return 1;
+
+        start = (*(*req) ++) << 8;
+        start |= *(*req) ++;
+        end = start;
+        *len -= 3;
+    } else if (**req == (SDP_DTYPE_UINT | SDP_DSIZE_4)) {
+        (*req) ++;
+        if (*len < 5)
+            return 1;
+
+        start = (*(*req) ++) << 8;
+        start |= *(*req) ++;
+        end = (*(*req) ++) << 8;
+        end |= *(*req) ++;
+        *len -= 5;
+    } else
+        return 1;
+
+    for (i = 0; i < sdp->services; i ++)
+        if ((record = &sdp->service_list[i])->match)
+            for (j = 0; j < record->attributes; j ++)
+                if (record->attribute_list[j].attribute_id >= start &&
+                                record->attribute_list[j].attribute_id <= end)
+                    record->attribute_list[j].match = 1;
+
+    return 0;
+}
+
+static ssize_t sdp_svc_search_attr_get(struct bt_l2cap_sdp_state_s *sdp,
+                uint8_t *rsp, const uint8_t *req, ssize_t len)
+{
+    ssize_t seqlen;
+    int i, j, start, end, max;
+    struct sdp_service_record_s *record;
+    uint8_t *lst;
+
+    /* Perform the search */
+    for (i = 0; i < sdp->services; i ++) {
+        sdp->service_list[i].match = 0;
+            for (j = 0; j < sdp->service_list[i].attributes; j ++)
+                sdp->service_list[i].attribute_list[j].match = 0;
+    }
+
+    if (len < 1)
+        return -SDP_INVALID_SYNTAX;
+    if ((*req & ~SDP_DSIZE_MASK) == SDP_DTYPE_SEQ) {
+        seqlen = sdp_datalen(&req, &len);
+        if (seqlen < 3 || len < seqlen)
+            return -SDP_INVALID_SYNTAX;
+        len -= seqlen;
+
+        while (seqlen)
+            if (sdp_svc_match(sdp, &req, &seqlen))
+                return -SDP_INVALID_SYNTAX;
+    } else if (sdp_svc_match(sdp, &req, &seqlen))
+        return -SDP_INVALID_SYNTAX;
+
+    if (len < 3)
+        return -SDP_INVALID_SYNTAX;
+    max = (req[0] << 8) | req[1];
+    req += 2;
+    len -= 2;
+    if (max < 0x0007)
+        return -SDP_INVALID_SYNTAX;
+
+    if ((*req & ~SDP_DSIZE_MASK) == SDP_DTYPE_SEQ) {
+        seqlen = sdp_datalen(&req, &len);
+        if (seqlen < 3 || len < seqlen)
+            return -SDP_INVALID_SYNTAX;
+        len -= seqlen;
+
+        while (seqlen)
+            if (sdp_svc_attr_match(sdp, &req, &seqlen))
+                return -SDP_INVALID_SYNTAX;
+    } else if (sdp_svc_attr_match(sdp, &req, &seqlen))
+        return -SDP_INVALID_SYNTAX;
+
+    if (len < 1)
+        return -SDP_INVALID_SYNTAX;
+
+    if (*req) {
+        if (len <= sizeof(int))
+            return -SDP_INVALID_SYNTAX;
+        len -= sizeof(int);
+        memcpy(&start, req + 1, sizeof(int));
+    } else
+        start = 0;
+
+    if (len > 1)
+        return -SDP_INVALID_SYNTAX;
+
+    /* Output the results */
+    /* This assumes empty attribute lists are never to be returned even
+     * for matching Service Records.  In practice this shouldn't happen
+     * as the requestor will usually include the always present
+     * ServiceRecordHandle AttributeID in AttributeIDList.  */
+    lst = rsp + 2;
+    max = MIN(max, MAX_RSP_PARAM_SIZE);
+    len = 3 - start;
+    end = 0;
+    for (i = 0; i < sdp->services; i ++)
+        if ((record = &sdp->service_list[i])->match) {
+            len += 3;
+            seqlen = len;
+            for (j = 0; j < record->attributes; j ++)
+                if (record->attribute_list[j].match) {
+                    if (len >= 0)
+                        if (len + record->attribute_list[j].len < max) {
+                            memcpy(lst + len, record->attribute_list[j].pair,
+                                            record->attribute_list[j].len);
+                            end = len + record->attribute_list[j].len;
+                        }
+                    len += record->attribute_list[j].len;
+                }
+            if (seqlen == len)
+                len -= 3;
+            else if (seqlen >= 3 && seqlen < max) {
+                lst[seqlen - 3] = SDP_DTYPE_SEQ | SDP_DSIZE_NEXT2;
+                lst[seqlen - 2] = (len - seqlen) >> 8;
+                lst[seqlen - 1] = (len - seqlen) & 0xff;
+            }
+        }
+    if (len == 3 - start)
+        len -= 3;
+    else if (0 >= start) {
+       lst[0] = SDP_DTYPE_SEQ | SDP_DSIZE_NEXT2;
+       lst[1] = (len + start - 3) >> 8;
+       lst[2] = (len + start - 3) & 0xff;
+    }
+
+    rsp[0] = end >> 8;
+    rsp[1] = end & 0xff;
+
+    if (end < len) {
+        len = end + start;
+        lst[end ++] = sizeof(int);
+        memcpy(lst + end, &len, sizeof(int));
+        end += sizeof(int);
+    } else
+        lst[end ++] = 0;
+
+    return end + 2;
+}
+
+static void bt_l2cap_sdp_sdu_in(void *opaque, const uint8_t *data, int len)
+{
+    struct bt_l2cap_sdp_state_s *sdp = opaque;
+    enum bt_sdp_cmd pdu_id;
+    uint8_t rsp[MAX_PDU_OUT_SIZE - PDU_HEADER_SIZE], *sdu_out;
+    int transaction_id, plen;
+    int err = 0;
+    int rsp_len = 0;
+
+    if (len < 5) {
+        fprintf(stderr, "%s: short SDP PDU (%iB).\n", __FUNCTION__, len);
+        return;
+    }
+
+    pdu_id = *data ++;
+    transaction_id = (data[0] << 8) | data[1];
+    plen = (data[2] << 8) | data[3];
+    data += 4;
+    len -= 5;
+
+    if (len != plen) {
+        fprintf(stderr, "%s: wrong SDP PDU length (%iB != %iB).\n",
+                        __FUNCTION__, plen, len);
+        err = SDP_INVALID_PDU_SIZE;
+        goto respond;
+    }
+
+    switch (pdu_id) {
+    case SDP_SVC_SEARCH_REQ:
+        rsp_len = sdp_svc_search(sdp, rsp, data, len);
+        pdu_id = SDP_SVC_SEARCH_RSP;
+        break;
+
+    case SDP_SVC_ATTR_REQ:
+        rsp_len = sdp_attr_get(sdp, rsp, data, len);
+        pdu_id = SDP_SVC_ATTR_RSP;
+        break;
+
+    case SDP_SVC_SEARCH_ATTR_REQ:
+        rsp_len = sdp_svc_search_attr_get(sdp, rsp, data, len);
+        pdu_id = SDP_SVC_SEARCH_ATTR_RSP;
+        break;
+
+    case SDP_ERROR_RSP:
+    case SDP_SVC_ATTR_RSP:
+    case SDP_SVC_SEARCH_RSP:
+    case SDP_SVC_SEARCH_ATTR_RSP:
+    default:
+        fprintf(stderr, "%s: unexpected SDP PDU ID %02x.\n",
+                        __FUNCTION__, pdu_id);
+        err = SDP_INVALID_SYNTAX;
+        break;
+    }
+
+    if (rsp_len < 0) {
+        err = -rsp_len;
+        rsp_len = 0;
+    }
+
+respond:
+    if (err) {
+        pdu_id = SDP_ERROR_RSP;
+        rsp[rsp_len ++] = err >> 8;
+        rsp[rsp_len ++] = err & 0xff;
+    }
+
+    sdu_out = sdp->channel->sdu_out(sdp->channel, rsp_len + PDU_HEADER_SIZE);
+
+    sdu_out[0] = pdu_id;
+    sdu_out[1] = transaction_id >> 8;
+    sdu_out[2] = transaction_id & 0xff;
+    sdu_out[3] = rsp_len >> 8;
+    sdu_out[4] = rsp_len & 0xff;
+    memcpy(sdu_out + PDU_HEADER_SIZE, rsp, rsp_len);
+
+    sdp->channel->sdu_submit(sdp->channel);
+}
+
+static void bt_l2cap_sdp_close_ch(void *opaque)
+{
+    struct bt_l2cap_sdp_state_s *sdp = opaque;
+    int i;
+
+    for (i = 0; i < sdp->services; i ++) {
+        g_free(sdp->service_list[i].attribute_list->pair);
+        g_free(sdp->service_list[i].attribute_list);
+        g_free(sdp->service_list[i].uuid);
+    }
+    g_free(sdp->service_list);
+    g_free(sdp);
+}
+
+struct sdp_def_service_s {
+    uint16_t class_uuid;
+    struct sdp_def_attribute_s {
+        uint16_t id;
+        struct sdp_def_data_element_s {
+            uint8_t type;
+            union {
+                uint32_t uint;
+                const char *str;
+                struct sdp_def_data_element_s *list;
+            } value;
+        } data;
+    } attributes[];
+};
+
+/* Calculate a safe byte count to allocate that will store the given
+ * element, at the same time count elements of a UUID type.  */
+static int sdp_attr_max_size(struct sdp_def_data_element_s *element,
+                int *uuids)
+{
+    int type = element->type & ~SDP_DSIZE_MASK;
+    int len;
+
+    if (type == SDP_DTYPE_UINT || type == SDP_DTYPE_UUID ||
+                    type == SDP_DTYPE_BOOL) {
+        if (type == SDP_DTYPE_UUID)
+            (*uuids) ++;
+        return 1 + (1 << (element->type & SDP_DSIZE_MASK));
+    }
+
+    if (type == SDP_DTYPE_STRING || type == SDP_DTYPE_URL) {
+        if (element->type & SDP_DSIZE_MASK) {
+            for (len = 0; element->value.str[len] |
+                            element->value.str[len + 1]; len ++);
+            return len;
+        } else
+            return 2 + strlen(element->value.str);
+    }
+
+    if (type != SDP_DTYPE_SEQ)
+        exit(-1);
+    len = 2;
+    element = element->value.list;
+    while (element->type)
+        len += sdp_attr_max_size(element ++, uuids);
+    if (len > 255)
+        exit (-1);
+
+    return len;
+}
+
+static int sdp_attr_write(uint8_t *data,
+                struct sdp_def_data_element_s *element, int **uuid)
+{
+    int type = element->type & ~SDP_DSIZE_MASK;
+    int len = 0;
+
+    if (type == SDP_DTYPE_UINT || type == SDP_DTYPE_BOOL) {
+        data[len ++] = element->type;
+        if ((element->type & SDP_DSIZE_MASK) == SDP_DSIZE_1)
+            data[len ++] = (element->value.uint >>  0) & 0xff;
+        else if ((element->type & SDP_DSIZE_MASK) == SDP_DSIZE_2) {
+            data[len ++] = (element->value.uint >>  8) & 0xff;
+            data[len ++] = (element->value.uint >>  0) & 0xff;
+        } else if ((element->type & SDP_DSIZE_MASK) == SDP_DSIZE_4) {
+            data[len ++] = (element->value.uint >>  24) & 0xff;
+            data[len ++] = (element->value.uint >>  16) & 0xff;
+            data[len ++] = (element->value.uint >>  8) & 0xff;
+            data[len ++] = (element->value.uint >>  0) & 0xff;
+        }
+
+        return len;
+    }
+
+    if (type == SDP_DTYPE_UUID) {
+        *(*uuid) ++ = element->value.uint;
+
+        data[len ++] = element->type;
+        data[len ++] = (element->value.uint >>  24) & 0xff;
+        data[len ++] = (element->value.uint >>  16) & 0xff;
+        data[len ++] = (element->value.uint >>  8) & 0xff;
+        data[len ++] = (element->value.uint >>  0) & 0xff;
+        memcpy(data + len, bt_base_uuid, 12);
+
+        return len + 12;
+    }
+
+    data[0] = type | SDP_DSIZE_NEXT1;
+    if (type == SDP_DTYPE_STRING || type == SDP_DTYPE_URL) {
+        if (element->type & SDP_DSIZE_MASK)
+            for (len = 0; element->value.str[len] |
+                            element->value.str[len + 1]; len ++);
+        else
+            len = strlen(element->value.str);
+        memcpy(data + 2, element->value.str, data[1] = len);
+
+        return len + 2;
+    }
+
+    len = 2;
+    element = element->value.list;
+    while (element->type)
+        len += sdp_attr_write(data + len, element ++, uuid);
+    data[1] = len - 2;
+
+    return len;
+}
+
+static int sdp_attributeid_compare(const struct sdp_service_attribute_s *a,
+                const struct sdp_service_attribute_s *b)
+{
+    return (int) b->attribute_id - a->attribute_id;
+}
+
+static int sdp_uuid_compare(const int *a, const int *b)
+{
+    return *a - *b;
+}
+
+static void sdp_service_record_build(struct sdp_service_record_s *record,
+                struct sdp_def_service_s *def, int handle)
+{
+    int len = 0;
+    uint8_t *data;
+    int *uuid;
+
+    record->uuids = 0;
+    while (def->attributes[record->attributes].data.type) {
+        len += 3;
+        len += sdp_attr_max_size(&def->attributes[record->attributes ++].data,
+                        &record->uuids);
+    }
+    record->uuids = 1 << ffs(record->uuids - 1);
+    record->attribute_list =
+            g_malloc0(record->attributes * sizeof(*record->attribute_list));
+    record->uuid =
+            g_malloc0(record->uuids * sizeof(*record->uuid));
+    data = g_malloc(len);
+
+    record->attributes = 0;
+    uuid = record->uuid;
+    while (def->attributes[record->attributes].data.type) {
+        record->attribute_list[record->attributes].pair = data;
+
+        len = 0;
+        data[len ++] = SDP_DTYPE_UINT | SDP_DSIZE_2;
+        data[len ++] = def->attributes[record->attributes].id >> 8;
+        data[len ++] = def->attributes[record->attributes].id & 0xff;
+        len += sdp_attr_write(data + len,
+                        &def->attributes[record->attributes].data, &uuid);
+
+        /* Special case: assign a ServiceRecordHandle in sequence */
+        if (def->attributes[record->attributes].id == SDP_ATTR_RECORD_HANDLE)
+            def->attributes[record->attributes].data.value.uint = handle;
+        /* Note: we could also assign a ServiceDescription based on
+         * sdp->device.device->lmp_name.  */
+
+        record->attribute_list[record->attributes ++].len = len;
+        data += len;
+    }
+
+    /* Sort the attribute list by the AttributeID */
+    qsort(record->attribute_list, record->attributes,
+                    sizeof(*record->attribute_list),
+                    (void *) sdp_attributeid_compare);
+    /* Sort the searchable UUIDs list for bisection */
+    qsort(record->uuid, record->uuids,
+                    sizeof(*record->uuid),
+                    (void *) sdp_uuid_compare);
+}
+
+static void sdp_service_db_build(struct bt_l2cap_sdp_state_s *sdp,
+                struct sdp_def_service_s **service)
+{
+    sdp->services = 0;
+    while (service[sdp->services])
+        sdp->services ++;
+    sdp->service_list =
+            g_malloc0(sdp->services * sizeof(*sdp->service_list));
+
+    sdp->services = 0;
+    while (*service) {
+        sdp_service_record_build(&sdp->service_list[sdp->services],
+                        *service, sdp->services);
+        service ++;
+        sdp->services ++;
+    }
+}
+
+#define LAST { .type = 0 }
+#define SERVICE(name, attrs)                           \
+    static struct sdp_def_service_s glue(glue(sdp_service_, name), _s) = { \
+        .attributes = { attrs { .data = LAST } },      \
+    };
+#define ATTRIBUTE(attrid, val) { .id = glue(SDP_ATTR_, attrid), .data = val },
+#define UINT8(val)     {                               \
+        .type       = SDP_DTYPE_UINT | SDP_DSIZE_1,    \
+        .value.uint = val,                             \
+    },
+#define UINT16(val)    {                               \
+        .type       = SDP_DTYPE_UINT | SDP_DSIZE_2,    \
+        .value.uint = val,                             \
+    },
+#define UINT32(val)    {                               \
+        .type       = SDP_DTYPE_UINT | SDP_DSIZE_4,    \
+        .value.uint = val,                             \
+    },
+#define UUID128(val)   {                               \
+        .type       = SDP_DTYPE_UUID | SDP_DSIZE_16,   \
+        .value.uint = val,                             \
+    },
+#define SDP_TRUE       {                               \
+        .type       = SDP_DTYPE_BOOL | SDP_DSIZE_1,    \
+        .value.uint = 1,                               \
+    },
+#define SDP_FALSE      {                               \
+        .type       = SDP_DTYPE_BOOL | SDP_DSIZE_1,    \
+        .value.uint = 0,                               \
+    },
+#define STRING(val)    {                               \
+        .type       = SDP_DTYPE_STRING,                        \
+        .value.str  = val,                             \
+    },
+#define ARRAY(...)     {                               \
+        .type       = SDP_DTYPE_STRING | SDP_DSIZE_2,  \
+        .value.str  = (char []) { __VA_ARGS__, 0, 0 }, \
+    },
+#define URL(val)       {                               \
+        .type       = SDP_DTYPE_URL,                   \
+        .value.str  = val,                             \
+    },
+#if 1
+#define LIST(val)      {                               \
+        .type       = SDP_DTYPE_SEQ,                   \
+        .value.list = (struct sdp_def_data_element_s []) { val LAST }, \
+    },
+#endif
+
+/* Try to keep each single attribute below MAX_PDU_OUT_SIZE bytes
+ * in resulting SDP data representation size.  */
+
+SERVICE(hid,
+    ATTRIBUTE(RECORD_HANDLE,   UINT32(0))      /* Filled in later */
+    ATTRIBUTE(SVCLASS_ID_LIST, LIST(UUID128(HID_SVCLASS_ID)))
+    ATTRIBUTE(RECORD_STATE,    UINT32(1))
+    ATTRIBUTE(PROTO_DESC_LIST, LIST(
+        LIST(UUID128(L2CAP_UUID) UINT16(BT_PSM_HID_CTRL))
+        LIST(UUID128(HIDP_UUID))
+    ))
+    ATTRIBUTE(BROWSE_GRP_LIST, LIST(UUID128(0x1002)))
+    ATTRIBUTE(LANG_BASE_ATTR_ID_LIST, LIST(
+        UINT16(0x656e) UINT16(0x006a) UINT16(0x0100)
+    ))
+    ATTRIBUTE(PFILE_DESC_LIST, LIST(
+        LIST(UUID128(HID_PROFILE_ID) UINT16(0x0100))
+    ))
+    ATTRIBUTE(DOC_URL,         URL("http://bellard.org/qemu/user-doc.html"))
+    ATTRIBUTE(SVCNAME_PRIMARY, STRING("QEMU Bluetooth HID"))
+    ATTRIBUTE(SVCDESC_PRIMARY, STRING("QEMU Keyboard/Mouse"))
+    ATTRIBUTE(SVCPROV_PRIMARY, STRING("QEMU"))
+
+    /* Profile specific */
+    ATTRIBUTE(DEVICE_RELEASE_NUMBER,   UINT16(0x0091)) /* Deprecated, remove */
+    ATTRIBUTE(PARSER_VERSION,          UINT16(0x0111))
+    /* TODO: extract from l2cap_device->device.class[0] */
+    ATTRIBUTE(DEVICE_SUBCLASS,         UINT8(0x40))
+    ATTRIBUTE(COUNTRY_CODE,            UINT8(0x15))
+    ATTRIBUTE(VIRTUAL_CABLE,           SDP_TRUE)
+    ATTRIBUTE(RECONNECT_INITIATE,      SDP_FALSE)
+    /* TODO: extract from hid->usbdev->report_desc */
+    ATTRIBUTE(DESCRIPTOR_LIST,         LIST(
+        LIST(UINT8(0x22) ARRAY(
+            0x05, 0x01,        /* Usage Page (Generic Desktop) */
+            0x09, 0x06,        /* Usage (Keyboard) */
+            0xa1, 0x01,        /* Collection (Application) */
+            0x75, 0x01,        /*   Report Size (1) */
+            0x95, 0x08,        /*   Report Count (8) */
+            0x05, 0x07,        /*   Usage Page (Key Codes) */
+            0x19, 0xe0,        /*   Usage Minimum (224) */
+            0x29, 0xe7,        /*   Usage Maximum (231) */
+            0x15, 0x00,        /*   Logical Minimum (0) */
+            0x25, 0x01,        /*   Logical Maximum (1) */
+            0x81, 0x02,        /*   Input (Data, Variable, Absolute) */
+            0x95, 0x01,        /*   Report Count (1) */
+            0x75, 0x08,        /*   Report Size (8) */
+            0x81, 0x01,        /*   Input (Constant) */
+            0x95, 0x05,        /*   Report Count (5) */
+            0x75, 0x01,        /*   Report Size (1) */
+            0x05, 0x08,        /*   Usage Page (LEDs) */
+            0x19, 0x01,        /*   Usage Minimum (1) */
+            0x29, 0x05,        /*   Usage Maximum (5) */
+            0x91, 0x02,        /*   Output (Data, Variable, Absolute) */
+            0x95, 0x01,        /*   Report Count (1) */
+            0x75, 0x03,        /*   Report Size (3) */
+            0x91, 0x01,        /*   Output (Constant) */
+            0x95, 0x06,        /*   Report Count (6) */
+            0x75, 0x08,        /*   Report Size (8) */
+            0x15, 0x00,        /*   Logical Minimum (0) */
+            0x25, 0xff,        /*   Logical Maximum (255) */
+            0x05, 0x07,        /*   Usage Page (Key Codes) */
+            0x19, 0x00,        /*   Usage Minimum (0) */
+            0x29, 0xff,        /*   Usage Maximum (255) */
+            0x81, 0x00,        /*   Input (Data, Array) */
+            0xc0       /* End Collection */
+    ))))
+    ATTRIBUTE(LANG_ID_BASE_LIST,       LIST(
+        LIST(UINT16(0x0409) UINT16(0x0100))
+    ))
+    ATTRIBUTE(SDP_DISABLE,             SDP_FALSE)
+    ATTRIBUTE(BATTERY_POWER,           SDP_TRUE)
+    ATTRIBUTE(REMOTE_WAKEUP,           SDP_TRUE)
+    ATTRIBUTE(BOOT_DEVICE,             SDP_TRUE)       /* XXX: untested */
+    ATTRIBUTE(SUPERVISION_TIMEOUT,     UINT16(0x0c80))
+    ATTRIBUTE(NORMALLY_CONNECTABLE,    SDP_TRUE)
+    ATTRIBUTE(PROFILE_VERSION,         UINT16(0x0100))
+)
+
+SERVICE(sdp,
+    ATTRIBUTE(RECORD_HANDLE,   UINT32(0))      /* Filled in later */
+    ATTRIBUTE(SVCLASS_ID_LIST, LIST(UUID128(SDP_SERVER_SVCLASS_ID)))
+    ATTRIBUTE(RECORD_STATE,    UINT32(1))
+    ATTRIBUTE(PROTO_DESC_LIST, LIST(
+        LIST(UUID128(L2CAP_UUID) UINT16(BT_PSM_SDP))
+        LIST(UUID128(SDP_UUID))
+    ))
+    ATTRIBUTE(BROWSE_GRP_LIST, LIST(UUID128(0x1002)))
+    ATTRIBUTE(LANG_BASE_ATTR_ID_LIST, LIST(
+        UINT16(0x656e) UINT16(0x006a) UINT16(0x0100)
+    ))
+    ATTRIBUTE(PFILE_DESC_LIST, LIST(
+        LIST(UUID128(SDP_SERVER_PROFILE_ID) UINT16(0x0100))
+    ))
+    ATTRIBUTE(DOC_URL,         URL("http://bellard.org/qemu/user-doc.html"))
+    ATTRIBUTE(SVCPROV_PRIMARY, STRING("QEMU"))
+
+    /* Profile specific */
+    ATTRIBUTE(VERSION_NUM_LIST, LIST(UINT16(0x0100)))
+    ATTRIBUTE(SVCDB_STATE    , UINT32(1))
+)
+
+SERVICE(pnp,
+    ATTRIBUTE(RECORD_HANDLE,   UINT32(0))      /* Filled in later */
+    ATTRIBUTE(SVCLASS_ID_LIST, LIST(UUID128(PNP_INFO_SVCLASS_ID)))
+    ATTRIBUTE(RECORD_STATE,    UINT32(1))
+    ATTRIBUTE(PROTO_DESC_LIST, LIST(
+        LIST(UUID128(L2CAP_UUID) UINT16(BT_PSM_SDP))
+        LIST(UUID128(SDP_UUID))
+    ))
+    ATTRIBUTE(BROWSE_GRP_LIST, LIST(UUID128(0x1002)))
+    ATTRIBUTE(LANG_BASE_ATTR_ID_LIST, LIST(
+        UINT16(0x656e) UINT16(0x006a) UINT16(0x0100)
+    ))
+    ATTRIBUTE(PFILE_DESC_LIST, LIST(
+        LIST(UUID128(PNP_INFO_PROFILE_ID) UINT16(0x0100))
+    ))
+    ATTRIBUTE(DOC_URL,         URL("http://bellard.org/qemu/user-doc.html"))
+    ATTRIBUTE(SVCPROV_PRIMARY, STRING("QEMU"))
+
+    /* Profile specific */
+    ATTRIBUTE(SPECIFICATION_ID, UINT16(0x0100))
+    ATTRIBUTE(VERSION,         UINT16(0x0100))
+    ATTRIBUTE(PRIMARY_RECORD,  SDP_TRUE)
+)
+
+static int bt_l2cap_sdp_new_ch(struct bt_l2cap_device_s *dev,
+                struct bt_l2cap_conn_params_s *params)
+{
+    struct bt_l2cap_sdp_state_s *sdp = g_malloc0(sizeof(*sdp));
+    struct sdp_def_service_s *services[] = {
+        &sdp_service_sdp_s,
+        &sdp_service_hid_s,
+        &sdp_service_pnp_s,
+        NULL,
+    };
+
+    sdp->channel = params;
+    sdp->channel->opaque = sdp;
+    sdp->channel->close = bt_l2cap_sdp_close_ch;
+    sdp->channel->sdu_in = bt_l2cap_sdp_sdu_in;
+
+    sdp_service_db_build(sdp, services);
+
+    return 0;
+}
+
+void bt_l2cap_sdp_init(struct bt_l2cap_device_s *dev)
+{
+    bt_l2cap_psm_register(dev, BT_PSM_SDP,
+                    MAX_PDU_OUT_SIZE, bt_l2cap_sdp_new_ch);
+}
diff --git a/hw/cadence_gem.c b/hw/cadence_gem.c
deleted file mode 100644 (file)
index e177057..0000000
+++ /dev/null
@@ -1,1219 +0,0 @@
-/*
- * QEMU Xilinx GEM emulation
- *
- * Copyright (c) 2011 Xilinx, 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 <zlib.h> /* For crc32 */
-
-#include "hw/sysbus.h"
-#include "net/net.h"
-#include "net/checksum.h"
-
-#ifdef CADENCE_GEM_ERR_DEBUG
-#define DB_PRINT(...) do { \
-    fprintf(stderr,  ": %s: ", __func__); \
-    fprintf(stderr, ## __VA_ARGS__); \
-    } while (0);
-#else
-    #define DB_PRINT(...)
-#endif
-
-#define GEM_NWCTRL        (0x00000000/4) /* Network Control reg */
-#define GEM_NWCFG         (0x00000004/4) /* Network Config reg */
-#define GEM_NWSTATUS      (0x00000008/4) /* Network Status reg */
-#define GEM_USERIO        (0x0000000C/4) /* User IO reg */
-#define GEM_DMACFG        (0x00000010/4) /* DMA Control reg */
-#define GEM_TXSTATUS      (0x00000014/4) /* TX Status reg */
-#define GEM_RXQBASE       (0x00000018/4) /* RX Q Base address reg */
-#define GEM_TXQBASE       (0x0000001C/4) /* TX Q Base address reg */
-#define GEM_RXSTATUS      (0x00000020/4) /* RX Status reg */
-#define GEM_ISR           (0x00000024/4) /* Interrupt Status reg */
-#define GEM_IER           (0x00000028/4) /* Interrupt Enable reg */
-#define GEM_IDR           (0x0000002C/4) /* Interrupt Disable reg */
-#define GEM_IMR           (0x00000030/4) /* Interrupt Mask reg */
-#define GEM_PHYMNTNC      (0x00000034/4) /* Phy Maintaince reg */
-#define GEM_RXPAUSE       (0x00000038/4) /* RX Pause Time reg */
-#define GEM_TXPAUSE       (0x0000003C/4) /* TX Pause Time reg */
-#define GEM_TXPARTIALSF   (0x00000040/4) /* TX Partial Store and Forward */
-#define GEM_RXPARTIALSF   (0x00000044/4) /* RX Partial Store and Forward */
-#define GEM_HASHLO        (0x00000080/4) /* Hash Low address reg */
-#define GEM_HASHHI        (0x00000084/4) /* Hash High address reg */
-#define GEM_SPADDR1LO     (0x00000088/4) /* Specific addr 1 low reg */
-#define GEM_SPADDR1HI     (0x0000008C/4) /* Specific addr 1 high reg */
-#define GEM_SPADDR2LO     (0x00000090/4) /* Specific addr 2 low reg */
-#define GEM_SPADDR2HI     (0x00000094/4) /* Specific addr 2 high reg */
-#define GEM_SPADDR3LO     (0x00000098/4) /* Specific addr 3 low reg */
-#define GEM_SPADDR3HI     (0x0000009C/4) /* Specific addr 3 high reg */
-#define GEM_SPADDR4LO     (0x000000A0/4) /* Specific addr 4 low reg */
-#define GEM_SPADDR4HI     (0x000000A4/4) /* Specific addr 4 high reg */
-#define GEM_TIDMATCH1     (0x000000A8/4) /* Type ID1 Match reg */
-#define GEM_TIDMATCH2     (0x000000AC/4) /* Type ID2 Match reg */
-#define GEM_TIDMATCH3     (0x000000B0/4) /* Type ID3 Match reg */
-#define GEM_TIDMATCH4     (0x000000B4/4) /* Type ID4 Match reg */
-#define GEM_WOLAN         (0x000000B8/4) /* Wake on LAN reg */
-#define GEM_IPGSTRETCH    (0x000000BC/4) /* IPG Stretch reg */
-#define GEM_SVLAN         (0x000000C0/4) /* Stacked VLAN reg */
-#define GEM_MODID         (0x000000FC/4) /* Module ID reg */
-#define GEM_OCTTXLO       (0x00000100/4) /* Octects transmitted Low reg */
-#define GEM_OCTTXHI       (0x00000104/4) /* Octects transmitted High reg */
-#define GEM_TXCNT         (0x00000108/4) /* Error-free Frames transmitted */
-#define GEM_TXBCNT        (0x0000010C/4) /* Error-free Broadcast Frames */
-#define GEM_TXMCNT        (0x00000110/4) /* Error-free Multicast Frame */
-#define GEM_TXPAUSECNT    (0x00000114/4) /* Pause Frames Transmitted */
-#define GEM_TX64CNT       (0x00000118/4) /* Error-free 64 TX */
-#define GEM_TX65CNT       (0x0000011C/4) /* Error-free 65-127 TX */
-#define GEM_TX128CNT      (0x00000120/4) /* Error-free 128-255 TX */
-#define GEM_TX256CNT      (0x00000124/4) /* Error-free 256-511 */
-#define GEM_TX512CNT      (0x00000128/4) /* Error-free 512-1023 TX */
-#define GEM_TX1024CNT     (0x0000012C/4) /* Error-free 1024-1518 TX */
-#define GEM_TX1519CNT     (0x00000130/4) /* Error-free larger than 1519 TX */
-#define GEM_TXURUNCNT     (0x00000134/4) /* TX under run error counter */
-#define GEM_SINGLECOLLCNT (0x00000138/4) /* Single Collision Frames */
-#define GEM_MULTCOLLCNT   (0x0000013C/4) /* Multiple Collision Frames */
-#define GEM_EXCESSCOLLCNT (0x00000140/4) /* Excessive Collision Frames */
-#define GEM_LATECOLLCNT   (0x00000144/4) /* Late Collision Frames */
-#define GEM_DEFERTXCNT    (0x00000148/4) /* Deferred Transmission Frames */
-#define GEM_CSENSECNT     (0x0000014C/4) /* Carrier Sense Error Counter */
-#define GEM_OCTRXLO       (0x00000150/4) /* Octects Received register Low */
-#define GEM_OCTRXHI       (0x00000154/4) /* Octects Received register High */
-#define GEM_RXCNT         (0x00000158/4) /* Error-free Frames Received */
-#define GEM_RXBROADCNT    (0x0000015C/4) /* Error-free Broadcast Frames RX */
-#define GEM_RXMULTICNT    (0x00000160/4) /* Error-free Multicast Frames RX */
-#define GEM_RXPAUSECNT    (0x00000164/4) /* Pause Frames Received Counter */
-#define GEM_RX64CNT       (0x00000168/4) /* Error-free 64 byte Frames RX */
-#define GEM_RX65CNT       (0x0000016C/4) /* Error-free 65-127B Frames RX */
-#define GEM_RX128CNT      (0x00000170/4) /* Error-free 128-255B Frames RX */
-#define GEM_RX256CNT      (0x00000174/4) /* Error-free 256-512B Frames RX */
-#define GEM_RX512CNT      (0x00000178/4) /* Error-free 512-1023B Frames RX */
-#define GEM_RX1024CNT     (0x0000017C/4) /* Error-free 1024-1518B Frames RX */
-#define GEM_RX1519CNT     (0x00000180/4) /* Error-free 1519-max Frames RX */
-#define GEM_RXUNDERCNT    (0x00000184/4) /* Undersize Frames Received */
-#define GEM_RXOVERCNT     (0x00000188/4) /* Oversize Frames Received */
-#define GEM_RXJABCNT      (0x0000018C/4) /* Jabbers Received Counter */
-#define GEM_RXFCSCNT      (0x00000190/4) /* Frame Check seq. Error Counter */
-#define GEM_RXLENERRCNT   (0x00000194/4) /* Length Field Error Counter */
-#define GEM_RXSYMERRCNT   (0x00000198/4) /* Symbol Error Counter */
-#define GEM_RXALIGNERRCNT (0x0000019C/4) /* Alignment Error Counter */
-#define GEM_RXRSCERRCNT   (0x000001A0/4) /* Receive Resource Error Counter */
-#define GEM_RXORUNCNT     (0x000001A4/4) /* Receive Overrun Counter */
-#define GEM_RXIPCSERRCNT  (0x000001A8/4) /* IP header Checksum Error Counter */
-#define GEM_RXTCPCCNT     (0x000001AC/4) /* TCP Checksum Error Counter */
-#define GEM_RXUDPCCNT     (0x000001B0/4) /* UDP Checksum Error Counter */
-
-#define GEM_1588S         (0x000001D0/4) /* 1588 Timer Seconds */
-#define GEM_1588NS        (0x000001D4/4) /* 1588 Timer Nanoseconds */
-#define GEM_1588ADJ       (0x000001D8/4) /* 1588 Timer Adjust */
-#define GEM_1588INC       (0x000001DC/4) /* 1588 Timer Increment */
-#define GEM_PTPETXS       (0x000001E0/4) /* PTP Event Frame Transmitted (s) */
-#define GEM_PTPETXNS      (0x000001E4/4) /* PTP Event Frame Transmitted (ns) */
-#define GEM_PTPERXS       (0x000001E8/4) /* PTP Event Frame Received (s) */
-#define GEM_PTPERXNS      (0x000001EC/4) /* PTP Event Frame Received (ns) */
-#define GEM_PTPPTXS       (0x000001E0/4) /* PTP Peer Frame Transmitted (s) */
-#define GEM_PTPPTXNS      (0x000001E4/4) /* PTP Peer Frame Transmitted (ns) */
-#define GEM_PTPPRXS       (0x000001E8/4) /* PTP Peer Frame Received (s) */
-#define GEM_PTPPRXNS      (0x000001EC/4) /* PTP Peer Frame Received (ns) */
-
-/* Design Configuration Registers */
-#define GEM_DESCONF       (0x00000280/4)
-#define GEM_DESCONF2      (0x00000284/4)
-#define GEM_DESCONF3      (0x00000288/4)
-#define GEM_DESCONF4      (0x0000028C/4)
-#define GEM_DESCONF5      (0x00000290/4)
-#define GEM_DESCONF6      (0x00000294/4)
-#define GEM_DESCONF7      (0x00000298/4)
-
-#define GEM_MAXREG        (0x00000640/4) /* Last valid GEM address */
-
-/*****************************************/
-#define GEM_NWCTRL_TXSTART     0x00000200 /* Transmit Enable */
-#define GEM_NWCTRL_TXENA       0x00000008 /* Transmit Enable */
-#define GEM_NWCTRL_RXENA       0x00000004 /* Receive Enable */
-#define GEM_NWCTRL_LOCALLOOP   0x00000002 /* Local Loopback */
-
-#define GEM_NWCFG_STRIP_FCS    0x00020000 /* Strip FCS field */
-#define GEM_NWCFG_LERR_DISC    0x00010000 /* Discard RX frames with lenth err */
-#define GEM_NWCFG_BUFF_OFST_M  0x0000C000 /* Receive buffer offset mask */
-#define GEM_NWCFG_BUFF_OFST_S  14         /* Receive buffer offset shift */
-#define GEM_NWCFG_UCAST_HASH   0x00000080 /* accept unicast if hash match */
-#define GEM_NWCFG_MCAST_HASH   0x00000040 /* accept multicast if hash match */
-#define GEM_NWCFG_BCAST_REJ    0x00000020 /* Reject broadcast packets */
-#define GEM_NWCFG_PROMISC      0x00000010 /* Accept all packets */
-
-#define GEM_DMACFG_RBUFSZ_M    0x007F0000 /* DMA RX Buffer Size mask */
-#define GEM_DMACFG_RBUFSZ_S    16         /* DMA RX Buffer Size shift */
-#define GEM_DMACFG_RBUFSZ_MUL  64         /* DMA RX Buffer Size multiplier */
-#define GEM_DMACFG_TXCSUM_OFFL 0x00000800 /* Transmit checksum offload */
-
-#define GEM_TXSTATUS_TXCMPL    0x00000020 /* Transmit Complete */
-#define GEM_TXSTATUS_USED      0x00000001 /* sw owned descriptor encountered */
-
-#define GEM_RXSTATUS_FRMRCVD   0x00000002 /* Frame received */
-#define GEM_RXSTATUS_NOBUF     0x00000001 /* Buffer unavailable */
-
-/* GEM_ISR GEM_IER GEM_IDR GEM_IMR */
-#define GEM_INT_TXCMPL        0x00000080 /* Transmit Complete */
-#define GEM_INT_TXUSED         0x00000008
-#define GEM_INT_RXUSED         0x00000004
-#define GEM_INT_RXCMPL        0x00000002
-
-#define GEM_PHYMNTNC_OP_R      0x20000000 /* read operation */
-#define GEM_PHYMNTNC_OP_W      0x10000000 /* write operation */
-#define GEM_PHYMNTNC_ADDR      0x0F800000 /* Address bits */
-#define GEM_PHYMNTNC_ADDR_SHFT 23
-#define GEM_PHYMNTNC_REG       0x007C0000 /* register bits */
-#define GEM_PHYMNTNC_REG_SHIFT 18
-
-/* Marvell PHY definitions */
-#define BOARD_PHY_ADDRESS    23 /* PHY address we will emulate a device at */
-
-#define PHY_REG_CONTROL      0
-#define PHY_REG_STATUS       1
-#define PHY_REG_PHYID1       2
-#define PHY_REG_PHYID2       3
-#define PHY_REG_ANEGADV      4
-#define PHY_REG_LINKPABIL    5
-#define PHY_REG_ANEGEXP      6
-#define PHY_REG_NEXTP        7
-#define PHY_REG_LINKPNEXTP   8
-#define PHY_REG_100BTCTRL    9
-#define PHY_REG_1000BTSTAT   10
-#define PHY_REG_EXTSTAT      15
-#define PHY_REG_PHYSPCFC_CTL 16
-#define PHY_REG_PHYSPCFC_ST  17
-#define PHY_REG_INT_EN       18
-#define PHY_REG_INT_ST       19
-#define PHY_REG_EXT_PHYSPCFC_CTL  20
-#define PHY_REG_RXERR        21
-#define PHY_REG_EACD         22
-#define PHY_REG_LED          24
-#define PHY_REG_LED_OVRD     25
-#define PHY_REG_EXT_PHYSPCFC_CTL2 26
-#define PHY_REG_EXT_PHYSPCFC_ST   27
-#define PHY_REG_CABLE_DIAG   28
-
-#define PHY_REG_CONTROL_RST  0x8000
-#define PHY_REG_CONTROL_LOOP 0x4000
-#define PHY_REG_CONTROL_ANEG 0x1000
-
-#define PHY_REG_STATUS_LINK     0x0004
-#define PHY_REG_STATUS_ANEGCMPL 0x0020
-
-#define PHY_REG_INT_ST_ANEGCMPL 0x0800
-#define PHY_REG_INT_ST_LINKC    0x0400
-#define PHY_REG_INT_ST_ENERGY   0x0010
-
-/***********************************************************************/
-#define GEM_RX_REJECT  1
-#define GEM_RX_ACCEPT  0
-
-/***********************************************************************/
-
-#define DESC_1_USED 0x80000000
-#define DESC_1_LENGTH 0x00001FFF
-
-#define DESC_1_TX_WRAP 0x40000000
-#define DESC_1_TX_LAST 0x00008000
-
-#define DESC_0_RX_WRAP 0x00000002
-#define DESC_0_RX_OWNERSHIP 0x00000001
-
-#define DESC_1_RX_SOF 0x00004000
-#define DESC_1_RX_EOF 0x00008000
-
-static inline unsigned tx_desc_get_buffer(unsigned *desc)
-{
-    return desc[0];
-}
-
-static inline unsigned tx_desc_get_used(unsigned *desc)
-{
-    return (desc[1] & DESC_1_USED) ? 1 : 0;
-}
-
-static inline void tx_desc_set_used(unsigned *desc)
-{
-    desc[1] |= DESC_1_USED;
-}
-
-static inline unsigned tx_desc_get_wrap(unsigned *desc)
-{
-    return (desc[1] & DESC_1_TX_WRAP) ? 1 : 0;
-}
-
-static inline unsigned tx_desc_get_last(unsigned *desc)
-{
-    return (desc[1] & DESC_1_TX_LAST) ? 1 : 0;
-}
-
-static inline unsigned tx_desc_get_length(unsigned *desc)
-{
-    return desc[1] & DESC_1_LENGTH;
-}
-
-static inline void print_gem_tx_desc(unsigned *desc)
-{
-    DB_PRINT("TXDESC:\n");
-    DB_PRINT("bufaddr: 0x%08x\n", *desc);
-    DB_PRINT("used_hw: %d\n", tx_desc_get_used(desc));
-    DB_PRINT("wrap:    %d\n", tx_desc_get_wrap(desc));
-    DB_PRINT("last:    %d\n", tx_desc_get_last(desc));
-    DB_PRINT("length:  %d\n", tx_desc_get_length(desc));
-}
-
-static inline unsigned rx_desc_get_buffer(unsigned *desc)
-{
-    return desc[0] & ~0x3UL;
-}
-
-static inline unsigned rx_desc_get_wrap(unsigned *desc)
-{
-    return desc[0] & DESC_0_RX_WRAP ? 1 : 0;
-}
-
-static inline unsigned rx_desc_get_ownership(unsigned *desc)
-{
-    return desc[0] & DESC_0_RX_OWNERSHIP ? 1 : 0;
-}
-
-static inline void rx_desc_set_ownership(unsigned *desc)
-{
-    desc[0] |= DESC_0_RX_OWNERSHIP;
-}
-
-static inline void rx_desc_set_sof(unsigned *desc)
-{
-    desc[1] |= DESC_1_RX_SOF;
-}
-
-static inline void rx_desc_set_eof(unsigned *desc)
-{
-    desc[1] |= DESC_1_RX_EOF;
-}
-
-static inline void rx_desc_set_length(unsigned *desc, unsigned len)
-{
-    desc[1] &= ~DESC_1_LENGTH;
-    desc[1] |= len;
-}
-
-typedef struct {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-    NICState *nic;
-    NICConf conf;
-    qemu_irq irq;
-
-    /* GEM registers backing store */
-    uint32_t regs[GEM_MAXREG];
-    /* Mask of register bits which are write only */
-    uint32_t regs_wo[GEM_MAXREG];
-    /* Mask of register bits which are read only */
-    uint32_t regs_ro[GEM_MAXREG];
-    /* Mask of register bits which are clear on read */
-    uint32_t regs_rtc[GEM_MAXREG];
-    /* Mask of register bits which are write 1 to clear */
-    uint32_t regs_w1c[GEM_MAXREG];
-
-    /* PHY registers backing store */
-    uint16_t phy_regs[32];
-
-    uint8_t phy_loop; /* Are we in phy loopback? */
-
-    /* The current DMA descriptor pointers */
-    uint32_t rx_desc_addr;
-    uint32_t tx_desc_addr;
-
-} GemState;
-
-/* The broadcast MAC address: 0xFFFFFFFFFFFF */
-const uint8_t broadcast_addr[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
-
-/*
- * gem_init_register_masks:
- * One time initialization.
- * Set masks to identify which register bits have magical clear properties
- */
-static void gem_init_register_masks(GemState *s)
-{
-    /* Mask of register bits which are read only*/
-    memset(&s->regs_ro[0], 0, sizeof(s->regs_ro));
-    s->regs_ro[GEM_NWCTRL]   = 0xFFF80000;
-    s->regs_ro[GEM_NWSTATUS] = 0xFFFFFFFF;
-    s->regs_ro[GEM_DMACFG]   = 0xFE00F000;
-    s->regs_ro[GEM_TXSTATUS] = 0xFFFFFE08;
-    s->regs_ro[GEM_RXQBASE]  = 0x00000003;
-    s->regs_ro[GEM_TXQBASE]  = 0x00000003;
-    s->regs_ro[GEM_RXSTATUS] = 0xFFFFFFF0;
-    s->regs_ro[GEM_ISR]      = 0xFFFFFFFF;
-    s->regs_ro[GEM_IMR]      = 0xFFFFFFFF;
-    s->regs_ro[GEM_MODID]    = 0xFFFFFFFF;
-
-    /* Mask of register bits which are clear on read */
-    memset(&s->regs_rtc[0], 0, sizeof(s->regs_rtc));
-    s->regs_rtc[GEM_ISR]      = 0xFFFFFFFF;
-
-    /* Mask of register bits which are write 1 to clear */
-    memset(&s->regs_w1c[0], 0, sizeof(s->regs_w1c));
-    s->regs_w1c[GEM_TXSTATUS] = 0x000001F7;
-    s->regs_w1c[GEM_RXSTATUS] = 0x0000000F;
-
-    /* Mask of register bits which are write only */
-    memset(&s->regs_wo[0], 0, sizeof(s->regs_wo));
-    s->regs_wo[GEM_NWCTRL]   = 0x00073E60;
-    s->regs_wo[GEM_IER]      = 0x07FFFFFF;
-    s->regs_wo[GEM_IDR]      = 0x07FFFFFF;
-}
-
-/*
- * phy_update_link:
- * Make the emulated PHY link state match the QEMU "interface" state.
- */
-static void phy_update_link(GemState *s)
-{
-    DB_PRINT("down %d\n", qemu_get_queue(s->nic)->link_down);
-
-    /* Autonegotiation status mirrors link status.  */
-    if (qemu_get_queue(s->nic)->link_down) {
-        s->phy_regs[PHY_REG_STATUS] &= ~(PHY_REG_STATUS_ANEGCMPL |
-                                         PHY_REG_STATUS_LINK);
-        s->phy_regs[PHY_REG_INT_ST] |= PHY_REG_INT_ST_LINKC;
-    } else {
-        s->phy_regs[PHY_REG_STATUS] |= (PHY_REG_STATUS_ANEGCMPL |
-                                         PHY_REG_STATUS_LINK);
-        s->phy_regs[PHY_REG_INT_ST] |= (PHY_REG_INT_ST_LINKC |
-                                        PHY_REG_INT_ST_ANEGCMPL |
-                                        PHY_REG_INT_ST_ENERGY);
-    }
-}
-
-static int gem_can_receive(NetClientState *nc)
-{
-    GemState *s;
-
-    s = qemu_get_nic_opaque(nc);
-
-    DB_PRINT("\n");
-
-    /* Do nothing if receive is not enabled. */
-    if (!(s->regs[GEM_NWCTRL] & GEM_NWCTRL_RXENA)) {
-        return 0;
-    }
-
-    return 1;
-}
-
-/*
- * gem_update_int_status:
- * Raise or lower interrupt based on current status.
- */
-static void gem_update_int_status(GemState *s)
-{
-    if (s->regs[GEM_ISR]) {
-        DB_PRINT("asserting int. (0x%08x)\n", s->regs[GEM_ISR]);
-        qemu_set_irq(s->irq, 1);
-    }
-}
-
-/*
- * gem_receive_updatestats:
- * Increment receive statistics.
- */
-static void gem_receive_updatestats(GemState *s, const uint8_t *packet,
-                                    unsigned bytes)
-{
-    uint64_t octets;
-
-    /* Total octets (bytes) received */
-    octets = ((uint64_t)(s->regs[GEM_OCTRXLO]) << 32) |
-             s->regs[GEM_OCTRXHI];
-    octets += bytes;
-    s->regs[GEM_OCTRXLO] = octets >> 32;
-    s->regs[GEM_OCTRXHI] = octets;
-
-    /* Error-free Frames received */
-    s->regs[GEM_RXCNT]++;
-
-    /* Error-free Broadcast Frames counter */
-    if (!memcmp(packet, broadcast_addr, 6)) {
-        s->regs[GEM_RXBROADCNT]++;
-    }
-
-    /* Error-free Multicast Frames counter */
-    if (packet[0] == 0x01) {
-        s->regs[GEM_RXMULTICNT]++;
-    }
-
-    if (bytes <= 64) {
-        s->regs[GEM_RX64CNT]++;
-    } else if (bytes <= 127) {
-        s->regs[GEM_RX65CNT]++;
-    } else if (bytes <= 255) {
-        s->regs[GEM_RX128CNT]++;
-    } else if (bytes <= 511) {
-        s->regs[GEM_RX256CNT]++;
-    } else if (bytes <= 1023) {
-        s->regs[GEM_RX512CNT]++;
-    } else if (bytes <= 1518) {
-        s->regs[GEM_RX1024CNT]++;
-    } else {
-        s->regs[GEM_RX1519CNT]++;
-    }
-}
-
-/*
- * Get the MAC Address bit from the specified position
- */
-static unsigned get_bit(const uint8_t *mac, unsigned bit)
-{
-    unsigned byte;
-
-    byte = mac[bit / 8];
-    byte >>= (bit & 0x7);
-    byte &= 1;
-
-    return byte;
-}
-
-/*
- * Calculate a GEM MAC Address hash index
- */
-static unsigned calc_mac_hash(const uint8_t *mac)
-{
-    int index_bit, mac_bit;
-    unsigned hash_index;
-
-    hash_index = 0;
-    mac_bit = 5;
-    for (index_bit = 5; index_bit >= 0; index_bit--) {
-        hash_index |= (get_bit(mac,  mac_bit) ^
-                               get_bit(mac, mac_bit + 6) ^
-                               get_bit(mac, mac_bit + 12) ^
-                               get_bit(mac, mac_bit + 18) ^
-                               get_bit(mac, mac_bit + 24) ^
-                               get_bit(mac, mac_bit + 30) ^
-                               get_bit(mac, mac_bit + 36) ^
-                               get_bit(mac, mac_bit + 42)) << index_bit;
-        mac_bit--;
-    }
-
-    return hash_index;
-}
-
-/*
- * gem_mac_address_filter:
- * Accept or reject this destination address?
- * Returns:
- * GEM_RX_REJECT: reject
- * GEM_RX_ACCEPT: accept
- */
-static int gem_mac_address_filter(GemState *s, const uint8_t *packet)
-{
-    uint8_t *gem_spaddr;
-    int i;
-
-    /* Promiscuous mode? */
-    if (s->regs[GEM_NWCFG] & GEM_NWCFG_PROMISC) {
-        return GEM_RX_ACCEPT;
-    }
-
-    if (!memcmp(packet, broadcast_addr, 6)) {
-        /* Reject broadcast packets? */
-        if (s->regs[GEM_NWCFG] & GEM_NWCFG_BCAST_REJ) {
-            return GEM_RX_REJECT;
-        }
-        return GEM_RX_ACCEPT;
-    }
-
-    /* Accept packets -w- hash match? */
-    if ((packet[0] == 0x01 && (s->regs[GEM_NWCFG] & GEM_NWCFG_MCAST_HASH)) ||
-        (packet[0] != 0x01 && (s->regs[GEM_NWCFG] & GEM_NWCFG_UCAST_HASH))) {
-        unsigned hash_index;
-
-        hash_index = calc_mac_hash(packet);
-        if (hash_index < 32) {
-            if (s->regs[GEM_HASHLO] & (1<<hash_index)) {
-                return GEM_RX_ACCEPT;
-            }
-        } else {
-            hash_index -= 32;
-            if (s->regs[GEM_HASHHI] & (1<<hash_index)) {
-                return GEM_RX_ACCEPT;
-            }
-        }
-    }
-
-    /* Check all 4 specific addresses */
-    gem_spaddr = (uint8_t *)&(s->regs[GEM_SPADDR1LO]);
-    for (i = 0; i < 4; i++) {
-        if (!memcmp(packet, gem_spaddr, 6)) {
-            return GEM_RX_ACCEPT;
-        }
-
-        gem_spaddr += 8;
-    }
-
-    /* No address match; reject the packet */
-    return GEM_RX_REJECT;
-}
-
-/*
- * gem_receive:
- * Fit a packet handed to us by QEMU into the receive descriptor ring.
- */
-static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size)
-{
-    unsigned    desc[2];
-    hwaddr packet_desc_addr, last_desc_addr;
-    GemState *s;
-    unsigned   rxbufsize, bytes_to_copy;
-    unsigned   rxbuf_offset;
-    uint8_t    rxbuf[2048];
-    uint8_t   *rxbuf_ptr;
-
-    s = qemu_get_nic_opaque(nc);
-
-    /* Do nothing if receive is not enabled. */
-    if (!gem_can_receive(nc)) {
-        return -1;
-    }
-
-    /* Is this destination MAC address "for us" ? */
-    if (gem_mac_address_filter(s, buf) == GEM_RX_REJECT) {
-        return -1;
-    }
-
-    /* Discard packets with receive length error enabled ? */
-    if (s->regs[GEM_NWCFG] & GEM_NWCFG_LERR_DISC) {
-        unsigned type_len;
-
-        /* Fish the ethertype / length field out of the RX packet */
-        type_len = buf[12] << 8 | buf[13];
-        /* It is a length field, not an ethertype */
-        if (type_len < 0x600) {
-            if (size < type_len) {
-                /* discard */
-                return -1;
-            }
-        }
-    }
-
-    /*
-     * Determine configured receive buffer offset (probably 0)
-     */
-    rxbuf_offset = (s->regs[GEM_NWCFG] & GEM_NWCFG_BUFF_OFST_M) >>
-                   GEM_NWCFG_BUFF_OFST_S;
-
-    /* The configure size of each receive buffer.  Determines how many
-     * buffers needed to hold this packet.
-     */
-    rxbufsize = ((s->regs[GEM_DMACFG] & GEM_DMACFG_RBUFSZ_M) >>
-                 GEM_DMACFG_RBUFSZ_S) * GEM_DMACFG_RBUFSZ_MUL;
-    bytes_to_copy = size;
-
-    /* Strip of FCS field ? (usually yes) */
-    if (s->regs[GEM_NWCFG] & GEM_NWCFG_STRIP_FCS) {
-        rxbuf_ptr = (void *)buf;
-    } else {
-        unsigned crc_val;
-        int      crc_offset;
-
-        /* The application wants the FCS field, which QEMU does not provide.
-         * We must try and caclculate one.
-         */
-
-        memcpy(rxbuf, buf, size);
-        memset(rxbuf + size, 0, sizeof(rxbuf) - size);
-        rxbuf_ptr = rxbuf;
-        crc_val = cpu_to_le32(crc32(0, rxbuf, MAX(size, 60)));
-        if (size < 60) {
-            crc_offset = 60;
-        } else {
-            crc_offset = size;
-        }
-        memcpy(rxbuf + crc_offset, &crc_val, sizeof(crc_val));
-
-        bytes_to_copy += 4;
-        size += 4;
-    }
-
-    /* Pad to minimum length */
-    if (size < 64) {
-        size = 64;
-    }
-
-    DB_PRINT("config bufsize: %d packet size: %ld\n", rxbufsize, size);
-
-    packet_desc_addr = s->rx_desc_addr;
-    while (1) {
-        DB_PRINT("read descriptor 0x%x\n", (unsigned)packet_desc_addr);
-        /* read current descriptor */
-        cpu_physical_memory_read(packet_desc_addr,
-                                 (uint8_t *)&desc[0], sizeof(desc));
-
-        /* Descriptor owned by software ? */
-        if (rx_desc_get_ownership(desc) == 1) {
-            DB_PRINT("descriptor 0x%x owned by sw.\n",
-                     (unsigned)packet_desc_addr);
-            s->regs[GEM_RXSTATUS] |= GEM_RXSTATUS_NOBUF;
-            s->regs[GEM_ISR] |= GEM_INT_RXUSED & ~(s->regs[GEM_IMR]);
-            /* Handle interrupt consequences */
-            gem_update_int_status(s);
-            return -1;
-        }
-
-        DB_PRINT("copy %d bytes to 0x%x\n", MIN(bytes_to_copy, rxbufsize),
-                rx_desc_get_buffer(desc));
-
-        /*
-         * Let's have QEMU lend a helping hand.
-         */
-        if (rx_desc_get_buffer(desc) == 0) {
-            DB_PRINT("Invalid RX buffer (NULL) for descriptor 0x%x\n",
-                     (unsigned)packet_desc_addr);
-            break;
-        }
-
-        /* Copy packet data to emulated DMA buffer */
-        cpu_physical_memory_write(rx_desc_get_buffer(desc) + rxbuf_offset,
-                                  rxbuf_ptr, MIN(bytes_to_copy, rxbufsize));
-        bytes_to_copy -= MIN(bytes_to_copy, rxbufsize);
-        rxbuf_ptr += MIN(bytes_to_copy, rxbufsize);
-        if (bytes_to_copy == 0) {
-            break;
-        }
-
-        /* Next descriptor */
-        if (rx_desc_get_wrap(desc)) {
-            packet_desc_addr = s->regs[GEM_RXQBASE];
-        } else {
-            packet_desc_addr += 8;
-        }
-    }
-
-    DB_PRINT("set length: %ld, EOF on descriptor 0x%x\n", size,
-            (unsigned)packet_desc_addr);
-
-    /* Update last descriptor with EOF and total length */
-    rx_desc_set_eof(desc);
-    rx_desc_set_length(desc, size);
-    cpu_physical_memory_write(packet_desc_addr,
-                              (uint8_t *)&desc[0], sizeof(desc));
-
-    /* Advance RX packet descriptor Q */
-    last_desc_addr = packet_desc_addr;
-    packet_desc_addr = s->rx_desc_addr;
-    s->rx_desc_addr = last_desc_addr;
-    if (rx_desc_get_wrap(desc)) {
-        s->rx_desc_addr = s->regs[GEM_RXQBASE];
-        DB_PRINT("wrapping RX descriptor list\n");
-    } else {
-        DB_PRINT("incrementing RX descriptor list\n");
-        s->rx_desc_addr += 8;
-    }
-
-    DB_PRINT("set SOF, OWN on descriptor 0x%08x\n", (unsigned)packet_desc_addr);
-
-    /* Count it */
-    gem_receive_updatestats(s, buf, size);
-
-    /* Update first descriptor (which could also be the last) */
-    /* read descriptor */
-    cpu_physical_memory_read(packet_desc_addr,
-                             (uint8_t *)&desc[0], sizeof(desc));
-    rx_desc_set_sof(desc);
-    rx_desc_set_ownership(desc);
-    cpu_physical_memory_write(packet_desc_addr,
-                              (uint8_t *)&desc[0], sizeof(desc));
-
-    s->regs[GEM_RXSTATUS] |= GEM_RXSTATUS_FRMRCVD;
-    s->regs[GEM_ISR] |= GEM_INT_RXCMPL & ~(s->regs[GEM_IMR]);
-
-    /* Handle interrupt consequences */
-    gem_update_int_status(s);
-
-    return size;
-}
-
-/*
- * gem_transmit_updatestats:
- * Increment transmit statistics.
- */
-static void gem_transmit_updatestats(GemState *s, const uint8_t *packet,
-                                     unsigned bytes)
-{
-    uint64_t octets;
-
-    /* Total octets (bytes) transmitted */
-    octets = ((uint64_t)(s->regs[GEM_OCTTXLO]) << 32) |
-             s->regs[GEM_OCTTXHI];
-    octets += bytes;
-    s->regs[GEM_OCTTXLO] = octets >> 32;
-    s->regs[GEM_OCTTXHI] = octets;
-
-    /* Error-free Frames transmitted */
-    s->regs[GEM_TXCNT]++;
-
-    /* Error-free Broadcast Frames counter */
-    if (!memcmp(packet, broadcast_addr, 6)) {
-        s->regs[GEM_TXBCNT]++;
-    }
-
-    /* Error-free Multicast Frames counter */
-    if (packet[0] == 0x01) {
-        s->regs[GEM_TXMCNT]++;
-    }
-
-    if (bytes <= 64) {
-        s->regs[GEM_TX64CNT]++;
-    } else if (bytes <= 127) {
-        s->regs[GEM_TX65CNT]++;
-    } else if (bytes <= 255) {
-        s->regs[GEM_TX128CNT]++;
-    } else if (bytes <= 511) {
-        s->regs[GEM_TX256CNT]++;
-    } else if (bytes <= 1023) {
-        s->regs[GEM_TX512CNT]++;
-    } else if (bytes <= 1518) {
-        s->regs[GEM_TX1024CNT]++;
-    } else {
-        s->regs[GEM_TX1519CNT]++;
-    }
-}
-
-/*
- * gem_transmit:
- * Fish packets out of the descriptor ring and feed them to QEMU
- */
-static void gem_transmit(GemState *s)
-{
-    unsigned    desc[2];
-    hwaddr packet_desc_addr;
-    uint8_t     tx_packet[2048];
-    uint8_t     *p;
-    unsigned    total_bytes;
-
-    /* Do nothing if transmit is not enabled. */
-    if (!(s->regs[GEM_NWCTRL] & GEM_NWCTRL_TXENA)) {
-        return;
-    }
-
-    DB_PRINT("\n");
-
-    /* The packet we will hand off to qemu.
-     * Packets scattered across multiple descriptors are gathered to this
-     * one contiguous buffer first.
-     */
-    p = tx_packet;
-    total_bytes = 0;
-
-    /* read current descriptor */
-    packet_desc_addr = s->tx_desc_addr;
-    cpu_physical_memory_read(packet_desc_addr,
-                             (uint8_t *)&desc[0], sizeof(desc));
-    /* Handle all descriptors owned by hardware */
-    while (tx_desc_get_used(desc) == 0) {
-
-        /* Do nothing if transmit is not enabled. */
-        if (!(s->regs[GEM_NWCTRL] & GEM_NWCTRL_TXENA)) {
-            return;
-        }
-        print_gem_tx_desc(desc);
-
-        /* The real hardware would eat this (and possibly crash).
-         * For QEMU let's lend a helping hand.
-         */
-        if ((tx_desc_get_buffer(desc) == 0) ||
-            (tx_desc_get_length(desc) == 0)) {
-            DB_PRINT("Invalid TX descriptor @ 0x%x\n",
-                     (unsigned)packet_desc_addr);
-            break;
-        }
-
-        /* Gather this fragment of the packet from "dma memory" to our contig.
-         * buffer.
-         */
-        cpu_physical_memory_read(tx_desc_get_buffer(desc), p,
-                                 tx_desc_get_length(desc));
-        p += tx_desc_get_length(desc);
-        total_bytes += tx_desc_get_length(desc);
-
-        /* Last descriptor for this packet; hand the whole thing off */
-        if (tx_desc_get_last(desc)) {
-            /* Modify the 1st descriptor of this packet to be owned by
-             * the processor.
-             */
-            cpu_physical_memory_read(s->tx_desc_addr,
-                                     (uint8_t *)&desc[0], sizeof(desc));
-            tx_desc_set_used(desc);
-            cpu_physical_memory_write(s->tx_desc_addr,
-                                      (uint8_t *)&desc[0], sizeof(desc));
-            /* Advance the hardare current descriptor past this packet */
-            if (tx_desc_get_wrap(desc)) {
-                s->tx_desc_addr = s->regs[GEM_TXQBASE];
-            } else {
-                s->tx_desc_addr = packet_desc_addr + 8;
-            }
-            DB_PRINT("TX descriptor next: 0x%08x\n", s->tx_desc_addr);
-
-            s->regs[GEM_TXSTATUS] |= GEM_TXSTATUS_TXCMPL;
-            s->regs[GEM_ISR] |= GEM_INT_TXCMPL & ~(s->regs[GEM_IMR]);
-
-            /* Handle interrupt consequences */
-            gem_update_int_status(s);
-
-            /* Is checksum offload enabled? */
-            if (s->regs[GEM_DMACFG] & GEM_DMACFG_TXCSUM_OFFL) {
-                net_checksum_calculate(tx_packet, total_bytes);
-            }
-
-            /* Update MAC statistics */
-            gem_transmit_updatestats(s, tx_packet, total_bytes);
-
-            /* Send the packet somewhere */
-            if (s->phy_loop) {
-                gem_receive(qemu_get_queue(s->nic), tx_packet, total_bytes);
-            } else {
-                qemu_send_packet(qemu_get_queue(s->nic), tx_packet,
-                                 total_bytes);
-            }
-
-            /* Prepare for next packet */
-            p = tx_packet;
-            total_bytes = 0;
-        }
-
-        /* read next descriptor */
-        if (tx_desc_get_wrap(desc)) {
-            packet_desc_addr = s->regs[GEM_TXQBASE];
-        } else {
-            packet_desc_addr += 8;
-        }
-        cpu_physical_memory_read(packet_desc_addr,
-                                 (uint8_t *)&desc[0], sizeof(desc));
-    }
-
-    if (tx_desc_get_used(desc)) {
-        s->regs[GEM_TXSTATUS] |= GEM_TXSTATUS_USED;
-        s->regs[GEM_ISR] |= GEM_INT_TXUSED & ~(s->regs[GEM_IMR]);
-        gem_update_int_status(s);
-    }
-}
-
-static void gem_phy_reset(GemState *s)
-{
-    memset(&s->phy_regs[0], 0, sizeof(s->phy_regs));
-    s->phy_regs[PHY_REG_CONTROL] = 0x1140;
-    s->phy_regs[PHY_REG_STATUS] = 0x7969;
-    s->phy_regs[PHY_REG_PHYID1] = 0x0141;
-    s->phy_regs[PHY_REG_PHYID2] = 0x0CC2;
-    s->phy_regs[PHY_REG_ANEGADV] = 0x01E1;
-    s->phy_regs[PHY_REG_LINKPABIL] = 0xCDE1;
-    s->phy_regs[PHY_REG_ANEGEXP] = 0x000F;
-    s->phy_regs[PHY_REG_NEXTP] = 0x2001;
-    s->phy_regs[PHY_REG_LINKPNEXTP] = 0x40E6;
-    s->phy_regs[PHY_REG_100BTCTRL] = 0x0300;
-    s->phy_regs[PHY_REG_1000BTSTAT] = 0x7C00;
-    s->phy_regs[PHY_REG_EXTSTAT] = 0x3000;
-    s->phy_regs[PHY_REG_PHYSPCFC_CTL] = 0x0078;
-    s->phy_regs[PHY_REG_PHYSPCFC_ST] = 0xBC00;
-    s->phy_regs[PHY_REG_EXT_PHYSPCFC_CTL] = 0x0C60;
-    s->phy_regs[PHY_REG_LED] = 0x4100;
-    s->phy_regs[PHY_REG_EXT_PHYSPCFC_CTL2] = 0x000A;
-    s->phy_regs[PHY_REG_EXT_PHYSPCFC_ST] = 0x848B;
-
-    phy_update_link(s);
-}
-
-static void gem_reset(DeviceState *d)
-{
-    GemState *s = FROM_SYSBUS(GemState, SYS_BUS_DEVICE(d));
-
-    DB_PRINT("\n");
-
-    /* Set post reset register values */
-    memset(&s->regs[0], 0, sizeof(s->regs));
-    s->regs[GEM_NWCFG] = 0x00080000;
-    s->regs[GEM_NWSTATUS] = 0x00000006;
-    s->regs[GEM_DMACFG] = 0x00020784;
-    s->regs[GEM_IMR] = 0x07ffffff;
-    s->regs[GEM_TXPAUSE] = 0x0000ffff;
-    s->regs[GEM_TXPARTIALSF] = 0x000003ff;
-    s->regs[GEM_RXPARTIALSF] = 0x000003ff;
-    s->regs[GEM_MODID] = 0x00020118;
-    s->regs[GEM_DESCONF] = 0x02500111;
-    s->regs[GEM_DESCONF2] = 0x2ab13fff;
-    s->regs[GEM_DESCONF5] = 0x002f2145;
-    s->regs[GEM_DESCONF6] = 0x00000200;
-
-    gem_phy_reset(s);
-
-    gem_update_int_status(s);
-}
-
-static uint16_t gem_phy_read(GemState *s, unsigned reg_num)
-{
-    DB_PRINT("reg: %d value: 0x%04x\n", reg_num, s->phy_regs[reg_num]);
-    return s->phy_regs[reg_num];
-}
-
-static void gem_phy_write(GemState *s, unsigned reg_num, uint16_t val)
-{
-    DB_PRINT("reg: %d value: 0x%04x\n", reg_num, val);
-
-    switch (reg_num) {
-    case PHY_REG_CONTROL:
-        if (val & PHY_REG_CONTROL_RST) {
-            /* Phy reset */
-            gem_phy_reset(s);
-            val &= ~(PHY_REG_CONTROL_RST | PHY_REG_CONTROL_LOOP);
-            s->phy_loop = 0;
-        }
-        if (val & PHY_REG_CONTROL_ANEG) {
-            /* Complete autonegotiation immediately */
-            val &= ~PHY_REG_CONTROL_ANEG;
-            s->phy_regs[PHY_REG_STATUS] |= PHY_REG_STATUS_ANEGCMPL;
-        }
-        if (val & PHY_REG_CONTROL_LOOP) {
-            DB_PRINT("PHY placed in loopback\n");
-            s->phy_loop = 1;
-        } else {
-            s->phy_loop = 0;
-        }
-        break;
-    }
-    s->phy_regs[reg_num] = val;
-}
-
-/*
- * gem_read32:
- * Read a GEM register.
- */
-static uint64_t gem_read(void *opaque, hwaddr offset, unsigned size)
-{
-    GemState *s;
-    uint32_t retval;
-
-    s = (GemState *)opaque;
-
-    offset >>= 2;
-    retval = s->regs[offset];
-
-    DB_PRINT("offset: 0x%04x read: 0x%08x\n", (unsigned)offset*4, retval);
-
-    switch (offset) {
-    case GEM_ISR:
-        DB_PRINT("lowering irq on ISR read\n");
-        qemu_set_irq(s->irq, 0);
-        break;
-    case GEM_PHYMNTNC:
-        if (retval & GEM_PHYMNTNC_OP_R) {
-            uint32_t phy_addr, reg_num;
-
-            phy_addr = (retval & GEM_PHYMNTNC_ADDR) >> GEM_PHYMNTNC_ADDR_SHFT;
-            if (phy_addr == BOARD_PHY_ADDRESS) {
-                reg_num = (retval & GEM_PHYMNTNC_REG) >> GEM_PHYMNTNC_REG_SHIFT;
-                retval &= 0xFFFF0000;
-                retval |= gem_phy_read(s, reg_num);
-            } else {
-                retval |= 0xFFFF; /* No device at this address */
-            }
-        }
-        break;
-    }
-
-    /* Squash read to clear bits */
-    s->regs[offset] &= ~(s->regs_rtc[offset]);
-
-    /* Do not provide write only bits */
-    retval &= ~(s->regs_wo[offset]);
-
-    DB_PRINT("0x%08x\n", retval);
-    return retval;
-}
-
-/*
- * gem_write32:
- * Write a GEM register.
- */
-static void gem_write(void *opaque, hwaddr offset, uint64_t val,
-        unsigned size)
-{
-    GemState *s = (GemState *)opaque;
-    uint32_t readonly;
-
-    DB_PRINT("offset: 0x%04x write: 0x%08x ", (unsigned)offset, (unsigned)val);
-    offset >>= 2;
-
-    /* Squash bits which are read only in write value */
-    val &= ~(s->regs_ro[offset]);
-    /* Preserve (only) bits which are read only in register */
-    readonly = s->regs[offset];
-    readonly &= s->regs_ro[offset];
-
-    /* Squash bits which are write 1 to clear */
-    val &= ~(s->regs_w1c[offset] & val);
-
-    /* Copy register write to backing store */
-    s->regs[offset] = val | readonly;
-
-    /* Handle register write side effects */
-    switch (offset) {
-    case GEM_NWCTRL:
-        if (val & GEM_NWCTRL_TXSTART) {
-            gem_transmit(s);
-        }
-        if (!(val & GEM_NWCTRL_TXENA)) {
-            /* Reset to start of Q when transmit disabled. */
-            s->tx_desc_addr = s->regs[GEM_TXQBASE];
-        }
-        if (val & GEM_NWCTRL_RXENA) {
-            qemu_flush_queued_packets(qemu_get_queue(s->nic));
-        }
-        break;
-
-    case GEM_TXSTATUS:
-        gem_update_int_status(s);
-        break;
-    case GEM_RXQBASE:
-        s->rx_desc_addr = val;
-        break;
-    case GEM_TXQBASE:
-        s->tx_desc_addr = val;
-        break;
-    case GEM_RXSTATUS:
-        gem_update_int_status(s);
-        break;
-    case GEM_IER:
-        s->regs[GEM_IMR] &= ~val;
-        gem_update_int_status(s);
-        break;
-    case GEM_IDR:
-        s->regs[GEM_IMR] |= val;
-        gem_update_int_status(s);
-        break;
-    case GEM_PHYMNTNC:
-        if (val & GEM_PHYMNTNC_OP_W) {
-            uint32_t phy_addr, reg_num;
-
-            phy_addr = (val & GEM_PHYMNTNC_ADDR) >> GEM_PHYMNTNC_ADDR_SHFT;
-            if (phy_addr == BOARD_PHY_ADDRESS) {
-                reg_num = (val & GEM_PHYMNTNC_REG) >> GEM_PHYMNTNC_REG_SHIFT;
-                gem_phy_write(s, reg_num, val);
-            }
-        }
-        break;
-    }
-
-    DB_PRINT("newval: 0x%08x\n", s->regs[offset]);
-}
-
-static const MemoryRegionOps gem_ops = {
-    .read = gem_read,
-    .write = gem_write,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static void gem_cleanup(NetClientState *nc)
-{
-    GemState *s = qemu_get_nic_opaque(nc);
-
-    DB_PRINT("\n");
-    s->nic = NULL;
-}
-
-static void gem_set_link(NetClientState *nc)
-{
-    DB_PRINT("\n");
-    phy_update_link(qemu_get_nic_opaque(nc));
-}
-
-static NetClientInfo net_gem_info = {
-    .type = NET_CLIENT_OPTIONS_KIND_NIC,
-    .size = sizeof(NICState),
-    .can_receive = gem_can_receive,
-    .receive = gem_receive,
-    .cleanup = gem_cleanup,
-    .link_status_changed = gem_set_link,
-};
-
-static int gem_init(SysBusDevice *dev)
-{
-    GemState *s;
-
-    DB_PRINT("\n");
-
-    s = FROM_SYSBUS(GemState, dev);
-    gem_init_register_masks(s);
-    memory_region_init_io(&s->iomem, &gem_ops, s, "enet", sizeof(s->regs));
-    sysbus_init_mmio(dev, &s->iomem);
-    sysbus_init_irq(dev, &s->irq);
-    qemu_macaddr_default_if_unset(&s->conf.macaddr);
-
-    s->nic = qemu_new_nic(&net_gem_info, &s->conf,
-            object_get_typename(OBJECT(dev)), dev->qdev.id, s);
-
-    return 0;
-}
-
-static const VMStateDescription vmstate_cadence_gem = {
-    .name = "cadence_gem",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField[]) {
-        VMSTATE_UINT32_ARRAY(regs, GemState, GEM_MAXREG),
-        VMSTATE_UINT16_ARRAY(phy_regs, GemState, 32),
-        VMSTATE_UINT8(phy_loop, GemState),
-        VMSTATE_UINT32(rx_desc_addr, GemState),
-        VMSTATE_UINT32(tx_desc_addr, GemState),
-    }
-};
-
-static Property gem_properties[] = {
-    DEFINE_NIC_PROPERTIES(GemState, conf),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void gem_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
-
-    sdc->init = gem_init;
-    dc->props = gem_properties;
-    dc->vmsd = &vmstate_cadence_gem;
-    dc->reset = gem_reset;
-}
-
-static const TypeInfo gem_info = {
-    .class_init = gem_class_init,
-    .name  = "cadence_gem",
-    .parent = TYPE_SYS_BUS_DEVICE,
-    .instance_size  = sizeof(GemState),
-};
-
-static void gem_register_types(void)
-{
-    type_register_static(&gem_info);
-}
-
-type_init(gem_register_types)
diff --git a/hw/cadence_ttc.c b/hw/cadence_ttc.c
deleted file mode 100644 (file)
index ba584f4..0000000
+++ /dev/null
@@ -1,489 +0,0 @@
-/*
- * Xilinx Zynq cadence TTC model
- *
- * Copyright (c) 2011 Xilinx Inc.
- * Copyright (c) 2012 Peter A.G. Crosthwaite (peter.crosthwaite@petalogix.com)
- * Copyright (c) 2012 PetaLogix Pty Ltd.
- * Written By Haibing Ma
- *            M. Habib
- *
- * 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.
- *
- * 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 "hw/sysbus.h"
-#include "qemu/timer.h"
-
-#ifdef CADENCE_TTC_ERR_DEBUG
-#define DB_PRINT(...) do { \
-    fprintf(stderr,  ": %s: ", __func__); \
-    fprintf(stderr, ## __VA_ARGS__); \
-    } while (0);
-#else
-    #define DB_PRINT(...)
-#endif
-
-#define COUNTER_INTR_IV     0x00000001
-#define COUNTER_INTR_M1     0x00000002
-#define COUNTER_INTR_M2     0x00000004
-#define COUNTER_INTR_M3     0x00000008
-#define COUNTER_INTR_OV     0x00000010
-#define COUNTER_INTR_EV     0x00000020
-
-#define COUNTER_CTRL_DIS    0x00000001
-#define COUNTER_CTRL_INT    0x00000002
-#define COUNTER_CTRL_DEC    0x00000004
-#define COUNTER_CTRL_MATCH  0x00000008
-#define COUNTER_CTRL_RST    0x00000010
-
-#define CLOCK_CTRL_PS_EN    0x00000001
-#define CLOCK_CTRL_PS_V     0x0000001e
-
-typedef struct {
-    QEMUTimer *timer;
-    int freq;
-
-    uint32_t reg_clock;
-    uint32_t reg_count;
-    uint32_t reg_value;
-    uint16_t reg_interval;
-    uint16_t reg_match[3];
-    uint32_t reg_intr;
-    uint32_t reg_intr_en;
-    uint32_t reg_event_ctrl;
-    uint32_t reg_event;
-
-    uint64_t cpu_time;
-    unsigned int cpu_time_valid;
-
-    qemu_irq irq;
-} CadenceTimerState;
-
-typedef struct {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-    CadenceTimerState timer[3];
-} CadenceTTCState;
-
-static void cadence_timer_update(CadenceTimerState *s)
-{
-    qemu_set_irq(s->irq, !!(s->reg_intr & s->reg_intr_en));
-}
-
-static CadenceTimerState *cadence_timer_from_addr(void *opaque,
-                                        hwaddr offset)
-{
-    unsigned int index;
-    CadenceTTCState *s = (CadenceTTCState *)opaque;
-
-    index = (offset >> 2) % 3;
-
-    return &s->timer[index];
-}
-
-static uint64_t cadence_timer_get_ns(CadenceTimerState *s, uint64_t timer_steps)
-{
-    /* timer_steps has max value of 0x100000000. double check it
-     * (or overflow can happen below) */
-    assert(timer_steps <= 1ULL << 32);
-
-    uint64_t r = timer_steps * 1000000000ULL;
-    if (s->reg_clock & CLOCK_CTRL_PS_EN) {
-        r >>= 16 - (((s->reg_clock & CLOCK_CTRL_PS_V) >> 1) + 1);
-    } else {
-        r >>= 16;
-    }
-    r /= (uint64_t)s->freq;
-    return r;
-}
-
-static uint64_t cadence_timer_get_steps(CadenceTimerState *s, uint64_t ns)
-{
-    uint64_t to_divide = 1000000000ULL;
-
-    uint64_t r = ns;
-     /* for very large intervals (> 8s) do some division first to stop
-      * overflow (costs some prescision) */
-    while (r >= 8ULL << 30 && to_divide > 1) {
-        r /= 1000;
-        to_divide /= 1000;
-    }
-    r <<= 16;
-    /* keep early-dividing as needed */
-    while (r >= 8ULL << 30 && to_divide > 1) {
-        r /= 1000;
-        to_divide /= 1000;
-    }
-    r *= (uint64_t)s->freq;
-    if (s->reg_clock & CLOCK_CTRL_PS_EN) {
-        r /= 1 << (((s->reg_clock & CLOCK_CTRL_PS_V) >> 1) + 1);
-    }
-
-    r /= to_divide;
-    return r;
-}
-
-/* determine if x is in between a and b, exclusive of a, inclusive of b */
-
-static inline int64_t is_between(int64_t x, int64_t a, int64_t b)
-{
-    if (a < b) {
-        return x > a && x <= b;
-    }
-    return x < a && x >= b;
-}
-
-static void cadence_timer_run(CadenceTimerState *s)
-{
-    int i;
-    int64_t event_interval, next_value;
-
-    assert(s->cpu_time_valid); /* cadence_timer_sync must be called first */
-
-    if (s->reg_count & COUNTER_CTRL_DIS) {
-        s->cpu_time_valid = 0;
-        return;
-    }
-
-    { /* figure out what's going to happen next (rollover or match) */
-        int64_t interval = (uint64_t)((s->reg_count & COUNTER_CTRL_INT) ?
-                (int64_t)s->reg_interval + 1 : 0x10000ULL) << 16;
-        next_value = (s->reg_count & COUNTER_CTRL_DEC) ? -1ULL : interval;
-        for (i = 0; i < 3; ++i) {
-            int64_t cand = (uint64_t)s->reg_match[i] << 16;
-            if (is_between(cand, (uint64_t)s->reg_value, next_value)) {
-                next_value = cand;
-            }
-        }
-    }
-    DB_PRINT("next timer event value: %09llx\n",
-            (unsigned long long)next_value);
-
-    event_interval = next_value - (int64_t)s->reg_value;
-    event_interval = (event_interval < 0) ? -event_interval : event_interval;
-
-    qemu_mod_timer(s->timer, s->cpu_time +
-                cadence_timer_get_ns(s, event_interval));
-}
-
-static void cadence_timer_sync(CadenceTimerState *s)
-{
-    int i;
-    int64_t r, x;
-    int64_t interval = ((s->reg_count & COUNTER_CTRL_INT) ?
-            (int64_t)s->reg_interval + 1 : 0x10000ULL) << 16;
-    uint64_t old_time = s->cpu_time;
-
-    s->cpu_time = qemu_get_clock_ns(vm_clock);
-    DB_PRINT("cpu time: %lld ns\n", (long long)old_time);
-
-    if (!s->cpu_time_valid || old_time == s->cpu_time) {
-        s->cpu_time_valid = 1;
-        return;
-    }
-
-    r = (int64_t)cadence_timer_get_steps(s, s->cpu_time - old_time);
-    x = (int64_t)s->reg_value + ((s->reg_count & COUNTER_CTRL_DEC) ? -r : r);
-
-    for (i = 0; i < 3; ++i) {
-        int64_t m = (int64_t)s->reg_match[i] << 16;
-        if (m > interval) {
-            continue;
-        }
-        /* check to see if match event has occurred. check m +/- interval
-         * to account for match events in wrap around cases */
-        if (is_between(m, s->reg_value, x) ||
-            is_between(m + interval, s->reg_value, x) ||
-            is_between(m - interval, s->reg_value, x)) {
-            s->reg_intr |= (2 << i);
-        }
-    }
-    while (x < 0) {
-        x += interval;
-    }
-    s->reg_value = (uint32_t)(x % interval);
-
-    if (s->reg_value != x) {
-        s->reg_intr |= (s->reg_count & COUNTER_CTRL_INT) ?
-            COUNTER_INTR_IV : COUNTER_INTR_OV;
-    }
-    cadence_timer_update(s);
-}
-
-static void cadence_timer_tick(void *opaque)
-{
-    CadenceTimerState *s = opaque;
-
-    DB_PRINT("\n");
-    cadence_timer_sync(s);
-    cadence_timer_run(s);
-}
-
-static uint32_t cadence_ttc_read_imp(void *opaque, hwaddr offset)
-{
-    CadenceTimerState *s = cadence_timer_from_addr(opaque, offset);
-    uint32_t value;
-
-    cadence_timer_sync(s);
-    cadence_timer_run(s);
-
-    switch (offset) {
-    case 0x00: /* clock control */
-    case 0x04:
-    case 0x08:
-        return s->reg_clock;
-
-    case 0x0c: /* counter control */
-    case 0x10:
-    case 0x14:
-        return s->reg_count;
-
-    case 0x18: /* counter value */
-    case 0x1c:
-    case 0x20:
-        return (uint16_t)(s->reg_value >> 16);
-
-    case 0x24: /* reg_interval counter */
-    case 0x28:
-    case 0x2c:
-        return s->reg_interval;
-
-    case 0x30: /* match 1 counter */
-    case 0x34:
-    case 0x38:
-        return s->reg_match[0];
-
-    case 0x3c: /* match 2 counter */
-    case 0x40:
-    case 0x44:
-        return s->reg_match[1];
-
-    case 0x48: /* match 3 counter */
-    case 0x4c:
-    case 0x50:
-        return s->reg_match[2];
-
-    case 0x54: /* interrupt register */
-    case 0x58:
-    case 0x5c:
-        /* cleared after read */
-        value = s->reg_intr;
-        s->reg_intr = 0;
-        cadence_timer_update(s);
-        return value;
-
-    case 0x60: /* interrupt enable */
-    case 0x64:
-    case 0x68:
-        return s->reg_intr_en;
-
-    case 0x6c:
-    case 0x70:
-    case 0x74:
-        return s->reg_event_ctrl;
-
-    case 0x78:
-    case 0x7c:
-    case 0x80:
-        return s->reg_event;
-
-    default:
-        return 0;
-    }
-}
-
-static uint64_t cadence_ttc_read(void *opaque, hwaddr offset,
-    unsigned size)
-{
-    uint32_t ret = cadence_ttc_read_imp(opaque, offset);
-
-    DB_PRINT("addr: %08x data: %08x\n", (unsigned)offset, (unsigned)ret);
-    return ret;
-}
-
-static void cadence_ttc_write(void *opaque, hwaddr offset,
-        uint64_t value, unsigned size)
-{
-    CadenceTimerState *s = cadence_timer_from_addr(opaque, offset);
-
-    DB_PRINT("addr: %08x data %08x\n", (unsigned)offset, (unsigned)value);
-
-    cadence_timer_sync(s);
-
-    switch (offset) {
-    case 0x00: /* clock control */
-    case 0x04:
-    case 0x08:
-        s->reg_clock = value & 0x3F;
-        break;
-
-    case 0x0c: /* counter control */
-    case 0x10:
-    case 0x14:
-        if (value & COUNTER_CTRL_RST) {
-            s->reg_value = 0;
-        }
-        s->reg_count = value & 0x3f & ~COUNTER_CTRL_RST;
-        break;
-
-    case 0x24: /* interval register */
-    case 0x28:
-    case 0x2c:
-        s->reg_interval = value & 0xffff;
-        break;
-
-    case 0x30: /* match register */
-    case 0x34:
-    case 0x38:
-        s->reg_match[0] = value & 0xffff;
-
-    case 0x3c: /* match register */
-    case 0x40:
-    case 0x44:
-        s->reg_match[1] = value & 0xffff;
-
-    case 0x48: /* match register */
-    case 0x4c:
-    case 0x50:
-        s->reg_match[2] = value & 0xffff;
-        break;
-
-    case 0x54: /* interrupt register */
-    case 0x58:
-    case 0x5c:
-        break;
-
-    case 0x60: /* interrupt enable */
-    case 0x64:
-    case 0x68:
-        s->reg_intr_en = value & 0x3f;
-        break;
-
-    case 0x6c: /* event control */
-    case 0x70:
-    case 0x74:
-        s->reg_event_ctrl = value & 0x07;
-        break;
-
-    default:
-        return;
-    }
-
-    cadence_timer_run(s);
-    cadence_timer_update(s);
-}
-
-static const MemoryRegionOps cadence_ttc_ops = {
-    .read = cadence_ttc_read,
-    .write = cadence_ttc_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void cadence_timer_reset(CadenceTimerState *s)
-{
-   s->reg_count = 0x21;
-}
-
-static void cadence_timer_init(uint32_t freq, CadenceTimerState *s)
-{
-    memset(s, 0, sizeof(CadenceTimerState));
-    s->freq = freq;
-
-    cadence_timer_reset(s);
-
-    s->timer = qemu_new_timer_ns(vm_clock, cadence_timer_tick, s);
-}
-
-static int cadence_ttc_init(SysBusDevice *dev)
-{
-    CadenceTTCState *s = FROM_SYSBUS(CadenceTTCState, dev);
-    int i;
-
-    for (i = 0; i < 3; ++i) {
-        cadence_timer_init(133000000, &s->timer[i]);
-        sysbus_init_irq(dev, &s->timer[i].irq);
-    }
-
-    memory_region_init_io(&s->iomem, &cadence_ttc_ops, s, "timer", 0x1000);
-    sysbus_init_mmio(dev, &s->iomem);
-
-    return 0;
-}
-
-static void cadence_timer_pre_save(void *opaque)
-{
-    cadence_timer_sync((CadenceTimerState *)opaque);
-}
-
-static int cadence_timer_post_load(void *opaque, int version_id)
-{
-    CadenceTimerState *s = opaque;
-
-    s->cpu_time_valid = 0;
-    cadence_timer_sync(s);
-    cadence_timer_run(s);
-    cadence_timer_update(s);
-    return 0;
-}
-
-static const VMStateDescription vmstate_cadence_timer = {
-    .name = "cadence_timer",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .pre_save = cadence_timer_pre_save,
-    .post_load = cadence_timer_post_load,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT32(reg_clock, CadenceTimerState),
-        VMSTATE_UINT32(reg_count, CadenceTimerState),
-        VMSTATE_UINT32(reg_value, CadenceTimerState),
-        VMSTATE_UINT16(reg_interval, CadenceTimerState),
-        VMSTATE_UINT16_ARRAY(reg_match, CadenceTimerState, 3),
-        VMSTATE_UINT32(reg_intr, CadenceTimerState),
-        VMSTATE_UINT32(reg_intr_en, CadenceTimerState),
-        VMSTATE_UINT32(reg_event_ctrl, CadenceTimerState),
-        VMSTATE_UINT32(reg_event, CadenceTimerState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static const VMStateDescription vmstate_cadence_ttc = {
-    .name = "cadence_TTC",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_STRUCT_ARRAY(timer, CadenceTTCState, 3, 0,
-                            vmstate_cadence_timer,
-                            CadenceTimerState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void cadence_ttc_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
-
-    sdc->init = cadence_ttc_init;
-    dc->vmsd = &vmstate_cadence_ttc;
-}
-
-static const TypeInfo cadence_ttc_info = {
-    .name  = "cadence_ttc",
-    .parent = TYPE_SYS_BUS_DEVICE,
-    .instance_size  = sizeof(CadenceTTCState),
-    .class_init = cadence_ttc_class_init,
-};
-
-static void cadence_ttc_register_types(void)
-{
-    type_register_static(&cadence_ttc_info);
-}
-
-type_init(cadence_ttc_register_types)
diff --git a/hw/cadence_uart.c b/hw/cadence_uart.c
deleted file mode 100644 (file)
index 5426f10..0000000
+++ /dev/null
@@ -1,517 +0,0 @@
-/*
- * Device model for Cadence UART
- *
- * Copyright (c) 2010 Xilinx Inc.
- * Copyright (c) 2012 Peter A.G. Crosthwaite (peter.crosthwaite@petalogix.com)
- * Copyright (c) 2012 PetaLogix Pty Ltd.
- * Written by Haibing Ma
- *            M.Habib
- *
- * 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.
- *
- * 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 "hw/sysbus.h"
-#include "char/char.h"
-#include "qemu/timer.h"
-
-#ifdef CADENCE_UART_ERR_DEBUG
-#define DB_PRINT(...) do { \
-    fprintf(stderr,  ": %s: ", __func__); \
-    fprintf(stderr, ## __VA_ARGS__); \
-    } while (0);
-#else
-    #define DB_PRINT(...)
-#endif
-
-#define UART_SR_INTR_RTRIG     0x00000001
-#define UART_SR_INTR_REMPTY    0x00000002
-#define UART_SR_INTR_RFUL      0x00000004
-#define UART_SR_INTR_TEMPTY    0x00000008
-#define UART_SR_INTR_TFUL      0x00000010
-/* bits fields in CSR that correlate to CISR. If any of these bits are set in
- * SR, then the same bit in CISR is set high too */
-#define UART_SR_TO_CISR_MASK   0x0000001F
-
-#define UART_INTR_ROVR         0x00000020
-#define UART_INTR_FRAME        0x00000040
-#define UART_INTR_PARE         0x00000080
-#define UART_INTR_TIMEOUT      0x00000100
-#define UART_INTR_DMSI         0x00000200
-
-#define UART_SR_RACTIVE    0x00000400
-#define UART_SR_TACTIVE    0x00000800
-#define UART_SR_FDELT      0x00001000
-
-#define UART_CR_RXRST       0x00000001
-#define UART_CR_TXRST       0x00000002
-#define UART_CR_RX_EN       0x00000004
-#define UART_CR_RX_DIS      0x00000008
-#define UART_CR_TX_EN       0x00000010
-#define UART_CR_TX_DIS      0x00000020
-#define UART_CR_RST_TO      0x00000040
-#define UART_CR_STARTBRK    0x00000080
-#define UART_CR_STOPBRK     0x00000100
-
-#define UART_MR_CLKS            0x00000001
-#define UART_MR_CHRL            0x00000006
-#define UART_MR_CHRL_SH         1
-#define UART_MR_PAR             0x00000038
-#define UART_MR_PAR_SH          3
-#define UART_MR_NBSTOP          0x000000C0
-#define UART_MR_NBSTOP_SH       6
-#define UART_MR_CHMODE          0x00000300
-#define UART_MR_CHMODE_SH       8
-#define UART_MR_UCLKEN          0x00000400
-#define UART_MR_IRMODE          0x00000800
-
-#define UART_DATA_BITS_6       (0x3 << UART_MR_CHRL_SH)
-#define UART_DATA_BITS_7       (0x2 << UART_MR_CHRL_SH)
-#define UART_PARITY_ODD        (0x1 << UART_MR_PAR_SH)
-#define UART_PARITY_EVEN       (0x0 << UART_MR_PAR_SH)
-#define UART_STOP_BITS_1       (0x3 << UART_MR_NBSTOP_SH)
-#define UART_STOP_BITS_2       (0x2 << UART_MR_NBSTOP_SH)
-#define NORMAL_MODE            (0x0 << UART_MR_CHMODE_SH)
-#define ECHO_MODE              (0x1 << UART_MR_CHMODE_SH)
-#define LOCAL_LOOPBACK         (0x2 << UART_MR_CHMODE_SH)
-#define REMOTE_LOOPBACK        (0x3 << UART_MR_CHMODE_SH)
-
-#define RX_FIFO_SIZE           16
-#define TX_FIFO_SIZE           16
-#define UART_INPUT_CLK         50000000
-
-#define R_CR       (0x00/4)
-#define R_MR       (0x04/4)
-#define R_IER      (0x08/4)
-#define R_IDR      (0x0C/4)
-#define R_IMR      (0x10/4)
-#define R_CISR     (0x14/4)
-#define R_BRGR     (0x18/4)
-#define R_RTOR     (0x1C/4)
-#define R_RTRIG    (0x20/4)
-#define R_MCR      (0x24/4)
-#define R_MSR      (0x28/4)
-#define R_SR       (0x2C/4)
-#define R_TX_RX    (0x30/4)
-#define R_BDIV     (0x34/4)
-#define R_FDEL     (0x38/4)
-#define R_PMIN     (0x3C/4)
-#define R_PWID     (0x40/4)
-#define R_TTRIG    (0x44/4)
-
-#define R_MAX (R_TTRIG + 1)
-
-typedef struct {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-    uint32_t r[R_MAX];
-    uint8_t r_fifo[RX_FIFO_SIZE];
-    uint32_t rx_wpos;
-    uint32_t rx_count;
-    uint64_t char_tx_time;
-    CharDriverState *chr;
-    qemu_irq irq;
-    struct QEMUTimer *fifo_trigger_handle;
-    struct QEMUTimer *tx_time_handle;
-} UartState;
-
-static void uart_update_status(UartState *s)
-{
-    s->r[R_CISR] |= s->r[R_SR] & UART_SR_TO_CISR_MASK;
-    qemu_set_irq(s->irq, !!(s->r[R_IMR] & s->r[R_CISR]));
-}
-
-static void fifo_trigger_update(void *opaque)
-{
-    UartState *s = (UartState *)opaque;
-
-    s->r[R_CISR] |= UART_INTR_TIMEOUT;
-
-    uart_update_status(s);
-}
-
-static void uart_tx_redo(UartState *s)
-{
-    uint64_t new_tx_time = qemu_get_clock_ns(vm_clock);
-
-    qemu_mod_timer(s->tx_time_handle, new_tx_time + s->char_tx_time);
-
-    s->r[R_SR] |= UART_SR_INTR_TEMPTY;
-
-    uart_update_status(s);
-}
-
-static void uart_tx_write(void *opaque)
-{
-    UartState *s = (UartState *)opaque;
-
-    uart_tx_redo(s);
-}
-
-static void uart_rx_reset(UartState *s)
-{
-    s->rx_wpos = 0;
-    s->rx_count = 0;
-
-    s->r[R_SR] |= UART_SR_INTR_REMPTY;
-    s->r[R_SR] &= ~UART_SR_INTR_RFUL;
-}
-
-static void uart_tx_reset(UartState *s)
-{
-    s->r[R_SR] |= UART_SR_INTR_TEMPTY;
-    s->r[R_SR] &= ~UART_SR_INTR_TFUL;
-}
-
-static void uart_send_breaks(UartState *s)
-{
-    int break_enabled = 1;
-
-    qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_BREAK,
-                               &break_enabled);
-}
-
-static void uart_parameters_setup(UartState *s)
-{
-    QEMUSerialSetParams ssp;
-    unsigned int baud_rate, packet_size;
-
-    baud_rate = (s->r[R_MR] & UART_MR_CLKS) ?
-            UART_INPUT_CLK / 8 : UART_INPUT_CLK;
-
-    ssp.speed = baud_rate / (s->r[R_BRGR] * (s->r[R_BDIV] + 1));
-    packet_size = 1;
-
-    switch (s->r[R_MR] & UART_MR_PAR) {
-    case UART_PARITY_EVEN:
-        ssp.parity = 'E';
-        packet_size++;
-        break;
-    case UART_PARITY_ODD:
-        ssp.parity = 'O';
-        packet_size++;
-        break;
-    default:
-        ssp.parity = 'N';
-        break;
-    }
-
-    switch (s->r[R_MR] & UART_MR_CHRL) {
-    case UART_DATA_BITS_6:
-        ssp.data_bits = 6;
-        break;
-    case UART_DATA_BITS_7:
-        ssp.data_bits = 7;
-        break;
-    default:
-        ssp.data_bits = 8;
-        break;
-    }
-
-    switch (s->r[R_MR] & UART_MR_NBSTOP) {
-    case UART_STOP_BITS_1:
-        ssp.stop_bits = 1;
-        break;
-    default:
-        ssp.stop_bits = 2;
-        break;
-    }
-
-    packet_size += ssp.data_bits + ssp.stop_bits;
-    s->char_tx_time = (get_ticks_per_sec() / ssp.speed) * packet_size;
-    qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
-}
-
-static int uart_can_receive(void *opaque)
-{
-    UartState *s = (UartState *)opaque;
-
-    return RX_FIFO_SIZE - s->rx_count;
-}
-
-static void uart_ctrl_update(UartState *s)
-{
-    if (s->r[R_CR] & UART_CR_TXRST) {
-        uart_tx_reset(s);
-    }
-
-    if (s->r[R_CR] & UART_CR_RXRST) {
-        uart_rx_reset(s);
-    }
-
-    s->r[R_CR] &= ~(UART_CR_TXRST | UART_CR_RXRST);
-
-    if ((s->r[R_CR] & UART_CR_TX_EN) && !(s->r[R_CR] & UART_CR_TX_DIS)) {
-            uart_tx_redo(s);
-    }
-
-    if (s->r[R_CR] & UART_CR_STARTBRK && !(s->r[R_CR] & UART_CR_STOPBRK)) {
-        uart_send_breaks(s);
-    }
-}
-
-static void uart_write_rx_fifo(void *opaque, const uint8_t *buf, int size)
-{
-    UartState *s = (UartState *)opaque;
-    uint64_t new_rx_time = qemu_get_clock_ns(vm_clock);
-    int i;
-
-    if ((s->r[R_CR] & UART_CR_RX_DIS) || !(s->r[R_CR] & UART_CR_RX_EN)) {
-        return;
-    }
-
-    s->r[R_SR] &= ~UART_SR_INTR_REMPTY;
-
-    if (s->rx_count == RX_FIFO_SIZE) {
-        s->r[R_CISR] |= UART_INTR_ROVR;
-    } else {
-        for (i = 0; i < size; i++) {
-            s->r_fifo[s->rx_wpos] = buf[i];
-            s->rx_wpos = (s->rx_wpos + 1) % RX_FIFO_SIZE;
-            s->rx_count++;
-
-            if (s->rx_count == RX_FIFO_SIZE) {
-                s->r[R_SR] |= UART_SR_INTR_RFUL;
-                break;
-            }
-
-            if (s->rx_count >= s->r[R_RTRIG]) {
-                s->r[R_SR] |= UART_SR_INTR_RTRIG;
-            }
-        }
-        qemu_mod_timer(s->fifo_trigger_handle, new_rx_time +
-                                                (s->char_tx_time * 4));
-    }
-    uart_update_status(s);
-}
-
-static void uart_write_tx_fifo(UartState *s, const uint8_t *buf, int size)
-{
-    if ((s->r[R_CR] & UART_CR_TX_DIS) || !(s->r[R_CR] & UART_CR_TX_EN)) {
-        return;
-    }
-
-    while (size) {
-        size -= qemu_chr_fe_write(s->chr, buf, size);
-    }
-}
-
-static void uart_receive(void *opaque, const uint8_t *buf, int size)
-{
-    UartState *s = (UartState *)opaque;
-    uint32_t ch_mode = s->r[R_MR] & UART_MR_CHMODE;
-
-    if (ch_mode == NORMAL_MODE || ch_mode == ECHO_MODE) {
-        uart_write_rx_fifo(opaque, buf, size);
-    }
-    if (ch_mode == REMOTE_LOOPBACK || ch_mode == ECHO_MODE) {
-        uart_write_tx_fifo(s, buf, size);
-    }
-}
-
-static void uart_event(void *opaque, int event)
-{
-    UartState *s = (UartState *)opaque;
-    uint8_t buf = '\0';
-
-    if (event == CHR_EVENT_BREAK) {
-        uart_write_rx_fifo(opaque, &buf, 1);
-    }
-
-    uart_update_status(s);
-}
-
-static void uart_read_rx_fifo(UartState *s, uint32_t *c)
-{
-    if ((s->r[R_CR] & UART_CR_RX_DIS) || !(s->r[R_CR] & UART_CR_RX_EN)) {
-        return;
-    }
-
-    s->r[R_SR] &= ~UART_SR_INTR_RFUL;
-
-    if (s->rx_count) {
-        uint32_t rx_rpos =
-                (RX_FIFO_SIZE + s->rx_wpos - s->rx_count) % RX_FIFO_SIZE;
-        *c = s->r_fifo[rx_rpos];
-        s->rx_count--;
-
-        if (!s->rx_count) {
-            s->r[R_SR] |= UART_SR_INTR_REMPTY;
-        }
-        qemu_chr_accept_input(s->chr);
-    } else {
-        *c = 0;
-        s->r[R_SR] |= UART_SR_INTR_REMPTY;
-    }
-
-    if (s->rx_count < s->r[R_RTRIG]) {
-        s->r[R_SR] &= ~UART_SR_INTR_RTRIG;
-    }
-    uart_update_status(s);
-}
-
-static void uart_write(void *opaque, hwaddr offset,
-                          uint64_t value, unsigned size)
-{
-    UartState *s = (UartState *)opaque;
-
-    DB_PRINT(" offset:%x data:%08x\n", (unsigned)offset, (unsigned)value);
-    offset >>= 2;
-    switch (offset) {
-    case R_IER: /* ier (wts imr) */
-        s->r[R_IMR] |= value;
-        break;
-    case R_IDR: /* idr (wtc imr) */
-        s->r[R_IMR] &= ~value;
-        break;
-    case R_IMR: /* imr (read only) */
-        break;
-    case R_CISR: /* cisr (wtc) */
-        s->r[R_CISR] &= ~value;
-        break;
-    case R_TX_RX: /* UARTDR */
-        switch (s->r[R_MR] & UART_MR_CHMODE) {
-        case NORMAL_MODE:
-            uart_write_tx_fifo(s, (uint8_t *) &value, 1);
-            break;
-        case LOCAL_LOOPBACK:
-            uart_write_rx_fifo(opaque, (uint8_t *) &value, 1);
-            break;
-        }
-        break;
-    default:
-        s->r[offset] = value;
-    }
-
-    switch (offset) {
-    case R_CR:
-        uart_ctrl_update(s);
-        break;
-    case R_MR:
-        uart_parameters_setup(s);
-        break;
-    }
-}
-
-static uint64_t uart_read(void *opaque, hwaddr offset,
-        unsigned size)
-{
-    UartState *s = (UartState *)opaque;
-    uint32_t c = 0;
-
-    offset >>= 2;
-    if (offset >= R_MAX) {
-        c = 0;
-    } else if (offset == R_TX_RX) {
-        uart_read_rx_fifo(s, &c);
-    } else {
-       c = s->r[offset];
-    }
-
-    DB_PRINT(" offset:%x data:%08x\n", (unsigned)(offset << 2), (unsigned)c);
-    return c;
-}
-
-static const MemoryRegionOps uart_ops = {
-    .read = uart_read,
-    .write = uart_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void cadence_uart_reset(UartState *s)
-{
-    s->r[R_CR] = 0x00000128;
-    s->r[R_IMR] = 0;
-    s->r[R_CISR] = 0;
-    s->r[R_RTRIG] = 0x00000020;
-    s->r[R_BRGR] = 0x0000000F;
-    s->r[R_TTRIG] = 0x00000020;
-
-    uart_rx_reset(s);
-    uart_tx_reset(s);
-
-    s->rx_count = 0;
-    s->rx_wpos = 0;
-}
-
-static int cadence_uart_init(SysBusDevice *dev)
-{
-    UartState *s = FROM_SYSBUS(UartState, dev);
-
-    memory_region_init_io(&s->iomem, &uart_ops, s, "uart", 0x1000);
-    sysbus_init_mmio(dev, &s->iomem);
-    sysbus_init_irq(dev, &s->irq);
-
-    s->fifo_trigger_handle = qemu_new_timer_ns(vm_clock,
-            (QEMUTimerCB *)fifo_trigger_update, s);
-
-    s->tx_time_handle = qemu_new_timer_ns(vm_clock,
-            (QEMUTimerCB *)uart_tx_write, s);
-
-    s->char_tx_time = (get_ticks_per_sec() / 9600) * 10;
-
-    s->chr = qemu_char_get_next_serial();
-
-    cadence_uart_reset(s);
-
-    if (s->chr) {
-        qemu_chr_add_handlers(s->chr, uart_can_receive, uart_receive,
-                              uart_event, s);
-    }
-
-    return 0;
-}
-
-static int cadence_uart_post_load(void *opaque, int version_id)
-{
-    UartState *s = opaque;
-
-    uart_parameters_setup(s);
-    uart_update_status(s);
-    return 0;
-}
-
-static const VMStateDescription vmstate_cadence_uart = {
-    .name = "cadence_uart",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .post_load = cadence_uart_post_load,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT32_ARRAY(r, UartState, R_MAX),
-        VMSTATE_UINT8_ARRAY(r_fifo, UartState, RX_FIFO_SIZE),
-        VMSTATE_UINT32(rx_count, UartState),
-        VMSTATE_UINT32(rx_wpos, UartState),
-        VMSTATE_TIMER(fifo_trigger_handle, UartState),
-        VMSTATE_TIMER(tx_time_handle, UartState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void cadence_uart_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
-
-    sdc->init = cadence_uart_init;
-    dc->vmsd = &vmstate_cadence_uart;
-}
-
-static const TypeInfo cadence_uart_info = {
-    .name          = "cadence_uart",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(UartState),
-    .class_init    = cadence_uart_class_init,
-};
-
-static void cadence_uart_register_types(void)
-{
-    type_register_static(&cadence_uart_info);
-}
-
-type_init(cadence_uart_register_types)
diff --git a/hw/cbus.c b/hw/cbus.c
deleted file mode 100644 (file)
index 29b467b..0000000
--- a/hw/cbus.c
+++ /dev/null
@@ -1,618 +0,0 @@
-/*
- * CBUS three-pin bus and the Retu / Betty / Tahvo / Vilma / Avilma /
- * Hinku / Vinku / Ahne / Pihi chips used in various Nokia platforms.
- * Based on reverse-engineering of a linux driver.
- *
- * Copyright (C) 2008 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.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 or
- * (at your option) version 3 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
- * 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 "hw/irq.h"
-#include "hw/devices.h"
-#include "sysemu/sysemu.h"
-
-//#define DEBUG
-
-typedef struct {
-    void *opaque;
-    void (*io)(void *opaque, int rw, int reg, uint16_t *val);
-    int addr;
-} CBusSlave;
-
-typedef struct {
-    CBus cbus;
-
-    int sel;
-    int dat;
-    int clk;
-    int bit;
-    int dir;
-    uint16_t val;
-    qemu_irq dat_out;
-
-    int addr;
-    int reg;
-    int rw;
-    enum {
-        cbus_address,
-        cbus_value,
-    } cycle;
-
-    CBusSlave *slave[8];
-} CBusPriv;
-
-static void cbus_io(CBusPriv *s)
-{
-    if (s->slave[s->addr])
-        s->slave[s->addr]->io(s->slave[s->addr]->opaque,
-                        s->rw, s->reg, &s->val);
-    else
-        hw_error("%s: bad slave address %i\n", __FUNCTION__, s->addr);
-}
-
-static void cbus_cycle(CBusPriv *s)
-{
-    switch (s->cycle) {
-    case cbus_address:
-        s->addr = (s->val >> 6) & 7;
-        s->rw =   (s->val >> 5) & 1;
-        s->reg =  (s->val >> 0) & 0x1f;
-
-        s->cycle = cbus_value;
-        s->bit = 15;
-        s->dir = !s->rw;
-        s->val = 0;
-
-        if (s->rw)
-            cbus_io(s);
-        break;
-
-    case cbus_value:
-        if (!s->rw)
-            cbus_io(s);
-
-        s->cycle = cbus_address;
-        s->bit = 8;
-        s->dir = 1;
-        s->val = 0;
-        break;
-    }
-}
-
-static void cbus_clk(void *opaque, int line, int level)
-{
-    CBusPriv *s = (CBusPriv *) opaque;
-
-    if (!s->sel && level && !s->clk) {
-        if (s->dir)
-            s->val |= s->dat << (s->bit --);
-        else
-            qemu_set_irq(s->dat_out, (s->val >> (s->bit --)) & 1);
-
-        if (s->bit < 0)
-            cbus_cycle(s);
-    }
-
-    s->clk = level;
-}
-
-static void cbus_dat(void *opaque, int line, int level)
-{
-    CBusPriv *s = (CBusPriv *) opaque;
-
-    s->dat = level;
-}
-
-static void cbus_sel(void *opaque, int line, int level)
-{
-    CBusPriv *s = (CBusPriv *) opaque;
-
-    if (!level) {
-        s->dir = 1;
-        s->bit = 8;
-        s->val = 0;
-    }
-
-    s->sel = level;
-}
-
-CBus *cbus_init(qemu_irq dat)
-{
-    CBusPriv *s = (CBusPriv *) g_malloc0(sizeof(*s));
-
-    s->dat_out = dat;
-    s->cbus.clk = qemu_allocate_irqs(cbus_clk, s, 1)[0];
-    s->cbus.dat = qemu_allocate_irqs(cbus_dat, s, 1)[0];
-    s->cbus.sel = qemu_allocate_irqs(cbus_sel, s, 1)[0];
-
-    s->sel = 1;
-    s->clk = 0;
-    s->dat = 0;
-
-    return &s->cbus;
-}
-
-void cbus_attach(CBus *bus, void *slave_opaque)
-{
-    CBusSlave *slave = (CBusSlave *) slave_opaque;
-    CBusPriv *s = (CBusPriv *) bus;
-
-    s->slave[slave->addr] = slave;
-}
-
-/* Retu/Vilma */
-typedef struct {
-    uint16_t irqst;
-    uint16_t irqen;
-    uint16_t cc[2];
-    int channel;
-    uint16_t result[16];
-    uint16_t sample;
-    uint16_t status;
-
-    struct {
-        uint16_t cal;
-    } rtc;
-
-    int is_vilma;
-    qemu_irq irq;
-    CBusSlave cbus;
-} CBusRetu;
-
-static void retu_interrupt_update(CBusRetu *s)
-{
-    qemu_set_irq(s->irq, s->irqst & ~s->irqen);
-}
-
-#define RETU_REG_ASICR         0x00    /* (RO) ASIC ID & revision */
-#define RETU_REG_IDR           0x01    /* (T)  Interrupt ID */
-#define RETU_REG_IMR           0x02    /* (RW) Interrupt mask */
-#define RETU_REG_RTCDSR                0x03    /* (RW) RTC seconds register */
-#define RETU_REG_RTCHMR                0x04    /* (RO) RTC hours and minutes reg */
-#define RETU_REG_RTCHMAR       0x05    /* (RW) RTC hours and minutes set reg */
-#define RETU_REG_RTCCALR       0x06    /* (RW) RTC calibration register */
-#define RETU_REG_ADCR          0x08    /* (RW) ADC result register */
-#define RETU_REG_ADCSCR                0x09    /* (RW) ADC sample control register */
-#define RETU_REG_AFCR          0x0a    /* (RW) AFC register */
-#define RETU_REG_ANTIFR                0x0b    /* (RW) AntiF register */
-#define RETU_REG_CALIBR                0x0c    /* (RW) CalibR register*/
-#define RETU_REG_CCR1          0x0d    /* (RW) Common control register 1 */
-#define RETU_REG_CCR2          0x0e    /* (RW) Common control register 2 */
-#define RETU_REG_RCTRL_CLR     0x0f    /* (T)  Regulator clear register */
-#define RETU_REG_RCTRL_SET     0x10    /* (T)  Regulator set register */
-#define RETU_REG_TXCR          0x11    /* (RW) TxC register */
-#define RETU_REG_STATUS                0x16    /* (RO) Status register */
-#define RETU_REG_WATCHDOG      0x17    /* (RW) Watchdog register */
-#define RETU_REG_AUDTXR                0x18    /* (RW) Audio Codec Tx register */
-#define RETU_REG_AUDPAR                0x19    /* (RW) AudioPA register */
-#define RETU_REG_AUDRXR1       0x1a    /* (RW) Audio receive register 1 */
-#define RETU_REG_AUDRXR2       0x1b    /* (RW) Audio receive register 2 */
-#define RETU_REG_SGR1          0x1c    /* (RW) */
-#define RETU_REG_SCR1          0x1d    /* (RW) */
-#define RETU_REG_SGR2          0x1e    /* (RW) */
-#define RETU_REG_SCR2          0x1f    /* (RW) */
-
-/* Retu Interrupt sources */
-enum {
-    retu_int_pwr       = 0,    /* Power button */
-    retu_int_char      = 1,    /* Charger */
-    retu_int_rtcs      = 2,    /* Seconds */
-    retu_int_rtcm      = 3,    /* Minutes */
-    retu_int_rtcd      = 4,    /* Days */
-    retu_int_rtca      = 5,    /* Alarm */
-    retu_int_hook      = 6,    /* Hook */
-    retu_int_head      = 7,    /* Headset */
-    retu_int_adcs      = 8,    /* ADC sample */
-};
-
-/* Retu ADC channel wiring */
-enum {
-    retu_adc_bsi       = 1,    /* BSI */
-    retu_adc_batt_temp = 2,    /* Battery temperature */
-    retu_adc_chg_volt  = 3,    /* Charger voltage */
-    retu_adc_head_det  = 4,    /* Headset detection */
-    retu_adc_hook_det  = 5,    /* Hook detection */
-    retu_adc_rf_gp     = 6,    /* RF GP */
-    retu_adc_tx_det    = 7,    /* Wideband Tx detection */
-    retu_adc_batt_volt = 8,    /* Battery voltage */
-    retu_adc_sens      = 10,   /* Light sensor */
-    retu_adc_sens_temp = 11,   /* Light sensor temperature */
-    retu_adc_bbatt_volt        = 12,   /* Backup battery voltage */
-    retu_adc_self_temp = 13,   /* RETU temperature */
-};
-
-static inline uint16_t retu_read(CBusRetu *s, int reg)
-{
-#ifdef DEBUG
-    printf("RETU read at %02x\n", reg);
-#endif
-
-    switch (reg) {
-    case RETU_REG_ASICR:
-        return 0x0215 | (s->is_vilma << 7);
-
-    case RETU_REG_IDR: /* TODO: Or is this ffs(s->irqst)?  */
-        return s->irqst;
-
-    case RETU_REG_IMR:
-        return s->irqen;
-
-    case RETU_REG_RTCDSR:
-    case RETU_REG_RTCHMR:
-    case RETU_REG_RTCHMAR:
-        /* TODO */
-        return 0x0000;
-
-    case RETU_REG_RTCCALR:
-        return s->rtc.cal;
-
-    case RETU_REG_ADCR:
-        return (s->channel << 10) | s->result[s->channel];
-    case RETU_REG_ADCSCR:
-        return s->sample;
-
-    case RETU_REG_AFCR:
-    case RETU_REG_ANTIFR:
-    case RETU_REG_CALIBR:
-        /* TODO */
-        return 0x0000;
-
-    case RETU_REG_CCR1:
-        return s->cc[0];
-    case RETU_REG_CCR2:
-        return s->cc[1];
-
-    case RETU_REG_RCTRL_CLR:
-    case RETU_REG_RCTRL_SET:
-    case RETU_REG_TXCR:
-        /* TODO */
-        return 0x0000;
-
-    case RETU_REG_STATUS:
-        return s->status;
-
-    case RETU_REG_WATCHDOG:
-    case RETU_REG_AUDTXR:
-    case RETU_REG_AUDPAR:
-    case RETU_REG_AUDRXR1:
-    case RETU_REG_AUDRXR2:
-    case RETU_REG_SGR1:
-    case RETU_REG_SCR1:
-    case RETU_REG_SGR2:
-    case RETU_REG_SCR2:
-        /* TODO */
-        return 0x0000;
-
-    default:
-        hw_error("%s: bad register %02x\n", __FUNCTION__, reg);
-    }
-}
-
-static inline void retu_write(CBusRetu *s, int reg, uint16_t val)
-{
-#ifdef DEBUG
-    printf("RETU write of %04x at %02x\n", val, reg);
-#endif
-
-    switch (reg) {
-    case RETU_REG_IDR:
-        s->irqst ^= val;
-        retu_interrupt_update(s);
-        break;
-
-    case RETU_REG_IMR:
-        s->irqen = val;
-        retu_interrupt_update(s);
-        break;
-
-    case RETU_REG_RTCDSR:
-    case RETU_REG_RTCHMAR:
-        /* TODO */
-        break;
-
-    case RETU_REG_RTCCALR:
-        s->rtc.cal = val;
-        break;
-
-    case RETU_REG_ADCR:
-        s->channel = (val >> 10) & 0xf;
-        s->irqst |= 1 << retu_int_adcs;
-        retu_interrupt_update(s);
-        break;
-    case RETU_REG_ADCSCR:
-        s->sample &= ~val;
-        break;
-
-    case RETU_REG_AFCR:
-    case RETU_REG_ANTIFR:
-    case RETU_REG_CALIBR:
-
-    case RETU_REG_CCR1:
-        s->cc[0] = val;
-        break;
-    case RETU_REG_CCR2:
-        s->cc[1] = val;
-        break;
-
-    case RETU_REG_RCTRL_CLR:
-    case RETU_REG_RCTRL_SET:
-        /* TODO */
-        break;
-
-    case RETU_REG_WATCHDOG:
-        if (val == 0 && (s->cc[0] & 2))
-            qemu_system_shutdown_request();
-        break;
-
-    case RETU_REG_TXCR:
-    case RETU_REG_AUDTXR:
-    case RETU_REG_AUDPAR:
-    case RETU_REG_AUDRXR1:
-    case RETU_REG_AUDRXR2:
-    case RETU_REG_SGR1:
-    case RETU_REG_SCR1:
-    case RETU_REG_SGR2:
-    case RETU_REG_SCR2:
-        /* TODO */
-        break;
-
-    default:
-        hw_error("%s: bad register %02x\n", __FUNCTION__, reg);
-    }
-}
-
-static void retu_io(void *opaque, int rw, int reg, uint16_t *val)
-{
-    CBusRetu *s = (CBusRetu *) opaque;
-
-    if (rw)
-        *val = retu_read(s, reg);
-    else
-        retu_write(s, reg, *val);
-}
-
-void *retu_init(qemu_irq irq, int vilma)
-{
-    CBusRetu *s = (CBusRetu *) g_malloc0(sizeof(*s));
-
-    s->irq = irq;
-    s->irqen = 0xffff;
-    s->irqst = 0x0000;
-    s->status = 0x0020;
-    s->is_vilma = !!vilma;
-    s->rtc.cal = 0x01;
-    s->result[retu_adc_bsi] = 0x3c2;
-    s->result[retu_adc_batt_temp] = 0x0fc;
-    s->result[retu_adc_chg_volt] = 0x165;
-    s->result[retu_adc_head_det] = 123;
-    s->result[retu_adc_hook_det] = 1023;
-    s->result[retu_adc_rf_gp] = 0x11;
-    s->result[retu_adc_tx_det] = 0x11;
-    s->result[retu_adc_batt_volt] = 0x250;
-    s->result[retu_adc_sens] = 2;
-    s->result[retu_adc_sens_temp] = 0x11;
-    s->result[retu_adc_bbatt_volt] = 0x3d0;
-    s->result[retu_adc_self_temp] = 0x330;
-
-    s->cbus.opaque = s;
-    s->cbus.io = retu_io;
-    s->cbus.addr = 1;
-
-    return &s->cbus;
-}
-
-void retu_key_event(void *retu, int state)
-{
-    CBusSlave *slave = (CBusSlave *) retu;
-    CBusRetu *s = (CBusRetu *) slave->opaque;
-
-    s->irqst |= 1 << retu_int_pwr;
-    retu_interrupt_update(s);
-
-    if (state)
-        s->status &= ~(1 << 5);
-    else
-        s->status |= 1 << 5;
-}
-
-#if 0
-static void retu_head_event(void *retu, int state)
-{
-    CBusSlave *slave = (CBusSlave *) retu;
-    CBusRetu *s = (CBusRetu *) slave->opaque;
-
-    if ((s->cc[0] & 0x500) == 0x500) { /* TODO: Which bits? */
-        /* TODO: reissue the interrupt every 100ms or so.  */
-        s->irqst |= 1 << retu_int_head;
-        retu_interrupt_update(s);
-    }
-
-    if (state)
-        s->result[retu_adc_head_det] = 50;
-    else
-        s->result[retu_adc_head_det] = 123;
-}
-
-static void retu_hook_event(void *retu, int state)
-{
-    CBusSlave *slave = (CBusSlave *) retu;
-    CBusRetu *s = (CBusRetu *) slave->opaque;
-
-    if ((s->cc[0] & 0x500) == 0x500) {
-        /* TODO: reissue the interrupt every 100ms or so.  */
-        s->irqst |= 1 << retu_int_hook;
-        retu_interrupt_update(s);
-    }
-
-    if (state)
-        s->result[retu_adc_hook_det] = 50;
-    else
-        s->result[retu_adc_hook_det] = 123;
-}
-#endif
-
-/* Tahvo/Betty */
-typedef struct {
-    uint16_t irqst;
-    uint16_t irqen;
-    uint8_t charger;
-    uint8_t backlight;
-    uint16_t usbr;
-    uint16_t power;
-
-    int is_betty;
-    qemu_irq irq;
-    CBusSlave cbus;
-} CBusTahvo;
-
-static void tahvo_interrupt_update(CBusTahvo *s)
-{
-    qemu_set_irq(s->irq, s->irqst & ~s->irqen);
-}
-
-#define TAHVO_REG_ASICR                0x00    /* (RO) ASIC ID & revision */
-#define TAHVO_REG_IDR          0x01    /* (T)  Interrupt ID */
-#define TAHVO_REG_IDSR         0x02    /* (RO) Interrupt status */
-#define TAHVO_REG_IMR          0x03    /* (RW) Interrupt mask */
-#define TAHVO_REG_CHAPWMR      0x04    /* (RW) Charger PWM */
-#define TAHVO_REG_LEDPWMR      0x05    /* (RW) LED PWM */
-#define TAHVO_REG_USBR         0x06    /* (RW) USB control */
-#define TAHVO_REG_RCR          0x07    /* (RW) Some kind of power management */
-#define TAHVO_REG_CCR1         0x08    /* (RW) Common control register 1 */
-#define TAHVO_REG_CCR2         0x09    /* (RW) Common control register 2 */
-#define TAHVO_REG_TESTR1       0x0a    /* (RW) Test register 1 */
-#define TAHVO_REG_TESTR2       0x0b    /* (RW) Test register 2 */
-#define TAHVO_REG_NOPR         0x0c    /* (RW) Number of periods */
-#define TAHVO_REG_FRR          0x0d    /* (RO) FR */
-
-static inline uint16_t tahvo_read(CBusTahvo *s, int reg)
-{
-#ifdef DEBUG
-    printf("TAHVO read at %02x\n", reg);
-#endif
-
-    switch (reg) {
-    case TAHVO_REG_ASICR:
-        return 0x0021 | (s->is_betty ? 0x0b00 : 0x0300);       /* 22 in N810 */
-
-    case TAHVO_REG_IDR:
-    case TAHVO_REG_IDSR:       /* XXX: what does this do?  */
-        return s->irqst;
-
-    case TAHVO_REG_IMR:
-        return s->irqen;
-
-    case TAHVO_REG_CHAPWMR:
-        return s->charger;
-
-    case TAHVO_REG_LEDPWMR:
-        return s->backlight;
-
-    case TAHVO_REG_USBR:
-        return s->usbr;
-
-    case TAHVO_REG_RCR:
-        return s->power;
-
-    case TAHVO_REG_CCR1:
-    case TAHVO_REG_CCR2:
-    case TAHVO_REG_TESTR1:
-    case TAHVO_REG_TESTR2:
-    case TAHVO_REG_NOPR:
-    case TAHVO_REG_FRR:
-        return 0x0000;
-
-    default:
-        hw_error("%s: bad register %02x\n", __FUNCTION__, reg);
-    }
-}
-
-static inline void tahvo_write(CBusTahvo *s, int reg, uint16_t val)
-{
-#ifdef DEBUG
-    printf("TAHVO write of %04x at %02x\n", val, reg);
-#endif
-
-    switch (reg) {
-    case TAHVO_REG_IDR:
-        s->irqst ^= val;
-        tahvo_interrupt_update(s);
-        break;
-
-    case TAHVO_REG_IMR:
-        s->irqen = val;
-        tahvo_interrupt_update(s);
-        break;
-
-    case TAHVO_REG_CHAPWMR:
-        s->charger = val;
-        break;
-
-    case TAHVO_REG_LEDPWMR:
-        if (s->backlight != (val & 0x7f)) {
-            s->backlight = val & 0x7f;
-            printf("%s: LCD backlight now at %i / 127\n",
-                            __FUNCTION__, s->backlight);
-        }
-        break;
-
-    case TAHVO_REG_USBR:
-        s->usbr = val;
-        break;
-
-    case TAHVO_REG_RCR:
-        s->power = val;
-        break;
-
-    case TAHVO_REG_CCR1:
-    case TAHVO_REG_CCR2:
-    case TAHVO_REG_TESTR1:
-    case TAHVO_REG_TESTR2:
-    case TAHVO_REG_NOPR:
-    case TAHVO_REG_FRR:
-        break;
-
-    default:
-        hw_error("%s: bad register %02x\n", __FUNCTION__, reg);
-    }
-}
-
-static void tahvo_io(void *opaque, int rw, int reg, uint16_t *val)
-{
-    CBusTahvo *s = (CBusTahvo *) opaque;
-
-    if (rw)
-        *val = tahvo_read(s, reg);
-    else
-        tahvo_write(s, reg, *val);
-}
-
-void *tahvo_init(qemu_irq irq, int betty)
-{
-    CBusTahvo *s = (CBusTahvo *) g_malloc0(sizeof(*s));
-
-    s->irq = irq;
-    s->irqen = 0xffff;
-    s->irqst = 0x0000;
-    s->is_betty = !!betty;
-
-    s->cbus.opaque = s;
-    s->cbus.io = tahvo_io;
-    s->cbus.addr = 2;
-
-    return &s->cbus;
-}
diff --git a/hw/ccid-card-emulated.c b/hw/ccid-card-emulated.c
deleted file mode 100644 (file)
index c8f8ba3..0000000
+++ /dev/null
@@ -1,602 +0,0 @@
-/*
- * CCID Card Device. Emulated card.
- *
- * Copyright (c) 2011 Red Hat.
- * Written by Alon Levy.
- *
- * This code is licensed under the GNU LGPL, version 2 or later.
- */
-
-/*
- * It can be used to provide access to the local hardware in a non exclusive
- * way, or it can use certificates. It requires the usb-ccid bus.
- *
- * Usage 1: standard, mirror hardware reader+card:
- * qemu .. -usb -device usb-ccid -device ccid-card-emulated
- *
- * Usage 2: use certificates, no hardware required
- * one time: create the certificates:
- *  for i in 1 2 3; do
- *      certutil -d /etc/pki/nssdb -x -t "CT,CT,CT" -S -s "CN=user$i" -n user$i
- *  done
- * qemu .. -usb -device usb-ccid \
- *  -device ccid-card-emulated,cert1=user1,cert2=user2,cert3=user3
- *
- * If you use a non default db for the certificates you can specify it using
- * the db parameter.
- */
-
-#include <eventt.h>
-#include <vevent.h>
-#include <vreader.h>
-#include <vcard_emul.h>
-
-#include "qemu/thread.h"
-#include "char/char.h"
-#include "monitor/monitor.h"
-#include "hw/ccid.h"
-
-#define DPRINTF(card, lvl, fmt, ...) \
-do {\
-    if (lvl <= card->debug) {\
-        printf("ccid-card-emul: %s: " fmt , __func__, ## __VA_ARGS__);\
-    } \
-} while (0)
-
-#define EMULATED_DEV_NAME "ccid-card-emulated"
-
-#define BACKEND_NSS_EMULATED_NAME "nss-emulated"
-#define BACKEND_CERTIFICATES_NAME "certificates"
-
-enum {
-    BACKEND_NSS_EMULATED = 1,
-    BACKEND_CERTIFICATES
-};
-
-#define DEFAULT_BACKEND BACKEND_NSS_EMULATED
-
-typedef struct EmulatedState EmulatedState;
-
-enum {
-    EMUL_READER_INSERT = 0,
-    EMUL_READER_REMOVE,
-    EMUL_CARD_INSERT,
-    EMUL_CARD_REMOVE,
-    EMUL_GUEST_APDU,
-    EMUL_RESPONSE_APDU,
-    EMUL_ERROR,
-};
-
-static const char *emul_event_to_string(uint32_t emul_event)
-{
-    switch (emul_event) {
-    case EMUL_READER_INSERT:
-        return "EMUL_READER_INSERT";
-    case EMUL_READER_REMOVE:
-        return "EMUL_READER_REMOVE";
-    case EMUL_CARD_INSERT:
-        return "EMUL_CARD_INSERT";
-    case EMUL_CARD_REMOVE:
-        return "EMUL_CARD_REMOVE";
-    case EMUL_GUEST_APDU:
-        return "EMUL_GUEST_APDU";
-    case EMUL_RESPONSE_APDU:
-        return "EMUL_RESPONSE_APDU";
-    case EMUL_ERROR:
-        return "EMUL_ERROR";
-    }
-    return "UNKNOWN";
-}
-
-typedef struct EmulEvent {
-    QSIMPLEQ_ENTRY(EmulEvent) entry;
-    union {
-        struct {
-            uint32_t type;
-        } gen;
-        struct {
-            uint32_t type;
-            uint64_t code;
-        } error;
-        struct {
-            uint32_t type;
-            uint32_t len;
-            uint8_t data[];
-        } data;
-    } p;
-} EmulEvent;
-
-#define MAX_ATR_SIZE 40
-struct EmulatedState {
-    CCIDCardState base;
-    uint8_t  debug;
-    char    *backend_str;
-    uint32_t backend;
-    char    *cert1;
-    char    *cert2;
-    char    *cert3;
-    char    *db;
-    uint8_t  atr[MAX_ATR_SIZE];
-    uint8_t  atr_length;
-    QSIMPLEQ_HEAD(event_list, EmulEvent) event_list;
-    QemuMutex event_list_mutex;
-    QemuThread event_thread_id;
-    VReader *reader;
-    QSIMPLEQ_HEAD(guest_apdu_list, EmulEvent) guest_apdu_list;
-    QemuMutex vreader_mutex; /* and guest_apdu_list mutex */
-    QemuMutex handle_apdu_mutex;
-    QemuCond handle_apdu_cond;
-    int      pipe[2];
-    int      quit_apdu_thread;
-    QemuThread apdu_thread_id;
-};
-
-static void emulated_apdu_from_guest(CCIDCardState *base,
-    const uint8_t *apdu, uint32_t len)
-{
-    EmulatedState *card = DO_UPCAST(EmulatedState, base, base);
-    EmulEvent *event = (EmulEvent *)g_malloc(sizeof(EmulEvent) + len);
-
-    assert(event);
-    event->p.data.type = EMUL_GUEST_APDU;
-    event->p.data.len = len;
-    memcpy(event->p.data.data, apdu, len);
-    qemu_mutex_lock(&card->vreader_mutex);
-    QSIMPLEQ_INSERT_TAIL(&card->guest_apdu_list, event, entry);
-    qemu_mutex_unlock(&card->vreader_mutex);
-    qemu_mutex_lock(&card->handle_apdu_mutex);
-    qemu_cond_signal(&card->handle_apdu_cond);
-    qemu_mutex_unlock(&card->handle_apdu_mutex);
-}
-
-static const uint8_t *emulated_get_atr(CCIDCardState *base, uint32_t *len)
-{
-    EmulatedState *card = DO_UPCAST(EmulatedState, base, base);
-
-    *len = card->atr_length;
-    return card->atr;
-}
-
-static void emulated_push_event(EmulatedState *card, EmulEvent *event)
-{
-    qemu_mutex_lock(&card->event_list_mutex);
-    QSIMPLEQ_INSERT_TAIL(&(card->event_list), event, entry);
-    qemu_mutex_unlock(&card->event_list_mutex);
-    if (write(card->pipe[1], card, 1) != 1) {
-        DPRINTF(card, 1, "write to pipe failed\n");
-    }
-}
-
-static void emulated_push_type(EmulatedState *card, uint32_t type)
-{
-    EmulEvent *event = (EmulEvent *)g_malloc(sizeof(EmulEvent));
-
-    assert(event);
-    event->p.gen.type = type;
-    emulated_push_event(card, event);
-}
-
-static void emulated_push_error(EmulatedState *card, uint64_t code)
-{
-    EmulEvent *event = (EmulEvent *)g_malloc(sizeof(EmulEvent));
-
-    assert(event);
-    event->p.error.type = EMUL_ERROR;
-    event->p.error.code = code;
-    emulated_push_event(card, event);
-}
-
-static void emulated_push_data_type(EmulatedState *card, uint32_t type,
-    const uint8_t *data, uint32_t len)
-{
-    EmulEvent *event = (EmulEvent *)g_malloc(sizeof(EmulEvent) + len);
-
-    assert(event);
-    event->p.data.type = type;
-    event->p.data.len = len;
-    memcpy(event->p.data.data, data, len);
-    emulated_push_event(card, event);
-}
-
-static void emulated_push_reader_insert(EmulatedState *card)
-{
-    emulated_push_type(card, EMUL_READER_INSERT);
-}
-
-static void emulated_push_reader_remove(EmulatedState *card)
-{
-    emulated_push_type(card, EMUL_READER_REMOVE);
-}
-
-static void emulated_push_card_insert(EmulatedState *card,
-    const uint8_t *atr, uint32_t len)
-{
-    emulated_push_data_type(card, EMUL_CARD_INSERT, atr, len);
-}
-
-static void emulated_push_card_remove(EmulatedState *card)
-{
-    emulated_push_type(card, EMUL_CARD_REMOVE);
-}
-
-static void emulated_push_response_apdu(EmulatedState *card,
-    const uint8_t *apdu, uint32_t len)
-{
-    emulated_push_data_type(card, EMUL_RESPONSE_APDU, apdu, len);
-}
-
-#define APDU_BUF_SIZE 270
-static void *handle_apdu_thread(void* arg)
-{
-    EmulatedState *card = arg;
-    uint8_t recv_data[APDU_BUF_SIZE];
-    int recv_len;
-    VReaderStatus reader_status;
-    EmulEvent *event;
-
-    while (1) {
-        qemu_mutex_lock(&card->handle_apdu_mutex);
-        qemu_cond_wait(&card->handle_apdu_cond, &card->handle_apdu_mutex);
-        qemu_mutex_unlock(&card->handle_apdu_mutex);
-        if (card->quit_apdu_thread) {
-            card->quit_apdu_thread = 0; /* debugging */
-            break;
-        }
-        qemu_mutex_lock(&card->vreader_mutex);
-        while (!QSIMPLEQ_EMPTY(&card->guest_apdu_list)) {
-            event = QSIMPLEQ_FIRST(&card->guest_apdu_list);
-            assert((unsigned long)event > 1000);
-            QSIMPLEQ_REMOVE_HEAD(&card->guest_apdu_list, entry);
-            if (event->p.data.type != EMUL_GUEST_APDU) {
-                DPRINTF(card, 1, "unexpected message in handle_apdu_thread\n");
-                g_free(event);
-                continue;
-            }
-            if (card->reader == NULL) {
-                DPRINTF(card, 1, "reader is NULL\n");
-                g_free(event);
-                continue;
-            }
-            recv_len = sizeof(recv_data);
-            reader_status = vreader_xfr_bytes(card->reader,
-                    event->p.data.data, event->p.data.len,
-                    recv_data, &recv_len);
-            DPRINTF(card, 2, "got back apdu of length %d\n", recv_len);
-            if (reader_status == VREADER_OK) {
-                emulated_push_response_apdu(card, recv_data, recv_len);
-            } else {
-                emulated_push_error(card, reader_status);
-            }
-            g_free(event);
-        }
-        qemu_mutex_unlock(&card->vreader_mutex);
-    }
-    return NULL;
-}
-
-static void *event_thread(void *arg)
-{
-    int atr_len = MAX_ATR_SIZE;
-    uint8_t atr[MAX_ATR_SIZE];
-    VEvent *event = NULL;
-    EmulatedState *card = arg;
-
-    while (1) {
-        const char *reader_name;
-
-        event = vevent_wait_next_vevent();
-        if (event == NULL || event->type == VEVENT_LAST) {
-            break;
-        }
-        if (event->type != VEVENT_READER_INSERT) {
-            if (card->reader == NULL && event->reader != NULL) {
-                /* Happens after device_add followed by card remove or insert.
-                 * XXX: create synthetic add_reader events if vcard_emul_init
-                 * already called, which happens if device_del and device_add
-                 * are called */
-                card->reader = vreader_reference(event->reader);
-            } else {
-                if (event->reader != card->reader) {
-                    fprintf(stderr,
-                        "ERROR: wrong reader: quiting event_thread\n");
-                    break;
-                }
-            }
-        }
-        switch (event->type) {
-        case VEVENT_READER_INSERT:
-            /* TODO: take a specific reader. i.e. track which reader
-             * we are seeing here, check it is the one we want (the first,
-             * or by a particular name), and ignore if we don't want it.
-             */
-            reader_name = vreader_get_name(event->reader);
-            if (card->reader != NULL) {
-                DPRINTF(card, 2, "READER INSERT - replacing %s with %s\n",
-                    vreader_get_name(card->reader), reader_name);
-                qemu_mutex_lock(&card->vreader_mutex);
-                vreader_free(card->reader);
-                qemu_mutex_unlock(&card->vreader_mutex);
-                emulated_push_reader_remove(card);
-            }
-            qemu_mutex_lock(&card->vreader_mutex);
-            DPRINTF(card, 2, "READER INSERT %s\n", reader_name);
-            card->reader = vreader_reference(event->reader);
-            qemu_mutex_unlock(&card->vreader_mutex);
-            emulated_push_reader_insert(card);
-            break;
-        case VEVENT_READER_REMOVE:
-            DPRINTF(card, 2, " READER REMOVE: %s\n",
-                    vreader_get_name(event->reader));
-            qemu_mutex_lock(&card->vreader_mutex);
-            vreader_free(card->reader);
-            card->reader = NULL;
-            qemu_mutex_unlock(&card->vreader_mutex);
-            emulated_push_reader_remove(card);
-            break;
-        case VEVENT_CARD_INSERT:
-            /* get the ATR (intended as a response to a power on from the
-             * reader */
-            atr_len = MAX_ATR_SIZE;
-            vreader_power_on(event->reader, atr, &atr_len);
-            card->atr_length = (uint8_t)atr_len;
-            DPRINTF(card, 2, " CARD INSERT\n");
-            emulated_push_card_insert(card, atr, atr_len);
-            break;
-        case VEVENT_CARD_REMOVE:
-            DPRINTF(card, 2, " CARD REMOVE\n");
-            emulated_push_card_remove(card);
-            break;
-        case VEVENT_LAST: /* quit */
-            vevent_delete(event);
-            return NULL;
-            break;
-        default:
-            break;
-        }
-        vevent_delete(event);
-    }
-    return NULL;
-}
-
-static void pipe_read(void *opaque)
-{
-    EmulatedState *card = opaque;
-    EmulEvent *event, *next;
-    char dummy;
-    int len;
-
-    do {
-        len = read(card->pipe[0], &dummy, sizeof(dummy));
-    } while (len == sizeof(dummy));
-    qemu_mutex_lock(&card->event_list_mutex);
-    QSIMPLEQ_FOREACH_SAFE(event, &card->event_list, entry, next) {
-        DPRINTF(card, 2, "event %s\n", emul_event_to_string(event->p.gen.type));
-        switch (event->p.gen.type) {
-        case EMUL_RESPONSE_APDU:
-            ccid_card_send_apdu_to_guest(&card->base, event->p.data.data,
-                event->p.data.len);
-            break;
-        case EMUL_READER_INSERT:
-            ccid_card_ccid_attach(&card->base);
-            break;
-        case EMUL_READER_REMOVE:
-            ccid_card_ccid_detach(&card->base);
-            break;
-        case EMUL_CARD_INSERT:
-            assert(event->p.data.len <= MAX_ATR_SIZE);
-            card->atr_length = event->p.data.len;
-            memcpy(card->atr, event->p.data.data, card->atr_length);
-            ccid_card_card_inserted(&card->base);
-            break;
-        case EMUL_CARD_REMOVE:
-            ccid_card_card_removed(&card->base);
-            break;
-        case EMUL_ERROR:
-            ccid_card_card_error(&card->base, event->p.error.code);
-            break;
-        default:
-            DPRINTF(card, 2, "unexpected event\n");
-            break;
-        }
-        g_free(event);
-    }
-    QSIMPLEQ_INIT(&card->event_list);
-    qemu_mutex_unlock(&card->event_list_mutex);
-}
-
-static int init_pipe_signaling(EmulatedState *card)
-{
-    if (pipe(card->pipe) < 0) {
-        DPRINTF(card, 2, "pipe creation failed\n");
-        return -1;
-    }
-    fcntl(card->pipe[0], F_SETFL, O_NONBLOCK);
-    fcntl(card->pipe[1], F_SETFL, O_NONBLOCK);
-    fcntl(card->pipe[0], F_SETOWN, getpid());
-    qemu_set_fd_handler(card->pipe[0], pipe_read, NULL, card);
-    return 0;
-}
-
-#define CERTIFICATES_DEFAULT_DB "/etc/pki/nssdb"
-#define CERTIFICATES_ARGS_TEMPLATE\
-    "db=\"%s\" use_hw=no soft=(,Virtual Reader,CAC,,%s,%s,%s)"
-
-static int wrap_vcard_emul_init(VCardEmulOptions *options)
-{
-    static int called;
-    static int options_was_null;
-
-    if (called) {
-        if ((options == NULL) != options_was_null) {
-            printf("%s: warning: running emulated with certificates"
-                   " and emulated side by side is not supported\n",
-                   __func__);
-            return VCARD_EMUL_FAIL;
-        }
-        vcard_emul_replay_insertion_events();
-        return VCARD_EMUL_OK;
-    }
-    options_was_null = (options == NULL);
-    called = 1;
-    return vcard_emul_init(options);
-}
-
-static int emulated_initialize_vcard_from_certificates(EmulatedState *card)
-{
-    char emul_args[200];
-    VCardEmulOptions *options = NULL;
-
-    snprintf(emul_args, sizeof(emul_args) - 1, CERTIFICATES_ARGS_TEMPLATE,
-        card->db ? card->db : CERTIFICATES_DEFAULT_DB,
-        card->cert1, card->cert2, card->cert3);
-    options = vcard_emul_options(emul_args);
-    if (options == NULL) {
-        printf("%s: warning: not using certificates due to"
-               " initialization error\n", __func__);
-    }
-    return wrap_vcard_emul_init(options);
-}
-
-typedef struct EnumTable {
-    const char *name;
-    uint32_t value;
-} EnumTable;
-
-EnumTable backend_enum_table[] = {
-    {BACKEND_NSS_EMULATED_NAME, BACKEND_NSS_EMULATED},
-    {BACKEND_CERTIFICATES_NAME, BACKEND_CERTIFICATES},
-    {NULL, 0},
-};
-
-static uint32_t parse_enumeration(char *str,
-    EnumTable *table, uint32_t not_found_value)
-{
-    uint32_t ret = not_found_value;
-
-    while (table->name != NULL) {
-        if (strcmp(table->name, str) == 0) {
-            ret = table->value;
-            break;
-        }
-        table++;
-    }
-    return ret;
-}
-
-static int emulated_initfn(CCIDCardState *base)
-{
-    EmulatedState *card = DO_UPCAST(EmulatedState, base, base);
-    VCardEmulError ret;
-    EnumTable *ptable;
-
-    QSIMPLEQ_INIT(&card->event_list);
-    QSIMPLEQ_INIT(&card->guest_apdu_list);
-    qemu_mutex_init(&card->event_list_mutex);
-    qemu_mutex_init(&card->vreader_mutex);
-    qemu_mutex_init(&card->handle_apdu_mutex);
-    qemu_cond_init(&card->handle_apdu_cond);
-    card->reader = NULL;
-    card->quit_apdu_thread = 0;
-    if (init_pipe_signaling(card) < 0) {
-        return -1;
-    }
-    card->backend = parse_enumeration(card->backend_str, backend_enum_table, 0);
-    if (card->backend == 0) {
-        printf("unknown backend, must be one of:\n");
-        for (ptable = backend_enum_table; ptable->name != NULL; ++ptable) {
-            printf("%s\n", ptable->name);
-        }
-        return -1;
-    }
-
-    /* TODO: a passthru backened that works on local machine. third card type?*/
-    if (card->backend == BACKEND_CERTIFICATES) {
-        if (card->cert1 != NULL && card->cert2 != NULL && card->cert3 != NULL) {
-            ret = emulated_initialize_vcard_from_certificates(card);
-        } else {
-            printf("%s: you must provide all three certs for"
-                   " certificates backend\n", EMULATED_DEV_NAME);
-            return -1;
-        }
-    } else {
-        if (card->backend != BACKEND_NSS_EMULATED) {
-            printf("%s: bad backend specified. The options are:\n%s (default),"
-                " %s.\n", EMULATED_DEV_NAME, BACKEND_NSS_EMULATED_NAME,
-                BACKEND_CERTIFICATES_NAME);
-            return -1;
-        }
-        if (card->cert1 != NULL || card->cert2 != NULL || card->cert3 != NULL) {
-            printf("%s: unexpected cert parameters to nss emulated backend\n",
-                   EMULATED_DEV_NAME);
-            return -1;
-        }
-        /* default to mirroring the local hardware readers */
-        ret = wrap_vcard_emul_init(NULL);
-    }
-    if (ret != VCARD_EMUL_OK) {
-        printf("%s: failed to initialize vcard\n", EMULATED_DEV_NAME);
-        return -1;
-    }
-    qemu_thread_create(&card->event_thread_id, event_thread, card,
-                       QEMU_THREAD_JOINABLE);
-    qemu_thread_create(&card->apdu_thread_id, handle_apdu_thread, card,
-                       QEMU_THREAD_JOINABLE);
-    return 0;
-}
-
-static int emulated_exitfn(CCIDCardState *base)
-{
-    EmulatedState *card = DO_UPCAST(EmulatedState, base, base);
-    VEvent *vevent = vevent_new(VEVENT_LAST, NULL, NULL);
-
-    vevent_queue_vevent(vevent); /* stop vevent thread */
-    qemu_thread_join(&card->event_thread_id);
-
-    card->quit_apdu_thread = 1; /* stop handle_apdu thread */
-    qemu_cond_signal(&card->handle_apdu_cond);
-    qemu_thread_join(&card->apdu_thread_id);
-
-    /* threads exited, can destroy all condvars/mutexes */
-    qemu_cond_destroy(&card->handle_apdu_cond);
-    qemu_mutex_destroy(&card->handle_apdu_mutex);
-    qemu_mutex_destroy(&card->vreader_mutex);
-    qemu_mutex_destroy(&card->event_list_mutex);
-    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 const 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_types(void)
-{
-    type_register_static(&emulated_card_info);
-}
-
-type_init(ccid_card_emulated_register_types)
diff --git a/hw/ccid-card-passthru.c b/hw/ccid-card-passthru.c
deleted file mode 100644 (file)
index 984bd0b..0000000
+++ /dev/null
@@ -1,351 +0,0 @@
-/*
- * CCID Passthru Card Device emulation
- *
- * Copyright (c) 2011 Red Hat.
- * Written by Alon Levy.
- *
- * This work is licensed under the terms of the GNU GPL, version 2.1 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include "char/char.h"
-#include "qemu/sockets.h"
-#include "monitor/monitor.h"
-#include "hw/ccid.h"
-#include "libcacard/vscard_common.h"
-
-#define DPRINTF(card, lvl, fmt, ...)                    \
-do {                                                    \
-    if (lvl <= card->debug) {                           \
-        printf("ccid-card-passthru: " fmt , ## __VA_ARGS__);     \
-    }                                                   \
-} while (0)
-
-#define D_WARN 1
-#define D_INFO 2
-#define D_MORE_INFO 3
-#define D_VERBOSE 4
-
-/* TODO: do we still need this? */
-uint8_t DEFAULT_ATR[] = {
-/*
- * From some example somewhere
- * 0x3B, 0xB0, 0x18, 0x00, 0xD1, 0x81, 0x05, 0xB1, 0x40, 0x38, 0x1F, 0x03, 0x28
- */
-
-/* From an Athena smart card */
- 0x3B, 0xD5, 0x18, 0xFF, 0x80, 0x91, 0xFE, 0x1F, 0xC3, 0x80, 0x73, 0xC8, 0x21,
- 0x13, 0x08
-};
-
-
-#define PASSTHRU_DEV_NAME "ccid-card-passthru"
-#define VSCARD_IN_SIZE 65536
-
-/* maximum size of ATR - from 7816-3 */
-#define MAX_ATR_SIZE        40
-
-typedef struct PassthruState PassthruState;
-
-struct PassthruState {
-    CCIDCardState base;
-    CharDriverState *cs;
-    uint8_t  vscard_in_data[VSCARD_IN_SIZE];
-    uint32_t vscard_in_pos;
-    uint32_t vscard_in_hdr;
-    uint8_t  atr[MAX_ATR_SIZE];
-    uint8_t  atr_length;
-    uint8_t  debug;
-};
-
-/*
- * VSCard protocol over chardev
- * This code should not depend on the card type.
- */
-
-static void ccid_card_vscard_send_msg(PassthruState *s,
-        VSCMsgType type, uint32_t reader_id,
-        const uint8_t *payload, uint32_t length)
-{
-    VSCMsgHeader scr_msg_header;
-
-    scr_msg_header.type = htonl(type);
-    scr_msg_header.reader_id = htonl(reader_id);
-    scr_msg_header.length = htonl(length);
-    qemu_chr_fe_write(s->cs, (uint8_t *)&scr_msg_header, sizeof(VSCMsgHeader));
-    qemu_chr_fe_write(s->cs, payload, length);
-}
-
-static void ccid_card_vscard_send_apdu(PassthruState *s,
-    const uint8_t *apdu, uint32_t length)
-{
-    ccid_card_vscard_send_msg(
-        s, VSC_APDU, VSCARD_MINIMAL_READER_ID, apdu, length);
-}
-
-static void ccid_card_vscard_send_error(PassthruState *s,
-                    uint32_t reader_id, VSCErrorCode code)
-{
-    VSCMsgError msg = {.code = htonl(code)};
-
-    ccid_card_vscard_send_msg(
-        s, VSC_Error, reader_id, (uint8_t *)&msg, sizeof(msg));
-}
-
-static void ccid_card_vscard_send_init(PassthruState *s)
-{
-    VSCMsgInit msg = {
-        .version = htonl(VSCARD_VERSION),
-        .magic = VSCARD_MAGIC,
-        .capabilities = {0}
-    };
-
-    ccid_card_vscard_send_msg(s, VSC_Init, VSCARD_UNDEFINED_READER_ID,
-                         (uint8_t *)&msg, sizeof(msg));
-}
-
-static int ccid_card_vscard_can_read(void *opaque)
-{
-    PassthruState *card = opaque;
-
-    return VSCARD_IN_SIZE >= card->vscard_in_pos ?
-           VSCARD_IN_SIZE - card->vscard_in_pos : 0;
-}
-
-static void ccid_card_vscard_handle_init(
-    PassthruState *card, VSCMsgHeader *hdr, VSCMsgInit *init)
-{
-    uint32_t *capabilities;
-    int num_capabilities;
-    int i;
-
-    capabilities = init->capabilities;
-    num_capabilities =
-        1 + ((hdr->length - sizeof(VSCMsgInit)) / sizeof(uint32_t));
-    init->version = ntohl(init->version);
-    for (i = 0 ; i < num_capabilities; ++i) {
-        capabilities[i] = ntohl(capabilities[i]);
-    }
-    if (init->magic != VSCARD_MAGIC) {
-        error_report("wrong magic");
-        /* we can't disconnect the chardev */
-    }
-    if (init->version != VSCARD_VERSION) {
-        DPRINTF(card, D_WARN,
-            "got version %d, have %d", init->version, VSCARD_VERSION);
-    }
-    /* future handling of capabilities, none exist atm */
-    ccid_card_vscard_send_init(card);
-}
-
-static void ccid_card_vscard_handle_message(PassthruState *card,
-    VSCMsgHeader *scr_msg_header)
-{
-    uint8_t *data = (uint8_t *)&scr_msg_header[1];
-
-    switch (scr_msg_header->type) {
-    case VSC_ATR:
-        DPRINTF(card, D_INFO, "VSC_ATR %d\n", scr_msg_header->length);
-        if (scr_msg_header->length > MAX_ATR_SIZE) {
-            error_report("ATR size exceeds spec, ignoring");
-            ccid_card_vscard_send_error(card, scr_msg_header->reader_id,
-                                        VSC_GENERAL_ERROR);
-            break;
-        }
-        memcpy(card->atr, data, scr_msg_header->length);
-        card->atr_length = scr_msg_header->length;
-        ccid_card_card_inserted(&card->base);
-        ccid_card_vscard_send_error(card, scr_msg_header->reader_id,
-                                    VSC_SUCCESS);
-        break;
-    case VSC_APDU:
-        ccid_card_send_apdu_to_guest(
-            &card->base, data, scr_msg_header->length);
-        break;
-    case VSC_CardRemove:
-        DPRINTF(card, D_INFO, "VSC_CardRemove\n");
-        ccid_card_card_removed(&card->base);
-        ccid_card_vscard_send_error(card,
-            scr_msg_header->reader_id, VSC_SUCCESS);
-        break;
-    case VSC_Init:
-        ccid_card_vscard_handle_init(
-            card, scr_msg_header, (VSCMsgInit *)data);
-        break;
-    case VSC_Error:
-        ccid_card_card_error(&card->base, *(uint32_t *)data);
-        break;
-    case VSC_ReaderAdd:
-        if (ccid_card_ccid_attach(&card->base) < 0) {
-            ccid_card_vscard_send_error(card, VSCARD_UNDEFINED_READER_ID,
-                                      VSC_CANNOT_ADD_MORE_READERS);
-        } else {
-            ccid_card_vscard_send_error(card, VSCARD_MINIMAL_READER_ID,
-                                        VSC_SUCCESS);
-        }
-        break;
-    case VSC_ReaderRemove:
-        ccid_card_ccid_detach(&card->base);
-        ccid_card_vscard_send_error(card,
-            scr_msg_header->reader_id, VSC_SUCCESS);
-        break;
-    default:
-        printf("usb-ccid: chardev: unexpected message of type %X\n",
-               scr_msg_header->type);
-        ccid_card_vscard_send_error(card, scr_msg_header->reader_id,
-            VSC_GENERAL_ERROR);
-    }
-}
-
-static void ccid_card_vscard_drop_connection(PassthruState *card)
-{
-    qemu_chr_delete(card->cs);
-    card->vscard_in_pos = card->vscard_in_hdr = 0;
-}
-
-static void ccid_card_vscard_read(void *opaque, const uint8_t *buf, int size)
-{
-    PassthruState *card = opaque;
-    VSCMsgHeader *hdr;
-
-    if (card->vscard_in_pos + size > VSCARD_IN_SIZE) {
-        error_report(
-            "no room for data: pos %d +  size %d > %d. dropping connection.",
-            card->vscard_in_pos, size, VSCARD_IN_SIZE);
-        ccid_card_vscard_drop_connection(card);
-        return;
-    }
-    assert(card->vscard_in_pos < VSCARD_IN_SIZE);
-    assert(card->vscard_in_hdr < VSCARD_IN_SIZE);
-    memcpy(card->vscard_in_data + card->vscard_in_pos, buf, size);
-    card->vscard_in_pos += size;
-    hdr = (VSCMsgHeader *)(card->vscard_in_data + card->vscard_in_hdr);
-
-    while ((card->vscard_in_pos - card->vscard_in_hdr >= sizeof(VSCMsgHeader))
-         &&(card->vscard_in_pos - card->vscard_in_hdr >=
-                                  sizeof(VSCMsgHeader) + ntohl(hdr->length))) {
-        hdr->reader_id = ntohl(hdr->reader_id);
-        hdr->length = ntohl(hdr->length);
-        hdr->type = ntohl(hdr->type);
-        ccid_card_vscard_handle_message(card, hdr);
-        card->vscard_in_hdr += hdr->length + sizeof(VSCMsgHeader);
-        hdr = (VSCMsgHeader *)(card->vscard_in_data + card->vscard_in_hdr);
-    }
-    if (card->vscard_in_hdr == card->vscard_in_pos) {
-        card->vscard_in_pos = card->vscard_in_hdr = 0;
-    }
-}
-
-static void ccid_card_vscard_event(void *opaque, int event)
-{
-    PassthruState *card = opaque;
-
-    switch (event) {
-    case CHR_EVENT_BREAK:
-        card->vscard_in_pos = card->vscard_in_hdr = 0;
-        break;
-    case CHR_EVENT_FOCUS:
-        break;
-    case CHR_EVENT_OPENED:
-        DPRINTF(card, D_INFO, "%s: CHR_EVENT_OPENED\n", __func__);
-        break;
-    }
-}
-
-/* End VSCard handling */
-
-static void passthru_apdu_from_guest(
-    CCIDCardState *base, const uint8_t *apdu, uint32_t len)
-{
-    PassthruState *card = DO_UPCAST(PassthruState, base, base);
-
-    if (!card->cs) {
-        printf("ccid-passthru: no chardev, discarding apdu length %d\n", len);
-        return;
-    }
-    ccid_card_vscard_send_apdu(card, apdu, len);
-}
-
-static const uint8_t *passthru_get_atr(CCIDCardState *base, uint32_t *len)
-{
-    PassthruState *card = DO_UPCAST(PassthruState, base, base);
-
-    *len = card->atr_length;
-    return card->atr;
-}
-
-static int passthru_initfn(CCIDCardState *base)
-{
-    PassthruState *card = DO_UPCAST(PassthruState, base, base);
-
-    card->vscard_in_pos = 0;
-    card->vscard_in_hdr = 0;
-    if (card->cs) {
-        DPRINTF(card, D_INFO, "initing chardev\n");
-        qemu_chr_add_handlers(card->cs,
-            ccid_card_vscard_can_read,
-            ccid_card_vscard_read,
-            ccid_card_vscard_event, card);
-        ccid_card_vscard_send_init(card);
-    } else {
-        error_report("missing chardev");
-        return -1;
-    }
-    assert(sizeof(DEFAULT_ATR) <= MAX_ATR_SIZE);
-    memcpy(card->atr, DEFAULT_ATR, sizeof(DEFAULT_ATR));
-    card->atr_length = sizeof(DEFAULT_ATR);
-    return 0;
-}
-
-static int passthru_exitfn(CCIDCardState *base)
-{
-    return 0;
-}
-
-static VMStateDescription passthru_vmstate = {
-    .name = PASSTHRU_DEV_NAME,
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_BUFFER(vscard_in_data, PassthruState),
-        VMSTATE_UINT32(vscard_in_pos, PassthruState),
-        VMSTATE_UINT32(vscard_in_hdr, PassthruState),
-        VMSTATE_BUFFER(atr, PassthruState),
-        VMSTATE_UINT8(atr_length, PassthruState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static Property passthru_card_properties[] = {
-    DEFINE_PROP_CHR("chardev", PassthruState, cs),
-    DEFINE_PROP_UINT8("debug", PassthruState, debug, 0),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void passthru_class_initfn(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    CCIDCardClass *cc = CCID_CARD_CLASS(klass);
-
-    cc->initfn = passthru_initfn;
-    cc->exitfn = passthru_exitfn;
-    cc->get_atr = passthru_get_atr;
-    cc->apdu_from_guest = passthru_apdu_from_guest;
-    dc->desc = "passthrough smartcard";
-    dc->vmsd = &passthru_vmstate;
-    dc->props = passthru_card_properties;
-}
-
-static const 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_types(void)
-{
-    type_register_static(&passthru_card_info);
-}
-
-type_init(ccid_card_passthru_register_types)
diff --git a/hw/ccid.h b/hw/ccid.h
deleted file mode 100644 (file)
index 9334da8..0000000
--- a/hw/ccid.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * CCID Passthru Card Device emulation
- *
- * Copyright (c) 2011 Red Hat.
- * Written by Alon Levy.
- *
- * This code is licensed under the GNU LGPL, version 2 or later.
- */
-
-#ifndef CCID_H
-#define CCID_H
-
-#include "hw/qdev.h"
-
-typedef struct CCIDCardState CCIDCardState;
-typedef struct CCIDCardInfo CCIDCardInfo;
-
-#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)
- */
-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. */
-};
-
-/*
- * API for smartcard calling the CCID device (used by hw/ccid-card-*.c)
- */
-void ccid_card_send_apdu_to_guest(CCIDCardState *card,
-                                  uint8_t *apdu,
-                                  uint32_t len);
-void ccid_card_card_removed(CCIDCardState *card);
-void ccid_card_card_inserted(CCIDCardState *card);
-void ccid_card_card_error(CCIDCardState *card, uint64_t error);
-
-/*
- * support guest visible insertion/removal of ccid devices based on actual
- * devices connected/removed. Called by card implementation (passthru, local)
- */
-int ccid_card_ccid_attach(CCIDCardState *card);
-void ccid_card_ccid_detach(CCIDCardState *card);
-
-#endif /* CCID_H */
diff --git a/hw/cdrom.c b/hw/cdrom.c
deleted file mode 100644 (file)
index a018eec..0000000
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * QEMU ATAPI CD-ROM Emulator
- *
- * Copyright (c) 2006 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.
- */
-
-/* ??? Most of the ATAPI emulation is still in ide.c.  It should be moved
-   here.  */
-
-#include "qemu-common.h"
-#include "hw/scsi.h"
-
-static void lba_to_msf(uint8_t *buf, int lba)
-{
-    lba += 150;
-    buf[0] = (lba / 75) / 60;
-    buf[1] = (lba / 75) % 60;
-    buf[2] = lba % 75;
-}
-
-/* same toc as bochs. Return -1 if error or the toc length */
-/* XXX: check this */
-int cdrom_read_toc(int nb_sectors, uint8_t *buf, int msf, int start_track)
-{
-    uint8_t *q;
-    int len;
-
-    if (start_track > 1 && start_track != 0xaa)
-        return -1;
-    q = buf + 2;
-    *q++ = 1; /* first session */
-    *q++ = 1; /* last session */
-    if (start_track <= 1) {
-        *q++ = 0; /* reserved */
-        *q++ = 0x14; /* ADR, control */
-        *q++ = 1;    /* track number */
-        *q++ = 0; /* reserved */
-        if (msf) {
-            *q++ = 0; /* reserved */
-            lba_to_msf(q, 0);
-            q += 3;
-        } else {
-            /* sector 0 */
-            cpu_to_be32wu((uint32_t *)q, 0);
-            q += 4;
-        }
-    }
-    /* lead out track */
-    *q++ = 0; /* reserved */
-    *q++ = 0x16; /* ADR, control */
-    *q++ = 0xaa; /* track number */
-    *q++ = 0; /* reserved */
-    if (msf) {
-        *q++ = 0; /* reserved */
-        lba_to_msf(q, nb_sectors);
-        q += 3;
-    } else {
-        cpu_to_be32wu((uint32_t *)q, nb_sectors);
-        q += 4;
-    }
-    len = q - buf;
-    cpu_to_be16wu((uint16_t *)buf, len - 2);
-    return len;
-}
-
-/* mostly same info as PearPc */
-int cdrom_read_toc_raw(int nb_sectors, uint8_t *buf, int msf, int session_num)
-{
-    uint8_t *q;
-    int len;
-
-    q = buf + 2;
-    *q++ = 1; /* first session */
-    *q++ = 1; /* last session */
-
-    *q++ = 1; /* session number */
-    *q++ = 0x14; /* data track */
-    *q++ = 0; /* track number */
-    *q++ = 0xa0; /* lead-in */
-    *q++ = 0; /* min */
-    *q++ = 0; /* sec */
-    *q++ = 0; /* frame */
-    *q++ = 0;
-    *q++ = 1; /* first track */
-    *q++ = 0x00; /* disk type */
-    *q++ = 0x00;
-
-    *q++ = 1; /* session number */
-    *q++ = 0x14; /* data track */
-    *q++ = 0; /* track number */
-    *q++ = 0xa1;
-    *q++ = 0; /* min */
-    *q++ = 0; /* sec */
-    *q++ = 0; /* frame */
-    *q++ = 0;
-    *q++ = 1; /* last track */
-    *q++ = 0x00;
-    *q++ = 0x00;
-
-    *q++ = 1; /* session number */
-    *q++ = 0x14; /* data track */
-    *q++ = 0; /* track number */
-    *q++ = 0xa2; /* lead-out */
-    *q++ = 0; /* min */
-    *q++ = 0; /* sec */
-    *q++ = 0; /* frame */
-    if (msf) {
-        *q++ = 0; /* reserved */
-        lba_to_msf(q, nb_sectors);
-        q += 3;
-    } else {
-        cpu_to_be32wu((uint32_t *)q, nb_sectors);
-        q += 4;
-    }
-
-    *q++ = 1; /* session number */
-    *q++ = 0x14; /* ADR, control */
-    *q++ = 0;    /* track number */
-    *q++ = 1;    /* point */
-    *q++ = 0; /* min */
-    *q++ = 0; /* sec */
-    *q++ = 0; /* frame */
-    if (msf) {
-        *q++ = 0;
-        lba_to_msf(q, 0);
-        q += 3;
-    } else {
-        *q++ = 0;
-        *q++ = 0;
-        *q++ = 0;
-        *q++ = 0;
-    }
-
-    len = q - buf;
-    cpu_to_be16wu((uint16_t *)buf, len - 2);
-    return len;
-}
diff --git a/hw/char/Makefile.objs b/hw/char/Makefile.objs
new file mode 100644 (file)
index 0000000..f8f3dbc
--- /dev/null
@@ -0,0 +1,27 @@
+common-obj-$(CONFIG_IPACK) += tpci200.o ipoctal232.o ipack.o
+common-obj-$(CONFIG_ESCC) += escc.o
+common-obj-$(CONFIG_PARALLEL) += parallel.o
+common-obj-$(CONFIG_PL011) += pl011.o
+common-obj-$(CONFIG_SERIAL) += serial.o serial-isa.o
+common-obj-$(CONFIG_SERIAL_PCI) += serial-pci.o
+common-obj-$(CONFIG_VIRTIO) += virtio-console.o
+common-obj-$(CONFIG_XILINX) += xilinx_uartlite.o
+common-obj-$(CONFIG_XEN_BACKEND) += xen_console.o
+common-obj-$(CONFIG_CADENCE) += cadence_uart.o
+
+obj-$(CONFIG_EXYNOS4) += exynos4210_uart.o
+obj-$(CONFIG_COLDFIRE) += mcf_uart.o
+obj-$(CONFIG_OMAP) += omap_uart.o
+obj-$(CONFIG_SH4) += sh_serial.o
+obj-$(CONFIG_PSERIES) += spapr_vty.o
+
+common-obj-$(CONFIG_ETRAXFS) += etraxfs_ser.o
+common-obj-$(CONFIG_ISA_DEBUG) += debugcon.o
+common-obj-$(CONFIG_GRLIB) += grlib_apbuart.o
+common-obj-$(CONFIG_IMX) += imx_serial.o
+common-obj-$(CONFIG_LM32) += lm32_juart.o
+common-obj-$(CONFIG_LM32) += lm32_uart.o
+common-obj-$(CONFIG_MILKYMIST) += milkymist-uart.o
+common-obj-$(CONFIG_SCLPCONSOLE) += sclpconsole.o
+
+obj-$(CONFIG_VIRTIO) += virtio-serial-bus.o
diff --git a/hw/char/cadence_uart.c b/hw/char/cadence_uart.c
new file mode 100644 (file)
index 0000000..421ec99
--- /dev/null
@@ -0,0 +1,518 @@
+/*
+ * Device model for Cadence UART
+ *
+ * Copyright (c) 2010 Xilinx Inc.
+ * Copyright (c) 2012 Peter A.G. Crosthwaite (peter.crosthwaite@petalogix.com)
+ * Copyright (c) 2012 PetaLogix Pty Ltd.
+ * Written by Haibing Ma
+ *            M.Habib
+ *
+ * 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.
+ *
+ * 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 "hw/sysbus.h"
+#include "char/char.h"
+#include "qemu/timer.h"
+
+#ifdef CADENCE_UART_ERR_DEBUG
+#define DB_PRINT(...) do { \
+    fprintf(stderr,  ": %s: ", __func__); \
+    fprintf(stderr, ## __VA_ARGS__); \
+    } while (0);
+#else
+    #define DB_PRINT(...)
+#endif
+
+#define UART_SR_INTR_RTRIG     0x00000001
+#define UART_SR_INTR_REMPTY    0x00000002
+#define UART_SR_INTR_RFUL      0x00000004
+#define UART_SR_INTR_TEMPTY    0x00000008
+#define UART_SR_INTR_TFUL      0x00000010
+/* bits fields in CSR that correlate to CISR. If any of these bits are set in
+ * SR, then the same bit in CISR is set high too */
+#define UART_SR_TO_CISR_MASK   0x0000001F
+
+#define UART_INTR_ROVR         0x00000020
+#define UART_INTR_FRAME        0x00000040
+#define UART_INTR_PARE         0x00000080
+#define UART_INTR_TIMEOUT      0x00000100
+#define UART_INTR_DMSI         0x00000200
+
+#define UART_SR_RACTIVE    0x00000400
+#define UART_SR_TACTIVE    0x00000800
+#define UART_SR_FDELT      0x00001000
+
+#define UART_CR_RXRST       0x00000001
+#define UART_CR_TXRST       0x00000002
+#define UART_CR_RX_EN       0x00000004
+#define UART_CR_RX_DIS      0x00000008
+#define UART_CR_TX_EN       0x00000010
+#define UART_CR_TX_DIS      0x00000020
+#define UART_CR_RST_TO      0x00000040
+#define UART_CR_STARTBRK    0x00000080
+#define UART_CR_STOPBRK     0x00000100
+
+#define UART_MR_CLKS            0x00000001
+#define UART_MR_CHRL            0x00000006
+#define UART_MR_CHRL_SH         1
+#define UART_MR_PAR             0x00000038
+#define UART_MR_PAR_SH          3
+#define UART_MR_NBSTOP          0x000000C0
+#define UART_MR_NBSTOP_SH       6
+#define UART_MR_CHMODE          0x00000300
+#define UART_MR_CHMODE_SH       8
+#define UART_MR_UCLKEN          0x00000400
+#define UART_MR_IRMODE          0x00000800
+
+#define UART_DATA_BITS_6       (0x3 << UART_MR_CHRL_SH)
+#define UART_DATA_BITS_7       (0x2 << UART_MR_CHRL_SH)
+#define UART_PARITY_ODD        (0x1 << UART_MR_PAR_SH)
+#define UART_PARITY_EVEN       (0x0 << UART_MR_PAR_SH)
+#define UART_STOP_BITS_1       (0x3 << UART_MR_NBSTOP_SH)
+#define UART_STOP_BITS_2       (0x2 << UART_MR_NBSTOP_SH)
+#define NORMAL_MODE            (0x0 << UART_MR_CHMODE_SH)
+#define ECHO_MODE              (0x1 << UART_MR_CHMODE_SH)
+#define LOCAL_LOOPBACK         (0x2 << UART_MR_CHMODE_SH)
+#define REMOTE_LOOPBACK        (0x3 << UART_MR_CHMODE_SH)
+
+#define RX_FIFO_SIZE           16
+#define TX_FIFO_SIZE           16
+#define UART_INPUT_CLK         50000000
+
+#define R_CR       (0x00/4)
+#define R_MR       (0x04/4)
+#define R_IER      (0x08/4)
+#define R_IDR      (0x0C/4)
+#define R_IMR      (0x10/4)
+#define R_CISR     (0x14/4)
+#define R_BRGR     (0x18/4)
+#define R_RTOR     (0x1C/4)
+#define R_RTRIG    (0x20/4)
+#define R_MCR      (0x24/4)
+#define R_MSR      (0x28/4)
+#define R_SR       (0x2C/4)
+#define R_TX_RX    (0x30/4)
+#define R_BDIV     (0x34/4)
+#define R_FDEL     (0x38/4)
+#define R_PMIN     (0x3C/4)
+#define R_PWID     (0x40/4)
+#define R_TTRIG    (0x44/4)
+
+#define R_MAX (R_TTRIG + 1)
+
+typedef struct {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    uint32_t r[R_MAX];
+    uint8_t r_fifo[RX_FIFO_SIZE];
+    uint32_t rx_wpos;
+    uint32_t rx_count;
+    uint64_t char_tx_time;
+    CharDriverState *chr;
+    qemu_irq irq;
+    struct QEMUTimer *fifo_trigger_handle;
+    struct QEMUTimer *tx_time_handle;
+} UartState;
+
+static void uart_update_status(UartState *s)
+{
+    s->r[R_CISR] |= s->r[R_SR] & UART_SR_TO_CISR_MASK;
+    qemu_set_irq(s->irq, !!(s->r[R_IMR] & s->r[R_CISR]));
+}
+
+static void fifo_trigger_update(void *opaque)
+{
+    UartState *s = (UartState *)opaque;
+
+    s->r[R_CISR] |= UART_INTR_TIMEOUT;
+
+    uart_update_status(s);
+}
+
+static void uart_tx_redo(UartState *s)
+{
+    uint64_t new_tx_time = qemu_get_clock_ns(vm_clock);
+
+    qemu_mod_timer(s->tx_time_handle, new_tx_time + s->char_tx_time);
+
+    s->r[R_SR] |= UART_SR_INTR_TEMPTY;
+
+    uart_update_status(s);
+}
+
+static void uart_tx_write(void *opaque)
+{
+    UartState *s = (UartState *)opaque;
+
+    uart_tx_redo(s);
+}
+
+static void uart_rx_reset(UartState *s)
+{
+    s->rx_wpos = 0;
+    s->rx_count = 0;
+    qemu_chr_accept_input(s->chr);
+
+    s->r[R_SR] |= UART_SR_INTR_REMPTY;
+    s->r[R_SR] &= ~UART_SR_INTR_RFUL;
+}
+
+static void uart_tx_reset(UartState *s)
+{
+    s->r[R_SR] |= UART_SR_INTR_TEMPTY;
+    s->r[R_SR] &= ~UART_SR_INTR_TFUL;
+}
+
+static void uart_send_breaks(UartState *s)
+{
+    int break_enabled = 1;
+
+    qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_BREAK,
+                               &break_enabled);
+}
+
+static void uart_parameters_setup(UartState *s)
+{
+    QEMUSerialSetParams ssp;
+    unsigned int baud_rate, packet_size;
+
+    baud_rate = (s->r[R_MR] & UART_MR_CLKS) ?
+            UART_INPUT_CLK / 8 : UART_INPUT_CLK;
+
+    ssp.speed = baud_rate / (s->r[R_BRGR] * (s->r[R_BDIV] + 1));
+    packet_size = 1;
+
+    switch (s->r[R_MR] & UART_MR_PAR) {
+    case UART_PARITY_EVEN:
+        ssp.parity = 'E';
+        packet_size++;
+        break;
+    case UART_PARITY_ODD:
+        ssp.parity = 'O';
+        packet_size++;
+        break;
+    default:
+        ssp.parity = 'N';
+        break;
+    }
+
+    switch (s->r[R_MR] & UART_MR_CHRL) {
+    case UART_DATA_BITS_6:
+        ssp.data_bits = 6;
+        break;
+    case UART_DATA_BITS_7:
+        ssp.data_bits = 7;
+        break;
+    default:
+        ssp.data_bits = 8;
+        break;
+    }
+
+    switch (s->r[R_MR] & UART_MR_NBSTOP) {
+    case UART_STOP_BITS_1:
+        ssp.stop_bits = 1;
+        break;
+    default:
+        ssp.stop_bits = 2;
+        break;
+    }
+
+    packet_size += ssp.data_bits + ssp.stop_bits;
+    s->char_tx_time = (get_ticks_per_sec() / ssp.speed) * packet_size;
+    qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
+}
+
+static int uart_can_receive(void *opaque)
+{
+    UartState *s = (UartState *)opaque;
+
+    return RX_FIFO_SIZE - s->rx_count;
+}
+
+static void uart_ctrl_update(UartState *s)
+{
+    if (s->r[R_CR] & UART_CR_TXRST) {
+        uart_tx_reset(s);
+    }
+
+    if (s->r[R_CR] & UART_CR_RXRST) {
+        uart_rx_reset(s);
+    }
+
+    s->r[R_CR] &= ~(UART_CR_TXRST | UART_CR_RXRST);
+
+    if ((s->r[R_CR] & UART_CR_TX_EN) && !(s->r[R_CR] & UART_CR_TX_DIS)) {
+            uart_tx_redo(s);
+    }
+
+    if (s->r[R_CR] & UART_CR_STARTBRK && !(s->r[R_CR] & UART_CR_STOPBRK)) {
+        uart_send_breaks(s);
+    }
+}
+
+static void uart_write_rx_fifo(void *opaque, const uint8_t *buf, int size)
+{
+    UartState *s = (UartState *)opaque;
+    uint64_t new_rx_time = qemu_get_clock_ns(vm_clock);
+    int i;
+
+    if ((s->r[R_CR] & UART_CR_RX_DIS) || !(s->r[R_CR] & UART_CR_RX_EN)) {
+        return;
+    }
+
+    s->r[R_SR] &= ~UART_SR_INTR_REMPTY;
+
+    if (s->rx_count == RX_FIFO_SIZE) {
+        s->r[R_CISR] |= UART_INTR_ROVR;
+    } else {
+        for (i = 0; i < size; i++) {
+            s->r_fifo[s->rx_wpos] = buf[i];
+            s->rx_wpos = (s->rx_wpos + 1) % RX_FIFO_SIZE;
+            s->rx_count++;
+
+            if (s->rx_count == RX_FIFO_SIZE) {
+                s->r[R_SR] |= UART_SR_INTR_RFUL;
+                break;
+            }
+
+            if (s->rx_count >= s->r[R_RTRIG]) {
+                s->r[R_SR] |= UART_SR_INTR_RTRIG;
+            }
+        }
+        qemu_mod_timer(s->fifo_trigger_handle, new_rx_time +
+                                                (s->char_tx_time * 4));
+    }
+    uart_update_status(s);
+}
+
+static void uart_write_tx_fifo(UartState *s, const uint8_t *buf, int size)
+{
+    if ((s->r[R_CR] & UART_CR_TX_DIS) || !(s->r[R_CR] & UART_CR_TX_EN)) {
+        return;
+    }
+
+    while (size) {
+        size -= qemu_chr_fe_write(s->chr, buf, size);
+    }
+}
+
+static void uart_receive(void *opaque, const uint8_t *buf, int size)
+{
+    UartState *s = (UartState *)opaque;
+    uint32_t ch_mode = s->r[R_MR] & UART_MR_CHMODE;
+
+    if (ch_mode == NORMAL_MODE || ch_mode == ECHO_MODE) {
+        uart_write_rx_fifo(opaque, buf, size);
+    }
+    if (ch_mode == REMOTE_LOOPBACK || ch_mode == ECHO_MODE) {
+        uart_write_tx_fifo(s, buf, size);
+    }
+}
+
+static void uart_event(void *opaque, int event)
+{
+    UartState *s = (UartState *)opaque;
+    uint8_t buf = '\0';
+
+    if (event == CHR_EVENT_BREAK) {
+        uart_write_rx_fifo(opaque, &buf, 1);
+    }
+
+    uart_update_status(s);
+}
+
+static void uart_read_rx_fifo(UartState *s, uint32_t *c)
+{
+    if ((s->r[R_CR] & UART_CR_RX_DIS) || !(s->r[R_CR] & UART_CR_RX_EN)) {
+        return;
+    }
+
+    s->r[R_SR] &= ~UART_SR_INTR_RFUL;
+
+    if (s->rx_count) {
+        uint32_t rx_rpos =
+                (RX_FIFO_SIZE + s->rx_wpos - s->rx_count) % RX_FIFO_SIZE;
+        *c = s->r_fifo[rx_rpos];
+        s->rx_count--;
+
+        if (!s->rx_count) {
+            s->r[R_SR] |= UART_SR_INTR_REMPTY;
+        }
+        qemu_chr_accept_input(s->chr);
+    } else {
+        *c = 0;
+        s->r[R_SR] |= UART_SR_INTR_REMPTY;
+    }
+
+    if (s->rx_count < s->r[R_RTRIG]) {
+        s->r[R_SR] &= ~UART_SR_INTR_RTRIG;
+    }
+    uart_update_status(s);
+}
+
+static void uart_write(void *opaque, hwaddr offset,
+                          uint64_t value, unsigned size)
+{
+    UartState *s = (UartState *)opaque;
+
+    DB_PRINT(" offset:%x data:%08x\n", (unsigned)offset, (unsigned)value);
+    offset >>= 2;
+    switch (offset) {
+    case R_IER: /* ier (wts imr) */
+        s->r[R_IMR] |= value;
+        break;
+    case R_IDR: /* idr (wtc imr) */
+        s->r[R_IMR] &= ~value;
+        break;
+    case R_IMR: /* imr (read only) */
+        break;
+    case R_CISR: /* cisr (wtc) */
+        s->r[R_CISR] &= ~value;
+        break;
+    case R_TX_RX: /* UARTDR */
+        switch (s->r[R_MR] & UART_MR_CHMODE) {
+        case NORMAL_MODE:
+            uart_write_tx_fifo(s, (uint8_t *) &value, 1);
+            break;
+        case LOCAL_LOOPBACK:
+            uart_write_rx_fifo(opaque, (uint8_t *) &value, 1);
+            break;
+        }
+        break;
+    default:
+        s->r[offset] = value;
+    }
+
+    switch (offset) {
+    case R_CR:
+        uart_ctrl_update(s);
+        break;
+    case R_MR:
+        uart_parameters_setup(s);
+        break;
+    }
+}
+
+static uint64_t uart_read(void *opaque, hwaddr offset,
+        unsigned size)
+{
+    UartState *s = (UartState *)opaque;
+    uint32_t c = 0;
+
+    offset >>= 2;
+    if (offset >= R_MAX) {
+        c = 0;
+    } else if (offset == R_TX_RX) {
+        uart_read_rx_fifo(s, &c);
+    } else {
+       c = s->r[offset];
+    }
+
+    DB_PRINT(" offset:%x data:%08x\n", (unsigned)(offset << 2), (unsigned)c);
+    return c;
+}
+
+static const MemoryRegionOps uart_ops = {
+    .read = uart_read,
+    .write = uart_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void cadence_uart_reset(UartState *s)
+{
+    s->r[R_CR] = 0x00000128;
+    s->r[R_IMR] = 0;
+    s->r[R_CISR] = 0;
+    s->r[R_RTRIG] = 0x00000020;
+    s->r[R_BRGR] = 0x0000000F;
+    s->r[R_TTRIG] = 0x00000020;
+
+    uart_rx_reset(s);
+    uart_tx_reset(s);
+
+    s->rx_count = 0;
+    s->rx_wpos = 0;
+}
+
+static int cadence_uart_init(SysBusDevice *dev)
+{
+    UartState *s = FROM_SYSBUS(UartState, dev);
+
+    memory_region_init_io(&s->iomem, &uart_ops, s, "uart", 0x1000);
+    sysbus_init_mmio(dev, &s->iomem);
+    sysbus_init_irq(dev, &s->irq);
+
+    s->fifo_trigger_handle = qemu_new_timer_ns(vm_clock,
+            (QEMUTimerCB *)fifo_trigger_update, s);
+
+    s->tx_time_handle = qemu_new_timer_ns(vm_clock,
+            (QEMUTimerCB *)uart_tx_write, s);
+
+    s->char_tx_time = (get_ticks_per_sec() / 9600) * 10;
+
+    s->chr = qemu_char_get_next_serial();
+
+    cadence_uart_reset(s);
+
+    if (s->chr) {
+        qemu_chr_add_handlers(s->chr, uart_can_receive, uart_receive,
+                              uart_event, s);
+    }
+
+    return 0;
+}
+
+static int cadence_uart_post_load(void *opaque, int version_id)
+{
+    UartState *s = opaque;
+
+    uart_parameters_setup(s);
+    uart_update_status(s);
+    return 0;
+}
+
+static const VMStateDescription vmstate_cadence_uart = {
+    .name = "cadence_uart",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .post_load = cadence_uart_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(r, UartState, R_MAX),
+        VMSTATE_UINT8_ARRAY(r_fifo, UartState, RX_FIFO_SIZE),
+        VMSTATE_UINT32(rx_count, UartState),
+        VMSTATE_UINT32(rx_wpos, UartState),
+        VMSTATE_TIMER(fifo_trigger_handle, UartState),
+        VMSTATE_TIMER(tx_time_handle, UartState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void cadence_uart_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sdc->init = cadence_uart_init;
+    dc->vmsd = &vmstate_cadence_uart;
+}
+
+static const TypeInfo cadence_uart_info = {
+    .name          = "cadence_uart",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(UartState),
+    .class_init    = cadence_uart_class_init,
+};
+
+static void cadence_uart_register_types(void)
+{
+    type_register_static(&cadence_uart_info);
+}
+
+type_init(cadence_uart_register_types)
diff --git a/hw/char/debugcon.c b/hw/char/debugcon.c
new file mode 100644 (file)
index 0000000..0588eeb
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * QEMU Bochs-style debug console ("port E9") emulation
+ *
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ * Copyright (c) 2008 Citrix Systems, Inc.
+ * Copyright (c) Intel Corporation; author: H. Peter Anvin
+ *
+ * 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 "hw/hw.h"
+#include "char/char.h"
+#include "hw/isa/isa.h"
+#include "hw/i386/pc.h"
+
+#define TYPE_ISA_DEBUGCON_DEVICE "isa-debugcon"
+#define ISA_DEBUGCON_DEVICE(obj) \
+     OBJECT_CHECK(ISADebugconState, (obj), TYPE_ISA_DEBUGCON_DEVICE)
+
+//#define DEBUG_DEBUGCON
+
+typedef struct DebugconState {
+    MemoryRegion io;
+    CharDriverState *chr;
+    uint32_t readback;
+} DebugconState;
+
+typedef struct ISADebugconState {
+    ISADevice parent_obj;
+
+    uint32_t iobase;
+    DebugconState state;
+} ISADebugconState;
+
+static void debugcon_ioport_write(void *opaque, hwaddr addr, uint64_t val,
+                                  unsigned width)
+{
+    DebugconState *s = opaque;
+    unsigned char ch = val;
+
+#ifdef DEBUG_DEBUGCON
+    printf("debugcon: write addr=0x%04x val=0x%02x\n", addr, val);
+#endif
+
+    qemu_chr_fe_write(s->chr, &ch, 1);
+}
+
+
+static uint64_t debugcon_ioport_read(void *opaque, hwaddr addr, unsigned width)
+{
+    DebugconState *s = opaque;
+
+#ifdef DEBUG_DEBUGCON
+    printf("debugcon: read addr=0x%04x\n", addr);
+#endif
+
+    return s->readback;
+}
+
+static const MemoryRegionOps debugcon_ops = {
+    .read = debugcon_ioport_read,
+    .write = debugcon_ioport_write,
+    .valid.min_access_size = 1,
+    .valid.max_access_size = 1,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void debugcon_init_core(DebugconState *s)
+{
+    if (!s->chr) {
+        fprintf(stderr, "Can't create debugcon device, empty char device\n");
+        exit(1);
+    }
+
+    qemu_chr_add_handlers(s->chr, NULL, NULL, NULL, s);
+}
+
+static int debugcon_isa_initfn(ISADevice *dev)
+{
+    ISADebugconState *isa = ISA_DEBUGCON_DEVICE(dev);
+    DebugconState *s = &isa->state;
+
+    debugcon_init_core(s);
+    memory_region_init_io(&s->io, &debugcon_ops, s,
+                          TYPE_ISA_DEBUGCON_DEVICE, 1);
+    memory_region_add_subregion(isa_address_space_io(dev),
+                                isa->iobase, &s->io);
+    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 const TypeInfo debugcon_isa_info = {
+    .name          = TYPE_ISA_DEBUGCON_DEVICE,
+    .parent        = TYPE_ISA_DEVICE,
+    .instance_size = sizeof(ISADebugconState),
+    .class_init    = debugcon_isa_class_initfn,
+};
+
+static void debugcon_register_types(void)
+{
+    type_register_static(&debugcon_isa_info);
+}
+
+type_init(debugcon_register_types)
diff --git a/hw/char/escc.c b/hw/char/escc.c
new file mode 100644 (file)
index 0000000..067b055
--- /dev/null
@@ -0,0 +1,938 @@
+/*
+ * QEMU ESCC (Z8030/Z8530/Z85C30/SCC/ESCC) serial port emulation
+ *
+ * Copyright (c) 2003-2005 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.
+ */
+
+#include "hw/hw.h"
+#include "hw/sysbus.h"
+#include "hw/char/escc.h"
+#include "char/char.h"
+#include "ui/console.h"
+#include "trace.h"
+
+/*
+ * Chipset docs:
+ * "Z80C30/Z85C30/Z80230/Z85230/Z85233 SCC/ESCC User Manual",
+ * http://www.zilog.com/docs/serial/scc_escc_um.pdf
+ *
+ * On Sparc32 this is the serial port, mouse and keyboard part of chip STP2001
+ * (Slave I/O), also produced as NCR89C105. See
+ * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
+ *
+ * The serial ports implement full AMD AM8530 or Zilog Z8530 chips,
+ * mouse and keyboard ports don't implement all functions and they are
+ * only asynchronous. There is no DMA.
+ *
+ * Z85C30 is also used on PowerMacs. There are some small differences
+ * between Sparc version (sunzilog) and PowerMac (pmac):
+ *  Offset between control and data registers
+ *  There is some kind of lockup bug, but we can ignore it
+ *  CTS is inverted
+ *  DMA on pmac using DBDMA chip
+ *  pmac can do IRDA and faster rates, sunzilog can only do 38400
+ *  pmac baud rate generator clock is 3.6864 MHz, sunzilog 4.9152 MHz
+ */
+
+/*
+ * Modifications:
+ *  2006-Aug-10  Igor Kovalenko :   Renamed KBDQueue to SERIOQueue, implemented
+ *                                  serial mouse queue.
+ *                                  Implemented serial mouse protocol.
+ *
+ *  2010-May-23  Artyom Tarasenko:  Reworked IUS logic
+ */
+
+typedef enum {
+    chn_a, chn_b,
+} ChnID;
+
+#define CHN_C(s) ((s)->chn == chn_b? 'b' : 'a')
+
+typedef enum {
+    ser, kbd, mouse,
+} ChnType;
+
+#define SERIO_QUEUE_SIZE 256
+
+typedef struct {
+    uint8_t data[SERIO_QUEUE_SIZE];
+    int rptr, wptr, count;
+} SERIOQueue;
+
+#define SERIAL_REGS 16
+typedef struct ChannelState {
+    qemu_irq irq;
+    uint32_t rxint, txint, rxint_under_svc, txint_under_svc;
+    struct ChannelState *otherchn;
+    uint32_t reg;
+    uint8_t wregs[SERIAL_REGS], rregs[SERIAL_REGS];
+    SERIOQueue queue;
+    CharDriverState *chr;
+    int e0_mode, led_mode, caps_lock_mode, num_lock_mode;
+    int disabled;
+    int clock;
+    uint32_t vmstate_dummy;
+    ChnID chn; // this channel, A (base+4) or B (base+0)
+    ChnType type;
+    uint8_t rx, tx;
+} ChannelState;
+
+struct SerialState {
+    SysBusDevice busdev;
+    struct ChannelState chn[2];
+    uint32_t it_shift;
+    MemoryRegion mmio;
+    uint32_t disabled;
+    uint32_t frequency;
+};
+
+#define SERIAL_CTRL 0
+#define SERIAL_DATA 1
+
+#define W_CMD     0
+#define CMD_PTR_MASK   0x07
+#define CMD_CMD_MASK   0x38
+#define CMD_HI         0x08
+#define CMD_CLR_TXINT  0x28
+#define CMD_CLR_IUS    0x38
+#define W_INTR    1
+#define INTR_INTALL    0x01
+#define INTR_TXINT     0x02
+#define INTR_RXMODEMSK 0x18
+#define INTR_RXINT1ST  0x08
+#define INTR_RXINTALL  0x10
+#define W_IVEC    2
+#define W_RXCTRL  3
+#define RXCTRL_RXEN    0x01
+#define W_TXCTRL1 4
+#define TXCTRL1_PAREN  0x01
+#define TXCTRL1_PAREV  0x02
+#define TXCTRL1_1STOP  0x04
+#define TXCTRL1_1HSTOP 0x08
+#define TXCTRL1_2STOP  0x0c
+#define TXCTRL1_STPMSK 0x0c
+#define TXCTRL1_CLK1X  0x00
+#define TXCTRL1_CLK16X 0x40
+#define TXCTRL1_CLK32X 0x80
+#define TXCTRL1_CLK64X 0xc0
+#define TXCTRL1_CLKMSK 0xc0
+#define W_TXCTRL2 5
+#define TXCTRL2_TXEN   0x08
+#define TXCTRL2_BITMSK 0x60
+#define TXCTRL2_5BITS  0x00
+#define TXCTRL2_7BITS  0x20
+#define TXCTRL2_6BITS  0x40
+#define TXCTRL2_8BITS  0x60
+#define W_SYNC1   6
+#define W_SYNC2   7
+#define W_TXBUF   8
+#define W_MINTR   9
+#define MINTR_STATUSHI 0x10
+#define MINTR_RST_MASK 0xc0
+#define MINTR_RST_B    0x40
+#define MINTR_RST_A    0x80
+#define MINTR_RST_ALL  0xc0
+#define W_MISC1  10
+#define W_CLOCK  11
+#define CLOCK_TRXC     0x08
+#define W_BRGLO  12
+#define W_BRGHI  13
+#define W_MISC2  14
+#define MISC2_PLLDIS   0x30
+#define W_EXTINT 15
+#define EXTINT_DCD     0x08
+#define EXTINT_SYNCINT 0x10
+#define EXTINT_CTSINT  0x20
+#define EXTINT_TXUNDRN 0x40
+#define EXTINT_BRKINT  0x80
+
+#define R_STATUS  0
+#define STATUS_RXAV    0x01
+#define STATUS_ZERO    0x02
+#define STATUS_TXEMPTY 0x04
+#define STATUS_DCD     0x08
+#define STATUS_SYNC    0x10
+#define STATUS_CTS     0x20
+#define STATUS_TXUNDRN 0x40
+#define STATUS_BRK     0x80
+#define R_SPEC    1
+#define SPEC_ALLSENT   0x01
+#define SPEC_BITS8     0x06
+#define R_IVEC    2
+#define IVEC_TXINTB    0x00
+#define IVEC_LONOINT   0x06
+#define IVEC_LORXINTA  0x0c
+#define IVEC_LORXINTB  0x04
+#define IVEC_LOTXINTA  0x08
+#define IVEC_HINOINT   0x60
+#define IVEC_HIRXINTA  0x30
+#define IVEC_HIRXINTB  0x20
+#define IVEC_HITXINTA  0x10
+#define R_INTR    3
+#define INTR_EXTINTB   0x01
+#define INTR_TXINTB    0x02
+#define INTR_RXINTB    0x04
+#define INTR_EXTINTA   0x08
+#define INTR_TXINTA    0x10
+#define INTR_RXINTA    0x20
+#define R_IPEN    4
+#define R_TXCTRL1 5
+#define R_TXCTRL2 6
+#define R_BC      7
+#define R_RXBUF   8
+#define R_RXCTRL  9
+#define R_MISC   10
+#define R_MISC1  11
+#define R_BRGLO  12
+#define R_BRGHI  13
+#define R_MISC1I 14
+#define R_EXTINT 15
+
+static void handle_kbd_command(ChannelState *s, int val);
+static int serial_can_receive(void *opaque);
+static void serial_receive_byte(ChannelState *s, int ch);
+
+static void clear_queue(void *opaque)
+{
+    ChannelState *s = opaque;
+    SERIOQueue *q = &s->queue;
+    q->rptr = q->wptr = q->count = 0;
+}
+
+static void put_queue(void *opaque, int b)
+{
+    ChannelState *s = opaque;
+    SERIOQueue *q = &s->queue;
+
+    trace_escc_put_queue(CHN_C(s), b);
+    if (q->count >= SERIO_QUEUE_SIZE)
+        return;
+    q->data[q->wptr] = b;
+    if (++q->wptr == SERIO_QUEUE_SIZE)
+        q->wptr = 0;
+    q->count++;
+    serial_receive_byte(s, 0);
+}
+
+static uint32_t get_queue(void *opaque)
+{
+    ChannelState *s = opaque;
+    SERIOQueue *q = &s->queue;
+    int val;
+
+    if (q->count == 0) {
+        return 0;
+    } else {
+        val = q->data[q->rptr];
+        if (++q->rptr == SERIO_QUEUE_SIZE)
+            q->rptr = 0;
+        q->count--;
+    }
+    trace_escc_get_queue(CHN_C(s), val);
+    if (q->count > 0)
+        serial_receive_byte(s, 0);
+    return val;
+}
+
+static int escc_update_irq_chn(ChannelState *s)
+{
+    if ((((s->wregs[W_INTR] & INTR_TXINT) && (s->txint == 1)) ||
+         // tx ints enabled, pending
+         ((((s->wregs[W_INTR] & INTR_RXMODEMSK) == INTR_RXINT1ST) ||
+           ((s->wregs[W_INTR] & INTR_RXMODEMSK) == INTR_RXINTALL)) &&
+          s->rxint == 1) || // rx ints enabled, pending
+         ((s->wregs[W_EXTINT] & EXTINT_BRKINT) &&
+          (s->rregs[R_STATUS] & STATUS_BRK)))) { // break int e&p
+        return 1;
+    }
+    return 0;
+}
+
+static void escc_update_irq(ChannelState *s)
+{
+    int irq;
+
+    irq = escc_update_irq_chn(s);
+    irq |= escc_update_irq_chn(s->otherchn);
+
+    trace_escc_update_irq(irq);
+    qemu_set_irq(s->irq, irq);
+}
+
+static void escc_reset_chn(ChannelState *s)
+{
+    int i;
+
+    s->reg = 0;
+    for (i = 0; i < SERIAL_REGS; i++) {
+        s->rregs[i] = 0;
+        s->wregs[i] = 0;
+    }
+    s->wregs[W_TXCTRL1] = TXCTRL1_1STOP; // 1X divisor, 1 stop bit, no parity
+    s->wregs[W_MINTR] = MINTR_RST_ALL;
+    s->wregs[W_CLOCK] = CLOCK_TRXC; // Synch mode tx clock = TRxC
+    s->wregs[W_MISC2] = MISC2_PLLDIS; // PLL disabled
+    s->wregs[W_EXTINT] = EXTINT_DCD | EXTINT_SYNCINT | EXTINT_CTSINT |
+        EXTINT_TXUNDRN | EXTINT_BRKINT; // Enable most interrupts
+    if (s->disabled)
+        s->rregs[R_STATUS] = STATUS_TXEMPTY | STATUS_DCD | STATUS_SYNC |
+            STATUS_CTS | STATUS_TXUNDRN;
+    else
+        s->rregs[R_STATUS] = STATUS_TXEMPTY | STATUS_TXUNDRN;
+    s->rregs[R_SPEC] = SPEC_BITS8 | SPEC_ALLSENT;
+
+    s->rx = s->tx = 0;
+    s->rxint = s->txint = 0;
+    s->rxint_under_svc = s->txint_under_svc = 0;
+    s->e0_mode = s->led_mode = s->caps_lock_mode = s->num_lock_mode = 0;
+    clear_queue(s);
+}
+
+static void escc_reset(DeviceState *d)
+{
+    SerialState *s = container_of(d, SerialState, busdev.qdev);
+
+    escc_reset_chn(&s->chn[0]);
+    escc_reset_chn(&s->chn[1]);
+}
+
+static inline void set_rxint(ChannelState *s)
+{
+    s->rxint = 1;
+    /* XXX: missing daisy chainnig: chn_b rx should have a lower priority
+       than chn_a rx/tx/special_condition service*/
+    s->rxint_under_svc = 1;
+    if (s->chn == chn_a) {
+        s->rregs[R_INTR] |= INTR_RXINTA;
+        if (s->wregs[W_MINTR] & MINTR_STATUSHI)
+            s->otherchn->rregs[R_IVEC] = IVEC_HIRXINTA;
+        else
+            s->otherchn->rregs[R_IVEC] = IVEC_LORXINTA;
+    } else {
+        s->otherchn->rregs[R_INTR] |= INTR_RXINTB;
+        if (s->wregs[W_MINTR] & MINTR_STATUSHI)
+            s->rregs[R_IVEC] = IVEC_HIRXINTB;
+        else
+            s->rregs[R_IVEC] = IVEC_LORXINTB;
+    }
+    escc_update_irq(s);
+}
+
+static inline void set_txint(ChannelState *s)
+{
+    s->txint = 1;
+    if (!s->rxint_under_svc) {
+        s->txint_under_svc = 1;
+        if (s->chn == chn_a) {
+            if (s->wregs[W_INTR] & INTR_TXINT) {
+                s->rregs[R_INTR] |= INTR_TXINTA;
+            }
+            if (s->wregs[W_MINTR] & MINTR_STATUSHI)
+                s->otherchn->rregs[R_IVEC] = IVEC_HITXINTA;
+            else
+                s->otherchn->rregs[R_IVEC] = IVEC_LOTXINTA;
+        } else {
+            s->rregs[R_IVEC] = IVEC_TXINTB;
+            if (s->wregs[W_INTR] & INTR_TXINT) {
+                s->otherchn->rregs[R_INTR] |= INTR_TXINTB;
+            }
+        }
+    escc_update_irq(s);
+    }
+}
+
+static inline void clr_rxint(ChannelState *s)
+{
+    s->rxint = 0;
+    s->rxint_under_svc = 0;
+    if (s->chn == chn_a) {
+        if (s->wregs[W_MINTR] & MINTR_STATUSHI)
+            s->otherchn->rregs[R_IVEC] = IVEC_HINOINT;
+        else
+            s->otherchn->rregs[R_IVEC] = IVEC_LONOINT;
+        s->rregs[R_INTR] &= ~INTR_RXINTA;
+    } else {
+        if (s->wregs[W_MINTR] & MINTR_STATUSHI)
+            s->rregs[R_IVEC] = IVEC_HINOINT;
+        else
+            s->rregs[R_IVEC] = IVEC_LONOINT;
+        s->otherchn->rregs[R_INTR] &= ~INTR_RXINTB;
+    }
+    if (s->txint)
+        set_txint(s);
+    escc_update_irq(s);
+}
+
+static inline void clr_txint(ChannelState *s)
+{
+    s->txint = 0;
+    s->txint_under_svc = 0;
+    if (s->chn == chn_a) {
+        if (s->wregs[W_MINTR] & MINTR_STATUSHI)
+            s->otherchn->rregs[R_IVEC] = IVEC_HINOINT;
+        else
+            s->otherchn->rregs[R_IVEC] = IVEC_LONOINT;
+        s->rregs[R_INTR] &= ~INTR_TXINTA;
+    } else {
+        s->otherchn->rregs[R_INTR] &= ~INTR_TXINTB;
+        if (s->wregs[W_MINTR] & MINTR_STATUSHI)
+            s->rregs[R_IVEC] = IVEC_HINOINT;
+        else
+            s->rregs[R_IVEC] = IVEC_LONOINT;
+        s->otherchn->rregs[R_INTR] &= ~INTR_TXINTB;
+    }
+    if (s->rxint)
+        set_rxint(s);
+    escc_update_irq(s);
+}
+
+static void escc_update_parameters(ChannelState *s)
+{
+    int speed, parity, data_bits, stop_bits;
+    QEMUSerialSetParams ssp;
+
+    if (!s->chr || s->type != ser)
+        return;
+
+    if (s->wregs[W_TXCTRL1] & TXCTRL1_PAREN) {
+        if (s->wregs[W_TXCTRL1] & TXCTRL1_PAREV)
+            parity = 'E';
+        else
+            parity = 'O';
+    } else {
+        parity = 'N';
+    }
+    if ((s->wregs[W_TXCTRL1] & TXCTRL1_STPMSK) == TXCTRL1_2STOP)
+        stop_bits = 2;
+    else
+        stop_bits = 1;
+    switch (s->wregs[W_TXCTRL2] & TXCTRL2_BITMSK) {
+    case TXCTRL2_5BITS:
+        data_bits = 5;
+        break;
+    case TXCTRL2_7BITS:
+        data_bits = 7;
+        break;
+    case TXCTRL2_6BITS:
+        data_bits = 6;
+        break;
+    default:
+    case TXCTRL2_8BITS:
+        data_bits = 8;
+        break;
+    }
+    speed = s->clock / ((s->wregs[W_BRGLO] | (s->wregs[W_BRGHI] << 8)) + 2);
+    switch (s->wregs[W_TXCTRL1] & TXCTRL1_CLKMSK) {
+    case TXCTRL1_CLK1X:
+        break;
+    case TXCTRL1_CLK16X:
+        speed /= 16;
+        break;
+    case TXCTRL1_CLK32X:
+        speed /= 32;
+        break;
+    default:
+    case TXCTRL1_CLK64X:
+        speed /= 64;
+        break;
+    }
+    ssp.speed = speed;
+    ssp.parity = parity;
+    ssp.data_bits = data_bits;
+    ssp.stop_bits = stop_bits;
+    trace_escc_update_parameters(CHN_C(s), speed, parity, data_bits, stop_bits);
+    qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
+}
+
+static void escc_mem_write(void *opaque, hwaddr addr,
+                           uint64_t val, unsigned size)
+{
+    SerialState *serial = opaque;
+    ChannelState *s;
+    uint32_t saddr;
+    int newreg, channel;
+
+    val &= 0xff;
+    saddr = (addr >> serial->it_shift) & 1;
+    channel = (addr >> (serial->it_shift + 1)) & 1;
+    s = &serial->chn[channel];
+    switch (saddr) {
+    case SERIAL_CTRL:
+        trace_escc_mem_writeb_ctrl(CHN_C(s), s->reg, val & 0xff);
+        newreg = 0;
+        switch (s->reg) {
+        case W_CMD:
+            newreg = val & CMD_PTR_MASK;
+            val &= CMD_CMD_MASK;
+            switch (val) {
+            case CMD_HI:
+                newreg |= CMD_HI;
+                break;
+            case CMD_CLR_TXINT:
+                clr_txint(s);
+                break;
+            case CMD_CLR_IUS:
+                if (s->rxint_under_svc) {
+                    s->rxint_under_svc = 0;
+                    if (s->txint) {
+                        set_txint(s);
+                    }
+                } else if (s->txint_under_svc) {
+                    s->txint_under_svc = 0;
+                }
+                escc_update_irq(s);
+                break;
+            default:
+                break;
+            }
+            break;
+        case W_INTR ... W_RXCTRL:
+        case W_SYNC1 ... W_TXBUF:
+        case W_MISC1 ... W_CLOCK:
+        case W_MISC2 ... W_EXTINT:
+            s->wregs[s->reg] = val;
+            break;
+        case W_TXCTRL1:
+        case W_TXCTRL2:
+            s->wregs[s->reg] = val;
+            escc_update_parameters(s);
+            break;
+        case W_BRGLO:
+        case W_BRGHI:
+            s->wregs[s->reg] = val;
+            s->rregs[s->reg] = val;
+            escc_update_parameters(s);
+            break;
+        case W_MINTR:
+            switch (val & MINTR_RST_MASK) {
+            case 0:
+            default:
+                break;
+            case MINTR_RST_B:
+                escc_reset_chn(&serial->chn[0]);
+                return;
+            case MINTR_RST_A:
+                escc_reset_chn(&serial->chn[1]);
+                return;
+            case MINTR_RST_ALL:
+                escc_reset(&serial->busdev.qdev);
+                return;
+            }
+            break;
+        default:
+            break;
+        }
+        if (s->reg == 0)
+            s->reg = newreg;
+        else
+            s->reg = 0;
+        break;
+    case SERIAL_DATA:
+        trace_escc_mem_writeb_data(CHN_C(s), val);
+        s->tx = val;
+        if (s->wregs[W_TXCTRL2] & TXCTRL2_TXEN) { // tx enabled
+            if (s->chr)
+                qemu_chr_fe_write(s->chr, &s->tx, 1);
+            else if (s->type == kbd && !s->disabled) {
+                handle_kbd_command(s, val);
+            }
+        }
+        s->rregs[R_STATUS] |= STATUS_TXEMPTY; // Tx buffer empty
+        s->rregs[R_SPEC] |= SPEC_ALLSENT; // All sent
+        set_txint(s);
+        break;
+    default:
+        break;
+    }
+}
+
+static uint64_t escc_mem_read(void *opaque, hwaddr addr,
+                              unsigned size)
+{
+    SerialState *serial = opaque;
+    ChannelState *s;
+    uint32_t saddr;
+    uint32_t ret;
+    int channel;
+
+    saddr = (addr >> serial->it_shift) & 1;
+    channel = (addr >> (serial->it_shift + 1)) & 1;
+    s = &serial->chn[channel];
+    switch (saddr) {
+    case SERIAL_CTRL:
+        trace_escc_mem_readb_ctrl(CHN_C(s), s->reg, s->rregs[s->reg]);
+        ret = s->rregs[s->reg];
+        s->reg = 0;
+        return ret;
+    case SERIAL_DATA:
+        s->rregs[R_STATUS] &= ~STATUS_RXAV;
+        clr_rxint(s);
+        if (s->type == kbd || s->type == mouse)
+            ret = get_queue(s);
+        else
+            ret = s->rx;
+        trace_escc_mem_readb_data(CHN_C(s), ret);
+        if (s->chr)
+            qemu_chr_accept_input(s->chr);
+        return ret;
+    default:
+        break;
+    }
+    return 0;
+}
+
+static const MemoryRegionOps escc_mem_ops = {
+    .read = escc_mem_read,
+    .write = escc_mem_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+};
+
+static int serial_can_receive(void *opaque)
+{
+    ChannelState *s = opaque;
+    int ret;
+
+    if (((s->wregs[W_RXCTRL] & RXCTRL_RXEN) == 0) // Rx not enabled
+        || ((s->rregs[R_STATUS] & STATUS_RXAV) == STATUS_RXAV))
+        // char already available
+        ret = 0;
+    else
+        ret = 1;
+    return ret;
+}
+
+static void serial_receive_byte(ChannelState *s, int ch)
+{
+    trace_escc_serial_receive_byte(CHN_C(s), ch);
+    s->rregs[R_STATUS] |= STATUS_RXAV;
+    s->rx = ch;
+    set_rxint(s);
+}
+
+static void serial_receive_break(ChannelState *s)
+{
+    s->rregs[R_STATUS] |= STATUS_BRK;
+    escc_update_irq(s);
+}
+
+static void serial_receive1(void *opaque, const uint8_t *buf, int size)
+{
+    ChannelState *s = opaque;
+    serial_receive_byte(s, buf[0]);
+}
+
+static void serial_event(void *opaque, int event)
+{
+    ChannelState *s = opaque;
+    if (event == CHR_EVENT_BREAK)
+        serial_receive_break(s);
+}
+
+static const VMStateDescription vmstate_escc_chn = {
+    .name ="escc_chn",
+    .version_id = 2,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT32(vmstate_dummy, ChannelState),
+        VMSTATE_UINT32(reg, ChannelState),
+        VMSTATE_UINT32(rxint, ChannelState),
+        VMSTATE_UINT32(txint, ChannelState),
+        VMSTATE_UINT32(rxint_under_svc, ChannelState),
+        VMSTATE_UINT32(txint_under_svc, ChannelState),
+        VMSTATE_UINT8(rx, ChannelState),
+        VMSTATE_UINT8(tx, ChannelState),
+        VMSTATE_BUFFER(wregs, ChannelState),
+        VMSTATE_BUFFER(rregs, ChannelState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_escc = {
+    .name ="escc",
+    .version_id = 2,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_STRUCT_ARRAY(chn, SerialState, 2, 2, vmstate_escc_chn,
+                             ChannelState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+MemoryRegion *escc_init(hwaddr base, qemu_irq irqA, qemu_irq irqB,
+              CharDriverState *chrA, CharDriverState *chrB,
+              int clock, int it_shift)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+    SerialState *d;
+
+    dev = qdev_create(NULL, "escc");
+    qdev_prop_set_uint32(dev, "disabled", 0);
+    qdev_prop_set_uint32(dev, "frequency", clock);
+    qdev_prop_set_uint32(dev, "it_shift", it_shift);
+    qdev_prop_set_chr(dev, "chrB", chrB);
+    qdev_prop_set_chr(dev, "chrA", chrA);
+    qdev_prop_set_uint32(dev, "chnBtype", ser);
+    qdev_prop_set_uint32(dev, "chnAtype", ser);
+    qdev_init_nofail(dev);
+    s = SYS_BUS_DEVICE(dev);
+    sysbus_connect_irq(s, 0, irqB);
+    sysbus_connect_irq(s, 1, irqA);
+    if (base) {
+        sysbus_mmio_map(s, 0, base);
+    }
+
+    d = FROM_SYSBUS(SerialState, s);
+    return &d->mmio;
+}
+
+static const uint8_t keycodes[128] = {
+    127, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 43, 53,
+    54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 89, 76, 77, 78,
+    79, 80, 81, 82, 83, 84, 85, 86, 87, 42, 99, 88, 100, 101, 102, 103,
+    104, 105, 106, 107, 108, 109, 110, 47, 19, 121, 119, 5, 6, 8, 10, 12,
+    14, 16, 17, 18, 7, 98, 23, 68, 69, 70, 71, 91, 92, 93, 125, 112,
+    113, 114, 94, 50, 0, 0, 124, 9, 11, 0, 0, 0, 0, 0, 0, 0,
+    90, 0, 46, 22, 13, 111, 52, 20, 96, 24, 28, 74, 27, 123, 44, 66,
+    0, 45, 2, 4, 48, 0, 0, 21, 0, 0, 0, 0, 0, 120, 122, 67,
+};
+
+static const uint8_t e0_keycodes[128] = {
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 90, 76, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 109, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 68, 69, 70, 0, 91, 0, 93, 0, 112,
+    113, 114, 94, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    1, 3, 25, 26, 49, 52, 72, 73, 97, 99, 111, 118, 120, 122, 67, 0,
+};
+
+static void sunkbd_event(void *opaque, int ch)
+{
+    ChannelState *s = opaque;
+    int release = ch & 0x80;
+
+    trace_escc_sunkbd_event_in(ch);
+    switch (ch) {
+    case 58: // Caps lock press
+        s->caps_lock_mode ^= 1;
+        if (s->caps_lock_mode == 2)
+            return; // Drop second press
+        break;
+    case 69: // Num lock press
+        s->num_lock_mode ^= 1;
+        if (s->num_lock_mode == 2)
+            return; // Drop second press
+        break;
+    case 186: // Caps lock release
+        s->caps_lock_mode ^= 2;
+        if (s->caps_lock_mode == 3)
+            return; // Drop first release
+        break;
+    case 197: // Num lock release
+        s->num_lock_mode ^= 2;
+        if (s->num_lock_mode == 3)
+            return; // Drop first release
+        break;
+    case 0xe0:
+        s->e0_mode = 1;
+        return;
+    default:
+        break;
+    }
+    if (s->e0_mode) {
+        s->e0_mode = 0;
+        ch = e0_keycodes[ch & 0x7f];
+    } else {
+        ch = keycodes[ch & 0x7f];
+    }
+    trace_escc_sunkbd_event_out(ch);
+    put_queue(s, ch | release);
+}
+
+static void handle_kbd_command(ChannelState *s, int val)
+{
+    trace_escc_kbd_command(val);
+    if (s->led_mode) { // Ignore led byte
+        s->led_mode = 0;
+        return;
+    }
+    switch (val) {
+    case 1: // Reset, return type code
+        clear_queue(s);
+        put_queue(s, 0xff);
+        put_queue(s, 4); // Type 4
+        put_queue(s, 0x7f);
+        break;
+    case 0xe: // Set leds
+        s->led_mode = 1;
+        break;
+    case 7: // Query layout
+    case 0xf:
+        clear_queue(s);
+        put_queue(s, 0xfe);
+        put_queue(s, 0); // XXX, layout?
+        break;
+    default:
+        break;
+    }
+}
+
+static void sunmouse_event(void *opaque,
+                               int dx, int dy, int dz, int buttons_state)
+{
+    ChannelState *s = opaque;
+    int ch;
+
+    trace_escc_sunmouse_event(dx, dy, buttons_state);
+    ch = 0x80 | 0x7; /* protocol start byte, no buttons pressed */
+
+    if (buttons_state & MOUSE_EVENT_LBUTTON)
+        ch ^= 0x4;
+    if (buttons_state & MOUSE_EVENT_MBUTTON)
+        ch ^= 0x2;
+    if (buttons_state & MOUSE_EVENT_RBUTTON)
+        ch ^= 0x1;
+
+    put_queue(s, ch);
+
+    ch = dx;
+
+    if (ch > 127)
+        ch = 127;
+    else if (ch < -127)
+        ch = -127;
+
+    put_queue(s, ch & 0xff);
+
+    ch = -dy;
+
+    if (ch > 127)
+        ch = 127;
+    else if (ch < -127)
+        ch = -127;
+
+    put_queue(s, ch & 0xff);
+
+    // MSC protocol specify two extra motion bytes
+
+    put_queue(s, 0);
+    put_queue(s, 0);
+}
+
+void slavio_serial_ms_kbd_init(hwaddr base, qemu_irq irq,
+                               int disabled, int clock, int it_shift)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+
+    dev = qdev_create(NULL, "escc");
+    qdev_prop_set_uint32(dev, "disabled", disabled);
+    qdev_prop_set_uint32(dev, "frequency", clock);
+    qdev_prop_set_uint32(dev, "it_shift", it_shift);
+    qdev_prop_set_chr(dev, "chrB", NULL);
+    qdev_prop_set_chr(dev, "chrA", NULL);
+    qdev_prop_set_uint32(dev, "chnBtype", mouse);
+    qdev_prop_set_uint32(dev, "chnAtype", kbd);
+    qdev_init_nofail(dev);
+    s = SYS_BUS_DEVICE(dev);
+    sysbus_connect_irq(s, 0, irq);
+    sysbus_connect_irq(s, 1, irq);
+    sysbus_mmio_map(s, 0, base);
+}
+
+static int escc_init1(SysBusDevice *dev)
+{
+    SerialState *s = FROM_SYSBUS(SerialState, dev);
+    unsigned int i;
+
+    s->chn[0].disabled = s->disabled;
+    s->chn[1].disabled = s->disabled;
+    for (i = 0; i < 2; i++) {
+        sysbus_init_irq(dev, &s->chn[i].irq);
+        s->chn[i].chn = 1 - i;
+        s->chn[i].clock = s->frequency / 2;
+        if (s->chn[i].chr) {
+            qemu_chr_add_handlers(s->chn[i].chr, serial_can_receive,
+                                  serial_receive1, serial_event, &s->chn[i]);
+        }
+    }
+    s->chn[0].otherchn = &s->chn[1];
+    s->chn[1].otherchn = &s->chn[0];
+
+    memory_region_init_io(&s->mmio, &escc_mem_ops, s, "escc",
+                          ESCC_SIZE << s->it_shift);
+    sysbus_init_mmio(dev, &s->mmio);
+
+    if (s->chn[0].type == mouse) {
+        qemu_add_mouse_event_handler(sunmouse_event, &s->chn[0], 0,
+                                     "QEMU Sun Mouse");
+    }
+    if (s->chn[1].type == kbd) {
+        qemu_add_kbd_event_handler(sunkbd_event, &s->chn[1]);
+    }
+
+    return 0;
+}
+
+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("chnBtype",  SerialState, chn[0].type, 0),
+    DEFINE_PROP_UINT32("chnAtype",  SerialState, chn[1].type, 0),
+    DEFINE_PROP_CHR("chrB", SerialState, chn[0].chr),
+    DEFINE_PROP_CHR("chrA", SerialState, chn[1].chr),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void escc_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = escc_init1;
+    dc->reset = escc_reset;
+    dc->vmsd = &vmstate_escc;
+    dc->props = escc_properties;
+}
+
+static const TypeInfo escc_info = {
+    .name          = "escc",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(SerialState),
+    .class_init    = escc_class_init,
+};
+
+static void escc_register_types(void)
+{
+    type_register_static(&escc_info);
+}
+
+type_init(escc_register_types)
diff --git a/hw/char/etraxfs_ser.c b/hw/char/etraxfs_ser.c
new file mode 100644 (file)
index 0000000..b7499d7
--- /dev/null
@@ -0,0 +1,246 @@
+/*
+ * QEMU ETRAX System Emulator
+ *
+ * Copyright (c) 2007 Edgar E. Iglesias, Axis Communications AB.
+ *
+ * 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 "hw/sysbus.h"
+#include "char/char.h"
+#include "qemu/log.h"
+
+#define D(x)
+
+#define RW_TR_CTRL     (0x00 / 4)
+#define RW_TR_DMA_EN   (0x04 / 4)
+#define RW_REC_CTRL    (0x08 / 4)
+#define RW_DOUT        (0x1c / 4)
+#define RS_STAT_DIN    (0x20 / 4)
+#define R_STAT_DIN     (0x24 / 4)
+#define RW_INTR_MASK   (0x2c / 4)
+#define RW_ACK_INTR    (0x30 / 4)
+#define R_INTR         (0x34 / 4)
+#define R_MASKED_INTR  (0x38 / 4)
+#define R_MAX          (0x3c / 4)
+
+#define STAT_DAV     16
+#define STAT_TR_IDLE 22
+#define STAT_TR_RDY  24
+
+struct etrax_serial
+{
+    SysBusDevice busdev;
+    MemoryRegion mmio;
+    CharDriverState *chr;
+    qemu_irq irq;
+
+    int pending_tx;
+
+    uint8_t rx_fifo[16];
+    unsigned int rx_fifo_pos;
+    unsigned int rx_fifo_len;
+
+    /* Control registers.  */
+    uint32_t regs[R_MAX];
+};
+
+static void ser_update_irq(struct etrax_serial *s)
+{
+
+    if (s->rx_fifo_len) {
+        s->regs[R_INTR] |= 8;
+    } else {
+        s->regs[R_INTR] &= ~8;
+    }
+
+    s->regs[R_MASKED_INTR] = s->regs[R_INTR] & s->regs[RW_INTR_MASK];
+    qemu_set_irq(s->irq, !!s->regs[R_MASKED_INTR]);
+}
+
+static uint64_t
+ser_read(void *opaque, hwaddr addr, unsigned int size)
+{
+    struct etrax_serial *s = opaque;
+    uint32_t r = 0;
+
+    addr >>= 2;
+    switch (addr)
+    {
+        case R_STAT_DIN:
+            r = s->rx_fifo[(s->rx_fifo_pos - s->rx_fifo_len) & 15];
+            if (s->rx_fifo_len) {
+                r |= 1 << STAT_DAV;
+            }
+            r |= 1 << STAT_TR_RDY;
+            r |= 1 << STAT_TR_IDLE;
+            break;
+        case RS_STAT_DIN:
+            r = s->rx_fifo[(s->rx_fifo_pos - s->rx_fifo_len) & 15];
+            if (s->rx_fifo_len) {
+                r |= 1 << STAT_DAV;
+                s->rx_fifo_len--;
+            }
+            r |= 1 << STAT_TR_RDY;
+            r |= 1 << STAT_TR_IDLE;
+            break;
+        default:
+            r = s->regs[addr];
+            D(qemu_log("%s " TARGET_FMT_plx "=%x\n", __func__, addr, r));
+            break;
+    }
+    return r;
+}
+
+static void
+ser_write(void *opaque, hwaddr addr,
+          uint64_t val64, unsigned int size)
+{
+    struct etrax_serial *s = opaque;
+    uint32_t value = val64;
+    unsigned char ch = val64;
+
+    D(qemu_log("%s " TARGET_FMT_plx "=%x\n",  __func__, addr, value));
+    addr >>= 2;
+    switch (addr)
+    {
+        case RW_DOUT:
+            qemu_chr_fe_write(s->chr, &ch, 1);
+            s->regs[R_INTR] |= 3;
+            s->pending_tx = 1;
+            s->regs[addr] = value;
+            break;
+        case RW_ACK_INTR:
+            if (s->pending_tx) {
+                value &= ~1;
+                s->pending_tx = 0;
+                D(qemu_log("fixedup value=%x r_intr=%x\n",
+                           value, s->regs[R_INTR]));
+            }
+            s->regs[addr] = value;
+            s->regs[R_INTR] &= ~value;
+            D(printf("r_intr=%x\n", s->regs[R_INTR]));
+            break;
+        default:
+            s->regs[addr] = value;
+            break;
+    }
+    ser_update_irq(s);
+}
+
+static const MemoryRegionOps ser_ops = {
+    .read = ser_read,
+    .write = ser_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4
+    }
+};
+
+static void serial_receive(void *opaque, const uint8_t *buf, int size)
+{
+    struct etrax_serial *s = opaque;
+    int i;
+
+    /* Got a byte.  */
+    if (s->rx_fifo_len >= 16) {
+        qemu_log("WARNING: UART dropped char.\n");
+        return;
+    }
+
+    for (i = 0; i < size; i++) { 
+        s->rx_fifo[s->rx_fifo_pos] = buf[i];
+        s->rx_fifo_pos++;
+        s->rx_fifo_pos &= 15;
+        s->rx_fifo_len++;
+    }
+
+    ser_update_irq(s);
+}
+
+static int serial_can_receive(void *opaque)
+{
+    struct etrax_serial *s = opaque;
+    int r;
+
+    /* Is the receiver enabled?  */
+    if (!(s->regs[RW_REC_CTRL] & (1 << 3))) {
+        return 0;
+    }
+
+    r = sizeof(s->rx_fifo) - s->rx_fifo_len;
+    return r;
+}
+
+static void serial_event(void *opaque, int event)
+{
+
+}
+
+static void etraxfs_ser_reset(DeviceState *d)
+{
+    struct etrax_serial *s = container_of(d, typeof(*s), busdev.qdev);
+
+    /* transmitter begins ready and idle.  */
+    s->regs[RS_STAT_DIN] |= (1 << STAT_TR_RDY);
+    s->regs[RS_STAT_DIN] |= (1 << STAT_TR_IDLE);
+
+    s->regs[RW_REC_CTRL] = 0x10000;
+
+}
+
+static int etraxfs_ser_init(SysBusDevice *dev)
+{
+    struct etrax_serial *s = FROM_SYSBUS(typeof (*s), dev);
+
+    sysbus_init_irq(dev, &s->irq);
+    memory_region_init_io(&s->mmio, &ser_ops, s, "etraxfs-serial", R_MAX * 4);
+    sysbus_init_mmio(dev, &s->mmio);
+
+    s->chr = qemu_char_get_next_serial();
+    if (s->chr)
+        qemu_chr_add_handlers(s->chr,
+                      serial_can_receive, serial_receive,
+                      serial_event, s);
+    return 0;
+}
+
+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 const 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_types(void)
+{
+    type_register_static(&etraxfs_ser_info);
+}
+
+type_init(etraxfs_serial_register_types)
diff --git a/hw/char/exynos4210_uart.c b/hw/char/exynos4210_uart.c
new file mode 100644 (file)
index 0000000..8b4e72c
--- /dev/null
@@ -0,0 +1,676 @@
+/*
+ *  Exynos4210 UART Emulation
+ *
+ *  Copyright (C) 2011 Samsung Electronics Co Ltd.
+ *    Maksim Kozlov, <m.kozlov@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 "hw/sysbus.h"
+#include "sysemu/sysemu.h"
+#include "char/char.h"
+
+#include "hw/arm/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 */
+    hwaddr  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(hwaddr  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, hwaddr 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, hwaddr 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(hwaddr 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 = SYS_BUS_DEVICE(dev);
+    qdev_init_nofail(dev);
+    if (addr != (hwaddr)-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 const 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)
diff --git a/hw/char/grlib_apbuart.c b/hw/char/grlib_apbuart.c
new file mode 100644 (file)
index 0000000..62f7990
--- /dev/null
@@ -0,0 +1,293 @@
+/*
+ * QEMU GRLIB APB UART Emulator
+ *
+ * Copyright (c) 2010-2011 AdaCore
+ *
+ * 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 "hw/sysbus.h"
+#include "char/char.h"
+
+#include "trace.h"
+
+#define UART_REG_SIZE 20     /* Size of memory mapped registers */
+
+/* UART status register fields */
+#define UART_DATA_READY           (1 <<  0)
+#define UART_TRANSMIT_SHIFT_EMPTY (1 <<  1)
+#define UART_TRANSMIT_FIFO_EMPTY  (1 <<  2)
+#define UART_BREAK_RECEIVED       (1 <<  3)
+#define UART_OVERRUN              (1 <<  4)
+#define UART_PARITY_ERROR         (1 <<  5)
+#define UART_FRAMING_ERROR        (1 <<  6)
+#define UART_TRANSMIT_FIFO_HALF   (1 <<  7)
+#define UART_RECEIVE_FIFO_HALF    (1 <<  8)
+#define UART_TRANSMIT_FIFO_FULL   (1 <<  9)
+#define UART_RECEIVE_FIFO_FULL    (1 << 10)
+
+/* UART control register fields */
+#define UART_RECEIVE_ENABLE          (1 <<  0)
+#define UART_TRANSMIT_ENABLE         (1 <<  1)
+#define UART_RECEIVE_INTERRUPT       (1 <<  2)
+#define UART_TRANSMIT_INTERRUPT      (1 <<  3)
+#define UART_PARITY_SELECT           (1 <<  4)
+#define UART_PARITY_ENABLE           (1 <<  5)
+#define UART_FLOW_CONTROL            (1 <<  6)
+#define UART_LOOPBACK                (1 <<  7)
+#define UART_EXTERNAL_CLOCK          (1 <<  8)
+#define UART_RECEIVE_FIFO_INTERRUPT  (1 <<  9)
+#define UART_TRANSMIT_FIFO_INTERRUPT (1 << 10)
+#define UART_FIFO_DEBUG_MODE         (1 << 11)
+#define UART_OUTPUT_ENABLE           (1 << 12)
+#define UART_FIFO_AVAILABLE          (1 << 31)
+
+/* Memory mapped register offsets */
+#define DATA_OFFSET       0x00
+#define STATUS_OFFSET     0x04
+#define CONTROL_OFFSET    0x08
+#define SCALER_OFFSET     0x0C  /* not supported */
+#define FIFO_DEBUG_OFFSET 0x10  /* not supported */
+
+#define FIFO_LENGTH 1024
+
+typedef struct UART {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    qemu_irq irq;
+
+    CharDriverState *chr;
+
+    /* registers */
+    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 FIFO_LENGTH - uart->len;
+}
+
+static void grlib_apbuart_receive(void *opaque, const uint8_t *buf, int size)
+{
+    UART *uart = opaque;
+
+    if (uart->control & UART_RECEIVE_ENABLE) {
+        uart_add_to_fifo(uart, buf, size);
+
+        uart->status |= UART_DATA_READY;
+
+        if (uart->control & UART_RECEIVE_INTERRUPT) {
+            qemu_irq_pulse(uart->irq);
+        }
+    }
+}
+
+static void grlib_apbuart_event(void *opaque, int event)
+{
+    trace_grlib_apbuart_event(event);
+}
+
+
+static uint64_t grlib_apbuart_read(void *opaque, hwaddr 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, hwaddr addr,
+                                uint64_t value, unsigned size)
+{
+    UART          *uart = opaque;
+    unsigned char  c    = 0;
+
+    addr &= 0xff;
+
+    /* Unit registers */
+    switch (addr) {
+    case DATA_OFFSET:
+    case DATA_OFFSET + 3:       /* When only one byte write */
+        /* Transmit when character device available and transmitter enabled */
+        if ((uart->chr) && (uart->control & UART_TRANSMIT_ENABLE)) {
+            c = value & 0xFF;
+            qemu_chr_fe_write(uart->chr, &c, 1);
+            /* Generate interrupt */
+            if (uart->control & UART_TRANSMIT_INTERRUPT) {
+                qemu_irq_pulse(uart->irq);
+            }
+        }
+        return;
+
+    case STATUS_OFFSET:
+        /* Read Only */
+        return;
+
+    case CONTROL_OFFSET:
+        uart->control = value;
+        return;
+
+    case SCALER_OFFSET:
+        /* Not supported */
+        return;
+
+    default:
+        break;
+    }
+
+    trace_grlib_apbuart_writel_unknown(addr, value);
+}
+
+static const MemoryRegionOps grlib_apbuart_ops = {
+    .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);
+
+    qemu_chr_add_handlers(uart->chr,
+                          grlib_apbuart_can_receive,
+                          grlib_apbuart_receive,
+                          grlib_apbuart_event,
+                          uart);
+
+    sysbus_init_irq(dev, &uart->irq);
+
+    memory_region_init_io(&uart->iomem, &grlib_apbuart_ops, uart,
+                          "uart", UART_REG_SIZE);
+
+    sysbus_init_mmio(dev, &uart->iomem);
+
+    return 0;
+}
+
+static void grlib_apbuart_reset(DeviceState *d)
+{
+    UART *uart = container_of(d, UART, busdev.qdev);
+
+    /* Transmitter FIFO and shift registers are always empty in QEMU */
+    uart->status =  UART_TRANSMIT_FIFO_EMPTY | UART_TRANSMIT_SHIFT_EMPTY;
+    /* Everything is off */
+    uart->control = 0;
+    /* Flush receive FIFO */
+    uart->len = 0;
+    uart->current = 0;
+}
+
+static Property grlib_apbuart_properties[] = {
+    DEFINE_PROP_CHR("chrdev", UART, chr),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void grlib_apbuart_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = grlib_apbuart_init;
+    dc->reset = grlib_apbuart_reset;
+    dc->props = grlib_apbuart_properties;
+}
+
+static const TypeInfo grlib_apbuart_info = {
+    .name          = "grlib,apbuart",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(UART),
+    .class_init    = grlib_apbuart_class_init,
+};
+
+static void grlib_apbuart_register_types(void)
+{
+    type_register_static(&grlib_apbuart_info);
+}
+
+type_init(grlib_apbuart_register_types)
diff --git a/hw/char/imx_serial.c b/hw/char/imx_serial.c
new file mode 100644 (file)
index 0000000..d7ec209
--- /dev/null
@@ -0,0 +1,467 @@
+/*
+ * IMX31 UARTS
+ *
+ * Copyright (c) 2008 OKL
+ * Originally Written by Hans Jiang
+ * Copyright (c) 2011 NICTA Pty Ltd.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ * This is a `bare-bones' implementation of the IMX series serial ports.
+ * TODO:
+ *  -- implement FIFOs.  The real hardware has 32 word transmit
+ *                       and receive FIFOs; we currently use a 1-char buffer
+ *  -- implement DMA
+ *  -- implement BAUD-rate and modem lines, for when the backend
+ *     is a real serial device.
+ */
+
+#include "hw/hw.h"
+#include "hw/sysbus.h"
+#include "sysemu/sysemu.h"
+#include "char/char.h"
+#include "hw/arm/imx.h"
+
+//#define DEBUG_SERIAL 1
+#ifdef DEBUG_SERIAL
+#define DPRINTF(fmt, args...) \
+do { printf("imx_serial: " fmt , ##args); } while (0)
+#else
+#define DPRINTF(fmt, args...) do {} while (0)
+#endif
+
+/*
+ * Define to 1 for messages about attempts to
+ * access unimplemented registers or similar.
+ */
+//#define DEBUG_IMPLEMENTATION 1
+#ifdef DEBUG_IMPLEMENTATION
+#  define IPRINTF(fmt, args...) \
+    do  { fprintf(stderr, "imx_serial: " fmt, ##args); } while (0)
+#else
+#  define IPRINTF(fmt, args...) do {} while (0)
+#endif
+
+typedef struct {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    int32_t readbuff;
+
+    uint32_t usr1;
+    uint32_t usr2;
+    uint32_t ucr1;
+    uint32_t ucr2;
+    uint32_t uts1;
+
+    /*
+     * The registers below are implemented just so that the
+     * guest OS sees what it has written
+     */
+    uint32_t onems;
+    uint32_t ufcr;
+    uint32_t ubmr;
+    uint32_t ubrc;
+    uint32_t ucr3;
+
+    qemu_irq irq;
+    CharDriverState *chr;
+} IMXSerialState;
+
+static const VMStateDescription vmstate_imx_serial = {
+    .name = "imx-serial",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_INT32(readbuff, IMXSerialState),
+        VMSTATE_UINT32(usr1, IMXSerialState),
+        VMSTATE_UINT32(usr2, IMXSerialState),
+        VMSTATE_UINT32(ucr1, IMXSerialState),
+        VMSTATE_UINT32(uts1, IMXSerialState),
+        VMSTATE_UINT32(onems, IMXSerialState),
+        VMSTATE_UINT32(ufcr, IMXSerialState),
+        VMSTATE_UINT32(ubmr, IMXSerialState),
+        VMSTATE_UINT32(ubrc, IMXSerialState),
+        VMSTATE_UINT32(ucr3, IMXSerialState),
+        VMSTATE_END_OF_LIST()
+    },
+};
+
+
+#define URXD_CHARRDY    (1<<15)   /* character read is valid */
+#define URXD_ERR        (1<<14)   /* Character has error */
+#define URXD_BRK        (1<<11)   /* Break received */
+
+#define USR1_PARTYER    (1<<15)   /* Parity Error */
+#define USR1_RTSS       (1<<14)   /* RTS pin status */
+#define USR1_TRDY       (1<<13)   /* Tx ready */
+#define USR1_RTSD       (1<<12)   /* RTS delta: pin changed state */
+#define USR1_ESCF       (1<<11)   /* Escape sequence interrupt */
+#define USR1_FRAMERR    (1<<10)   /* Framing error  */
+#define USR1_RRDY       (1<<9)    /* receiver ready */
+#define USR1_AGTIM      (1<<8)    /* Aging timer interrupt */
+#define USR1_DTRD       (1<<7)    /* DTR changed */
+#define USR1_RXDS       (1<<6)    /* Receiver is idle */
+#define USR1_AIRINT     (1<<5)    /* Aysnch IR interrupt */
+#define USR1_AWAKE      (1<<4)    /* Falling edge detected on RXd pin */
+
+#define USR2_ADET       (1<<15)   /* Autobaud complete */
+#define USR2_TXFE       (1<<14)   /* Transmit FIFO empty */
+#define USR2_DTRF       (1<<13)   /* DTR/DSR transition */
+#define USR2_IDLE       (1<<12)   /* UART has been idle for too long */
+#define USR2_ACST       (1<<11)   /* Autobaud counter stopped */
+#define USR2_RIDELT     (1<<10)   /* Ring Indicator delta */
+#define USR2_RIIN       (1<<9)    /* Ring Indicator Input */
+#define USR2_IRINT      (1<<8)    /* Serial Infrared Interrupt */
+#define USR2_WAKE       (1<<7)    /* Start bit detected */
+#define USR2_DCDDELT    (1<<6)    /* Data Carrier Detect delta */
+#define USR2_DCDIN      (1<<5)    /* Data Carrier Detect Input */
+#define USR2_RTSF       (1<<4)    /* RTS transition */
+#define USR2_TXDC       (1<<3)    /* Transmission complete */
+#define USR2_BRCD       (1<<2)    /* Break condition detected */
+#define USR2_ORE        (1<<1)    /* Overrun error */
+#define USR2_RDR        (1<<0)    /* Receive data ready */
+
+#define UCR1_TRDYEN     (1<<13)   /* Tx Ready Interrupt Enable */
+#define UCR1_RRDYEN     (1<<9)    /* Rx Ready Interrupt Enable */
+#define UCR1_TXMPTYEN   (1<<6)    /* Tx Empty Interrupt Enable */
+#define UCR1_UARTEN     (1<<0)    /* UART Enable */
+
+#define UCR2_TXEN       (1<<2)    /* Transmitter enable */
+#define UCR2_RXEN       (1<<1)    /* Receiver enable */
+#define UCR2_SRST       (1<<0)    /* Reset complete */
+
+#define UTS1_TXEMPTY    (1<<6)
+#define UTS1_RXEMPTY    (1<<5)
+#define UTS1_TXFULL     (1<<4)
+#define UTS1_RXFULL     (1<<3)
+
+static void imx_update(IMXSerialState *s)
+{
+    uint32_t flags;
+
+    flags = (s->usr1 & s->ucr1) & (USR1_TRDY|USR1_RRDY);
+    if (!(s->ucr1 & UCR1_TXMPTYEN)) {
+        flags &= ~USR1_TRDY;
+    }
+
+    qemu_set_irq(s->irq, !!flags);
+}
+
+static void imx_serial_reset(IMXSerialState *s)
+{
+
+    s->usr1 = USR1_TRDY | USR1_RXDS;
+    /*
+     * Fake attachment of a terminal: assert RTS.
+     */
+    s->usr1 |= USR1_RTSS;
+    s->usr2 = USR2_TXFE | USR2_TXDC | USR2_DCDIN;
+    s->uts1 = UTS1_RXEMPTY | UTS1_TXEMPTY;
+    s->ucr1 = 0;
+    s->ucr2 = UCR2_SRST;
+    s->ucr3 = 0x700;
+    s->ubmr = 0;
+    s->ubrc = 4;
+    s->readbuff = URXD_ERR;
+}
+
+static void imx_serial_reset_at_boot(DeviceState *dev)
+{
+    IMXSerialState *s = container_of(dev, IMXSerialState, busdev.qdev);
+
+    imx_serial_reset(s);
+
+    /*
+     * enable the uart on boot, so messages from the linux decompresser
+     * are visible.  On real hardware this is done by the boot rom
+     * before anything else is loaded.
+     */
+    s->ucr1 = UCR1_UARTEN;
+    s->ucr2 = UCR2_TXEN;
+
+}
+
+static uint64_t imx_serial_read(void *opaque, hwaddr offset,
+                                unsigned size)
+{
+    IMXSerialState *s = (IMXSerialState *)opaque;
+    uint32_t c;
+
+    DPRINTF("read(offset=%x)\n", offset >> 2);
+    switch (offset >> 2) {
+    case 0x0: /* URXD */
+        c = s->readbuff;
+        if (!(s->uts1 & UTS1_RXEMPTY)) {
+            /* Character is valid */
+            c |= URXD_CHARRDY;
+            s->usr1 &= ~USR1_RRDY;
+            s->usr2 &= ~USR2_RDR;
+            s->uts1 |= UTS1_RXEMPTY;
+            imx_update(s);
+            qemu_chr_accept_input(s->chr);
+        }
+        return c;
+
+    case 0x20: /* UCR1 */
+        return s->ucr1;
+
+    case 0x21: /* UCR2 */
+        return s->ucr2;
+
+    case 0x25: /* USR1 */
+        return s->usr1;
+
+    case 0x26: /* USR2 */
+        return s->usr2;
+
+    case 0x2A: /* BRM Modulator */
+        return s->ubmr;
+
+    case 0x2B: /* Baud Rate Count */
+        return s->ubrc;
+
+    case 0x2d: /* Test register */
+        return s->uts1;
+
+    case 0x24: /* UFCR */
+        return s->ufcr;
+
+    case 0x2c:
+        return s->onems;
+
+    case 0x22: /* UCR3 */
+        return s->ucr3;
+
+    case 0x23: /* UCR4 */
+    case 0x29: /* BRM Incremental */
+        return 0x0; /* TODO */
+
+    default:
+        IPRINTF("imx_serial_read: bad offset: 0x%x\n", (int)offset);
+        return 0;
+    }
+}
+
+static void imx_serial_write(void *opaque, hwaddr offset,
+                      uint64_t value, unsigned size)
+{
+    IMXSerialState *s = (IMXSerialState *)opaque;
+    unsigned char ch;
+
+    DPRINTF("write(offset=%x, value = %x) to %s\n",
+            offset >> 2,
+            (unsigned int)value, s->chr ? s->chr->label : "NODEV");
+
+    switch (offset >> 2) {
+    case 0x10: /* UTXD */
+        ch = value;
+        if (s->ucr2 & UCR2_TXEN) {
+            if (s->chr) {
+                qemu_chr_fe_write(s->chr, &ch, 1);
+            }
+            s->usr1 &= ~USR1_TRDY;
+            imx_update(s);
+            s->usr1 |= USR1_TRDY;
+            imx_update(s);
+        }
+        break;
+
+    case 0x20: /* UCR1 */
+        s->ucr1 = value & 0xffff;
+        DPRINTF("write(ucr1=%x)\n", (unsigned int)value);
+        imx_update(s);
+        break;
+
+    case 0x21: /* UCR2 */
+        /*
+         * Only a few bits in control register 2 are implemented as yet.
+         * If it's intended to use a real serial device as a back-end, this
+         * register will have to be implemented more fully.
+         */
+        if (!(value & UCR2_SRST)) {
+            imx_serial_reset(s);
+            imx_update(s);
+            value |= UCR2_SRST;
+        }
+        if (value & UCR2_RXEN) {
+            if (!(s->ucr2 & UCR2_RXEN)) {
+                qemu_chr_accept_input(s->chr);
+            }
+        }
+        s->ucr2 = value & 0xffff;
+        break;
+
+    case 0x25: /* USR1 */
+        value &= USR1_AWAKE | USR1_AIRINT | USR1_DTRD | USR1_AGTIM |
+            USR1_FRAMERR | USR1_ESCF | USR1_RTSD | USR1_PARTYER;
+        s->usr1 &= ~value;
+        break;
+
+    case 0x26: /* USR2 */
+       /*
+        * Writing 1 to some bits clears them; all other
+        * values are ignored
+        */
+        value &= USR2_ADET | USR2_DTRF | USR2_IDLE | USR2_ACST |
+            USR2_RIDELT | USR2_IRINT | USR2_WAKE |
+            USR2_DCDDELT | USR2_RTSF | USR2_BRCD | USR2_ORE;
+        s->usr2 &= ~value;
+        break;
+
+        /*
+         * Linux expects to see what it writes to these registers
+         * We don't currently alter the baud rate
+         */
+    case 0x29: /* UBIR */
+        s->ubrc = value & 0xffff;
+        break;
+
+    case 0x2a: /* UBMR */
+        s->ubmr = value & 0xffff;
+        break;
+
+    case 0x2c: /* One ms reg */
+        s->onems = value & 0xffff;
+        break;
+
+    case 0x24: /* FIFO control register */
+        s->ufcr = value & 0xffff;
+        break;
+
+    case 0x22: /* UCR3 */
+        s->ucr3 = value & 0xffff;
+        break;
+
+    case 0x2d: /* UTS1 */
+    case 0x23: /* UCR4 */
+        IPRINTF("Unimplemented Register %x written to\n", offset >> 2);
+        /* TODO */
+        break;
+
+    default:
+        IPRINTF("imx_serial_write: Bad offset 0x%x\n", (int)offset);
+    }
+}
+
+static int imx_can_receive(void *opaque)
+{
+    IMXSerialState *s = (IMXSerialState *)opaque;
+    return !(s->usr1 & USR1_RRDY);
+}
+
+static void imx_put_data(void *opaque, uint32_t value)
+{
+    IMXSerialState *s = (IMXSerialState *)opaque;
+    DPRINTF("received char\n");
+    s->usr1 |= USR1_RRDY;
+    s->usr2 |= USR2_RDR;
+    s->uts1 &= ~UTS1_RXEMPTY;
+    s->readbuff = value;
+    imx_update(s);
+}
+
+static void imx_receive(void *opaque, const uint8_t *buf, int size)
+{
+    imx_put_data(opaque, *buf);
+}
+
+static void imx_event(void *opaque, int event)
+{
+    if (event == CHR_EVENT_BREAK) {
+        imx_put_data(opaque, URXD_BRK);
+    }
+}
+
+
+static const struct MemoryRegionOps imx_serial_ops = {
+    .read = imx_serial_read,
+    .write = imx_serial_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int imx_serial_init(SysBusDevice *dev)
+{
+    IMXSerialState *s = FROM_SYSBUS(IMXSerialState, dev);
+
+
+    memory_region_init_io(&s->iomem, &imx_serial_ops, s, "imx-serial", 0x1000);
+    sysbus_init_mmio(dev, &s->iomem);
+    sysbus_init_irq(dev, &s->irq);
+
+    if (s->chr) {
+        qemu_chr_add_handlers(s->chr, imx_can_receive, imx_receive,
+                              imx_event, s);
+    } else {
+        DPRINTF("No char dev for uart at 0x%lx\n",
+                (unsigned long)s->iomem.ram_addr);
+    }
+
+    return 0;
+}
+
+void imx_serial_create(int uart, const hwaddr addr, qemu_irq irq)
+{
+    DeviceState *dev;
+    SysBusDevice *bus;
+    CharDriverState *chr;
+    const char chr_name[] = "serial";
+    char label[ARRAY_SIZE(chr_name) + 1];
+
+    dev = qdev_create(NULL, "imx-serial");
+
+    if (uart >= MAX_SERIAL_PORTS) {
+        hw_error("Cannot assign uart %d: QEMU supports only %d ports\n",
+                 uart, MAX_SERIAL_PORTS);
+    }
+    chr = serial_hds[uart];
+    if (!chr) {
+        snprintf(label, ARRAY_SIZE(label), "%s%d", chr_name, uart);
+        chr = qemu_chr_new(label, "null", NULL);
+        if (!(chr)) {
+            hw_error("Can't assign serial port to imx-uart%d.\n", uart);
+        }
+    }
+
+    qdev_prop_set_chr(dev, "chardev", chr);
+    bus = SYS_BUS_DEVICE(dev);
+    qdev_init_nofail(dev);
+    if (addr != (hwaddr)-1) {
+        sysbus_mmio_map(bus, 0, addr);
+    }
+    sysbus_connect_irq(bus, 0, irq);
+
+}
+
+
+static Property imx32_serial_properties[] = {
+    DEFINE_PROP_CHR("chardev", IMXSerialState, chr),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void imx_serial_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = imx_serial_init;
+    dc->vmsd = &vmstate_imx_serial;
+    dc->reset = imx_serial_reset_at_boot;
+    dc->desc = "i.MX series UART";
+    dc->props = imx32_serial_properties;
+}
+
+static const TypeInfo imx_serial_info = {
+    .name = "imx-serial",
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(IMXSerialState),
+    .class_init = imx_serial_class_init,
+};
+
+static void imx_serial_register_types(void)
+{
+    type_register_static(&imx_serial_info);
+}
+
+type_init(imx_serial_register_types)
diff --git a/hw/char/ipack.c b/hw/char/ipack.c
new file mode 100644 (file)
index 0000000..e15540d
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * QEMU IndustryPack emulation
+ *
+ * Copyright (C) 2012 Igalia, S.L.
+ * Author: Alberto Garcia <agarcia@igalia.com>
+ *
+ * This code is licensed under the GNU GPL v2 or (at your option) any
+ * later version.
+ */
+
+#include "ipack.h"
+
+IPackDevice *ipack_device_find(IPackBus *bus, int32_t slot)
+{
+    BusChild *kid;
+
+    QTAILQ_FOREACH(kid, &BUS(bus)->children, sibling) {
+        DeviceState *qdev = kid->child;
+        IPackDevice *ip = IPACK_DEVICE(qdev);
+        if (ip->slot == slot) {
+            return ip;
+        }
+    }
+    return NULL;
+}
+
+void ipack_bus_new_inplace(IPackBus *bus, DeviceState *parent,
+                           const char *name, uint8_t n_slots,
+                           qemu_irq_handler handler)
+{
+    qbus_create_inplace(&bus->qbus, TYPE_IPACK_BUS, parent, name);
+    bus->n_slots = n_slots;
+    bus->set_irq = handler;
+}
+
+static int ipack_device_dev_init(DeviceState *qdev)
+{
+    IPackBus *bus = IPACK_BUS(qdev_get_parent_bus(qdev));
+    IPackDevice *dev = IPACK_DEVICE(qdev);
+    IPackDeviceClass *k = IPACK_DEVICE_GET_CLASS(dev);
+
+    if (dev->slot < 0) {
+        dev->slot = bus->free_slot;
+    }
+    if (dev->slot >= bus->n_slots) {
+        return -1;
+    }
+    bus->free_slot = dev->slot + 1;
+
+    dev->irq = qemu_allocate_irqs(bus->set_irq, dev, 2);
+
+    return k->init(dev);
+}
+
+static int ipack_device_dev_exit(DeviceState *qdev)
+{
+    IPackDevice *dev = IPACK_DEVICE(qdev);
+    IPackDeviceClass *k = IPACK_DEVICE_GET_CLASS(dev);
+
+    if (k->exit) {
+        k->exit(dev);
+    }
+
+    qemu_free_irqs(dev->irq);
+
+    return 0;
+}
+
+static Property ipack_device_props[] = {
+    DEFINE_PROP_INT32("slot", IPackDevice, slot, -1),
+    DEFINE_PROP_END_OF_LIST()
+};
+
+static void ipack_device_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *k = DEVICE_CLASS(klass);
+    k->bus_type = TYPE_IPACK_BUS;
+    k->init = ipack_device_dev_init;
+    k->exit = ipack_device_dev_exit;
+    k->props = ipack_device_props;
+}
+
+const VMStateDescription vmstate_ipack_device = {
+    .name = "ipack_device",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_INT32(slot, IPackDevice),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const TypeInfo ipack_device_info = {
+    .name          = TYPE_IPACK_DEVICE,
+    .parent        = TYPE_DEVICE,
+    .instance_size = sizeof(IPackDevice),
+    .class_size    = sizeof(IPackDeviceClass),
+    .class_init    = ipack_device_class_init,
+    .abstract      = true,
+};
+
+static const TypeInfo ipack_bus_info = {
+    .name = TYPE_IPACK_BUS,
+    .parent = TYPE_BUS,
+    .instance_size = sizeof(IPackBus),
+};
+
+static void ipack_register_types(void)
+{
+    type_register_static(&ipack_device_info);
+    type_register_static(&ipack_bus_info);
+}
+
+type_init(ipack_register_types)
diff --git a/hw/char/ipack.h b/hw/char/ipack.h
new file mode 100644 (file)
index 0000000..f2b7a12
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * QEMU IndustryPack emulation
+ *
+ * Copyright (C) 2012 Igalia, S.L.
+ * Author: Alberto Garcia <agarcia@igalia.com>
+ *
+ * This code is licensed under the GNU GPL v2 or (at your option) any
+ * later version.
+ */
+
+#ifndef QEMU_IPACK_H
+#define QEMU_IPACK_H
+
+#include "hw/qdev.h"
+
+typedef struct IPackBus IPackBus;
+
+#define TYPE_IPACK_BUS "IndustryPack"
+#define IPACK_BUS(obj) OBJECT_CHECK(IPackBus, (obj), TYPE_IPACK_BUS)
+
+struct IPackBus {
+    BusState qbus;
+    /* All fields are private */
+    uint8_t n_slots;
+    uint8_t free_slot;
+    qemu_irq_handler set_irq;
+};
+
+typedef struct IPackDevice IPackDevice;
+typedef struct IPackDeviceClass IPackDeviceClass;
+
+#define TYPE_IPACK_DEVICE "ipack-device"
+#define IPACK_DEVICE(obj) \
+     OBJECT_CHECK(IPackDevice, (obj), TYPE_IPACK_DEVICE)
+#define IPACK_DEVICE_CLASS(klass)                                        \
+     OBJECT_CLASS_CHECK(IPackDeviceClass, (klass), TYPE_IPACK_DEVICE)
+#define IPACK_DEVICE_GET_CLASS(obj) \
+     OBJECT_GET_CLASS(IPackDeviceClass, (obj), TYPE_IPACK_DEVICE)
+
+struct IPackDeviceClass {
+    DeviceClass parent_class;
+
+    int (*init)(IPackDevice *dev);
+    int (*exit)(IPackDevice *dev);
+
+    uint16_t (*io_read)(IPackDevice *dev, uint8_t addr);
+    void (*io_write)(IPackDevice *dev, uint8_t addr, uint16_t val);
+
+    uint16_t (*id_read)(IPackDevice *dev, uint8_t addr);
+    void (*id_write)(IPackDevice *dev, uint8_t addr, uint16_t val);
+
+    uint16_t (*int_read)(IPackDevice *dev, uint8_t addr);
+    void (*int_write)(IPackDevice *dev, uint8_t addr, uint16_t val);
+
+    uint16_t (*mem_read16)(IPackDevice *dev, uint32_t addr);
+    void (*mem_write16)(IPackDevice *dev, uint32_t addr, uint16_t val);
+
+    uint8_t (*mem_read8)(IPackDevice *dev, uint32_t addr);
+    void (*mem_write8)(IPackDevice *dev, uint32_t addr, uint8_t val);
+};
+
+struct IPackDevice {
+    DeviceState qdev;
+    int32_t slot;
+    /* IRQ objects for the IndustryPack INT0# and INT1# */
+    qemu_irq *irq;
+};
+
+extern const VMStateDescription vmstate_ipack_device;
+
+#define VMSTATE_IPACK_DEVICE(_field, _state)                            \
+    VMSTATE_STRUCT(_field, _state, 1, vmstate_ipack_device, IPackDevice)
+
+IPackDevice *ipack_device_find(IPackBus *bus, int32_t slot);
+void ipack_bus_new_inplace(IPackBus *bus, DeviceState *parent,
+                           const char *name, uint8_t n_slots,
+                           qemu_irq_handler handler);
+
+#endif
diff --git a/hw/char/ipoctal232.c b/hw/char/ipoctal232.c
new file mode 100644 (file)
index 0000000..fcd0af3
--- /dev/null
@@ -0,0 +1,605 @@
+/*
+ * QEMU GE IP-Octal 232 IndustryPack emulation
+ *
+ * Copyright (C) 2012 Igalia, S.L.
+ * Author: Alberto Garcia <agarcia@igalia.com>
+ *
+ * This code is licensed under the GNU GPL v2 or (at your option) any
+ * later version.
+ */
+
+#include "ipack.h"
+#include "qemu/bitops.h"
+#include "char/char.h"
+
+/* #define DEBUG_IPOCTAL */
+
+#ifdef DEBUG_IPOCTAL
+#define DPRINTF2(fmt, ...) \
+    do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF2(fmt, ...) do { } while (0)
+#endif
+
+#define DPRINTF(fmt, ...) DPRINTF2("IP-Octal: " fmt, ## __VA_ARGS__)
+
+#define RX_FIFO_SIZE 3
+
+/* The IP-Octal has 8 channels (a-h)
+   divided into 4 blocks (A-D) */
+#define N_CHANNELS 8
+#define N_BLOCKS   4
+
+#define REG_MRa  0x01
+#define REG_MRb  0x11
+#define REG_SRa  0x03
+#define REG_SRb  0x13
+#define REG_CSRa 0x03
+#define REG_CSRb 0x13
+#define REG_CRa  0x05
+#define REG_CRb  0x15
+#define REG_RHRa 0x07
+#define REG_RHRb 0x17
+#define REG_THRa 0x07
+#define REG_THRb 0x17
+#define REG_ACR  0x09
+#define REG_ISR  0x0B
+#define REG_IMR  0x0B
+#define REG_OPCR 0x1B
+
+#define CR_ENABLE_RX    BIT(0)
+#define CR_DISABLE_RX   BIT(1)
+#define CR_ENABLE_TX    BIT(2)
+#define CR_DISABLE_TX   BIT(3)
+#define CR_CMD(cr)      ((cr) >> 4)
+#define CR_NO_OP        0
+#define CR_RESET_MR     1
+#define CR_RESET_RX     2
+#define CR_RESET_TX     3
+#define CR_RESET_ERR    4
+#define CR_RESET_BRKINT 5
+#define CR_START_BRK    6
+#define CR_STOP_BRK     7
+#define CR_ASSERT_RTSN  8
+#define CR_NEGATE_RTSN  9
+#define CR_TIMEOUT_ON   10
+#define CR_TIMEOUT_OFF  12
+
+#define SR_RXRDY   BIT(0)
+#define SR_FFULL   BIT(1)
+#define SR_TXRDY   BIT(2)
+#define SR_TXEMT   BIT(3)
+#define SR_OVERRUN BIT(4)
+#define SR_PARITY  BIT(5)
+#define SR_FRAMING BIT(6)
+#define SR_BREAK   BIT(7)
+
+#define ISR_TXRDYA BIT(0)
+#define ISR_RXRDYA BIT(1)
+#define ISR_BREAKA BIT(2)
+#define ISR_CNTRDY BIT(3)
+#define ISR_TXRDYB BIT(4)
+#define ISR_RXRDYB BIT(5)
+#define ISR_BREAKB BIT(6)
+#define ISR_MPICHG BIT(7)
+#define ISR_TXRDY(CH) (((CH) & 1) ? BIT(4) : BIT(0))
+#define ISR_RXRDY(CH) (((CH) & 1) ? BIT(5) : BIT(1))
+#define ISR_BREAK(CH) (((CH) & 1) ? BIT(6) : BIT(2))
+
+typedef struct IPOctalState IPOctalState;
+typedef struct SCC2698Channel SCC2698Channel;
+typedef struct SCC2698Block SCC2698Block;
+
+struct SCC2698Channel {
+    IPOctalState *ipoctal;
+    CharDriverState *dev;
+    bool rx_enabled;
+    uint8_t mr[2];
+    uint8_t mr_idx;
+    uint8_t sr;
+    uint8_t rhr[RX_FIFO_SIZE];
+    uint8_t rhr_idx;
+    uint8_t rx_pending;
+};
+
+struct SCC2698Block {
+    uint8_t imr;
+    uint8_t isr;
+};
+
+struct IPOctalState {
+    IPackDevice dev;
+    SCC2698Channel ch[N_CHANNELS];
+    SCC2698Block blk[N_BLOCKS];
+    uint8_t irq_vector;
+};
+
+#define TYPE_IPOCTAL "ipoctal232"
+
+#define IPOCTAL(obj) \
+    OBJECT_CHECK(IPOctalState, (obj), TYPE_IPOCTAL)
+
+static const VMStateDescription vmstate_scc2698_channel = {
+    .name = "scc2698_channel",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_BOOL(rx_enabled, SCC2698Channel),
+        VMSTATE_UINT8_ARRAY(mr, SCC2698Channel, 2),
+        VMSTATE_UINT8(mr_idx, SCC2698Channel),
+        VMSTATE_UINT8(sr, SCC2698Channel),
+        VMSTATE_UINT8_ARRAY(rhr, SCC2698Channel, RX_FIFO_SIZE),
+        VMSTATE_UINT8(rhr_idx, SCC2698Channel),
+        VMSTATE_UINT8(rx_pending, SCC2698Channel),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_scc2698_block = {
+    .name = "scc2698_block",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT8(imr, SCC2698Block),
+        VMSTATE_UINT8(isr, SCC2698Block),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_ipoctal = {
+    .name = "ipoctal232",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_IPACK_DEVICE(dev, IPOctalState),
+        VMSTATE_STRUCT_ARRAY(ch, IPOctalState, N_CHANNELS, 1,
+                             vmstate_scc2698_channel, SCC2698Channel),
+        VMSTATE_STRUCT_ARRAY(blk, IPOctalState, N_BLOCKS, 1,
+                             vmstate_scc2698_block, SCC2698Block),
+        VMSTATE_UINT8(irq_vector, IPOctalState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+/* data[10] is 0x0C, not 0x0B as the doc says */
+static const uint8_t id_prom_data[] = {
+    0x49, 0x50, 0x41, 0x43, 0xF0, 0x22,
+    0xA1, 0x00, 0x00, 0x00, 0x0C, 0xCC
+};
+
+static void update_irq(IPOctalState *dev, unsigned block)
+{
+    /* Blocks A and B interrupt on INT0#, C and D on INT1#.
+       Thus, to get the status we have to check two blocks. */
+    SCC2698Block *blk0 = &dev->blk[block];
+    SCC2698Block *blk1 = &dev->blk[block^1];
+    unsigned intno = block / 2;
+
+    if ((blk0->isr & blk0->imr) || (blk1->isr & blk1->imr)) {
+        qemu_irq_raise(dev->dev.irq[intno]);
+    } else {
+        qemu_irq_lower(dev->dev.irq[intno]);
+    }
+}
+
+static void write_cr(IPOctalState *dev, unsigned channel, uint8_t val)
+{
+    SCC2698Channel *ch = &dev->ch[channel];
+    SCC2698Block *blk = &dev->blk[channel / 2];
+
+    DPRINTF("Write CR%c %u: ", channel + 'a', val);
+
+    /* The lower 4 bits are used to enable and disable Tx and Rx */
+    if (val & CR_ENABLE_RX) {
+        DPRINTF2("Rx on, ");
+        ch->rx_enabled = true;
+    }
+    if (val & CR_DISABLE_RX) {
+        DPRINTF2("Rx off, ");
+        ch->rx_enabled = false;
+    }
+    if (val & CR_ENABLE_TX) {
+        DPRINTF2("Tx on, ");
+        ch->sr |= SR_TXRDY | SR_TXEMT;
+        blk->isr |= ISR_TXRDY(channel);
+    }
+    if (val & CR_DISABLE_TX) {
+        DPRINTF2("Tx off, ");
+        ch->sr &= ~(SR_TXRDY | SR_TXEMT);
+        blk->isr &= ~ISR_TXRDY(channel);
+    }
+
+    DPRINTF2("cmd: ");
+
+    /* The rest of the bits implement different commands */
+    switch (CR_CMD(val)) {
+    case CR_NO_OP:
+        DPRINTF2("none");
+        break;
+    case CR_RESET_MR:
+        DPRINTF2("reset MR");
+        ch->mr_idx = 0;
+        break;
+    case CR_RESET_RX:
+        DPRINTF2("reset Rx");
+        ch->rx_enabled = false;
+        ch->rx_pending = 0;
+        ch->sr &= ~SR_RXRDY;
+        blk->isr &= ~ISR_RXRDY(channel);
+        break;
+    case CR_RESET_TX:
+        DPRINTF2("reset Tx");
+        ch->sr &= ~(SR_TXRDY | SR_TXEMT);
+        blk->isr &= ~ISR_TXRDY(channel);
+        break;
+    case CR_RESET_ERR:
+        DPRINTF2("reset err");
+        ch->sr &= ~(SR_OVERRUN | SR_PARITY | SR_FRAMING | SR_BREAK);
+        break;
+    case CR_RESET_BRKINT:
+        DPRINTF2("reset brk ch int");
+        blk->isr &= ~(ISR_BREAKA | ISR_BREAKB);
+        break;
+    default:
+        DPRINTF2("unsupported 0x%x", CR_CMD(val));
+    }
+
+    DPRINTF2("\n");
+}
+
+static uint16_t io_read(IPackDevice *ip, uint8_t addr)
+{
+    IPOctalState *dev = IPOCTAL(ip);
+    uint16_t ret = 0;
+    /* addr[7:6]: block   (A-D)
+       addr[7:5]: channel (a-h)
+       addr[5:0]: register */
+    unsigned block = addr >> 5;
+    unsigned channel = addr >> 4;
+    /* Big endian, accessed using 8-bit bytes at odd locations */
+    unsigned offset = (addr & 0x1F) ^ 1;
+    SCC2698Channel *ch = &dev->ch[channel];
+    SCC2698Block *blk = &dev->blk[block];
+    uint8_t old_isr = blk->isr;
+
+    switch (offset) {
+
+    case REG_MRa:
+    case REG_MRb:
+        ret = ch->mr[ch->mr_idx];
+        DPRINTF("Read MR%u%c: 0x%x\n", ch->mr_idx + 1, channel + 'a', ret);
+        ch->mr_idx = 1;
+        break;
+
+    case REG_SRa:
+    case REG_SRb:
+        ret = ch->sr;
+        DPRINTF("Read SR%c: 0x%x\n", channel + 'a', ret);
+        break;
+
+    case REG_RHRa:
+    case REG_RHRb:
+        ret = ch->rhr[ch->rhr_idx];
+        if (ch->rx_pending > 0) {
+            ch->rx_pending--;
+            if (ch->rx_pending == 0) {
+                ch->sr &= ~SR_RXRDY;
+                blk->isr &= ~ISR_RXRDY(channel);
+                if (ch->dev) {
+                    qemu_chr_accept_input(ch->dev);
+                }
+            } else {
+                ch->rhr_idx = (ch->rhr_idx + 1) % RX_FIFO_SIZE;
+            }
+            if (ch->sr & SR_BREAK) {
+                ch->sr &= ~SR_BREAK;
+                blk->isr |= ISR_BREAK(channel);
+            }
+        }
+        DPRINTF("Read RHR%c (0x%x)\n", channel + 'a', ret);
+        break;
+
+    case REG_ISR:
+        ret = blk->isr;
+        DPRINTF("Read ISR%c: 0x%x\n", block + 'A', ret);
+        break;
+
+    default:
+        DPRINTF("Read unknown/unsupported register 0x%02x\n", offset);
+    }
+
+    if (old_isr != blk->isr) {
+        update_irq(dev, block);
+    }
+
+    return ret;
+}
+
+static void io_write(IPackDevice *ip, uint8_t addr, uint16_t val)
+{
+    IPOctalState *dev = IPOCTAL(ip);
+    unsigned reg = val & 0xFF;
+    /* addr[7:6]: block   (A-D)
+       addr[7:5]: channel (a-h)
+       addr[5:0]: register */
+    unsigned block = addr >> 5;
+    unsigned channel = addr >> 4;
+    /* Big endian, accessed using 8-bit bytes at odd locations */
+    unsigned offset = (addr & 0x1F) ^ 1;
+    SCC2698Channel *ch = &dev->ch[channel];
+    SCC2698Block *blk = &dev->blk[block];
+    uint8_t old_isr = blk->isr;
+    uint8_t old_imr = blk->imr;
+
+    switch (offset) {
+
+    case REG_MRa:
+    case REG_MRb:
+        ch->mr[ch->mr_idx] = reg;
+        DPRINTF("Write MR%u%c 0x%x\n", ch->mr_idx + 1, channel + 'a', reg);
+        ch->mr_idx = 1;
+        break;
+
+    /* Not implemented */
+    case REG_CSRa:
+    case REG_CSRb:
+        DPRINTF("Write CSR%c: 0x%x\n", channel + 'a', reg);
+        break;
+
+    case REG_CRa:
+    case REG_CRb:
+        write_cr(dev, channel, reg);
+        break;
+
+    case REG_THRa:
+    case REG_THRb:
+        if (ch->sr & SR_TXRDY) {
+            DPRINTF("Write THR%c (0x%x)\n", channel + 'a', reg);
+            if (ch->dev) {
+                uint8_t thr = reg;
+                qemu_chr_fe_write(ch->dev, &thr, 1);
+            }
+        } else {
+            DPRINTF("Write THR%c (0x%x), Tx disabled\n", channel + 'a', reg);
+        }
+        break;
+
+    /* Not implemented */
+    case REG_ACR:
+        DPRINTF("Write ACR%c 0x%x\n", block + 'A', val);
+        break;
+
+    case REG_IMR:
+        DPRINTF("Write IMR%c 0x%x\n", block + 'A', val);
+        blk->imr = reg;
+        break;
+
+    /* Not implemented */
+    case REG_OPCR:
+        DPRINTF("Write OPCR%c 0x%x\n", block + 'A', val);
+        break;
+
+    default:
+        DPRINTF("Write unknown/unsupported register 0x%02x %u\n", offset, val);
+    }
+
+    if (old_isr != blk->isr || old_imr != blk->imr) {
+        update_irq(dev, block);
+    }
+}
+
+static uint16_t id_read(IPackDevice *ip, uint8_t addr)
+{
+    uint16_t ret = 0;
+    unsigned pos = addr / 2; /* The ID PROM data is stored every other byte */
+
+    if (pos < ARRAY_SIZE(id_prom_data)) {
+        ret = id_prom_data[pos];
+    } else {
+        DPRINTF("Attempt to read unavailable PROM data at 0x%x\n",  addr);
+    }
+
+    return ret;
+}
+
+static void id_write(IPackDevice *ip, uint8_t addr, uint16_t val)
+{
+    IPOctalState *dev = IPOCTAL(ip);
+    if (addr == 1) {
+        DPRINTF("Write IRQ vector: %u\n", (unsigned) val);
+        dev->irq_vector = val; /* Undocumented, but the hw works like that */
+    } else {
+        DPRINTF("Attempt to write 0x%x to 0x%x\n", val, addr);
+    }
+}
+
+static uint16_t int_read(IPackDevice *ip, uint8_t addr)
+{
+    IPOctalState *dev = IPOCTAL(ip);
+    /* Read address 0 to ACK INT0# and address 2 to ACK INT1# */
+    if (addr != 0 && addr != 2) {
+        DPRINTF("Attempt to read from 0x%x\n", addr);
+        return 0;
+    } else {
+        /* Update interrupts if necessary */
+        update_irq(dev, addr);
+        return dev->irq_vector;
+    }
+}
+
+static void int_write(IPackDevice *ip, uint8_t addr, uint16_t val)
+{
+    DPRINTF("Attempt to write 0x%x to 0x%x\n", val, addr);
+}
+
+static uint16_t mem_read16(IPackDevice *ip, uint32_t addr)
+{
+    DPRINTF("Attempt to read from 0x%x\n", addr);
+    return 0;
+}
+
+static void mem_write16(IPackDevice *ip, uint32_t addr, uint16_t val)
+{
+    DPRINTF("Attempt to write 0x%x to 0x%x\n", val, addr);
+}
+
+static uint8_t mem_read8(IPackDevice *ip, uint32_t addr)
+{
+    DPRINTF("Attempt to read from 0x%x\n", addr);
+    return 0;
+}
+
+static void mem_write8(IPackDevice *ip, uint32_t addr, uint8_t val)
+{
+    IPOctalState *dev = IPOCTAL(ip);
+    if (addr == 1) {
+        DPRINTF("Write IRQ vector: %u\n", (unsigned) val);
+        dev->irq_vector = val;
+    } else {
+        DPRINTF("Attempt to write 0x%x to 0x%x\n", val, addr);
+    }
+}
+
+static int hostdev_can_receive(void *opaque)
+{
+    SCC2698Channel *ch = opaque;
+    int available_bytes = RX_FIFO_SIZE - ch->rx_pending;
+    return ch->rx_enabled ? available_bytes : 0;
+}
+
+static void hostdev_receive(void *opaque, const uint8_t *buf, int size)
+{
+    SCC2698Channel *ch = opaque;
+    IPOctalState *dev = ch->ipoctal;
+    unsigned pos = ch->rhr_idx + ch->rx_pending;
+    int i;
+
+    assert(size + ch->rx_pending <= RX_FIFO_SIZE);
+
+    /* Copy data to the RxFIFO */
+    for (i = 0; i < size; i++) {
+        pos %= RX_FIFO_SIZE;
+        ch->rhr[pos++] = buf[i];
+    }
+
+    ch->rx_pending += size;
+
+    /* If the RxFIFO was empty raise an interrupt */
+    if (!(ch->sr & SR_RXRDY)) {
+        unsigned block, channel = 0;
+        /* Find channel number to update the ISR register */
+        while (&dev->ch[channel] != ch) {
+            channel++;
+        }
+        block = channel / 2;
+        dev->blk[block].isr |= ISR_RXRDY(channel);
+        ch->sr |= SR_RXRDY;
+        update_irq(dev, block);
+    }
+}
+
+static void hostdev_event(void *opaque, int event)
+{
+    SCC2698Channel *ch = opaque;
+    switch (event) {
+    case CHR_EVENT_OPENED:
+        DPRINTF("Device %s opened\n", ch->dev->label);
+        break;
+    case CHR_EVENT_BREAK: {
+        uint8_t zero = 0;
+        DPRINTF("Device %s received break\n", ch->dev->label);
+
+        if (!(ch->sr & SR_BREAK)) {
+            IPOctalState *dev = ch->ipoctal;
+            unsigned block, channel = 0;
+
+            while (&dev->ch[channel] != ch) {
+                channel++;
+            }
+            block = channel / 2;
+
+            ch->sr |= SR_BREAK;
+            dev->blk[block].isr |= ISR_BREAK(channel);
+        }
+
+        /* Put a zero character in the buffer */
+        hostdev_receive(ch, &zero, 1);
+    }
+        break;
+    default:
+        DPRINTF("Device %s received event %d\n", ch->dev->label, event);
+    }
+}
+
+static int ipoctal_init(IPackDevice *ip)
+{
+    IPOctalState *s = IPOCTAL(ip);
+    unsigned i;
+
+    for (i = 0; i < N_CHANNELS; i++) {
+        SCC2698Channel *ch = &s->ch[i];
+        ch->ipoctal = s;
+
+        /* Redirect IP-Octal channels to host character devices */
+        if (ch->dev) {
+            qemu_chr_add_handlers(ch->dev, hostdev_can_receive,
+                                  hostdev_receive, hostdev_event, ch);
+            DPRINTF("Redirecting channel %u to %s\n", i, ch->dev->label);
+        } else {
+            DPRINTF("Could not redirect channel %u, no chardev set\n", i);
+        }
+    }
+
+    return 0;
+}
+
+static Property ipoctal_properties[] = {
+    DEFINE_PROP_CHR("chardev0", IPOctalState, ch[0].dev),
+    DEFINE_PROP_CHR("chardev1", IPOctalState, ch[1].dev),
+    DEFINE_PROP_CHR("chardev2", IPOctalState, ch[2].dev),
+    DEFINE_PROP_CHR("chardev3", IPOctalState, ch[3].dev),
+    DEFINE_PROP_CHR("chardev4", IPOctalState, ch[4].dev),
+    DEFINE_PROP_CHR("chardev5", IPOctalState, ch[5].dev),
+    DEFINE_PROP_CHR("chardev6", IPOctalState, ch[6].dev),
+    DEFINE_PROP_CHR("chardev7", IPOctalState, ch[7].dev),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void ipoctal_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    IPackDeviceClass *ic = IPACK_DEVICE_CLASS(klass);
+
+    ic->init        = ipoctal_init;
+    ic->io_read     = io_read;
+    ic->io_write    = io_write;
+    ic->id_read     = id_read;
+    ic->id_write    = id_write;
+    ic->int_read    = int_read;
+    ic->int_write   = int_write;
+    ic->mem_read16  = mem_read16;
+    ic->mem_write16 = mem_write16;
+    ic->mem_read8   = mem_read8;
+    ic->mem_write8  = mem_write8;
+
+    dc->desc    = "GE IP-Octal 232 8-channel RS-232 IndustryPack";
+    dc->props   = ipoctal_properties;
+    dc->vmsd    = &vmstate_ipoctal;
+}
+
+static const TypeInfo ipoctal_info = {
+    .name          = TYPE_IPOCTAL,
+    .parent        = TYPE_IPACK_DEVICE,
+    .instance_size = sizeof(IPOctalState),
+    .class_init    = ipoctal_class_init,
+};
+
+static void ipoctal_register_types(void)
+{
+    type_register_static(&ipoctal_info);
+}
+
+type_init(ipoctal_register_types)
diff --git a/hw/char/lm32_juart.c b/hw/char/lm32_juart.c
new file mode 100644 (file)
index 0000000..93f0d15
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ *  LatticeMico32 JTAG UART model.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
+ *
+ * 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/hw.h"
+#include "hw/sysbus.h"
+#include "trace.h"
+#include "char/char.h"
+
+#include "hw/lm32/lm32_juart.h"
+
+enum {
+    LM32_JUART_MIN_SAVE_VERSION = 0,
+    LM32_JUART_CURRENT_SAVE_VERSION = 0,
+    LM32_JUART_MAX_SAVE_VERSION = 0,
+};
+
+enum {
+    JTX_FULL = (1<<8),
+};
+
+enum {
+    JRX_FULL = (1<<8),
+};
+
+struct LM32JuartState {
+    SysBusDevice busdev;
+    CharDriverState *chr;
+
+    uint32_t jtx;
+    uint32_t jrx;
+};
+typedef struct LM32JuartState LM32JuartState;
+
+uint32_t lm32_juart_get_jtx(DeviceState *d)
+{
+    LM32JuartState *s = container_of(d, LM32JuartState, busdev.qdev);
+
+    trace_lm32_juart_get_jtx(s->jtx);
+    return s->jtx;
+}
+
+uint32_t lm32_juart_get_jrx(DeviceState *d)
+{
+    LM32JuartState *s = container_of(d, LM32JuartState, busdev.qdev);
+
+    trace_lm32_juart_get_jrx(s->jrx);
+    return s->jrx;
+}
+
+void lm32_juart_set_jtx(DeviceState *d, uint32_t jtx)
+{
+    LM32JuartState *s = container_of(d, LM32JuartState, busdev.qdev);
+    unsigned char ch = jtx & 0xff;
+
+    trace_lm32_juart_set_jtx(s->jtx);
+
+    s->jtx = jtx;
+    if (s->chr) {
+        qemu_chr_fe_write(s->chr, &ch, 1);
+    }
+}
+
+void lm32_juart_set_jrx(DeviceState *d, uint32_t jtx)
+{
+    LM32JuartState *s = container_of(d, LM32JuartState, busdev.qdev);
+
+    trace_lm32_juart_set_jrx(s->jrx);
+    s->jrx &= ~JRX_FULL;
+}
+
+static void juart_rx(void *opaque, const uint8_t *buf, int size)
+{
+    LM32JuartState *s = opaque;
+
+    s->jrx = *buf | JRX_FULL;
+}
+
+static int juart_can_rx(void *opaque)
+{
+    LM32JuartState *s = opaque;
+
+    return !(s->jrx & JRX_FULL);
+}
+
+static void juart_event(void *opaque, int event)
+{
+}
+
+static void juart_reset(DeviceState *d)
+{
+    LM32JuartState *s = container_of(d, LM32JuartState, busdev.qdev);
+
+    s->jtx = 0;
+    s->jrx = 0;
+}
+
+static int lm32_juart_init(SysBusDevice *dev)
+{
+    LM32JuartState *s = FROM_SYSBUS(typeof(*s), dev);
+
+    s->chr = qemu_char_get_next_serial();
+    if (s->chr) {
+        qemu_chr_add_handlers(s->chr, juart_can_rx, juart_rx, juart_event, s);
+    }
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_lm32_juart = {
+    .name = "lm32-juart",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32(jtx, LM32JuartState),
+        VMSTATE_UINT32(jrx, LM32JuartState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+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 const 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_types(void)
+{
+    type_register_static(&lm32_juart_info);
+}
+
+type_init(lm32_juart_register_types)
diff --git a/hw/char/lm32_uart.c b/hw/char/lm32_uart.c
new file mode 100644 (file)
index 0000000..32bc37a
--- /dev/null
@@ -0,0 +1,297 @@
+/*
+ *  QEMU model of the LatticeMico32 UART block.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
+ *
+ * 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/>.
+ *
+ *
+ * Specification available at:
+ *   http://www.latticesemi.com/documents/mico32uart.pdf
+ */
+
+
+#include "hw/hw.h"
+#include "hw/sysbus.h"
+#include "trace.h"
+#include "char/char.h"
+#include "qemu/error-report.h"
+
+enum {
+    R_RXTX = 0,
+    R_IER,
+    R_IIR,
+    R_LCR,
+    R_MCR,
+    R_LSR,
+    R_MSR,
+    R_DIV,
+    R_MAX
+};
+
+enum {
+    IER_RBRI = (1<<0),
+    IER_THRI = (1<<1),
+    IER_RLSI = (1<<2),
+    IER_MSI  = (1<<3),
+};
+
+enum {
+    IIR_STAT = (1<<0),
+    IIR_ID0  = (1<<1),
+    IIR_ID1  = (1<<2),
+};
+
+enum {
+    LCR_WLS0 = (1<<0),
+    LCR_WLS1 = (1<<1),
+    LCR_STB  = (1<<2),
+    LCR_PEN  = (1<<3),
+    LCR_EPS  = (1<<4),
+    LCR_SP   = (1<<5),
+    LCR_SB   = (1<<6),
+};
+
+enum {
+    MCR_DTR  = (1<<0),
+    MCR_RTS  = (1<<1),
+};
+
+enum {
+    LSR_DR   = (1<<0),
+    LSR_OE   = (1<<1),
+    LSR_PE   = (1<<2),
+    LSR_FE   = (1<<3),
+    LSR_BI   = (1<<4),
+    LSR_THRE = (1<<5),
+    LSR_TEMT = (1<<6),
+};
+
+enum {
+    MSR_DCTS = (1<<0),
+    MSR_DDSR = (1<<1),
+    MSR_TERI = (1<<2),
+    MSR_DDCD = (1<<3),
+    MSR_CTS  = (1<<4),
+    MSR_DSR  = (1<<5),
+    MSR_RI   = (1<<6),
+    MSR_DCD  = (1<<7),
+};
+
+struct LM32UartState {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    CharDriverState *chr;
+    qemu_irq irq;
+
+    uint32_t regs[R_MAX];
+};
+typedef struct LM32UartState LM32UartState;
+
+static void uart_update_irq(LM32UartState *s)
+{
+    unsigned int irq;
+
+    if ((s->regs[R_LSR] & (LSR_OE | LSR_PE | LSR_FE | LSR_BI))
+            && (s->regs[R_IER] & IER_RLSI)) {
+        irq = 1;
+        s->regs[R_IIR] = IIR_ID1 | IIR_ID0;
+    } else if ((s->regs[R_LSR] & LSR_DR) && (s->regs[R_IER] & IER_RBRI)) {
+        irq = 1;
+        s->regs[R_IIR] = IIR_ID1;
+    } else if ((s->regs[R_LSR] & LSR_THRE) && (s->regs[R_IER] & IER_THRI)) {
+        irq = 1;
+        s->regs[R_IIR] = IIR_ID0;
+    } else if ((s->regs[R_MSR] & 0x0f) && (s->regs[R_IER] & IER_MSI)) {
+        irq = 1;
+        s->regs[R_IIR] = 0;
+    } else {
+        irq = 0;
+        s->regs[R_IIR] = IIR_STAT;
+    }
+
+    trace_lm32_uart_irq_state(irq);
+    qemu_set_irq(s->irq, irq);
+}
+
+static uint64_t uart_read(void *opaque, hwaddr addr,
+                          unsigned size)
+{
+    LM32UartState *s = opaque;
+    uint32_t r = 0;
+
+    addr >>= 2;
+    switch (addr) {
+    case R_RXTX:
+        r = s->regs[R_RXTX];
+        s->regs[R_LSR] &= ~LSR_DR;
+        uart_update_irq(s);
+        qemu_chr_accept_input(s->chr);
+        break;
+    case R_IIR:
+    case R_LSR:
+    case R_MSR:
+        r = s->regs[addr];
+        break;
+    case R_IER:
+    case R_LCR:
+    case R_MCR:
+    case R_DIV:
+        error_report("lm32_uart: read access to write only register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    default:
+        error_report("lm32_uart: read access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+
+    trace_lm32_uart_memory_read(addr << 2, r);
+    return r;
+}
+
+static void uart_write(void *opaque, hwaddr addr,
+                       uint64_t value, unsigned size)
+{
+    LM32UartState *s = opaque;
+    unsigned char ch = value;
+
+    trace_lm32_uart_memory_write(addr, value);
+
+    addr >>= 2;
+    switch (addr) {
+    case R_RXTX:
+        if (s->chr) {
+            qemu_chr_fe_write(s->chr, &ch, 1);
+        }
+        break;
+    case R_IER:
+    case R_LCR:
+    case R_MCR:
+    case R_DIV:
+        s->regs[addr] = value;
+        break;
+    case R_IIR:
+    case R_LSR:
+    case R_MSR:
+        error_report("lm32_uart: write access to read only register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    default:
+        error_report("lm32_uart: write access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+    uart_update_irq(s);
+}
+
+static const MemoryRegionOps uart_ops = {
+    .read = uart_read,
+    .write = uart_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static void uart_rx(void *opaque, const uint8_t *buf, int size)
+{
+    LM32UartState *s = opaque;
+
+    if (s->regs[R_LSR] & LSR_DR) {
+        s->regs[R_LSR] |= LSR_OE;
+    }
+
+    s->regs[R_LSR] |= LSR_DR;
+    s->regs[R_RXTX] = *buf;
+
+    uart_update_irq(s);
+}
+
+static int uart_can_rx(void *opaque)
+{
+    LM32UartState *s = opaque;
+
+    return !(s->regs[R_LSR] & LSR_DR);
+}
+
+static void uart_event(void *opaque, int event)
+{
+}
+
+static void uart_reset(DeviceState *d)
+{
+    LM32UartState *s = container_of(d, LM32UartState, busdev.qdev);
+    int i;
+
+    for (i = 0; i < R_MAX; i++) {
+        s->regs[i] = 0;
+    }
+
+    /* defaults */
+    s->regs[R_LSR] = LSR_THRE | LSR_TEMT;
+}
+
+static int lm32_uart_init(SysBusDevice *dev)
+{
+    LM32UartState *s = FROM_SYSBUS(typeof(*s), dev);
+
+    sysbus_init_irq(dev, &s->irq);
+
+    memory_region_init_io(&s->iomem, &uart_ops, s, "uart", R_MAX * 4);
+    sysbus_init_mmio(dev, &s->iomem);
+
+    s->chr = qemu_char_get_next_serial();
+    if (s->chr) {
+        qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s);
+    }
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_lm32_uart = {
+    .name = "lm32-uart",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(regs, LM32UartState, R_MAX),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+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 const 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_types(void)
+{
+    type_register_static(&lm32_uart_info);
+}
+
+type_init(lm32_uart_register_types)
diff --git a/hw/char/mcf_uart.c b/hw/char/mcf_uart.c
new file mode 100644 (file)
index 0000000..6724b1b
--- /dev/null
@@ -0,0 +1,307 @@
+/*
+ * ColdFire UART emulation.
+ *
+ * Copyright (c) 2007 CodeSourcery.
+ *
+ * This code is licensed under the GPL
+ */
+#include "hw/hw.h"
+#include "hw/m68k/mcf.h"
+#include "char/char.h"
+#include "exec/address-spaces.h"
+
+typedef struct {
+    MemoryRegion iomem;
+    uint8_t mr[2];
+    uint8_t sr;
+    uint8_t isr;
+    uint8_t imr;
+    uint8_t bg1;
+    uint8_t bg2;
+    uint8_t fifo[4];
+    uint8_t tb;
+    int current_mr;
+    int fifo_len;
+    int tx_enabled;
+    int rx_enabled;
+    qemu_irq irq;
+    CharDriverState *chr;
+} mcf_uart_state;
+
+/* UART Status Register bits.  */
+#define MCF_UART_RxRDY  0x01
+#define MCF_UART_FFULL  0x02
+#define MCF_UART_TxRDY  0x04
+#define MCF_UART_TxEMP  0x08
+#define MCF_UART_OE     0x10
+#define MCF_UART_PE     0x20
+#define MCF_UART_FE     0x40
+#define MCF_UART_RB     0x80
+
+/* Interrupt flags.  */
+#define MCF_UART_TxINT  0x01
+#define MCF_UART_RxINT  0x02
+#define MCF_UART_DBINT  0x04
+#define MCF_UART_COSINT 0x80
+
+/* UMR1 flags.  */
+#define MCF_UART_BC0    0x01
+#define MCF_UART_BC1    0x02
+#define MCF_UART_PT     0x04
+#define MCF_UART_PM0    0x08
+#define MCF_UART_PM1    0x10
+#define MCF_UART_ERR    0x20
+#define MCF_UART_RxIRQ  0x40
+#define MCF_UART_RxRTS  0x80
+
+static void mcf_uart_update(mcf_uart_state *s)
+{
+    s->isr &= ~(MCF_UART_TxINT | MCF_UART_RxINT);
+    if (s->sr & MCF_UART_TxRDY)
+        s->isr |= MCF_UART_TxINT;
+    if ((s->sr & ((s->mr[0] & MCF_UART_RxIRQ)
+                  ? MCF_UART_FFULL : MCF_UART_RxRDY)) != 0)
+        s->isr |= MCF_UART_RxINT;
+
+    qemu_set_irq(s->irq, (s->isr & s->imr) != 0);
+}
+
+uint64_t mcf_uart_read(void *opaque, hwaddr addr,
+                       unsigned size)
+{
+    mcf_uart_state *s = (mcf_uart_state *)opaque;
+    switch (addr & 0x3f) {
+    case 0x00:
+        return s->mr[s->current_mr];
+    case 0x04:
+        return s->sr;
+    case 0x0c:
+        {
+            uint8_t val;
+            int i;
+
+            if (s->fifo_len == 0)
+                return 0;
+
+            val = s->fifo[0];
+            s->fifo_len--;
+            for (i = 0; i < s->fifo_len; i++)
+                s->fifo[i] = s->fifo[i + 1];
+            s->sr &= ~MCF_UART_FFULL;
+            if (s->fifo_len == 0)
+                s->sr &= ~MCF_UART_RxRDY;
+            mcf_uart_update(s);
+            qemu_chr_accept_input(s->chr);
+            return val;
+        }
+    case 0x10:
+        /* TODO: Implement IPCR.  */
+        return 0;
+    case 0x14:
+        return s->isr;
+    case 0x18:
+        return s->bg1;
+    case 0x1c:
+        return s->bg2;
+    default:
+        return 0;
+    }
+}
+
+/* Update TxRDY flag and set data if present and enabled.  */
+static void mcf_uart_do_tx(mcf_uart_state *s)
+{
+    if (s->tx_enabled && (s->sr & MCF_UART_TxEMP) == 0) {
+        if (s->chr)
+            qemu_chr_fe_write(s->chr, (unsigned char *)&s->tb, 1);
+        s->sr |= MCF_UART_TxEMP;
+    }
+    if (s->tx_enabled) {
+        s->sr |= MCF_UART_TxRDY;
+    } else {
+        s->sr &= ~MCF_UART_TxRDY;
+    }
+}
+
+static void mcf_do_command(mcf_uart_state *s, uint8_t cmd)
+{
+    /* Misc command.  */
+    switch ((cmd >> 4) & 3) {
+    case 0: /* No-op.  */
+        break;
+    case 1: /* Reset mode register pointer.  */
+        s->current_mr = 0;
+        break;
+    case 2: /* Reset receiver.  */
+        s->rx_enabled = 0;
+        s->fifo_len = 0;
+        s->sr &= ~(MCF_UART_RxRDY | MCF_UART_FFULL);
+        break;
+    case 3: /* Reset transmitter.  */
+        s->tx_enabled = 0;
+        s->sr |= MCF_UART_TxEMP;
+        s->sr &= ~MCF_UART_TxRDY;
+        break;
+    case 4: /* Reset error status.  */
+        break;
+    case 5: /* Reset break-change interrupt.  */
+        s->isr &= ~MCF_UART_DBINT;
+        break;
+    case 6: /* Start break.  */
+    case 7: /* Stop break.  */
+        break;
+    }
+
+    /* Transmitter command.  */
+    switch ((cmd >> 2) & 3) {
+    case 0: /* No-op.  */
+        break;
+    case 1: /* Enable.  */
+        s->tx_enabled = 1;
+        mcf_uart_do_tx(s);
+        break;
+    case 2: /* Disable.  */
+        s->tx_enabled = 0;
+        mcf_uart_do_tx(s);
+        break;
+    case 3: /* Reserved.  */
+        fprintf(stderr, "mcf_uart: Bad TX command\n");
+        break;
+    }
+
+    /* Receiver command.  */
+    switch (cmd & 3) {
+    case 0: /* No-op.  */
+        break;
+    case 1: /* Enable.  */
+        s->rx_enabled = 1;
+        break;
+    case 2:
+        s->rx_enabled = 0;
+        break;
+    case 3: /* Reserved.  */
+        fprintf(stderr, "mcf_uart: Bad RX command\n");
+        break;
+    }
+}
+
+void mcf_uart_write(void *opaque, hwaddr addr,
+                    uint64_t val, unsigned size)
+{
+    mcf_uart_state *s = (mcf_uart_state *)opaque;
+    switch (addr & 0x3f) {
+    case 0x00:
+        s->mr[s->current_mr] = val;
+        s->current_mr = 1;
+        break;
+    case 0x04:
+        /* CSR is ignored.  */
+        break;
+    case 0x08: /* Command Register.  */
+        mcf_do_command(s, val);
+        break;
+    case 0x0c: /* Transmit Buffer.  */
+        s->sr &= ~MCF_UART_TxEMP;
+        s->tb = val;
+        mcf_uart_do_tx(s);
+        break;
+    case 0x10:
+        /* ACR is ignored.  */
+        break;
+    case 0x14:
+        s->imr = val;
+        break;
+    default:
+        break;
+    }
+    mcf_uart_update(s);
+}
+
+static void mcf_uart_reset(mcf_uart_state *s)
+{
+    s->fifo_len = 0;
+    s->mr[0] = 0;
+    s->mr[1] = 0;
+    s->sr = MCF_UART_TxEMP;
+    s->tx_enabled = 0;
+    s->rx_enabled = 0;
+    s->isr = 0;
+    s->imr = 0;
+}
+
+static void mcf_uart_push_byte(mcf_uart_state *s, uint8_t data)
+{
+    /* Break events overwrite the last byte if the fifo is full.  */
+    if (s->fifo_len == 4)
+        s->fifo_len--;
+
+    s->fifo[s->fifo_len] = data;
+    s->fifo_len++;
+    s->sr |= MCF_UART_RxRDY;
+    if (s->fifo_len == 4)
+        s->sr |= MCF_UART_FFULL;
+
+    mcf_uart_update(s);
+}
+
+static void mcf_uart_event(void *opaque, int event)
+{
+    mcf_uart_state *s = (mcf_uart_state *)opaque;
+
+    switch (event) {
+    case CHR_EVENT_BREAK:
+        s->isr |= MCF_UART_DBINT;
+        mcf_uart_push_byte(s, 0);
+        break;
+    default:
+        break;
+    }
+}
+
+static int mcf_uart_can_receive(void *opaque)
+{
+    mcf_uart_state *s = (mcf_uart_state *)opaque;
+
+    return s->rx_enabled && (s->sr & MCF_UART_FFULL) == 0;
+}
+
+static void mcf_uart_receive(void *opaque, const uint8_t *buf, int size)
+{
+    mcf_uart_state *s = (mcf_uart_state *)opaque;
+
+    mcf_uart_push_byte(s, buf[0]);
+}
+
+void *mcf_uart_init(qemu_irq irq, CharDriverState *chr)
+{
+    mcf_uart_state *s;
+
+    s = g_malloc0(sizeof(mcf_uart_state));
+    s->chr = chr;
+    s->irq = irq;
+    if (chr) {
+        qemu_chr_fe_claim_no_fail(chr);
+        qemu_chr_add_handlers(chr, mcf_uart_can_receive, mcf_uart_receive,
+                              mcf_uart_event, s);
+    }
+    mcf_uart_reset(s);
+    return s;
+}
+
+static const MemoryRegionOps mcf_uart_ops = {
+    .read = mcf_uart_read,
+    .write = mcf_uart_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+void mcf_uart_mm_init(MemoryRegion *sysmem,
+                      hwaddr base,
+                      qemu_irq irq,
+                      CharDriverState *chr)
+{
+    mcf_uart_state *s;
+
+    s = mcf_uart_init(irq, chr);
+    memory_region_init_io(&s->iomem, &mcf_uart_ops, s, "uart", 0x40);
+    memory_region_add_subregion(sysmem, base, &s->iomem);
+}
diff --git a/hw/char/milkymist-uart.c b/hw/char/milkymist-uart.c
new file mode 100644 (file)
index 0000000..f3bdf69
--- /dev/null
@@ -0,0 +1,244 @@
+/*
+ *  QEMU model of the Milkymist UART block.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
+ *
+ * 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/>.
+ *
+ *
+ * Specification available at:
+ *   http://www.milkymist.org/socdoc/uart.pdf
+ */
+
+#include "hw/hw.h"
+#include "hw/sysbus.h"
+#include "trace.h"
+#include "char/char.h"
+#include "qemu/error-report.h"
+
+enum {
+    R_RXTX = 0,
+    R_DIV,
+    R_STAT,
+    R_CTRL,
+    R_DBG,
+    R_MAX
+};
+
+enum {
+    STAT_THRE   = (1<<0),
+    STAT_RX_EVT = (1<<1),
+    STAT_TX_EVT = (1<<2),
+};
+
+enum {
+    CTRL_RX_IRQ_EN = (1<<0),
+    CTRL_TX_IRQ_EN = (1<<1),
+    CTRL_THRU_EN   = (1<<2),
+};
+
+enum {
+    DBG_BREAK_EN = (1<<0),
+};
+
+struct MilkymistUartState {
+    SysBusDevice busdev;
+    MemoryRegion regs_region;
+    CharDriverState *chr;
+    qemu_irq irq;
+
+    uint32_t regs[R_MAX];
+};
+typedef struct MilkymistUartState MilkymistUartState;
+
+static void uart_update_irq(MilkymistUartState *s)
+{
+    int rx_event = s->regs[R_STAT] & STAT_RX_EVT;
+    int tx_event = s->regs[R_STAT] & STAT_TX_EVT;
+    int rx_irq_en = s->regs[R_CTRL] & CTRL_RX_IRQ_EN;
+    int tx_irq_en = s->regs[R_CTRL] & CTRL_TX_IRQ_EN;
+
+    if ((rx_irq_en && rx_event) || (tx_irq_en && tx_event)) {
+        trace_milkymist_uart_raise_irq();
+        qemu_irq_raise(s->irq);
+    } else {
+        trace_milkymist_uart_lower_irq();
+        qemu_irq_lower(s->irq);
+    }
+}
+
+static uint64_t uart_read(void *opaque, hwaddr addr,
+                          unsigned size)
+{
+    MilkymistUartState *s = opaque;
+    uint32_t r = 0;
+
+    addr >>= 2;
+    switch (addr) {
+    case R_RXTX:
+        r = s->regs[addr];
+        break;
+    case R_DIV:
+    case R_STAT:
+    case R_CTRL:
+    case R_DBG:
+        r = s->regs[addr];
+        break;
+
+    default:
+        error_report("milkymist_uart: read access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+
+    trace_milkymist_uart_memory_read(addr << 2, r);
+
+    return r;
+}
+
+static void uart_write(void *opaque, hwaddr addr, uint64_t value,
+                       unsigned size)
+{
+    MilkymistUartState *s = opaque;
+    unsigned char ch = value;
+
+    trace_milkymist_uart_memory_write(addr, value);
+
+    addr >>= 2;
+    switch (addr) {
+    case R_RXTX:
+        if (s->chr) {
+            qemu_chr_fe_write(s->chr, &ch, 1);
+        }
+        s->regs[R_STAT] |= STAT_TX_EVT;
+        break;
+    case R_DIV:
+    case R_CTRL:
+    case R_DBG:
+        s->regs[addr] = value;
+        break;
+
+    case R_STAT:
+        /* write one to clear bits */
+        s->regs[addr] &= ~(value & (STAT_RX_EVT | STAT_TX_EVT));
+        qemu_chr_accept_input(s->chr);
+        break;
+
+    default:
+        error_report("milkymist_uart: write access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+
+    uart_update_irq(s);
+}
+
+static const MemoryRegionOps uart_mmio_ops = {
+    .read = uart_read,
+    .write = uart_write,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void uart_rx(void *opaque, const uint8_t *buf, int size)
+{
+    MilkymistUartState *s = opaque;
+
+    assert(!(s->regs[R_STAT] & STAT_RX_EVT));
+
+    s->regs[R_STAT] |= STAT_RX_EVT;
+    s->regs[R_RXTX] = *buf;
+
+    uart_update_irq(s);
+}
+
+static int uart_can_rx(void *opaque)
+{
+    MilkymistUartState *s = opaque;
+
+    return !(s->regs[R_STAT] & STAT_RX_EVT);
+}
+
+static void uart_event(void *opaque, int event)
+{
+}
+
+static void milkymist_uart_reset(DeviceState *d)
+{
+    MilkymistUartState *s = container_of(d, MilkymistUartState, busdev.qdev);
+    int i;
+
+    for (i = 0; i < R_MAX; i++) {
+        s->regs[i] = 0;
+    }
+
+    /* THRE is always set */
+    s->regs[R_STAT] = STAT_THRE;
+}
+
+static int milkymist_uart_init(SysBusDevice *dev)
+{
+    MilkymistUartState *s = FROM_SYSBUS(typeof(*s), dev);
+
+    sysbus_init_irq(dev, &s->irq);
+
+    memory_region_init_io(&s->regs_region, &uart_mmio_ops, s,
+            "milkymist-uart", R_MAX * 4);
+    sysbus_init_mmio(dev, &s->regs_region);
+
+    s->chr = qemu_char_get_next_serial();
+    if (s->chr) {
+        qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s);
+    }
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_milkymist_uart = {
+    .name = "milkymist-uart",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(regs, MilkymistUartState, R_MAX),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+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 const 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_types(void)
+{
+    type_register_static(&milkymist_uart_info);
+}
+
+type_init(milkymist_uart_register_types)
diff --git a/hw/char/omap_uart.c b/hw/char/omap_uart.c
new file mode 100644 (file)
index 0000000..26c1426
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * TI OMAP processors UART emulation.
+ *
+ * Copyright (C) 2006-2008 Andrzej Zaborowski  <balrog@zabor.org>
+ * Copyright (C) 2007-2009 Nokia Corporation
+ *
+ * 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 or
+ * (at your option) version 3 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
+ * 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 "char/char.h"
+#include "hw/hw.h"
+#include "hw/arm/omap.h"
+#include "hw/char/serial.h"
+#include "exec/address-spaces.h"
+
+/* UARTs */
+struct omap_uart_s {
+    MemoryRegion iomem;
+    hwaddr base;
+    SerialState *serial; /* TODO */
+    struct omap_target_agent_s *ta;
+    omap_clk fclk;
+    qemu_irq irq;
+
+    uint8_t eblr;
+    uint8_t syscontrol;
+    uint8_t wkup;
+    uint8_t cfps;
+    uint8_t mdr[2];
+    uint8_t scr;
+    uint8_t clksel;
+};
+
+void omap_uart_reset(struct omap_uart_s *s)
+{
+    s->eblr = 0x00;
+    s->syscontrol = 0;
+    s->wkup = 0x3f;
+    s->cfps = 0x69;
+    s->clksel = 0;
+}
+
+struct omap_uart_s *omap_uart_init(hwaddr base,
+                qemu_irq irq, omap_clk fclk, omap_clk iclk,
+                qemu_irq txdma, qemu_irq rxdma,
+                const char *label, CharDriverState *chr)
+{
+    struct omap_uart_s *s = (struct omap_uart_s *)
+            g_malloc0(sizeof(struct omap_uart_s));
+
+    s->base = base;
+    s->fclk = fclk;
+    s->irq = irq;
+    s->serial = serial_mm_init(get_system_memory(), base, 2, irq,
+                               omap_clk_getrate(fclk)/16,
+                               chr ?: qemu_chr_new(label, "null", NULL),
+                               DEVICE_NATIVE_ENDIAN);
+    return s;
+}
+
+static uint64_t omap_uart_read(void *opaque, hwaddr addr,
+                               unsigned size)
+{
+    struct omap_uart_s *s = (struct omap_uart_s *) opaque;
+
+    if (size == 4) {
+        return omap_badwidth_read8(opaque, addr);
+    }
+
+    switch (addr) {
+    case 0x20: /* MDR1 */
+        return s->mdr[0];
+    case 0x24: /* MDR2 */
+        return s->mdr[1];
+    case 0x40: /* SCR */
+        return s->scr;
+    case 0x44: /* SSR */
+        return 0x0;
+    case 0x48: /* EBLR (OMAP2) */
+        return s->eblr;
+    case 0x4C: /* OSC_12M_SEL (OMAP1) */
+        return s->clksel;
+    case 0x50: /* MVR */
+        return 0x30;
+    case 0x54: /* SYSC (OMAP2) */
+        return s->syscontrol;
+    case 0x58: /* SYSS (OMAP2) */
+        return 1;
+    case 0x5c: /* WER (OMAP2) */
+        return s->wkup;
+    case 0x60: /* CFPS (OMAP2) */
+        return s->cfps;
+    }
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_uart_write(void *opaque, hwaddr addr,
+                            uint64_t value, unsigned size)
+{
+    struct omap_uart_s *s = (struct omap_uart_s *) opaque;
+
+    if (size == 4) {
+        return omap_badwidth_write8(opaque, addr, value);
+    }
+
+    switch (addr) {
+    case 0x20: /* MDR1 */
+        s->mdr[0] = value & 0x7f;
+        break;
+    case 0x24: /* MDR2 */
+        s->mdr[1] = value & 0xff;
+        break;
+    case 0x40: /* SCR */
+        s->scr = value & 0xff;
+        break;
+    case 0x48: /* EBLR (OMAP2) */
+        s->eblr = value & 0xff;
+        break;
+    case 0x4C: /* OSC_12M_SEL (OMAP1) */
+        s->clksel = value & 1;
+        break;
+    case 0x44: /* SSR */
+    case 0x50: /* MVR */
+    case 0x58: /* SYSS (OMAP2) */
+        OMAP_RO_REG(addr);
+        break;
+    case 0x54: /* SYSC (OMAP2) */
+        s->syscontrol = value & 0x1d;
+        if (value & 2)
+            omap_uart_reset(s);
+        break;
+    case 0x5c: /* WER (OMAP2) */
+        s->wkup = value & 0x7f;
+        break;
+    case 0x60: /* CFPS (OMAP2) */
+        s->cfps = value & 0xff;
+        break;
+    default:
+        OMAP_BAD_REG(addr);
+    }
+}
+
+static const MemoryRegionOps omap_uart_ops = {
+    .read = omap_uart_read,
+    .write = omap_uart_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+struct omap_uart_s *omap2_uart_init(MemoryRegion *sysmem,
+                struct omap_target_agent_s *ta,
+                qemu_irq irq, omap_clk fclk, omap_clk iclk,
+                qemu_irq txdma, qemu_irq rxdma,
+                const char *label, CharDriverState *chr)
+{
+    hwaddr base = omap_l4_attach(ta, 0, NULL);
+    struct omap_uart_s *s = omap_uart_init(base, irq,
+                    fclk, iclk, txdma, rxdma, label, chr);
+
+    memory_region_init_io(&s->iomem, &omap_uart_ops, s, "omap.uart", 0x100);
+
+    s->ta = ta;
+
+    memory_region_add_subregion(sysmem, base + 0x20, &s->iomem);
+
+    return s;
+}
+
+void omap_uart_attach(struct omap_uart_s *s, CharDriverState *chr)
+{
+    /* TODO: Should reuse or destroy current s->serial */
+    s->serial = serial_mm_init(get_system_memory(), s->base, 2, s->irq,
+                               omap_clk_getrate(s->fclk) / 16,
+                               chr ?: qemu_chr_new("null", "null", NULL),
+                               DEVICE_NATIVE_ENDIAN);
+}
diff --git a/hw/char/parallel.c b/hw/char/parallel.c
new file mode 100644 (file)
index 0000000..863a6fb
--- /dev/null
@@ -0,0 +1,614 @@
+/*
+ * QEMU Parallel PORT emulation
+ *
+ * Copyright (c) 2003-2005 Fabrice Bellard
+ * Copyright (c) 2007 Marko Kohtala
+ *
+ * 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 "hw/hw.h"
+#include "char/char.h"
+#include "hw/isa/isa.h"
+#include "hw/i386/pc.h"
+#include "sysemu/sysemu.h"
+
+//#define DEBUG_PARALLEL
+
+#ifdef DEBUG_PARALLEL
+#define pdebug(fmt, ...) printf("pp: " fmt, ## __VA_ARGS__)
+#else
+#define pdebug(fmt, ...) ((void)0)
+#endif
+
+#define PARA_REG_DATA 0
+#define PARA_REG_STS 1
+#define PARA_REG_CTR 2
+#define PARA_REG_EPP_ADDR 3
+#define PARA_REG_EPP_DATA 4
+
+/*
+ * These are the definitions for the Printer Status Register
+ */
+#define PARA_STS_BUSY  0x80    /* Busy complement */
+#define PARA_STS_ACK   0x40    /* Acknowledge */
+#define PARA_STS_PAPER 0x20    /* Out of paper */
+#define PARA_STS_ONLINE        0x10    /* Online */
+#define PARA_STS_ERROR 0x08    /* Error complement */
+#define PARA_STS_TMOUT 0x01    /* EPP timeout */
+
+/*
+ * These are the definitions for the Printer Control Register
+ */
+#define PARA_CTR_DIR   0x20    /* Direction (1=read, 0=write) */
+#define PARA_CTR_INTEN 0x10    /* IRQ Enable */
+#define PARA_CTR_SELECT        0x08    /* Select In complement */
+#define PARA_CTR_INIT  0x04    /* Initialize Printer complement */
+#define PARA_CTR_AUTOLF        0x02    /* Auto linefeed complement */
+#define PARA_CTR_STROBE        0x01    /* Strobe complement */
+
+#define PARA_CTR_SIGNAL (PARA_CTR_SELECT|PARA_CTR_INIT|PARA_CTR_AUTOLF|PARA_CTR_STROBE)
+
+typedef struct ParallelState {
+    MemoryRegion iomem;
+    uint8_t dataw;
+    uint8_t datar;
+    uint8_t status;
+    uint8_t control;
+    qemu_irq irq;
+    int irq_pending;
+    CharDriverState *chr;
+    int hw_driver;
+    int epp_timeout;
+    uint32_t last_read_offset; /* For debugging */
+    /* Memory-mapped interface */
+    int it_shift;
+} ParallelState;
+
+typedef struct ISAParallelState {
+    ISADevice dev;
+    uint32_t index;
+    uint32_t iobase;
+    uint32_t isairq;
+    ParallelState state;
+} ISAParallelState;
+
+static void parallel_update_irq(ParallelState *s)
+{
+    if (s->irq_pending)
+        qemu_irq_raise(s->irq);
+    else
+        qemu_irq_lower(s->irq);
+}
+
+static void
+parallel_ioport_write_sw(void *opaque, uint32_t addr, uint32_t val)
+{
+    ParallelState *s = opaque;
+
+    pdebug("write addr=0x%02x val=0x%02x\n", addr, val);
+
+    addr &= 7;
+    switch(addr) {
+    case PARA_REG_DATA:
+        s->dataw = val;
+        parallel_update_irq(s);
+        break;
+    case PARA_REG_CTR:
+        val |= 0xc0;
+        if ((val & PARA_CTR_INIT) == 0 ) {
+            s->status = PARA_STS_BUSY;
+            s->status |= PARA_STS_ACK;
+            s->status |= PARA_STS_ONLINE;
+            s->status |= PARA_STS_ERROR;
+        }
+        else if (val & PARA_CTR_SELECT) {
+            if (val & PARA_CTR_STROBE) {
+                s->status &= ~PARA_STS_BUSY;
+                if ((s->control & PARA_CTR_STROBE) == 0)
+                    qemu_chr_fe_write(s->chr, &s->dataw, 1);
+            } else {
+                if (s->control & PARA_CTR_INTEN) {
+                    s->irq_pending = 1;
+                }
+            }
+        }
+        parallel_update_irq(s);
+        s->control = val;
+        break;
+    }
+}
+
+static void parallel_ioport_write_hw(void *opaque, uint32_t addr, uint32_t val)
+{
+    ParallelState *s = opaque;
+    uint8_t parm = val;
+    int dir;
+
+    /* Sometimes programs do several writes for timing purposes on old
+       HW. Take care not to waste time on writes that do nothing. */
+
+    s->last_read_offset = ~0U;
+
+    addr &= 7;
+    switch(addr) {
+    case PARA_REG_DATA:
+        if (s->dataw == val)
+            return;
+        pdebug("wd%02x\n", val);
+        qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_WRITE_DATA, &parm);
+        s->dataw = val;
+        break;
+    case PARA_REG_STS:
+        pdebug("ws%02x\n", val);
+        if (val & PARA_STS_TMOUT)
+            s->epp_timeout = 0;
+        break;
+    case PARA_REG_CTR:
+        val |= 0xc0;
+        if (s->control == val)
+            return;
+        pdebug("wc%02x\n", val);
+
+        if ((val & PARA_CTR_DIR) != (s->control & PARA_CTR_DIR)) {
+            if (val & PARA_CTR_DIR) {
+                dir = 1;
+            } else {
+                dir = 0;
+            }
+            qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_DATA_DIR, &dir);
+            parm &= ~PARA_CTR_DIR;
+        }
+
+        qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_WRITE_CONTROL, &parm);
+        s->control = val;
+        break;
+    case PARA_REG_EPP_ADDR:
+        if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != PARA_CTR_INIT)
+            /* Controls not correct for EPP address cycle, so do nothing */
+            pdebug("wa%02x s\n", val);
+        else {
+            struct ParallelIOArg ioarg = { .buffer = &parm, .count = 1 };
+            if (qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_EPP_WRITE_ADDR, &ioarg)) {
+                s->epp_timeout = 1;
+                pdebug("wa%02x t\n", val);
+            }
+            else
+                pdebug("wa%02x\n", val);
+        }
+        break;
+    case PARA_REG_EPP_DATA:
+        if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != PARA_CTR_INIT)
+            /* Controls not correct for EPP data cycle, so do nothing */
+            pdebug("we%02x s\n", val);
+        else {
+            struct ParallelIOArg ioarg = { .buffer = &parm, .count = 1 };
+            if (qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_EPP_WRITE, &ioarg)) {
+                s->epp_timeout = 1;
+                pdebug("we%02x t\n", val);
+            }
+            else
+                pdebug("we%02x\n", val);
+        }
+        break;
+    }
+}
+
+static void
+parallel_ioport_eppdata_write_hw2(void *opaque, uint32_t addr, uint32_t val)
+{
+    ParallelState *s = opaque;
+    uint16_t eppdata = cpu_to_le16(val);
+    int err;
+    struct ParallelIOArg ioarg = {
+        .buffer = &eppdata, .count = sizeof(eppdata)
+    };
+    if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != PARA_CTR_INIT) {
+        /* Controls not correct for EPP data cycle, so do nothing */
+        pdebug("we%04x s\n", val);
+        return;
+    }
+    err = qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_EPP_WRITE, &ioarg);
+    if (err) {
+        s->epp_timeout = 1;
+        pdebug("we%04x t\n", val);
+    }
+    else
+        pdebug("we%04x\n", val);
+}
+
+static void
+parallel_ioport_eppdata_write_hw4(void *opaque, uint32_t addr, uint32_t val)
+{
+    ParallelState *s = opaque;
+    uint32_t eppdata = cpu_to_le32(val);
+    int err;
+    struct ParallelIOArg ioarg = {
+        .buffer = &eppdata, .count = sizeof(eppdata)
+    };
+    if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != PARA_CTR_INIT) {
+        /* Controls not correct for EPP data cycle, so do nothing */
+        pdebug("we%08x s\n", val);
+        return;
+    }
+    err = qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_EPP_WRITE, &ioarg);
+    if (err) {
+        s->epp_timeout = 1;
+        pdebug("we%08x t\n", val);
+    }
+    else
+        pdebug("we%08x\n", val);
+}
+
+static uint32_t parallel_ioport_read_sw(void *opaque, uint32_t addr)
+{
+    ParallelState *s = opaque;
+    uint32_t ret = 0xff;
+
+    addr &= 7;
+    switch(addr) {
+    case PARA_REG_DATA:
+        if (s->control & PARA_CTR_DIR)
+            ret = s->datar;
+        else
+            ret = s->dataw;
+        break;
+    case PARA_REG_STS:
+        ret = s->status;
+        s->irq_pending = 0;
+        if ((s->status & PARA_STS_BUSY) == 0 && (s->control & PARA_CTR_STROBE) == 0) {
+            /* XXX Fixme: wait 5 microseconds */
+            if (s->status & PARA_STS_ACK)
+                s->status &= ~PARA_STS_ACK;
+            else {
+                /* XXX Fixme: wait 5 microseconds */
+                s->status |= PARA_STS_ACK;
+                s->status |= PARA_STS_BUSY;
+            }
+        }
+        parallel_update_irq(s);
+        break;
+    case PARA_REG_CTR:
+        ret = s->control;
+        break;
+    }
+    pdebug("read addr=0x%02x val=0x%02x\n", addr, ret);
+    return ret;
+}
+
+static uint32_t parallel_ioport_read_hw(void *opaque, uint32_t addr)
+{
+    ParallelState *s = opaque;
+    uint8_t ret = 0xff;
+    addr &= 7;
+    switch(addr) {
+    case PARA_REG_DATA:
+        qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_READ_DATA, &ret);
+        if (s->last_read_offset != addr || s->datar != ret)
+            pdebug("rd%02x\n", ret);
+        s->datar = ret;
+        break;
+    case PARA_REG_STS:
+        qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_READ_STATUS, &ret);
+        ret &= ~PARA_STS_TMOUT;
+        if (s->epp_timeout)
+            ret |= PARA_STS_TMOUT;
+        if (s->last_read_offset != addr || s->status != ret)
+            pdebug("rs%02x\n", ret);
+        s->status = ret;
+        break;
+    case PARA_REG_CTR:
+        /* s->control has some bits fixed to 1. It is zero only when
+           it has not been yet written to.  */
+        if (s->control == 0) {
+            qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_READ_CONTROL, &ret);
+            if (s->last_read_offset != addr)
+                pdebug("rc%02x\n", ret);
+            s->control = ret;
+        }
+        else {
+            ret = s->control;
+            if (s->last_read_offset != addr)
+                pdebug("rc%02x\n", ret);
+        }
+        break;
+    case PARA_REG_EPP_ADDR:
+        if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != (PARA_CTR_DIR|PARA_CTR_INIT))
+            /* Controls not correct for EPP addr cycle, so do nothing */
+            pdebug("ra%02x s\n", ret);
+        else {
+            struct ParallelIOArg ioarg = { .buffer = &ret, .count = 1 };
+            if (qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_EPP_READ_ADDR, &ioarg)) {
+                s->epp_timeout = 1;
+                pdebug("ra%02x t\n", ret);
+            }
+            else
+                pdebug("ra%02x\n", ret);
+        }
+        break;
+    case PARA_REG_EPP_DATA:
+        if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != (PARA_CTR_DIR|PARA_CTR_INIT))
+            /* Controls not correct for EPP data cycle, so do nothing */
+            pdebug("re%02x s\n", ret);
+        else {
+            struct ParallelIOArg ioarg = { .buffer = &ret, .count = 1 };
+            if (qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_EPP_READ, &ioarg)) {
+                s->epp_timeout = 1;
+                pdebug("re%02x t\n", ret);
+            }
+            else
+                pdebug("re%02x\n", ret);
+        }
+        break;
+    }
+    s->last_read_offset = addr;
+    return ret;
+}
+
+static uint32_t
+parallel_ioport_eppdata_read_hw2(void *opaque, uint32_t addr)
+{
+    ParallelState *s = opaque;
+    uint32_t ret;
+    uint16_t eppdata = ~0;
+    int err;
+    struct ParallelIOArg ioarg = {
+        .buffer = &eppdata, .count = sizeof(eppdata)
+    };
+    if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != (PARA_CTR_DIR|PARA_CTR_INIT)) {
+        /* Controls not correct for EPP data cycle, so do nothing */
+        pdebug("re%04x s\n", eppdata);
+        return eppdata;
+    }
+    err = qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_EPP_READ, &ioarg);
+    ret = le16_to_cpu(eppdata);
+
+    if (err) {
+        s->epp_timeout = 1;
+        pdebug("re%04x t\n", ret);
+    }
+    else
+        pdebug("re%04x\n", ret);
+    return ret;
+}
+
+static uint32_t
+parallel_ioport_eppdata_read_hw4(void *opaque, uint32_t addr)
+{
+    ParallelState *s = opaque;
+    uint32_t ret;
+    uint32_t eppdata = ~0U;
+    int err;
+    struct ParallelIOArg ioarg = {
+        .buffer = &eppdata, .count = sizeof(eppdata)
+    };
+    if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != (PARA_CTR_DIR|PARA_CTR_INIT)) {
+        /* Controls not correct for EPP data cycle, so do nothing */
+        pdebug("re%08x s\n", eppdata);
+        return eppdata;
+    }
+    err = qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_EPP_READ, &ioarg);
+    ret = le32_to_cpu(eppdata);
+
+    if (err) {
+        s->epp_timeout = 1;
+        pdebug("re%08x t\n", ret);
+    }
+    else
+        pdebug("re%08x\n", ret);
+    return ret;
+}
+
+static void parallel_ioport_ecp_write(void *opaque, uint32_t addr, uint32_t val)
+{
+    pdebug("wecp%d=%02x\n", addr & 7, val);
+}
+
+static uint32_t parallel_ioport_ecp_read(void *opaque, uint32_t addr)
+{
+    uint8_t ret = 0xff;
+
+    pdebug("recp%d:%02x\n", addr & 7, ret);
+    return ret;
+}
+
+static void parallel_reset(void *opaque)
+{
+    ParallelState *s = opaque;
+
+    s->datar = ~0;
+    s->dataw = ~0;
+    s->status = PARA_STS_BUSY;
+    s->status |= PARA_STS_ACK;
+    s->status |= PARA_STS_ONLINE;
+    s->status |= PARA_STS_ERROR;
+    s->status |= PARA_STS_TMOUT;
+    s->control = PARA_CTR_SELECT;
+    s->control |= PARA_CTR_INIT;
+    s->control |= 0xc0;
+    s->irq_pending = 0;
+    s->hw_driver = 0;
+    s->epp_timeout = 0;
+    s->last_read_offset = ~0U;
+}
+
+static const int isa_parallel_io[MAX_PARALLEL_PORTS] = { 0x378, 0x278, 0x3bc };
+
+static const MemoryRegionPortio isa_parallel_portio_hw_list[] = {
+    { 0, 8, 1,
+      .read = parallel_ioport_read_hw,
+      .write = parallel_ioport_write_hw },
+    { 4, 1, 2,
+      .read = parallel_ioport_eppdata_read_hw2,
+      .write = parallel_ioport_eppdata_write_hw2 },
+    { 4, 1, 4,
+      .read = parallel_ioport_eppdata_read_hw4,
+      .write = parallel_ioport_eppdata_write_hw4 },
+    { 0x400, 8, 1,
+      .read = parallel_ioport_ecp_read,
+      .write = parallel_ioport_ecp_write },
+    PORTIO_END_OF_LIST(),
+};
+
+static const MemoryRegionPortio isa_parallel_portio_sw_list[] = {
+    { 0, 8, 1,
+      .read = parallel_ioport_read_sw,
+      .write = parallel_ioport_write_sw },
+    PORTIO_END_OF_LIST(),
+};
+
+static int parallel_isa_initfn(ISADevice *dev)
+{
+    static int index;
+    ISAParallelState *isa = DO_UPCAST(ISAParallelState, dev, dev);
+    ParallelState *s = &isa->state;
+    int base;
+    uint8_t dummy;
+
+    if (!s->chr) {
+        fprintf(stderr, "Can't create parallel device, empty char device\n");
+        exit(1);
+    }
+
+    if (isa->index == -1)
+        isa->index = index;
+    if (isa->index >= MAX_PARALLEL_PORTS)
+        return -1;
+    if (isa->iobase == -1)
+        isa->iobase = isa_parallel_io[isa->index];
+    index++;
+
+    base = isa->iobase;
+    isa_init_irq(dev, &s->irq, isa->isairq);
+    qemu_register_reset(parallel_reset, s);
+
+    if (qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_READ_STATUS, &dummy) == 0) {
+        s->hw_driver = 1;
+        s->status = dummy;
+    }
+
+    isa_register_portio_list(dev, base,
+                             (s->hw_driver
+                              ? &isa_parallel_portio_hw_list[0]
+                              : &isa_parallel_portio_sw_list[0]),
+                             s, "parallel");
+    return 0;
+}
+
+/* Memory mapped interface */
+static uint32_t parallel_mm_readb (void *opaque, hwaddr addr)
+{
+    ParallelState *s = opaque;
+
+    return parallel_ioport_read_sw(s, addr >> s->it_shift) & 0xFF;
+}
+
+static void parallel_mm_writeb (void *opaque,
+                                hwaddr addr, uint32_t value)
+{
+    ParallelState *s = opaque;
+
+    parallel_ioport_write_sw(s, addr >> s->it_shift, value & 0xFF);
+}
+
+static uint32_t parallel_mm_readw (void *opaque, hwaddr addr)
+{
+    ParallelState *s = opaque;
+
+    return parallel_ioport_read_sw(s, addr >> s->it_shift) & 0xFFFF;
+}
+
+static void parallel_mm_writew (void *opaque,
+                                hwaddr addr, uint32_t value)
+{
+    ParallelState *s = opaque;
+
+    parallel_ioport_write_sw(s, addr >> s->it_shift, value & 0xFFFF);
+}
+
+static uint32_t parallel_mm_readl (void *opaque, hwaddr addr)
+{
+    ParallelState *s = opaque;
+
+    return parallel_ioport_read_sw(s, addr >> s->it_shift);
+}
+
+static void parallel_mm_writel (void *opaque,
+                                hwaddr addr, uint32_t value)
+{
+    ParallelState *s = opaque;
+
+    parallel_ioport_write_sw(s, addr >> s->it_shift, value);
+}
+
+static const MemoryRegionOps parallel_mm_ops = {
+    .old_mmio = {
+        .read = { parallel_mm_readb, parallel_mm_readw, parallel_mm_readl },
+        .write = { parallel_mm_writeb, parallel_mm_writew, parallel_mm_writel },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+/* If fd is zero, it means that the parallel device uses the console */
+bool parallel_mm_init(MemoryRegion *address_space,
+                      hwaddr base, int it_shift, qemu_irq irq,
+                      CharDriverState *chr)
+{
+    ParallelState *s;
+
+    s = g_malloc0(sizeof(ParallelState));
+    s->irq = irq;
+    s->chr = chr;
+    s->it_shift = it_shift;
+    qemu_register_reset(parallel_reset, s);
+
+    memory_region_init_io(&s->iomem, &parallel_mm_ops, s,
+                          "parallel", 8 << it_shift);
+    memory_region_add_subregion(address_space, base, &s->iomem);
+    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 const 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_types(void)
+{
+    type_register_static(&parallel_isa_info);
+}
+
+type_init(parallel_register_types)
diff --git a/hw/char/pl011.c b/hw/char/pl011.c
new file mode 100644 (file)
index 0000000..332d5b9
--- /dev/null
@@ -0,0 +1,330 @@
+/*
+ * Arm PrimeCell PL011 UART
+ *
+ * Copyright (c) 2006 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the GPL.
+ */
+
+#include "hw/sysbus.h"
+#include "char/char.h"
+
+typedef struct {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    uint32_t readbuff;
+    uint32_t flags;
+    uint32_t lcr;
+    uint32_t cr;
+    uint32_t dmacr;
+    uint32_t int_enabled;
+    uint32_t int_level;
+    uint32_t read_fifo[16];
+    uint32_t ilpr;
+    uint32_t ibrd;
+    uint32_t fbrd;
+    uint32_t ifl;
+    int read_pos;
+    int read_count;
+    int read_trigger;
+    CharDriverState *chr;
+    qemu_irq irq;
+    const unsigned char *id;
+} pl011_state;
+
+#define PL011_INT_TX 0x20
+#define PL011_INT_RX 0x10
+
+#define PL011_FLAG_TXFE 0x80
+#define PL011_FLAG_RXFF 0x40
+#define PL011_FLAG_TXFF 0x20
+#define PL011_FLAG_RXFE 0x10
+
+static const unsigned char pl011_id_arm[8] =
+  { 0x11, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
+static const unsigned char pl011_id_luminary[8] =
+  { 0x11, 0x00, 0x18, 0x01, 0x0d, 0xf0, 0x05, 0xb1 };
+
+static void pl011_update(pl011_state *s)
+{
+    uint32_t flags;
+
+    flags = s->int_level & s->int_enabled;
+    qemu_set_irq(s->irq, flags != 0);
+}
+
+static uint64_t pl011_read(void *opaque, hwaddr offset,
+                           unsigned size)
+{
+    pl011_state *s = (pl011_state *)opaque;
+    uint32_t c;
+
+    if (offset >= 0xfe0 && offset < 0x1000) {
+        return s->id[(offset - 0xfe0) >> 2];
+    }
+    switch (offset >> 2) {
+    case 0: /* UARTDR */
+        s->flags &= ~PL011_FLAG_RXFF;
+        c = s->read_fifo[s->read_pos];
+        if (s->read_count > 0) {
+            s->read_count--;
+            if (++s->read_pos == 16)
+                s->read_pos = 0;
+        }
+        if (s->read_count == 0) {
+            s->flags |= PL011_FLAG_RXFE;
+        }
+        if (s->read_count == s->read_trigger - 1)
+            s->int_level &= ~ PL011_INT_RX;
+        pl011_update(s);
+        if (s->chr) {
+            qemu_chr_accept_input(s->chr);
+        }
+        return c;
+    case 1: /* UARTCR */
+        return 0;
+    case 6: /* UARTFR */
+        return s->flags;
+    case 8: /* UARTILPR */
+        return s->ilpr;
+    case 9: /* UARTIBRD */
+        return s->ibrd;
+    case 10: /* UARTFBRD */
+        return s->fbrd;
+    case 11: /* UARTLCR_H */
+        return s->lcr;
+    case 12: /* UARTCR */
+        return s->cr;
+    case 13: /* UARTIFLS */
+        return s->ifl;
+    case 14: /* UARTIMSC */
+        return s->int_enabled;
+    case 15: /* UARTRIS */
+        return s->int_level;
+    case 16: /* UARTMIS */
+        return s->int_level & s->int_enabled;
+    case 18: /* UARTDMACR */
+        return s->dmacr;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "pl011_read: Bad offset %x\n", (int)offset);
+        return 0;
+    }
+}
+
+static void pl011_set_read_trigger(pl011_state *s)
+{
+#if 0
+    /* The docs say the RX interrupt is triggered when the FIFO exceeds
+       the threshold.  However linux only reads the FIFO in response to an
+       interrupt.  Triggering the interrupt when the FIFO is non-empty seems
+       to make things work.  */
+    if (s->lcr & 0x10)
+        s->read_trigger = (s->ifl >> 1) & 0x1c;
+    else
+#endif
+        s->read_trigger = 1;
+}
+
+static void pl011_write(void *opaque, hwaddr offset,
+                        uint64_t value, unsigned size)
+{
+    pl011_state *s = (pl011_state *)opaque;
+    unsigned char ch;
+
+    switch (offset >> 2) {
+    case 0: /* UARTDR */
+        /* ??? Check if transmitter is enabled.  */
+        ch = value;
+        if (s->chr)
+            qemu_chr_fe_write(s->chr, &ch, 1);
+        s->int_level |= PL011_INT_TX;
+        pl011_update(s);
+        break;
+    case 1: /* UARTCR */
+        s->cr = value;
+        break;
+    case 6: /* UARTFR */
+        /* Writes to Flag register are ignored.  */
+        break;
+    case 8: /* UARTUARTILPR */
+        s->ilpr = value;
+        break;
+    case 9: /* UARTIBRD */
+        s->ibrd = value;
+        break;
+    case 10: /* UARTFBRD */
+        s->fbrd = value;
+        break;
+    case 11: /* UARTLCR_H */
+        s->lcr = value;
+        pl011_set_read_trigger(s);
+        break;
+    case 12: /* UARTCR */
+        /* ??? Need to implement the enable and loopback bits.  */
+        s->cr = value;
+        break;
+    case 13: /* UARTIFS */
+        s->ifl = value;
+        pl011_set_read_trigger(s);
+        break;
+    case 14: /* UARTIMSC */
+        s->int_enabled = value;
+        pl011_update(s);
+        break;
+    case 17: /* UARTICR */
+        s->int_level &= ~value;
+        pl011_update(s);
+        break;
+    case 18: /* UARTDMACR */
+        s->dmacr = value;
+        if (value & 3) {
+            qemu_log_mask(LOG_UNIMP, "pl011: DMA not implemented\n");
+        }
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "pl011_write: Bad offset %x\n", (int)offset);
+    }
+}
+
+static int pl011_can_receive(void *opaque)
+{
+    pl011_state *s = (pl011_state *)opaque;
+
+    if (s->lcr & 0x10)
+        return s->read_count < 16;
+    else
+        return s->read_count < 1;
+}
+
+static void pl011_put_fifo(void *opaque, uint32_t value)
+{
+    pl011_state *s = (pl011_state *)opaque;
+    int slot;
+
+    slot = s->read_pos + s->read_count;
+    if (slot >= 16)
+        slot -= 16;
+    s->read_fifo[slot] = value;
+    s->read_count++;
+    s->flags &= ~PL011_FLAG_RXFE;
+    if (s->cr & 0x10 || s->read_count == 16) {
+        s->flags |= PL011_FLAG_RXFF;
+    }
+    if (s->read_count == s->read_trigger) {
+        s->int_level |= PL011_INT_RX;
+        pl011_update(s);
+    }
+}
+
+static void pl011_receive(void *opaque, const uint8_t *buf, int size)
+{
+    pl011_put_fifo(opaque, *buf);
+}
+
+static void pl011_event(void *opaque, int event)
+{
+    if (event == CHR_EVENT_BREAK)
+        pl011_put_fifo(opaque, 0x400);
+}
+
+static const MemoryRegionOps pl011_ops = {
+    .read = pl011_read,
+    .write = pl011_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static const VMStateDescription vmstate_pl011 = {
+    .name = "pl011",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32(readbuff, pl011_state),
+        VMSTATE_UINT32(flags, pl011_state),
+        VMSTATE_UINT32(lcr, pl011_state),
+        VMSTATE_UINT32(cr, pl011_state),
+        VMSTATE_UINT32(dmacr, pl011_state),
+        VMSTATE_UINT32(int_enabled, pl011_state),
+        VMSTATE_UINT32(int_level, pl011_state),
+        VMSTATE_UINT32_ARRAY(read_fifo, pl011_state, 16),
+        VMSTATE_UINT32(ilpr, pl011_state),
+        VMSTATE_UINT32(ibrd, pl011_state),
+        VMSTATE_UINT32(fbrd, pl011_state),
+        VMSTATE_UINT32(ifl, pl011_state),
+        VMSTATE_INT32(read_pos, pl011_state),
+        VMSTATE_INT32(read_count, pl011_state),
+        VMSTATE_INT32(read_trigger, pl011_state),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int pl011_init(SysBusDevice *dev, const unsigned char *id)
+{
+    pl011_state *s = FROM_SYSBUS(pl011_state, dev);
+
+    memory_region_init_io(&s->iomem, &pl011_ops, s, "pl011", 0x1000);
+    sysbus_init_mmio(dev, &s->iomem);
+    sysbus_init_irq(dev, &s->irq);
+    s->id = id;
+    s->chr = qemu_char_get_next_serial();
+
+    s->read_trigger = 1;
+    s->ifl = 0x12;
+    s->cr = 0x300;
+    s->flags = 0x90;
+    if (s->chr) {
+        qemu_chr_add_handlers(s->chr, pl011_can_receive, pl011_receive,
+                              pl011_event, s);
+    }
+    vmstate_register(&dev->qdev, -1, &vmstate_pl011, s);
+    return 0;
+}
+
+static int pl011_arm_init(SysBusDevice *dev)
+{
+    return pl011_init(dev, pl011_id_arm);
+}
+
+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 const TypeInfo pl011_arm_info = {
+    .name          = "pl011",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(pl011_state),
+    .class_init    = pl011_arm_class_init,
+};
+
+static void pl011_luminary_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sdc->init = pl011_luminary_init;
+}
+
+static const 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_types(void)
+{
+    type_register_static(&pl011_arm_info);
+    type_register_static(&pl011_luminary_info);
+}
+
+type_init(pl011_register_types)
diff --git a/hw/char/sclpconsole.c b/hw/char/sclpconsole.c
new file mode 100644 (file)
index 0000000..42ed54c
--- /dev/null
@@ -0,0 +1,305 @@
+/*
+ * SCLP event type
+ *    Ascii Console Data (VT220 Console)
+ *
+ * Copyright IBM, Corp. 2012
+ *
+ * Authors:
+ *  Heinz Graalfs <graalfs@de.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at your
+ * option) any later version.  See the COPYING file in the top-level directory.
+ *
+ */
+
+#include <hw/qdev.h>
+#include "qemu/thread.h"
+#include "qemu/error-report.h"
+
+#include "hw/s390x/sclp.h"
+#include "hw/s390x/event-facility.h"
+#include "char/char.h"
+
+typedef struct ASCIIConsoleData {
+    EventBufferHeader ebh;
+    char data[0];
+} QEMU_PACKED ASCIIConsoleData;
+
+/* max size for ASCII data in 4K SCCB page */
+#define SIZE_BUFFER_VT220 4080
+
+typedef struct SCLPConsole {
+    SCLPEvent event;
+    CharDriverState *chr;
+    /* io vector                                                       */
+    uint8_t *iov;           /* iov buffer pointer                      */
+    uint8_t *iov_sclp;      /* pointer to SCLP read offset             */
+    uint8_t *iov_bs;        /* pointer byte stream read offset         */
+    uint32_t iov_data_len;  /* length of byte stream in buffer         */
+    uint32_t iov_sclp_rest; /* length of byte stream not read via SCLP */
+    qemu_irq irq_read_vt220;
+} SCLPConsole;
+
+/* character layer call-back functions */
+
+/* Return number of bytes that fit into iov buffer */
+static int chr_can_read(void *opaque)
+{
+    SCLPConsole *scon = opaque;
+
+    return scon->iov ? SIZE_BUFFER_VT220 - scon->iov_data_len : 0;
+}
+
+/* Receive n bytes from character layer, save in iov buffer,
+ * and set event pending */
+static void receive_from_chr_layer(SCLPConsole *scon, const uint8_t *buf,
+                                   int size)
+{
+    assert(scon->iov);
+
+    /* read data must fit into current buffer */
+    assert(size <= SIZE_BUFFER_VT220 - scon->iov_data_len);
+
+    /* put byte-stream from character layer into buffer */
+    memcpy(scon->iov_bs, buf, size);
+    scon->iov_data_len += size;
+    scon->iov_sclp_rest += size;
+    scon->iov_bs += size;
+    scon->event.event_pending = true;
+}
+
+/* Send data from a char device over to the guest */
+static void chr_read(void *opaque, const uint8_t *buf, int size)
+{
+    SCLPConsole *scon = opaque;
+
+    assert(scon);
+
+    receive_from_chr_layer(scon, buf, size);
+    /* trigger SCLP read operation */
+    qemu_irq_raise(scon->irq_read_vt220);
+}
+
+static void chr_event(void *opaque, int event)
+{
+    SCLPConsole *scon = opaque;
+
+    switch (event) {
+    case CHR_EVENT_OPENED:
+        if (!scon->iov) {
+            scon->iov = g_malloc0(SIZE_BUFFER_VT220);
+            scon->iov_sclp = scon->iov;
+            scon->iov_bs = scon->iov;
+            scon->iov_data_len = 0;
+            scon->iov_sclp_rest = 0;
+        }
+        break;
+    case CHR_EVENT_CLOSED:
+        if (scon->iov) {
+            g_free(scon->iov);
+            scon->iov = NULL;
+        }
+        break;
+    }
+}
+
+/* functions to be called by event facility */
+
+static int event_type(void)
+{
+    return SCLP_EVENT_ASCII_CONSOLE_DATA;
+}
+
+static unsigned int send_mask(void)
+{
+    return SCLP_EVENT_MASK_MSG_ASCII;
+}
+
+static unsigned int receive_mask(void)
+{
+    return SCLP_EVENT_MASK_MSG_ASCII;
+}
+
+/* triggered by SCLP's read_event_data -
+ * copy console data byte-stream into provided (SCLP) buffer
+ */
+static void get_console_data(SCLPEvent *event, uint8_t *buf, size_t *size,
+                             int avail)
+{
+    SCLPConsole *cons = DO_UPCAST(SCLPConsole, event, event);
+
+    /* first byte is hex 0 saying an ascii string follows */
+    *buf++ = '\0';
+    avail--;
+    /* if all data fit into provided SCLP buffer */
+    if (avail >= cons->iov_sclp_rest) {
+        /* copy character byte-stream to SCLP buffer */
+        memcpy(buf, cons->iov_sclp, cons->iov_sclp_rest);
+        *size = cons->iov_sclp_rest + 1;
+        cons->iov_sclp = cons->iov;
+        cons->iov_bs = cons->iov;
+        cons->iov_data_len = 0;
+        cons->iov_sclp_rest = 0;
+        event->event_pending = false;
+        /* data provided and no more data pending */
+    } else {
+        /* if provided buffer is too small, just copy part */
+        memcpy(buf, cons->iov_sclp, avail);
+        *size = avail + 1;
+        cons->iov_sclp_rest -= avail;
+        cons->iov_sclp += avail;
+        /* more data pending */
+    }
+}
+
+static int read_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr,
+                           int *slen)
+{
+    int avail;
+    size_t src_len;
+    uint8_t *to;
+    ASCIIConsoleData *acd = (ASCIIConsoleData *) evt_buf_hdr;
+
+    if (!event->event_pending) {
+        /* no data pending */
+        return 0;
+    }
+
+    to = (uint8_t *)&acd->data;
+    avail = *slen - sizeof(ASCIIConsoleData);
+    get_console_data(event, to, &src_len, avail);
+
+    acd->ebh.length = cpu_to_be16(sizeof(ASCIIConsoleData) + src_len);
+    acd->ebh.type = SCLP_EVENT_ASCII_CONSOLE_DATA;
+    acd->ebh.flags |= SCLP_EVENT_BUFFER_ACCEPTED;
+    *slen = avail - src_len;
+
+    return 1;
+}
+
+/* triggered by SCLP's write_event_data
+ *  - write console data to character layer
+ *  returns < 0 if an error occurred
+ */
+static ssize_t write_console_data(SCLPEvent *event, const uint8_t *buf,
+                                  size_t len)
+{
+    ssize_t ret = 0;
+    const uint8_t *iov_offset;
+    SCLPConsole *scon = DO_UPCAST(SCLPConsole, event, event);
+
+    if (!scon->chr) {
+        /* If there's no backend, we can just say we consumed all data. */
+        return len;
+    }
+
+    iov_offset = buf;
+    while (len > 0) {
+        ret = qemu_chr_fe_write(scon->chr, buf, len);
+        if (ret == 0) {
+            /* a pty doesn't seem to be connected - no error */
+            len = 0;
+        } else if (ret == -EAGAIN || (ret > 0 && ret < len)) {
+            len -= ret;
+            iov_offset += ret;
+        } else {
+            len = 0;
+        }
+    }
+
+    return ret;
+}
+
+static int write_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr)
+{
+    int rc;
+    int length;
+    ssize_t written;
+    ASCIIConsoleData *acd = (ASCIIConsoleData *) evt_buf_hdr;
+
+    length = be16_to_cpu(evt_buf_hdr->length) - sizeof(EventBufferHeader);
+    written = write_console_data(event, (uint8_t *)acd->data, length);
+
+    rc = SCLP_RC_NORMAL_COMPLETION;
+    /* set event buffer accepted flag */
+    evt_buf_hdr->flags |= SCLP_EVENT_BUFFER_ACCEPTED;
+
+    /* written will be zero if a pty is not connected - don't treat as error */
+    if (written < 0) {
+        /* event buffer not accepted due to error in character layer */
+        evt_buf_hdr->flags &= ~(SCLP_EVENT_BUFFER_ACCEPTED);
+        rc = SCLP_RC_CONTAINED_EQUIPMENT_CHECK;
+    }
+
+    return rc;
+}
+
+static void trigger_ascii_console_data(void *opaque, int n, int level)
+{
+    sclp_service_interrupt(0);
+}
+
+/* qemu object creation and initialization functions */
+
+/* tell character layer our call-back functions */
+static int console_init(SCLPEvent *event)
+{
+    static bool console_available;
+
+    SCLPConsole *scon = DO_UPCAST(SCLPConsole, event, event);
+
+    if (console_available) {
+        error_report("Multiple VT220 operator consoles are not supported");
+        return -1;
+    }
+    console_available = true;
+    event->event_type = SCLP_EVENT_ASCII_CONSOLE_DATA;
+    if (scon->chr) {
+        qemu_chr_add_handlers(scon->chr, chr_can_read,
+                              chr_read, chr_event, scon);
+    }
+    scon->irq_read_vt220 = *qemu_allocate_irqs(trigger_ascii_console_data,
+                                               NULL, 1);
+
+    return 0;
+}
+
+static int console_exit(SCLPEvent *event)
+{
+    return 0;
+}
+
+static Property console_properties[] = {
+    DEFINE_PROP_CHR("chardev", SCLPConsole, chr),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void console_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SCLPEventClass *ec = SCLP_EVENT_CLASS(klass);
+
+    dc->props = console_properties;
+    ec->init = console_init;
+    ec->exit = console_exit;
+    ec->get_send_mask = send_mask;
+    ec->get_receive_mask = receive_mask;
+    ec->event_type = event_type;
+    ec->read_event_data = read_event_data;
+    ec->write_event_data = write_event_data;
+}
+
+static const TypeInfo sclp_console_info = {
+    .name          = "sclpconsole",
+    .parent        = TYPE_SCLP_EVENT,
+    .instance_size = sizeof(SCLPConsole),
+    .class_init    = console_class_init,
+    .class_size    = sizeof(SCLPEventClass),
+};
+
+static void register_types(void)
+{
+    type_register_static(&sclp_console_info);
+}
+
+type_init(register_types)
diff --git a/hw/char/serial-isa.c b/hw/char/serial-isa.c
new file mode 100644 (file)
index 0000000..ed140d0
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * QEMU 16550A UART emulation
+ *
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ * Copyright (c) 2008 Citrix Systems, 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 "hw/char/serial.h"
+#include "hw/isa/isa.h"
+
+typedef struct ISASerialState {
+    ISADevice dev;
+    uint32_t index;
+    uint32_t iobase;
+    uint32_t isairq;
+    SerialState state;
+} ISASerialState;
+
+static const int isa_serial_io[MAX_SERIAL_PORTS] = {
+    0x3f8, 0x2f8, 0x3e8, 0x2e8
+};
+static const int isa_serial_irq[MAX_SERIAL_PORTS] = {
+    4, 3, 4, 3
+};
+
+static int serial_isa_initfn(ISADevice *dev)
+{
+    static int index;
+    ISASerialState *isa = DO_UPCAST(ISASerialState, dev, dev);
+    SerialState *s = &isa->state;
+
+    if (isa->index == -1) {
+        isa->index = index;
+    }
+    if (isa->index >= MAX_SERIAL_PORTS) {
+        return -1;
+    }
+    if (isa->iobase == -1) {
+        isa->iobase = isa_serial_io[isa->index];
+    }
+    if (isa->isairq == -1) {
+        isa->isairq = isa_serial_irq[isa->index];
+    }
+    index++;
+
+    s->baudbase = 115200;
+    isa_init_irq(dev, &s->irq, isa->isairq);
+    serial_init_core(s);
+    qdev_set_legacy_instance_id(&dev->qdev, isa->iobase, 3);
+
+    memory_region_init_io(&s->io, &serial_io_ops, s, "serial", 8);
+    isa_register_ioport(dev, &s->io, isa->iobase);
+    return 0;
+}
+
+static const VMStateDescription vmstate_isa_serial = {
+    .name = "serial",
+    .version_id = 3,
+    .minimum_version_id = 2,
+    .fields = (VMStateField[]) {
+        VMSTATE_STRUCT(state, ISASerialState, 0, vmstate_serial, SerialState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static Property serial_isa_properties[] = {
+    DEFINE_PROP_UINT32("index",  ISASerialState, index,   -1),
+    DEFINE_PROP_HEX32("iobase",  ISASerialState, iobase,  -1),
+    DEFINE_PROP_UINT32("irq",    ISASerialState, isairq,  -1),
+    DEFINE_PROP_CHR("chardev",   ISASerialState, state.chr),
+    DEFINE_PROP_UINT32("wakeup", ISASerialState, state.wakeup, 0),
+    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 const 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_types(void)
+{
+    type_register_static(&serial_isa_info);
+}
+
+type_init(serial_register_types)
+
+bool serial_isa_init(ISABus *bus, int index, CharDriverState *chr)
+{
+    ISADevice *dev;
+
+    dev = isa_try_create(bus, "isa-serial");
+    if (!dev) {
+        return false;
+    }
+    qdev_prop_set_uint32(&dev->qdev, "index", index);
+    qdev_prop_set_chr(&dev->qdev, "chardev", chr);
+    if (qdev_init(&dev->qdev) < 0) {
+        return false;
+    }
+    return true;
+}
diff --git a/hw/char/serial-pci.c b/hw/char/serial-pci.c
new file mode 100644 (file)
index 0000000..2138e35
--- /dev/null
@@ -0,0 +1,252 @@
+/*
+ * QEMU 16550A UART emulation
+ *
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ * Copyright (c) 2008 Citrix Systems, 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.
+ */
+
+/* see docs/specs/pci-serial.txt */
+
+#include "hw/char/serial.h"
+#include "hw/pci/pci.h"
+
+#define PCI_SERIAL_MAX_PORTS 4
+
+typedef struct PCISerialState {
+    PCIDevice dev;
+    SerialState state;
+} PCISerialState;
+
+typedef struct PCIMultiSerialState {
+    PCIDevice    dev;
+    MemoryRegion iobar;
+    uint32_t     ports;
+    char         *name[PCI_SERIAL_MAX_PORTS];
+    SerialState  state[PCI_SERIAL_MAX_PORTS];
+    uint32_t     level[PCI_SERIAL_MAX_PORTS];
+    qemu_irq     *irqs;
+} PCIMultiSerialState;
+
+static int serial_pci_init(PCIDevice *dev)
+{
+    PCISerialState *pci = DO_UPCAST(PCISerialState, dev, dev);
+    SerialState *s = &pci->state;
+
+    s->baudbase = 115200;
+    serial_init_core(s);
+
+    pci->dev.config[PCI_INTERRUPT_PIN] = 0x01;
+    s->irq = pci->dev.irq[0];
+
+    memory_region_init_io(&s->io, &serial_io_ops, s, "serial", 8);
+    pci_register_bar(&pci->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io);
+    return 0;
+}
+
+static void multi_serial_irq_mux(void *opaque, int n, int level)
+{
+    PCIMultiSerialState *pci = opaque;
+    int i, pending = 0;
+
+    pci->level[n] = level;
+    for (i = 0; i < pci->ports; i++) {
+        if (pci->level[i]) {
+            pending = 1;
+        }
+    }
+    qemu_set_irq(pci->dev.irq[0], pending);
+}
+
+static int multi_serial_pci_init(PCIDevice *dev)
+{
+    PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev);
+    PCIMultiSerialState *pci = DO_UPCAST(PCIMultiSerialState, dev, dev);
+    SerialState *s;
+    int i;
+
+    switch (pc->device_id) {
+    case 0x0003:
+        pci->ports = 2;
+        break;
+    case 0x0004:
+        pci->ports = 4;
+        break;
+    }
+    assert(pci->ports > 0);
+    assert(pci->ports <= PCI_SERIAL_MAX_PORTS);
+
+    pci->dev.config[PCI_INTERRUPT_PIN] = 0x01;
+    memory_region_init(&pci->iobar, "multiserial", 8 * pci->ports);
+    pci_register_bar(&pci->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &pci->iobar);
+    pci->irqs = qemu_allocate_irqs(multi_serial_irq_mux, pci,
+                                   pci->ports);
+
+    for (i = 0; i < pci->ports; i++) {
+        s = pci->state + i;
+        s->baudbase = 115200;
+        serial_init_core(s);
+        s->irq = pci->irqs[i];
+        pci->name[i] = g_strdup_printf("uart #%d", i+1);
+        memory_region_init_io(&s->io, &serial_io_ops, s, pci->name[i], 8);
+        memory_region_add_subregion(&pci->iobar, 8 * i, &s->io);
+    }
+    return 0;
+}
+
+static void serial_pci_exit(PCIDevice *dev)
+{
+    PCISerialState *pci = DO_UPCAST(PCISerialState, dev, dev);
+    SerialState *s = &pci->state;
+
+    serial_exit_core(s);
+    memory_region_destroy(&s->io);
+}
+
+static void multi_serial_pci_exit(PCIDevice *dev)
+{
+    PCIMultiSerialState *pci = DO_UPCAST(PCIMultiSerialState, dev, dev);
+    SerialState *s;
+    int i;
+
+    for (i = 0; i < pci->ports; i++) {
+        s = pci->state + i;
+        serial_exit_core(s);
+        memory_region_destroy(&s->io);
+        g_free(pci->name[i]);
+    }
+    memory_region_destroy(&pci->iobar);
+    qemu_free_irqs(pci->irqs);
+}
+
+static const VMStateDescription vmstate_pci_serial = {
+    .name = "pci-serial",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_PCI_DEVICE(dev, PCISerialState),
+        VMSTATE_STRUCT(state, PCISerialState, 0, vmstate_serial, SerialState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_pci_multi_serial = {
+    .name = "pci-serial-multi",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_PCI_DEVICE(dev, PCIMultiSerialState),
+        VMSTATE_STRUCT_ARRAY(state, PCIMultiSerialState, PCI_SERIAL_MAX_PORTS,
+                             0, vmstate_serial, SerialState),
+        VMSTATE_UINT32_ARRAY(level, PCIMultiSerialState, PCI_SERIAL_MAX_PORTS),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static Property serial_pci_properties[] = {
+    DEFINE_PROP_CHR("chardev",  PCISerialState, state.chr),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static Property multi_2x_serial_pci_properties[] = {
+    DEFINE_PROP_CHR("chardev1",  PCIMultiSerialState, state[0].chr),
+    DEFINE_PROP_CHR("chardev2",  PCIMultiSerialState, state[1].chr),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static Property multi_4x_serial_pci_properties[] = {
+    DEFINE_PROP_CHR("chardev1",  PCIMultiSerialState, state[0].chr),
+    DEFINE_PROP_CHR("chardev2",  PCIMultiSerialState, state[1].chr),
+    DEFINE_PROP_CHR("chardev3",  PCIMultiSerialState, state[2].chr),
+    DEFINE_PROP_CHR("chardev4",  PCIMultiSerialState, state[3].chr),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void serial_pci_class_initfn(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *pc = PCI_DEVICE_CLASS(klass);
+    pc->init = serial_pci_init;
+    pc->exit = serial_pci_exit;
+    pc->vendor_id = PCI_VENDOR_ID_REDHAT;
+    pc->device_id = PCI_DEVICE_ID_REDHAT_SERIAL;
+    pc->revision = 1;
+    pc->class_id = PCI_CLASS_COMMUNICATION_SERIAL;
+    dc->vmsd = &vmstate_pci_serial;
+    dc->props = serial_pci_properties;
+}
+
+static void multi_2x_serial_pci_class_initfn(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *pc = PCI_DEVICE_CLASS(klass);
+    pc->init = multi_serial_pci_init;
+    pc->exit = multi_serial_pci_exit;
+    pc->vendor_id = PCI_VENDOR_ID_REDHAT;
+    pc->device_id = PCI_DEVICE_ID_REDHAT_SERIAL2;
+    pc->revision = 1;
+    pc->class_id = PCI_CLASS_COMMUNICATION_SERIAL;
+    dc->vmsd = &vmstate_pci_multi_serial;
+    dc->props = multi_2x_serial_pci_properties;
+}
+
+static void multi_4x_serial_pci_class_initfn(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *pc = PCI_DEVICE_CLASS(klass);
+    pc->init = multi_serial_pci_init;
+    pc->exit = multi_serial_pci_exit;
+    pc->vendor_id = PCI_VENDOR_ID_REDHAT;
+    pc->device_id = PCI_DEVICE_ID_REDHAT_SERIAL4;
+    pc->revision = 1;
+    pc->class_id = PCI_CLASS_COMMUNICATION_SERIAL;
+    dc->vmsd = &vmstate_pci_multi_serial;
+    dc->props = multi_4x_serial_pci_properties;
+}
+
+static const TypeInfo serial_pci_info = {
+    .name          = "pci-serial",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PCISerialState),
+    .class_init    = serial_pci_class_initfn,
+};
+
+static const TypeInfo multi_2x_serial_pci_info = {
+    .name          = "pci-serial-2x",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PCIMultiSerialState),
+    .class_init    = multi_2x_serial_pci_class_initfn,
+};
+
+static const TypeInfo multi_4x_serial_pci_info = {
+    .name          = "pci-serial-4x",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PCIMultiSerialState),
+    .class_init    = multi_4x_serial_pci_class_initfn,
+};
+
+static void serial_pci_register_types(void)
+{
+    type_register_static(&serial_pci_info);
+    type_register_static(&multi_2x_serial_pci_info);
+    type_register_static(&multi_4x_serial_pci_info);
+}
+
+type_init(serial_pci_register_types)
diff --git a/hw/char/serial.c b/hw/char/serial.c
new file mode 100644 (file)
index 0000000..1151bf1
--- /dev/null
@@ -0,0 +1,789 @@
+/*
+ * QEMU 16550A UART emulation
+ *
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ * Copyright (c) 2008 Citrix Systems, 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 "hw/char/serial.h"
+#include "char/char.h"
+#include "qemu/timer.h"
+#include "exec/address-spaces.h"
+
+//#define DEBUG_SERIAL
+
+#define UART_LCR_DLAB  0x80    /* Divisor latch access bit */
+
+#define UART_IER_MSI   0x08    /* Enable Modem status interrupt */
+#define UART_IER_RLSI  0x04    /* Enable receiver line status interrupt */
+#define UART_IER_THRI  0x02    /* Enable Transmitter holding register int. */
+#define UART_IER_RDI   0x01    /* Enable receiver data interrupt */
+
+#define UART_IIR_NO_INT        0x01    /* No interrupts pending */
+#define UART_IIR_ID    0x06    /* Mask for the interrupt ID */
+
+#define UART_IIR_MSI   0x00    /* Modem status interrupt */
+#define UART_IIR_THRI  0x02    /* Transmitter holding register empty */
+#define UART_IIR_RDI   0x04    /* Receiver data interrupt */
+#define UART_IIR_RLSI  0x06    /* Receiver line status interrupt */
+#define UART_IIR_CTI    0x0C    /* Character Timeout Indication */
+
+#define UART_IIR_FENF   0x80    /* Fifo enabled, but not functionning */
+#define UART_IIR_FE     0xC0    /* Fifo enabled */
+
+/*
+ * These are the definitions for the Modem Control Register
+ */
+#define UART_MCR_LOOP  0x10    /* Enable loopback test mode */
+#define UART_MCR_OUT2  0x08    /* Out2 complement */
+#define UART_MCR_OUT1  0x04    /* Out1 complement */
+#define UART_MCR_RTS   0x02    /* RTS complement */
+#define UART_MCR_DTR   0x01    /* DTR complement */
+
+/*
+ * These are the definitions for the Modem Status Register
+ */
+#define UART_MSR_DCD   0x80    /* Data Carrier Detect */
+#define UART_MSR_RI    0x40    /* Ring Indicator */
+#define UART_MSR_DSR   0x20    /* Data Set Ready */
+#define UART_MSR_CTS   0x10    /* Clear to Send */
+#define UART_MSR_DDCD  0x08    /* Delta DCD */
+#define UART_MSR_TERI  0x04    /* Trailing edge ring indicator */
+#define UART_MSR_DDSR  0x02    /* Delta DSR */
+#define UART_MSR_DCTS  0x01    /* Delta CTS */
+#define UART_MSR_ANY_DELTA 0x0F        /* Any of the delta bits! */
+
+#define UART_LSR_TEMT  0x40    /* Transmitter empty */
+#define UART_LSR_THRE  0x20    /* Transmit-hold-register empty */
+#define UART_LSR_BI    0x10    /* Break interrupt indicator */
+#define UART_LSR_FE    0x08    /* Frame error indicator */
+#define UART_LSR_PE    0x04    /* Parity error indicator */
+#define UART_LSR_OE    0x02    /* Overrun error indicator */
+#define UART_LSR_DR    0x01    /* Receiver data ready */
+#define UART_LSR_INT_ANY 0x1E  /* Any of the lsr-interrupt-triggering status bits */
+
+/* Interrupt trigger levels. The byte-counts are for 16550A - in newer UARTs the byte-count for each ITL is higher. */
+
+#define UART_FCR_ITL_1      0x00 /* 1 byte ITL */
+#define UART_FCR_ITL_2      0x40 /* 4 bytes ITL */
+#define UART_FCR_ITL_3      0x80 /* 8 bytes ITL */
+#define UART_FCR_ITL_4      0xC0 /* 14 bytes ITL */
+
+#define UART_FCR_DMS        0x08    /* DMA Mode Select */
+#define UART_FCR_XFR        0x04    /* XMIT Fifo Reset */
+#define UART_FCR_RFR        0x02    /* RCVR Fifo Reset */
+#define UART_FCR_FE         0x01    /* FIFO Enable */
+
+#define XMIT_FIFO           0
+#define RECV_FIFO           1
+#define MAX_XMIT_RETRY      4
+
+#ifdef DEBUG_SERIAL
+#define DPRINTF(fmt, ...) \
+do { fprintf(stderr, "serial: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) \
+do {} while (0)
+#endif
+
+static void serial_receive1(void *opaque, const uint8_t *buf, int size);
+
+static void fifo_clear(SerialState *s, int fifo)
+{
+    SerialFIFO *f = (fifo) ? &s->recv_fifo : &s->xmit_fifo;
+    memset(f->data, 0, UART_FIFO_LENGTH);
+    f->count = 0;
+    f->head = 0;
+    f->tail = 0;
+}
+
+static int fifo_put(SerialState *s, int fifo, uint8_t chr)
+{
+    SerialFIFO *f = (fifo) ? &s->recv_fifo : &s->xmit_fifo;
+
+    /* Receive overruns do not overwrite FIFO contents. */
+    if (fifo == XMIT_FIFO || f->count < UART_FIFO_LENGTH) {
+
+        f->data[f->head++] = chr;
+
+        if (f->head == UART_FIFO_LENGTH)
+            f->head = 0;
+    }
+
+    if (f->count < UART_FIFO_LENGTH)
+        f->count++;
+    else if (fifo == RECV_FIFO)
+        s->lsr |= UART_LSR_OE;
+
+    return 1;
+}
+
+static uint8_t fifo_get(SerialState *s, int fifo)
+{
+    SerialFIFO *f = (fifo) ? &s->recv_fifo : &s->xmit_fifo;
+    uint8_t c;
+
+    if(f->count == 0)
+        return 0;
+
+    c = f->data[f->tail++];
+    if (f->tail == UART_FIFO_LENGTH)
+        f->tail = 0;
+    f->count--;
+
+    return c;
+}
+
+static void serial_update_irq(SerialState *s)
+{
+    uint8_t tmp_iir = UART_IIR_NO_INT;
+
+    if ((s->ier & UART_IER_RLSI) && (s->lsr & UART_LSR_INT_ANY)) {
+        tmp_iir = UART_IIR_RLSI;
+    } else if ((s->ier & UART_IER_RDI) && s->timeout_ipending) {
+        /* Note that(s->ier & UART_IER_RDI) can mask this interrupt,
+         * this is not in the specification but is observed on existing
+         * hardware.  */
+        tmp_iir = UART_IIR_CTI;
+    } else if ((s->ier & UART_IER_RDI) && (s->lsr & UART_LSR_DR) &&
+               (!(s->fcr & UART_FCR_FE) ||
+                s->recv_fifo.count >= s->recv_fifo.itl)) {
+        tmp_iir = UART_IIR_RDI;
+    } else if ((s->ier & UART_IER_THRI) && s->thr_ipending) {
+        tmp_iir = UART_IIR_THRI;
+    } else if ((s->ier & UART_IER_MSI) && (s->msr & UART_MSR_ANY_DELTA)) {
+        tmp_iir = UART_IIR_MSI;
+    }
+
+    s->iir = tmp_iir | (s->iir & 0xF0);
+
+    if (tmp_iir != UART_IIR_NO_INT) {
+        qemu_irq_raise(s->irq);
+    } else {
+        qemu_irq_lower(s->irq);
+    }
+}
+
+static void serial_update_parameters(SerialState *s)
+{
+    int speed, parity, data_bits, stop_bits, frame_size;
+    QEMUSerialSetParams ssp;
+
+    if (s->divider == 0)
+        return;
+
+    /* Start bit. */
+    frame_size = 1;
+    if (s->lcr & 0x08) {
+        /* Parity bit. */
+        frame_size++;
+        if (s->lcr & 0x10)
+            parity = 'E';
+        else
+            parity = 'O';
+    } else {
+            parity = 'N';
+    }
+    if (s->lcr & 0x04)
+        stop_bits = 2;
+    else
+        stop_bits = 1;
+
+    data_bits = (s->lcr & 0x03) + 5;
+    frame_size += data_bits + stop_bits;
+    speed = s->baudbase / s->divider;
+    ssp.speed = speed;
+    ssp.parity = parity;
+    ssp.data_bits = data_bits;
+    ssp.stop_bits = stop_bits;
+    s->char_transmit_time =  (get_ticks_per_sec() / speed) * frame_size;
+    qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
+
+    DPRINTF("speed=%d parity=%c data=%d stop=%d\n",
+           speed, parity, data_bits, stop_bits);
+}
+
+static void serial_update_msl(SerialState *s)
+{
+    uint8_t omsr;
+    int flags;
+
+    qemu_del_timer(s->modem_status_poll);
+
+    if (qemu_chr_fe_ioctl(s->chr,CHR_IOCTL_SERIAL_GET_TIOCM, &flags) == -ENOTSUP) {
+        s->poll_msl = -1;
+        return;
+    }
+
+    omsr = s->msr;
+
+    s->msr = (flags & CHR_TIOCM_CTS) ? s->msr | UART_MSR_CTS : s->msr & ~UART_MSR_CTS;
+    s->msr = (flags & CHR_TIOCM_DSR) ? s->msr | UART_MSR_DSR : s->msr & ~UART_MSR_DSR;
+    s->msr = (flags & CHR_TIOCM_CAR) ? s->msr | UART_MSR_DCD : s->msr & ~UART_MSR_DCD;
+    s->msr = (flags & CHR_TIOCM_RI) ? s->msr | UART_MSR_RI : s->msr & ~UART_MSR_RI;
+
+    if (s->msr != omsr) {
+         /* Set delta bits */
+         s->msr = s->msr | ((s->msr >> 4) ^ (omsr >> 4));
+         /* UART_MSR_TERI only if change was from 1 -> 0 */
+         if ((s->msr & UART_MSR_TERI) && !(omsr & UART_MSR_RI))
+             s->msr &= ~UART_MSR_TERI;
+         serial_update_irq(s);
+    }
+
+    /* The real 16550A apparently has a 250ns response latency to line status changes.
+       We'll be lazy and poll only every 10ms, and only poll it at all if MSI interrupts are turned on */
+
+    if (s->poll_msl)
+        qemu_mod_timer(s->modem_status_poll, qemu_get_clock_ns(vm_clock) + get_ticks_per_sec() / 100);
+}
+
+static gboolean serial_xmit(GIOChannel *chan, GIOCondition cond, void *opaque)
+{
+    SerialState *s = opaque;
+
+    if (s->tsr_retry <= 0) {
+        if (s->fcr & UART_FCR_FE) {
+            s->tsr = fifo_get(s,XMIT_FIFO);
+            if (!s->xmit_fifo.count)
+                s->lsr |= UART_LSR_THRE;
+        } else if ((s->lsr & UART_LSR_THRE)) {
+            return FALSE;
+        } else {
+            s->tsr = s->thr;
+            s->lsr |= UART_LSR_THRE;
+            s->lsr &= ~UART_LSR_TEMT;
+        }
+    }
+
+    if (s->mcr & UART_MCR_LOOP) {
+        /* in loopback mode, say that we just received a char */
+        serial_receive1(s, &s->tsr, 1);
+    } else if (qemu_chr_fe_write(s->chr, &s->tsr, 1) != 1) {
+        if (s->tsr_retry >= 0 && s->tsr_retry < MAX_XMIT_RETRY &&
+            qemu_chr_fe_add_watch(s->chr, G_IO_OUT, serial_xmit, s) > 0) {
+            s->tsr_retry++;
+            return FALSE;
+        }
+        s->tsr_retry = 0;
+    } else {
+        s->tsr_retry = 0;
+    }
+
+    s->last_xmit_ts = qemu_get_clock_ns(vm_clock);
+
+    if (s->lsr & UART_LSR_THRE) {
+        s->lsr |= UART_LSR_TEMT;
+        s->thr_ipending = 1;
+        serial_update_irq(s);
+    }
+
+    return FALSE;
+}
+
+
+static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val,
+                                unsigned size)
+{
+    SerialState *s = opaque;
+
+    addr &= 7;
+    DPRINTF("write addr=0x%" HWADDR_PRIx " val=0x%" PRIx64 "\n", addr, val);
+    switch(addr) {
+    default:
+    case 0:
+        if (s->lcr & UART_LCR_DLAB) {
+            s->divider = (s->divider & 0xff00) | val;
+            serial_update_parameters(s);
+        } else {
+            s->thr = (uint8_t) val;
+            if(s->fcr & UART_FCR_FE) {
+                fifo_put(s, XMIT_FIFO, s->thr);
+                s->thr_ipending = 0;
+                s->lsr &= ~UART_LSR_TEMT;
+                s->lsr &= ~UART_LSR_THRE;
+                serial_update_irq(s);
+            } else {
+                s->thr_ipending = 0;
+                s->lsr &= ~UART_LSR_THRE;
+                serial_update_irq(s);
+            }
+            serial_xmit(NULL, G_IO_OUT, s);
+        }
+        break;
+    case 1:
+        if (s->lcr & UART_LCR_DLAB) {
+            s->divider = (s->divider & 0x00ff) | (val << 8);
+            serial_update_parameters(s);
+        } else {
+            s->ier = val & 0x0f;
+            /* If the backend device is a real serial port, turn polling of the modem
+               status lines on physical port on or off depending on UART_IER_MSI state */
+            if (s->poll_msl >= 0) {
+                if (s->ier & UART_IER_MSI) {
+                     s->poll_msl = 1;
+                     serial_update_msl(s);
+                } else {
+                     qemu_del_timer(s->modem_status_poll);
+                     s->poll_msl = 0;
+                }
+            }
+            if (s->lsr & UART_LSR_THRE) {
+                s->thr_ipending = 1;
+                serial_update_irq(s);
+            }
+        }
+        break;
+    case 2:
+        val = val & 0xFF;
+
+        if (s->fcr == val)
+            break;
+
+        /* Did the enable/disable flag change? If so, make sure FIFOs get flushed */
+        if ((val ^ s->fcr) & UART_FCR_FE)
+            val |= UART_FCR_XFR | UART_FCR_RFR;
+
+        /* FIFO clear */
+
+        if (val & UART_FCR_RFR) {
+            qemu_del_timer(s->fifo_timeout_timer);
+            s->timeout_ipending=0;
+            fifo_clear(s,RECV_FIFO);
+        }
+
+        if (val & UART_FCR_XFR) {
+            fifo_clear(s,XMIT_FIFO);
+        }
+
+        if (val & UART_FCR_FE) {
+            s->iir |= UART_IIR_FE;
+            /* Set RECV_FIFO trigger Level */
+            switch (val & 0xC0) {
+            case UART_FCR_ITL_1:
+                s->recv_fifo.itl = 1;
+                break;
+            case UART_FCR_ITL_2:
+                s->recv_fifo.itl = 4;
+                break;
+            case UART_FCR_ITL_3:
+                s->recv_fifo.itl = 8;
+                break;
+            case UART_FCR_ITL_4:
+                s->recv_fifo.itl = 14;
+                break;
+            }
+        } else
+            s->iir &= ~UART_IIR_FE;
+
+        /* Set fcr - or at least the bits in it that are supposed to "stick" */
+        s->fcr = val & 0xC9;
+        serial_update_irq(s);
+        break;
+    case 3:
+        {
+            int break_enable;
+            s->lcr = val;
+            serial_update_parameters(s);
+            break_enable = (val >> 6) & 1;
+            if (break_enable != s->last_break_enable) {
+                s->last_break_enable = break_enable;
+                qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_BREAK,
+                               &break_enable);
+            }
+        }
+        break;
+    case 4:
+        {
+            int flags;
+            int old_mcr = s->mcr;
+            s->mcr = val & 0x1f;
+            if (val & UART_MCR_LOOP)
+                break;
+
+            if (s->poll_msl >= 0 && old_mcr != s->mcr) {
+
+                qemu_chr_fe_ioctl(s->chr,CHR_IOCTL_SERIAL_GET_TIOCM, &flags);
+
+                flags &= ~(CHR_TIOCM_RTS | CHR_TIOCM_DTR);
+
+                if (val & UART_MCR_RTS)
+                    flags |= CHR_TIOCM_RTS;
+                if (val & UART_MCR_DTR)
+                    flags |= CHR_TIOCM_DTR;
+
+                qemu_chr_fe_ioctl(s->chr,CHR_IOCTL_SERIAL_SET_TIOCM, &flags);
+                /* Update the modem status after a one-character-send wait-time, since there may be a response
+                   from the device/computer at the other end of the serial line */
+                qemu_mod_timer(s->modem_status_poll, qemu_get_clock_ns(vm_clock) + s->char_transmit_time);
+            }
+        }
+        break;
+    case 5:
+        break;
+    case 6:
+        break;
+    case 7:
+        s->scr = val;
+        break;
+    }
+}
+
+static uint64_t serial_ioport_read(void *opaque, hwaddr addr, unsigned size)
+{
+    SerialState *s = opaque;
+    uint32_t ret;
+
+    addr &= 7;
+    switch(addr) {
+    default:
+    case 0:
+        if (s->lcr & UART_LCR_DLAB) {
+            ret = s->divider & 0xff;
+        } else {
+            if(s->fcr & UART_FCR_FE) {
+                ret = fifo_get(s,RECV_FIFO);
+                if (s->recv_fifo.count == 0)
+                    s->lsr &= ~(UART_LSR_DR | UART_LSR_BI);
+                else
+                    qemu_mod_timer(s->fifo_timeout_timer, qemu_get_clock_ns (vm_clock) + s->char_transmit_time * 4);
+                s->timeout_ipending = 0;
+            } else {
+                ret = s->rbr;
+                s->lsr &= ~(UART_LSR_DR | UART_LSR_BI);
+            }
+            serial_update_irq(s);
+            if (!(s->mcr & UART_MCR_LOOP)) {
+                /* in loopback mode, don't receive any data */
+                qemu_chr_accept_input(s->chr);
+            }
+        }
+        break;
+    case 1:
+        if (s->lcr & UART_LCR_DLAB) {
+            ret = (s->divider >> 8) & 0xff;
+        } else {
+            ret = s->ier;
+        }
+        break;
+    case 2:
+        ret = s->iir;
+        if ((ret & UART_IIR_ID) == UART_IIR_THRI) {
+            s->thr_ipending = 0;
+            serial_update_irq(s);
+        }
+        break;
+    case 3:
+        ret = s->lcr;
+        break;
+    case 4:
+        ret = s->mcr;
+        break;
+    case 5:
+        ret = s->lsr;
+        /* Clear break and overrun interrupts */
+        if (s->lsr & (UART_LSR_BI|UART_LSR_OE)) {
+            s->lsr &= ~(UART_LSR_BI|UART_LSR_OE);
+            serial_update_irq(s);
+        }
+        break;
+    case 6:
+        if (s->mcr & UART_MCR_LOOP) {
+            /* in loopback, the modem output pins are connected to the
+               inputs */
+            ret = (s->mcr & 0x0c) << 4;
+            ret |= (s->mcr & 0x02) << 3;
+            ret |= (s->mcr & 0x01) << 5;
+        } else {
+            if (s->poll_msl >= 0)
+                serial_update_msl(s);
+            ret = s->msr;
+            /* Clear delta bits & msr int after read, if they were set */
+            if (s->msr & UART_MSR_ANY_DELTA) {
+                s->msr &= 0xF0;
+                serial_update_irq(s);
+            }
+        }
+        break;
+    case 7:
+        ret = s->scr;
+        break;
+    }
+    DPRINTF("read addr=0x%" HWADDR_PRIx " val=0x%02x\n", addr, ret);
+    return ret;
+}
+
+static int serial_can_receive(SerialState *s)
+{
+    if(s->fcr & UART_FCR_FE) {
+        if(s->recv_fifo.count < UART_FIFO_LENGTH)
+        /* Advertise (fifo.itl - fifo.count) bytes when count < ITL, and 1 if above. If UART_FIFO_LENGTH - fifo.count is
+        advertised the effect will be to almost always fill the fifo completely before the guest has a chance to respond,
+        effectively overriding the ITL that the guest has set. */
+             return (s->recv_fifo.count <= s->recv_fifo.itl) ? s->recv_fifo.itl - s->recv_fifo.count : 1;
+        else
+             return 0;
+    } else {
+    return !(s->lsr & UART_LSR_DR);
+    }
+}
+
+static void serial_receive_break(SerialState *s)
+{
+    s->rbr = 0;
+    /* When the LSR_DR is set a null byte is pushed into the fifo */
+    fifo_put(s, RECV_FIFO, '\0');
+    s->lsr |= UART_LSR_BI | UART_LSR_DR;
+    serial_update_irq(s);
+}
+
+/* There's data in recv_fifo and s->rbr has not been read for 4 char transmit times */
+static void fifo_timeout_int (void *opaque) {
+    SerialState *s = opaque;
+    if (s->recv_fifo.count) {
+        s->timeout_ipending = 1;
+        serial_update_irq(s);
+    }
+}
+
+static int serial_can_receive1(void *opaque)
+{
+    SerialState *s = opaque;
+    return serial_can_receive(s);
+}
+
+static void serial_receive1(void *opaque, const uint8_t *buf, int size)
+{
+    SerialState *s = opaque;
+
+    if (s->wakeup) {
+        qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER);
+    }
+    if(s->fcr & UART_FCR_FE) {
+        int i;
+        for (i = 0; i < size; i++) {
+            fifo_put(s, RECV_FIFO, buf[i]);
+        }
+        s->lsr |= UART_LSR_DR;
+        /* call the timeout receive callback in 4 char transmit time */
+        qemu_mod_timer(s->fifo_timeout_timer, qemu_get_clock_ns (vm_clock) + s->char_transmit_time * 4);
+    } else {
+        if (s->lsr & UART_LSR_DR)
+            s->lsr |= UART_LSR_OE;
+        s->rbr = buf[0];
+        s->lsr |= UART_LSR_DR;
+    }
+    serial_update_irq(s);
+}
+
+static void serial_event(void *opaque, int event)
+{
+    SerialState *s = opaque;
+    DPRINTF("event %x\n", event);
+    if (event == CHR_EVENT_BREAK)
+        serial_receive_break(s);
+}
+
+static void serial_pre_save(void *opaque)
+{
+    SerialState *s = opaque;
+    s->fcr_vmstate = s->fcr;
+}
+
+static int serial_post_load(void *opaque, int version_id)
+{
+    SerialState *s = opaque;
+
+    if (version_id < 3) {
+        s->fcr_vmstate = 0;
+    }
+    /* Initialize fcr via setter to perform essential side-effects */
+    serial_ioport_write(s, 0x02, s->fcr_vmstate, 1);
+    serial_update_parameters(s);
+    return 0;
+}
+
+const VMStateDescription vmstate_serial = {
+    .name = "serial",
+    .version_id = 3,
+    .minimum_version_id = 2,
+    .pre_save = serial_pre_save,
+    .post_load = serial_post_load,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT16_V(divider, SerialState, 2),
+        VMSTATE_UINT8(rbr, SerialState),
+        VMSTATE_UINT8(ier, SerialState),
+        VMSTATE_UINT8(iir, SerialState),
+        VMSTATE_UINT8(lcr, SerialState),
+        VMSTATE_UINT8(mcr, SerialState),
+        VMSTATE_UINT8(lsr, SerialState),
+        VMSTATE_UINT8(msr, SerialState),
+        VMSTATE_UINT8(scr, SerialState),
+        VMSTATE_UINT8_V(fcr_vmstate, SerialState, 3),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void serial_reset(void *opaque)
+{
+    SerialState *s = opaque;
+
+    s->rbr = 0;
+    s->ier = 0;
+    s->iir = UART_IIR_NO_INT;
+    s->lcr = 0;
+    s->lsr = UART_LSR_TEMT | UART_LSR_THRE;
+    s->msr = UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS;
+    /* Default to 9600 baud, 1 start bit, 8 data bits, 1 stop bit, no parity. */
+    s->divider = 0x0C;
+    s->mcr = UART_MCR_OUT2;
+    s->scr = 0;
+    s->tsr_retry = 0;
+    s->char_transmit_time = (get_ticks_per_sec() / 9600) * 10;
+    s->poll_msl = 0;
+
+    fifo_clear(s,RECV_FIFO);
+    fifo_clear(s,XMIT_FIFO);
+
+    s->last_xmit_ts = qemu_get_clock_ns(vm_clock);
+
+    s->thr_ipending = 0;
+    s->last_break_enable = 0;
+    qemu_irq_lower(s->irq);
+}
+
+void serial_init_core(SerialState *s)
+{
+    if (!s->chr) {
+        fprintf(stderr, "Can't create serial device, empty char device\n");
+       exit(1);
+    }
+
+    s->modem_status_poll = qemu_new_timer_ns(vm_clock, (QEMUTimerCB *) serial_update_msl, s);
+
+    s->fifo_timeout_timer = qemu_new_timer_ns(vm_clock, (QEMUTimerCB *) fifo_timeout_int, s);
+    qemu_register_reset(serial_reset, s);
+
+    qemu_chr_add_handlers(s->chr, serial_can_receive1, serial_receive1,
+                          serial_event, s);
+}
+
+void serial_exit_core(SerialState *s)
+{
+    qemu_chr_add_handlers(s->chr, NULL, NULL, NULL, NULL);
+    qemu_unregister_reset(serial_reset, s);
+}
+
+/* Change the main reference oscillator frequency. */
+void serial_set_frequency(SerialState *s, uint32_t frequency)
+{
+    s->baudbase = frequency;
+    serial_update_parameters(s);
+}
+
+const MemoryRegionOps serial_io_ops = {
+    .read = serial_ioport_read,
+    .write = serial_ioport_write,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+SerialState *serial_init(int base, qemu_irq irq, int baudbase,
+                         CharDriverState *chr, MemoryRegion *system_io)
+{
+    SerialState *s;
+
+    s = g_malloc0(sizeof(SerialState));
+
+    s->irq = irq;
+    s->baudbase = baudbase;
+    s->chr = chr;
+    serial_init_core(s);
+
+    vmstate_register(NULL, base, &vmstate_serial, s);
+
+    memory_region_init_io(&s->io, &serial_io_ops, s, "serial", 8);
+    memory_region_add_subregion(system_io, base, &s->io);
+
+    return s;
+}
+
+/* Memory mapped interface */
+static uint64_t serial_mm_read(void *opaque, hwaddr addr,
+                               unsigned size)
+{
+    SerialState *s = opaque;
+    return serial_ioport_read(s, addr >> s->it_shift, 1);
+}
+
+static void serial_mm_write(void *opaque, hwaddr addr,
+                            uint64_t value, unsigned size)
+{
+    SerialState *s = opaque;
+    value &= ~0u >> (32 - (size * 8));
+    serial_ioport_write(s, addr >> s->it_shift, value, 1);
+}
+
+static const MemoryRegionOps serial_mm_ops[3] = {
+    [DEVICE_NATIVE_ENDIAN] = {
+        .read = serial_mm_read,
+        .write = serial_mm_write,
+        .endianness = DEVICE_NATIVE_ENDIAN,
+    },
+    [DEVICE_LITTLE_ENDIAN] = {
+        .read = serial_mm_read,
+        .write = serial_mm_write,
+        .endianness = DEVICE_LITTLE_ENDIAN,
+    },
+    [DEVICE_BIG_ENDIAN] = {
+        .read = serial_mm_read,
+        .write = serial_mm_write,
+        .endianness = DEVICE_BIG_ENDIAN,
+    },
+};
+
+SerialState *serial_mm_init(MemoryRegion *address_space,
+                            hwaddr base, int it_shift,
+                            qemu_irq irq, int baudbase,
+                            CharDriverState *chr, enum device_endian end)
+{
+    SerialState *s;
+
+    s = g_malloc0(sizeof(SerialState));
+
+    s->it_shift = it_shift;
+    s->irq = irq;
+    s->baudbase = baudbase;
+    s->chr = chr;
+
+    serial_init_core(s);
+    vmstate_register(NULL, base, &vmstate_serial, s);
+
+    memory_region_init_io(&s->io, &serial_mm_ops[end], s,
+                          "serial", 8 << it_shift);
+    memory_region_add_subregion(address_space, base, &s->io);
+
+    serial_update_msl(s);
+    return s;
+}
diff --git a/hw/char/sh_serial.c b/hw/char/sh_serial.c
new file mode 100644 (file)
index 0000000..450c7d8
--- /dev/null
@@ -0,0 +1,410 @@
+/*
+ * QEMU SCI/SCIF serial port emulation
+ *
+ * Copyright (c) 2007 Magnus Damm
+ *
+ * Based on serial.c - QEMU 16450 UART 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.
+ */
+#include "hw/hw.h"
+#include "hw/sh4/sh.h"
+#include "char/char.h"
+#include "exec/address-spaces.h"
+
+//#define DEBUG_SERIAL
+
+#define SH_SERIAL_FLAG_TEND (1 << 0)
+#define SH_SERIAL_FLAG_TDE  (1 << 1)
+#define SH_SERIAL_FLAG_RDF  (1 << 2)
+#define SH_SERIAL_FLAG_BRK  (1 << 3)
+#define SH_SERIAL_FLAG_DR   (1 << 4)
+
+#define SH_RX_FIFO_LENGTH (16)
+
+typedef struct {
+    MemoryRegion iomem;
+    MemoryRegion iomem_p4;
+    MemoryRegion iomem_a7;
+    uint8_t smr;
+    uint8_t brr;
+    uint8_t scr;
+    uint8_t dr; /* ftdr / tdr */
+    uint8_t sr; /* fsr / ssr */
+    uint16_t fcr;
+    uint8_t sptr;
+
+    uint8_t rx_fifo[SH_RX_FIFO_LENGTH]; /* frdr / rdr */
+    uint8_t rx_cnt;
+    uint8_t rx_tail;
+    uint8_t rx_head;
+
+    int freq;
+    int feat;
+    int flags;
+    int rtrg;
+
+    CharDriverState *chr;
+
+    qemu_irq eri;
+    qemu_irq rxi;
+    qemu_irq txi;
+    qemu_irq tei;
+    qemu_irq bri;
+} sh_serial_state;
+
+static void sh_serial_clear_fifo(sh_serial_state * s)
+{
+    memset(s->rx_fifo, 0, SH_RX_FIFO_LENGTH);
+    s->rx_cnt = 0;
+    s->rx_head = 0;
+    s->rx_tail = 0;
+}
+
+static void sh_serial_write(void *opaque, hwaddr offs,
+                            uint64_t val, unsigned size)
+{
+    sh_serial_state *s = opaque;
+    unsigned char ch;
+
+#ifdef DEBUG_SERIAL
+    printf("sh_serial: write offs=0x%02x val=0x%02x\n",
+          offs, val);
+#endif
+    switch(offs) {
+    case 0x00: /* SMR */
+        s->smr = val & ((s->feat & SH_SERIAL_FEAT_SCIF) ? 0x7b : 0xff);
+        return;
+    case 0x04: /* BRR */
+        s->brr = val;
+       return;
+    case 0x08: /* SCR */
+        /* TODO : For SH7751, SCIF mask should be 0xfb. */
+        s->scr = val & ((s->feat & SH_SERIAL_FEAT_SCIF) ? 0xfa : 0xff);
+        if (!(val & (1 << 5)))
+            s->flags |= SH_SERIAL_FLAG_TEND;
+        if ((s->feat & SH_SERIAL_FEAT_SCIF) && s->txi) {
+           qemu_set_irq(s->txi, val & (1 << 7));
+        }
+        if (!(val & (1 << 6))) {
+           qemu_set_irq(s->rxi, 0);
+        }
+        return;
+    case 0x0c: /* FTDR / TDR */
+        if (s->chr) {
+            ch = val;
+            qemu_chr_fe_write(s->chr, &ch, 1);
+       }
+       s->dr = val;
+       s->flags &= ~SH_SERIAL_FLAG_TDE;
+        return;
+#if 0
+    case 0x14: /* FRDR / RDR */
+        ret = 0;
+        break;
+#endif
+    }
+    if (s->feat & SH_SERIAL_FEAT_SCIF) {
+        switch(offs) {
+        case 0x10: /* FSR */
+            if (!(val & (1 << 6)))
+                s->flags &= ~SH_SERIAL_FLAG_TEND;
+            if (!(val & (1 << 5)))
+                s->flags &= ~SH_SERIAL_FLAG_TDE;
+            if (!(val & (1 << 4)))
+                s->flags &= ~SH_SERIAL_FLAG_BRK;
+            if (!(val & (1 << 1)))
+                s->flags &= ~SH_SERIAL_FLAG_RDF;
+            if (!(val & (1 << 0)))
+                s->flags &= ~SH_SERIAL_FLAG_DR;
+
+            if (!(val & (1 << 1)) || !(val & (1 << 0))) {
+                if (s->rxi) {
+                    qemu_set_irq(s->rxi, 0);
+                }
+            }
+            return;
+        case 0x18: /* FCR */
+            s->fcr = val;
+            switch ((val >> 6) & 3) {
+            case 0:
+                s->rtrg = 1;
+                break;
+            case 1:
+                s->rtrg = 4;
+                break;
+            case 2:
+                s->rtrg = 8;
+                break;
+            case 3:
+                s->rtrg = 14;
+                break;
+            }
+            if (val & (1 << 1)) {
+                sh_serial_clear_fifo(s);
+                s->sr &= ~(1 << 1);
+            }
+
+            return;
+        case 0x20: /* SPTR */
+            s->sptr = val & 0xf3;
+            return;
+        case 0x24: /* LSR */
+            return;
+        }
+    }
+    else {
+        switch(offs) {
+#if 0
+        case 0x0c:
+            ret = s->dr;
+            break;
+        case 0x10:
+            ret = 0;
+            break;
+#endif
+        case 0x1c:
+            s->sptr = val & 0x8f;
+            return;
+        }
+    }
+
+    fprintf(stderr, "sh_serial: unsupported write to 0x%02"
+            HWADDR_PRIx "\n", offs);
+    abort();
+}
+
+static uint64_t sh_serial_read(void *opaque, hwaddr offs,
+                               unsigned size)
+{
+    sh_serial_state *s = opaque;
+    uint32_t ret = ~0;
+
+#if 0
+    switch(offs) {
+    case 0x00:
+        ret = s->smr;
+        break;
+    case 0x04:
+        ret = s->brr;
+       break;
+    case 0x08:
+        ret = s->scr;
+        break;
+    case 0x14:
+        ret = 0;
+        break;
+    }
+#endif
+    if (s->feat & SH_SERIAL_FEAT_SCIF) {
+        switch(offs) {
+        case 0x00: /* SMR */
+            ret = s->smr;
+            break;
+        case 0x08: /* SCR */
+            ret = s->scr;
+            break;
+        case 0x10: /* FSR */
+            ret = 0;
+            if (s->flags & SH_SERIAL_FLAG_TEND)
+                ret |= (1 << 6);
+            if (s->flags & SH_SERIAL_FLAG_TDE)
+                ret |= (1 << 5);
+            if (s->flags & SH_SERIAL_FLAG_BRK)
+                ret |= (1 << 4);
+            if (s->flags & SH_SERIAL_FLAG_RDF)
+                ret |= (1 << 1);
+            if (s->flags & SH_SERIAL_FLAG_DR)
+                ret |= (1 << 0);
+
+            if (s->scr & (1 << 5))
+                s->flags |= SH_SERIAL_FLAG_TDE | SH_SERIAL_FLAG_TEND;
+
+            break;
+        case 0x14:
+            if (s->rx_cnt > 0) {
+                ret = s->rx_fifo[s->rx_tail++];
+                s->rx_cnt--;
+                if (s->rx_tail == SH_RX_FIFO_LENGTH)
+                    s->rx_tail = 0;
+                if (s->rx_cnt < s->rtrg)
+                    s->flags &= ~SH_SERIAL_FLAG_RDF;
+            }
+            break;
+#if 0
+        case 0x18:
+            ret = s->fcr;
+            break;
+#endif
+        case 0x1c:
+            ret = s->rx_cnt;
+            break;
+        case 0x20:
+            ret = s->sptr;
+            break;
+        case 0x24:
+            ret = 0;
+            break;
+        }
+    }
+    else {
+        switch(offs) {
+#if 0
+        case 0x0c:
+            ret = s->dr;
+            break;
+        case 0x10:
+            ret = 0;
+            break;
+        case 0x14:
+            ret = s->rx_fifo[0];
+            break;
+#endif
+        case 0x1c:
+            ret = s->sptr;
+            break;
+        }
+    }
+#ifdef DEBUG_SERIAL
+    printf("sh_serial: read offs=0x%02x val=0x%x\n",
+          offs, ret);
+#endif
+
+    if (ret & ~((1 << 16) - 1)) {
+        fprintf(stderr, "sh_serial: unsupported read from 0x%02"
+                HWADDR_PRIx "\n", offs);
+        abort();
+    }
+
+    return ret;
+}
+
+static int sh_serial_can_receive(sh_serial_state *s)
+{
+    return s->scr & (1 << 4);
+}
+
+static void sh_serial_receive_break(sh_serial_state *s)
+{
+    if (s->feat & SH_SERIAL_FEAT_SCIF)
+        s->sr |= (1 << 4);
+}
+
+static int sh_serial_can_receive1(void *opaque)
+{
+    sh_serial_state *s = opaque;
+    return sh_serial_can_receive(s);
+}
+
+static void sh_serial_receive1(void *opaque, const uint8_t *buf, int size)
+{
+    sh_serial_state *s = opaque;
+
+    if (s->feat & SH_SERIAL_FEAT_SCIF) {
+        int i;
+        for (i = 0; i < size; i++) {
+            if (s->rx_cnt < SH_RX_FIFO_LENGTH) {
+                s->rx_fifo[s->rx_head++] = buf[i];
+                if (s->rx_head == SH_RX_FIFO_LENGTH) {
+                    s->rx_head = 0;
+                }
+                s->rx_cnt++;
+                if (s->rx_cnt >= s->rtrg) {
+                    s->flags |= SH_SERIAL_FLAG_RDF;
+                    if (s->scr & (1 << 6) && s->rxi) {
+                        qemu_set_irq(s->rxi, 1);
+                    }
+                }
+            }
+        }
+    } else {
+        s->rx_fifo[0] = buf[0];
+    }
+}
+
+static void sh_serial_event(void *opaque, int event)
+{
+    sh_serial_state *s = opaque;
+    if (event == CHR_EVENT_BREAK)
+        sh_serial_receive_break(s);
+}
+
+static const MemoryRegionOps sh_serial_ops = {
+    .read = sh_serial_read,
+    .write = sh_serial_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+void sh_serial_init(MemoryRegion *sysmem,
+                    hwaddr base, int feat,
+                    uint32_t freq, CharDriverState *chr,
+                    qemu_irq eri_source,
+                    qemu_irq rxi_source,
+                    qemu_irq txi_source,
+                    qemu_irq tei_source,
+                    qemu_irq bri_source)
+{
+    sh_serial_state *s;
+
+    s = g_malloc0(sizeof(sh_serial_state));
+
+    s->feat = feat;
+    s->flags = SH_SERIAL_FLAG_TEND | SH_SERIAL_FLAG_TDE;
+    s->rtrg = 1;
+
+    s->smr = 0;
+    s->brr = 0xff;
+    s->scr = 1 << 5; /* pretend that TX is enabled so early printk works */
+    s->sptr = 0;
+
+    if (feat & SH_SERIAL_FEAT_SCIF) {
+        s->fcr = 0;
+    }
+    else {
+        s->dr = 0xff;
+    }
+
+    sh_serial_clear_fifo(s);
+
+    memory_region_init_io(&s->iomem, &sh_serial_ops, s,
+                          "serial", 0x100000000ULL);
+
+    memory_region_init_alias(&s->iomem_p4, "serial-p4", &s->iomem,
+                             0, 0x28);
+    memory_region_add_subregion(sysmem, P4ADDR(base), &s->iomem_p4);
+
+    memory_region_init_alias(&s->iomem_a7, "serial-a7", &s->iomem,
+                             0, 0x28);
+    memory_region_add_subregion(sysmem, A7ADDR(base), &s->iomem_a7);
+
+    s->chr = chr;
+
+    if (chr) {
+        qemu_chr_fe_claim_no_fail(chr);
+        qemu_chr_add_handlers(chr, sh_serial_can_receive1, sh_serial_receive1,
+                             sh_serial_event, s);
+    }
+
+    s->eri = eri_source;
+    s->rxi = rxi_source;
+    s->txi = txi_source;
+    s->tei = tei_source;
+    s->bri = bri_source;
+}
diff --git a/hw/char/spapr_vty.c b/hw/char/spapr_vty.c
new file mode 100644 (file)
index 0000000..9df018a
--- /dev/null
@@ -0,0 +1,221 @@
+#include "hw/qdev.h"
+#include "char/char.h"
+#include "hw/ppc/spapr.h"
+#include "hw/ppc/spapr_vio.h"
+
+#define VTERM_BUFSIZE   16
+
+typedef struct VIOsPAPRVTYDevice {
+    VIOsPAPRDevice sdev;
+    CharDriverState *chardev;
+    uint32_t in, out;
+    uint8_t buf[VTERM_BUFSIZE];
+} VIOsPAPRVTYDevice;
+
+static int vty_can_receive(void *opaque)
+{
+    VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)opaque;
+
+    return (dev->in - dev->out) < VTERM_BUFSIZE;
+}
+
+static void vty_receive(void *opaque, const uint8_t *buf, int size)
+{
+    VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)opaque;
+    int i;
+
+    if ((dev->in == dev->out) && size) {
+        /* toggle line to simulate edge interrupt */
+        qemu_irq_pulse(spapr_vio_qirq(&dev->sdev));
+    }
+    for (i = 0; i < size; i++) {
+        assert((dev->in - dev->out) < VTERM_BUFSIZE);
+        dev->buf[dev->in++ % VTERM_BUFSIZE] = buf[i];
+    }
+}
+
+static int vty_getchars(VIOsPAPRDevice *sdev, uint8_t *buf, int max)
+{
+    VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)sdev;
+    int n = 0;
+
+    while ((n < max) && (dev->out != dev->in)) {
+        buf[n++] = dev->buf[dev->out++ % VTERM_BUFSIZE];
+    }
+
+    return n;
+}
+
+void vty_putchars(VIOsPAPRDevice *sdev, uint8_t *buf, int len)
+{
+    VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)sdev;
+
+    /* FIXME: should check the qemu_chr_fe_write() return value */
+    qemu_chr_fe_write(dev->chardev, buf, len);
+}
+
+static int spapr_vty_init(VIOsPAPRDevice *sdev)
+{
+    VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)sdev;
+
+    if (!dev->chardev) {
+        fprintf(stderr, "spapr-vty: Can't create vty without a chardev!\n");
+        exit(1);
+    }
+
+    qemu_chr_add_handlers(dev->chardev, vty_can_receive,
+                          vty_receive, NULL, dev);
+
+    return 0;
+}
+
+/* Forward declaration */
+static target_ulong h_put_term_char(PowerPCCPU *cpu, sPAPREnvironment *spapr,
+                                    target_ulong opcode, target_ulong *args)
+{
+    target_ulong reg = args[0];
+    target_ulong len = args[1];
+    target_ulong char0_7 = args[2];
+    target_ulong char8_15 = args[3];
+    VIOsPAPRDevice *sdev;
+    uint8_t buf[16];
+
+    sdev = vty_lookup(spapr, reg);
+    if (!sdev) {
+        return H_PARAMETER;
+    }
+
+    if (len > 16) {
+        return H_PARAMETER;
+    }
+
+    *((uint64_t *)buf) = cpu_to_be64(char0_7);
+    *((uint64_t *)buf + 1) = cpu_to_be64(char8_15);
+
+    vty_putchars(sdev, buf, len);
+
+    return H_SUCCESS;
+}
+
+static target_ulong h_get_term_char(PowerPCCPU *cpu, sPAPREnvironment *spapr,
+                                    target_ulong opcode, target_ulong *args)
+{
+    target_ulong reg = args[0];
+    target_ulong *len = args + 0;
+    target_ulong *char0_7 = args + 1;
+    target_ulong *char8_15 = args + 2;
+    VIOsPAPRDevice *sdev;
+    uint8_t buf[16];
+
+    sdev = vty_lookup(spapr, reg);
+    if (!sdev) {
+        return H_PARAMETER;
+    }
+
+    *len = vty_getchars(sdev, buf, sizeof(buf));
+    if (*len < 16) {
+        memset(buf + *len, 0, 16 - *len);
+    }
+
+    *char0_7 = be64_to_cpu(*((uint64_t *)buf));
+    *char8_15 = be64_to_cpu(*((uint64_t *)buf + 1));
+
+    return H_SUCCESS;
+}
+
+void spapr_vty_create(VIOsPAPRBus *bus, CharDriverState *chardev)
+{
+    DeviceState *dev;
+
+    dev = qdev_create(&bus->bus, "spapr-vty");
+    qdev_prop_set_chr(dev, "chardev", chardev);
+    qdev_init_nofail(dev);
+}
+
+static Property spapr_vty_properties[] = {
+    DEFINE_SPAPR_PROPERTIES(VIOsPAPRVTYDevice, sdev),
+    DEFINE_PROP_CHR("chardev", VIOsPAPRVTYDevice, chardev),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void spapr_vty_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    VIOsPAPRDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass);
+
+    k->init = spapr_vty_init;
+    k->dt_name = "vty";
+    k->dt_type = "serial";
+    k->dt_compatible = "hvterm1";
+    dc->props = spapr_vty_properties;
+}
+
+static const 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)
+{
+    VIOsPAPRDevice *sdev, *selected;
+    BusChild *kid;
+
+    /*
+     * To avoid the console bouncing around we want one VTY to be
+     * the "default". We haven't really got anything to go on, so
+     * arbitrarily choose the one with the lowest reg value.
+     */
+
+    selected = NULL;
+    QTAILQ_FOREACH(kid, &bus->bus.children, sibling) {
+        DeviceState *iter = kid->child;
+
+        /* Only look at VTY devices */
+        if (!object_dynamic_cast(OBJECT(iter), "spapr-vty")) {
+            continue;
+        }
+
+        sdev = DO_UPCAST(VIOsPAPRDevice, qdev, iter);
+
+        /* First VTY we've found, so it is selected for now */
+        if (!selected) {
+            selected = sdev;
+            continue;
+        }
+
+        /* Choose VTY with lowest reg value */
+        if (sdev->reg < selected->reg) {
+            selected = sdev;
+        }
+    }
+
+    return selected;
+}
+
+VIOsPAPRDevice *vty_lookup(sPAPREnvironment *spapr, target_ulong reg)
+{
+    VIOsPAPRDevice *sdev;
+
+    sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
+    if (!sdev && reg == 0) {
+        /* Hack for kernel early debug, which always specifies reg==0.
+         * We search all VIO devices, and grab the vty with the lowest
+         * reg.  This attempts to mimic existing PowerVM behaviour
+         * (early debug does work there, despite having no vty with
+         * reg==0. */
+        return spapr_vty_get_default(spapr->vio_bus);
+    }
+
+    return sdev;
+}
+
+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);
+}
+
+type_init(spapr_vty_register_types)
diff --git a/hw/char/tpci200.c b/hw/char/tpci200.c
new file mode 100644 (file)
index 0000000..0170602
--- /dev/null
@@ -0,0 +1,671 @@
+/*
+ * QEMU TEWS TPCI200 IndustryPack carrier emulation
+ *
+ * Copyright (C) 2012 Igalia, S.L.
+ * Author: Alberto Garcia <agarcia@igalia.com>
+ *
+ * This code is licensed under the GNU GPL v2 or (at your option) any
+ * later version.
+ */
+
+#include "ipack.h"
+#include "hw/pci/pci.h"
+#include "qemu/bitops.h"
+#include <stdio.h>
+
+/* #define DEBUG_TPCI */
+
+#ifdef DEBUG_TPCI
+#define DPRINTF(fmt, ...) \
+    do { fprintf(stderr, "TPCI200: " fmt, ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) do { } while (0)
+#endif
+
+#define N_MODULES 4
+
+#define IP_ID_SPACE  2
+#define IP_INT_SPACE 3
+#define IP_IO_SPACE_ADDR_MASK  0x7F
+#define IP_ID_SPACE_ADDR_MASK  0x3F
+#define IP_INT_SPACE_ADDR_MASK 0x3F
+
+#define STATUS_INT(IP, INTNO) BIT((IP) * 2 + (INTNO))
+#define STATUS_TIME(IP)       BIT((IP) + 12)
+#define STATUS_ERR_ANY        0xF00
+
+#define CTRL_CLKRATE          BIT(0)
+#define CTRL_RECOVER          BIT(1)
+#define CTRL_TIME_INT         BIT(2)
+#define CTRL_ERR_INT          BIT(3)
+#define CTRL_INT_EDGE(INTNO)  BIT(4 + (INTNO))
+#define CTRL_INT(INTNO)       BIT(6 + (INTNO))
+
+#define REG_REV_ID    0x00
+#define REG_IP_A_CTRL 0x02
+#define REG_IP_B_CTRL 0x04
+#define REG_IP_C_CTRL 0x06
+#define REG_IP_D_CTRL 0x08
+#define REG_RESET     0x0A
+#define REG_STATUS    0x0C
+#define IP_N_FROM_REG(REG) ((REG) / 2 - 1)
+
+typedef struct {
+    PCIDevice dev;
+    IPackBus bus;
+    MemoryRegion mmio;
+    MemoryRegion io;
+    MemoryRegion las0;
+    MemoryRegion las1;
+    MemoryRegion las2;
+    MemoryRegion las3;
+    bool big_endian[3];
+    uint8_t ctrl[N_MODULES];
+    uint16_t status;
+    uint8_t int_set;
+} TPCI200State;
+
+#define TYPE_TPCI200 "tpci200"
+
+#define TPCI200(obj) \
+    OBJECT_CHECK(TPCI200State, (obj), TYPE_TPCI200)
+
+static const uint8_t local_config_regs[] = {
+    0x00, 0xFF, 0xFF, 0x0F, 0x00, 0xFC, 0xFF, 0x0F, 0x00, 0x00, 0x00,
+    0x0E, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
+    0x00, 0x08, 0x01, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00, 0x00, 0x01,
+    0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0xA0, 0x60, 0x41, 0xD4,
+    0xA2, 0x20, 0x41, 0x14, 0xA2, 0x20, 0x41, 0x14, 0xA2, 0x20, 0x01,
+    0x14, 0x00, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x08, 0x01, 0x02,
+    0x00, 0x04, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x80, 0x02, 0x41,
+    0x00, 0x00, 0x00, 0x00, 0x40, 0x7A, 0x00, 0x52, 0x92, 0x24, 0x02
+};
+
+static void adjust_addr(bool big_endian, hwaddr *addr, unsigned size)
+{
+    /* During 8 bit access in big endian mode,
+       odd and even addresses are swapped */
+    if (big_endian && size == 1) {
+        *addr ^= 1;
+    }
+}
+
+static uint64_t adjust_value(bool big_endian, uint64_t *val, unsigned size)
+{
+    /* Local spaces only support 8/16 bit access,
+     * so there's no need to care for sizes > 2 */
+    if (big_endian && size == 2) {
+        *val = bswap16(*val);
+    }
+    return *val;
+}
+
+static void tpci200_set_irq(void *opaque, int intno, int level)
+{
+    IPackDevice *ip = opaque;
+    IPackBus *bus = IPACK_BUS(qdev_get_parent_bus(DEVICE(ip)));
+    PCIDevice *pcidev = PCI_DEVICE(BUS(bus)->parent);
+    TPCI200State *dev = TPCI200(pcidev);
+    unsigned ip_n = ip->slot;
+    uint16_t prev_status = dev->status;
+
+    assert(ip->slot >= 0 && ip->slot < N_MODULES);
+
+    /* The requested interrupt must be enabled in the IP CONTROL
+     * register */
+    if (!(dev->ctrl[ip_n] & CTRL_INT(intno))) {
+        return;
+    }
+
+    /* Update the interrupt status in the IP STATUS register */
+    if (level) {
+        dev->status |=  STATUS_INT(ip_n, intno);
+    } else {
+        dev->status &= ~STATUS_INT(ip_n, intno);
+    }
+
+    /* Return if there are no changes */
+    if (dev->status == prev_status) {
+        return;
+    }
+
+    DPRINTF("IP %u INT%u#: %u\n", ip_n, intno, level);
+
+    /* Check if the interrupt is edge sensitive */
+    if (dev->ctrl[ip_n] & CTRL_INT_EDGE(intno)) {
+        if (level) {
+            qemu_set_irq(dev->dev.irq[0], !dev->int_set);
+            qemu_set_irq(dev->dev.irq[0],  dev->int_set);
+        }
+    } else {
+        unsigned i, j;
+        uint16_t level_status = dev->status;
+
+        /* Check if there are any level sensitive interrupts set by
+           removing the ones that are edge sensitive from the status
+           register */
+        for (i = 0; i < N_MODULES; i++) {
+            for (j = 0; j < 2; j++) {
+                if (dev->ctrl[i] & CTRL_INT_EDGE(j)) {
+                    level_status &= ~STATUS_INT(i, j);
+                }
+            }
+        }
+
+        if (level_status && !dev->int_set) {
+            qemu_irq_raise(dev->dev.irq[0]);
+            dev->int_set = 1;
+        } else if (!level_status && dev->int_set) {
+            qemu_irq_lower(dev->dev.irq[0]);
+            dev->int_set = 0;
+        }
+    }
+}
+
+static uint64_t tpci200_read_cfg(void *opaque, hwaddr addr, unsigned size)
+{
+    TPCI200State *s = opaque;
+    uint8_t ret = 0;
+    if (addr < ARRAY_SIZE(local_config_regs)) {
+        ret = local_config_regs[addr];
+    }
+    /* Endianness is stored in the first bit of these registers */
+    if ((addr == 0x2b && s->big_endian[0]) ||
+        (addr == 0x2f && s->big_endian[1]) ||
+        (addr == 0x33 && s->big_endian[2])) {
+        ret |= 1;
+    }
+    DPRINTF("Read from LCR 0x%x: 0x%x\n", (unsigned) addr, (unsigned) ret);
+    return ret;
+}
+
+static void tpci200_write_cfg(void *opaque, hwaddr addr, uint64_t val,
+                              unsigned size)
+{
+    TPCI200State *s = opaque;
+    /* Endianness is stored in the first bit of these registers */
+    if (addr == 0x2b || addr == 0x2f || addr == 0x33) {
+        unsigned las = (addr - 0x2b) / 4;
+        s->big_endian[las] = val & 1;
+        DPRINTF("LAS%u big endian mode: %u\n", las, (unsigned) val & 1);
+    } else {
+        DPRINTF("Write to LCR 0x%x: 0x%x\n", (unsigned) addr, (unsigned) val);
+    }
+}
+
+static uint64_t tpci200_read_las0(void *opaque, hwaddr addr, unsigned size)
+{
+    TPCI200State *s = opaque;
+    uint64_t ret = 0;
+
+    switch (addr) {
+
+    case REG_REV_ID:
+        DPRINTF("Read REVISION ID\n"); /* Current value is 0x00 */
+        break;
+
+    case REG_IP_A_CTRL:
+    case REG_IP_B_CTRL:
+    case REG_IP_C_CTRL:
+    case REG_IP_D_CTRL:
+        {
+            unsigned ip_n = IP_N_FROM_REG(addr);
+            ret = s->ctrl[ip_n];
+            DPRINTF("Read IP %c CONTROL: 0x%x\n", 'A' + ip_n, (unsigned) ret);
+        }
+        break;
+
+    case REG_RESET:
+        DPRINTF("Read RESET\n"); /* Not implemented */
+        break;
+
+    case REG_STATUS:
+        ret = s->status;
+        DPRINTF("Read STATUS: 0x%x\n", (unsigned) ret);
+        break;
+
+    /* Reserved */
+    default:
+        DPRINTF("Unsupported read from LAS0 0x%x\n", (unsigned) addr);
+        break;
+    }
+
+    return adjust_value(s->big_endian[0], &ret, size);
+}
+
+static void tpci200_write_las0(void *opaque, hwaddr addr, uint64_t val,
+                               unsigned size)
+{
+    TPCI200State *s = opaque;
+
+    adjust_value(s->big_endian[0], &val, size);
+
+    switch (addr) {
+
+    case REG_REV_ID:
+        DPRINTF("Write Revision ID: 0x%x\n", (unsigned) val); /* No effect */
+        break;
+
+    case REG_IP_A_CTRL:
+    case REG_IP_B_CTRL:
+    case REG_IP_C_CTRL:
+    case REG_IP_D_CTRL:
+        {
+            unsigned ip_n = IP_N_FROM_REG(addr);
+            s->ctrl[ip_n] = val;
+            DPRINTF("Write IP %c CONTROL: 0x%x\n", 'A' + ip_n, (unsigned) val);
+        }
+        break;
+
+    case REG_RESET:
+        DPRINTF("Write RESET: 0x%x\n", (unsigned) val); /* Not implemented */
+        break;
+
+    case REG_STATUS:
+        {
+            unsigned i;
+
+            for (i = 0; i < N_MODULES; i++) {
+                IPackDevice *ip = ipack_device_find(&s->bus, i);
+
+                if (ip != NULL) {
+                    if (val & STATUS_INT(i, 0)) {
+                        DPRINTF("Clear IP %c INT0# status\n", 'A' + i);
+                        qemu_irq_lower(ip->irq[0]);
+                    }
+                    if (val & STATUS_INT(i, 1)) {
+                        DPRINTF("Clear IP %c INT1# status\n", 'A' + i);
+                        qemu_irq_lower(ip->irq[1]);
+                    }
+                }
+
+                if (val & STATUS_TIME(i)) {
+                    DPRINTF("Clear IP %c timeout\n", 'A' + i);
+                    s->status &= ~STATUS_TIME(i);
+                }
+            }
+
+            if (val & STATUS_ERR_ANY) {
+                DPRINTF("Unexpected write to STATUS register: 0x%x\n",
+                        (unsigned) val);
+            }
+        }
+        break;
+
+    /* Reserved */
+    default:
+        DPRINTF("Unsupported write to LAS0 0x%x: 0x%x\n",
+                (unsigned) addr, (unsigned) val);
+        break;
+    }
+}
+
+static uint64_t tpci200_read_las1(void *opaque, hwaddr addr, unsigned size)
+{
+    TPCI200State *s = opaque;
+    IPackDevice *ip;
+    uint64_t ret = 0;
+    unsigned ip_n, space;
+    uint8_t offset;
+
+    adjust_addr(s->big_endian[1], &addr, size);
+
+    /*
+     * The address is divided into the IP module number (0-4), the IP
+     * address space (I/O, ID, INT) and the offset within that space.
+     */
+    ip_n = addr >> 8;
+    space = (addr >> 6) & 3;
+    ip = ipack_device_find(&s->bus, ip_n);
+
+    if (ip == NULL) {
+        DPRINTF("Read LAS1: IP module %u not installed\n", ip_n);
+    } else {
+        IPackDeviceClass *k = IPACK_DEVICE_GET_CLASS(ip);
+        switch (space) {
+
+        case IP_ID_SPACE:
+            offset = addr & IP_ID_SPACE_ADDR_MASK;
+            if (k->id_read) {
+                ret = k->id_read(ip, offset);
+            }
+            break;
+
+        case IP_INT_SPACE:
+            offset = addr & IP_INT_SPACE_ADDR_MASK;
+
+            /* Read address 0 to ACK IP INT0# and address 2 to ACK IP INT1# */
+            if (offset == 0 || offset == 2) {
+                unsigned intno = offset / 2;
+                bool int_set = s->status & STATUS_INT(ip_n, intno);
+                bool int_edge_sensitive = s->ctrl[ip_n] & CTRL_INT_EDGE(intno);
+                if (int_set && !int_edge_sensitive) {
+                    qemu_irq_lower(ip->irq[intno]);
+                }
+            }
+
+            if (k->int_read) {
+                ret = k->int_read(ip, offset);
+            }
+            break;
+
+        default:
+            offset = addr & IP_IO_SPACE_ADDR_MASK;
+            if (k->io_read) {
+                ret = k->io_read(ip, offset);
+            }
+            break;
+        }
+    }
+
+    return adjust_value(s->big_endian[1], &ret, size);
+}
+
+static void tpci200_write_las1(void *opaque, hwaddr addr, uint64_t val,
+                               unsigned size)
+{
+    TPCI200State *s = opaque;
+    IPackDevice *ip;
+    unsigned ip_n, space;
+    uint8_t offset;
+
+    adjust_addr(s->big_endian[1], &addr, size);
+    adjust_value(s->big_endian[1], &val, size);
+
+    /*
+     * The address is divided into the IP module number, the IP
+     * address space (I/O, ID, INT) and the offset within that space.
+     */
+    ip_n = addr >> 8;
+    space = (addr >> 6) & 3;
+    ip = ipack_device_find(&s->bus, ip_n);
+
+    if (ip == NULL) {
+        DPRINTF("Write LAS1: IP module %u not installed\n", ip_n);
+    } else {
+        IPackDeviceClass *k = IPACK_DEVICE_GET_CLASS(ip);
+        switch (space) {
+
+        case IP_ID_SPACE:
+            offset = addr & IP_ID_SPACE_ADDR_MASK;
+            if (k->id_write) {
+                k->id_write(ip, offset, val);
+            }
+            break;
+
+        case IP_INT_SPACE:
+            offset = addr & IP_INT_SPACE_ADDR_MASK;
+            if (k->int_write) {
+                k->int_write(ip, offset, val);
+            }
+            break;
+
+        default:
+            offset = addr & IP_IO_SPACE_ADDR_MASK;
+            if (k->io_write) {
+                k->io_write(ip, offset, val);
+            }
+            break;
+        }
+    }
+}
+
+static uint64_t tpci200_read_las2(void *opaque, hwaddr addr, unsigned size)
+{
+    TPCI200State *s = opaque;
+    IPackDevice *ip;
+    uint64_t ret = 0;
+    unsigned ip_n;
+    uint32_t offset;
+
+    adjust_addr(s->big_endian[2], &addr, size);
+
+    /*
+     * The address is divided into the IP module number and the offset
+     * within the IP module MEM space.
+     */
+    ip_n = addr >> 23;
+    offset = addr & 0x7fffff;
+    ip = ipack_device_find(&s->bus, ip_n);
+
+    if (ip == NULL) {
+        DPRINTF("Read LAS2: IP module %u not installed\n", ip_n);
+    } else {
+        IPackDeviceClass *k = IPACK_DEVICE_GET_CLASS(ip);
+        if (k->mem_read16) {
+            ret = k->mem_read16(ip, offset);
+        }
+    }
+
+    return adjust_value(s->big_endian[2], &ret, size);
+}
+
+static void tpci200_write_las2(void *opaque, hwaddr addr, uint64_t val,
+                               unsigned size)
+{
+    TPCI200State *s = opaque;
+    IPackDevice *ip;
+    unsigned ip_n;
+    uint32_t offset;
+
+    adjust_addr(s->big_endian[2], &addr, size);
+    adjust_value(s->big_endian[2], &val, size);
+
+    /*
+     * The address is divided into the IP module number and the offset
+     * within the IP module MEM space.
+     */
+    ip_n = addr >> 23;
+    offset = addr & 0x7fffff;
+    ip = ipack_device_find(&s->bus, ip_n);
+
+    if (ip == NULL) {
+        DPRINTF("Write LAS2: IP module %u not installed\n", ip_n);
+    } else {
+        IPackDeviceClass *k = IPACK_DEVICE_GET_CLASS(ip);
+        if (k->mem_write16) {
+            k->mem_write16(ip, offset, val);
+        }
+    }
+}
+
+static uint64_t tpci200_read_las3(void *opaque, hwaddr addr, unsigned size)
+{
+    TPCI200State *s = opaque;
+    IPackDevice *ip;
+    uint64_t ret = 0;
+    /*
+     * The address is divided into the IP module number and the offset
+     * within the IP module MEM space.
+     */
+    unsigned ip_n = addr >> 22;
+    uint32_t offset = addr & 0x3fffff;
+
+    ip = ipack_device_find(&s->bus, ip_n);
+
+    if (ip == NULL) {
+        DPRINTF("Read LAS3: IP module %u not installed\n", ip_n);
+    } else {
+        IPackDeviceClass *k = IPACK_DEVICE_GET_CLASS(ip);
+        if (k->mem_read8) {
+            ret = k->mem_read8(ip, offset);
+        }
+    }
+
+    return ret;
+}
+
+static void tpci200_write_las3(void *opaque, hwaddr addr, uint64_t val,
+                               unsigned size)
+{
+    TPCI200State *s = opaque;
+    IPackDevice *ip;
+    /*
+     * The address is divided into the IP module number and the offset
+     * within the IP module MEM space.
+     */
+    unsigned ip_n = addr >> 22;
+    uint32_t offset = addr & 0x3fffff;
+
+    ip = ipack_device_find(&s->bus, ip_n);
+
+    if (ip == NULL) {
+        DPRINTF("Write LAS3: IP module %u not installed\n", ip_n);
+    } else {
+        IPackDeviceClass *k = IPACK_DEVICE_GET_CLASS(ip);
+        if (k->mem_write8) {
+            k->mem_write8(ip, offset, val);
+        }
+    }
+}
+
+static const MemoryRegionOps tpci200_cfg_ops = {
+    .read = tpci200_read_cfg,
+    .write = tpci200_write_cfg,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid =  {
+        .min_access_size = 1,
+        .max_access_size = 4
+    },
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 1
+    }
+};
+
+static const MemoryRegionOps tpci200_las0_ops = {
+    .read = tpci200_read_las0,
+    .write = tpci200_write_las0,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid =  {
+        .min_access_size = 2,
+        .max_access_size = 2
+    }
+};
+
+static const MemoryRegionOps tpci200_las1_ops = {
+    .read = tpci200_read_las1,
+    .write = tpci200_write_las1,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid =  {
+        .min_access_size = 1,
+        .max_access_size = 2
+    }
+};
+
+static const MemoryRegionOps tpci200_las2_ops = {
+    .read = tpci200_read_las2,
+    .write = tpci200_write_las2,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid =  {
+        .min_access_size = 1,
+        .max_access_size = 2
+    }
+};
+
+static const MemoryRegionOps tpci200_las3_ops = {
+    .read = tpci200_read_las3,
+    .write = tpci200_write_las3,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid =  {
+        .min_access_size = 1,
+        .max_access_size = 1
+    }
+};
+
+static int tpci200_initfn(PCIDevice *pci_dev)
+{
+    TPCI200State *s = TPCI200(pci_dev);
+    uint8_t *c = s->dev.config;
+
+    pci_set_word(c + PCI_COMMAND, 0x0003);
+    pci_set_word(c + PCI_STATUS,  0x0280);
+
+    pci_set_byte(c + PCI_INTERRUPT_PIN, 0x01); /* Interrupt pin A */
+
+    pci_set_byte(c + PCI_CAPABILITY_LIST, 0x40);
+    pci_set_long(c + 0x40, 0x48014801);
+    pci_set_long(c + 0x48, 0x00024C06);
+    pci_set_long(c + 0x4C, 0x00000003);
+
+    memory_region_init_io(&s->mmio, &tpci200_cfg_ops,
+                          s, "tpci200_mmio", 128);
+    memory_region_init_io(&s->io,   &tpci200_cfg_ops,
+                          s, "tpci200_io",   128);
+    memory_region_init_io(&s->las0, &tpci200_las0_ops,
+                          s, "tpci200_las0", 256);
+    memory_region_init_io(&s->las1, &tpci200_las1_ops,
+                          s, "tpci200_las1", 1024);
+    memory_region_init_io(&s->las2, &tpci200_las2_ops,
+                          s, "tpci200_las2", 1024*1024*32);
+    memory_region_init_io(&s->las3, &tpci200_las3_ops,
+                          s, "tpci200_las3", 1024*1024*16);
+    pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mmio);
+    pci_register_bar(&s->dev, 1, PCI_BASE_ADDRESS_SPACE_IO,     &s->io);
+    pci_register_bar(&s->dev, 2, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->las0);
+    pci_register_bar(&s->dev, 3, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->las1);
+    pci_register_bar(&s->dev, 4, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->las2);
+    pci_register_bar(&s->dev, 5, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->las3);
+
+    ipack_bus_new_inplace(&s->bus, DEVICE(&s->dev), NULL,
+                          N_MODULES, tpci200_set_irq);
+
+    return 0;
+}
+
+static void tpci200_exitfn(PCIDevice *pci_dev)
+{
+    TPCI200State *s = TPCI200(pci_dev);
+
+    memory_region_destroy(&s->mmio);
+    memory_region_destroy(&s->io);
+    memory_region_destroy(&s->las0);
+    memory_region_destroy(&s->las1);
+    memory_region_destroy(&s->las2);
+    memory_region_destroy(&s->las3);
+}
+
+static const VMStateDescription vmstate_tpci200 = {
+    .name = "tpci200",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_PCI_DEVICE(dev, TPCI200State),
+        VMSTATE_BOOL_ARRAY(big_endian, TPCI200State, 3),
+        VMSTATE_UINT8_ARRAY(ctrl, TPCI200State, N_MODULES),
+        VMSTATE_UINT16(status, TPCI200State),
+        VMSTATE_UINT8(int_set, TPCI200State),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void tpci200_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = tpci200_initfn;
+    k->exit = tpci200_exitfn;
+    k->vendor_id = PCI_VENDOR_ID_TEWS;
+    k->device_id = PCI_DEVICE_ID_TEWS_TPCI200;
+    k->class_id = PCI_CLASS_BRIDGE_OTHER;
+    k->subsystem_vendor_id = PCI_VENDOR_ID_TEWS;
+    k->subsystem_id = 0x300A;
+    dc->desc = "TEWS TPCI200 IndustryPack carrier";
+    dc->vmsd = &vmstate_tpci200;
+}
+
+static const TypeInfo tpci200_info = {
+    .name          = TYPE_TPCI200,
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(TPCI200State),
+    .class_init    = tpci200_class_init,
+};
+
+static void tpci200_register_types(void)
+{
+    type_register_static(&tpci200_info);
+}
+
+type_init(tpci200_register_types)
diff --git a/hw/char/virtio-console.c b/hw/char/virtio-console.c
new file mode 100644 (file)
index 0000000..31f672c
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ * Virtio Console and Generic Serial Port Devices
+ *
+ * Copyright Red Hat, Inc. 2009, 2010
+ *
+ * Authors:
+ *  Amit Shah <amit.shah@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ */
+
+#include "char/char.h"
+#include "qemu/error-report.h"
+#include "trace.h"
+#include "hw/virtio/virtio-serial.h"
+
+typedef struct VirtConsole {
+    VirtIOSerialPort port;
+    CharDriverState *chr;
+} VirtConsole;
+
+/*
+ * Callback function that's called from chardevs when backend becomes
+ * writable.
+ */
+static gboolean chr_write_unblocked(GIOChannel *chan, GIOCondition cond,
+                                    void *opaque)
+{
+    VirtConsole *vcon = opaque;
+
+    virtio_serial_throttle_port(&vcon->port, false);
+    return FALSE;
+}
+
+/* Callback function that's called when the guest sends us data */
+static ssize_t flush_buf(VirtIOSerialPort *port, const uint8_t *buf, size_t len)
+{
+    VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
+    ssize_t ret;
+
+    if (!vcon->chr) {
+        /* If there's no backend, we can just say we consumed all data. */
+        return len;
+    }
+
+    ret = qemu_chr_fe_write(vcon->chr, buf, len);
+    trace_virtio_console_flush_buf(port->id, len, ret);
+
+    if (ret <= 0) {
+        VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_GET_CLASS(port);
+
+        /*
+         * Ideally we'd get a better error code than just -1, but
+         * that's what the chardev interface gives us right now.  If
+         * we had a finer-grained message, like -EPIPE, we could close
+         * this connection.
+         */
+        ret = 0;
+        if (!k->is_console) {
+            virtio_serial_throttle_port(port, true);
+            qemu_chr_fe_add_watch(vcon->chr, G_IO_OUT, chr_write_unblocked,
+                                  vcon);
+        }
+    }
+    return ret;
+}
+
+/* Callback function that's called when the guest opens/closes the port */
+static void set_guest_connected(VirtIOSerialPort *port, int guest_connected)
+{
+    VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
+
+    if (!vcon->chr) {
+        return;
+    }
+    qemu_chr_fe_set_open(vcon->chr, guest_connected);
+}
+
+/* Readiness of the guest to accept data on a port */
+static int chr_can_read(void *opaque)
+{
+    VirtConsole *vcon = opaque;
+
+    return virtio_serial_guest_ready(&vcon->port);
+}
+
+/* Send data from a char device over to the guest */
+static void chr_read(void *opaque, const uint8_t *buf, int size)
+{
+    VirtConsole *vcon = opaque;
+
+    trace_virtio_console_chr_read(vcon->port.id, size);
+    virtio_serial_write(&vcon->port, buf, size);
+}
+
+static void chr_event(void *opaque, int event)
+{
+    VirtConsole *vcon = opaque;
+
+    trace_virtio_console_chr_event(vcon->port.id, event);
+    switch (event) {
+    case CHR_EVENT_OPENED:
+        virtio_serial_open(&vcon->port);
+        break;
+    case CHR_EVENT_CLOSED:
+        virtio_serial_close(&vcon->port);
+        break;
+    }
+}
+
+static int virtconsole_initfn(VirtIOSerialPort *port)
+{
+    VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
+    VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_GET_CLASS(port);
+
+    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;
+    }
+
+    if (vcon->chr) {
+        vcon->chr->explicit_fe_open = 1;
+        qemu_chr_add_handlers(vcon->chr, chr_can_read, chr_read, chr_event,
+                              vcon);
+    }
+
+    return 0;
+}
+
+static Property virtconsole_properties[] = {
+    DEFINE_PROP_CHR("chardev", VirtConsole, chr),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void virtconsole_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_CLASS(klass);
+
+    k->is_console = true;
+    k->init = virtconsole_initfn;
+    k->have_data = flush_buf;
+    k->set_guest_connected = set_guest_connected;
+    dc->props = virtconsole_properties;
+}
+
+static const TypeInfo virtconsole_info = {
+    .name          = "virtconsole",
+    .parent        = TYPE_VIRTIO_SERIAL_PORT,
+    .instance_size = sizeof(VirtConsole),
+    .class_init    = virtconsole_class_init,
+};
+
+static Property virtserialport_properties[] = {
+    DEFINE_PROP_CHR("chardev", VirtConsole, chr),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void virtserialport_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_CLASS(klass);
+
+    k->init = virtconsole_initfn;
+    k->have_data = flush_buf;
+    k->set_guest_connected = set_guest_connected;
+    dc->props = virtserialport_properties;
+}
+
+static const TypeInfo virtserialport_info = {
+    .name          = "virtserialport",
+    .parent        = TYPE_VIRTIO_SERIAL_PORT,
+    .instance_size = sizeof(VirtConsole),
+    .class_init    = virtserialport_class_init,
+};
+
+static void virtconsole_register_types(void)
+{
+    type_register_static(&virtconsole_info);
+    type_register_static(&virtserialport_info);
+}
+
+type_init(virtconsole_register_types)
diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c
new file mode 100644 (file)
index 0000000..1dba8ab
--- /dev/null
@@ -0,0 +1,1018 @@
+/*
+ * A bus for connecting virtio serial and console ports
+ *
+ * Copyright (C) 2009, 2010 Red Hat, Inc.
+ *
+ * Author(s):
+ *  Amit Shah <amit.shah@redhat.com>
+ *
+ * Some earlier parts are:
+ *  Copyright IBM, Corp. 2008
+ * authored by
+ *  Christian Ehrhardt <ehrhardt@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.
+ *
+ * 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/iov.h"
+#include "monitor/monitor.h"
+#include "qemu/queue.h"
+#include "hw/sysbus.h"
+#include "trace.h"
+#include "hw/virtio/virtio-serial.h"
+
+static VirtIOSerialPort *find_port_by_id(VirtIOSerial *vser, uint32_t id)
+{
+    VirtIOSerialPort *port;
+
+    if (id == VIRTIO_CONSOLE_BAD_ID) {
+        return NULL;
+    }
+
+    QTAILQ_FOREACH(port, &vser->ports, next) {
+        if (port->id == id)
+            return port;
+    }
+    return NULL;
+}
+
+static VirtIOSerialPort *find_port_by_vq(VirtIOSerial *vser, VirtQueue *vq)
+{
+    VirtIOSerialPort *port;
+
+    QTAILQ_FOREACH(port, &vser->ports, next) {
+        if (port->ivq == vq || port->ovq == vq)
+            return port;
+    }
+    return NULL;
+}
+
+static bool use_multiport(VirtIOSerial *vser)
+{
+    return vser->vdev.guest_features & (1 << VIRTIO_CONSOLE_F_MULTIPORT);
+}
+
+static size_t write_to_port(VirtIOSerialPort *port,
+                            const uint8_t *buf, size_t size)
+{
+    VirtQueueElement elem;
+    VirtQueue *vq;
+    size_t offset;
+
+    vq = port->ivq;
+    if (!virtio_queue_ready(vq)) {
+        return 0;
+    }
+
+    offset = 0;
+    while (offset < size) {
+        size_t len;
+
+        if (!virtqueue_pop(vq, &elem)) {
+            break;
+        }
+
+        len = iov_from_buf(elem.in_sg, elem.in_num, 0,
+                           buf + offset, size - offset);
+        offset += len;
+
+        virtqueue_push(vq, &elem, len);
+    }
+
+    virtio_notify(&port->vser->vdev, vq);
+    return offset;
+}
+
+static void discard_vq_data(VirtQueue *vq, VirtIODevice *vdev)
+{
+    VirtQueueElement elem;
+
+    if (!virtio_queue_ready(vq)) {
+        return;
+    }
+    while (virtqueue_pop(vq, &elem)) {
+        virtqueue_push(vq, &elem, 0);
+    }
+    virtio_notify(vdev, vq);
+}
+
+static void do_flush_queued_data(VirtIOSerialPort *port, VirtQueue *vq,
+                                 VirtIODevice *vdev)
+{
+    VirtIOSerialPortClass *vsc;
+
+    assert(port);
+    assert(virtio_queue_ready(vq));
+
+    vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port);
+
+    while (!port->throttled) {
+        unsigned int i;
+
+        /* Pop an elem only if we haven't left off a previous one mid-way */
+        if (!port->elem.out_num) {
+            if (!virtqueue_pop(vq, &port->elem)) {
+                break;
+            }
+            port->iov_idx = 0;
+            port->iov_offset = 0;
+        }
+
+        for (i = port->iov_idx; i < port->elem.out_num; i++) {
+            size_t buf_size;
+            ssize_t ret;
+
+            buf_size = port->elem.out_sg[i].iov_len - port->iov_offset;
+            ret = vsc->have_data(port,
+                                  port->elem.out_sg[i].iov_base
+                                  + port->iov_offset,
+                                  buf_size);
+            if (port->throttled) {
+                port->iov_idx = i;
+                if (ret > 0) {
+                    port->iov_offset += ret;
+                }
+                break;
+            }
+            port->iov_offset = 0;
+        }
+        if (port->throttled) {
+            break;
+        }
+        virtqueue_push(vq, &port->elem, 0);
+        port->elem.out_num = 0;
+    }
+    virtio_notify(vdev, vq);
+}
+
+static void flush_queued_data(VirtIOSerialPort *port)
+{
+    assert(port);
+
+    if (!virtio_queue_ready(port->ovq)) {
+        return;
+    }
+    do_flush_queued_data(port, port->ovq, &port->vser->vdev);
+}
+
+static size_t send_control_msg(VirtIOSerial *vser, void *buf, size_t len)
+{
+    VirtQueueElement elem;
+    VirtQueue *vq;
+
+    vq = vser->c_ivq;
+    if (!virtio_queue_ready(vq)) {
+        return 0;
+    }
+    if (!virtqueue_pop(vq, &elem)) {
+        return 0;
+    }
+
+    memcpy(elem.in_sg[0].iov_base, buf, len);
+
+    virtqueue_push(vq, &elem, len);
+    virtio_notify(&vser->vdev, vq);
+    return len;
+}
+
+static size_t send_control_event(VirtIOSerial *vser, uint32_t port_id,
+                                 uint16_t event, uint16_t value)
+{
+    struct virtio_console_control cpkt;
+
+    stl_p(&cpkt.id, port_id);
+    stw_p(&cpkt.event, event);
+    stw_p(&cpkt.value, value);
+
+    trace_virtio_serial_send_control_event(port_id, event, value);
+    return send_control_msg(vser, &cpkt, sizeof(cpkt));
+}
+
+/* Functions for use inside qemu to open and read from/write to ports */
+int virtio_serial_open(VirtIOSerialPort *port)
+{
+    /* Don't allow opening an already-open port */
+    if (port->host_connected) {
+        return 0;
+    }
+    /* Send port open notification to the guest */
+    port->host_connected = true;
+    send_control_event(port->vser, port->id, VIRTIO_CONSOLE_PORT_OPEN, 1);
+
+    return 0;
+}
+
+int virtio_serial_close(VirtIOSerialPort *port)
+{
+    port->host_connected = false;
+    /*
+     * If there's any data the guest sent which the app didn't
+     * consume, reset the throttling flag and discard the data.
+     */
+    port->throttled = false;
+    discard_vq_data(port->ovq, &port->vser->vdev);
+
+    send_control_event(port->vser, port->id, VIRTIO_CONSOLE_PORT_OPEN, 0);
+
+    return 0;
+}
+
+/* Individual ports/apps call this function to write to the guest. */
+ssize_t virtio_serial_write(VirtIOSerialPort *port, const uint8_t *buf,
+                            size_t size)
+{
+    if (!port || !port->host_connected || !port->guest_connected) {
+        return 0;
+    }
+    return write_to_port(port, buf, size);
+}
+
+/*
+ * Readiness of the guest to accept data on a port.
+ * Returns max. data the guest can receive
+ */
+size_t virtio_serial_guest_ready(VirtIOSerialPort *port)
+{
+    VirtQueue *vq = port->ivq;
+    unsigned int bytes;
+
+    if (!virtio_queue_ready(vq) ||
+        !(port->vser->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK) ||
+        virtio_queue_empty(vq)) {
+        return 0;
+    }
+    if (use_multiport(port->vser) && !port->guest_connected) {
+        return 0;
+    }
+    virtqueue_get_avail_bytes(vq, &bytes, NULL, 4096, 0);
+    return bytes;
+}
+
+static void flush_queued_data_bh(void *opaque)
+{
+    VirtIOSerialPort *port = opaque;
+
+    flush_queued_data(port);
+}
+
+void virtio_serial_throttle_port(VirtIOSerialPort *port, bool throttle)
+{
+    if (!port) {
+        return;
+    }
+
+    trace_virtio_serial_throttle_port(port->id, throttle);
+    port->throttled = throttle;
+    if (throttle) {
+        return;
+    }
+    qemu_bh_schedule(port->bh);
+}
+
+/* Guest wants to notify us of some event */
+static void handle_control_message(VirtIOSerial *vser, void *buf, size_t len)
+{
+    struct VirtIOSerialPort *port;
+    VirtIOSerialPortClass *vsc;
+    struct virtio_console_control cpkt, *gcpkt;
+    uint8_t *buffer;
+    size_t buffer_len;
+
+    gcpkt = buf;
+
+    if (len < sizeof(cpkt)) {
+        /* The guest sent an invalid control packet */
+        return;
+    }
+
+    cpkt.event = lduw_p(&gcpkt->event);
+    cpkt.value = lduw_p(&gcpkt->value);
+
+    trace_virtio_serial_handle_control_message(cpkt.event, cpkt.value);
+
+    if (cpkt.event == VIRTIO_CONSOLE_DEVICE_READY) {
+        if (!cpkt.value) {
+            error_report("virtio-serial-bus: Guest failure in adding device %s",
+                         vser->bus.qbus.name);
+            return;
+        }
+        /*
+         * The device is up, we can now tell the device about all the
+         * ports we have here.
+         */
+        QTAILQ_FOREACH(port, &vser->ports, next) {
+            send_control_event(vser, port->id, VIRTIO_CONSOLE_PORT_ADD, 1);
+        }
+        return;
+    }
+
+    port = find_port_by_id(vser, ldl_p(&gcpkt->id));
+    if (!port) {
+        error_report("virtio-serial-bus: Unexpected port id %u for device %s",
+                     ldl_p(&gcpkt->id), vser->bus.qbus.name);
+        return;
+    }
+
+    trace_virtio_serial_handle_control_message_port(port->id);
+
+    vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port);
+
+    switch(cpkt.event) {
+    case VIRTIO_CONSOLE_PORT_READY:
+        if (!cpkt.value) {
+            error_report("virtio-serial-bus: Guest failure in adding port %u for device %s",
+                         port->id, vser->bus.qbus.name);
+            break;
+        }
+        /*
+         * Now that we know the guest asked for the port name, we're
+         * sure the guest has initialised whatever state is necessary
+         * for this port. Now's a good time to let the guest know if
+         * this port is a console port so that the guest can hook it
+         * up to hvc.
+         */
+        if (vsc->is_console) {
+            send_control_event(vser, port->id, VIRTIO_CONSOLE_CONSOLE_PORT, 1);
+        }
+
+        if (port->name) {
+            stl_p(&cpkt.id, port->id);
+            stw_p(&cpkt.event, VIRTIO_CONSOLE_PORT_NAME);
+            stw_p(&cpkt.value, 1);
+
+            buffer_len = sizeof(cpkt) + strlen(port->name) + 1;
+            buffer = g_malloc(buffer_len);
+
+            memcpy(buffer, &cpkt, sizeof(cpkt));
+            memcpy(buffer + sizeof(cpkt), port->name, strlen(port->name));
+            buffer[buffer_len - 1] = 0;
+
+            send_control_msg(vser, buffer, buffer_len);
+            g_free(buffer);
+        }
+
+        if (port->host_connected) {
+            send_control_event(vser, port->id, VIRTIO_CONSOLE_PORT_OPEN, 1);
+        }
+
+        /*
+         * When the guest has asked us for this information it means
+         * the guest is all setup and has its virtqueues
+         * initialised. If some app is interested in knowing about
+         * this event, let it know.
+         */
+        if (vsc->guest_ready) {
+            vsc->guest_ready(port);
+        }
+        break;
+
+    case VIRTIO_CONSOLE_PORT_OPEN:
+        port->guest_connected = cpkt.value;
+        if (vsc->set_guest_connected) {
+            /* Send the guest opened notification if an app is interested */
+            vsc->set_guest_connected(port, cpkt.value);
+        }
+        break;
+    }
+}
+
+static void control_in(VirtIODevice *vdev, VirtQueue *vq)
+{
+}
+
+static void control_out(VirtIODevice *vdev, VirtQueue *vq)
+{
+    VirtQueueElement elem;
+    VirtIOSerial *vser;
+    uint8_t *buf;
+    size_t len;
+
+    vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
+
+    len = 0;
+    buf = NULL;
+    while (virtqueue_pop(vq, &elem)) {
+        size_t cur_len;
+
+        cur_len = iov_size(elem.out_sg, elem.out_num);
+        /*
+         * Allocate a new buf only if we didn't have one previously or
+         * if the size of the buf differs
+         */
+        if (cur_len > len) {
+            g_free(buf);
+
+            buf = g_malloc(cur_len);
+            len = cur_len;
+        }
+        iov_to_buf(elem.out_sg, elem.out_num, 0, buf, cur_len);
+
+        handle_control_message(vser, buf, cur_len);
+        virtqueue_push(vq, &elem, 0);
+    }
+    g_free(buf);
+    virtio_notify(vdev, vq);
+}
+
+/* Guest wrote something to some port. */
+static void handle_output(VirtIODevice *vdev, VirtQueue *vq)
+{
+    VirtIOSerial *vser;
+    VirtIOSerialPort *port;
+
+    vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
+    port = find_port_by_vq(vser, vq);
+
+    if (!port || !port->host_connected) {
+        discard_vq_data(vq, vdev);
+        return;
+    }
+
+    if (!port->throttled) {
+        do_flush_queued_data(port, vq, vdev);
+        return;
+    }
+}
+
+static void handle_input(VirtIODevice *vdev, VirtQueue *vq)
+{
+}
+
+static uint32_t get_features(VirtIODevice *vdev, uint32_t features)
+{
+    VirtIOSerial *vser;
+
+    vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
+
+    if (vser->bus.max_nr_ports > 1) {
+        features |= (1 << VIRTIO_CONSOLE_F_MULTIPORT);
+    }
+    return features;
+}
+
+/* Guest requested config info */
+static void get_config(VirtIODevice *vdev, uint8_t *config_data)
+{
+    VirtIOSerial *vser;
+
+    vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
+    memcpy(config_data, &vser->config, sizeof(struct virtio_console_config));
+}
+
+static void set_config(VirtIODevice *vdev, const uint8_t *config_data)
+{
+    struct virtio_console_config config;
+
+    memcpy(&config, config_data, sizeof(config));
+}
+
+static void guest_reset(VirtIOSerial *vser)
+{
+    VirtIOSerialPort *port;
+    VirtIOSerialPortClass *vsc;
+
+    QTAILQ_FOREACH(port, &vser->ports, next) {
+        vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port);
+        if (port->guest_connected) {
+            port->guest_connected = false;
+            if (vsc->set_guest_connected) {
+                vsc->set_guest_connected(port, false);
+            }
+        }
+    }
+}
+
+static void set_status(VirtIODevice *vdev, uint8_t status)
+{
+    VirtIOSerial *vser;
+    VirtIOSerialPort *port;
+
+    vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
+    port = find_port_by_id(vser, 0);
+
+    if (port && !use_multiport(port->vser)
+        && (status & VIRTIO_CONFIG_S_DRIVER_OK)) {
+        /*
+         * Non-multiport guests won't be able to tell us guest
+         * open/close status.  Such guests can only have a port at id
+         * 0, so set guest_connected for such ports as soon as guest
+         * is up.
+         */
+        port->guest_connected = true;
+    }
+    if (!(status & VIRTIO_CONFIG_S_DRIVER_OK)) {
+        guest_reset(vser);
+    }
+}
+
+static void vser_reset(VirtIODevice *vdev)
+{
+    VirtIOSerial *vser;
+
+    vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
+    guest_reset(vser);
+}
+
+static void virtio_serial_save(QEMUFile *f, void *opaque)
+{
+    VirtIOSerial *s = opaque;
+    VirtIOSerialPort *port;
+    uint32_t nr_active_ports;
+    unsigned int i, max_nr_ports;
+
+    /* The virtio device */
+    virtio_save(&s->vdev, f);
+
+    /* The config space */
+    qemu_put_be16s(f, &s->config.cols);
+    qemu_put_be16s(f, &s->config.rows);
+
+    qemu_put_be32s(f, &s->config.max_nr_ports);
+
+    /* The ports map */
+    max_nr_ports = tswap32(s->config.max_nr_ports);
+    for (i = 0; i < (max_nr_ports + 31) / 32; i++) {
+        qemu_put_be32s(f, &s->ports_map[i]);
+    }
+
+    /* Ports */
+
+    nr_active_ports = 0;
+    QTAILQ_FOREACH(port, &s->ports, next) {
+        nr_active_ports++;
+    }
+
+    qemu_put_be32s(f, &nr_active_ports);
+
+    /*
+     * Items in struct VirtIOSerialPort.
+     */
+    QTAILQ_FOREACH(port, &s->ports, next) {
+        uint32_t elem_popped;
+
+        qemu_put_be32s(f, &port->id);
+        qemu_put_byte(f, port->guest_connected);
+        qemu_put_byte(f, port->host_connected);
+
+       elem_popped = 0;
+        if (port->elem.out_num) {
+            elem_popped = 1;
+        }
+        qemu_put_be32s(f, &elem_popped);
+        if (elem_popped) {
+            qemu_put_be32s(f, &port->iov_idx);
+            qemu_put_be64s(f, &port->iov_offset);
+
+            qemu_put_buffer(f, (unsigned char *)&port->elem,
+                            sizeof(port->elem));
+        }
+    }
+}
+
+static void virtio_serial_post_load_timer_cb(void *opaque)
+{
+    uint32_t i;
+    VirtIOSerial *s = opaque;
+    VirtIOSerialPort *port;
+    uint8_t host_connected;
+    VirtIOSerialPortClass *vsc;
+
+    if (!s->post_load) {
+        return;
+    }
+    for (i = 0 ; i < s->post_load->nr_active_ports; ++i) {
+        port = s->post_load->connected[i].port;
+        host_connected = s->post_load->connected[i].host_connected;
+        if (host_connected != port->host_connected) {
+            /*
+             * We have to let the guest know of the host connection
+             * status change
+             */
+            send_control_event(s, port->id, VIRTIO_CONSOLE_PORT_OPEN,
+                               port->host_connected);
+        }
+        vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port);
+        if (vsc->set_guest_connected) {
+            vsc->set_guest_connected(port, port->guest_connected);
+        }
+    }
+    g_free(s->post_load->connected);
+    qemu_free_timer(s->post_load->timer);
+    g_free(s->post_load);
+    s->post_load = NULL;
+}
+
+static int fetch_active_ports_list(QEMUFile *f, int version_id,
+                                   VirtIOSerial *s, uint32_t nr_active_ports)
+{
+    uint32_t i;
+
+    s->post_load = g_malloc0(sizeof(*s->post_load));
+    s->post_load->nr_active_ports = nr_active_ports;
+    s->post_load->connected =
+        g_malloc0(sizeof(*s->post_load->connected) * nr_active_ports);
+
+    s->post_load->timer = qemu_new_timer_ns(vm_clock,
+                                            virtio_serial_post_load_timer_cb,
+                                            s);
+
+    /* Items in struct VirtIOSerialPort */
+    for (i = 0; i < nr_active_ports; i++) {
+        VirtIOSerialPort *port;
+        uint32_t id;
+
+        id = qemu_get_be32(f);
+        port = find_port_by_id(s, id);
+        if (!port) {
+            return -EINVAL;
+        }
+
+        port->guest_connected = qemu_get_byte(f);
+        s->post_load->connected[i].port = port;
+        s->post_load->connected[i].host_connected = qemu_get_byte(f);
+
+        if (version_id > 2) {
+            uint32_t elem_popped;
+
+            qemu_get_be32s(f, &elem_popped);
+            if (elem_popped) {
+                qemu_get_be32s(f, &port->iov_idx);
+                qemu_get_be64s(f, &port->iov_offset);
+
+                qemu_get_buffer(f, (unsigned char *)&port->elem,
+                                sizeof(port->elem));
+                virtqueue_map_sg(port->elem.in_sg, port->elem.in_addr,
+                                 port->elem.in_num, 1);
+                virtqueue_map_sg(port->elem.out_sg, port->elem.out_addr,
+                                 port->elem.out_num, 1);
+
+                /*
+                 *  Port was throttled on source machine.  Let's
+                 *  unthrottle it here so data starts flowing again.
+                 */
+                virtio_serial_throttle_port(port, false);
+            }
+        }
+    }
+    qemu_mod_timer(s->post_load->timer, 1);
+    return 0;
+}
+
+static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id)
+{
+    VirtIOSerial *s = opaque;
+    uint32_t max_nr_ports, nr_active_ports, ports_map;
+    unsigned int i;
+    int ret;
+
+    if (version_id > 3) {
+        return -EINVAL;
+    }
+
+    /* The virtio device */
+    ret = virtio_load(&s->vdev, f);
+    if (ret) {
+        return ret;
+    }
+
+    if (version_id < 2) {
+        return 0;
+    }
+
+    /* The config space */
+    qemu_get_be16s(f, &s->config.cols);
+    qemu_get_be16s(f, &s->config.rows);
+
+    qemu_get_be32s(f, &max_nr_ports);
+    tswap32s(&max_nr_ports);
+    if (max_nr_ports > tswap32(s->config.max_nr_ports)) {
+        /* Source could have had more ports than us. Fail migration. */
+        return -EINVAL;
+    }
+
+    for (i = 0; i < (max_nr_ports + 31) / 32; i++) {
+        qemu_get_be32s(f, &ports_map);
+
+        if (ports_map != s->ports_map[i]) {
+            /*
+             * Ports active on source and destination don't
+             * match. Fail migration.
+             */
+            return -EINVAL;
+        }
+    }
+
+    qemu_get_be32s(f, &nr_active_ports);
+
+    if (nr_active_ports) {
+        ret = fetch_active_ports_list(f, version_id, s, nr_active_ports);
+        if (ret) {
+            return ret;
+        }
+    }
+    return 0;
+}
+
+static void virtser_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent);
+
+static Property virtser_props[] = {
+    DEFINE_PROP_UINT32("nr", VirtIOSerialPort, id, VIRTIO_CONSOLE_BAD_ID),
+    DEFINE_PROP_STRING("name", VirtIOSerialPort, name),
+    DEFINE_PROP_END_OF_LIST()
+};
+
+#define TYPE_VIRTIO_SERIAL_BUS "virtio-serial-bus"
+#define VIRTIO_SERIAL_BUS(obj) \
+      OBJECT_CHECK(VirtIOSerialBus, (obj), TYPE_VIRTIO_SERIAL_BUS)
+
+static void virtser_bus_class_init(ObjectClass *klass, void *data)
+{
+    BusClass *k = BUS_CLASS(klass);
+    k->print_dev = virtser_bus_dev_print;
+}
+
+static const TypeInfo virtser_bus_info = {
+    .name = TYPE_VIRTIO_SERIAL_BUS,
+    .parent = TYPE_BUS,
+    .instance_size = sizeof(VirtIOSerialBus),
+    .class_init = virtser_bus_class_init,
+};
+
+static void virtser_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent)
+{
+    VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, qdev);
+
+    monitor_printf(mon, "%*sport %d, guest %s, host %s, throttle %s\n",
+                   indent, "", port->id,
+                   port->guest_connected ? "on" : "off",
+                   port->host_connected ? "on" : "off",
+                   port->throttled ? "on" : "off");
+}
+
+/* This function is only used if a port id is not provided by the user */
+static uint32_t find_free_port_id(VirtIOSerial *vser)
+{
+    unsigned int i, max_nr_ports;
+
+    max_nr_ports = tswap32(vser->config.max_nr_ports);
+    for (i = 0; i < (max_nr_ports + 31) / 32; i++) {
+        uint32_t map, bit;
+
+        map = vser->ports_map[i];
+        bit = ffs(~map);
+        if (bit) {
+            return (bit - 1) + i * 32;
+        }
+    }
+    return VIRTIO_CONSOLE_BAD_ID;
+}
+
+static void mark_port_added(VirtIOSerial *vser, uint32_t port_id)
+{
+    unsigned int i;
+
+    i = port_id / 32;
+    vser->ports_map[i] |= 1U << (port_id % 32);
+}
+
+static void add_port(VirtIOSerial *vser, uint32_t port_id)
+{
+    mark_port_added(vser, port_id);
+    send_control_event(vser, port_id, VIRTIO_CONSOLE_PORT_ADD, 1);
+}
+
+static void remove_port(VirtIOSerial *vser, uint32_t port_id)
+{
+    VirtIOSerialPort *port;
+    unsigned int i;
+
+    i = port_id / 32;
+    vser->ports_map[i] &= ~(1U << (port_id % 32));
+
+    port = find_port_by_id(vser, port_id);
+    /*
+     * This function is only called from qdev's unplug callback; if we
+     * get a NULL port here, we're in trouble.
+     */
+    assert(port);
+
+    /* Flush out any unconsumed buffers first */
+    discard_vq_data(port->ovq, &port->vser->vdev);
+
+    send_control_event(vser, port->id, VIRTIO_CONSOLE_PORT_REMOVE, 1);
+}
+
+static int virtser_port_qdev_init(DeviceState *qdev)
+{
+    VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, qdev);
+    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;
+
+    port->vser = bus->vser;
+    port->bh = qemu_bh_new(flush_queued_data_bh, port);
+
+    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 = 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",
+                     port->id);
+        return -1;
+    }
+
+    if (port->id == VIRTIO_CONSOLE_BAD_ID) {
+        if (plugging_port0) {
+            port->id = 0;
+        } else {
+            port->id = find_free_port_id(port->vser);
+            if (port->id == VIRTIO_CONSOLE_BAD_ID) {
+                error_report("virtio-serial-bus: Maximum port limit for this device reached");
+                return -1;
+            }
+        }
+    }
+
+    max_nr_ports = tswap32(port->vser->config.max_nr_ports);
+    if (port->id >= max_nr_ports) {
+        error_report("virtio-serial-bus: Out-of-range port id specified, max. allowed: %u",
+                     max_nr_ports - 1);
+        return -1;
+    }
+
+    ret = vsc->init(port);
+    if (ret) {
+        return ret;
+    }
+
+    port->elem.out_num = 0;
+
+    QTAILQ_INSERT_TAIL(&port->vser->ports, port, next);
+    port->ivq = port->vser->ivqs[port->id];
+    port->ovq = port->vser->ovqs[port->id];
+
+    add_port(port->vser, port->id);
+
+    /* Send an update to the guest about this new port added */
+    virtio_notify_config(&port->vser->vdev);
+
+    return ret;
+}
+
+static int virtser_port_qdev_exit(DeviceState *qdev)
+{
+    VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, qdev);
+    VirtIOSerialPortClass *vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port);
+    VirtIOSerial *vser = port->vser;
+
+    qemu_bh_delete(port->bh);
+    remove_port(port->vser, port->id);
+
+    QTAILQ_REMOVE(&vser->ports, port, next);
+
+    if (vsc->exit) {
+        vsc->exit(port);
+    }
+    return 0;
+}
+
+VirtIODevice *virtio_serial_init(DeviceState *dev, virtio_serial_conf *conf)
+{
+    VirtIOSerial *vser;
+    VirtIODevice *vdev;
+    uint32_t i, max_supported_ports;
+
+    if (!conf->max_virtserial_ports)
+        return NULL;
+
+    /* Each port takes 2 queues, and one pair is for the control queue */
+    max_supported_ports = VIRTIO_PCI_QUEUE_MAX / 2 - 1;
+
+    if (conf->max_virtserial_ports > max_supported_ports) {
+        error_report("maximum ports supported: %u", max_supported_ports);
+        return NULL;
+    }
+
+    vdev = virtio_common_init("virtio-serial", VIRTIO_ID_CONSOLE,
+                              sizeof(struct virtio_console_config),
+                              sizeof(VirtIOSerial));
+
+    vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
+
+    /* Spawn a new virtio-serial bus on which the ports will ride as devices */
+    qbus_create_inplace(&vser->bus.qbus, TYPE_VIRTIO_SERIAL_BUS, dev, NULL);
+    vser->bus.qbus.allow_hotplug = 1;
+    vser->bus.vser = vser;
+    QTAILQ_INIT(&vser->ports);
+
+    vser->bus.max_nr_ports = conf->max_virtserial_ports;
+    vser->ivqs = g_malloc(conf->max_virtserial_ports * sizeof(VirtQueue *));
+    vser->ovqs = g_malloc(conf->max_virtserial_ports * sizeof(VirtQueue *));
+
+    /* Add a queue for host to guest transfers for port 0 (backward compat) */
+    vser->ivqs[0] = virtio_add_queue(vdev, 128, handle_input);
+    /* Add a queue for guest to host transfers for port 0 (backward compat) */
+    vser->ovqs[0] = virtio_add_queue(vdev, 128, handle_output);
+
+    /* TODO: host to guest notifications can get dropped
+     * if the queue fills up. Implement queueing in host,
+     * this might also make it possible to reduce the control
+     * queue size: as guest preposts buffers there,
+     * this will save 4Kbyte of guest memory per entry. */
+
+    /* control queue: host to guest */
+    vser->c_ivq = virtio_add_queue(vdev, 32, control_in);
+    /* control queue: guest to host */
+    vser->c_ovq = virtio_add_queue(vdev, 32, control_out);
+
+    for (i = 1; i < vser->bus.max_nr_ports; i++) {
+        /* Add a per-port queue for host to guest transfers */
+        vser->ivqs[i] = virtio_add_queue(vdev, 128, handle_input);
+        /* Add a per-per queue for guest to host transfers */
+        vser->ovqs[i] = virtio_add_queue(vdev, 128, handle_output);
+    }
+
+    vser->config.max_nr_ports = tswap32(conf->max_virtserial_ports);
+    vser->ports_map = g_malloc0(((conf->max_virtserial_ports + 31) / 32)
+        * sizeof(vser->ports_map[0]));
+    /*
+     * Reserve location 0 for a console port for backward compat
+     * (old kernel, new qemu)
+     */
+    mark_port_added(vser, 0);
+
+    vser->vdev.get_features = get_features;
+    vser->vdev.get_config = get_config;
+    vser->vdev.set_config = set_config;
+    vser->vdev.set_status = set_status;
+    vser->vdev.reset = vser_reset;
+
+    vser->qdev = dev;
+
+    vser->post_load = NULL;
+
+    /*
+     * Register for the savevm section with the virtio-console name
+     * to preserve backward compat
+     */
+    register_savevm(dev, "virtio-console", -1, 3, virtio_serial_save,
+                    virtio_serial_load, vser);
+
+    return vdev;
+}
+
+void virtio_serial_exit(VirtIODevice *vdev)
+{
+    VirtIOSerial *vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
+
+    unregister_savevm(vser->qdev, "virtio-console", vser);
+
+    g_free(vser->ivqs);
+    g_free(vser->ovqs);
+    g_free(vser->ports_map);
+    if (vser->post_load) {
+        g_free(vser->post_load->connected);
+        qemu_del_timer(vser->post_load->timer);
+        qemu_free_timer(vser->post_load->timer);
+        g_free(vser->post_load);
+    }
+    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_type = TYPE_VIRTIO_SERIAL_BUS;
+    k->exit = virtser_port_qdev_exit;
+    k->unplug = qdev_simple_unplug_cb;
+    k->props = virtser_props;
+}
+
+static const 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_types(void)
+{
+    type_register_static(&virtser_bus_info);
+    type_register_static(&virtio_serial_port_type_info);
+}
+
+type_init(virtio_serial_register_types)
diff --git a/hw/char/xen_console.c b/hw/char/xen_console.c
new file mode 100644 (file)
index 0000000..efc3232
--- /dev/null
@@ -0,0 +1,305 @@
+/*
+ *  Copyright (C) International Business Machines  Corp., 2005
+ *  Author(s): Anthony Liguori <aliguori@us.ibm.com>
+ *
+ *  Copyright (C) Red Hat 2007
+ *
+ *  Xen Console
+ *
+ *  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.
+ *
+ *  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 <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/select.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <termios.h>
+#include <stdarg.h>
+#include <sys/mman.h>
+
+#include "hw/hw.h"
+#include "char/char.h"
+#include "hw/xen/xen_backend.h"
+
+#include <xen/io/console.h>
+
+struct buffer {
+    uint8_t *data;
+    size_t consumed;
+    size_t size;
+    size_t capacity;
+    size_t max_capacity;
+};
+
+struct XenConsole {
+    struct XenDevice  xendev;  /* must be first */
+    struct buffer     buffer;
+    char              console[XEN_BUFSIZE];
+    int               ring_ref;
+    void              *sring;
+    CharDriverState   *chr;
+    int               backlog;
+};
+
+static void buffer_append(struct XenConsole *con)
+{
+    struct buffer *buffer = &con->buffer;
+    XENCONS_RING_IDX cons, prod, size;
+    struct xencons_interface *intf = con->sring;
+
+    cons = intf->out_cons;
+    prod = intf->out_prod;
+    xen_mb();
+
+    size = prod - cons;
+    if ((size == 0) || (size > sizeof(intf->out)))
+       return;
+
+    if ((buffer->capacity - buffer->size) < size) {
+       buffer->capacity += (size + 1024);
+       buffer->data = g_realloc(buffer->data, buffer->capacity);
+    }
+
+    while (cons != prod)
+       buffer->data[buffer->size++] = intf->out[
+           MASK_XENCONS_IDX(cons++, intf->out)];
+
+    xen_mb();
+    intf->out_cons = cons;
+    xen_be_send_notify(&con->xendev);
+
+    if (buffer->max_capacity &&
+       buffer->size > buffer->max_capacity) {
+       /* Discard the middle of the data. */
+
+       size_t over = buffer->size - buffer->max_capacity;
+       uint8_t *maxpos = buffer->data + buffer->max_capacity;
+
+       memmove(maxpos - over, maxpos, over);
+       buffer->data = g_realloc(buffer->data, buffer->max_capacity);
+       buffer->size = buffer->capacity = buffer->max_capacity;
+
+       if (buffer->consumed > buffer->max_capacity - over)
+           buffer->consumed = buffer->max_capacity - over;
+    }
+}
+
+static void buffer_advance(struct buffer *buffer, size_t len)
+{
+    buffer->consumed += len;
+    if (buffer->consumed == buffer->size) {
+       buffer->consumed = 0;
+       buffer->size = 0;
+    }
+}
+
+static int ring_free_bytes(struct XenConsole *con)
+{
+    struct xencons_interface *intf = con->sring;
+    XENCONS_RING_IDX cons, prod, space;
+
+    cons = intf->in_cons;
+    prod = intf->in_prod;
+    xen_mb();
+
+    space = prod - cons;
+    if (space > sizeof(intf->in))
+       return 0; /* ring is screwed: ignore it */
+
+    return (sizeof(intf->in) - space);
+}
+
+static int xencons_can_receive(void *opaque)
+{
+    struct XenConsole *con = opaque;
+    return ring_free_bytes(con);
+}
+
+static void xencons_receive(void *opaque, const uint8_t *buf, int len)
+{
+    struct XenConsole *con = opaque;
+    struct xencons_interface *intf = con->sring;
+    XENCONS_RING_IDX prod;
+    int i, max;
+
+    max = ring_free_bytes(con);
+    /* The can_receive() func limits this, but check again anyway */
+    if (max < len)
+       len = max;
+
+    prod = intf->in_prod;
+    for (i = 0; i < len; i++) {
+       intf->in[MASK_XENCONS_IDX(prod++, intf->in)] =
+           buf[i];
+    }
+    xen_wmb();
+    intf->in_prod = prod;
+    xen_be_send_notify(&con->xendev);
+}
+
+static void xencons_send(struct XenConsole *con)
+{
+    ssize_t len, size;
+
+    size = con->buffer.size - con->buffer.consumed;
+    if (con->chr)
+        len = qemu_chr_fe_write(con->chr, con->buffer.data + con->buffer.consumed,
+                             size);
+    else
+        len = size;
+    if (len < 1) {
+       if (!con->backlog) {
+           con->backlog = 1;
+           xen_be_printf(&con->xendev, 1, "backlog piling up, nobody listening?\n");
+       }
+    } else {
+       buffer_advance(&con->buffer, len);
+       if (con->backlog && len == size) {
+           con->backlog = 0;
+           xen_be_printf(&con->xendev, 1, "backlog is gone\n");
+       }
+    }
+}
+
+/* -------------------------------------------------------------------- */
+
+static int con_init(struct XenDevice *xendev)
+{
+    struct XenConsole *con = container_of(xendev, struct XenConsole, xendev);
+    char *type, *dom, label[32];
+    int ret = 0;
+    const char *output;
+
+    /* setup */
+    dom = xs_get_domain_path(xenstore, con->xendev.dom);
+    if (!xendev->dev) {
+        snprintf(con->console, sizeof(con->console), "%s/console", dom);
+    } else {
+        snprintf(con->console, sizeof(con->console), "%s/device/console/%d", dom, xendev->dev);
+    }
+    free(dom);
+
+    type = xenstore_read_str(con->console, "type");
+    if (!type || strcmp(type, "ioemu") != 0) {
+       xen_be_printf(xendev, 1, "not for me (type=%s)\n", type);
+        ret = -1;
+        goto out;
+    }
+
+    output = xenstore_read_str(con->console, "output");
+
+    /* no Xen override, use qemu output device */
+    if (output == NULL) {
+        con->chr = serial_hds[con->xendev.dev];
+    } else {
+        snprintf(label, sizeof(label), "xencons%d", con->xendev.dev);
+        con->chr = qemu_chr_new(label, output, NULL);
+    }
+
+    xenstore_store_pv_console_info(con->xendev.dev, con->chr);
+
+out:
+    g_free(type);
+    return ret;
+}
+
+static int con_initialise(struct XenDevice *xendev)
+{
+    struct XenConsole *con = container_of(xendev, struct XenConsole, xendev);
+    int limit;
+
+    if (xenstore_read_int(con->console, "ring-ref", &con->ring_ref) == -1)
+       return -1;
+    if (xenstore_read_int(con->console, "port", &con->xendev.remote_port) == -1)
+       return -1;
+    if (xenstore_read_int(con->console, "limit", &limit) == 0)
+       con->buffer.max_capacity = limit;
+
+    if (!xendev->dev) {
+        con->sring = xc_map_foreign_range(xen_xc, con->xendev.dom,
+                                          XC_PAGE_SIZE,
+                                          PROT_READ|PROT_WRITE,
+                                          con->ring_ref);
+    } else {
+        con->sring = xc_gnttab_map_grant_ref(xendev->gnttabdev, con->xendev.dom,
+                                             con->ring_ref,
+                                             PROT_READ|PROT_WRITE);
+    }
+    if (!con->sring)
+       return -1;
+
+    xen_be_bind_evtchn(&con->xendev);
+    if (con->chr) {
+        if (qemu_chr_fe_claim(con->chr) == 0) {
+            qemu_chr_add_handlers(con->chr, xencons_can_receive,
+                                  xencons_receive, NULL, con);
+        } else {
+            xen_be_printf(xendev, 0,
+                          "xen_console_init error chardev %s already used\n",
+                          con->chr->label);
+            con->chr = NULL;
+        }
+    }
+
+    xen_be_printf(xendev, 1, "ring mfn %d, remote port %d, local port %d, limit %zd\n",
+                 con->ring_ref,
+                 con->xendev.remote_port,
+                 con->xendev.local_port,
+                 con->buffer.max_capacity);
+    return 0;
+}
+
+static void con_disconnect(struct XenDevice *xendev)
+{
+    struct XenConsole *con = container_of(xendev, struct XenConsole, xendev);
+
+    if (!xendev->dev) {
+        return;
+    }
+    if (con->chr) {
+        qemu_chr_add_handlers(con->chr, NULL, NULL, NULL, NULL);
+        qemu_chr_fe_release(con->chr);
+    }
+    xen_be_unbind_evtchn(&con->xendev);
+
+    if (con->sring) {
+        if (!xendev->gnttabdev) {
+            munmap(con->sring, XC_PAGE_SIZE);
+        } else {
+            xc_gnttab_munmap(xendev->gnttabdev, con->sring, 1);
+        }
+       con->sring = NULL;
+    }
+}
+
+static void con_event(struct XenDevice *xendev)
+{
+    struct XenConsole *con = container_of(xendev, struct XenConsole, xendev);
+
+    buffer_append(con);
+    if (con->buffer.size - con->buffer.consumed)
+       xencons_send(con);
+}
+
+/* -------------------------------------------------------------------- */
+
+struct XenDevOps xen_console_ops = {
+    .size       = sizeof(struct XenConsole),
+    .flags      = DEVOPS_FLAG_IGNORE_STATE|DEVOPS_FLAG_NEED_GNTDEV,
+    .init       = con_init,
+    .initialise = con_initialise,
+    .event      = con_event,
+    .disconnect = con_disconnect,
+};
diff --git a/hw/char/xilinx_uartlite.c b/hw/char/xilinx_uartlite.c
new file mode 100644 (file)
index 0000000..079f4d4
--- /dev/null
@@ -0,0 +1,231 @@
+/*
+ * QEMU model of Xilinx uartlite.
+ *
+ * Copyright (c) 2009 Edgar E. Iglesias.
+ *
+ * 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 "hw/sysbus.h"
+#include "char/char.h"
+
+#define DUART(x)
+
+#define R_RX            0
+#define R_TX            1
+#define R_STATUS        2
+#define R_CTRL          3
+#define R_MAX           4
+
+#define STATUS_RXVALID    0x01
+#define STATUS_RXFULL     0x02
+#define STATUS_TXEMPTY    0x04
+#define STATUS_TXFULL     0x08
+#define STATUS_IE         0x10
+#define STATUS_OVERRUN    0x20
+#define STATUS_FRAME      0x40
+#define STATUS_PARITY     0x80
+
+#define CONTROL_RST_TX    0x01
+#define CONTROL_RST_RX    0x02
+#define CONTROL_IE        0x10
+
+struct xlx_uartlite
+{
+    SysBusDevice busdev;
+    MemoryRegion mmio;
+    CharDriverState *chr;
+    qemu_irq irq;
+
+    uint8_t rx_fifo[8];
+    unsigned int rx_fifo_pos;
+    unsigned int rx_fifo_len;
+
+    uint32_t regs[R_MAX];
+};
+
+static void uart_update_irq(struct xlx_uartlite *s)
+{
+    unsigned int irq;
+
+    if (s->rx_fifo_len)
+        s->regs[R_STATUS] |= STATUS_IE;
+
+    irq = (s->regs[R_STATUS] & STATUS_IE) && (s->regs[R_CTRL] & CONTROL_IE);
+    qemu_set_irq(s->irq, irq);
+}
+
+static void uart_update_status(struct xlx_uartlite *s)
+{
+    uint32_t r;
+
+    r = s->regs[R_STATUS];
+    r &= ~7;
+    r |= 1 << 2; /* Tx fifo is always empty. We are fast :) */
+    r |= (s->rx_fifo_len == sizeof (s->rx_fifo)) << 1;
+    r |= (!!s->rx_fifo_len);
+    s->regs[R_STATUS] = r;
+}
+
+static uint64_t
+uart_read(void *opaque, hwaddr addr, unsigned int size)
+{
+    struct xlx_uartlite *s = opaque;
+    uint32_t r = 0;
+    addr >>= 2;
+    switch (addr)
+    {
+        case R_RX:
+            r = s->rx_fifo[(s->rx_fifo_pos - s->rx_fifo_len) & 7];
+            if (s->rx_fifo_len)
+                s->rx_fifo_len--;
+            uart_update_status(s);
+            uart_update_irq(s);
+            qemu_chr_accept_input(s->chr);
+            break;
+
+        default:
+            if (addr < ARRAY_SIZE(s->regs))
+                r = s->regs[addr];
+            DUART(qemu_log("%s addr=%x v=%x\n", __func__, addr, r));
+            break;
+    }
+    return r;
+}
+
+static void
+uart_write(void *opaque, hwaddr addr,
+           uint64_t val64, unsigned int size)
+{
+    struct xlx_uartlite *s = opaque;
+    uint32_t value = val64;
+    unsigned char ch = value;
+
+    addr >>= 2;
+    switch (addr)
+    {
+        case R_STATUS:
+            hw_error("write to UART STATUS?\n");
+            break;
+
+        case R_CTRL:
+            if (value & CONTROL_RST_RX) {
+                s->rx_fifo_pos = 0;
+                s->rx_fifo_len = 0;
+            }
+            s->regs[addr] = value;
+            break;
+
+        case R_TX:
+            if (s->chr)
+                qemu_chr_fe_write(s->chr, &ch, 1);
+
+            s->regs[addr] = value;
+
+            /* hax.  */
+            s->regs[R_STATUS] |= STATUS_IE;
+            break;
+
+        default:
+            DUART(printf("%s addr=%x v=%x\n", __func__, addr, value));
+            if (addr < ARRAY_SIZE(s->regs))
+                s->regs[addr] = value;
+            break;
+    }
+    uart_update_status(s);
+    uart_update_irq(s);
+}
+
+static const MemoryRegionOps uart_ops = {
+    .read = uart_read,
+    .write = uart_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 1,
+        .max_access_size = 4
+    }
+};
+
+static void uart_rx(void *opaque, const uint8_t *buf, int size)
+{
+    struct xlx_uartlite *s = opaque;
+
+    /* Got a byte.  */
+    if (s->rx_fifo_len >= 8) {
+        printf("WARNING: UART dropped char.\n");
+        return;
+    }
+    s->rx_fifo[s->rx_fifo_pos] = *buf;
+    s->rx_fifo_pos++;
+    s->rx_fifo_pos &= 0x7;
+    s->rx_fifo_len++;
+
+    uart_update_status(s);
+    uart_update_irq(s);
+}
+
+static int uart_can_rx(void *opaque)
+{
+    struct xlx_uartlite *s = opaque;
+
+    return s->rx_fifo_len < sizeof(s->rx_fifo);
+}
+
+static void uart_event(void *opaque, int event)
+{
+
+}
+
+static int xilinx_uartlite_init(SysBusDevice *dev)
+{
+    struct xlx_uartlite *s = FROM_SYSBUS(typeof (*s), dev);
+
+    sysbus_init_irq(dev, &s->irq);
+
+    uart_update_status(s);
+    memory_region_init_io(&s->mmio, &uart_ops, s, "xlnx.xps-uartlite",
+                                                                R_MAX * 4);
+    sysbus_init_mmio(dev, &s->mmio);
+
+    s->chr = qemu_char_get_next_serial();
+    if (s->chr)
+        qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s);
+    return 0;
+}
+
+static void xilinx_uartlite_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sdc->init = xilinx_uartlite_init;
+}
+
+static const TypeInfo xilinx_uartlite_info = {
+    .name          = "xlnx.xps-uartlite",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof (struct xlx_uartlite),
+    .class_init    = xilinx_uartlite_class_init,
+};
+
+static void xilinx_uart_register_types(void)
+{
+    type_register_static(&xilinx_uartlite_info);
+}
+
+type_init(xilinx_uart_register_types)
diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c
deleted file mode 100644 (file)
index 7a4d634..0000000
+++ /dev/null
@@ -1,3021 +0,0 @@
-/*
- * QEMU Cirrus CLGD 54xx VGA Emulator.
- *
- * Copyright (c) 2004 Fabrice Bellard
- * Copyright (c) 2004 Makoto Suzuki (suzu)
- *
- * 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.
- */
-/*
- * Reference: Finn Thogersons' VGADOC4b
- *   available at http://home.worldonline.dk/~finth/
- */
-#include "hw/hw.h"
-#include "hw/pci/pci.h"
-#include "ui/console.h"
-#include "hw/vga_int.h"
-#include "hw/loader.h"
-
-/*
- * TODO:
- *    - destination write mask support not complete (bits 5..7)
- *    - optimize linear mappings
- *    - optimize bitblt functions
- */
-
-//#define DEBUG_CIRRUS
-//#define DEBUG_BITBLT
-
-/***************************************
- *
- *  definitions
- *
- ***************************************/
-
-// ID
-#define CIRRUS_ID_CLGD5422  (0x23<<2)
-#define CIRRUS_ID_CLGD5426  (0x24<<2)
-#define CIRRUS_ID_CLGD5424  (0x25<<2)
-#define CIRRUS_ID_CLGD5428  (0x26<<2)
-#define CIRRUS_ID_CLGD5430  (0x28<<2)
-#define CIRRUS_ID_CLGD5434  (0x2A<<2)
-#define CIRRUS_ID_CLGD5436  (0x2B<<2)
-#define CIRRUS_ID_CLGD5446  (0x2E<<2)
-
-// sequencer 0x07
-#define CIRRUS_SR7_BPP_VGA            0x00
-#define CIRRUS_SR7_BPP_SVGA           0x01
-#define CIRRUS_SR7_BPP_MASK           0x0e
-#define CIRRUS_SR7_BPP_8              0x00
-#define CIRRUS_SR7_BPP_16_DOUBLEVCLK  0x02
-#define CIRRUS_SR7_BPP_24             0x04
-#define CIRRUS_SR7_BPP_16             0x06
-#define CIRRUS_SR7_BPP_32             0x08
-#define CIRRUS_SR7_ISAADDR_MASK       0xe0
-
-// sequencer 0x0f
-#define CIRRUS_MEMSIZE_512k        0x08
-#define CIRRUS_MEMSIZE_1M          0x10
-#define CIRRUS_MEMSIZE_2M          0x18
-#define CIRRUS_MEMFLAGS_BANKSWITCH 0x80        // bank switching is enabled.
-
-// sequencer 0x12
-#define CIRRUS_CURSOR_SHOW         0x01
-#define CIRRUS_CURSOR_HIDDENPEL    0x02
-#define CIRRUS_CURSOR_LARGE        0x04        // 64x64 if set, 32x32 if clear
-
-// sequencer 0x17
-#define CIRRUS_BUSTYPE_VLBFAST   0x10
-#define CIRRUS_BUSTYPE_PCI       0x20
-#define CIRRUS_BUSTYPE_VLBSLOW   0x30
-#define CIRRUS_BUSTYPE_ISA       0x38
-#define CIRRUS_MMIO_ENABLE       0x04
-#define CIRRUS_MMIO_USE_PCIADDR  0x40  // 0xb8000 if cleared.
-#define CIRRUS_MEMSIZEEXT_DOUBLE 0x80
-
-// control 0x0b
-#define CIRRUS_BANKING_DUAL             0x01
-#define CIRRUS_BANKING_GRANULARITY_16K  0x20   // set:16k, clear:4k
-
-// control 0x30
-#define CIRRUS_BLTMODE_BACKWARDS        0x01
-#define CIRRUS_BLTMODE_MEMSYSDEST       0x02
-#define CIRRUS_BLTMODE_MEMSYSSRC        0x04
-#define CIRRUS_BLTMODE_TRANSPARENTCOMP  0x08
-#define CIRRUS_BLTMODE_PATTERNCOPY      0x40
-#define CIRRUS_BLTMODE_COLOREXPAND      0x80
-#define CIRRUS_BLTMODE_PIXELWIDTHMASK   0x30
-#define CIRRUS_BLTMODE_PIXELWIDTH8      0x00
-#define CIRRUS_BLTMODE_PIXELWIDTH16     0x10
-#define CIRRUS_BLTMODE_PIXELWIDTH24     0x20
-#define CIRRUS_BLTMODE_PIXELWIDTH32     0x30
-
-// control 0x31
-#define CIRRUS_BLT_BUSY                 0x01
-#define CIRRUS_BLT_START                0x02
-#define CIRRUS_BLT_RESET                0x04
-#define CIRRUS_BLT_FIFOUSED             0x10
-#define CIRRUS_BLT_AUTOSTART            0x80
-
-// control 0x32
-#define CIRRUS_ROP_0                    0x00
-#define CIRRUS_ROP_SRC_AND_DST          0x05
-#define CIRRUS_ROP_NOP                  0x06
-#define CIRRUS_ROP_SRC_AND_NOTDST       0x09
-#define CIRRUS_ROP_NOTDST               0x0b
-#define CIRRUS_ROP_SRC                  0x0d
-#define CIRRUS_ROP_1                    0x0e
-#define CIRRUS_ROP_NOTSRC_AND_DST       0x50
-#define CIRRUS_ROP_SRC_XOR_DST          0x59
-#define CIRRUS_ROP_SRC_OR_DST           0x6d
-#define CIRRUS_ROP_NOTSRC_OR_NOTDST     0x90
-#define CIRRUS_ROP_SRC_NOTXOR_DST       0x95
-#define CIRRUS_ROP_SRC_OR_NOTDST        0xad
-#define CIRRUS_ROP_NOTSRC               0xd0
-#define CIRRUS_ROP_NOTSRC_OR_DST        0xd6
-#define CIRRUS_ROP_NOTSRC_AND_NOTDST    0xda
-
-#define CIRRUS_ROP_NOP_INDEX 2
-#define CIRRUS_ROP_SRC_INDEX 5
-
-// control 0x33
-#define CIRRUS_BLTMODEEXT_SOLIDFILL        0x04
-#define CIRRUS_BLTMODEEXT_COLOREXPINV      0x02
-#define CIRRUS_BLTMODEEXT_DWORDGRANULARITY 0x01
-
-// memory-mapped IO
-#define CIRRUS_MMIO_BLTBGCOLOR        0x00     // dword
-#define CIRRUS_MMIO_BLTFGCOLOR        0x04     // dword
-#define CIRRUS_MMIO_BLTWIDTH          0x08     // word
-#define CIRRUS_MMIO_BLTHEIGHT         0x0a     // word
-#define CIRRUS_MMIO_BLTDESTPITCH      0x0c     // word
-#define CIRRUS_MMIO_BLTSRCPITCH       0x0e     // word
-#define CIRRUS_MMIO_BLTDESTADDR       0x10     // dword
-#define CIRRUS_MMIO_BLTSRCADDR        0x14     // dword
-#define CIRRUS_MMIO_BLTWRITEMASK      0x17     // byte
-#define CIRRUS_MMIO_BLTMODE           0x18     // byte
-#define CIRRUS_MMIO_BLTROP            0x1a     // byte
-#define CIRRUS_MMIO_BLTMODEEXT        0x1b     // byte
-#define CIRRUS_MMIO_BLTTRANSPARENTCOLOR 0x1c   // word?
-#define CIRRUS_MMIO_BLTTRANSPARENTCOLORMASK 0x20       // word?
-#define CIRRUS_MMIO_LINEARDRAW_START_X 0x24    // word
-#define CIRRUS_MMIO_LINEARDRAW_START_Y 0x26    // word
-#define CIRRUS_MMIO_LINEARDRAW_END_X  0x28     // word
-#define CIRRUS_MMIO_LINEARDRAW_END_Y  0x2a     // word
-#define CIRRUS_MMIO_LINEARDRAW_LINESTYLE_INC 0x2c      // byte
-#define CIRRUS_MMIO_LINEARDRAW_LINESTYLE_ROLLOVER 0x2d // byte
-#define CIRRUS_MMIO_LINEARDRAW_LINESTYLE_MASK 0x2e     // byte
-#define CIRRUS_MMIO_LINEARDRAW_LINESTYLE_ACCUM 0x2f    // byte
-#define CIRRUS_MMIO_BRESENHAM_K1      0x30     // word
-#define CIRRUS_MMIO_BRESENHAM_K3      0x32     // word
-#define CIRRUS_MMIO_BRESENHAM_ERROR   0x34     // word
-#define CIRRUS_MMIO_BRESENHAM_DELTA_MAJOR 0x36 // word
-#define CIRRUS_MMIO_BRESENHAM_DIRECTION 0x38   // byte
-#define CIRRUS_MMIO_LINEDRAW_MODE     0x39     // byte
-#define CIRRUS_MMIO_BLTSTATUS         0x40     // byte
-
-#define CIRRUS_PNPMMIO_SIZE         0x1000
-
-#define BLTUNSAFE(s) \
-    ( \
-        ( /* check dst is within bounds */ \
-            (s)->cirrus_blt_height * ABS((s)->cirrus_blt_dstpitch) \
-                + ((s)->cirrus_blt_dstaddr & (s)->cirrus_addr_mask) > \
-                    (s)->vga.vram_size \
-        ) || \
-        ( /* check src is within bounds */ \
-            (s)->cirrus_blt_height * ABS((s)->cirrus_blt_srcpitch) \
-                + ((s)->cirrus_blt_srcaddr & (s)->cirrus_addr_mask) > \
-                    (s)->vga.vram_size \
-        ) \
-    )
-
-struct CirrusVGAState;
-typedef void (*cirrus_bitblt_rop_t) (struct CirrusVGAState *s,
-                                     uint8_t * dst, const uint8_t * src,
-                                    int dstpitch, int srcpitch,
-                                    int bltwidth, int bltheight);
-typedef void (*cirrus_fill_t)(struct CirrusVGAState *s,
-                              uint8_t *dst, int dst_pitch, int width, int height);
-
-typedef struct CirrusVGAState {
-    VGACommonState vga;
-
-    MemoryRegion cirrus_vga_io;
-    MemoryRegion cirrus_linear_io;
-    MemoryRegion cirrus_linear_bitblt_io;
-    MemoryRegion cirrus_mmio_io;
-    MemoryRegion pci_bar;
-    bool linear_vram;  /* vga.vram mapped over cirrus_linear_io */
-    MemoryRegion low_mem_container; /* container for 0xa0000-0xc0000 */
-    MemoryRegion low_mem;           /* always mapped, overridden by: */
-    MemoryRegion cirrus_bank[2];    /*   aliases at 0xa0000-0xb0000  */
-    uint32_t cirrus_addr_mask;
-    uint32_t linear_mmio_mask;
-    uint8_t cirrus_shadow_gr0;
-    uint8_t cirrus_shadow_gr1;
-    uint8_t cirrus_hidden_dac_lockindex;
-    uint8_t cirrus_hidden_dac_data;
-    uint32_t cirrus_bank_base[2];
-    uint32_t cirrus_bank_limit[2];
-    uint8_t cirrus_hidden_palette[48];
-    uint32_t hw_cursor_x;
-    uint32_t hw_cursor_y;
-    int cirrus_blt_pixelwidth;
-    int cirrus_blt_width;
-    int cirrus_blt_height;
-    int cirrus_blt_dstpitch;
-    int cirrus_blt_srcpitch;
-    uint32_t cirrus_blt_fgcol;
-    uint32_t cirrus_blt_bgcol;
-    uint32_t cirrus_blt_dstaddr;
-    uint32_t cirrus_blt_srcaddr;
-    uint8_t cirrus_blt_mode;
-    uint8_t cirrus_blt_modeext;
-    cirrus_bitblt_rop_t cirrus_rop;
-#define CIRRUS_BLTBUFSIZE (2048 * 4) /* one line width */
-    uint8_t cirrus_bltbuf[CIRRUS_BLTBUFSIZE];
-    uint8_t *cirrus_srcptr;
-    uint8_t *cirrus_srcptr_end;
-    uint32_t cirrus_srccounter;
-    /* hwcursor display state */
-    int last_hw_cursor_size;
-    int last_hw_cursor_x;
-    int last_hw_cursor_y;
-    int last_hw_cursor_y_start;
-    int last_hw_cursor_y_end;
-    int real_vram_size; /* XXX: suppress that */
-    int device_id;
-    int bustype;
-} CirrusVGAState;
-
-typedef struct PCICirrusVGAState {
-    PCIDevice dev;
-    CirrusVGAState cirrus_vga;
-} PCICirrusVGAState;
-
-typedef struct ISACirrusVGAState {
-    ISADevice dev;
-    CirrusVGAState cirrus_vga;
-} ISACirrusVGAState;
-
-static uint8_t rop_to_index[256];
-
-/***************************************
- *
- *  prototypes.
- *
- ***************************************/
-
-
-static void cirrus_bitblt_reset(CirrusVGAState *s);
-static void cirrus_update_memory_access(CirrusVGAState *s);
-
-/***************************************
- *
- *  raster operations
- *
- ***************************************/
-
-static void cirrus_bitblt_rop_nop(CirrusVGAState *s,
-                                  uint8_t *dst,const uint8_t *src,
-                                  int dstpitch,int srcpitch,
-                                  int bltwidth,int bltheight)
-{
-}
-
-static void cirrus_bitblt_fill_nop(CirrusVGAState *s,
-                                   uint8_t *dst,
-                                   int dstpitch, int bltwidth,int bltheight)
-{
-}
-
-#define ROP_NAME 0
-#define ROP_FN(d, s) 0
-#include "hw/cirrus_vga_rop.h"
-
-#define ROP_NAME src_and_dst
-#define ROP_FN(d, s) (s) & (d)
-#include "hw/cirrus_vga_rop.h"
-
-#define ROP_NAME src_and_notdst
-#define ROP_FN(d, s) (s) & (~(d))
-#include "hw/cirrus_vga_rop.h"
-
-#define ROP_NAME notdst
-#define ROP_FN(d, s) ~(d)
-#include "hw/cirrus_vga_rop.h"
-
-#define ROP_NAME src
-#define ROP_FN(d, s) s
-#include "hw/cirrus_vga_rop.h"
-
-#define ROP_NAME 1
-#define ROP_FN(d, s) ~0
-#include "hw/cirrus_vga_rop.h"
-
-#define ROP_NAME notsrc_and_dst
-#define ROP_FN(d, s) (~(s)) & (d)
-#include "hw/cirrus_vga_rop.h"
-
-#define ROP_NAME src_xor_dst
-#define ROP_FN(d, s) (s) ^ (d)
-#include "hw/cirrus_vga_rop.h"
-
-#define ROP_NAME src_or_dst
-#define ROP_FN(d, s) (s) | (d)
-#include "hw/cirrus_vga_rop.h"
-
-#define ROP_NAME notsrc_or_notdst
-#define ROP_FN(d, s) (~(s)) | (~(d))
-#include "hw/cirrus_vga_rop.h"
-
-#define ROP_NAME src_notxor_dst
-#define ROP_FN(d, s) ~((s) ^ (d))
-#include "hw/cirrus_vga_rop.h"
-
-#define ROP_NAME src_or_notdst
-#define ROP_FN(d, s) (s) | (~(d))
-#include "hw/cirrus_vga_rop.h"
-
-#define ROP_NAME notsrc
-#define ROP_FN(d, s) (~(s))
-#include "hw/cirrus_vga_rop.h"
-
-#define ROP_NAME notsrc_or_dst
-#define ROP_FN(d, s) (~(s)) | (d)
-#include "hw/cirrus_vga_rop.h"
-
-#define ROP_NAME notsrc_and_notdst
-#define ROP_FN(d, s) (~(s)) & (~(d))
-#include "hw/cirrus_vga_rop.h"
-
-static const cirrus_bitblt_rop_t cirrus_fwd_rop[16] = {
-    cirrus_bitblt_rop_fwd_0,
-    cirrus_bitblt_rop_fwd_src_and_dst,
-    cirrus_bitblt_rop_nop,
-    cirrus_bitblt_rop_fwd_src_and_notdst,
-    cirrus_bitblt_rop_fwd_notdst,
-    cirrus_bitblt_rop_fwd_src,
-    cirrus_bitblt_rop_fwd_1,
-    cirrus_bitblt_rop_fwd_notsrc_and_dst,
-    cirrus_bitblt_rop_fwd_src_xor_dst,
-    cirrus_bitblt_rop_fwd_src_or_dst,
-    cirrus_bitblt_rop_fwd_notsrc_or_notdst,
-    cirrus_bitblt_rop_fwd_src_notxor_dst,
-    cirrus_bitblt_rop_fwd_src_or_notdst,
-    cirrus_bitblt_rop_fwd_notsrc,
-    cirrus_bitblt_rop_fwd_notsrc_or_dst,
-    cirrus_bitblt_rop_fwd_notsrc_and_notdst,
-};
-
-static const cirrus_bitblt_rop_t cirrus_bkwd_rop[16] = {
-    cirrus_bitblt_rop_bkwd_0,
-    cirrus_bitblt_rop_bkwd_src_and_dst,
-    cirrus_bitblt_rop_nop,
-    cirrus_bitblt_rop_bkwd_src_and_notdst,
-    cirrus_bitblt_rop_bkwd_notdst,
-    cirrus_bitblt_rop_bkwd_src,
-    cirrus_bitblt_rop_bkwd_1,
-    cirrus_bitblt_rop_bkwd_notsrc_and_dst,
-    cirrus_bitblt_rop_bkwd_src_xor_dst,
-    cirrus_bitblt_rop_bkwd_src_or_dst,
-    cirrus_bitblt_rop_bkwd_notsrc_or_notdst,
-    cirrus_bitblt_rop_bkwd_src_notxor_dst,
-    cirrus_bitblt_rop_bkwd_src_or_notdst,
-    cirrus_bitblt_rop_bkwd_notsrc,
-    cirrus_bitblt_rop_bkwd_notsrc_or_dst,
-    cirrus_bitblt_rop_bkwd_notsrc_and_notdst,
-};
-
-#define TRANSP_ROP(name) {\
-    name ## _8,\
-    name ## _16,\
-        }
-#define TRANSP_NOP(func) {\
-    func,\
-    func,\
-        }
-
-static const cirrus_bitblt_rop_t cirrus_fwd_transp_rop[16][2] = {
-    TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_0),
-    TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_src_and_dst),
-    TRANSP_NOP(cirrus_bitblt_rop_nop),
-    TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_src_and_notdst),
-    TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_notdst),
-    TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_src),
-    TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_1),
-    TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_notsrc_and_dst),
-    TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_src_xor_dst),
-    TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_src_or_dst),
-    TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_notsrc_or_notdst),
-    TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_src_notxor_dst),
-    TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_src_or_notdst),
-    TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_notsrc),
-    TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_notsrc_or_dst),
-    TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_notsrc_and_notdst),
-};
-
-static const cirrus_bitblt_rop_t cirrus_bkwd_transp_rop[16][2] = {
-    TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_0),
-    TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_src_and_dst),
-    TRANSP_NOP(cirrus_bitblt_rop_nop),
-    TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_src_and_notdst),
-    TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_notdst),
-    TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_src),
-    TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_1),
-    TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_notsrc_and_dst),
-    TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_src_xor_dst),
-    TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_src_or_dst),
-    TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_notsrc_or_notdst),
-    TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_src_notxor_dst),
-    TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_src_or_notdst),
-    TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_notsrc),
-    TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_notsrc_or_dst),
-    TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_notsrc_and_notdst),
-};
-
-#define ROP2(name) {\
-    name ## _8,\
-    name ## _16,\
-    name ## _24,\
-    name ## _32,\
-        }
-
-#define ROP_NOP2(func) {\
-    func,\
-    func,\
-    func,\
-    func,\
-        }
-
-static const cirrus_bitblt_rop_t cirrus_patternfill[16][4] = {
-    ROP2(cirrus_patternfill_0),
-    ROP2(cirrus_patternfill_src_and_dst),
-    ROP_NOP2(cirrus_bitblt_rop_nop),
-    ROP2(cirrus_patternfill_src_and_notdst),
-    ROP2(cirrus_patternfill_notdst),
-    ROP2(cirrus_patternfill_src),
-    ROP2(cirrus_patternfill_1),
-    ROP2(cirrus_patternfill_notsrc_and_dst),
-    ROP2(cirrus_patternfill_src_xor_dst),
-    ROP2(cirrus_patternfill_src_or_dst),
-    ROP2(cirrus_patternfill_notsrc_or_notdst),
-    ROP2(cirrus_patternfill_src_notxor_dst),
-    ROP2(cirrus_patternfill_src_or_notdst),
-    ROP2(cirrus_patternfill_notsrc),
-    ROP2(cirrus_patternfill_notsrc_or_dst),
-    ROP2(cirrus_patternfill_notsrc_and_notdst),
-};
-
-static const cirrus_bitblt_rop_t cirrus_colorexpand_transp[16][4] = {
-    ROP2(cirrus_colorexpand_transp_0),
-    ROP2(cirrus_colorexpand_transp_src_and_dst),
-    ROP_NOP2(cirrus_bitblt_rop_nop),
-    ROP2(cirrus_colorexpand_transp_src_and_notdst),
-    ROP2(cirrus_colorexpand_transp_notdst),
-    ROP2(cirrus_colorexpand_transp_src),
-    ROP2(cirrus_colorexpand_transp_1),
-    ROP2(cirrus_colorexpand_transp_notsrc_and_dst),
-    ROP2(cirrus_colorexpand_transp_src_xor_dst),
-    ROP2(cirrus_colorexpand_transp_src_or_dst),
-    ROP2(cirrus_colorexpand_transp_notsrc_or_notdst),
-    ROP2(cirrus_colorexpand_transp_src_notxor_dst),
-    ROP2(cirrus_colorexpand_transp_src_or_notdst),
-    ROP2(cirrus_colorexpand_transp_notsrc),
-    ROP2(cirrus_colorexpand_transp_notsrc_or_dst),
-    ROP2(cirrus_colorexpand_transp_notsrc_and_notdst),
-};
-
-static const cirrus_bitblt_rop_t cirrus_colorexpand[16][4] = {
-    ROP2(cirrus_colorexpand_0),
-    ROP2(cirrus_colorexpand_src_and_dst),
-    ROP_NOP2(cirrus_bitblt_rop_nop),
-    ROP2(cirrus_colorexpand_src_and_notdst),
-    ROP2(cirrus_colorexpand_notdst),
-    ROP2(cirrus_colorexpand_src),
-    ROP2(cirrus_colorexpand_1),
-    ROP2(cirrus_colorexpand_notsrc_and_dst),
-    ROP2(cirrus_colorexpand_src_xor_dst),
-    ROP2(cirrus_colorexpand_src_or_dst),
-    ROP2(cirrus_colorexpand_notsrc_or_notdst),
-    ROP2(cirrus_colorexpand_src_notxor_dst),
-    ROP2(cirrus_colorexpand_src_or_notdst),
-    ROP2(cirrus_colorexpand_notsrc),
-    ROP2(cirrus_colorexpand_notsrc_or_dst),
-    ROP2(cirrus_colorexpand_notsrc_and_notdst),
-};
-
-static const cirrus_bitblt_rop_t cirrus_colorexpand_pattern_transp[16][4] = {
-    ROP2(cirrus_colorexpand_pattern_transp_0),
-    ROP2(cirrus_colorexpand_pattern_transp_src_and_dst),
-    ROP_NOP2(cirrus_bitblt_rop_nop),
-    ROP2(cirrus_colorexpand_pattern_transp_src_and_notdst),
-    ROP2(cirrus_colorexpand_pattern_transp_notdst),
-    ROP2(cirrus_colorexpand_pattern_transp_src),
-    ROP2(cirrus_colorexpand_pattern_transp_1),
-    ROP2(cirrus_colorexpand_pattern_transp_notsrc_and_dst),
-    ROP2(cirrus_colorexpand_pattern_transp_src_xor_dst),
-    ROP2(cirrus_colorexpand_pattern_transp_src_or_dst),
-    ROP2(cirrus_colorexpand_pattern_transp_notsrc_or_notdst),
-    ROP2(cirrus_colorexpand_pattern_transp_src_notxor_dst),
-    ROP2(cirrus_colorexpand_pattern_transp_src_or_notdst),
-    ROP2(cirrus_colorexpand_pattern_transp_notsrc),
-    ROP2(cirrus_colorexpand_pattern_transp_notsrc_or_dst),
-    ROP2(cirrus_colorexpand_pattern_transp_notsrc_and_notdst),
-};
-
-static const cirrus_bitblt_rop_t cirrus_colorexpand_pattern[16][4] = {
-    ROP2(cirrus_colorexpand_pattern_0),
-    ROP2(cirrus_colorexpand_pattern_src_and_dst),
-    ROP_NOP2(cirrus_bitblt_rop_nop),
-    ROP2(cirrus_colorexpand_pattern_src_and_notdst),
-    ROP2(cirrus_colorexpand_pattern_notdst),
-    ROP2(cirrus_colorexpand_pattern_src),
-    ROP2(cirrus_colorexpand_pattern_1),
-    ROP2(cirrus_colorexpand_pattern_notsrc_and_dst),
-    ROP2(cirrus_colorexpand_pattern_src_xor_dst),
-    ROP2(cirrus_colorexpand_pattern_src_or_dst),
-    ROP2(cirrus_colorexpand_pattern_notsrc_or_notdst),
-    ROP2(cirrus_colorexpand_pattern_src_notxor_dst),
-    ROP2(cirrus_colorexpand_pattern_src_or_notdst),
-    ROP2(cirrus_colorexpand_pattern_notsrc),
-    ROP2(cirrus_colorexpand_pattern_notsrc_or_dst),
-    ROP2(cirrus_colorexpand_pattern_notsrc_and_notdst),
-};
-
-static const cirrus_fill_t cirrus_fill[16][4] = {
-    ROP2(cirrus_fill_0),
-    ROP2(cirrus_fill_src_and_dst),
-    ROP_NOP2(cirrus_bitblt_fill_nop),
-    ROP2(cirrus_fill_src_and_notdst),
-    ROP2(cirrus_fill_notdst),
-    ROP2(cirrus_fill_src),
-    ROP2(cirrus_fill_1),
-    ROP2(cirrus_fill_notsrc_and_dst),
-    ROP2(cirrus_fill_src_xor_dst),
-    ROP2(cirrus_fill_src_or_dst),
-    ROP2(cirrus_fill_notsrc_or_notdst),
-    ROP2(cirrus_fill_src_notxor_dst),
-    ROP2(cirrus_fill_src_or_notdst),
-    ROP2(cirrus_fill_notsrc),
-    ROP2(cirrus_fill_notsrc_or_dst),
-    ROP2(cirrus_fill_notsrc_and_notdst),
-};
-
-static inline void cirrus_bitblt_fgcol(CirrusVGAState *s)
-{
-    unsigned int color;
-    switch (s->cirrus_blt_pixelwidth) {
-    case 1:
-        s->cirrus_blt_fgcol = s->cirrus_shadow_gr1;
-        break;
-    case 2:
-        color = s->cirrus_shadow_gr1 | (s->vga.gr[0x11] << 8);
-        s->cirrus_blt_fgcol = le16_to_cpu(color);
-        break;
-    case 3:
-        s->cirrus_blt_fgcol = s->cirrus_shadow_gr1 |
-            (s->vga.gr[0x11] << 8) | (s->vga.gr[0x13] << 16);
-        break;
-    default:
-    case 4:
-        color = s->cirrus_shadow_gr1 | (s->vga.gr[0x11] << 8) |
-            (s->vga.gr[0x13] << 16) | (s->vga.gr[0x15] << 24);
-        s->cirrus_blt_fgcol = le32_to_cpu(color);
-        break;
-    }
-}
-
-static inline void cirrus_bitblt_bgcol(CirrusVGAState *s)
-{
-    unsigned int color;
-    switch (s->cirrus_blt_pixelwidth) {
-    case 1:
-        s->cirrus_blt_bgcol = s->cirrus_shadow_gr0;
-        break;
-    case 2:
-        color = s->cirrus_shadow_gr0 | (s->vga.gr[0x10] << 8);
-        s->cirrus_blt_bgcol = le16_to_cpu(color);
-        break;
-    case 3:
-        s->cirrus_blt_bgcol = s->cirrus_shadow_gr0 |
-            (s->vga.gr[0x10] << 8) | (s->vga.gr[0x12] << 16);
-        break;
-    default:
-    case 4:
-        color = s->cirrus_shadow_gr0 | (s->vga.gr[0x10] << 8) |
-            (s->vga.gr[0x12] << 16) | (s->vga.gr[0x14] << 24);
-        s->cirrus_blt_bgcol = le32_to_cpu(color);
-        break;
-    }
-}
-
-static void cirrus_invalidate_region(CirrusVGAState * s, int off_begin,
-                                    int off_pitch, int bytesperline,
-                                    int lines)
-{
-    int y;
-    int off_cur;
-    int off_cur_end;
-
-    for (y = 0; y < lines; y++) {
-       off_cur = off_begin;
-       off_cur_end = (off_cur + bytesperline) & s->cirrus_addr_mask;
-        memory_region_set_dirty(&s->vga.vram, off_cur, off_cur_end - off_cur);
-       off_begin += off_pitch;
-    }
-}
-
-static int cirrus_bitblt_common_patterncopy(CirrusVGAState * s,
-                                           const uint8_t * src)
-{
-    uint8_t *dst;
-
-    dst = s->vga.vram_ptr + (s->cirrus_blt_dstaddr & s->cirrus_addr_mask);
-
-    if (BLTUNSAFE(s))
-        return 0;
-
-    (*s->cirrus_rop) (s, dst, src,
-                      s->cirrus_blt_dstpitch, 0,
-                      s->cirrus_blt_width, s->cirrus_blt_height);
-    cirrus_invalidate_region(s, s->cirrus_blt_dstaddr,
-                             s->cirrus_blt_dstpitch, s->cirrus_blt_width,
-                             s->cirrus_blt_height);
-    return 1;
-}
-
-/* fill */
-
-static int cirrus_bitblt_solidfill(CirrusVGAState *s, int blt_rop)
-{
-    cirrus_fill_t rop_func;
-
-    if (BLTUNSAFE(s))
-        return 0;
-    rop_func = cirrus_fill[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
-    rop_func(s, s->vga.vram_ptr + (s->cirrus_blt_dstaddr & s->cirrus_addr_mask),
-             s->cirrus_blt_dstpitch,
-             s->cirrus_blt_width, s->cirrus_blt_height);
-    cirrus_invalidate_region(s, s->cirrus_blt_dstaddr,
-                            s->cirrus_blt_dstpitch, s->cirrus_blt_width,
-                            s->cirrus_blt_height);
-    cirrus_bitblt_reset(s);
-    return 1;
-}
-
-/***************************************
- *
- *  bitblt (video-to-video)
- *
- ***************************************/
-
-static int cirrus_bitblt_videotovideo_patterncopy(CirrusVGAState * s)
-{
-    return cirrus_bitblt_common_patterncopy(s,
-                                           s->vga.vram_ptr + ((s->cirrus_blt_srcaddr & ~7) &
-                                            s->cirrus_addr_mask));
-}
-
-static void cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h)
-{
-    int sx = 0, sy = 0;
-    int dx = 0, dy = 0;
-    int depth = 0;
-    int notify = 0;
-
-    /* make sure to only copy if it's a plain copy ROP */
-    if (*s->cirrus_rop == cirrus_bitblt_rop_fwd_src ||
-        *s->cirrus_rop == cirrus_bitblt_rop_bkwd_src) {
-
-        int width, height;
-
-        depth = s->vga.get_bpp(&s->vga) / 8;
-        s->vga.get_resolution(&s->vga, &width, &height);
-
-        /* extra x, y */
-        sx = (src % ABS(s->cirrus_blt_srcpitch)) / depth;
-        sy = (src / ABS(s->cirrus_blt_srcpitch));
-        dx = (dst % ABS(s->cirrus_blt_dstpitch)) / depth;
-        dy = (dst / ABS(s->cirrus_blt_dstpitch));
-
-        /* normalize width */
-        w /= depth;
-
-        /* if we're doing a backward copy, we have to adjust
-           our x/y to be the upper left corner (instead of the lower
-           right corner) */
-        if (s->cirrus_blt_dstpitch < 0) {
-            sx -= (s->cirrus_blt_width / depth) - 1;
-            dx -= (s->cirrus_blt_width / depth) - 1;
-            sy -= s->cirrus_blt_height - 1;
-            dy -= s->cirrus_blt_height - 1;
-        }
-
-        /* are we in the visible portion of memory? */
-        if (sx >= 0 && sy >= 0 && dx >= 0 && dy >= 0 &&
-            (sx + w) <= width && (sy + h) <= height &&
-            (dx + w) <= width && (dy + h) <= height) {
-            notify = 1;
-        }
-    }
-
-    /* we have to flush all pending changes so that the copy
-       is generated at the appropriate moment in time */
-    if (notify)
-       vga_hw_update();
-
-    (*s->cirrus_rop) (s, s->vga.vram_ptr +
-                     (s->cirrus_blt_dstaddr & s->cirrus_addr_mask),
-                     s->vga.vram_ptr +
-                     (s->cirrus_blt_srcaddr & s->cirrus_addr_mask),
-                     s->cirrus_blt_dstpitch, s->cirrus_blt_srcpitch,
-                     s->cirrus_blt_width, s->cirrus_blt_height);
-
-    if (notify) {
-        qemu_console_copy(s->vga.con,
-                         sx, sy, dx, dy,
-                         s->cirrus_blt_width / depth,
-                         s->cirrus_blt_height);
-    }
-
-    /* we don't have to notify the display that this portion has
-       changed since qemu_console_copy implies this */
-
-    cirrus_invalidate_region(s, s->cirrus_blt_dstaddr,
-                               s->cirrus_blt_dstpitch, s->cirrus_blt_width,
-                               s->cirrus_blt_height);
-}
-
-static int cirrus_bitblt_videotovideo_copy(CirrusVGAState * s)
-{
-    if (BLTUNSAFE(s))
-        return 0;
-
-    cirrus_do_copy(s, s->cirrus_blt_dstaddr - s->vga.start_addr,
-            s->cirrus_blt_srcaddr - s->vga.start_addr,
-            s->cirrus_blt_width, s->cirrus_blt_height);
-
-    return 1;
-}
-
-/***************************************
- *
- *  bitblt (cpu-to-video)
- *
- ***************************************/
-
-static void cirrus_bitblt_cputovideo_next(CirrusVGAState * s)
-{
-    int copy_count;
-    uint8_t *end_ptr;
-
-    if (s->cirrus_srccounter > 0) {
-        if (s->cirrus_blt_mode & CIRRUS_BLTMODE_PATTERNCOPY) {
-            cirrus_bitblt_common_patterncopy(s, s->cirrus_bltbuf);
-        the_end:
-            s->cirrus_srccounter = 0;
-            cirrus_bitblt_reset(s);
-        } else {
-            /* at least one scan line */
-            do {
-                (*s->cirrus_rop)(s, s->vga.vram_ptr +
-                                 (s->cirrus_blt_dstaddr & s->cirrus_addr_mask),
-                                  s->cirrus_bltbuf, 0, 0, s->cirrus_blt_width, 1);
-                cirrus_invalidate_region(s, s->cirrus_blt_dstaddr, 0,
-                                         s->cirrus_blt_width, 1);
-                s->cirrus_blt_dstaddr += s->cirrus_blt_dstpitch;
-                s->cirrus_srccounter -= s->cirrus_blt_srcpitch;
-                if (s->cirrus_srccounter <= 0)
-                    goto the_end;
-                /* more bytes than needed can be transferred because of
-                   word alignment, so we keep them for the next line */
-                /* XXX: keep alignment to speed up transfer */
-                end_ptr = s->cirrus_bltbuf + s->cirrus_blt_srcpitch;
-                copy_count = s->cirrus_srcptr_end - end_ptr;
-                memmove(s->cirrus_bltbuf, end_ptr, copy_count);
-                s->cirrus_srcptr = s->cirrus_bltbuf + copy_count;
-                s->cirrus_srcptr_end = s->cirrus_bltbuf + s->cirrus_blt_srcpitch;
-            } while (s->cirrus_srcptr >= s->cirrus_srcptr_end);
-        }
-    }
-}
-
-/***************************************
- *
- *  bitblt wrapper
- *
- ***************************************/
-
-static void cirrus_bitblt_reset(CirrusVGAState * s)
-{
-    int need_update;
-
-    s->vga.gr[0x31] &=
-       ~(CIRRUS_BLT_START | CIRRUS_BLT_BUSY | CIRRUS_BLT_FIFOUSED);
-    need_update = s->cirrus_srcptr != &s->cirrus_bltbuf[0]
-        || s->cirrus_srcptr_end != &s->cirrus_bltbuf[0];
-    s->cirrus_srcptr = &s->cirrus_bltbuf[0];
-    s->cirrus_srcptr_end = &s->cirrus_bltbuf[0];
-    s->cirrus_srccounter = 0;
-    if (!need_update)
-        return;
-    cirrus_update_memory_access(s);
-}
-
-static int cirrus_bitblt_cputovideo(CirrusVGAState * s)
-{
-    int w;
-
-    s->cirrus_blt_mode &= ~CIRRUS_BLTMODE_MEMSYSSRC;
-    s->cirrus_srcptr = &s->cirrus_bltbuf[0];
-    s->cirrus_srcptr_end = &s->cirrus_bltbuf[0];
-
-    if (s->cirrus_blt_mode & CIRRUS_BLTMODE_PATTERNCOPY) {
-       if (s->cirrus_blt_mode & CIRRUS_BLTMODE_COLOREXPAND) {
-           s->cirrus_blt_srcpitch = 8;
-       } else {
-            /* XXX: check for 24 bpp */
-           s->cirrus_blt_srcpitch = 8 * 8 * s->cirrus_blt_pixelwidth;
-       }
-       s->cirrus_srccounter = s->cirrus_blt_srcpitch;
-    } else {
-       if (s->cirrus_blt_mode & CIRRUS_BLTMODE_COLOREXPAND) {
-            w = s->cirrus_blt_width / s->cirrus_blt_pixelwidth;
-            if (s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_DWORDGRANULARITY)
-                s->cirrus_blt_srcpitch = ((w + 31) >> 5);
-            else
-                s->cirrus_blt_srcpitch = ((w + 7) >> 3);
-       } else {
-            /* always align input size to 32 bits */
-           s->cirrus_blt_srcpitch = (s->cirrus_blt_width + 3) & ~3;
-       }
-        s->cirrus_srccounter = s->cirrus_blt_srcpitch * s->cirrus_blt_height;
-    }
-    s->cirrus_srcptr = s->cirrus_bltbuf;
-    s->cirrus_srcptr_end = s->cirrus_bltbuf + s->cirrus_blt_srcpitch;
-    cirrus_update_memory_access(s);
-    return 1;
-}
-
-static int cirrus_bitblt_videotocpu(CirrusVGAState * s)
-{
-    /* XXX */
-#ifdef DEBUG_BITBLT
-    printf("cirrus: bitblt (video to cpu) is not implemented yet\n");
-#endif
-    return 0;
-}
-
-static int cirrus_bitblt_videotovideo(CirrusVGAState * s)
-{
-    int ret;
-
-    if (s->cirrus_blt_mode & CIRRUS_BLTMODE_PATTERNCOPY) {
-       ret = cirrus_bitblt_videotovideo_patterncopy(s);
-    } else {
-       ret = cirrus_bitblt_videotovideo_copy(s);
-    }
-    if (ret)
-       cirrus_bitblt_reset(s);
-    return ret;
-}
-
-static void cirrus_bitblt_start(CirrusVGAState * s)
-{
-    uint8_t blt_rop;
-
-    s->vga.gr[0x31] |= CIRRUS_BLT_BUSY;
-
-    s->cirrus_blt_width = (s->vga.gr[0x20] | (s->vga.gr[0x21] << 8)) + 1;
-    s->cirrus_blt_height = (s->vga.gr[0x22] | (s->vga.gr[0x23] << 8)) + 1;
-    s->cirrus_blt_dstpitch = (s->vga.gr[0x24] | (s->vga.gr[0x25] << 8));
-    s->cirrus_blt_srcpitch = (s->vga.gr[0x26] | (s->vga.gr[0x27] << 8));
-    s->cirrus_blt_dstaddr =
-       (s->vga.gr[0x28] | (s->vga.gr[0x29] << 8) | (s->vga.gr[0x2a] << 16));
-    s->cirrus_blt_srcaddr =
-       (s->vga.gr[0x2c] | (s->vga.gr[0x2d] << 8) | (s->vga.gr[0x2e] << 16));
-    s->cirrus_blt_mode = s->vga.gr[0x30];
-    s->cirrus_blt_modeext = s->vga.gr[0x33];
-    blt_rop = s->vga.gr[0x32];
-
-#ifdef DEBUG_BITBLT
-    printf("rop=0x%02x mode=0x%02x modeext=0x%02x w=%d h=%d dpitch=%d spitch=%d daddr=0x%08x saddr=0x%08x writemask=0x%02x\n",
-           blt_rop,
-           s->cirrus_blt_mode,
-           s->cirrus_blt_modeext,
-           s->cirrus_blt_width,
-           s->cirrus_blt_height,
-           s->cirrus_blt_dstpitch,
-           s->cirrus_blt_srcpitch,
-           s->cirrus_blt_dstaddr,
-           s->cirrus_blt_srcaddr,
-           s->vga.gr[0x2f]);
-#endif
-
-    switch (s->cirrus_blt_mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) {
-    case CIRRUS_BLTMODE_PIXELWIDTH8:
-       s->cirrus_blt_pixelwidth = 1;
-       break;
-    case CIRRUS_BLTMODE_PIXELWIDTH16:
-       s->cirrus_blt_pixelwidth = 2;
-       break;
-    case CIRRUS_BLTMODE_PIXELWIDTH24:
-       s->cirrus_blt_pixelwidth = 3;
-       break;
-    case CIRRUS_BLTMODE_PIXELWIDTH32:
-       s->cirrus_blt_pixelwidth = 4;
-       break;
-    default:
-#ifdef DEBUG_BITBLT
-       printf("cirrus: bitblt - pixel width is unknown\n");
-#endif
-       goto bitblt_ignore;
-    }
-    s->cirrus_blt_mode &= ~CIRRUS_BLTMODE_PIXELWIDTHMASK;
-
-    if ((s->
-        cirrus_blt_mode & (CIRRUS_BLTMODE_MEMSYSSRC |
-                           CIRRUS_BLTMODE_MEMSYSDEST))
-       == (CIRRUS_BLTMODE_MEMSYSSRC | CIRRUS_BLTMODE_MEMSYSDEST)) {
-#ifdef DEBUG_BITBLT
-       printf("cirrus: bitblt - memory-to-memory copy is requested\n");
-#endif
-       goto bitblt_ignore;
-    }
-
-    if ((s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_SOLIDFILL) &&
-        (s->cirrus_blt_mode & (CIRRUS_BLTMODE_MEMSYSDEST |
-                               CIRRUS_BLTMODE_TRANSPARENTCOMP |
-                               CIRRUS_BLTMODE_PATTERNCOPY |
-                               CIRRUS_BLTMODE_COLOREXPAND)) ==
-         (CIRRUS_BLTMODE_PATTERNCOPY | CIRRUS_BLTMODE_COLOREXPAND)) {
-        cirrus_bitblt_fgcol(s);
-        cirrus_bitblt_solidfill(s, blt_rop);
-    } else {
-        if ((s->cirrus_blt_mode & (CIRRUS_BLTMODE_COLOREXPAND |
-                                   CIRRUS_BLTMODE_PATTERNCOPY)) ==
-            CIRRUS_BLTMODE_COLOREXPAND) {
-
-            if (s->cirrus_blt_mode & CIRRUS_BLTMODE_TRANSPARENTCOMP) {
-                if (s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_COLOREXPINV)
-                    cirrus_bitblt_bgcol(s);
-                else
-                    cirrus_bitblt_fgcol(s);
-                s->cirrus_rop = cirrus_colorexpand_transp[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
-            } else {
-                cirrus_bitblt_fgcol(s);
-                cirrus_bitblt_bgcol(s);
-                s->cirrus_rop = cirrus_colorexpand[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
-            }
-        } else if (s->cirrus_blt_mode & CIRRUS_BLTMODE_PATTERNCOPY) {
-            if (s->cirrus_blt_mode & CIRRUS_BLTMODE_COLOREXPAND) {
-                if (s->cirrus_blt_mode & CIRRUS_BLTMODE_TRANSPARENTCOMP) {
-                    if (s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_COLOREXPINV)
-                        cirrus_bitblt_bgcol(s);
-                    else
-                        cirrus_bitblt_fgcol(s);
-                    s->cirrus_rop = cirrus_colorexpand_pattern_transp[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
-                } else {
-                    cirrus_bitblt_fgcol(s);
-                    cirrus_bitblt_bgcol(s);
-                    s->cirrus_rop = cirrus_colorexpand_pattern[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
-                }
-            } else {
-                s->cirrus_rop = cirrus_patternfill[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
-            }
-        } else {
-           if (s->cirrus_blt_mode & CIRRUS_BLTMODE_TRANSPARENTCOMP) {
-               if (s->cirrus_blt_pixelwidth > 2) {
-                   printf("src transparent without colorexpand must be 8bpp or 16bpp\n");
-                   goto bitblt_ignore;
-               }
-               if (s->cirrus_blt_mode & CIRRUS_BLTMODE_BACKWARDS) {
-                   s->cirrus_blt_dstpitch = -s->cirrus_blt_dstpitch;
-                   s->cirrus_blt_srcpitch = -s->cirrus_blt_srcpitch;
-                   s->cirrus_rop = cirrus_bkwd_transp_rop[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
-               } else {
-                   s->cirrus_rop = cirrus_fwd_transp_rop[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
-               }
-           } else {
-               if (s->cirrus_blt_mode & CIRRUS_BLTMODE_BACKWARDS) {
-                   s->cirrus_blt_dstpitch = -s->cirrus_blt_dstpitch;
-                   s->cirrus_blt_srcpitch = -s->cirrus_blt_srcpitch;
-                   s->cirrus_rop = cirrus_bkwd_rop[rop_to_index[blt_rop]];
-               } else {
-                   s->cirrus_rop = cirrus_fwd_rop[rop_to_index[blt_rop]];
-               }
-           }
-       }
-        // setup bitblt engine.
-        if (s->cirrus_blt_mode & CIRRUS_BLTMODE_MEMSYSSRC) {
-            if (!cirrus_bitblt_cputovideo(s))
-                goto bitblt_ignore;
-        } else if (s->cirrus_blt_mode & CIRRUS_BLTMODE_MEMSYSDEST) {
-            if (!cirrus_bitblt_videotocpu(s))
-                goto bitblt_ignore;
-        } else {
-            if (!cirrus_bitblt_videotovideo(s))
-                goto bitblt_ignore;
-        }
-    }
-    return;
-  bitblt_ignore:;
-    cirrus_bitblt_reset(s);
-}
-
-static void cirrus_write_bitblt(CirrusVGAState * s, unsigned reg_value)
-{
-    unsigned old_value;
-
-    old_value = s->vga.gr[0x31];
-    s->vga.gr[0x31] = reg_value;
-
-    if (((old_value & CIRRUS_BLT_RESET) != 0) &&
-       ((reg_value & CIRRUS_BLT_RESET) == 0)) {
-       cirrus_bitblt_reset(s);
-    } else if (((old_value & CIRRUS_BLT_START) == 0) &&
-              ((reg_value & CIRRUS_BLT_START) != 0)) {
-       cirrus_bitblt_start(s);
-    }
-}
-
-
-/***************************************
- *
- *  basic parameters
- *
- ***************************************/
-
-static void cirrus_get_offsets(VGACommonState *s1,
-                               uint32_t *pline_offset,
-                               uint32_t *pstart_addr,
-                               uint32_t *pline_compare)
-{
-    CirrusVGAState * s = container_of(s1, CirrusVGAState, vga);
-    uint32_t start_addr, line_offset, line_compare;
-
-    line_offset = s->vga.cr[0x13]
-       | ((s->vga.cr[0x1b] & 0x10) << 4);
-    line_offset <<= 3;
-    *pline_offset = line_offset;
-
-    start_addr = (s->vga.cr[0x0c] << 8)
-       | s->vga.cr[0x0d]
-       | ((s->vga.cr[0x1b] & 0x01) << 16)
-       | ((s->vga.cr[0x1b] & 0x0c) << 15)
-       | ((s->vga.cr[0x1d] & 0x80) << 12);
-    *pstart_addr = start_addr;
-
-    line_compare = s->vga.cr[0x18] |
-        ((s->vga.cr[0x07] & 0x10) << 4) |
-        ((s->vga.cr[0x09] & 0x40) << 3);
-    *pline_compare = line_compare;
-}
-
-static uint32_t cirrus_get_bpp16_depth(CirrusVGAState * s)
-{
-    uint32_t ret = 16;
-
-    switch (s->cirrus_hidden_dac_data & 0xf) {
-    case 0:
-       ret = 15;
-       break;                  /* Sierra HiColor */
-    case 1:
-       ret = 16;
-       break;                  /* XGA HiColor */
-    default:
-#ifdef DEBUG_CIRRUS
-       printf("cirrus: invalid DAC value %x in 16bpp\n",
-              (s->cirrus_hidden_dac_data & 0xf));
-#endif
-       ret = 15;               /* XXX */
-       break;
-    }
-    return ret;
-}
-
-static int cirrus_get_bpp(VGACommonState *s1)
-{
-    CirrusVGAState * s = container_of(s1, CirrusVGAState, vga);
-    uint32_t ret = 8;
-
-    if ((s->vga.sr[0x07] & 0x01) != 0) {
-       /* Cirrus SVGA */
-       switch (s->vga.sr[0x07] & CIRRUS_SR7_BPP_MASK) {
-       case CIRRUS_SR7_BPP_8:
-           ret = 8;
-           break;
-       case CIRRUS_SR7_BPP_16_DOUBLEVCLK:
-           ret = cirrus_get_bpp16_depth(s);
-           break;
-       case CIRRUS_SR7_BPP_24:
-           ret = 24;
-           break;
-       case CIRRUS_SR7_BPP_16:
-           ret = cirrus_get_bpp16_depth(s);
-           break;
-       case CIRRUS_SR7_BPP_32:
-           ret = 32;
-           break;
-       default:
-#ifdef DEBUG_CIRRUS
-           printf("cirrus: unknown bpp - sr7=%x\n", s->vga.sr[0x7]);
-#endif
-           ret = 8;
-           break;
-       }
-    } else {
-       /* VGA */
-       ret = 0;
-    }
-
-    return ret;
-}
-
-static void cirrus_get_resolution(VGACommonState *s, int *pwidth, int *pheight)
-{
-    int width, height;
-
-    width = (s->cr[0x01] + 1) * 8;
-    height = s->cr[0x12] |
-        ((s->cr[0x07] & 0x02) << 7) |
-        ((s->cr[0x07] & 0x40) << 3);
-    height = (height + 1);
-    /* interlace support */
-    if (s->cr[0x1a] & 0x01)
-        height = height * 2;
-    *pwidth = width;
-    *pheight = height;
-}
-
-/***************************************
- *
- * bank memory
- *
- ***************************************/
-
-static void cirrus_update_bank_ptr(CirrusVGAState * s, unsigned bank_index)
-{
-    unsigned offset;
-    unsigned limit;
-
-    if ((s->vga.gr[0x0b] & 0x01) != 0) /* dual bank */
-       offset = s->vga.gr[0x09 + bank_index];
-    else                       /* single bank */
-       offset = s->vga.gr[0x09];
-
-    if ((s->vga.gr[0x0b] & 0x20) != 0)
-       offset <<= 14;
-    else
-       offset <<= 12;
-
-    if (s->real_vram_size <= offset)
-       limit = 0;
-    else
-       limit = s->real_vram_size - offset;
-
-    if (((s->vga.gr[0x0b] & 0x01) == 0) && (bank_index != 0)) {
-       if (limit > 0x8000) {
-           offset += 0x8000;
-           limit -= 0x8000;
-       } else {
-           limit = 0;
-       }
-    }
-
-    if (limit > 0) {
-       s->cirrus_bank_base[bank_index] = offset;
-       s->cirrus_bank_limit[bank_index] = limit;
-    } else {
-       s->cirrus_bank_base[bank_index] = 0;
-       s->cirrus_bank_limit[bank_index] = 0;
-    }
-}
-
-/***************************************
- *
- *  I/O access between 0x3c4-0x3c5
- *
- ***************************************/
-
-static int cirrus_vga_read_sr(CirrusVGAState * s)
-{
-    switch (s->vga.sr_index) {
-    case 0x00:                 // Standard VGA
-    case 0x01:                 // Standard VGA
-    case 0x02:                 // Standard VGA
-    case 0x03:                 // Standard VGA
-    case 0x04:                 // Standard VGA
-       return s->vga.sr[s->vga.sr_index];
-    case 0x06:                 // Unlock Cirrus extensions
-       return s->vga.sr[s->vga.sr_index];
-    case 0x10:
-    case 0x30:
-    case 0x50:
-    case 0x70:                 // Graphics Cursor X
-    case 0x90:
-    case 0xb0:
-    case 0xd0:
-    case 0xf0:                 // Graphics Cursor X
-       return s->vga.sr[0x10];
-    case 0x11:
-    case 0x31:
-    case 0x51:
-    case 0x71:                 // Graphics Cursor Y
-    case 0x91:
-    case 0xb1:
-    case 0xd1:
-    case 0xf1:                 // Graphics Cursor Y
-       return s->vga.sr[0x11];
-    case 0x05:                 // ???
-    case 0x07:                 // Extended Sequencer Mode
-    case 0x08:                 // EEPROM Control
-    case 0x09:                 // Scratch Register 0
-    case 0x0a:                 // Scratch Register 1
-    case 0x0b:                 // VCLK 0
-    case 0x0c:                 // VCLK 1
-    case 0x0d:                 // VCLK 2
-    case 0x0e:                 // VCLK 3
-    case 0x0f:                 // DRAM Control
-    case 0x12:                 // Graphics Cursor Attribute
-    case 0x13:                 // Graphics Cursor Pattern Address
-    case 0x14:                 // Scratch Register 2
-    case 0x15:                 // Scratch Register 3
-    case 0x16:                 // Performance Tuning Register
-    case 0x17:                 // Configuration Readback and Extended Control
-    case 0x18:                 // Signature Generator Control
-    case 0x19:                 // Signal Generator Result
-    case 0x1a:                 // Signal Generator Result
-    case 0x1b:                 // VCLK 0 Denominator & Post
-    case 0x1c:                 // VCLK 1 Denominator & Post
-    case 0x1d:                 // VCLK 2 Denominator & Post
-    case 0x1e:                 // VCLK 3 Denominator & Post
-    case 0x1f:                 // BIOS Write Enable and MCLK select
-#ifdef DEBUG_CIRRUS
-       printf("cirrus: handled inport sr_index %02x\n", s->vga.sr_index);
-#endif
-       return s->vga.sr[s->vga.sr_index];
-    default:
-#ifdef DEBUG_CIRRUS
-       printf("cirrus: inport sr_index %02x\n", s->vga.sr_index);
-#endif
-       return 0xff;
-       break;
-    }
-}
-
-static void cirrus_vga_write_sr(CirrusVGAState * s, uint32_t val)
-{
-    switch (s->vga.sr_index) {
-    case 0x00:                 // Standard VGA
-    case 0x01:                 // Standard VGA
-    case 0x02:                 // Standard VGA
-    case 0x03:                 // Standard VGA
-    case 0x04:                 // Standard VGA
-       s->vga.sr[s->vga.sr_index] = val & sr_mask[s->vga.sr_index];
-       if (s->vga.sr_index == 1)
-            s->vga.update_retrace_info(&s->vga);
-        break;
-    case 0x06:                 // Unlock Cirrus extensions
-       val &= 0x17;
-       if (val == 0x12) {
-           s->vga.sr[s->vga.sr_index] = 0x12;
-       } else {
-           s->vga.sr[s->vga.sr_index] = 0x0f;
-       }
-       break;
-    case 0x10:
-    case 0x30:
-    case 0x50:
-    case 0x70:                 // Graphics Cursor X
-    case 0x90:
-    case 0xb0:
-    case 0xd0:
-    case 0xf0:                 // Graphics Cursor X
-       s->vga.sr[0x10] = val;
-       s->hw_cursor_x = (val << 3) | (s->vga.sr_index >> 5);
-       break;
-    case 0x11:
-    case 0x31:
-    case 0x51:
-    case 0x71:                 // Graphics Cursor Y
-    case 0x91:
-    case 0xb1:
-    case 0xd1:
-    case 0xf1:                 // Graphics Cursor Y
-       s->vga.sr[0x11] = val;
-       s->hw_cursor_y = (val << 3) | (s->vga.sr_index >> 5);
-       break;
-    case 0x07:                 // Extended Sequencer Mode
-    cirrus_update_memory_access(s);
-    case 0x08:                 // EEPROM Control
-    case 0x09:                 // Scratch Register 0
-    case 0x0a:                 // Scratch Register 1
-    case 0x0b:                 // VCLK 0
-    case 0x0c:                 // VCLK 1
-    case 0x0d:                 // VCLK 2
-    case 0x0e:                 // VCLK 3
-    case 0x0f:                 // DRAM Control
-    case 0x12:                 // Graphics Cursor Attribute
-    case 0x13:                 // Graphics Cursor Pattern Address
-    case 0x14:                 // Scratch Register 2
-    case 0x15:                 // Scratch Register 3
-    case 0x16:                 // Performance Tuning Register
-    case 0x18:                 // Signature Generator Control
-    case 0x19:                 // Signature Generator Result
-    case 0x1a:                 // Signature Generator Result
-    case 0x1b:                 // VCLK 0 Denominator & Post
-    case 0x1c:                 // VCLK 1 Denominator & Post
-    case 0x1d:                 // VCLK 2 Denominator & Post
-    case 0x1e:                 // VCLK 3 Denominator & Post
-    case 0x1f:                 // BIOS Write Enable and MCLK select
-       s->vga.sr[s->vga.sr_index] = val;
-#ifdef DEBUG_CIRRUS
-       printf("cirrus: handled outport sr_index %02x, sr_value %02x\n",
-              s->vga.sr_index, val);
-#endif
-       break;
-    case 0x17:                 // Configuration Readback and Extended Control
-       s->vga.sr[s->vga.sr_index] = (s->vga.sr[s->vga.sr_index] & 0x38)
-                                   | (val & 0xc7);
-        cirrus_update_memory_access(s);
-        break;
-    default:
-#ifdef DEBUG_CIRRUS
-       printf("cirrus: outport sr_index %02x, sr_value %02x\n",
-               s->vga.sr_index, val);
-#endif
-       break;
-    }
-}
-
-/***************************************
- *
- *  I/O access at 0x3c6
- *
- ***************************************/
-
-static int cirrus_read_hidden_dac(CirrusVGAState * s)
-{
-    if (++s->cirrus_hidden_dac_lockindex == 5) {
-        s->cirrus_hidden_dac_lockindex = 0;
-        return s->cirrus_hidden_dac_data;
-    }
-    return 0xff;
-}
-
-static void cirrus_write_hidden_dac(CirrusVGAState * s, int reg_value)
-{
-    if (s->cirrus_hidden_dac_lockindex == 4) {
-       s->cirrus_hidden_dac_data = reg_value;
-#if defined(DEBUG_CIRRUS)
-       printf("cirrus: outport hidden DAC, value %02x\n", reg_value);
-#endif
-    }
-    s->cirrus_hidden_dac_lockindex = 0;
-}
-
-/***************************************
- *
- *  I/O access at 0x3c9
- *
- ***************************************/
-
-static int cirrus_vga_read_palette(CirrusVGAState * s)
-{
-    int val;
-
-    if ((s->vga.sr[0x12] & CIRRUS_CURSOR_HIDDENPEL)) {
-        val = s->cirrus_hidden_palette[(s->vga.dac_read_index & 0x0f) * 3 +
-                                       s->vga.dac_sub_index];
-    } else {
-        val = s->vga.palette[s->vga.dac_read_index * 3 + s->vga.dac_sub_index];
-    }
-    if (++s->vga.dac_sub_index == 3) {
-       s->vga.dac_sub_index = 0;
-       s->vga.dac_read_index++;
-    }
-    return val;
-}
-
-static void cirrus_vga_write_palette(CirrusVGAState * s, int reg_value)
-{
-    s->vga.dac_cache[s->vga.dac_sub_index] = reg_value;
-    if (++s->vga.dac_sub_index == 3) {
-        if ((s->vga.sr[0x12] & CIRRUS_CURSOR_HIDDENPEL)) {
-            memcpy(&s->cirrus_hidden_palette[(s->vga.dac_write_index & 0x0f) * 3],
-                   s->vga.dac_cache, 3);
-        } else {
-            memcpy(&s->vga.palette[s->vga.dac_write_index * 3], s->vga.dac_cache, 3);
-        }
-        /* XXX update cursor */
-       s->vga.dac_sub_index = 0;
-       s->vga.dac_write_index++;
-    }
-}
-
-/***************************************
- *
- *  I/O access between 0x3ce-0x3cf
- *
- ***************************************/
-
-static int cirrus_vga_read_gr(CirrusVGAState * s, unsigned reg_index)
-{
-    switch (reg_index) {
-    case 0x00: // Standard VGA, BGCOLOR 0x000000ff
-        return s->cirrus_shadow_gr0;
-    case 0x01: // Standard VGA, FGCOLOR 0x000000ff
-        return s->cirrus_shadow_gr1;
-    case 0x02:                 // Standard VGA
-    case 0x03:                 // Standard VGA
-    case 0x04:                 // Standard VGA
-    case 0x06:                 // Standard VGA
-    case 0x07:                 // Standard VGA
-    case 0x08:                 // Standard VGA
-        return s->vga.gr[s->vga.gr_index];
-    case 0x05:                 // Standard VGA, Cirrus extended mode
-    default:
-       break;
-    }
-
-    if (reg_index < 0x3a) {
-       return s->vga.gr[reg_index];
-    } else {
-#ifdef DEBUG_CIRRUS
-       printf("cirrus: inport gr_index %02x\n", reg_index);
-#endif
-       return 0xff;
-    }
-}
-
-static void
-cirrus_vga_write_gr(CirrusVGAState * s, unsigned reg_index, int reg_value)
-{
-#if defined(DEBUG_BITBLT) && 0
-    printf("gr%02x: %02x\n", reg_index, reg_value);
-#endif
-    switch (reg_index) {
-    case 0x00:                 // Standard VGA, BGCOLOR 0x000000ff
-       s->vga.gr[reg_index] = reg_value & gr_mask[reg_index];
-       s->cirrus_shadow_gr0 = reg_value;
-       break;
-    case 0x01:                 // Standard VGA, FGCOLOR 0x000000ff
-       s->vga.gr[reg_index] = reg_value & gr_mask[reg_index];
-       s->cirrus_shadow_gr1 = reg_value;
-       break;
-    case 0x02:                 // Standard VGA
-    case 0x03:                 // Standard VGA
-    case 0x04:                 // Standard VGA
-    case 0x06:                 // Standard VGA
-    case 0x07:                 // Standard VGA
-    case 0x08:                 // Standard VGA
-       s->vga.gr[reg_index] = reg_value & gr_mask[reg_index];
-        break;
-    case 0x05:                 // Standard VGA, Cirrus extended mode
-       s->vga.gr[reg_index] = reg_value & 0x7f;
-        cirrus_update_memory_access(s);
-       break;
-    case 0x09:                 // bank offset #0
-    case 0x0A:                 // bank offset #1
-       s->vga.gr[reg_index] = reg_value;
-       cirrus_update_bank_ptr(s, 0);
-       cirrus_update_bank_ptr(s, 1);
-        cirrus_update_memory_access(s);
-        break;
-    case 0x0B:
-       s->vga.gr[reg_index] = reg_value;
-       cirrus_update_bank_ptr(s, 0);
-       cirrus_update_bank_ptr(s, 1);
-        cirrus_update_memory_access(s);
-       break;
-    case 0x10:                 // BGCOLOR 0x0000ff00
-    case 0x11:                 // FGCOLOR 0x0000ff00
-    case 0x12:                 // BGCOLOR 0x00ff0000
-    case 0x13:                 // FGCOLOR 0x00ff0000
-    case 0x14:                 // BGCOLOR 0xff000000
-    case 0x15:                 // FGCOLOR 0xff000000
-    case 0x20:                 // BLT WIDTH 0x0000ff
-    case 0x22:                 // BLT HEIGHT 0x0000ff
-    case 0x24:                 // BLT DEST PITCH 0x0000ff
-    case 0x26:                 // BLT SRC PITCH 0x0000ff
-    case 0x28:                 // BLT DEST ADDR 0x0000ff
-    case 0x29:                 // BLT DEST ADDR 0x00ff00
-    case 0x2c:                 // BLT SRC ADDR 0x0000ff
-    case 0x2d:                 // BLT SRC ADDR 0x00ff00
-    case 0x2f:                  // BLT WRITEMASK
-    case 0x30:                 // BLT MODE
-    case 0x32:                 // RASTER OP
-    case 0x33:                 // BLT MODEEXT
-    case 0x34:                 // BLT TRANSPARENT COLOR 0x00ff
-    case 0x35:                 // BLT TRANSPARENT COLOR 0xff00
-    case 0x38:                 // BLT TRANSPARENT COLOR MASK 0x00ff
-    case 0x39:                 // BLT TRANSPARENT COLOR MASK 0xff00
-       s->vga.gr[reg_index] = reg_value;
-       break;
-    case 0x21:                 // BLT WIDTH 0x001f00
-    case 0x23:                 // BLT HEIGHT 0x001f00
-    case 0x25:                 // BLT DEST PITCH 0x001f00
-    case 0x27:                 // BLT SRC PITCH 0x001f00
-       s->vga.gr[reg_index] = reg_value & 0x1f;
-       break;
-    case 0x2a:                 // BLT DEST ADDR 0x3f0000
-       s->vga.gr[reg_index] = reg_value & 0x3f;
-        /* if auto start mode, starts bit blt now */
-        if (s->vga.gr[0x31] & CIRRUS_BLT_AUTOSTART) {
-            cirrus_bitblt_start(s);
-        }
-       break;
-    case 0x2e:                 // BLT SRC ADDR 0x3f0000
-       s->vga.gr[reg_index] = reg_value & 0x3f;
-       break;
-    case 0x31:                 // BLT STATUS/START
-       cirrus_write_bitblt(s, reg_value);
-       break;
-    default:
-#ifdef DEBUG_CIRRUS
-       printf("cirrus: outport gr_index %02x, gr_value %02x\n", reg_index,
-              reg_value);
-#endif
-       break;
-    }
-}
-
-/***************************************
- *
- *  I/O access between 0x3d4-0x3d5
- *
- ***************************************/
-
-static int cirrus_vga_read_cr(CirrusVGAState * s, unsigned reg_index)
-{
-    switch (reg_index) {
-    case 0x00:                 // Standard VGA
-    case 0x01:                 // Standard VGA
-    case 0x02:                 // Standard VGA
-    case 0x03:                 // Standard VGA
-    case 0x04:                 // Standard VGA
-    case 0x05:                 // Standard VGA
-    case 0x06:                 // Standard VGA
-    case 0x07:                 // Standard VGA
-    case 0x08:                 // Standard VGA
-    case 0x09:                 // Standard VGA
-    case 0x0a:                 // Standard VGA
-    case 0x0b:                 // Standard VGA
-    case 0x0c:                 // Standard VGA
-    case 0x0d:                 // Standard VGA
-    case 0x0e:                 // Standard VGA
-    case 0x0f:                 // Standard VGA
-    case 0x10:                 // Standard VGA
-    case 0x11:                 // Standard VGA
-    case 0x12:                 // Standard VGA
-    case 0x13:                 // Standard VGA
-    case 0x14:                 // Standard VGA
-    case 0x15:                 // Standard VGA
-    case 0x16:                 // Standard VGA
-    case 0x17:                 // Standard VGA
-    case 0x18:                 // Standard VGA
-       return s->vga.cr[s->vga.cr_index];
-    case 0x24:                 // Attribute Controller Toggle Readback (R)
-        return (s->vga.ar_flip_flop << 7);
-    case 0x19:                 // Interlace End
-    case 0x1a:                 // Miscellaneous Control
-    case 0x1b:                 // Extended Display Control
-    case 0x1c:                 // Sync Adjust and Genlock
-    case 0x1d:                 // Overlay Extended Control
-    case 0x22:                 // Graphics Data Latches Readback (R)
-    case 0x25:                 // Part Status
-    case 0x27:                 // Part ID (R)
-       return s->vga.cr[s->vga.cr_index];
-    case 0x26:                 // Attribute Controller Index Readback (R)
-       return s->vga.ar_index & 0x3f;
-       break;
-    default:
-#ifdef DEBUG_CIRRUS
-       printf("cirrus: inport cr_index %02x\n", reg_index);
-#endif
-       return 0xff;
-    }
-}
-
-static void cirrus_vga_write_cr(CirrusVGAState * s, int reg_value)
-{
-    switch (s->vga.cr_index) {
-    case 0x00:                 // Standard VGA
-    case 0x01:                 // Standard VGA
-    case 0x02:                 // Standard VGA
-    case 0x03:                 // Standard VGA
-    case 0x04:                 // Standard VGA
-    case 0x05:                 // Standard VGA
-    case 0x06:                 // Standard VGA
-    case 0x07:                 // Standard VGA
-    case 0x08:                 // Standard VGA
-    case 0x09:                 // Standard VGA
-    case 0x0a:                 // Standard VGA
-    case 0x0b:                 // Standard VGA
-    case 0x0c:                 // Standard VGA
-    case 0x0d:                 // Standard VGA
-    case 0x0e:                 // Standard VGA
-    case 0x0f:                 // Standard VGA
-    case 0x10:                 // Standard VGA
-    case 0x11:                 // Standard VGA
-    case 0x12:                 // Standard VGA
-    case 0x13:                 // Standard VGA
-    case 0x14:                 // Standard VGA
-    case 0x15:                 // Standard VGA
-    case 0x16:                 // Standard VGA
-    case 0x17:                 // Standard VGA
-    case 0x18:                 // Standard VGA
-       /* handle CR0-7 protection */
-       if ((s->vga.cr[0x11] & 0x80) && s->vga.cr_index <= 7) {
-           /* can always write bit 4 of CR7 */
-           if (s->vga.cr_index == 7)
-               s->vga.cr[7] = (s->vga.cr[7] & ~0x10) | (reg_value & 0x10);
-           return;
-       }
-       s->vga.cr[s->vga.cr_index] = reg_value;
-       switch(s->vga.cr_index) {
-       case 0x00:
-       case 0x04:
-       case 0x05:
-       case 0x06:
-       case 0x07:
-       case 0x11:
-       case 0x17:
-           s->vga.update_retrace_info(&s->vga);
-           break;
-       }
-        break;
-    case 0x19:                 // Interlace End
-    case 0x1a:                 // Miscellaneous Control
-    case 0x1b:                 // Extended Display Control
-    case 0x1c:                 // Sync Adjust and Genlock
-    case 0x1d:                 // Overlay Extended Control
-       s->vga.cr[s->vga.cr_index] = reg_value;
-#ifdef DEBUG_CIRRUS
-       printf("cirrus: handled outport cr_index %02x, cr_value %02x\n",
-              s->vga.cr_index, reg_value);
-#endif
-       break;
-    case 0x22:                 // Graphics Data Latches Readback (R)
-    case 0x24:                 // Attribute Controller Toggle Readback (R)
-    case 0x26:                 // Attribute Controller Index Readback (R)
-    case 0x27:                 // Part ID (R)
-       break;
-    case 0x25:                 // Part Status
-    default:
-#ifdef DEBUG_CIRRUS
-       printf("cirrus: outport cr_index %02x, cr_value %02x\n",
-               s->vga.cr_index, reg_value);
-#endif
-       break;
-    }
-}
-
-/***************************************
- *
- *  memory-mapped I/O (bitblt)
- *
- ***************************************/
-
-static uint8_t cirrus_mmio_blt_read(CirrusVGAState * s, unsigned address)
-{
-    int value = 0xff;
-
-    switch (address) {
-    case (CIRRUS_MMIO_BLTBGCOLOR + 0):
-       value = cirrus_vga_read_gr(s, 0x00);
-       break;
-    case (CIRRUS_MMIO_BLTBGCOLOR + 1):
-       value = cirrus_vga_read_gr(s, 0x10);
-       break;
-    case (CIRRUS_MMIO_BLTBGCOLOR + 2):
-       value = cirrus_vga_read_gr(s, 0x12);
-       break;
-    case (CIRRUS_MMIO_BLTBGCOLOR + 3):
-       value = cirrus_vga_read_gr(s, 0x14);
-       break;
-    case (CIRRUS_MMIO_BLTFGCOLOR + 0):
-       value = cirrus_vga_read_gr(s, 0x01);
-       break;
-    case (CIRRUS_MMIO_BLTFGCOLOR + 1):
-       value = cirrus_vga_read_gr(s, 0x11);
-       break;
-    case (CIRRUS_MMIO_BLTFGCOLOR + 2):
-       value = cirrus_vga_read_gr(s, 0x13);
-       break;
-    case (CIRRUS_MMIO_BLTFGCOLOR + 3):
-       value = cirrus_vga_read_gr(s, 0x15);
-       break;
-    case (CIRRUS_MMIO_BLTWIDTH + 0):
-       value = cirrus_vga_read_gr(s, 0x20);
-       break;
-    case (CIRRUS_MMIO_BLTWIDTH + 1):
-       value = cirrus_vga_read_gr(s, 0x21);
-       break;
-    case (CIRRUS_MMIO_BLTHEIGHT + 0):
-       value = cirrus_vga_read_gr(s, 0x22);
-       break;
-    case (CIRRUS_MMIO_BLTHEIGHT + 1):
-       value = cirrus_vga_read_gr(s, 0x23);
-       break;
-    case (CIRRUS_MMIO_BLTDESTPITCH + 0):
-       value = cirrus_vga_read_gr(s, 0x24);
-       break;
-    case (CIRRUS_MMIO_BLTDESTPITCH + 1):
-       value = cirrus_vga_read_gr(s, 0x25);
-       break;
-    case (CIRRUS_MMIO_BLTSRCPITCH + 0):
-       value = cirrus_vga_read_gr(s, 0x26);
-       break;
-    case (CIRRUS_MMIO_BLTSRCPITCH + 1):
-       value = cirrus_vga_read_gr(s, 0x27);
-       break;
-    case (CIRRUS_MMIO_BLTDESTADDR + 0):
-       value = cirrus_vga_read_gr(s, 0x28);
-       break;
-    case (CIRRUS_MMIO_BLTDESTADDR + 1):
-       value = cirrus_vga_read_gr(s, 0x29);
-       break;
-    case (CIRRUS_MMIO_BLTDESTADDR + 2):
-       value = cirrus_vga_read_gr(s, 0x2a);
-       break;
-    case (CIRRUS_MMIO_BLTSRCADDR + 0):
-       value = cirrus_vga_read_gr(s, 0x2c);
-       break;
-    case (CIRRUS_MMIO_BLTSRCADDR + 1):
-       value = cirrus_vga_read_gr(s, 0x2d);
-       break;
-    case (CIRRUS_MMIO_BLTSRCADDR + 2):
-       value = cirrus_vga_read_gr(s, 0x2e);
-       break;
-    case CIRRUS_MMIO_BLTWRITEMASK:
-       value = cirrus_vga_read_gr(s, 0x2f);
-       break;
-    case CIRRUS_MMIO_BLTMODE:
-       value = cirrus_vga_read_gr(s, 0x30);
-       break;
-    case CIRRUS_MMIO_BLTROP:
-       value = cirrus_vga_read_gr(s, 0x32);
-       break;
-    case CIRRUS_MMIO_BLTMODEEXT:
-       value = cirrus_vga_read_gr(s, 0x33);
-       break;
-    case (CIRRUS_MMIO_BLTTRANSPARENTCOLOR + 0):
-       value = cirrus_vga_read_gr(s, 0x34);
-       break;
-    case (CIRRUS_MMIO_BLTTRANSPARENTCOLOR + 1):
-       value = cirrus_vga_read_gr(s, 0x35);
-       break;
-    case (CIRRUS_MMIO_BLTTRANSPARENTCOLORMASK + 0):
-       value = cirrus_vga_read_gr(s, 0x38);
-       break;
-    case (CIRRUS_MMIO_BLTTRANSPARENTCOLORMASK + 1):
-       value = cirrus_vga_read_gr(s, 0x39);
-       break;
-    case CIRRUS_MMIO_BLTSTATUS:
-       value = cirrus_vga_read_gr(s, 0x31);
-       break;
-    default:
-#ifdef DEBUG_CIRRUS
-       printf("cirrus: mmio read - address 0x%04x\n", address);
-#endif
-       break;
-    }
-
-    return (uint8_t) value;
-}
-
-static void cirrus_mmio_blt_write(CirrusVGAState * s, unsigned address,
-                                 uint8_t value)
-{
-    switch (address) {
-    case (CIRRUS_MMIO_BLTBGCOLOR + 0):
-       cirrus_vga_write_gr(s, 0x00, value);
-       break;
-    case (CIRRUS_MMIO_BLTBGCOLOR + 1):
-       cirrus_vga_write_gr(s, 0x10, value);
-       break;
-    case (CIRRUS_MMIO_BLTBGCOLOR + 2):
-       cirrus_vga_write_gr(s, 0x12, value);
-       break;
-    case (CIRRUS_MMIO_BLTBGCOLOR + 3):
-       cirrus_vga_write_gr(s, 0x14, value);
-       break;
-    case (CIRRUS_MMIO_BLTFGCOLOR + 0):
-       cirrus_vga_write_gr(s, 0x01, value);
-       break;
-    case (CIRRUS_MMIO_BLTFGCOLOR + 1):
-       cirrus_vga_write_gr(s, 0x11, value);
-       break;
-    case (CIRRUS_MMIO_BLTFGCOLOR + 2):
-       cirrus_vga_write_gr(s, 0x13, value);
-       break;
-    case (CIRRUS_MMIO_BLTFGCOLOR + 3):
-       cirrus_vga_write_gr(s, 0x15, value);
-       break;
-    case (CIRRUS_MMIO_BLTWIDTH + 0):
-       cirrus_vga_write_gr(s, 0x20, value);
-       break;
-    case (CIRRUS_MMIO_BLTWIDTH + 1):
-       cirrus_vga_write_gr(s, 0x21, value);
-       break;
-    case (CIRRUS_MMIO_BLTHEIGHT + 0):
-       cirrus_vga_write_gr(s, 0x22, value);
-       break;
-    case (CIRRUS_MMIO_BLTHEIGHT + 1):
-       cirrus_vga_write_gr(s, 0x23, value);
-       break;
-    case (CIRRUS_MMIO_BLTDESTPITCH + 0):
-       cirrus_vga_write_gr(s, 0x24, value);
-       break;
-    case (CIRRUS_MMIO_BLTDESTPITCH + 1):
-       cirrus_vga_write_gr(s, 0x25, value);
-       break;
-    case (CIRRUS_MMIO_BLTSRCPITCH + 0):
-       cirrus_vga_write_gr(s, 0x26, value);
-       break;
-    case (CIRRUS_MMIO_BLTSRCPITCH + 1):
-       cirrus_vga_write_gr(s, 0x27, value);
-       break;
-    case (CIRRUS_MMIO_BLTDESTADDR + 0):
-       cirrus_vga_write_gr(s, 0x28, value);
-       break;
-    case (CIRRUS_MMIO_BLTDESTADDR + 1):
-       cirrus_vga_write_gr(s, 0x29, value);
-       break;
-    case (CIRRUS_MMIO_BLTDESTADDR + 2):
-       cirrus_vga_write_gr(s, 0x2a, value);
-       break;
-    case (CIRRUS_MMIO_BLTDESTADDR + 3):
-       /* ignored */
-       break;
-    case (CIRRUS_MMIO_BLTSRCADDR + 0):
-       cirrus_vga_write_gr(s, 0x2c, value);
-       break;
-    case (CIRRUS_MMIO_BLTSRCADDR + 1):
-       cirrus_vga_write_gr(s, 0x2d, value);
-       break;
-    case (CIRRUS_MMIO_BLTSRCADDR + 2):
-       cirrus_vga_write_gr(s, 0x2e, value);
-       break;
-    case CIRRUS_MMIO_BLTWRITEMASK:
-       cirrus_vga_write_gr(s, 0x2f, value);
-       break;
-    case CIRRUS_MMIO_BLTMODE:
-       cirrus_vga_write_gr(s, 0x30, value);
-       break;
-    case CIRRUS_MMIO_BLTROP:
-       cirrus_vga_write_gr(s, 0x32, value);
-       break;
-    case CIRRUS_MMIO_BLTMODEEXT:
-       cirrus_vga_write_gr(s, 0x33, value);
-       break;
-    case (CIRRUS_MMIO_BLTTRANSPARENTCOLOR + 0):
-       cirrus_vga_write_gr(s, 0x34, value);
-       break;
-    case (CIRRUS_MMIO_BLTTRANSPARENTCOLOR + 1):
-       cirrus_vga_write_gr(s, 0x35, value);
-       break;
-    case (CIRRUS_MMIO_BLTTRANSPARENTCOLORMASK + 0):
-       cirrus_vga_write_gr(s, 0x38, value);
-       break;
-    case (CIRRUS_MMIO_BLTTRANSPARENTCOLORMASK + 1):
-       cirrus_vga_write_gr(s, 0x39, value);
-       break;
-    case CIRRUS_MMIO_BLTSTATUS:
-       cirrus_vga_write_gr(s, 0x31, value);
-       break;
-    default:
-#ifdef DEBUG_CIRRUS
-       printf("cirrus: mmio write - addr 0x%04x val 0x%02x (ignored)\n",
-              address, value);
-#endif
-       break;
-    }
-}
-
-/***************************************
- *
- *  write mode 4/5
- *
- ***************************************/
-
-static void cirrus_mem_writeb_mode4and5_8bpp(CirrusVGAState * s,
-                                            unsigned mode,
-                                            unsigned offset,
-                                            uint32_t mem_value)
-{
-    int x;
-    unsigned val = mem_value;
-    uint8_t *dst;
-
-    dst = s->vga.vram_ptr + (offset &= s->cirrus_addr_mask);
-    for (x = 0; x < 8; x++) {
-       if (val & 0x80) {
-           *dst = s->cirrus_shadow_gr1;
-       } else if (mode == 5) {
-           *dst = s->cirrus_shadow_gr0;
-       }
-       val <<= 1;
-       dst++;
-    }
-    memory_region_set_dirty(&s->vga.vram, offset, 8);
-}
-
-static void cirrus_mem_writeb_mode4and5_16bpp(CirrusVGAState * s,
-                                             unsigned mode,
-                                             unsigned offset,
-                                             uint32_t mem_value)
-{
-    int x;
-    unsigned val = mem_value;
-    uint8_t *dst;
-
-    dst = s->vga.vram_ptr + (offset &= s->cirrus_addr_mask);
-    for (x = 0; x < 8; x++) {
-       if (val & 0x80) {
-           *dst = s->cirrus_shadow_gr1;
-           *(dst + 1) = s->vga.gr[0x11];
-       } else if (mode == 5) {
-           *dst = s->cirrus_shadow_gr0;
-           *(dst + 1) = s->vga.gr[0x10];
-       }
-       val <<= 1;
-       dst += 2;
-    }
-    memory_region_set_dirty(&s->vga.vram, offset, 16);
-}
-
-/***************************************
- *
- *  memory access between 0xa0000-0xbffff
- *
- ***************************************/
-
-static uint64_t cirrus_vga_mem_read(void *opaque,
-                                    hwaddr addr,
-                                    uint32_t size)
-{
-    CirrusVGAState *s = opaque;
-    unsigned bank_index;
-    unsigned bank_offset;
-    uint32_t val;
-
-    if ((s->vga.sr[0x07] & 0x01) == 0) {
-        return vga_mem_readb(&s->vga, addr);
-    }
-
-    if (addr < 0x10000) {
-       /* XXX handle bitblt */
-       /* video memory */
-       bank_index = addr >> 15;
-       bank_offset = addr & 0x7fff;
-       if (bank_offset < s->cirrus_bank_limit[bank_index]) {
-           bank_offset += s->cirrus_bank_base[bank_index];
-           if ((s->vga.gr[0x0B] & 0x14) == 0x14) {
-               bank_offset <<= 4;
-           } else if (s->vga.gr[0x0B] & 0x02) {
-               bank_offset <<= 3;
-           }
-           bank_offset &= s->cirrus_addr_mask;
-           val = *(s->vga.vram_ptr + bank_offset);
-       } else
-           val = 0xff;
-    } else if (addr >= 0x18000 && addr < 0x18100) {
-       /* memory-mapped I/O */
-       val = 0xff;
-       if ((s->vga.sr[0x17] & 0x44) == 0x04) {
-           val = cirrus_mmio_blt_read(s, addr & 0xff);
-       }
-    } else {
-       val = 0xff;
-#ifdef DEBUG_CIRRUS
-       printf("cirrus: mem_readb " TARGET_FMT_plx "\n", addr);
-#endif
-    }
-    return val;
-}
-
-static void cirrus_vga_mem_write(void *opaque,
-                                 hwaddr addr,
-                                 uint64_t mem_value,
-                                 uint32_t size)
-{
-    CirrusVGAState *s = opaque;
-    unsigned bank_index;
-    unsigned bank_offset;
-    unsigned mode;
-
-    if ((s->vga.sr[0x07] & 0x01) == 0) {
-        vga_mem_writeb(&s->vga, addr, mem_value);
-        return;
-    }
-
-    if (addr < 0x10000) {
-       if (s->cirrus_srcptr != s->cirrus_srcptr_end) {
-           /* bitblt */
-           *s->cirrus_srcptr++ = (uint8_t) mem_value;
-           if (s->cirrus_srcptr >= s->cirrus_srcptr_end) {
-               cirrus_bitblt_cputovideo_next(s);
-           }
-       } else {
-           /* video memory */
-           bank_index = addr >> 15;
-           bank_offset = addr & 0x7fff;
-           if (bank_offset < s->cirrus_bank_limit[bank_index]) {
-               bank_offset += s->cirrus_bank_base[bank_index];
-               if ((s->vga.gr[0x0B] & 0x14) == 0x14) {
-                   bank_offset <<= 4;
-               } else if (s->vga.gr[0x0B] & 0x02) {
-                   bank_offset <<= 3;
-               }
-               bank_offset &= s->cirrus_addr_mask;
-               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,
-                                            sizeof(mem_value));
-               } else {
-                   if ((s->vga.gr[0x0B] & 0x14) != 0x14) {
-                       cirrus_mem_writeb_mode4and5_8bpp(s, mode,
-                                                        bank_offset,
-                                                        mem_value);
-                   } else {
-                       cirrus_mem_writeb_mode4and5_16bpp(s, mode,
-                                                         bank_offset,
-                                                         mem_value);
-                   }
-               }
-           }
-       }
-    } else if (addr >= 0x18000 && addr < 0x18100) {
-       /* memory-mapped I/O */
-       if ((s->vga.sr[0x17] & 0x44) == 0x04) {
-           cirrus_mmio_blt_write(s, addr & 0xff, mem_value);
-       }
-    } else {
-#ifdef DEBUG_CIRRUS
-        printf("cirrus: mem_writeb " TARGET_FMT_plx " value %02x\n", addr,
-               mem_value);
-#endif
-    }
-}
-
-static const MemoryRegionOps cirrus_vga_mem_ops = {
-    .read = cirrus_vga_mem_read,
-    .write = cirrus_vga_mem_write,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-    .impl = {
-        .min_access_size = 1,
-        .max_access_size = 1,
-    },
-};
-
-/***************************************
- *
- *  hardware cursor
- *
- ***************************************/
-
-static inline void invalidate_cursor1(CirrusVGAState *s)
-{
-    if (s->last_hw_cursor_size) {
-        vga_invalidate_scanlines(&s->vga,
-                                 s->last_hw_cursor_y + s->last_hw_cursor_y_start,
-                                 s->last_hw_cursor_y + s->last_hw_cursor_y_end);
-    }
-}
-
-static inline void cirrus_cursor_compute_yrange(CirrusVGAState *s)
-{
-    const uint8_t *src;
-    uint32_t content;
-    int y, y_min, y_max;
-
-    src = s->vga.vram_ptr + s->real_vram_size - 16 * 1024;
-    if (s->vga.sr[0x12] & CIRRUS_CURSOR_LARGE) {
-        src += (s->vga.sr[0x13] & 0x3c) * 256;
-        y_min = 64;
-        y_max = -1;
-        for(y = 0; y < 64; y++) {
-            content = ((uint32_t *)src)[0] |
-                ((uint32_t *)src)[1] |
-                ((uint32_t *)src)[2] |
-                ((uint32_t *)src)[3];
-            if (content) {
-                if (y < y_min)
-                    y_min = y;
-                if (y > y_max)
-                    y_max = y;
-            }
-            src += 16;
-        }
-    } else {
-        src += (s->vga.sr[0x13] & 0x3f) * 256;
-        y_min = 32;
-        y_max = -1;
-        for(y = 0; y < 32; y++) {
-            content = ((uint32_t *)src)[0] |
-                ((uint32_t *)(src + 128))[0];
-            if (content) {
-                if (y < y_min)
-                    y_min = y;
-                if (y > y_max)
-                    y_max = y;
-            }
-            src += 4;
-        }
-    }
-    if (y_min > y_max) {
-        s->last_hw_cursor_y_start = 0;
-        s->last_hw_cursor_y_end = 0;
-    } else {
-        s->last_hw_cursor_y_start = y_min;
-        s->last_hw_cursor_y_end = y_max + 1;
-    }
-}
-
-/* NOTE: we do not currently handle the cursor bitmap change, so we
-   update the cursor only if it moves. */
-static void cirrus_cursor_invalidate(VGACommonState *s1)
-{
-    CirrusVGAState *s = container_of(s1, CirrusVGAState, vga);
-    int size;
-
-    if (!(s->vga.sr[0x12] & CIRRUS_CURSOR_SHOW)) {
-        size = 0;
-    } else {
-        if (s->vga.sr[0x12] & CIRRUS_CURSOR_LARGE)
-            size = 64;
-        else
-            size = 32;
-    }
-    /* invalidate last cursor and new cursor if any change */
-    if (s->last_hw_cursor_size != size ||
-        s->last_hw_cursor_x != s->hw_cursor_x ||
-        s->last_hw_cursor_y != s->hw_cursor_y) {
-
-        invalidate_cursor1(s);
-
-        s->last_hw_cursor_size = size;
-        s->last_hw_cursor_x = s->hw_cursor_x;
-        s->last_hw_cursor_y = s->hw_cursor_y;
-        /* compute the real cursor min and max y */
-        cirrus_cursor_compute_yrange(s);
-        invalidate_cursor1(s);
-    }
-}
-
-#define DEPTH 8
-#include "hw/cirrus_vga_template.h"
-
-#define DEPTH 16
-#include "hw/cirrus_vga_template.h"
-
-#define DEPTH 32
-#include "hw/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);
-    DisplaySurface *surface = qemu_console_surface(s->vga.con);
-    int w, h, bpp, x1, x2, poffset;
-    unsigned int color0, color1;
-    const uint8_t *palette, *src;
-    uint32_t content;
-
-    if (!(s->vga.sr[0x12] & CIRRUS_CURSOR_SHOW))
-        return;
-    /* fast test to see if the cursor intersects with the scan line */
-    if (s->vga.sr[0x12] & CIRRUS_CURSOR_LARGE) {
-        h = 64;
-    } else {
-        h = 32;
-    }
-    if (scr_y < s->hw_cursor_y ||
-        scr_y >= (s->hw_cursor_y + h))
-        return;
-
-    src = s->vga.vram_ptr + s->real_vram_size - 16 * 1024;
-    if (s->vga.sr[0x12] & CIRRUS_CURSOR_LARGE) {
-        src += (s->vga.sr[0x13] & 0x3c) * 256;
-        src += (scr_y - s->hw_cursor_y) * 16;
-        poffset = 8;
-        content = ((uint32_t *)src)[0] |
-            ((uint32_t *)src)[1] |
-            ((uint32_t *)src)[2] |
-            ((uint32_t *)src)[3];
-    } else {
-        src += (s->vga.sr[0x13] & 0x3f) * 256;
-        src += (scr_y - s->hw_cursor_y) * 4;
-        poffset = 128;
-        content = ((uint32_t *)src)[0] |
-            ((uint32_t *)(src + 128))[0];
-    }
-    /* if nothing to draw, no need to continue */
-    if (!content)
-        return;
-    w = h;
-
-    x1 = s->hw_cursor_x;
-    if (x1 >= s->vga.last_scr_width)
-        return;
-    x2 = s->hw_cursor_x + w;
-    if (x2 > s->vga.last_scr_width)
-        x2 = s->vga.last_scr_width;
-    w = x2 - x1;
-    palette = s->cirrus_hidden_palette;
-    color0 = s->vga.rgb_to_pixel(c6_to_8(palette[0x0 * 3]),
-                                 c6_to_8(palette[0x0 * 3 + 1]),
-                                 c6_to_8(palette[0x0 * 3 + 2]));
-    color1 = s->vga.rgb_to_pixel(c6_to_8(palette[0xf * 3]),
-                                 c6_to_8(palette[0xf * 3 + 1]),
-                                 c6_to_8(palette[0xf * 3 + 2]));
-    bpp = surface_bytes_per_pixel(surface);
-    d1 += x1 * bpp;
-    switch (surface_bits_per_pixel(surface)) {
-    default:
-        break;
-    case 8:
-        vga_draw_cursor_line_8(d1, src, poffset, w, color0, color1, 0xff);
-        break;
-    case 15:
-        vga_draw_cursor_line_16(d1, src, poffset, w, color0, color1, 0x7fff);
-        break;
-    case 16:
-        vga_draw_cursor_line_16(d1, src, poffset, w, color0, color1, 0xffff);
-        break;
-    case 32:
-        vga_draw_cursor_line_32(d1, src, poffset, w, color0, color1, 0xffffff);
-        break;
-    }
-}
-
-/***************************************
- *
- *  LFB memory access
- *
- ***************************************/
-
-static uint64_t cirrus_linear_read(void *opaque, hwaddr addr,
-                                   unsigned size)
-{
-    CirrusVGAState *s = opaque;
-    uint32_t ret;
-
-    addr &= s->cirrus_addr_mask;
-
-    if (((s->vga.sr[0x17] & 0x44) == 0x44) &&
-        ((addr & s->linear_mmio_mask) == s->linear_mmio_mask)) {
-       /* memory-mapped I/O */
-       ret = cirrus_mmio_blt_read(s, addr & 0xff);
-    } else if (0) {
-       /* XXX handle bitblt */
-       ret = 0xff;
-    } else {
-       /* video memory */
-       if ((s->vga.gr[0x0B] & 0x14) == 0x14) {
-           addr <<= 4;
-       } else if (s->vga.gr[0x0B] & 0x02) {
-           addr <<= 3;
-       }
-       addr &= s->cirrus_addr_mask;
-       ret = *(s->vga.vram_ptr + addr);
-    }
-
-    return ret;
-}
-
-static void cirrus_linear_write(void *opaque, hwaddr addr,
-                                uint64_t val, unsigned size)
-{
-    CirrusVGAState *s = opaque;
-    unsigned mode;
-
-    addr &= s->cirrus_addr_mask;
-
-    if (((s->vga.sr[0x17] & 0x44) == 0x44) &&
-        ((addr & s->linear_mmio_mask) ==  s->linear_mmio_mask)) {
-       /* memory-mapped I/O */
-       cirrus_mmio_blt_write(s, addr & 0xff, val);
-    } else if (s->cirrus_srcptr != s->cirrus_srcptr_end) {
-       /* bitblt */
-       *s->cirrus_srcptr++ = (uint8_t) val;
-       if (s->cirrus_srcptr >= s->cirrus_srcptr_end) {
-           cirrus_bitblt_cputovideo_next(s);
-       }
-    } else {
-       /* video memory */
-       if ((s->vga.gr[0x0B] & 0x14) == 0x14) {
-           addr <<= 4;
-       } else if (s->vga.gr[0x0B] & 0x02) {
-           addr <<= 3;
-       }
-       addr &= s->cirrus_addr_mask;
-
-       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, 1);
-       } else {
-           if ((s->vga.gr[0x0B] & 0x14) != 0x14) {
-               cirrus_mem_writeb_mode4and5_8bpp(s, mode, addr, val);
-           } else {
-               cirrus_mem_writeb_mode4and5_16bpp(s, mode, addr, val);
-           }
-       }
-    }
-}
-
-/***************************************
- *
- *  system to screen memory access
- *
- ***************************************/
-
-
-static uint64_t cirrus_linear_bitblt_read(void *opaque,
-                                          hwaddr addr,
-                                          unsigned size)
-{
-    CirrusVGAState *s = opaque;
-    uint32_t ret;
-
-    /* XXX handle bitblt */
-    (void)s;
-    ret = 0xff;
-    return ret;
-}
-
-static void cirrus_linear_bitblt_write(void *opaque,
-                                       hwaddr addr,
-                                       uint64_t val,
-                                       unsigned size)
-{
-    CirrusVGAState *s = opaque;
-
-    if (s->cirrus_srcptr != s->cirrus_srcptr_end) {
-       /* bitblt */
-       *s->cirrus_srcptr++ = (uint8_t) val;
-       if (s->cirrus_srcptr >= s->cirrus_srcptr_end) {
-           cirrus_bitblt_cputovideo_next(s);
-       }
-    }
-}
-
-static const MemoryRegionOps cirrus_linear_bitblt_io_ops = {
-    .read = cirrus_linear_bitblt_read,
-    .write = cirrus_linear_bitblt_write,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-    .impl = {
-        .min_access_size = 1,
-        .max_access_size = 1,
-    },
-};
-
-static void map_linear_vram_bank(CirrusVGAState *s, unsigned bank)
-{
-    MemoryRegion *mr = &s->cirrus_bank[bank];
-    bool enabled = !(s->cirrus_srcptr != s->cirrus_srcptr_end)
-        && !((s->vga.sr[0x07] & 0x01) == 0)
-        && !((s->vga.gr[0x0B] & 0x14) == 0x14)
-        && !(s->vga.gr[0x0B] & 0x02);
-
-    memory_region_set_enabled(mr, enabled);
-    memory_region_set_alias_offset(mr, s->cirrus_bank_base[bank]);
-}
-
-static void map_linear_vram(CirrusVGAState *s)
-{
-    if (s->bustype == CIRRUS_BUSTYPE_PCI && !s->linear_vram) {
-        s->linear_vram = true;
-        memory_region_add_subregion_overlap(&s->pci_bar, 0, &s->vga.vram, 1);
-    }
-    map_linear_vram_bank(s, 0);
-    map_linear_vram_bank(s, 1);
-}
-
-static void unmap_linear_vram(CirrusVGAState *s)
-{
-    if (s->bustype == CIRRUS_BUSTYPE_PCI && s->linear_vram) {
-        s->linear_vram = false;
-        memory_region_del_subregion(&s->pci_bar, &s->vga.vram);
-    }
-    memory_region_set_enabled(&s->cirrus_bank[0], false);
-    memory_region_set_enabled(&s->cirrus_bank[1], false);
-}
-
-/* Compute the memory access functions */
-static void cirrus_update_memory_access(CirrusVGAState *s)
-{
-    unsigned mode;
-
-    memory_region_transaction_begin();
-    if ((s->vga.sr[0x17] & 0x44) == 0x44) {
-        goto generic_io;
-    } else if (s->cirrus_srcptr != s->cirrus_srcptr_end) {
-        goto generic_io;
-    } else {
-       if ((s->vga.gr[0x0B] & 0x14) == 0x14) {
-            goto generic_io;
-       } else if (s->vga.gr[0x0B] & 0x02) {
-            goto generic_io;
-        }
-
-       mode = s->vga.gr[0x05] & 0x7;
-       if (mode < 4 || mode > 5 || ((s->vga.gr[0x0B] & 0x4) == 0)) {
-            map_linear_vram(s);
-        } else {
-        generic_io:
-            unmap_linear_vram(s);
-        }
-    }
-    memory_region_transaction_commit();
-}
-
-
-/* I/O ports */
-
-static uint64_t cirrus_vga_ioport_read(void *opaque, hwaddr addr,
-                                       unsigned size)
-{
-    CirrusVGAState *c = opaque;
-    VGACommonState *s = &c->vga;
-    int val, index;
-
-    qemu_flush_coalesced_mmio_buffer();
-    addr += 0x3b0;
-
-    if (vga_ioport_invalid(s, addr)) {
-       val = 0xff;
-    } else {
-       switch (addr) {
-       case 0x3c0:
-           if (s->ar_flip_flop == 0) {
-               val = s->ar_index;
-           } else {
-               val = 0;
-           }
-           break;
-       case 0x3c1:
-           index = s->ar_index & 0x1f;
-           if (index < 21)
-               val = s->ar[index];
-           else
-               val = 0;
-           break;
-       case 0x3c2:
-           val = s->st00;
-           break;
-       case 0x3c4:
-           val = s->sr_index;
-           break;
-       case 0x3c5:
-           val = cirrus_vga_read_sr(c);
-            break;
-#ifdef DEBUG_VGA_REG
-           printf("vga: read SR%x = 0x%02x\n", s->sr_index, val);
-#endif
-           break;
-       case 0x3c6:
-           val = cirrus_read_hidden_dac(c);
-           break;
-       case 0x3c7:
-           val = s->dac_state;
-           break;
-       case 0x3c8:
-           val = s->dac_write_index;
-           c->cirrus_hidden_dac_lockindex = 0;
-           break;
-        case 0x3c9:
-            val = cirrus_vga_read_palette(c);
-            break;
-       case 0x3ca:
-           val = s->fcr;
-           break;
-       case 0x3cc:
-           val = s->msr;
-           break;
-       case 0x3ce:
-           val = s->gr_index;
-           break;
-       case 0x3cf:
-           val = cirrus_vga_read_gr(c, 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:
-           val = s->cr_index;
-           break;
-       case 0x3b5:
-       case 0x3d5:
-            val = cirrus_vga_read_cr(c, 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:
-           /* just toggle to fool polling */
-           val = s->st01 = s->retrace(s);
-           s->ar_flip_flop = 0;
-           break;
-       default:
-           val = 0x00;
-           break;
-       }
-    }
-#if defined(DEBUG_VGA)
-    printf("VGA: read addr=0x%04x data=0x%02x\n", addr, val);
-#endif
-    return val;
-}
-
-static void cirrus_vga_ioport_write(void *opaque, hwaddr addr, uint64_t val,
-                                    unsigned size)
-{
-    CirrusVGAState *c = opaque;
-    VGACommonState *s = &c->vga;
-    int index;
-
-    qemu_flush_coalesced_mmio_buffer();
-    addr += 0x3b0;
-
-    /* check port range access depending on color/monochrome mode */
-    if (vga_ioport_invalid(s, addr)) {
-       return;
-    }
-#ifdef DEBUG_VGA
-    printf("VGA: write addr=0x%04x data=0x%02x\n", addr, val);
-#endif
-
-    switch (addr) {
-    case 0x3c0:
-       if (s->ar_flip_flop == 0) {
-           val &= 0x3f;
-           s->ar_index = val;
-       } else {
-           index = s->ar_index & 0x1f;
-           switch (index) {
-           case 0x00 ... 0x0f:
-               s->ar[index] = val & 0x3f;
-               break;
-           case 0x10:
-               s->ar[index] = val & ~0x10;
-               break;
-           case 0x11:
-               s->ar[index] = val;
-               break;
-           case 0x12:
-               s->ar[index] = val & ~0xc0;
-               break;
-           case 0x13:
-               s->ar[index] = val & ~0xf0;
-               break;
-           case 0x14:
-               s->ar[index] = val & ~0xf0;
-               break;
-           default:
-               break;
-           }
-       }
-       s->ar_flip_flop ^= 1;
-       break;
-    case 0x3c2:
-       s->msr = val & ~0x10;
-       s->update_retrace_info(s);
-       break;
-    case 0x3c4:
-       s->sr_index = val;
-       break;
-    case 0x3c5:
-#ifdef DEBUG_VGA_REG
-       printf("vga: write SR%x = 0x%02x\n", s->sr_index, val);
-#endif
-       cirrus_vga_write_sr(c, val);
-        break;
-       break;
-    case 0x3c6:
-       cirrus_write_hidden_dac(c, val);
-       break;
-    case 0x3c7:
-       s->dac_read_index = val;
-       s->dac_sub_index = 0;
-       s->dac_state = 3;
-       break;
-    case 0x3c8:
-       s->dac_write_index = val;
-       s->dac_sub_index = 0;
-       s->dac_state = 0;
-       break;
-    case 0x3c9:
-        cirrus_vga_write_palette(c, val);
-        break;
-    case 0x3ce:
-       s->gr_index = val;
-       break;
-    case 0x3cf:
-#ifdef DEBUG_VGA_REG
-       printf("vga: write GR%x = 0x%02x\n", s->gr_index, val);
-#endif
-       cirrus_vga_write_gr(c, s->gr_index, val);
-       break;
-    case 0x3b4:
-    case 0x3d4:
-       s->cr_index = val;
-       break;
-    case 0x3b5:
-    case 0x3d5:
-#ifdef DEBUG_VGA_REG
-       printf("vga: write CR%x = 0x%02x\n", s->cr_index, val);
-#endif
-       cirrus_vga_write_cr(c, val);
-       break;
-    case 0x3ba:
-    case 0x3da:
-       s->fcr = val & 0x10;
-       break;
-    }
-}
-
-/***************************************
- *
- *  memory-mapped I/O access
- *
- ***************************************/
-
-static uint64_t cirrus_mmio_read(void *opaque, hwaddr addr,
-                                 unsigned size)
-{
-    CirrusVGAState *s = opaque;
-
-    if (addr >= 0x100) {
-        return cirrus_mmio_blt_read(s, addr - 0x100);
-    } else {
-        return cirrus_vga_ioport_read(s, addr + 0x10, size);
-    }
-}
-
-static void cirrus_mmio_write(void *opaque, hwaddr addr,
-                              uint64_t val, unsigned size)
-{
-    CirrusVGAState *s = opaque;
-
-    if (addr >= 0x100) {
-       cirrus_mmio_blt_write(s, addr - 0x100, val);
-    } else {
-        cirrus_vga_ioport_write(s, addr + 0x10, val, size);
-    }
-}
-
-static const MemoryRegionOps cirrus_mmio_io_ops = {
-    .read = cirrus_mmio_read,
-    .write = cirrus_mmio_write,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-    .impl = {
-        .min_access_size = 1,
-        .max_access_size = 1,
-    },
-};
-
-/* load/save state */
-
-static int cirrus_post_load(void *opaque, int version_id)
-{
-    CirrusVGAState *s = opaque;
-
-    s->vga.gr[0x00] = s->cirrus_shadow_gr0 & 0x0f;
-    s->vga.gr[0x01] = s->cirrus_shadow_gr1 & 0x0f;
-
-    cirrus_update_memory_access(s);
-    /* force refresh */
-    s->vga.graphic_mode = -1;
-    cirrus_update_bank_ptr(s, 0);
-    cirrus_update_bank_ptr(s, 1);
-    return 0;
-}
-
-static const VMStateDescription vmstate_cirrus_vga = {
-    .name = "cirrus_vga",
-    .version_id = 2,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .post_load = cirrus_post_load,
-    .fields      = (VMStateField []) {
-        VMSTATE_UINT32(vga.latch, CirrusVGAState),
-        VMSTATE_UINT8(vga.sr_index, CirrusVGAState),
-        VMSTATE_BUFFER(vga.sr, CirrusVGAState),
-        VMSTATE_UINT8(vga.gr_index, CirrusVGAState),
-        VMSTATE_UINT8(cirrus_shadow_gr0, CirrusVGAState),
-        VMSTATE_UINT8(cirrus_shadow_gr1, CirrusVGAState),
-        VMSTATE_BUFFER_START_MIDDLE(vga.gr, CirrusVGAState, 2),
-        VMSTATE_UINT8(vga.ar_index, CirrusVGAState),
-        VMSTATE_BUFFER(vga.ar, CirrusVGAState),
-        VMSTATE_INT32(vga.ar_flip_flop, CirrusVGAState),
-        VMSTATE_UINT8(vga.cr_index, CirrusVGAState),
-        VMSTATE_BUFFER(vga.cr, CirrusVGAState),
-        VMSTATE_UINT8(vga.msr, CirrusVGAState),
-        VMSTATE_UINT8(vga.fcr, CirrusVGAState),
-        VMSTATE_UINT8(vga.st00, CirrusVGAState),
-        VMSTATE_UINT8(vga.st01, CirrusVGAState),
-        VMSTATE_UINT8(vga.dac_state, CirrusVGAState),
-        VMSTATE_UINT8(vga.dac_sub_index, CirrusVGAState),
-        VMSTATE_UINT8(vga.dac_read_index, CirrusVGAState),
-        VMSTATE_UINT8(vga.dac_write_index, CirrusVGAState),
-        VMSTATE_BUFFER(vga.dac_cache, CirrusVGAState),
-        VMSTATE_BUFFER(vga.palette, CirrusVGAState),
-        VMSTATE_INT32(vga.bank_offset, CirrusVGAState),
-        VMSTATE_UINT8(cirrus_hidden_dac_lockindex, CirrusVGAState),
-        VMSTATE_UINT8(cirrus_hidden_dac_data, CirrusVGAState),
-        VMSTATE_UINT32(hw_cursor_x, CirrusVGAState),
-        VMSTATE_UINT32(hw_cursor_y, CirrusVGAState),
-        /* XXX: we do not save the bitblt state - we assume we do not save
-           the state when the blitter is active */
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static const VMStateDescription vmstate_pci_cirrus_vga = {
-    .name = "cirrus_vga",
-    .version_id = 2,
-    .minimum_version_id = 2,
-    .minimum_version_id_old = 2,
-    .fields      = (VMStateField []) {
-        VMSTATE_PCI_DEVICE(dev, PCICirrusVGAState),
-        VMSTATE_STRUCT(cirrus_vga, PCICirrusVGAState, 0,
-                       vmstate_cirrus_vga, CirrusVGAState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-/***************************************
- *
- *  initialize
- *
- ***************************************/
-
-static void cirrus_reset(void *opaque)
-{
-    CirrusVGAState *s = opaque;
-
-    vga_common_reset(&s->vga);
-    unmap_linear_vram(s);
-    s->vga.sr[0x06] = 0x0f;
-    if (s->device_id == CIRRUS_ID_CLGD5446) {
-        /* 4MB 64 bit memory config, always PCI */
-        s->vga.sr[0x1F] = 0x2d;                // MemClock
-        s->vga.gr[0x18] = 0x0f;             // fastest memory configuration
-        s->vga.sr[0x0f] = 0x98;
-        s->vga.sr[0x17] = 0x20;
-        s->vga.sr[0x15] = 0x04; /* memory size, 3=2MB, 4=4MB */
-    } else {
-        s->vga.sr[0x1F] = 0x22;                // MemClock
-        s->vga.sr[0x0F] = CIRRUS_MEMSIZE_2M;
-        s->vga.sr[0x17] = s->bustype;
-        s->vga.sr[0x15] = 0x03; /* memory size, 3=2MB, 4=4MB */
-    }
-    s->vga.cr[0x27] = s->device_id;
-
-    s->cirrus_hidden_dac_lockindex = 5;
-    s->cirrus_hidden_dac_data = 0;
-}
-
-static const MemoryRegionOps cirrus_linear_io_ops = {
-    .read = cirrus_linear_read,
-    .write = cirrus_linear_write,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-    .impl = {
-        .min_access_size = 1,
-        .max_access_size = 1,
-    },
-};
-
-static const MemoryRegionOps cirrus_vga_io_ops = {
-    .read = cirrus_vga_ioport_read,
-    .write = cirrus_vga_ioport_write,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-    .impl = {
-        .min_access_size = 1,
-        .max_access_size = 1,
-    },
-};
-
-static void cirrus_init_common(CirrusVGAState * s, int device_id, int is_pci,
-                               MemoryRegion *system_memory,
-                               MemoryRegion *system_io)
-{
-    int i;
-    static int inited;
-
-    if (!inited) {
-        inited = 1;
-        for(i = 0;i < 256; i++)
-            rop_to_index[i] = CIRRUS_ROP_NOP_INDEX; /* nop rop */
-        rop_to_index[CIRRUS_ROP_0] = 0;
-        rop_to_index[CIRRUS_ROP_SRC_AND_DST] = 1;
-        rop_to_index[CIRRUS_ROP_NOP] = 2;
-        rop_to_index[CIRRUS_ROP_SRC_AND_NOTDST] = 3;
-        rop_to_index[CIRRUS_ROP_NOTDST] = 4;
-        rop_to_index[CIRRUS_ROP_SRC] = 5;
-        rop_to_index[CIRRUS_ROP_1] = 6;
-        rop_to_index[CIRRUS_ROP_NOTSRC_AND_DST] = 7;
-        rop_to_index[CIRRUS_ROP_SRC_XOR_DST] = 8;
-        rop_to_index[CIRRUS_ROP_SRC_OR_DST] = 9;
-        rop_to_index[CIRRUS_ROP_NOTSRC_OR_NOTDST] = 10;
-        rop_to_index[CIRRUS_ROP_SRC_NOTXOR_DST] = 11;
-        rop_to_index[CIRRUS_ROP_SRC_OR_NOTDST] = 12;
-        rop_to_index[CIRRUS_ROP_NOTSRC] = 13;
-        rop_to_index[CIRRUS_ROP_NOTSRC_OR_DST] = 14;
-        rop_to_index[CIRRUS_ROP_NOTSRC_AND_NOTDST] = 15;
-        s->device_id = device_id;
-        if (is_pci)
-            s->bustype = CIRRUS_BUSTYPE_PCI;
-        else
-            s->bustype = CIRRUS_BUSTYPE_ISA;
-    }
-
-    /* Register ioport 0x3b0 - 0x3df */
-    memory_region_init_io(&s->cirrus_vga_io, &cirrus_vga_io_ops, s,
-                          "cirrus-io", 0x30);
-    memory_region_add_subregion(system_io, 0x3b0, &s->cirrus_vga_io);
-
-    memory_region_init(&s->low_mem_container,
-                       "cirrus-lowmem-container",
-                       0x20000);
-
-    memory_region_init_io(&s->low_mem, &cirrus_vga_mem_ops, s,
-                          "cirrus-low-memory", 0x20000);
-    memory_region_add_subregion(&s->low_mem_container, 0, &s->low_mem);
-    for (i = 0; i < 2; ++i) {
-        static const char *names[] = { "vga.bank0", "vga.bank1" };
-        MemoryRegion *bank = &s->cirrus_bank[i];
-        memory_region_init_alias(bank, names[i], &s->vga.vram, 0, 0x8000);
-        memory_region_set_enabled(bank, false);
-        memory_region_add_subregion_overlap(&s->low_mem_container, i * 0x8000,
-                                            bank, 1);
-    }
-    memory_region_add_subregion_overlap(system_memory,
-                                        isa_mem_base + 0x000a0000,
-                                        &s->low_mem_container,
-                                        1);
-    memory_region_set_coalescing(&s->low_mem);
-
-    /* I/O handler for LFB */
-    memory_region_init_io(&s->cirrus_linear_io, &cirrus_linear_io_ops, s,
-                          "cirrus-linear-io", s->vga.vram_size_mb
-                                              * 1024 * 1024);
-    memory_region_set_flush_coalesced(&s->cirrus_linear_io);
-
-    /* I/O handler for LFB */
-    memory_region_init_io(&s->cirrus_linear_bitblt_io,
-                          &cirrus_linear_bitblt_io_ops,
-                          s,
-                          "cirrus-bitblt-mmio",
-                          0x400000);
-    memory_region_set_flush_coalesced(&s->cirrus_linear_bitblt_io);
-
-    /* I/O handler for memory-mapped I/O */
-    memory_region_init_io(&s->cirrus_mmio_io, &cirrus_mmio_io_ops, s,
-                          "cirrus-mmio", CIRRUS_PNPMMIO_SIZE);
-    memory_region_set_flush_coalesced(&s->cirrus_mmio_io);
-
-    s->real_vram_size =
-        (s->device_id == CIRRUS_ID_CLGD5446) ? 4096 * 1024 : 2048 * 1024;
-
-    /* XXX: s->vga.vram_size must be a power of two */
-    s->cirrus_addr_mask = s->real_vram_size - 1;
-    s->linear_mmio_mask = s->real_vram_size - 256;
-
-    s->vga.get_bpp = cirrus_get_bpp;
-    s->vga.get_offsets = cirrus_get_offsets;
-    s->vga.get_resolution = cirrus_get_resolution;
-    s->vga.cursor_invalidate = cirrus_cursor_invalidate;
-    s->vga.cursor_draw_line = cirrus_cursor_draw_line;
-
-    qemu_register_reset(cirrus_reset, s);
-}
-
-/***************************************
- *
- *  ISA bus support
- *
- ***************************************/
-
-static int vga_initfn(ISADevice *dev)
-{
-    ISACirrusVGAState *d = DO_UPCAST(ISACirrusVGAState, dev, dev);
-    VGACommonState *s = &d->cirrus_vga.vga;
-
-    vga_common_init(s);
-    cirrus_init_common(&d->cirrus_vga, CIRRUS_ID_CLGD5430, 0,
-                       isa_address_space(dev), isa_address_space_io(dev));
-    s->con = 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 0;
-}
-
-static Property isa_vga_cirrus_properties[] = {
-    DEFINE_PROP_UINT32("vgamem_mb", struct ISACirrusVGAState,
-                       cirrus_vga.vga.vram_size_mb, 8),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void isa_cirrus_vga_class_init(ObjectClass *klass, void *data)
-{
-    ISADeviceClass *k = ISA_DEVICE_CLASS(klass);
-    DeviceClass *dc = DEVICE_CLASS(klass);
-
-    dc->vmsd  = &vmstate_cirrus_vga;
-    k->init   = vga_initfn;
-    dc->props = isa_vga_cirrus_properties;
-}
-
-static const TypeInfo isa_cirrus_vga_info = {
-    .name          = "isa-cirrus-vga",
-    .parent        = TYPE_ISA_DEVICE,
-    .instance_size = sizeof(ISACirrusVGAState),
-    .class_init = isa_cirrus_vga_class_init,
-};
-
-/***************************************
- *
- *  PCI bus support
- *
- ***************************************/
-
-static int pci_cirrus_vga_initfn(PCIDevice *dev)
-{
-     PCICirrusVGAState *d = DO_UPCAST(PCICirrusVGAState, dev, dev);
-     CirrusVGAState *s = &d->cirrus_vga;
-     PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev);
-     int16_t device_id = pc->device_id;
-
-     /* setup VGA */
-     vga_common_init(&s->vga);
-     cirrus_init_common(s, device_id, 1, pci_address_space(dev),
-                        pci_address_space_io(dev));
-     s->vga.con = graphic_console_init(s->vga.update, s->vga.invalidate,
-                                       s->vga.screen_dump, s->vga.text_update,
-                                       &s->vga);
-
-     /* setup PCI */
-
-    memory_region_init(&s->pci_bar, "cirrus-pci-bar0", 0x2000000);
-
-    /* XXX: add byte swapping apertures */
-    memory_region_add_subregion(&s->pci_bar, 0, &s->cirrus_linear_io);
-    memory_region_add_subregion(&s->pci_bar, 0x1000000,
-                                &s->cirrus_linear_bitblt_io);
-
-     /* setup memory space */
-     /* memory #0 LFB */
-     /* memory #1 memory-mapped I/O */
-     /* XXX: s->vga.vram_size must be a power of two */
-     pci_register_bar(&d->dev, 0, PCI_BASE_ADDRESS_MEM_PREFETCH, &s->pci_bar);
-     if (device_id == CIRRUS_ID_CLGD5446) {
-         pci_register_bar(&d->dev, 1, 0, &s->cirrus_mmio_io);
-     }
-     return 0;
-}
-
-static Property pci_vga_cirrus_properties[] = {
-    DEFINE_PROP_UINT32("vgamem_mb", struct PCICirrusVGAState,
-                       cirrus_vga.vga.vram_size_mb, 8),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void cirrus_vga_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
-    k->no_hotplug = 1;
-    k->init = pci_cirrus_vga_initfn;
-    k->romfile = VGABIOS_CIRRUS_FILENAME;
-    k->vendor_id = PCI_VENDOR_ID_CIRRUS;
-    k->device_id = CIRRUS_ID_CLGD5446;
-    k->class_id = PCI_CLASS_DISPLAY_VGA;
-    dc->desc = "Cirrus CLGD 54xx VGA";
-    dc->vmsd = &vmstate_pci_cirrus_vga;
-    dc->props = pci_vga_cirrus_properties;
-}
-
-static const 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_types(void)
-{
-    type_register_static(&isa_cirrus_vga_info);
-    type_register_static(&cirrus_vga_info);
-}
-
-type_init(cirrus_vga_register_types)
diff --git a/hw/cirrus_vga_rop.h b/hw/cirrus_vga_rop.h
deleted file mode 100644 (file)
index 894610c..0000000
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
- * QEMU Cirrus CLGD 54xx VGA Emulator.
- *
- * Copyright (c) 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.
- */
-
-static inline void glue(rop_8_,ROP_NAME)(uint8_t *dst, uint8_t src)
-{
-    *dst = ROP_FN(*dst, src);
-}
-
-static inline void glue(rop_16_,ROP_NAME)(uint16_t *dst, uint16_t src)
-{
-    *dst = ROP_FN(*dst, src);
-}
-
-static inline void glue(rop_32_,ROP_NAME)(uint32_t *dst, uint32_t src)
-{
-    *dst = ROP_FN(*dst, src);
-}
-
-#define ROP_OP(d, s) glue(rop_8_,ROP_NAME)(d, s)
-#define ROP_OP_16(d, s) glue(rop_16_,ROP_NAME)(d, s)
-#define ROP_OP_32(d, s) glue(rop_32_,ROP_NAME)(d, s)
-#undef ROP_FN
-
-static void
-glue(cirrus_bitblt_rop_fwd_, ROP_NAME)(CirrusVGAState *s,
-                             uint8_t *dst,const uint8_t *src,
-                             int dstpitch,int srcpitch,
-                             int bltwidth,int bltheight)
-{
-    int x,y;
-    dstpitch -= bltwidth;
-    srcpitch -= bltwidth;
-
-    if (dstpitch < 0 || srcpitch < 0) {
-        /* is 0 valid? srcpitch == 0 could be useful */
-        return;
-    }
-
-    for (y = 0; y < bltheight; y++) {
-        for (x = 0; x < bltwidth; x++) {
-            ROP_OP(dst, *src);
-            dst++;
-            src++;
-        }
-        dst += dstpitch;
-        src += srcpitch;
-    }
-}
-
-static void
-glue(cirrus_bitblt_rop_bkwd_, ROP_NAME)(CirrusVGAState *s,
-                                        uint8_t *dst,const uint8_t *src,
-                                        int dstpitch,int srcpitch,
-                                        int bltwidth,int bltheight)
-{
-    int x,y;
-    dstpitch += bltwidth;
-    srcpitch += bltwidth;
-    for (y = 0; y < bltheight; y++) {
-        for (x = 0; x < bltwidth; x++) {
-            ROP_OP(dst, *src);
-            dst--;
-            src--;
-        }
-        dst += dstpitch;
-        src += srcpitch;
-    }
-}
-
-static void
-glue(glue(cirrus_bitblt_rop_fwd_transp_, ROP_NAME),_8)(CirrusVGAState *s,
-                                                      uint8_t *dst,const uint8_t *src,
-                                                      int dstpitch,int srcpitch,
-                                                      int bltwidth,int bltheight)
-{
-    int x,y;
-    uint8_t p;
-    dstpitch -= bltwidth;
-    srcpitch -= bltwidth;
-    for (y = 0; y < bltheight; y++) {
-        for (x = 0; x < bltwidth; x++) {
-           p = *dst;
-            ROP_OP(&p, *src);
-           if (p != s->vga.gr[0x34]) *dst = p;
-            dst++;
-            src++;
-        }
-        dst += dstpitch;
-        src += srcpitch;
-    }
-}
-
-static void
-glue(glue(cirrus_bitblt_rop_bkwd_transp_, ROP_NAME),_8)(CirrusVGAState *s,
-                                                       uint8_t *dst,const uint8_t *src,
-                                                       int dstpitch,int srcpitch,
-                                                       int bltwidth,int bltheight)
-{
-    int x,y;
-    uint8_t p;
-    dstpitch += bltwidth;
-    srcpitch += bltwidth;
-    for (y = 0; y < bltheight; y++) {
-        for (x = 0; x < bltwidth; x++) {
-           p = *dst;
-            ROP_OP(&p, *src);
-           if (p != s->vga.gr[0x34]) *dst = p;
-            dst--;
-            src--;
-        }
-        dst += dstpitch;
-        src += srcpitch;
-    }
-}
-
-static void
-glue(glue(cirrus_bitblt_rop_fwd_transp_, ROP_NAME),_16)(CirrusVGAState *s,
-                                                       uint8_t *dst,const uint8_t *src,
-                                                       int dstpitch,int srcpitch,
-                                                       int bltwidth,int bltheight)
-{
-    int x,y;
-    uint8_t p1, p2;
-    dstpitch -= bltwidth;
-    srcpitch -= bltwidth;
-    for (y = 0; y < bltheight; y++) {
-        for (x = 0; x < bltwidth; x+=2) {
-           p1 = *dst;
-           p2 = *(dst+1);
-            ROP_OP(&p1, *src);
-            ROP_OP(&p2, *(src + 1));
-           if ((p1 != s->vga.gr[0x34]) || (p2 != s->vga.gr[0x35])) {
-               *dst = p1;
-               *(dst+1) = p2;
-           }
-            dst+=2;
-            src+=2;
-        }
-        dst += dstpitch;
-        src += srcpitch;
-    }
-}
-
-static void
-glue(glue(cirrus_bitblt_rop_bkwd_transp_, ROP_NAME),_16)(CirrusVGAState *s,
-                                                        uint8_t *dst,const uint8_t *src,
-                                                        int dstpitch,int srcpitch,
-                                                        int bltwidth,int bltheight)
-{
-    int x,y;
-    uint8_t p1, p2;
-    dstpitch += bltwidth;
-    srcpitch += bltwidth;
-    for (y = 0; y < bltheight; y++) {
-        for (x = 0; x < bltwidth; x+=2) {
-           p1 = *(dst-1);
-           p2 = *dst;
-            ROP_OP(&p1, *(src - 1));
-            ROP_OP(&p2, *src);
-           if ((p1 != s->vga.gr[0x34]) || (p2 != s->vga.gr[0x35])) {
-               *(dst-1) = p1;
-               *dst = p2;
-           }
-            dst-=2;
-            src-=2;
-        }
-        dst += dstpitch;
-        src += srcpitch;
-    }
-}
-
-#define DEPTH 8
-#include "hw/cirrus_vga_rop2.h"
-
-#define DEPTH 16
-#include "hw/cirrus_vga_rop2.h"
-
-#define DEPTH 24
-#include "hw/cirrus_vga_rop2.h"
-
-#define DEPTH 32
-#include "hw/cirrus_vga_rop2.h"
-
-#undef ROP_NAME
-#undef ROP_OP
-#undef ROP_OP_16
-#undef ROP_OP_32
diff --git a/hw/cirrus_vga_rop2.h b/hw/cirrus_vga_rop2.h
deleted file mode 100644 (file)
index d28bcc6..0000000
+++ /dev/null
@@ -1,281 +0,0 @@
-/*
- * QEMU Cirrus CLGD 54xx VGA Emulator.
- *
- * Copyright (c) 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.
- */
-
-#if DEPTH == 8
-#define PUTPIXEL()    ROP_OP(&d[0], col)
-#elif DEPTH == 16
-#define PUTPIXEL()    ROP_OP_16((uint16_t *)&d[0], col)
-#elif DEPTH == 24
-#define PUTPIXEL()    ROP_OP(&d[0], col);        \
-                      ROP_OP(&d[1], (col >> 8)); \
-                      ROP_OP(&d[2], (col >> 16))
-#elif DEPTH == 32
-#define PUTPIXEL()    ROP_OP_32(((uint32_t *)&d[0]), col)
-#else
-#error unsupported DEPTH
-#endif
-
-static void
-glue(glue(glue(cirrus_patternfill_, ROP_NAME), _),DEPTH)
-     (CirrusVGAState * s, uint8_t * dst,
-      const uint8_t * src,
-      int dstpitch, int srcpitch,
-      int bltwidth, int bltheight)
-{
-    uint8_t *d;
-    int x, y, pattern_y, pattern_pitch, pattern_x;
-    unsigned int col;
-    const uint8_t *src1;
-#if DEPTH == 24
-    int skipleft = s->vga.gr[0x2f] & 0x1f;
-#else
-    int skipleft = (s->vga.gr[0x2f] & 0x07) * (DEPTH / 8);
-#endif
-
-#if DEPTH == 8
-    pattern_pitch = 8;
-#elif DEPTH == 16
-    pattern_pitch = 16;
-#else
-    pattern_pitch = 32;
-#endif
-    pattern_y = s->cirrus_blt_srcaddr & 7;
-    for(y = 0; y < bltheight; y++) {
-        pattern_x = skipleft;
-        d = dst + skipleft;
-        src1 = src + pattern_y * pattern_pitch;
-        for (x = skipleft; x < bltwidth; x += (DEPTH / 8)) {
-#if DEPTH == 8
-            col = src1[pattern_x];
-            pattern_x = (pattern_x + 1) & 7;
-#elif DEPTH == 16
-            col = ((uint16_t *)(src1 + pattern_x))[0];
-            pattern_x = (pattern_x + 2) & 15;
-#elif DEPTH == 24
-            {
-                const uint8_t *src2 = src1 + pattern_x * 3;
-                col = src2[0] | (src2[1] << 8) | (src2[2] << 16);
-                pattern_x = (pattern_x + 1) & 7;
-            }
-#else
-            col = ((uint32_t *)(src1 + pattern_x))[0];
-            pattern_x = (pattern_x + 4) & 31;
-#endif
-            PUTPIXEL();
-            d += (DEPTH / 8);
-        }
-        pattern_y = (pattern_y + 1) & 7;
-        dst += dstpitch;
-    }
-}
-
-/* NOTE: srcpitch is ignored */
-static void
-glue(glue(glue(cirrus_colorexpand_transp_, ROP_NAME), _),DEPTH)
-     (CirrusVGAState * s, uint8_t * dst,
-      const uint8_t * src,
-      int dstpitch, int srcpitch,
-      int bltwidth, int bltheight)
-{
-    uint8_t *d;
-    int x, y;
-    unsigned bits, bits_xor;
-    unsigned int col;
-    unsigned bitmask;
-    unsigned index;
-#if DEPTH == 24
-    int dstskipleft = s->vga.gr[0x2f] & 0x1f;
-    int srcskipleft = dstskipleft / 3;
-#else
-    int srcskipleft = s->vga.gr[0x2f] & 0x07;
-    int dstskipleft = srcskipleft * (DEPTH / 8);
-#endif
-
-    if (s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_COLOREXPINV) {
-        bits_xor = 0xff;
-        col = s->cirrus_blt_bgcol;
-    } else {
-        bits_xor = 0x00;
-        col = s->cirrus_blt_fgcol;
-    }
-
-    for(y = 0; y < bltheight; y++) {
-        bitmask = 0x80 >> srcskipleft;
-        bits = *src++ ^ bits_xor;
-        d = dst + dstskipleft;
-        for (x = dstskipleft; x < bltwidth; x += (DEPTH / 8)) {
-            if ((bitmask & 0xff) == 0) {
-                bitmask = 0x80;
-                bits = *src++ ^ bits_xor;
-            }
-            index = (bits & bitmask);
-            if (index) {
-                PUTPIXEL();
-            }
-            d += (DEPTH / 8);
-            bitmask >>= 1;
-        }
-        dst += dstpitch;
-    }
-}
-
-static void
-glue(glue(glue(cirrus_colorexpand_, ROP_NAME), _),DEPTH)
-     (CirrusVGAState * s, uint8_t * dst,
-      const uint8_t * src,
-      int dstpitch, int srcpitch,
-      int bltwidth, int bltheight)
-{
-    uint32_t colors[2];
-    uint8_t *d;
-    int x, y;
-    unsigned bits;
-    unsigned int col;
-    unsigned bitmask;
-    int srcskipleft = s->vga.gr[0x2f] & 0x07;
-    int dstskipleft = srcskipleft * (DEPTH / 8);
-
-    colors[0] = s->cirrus_blt_bgcol;
-    colors[1] = s->cirrus_blt_fgcol;
-    for(y = 0; y < bltheight; y++) {
-        bitmask = 0x80 >> srcskipleft;
-        bits = *src++;
-        d = dst + dstskipleft;
-        for (x = dstskipleft; x < bltwidth; x += (DEPTH / 8)) {
-            if ((bitmask & 0xff) == 0) {
-                bitmask = 0x80;
-                bits = *src++;
-            }
-            col = colors[!!(bits & bitmask)];
-            PUTPIXEL();
-            d += (DEPTH / 8);
-            bitmask >>= 1;
-        }
-        dst += dstpitch;
-    }
-}
-
-static void
-glue(glue(glue(cirrus_colorexpand_pattern_transp_, ROP_NAME), _),DEPTH)
-     (CirrusVGAState * s, uint8_t * dst,
-      const uint8_t * src,
-      int dstpitch, int srcpitch,
-      int bltwidth, int bltheight)
-{
-    uint8_t *d;
-    int x, y, bitpos, pattern_y;
-    unsigned int bits, bits_xor;
-    unsigned int col;
-#if DEPTH == 24
-    int dstskipleft = s->vga.gr[0x2f] & 0x1f;
-    int srcskipleft = dstskipleft / 3;
-#else
-    int srcskipleft = s->vga.gr[0x2f] & 0x07;
-    int dstskipleft = srcskipleft * (DEPTH / 8);
-#endif
-
-    if (s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_COLOREXPINV) {
-        bits_xor = 0xff;
-        col = s->cirrus_blt_bgcol;
-    } else {
-        bits_xor = 0x00;
-        col = s->cirrus_blt_fgcol;
-    }
-    pattern_y = s->cirrus_blt_srcaddr & 7;
-
-    for(y = 0; y < bltheight; y++) {
-        bits = src[pattern_y] ^ bits_xor;
-        bitpos = 7 - srcskipleft;
-        d = dst + dstskipleft;
-        for (x = dstskipleft; x < bltwidth; x += (DEPTH / 8)) {
-            if ((bits >> bitpos) & 1) {
-                PUTPIXEL();
-            }
-            d += (DEPTH / 8);
-            bitpos = (bitpos - 1) & 7;
-        }
-        pattern_y = (pattern_y + 1) & 7;
-        dst += dstpitch;
-    }
-}
-
-static void
-glue(glue(glue(cirrus_colorexpand_pattern_, ROP_NAME), _),DEPTH)
-     (CirrusVGAState * s, uint8_t * dst,
-      const uint8_t * src,
-      int dstpitch, int srcpitch,
-      int bltwidth, int bltheight)
-{
-    uint32_t colors[2];
-    uint8_t *d;
-    int x, y, bitpos, pattern_y;
-    unsigned int bits;
-    unsigned int col;
-    int srcskipleft = s->vga.gr[0x2f] & 0x07;
-    int dstskipleft = srcskipleft * (DEPTH / 8);
-
-    colors[0] = s->cirrus_blt_bgcol;
-    colors[1] = s->cirrus_blt_fgcol;
-    pattern_y = s->cirrus_blt_srcaddr & 7;
-
-    for(y = 0; y < bltheight; y++) {
-        bits = src[pattern_y];
-        bitpos = 7 - srcskipleft;
-        d = dst + dstskipleft;
-        for (x = dstskipleft; x < bltwidth; x += (DEPTH / 8)) {
-            col = colors[(bits >> bitpos) & 1];
-            PUTPIXEL();
-            d += (DEPTH / 8);
-            bitpos = (bitpos - 1) & 7;
-        }
-        pattern_y = (pattern_y + 1) & 7;
-        dst += dstpitch;
-    }
-}
-
-static void
-glue(glue(glue(cirrus_fill_, ROP_NAME), _),DEPTH)
-     (CirrusVGAState *s,
-      uint8_t *dst, int dst_pitch,
-      int width, int height)
-{
-    uint8_t *d, *d1;
-    uint32_t col;
-    int x, y;
-
-    col = s->cirrus_blt_fgcol;
-
-    d1 = dst;
-    for(y = 0; y < height; y++) {
-        d = d1;
-        for(x = 0; x < width; x += (DEPTH / 8)) {
-            PUTPIXEL();
-            d += (DEPTH / 8);
-        }
-        d1 += dst_pitch;
-    }
-}
-
-#undef DEPTH
-#undef PUTPIXEL
diff --git a/hw/cirrus_vga_template.h b/hw/cirrus_vga_template.h
deleted file mode 100644 (file)
index 3b28280..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * 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/core/Makefile.objs b/hw/core/Makefile.objs
new file mode 100644 (file)
index 0000000..94109f3
--- /dev/null
@@ -0,0 +1,14 @@
+# core qdev-related obj files, also used by *-user:
+common-obj-y += qdev.o qdev-properties.o
+# irq.o needed for qdev GPIO handling:
+common-obj-y += irq.o
+
+common-obj-$(CONFIG_EMPTY_SLOT) += empty_slot.o
+common-obj-$(CONFIG_XILINX_AXI) += stream.o
+common-obj-$(CONFIG_PTIMER) += ptimer.o
+common-obj-$(CONFIG_SOFTMMU) += sysbus.o
+common-obj-$(CONFIG_SOFTMMU) += null-machine.o
+common-obj-$(CONFIG_SOFTMMU) += loader.o
+common-obj-$(CONFIG_SOFTMMU) += qdev-addr.o
+common-obj-$(CONFIG_SOFTMMU) += qdev-properties-system.o
+
diff --git a/hw/core/empty_slot.c b/hw/core/empty_slot.c
new file mode 100644 (file)
index 0000000..5234a4d
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * QEMU Empty Slot
+ *
+ * The empty_slot device emulates known to a bus but not connected devices.
+ *
+ * Copyright (c) 2010 Artyom Tarasenko
+ *
+ * This code is licensed under the GNU GPL v2 or (at your option) any later
+ * version.
+ */
+
+#include "hw/hw.h"
+#include "hw/sysbus.h"
+#include "hw/empty_slot.h"
+
+//#define DEBUG_EMPTY_SLOT
+
+#ifdef DEBUG_EMPTY_SLOT
+#define DPRINTF(fmt, ...)                                       \
+    do { printf("empty_slot: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while (0)
+#endif
+
+typedef struct EmptySlot {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    uint64_t size;
+} EmptySlot;
+
+static uint64_t empty_slot_read(void *opaque, hwaddr addr,
+                                unsigned size)
+{
+    DPRINTF("read from " TARGET_FMT_plx "\n", addr);
+    return 0;
+}
+
+static void empty_slot_write(void *opaque, hwaddr addr,
+                             uint64_t val, unsigned size)
+{
+    DPRINTF("write 0x%x to " TARGET_FMT_plx "\n", (unsigned)val, addr);
+}
+
+static const MemoryRegionOps empty_slot_ops = {
+    .read = empty_slot_read,
+    .write = empty_slot_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+void empty_slot_init(hwaddr addr, uint64_t slot_size)
+{
+    if (slot_size > 0) {
+        /* Only empty slots larger than 0 byte need handling. */
+        DeviceState *dev;
+        SysBusDevice *s;
+        EmptySlot *e;
+
+        dev = qdev_create(NULL, "empty_slot");
+        s = SYS_BUS_DEVICE(dev);
+        e = FROM_SYSBUS(EmptySlot, s);
+        e->size = slot_size;
+
+        qdev_init_nofail(dev);
+
+        sysbus_mmio_map(s, 0, addr);
+    }
+}
+
+static int empty_slot_init1(SysBusDevice *dev)
+{
+    EmptySlot *s = FROM_SYSBUS(EmptySlot, dev);
+
+    memory_region_init_io(&s->iomem, &empty_slot_ops, s,
+                          "empty-slot", s->size);
+    sysbus_init_mmio(dev, &s->iomem);
+    return 0;
+}
+
+static void empty_slot_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = empty_slot_init1;
+}
+
+static const 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_types(void)
+{
+    type_register_static(&empty_slot_info);
+}
+
+type_init(empty_slot_register_types)
diff --git a/hw/core/irq.c b/hw/core/irq.c
new file mode 100644 (file)
index 0000000..2078542
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * QEMU IRQ/GPIO common code.
+ *
+ * Copyright (c) 2007 CodeSourcery.
+ *
+ * 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 "hw/irq.h"
+
+struct IRQState {
+    qemu_irq_handler handler;
+    void *opaque;
+    int n;
+};
+
+void qemu_set_irq(qemu_irq irq, int level)
+{
+    if (!irq)
+        return;
+
+    irq->handler(irq->opaque, irq->n, level);
+}
+
+qemu_irq *qemu_extend_irqs(qemu_irq *old, int n_old, qemu_irq_handler handler,
+                           void *opaque, int n)
+{
+    qemu_irq *s;
+    struct IRQState *p;
+    int i;
+
+    if (!old) {
+        n_old = 0;
+    }
+    s = old ? g_renew(qemu_irq, old, n + n_old) : g_new(qemu_irq, n);
+    p = old ? g_renew(struct IRQState, s[0], n + n_old) :
+                g_new(struct IRQState, n);
+    for (i = 0; i < n + n_old; i++) {
+        if (i >= n_old) {
+            p->handler = handler;
+            p->opaque = opaque;
+            p->n = i;
+        }
+        s[i] = p;
+        p++;
+    }
+    return s;
+}
+
+qemu_irq *qemu_allocate_irqs(qemu_irq_handler handler, void *opaque, int n)
+{
+    return qemu_extend_irqs(NULL, 0, handler, opaque, n);
+}
+
+
+void qemu_free_irqs(qemu_irq *s)
+{
+    g_free(s[0]);
+    g_free(s);
+}
+
+static void qemu_notirq(void *opaque, int line, int level)
+{
+    struct IRQState *irq = opaque;
+
+    irq->handler(irq->opaque, irq->n, !level);
+}
+
+qemu_irq qemu_irq_invert(qemu_irq irq)
+{
+    /* The default state for IRQs is low, so raise the output now.  */
+    qemu_irq_raise(irq);
+    return qemu_allocate_irqs(qemu_notirq, irq, 1)[0];
+}
+
+static void qemu_splitirq(void *opaque, int line, int level)
+{
+    struct IRQState **irq = opaque;
+    irq[0]->handler(irq[0]->opaque, irq[0]->n, level);
+    irq[1]->handler(irq[1]->opaque, irq[1]->n, level);
+}
+
+qemu_irq qemu_irq_split(qemu_irq irq1, qemu_irq irq2)
+{
+    qemu_irq *s = g_malloc0(2 * sizeof(qemu_irq));
+    s[0] = irq1;
+    s[1] = irq2;
+    return qemu_allocate_irqs(qemu_splitirq, s, 1)[0];
+}
+
+static void proxy_irq_handler(void *opaque, int n, int level)
+{
+    qemu_irq **target = opaque;
+
+    if (*target) {
+        qemu_set_irq((*target)[n], level);
+    }
+}
+
+qemu_irq *qemu_irq_proxy(qemu_irq **target, int n)
+{
+    return qemu_allocate_irqs(proxy_irq_handler, target, n);
+}
+
+void qemu_irq_intercept_in(qemu_irq *gpio_in, qemu_irq_handler handler, int n)
+{
+    int i;
+    qemu_irq *old_irqs = qemu_allocate_irqs(NULL, NULL, n);
+    for (i = 0; i < n; i++) {
+        *old_irqs[i] = *gpio_in[i];
+        gpio_in[i]->handler = handler;
+        gpio_in[i]->opaque = old_irqs;
+    }
+}
+
+void qemu_irq_intercept_out(qemu_irq **gpio_out, qemu_irq_handler handler, int n)
+{
+    qemu_irq *old_irqs = *gpio_out;
+    *gpio_out = qemu_allocate_irqs(handler, old_irqs, n);
+}
diff --git a/hw/core/loader.c b/hw/core/loader.c
new file mode 100644 (file)
index 0000000..7507914
--- /dev/null
@@ -0,0 +1,850 @@
+/*
+ * QEMU Executable loader
+ *
+ * Copyright (c) 2006 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.
+ *
+ * Gunzip functionality in this file is derived from u-boot:
+ *
+ * (C) Copyright 2008 Semihalf
+ *
+ * (C) Copyright 2000-2005
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * 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 "hw/hw.h"
+#include "disas/disas.h"
+#include "monitor/monitor.h"
+#include "sysemu/sysemu.h"
+#include "uboot_image.h"
+#include "hw/loader.h"
+#include "hw/nvram/fw_cfg.h"
+#include "exec/memory.h"
+#include "exec/address-spaces.h"
+
+#include <zlib.h>
+
+static int roms_loaded;
+
+/* return the size or -1 if error */
+int get_image_size(const char *filename)
+{
+    int fd, size;
+    fd = open(filename, O_RDONLY | O_BINARY);
+    if (fd < 0)
+        return -1;
+    size = lseek(fd, 0, SEEK_END);
+    close(fd);
+    return size;
+}
+
+/* return the size or -1 if error */
+/* deprecated, because caller does not specify buffer size! */
+int load_image(const char *filename, uint8_t *addr)
+{
+    int fd, size;
+    fd = open(filename, O_RDONLY | O_BINARY);
+    if (fd < 0)
+        return -1;
+    size = lseek(fd, 0, SEEK_END);
+    lseek(fd, 0, SEEK_SET);
+    if (read(fd, addr, size) != size) {
+        close(fd);
+        return -1;
+    }
+    close(fd);
+    return size;
+}
+
+/* read()-like version */
+ssize_t read_targphys(const char *name,
+                      int fd, hwaddr dst_addr, size_t nbytes)
+{
+    uint8_t *buf;
+    ssize_t did;
+
+    buf = g_malloc(nbytes);
+    did = read(fd, buf, nbytes);
+    if (did > 0)
+        rom_add_blob_fixed("read", buf, did, dst_addr);
+    g_free(buf);
+    return did;
+}
+
+/* return the size or -1 if error */
+int load_image_targphys(const char *filename,
+                        hwaddr addr, uint64_t max_sz)
+{
+    int size;
+
+    size = get_image_size(filename);
+    if (size > max_sz) {
+        return -1;
+    }
+    if (size > 0) {
+        rom_add_file_fixed(filename, addr, -1);
+    }
+    return size;
+}
+
+void pstrcpy_targphys(const char *name, hwaddr dest, int buf_size,
+                      const char *source)
+{
+    const char *nulp;
+    char *ptr;
+
+    if (buf_size <= 0) return;
+    nulp = memchr(source, 0, buf_size);
+    if (nulp) {
+        rom_add_blob_fixed(name, source, (nulp - source) + 1, dest);
+    } else {
+        rom_add_blob_fixed(name, source, buf_size, dest);
+        ptr = rom_ptr(dest + buf_size - 1);
+        *ptr = 0;
+    }
+}
+
+/* A.OUT loader */
+
+struct exec
+{
+  uint32_t a_info;   /* Use macros N_MAGIC, etc for access */
+  uint32_t a_text;   /* length of text, in bytes */
+  uint32_t a_data;   /* length of data, in bytes */
+  uint32_t a_bss;    /* length of uninitialized data area, in bytes */
+  uint32_t a_syms;   /* length of symbol table data in file, in bytes */
+  uint32_t a_entry;  /* start address */
+  uint32_t a_trsize; /* length of relocation info for text, in bytes */
+  uint32_t a_drsize; /* length of relocation info for data, in bytes */
+};
+
+static void bswap_ahdr(struct exec *e)
+{
+    bswap32s(&e->a_info);
+    bswap32s(&e->a_text);
+    bswap32s(&e->a_data);
+    bswap32s(&e->a_bss);
+    bswap32s(&e->a_syms);
+    bswap32s(&e->a_entry);
+    bswap32s(&e->a_trsize);
+    bswap32s(&e->a_drsize);
+}
+
+#define N_MAGIC(exec) ((exec).a_info & 0xffff)
+#define OMAGIC 0407
+#define NMAGIC 0410
+#define ZMAGIC 0413
+#define QMAGIC 0314
+#define _N_HDROFF(x) (1024 - sizeof (struct exec))
+#define N_TXTOFF(x)                                                    \
+    (N_MAGIC(x) == ZMAGIC ? _N_HDROFF((x)) + sizeof (struct exec) :    \
+     (N_MAGIC(x) == QMAGIC ? 0 : sizeof (struct exec)))
+#define N_TXTADDR(x, target_page_size) (N_MAGIC(x) == QMAGIC ? target_page_size : 0)
+#define _N_SEGMENT_ROUND(x, target_page_size) (((x) + target_page_size - 1) & ~(target_page_size - 1))
+
+#define _N_TXTENDADDR(x, target_page_size) (N_TXTADDR(x, target_page_size)+(x).a_text)
+
+#define N_DATADDR(x, target_page_size) \
+    (N_MAGIC(x)==OMAGIC? (_N_TXTENDADDR(x, target_page_size)) \
+     : (_N_SEGMENT_ROUND (_N_TXTENDADDR(x, target_page_size), target_page_size)))
+
+
+int load_aout(const char *filename, hwaddr addr, int max_sz,
+              int bswap_needed, hwaddr target_page_size)
+{
+    int fd;
+    ssize_t size, ret;
+    struct exec e;
+    uint32_t magic;
+
+    fd = open(filename, O_RDONLY | O_BINARY);
+    if (fd < 0)
+        return -1;
+
+    size = read(fd, &e, sizeof(e));
+    if (size < 0)
+        goto fail;
+
+    if (bswap_needed) {
+        bswap_ahdr(&e);
+    }
+
+    magic = N_MAGIC(e);
+    switch (magic) {
+    case ZMAGIC:
+    case QMAGIC:
+    case OMAGIC:
+        if (e.a_text + e.a_data > max_sz)
+            goto fail;
+       lseek(fd, N_TXTOFF(e), SEEK_SET);
+       size = read_targphys(filename, fd, addr, e.a_text + e.a_data);
+       if (size < 0)
+           goto fail;
+       break;
+    case NMAGIC:
+        if (N_DATADDR(e, target_page_size) + e.a_data > max_sz)
+            goto fail;
+       lseek(fd, N_TXTOFF(e), SEEK_SET);
+       size = read_targphys(filename, fd, addr, e.a_text);
+       if (size < 0)
+           goto fail;
+        ret = read_targphys(filename, fd, addr + N_DATADDR(e, target_page_size),
+                            e.a_data);
+       if (ret < 0)
+           goto fail;
+       size += ret;
+       break;
+    default:
+       goto fail;
+    }
+    close(fd);
+    return size;
+ fail:
+    close(fd);
+    return -1;
+}
+
+/* ELF loader */
+
+static void *load_at(int fd, int offset, int size)
+{
+    void *ptr;
+    if (lseek(fd, offset, SEEK_SET) < 0)
+        return NULL;
+    ptr = g_malloc(size);
+    if (read(fd, ptr, size) != size) {
+        g_free(ptr);
+        return NULL;
+    }
+    return ptr;
+}
+
+#ifdef ELF_CLASS
+#undef ELF_CLASS
+#endif
+
+#define ELF_CLASS   ELFCLASS32
+#include "elf.h"
+
+#define SZ             32
+#define elf_word        uint32_t
+#define elf_sword        int32_t
+#define bswapSZs       bswap32s
+#include "hw/elf_ops.h"
+
+#undef elfhdr
+#undef elf_phdr
+#undef elf_shdr
+#undef elf_sym
+#undef elf_note
+#undef elf_word
+#undef elf_sword
+#undef bswapSZs
+#undef SZ
+#define elfhdr         elf64_hdr
+#define elf_phdr       elf64_phdr
+#define elf_note       elf64_note
+#define elf_shdr       elf64_shdr
+#define elf_sym                elf64_sym
+#define elf_word        uint64_t
+#define elf_sword        int64_t
+#define bswapSZs       bswap64s
+#define SZ             64
+#include "hw/elf_ops.h"
+
+/* return < 0 if error, otherwise the number of bytes loaded in memory */
+int load_elf(const char *filename, uint64_t (*translate_fn)(void *, uint64_t),
+             void *translate_opaque, uint64_t *pentry, uint64_t *lowaddr,
+             uint64_t *highaddr, int big_endian, int elf_machine, int clear_lsb)
+{
+    int fd, data_order, target_data_order, must_swab, ret;
+    uint8_t e_ident[EI_NIDENT];
+
+    fd = open(filename, O_RDONLY | O_BINARY);
+    if (fd < 0) {
+        perror(filename);
+        return -1;
+    }
+    if (read(fd, e_ident, sizeof(e_ident)) != sizeof(e_ident))
+        goto fail;
+    if (e_ident[0] != ELFMAG0 ||
+        e_ident[1] != ELFMAG1 ||
+        e_ident[2] != ELFMAG2 ||
+        e_ident[3] != ELFMAG3)
+        goto fail;
+#ifdef HOST_WORDS_BIGENDIAN
+    data_order = ELFDATA2MSB;
+#else
+    data_order = ELFDATA2LSB;
+#endif
+    must_swab = data_order != e_ident[EI_DATA];
+    if (big_endian) {
+        target_data_order = ELFDATA2MSB;
+    } else {
+        target_data_order = ELFDATA2LSB;
+    }
+
+    if (target_data_order != e_ident[EI_DATA]) {
+        goto fail;
+    }
+
+    lseek(fd, 0, SEEK_SET);
+    if (e_ident[EI_CLASS] == ELFCLASS64) {
+        ret = load_elf64(filename, fd, translate_fn, translate_opaque, must_swab,
+                         pentry, lowaddr, highaddr, elf_machine, clear_lsb);
+    } else {
+        ret = load_elf32(filename, fd, translate_fn, translate_opaque, must_swab,
+                         pentry, lowaddr, highaddr, elf_machine, clear_lsb);
+    }
+
+    close(fd);
+    return ret;
+
+ fail:
+    close(fd);
+    return -1;
+}
+
+static void bswap_uboot_header(uboot_image_header_t *hdr)
+{
+#ifndef HOST_WORDS_BIGENDIAN
+    bswap32s(&hdr->ih_magic);
+    bswap32s(&hdr->ih_hcrc);
+    bswap32s(&hdr->ih_time);
+    bswap32s(&hdr->ih_size);
+    bswap32s(&hdr->ih_load);
+    bswap32s(&hdr->ih_ep);
+    bswap32s(&hdr->ih_dcrc);
+#endif
+}
+
+
+#define ZALLOC_ALIGNMENT       16
+
+static void *zalloc(void *x, unsigned items, unsigned size)
+{
+    void *p;
+
+    size *= items;
+    size = (size + ZALLOC_ALIGNMENT - 1) & ~(ZALLOC_ALIGNMENT - 1);
+
+    p = g_malloc(size);
+
+    return (p);
+}
+
+static void zfree(void *x, void *addr)
+{
+    g_free(addr);
+}
+
+
+#define HEAD_CRC       2
+#define EXTRA_FIELD    4
+#define ORIG_NAME      8
+#define COMMENT                0x10
+#define RESERVED       0xe0
+
+#define DEFLATED       8
+
+/* This is the usual maximum in uboot, so if a uImage overflows this, it would
+ * overflow on real hardware too. */
+#define UBOOT_MAX_GUNZIP_BYTES (64 << 20)
+
+static ssize_t gunzip(void *dst, size_t dstlen, uint8_t *src,
+                      size_t srclen)
+{
+    z_stream s;
+    ssize_t dstbytes;
+    int r, i, flags;
+
+    /* skip header */
+    i = 10;
+    flags = src[3];
+    if (src[2] != DEFLATED || (flags & RESERVED) != 0) {
+        puts ("Error: Bad gzipped data\n");
+        return -1;
+    }
+    if ((flags & EXTRA_FIELD) != 0)
+        i = 12 + src[10] + (src[11] << 8);
+    if ((flags & ORIG_NAME) != 0)
+        while (src[i++] != 0)
+            ;
+    if ((flags & COMMENT) != 0)
+        while (src[i++] != 0)
+            ;
+    if ((flags & HEAD_CRC) != 0)
+        i += 2;
+    if (i >= srclen) {
+        puts ("Error: gunzip out of data in header\n");
+        return -1;
+    }
+
+    s.zalloc = zalloc;
+    s.zfree = zfree;
+
+    r = inflateInit2(&s, -MAX_WBITS);
+    if (r != Z_OK) {
+        printf ("Error: inflateInit2() returned %d\n", r);
+        return (-1);
+    }
+    s.next_in = src + i;
+    s.avail_in = srclen - i;
+    s.next_out = dst;
+    s.avail_out = dstlen;
+    r = inflate(&s, Z_FINISH);
+    if (r != Z_OK && r != Z_STREAM_END) {
+        printf ("Error: inflate() returned %d\n", r);
+        return -1;
+    }
+    dstbytes = s.next_out - (unsigned char *) dst;
+    inflateEnd(&s);
+
+    return dstbytes;
+}
+
+/* Load a U-Boot image.  */
+int load_uimage(const char *filename, hwaddr *ep,
+                hwaddr *loadaddr, int *is_linux)
+{
+    int fd;
+    int size;
+    uboot_image_header_t h;
+    uboot_image_header_t *hdr = &h;
+    uint8_t *data = NULL;
+    int ret = -1;
+
+    fd = open(filename, O_RDONLY | O_BINARY);
+    if (fd < 0)
+        return -1;
+
+    size = read(fd, hdr, sizeof(uboot_image_header_t));
+    if (size < 0)
+        goto out;
+
+    bswap_uboot_header(hdr);
+
+    if (hdr->ih_magic != IH_MAGIC)
+        goto out;
+
+    /* TODO: Implement other image types.  */
+    if (hdr->ih_type != IH_TYPE_KERNEL) {
+        fprintf(stderr, "Can only load u-boot image type \"kernel\"\n");
+        goto out;
+    }
+
+    switch (hdr->ih_comp) {
+    case IH_COMP_NONE:
+    case IH_COMP_GZIP:
+        break;
+    default:
+        fprintf(stderr,
+                "Unable to load u-boot images with compression type %d\n",
+                hdr->ih_comp);
+        goto out;
+    }
+
+    /* TODO: Check CPU type.  */
+    if (is_linux) {
+        if (hdr->ih_os == IH_OS_LINUX)
+            *is_linux = 1;
+        else
+            *is_linux = 0;
+    }
+
+    *ep = hdr->ih_ep;
+    data = g_malloc(hdr->ih_size);
+
+    if (read(fd, data, hdr->ih_size) != hdr->ih_size) {
+        fprintf(stderr, "Error reading file\n");
+        goto out;
+    }
+
+    if (hdr->ih_comp == IH_COMP_GZIP) {
+        uint8_t *compressed_data;
+        size_t max_bytes;
+        ssize_t bytes;
+
+        compressed_data = data;
+        max_bytes = UBOOT_MAX_GUNZIP_BYTES;
+        data = g_malloc(max_bytes);
+
+        bytes = gunzip(data, max_bytes, compressed_data, hdr->ih_size);
+        g_free(compressed_data);
+        if (bytes < 0) {
+            fprintf(stderr, "Unable to decompress gzipped image!\n");
+            goto out;
+        }
+        hdr->ih_size = bytes;
+    }
+
+    rom_add_blob_fixed(filename, data, hdr->ih_size, hdr->ih_load);
+
+    if (loadaddr)
+        *loadaddr = hdr->ih_load;
+
+    ret = hdr->ih_size;
+
+out:
+    if (data)
+        g_free(data);
+    close(fd);
+    return ret;
+}
+
+/*
+ * Functions for reboot-persistent memory regions.
+ *  - used for vga bios and option roms.
+ *  - also linux kernel (-kernel / -initrd).
+ */
+
+typedef struct Rom Rom;
+
+struct Rom {
+    char *name;
+    char *path;
+
+    /* datasize is the amount of memory allocated in "data". If datasize is less
+     * than romsize, it means that the area from datasize to romsize is filled
+     * with zeros.
+     */
+    size_t romsize;
+    size_t datasize;
+
+    uint8_t *data;
+    int isrom;
+    char *fw_dir;
+    char *fw_file;
+
+    hwaddr addr;
+    QTAILQ_ENTRY(Rom) next;
+};
+
+static FWCfgState *fw_cfg;
+static QTAILQ_HEAD(, Rom) roms = QTAILQ_HEAD_INITIALIZER(roms);
+
+static void rom_insert(Rom *rom)
+{
+    Rom *item;
+
+    if (roms_loaded) {
+        hw_error ("ROM images must be loaded at startup\n");
+    }
+
+    /* list is ordered by load address */
+    QTAILQ_FOREACH(item, &roms, next) {
+        if (rom->addr >= item->addr)
+            continue;
+        QTAILQ_INSERT_BEFORE(item, rom, next);
+        return;
+    }
+    QTAILQ_INSERT_TAIL(&roms, rom, next);
+}
+
+int rom_add_file(const char *file, const char *fw_dir,
+                 hwaddr addr, int32_t bootindex)
+{
+    Rom *rom;
+    int rc, fd = -1;
+    char devpath[100];
+
+    rom = g_malloc0(sizeof(*rom));
+    rom->name = g_strdup(file);
+    rom->path = qemu_find_file(QEMU_FILE_TYPE_BIOS, rom->name);
+    if (rom->path == NULL) {
+        rom->path = g_strdup(file);
+    }
+
+    fd = open(rom->path, O_RDONLY | O_BINARY);
+    if (fd == -1) {
+        fprintf(stderr, "Could not open option rom '%s': %s\n",
+                rom->path, strerror(errno));
+        goto err;
+    }
+
+    if (fw_dir) {
+        rom->fw_dir  = g_strdup(fw_dir);
+        rom->fw_file = g_strdup(file);
+    }
+    rom->addr     = addr;
+    rom->romsize  = lseek(fd, 0, SEEK_END);
+    rom->datasize = rom->romsize;
+    rom->data     = g_malloc0(rom->datasize);
+    lseek(fd, 0, SEEK_SET);
+    rc = read(fd, rom->data, rom->datasize);
+    if (rc != rom->datasize) {
+        fprintf(stderr, "rom: file %-20s: read error: rc=%d (expected %zd)\n",
+                rom->name, rc, rom->datasize);
+        goto err;
+    }
+    close(fd);
+    rom_insert(rom);
+    if (rom->fw_file && fw_cfg) {
+        const char *basename;
+        char fw_file_name[56];
+
+        basename = strrchr(rom->fw_file, '/');
+        if (basename) {
+            basename++;
+        } else {
+            basename = rom->fw_file;
+        }
+        snprintf(fw_file_name, sizeof(fw_file_name), "%s/%s", rom->fw_dir,
+                 basename);
+        fw_cfg_add_file(fw_cfg, fw_file_name, rom->data, rom->romsize);
+        snprintf(devpath, sizeof(devpath), "/rom@%s", fw_file_name);
+    } else {
+        snprintf(devpath, sizeof(devpath), "/rom@" TARGET_FMT_plx, addr);
+    }
+
+    add_boot_device_path(bootindex, NULL, devpath);
+    return 0;
+
+err:
+    if (fd != -1)
+        close(fd);
+    g_free(rom->data);
+    g_free(rom->path);
+    g_free(rom->name);
+    g_free(rom);
+    return -1;
+}
+
+int rom_add_blob(const char *name, const void *blob, size_t len,
+                 hwaddr addr)
+{
+    Rom *rom;
+
+    rom           = g_malloc0(sizeof(*rom));
+    rom->name     = g_strdup(name);
+    rom->addr     = addr;
+    rom->romsize  = len;
+    rom->datasize = len;
+    rom->data     = g_malloc0(rom->datasize);
+    memcpy(rom->data, blob, len);
+    rom_insert(rom);
+    return 0;
+}
+
+/* This function is specific for elf program because we don't need to allocate
+ * all the rom. We just allocate the first part and the rest is just zeros. This
+ * is why romsize and datasize are different. Also, this function seize the
+ * memory ownership of "data", so we don't have to allocate and copy the buffer.
+ */
+int rom_add_elf_program(const char *name, void *data, size_t datasize,
+                        size_t romsize, hwaddr addr)
+{
+    Rom *rom;
+
+    rom           = g_malloc0(sizeof(*rom));
+    rom->name     = g_strdup(name);
+    rom->addr     = addr;
+    rom->datasize = datasize;
+    rom->romsize  = romsize;
+    rom->data     = data;
+    rom_insert(rom);
+    return 0;
+}
+
+int rom_add_vga(const char *file)
+{
+    return rom_add_file(file, "vgaroms", 0, -1);
+}
+
+int rom_add_option(const char *file, int32_t bootindex)
+{
+    return rom_add_file(file, "genroms", 0, bootindex);
+}
+
+static void rom_reset(void *unused)
+{
+    Rom *rom;
+
+    QTAILQ_FOREACH(rom, &roms, next) {
+        if (rom->fw_file) {
+            continue;
+        }
+        if (rom->data == NULL) {
+            continue;
+        }
+        cpu_physical_memory_write_rom(rom->addr, rom->data, rom->datasize);
+        if (rom->isrom) {
+            /* rom needs to be written only once */
+            g_free(rom->data);
+            rom->data = NULL;
+        }
+    }
+}
+
+int rom_load_all(void)
+{
+    hwaddr addr = 0;
+    MemoryRegionSection section;
+    Rom *rom;
+
+    QTAILQ_FOREACH(rom, &roms, next) {
+        if (rom->fw_file) {
+            continue;
+        }
+        if (addr > rom->addr) {
+            fprintf(stderr, "rom: requested regions overlap "
+                    "(rom %s. free=0x" TARGET_FMT_plx
+                    ", addr=0x" TARGET_FMT_plx ")\n",
+                    rom->name, addr, rom->addr);
+            return -1;
+        }
+        addr  = rom->addr;
+        addr += rom->romsize;
+        section = memory_region_find(get_system_memory(), rom->addr, 1);
+        rom->isrom = section.size && memory_region_is_rom(section.mr);
+    }
+    qemu_register_reset(rom_reset, NULL);
+    roms_loaded = 1;
+    return 0;
+}
+
+void rom_set_fw(void *f)
+{
+    fw_cfg = f;
+}
+
+static Rom *find_rom(hwaddr addr)
+{
+    Rom *rom;
+
+    QTAILQ_FOREACH(rom, &roms, next) {
+        if (rom->fw_file) {
+            continue;
+        }
+        if (rom->addr > addr) {
+            continue;
+        }
+        if (rom->addr + rom->romsize < addr) {
+            continue;
+        }
+        return rom;
+    }
+    return NULL;
+}
+
+/*
+ * Copies memory from registered ROMs to dest. Any memory that is contained in
+ * a ROM between addr and addr + size is copied. Note that this can involve
+ * multiple ROMs, which need not start at addr and need not end at addr + size.
+ */
+int rom_copy(uint8_t *dest, hwaddr addr, size_t size)
+{
+    hwaddr end = addr + size;
+    uint8_t *s, *d = dest;
+    size_t l = 0;
+    Rom *rom;
+
+    QTAILQ_FOREACH(rom, &roms, next) {
+        if (rom->fw_file) {
+            continue;
+        }
+        if (rom->addr + rom->romsize < addr) {
+            continue;
+        }
+        if (rom->addr > end) {
+            break;
+        }
+        if (!rom->data) {
+            continue;
+        }
+
+        d = dest + (rom->addr - addr);
+        s = rom->data;
+        l = rom->datasize;
+
+        if ((d + l) > (dest + size)) {
+            l = dest - d;
+        }
+
+        memcpy(d, s, l);
+
+        if (rom->romsize > rom->datasize) {
+            /* If datasize is less than romsize, it means that we didn't
+             * allocate all the ROM because the trailing data are only zeros.
+             */
+
+            d += l;
+            l = rom->romsize - rom->datasize;
+
+            if ((d + l) > (dest + size)) {
+                /* Rom size doesn't fit in the destination area. Adjust to avoid
+                 * overflow.
+                 */
+                l = dest - d;
+            }
+
+            if (l > 0) {
+                memset(d, 0x0, l);
+            }
+        }
+    }
+
+    return (d + l) - dest;
+}
+
+void *rom_ptr(hwaddr addr)
+{
+    Rom *rom;
+
+    rom = find_rom(addr);
+    if (!rom || !rom->data)
+        return NULL;
+    return rom->data + (addr - rom->addr);
+}
+
+void do_info_roms(Monitor *mon, const QDict *qdict)
+{
+    Rom *rom;
+
+    QTAILQ_FOREACH(rom, &roms, next) {
+        if (!rom->fw_file) {
+            monitor_printf(mon, "addr=" TARGET_FMT_plx
+                           " size=0x%06zx mem=%s name=\"%s\"\n",
+                           rom->addr, rom->romsize,
+                           rom->isrom ? "rom" : "ram",
+                           rom->name);
+        } else {
+            monitor_printf(mon, "fw=%s/%s"
+                           " size=0x%06zx name=\"%s\"\n",
+                           rom->fw_dir,
+                           rom->fw_file,
+                           rom->romsize,
+                           rom->name);
+        }
+    }
+}
diff --git a/hw/core/null-machine.c b/hw/core/null-machine.c
new file mode 100644 (file)
index 0000000..bdf109f
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Empty machine
+ *
+ * Copyright IBM, Corp. 2012
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@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-common.h"
+#include "hw/hw.h"
+#include "hw/boards.h"
+
+static void machine_none_init(QEMUMachineInitArgs *args)
+{
+}
+
+static QEMUMachine machine_none = {
+    .name = "none",
+    .desc = "empty machine",
+    .init = machine_none_init,
+    .max_cpus = 0,
+    DEFAULT_MACHINE_OPTIONS,
+};
+
+static void register_machines(void)
+{
+    qemu_register_machine(&machine_none);
+}
+
+machine_init(register_machines);
+
diff --git a/hw/core/ptimer.c b/hw/core/ptimer.c
new file mode 100644 (file)
index 0000000..4bc96c9
--- /dev/null
@@ -0,0 +1,231 @@
+/*
+ * General purpose implementation of a simple periodic countdown timer.
+ *
+ * Copyright (c) 2007 CodeSourcery.
+ *
+ * This code is licensed under the GNU LGPL.
+ */
+#include "hw/hw.h"
+#include "qemu/timer.h"
+#include "hw/ptimer.h"
+#include "qemu/host-utils.h"
+
+struct ptimer_state
+{
+    uint8_t enabled; /* 0 = disabled, 1 = periodic, 2 = oneshot.  */
+    uint64_t limit;
+    uint64_t delta;
+    uint32_t period_frac;
+    int64_t period;
+    int64_t last_event;
+    int64_t next_event;
+    QEMUBH *bh;
+    QEMUTimer *timer;
+};
+
+/* Use a bottom-half routine to avoid reentrancy issues.  */
+static void ptimer_trigger(ptimer_state *s)
+{
+    if (s->bh) {
+        qemu_bh_schedule(s->bh);
+    }
+}
+
+static void ptimer_reload(ptimer_state *s)
+{
+    if (s->delta == 0) {
+        ptimer_trigger(s);
+        s->delta = s->limit;
+    }
+    if (s->delta == 0 || s->period == 0) {
+        fprintf(stderr, "Timer with period zero, disabling\n");
+        s->enabled = 0;
+        return;
+    }
+
+    s->last_event = s->next_event;
+    s->next_event = s->last_event + s->delta * s->period;
+    if (s->period_frac) {
+        s->next_event += ((int64_t)s->period_frac * s->delta) >> 32;
+    }
+    qemu_mod_timer(s->timer, s->next_event);
+}
+
+static void ptimer_tick(void *opaque)
+{
+    ptimer_state *s = (ptimer_state *)opaque;
+    ptimer_trigger(s);
+    s->delta = 0;
+    if (s->enabled == 2) {
+        s->enabled = 0;
+    } else {
+        ptimer_reload(s);
+    }
+}
+
+uint64_t ptimer_get_count(ptimer_state *s)
+{
+    int64_t now;
+    uint64_t counter;
+
+    if (s->enabled) {
+        now = qemu_get_clock_ns(vm_clock);
+        /* Figure out the current counter value.  */
+        if (now - s->next_event > 0
+            || s->period == 0) {
+            /* Prevent timer underflowing if it should already have
+               triggered.  */
+            counter = 0;
+        } else {
+            uint64_t rem;
+            uint64_t div;
+            int clz1, clz2;
+            int shift;
+
+            /* We need to divide time by period, where time is stored in
+               rem (64-bit integer) and period is stored in period/period_frac
+               (64.32 fixed point).
+              
+               Doing full precision division is hard, so scale values and
+               do a 64-bit division.  The result should be rounded down,
+               so that the rounding error never causes the timer to go
+               backwards.
+            */
+
+            rem = s->next_event - now;
+            div = s->period;
+
+            clz1 = clz64(rem);
+            clz2 = clz64(div);
+            shift = clz1 < clz2 ? clz1 : clz2;
+
+            rem <<= shift;
+            div <<= shift;
+            if (shift >= 32) {
+                div |= ((uint64_t)s->period_frac << (shift - 32));
+            } else {
+                if (shift != 0)
+                    div |= (s->period_frac >> (32 - shift));
+                /* Look at remaining bits of period_frac and round div up if 
+                   necessary.  */
+                if ((uint32_t)(s->period_frac << shift))
+                    div += 1;
+            }
+            counter = rem / div;
+        }
+    } else {
+        counter = s->delta;
+    }
+    return counter;
+}
+
+void ptimer_set_count(ptimer_state *s, uint64_t count)
+{
+    s->delta = count;
+    if (s->enabled) {
+        s->next_event = qemu_get_clock_ns(vm_clock);
+        ptimer_reload(s);
+    }
+}
+
+void ptimer_run(ptimer_state *s, int oneshot)
+{
+    if (s->enabled) {
+        return;
+    }
+    if (s->period == 0) {
+        fprintf(stderr, "Timer with period zero, disabling\n");
+        return;
+    }
+    s->enabled = oneshot ? 2 : 1;
+    s->next_event = qemu_get_clock_ns(vm_clock);
+    ptimer_reload(s);
+}
+
+/* Pause a timer.  Note that this may cause it to "lose" time, even if it
+   is immediately restarted.  */
+void ptimer_stop(ptimer_state *s)
+{
+    if (!s->enabled)
+        return;
+
+    s->delta = ptimer_get_count(s);
+    qemu_del_timer(s->timer);
+    s->enabled = 0;
+}
+
+/* Set counter increment interval in nanoseconds.  */
+void ptimer_set_period(ptimer_state *s, int64_t period)
+{
+    s->period = period;
+    s->period_frac = 0;
+    if (s->enabled) {
+        s->next_event = qemu_get_clock_ns(vm_clock);
+        ptimer_reload(s);
+    }
+}
+
+/* Set counter frequency in Hz.  */
+void ptimer_set_freq(ptimer_state *s, uint32_t freq)
+{
+    s->period = 1000000000ll / freq;
+    s->period_frac = (1000000000ll << 32) / freq;
+    if (s->enabled) {
+        s->next_event = qemu_get_clock_ns(vm_clock);
+        ptimer_reload(s);
+    }
+}
+
+/* Set the initial countdown value.  If reload is nonzero then also set
+   count = limit.  */
+void ptimer_set_limit(ptimer_state *s, uint64_t limit, int reload)
+{
+    /*
+     * Artificially limit timeout rate to something
+     * achievable under QEMU.  Otherwise, QEMU spends all
+     * its time generating timer interrupts, and there
+     * is no forward progress.
+     * About ten microseconds is the fastest that really works
+     * on the current generation of host machines.
+     */
+
+    if (limit * s->period < 10000 && s->period) {
+        limit = 10000 / s->period;
+    }
+
+    s->limit = limit;
+    if (reload)
+        s->delta = limit;
+    if (s->enabled && reload) {
+        s->next_event = qemu_get_clock_ns(vm_clock);
+        ptimer_reload(s);
+    }
+}
+
+const VMStateDescription vmstate_ptimer = {
+    .name = "ptimer",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT8(enabled, ptimer_state),
+        VMSTATE_UINT64(limit, ptimer_state),
+        VMSTATE_UINT64(delta, ptimer_state),
+        VMSTATE_UINT32(period_frac, ptimer_state),
+        VMSTATE_INT64(period, ptimer_state),
+        VMSTATE_INT64(last_event, ptimer_state),
+        VMSTATE_INT64(next_event, ptimer_state),
+        VMSTATE_TIMER(timer, ptimer_state),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+ptimer_state *ptimer_init(QEMUBH *bh)
+{
+    ptimer_state *s;
+
+    s = (ptimer_state *)g_malloc0(sizeof(ptimer_state));
+    s->bh = bh;
+    s->timer = qemu_new_timer_ns(vm_clock, ptimer_tick, s);
+    return s;
+}
diff --git a/hw/core/qdev-addr.c b/hw/core/qdev-addr.c
new file mode 100644 (file)
index 0000000..80a38bb
--- /dev/null
@@ -0,0 +1,78 @@
+#include "hw/qdev.h"
+#include "hw/qdev-addr.h"
+#include "exec/hwaddr.h"
+#include "qapi/qmp/qerror.h"
+#include "qapi/visitor.h"
+
+/* --- target physical address --- */
+
+static int parse_taddr(DeviceState *dev, Property *prop, const char *str)
+{
+    hwaddr *ptr = qdev_get_prop_ptr(dev, prop);
+
+    *ptr = strtoull(str, NULL, 16);
+    return 0;
+}
+
+static int print_taddr(DeviceState *dev, Property *prop, char *dest, size_t len)
+{
+    hwaddr *ptr = qdev_get_prop_ptr(dev, prop);
+    return snprintf(dest, len, "0x" TARGET_FMT_plx, *ptr);
+}
+
+static void get_taddr(Object *obj, Visitor *v, void *opaque,
+                      const char *name, Error **errp)
+{
+    DeviceState *dev = DEVICE(obj);
+    Property *prop = opaque;
+    hwaddr *ptr = qdev_get_prop_ptr(dev, prop);
+    int64_t value;
+
+    value = *ptr;
+    visit_type_int64(v, &value, name, errp);
+}
+
+static void set_taddr(Object *obj, Visitor *v, void *opaque,
+                      const char *name, Error **errp)
+{
+    DeviceState *dev = DEVICE(obj);
+    Property *prop = opaque;
+    hwaddr *ptr = qdev_get_prop_ptr(dev, prop);
+    Error *local_err = NULL;
+    int64_t value;
+
+    if (dev->realized) {
+        qdev_prop_set_after_realize(dev, name, errp);
+        return;
+    }
+
+    visit_type_int64(v, &value, name, &local_err);
+    if (local_err) {
+        error_propagate(errp, local_err);
+        return;
+    }
+    if ((uint64_t)value <= (uint64_t) ~(hwaddr)0) {
+        *ptr = value;
+    } else {
+        error_set(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE,
+                  dev->id?:"", name, value, (uint64_t) 0,
+                  (uint64_t) ~(hwaddr)0);
+    }
+}
+
+
+PropertyInfo qdev_prop_taddr = {
+    .name  = "taddr",
+    .parse = parse_taddr,
+    .print = print_taddr,
+    .get   = get_taddr,
+    .set   = set_taddr,
+};
+
+void qdev_prop_set_taddr(DeviceState *dev, const char *name, hwaddr value)
+{
+    Error *errp = NULL;
+    object_property_set_int(OBJECT(dev), value, name, &errp);
+    assert(!errp);
+
+}
diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c
new file mode 100644 (file)
index 0000000..8c2e152
--- /dev/null
@@ -0,0 +1,391 @@
+/*
+ * qdev property parsing and global properties
+ * (parts specific for qemu-system-*)
+ *
+ * This file is based on code from hw/qdev-properties.c from
+ * commit 074a86fccd185616469dfcdc0e157f438aebba18,
+ * Copyright (c) Gerd Hoffmann <kraxel@redhat.com> and other contributors.
+ *
+ * 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 "net/net.h"
+#include "hw/qdev.h"
+#include "qapi/qmp/qerror.h"
+#include "sysemu/blockdev.h"
+#include "hw/block/block.h"
+#include "net/hub.h"
+#include "qapi/visitor.h"
+#include "char/char.h"
+
+static void get_pointer(Object *obj, Visitor *v, Property *prop,
+                        const char *(*print)(void *ptr),
+                        const char *name, Error **errp)
+{
+    DeviceState *dev = DEVICE(obj);
+    void **ptr = qdev_get_prop_ptr(dev, prop);
+    char *p;
+
+    p = (char *) (*ptr ? print(*ptr) : "");
+    visit_type_str(v, &p, name, errp);
+}
+
+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);
+    Error *local_err = NULL;
+    void **ptr = qdev_get_prop_ptr(dev, prop);
+    char *str;
+    int ret;
+
+    if (dev->realized) {
+        qdev_prop_set_after_realize(dev, name, errp);
+        return;
+    }
+
+    visit_type_str(v, &str, name, &local_err);
+    if (local_err) {
+        error_propagate(errp, local_err);
+        return;
+    }
+    if (!*str) {
+        g_free(str);
+        *ptr = NULL;
+        return;
+    }
+    ret = parse(dev, str, ptr);
+    error_set_from_qdev_prop_error(errp, ret, dev, prop, str);
+    g_free(str);
+}
+
+/* --- drive --- */
+
+static int parse_drive(DeviceState *dev, const char *str, void **ptr)
+{
+    BlockDriverState *bs;
+
+    bs = bdrv_find(str);
+    if (bs == NULL) {
+        return -ENOENT;
+    }
+    if (bdrv_attach_dev(bs, dev) < 0) {
+        return -EEXIST;
+    }
+    *ptr = bs;
+    return 0;
+}
+
+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) {
+        bdrv_detach_dev(*ptr, dev);
+        blockdev_auto_del(*ptr);
+    }
+}
+
+static const char *print_drive(void *ptr)
+{
+    return bdrv_get_device_name(ptr);
+}
+
+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",
+    .get   = get_drive,
+    .set   = set_drive,
+    .release = release_drive,
+};
+
+/* --- character device --- */
+
+static int parse_chr(DeviceState *dev, const char *str, void **ptr)
+{
+    CharDriverState *chr = qemu_chr_find(str);
+    if (chr == NULL) {
+        return -ENOENT;
+    }
+    if (qemu_chr_fe_claim(chr) != 0) {
+        return -EEXIST;
+    }
+    *ptr = chr;
+    return 0;
+}
+
+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);
+    CharDriverState *chr = *ptr;
+
+    if (chr) {
+        qemu_chr_add_handlers(chr, NULL, NULL, NULL, NULL);
+        qemu_chr_fe_release(chr);
+    }
+}
+
+
+static const char *print_chr(void *ptr)
+{
+    CharDriverState *chr = ptr;
+
+    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",
+    .get   = get_chr,
+    .set   = set_chr,
+    .release = release_chr,
+};
+
+/* --- netdev device --- */
+
+static int parse_netdev(DeviceState *dev, const char *str, void **ptr)
+{
+    NICPeers *peers_ptr = (NICPeers *)ptr;
+    NICConf *conf = container_of(peers_ptr, NICConf, peers);
+    NetClientState **ncs = peers_ptr->ncs;
+    NetClientState *peers[MAX_QUEUE_NUM];
+    int queues, i = 0;
+    int ret;
+
+    queues = qemu_find_net_clients_except(str, peers,
+                                          NET_CLIENT_OPTIONS_KIND_NIC,
+                                          MAX_QUEUE_NUM);
+    if (queues == 0) {
+        ret = -ENOENT;
+        goto err;
+    }
+
+    if (queues > MAX_QUEUE_NUM) {
+        ret = -E2BIG;
+        goto err;
+    }
+
+    for (i = 0; i < queues; i++) {
+        if (peers[i] == NULL) {
+            ret = -ENOENT;
+            goto err;
+        }
+
+        if (peers[i]->peer) {
+            ret = -EEXIST;
+            goto err;
+        }
+
+        ncs[i] = peers[i];
+        ncs[i]->queue_index = i;
+    }
+
+    conf->queues = queues;
+
+    return 0;
+
+err:
+    return ret;
+}
+
+static const char *print_netdev(void *ptr)
+{
+    NetClientState *netdev = ptr;
+
+    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",
+    .get   = get_netdev,
+    .set   = set_netdev,
+};
+
+/* --- vlan --- */
+
+static int print_vlan(DeviceState *dev, Property *prop, char *dest, size_t len)
+{
+    NetClientState **ptr = qdev_get_prop_ptr(dev, prop);
+
+    if (*ptr) {
+        int id;
+        if (!net_hub_id_for_client(*ptr, &id)) {
+            return snprintf(dest, len, "%d", id);
+        }
+    }
+
+    return snprintf(dest, len, "<null>");
+}
+
+static void get_vlan(Object *obj, Visitor *v, void *opaque,
+                     const char *name, Error **errp)
+{
+    DeviceState *dev = DEVICE(obj);
+    Property *prop = opaque;
+    NetClientState **ptr = qdev_get_prop_ptr(dev, prop);
+    int32_t id = -1;
+
+    if (*ptr) {
+        int hub_id;
+        if (!net_hub_id_for_client(*ptr, &hub_id)) {
+            id = hub_id;
+        }
+    }
+
+    visit_type_int32(v, &id, name, errp);
+}
+
+static void set_vlan(Object *obj, Visitor *v, void *opaque,
+                     const char *name, Error **errp)
+{
+    DeviceState *dev = DEVICE(obj);
+    Property *prop = opaque;
+    NICPeers *peers_ptr = qdev_get_prop_ptr(dev, prop);
+    NetClientState **ptr = &peers_ptr->ncs[0];
+    Error *local_err = NULL;
+    int32_t id;
+    NetClientState *hubport;
+
+    if (dev->realized) {
+        qdev_prop_set_after_realize(dev, name, errp);
+        return;
+    }
+
+    visit_type_int32(v, &id, name, &local_err);
+    if (local_err) {
+        error_propagate(errp, local_err);
+        return;
+    }
+    if (id == -1) {
+        *ptr = NULL;
+        return;
+    }
+
+    hubport = net_hub_port_find(id);
+    if (!hubport) {
+        error_set(errp, QERR_INVALID_PARAMETER_VALUE,
+                  name, prop->info->name);
+        return;
+    }
+    *ptr = hubport;
+}
+
+PropertyInfo qdev_prop_vlan = {
+    .name  = "vlan",
+    .print = print_vlan,
+    .get   = get_vlan,
+    .set   = set_vlan,
+};
+
+int qdev_prop_set_drive(DeviceState *dev, const char *name,
+                        BlockDriverState *value)
+{
+    Error *errp = NULL;
+    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);
+        error_free(errp);
+        return -1;
+    }
+    return 0;
+}
+
+void qdev_prop_set_drive_nofail(DeviceState *dev, const char *name,
+                                BlockDriverState *value)
+{
+    if (qdev_prop_set_drive(dev, name, value) < 0) {
+        exit(1);
+    }
+}
+void qdev_prop_set_chr(DeviceState *dev, const char *name,
+                       CharDriverState *value)
+{
+    Error *errp = NULL;
+    assert(!value || value->label);
+    object_property_set_str(OBJECT(dev),
+                            value ? value->label : "", name, &errp);
+    assert_no_error(errp);
+}
+
+void qdev_prop_set_netdev(DeviceState *dev, const char *name,
+                          NetClientState *value)
+{
+    Error *errp = NULL;
+    assert(!value || value->name);
+    object_property_set_str(OBJECT(dev),
+                            value ? value->name : "", name, &errp);
+    assert_no_error(errp);
+}
+
+void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd)
+{
+    qdev_prop_set_macaddr(dev, "mac", nd->macaddr.a);
+    if (nd->netdev) {
+        qdev_prop_set_netdev(dev, "netdev", nd->netdev);
+    }
+    if (nd->nvectors != DEV_NVECTORS_UNSPECIFIED &&
+        object_property_find(OBJECT(dev), "vectors", NULL)) {
+        qdev_prop_set_uint32(dev, "vectors", nd->nvectors);
+    }
+    nd->instantiated = 1;
+}
+
+static int qdev_add_one_global(QemuOpts *opts, void *opaque)
+{
+    GlobalProperty *g;
+
+    g = g_malloc0(sizeof(*g));
+    g->driver   = qemu_opt_get(opts, "driver");
+    g->property = qemu_opt_get(opts, "property");
+    g->value    = qemu_opt_get(opts, "value");
+    qdev_prop_register_global(g);
+    return 0;
+}
+
+void qemu_add_globals(void)
+{
+    qemu_opts_foreach(qemu_find_opts("global"), qdev_add_one_global, NULL, 0);
+}
diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c
new file mode 100644 (file)
index 0000000..9a0872d
--- /dev/null
@@ -0,0 +1,1092 @@
+#include "net/net.h"
+#include "hw/qdev.h"
+#include "qapi/qmp/qerror.h"
+#include "sysemu/blockdev.h"
+#include "hw/block/block.h"
+#include "net/hub.h"
+#include "qapi/visitor.h"
+#include "char/char.h"
+
+void qdev_prop_set_after_realize(DeviceState *dev, const char *name,
+                                  Error **errp)
+{
+    if (dev->id) {
+        error_setg(errp, "Attempt to set property '%s' on device '%s' "
+                   "(type '%s') after it was realized", name, dev->id,
+                   object_get_typename(OBJECT(dev)));
+    } else {
+        error_setg(errp, "Attempt to set property '%s' on anonymous device "
+                   "(type '%s') after it was realized", name,
+                   object_get_typename(OBJECT(dev)));
+    }
+}
+
+void *qdev_get_prop_ptr(DeviceState *dev, Property *prop)
+{
+    void *ptr = dev;
+    ptr += prop->offset;
+    return ptr;
+}
+
+static void get_enum(Object *obj, Visitor *v, void *opaque,
+                     const char *name, Error **errp)
+{
+    DeviceState *dev = DEVICE(obj);
+    Property *prop = opaque;
+    int *ptr = qdev_get_prop_ptr(dev, prop);
+
+    visit_type_enum(v, ptr, prop->info->enum_table,
+                    prop->info->name, prop->name, errp);
+}
+
+static void set_enum(Object *obj, Visitor *v, void *opaque,
+                     const char *name, Error **errp)
+{
+    DeviceState *dev = DEVICE(obj);
+    Property *prop = opaque;
+    int *ptr = qdev_get_prop_ptr(dev, prop);
+
+    if (dev->realized) {
+        qdev_prop_set_after_realize(dev, name, errp);
+        return;
+    }
+
+    visit_type_enum(v, ptr, prop->info->enum_table,
+                    prop->info->name, prop->name, errp);
+}
+
+/* Bit */
+
+static uint32_t qdev_get_prop_mask(Property *prop)
+{
+    assert(prop->info == &qdev_prop_bit);
+    return 0x1 << prop->bitnr;
+}
+
+static void bit_prop_set(DeviceState *dev, Property *props, bool val)
+{
+    uint32_t *p = qdev_get_prop_ptr(dev, props);
+    uint32_t mask = qdev_get_prop_mask(props);
+    if (val) {
+        *p |= mask;
+    } else {
+        *p &= ~mask;
+    }
+}
+
+static int print_bit(DeviceState *dev, Property *prop, char *dest, size_t len)
+{
+    uint32_t *p = qdev_get_prop_ptr(dev, prop);
+    return snprintf(dest, len, (*p & qdev_get_prop_mask(prop)) ? "on" : "off");
+}
+
+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;
+
+    visit_type_bool(v, &value, name, errp);
+}
+
+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;
+
+    if (dev->realized) {
+        qdev_prop_set_after_realize(dev, name, errp);
+        return;
+    }
+
+    visit_type_bool(v, &value, name, &local_err);
+    if (local_err) {
+        error_propagate(errp, local_err);
+        return;
+    }
+    bit_prop_set(dev, prop, value);
+}
+
+PropertyInfo qdev_prop_bit = {
+    .name  = "boolean",
+    .legacy_name  = "on/off",
+    .print = print_bit,
+    .get   = get_bit,
+    .set   = set_bit,
+};
+
+/* --- 8bit integer --- */
+
+static void get_uint8(Object *obj, Visitor *v, void *opaque,
+                      const char *name, Error **errp)
+{
+    DeviceState *dev = DEVICE(obj);
+    Property *prop = opaque;
+    uint8_t *ptr = qdev_get_prop_ptr(dev, prop);
+
+    visit_type_uint8(v, ptr, name, errp);
+}
+
+static void set_uint8(Object *obj, Visitor *v, void *opaque,
+                      const char *name, Error **errp)
+{
+    DeviceState *dev = DEVICE(obj);
+    Property *prop = opaque;
+    uint8_t *ptr = qdev_get_prop_ptr(dev, prop);
+
+    if (dev->realized) {
+        qdev_prop_set_after_realize(dev, name, errp);
+        return;
+    }
+
+    visit_type_uint8(v, ptr, name, errp);
+}
+
+PropertyInfo qdev_prop_uint8 = {
+    .name  = "uint8",
+    .get   = get_uint8,
+    .set   = set_uint8,
+};
+
+/* --- 8bit hex value --- */
+
+static int parse_hex8(DeviceState *dev, Property *prop, const char *str)
+{
+    uint8_t *ptr = qdev_get_prop_ptr(dev, prop);
+    char *end;
+
+    if (str[0] != '0' || str[1] != 'x') {
+        return -EINVAL;
+    }
+
+    *ptr = strtoul(str, &end, 16);
+    if ((*end != '\0') || (end == str)) {
+        return -EINVAL;
+    }
+
+    return 0;
+}
+
+static int print_hex8(DeviceState *dev, Property *prop, char *dest, size_t len)
+{
+    uint8_t *ptr = qdev_get_prop_ptr(dev, prop);
+    return snprintf(dest, len, "0x%" PRIx8, *ptr);
+}
+
+PropertyInfo qdev_prop_hex8 = {
+    .name  = "uint8",
+    .legacy_name  = "hex8",
+    .parse = parse_hex8,
+    .print = print_hex8,
+    .get   = get_uint8,
+    .set   = set_uint8,
+};
+
+/* --- 16bit integer --- */
+
+static void get_uint16(Object *obj, Visitor *v, void *opaque,
+                       const char *name, Error **errp)
+{
+    DeviceState *dev = DEVICE(obj);
+    Property *prop = opaque;
+    uint16_t *ptr = qdev_get_prop_ptr(dev, prop);
+
+    visit_type_uint16(v, ptr, name, errp);
+}
+
+static void set_uint16(Object *obj, Visitor *v, void *opaque,
+                       const char *name, Error **errp)
+{
+    DeviceState *dev = DEVICE(obj);
+    Property *prop = opaque;
+    uint16_t *ptr = qdev_get_prop_ptr(dev, prop);
+
+    if (dev->realized) {
+        qdev_prop_set_after_realize(dev, name, errp);
+        return;
+    }
+
+    visit_type_uint16(v, ptr, name, errp);
+}
+
+PropertyInfo qdev_prop_uint16 = {
+    .name  = "uint16",
+    .get   = get_uint16,
+    .set   = set_uint16,
+};
+
+/* --- 32bit integer --- */
+
+static void get_uint32(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);
+
+    visit_type_uint32(v, ptr, name, errp);
+}
+
+static void set_uint32(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);
+
+    if (dev->realized) {
+        qdev_prop_set_after_realize(dev, name, errp);
+        return;
+    }
+
+    visit_type_uint32(v, ptr, name, errp);
+}
+
+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);
+
+    visit_type_int32(v, ptr, name, errp);
+}
+
+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);
+
+    if (dev->realized) {
+        qdev_prop_set_after_realize(dev, name, errp);
+        return;
+    }
+
+    visit_type_int32(v, ptr, name, errp);
+}
+
+PropertyInfo qdev_prop_uint32 = {
+    .name  = "uint32",
+    .get   = get_uint32,
+    .set   = set_uint32,
+};
+
+PropertyInfo qdev_prop_int32 = {
+    .name  = "int32",
+    .get   = get_int32,
+    .set   = set_int32,
+};
+
+/* --- 32bit hex value --- */
+
+static int parse_hex32(DeviceState *dev, Property *prop, const char *str)
+{
+    uint32_t *ptr = qdev_get_prop_ptr(dev, prop);
+    char *end;
+
+    if (str[0] != '0' || str[1] != 'x') {
+        return -EINVAL;
+    }
+
+    *ptr = strtoul(str, &end, 16);
+    if ((*end != '\0') || (end == str)) {
+        return -EINVAL;
+    }
+
+    return 0;
+}
+
+static int print_hex32(DeviceState *dev, Property *prop, char *dest, size_t len)
+{
+    uint32_t *ptr = qdev_get_prop_ptr(dev, prop);
+    return snprintf(dest, len, "0x%" PRIx32, *ptr);
+}
+
+PropertyInfo qdev_prop_hex32 = {
+    .name  = "uint32",
+    .legacy_name  = "hex32",
+    .parse = parse_hex32,
+    .print = print_hex32,
+    .get   = get_uint32,
+    .set   = set_uint32,
+};
+
+/* --- 64bit integer --- */
+
+static void get_uint64(Object *obj, Visitor *v, void *opaque,
+                       const char *name, Error **errp)
+{
+    DeviceState *dev = DEVICE(obj);
+    Property *prop = opaque;
+    uint64_t *ptr = qdev_get_prop_ptr(dev, prop);
+
+    visit_type_uint64(v, ptr, name, errp);
+}
+
+static void set_uint64(Object *obj, Visitor *v, void *opaque,
+                       const char *name, Error **errp)
+{
+    DeviceState *dev = DEVICE(obj);
+    Property *prop = opaque;
+    uint64_t *ptr = qdev_get_prop_ptr(dev, prop);
+
+    if (dev->realized) {
+        qdev_prop_set_after_realize(dev, name, errp);
+        return;
+    }
+
+    visit_type_uint64(v, ptr, name, errp);
+}
+
+PropertyInfo qdev_prop_uint64 = {
+    .name  = "uint64",
+    .get   = get_uint64,
+    .set   = set_uint64,
+};
+
+/* --- 64bit hex value --- */
+
+static int parse_hex64(DeviceState *dev, Property *prop, const char *str)
+{
+    uint64_t *ptr = qdev_get_prop_ptr(dev, prop);
+    char *end;
+
+    if (str[0] != '0' || str[1] != 'x') {
+        return -EINVAL;
+    }
+
+    *ptr = strtoull(str, &end, 16);
+    if ((*end != '\0') || (end == str)) {
+        return -EINVAL;
+    }
+
+    return 0;
+}
+
+static int print_hex64(DeviceState *dev, Property *prop, char *dest, size_t len)
+{
+    uint64_t *ptr = qdev_get_prop_ptr(dev, prop);
+    return snprintf(dest, len, "0x%" PRIx64, *ptr);
+}
+
+PropertyInfo qdev_prop_hex64 = {
+    .name  = "uint64",
+    .legacy_name  = "hex64",
+    .parse = parse_hex64,
+    .print = print_hex64,
+    .get   = get_uint64,
+    .set   = set_uint64,
+};
+
+/* --- string --- */
+
+static void release_string(Object *obj, const char *name, void *opaque)
+{
+    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)
+{
+    char **ptr = qdev_get_prop_ptr(dev, prop);
+    if (!*ptr) {
+        return snprintf(dest, len, "<null>");
+    }
+    return snprintf(dest, len, "\"%s\"", *ptr);
+}
+
+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);
+
+    if (!*ptr) {
+        char *str = (char *)"";
+        visit_type_str(v, &str, name, errp);
+    } else {
+        visit_type_str(v, ptr, name, errp);
+    }
+}
+
+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;
+    char *str;
+
+    if (dev->realized) {
+        qdev_prop_set_after_realize(dev, name, errp);
+        return;
+    }
+
+    visit_type_str(v, &str, name, &local_err);
+    if (local_err) {
+        error_propagate(errp, local_err);
+        return;
+    }
+    if (*ptr) {
+        g_free(*ptr);
+    }
+    *ptr = str;
+}
+
+PropertyInfo qdev_prop_string = {
+    .name  = "string",
+    .print = print_string,
+    .release = release_string,
+    .get   = get_string,
+    .set   = set_string,
+};
+
+/* --- pointer --- */
+
+/* Not a proper property, just for dirty hacks.  TODO Remove it!  */
+PropertyInfo qdev_prop_ptr = {
+    .name  = "ptr",
+};
+
+/* --- mac address --- */
+
+/*
+ * accepted syntax versions:
+ *   01:02:03:04:05:06
+ *   01-02-03-04-05-06
+ */
+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 *str, *p;
+
+    if (dev->realized) {
+        qdev_prop_set_after_realize(dev, name, errp);
+        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])) {
+            goto inval;
+        }
+        if (!qemu_isxdigit(str[pos+1])) {
+            goto inval;
+        }
+        if (i == 5) {
+            if (str[pos+2] != '\0') {
+                goto inval;
+            }
+        } else {
+            if (str[pos+2] != ':' && str[pos+2] != '-') {
+                goto inval;
+            }
+        }
+        mac->a[i] = strtol(str+pos, &p, 16);
+    }
+    g_free(str);
+    return;
+
+inval:
+    error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str);
+    g_free(str);
+}
+
+PropertyInfo qdev_prop_macaddr = {
+    .name  = "macaddr",
+    .get   = get_mac,
+    .set   = set_mac,
+};
+
+/* --- lost tick policy --- */
+
+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,
+};
+
+QEMU_BUILD_BUG_ON(sizeof(LostTickPolicy) != sizeof(int));
+
+PropertyInfo qdev_prop_losttickpolicy = {
+    .name  = "LostTickPolicy",
+    .enum_table  = lost_tick_policy_table,
+    .get   = get_enum,
+    .set   = set_enum,
+};
+
+/* --- BIOS CHS translation */
+
+static const char *bios_chs_trans_table[] = {
+    [BIOS_ATA_TRANSLATION_AUTO] = "auto",
+    [BIOS_ATA_TRANSLATION_NONE] = "none",
+    [BIOS_ATA_TRANSLATION_LBA]  = "lba",
+};
+
+PropertyInfo qdev_prop_bios_chs_trans = {
+    .name = "bios-chs-trans",
+    .enum_table = bios_chs_trans_table,
+    .get = get_enum,
+    .set = set_enum,
+};
+
+/* --- pci address --- */
+
+/*
+ * bus-local address, i.e. "$slot" or "$slot.$fn"
+ */
+static void set_pci_devfn(Object *obj, Visitor *v, void *opaque,
+                          const char *name, Error **errp)
+{
+    DeviceState *dev = DEVICE(obj);
+    Property *prop = opaque;
+    int32_t value, *ptr = qdev_get_prop_ptr(dev, prop);
+    unsigned int slot, fn, n;
+    Error *local_err = NULL;
+    char *str;
+
+    if (dev->realized) {
+        qdev_prop_set_after_realize(dev, name, errp);
+        return;
+    }
+
+    visit_type_str(v, &str, name, &local_err);
+    if (local_err) {
+        error_free(local_err);
+        local_err = NULL;
+        visit_type_int32(v, &value, name, &local_err);
+        if (local_err) {
+            error_propagate(errp, local_err);
+        } else if (value < -1 || value > 255) {
+            error_set(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null",
+                      "pci_devfn");
+        } else {
+            *ptr = value;
+        }
+        return;
+    }
+
+    if (sscanf(str, "%x.%x%n", &slot, &fn, &n) != 2) {
+        fn = 0;
+        if (sscanf(str, "%x%n", &slot, &n) != 1) {
+            goto invalid;
+        }
+    }
+    if (str[n] != '\0' || fn > 7 || slot > 31) {
+        goto invalid;
+    }
+    *ptr = slot << 3 | fn;
+    g_free(str);
+    return;
+
+invalid:
+    error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str);
+    g_free(str);
+}
+
+static int print_pci_devfn(DeviceState *dev, Property *prop, char *dest,
+                           size_t len)
+{
+    int32_t *ptr = qdev_get_prop_ptr(dev, prop);
+
+    if (*ptr == -1) {
+        return snprintf(dest, len, "<unset>");
+    } else {
+        return snprintf(dest, len, "%02x.%x", *ptr >> 3, *ptr & 7);
+    }
+}
+
+PropertyInfo qdev_prop_pci_devfn = {
+    .name  = "int32",
+    .legacy_name  = "pci-devfn",
+    .print = print_pci_devfn,
+    .get   = get_int32,
+    .set   = set_pci_devfn,
+};
+
+/* --- blocksize --- */
+
+static void set_blocksize(Object *obj, Visitor *v, void *opaque,
+                          const char *name, Error **errp)
+{
+    DeviceState *dev = DEVICE(obj);
+    Property *prop = opaque;
+    uint16_t value, *ptr = qdev_get_prop_ptr(dev, prop);
+    Error *local_err = NULL;
+    const int64_t min = 512;
+    const int64_t max = 32768;
+
+    if (dev->realized) {
+        qdev_prop_set_after_realize(dev, name, errp);
+        return;
+    }
+
+    visit_type_uint16(v, &value, name, &local_err);
+    if (local_err) {
+        error_propagate(errp, local_err);
+        return;
+    }
+    if (value < min || value > max) {
+        error_set(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE,
+                  dev->id?:"", name, (int64_t)value, min, max);
+        return;
+    }
+
+    /* We rely on power-of-2 blocksizes for bitmasks */
+    if ((value & (value - 1)) != 0) {
+        error_set(errp, QERR_PROPERTY_VALUE_NOT_POWER_OF_2,
+                  dev->id?:"", name, (int64_t)value);
+        return;
+    }
+
+    *ptr = value;
+}
+
+PropertyInfo qdev_prop_blocksize = {
+    .name  = "blocksize",
+    .get   = get_uint16,
+    .set   = set_blocksize,
+};
+
+/* --- pci host address --- */
+
+static void get_pci_host_devaddr(Object *obj, Visitor *v, void *opaque,
+                                 const char *name, Error **errp)
+{
+    DeviceState *dev = DEVICE(obj);
+    Property *prop = opaque;
+    PCIHostDeviceAddress *addr = qdev_get_prop_ptr(dev, prop);
+    char buffer[] = "xxxx:xx:xx.x";
+    char *p = buffer;
+    int rc = 0;
+
+    rc = snprintf(buffer, sizeof(buffer), "%04x:%02x:%02x.%d",
+                  addr->domain, addr->bus, addr->slot, addr->function);
+    assert(rc == sizeof(buffer) - 1);
+
+    visit_type_str(v, &p, name, errp);
+}
+
+/*
+ * Parse [<domain>:]<bus>:<slot>.<func>
+ *   if <domain> is not supplied, it's assumed to be 0.
+ */
+static void set_pci_host_devaddr(Object *obj, Visitor *v, void *opaque,
+                                 const char *name, Error **errp)
+{
+    DeviceState *dev = DEVICE(obj);
+    Property *prop = opaque;
+    PCIHostDeviceAddress *addr = qdev_get_prop_ptr(dev, prop);
+    Error *local_err = NULL;
+    char *str, *p;
+    char *e;
+    unsigned long val;
+    unsigned long dom = 0, bus = 0;
+    unsigned int slot = 0, func = 0;
+
+    if (dev->realized) {
+        qdev_prop_set_after_realize(dev, name, errp);
+        return;
+    }
+
+    visit_type_str(v, &str, name, &local_err);
+    if (local_err) {
+        error_propagate(errp, local_err);
+        return;
+    }
+
+    p = str;
+    val = strtoul(p, &e, 16);
+    if (e == p || *e != ':') {
+        goto inval;
+    }
+    bus = val;
+
+    p = e + 1;
+    val = strtoul(p, &e, 16);
+    if (e == p) {
+        goto inval;
+    }
+    if (*e == ':') {
+        dom = bus;
+        bus = val;
+        p = e + 1;
+        val = strtoul(p, &e, 16);
+        if (e == p) {
+            goto inval;
+        }
+    }
+    slot = val;
+
+    if (*e != '.') {
+        goto inval;
+    }
+    p = e + 1;
+    val = strtoul(p, &e, 10);
+    if (e == p) {
+        goto inval;
+    }
+    func = val;
+
+    if (dom > 0xffff || bus > 0xff || slot > 0x1f || func > 7) {
+        goto inval;
+    }
+
+    if (*e) {
+        goto inval;
+    }
+
+    addr->domain = dom;
+    addr->bus = bus;
+    addr->slot = slot;
+    addr->function = func;
+
+    g_free(str);
+    return;
+
+inval:
+    error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str);
+    g_free(str);
+}
+
+PropertyInfo qdev_prop_pci_host_devaddr = {
+    .name = "pci-host-devaddr",
+    .get = get_pci_host_devaddr,
+    .set = set_pci_host_devaddr,
+};
+
+/* --- support for array properties --- */
+
+/* Used as an opaque for the object properties we add for each
+ * array element. Note that the struct Property must be first
+ * in the struct so that a pointer to this works as the opaque
+ * for the underlying element's property hooks as well as for
+ * our own release callback.
+ */
+typedef struct {
+    struct Property prop;
+    char *propname;
+    ObjectPropertyRelease *release;
+} ArrayElementProperty;
+
+/* object property release callback for array element properties:
+ * we call the underlying element's property release hook, and
+ * then free the memory we allocated when we added the property.
+ */
+static void array_element_release(Object *obj, const char *name, void *opaque)
+{
+    ArrayElementProperty *p = opaque;
+    if (p->release) {
+        p->release(obj, name, opaque);
+    }
+    g_free(p->propname);
+    g_free(p);
+}
+
+static void set_prop_arraylen(Object *obj, Visitor *v, void *opaque,
+                              const char *name, Error **errp)
+{
+    /* Setter for the property which defines the length of a
+     * variable-sized property array. As well as actually setting the
+     * array-length field in the device struct, we have to create the
+     * array itself and dynamically add the corresponding properties.
+     */
+    DeviceState *dev = DEVICE(obj);
+    Property *prop = opaque;
+    uint32_t *alenptr = qdev_get_prop_ptr(dev, prop);
+    void **arrayptr = (void *)dev + prop->arrayoffset;
+    void *eltptr;
+    const char *arrayname;
+    int i;
+
+    if (dev->realized) {
+        qdev_prop_set_after_realize(dev, name, errp);
+        return;
+    }
+    if (*alenptr) {
+        error_setg(errp, "array size property %s may not be set more than once",
+                   name);
+        return;
+    }
+    visit_type_uint32(v, alenptr, name, errp);
+    if (error_is_set(errp)) {
+        return;
+    }
+    if (!*alenptr) {
+        return;
+    }
+
+    /* DEFINE_PROP_ARRAY guarantees that name should start with this prefix;
+     * strip it off so we can get the name of the array itself.
+     */
+    assert(strncmp(name, PROP_ARRAY_LEN_PREFIX,
+                   strlen(PROP_ARRAY_LEN_PREFIX)) == 0);
+    arrayname = name + strlen(PROP_ARRAY_LEN_PREFIX);
+
+    /* Note that it is the responsibility of the individual device's deinit
+     * to free the array proper.
+     */
+    *arrayptr = eltptr = g_malloc0(*alenptr * prop->arrayfieldsize);
+    for (i = 0; i < *alenptr; i++, eltptr += prop->arrayfieldsize) {
+        char *propname = g_strdup_printf("%s[%d]", arrayname, i);
+        ArrayElementProperty *arrayprop = g_new0(ArrayElementProperty, 1);
+        arrayprop->release = prop->arrayinfo->release;
+        arrayprop->propname = propname;
+        arrayprop->prop.info = prop->arrayinfo;
+        arrayprop->prop.name = propname;
+        /* This ugly piece of pointer arithmetic sets up the offset so
+         * that when the underlying get/set hooks call qdev_get_prop_ptr
+         * they get the right answer despite the array element not actually
+         * being inside the device struct.
+         */
+        arrayprop->prop.offset = eltptr - (void *)dev;
+        assert(qdev_get_prop_ptr(dev, &arrayprop->prop) == eltptr);
+        object_property_add(obj, propname,
+                            arrayprop->prop.info->name,
+                            arrayprop->prop.info->get,
+                            arrayprop->prop.info->set,
+                            array_element_release,
+                            arrayprop, errp);
+        if (error_is_set(errp)) {
+            return;
+        }
+    }
+}
+
+PropertyInfo qdev_prop_arraylen = {
+    .name = "uint32",
+    .get = get_uint32,
+    .set = set_prop_arraylen,
+};
+
+/* --- public helpers --- */
+
+static Property *qdev_prop_walk(Property *props, const char *name)
+{
+    if (!props) {
+        return NULL;
+    }
+    while (props->name) {
+        if (strcmp(props->name, name) == 0) {
+            return props;
+        }
+        props++;
+    }
+    return NULL;
+}
+
+static Property *qdev_prop_find(DeviceState *dev, const char *name)
+{
+    ObjectClass *class;
+    Property *prop;
+
+    /* device properties */
+    class = object_get_class(OBJECT(dev));
+    do {
+        prop = qdev_prop_walk(DEVICE_CLASS(class)->props, name);
+        if (prop) {
+            return prop;
+        }
+        class = object_class_get_parent(class);
+    } while (class != object_class_by_name(TYPE_DEVICE));
+
+    return NULL;
+}
+
+void error_set_from_qdev_prop_error(Error **errp, int ret, DeviceState *dev,
+                                    Property *prop, const char *value)
+{
+    switch (ret) {
+    case -EEXIST:
+        error_set(errp, QERR_PROPERTY_VALUE_IN_USE,
+                  object_get_typename(OBJECT(dev)), prop->name, value);
+        break;
+    default:
+    case -EINVAL:
+        error_set(errp, QERR_PROPERTY_VALUE_BAD,
+                  object_get_typename(OBJECT(dev)), prop->name, value);
+        break;
+    case -ENOENT:
+        error_set(errp, QERR_PROPERTY_VALUE_NOT_FOUND,
+                  object_get_typename(OBJECT(dev)), prop->name, value);
+        break;
+    case 0:
+        break;
+    }
+}
+
+int qdev_prop_parse(DeviceState *dev, const char *name, const char *value)
+{
+    char *legacy_name;
+    Error *err = NULL;
+
+    legacy_name = g_strdup_printf("legacy-%s", name);
+    if (object_property_get_type(OBJECT(dev), legacy_name, NULL)) {
+        object_property_parse(OBJECT(dev), value, legacy_name, &err);
+    } else {
+        object_property_parse(OBJECT(dev), value, name, &err);
+    }
+    g_free(legacy_name);
+
+    if (err) {
+        qerror_report_err(err);
+        error_free(err);
+        return -1;
+    }
+    return 0;
+}
+
+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_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_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_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_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_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_no_error(errp);
+}
+
+void qdev_prop_set_string(DeviceState *dev, const char *name, const char *value)
+{
+    Error *errp = NULL;
+    object_property_set_str(OBJECT(dev), value, name, &errp);
+    assert_no_error(errp);
+}
+
+void qdev_prop_set_macaddr(DeviceState *dev, const char *name, uint8_t *value)
+{
+    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_no_error(errp);
+}
+
+void qdev_prop_set_enum(DeviceState *dev, const char *name, int value)
+{
+    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_no_error(errp);
+}
+
+void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value)
+{
+    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;
+}
+
+static QTAILQ_HEAD(, GlobalProperty) global_props =
+        QTAILQ_HEAD_INITIALIZER(global_props);
+
+void qdev_prop_register_global(GlobalProperty *prop)
+{
+    QTAILQ_INSERT_TAIL(&global_props, prop, next);
+}
+
+void qdev_prop_register_global_list(GlobalProperty *props)
+{
+    int i;
+
+    for (i = 0; props[i].driver != NULL; i++) {
+        qdev_prop_register_global(props+i);
+    }
+}
+
+void qdev_prop_set_globals(DeviceState *dev)
+{
+    ObjectClass *class = object_get_class(OBJECT(dev));
+
+    do {
+        GlobalProperty *prop;
+        QTAILQ_FOREACH(prop, &global_props, next) {
+            if (strcmp(object_class_get_name(class), prop->driver) != 0) {
+                continue;
+            }
+            if (qdev_prop_parse(dev, prop->property, prop->value) != 0) {
+                exit(1);
+            }
+        }
+        class = object_class_get_parent(class);
+    } while (class);
+}
diff --git a/hw/core/qdev.c b/hw/core/qdev.c
new file mode 100644 (file)
index 0000000..e2bb37d
--- /dev/null
@@ -0,0 +1,882 @@
+/*
+ *  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/>.
+ */
+
+/* The theory here is that it should be possible to create a machine without
+   knowledge of specific devices.  Historically board init routines have
+   passed a bunch of arguments to each device, requiring the board know
+   exactly which device it is dealing with.  This file provides an abstract
+   API for device configuration and initialization.  Devices will generally
+   inherit from a particular bus (e.g. PCI or I2C) rather than
+   this API directly.  */
+
+#include "hw/qdev.h"
+#include "sysemu/sysemu.h"
+#include "qapi/error.h"
+#include "qapi/qmp/qerror.h"
+#include "qapi/visitor.h"
+#include "qapi/qmp/qjson.h"
+#include "monitor/monitor.h"
+
+int qdev_hotplug = 0;
+static bool qdev_hot_added = false;
+static bool qdev_hot_removed = false;
+
+const VMStateDescription *qdev_get_vmsd(DeviceState *dev)
+{
+    DeviceClass *dc = DEVICE_GET_CLASS(dev);
+    return dc->vmsd;
+}
+
+const char *qdev_fw_name(DeviceState *dev)
+{
+    DeviceClass *dc = DEVICE_GET_CLASS(dev);
+
+    if (dc->fw_name) {
+        return dc->fw_name;
+    }
+
+    return object_get_typename(OBJECT(dev));
+}
+
+static void qdev_property_add_legacy(DeviceState *dev, Property *prop,
+                                     Error **errp);
+
+static void bus_remove_child(BusState *bus, DeviceState *child)
+{
+    BusChild *kid;
+
+    QTAILQ_FOREACH(kid, &bus->children, sibling) {
+        if (kid->child == child) {
+            char name[32];
+
+            snprintf(name, sizeof(name), "child[%d]", kid->index);
+            QTAILQ_REMOVE(&bus->children, kid, sibling);
+
+            /* This gives back ownership of kid->child back to us.  */
+            object_property_del(OBJECT(bus), name, NULL);
+            object_unref(OBJECT(kid->child));
+            g_free(kid);
+            return;
+        }
+    }
+}
+
+static void bus_add_child(BusState *bus, DeviceState *child)
+{
+    char name[32];
+    BusChild *kid = g_malloc0(sizeof(*kid));
+
+    if (qdev_hotplug) {
+        assert(bus->allow_hotplug);
+    }
+
+    kid->index = bus->max_index++;
+    kid->child = child;
+    object_ref(OBJECT(kid->child));
+
+    QTAILQ_INSERT_HEAD(&bus->children, kid, sibling);
+
+    /* This transfers ownership of kid->child to the property.  */
+    snprintf(name, sizeof(name), "child[%d]", kid->index);
+    object_property_add_link(OBJECT(bus), name,
+                             object_get_typename(OBJECT(child)),
+                             (Object **)&kid->child,
+                             NULL);
+}
+
+void qdev_set_parent_bus(DeviceState *dev, BusState *bus)
+{
+    dev->parent_bus = bus;
+    object_ref(OBJECT(bus));
+    bus_add_child(bus, dev);
+}
+
+/* Create a new device.  This only initializes the device state structure
+   and allows properties to be set.  qdev_init should be called to
+   initialize the actual device emulation.  */
+DeviceState *qdev_create(BusState *bus, const char *name)
+{
+    DeviceState *dev;
+
+    dev = qdev_try_create(bus, name);
+    if (!dev) {
+        if (bus) {
+            error_report("Unknown device '%s' for bus '%s'", name,
+                         object_get_typename(OBJECT(bus)));
+        } else {
+            error_report("Unknown device '%s' for default sysbus", name);
+        }
+        abort();
+    }
+
+    return dev;
+}
+
+DeviceState *qdev_try_create(BusState *bus, const char *type)
+{
+    DeviceState *dev;
+
+    if (object_class_by_name(type) == NULL) {
+        return NULL;
+    }
+    dev = DEVICE(object_new(type));
+    if (!dev) {
+        return NULL;
+    }
+
+    if (!bus) {
+        bus = sysbus_get_default();
+    }
+
+    qdev_set_parent_bus(dev, bus);
+    object_unref(OBJECT(dev));
+    return dev;
+}
+
+/* Initialize a device.  Device properties should be set before calling
+   this function.  IRQs and MMIO regions should be connected/mapped after
+   calling this function.
+   On failure, destroy the device and return negative value.
+   Return 0 on success.  */
+int qdev_init(DeviceState *dev)
+{
+    Error *local_err = NULL;
+
+    assert(!dev->realized);
+
+    object_property_set_bool(OBJECT(dev), true, "realized", &local_err);
+    if (local_err != NULL) {
+        error_free(local_err);
+        qdev_free(dev);
+        return -1;
+    }
+    return 0;
+}
+
+static void device_realize(DeviceState *dev, Error **err)
+{
+    DeviceClass *dc = DEVICE_GET_CLASS(dev);
+
+    if (dc->init) {
+        int rc = dc->init(dev);
+        if (rc < 0) {
+            error_setg(err, "Device initialization failed.");
+            return;
+        }
+    }
+}
+
+void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id,
+                                 int required_for_version)
+{
+    assert(!dev->realized);
+    dev->instance_id_alias = alias_id;
+    dev->alias_required_for_version = required_for_version;
+}
+
+void qdev_unplug(DeviceState *dev, Error **errp)
+{
+    DeviceClass *dc = DEVICE_GET_CLASS(dev);
+
+    if (!dev->parent_bus->allow_hotplug) {
+        error_set(errp, QERR_BUS_NO_HOTPLUG, dev->parent_bus->name);
+        return;
+    }
+    assert(dc->unplug != NULL);
+
+    qdev_hot_removed = true;
+
+    if (dc->unplug(dev) < 0) {
+        error_set(errp, QERR_UNDEFINED_ERROR);
+        return;
+    }
+}
+
+static int qdev_reset_one(DeviceState *dev, void *opaque)
+{
+    device_reset(dev);
+
+    return 0;
+}
+
+static int qbus_reset_one(BusState *bus, void *opaque)
+{
+    BusClass *bc = BUS_GET_CLASS(bus);
+    if (bc->reset) {
+        return bc->reset(bus);
+    }
+    return 0;
+}
+
+void qdev_reset_all(DeviceState *dev)
+{
+    qdev_walk_children(dev, qdev_reset_one, qbus_reset_one, NULL);
+}
+
+void qbus_reset_all(BusState *bus)
+{
+    qbus_walk_children(bus, qdev_reset_one, qbus_reset_one, NULL);
+}
+
+void qbus_reset_all_fn(void *opaque)
+{
+    BusState *bus = opaque;
+    qbus_reset_all(bus);
+}
+
+/* can be used as ->unplug() callback for the simple cases */
+int qdev_simple_unplug_cb(DeviceState *dev)
+{
+    /* just zap it */
+    qdev_free(dev);
+    return 0;
+}
+
+
+/* Like qdev_init(), but terminate program via error_report() instead of
+   returning an error value.  This is okay during machine creation.
+   Don't use for hotplug, because there callers need to recover from
+   failure.  Exception: if you know the device's init() callback can't
+   fail, then qdev_init_nofail() can't fail either, and is therefore
+   usable even then.  But relying on the device implementation that
+   way is somewhat unclean, and best avoided.  */
+void qdev_init_nofail(DeviceState *dev)
+{
+    const char *typename = object_get_typename(OBJECT(dev));
+
+    if (qdev_init(dev) < 0) {
+        error_report("Initialization of device %s failed", typename);
+        exit(1);
+    }
+}
+
+/* Unlink device from bus and free the structure.  */
+void qdev_free(DeviceState *dev)
+{
+    object_unparent(OBJECT(dev));
+}
+
+void qdev_machine_creation_done(void)
+{
+    /*
+     * ok, initial machine setup is done, starting from now we can
+     * only create hotpluggable devices
+     */
+    qdev_hotplug = 1;
+}
+
+bool qdev_machine_modified(void)
+{
+    return qdev_hot_added || qdev_hot_removed;
+}
+
+BusState *qdev_get_parent_bus(DeviceState *dev)
+{
+    return dev->parent_bus;
+}
+
+void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n)
+{
+    dev->gpio_in = qemu_extend_irqs(dev->gpio_in, dev->num_gpio_in, handler,
+                                        dev, n);
+    dev->num_gpio_in += n;
+}
+
+void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n)
+{
+    assert(dev->num_gpio_out == 0);
+    dev->num_gpio_out = n;
+    dev->gpio_out = pins;
+}
+
+qemu_irq qdev_get_gpio_in(DeviceState *dev, int n)
+{
+    assert(n >= 0 && n < dev->num_gpio_in);
+    return dev->gpio_in[n];
+}
+
+void qdev_connect_gpio_out(DeviceState * dev, int n, qemu_irq pin)
+{
+    assert(n >= 0 && n < dev->num_gpio_out);
+    dev->gpio_out[n] = pin;
+}
+
+BusState *qdev_get_child_bus(DeviceState *dev, const char *name)
+{
+    BusState *bus;
+
+    QLIST_FOREACH(bus, &dev->child_bus, sibling) {
+        if (strcmp(name, bus->name) == 0) {
+            return bus;
+        }
+    }
+    return NULL;
+}
+
+int qbus_walk_children(BusState *bus, qdev_walkerfn *devfn,
+                       qbus_walkerfn *busfn, void *opaque)
+{
+    BusChild *kid;
+    int err;
+
+    if (busfn) {
+        err = busfn(bus, opaque);
+        if (err) {
+            return err;
+        }
+    }
+
+    QTAILQ_FOREACH(kid, &bus->children, sibling) {
+        err = qdev_walk_children(kid->child, devfn, busfn, opaque);
+        if (err < 0) {
+            return err;
+        }
+    }
+
+    return 0;
+}
+
+int qdev_walk_children(DeviceState *dev, qdev_walkerfn *devfn,
+                       qbus_walkerfn *busfn, void *opaque)
+{
+    BusState *bus;
+    int err;
+
+    if (devfn) {
+        err = devfn(dev, opaque);
+        if (err) {
+            return err;
+        }
+    }
+
+    QLIST_FOREACH(bus, &dev->child_bus, sibling) {
+        err = qbus_walk_children(bus, devfn, busfn, opaque);
+        if (err < 0) {
+            return err;
+        }
+    }
+
+    return 0;
+}
+
+DeviceState *qdev_find_recursive(BusState *bus, const char *id)
+{
+    BusChild *kid;
+    DeviceState *ret;
+    BusState *child;
+
+    QTAILQ_FOREACH(kid, &bus->children, sibling) {
+        DeviceState *dev = kid->child;
+
+        if (dev->id && strcmp(dev->id, id) == 0) {
+            return dev;
+        }
+
+        QLIST_FOREACH(child, &dev->child_bus, sibling) {
+            ret = qdev_find_recursive(child, id);
+            if (ret) {
+                return ret;
+            }
+        }
+    }
+    return NULL;
+}
+
+static void qbus_realize(BusState *bus, DeviceState *parent, const char *name)
+{
+    const char *typename = object_get_typename(OBJECT(bus));
+    char *buf;
+    int i,len;
+
+    bus->parent = parent;
+
+    if (name) {
+        bus->name = g_strdup(name);
+    } else if (bus->parent && bus->parent->id) {
+        /* parent device has id -> use it for bus name */
+        len = strlen(bus->parent->id) + 16;
+        buf = g_malloc(len);
+        snprintf(buf, len, "%s.%d", bus->parent->id, bus->parent->num_child_bus);
+        bus->name = buf;
+    } else {
+        /* no id -> use lowercase bus type for bus name */
+        len = strlen(typename) + 16;
+        buf = g_malloc(len);
+        len = snprintf(buf, len, "%s.%d", typename,
+                       bus->parent ? bus->parent->num_child_bus : 0);
+        for (i = 0; i < len; i++)
+            buf[i] = qemu_tolower(buf[i]);
+        bus->name = buf;
+    }
+
+    if (bus->parent) {
+        QLIST_INSERT_HEAD(&bus->parent->child_bus, bus, sibling);
+        bus->parent->num_child_bus++;
+        object_property_add_child(OBJECT(bus->parent), bus->name, OBJECT(bus), NULL);
+        object_unref(OBJECT(bus));
+    } else if (bus != sysbus_get_default()) {
+        /* TODO: once all bus devices are qdevified,
+           only reset handler for main_system_bus should be registered here. */
+        qemu_register_reset(qbus_reset_all_fn, bus);
+    }
+}
+
+static void bus_unparent(Object *obj)
+{
+    BusState *bus = BUS(obj);
+    BusChild *kid;
+
+    while ((kid = QTAILQ_FIRST(&bus->children)) != NULL) {
+        DeviceState *dev = kid->child;
+        qdev_free(dev);
+    }
+    if (bus->parent) {
+        QLIST_REMOVE(bus, sibling);
+        bus->parent->num_child_bus--;
+        bus->parent = NULL;
+    } else {
+        assert(bus != sysbus_get_default()); /* main_system_bus is never freed */
+        qemu_unregister_reset(qbus_reset_all_fn, bus);
+    }
+}
+
+void qbus_create_inplace(void *bus, const char *typename,
+                         DeviceState *parent, const char *name)
+{
+    object_initialize(bus, typename);
+    qbus_realize(bus, parent, name);
+}
+
+BusState *qbus_create(const char *typename, DeviceState *parent, const char *name)
+{
+    BusState *bus;
+
+    bus = BUS(object_new(typename));
+    qbus_realize(bus, parent, name);
+
+    return bus;
+}
+
+void qbus_free(BusState *bus)
+{
+    object_unparent(OBJECT(bus));
+}
+
+static char *bus_get_fw_dev_path(BusState *bus, DeviceState *dev)
+{
+    BusClass *bc = BUS_GET_CLASS(bus);
+
+    if (bc->get_fw_dev_path) {
+        return bc->get_fw_dev_path(dev);
+    }
+
+    return NULL;
+}
+
+static int qdev_get_fw_dev_path_helper(DeviceState *dev, char *p, int size)
+{
+    int l = 0;
+
+    if (dev && dev->parent_bus) {
+        char *d;
+        l = qdev_get_fw_dev_path_helper(dev->parent_bus->parent, p, size);
+        d = bus_get_fw_dev_path(dev->parent_bus, dev);
+        if (d) {
+            l += snprintf(p + l, size - l, "%s", d);
+            g_free(d);
+        } else {
+            l += snprintf(p + l, size - l, "%s", object_get_typename(OBJECT(dev)));
+        }
+    }
+    l += snprintf(p + l , size - l, "/");
+
+    return l;
+}
+
+char* qdev_get_fw_dev_path(DeviceState *dev)
+{
+    char path[128];
+    int l;
+
+    l = qdev_get_fw_dev_path_helper(dev, path, 128);
+
+    path[l-1] = '\0';
+
+    return g_strdup(path);
+}
+
+char *qdev_get_dev_path(DeviceState *dev)
+{
+    BusClass *bc;
+
+    if (!dev || !dev->parent_bus) {
+        return NULL;
+    }
+
+    bc = BUS_GET_CLASS(dev->parent_bus);
+    if (bc->get_dev_path) {
+        return bc->get_dev_path(dev);
+    }
+
+    return NULL;
+}
+
+/**
+ * Legacy property handling
+ */
+
+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];
+    char *ptr = buffer;
+
+    prop->info->print(dev, prop, buffer, sizeof(buffer));
+    visit_type_str(v, &ptr, name, errp);
+}
+
+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;
+    int ret;
+
+    if (dev->realized) {
+        qdev_prop_set_after_realize(dev, name, errp);
+        return;
+    }
+
+    visit_type_str(v, &ptr, name, &local_err);
+    if (local_err) {
+        error_propagate(errp, local_err);
+        return;
+    }
+
+    ret = prop->info->parse(dev, prop, ptr);
+    error_set_from_qdev_prop_error(errp, ret, dev, prop, ptr);
+    g_free(ptr);
+}
+
+/**
+ * @qdev_add_legacy_property - adds a legacy property
+ *
+ * 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 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;
+
+    /* Register pointer properties as legacy properties */
+    if (!prop->info->print && !prop->info->parse &&
+        (prop->info->set || prop->info->get)) {
+        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 : prop->info->get,
+                        prop->info->parse ? qdev_set_legacy_property : prop->info->set,
+                        NULL,
+                        prop, errp);
+
+    g_free(type);
+    g_free(name);
+}
+
+/**
+ * @qdev_property_add_static - add a @Property to a device.
+ *
+ * Static properties access data in a struct.  The actual type of the
+ * property and the field depends on the property type.
+ */
+void qdev_property_add_static(DeviceState *dev, Property *prop,
+                              Error **errp)
+{
+    Error *local_err = NULL;
+    Object *obj = OBJECT(dev);
+
+    /*
+     * TODO qdev_prop_ptr does not have getters or setters.  It must
+     * go now that it can be replaced with links.  The test should be
+     * removed along with it: all static properties are read/write.
+     */
+    if (!prop->info->get && !prop->info->set) {
+        return;
+    }
+
+    object_property_add(obj, prop->name, prop->info->name,
+                        prop->info->get, prop->info->set,
+                        prop->info->release,
+                        prop, &local_err);
+
+    if (local_err) {
+        error_propagate(errp, local_err);
+        return;
+    }
+    if (prop->qtype == QTYPE_NONE) {
+        return;
+    }
+
+    if (prop->qtype == QTYPE_QBOOL) {
+        object_property_set_bool(obj, prop->defval, prop->name, &local_err);
+    } else if (prop->info->enum_table) {
+        object_property_set_str(obj, prop->info->enum_table[prop->defval],
+                                prop->name, &local_err);
+    } else if (prop->qtype == QTYPE_QINT) {
+        object_property_set_int(obj, prop->defval, prop->name, &local_err);
+    }
+    assert_no_error(local_err);
+}
+
+static bool device_get_realized(Object *obj, Error **err)
+{
+    DeviceState *dev = DEVICE(obj);
+    return dev->realized;
+}
+
+static void device_set_realized(Object *obj, bool value, Error **err)
+{
+    DeviceState *dev = DEVICE(obj);
+    DeviceClass *dc = DEVICE_GET_CLASS(dev);
+    Error *local_err = NULL;
+
+    if (value && !dev->realized) {
+        if (dc->realize) {
+            dc->realize(dev, &local_err);
+        }
+
+        if (!obj->parent && local_err == NULL) {
+            static int unattached_count;
+            gchar *name = g_strdup_printf("device[%d]", unattached_count++);
+
+            object_property_add_child(container_get(qdev_get_machine(),
+                                                    "/unattached"),
+                                      name, obj, &local_err);
+            g_free(name);
+        }
+
+        if (qdev_get_vmsd(dev) && local_err == NULL) {
+            vmstate_register_with_alias_id(dev, -1, qdev_get_vmsd(dev), dev,
+                                           dev->instance_id_alias,
+                                           dev->alias_required_for_version);
+        }
+        if (dev->hotplugged && local_err == NULL) {
+            device_reset(dev);
+        }
+    } else if (!value && dev->realized) {
+        if (dc->unrealize) {
+            dc->unrealize(dev, &local_err);
+        }
+    }
+
+    if (local_err != NULL) {
+        error_propagate(err, local_err);
+        return;
+    }
+
+    dev->realized = value;
+}
+
+static void device_initfn(Object *obj)
+{
+    DeviceState *dev = DEVICE(obj);
+    ObjectClass *class;
+    Property *prop;
+    Error *err = NULL;
+
+    if (qdev_hotplug) {
+        dev->hotplugged = 1;
+        qdev_hot_added = true;
+    }
+
+    dev->instance_id_alias = -1;
+    dev->realized = false;
+
+    object_property_add_bool(obj, "realized",
+                             device_get_realized, device_set_realized, NULL);
+
+    class = object_get_class(OBJECT(dev));
+    do {
+        for (prop = DEVICE_CLASS(class)->props; prop && prop->name; prop++) {
+            qdev_property_add_legacy(dev, prop, &err);
+            assert_no_error(err);
+            qdev_property_add_static(dev, prop, &err);
+            assert_no_error(err);
+        }
+        class = object_class_get_parent(class);
+    } while (class != object_class_by_name(TYPE_DEVICE));
+    qdev_prop_set_globals(dev);
+
+    object_property_add_link(OBJECT(dev), "parent_bus", TYPE_BUS,
+                             (Object **)&dev->parent_bus, &err);
+    assert_no_error(err);
+}
+
+/* Unlink device from bus and free the structure.  */
+static void device_finalize(Object *obj)
+{
+    DeviceState *dev = DEVICE(obj);
+    if (dev->opts) {
+        qemu_opts_del(dev->opts);
+    }
+}
+
+static void device_class_base_init(ObjectClass *class, void *data)
+{
+    DeviceClass *klass = DEVICE_CLASS(class);
+
+    /* We explicitly look up properties in the superclasses,
+     * so do not propagate them to the subclasses.
+     */
+    klass->props = NULL;
+}
+
+static void device_unparent(Object *obj)
+{
+    DeviceState *dev = DEVICE(obj);
+    DeviceClass *dc = DEVICE_GET_CLASS(dev);
+    BusState *bus;
+    QObject *event_data;
+    bool have_realized = dev->realized;
+
+    while (dev->num_child_bus) {
+        bus = QLIST_FIRST(&dev->child_bus);
+        qbus_free(bus);
+    }
+    if (dev->realized) {
+        if (qdev_get_vmsd(dev)) {
+            vmstate_unregister(dev, qdev_get_vmsd(dev), dev);
+        }
+        if (dc->exit) {
+            dc->exit(dev);
+        }
+    }
+    if (dev->parent_bus) {
+        bus_remove_child(dev->parent_bus, dev);
+        object_unref(OBJECT(dev->parent_bus));
+        dev->parent_bus = NULL;
+    }
+
+    /* Only send event if the device had been completely realized */
+    if (have_realized) {
+        gchar *path = object_get_canonical_path(OBJECT(dev));
+
+        if (dev->id) {
+            event_data = qobject_from_jsonf("{ 'device': %s, 'path': %s }",
+                                            dev->id, path);
+        } else {
+            event_data = qobject_from_jsonf("{ 'path': %s }", path);
+        }
+        monitor_protocol_event(QEVENT_DEVICE_DELETED, event_data);
+        qobject_decref(event_data);
+        g_free(path);
+    }
+}
+
+static void device_class_init(ObjectClass *class, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(class);
+
+    class->unparent = device_unparent;
+    dc->realize = device_realize;
+}
+
+void device_reset(DeviceState *dev)
+{
+    DeviceClass *klass = DEVICE_GET_CLASS(dev);
+
+    if (klass->reset) {
+        klass->reset(dev);
+    }
+}
+
+Object *qdev_get_machine(void)
+{
+    static Object *dev;
+
+    if (dev == NULL) {
+        dev = container_get(object_get_root(), "/machine");
+    }
+
+    return dev;
+}
+
+static const TypeInfo device_type_info = {
+    .name = TYPE_DEVICE,
+    .parent = TYPE_OBJECT,
+    .instance_size = sizeof(DeviceState),
+    .instance_init = device_initfn,
+    .instance_finalize = device_finalize,
+    .class_base_init = device_class_base_init,
+    .class_init = device_class_init,
+    .abstract = true,
+    .class_size = sizeof(DeviceClass),
+};
+
+static void qbus_initfn(Object *obj)
+{
+    BusState *bus = BUS(obj);
+
+    QTAILQ_INIT(&bus->children);
+}
+
+static void bus_class_init(ObjectClass *class, void *data)
+{
+    class->unparent = bus_unparent;
+}
+
+static void qbus_finalize(Object *obj)
+{
+    BusState *bus = BUS(obj);
+
+    g_free((char *)bus->name);
+}
+
+static const TypeInfo bus_info = {
+    .name = TYPE_BUS,
+    .parent = TYPE_OBJECT,
+    .instance_size = sizeof(BusState),
+    .abstract = true,
+    .class_size = sizeof(BusClass),
+    .instance_init = qbus_initfn,
+    .instance_finalize = qbus_finalize,
+    .class_init = bus_class_init,
+};
+
+static void qdev_register_types(void)
+{
+    type_register_static(&bus_info);
+    type_register_static(&device_type_info);
+}
+
+type_init(qdev_register_types)
diff --git a/hw/core/stream.c b/hw/core/stream.c
new file mode 100644 (file)
index 0000000..a07d6a5
--- /dev/null
@@ -0,0 +1,23 @@
+#include "hw/stream.h"
+
+void
+stream_push(StreamSlave *sink, uint8_t *buf, size_t len, uint32_t *app)
+{
+    StreamSlaveClass *k =  STREAM_SLAVE_GET_CLASS(sink);
+
+    k->push(sink, buf, len, app);
+}
+
+static const TypeInfo stream_slave_info = {
+    .name          = TYPE_STREAM_SLAVE,
+    .parent        = TYPE_INTERFACE,
+    .class_size = sizeof(StreamSlaveClass),
+};
+
+
+static void stream_slave_register_types(void)
+{
+    type_register_static(&stream_slave_info);
+}
+
+type_init(stream_slave_register_types)
diff --git a/hw/core/sysbus.c b/hw/core/sysbus.c
new file mode 100644 (file)
index 0000000..9004d8c
--- /dev/null
@@ -0,0 +1,301 @@
+/*
+ *  System (CPU) Bus device support code
+ *
+ *  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 "hw/sysbus.h"
+#include "monitor/monitor.h"
+#include "exec/address-spaces.h"
+
+static void sysbus_dev_print(Monitor *mon, DeviceState *dev, int indent);
+static char *sysbus_get_fw_dev_path(DeviceState *dev);
+
+static void system_bus_class_init(ObjectClass *klass, void *data)
+{
+    BusClass *k = BUS_CLASS(klass);
+
+    k->print_dev = sysbus_dev_print;
+    k->get_fw_dev_path = sysbus_get_fw_dev_path;
+}
+
+static const TypeInfo system_bus_info = {
+    .name = TYPE_SYSTEM_BUS,
+    .parent = TYPE_BUS,
+    .instance_size = sizeof(BusState),
+    .class_init = system_bus_class_init,
+};
+
+void sysbus_connect_irq(SysBusDevice *dev, int n, qemu_irq irq)
+{
+    assert(n >= 0 && n < dev->num_irq);
+    dev->irqs[n] = NULL;
+    if (dev->irqp[n]) {
+        *dev->irqp[n] = irq;
+    }
+}
+
+static void sysbus_mmio_map_common(SysBusDevice *dev, int n, hwaddr addr,
+                                   bool may_overlap, unsigned priority)
+{
+    assert(n >= 0 && n < dev->num_mmio);
+
+    if (dev->mmio[n].addr == addr) {
+        /* ??? region already mapped here.  */
+        return;
+    }
+    if (dev->mmio[n].addr != (hwaddr)-1) {
+        /* Unregister previous mapping.  */
+        memory_region_del_subregion(get_system_memory(), dev->mmio[n].memory);
+    }
+    dev->mmio[n].addr = addr;
+    if (may_overlap) {
+        memory_region_add_subregion_overlap(get_system_memory(),
+                                            addr,
+                                            dev->mmio[n].memory,
+                                            priority);
+    }
+    else {
+        memory_region_add_subregion(get_system_memory(),
+                                    addr,
+                                    dev->mmio[n].memory);
+    }
+}
+
+void sysbus_mmio_map(SysBusDevice *dev, int n, hwaddr addr)
+{
+    sysbus_mmio_map_common(dev, n, addr, false, 0);
+}
+
+void sysbus_mmio_map_overlap(SysBusDevice *dev, int n, hwaddr addr,
+                             unsigned priority)
+{
+    sysbus_mmio_map_common(dev, n, addr, true, priority);
+}
+
+/* Request an IRQ source.  The actual IRQ object may be populated later.  */
+void sysbus_init_irq(SysBusDevice *dev, qemu_irq *p)
+{
+    int n;
+
+    assert(dev->num_irq < QDEV_MAX_IRQ);
+    n = dev->num_irq++;
+    dev->irqp[n] = p;
+}
+
+/* Pass IRQs from a target device.  */
+void sysbus_pass_irq(SysBusDevice *dev, SysBusDevice *target)
+{
+    int i;
+    assert(dev->num_irq == 0);
+    dev->num_irq = target->num_irq;
+    for (i = 0; i < dev->num_irq; i++) {
+        dev->irqp[i] = target->irqp[i];
+    }
+}
+
+void sysbus_init_mmio(SysBusDevice *dev, MemoryRegion *memory)
+{
+    int n;
+
+    assert(dev->num_mmio < QDEV_MAX_MMIO);
+    n = dev->num_mmio++;
+    dev->mmio[n].addr = -1;
+    dev->mmio[n].memory = memory;
+}
+
+MemoryRegion *sysbus_mmio_get_region(SysBusDevice *dev, int n)
+{
+    return dev->mmio[n].memory;
+}
+
+void sysbus_init_ioports(SysBusDevice *dev, pio_addr_t ioport, pio_addr_t size)
+{
+    pio_addr_t i;
+
+    for (i = 0; i < size; i++) {
+        assert(dev->num_pio < QDEV_MAX_PIO);
+        dev->pio[dev->num_pio++] = ioport++;
+    }
+}
+
+static int sysbus_device_init(DeviceState *dev)
+{
+    SysBusDevice *sd = SYS_BUS_DEVICE(dev);
+    SysBusDeviceClass *sbc = SYS_BUS_DEVICE_GET_CLASS(sd);
+
+    if (!sbc->init) {
+        return 0;
+    }
+    return sbc->init(sd);
+}
+
+DeviceState *sysbus_create_varargs(const char *name,
+                                   hwaddr addr, ...)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+    va_list va;
+    qemu_irq irq;
+    int n;
+
+    dev = qdev_create(NULL, name);
+    s = SYS_BUS_DEVICE(dev);
+    qdev_init_nofail(dev);
+    if (addr != (hwaddr)-1) {
+        sysbus_mmio_map(s, 0, addr);
+    }
+    va_start(va, addr);
+    n = 0;
+    while (1) {
+        irq = va_arg(va, qemu_irq);
+        if (!irq) {
+            break;
+        }
+        sysbus_connect_irq(s, n, irq);
+        n++;
+    }
+    va_end(va);
+    return dev;
+}
+
+DeviceState *sysbus_try_create_varargs(const char *name,
+                                       hwaddr addr, ...)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+    va_list va;
+    qemu_irq irq;
+    int n;
+
+    dev = qdev_try_create(NULL, name);
+    if (!dev) {
+        return NULL;
+    }
+    s = SYS_BUS_DEVICE(dev);
+    qdev_init_nofail(dev);
+    if (addr != (hwaddr)-1) {
+        sysbus_mmio_map(s, 0, addr);
+    }
+    va_start(va, addr);
+    n = 0;
+    while (1) {
+        irq = va_arg(va, qemu_irq);
+        if (!irq) {
+            break;
+        }
+        sysbus_connect_irq(s, n, irq);
+        n++;
+    }
+    va_end(va);
+    return dev;
+}
+
+static void sysbus_dev_print(Monitor *mon, DeviceState *dev, int indent)
+{
+    SysBusDevice *s = SYS_BUS_DEVICE(dev);
+    hwaddr size;
+    int i;
+
+    monitor_printf(mon, "%*sirq %d\n", indent, "", s->num_irq);
+    for (i = 0; i < s->num_mmio; i++) {
+        size = memory_region_size(s->mmio[i].memory);
+        monitor_printf(mon, "%*smmio " TARGET_FMT_plx "/" TARGET_FMT_plx "\n",
+                       indent, "", s->mmio[i].addr, size);
+    }
+}
+
+static char *sysbus_get_fw_dev_path(DeviceState *dev)
+{
+    SysBusDevice *s = SYS_BUS_DEVICE(dev);
+    char path[40];
+    int off;
+
+    off = snprintf(path, sizeof(path), "%s", qdev_fw_name(dev));
+
+    if (s->num_mmio) {
+        snprintf(path + off, sizeof(path) - off, "@"TARGET_FMT_plx,
+                 s->mmio[0].addr);
+    } else if (s->num_pio) {
+        snprintf(path + off, sizeof(path) - off, "@i%04x", s->pio[0]);
+    }
+
+    return g_strdup(path);
+}
+
+void sysbus_add_io(SysBusDevice *dev, hwaddr addr,
+                       MemoryRegion *mem)
+{
+    memory_region_add_subregion(get_system_io(), addr, mem);
+}
+
+void sysbus_del_io(SysBusDevice *dev, MemoryRegion *mem)
+{
+    memory_region_del_subregion(get_system_io(), mem);
+}
+
+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_type = TYPE_SYSTEM_BUS;
+}
+
+static const 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,
+};
+
+/* This is a nasty hack to allow passing a NULL bus to qdev_create.  */
+static BusState *main_system_bus;
+
+static void main_system_bus_create(void)
+{
+    /* assign main_system_bus before qbus_create_inplace()
+     * in order to make "if (bus != sysbus_get_default())" work */
+    main_system_bus = g_malloc0(system_bus_info.instance_size);
+    qbus_create_inplace(main_system_bus, TYPE_SYSTEM_BUS, NULL,
+                        "main-system-bus");
+    OBJECT(main_system_bus)->free = g_free;
+    object_property_add_child(container_get(qdev_get_machine(),
+                                            "/unattached"),
+                              "sysbus", OBJECT(main_system_bus), NULL);
+}
+
+BusState *sysbus_get_default(void)
+{
+    if (!main_system_bus) {
+        main_system_bus_create();
+    }
+    return main_system_bus;
+}
+
+static void sysbus_register_types(void)
+{
+    type_register_static(&system_bus_info);
+    type_register_static(&sysbus_device_type_info);
+}
+
+type_init(sysbus_register_types)
diff --git a/hw/core/uboot_image.h b/hw/core/uboot_image.h
new file mode 100644 (file)
index 0000000..9fc2760
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * (C) Copyright 2000-2005
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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/>.
+ *
+ ********************************************************************
+ * NOTE: This header file defines an interface to U-Boot. Including
+ * this (unmodified) header file in another file is considered normal
+ * use of U-Boot, and does *not* fall under the heading of "derived
+ * work".
+ ********************************************************************
+ */
+
+#ifndef __UBOOT_IMAGE_H__
+#define __UBOOT_IMAGE_H__
+
+/*
+ * Operating System Codes
+ */
+#define IH_OS_INVALID          0       /* Invalid OS   */
+#define IH_OS_OPENBSD          1       /* OpenBSD      */
+#define IH_OS_NETBSD           2       /* NetBSD       */
+#define IH_OS_FREEBSD          3       /* FreeBSD      */
+#define IH_OS_4_4BSD           4       /* 4.4BSD       */
+#define IH_OS_LINUX            5       /* Linux        */
+#define IH_OS_SVR4             6       /* SVR4         */
+#define IH_OS_ESIX             7       /* Esix         */
+#define IH_OS_SOLARIS          8       /* Solaris      */
+#define IH_OS_IRIX             9       /* Irix         */
+#define IH_OS_SCO              10      /* SCO          */
+#define IH_OS_DELL             11      /* Dell         */
+#define IH_OS_NCR              12      /* NCR          */
+#define IH_OS_LYNXOS           13      /* LynxOS       */
+#define IH_OS_VXWORKS          14      /* VxWorks      */
+#define IH_OS_PSOS             15      /* pSOS         */
+#define IH_OS_QNX              16      /* QNX          */
+#define IH_OS_U_BOOT           17      /* Firmware     */
+#define IH_OS_RTEMS            18      /* RTEMS        */
+#define IH_OS_ARTOS            19      /* ARTOS        */
+#define IH_OS_UNITY            20      /* Unity OS     */
+
+/*
+ * CPU Architecture Codes (supported by Linux)
+ */
+#define IH_CPU_INVALID         0       /* Invalid CPU  */
+#define IH_CPU_ALPHA           1       /* Alpha        */
+#define IH_CPU_ARM             2       /* ARM          */
+#define IH_CPU_I386            3       /* Intel x86    */
+#define IH_CPU_IA64            4       /* IA64         */
+#define IH_CPU_MIPS            5       /* MIPS         */
+#define IH_CPU_MIPS64          6       /* MIPS  64 Bit */
+#define IH_CPU_PPC             7       /* PowerPC      */
+#define IH_CPU_S390            8       /* IBM S390     */
+#define IH_CPU_SH              9       /* SuperH       */
+#define IH_CPU_SPARC           10      /* Sparc        */
+#define IH_CPU_SPARC64         11      /* Sparc 64 Bit */
+#define IH_CPU_M68K            12      /* M68K         */
+#define IH_CPU_NIOS            13      /* Nios-32      */
+#define IH_CPU_MICROBLAZE      14      /* MicroBlaze   */
+#define IH_CPU_NIOS2           15      /* Nios-II      */
+#define IH_CPU_BLACKFIN                16      /* Blackfin     */
+#define IH_CPU_AVR32           17      /* AVR32        */
+
+/*
+ * Image Types
+ *
+ * "Standalone Programs" are directly runnable in the environment
+ *     provided by U-Boot; it is expected that (if they behave
+ *     well) you can continue to work in U-Boot after return from
+ *     the Standalone Program.
+ * "OS Kernel Images" are usually images of some Embedded OS which
+ *     will take over control completely. Usually these programs
+ *     will install their own set of exception handlers, device
+ *     drivers, set up the MMU, etc. - this means, that you cannot
+ *     expect to re-enter U-Boot except by resetting the CPU.
+ * "RAMDisk Images" are more or less just data blocks, and their
+ *     parameters (address, size) are passed to an OS kernel that is
+ *     being started.
+ * "Multi-File Images" contain several images, typically an OS
+ *     (Linux) kernel image and one or more data images like
+ *     RAMDisks. This construct is useful for instance when you want
+ *     to boot over the network using BOOTP etc., where the boot
+ *     server provides just a single image file, but you want to get
+ *     for instance an OS kernel and a RAMDisk image.
+ *
+ *     "Multi-File Images" start with a list of image sizes, each
+ *     image size (in bytes) specified by an "uint32_t" in network
+ *     byte order. This list is terminated by an "(uint32_t)0".
+ *     Immediately after the terminating 0 follow the images, one by
+ *     one, all aligned on "uint32_t" boundaries (size rounded up to
+ *     a multiple of 4 bytes - except for the last file).
+ *
+ * "Firmware Images" are binary images containing firmware (like
+ *     U-Boot or FPGA images) which usually will be programmed to
+ *     flash memory.
+ *
+ * "Script files" are command sequences that will be executed by
+ *     U-Boot's command interpreter; this feature is especially
+ *     useful when you configure U-Boot to use a real shell (hush)
+ *     as command interpreter (=> Shell Scripts).
+ */
+
+#define IH_TYPE_INVALID                0       /* Invalid Image                */
+#define IH_TYPE_STANDALONE     1       /* Standalone Program           */
+#define IH_TYPE_KERNEL         2       /* OS Kernel Image              */
+#define IH_TYPE_RAMDISK                3       /* RAMDisk Image                */
+#define IH_TYPE_MULTI          4       /* Multi-File Image             */
+#define IH_TYPE_FIRMWARE       5       /* Firmware Image               */
+#define IH_TYPE_SCRIPT         6       /* Script file                  */
+#define IH_TYPE_FILESYSTEM     7       /* Filesystem Image (any type)  */
+#define IH_TYPE_FLATDT         8       /* Binary Flat Device Tree Blob */
+
+/*
+ * Compression Types
+ */
+#define IH_COMP_NONE           0       /*  No   Compression Used       */
+#define IH_COMP_GZIP           1       /* gzip  Compression Used       */
+#define IH_COMP_BZIP2          2       /* bzip2 Compression Used       */
+
+#define IH_MAGIC       0x27051956      /* Image Magic Number           */
+#define IH_NMLEN               32      /* Image Name Length            */
+
+/*
+ * all data in network byte order (aka natural aka bigendian)
+ */
+
+typedef struct uboot_image_header {
+       uint32_t        ih_magic;       /* Image Header Magic Number    */
+       uint32_t        ih_hcrc;        /* Image Header CRC Checksum    */
+       uint32_t        ih_time;        /* Image Creation Timestamp     */
+       uint32_t        ih_size;        /* Image Data Size              */
+       uint32_t        ih_load;        /* Data  Load  Address          */
+       uint32_t        ih_ep;          /* Entry Point Address          */
+       uint32_t        ih_dcrc;        /* Image Data CRC Checksum      */
+       uint8_t         ih_os;          /* Operating System             */
+       uint8_t         ih_arch;        /* CPU architecture             */
+       uint8_t         ih_type;        /* Image Type                   */
+       uint8_t         ih_comp;        /* Compression Type             */
+       uint8_t         ih_name[IH_NMLEN];      /* Image Name           */
+} uboot_image_header_t;
+
+
+#endif /* __IMAGE_H__ */
diff --git a/hw/cpu/Makefile.objs b/hw/cpu/Makefile.objs
new file mode 100644 (file)
index 0000000..a49ca04
--- /dev/null
@@ -0,0 +1,4 @@
+obj-$(CONFIG_ARM11MPCORE) += arm11mpcore.o
+obj-$(CONFIG_ARM9MPCORE) += a9mpcore.o
+obj-$(CONFIG_ARM15MPCORE) += a15mpcore.o
+
diff --git a/hw/cpu/a15mpcore.c b/hw/cpu/a15mpcore.c
new file mode 100644 (file)
index 0000000..648656d
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * 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 "hw/sysbus.h"
+#include "sysemu/kvm.h"
+
+/* A15MP private memory region.  */
+
+typedef struct A15MPPrivState {
+    SysBusDevice busdev;
+    uint32_t num_cpu;
+    uint32_t num_irq;
+    MemoryRegion container;
+    DeviceState *gic;
+} A15MPPrivState;
+
+static void a15mp_priv_set_irq(void *opaque, int irq, int level)
+{
+    A15MPPrivState *s = (A15MPPrivState *)opaque;
+    qemu_set_irq(qdev_get_gpio_in(s->gic, irq), level);
+}
+
+static int a15mp_priv_init(SysBusDevice *dev)
+{
+    A15MPPrivState *s = FROM_SYSBUS(A15MPPrivState, dev);
+    SysBusDevice *busdev;
+    const char *gictype = "arm_gic";
+
+    if (kvm_irqchip_in_kernel()) {
+        gictype = "kvm-arm-gic";
+    }
+
+    s->gic = qdev_create(NULL, gictype);
+    qdev_prop_set_uint32(s->gic, "num-cpu", s->num_cpu);
+    qdev_prop_set_uint32(s->gic, "num-irq", s->num_irq);
+    qdev_prop_set_uint32(s->gic, "revision", 2);
+    qdev_init_nofail(s->gic);
+    busdev = SYS_BUS_DEVICE(s->gic);
+
+    /* Pass through outbound IRQ lines from the GIC */
+    sysbus_pass_irq(dev, busdev);
+
+    /* Pass through inbound GPIO lines to the GIC */
+    qdev_init_gpio_in(&s->busdev.qdev, a15mp_priv_set_irq, s->num_irq - 32);
+
+    /* 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,
+                                sysbus_mmio_get_region(busdev, 0));
+    memory_region_add_subregion(&s->container, 0x2000,
+                                sysbus_mmio_get_region(busdev, 1));
+
+    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 */
+}
+
+static const 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)
diff --git a/hw/cpu/a9mpcore.c b/hw/cpu/a9mpcore.c
new file mode 100644 (file)
index 0000000..0a1a10f
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * Cortex-A9MPCore internal peripheral emulation.
+ *
+ * Copyright (c) 2009 CodeSourcery.
+ * Copyright (c) 2011 Linaro Limited.
+ * Written by Paul Brook, Peter Maydell.
+ *
+ * This code is licensed under the GPL.
+ */
+
+#include "hw/sysbus.h"
+
+typedef struct A9MPPrivState {
+    SysBusDevice busdev;
+    uint32_t num_cpu;
+    MemoryRegion container;
+    DeviceState *mptimer;
+    DeviceState *wdt;
+    DeviceState *gic;
+    DeviceState *scu;
+    uint32_t num_irq;
+} A9MPPrivState;
+
+static void a9mp_priv_set_irq(void *opaque, int irq, int level)
+{
+    A9MPPrivState *s = (A9MPPrivState *)opaque;
+    qemu_set_irq(qdev_get_gpio_in(s->gic, irq), level);
+}
+
+static int a9mp_priv_init(SysBusDevice *dev)
+{
+    A9MPPrivState *s = FROM_SYSBUS(A9MPPrivState, dev);
+    SysBusDevice *timerbusdev, *wdtbusdev, *gicbusdev, *scubusdev;
+    int i;
+
+    s->gic = qdev_create(NULL, "arm_gic");
+    qdev_prop_set_uint32(s->gic, "num-cpu", s->num_cpu);
+    qdev_prop_set_uint32(s->gic, "num-irq", s->num_irq);
+    qdev_init_nofail(s->gic);
+    gicbusdev = SYS_BUS_DEVICE(s->gic);
+
+    /* Pass through outbound IRQ lines from the GIC */
+    sysbus_pass_irq(dev, gicbusdev);
+
+    /* Pass through inbound GPIO lines to the GIC */
+    qdev_init_gpio_in(&s->busdev.qdev, a9mp_priv_set_irq, s->num_irq - 32);
+
+    s->scu = qdev_create(NULL, "a9-scu");
+    qdev_prop_set_uint32(s->scu, "num-cpu", s->num_cpu);
+    qdev_init_nofail(s->scu);
+    scubusdev = SYS_BUS_DEVICE(s->scu);
+
+    s->mptimer = qdev_create(NULL, "arm_mptimer");
+    qdev_prop_set_uint32(s->mptimer, "num-cpu", s->num_cpu);
+    qdev_init_nofail(s->mptimer);
+    timerbusdev = SYS_BUS_DEVICE(s->mptimer);
+
+    s->wdt = qdev_create(NULL, "arm_mptimer");
+    qdev_prop_set_uint32(s->wdt, "num-cpu", s->num_cpu);
+    qdev_init_nofail(s->wdt);
+    wdtbusdev = SYS_BUS_DEVICE(s->wdt);
+
+    /* Memory map (addresses are offsets from PERIPHBASE):
+     *  0x0000-0x00ff -- Snoop Control Unit
+     *  0x0100-0x01ff -- GIC CPU interface
+     *  0x0200-0x02ff -- Global Timer
+     *  0x0300-0x05ff -- nothing
+     *  0x0600-0x06ff -- private timers and watchdogs
+     *  0x0700-0x0fff -- nothing
+     *  0x1000-0x1fff -- GIC Distributor
+     *
+     * We should implement the global timer but don't currently do so.
+     */
+    memory_region_init(&s->container, "a9mp-priv-container", 0x2000);
+    memory_region_add_subregion(&s->container, 0,
+                                sysbus_mmio_get_region(scubusdev, 0));
+    /* GIC CPU interface */
+    memory_region_add_subregion(&s->container, 0x100,
+                                sysbus_mmio_get_region(gicbusdev, 1));
+    /* Note that the A9 exposes only the "timer/watchdog for this core"
+     * memory region, not the "timer/watchdog for core X" ones 11MPcore has.
+     */
+    memory_region_add_subregion(&s->container, 0x600,
+                                sysbus_mmio_get_region(timerbusdev, 0));
+    memory_region_add_subregion(&s->container, 0x620,
+                                sysbus_mmio_get_region(wdtbusdev, 0));
+    memory_region_add_subregion(&s->container, 0x1000,
+                                sysbus_mmio_get_region(gicbusdev, 0));
+
+    sysbus_init_mmio(dev, &s->container);
+
+    /* Wire up the interrupt from each watchdog and timer.
+     * For each core the timer is PPI 29 and the watchdog PPI 30.
+     */
+    for (i = 0; i < s->num_cpu; i++) {
+        int ppibase = (s->num_irq - 32) + i * 32;
+        sysbus_connect_irq(timerbusdev, i,
+                           qdev_get_gpio_in(s->gic, ppibase + 29));
+        sysbus_connect_irq(wdtbusdev, i,
+                           qdev_get_gpio_in(s->gic, ppibase + 30));
+    }
+    return 0;
+}
+
+static Property a9mp_priv_properties[] = {
+    DEFINE_PROP_UINT32("num-cpu", A9MPPrivState, 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", A9MPPrivState, 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;
+}
+
+static const TypeInfo a9mp_priv_info = {
+    .name          = "a9mpcore_priv",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(A9MPPrivState),
+    .class_init    = a9mp_priv_class_init,
+};
+
+static void a9mp_register_types(void)
+{
+    type_register_static(&a9mp_priv_info);
+}
+
+type_init(a9mp_register_types)
diff --git a/hw/cpu/arm11mpcore.c b/hw/cpu/arm11mpcore.c
new file mode 100644 (file)
index 0000000..90dcead
--- /dev/null
@@ -0,0 +1,277 @@
+/*
+ * ARM11MPCore internal peripheral emulation.
+ *
+ * Copyright (c) 2006-2007 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the GPL.
+ */
+
+#include "hw/sysbus.h"
+#include "qemu/timer.h"
+
+/* MPCore private memory region.  */
+
+typedef struct ARM11MPCorePriveState {
+    SysBusDevice busdev;
+    uint32_t scu_control;
+    int iomemtype;
+    uint32_t old_timer_status[8];
+    uint32_t num_cpu;
+    MemoryRegion iomem;
+    MemoryRegion container;
+    DeviceState *mptimer;
+    DeviceState *wdtimer;
+    DeviceState *gic;
+    uint32_t num_irq;
+} ARM11MPCorePriveState;
+
+/* Per-CPU private memory mapped IO.  */
+
+static uint64_t mpcore_scu_read(void *opaque, hwaddr offset,
+                                unsigned size)
+{
+    ARM11MPCorePriveState *s = (ARM11MPCorePriveState *)opaque;
+    int id;
+    /* SCU */
+    switch (offset) {
+    case 0x00: /* Control.  */
+        return s->scu_control;
+    case 0x04: /* Configuration.  */
+        id = ((1 << s->num_cpu) - 1) << 4;
+        return id | (s->num_cpu - 1);
+    case 0x08: /* CPU status.  */
+        return 0;
+    case 0x0c: /* Invalidate all.  */
+        return 0;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "mpcore_priv_read: Bad offset %x\n", (int)offset);
+        return 0;
+    }
+}
+
+static void mpcore_scu_write(void *opaque, hwaddr offset,
+                             uint64_t value, unsigned size)
+{
+    ARM11MPCorePriveState *s = (ARM11MPCorePriveState *)opaque;
+    /* SCU */
+    switch (offset) {
+    case 0: /* Control register.  */
+        s->scu_control = value & 1;
+        break;
+    case 0x0c: /* Invalidate all.  */
+        /* This is a no-op as cache is not emulated.  */
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "mpcore_priv_read: Bad offset %x\n", (int)offset);
+    }
+}
+
+static const MemoryRegionOps mpcore_scu_ops = {
+    .read = mpcore_scu_read,
+    .write = mpcore_scu_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void mpcore_priv_set_irq(void *opaque, int irq, int level)
+{
+    ARM11MPCorePriveState *s = (ARM11MPCorePriveState *)opaque;
+    qemu_set_irq(qdev_get_gpio_in(s->gic, irq), level);
+}
+
+static void mpcore_priv_map_setup(ARM11MPCorePriveState *s)
+{
+    int i;
+    SysBusDevice *gicbusdev = SYS_BUS_DEVICE(s->gic);
+    SysBusDevice *timerbusdev = SYS_BUS_DEVICE(s->mptimer);
+    SysBusDevice *wdtbusdev = SYS_BUS_DEVICE(s->wdtimer);
+    memory_region_init(&s->container, "mpcode-priv-container", 0x2000);
+    memory_region_init_io(&s->iomem, &mpcore_scu_ops, s, "mpcore-scu", 0x100);
+    memory_region_add_subregion(&s->container, 0, &s->iomem);
+    /* GIC CPU interfaces: "current CPU" at 0x100, then specific CPUs
+     * at 0x200, 0x300...
+     */
+    for (i = 0; i < (s->num_cpu + 1); i++) {
+        hwaddr offset = 0x100 + (i * 0x100);
+        memory_region_add_subregion(&s->container, offset,
+                                    sysbus_mmio_get_region(gicbusdev, i + 1));
+    }
+    /* Add the regions for timer and watchdog for "current CPU" and
+     * for each specific CPU.
+     */
+    for (i = 0; i < (s->num_cpu + 1); i++) {
+        /* Timers at 0x600, 0x700, ...; watchdogs at 0x620, 0x720, ... */
+        hwaddr offset = 0x600 + i * 0x100;
+        memory_region_add_subregion(&s->container, offset,
+                                    sysbus_mmio_get_region(timerbusdev, i));
+        memory_region_add_subregion(&s->container, offset + 0x20,
+                                    sysbus_mmio_get_region(wdtbusdev, i));
+    }
+    memory_region_add_subregion(&s->container, 0x1000,
+                                sysbus_mmio_get_region(gicbusdev, 0));
+    /* Wire up the interrupt from each watchdog and timer.
+     * For each core the timer is PPI 29 and the watchdog PPI 30.
+     */
+    for (i = 0; i < s->num_cpu; i++) {
+        int ppibase = (s->num_irq - 32) + i * 32;
+        sysbus_connect_irq(timerbusdev, i,
+                           qdev_get_gpio_in(s->gic, ppibase + 29));
+        sysbus_connect_irq(wdtbusdev, i,
+                           qdev_get_gpio_in(s->gic, ppibase + 30));
+    }
+}
+
+static int mpcore_priv_init(SysBusDevice *dev)
+{
+    ARM11MPCorePriveState *s = FROM_SYSBUS(ARM11MPCorePriveState, dev);
+
+    s->gic = qdev_create(NULL, "arm_gic");
+    qdev_prop_set_uint32(s->gic, "num-cpu", s->num_cpu);
+    qdev_prop_set_uint32(s->gic, "num-irq", s->num_irq);
+    /* Request the legacy 11MPCore GIC behaviour: */
+    qdev_prop_set_uint32(s->gic, "revision", 0);
+    qdev_init_nofail(s->gic);
+
+    /* Pass through outbound IRQ lines from the GIC */
+    sysbus_pass_irq(dev, SYS_BUS_DEVICE(s->gic));
+
+    /* Pass through inbound GPIO lines to the GIC */
+    qdev_init_gpio_in(&s->busdev.qdev, mpcore_priv_set_irq, s->num_irq - 32);
+
+    s->mptimer = qdev_create(NULL, "arm_mptimer");
+    qdev_prop_set_uint32(s->mptimer, "num-cpu", s->num_cpu);
+    qdev_init_nofail(s->mptimer);
+
+    s->wdtimer = qdev_create(NULL, "arm_mptimer");
+    qdev_prop_set_uint32(s->wdtimer, "num-cpu", s->num_cpu);
+    qdev_init_nofail(s->wdtimer);
+
+    mpcore_priv_map_setup(s);
+    sysbus_init_mmio(dev, &s->container);
+    return 0;
+}
+
+/* Dummy PIC to route IRQ lines.  The baseboard has 4 independent IRQ
+   controllers.  The output of these, plus some of the raw input lines
+   are fed into a single SMP-aware interrupt controller on the CPU.  */
+typedef struct {
+    SysBusDevice busdev;
+    SysBusDevice *priv;
+    qemu_irq cpuic[32];
+    qemu_irq rvic[4][64];
+    uint32_t num_cpu;
+} mpcore_rirq_state;
+
+/* Map baseboard IRQs onto CPU IRQ lines.  */
+static const int mpcore_irq_map[32] = {
+    -1, -1, -1, -1,  1,  2, -1, -1,
+    -1, -1,  6, -1,  4,  5, -1, -1,
+    -1, 14, 15,  0,  7,  8, -1, -1,
+    -1, -1, -1, -1,  9,  3, -1, -1,
+};
+
+static void mpcore_rirq_set_irq(void *opaque, int irq, int level)
+{
+    mpcore_rirq_state *s = (mpcore_rirq_state *)opaque;
+    int i;
+
+    for (i = 0; i < 4; i++) {
+        qemu_set_irq(s->rvic[i][irq], level);
+    }
+    if (irq < 32) {
+        irq = mpcore_irq_map[irq];
+        if (irq >= 0) {
+            qemu_set_irq(s->cpuic[irq], level);
+        }
+    }
+}
+
+static int realview_mpcore_init(SysBusDevice *dev)
+{
+    mpcore_rirq_state *s = FROM_SYSBUS(mpcore_rirq_state, dev);
+    DeviceState *gic;
+    DeviceState *priv;
+    int n;
+    int i;
+
+    priv = qdev_create(NULL, "arm11mpcore_priv");
+    qdev_prop_set_uint32(priv, "num-cpu", s->num_cpu);
+    qdev_init_nofail(priv);
+    s->priv = SYS_BUS_DEVICE(priv);
+    sysbus_pass_irq(dev, s->priv);
+    for (i = 0; i < 32; i++) {
+        s->cpuic[i] = qdev_get_gpio_in(priv, i);
+    }
+    /* ??? IRQ routing is hardcoded to "normal" mode.  */
+    for (n = 0; n < 4; n++) {
+        gic = sysbus_create_simple("realview_gic", 0x10040000 + n * 0x10000,
+                                   s->cpuic[10 + n]);
+        for (i = 0; i < 64; i++) {
+            s->rvic[n][i] = qdev_get_gpio_in(gic, i);
+        }
+    }
+    qdev_init_gpio_in(&dev->qdev, mpcore_rirq_set_irq, 64);
+    sysbus_init_mmio(dev, sysbus_mmio_get_region(s->priv, 0));
+    return 0;
+}
+
+static Property mpcore_rirq_properties[] = {
+    DEFINE_PROP_UINT32("num-cpu", mpcore_rirq_state, num_cpu, 1),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void mpcore_rirq_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = realview_mpcore_init;
+    dc->props = mpcore_rirq_properties;
+}
+
+static const TypeInfo mpcore_rirq_info = {
+    .name          = "realview_mpcore",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(mpcore_rirq_state),
+    .class_init    = mpcore_rirq_class_init,
+};
+
+static Property mpcore_priv_properties[] = {
+    DEFINE_PROP_UINT32("num-cpu", ARM11MPCorePriveState, 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", ARM11MPCorePriveState, num_irq, 64),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void mpcore_priv_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = mpcore_priv_init;
+    dc->props = mpcore_priv_properties;
+}
+
+static const TypeInfo mpcore_priv_info = {
+    .name          = "arm11mpcore_priv",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(ARM11MPCorePriveState),
+    .class_init    = mpcore_priv_class_init,
+};
+
+static void arm11mpcore_register_types(void)
+{
+    type_register_static(&mpcore_rirq_info);
+    type_register_static(&mpcore_priv_info);
+}
+
+type_init(arm11mpcore_register_types)
diff --git a/hw/cris-boot.h b/hw/cris-boot.h
deleted file mode 100644 (file)
index c4d3fa6..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-#ifndef _CRIS_BOOT_H
-#define HW_CRIS_BOOT_H 1
-
-struct cris_load_info
-{
-    const char *image_filename;
-    const char *cmdline;
-    int image_size;
-
-    hwaddr entry;
-};
-
-void cris_load_image(CRISCPU *cpu, struct cris_load_info *li);
-
-#endif
index a94c62450d308e8c9b4f654d0105c754877460af..776db7c5cda854d60a313cb31e2136480c44db25 100644 (file)
@@ -1,13 +1,3 @@
-# IO blocks
-obj-y += etraxfs_dma.o
-obj-y += etraxfs_pic.o
-obj-y += etraxfs_eth.o
-obj-y += etraxfs_timer.o
-obj-y += etraxfs_ser.o
-
-obj-y := $(addprefix ../,$(obj-y))
-
-# Boards
 obj-y += pic_cpu.o
 obj-y += boot.o
 obj-y += axis_dev88.o
index eccd423abfba294455906df5627cce649dee29db..7475671308e582f3c60250b7a2bd7ac53ae5ad23 100644 (file)
 
 #include "hw/sysbus.h"
 #include "net/net.h"
-#include "hw/flash.h"
+#include "hw/block/flash.h"
 #include "hw/boards.h"
-#include "hw/etraxfs.h"
+#include "hw/cris/etraxfs.h"
 #include "hw/loader.h"
 #include "elf.h"
-#include "hw/cris-boot.h"
+#include "boot.h"
 #include "sysemu/blockdev.h"
 #include "exec/address-spaces.h"
 
index c330e22a86cb387ded7e2a1443812d3c275f51a3..622f353c9a8becfe2e37f428d1bf0f58dc3f2bfc 100644 (file)
@@ -25,7 +25,7 @@
 #include "hw/hw.h"
 #include "hw/loader.h"
 #include "elf.h"
-#include "hw/cris-boot.h"
+#include "boot.h"
 
 static void main_cpu_reset(void *opaque)
 {
diff --git a/hw/cris/boot.h b/hw/cris/boot.h
new file mode 100644 (file)
index 0000000..c4d3fa6
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef _CRIS_BOOT_H
+#define HW_CRIS_BOOT_H 1
+
+struct cris_load_info
+{
+    const char *image_filename;
+    const char *cmdline;
+    int image_size;
+
+    hwaddr entry;
+};
+
+void cris_load_image(CRISCPU *cpu, struct cris_load_info *li);
+
+#endif
index 85c68c04971874b5ef2ca4079df654859c4b5823..bd47bf1a5d0a6bd44bcf7a2a49c848252f2e260d 100644 (file)
@@ -24,7 +24,7 @@
 
 #include "hw/sysbus.h"
 #include "hw/hw.h"
-#include "hw/etraxfs.h"
+#include "hw/cris/etraxfs.h"
 
 #define D(x)
 
diff --git a/hw/cs4231.c b/hw/cs4231.c
deleted file mode 100644 (file)
index 2975336..0000000
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- * QEMU Crystal CS4231 audio chip emulation
- *
- * Copyright (c) 2006 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.
- */
-
-#include "hw/sysbus.h"
-#include "trace.h"
-
-/*
- * In addition to Crystal CS4231 there is a DMA controller on Sparc.
- */
-#define CS_SIZE 0x40
-#define CS_REGS 16
-#define CS_DREGS 32
-#define CS_MAXDREG (CS_DREGS - 1)
-
-typedef struct CSState {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-    qemu_irq irq;
-    uint32_t regs[CS_REGS];
-    uint8_t dregs[CS_DREGS];
-} CSState;
-
-#define CS_RAP(s) ((s)->regs[0] & CS_MAXDREG)
-#define CS_VER 0xa0
-#define CS_CDC_VER 0x8a
-
-static void cs_reset(DeviceState *d)
-{
-    CSState *s = container_of(d, CSState, busdev.qdev);
-
-    memset(s->regs, 0, CS_REGS * 4);
-    memset(s->dregs, 0, CS_DREGS);
-    s->dregs[12] = CS_CDC_VER;
-    s->dregs[25] = CS_VER;
-}
-
-static uint64_t cs_mem_read(void *opaque, hwaddr addr,
-                            unsigned size)
-{
-    CSState *s = opaque;
-    uint32_t saddr, ret;
-
-    saddr = addr >> 2;
-    switch (saddr) {
-    case 1:
-        switch (CS_RAP(s)) {
-        case 3: // Write only
-            ret = 0;
-            break;
-        default:
-            ret = s->dregs[CS_RAP(s)];
-            break;
-        }
-        trace_cs4231_mem_readl_dreg(CS_RAP(s), ret);
-        break;
-    default:
-        ret = s->regs[saddr];
-        trace_cs4231_mem_readl_reg(saddr, ret);
-        break;
-    }
-    return ret;
-}
-
-static void cs_mem_write(void *opaque, hwaddr addr,
-                         uint64_t val, unsigned size)
-{
-    CSState *s = opaque;
-    uint32_t saddr;
-
-    saddr = addr >> 2;
-    trace_cs4231_mem_writel_reg(saddr, s->regs[saddr], val);
-    switch (saddr) {
-    case 1:
-        trace_cs4231_mem_writel_dreg(CS_RAP(s), s->dregs[CS_RAP(s)], val);
-        switch(CS_RAP(s)) {
-        case 11:
-        case 25: // Read only
-            break;
-        case 12:
-            val &= 0x40;
-            val |= CS_CDC_VER; // Codec version
-            s->dregs[CS_RAP(s)] = val;
-            break;
-        default:
-            s->dregs[CS_RAP(s)] = val;
-            break;
-        }
-        break;
-    case 2: // Read only
-        break;
-    case 4:
-        if (val & 1) {
-            cs_reset(&s->busdev.qdev);
-        }
-        val &= 0x7f;
-        s->regs[saddr] = val;
-        break;
-    default:
-        s->regs[saddr] = val;
-        break;
-    }
-}
-
-static const MemoryRegionOps cs_mem_ops = {
-    .read = cs_mem_read,
-    .write = cs_mem_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static const VMStateDescription vmstate_cs4231 = {
-    .name ="cs4231",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField []) {
-        VMSTATE_UINT32_ARRAY(regs, CSState, CS_REGS),
-        VMSTATE_UINT8_ARRAY(dregs, CSState, CS_DREGS),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static int cs4231_init1(SysBusDevice *dev)
-{
-    CSState *s = FROM_SYSBUS(CSState, dev);
-
-    memory_region_init_io(&s->iomem, &cs_mem_ops, s, "cs4321", CS_SIZE);
-    sysbus_init_mmio(dev, &s->iomem);
-    sysbus_init_irq(dev, &s->irq);
-
-    return 0;
-}
-
-static Property cs4231_properties[] = {
-    {.name = NULL},
-};
-
-static void cs4231_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = cs4231_init1;
-    dc->reset = cs_reset;
-    dc->vmsd = &vmstate_cs4231;
-    dc->props = cs4231_properties;
-}
-
-static const TypeInfo cs4231_info = {
-    .name          = "SUNW,CS4231",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(CSState),
-    .class_init    = cs4231_class_init,
-};
-
-static void cs4231_register_types(void)
-{
-    type_register_static(&cs4231_info);
-}
-
-type_init(cs4231_register_types)
diff --git a/hw/cs4231a.c b/hw/cs4231a.c
deleted file mode 100644 (file)
index f005f25..0000000
+++ /dev/null
@@ -1,697 +0,0 @@
-/*
- * QEMU Crystal CS4231 audio chip emulation
- *
- * Copyright (c) 2006 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.
- */
-#include "hw/hw.h"
-#include "hw/audiodev.h"
-#include "audio/audio.h"
-#include "hw/isa.h"
-#include "hw/qdev.h"
-#include "qemu/timer.h"
-
-/*
-  Missing features:
-  ADC
-  Loopback
-  Timer
-  ADPCM
-  More...
-*/
-
-/* #define DEBUG */
-/* #define DEBUG_XLAW */
-
-static struct {
-    int aci_counter;
-} conf = {1};
-
-#ifdef DEBUG
-#define dolog(...) AUD_log ("cs4231a", __VA_ARGS__)
-#else
-#define dolog(...)
-#endif
-
-#define lwarn(...) AUD_log ("cs4231a", "warning: " __VA_ARGS__)
-#define lerr(...) AUD_log ("cs4231a", "error: " __VA_ARGS__)
-
-#define CS_REGS 16
-#define CS_DREGS 32
-
-typedef struct CSState {
-    ISADevice dev;
-    QEMUSoundCard card;
-    MemoryRegion ioports;
-    qemu_irq pic;
-    uint32_t regs[CS_REGS];
-    uint8_t dregs[CS_DREGS];
-    uint32_t irq;
-    uint32_t dma;
-    uint32_t port;
-    int shift;
-    int dma_running;
-    int audio_free;
-    int transferred;
-    int aci_counter;
-    SWVoiceOut *voice;
-    int16_t *tab;
-} CSState;
-
-#define MODE2 (1 << 6)
-#define MCE (1 << 6)
-#define PMCE (1 << 4)
-#define CMCE (1 << 5)
-#define TE (1 << 6)
-#define PEN (1 << 0)
-#define INT (1 << 0)
-#define IEN (1 << 1)
-#define PPIO (1 << 6)
-#define PI (1 << 4)
-#define CI (1 << 5)
-#define TI (1 << 6)
-
-enum {
-    Index_Address,
-    Index_Data,
-    Status,
-    PIO_Data
-};
-
-enum {
-    Left_ADC_Input_Control,
-    Right_ADC_Input_Control,
-    Left_AUX1_Input_Control,
-    Right_AUX1_Input_Control,
-    Left_AUX2_Input_Control,
-    Right_AUX2_Input_Control,
-    Left_DAC_Output_Control,
-    Right_DAC_Output_Control,
-    FS_And_Playback_Data_Format,
-    Interface_Configuration,
-    Pin_Control,
-    Error_Status_And_Initialization,
-    MODE_And_ID,
-    Loopback_Control,
-    Playback_Upper_Base_Count,
-    Playback_Lower_Base_Count,
-    Alternate_Feature_Enable_I,
-    Alternate_Feature_Enable_II,
-    Left_Line_Input_Control,
-    Right_Line_Input_Control,
-    Timer_Low_Base,
-    Timer_High_Base,
-    RESERVED,
-    Alternate_Feature_Enable_III,
-    Alternate_Feature_Status,
-    Version_Chip_ID,
-    Mono_Input_And_Output_Control,
-    RESERVED_2,
-    Capture_Data_Format,
-    RESERVED_3,
-    Capture_Upper_Base_Count,
-    Capture_Lower_Base_Count
-};
-
-static int freqs[2][8] = {
-    { 8000, 16000, 27420, 32000,    -1,    -1, 48000, 9000 },
-    { 5510, 11025, 18900, 22050, 37800, 44100, 33075, 6620 }
-};
-
-/* Tables courtesy http://hazelware.luggle.com/tutorials/mulawcompression.html */
-static int16_t MuLawDecompressTable[256] =
-{
-     -32124,-31100,-30076,-29052,-28028,-27004,-25980,-24956,
-     -23932,-22908,-21884,-20860,-19836,-18812,-17788,-16764,
-     -15996,-15484,-14972,-14460,-13948,-13436,-12924,-12412,
-     -11900,-11388,-10876,-10364, -9852, -9340, -8828, -8316,
-      -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140,
-      -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092,
-      -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004,
-      -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980,
-      -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436,
-      -1372, -1308, -1244, -1180, -1116, -1052,  -988,  -924,
-       -876,  -844,  -812,  -780,  -748,  -716,  -684,  -652,
-       -620,  -588,  -556,  -524,  -492,  -460,  -428,  -396,
-       -372,  -356,  -340,  -324,  -308,  -292,  -276,  -260,
-       -244,  -228,  -212,  -196,  -180,  -164,  -148,  -132,
-       -120,  -112,  -104,   -96,   -88,   -80,   -72,   -64,
-        -56,   -48,   -40,   -32,   -24,   -16,    -8,     0,
-      32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956,
-      23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764,
-      15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412,
-      11900, 11388, 10876, 10364,  9852,  9340,  8828,  8316,
-       7932,  7676,  7420,  7164,  6908,  6652,  6396,  6140,
-       5884,  5628,  5372,  5116,  4860,  4604,  4348,  4092,
-       3900,  3772,  3644,  3516,  3388,  3260,  3132,  3004,
-       2876,  2748,  2620,  2492,  2364,  2236,  2108,  1980,
-       1884,  1820,  1756,  1692,  1628,  1564,  1500,  1436,
-       1372,  1308,  1244,  1180,  1116,  1052,   988,   924,
-        876,   844,   812,   780,   748,   716,   684,   652,
-        620,   588,   556,   524,   492,   460,   428,   396,
-        372,   356,   340,   324,   308,   292,   276,   260,
-        244,   228,   212,   196,   180,   164,   148,   132,
-        120,   112,   104,    96,    88,    80,    72,    64,
-         56,    48,    40,    32,    24,    16,     8,     0
-};
-
-static int16_t ALawDecompressTable[256] =
-{
-     -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736,
-     -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784,
-     -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368,
-     -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392,
-     -22016,-20992,-24064,-23040,-17920,-16896,-19968,-18944,
-     -30208,-29184,-32256,-31232,-26112,-25088,-28160,-27136,
-     -11008,-10496,-12032,-11520,-8960, -8448, -9984, -9472,
-     -15104,-14592,-16128,-15616,-13056,-12544,-14080,-13568,
-     -344,  -328,  -376,  -360,  -280,  -264,  -312,  -296,
-     -472,  -456,  -504,  -488,  -408,  -392,  -440,  -424,
-     -88,   -72,   -120,  -104,  -24,   -8,    -56,   -40,
-     -216,  -200,  -248,  -232,  -152,  -136,  -184,  -168,
-     -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184,
-     -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696,
-     -688,  -656,  -752,  -720,  -560,  -528,  -624,  -592,
-     -944,  -912,  -1008, -976,  -816,  -784,  -880,  -848,
-      5504,  5248,  6016,  5760,  4480,  4224,  4992,  4736,
-      7552,  7296,  8064,  7808,  6528,  6272,  7040,  6784,
-      2752,  2624,  3008,  2880,  2240,  2112,  2496,  2368,
-      3776,  3648,  4032,  3904,  3264,  3136,  3520,  3392,
-      22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944,
-      30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136,
-      11008, 10496, 12032, 11520, 8960,  8448,  9984,  9472,
-      15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568,
-      344,   328,   376,   360,   280,   264,   312,   296,
-      472,   456,   504,   488,   408,   392,   440,   424,
-      88,    72,   120,   104,    24,     8,    56,    40,
-      216,   200,   248,   232,   152,   136,   184,   168,
-      1376,  1312,  1504,  1440,  1120,  1056,  1248,  1184,
-      1888,  1824,  2016,  1952,  1632,  1568,  1760,  1696,
-      688,   656,   752,   720,   560,   528,   624,   592,
-      944,   912,  1008,   976,   816,   784,   880,   848
-};
-
-static void cs_reset (void *opaque)
-{
-    CSState *s = opaque;
-
-    s->regs[Index_Address] = 0x40;
-    s->regs[Index_Data]    = 0x00;
-    s->regs[Status]        = 0x00;
-    s->regs[PIO_Data]      = 0x00;
-
-    s->dregs[Left_ADC_Input_Control]          = 0x00;
-    s->dregs[Right_ADC_Input_Control]         = 0x00;
-    s->dregs[Left_AUX1_Input_Control]         = 0x88;
-    s->dregs[Right_AUX1_Input_Control]        = 0x88;
-    s->dregs[Left_AUX2_Input_Control]         = 0x88;
-    s->dregs[Right_AUX2_Input_Control]        = 0x88;
-    s->dregs[Left_DAC_Output_Control]         = 0x80;
-    s->dregs[Right_DAC_Output_Control]        = 0x80;
-    s->dregs[FS_And_Playback_Data_Format]     = 0x00;
-    s->dregs[Interface_Configuration]         = 0x08;
-    s->dregs[Pin_Control]                     = 0x00;
-    s->dregs[Error_Status_And_Initialization] = 0x00;
-    s->dregs[MODE_And_ID]                     = 0x8a;
-    s->dregs[Loopback_Control]                = 0x00;
-    s->dregs[Playback_Upper_Base_Count]       = 0x00;
-    s->dregs[Playback_Lower_Base_Count]       = 0x00;
-    s->dregs[Alternate_Feature_Enable_I]      = 0x00;
-    s->dregs[Alternate_Feature_Enable_II]     = 0x00;
-    s->dregs[Left_Line_Input_Control]         = 0x88;
-    s->dregs[Right_Line_Input_Control]        = 0x88;
-    s->dregs[Timer_Low_Base]                  = 0x00;
-    s->dregs[Timer_High_Base]                 = 0x00;
-    s->dregs[RESERVED]                        = 0x00;
-    s->dregs[Alternate_Feature_Enable_III]    = 0x00;
-    s->dregs[Alternate_Feature_Status]        = 0x00;
-    s->dregs[Version_Chip_ID]                 = 0xa0;
-    s->dregs[Mono_Input_And_Output_Control]   = 0xa0;
-    s->dregs[RESERVED_2]                      = 0x00;
-    s->dregs[Capture_Data_Format]             = 0x00;
-    s->dregs[RESERVED_3]                      = 0x00;
-    s->dregs[Capture_Upper_Base_Count]        = 0x00;
-    s->dregs[Capture_Lower_Base_Count]        = 0x00;
-}
-
-static void cs_audio_callback (void *opaque, int free)
-{
-    CSState *s = opaque;
-    s->audio_free = free;
-}
-
-static void cs_reset_voices (CSState *s, uint32_t val)
-{
-    int xtal;
-    struct audsettings as;
-
-#ifdef DEBUG_XLAW
-    if (val == 0 || val == 32)
-        val = (1 << 4) | (1 << 5);
-#endif
-
-    xtal = val & 1;
-    as.freq = freqs[xtal][(val >> 1) & 7];
-
-    if (as.freq == -1) {
-        lerr ("unsupported frequency (val=%#x)\n", val);
-        goto error;
-    }
-
-    as.nchannels = (val & (1 << 4)) ? 2 : 1;
-    as.endianness = 0;
-    s->tab = NULL;
-
-    switch ((val >> 5) & ((s->dregs[MODE_And_ID] & MODE2) ? 7 : 3)) {
-    case 0:
-        as.fmt = AUD_FMT_U8;
-        s->shift = as.nchannels == 2;
-        break;
-
-    case 1:
-        s->tab = MuLawDecompressTable;
-        goto x_law;
-    case 3:
-        s->tab = ALawDecompressTable;
-    x_law:
-        as.fmt = AUD_FMT_S16;
-        as.endianness = AUDIO_HOST_ENDIANNESS;
-        s->shift = as.nchannels == 2;
-        break;
-
-    case 6:
-        as.endianness = 1;
-    case 2:
-        as.fmt = AUD_FMT_S16;
-        s->shift = as.nchannels;
-        break;
-
-    case 7:
-    case 4:
-        lerr ("attempt to use reserved format value (%#x)\n", val);
-        goto error;
-
-    case 5:
-        lerr ("ADPCM 4 bit IMA compatible format is not supported\n");
-        goto error;
-    }
-
-    s->voice = AUD_open_out (
-        &s->card,
-        s->voice,
-        "cs4231a",
-        s,
-        cs_audio_callback,
-        &as
-        );
-
-    if (s->dregs[Interface_Configuration] & PEN) {
-        if (!s->dma_running) {
-            DMA_hold_DREQ (s->dma);
-            AUD_set_active_out (s->voice, 1);
-            s->transferred = 0;
-        }
-        s->dma_running = 1;
-    }
-    else {
-        if (s->dma_running) {
-            DMA_release_DREQ (s->dma);
-            AUD_set_active_out (s->voice, 0);
-        }
-        s->dma_running = 0;
-    }
-    return;
-
- error:
-    if (s->dma_running) {
-        DMA_release_DREQ (s->dma);
-        AUD_set_active_out (s->voice, 0);
-    }
-}
-
-static uint64_t cs_read (void *opaque, hwaddr addr, unsigned size)
-{
-    CSState *s = opaque;
-    uint32_t saddr, iaddr, ret;
-
-    saddr = addr;
-    iaddr = ~0U;
-
-    switch (saddr) {
-    case Index_Address:
-        ret = s->regs[saddr] & ~0x80;
-        break;
-
-    case Index_Data:
-        if (!(s->dregs[MODE_And_ID] & MODE2))
-            iaddr = s->regs[Index_Address] & 0x0f;
-        else
-            iaddr = s->regs[Index_Address] & 0x1f;
-
-        ret = s->dregs[iaddr];
-        if (iaddr == Error_Status_And_Initialization) {
-            /* keep SEAL happy */
-            if (s->aci_counter) {
-                ret |= 1 << 5;
-                s->aci_counter -= 1;
-            }
-        }
-        break;
-
-    default:
-        ret = s->regs[saddr];
-        break;
-    }
-    dolog ("read %d:%d -> %d\n", saddr, iaddr, ret);
-    return ret;
-}
-
-static void cs_write (void *opaque, hwaddr addr,
-                      uint64_t val64, unsigned size)
-{
-    CSState *s = opaque;
-    uint32_t saddr, iaddr, val;
-
-    saddr = addr;
-    val = val64;
-
-    switch (saddr) {
-    case Index_Address:
-        if (!(s->regs[Index_Address] & MCE) && (val & MCE)
-            && (s->dregs[Interface_Configuration] & (3 << 3)))
-            s->aci_counter = conf.aci_counter;
-
-        s->regs[Index_Address] = val & ~(1 << 7);
-        break;
-
-    case Index_Data:
-        if (!(s->dregs[MODE_And_ID] & MODE2))
-            iaddr = s->regs[Index_Address] & 0x0f;
-        else
-            iaddr = s->regs[Index_Address] & 0x1f;
-
-        switch (iaddr) {
-        case RESERVED:
-        case RESERVED_2:
-        case RESERVED_3:
-            lwarn ("attempt to write %#x to reserved indirect register %d\n",
-                   val, iaddr);
-            break;
-
-        case FS_And_Playback_Data_Format:
-            if (s->regs[Index_Address] & MCE) {
-                cs_reset_voices (s, val);
-            }
-            else {
-                if (s->dregs[Alternate_Feature_Status] & PMCE) {
-                    val = (val & ~0x0f) | (s->dregs[iaddr] & 0x0f);
-                    cs_reset_voices (s, val);
-                }
-                else {
-                    lwarn ("[P]MCE(%#x, %#x) is not set, val=%#x\n",
-                           s->regs[Index_Address],
-                           s->dregs[Alternate_Feature_Status],
-                           val);
-                    break;
-                }
-            }
-            s->dregs[iaddr] = val;
-            break;
-
-        case Interface_Configuration:
-            val &= ~(1 << 5);   /* D5 is reserved */
-            s->dregs[iaddr] = val;
-            if (val & PPIO) {
-                lwarn ("PIO is not supported (%#x)\n", val);
-                break;
-            }
-            if (val & PEN) {
-                if (!s->dma_running) {
-                    cs_reset_voices (s, s->dregs[FS_And_Playback_Data_Format]);
-                }
-            }
-            else {
-                if (s->dma_running) {
-                    DMA_release_DREQ (s->dma);
-                    AUD_set_active_out (s->voice, 0);
-                    s->dma_running = 0;
-                }
-            }
-            break;
-
-        case Error_Status_And_Initialization:
-            lwarn ("attempt to write to read only register %d\n", iaddr);
-            break;
-
-        case MODE_And_ID:
-            dolog ("val=%#x\n", val);
-            if (val & MODE2)
-                s->dregs[iaddr] |= MODE2;
-            else
-                s->dregs[iaddr] &= ~MODE2;
-            break;
-
-        case Alternate_Feature_Enable_I:
-            if (val & TE)
-                lerr ("timer is not yet supported\n");
-            s->dregs[iaddr] = val;
-            break;
-
-        case Alternate_Feature_Status:
-            if ((s->dregs[iaddr] & PI) && !(val & PI)) {
-                /* XXX: TI CI */
-                qemu_irq_lower (s->pic);
-                s->regs[Status] &= ~INT;
-            }
-            s->dregs[iaddr] = val;
-            break;
-
-        case Version_Chip_ID:
-            lwarn ("write to Version_Chip_ID register %#x\n", val);
-            s->dregs[iaddr] = val;
-            break;
-
-        default:
-            s->dregs[iaddr] = val;
-            break;
-        }
-        dolog ("written value %#x to indirect register %d\n", val, iaddr);
-        break;
-
-    case Status:
-        if (s->regs[Status] & INT) {
-            qemu_irq_lower (s->pic);
-        }
-        s->regs[Status] &= ~INT;
-        s->dregs[Alternate_Feature_Status] &= ~(PI | CI | TI);
-        break;
-
-    case PIO_Data:
-        lwarn ("attempt to write value %#x to PIO register\n", val);
-        break;
-    }
-}
-
-static int cs_write_audio (CSState *s, int nchan, int dma_pos,
-                           int dma_len, int len)
-{
-    int temp, net;
-    uint8_t tmpbuf[4096];
-
-    temp = len;
-    net = 0;
-
-    while (temp) {
-        int left = dma_len - dma_pos;
-        int copied;
-        size_t to_copy;
-
-        to_copy = audio_MIN (temp, left);
-        if (to_copy > sizeof (tmpbuf)) {
-            to_copy = sizeof (tmpbuf);
-        }
-
-        copied = DMA_read_memory (nchan, tmpbuf, dma_pos, to_copy);
-        if (s->tab) {
-            int i;
-            int16_t linbuf[4096];
-
-            for (i = 0; i < copied; ++i)
-                linbuf[i] = s->tab[tmpbuf[i]];
-            copied = AUD_write (s->voice, linbuf, copied << 1);
-            copied >>= 1;
-        }
-        else {
-            copied = AUD_write (s->voice, tmpbuf, copied);
-        }
-
-        temp -= copied;
-        dma_pos = (dma_pos + copied) % dma_len;
-        net += copied;
-
-        if (!copied) {
-            break;
-        }
-    }
-
-    return net;
-}
-
-static int cs_dma_read (void *opaque, int nchan, int dma_pos, int dma_len)
-{
-    CSState *s = opaque;
-    int copy, written;
-    int till = -1;
-
-    copy = s->voice ? (s->audio_free >> (s->tab != NULL)) : dma_len;
-
-    if (s->dregs[Pin_Control] & IEN) {
-        till = (s->dregs[Playback_Lower_Base_Count]
-            | (s->dregs[Playback_Upper_Base_Count] << 8)) << s->shift;
-        till -= s->transferred;
-        copy = audio_MIN (till, copy);
-    }
-
-    if ((copy <= 0) || (dma_len <= 0)) {
-        return dma_pos;
-    }
-
-    written = cs_write_audio (s, nchan, dma_pos, dma_len, copy);
-
-    dma_pos = (dma_pos + written) % dma_len;
-    s->audio_free -= (written << (s->tab != NULL));
-
-    if (written == till) {
-        s->regs[Status] |= INT;
-        s->dregs[Alternate_Feature_Status] |= PI;
-        s->transferred = 0;
-        qemu_irq_raise (s->pic);
-    }
-    else {
-        s->transferred += written;
-    }
-
-    return dma_pos;
-}
-
-static int cs4231a_pre_load (void *opaque)
-{
-    CSState *s = opaque;
-
-    if (s->dma_running) {
-        DMA_release_DREQ (s->dma);
-        AUD_set_active_out (s->voice, 0);
-    }
-    s->dma_running = 0;
-    return 0;
-}
-
-static int cs4231a_post_load (void *opaque, int version_id)
-{
-    CSState *s = opaque;
-
-    if (s->dma_running && (s->dregs[Interface_Configuration] & PEN)) {
-        s->dma_running = 0;
-        cs_reset_voices (s, s->dregs[FS_And_Playback_Data_Format]);
-    }
-    return 0;
-}
-
-static const VMStateDescription vmstate_cs4231a = {
-    .name = "cs4231a",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .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 ()
-    }
-};
-
-static const MemoryRegionOps cs_ioport_ops = {
-    .read = cs_read,
-    .write = cs_write,
-    .impl = {
-        .min_access_size = 1,
-        .max_access_size = 1,
-    }
-};
-
-static int cs4231a_initfn (ISADevice *dev)
-{
-    CSState *s = DO_UPCAST (CSState, dev, dev);
-
-    isa_init_irq (dev, &s->pic, s->irq);
-
-    memory_region_init_io (&s->ioports, &cs_ioport_ops, s, "cs4231a", 4);
-    isa_register_ioport (dev, &s->ioports, s->port);
-
-    DMA_register_channel (s->dma, cs_dma_read, s);
-
-    qemu_register_reset (cs_reset, s);
-    cs_reset (s);
-
-    AUD_register_card ("cs4231a", &s->card);
-    return 0;
-}
-
-int cs4231a_init (ISABus *bus)
-{
-    isa_create_simple (bus, "cs4231a");
-    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 const TypeInfo cs4231a_info = {
-    .name          = "cs4231a",
-    .parent        = TYPE_ISA_DEVICE,
-    .instance_size = sizeof (CSState),
-    .class_init    = cs4231a_class_initfn,
-};
-
-static void cs4231a_register_types (void)
-{
-    type_register_static (&cs4231a_info);
-}
-
-type_init (cs4231a_register_types)
diff --git a/hw/cuda.c b/hw/cuda.c
deleted file mode 100644 (file)
index 2ae430d..0000000
--- a/hw/cuda.c
+++ /dev/null
@@ -1,740 +0,0 @@
-/*
- * QEMU PowerMac CUDA device support
- *
- * Copyright (c) 2004-2007 Fabrice Bellard
- * Copyright (c) 2007 Jocelyn Mayer
- *
- * 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 "hw/hw.h"
-#include "hw/ppc/mac.h"
-#include "hw/adb.h"
-#include "qemu/timer.h"
-#include "sysemu/sysemu.h"
-
-/* XXX: implement all timer modes */
-
-/* debug CUDA */
-//#define DEBUG_CUDA
-
-/* debug CUDA packets */
-//#define DEBUG_CUDA_PACKET
-
-#ifdef DEBUG_CUDA
-#define CUDA_DPRINTF(fmt, ...)                                  \
-    do { printf("CUDA: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define CUDA_DPRINTF(fmt, ...)
-#endif
-
-/* Bits in B data register: all active low */
-#define TREQ           0x08            /* Transfer request (input) */
-#define TACK           0x10            /* Transfer acknowledge (output) */
-#define TIP            0x20            /* Transfer in progress (output) */
-
-/* Bits in ACR */
-#define SR_CTRL                0x1c            /* Shift register control bits */
-#define SR_EXT         0x0c            /* Shift on external clock */
-#define SR_OUT         0x10            /* Shift out if 1 */
-
-/* Bits in IFR and IER */
-#define IER_SET                0x80            /* set bits in IER */
-#define IER_CLR                0               /* clear bits in IER */
-#define SR_INT         0x04            /* Shift register full/empty */
-#define T1_INT          0x40            /* Timer 1 interrupt */
-#define T2_INT          0x20            /* Timer 2 interrupt */
-
-/* Bits in ACR */
-#define T1MODE          0xc0            /* Timer 1 mode */
-#define T1MODE_CONT     0x40            /*  continuous interrupts */
-
-/* commands (1st byte) */
-#define ADB_PACKET     0
-#define CUDA_PACKET    1
-#define ERROR_PACKET   2
-#define TIMER_PACKET   3
-#define POWER_PACKET   4
-#define MACIIC_PACKET  5
-#define PMU_PACKET     6
-
-
-/* CUDA commands (2nd byte) */
-#define CUDA_WARM_START                        0x0
-#define CUDA_AUTOPOLL                  0x1
-#define CUDA_GET_6805_ADDR             0x2
-#define CUDA_GET_TIME                  0x3
-#define CUDA_GET_PRAM                  0x7
-#define CUDA_SET_6805_ADDR             0x8
-#define CUDA_SET_TIME                  0x9
-#define CUDA_POWERDOWN                 0xa
-#define CUDA_POWERUP_TIME              0xb
-#define CUDA_SET_PRAM                  0xc
-#define CUDA_MS_RESET                  0xd
-#define CUDA_SEND_DFAC                 0xe
-#define CUDA_BATTERY_SWAP_SENSE                0x10
-#define CUDA_RESET_SYSTEM              0x11
-#define CUDA_SET_IPL                   0x12
-#define CUDA_FILE_SERVER_FLAG          0x13
-#define CUDA_SET_AUTO_RATE             0x14
-#define CUDA_GET_AUTO_RATE             0x16
-#define CUDA_SET_DEVICE_LIST           0x19
-#define CUDA_GET_DEVICE_LIST           0x1a
-#define CUDA_SET_ONE_SECOND_MODE       0x1b
-#define CUDA_SET_POWER_MESSAGES                0x21
-#define CUDA_GET_SET_IIC               0x22
-#define CUDA_WAKEUP                    0x23
-#define CUDA_TIMER_TICKLE              0x24
-#define CUDA_COMBINED_FORMAT_IIC       0x25
-
-#define CUDA_TIMER_FREQ (4700000 / 6)
-#define CUDA_ADB_POLL_FREQ 50
-
-/* CUDA returns time_t's offset from Jan 1, 1904, not 1970 */
-#define RTC_OFFSET                      2082844800
-
-static void cuda_update(CUDAState *s);
-static void cuda_receive_packet_from_host(CUDAState *s,
-                                          const uint8_t *data, int len);
-static void cuda_timer_update(CUDAState *s, CUDATimer *ti,
-                              int64_t current_time);
-
-static void cuda_update_irq(CUDAState *s)
-{
-    if (s->ifr & s->ier & (SR_INT | T1_INT)) {
-        qemu_irq_raise(s->irq);
-    } else {
-        qemu_irq_lower(s->irq);
-    }
-}
-
-static unsigned int get_counter(CUDATimer *s)
-{
-    int64_t d;
-    unsigned int counter;
-
-    d = muldiv64(qemu_get_clock_ns(vm_clock) - s->load_time,
-                 CUDA_TIMER_FREQ, get_ticks_per_sec());
-    if (s->index == 0) {
-        /* the timer goes down from latch to -1 (period of latch + 2) */
-        if (d <= (s->counter_value + 1)) {
-            counter = (s->counter_value - d) & 0xffff;
-        } else {
-            counter = (d - (s->counter_value + 1)) % (s->latch + 2);
-            counter = (s->latch - counter) & 0xffff;
-        }
-    } else {
-        counter = (s->counter_value - d) & 0xffff;
-    }
-    return counter;
-}
-
-static void set_counter(CUDAState *s, CUDATimer *ti, unsigned int val)
-{
-    CUDA_DPRINTF("T%d.counter=%d\n", 1 + (ti->timer == NULL), val);
-    ti->load_time = qemu_get_clock_ns(vm_clock);
-    ti->counter_value = val;
-    cuda_timer_update(s, ti, ti->load_time);
-}
-
-static int64_t get_next_irq_time(CUDATimer *s, int64_t current_time)
-{
-    int64_t d, next_time;
-    unsigned int counter;
-
-    /* current counter value */
-    d = muldiv64(current_time - s->load_time,
-                 CUDA_TIMER_FREQ, get_ticks_per_sec());
-    /* the timer goes down from latch to -1 (period of latch + 2) */
-    if (d <= (s->counter_value + 1)) {
-        counter = (s->counter_value - d) & 0xffff;
-    } else {
-        counter = (d - (s->counter_value + 1)) % (s->latch + 2);
-        counter = (s->latch - counter) & 0xffff;
-    }
-
-    /* Note: we consider the irq is raised on 0 */
-    if (counter == 0xffff) {
-        next_time = d + s->latch + 1;
-    } else if (counter == 0) {
-        next_time = d + s->latch + 2;
-    } else {
-        next_time = d + counter;
-    }
-    CUDA_DPRINTF("latch=%d counter=%" PRId64 " delta_next=%" PRId64 "\n",
-                 s->latch, d, next_time - d);
-    next_time = muldiv64(next_time, get_ticks_per_sec(), CUDA_TIMER_FREQ) +
-        s->load_time;
-    if (next_time <= current_time)
-        next_time = current_time + 1;
-    return next_time;
-}
-
-static void cuda_timer_update(CUDAState *s, CUDATimer *ti,
-                              int64_t current_time)
-{
-    if (!ti->timer)
-        return;
-    if ((s->acr & T1MODE) != T1MODE_CONT) {
-        qemu_del_timer(ti->timer);
-    } else {
-        ti->next_irq_time = get_next_irq_time(ti, current_time);
-        qemu_mod_timer(ti->timer, ti->next_irq_time);
-    }
-}
-
-static void cuda_timer1(void *opaque)
-{
-    CUDAState *s = opaque;
-    CUDATimer *ti = &s->timers[0];
-
-    cuda_timer_update(s, ti, ti->next_irq_time);
-    s->ifr |= T1_INT;
-    cuda_update_irq(s);
-}
-
-static uint32_t cuda_readb(void *opaque, hwaddr addr)
-{
-    CUDAState *s = opaque;
-    uint32_t val;
-
-    addr = (addr >> 9) & 0xf;
-    switch(addr) {
-    case 0:
-        val = s->b;
-        break;
-    case 1:
-        val = s->a;
-        break;
-    case 2:
-        val = s->dirb;
-        break;
-    case 3:
-        val = s->dira;
-        break;
-    case 4:
-        val = get_counter(&s->timers[0]) & 0xff;
-        s->ifr &= ~T1_INT;
-        cuda_update_irq(s);
-        break;
-    case 5:
-        val = get_counter(&s->timers[0]) >> 8;
-        cuda_update_irq(s);
-        break;
-    case 6:
-        val = s->timers[0].latch & 0xff;
-        break;
-    case 7:
-        /* XXX: check this */
-        val = (s->timers[0].latch >> 8) & 0xff;
-        break;
-    case 8:
-        val = get_counter(&s->timers[1]) & 0xff;
-        s->ifr &= ~T2_INT;
-        break;
-    case 9:
-        val = get_counter(&s->timers[1]) >> 8;
-        break;
-    case 10:
-        val = s->sr;
-        s->ifr &= ~SR_INT;
-        cuda_update_irq(s);
-        break;
-    case 11:
-        val = s->acr;
-        break;
-    case 12:
-        val = s->pcr;
-        break;
-    case 13:
-        val = s->ifr;
-        if (s->ifr & s->ier)
-            val |= 0x80;
-        break;
-    case 14:
-        val = s->ier | 0x80;
-        break;
-    default:
-    case 15:
-        val = s->anh;
-        break;
-    }
-    if (addr != 13 || val != 0) {
-        CUDA_DPRINTF("read: reg=0x%x val=%02x\n", (int)addr, val);
-    }
-
-    return val;
-}
-
-static void cuda_writeb(void *opaque, hwaddr addr, uint32_t val)
-{
-    CUDAState *s = opaque;
-
-    addr = (addr >> 9) & 0xf;
-    CUDA_DPRINTF("write: reg=0x%x val=%02x\n", (int)addr, val);
-
-    switch(addr) {
-    case 0:
-        s->b = val;
-        cuda_update(s);
-        break;
-    case 1:
-        s->a = val;
-        break;
-    case 2:
-        s->dirb = val;
-        break;
-    case 3:
-        s->dira = val;
-        break;
-    case 4:
-        s->timers[0].latch = (s->timers[0].latch & 0xff00) | val;
-        cuda_timer_update(s, &s->timers[0], qemu_get_clock_ns(vm_clock));
-        break;
-    case 5:
-        s->timers[0].latch = (s->timers[0].latch & 0xff) | (val << 8);
-        s->ifr &= ~T1_INT;
-        set_counter(s, &s->timers[0], s->timers[0].latch);
-        break;
-    case 6:
-        s->timers[0].latch = (s->timers[0].latch & 0xff00) | val;
-        cuda_timer_update(s, &s->timers[0], qemu_get_clock_ns(vm_clock));
-        break;
-    case 7:
-        s->timers[0].latch = (s->timers[0].latch & 0xff) | (val << 8);
-        s->ifr &= ~T1_INT;
-        cuda_timer_update(s, &s->timers[0], qemu_get_clock_ns(vm_clock));
-        break;
-    case 8:
-        s->timers[1].latch = val;
-        set_counter(s, &s->timers[1], val);
-        break;
-    case 9:
-        set_counter(s, &s->timers[1], (val << 8) | s->timers[1].latch);
-        break;
-    case 10:
-        s->sr = val;
-        break;
-    case 11:
-        s->acr = val;
-        cuda_timer_update(s, &s->timers[0], qemu_get_clock_ns(vm_clock));
-        cuda_update(s);
-        break;
-    case 12:
-        s->pcr = val;
-        break;
-    case 13:
-        /* reset bits */
-        s->ifr &= ~val;
-        cuda_update_irq(s);
-        break;
-    case 14:
-        if (val & IER_SET) {
-            /* set bits */
-            s->ier |= val & 0x7f;
-        } else {
-            /* reset bits */
-            s->ier &= ~val;
-        }
-        cuda_update_irq(s);
-        break;
-    default:
-    case 15:
-        s->anh = val;
-        break;
-    }
-}
-
-/* NOTE: TIP and TREQ are negated */
-static void cuda_update(CUDAState *s)
-{
-    int packet_received, len;
-
-    packet_received = 0;
-    if (!(s->b & TIP)) {
-        /* transfer requested from host */
-
-        if (s->acr & SR_OUT) {
-            /* data output */
-            if ((s->b & (TACK | TIP)) != (s->last_b & (TACK | TIP))) {
-                if (s->data_out_index < sizeof(s->data_out)) {
-                    CUDA_DPRINTF("send: %02x\n", s->sr);
-                    s->data_out[s->data_out_index++] = s->sr;
-                    s->ifr |= SR_INT;
-                    cuda_update_irq(s);
-                }
-            }
-        } else {
-            if (s->data_in_index < s->data_in_size) {
-                /* data input */
-                if ((s->b & (TACK | TIP)) != (s->last_b & (TACK | TIP))) {
-                    s->sr = s->data_in[s->data_in_index++];
-                    CUDA_DPRINTF("recv: %02x\n", s->sr);
-                    /* indicate end of transfer */
-                    if (s->data_in_index >= s->data_in_size) {
-                        s->b = (s->b | TREQ);
-                    }
-                    s->ifr |= SR_INT;
-                    cuda_update_irq(s);
-                }
-            }
-        }
-    } else {
-        /* no transfer requested: handle sync case */
-        if ((s->last_b & TIP) && (s->b & TACK) != (s->last_b & TACK)) {
-            /* update TREQ state each time TACK change state */
-            if (s->b & TACK)
-                s->b = (s->b | TREQ);
-            else
-                s->b = (s->b & ~TREQ);
-            s->ifr |= SR_INT;
-            cuda_update_irq(s);
-        } else {
-            if (!(s->last_b & TIP)) {
-                /* handle end of host to cuda transfer */
-                packet_received = (s->data_out_index > 0);
-                /* always an IRQ at the end of transfer */
-                s->ifr |= SR_INT;
-                cuda_update_irq(s);
-            }
-            /* signal if there is data to read */
-            if (s->data_in_index < s->data_in_size) {
-                s->b = (s->b & ~TREQ);
-            }
-        }
-    }
-
-    s->last_acr = s->acr;
-    s->last_b = s->b;
-
-    /* NOTE: cuda_receive_packet_from_host() can call cuda_update()
-       recursively */
-    if (packet_received) {
-        len = s->data_out_index;
-        s->data_out_index = 0;
-        cuda_receive_packet_from_host(s, s->data_out, len);
-    }
-}
-
-static void cuda_send_packet_to_host(CUDAState *s,
-                                     const uint8_t *data, int len)
-{
-#ifdef DEBUG_CUDA_PACKET
-    {
-        int i;
-        printf("cuda_send_packet_to_host:\n");
-        for(i = 0; i < len; i++)
-            printf(" %02x", data[i]);
-        printf("\n");
-    }
-#endif
-    memcpy(s->data_in, data, len);
-    s->data_in_size = len;
-    s->data_in_index = 0;
-    cuda_update(s);
-    s->ifr |= SR_INT;
-    cuda_update_irq(s);
-}
-
-static void cuda_adb_poll(void *opaque)
-{
-    CUDAState *s = opaque;
-    uint8_t obuf[ADB_MAX_OUT_LEN + 2];
-    int olen;
-
-    olen = adb_poll(&s->adb_bus, obuf + 2);
-    if (olen > 0) {
-        obuf[0] = ADB_PACKET;
-        obuf[1] = 0x40; /* polled data */
-        cuda_send_packet_to_host(s, obuf, olen + 2);
-    }
-    qemu_mod_timer(s->adb_poll_timer,
-                   qemu_get_clock_ns(vm_clock) +
-                   (get_ticks_per_sec() / CUDA_ADB_POLL_FREQ));
-}
-
-static void cuda_receive_packet(CUDAState *s,
-                                const uint8_t *data, int len)
-{
-    uint8_t obuf[16];
-    int autopoll;
-    uint32_t ti;
-
-    switch(data[0]) {
-    case CUDA_AUTOPOLL:
-        autopoll = (data[1] != 0);
-        if (autopoll != s->autopoll) {
-            s->autopoll = autopoll;
-            if (autopoll) {
-                qemu_mod_timer(s->adb_poll_timer,
-                               qemu_get_clock_ns(vm_clock) +
-                               (get_ticks_per_sec() / CUDA_ADB_POLL_FREQ));
-            } else {
-                qemu_del_timer(s->adb_poll_timer);
-            }
-        }
-        obuf[0] = CUDA_PACKET;
-        obuf[1] = data[1];
-        cuda_send_packet_to_host(s, obuf, 2);
-        break;
-    case CUDA_SET_TIME:
-        ti = (((uint32_t)data[1]) << 24) + (((uint32_t)data[2]) << 16) + (((uint32_t)data[3]) << 8) + data[4];
-        s->tick_offset = ti - (qemu_get_clock_ns(vm_clock) / get_ticks_per_sec());
-        obuf[0] = CUDA_PACKET;
-        obuf[1] = 0;
-        obuf[2] = 0;
-        cuda_send_packet_to_host(s, obuf, 3);
-        break;
-    case CUDA_GET_TIME:
-        ti = s->tick_offset + (qemu_get_clock_ns(vm_clock) / get_ticks_per_sec());
-        obuf[0] = CUDA_PACKET;
-        obuf[1] = 0;
-        obuf[2] = 0;
-        obuf[3] = ti >> 24;
-        obuf[4] = ti >> 16;
-        obuf[5] = ti >> 8;
-        obuf[6] = ti;
-        cuda_send_packet_to_host(s, obuf, 7);
-        break;
-    case CUDA_FILE_SERVER_FLAG:
-    case CUDA_SET_DEVICE_LIST:
-    case CUDA_SET_AUTO_RATE:
-    case CUDA_SET_POWER_MESSAGES:
-        obuf[0] = CUDA_PACKET;
-        obuf[1] = 0;
-        cuda_send_packet_to_host(s, obuf, 2);
-        break;
-    case CUDA_POWERDOWN:
-        obuf[0] = CUDA_PACKET;
-        obuf[1] = 0;
-        cuda_send_packet_to_host(s, obuf, 2);
-        qemu_system_shutdown_request();
-        break;
-    case CUDA_RESET_SYSTEM:
-        obuf[0] = CUDA_PACKET;
-        obuf[1] = 0;
-        cuda_send_packet_to_host(s, obuf, 2);
-        qemu_system_reset_request();
-        break;
-    default:
-        break;
-    }
-}
-
-static void cuda_receive_packet_from_host(CUDAState *s,
-                                          const uint8_t *data, int len)
-{
-#ifdef DEBUG_CUDA_PACKET
-    {
-        int i;
-        printf("cuda_receive_packet_from_host:\n");
-        for(i = 0; i < len; i++)
-            printf(" %02x", data[i]);
-        printf("\n");
-    }
-#endif
-    switch(data[0]) {
-    case ADB_PACKET:
-        {
-            uint8_t obuf[ADB_MAX_OUT_LEN + 2];
-            int olen;
-            olen = adb_request(&s->adb_bus, obuf + 2, data + 1, len - 1);
-            if (olen > 0) {
-                obuf[0] = ADB_PACKET;
-                obuf[1] = 0x00;
-            } else {
-                /* error */
-                obuf[0] = ADB_PACKET;
-                obuf[1] = -olen;
-                olen = 0;
-            }
-            cuda_send_packet_to_host(s, obuf, olen + 2);
-        }
-        break;
-    case CUDA_PACKET:
-        cuda_receive_packet(s, data + 1, len - 1);
-        break;
-    }
-}
-
-static void cuda_writew (void *opaque, hwaddr addr, uint32_t value)
-{
-}
-
-static void cuda_writel (void *opaque, hwaddr addr, uint32_t value)
-{
-}
-
-static uint32_t cuda_readw (void *opaque, hwaddr addr)
-{
-    return 0;
-}
-
-static uint32_t cuda_readl (void *opaque, hwaddr addr)
-{
-    return 0;
-}
-
-static const MemoryRegionOps cuda_ops = {
-    .old_mmio = {
-        .write = {
-            cuda_writeb,
-            cuda_writew,
-            cuda_writel,
-        },
-        .read = {
-            cuda_readb,
-            cuda_readw,
-            cuda_readl,
-        },
-    },
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static bool cuda_timer_exist(void *opaque, int version_id)
-{
-    CUDATimer *s = opaque;
-
-    return s->timer != NULL;
-}
-
-static const VMStateDescription vmstate_cuda_timer = {
-    .name = "cuda_timer",
-    .version_id = 0,
-    .minimum_version_id = 0,
-    .minimum_version_id_old = 0,
-    .fields      = (VMStateField[]) {
-        VMSTATE_UINT16(latch, CUDATimer),
-        VMSTATE_UINT16(counter_value, CUDATimer),
-        VMSTATE_INT64(load_time, CUDATimer),
-        VMSTATE_INT64(next_irq_time, CUDATimer),
-        VMSTATE_TIMER_TEST(timer, CUDATimer, cuda_timer_exist),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static const VMStateDescription vmstate_cuda = {
-    .name = "cuda",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField[]) {
-        VMSTATE_UINT8(a, CUDAState),
-        VMSTATE_UINT8(b, CUDAState),
-        VMSTATE_UINT8(dira, CUDAState),
-        VMSTATE_UINT8(dirb, CUDAState),
-        VMSTATE_UINT8(sr, CUDAState),
-        VMSTATE_UINT8(acr, CUDAState),
-        VMSTATE_UINT8(pcr, CUDAState),
-        VMSTATE_UINT8(ifr, CUDAState),
-        VMSTATE_UINT8(ier, CUDAState),
-        VMSTATE_UINT8(anh, CUDAState),
-        VMSTATE_INT32(data_in_size, CUDAState),
-        VMSTATE_INT32(data_in_index, CUDAState),
-        VMSTATE_INT32(data_out_index, CUDAState),
-        VMSTATE_UINT8(autopoll, CUDAState),
-        VMSTATE_BUFFER(data_in, CUDAState),
-        VMSTATE_BUFFER(data_out, CUDAState),
-        VMSTATE_UINT32(tick_offset, CUDAState),
-        VMSTATE_STRUCT_ARRAY(timers, CUDAState, 2, 1,
-                             vmstate_cuda_timer, CUDATimer),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void cuda_reset(DeviceState *dev)
-{
-    CUDAState *s = CUDA(dev);
-
-    s->b = 0;
-    s->a = 0;
-    s->dirb = 0;
-    s->dira = 0;
-    s->sr = 0;
-    s->acr = 0;
-    s->pcr = 0;
-    s->ifr = 0;
-    s->ier = 0;
-    //    s->ier = T1_INT | SR_INT;
-    s->anh = 0;
-    s->data_in_size = 0;
-    s->data_in_index = 0;
-    s->data_out_index = 0;
-    s->autopoll = 0;
-
-    s->timers[0].latch = 0xffff;
-    set_counter(s, &s->timers[0], 0xffff);
-
-    s->timers[1].latch = 0;
-    set_counter(s, &s->timers[1], 0xffff);
-}
-
-static void cuda_realizefn(DeviceState *dev, Error **errp)
-{
-    CUDAState *s = CUDA(dev);
-    struct tm tm;
-
-    s->timers[0].timer = qemu_new_timer_ns(vm_clock, cuda_timer1, s);
-
-    qemu_get_timedate(&tm, 0);
-    s->tick_offset = (uint32_t)mktimegm(&tm) + RTC_OFFSET;
-
-    s->adb_poll_timer = qemu_new_timer_ns(vm_clock, cuda_adb_poll, s);
-}
-
-static void cuda_initfn(Object *obj)
-{
-    SysBusDevice *d = SYS_BUS_DEVICE(obj);
-    CUDAState *s = CUDA(obj);
-    int i;
-
-    memory_region_init_io(&s->mem, &cuda_ops, s, "cuda", 0x2000);
-    sysbus_init_mmio(d, &s->mem);
-    sysbus_init_irq(d, &s->irq);
-
-    for (i = 0; i < ARRAY_SIZE(s->timers); i++) {
-        s->timers[i].index = i;
-    }
-
-    qbus_create_inplace((BusState *)&s->adb_bus, TYPE_ADB_BUS, DEVICE(obj),
-                        "adb.0");
-}
-
-static void cuda_class_init(ObjectClass *oc, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(oc);
-
-    dc->realize = cuda_realizefn;
-    dc->reset = cuda_reset;
-    dc->vmsd = &vmstate_cuda;
-}
-
-static const TypeInfo cuda_type_info = {
-    .name = TYPE_CUDA,
-    .parent = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(CUDAState),
-    .instance_init = cuda_initfn,
-    .class_init = cuda_class_init,
-};
-
-static void cuda_register_types(void)
-{
-    type_register_static(&cuda_type_info);
-}
-
-type_init(cuda_register_types)
diff --git a/hw/dataplane/Makefile.objs b/hw/dataplane/Makefile.objs
deleted file mode 100644 (file)
index 701111c..0000000
+++ /dev/null
@@ -1 +0,0 @@
-obj-$(CONFIG_VIRTIO_BLK_DATA_PLANE) += hostmem.o vring.o ioq.o virtio-blk.o
diff --git a/hw/dataplane/hostmem.c b/hw/dataplane/hostmem.c
deleted file mode 100644 (file)
index 380537e..0000000
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * Thread-safe guest to host memory mapping
- *
- * Copyright 2012 Red Hat, Inc. and/or its affiliates
- *
- * Authors:
- *   Stefan Hajnoczi <stefanha@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 "exec/address-spaces.h"
-#include "hostmem.h"
-
-static int hostmem_lookup_cmp(const void *phys_, const void *region_)
-{
-    hwaddr phys = *(const hwaddr *)phys_;
-    const HostMemRegion *region = region_;
-
-    if (phys < region->guest_addr) {
-        return -1;
-    } else if (phys >= region->guest_addr + region->size) {
-        return 1;
-    } else {
-        return 0;
-    }
-}
-
-/**
- * Map guest physical address to host pointer
- */
-void *hostmem_lookup(HostMem *hostmem, hwaddr phys, hwaddr len, bool is_write)
-{
-    HostMemRegion *region;
-    void *host_addr = NULL;
-    hwaddr offset_within_region;
-
-    qemu_mutex_lock(&hostmem->current_regions_lock);
-    region = bsearch(&phys, hostmem->current_regions,
-                     hostmem->num_current_regions,
-                     sizeof(hostmem->current_regions[0]),
-                     hostmem_lookup_cmp);
-    if (!region) {
-        goto out;
-    }
-    if (is_write && region->readonly) {
-        goto out;
-    }
-    offset_within_region = phys - region->guest_addr;
-    if (len <= region->size - offset_within_region) {
-        host_addr = region->host_addr + offset_within_region;
-    }
-out:
-    qemu_mutex_unlock(&hostmem->current_regions_lock);
-
-    return host_addr;
-}
-
-/**
- * Install new regions list
- */
-static void hostmem_listener_commit(MemoryListener *listener)
-{
-    HostMem *hostmem = container_of(listener, HostMem, listener);
-
-    qemu_mutex_lock(&hostmem->current_regions_lock);
-    g_free(hostmem->current_regions);
-    hostmem->current_regions = hostmem->new_regions;
-    hostmem->num_current_regions = hostmem->num_new_regions;
-    qemu_mutex_unlock(&hostmem->current_regions_lock);
-
-    /* Reset new regions list */
-    hostmem->new_regions = NULL;
-    hostmem->num_new_regions = 0;
-}
-
-/**
- * Add a MemoryRegionSection to the new regions list
- */
-static void hostmem_append_new_region(HostMem *hostmem,
-                                      MemoryRegionSection *section)
-{
-    void *ram_ptr = memory_region_get_ram_ptr(section->mr);
-    size_t num = hostmem->num_new_regions;
-    size_t new_size = (num + 1) * sizeof(hostmem->new_regions[0]);
-
-    hostmem->new_regions = g_realloc(hostmem->new_regions, new_size);
-    hostmem->new_regions[num] = (HostMemRegion){
-        .host_addr = ram_ptr + section->offset_within_region,
-        .guest_addr = section->offset_within_address_space,
-        .size = section->size,
-        .readonly = section->readonly,
-    };
-    hostmem->num_new_regions++;
-}
-
-static void hostmem_listener_append_region(MemoryListener *listener,
-                                           MemoryRegionSection *section)
-{
-    HostMem *hostmem = container_of(listener, HostMem, listener);
-
-    /* Ignore non-RAM regions, we may not be able to map them */
-    if (!memory_region_is_ram(section->mr)) {
-        return;
-    }
-
-    /* Ignore regions with dirty logging, we cannot mark them dirty */
-    if (memory_region_is_logging(section->mr)) {
-        return;
-    }
-
-    hostmem_append_new_region(hostmem, section);
-}
-
-/* We don't implement most MemoryListener callbacks, use these nop stubs */
-static void hostmem_listener_dummy(MemoryListener *listener)
-{
-}
-
-static void hostmem_listener_section_dummy(MemoryListener *listener,
-                                           MemoryRegionSection *section)
-{
-}
-
-static void hostmem_listener_eventfd_dummy(MemoryListener *listener,
-                                           MemoryRegionSection *section,
-                                           bool match_data, uint64_t data,
-                                           EventNotifier *e)
-{
-}
-
-static void hostmem_listener_coalesced_mmio_dummy(MemoryListener *listener,
-                                                  MemoryRegionSection *section,
-                                                  hwaddr addr, hwaddr len)
-{
-}
-
-void hostmem_init(HostMem *hostmem)
-{
-    memset(hostmem, 0, sizeof(*hostmem));
-
-    qemu_mutex_init(&hostmem->current_regions_lock);
-
-    hostmem->listener = (MemoryListener){
-        .begin = hostmem_listener_dummy,
-        .commit = hostmem_listener_commit,
-        .region_add = hostmem_listener_append_region,
-        .region_del = hostmem_listener_section_dummy,
-        .region_nop = hostmem_listener_append_region,
-        .log_start = hostmem_listener_section_dummy,
-        .log_stop = hostmem_listener_section_dummy,
-        .log_sync = hostmem_listener_section_dummy,
-        .log_global_start = hostmem_listener_dummy,
-        .log_global_stop = hostmem_listener_dummy,
-        .eventfd_add = hostmem_listener_eventfd_dummy,
-        .eventfd_del = hostmem_listener_eventfd_dummy,
-        .coalesced_mmio_add = hostmem_listener_coalesced_mmio_dummy,
-        .coalesced_mmio_del = hostmem_listener_coalesced_mmio_dummy,
-        .priority = 10,
-    };
-
-    memory_listener_register(&hostmem->listener, &address_space_memory);
-    if (hostmem->num_new_regions > 0) {
-        hostmem_listener_commit(&hostmem->listener);
-    }
-}
-
-void hostmem_finalize(HostMem *hostmem)
-{
-    memory_listener_unregister(&hostmem->listener);
-    g_free(hostmem->new_regions);
-    g_free(hostmem->current_regions);
-    qemu_mutex_destroy(&hostmem->current_regions_lock);
-}
diff --git a/hw/dataplane/hostmem.h b/hw/dataplane/hostmem.h
deleted file mode 100644 (file)
index b2cf093..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Thread-safe guest to host memory mapping
- *
- * Copyright 2012 Red Hat, Inc. and/or its affiliates
- *
- * Authors:
- *   Stefan Hajnoczi <stefanha@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 HOSTMEM_H
-#define HOSTMEM_H
-
-#include "exec/memory.h"
-#include "qemu/thread.h"
-
-typedef struct {
-    void *host_addr;
-    hwaddr guest_addr;
-    uint64_t size;
-    bool readonly;
-} HostMemRegion;
-
-typedef struct {
-    /* The listener is invoked when regions change and a new list of regions is
-     * built up completely before they are installed.
-     */
-    MemoryListener listener;
-    HostMemRegion *new_regions;
-    size_t num_new_regions;
-
-    /* Current regions are accessed from multiple threads either to lookup
-     * addresses or to install a new list of regions.  The lock protects the
-     * pointer and the regions.
-     */
-    QemuMutex current_regions_lock;
-    HostMemRegion *current_regions;
-    size_t num_current_regions;
-} HostMem;
-
-void hostmem_init(HostMem *hostmem);
-void hostmem_finalize(HostMem *hostmem);
-
-/**
- * Map a guest physical address to a pointer
- *
- * Note that there is map/unmap mechanism here.  The caller must ensure that
- * mapped memory is no longer used across events like hot memory unplug.  This
- * can be done with other mechanisms like bdrv_drain_all() that quiesce
- * in-flight I/O.
- */
-void *hostmem_lookup(HostMem *hostmem, hwaddr phys, hwaddr len, bool is_write);
-
-#endif /* HOSTMEM_H */
diff --git a/hw/dataplane/ioq.c b/hw/dataplane/ioq.c
deleted file mode 100644 (file)
index f709f87..0000000
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Linux AIO request queue
- *
- * Copyright 2012 IBM, Corp.
- * Copyright 2012 Red Hat, Inc. and/or its affiliates
- *
- * Authors:
- *   Stefan Hajnoczi <stefanha@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 "ioq.h"
-
-void ioq_init(IOQueue *ioq, int fd, unsigned int max_reqs)
-{
-    int rc;
-
-    ioq->fd = fd;
-    ioq->max_reqs = max_reqs;
-
-    memset(&ioq->io_ctx, 0, sizeof ioq->io_ctx);
-    rc = io_setup(max_reqs, &ioq->io_ctx);
-    if (rc != 0) {
-        fprintf(stderr, "ioq io_setup failed %d\n", rc);
-        exit(1);
-    }
-
-    rc = event_notifier_init(&ioq->io_notifier, 0);
-    if (rc != 0) {
-        fprintf(stderr, "ioq io event notifier creation failed %d\n", rc);
-        exit(1);
-    }
-
-    ioq->freelist = g_malloc0(sizeof ioq->freelist[0] * max_reqs);
-    ioq->freelist_idx = 0;
-
-    ioq->queue = g_malloc0(sizeof ioq->queue[0] * max_reqs);
-    ioq->queue_idx = 0;
-}
-
-void ioq_cleanup(IOQueue *ioq)
-{
-    g_free(ioq->freelist);
-    g_free(ioq->queue);
-
-    event_notifier_cleanup(&ioq->io_notifier);
-    io_destroy(ioq->io_ctx);
-}
-
-EventNotifier *ioq_get_notifier(IOQueue *ioq)
-{
-    return &ioq->io_notifier;
-}
-
-struct iocb *ioq_get_iocb(IOQueue *ioq)
-{
-    /* Underflow cannot happen since ioq is sized for max_reqs */
-    assert(ioq->freelist_idx != 0);
-
-    struct iocb *iocb = ioq->freelist[--ioq->freelist_idx];
-    ioq->queue[ioq->queue_idx++] = iocb;
-    return iocb;
-}
-
-void ioq_put_iocb(IOQueue *ioq, struct iocb *iocb)
-{
-    /* Overflow cannot happen since ioq is sized for max_reqs */
-    assert(ioq->freelist_idx != ioq->max_reqs);
-
-    ioq->freelist[ioq->freelist_idx++] = iocb;
-}
-
-struct iocb *ioq_rdwr(IOQueue *ioq, bool read, struct iovec *iov,
-                      unsigned int count, long long offset)
-{
-    struct iocb *iocb = ioq_get_iocb(ioq);
-
-    if (read) {
-        io_prep_preadv(iocb, ioq->fd, iov, count, offset);
-    } else {
-        io_prep_pwritev(iocb, ioq->fd, iov, count, offset);
-    }
-    io_set_eventfd(iocb, event_notifier_get_fd(&ioq->io_notifier));
-    return iocb;
-}
-
-int ioq_submit(IOQueue *ioq)
-{
-    int rc = io_submit(ioq->io_ctx, ioq->queue_idx, ioq->queue);
-    ioq->queue_idx = 0; /* reset */
-    return rc;
-}
-
-int ioq_run_completion(IOQueue *ioq, IOQueueCompletion *completion,
-                       void *opaque)
-{
-    struct io_event events[ioq->max_reqs];
-    int nevents, i;
-
-    do {
-        nevents = io_getevents(ioq->io_ctx, 0, ioq->max_reqs, events, NULL);
-    } while (nevents < 0 && errno == EINTR);
-    if (nevents < 0) {
-        return nevents;
-    }
-
-    for (i = 0; i < nevents; i++) {
-        ssize_t ret = ((uint64_t)events[i].res2 << 32) | events[i].res;
-
-        completion(events[i].obj, ret, opaque);
-        ioq_put_iocb(ioq, events[i].obj);
-    }
-    return nevents;
-}
diff --git a/hw/dataplane/ioq.h b/hw/dataplane/ioq.h
deleted file mode 100644 (file)
index b49b5de..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Linux AIO request queue
- *
- * Copyright 2012 IBM, Corp.
- * Copyright 2012 Red Hat, Inc. and/or its affiliates
- *
- * Authors:
- *   Stefan Hajnoczi <stefanha@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 IOQ_H
-#define IOQ_H
-
-#include <libaio.h>
-#include "qemu/event_notifier.h"
-
-typedef struct {
-    int fd;                         /* file descriptor */
-    unsigned int max_reqs;          /* max length of freelist and queue */
-
-    io_context_t io_ctx;            /* Linux AIO context */
-    EventNotifier io_notifier;      /* Linux AIO eventfd */
-
-    /* Requests can complete in any order so a free list is necessary to manage
-     * available iocbs.
-     */
-    struct iocb **freelist;         /* free iocbs */
-    unsigned int freelist_idx;
-
-    /* Multiple requests are queued up before submitting them all in one go */
-    struct iocb **queue;            /* queued iocbs */
-    unsigned int queue_idx;
-} IOQueue;
-
-void ioq_init(IOQueue *ioq, int fd, unsigned int max_reqs);
-void ioq_cleanup(IOQueue *ioq);
-EventNotifier *ioq_get_notifier(IOQueue *ioq);
-struct iocb *ioq_get_iocb(IOQueue *ioq);
-void ioq_put_iocb(IOQueue *ioq, struct iocb *iocb);
-struct iocb *ioq_rdwr(IOQueue *ioq, bool read, struct iovec *iov,
-                      unsigned int count, long long offset);
-int ioq_submit(IOQueue *ioq);
-
-static inline unsigned int ioq_num_queued(IOQueue *ioq)
-{
-    return ioq->queue_idx;
-}
-
-typedef void IOQueueCompletion(struct iocb *iocb, ssize_t ret, void *opaque);
-int ioq_run_completion(IOQueue *ioq, IOQueueCompletion *completion,
-                       void *opaque);
-
-#endif /* IOQ_H */
diff --git a/hw/dataplane/virtio-blk.c b/hw/dataplane/virtio-blk.c
deleted file mode 100644 (file)
index 1242d61..0000000
+++ /dev/null
@@ -1,540 +0,0 @@
-/*
- * Dedicated thread for virtio-blk I/O processing
- *
- * Copyright 2012 IBM, Corp.
- * Copyright 2012 Red Hat, Inc. and/or its affiliates
- *
- * Authors:
- *   Stefan Hajnoczi <stefanha@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 "trace.h"
-#include "qemu/iov.h"
-#include "qemu/thread.h"
-#include "qemu/error-report.h"
-#include "vring.h"
-#include "ioq.h"
-#include "migration/migration.h"
-#include "block/block.h"
-#include "hw/virtio-blk.h"
-#include "hw/dataplane/virtio-blk.h"
-#include "block/aio.h"
-
-enum {
-    SEG_MAX = 126,                  /* maximum number of I/O segments */
-    VRING_MAX = SEG_MAX + 2,        /* maximum number of vring descriptors */
-    REQ_MAX = VRING_MAX,            /* maximum number of requests in the vring,
-                                     * is VRING_MAX / 2 with traditional and
-                                     * VRING_MAX with indirect descriptors */
-};
-
-typedef struct {
-    struct iocb iocb;               /* Linux AIO control block */
-    QEMUIOVector *inhdr;            /* iovecs for virtio_blk_inhdr */
-    unsigned int head;              /* vring descriptor index */
-    struct iovec *bounce_iov;       /* used if guest buffers are unaligned */
-    QEMUIOVector *read_qiov;        /* for read completion /w bounce buffer */
-} VirtIOBlockRequest;
-
-struct VirtIOBlockDataPlane {
-    bool started;
-    bool stopping;
-    QEMUBH *start_bh;
-    QemuThread thread;
-
-    VirtIOBlkConf *blk;
-    int fd;                         /* image file descriptor */
-
-    VirtIODevice *vdev;
-    Vring vring;                    /* virtqueue vring */
-    EventNotifier *guest_notifier;  /* irq */
-
-    /* Note that these EventNotifiers are assigned by value.  This is
-     * fine as long as you do not call event_notifier_cleanup on them
-     * (because you don't own the file descriptor or handle; you just
-     * use it).
-     */
-    AioContext *ctx;
-    EventNotifier io_notifier;      /* Linux AIO completion */
-    EventNotifier host_notifier;    /* doorbell */
-
-    IOQueue ioqueue;                /* Linux AIO queue (should really be per
-                                       dataplane thread) */
-    VirtIOBlockRequest requests[REQ_MAX]; /* pool of requests, managed by the
-                                             queue */
-
-    unsigned int num_reqs;
-
-    Error *migration_blocker;
-};
-
-/* Raise an interrupt to signal guest, if necessary */
-static void notify_guest(VirtIOBlockDataPlane *s)
-{
-    if (!vring_should_notify(s->vdev, &s->vring)) {
-        return;
-    }
-
-    event_notifier_set(s->guest_notifier);
-}
-
-static void complete_request(struct iocb *iocb, ssize_t ret, void *opaque)
-{
-    VirtIOBlockDataPlane *s = opaque;
-    VirtIOBlockRequest *req = container_of(iocb, VirtIOBlockRequest, iocb);
-    struct virtio_blk_inhdr hdr;
-    int len;
-
-    if (likely(ret >= 0)) {
-        hdr.status = VIRTIO_BLK_S_OK;
-        len = ret;
-    } else {
-        hdr.status = VIRTIO_BLK_S_IOERR;
-        len = 0;
-    }
-
-    trace_virtio_blk_data_plane_complete_request(s, req->head, ret);
-
-    if (req->read_qiov) {
-        assert(req->bounce_iov);
-        qemu_iovec_from_buf(req->read_qiov, 0, req->bounce_iov->iov_base, len);
-        qemu_iovec_destroy(req->read_qiov);
-        g_slice_free(QEMUIOVector, req->read_qiov);
-    }
-
-    if (req->bounce_iov) {
-        qemu_vfree(req->bounce_iov->iov_base);
-        g_slice_free(struct iovec, req->bounce_iov);
-    }
-
-    qemu_iovec_from_buf(req->inhdr, 0, &hdr, sizeof(hdr));
-    qemu_iovec_destroy(req->inhdr);
-    g_slice_free(QEMUIOVector, req->inhdr);
-
-    /* According to the virtio specification len should be the number of bytes
-     * written to, but for virtio-blk it seems to be the number of bytes
-     * transferred plus the status bytes.
-     */
-    vring_push(&s->vring, req->head, len + sizeof(hdr));
-
-    s->num_reqs--;
-}
-
-static void complete_request_early(VirtIOBlockDataPlane *s, unsigned int head,
-                                   QEMUIOVector *inhdr, unsigned char status)
-{
-    struct virtio_blk_inhdr hdr = {
-        .status = status,
-    };
-
-    qemu_iovec_from_buf(inhdr, 0, &hdr, sizeof(hdr));
-    qemu_iovec_destroy(inhdr);
-    g_slice_free(QEMUIOVector, inhdr);
-
-    vring_push(&s->vring, head, sizeof(hdr));
-    notify_guest(s);
-}
-
-/* Get disk serial number */
-static void do_get_id_cmd(VirtIOBlockDataPlane *s,
-                          struct iovec *iov, unsigned int iov_cnt,
-                          unsigned int head, QEMUIOVector *inhdr)
-{
-    char id[VIRTIO_BLK_ID_BYTES];
-
-    /* Serial number not NUL-terminated when shorter than buffer */
-    strncpy(id, s->blk->serial ? s->blk->serial : "", sizeof(id));
-    iov_from_buf(iov, iov_cnt, 0, id, sizeof(id));
-    complete_request_early(s, head, inhdr, VIRTIO_BLK_S_OK);
-}
-
-static int do_rdwr_cmd(VirtIOBlockDataPlane *s, bool read,
-                       struct iovec *iov, unsigned int iov_cnt,
-                       long long offset, unsigned int head,
-                       QEMUIOVector *inhdr)
-{
-    struct iocb *iocb;
-    QEMUIOVector qiov;
-    struct iovec *bounce_iov = NULL;
-    QEMUIOVector *read_qiov = NULL;
-
-    qemu_iovec_init_external(&qiov, iov, iov_cnt);
-    if (!bdrv_qiov_is_aligned(s->blk->conf.bs, &qiov)) {
-        void *bounce_buffer = qemu_blockalign(s->blk->conf.bs, qiov.size);
-
-        if (read) {
-            /* Need to copy back from bounce buffer on completion */
-            read_qiov = g_slice_new(QEMUIOVector);
-            qemu_iovec_init(read_qiov, iov_cnt);
-            qemu_iovec_concat_iov(read_qiov, iov, iov_cnt, 0, qiov.size);
-        } else {
-            qemu_iovec_to_buf(&qiov, 0, bounce_buffer, qiov.size);
-        }
-
-        /* Redirect I/O to aligned bounce buffer */
-        bounce_iov = g_slice_new(struct iovec);
-        bounce_iov->iov_base = bounce_buffer;
-        bounce_iov->iov_len = qiov.size;
-        iov = bounce_iov;
-        iov_cnt = 1;
-    }
-
-    iocb = ioq_rdwr(&s->ioqueue, read, iov, iov_cnt, offset);
-
-    /* Fill in virtio block metadata needed for completion */
-    VirtIOBlockRequest *req = container_of(iocb, VirtIOBlockRequest, iocb);
-    req->head = head;
-    req->inhdr = inhdr;
-    req->bounce_iov = bounce_iov;
-    req->read_qiov = read_qiov;
-    return 0;
-}
-
-static int process_request(IOQueue *ioq, struct iovec iov[],
-                           unsigned int out_num, unsigned int in_num,
-                           unsigned int head)
-{
-    VirtIOBlockDataPlane *s = container_of(ioq, VirtIOBlockDataPlane, ioqueue);
-    struct iovec *in_iov = &iov[out_num];
-    struct virtio_blk_outhdr outhdr;
-    QEMUIOVector *inhdr;
-    size_t in_size;
-
-    /* Copy in outhdr */
-    if (unlikely(iov_to_buf(iov, out_num, 0, &outhdr,
-                            sizeof(outhdr)) != sizeof(outhdr))) {
-        error_report("virtio-blk request outhdr too short");
-        return -EFAULT;
-    }
-    iov_discard_front(&iov, &out_num, sizeof(outhdr));
-
-    /* Grab inhdr for later */
-    in_size = iov_size(in_iov, in_num);
-    if (in_size < sizeof(struct virtio_blk_inhdr)) {
-        error_report("virtio_blk request inhdr too short");
-        return -EFAULT;
-    }
-    inhdr = g_slice_new(QEMUIOVector);
-    qemu_iovec_init(inhdr, 1);
-    qemu_iovec_concat_iov(inhdr, in_iov, in_num,
-            in_size - sizeof(struct virtio_blk_inhdr),
-            sizeof(struct virtio_blk_inhdr));
-    iov_discard_back(in_iov, &in_num, sizeof(struct virtio_blk_inhdr));
-
-    /* TODO Linux sets the barrier bit even when not advertised! */
-    outhdr.type &= ~VIRTIO_BLK_T_BARRIER;
-
-    switch (outhdr.type) {
-    case VIRTIO_BLK_T_IN:
-        do_rdwr_cmd(s, true, in_iov, in_num, outhdr.sector * 512, head, inhdr);
-        return 0;
-
-    case VIRTIO_BLK_T_OUT:
-        do_rdwr_cmd(s, false, iov, out_num, outhdr.sector * 512, head, inhdr);
-        return 0;
-
-    case VIRTIO_BLK_T_SCSI_CMD:
-        /* TODO support SCSI commands */
-        complete_request_early(s, head, inhdr, VIRTIO_BLK_S_UNSUPP);
-        return 0;
-
-    case VIRTIO_BLK_T_FLUSH:
-        /* TODO fdsync not supported by Linux AIO, do it synchronously here! */
-        if (qemu_fdatasync(s->fd) < 0) {
-            complete_request_early(s, head, inhdr, VIRTIO_BLK_S_IOERR);
-        } else {
-            complete_request_early(s, head, inhdr, VIRTIO_BLK_S_OK);
-        }
-        return 0;
-
-    case VIRTIO_BLK_T_GET_ID:
-        do_get_id_cmd(s, in_iov, in_num, head, inhdr);
-        return 0;
-
-    default:
-        error_report("virtio-blk unsupported request type %#x", outhdr.type);
-        qemu_iovec_destroy(inhdr);
-        g_slice_free(QEMUIOVector, inhdr);
-        return -EFAULT;
-    }
-}
-
-static int flush_true(EventNotifier *e)
-{
-    return true;
-}
-
-static void handle_notify(EventNotifier *e)
-{
-    VirtIOBlockDataPlane *s = container_of(e, VirtIOBlockDataPlane,
-                                           host_notifier);
-
-    /* There is one array of iovecs into which all new requests are extracted
-     * from the vring.  Requests are read from the vring and the translated
-     * descriptors are written to the iovecs array.  The iovecs do not have to
-     * persist across handle_notify() calls because the kernel copies the
-     * iovecs on io_submit().
-     *
-     * Handling io_submit() EAGAIN may require storing the requests across
-     * handle_notify() calls until the kernel has sufficient resources to
-     * accept more I/O.  This is not implemented yet.
-     */
-    struct iovec iovec[VRING_MAX];
-    struct iovec *end = &iovec[VRING_MAX];
-    struct iovec *iov = iovec;
-
-    /* When a request is read from the vring, the index of the first descriptor
-     * (aka head) is returned so that the completed request can be pushed onto
-     * the vring later.
-     *
-     * The number of hypervisor read-only iovecs is out_num.  The number of
-     * hypervisor write-only iovecs is in_num.
-     */
-    int head;
-    unsigned int out_num = 0, in_num = 0;
-    unsigned int num_queued;
-
-    event_notifier_test_and_clear(&s->host_notifier);
-    for (;;) {
-        /* Disable guest->host notifies to avoid unnecessary vmexits */
-        vring_disable_notification(s->vdev, &s->vring);
-
-        for (;;) {
-            head = vring_pop(s->vdev, &s->vring, iov, end, &out_num, &in_num);
-            if (head < 0) {
-                break; /* no more requests */
-            }
-
-            trace_virtio_blk_data_plane_process_request(s, out_num, in_num,
-                                                        head);
-
-            if (process_request(&s->ioqueue, iov, out_num, in_num, head) < 0) {
-                vring_set_broken(&s->vring);
-                break;
-            }
-            iov += out_num + in_num;
-        }
-
-        if (likely(head == -EAGAIN)) { /* vring emptied */
-            /* Re-enable guest->host notifies and stop processing the vring.
-             * But if the guest has snuck in more descriptors, keep processing.
-             */
-            if (vring_enable_notification(s->vdev, &s->vring)) {
-                break;
-            }
-        } else { /* head == -ENOBUFS or fatal error, iovecs[] is depleted */
-            /* Since there are no iovecs[] left, stop processing for now.  Do
-             * not re-enable guest->host notifies since the I/O completion
-             * handler knows to check for more vring descriptors anyway.
-             */
-            break;
-        }
-    }
-
-    num_queued = ioq_num_queued(&s->ioqueue);
-    if (num_queued > 0) {
-        s->num_reqs += num_queued;
-
-        int rc = ioq_submit(&s->ioqueue);
-        if (unlikely(rc < 0)) {
-            fprintf(stderr, "ioq_submit failed %d\n", rc);
-            exit(1);
-        }
-    }
-}
-
-static int flush_io(EventNotifier *e)
-{
-    VirtIOBlockDataPlane *s = container_of(e, VirtIOBlockDataPlane,
-                                           io_notifier);
-
-    return s->num_reqs > 0;
-}
-
-static void handle_io(EventNotifier *e)
-{
-    VirtIOBlockDataPlane *s = container_of(e, VirtIOBlockDataPlane,
-                                           io_notifier);
-
-    event_notifier_test_and_clear(&s->io_notifier);
-    if (ioq_run_completion(&s->ioqueue, complete_request, s) > 0) {
-        notify_guest(s);
-    }
-
-    /* If there were more requests than iovecs, the vring will not be empty yet
-     * so check again.  There should now be enough resources to process more
-     * requests.
-     */
-    if (unlikely(vring_more_avail(&s->vring))) {
-        handle_notify(&s->host_notifier);
-    }
-}
-
-static void *data_plane_thread(void *opaque)
-{
-    VirtIOBlockDataPlane *s = opaque;
-
-    do {
-        aio_poll(s->ctx, true);
-    } while (!s->stopping || s->num_reqs > 0);
-    return NULL;
-}
-
-static void start_data_plane_bh(void *opaque)
-{
-    VirtIOBlockDataPlane *s = opaque;
-
-    qemu_bh_delete(s->start_bh);
-    s->start_bh = NULL;
-    qemu_thread_create(&s->thread, data_plane_thread,
-                       s, QEMU_THREAD_JOINABLE);
-}
-
-bool virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *blk,
-                                  VirtIOBlockDataPlane **dataplane)
-{
-    VirtIOBlockDataPlane *s;
-    int fd;
-
-    *dataplane = NULL;
-
-    if (!blk->data_plane) {
-        return true;
-    }
-
-    if (blk->scsi) {
-        error_report("device is incompatible with x-data-plane, use scsi=off");
-        return false;
-    }
-
-    if (blk->config_wce) {
-        error_report("device is incompatible with x-data-plane, "
-                     "use config-wce=off");
-        return false;
-    }
-
-    fd = raw_get_aio_fd(blk->conf.bs);
-    if (fd < 0) {
-        error_report("drive is incompatible with x-data-plane, "
-                     "use format=raw,cache=none,aio=native");
-        return false;
-    }
-
-    s = g_new0(VirtIOBlockDataPlane, 1);
-    s->vdev = vdev;
-    s->fd = fd;
-    s->blk = blk;
-
-    /* Prevent block operations that conflict with data plane thread */
-    bdrv_set_in_use(blk->conf.bs, 1);
-
-    error_setg(&s->migration_blocker,
-            "x-data-plane does not support migration");
-    migrate_add_blocker(s->migration_blocker);
-
-    *dataplane = s;
-    return true;
-}
-
-void virtio_blk_data_plane_destroy(VirtIOBlockDataPlane *s)
-{
-    if (!s) {
-        return;
-    }
-
-    virtio_blk_data_plane_stop(s);
-    migrate_del_blocker(s->migration_blocker);
-    error_free(s->migration_blocker);
-    bdrv_set_in_use(s->blk->conf.bs, 0);
-    g_free(s);
-}
-
-void virtio_blk_data_plane_start(VirtIOBlockDataPlane *s)
-{
-    VirtQueue *vq;
-    int i;
-
-    if (s->started) {
-        return;
-    }
-
-    vq = virtio_get_queue(s->vdev, 0);
-    if (!vring_setup(&s->vring, s->vdev, 0)) {
-        return;
-    }
-
-    s->ctx = aio_context_new();
-
-    /* Set up guest notifier (irq) */
-    if (s->vdev->binding->set_guest_notifiers(s->vdev->binding_opaque, 1,
-                                              true) != 0) {
-        fprintf(stderr, "virtio-blk failed to set guest notifier, "
-                "ensure -enable-kvm is set\n");
-        exit(1);
-    }
-    s->guest_notifier = virtio_queue_get_guest_notifier(vq);
-
-    /* Set up virtqueue notify */
-    if (s->vdev->binding->set_host_notifier(s->vdev->binding_opaque,
-                                            0, true) != 0) {
-        fprintf(stderr, "virtio-blk failed to set host notifier\n");
-        exit(1);
-    }
-    s->host_notifier = *virtio_queue_get_host_notifier(vq);
-    aio_set_event_notifier(s->ctx, &s->host_notifier, handle_notify, flush_true);
-
-    /* Set up ioqueue */
-    ioq_init(&s->ioqueue, s->fd, REQ_MAX);
-    for (i = 0; i < ARRAY_SIZE(s->requests); i++) {
-        ioq_put_iocb(&s->ioqueue, &s->requests[i].iocb);
-    }
-    s->io_notifier = *ioq_get_notifier(&s->ioqueue);
-    aio_set_event_notifier(s->ctx, &s->io_notifier, handle_io, flush_io);
-
-    s->started = true;
-    trace_virtio_blk_data_plane_start(s);
-
-    /* Kick right away to begin processing requests already in vring */
-    event_notifier_set(virtio_queue_get_host_notifier(vq));
-
-    /* Spawn thread in BH so it inherits iothread cpusets */
-    s->start_bh = qemu_bh_new(start_data_plane_bh, s);
-    qemu_bh_schedule(s->start_bh);
-}
-
-void virtio_blk_data_plane_stop(VirtIOBlockDataPlane *s)
-{
-    if (!s->started || s->stopping) {
-        return;
-    }
-    s->stopping = true;
-    trace_virtio_blk_data_plane_stop(s);
-
-    /* Stop thread or cancel pending thread creation BH */
-    if (s->start_bh) {
-        qemu_bh_delete(s->start_bh);
-        s->start_bh = NULL;
-    } else {
-        aio_notify(s->ctx);
-        qemu_thread_join(&s->thread);
-    }
-
-    aio_set_event_notifier(s->ctx, &s->io_notifier, NULL, NULL);
-    ioq_cleanup(&s->ioqueue);
-
-    aio_set_event_notifier(s->ctx, &s->host_notifier, NULL, NULL);
-    s->vdev->binding->set_host_notifier(s->vdev->binding_opaque, 0, false);
-
-    aio_context_unref(s->ctx);
-
-    /* Clean up guest notifier (irq) */
-    s->vdev->binding->set_guest_notifiers(s->vdev->binding_opaque, 1, false);
-
-    vring_teardown(&s->vring);
-    s->started = false;
-    s->stopping = false;
-}
diff --git a/hw/dataplane/virtio-blk.h b/hw/dataplane/virtio-blk.h
deleted file mode 100644 (file)
index 1e8fdfe..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Dedicated thread for virtio-blk I/O processing
- *
- * Copyright 2012 IBM, Corp.
- * Copyright 2012 Red Hat, Inc. and/or its affiliates
- *
- * Authors:
- *   Stefan Hajnoczi <stefanha@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 HW_DATAPLANE_VIRTIO_BLK_H
-#define HW_DATAPLANE_VIRTIO_BLK_H
-
-#include "hw/virtio.h"
-
-typedef struct VirtIOBlockDataPlane VirtIOBlockDataPlane;
-
-bool virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *blk,
-                                  VirtIOBlockDataPlane **dataplane);
-void virtio_blk_data_plane_destroy(VirtIOBlockDataPlane *s);
-void virtio_blk_data_plane_start(VirtIOBlockDataPlane *s);
-void virtio_blk_data_plane_stop(VirtIOBlockDataPlane *s);
-void virtio_blk_data_plane_drain(VirtIOBlockDataPlane *s);
-
-#endif /* HW_DATAPLANE_VIRTIO_BLK_H */
diff --git a/hw/dataplane/vring.c b/hw/dataplane/vring.c
deleted file mode 100644 (file)
index e3b2253..0000000
+++ /dev/null
@@ -1,363 +0,0 @@
-/* Copyright 2012 Red Hat, Inc.
- * Copyright IBM, Corp. 2012
- *
- * Based on Linux 2.6.39 vhost code:
- * Copyright (C) 2009 Red Hat, Inc.
- * Copyright (C) 2006 Rusty Russell IBM Corporation
- *
- * Author: Michael S. Tsirkin <mst@redhat.com>
- *         Stefan Hajnoczi <stefanha@redhat.com>
- *
- * Inspiration, some code, and most witty comments come from
- * Documentation/virtual/lguest/lguest.c, by Rusty Russell
- *
- * This work is licensed under the terms of the GNU GPL, version 2.
- */
-
-#include "trace.h"
-#include "vring.h"
-#include "qemu/error-report.h"
-
-/* Map the guest's vring to host memory */
-bool vring_setup(Vring *vring, VirtIODevice *vdev, int n)
-{
-    hwaddr vring_addr = virtio_queue_get_ring_addr(vdev, n);
-    hwaddr vring_size = virtio_queue_get_ring_size(vdev, n);
-    void *vring_ptr;
-
-    vring->broken = false;
-
-    hostmem_init(&vring->hostmem);
-    vring_ptr = hostmem_lookup(&vring->hostmem, vring_addr, vring_size, true);
-    if (!vring_ptr) {
-        error_report("Failed to map vring "
-                     "addr %#" HWADDR_PRIx " size %" HWADDR_PRIu,
-                     vring_addr, vring_size);
-        vring->broken = true;
-        return false;
-    }
-
-    vring_init(&vring->vr, virtio_queue_get_num(vdev, n), vring_ptr, 4096);
-
-    vring->last_avail_idx = 0;
-    vring->last_used_idx = 0;
-    vring->signalled_used = 0;
-    vring->signalled_used_valid = false;
-
-    trace_vring_setup(virtio_queue_get_ring_addr(vdev, n),
-                      vring->vr.desc, vring->vr.avail, vring->vr.used);
-    return true;
-}
-
-void vring_teardown(Vring *vring)
-{
-    hostmem_finalize(&vring->hostmem);
-}
-
-/* Disable guest->host notifies */
-void vring_disable_notification(VirtIODevice *vdev, Vring *vring)
-{
-    if (!(vdev->guest_features & (1 << VIRTIO_RING_F_EVENT_IDX))) {
-        vring->vr.used->flags |= VRING_USED_F_NO_NOTIFY;
-    }
-}
-
-/* Enable guest->host notifies
- *
- * Return true if the vring is empty, false if there are more requests.
- */
-bool vring_enable_notification(VirtIODevice *vdev, Vring *vring)
-{
-    if (vdev->guest_features & (1 << VIRTIO_RING_F_EVENT_IDX)) {
-        vring_avail_event(&vring->vr) = vring->vr.avail->idx;
-    } else {
-        vring->vr.used->flags &= ~VRING_USED_F_NO_NOTIFY;
-    }
-    smp_mb(); /* ensure update is seen before reading avail_idx */
-    return !vring_more_avail(vring);
-}
-
-/* This is stolen from linux/drivers/vhost/vhost.c:vhost_notify() */
-bool vring_should_notify(VirtIODevice *vdev, Vring *vring)
-{
-    uint16_t old, new;
-    bool v;
-    /* Flush out used index updates. This is paired
-     * with the barrier that the Guest executes when enabling
-     * interrupts. */
-    smp_mb();
-
-    if ((vdev->guest_features & VIRTIO_F_NOTIFY_ON_EMPTY) &&
-        unlikely(vring->vr.avail->idx == vring->last_avail_idx)) {
-        return true;
-    }
-
-    if (!(vdev->guest_features & VIRTIO_RING_F_EVENT_IDX)) {
-        return !(vring->vr.avail->flags & VRING_AVAIL_F_NO_INTERRUPT);
-    }
-    old = vring->signalled_used;
-    v = vring->signalled_used_valid;
-    new = vring->signalled_used = vring->last_used_idx;
-    vring->signalled_used_valid = true;
-
-    if (unlikely(!v)) {
-        return true;
-    }
-
-    return vring_need_event(vring_used_event(&vring->vr), new, old);
-}
-
-/* This is stolen from linux/drivers/vhost/vhost.c. */
-static int get_indirect(Vring *vring,
-                        struct iovec iov[], struct iovec *iov_end,
-                        unsigned int *out_num, unsigned int *in_num,
-                        struct vring_desc *indirect)
-{
-    struct vring_desc desc;
-    unsigned int i = 0, count, found = 0;
-
-    /* Sanity check */
-    if (unlikely(indirect->len % sizeof(desc))) {
-        error_report("Invalid length in indirect descriptor: "
-                     "len %#x not multiple of %#zx",
-                     indirect->len, sizeof(desc));
-        vring->broken = true;
-        return -EFAULT;
-    }
-
-    count = indirect->len / sizeof(desc);
-    /* Buffers are chained via a 16 bit next field, so
-     * we can have at most 2^16 of these. */
-    if (unlikely(count > USHRT_MAX + 1)) {
-        error_report("Indirect buffer length too big: %d", indirect->len);
-        vring->broken = true;
-        return -EFAULT;
-    }
-
-    do {
-        struct vring_desc *desc_ptr;
-
-        /* Translate indirect descriptor */
-        desc_ptr = hostmem_lookup(&vring->hostmem,
-                                  indirect->addr + found * sizeof(desc),
-                                  sizeof(desc), false);
-        if (!desc_ptr) {
-            error_report("Failed to map indirect descriptor "
-                         "addr %#" PRIx64 " len %zu",
-                         (uint64_t)indirect->addr + found * sizeof(desc),
-                         sizeof(desc));
-            vring->broken = true;
-            return -EFAULT;
-        }
-        desc = *desc_ptr;
-
-        /* Ensure descriptor has been loaded before accessing fields */
-        barrier(); /* read_barrier_depends(); */
-
-        if (unlikely(++found > count)) {
-            error_report("Loop detected: last one at %u "
-                         "indirect size %u", i, count);
-            vring->broken = true;
-            return -EFAULT;
-        }
-
-        if (unlikely(desc.flags & VRING_DESC_F_INDIRECT)) {
-            error_report("Nested indirect descriptor");
-            vring->broken = true;
-            return -EFAULT;
-        }
-
-        /* Stop for now if there are not enough iovecs available. */
-        if (iov >= iov_end) {
-            return -ENOBUFS;
-        }
-
-        iov->iov_base = hostmem_lookup(&vring->hostmem, desc.addr, desc.len,
-                                       desc.flags & VRING_DESC_F_WRITE);
-        if (!iov->iov_base) {
-            error_report("Failed to map indirect descriptor"
-                         "addr %#" PRIx64 " len %u",
-                         (uint64_t)desc.addr, desc.len);
-            vring->broken = true;
-            return -EFAULT;
-        }
-        iov->iov_len = desc.len;
-        iov++;
-
-        /* If this is an input descriptor, increment that count. */
-        if (desc.flags & VRING_DESC_F_WRITE) {
-            *in_num += 1;
-        } else {
-            /* If it's an output descriptor, they're all supposed
-             * to come before any input descriptors. */
-            if (unlikely(*in_num)) {
-                error_report("Indirect descriptor "
-                             "has out after in: idx %u", i);
-                vring->broken = true;
-                return -EFAULT;
-            }
-            *out_num += 1;
-        }
-        i = desc.next;
-    } while (desc.flags & VRING_DESC_F_NEXT);
-    return 0;
-}
-
-/* This looks in the virtqueue and for the first available buffer, and converts
- * it to an iovec for convenient access.  Since descriptors consist of some
- * number of output then some number of input descriptors, it's actually two
- * iovecs, but we pack them into one and note how many of each there were.
- *
- * This function returns the descriptor number found, or vq->num (which is
- * never a valid descriptor number) if none was found.  A negative code is
- * returned on error.
- *
- * Stolen from linux/drivers/vhost/vhost.c.
- */
-int vring_pop(VirtIODevice *vdev, Vring *vring,
-              struct iovec iov[], struct iovec *iov_end,
-              unsigned int *out_num, unsigned int *in_num)
-{
-    struct vring_desc desc;
-    unsigned int i, head, found = 0, num = vring->vr.num;
-    uint16_t avail_idx, last_avail_idx;
-
-    /* If there was a fatal error then refuse operation */
-    if (vring->broken) {
-        return -EFAULT;
-    }
-
-    /* Check it isn't doing very strange things with descriptor numbers. */
-    last_avail_idx = vring->last_avail_idx;
-    avail_idx = vring->vr.avail->idx;
-    barrier(); /* load indices now and not again later */
-
-    if (unlikely((uint16_t)(avail_idx - last_avail_idx) > num)) {
-        error_report("Guest moved used index from %u to %u",
-                     last_avail_idx, avail_idx);
-        vring->broken = true;
-        return -EFAULT;
-    }
-
-    /* If there's nothing new since last we looked. */
-    if (avail_idx == last_avail_idx) {
-        return -EAGAIN;
-    }
-
-    /* Only get avail ring entries after they have been exposed by guest. */
-    smp_rmb();
-
-    /* Grab the next descriptor number they're advertising, and increment
-     * the index we've seen. */
-    head = vring->vr.avail->ring[last_avail_idx % num];
-
-    /* If their number is silly, that's an error. */
-    if (unlikely(head >= num)) {
-        error_report("Guest says index %u > %u is available", head, num);
-        vring->broken = true;
-        return -EFAULT;
-    }
-
-    if (vdev->guest_features & (1 << VIRTIO_RING_F_EVENT_IDX)) {
-        vring_avail_event(&vring->vr) = vring->vr.avail->idx;
-    }
-
-    /* When we start there are none of either input nor output. */
-    *out_num = *in_num = 0;
-
-    i = head;
-    do {
-        if (unlikely(i >= num)) {
-            error_report("Desc index is %u > %u, head = %u", i, num, head);
-            vring->broken = true;
-            return -EFAULT;
-        }
-        if (unlikely(++found > num)) {
-            error_report("Loop detected: last one at %u vq size %u head %u",
-                         i, num, head);
-            vring->broken = true;
-            return -EFAULT;
-        }
-        desc = vring->vr.desc[i];
-
-        /* Ensure descriptor is loaded before accessing fields */
-        barrier();
-
-        if (desc.flags & VRING_DESC_F_INDIRECT) {
-            int ret = get_indirect(vring, iov, iov_end, out_num, in_num, &desc);
-            if (ret < 0) {
-                return ret;
-            }
-            continue;
-        }
-
-        /* If there are not enough iovecs left, stop for now.  The caller
-         * should check if there are more descs available once they have dealt
-         * with the current set.
-         */
-        if (iov >= iov_end) {
-            return -ENOBUFS;
-        }
-
-        /* TODO handle non-contiguous memory across region boundaries */
-        iov->iov_base = hostmem_lookup(&vring->hostmem, desc.addr, desc.len,
-                                       desc.flags & VRING_DESC_F_WRITE);
-        if (!iov->iov_base) {
-            error_report("Failed to map vring desc addr %#" PRIx64 " len %u",
-                         (uint64_t)desc.addr, desc.len);
-            vring->broken = true;
-            return -EFAULT;
-        }
-        iov->iov_len  = desc.len;
-        iov++;
-
-        if (desc.flags & VRING_DESC_F_WRITE) {
-            /* If this is an input descriptor,
-             * increment that count. */
-            *in_num += 1;
-        } else {
-            /* If it's an output descriptor, they're all supposed
-             * to come before any input descriptors. */
-            if (unlikely(*in_num)) {
-                error_report("Descriptor has out after in: idx %d", i);
-                vring->broken = true;
-                return -EFAULT;
-            }
-            *out_num += 1;
-        }
-        i = desc.next;
-    } while (desc.flags & VRING_DESC_F_NEXT);
-
-    /* On success, increment avail index. */
-    vring->last_avail_idx++;
-    return head;
-}
-
-/* After we've used one of their buffers, we tell them about it.
- *
- * Stolen from linux/drivers/vhost/vhost.c.
- */
-void vring_push(Vring *vring, unsigned int head, int len)
-{
-    struct vring_used_elem *used;
-    uint16_t new;
-
-    /* Don't touch vring if a fatal error occurred */
-    if (vring->broken) {
-        return;
-    }
-
-    /* The virtqueue contains a ring of used buffers.  Get a pointer to the
-     * next entry in that used ring. */
-    used = &vring->vr.used->ring[vring->last_used_idx % vring->vr.num];
-    used->id = head;
-    used->len = len;
-
-    /* Make sure buffer is written before we update index. */
-    smp_wmb();
-
-    new = vring->vr.used->idx = ++vring->last_used_idx;
-    if (unlikely((int16_t)(new - vring->signalled_used) < (uint16_t)1)) {
-        vring->signalled_used_valid = false;
-    }
-}
diff --git a/hw/dataplane/vring.h b/hw/dataplane/vring.h
deleted file mode 100644 (file)
index defb1ef..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-/* Copyright 2012 Red Hat, Inc. and/or its affiliates
- * Copyright IBM, Corp. 2012
- *
- * Based on Linux 2.6.39 vhost code:
- * Copyright (C) 2009 Red Hat, Inc.
- * Copyright (C) 2006 Rusty Russell IBM Corporation
- *
- * Author: Michael S. Tsirkin <mst@redhat.com>
- *         Stefan Hajnoczi <stefanha@redhat.com>
- *
- * Inspiration, some code, and most witty comments come from
- * Documentation/virtual/lguest/lguest.c, by Rusty Russell
- *
- * This work is licensed under the terms of the GNU GPL, version 2.
- */
-
-#ifndef VRING_H
-#define VRING_H
-
-#include <linux/virtio_ring.h>
-#include "qemu-common.h"
-#include "hostmem.h"
-#include "hw/virtio.h"
-
-typedef struct {
-    HostMem hostmem;                /* guest memory mapper */
-    struct vring vr;                /* virtqueue vring mapped to host memory */
-    uint16_t last_avail_idx;        /* last processed avail ring index */
-    uint16_t last_used_idx;         /* last processed used ring index */
-    uint16_t signalled_used;        /* EVENT_IDX state */
-    bool signalled_used_valid;
-    bool broken;                    /* was there a fatal error? */
-} Vring;
-
-static inline unsigned int vring_get_num(Vring *vring)
-{
-    return vring->vr.num;
-}
-
-/* Are there more descriptors available? */
-static inline bool vring_more_avail(Vring *vring)
-{
-    return vring->vr.avail->idx != vring->last_avail_idx;
-}
-
-/* Fail future vring_pop() and vring_push() calls until reset */
-static inline void vring_set_broken(Vring *vring)
-{
-    vring->broken = true;
-}
-
-bool vring_setup(Vring *vring, VirtIODevice *vdev, int n);
-void vring_teardown(Vring *vring);
-void vring_disable_notification(VirtIODevice *vdev, Vring *vring);
-bool vring_enable_notification(VirtIODevice *vdev, Vring *vring);
-bool vring_should_notify(VirtIODevice *vdev, Vring *vring);
-int vring_pop(VirtIODevice *vdev, Vring *vring,
-              struct iovec iov[], struct iovec *iov_end,
-              unsigned int *out_num, unsigned int *in_num);
-void vring_push(Vring *vring, unsigned int head, int len);
-
-#endif /* VRING_H */
diff --git a/hw/debugcon.c b/hw/debugcon.c
deleted file mode 100644 (file)
index cab7691..0000000
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * QEMU Bochs-style debug console ("port E9") emulation
- *
- * Copyright (c) 2003-2004 Fabrice Bellard
- * Copyright (c) 2008 Citrix Systems, Inc.
- * Copyright (c) Intel Corporation; author: H. Peter Anvin
- *
- * 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 "hw/hw.h"
-#include "char/char.h"
-#include "hw/isa.h"
-#include "hw/pc.h"
-
-#define TYPE_ISA_DEBUGCON_DEVICE "isa-debugcon"
-#define ISA_DEBUGCON_DEVICE(obj) \
-     OBJECT_CHECK(ISADebugconState, (obj), TYPE_ISA_DEBUGCON_DEVICE)
-
-//#define DEBUG_DEBUGCON
-
-typedef struct DebugconState {
-    MemoryRegion io;
-    CharDriverState *chr;
-    uint32_t readback;
-} DebugconState;
-
-typedef struct ISADebugconState {
-    ISADevice parent_obj;
-
-    uint32_t iobase;
-    DebugconState state;
-} ISADebugconState;
-
-static void debugcon_ioport_write(void *opaque, hwaddr addr, uint64_t val,
-                                  unsigned width)
-{
-    DebugconState *s = opaque;
-    unsigned char ch = val;
-
-#ifdef DEBUG_DEBUGCON
-    printf("debugcon: write addr=0x%04x val=0x%02x\n", addr, val);
-#endif
-
-    qemu_chr_fe_write(s->chr, &ch, 1);
-}
-
-
-static uint64_t debugcon_ioport_read(void *opaque, hwaddr addr, unsigned width)
-{
-    DebugconState *s = opaque;
-
-#ifdef DEBUG_DEBUGCON
-    printf("debugcon: read addr=0x%04x\n", addr);
-#endif
-
-    return s->readback;
-}
-
-static const MemoryRegionOps debugcon_ops = {
-    .read = debugcon_ioport_read,
-    .write = debugcon_ioport_write,
-    .valid.min_access_size = 1,
-    .valid.max_access_size = 1,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static void debugcon_init_core(DebugconState *s)
-{
-    if (!s->chr) {
-        fprintf(stderr, "Can't create debugcon device, empty char device\n");
-        exit(1);
-    }
-
-    qemu_chr_add_handlers(s->chr, NULL, NULL, NULL, s);
-}
-
-static int debugcon_isa_initfn(ISADevice *dev)
-{
-    ISADebugconState *isa = ISA_DEBUGCON_DEVICE(dev);
-    DebugconState *s = &isa->state;
-
-    debugcon_init_core(s);
-    memory_region_init_io(&s->io, &debugcon_ops, s,
-                          TYPE_ISA_DEBUGCON_DEVICE, 1);
-    memory_region_add_subregion(isa_address_space_io(dev),
-                                isa->iobase, &s->io);
-    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 const TypeInfo debugcon_isa_info = {
-    .name          = TYPE_ISA_DEBUGCON_DEVICE,
-    .parent        = TYPE_ISA_DEVICE,
-    .instance_size = sizeof(ISADebugconState),
-    .class_init    = debugcon_isa_class_initfn,
-};
-
-static void debugcon_register_types(void)
-{
-    type_register_static(&debugcon_isa_info);
-}
-
-type_init(debugcon_register_types)
diff --git a/hw/debugexit.c b/hw/debugexit.c
deleted file mode 100644 (file)
index ba67a8f..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * debug exit port emulation
- *
- * 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 or
- * (at your option) any later version.
- */
-
-#include "hw/hw.h"
-#include "hw/isa.h"
-
-#define TYPE_ISA_DEBUG_EXIT_DEVICE "isa-debug-exit"
-#define ISA_DEBUG_EXIT_DEVICE(obj) \
-     OBJECT_CHECK(ISADebugExitState, (obj), TYPE_ISA_DEBUG_EXIT_DEVICE)
-
-typedef struct ISADebugExitState {
-    ISADevice parent_obj;
-
-    uint32_t iobase;
-    uint32_t iosize;
-    MemoryRegion io;
-} ISADebugExitState;
-
-static void debug_exit_write(void *opaque, hwaddr addr, uint64_t val,
-                             unsigned width)
-{
-    exit((val << 1) | 1);
-}
-
-static const MemoryRegionOps debug_exit_ops = {
-    .write = debug_exit_write,
-    .valid.min_access_size = 1,
-    .valid.max_access_size = 4,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static int debug_exit_initfn(ISADevice *dev)
-{
-    ISADebugExitState *isa = ISA_DEBUG_EXIT_DEVICE(dev);
-
-    memory_region_init_io(&isa->io, &debug_exit_ops, isa,
-                          TYPE_ISA_DEBUG_EXIT_DEVICE, isa->iosize);
-    memory_region_add_subregion(isa_address_space_io(dev),
-                                isa->iobase, &isa->io);
-    return 0;
-}
-
-static Property debug_exit_properties[] = {
-    DEFINE_PROP_HEX32("iobase", ISADebugExitState, iobase, 0x501),
-    DEFINE_PROP_HEX32("iosize", ISADebugExitState, iosize, 0x02),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void debug_exit_class_initfn(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
-    ic->init = debug_exit_initfn;
-    dc->props = debug_exit_properties;
-}
-
-static const TypeInfo debug_exit_info = {
-    .name          = TYPE_ISA_DEBUG_EXIT_DEVICE,
-    .parent        = TYPE_ISA_DEVICE,
-    .instance_size = sizeof(ISADebugExitState),
-    .class_init    = debug_exit_class_initfn,
-};
-
-static void debug_exit_register_types(void)
-{
-    type_register_static(&debug_exit_info);
-}
-
-type_init(debug_exit_register_types)
diff --git a/hw/dec_pci.c b/hw/dec_pci.c
deleted file mode 100644 (file)
index 6ec3d22..0000000
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * QEMU DEC 21154 PCI bridge
- *
- * Copyright (c) 2006-2007 Fabrice Bellard
- * Copyright (c) 2007 Jocelyn Mayer
- *
- * 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 "hw/dec_pci.h"
-#include "hw/sysbus.h"
-#include "hw/pci/pci.h"
-#include "hw/pci/pci_host.h"
-#include "hw/pci/pci_bridge.h"
-#include "hw/pci/pci_bus.h"
-
-/* debug DEC */
-//#define DEBUG_DEC
-
-#ifdef DEBUG_DEC
-#define DEC_DPRINTF(fmt, ...)                               \
-    do { printf("DEC: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DEC_DPRINTF(fmt, ...)
-#endif
-
-#define DEC_21154(obj) OBJECT_CHECK(DECState, (obj), TYPE_DEC_21154)
-
-typedef struct DECState {
-    PCIHostState parent_obj;
-} DECState;
-
-static int dec_map_irq(PCIDevice *pci_dev, int irq_num)
-{
-    return irq_num;
-}
-
-static int dec_pci_bridge_initfn(PCIDevice *pci_dev)
-{
-    return pci_bridge_initfn(pci_dev, TYPE_PCI_BUS);
-}
-
-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 = dec_pci_bridge_initfn;
-    k->exit = pci_bridge_exitfn;
-    k->vendor_id = PCI_VENDOR_ID_DEC;
-    k->device_id = PCI_DEVICE_ID_DEC_21154;
-    k->config_write = pci_bridge_write_config;
-    k->is_bridge = 1;
-    dc->desc = "DEC 21154 PCI-PCI bridge";
-    dc->reset = pci_bridge_reset;
-    dc->vmsd = &vmstate_pci_device;
-}
-
-static const 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)
-{
-    PCIDevice *dev;
-    PCIBridge *br;
-
-    dev = pci_create_multifunction(parent_bus, devfn, false,
-                                   "dec-21154-p2p-bridge");
-    br = DO_UPCAST(PCIBridge, dev, dev);
-    pci_bridge_map_irq(br, "DEC 21154 PCI-PCI bridge", dec_map_irq);
-    qdev_init_nofail(&dev->qdev);
-    return pci_bridge_get_sec_bus(br);
-}
-
-static int pci_dec_21154_device_init(SysBusDevice *dev)
-{
-    PCIHostState *phb;
-
-    phb = PCI_HOST_BRIDGE(dev);
-
-    memory_region_init_io(&phb->conf_mem, &pci_host_conf_le_ops,
-                          dev, "pci-conf-idx", 0x1000);
-    memory_region_init_io(&phb->data_mem, &pci_host_data_le_ops,
-                          dev, "pci-data-idx", 0x1000);
-    sysbus_init_mmio(dev, &phb->conf_mem);
-    sysbus_init_mmio(dev, &phb->data_mem);
-    return 0;
-}
-
-static int dec_21154_pci_host_init(PCIDevice *d)
-{
-    /* PCI2PCI bridge same values as PearPC - check this */
-    return 0;
-}
-
-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 const TypeInfo dec_21154_pci_host_info = {
-    .name          = "dec-21154",
-    .parent        = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(PCIDevice),
-    .class_init    = dec_21154_pci_host_class_init,
-};
-
-static void pci_dec_21154_device_class_init(ObjectClass *klass, void *data)
-{
-    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
-
-    sdc->init = pci_dec_21154_device_init;
-}
-
-static const TypeInfo pci_dec_21154_device_info = {
-    .name          = TYPE_DEC_21154,
-    .parent        = TYPE_PCI_HOST_BRIDGE,
-    .instance_size = sizeof(DECState),
-    .class_init    = pci_dec_21154_device_class_init,
-};
-
-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);
-}
-
-type_init(dec_register_types)
diff --git a/hw/dec_pci.h b/hw/dec_pci.h
deleted file mode 100644 (file)
index 17dc0c2..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef DEC_PCI_H
-#define DEC_PCI_H
-
-#include "qemu-common.h"
-
-#define TYPE_DEC_21154 "dec-21154-sysbus"
-
-PCIBus *pci_dec_21154_init(PCIBus *parent_bus, int devfn);
-
-#endif
diff --git a/hw/devices.h b/hw/devices.h
deleted file mode 100644 (file)
index c60bcab..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-#ifndef QEMU_DEVICES_H
-#define QEMU_DEVICES_H
-
-#include "hw/irq.h"
-
-/* ??? Not all users of this file can include cpu-common.h.  */
-struct MemoryRegion;
-
-/* Devices that have nowhere better to go.  */
-
-/* smc91c111.c */
-void smc91c111_init(NICInfo *, uint32_t, qemu_irq);
-
-/* lan9118.c */
-void lan9118_init(NICInfo *, uint32_t, qemu_irq);
-
-/* tsc210x.c */
-uWireSlave *tsc2102_init(qemu_irq pint);
-uWireSlave *tsc2301_init(qemu_irq penirq, qemu_irq kbirq, qemu_irq dav);
-I2SCodec *tsc210x_codec(uWireSlave *chip);
-uint32_t tsc210x_txrx(void *opaque, uint32_t value, int len);
-void tsc210x_set_transform(uWireSlave *chip,
-                MouseTransformInfo *info);
-void tsc210x_key_event(uWireSlave *chip, int key, int down);
-
-/* tsc2005.c */
-void *tsc2005_init(qemu_irq pintdav);
-uint32_t tsc2005_txrx(void *opaque, uint32_t value, int len);
-void tsc2005_set_transform(void *opaque, MouseTransformInfo *info);
-
-/* stellaris_input.c */
-void stellaris_gamepad_init(int n, qemu_irq *irq, const int *keycode);
-
-/* blizzard.c */
-void *s1d13745_init(qemu_irq gpio_int);
-void s1d13745_write(void *opaque, int dc, uint16_t value);
-void s1d13745_write_block(void *opaque, int dc,
-                void *buf, size_t len, int pitch);
-uint16_t s1d13745_read(void *opaque, int dc);
-
-/* cbus.c */
-typedef struct {
-    qemu_irq clk;
-    qemu_irq dat;
-    qemu_irq sel;
-} CBus;
-CBus *cbus_init(qemu_irq dat_out);
-void cbus_attach(CBus *bus, void *slave_opaque);
-
-void *retu_init(qemu_irq irq, int vilma);
-void *tahvo_init(qemu_irq irq, int betty);
-
-void retu_key_event(void *retu, int state);
-
-/* tc6393xb.c */
-typedef struct TC6393xbState TC6393xbState;
-#define TC6393XB_RAM   0x110000 /* amount of ram for Video and USB */
-TC6393xbState *tc6393xb_init(struct MemoryRegion *sysmem,
-                             uint32_t base, qemu_irq irq);
-void tc6393xb_gpio_out_set(TC6393xbState *s, int line,
-                    qemu_irq handler);
-qemu_irq *tc6393xb_gpio_in_get(TC6393xbState *s);
-qemu_irq tc6393xb_l3v_get(TC6393xbState *s);
-
-/* sm501.c */
-void sm501_init(struct MemoryRegion *address_space_mem, uint32_t base,
-                uint32_t local_mem_bytes, qemu_irq irq,
-                CharDriverState *chr);
-
-#endif
diff --git a/hw/display/Makefile.objs b/hw/display/Makefile.objs
new file mode 100644 (file)
index 0000000..3f7027d
--- /dev/null
@@ -0,0 +1,34 @@
+common-obj-$(CONFIG_ADS7846) += ads7846.o
+common-obj-$(CONFIG_VGA_CIRRUS) += cirrus_vga.o
+common-obj-$(CONFIG_G364FB) += g364fb.o
+common-obj-$(CONFIG_JAZZ_LED) += jazz_led.o
+common-obj-$(CONFIG_PL110) += pl110.o
+common-obj-$(CONFIG_SSD0303) += ssd0303.o
+common-obj-$(CONFIG_SSD0323) += ssd0323.o
+common-obj-$(CONFIG_XEN_BACKEND) += xenfb.o
+
+common-obj-$(CONFIG_VGA_PCI) += vga-pci.o
+common-obj-$(CONFIG_VGA_ISA) += vga-isa.o
+common-obj-$(CONFIG_VGA_ISA_MM) += vga-isa-mm.o
+common-obj-$(CONFIG_VMWARE_VGA) += vmware_vga.o
+
+common-obj-$(CONFIG_BLIZZARD) += blizzard.o
+common-obj-$(CONFIG_EXYNOS4) += exynos4210_fimd.o
+common-obj-$(CONFIG_FRAMEBUFFER) += framebuffer.o
+common-obj-$(CONFIG_MILKYMIST) += milkymist-vgafb.o
+common-obj-$(CONFIG_ZAURUS) += tc6393xb.o
+
+ifeq ($(CONFIG_GLX),y)
+common-obj-$(CONFIG_MILKYMIST) += milkymist-tmu2.o
+endif
+
+obj-$(CONFIG_OMAP) += omap_dss.o
+obj-$(CONFIG_OMAP) += omap_lcdc.o
+obj-$(CONFIG_PXA2XX) += pxa2xx_lcd.o
+obj-$(CONFIG_SM501) += sm501.o
+obj-$(CONFIG_TCX) += tcx.o
+
+obj-$(CONFIG_VGA) += vga.o
+
+common-obj-$(CONFIG_QXL) += qxl-logger.o qxl-render.o
+obj-$(CONFIG_QXL) += qxl.o
diff --git a/hw/display/ads7846.c b/hw/display/ads7846.c
new file mode 100644 (file)
index 0000000..5da3dc5
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * TI ADS7846 / TSC2046 chip emulation.
+ *
+ * Copyright (c) 2006 Openedhand Ltd.
+ * Written by Andrzej Zaborowski <balrog@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/ssi.h"
+#include "ui/console.h"
+
+typedef struct {
+    SSISlave ssidev;
+    qemu_irq interrupt;
+
+    int input[8];
+    int pressure;
+    int noise;
+
+    int cycle;
+    int output;
+} ADS7846State;
+
+/* Control-byte bitfields */
+#define CB_PD0         (1 << 0)
+#define CB_PD1         (1 << 1)
+#define CB_SER         (1 << 2)
+#define CB_MODE                (1 << 3)
+#define CB_A0          (1 << 4)
+#define CB_A1          (1 << 5)
+#define CB_A2          (1 << 6)
+#define CB_START       (1 << 7)
+
+#define X_AXIS_DMAX    3470
+#define X_AXIS_MIN     290
+#define Y_AXIS_DMAX    3450
+#define Y_AXIS_MIN     200
+
+#define ADS_VBAT       2000
+#define ADS_VAUX       2000
+#define ADS_TEMP0      2000
+#define ADS_TEMP1      3000
+#define ADS_XPOS(x, y) (X_AXIS_MIN + ((X_AXIS_DMAX * (x)) >> 15))
+#define ADS_YPOS(x, y) (Y_AXIS_MIN + ((Y_AXIS_DMAX * (y)) >> 15))
+#define ADS_Z1POS(x, y)        600
+#define ADS_Z2POS(x, y)        (600 + 6000 / ADS_XPOS(x, y))
+
+static void ads7846_int_update(ADS7846State *s)
+{
+    if (s->interrupt)
+        qemu_set_irq(s->interrupt, s->pressure == 0);
+}
+
+static uint32_t ads7846_transfer(SSISlave *dev, uint32_t value)
+{
+    ADS7846State *s = FROM_SSI_SLAVE(ADS7846State, dev);
+
+    switch (s->cycle ++) {
+    case 0:
+        if (!(value & CB_START)) {
+            s->cycle = 0;
+            break;
+        }
+
+        s->output = s->input[(value >> 4) & 7];
+
+        /* Imitate the ADC noise, some drivers expect this.  */
+        s->noise = (s->noise + 3) & 7;
+        switch ((value >> 4) & 7) {
+        case 1: s->output += s->noise ^ 2; break;
+        case 3: s->output += s->noise ^ 0; break;
+        case 4: s->output += s->noise ^ 7; break;
+        case 5: s->output += s->noise ^ 5; break;
+        }
+
+        if (value & CB_MODE)
+            s->output >>= 4;   /* 8 bits instead of 12 */
+
+        break;
+    case 1:
+        s->cycle = 0;
+        break;
+    }
+    return s->output;
+}
+
+static void ads7846_ts_event(void *opaque,
+                int x, int y, int z, int buttons_state)
+{
+    ADS7846State *s = opaque;
+
+    if (buttons_state) {
+        x = 0x7fff - x;
+        s->input[1] = ADS_XPOS(x, y);
+        s->input[3] = ADS_Z1POS(x, y);
+        s->input[4] = ADS_Z2POS(x, y);
+        s->input[5] = ADS_YPOS(x, y);
+    }
+
+    if (s->pressure == !buttons_state) {
+        s->pressure = !!buttons_state;
+
+        ads7846_int_update(s);
+    }
+}
+
+static int ads7856_post_load(void *opaque, int version_id)
+{
+    ADS7846State *s = opaque;
+
+    s->pressure = 0;
+    ads7846_int_update(s);
+    return 0;
+}
+
+static const VMStateDescription vmstate_ads7846 = {
+    .name = "ads7846",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .post_load = ads7856_post_load,
+    .fields      = (VMStateField[]) {
+        VMSTATE_SSI_SLAVE(ssidev, ADS7846State),
+        VMSTATE_INT32_ARRAY(input, ADS7846State, 8),
+        VMSTATE_INT32(noise, ADS7846State),
+        VMSTATE_INT32(cycle, ADS7846State),
+        VMSTATE_INT32(output, ADS7846State),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int ads7846_init(SSISlave *dev)
+{
+    ADS7846State *s = FROM_SSI_SLAVE(ADS7846State, dev);
+
+    qdev_init_gpio_out(&dev->qdev, &s->interrupt, 1);
+
+    s->input[0] = ADS_TEMP0;   /* TEMP0 */
+    s->input[2] = ADS_VBAT;    /* VBAT */
+    s->input[6] = ADS_VAUX;    /* VAUX */
+    s->input[7] = ADS_TEMP1;   /* TEMP1 */
+
+    /* We want absolute coordinates */
+    qemu_add_mouse_event_handler(ads7846_ts_event, s, 1,
+                    "QEMU ADS7846-driven Touchscreen");
+
+    ads7846_int_update(s);
+
+    vmstate_register(NULL, -1, &vmstate_ads7846, s);
+    return 0;
+}
+
+static void ads7846_class_init(ObjectClass *klass, void *data)
+{
+    SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
+
+    k->init = ads7846_init;
+    k->transfer = ads7846_transfer;
+}
+
+static const TypeInfo ads7846_info = {
+    .name          = "ads7846",
+    .parent        = TYPE_SSI_SLAVE,
+    .instance_size = sizeof(ADS7846State),
+    .class_init    = ads7846_class_init,
+};
+
+static void ads7846_register_types(void)
+{
+    type_register_static(&ads7846_info);
+}
+
+type_init(ads7846_register_types)
diff --git a/hw/display/blizzard.c b/hw/display/blizzard.c
new file mode 100644 (file)
index 0000000..175c5cd
--- /dev/null
@@ -0,0 +1,1004 @@
+/*
+ * Epson S1D13744/S1D13745 (Blizzard/Hailstorm/Tornado) LCD/TV controller.
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ * Written by Andrzej Zaborowski <andrew@openedhand.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 or
+ * (at your option) version 3 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
+ * 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 "ui/console.h"
+#include "hw/arm/devices.h"
+#include "vga_int.h"
+#include "ui/pixel_ops.h"
+
+typedef void (*blizzard_fn_t)(uint8_t *, const uint8_t *, unsigned int);
+
+typedef struct {
+    uint8_t reg;
+    uint32_t addr;
+    int swallow;
+
+    int pll;
+    int pll_range;
+    int pll_ctrl;
+    uint8_t pll_mode;
+    uint8_t clksel;
+    int memenable;
+    int memrefresh;
+    uint8_t timing[3];
+    int priority;
+
+    uint8_t lcd_config;
+    int x;
+    int y;
+    int skipx;
+    int skipy;
+    uint8_t hndp;
+    uint8_t vndp;
+    uint8_t hsync;
+    uint8_t vsync;
+    uint8_t pclk;
+    uint8_t u;
+    uint8_t v;
+    uint8_t yrc[2];
+    int ix[2];
+    int iy[2];
+    int ox[2];
+    int oy[2];
+
+    int enable;
+    int blank;
+    int bpp;
+    int invalidate;
+    int mx[2];
+    int my[2];
+    uint8_t mode;
+    uint8_t effect;
+    uint8_t iformat;
+    uint8_t source;
+    QemuConsole *con;
+    blizzard_fn_t *line_fn_tab[2];
+    void *fb;
+
+    uint8_t hssi_config[3];
+    uint8_t tv_config;
+    uint8_t tv_timing[4];
+    uint8_t vbi;
+    uint8_t tv_x;
+    uint8_t tv_y;
+    uint8_t tv_test;
+    uint8_t tv_filter_config;
+    uint8_t tv_filter_idx;
+    uint8_t tv_filter_coeff[0x20];
+    uint8_t border_r;
+    uint8_t border_g;
+    uint8_t border_b;
+    uint8_t gamma_config;
+    uint8_t gamma_idx;
+    uint8_t gamma_lut[0x100];
+    uint8_t matrix_ena;
+    uint8_t matrix_coeff[0x12];
+    uint8_t matrix_r;
+    uint8_t matrix_g;
+    uint8_t matrix_b;
+    uint8_t pm;
+    uint8_t status;
+    uint8_t rgbgpio_dir;
+    uint8_t rgbgpio;
+    uint8_t gpio_dir;
+    uint8_t gpio;
+    uint8_t gpio_edge[2];
+    uint8_t gpio_irq;
+    uint8_t gpio_pdown;
+
+    struct {
+        int x;
+        int y;
+        int dx;
+        int dy;
+        int len;
+        int buflen;
+        void *buf;
+        void *data;
+        uint16_t *ptr;
+        int angle;
+        int pitch;
+        blizzard_fn_t line_fn;
+    } data;
+} BlizzardState;
+
+/* Bytes(!) per pixel */
+static const int blizzard_iformat_bpp[0x10] = {
+    0,
+    2, /* RGB 5:6:5*/
+    3, /* RGB 6:6:6 mode 1 */
+    3, /* RGB 8:8:8 mode 1 */
+    0, 0,
+    4, /* RGB 6:6:6 mode 2 */
+    4, /* RGB 8:8:8 mode 2 */
+    0, /* YUV 4:2:2 */
+    0, /* YUV 4:2:0 */
+    0, 0, 0, 0, 0, 0,
+};
+
+static inline void blizzard_rgb2yuv(int r, int g, int b,
+                int *y, int *u, int *v)
+{
+    *y = 0x10 + ((0x838 * r + 0x1022 * g + 0x322 * b) >> 13);
+    *u = 0x80 + ((0xe0e * b - 0x04c1 * r - 0x94e * g) >> 13);
+    *v = 0x80 + ((0xe0e * r - 0x0bc7 * g - 0x247 * b) >> 13);
+}
+
+static void blizzard_window(BlizzardState *s)
+{
+    DisplaySurface *surface = qemu_console_surface(s->con);
+    uint8_t *src, *dst;
+    int bypp[2];
+    int bypl[3];
+    int y;
+    blizzard_fn_t fn = s->data.line_fn;
+
+    if (!fn)
+        return;
+    if (s->mx[0] > s->data.x)
+        s->mx[0] = s->data.x;
+    if (s->my[0] > s->data.y)
+        s->my[0] = s->data.y;
+    if (s->mx[1] < s->data.x + s->data.dx)
+        s->mx[1] = s->data.x + s->data.dx;
+    if (s->my[1] < s->data.y + s->data.dy)
+        s->my[1] = s->data.y + s->data.dy;
+
+    bypp[0] = s->bpp;
+    bypp[1] = surface_bytes_per_pixel(surface);
+    bypl[0] = bypp[0] * s->data.pitch;
+    bypl[1] = bypp[1] * s->x;
+    bypl[2] = bypp[0] * s->data.dx;
+
+    src = s->data.data;
+    dst = s->fb + bypl[1] * s->data.y + bypp[1] * s->data.x;
+    for (y = s->data.dy; y > 0; y --, src += bypl[0], dst += bypl[1])
+        fn(dst, src, bypl[2]);
+}
+
+static int blizzard_transfer_setup(BlizzardState *s)
+{
+    if (s->source > 3 || !s->bpp ||
+                    s->ix[1] < s->ix[0] || s->iy[1] < s->iy[0])
+        return 0;
+
+    s->data.angle = s->effect & 3;
+    s->data.line_fn = s->line_fn_tab[!!s->data.angle][s->iformat];
+    s->data.x = s->ix[0];
+    s->data.y = s->iy[0];
+    s->data.dx = s->ix[1] - s->ix[0] + 1;
+    s->data.dy = s->iy[1] - s->iy[0] + 1;
+    s->data.len = s->bpp * s->data.dx * s->data.dy;
+    s->data.pitch = s->data.dx;
+    if (s->data.len > s->data.buflen) {
+        s->data.buf = g_realloc(s->data.buf, s->data.len);
+        s->data.buflen = s->data.len;
+    }
+    s->data.ptr = s->data.buf;
+    s->data.data = s->data.buf;
+    s->data.len /= 2;
+    return 1;
+}
+
+static void blizzard_reset(BlizzardState *s)
+{
+    s->reg = 0;
+    s->swallow = 0;
+
+    s->pll = 9;
+    s->pll_range = 1;
+    s->pll_ctrl = 0x14;
+    s->pll_mode = 0x32;
+    s->clksel = 0x00;
+    s->memenable = 0;
+    s->memrefresh = 0x25c;
+    s->timing[0] = 0x3f;
+    s->timing[1] = 0x13;
+    s->timing[2] = 0x21;
+    s->priority = 0;
+
+    s->lcd_config = 0x74;
+    s->x = 8;
+    s->y = 1;
+    s->skipx = 0;
+    s->skipy = 0;
+    s->hndp = 3;
+    s->vndp = 2;
+    s->hsync = 1;
+    s->vsync = 1;
+    s->pclk = 0x80;
+
+    s->ix[0] = 0;
+    s->ix[1] = 0;
+    s->iy[0] = 0;
+    s->iy[1] = 0;
+    s->ox[0] = 0;
+    s->ox[1] = 0;
+    s->oy[0] = 0;
+    s->oy[1] = 0;
+
+    s->yrc[0] = 0x00;
+    s->yrc[1] = 0x30;
+    s->u = 0;
+    s->v = 0;
+
+    s->iformat = 3;
+    s->source = 0;
+    s->bpp = blizzard_iformat_bpp[s->iformat];
+
+    s->hssi_config[0] = 0x00;
+    s->hssi_config[1] = 0x00;
+    s->hssi_config[2] = 0x01;
+    s->tv_config = 0x00;
+    s->tv_timing[0] = 0x00;
+    s->tv_timing[1] = 0x00;
+    s->tv_timing[2] = 0x00;
+    s->tv_timing[3] = 0x00;
+    s->vbi = 0x10;
+    s->tv_x = 0x14;
+    s->tv_y = 0x03;
+    s->tv_test = 0x00;
+    s->tv_filter_config = 0x80;
+    s->tv_filter_idx = 0x00;
+    s->border_r = 0x10;
+    s->border_g = 0x80;
+    s->border_b = 0x80;
+    s->gamma_config = 0x00;
+    s->gamma_idx = 0x00;
+    s->matrix_ena = 0x00;
+    memset(&s->matrix_coeff, 0, sizeof(s->matrix_coeff));
+    s->matrix_r = 0x00;
+    s->matrix_g = 0x00;
+    s->matrix_b = 0x00;
+    s->pm = 0x02;
+    s->status = 0x00;
+    s->rgbgpio_dir = 0x00;
+    s->gpio_dir = 0x00;
+    s->gpio_edge[0] = 0x00;
+    s->gpio_edge[1] = 0x00;
+    s->gpio_irq = 0x00;
+    s->gpio_pdown = 0xff;
+}
+
+static inline void blizzard_invalidate_display(void *opaque) {
+    BlizzardState *s = (BlizzardState *) opaque;
+
+    s->invalidate = 1;
+}
+
+static uint16_t blizzard_reg_read(void *opaque, uint8_t reg)
+{
+    BlizzardState *s = (BlizzardState *) opaque;
+
+    switch (reg) {
+    case 0x00: /* Revision Code */
+        return 0xa5;
+
+    case 0x02: /* Configuration Readback */
+        return 0x83;   /* Macrovision OK, CNF[2:0] = 3 */
+
+    case 0x04: /* PLL M-Divider */
+        return (s->pll - 1) | (1 << 7);
+    case 0x06: /* PLL Lock Range Control */
+        return s->pll_range;
+    case 0x08: /* PLL Lock Synthesis Control 0 */
+        return s->pll_ctrl & 0xff;
+    case 0x0a: /* PLL Lock Synthesis Control 1 */
+        return s->pll_ctrl >> 8;
+    case 0x0c: /* PLL Mode Control 0 */
+        return s->pll_mode;
+
+    case 0x0e: /* Clock-Source Select */
+        return s->clksel;
+
+    case 0x10: /* Memory Controller Activate */
+    case 0x14: /* Memory Controller Bank 0 Status Flag */
+        return s->memenable;
+
+    case 0x18: /* Auto-Refresh Interval Setting 0 */
+        return s->memrefresh & 0xff;
+    case 0x1a: /* Auto-Refresh Interval Setting 1 */
+        return s->memrefresh >> 8;
+
+    case 0x1c: /* Power-On Sequence Timing Control */
+        return s->timing[0];
+    case 0x1e: /* Timing Control 0 */
+        return s->timing[1];
+    case 0x20: /* Timing Control 1 */
+        return s->timing[2];
+
+    case 0x24: /* Arbitration Priority Control */
+        return s->priority;
+
+    case 0x28: /* LCD Panel Configuration */
+        return s->lcd_config;
+
+    case 0x2a: /* LCD Horizontal Display Width */
+        return s->x >> 3;
+    case 0x2c: /* LCD Horizontal Non-display Period */
+        return s->hndp;
+    case 0x2e: /* LCD Vertical Display Height 0 */
+        return s->y & 0xff;
+    case 0x30: /* LCD Vertical Display Height 1 */
+        return s->y >> 8;
+    case 0x32: /* LCD Vertical Non-display Period */
+        return s->vndp;
+    case 0x34: /* LCD HS Pulse-width */
+        return s->hsync;
+    case 0x36: /* LCd HS Pulse Start Position */
+        return s->skipx >> 3;
+    case 0x38: /* LCD VS Pulse-width */
+        return s->vsync;
+    case 0x3a: /* LCD VS Pulse Start Position */
+        return s->skipy;
+
+    case 0x3c: /* PCLK Polarity */
+        return s->pclk;
+
+    case 0x3e: /* High-speed Serial Interface Tx Configuration Port 0 */
+        return s->hssi_config[0];
+    case 0x40: /* High-speed Serial Interface Tx Configuration Port 1 */
+        return s->hssi_config[1];
+    case 0x42: /* High-speed Serial Interface Tx Mode */
+        return s->hssi_config[2];
+    case 0x44: /* TV Display Configuration */
+        return s->tv_config;
+    case 0x46 ... 0x4c:        /* TV Vertical Blanking Interval Data bits */
+        return s->tv_timing[(reg - 0x46) >> 1];
+    case 0x4e: /* VBI: Closed Caption / XDS Control / Status */
+        return s->vbi;
+    case 0x50: /* TV Horizontal Start Position */
+        return s->tv_x;
+    case 0x52: /* TV Vertical Start Position */
+        return s->tv_y;
+    case 0x54: /* TV Test Pattern Setting */
+        return s->tv_test;
+    case 0x56: /* TV Filter Setting */
+        return s->tv_filter_config;
+    case 0x58: /* TV Filter Coefficient Index */
+        return s->tv_filter_idx;
+    case 0x5a: /* TV Filter Coefficient Data */
+        if (s->tv_filter_idx < 0x20)
+            return s->tv_filter_coeff[s->tv_filter_idx ++];
+        return 0;
+
+    case 0x60: /* Input YUV/RGB Translate Mode 0 */
+        return s->yrc[0];
+    case 0x62: /* Input YUV/RGB Translate Mode 1 */
+        return s->yrc[1];
+    case 0x64: /* U Data Fix */
+        return s->u;
+    case 0x66: /* V Data Fix */
+        return s->v;
+
+    case 0x68: /* Display Mode */
+        return s->mode;
+
+    case 0x6a: /* Special Effects */
+        return s->effect;
+
+    case 0x6c: /* Input Window X Start Position 0 */
+        return s->ix[0] & 0xff;
+    case 0x6e: /* Input Window X Start Position 1 */
+        return s->ix[0] >> 3;
+    case 0x70: /* Input Window Y Start Position 0 */
+        return s->ix[0] & 0xff;
+    case 0x72: /* Input Window Y Start Position 1 */
+        return s->ix[0] >> 3;
+    case 0x74: /* Input Window X End Position 0 */
+        return s->ix[1] & 0xff;
+    case 0x76: /* Input Window X End Position 1 */
+        return s->ix[1] >> 3;
+    case 0x78: /* Input Window Y End Position 0 */
+        return s->ix[1] & 0xff;
+    case 0x7a: /* Input Window Y End Position 1 */
+        return s->ix[1] >> 3;
+    case 0x7c: /* Output Window X Start Position 0 */
+        return s->ox[0] & 0xff;
+    case 0x7e: /* Output Window X Start Position 1 */
+        return s->ox[0] >> 3;
+    case 0x80: /* Output Window Y Start Position 0 */
+        return s->oy[0] & 0xff;
+    case 0x82: /* Output Window Y Start Position 1 */
+        return s->oy[0] >> 3;
+    case 0x84: /* Output Window X End Position 0 */
+        return s->ox[1] & 0xff;
+    case 0x86: /* Output Window X End Position 1 */
+        return s->ox[1] >> 3;
+    case 0x88: /* Output Window Y End Position 0 */
+        return s->oy[1] & 0xff;
+    case 0x8a: /* Output Window Y End Position 1 */
+        return s->oy[1] >> 3;
+
+    case 0x8c: /* Input Data Format */
+        return s->iformat;
+    case 0x8e: /* Data Source Select */
+        return s->source;
+    case 0x90: /* Display Memory Data Port */
+        return 0;
+
+    case 0xa8: /* Border Color 0 */
+        return s->border_r;
+    case 0xaa: /* Border Color 1 */
+        return s->border_g;
+    case 0xac: /* Border Color 2 */
+        return s->border_b;
+
+    case 0xb4: /* Gamma Correction Enable */
+        return s->gamma_config;
+    case 0xb6: /* Gamma Correction Table Index */
+        return s->gamma_idx;
+    case 0xb8: /* Gamma Correction Table Data */
+        return s->gamma_lut[s->gamma_idx ++];
+
+    case 0xba: /* 3x3 Matrix Enable */
+        return s->matrix_ena;
+    case 0xbc ... 0xde:        /* Coefficient Registers */
+        return s->matrix_coeff[(reg - 0xbc) >> 1];
+    case 0xe0: /* 3x3 Matrix Red Offset */
+        return s->matrix_r;
+    case 0xe2: /* 3x3 Matrix Green Offset */
+        return s->matrix_g;
+    case 0xe4: /* 3x3 Matrix Blue Offset */
+        return s->matrix_b;
+
+    case 0xe6: /* Power-save */
+        return s->pm;
+    case 0xe8: /* Non-display Period Control / Status */
+        return s->status | (1 << 5);
+    case 0xea: /* RGB Interface Control */
+        return s->rgbgpio_dir;
+    case 0xec: /* RGB Interface Status */
+        return s->rgbgpio;
+    case 0xee: /* General-purpose IO Pins Configuration */
+        return s->gpio_dir;
+    case 0xf0: /* General-purpose IO Pins Status / Control */
+        return s->gpio;
+    case 0xf2: /* GPIO Positive Edge Interrupt Trigger */
+        return s->gpio_edge[0];
+    case 0xf4: /* GPIO Negative Edge Interrupt Trigger */
+        return s->gpio_edge[1];
+    case 0xf6: /* GPIO Interrupt Status */
+        return s->gpio_irq;
+    case 0xf8: /* GPIO Pull-down Control */
+        return s->gpio_pdown;
+
+    default:
+        fprintf(stderr, "%s: unknown register %02x\n", __FUNCTION__, reg);
+        return 0;
+    }
+}
+
+static void blizzard_reg_write(void *opaque, uint8_t reg, uint16_t value)
+{
+    BlizzardState *s = (BlizzardState *) opaque;
+
+    switch (reg) {
+    case 0x04: /* PLL M-Divider */
+        s->pll = (value & 0x3f) + 1;
+        break;
+    case 0x06: /* PLL Lock Range Control */
+        s->pll_range = value & 3;
+        break;
+    case 0x08: /* PLL Lock Synthesis Control 0 */
+        s->pll_ctrl &= 0xf00;
+        s->pll_ctrl |= (value << 0) & 0x0ff;
+        break;
+    case 0x0a: /* PLL Lock Synthesis Control 1 */
+        s->pll_ctrl &= 0x0ff;
+        s->pll_ctrl |= (value << 8) & 0xf00;
+        break;
+    case 0x0c: /* PLL Mode Control 0 */
+        s->pll_mode = value & 0x77;
+        if ((value & 3) == 0 || (value & 3) == 3)
+            fprintf(stderr, "%s: wrong PLL Control bits (%i)\n",
+                    __FUNCTION__, value & 3);
+        break;
+
+    case 0x0e: /* Clock-Source Select */
+        s->clksel = value & 0xff;
+        break;
+
+    case 0x10: /* Memory Controller Activate */
+        s->memenable = value & 1;
+        break;
+    case 0x14: /* Memory Controller Bank 0 Status Flag */
+        break;
+
+    case 0x18: /* Auto-Refresh Interval Setting 0 */
+        s->memrefresh &= 0xf00;
+        s->memrefresh |= (value << 0) & 0x0ff;
+        break;
+    case 0x1a: /* Auto-Refresh Interval Setting 1 */
+        s->memrefresh &= 0x0ff;
+        s->memrefresh |= (value << 8) & 0xf00;
+        break;
+
+    case 0x1c: /* Power-On Sequence Timing Control */
+        s->timing[0] = value & 0x7f;
+        break;
+    case 0x1e: /* Timing Control 0 */
+        s->timing[1] = value & 0x17;
+        break;
+    case 0x20: /* Timing Control 1 */
+        s->timing[2] = value & 0x35;
+        break;
+
+    case 0x24: /* Arbitration Priority Control */
+        s->priority = value & 1;
+        break;
+
+    case 0x28: /* LCD Panel Configuration */
+        s->lcd_config = value & 0xff;
+        if (value & (1 << 7))
+            fprintf(stderr, "%s: data swap not supported!\n", __FUNCTION__);
+        break;
+
+    case 0x2a: /* LCD Horizontal Display Width */
+        s->x = value << 3;
+        break;
+    case 0x2c: /* LCD Horizontal Non-display Period */
+        s->hndp = value & 0xff;
+        break;
+    case 0x2e: /* LCD Vertical Display Height 0 */
+        s->y &= 0x300;
+        s->y |= (value << 0) & 0x0ff;
+        break;
+    case 0x30: /* LCD Vertical Display Height 1 */
+        s->y &= 0x0ff;
+        s->y |= (value << 8) & 0x300;
+        break;
+    case 0x32: /* LCD Vertical Non-display Period */
+        s->vndp = value & 0xff;
+        break;
+    case 0x34: /* LCD HS Pulse-width */
+        s->hsync = value & 0xff;
+        break;
+    case 0x36: /* LCD HS Pulse Start Position */
+        s->skipx = value & 0xff;
+        break;
+    case 0x38: /* LCD VS Pulse-width */
+        s->vsync = value & 0xbf;
+        break;
+    case 0x3a: /* LCD VS Pulse Start Position */
+        s->skipy = value & 0xff;
+        break;
+
+    case 0x3c: /* PCLK Polarity */
+        s->pclk = value & 0x82;
+        /* Affects calculation of s->hndp, s->hsync and s->skipx.  */
+        break;
+
+    case 0x3e: /* High-speed Serial Interface Tx Configuration Port 0 */
+        s->hssi_config[0] = value;
+        break;
+    case 0x40: /* High-speed Serial Interface Tx Configuration Port 1 */
+        s->hssi_config[1] = value;
+        if (((value >> 4) & 3) == 3)
+            fprintf(stderr, "%s: Illegal active-data-links value\n",
+                            __FUNCTION__);
+        break;
+    case 0x42: /* High-speed Serial Interface Tx Mode */
+        s->hssi_config[2] = value & 0xbd;
+        break;
+
+    case 0x44: /* TV Display Configuration */
+        s->tv_config = value & 0xfe;
+        break;
+    case 0x46 ... 0x4c:        /* TV Vertical Blanking Interval Data bits 0 */
+        s->tv_timing[(reg - 0x46) >> 1] = value;
+        break;
+    case 0x4e: /* VBI: Closed Caption / XDS Control / Status */
+        s->vbi = value;
+        break;
+    case 0x50: /* TV Horizontal Start Position */
+        s->tv_x = value;
+        break;
+    case 0x52: /* TV Vertical Start Position */
+        s->tv_y = value & 0x7f;
+        break;
+    case 0x54: /* TV Test Pattern Setting */
+        s->tv_test = value;
+        break;
+    case 0x56: /* TV Filter Setting */
+        s->tv_filter_config = value & 0xbf;
+        break;
+    case 0x58: /* TV Filter Coefficient Index */
+        s->tv_filter_idx = value & 0x1f;
+        break;
+    case 0x5a: /* TV Filter Coefficient Data */
+        if (s->tv_filter_idx < 0x20)
+            s->tv_filter_coeff[s->tv_filter_idx ++] = value;
+        break;
+
+    case 0x60: /* Input YUV/RGB Translate Mode 0 */
+        s->yrc[0] = value & 0xb0;
+        break;
+    case 0x62: /* Input YUV/RGB Translate Mode 1 */
+        s->yrc[1] = value & 0x30;
+        break;
+    case 0x64: /* U Data Fix */
+        s->u = value & 0xff;
+        break;
+    case 0x66: /* V Data Fix */
+        s->v = value & 0xff;
+        break;
+
+    case 0x68: /* Display Mode */
+        if ((s->mode ^ value) & 3)
+            s->invalidate = 1;
+        s->mode = value & 0xb7;
+        s->enable = value & 1;
+        s->blank = (value >> 1) & 1;
+        if (value & (1 << 4))
+            fprintf(stderr, "%s: Macrovision enable attempt!\n", __FUNCTION__);
+        break;
+
+    case 0x6a: /* Special Effects */
+        s->effect = value & 0xfb;
+        break;
+
+    case 0x6c: /* Input Window X Start Position 0 */
+        s->ix[0] &= 0x300;
+        s->ix[0] |= (value << 0) & 0x0ff;
+        break;
+    case 0x6e: /* Input Window X Start Position 1 */
+        s->ix[0] &= 0x0ff;
+        s->ix[0] |= (value << 8) & 0x300;
+        break;
+    case 0x70: /* Input Window Y Start Position 0 */
+        s->iy[0] &= 0x300;
+        s->iy[0] |= (value << 0) & 0x0ff;
+        break;
+    case 0x72: /* Input Window Y Start Position 1 */
+        s->iy[0] &= 0x0ff;
+        s->iy[0] |= (value << 8) & 0x300;
+        break;
+    case 0x74: /* Input Window X End Position 0 */
+        s->ix[1] &= 0x300;
+        s->ix[1] |= (value << 0) & 0x0ff;
+        break;
+    case 0x76: /* Input Window X End Position 1 */
+        s->ix[1] &= 0x0ff;
+        s->ix[1] |= (value << 8) & 0x300;
+        break;
+    case 0x78: /* Input Window Y End Position 0 */
+        s->iy[1] &= 0x300;
+        s->iy[1] |= (value << 0) & 0x0ff;
+        break;
+    case 0x7a: /* Input Window Y End Position 1 */
+        s->iy[1] &= 0x0ff;
+        s->iy[1] |= (value << 8) & 0x300;
+        break;
+    case 0x7c: /* Output Window X Start Position 0 */
+        s->ox[0] &= 0x300;
+        s->ox[0] |= (value << 0) & 0x0ff;
+        break;
+    case 0x7e: /* Output Window X Start Position 1 */
+        s->ox[0] &= 0x0ff;
+        s->ox[0] |= (value << 8) & 0x300;
+        break;
+    case 0x80: /* Output Window Y Start Position 0 */
+        s->oy[0] &= 0x300;
+        s->oy[0] |= (value << 0) & 0x0ff;
+        break;
+    case 0x82: /* Output Window Y Start Position 1 */
+        s->oy[0] &= 0x0ff;
+        s->oy[0] |= (value << 8) & 0x300;
+        break;
+    case 0x84: /* Output Window X End Position 0 */
+        s->ox[1] &= 0x300;
+        s->ox[1] |= (value << 0) & 0x0ff;
+        break;
+    case 0x86: /* Output Window X End Position 1 */
+        s->ox[1] &= 0x0ff;
+        s->ox[1] |= (value << 8) & 0x300;
+        break;
+    case 0x88: /* Output Window Y End Position 0 */
+        s->oy[1] &= 0x300;
+        s->oy[1] |= (value << 0) & 0x0ff;
+        break;
+    case 0x8a: /* Output Window Y End Position 1 */
+        s->oy[1] &= 0x0ff;
+        s->oy[1] |= (value << 8) & 0x300;
+        break;
+
+    case 0x8c: /* Input Data Format */
+        s->iformat = value & 0xf;
+        s->bpp = blizzard_iformat_bpp[s->iformat];
+        if (!s->bpp)
+            fprintf(stderr, "%s: Illegal or unsupported input format %x\n",
+                            __FUNCTION__, s->iformat);
+        break;
+    case 0x8e: /* Data Source Select */
+        s->source = value & 7;
+        /* Currently all windows will be "destructive overlays".  */
+        if ((!(s->effect & (1 << 3)) && (s->ix[0] != s->ox[0] ||
+                                        s->iy[0] != s->oy[0] ||
+                                        s->ix[1] != s->ox[1] ||
+                                        s->iy[1] != s->oy[1])) ||
+                        !((s->ix[1] - s->ix[0]) & (s->iy[1] - s->iy[0]) &
+                          (s->ox[1] - s->ox[0]) & (s->oy[1] - s->oy[0]) & 1))
+            fprintf(stderr, "%s: Illegal input/output window positions\n",
+                            __FUNCTION__);
+
+        blizzard_transfer_setup(s);
+        break;
+
+    case 0x90: /* Display Memory Data Port */
+        if (!s->data.len && !blizzard_transfer_setup(s))
+            break;
+
+        *s->data.ptr ++ = value;
+        if (-- s->data.len == 0)
+            blizzard_window(s);
+        break;
+
+    case 0xa8: /* Border Color 0 */
+        s->border_r = value;
+        break;
+    case 0xaa: /* Border Color 1 */
+        s->border_g = value;
+        break;
+    case 0xac: /* Border Color 2 */
+        s->border_b = value;
+        break;
+
+    case 0xb4: /* Gamma Correction Enable */
+        s->gamma_config = value & 0x87;
+        break;
+    case 0xb6: /* Gamma Correction Table Index */
+        s->gamma_idx = value;
+        break;
+    case 0xb8: /* Gamma Correction Table Data */
+        s->gamma_lut[s->gamma_idx ++] = value;
+        break;
+
+    case 0xba: /* 3x3 Matrix Enable */
+        s->matrix_ena = value & 1;
+        break;
+    case 0xbc ... 0xde:        /* Coefficient Registers */
+        s->matrix_coeff[(reg - 0xbc) >> 1] = value & ((reg & 2) ? 0x80 : 0xff);
+        break;
+    case 0xe0: /* 3x3 Matrix Red Offset */
+        s->matrix_r = value;
+        break;
+    case 0xe2: /* 3x3 Matrix Green Offset */
+        s->matrix_g = value;
+        break;
+    case 0xe4: /* 3x3 Matrix Blue Offset */
+        s->matrix_b = value;
+        break;
+
+    case 0xe6: /* Power-save */
+        s->pm = value & 0x83;
+        if (value & s->mode & 1)
+            fprintf(stderr, "%s: The display must be disabled before entering "
+                            "Standby Mode\n", __FUNCTION__);
+        break;
+    case 0xe8: /* Non-display Period Control / Status */
+        s->status = value & 0x1b;
+        break;
+    case 0xea: /* RGB Interface Control */
+        s->rgbgpio_dir = value & 0x8f;
+        break;
+    case 0xec: /* RGB Interface Status */
+        s->rgbgpio = value & 0xcf;
+        break;
+    case 0xee: /* General-purpose IO Pins Configuration */
+        s->gpio_dir = value;
+        break;
+    case 0xf0: /* General-purpose IO Pins Status / Control */
+        s->gpio = value;
+        break;
+    case 0xf2: /* GPIO Positive Edge Interrupt Trigger */
+        s->gpio_edge[0] = value;
+        break;
+    case 0xf4: /* GPIO Negative Edge Interrupt Trigger */
+        s->gpio_edge[1] = value;
+        break;
+    case 0xf6: /* GPIO Interrupt Status */
+        s->gpio_irq &= value;
+        break;
+    case 0xf8: /* GPIO Pull-down Control */
+        s->gpio_pdown = value;
+        break;
+
+    default:
+        fprintf(stderr, "%s: unknown register %02x\n", __FUNCTION__, reg);
+        break;
+    }
+}
+
+uint16_t s1d13745_read(void *opaque, int dc)
+{
+    BlizzardState *s = (BlizzardState *) opaque;
+    uint16_t value = blizzard_reg_read(s, s->reg);
+
+    if (s->swallow -- > 0)
+        return 0;
+    if (dc)
+        s->reg ++;
+
+    return value;
+}
+
+void s1d13745_write(void *opaque, int dc, uint16_t value)
+{
+    BlizzardState *s = (BlizzardState *) opaque;
+
+    if (s->swallow -- > 0)
+        return;
+    if (dc) {
+        blizzard_reg_write(s, s->reg, value);
+
+        if (s->reg != 0x90 && s->reg != 0x5a && s->reg != 0xb8)
+            s->reg += 2;
+    } else
+        s->reg = value & 0xff;
+}
+
+void s1d13745_write_block(void *opaque, int dc,
+                void *buf, size_t len, int pitch)
+{
+    BlizzardState *s = (BlizzardState *) opaque;
+
+    while (len > 0) {
+        if (s->reg == 0x90 && dc &&
+                        (s->data.len || blizzard_transfer_setup(s)) &&
+                        len >= (s->data.len << 1)) {
+            len -= s->data.len << 1;
+            s->data.len = 0;
+            s->data.data = buf;
+            if (pitch)
+                s->data.pitch = pitch;
+            blizzard_window(s);
+            s->data.data = s->data.buf;
+            continue;
+        }
+
+        s1d13745_write(opaque, dc, *(uint16_t *) buf);
+        len -= 2;
+        buf += 2;
+    }
+}
+
+static void blizzard_update_display(void *opaque)
+{
+    BlizzardState *s = (BlizzardState *) opaque;
+    DisplaySurface *surface = qemu_console_surface(s->con);
+    int y, bypp, bypl, bwidth;
+    uint8_t *src, *dst;
+
+    if (!s->enable)
+        return;
+
+    if (s->x != surface_width(surface) || s->y != surface_height(surface)) {
+        s->invalidate = 1;
+        qemu_console_resize(s->con, s->x, s->y);
+        surface = qemu_console_surface(s->con);
+    }
+
+    if (s->invalidate) {
+        s->invalidate = 0;
+
+        if (s->blank) {
+            bypp = surface_bytes_per_pixel(surface);
+            memset(surface_data(surface), 0, bypp * s->x * s->y);
+            return;
+        }
+
+        s->mx[0] = 0;
+        s->mx[1] = s->x;
+        s->my[0] = 0;
+        s->my[1] = s->y;
+    }
+
+    if (s->mx[1] <= s->mx[0])
+        return;
+
+    bypp = surface_bytes_per_pixel(surface);
+    bypl = bypp * s->x;
+    bwidth = bypp * (s->mx[1] - s->mx[0]);
+    y = s->my[0];
+    src = s->fb + bypl * y + bypp * s->mx[0];
+    dst = surface_data(surface) + bypl * y + bypp * s->mx[0];
+    for (; y < s->my[1]; y ++, src += bypl, dst += bypl)
+        memcpy(dst, src, bwidth);
+
+    dpy_gfx_update(s->con, s->mx[0], s->my[0],
+                   s->mx[1] - s->mx[0], y - s->my[0]);
+
+    s->mx[0] = s->x;
+    s->mx[1] = 0;
+    s->my[0] = s->y;
+    s->my[1] = 0;
+}
+
+static void blizzard_screen_dump(void *opaque, const char *filename,
+                                 bool cswitch, Error **errp)
+{
+    BlizzardState *s = (BlizzardState *) opaque;
+    DisplaySurface *surface = qemu_console_surface(s->con);
+
+    blizzard_update_display(opaque);
+    if (s && surface_data(surface)) {
+        ppm_save(filename, surface, errp);
+    }
+}
+
+#define DEPTH 8
+#include "blizzard_template.h"
+#define DEPTH 15
+#include "blizzard_template.h"
+#define DEPTH 16
+#include "blizzard_template.h"
+#define DEPTH 24
+#include "blizzard_template.h"
+#define DEPTH 32
+#include "blizzard_template.h"
+
+void *s1d13745_init(qemu_irq gpio_int)
+{
+    BlizzardState *s = (BlizzardState *) g_malloc0(sizeof(*s));
+    DisplaySurface *surface;
+
+    s->fb = g_malloc(0x180000);
+
+    s->con = graphic_console_init(blizzard_update_display,
+                                  blizzard_invalidate_display,
+                                  blizzard_screen_dump, NULL, s);
+    surface = qemu_console_surface(s->con);
+
+    switch (surface_bits_per_pixel(surface)) {
+    case 0:
+        s->line_fn_tab[0] = s->line_fn_tab[1] =
+                g_malloc0(sizeof(blizzard_fn_t) * 0x10);
+        break;
+    case 8:
+        s->line_fn_tab[0] = blizzard_draw_fn_8;
+        s->line_fn_tab[1] = blizzard_draw_fn_r_8;
+        break;
+    case 15:
+        s->line_fn_tab[0] = blizzard_draw_fn_15;
+        s->line_fn_tab[1] = blizzard_draw_fn_r_15;
+        break;
+    case 16:
+        s->line_fn_tab[0] = blizzard_draw_fn_16;
+        s->line_fn_tab[1] = blizzard_draw_fn_r_16;
+        break;
+    case 24:
+        s->line_fn_tab[0] = blizzard_draw_fn_24;
+        s->line_fn_tab[1] = blizzard_draw_fn_r_24;
+        break;
+    case 32:
+        s->line_fn_tab[0] = blizzard_draw_fn_32;
+        s->line_fn_tab[1] = blizzard_draw_fn_r_32;
+        break;
+    default:
+        fprintf(stderr, "%s: Bad color depth\n", __FUNCTION__);
+        exit(1);
+    }
+
+    blizzard_reset(s);
+
+    return s;
+}
diff --git a/hw/display/blizzard_template.h b/hw/display/blizzard_template.h
new file mode 100644 (file)
index 0000000..a8a8899
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * QEMU Epson S1D13744/S1D13745 templates
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ * Written by Andrzej Zaborowski <andrew@openedhand.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 or
+ * (at your option) version 3 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
+ * 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/>.
+ */
+
+#define SKIP_PIXEL(to)         to += deststep
+#if DEPTH == 8
+# define PIXEL_TYPE            uint8_t
+# define COPY_PIXEL(to, from)  *to = from; SKIP_PIXEL(to)
+# define COPY_PIXEL1(to, from) *to ++ = from
+#elif DEPTH == 15 || DEPTH == 16
+# define PIXEL_TYPE            uint16_t
+# define COPY_PIXEL(to, from)  *to = from; SKIP_PIXEL(to)
+# define COPY_PIXEL1(to, from) *to ++ = from
+#elif DEPTH == 24
+# define PIXEL_TYPE            uint8_t
+# define COPY_PIXEL(to, from)  \
+    to[0] = from; to[1] = (from) >> 8; to[2] = (from) >> 16; SKIP_PIXEL(to)
+# define COPY_PIXEL1(to, from) \
+    *to ++ = from; *to ++ = (from) >> 8; *to ++ = (from) >> 16
+#elif DEPTH == 32
+# define PIXEL_TYPE            uint32_t
+# define COPY_PIXEL(to, from)  *to = from; SKIP_PIXEL(to)
+# define COPY_PIXEL1(to, from) *to ++ = from
+#else
+# error unknown bit depth
+#endif
+
+#ifdef HOST_WORDS_BIGENDIAN
+# define SWAP_WORDS    1
+#endif
+
+static void glue(blizzard_draw_line16_, DEPTH)(PIXEL_TYPE *dest,
+                const uint16_t *src, unsigned int width)
+{
+#if !defined(SWAP_WORDS) && DEPTH == 16
+    memcpy(dest, src, width);
+#else
+    uint16_t data;
+    unsigned int r, g, b;
+    const uint16_t *end = (const void *) src + width;
+    while (src < end) {
+        data = *src ++;
+        b = (data & 0x1f) << 3;
+        data >>= 5;
+        g = (data & 0x3f) << 2;
+        data >>= 6;
+        r = (data & 0x1f) << 3;
+        data >>= 5;
+        COPY_PIXEL1(dest, glue(rgb_to_pixel, DEPTH)(r, g, b));
+    }
+#endif
+}
+
+static void glue(blizzard_draw_line24mode1_, DEPTH)(PIXEL_TYPE *dest,
+                const uint8_t *src, unsigned int width)
+{
+    /* TODO: check if SDL 24-bit planes are not in the same format and
+     * if so, use memcpy */
+    unsigned int r[2], g[2], b[2];
+    const uint8_t *end = src + width;
+    while (src < end) {
+        g[0] = *src ++;
+        r[0] = *src ++;
+        r[1] = *src ++;
+        b[0] = *src ++;
+        COPY_PIXEL1(dest, glue(rgb_to_pixel, DEPTH)(r[0], g[0], b[0]));
+        b[1] = *src ++;
+        g[1] = *src ++;
+        COPY_PIXEL1(dest, glue(rgb_to_pixel, DEPTH)(r[1], g[1], b[1]));
+    }
+}
+
+static void glue(blizzard_draw_line24mode2_, DEPTH)(PIXEL_TYPE *dest,
+                const uint8_t *src, unsigned int width)
+{
+    unsigned int r, g, b;
+    const uint8_t *end = src + width;
+    while (src < end) {
+        r = *src ++;
+        src ++;
+        b = *src ++;
+        g = *src ++;
+        COPY_PIXEL1(dest, glue(rgb_to_pixel, DEPTH)(r, g, b));
+    }
+}
+
+/* No rotation */
+static blizzard_fn_t glue(blizzard_draw_fn_, DEPTH)[0x10] = {
+    NULL,
+    /* RGB 5:6:5*/
+    (blizzard_fn_t) glue(blizzard_draw_line16_, DEPTH),
+    /* RGB 6:6:6 mode 1 */
+    (blizzard_fn_t) glue(blizzard_draw_line24mode1_, DEPTH),
+    /* RGB 8:8:8 mode 1 */
+    (blizzard_fn_t) glue(blizzard_draw_line24mode1_, DEPTH),
+    NULL, NULL,
+    /* RGB 6:6:6 mode 2 */
+    (blizzard_fn_t) glue(blizzard_draw_line24mode2_, DEPTH),
+    /* RGB 8:8:8 mode 2 */
+    (blizzard_fn_t) glue(blizzard_draw_line24mode2_, DEPTH),
+    /* YUV 4:2:2 */
+    NULL,
+    /* YUV 4:2:0 */
+    NULL,
+    NULL, NULL, NULL, NULL, NULL, NULL,
+};
+
+/* 90deg, 180deg and 270deg rotation */
+static blizzard_fn_t glue(blizzard_draw_fn_r_, DEPTH)[0x10] = {
+    /* TODO */
+    [0 ... 0xf] = NULL,
+};
+
+#undef DEPTH
+#undef SKIP_PIXEL
+#undef COPY_PIXEL
+#undef COPY_PIXEL1
+#undef PIXEL_TYPE
+
+#undef SWAP_WORDS
diff --git a/hw/display/cirrus_vga.c b/hw/display/cirrus_vga.c
new file mode 100644 (file)
index 0000000..bf2181a
--- /dev/null
@@ -0,0 +1,3021 @@
+/*
+ * QEMU Cirrus CLGD 54xx VGA Emulator.
+ *
+ * Copyright (c) 2004 Fabrice Bellard
+ * Copyright (c) 2004 Makoto Suzuki (suzu)
+ *
+ * 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.
+ */
+/*
+ * Reference: Finn Thogersons' VGADOC4b
+ *   available at http://home.worldonline.dk/~finth/
+ */
+#include "hw/hw.h"
+#include "hw/pci/pci.h"
+#include "ui/console.h"
+#include "vga_int.h"
+#include "hw/loader.h"
+
+/*
+ * TODO:
+ *    - destination write mask support not complete (bits 5..7)
+ *    - optimize linear mappings
+ *    - optimize bitblt functions
+ */
+
+//#define DEBUG_CIRRUS
+//#define DEBUG_BITBLT
+
+/***************************************
+ *
+ *  definitions
+ *
+ ***************************************/
+
+// ID
+#define CIRRUS_ID_CLGD5422  (0x23<<2)
+#define CIRRUS_ID_CLGD5426  (0x24<<2)
+#define CIRRUS_ID_CLGD5424  (0x25<<2)
+#define CIRRUS_ID_CLGD5428  (0x26<<2)
+#define CIRRUS_ID_CLGD5430  (0x28<<2)
+#define CIRRUS_ID_CLGD5434  (0x2A<<2)
+#define CIRRUS_ID_CLGD5436  (0x2B<<2)
+#define CIRRUS_ID_CLGD5446  (0x2E<<2)
+
+// sequencer 0x07
+#define CIRRUS_SR7_BPP_VGA            0x00
+#define CIRRUS_SR7_BPP_SVGA           0x01
+#define CIRRUS_SR7_BPP_MASK           0x0e
+#define CIRRUS_SR7_BPP_8              0x00
+#define CIRRUS_SR7_BPP_16_DOUBLEVCLK  0x02
+#define CIRRUS_SR7_BPP_24             0x04
+#define CIRRUS_SR7_BPP_16             0x06
+#define CIRRUS_SR7_BPP_32             0x08
+#define CIRRUS_SR7_ISAADDR_MASK       0xe0
+
+// sequencer 0x0f
+#define CIRRUS_MEMSIZE_512k        0x08
+#define CIRRUS_MEMSIZE_1M          0x10
+#define CIRRUS_MEMSIZE_2M          0x18
+#define CIRRUS_MEMFLAGS_BANKSWITCH 0x80        // bank switching is enabled.
+
+// sequencer 0x12
+#define CIRRUS_CURSOR_SHOW         0x01
+#define CIRRUS_CURSOR_HIDDENPEL    0x02
+#define CIRRUS_CURSOR_LARGE        0x04        // 64x64 if set, 32x32 if clear
+
+// sequencer 0x17
+#define CIRRUS_BUSTYPE_VLBFAST   0x10
+#define CIRRUS_BUSTYPE_PCI       0x20
+#define CIRRUS_BUSTYPE_VLBSLOW   0x30
+#define CIRRUS_BUSTYPE_ISA       0x38
+#define CIRRUS_MMIO_ENABLE       0x04
+#define CIRRUS_MMIO_USE_PCIADDR  0x40  // 0xb8000 if cleared.
+#define CIRRUS_MEMSIZEEXT_DOUBLE 0x80
+
+// control 0x0b
+#define CIRRUS_BANKING_DUAL             0x01
+#define CIRRUS_BANKING_GRANULARITY_16K  0x20   // set:16k, clear:4k
+
+// control 0x30
+#define CIRRUS_BLTMODE_BACKWARDS        0x01
+#define CIRRUS_BLTMODE_MEMSYSDEST       0x02
+#define CIRRUS_BLTMODE_MEMSYSSRC        0x04
+#define CIRRUS_BLTMODE_TRANSPARENTCOMP  0x08
+#define CIRRUS_BLTMODE_PATTERNCOPY      0x40
+#define CIRRUS_BLTMODE_COLOREXPAND      0x80
+#define CIRRUS_BLTMODE_PIXELWIDTHMASK   0x30
+#define CIRRUS_BLTMODE_PIXELWIDTH8      0x00
+#define CIRRUS_BLTMODE_PIXELWIDTH16     0x10
+#define CIRRUS_BLTMODE_PIXELWIDTH24     0x20
+#define CIRRUS_BLTMODE_PIXELWIDTH32     0x30
+
+// control 0x31
+#define CIRRUS_BLT_BUSY                 0x01
+#define CIRRUS_BLT_START                0x02
+#define CIRRUS_BLT_RESET                0x04
+#define CIRRUS_BLT_FIFOUSED             0x10
+#define CIRRUS_BLT_AUTOSTART            0x80
+
+// control 0x32
+#define CIRRUS_ROP_0                    0x00
+#define CIRRUS_ROP_SRC_AND_DST          0x05
+#define CIRRUS_ROP_NOP                  0x06
+#define CIRRUS_ROP_SRC_AND_NOTDST       0x09
+#define CIRRUS_ROP_NOTDST               0x0b
+#define CIRRUS_ROP_SRC                  0x0d
+#define CIRRUS_ROP_1                    0x0e
+#define CIRRUS_ROP_NOTSRC_AND_DST       0x50
+#define CIRRUS_ROP_SRC_XOR_DST          0x59
+#define CIRRUS_ROP_SRC_OR_DST           0x6d
+#define CIRRUS_ROP_NOTSRC_OR_NOTDST     0x90
+#define CIRRUS_ROP_SRC_NOTXOR_DST       0x95
+#define CIRRUS_ROP_SRC_OR_NOTDST        0xad
+#define CIRRUS_ROP_NOTSRC               0xd0
+#define CIRRUS_ROP_NOTSRC_OR_DST        0xd6
+#define CIRRUS_ROP_NOTSRC_AND_NOTDST    0xda
+
+#define CIRRUS_ROP_NOP_INDEX 2
+#define CIRRUS_ROP_SRC_INDEX 5
+
+// control 0x33
+#define CIRRUS_BLTMODEEXT_SOLIDFILL        0x04
+#define CIRRUS_BLTMODEEXT_COLOREXPINV      0x02
+#define CIRRUS_BLTMODEEXT_DWORDGRANULARITY 0x01
+
+// memory-mapped IO
+#define CIRRUS_MMIO_BLTBGCOLOR        0x00     // dword
+#define CIRRUS_MMIO_BLTFGCOLOR        0x04     // dword
+#define CIRRUS_MMIO_BLTWIDTH          0x08     // word
+#define CIRRUS_MMIO_BLTHEIGHT         0x0a     // word
+#define CIRRUS_MMIO_BLTDESTPITCH      0x0c     // word
+#define CIRRUS_MMIO_BLTSRCPITCH       0x0e     // word
+#define CIRRUS_MMIO_BLTDESTADDR       0x10     // dword
+#define CIRRUS_MMIO_BLTSRCADDR        0x14     // dword
+#define CIRRUS_MMIO_BLTWRITEMASK      0x17     // byte
+#define CIRRUS_MMIO_BLTMODE           0x18     // byte
+#define CIRRUS_MMIO_BLTROP            0x1a     // byte
+#define CIRRUS_MMIO_BLTMODEEXT        0x1b     // byte
+#define CIRRUS_MMIO_BLTTRANSPARENTCOLOR 0x1c   // word?
+#define CIRRUS_MMIO_BLTTRANSPARENTCOLORMASK 0x20       // word?
+#define CIRRUS_MMIO_LINEARDRAW_START_X 0x24    // word
+#define CIRRUS_MMIO_LINEARDRAW_START_Y 0x26    // word
+#define CIRRUS_MMIO_LINEARDRAW_END_X  0x28     // word
+#define CIRRUS_MMIO_LINEARDRAW_END_Y  0x2a     // word
+#define CIRRUS_MMIO_LINEARDRAW_LINESTYLE_INC 0x2c      // byte
+#define CIRRUS_MMIO_LINEARDRAW_LINESTYLE_ROLLOVER 0x2d // byte
+#define CIRRUS_MMIO_LINEARDRAW_LINESTYLE_MASK 0x2e     // byte
+#define CIRRUS_MMIO_LINEARDRAW_LINESTYLE_ACCUM 0x2f    // byte
+#define CIRRUS_MMIO_BRESENHAM_K1      0x30     // word
+#define CIRRUS_MMIO_BRESENHAM_K3      0x32     // word
+#define CIRRUS_MMIO_BRESENHAM_ERROR   0x34     // word
+#define CIRRUS_MMIO_BRESENHAM_DELTA_MAJOR 0x36 // word
+#define CIRRUS_MMIO_BRESENHAM_DIRECTION 0x38   // byte
+#define CIRRUS_MMIO_LINEDRAW_MODE     0x39     // byte
+#define CIRRUS_MMIO_BLTSTATUS         0x40     // byte
+
+#define CIRRUS_PNPMMIO_SIZE         0x1000
+
+#define BLTUNSAFE(s) \
+    ( \
+        ( /* check dst is within bounds */ \
+            (s)->cirrus_blt_height * ABS((s)->cirrus_blt_dstpitch) \
+                + ((s)->cirrus_blt_dstaddr & (s)->cirrus_addr_mask) > \
+                    (s)->vga.vram_size \
+        ) || \
+        ( /* check src is within bounds */ \
+            (s)->cirrus_blt_height * ABS((s)->cirrus_blt_srcpitch) \
+                + ((s)->cirrus_blt_srcaddr & (s)->cirrus_addr_mask) > \
+                    (s)->vga.vram_size \
+        ) \
+    )
+
+struct CirrusVGAState;
+typedef void (*cirrus_bitblt_rop_t) (struct CirrusVGAState *s,
+                                     uint8_t * dst, const uint8_t * src,
+                                    int dstpitch, int srcpitch,
+                                    int bltwidth, int bltheight);
+typedef void (*cirrus_fill_t)(struct CirrusVGAState *s,
+                              uint8_t *dst, int dst_pitch, int width, int height);
+
+typedef struct CirrusVGAState {
+    VGACommonState vga;
+
+    MemoryRegion cirrus_vga_io;
+    MemoryRegion cirrus_linear_io;
+    MemoryRegion cirrus_linear_bitblt_io;
+    MemoryRegion cirrus_mmio_io;
+    MemoryRegion pci_bar;
+    bool linear_vram;  /* vga.vram mapped over cirrus_linear_io */
+    MemoryRegion low_mem_container; /* container for 0xa0000-0xc0000 */
+    MemoryRegion low_mem;           /* always mapped, overridden by: */
+    MemoryRegion cirrus_bank[2];    /*   aliases at 0xa0000-0xb0000  */
+    uint32_t cirrus_addr_mask;
+    uint32_t linear_mmio_mask;
+    uint8_t cirrus_shadow_gr0;
+    uint8_t cirrus_shadow_gr1;
+    uint8_t cirrus_hidden_dac_lockindex;
+    uint8_t cirrus_hidden_dac_data;
+    uint32_t cirrus_bank_base[2];
+    uint32_t cirrus_bank_limit[2];
+    uint8_t cirrus_hidden_palette[48];
+    uint32_t hw_cursor_x;
+    uint32_t hw_cursor_y;
+    int cirrus_blt_pixelwidth;
+    int cirrus_blt_width;
+    int cirrus_blt_height;
+    int cirrus_blt_dstpitch;
+    int cirrus_blt_srcpitch;
+    uint32_t cirrus_blt_fgcol;
+    uint32_t cirrus_blt_bgcol;
+    uint32_t cirrus_blt_dstaddr;
+    uint32_t cirrus_blt_srcaddr;
+    uint8_t cirrus_blt_mode;
+    uint8_t cirrus_blt_modeext;
+    cirrus_bitblt_rop_t cirrus_rop;
+#define CIRRUS_BLTBUFSIZE (2048 * 4) /* one line width */
+    uint8_t cirrus_bltbuf[CIRRUS_BLTBUFSIZE];
+    uint8_t *cirrus_srcptr;
+    uint8_t *cirrus_srcptr_end;
+    uint32_t cirrus_srccounter;
+    /* hwcursor display state */
+    int last_hw_cursor_size;
+    int last_hw_cursor_x;
+    int last_hw_cursor_y;
+    int last_hw_cursor_y_start;
+    int last_hw_cursor_y_end;
+    int real_vram_size; /* XXX: suppress that */
+    int device_id;
+    int bustype;
+} CirrusVGAState;
+
+typedef struct PCICirrusVGAState {
+    PCIDevice dev;
+    CirrusVGAState cirrus_vga;
+} PCICirrusVGAState;
+
+typedef struct ISACirrusVGAState {
+    ISADevice dev;
+    CirrusVGAState cirrus_vga;
+} ISACirrusVGAState;
+
+static uint8_t rop_to_index[256];
+
+/***************************************
+ *
+ *  prototypes.
+ *
+ ***************************************/
+
+
+static void cirrus_bitblt_reset(CirrusVGAState *s);
+static void cirrus_update_memory_access(CirrusVGAState *s);
+
+/***************************************
+ *
+ *  raster operations
+ *
+ ***************************************/
+
+static void cirrus_bitblt_rop_nop(CirrusVGAState *s,
+                                  uint8_t *dst,const uint8_t *src,
+                                  int dstpitch,int srcpitch,
+                                  int bltwidth,int bltheight)
+{
+}
+
+static void cirrus_bitblt_fill_nop(CirrusVGAState *s,
+                                   uint8_t *dst,
+                                   int dstpitch, int bltwidth,int bltheight)
+{
+}
+
+#define ROP_NAME 0
+#define ROP_FN(d, s) 0
+#include "cirrus_vga_rop.h"
+
+#define ROP_NAME src_and_dst
+#define ROP_FN(d, s) (s) & (d)
+#include "cirrus_vga_rop.h"
+
+#define ROP_NAME src_and_notdst
+#define ROP_FN(d, s) (s) & (~(d))
+#include "cirrus_vga_rop.h"
+
+#define ROP_NAME notdst
+#define ROP_FN(d, s) ~(d)
+#include "cirrus_vga_rop.h"
+
+#define ROP_NAME src
+#define ROP_FN(d, s) s
+#include "cirrus_vga_rop.h"
+
+#define ROP_NAME 1
+#define ROP_FN(d, s) ~0
+#include "cirrus_vga_rop.h"
+
+#define ROP_NAME notsrc_and_dst
+#define ROP_FN(d, s) (~(s)) & (d)
+#include "cirrus_vga_rop.h"
+
+#define ROP_NAME src_xor_dst
+#define ROP_FN(d, s) (s) ^ (d)
+#include "cirrus_vga_rop.h"
+
+#define ROP_NAME src_or_dst
+#define ROP_FN(d, s) (s) | (d)
+#include "cirrus_vga_rop.h"
+
+#define ROP_NAME notsrc_or_notdst
+#define ROP_FN(d, s) (~(s)) | (~(d))
+#include "cirrus_vga_rop.h"
+
+#define ROP_NAME src_notxor_dst
+#define ROP_FN(d, s) ~((s) ^ (d))
+#include "cirrus_vga_rop.h"
+
+#define ROP_NAME src_or_notdst
+#define ROP_FN(d, s) (s) | (~(d))
+#include "cirrus_vga_rop.h"
+
+#define ROP_NAME notsrc
+#define ROP_FN(d, s) (~(s))
+#include "cirrus_vga_rop.h"
+
+#define ROP_NAME notsrc_or_dst
+#define ROP_FN(d, s) (~(s)) | (d)
+#include "cirrus_vga_rop.h"
+
+#define ROP_NAME notsrc_and_notdst
+#define ROP_FN(d, s) (~(s)) & (~(d))
+#include "cirrus_vga_rop.h"
+
+static const cirrus_bitblt_rop_t cirrus_fwd_rop[16] = {
+    cirrus_bitblt_rop_fwd_0,
+    cirrus_bitblt_rop_fwd_src_and_dst,
+    cirrus_bitblt_rop_nop,
+    cirrus_bitblt_rop_fwd_src_and_notdst,
+    cirrus_bitblt_rop_fwd_notdst,
+    cirrus_bitblt_rop_fwd_src,
+    cirrus_bitblt_rop_fwd_1,
+    cirrus_bitblt_rop_fwd_notsrc_and_dst,
+    cirrus_bitblt_rop_fwd_src_xor_dst,
+    cirrus_bitblt_rop_fwd_src_or_dst,
+    cirrus_bitblt_rop_fwd_notsrc_or_notdst,
+    cirrus_bitblt_rop_fwd_src_notxor_dst,
+    cirrus_bitblt_rop_fwd_src_or_notdst,
+    cirrus_bitblt_rop_fwd_notsrc,
+    cirrus_bitblt_rop_fwd_notsrc_or_dst,
+    cirrus_bitblt_rop_fwd_notsrc_and_notdst,
+};
+
+static const cirrus_bitblt_rop_t cirrus_bkwd_rop[16] = {
+    cirrus_bitblt_rop_bkwd_0,
+    cirrus_bitblt_rop_bkwd_src_and_dst,
+    cirrus_bitblt_rop_nop,
+    cirrus_bitblt_rop_bkwd_src_and_notdst,
+    cirrus_bitblt_rop_bkwd_notdst,
+    cirrus_bitblt_rop_bkwd_src,
+    cirrus_bitblt_rop_bkwd_1,
+    cirrus_bitblt_rop_bkwd_notsrc_and_dst,
+    cirrus_bitblt_rop_bkwd_src_xor_dst,
+    cirrus_bitblt_rop_bkwd_src_or_dst,
+    cirrus_bitblt_rop_bkwd_notsrc_or_notdst,
+    cirrus_bitblt_rop_bkwd_src_notxor_dst,
+    cirrus_bitblt_rop_bkwd_src_or_notdst,
+    cirrus_bitblt_rop_bkwd_notsrc,
+    cirrus_bitblt_rop_bkwd_notsrc_or_dst,
+    cirrus_bitblt_rop_bkwd_notsrc_and_notdst,
+};
+
+#define TRANSP_ROP(name) {\
+    name ## _8,\
+    name ## _16,\
+        }
+#define TRANSP_NOP(func) {\
+    func,\
+    func,\
+        }
+
+static const cirrus_bitblt_rop_t cirrus_fwd_transp_rop[16][2] = {
+    TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_0),
+    TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_src_and_dst),
+    TRANSP_NOP(cirrus_bitblt_rop_nop),
+    TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_src_and_notdst),
+    TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_notdst),
+    TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_src),
+    TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_1),
+    TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_notsrc_and_dst),
+    TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_src_xor_dst),
+    TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_src_or_dst),
+    TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_notsrc_or_notdst),
+    TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_src_notxor_dst),
+    TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_src_or_notdst),
+    TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_notsrc),
+    TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_notsrc_or_dst),
+    TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_notsrc_and_notdst),
+};
+
+static const cirrus_bitblt_rop_t cirrus_bkwd_transp_rop[16][2] = {
+    TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_0),
+    TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_src_and_dst),
+    TRANSP_NOP(cirrus_bitblt_rop_nop),
+    TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_src_and_notdst),
+    TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_notdst),
+    TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_src),
+    TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_1),
+    TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_notsrc_and_dst),
+    TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_src_xor_dst),
+    TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_src_or_dst),
+    TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_notsrc_or_notdst),
+    TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_src_notxor_dst),
+    TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_src_or_notdst),
+    TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_notsrc),
+    TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_notsrc_or_dst),
+    TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_notsrc_and_notdst),
+};
+
+#define ROP2(name) {\
+    name ## _8,\
+    name ## _16,\
+    name ## _24,\
+    name ## _32,\
+        }
+
+#define ROP_NOP2(func) {\
+    func,\
+    func,\
+    func,\
+    func,\
+        }
+
+static const cirrus_bitblt_rop_t cirrus_patternfill[16][4] = {
+    ROP2(cirrus_patternfill_0),
+    ROP2(cirrus_patternfill_src_and_dst),
+    ROP_NOP2(cirrus_bitblt_rop_nop),
+    ROP2(cirrus_patternfill_src_and_notdst),
+    ROP2(cirrus_patternfill_notdst),
+    ROP2(cirrus_patternfill_src),
+    ROP2(cirrus_patternfill_1),
+    ROP2(cirrus_patternfill_notsrc_and_dst),
+    ROP2(cirrus_patternfill_src_xor_dst),
+    ROP2(cirrus_patternfill_src_or_dst),
+    ROP2(cirrus_patternfill_notsrc_or_notdst),
+    ROP2(cirrus_patternfill_src_notxor_dst),
+    ROP2(cirrus_patternfill_src_or_notdst),
+    ROP2(cirrus_patternfill_notsrc),
+    ROP2(cirrus_patternfill_notsrc_or_dst),
+    ROP2(cirrus_patternfill_notsrc_and_notdst),
+};
+
+static const cirrus_bitblt_rop_t cirrus_colorexpand_transp[16][4] = {
+    ROP2(cirrus_colorexpand_transp_0),
+    ROP2(cirrus_colorexpand_transp_src_and_dst),
+    ROP_NOP2(cirrus_bitblt_rop_nop),
+    ROP2(cirrus_colorexpand_transp_src_and_notdst),
+    ROP2(cirrus_colorexpand_transp_notdst),
+    ROP2(cirrus_colorexpand_transp_src),
+    ROP2(cirrus_colorexpand_transp_1),
+    ROP2(cirrus_colorexpand_transp_notsrc_and_dst),
+    ROP2(cirrus_colorexpand_transp_src_xor_dst),
+    ROP2(cirrus_colorexpand_transp_src_or_dst),
+    ROP2(cirrus_colorexpand_transp_notsrc_or_notdst),
+    ROP2(cirrus_colorexpand_transp_src_notxor_dst),
+    ROP2(cirrus_colorexpand_transp_src_or_notdst),
+    ROP2(cirrus_colorexpand_transp_notsrc),
+    ROP2(cirrus_colorexpand_transp_notsrc_or_dst),
+    ROP2(cirrus_colorexpand_transp_notsrc_and_notdst),
+};
+
+static const cirrus_bitblt_rop_t cirrus_colorexpand[16][4] = {
+    ROP2(cirrus_colorexpand_0),
+    ROP2(cirrus_colorexpand_src_and_dst),
+    ROP_NOP2(cirrus_bitblt_rop_nop),
+    ROP2(cirrus_colorexpand_src_and_notdst),
+    ROP2(cirrus_colorexpand_notdst),
+    ROP2(cirrus_colorexpand_src),
+    ROP2(cirrus_colorexpand_1),
+    ROP2(cirrus_colorexpand_notsrc_and_dst),
+    ROP2(cirrus_colorexpand_src_xor_dst),
+    ROP2(cirrus_colorexpand_src_or_dst),
+    ROP2(cirrus_colorexpand_notsrc_or_notdst),
+    ROP2(cirrus_colorexpand_src_notxor_dst),
+    ROP2(cirrus_colorexpand_src_or_notdst),
+    ROP2(cirrus_colorexpand_notsrc),
+    ROP2(cirrus_colorexpand_notsrc_or_dst),
+    ROP2(cirrus_colorexpand_notsrc_and_notdst),
+};
+
+static const cirrus_bitblt_rop_t cirrus_colorexpand_pattern_transp[16][4] = {
+    ROP2(cirrus_colorexpand_pattern_transp_0),
+    ROP2(cirrus_colorexpand_pattern_transp_src_and_dst),
+    ROP_NOP2(cirrus_bitblt_rop_nop),
+    ROP2(cirrus_colorexpand_pattern_transp_src_and_notdst),
+    ROP2(cirrus_colorexpand_pattern_transp_notdst),
+    ROP2(cirrus_colorexpand_pattern_transp_src),
+    ROP2(cirrus_colorexpand_pattern_transp_1),
+    ROP2(cirrus_colorexpand_pattern_transp_notsrc_and_dst),
+    ROP2(cirrus_colorexpand_pattern_transp_src_xor_dst),
+    ROP2(cirrus_colorexpand_pattern_transp_src_or_dst),
+    ROP2(cirrus_colorexpand_pattern_transp_notsrc_or_notdst),
+    ROP2(cirrus_colorexpand_pattern_transp_src_notxor_dst),
+    ROP2(cirrus_colorexpand_pattern_transp_src_or_notdst),
+    ROP2(cirrus_colorexpand_pattern_transp_notsrc),
+    ROP2(cirrus_colorexpand_pattern_transp_notsrc_or_dst),
+    ROP2(cirrus_colorexpand_pattern_transp_notsrc_and_notdst),
+};
+
+static const cirrus_bitblt_rop_t cirrus_colorexpand_pattern[16][4] = {
+    ROP2(cirrus_colorexpand_pattern_0),
+    ROP2(cirrus_colorexpand_pattern_src_and_dst),
+    ROP_NOP2(cirrus_bitblt_rop_nop),
+    ROP2(cirrus_colorexpand_pattern_src_and_notdst),
+    ROP2(cirrus_colorexpand_pattern_notdst),
+    ROP2(cirrus_colorexpand_pattern_src),
+    ROP2(cirrus_colorexpand_pattern_1),
+    ROP2(cirrus_colorexpand_pattern_notsrc_and_dst),
+    ROP2(cirrus_colorexpand_pattern_src_xor_dst),
+    ROP2(cirrus_colorexpand_pattern_src_or_dst),
+    ROP2(cirrus_colorexpand_pattern_notsrc_or_notdst),
+    ROP2(cirrus_colorexpand_pattern_src_notxor_dst),
+    ROP2(cirrus_colorexpand_pattern_src_or_notdst),
+    ROP2(cirrus_colorexpand_pattern_notsrc),
+    ROP2(cirrus_colorexpand_pattern_notsrc_or_dst),
+    ROP2(cirrus_colorexpand_pattern_notsrc_and_notdst),
+};
+
+static const cirrus_fill_t cirrus_fill[16][4] = {
+    ROP2(cirrus_fill_0),
+    ROP2(cirrus_fill_src_and_dst),
+    ROP_NOP2(cirrus_bitblt_fill_nop),
+    ROP2(cirrus_fill_src_and_notdst),
+    ROP2(cirrus_fill_notdst),
+    ROP2(cirrus_fill_src),
+    ROP2(cirrus_fill_1),
+    ROP2(cirrus_fill_notsrc_and_dst),
+    ROP2(cirrus_fill_src_xor_dst),
+    ROP2(cirrus_fill_src_or_dst),
+    ROP2(cirrus_fill_notsrc_or_notdst),
+    ROP2(cirrus_fill_src_notxor_dst),
+    ROP2(cirrus_fill_src_or_notdst),
+    ROP2(cirrus_fill_notsrc),
+    ROP2(cirrus_fill_notsrc_or_dst),
+    ROP2(cirrus_fill_notsrc_and_notdst),
+};
+
+static inline void cirrus_bitblt_fgcol(CirrusVGAState *s)
+{
+    unsigned int color;
+    switch (s->cirrus_blt_pixelwidth) {
+    case 1:
+        s->cirrus_blt_fgcol = s->cirrus_shadow_gr1;
+        break;
+    case 2:
+        color = s->cirrus_shadow_gr1 | (s->vga.gr[0x11] << 8);
+        s->cirrus_blt_fgcol = le16_to_cpu(color);
+        break;
+    case 3:
+        s->cirrus_blt_fgcol = s->cirrus_shadow_gr1 |
+            (s->vga.gr[0x11] << 8) | (s->vga.gr[0x13] << 16);
+        break;
+    default:
+    case 4:
+        color = s->cirrus_shadow_gr1 | (s->vga.gr[0x11] << 8) |
+            (s->vga.gr[0x13] << 16) | (s->vga.gr[0x15] << 24);
+        s->cirrus_blt_fgcol = le32_to_cpu(color);
+        break;
+    }
+}
+
+static inline void cirrus_bitblt_bgcol(CirrusVGAState *s)
+{
+    unsigned int color;
+    switch (s->cirrus_blt_pixelwidth) {
+    case 1:
+        s->cirrus_blt_bgcol = s->cirrus_shadow_gr0;
+        break;
+    case 2:
+        color = s->cirrus_shadow_gr0 | (s->vga.gr[0x10] << 8);
+        s->cirrus_blt_bgcol = le16_to_cpu(color);
+        break;
+    case 3:
+        s->cirrus_blt_bgcol = s->cirrus_shadow_gr0 |
+            (s->vga.gr[0x10] << 8) | (s->vga.gr[0x12] << 16);
+        break;
+    default:
+    case 4:
+        color = s->cirrus_shadow_gr0 | (s->vga.gr[0x10] << 8) |
+            (s->vga.gr[0x12] << 16) | (s->vga.gr[0x14] << 24);
+        s->cirrus_blt_bgcol = le32_to_cpu(color);
+        break;
+    }
+}
+
+static void cirrus_invalidate_region(CirrusVGAState * s, int off_begin,
+                                    int off_pitch, int bytesperline,
+                                    int lines)
+{
+    int y;
+    int off_cur;
+    int off_cur_end;
+
+    for (y = 0; y < lines; y++) {
+       off_cur = off_begin;
+       off_cur_end = (off_cur + bytesperline) & s->cirrus_addr_mask;
+        memory_region_set_dirty(&s->vga.vram, off_cur, off_cur_end - off_cur);
+       off_begin += off_pitch;
+    }
+}
+
+static int cirrus_bitblt_common_patterncopy(CirrusVGAState * s,
+                                           const uint8_t * src)
+{
+    uint8_t *dst;
+
+    dst = s->vga.vram_ptr + (s->cirrus_blt_dstaddr & s->cirrus_addr_mask);
+
+    if (BLTUNSAFE(s))
+        return 0;
+
+    (*s->cirrus_rop) (s, dst, src,
+                      s->cirrus_blt_dstpitch, 0,
+                      s->cirrus_blt_width, s->cirrus_blt_height);
+    cirrus_invalidate_region(s, s->cirrus_blt_dstaddr,
+                             s->cirrus_blt_dstpitch, s->cirrus_blt_width,
+                             s->cirrus_blt_height);
+    return 1;
+}
+
+/* fill */
+
+static int cirrus_bitblt_solidfill(CirrusVGAState *s, int blt_rop)
+{
+    cirrus_fill_t rop_func;
+
+    if (BLTUNSAFE(s))
+        return 0;
+    rop_func = cirrus_fill[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
+    rop_func(s, s->vga.vram_ptr + (s->cirrus_blt_dstaddr & s->cirrus_addr_mask),
+             s->cirrus_blt_dstpitch,
+             s->cirrus_blt_width, s->cirrus_blt_height);
+    cirrus_invalidate_region(s, s->cirrus_blt_dstaddr,
+                            s->cirrus_blt_dstpitch, s->cirrus_blt_width,
+                            s->cirrus_blt_height);
+    cirrus_bitblt_reset(s);
+    return 1;
+}
+
+/***************************************
+ *
+ *  bitblt (video-to-video)
+ *
+ ***************************************/
+
+static int cirrus_bitblt_videotovideo_patterncopy(CirrusVGAState * s)
+{
+    return cirrus_bitblt_common_patterncopy(s,
+                                           s->vga.vram_ptr + ((s->cirrus_blt_srcaddr & ~7) &
+                                            s->cirrus_addr_mask));
+}
+
+static void cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h)
+{
+    int sx = 0, sy = 0;
+    int dx = 0, dy = 0;
+    int depth = 0;
+    int notify = 0;
+
+    /* make sure to only copy if it's a plain copy ROP */
+    if (*s->cirrus_rop == cirrus_bitblt_rop_fwd_src ||
+        *s->cirrus_rop == cirrus_bitblt_rop_bkwd_src) {
+
+        int width, height;
+
+        depth = s->vga.get_bpp(&s->vga) / 8;
+        s->vga.get_resolution(&s->vga, &width, &height);
+
+        /* extra x, y */
+        sx = (src % ABS(s->cirrus_blt_srcpitch)) / depth;
+        sy = (src / ABS(s->cirrus_blt_srcpitch));
+        dx = (dst % ABS(s->cirrus_blt_dstpitch)) / depth;
+        dy = (dst / ABS(s->cirrus_blt_dstpitch));
+
+        /* normalize width */
+        w /= depth;
+
+        /* if we're doing a backward copy, we have to adjust
+           our x/y to be the upper left corner (instead of the lower
+           right corner) */
+        if (s->cirrus_blt_dstpitch < 0) {
+            sx -= (s->cirrus_blt_width / depth) - 1;
+            dx -= (s->cirrus_blt_width / depth) - 1;
+            sy -= s->cirrus_blt_height - 1;
+            dy -= s->cirrus_blt_height - 1;
+        }
+
+        /* are we in the visible portion of memory? */
+        if (sx >= 0 && sy >= 0 && dx >= 0 && dy >= 0 &&
+            (sx + w) <= width && (sy + h) <= height &&
+            (dx + w) <= width && (dy + h) <= height) {
+            notify = 1;
+        }
+    }
+
+    /* we have to flush all pending changes so that the copy
+       is generated at the appropriate moment in time */
+    if (notify)
+       vga_hw_update();
+
+    (*s->cirrus_rop) (s, s->vga.vram_ptr +
+                     (s->cirrus_blt_dstaddr & s->cirrus_addr_mask),
+                     s->vga.vram_ptr +
+                     (s->cirrus_blt_srcaddr & s->cirrus_addr_mask),
+                     s->cirrus_blt_dstpitch, s->cirrus_blt_srcpitch,
+                     s->cirrus_blt_width, s->cirrus_blt_height);
+
+    if (notify) {
+        qemu_console_copy(s->vga.con,
+                         sx, sy, dx, dy,
+                         s->cirrus_blt_width / depth,
+                         s->cirrus_blt_height);
+    }
+
+    /* we don't have to notify the display that this portion has
+       changed since qemu_console_copy implies this */
+
+    cirrus_invalidate_region(s, s->cirrus_blt_dstaddr,
+                               s->cirrus_blt_dstpitch, s->cirrus_blt_width,
+                               s->cirrus_blt_height);
+}
+
+static int cirrus_bitblt_videotovideo_copy(CirrusVGAState * s)
+{
+    if (BLTUNSAFE(s))
+        return 0;
+
+    cirrus_do_copy(s, s->cirrus_blt_dstaddr - s->vga.start_addr,
+            s->cirrus_blt_srcaddr - s->vga.start_addr,
+            s->cirrus_blt_width, s->cirrus_blt_height);
+
+    return 1;
+}
+
+/***************************************
+ *
+ *  bitblt (cpu-to-video)
+ *
+ ***************************************/
+
+static void cirrus_bitblt_cputovideo_next(CirrusVGAState * s)
+{
+    int copy_count;
+    uint8_t *end_ptr;
+
+    if (s->cirrus_srccounter > 0) {
+        if (s->cirrus_blt_mode & CIRRUS_BLTMODE_PATTERNCOPY) {
+            cirrus_bitblt_common_patterncopy(s, s->cirrus_bltbuf);
+        the_end:
+            s->cirrus_srccounter = 0;
+            cirrus_bitblt_reset(s);
+        } else {
+            /* at least one scan line */
+            do {
+                (*s->cirrus_rop)(s, s->vga.vram_ptr +
+                                 (s->cirrus_blt_dstaddr & s->cirrus_addr_mask),
+                                  s->cirrus_bltbuf, 0, 0, s->cirrus_blt_width, 1);
+                cirrus_invalidate_region(s, s->cirrus_blt_dstaddr, 0,
+                                         s->cirrus_blt_width, 1);
+                s->cirrus_blt_dstaddr += s->cirrus_blt_dstpitch;
+                s->cirrus_srccounter -= s->cirrus_blt_srcpitch;
+                if (s->cirrus_srccounter <= 0)
+                    goto the_end;
+                /* more bytes than needed can be transferred because of
+                   word alignment, so we keep them for the next line */
+                /* XXX: keep alignment to speed up transfer */
+                end_ptr = s->cirrus_bltbuf + s->cirrus_blt_srcpitch;
+                copy_count = s->cirrus_srcptr_end - end_ptr;
+                memmove(s->cirrus_bltbuf, end_ptr, copy_count);
+                s->cirrus_srcptr = s->cirrus_bltbuf + copy_count;
+                s->cirrus_srcptr_end = s->cirrus_bltbuf + s->cirrus_blt_srcpitch;
+            } while (s->cirrus_srcptr >= s->cirrus_srcptr_end);
+        }
+    }
+}
+
+/***************************************
+ *
+ *  bitblt wrapper
+ *
+ ***************************************/
+
+static void cirrus_bitblt_reset(CirrusVGAState * s)
+{
+    int need_update;
+
+    s->vga.gr[0x31] &=
+       ~(CIRRUS_BLT_START | CIRRUS_BLT_BUSY | CIRRUS_BLT_FIFOUSED);
+    need_update = s->cirrus_srcptr != &s->cirrus_bltbuf[0]
+        || s->cirrus_srcptr_end != &s->cirrus_bltbuf[0];
+    s->cirrus_srcptr = &s->cirrus_bltbuf[0];
+    s->cirrus_srcptr_end = &s->cirrus_bltbuf[0];
+    s->cirrus_srccounter = 0;
+    if (!need_update)
+        return;
+    cirrus_update_memory_access(s);
+}
+
+static int cirrus_bitblt_cputovideo(CirrusVGAState * s)
+{
+    int w;
+
+    s->cirrus_blt_mode &= ~CIRRUS_BLTMODE_MEMSYSSRC;
+    s->cirrus_srcptr = &s->cirrus_bltbuf[0];
+    s->cirrus_srcptr_end = &s->cirrus_bltbuf[0];
+
+    if (s->cirrus_blt_mode & CIRRUS_BLTMODE_PATTERNCOPY) {
+       if (s->cirrus_blt_mode & CIRRUS_BLTMODE_COLOREXPAND) {
+           s->cirrus_blt_srcpitch = 8;
+       } else {
+            /* XXX: check for 24 bpp */
+           s->cirrus_blt_srcpitch = 8 * 8 * s->cirrus_blt_pixelwidth;
+       }
+       s->cirrus_srccounter = s->cirrus_blt_srcpitch;
+    } else {
+       if (s->cirrus_blt_mode & CIRRUS_BLTMODE_COLOREXPAND) {
+            w = s->cirrus_blt_width / s->cirrus_blt_pixelwidth;
+            if (s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_DWORDGRANULARITY)
+                s->cirrus_blt_srcpitch = ((w + 31) >> 5);
+            else
+                s->cirrus_blt_srcpitch = ((w + 7) >> 3);
+       } else {
+            /* always align input size to 32 bits */
+           s->cirrus_blt_srcpitch = (s->cirrus_blt_width + 3) & ~3;
+       }
+        s->cirrus_srccounter = s->cirrus_blt_srcpitch * s->cirrus_blt_height;
+    }
+    s->cirrus_srcptr = s->cirrus_bltbuf;
+    s->cirrus_srcptr_end = s->cirrus_bltbuf + s->cirrus_blt_srcpitch;
+    cirrus_update_memory_access(s);
+    return 1;
+}
+
+static int cirrus_bitblt_videotocpu(CirrusVGAState * s)
+{
+    /* XXX */
+#ifdef DEBUG_BITBLT
+    printf("cirrus: bitblt (video to cpu) is not implemented yet\n");
+#endif
+    return 0;
+}
+
+static int cirrus_bitblt_videotovideo(CirrusVGAState * s)
+{
+    int ret;
+
+    if (s->cirrus_blt_mode & CIRRUS_BLTMODE_PATTERNCOPY) {
+       ret = cirrus_bitblt_videotovideo_patterncopy(s);
+    } else {
+       ret = cirrus_bitblt_videotovideo_copy(s);
+    }
+    if (ret)
+       cirrus_bitblt_reset(s);
+    return ret;
+}
+
+static void cirrus_bitblt_start(CirrusVGAState * s)
+{
+    uint8_t blt_rop;
+
+    s->vga.gr[0x31] |= CIRRUS_BLT_BUSY;
+
+    s->cirrus_blt_width = (s->vga.gr[0x20] | (s->vga.gr[0x21] << 8)) + 1;
+    s->cirrus_blt_height = (s->vga.gr[0x22] | (s->vga.gr[0x23] << 8)) + 1;
+    s->cirrus_blt_dstpitch = (s->vga.gr[0x24] | (s->vga.gr[0x25] << 8));
+    s->cirrus_blt_srcpitch = (s->vga.gr[0x26] | (s->vga.gr[0x27] << 8));
+    s->cirrus_blt_dstaddr =
+       (s->vga.gr[0x28] | (s->vga.gr[0x29] << 8) | (s->vga.gr[0x2a] << 16));
+    s->cirrus_blt_srcaddr =
+       (s->vga.gr[0x2c] | (s->vga.gr[0x2d] << 8) | (s->vga.gr[0x2e] << 16));
+    s->cirrus_blt_mode = s->vga.gr[0x30];
+    s->cirrus_blt_modeext = s->vga.gr[0x33];
+    blt_rop = s->vga.gr[0x32];
+
+#ifdef DEBUG_BITBLT
+    printf("rop=0x%02x mode=0x%02x modeext=0x%02x w=%d h=%d dpitch=%d spitch=%d daddr=0x%08x saddr=0x%08x writemask=0x%02x\n",
+           blt_rop,
+           s->cirrus_blt_mode,
+           s->cirrus_blt_modeext,
+           s->cirrus_blt_width,
+           s->cirrus_blt_height,
+           s->cirrus_blt_dstpitch,
+           s->cirrus_blt_srcpitch,
+           s->cirrus_blt_dstaddr,
+           s->cirrus_blt_srcaddr,
+           s->vga.gr[0x2f]);
+#endif
+
+    switch (s->cirrus_blt_mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) {
+    case CIRRUS_BLTMODE_PIXELWIDTH8:
+       s->cirrus_blt_pixelwidth = 1;
+       break;
+    case CIRRUS_BLTMODE_PIXELWIDTH16:
+       s->cirrus_blt_pixelwidth = 2;
+       break;
+    case CIRRUS_BLTMODE_PIXELWIDTH24:
+       s->cirrus_blt_pixelwidth = 3;
+       break;
+    case CIRRUS_BLTMODE_PIXELWIDTH32:
+       s->cirrus_blt_pixelwidth = 4;
+       break;
+    default:
+#ifdef DEBUG_BITBLT
+       printf("cirrus: bitblt - pixel width is unknown\n");
+#endif
+       goto bitblt_ignore;
+    }
+    s->cirrus_blt_mode &= ~CIRRUS_BLTMODE_PIXELWIDTHMASK;
+
+    if ((s->
+        cirrus_blt_mode & (CIRRUS_BLTMODE_MEMSYSSRC |
+                           CIRRUS_BLTMODE_MEMSYSDEST))
+       == (CIRRUS_BLTMODE_MEMSYSSRC | CIRRUS_BLTMODE_MEMSYSDEST)) {
+#ifdef DEBUG_BITBLT
+       printf("cirrus: bitblt - memory-to-memory copy is requested\n");
+#endif
+       goto bitblt_ignore;
+    }
+
+    if ((s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_SOLIDFILL) &&
+        (s->cirrus_blt_mode & (CIRRUS_BLTMODE_MEMSYSDEST |
+                               CIRRUS_BLTMODE_TRANSPARENTCOMP |
+                               CIRRUS_BLTMODE_PATTERNCOPY |
+                               CIRRUS_BLTMODE_COLOREXPAND)) ==
+         (CIRRUS_BLTMODE_PATTERNCOPY | CIRRUS_BLTMODE_COLOREXPAND)) {
+        cirrus_bitblt_fgcol(s);
+        cirrus_bitblt_solidfill(s, blt_rop);
+    } else {
+        if ((s->cirrus_blt_mode & (CIRRUS_BLTMODE_COLOREXPAND |
+                                   CIRRUS_BLTMODE_PATTERNCOPY)) ==
+            CIRRUS_BLTMODE_COLOREXPAND) {
+
+            if (s->cirrus_blt_mode & CIRRUS_BLTMODE_TRANSPARENTCOMP) {
+                if (s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_COLOREXPINV)
+                    cirrus_bitblt_bgcol(s);
+                else
+                    cirrus_bitblt_fgcol(s);
+                s->cirrus_rop = cirrus_colorexpand_transp[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
+            } else {
+                cirrus_bitblt_fgcol(s);
+                cirrus_bitblt_bgcol(s);
+                s->cirrus_rop = cirrus_colorexpand[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
+            }
+        } else if (s->cirrus_blt_mode & CIRRUS_BLTMODE_PATTERNCOPY) {
+            if (s->cirrus_blt_mode & CIRRUS_BLTMODE_COLOREXPAND) {
+                if (s->cirrus_blt_mode & CIRRUS_BLTMODE_TRANSPARENTCOMP) {
+                    if (s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_COLOREXPINV)
+                        cirrus_bitblt_bgcol(s);
+                    else
+                        cirrus_bitblt_fgcol(s);
+                    s->cirrus_rop = cirrus_colorexpand_pattern_transp[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
+                } else {
+                    cirrus_bitblt_fgcol(s);
+                    cirrus_bitblt_bgcol(s);
+                    s->cirrus_rop = cirrus_colorexpand_pattern[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
+                }
+            } else {
+                s->cirrus_rop = cirrus_patternfill[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
+            }
+        } else {
+           if (s->cirrus_blt_mode & CIRRUS_BLTMODE_TRANSPARENTCOMP) {
+               if (s->cirrus_blt_pixelwidth > 2) {
+                   printf("src transparent without colorexpand must be 8bpp or 16bpp\n");
+                   goto bitblt_ignore;
+               }
+               if (s->cirrus_blt_mode & CIRRUS_BLTMODE_BACKWARDS) {
+                   s->cirrus_blt_dstpitch = -s->cirrus_blt_dstpitch;
+                   s->cirrus_blt_srcpitch = -s->cirrus_blt_srcpitch;
+                   s->cirrus_rop = cirrus_bkwd_transp_rop[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
+               } else {
+                   s->cirrus_rop = cirrus_fwd_transp_rop[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
+               }
+           } else {
+               if (s->cirrus_blt_mode & CIRRUS_BLTMODE_BACKWARDS) {
+                   s->cirrus_blt_dstpitch = -s->cirrus_blt_dstpitch;
+                   s->cirrus_blt_srcpitch = -s->cirrus_blt_srcpitch;
+                   s->cirrus_rop = cirrus_bkwd_rop[rop_to_index[blt_rop]];
+               } else {
+                   s->cirrus_rop = cirrus_fwd_rop[rop_to_index[blt_rop]];
+               }
+           }
+       }
+        // setup bitblt engine.
+        if (s->cirrus_blt_mode & CIRRUS_BLTMODE_MEMSYSSRC) {
+            if (!cirrus_bitblt_cputovideo(s))
+                goto bitblt_ignore;
+        } else if (s->cirrus_blt_mode & CIRRUS_BLTMODE_MEMSYSDEST) {
+            if (!cirrus_bitblt_videotocpu(s))
+                goto bitblt_ignore;
+        } else {
+            if (!cirrus_bitblt_videotovideo(s))
+                goto bitblt_ignore;
+        }
+    }
+    return;
+  bitblt_ignore:;
+    cirrus_bitblt_reset(s);
+}
+
+static void cirrus_write_bitblt(CirrusVGAState * s, unsigned reg_value)
+{
+    unsigned old_value;
+
+    old_value = s->vga.gr[0x31];
+    s->vga.gr[0x31] = reg_value;
+
+    if (((old_value & CIRRUS_BLT_RESET) != 0) &&
+       ((reg_value & CIRRUS_BLT_RESET) == 0)) {
+       cirrus_bitblt_reset(s);
+    } else if (((old_value & CIRRUS_BLT_START) == 0) &&
+              ((reg_value & CIRRUS_BLT_START) != 0)) {
+       cirrus_bitblt_start(s);
+    }
+}
+
+
+/***************************************
+ *
+ *  basic parameters
+ *
+ ***************************************/
+
+static void cirrus_get_offsets(VGACommonState *s1,
+                               uint32_t *pline_offset,
+                               uint32_t *pstart_addr,
+                               uint32_t *pline_compare)
+{
+    CirrusVGAState * s = container_of(s1, CirrusVGAState, vga);
+    uint32_t start_addr, line_offset, line_compare;
+
+    line_offset = s->vga.cr[0x13]
+       | ((s->vga.cr[0x1b] & 0x10) << 4);
+    line_offset <<= 3;
+    *pline_offset = line_offset;
+
+    start_addr = (s->vga.cr[0x0c] << 8)
+       | s->vga.cr[0x0d]
+       | ((s->vga.cr[0x1b] & 0x01) << 16)
+       | ((s->vga.cr[0x1b] & 0x0c) << 15)
+       | ((s->vga.cr[0x1d] & 0x80) << 12);
+    *pstart_addr = start_addr;
+
+    line_compare = s->vga.cr[0x18] |
+        ((s->vga.cr[0x07] & 0x10) << 4) |
+        ((s->vga.cr[0x09] & 0x40) << 3);
+    *pline_compare = line_compare;
+}
+
+static uint32_t cirrus_get_bpp16_depth(CirrusVGAState * s)
+{
+    uint32_t ret = 16;
+
+    switch (s->cirrus_hidden_dac_data & 0xf) {
+    case 0:
+       ret = 15;
+       break;                  /* Sierra HiColor */
+    case 1:
+       ret = 16;
+       break;                  /* XGA HiColor */
+    default:
+#ifdef DEBUG_CIRRUS
+       printf("cirrus: invalid DAC value %x in 16bpp\n",
+              (s->cirrus_hidden_dac_data & 0xf));
+#endif
+       ret = 15;               /* XXX */
+       break;
+    }
+    return ret;
+}
+
+static int cirrus_get_bpp(VGACommonState *s1)
+{
+    CirrusVGAState * s = container_of(s1, CirrusVGAState, vga);
+    uint32_t ret = 8;
+
+    if ((s->vga.sr[0x07] & 0x01) != 0) {
+       /* Cirrus SVGA */
+       switch (s->vga.sr[0x07] & CIRRUS_SR7_BPP_MASK) {
+       case CIRRUS_SR7_BPP_8:
+           ret = 8;
+           break;
+       case CIRRUS_SR7_BPP_16_DOUBLEVCLK:
+           ret = cirrus_get_bpp16_depth(s);
+           break;
+       case CIRRUS_SR7_BPP_24:
+           ret = 24;
+           break;
+       case CIRRUS_SR7_BPP_16:
+           ret = cirrus_get_bpp16_depth(s);
+           break;
+       case CIRRUS_SR7_BPP_32:
+           ret = 32;
+           break;
+       default:
+#ifdef DEBUG_CIRRUS
+           printf("cirrus: unknown bpp - sr7=%x\n", s->vga.sr[0x7]);
+#endif
+           ret = 8;
+           break;
+       }
+    } else {
+       /* VGA */
+       ret = 0;
+    }
+
+    return ret;
+}
+
+static void cirrus_get_resolution(VGACommonState *s, int *pwidth, int *pheight)
+{
+    int width, height;
+
+    width = (s->cr[0x01] + 1) * 8;
+    height = s->cr[0x12] |
+        ((s->cr[0x07] & 0x02) << 7) |
+        ((s->cr[0x07] & 0x40) << 3);
+    height = (height + 1);
+    /* interlace support */
+    if (s->cr[0x1a] & 0x01)
+        height = height * 2;
+    *pwidth = width;
+    *pheight = height;
+}
+
+/***************************************
+ *
+ * bank memory
+ *
+ ***************************************/
+
+static void cirrus_update_bank_ptr(CirrusVGAState * s, unsigned bank_index)
+{
+    unsigned offset;
+    unsigned limit;
+
+    if ((s->vga.gr[0x0b] & 0x01) != 0) /* dual bank */
+       offset = s->vga.gr[0x09 + bank_index];
+    else                       /* single bank */
+       offset = s->vga.gr[0x09];
+
+    if ((s->vga.gr[0x0b] & 0x20) != 0)
+       offset <<= 14;
+    else
+       offset <<= 12;
+
+    if (s->real_vram_size <= offset)
+       limit = 0;
+    else
+       limit = s->real_vram_size - offset;
+
+    if (((s->vga.gr[0x0b] & 0x01) == 0) && (bank_index != 0)) {
+       if (limit > 0x8000) {
+           offset += 0x8000;
+           limit -= 0x8000;
+       } else {
+           limit = 0;
+       }
+    }
+
+    if (limit > 0) {
+       s->cirrus_bank_base[bank_index] = offset;
+       s->cirrus_bank_limit[bank_index] = limit;
+    } else {
+       s->cirrus_bank_base[bank_index] = 0;
+       s->cirrus_bank_limit[bank_index] = 0;
+    }
+}
+
+/***************************************
+ *
+ *  I/O access between 0x3c4-0x3c5
+ *
+ ***************************************/
+
+static int cirrus_vga_read_sr(CirrusVGAState * s)
+{
+    switch (s->vga.sr_index) {
+    case 0x00:                 // Standard VGA
+    case 0x01:                 // Standard VGA
+    case 0x02:                 // Standard VGA
+    case 0x03:                 // Standard VGA
+    case 0x04:                 // Standard VGA
+       return s->vga.sr[s->vga.sr_index];
+    case 0x06:                 // Unlock Cirrus extensions
+       return s->vga.sr[s->vga.sr_index];
+    case 0x10:
+    case 0x30:
+    case 0x50:
+    case 0x70:                 // Graphics Cursor X
+    case 0x90:
+    case 0xb0:
+    case 0xd0:
+    case 0xf0:                 // Graphics Cursor X
+       return s->vga.sr[0x10];
+    case 0x11:
+    case 0x31:
+    case 0x51:
+    case 0x71:                 // Graphics Cursor Y
+    case 0x91:
+    case 0xb1:
+    case 0xd1:
+    case 0xf1:                 // Graphics Cursor Y
+       return s->vga.sr[0x11];
+    case 0x05:                 // ???
+    case 0x07:                 // Extended Sequencer Mode
+    case 0x08:                 // EEPROM Control
+    case 0x09:                 // Scratch Register 0
+    case 0x0a:                 // Scratch Register 1
+    case 0x0b:                 // VCLK 0
+    case 0x0c:                 // VCLK 1
+    case 0x0d:                 // VCLK 2
+    case 0x0e:                 // VCLK 3
+    case 0x0f:                 // DRAM Control
+    case 0x12:                 // Graphics Cursor Attribute
+    case 0x13:                 // Graphics Cursor Pattern Address
+    case 0x14:                 // Scratch Register 2
+    case 0x15:                 // Scratch Register 3
+    case 0x16:                 // Performance Tuning Register
+    case 0x17:                 // Configuration Readback and Extended Control
+    case 0x18:                 // Signature Generator Control
+    case 0x19:                 // Signal Generator Result
+    case 0x1a:                 // Signal Generator Result
+    case 0x1b:                 // VCLK 0 Denominator & Post
+    case 0x1c:                 // VCLK 1 Denominator & Post
+    case 0x1d:                 // VCLK 2 Denominator & Post
+    case 0x1e:                 // VCLK 3 Denominator & Post
+    case 0x1f:                 // BIOS Write Enable and MCLK select
+#ifdef DEBUG_CIRRUS
+       printf("cirrus: handled inport sr_index %02x\n", s->vga.sr_index);
+#endif
+       return s->vga.sr[s->vga.sr_index];
+    default:
+#ifdef DEBUG_CIRRUS
+       printf("cirrus: inport sr_index %02x\n", s->vga.sr_index);
+#endif
+       return 0xff;
+       break;
+    }
+}
+
+static void cirrus_vga_write_sr(CirrusVGAState * s, uint32_t val)
+{
+    switch (s->vga.sr_index) {
+    case 0x00:                 // Standard VGA
+    case 0x01:                 // Standard VGA
+    case 0x02:                 // Standard VGA
+    case 0x03:                 // Standard VGA
+    case 0x04:                 // Standard VGA
+       s->vga.sr[s->vga.sr_index] = val & sr_mask[s->vga.sr_index];
+       if (s->vga.sr_index == 1)
+            s->vga.update_retrace_info(&s->vga);
+        break;
+    case 0x06:                 // Unlock Cirrus extensions
+       val &= 0x17;
+       if (val == 0x12) {
+           s->vga.sr[s->vga.sr_index] = 0x12;
+       } else {
+           s->vga.sr[s->vga.sr_index] = 0x0f;
+       }
+       break;
+    case 0x10:
+    case 0x30:
+    case 0x50:
+    case 0x70:                 // Graphics Cursor X
+    case 0x90:
+    case 0xb0:
+    case 0xd0:
+    case 0xf0:                 // Graphics Cursor X
+       s->vga.sr[0x10] = val;
+       s->hw_cursor_x = (val << 3) | (s->vga.sr_index >> 5);
+       break;
+    case 0x11:
+    case 0x31:
+    case 0x51:
+    case 0x71:                 // Graphics Cursor Y
+    case 0x91:
+    case 0xb1:
+    case 0xd1:
+    case 0xf1:                 // Graphics Cursor Y
+       s->vga.sr[0x11] = val;
+       s->hw_cursor_y = (val << 3) | (s->vga.sr_index >> 5);
+       break;
+    case 0x07:                 // Extended Sequencer Mode
+    cirrus_update_memory_access(s);
+    case 0x08:                 // EEPROM Control
+    case 0x09:                 // Scratch Register 0
+    case 0x0a:                 // Scratch Register 1
+    case 0x0b:                 // VCLK 0
+    case 0x0c:                 // VCLK 1
+    case 0x0d:                 // VCLK 2
+    case 0x0e:                 // VCLK 3
+    case 0x0f:                 // DRAM Control
+    case 0x12:                 // Graphics Cursor Attribute
+    case 0x13:                 // Graphics Cursor Pattern Address
+    case 0x14:                 // Scratch Register 2
+    case 0x15:                 // Scratch Register 3
+    case 0x16:                 // Performance Tuning Register
+    case 0x18:                 // Signature Generator Control
+    case 0x19:                 // Signature Generator Result
+    case 0x1a:                 // Signature Generator Result
+    case 0x1b:                 // VCLK 0 Denominator & Post
+    case 0x1c:                 // VCLK 1 Denominator & Post
+    case 0x1d:                 // VCLK 2 Denominator & Post
+    case 0x1e:                 // VCLK 3 Denominator & Post
+    case 0x1f:                 // BIOS Write Enable and MCLK select
+       s->vga.sr[s->vga.sr_index] = val;
+#ifdef DEBUG_CIRRUS
+       printf("cirrus: handled outport sr_index %02x, sr_value %02x\n",
+              s->vga.sr_index, val);
+#endif
+       break;
+    case 0x17:                 // Configuration Readback and Extended Control
+       s->vga.sr[s->vga.sr_index] = (s->vga.sr[s->vga.sr_index] & 0x38)
+                                   | (val & 0xc7);
+        cirrus_update_memory_access(s);
+        break;
+    default:
+#ifdef DEBUG_CIRRUS
+       printf("cirrus: outport sr_index %02x, sr_value %02x\n",
+               s->vga.sr_index, val);
+#endif
+       break;
+    }
+}
+
+/***************************************
+ *
+ *  I/O access at 0x3c6
+ *
+ ***************************************/
+
+static int cirrus_read_hidden_dac(CirrusVGAState * s)
+{
+    if (++s->cirrus_hidden_dac_lockindex == 5) {
+        s->cirrus_hidden_dac_lockindex = 0;
+        return s->cirrus_hidden_dac_data;
+    }
+    return 0xff;
+}
+
+static void cirrus_write_hidden_dac(CirrusVGAState * s, int reg_value)
+{
+    if (s->cirrus_hidden_dac_lockindex == 4) {
+       s->cirrus_hidden_dac_data = reg_value;
+#if defined(DEBUG_CIRRUS)
+       printf("cirrus: outport hidden DAC, value %02x\n", reg_value);
+#endif
+    }
+    s->cirrus_hidden_dac_lockindex = 0;
+}
+
+/***************************************
+ *
+ *  I/O access at 0x3c9
+ *
+ ***************************************/
+
+static int cirrus_vga_read_palette(CirrusVGAState * s)
+{
+    int val;
+
+    if ((s->vga.sr[0x12] & CIRRUS_CURSOR_HIDDENPEL)) {
+        val = s->cirrus_hidden_palette[(s->vga.dac_read_index & 0x0f) * 3 +
+                                       s->vga.dac_sub_index];
+    } else {
+        val = s->vga.palette[s->vga.dac_read_index * 3 + s->vga.dac_sub_index];
+    }
+    if (++s->vga.dac_sub_index == 3) {
+       s->vga.dac_sub_index = 0;
+       s->vga.dac_read_index++;
+    }
+    return val;
+}
+
+static void cirrus_vga_write_palette(CirrusVGAState * s, int reg_value)
+{
+    s->vga.dac_cache[s->vga.dac_sub_index] = reg_value;
+    if (++s->vga.dac_sub_index == 3) {
+        if ((s->vga.sr[0x12] & CIRRUS_CURSOR_HIDDENPEL)) {
+            memcpy(&s->cirrus_hidden_palette[(s->vga.dac_write_index & 0x0f) * 3],
+                   s->vga.dac_cache, 3);
+        } else {
+            memcpy(&s->vga.palette[s->vga.dac_write_index * 3], s->vga.dac_cache, 3);
+        }
+        /* XXX update cursor */
+       s->vga.dac_sub_index = 0;
+       s->vga.dac_write_index++;
+    }
+}
+
+/***************************************
+ *
+ *  I/O access between 0x3ce-0x3cf
+ *
+ ***************************************/
+
+static int cirrus_vga_read_gr(CirrusVGAState * s, unsigned reg_index)
+{
+    switch (reg_index) {
+    case 0x00: // Standard VGA, BGCOLOR 0x000000ff
+        return s->cirrus_shadow_gr0;
+    case 0x01: // Standard VGA, FGCOLOR 0x000000ff
+        return s->cirrus_shadow_gr1;
+    case 0x02:                 // Standard VGA
+    case 0x03:                 // Standard VGA
+    case 0x04:                 // Standard VGA
+    case 0x06:                 // Standard VGA
+    case 0x07:                 // Standard VGA
+    case 0x08:                 // Standard VGA
+        return s->vga.gr[s->vga.gr_index];
+    case 0x05:                 // Standard VGA, Cirrus extended mode
+    default:
+       break;
+    }
+
+    if (reg_index < 0x3a) {
+       return s->vga.gr[reg_index];
+    } else {
+#ifdef DEBUG_CIRRUS
+       printf("cirrus: inport gr_index %02x\n", reg_index);
+#endif
+       return 0xff;
+    }
+}
+
+static void
+cirrus_vga_write_gr(CirrusVGAState * s, unsigned reg_index, int reg_value)
+{
+#if defined(DEBUG_BITBLT) && 0
+    printf("gr%02x: %02x\n", reg_index, reg_value);
+#endif
+    switch (reg_index) {
+    case 0x00:                 // Standard VGA, BGCOLOR 0x000000ff
+       s->vga.gr[reg_index] = reg_value & gr_mask[reg_index];
+       s->cirrus_shadow_gr0 = reg_value;
+       break;
+    case 0x01:                 // Standard VGA, FGCOLOR 0x000000ff
+       s->vga.gr[reg_index] = reg_value & gr_mask[reg_index];
+       s->cirrus_shadow_gr1 = reg_value;
+       break;
+    case 0x02:                 // Standard VGA
+    case 0x03:                 // Standard VGA
+    case 0x04:                 // Standard VGA
+    case 0x06:                 // Standard VGA
+    case 0x07:                 // Standard VGA
+    case 0x08:                 // Standard VGA
+       s->vga.gr[reg_index] = reg_value & gr_mask[reg_index];
+        break;
+    case 0x05:                 // Standard VGA, Cirrus extended mode
+       s->vga.gr[reg_index] = reg_value & 0x7f;
+        cirrus_update_memory_access(s);
+       break;
+    case 0x09:                 // bank offset #0
+    case 0x0A:                 // bank offset #1
+       s->vga.gr[reg_index] = reg_value;
+       cirrus_update_bank_ptr(s, 0);
+       cirrus_update_bank_ptr(s, 1);
+        cirrus_update_memory_access(s);
+        break;
+    case 0x0B:
+       s->vga.gr[reg_index] = reg_value;
+       cirrus_update_bank_ptr(s, 0);
+       cirrus_update_bank_ptr(s, 1);
+        cirrus_update_memory_access(s);
+       break;
+    case 0x10:                 // BGCOLOR 0x0000ff00
+    case 0x11:                 // FGCOLOR 0x0000ff00
+    case 0x12:                 // BGCOLOR 0x00ff0000
+    case 0x13:                 // FGCOLOR 0x00ff0000
+    case 0x14:                 // BGCOLOR 0xff000000
+    case 0x15:                 // FGCOLOR 0xff000000
+    case 0x20:                 // BLT WIDTH 0x0000ff
+    case 0x22:                 // BLT HEIGHT 0x0000ff
+    case 0x24:                 // BLT DEST PITCH 0x0000ff
+    case 0x26:                 // BLT SRC PITCH 0x0000ff
+    case 0x28:                 // BLT DEST ADDR 0x0000ff
+    case 0x29:                 // BLT DEST ADDR 0x00ff00
+    case 0x2c:                 // BLT SRC ADDR 0x0000ff
+    case 0x2d:                 // BLT SRC ADDR 0x00ff00
+    case 0x2f:                  // BLT WRITEMASK
+    case 0x30:                 // BLT MODE
+    case 0x32:                 // RASTER OP
+    case 0x33:                 // BLT MODEEXT
+    case 0x34:                 // BLT TRANSPARENT COLOR 0x00ff
+    case 0x35:                 // BLT TRANSPARENT COLOR 0xff00
+    case 0x38:                 // BLT TRANSPARENT COLOR MASK 0x00ff
+    case 0x39:                 // BLT TRANSPARENT COLOR MASK 0xff00
+       s->vga.gr[reg_index] = reg_value;
+       break;
+    case 0x21:                 // BLT WIDTH 0x001f00
+    case 0x23:                 // BLT HEIGHT 0x001f00
+    case 0x25:                 // BLT DEST PITCH 0x001f00
+    case 0x27:                 // BLT SRC PITCH 0x001f00
+       s->vga.gr[reg_index] = reg_value & 0x1f;
+       break;
+    case 0x2a:                 // BLT DEST ADDR 0x3f0000
+       s->vga.gr[reg_index] = reg_value & 0x3f;
+        /* if auto start mode, starts bit blt now */
+        if (s->vga.gr[0x31] & CIRRUS_BLT_AUTOSTART) {
+            cirrus_bitblt_start(s);
+        }
+       break;
+    case 0x2e:                 // BLT SRC ADDR 0x3f0000
+       s->vga.gr[reg_index] = reg_value & 0x3f;
+       break;
+    case 0x31:                 // BLT STATUS/START
+       cirrus_write_bitblt(s, reg_value);
+       break;
+    default:
+#ifdef DEBUG_CIRRUS
+       printf("cirrus: outport gr_index %02x, gr_value %02x\n", reg_index,
+              reg_value);
+#endif
+       break;
+    }
+}
+
+/***************************************
+ *
+ *  I/O access between 0x3d4-0x3d5
+ *
+ ***************************************/
+
+static int cirrus_vga_read_cr(CirrusVGAState * s, unsigned reg_index)
+{
+    switch (reg_index) {
+    case 0x00:                 // Standard VGA
+    case 0x01:                 // Standard VGA
+    case 0x02:                 // Standard VGA
+    case 0x03:                 // Standard VGA
+    case 0x04:                 // Standard VGA
+    case 0x05:                 // Standard VGA
+    case 0x06:                 // Standard VGA
+    case 0x07:                 // Standard VGA
+    case 0x08:                 // Standard VGA
+    case 0x09:                 // Standard VGA
+    case 0x0a:                 // Standard VGA
+    case 0x0b:                 // Standard VGA
+    case 0x0c:                 // Standard VGA
+    case 0x0d:                 // Standard VGA
+    case 0x0e:                 // Standard VGA
+    case 0x0f:                 // Standard VGA
+    case 0x10:                 // Standard VGA
+    case 0x11:                 // Standard VGA
+    case 0x12:                 // Standard VGA
+    case 0x13:                 // Standard VGA
+    case 0x14:                 // Standard VGA
+    case 0x15:                 // Standard VGA
+    case 0x16:                 // Standard VGA
+    case 0x17:                 // Standard VGA
+    case 0x18:                 // Standard VGA
+       return s->vga.cr[s->vga.cr_index];
+    case 0x24:                 // Attribute Controller Toggle Readback (R)
+        return (s->vga.ar_flip_flop << 7);
+    case 0x19:                 // Interlace End
+    case 0x1a:                 // Miscellaneous Control
+    case 0x1b:                 // Extended Display Control
+    case 0x1c:                 // Sync Adjust and Genlock
+    case 0x1d:                 // Overlay Extended Control
+    case 0x22:                 // Graphics Data Latches Readback (R)
+    case 0x25:                 // Part Status
+    case 0x27:                 // Part ID (R)
+       return s->vga.cr[s->vga.cr_index];
+    case 0x26:                 // Attribute Controller Index Readback (R)
+       return s->vga.ar_index & 0x3f;
+       break;
+    default:
+#ifdef DEBUG_CIRRUS
+       printf("cirrus: inport cr_index %02x\n", reg_index);
+#endif
+       return 0xff;
+    }
+}
+
+static void cirrus_vga_write_cr(CirrusVGAState * s, int reg_value)
+{
+    switch (s->vga.cr_index) {
+    case 0x00:                 // Standard VGA
+    case 0x01:                 // Standard VGA
+    case 0x02:                 // Standard VGA
+    case 0x03:                 // Standard VGA
+    case 0x04:                 // Standard VGA
+    case 0x05:                 // Standard VGA
+    case 0x06:                 // Standard VGA
+    case 0x07:                 // Standard VGA
+    case 0x08:                 // Standard VGA
+    case 0x09:                 // Standard VGA
+    case 0x0a:                 // Standard VGA
+    case 0x0b:                 // Standard VGA
+    case 0x0c:                 // Standard VGA
+    case 0x0d:                 // Standard VGA
+    case 0x0e:                 // Standard VGA
+    case 0x0f:                 // Standard VGA
+    case 0x10:                 // Standard VGA
+    case 0x11:                 // Standard VGA
+    case 0x12:                 // Standard VGA
+    case 0x13:                 // Standard VGA
+    case 0x14:                 // Standard VGA
+    case 0x15:                 // Standard VGA
+    case 0x16:                 // Standard VGA
+    case 0x17:                 // Standard VGA
+    case 0x18:                 // Standard VGA
+       /* handle CR0-7 protection */
+       if ((s->vga.cr[0x11] & 0x80) && s->vga.cr_index <= 7) {
+           /* can always write bit 4 of CR7 */
+           if (s->vga.cr_index == 7)
+               s->vga.cr[7] = (s->vga.cr[7] & ~0x10) | (reg_value & 0x10);
+           return;
+       }
+       s->vga.cr[s->vga.cr_index] = reg_value;
+       switch(s->vga.cr_index) {
+       case 0x00:
+       case 0x04:
+       case 0x05:
+       case 0x06:
+       case 0x07:
+       case 0x11:
+       case 0x17:
+           s->vga.update_retrace_info(&s->vga);
+           break;
+       }
+        break;
+    case 0x19:                 // Interlace End
+    case 0x1a:                 // Miscellaneous Control
+    case 0x1b:                 // Extended Display Control
+    case 0x1c:                 // Sync Adjust and Genlock
+    case 0x1d:                 // Overlay Extended Control
+       s->vga.cr[s->vga.cr_index] = reg_value;
+#ifdef DEBUG_CIRRUS
+       printf("cirrus: handled outport cr_index %02x, cr_value %02x\n",
+              s->vga.cr_index, reg_value);
+#endif
+       break;
+    case 0x22:                 // Graphics Data Latches Readback (R)
+    case 0x24:                 // Attribute Controller Toggle Readback (R)
+    case 0x26:                 // Attribute Controller Index Readback (R)
+    case 0x27:                 // Part ID (R)
+       break;
+    case 0x25:                 // Part Status
+    default:
+#ifdef DEBUG_CIRRUS
+       printf("cirrus: outport cr_index %02x, cr_value %02x\n",
+               s->vga.cr_index, reg_value);
+#endif
+       break;
+    }
+}
+
+/***************************************
+ *
+ *  memory-mapped I/O (bitblt)
+ *
+ ***************************************/
+
+static uint8_t cirrus_mmio_blt_read(CirrusVGAState * s, unsigned address)
+{
+    int value = 0xff;
+
+    switch (address) {
+    case (CIRRUS_MMIO_BLTBGCOLOR + 0):
+       value = cirrus_vga_read_gr(s, 0x00);
+       break;
+    case (CIRRUS_MMIO_BLTBGCOLOR + 1):
+       value = cirrus_vga_read_gr(s, 0x10);
+       break;
+    case (CIRRUS_MMIO_BLTBGCOLOR + 2):
+       value = cirrus_vga_read_gr(s, 0x12);
+       break;
+    case (CIRRUS_MMIO_BLTBGCOLOR + 3):
+       value = cirrus_vga_read_gr(s, 0x14);
+       break;
+    case (CIRRUS_MMIO_BLTFGCOLOR + 0):
+       value = cirrus_vga_read_gr(s, 0x01);
+       break;
+    case (CIRRUS_MMIO_BLTFGCOLOR + 1):
+       value = cirrus_vga_read_gr(s, 0x11);
+       break;
+    case (CIRRUS_MMIO_BLTFGCOLOR + 2):
+       value = cirrus_vga_read_gr(s, 0x13);
+       break;
+    case (CIRRUS_MMIO_BLTFGCOLOR + 3):
+       value = cirrus_vga_read_gr(s, 0x15);
+       break;
+    case (CIRRUS_MMIO_BLTWIDTH + 0):
+       value = cirrus_vga_read_gr(s, 0x20);
+       break;
+    case (CIRRUS_MMIO_BLTWIDTH + 1):
+       value = cirrus_vga_read_gr(s, 0x21);
+       break;
+    case (CIRRUS_MMIO_BLTHEIGHT + 0):
+       value = cirrus_vga_read_gr(s, 0x22);
+       break;
+    case (CIRRUS_MMIO_BLTHEIGHT + 1):
+       value = cirrus_vga_read_gr(s, 0x23);
+       break;
+    case (CIRRUS_MMIO_BLTDESTPITCH + 0):
+       value = cirrus_vga_read_gr(s, 0x24);
+       break;
+    case (CIRRUS_MMIO_BLTDESTPITCH + 1):
+       value = cirrus_vga_read_gr(s, 0x25);
+       break;
+    case (CIRRUS_MMIO_BLTSRCPITCH + 0):
+       value = cirrus_vga_read_gr(s, 0x26);
+       break;
+    case (CIRRUS_MMIO_BLTSRCPITCH + 1):
+       value = cirrus_vga_read_gr(s, 0x27);
+       break;
+    case (CIRRUS_MMIO_BLTDESTADDR + 0):
+       value = cirrus_vga_read_gr(s, 0x28);
+       break;
+    case (CIRRUS_MMIO_BLTDESTADDR + 1):
+       value = cirrus_vga_read_gr(s, 0x29);
+       break;
+    case (CIRRUS_MMIO_BLTDESTADDR + 2):
+       value = cirrus_vga_read_gr(s, 0x2a);
+       break;
+    case (CIRRUS_MMIO_BLTSRCADDR + 0):
+       value = cirrus_vga_read_gr(s, 0x2c);
+       break;
+    case (CIRRUS_MMIO_BLTSRCADDR + 1):
+       value = cirrus_vga_read_gr(s, 0x2d);
+       break;
+    case (CIRRUS_MMIO_BLTSRCADDR + 2):
+       value = cirrus_vga_read_gr(s, 0x2e);
+       break;
+    case CIRRUS_MMIO_BLTWRITEMASK:
+       value = cirrus_vga_read_gr(s, 0x2f);
+       break;
+    case CIRRUS_MMIO_BLTMODE:
+       value = cirrus_vga_read_gr(s, 0x30);
+       break;
+    case CIRRUS_MMIO_BLTROP:
+       value = cirrus_vga_read_gr(s, 0x32);
+       break;
+    case CIRRUS_MMIO_BLTMODEEXT:
+       value = cirrus_vga_read_gr(s, 0x33);
+       break;
+    case (CIRRUS_MMIO_BLTTRANSPARENTCOLOR + 0):
+       value = cirrus_vga_read_gr(s, 0x34);
+       break;
+    case (CIRRUS_MMIO_BLTTRANSPARENTCOLOR + 1):
+       value = cirrus_vga_read_gr(s, 0x35);
+       break;
+    case (CIRRUS_MMIO_BLTTRANSPARENTCOLORMASK + 0):
+       value = cirrus_vga_read_gr(s, 0x38);
+       break;
+    case (CIRRUS_MMIO_BLTTRANSPARENTCOLORMASK + 1):
+       value = cirrus_vga_read_gr(s, 0x39);
+       break;
+    case CIRRUS_MMIO_BLTSTATUS:
+       value = cirrus_vga_read_gr(s, 0x31);
+       break;
+    default:
+#ifdef DEBUG_CIRRUS
+       printf("cirrus: mmio read - address 0x%04x\n", address);
+#endif
+       break;
+    }
+
+    return (uint8_t) value;
+}
+
+static void cirrus_mmio_blt_write(CirrusVGAState * s, unsigned address,
+                                 uint8_t value)
+{
+    switch (address) {
+    case (CIRRUS_MMIO_BLTBGCOLOR + 0):
+       cirrus_vga_write_gr(s, 0x00, value);
+       break;
+    case (CIRRUS_MMIO_BLTBGCOLOR + 1):
+       cirrus_vga_write_gr(s, 0x10, value);
+       break;
+    case (CIRRUS_MMIO_BLTBGCOLOR + 2):
+       cirrus_vga_write_gr(s, 0x12, value);
+       break;
+    case (CIRRUS_MMIO_BLTBGCOLOR + 3):
+       cirrus_vga_write_gr(s, 0x14, value);
+       break;
+    case (CIRRUS_MMIO_BLTFGCOLOR + 0):
+       cirrus_vga_write_gr(s, 0x01, value);
+       break;
+    case (CIRRUS_MMIO_BLTFGCOLOR + 1):
+       cirrus_vga_write_gr(s, 0x11, value);
+       break;
+    case (CIRRUS_MMIO_BLTFGCOLOR + 2):
+       cirrus_vga_write_gr(s, 0x13, value);
+       break;
+    case (CIRRUS_MMIO_BLTFGCOLOR + 3):
+       cirrus_vga_write_gr(s, 0x15, value);
+       break;
+    case (CIRRUS_MMIO_BLTWIDTH + 0):
+       cirrus_vga_write_gr(s, 0x20, value);
+       break;
+    case (CIRRUS_MMIO_BLTWIDTH + 1):
+       cirrus_vga_write_gr(s, 0x21, value);
+       break;
+    case (CIRRUS_MMIO_BLTHEIGHT + 0):
+       cirrus_vga_write_gr(s, 0x22, value);
+       break;
+    case (CIRRUS_MMIO_BLTHEIGHT + 1):
+       cirrus_vga_write_gr(s, 0x23, value);
+       break;
+    case (CIRRUS_MMIO_BLTDESTPITCH + 0):
+       cirrus_vga_write_gr(s, 0x24, value);
+       break;
+    case (CIRRUS_MMIO_BLTDESTPITCH + 1):
+       cirrus_vga_write_gr(s, 0x25, value);
+       break;
+    case (CIRRUS_MMIO_BLTSRCPITCH + 0):
+       cirrus_vga_write_gr(s, 0x26, value);
+       break;
+    case (CIRRUS_MMIO_BLTSRCPITCH + 1):
+       cirrus_vga_write_gr(s, 0x27, value);
+       break;
+    case (CIRRUS_MMIO_BLTDESTADDR + 0):
+       cirrus_vga_write_gr(s, 0x28, value);
+       break;
+    case (CIRRUS_MMIO_BLTDESTADDR + 1):
+       cirrus_vga_write_gr(s, 0x29, value);
+       break;
+    case (CIRRUS_MMIO_BLTDESTADDR + 2):
+       cirrus_vga_write_gr(s, 0x2a, value);
+       break;
+    case (CIRRUS_MMIO_BLTDESTADDR + 3):
+       /* ignored */
+       break;
+    case (CIRRUS_MMIO_BLTSRCADDR + 0):
+       cirrus_vga_write_gr(s, 0x2c, value);
+       break;
+    case (CIRRUS_MMIO_BLTSRCADDR + 1):
+       cirrus_vga_write_gr(s, 0x2d, value);
+       break;
+    case (CIRRUS_MMIO_BLTSRCADDR + 2):
+       cirrus_vga_write_gr(s, 0x2e, value);
+       break;
+    case CIRRUS_MMIO_BLTWRITEMASK:
+       cirrus_vga_write_gr(s, 0x2f, value);
+       break;
+    case CIRRUS_MMIO_BLTMODE:
+       cirrus_vga_write_gr(s, 0x30, value);
+       break;
+    case CIRRUS_MMIO_BLTROP:
+       cirrus_vga_write_gr(s, 0x32, value);
+       break;
+    case CIRRUS_MMIO_BLTMODEEXT:
+       cirrus_vga_write_gr(s, 0x33, value);
+       break;
+    case (CIRRUS_MMIO_BLTTRANSPARENTCOLOR + 0):
+       cirrus_vga_write_gr(s, 0x34, value);
+       break;
+    case (CIRRUS_MMIO_BLTTRANSPARENTCOLOR + 1):
+       cirrus_vga_write_gr(s, 0x35, value);
+       break;
+    case (CIRRUS_MMIO_BLTTRANSPARENTCOLORMASK + 0):
+       cirrus_vga_write_gr(s, 0x38, value);
+       break;
+    case (CIRRUS_MMIO_BLTTRANSPARENTCOLORMASK + 1):
+       cirrus_vga_write_gr(s, 0x39, value);
+       break;
+    case CIRRUS_MMIO_BLTSTATUS:
+       cirrus_vga_write_gr(s, 0x31, value);
+       break;
+    default:
+#ifdef DEBUG_CIRRUS
+       printf("cirrus: mmio write - addr 0x%04x val 0x%02x (ignored)\n",
+              address, value);
+#endif
+       break;
+    }
+}
+
+/***************************************
+ *
+ *  write mode 4/5
+ *
+ ***************************************/
+
+static void cirrus_mem_writeb_mode4and5_8bpp(CirrusVGAState * s,
+                                            unsigned mode,
+                                            unsigned offset,
+                                            uint32_t mem_value)
+{
+    int x;
+    unsigned val = mem_value;
+    uint8_t *dst;
+
+    dst = s->vga.vram_ptr + (offset &= s->cirrus_addr_mask);
+    for (x = 0; x < 8; x++) {
+       if (val & 0x80) {
+           *dst = s->cirrus_shadow_gr1;
+       } else if (mode == 5) {
+           *dst = s->cirrus_shadow_gr0;
+       }
+       val <<= 1;
+       dst++;
+    }
+    memory_region_set_dirty(&s->vga.vram, offset, 8);
+}
+
+static void cirrus_mem_writeb_mode4and5_16bpp(CirrusVGAState * s,
+                                             unsigned mode,
+                                             unsigned offset,
+                                             uint32_t mem_value)
+{
+    int x;
+    unsigned val = mem_value;
+    uint8_t *dst;
+
+    dst = s->vga.vram_ptr + (offset &= s->cirrus_addr_mask);
+    for (x = 0; x < 8; x++) {
+       if (val & 0x80) {
+           *dst = s->cirrus_shadow_gr1;
+           *(dst + 1) = s->vga.gr[0x11];
+       } else if (mode == 5) {
+           *dst = s->cirrus_shadow_gr0;
+           *(dst + 1) = s->vga.gr[0x10];
+       }
+       val <<= 1;
+       dst += 2;
+    }
+    memory_region_set_dirty(&s->vga.vram, offset, 16);
+}
+
+/***************************************
+ *
+ *  memory access between 0xa0000-0xbffff
+ *
+ ***************************************/
+
+static uint64_t cirrus_vga_mem_read(void *opaque,
+                                    hwaddr addr,
+                                    uint32_t size)
+{
+    CirrusVGAState *s = opaque;
+    unsigned bank_index;
+    unsigned bank_offset;
+    uint32_t val;
+
+    if ((s->vga.sr[0x07] & 0x01) == 0) {
+        return vga_mem_readb(&s->vga, addr);
+    }
+
+    if (addr < 0x10000) {
+       /* XXX handle bitblt */
+       /* video memory */
+       bank_index = addr >> 15;
+       bank_offset = addr & 0x7fff;
+       if (bank_offset < s->cirrus_bank_limit[bank_index]) {
+           bank_offset += s->cirrus_bank_base[bank_index];
+           if ((s->vga.gr[0x0B] & 0x14) == 0x14) {
+               bank_offset <<= 4;
+           } else if (s->vga.gr[0x0B] & 0x02) {
+               bank_offset <<= 3;
+           }
+           bank_offset &= s->cirrus_addr_mask;
+           val = *(s->vga.vram_ptr + bank_offset);
+       } else
+           val = 0xff;
+    } else if (addr >= 0x18000 && addr < 0x18100) {
+       /* memory-mapped I/O */
+       val = 0xff;
+       if ((s->vga.sr[0x17] & 0x44) == 0x04) {
+           val = cirrus_mmio_blt_read(s, addr & 0xff);
+       }
+    } else {
+       val = 0xff;
+#ifdef DEBUG_CIRRUS
+       printf("cirrus: mem_readb " TARGET_FMT_plx "\n", addr);
+#endif
+    }
+    return val;
+}
+
+static void cirrus_vga_mem_write(void *opaque,
+                                 hwaddr addr,
+                                 uint64_t mem_value,
+                                 uint32_t size)
+{
+    CirrusVGAState *s = opaque;
+    unsigned bank_index;
+    unsigned bank_offset;
+    unsigned mode;
+
+    if ((s->vga.sr[0x07] & 0x01) == 0) {
+        vga_mem_writeb(&s->vga, addr, mem_value);
+        return;
+    }
+
+    if (addr < 0x10000) {
+       if (s->cirrus_srcptr != s->cirrus_srcptr_end) {
+           /* bitblt */
+           *s->cirrus_srcptr++ = (uint8_t) mem_value;
+           if (s->cirrus_srcptr >= s->cirrus_srcptr_end) {
+               cirrus_bitblt_cputovideo_next(s);
+           }
+       } else {
+           /* video memory */
+           bank_index = addr >> 15;
+           bank_offset = addr & 0x7fff;
+           if (bank_offset < s->cirrus_bank_limit[bank_index]) {
+               bank_offset += s->cirrus_bank_base[bank_index];
+               if ((s->vga.gr[0x0B] & 0x14) == 0x14) {
+                   bank_offset <<= 4;
+               } else if (s->vga.gr[0x0B] & 0x02) {
+                   bank_offset <<= 3;
+               }
+               bank_offset &= s->cirrus_addr_mask;
+               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,
+                                            sizeof(mem_value));
+               } else {
+                   if ((s->vga.gr[0x0B] & 0x14) != 0x14) {
+                       cirrus_mem_writeb_mode4and5_8bpp(s, mode,
+                                                        bank_offset,
+                                                        mem_value);
+                   } else {
+                       cirrus_mem_writeb_mode4and5_16bpp(s, mode,
+                                                         bank_offset,
+                                                         mem_value);
+                   }
+               }
+           }
+       }
+    } else if (addr >= 0x18000 && addr < 0x18100) {
+       /* memory-mapped I/O */
+       if ((s->vga.sr[0x17] & 0x44) == 0x04) {
+           cirrus_mmio_blt_write(s, addr & 0xff, mem_value);
+       }
+    } else {
+#ifdef DEBUG_CIRRUS
+        printf("cirrus: mem_writeb " TARGET_FMT_plx " value %02x\n", addr,
+               mem_value);
+#endif
+    }
+}
+
+static const MemoryRegionOps cirrus_vga_mem_ops = {
+    .read = cirrus_vga_mem_read,
+    .write = cirrus_vga_mem_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+};
+
+/***************************************
+ *
+ *  hardware cursor
+ *
+ ***************************************/
+
+static inline void invalidate_cursor1(CirrusVGAState *s)
+{
+    if (s->last_hw_cursor_size) {
+        vga_invalidate_scanlines(&s->vga,
+                                 s->last_hw_cursor_y + s->last_hw_cursor_y_start,
+                                 s->last_hw_cursor_y + s->last_hw_cursor_y_end);
+    }
+}
+
+static inline void cirrus_cursor_compute_yrange(CirrusVGAState *s)
+{
+    const uint8_t *src;
+    uint32_t content;
+    int y, y_min, y_max;
+
+    src = s->vga.vram_ptr + s->real_vram_size - 16 * 1024;
+    if (s->vga.sr[0x12] & CIRRUS_CURSOR_LARGE) {
+        src += (s->vga.sr[0x13] & 0x3c) * 256;
+        y_min = 64;
+        y_max = -1;
+        for(y = 0; y < 64; y++) {
+            content = ((uint32_t *)src)[0] |
+                ((uint32_t *)src)[1] |
+                ((uint32_t *)src)[2] |
+                ((uint32_t *)src)[3];
+            if (content) {
+                if (y < y_min)
+                    y_min = y;
+                if (y > y_max)
+                    y_max = y;
+            }
+            src += 16;
+        }
+    } else {
+        src += (s->vga.sr[0x13] & 0x3f) * 256;
+        y_min = 32;
+        y_max = -1;
+        for(y = 0; y < 32; y++) {
+            content = ((uint32_t *)src)[0] |
+                ((uint32_t *)(src + 128))[0];
+            if (content) {
+                if (y < y_min)
+                    y_min = y;
+                if (y > y_max)
+                    y_max = y;
+            }
+            src += 4;
+        }
+    }
+    if (y_min > y_max) {
+        s->last_hw_cursor_y_start = 0;
+        s->last_hw_cursor_y_end = 0;
+    } else {
+        s->last_hw_cursor_y_start = y_min;
+        s->last_hw_cursor_y_end = y_max + 1;
+    }
+}
+
+/* NOTE: we do not currently handle the cursor bitmap change, so we
+   update the cursor only if it moves. */
+static void cirrus_cursor_invalidate(VGACommonState *s1)
+{
+    CirrusVGAState *s = container_of(s1, CirrusVGAState, vga);
+    int size;
+
+    if (!(s->vga.sr[0x12] & CIRRUS_CURSOR_SHOW)) {
+        size = 0;
+    } else {
+        if (s->vga.sr[0x12] & CIRRUS_CURSOR_LARGE)
+            size = 64;
+        else
+            size = 32;
+    }
+    /* invalidate last cursor and new cursor if any change */
+    if (s->last_hw_cursor_size != size ||
+        s->last_hw_cursor_x != s->hw_cursor_x ||
+        s->last_hw_cursor_y != s->hw_cursor_y) {
+
+        invalidate_cursor1(s);
+
+        s->last_hw_cursor_size = size;
+        s->last_hw_cursor_x = s->hw_cursor_x;
+        s->last_hw_cursor_y = s->hw_cursor_y;
+        /* compute the real cursor min and max y */
+        cirrus_cursor_compute_yrange(s);
+        invalidate_cursor1(s);
+    }
+}
+
+#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);
+    DisplaySurface *surface = qemu_console_surface(s->vga.con);
+    int w, h, bpp, x1, x2, poffset;
+    unsigned int color0, color1;
+    const uint8_t *palette, *src;
+    uint32_t content;
+
+    if (!(s->vga.sr[0x12] & CIRRUS_CURSOR_SHOW))
+        return;
+    /* fast test to see if the cursor intersects with the scan line */
+    if (s->vga.sr[0x12] & CIRRUS_CURSOR_LARGE) {
+        h = 64;
+    } else {
+        h = 32;
+    }
+    if (scr_y < s->hw_cursor_y ||
+        scr_y >= (s->hw_cursor_y + h))
+        return;
+
+    src = s->vga.vram_ptr + s->real_vram_size - 16 * 1024;
+    if (s->vga.sr[0x12] & CIRRUS_CURSOR_LARGE) {
+        src += (s->vga.sr[0x13] & 0x3c) * 256;
+        src += (scr_y - s->hw_cursor_y) * 16;
+        poffset = 8;
+        content = ((uint32_t *)src)[0] |
+            ((uint32_t *)src)[1] |
+            ((uint32_t *)src)[2] |
+            ((uint32_t *)src)[3];
+    } else {
+        src += (s->vga.sr[0x13] & 0x3f) * 256;
+        src += (scr_y - s->hw_cursor_y) * 4;
+        poffset = 128;
+        content = ((uint32_t *)src)[0] |
+            ((uint32_t *)(src + 128))[0];
+    }
+    /* if nothing to draw, no need to continue */
+    if (!content)
+        return;
+    w = h;
+
+    x1 = s->hw_cursor_x;
+    if (x1 >= s->vga.last_scr_width)
+        return;
+    x2 = s->hw_cursor_x + w;
+    if (x2 > s->vga.last_scr_width)
+        x2 = s->vga.last_scr_width;
+    w = x2 - x1;
+    palette = s->cirrus_hidden_palette;
+    color0 = s->vga.rgb_to_pixel(c6_to_8(palette[0x0 * 3]),
+                                 c6_to_8(palette[0x0 * 3 + 1]),
+                                 c6_to_8(palette[0x0 * 3 + 2]));
+    color1 = s->vga.rgb_to_pixel(c6_to_8(palette[0xf * 3]),
+                                 c6_to_8(palette[0xf * 3 + 1]),
+                                 c6_to_8(palette[0xf * 3 + 2]));
+    bpp = surface_bytes_per_pixel(surface);
+    d1 += x1 * bpp;
+    switch (surface_bits_per_pixel(surface)) {
+    default:
+        break;
+    case 8:
+        vga_draw_cursor_line_8(d1, src, poffset, w, color0, color1, 0xff);
+        break;
+    case 15:
+        vga_draw_cursor_line_16(d1, src, poffset, w, color0, color1, 0x7fff);
+        break;
+    case 16:
+        vga_draw_cursor_line_16(d1, src, poffset, w, color0, color1, 0xffff);
+        break;
+    case 32:
+        vga_draw_cursor_line_32(d1, src, poffset, w, color0, color1, 0xffffff);
+        break;
+    }
+}
+
+/***************************************
+ *
+ *  LFB memory access
+ *
+ ***************************************/
+
+static uint64_t cirrus_linear_read(void *opaque, hwaddr addr,
+                                   unsigned size)
+{
+    CirrusVGAState *s = opaque;
+    uint32_t ret;
+
+    addr &= s->cirrus_addr_mask;
+
+    if (((s->vga.sr[0x17] & 0x44) == 0x44) &&
+        ((addr & s->linear_mmio_mask) == s->linear_mmio_mask)) {
+       /* memory-mapped I/O */
+       ret = cirrus_mmio_blt_read(s, addr & 0xff);
+    } else if (0) {
+       /* XXX handle bitblt */
+       ret = 0xff;
+    } else {
+       /* video memory */
+       if ((s->vga.gr[0x0B] & 0x14) == 0x14) {
+           addr <<= 4;
+       } else if (s->vga.gr[0x0B] & 0x02) {
+           addr <<= 3;
+       }
+       addr &= s->cirrus_addr_mask;
+       ret = *(s->vga.vram_ptr + addr);
+    }
+
+    return ret;
+}
+
+static void cirrus_linear_write(void *opaque, hwaddr addr,
+                                uint64_t val, unsigned size)
+{
+    CirrusVGAState *s = opaque;
+    unsigned mode;
+
+    addr &= s->cirrus_addr_mask;
+
+    if (((s->vga.sr[0x17] & 0x44) == 0x44) &&
+        ((addr & s->linear_mmio_mask) ==  s->linear_mmio_mask)) {
+       /* memory-mapped I/O */
+       cirrus_mmio_blt_write(s, addr & 0xff, val);
+    } else if (s->cirrus_srcptr != s->cirrus_srcptr_end) {
+       /* bitblt */
+       *s->cirrus_srcptr++ = (uint8_t) val;
+       if (s->cirrus_srcptr >= s->cirrus_srcptr_end) {
+           cirrus_bitblt_cputovideo_next(s);
+       }
+    } else {
+       /* video memory */
+       if ((s->vga.gr[0x0B] & 0x14) == 0x14) {
+           addr <<= 4;
+       } else if (s->vga.gr[0x0B] & 0x02) {
+           addr <<= 3;
+       }
+       addr &= s->cirrus_addr_mask;
+
+       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, 1);
+       } else {
+           if ((s->vga.gr[0x0B] & 0x14) != 0x14) {
+               cirrus_mem_writeb_mode4and5_8bpp(s, mode, addr, val);
+           } else {
+               cirrus_mem_writeb_mode4and5_16bpp(s, mode, addr, val);
+           }
+       }
+    }
+}
+
+/***************************************
+ *
+ *  system to screen memory access
+ *
+ ***************************************/
+
+
+static uint64_t cirrus_linear_bitblt_read(void *opaque,
+                                          hwaddr addr,
+                                          unsigned size)
+{
+    CirrusVGAState *s = opaque;
+    uint32_t ret;
+
+    /* XXX handle bitblt */
+    (void)s;
+    ret = 0xff;
+    return ret;
+}
+
+static void cirrus_linear_bitblt_write(void *opaque,
+                                       hwaddr addr,
+                                       uint64_t val,
+                                       unsigned size)
+{
+    CirrusVGAState *s = opaque;
+
+    if (s->cirrus_srcptr != s->cirrus_srcptr_end) {
+       /* bitblt */
+       *s->cirrus_srcptr++ = (uint8_t) val;
+       if (s->cirrus_srcptr >= s->cirrus_srcptr_end) {
+           cirrus_bitblt_cputovideo_next(s);
+       }
+    }
+}
+
+static const MemoryRegionOps cirrus_linear_bitblt_io_ops = {
+    .read = cirrus_linear_bitblt_read,
+    .write = cirrus_linear_bitblt_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+};
+
+static void map_linear_vram_bank(CirrusVGAState *s, unsigned bank)
+{
+    MemoryRegion *mr = &s->cirrus_bank[bank];
+    bool enabled = !(s->cirrus_srcptr != s->cirrus_srcptr_end)
+        && !((s->vga.sr[0x07] & 0x01) == 0)
+        && !((s->vga.gr[0x0B] & 0x14) == 0x14)
+        && !(s->vga.gr[0x0B] & 0x02);
+
+    memory_region_set_enabled(mr, enabled);
+    memory_region_set_alias_offset(mr, s->cirrus_bank_base[bank]);
+}
+
+static void map_linear_vram(CirrusVGAState *s)
+{
+    if (s->bustype == CIRRUS_BUSTYPE_PCI && !s->linear_vram) {
+        s->linear_vram = true;
+        memory_region_add_subregion_overlap(&s->pci_bar, 0, &s->vga.vram, 1);
+    }
+    map_linear_vram_bank(s, 0);
+    map_linear_vram_bank(s, 1);
+}
+
+static void unmap_linear_vram(CirrusVGAState *s)
+{
+    if (s->bustype == CIRRUS_BUSTYPE_PCI && s->linear_vram) {
+        s->linear_vram = false;
+        memory_region_del_subregion(&s->pci_bar, &s->vga.vram);
+    }
+    memory_region_set_enabled(&s->cirrus_bank[0], false);
+    memory_region_set_enabled(&s->cirrus_bank[1], false);
+}
+
+/* Compute the memory access functions */
+static void cirrus_update_memory_access(CirrusVGAState *s)
+{
+    unsigned mode;
+
+    memory_region_transaction_begin();
+    if ((s->vga.sr[0x17] & 0x44) == 0x44) {
+        goto generic_io;
+    } else if (s->cirrus_srcptr != s->cirrus_srcptr_end) {
+        goto generic_io;
+    } else {
+       if ((s->vga.gr[0x0B] & 0x14) == 0x14) {
+            goto generic_io;
+       } else if (s->vga.gr[0x0B] & 0x02) {
+            goto generic_io;
+        }
+
+       mode = s->vga.gr[0x05] & 0x7;
+       if (mode < 4 || mode > 5 || ((s->vga.gr[0x0B] & 0x4) == 0)) {
+            map_linear_vram(s);
+        } else {
+        generic_io:
+            unmap_linear_vram(s);
+        }
+    }
+    memory_region_transaction_commit();
+}
+
+
+/* I/O ports */
+
+static uint64_t cirrus_vga_ioport_read(void *opaque, hwaddr addr,
+                                       unsigned size)
+{
+    CirrusVGAState *c = opaque;
+    VGACommonState *s = &c->vga;
+    int val, index;
+
+    qemu_flush_coalesced_mmio_buffer();
+    addr += 0x3b0;
+
+    if (vga_ioport_invalid(s, addr)) {
+       val = 0xff;
+    } else {
+       switch (addr) {
+       case 0x3c0:
+           if (s->ar_flip_flop == 0) {
+               val = s->ar_index;
+           } else {
+               val = 0;
+           }
+           break;
+       case 0x3c1:
+           index = s->ar_index & 0x1f;
+           if (index < 21)
+               val = s->ar[index];
+           else
+               val = 0;
+           break;
+       case 0x3c2:
+           val = s->st00;
+           break;
+       case 0x3c4:
+           val = s->sr_index;
+           break;
+       case 0x3c5:
+           val = cirrus_vga_read_sr(c);
+            break;
+#ifdef DEBUG_VGA_REG
+           printf("vga: read SR%x = 0x%02x\n", s->sr_index, val);
+#endif
+           break;
+       case 0x3c6:
+           val = cirrus_read_hidden_dac(c);
+           break;
+       case 0x3c7:
+           val = s->dac_state;
+           break;
+       case 0x3c8:
+           val = s->dac_write_index;
+           c->cirrus_hidden_dac_lockindex = 0;
+           break;
+        case 0x3c9:
+            val = cirrus_vga_read_palette(c);
+            break;
+       case 0x3ca:
+           val = s->fcr;
+           break;
+       case 0x3cc:
+           val = s->msr;
+           break;
+       case 0x3ce:
+           val = s->gr_index;
+           break;
+       case 0x3cf:
+           val = cirrus_vga_read_gr(c, 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:
+           val = s->cr_index;
+           break;
+       case 0x3b5:
+       case 0x3d5:
+            val = cirrus_vga_read_cr(c, 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:
+           /* just toggle to fool polling */
+           val = s->st01 = s->retrace(s);
+           s->ar_flip_flop = 0;
+           break;
+       default:
+           val = 0x00;
+           break;
+       }
+    }
+#if defined(DEBUG_VGA)
+    printf("VGA: read addr=0x%04x data=0x%02x\n", addr, val);
+#endif
+    return val;
+}
+
+static void cirrus_vga_ioport_write(void *opaque, hwaddr addr, uint64_t val,
+                                    unsigned size)
+{
+    CirrusVGAState *c = opaque;
+    VGACommonState *s = &c->vga;
+    int index;
+
+    qemu_flush_coalesced_mmio_buffer();
+    addr += 0x3b0;
+
+    /* check port range access depending on color/monochrome mode */
+    if (vga_ioport_invalid(s, addr)) {
+       return;
+    }
+#ifdef DEBUG_VGA
+    printf("VGA: write addr=0x%04x data=0x%02x\n", addr, val);
+#endif
+
+    switch (addr) {
+    case 0x3c0:
+       if (s->ar_flip_flop == 0) {
+           val &= 0x3f;
+           s->ar_index = val;
+       } else {
+           index = s->ar_index & 0x1f;
+           switch (index) {
+           case 0x00 ... 0x0f:
+               s->ar[index] = val & 0x3f;
+               break;
+           case 0x10:
+               s->ar[index] = val & ~0x10;
+               break;
+           case 0x11:
+               s->ar[index] = val;
+               break;
+           case 0x12:
+               s->ar[index] = val & ~0xc0;
+               break;
+           case 0x13:
+               s->ar[index] = val & ~0xf0;
+               break;
+           case 0x14:
+               s->ar[index] = val & ~0xf0;
+               break;
+           default:
+               break;
+           }
+       }
+       s->ar_flip_flop ^= 1;
+       break;
+    case 0x3c2:
+       s->msr = val & ~0x10;
+       s->update_retrace_info(s);
+       break;
+    case 0x3c4:
+       s->sr_index = val;
+       break;
+    case 0x3c5:
+#ifdef DEBUG_VGA_REG
+       printf("vga: write SR%x = 0x%02x\n", s->sr_index, val);
+#endif
+       cirrus_vga_write_sr(c, val);
+        break;
+       break;
+    case 0x3c6:
+       cirrus_write_hidden_dac(c, val);
+       break;
+    case 0x3c7:
+       s->dac_read_index = val;
+       s->dac_sub_index = 0;
+       s->dac_state = 3;
+       break;
+    case 0x3c8:
+       s->dac_write_index = val;
+       s->dac_sub_index = 0;
+       s->dac_state = 0;
+       break;
+    case 0x3c9:
+        cirrus_vga_write_palette(c, val);
+        break;
+    case 0x3ce:
+       s->gr_index = val;
+       break;
+    case 0x3cf:
+#ifdef DEBUG_VGA_REG
+       printf("vga: write GR%x = 0x%02x\n", s->gr_index, val);
+#endif
+       cirrus_vga_write_gr(c, s->gr_index, val);
+       break;
+    case 0x3b4:
+    case 0x3d4:
+       s->cr_index = val;
+       break;
+    case 0x3b5:
+    case 0x3d5:
+#ifdef DEBUG_VGA_REG
+       printf("vga: write CR%x = 0x%02x\n", s->cr_index, val);
+#endif
+       cirrus_vga_write_cr(c, val);
+       break;
+    case 0x3ba:
+    case 0x3da:
+       s->fcr = val & 0x10;
+       break;
+    }
+}
+
+/***************************************
+ *
+ *  memory-mapped I/O access
+ *
+ ***************************************/
+
+static uint64_t cirrus_mmio_read(void *opaque, hwaddr addr,
+                                 unsigned size)
+{
+    CirrusVGAState *s = opaque;
+
+    if (addr >= 0x100) {
+        return cirrus_mmio_blt_read(s, addr - 0x100);
+    } else {
+        return cirrus_vga_ioport_read(s, addr + 0x10, size);
+    }
+}
+
+static void cirrus_mmio_write(void *opaque, hwaddr addr,
+                              uint64_t val, unsigned size)
+{
+    CirrusVGAState *s = opaque;
+
+    if (addr >= 0x100) {
+       cirrus_mmio_blt_write(s, addr - 0x100, val);
+    } else {
+        cirrus_vga_ioport_write(s, addr + 0x10, val, size);
+    }
+}
+
+static const MemoryRegionOps cirrus_mmio_io_ops = {
+    .read = cirrus_mmio_read,
+    .write = cirrus_mmio_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+};
+
+/* load/save state */
+
+static int cirrus_post_load(void *opaque, int version_id)
+{
+    CirrusVGAState *s = opaque;
+
+    s->vga.gr[0x00] = s->cirrus_shadow_gr0 & 0x0f;
+    s->vga.gr[0x01] = s->cirrus_shadow_gr1 & 0x0f;
+
+    cirrus_update_memory_access(s);
+    /* force refresh */
+    s->vga.graphic_mode = -1;
+    cirrus_update_bank_ptr(s, 0);
+    cirrus_update_bank_ptr(s, 1);
+    return 0;
+}
+
+static const VMStateDescription vmstate_cirrus_vga = {
+    .name = "cirrus_vga",
+    .version_id = 2,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .post_load = cirrus_post_load,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT32(vga.latch, CirrusVGAState),
+        VMSTATE_UINT8(vga.sr_index, CirrusVGAState),
+        VMSTATE_BUFFER(vga.sr, CirrusVGAState),
+        VMSTATE_UINT8(vga.gr_index, CirrusVGAState),
+        VMSTATE_UINT8(cirrus_shadow_gr0, CirrusVGAState),
+        VMSTATE_UINT8(cirrus_shadow_gr1, CirrusVGAState),
+        VMSTATE_BUFFER_START_MIDDLE(vga.gr, CirrusVGAState, 2),
+        VMSTATE_UINT8(vga.ar_index, CirrusVGAState),
+        VMSTATE_BUFFER(vga.ar, CirrusVGAState),
+        VMSTATE_INT32(vga.ar_flip_flop, CirrusVGAState),
+        VMSTATE_UINT8(vga.cr_index, CirrusVGAState),
+        VMSTATE_BUFFER(vga.cr, CirrusVGAState),
+        VMSTATE_UINT8(vga.msr, CirrusVGAState),
+        VMSTATE_UINT8(vga.fcr, CirrusVGAState),
+        VMSTATE_UINT8(vga.st00, CirrusVGAState),
+        VMSTATE_UINT8(vga.st01, CirrusVGAState),
+        VMSTATE_UINT8(vga.dac_state, CirrusVGAState),
+        VMSTATE_UINT8(vga.dac_sub_index, CirrusVGAState),
+        VMSTATE_UINT8(vga.dac_read_index, CirrusVGAState),
+        VMSTATE_UINT8(vga.dac_write_index, CirrusVGAState),
+        VMSTATE_BUFFER(vga.dac_cache, CirrusVGAState),
+        VMSTATE_BUFFER(vga.palette, CirrusVGAState),
+        VMSTATE_INT32(vga.bank_offset, CirrusVGAState),
+        VMSTATE_UINT8(cirrus_hidden_dac_lockindex, CirrusVGAState),
+        VMSTATE_UINT8(cirrus_hidden_dac_data, CirrusVGAState),
+        VMSTATE_UINT32(hw_cursor_x, CirrusVGAState),
+        VMSTATE_UINT32(hw_cursor_y, CirrusVGAState),
+        /* XXX: we do not save the bitblt state - we assume we do not save
+           the state when the blitter is active */
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_pci_cirrus_vga = {
+    .name = "cirrus_vga",
+    .version_id = 2,
+    .minimum_version_id = 2,
+    .minimum_version_id_old = 2,
+    .fields      = (VMStateField []) {
+        VMSTATE_PCI_DEVICE(dev, PCICirrusVGAState),
+        VMSTATE_STRUCT(cirrus_vga, PCICirrusVGAState, 0,
+                       vmstate_cirrus_vga, CirrusVGAState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+/***************************************
+ *
+ *  initialize
+ *
+ ***************************************/
+
+static void cirrus_reset(void *opaque)
+{
+    CirrusVGAState *s = opaque;
+
+    vga_common_reset(&s->vga);
+    unmap_linear_vram(s);
+    s->vga.sr[0x06] = 0x0f;
+    if (s->device_id == CIRRUS_ID_CLGD5446) {
+        /* 4MB 64 bit memory config, always PCI */
+        s->vga.sr[0x1F] = 0x2d;                // MemClock
+        s->vga.gr[0x18] = 0x0f;             // fastest memory configuration
+        s->vga.sr[0x0f] = 0x98;
+        s->vga.sr[0x17] = 0x20;
+        s->vga.sr[0x15] = 0x04; /* memory size, 3=2MB, 4=4MB */
+    } else {
+        s->vga.sr[0x1F] = 0x22;                // MemClock
+        s->vga.sr[0x0F] = CIRRUS_MEMSIZE_2M;
+        s->vga.sr[0x17] = s->bustype;
+        s->vga.sr[0x15] = 0x03; /* memory size, 3=2MB, 4=4MB */
+    }
+    s->vga.cr[0x27] = s->device_id;
+
+    s->cirrus_hidden_dac_lockindex = 5;
+    s->cirrus_hidden_dac_data = 0;
+}
+
+static const MemoryRegionOps cirrus_linear_io_ops = {
+    .read = cirrus_linear_read,
+    .write = cirrus_linear_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+};
+
+static const MemoryRegionOps cirrus_vga_io_ops = {
+    .read = cirrus_vga_ioport_read,
+    .write = cirrus_vga_ioport_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+};
+
+static void cirrus_init_common(CirrusVGAState * s, int device_id, int is_pci,
+                               MemoryRegion *system_memory,
+                               MemoryRegion *system_io)
+{
+    int i;
+    static int inited;
+
+    if (!inited) {
+        inited = 1;
+        for(i = 0;i < 256; i++)
+            rop_to_index[i] = CIRRUS_ROP_NOP_INDEX; /* nop rop */
+        rop_to_index[CIRRUS_ROP_0] = 0;
+        rop_to_index[CIRRUS_ROP_SRC_AND_DST] = 1;
+        rop_to_index[CIRRUS_ROP_NOP] = 2;
+        rop_to_index[CIRRUS_ROP_SRC_AND_NOTDST] = 3;
+        rop_to_index[CIRRUS_ROP_NOTDST] = 4;
+        rop_to_index[CIRRUS_ROP_SRC] = 5;
+        rop_to_index[CIRRUS_ROP_1] = 6;
+        rop_to_index[CIRRUS_ROP_NOTSRC_AND_DST] = 7;
+        rop_to_index[CIRRUS_ROP_SRC_XOR_DST] = 8;
+        rop_to_index[CIRRUS_ROP_SRC_OR_DST] = 9;
+        rop_to_index[CIRRUS_ROP_NOTSRC_OR_NOTDST] = 10;
+        rop_to_index[CIRRUS_ROP_SRC_NOTXOR_DST] = 11;
+        rop_to_index[CIRRUS_ROP_SRC_OR_NOTDST] = 12;
+        rop_to_index[CIRRUS_ROP_NOTSRC] = 13;
+        rop_to_index[CIRRUS_ROP_NOTSRC_OR_DST] = 14;
+        rop_to_index[CIRRUS_ROP_NOTSRC_AND_NOTDST] = 15;
+        s->device_id = device_id;
+        if (is_pci)
+            s->bustype = CIRRUS_BUSTYPE_PCI;
+        else
+            s->bustype = CIRRUS_BUSTYPE_ISA;
+    }
+
+    /* Register ioport 0x3b0 - 0x3df */
+    memory_region_init_io(&s->cirrus_vga_io, &cirrus_vga_io_ops, s,
+                          "cirrus-io", 0x30);
+    memory_region_add_subregion(system_io, 0x3b0, &s->cirrus_vga_io);
+
+    memory_region_init(&s->low_mem_container,
+                       "cirrus-lowmem-container",
+                       0x20000);
+
+    memory_region_init_io(&s->low_mem, &cirrus_vga_mem_ops, s,
+                          "cirrus-low-memory", 0x20000);
+    memory_region_add_subregion(&s->low_mem_container, 0, &s->low_mem);
+    for (i = 0; i < 2; ++i) {
+        static const char *names[] = { "vga.bank0", "vga.bank1" };
+        MemoryRegion *bank = &s->cirrus_bank[i];
+        memory_region_init_alias(bank, names[i], &s->vga.vram, 0, 0x8000);
+        memory_region_set_enabled(bank, false);
+        memory_region_add_subregion_overlap(&s->low_mem_container, i * 0x8000,
+                                            bank, 1);
+    }
+    memory_region_add_subregion_overlap(system_memory,
+                                        isa_mem_base + 0x000a0000,
+                                        &s->low_mem_container,
+                                        1);
+    memory_region_set_coalescing(&s->low_mem);
+
+    /* I/O handler for LFB */
+    memory_region_init_io(&s->cirrus_linear_io, &cirrus_linear_io_ops, s,
+                          "cirrus-linear-io", s->vga.vram_size_mb
+                                              * 1024 * 1024);
+    memory_region_set_flush_coalesced(&s->cirrus_linear_io);
+
+    /* I/O handler for LFB */
+    memory_region_init_io(&s->cirrus_linear_bitblt_io,
+                          &cirrus_linear_bitblt_io_ops,
+                          s,
+                          "cirrus-bitblt-mmio",
+                          0x400000);
+    memory_region_set_flush_coalesced(&s->cirrus_linear_bitblt_io);
+
+    /* I/O handler for memory-mapped I/O */
+    memory_region_init_io(&s->cirrus_mmio_io, &cirrus_mmio_io_ops, s,
+                          "cirrus-mmio", CIRRUS_PNPMMIO_SIZE);
+    memory_region_set_flush_coalesced(&s->cirrus_mmio_io);
+
+    s->real_vram_size =
+        (s->device_id == CIRRUS_ID_CLGD5446) ? 4096 * 1024 : 2048 * 1024;
+
+    /* XXX: s->vga.vram_size must be a power of two */
+    s->cirrus_addr_mask = s->real_vram_size - 1;
+    s->linear_mmio_mask = s->real_vram_size - 256;
+
+    s->vga.get_bpp = cirrus_get_bpp;
+    s->vga.get_offsets = cirrus_get_offsets;
+    s->vga.get_resolution = cirrus_get_resolution;
+    s->vga.cursor_invalidate = cirrus_cursor_invalidate;
+    s->vga.cursor_draw_line = cirrus_cursor_draw_line;
+
+    qemu_register_reset(cirrus_reset, s);
+}
+
+/***************************************
+ *
+ *  ISA bus support
+ *
+ ***************************************/
+
+static int vga_initfn(ISADevice *dev)
+{
+    ISACirrusVGAState *d = DO_UPCAST(ISACirrusVGAState, dev, dev);
+    VGACommonState *s = &d->cirrus_vga.vga;
+
+    vga_common_init(s);
+    cirrus_init_common(&d->cirrus_vga, CIRRUS_ID_CLGD5430, 0,
+                       isa_address_space(dev), isa_address_space_io(dev));
+    s->con = 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 0;
+}
+
+static Property isa_vga_cirrus_properties[] = {
+    DEFINE_PROP_UINT32("vgamem_mb", struct ISACirrusVGAState,
+                       cirrus_vga.vga.vram_size_mb, 8),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void isa_cirrus_vga_class_init(ObjectClass *klass, void *data)
+{
+    ISADeviceClass *k = ISA_DEVICE_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->vmsd  = &vmstate_cirrus_vga;
+    k->init   = vga_initfn;
+    dc->props = isa_vga_cirrus_properties;
+}
+
+static const TypeInfo isa_cirrus_vga_info = {
+    .name          = "isa-cirrus-vga",
+    .parent        = TYPE_ISA_DEVICE,
+    .instance_size = sizeof(ISACirrusVGAState),
+    .class_init = isa_cirrus_vga_class_init,
+};
+
+/***************************************
+ *
+ *  PCI bus support
+ *
+ ***************************************/
+
+static int pci_cirrus_vga_initfn(PCIDevice *dev)
+{
+     PCICirrusVGAState *d = DO_UPCAST(PCICirrusVGAState, dev, dev);
+     CirrusVGAState *s = &d->cirrus_vga;
+     PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev);
+     int16_t device_id = pc->device_id;
+
+     /* setup VGA */
+     vga_common_init(&s->vga);
+     cirrus_init_common(s, device_id, 1, pci_address_space(dev),
+                        pci_address_space_io(dev));
+     s->vga.con = graphic_console_init(s->vga.update, s->vga.invalidate,
+                                       s->vga.screen_dump, s->vga.text_update,
+                                       &s->vga);
+
+     /* setup PCI */
+
+    memory_region_init(&s->pci_bar, "cirrus-pci-bar0", 0x2000000);
+
+    /* XXX: add byte swapping apertures */
+    memory_region_add_subregion(&s->pci_bar, 0, &s->cirrus_linear_io);
+    memory_region_add_subregion(&s->pci_bar, 0x1000000,
+                                &s->cirrus_linear_bitblt_io);
+
+     /* setup memory space */
+     /* memory #0 LFB */
+     /* memory #1 memory-mapped I/O */
+     /* XXX: s->vga.vram_size must be a power of two */
+     pci_register_bar(&d->dev, 0, PCI_BASE_ADDRESS_MEM_PREFETCH, &s->pci_bar);
+     if (device_id == CIRRUS_ID_CLGD5446) {
+         pci_register_bar(&d->dev, 1, 0, &s->cirrus_mmio_io);
+     }
+     return 0;
+}
+
+static Property pci_vga_cirrus_properties[] = {
+    DEFINE_PROP_UINT32("vgamem_mb", struct PCICirrusVGAState,
+                       cirrus_vga.vga.vram_size_mb, 8),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void cirrus_vga_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->no_hotplug = 1;
+    k->init = pci_cirrus_vga_initfn;
+    k->romfile = VGABIOS_CIRRUS_FILENAME;
+    k->vendor_id = PCI_VENDOR_ID_CIRRUS;
+    k->device_id = CIRRUS_ID_CLGD5446;
+    k->class_id = PCI_CLASS_DISPLAY_VGA;
+    dc->desc = "Cirrus CLGD 54xx VGA";
+    dc->vmsd = &vmstate_pci_cirrus_vga;
+    dc->props = pci_vga_cirrus_properties;
+}
+
+static const 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_types(void)
+{
+    type_register_static(&isa_cirrus_vga_info);
+    type_register_static(&cirrus_vga_info);
+}
+
+type_init(cirrus_vga_register_types)
diff --git a/hw/display/cirrus_vga_rop.h b/hw/display/cirrus_vga_rop.h
new file mode 100644 (file)
index 0000000..9c7bb09
--- /dev/null
@@ -0,0 +1,208 @@
+/*
+ * QEMU Cirrus CLGD 54xx VGA Emulator.
+ *
+ * Copyright (c) 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.
+ */
+
+static inline void glue(rop_8_,ROP_NAME)(uint8_t *dst, uint8_t src)
+{
+    *dst = ROP_FN(*dst, src);
+}
+
+static inline void glue(rop_16_,ROP_NAME)(uint16_t *dst, uint16_t src)
+{
+    *dst = ROP_FN(*dst, src);
+}
+
+static inline void glue(rop_32_,ROP_NAME)(uint32_t *dst, uint32_t src)
+{
+    *dst = ROP_FN(*dst, src);
+}
+
+#define ROP_OP(d, s) glue(rop_8_,ROP_NAME)(d, s)
+#define ROP_OP_16(d, s) glue(rop_16_,ROP_NAME)(d, s)
+#define ROP_OP_32(d, s) glue(rop_32_,ROP_NAME)(d, s)
+#undef ROP_FN
+
+static void
+glue(cirrus_bitblt_rop_fwd_, ROP_NAME)(CirrusVGAState *s,
+                             uint8_t *dst,const uint8_t *src,
+                             int dstpitch,int srcpitch,
+                             int bltwidth,int bltheight)
+{
+    int x,y;
+    dstpitch -= bltwidth;
+    srcpitch -= bltwidth;
+
+    if (dstpitch < 0 || srcpitch < 0) {
+        /* is 0 valid? srcpitch == 0 could be useful */
+        return;
+    }
+
+    for (y = 0; y < bltheight; y++) {
+        for (x = 0; x < bltwidth; x++) {
+            ROP_OP(dst, *src);
+            dst++;
+            src++;
+        }
+        dst += dstpitch;
+        src += srcpitch;
+    }
+}
+
+static void
+glue(cirrus_bitblt_rop_bkwd_, ROP_NAME)(CirrusVGAState *s,
+                                        uint8_t *dst,const uint8_t *src,
+                                        int dstpitch,int srcpitch,
+                                        int bltwidth,int bltheight)
+{
+    int x,y;
+    dstpitch += bltwidth;
+    srcpitch += bltwidth;
+    for (y = 0; y < bltheight; y++) {
+        for (x = 0; x < bltwidth; x++) {
+            ROP_OP(dst, *src);
+            dst--;
+            src--;
+        }
+        dst += dstpitch;
+        src += srcpitch;
+    }
+}
+
+static void
+glue(glue(cirrus_bitblt_rop_fwd_transp_, ROP_NAME),_8)(CirrusVGAState *s,
+                                                      uint8_t *dst,const uint8_t *src,
+                                                      int dstpitch,int srcpitch,
+                                                      int bltwidth,int bltheight)
+{
+    int x,y;
+    uint8_t p;
+    dstpitch -= bltwidth;
+    srcpitch -= bltwidth;
+    for (y = 0; y < bltheight; y++) {
+        for (x = 0; x < bltwidth; x++) {
+           p = *dst;
+            ROP_OP(&p, *src);
+           if (p != s->vga.gr[0x34]) *dst = p;
+            dst++;
+            src++;
+        }
+        dst += dstpitch;
+        src += srcpitch;
+    }
+}
+
+static void
+glue(glue(cirrus_bitblt_rop_bkwd_transp_, ROP_NAME),_8)(CirrusVGAState *s,
+                                                       uint8_t *dst,const uint8_t *src,
+                                                       int dstpitch,int srcpitch,
+                                                       int bltwidth,int bltheight)
+{
+    int x,y;
+    uint8_t p;
+    dstpitch += bltwidth;
+    srcpitch += bltwidth;
+    for (y = 0; y < bltheight; y++) {
+        for (x = 0; x < bltwidth; x++) {
+           p = *dst;
+            ROP_OP(&p, *src);
+           if (p != s->vga.gr[0x34]) *dst = p;
+            dst--;
+            src--;
+        }
+        dst += dstpitch;
+        src += srcpitch;
+    }
+}
+
+static void
+glue(glue(cirrus_bitblt_rop_fwd_transp_, ROP_NAME),_16)(CirrusVGAState *s,
+                                                       uint8_t *dst,const uint8_t *src,
+                                                       int dstpitch,int srcpitch,
+                                                       int bltwidth,int bltheight)
+{
+    int x,y;
+    uint8_t p1, p2;
+    dstpitch -= bltwidth;
+    srcpitch -= bltwidth;
+    for (y = 0; y < bltheight; y++) {
+        for (x = 0; x < bltwidth; x+=2) {
+           p1 = *dst;
+           p2 = *(dst+1);
+            ROP_OP(&p1, *src);
+            ROP_OP(&p2, *(src + 1));
+           if ((p1 != s->vga.gr[0x34]) || (p2 != s->vga.gr[0x35])) {
+               *dst = p1;
+               *(dst+1) = p2;
+           }
+            dst+=2;
+            src+=2;
+        }
+        dst += dstpitch;
+        src += srcpitch;
+    }
+}
+
+static void
+glue(glue(cirrus_bitblt_rop_bkwd_transp_, ROP_NAME),_16)(CirrusVGAState *s,
+                                                        uint8_t *dst,const uint8_t *src,
+                                                        int dstpitch,int srcpitch,
+                                                        int bltwidth,int bltheight)
+{
+    int x,y;
+    uint8_t p1, p2;
+    dstpitch += bltwidth;
+    srcpitch += bltwidth;
+    for (y = 0; y < bltheight; y++) {
+        for (x = 0; x < bltwidth; x+=2) {
+           p1 = *(dst-1);
+           p2 = *dst;
+            ROP_OP(&p1, *(src - 1));
+            ROP_OP(&p2, *src);
+           if ((p1 != s->vga.gr[0x34]) || (p2 != s->vga.gr[0x35])) {
+               *(dst-1) = p1;
+               *dst = p2;
+           }
+            dst-=2;
+            src-=2;
+        }
+        dst += dstpitch;
+        src += srcpitch;
+    }
+}
+
+#define DEPTH 8
+#include "cirrus_vga_rop2.h"
+
+#define DEPTH 16
+#include "cirrus_vga_rop2.h"
+
+#define DEPTH 24
+#include "cirrus_vga_rop2.h"
+
+#define DEPTH 32
+#include "cirrus_vga_rop2.h"
+
+#undef ROP_NAME
+#undef ROP_OP
+#undef ROP_OP_16
+#undef ROP_OP_32
diff --git a/hw/display/cirrus_vga_rop2.h b/hw/display/cirrus_vga_rop2.h
new file mode 100644 (file)
index 0000000..d28bcc6
--- /dev/null
@@ -0,0 +1,281 @@
+/*
+ * QEMU Cirrus CLGD 54xx VGA Emulator.
+ *
+ * Copyright (c) 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.
+ */
+
+#if DEPTH == 8
+#define PUTPIXEL()    ROP_OP(&d[0], col)
+#elif DEPTH == 16
+#define PUTPIXEL()    ROP_OP_16((uint16_t *)&d[0], col)
+#elif DEPTH == 24
+#define PUTPIXEL()    ROP_OP(&d[0], col);        \
+                      ROP_OP(&d[1], (col >> 8)); \
+                      ROP_OP(&d[2], (col >> 16))
+#elif DEPTH == 32
+#define PUTPIXEL()    ROP_OP_32(((uint32_t *)&d[0]), col)
+#else
+#error unsupported DEPTH
+#endif
+
+static void
+glue(glue(glue(cirrus_patternfill_, ROP_NAME), _),DEPTH)
+     (CirrusVGAState * s, uint8_t * dst,
+      const uint8_t * src,
+      int dstpitch, int srcpitch,
+      int bltwidth, int bltheight)
+{
+    uint8_t *d;
+    int x, y, pattern_y, pattern_pitch, pattern_x;
+    unsigned int col;
+    const uint8_t *src1;
+#if DEPTH == 24
+    int skipleft = s->vga.gr[0x2f] & 0x1f;
+#else
+    int skipleft = (s->vga.gr[0x2f] & 0x07) * (DEPTH / 8);
+#endif
+
+#if DEPTH == 8
+    pattern_pitch = 8;
+#elif DEPTH == 16
+    pattern_pitch = 16;
+#else
+    pattern_pitch = 32;
+#endif
+    pattern_y = s->cirrus_blt_srcaddr & 7;
+    for(y = 0; y < bltheight; y++) {
+        pattern_x = skipleft;
+        d = dst + skipleft;
+        src1 = src + pattern_y * pattern_pitch;
+        for (x = skipleft; x < bltwidth; x += (DEPTH / 8)) {
+#if DEPTH == 8
+            col = src1[pattern_x];
+            pattern_x = (pattern_x + 1) & 7;
+#elif DEPTH == 16
+            col = ((uint16_t *)(src1 + pattern_x))[0];
+            pattern_x = (pattern_x + 2) & 15;
+#elif DEPTH == 24
+            {
+                const uint8_t *src2 = src1 + pattern_x * 3;
+                col = src2[0] | (src2[1] << 8) | (src2[2] << 16);
+                pattern_x = (pattern_x + 1) & 7;
+            }
+#else
+            col = ((uint32_t *)(src1 + pattern_x))[0];
+            pattern_x = (pattern_x + 4) & 31;
+#endif
+            PUTPIXEL();
+            d += (DEPTH / 8);
+        }
+        pattern_y = (pattern_y + 1) & 7;
+        dst += dstpitch;
+    }
+}
+
+/* NOTE: srcpitch is ignored */
+static void
+glue(glue(glue(cirrus_colorexpand_transp_, ROP_NAME), _),DEPTH)
+     (CirrusVGAState * s, uint8_t * dst,
+      const uint8_t * src,
+      int dstpitch, int srcpitch,
+      int bltwidth, int bltheight)
+{
+    uint8_t *d;
+    int x, y;
+    unsigned bits, bits_xor;
+    unsigned int col;
+    unsigned bitmask;
+    unsigned index;
+#if DEPTH == 24
+    int dstskipleft = s->vga.gr[0x2f] & 0x1f;
+    int srcskipleft = dstskipleft / 3;
+#else
+    int srcskipleft = s->vga.gr[0x2f] & 0x07;
+    int dstskipleft = srcskipleft * (DEPTH / 8);
+#endif
+
+    if (s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_COLOREXPINV) {
+        bits_xor = 0xff;
+        col = s->cirrus_blt_bgcol;
+    } else {
+        bits_xor = 0x00;
+        col = s->cirrus_blt_fgcol;
+    }
+
+    for(y = 0; y < bltheight; y++) {
+        bitmask = 0x80 >> srcskipleft;
+        bits = *src++ ^ bits_xor;
+        d = dst + dstskipleft;
+        for (x = dstskipleft; x < bltwidth; x += (DEPTH / 8)) {
+            if ((bitmask & 0xff) == 0) {
+                bitmask = 0x80;
+                bits = *src++ ^ bits_xor;
+            }
+            index = (bits & bitmask);
+            if (index) {
+                PUTPIXEL();
+            }
+            d += (DEPTH / 8);
+            bitmask >>= 1;
+        }
+        dst += dstpitch;
+    }
+}
+
+static void
+glue(glue(glue(cirrus_colorexpand_, ROP_NAME), _),DEPTH)
+     (CirrusVGAState * s, uint8_t * dst,
+      const uint8_t * src,
+      int dstpitch, int srcpitch,
+      int bltwidth, int bltheight)
+{
+    uint32_t colors[2];
+    uint8_t *d;
+    int x, y;
+    unsigned bits;
+    unsigned int col;
+    unsigned bitmask;
+    int srcskipleft = s->vga.gr[0x2f] & 0x07;
+    int dstskipleft = srcskipleft * (DEPTH / 8);
+
+    colors[0] = s->cirrus_blt_bgcol;
+    colors[1] = s->cirrus_blt_fgcol;
+    for(y = 0; y < bltheight; y++) {
+        bitmask = 0x80 >> srcskipleft;
+        bits = *src++;
+        d = dst + dstskipleft;
+        for (x = dstskipleft; x < bltwidth; x += (DEPTH / 8)) {
+            if ((bitmask & 0xff) == 0) {
+                bitmask = 0x80;
+                bits = *src++;
+            }
+            col = colors[!!(bits & bitmask)];
+            PUTPIXEL();
+            d += (DEPTH / 8);
+            bitmask >>= 1;
+        }
+        dst += dstpitch;
+    }
+}
+
+static void
+glue(glue(glue(cirrus_colorexpand_pattern_transp_, ROP_NAME), _),DEPTH)
+     (CirrusVGAState * s, uint8_t * dst,
+      const uint8_t * src,
+      int dstpitch, int srcpitch,
+      int bltwidth, int bltheight)
+{
+    uint8_t *d;
+    int x, y, bitpos, pattern_y;
+    unsigned int bits, bits_xor;
+    unsigned int col;
+#if DEPTH == 24
+    int dstskipleft = s->vga.gr[0x2f] & 0x1f;
+    int srcskipleft = dstskipleft / 3;
+#else
+    int srcskipleft = s->vga.gr[0x2f] & 0x07;
+    int dstskipleft = srcskipleft * (DEPTH / 8);
+#endif
+
+    if (s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_COLOREXPINV) {
+        bits_xor = 0xff;
+        col = s->cirrus_blt_bgcol;
+    } else {
+        bits_xor = 0x00;
+        col = s->cirrus_blt_fgcol;
+    }
+    pattern_y = s->cirrus_blt_srcaddr & 7;
+
+    for(y = 0; y < bltheight; y++) {
+        bits = src[pattern_y] ^ bits_xor;
+        bitpos = 7 - srcskipleft;
+        d = dst + dstskipleft;
+        for (x = dstskipleft; x < bltwidth; x += (DEPTH / 8)) {
+            if ((bits >> bitpos) & 1) {
+                PUTPIXEL();
+            }
+            d += (DEPTH / 8);
+            bitpos = (bitpos - 1) & 7;
+        }
+        pattern_y = (pattern_y + 1) & 7;
+        dst += dstpitch;
+    }
+}
+
+static void
+glue(glue(glue(cirrus_colorexpand_pattern_, ROP_NAME), _),DEPTH)
+     (CirrusVGAState * s, uint8_t * dst,
+      const uint8_t * src,
+      int dstpitch, int srcpitch,
+      int bltwidth, int bltheight)
+{
+    uint32_t colors[2];
+    uint8_t *d;
+    int x, y, bitpos, pattern_y;
+    unsigned int bits;
+    unsigned int col;
+    int srcskipleft = s->vga.gr[0x2f] & 0x07;
+    int dstskipleft = srcskipleft * (DEPTH / 8);
+
+    colors[0] = s->cirrus_blt_bgcol;
+    colors[1] = s->cirrus_blt_fgcol;
+    pattern_y = s->cirrus_blt_srcaddr & 7;
+
+    for(y = 0; y < bltheight; y++) {
+        bits = src[pattern_y];
+        bitpos = 7 - srcskipleft;
+        d = dst + dstskipleft;
+        for (x = dstskipleft; x < bltwidth; x += (DEPTH / 8)) {
+            col = colors[(bits >> bitpos) & 1];
+            PUTPIXEL();
+            d += (DEPTH / 8);
+            bitpos = (bitpos - 1) & 7;
+        }
+        pattern_y = (pattern_y + 1) & 7;
+        dst += dstpitch;
+    }
+}
+
+static void
+glue(glue(glue(cirrus_fill_, ROP_NAME), _),DEPTH)
+     (CirrusVGAState *s,
+      uint8_t *dst, int dst_pitch,
+      int width, int height)
+{
+    uint8_t *d, *d1;
+    uint32_t col;
+    int x, y;
+
+    col = s->cirrus_blt_fgcol;
+
+    d1 = dst;
+    for(y = 0; y < height; y++) {
+        d = d1;
+        for(x = 0; x < width; x += (DEPTH / 8)) {
+            PUTPIXEL();
+            d += (DEPTH / 8);
+        }
+        d1 += dst_pitch;
+    }
+}
+
+#undef DEPTH
+#undef PUTPIXEL
diff --git a/hw/display/cirrus_vga_template.h b/hw/display/cirrus_vga_template.h
new file mode 100644 (file)
index 0000000..3b28280
--- /dev/null
@@ -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/display/exynos4210_fimd.c b/hw/display/exynos4210_fimd.c
new file mode 100644 (file)
index 0000000..49cca4b
--- /dev/null
@@ -0,0 +1,1930 @@
+/*
+ * 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@ispras.ru>
+ *
+ * Contributed by Mitsyanko Igor <i.mitsyanko@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 "hw/sysbus.h"
+#include "ui/console.h"
+#include "ui/pixel_ops.h"
+#include "qemu/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 */
+    hwaddr fb_len;       /* Framebuffer length */
+};
+
+typedef struct {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    QemuConsole *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 { \
+        memcpy(&data, src, sizeof(data)); \
+        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 { \
+        memcpy(&data, src, sizeof(data)); \
+        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];
+    hwaddr 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)
+{
+    DisplaySurface *surface = qemu_console_surface(s->console);
+
+    /* 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 || surface_width(surface) != width ||
+            surface_height(surface) != height) {
+        DPRINT_L1("Resolution changed from %ux%u to %ux%u\n",
+           surface_width(surface), surface_height(surface), 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;
+    DisplaySurface *surface = qemu_console_surface(s->console);
+    Exynos4210fimdWindow *w;
+    int i, line;
+    hwaddr 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 || !surface_bits_per_pixel(surface) ||
+            !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 = surface_bits_per_pixel(surface);
+        fimd_update_putpix_qemu(bpp);
+        bpp = (bpp + 1) >> 3;
+        d = surface_data(surface);
+        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_gfx_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, hwaddr 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, hwaddr 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 const 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)
diff --git a/hw/display/framebuffer.c b/hw/display/framebuffer.c
new file mode 100644 (file)
index 0000000..6be31db
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * Framebuffer device helper routines
+ *
+ * Copyright (c) 2009 CodeSourcery
+ * Written by Paul Brook <paul@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:
+   - Do something similar for framebuffers with local ram
+   - Handle rotation here instead of hacking dest_pitch
+   - Use common pixel conversion routines instead of per-device drawfn
+   - Remove all DisplayState knowledge from devices.
+ */
+
+#include "hw/hw.h"
+#include "ui/console.h"
+#include "framebuffer.h"
+
+/* Render an image from a shared memory framebuffer.  */
+   
+void framebuffer_update_display(
+    DisplaySurface *ds,
+    MemoryRegion *address_space,
+    hwaddr base,
+    int cols, /* Width in pixels.  */
+    int rows, /* Height in pixels.  */
+    int src_width, /* Length of source line, in bytes.  */
+    int dest_row_pitch, /* Bytes between adjacent horizontal output pixels.  */
+    int dest_col_pitch, /* Bytes between adjacent vertical output pixels.  */
+    int invalidate, /* nonzero to redraw the whole image.  */
+    drawfn fn,
+    void *opaque,
+    int *first_row, /* Input and output.  */
+    int *last_row /* Output only */)
+{
+    hwaddr src_len;
+    uint8_t *dest;
+    uint8_t *src;
+    uint8_t *src_base;
+    int first, last = 0;
+    int dirty;
+    int i;
+    ram_addr_t addr;
+    MemoryRegionSection mem_section;
+    MemoryRegion *mem;
+
+    i = *first_row;
+    *first_row = -1;
+    src_len = src_width * rows;
+
+    mem_section = memory_region_find(address_space, base, src_len);
+    if (mem_section.size != src_len || !memory_region_is_ram(mem_section.mr)) {
+        return;
+    }
+    mem = mem_section.mr;
+    assert(mem);
+    assert(mem_section.offset_within_address_space == base);
+
+    memory_region_sync_dirty_bitmap(mem);
+    src_base = cpu_physical_memory_map(base, &src_len, 0);
+    /* If we can't map the framebuffer then bail.  We could try harder,
+       but it's not really worth it as dirty flag tracking will probably
+       already have failed above.  */
+    if (!src_base)
+        return;
+    if (src_len != src_width * rows) {
+        cpu_physical_memory_unmap(src_base, src_len, 0, 0);
+        return;
+    }
+    src = src_base;
+    dest = surface_data(ds);
+    if (dest_col_pitch < 0)
+        dest -= dest_col_pitch * (cols - 1);
+    if (dest_row_pitch < 0) {
+        dest -= dest_row_pitch * (rows - 1);
+    }
+    first = -1;
+    addr = mem_section.offset_within_region;
+
+    addr += i * src_width;
+    src += i * src_width;
+    dest += i * dest_row_pitch;
+
+    for (; i < rows; i++) {
+        dirty = memory_region_get_dirty(mem, addr, src_width,
+                                             DIRTY_MEMORY_VGA);
+        if (dirty || invalidate) {
+            fn(opaque, dest, src, cols, dest_col_pitch);
+            if (first == -1)
+                first = i;
+            last = i;
+        }
+        addr += src_width;
+        src += src_width;
+        dest += dest_row_pitch;
+    }
+    cpu_physical_memory_unmap(src_base, src_len, 0, 0);
+    if (first < 0) {
+        return;
+    }
+    memory_region_reset_dirty(mem, mem_section.offset_within_region, src_len,
+                              DIRTY_MEMORY_VGA);
+    *first_row = first;
+    *last_row = last;
+}
diff --git a/hw/display/framebuffer.h b/hw/display/framebuffer.h
new file mode 100644 (file)
index 0000000..6eae035
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef QEMU_FRAMEBUFFER_H
+#define QEMU_FRAMEBUFFER_H
+
+#include "exec/memory.h"
+
+/* Framebuffer device helper routines.  */
+
+typedef void (*drawfn)(void *, uint8_t *, const uint8_t *, int, int);
+
+void framebuffer_update_display(
+    DisplaySurface *ds,
+    MemoryRegion *address_space,
+    hwaddr base,
+    int cols,
+    int rows,
+    int src_width,
+    int dest_row_pitch,
+    int dest_col_pitch,
+    int invalidate,
+    drawfn fn,
+    void *opaque,
+    int *first_row,
+    int *last_row);
+
+#endif
diff --git a/hw/display/g364fb.c b/hw/display/g364fb.c
new file mode 100644 (file)
index 0000000..f7014e9
--- /dev/null
@@ -0,0 +1,617 @@
+/*
+ * QEMU G364 framebuffer Emulator.
+ *
+ * Copyright (c) 2007-2011 Herve Poussineau
+ *
+ * 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 "hw/hw.h"
+#include "ui/console.h"
+#include "ui/pixel_ops.h"
+#include "trace.h"
+#include "hw/sysbus.h"
+
+typedef struct G364State {
+    /* hardware */
+    uint8_t *vram;
+    uint32_t vram_size;
+    qemu_irq irq;
+    MemoryRegion mem_vram;
+    MemoryRegion mem_ctrl;
+    /* registers */
+    uint8_t color_palette[256][3];
+    uint8_t cursor_palette[3][3];
+    uint16_t cursor[512];
+    uint32_t cursor_position;
+    uint32_t ctla;
+    uint32_t top_of_screen;
+    uint32_t width, height; /* in pixels */
+    /* display refresh support */
+    QemuConsole *con;
+    int depth;
+    int blanked;
+} G364State;
+
+#define REG_BOOT     0x000000
+#define REG_DISPLAY  0x000118
+#define REG_VDISPLAY 0x000150
+#define REG_CTLA     0x000300
+#define REG_TOP      0x000400
+#define REG_CURS_PAL 0x000508
+#define REG_CURS_POS 0x000638
+#define REG_CLR_PAL  0x000800
+#define REG_CURS_PAT 0x001000
+#define REG_RESET    0x100000
+
+#define CTLA_FORCE_BLANK 0x00000400
+#define CTLA_NO_CURSOR   0x00800000
+
+#define G364_PAGE_SIZE 4096
+
+static inline int check_dirty(G364State *s, ram_addr_t page)
+{
+    return memory_region_get_dirty(&s->mem_vram, page, G364_PAGE_SIZE,
+                                   DIRTY_MEMORY_VGA);
+}
+
+static inline void reset_dirty(G364State *s,
+                               ram_addr_t page_min, ram_addr_t page_max)
+{
+    memory_region_reset_dirty(&s->mem_vram,
+                              page_min,
+                              page_max + G364_PAGE_SIZE - page_min - 1,
+                              DIRTY_MEMORY_VGA);
+}
+
+static void g364fb_draw_graphic8(G364State *s)
+{
+    DisplaySurface *surface = qemu_console_surface(s->con);
+    int i, w;
+    uint8_t *vram;
+    uint8_t *data_display, *dd;
+    ram_addr_t page, page_min, page_max;
+    int x, y;
+    int xmin, xmax;
+    int ymin, ymax;
+    int xcursor, ycursor;
+    unsigned int (*rgb_to_pixel)(unsigned int r, unsigned int g, unsigned int b);
+
+    switch (surface_bits_per_pixel(surface)) {
+        case 8:
+            rgb_to_pixel = rgb_to_pixel8;
+            w = 1;
+            break;
+        case 15:
+            rgb_to_pixel = rgb_to_pixel15;
+            w = 2;
+            break;
+        case 16:
+            rgb_to_pixel = rgb_to_pixel16;
+            w = 2;
+            break;
+        case 32:
+            rgb_to_pixel = rgb_to_pixel32;
+            w = 4;
+            break;
+        default:
+            hw_error("g364: unknown host depth %d",
+                     surface_bits_per_pixel(surface));
+            return;
+    }
+
+    page = 0;
+    page_min = (ram_addr_t)-1;
+    page_max = 0;
+
+    x = y = 0;
+    xmin = s->width;
+    xmax = 0;
+    ymin = s->height;
+    ymax = 0;
+
+    if (!(s->ctla & CTLA_NO_CURSOR)) {
+        xcursor = s->cursor_position >> 12;
+        ycursor = s->cursor_position & 0xfff;
+    } else {
+        xcursor = ycursor = -65;
+    }
+
+    vram = s->vram + s->top_of_screen;
+    /* XXX: out of range in vram? */
+    data_display = dd = surface_data(surface);
+    while (y < s->height) {
+        if (check_dirty(s, page)) {
+            if (y < ymin)
+                ymin = ymax = y;
+            if (page_min == (ram_addr_t)-1)
+                page_min = page;
+            page_max = page;
+            if (x < xmin)
+                xmin = x;
+            for (i = 0; i < G364_PAGE_SIZE; i++) {
+                uint8_t index;
+                unsigned int color;
+                if (unlikely((y >= ycursor && y < ycursor + 64) &&
+                    (x >= xcursor && x < xcursor + 64))) {
+                    /* pointer area */
+                    int xdiff = x - xcursor;
+                    uint16_t curs = s->cursor[(y - ycursor) * 8 + xdiff / 8];
+                    int op = (curs >> ((xdiff & 7) * 2)) & 3;
+                    if (likely(op == 0)) {
+                        /* transparent */
+                        index = *vram;
+                        color = (*rgb_to_pixel)(
+                            s->color_palette[index][0],
+                            s->color_palette[index][1],
+                            s->color_palette[index][2]);
+                    } else {
+                        /* get cursor color */
+                        index = op - 1;
+                        color = (*rgb_to_pixel)(
+                            s->cursor_palette[index][0],
+                            s->cursor_palette[index][1],
+                            s->cursor_palette[index][2]);
+                    }
+                } else {
+                    /* normal area */
+                    index = *vram;
+                    color = (*rgb_to_pixel)(
+                        s->color_palette[index][0],
+                        s->color_palette[index][1],
+                        s->color_palette[index][2]);
+                }
+                memcpy(dd, &color, w);
+                dd += w;
+                x++;
+                vram++;
+                if (x == s->width) {
+                    xmax = s->width - 1;
+                    y++;
+                    if (y == s->height) {
+                        ymax = s->height - 1;
+                        goto done;
+                    }
+                    data_display = dd = data_display + surface_stride(surface);
+                    xmin = 0;
+                    x = 0;
+                }
+            }
+            if (x > xmax)
+                xmax = x;
+            if (y > ymax)
+                ymax = y;
+        } else {
+            int dy;
+            if (page_min != (ram_addr_t)-1) {
+                reset_dirty(s, page_min, page_max);
+                page_min = (ram_addr_t)-1;
+                page_max = 0;
+                dpy_gfx_update(s->con, xmin, ymin,
+                               xmax - xmin + 1, ymax - ymin + 1);
+                xmin = s->width;
+                xmax = 0;
+                ymin = s->height;
+                ymax = 0;
+            }
+            x += G364_PAGE_SIZE;
+            dy = x / s->width;
+            x = x % s->width;
+            y += dy;
+            vram += G364_PAGE_SIZE;
+            data_display += dy * surface_stride(surface);
+            dd = data_display + x * w;
+        }
+        page += G364_PAGE_SIZE;
+    }
+
+done:
+    if (page_min != (ram_addr_t)-1) {
+        dpy_gfx_update(s->con, xmin, ymin, xmax - xmin + 1, ymax - ymin + 1);
+        reset_dirty(s, page_min, page_max);
+    }
+}
+
+static void g364fb_draw_blank(G364State *s)
+{
+    DisplaySurface *surface = qemu_console_surface(s->con);
+    int i, w;
+    uint8_t *d;
+
+    if (s->blanked) {
+        /* Screen is already blank. No need to redraw it */
+        return;
+    }
+
+    w = s->width * surface_bytes_per_pixel(surface);
+    d = surface_data(surface);
+    for (i = 0; i < s->height; i++) {
+        memset(d, 0, w);
+        d += surface_stride(surface);
+    }
+
+    dpy_gfx_update(s->con, 0, 0, s->width, s->height);
+    s->blanked = 1;
+}
+
+static void g364fb_update_display(void *opaque)
+{
+    G364State *s = opaque;
+    DisplaySurface *surface = qemu_console_surface(s->con);
+
+    qemu_flush_coalesced_mmio_buffer();
+
+    if (s->width == 0 || s->height == 0)
+        return;
+
+    if (s->width != surface_width(surface) ||
+        s->height != surface_height(surface)) {
+        qemu_console_resize(s->con, s->width, s->height);
+    }
+
+    if (s->ctla & CTLA_FORCE_BLANK) {
+        g364fb_draw_blank(s);
+    } else if (s->depth == 8) {
+        g364fb_draw_graphic8(s);
+    } else {
+        error_report("g364: unknown guest depth %d", s->depth);
+    }
+
+    qemu_irq_raise(s->irq);
+}
+
+static inline void g364fb_invalidate_display(void *opaque)
+{
+    G364State *s = opaque;
+
+    s->blanked = 0;
+    memory_region_set_dirty(&s->mem_vram, 0, s->vram_size);
+}
+
+static void g364fb_reset(G364State *s)
+{
+    qemu_irq_lower(s->irq);
+
+    memset(s->color_palette, 0, sizeof(s->color_palette));
+    memset(s->cursor_palette, 0, sizeof(s->cursor_palette));
+    memset(s->cursor, 0, sizeof(s->cursor));
+    s->cursor_position = 0;
+    s->ctla = 0;
+    s->top_of_screen = 0;
+    s->width = s->height = 0;
+    memset(s->vram, 0, s->vram_size);
+    g364fb_invalidate_display(s);
+}
+
+static void g364fb_screen_dump(void *opaque, const char *filename, bool cswitch,
+                               Error **errp)
+{
+    G364State *s = opaque;
+    int ret, y, x;
+    uint8_t index;
+    uint8_t *data_buffer;
+    FILE *f;
+
+    qemu_flush_coalesced_mmio_buffer();
+
+    if (s->depth != 8) {
+        error_setg(errp, "g364: unknown guest depth %d", s->depth);
+        return;
+    }
+
+    f = fopen(filename, "wb");
+    if (!f) {
+        error_setg(errp, "failed to open file '%s': %s", filename,
+                   strerror(errno));
+        return;
+    }
+
+    if (s->ctla & CTLA_FORCE_BLANK) {
+        /* blank screen */
+        ret = fprintf(f, "P4\n%d %d\n", s->width, s->height);
+        if (ret < 0) {
+            goto write_err;
+        }
+        for (y = 0; y < s->height; y++)
+            for (x = 0; x < s->width; x++) {
+                ret = fputc(0, f);
+                if (ret == EOF) {
+                    goto write_err;
+                }
+            }
+    } else {
+        data_buffer = s->vram + s->top_of_screen;
+        ret = fprintf(f, "P6\n%d %d\n%d\n", s->width, s->height, 255);
+        if (ret < 0) {
+            goto write_err;
+        }
+        for (y = 0; y < s->height; y++)
+            for (x = 0; x < s->width; x++, data_buffer++) {
+                index = *data_buffer;
+                ret = fputc(s->color_palette[index][0], f);
+                if (ret == EOF) {
+                    goto write_err;
+                }
+                ret = fputc(s->color_palette[index][1], f);
+                if (ret == EOF) {
+                    goto write_err;
+                }
+                ret = fputc(s->color_palette[index][2], f);
+                if (ret == EOF) {
+                    goto write_err;
+                }
+        }
+    }
+
+out:
+    fclose(f);
+    return;
+
+write_err:
+    error_setg(errp, "failed to write to file '%s': %s", filename,
+               strerror(errno));
+    unlink(filename);
+    goto out;
+}
+
+/* called for accesses to io ports */
+static uint64_t g364fb_ctrl_read(void *opaque,
+                                 hwaddr addr,
+                                 unsigned int size)
+{
+    G364State *s = opaque;
+    uint32_t val;
+
+    if (addr >= REG_CURS_PAT && addr < REG_CURS_PAT + 0x1000) {
+        /* cursor pattern */
+        int idx = (addr - REG_CURS_PAT) >> 3;
+        val = s->cursor[idx];
+    } else if (addr >= REG_CURS_PAL && addr < REG_CURS_PAL + 0x18) {
+        /* cursor palette */
+        int idx = (addr - REG_CURS_PAL) >> 3;
+        val = ((uint32_t)s->cursor_palette[idx][0] << 16);
+        val |= ((uint32_t)s->cursor_palette[idx][1] << 8);
+        val |= ((uint32_t)s->cursor_palette[idx][2] << 0);
+    } else {
+        switch (addr) {
+            case REG_DISPLAY:
+                val = s->width / 4;
+                break;
+            case REG_VDISPLAY:
+                val = s->height * 2;
+                break;
+            case REG_CTLA:
+                val = s->ctla;
+                break;
+            default:
+            {
+                error_report("g364: invalid read at [" TARGET_FMT_plx "]",
+                             addr);
+                val = 0;
+                break;
+            }
+        }
+    }
+
+    trace_g364fb_read(addr, val);
+
+    return val;
+}
+
+static void g364fb_update_depth(G364State *s)
+{
+    static const int depths[8] = { 1, 2, 4, 8, 15, 16, 0 };
+    s->depth = depths[(s->ctla & 0x00700000) >> 20];
+}
+
+static void g364_invalidate_cursor_position(G364State *s)
+{
+    DisplaySurface *surface = qemu_console_surface(s->con);
+    int ymin, ymax, start, end;
+
+    /* invalidate only near the cursor */
+    ymin = s->cursor_position & 0xfff;
+    ymax = MIN(s->height, ymin + 64);
+    start = ymin * surface_stride(surface);
+    end = (ymax + 1) * surface_stride(surface);
+
+    memory_region_set_dirty(&s->mem_vram, start, end - start);
+}
+
+static void g364fb_ctrl_write(void *opaque,
+                              hwaddr addr,
+                              uint64_t val,
+                              unsigned int size)
+{
+    G364State *s = opaque;
+
+    trace_g364fb_write(addr, val);
+
+    if (addr >= REG_CLR_PAL && addr < REG_CLR_PAL + 0x800) {
+        /* color palette */
+        int idx = (addr - REG_CLR_PAL) >> 3;
+        s->color_palette[idx][0] = (val >> 16) & 0xff;
+        s->color_palette[idx][1] = (val >> 8) & 0xff;
+        s->color_palette[idx][2] = val & 0xff;
+        g364fb_invalidate_display(s);
+    } else if (addr >= REG_CURS_PAT && addr < REG_CURS_PAT + 0x1000) {
+        /* cursor pattern */
+        int idx = (addr - REG_CURS_PAT) >> 3;
+        s->cursor[idx] = val;
+        g364fb_invalidate_display(s);
+    } else if (addr >= REG_CURS_PAL && addr < REG_CURS_PAL + 0x18) {
+        /* cursor palette */
+        int idx = (addr - REG_CURS_PAL) >> 3;
+        s->cursor_palette[idx][0] = (val >> 16) & 0xff;
+        s->cursor_palette[idx][1] = (val >> 8) & 0xff;
+        s->cursor_palette[idx][2] = val & 0xff;
+        g364fb_invalidate_display(s);
+    } else {
+        switch (addr) {
+        case REG_BOOT: /* Boot timing */
+        case 0x00108: /* Line timing: half sync */
+        case 0x00110: /* Line timing: back porch */
+        case 0x00120: /* Line timing: short display */
+        case 0x00128: /* Frame timing: broad pulse */
+        case 0x00130: /* Frame timing: v sync */
+        case 0x00138: /* Frame timing: v preequalise */
+        case 0x00140: /* Frame timing: v postequalise */
+        case 0x00148: /* Frame timing: v blank */
+        case 0x00158: /* Line timing: line time */
+        case 0x00160: /* Frame store: line start */
+        case 0x00168: /* vram cycle: mem init */
+        case 0x00170: /* vram cycle: transfer delay */
+        case 0x00200: /* vram cycle: mask register */
+            /* ignore */
+            break;
+        case REG_TOP:
+            s->top_of_screen = val;
+            g364fb_invalidate_display(s);
+            break;
+        case REG_DISPLAY:
+            s->width = val * 4;
+            break;
+        case REG_VDISPLAY:
+            s->height = val / 2;
+            break;
+        case REG_CTLA:
+            s->ctla = val;
+            g364fb_update_depth(s);
+            g364fb_invalidate_display(s);
+            break;
+        case REG_CURS_POS:
+            g364_invalidate_cursor_position(s);
+            s->cursor_position = val;
+            g364_invalidate_cursor_position(s);
+            break;
+        case REG_RESET:
+            g364fb_reset(s);
+            break;
+        default:
+            error_report("g364: invalid write of 0x%" PRIx64
+                         " at [" TARGET_FMT_plx "]", val, addr);
+            break;
+        }
+    }
+    qemu_irq_lower(s->irq);
+}
+
+static const MemoryRegionOps g364fb_ctrl_ops = {
+    .read = g364fb_ctrl_read,
+    .write = g364fb_ctrl_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl.min_access_size = 4,
+    .impl.max_access_size = 4,
+};
+
+static int g364fb_post_load(void *opaque, int version_id)
+{
+    G364State *s = opaque;
+
+    /* force refresh */
+    g364fb_update_depth(s);
+    g364fb_invalidate_display(s);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_g364fb = {
+    .name = "g364fb",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .post_load = g364fb_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_VBUFFER_UINT32(vram, G364State, 1, NULL, 0, vram_size),
+        VMSTATE_BUFFER_UNSAFE(color_palette, G364State, 0, 256 * 3),
+        VMSTATE_BUFFER_UNSAFE(cursor_palette, G364State, 0, 9),
+        VMSTATE_UINT16_ARRAY(cursor, G364State, 512),
+        VMSTATE_UINT32(cursor_position, G364State),
+        VMSTATE_UINT32(ctla, G364State),
+        VMSTATE_UINT32(top_of_screen, G364State),
+        VMSTATE_UINT32(width, G364State),
+        VMSTATE_UINT32(height, G364State),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void g364fb_init(DeviceState *dev, G364State *s)
+{
+    s->vram = g_malloc0(s->vram_size);
+
+    s->con = graphic_console_init(g364fb_update_display,
+                                  g364fb_invalidate_display,
+                                  g364fb_screen_dump, NULL, s);
+
+    memory_region_init_io(&s->mem_ctrl, &g364fb_ctrl_ops, s, "ctrl", 0x180000);
+    memory_region_init_ram_ptr(&s->mem_vram, "vram",
+                               s->vram_size, s->vram);
+    vmstate_register_ram(&s->mem_vram, dev);
+    memory_region_set_coalescing(&s->mem_vram);
+}
+
+typedef struct {
+    SysBusDevice busdev;
+    G364State g364;
+} G364SysBusState;
+
+static int g364fb_sysbus_init(SysBusDevice *dev)
+{
+    G364State *s = &FROM_SYSBUS(G364SysBusState, dev)->g364;
+
+    g364fb_init(&dev->qdev, s);
+    sysbus_init_irq(dev, &s->irq);
+    sysbus_init_mmio(dev, &s->mem_ctrl);
+    sysbus_init_mmio(dev, &s->mem_vram);
+
+    return 0;
+}
+
+static void g364fb_sysbus_reset(DeviceState *d)
+{
+    G364SysBusState *s = DO_UPCAST(G364SysBusState, busdev.qdev, d);
+    g364fb_reset(&s->g364);
+}
+
+static Property g364fb_sysbus_properties[] = {
+    DEFINE_PROP_HEX32("vram_size", G364SysBusState, g364.vram_size,
+    8 * 1024 * 1024),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void g364fb_sysbus_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = g364fb_sysbus_init;
+    dc->desc = "G364 framebuffer";
+    dc->reset = g364fb_sysbus_reset;
+    dc->vmsd = &vmstate_g364fb;
+    dc->props = g364fb_sysbus_properties;
+}
+
+static const 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_types(void)
+{
+    type_register_static(&g364fb_sysbus_info);
+}
+
+type_init(g364fb_register_types)
diff --git a/hw/display/jazz_led.c b/hw/display/jazz_led.c
new file mode 100644 (file)
index 0000000..05528c7
--- /dev/null
@@ -0,0 +1,304 @@
+/*
+ * QEMU JAZZ LED emulator.
+ *
+ * Copyright (c) 2007-2012 Herve 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 "qemu-common.h"
+#include "ui/console.h"
+#include "ui/pixel_ops.h"
+#include "trace.h"
+#include "hw/sysbus.h"
+
+typedef enum {
+    REDRAW_NONE = 0, REDRAW_SEGMENTS = 1, REDRAW_BACKGROUND = 2,
+} screen_state_t;
+
+typedef struct LedState {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    uint8_t segments;
+    QemuConsole *con;
+    screen_state_t state;
+} LedState;
+
+static uint64_t jazz_led_read(void *opaque, hwaddr addr,
+                              unsigned int size)
+{
+    LedState *s = opaque;
+    uint8_t val;
+
+    val = s->segments;
+    trace_jazz_led_read(addr, val);
+
+    return val;
+}
+
+static void jazz_led_write(void *opaque, hwaddr addr,
+                           uint64_t val, unsigned int size)
+{
+    LedState *s = opaque;
+    uint8_t new_val = val & 0xff;
+
+    trace_jazz_led_write(addr, new_val);
+
+    s->segments = new_val;
+    s->state |= REDRAW_SEGMENTS;
+}
+
+static const MemoryRegionOps led_ops = {
+    .read = jazz_led_read,
+    .write = jazz_led_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .impl.min_access_size = 1,
+    .impl.max_access_size = 1,
+};
+
+/***********************************************************/
+/* jazz_led display */
+
+static void draw_horizontal_line(DisplaySurface *ds,
+                                 int posy, int posx1, int posx2,
+                                 uint32_t color)
+{
+    uint8_t *d;
+    int x, bpp;
+
+    bpp = (surface_bits_per_pixel(ds) + 7) >> 3;
+    d = surface_data(ds) + surface_stride(ds) * posy + bpp * posx1;
+    switch(bpp) {
+        case 1:
+            for (x = posx1; x <= posx2; x++) {
+                *((uint8_t *)d) = color;
+                d++;
+            }
+            break;
+        case 2:
+            for (x = posx1; x <= posx2; x++) {
+                *((uint16_t *)d) = color;
+                d += 2;
+            }
+            break;
+        case 4:
+            for (x = posx1; x <= posx2; x++) {
+                *((uint32_t *)d) = color;
+                d += 4;
+            }
+            break;
+    }
+}
+
+static void draw_vertical_line(DisplaySurface *ds,
+                               int posx, int posy1, int posy2,
+                               uint32_t color)
+{
+    uint8_t *d;
+    int y, bpp;
+
+    bpp = (surface_bits_per_pixel(ds) + 7) >> 3;
+    d = surface_data(ds) + surface_stride(ds) * posy1 + bpp * posx;
+    switch(bpp) {
+        case 1:
+            for (y = posy1; y <= posy2; y++) {
+                *((uint8_t *)d) = color;
+                d += surface_stride(ds);
+            }
+            break;
+        case 2:
+            for (y = posy1; y <= posy2; y++) {
+                *((uint16_t *)d) = color;
+                d += surface_stride(ds);
+            }
+            break;
+        case 4:
+            for (y = posy1; y <= posy2; y++) {
+                *((uint32_t *)d) = color;
+                d += surface_stride(ds);
+            }
+            break;
+    }
+}
+
+static void jazz_led_update_display(void *opaque)
+{
+    LedState *s = opaque;
+    DisplaySurface *surface = qemu_console_surface(s->con);
+    uint8_t *d1;
+    uint32_t color_segment, color_led;
+    int y, bpp;
+
+    if (s->state & REDRAW_BACKGROUND) {
+        /* clear screen */
+        bpp = (surface_bits_per_pixel(surface) + 7) >> 3;
+        d1 = surface_data(surface);
+        for (y = 0; y < surface_height(surface); y++) {
+            memset(d1, 0x00, surface_width(surface) * bpp);
+            d1 += surface_stride(surface);
+        }
+    }
+
+    if (s->state & REDRAW_SEGMENTS) {
+        /* set colors according to bpp */
+        switch (surface_bits_per_pixel(surface)) {
+            case 8:
+                color_segment = rgb_to_pixel8(0xaa, 0xaa, 0xaa);
+                color_led = rgb_to_pixel8(0x00, 0xff, 0x00);
+                break;
+            case 15:
+                color_segment = rgb_to_pixel15(0xaa, 0xaa, 0xaa);
+                color_led = rgb_to_pixel15(0x00, 0xff, 0x00);
+                break;
+            case 16:
+                color_segment = rgb_to_pixel16(0xaa, 0xaa, 0xaa);
+                color_led = rgb_to_pixel16(0x00, 0xff, 0x00);
+            case 24:
+                color_segment = rgb_to_pixel24(0xaa, 0xaa, 0xaa);
+                color_led = rgb_to_pixel24(0x00, 0xff, 0x00);
+                break;
+            case 32:
+                color_segment = rgb_to_pixel32(0xaa, 0xaa, 0xaa);
+                color_led = rgb_to_pixel32(0x00, 0xff, 0x00);
+                break;
+            default:
+                return;
+        }
+
+        /* display segments */
+        draw_horizontal_line(surface, 40, 10, 40,
+                             (s->segments & 0x02) ? color_segment : 0);
+        draw_vertical_line(surface, 10, 10, 40,
+                           (s->segments & 0x04) ? color_segment : 0);
+        draw_vertical_line(surface, 10, 40, 70,
+                           (s->segments & 0x08) ? color_segment : 0);
+        draw_horizontal_line(surface, 70, 10, 40,
+                             (s->segments & 0x10) ? color_segment : 0);
+        draw_vertical_line(surface, 40, 40, 70,
+                           (s->segments & 0x20) ? color_segment : 0);
+        draw_vertical_line(surface, 40, 10, 40,
+                           (s->segments & 0x40) ? color_segment : 0);
+        draw_horizontal_line(surface, 10, 10, 40,
+                             (s->segments & 0x80) ? color_segment : 0);
+
+        /* display led */
+        if (!(s->segments & 0x01))
+            color_led = 0; /* black */
+        draw_horizontal_line(surface, 68, 50, 50, color_led);
+        draw_horizontal_line(surface, 69, 49, 51, color_led);
+        draw_horizontal_line(surface, 70, 48, 52, color_led);
+        draw_horizontal_line(surface, 71, 49, 51, color_led);
+        draw_horizontal_line(surface, 72, 50, 50, color_led);
+    }
+
+    s->state = REDRAW_NONE;
+    dpy_gfx_update(s->con, 0, 0,
+                   surface_width(surface), surface_height(surface));
+}
+
+static void jazz_led_invalidate_display(void *opaque)
+{
+    LedState *s = opaque;
+    s->state |= REDRAW_SEGMENTS | REDRAW_BACKGROUND;
+}
+
+static void jazz_led_text_update(void *opaque, console_ch_t *chardata)
+{
+    LedState *s = opaque;
+    char buf[2];
+
+    dpy_text_cursor(s->con, -1, -1);
+    qemu_console_resize(s->con, 2, 1);
+
+    /* TODO: draw the segments */
+    snprintf(buf, 2, "%02hhx\n", s->segments);
+    console_write_ch(chardata++, 0x00200100 | buf[0]);
+    console_write_ch(chardata++, 0x00200100 | buf[1]);
+
+    dpy_text_update(s->con, 0, 0, 2, 1);
+}
+
+static int jazz_led_post_load(void *opaque, int version_id)
+{
+    /* force refresh */
+    jazz_led_invalidate_display(opaque);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_jazz_led = {
+    .name = "jazz-led",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .post_load = jazz_led_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT8(segments, LedState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int jazz_led_init(SysBusDevice *dev)
+{
+    LedState *s = FROM_SYSBUS(LedState, dev);
+
+    memory_region_init_io(&s->iomem, &led_ops, s, "led", 1);
+    sysbus_init_mmio(dev, &s->iomem);
+
+    s->con = graphic_console_init(jazz_led_update_display,
+                                  jazz_led_invalidate_display,
+                                  NULL,
+                                  jazz_led_text_update, s);
+
+    return 0;
+}
+
+static void jazz_led_reset(DeviceState *d)
+{
+    LedState *s = DO_UPCAST(LedState, busdev.qdev, d);
+
+    s->segments = 0;
+    s->state = REDRAW_SEGMENTS | REDRAW_BACKGROUND;
+    qemu_console_resize(s->con, 60, 80);
+}
+
+static void jazz_led_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = jazz_led_init;
+    dc->desc = "Jazz LED display",
+    dc->vmsd = &vmstate_jazz_led;
+    dc->reset = jazz_led_reset;
+}
+
+static const TypeInfo jazz_led_info = {
+    .name          = "jazz-led",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(LedState),
+    .class_init    = jazz_led_class_init,
+};
+
+static void jazz_led_register(void)
+{
+    type_register_static(&jazz_led_info);
+}
+
+type_init(jazz_led_register);
diff --git a/hw/display/milkymist-tmu2.c b/hw/display/milkymist-tmu2.c
new file mode 100644 (file)
index 0000000..b723a04
--- /dev/null
@@ -0,0 +1,490 @@
+/*
+ *  QEMU model of the Milkymist texture mapping unit.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
+ *  Copyright (c) 2010 Sebastien Bourdeauducq
+ *                       <sebastien.bourdeauducq@lekernel.net>
+ *
+ * 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/>.
+ *
+ *
+ * Specification available at:
+ *   http://www.milkymist.org/socdoc/tmu2.pdf
+ *
+ */
+
+#include "hw/hw.h"
+#include "hw/sysbus.h"
+#include "trace.h"
+#include "qemu/error-report.h"
+
+#include <X11/Xlib.h>
+#include <GL/gl.h>
+#include <GL/glx.h>
+
+enum {
+    R_CTL = 0,
+    R_HMESHLAST,
+    R_VMESHLAST,
+    R_BRIGHTNESS,
+    R_CHROMAKEY,
+    R_VERTICESADDR,
+    R_TEXFBUF,
+    R_TEXHRES,
+    R_TEXVRES,
+    R_TEXHMASK,
+    R_TEXVMASK,
+    R_DSTFBUF,
+    R_DSTHRES,
+    R_DSTVRES,
+    R_DSTHOFFSET,
+    R_DSTVOFFSET,
+    R_DSTSQUAREW,
+    R_DSTSQUAREH,
+    R_ALPHA,
+    R_MAX
+};
+
+enum {
+    CTL_START_BUSY  = (1<<0),
+    CTL_CHROMAKEY   = (1<<1),
+};
+
+enum {
+    MAX_BRIGHTNESS = 63,
+    MAX_ALPHA      = 63,
+};
+
+enum {
+    MESH_MAXSIZE = 128,
+};
+
+struct vertex {
+    int x;
+    int y;
+} QEMU_PACKED;
+
+struct MilkymistTMU2State {
+    SysBusDevice busdev;
+    MemoryRegion regs_region;
+    CharDriverState *chr;
+    qemu_irq irq;
+
+    uint32_t regs[R_MAX];
+
+    Display *dpy;
+    GLXFBConfig glx_fb_config;
+    GLXContext glx_context;
+};
+typedef struct MilkymistTMU2State MilkymistTMU2State;
+
+static const int glx_fbconfig_attr[] = {
+    GLX_GREEN_SIZE, 5,
+    GLX_GREEN_SIZE, 6,
+    GLX_BLUE_SIZE, 5,
+    None
+};
+
+static int tmu2_glx_init(MilkymistTMU2State *s)
+{
+    GLXFBConfig *configs;
+    int nelements;
+
+    s->dpy = XOpenDisplay(NULL); /* FIXME: call XCloseDisplay() */
+    if (s->dpy == NULL) {
+        return 1;
+    }
+
+    configs = glXChooseFBConfig(s->dpy, 0, glx_fbconfig_attr, &nelements);
+    if (configs == NULL) {
+        return 1;
+    }
+
+    s->glx_fb_config = *configs;
+    XFree(configs);
+
+    /* FIXME: call glXDestroyContext() */
+    s->glx_context = glXCreateNewContext(s->dpy, s->glx_fb_config,
+            GLX_RGBA_TYPE, NULL, 1);
+    if (s->glx_context == NULL) {
+        return 1;
+    }
+
+    return 0;
+}
+
+static void tmu2_gl_map(struct vertex *mesh, int texhres, int texvres,
+        int hmeshlast, int vmeshlast, int ho, int vo, int sw, int sh)
+{
+    int x, y;
+    int x0, y0, x1, y1;
+    int u0, v0, u1, v1, u2, v2, u3, v3;
+    double xscale = 1.0 / ((double)(64 * texhres));
+    double yscale = 1.0 / ((double)(64 * texvres));
+
+    glLoadIdentity();
+    glTranslatef(ho, vo, 0);
+    glEnable(GL_TEXTURE_2D);
+    glBegin(GL_QUADS);
+
+    for (y = 0; y < vmeshlast; y++) {
+        y0 = y * sh;
+        y1 = y0 + sh;
+        for (x = 0; x < hmeshlast; x++) {
+            x0 = x * sw;
+            x1 = x0 + sw;
+
+            u0 = be32_to_cpu(mesh[MESH_MAXSIZE * y + x].x);
+            v0 = be32_to_cpu(mesh[MESH_MAXSIZE * y + x].y);
+            u1 = be32_to_cpu(mesh[MESH_MAXSIZE * y + x + 1].x);
+            v1 = be32_to_cpu(mesh[MESH_MAXSIZE * y + x + 1].y);
+            u2 = be32_to_cpu(mesh[MESH_MAXSIZE * (y + 1) + x + 1].x);
+            v2 = be32_to_cpu(mesh[MESH_MAXSIZE * (y + 1) + x + 1].y);
+            u3 = be32_to_cpu(mesh[MESH_MAXSIZE * (y + 1) + x].x);
+            v3 = be32_to_cpu(mesh[MESH_MAXSIZE * (y + 1) + x].y);
+
+            glTexCoord2d(((double)u0) * xscale, ((double)v0) * yscale);
+            glVertex3i(x0, y0, 0);
+            glTexCoord2d(((double)u1) * xscale, ((double)v1) * yscale);
+            glVertex3i(x1, y0, 0);
+            glTexCoord2d(((double)u2) * xscale, ((double)v2) * yscale);
+            glVertex3i(x1, y1, 0);
+            glTexCoord2d(((double)u3) * xscale, ((double)v3) * yscale);
+            glVertex3i(x0, y1, 0);
+        }
+    }
+
+    glEnd();
+}
+
+static void tmu2_start(MilkymistTMU2State *s)
+{
+    int pbuffer_attrib[6] = {
+        GLX_PBUFFER_WIDTH,
+        0,
+        GLX_PBUFFER_HEIGHT,
+        0,
+        GLX_PRESERVED_CONTENTS,
+        True
+    };
+
+    GLXPbuffer pbuffer;
+    GLuint texture;
+    void *fb;
+    hwaddr fb_len;
+    void *mesh;
+    hwaddr mesh_len;
+    float m;
+
+    trace_milkymist_tmu2_start();
+
+    /* Create and set up a suitable OpenGL context */
+    pbuffer_attrib[1] = s->regs[R_DSTHRES];
+    pbuffer_attrib[3] = s->regs[R_DSTVRES];
+    pbuffer = glXCreatePbuffer(s->dpy, s->glx_fb_config, pbuffer_attrib);
+    glXMakeContextCurrent(s->dpy, pbuffer, pbuffer, s->glx_context);
+
+    /* Fixup endianness. TODO: would it work on BE hosts? */
+    glPixelStorei(GL_UNPACK_SWAP_BYTES, 1);
+    glPixelStorei(GL_PACK_SWAP_BYTES, 1);
+
+    /* Row alignment */
+    glPixelStorei(GL_UNPACK_ALIGNMENT, 2);
+    glPixelStorei(GL_PACK_ALIGNMENT, 2);
+
+    /* Read the QEMU source framebuffer into an OpenGL texture */
+    glGenTextures(1, &texture);
+    glBindTexture(GL_TEXTURE_2D, texture);
+    fb_len = 2*s->regs[R_TEXHRES]*s->regs[R_TEXVRES];
+    fb = cpu_physical_memory_map(s->regs[R_TEXFBUF], &fb_len, 0);
+    if (fb == NULL) {
+        glDeleteTextures(1, &texture);
+        glXMakeContextCurrent(s->dpy, None, None, NULL);
+        glXDestroyPbuffer(s->dpy, pbuffer);
+        return;
+    }
+    glTexImage2D(GL_TEXTURE_2D, 0, 3, s->regs[R_TEXHRES], s->regs[R_TEXVRES],
+            0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, fb);
+    cpu_physical_memory_unmap(fb, fb_len, 0, fb_len);
+
+    /* Set up texturing options */
+    /* WARNING:
+     * Many cases of TMU2 masking are not supported by OpenGL.
+     * We only implement the most common ones:
+     *  - full bilinear filtering vs. nearest texel
+     *  - texture clamping vs. texture wrapping
+     */
+    if ((s->regs[R_TEXHMASK] & 0x3f) > 0x20) {
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    } else {
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+    }
+    if ((s->regs[R_TEXHMASK] >> 6) & s->regs[R_TEXHRES]) {
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
+    } else {
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+    }
+    if ((s->regs[R_TEXVMASK] >> 6) & s->regs[R_TEXVRES]) {
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
+    } else {
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+    }
+
+    /* Translucency and decay */
+    glEnable(GL_BLEND);
+    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+    m = (float)(s->regs[R_BRIGHTNESS] + 1) / 64.0f;
+    glColor4f(m, m, m, (float)(s->regs[R_ALPHA] + 1) / 64.0f);
+
+    /* Read the QEMU dest. framebuffer into the OpenGL framebuffer */
+    fb_len = 2 * s->regs[R_DSTHRES] * s->regs[R_DSTVRES];
+    fb = cpu_physical_memory_map(s->regs[R_DSTFBUF], &fb_len, 0);
+    if (fb == NULL) {
+        glDeleteTextures(1, &texture);
+        glXMakeContextCurrent(s->dpy, None, None, NULL);
+        glXDestroyPbuffer(s->dpy, pbuffer);
+        return;
+    }
+
+    glDrawPixels(s->regs[R_DSTHRES], s->regs[R_DSTVRES], GL_RGB,
+            GL_UNSIGNED_SHORT_5_6_5, fb);
+    cpu_physical_memory_unmap(fb, fb_len, 0, fb_len);
+    glViewport(0, 0, s->regs[R_DSTHRES], s->regs[R_DSTVRES]);
+    glMatrixMode(GL_PROJECTION);
+    glLoadIdentity();
+    glOrtho(0.0, s->regs[R_DSTHRES], 0.0, s->regs[R_DSTVRES], -1.0, 1.0);
+    glMatrixMode(GL_MODELVIEW);
+
+    /* Map the texture */
+    mesh_len = MESH_MAXSIZE*MESH_MAXSIZE*sizeof(struct vertex);
+    mesh = cpu_physical_memory_map(s->regs[R_VERTICESADDR], &mesh_len, 0);
+    if (mesh == NULL) {
+        glDeleteTextures(1, &texture);
+        glXMakeContextCurrent(s->dpy, None, None, NULL);
+        glXDestroyPbuffer(s->dpy, pbuffer);
+        return;
+    }
+
+    tmu2_gl_map((struct vertex *)mesh,
+        s->regs[R_TEXHRES], s->regs[R_TEXVRES],
+        s->regs[R_HMESHLAST], s->regs[R_VMESHLAST],
+        s->regs[R_DSTHOFFSET], s->regs[R_DSTVOFFSET],
+        s->regs[R_DSTSQUAREW], s->regs[R_DSTSQUAREH]);
+    cpu_physical_memory_unmap(mesh, mesh_len, 0, mesh_len);
+
+    /* Write back the OpenGL framebuffer to the QEMU framebuffer */
+    fb_len = 2 * s->regs[R_DSTHRES] * s->regs[R_DSTVRES];
+    fb = cpu_physical_memory_map(s->regs[R_DSTFBUF], &fb_len, 1);
+    if (fb == NULL) {
+        glDeleteTextures(1, &texture);
+        glXMakeContextCurrent(s->dpy, None, None, NULL);
+        glXDestroyPbuffer(s->dpy, pbuffer);
+        return;
+    }
+
+    glReadPixels(0, 0, s->regs[R_DSTHRES], s->regs[R_DSTVRES], GL_RGB,
+            GL_UNSIGNED_SHORT_5_6_5, fb);
+    cpu_physical_memory_unmap(fb, fb_len, 1, fb_len);
+
+    /* Free OpenGL allocs */
+    glDeleteTextures(1, &texture);
+    glXMakeContextCurrent(s->dpy, None, None, NULL);
+    glXDestroyPbuffer(s->dpy, pbuffer);
+
+    s->regs[R_CTL] &= ~CTL_START_BUSY;
+
+    trace_milkymist_tmu2_pulse_irq();
+    qemu_irq_pulse(s->irq);
+}
+
+static uint64_t tmu2_read(void *opaque, hwaddr addr,
+                          unsigned size)
+{
+    MilkymistTMU2State *s = opaque;
+    uint32_t r = 0;
+
+    addr >>= 2;
+    switch (addr) {
+    case R_CTL:
+    case R_HMESHLAST:
+    case R_VMESHLAST:
+    case R_BRIGHTNESS:
+    case R_CHROMAKEY:
+    case R_VERTICESADDR:
+    case R_TEXFBUF:
+    case R_TEXHRES:
+    case R_TEXVRES:
+    case R_TEXHMASK:
+    case R_TEXVMASK:
+    case R_DSTFBUF:
+    case R_DSTHRES:
+    case R_DSTVRES:
+    case R_DSTHOFFSET:
+    case R_DSTVOFFSET:
+    case R_DSTSQUAREW:
+    case R_DSTSQUAREH:
+    case R_ALPHA:
+        r = s->regs[addr];
+        break;
+
+    default:
+        error_report("milkymist_tmu2: read access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+
+    trace_milkymist_tmu2_memory_read(addr << 2, r);
+
+    return r;
+}
+
+static void tmu2_check_registers(MilkymistTMU2State *s)
+{
+    if (s->regs[R_BRIGHTNESS] > MAX_BRIGHTNESS) {
+        error_report("milkymist_tmu2: max brightness is %d", MAX_BRIGHTNESS);
+    }
+
+    if (s->regs[R_ALPHA] > MAX_ALPHA) {
+        error_report("milkymist_tmu2: max alpha is %d", MAX_ALPHA);
+    }
+
+    if (s->regs[R_VERTICESADDR] & 0x07) {
+        error_report("milkymist_tmu2: vertex mesh address has to be 64-bit "
+                "aligned");
+    }
+
+    if (s->regs[R_TEXFBUF] & 0x01) {
+        error_report("milkymist_tmu2: texture buffer address has to be "
+                "16-bit aligned");
+    }
+}
+
+static void tmu2_write(void *opaque, hwaddr addr, uint64_t value,
+                       unsigned size)
+{
+    MilkymistTMU2State *s = opaque;
+
+    trace_milkymist_tmu2_memory_write(addr, value);
+
+    addr >>= 2;
+    switch (addr) {
+    case R_CTL:
+        s->regs[addr] = value;
+        if (value & CTL_START_BUSY) {
+            tmu2_start(s);
+        }
+        break;
+    case R_BRIGHTNESS:
+    case R_HMESHLAST:
+    case R_VMESHLAST:
+    case R_CHROMAKEY:
+    case R_VERTICESADDR:
+    case R_TEXFBUF:
+    case R_TEXHRES:
+    case R_TEXVRES:
+    case R_TEXHMASK:
+    case R_TEXVMASK:
+    case R_DSTFBUF:
+    case R_DSTHRES:
+    case R_DSTVRES:
+    case R_DSTHOFFSET:
+    case R_DSTVOFFSET:
+    case R_DSTSQUAREW:
+    case R_DSTSQUAREH:
+    case R_ALPHA:
+        s->regs[addr] = value;
+        break;
+
+    default:
+        error_report("milkymist_tmu2: write access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+
+    tmu2_check_registers(s);
+}
+
+static const MemoryRegionOps tmu2_mmio_ops = {
+    .read = tmu2_read,
+    .write = tmu2_write,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void milkymist_tmu2_reset(DeviceState *d)
+{
+    MilkymistTMU2State *s = container_of(d, MilkymistTMU2State, busdev.qdev);
+    int i;
+
+    for (i = 0; i < R_MAX; i++) {
+        s->regs[i] = 0;
+    }
+}
+
+static int milkymist_tmu2_init(SysBusDevice *dev)
+{
+    MilkymistTMU2State *s = FROM_SYSBUS(typeof(*s), dev);
+
+    if (tmu2_glx_init(s)) {
+        return 1;
+    }
+
+    sysbus_init_irq(dev, &s->irq);
+
+    memory_region_init_io(&s->regs_region, &tmu2_mmio_ops, s,
+            "milkymist-tmu2", R_MAX * 4);
+    sysbus_init_mmio(dev, &s->regs_region);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_milkymist_tmu2 = {
+    .name = "milkymist-tmu2",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(regs, MilkymistTMU2State, R_MAX),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+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 const 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_types(void)
+{
+    type_register_static(&milkymist_tmu2_info);
+}
+
+type_init(milkymist_tmu2_register_types)
diff --git a/hw/display/milkymist-vgafb.c b/hw/display/milkymist-vgafb.c
new file mode 100644 (file)
index 0000000..3219041
--- /dev/null
@@ -0,0 +1,335 @@
+
+/*
+ *  QEMU model of the Milkymist VGA framebuffer.
+ *
+ *  Copyright (c) 2010-2012 Michael Walle <michael@walle.cc>
+ *
+ * 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/>.
+ *
+ *
+ * Specification available at:
+ *   http://www.milkymist.org/socdoc/vgafb.pdf
+ */
+
+#include "hw/hw.h"
+#include "hw/sysbus.h"
+#include "trace.h"
+#include "ui/console.h"
+#include "framebuffer.h"
+#include "ui/pixel_ops.h"
+#include "qemu/error-report.h"
+
+#define BITS 8
+#include "milkymist-vgafb_template.h"
+#define BITS 15
+#include "milkymist-vgafb_template.h"
+#define BITS 16
+#include "milkymist-vgafb_template.h"
+#define BITS 24
+#include "milkymist-vgafb_template.h"
+#define BITS 32
+#include "milkymist-vgafb_template.h"
+
+enum {
+    R_CTRL = 0,
+    R_HRES,
+    R_HSYNC_START,
+    R_HSYNC_END,
+    R_HSCAN,
+    R_VRES,
+    R_VSYNC_START,
+    R_VSYNC_END,
+    R_VSCAN,
+    R_BASEADDRESS,
+    R_BASEADDRESS_ACT,
+    R_BURST_COUNT,
+    R_DDC,
+    R_SOURCE_CLOCK,
+    R_MAX
+};
+
+enum {
+    CTRL_RESET = (1<<0),
+};
+
+struct MilkymistVgafbState {
+    SysBusDevice busdev;
+    MemoryRegion regs_region;
+    QemuConsole *con;
+
+    int invalidate;
+    uint32_t fb_offset;
+    uint32_t fb_mask;
+
+    uint32_t regs[R_MAX];
+};
+typedef struct MilkymistVgafbState MilkymistVgafbState;
+
+static int vgafb_enabled(MilkymistVgafbState *s)
+{
+    return !(s->regs[R_CTRL] & CTRL_RESET);
+}
+
+static void vgafb_update_display(void *opaque)
+{
+    MilkymistVgafbState *s = opaque;
+    DisplaySurface *surface = qemu_console_surface(s->con);
+    int first = 0;
+    int last = 0;
+    drawfn fn;
+
+    if (!vgafb_enabled(s)) {
+        return;
+    }
+
+    int dest_width = s->regs[R_HRES];
+
+    switch (surface_bits_per_pixel(surface)) {
+    case 0:
+        return;
+    case 8:
+        fn = draw_line_8;
+        break;
+    case 15:
+        fn = draw_line_15;
+        dest_width *= 2;
+        break;
+    case 16:
+        fn = draw_line_16;
+        dest_width *= 2;
+        break;
+    case 24:
+        fn = draw_line_24;
+        dest_width *= 3;
+        break;
+    case 32:
+        fn = draw_line_32;
+        dest_width *= 4;
+        break;
+    default:
+        hw_error("milkymist_vgafb: bad color depth\n");
+        break;
+    }
+
+    framebuffer_update_display(surface, sysbus_address_space(&s->busdev),
+                               s->regs[R_BASEADDRESS] + s->fb_offset,
+                               s->regs[R_HRES],
+                               s->regs[R_VRES],
+                               s->regs[R_HRES] * 2,
+                               dest_width,
+                               0,
+                               s->invalidate,
+                               fn,
+                               NULL,
+                               &first, &last);
+
+    if (first >= 0) {
+        dpy_gfx_update(s->con, 0, first, s->regs[R_HRES], last - first + 1);
+    }
+    s->invalidate = 0;
+}
+
+static void vgafb_invalidate_display(void *opaque)
+{
+    MilkymistVgafbState *s = opaque;
+    s->invalidate = 1;
+}
+
+static void vgafb_resize(MilkymistVgafbState *s)
+{
+    if (!vgafb_enabled(s)) {
+        return;
+    }
+
+    qemu_console_resize(s->con, s->regs[R_HRES], s->regs[R_VRES]);
+    s->invalidate = 1;
+}
+
+static uint64_t vgafb_read(void *opaque, hwaddr addr,
+                           unsigned size)
+{
+    MilkymistVgafbState *s = opaque;
+    uint32_t r = 0;
+
+    addr >>= 2;
+    switch (addr) {
+    case R_CTRL:
+    case R_HRES:
+    case R_HSYNC_START:
+    case R_HSYNC_END:
+    case R_HSCAN:
+    case R_VRES:
+    case R_VSYNC_START:
+    case R_VSYNC_END:
+    case R_VSCAN:
+    case R_BASEADDRESS:
+    case R_BURST_COUNT:
+    case R_DDC:
+    case R_SOURCE_CLOCK:
+        r = s->regs[addr];
+    break;
+    case R_BASEADDRESS_ACT:
+        r = s->regs[R_BASEADDRESS];
+    break;
+
+    default:
+        error_report("milkymist_vgafb: read access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+
+    trace_milkymist_vgafb_memory_read(addr << 2, r);
+
+    return r;
+}
+
+static void vgafb_write(void *opaque, hwaddr addr, uint64_t value,
+                        unsigned size)
+{
+    MilkymistVgafbState *s = opaque;
+
+    trace_milkymist_vgafb_memory_write(addr, value);
+
+    addr >>= 2;
+    switch (addr) {
+    case R_CTRL:
+        s->regs[addr] = value;
+        vgafb_resize(s);
+        break;
+    case R_HSYNC_START:
+    case R_HSYNC_END:
+    case R_HSCAN:
+    case R_VSYNC_START:
+    case R_VSYNC_END:
+    case R_VSCAN:
+    case R_BURST_COUNT:
+    case R_DDC:
+    case R_SOURCE_CLOCK:
+        s->regs[addr] = value;
+        break;
+    case R_BASEADDRESS:
+        if (value & 0x1f) {
+            error_report("milkymist_vgafb: framebuffer base address have to "
+                     "be 32 byte aligned");
+            break;
+        }
+        s->regs[addr] = value & s->fb_mask;
+        s->invalidate = 1;
+        break;
+    case R_HRES:
+    case R_VRES:
+        s->regs[addr] = value;
+        vgafb_resize(s);
+        break;
+    case R_BASEADDRESS_ACT:
+        error_report("milkymist_vgafb: write to read-only register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+
+    default:
+        error_report("milkymist_vgafb: write access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+}
+
+static const MemoryRegionOps vgafb_mmio_ops = {
+    .read = vgafb_read,
+    .write = vgafb_write,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void milkymist_vgafb_reset(DeviceState *d)
+{
+    MilkymistVgafbState *s = container_of(d, MilkymistVgafbState, busdev.qdev);
+    int i;
+
+    for (i = 0; i < R_MAX; i++) {
+        s->regs[i] = 0;
+    }
+
+    /* defaults */
+    s->regs[R_CTRL] = CTRL_RESET;
+    s->regs[R_HRES] = 640;
+    s->regs[R_VRES] = 480;
+    s->regs[R_BASEADDRESS] = 0;
+}
+
+static int milkymist_vgafb_init(SysBusDevice *dev)
+{
+    MilkymistVgafbState *s = FROM_SYSBUS(typeof(*s), dev);
+
+    memory_region_init_io(&s->regs_region, &vgafb_mmio_ops, s,
+            "milkymist-vgafb", R_MAX * 4);
+    sysbus_init_mmio(dev, &s->regs_region);
+
+    s->con = graphic_console_init(vgafb_update_display,
+                                  vgafb_invalidate_display,
+                                  NULL, NULL, s);
+
+    return 0;
+}
+
+static int vgafb_post_load(void *opaque, int version_id)
+{
+    vgafb_invalidate_display(opaque);
+    return 0;
+}
+
+static const VMStateDescription vmstate_milkymist_vgafb = {
+    .name = "milkymist-vgafb",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .post_load = vgafb_post_load,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(regs, MilkymistVgafbState, R_MAX),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static Property milkymist_vgafb_properties[] = {
+    DEFINE_PROP_UINT32("fb_offset", MilkymistVgafbState, fb_offset, 0x0),
+    DEFINE_PROP_UINT32("fb_mask", MilkymistVgafbState, fb_mask, 0xffffffff),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void milkymist_vgafb_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = milkymist_vgafb_init;
+    dc->reset = milkymist_vgafb_reset;
+    dc->vmsd = &vmstate_milkymist_vgafb;
+    dc->props = milkymist_vgafb_properties;
+}
+
+static const 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_types(void)
+{
+    type_register_static(&milkymist_vgafb_info);
+}
+
+type_init(milkymist_vgafb_register_types)
diff --git a/hw/display/milkymist-vgafb_template.h b/hw/display/milkymist-vgafb_template.h
new file mode 100644 (file)
index 0000000..e0036e1
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ *  QEMU model of the Milkymist VGA framebuffer.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
+ *
+ * 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/>.
+ *
+ */
+
+#if BITS == 8
+#define COPY_PIXEL(to, r, g, b)                    \
+    do {                                           \
+        *to = rgb_to_pixel8(r, g, b);              \
+        to += 1;                                   \
+    } while (0)
+#elif BITS == 15
+#define COPY_PIXEL(to, r, g, b)                    \
+    do {                                           \
+        *(uint16_t *)to = rgb_to_pixel15(r, g, b); \
+        to += 2;                                   \
+    } while (0)
+#elif BITS == 16
+#define COPY_PIXEL(to, r, g, b)                    \
+    do {                                           \
+        *(uint16_t *)to = rgb_to_pixel16(r, g, b); \
+        to += 2;                                   \
+    } while (0)
+#elif BITS == 24
+#define COPY_PIXEL(to, r, g, b)                    \
+    do {                                           \
+        uint32_t tmp = rgb_to_pixel24(r, g, b);    \
+        *(to++) =         tmp & 0xff;              \
+        *(to++) =  (tmp >> 8) & 0xff;              \
+        *(to++) = (tmp >> 16) & 0xff;              \
+    } while (0)
+#elif BITS == 32
+#define COPY_PIXEL(to, r, g, b)                    \
+    do {                                           \
+        *(uint32_t *)to = rgb_to_pixel32(r, g, b); \
+        to += 4;                                   \
+    } while (0)
+#else
+#error unknown bit depth
+#endif
+
+static void glue(draw_line_, BITS)(void *opaque, uint8_t *d, const uint8_t *s,
+        int width, int deststep)
+{
+    uint16_t rgb565;
+    uint8_t r, g, b;
+
+    while (width--) {
+        memcpy(&rgb565, s, sizeof(rgb565));
+        r = ((rgb565 >> 11) & 0x1f) << 3;
+        g = ((rgb565 >>  5) & 0x3f) << 2;
+        b = ((rgb565 >>  0) & 0x1f) << 3;
+        COPY_PIXEL(d, r, g, b);
+        s += 2;
+    }
+}
+
+#undef BITS
+#undef COPY_PIXEL
diff --git a/hw/display/omap_dss.c b/hw/display/omap_dss.c
new file mode 100644 (file)
index 0000000..ea3afce
--- /dev/null
@@ -0,0 +1,1086 @@
+/*
+ * OMAP2 Display Subsystem.
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ * Written by Andrzej Zaborowski <andrew@openedhand.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 or
+ * (at your option) version 3 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
+ * 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 "hw/hw.h"
+#include "ui/console.h"
+#include "hw/arm/omap.h"
+
+struct omap_dss_s {
+    qemu_irq irq;
+    qemu_irq drq;
+    DisplayState *state;
+    MemoryRegion iomem_diss1, iomem_disc1, iomem_rfbi1, iomem_venc1, iomem_im3;
+
+    int autoidle;
+    int control;
+    int enable;
+
+    struct omap_dss_panel_s {
+        int enable;
+        int nx;
+        int ny;
+
+        int x;
+        int y;
+    } dig, lcd;
+
+    struct {
+        uint32_t idlemode;
+        uint32_t irqst;
+        uint32_t irqen;
+        uint32_t control;
+        uint32_t config;
+        uint32_t capable;
+        uint32_t timing[4];
+        int line;
+        uint32_t bg[2];
+        uint32_t trans[2];
+
+        struct omap_dss_plane_s {
+            int enable;
+            int bpp;
+            int posx;
+            int posy;
+            int nx;
+            int ny;
+
+            hwaddr addr[3];
+
+            uint32_t attr;
+            uint32_t tresh;
+            int rowinc;
+            int colinc;
+            int wininc;
+        } l[3];
+
+        int invalidate;
+        uint16_t palette[256];
+    } dispc;
+
+    struct {
+        int idlemode;
+        uint32_t control;
+        int enable;
+        int pixels;
+        int busy;
+        int skiplines;
+        uint16_t rxbuf;
+        uint32_t config[2];
+        uint32_t time[4];
+        uint32_t data[6];
+        uint16_t vsync;
+        uint16_t hsync;
+        struct rfbi_chip_s *chip[2];
+    } rfbi;
+};
+
+static void omap_dispc_interrupt_update(struct omap_dss_s *s)
+{
+    qemu_set_irq(s->irq, s->dispc.irqst & s->dispc.irqen);
+}
+
+static void omap_rfbi_reset(struct omap_dss_s *s)
+{
+    s->rfbi.idlemode = 0;
+    s->rfbi.control = 2;
+    s->rfbi.enable = 0;
+    s->rfbi.pixels = 0;
+    s->rfbi.skiplines = 0;
+    s->rfbi.busy = 0;
+    s->rfbi.config[0] = 0x00310000;
+    s->rfbi.config[1] = 0x00310000;
+    s->rfbi.time[0] = 0;
+    s->rfbi.time[1] = 0;
+    s->rfbi.time[2] = 0;
+    s->rfbi.time[3] = 0;
+    s->rfbi.data[0] = 0;
+    s->rfbi.data[1] = 0;
+    s->rfbi.data[2] = 0;
+    s->rfbi.data[3] = 0;
+    s->rfbi.data[4] = 0;
+    s->rfbi.data[5] = 0;
+    s->rfbi.vsync = 0;
+    s->rfbi.hsync = 0;
+}
+
+void omap_dss_reset(struct omap_dss_s *s)
+{
+    s->autoidle = 0;
+    s->control = 0;
+    s->enable = 0;
+
+    s->dig.enable = 0;
+    s->dig.nx = 1;
+    s->dig.ny = 1;
+
+    s->lcd.enable = 0;
+    s->lcd.nx = 1;
+    s->lcd.ny = 1;
+
+    s->dispc.idlemode = 0;
+    s->dispc.irqst = 0;
+    s->dispc.irqen = 0;
+    s->dispc.control = 0;
+    s->dispc.config = 0;
+    s->dispc.capable = 0x161;
+    s->dispc.timing[0] = 0;
+    s->dispc.timing[1] = 0;
+    s->dispc.timing[2] = 0;
+    s->dispc.timing[3] = 0;
+    s->dispc.line = 0;
+    s->dispc.bg[0] = 0;
+    s->dispc.bg[1] = 0;
+    s->dispc.trans[0] = 0;
+    s->dispc.trans[1] = 0;
+
+    s->dispc.l[0].enable = 0;
+    s->dispc.l[0].bpp = 0;
+    s->dispc.l[0].addr[0] = 0;
+    s->dispc.l[0].addr[1] = 0;
+    s->dispc.l[0].addr[2] = 0;
+    s->dispc.l[0].posx = 0;
+    s->dispc.l[0].posy = 0;
+    s->dispc.l[0].nx = 1;
+    s->dispc.l[0].ny = 1;
+    s->dispc.l[0].attr = 0;
+    s->dispc.l[0].tresh = 0;
+    s->dispc.l[0].rowinc = 1;
+    s->dispc.l[0].colinc = 1;
+    s->dispc.l[0].wininc = 0;
+
+    omap_rfbi_reset(s);
+    omap_dispc_interrupt_update(s);
+}
+
+static uint64_t omap_diss_read(void *opaque, hwaddr addr,
+                               unsigned size)
+{
+    struct omap_dss_s *s = (struct omap_dss_s *) opaque;
+
+    if (size != 4) {
+        return omap_badwidth_read32(opaque, addr);
+    }
+
+    switch (addr) {
+    case 0x00: /* DSS_REVISIONNUMBER */
+        return 0x20;
+
+    case 0x10: /* DSS_SYSCONFIG */
+        return s->autoidle;
+
+    case 0x14: /* DSS_SYSSTATUS */
+        return 1;                                              /* RESETDONE */
+
+    case 0x40: /* DSS_CONTROL */
+        return s->control;
+
+    case 0x50: /* DSS_PSA_LCD_REG_1 */
+    case 0x54: /* DSS_PSA_LCD_REG_2 */
+    case 0x58: /* DSS_PSA_VIDEO_REG */
+        /* TODO: fake some values when appropriate s->control bits are set */
+        return 0;
+
+    case 0x5c: /* DSS_STATUS */
+        return 1 + (s->control & 1);
+
+    default:
+        break;
+    }
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_diss_write(void *opaque, hwaddr addr,
+                            uint64_t value, unsigned size)
+{
+    struct omap_dss_s *s = (struct omap_dss_s *) opaque;
+
+    if (size != 4) {
+        return omap_badwidth_write32(opaque, addr, value);
+    }
+
+    switch (addr) {
+    case 0x00: /* DSS_REVISIONNUMBER */
+    case 0x14: /* DSS_SYSSTATUS */
+    case 0x50: /* DSS_PSA_LCD_REG_1 */
+    case 0x54: /* DSS_PSA_LCD_REG_2 */
+    case 0x58: /* DSS_PSA_VIDEO_REG */
+    case 0x5c: /* DSS_STATUS */
+        OMAP_RO_REG(addr);
+        break;
+
+    case 0x10: /* DSS_SYSCONFIG */
+        if (value & 2)                                         /* SOFTRESET */
+            omap_dss_reset(s);
+        s->autoidle = value & 1;
+        break;
+
+    case 0x40: /* DSS_CONTROL */
+        s->control = value & 0x3dd;
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+    }
+}
+
+static const MemoryRegionOps omap_diss_ops = {
+    .read = omap_diss_read,
+    .write = omap_diss_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static uint64_t omap_disc_read(void *opaque, hwaddr addr,
+                               unsigned size)
+{
+    struct omap_dss_s *s = (struct omap_dss_s *) opaque;
+
+    if (size != 4) {
+        return omap_badwidth_read32(opaque, addr);
+    }
+
+    switch (addr) {
+    case 0x000:        /* DISPC_REVISION */
+        return 0x20;
+
+    case 0x010:        /* DISPC_SYSCONFIG */
+        return s->dispc.idlemode;
+
+    case 0x014:        /* DISPC_SYSSTATUS */
+        return 1;                                              /* RESETDONE */
+
+    case 0x018:        /* DISPC_IRQSTATUS */
+        return s->dispc.irqst;
+
+    case 0x01c:        /* DISPC_IRQENABLE */
+        return s->dispc.irqen;
+
+    case 0x040:        /* DISPC_CONTROL */
+        return s->dispc.control;
+
+    case 0x044:        /* DISPC_CONFIG */
+        return s->dispc.config;
+
+    case 0x048:        /* DISPC_CAPABLE */
+        return s->dispc.capable;
+
+    case 0x04c:        /* DISPC_DEFAULT_COLOR0 */
+        return s->dispc.bg[0];
+    case 0x050:        /* DISPC_DEFAULT_COLOR1 */
+        return s->dispc.bg[1];
+    case 0x054:        /* DISPC_TRANS_COLOR0 */
+        return s->dispc.trans[0];
+    case 0x058:        /* DISPC_TRANS_COLOR1 */
+        return s->dispc.trans[1];
+
+    case 0x05c:        /* DISPC_LINE_STATUS */
+        return 0x7ff;
+    case 0x060:        /* DISPC_LINE_NUMBER */
+        return s->dispc.line;
+
+    case 0x064:        /* DISPC_TIMING_H */
+        return s->dispc.timing[0];
+    case 0x068:        /* DISPC_TIMING_V */
+        return s->dispc.timing[1];
+    case 0x06c:        /* DISPC_POL_FREQ */
+        return s->dispc.timing[2];
+    case 0x070:        /* DISPC_DIVISOR */
+        return s->dispc.timing[3];
+
+    case 0x078:        /* DISPC_SIZE_DIG */
+        return ((s->dig.ny - 1) << 16) | (s->dig.nx - 1);
+    case 0x07c:        /* DISPC_SIZE_LCD */
+        return ((s->lcd.ny - 1) << 16) | (s->lcd.nx - 1);
+
+    case 0x080:        /* DISPC_GFX_BA0 */
+        return s->dispc.l[0].addr[0];
+    case 0x084:        /* DISPC_GFX_BA1 */
+        return s->dispc.l[0].addr[1];
+    case 0x088:        /* DISPC_GFX_POSITION */
+        return (s->dispc.l[0].posy << 16) | s->dispc.l[0].posx;
+    case 0x08c:        /* DISPC_GFX_SIZE */
+        return ((s->dispc.l[0].ny - 1) << 16) | (s->dispc.l[0].nx - 1);
+    case 0x0a0:        /* DISPC_GFX_ATTRIBUTES */
+        return s->dispc.l[0].attr;
+    case 0x0a4:        /* DISPC_GFX_FIFO_TRESHOLD */
+        return s->dispc.l[0].tresh;
+    case 0x0a8:        /* DISPC_GFX_FIFO_SIZE_STATUS */
+        return 256;
+    case 0x0ac:        /* DISPC_GFX_ROW_INC */
+        return s->dispc.l[0].rowinc;
+    case 0x0b0:        /* DISPC_GFX_PIXEL_INC */
+        return s->dispc.l[0].colinc;
+    case 0x0b4:        /* DISPC_GFX_WINDOW_SKIP */
+        return s->dispc.l[0].wininc;
+    case 0x0b8:        /* DISPC_GFX_TABLE_BA */
+        return s->dispc.l[0].addr[2];
+
+    case 0x0bc:        /* DISPC_VID1_BA0 */
+    case 0x0c0:        /* DISPC_VID1_BA1 */
+    case 0x0c4:        /* DISPC_VID1_POSITION */
+    case 0x0c8:        /* DISPC_VID1_SIZE */
+    case 0x0cc:        /* DISPC_VID1_ATTRIBUTES */
+    case 0x0d0:        /* DISPC_VID1_FIFO_TRESHOLD */
+    case 0x0d4:        /* DISPC_VID1_FIFO_SIZE_STATUS */
+    case 0x0d8:        /* DISPC_VID1_ROW_INC */
+    case 0x0dc:        /* DISPC_VID1_PIXEL_INC */
+    case 0x0e0:        /* DISPC_VID1_FIR */
+    case 0x0e4:        /* DISPC_VID1_PICTURE_SIZE */
+    case 0x0e8:        /* DISPC_VID1_ACCU0 */
+    case 0x0ec:        /* DISPC_VID1_ACCU1 */
+    case 0x0f0 ... 0x140:      /* DISPC_VID1_FIR_COEF, DISPC_VID1_CONV_COEF */
+    case 0x14c:        /* DISPC_VID2_BA0 */
+    case 0x150:        /* DISPC_VID2_BA1 */
+    case 0x154:        /* DISPC_VID2_POSITION */
+    case 0x158:        /* DISPC_VID2_SIZE */
+    case 0x15c:        /* DISPC_VID2_ATTRIBUTES */
+    case 0x160:        /* DISPC_VID2_FIFO_TRESHOLD */
+    case 0x164:        /* DISPC_VID2_FIFO_SIZE_STATUS */
+    case 0x168:        /* DISPC_VID2_ROW_INC */
+    case 0x16c:        /* DISPC_VID2_PIXEL_INC */
+    case 0x170:        /* DISPC_VID2_FIR */
+    case 0x174:        /* DISPC_VID2_PICTURE_SIZE */
+    case 0x178:        /* DISPC_VID2_ACCU0 */
+    case 0x17c:        /* DISPC_VID2_ACCU1 */
+    case 0x180 ... 0x1d0:      /* DISPC_VID2_FIR_COEF, DISPC_VID2_CONV_COEF */
+    case 0x1d4:        /* DISPC_DATA_CYCLE1 */
+    case 0x1d8:        /* DISPC_DATA_CYCLE2 */
+    case 0x1dc:        /* DISPC_DATA_CYCLE3 */
+        return 0;
+
+    default:
+        break;
+    }
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_disc_write(void *opaque, hwaddr addr,
+                            uint64_t value, unsigned size)
+{
+    struct omap_dss_s *s = (struct omap_dss_s *) opaque;
+
+    if (size != 4) {
+        return omap_badwidth_write32(opaque, addr, value);
+    }
+
+    switch (addr) {
+    case 0x010:        /* DISPC_SYSCONFIG */
+        if (value & 2)                                         /* SOFTRESET */
+            omap_dss_reset(s);
+        s->dispc.idlemode = value & 0x301b;
+        break;
+
+    case 0x018:        /* DISPC_IRQSTATUS */
+        s->dispc.irqst &= ~value;
+        omap_dispc_interrupt_update(s);
+        break;
+
+    case 0x01c:        /* DISPC_IRQENABLE */
+        s->dispc.irqen = value & 0xffff;
+        omap_dispc_interrupt_update(s);
+        break;
+
+    case 0x040:        /* DISPC_CONTROL */
+        s->dispc.control = value & 0x07ff9fff;
+        s->dig.enable = (value >> 1) & 1;
+        s->lcd.enable = (value >> 0) & 1;
+        if (value & (1 << 12))                 /* OVERLAY_OPTIMIZATION */
+            if (!((s->dispc.l[1].attr | s->dispc.l[2].attr) & 1)) {
+                fprintf(stderr, "%s: Overlay Optimization when no overlay "
+                        "region effectively exists leads to "
+                        "unpredictable behaviour!\n", __func__);
+            }
+        if (value & (1 << 6)) {                                /* GODIGITAL */
+            /* XXX: Shadowed fields are:
+             * s->dispc.config
+             * s->dispc.capable
+             * s->dispc.bg[0]
+             * s->dispc.bg[1]
+             * s->dispc.trans[0]
+             * s->dispc.trans[1]
+             * s->dispc.line
+             * s->dispc.timing[0]
+             * s->dispc.timing[1]
+             * s->dispc.timing[2]
+             * s->dispc.timing[3]
+             * s->lcd.nx
+             * s->lcd.ny
+             * s->dig.nx
+             * s->dig.ny
+             * s->dispc.l[0].addr[0]
+             * s->dispc.l[0].addr[1]
+             * s->dispc.l[0].addr[2]
+             * s->dispc.l[0].posx
+             * s->dispc.l[0].posy
+             * s->dispc.l[0].nx
+             * s->dispc.l[0].ny
+             * s->dispc.l[0].tresh
+             * s->dispc.l[0].rowinc
+             * s->dispc.l[0].colinc
+             * s->dispc.l[0].wininc
+             * All they need to be loaded here from their shadow registers.
+             */
+        }
+        if (value & (1 << 5)) {                                /* GOLCD */
+             /* XXX: Likewise for LCD here.  */
+        }
+        s->dispc.invalidate = 1;
+        break;
+
+    case 0x044:        /* DISPC_CONFIG */
+        s->dispc.config = value & 0x3fff;
+        /* XXX:
+         * bits 2:1 (LOADMODE) reset to 0 after set to 1 and palette loaded
+         * bits 2:1 (LOADMODE) reset to 2 after set to 3 and palette loaded
+         */
+        s->dispc.invalidate = 1;
+        break;
+
+    case 0x048:        /* DISPC_CAPABLE */
+        s->dispc.capable = value & 0x3ff;
+        break;
+
+    case 0x04c:        /* DISPC_DEFAULT_COLOR0 */
+        s->dispc.bg[0] = value & 0xffffff;
+        s->dispc.invalidate = 1;
+        break;
+    case 0x050:        /* DISPC_DEFAULT_COLOR1 */
+        s->dispc.bg[1] = value & 0xffffff;
+        s->dispc.invalidate = 1;
+        break;
+    case 0x054:        /* DISPC_TRANS_COLOR0 */
+        s->dispc.trans[0] = value & 0xffffff;
+        s->dispc.invalidate = 1;
+        break;
+    case 0x058:        /* DISPC_TRANS_COLOR1 */
+        s->dispc.trans[1] = value & 0xffffff;
+        s->dispc.invalidate = 1;
+        break;
+
+    case 0x060:        /* DISPC_LINE_NUMBER */
+        s->dispc.line = value & 0x7ff;
+        break;
+
+    case 0x064:        /* DISPC_TIMING_H */
+        s->dispc.timing[0] = value & 0x0ff0ff3f;
+        break;
+    case 0x068:        /* DISPC_TIMING_V */
+        s->dispc.timing[1] = value & 0x0ff0ff3f;
+        break;
+    case 0x06c:        /* DISPC_POL_FREQ */
+        s->dispc.timing[2] = value & 0x0003ffff;
+        break;
+    case 0x070:        /* DISPC_DIVISOR */
+        s->dispc.timing[3] = value & 0x00ff00ff;
+        break;
+
+    case 0x078:        /* DISPC_SIZE_DIG */
+        s->dig.nx = ((value >>  0) & 0x7ff) + 1;               /* PPL */
+        s->dig.ny = ((value >> 16) & 0x7ff) + 1;               /* LPP */
+        s->dispc.invalidate = 1;
+        break;
+    case 0x07c:        /* DISPC_SIZE_LCD */
+        s->lcd.nx = ((value >>  0) & 0x7ff) + 1;               /* PPL */
+        s->lcd.ny = ((value >> 16) & 0x7ff) + 1;               /* LPP */
+        s->dispc.invalidate = 1;
+        break;
+    case 0x080:        /* DISPC_GFX_BA0 */
+        s->dispc.l[0].addr[0] = (hwaddr) value;
+        s->dispc.invalidate = 1;
+        break;
+    case 0x084:        /* DISPC_GFX_BA1 */
+        s->dispc.l[0].addr[1] = (hwaddr) value;
+        s->dispc.invalidate = 1;
+        break;
+    case 0x088:        /* DISPC_GFX_POSITION */
+        s->dispc.l[0].posx = ((value >>  0) & 0x7ff);          /* GFXPOSX */
+        s->dispc.l[0].posy = ((value >> 16) & 0x7ff);          /* GFXPOSY */
+        s->dispc.invalidate = 1;
+        break;
+    case 0x08c:        /* DISPC_GFX_SIZE */
+        s->dispc.l[0].nx = ((value >>  0) & 0x7ff) + 1;                /* GFXSIZEX */
+        s->dispc.l[0].ny = ((value >> 16) & 0x7ff) + 1;                /* GFXSIZEY */
+        s->dispc.invalidate = 1;
+        break;
+    case 0x0a0:        /* DISPC_GFX_ATTRIBUTES */
+        s->dispc.l[0].attr = value & 0x7ff;
+        if (value & (3 << 9))
+            fprintf(stderr, "%s: Big-endian pixel format not supported\n",
+                            __FUNCTION__);
+        s->dispc.l[0].enable = value & 1;
+        s->dispc.l[0].bpp = (value >> 1) & 0xf;
+        s->dispc.invalidate = 1;
+        break;
+    case 0x0a4:        /* DISPC_GFX_FIFO_TRESHOLD */
+        s->dispc.l[0].tresh = value & 0x01ff01ff;
+        break;
+    case 0x0ac:        /* DISPC_GFX_ROW_INC */
+        s->dispc.l[0].rowinc = value;
+        s->dispc.invalidate = 1;
+        break;
+    case 0x0b0:        /* DISPC_GFX_PIXEL_INC */
+        s->dispc.l[0].colinc = value;
+        s->dispc.invalidate = 1;
+        break;
+    case 0x0b4:        /* DISPC_GFX_WINDOW_SKIP */
+        s->dispc.l[0].wininc = value;
+        break;
+    case 0x0b8:        /* DISPC_GFX_TABLE_BA */
+        s->dispc.l[0].addr[2] = (hwaddr) value;
+        s->dispc.invalidate = 1;
+        break;
+
+    case 0x0bc:        /* DISPC_VID1_BA0 */
+    case 0x0c0:        /* DISPC_VID1_BA1 */
+    case 0x0c4:        /* DISPC_VID1_POSITION */
+    case 0x0c8:        /* DISPC_VID1_SIZE */
+    case 0x0cc:        /* DISPC_VID1_ATTRIBUTES */
+    case 0x0d0:        /* DISPC_VID1_FIFO_TRESHOLD */
+    case 0x0d8:        /* DISPC_VID1_ROW_INC */
+    case 0x0dc:        /* DISPC_VID1_PIXEL_INC */
+    case 0x0e0:        /* DISPC_VID1_FIR */
+    case 0x0e4:        /* DISPC_VID1_PICTURE_SIZE */
+    case 0x0e8:        /* DISPC_VID1_ACCU0 */
+    case 0x0ec:        /* DISPC_VID1_ACCU1 */
+    case 0x0f0 ... 0x140:      /* DISPC_VID1_FIR_COEF, DISPC_VID1_CONV_COEF */
+    case 0x14c:        /* DISPC_VID2_BA0 */
+    case 0x150:        /* DISPC_VID2_BA1 */
+    case 0x154:        /* DISPC_VID2_POSITION */
+    case 0x158:        /* DISPC_VID2_SIZE */
+    case 0x15c:        /* DISPC_VID2_ATTRIBUTES */
+    case 0x160:        /* DISPC_VID2_FIFO_TRESHOLD */
+    case 0x168:        /* DISPC_VID2_ROW_INC */
+    case 0x16c:        /* DISPC_VID2_PIXEL_INC */
+    case 0x170:        /* DISPC_VID2_FIR */
+    case 0x174:        /* DISPC_VID2_PICTURE_SIZE */
+    case 0x178:        /* DISPC_VID2_ACCU0 */
+    case 0x17c:        /* DISPC_VID2_ACCU1 */
+    case 0x180 ... 0x1d0:      /* DISPC_VID2_FIR_COEF, DISPC_VID2_CONV_COEF */
+    case 0x1d4:        /* DISPC_DATA_CYCLE1 */
+    case 0x1d8:        /* DISPC_DATA_CYCLE2 */
+    case 0x1dc:        /* DISPC_DATA_CYCLE3 */
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+    }
+}
+
+static const MemoryRegionOps omap_disc_ops = {
+    .read = omap_disc_read,
+    .write = omap_disc_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void omap_rfbi_transfer_stop(struct omap_dss_s *s)
+{
+    if (!s->rfbi.busy)
+        return;
+
+    /* TODO: in non-Bypass mode we probably need to just deassert the DRQ.  */
+
+    s->rfbi.busy = 0;
+}
+
+static void omap_rfbi_transfer_start(struct omap_dss_s *s)
+{
+    void *data;
+    hwaddr len;
+    hwaddr data_addr;
+    int pitch;
+    static void *bounce_buffer;
+    static hwaddr bounce_len;
+
+    if (!s->rfbi.enable || s->rfbi.busy)
+        return;
+
+    if (s->rfbi.control & (1 << 1)) {                          /* BYPASS */
+        /* TODO: in non-Bypass mode we probably need to just assert the
+         * DRQ and wait for DMA to write the pixels.  */
+        fprintf(stderr, "%s: Bypass mode unimplemented\n", __FUNCTION__);
+        return;
+    }
+
+    if (!(s->dispc.control & (1 << 11)))                       /* RFBIMODE */
+        return;
+    /* TODO: check that LCD output is enabled in DISPC.  */
+
+    s->rfbi.busy = 1;
+
+    len = s->rfbi.pixels * 2;
+
+    data_addr = s->dispc.l[0].addr[0];
+    data = cpu_physical_memory_map(data_addr, &len, 0);
+    if (data && len != s->rfbi.pixels * 2) {
+        cpu_physical_memory_unmap(data, len, 0, 0);
+        data = NULL;
+        len = s->rfbi.pixels * 2;
+    }
+    if (!data) {
+        if (len > bounce_len) {
+            bounce_buffer = g_realloc(bounce_buffer, len);
+        }
+        data = bounce_buffer;
+        cpu_physical_memory_read(data_addr, data, len);
+    }
+
+    /* TODO bpp */
+    s->rfbi.pixels = 0;
+
+    /* TODO: negative values */
+    pitch = s->dispc.l[0].nx + (s->dispc.l[0].rowinc - 1) / 2;
+
+    if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0])
+        s->rfbi.chip[0]->block(s->rfbi.chip[0]->opaque, 1, data, len, pitch);
+    if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1])
+        s->rfbi.chip[1]->block(s->rfbi.chip[1]->opaque, 1, data, len, pitch);
+
+    if (data != bounce_buffer) {
+        cpu_physical_memory_unmap(data, len, 0, len);
+    }
+
+    omap_rfbi_transfer_stop(s);
+
+    /* TODO */
+    s->dispc.irqst |= 1;                                       /* FRAMEDONE */
+    omap_dispc_interrupt_update(s);
+}
+
+static uint64_t omap_rfbi_read(void *opaque, hwaddr addr,
+                               unsigned size)
+{
+    struct omap_dss_s *s = (struct omap_dss_s *) opaque;
+
+    if (size != 4) {
+        return omap_badwidth_read32(opaque, addr);
+    }
+
+    switch (addr) {
+    case 0x00: /* RFBI_REVISION */
+        return 0x10;
+
+    case 0x10: /* RFBI_SYSCONFIG */
+        return s->rfbi.idlemode;
+
+    case 0x14: /* RFBI_SYSSTATUS */
+        return 1 | (s->rfbi.busy << 8);                                /* RESETDONE */
+
+    case 0x40: /* RFBI_CONTROL */
+        return s->rfbi.control;
+
+    case 0x44: /* RFBI_PIXELCNT */
+        return s->rfbi.pixels;
+
+    case 0x48: /* RFBI_LINE_NUMBER */
+        return s->rfbi.skiplines;
+
+    case 0x58: /* RFBI_READ */
+    case 0x5c: /* RFBI_STATUS */
+        return s->rfbi.rxbuf;
+
+    case 0x60: /* RFBI_CONFIG0 */
+        return s->rfbi.config[0];
+    case 0x64: /* RFBI_ONOFF_TIME0 */
+        return s->rfbi.time[0];
+    case 0x68: /* RFBI_CYCLE_TIME0 */
+        return s->rfbi.time[1];
+    case 0x6c: /* RFBI_DATA_CYCLE1_0 */
+        return s->rfbi.data[0];
+    case 0x70: /* RFBI_DATA_CYCLE2_0 */
+        return s->rfbi.data[1];
+    case 0x74: /* RFBI_DATA_CYCLE3_0 */
+        return s->rfbi.data[2];
+
+    case 0x78: /* RFBI_CONFIG1 */
+        return s->rfbi.config[1];
+    case 0x7c: /* RFBI_ONOFF_TIME1 */
+        return s->rfbi.time[2];
+    case 0x80: /* RFBI_CYCLE_TIME1 */
+        return s->rfbi.time[3];
+    case 0x84: /* RFBI_DATA_CYCLE1_1 */
+        return s->rfbi.data[3];
+    case 0x88: /* RFBI_DATA_CYCLE2_1 */
+        return s->rfbi.data[4];
+    case 0x8c: /* RFBI_DATA_CYCLE3_1 */
+        return s->rfbi.data[5];
+
+    case 0x90: /* RFBI_VSYNC_WIDTH */
+        return s->rfbi.vsync;
+    case 0x94: /* RFBI_HSYNC_WIDTH */
+        return s->rfbi.hsync;
+    }
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_rfbi_write(void *opaque, hwaddr addr,
+                            uint64_t value, unsigned size)
+{
+    struct omap_dss_s *s = (struct omap_dss_s *) opaque;
+
+    if (size != 4) {
+        return omap_badwidth_write32(opaque, addr, value);
+    }
+
+    switch (addr) {
+    case 0x10: /* RFBI_SYSCONFIG */
+        if (value & 2)                                         /* SOFTRESET */
+            omap_rfbi_reset(s);
+        s->rfbi.idlemode = value & 0x19;
+        break;
+
+    case 0x40: /* RFBI_CONTROL */
+        s->rfbi.control = value & 0xf;
+        s->rfbi.enable = value & 1;
+        if (value & (1 << 4) &&                                        /* ITE */
+                        !(s->rfbi.config[0] & s->rfbi.config[1] & 0xc))
+            omap_rfbi_transfer_start(s);
+        break;
+
+    case 0x44: /* RFBI_PIXELCNT */
+        s->rfbi.pixels = value;
+        break;
+
+    case 0x48: /* RFBI_LINE_NUMBER */
+        s->rfbi.skiplines = value & 0x7ff;
+        break;
+
+    case 0x4c: /* RFBI_CMD */
+        if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0])
+            s->rfbi.chip[0]->write(s->rfbi.chip[0]->opaque, 0, value & 0xffff);
+        if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1])
+            s->rfbi.chip[1]->write(s->rfbi.chip[1]->opaque, 0, value & 0xffff);
+        break;
+    case 0x50: /* RFBI_PARAM */
+        if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0])
+            s->rfbi.chip[0]->write(s->rfbi.chip[0]->opaque, 1, value & 0xffff);
+        if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1])
+            s->rfbi.chip[1]->write(s->rfbi.chip[1]->opaque, 1, value & 0xffff);
+        break;
+    case 0x54: /* RFBI_DATA */
+        /* TODO: take into account the format set up in s->rfbi.config[?] and
+         * s->rfbi.data[?], but special-case the most usual scenario so that
+         * speed doesn't suffer.  */
+        if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0]) {
+            s->rfbi.chip[0]->write(s->rfbi.chip[0]->opaque, 1, value & 0xffff);
+            s->rfbi.chip[0]->write(s->rfbi.chip[0]->opaque, 1, value >> 16);
+        }
+        if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1]) {
+            s->rfbi.chip[1]->write(s->rfbi.chip[1]->opaque, 1, value & 0xffff);
+            s->rfbi.chip[1]->write(s->rfbi.chip[1]->opaque, 1, value >> 16);
+        }
+        if (!-- s->rfbi.pixels)
+            omap_rfbi_transfer_stop(s);
+        break;
+    case 0x58: /* RFBI_READ */
+        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[1]->read(s->rfbi.chip[1]->opaque, 1);
+        if (!-- s->rfbi.pixels)
+            omap_rfbi_transfer_stop(s);
+        break;
+
+    case 0x5c: /* RFBI_STATUS */
+        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[1]->read(s->rfbi.chip[1]->opaque, 0);
+        if (!-- s->rfbi.pixels)
+            omap_rfbi_transfer_stop(s);
+        break;
+
+    case 0x60: /* RFBI_CONFIG0 */
+        s->rfbi.config[0] = value & 0x003f1fff;
+        break;
+
+    case 0x64: /* RFBI_ONOFF_TIME0 */
+        s->rfbi.time[0] = value & 0x3fffffff;
+        break;
+    case 0x68: /* RFBI_CYCLE_TIME0 */
+        s->rfbi.time[1] = value & 0x0fffffff;
+        break;
+    case 0x6c: /* RFBI_DATA_CYCLE1_0 */
+        s->rfbi.data[0] = value & 0x0f1f0f1f;
+        break;
+    case 0x70: /* RFBI_DATA_CYCLE2_0 */
+        s->rfbi.data[1] = value & 0x0f1f0f1f;
+        break;
+    case 0x74: /* RFBI_DATA_CYCLE3_0 */
+        s->rfbi.data[2] = value & 0x0f1f0f1f;
+        break;
+    case 0x78: /* RFBI_CONFIG1 */
+        s->rfbi.config[1] = value & 0x003f1fff;
+        break;
+
+    case 0x7c: /* RFBI_ONOFF_TIME1 */
+        s->rfbi.time[2] = value & 0x3fffffff;
+        break;
+    case 0x80: /* RFBI_CYCLE_TIME1 */
+        s->rfbi.time[3] = value & 0x0fffffff;
+        break;
+    case 0x84: /* RFBI_DATA_CYCLE1_1 */
+        s->rfbi.data[3] = value & 0x0f1f0f1f;
+        break;
+    case 0x88: /* RFBI_DATA_CYCLE2_1 */
+        s->rfbi.data[4] = value & 0x0f1f0f1f;
+        break;
+    case 0x8c: /* RFBI_DATA_CYCLE3_1 */
+        s->rfbi.data[5] = value & 0x0f1f0f1f;
+        break;
+
+    case 0x90: /* RFBI_VSYNC_WIDTH */
+        s->rfbi.vsync = value & 0xffff;
+        break;
+    case 0x94: /* RFBI_HSYNC_WIDTH */
+        s->rfbi.hsync = value & 0xffff;
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+    }
+}
+
+static const MemoryRegionOps omap_rfbi_ops = {
+    .read = omap_rfbi_read,
+    .write = omap_rfbi_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static uint64_t omap_venc_read(void *opaque, hwaddr addr,
+                               unsigned size)
+{
+    if (size != 4) {
+        return omap_badwidth_read32(opaque, addr);
+    }
+
+    switch (addr) {
+    case 0x00: /* REV_ID */
+    case 0x04: /* STATUS */
+    case 0x08: /* F_CONTROL */
+    case 0x10: /* VIDOUT_CTRL */
+    case 0x14: /* SYNC_CTRL */
+    case 0x1c: /* LLEN */
+    case 0x20: /* FLENS */
+    case 0x24: /* HFLTR_CTRL */
+    case 0x28: /* CC_CARR_WSS_CARR */
+    case 0x2c: /* C_PHASE */
+    case 0x30: /* GAIN_U */
+    case 0x34: /* GAIN_V */
+    case 0x38: /* GAIN_Y */
+    case 0x3c: /* BLACK_LEVEL */
+    case 0x40: /* BLANK_LEVEL */
+    case 0x44: /* X_COLOR */
+    case 0x48: /* M_CONTROL */
+    case 0x4c: /* BSTAMP_WSS_DATA */
+    case 0x50: /* S_CARR */
+    case 0x54: /* LINE21 */
+    case 0x58: /* LN_SEL */
+    case 0x5c: /* L21__WC_CTL */
+    case 0x60: /* HTRIGGER_VTRIGGER */
+    case 0x64: /* SAVID__EAVID */
+    case 0x68: /* FLEN__FAL */
+    case 0x6c: /* LAL__PHASE_RESET */
+    case 0x70: /* HS_INT_START_STOP_X */
+    case 0x74: /* HS_EXT_START_STOP_X */
+    case 0x78: /* VS_INT_START_X */
+    case 0x7c: /* VS_INT_STOP_X__VS_INT_START_Y */
+    case 0x80: /* VS_INT_STOP_Y__VS_INT_START_X */
+    case 0x84: /* VS_EXT_STOP_X__VS_EXT_START_Y */
+    case 0x88: /* VS_EXT_STOP_Y */
+    case 0x90: /* AVID_START_STOP_X */
+    case 0x94: /* AVID_START_STOP_Y */
+    case 0xa0: /* FID_INT_START_X__FID_INT_START_Y */
+    case 0xa4: /* FID_INT_OFFSET_Y__FID_EXT_START_X */
+    case 0xa8: /* FID_EXT_START_Y__FID_EXT_OFFSET_Y */
+    case 0xb0: /* TVDETGP_INT_START_STOP_X */
+    case 0xb4: /* TVDETGP_INT_START_STOP_Y */
+    case 0xb8: /* GEN_CTRL */
+    case 0xc4: /* DAC_TST__DAC_A */
+    case 0xc8: /* DAC_B__DAC_C */
+        return 0;
+
+    default:
+        break;
+    }
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_venc_write(void *opaque, hwaddr addr,
+                            uint64_t value, unsigned size)
+{
+    if (size != 4) {
+        return omap_badwidth_write32(opaque, addr, size);
+    }
+
+    switch (addr) {
+    case 0x08: /* F_CONTROL */
+    case 0x10: /* VIDOUT_CTRL */
+    case 0x14: /* SYNC_CTRL */
+    case 0x1c: /* LLEN */
+    case 0x20: /* FLENS */
+    case 0x24: /* HFLTR_CTRL */
+    case 0x28: /* CC_CARR_WSS_CARR */
+    case 0x2c: /* C_PHASE */
+    case 0x30: /* GAIN_U */
+    case 0x34: /* GAIN_V */
+    case 0x38: /* GAIN_Y */
+    case 0x3c: /* BLACK_LEVEL */
+    case 0x40: /* BLANK_LEVEL */
+    case 0x44: /* X_COLOR */
+    case 0x48: /* M_CONTROL */
+    case 0x4c: /* BSTAMP_WSS_DATA */
+    case 0x50: /* S_CARR */
+    case 0x54: /* LINE21 */
+    case 0x58: /* LN_SEL */
+    case 0x5c: /* L21__WC_CTL */
+    case 0x60: /* HTRIGGER_VTRIGGER */
+    case 0x64: /* SAVID__EAVID */
+    case 0x68: /* FLEN__FAL */
+    case 0x6c: /* LAL__PHASE_RESET */
+    case 0x70: /* HS_INT_START_STOP_X */
+    case 0x74: /* HS_EXT_START_STOP_X */
+    case 0x78: /* VS_INT_START_X */
+    case 0x7c: /* VS_INT_STOP_X__VS_INT_START_Y */
+    case 0x80: /* VS_INT_STOP_Y__VS_INT_START_X */
+    case 0x84: /* VS_EXT_STOP_X__VS_EXT_START_Y */
+    case 0x88: /* VS_EXT_STOP_Y */
+    case 0x90: /* AVID_START_STOP_X */
+    case 0x94: /* AVID_START_STOP_Y */
+    case 0xa0: /* FID_INT_START_X__FID_INT_START_Y */
+    case 0xa4: /* FID_INT_OFFSET_Y__FID_EXT_START_X */
+    case 0xa8: /* FID_EXT_START_Y__FID_EXT_OFFSET_Y */
+    case 0xb0: /* TVDETGP_INT_START_STOP_X */
+    case 0xb4: /* TVDETGP_INT_START_STOP_Y */
+    case 0xb8: /* GEN_CTRL */
+    case 0xc4: /* DAC_TST__DAC_A */
+    case 0xc8: /* DAC_B__DAC_C */
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+    }
+}
+
+static const MemoryRegionOps omap_venc_ops = {
+    .read = omap_venc_read,
+    .write = omap_venc_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static uint64_t omap_im3_read(void *opaque, hwaddr addr,
+                              unsigned size)
+{
+    if (size != 4) {
+        return omap_badwidth_read32(opaque, addr);
+    }
+
+    switch (addr) {
+    case 0x0a8:        /* SBIMERRLOGA */
+    case 0x0b0:        /* SBIMERRLOG */
+    case 0x190:        /* SBIMSTATE */
+    case 0x198:        /* SBTMSTATE_L */
+    case 0x19c:        /* SBTMSTATE_H */
+    case 0x1a8:        /* SBIMCONFIG_L */
+    case 0x1ac:        /* SBIMCONFIG_H */
+    case 0x1f8:        /* SBID_L */
+    case 0x1fc:        /* SBID_H */
+        return 0;
+
+    default:
+        break;
+    }
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_im3_write(void *opaque, hwaddr addr,
+                           uint64_t value, unsigned size)
+{
+    if (size != 4) {
+        return omap_badwidth_write32(opaque, addr, value);
+    }
+
+    switch (addr) {
+    case 0x0b0:        /* SBIMERRLOG */
+    case 0x190:        /* SBIMSTATE */
+    case 0x198:        /* SBTMSTATE_L */
+    case 0x19c:        /* SBTMSTATE_H */
+    case 0x1a8:        /* SBIMCONFIG_L */
+    case 0x1ac:        /* SBIMCONFIG_H */
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+    }
+}
+
+static const MemoryRegionOps omap_im3_ops = {
+    .read = omap_im3_read,
+    .write = omap_im3_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+struct omap_dss_s *omap_dss_init(struct omap_target_agent_s *ta,
+                MemoryRegion *sysmem,
+                hwaddr l3_base,
+                qemu_irq irq, qemu_irq drq,
+                omap_clk fck1, omap_clk fck2, omap_clk ck54m,
+                omap_clk ick1, omap_clk ick2)
+{
+    struct omap_dss_s *s = (struct omap_dss_s *)
+            g_malloc0(sizeof(struct omap_dss_s));
+
+    s->irq = irq;
+    s->drq = drq;
+    omap_dss_reset(s);
+
+    memory_region_init_io(&s->iomem_diss1, &omap_diss_ops, s, "omap.diss1",
+                          omap_l4_region_size(ta, 0));
+    memory_region_init_io(&s->iomem_disc1, &omap_disc_ops, s, "omap.disc1",
+                          omap_l4_region_size(ta, 1));
+    memory_region_init_io(&s->iomem_rfbi1, &omap_rfbi_ops, s, "omap.rfbi1",
+                          omap_l4_region_size(ta, 2));
+    memory_region_init_io(&s->iomem_venc1, &omap_venc_ops, s, "omap.venc1",
+                          omap_l4_region_size(ta, 3));
+    memory_region_init_io(&s->iomem_im3, &omap_im3_ops, s,
+                          "omap.im3", 0x1000);
+
+    omap_l4_attach(ta, 0, &s->iomem_diss1);
+    omap_l4_attach(ta, 1, &s->iomem_disc1);
+    omap_l4_attach(ta, 2, &s->iomem_rfbi1);
+    omap_l4_attach(ta, 3, &s->iomem_venc1);
+    memory_region_add_subregion(sysmem, l3_base, &s->iomem_im3);
+
+#if 0
+    s->state = graphic_console_init(omap_update_display,
+                                    omap_invalidate_display, omap_screen_dump, s);
+#endif
+
+    return s;
+}
+
+void omap_rfbi_attach(struct omap_dss_s *s, int cs, struct rfbi_chip_s *chip)
+{
+    if (cs < 0 || cs > 1)
+        hw_error("%s: wrong CS %i\n", __FUNCTION__, cs);
+    s->rfbi.chip[cs] = chip;
+}
diff --git a/hw/display/omap_lcd_template.h b/hw/display/omap_lcd_template.h
new file mode 100644 (file)
index 0000000..2fb96f8
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * QEMU OMAP LCD Emulator templates
+ *
+ * Copyright (c) 2006 Andrzej Zaborowski  <balrog@zabor.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if DEPTH == 8
+# define BPP 1
+# define PIXEL_TYPE uint8_t
+#elif DEPTH == 15 || DEPTH == 16
+# define BPP 2
+# define PIXEL_TYPE uint16_t
+#elif DEPTH == 32
+# define BPP 4
+# define PIXEL_TYPE uint32_t
+#else
+# error unsupport depth
+#endif
+
+/*
+ * 2-bit colour
+ */
+static void glue(draw_line2_, DEPTH)(void *opaque,
+                uint8_t *d, const uint8_t *s, int width, int deststep)
+{
+    uint16_t *pal = opaque;
+    uint8_t v, r, g, b;
+
+    do {
+        v = ldub_raw((void *) s);
+        r = (pal[v & 3] >> 4) & 0xf0;
+        g = pal[v & 3] & 0xf0;
+        b = (pal[v & 3] << 4) & 0xf0;
+        ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
+        d += BPP;
+        v >>= 2;
+        r = (pal[v & 3] >> 4) & 0xf0;
+        g = pal[v & 3] & 0xf0;
+        b = (pal[v & 3] << 4) & 0xf0;
+        ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
+        d += BPP;
+        v >>= 2;
+        r = (pal[v & 3] >> 4) & 0xf0;
+        g = pal[v & 3] & 0xf0;
+        b = (pal[v & 3] << 4) & 0xf0;
+        ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
+        d += BPP;
+        v >>= 2;
+        r = (pal[v & 3] >> 4) & 0xf0;
+        g = pal[v & 3] & 0xf0;
+        b = (pal[v & 3] << 4) & 0xf0;
+        ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
+        d += BPP;
+        s ++;
+        width -= 4;
+    } while (width > 0);
+}
+
+/*
+ * 4-bit colour
+ */
+static void glue(draw_line4_, DEPTH)(void *opaque,
+                uint8_t *d, const uint8_t *s, int width, int deststep)
+{
+    uint16_t *pal = opaque;
+    uint8_t v, r, g, b;
+
+    do {
+        v = ldub_raw((void *) s);
+        r = (pal[v & 0xf] >> 4) & 0xf0;
+        g = pal[v & 0xf] & 0xf0;
+        b = (pal[v & 0xf] << 4) & 0xf0;
+        ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
+        d += BPP;
+        v >>= 4;
+        r = (pal[v & 0xf] >> 4) & 0xf0;
+        g = pal[v & 0xf] & 0xf0;
+        b = (pal[v & 0xf] << 4) & 0xf0;
+        ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
+        d += BPP;
+        s ++;
+        width -= 2;
+    } while (width > 0);
+}
+
+/*
+ * 8-bit colour
+ */
+static void glue(draw_line8_, DEPTH)(void *opaque,
+                uint8_t *d, const uint8_t *s, int width, int deststep)
+{
+    uint16_t *pal = opaque;
+    uint8_t v, r, g, b;
+
+    do {
+        v = ldub_raw((void *) s);
+        r = (pal[v] >> 4) & 0xf0;
+        g = pal[v] & 0xf0;
+        b = (pal[v] << 4) & 0xf0;
+        ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
+        s ++;
+        d += BPP;
+    } while (-- width != 0);
+}
+
+/*
+ * 12-bit colour
+ */
+static void glue(draw_line12_, DEPTH)(void *opaque,
+                uint8_t *d, const uint8_t *s, int width, int deststep)
+{
+    uint16_t v;
+    uint8_t r, g, b;
+
+    do {
+        v = lduw_raw((void *) s);
+        r = (v >> 4) & 0xf0;
+        g = v & 0xf0;
+        b = (v << 4) & 0xf0;
+        ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
+        s += 2;
+        d += BPP;
+    } while (-- width != 0);
+}
+
+/*
+ * 16-bit colour
+ */
+static void glue(draw_line16_, DEPTH)(void *opaque,
+                uint8_t *d, const uint8_t *s, int width, int deststep)
+{
+#if DEPTH == 16 && defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
+    memcpy(d, s, width * 2);
+#else
+    uint16_t v;
+    uint8_t r, g, b;
+
+    do {
+        v = lduw_raw((void *) s);
+        r = (v >> 8) & 0xf8;
+        g = (v >> 3) & 0xfc;
+        b = (v << 3) & 0xf8;
+        ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
+        s += 2;
+        d += BPP;
+    } while (-- width != 0);
+#endif
+}
+
+#undef DEPTH
+#undef BPP
+#undef PIXEL_TYPE
diff --git a/hw/display/omap_lcdc.c b/hw/display/omap_lcdc.c
new file mode 100644 (file)
index 0000000..be7e9c0
--- /dev/null
@@ -0,0 +1,493 @@
+/*
+ * OMAP LCD controller.
+ *
+ * Copyright (C) 2006-2007 Andrzej Zaborowski  <balrog@zabor.org>
+ *
+ * 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 "hw/hw.h"
+#include "ui/console.h"
+#include "hw/arm/omap.h"
+#include "framebuffer.h"
+#include "ui/pixel_ops.h"
+
+struct omap_lcd_panel_s {
+    MemoryRegion *sysmem;
+    MemoryRegion iomem;
+    qemu_irq irq;
+    QemuConsole *con;
+
+    int plm;
+    int tft;
+    int mono;
+    int enable;
+    int width;
+    int height;
+    int interrupts;
+    uint32_t timing[3];
+    uint32_t subpanel;
+    uint32_t ctrl;
+
+    struct omap_dma_lcd_channel_s *dma;
+    uint16_t palette[256];
+    int palette_done;
+    int frame_done;
+    int invalidate;
+    int sync_error;
+};
+
+static void omap_lcd_interrupts(struct omap_lcd_panel_s *s)
+{
+    if (s->frame_done && (s->interrupts & 1)) {
+        qemu_irq_raise(s->irq);
+        return;
+    }
+
+    if (s->palette_done && (s->interrupts & 2)) {
+        qemu_irq_raise(s->irq);
+        return;
+    }
+
+    if (s->sync_error) {
+        qemu_irq_raise(s->irq);
+        return;
+    }
+
+    qemu_irq_lower(s->irq);
+}
+
+#define draw_line_func drawfn
+
+#define DEPTH 8
+#include "omap_lcd_template.h"
+#define DEPTH 15
+#include "omap_lcd_template.h"
+#define DEPTH 16
+#include "omap_lcd_template.h"
+#define DEPTH 32
+#include "omap_lcd_template.h"
+
+static draw_line_func draw_line_table2[33] = {
+    [0 ... 32] = NULL,
+    [8]                = draw_line2_8,
+    [15]       = draw_line2_15,
+    [16]       = draw_line2_16,
+    [32]       = draw_line2_32,
+}, draw_line_table4[33] = {
+    [0 ... 32] = NULL,
+    [8]                = draw_line4_8,
+    [15]       = draw_line4_15,
+    [16]       = draw_line4_16,
+    [32]       = draw_line4_32,
+}, draw_line_table8[33] = {
+    [0 ... 32] = NULL,
+    [8]                = draw_line8_8,
+    [15]       = draw_line8_15,
+    [16]       = draw_line8_16,
+    [32]       = draw_line8_32,
+}, draw_line_table12[33] = {
+    [0 ... 32] = NULL,
+    [8]                = draw_line12_8,
+    [15]       = draw_line12_15,
+    [16]       = draw_line12_16,
+    [32]       = draw_line12_32,
+}, draw_line_table16[33] = {
+    [0 ... 32] = NULL,
+    [8]                = draw_line16_8,
+    [15]       = draw_line16_15,
+    [16]       = draw_line16_16,
+    [32]       = draw_line16_32,
+};
+
+static void omap_update_display(void *opaque)
+{
+    struct omap_lcd_panel_s *omap_lcd = (struct omap_lcd_panel_s *) opaque;
+    DisplaySurface *surface = qemu_console_surface(omap_lcd->con);
+    draw_line_func draw_line;
+    int size, height, first, last;
+    int width, linesize, step, bpp, frame_offset;
+    hwaddr frame_base;
+
+    if (!omap_lcd || omap_lcd->plm == 1 || !omap_lcd->enable ||
+        !surface_bits_per_pixel(surface)) {
+        return;
+    }
+
+    frame_offset = 0;
+    if (omap_lcd->plm != 2) {
+        cpu_physical_memory_read(omap_lcd->dma->phys_framebuffer[
+                                  omap_lcd->dma->current_frame],
+                                 (void *)omap_lcd->palette, 0x200);
+        switch (omap_lcd->palette[0] >> 12 & 7) {
+        case 3 ... 7:
+            frame_offset += 0x200;
+            break;
+        default:
+            frame_offset += 0x20;
+        }
+    }
+
+    /* Colour depth */
+    switch ((omap_lcd->palette[0] >> 12) & 7) {
+    case 1:
+        draw_line = draw_line_table2[surface_bits_per_pixel(surface)];
+        bpp = 2;
+        break;
+
+    case 2:
+        draw_line = draw_line_table4[surface_bits_per_pixel(surface)];
+        bpp = 4;
+        break;
+
+    case 3:
+        draw_line = draw_line_table8[surface_bits_per_pixel(surface)];
+        bpp = 8;
+        break;
+
+    case 4 ... 7:
+        if (!omap_lcd->tft)
+            draw_line = draw_line_table12[surface_bits_per_pixel(surface)];
+        else
+            draw_line = draw_line_table16[surface_bits_per_pixel(surface)];
+        bpp = 16;
+        break;
+
+    default:
+        /* Unsupported at the moment.  */
+        return;
+    }
+
+    /* Resolution */
+    width = omap_lcd->width;
+    if (width != surface_width(surface) ||
+        omap_lcd->height != surface_height(surface)) {
+        qemu_console_resize(omap_lcd->con,
+                            omap_lcd->width, omap_lcd->height);
+        surface = qemu_console_surface(omap_lcd->con);
+        omap_lcd->invalidate = 1;
+    }
+
+    if (omap_lcd->dma->current_frame == 0)
+        size = omap_lcd->dma->src_f1_bottom - omap_lcd->dma->src_f1_top;
+    else
+        size = omap_lcd->dma->src_f2_bottom - omap_lcd->dma->src_f2_top;
+
+    if (frame_offset + ((width * omap_lcd->height * bpp) >> 3) > size + 2) {
+        omap_lcd->sync_error = 1;
+        omap_lcd_interrupts(omap_lcd);
+        omap_lcd->enable = 0;
+        return;
+    }
+
+    /* Content */
+    frame_base = omap_lcd->dma->phys_framebuffer[
+            omap_lcd->dma->current_frame] + frame_offset;
+    omap_lcd->dma->condition |= 1 << omap_lcd->dma->current_frame;
+    if (omap_lcd->dma->interrupts & 1)
+        qemu_irq_raise(omap_lcd->dma->irq);
+    if (omap_lcd->dma->dual)
+        omap_lcd->dma->current_frame ^= 1;
+
+    if (!surface_bits_per_pixel(surface)) {
+        return;
+    }
+
+    first = 0;
+    height = omap_lcd->height;
+    if (omap_lcd->subpanel & (1 << 31)) {
+        if (omap_lcd->subpanel & (1 << 29))
+            first = (omap_lcd->subpanel >> 16) & 0x3ff;
+        else
+            height = (omap_lcd->subpanel >> 16) & 0x3ff;
+        /* TODO: fill the rest of the panel with DPD */
+    }
+
+    step = width * bpp >> 3;
+    linesize = surface_stride(surface);
+    framebuffer_update_display(surface, omap_lcd->sysmem,
+                               frame_base, width, height,
+                               step, linesize, 0,
+                               omap_lcd->invalidate,
+                               draw_line, omap_lcd->palette,
+                               &first, &last);
+    if (first >= 0) {
+        dpy_gfx_update(omap_lcd->con, 0, first, width, last - first + 1);
+    }
+    omap_lcd->invalidate = 0;
+}
+
+static void omap_ppm_save(const char *filename, uint8_t *data,
+                    int w, int h, int linesize, Error **errp)
+{
+    FILE *f;
+    uint8_t *d, *d1;
+    unsigned int v;
+    int ret, y, x, bpp;
+
+    f = fopen(filename, "wb");
+    if (!f) {
+        error_setg(errp, "failed to open file '%s': %s", filename,
+                   strerror(errno));
+        return;
+    }
+    ret = fprintf(f, "P6\n%d %d\n%d\n", w, h, 255);
+    if (ret < 0) {
+        goto write_err;
+    }
+    d1 = data;
+    bpp = linesize / w;
+    for (y = 0; y < h; y ++) {
+        d = d1;
+        for (x = 0; x < w; x ++) {
+            v = *(uint32_t *) d;
+            switch (bpp) {
+            case 2:
+                ret = fputc((v >> 8) & 0xf8, f);
+                if (ret == EOF) {
+                    goto write_err;
+                }
+                ret = fputc((v >> 3) & 0xfc, f);
+                if (ret == EOF) {
+                    goto write_err;
+                }
+                ret = fputc((v << 3) & 0xf8, f);
+                if (ret == EOF) {
+                    goto write_err;
+                }
+                break;
+            case 3:
+            case 4:
+            default:
+                ret = fputc((v >> 16) & 0xff, f);
+                if (ret == EOF) {
+                    goto write_err;
+                }
+                ret = fputc((v >> 8) & 0xff, f);
+                if (ret == EOF) {
+                    goto write_err;
+                }
+                ret = fputc((v) & 0xff, f);
+                if (ret == EOF) {
+                    goto write_err;
+                }
+                break;
+            }
+            d += bpp;
+        }
+        d1 += linesize;
+    }
+out:
+    fclose(f);
+    return;
+
+write_err:
+    error_setg(errp, "failed to write to file '%s': %s", filename,
+               strerror(errno));
+    unlink(filename);
+    goto out;
+}
+
+static void omap_screen_dump(void *opaque, const char *filename, bool cswitch,
+                             Error **errp)
+{
+    struct omap_lcd_panel_s *omap_lcd = opaque;
+    DisplaySurface *surface = qemu_console_surface(omap_lcd->con);
+
+    omap_update_display(opaque);
+    if (omap_lcd && surface_data(surface))
+        omap_ppm_save(filename, surface_data(surface),
+                    omap_lcd->width, omap_lcd->height,
+                    surface_stride(surface), errp);
+}
+
+static void omap_invalidate_display(void *opaque) {
+    struct omap_lcd_panel_s *omap_lcd = opaque;
+    omap_lcd->invalidate = 1;
+}
+
+static void omap_lcd_update(struct omap_lcd_panel_s *s) {
+    if (!s->enable) {
+        s->dma->current_frame = -1;
+        s->sync_error = 0;
+        if (s->plm != 1)
+            s->frame_done = 1;
+        omap_lcd_interrupts(s);
+        return;
+    }
+
+    if (s->dma->current_frame == -1) {
+        s->frame_done = 0;
+        s->palette_done = 0;
+        s->dma->current_frame = 0;
+    }
+
+    if (!s->dma->mpu->port[s->dma->src].addr_valid(s->dma->mpu,
+                            s->dma->src_f1_top) ||
+                    !s->dma->mpu->port[
+                    s->dma->src].addr_valid(s->dma->mpu,
+                            s->dma->src_f1_bottom) ||
+                    (s->dma->dual &&
+                     (!s->dma->mpu->port[
+                      s->dma->src].addr_valid(s->dma->mpu,
+                              s->dma->src_f2_top) ||
+                      !s->dma->mpu->port[
+                      s->dma->src].addr_valid(s->dma->mpu,
+                              s->dma->src_f2_bottom)))) {
+        s->dma->condition |= 1 << 2;
+        if (s->dma->interrupts & (1 << 1))
+            qemu_irq_raise(s->dma->irq);
+        s->enable = 0;
+        return;
+    }
+
+    s->dma->phys_framebuffer[0] = s->dma->src_f1_top;
+    s->dma->phys_framebuffer[1] = s->dma->src_f2_top;
+
+    if (s->plm != 2 && !s->palette_done) {
+        cpu_physical_memory_read(
+            s->dma->phys_framebuffer[s->dma->current_frame],
+            (void *)s->palette, 0x200);
+        s->palette_done = 1;
+        omap_lcd_interrupts(s);
+    }
+}
+
+static uint64_t omap_lcdc_read(void *opaque, hwaddr addr,
+                               unsigned size)
+{
+    struct omap_lcd_panel_s *s = (struct omap_lcd_panel_s *) opaque;
+
+    switch (addr) {
+    case 0x00: /* LCD_CONTROL */
+        return (s->tft << 23) | (s->plm << 20) |
+                (s->tft << 7) | (s->interrupts << 3) |
+                (s->mono << 1) | s->enable | s->ctrl | 0xfe000c34;
+
+    case 0x04: /* LCD_TIMING0 */
+        return (s->timing[0] << 10) | (s->width - 1) | 0x0000000f;
+
+    case 0x08: /* LCD_TIMING1 */
+        return (s->timing[1] << 10) | (s->height - 1);
+
+    case 0x0c: /* LCD_TIMING2 */
+        return s->timing[2] | 0xfc000000;
+
+    case 0x10: /* LCD_STATUS */
+        return (s->palette_done << 6) | (s->sync_error << 2) | s->frame_done;
+
+    case 0x14: /* LCD_SUBPANEL */
+        return s->subpanel;
+
+    default:
+        break;
+    }
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_lcdc_write(void *opaque, hwaddr addr,
+                            uint64_t value, unsigned size)
+{
+    struct omap_lcd_panel_s *s = (struct omap_lcd_panel_s *) opaque;
+
+    switch (addr) {
+    case 0x00: /* LCD_CONTROL */
+        s->plm = (value >> 20) & 3;
+        s->tft = (value >> 7) & 1;
+        s->interrupts = (value >> 3) & 3;
+        s->mono = (value >> 1) & 1;
+        s->ctrl = value & 0x01cff300;
+        if (s->enable != (value & 1)) {
+            s->enable = value & 1;
+            omap_lcd_update(s);
+        }
+        break;
+
+    case 0x04: /* LCD_TIMING0 */
+        s->timing[0] = value >> 10;
+        s->width = (value & 0x3ff) + 1;
+        break;
+
+    case 0x08: /* LCD_TIMING1 */
+        s->timing[1] = value >> 10;
+        s->height = (value & 0x3ff) + 1;
+        break;
+
+    case 0x0c: /* LCD_TIMING2 */
+        s->timing[2] = value;
+        break;
+
+    case 0x10: /* LCD_STATUS */
+        break;
+
+    case 0x14: /* LCD_SUBPANEL */
+        s->subpanel = value & 0xa1ffffff;
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+    }
+}
+
+static const MemoryRegionOps omap_lcdc_ops = {
+    .read = omap_lcdc_read,
+    .write = omap_lcdc_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+void omap_lcdc_reset(struct omap_lcd_panel_s *s)
+{
+    s->dma->current_frame = -1;
+    s->plm = 0;
+    s->tft = 0;
+    s->mono = 0;
+    s->enable = 0;
+    s->width = 0;
+    s->height = 0;
+    s->interrupts = 0;
+    s->timing[0] = 0;
+    s->timing[1] = 0;
+    s->timing[2] = 0;
+    s->subpanel = 0;
+    s->palette_done = 0;
+    s->frame_done = 0;
+    s->sync_error = 0;
+    s->invalidate = 1;
+    s->subpanel = 0;
+    s->ctrl = 0;
+}
+
+struct omap_lcd_panel_s *omap_lcdc_init(MemoryRegion *sysmem,
+                                        hwaddr base,
+                                        qemu_irq irq,
+                                        struct omap_dma_lcd_channel_s *dma,
+                                        omap_clk clk)
+{
+    struct omap_lcd_panel_s *s = (struct omap_lcd_panel_s *)
+            g_malloc0(sizeof(struct omap_lcd_panel_s));
+
+    s->irq = irq;
+    s->dma = dma;
+    s->sysmem = sysmem;
+    omap_lcdc_reset(s);
+
+    memory_region_init_io(&s->iomem, &omap_lcdc_ops, s, "omap.lcdc", 0x100);
+    memory_region_add_subregion(sysmem, base, &s->iomem);
+
+    s->con = graphic_console_init(omap_update_display,
+                                  omap_invalidate_display,
+                                  omap_screen_dump, NULL, s);
+
+    return s;
+}
diff --git a/hw/display/pl110.c b/hw/display/pl110.c
new file mode 100644 (file)
index 0000000..295434e
--- /dev/null
@@ -0,0 +1,533 @@
+/*
+ * Arm PrimeCell PL110 Color LCD Controller
+ *
+ * Copyright (c) 2005-2009 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the GNU LGPL
+ */
+
+#include "hw/sysbus.h"
+#include "ui/console.h"
+#include "framebuffer.h"
+#include "ui/pixel_ops.h"
+
+#define PL110_CR_EN   0x001
+#define PL110_CR_BGR  0x100
+#define PL110_CR_BEBO 0x200
+#define PL110_CR_BEPO 0x400
+#define PL110_CR_PWR  0x800
+
+enum pl110_bppmode
+{
+    BPP_1,
+    BPP_2,
+    BPP_4,
+    BPP_8,
+    BPP_16,
+    BPP_32,
+    BPP_16_565, /* PL111 only */
+    BPP_12      /* PL111 only */
+};
+
+
+/* The Versatile/PB uses a slightly modified PL110 controller.  */
+enum pl110_version
+{
+    PL110,
+    PL110_VERSATILE,
+    PL111
+};
+
+typedef struct {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    QemuConsole *con;
+
+    int version;
+    uint32_t timing[4];
+    uint32_t cr;
+    uint32_t upbase;
+    uint32_t lpbase;
+    uint32_t int_status;
+    uint32_t int_mask;
+    int cols;
+    int rows;
+    enum pl110_bppmode bpp;
+    int invalidate;
+    uint32_t mux_ctrl;
+    uint32_t palette[256];
+    uint32_t raw_palette[128];
+    qemu_irq irq;
+} pl110_state;
+
+static int vmstate_pl110_post_load(void *opaque, int version_id);
+
+static const VMStateDescription vmstate_pl110 = {
+    .name = "pl110",
+    .version_id = 2,
+    .minimum_version_id = 1,
+    .post_load = vmstate_pl110_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_INT32(version, pl110_state),
+        VMSTATE_UINT32_ARRAY(timing, pl110_state, 4),
+        VMSTATE_UINT32(cr, pl110_state),
+        VMSTATE_UINT32(upbase, pl110_state),
+        VMSTATE_UINT32(lpbase, pl110_state),
+        VMSTATE_UINT32(int_status, pl110_state),
+        VMSTATE_UINT32(int_mask, pl110_state),
+        VMSTATE_INT32(cols, pl110_state),
+        VMSTATE_INT32(rows, pl110_state),
+        VMSTATE_UINT32(bpp, pl110_state),
+        VMSTATE_INT32(invalidate, pl110_state),
+        VMSTATE_UINT32_ARRAY(palette, pl110_state, 256),
+        VMSTATE_UINT32_ARRAY(raw_palette, pl110_state, 128),
+        VMSTATE_UINT32_V(mux_ctrl, pl110_state, 2),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const unsigned char pl110_id[] =
+{ 0x10, 0x11, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
+
+/* The Arm documentation (DDI0224C) says the CLDC on the Versatile board
+   has a different ID.  However Linux only looks for the normal ID.  */
+#if 0
+static const unsigned char pl110_versatile_id[] =
+{ 0x93, 0x10, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
+#else
+#define pl110_versatile_id pl110_id
+#endif
+
+static const unsigned char pl111_id[] = {
+    0x11, 0x11, 0x24, 0x00, 0x0d, 0xf0, 0x05, 0xb1
+};
+
+/* Indexed by pl110_version */
+static const unsigned char *idregs[] = {
+    pl110_id,
+    pl110_versatile_id,
+    pl111_id
+};
+
+#define BITS 8
+#include "pl110_template.h"
+#define BITS 15
+#include "pl110_template.h"
+#define BITS 16
+#include "pl110_template.h"
+#define BITS 24
+#include "pl110_template.h"
+#define BITS 32
+#include "pl110_template.h"
+
+static int pl110_enabled(pl110_state *s)
+{
+  return (s->cr & PL110_CR_EN) && (s->cr & PL110_CR_PWR);
+}
+
+static void pl110_update_display(void *opaque)
+{
+    pl110_state *s = (pl110_state *)opaque;
+    DisplaySurface *surface = qemu_console_surface(s->con);
+    drawfn* fntable;
+    drawfn fn;
+    int dest_width;
+    int src_width;
+    int bpp_offset;
+    int first;
+    int last;
+
+    if (!pl110_enabled(s))
+        return;
+
+    switch (surface_bits_per_pixel(surface)) {
+    case 0:
+        return;
+    case 8:
+        fntable = pl110_draw_fn_8;
+        dest_width = 1;
+        break;
+    case 15:
+        fntable = pl110_draw_fn_15;
+        dest_width = 2;
+        break;
+    case 16:
+        fntable = pl110_draw_fn_16;
+        dest_width = 2;
+        break;
+    case 24:
+        fntable = pl110_draw_fn_24;
+        dest_width = 3;
+        break;
+    case 32:
+        fntable = pl110_draw_fn_32;
+        dest_width = 4;
+        break;
+    default:
+        fprintf(stderr, "pl110: Bad color depth\n");
+        exit(1);
+    }
+    if (s->cr & PL110_CR_BGR)
+        bpp_offset = 0;
+    else
+        bpp_offset = 24;
+
+    if ((s->version != PL111) && (s->bpp == BPP_16)) {
+        /* The PL110's native 16 bit mode is 5551; however
+         * most boards with a PL110 implement an external
+         * mux which allows bits to be reshuffled to give
+         * 565 format. The mux is typically controlled by
+         * an external system register.
+         * This is controlled by a GPIO input pin
+         * so boards can wire it up to their register.
+         *
+         * The PL111 straightforwardly implements both
+         * 5551 and 565 under control of the bpp field
+         * in the LCDControl register.
+         */
+        switch (s->mux_ctrl) {
+        case 3: /* 565 BGR */
+            bpp_offset = (BPP_16_565 - BPP_16);
+            break;
+        case 1: /* 5551 */
+            break;
+        case 0: /* 888; also if we have loaded vmstate from an old version */
+        case 2: /* 565 RGB */
+        default:
+            /* treat as 565 but honour BGR bit */
+            bpp_offset += (BPP_16_565 - BPP_16);
+            break;
+        }
+    }
+
+    if (s->cr & PL110_CR_BEBO)
+        fn = fntable[s->bpp + 8 + bpp_offset];
+    else if (s->cr & PL110_CR_BEPO)
+        fn = fntable[s->bpp + 16 + bpp_offset];
+    else
+        fn = fntable[s->bpp + bpp_offset];
+
+    src_width = s->cols;
+    switch (s->bpp) {
+    case BPP_1:
+        src_width >>= 3;
+        break;
+    case BPP_2:
+        src_width >>= 2;
+        break;
+    case BPP_4:
+        src_width >>= 1;
+        break;
+    case BPP_8:
+        break;
+    case BPP_16:
+    case BPP_16_565:
+    case BPP_12:
+        src_width <<= 1;
+        break;
+    case BPP_32:
+        src_width <<= 2;
+        break;
+    }
+    dest_width *= s->cols;
+    first = 0;
+    framebuffer_update_display(surface, sysbus_address_space(&s->busdev),
+                               s->upbase, s->cols, s->rows,
+                               src_width, dest_width, 0,
+                               s->invalidate,
+                               fn, s->palette,
+                               &first, &last);
+    if (first >= 0) {
+        dpy_gfx_update(s->con, 0, first, s->cols, last - first + 1);
+    }
+    s->invalidate = 0;
+}
+
+static void pl110_invalidate_display(void * opaque)
+{
+    pl110_state *s = (pl110_state *)opaque;
+    s->invalidate = 1;
+    if (pl110_enabled(s)) {
+        qemu_console_resize(s->con, s->cols, s->rows);
+    }
+}
+
+static void pl110_update_palette(pl110_state *s, int n)
+{
+    DisplaySurface *surface = qemu_console_surface(s->con);
+    int i;
+    uint32_t raw;
+    unsigned int r, g, b;
+
+    raw = s->raw_palette[n];
+    n <<= 1;
+    for (i = 0; i < 2; i++) {
+        r = (raw & 0x1f) << 3;
+        raw >>= 5;
+        g = (raw & 0x1f) << 3;
+        raw >>= 5;
+        b = (raw & 0x1f) << 3;
+        /* The I bit is ignored.  */
+        raw >>= 6;
+        switch (surface_bits_per_pixel(surface)) {
+        case 8:
+            s->palette[n] = rgb_to_pixel8(r, g, b);
+            break;
+        case 15:
+            s->palette[n] = rgb_to_pixel15(r, g, b);
+            break;
+        case 16:
+            s->palette[n] = rgb_to_pixel16(r, g, b);
+            break;
+        case 24:
+        case 32:
+            s->palette[n] = rgb_to_pixel32(r, g, b);
+            break;
+        }
+        n++;
+    }
+}
+
+static void pl110_resize(pl110_state *s, int width, int height)
+{
+    if (width != s->cols || height != s->rows) {
+        if (pl110_enabled(s)) {
+            qemu_console_resize(s->con, width, height);
+        }
+    }
+    s->cols = width;
+    s->rows = height;
+}
+
+/* Update interrupts.  */
+static void pl110_update(pl110_state *s)
+{
+  /* TODO: Implement interrupts.  */
+}
+
+static uint64_t pl110_read(void *opaque, hwaddr offset,
+                           unsigned size)
+{
+    pl110_state *s = (pl110_state *)opaque;
+
+    if (offset >= 0xfe0 && offset < 0x1000) {
+        return idregs[s->version][(offset - 0xfe0) >> 2];
+    }
+    if (offset >= 0x200 && offset < 0x400) {
+        return s->raw_palette[(offset - 0x200) >> 2];
+    }
+    switch (offset >> 2) {
+    case 0: /* LCDTiming0 */
+        return s->timing[0];
+    case 1: /* LCDTiming1 */
+        return s->timing[1];
+    case 2: /* LCDTiming2 */
+        return s->timing[2];
+    case 3: /* LCDTiming3 */
+        return s->timing[3];
+    case 4: /* LCDUPBASE */
+        return s->upbase;
+    case 5: /* LCDLPBASE */
+        return s->lpbase;
+    case 6: /* LCDIMSC */
+        if (s->version != PL110) {
+            return s->cr;
+        }
+        return s->int_mask;
+    case 7: /* LCDControl */
+        if (s->version != PL110) {
+            return s->int_mask;
+        }
+        return s->cr;
+    case 8: /* LCDRIS */
+        return s->int_status;
+    case 9: /* LCDMIS */
+        return s->int_status & s->int_mask;
+    case 11: /* LCDUPCURR */
+        /* TODO: Implement vertical refresh.  */
+        return s->upbase;
+    case 12: /* LCDLPCURR */
+        return s->lpbase;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "pl110_read: Bad offset %x\n", (int)offset);
+        return 0;
+    }
+}
+
+static void pl110_write(void *opaque, hwaddr offset,
+                        uint64_t val, unsigned size)
+{
+    pl110_state *s = (pl110_state *)opaque;
+    int n;
+
+    /* For simplicity invalidate the display whenever a control register
+       is written to.  */
+    s->invalidate = 1;
+    if (offset >= 0x200 && offset < 0x400) {
+        /* Palette.  */
+        n = (offset - 0x200) >> 2;
+        s->raw_palette[(offset - 0x200) >> 2] = val;
+        pl110_update_palette(s, n);
+        return;
+    }
+    switch (offset >> 2) {
+    case 0: /* LCDTiming0 */
+        s->timing[0] = val;
+        n = ((val & 0xfc) + 4) * 4;
+        pl110_resize(s, n, s->rows);
+        break;
+    case 1: /* LCDTiming1 */
+        s->timing[1] = val;
+        n = (val & 0x3ff) + 1;
+        pl110_resize(s, s->cols, n);
+        break;
+    case 2: /* LCDTiming2 */
+        s->timing[2] = val;
+        break;
+    case 3: /* LCDTiming3 */
+        s->timing[3] = val;
+        break;
+    case 4: /* LCDUPBASE */
+        s->upbase = val;
+        break;
+    case 5: /* LCDLPBASE */
+        s->lpbase = val;
+        break;
+    case 6: /* LCDIMSC */
+        if (s->version != PL110) {
+            goto control;
+        }
+    imsc:
+        s->int_mask = val;
+        pl110_update(s);
+        break;
+    case 7: /* LCDControl */
+        if (s->version != PL110) {
+            goto imsc;
+        }
+    control:
+        s->cr = val;
+        s->bpp = (val >> 1) & 7;
+        if (pl110_enabled(s)) {
+            qemu_console_resize(s->con, s->cols, s->rows);
+        }
+        break;
+    case 10: /* LCDICR */
+        s->int_status &= ~val;
+        pl110_update(s);
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "pl110_write: Bad offset %x\n", (int)offset);
+    }
+}
+
+static const MemoryRegionOps pl110_ops = {
+    .read = pl110_read,
+    .write = pl110_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void pl110_mux_ctrl_set(void *opaque, int line, int level)
+{
+    pl110_state *s = (pl110_state *)opaque;
+    s->mux_ctrl = level;
+}
+
+static int vmstate_pl110_post_load(void *opaque, int version_id)
+{
+    pl110_state *s = opaque;
+    /* Make sure we redraw, and at the right size */
+    pl110_invalidate_display(s);
+    return 0;
+}
+
+static int pl110_init(SysBusDevice *dev)
+{
+    pl110_state *s = FROM_SYSBUS(pl110_state, dev);
+
+    memory_region_init_io(&s->iomem, &pl110_ops, s, "pl110", 0x1000);
+    sysbus_init_mmio(dev, &s->iomem);
+    sysbus_init_irq(dev, &s->irq);
+    qdev_init_gpio_in(&s->busdev.qdev, pl110_mux_ctrl_set, 1);
+    s->con = graphic_console_init(pl110_update_display,
+                                  pl110_invalidate_display,
+                                  NULL, NULL, s);
+    return 0;
+}
+
+static int pl110_versatile_init(SysBusDevice *dev)
+{
+    pl110_state *s = FROM_SYSBUS(pl110_state, dev);
+    s->version = PL110_VERSATILE;
+    return pl110_init(dev);
+}
+
+static int pl111_init(SysBusDevice *dev)
+{
+    pl110_state *s = FROM_SYSBUS(pl110_state, dev);
+    s->version = PL111;
+    return pl110_init(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 const 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 const 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 const TypeInfo pl111_info = {
+    .name          = "pl111",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(pl110_state),
+    .class_init    = pl111_class_init,
+};
+
+static void pl110_register_types(void)
+{
+    type_register_static(&pl110_info);
+    type_register_static(&pl110_versatile_info);
+    type_register_static(&pl111_info);
+}
+
+type_init(pl110_register_types)
diff --git a/hw/display/pl110_template.h b/hw/display/pl110_template.h
new file mode 100644 (file)
index 0000000..e738e4a
--- /dev/null
@@ -0,0 +1,395 @@
+/*
+ * Arm PrimeCell PL110 Color LCD Controller
+ *
+ * Copyright (c) 2005 CodeSourcery, LLC.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the GNU LGPL
+ *
+ * Framebuffer format conversion routines.
+ */
+
+#ifndef ORDER
+
+#if BITS == 8
+#define COPY_PIXEL(to, from) *(to++) = from
+#elif BITS == 15 || BITS == 16
+#define COPY_PIXEL(to, from) *(uint16_t *)to = from; to += 2;
+#elif BITS == 24
+#define COPY_PIXEL(to, from) \
+  *(to++) = from; *(to++) = (from) >> 8; *(to++) = (from) >> 16
+#elif BITS == 32
+#define COPY_PIXEL(to, from) *(uint32_t *)to = from; to += 4;
+#else
+#error unknown bit depth
+#endif
+
+#undef RGB
+#define BORDER bgr
+#define ORDER 0
+#include "pl110_template.h"
+#define ORDER 1
+#include "pl110_template.h"
+#define ORDER 2
+#include "pl110_template.h"
+#undef BORDER
+#define RGB
+#define BORDER rgb
+#define ORDER 0
+#include "pl110_template.h"
+#define ORDER 1
+#include "pl110_template.h"
+#define ORDER 2
+#include "pl110_template.h"
+#undef BORDER
+
+static drawfn glue(pl110_draw_fn_,BITS)[48] =
+{
+    glue(pl110_draw_line1_lblp_bgr,BITS),
+    glue(pl110_draw_line2_lblp_bgr,BITS),
+    glue(pl110_draw_line4_lblp_bgr,BITS),
+    glue(pl110_draw_line8_lblp_bgr,BITS),
+    glue(pl110_draw_line16_555_lblp_bgr,BITS),
+    glue(pl110_draw_line32_lblp_bgr,BITS),
+    glue(pl110_draw_line16_lblp_bgr,BITS),
+    glue(pl110_draw_line12_lblp_bgr,BITS),
+
+    glue(pl110_draw_line1_bbbp_bgr,BITS),
+    glue(pl110_draw_line2_bbbp_bgr,BITS),
+    glue(pl110_draw_line4_bbbp_bgr,BITS),
+    glue(pl110_draw_line8_bbbp_bgr,BITS),
+    glue(pl110_draw_line16_555_bbbp_bgr,BITS),
+    glue(pl110_draw_line32_bbbp_bgr,BITS),
+    glue(pl110_draw_line16_bbbp_bgr,BITS),
+    glue(pl110_draw_line12_bbbp_bgr,BITS),
+
+    glue(pl110_draw_line1_lbbp_bgr,BITS),
+    glue(pl110_draw_line2_lbbp_bgr,BITS),
+    glue(pl110_draw_line4_lbbp_bgr,BITS),
+    glue(pl110_draw_line8_lbbp_bgr,BITS),
+    glue(pl110_draw_line16_555_lbbp_bgr,BITS),
+    glue(pl110_draw_line32_lbbp_bgr,BITS),
+    glue(pl110_draw_line16_lbbp_bgr,BITS),
+    glue(pl110_draw_line12_lbbp_bgr,BITS),
+
+    glue(pl110_draw_line1_lblp_rgb,BITS),
+    glue(pl110_draw_line2_lblp_rgb,BITS),
+    glue(pl110_draw_line4_lblp_rgb,BITS),
+    glue(pl110_draw_line8_lblp_rgb,BITS),
+    glue(pl110_draw_line16_555_lblp_rgb,BITS),
+    glue(pl110_draw_line32_lblp_rgb,BITS),
+    glue(pl110_draw_line16_lblp_rgb,BITS),
+    glue(pl110_draw_line12_lblp_rgb,BITS),
+
+    glue(pl110_draw_line1_bbbp_rgb,BITS),
+    glue(pl110_draw_line2_bbbp_rgb,BITS),
+    glue(pl110_draw_line4_bbbp_rgb,BITS),
+    glue(pl110_draw_line8_bbbp_rgb,BITS),
+    glue(pl110_draw_line16_555_bbbp_rgb,BITS),
+    glue(pl110_draw_line32_bbbp_rgb,BITS),
+    glue(pl110_draw_line16_bbbp_rgb,BITS),
+    glue(pl110_draw_line12_bbbp_rgb,BITS),
+
+    glue(pl110_draw_line1_lbbp_rgb,BITS),
+    glue(pl110_draw_line2_lbbp_rgb,BITS),
+    glue(pl110_draw_line4_lbbp_rgb,BITS),
+    glue(pl110_draw_line8_lbbp_rgb,BITS),
+    glue(pl110_draw_line16_555_lbbp_rgb,BITS),
+    glue(pl110_draw_line32_lbbp_rgb,BITS),
+    glue(pl110_draw_line16_lbbp_rgb,BITS),
+    glue(pl110_draw_line12_lbbp_rgb,BITS),
+};
+
+#undef BITS
+#undef COPY_PIXEL
+
+#else
+
+#if ORDER == 0
+#define NAME glue(glue(lblp_, BORDER), BITS)
+#ifdef HOST_WORDS_BIGENDIAN
+#define SWAP_WORDS 1
+#endif
+#elif ORDER == 1
+#define NAME glue(glue(bbbp_, BORDER), BITS)
+#ifndef HOST_WORDS_BIGENDIAN
+#define SWAP_WORDS 1
+#endif
+#else
+#define SWAP_PIXELS 1
+#define NAME glue(glue(lbbp_, BORDER), BITS)
+#ifdef HOST_WORDS_BIGENDIAN
+#define SWAP_WORDS 1
+#endif
+#endif
+
+#define FN_2(x, y) FN(x, y) FN(x+1, y)
+#define FN_4(x, y) FN_2(x, y) FN_2(x+2, y)
+#define FN_8(y) FN_4(0, y) FN_4(4, y)
+
+static void glue(pl110_draw_line1_,NAME)(void *opaque, uint8_t *d, const uint8_t *src, int width, int deststep)
+{
+    uint32_t *palette = opaque;
+    uint32_t data;
+    while (width > 0) {
+        data = *(uint32_t *)src;
+#ifdef SWAP_PIXELS
+#define FN(x, y) COPY_PIXEL(d, palette[(data >> (y + 7 - (x))) & 1]);
+#else
+#define FN(x, y) COPY_PIXEL(d, palette[(data >> ((x) + y)) & 1]);
+#endif
+#ifdef SWAP_WORDS
+        FN_8(24)
+        FN_8(16)
+        FN_8(8)
+        FN_8(0)
+#else
+        FN_8(0)
+        FN_8(8)
+        FN_8(16)
+        FN_8(24)
+#endif
+#undef FN
+        width -= 32;
+        src += 4;
+    }
+}
+
+static void glue(pl110_draw_line2_,NAME)(void *opaque, uint8_t *d, const uint8_t *src, int width, int deststep)
+{
+    uint32_t *palette = opaque;
+    uint32_t data;
+    while (width > 0) {
+        data = *(uint32_t *)src;
+#ifdef SWAP_PIXELS
+#define FN(x, y) COPY_PIXEL(d, palette[(data >> (y + 6 - (x)*2)) & 3]);
+#else
+#define FN(x, y) COPY_PIXEL(d, palette[(data >> ((x)*2 + y)) & 3]);
+#endif
+#ifdef SWAP_WORDS
+        FN_4(0, 24)
+        FN_4(0, 16)
+        FN_4(0, 8)
+        FN_4(0, 0)
+#else
+        FN_4(0, 0)
+        FN_4(0, 8)
+        FN_4(0, 16)
+        FN_4(0, 24)
+#endif
+#undef FN
+        width -= 16;
+        src += 4;
+    }
+}
+
+static void glue(pl110_draw_line4_,NAME)(void *opaque, uint8_t *d, const uint8_t *src, int width, int deststep)
+{
+    uint32_t *palette = opaque;
+    uint32_t data;
+    while (width > 0) {
+        data = *(uint32_t *)src;
+#ifdef SWAP_PIXELS
+#define FN(x, y) COPY_PIXEL(d, palette[(data >> (y + 4 - (x)*4)) & 0xf]);
+#else
+#define FN(x, y) COPY_PIXEL(d, palette[(data >> ((x)*4 + y)) & 0xf]);
+#endif
+#ifdef SWAP_WORDS
+        FN_2(0, 24)
+        FN_2(0, 16)
+        FN_2(0, 8)
+        FN_2(0, 0)
+#else
+        FN_2(0, 0)
+        FN_2(0, 8)
+        FN_2(0, 16)
+        FN_2(0, 24)
+#endif
+#undef FN
+        width -= 8;
+        src += 4;
+    }
+}
+
+static void glue(pl110_draw_line8_,NAME)(void *opaque, uint8_t *d, const uint8_t *src, int width, int deststep)
+{
+    uint32_t *palette = opaque;
+    uint32_t data;
+    while (width > 0) {
+        data = *(uint32_t *)src;
+#define FN(x) COPY_PIXEL(d, palette[(data >> (x)) & 0xff]);
+#ifdef SWAP_WORDS
+        FN(24)
+        FN(16)
+        FN(8)
+        FN(0)
+#else
+        FN(0)
+        FN(8)
+        FN(16)
+        FN(24)
+#endif
+#undef FN
+        width -= 4;
+        src += 4;
+    }
+}
+
+static void glue(pl110_draw_line16_,NAME)(void *opaque, uint8_t *d, const uint8_t *src, int width, int deststep)
+{
+    uint32_t data;
+    unsigned int r, g, b;
+    while (width > 0) {
+        data = *(uint32_t *)src;
+#ifdef SWAP_WORDS
+        data = bswap32(data);
+#endif
+#ifdef RGB
+#define LSB r
+#define MSB b
+#else
+#define LSB b
+#define MSB r
+#endif
+#if 0
+        LSB = data & 0x1f;
+        data >>= 5;
+        g = data & 0x3f;
+        data >>= 6;
+        MSB = data & 0x1f;
+        data >>= 5;
+#else
+        LSB = (data & 0x1f) << 3;
+        data >>= 5;
+        g = (data & 0x3f) << 2;
+        data >>= 6;
+        MSB = (data & 0x1f) << 3;
+        data >>= 5;
+#endif
+        COPY_PIXEL(d, glue(rgb_to_pixel,BITS)(r, g, b));
+        LSB = (data & 0x1f) << 3;
+        data >>= 5;
+        g = (data & 0x3f) << 2;
+        data >>= 6;
+        MSB = (data & 0x1f) << 3;
+        data >>= 5;
+        COPY_PIXEL(d, glue(rgb_to_pixel,BITS)(r, g, b));
+#undef MSB
+#undef LSB
+        width -= 2;
+        src += 4;
+    }
+}
+
+static void glue(pl110_draw_line32_,NAME)(void *opaque, uint8_t *d, const uint8_t *src, int width, int deststep)
+{
+    uint32_t data;
+    unsigned int r, g, b;
+    while (width > 0) {
+        data = *(uint32_t *)src;
+#ifdef RGB
+#define LSB r
+#define MSB b
+#else
+#define LSB b
+#define MSB r
+#endif
+#ifndef SWAP_WORDS
+        LSB = data & 0xff;
+        g = (data >> 8) & 0xff;
+        MSB = (data >> 16) & 0xff;
+#else
+        LSB = (data >> 24) & 0xff;
+        g = (data >> 16) & 0xff;
+        MSB = (data >> 8) & 0xff;
+#endif
+        COPY_PIXEL(d, glue(rgb_to_pixel,BITS)(r, g, b));
+#undef MSB
+#undef LSB
+        width--;
+        src += 4;
+    }
+}
+
+static void glue(pl110_draw_line16_555_,NAME)(void *opaque, uint8_t *d, const uint8_t *src, int width, int deststep)
+{
+    /* RGB 555 plus an intensity bit (which we ignore) */
+    uint32_t data;
+    unsigned int r, g, b;
+    while (width > 0) {
+        data = *(uint32_t *)src;
+#ifdef SWAP_WORDS
+        data = bswap32(data);
+#endif
+#ifdef RGB
+#define LSB r
+#define MSB b
+#else
+#define LSB b
+#define MSB r
+#endif
+        LSB = (data & 0x1f) << 3;
+        data >>= 5;
+        g = (data & 0x1f) << 3;
+        data >>= 5;
+        MSB = (data & 0x1f) << 3;
+        data >>= 5;
+        COPY_PIXEL(d, glue(rgb_to_pixel,BITS)(r, g, b));
+        LSB = (data & 0x1f) << 3;
+        data >>= 5;
+        g = (data & 0x1f) << 3;
+        data >>= 5;
+        MSB = (data & 0x1f) << 3;
+        data >>= 6;
+        COPY_PIXEL(d, glue(rgb_to_pixel,BITS)(r, g, b));
+#undef MSB
+#undef LSB
+        width -= 2;
+        src += 4;
+    }
+}
+
+static void glue(pl110_draw_line12_,NAME)(void *opaque, uint8_t *d, const uint8_t *src, int width, int deststep)
+{
+    /* RGB 444 with 4 bits of zeroes at the top of each halfword */
+    uint32_t data;
+    unsigned int r, g, b;
+    while (width > 0) {
+        data = *(uint32_t *)src;
+#ifdef SWAP_WORDS
+        data = bswap32(data);
+#endif
+#ifdef RGB
+#define LSB r
+#define MSB b
+#else
+#define LSB b
+#define MSB r
+#endif
+        LSB = (data & 0xf) << 4;
+        data >>= 4;
+        g = (data & 0xf) << 4;
+        data >>= 4;
+        MSB = (data & 0xf) << 4;
+        data >>= 8;
+        COPY_PIXEL(d, glue(rgb_to_pixel,BITS)(r, g, b));
+        LSB = (data & 0xf) << 4;
+        data >>= 4;
+        g = (data & 0xf) << 4;
+        data >>= 4;
+        MSB = (data & 0xf) << 4;
+        data >>= 8;
+        COPY_PIXEL(d, glue(rgb_to_pixel,BITS)(r, g, b));
+#undef MSB
+#undef LSB
+        width -= 2;
+        src += 4;
+    }
+}
+
+#undef SWAP_PIXELS
+#undef NAME
+#undef SWAP_WORDS
+#undef ORDER
+
+#endif
diff --git a/hw/display/pxa2xx_lcd.c b/hw/display/pxa2xx_lcd.c
new file mode 100644 (file)
index 0000000..c9bd42e
--- /dev/null
@@ -0,0 +1,1058 @@
+/*
+ * Intel XScale PXA255/270 LCDC emulation.
+ *
+ * Copyright (c) 2006 Openedhand Ltd.
+ * Written by Andrzej Zaborowski <balrog@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/hw.h"
+#include "ui/console.h"
+#include "hw/arm/pxa.h"
+#include "ui/pixel_ops.h"
+/* FIXME: For graphic_rotate. Should probably be done in common code.  */
+#include "sysemu/sysemu.h"
+#include "framebuffer.h"
+
+struct DMAChannel {
+    uint32_t branch;
+    uint8_t up;
+    uint8_t palette[1024];
+    uint8_t pbuffer[1024];
+    void (*redraw)(PXA2xxLCDState *s, hwaddr addr,
+                   int *miny, int *maxy);
+
+    uint32_t descriptor;
+    uint32_t source;
+    uint32_t id;
+    uint32_t command;
+};
+
+struct PXA2xxLCDState {
+    MemoryRegion *sysmem;
+    MemoryRegion iomem;
+    qemu_irq irq;
+    int irqlevel;
+
+    int invalidated;
+    QemuConsole *con;
+    drawfn *line_fn[2];
+    int dest_width;
+    int xres, yres;
+    int pal_for;
+    int transp;
+    enum {
+        pxa_lcdc_2bpp = 1,
+        pxa_lcdc_4bpp = 2,
+        pxa_lcdc_8bpp = 3,
+        pxa_lcdc_16bpp = 4,
+        pxa_lcdc_18bpp = 5,
+        pxa_lcdc_18pbpp = 6,
+        pxa_lcdc_19bpp = 7,
+        pxa_lcdc_19pbpp = 8,
+        pxa_lcdc_24bpp = 9,
+        pxa_lcdc_25bpp = 10,
+    } bpp;
+
+    uint32_t control[6];
+    uint32_t status[2];
+    uint32_t ovl1c[2];
+    uint32_t ovl2c[2];
+    uint32_t ccr;
+    uint32_t cmdcr;
+    uint32_t trgbr;
+    uint32_t tcr;
+    uint32_t liidr;
+    uint8_t bscntr;
+
+    struct DMAChannel dma_ch[7];
+
+    qemu_irq vsync_cb;
+    int orientation;
+};
+
+typedef struct QEMU_PACKED {
+    uint32_t fdaddr;
+    uint32_t fsaddr;
+    uint32_t fidr;
+    uint32_t ldcmd;
+} PXAFrameDescriptor;
+
+#define LCCR0  0x000   /* LCD Controller Control register 0 */
+#define LCCR1  0x004   /* LCD Controller Control register 1 */
+#define LCCR2  0x008   /* LCD Controller Control register 2 */
+#define LCCR3  0x00c   /* LCD Controller Control register 3 */
+#define LCCR4  0x010   /* LCD Controller Control register 4 */
+#define LCCR5  0x014   /* LCD Controller Control register 5 */
+
+#define FBR0   0x020   /* DMA Channel 0 Frame Branch register */
+#define FBR1   0x024   /* DMA Channel 1 Frame Branch register */
+#define FBR2   0x028   /* DMA Channel 2 Frame Branch register */
+#define FBR3   0x02c   /* DMA Channel 3 Frame Branch register */
+#define FBR4   0x030   /* DMA Channel 4 Frame Branch register */
+#define FBR5   0x110   /* DMA Channel 5 Frame Branch register */
+#define FBR6   0x114   /* DMA Channel 6 Frame Branch register */
+
+#define LCSR1  0x034   /* LCD Controller Status register 1 */
+#define LCSR0  0x038   /* LCD Controller Status register 0 */
+#define LIIDR  0x03c   /* LCD Controller Interrupt ID register */
+
+#define TRGBR  0x040   /* TMED RGB Seed register */
+#define TCR    0x044   /* TMED Control register */
+
+#define OVL1C1 0x050   /* Overlay 1 Control register 1 */
+#define OVL1C2 0x060   /* Overlay 1 Control register 2 */
+#define OVL2C1 0x070   /* Overlay 2 Control register 1 */
+#define OVL2C2 0x080   /* Overlay 2 Control register 2 */
+#define CCR    0x090   /* Cursor Control register */
+
+#define CMDCR  0x100   /* Command Control register */
+#define PRSR   0x104   /* Panel Read Status register */
+
+#define PXA_LCDDMA_CHANS       7
+#define DMA_FDADR              0x00    /* Frame Descriptor Address register */
+#define DMA_FSADR              0x04    /* Frame Source Address register */
+#define DMA_FIDR               0x08    /* Frame ID register */
+#define DMA_LDCMD              0x0c    /* Command register */
+
+/* LCD Buffer Strength Control register */
+#define BSCNTR 0x04000054
+
+/* Bitfield masks */
+#define LCCR0_ENB      (1 << 0)
+#define LCCR0_CMS      (1 << 1)
+#define LCCR0_SDS      (1 << 2)
+#define LCCR0_LDM      (1 << 3)
+#define LCCR0_SOFM0    (1 << 4)
+#define LCCR0_IUM      (1 << 5)
+#define LCCR0_EOFM0    (1 << 6)
+#define LCCR0_PAS      (1 << 7)
+#define LCCR0_DPD      (1 << 9)
+#define LCCR0_DIS      (1 << 10)
+#define LCCR0_QDM      (1 << 11)
+#define LCCR0_PDD      (0xff << 12)
+#define LCCR0_BSM0     (1 << 20)
+#define LCCR0_OUM      (1 << 21)
+#define LCCR0_LCDT     (1 << 22)
+#define LCCR0_RDSTM    (1 << 23)
+#define LCCR0_CMDIM    (1 << 24)
+#define LCCR0_OUC      (1 << 25)
+#define LCCR0_LDDALT   (1 << 26)
+#define LCCR1_PPL(x)   ((x) & 0x3ff)
+#define LCCR2_LPP(x)   ((x) & 0x3ff)
+#define LCCR3_API      (15 << 16)
+#define LCCR3_BPP(x)   ((((x) >> 24) & 7) | (((x) >> 26) & 8))
+#define LCCR3_PDFOR(x) (((x) >> 30) & 3)
+#define LCCR4_K1(x)    (((x) >> 0) & 7)
+#define LCCR4_K2(x)    (((x) >> 3) & 7)
+#define LCCR4_K3(x)    (((x) >> 6) & 7)
+#define LCCR4_PALFOR(x)        (((x) >> 15) & 3)
+#define LCCR5_SOFM(ch) (1 << (ch - 1))
+#define LCCR5_EOFM(ch) (1 << (ch + 7))
+#define LCCR5_BSM(ch)  (1 << (ch + 15))
+#define LCCR5_IUM(ch)  (1 << (ch + 23))
+#define OVLC1_EN       (1 << 31)
+#define CCR_CEN                (1 << 31)
+#define FBR_BRA                (1 << 0)
+#define FBR_BINT       (1 << 1)
+#define FBR_SRCADDR    (0xfffffff << 4)
+#define LCSR0_LDD      (1 << 0)
+#define LCSR0_SOF0     (1 << 1)
+#define LCSR0_BER      (1 << 2)
+#define LCSR0_ABC      (1 << 3)
+#define LCSR0_IU0      (1 << 4)
+#define LCSR0_IU1      (1 << 5)
+#define LCSR0_OU       (1 << 6)
+#define LCSR0_QD       (1 << 7)
+#define LCSR0_EOF0     (1 << 8)
+#define LCSR0_BS0      (1 << 9)
+#define LCSR0_SINT     (1 << 10)
+#define LCSR0_RDST     (1 << 11)
+#define LCSR0_CMDINT   (1 << 12)
+#define LCSR0_BERCH(x) (((x) & 7) << 28)
+#define LCSR1_SOF(ch)  (1 << (ch - 1))
+#define LCSR1_EOF(ch)  (1 << (ch + 7))
+#define LCSR1_BS(ch)   (1 << (ch + 15))
+#define LCSR1_IU(ch)   (1 << (ch + 23))
+#define LDCMD_LENGTH(x)        ((x) & 0x001ffffc)
+#define LDCMD_EOFINT   (1 << 21)
+#define LDCMD_SOFINT   (1 << 22)
+#define LDCMD_PAL      (1 << 26)
+
+/* Route internal interrupt lines to the global IC */
+static void pxa2xx_lcdc_int_update(PXA2xxLCDState *s)
+{
+    int level = 0;
+    level |= (s->status[0] & LCSR0_LDD)    && !(s->control[0] & LCCR0_LDM);
+    level |= (s->status[0] & LCSR0_SOF0)   && !(s->control[0] & LCCR0_SOFM0);
+    level |= (s->status[0] & LCSR0_IU0)    && !(s->control[0] & LCCR0_IUM);
+    level |= (s->status[0] & LCSR0_IU1)    && !(s->control[5] & LCCR5_IUM(1));
+    level |= (s->status[0] & LCSR0_OU)     && !(s->control[0] & LCCR0_OUM);
+    level |= (s->status[0] & LCSR0_QD)     && !(s->control[0] & LCCR0_QDM);
+    level |= (s->status[0] & LCSR0_EOF0)   && !(s->control[0] & LCCR0_EOFM0);
+    level |= (s->status[0] & LCSR0_BS0)    && !(s->control[0] & LCCR0_BSM0);
+    level |= (s->status[0] & LCSR0_RDST)   && !(s->control[0] & LCCR0_RDSTM);
+    level |= (s->status[0] & LCSR0_CMDINT) && !(s->control[0] & LCCR0_CMDIM);
+    level |= (s->status[1] & ~s->control[5]);
+
+    qemu_set_irq(s->irq, !!level);
+    s->irqlevel = level;
+}
+
+/* Set Branch Status interrupt high and poke associated registers */
+static inline void pxa2xx_dma_bs_set(PXA2xxLCDState *s, int ch)
+{
+    int unmasked;
+    if (ch == 0) {
+        s->status[0] |= LCSR0_BS0;
+        unmasked = !(s->control[0] & LCCR0_BSM0);
+    } else {
+        s->status[1] |= LCSR1_BS(ch);
+        unmasked = !(s->control[5] & LCCR5_BSM(ch));
+    }
+
+    if (unmasked) {
+        if (s->irqlevel)
+            s->status[0] |= LCSR0_SINT;
+        else
+            s->liidr = s->dma_ch[ch].id;
+    }
+}
+
+/* Set Start Of Frame Status interrupt high and poke associated registers */
+static inline void pxa2xx_dma_sof_set(PXA2xxLCDState *s, int ch)
+{
+    int unmasked;
+    if (!(s->dma_ch[ch].command & LDCMD_SOFINT))
+        return;
+
+    if (ch == 0) {
+        s->status[0] |= LCSR0_SOF0;
+        unmasked = !(s->control[0] & LCCR0_SOFM0);
+    } else {
+        s->status[1] |= LCSR1_SOF(ch);
+        unmasked = !(s->control[5] & LCCR5_SOFM(ch));
+    }
+
+    if (unmasked) {
+        if (s->irqlevel)
+            s->status[0] |= LCSR0_SINT;
+        else
+            s->liidr = s->dma_ch[ch].id;
+    }
+}
+
+/* Set End Of Frame Status interrupt high and poke associated registers */
+static inline void pxa2xx_dma_eof_set(PXA2xxLCDState *s, int ch)
+{
+    int unmasked;
+    if (!(s->dma_ch[ch].command & LDCMD_EOFINT))
+        return;
+
+    if (ch == 0) {
+        s->status[0] |= LCSR0_EOF0;
+        unmasked = !(s->control[0] & LCCR0_EOFM0);
+    } else {
+        s->status[1] |= LCSR1_EOF(ch);
+        unmasked = !(s->control[5] & LCCR5_EOFM(ch));
+    }
+
+    if (unmasked) {
+        if (s->irqlevel)
+            s->status[0] |= LCSR0_SINT;
+        else
+            s->liidr = s->dma_ch[ch].id;
+    }
+}
+
+/* Set Bus Error Status interrupt high and poke associated registers */
+static inline void pxa2xx_dma_ber_set(PXA2xxLCDState *s, int ch)
+{
+    s->status[0] |= LCSR0_BERCH(ch) | LCSR0_BER;
+    if (s->irqlevel)
+        s->status[0] |= LCSR0_SINT;
+    else
+        s->liidr = s->dma_ch[ch].id;
+}
+
+/* Set Read Status interrupt high and poke associated registers */
+static inline void pxa2xx_dma_rdst_set(PXA2xxLCDState *s)
+{
+    s->status[0] |= LCSR0_RDST;
+    if (s->irqlevel && !(s->control[0] & LCCR0_RDSTM))
+        s->status[0] |= LCSR0_SINT;
+}
+
+/* Load new Frame Descriptors from DMA */
+static void pxa2xx_descriptor_load(PXA2xxLCDState *s)
+{
+    PXAFrameDescriptor desc;
+    hwaddr descptr;
+    int i;
+
+    for (i = 0; i < PXA_LCDDMA_CHANS; i ++) {
+        s->dma_ch[i].source = 0;
+
+        if (!s->dma_ch[i].up)
+            continue;
+
+        if (s->dma_ch[i].branch & FBR_BRA) {
+            descptr = s->dma_ch[i].branch & FBR_SRCADDR;
+            if (s->dma_ch[i].branch & FBR_BINT)
+                pxa2xx_dma_bs_set(s, i);
+            s->dma_ch[i].branch &= ~FBR_BRA;
+        } else
+            descptr = s->dma_ch[i].descriptor;
+
+        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);
+        s->dma_ch[i].source = tswap32(desc.fsaddr);
+        s->dma_ch[i].id = tswap32(desc.fidr);
+        s->dma_ch[i].command = tswap32(desc.ldcmd);
+    }
+}
+
+static uint64_t pxa2xx_lcdc_read(void *opaque, hwaddr offset,
+                                 unsigned size)
+{
+    PXA2xxLCDState *s = (PXA2xxLCDState *) opaque;
+    int ch;
+
+    switch (offset) {
+    case LCCR0:
+        return s->control[0];
+    case LCCR1:
+        return s->control[1];
+    case LCCR2:
+        return s->control[2];
+    case LCCR3:
+        return s->control[3];
+    case LCCR4:
+        return s->control[4];
+    case LCCR5:
+        return s->control[5];
+
+    case OVL1C1:
+        return s->ovl1c[0];
+    case OVL1C2:
+        return s->ovl1c[1];
+    case OVL2C1:
+        return s->ovl2c[0];
+    case OVL2C2:
+        return s->ovl2c[1];
+
+    case CCR:
+        return s->ccr;
+
+    case CMDCR:
+        return s->cmdcr;
+
+    case TRGBR:
+        return s->trgbr;
+    case TCR:
+        return s->tcr;
+
+    case 0x200 ... 0x1000:     /* DMA per-channel registers */
+        ch = (offset - 0x200) >> 4;
+        if (!(ch >= 0 && ch < PXA_LCDDMA_CHANS))
+            goto fail;
+
+        switch (offset & 0xf) {
+        case DMA_FDADR:
+            return s->dma_ch[ch].descriptor;
+        case DMA_FSADR:
+            return s->dma_ch[ch].source;
+        case DMA_FIDR:
+            return s->dma_ch[ch].id;
+        case DMA_LDCMD:
+            return s->dma_ch[ch].command;
+        default:
+            goto fail;
+        }
+
+    case FBR0:
+        return s->dma_ch[0].branch;
+    case FBR1:
+        return s->dma_ch[1].branch;
+    case FBR2:
+        return s->dma_ch[2].branch;
+    case FBR3:
+        return s->dma_ch[3].branch;
+    case FBR4:
+        return s->dma_ch[4].branch;
+    case FBR5:
+        return s->dma_ch[5].branch;
+    case FBR6:
+        return s->dma_ch[6].branch;
+
+    case BSCNTR:
+        return s->bscntr;
+
+    case PRSR:
+        return 0;
+
+    case LCSR0:
+        return s->status[0];
+    case LCSR1:
+        return s->status[1];
+    case LIIDR:
+        return s->liidr;
+
+    default:
+    fail:
+        hw_error("%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset);
+    }
+
+    return 0;
+}
+
+static void pxa2xx_lcdc_write(void *opaque, hwaddr offset,
+                              uint64_t value, unsigned size)
+{
+    PXA2xxLCDState *s = (PXA2xxLCDState *) opaque;
+    int ch;
+
+    switch (offset) {
+    case LCCR0:
+        /* ACK Quick Disable done */
+        if ((s->control[0] & LCCR0_ENB) && !(value & LCCR0_ENB))
+            s->status[0] |= LCSR0_QD;
+
+        if (!(s->control[0] & LCCR0_LCDT) && (value & LCCR0_LCDT))
+            printf("%s: internal frame buffer unsupported\n", __FUNCTION__);
+
+        if ((s->control[3] & LCCR3_API) &&
+                (value & LCCR0_ENB) && !(value & LCCR0_LCDT))
+            s->status[0] |= LCSR0_ABC;
+
+        s->control[0] = value & 0x07ffffff;
+        pxa2xx_lcdc_int_update(s);
+
+        s->dma_ch[0].up = !!(value & LCCR0_ENB);
+        s->dma_ch[1].up = (s->ovl1c[0] & OVLC1_EN) || (value & LCCR0_SDS);
+        break;
+
+    case LCCR1:
+        s->control[1] = value;
+        break;
+
+    case LCCR2:
+        s->control[2] = value;
+        break;
+
+    case LCCR3:
+        s->control[3] = value & 0xefffffff;
+        s->bpp = LCCR3_BPP(value);
+        break;
+
+    case LCCR4:
+        s->control[4] = value & 0x83ff81ff;
+        break;
+
+    case LCCR5:
+        s->control[5] = value & 0x3f3f3f3f;
+        break;
+
+    case OVL1C1:
+        if (!(s->ovl1c[0] & OVLC1_EN) && (value & OVLC1_EN))
+            printf("%s: Overlay 1 not supported\n", __FUNCTION__);
+
+        s->ovl1c[0] = value & 0x80ffffff;
+        s->dma_ch[1].up = (value & OVLC1_EN) || (s->control[0] & LCCR0_SDS);
+        break;
+
+    case OVL1C2:
+        s->ovl1c[1] = value & 0x000fffff;
+        break;
+
+    case OVL2C1:
+        if (!(s->ovl2c[0] & OVLC1_EN) && (value & OVLC1_EN))
+            printf("%s: Overlay 2 not supported\n", __FUNCTION__);
+
+        s->ovl2c[0] = value & 0x80ffffff;
+        s->dma_ch[2].up = !!(value & OVLC1_EN);
+        s->dma_ch[3].up = !!(value & OVLC1_EN);
+        s->dma_ch[4].up = !!(value & OVLC1_EN);
+        break;
+
+    case OVL2C2:
+        s->ovl2c[1] = value & 0x007fffff;
+        break;
+
+    case CCR:
+        if (!(s->ccr & CCR_CEN) && (value & CCR_CEN))
+            printf("%s: Hardware cursor unimplemented\n", __FUNCTION__);
+
+        s->ccr = value & 0x81ffffe7;
+        s->dma_ch[5].up = !!(value & CCR_CEN);
+        break;
+
+    case CMDCR:
+        s->cmdcr = value & 0xff;
+        break;
+
+    case TRGBR:
+        s->trgbr = value & 0x00ffffff;
+        break;
+
+    case TCR:
+        s->tcr = value & 0x7fff;
+        break;
+
+    case 0x200 ... 0x1000:     /* DMA per-channel registers */
+        ch = (offset - 0x200) >> 4;
+        if (!(ch >= 0 && ch < PXA_LCDDMA_CHANS))
+            goto fail;
+
+        switch (offset & 0xf) {
+        case DMA_FDADR:
+            s->dma_ch[ch].descriptor = value & 0xfffffff0;
+            break;
+
+        default:
+            goto fail;
+        }
+        break;
+
+    case FBR0:
+        s->dma_ch[0].branch = value & 0xfffffff3;
+        break;
+    case FBR1:
+        s->dma_ch[1].branch = value & 0xfffffff3;
+        break;
+    case FBR2:
+        s->dma_ch[2].branch = value & 0xfffffff3;
+        break;
+    case FBR3:
+        s->dma_ch[3].branch = value & 0xfffffff3;
+        break;
+    case FBR4:
+        s->dma_ch[4].branch = value & 0xfffffff3;
+        break;
+    case FBR5:
+        s->dma_ch[5].branch = value & 0xfffffff3;
+        break;
+    case FBR6:
+        s->dma_ch[6].branch = value & 0xfffffff3;
+        break;
+
+    case BSCNTR:
+        s->bscntr = value & 0xf;
+        break;
+
+    case PRSR:
+        break;
+
+    case LCSR0:
+        s->status[0] &= ~(value & 0xfff);
+        if (value & LCSR0_BER)
+            s->status[0] &= ~LCSR0_BERCH(7);
+        break;
+
+    case LCSR1:
+        s->status[1] &= ~(value & 0x3e3f3f);
+        break;
+
+    default:
+    fail:
+        hw_error("%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset);
+    }
+}
+
+static const MemoryRegionOps pxa2xx_lcdc_ops = {
+    .read = pxa2xx_lcdc_read,
+    .write = pxa2xx_lcdc_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+/* Load new palette for a given DMA channel, convert to internal format */
+static void pxa2xx_palette_parse(PXA2xxLCDState *s, int ch, int bpp)
+{
+    DisplaySurface *surface = qemu_console_surface(s->con);
+    int i, n, format, r, g, b, alpha;
+    uint32_t *dest;
+    uint8_t *src;
+    s->pal_for = LCCR4_PALFOR(s->control[4]);
+    format = s->pal_for;
+
+    switch (bpp) {
+    case pxa_lcdc_2bpp:
+        n = 4;
+        break;
+    case pxa_lcdc_4bpp:
+        n = 16;
+        break;
+    case pxa_lcdc_8bpp:
+        n = 256;
+        break;
+    default:
+        format = 0;
+        return;
+    }
+
+    src = (uint8_t *) s->dma_ch[ch].pbuffer;
+    dest = (uint32_t *) s->dma_ch[ch].palette;
+    alpha = r = g = b = 0;
+
+    for (i = 0; i < n; i ++) {
+        switch (format) {
+        case 0: /* 16 bpp, no transparency */
+            alpha = 0;
+            if (s->control[0] & LCCR0_CMS) {
+                r = g = b = *(uint16_t *) src & 0xff;
+            }
+            else {
+                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 = *(uint16_t *) src & (1 << 24);
+            if (s->control[0] & LCCR0_CMS)
+                r = g = b = *(uint16_t *) src & 0xff;
+            else {
+                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 = *(uint32_t *) src & (1 << 24);
+            if (s->control[0] & LCCR0_CMS)
+                r = g = b = *(uint32_t *) src & 0xff;
+            else {
+                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 = *(uint32_t *) src & (1 << 24);
+            if (s->control[0] & LCCR0_CMS)
+                r = g = b = *(uint32_t *) src & 0xff;
+            else {
+                r = (*(uint32_t *) src & 0xff0000) >> 16;
+                g = (*(uint32_t *) src & 0x00ff00) >> 8;
+                b = (*(uint32_t *) src & 0x0000ff);
+            }
+            src += 4;
+            break;
+        }
+        switch (surface_bits_per_pixel(surface)) {
+        case 8:
+            *dest = rgb_to_pixel8(r, g, b) | alpha;
+            break;
+        case 15:
+            *dest = rgb_to_pixel15(r, g, b) | alpha;
+            break;
+        case 16:
+            *dest = rgb_to_pixel16(r, g, b) | alpha;
+            break;
+        case 24:
+            *dest = rgb_to_pixel24(r, g, b) | alpha;
+            break;
+        case 32:
+            *dest = rgb_to_pixel32(r, g, b) | alpha;
+            break;
+        }
+        dest ++;
+    }
+}
+
+static void pxa2xx_lcdc_dma0_redraw_rot0(PXA2xxLCDState *s,
+                hwaddr addr, int *miny, int *maxy)
+{
+    DisplaySurface *surface = qemu_console_surface(s->con);
+    int src_width, dest_width;
+    drawfn fn = NULL;
+    if (s->dest_width)
+        fn = s->line_fn[s->transp][s->bpp];
+    if (!fn)
+        return;
+
+    src_width = (s->xres + 3) & ~3;     /* Pad to a 4 pixels multiple */
+    if (s->bpp == pxa_lcdc_19pbpp || s->bpp == pxa_lcdc_18pbpp)
+        src_width *= 3;
+    else if (s->bpp > pxa_lcdc_16bpp)
+        src_width *= 4;
+    else if (s->bpp > pxa_lcdc_8bpp)
+        src_width *= 2;
+
+    dest_width = s->xres * s->dest_width;
+    *miny = 0;
+    framebuffer_update_display(surface, s->sysmem,
+                               addr, s->xres, s->yres,
+                               src_width, dest_width, s->dest_width,
+                               s->invalidated,
+                               fn, s->dma_ch[0].palette, miny, maxy);
+}
+
+static void pxa2xx_lcdc_dma0_redraw_rot90(PXA2xxLCDState *s,
+               hwaddr addr, int *miny, int *maxy)
+{
+    DisplaySurface *surface = qemu_console_surface(s->con);
+    int src_width, dest_width;
+    drawfn fn = NULL;
+    if (s->dest_width)
+        fn = s->line_fn[s->transp][s->bpp];
+    if (!fn)
+        return;
+
+    src_width = (s->xres + 3) & ~3;     /* Pad to a 4 pixels multiple */
+    if (s->bpp == pxa_lcdc_19pbpp || s->bpp == pxa_lcdc_18pbpp)
+        src_width *= 3;
+    else if (s->bpp > pxa_lcdc_16bpp)
+        src_width *= 4;
+    else if (s->bpp > pxa_lcdc_8bpp)
+        src_width *= 2;
+
+    dest_width = s->yres * s->dest_width;
+    *miny = 0;
+    framebuffer_update_display(surface, s->sysmem,
+                               addr, s->xres, s->yres,
+                               src_width, s->dest_width, -dest_width,
+                               s->invalidated,
+                               fn, s->dma_ch[0].palette,
+                               miny, maxy);
+}
+
+static void pxa2xx_lcdc_dma0_redraw_rot180(PXA2xxLCDState *s,
+                hwaddr addr, int *miny, int *maxy)
+{
+    DisplaySurface *surface = qemu_console_surface(s->con);
+    int src_width, dest_width;
+    drawfn fn = NULL;
+    if (s->dest_width) {
+        fn = s->line_fn[s->transp][s->bpp];
+    }
+    if (!fn) {
+        return;
+    }
+
+    src_width = (s->xres + 3) & ~3;     /* Pad to a 4 pixels multiple */
+    if (s->bpp == pxa_lcdc_19pbpp || s->bpp == pxa_lcdc_18pbpp) {
+        src_width *= 3;
+    } else if (s->bpp > pxa_lcdc_16bpp) {
+        src_width *= 4;
+    } else if (s->bpp > pxa_lcdc_8bpp) {
+        src_width *= 2;
+    }
+
+    dest_width = s->xres * s->dest_width;
+    *miny = 0;
+    framebuffer_update_display(surface, s->sysmem,
+                               addr, s->xres, s->yres,
+                               src_width, -dest_width, -s->dest_width,
+                               s->invalidated,
+                               fn, s->dma_ch[0].palette, miny, maxy);
+}
+
+static void pxa2xx_lcdc_dma0_redraw_rot270(PXA2xxLCDState *s,
+               hwaddr addr, int *miny, int *maxy)
+{
+    DisplaySurface *surface = qemu_console_surface(s->con);
+    int src_width, dest_width;
+    drawfn fn = NULL;
+    if (s->dest_width) {
+        fn = s->line_fn[s->transp][s->bpp];
+    }
+    if (!fn) {
+        return;
+    }
+
+    src_width = (s->xres + 3) & ~3;     /* Pad to a 4 pixels multiple */
+    if (s->bpp == pxa_lcdc_19pbpp || s->bpp == pxa_lcdc_18pbpp) {
+        src_width *= 3;
+    } else if (s->bpp > pxa_lcdc_16bpp) {
+        src_width *= 4;
+    } else if (s->bpp > pxa_lcdc_8bpp) {
+        src_width *= 2;
+    }
+
+    dest_width = s->yres * s->dest_width;
+    *miny = 0;
+    framebuffer_update_display(surface, s->sysmem,
+                               addr, s->xres, s->yres,
+                               src_width, -s->dest_width, dest_width,
+                               s->invalidated,
+                               fn, s->dma_ch[0].palette,
+                               miny, maxy);
+}
+
+static void pxa2xx_lcdc_resize(PXA2xxLCDState *s)
+{
+    int width, height;
+    if (!(s->control[0] & LCCR0_ENB))
+        return;
+
+    width = LCCR1_PPL(s->control[1]) + 1;
+    height = LCCR2_LPP(s->control[2]) + 1;
+
+    if (width != s->xres || height != s->yres) {
+        if (s->orientation == 90 || s->orientation == 270) {
+            qemu_console_resize(s->con, height, width);
+        } else {
+            qemu_console_resize(s->con, width, height);
+        }
+        s->invalidated = 1;
+        s->xres = width;
+        s->yres = height;
+    }
+}
+
+static void pxa2xx_update_display(void *opaque)
+{
+    PXA2xxLCDState *s = (PXA2xxLCDState *) opaque;
+    hwaddr fbptr;
+    int miny, maxy;
+    int ch;
+    if (!(s->control[0] & LCCR0_ENB))
+        return;
+
+    pxa2xx_descriptor_load(s);
+
+    pxa2xx_lcdc_resize(s);
+    miny = s->yres;
+    maxy = 0;
+    s->transp = s->dma_ch[2].up || s->dma_ch[3].up;
+    /* Note: With overlay planes the order depends on LCCR0 bit 25.  */
+    for (ch = 0; ch < PXA_LCDDMA_CHANS; ch ++)
+        if (s->dma_ch[ch].up) {
+            if (!s->dma_ch[ch].source) {
+                pxa2xx_dma_ber_set(s, ch);
+                continue;
+            }
+            fbptr = s->dma_ch[ch].source;
+            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;
+            }
+
+            if (s->dma_ch[ch].command & LDCMD_PAL) {
+                cpu_physical_memory_read(fbptr, s->dma_ch[ch].pbuffer,
+                    MAX(LDCMD_LENGTH(s->dma_ch[ch].command),
+                        sizeof(s->dma_ch[ch].pbuffer)));
+                pxa2xx_palette_parse(s, ch, s->bpp);
+            } else {
+                /* Do we need to reparse palette */
+                if (LCCR4_PALFOR(s->control[4]) != s->pal_for)
+                    pxa2xx_palette_parse(s, ch, s->bpp);
+
+                /* ACK frame start */
+                pxa2xx_dma_sof_set(s, ch);
+
+                s->dma_ch[ch].redraw(s, fbptr, &miny, &maxy);
+                s->invalidated = 0;
+
+                /* ACK frame completed */
+                pxa2xx_dma_eof_set(s, ch);
+            }
+        }
+
+    if (s->control[0] & LCCR0_DIS) {
+        /* ACK last frame completed */
+        s->control[0] &= ~LCCR0_ENB;
+        s->status[0] |= LCSR0_LDD;
+    }
+
+    if (miny >= 0) {
+        switch (s->orientation) {
+        case 0:
+            dpy_gfx_update(s->con, 0, miny, s->xres, maxy - miny + 1);
+            break;
+        case 90:
+            dpy_gfx_update(s->con, miny, 0, maxy - miny + 1, s->xres);
+            break;
+        case 180:
+            maxy = s->yres - maxy - 1;
+            miny = s->yres - miny - 1;
+            dpy_gfx_update(s->con, 0, maxy, s->xres, miny - maxy + 1);
+            break;
+        case 270:
+            maxy = s->yres - maxy - 1;
+            miny = s->yres - miny - 1;
+            dpy_gfx_update(s->con, maxy, 0, miny - maxy + 1, s->xres);
+            break;
+        }
+    }
+    pxa2xx_lcdc_int_update(s);
+
+    qemu_irq_raise(s->vsync_cb);
+}
+
+static void pxa2xx_invalidate_display(void *opaque)
+{
+    PXA2xxLCDState *s = (PXA2xxLCDState *) opaque;
+    s->invalidated = 1;
+}
+
+static void pxa2xx_lcdc_orientation(void *opaque, int angle)
+{
+    PXA2xxLCDState *s = (PXA2xxLCDState *) opaque;
+
+    switch (angle) {
+    case 0:
+        s->dma_ch[0].redraw = pxa2xx_lcdc_dma0_redraw_rot0;
+        break;
+    case 90:
+        s->dma_ch[0].redraw = pxa2xx_lcdc_dma0_redraw_rot90;
+        break;
+    case 180:
+        s->dma_ch[0].redraw = pxa2xx_lcdc_dma0_redraw_rot180;
+        break;
+    case 270:
+        s->dma_ch[0].redraw = pxa2xx_lcdc_dma0_redraw_rot270;
+        break;
+    }
+
+    s->orientation = angle;
+    s->xres = s->yres = -1;
+    pxa2xx_lcdc_resize(s);
+}
+
+static const VMStateDescription vmstate_dma_channel = {
+    .name = "dma_channel",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32(branch, struct DMAChannel),
+        VMSTATE_UINT8(up, struct DMAChannel),
+        VMSTATE_BUFFER(pbuffer, struct DMAChannel),
+        VMSTATE_UINT32(descriptor, struct DMAChannel),
+        VMSTATE_UINT32(source, struct DMAChannel),
+        VMSTATE_UINT32(id, struct DMAChannel),
+        VMSTATE_UINT32(command, struct DMAChannel),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int pxa2xx_lcdc_post_load(void *opaque, int version_id)
+{
+    PXA2xxLCDState *s = opaque;
+
+    s->bpp = LCCR3_BPP(s->control[3]);
+    s->xres = s->yres = s->pal_for = -1;
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_pxa2xx_lcdc = {
+    .name = "pxa2xx_lcdc",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .post_load = pxa2xx_lcdc_post_load,
+    .fields      = (VMStateField[]) {
+        VMSTATE_INT32(irqlevel, PXA2xxLCDState),
+        VMSTATE_INT32(transp, PXA2xxLCDState),
+        VMSTATE_UINT32_ARRAY(control, PXA2xxLCDState, 6),
+        VMSTATE_UINT32_ARRAY(status, PXA2xxLCDState, 2),
+        VMSTATE_UINT32_ARRAY(ovl1c, PXA2xxLCDState, 2),
+        VMSTATE_UINT32_ARRAY(ovl2c, PXA2xxLCDState, 2),
+        VMSTATE_UINT32(ccr, PXA2xxLCDState),
+        VMSTATE_UINT32(cmdcr, PXA2xxLCDState),
+        VMSTATE_UINT32(trgbr, PXA2xxLCDState),
+        VMSTATE_UINT32(tcr, PXA2xxLCDState),
+        VMSTATE_UINT32(liidr, PXA2xxLCDState),
+        VMSTATE_UINT8(bscntr, PXA2xxLCDState),
+        VMSTATE_STRUCT_ARRAY(dma_ch, PXA2xxLCDState, 7, 0,
+                             vmstate_dma_channel, struct DMAChannel),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+#define BITS 8
+#include "pxa2xx_template.h"
+#define BITS 15
+#include "pxa2xx_template.h"
+#define BITS 16
+#include "pxa2xx_template.h"
+#define BITS 24
+#include "pxa2xx_template.h"
+#define BITS 32
+#include "pxa2xx_template.h"
+
+PXA2xxLCDState *pxa2xx_lcdc_init(MemoryRegion *sysmem,
+                                 hwaddr base, qemu_irq irq)
+{
+    PXA2xxLCDState *s;
+    DisplaySurface *surface;
+
+    s = (PXA2xxLCDState *) g_malloc0(sizeof(PXA2xxLCDState));
+    s->invalidated = 1;
+    s->irq = irq;
+    s->sysmem = sysmem;
+
+    pxa2xx_lcdc_orientation(s, graphic_rotate);
+
+    memory_region_init_io(&s->iomem, &pxa2xx_lcdc_ops, s,
+                          "pxa2xx-lcd-controller", 0x00100000);
+    memory_region_add_subregion(sysmem, base, &s->iomem);
+
+    s->con = graphic_console_init(pxa2xx_update_display,
+                                  pxa2xx_invalidate_display,
+                                  NULL, NULL, s);
+    surface = qemu_console_surface(s->con);
+
+    switch (surface_bits_per_pixel(surface)) {
+    case 0:
+        s->dest_width = 0;
+        break;
+    case 8:
+        s->line_fn[0] = pxa2xx_draw_fn_8;
+        s->line_fn[1] = pxa2xx_draw_fn_8t;
+        s->dest_width = 1;
+        break;
+    case 15:
+        s->line_fn[0] = pxa2xx_draw_fn_15;
+        s->line_fn[1] = pxa2xx_draw_fn_15t;
+        s->dest_width = 2;
+        break;
+    case 16:
+        s->line_fn[0] = pxa2xx_draw_fn_16;
+        s->line_fn[1] = pxa2xx_draw_fn_16t;
+        s->dest_width = 2;
+        break;
+    case 24:
+        s->line_fn[0] = pxa2xx_draw_fn_24;
+        s->line_fn[1] = pxa2xx_draw_fn_24t;
+        s->dest_width = 3;
+        break;
+    case 32:
+        s->line_fn[0] = pxa2xx_draw_fn_32;
+        s->line_fn[1] = pxa2xx_draw_fn_32t;
+        s->dest_width = 4;
+        break;
+    default:
+        fprintf(stderr, "%s: Bad color depth\n", __FUNCTION__);
+        exit(1);
+    }
+
+    vmstate_register(NULL, 0, &vmstate_pxa2xx_lcdc, s);
+
+    return s;
+}
+
+void pxa2xx_lcd_vsync_notifier(PXA2xxLCDState *s, qemu_irq handler)
+{
+    s->vsync_cb = handler;
+}
diff --git a/hw/display/pxa2xx_template.h b/hw/display/pxa2xx_template.h
new file mode 100644 (file)
index 0000000..1cbe36c
--- /dev/null
@@ -0,0 +1,435 @@
+/*
+ * Intel XScale PXA255/270 LCDC emulation.
+ *
+ * Copyright (c) 2006 Openedhand Ltd.
+ * Written by Andrzej Zaborowski <balrog@zabor.org>
+ *
+ * This code is licensed under the GPLv2.
+ *
+ * Framebuffer format conversion routines.
+ */
+
+# define SKIP_PIXEL(to)                to += deststep
+#if BITS == 8
+# define COPY_PIXEL(to, from)  *to = from; SKIP_PIXEL(to)
+#elif BITS == 15 || BITS == 16
+# define COPY_PIXEL(to, from)  *(uint16_t *) to = from; SKIP_PIXEL(to)
+#elif BITS == 24
+# define COPY_PIXEL(to, from)  \
+       *(uint16_t *) to = from; *(to + 2) = (from) >> 16; SKIP_PIXEL(to)
+#elif BITS == 32
+# define COPY_PIXEL(to, from)  *(uint32_t *) to = from; SKIP_PIXEL(to)
+#else
+# error unknown bit depth
+#endif
+
+#ifdef HOST_WORDS_BIGENDIAN
+# define SWAP_WORDS    1
+#endif
+
+#define FN_2(x)                FN(x + 1) FN(x)
+#define FN_4(x)                FN_2(x + 2) FN_2(x)
+
+static void glue(pxa2xx_draw_line2_, BITS)(void *opaque,
+                uint8_t *dest, const uint8_t *src, int width, int deststep)
+{
+    uint32_t *palette = opaque;
+    uint32_t data;
+    while (width > 0) {
+        data = *(uint32_t *) src;
+#define FN(x)          COPY_PIXEL(dest, palette[(data >> ((x) * 2)) & 3]);
+#ifdef SWAP_WORDS
+        FN_4(12)
+        FN_4(8)
+        FN_4(4)
+        FN_4(0)
+#else
+        FN_4(0)
+        FN_4(4)
+        FN_4(8)
+        FN_4(12)
+#endif
+#undef FN
+        width -= 16;
+        src += 4;
+    }
+}
+
+static void glue(pxa2xx_draw_line4_, BITS)(void *opaque,
+                uint8_t *dest, const uint8_t *src, int width, int deststep)
+{
+    uint32_t *palette = opaque;
+    uint32_t data;
+    while (width > 0) {
+        data = *(uint32_t *) src;
+#define FN(x)          COPY_PIXEL(dest, palette[(data >> ((x) * 4)) & 0xf]);
+#ifdef SWAP_WORDS
+        FN_2(6)
+        FN_2(4)
+        FN_2(2)
+        FN_2(0)
+#else
+        FN_2(0)
+        FN_2(2)
+        FN_2(4)
+        FN_2(6)
+#endif
+#undef FN
+        width -= 8;
+        src += 4;
+    }
+}
+
+static void glue(pxa2xx_draw_line8_, BITS)(void *opaque,
+                uint8_t *dest, const uint8_t *src, int width, int deststep)
+{
+    uint32_t *palette = opaque;
+    uint32_t data;
+    while (width > 0) {
+        data = *(uint32_t *) src;
+#define FN(x)          COPY_PIXEL(dest, palette[(data >> (x)) & 0xff]);
+#ifdef SWAP_WORDS
+        FN(24)
+        FN(16)
+        FN(8)
+        FN(0)
+#else
+        FN(0)
+        FN(8)
+        FN(16)
+        FN(24)
+#endif
+#undef FN
+        width -= 4;
+        src += 4;
+    }
+}
+
+static void glue(pxa2xx_draw_line16_, BITS)(void *opaque,
+                uint8_t *dest, const uint8_t *src, int width, int deststep)
+{
+    uint32_t data;
+    unsigned int r, g, b;
+    while (width > 0) {
+        data = *(uint32_t *) src;
+#ifdef SWAP_WORDS
+        data = bswap32(data);
+#endif
+        b = (data & 0x1f) << 3;
+        data >>= 5;
+        g = (data & 0x3f) << 2;
+        data >>= 6;
+        r = (data & 0x1f) << 3;
+        data >>= 5;
+        COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
+        b = (data & 0x1f) << 3;
+        data >>= 5;
+        g = (data & 0x3f) << 2;
+        data >>= 6;
+        r = (data & 0x1f) << 3;
+        COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
+        width -= 2;
+        src += 4;
+    }
+}
+
+static void glue(pxa2xx_draw_line16t_, BITS)(void *opaque,
+                uint8_t *dest, const uint8_t *src, int width, int deststep)
+{
+    uint32_t data;
+    unsigned int r, g, b;
+    while (width > 0) {
+        data = *(uint32_t *) src;
+#ifdef SWAP_WORDS
+        data = bswap32(data);
+#endif
+        b = (data & 0x1f) << 3;
+        data >>= 5;
+        g = (data & 0x1f) << 3;
+        data >>= 5;
+        r = (data & 0x1f) << 3;
+        data >>= 5;
+        if (data & 1)
+            SKIP_PIXEL(dest);
+        else
+            COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
+        data >>= 1;
+        b = (data & 0x1f) << 3;
+        data >>= 5;
+        g = (data & 0x1f) << 3;
+        data >>= 5;
+        r = (data & 0x1f) << 3;
+        data >>= 5;
+        if (data & 1)
+            SKIP_PIXEL(dest);
+        else
+            COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
+        width -= 2;
+        src += 4;
+    }
+}
+
+static void glue(pxa2xx_draw_line18_, BITS)(void *opaque,
+                uint8_t *dest, const uint8_t *src, int width, int deststep)
+{
+    uint32_t data;
+    unsigned int r, g, b;
+    while (width > 0) {
+        data = *(uint32_t *) src;
+#ifdef SWAP_WORDS
+        data = bswap32(data);
+#endif
+        b = (data & 0x3f) << 2;
+        data >>= 6;
+        g = (data & 0x3f) << 2;
+        data >>= 6;
+        r = (data & 0x3f) << 2;
+        COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
+        width -= 1;
+        src += 4;
+    }
+}
+
+/* The wicked packed format */
+static void glue(pxa2xx_draw_line18p_, BITS)(void *opaque,
+                uint8_t *dest, const uint8_t *src, int width, int deststep)
+{
+    uint32_t data[3];
+    unsigned int r, g, b;
+    while (width > 0) {
+        data[0] = *(uint32_t *) src;
+        src += 4;
+        data[1] = *(uint32_t *) src;
+        src += 4;
+        data[2] = *(uint32_t *) src;
+        src += 4;
+#ifdef SWAP_WORDS
+        data[0] = bswap32(data[0]);
+        data[1] = bswap32(data[1]);
+        data[2] = bswap32(data[2]);
+#endif
+        b = (data[0] & 0x3f) << 2;
+        data[0] >>= 6;
+        g = (data[0] & 0x3f) << 2;
+        data[0] >>= 6;
+        r = (data[0] & 0x3f) << 2;
+        data[0] >>= 12;
+        COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
+        b = (data[0] & 0x3f) << 2;
+        data[0] >>= 6;
+        g = ((data[1] & 0xf) << 4) | (data[0] << 2);
+        data[1] >>= 4;
+        r = (data[1] & 0x3f) << 2;
+        data[1] >>= 12;
+        COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
+        b = (data[1] & 0x3f) << 2;
+        data[1] >>= 6;
+        g = (data[1] & 0x3f) << 2;
+        data[1] >>= 6;
+        r = ((data[2] & 0x3) << 6) | (data[1] << 2);
+        data[2] >>= 8;
+        COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
+        b = (data[2] & 0x3f) << 2;
+        data[2] >>= 6;
+        g = (data[2] & 0x3f) << 2;
+        data[2] >>= 6;
+        r = data[2] << 2;
+        COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
+        width -= 4;
+    }
+}
+
+static void glue(pxa2xx_draw_line19_, BITS)(void *opaque,
+                uint8_t *dest, const uint8_t *src, int width, int deststep)
+{
+    uint32_t data;
+    unsigned int r, g, b;
+    while (width > 0) {
+        data = *(uint32_t *) src;
+#ifdef SWAP_WORDS
+        data = bswap32(data);
+#endif
+        b = (data & 0x3f) << 2;
+        data >>= 6;
+        g = (data & 0x3f) << 2;
+        data >>= 6;
+        r = (data & 0x3f) << 2;
+        data >>= 6;
+        if (data & 1)
+            SKIP_PIXEL(dest);
+        else
+            COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
+        width -= 1;
+        src += 4;
+    }
+}
+
+/* The wicked packed format */
+static void glue(pxa2xx_draw_line19p_, BITS)(void *opaque,
+                uint8_t *dest, const uint8_t *src, int width, int deststep)
+{
+    uint32_t data[3];
+    unsigned int r, g, b;
+    while (width > 0) {
+        data[0] = *(uint32_t *) src;
+        src += 4;
+        data[1] = *(uint32_t *) src;
+        src += 4;
+        data[2] = *(uint32_t *) src;
+        src += 4;
+# ifdef SWAP_WORDS
+        data[0] = bswap32(data[0]);
+        data[1] = bswap32(data[1]);
+        data[2] = bswap32(data[2]);
+# endif
+        b = (data[0] & 0x3f) << 2;
+        data[0] >>= 6;
+        g = (data[0] & 0x3f) << 2;
+        data[0] >>= 6;
+        r = (data[0] & 0x3f) << 2;
+        data[0] >>= 6;
+        if (data[0] & 1)
+            SKIP_PIXEL(dest);
+        else
+            COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
+        data[0] >>= 6;
+        b = (data[0] & 0x3f) << 2;
+        data[0] >>= 6;
+        g = ((data[1] & 0xf) << 4) | (data[0] << 2);
+        data[1] >>= 4;
+        r = (data[1] & 0x3f) << 2;
+        data[1] >>= 6;
+        if (data[1] & 1)
+            SKIP_PIXEL(dest);
+        else
+            COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
+        data[1] >>= 6;
+        b = (data[1] & 0x3f) << 2;
+        data[1] >>= 6;
+        g = (data[1] & 0x3f) << 2;
+        data[1] >>= 6;
+        r = ((data[2] & 0x3) << 6) | (data[1] << 2);
+        data[2] >>= 2;
+        if (data[2] & 1)
+            SKIP_PIXEL(dest);
+        else
+            COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
+        data[2] >>= 6;
+        b = (data[2] & 0x3f) << 2;
+        data[2] >>= 6;
+        g = (data[2] & 0x3f) << 2;
+        data[2] >>= 6;
+        r = data[2] << 2;
+        data[2] >>= 6;
+        if (data[2] & 1)
+            SKIP_PIXEL(dest);
+        else
+            COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
+        width -= 4;
+    }
+}
+
+static void glue(pxa2xx_draw_line24_, BITS)(void *opaque,
+                uint8_t *dest, const uint8_t *src, int width, int deststep)
+{
+    uint32_t data;
+    unsigned int r, g, b;
+    while (width > 0) {
+        data = *(uint32_t *) src;
+#ifdef SWAP_WORDS
+        data = bswap32(data);
+#endif
+        b = data & 0xff;
+        data >>= 8;
+        g = data & 0xff;
+        data >>= 8;
+        r = data & 0xff;
+        COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
+        width -= 1;
+        src += 4;
+    }
+}
+
+static void glue(pxa2xx_draw_line24t_, BITS)(void *opaque,
+                uint8_t *dest, const uint8_t *src, int width, int deststep)
+{
+    uint32_t data;
+    unsigned int r, g, b;
+    while (width > 0) {
+        data = *(uint32_t *) src;
+#ifdef SWAP_WORDS
+        data = bswap32(data);
+#endif
+        b = (data & 0x7f) << 1;
+        data >>= 7;
+        g = data & 0xff;
+        data >>= 8;
+        r = data & 0xff;
+        data >>= 8;
+        if (data & 1)
+            SKIP_PIXEL(dest);
+        else
+            COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
+        width -= 1;
+        src += 4;
+    }
+}
+
+static void glue(pxa2xx_draw_line25_, BITS)(void *opaque,
+                uint8_t *dest, const uint8_t *src, int width, int deststep)
+{
+    uint32_t data;
+    unsigned int r, g, b;
+    while (width > 0) {
+        data = *(uint32_t *) src;
+#ifdef SWAP_WORDS
+        data = bswap32(data);
+#endif
+        b = data & 0xff;
+        data >>= 8;
+        g = data & 0xff;
+        data >>= 8;
+        r = data & 0xff;
+        data >>= 8;
+        if (data & 1)
+            SKIP_PIXEL(dest);
+        else
+            COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
+        width -= 1;
+        src += 4;
+    }
+}
+
+/* Overlay planes disabled, no transparency */
+static drawfn glue(pxa2xx_draw_fn_, BITS)[16] =
+{
+    [0 ... 0xf]       = NULL,
+    [pxa_lcdc_2bpp]   = glue(pxa2xx_draw_line2_, BITS),
+    [pxa_lcdc_4bpp]   = glue(pxa2xx_draw_line4_, BITS),
+    [pxa_lcdc_8bpp]   = glue(pxa2xx_draw_line8_, BITS),
+    [pxa_lcdc_16bpp]  = glue(pxa2xx_draw_line16_, BITS),
+    [pxa_lcdc_18bpp]  = glue(pxa2xx_draw_line18_, BITS),
+    [pxa_lcdc_18pbpp] = glue(pxa2xx_draw_line18p_, BITS),
+    [pxa_lcdc_24bpp]  = glue(pxa2xx_draw_line24_, BITS),
+};
+
+/* Overlay planes enabled, transparency used */
+static drawfn glue(glue(pxa2xx_draw_fn_, BITS), t)[16] =
+{
+    [0 ... 0xf]       = NULL,
+    [pxa_lcdc_4bpp]   = glue(pxa2xx_draw_line4_, BITS),
+    [pxa_lcdc_8bpp]   = glue(pxa2xx_draw_line8_, BITS),
+    [pxa_lcdc_16bpp]  = glue(pxa2xx_draw_line16t_, BITS),
+    [pxa_lcdc_19bpp]  = glue(pxa2xx_draw_line19_, BITS),
+    [pxa_lcdc_19pbpp] = glue(pxa2xx_draw_line19p_, BITS),
+    [pxa_lcdc_24bpp]  = glue(pxa2xx_draw_line24t_, BITS),
+    [pxa_lcdc_25bpp]  = glue(pxa2xx_draw_line25_, BITS),
+};
+
+#undef BITS
+#undef COPY_PIXEL
+#undef SKIP_PIXEL
+
+#ifdef SWAP_WORDS
+# undef SWAP_WORDS
+#endif
diff --git a/hw/display/qxl-logger.c b/hw/display/qxl-logger.c
new file mode 100644 (file)
index 0000000..3cd85d9
--- /dev/null
@@ -0,0 +1,275 @@
+/*
+ * qxl command logging -- for debug purposes
+ *
+ * Copyright (C) 2010 Red Hat, Inc.
+ *
+ * maintained by Gerd Hoffmann <kraxel@redhat.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 or
+ * (at your option) version 3 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
+ * 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/timer.h"
+#include "qxl.h"
+
+static const char *qxl_type[] = {
+    [ QXL_CMD_NOP ]     = "nop",
+    [ QXL_CMD_DRAW ]    = "draw",
+    [ QXL_CMD_UPDATE ]  = "update",
+    [ QXL_CMD_CURSOR ]  = "cursor",
+    [ QXL_CMD_MESSAGE ] = "message",
+    [ QXL_CMD_SURFACE ] = "surface",
+};
+
+static const char *qxl_draw_type[] = {
+    [ QXL_DRAW_NOP         ] = "nop",
+    [ QXL_DRAW_FILL        ] = "fill",
+    [ QXL_DRAW_OPAQUE      ] = "opaque",
+    [ QXL_DRAW_COPY        ] = "copy",
+    [ QXL_COPY_BITS        ] = "copy-bits",
+    [ QXL_DRAW_BLEND       ] = "blend",
+    [ QXL_DRAW_BLACKNESS   ] = "blackness",
+    [ QXL_DRAW_WHITENESS   ] = "whitemess",
+    [ QXL_DRAW_INVERS      ] = "invers",
+    [ QXL_DRAW_ROP3        ] = "rop3",
+    [ QXL_DRAW_STROKE      ] = "stroke",
+    [ QXL_DRAW_TEXT        ] = "text",
+    [ QXL_DRAW_TRANSPARENT ] = "transparent",
+    [ QXL_DRAW_ALPHA_BLEND ] = "alpha-blend",
+};
+
+static const char *qxl_draw_effect[] = {
+    [ QXL_EFFECT_BLEND            ] = "blend",
+    [ QXL_EFFECT_OPAQUE           ] = "opaque",
+    [ QXL_EFFECT_REVERT_ON_DUP    ] = "revert-on-dup",
+    [ QXL_EFFECT_BLACKNESS_ON_DUP ] = "blackness-on-dup",
+    [ QXL_EFFECT_WHITENESS_ON_DUP ] = "whiteness-on-dup",
+    [ QXL_EFFECT_NOP_ON_DUP       ] = "nop-on-dup",
+    [ QXL_EFFECT_NOP              ] = "nop",
+    [ QXL_EFFECT_OPAQUE_BRUSH     ] = "opaque-brush",
+};
+
+static const char *qxl_surface_cmd[] = {
+   [ QXL_SURFACE_CMD_CREATE  ] = "create",
+   [ QXL_SURFACE_CMD_DESTROY ] = "destroy",
+};
+
+static const char *spice_surface_fmt[] = {
+   [ SPICE_SURFACE_FMT_INVALID  ] = "invalid",
+   [ SPICE_SURFACE_FMT_1_A      ] = "alpha/1",
+   [ SPICE_SURFACE_FMT_8_A      ] = "alpha/8",
+   [ SPICE_SURFACE_FMT_16_555   ] = "555/16",
+   [ SPICE_SURFACE_FMT_16_565   ] = "565/16",
+   [ SPICE_SURFACE_FMT_32_xRGB  ] = "xRGB/32",
+   [ SPICE_SURFACE_FMT_32_ARGB  ] = "ARGB/32",
+};
+
+static const char *qxl_cursor_cmd[] = {
+   [ QXL_CURSOR_SET   ] = "set",
+   [ QXL_CURSOR_MOVE  ] = "move",
+   [ QXL_CURSOR_HIDE  ] = "hide",
+   [ QXL_CURSOR_TRAIL ] = "trail",
+};
+
+static const char *spice_cursor_type[] = {
+   [ SPICE_CURSOR_TYPE_ALPHA   ] = "alpha",
+   [ SPICE_CURSOR_TYPE_MONO    ] = "mono",
+   [ SPICE_CURSOR_TYPE_COLOR4  ] = "color4",
+   [ SPICE_CURSOR_TYPE_COLOR8  ] = "color8",
+   [ SPICE_CURSOR_TYPE_COLOR16 ] = "color16",
+   [ SPICE_CURSOR_TYPE_COLOR24 ] = "color24",
+   [ SPICE_CURSOR_TYPE_COLOR32 ] = "color32",
+};
+
+static const char *qxl_v2n(const char *n[], size_t l, int v)
+{
+    if (v >= l || !n[v]) {
+        return "???";
+    }
+    return n[v];
+}
+#define qxl_name(_list, _value) qxl_v2n(_list, ARRAY_SIZE(_list), _value)
+
+static int qxl_log_image(PCIQXLDevice *qxl, QXLPHYSICAL addr, int group_id)
+{
+    QXLImage *image;
+    QXLImageDescriptor *desc;
+
+    image = qxl_phys2virt(qxl, addr, group_id);
+    if (!image) {
+        return 1;
+    }
+    desc = &image->descriptor;
+    fprintf(stderr, " (id %" PRIx64 " type %d flags %d width %d height %d",
+            desc->id, desc->type, desc->flags, desc->width, desc->height);
+    switch (desc->type) {
+    case SPICE_IMAGE_TYPE_BITMAP:
+        fprintf(stderr, ", fmt %d flags %d x %d y %d stride %d"
+                " palette %" PRIx64 " data %" PRIx64,
+                image->bitmap.format, image->bitmap.flags,
+                image->bitmap.x, image->bitmap.y,
+                image->bitmap.stride,
+                image->bitmap.palette, image->bitmap.data);
+        break;
+    }
+    fprintf(stderr, ")");
+    return 0;
+}
+
+static void qxl_log_rect(QXLRect *rect)
+{
+    fprintf(stderr, " %dx%d+%d+%d",
+            rect->right - rect->left,
+            rect->bottom - rect->top,
+            rect->left, rect->top);
+}
+
+static int qxl_log_cmd_draw_copy(PCIQXLDevice *qxl, QXLCopy *copy,
+                                 int group_id)
+{
+    int ret;
+
+    fprintf(stderr, " src %" PRIx64,
+            copy->src_bitmap);
+    ret = qxl_log_image(qxl, copy->src_bitmap, group_id);
+    if (ret != 0) {
+        return ret;
+    }
+    fprintf(stderr, " area");
+    qxl_log_rect(&copy->src_area);
+    fprintf(stderr, " rop %d", copy->rop_descriptor);
+    return 0;
+}
+
+static int qxl_log_cmd_draw(PCIQXLDevice *qxl, QXLDrawable *draw, int group_id)
+{
+    fprintf(stderr, ": surface_id %d type %s effect %s",
+            draw->surface_id,
+            qxl_name(qxl_draw_type, draw->type),
+            qxl_name(qxl_draw_effect, draw->effect));
+    switch (draw->type) {
+    case QXL_DRAW_COPY:
+        return qxl_log_cmd_draw_copy(qxl, &draw->u.copy, group_id);
+        break;
+    }
+    return 0;
+}
+
+static int qxl_log_cmd_draw_compat(PCIQXLDevice *qxl, QXLCompatDrawable *draw,
+                                   int group_id)
+{
+    fprintf(stderr, ": type %s effect %s",
+            qxl_name(qxl_draw_type, draw->type),
+            qxl_name(qxl_draw_effect, draw->effect));
+    if (draw->bitmap_offset) {
+        fprintf(stderr, ": bitmap %d",
+                draw->bitmap_offset);
+        qxl_log_rect(&draw->bitmap_area);
+    }
+    switch (draw->type) {
+    case QXL_DRAW_COPY:
+        return qxl_log_cmd_draw_copy(qxl, &draw->u.copy, group_id);
+        break;
+    }
+    return 0;
+}
+
+static void qxl_log_cmd_surface(PCIQXLDevice *qxl, QXLSurfaceCmd *cmd)
+{
+    fprintf(stderr, ": %s id %d",
+            qxl_name(qxl_surface_cmd, cmd->type),
+            cmd->surface_id);
+    if (cmd->type == QXL_SURFACE_CMD_CREATE) {
+        fprintf(stderr, " size %dx%d stride %d format %s (count %d, max %d)",
+                cmd->u.surface_create.width,
+                cmd->u.surface_create.height,
+                cmd->u.surface_create.stride,
+                qxl_name(spice_surface_fmt, cmd->u.surface_create.format),
+                qxl->guest_surfaces.count, qxl->guest_surfaces.max);
+    }
+    if (cmd->type == QXL_SURFACE_CMD_DESTROY) {
+        fprintf(stderr, " (count %d)", qxl->guest_surfaces.count);
+    }
+}
+
+int qxl_log_cmd_cursor(PCIQXLDevice *qxl, QXLCursorCmd *cmd, int group_id)
+{
+    QXLCursor *cursor;
+
+    fprintf(stderr, ": %s",
+            qxl_name(qxl_cursor_cmd, cmd->type));
+    switch (cmd->type) {
+    case QXL_CURSOR_SET:
+        fprintf(stderr, " +%d+%d visible %s, shape @ 0x%" PRIx64,
+                cmd->u.set.position.x,
+                cmd->u.set.position.y,
+                cmd->u.set.visible ? "yes" : "no",
+                cmd->u.set.shape);
+        cursor = qxl_phys2virt(qxl, cmd->u.set.shape, group_id);
+        if (!cursor) {
+            return 1;
+        }
+        fprintf(stderr, " type %s size %dx%d hot-spot +%d+%d"
+                " unique 0x%" PRIx64 " data-size %d",
+                qxl_name(spice_cursor_type, cursor->header.type),
+                cursor->header.width, cursor->header.height,
+                cursor->header.hot_spot_x, cursor->header.hot_spot_y,
+                cursor->header.unique, cursor->data_size);
+        break;
+    case QXL_CURSOR_MOVE:
+        fprintf(stderr, " +%d+%d", cmd->u.position.x, cmd->u.position.y);
+        break;
+    }
+    return 0;
+}
+
+int qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext)
+{
+    bool compat = ext->flags & QXL_COMMAND_FLAG_COMPAT;
+    void *data;
+    int ret;
+
+    if (!qxl->cmdlog) {
+        return 0;
+    }
+    fprintf(stderr, "%" PRId64 " qxl-%d/%s:", qemu_get_clock_ns(vm_clock),
+            qxl->id, ring);
+    fprintf(stderr, " cmd @ 0x%" PRIx64 " %s%s", ext->cmd.data,
+            qxl_name(qxl_type, ext->cmd.type),
+            compat ? "(compat)" : "");
+
+    data = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id);
+    if (!data) {
+        return 1;
+    }
+    switch (ext->cmd.type) {
+    case QXL_CMD_DRAW:
+        if (!compat) {
+            ret = qxl_log_cmd_draw(qxl, data, ext->group_id);
+        } else {
+            ret = qxl_log_cmd_draw_compat(qxl, data, ext->group_id);
+        }
+        if (ret) {
+            return ret;
+        }
+        break;
+    case QXL_CMD_SURFACE:
+        qxl_log_cmd_surface(qxl, data);
+        break;
+    case QXL_CMD_CURSOR:
+        qxl_log_cmd_cursor(qxl, data, ext->group_id);
+        break;
+    }
+    fprintf(stderr, "\n");
+    return 0;
+}
diff --git a/hw/display/qxl-render.c b/hw/display/qxl-render.c
new file mode 100644 (file)
index 0000000..f511a62
--- /dev/null
@@ -0,0 +1,280 @@
+/*
+ * qxl local rendering (aka display on sdl/vnc)
+ *
+ * Copyright (C) 2010 Red Hat, Inc.
+ *
+ * maintained by Gerd Hoffmann <kraxel@redhat.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 or
+ * (at your option) version 3 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
+ * 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 "qxl.h"
+
+static void qxl_blit(PCIQXLDevice *qxl, QXLRect *rect)
+{
+    DisplaySurface *surface = qemu_console_surface(qxl->vga.con);
+    uint8_t *dst = surface_data(surface);
+    uint8_t *src;
+    int len, i;
+
+    if (is_buffer_shared(surface)) {
+        return;
+    }
+    if (!qxl->guest_primary.data) {
+        trace_qxl_render_blit_guest_primary_initialized();
+        qxl->guest_primary.data = memory_region_get_ram_ptr(&qxl->vga.vram);
+    }
+    trace_qxl_render_blit(qxl->guest_primary.qxl_stride,
+            rect->left, rect->right, rect->top, rect->bottom);
+    src = qxl->guest_primary.data;
+    if (qxl->guest_primary.qxl_stride < 0) {
+        /* qxl surface is upside down, walk src scanlines
+         * in reverse order to flip it */
+        src += (qxl->guest_primary.surface.height - rect->top - 1) *
+            qxl->guest_primary.abs_stride;
+    } else {
+        src += rect->top * qxl->guest_primary.abs_stride;
+    }
+    dst += rect->top  * qxl->guest_primary.abs_stride;
+    src += rect->left * qxl->guest_primary.bytes_pp;
+    dst += rect->left * qxl->guest_primary.bytes_pp;
+    len  = (rect->right - rect->left) * qxl->guest_primary.bytes_pp;
+
+    for (i = rect->top; i < rect->bottom; i++) {
+        memcpy(dst, src, len);
+        dst += qxl->guest_primary.abs_stride;
+        src += qxl->guest_primary.qxl_stride;
+    }
+}
+
+void qxl_render_resize(PCIQXLDevice *qxl)
+{
+    QXLSurfaceCreate *sc = &qxl->guest_primary.surface;
+
+    qxl->guest_primary.qxl_stride = sc->stride;
+    qxl->guest_primary.abs_stride = abs(sc->stride);
+    qxl->guest_primary.resized++;
+    switch (sc->format) {
+    case SPICE_SURFACE_FMT_16_555:
+        qxl->guest_primary.bytes_pp = 2;
+        qxl->guest_primary.bits_pp = 15;
+        break;
+    case SPICE_SURFACE_FMT_16_565:
+        qxl->guest_primary.bytes_pp = 2;
+        qxl->guest_primary.bits_pp = 16;
+        break;
+    case SPICE_SURFACE_FMT_32_xRGB:
+    case SPICE_SURFACE_FMT_32_ARGB:
+        qxl->guest_primary.bytes_pp = 4;
+        qxl->guest_primary.bits_pp = 32;
+        break;
+    default:
+        fprintf(stderr, "%s: unhandled format: %x\n", __FUNCTION__,
+                qxl->guest_primary.surface.format);
+        qxl->guest_primary.bytes_pp = 4;
+        qxl->guest_primary.bits_pp = 32;
+        break;
+    }
+}
+
+static void qxl_set_rect_to_surface(PCIQXLDevice *qxl, QXLRect *area)
+{
+    area->left   = 0;
+    area->right  = qxl->guest_primary.surface.width;
+    area->top    = 0;
+    area->bottom = qxl->guest_primary.surface.height;
+}
+
+static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl)
+{
+    VGACommonState *vga = &qxl->vga;
+    DisplaySurface *surface;
+    int i;
+
+    if (qxl->guest_primary.resized) {
+        qxl->guest_primary.resized = 0;
+        qxl->guest_primary.data = memory_region_get_ram_ptr(&qxl->vga.vram);
+        qxl_set_rect_to_surface(qxl, &qxl->dirty[0]);
+        qxl->num_dirty_rects = 1;
+        trace_qxl_render_guest_primary_resized(
+               qxl->guest_primary.surface.width,
+               qxl->guest_primary.surface.height,
+               qxl->guest_primary.qxl_stride,
+               qxl->guest_primary.bytes_pp,
+               qxl->guest_primary.bits_pp);
+        if (qxl->guest_primary.qxl_stride > 0) {
+            surface = qemu_create_displaysurface_from
+                (qxl->guest_primary.surface.width,
+                 qxl->guest_primary.surface.height,
+                 qxl->guest_primary.bits_pp,
+                 qxl->guest_primary.abs_stride,
+                 qxl->guest_primary.data,
+                 false);
+        } else {
+            surface = qemu_create_displaysurface
+                (qxl->guest_primary.surface.width,
+                 qxl->guest_primary.surface.height);
+        }
+        dpy_gfx_replace_surface(vga->con, surface);
+    }
+    for (i = 0; i < qxl->num_dirty_rects; i++) {
+        if (qemu_spice_rect_is_empty(qxl->dirty+i)) {
+            break;
+        }
+        qxl_blit(qxl, qxl->dirty+i);
+        dpy_gfx_update(vga->con,
+                       qxl->dirty[i].left, qxl->dirty[i].top,
+                       qxl->dirty[i].right - qxl->dirty[i].left,
+                       qxl->dirty[i].bottom - qxl->dirty[i].top);
+    }
+    qxl->num_dirty_rects = 0;
+}
+
+/*
+ * use ssd.lock to protect render_update_cookie_num.
+ * qxl_render_update is called by io thread or vcpu thread, and the completion
+ * callbacks are called by spice_server thread, defering to bh called from the
+ * io thread.
+ */
+void qxl_render_update(PCIQXLDevice *qxl)
+{
+    QXLCookie *cookie;
+
+    qemu_mutex_lock(&qxl->ssd.lock);
+
+    if (!runstate_is_running() || !qxl->guest_primary.commands) {
+        qxl_render_update_area_unlocked(qxl);
+        qemu_mutex_unlock(&qxl->ssd.lock);
+        return;
+    }
+
+    qxl->guest_primary.commands = 0;
+    qxl->render_update_cookie_num++;
+    qemu_mutex_unlock(&qxl->ssd.lock);
+    cookie = qxl_cookie_new(QXL_COOKIE_TYPE_RENDER_UPDATE_AREA,
+                            0);
+    qxl_set_rect_to_surface(qxl, &cookie->u.render.area);
+    qxl_spice_update_area(qxl, 0, &cookie->u.render.area, NULL,
+                          0, 1 /* clear_dirty_region */, QXL_ASYNC, cookie);
+}
+
+void qxl_render_update_area_bh(void *opaque)
+{
+    PCIQXLDevice *qxl = opaque;
+
+    qemu_mutex_lock(&qxl->ssd.lock);
+    qxl_render_update_area_unlocked(qxl);
+    qemu_mutex_unlock(&qxl->ssd.lock);
+}
+
+void qxl_render_update_area_done(PCIQXLDevice *qxl, QXLCookie *cookie)
+{
+    qemu_mutex_lock(&qxl->ssd.lock);
+    trace_qxl_render_update_area_done(cookie);
+    qemu_bh_schedule(qxl->update_area_bh);
+    qxl->render_update_cookie_num--;
+    qemu_mutex_unlock(&qxl->ssd.lock);
+    g_free(cookie);
+}
+
+static QEMUCursor *qxl_cursor(PCIQXLDevice *qxl, QXLCursor *cursor)
+{
+    QEMUCursor *c;
+    uint8_t *image, *mask;
+    size_t size;
+
+    c = cursor_alloc(cursor->header.width, cursor->header.height);
+    c->hot_x = cursor->header.hot_spot_x;
+    c->hot_y = cursor->header.hot_spot_y;
+    switch (cursor->header.type) {
+    case SPICE_CURSOR_TYPE_ALPHA:
+        size = cursor->header.width * cursor->header.height * sizeof(uint32_t);
+        memcpy(c->data, cursor->chunk.data, size);
+        if (qxl->debug > 2) {
+            cursor_print_ascii_art(c, "qxl/alpha");
+        }
+        break;
+    case SPICE_CURSOR_TYPE_MONO:
+        mask  = cursor->chunk.data;
+        image = mask + cursor_get_mono_bpl(c) * c->width;
+        cursor_set_mono(c, 0xffffff, 0x000000, image, 1, mask);
+        if (qxl->debug > 2) {
+            cursor_print_ascii_art(c, "qxl/mono");
+        }
+        break;
+    default:
+        fprintf(stderr, "%s: not implemented: type %d\n",
+                __FUNCTION__, cursor->header.type);
+        goto fail;
+    }
+    return c;
+
+fail:
+    cursor_put(c);
+    return NULL;
+}
+
+
+/* called from spice server thread context only */
+int qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext)
+{
+    QXLCursorCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id);
+    QXLCursor *cursor;
+    QEMUCursor *c;
+
+    if (!cmd) {
+        return 1;
+    }
+
+    if (!dpy_cursor_define_supported(qxl->vga.con)) {
+        return 0;
+    }
+
+    if (qxl->debug > 1 && cmd->type != QXL_CURSOR_MOVE) {
+        fprintf(stderr, "%s", __FUNCTION__);
+        qxl_log_cmd_cursor(qxl, cmd, ext->group_id);
+        fprintf(stderr, "\n");
+    }
+    switch (cmd->type) {
+    case QXL_CURSOR_SET:
+        cursor = qxl_phys2virt(qxl, cmd->u.set.shape, ext->group_id);
+        if (!cursor) {
+            return 1;
+        }
+        if (cursor->chunk.data_size != cursor->data_size) {
+            fprintf(stderr, "%s: multiple chunks\n", __FUNCTION__);
+            return 1;
+        }
+        c = qxl_cursor(qxl, cursor);
+        if (c == NULL) {
+            c = cursor_builtin_left_ptr();
+        }
+        qemu_mutex_lock(&qxl->ssd.lock);
+        if (qxl->ssd.cursor) {
+            cursor_put(qxl->ssd.cursor);
+        }
+        qxl->ssd.cursor = c;
+        qxl->ssd.mouse_x = cmd->u.set.position.x;
+        qxl->ssd.mouse_y = cmd->u.set.position.y;
+        qemu_mutex_unlock(&qxl->ssd.lock);
+        break;
+    case QXL_CURSOR_MOVE:
+        qemu_mutex_lock(&qxl->ssd.lock);
+        qxl->ssd.mouse_x = cmd->u.position.x;
+        qxl->ssd.mouse_y = cmd->u.position.y;
+        qemu_mutex_unlock(&qxl->ssd.lock);
+        break;
+    }
+    return 0;
+}
diff --git a/hw/display/qxl.c b/hw/display/qxl.c
new file mode 100644 (file)
index 0000000..930b7cf
--- /dev/null
@@ -0,0 +1,2365 @@
+/*
+ * Copyright (C) 2010 Red Hat, Inc.
+ *
+ * written by Yaniv Kamay, Izik Eidus, Gerd Hoffmann
+ * maintained by Gerd Hoffmann <kraxel@redhat.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 or
+ * (at your option) version 3 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
+ * 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 <zlib.h>
+
+#include "qemu-common.h"
+#include "qemu/timer.h"
+#include "qemu/queue.h"
+#include "monitor/monitor.h"
+#include "sysemu/sysemu.h"
+#include "trace.h"
+
+#include "qxl.h"
+
+/*
+ * NOTE: SPICE_RING_PROD_ITEM accesses memory on the pci bar and as
+ * such can be changed by the guest, so to avoid a guest trigerrable
+ * abort we just qxl_set_guest_bug and set the return to NULL. Still
+ * it may happen as a result of emulator bug as well.
+ */
+#undef SPICE_RING_PROD_ITEM
+#define SPICE_RING_PROD_ITEM(qxl, r, ret) {                             \
+        uint32_t prod = (r)->prod & SPICE_RING_INDEX_MASK(r);           \
+        if (prod >= ARRAY_SIZE((r)->items)) {                           \
+            qxl_set_guest_bug(qxl, "SPICE_RING_PROD_ITEM indices mismatch " \
+                          "%u >= %zu", prod, ARRAY_SIZE((r)->items));   \
+            ret = NULL;                                                 \
+        } else {                                                        \
+            ret = &(r)->items[prod].el;                                 \
+        }                                                               \
+    }
+
+#undef SPICE_RING_CONS_ITEM
+#define SPICE_RING_CONS_ITEM(qxl, r, ret) {                             \
+        uint32_t cons = (r)->cons & SPICE_RING_INDEX_MASK(r);           \
+        if (cons >= ARRAY_SIZE((r)->items)) {                           \
+            qxl_set_guest_bug(qxl, "SPICE_RING_CONS_ITEM indices mismatch " \
+                          "%u >= %zu", cons, ARRAY_SIZE((r)->items));   \
+            ret = NULL;                                                 \
+        } else {                                                        \
+            ret = &(r)->items[cons].el;                                 \
+        }                                                               \
+    }
+
+#undef ALIGN
+#define ALIGN(a, b) (((a) + ((b) - 1)) & ~((b) - 1))
+
+#define PIXEL_SIZE 0.2936875 //1280x1024 is 14.8" x 11.9" 
+
+#define QXL_MODE(_x, _y, _b, _o)                  \
+    {   .x_res = _x,                              \
+        .y_res = _y,                              \
+        .bits  = _b,                              \
+        .stride = (_x) * (_b) / 8,                \
+        .x_mili = PIXEL_SIZE * (_x),              \
+        .y_mili = PIXEL_SIZE * (_y),              \
+        .orientation = _o,                        \
+    }
+
+#define QXL_MODE_16_32(x_res, y_res, orientation) \
+    QXL_MODE(x_res, y_res, 16, orientation),      \
+    QXL_MODE(x_res, y_res, 32, orientation)
+
+#define QXL_MODE_EX(x_res, y_res)                 \
+    QXL_MODE_16_32(x_res, y_res, 0),              \
+    QXL_MODE_16_32(x_res, y_res, 1)
+
+static QXLMode qxl_modes[] = {
+    QXL_MODE_EX(640, 480),
+    QXL_MODE_EX(800, 480),
+    QXL_MODE_EX(800, 600),
+    QXL_MODE_EX(832, 624),
+    QXL_MODE_EX(960, 640),
+    QXL_MODE_EX(1024, 600),
+    QXL_MODE_EX(1024, 768),
+    QXL_MODE_EX(1152, 864),
+    QXL_MODE_EX(1152, 870),
+    QXL_MODE_EX(1280, 720),
+    QXL_MODE_EX(1280, 760),
+    QXL_MODE_EX(1280, 768),
+    QXL_MODE_EX(1280, 800),
+    QXL_MODE_EX(1280, 960),
+    QXL_MODE_EX(1280, 1024),
+    QXL_MODE_EX(1360, 768),
+    QXL_MODE_EX(1366, 768),
+    QXL_MODE_EX(1400, 1050),
+    QXL_MODE_EX(1440, 900),
+    QXL_MODE_EX(1600, 900),
+    QXL_MODE_EX(1600, 1200),
+    QXL_MODE_EX(1680, 1050),
+    QXL_MODE_EX(1920, 1080),
+    /* these modes need more than 8 MB video memory */
+    QXL_MODE_EX(1920, 1200),
+    QXL_MODE_EX(1920, 1440),
+    QXL_MODE_EX(2048, 1536),
+    QXL_MODE_EX(2560, 1440),
+    QXL_MODE_EX(2560, 1600),
+    /* these modes need more than 16 MB video memory */
+    QXL_MODE_EX(2560, 2048),
+    QXL_MODE_EX(2800, 2100),
+    QXL_MODE_EX(3200, 2400),
+};
+
+static void qxl_send_events(PCIQXLDevice *d, uint32_t events);
+static int qxl_destroy_primary(PCIQXLDevice *d, qxl_async_io async);
+static void qxl_reset_memslots(PCIQXLDevice *d);
+static void qxl_reset_surfaces(PCIQXLDevice *d);
+static void qxl_ring_set_dirty(PCIQXLDevice *qxl);
+
+void qxl_set_guest_bug(PCIQXLDevice *qxl, const char *msg, ...)
+{
+    trace_qxl_set_guest_bug(qxl->id);
+    qxl_send_events(qxl, QXL_INTERRUPT_ERROR);
+    qxl->guest_bug = 1;
+    if (qxl->guestdebug) {
+        va_list ap;
+        va_start(ap, msg);
+        fprintf(stderr, "qxl-%d: guest bug: ", qxl->id);
+        vfprintf(stderr, msg, ap);
+        fprintf(stderr, "\n");
+        va_end(ap);
+    }
+}
+
+static void qxl_clear_guest_bug(PCIQXLDevice *qxl)
+{
+    qxl->guest_bug = 0;
+}
+
+void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id,
+                           struct QXLRect *area, struct QXLRect *dirty_rects,
+                           uint32_t num_dirty_rects,
+                           uint32_t clear_dirty_region,
+                           qxl_async_io async, struct QXLCookie *cookie)
+{
+    trace_qxl_spice_update_area(qxl->id, surface_id, area->left, area->right,
+                                area->top, area->bottom);
+    trace_qxl_spice_update_area_rest(qxl->id, num_dirty_rects,
+                                     clear_dirty_region);
+    if (async == QXL_SYNC) {
+        qxl->ssd.worker->update_area(qxl->ssd.worker, surface_id, area,
+                        dirty_rects, num_dirty_rects, clear_dirty_region);
+    } else {
+        assert(cookie != NULL);
+        spice_qxl_update_area_async(&qxl->ssd.qxl, surface_id, area,
+                                    clear_dirty_region, (uintptr_t)cookie);
+    }
+}
+
+static void qxl_spice_destroy_surface_wait_complete(PCIQXLDevice *qxl,
+                                                    uint32_t id)
+{
+    trace_qxl_spice_destroy_surface_wait_complete(qxl->id, id);
+    qemu_mutex_lock(&qxl->track_lock);
+    qxl->guest_surfaces.cmds[id] = 0;
+    qxl->guest_surfaces.count--;
+    qemu_mutex_unlock(&qxl->track_lock);
+}
+
+static void qxl_spice_destroy_surface_wait(PCIQXLDevice *qxl, uint32_t id,
+                                           qxl_async_io async)
+{
+    QXLCookie *cookie;
+
+    trace_qxl_spice_destroy_surface_wait(qxl->id, id, async);
+    if (async) {
+        cookie = qxl_cookie_new(QXL_COOKIE_TYPE_IO,
+                                QXL_IO_DESTROY_SURFACE_ASYNC);
+        cookie->u.surface_id = id;
+        spice_qxl_destroy_surface_async(&qxl->ssd.qxl, id, (uintptr_t)cookie);
+    } else {
+        qxl->ssd.worker->destroy_surface_wait(qxl->ssd.worker, id);
+        qxl_spice_destroy_surface_wait_complete(qxl, id);
+    }
+}
+
+static void qxl_spice_flush_surfaces_async(PCIQXLDevice *qxl)
+{
+    trace_qxl_spice_flush_surfaces_async(qxl->id, qxl->guest_surfaces.count,
+                                         qxl->num_free_res);
+    spice_qxl_flush_surfaces_async(&qxl->ssd.qxl,
+        (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO,
+                                  QXL_IO_FLUSH_SURFACES_ASYNC));
+}
+
+void qxl_spice_loadvm_commands(PCIQXLDevice *qxl, struct QXLCommandExt *ext,
+                               uint32_t count)
+{
+    trace_qxl_spice_loadvm_commands(qxl->id, ext, count);
+    qxl->ssd.worker->loadvm_commands(qxl->ssd.worker, ext, count);
+}
+
+void qxl_spice_oom(PCIQXLDevice *qxl)
+{
+    trace_qxl_spice_oom(qxl->id);
+    qxl->ssd.worker->oom(qxl->ssd.worker);
+}
+
+void qxl_spice_reset_memslots(PCIQXLDevice *qxl)
+{
+    trace_qxl_spice_reset_memslots(qxl->id);
+    qxl->ssd.worker->reset_memslots(qxl->ssd.worker);
+}
+
+static void qxl_spice_destroy_surfaces_complete(PCIQXLDevice *qxl)
+{
+    trace_qxl_spice_destroy_surfaces_complete(qxl->id);
+    qemu_mutex_lock(&qxl->track_lock);
+    memset(qxl->guest_surfaces.cmds, 0,
+           sizeof(qxl->guest_surfaces.cmds) * qxl->ssd.num_surfaces);
+    qxl->guest_surfaces.count = 0;
+    qemu_mutex_unlock(&qxl->track_lock);
+}
+
+static void qxl_spice_destroy_surfaces(PCIQXLDevice *qxl, qxl_async_io async)
+{
+    trace_qxl_spice_destroy_surfaces(qxl->id, async);
+    if (async) {
+        spice_qxl_destroy_surfaces_async(&qxl->ssd.qxl,
+                (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO,
+                                          QXL_IO_DESTROY_ALL_SURFACES_ASYNC));
+    } else {
+        qxl->ssd.worker->destroy_surfaces(qxl->ssd.worker);
+        qxl_spice_destroy_surfaces_complete(qxl);
+    }
+}
+
+static void qxl_spice_monitors_config_async(PCIQXLDevice *qxl, int replay)
+{
+    trace_qxl_spice_monitors_config(qxl->id);
+    if (replay) {
+        /*
+         * don't use QXL_COOKIE_TYPE_IO:
+         *  - we are not running yet (post_load), we will assert
+         *    in send_events
+         *  - this is not a guest io, but a reply, so async_io isn't set.
+         */
+        spice_qxl_monitors_config_async(&qxl->ssd.qxl,
+                qxl->guest_monitors_config,
+                MEMSLOT_GROUP_GUEST,
+                (uintptr_t)qxl_cookie_new(
+                    QXL_COOKIE_TYPE_POST_LOAD_MONITORS_CONFIG,
+                    0));
+    } else {
+        qxl->guest_monitors_config = qxl->ram->monitors_config;
+        spice_qxl_monitors_config_async(&qxl->ssd.qxl,
+                qxl->ram->monitors_config,
+                MEMSLOT_GROUP_GUEST,
+                (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO,
+                                          QXL_IO_MONITORS_CONFIG_ASYNC));
+    }
+}
+
+void qxl_spice_reset_image_cache(PCIQXLDevice *qxl)
+{
+    trace_qxl_spice_reset_image_cache(qxl->id);
+    qxl->ssd.worker->reset_image_cache(qxl->ssd.worker);
+}
+
+void qxl_spice_reset_cursor(PCIQXLDevice *qxl)
+{
+    trace_qxl_spice_reset_cursor(qxl->id);
+    qxl->ssd.worker->reset_cursor(qxl->ssd.worker);
+    qemu_mutex_lock(&qxl->track_lock);
+    qxl->guest_cursor = 0;
+    qemu_mutex_unlock(&qxl->track_lock);
+    if (qxl->ssd.cursor) {
+        cursor_put(qxl->ssd.cursor);
+    }
+    qxl->ssd.cursor = cursor_builtin_hidden();
+}
+
+
+static inline uint32_t msb_mask(uint32_t val)
+{
+    uint32_t mask;
+
+    do {
+        mask = ~(val - 1) & val;
+        val &= ~mask;
+    } while (mask < val);
+
+    return mask;
+}
+
+static ram_addr_t qxl_rom_size(void)
+{
+    uint32_t required_rom_size = sizeof(QXLRom) + sizeof(QXLModes) +
+                                 sizeof(qxl_modes);
+    uint32_t rom_size = 8192; /* two pages */
+
+    required_rom_size = MAX(required_rom_size, TARGET_PAGE_SIZE);
+    required_rom_size = msb_mask(required_rom_size * 2 - 1);
+    assert(required_rom_size <= rom_size);
+    return rom_size;
+}
+
+static void init_qxl_rom(PCIQXLDevice *d)
+{
+    QXLRom *rom = memory_region_get_ram_ptr(&d->rom_bar);
+    QXLModes *modes = (QXLModes *)(rom + 1);
+    uint32_t ram_header_size;
+    uint32_t surface0_area_size;
+    uint32_t num_pages;
+    uint32_t fb;
+    int i, n;
+
+    memset(rom, 0, d->rom_size);
+
+    rom->magic         = cpu_to_le32(QXL_ROM_MAGIC);
+    rom->id            = cpu_to_le32(d->id);
+    rom->log_level     = cpu_to_le32(d->guestdebug);
+    rom->modes_offset  = cpu_to_le32(sizeof(QXLRom));
+
+    rom->slot_gen_bits = MEMSLOT_GENERATION_BITS;
+    rom->slot_id_bits  = MEMSLOT_SLOT_BITS;
+    rom->slots_start   = 1;
+    rom->slots_end     = NUM_MEMSLOTS - 1;
+    rom->n_surfaces    = cpu_to_le32(d->ssd.num_surfaces);
+
+    for (i = 0, n = 0; i < ARRAY_SIZE(qxl_modes); i++) {
+        fb = qxl_modes[i].y_res * qxl_modes[i].stride;
+        if (fb > d->vgamem_size) {
+            continue;
+        }
+        modes->modes[n].id          = cpu_to_le32(i);
+        modes->modes[n].x_res       = cpu_to_le32(qxl_modes[i].x_res);
+        modes->modes[n].y_res       = cpu_to_le32(qxl_modes[i].y_res);
+        modes->modes[n].bits        = cpu_to_le32(qxl_modes[i].bits);
+        modes->modes[n].stride      = cpu_to_le32(qxl_modes[i].stride);
+        modes->modes[n].x_mili      = cpu_to_le32(qxl_modes[i].x_mili);
+        modes->modes[n].y_mili      = cpu_to_le32(qxl_modes[i].y_mili);
+        modes->modes[n].orientation = cpu_to_le32(qxl_modes[i].orientation);
+        n++;
+    }
+    modes->n_modes     = cpu_to_le32(n);
+
+    ram_header_size    = ALIGN(sizeof(QXLRam), 4096);
+    surface0_area_size = ALIGN(d->vgamem_size, 4096);
+    num_pages          = d->vga.vram_size;
+    num_pages         -= ram_header_size;
+    num_pages         -= surface0_area_size;
+    num_pages          = num_pages / TARGET_PAGE_SIZE;
+
+    rom->draw_area_offset   = cpu_to_le32(0);
+    rom->surface0_area_size = cpu_to_le32(surface0_area_size);
+    rom->pages_offset       = cpu_to_le32(surface0_area_size);
+    rom->num_pages          = cpu_to_le32(num_pages);
+    rom->ram_header_offset  = cpu_to_le32(d->vga.vram_size - ram_header_size);
+
+    d->shadow_rom = *rom;
+    d->rom        = rom;
+    d->modes      = modes;
+}
+
+static void init_qxl_ram(PCIQXLDevice *d)
+{
+    uint8_t *buf;
+    uint64_t *item;
+
+    buf = d->vga.vram_ptr;
+    d->ram = (QXLRam *)(buf + le32_to_cpu(d->shadow_rom.ram_header_offset));
+    d->ram->magic       = cpu_to_le32(QXL_RAM_MAGIC);
+    d->ram->int_pending = cpu_to_le32(0);
+    d->ram->int_mask    = cpu_to_le32(0);
+    d->ram->update_surface = 0;
+    SPICE_RING_INIT(&d->ram->cmd_ring);
+    SPICE_RING_INIT(&d->ram->cursor_ring);
+    SPICE_RING_INIT(&d->ram->release_ring);
+    SPICE_RING_PROD_ITEM(d, &d->ram->release_ring, item);
+    assert(item);
+    *item = 0;
+    qxl_ring_set_dirty(d);
+}
+
+/* can be called from spice server thread context */
+static void qxl_set_dirty(MemoryRegion *mr, ram_addr_t addr, ram_addr_t end)
+{
+    memory_region_set_dirty(mr, addr, end - addr);
+}
+
+static void qxl_rom_set_dirty(PCIQXLDevice *qxl)
+{
+    qxl_set_dirty(&qxl->rom_bar, 0, qxl->rom_size);
+}
+
+/* called from spice server thread context only */
+static void qxl_ram_set_dirty(PCIQXLDevice *qxl, void *ptr)
+{
+    void *base = qxl->vga.vram_ptr;
+    intptr_t offset;
+
+    offset = ptr - base;
+    offset &= ~(TARGET_PAGE_SIZE-1);
+    assert(offset < qxl->vga.vram_size);
+    qxl_set_dirty(&qxl->vga.vram, offset, offset + TARGET_PAGE_SIZE);
+}
+
+/* can be called from spice server thread context */
+static void qxl_ring_set_dirty(PCIQXLDevice *qxl)
+{
+    ram_addr_t addr = qxl->shadow_rom.ram_header_offset;
+    ram_addr_t end  = qxl->vga.vram_size;
+    qxl_set_dirty(&qxl->vga.vram, addr, end);
+}
+
+/*
+ * keep track of some command state, for savevm/loadvm.
+ * called from spice server thread context only
+ */
+static int qxl_track_command(PCIQXLDevice *qxl, struct QXLCommandExt *ext)
+{
+    switch (le32_to_cpu(ext->cmd.type)) {
+    case QXL_CMD_SURFACE:
+    {
+        QXLSurfaceCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id);
+
+        if (!cmd) {
+            return 1;
+        }
+        uint32_t id = le32_to_cpu(cmd->surface_id);
+
+        if (id >= qxl->ssd.num_surfaces) {
+            qxl_set_guest_bug(qxl, "QXL_CMD_SURFACE id %d >= %d", id,
+                              qxl->ssd.num_surfaces);
+            return 1;
+        }
+        if (cmd->type == QXL_SURFACE_CMD_CREATE &&
+            (cmd->u.surface_create.stride & 0x03) != 0) {
+            qxl_set_guest_bug(qxl, "QXL_CMD_SURFACE stride = %d %% 4 != 0\n",
+                              cmd->u.surface_create.stride);
+            return 1;
+        }
+        qemu_mutex_lock(&qxl->track_lock);
+        if (cmd->type == QXL_SURFACE_CMD_CREATE) {
+            qxl->guest_surfaces.cmds[id] = ext->cmd.data;
+            qxl->guest_surfaces.count++;
+            if (qxl->guest_surfaces.max < qxl->guest_surfaces.count)
+                qxl->guest_surfaces.max = qxl->guest_surfaces.count;
+        }
+        if (cmd->type == QXL_SURFACE_CMD_DESTROY) {
+            qxl->guest_surfaces.cmds[id] = 0;
+            qxl->guest_surfaces.count--;
+        }
+        qemu_mutex_unlock(&qxl->track_lock);
+        break;
+    }
+    case QXL_CMD_CURSOR:
+    {
+        QXLCursorCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id);
+
+        if (!cmd) {
+            return 1;
+        }
+        if (cmd->type == QXL_CURSOR_SET) {
+            qemu_mutex_lock(&qxl->track_lock);
+            qxl->guest_cursor = ext->cmd.data;
+            qemu_mutex_unlock(&qxl->track_lock);
+        }
+        break;
+    }
+    }
+    return 0;
+}
+
+/* spice display interface callbacks */
+
+static void interface_attach_worker(QXLInstance *sin, QXLWorker *qxl_worker)
+{
+    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
+
+    trace_qxl_interface_attach_worker(qxl->id);
+    qxl->ssd.worker = qxl_worker;
+}
+
+static void interface_set_compression_level(QXLInstance *sin, int level)
+{
+    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
+
+    trace_qxl_interface_set_compression_level(qxl->id, level);
+    qxl->shadow_rom.compression_level = cpu_to_le32(level);
+    qxl->rom->compression_level = cpu_to_le32(level);
+    qxl_rom_set_dirty(qxl);
+}
+
+static void interface_set_mm_time(QXLInstance *sin, uint32_t mm_time)
+{
+    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
+
+    trace_qxl_interface_set_mm_time(qxl->id, mm_time);
+    qxl->shadow_rom.mm_clock = cpu_to_le32(mm_time);
+    qxl->rom->mm_clock = cpu_to_le32(mm_time);
+    qxl_rom_set_dirty(qxl);
+}
+
+static void interface_get_init_info(QXLInstance *sin, QXLDevInitInfo *info)
+{
+    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
+
+    trace_qxl_interface_get_init_info(qxl->id);
+    info->memslot_gen_bits = MEMSLOT_GENERATION_BITS;
+    info->memslot_id_bits = MEMSLOT_SLOT_BITS;
+    info->num_memslots = NUM_MEMSLOTS;
+    info->num_memslots_groups = NUM_MEMSLOTS_GROUPS;
+    info->internal_groupslot_id = 0;
+    info->qxl_ram_size = le32_to_cpu(qxl->shadow_rom.num_pages) << TARGET_PAGE_BITS;
+    info->n_surfaces = qxl->ssd.num_surfaces;
+}
+
+static const char *qxl_mode_to_string(int mode)
+{
+    switch (mode) {
+    case QXL_MODE_COMPAT:
+        return "compat";
+    case QXL_MODE_NATIVE:
+        return "native";
+    case QXL_MODE_UNDEFINED:
+        return "undefined";
+    case QXL_MODE_VGA:
+        return "vga";
+    }
+    return "INVALID";
+}
+
+static const char *io_port_to_string(uint32_t io_port)
+{
+    if (io_port >= QXL_IO_RANGE_SIZE) {
+        return "out of range";
+    }
+    static const char *io_port_to_string[QXL_IO_RANGE_SIZE + 1] = {
+        [QXL_IO_NOTIFY_CMD]             = "QXL_IO_NOTIFY_CMD",
+        [QXL_IO_NOTIFY_CURSOR]          = "QXL_IO_NOTIFY_CURSOR",
+        [QXL_IO_UPDATE_AREA]            = "QXL_IO_UPDATE_AREA",
+        [QXL_IO_UPDATE_IRQ]             = "QXL_IO_UPDATE_IRQ",
+        [QXL_IO_NOTIFY_OOM]             = "QXL_IO_NOTIFY_OOM",
+        [QXL_IO_RESET]                  = "QXL_IO_RESET",
+        [QXL_IO_SET_MODE]               = "QXL_IO_SET_MODE",
+        [QXL_IO_LOG]                    = "QXL_IO_LOG",
+        [QXL_IO_MEMSLOT_ADD]            = "QXL_IO_MEMSLOT_ADD",
+        [QXL_IO_MEMSLOT_DEL]            = "QXL_IO_MEMSLOT_DEL",
+        [QXL_IO_DETACH_PRIMARY]         = "QXL_IO_DETACH_PRIMARY",
+        [QXL_IO_ATTACH_PRIMARY]         = "QXL_IO_ATTACH_PRIMARY",
+        [QXL_IO_CREATE_PRIMARY]         = "QXL_IO_CREATE_PRIMARY",
+        [QXL_IO_DESTROY_PRIMARY]        = "QXL_IO_DESTROY_PRIMARY",
+        [QXL_IO_DESTROY_SURFACE_WAIT]   = "QXL_IO_DESTROY_SURFACE_WAIT",
+        [QXL_IO_DESTROY_ALL_SURFACES]   = "QXL_IO_DESTROY_ALL_SURFACES",
+        [QXL_IO_UPDATE_AREA_ASYNC]      = "QXL_IO_UPDATE_AREA_ASYNC",
+        [QXL_IO_MEMSLOT_ADD_ASYNC]      = "QXL_IO_MEMSLOT_ADD_ASYNC",
+        [QXL_IO_CREATE_PRIMARY_ASYNC]   = "QXL_IO_CREATE_PRIMARY_ASYNC",
+        [QXL_IO_DESTROY_PRIMARY_ASYNC]  = "QXL_IO_DESTROY_PRIMARY_ASYNC",
+        [QXL_IO_DESTROY_SURFACE_ASYNC]  = "QXL_IO_DESTROY_SURFACE_ASYNC",
+        [QXL_IO_DESTROY_ALL_SURFACES_ASYNC]
+                                        = "QXL_IO_DESTROY_ALL_SURFACES_ASYNC",
+        [QXL_IO_FLUSH_SURFACES_ASYNC]   = "QXL_IO_FLUSH_SURFACES_ASYNC",
+        [QXL_IO_FLUSH_RELEASE]          = "QXL_IO_FLUSH_RELEASE",
+        [QXL_IO_MONITORS_CONFIG_ASYNC]  = "QXL_IO_MONITORS_CONFIG_ASYNC",
+    };
+    return io_port_to_string[io_port];
+}
+
+/* called from spice server thread context only */
+static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext)
+{
+    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
+    SimpleSpiceUpdate *update;
+    QXLCommandRing *ring;
+    QXLCommand *cmd;
+    int notify, ret;
+
+    trace_qxl_ring_command_check(qxl->id, qxl_mode_to_string(qxl->mode));
+
+    switch (qxl->mode) {
+    case QXL_MODE_VGA:
+        ret = false;
+        qemu_mutex_lock(&qxl->ssd.lock);
+        update = QTAILQ_FIRST(&qxl->ssd.updates);
+        if (update != NULL) {
+            QTAILQ_REMOVE(&qxl->ssd.updates, update, next);
+            *ext = update->ext;
+            ret = true;
+        }
+        qemu_mutex_unlock(&qxl->ssd.lock);
+        if (ret) {
+            trace_qxl_ring_command_get(qxl->id, qxl_mode_to_string(qxl->mode));
+            qxl_log_command(qxl, "vga", ext);
+        }
+        return ret;
+    case QXL_MODE_COMPAT:
+    case QXL_MODE_NATIVE:
+    case QXL_MODE_UNDEFINED:
+        ring = &qxl->ram->cmd_ring;
+        if (qxl->guest_bug || SPICE_RING_IS_EMPTY(ring)) {
+            return false;
+        }
+        SPICE_RING_CONS_ITEM(qxl, ring, cmd);
+        if (!cmd) {
+            return false;
+        }
+        ext->cmd      = *cmd;
+        ext->group_id = MEMSLOT_GROUP_GUEST;
+        ext->flags    = qxl->cmdflags;
+        SPICE_RING_POP(ring, notify);
+        qxl_ring_set_dirty(qxl);
+        if (notify) {
+            qxl_send_events(qxl, QXL_INTERRUPT_DISPLAY);
+        }
+        qxl->guest_primary.commands++;
+        qxl_track_command(qxl, ext);
+        qxl_log_command(qxl, "cmd", ext);
+        trace_qxl_ring_command_get(qxl->id, qxl_mode_to_string(qxl->mode));
+        return true;
+    default:
+        return false;
+    }
+}
+
+/* called from spice server thread context only */
+static int interface_req_cmd_notification(QXLInstance *sin)
+{
+    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
+    int wait = 1;
+
+    trace_qxl_ring_command_req_notification(qxl->id);
+    switch (qxl->mode) {
+    case QXL_MODE_COMPAT:
+    case QXL_MODE_NATIVE:
+    case QXL_MODE_UNDEFINED:
+        SPICE_RING_CONS_WAIT(&qxl->ram->cmd_ring, wait);
+        qxl_ring_set_dirty(qxl);
+        break;
+    default:
+        /* nothing */
+        break;
+    }
+    return wait;
+}
+
+/* called from spice server thread context only */
+static inline void qxl_push_free_res(PCIQXLDevice *d, int flush)
+{
+    QXLReleaseRing *ring = &d->ram->release_ring;
+    uint64_t *item;
+    int notify;
+
+#define QXL_FREE_BUNCH_SIZE 32
+
+    if (ring->prod - ring->cons + 1 == ring->num_items) {
+        /* ring full -- can't push */
+        return;
+    }
+    if (!flush && d->oom_running) {
+        /* collect everything from oom handler before pushing */
+        return;
+    }
+    if (!flush && d->num_free_res < QXL_FREE_BUNCH_SIZE) {
+        /* collect a bit more before pushing */
+        return;
+    }
+
+    SPICE_RING_PUSH(ring, notify);
+    trace_qxl_ring_res_push(d->id, qxl_mode_to_string(d->mode),
+           d->guest_surfaces.count, d->num_free_res,
+           d->last_release, notify ? "yes" : "no");
+    trace_qxl_ring_res_push_rest(d->id, ring->prod - ring->cons,
+           ring->num_items, ring->prod, ring->cons);
+    if (notify) {
+        qxl_send_events(d, QXL_INTERRUPT_DISPLAY);
+    }
+    SPICE_RING_PROD_ITEM(d, ring, item);
+    if (!item) {
+        return;
+    }
+    *item = 0;
+    d->num_free_res = 0;
+    d->last_release = NULL;
+    qxl_ring_set_dirty(d);
+}
+
+/* called from spice server thread context only */
+static void interface_release_resource(QXLInstance *sin,
+                                       struct QXLReleaseInfoExt ext)
+{
+    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
+    QXLReleaseRing *ring;
+    uint64_t *item, id;
+
+    if (ext.group_id == MEMSLOT_GROUP_HOST) {
+        /* host group -> vga mode update request */
+        qemu_spice_destroy_update(&qxl->ssd, (void *)(intptr_t)ext.info->id);
+        return;
+    }
+
+    /*
+     * ext->info points into guest-visible memory
+     * pci bar 0, $command.release_info
+     */
+    ring = &qxl->ram->release_ring;
+    SPICE_RING_PROD_ITEM(qxl, ring, item);
+    if (!item) {
+        return;
+    }
+    if (*item == 0) {
+        /* stick head into the ring */
+        id = ext.info->id;
+        ext.info->next = 0;
+        qxl_ram_set_dirty(qxl, &ext.info->next);
+        *item = id;
+        qxl_ring_set_dirty(qxl);
+    } else {
+        /* append item to the list */
+        qxl->last_release->next = ext.info->id;
+        qxl_ram_set_dirty(qxl, &qxl->last_release->next);
+        ext.info->next = 0;
+        qxl_ram_set_dirty(qxl, &ext.info->next);
+    }
+    qxl->last_release = ext.info;
+    qxl->num_free_res++;
+    trace_qxl_ring_res_put(qxl->id, qxl->num_free_res);
+    qxl_push_free_res(qxl, 0);
+}
+
+/* called from spice server thread context only */
+static int interface_get_cursor_command(QXLInstance *sin, struct QXLCommandExt *ext)
+{
+    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
+    QXLCursorRing *ring;
+    QXLCommand *cmd;
+    int notify;
+
+    trace_qxl_ring_cursor_check(qxl->id, qxl_mode_to_string(qxl->mode));
+
+    switch (qxl->mode) {
+    case QXL_MODE_COMPAT:
+    case QXL_MODE_NATIVE:
+    case QXL_MODE_UNDEFINED:
+        ring = &qxl->ram->cursor_ring;
+        if (SPICE_RING_IS_EMPTY(ring)) {
+            return false;
+        }
+        SPICE_RING_CONS_ITEM(qxl, ring, cmd);
+        if (!cmd) {
+            return false;
+        }
+        ext->cmd      = *cmd;
+        ext->group_id = MEMSLOT_GROUP_GUEST;
+        ext->flags    = qxl->cmdflags;
+        SPICE_RING_POP(ring, notify);
+        qxl_ring_set_dirty(qxl);
+        if (notify) {
+            qxl_send_events(qxl, QXL_INTERRUPT_CURSOR);
+        }
+        qxl->guest_primary.commands++;
+        qxl_track_command(qxl, ext);
+        qxl_log_command(qxl, "csr", ext);
+        if (qxl->id == 0) {
+            qxl_render_cursor(qxl, ext);
+        }
+        trace_qxl_ring_cursor_get(qxl->id, qxl_mode_to_string(qxl->mode));
+        return true;
+    default:
+        return false;
+    }
+}
+
+/* called from spice server thread context only */
+static int interface_req_cursor_notification(QXLInstance *sin)
+{
+    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
+    int wait = 1;
+
+    trace_qxl_ring_cursor_req_notification(qxl->id);
+    switch (qxl->mode) {
+    case QXL_MODE_COMPAT:
+    case QXL_MODE_NATIVE:
+    case QXL_MODE_UNDEFINED:
+        SPICE_RING_CONS_WAIT(&qxl->ram->cursor_ring, wait);
+        qxl_ring_set_dirty(qxl);
+        break;
+    default:
+        /* nothing */
+        break;
+    }
+    return wait;
+}
+
+/* called from spice server thread context */
+static void interface_notify_update(QXLInstance *sin, uint32_t update_id)
+{
+    /*
+     * Called by spice-server as a result of a QXL_CMD_UPDATE which is not in
+     * use by xf86-video-qxl and is defined out in the qxl windows driver.
+     * Probably was at some earlier version that is prior to git start (2009),
+     * and is still guest trigerrable.
+     */
+    fprintf(stderr, "%s: deprecated\n", __func__);
+}
+
+/* called from spice server thread context only */
+static int interface_flush_resources(QXLInstance *sin)
+{
+    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
+    int ret;
+
+    ret = qxl->num_free_res;
+    if (ret) {
+        qxl_push_free_res(qxl, 1);
+    }
+    return ret;
+}
+
+static void qxl_create_guest_primary_complete(PCIQXLDevice *d);
+
+/* called from spice server thread context only */
+static void interface_async_complete_io(PCIQXLDevice *qxl, QXLCookie *cookie)
+{
+    uint32_t current_async;
+
+    qemu_mutex_lock(&qxl->async_lock);
+    current_async = qxl->current_async;
+    qxl->current_async = QXL_UNDEFINED_IO;
+    qemu_mutex_unlock(&qxl->async_lock);
+
+    trace_qxl_interface_async_complete_io(qxl->id, current_async, cookie);
+    if (!cookie) {
+        fprintf(stderr, "qxl: %s: error, cookie is NULL\n", __func__);
+        return;
+    }
+    if (cookie && current_async != cookie->io) {
+        fprintf(stderr,
+                "qxl: %s: error: current_async = %d != %"
+                PRId64 " = cookie->io\n", __func__, current_async, cookie->io);
+    }
+    switch (current_async) {
+    case QXL_IO_MEMSLOT_ADD_ASYNC:
+    case QXL_IO_DESTROY_PRIMARY_ASYNC:
+    case QXL_IO_UPDATE_AREA_ASYNC:
+    case QXL_IO_FLUSH_SURFACES_ASYNC:
+    case QXL_IO_MONITORS_CONFIG_ASYNC:
+        break;
+    case QXL_IO_CREATE_PRIMARY_ASYNC:
+        qxl_create_guest_primary_complete(qxl);
+        break;
+    case QXL_IO_DESTROY_ALL_SURFACES_ASYNC:
+        qxl_spice_destroy_surfaces_complete(qxl);
+        break;
+    case QXL_IO_DESTROY_SURFACE_ASYNC:
+        qxl_spice_destroy_surface_wait_complete(qxl, cookie->u.surface_id);
+        break;
+    default:
+        fprintf(stderr, "qxl: %s: unexpected current_async %d\n", __func__,
+                current_async);
+    }
+    qxl_send_events(qxl, QXL_INTERRUPT_IO_CMD);
+}
+
+/* called from spice server thread context only */
+static void interface_update_area_complete(QXLInstance *sin,
+        uint32_t surface_id,
+        QXLRect *dirty, uint32_t num_updated_rects)
+{
+    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
+    int i;
+    int qxl_i;
+
+    qemu_mutex_lock(&qxl->ssd.lock);
+    if (surface_id != 0 || !qxl->render_update_cookie_num) {
+        qemu_mutex_unlock(&qxl->ssd.lock);
+        return;
+    }
+    trace_qxl_interface_update_area_complete(qxl->id, surface_id, dirty->left,
+            dirty->right, dirty->top, dirty->bottom);
+    trace_qxl_interface_update_area_complete_rest(qxl->id, num_updated_rects);
+    if (qxl->num_dirty_rects + num_updated_rects > QXL_NUM_DIRTY_RECTS) {
+        /*
+         * overflow - treat this as a full update. Not expected to be common.
+         */
+        trace_qxl_interface_update_area_complete_overflow(qxl->id,
+                                                          QXL_NUM_DIRTY_RECTS);
+        qxl->guest_primary.resized = 1;
+    }
+    if (qxl->guest_primary.resized) {
+        /*
+         * Don't bother copying or scheduling the bh since we will flip
+         * the whole area anyway on completion of the update_area async call
+         */
+        qemu_mutex_unlock(&qxl->ssd.lock);
+        return;
+    }
+    qxl_i = qxl->num_dirty_rects;
+    for (i = 0; i < num_updated_rects; i++) {
+        qxl->dirty[qxl_i++] = dirty[i];
+    }
+    qxl->num_dirty_rects += num_updated_rects;
+    trace_qxl_interface_update_area_complete_schedule_bh(qxl->id,
+                                                         qxl->num_dirty_rects);
+    qemu_bh_schedule(qxl->update_area_bh);
+    qemu_mutex_unlock(&qxl->ssd.lock);
+}
+
+/* called from spice server thread context only */
+static void interface_async_complete(QXLInstance *sin, uint64_t cookie_token)
+{
+    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
+    QXLCookie *cookie = (QXLCookie *)(uintptr_t)cookie_token;
+
+    switch (cookie->type) {
+    case QXL_COOKIE_TYPE_IO:
+        interface_async_complete_io(qxl, cookie);
+        g_free(cookie);
+        break;
+    case QXL_COOKIE_TYPE_RENDER_UPDATE_AREA:
+        qxl_render_update_area_done(qxl, cookie);
+        break;
+    case QXL_COOKIE_TYPE_POST_LOAD_MONITORS_CONFIG:
+        break;
+    default:
+        fprintf(stderr, "qxl: %s: unexpected cookie type %d\n",
+                __func__, cookie->type);
+        g_free(cookie);
+    }
+}
+
+/* called from spice server thread context only */
+static void interface_set_client_capabilities(QXLInstance *sin,
+                                              uint8_t client_present,
+                                              uint8_t caps[58])
+{
+    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
+
+    if (qxl->revision < 4) {
+        trace_qxl_set_client_capabilities_unsupported_by_revision(qxl->id,
+                                                              qxl->revision);
+        return;
+    }
+
+    if (runstate_check(RUN_STATE_INMIGRATE) ||
+        runstate_check(RUN_STATE_POSTMIGRATE)) {
+        return;
+    }
+
+    qxl->shadow_rom.client_present = client_present;
+    memcpy(qxl->shadow_rom.client_capabilities, caps,
+           sizeof(qxl->shadow_rom.client_capabilities));
+    qxl->rom->client_present = client_present;
+    memcpy(qxl->rom->client_capabilities, caps,
+           sizeof(qxl->rom->client_capabilities));
+    qxl_rom_set_dirty(qxl);
+
+    qxl_send_events(qxl, QXL_INTERRUPT_CLIENT);
+}
+
+static uint32_t qxl_crc32(const uint8_t *p, unsigned len)
+{
+    /*
+     * zlib xors the seed with 0xffffffff, and xors the result
+     * again with 0xffffffff; Both are not done with linux's crc32,
+     * which we want to be compatible with, so undo that.
+     */
+    return crc32(0xffffffff, p, len) ^ 0xffffffff;
+}
+
+/* called from main context only */
+static int interface_client_monitors_config(QXLInstance *sin,
+                                        VDAgentMonitorsConfig *monitors_config)
+{
+    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
+    QXLRom *rom = memory_region_get_ram_ptr(&qxl->rom_bar);
+    int i;
+
+    if (qxl->revision < 4) {
+        trace_qxl_client_monitors_config_unsupported_by_device(qxl->id,
+                                                               qxl->revision);
+        return 0;
+    }
+    /*
+     * Older windows drivers set int_mask to 0 when their ISR is called,
+     * then later set it to ~0. So it doesn't relate to the actual interrupts
+     * handled. However, they are old, so clearly they don't support this
+     * interrupt
+     */
+    if (qxl->ram->int_mask == 0 || qxl->ram->int_mask == ~0 ||
+        !(qxl->ram->int_mask & QXL_INTERRUPT_CLIENT_MONITORS_CONFIG)) {
+        trace_qxl_client_monitors_config_unsupported_by_guest(qxl->id,
+                                                            qxl->ram->int_mask,
+                                                            monitors_config);
+        return 0;
+    }
+    if (!monitors_config) {
+        return 1;
+    }
+    memset(&rom->client_monitors_config, 0,
+           sizeof(rom->client_monitors_config));
+    rom->client_monitors_config.count = monitors_config->num_of_monitors;
+    /* monitors_config->flags ignored */
+    if (rom->client_monitors_config.count >=
+            ARRAY_SIZE(rom->client_monitors_config.heads)) {
+        trace_qxl_client_monitors_config_capped(qxl->id,
+                                monitors_config->num_of_monitors,
+                                ARRAY_SIZE(rom->client_monitors_config.heads));
+        rom->client_monitors_config.count =
+            ARRAY_SIZE(rom->client_monitors_config.heads);
+    }
+    for (i = 0 ; i < rom->client_monitors_config.count ; ++i) {
+        VDAgentMonConfig *monitor = &monitors_config->monitors[i];
+        QXLURect *rect = &rom->client_monitors_config.heads[i];
+        /* monitor->depth ignored */
+        rect->left = monitor->x;
+        rect->top = monitor->y;
+        rect->right = monitor->x + monitor->width;
+        rect->bottom = monitor->y + monitor->height;
+    }
+    rom->client_monitors_config_crc = qxl_crc32(
+            (const uint8_t *)&rom->client_monitors_config,
+            sizeof(rom->client_monitors_config));
+    trace_qxl_client_monitors_config_crc(qxl->id,
+            sizeof(rom->client_monitors_config),
+            rom->client_monitors_config_crc);
+
+    trace_qxl_interrupt_client_monitors_config(qxl->id,
+                        rom->client_monitors_config.count,
+                        rom->client_monitors_config.heads);
+    qxl_send_events(qxl, QXL_INTERRUPT_CLIENT_MONITORS_CONFIG);
+    return 1;
+}
+
+static const QXLInterface qxl_interface = {
+    .base.type               = SPICE_INTERFACE_QXL,
+    .base.description        = "qxl gpu",
+    .base.major_version      = SPICE_INTERFACE_QXL_MAJOR,
+    .base.minor_version      = SPICE_INTERFACE_QXL_MINOR,
+
+    .attache_worker          = interface_attach_worker,
+    .set_compression_level   = interface_set_compression_level,
+    .set_mm_time             = interface_set_mm_time,
+    .get_init_info           = interface_get_init_info,
+
+    /* the callbacks below are called from spice server thread context */
+    .get_command             = interface_get_command,
+    .req_cmd_notification    = interface_req_cmd_notification,
+    .release_resource        = interface_release_resource,
+    .get_cursor_command      = interface_get_cursor_command,
+    .req_cursor_notification = interface_req_cursor_notification,
+    .notify_update           = interface_notify_update,
+    .flush_resources         = interface_flush_resources,
+    .async_complete          = interface_async_complete,
+    .update_area_complete    = interface_update_area_complete,
+    .set_client_capabilities = interface_set_client_capabilities,
+    .client_monitors_config = interface_client_monitors_config,
+};
+
+static void qxl_enter_vga_mode(PCIQXLDevice *d)
+{
+    if (d->mode == QXL_MODE_VGA) {
+        return;
+    }
+    trace_qxl_enter_vga_mode(d->id);
+    qemu_spice_create_host_primary(&d->ssd);
+    d->mode = QXL_MODE_VGA;
+    vga_dirty_log_start(&d->vga);
+    vga_hw_update();
+}
+
+static void qxl_exit_vga_mode(PCIQXLDevice *d)
+{
+    if (d->mode != QXL_MODE_VGA) {
+        return;
+    }
+    trace_qxl_exit_vga_mode(d->id);
+    vga_dirty_log_stop(&d->vga);
+    qxl_destroy_primary(d, QXL_SYNC);
+}
+
+static void qxl_update_irq(PCIQXLDevice *d)
+{
+    uint32_t pending = le32_to_cpu(d->ram->int_pending);
+    uint32_t mask    = le32_to_cpu(d->ram->int_mask);
+    int level = !!(pending & mask);
+    qemu_set_irq(d->pci.irq[0], level);
+    qxl_ring_set_dirty(d);
+}
+
+static void qxl_check_state(PCIQXLDevice *d)
+{
+    QXLRam *ram = d->ram;
+    int spice_display_running = qemu_spice_display_is_running(&d->ssd);
+
+    assert(!spice_display_running || SPICE_RING_IS_EMPTY(&ram->cmd_ring));
+    assert(!spice_display_running || SPICE_RING_IS_EMPTY(&ram->cursor_ring));
+}
+
+static void qxl_reset_state(PCIQXLDevice *d)
+{
+    QXLRom *rom = d->rom;
+
+    qxl_check_state(d);
+    d->shadow_rom.update_id = cpu_to_le32(0);
+    *rom = d->shadow_rom;
+    qxl_rom_set_dirty(d);
+    init_qxl_ram(d);
+    d->num_free_res = 0;
+    d->last_release = NULL;
+    memset(&d->ssd.dirty, 0, sizeof(d->ssd.dirty));
+}
+
+static void qxl_soft_reset(PCIQXLDevice *d)
+{
+    trace_qxl_soft_reset(d->id);
+    qxl_check_state(d);
+    qxl_clear_guest_bug(d);
+    d->current_async = QXL_UNDEFINED_IO;
+
+    if (d->id == 0) {
+        qxl_enter_vga_mode(d);
+    } else {
+        d->mode = QXL_MODE_UNDEFINED;
+    }
+}
+
+static void qxl_hard_reset(PCIQXLDevice *d, int loadvm)
+{
+    trace_qxl_hard_reset(d->id, loadvm);
+
+    qxl_spice_reset_cursor(d);
+    qxl_spice_reset_image_cache(d);
+    qxl_reset_surfaces(d);
+    qxl_reset_memslots(d);
+
+    /* pre loadvm reset must not touch QXLRam.  This lives in
+     * device memory, is migrated together with RAM and thus
+     * already loaded at this point */
+    if (!loadvm) {
+        qxl_reset_state(d);
+    }
+    qemu_spice_create_host_memslot(&d->ssd);
+    qxl_soft_reset(d);
+}
+
+static void qxl_reset_handler(DeviceState *dev)
+{
+    PCIQXLDevice *d = DO_UPCAST(PCIQXLDevice, pci.qdev, dev);
+
+    qxl_hard_reset(d, 0);
+}
+
+static void qxl_vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
+{
+    VGACommonState *vga = opaque;
+    PCIQXLDevice *qxl = container_of(vga, PCIQXLDevice, vga);
+
+    trace_qxl_io_write_vga(qxl->id, qxl_mode_to_string(qxl->mode), addr, val);
+    if (qxl->mode != QXL_MODE_VGA) {
+        qxl_destroy_primary(qxl, QXL_SYNC);
+        qxl_soft_reset(qxl);
+    }
+    vga_ioport_write(opaque, addr, val);
+}
+
+static const MemoryRegionPortio qxl_vga_portio_list[] = {
+    { 0x04,  2, 1, .read  = vga_ioport_read,
+                   .write = qxl_vga_ioport_write }, /* 3b4 */
+    { 0x0a,  1, 1, .read  = vga_ioport_read,
+                   .write = qxl_vga_ioport_write }, /* 3ba */
+    { 0x10, 16, 1, .read  = vga_ioport_read,
+                   .write = qxl_vga_ioport_write }, /* 3c0 */
+    { 0x24,  2, 1, .read  = vga_ioport_read,
+                   .write = qxl_vga_ioport_write }, /* 3d4 */
+    { 0x2a,  1, 1, .read  = vga_ioport_read,
+                   .write = qxl_vga_ioport_write }, /* 3da */
+    PORTIO_END_OF_LIST(),
+};
+
+static int qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta,
+                           qxl_async_io async)
+{
+    static const int regions[] = {
+        QXL_RAM_RANGE_INDEX,
+        QXL_VRAM_RANGE_INDEX,
+        QXL_VRAM64_RANGE_INDEX,
+    };
+    uint64_t guest_start;
+    uint64_t guest_end;
+    int pci_region;
+    pcibus_t pci_start;
+    pcibus_t pci_end;
+    intptr_t virt_start;
+    QXLDevMemSlot memslot;
+    int i;
+
+    guest_start = le64_to_cpu(d->guest_slots[slot_id].slot.mem_start);
+    guest_end   = le64_to_cpu(d->guest_slots[slot_id].slot.mem_end);
+
+    trace_qxl_memslot_add_guest(d->id, slot_id, guest_start, guest_end);
+
+    if (slot_id >= NUM_MEMSLOTS) {
+        qxl_set_guest_bug(d, "%s: slot_id >= NUM_MEMSLOTS %d >= %d", __func__,
+                      slot_id, NUM_MEMSLOTS);
+        return 1;
+    }
+    if (guest_start > guest_end) {
+        qxl_set_guest_bug(d, "%s: guest_start > guest_end 0x%" PRIx64
+                         " > 0x%" PRIx64, __func__, guest_start, guest_end);
+        return 1;
+    }
+
+    for (i = 0; i < ARRAY_SIZE(regions); i++) {
+        pci_region = regions[i];
+        pci_start = d->pci.io_regions[pci_region].addr;
+        pci_end = pci_start + d->pci.io_regions[pci_region].size;
+        /* mapped? */
+        if (pci_start == -1) {
+            continue;
+        }
+        /* start address in range ? */
+        if (guest_start < pci_start || guest_start > pci_end) {
+            continue;
+        }
+        /* end address in range ? */
+        if (guest_end > pci_end) {
+            continue;
+        }
+        /* passed */
+        break;
+    }
+    if (i == ARRAY_SIZE(regions)) {
+        qxl_set_guest_bug(d, "%s: finished loop without match", __func__);
+        return 1;
+    }
+
+    switch (pci_region) {
+    case QXL_RAM_RANGE_INDEX:
+        virt_start = (intptr_t)memory_region_get_ram_ptr(&d->vga.vram);
+        break;
+    case QXL_VRAM_RANGE_INDEX:
+    case 4 /* vram 64bit */:
+        virt_start = (intptr_t)memory_region_get_ram_ptr(&d->vram_bar);
+        break;
+    default:
+        /* should not happen */
+        qxl_set_guest_bug(d, "%s: pci_region = %d", __func__, pci_region);
+        return 1;
+    }
+
+    memslot.slot_id = slot_id;
+    memslot.slot_group_id = MEMSLOT_GROUP_GUEST; /* guest group */
+    memslot.virt_start = virt_start + (guest_start - pci_start);
+    memslot.virt_end   = virt_start + (guest_end   - pci_start);
+    memslot.addr_delta = memslot.virt_start - delta;
+    memslot.generation = d->rom->slot_generation = 0;
+    qxl_rom_set_dirty(d);
+
+    qemu_spice_add_memslot(&d->ssd, &memslot, async);
+    d->guest_slots[slot_id].ptr = (void*)memslot.virt_start;
+    d->guest_slots[slot_id].size = memslot.virt_end - memslot.virt_start;
+    d->guest_slots[slot_id].delta = delta;
+    d->guest_slots[slot_id].active = 1;
+    return 0;
+}
+
+static void qxl_del_memslot(PCIQXLDevice *d, uint32_t slot_id)
+{
+    qemu_spice_del_memslot(&d->ssd, MEMSLOT_GROUP_HOST, slot_id);
+    d->guest_slots[slot_id].active = 0;
+}
+
+static void qxl_reset_memslots(PCIQXLDevice *d)
+{
+    qxl_spice_reset_memslots(d);
+    memset(&d->guest_slots, 0, sizeof(d->guest_slots));
+}
+
+static void qxl_reset_surfaces(PCIQXLDevice *d)
+{
+    trace_qxl_reset_surfaces(d->id);
+    d->mode = QXL_MODE_UNDEFINED;
+    qxl_spice_destroy_surfaces(d, QXL_SYNC);
+}
+
+/* can be also called from spice server thread context */
+void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, int group_id)
+{
+    uint64_t phys   = le64_to_cpu(pqxl);
+    uint32_t slot   = (phys >> (64 -  8)) & 0xff;
+    uint64_t offset = phys & 0xffffffffffff;
+
+    switch (group_id) {
+    case MEMSLOT_GROUP_HOST:
+        return (void *)(intptr_t)offset;
+    case MEMSLOT_GROUP_GUEST:
+        if (slot >= NUM_MEMSLOTS) {
+            qxl_set_guest_bug(qxl, "slot too large %d >= %d", slot,
+                              NUM_MEMSLOTS);
+            return NULL;
+        }
+        if (!qxl->guest_slots[slot].active) {
+            qxl_set_guest_bug(qxl, "inactive slot %d\n", slot);
+            return NULL;
+        }
+        if (offset < qxl->guest_slots[slot].delta) {
+            qxl_set_guest_bug(qxl,
+                          "slot %d offset %"PRIu64" < delta %"PRIu64"\n",
+                          slot, offset, qxl->guest_slots[slot].delta);
+            return NULL;
+        }
+        offset -= qxl->guest_slots[slot].delta;
+        if (offset > qxl->guest_slots[slot].size) {
+            qxl_set_guest_bug(qxl,
+                          "slot %d offset %"PRIu64" > size %"PRIu64"\n",
+                          slot, offset, qxl->guest_slots[slot].size);
+            return NULL;
+        }
+        return qxl->guest_slots[slot].ptr + offset;
+    }
+    return NULL;
+}
+
+static void qxl_create_guest_primary_complete(PCIQXLDevice *qxl)
+{
+    /* for local rendering */
+    qxl_render_resize(qxl);
+}
+
+static void qxl_create_guest_primary(PCIQXLDevice *qxl, int loadvm,
+                                     qxl_async_io async)
+{
+    QXLDevSurfaceCreate surface;
+    QXLSurfaceCreate *sc = &qxl->guest_primary.surface;
+    int size;
+    int requested_height = le32_to_cpu(sc->height);
+    int requested_stride = le32_to_cpu(sc->stride);
+
+    size = abs(requested_stride) * requested_height;
+    if (size > qxl->vgamem_size) {
+        qxl_set_guest_bug(qxl, "%s: requested primary larger then framebuffer"
+                               " size", __func__);
+        return;
+    }
+
+    if (qxl->mode == QXL_MODE_NATIVE) {
+        qxl_set_guest_bug(qxl, "%s: nop since already in QXL_MODE_NATIVE",
+                      __func__);
+    }
+    qxl_exit_vga_mode(qxl);
+
+    surface.format     = le32_to_cpu(sc->format);
+    surface.height     = le32_to_cpu(sc->height);
+    surface.mem        = le64_to_cpu(sc->mem);
+    surface.position   = le32_to_cpu(sc->position);
+    surface.stride     = le32_to_cpu(sc->stride);
+    surface.width      = le32_to_cpu(sc->width);
+    surface.type       = le32_to_cpu(sc->type);
+    surface.flags      = le32_to_cpu(sc->flags);
+    trace_qxl_create_guest_primary(qxl->id, sc->width, sc->height, sc->mem,
+                                   sc->format, sc->position);
+    trace_qxl_create_guest_primary_rest(qxl->id, sc->stride, sc->type,
+                                        sc->flags);
+
+    if ((surface.stride & 0x3) != 0) {
+        qxl_set_guest_bug(qxl, "primary surface stride = %d %% 4 != 0",
+                          surface.stride);
+        return;
+    }
+
+    surface.mouse_mode = true;
+    surface.group_id   = MEMSLOT_GROUP_GUEST;
+    if (loadvm) {
+        surface.flags |= QXL_SURF_FLAG_KEEP_DATA;
+    }
+
+    qxl->mode = QXL_MODE_NATIVE;
+    qxl->cmdflags = 0;
+    qemu_spice_create_primary_surface(&qxl->ssd, 0, &surface, async);
+
+    if (async == QXL_SYNC) {
+        qxl_create_guest_primary_complete(qxl);
+    }
+}
+
+/* return 1 if surface destoy was initiated (in QXL_ASYNC case) or
+ * done (in QXL_SYNC case), 0 otherwise. */
+static int qxl_destroy_primary(PCIQXLDevice *d, qxl_async_io async)
+{
+    if (d->mode == QXL_MODE_UNDEFINED) {
+        return 0;
+    }
+    trace_qxl_destroy_primary(d->id);
+    d->mode = QXL_MODE_UNDEFINED;
+    qemu_spice_destroy_primary_surface(&d->ssd, 0, async);
+    qxl_spice_reset_cursor(d);
+    return 1;
+}
+
+static void qxl_set_mode(PCIQXLDevice *d, int modenr, int loadvm)
+{
+    pcibus_t start = d->pci.io_regions[QXL_RAM_RANGE_INDEX].addr;
+    pcibus_t end   = d->pci.io_regions[QXL_RAM_RANGE_INDEX].size + start;
+    QXLMode *mode = d->modes->modes + modenr;
+    uint64_t devmem = d->pci.io_regions[QXL_RAM_RANGE_INDEX].addr;
+    QXLMemSlot slot = {
+        .mem_start = start,
+        .mem_end = end
+    };
+    QXLSurfaceCreate surface = {
+        .width      = mode->x_res,
+        .height     = mode->y_res,
+        .stride     = -mode->x_res * 4,
+        .format     = SPICE_SURFACE_FMT_32_xRGB,
+        .flags      = loadvm ? QXL_SURF_FLAG_KEEP_DATA : 0,
+        .mouse_mode = true,
+        .mem        = devmem + d->shadow_rom.draw_area_offset,
+    };
+
+    trace_qxl_set_mode(d->id, modenr, mode->x_res, mode->y_res, mode->bits,
+                       devmem);
+    if (!loadvm) {
+        qxl_hard_reset(d, 0);
+    }
+
+    d->guest_slots[0].slot = slot;
+    assert(qxl_add_memslot(d, 0, devmem, QXL_SYNC) == 0);
+
+    d->guest_primary.surface = surface;
+    qxl_create_guest_primary(d, 0, QXL_SYNC);
+
+    d->mode = QXL_MODE_COMPAT;
+    d->cmdflags = QXL_COMMAND_FLAG_COMPAT;
+    if (mode->bits == 16) {
+        d->cmdflags |= QXL_COMMAND_FLAG_COMPAT_16BPP;
+    }
+    d->shadow_rom.mode = cpu_to_le32(modenr);
+    d->rom->mode = cpu_to_le32(modenr);
+    qxl_rom_set_dirty(d);
+}
+
+static void ioport_write(void *opaque, hwaddr addr,
+                         uint64_t val, unsigned size)
+{
+    PCIQXLDevice *d = opaque;
+    uint32_t io_port = addr;
+    qxl_async_io async = QXL_SYNC;
+    uint32_t orig_io_port = io_port;
+
+    if (d->guest_bug && io_port != QXL_IO_RESET) {
+        return;
+    }
+
+    if (d->revision <= QXL_REVISION_STABLE_V10 &&
+        io_port > QXL_IO_FLUSH_RELEASE) {
+        qxl_set_guest_bug(d, "unsupported io %d for revision %d\n",
+            io_port, d->revision);
+        return;
+    }
+
+    switch (io_port) {
+    case QXL_IO_RESET:
+    case QXL_IO_SET_MODE:
+    case QXL_IO_MEMSLOT_ADD:
+    case QXL_IO_MEMSLOT_DEL:
+    case QXL_IO_CREATE_PRIMARY:
+    case QXL_IO_UPDATE_IRQ:
+    case QXL_IO_LOG:
+    case QXL_IO_MEMSLOT_ADD_ASYNC:
+    case QXL_IO_CREATE_PRIMARY_ASYNC:
+        break;
+    default:
+        if (d->mode != QXL_MODE_VGA) {
+            break;
+        }
+        trace_qxl_io_unexpected_vga_mode(d->id,
+            addr, val, io_port_to_string(io_port));
+        /* be nice to buggy guest drivers */
+        if (io_port >= QXL_IO_UPDATE_AREA_ASYNC &&
+            io_port < QXL_IO_RANGE_SIZE) {
+            qxl_send_events(d, QXL_INTERRUPT_IO_CMD);
+        }
+        return;
+    }
+
+    /* we change the io_port to avoid ifdeffery in the main switch */
+    orig_io_port = io_port;
+    switch (io_port) {
+    case QXL_IO_UPDATE_AREA_ASYNC:
+        io_port = QXL_IO_UPDATE_AREA;
+        goto async_common;
+    case QXL_IO_MEMSLOT_ADD_ASYNC:
+        io_port = QXL_IO_MEMSLOT_ADD;
+        goto async_common;
+    case QXL_IO_CREATE_PRIMARY_ASYNC:
+        io_port = QXL_IO_CREATE_PRIMARY;
+        goto async_common;
+    case QXL_IO_DESTROY_PRIMARY_ASYNC:
+        io_port = QXL_IO_DESTROY_PRIMARY;
+        goto async_common;
+    case QXL_IO_DESTROY_SURFACE_ASYNC:
+        io_port = QXL_IO_DESTROY_SURFACE_WAIT;
+        goto async_common;
+    case QXL_IO_DESTROY_ALL_SURFACES_ASYNC:
+        io_port = QXL_IO_DESTROY_ALL_SURFACES;
+        goto async_common;
+    case QXL_IO_FLUSH_SURFACES_ASYNC:
+    case QXL_IO_MONITORS_CONFIG_ASYNC:
+async_common:
+        async = QXL_ASYNC;
+        qemu_mutex_lock(&d->async_lock);
+        if (d->current_async != QXL_UNDEFINED_IO) {
+            qxl_set_guest_bug(d, "%d async started before last (%d) complete",
+                io_port, d->current_async);
+            qemu_mutex_unlock(&d->async_lock);
+            return;
+        }
+        d->current_async = orig_io_port;
+        qemu_mutex_unlock(&d->async_lock);
+        break;
+    default:
+        break;
+    }
+    trace_qxl_io_write(d->id, qxl_mode_to_string(d->mode), addr, val, size,
+                       async);
+
+    switch (io_port) {
+    case QXL_IO_UPDATE_AREA:
+    {
+        QXLCookie *cookie = NULL;
+        QXLRect update = d->ram->update_area;
+
+        if (d->ram->update_surface > d->ssd.num_surfaces) {
+            qxl_set_guest_bug(d, "QXL_IO_UPDATE_AREA: invalid surface id %d\n",
+                              d->ram->update_surface);
+            break;
+        }
+        if (update.left >= update.right || update.top >= update.bottom ||
+            update.left < 0 || update.top < 0) {
+            qxl_set_guest_bug(d,
+                    "QXL_IO_UPDATE_AREA: invalid area (%ux%u)x(%ux%u)\n",
+                    update.left, update.top, update.right, update.bottom);
+            break;
+        }
+        if (async == QXL_ASYNC) {
+            cookie = qxl_cookie_new(QXL_COOKIE_TYPE_IO,
+                                    QXL_IO_UPDATE_AREA_ASYNC);
+            cookie->u.area = update;
+        }
+        qxl_spice_update_area(d, d->ram->update_surface,
+                              cookie ? &cookie->u.area : &update,
+                              NULL, 0, 0, async, cookie);
+        break;
+    }
+    case QXL_IO_NOTIFY_CMD:
+        qemu_spice_wakeup(&d->ssd);
+        break;
+    case QXL_IO_NOTIFY_CURSOR:
+        qemu_spice_wakeup(&d->ssd);
+        break;
+    case QXL_IO_UPDATE_IRQ:
+        qxl_update_irq(d);
+        break;
+    case QXL_IO_NOTIFY_OOM:
+        if (!SPICE_RING_IS_EMPTY(&d->ram->release_ring)) {
+            break;
+        }
+        d->oom_running = 1;
+        qxl_spice_oom(d);
+        d->oom_running = 0;
+        break;
+    case QXL_IO_SET_MODE:
+        qxl_set_mode(d, val, 0);
+        break;
+    case QXL_IO_LOG:
+        trace_qxl_io_log(d->id, d->ram->log_buf);
+        if (d->guestdebug) {
+            fprintf(stderr, "qxl/guest-%d: %" PRId64 ": %s", d->id,
+                    qemu_get_clock_ns(vm_clock), d->ram->log_buf);
+        }
+        break;
+    case QXL_IO_RESET:
+        qxl_hard_reset(d, 0);
+        break;
+    case QXL_IO_MEMSLOT_ADD:
+        if (val >= NUM_MEMSLOTS) {
+            qxl_set_guest_bug(d, "QXL_IO_MEMSLOT_ADD: val out of range");
+            break;
+        }
+        if (d->guest_slots[val].active) {
+            qxl_set_guest_bug(d,
+                        "QXL_IO_MEMSLOT_ADD: memory slot already active");
+            break;
+        }
+        d->guest_slots[val].slot = d->ram->mem_slot;
+        qxl_add_memslot(d, val, 0, async);
+        break;
+    case QXL_IO_MEMSLOT_DEL:
+        if (val >= NUM_MEMSLOTS) {
+            qxl_set_guest_bug(d, "QXL_IO_MEMSLOT_DEL: val out of range");
+            break;
+        }
+        qxl_del_memslot(d, val);
+        break;
+    case QXL_IO_CREATE_PRIMARY:
+        if (val != 0) {
+            qxl_set_guest_bug(d, "QXL_IO_CREATE_PRIMARY (async=%d): val != 0",
+                          async);
+            goto cancel_async;
+        }
+        d->guest_primary.surface = d->ram->create_surface;
+        qxl_create_guest_primary(d, 0, async);
+        break;
+    case QXL_IO_DESTROY_PRIMARY:
+        if (val != 0) {
+            qxl_set_guest_bug(d, "QXL_IO_DESTROY_PRIMARY (async=%d): val != 0",
+                          async);
+            goto cancel_async;
+        }
+        if (!qxl_destroy_primary(d, async)) {
+            trace_qxl_io_destroy_primary_ignored(d->id,
+                                                 qxl_mode_to_string(d->mode));
+            goto cancel_async;
+        }
+        break;
+    case QXL_IO_DESTROY_SURFACE_WAIT:
+        if (val >= d->ssd.num_surfaces) {
+            qxl_set_guest_bug(d, "QXL_IO_DESTROY_SURFACE (async=%d):"
+                             "%" PRIu64 " >= NUM_SURFACES", async, val);
+            goto cancel_async;
+        }
+        qxl_spice_destroy_surface_wait(d, val, async);
+        break;
+    case QXL_IO_FLUSH_RELEASE: {
+        QXLReleaseRing *ring = &d->ram->release_ring;
+        if (ring->prod - ring->cons + 1 == ring->num_items) {
+            fprintf(stderr,
+                "ERROR: no flush, full release ring [p%d,%dc]\n",
+                ring->prod, ring->cons);
+        }
+        qxl_push_free_res(d, 1 /* flush */);
+        break;
+    }
+    case QXL_IO_FLUSH_SURFACES_ASYNC:
+        qxl_spice_flush_surfaces_async(d);
+        break;
+    case QXL_IO_DESTROY_ALL_SURFACES:
+        d->mode = QXL_MODE_UNDEFINED;
+        qxl_spice_destroy_surfaces(d, async);
+        break;
+    case QXL_IO_MONITORS_CONFIG_ASYNC:
+        qxl_spice_monitors_config_async(d, 0);
+        break;
+    default:
+        qxl_set_guest_bug(d, "%s: unexpected ioport=0x%x\n", __func__, io_port);
+    }
+    return;
+cancel_async:
+    if (async) {
+        qxl_send_events(d, QXL_INTERRUPT_IO_CMD);
+        qemu_mutex_lock(&d->async_lock);
+        d->current_async = QXL_UNDEFINED_IO;
+        qemu_mutex_unlock(&d->async_lock);
+    }
+}
+
+static uint64_t ioport_read(void *opaque, hwaddr addr,
+                            unsigned size)
+{
+    PCIQXLDevice *qxl = opaque;
+
+    trace_qxl_io_read_unexpected(qxl->id);
+    return 0xff;
+}
+
+static const MemoryRegionOps qxl_io_ops = {
+    .read = ioport_read,
+    .write = ioport_write,
+    .valid = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+};
+
+static void pipe_read(void *opaque)
+{
+    PCIQXLDevice *d = opaque;
+    char dummy;
+    int len;
+
+    do {
+        len = read(d->pipe[0], &dummy, sizeof(dummy));
+    } while (len == sizeof(dummy));
+    qxl_update_irq(d);
+}
+
+static void qxl_send_events(PCIQXLDevice *d, uint32_t events)
+{
+    uint32_t old_pending;
+    uint32_t le_events = cpu_to_le32(events);
+
+    trace_qxl_send_events(d->id, events);
+    if (!qemu_spice_display_is_running(&d->ssd)) {
+        /* spice-server tracks guest running state and should not do this */
+        fprintf(stderr, "%s: spice-server bug: guest stopped, ignoring\n",
+                __func__);
+        trace_qxl_send_events_vm_stopped(d->id, events);
+        return;
+    }
+    old_pending = __sync_fetch_and_or(&d->ram->int_pending, le_events);
+    if ((old_pending & le_events) == le_events) {
+        return;
+    }
+    if (qemu_thread_is_self(&d->main)) {
+        qxl_update_irq(d);
+    } else {
+        if (write(d->pipe[1], d, 1) != 1) {
+            dprint(d, 1, "%s: write to pipe failed\n", __func__);
+        }
+    }
+}
+
+static void init_pipe_signaling(PCIQXLDevice *d)
+{
+    if (pipe(d->pipe) < 0) {
+        fprintf(stderr, "%s:%s: qxl pipe creation failed\n",
+                __FILE__, __func__);
+        exit(1);
+    }
+    fcntl(d->pipe[0], F_SETFL, O_NONBLOCK);
+    fcntl(d->pipe[1], F_SETFL, O_NONBLOCK);
+    fcntl(d->pipe[0], F_SETOWN, getpid());
+
+    qemu_thread_get_self(&d->main);
+    qemu_set_fd_handler(d->pipe[0], pipe_read, NULL, d);
+}
+
+/* graphics console */
+
+static void qxl_hw_update(void *opaque)
+{
+    PCIQXLDevice *qxl = opaque;
+    VGACommonState *vga = &qxl->vga;
+
+    switch (qxl->mode) {
+    case QXL_MODE_VGA:
+        vga->update(vga);
+        break;
+    case QXL_MODE_COMPAT:
+    case QXL_MODE_NATIVE:
+        qxl_render_update(qxl);
+        break;
+    default:
+        break;
+    }
+}
+
+static void qxl_hw_invalidate(void *opaque)
+{
+    PCIQXLDevice *qxl = opaque;
+    VGACommonState *vga = &qxl->vga;
+
+    vga->invalidate(vga);
+}
+
+static void qxl_hw_screen_dump(void *opaque, const char *filename, bool cswitch,
+                               Error **errp)
+{
+    PCIQXLDevice *qxl = opaque;
+    VGACommonState *vga = &qxl->vga;
+
+    switch (qxl->mode) {
+    case QXL_MODE_COMPAT:
+    case QXL_MODE_NATIVE:
+        qxl_render_update(qxl);
+        ppm_save(filename, qxl->ssd.ds, errp);
+        break;
+    case QXL_MODE_VGA:
+        vga->screen_dump(vga, filename, cswitch, errp);
+        break;
+    default:
+        break;
+    }
+}
+
+static void qxl_hw_text_update(void *opaque, console_ch_t *chardata)
+{
+    PCIQXLDevice *qxl = opaque;
+    VGACommonState *vga = &qxl->vga;
+
+    if (qxl->mode == QXL_MODE_VGA) {
+        vga->text_update(vga, chardata);
+        return;
+    }
+}
+
+static void qxl_dirty_surfaces(PCIQXLDevice *qxl)
+{
+    uintptr_t vram_start;
+    int i;
+
+    if (qxl->mode != QXL_MODE_NATIVE && qxl->mode != QXL_MODE_COMPAT) {
+        return;
+    }
+
+    /* dirty the primary surface */
+    qxl_set_dirty(&qxl->vga.vram, qxl->shadow_rom.draw_area_offset,
+                  qxl->shadow_rom.surface0_area_size);
+
+    vram_start = (uintptr_t)memory_region_get_ram_ptr(&qxl->vram_bar);
+
+    /* dirty the off-screen surfaces */
+    for (i = 0; i < qxl->ssd.num_surfaces; i++) {
+        QXLSurfaceCmd *cmd;
+        intptr_t surface_offset;
+        int surface_size;
+
+        if (qxl->guest_surfaces.cmds[i] == 0) {
+            continue;
+        }
+
+        cmd = qxl_phys2virt(qxl, qxl->guest_surfaces.cmds[i],
+                            MEMSLOT_GROUP_GUEST);
+        assert(cmd);
+        assert(cmd->type == QXL_SURFACE_CMD_CREATE);
+        surface_offset = (intptr_t)qxl_phys2virt(qxl,
+                                                 cmd->u.surface_create.data,
+                                                 MEMSLOT_GROUP_GUEST);
+        assert(surface_offset);
+        surface_offset -= vram_start;
+        surface_size = cmd->u.surface_create.height *
+                       abs(cmd->u.surface_create.stride);
+        trace_qxl_surfaces_dirty(qxl->id, i, (int)surface_offset, surface_size);
+        qxl_set_dirty(&qxl->vram_bar, surface_offset, surface_size);
+    }
+}
+
+static void qxl_vm_change_state_handler(void *opaque, int running,
+                                        RunState state)
+{
+    PCIQXLDevice *qxl = opaque;
+
+    if (running) {
+        /*
+         * if qxl_send_events was called from spice server context before
+         * migration ended, qxl_update_irq for these events might not have been
+         * called
+         */
+         qxl_update_irq(qxl);
+    } else {
+        /* make sure surfaces are saved before migration */
+        qxl_dirty_surfaces(qxl);
+    }
+}
+
+/* display change listener */
+
+static void display_update(DisplayChangeListener *dcl,
+                           int x, int y, int w, int h)
+{
+    PCIQXLDevice *qxl = container_of(dcl, PCIQXLDevice, ssd.dcl);
+
+    if (qxl->mode == QXL_MODE_VGA) {
+        qemu_spice_display_update(&qxl->ssd, x, y, w, h);
+    }
+}
+
+static void display_switch(DisplayChangeListener *dcl,
+                           struct DisplaySurface *surface)
+{
+    PCIQXLDevice *qxl = container_of(dcl, PCIQXLDevice, ssd.dcl);
+
+    qxl->ssd.ds = surface;
+    if (qxl->mode == QXL_MODE_VGA) {
+        qemu_spice_display_switch(&qxl->ssd, surface);
+    }
+}
+
+static void display_refresh(DisplayChangeListener *dcl)
+{
+    PCIQXLDevice *qxl = container_of(dcl, PCIQXLDevice, ssd.dcl);
+
+    if (qxl->mode == QXL_MODE_VGA) {
+        qemu_spice_display_refresh(&qxl->ssd);
+    } else {
+        qemu_mutex_lock(&qxl->ssd.lock);
+        qemu_spice_cursor_refresh_unlocked(&qxl->ssd);
+        qemu_mutex_unlock(&qxl->ssd.lock);
+    }
+}
+
+static DisplayChangeListenerOps display_listener_ops = {
+    .dpy_name        = "spice/qxl",
+    .dpy_gfx_update  = display_update,
+    .dpy_gfx_switch  = display_switch,
+    .dpy_refresh     = display_refresh,
+};
+
+static void qxl_init_ramsize(PCIQXLDevice *qxl)
+{
+    /* vga mode framebuffer / primary surface (bar 0, first part) */
+    if (qxl->vgamem_size_mb < 8) {
+        qxl->vgamem_size_mb = 8;
+    }
+    qxl->vgamem_size = qxl->vgamem_size_mb * 1024 * 1024;
+
+    /* vga ram (bar 0, total) */
+    if (qxl->ram_size_mb != -1) {
+        qxl->vga.vram_size = qxl->ram_size_mb * 1024 * 1024;
+    }
+    if (qxl->vga.vram_size < qxl->vgamem_size * 2) {
+        qxl->vga.vram_size = qxl->vgamem_size * 2;
+    }
+
+    /* vram32 (surfaces, 32bit, bar 1) */
+    if (qxl->vram32_size_mb != -1) {
+        qxl->vram32_size = qxl->vram32_size_mb * 1024 * 1024;
+    }
+    if (qxl->vram32_size < 4096) {
+        qxl->vram32_size = 4096;
+    }
+
+    /* vram (surfaces, 64bit, bar 4+5) */
+    if (qxl->vram_size_mb != -1) {
+        qxl->vram_size = qxl->vram_size_mb * 1024 * 1024;
+    }
+    if (qxl->vram_size < qxl->vram32_size) {
+        qxl->vram_size = qxl->vram32_size;
+    }
+
+    if (qxl->revision == 1) {
+        qxl->vram32_size = 4096;
+        qxl->vram_size = 4096;
+    }
+    qxl->vgamem_size = msb_mask(qxl->vgamem_size * 2 - 1);
+    qxl->vga.vram_size = msb_mask(qxl->vga.vram_size * 2 - 1);
+    qxl->vram32_size = msb_mask(qxl->vram32_size * 2 - 1);
+    qxl->vram_size = msb_mask(qxl->vram_size * 2 - 1);
+}
+
+static int qxl_init_common(PCIQXLDevice *qxl)
+{
+    uint8_t* config = qxl->pci.config;
+    uint32_t pci_device_rev;
+    uint32_t io_size;
+
+    qxl->mode = QXL_MODE_UNDEFINED;
+    qxl->generation = 1;
+    qxl->num_memslots = NUM_MEMSLOTS;
+    qemu_mutex_init(&qxl->track_lock);
+    qemu_mutex_init(&qxl->async_lock);
+    qxl->current_async = QXL_UNDEFINED_IO;
+    qxl->guest_bug = 0;
+
+    switch (qxl->revision) {
+    case 1: /* spice 0.4 -- qxl-1 */
+        pci_device_rev = QXL_REVISION_STABLE_V04;
+        io_size = 8;
+        break;
+    case 2: /* spice 0.6 -- qxl-2 */
+        pci_device_rev = QXL_REVISION_STABLE_V06;
+        io_size = 16;
+        break;
+    case 3: /* qxl-3 */
+        pci_device_rev = QXL_REVISION_STABLE_V10;
+        io_size = 32; /* PCI region size must be pow2 */
+        break;
+    case 4: /* qxl-4 */
+        pci_device_rev = QXL_REVISION_STABLE_V12;
+        io_size = msb_mask(QXL_IO_RANGE_SIZE * 2 - 1);
+        break;
+    default:
+        error_report("Invalid revision %d for qxl device (max %d)",
+                     qxl->revision, QXL_DEFAULT_REVISION);
+        return -1;
+    }
+
+    pci_set_byte(&config[PCI_REVISION_ID], pci_device_rev);
+    pci_set_byte(&config[PCI_INTERRUPT_PIN], 1);
+
+    qxl->rom_size = qxl_rom_size();
+    memory_region_init_ram(&qxl->rom_bar, "qxl.vrom", qxl->rom_size);
+    vmstate_register_ram(&qxl->rom_bar, &qxl->pci.qdev);
+    init_qxl_rom(qxl);
+    init_qxl_ram(qxl);
+
+    qxl->guest_surfaces.cmds = g_new0(QXLPHYSICAL, qxl->ssd.num_surfaces);
+    memory_region_init_ram(&qxl->vram_bar, "qxl.vram", qxl->vram_size);
+    vmstate_register_ram(&qxl->vram_bar, &qxl->pci.qdev);
+    memory_region_init_alias(&qxl->vram32_bar, "qxl.vram32", &qxl->vram_bar,
+                             0, qxl->vram32_size);
+
+    memory_region_init_io(&qxl->io_bar, &qxl_io_ops, qxl,
+                          "qxl-ioports", io_size);
+    if (qxl->id == 0) {
+        vga_dirty_log_start(&qxl->vga);
+    }
+    memory_region_set_flush_coalesced(&qxl->io_bar);
+
+
+    pci_register_bar(&qxl->pci, QXL_IO_RANGE_INDEX,
+                     PCI_BASE_ADDRESS_SPACE_IO, &qxl->io_bar);
+
+    pci_register_bar(&qxl->pci, QXL_ROM_RANGE_INDEX,
+                     PCI_BASE_ADDRESS_SPACE_MEMORY, &qxl->rom_bar);
+
+    pci_register_bar(&qxl->pci, QXL_RAM_RANGE_INDEX,
+                     PCI_BASE_ADDRESS_SPACE_MEMORY, &qxl->vga.vram);
+
+    pci_register_bar(&qxl->pci, QXL_VRAM_RANGE_INDEX,
+                     PCI_BASE_ADDRESS_SPACE_MEMORY, &qxl->vram32_bar);
+
+    if (qxl->vram32_size < qxl->vram_size) {
+        /*
+         * Make the 64bit vram bar show up only in case it is
+         * configured to be larger than the 32bit vram bar.
+         */
+        pci_register_bar(&qxl->pci, QXL_VRAM64_RANGE_INDEX,
+                         PCI_BASE_ADDRESS_SPACE_MEMORY |
+                         PCI_BASE_ADDRESS_MEM_TYPE_64 |
+                         PCI_BASE_ADDRESS_MEM_PREFETCH,
+                         &qxl->vram_bar);
+    }
+
+    /* print pci bar details */
+    dprint(qxl, 1, "ram/%s: %d MB [region 0]\n",
+           qxl->id == 0 ? "pri" : "sec",
+           qxl->vga.vram_size / (1024*1024));
+    dprint(qxl, 1, "vram/32: %d MB [region 1]\n",
+           qxl->vram32_size / (1024*1024));
+    dprint(qxl, 1, "vram/64: %d MB %s\n",
+           qxl->vram_size / (1024*1024),
+           qxl->vram32_size < qxl->vram_size ? "[region 4]" : "[unmapped]");
+
+    qxl->ssd.qxl.base.sif = &qxl_interface.base;
+    qxl->ssd.qxl.id = qxl->id;
+    if (qemu_spice_add_interface(&qxl->ssd.qxl.base) != 0) {
+        error_report("qxl interface %d.%d not supported by spice-server",
+                     SPICE_INTERFACE_QXL_MAJOR, SPICE_INTERFACE_QXL_MINOR);
+        return -1;
+    }
+    qemu_add_vm_change_state_handler(qxl_vm_change_state_handler, qxl);
+
+    init_pipe_signaling(qxl);
+    qxl_reset_state(qxl);
+
+    qxl->update_area_bh = qemu_bh_new(qxl_render_update_area_bh, qxl);
+
+    return 0;
+}
+
+static int qxl_init_primary(PCIDevice *dev)
+{
+    PCIQXLDevice *qxl = DO_UPCAST(PCIQXLDevice, pci, dev);
+    VGACommonState *vga = &qxl->vga;
+    PortioList *qxl_vga_port_list = g_new(PortioList, 1);
+    DisplayState *ds;
+    int rc;
+
+    qxl->id = 0;
+    qxl_init_ramsize(qxl);
+    vga->vram_size_mb = qxl->vga.vram_size >> 20;
+    vga_common_init(vga);
+    vga_init(vga, pci_address_space(dev), pci_address_space_io(dev), false);
+    portio_list_init(qxl_vga_port_list, qxl_vga_portio_list, vga, "vga");
+    portio_list_add(qxl_vga_port_list, pci_address_space_io(dev), 0x3b0);
+
+    vga->con = graphic_console_init(qxl_hw_update, qxl_hw_invalidate,
+                                    qxl_hw_screen_dump, qxl_hw_text_update,
+                                    qxl);
+    qxl->ssd.con = vga->con,
+    qemu_spice_display_init_common(&qxl->ssd);
+
+    rc = qxl_init_common(qxl);
+    if (rc != 0) {
+        return rc;
+    }
+
+    qxl->ssd.dcl.ops = &display_listener_ops;
+    ds = qemu_console_displaystate(vga->con);
+    register_displaychangelistener(ds, &qxl->ssd.dcl);
+    return rc;
+}
+
+static int qxl_init_secondary(PCIDevice *dev)
+{
+    static int device_id = 1;
+    PCIQXLDevice *qxl = DO_UPCAST(PCIQXLDevice, pci, dev);
+
+    qxl->id = device_id++;
+    qxl_init_ramsize(qxl);
+    memory_region_init_ram(&qxl->vga.vram, "qxl.vgavram", qxl->vga.vram_size);
+    vmstate_register_ram(&qxl->vga.vram, &qxl->pci.qdev);
+    qxl->vga.vram_ptr = memory_region_get_ram_ptr(&qxl->vga.vram);
+
+    return qxl_init_common(qxl);
+}
+
+static void qxl_pre_save(void *opaque)
+{
+    PCIQXLDevice* d = opaque;
+    uint8_t *ram_start = d->vga.vram_ptr;
+
+    trace_qxl_pre_save(d->id);
+    if (d->last_release == NULL) {
+        d->last_release_offset = 0;
+    } else {
+        d->last_release_offset = (uint8_t *)d->last_release - ram_start;
+    }
+    assert(d->last_release_offset < d->vga.vram_size);
+}
+
+static int qxl_pre_load(void *opaque)
+{
+    PCIQXLDevice* d = opaque;
+
+    trace_qxl_pre_load(d->id);
+    qxl_hard_reset(d, 1);
+    qxl_exit_vga_mode(d);
+    return 0;
+}
+
+static void qxl_create_memslots(PCIQXLDevice *d)
+{
+    int i;
+
+    for (i = 0; i < NUM_MEMSLOTS; i++) {
+        if (!d->guest_slots[i].active) {
+            continue;
+        }
+        qxl_add_memslot(d, i, 0, QXL_SYNC);
+    }
+}
+
+static int qxl_post_load(void *opaque, int version)
+{
+    PCIQXLDevice* d = opaque;
+    uint8_t *ram_start = d->vga.vram_ptr;
+    QXLCommandExt *cmds;
+    int in, out, newmode;
+
+    assert(d->last_release_offset < d->vga.vram_size);
+    if (d->last_release_offset == 0) {
+        d->last_release = NULL;
+    } else {
+        d->last_release = (QXLReleaseInfo *)(ram_start + d->last_release_offset);
+    }
+
+    d->modes = (QXLModes*)((uint8_t*)d->rom + d->rom->modes_offset);
+
+    trace_qxl_post_load(d->id, qxl_mode_to_string(d->mode));
+    newmode = d->mode;
+    d->mode = QXL_MODE_UNDEFINED;
+
+    switch (newmode) {
+    case QXL_MODE_UNDEFINED:
+        qxl_create_memslots(d);
+        break;
+    case QXL_MODE_VGA:
+        qxl_create_memslots(d);
+        qxl_enter_vga_mode(d);
+        break;
+    case QXL_MODE_NATIVE:
+        qxl_create_memslots(d);
+        qxl_create_guest_primary(d, 1, QXL_SYNC);
+
+        /* replay surface-create and cursor-set commands */
+        cmds = g_malloc0(sizeof(QXLCommandExt) * (d->ssd.num_surfaces + 1));
+        for (in = 0, out = 0; in < d->ssd.num_surfaces; in++) {
+            if (d->guest_surfaces.cmds[in] == 0) {
+                continue;
+            }
+            cmds[out].cmd.data = d->guest_surfaces.cmds[in];
+            cmds[out].cmd.type = QXL_CMD_SURFACE;
+            cmds[out].group_id = MEMSLOT_GROUP_GUEST;
+            out++;
+        }
+        if (d->guest_cursor) {
+            cmds[out].cmd.data = d->guest_cursor;
+            cmds[out].cmd.type = QXL_CMD_CURSOR;
+            cmds[out].group_id = MEMSLOT_GROUP_GUEST;
+            out++;
+        }
+        qxl_spice_loadvm_commands(d, cmds, out);
+        g_free(cmds);
+        if (d->guest_monitors_config) {
+            qxl_spice_monitors_config_async(d, 1);
+        }
+        break;
+    case QXL_MODE_COMPAT:
+        /* note: no need to call qxl_create_memslots, qxl_set_mode
+         * creates the mem slot. */
+        qxl_set_mode(d, d->shadow_rom.mode, 1);
+        break;
+    }
+    return 0;
+}
+
+#define QXL_SAVE_VERSION 21
+
+static bool qxl_monitors_config_needed(void *opaque)
+{
+    PCIQXLDevice *qxl = opaque;
+
+    return qxl->guest_monitors_config != 0;
+}
+
+
+static VMStateDescription qxl_memslot = {
+    .name               = "qxl-memslot",
+    .version_id         = QXL_SAVE_VERSION,
+    .minimum_version_id = QXL_SAVE_VERSION,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT64(slot.mem_start, struct guest_slots),
+        VMSTATE_UINT64(slot.mem_end,   struct guest_slots),
+        VMSTATE_UINT32(active,         struct guest_slots),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static VMStateDescription qxl_surface = {
+    .name               = "qxl-surface",
+    .version_id         = QXL_SAVE_VERSION,
+    .minimum_version_id = QXL_SAVE_VERSION,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(width,      QXLSurfaceCreate),
+        VMSTATE_UINT32(height,     QXLSurfaceCreate),
+        VMSTATE_INT32(stride,      QXLSurfaceCreate),
+        VMSTATE_UINT32(format,     QXLSurfaceCreate),
+        VMSTATE_UINT32(position,   QXLSurfaceCreate),
+        VMSTATE_UINT32(mouse_mode, QXLSurfaceCreate),
+        VMSTATE_UINT32(flags,      QXLSurfaceCreate),
+        VMSTATE_UINT32(type,       QXLSurfaceCreate),
+        VMSTATE_UINT64(mem,        QXLSurfaceCreate),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static VMStateDescription qxl_vmstate_monitors_config = {
+    .name               = "qxl/monitors-config",
+    .version_id         = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT64(guest_monitors_config, PCIQXLDevice),
+        VMSTATE_END_OF_LIST()
+    },
+};
+
+static VMStateDescription qxl_vmstate = {
+    .name               = "qxl",
+    .version_id         = QXL_SAVE_VERSION,
+    .minimum_version_id = QXL_SAVE_VERSION,
+    .pre_save           = qxl_pre_save,
+    .pre_load           = qxl_pre_load,
+    .post_load          = qxl_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_PCI_DEVICE(pci, PCIQXLDevice),
+        VMSTATE_STRUCT(vga, PCIQXLDevice, 0, vmstate_vga_common, VGACommonState),
+        VMSTATE_UINT32(shadow_rom.mode, PCIQXLDevice),
+        VMSTATE_UINT32(num_free_res, PCIQXLDevice),
+        VMSTATE_UINT32(last_release_offset, PCIQXLDevice),
+        VMSTATE_UINT32(mode, PCIQXLDevice),
+        VMSTATE_UINT32(ssd.unique, PCIQXLDevice),
+        VMSTATE_INT32_EQUAL(num_memslots, PCIQXLDevice),
+        VMSTATE_STRUCT_ARRAY(guest_slots, PCIQXLDevice, NUM_MEMSLOTS, 0,
+                             qxl_memslot, struct guest_slots),
+        VMSTATE_STRUCT(guest_primary.surface, PCIQXLDevice, 0,
+                       qxl_surface, QXLSurfaceCreate),
+        VMSTATE_INT32_EQUAL(ssd.num_surfaces, PCIQXLDevice),
+        VMSTATE_VARRAY_INT32(guest_surfaces.cmds, PCIQXLDevice,
+                             ssd.num_surfaces, 0,
+                             vmstate_info_uint64, uint64_t),
+        VMSTATE_UINT64(guest_cursor, PCIQXLDevice),
+        VMSTATE_END_OF_LIST()
+    },
+    .subsections = (VMStateSubsection[]) {
+        {
+            .vmsd = &qxl_vmstate_monitors_config,
+            .needed = qxl_monitors_config_needed,
+        }, {
+            /* empty */
+        }
+    }
+};
+
+static Property qxl_properties[] = {
+        DEFINE_PROP_UINT32("ram_size", PCIQXLDevice, vga.vram_size,
+                           64 * 1024 * 1024),
+        DEFINE_PROP_UINT32("vram_size", PCIQXLDevice, vram32_size,
+                           64 * 1024 * 1024),
+        DEFINE_PROP_UINT32("revision", PCIQXLDevice, revision,
+                           QXL_DEFAULT_REVISION),
+        DEFINE_PROP_UINT32("debug", PCIQXLDevice, debug, 0),
+        DEFINE_PROP_UINT32("guestdebug", PCIQXLDevice, guestdebug, 0),
+        DEFINE_PROP_UINT32("cmdlog", PCIQXLDevice, cmdlog, 0),
+        DEFINE_PROP_UINT32("ram_size_mb",  PCIQXLDevice, ram_size_mb, -1),
+        DEFINE_PROP_UINT32("vram_size_mb", PCIQXLDevice, vram32_size_mb, -1),
+        DEFINE_PROP_UINT32("vram64_size_mb", PCIQXLDevice, vram_size_mb, -1),
+        DEFINE_PROP_UINT32("vgamem_mb", PCIQXLDevice, vgamem_size_mb, 16),
+        DEFINE_PROP_INT32("surfaces", PCIQXLDevice, ssd.num_surfaces, 1024),
+        DEFINE_PROP_END_OF_LIST(),
+};
+
+static void qxl_primary_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->no_hotplug = 1;
+    k->init = qxl_init_primary;
+    k->romfile = "vgabios-qxl.bin";
+    k->vendor_id = REDHAT_PCI_VENDOR_ID;
+    k->device_id = QXL_DEVICE_ID_STABLE;
+    k->class_id = PCI_CLASS_DISPLAY_VGA;
+    dc->desc = "Spice QXL GPU (primary, vga compatible)";
+    dc->reset = qxl_reset_handler;
+    dc->vmsd = &qxl_vmstate;
+    dc->props = qxl_properties;
+}
+
+static const 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 const TypeInfo qxl_secondary_info = {
+    .name          = "qxl",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PCIQXLDevice),
+    .class_init    = qxl_secondary_class_init,
+};
+
+static void qxl_register_types(void)
+{
+    type_register_static(&qxl_primary_info);
+    type_register_static(&qxl_secondary_info);
+}
+
+type_init(qxl_register_types)
diff --git a/hw/display/qxl.h b/hw/display/qxl.h
new file mode 100644 (file)
index 0000000..8e9b0c2
--- /dev/null
@@ -0,0 +1,165 @@
+#ifndef HW_QXL_H
+#define HW_QXL_H 1
+
+#include "qemu-common.h"
+
+#include "ui/console.h"
+#include "hw/hw.h"
+#include "hw/pci/pci.h"
+#include "vga_int.h"
+#include "qemu/thread.h"
+
+#include "ui/qemu-spice.h"
+#include "ui/spice-display.h"
+
+enum qxl_mode {
+    QXL_MODE_UNDEFINED,
+    QXL_MODE_VGA,
+    QXL_MODE_COMPAT, /* spice 0.4.x */
+    QXL_MODE_NATIVE,
+};
+
+#ifndef QXL_VRAM64_RANGE_INDEX
+#define QXL_VRAM64_RANGE_INDEX 4
+#endif
+
+#define QXL_UNDEFINED_IO UINT32_MAX
+
+#define QXL_NUM_DIRTY_RECTS 64
+
+typedef struct PCIQXLDevice {
+    PCIDevice          pci;
+    SimpleSpiceDisplay ssd;
+    int                id;
+    uint32_t           debug;
+    uint32_t           guestdebug;
+    uint32_t           cmdlog;
+
+    uint32_t           guest_bug;
+
+    enum qxl_mode      mode;
+    uint32_t           cmdflags;
+    int                generation;
+    uint32_t           revision;
+
+    int32_t            num_memslots;
+
+    uint32_t           current_async;
+    QemuMutex          async_lock;
+
+    struct guest_slots {
+        QXLMemSlot     slot;
+        void           *ptr;
+        uint64_t       size;
+        uint64_t       delta;
+        uint32_t       active;
+    } guest_slots[NUM_MEMSLOTS];
+
+    struct guest_primary {
+        QXLSurfaceCreate surface;
+        uint32_t       commands;
+        uint32_t       resized;
+        int32_t        qxl_stride;
+        uint32_t       abs_stride;
+        uint32_t       bits_pp;
+        uint32_t       bytes_pp;
+        uint8_t        *data;
+    } guest_primary;
+
+    struct surfaces {
+        QXLPHYSICAL    *cmds;
+        uint32_t       count;
+        uint32_t       max;
+    } guest_surfaces;
+    QXLPHYSICAL        guest_cursor;
+
+    QXLPHYSICAL        guest_monitors_config;
+
+    QemuMutex          track_lock;
+
+    /* thread signaling */
+    QemuThread         main;
+    int                pipe[2];
+
+    /* ram pci bar */
+    QXLRam             *ram;
+    VGACommonState     vga;
+    uint32_t           num_free_res;
+    QXLReleaseInfo     *last_release;
+    uint32_t           last_release_offset;
+    uint32_t           oom_running;
+    uint32_t           vgamem_size;
+
+    /* rom pci bar */
+    QXLRom             shadow_rom;
+    QXLRom             *rom;
+    QXLModes           *modes;
+    uint32_t           rom_size;
+    MemoryRegion       rom_bar;
+
+    /* vram pci bar */
+    uint32_t           vram_size;
+    MemoryRegion       vram_bar;
+    uint32_t           vram32_size;
+    MemoryRegion       vram32_bar;
+
+    /* io bar */
+    MemoryRegion       io_bar;
+
+    /* user-friendly properties (in megabytes) */
+    uint32_t          ram_size_mb;
+    uint32_t          vram_size_mb;
+    uint32_t          vram32_size_mb;
+    uint32_t          vgamem_size_mb;
+
+    /* qxl_render_update state */
+    int                render_update_cookie_num;
+    int                num_dirty_rects;
+    QXLRect            dirty[QXL_NUM_DIRTY_RECTS];
+    QEMUBH            *update_area_bh;
+} PCIQXLDevice;
+
+#define PANIC_ON(x) if ((x)) {                         \
+    printf("%s: PANIC %s failed\n", __FUNCTION__, #x); \
+    abort();                                           \
+}
+
+#define dprint(_qxl, _level, _fmt, ...)                                 \
+    do {                                                                \
+        if (_qxl->debug >= _level) {                                    \
+            fprintf(stderr, "qxl-%d: ", _qxl->id);                      \
+            fprintf(stderr, _fmt, ## __VA_ARGS__);                      \
+        }                                                               \
+    } while (0)
+
+#define QXL_DEFAULT_REVISION QXL_REVISION_STABLE_V12
+
+/* qxl.c */
+void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL phys, int group_id);
+void qxl_set_guest_bug(PCIQXLDevice *qxl, const char *msg, ...)
+    GCC_FMT_ATTR(2, 3);
+
+void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id,
+                           struct QXLRect *area, struct QXLRect *dirty_rects,
+                           uint32_t num_dirty_rects,
+                           uint32_t clear_dirty_region,
+                           qxl_async_io async, QXLCookie *cookie);
+void qxl_spice_loadvm_commands(PCIQXLDevice *qxl, struct QXLCommandExt *ext,
+                               uint32_t count);
+void qxl_spice_oom(PCIQXLDevice *qxl);
+void qxl_spice_reset_memslots(PCIQXLDevice *qxl);
+void qxl_spice_reset_image_cache(PCIQXLDevice *qxl);
+void qxl_spice_reset_cursor(PCIQXLDevice *qxl);
+
+/* qxl-logger.c */
+int qxl_log_cmd_cursor(PCIQXLDevice *qxl, QXLCursorCmd *cmd, int group_id);
+int qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext);
+
+/* qxl-render.c */
+void qxl_render_resize(PCIQXLDevice *qxl);
+void qxl_render_update(PCIQXLDevice *qxl);
+int qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext);
+void qxl_render_update_area_done(PCIQXLDevice *qxl, QXLCookie *cookie);
+void qxl_render_update_area_bh(void *opaque);
+
+#endif
diff --git a/hw/display/sm501.c b/hw/display/sm501.c
new file mode 100644 (file)
index 0000000..6b660ac
--- /dev/null
@@ -0,0 +1,1450 @@
+/*
+ * QEMU SM501 Device
+ *
+ * Copyright (c) 2008 Shin-ichiro KAWASAKI
+ *
+ * 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 <stdio.h>
+#include "hw/hw.h"
+#include "hw/char/serial.h"
+#include "ui/console.h"
+#include "hw/arm/devices.h"
+#include "hw/sysbus.h"
+#include "hw/qdev-addr.h"
+#include "qemu/range.h"
+#include "ui/pixel_ops.h"
+
+/*
+ * Status: 2010/05/07
+ *   - Minimum implementation for Linux console : mmio regs and CRT layer.
+ *   - 2D grapihcs acceleration partially supported : only fill rectangle.
+ *
+ * TODO:
+ *   - Panel support
+ *   - Touch panel support
+ *   - USB support
+ *   - UART support
+ *   - More 2D graphics engine support
+ *   - Performance tuning
+ */
+
+//#define DEBUG_SM501
+//#define DEBUG_BITBLT
+
+#ifdef DEBUG_SM501
+#define SM501_DPRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__)
+#else
+#define SM501_DPRINTF(fmt, ...) do {} while(0)
+#endif
+
+
+#define MMIO_BASE_OFFSET 0x3e00000
+
+/* SM501 register definitions taken from "linux/include/linux/sm501-regs.h" */
+
+/* System Configuration area */
+/* System config base */
+#define SM501_SYS_CONFIG               (0x000000)
+
+/* config 1 */
+#define SM501_SYSTEM_CONTROL           (0x000000)
+
+#define SM501_SYSCTRL_PANEL_TRISTATE   (1<<0)
+#define SM501_SYSCTRL_MEM_TRISTATE     (1<<1)
+#define SM501_SYSCTRL_CRT_TRISTATE     (1<<2)
+
+#define SM501_SYSCTRL_PCI_SLAVE_BURST_MASK (3<<4)
+#define SM501_SYSCTRL_PCI_SLAVE_BURST_1        (0<<4)
+#define SM501_SYSCTRL_PCI_SLAVE_BURST_2        (1<<4)
+#define SM501_SYSCTRL_PCI_SLAVE_BURST_4        (2<<4)
+#define SM501_SYSCTRL_PCI_SLAVE_BURST_8        (3<<4)
+
+#define SM501_SYSCTRL_PCI_CLOCK_RUN_EN (1<<6)
+#define SM501_SYSCTRL_PCI_RETRY_DISABLE        (1<<7)
+#define SM501_SYSCTRL_PCI_SUBSYS_LOCK  (1<<11)
+#define SM501_SYSCTRL_PCI_BURST_READ_EN        (1<<15)
+
+/* miscellaneous control */
+
+#define SM501_MISC_CONTROL             (0x000004)
+
+#define SM501_MISC_BUS_SH              (0x0)
+#define SM501_MISC_BUS_PCI             (0x1)
+#define SM501_MISC_BUS_XSCALE          (0x2)
+#define SM501_MISC_BUS_NEC             (0x6)
+#define SM501_MISC_BUS_MASK            (0x7)
+
+#define SM501_MISC_VR_62MB             (1<<3)
+#define SM501_MISC_CDR_RESET           (1<<7)
+#define SM501_MISC_USB_LB              (1<<8)
+#define SM501_MISC_USB_SLAVE           (1<<9)
+#define SM501_MISC_BL_1                        (1<<10)
+#define SM501_MISC_MC                  (1<<11)
+#define SM501_MISC_DAC_POWER           (1<<12)
+#define SM501_MISC_IRQ_INVERT          (1<<16)
+#define SM501_MISC_SH                  (1<<17)
+
+#define SM501_MISC_HOLD_EMPTY          (0<<18)
+#define SM501_MISC_HOLD_8              (1<<18)
+#define SM501_MISC_HOLD_16             (2<<18)
+#define SM501_MISC_HOLD_24             (3<<18)
+#define SM501_MISC_HOLD_32             (4<<18)
+#define SM501_MISC_HOLD_MASK           (7<<18)
+
+#define SM501_MISC_FREQ_12             (1<<24)
+#define SM501_MISC_PNL_24BIT           (1<<25)
+#define SM501_MISC_8051_LE             (1<<26)
+
+
+
+#define SM501_GPIO31_0_CONTROL         (0x000008)
+#define SM501_GPIO63_32_CONTROL                (0x00000C)
+#define SM501_DRAM_CONTROL             (0x000010)
+
+/* command list */
+#define SM501_ARBTRTN_CONTROL          (0x000014)
+
+/* command list */
+#define SM501_COMMAND_LIST_STATUS      (0x000024)
+
+/* interrupt debug */
+#define SM501_RAW_IRQ_STATUS           (0x000028)
+#define SM501_RAW_IRQ_CLEAR            (0x000028)
+#define SM501_IRQ_STATUS               (0x00002C)
+#define SM501_IRQ_MASK                 (0x000030)
+#define SM501_DEBUG_CONTROL            (0x000034)
+
+/* power management */
+#define SM501_POWERMODE_P2X_SRC                (1<<29)
+#define SM501_POWERMODE_V2X_SRC                (1<<20)
+#define SM501_POWERMODE_M_SRC          (1<<12)
+#define SM501_POWERMODE_M1_SRC         (1<<4)
+
+#define SM501_CURRENT_GATE             (0x000038)
+#define SM501_CURRENT_CLOCK            (0x00003C)
+#define SM501_POWER_MODE_0_GATE                (0x000040)
+#define SM501_POWER_MODE_0_CLOCK       (0x000044)
+#define SM501_POWER_MODE_1_GATE                (0x000048)
+#define SM501_POWER_MODE_1_CLOCK       (0x00004C)
+#define SM501_SLEEP_MODE_GATE          (0x000050)
+#define SM501_POWER_MODE_CONTROL       (0x000054)
+
+/* power gates for units within the 501 */
+#define SM501_GATE_HOST                        (0)
+#define SM501_GATE_MEMORY              (1)
+#define SM501_GATE_DISPLAY             (2)
+#define SM501_GATE_2D_ENGINE           (3)
+#define SM501_GATE_CSC                 (4)
+#define SM501_GATE_ZVPORT              (5)
+#define SM501_GATE_GPIO                        (6)
+#define SM501_GATE_UART0               (7)
+#define SM501_GATE_UART1               (8)
+#define SM501_GATE_SSP                 (10)
+#define SM501_GATE_USB_HOST            (11)
+#define SM501_GATE_USB_GADGET          (12)
+#define SM501_GATE_UCONTROLLER         (17)
+#define SM501_GATE_AC97                        (18)
+
+/* panel clock */
+#define SM501_CLOCK_P2XCLK             (24)
+/* crt clock */
+#define SM501_CLOCK_V2XCLK             (16)
+/* main clock */
+#define SM501_CLOCK_MCLK               (8)
+/* SDRAM controller clock */
+#define SM501_CLOCK_M1XCLK             (0)
+
+/* config 2 */
+#define SM501_PCI_MASTER_BASE          (0x000058)
+#define SM501_ENDIAN_CONTROL           (0x00005C)
+#define SM501_DEVICEID                 (0x000060)
+/* 0x050100A0 */
+
+#define SM501_DEVICEID_SM501           (0x05010000)
+#define SM501_DEVICEID_IDMASK          (0xffff0000)
+#define SM501_DEVICEID_REVMASK         (0x000000ff)
+
+#define SM501_PLLCLOCK_COUNT           (0x000064)
+#define SM501_MISC_TIMING              (0x000068)
+#define SM501_CURRENT_SDRAM_CLOCK      (0x00006C)
+
+#define SM501_PROGRAMMABLE_PLL_CONTROL (0x000074)
+
+/* GPIO base */
+#define SM501_GPIO                     (0x010000)
+#define SM501_GPIO_DATA_LOW            (0x00)
+#define SM501_GPIO_DATA_HIGH           (0x04)
+#define SM501_GPIO_DDR_LOW             (0x08)
+#define SM501_GPIO_DDR_HIGH            (0x0C)
+#define SM501_GPIO_IRQ_SETUP           (0x10)
+#define SM501_GPIO_IRQ_STATUS          (0x14)
+#define SM501_GPIO_IRQ_RESET           (0x14)
+
+/* I2C controller base */
+#define SM501_I2C                      (0x010040)
+#define SM501_I2C_BYTE_COUNT           (0x00)
+#define SM501_I2C_CONTROL              (0x01)
+#define SM501_I2C_STATUS               (0x02)
+#define SM501_I2C_RESET                        (0x02)
+#define SM501_I2C_SLAVE_ADDRESS                (0x03)
+#define SM501_I2C_DATA                 (0x04)
+
+/* SSP base */
+#define SM501_SSP                      (0x020000)
+
+/* Uart 0 base */
+#define SM501_UART0                    (0x030000)
+
+/* Uart 1 base */
+#define SM501_UART1                    (0x030020)
+
+/* USB host port base */
+#define SM501_USB_HOST                 (0x040000)
+
+/* USB slave/gadget base */
+#define SM501_USB_GADGET               (0x060000)
+
+/* USB slave/gadget data port base */
+#define SM501_USB_GADGET_DATA          (0x070000)
+
+/* Display controller/video engine base */
+#define SM501_DC                       (0x080000)
+
+/* common defines for the SM501 address registers */
+#define SM501_ADDR_FLIP                        (1<<31)
+#define SM501_ADDR_EXT                 (1<<27)
+#define SM501_ADDR_CS1                 (1<<26)
+#define SM501_ADDR_MASK                        (0x3f << 26)
+
+#define SM501_FIFO_MASK                        (0x3 << 16)
+#define SM501_FIFO_1                   (0x0 << 16)
+#define SM501_FIFO_3                   (0x1 << 16)
+#define SM501_FIFO_7                   (0x2 << 16)
+#define SM501_FIFO_11                  (0x3 << 16)
+
+/* common registers for panel and the crt */
+#define SM501_OFF_DC_H_TOT             (0x000)
+#define SM501_OFF_DC_V_TOT             (0x008)
+#define SM501_OFF_DC_H_SYNC            (0x004)
+#define SM501_OFF_DC_V_SYNC            (0x00C)
+
+#define SM501_DC_PANEL_CONTROL         (0x000)
+
+#define SM501_DC_PANEL_CONTROL_FPEN    (1<<27)
+#define SM501_DC_PANEL_CONTROL_BIAS    (1<<26)
+#define SM501_DC_PANEL_CONTROL_DATA    (1<<25)
+#define SM501_DC_PANEL_CONTROL_VDD     (1<<24)
+#define SM501_DC_PANEL_CONTROL_DP      (1<<23)
+
+#define SM501_DC_PANEL_CONTROL_TFT_888 (0<<21)
+#define SM501_DC_PANEL_CONTROL_TFT_333 (1<<21)
+#define SM501_DC_PANEL_CONTROL_TFT_444 (2<<21)
+
+#define SM501_DC_PANEL_CONTROL_DE      (1<<20)
+
+#define SM501_DC_PANEL_CONTROL_LCD_TFT (0<<18)
+#define SM501_DC_PANEL_CONTROL_LCD_STN8        (1<<18)
+#define SM501_DC_PANEL_CONTROL_LCD_STN12 (2<<18)
+
+#define SM501_DC_PANEL_CONTROL_CP      (1<<14)
+#define SM501_DC_PANEL_CONTROL_VSP     (1<<13)
+#define SM501_DC_PANEL_CONTROL_HSP     (1<<12)
+#define SM501_DC_PANEL_CONTROL_CK      (1<<9)
+#define SM501_DC_PANEL_CONTROL_TE      (1<<8)
+#define SM501_DC_PANEL_CONTROL_VPD     (1<<7)
+#define SM501_DC_PANEL_CONTROL_VP      (1<<6)
+#define SM501_DC_PANEL_CONTROL_HPD     (1<<5)
+#define SM501_DC_PANEL_CONTROL_HP      (1<<4)
+#define SM501_DC_PANEL_CONTROL_GAMMA   (1<<3)
+#define SM501_DC_PANEL_CONTROL_EN      (1<<2)
+
+#define SM501_DC_PANEL_CONTROL_8BPP    (0<<0)
+#define SM501_DC_PANEL_CONTROL_16BPP   (1<<0)
+#define SM501_DC_PANEL_CONTROL_32BPP   (2<<0)
+
+
+#define SM501_DC_PANEL_PANNING_CONTROL (0x004)
+#define SM501_DC_PANEL_COLOR_KEY       (0x008)
+#define SM501_DC_PANEL_FB_ADDR         (0x00C)
+#define SM501_DC_PANEL_FB_OFFSET       (0x010)
+#define SM501_DC_PANEL_FB_WIDTH                (0x014)
+#define SM501_DC_PANEL_FB_HEIGHT       (0x018)
+#define SM501_DC_PANEL_TL_LOC          (0x01C)
+#define SM501_DC_PANEL_BR_LOC          (0x020)
+#define SM501_DC_PANEL_H_TOT           (0x024)
+#define SM501_DC_PANEL_H_SYNC          (0x028)
+#define SM501_DC_PANEL_V_TOT           (0x02C)
+#define SM501_DC_PANEL_V_SYNC          (0x030)
+#define SM501_DC_PANEL_CUR_LINE                (0x034)
+
+#define SM501_DC_VIDEO_CONTROL         (0x040)
+#define SM501_DC_VIDEO_FB0_ADDR                (0x044)
+#define SM501_DC_VIDEO_FB_WIDTH                (0x048)
+#define SM501_DC_VIDEO_FB0_LAST_ADDR   (0x04C)
+#define SM501_DC_VIDEO_TL_LOC          (0x050)
+#define SM501_DC_VIDEO_BR_LOC          (0x054)
+#define SM501_DC_VIDEO_SCALE           (0x058)
+#define SM501_DC_VIDEO_INIT_SCALE      (0x05C)
+#define SM501_DC_VIDEO_YUV_CONSTANTS   (0x060)
+#define SM501_DC_VIDEO_FB1_ADDR                (0x064)
+#define SM501_DC_VIDEO_FB1_LAST_ADDR   (0x068)
+
+#define SM501_DC_VIDEO_ALPHA_CONTROL   (0x080)
+#define SM501_DC_VIDEO_ALPHA_FB_ADDR   (0x084)
+#define SM501_DC_VIDEO_ALPHA_FB_OFFSET (0x088)
+#define SM501_DC_VIDEO_ALPHA_FB_LAST_ADDR      (0x08C)
+#define SM501_DC_VIDEO_ALPHA_TL_LOC    (0x090)
+#define SM501_DC_VIDEO_ALPHA_BR_LOC    (0x094)
+#define SM501_DC_VIDEO_ALPHA_SCALE     (0x098)
+#define SM501_DC_VIDEO_ALPHA_INIT_SCALE        (0x09C)
+#define SM501_DC_VIDEO_ALPHA_CHROMA_KEY        (0x0A0)
+#define SM501_DC_VIDEO_ALPHA_COLOR_LOOKUP      (0x0A4)
+
+#define SM501_DC_PANEL_HWC_BASE                (0x0F0)
+#define SM501_DC_PANEL_HWC_ADDR                (0x0F0)
+#define SM501_DC_PANEL_HWC_LOC         (0x0F4)
+#define SM501_DC_PANEL_HWC_COLOR_1_2   (0x0F8)
+#define SM501_DC_PANEL_HWC_COLOR_3     (0x0FC)
+
+#define SM501_HWC_EN                   (1<<31)
+
+#define SM501_OFF_HWC_ADDR             (0x00)
+#define SM501_OFF_HWC_LOC              (0x04)
+#define SM501_OFF_HWC_COLOR_1_2                (0x08)
+#define SM501_OFF_HWC_COLOR_3          (0x0C)
+
+#define SM501_DC_ALPHA_CONTROL         (0x100)
+#define SM501_DC_ALPHA_FB_ADDR         (0x104)
+#define SM501_DC_ALPHA_FB_OFFSET       (0x108)
+#define SM501_DC_ALPHA_TL_LOC          (0x10C)
+#define SM501_DC_ALPHA_BR_LOC          (0x110)
+#define SM501_DC_ALPHA_CHROMA_KEY      (0x114)
+#define SM501_DC_ALPHA_COLOR_LOOKUP    (0x118)
+
+#define SM501_DC_CRT_CONTROL           (0x200)
+
+#define SM501_DC_CRT_CONTROL_TVP       (1<<15)
+#define SM501_DC_CRT_CONTROL_CP                (1<<14)
+#define SM501_DC_CRT_CONTROL_VSP       (1<<13)
+#define SM501_DC_CRT_CONTROL_HSP       (1<<12)
+#define SM501_DC_CRT_CONTROL_VS                (1<<11)
+#define SM501_DC_CRT_CONTROL_BLANK     (1<<10)
+#define SM501_DC_CRT_CONTROL_SEL       (1<<9)
+#define SM501_DC_CRT_CONTROL_TE                (1<<8)
+#define SM501_DC_CRT_CONTROL_PIXEL_MASK (0xF << 4)
+#define SM501_DC_CRT_CONTROL_GAMMA     (1<<3)
+#define SM501_DC_CRT_CONTROL_ENABLE    (1<<2)
+
+#define SM501_DC_CRT_CONTROL_8BPP      (0<<0)
+#define SM501_DC_CRT_CONTROL_16BPP     (1<<0)
+#define SM501_DC_CRT_CONTROL_32BPP     (2<<0)
+
+#define SM501_DC_CRT_FB_ADDR           (0x204)
+#define SM501_DC_CRT_FB_OFFSET         (0x208)
+#define SM501_DC_CRT_H_TOT             (0x20C)
+#define SM501_DC_CRT_H_SYNC            (0x210)
+#define SM501_DC_CRT_V_TOT             (0x214)
+#define SM501_DC_CRT_V_SYNC            (0x218)
+#define SM501_DC_CRT_SIGNATURE_ANALYZER        (0x21C)
+#define SM501_DC_CRT_CUR_LINE          (0x220)
+#define SM501_DC_CRT_MONITOR_DETECT    (0x224)
+
+#define SM501_DC_CRT_HWC_BASE          (0x230)
+#define SM501_DC_CRT_HWC_ADDR          (0x230)
+#define SM501_DC_CRT_HWC_LOC           (0x234)
+#define SM501_DC_CRT_HWC_COLOR_1_2     (0x238)
+#define SM501_DC_CRT_HWC_COLOR_3       (0x23C)
+
+#define SM501_DC_PANEL_PALETTE         (0x400)
+
+#define SM501_DC_VIDEO_PALETTE         (0x800)
+
+#define SM501_DC_CRT_PALETTE           (0xC00)
+
+/* Zoom Video port base */
+#define SM501_ZVPORT                   (0x090000)
+
+/* AC97/I2S base */
+#define SM501_AC97                     (0x0A0000)
+
+/* 8051 micro controller base */
+#define SM501_UCONTROLLER              (0x0B0000)
+
+/* 8051 micro controller SRAM base */
+#define SM501_UCONTROLLER_SRAM         (0x0C0000)
+
+/* DMA base */
+#define SM501_DMA                      (0x0D0000)
+
+/* 2d engine base */
+#define SM501_2D_ENGINE                        (0x100000)
+#define SM501_2D_SOURCE                        (0x00)
+#define SM501_2D_DESTINATION           (0x04)
+#define SM501_2D_DIMENSION             (0x08)
+#define SM501_2D_CONTROL               (0x0C)
+#define SM501_2D_PITCH                 (0x10)
+#define SM501_2D_FOREGROUND            (0x14)
+#define SM501_2D_BACKGROUND            (0x18)
+#define SM501_2D_STRETCH               (0x1C)
+#define SM501_2D_COLOR_COMPARE         (0x20)
+#define SM501_2D_COLOR_COMPARE_MASK    (0x24)
+#define SM501_2D_MASK                  (0x28)
+#define SM501_2D_CLIP_TL               (0x2C)
+#define SM501_2D_CLIP_BR               (0x30)
+#define SM501_2D_MONO_PATTERN_LOW      (0x34)
+#define SM501_2D_MONO_PATTERN_HIGH     (0x38)
+#define SM501_2D_WINDOW_WIDTH          (0x3C)
+#define SM501_2D_SOURCE_BASE           (0x40)
+#define SM501_2D_DESTINATION_BASE      (0x44)
+#define SM501_2D_ALPHA                 (0x48)
+#define SM501_2D_WRAP                  (0x4C)
+#define SM501_2D_STATUS                        (0x50)
+
+#define SM501_CSC_Y_SOURCE_BASE                (0xC8)
+#define SM501_CSC_CONSTANTS            (0xCC)
+#define SM501_CSC_Y_SOURCE_X           (0xD0)
+#define SM501_CSC_Y_SOURCE_Y           (0xD4)
+#define SM501_CSC_U_SOURCE_BASE                (0xD8)
+#define SM501_CSC_V_SOURCE_BASE                (0xDC)
+#define SM501_CSC_SOURCE_DIMENSION     (0xE0)
+#define SM501_CSC_SOURCE_PITCH         (0xE4)
+#define SM501_CSC_DESTINATION          (0xE8)
+#define SM501_CSC_DESTINATION_DIMENSION        (0xEC)
+#define SM501_CSC_DESTINATION_PITCH    (0xF0)
+#define SM501_CSC_SCALE_FACTOR         (0xF4)
+#define SM501_CSC_DESTINATION_BASE     (0xF8)
+#define SM501_CSC_CONTROL              (0xFC)
+
+/* 2d engine data port base */
+#define SM501_2D_ENGINE_DATA           (0x110000)
+
+/* end of register definitions */
+
+#define SM501_HWC_WIDTH                       (64)
+#define SM501_HWC_HEIGHT                      (64)
+
+/* SM501 local memory size taken from "linux/drivers/mfd/sm501.c" */
+static const uint32_t sm501_mem_local_size[] = {
+       [0]     = 4*1024*1024,
+       [1]     = 8*1024*1024,
+       [2]     = 16*1024*1024,
+       [3]     = 32*1024*1024,
+       [4]     = 64*1024*1024,
+       [5]     = 2*1024*1024,
+};
+#define get_local_mem_size(s) sm501_mem_local_size[(s)->local_mem_size_index]
+
+typedef struct SM501State {
+    /* graphic console status */
+    QemuConsole *con;
+
+    /* status & internal resources */
+    hwaddr base;
+    uint32_t local_mem_size_index;
+    uint8_t * local_mem;
+    MemoryRegion local_mem_region;
+    uint32_t last_width;
+    uint32_t last_height;
+
+    /* mmio registers */
+    uint32_t system_control;
+    uint32_t misc_control;
+    uint32_t gpio_31_0_control;
+    uint32_t gpio_63_32_control;
+    uint32_t dram_control;
+    uint32_t irq_mask;
+    uint32_t misc_timing;
+    uint32_t power_mode_control;
+
+    uint32_t uart0_ier;
+    uint32_t uart0_lcr;
+    uint32_t uart0_mcr;
+    uint32_t uart0_scr;
+
+    uint8_t dc_palette[0x400 * 3];
+
+    uint32_t dc_panel_control;
+    uint32_t dc_panel_panning_control;
+    uint32_t dc_panel_fb_addr;
+    uint32_t dc_panel_fb_offset;
+    uint32_t dc_panel_fb_width;
+    uint32_t dc_panel_fb_height;
+    uint32_t dc_panel_tl_location;
+    uint32_t dc_panel_br_location;
+    uint32_t dc_panel_h_total;
+    uint32_t dc_panel_h_sync;
+    uint32_t dc_panel_v_total;
+    uint32_t dc_panel_v_sync;
+
+    uint32_t dc_panel_hwc_addr;
+    uint32_t dc_panel_hwc_location;
+    uint32_t dc_panel_hwc_color_1_2;
+    uint32_t dc_panel_hwc_color_3;
+
+    uint32_t dc_crt_control;
+    uint32_t dc_crt_fb_addr;
+    uint32_t dc_crt_fb_offset;
+    uint32_t dc_crt_h_total;
+    uint32_t dc_crt_h_sync;
+    uint32_t dc_crt_v_total;
+    uint32_t dc_crt_v_sync;
+
+    uint32_t dc_crt_hwc_addr;
+    uint32_t dc_crt_hwc_location;
+    uint32_t dc_crt_hwc_color_1_2;
+    uint32_t dc_crt_hwc_color_3;
+
+    uint32_t twoD_source;
+    uint32_t twoD_destination;
+    uint32_t twoD_dimension;
+    uint32_t twoD_control;
+    uint32_t twoD_pitch;
+    uint32_t twoD_foreground;
+    uint32_t twoD_stretch;
+    uint32_t twoD_color_compare_mask;
+    uint32_t twoD_mask;
+    uint32_t twoD_window_width;
+    uint32_t twoD_source_base;
+    uint32_t twoD_destination_base;
+
+} SM501State;
+
+static uint32_t get_local_mem_size_index(uint32_t size)
+{
+    uint32_t norm_size = 0;
+    int i, index = 0;
+
+    for (i = 0; i < ARRAY_SIZE(sm501_mem_local_size); i++) {
+       uint32_t new_size = sm501_mem_local_size[i];
+       if (new_size >= size) {
+           if (norm_size == 0 || norm_size > new_size) {
+               norm_size = new_size;
+               index = i;
+           }
+       }
+    }
+
+    return index;
+}
+
+/**
+ * Check the availability of hardware cursor.
+ * @param crt  0 for PANEL, 1 for CRT.
+ */
+static inline int is_hwc_enabled(SM501State *state, int crt)
+{
+    uint32_t addr = crt ? state->dc_crt_hwc_addr : state->dc_panel_hwc_addr;
+    return addr & 0x80000000;
+}
+
+/**
+ * Get the address which holds cursor pattern data.
+ * @param crt  0 for PANEL, 1 for CRT.
+ */
+static inline uint32_t get_hwc_address(SM501State *state, int crt)
+{
+    uint32_t addr = crt ? state->dc_crt_hwc_addr : state->dc_panel_hwc_addr;
+    return (addr & 0x03FFFFF0)/* >> 4*/;
+}
+
+/**
+ * Get the cursor position in y coordinate.
+ * @param crt  0 for PANEL, 1 for CRT.
+ */
+static inline uint32_t get_hwc_y(SM501State *state, int crt)
+{
+    uint32_t location = crt ? state->dc_crt_hwc_location
+                            : state->dc_panel_hwc_location;
+    return (location & 0x07FF0000) >> 16;
+}
+
+/**
+ * Get the cursor position in x coordinate.
+ * @param crt  0 for PANEL, 1 for CRT.
+ */
+static inline uint32_t get_hwc_x(SM501State *state, int crt)
+{
+    uint32_t location = crt ? state->dc_crt_hwc_location
+                            : state->dc_panel_hwc_location;
+    return location & 0x000007FF;
+}
+
+/**
+ * Get the cursor position in x coordinate.
+ * @param crt  0 for PANEL, 1 for CRT.
+ * @param index  0, 1, 2 or 3 which specifies color of corsor dot.
+ */
+static inline uint16_t get_hwc_color(SM501State *state, int crt, int index)
+{
+    uint32_t color_reg = 0;
+    uint16_t color_565 = 0;
+
+    if (index == 0) {
+        return 0;
+    }
+
+    switch (index) {
+    case 1:
+    case 2:
+        color_reg = crt ? state->dc_crt_hwc_color_1_2
+                        : state->dc_panel_hwc_color_1_2;
+        break;
+    case 3:
+        color_reg = crt ? state->dc_crt_hwc_color_3
+                        : state->dc_panel_hwc_color_3;
+        break;
+    default:
+        printf("invalid hw cursor color.\n");
+        abort();
+    }
+
+    switch (index) {
+    case 1:
+    case 3:
+        color_565 = (uint16_t)(color_reg & 0xFFFF);
+        break;
+    case 2:
+        color_565 = (uint16_t)((color_reg >> 16) & 0xFFFF);
+        break;
+    }
+    return color_565;
+}
+
+static int within_hwc_y_range(SM501State *state, int y, int crt)
+{
+    int hwc_y = get_hwc_y(state, crt);
+    return (hwc_y <= y && y < hwc_y + SM501_HWC_HEIGHT);
+}
+
+static void sm501_2d_operation(SM501State * s)
+{
+    /* obtain operation parameters */
+    int operation = (s->twoD_control >> 16) & 0x1f;
+    int rtl = s->twoD_control & 0x8000000;
+    int src_x = (s->twoD_source >> 16) & 0x01FFF;
+    int src_y = s->twoD_source & 0xFFFF;
+    int dst_x = (s->twoD_destination >> 16) & 0x01FFF;
+    int dst_y = s->twoD_destination & 0xFFFF;
+    int operation_width = (s->twoD_dimension >> 16) & 0x1FFF;
+    int operation_height = s->twoD_dimension & 0xFFFF;
+    uint32_t color = s->twoD_foreground;
+    int format_flags = (s->twoD_stretch >> 20) & 0x3;
+    int addressing = (s->twoD_stretch >> 16) & 0xF;
+
+    /* get frame buffer info */
+    uint8_t * src = s->local_mem + (s->twoD_source_base & 0x03FFFFFF);
+    uint8_t * dst = s->local_mem + (s->twoD_destination_base & 0x03FFFFFF);
+    int src_width = (s->dc_crt_h_total & 0x00000FFF) + 1;
+    int dst_width = (s->dc_crt_h_total & 0x00000FFF) + 1;
+
+    if (addressing != 0x0) {
+        printf("%s: only XY addressing is supported.\n", __func__);
+        abort();
+    }
+
+    if ((s->twoD_source_base & 0x08000000) ||
+        (s->twoD_destination_base & 0x08000000)) {
+        printf("%s: only local memory is supported.\n", __func__);
+        abort();
+    }
+
+    switch (operation) {
+    case 0x00: /* copy area */
+#define COPY_AREA(_bpp, _pixel_type, rtl) {                                 \
+        int y, x, index_d, index_s;                                         \
+        for (y = 0; y < operation_height; y++) {                            \
+            for (x = 0; x < operation_width; x++) {                         \
+                if (rtl) {                                                  \
+                    index_s = ((src_y - y) * src_width + src_x - x) * _bpp; \
+                    index_d = ((dst_y - y) * dst_width + dst_x - x) * _bpp; \
+                } else {                                                    \
+                    index_s = ((src_y + y) * src_width + src_x + x) * _bpp; \
+                    index_d = ((dst_y + y) * dst_width + dst_x + x) * _bpp; \
+                }                                                           \
+                *(_pixel_type*)&dst[index_d] = *(_pixel_type*)&src[index_s];\
+            }                                                               \
+        }                                                                   \
+    }
+        switch (format_flags) {
+        case 0:
+            COPY_AREA(1, uint8_t, rtl);
+            break;
+        case 1:
+            COPY_AREA(2, uint16_t, rtl);
+            break;
+        case 2:
+            COPY_AREA(4, uint32_t, rtl);
+            break;
+        }
+        break;
+
+    case 0x01: /* fill rectangle */
+#define FILL_RECT(_bpp, _pixel_type) {                                      \
+        int y, x;                                                           \
+        for (y = 0; y < operation_height; y++) {                            \
+            for (x = 0; x < operation_width; x++) {                         \
+                int index = ((dst_y + y) * dst_width + dst_x + x) * _bpp;   \
+                *(_pixel_type*)&dst[index] = (_pixel_type)color;            \
+            }                                                               \
+        }                                                                   \
+    }
+
+        switch (format_flags) {
+        case 0:
+            FILL_RECT(1, uint8_t);
+            break;
+        case 1:
+            FILL_RECT(2, uint16_t);
+            break;
+        case 2:
+            FILL_RECT(4, uint32_t);
+            break;
+        }
+        break;
+
+    default:
+        printf("non-implemented SM501 2D operation. %d\n", operation);
+        abort();
+        break;
+    }
+}
+
+static uint64_t sm501_system_config_read(void *opaque, hwaddr addr,
+                                         unsigned size)
+{
+    SM501State * s = (SM501State *)opaque;
+    uint32_t ret = 0;
+    SM501_DPRINTF("sm501 system config regs : read addr=%x\n", (int)addr);
+
+    switch(addr) {
+    case SM501_SYSTEM_CONTROL:
+       ret = s->system_control;
+       break;
+    case SM501_MISC_CONTROL:
+       ret = s->misc_control;
+       break;
+    case SM501_GPIO31_0_CONTROL:
+       ret = s->gpio_31_0_control;
+       break;
+    case SM501_GPIO63_32_CONTROL:
+       ret = s->gpio_63_32_control;
+       break;
+    case SM501_DEVICEID:
+       ret = 0x050100A0;
+       break;
+    case SM501_DRAM_CONTROL:
+       ret = (s->dram_control & 0x07F107C0) | s->local_mem_size_index << 13;
+       break;
+    case SM501_IRQ_MASK:
+       ret = s->irq_mask;
+       break;
+    case SM501_MISC_TIMING:
+       /* TODO : simulate gate control */
+       ret = s->misc_timing;
+       break;
+    case SM501_CURRENT_GATE:
+       /* TODO : simulate gate control */
+       ret = 0x00021807;
+       break;
+    case SM501_CURRENT_CLOCK:
+       ret = 0x2A1A0A09;
+       break;
+    case SM501_POWER_MODE_CONTROL:
+       ret = s->power_mode_control;
+       break;
+
+    default:
+       printf("sm501 system config : not implemented register read."
+              " addr=%x\n", (int)addr);
+        abort();
+    }
+
+    return ret;
+}
+
+static void sm501_system_config_write(void *opaque, hwaddr addr,
+                                      uint64_t value, unsigned size)
+{
+    SM501State * s = (SM501State *)opaque;
+    SM501_DPRINTF("sm501 system config regs : write addr=%x, val=%x\n",
+                 (uint32_t)addr, (uint32_t)value);
+
+    switch(addr) {
+    case SM501_SYSTEM_CONTROL:
+       s->system_control = value & 0xE300B8F7;
+       break;
+    case SM501_MISC_CONTROL:
+       s->misc_control = value & 0xFF7FFF20;
+       break;
+    case SM501_GPIO31_0_CONTROL:
+       s->gpio_31_0_control = value;
+       break;
+    case SM501_GPIO63_32_CONTROL:
+       s->gpio_63_32_control = value;
+       break;
+    case SM501_DRAM_CONTROL:
+       s->local_mem_size_index = (value >> 13) & 0x7;
+       /* rODO : check validity of size change */
+       s->dram_control |=  value & 0x7FFFFFC3;
+       break;
+    case SM501_IRQ_MASK:
+       s->irq_mask = value;
+       break;
+    case SM501_MISC_TIMING:
+       s->misc_timing = value & 0xF31F1FFF;
+       break;
+    case SM501_POWER_MODE_0_GATE:
+    case SM501_POWER_MODE_1_GATE:
+    case SM501_POWER_MODE_0_CLOCK:
+    case SM501_POWER_MODE_1_CLOCK:
+       /* TODO : simulate gate & clock control */
+       break;
+    case SM501_POWER_MODE_CONTROL:
+       s->power_mode_control = value & 0x00000003;
+       break;
+
+    default:
+       printf("sm501 system config : not implemented register write."
+              " addr=%x, val=%x\n", (int)addr, (uint32_t)value);
+        abort();
+    }
+}
+
+static const MemoryRegionOps sm501_system_config_ops = {
+    .read = sm501_system_config_read,
+    .write = sm501_system_config_write,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static uint32_t sm501_palette_read(void *opaque, hwaddr addr)
+{
+    SM501State * s = (SM501State *)opaque;
+    SM501_DPRINTF("sm501 palette read addr=%x\n", (int)addr);
+
+    /* TODO : consider BYTE/WORD access */
+    /* TODO : consider endian */
+
+    assert(range_covers_byte(0, 0x400 * 3, addr));
+    return *(uint32_t*)&s->dc_palette[addr];
+}
+
+static void sm501_palette_write(void *opaque,
+                               hwaddr addr, uint32_t value)
+{
+    SM501State * s = (SM501State *)opaque;
+    SM501_DPRINTF("sm501 palette write addr=%x, val=%x\n",
+                 (int)addr, value);
+
+    /* TODO : consider BYTE/WORD access */
+    /* TODO : consider endian */
+
+    assert(range_covers_byte(0, 0x400 * 3, addr));
+    *(uint32_t*)&s->dc_palette[addr] = value;
+}
+
+static uint64_t sm501_disp_ctrl_read(void *opaque, hwaddr addr,
+                                     unsigned size)
+{
+    SM501State * s = (SM501State *)opaque;
+    uint32_t ret = 0;
+    SM501_DPRINTF("sm501 disp ctrl regs : read addr=%x\n", (int)addr);
+
+    switch(addr) {
+
+    case SM501_DC_PANEL_CONTROL:
+       ret = s->dc_panel_control;
+       break;
+    case SM501_DC_PANEL_PANNING_CONTROL:
+       ret = s->dc_panel_panning_control;
+       break;
+    case SM501_DC_PANEL_FB_ADDR:
+       ret = s->dc_panel_fb_addr;
+       break;
+    case SM501_DC_PANEL_FB_OFFSET:
+       ret = s->dc_panel_fb_offset;
+       break;
+    case SM501_DC_PANEL_FB_WIDTH:
+       ret = s->dc_panel_fb_width;
+       break;
+    case SM501_DC_PANEL_FB_HEIGHT:
+       ret = s->dc_panel_fb_height;
+       break;
+    case SM501_DC_PANEL_TL_LOC:
+       ret = s->dc_panel_tl_location;
+       break;
+    case SM501_DC_PANEL_BR_LOC:
+       ret = s->dc_panel_br_location;
+       break;
+
+    case SM501_DC_PANEL_H_TOT:
+       ret = s->dc_panel_h_total;
+       break;
+    case SM501_DC_PANEL_H_SYNC:
+       ret = s->dc_panel_h_sync;
+       break;
+    case SM501_DC_PANEL_V_TOT:
+       ret = s->dc_panel_v_total;
+       break;
+    case SM501_DC_PANEL_V_SYNC:
+       ret = s->dc_panel_v_sync;
+       break;
+
+    case SM501_DC_CRT_CONTROL:
+       ret = s->dc_crt_control;
+       break;
+    case SM501_DC_CRT_FB_ADDR:
+       ret = s->dc_crt_fb_addr;
+       break;
+    case SM501_DC_CRT_FB_OFFSET:
+       ret = s->dc_crt_fb_offset;
+       break;
+    case SM501_DC_CRT_H_TOT:
+       ret = s->dc_crt_h_total;
+       break;
+    case SM501_DC_CRT_H_SYNC:
+       ret = s->dc_crt_h_sync;
+       break;
+    case SM501_DC_CRT_V_TOT:
+       ret = s->dc_crt_v_total;
+       break;
+    case SM501_DC_CRT_V_SYNC:
+       ret = s->dc_crt_v_sync;
+       break;
+
+    case SM501_DC_CRT_HWC_ADDR:
+       ret = s->dc_crt_hwc_addr;
+       break;
+    case SM501_DC_CRT_HWC_LOC:
+       ret = s->dc_crt_hwc_location;
+       break;
+    case SM501_DC_CRT_HWC_COLOR_1_2:
+       ret = s->dc_crt_hwc_color_1_2;
+       break;
+    case SM501_DC_CRT_HWC_COLOR_3:
+       ret = s->dc_crt_hwc_color_3;
+       break;
+
+    case SM501_DC_PANEL_PALETTE ... SM501_DC_PANEL_PALETTE + 0x400*3 - 4:
+        ret = sm501_palette_read(opaque, addr - SM501_DC_PANEL_PALETTE);
+        break;
+
+    default:
+       printf("sm501 disp ctrl : not implemented register read."
+              " addr=%x\n", (int)addr);
+        abort();
+    }
+
+    return ret;
+}
+
+static void sm501_disp_ctrl_write(void *opaque, hwaddr addr,
+                                  uint64_t value, unsigned size)
+{
+    SM501State * s = (SM501State *)opaque;
+    SM501_DPRINTF("sm501 disp ctrl regs : write addr=%x, val=%x\n",
+                 (unsigned)addr, (unsigned)value);
+
+    switch(addr) {
+    case SM501_DC_PANEL_CONTROL:
+       s->dc_panel_control = value & 0x0FFF73FF;
+       break;
+    case SM501_DC_PANEL_PANNING_CONTROL:
+       s->dc_panel_panning_control = value & 0xFF3FFF3F;
+       break;
+    case SM501_DC_PANEL_FB_ADDR:
+       s->dc_panel_fb_addr = value & 0x8FFFFFF0;
+       break;
+    case SM501_DC_PANEL_FB_OFFSET:
+       s->dc_panel_fb_offset = value & 0x3FF03FF0;
+       break;
+    case SM501_DC_PANEL_FB_WIDTH:
+       s->dc_panel_fb_width = value & 0x0FFF0FFF;
+       break;
+    case SM501_DC_PANEL_FB_HEIGHT:
+       s->dc_panel_fb_height = value & 0x0FFF0FFF;
+       break;
+    case SM501_DC_PANEL_TL_LOC:
+       s->dc_panel_tl_location = value & 0x07FF07FF;
+       break;
+    case SM501_DC_PANEL_BR_LOC:
+       s->dc_panel_br_location = value & 0x07FF07FF;
+       break;
+
+    case SM501_DC_PANEL_H_TOT:
+       s->dc_panel_h_total = value & 0x0FFF0FFF;
+       break;
+    case SM501_DC_PANEL_H_SYNC:
+       s->dc_panel_h_sync = value & 0x00FF0FFF;
+       break;
+    case SM501_DC_PANEL_V_TOT:
+       s->dc_panel_v_total = value & 0x0FFF0FFF;
+       break;
+    case SM501_DC_PANEL_V_SYNC:
+       s->dc_panel_v_sync = value & 0x003F0FFF;
+       break;
+
+    case SM501_DC_PANEL_HWC_ADDR:
+       s->dc_panel_hwc_addr = value & 0x8FFFFFF0;
+       break;
+    case SM501_DC_PANEL_HWC_LOC:
+       s->dc_panel_hwc_location = value & 0x0FFF0FFF;
+       break;
+    case SM501_DC_PANEL_HWC_COLOR_1_2:
+       s->dc_panel_hwc_color_1_2 = value;
+       break;
+    case SM501_DC_PANEL_HWC_COLOR_3:
+       s->dc_panel_hwc_color_3 = value & 0x0000FFFF;
+       break;
+
+    case SM501_DC_CRT_CONTROL:
+       s->dc_crt_control = value & 0x0003FFFF;
+       break;
+    case SM501_DC_CRT_FB_ADDR:
+       s->dc_crt_fb_addr = value & 0x8FFFFFF0;
+       break;
+    case SM501_DC_CRT_FB_OFFSET:
+       s->dc_crt_fb_offset = value & 0x3FF03FF0;
+       break;
+    case SM501_DC_CRT_H_TOT:
+       s->dc_crt_h_total = value & 0x0FFF0FFF;
+       break;
+    case SM501_DC_CRT_H_SYNC:
+       s->dc_crt_h_sync = value & 0x00FF0FFF;
+       break;
+    case SM501_DC_CRT_V_TOT:
+       s->dc_crt_v_total = value & 0x0FFF0FFF;
+       break;
+    case SM501_DC_CRT_V_SYNC:
+       s->dc_crt_v_sync = value & 0x003F0FFF;
+       break;
+
+    case SM501_DC_CRT_HWC_ADDR:
+       s->dc_crt_hwc_addr = value & 0x8FFFFFF0;
+       break;
+    case SM501_DC_CRT_HWC_LOC:
+       s->dc_crt_hwc_location = value & 0x0FFF0FFF;
+       break;
+    case SM501_DC_CRT_HWC_COLOR_1_2:
+       s->dc_crt_hwc_color_1_2 = value;
+       break;
+    case SM501_DC_CRT_HWC_COLOR_3:
+       s->dc_crt_hwc_color_3 = value & 0x0000FFFF;
+       break;
+
+    case SM501_DC_PANEL_PALETTE ... SM501_DC_PANEL_PALETTE + 0x400*3 - 4:
+        sm501_palette_write(opaque, addr - SM501_DC_PANEL_PALETTE, value);
+        break;
+
+    default:
+       printf("sm501 disp ctrl : not implemented register write."
+              " addr=%x, val=%x\n", (int)addr, (unsigned)value);
+        abort();
+    }
+}
+
+static const MemoryRegionOps sm501_disp_ctrl_ops = {
+    .read = sm501_disp_ctrl_read,
+    .write = sm501_disp_ctrl_write,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static uint64_t sm501_2d_engine_read(void *opaque, hwaddr addr,
+                                     unsigned size)
+{
+    SM501State * s = (SM501State *)opaque;
+    uint32_t ret = 0;
+    SM501_DPRINTF("sm501 2d engine regs : read addr=%x\n", (int)addr);
+
+    switch(addr) {
+    case SM501_2D_SOURCE_BASE:
+        ret = s->twoD_source_base;
+        break;
+    default:
+        printf("sm501 disp ctrl : not implemented register read."
+               " addr=%x\n", (int)addr);
+        abort();
+    }
+
+    return ret;
+}
+
+static void sm501_2d_engine_write(void *opaque, hwaddr addr,
+                                  uint64_t value, unsigned size)
+{
+    SM501State * s = (SM501State *)opaque;
+    SM501_DPRINTF("sm501 2d engine regs : write addr=%x, val=%x\n",
+                  (unsigned)addr, (unsigned)value);
+
+    switch(addr) {
+    case SM501_2D_SOURCE:
+        s->twoD_source = value;
+        break;
+    case SM501_2D_DESTINATION:
+        s->twoD_destination = value;
+        break;
+    case SM501_2D_DIMENSION:
+        s->twoD_dimension = value;
+        break;
+    case SM501_2D_CONTROL:
+        s->twoD_control = value;
+
+        /* do 2d operation if start flag is set. */
+        if (value & 0x80000000) {
+            sm501_2d_operation(s);
+            s->twoD_control &= ~0x80000000; /* start flag down */
+        }
+
+        break;
+    case SM501_2D_PITCH:
+        s->twoD_pitch = value;
+        break;
+    case SM501_2D_FOREGROUND:
+        s->twoD_foreground = value;
+        break;
+    case SM501_2D_STRETCH:
+        s->twoD_stretch = value;
+        break;
+    case SM501_2D_COLOR_COMPARE_MASK:
+        s->twoD_color_compare_mask = value;
+        break;
+    case SM501_2D_MASK:
+        s->twoD_mask = value;
+        break;
+    case SM501_2D_WINDOW_WIDTH:
+        s->twoD_window_width = value;
+        break;
+    case SM501_2D_SOURCE_BASE:
+        s->twoD_source_base = value;
+        break;
+    case SM501_2D_DESTINATION_BASE:
+        s->twoD_destination_base = value;
+        break;
+    default:
+        printf("sm501 2d engine : not implemented register write."
+               " addr=%x, val=%x\n", (int)addr, (unsigned)value);
+        abort();
+    }
+}
+
+static const MemoryRegionOps sm501_2d_engine_ops = {
+    .read = sm501_2d_engine_read,
+    .write = sm501_2d_engine_write,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+/* draw line functions for all console modes */
+
+typedef void draw_line_func(uint8_t *d, const uint8_t *s,
+                           int width, const uint32_t *pal);
+
+typedef void draw_hwc_line_func(SM501State * s, int crt, uint8_t * palette,
+                                int c_y, uint8_t *d, int width);
+
+#define DEPTH 8
+#include "sm501_template.h"
+
+#define DEPTH 15
+#include "sm501_template.h"
+
+#define BGR_FORMAT
+#define DEPTH 15
+#include "sm501_template.h"
+
+#define DEPTH 16
+#include "sm501_template.h"
+
+#define BGR_FORMAT
+#define DEPTH 16
+#include "sm501_template.h"
+
+#define DEPTH 32
+#include "sm501_template.h"
+
+#define BGR_FORMAT
+#define DEPTH 32
+#include "sm501_template.h"
+
+static draw_line_func * draw_line8_funcs[] = {
+    draw_line8_8,
+    draw_line8_15,
+    draw_line8_16,
+    draw_line8_32,
+    draw_line8_32bgr,
+    draw_line8_15bgr,
+    draw_line8_16bgr,
+};
+
+static draw_line_func * draw_line16_funcs[] = {
+    draw_line16_8,
+    draw_line16_15,
+    draw_line16_16,
+    draw_line16_32,
+    draw_line16_32bgr,
+    draw_line16_15bgr,
+    draw_line16_16bgr,
+};
+
+static draw_line_func * draw_line32_funcs[] = {
+    draw_line32_8,
+    draw_line32_15,
+    draw_line32_16,
+    draw_line32_32,
+    draw_line32_32bgr,
+    draw_line32_15bgr,
+    draw_line32_16bgr,
+};
+
+static draw_hwc_line_func * draw_hwc_line_funcs[] = {
+    draw_hwc_line_8,
+    draw_hwc_line_15,
+    draw_hwc_line_16,
+    draw_hwc_line_32,
+    draw_hwc_line_32bgr,
+    draw_hwc_line_15bgr,
+    draw_hwc_line_16bgr,
+};
+
+static inline int get_depth_index(DisplaySurface *surface)
+{
+    switch (surface_bits_per_pixel(surface)) {
+    default:
+    case 8:
+       return 0;
+    case 15:
+        return 1;
+    case 16:
+        return 2;
+    case 32:
+        if (is_surface_bgr(surface)) {
+            return 4;
+        } else {
+            return 3;
+        }
+    }
+}
+
+static void sm501_draw_crt(SM501State * s)
+{
+    DisplaySurface *surface = qemu_console_surface(s->con);
+    int y;
+    int width = (s->dc_crt_h_total & 0x00000FFF) + 1;
+    int height = (s->dc_crt_v_total & 0x00000FFF) + 1;
+
+    uint8_t  * src = s->local_mem;
+    int src_bpp = 0;
+    int dst_bpp = surface_bytes_per_pixel(surface);
+    uint32_t * palette = (uint32_t *)&s->dc_palette[SM501_DC_CRT_PALETTE
+                                                   - SM501_DC_PANEL_PALETTE];
+    uint8_t hwc_palette[3 * 3];
+    int ds_depth_index = get_depth_index(surface);
+    draw_line_func * draw_line = NULL;
+    draw_hwc_line_func * draw_hwc_line = NULL;
+    int full_update = 0;
+    int y_start = -1;
+    ram_addr_t page_min = ~0l;
+    ram_addr_t page_max = 0l;
+    ram_addr_t offset = 0;
+
+    /* choose draw_line function */
+    switch (s->dc_crt_control & 3) {
+    case SM501_DC_CRT_CONTROL_8BPP:
+       src_bpp = 1;
+       draw_line = draw_line8_funcs[ds_depth_index];
+       break;
+    case SM501_DC_CRT_CONTROL_16BPP:
+       src_bpp = 2;
+       draw_line = draw_line16_funcs[ds_depth_index];
+       break;
+    case SM501_DC_CRT_CONTROL_32BPP:
+       src_bpp = 4;
+       draw_line = draw_line32_funcs[ds_depth_index];
+       break;
+    default:
+       printf("sm501 draw crt : invalid DC_CRT_CONTROL=%x.\n",
+              s->dc_crt_control);
+        abort();
+       break;
+    }
+
+    /* set up to draw hardware cursor */
+    if (is_hwc_enabled(s, 1)) {
+        int i;
+
+        /* get cursor palette */
+        for (i = 0; i < 3; i++) {
+            uint16_t rgb565 = get_hwc_color(s, 1, i + 1);
+            hwc_palette[i * 3 + 0] = (rgb565 & 0xf800) >> 8; /* red */
+            hwc_palette[i * 3 + 1] = (rgb565 & 0x07e0) >> 3; /* green */
+            hwc_palette[i * 3 + 2] = (rgb565 & 0x001f) << 3; /* blue */
+        }
+
+        /* choose cursor draw line function */
+        draw_hwc_line = draw_hwc_line_funcs[ds_depth_index];
+    }
+
+    /* adjust console size */
+    if (s->last_width != width || s->last_height != height) {
+        qemu_console_resize(s->con, width, height);
+        surface = qemu_console_surface(s->con);
+       s->last_width = width;
+       s->last_height = height;
+       full_update = 1;
+    }
+
+    /* draw each line according to conditions */
+    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;
+        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 - page0, DIRTY_MEMORY_VGA);
+
+       /* draw line and change status */
+       if (update) {
+            uint8_t *d = surface_data(surface);
+            d +=  y * width * dst_bpp;
+
+            /* draw graphics layer */
+            draw_line(d, src, width, palette);
+
+            /* draw haredware cursor */
+            if (update_hwc) {
+                draw_hwc_line(s, 1, hwc_palette, y - get_hwc_y(s, 1), d, width);
+            }
+
+           if (y_start < 0)
+               y_start = y;
+           if (page0 < page_min)
+               page_min = page0;
+           if (page1 > page_max)
+               page_max = page1;
+       } else {
+           if (y_start >= 0) {
+               /* flush to display */
+                dpy_gfx_update(s->con, 0, y_start, width, y - y_start);
+               y_start = -1;
+           }
+       }
+
+       src += width * src_bpp;
+       offset += width * src_bpp;
+    }
+
+    /* complete flush to display */
+    if (y_start >= 0)
+        dpy_gfx_update(s->con, 0, y_start, width, y - y_start);
+
+    /* clear dirty flags */
+    if (page_min != ~0l) {
+       memory_region_reset_dirty(&s->local_mem_region,
+                                  page_min, page_max + TARGET_PAGE_SIZE,
+                                  DIRTY_MEMORY_VGA);
+    }
+}
+
+static void sm501_update_display(void *opaque)
+{
+    SM501State * s = (SM501State *)opaque;
+
+    if (s->dc_crt_control & SM501_DC_CRT_CONTROL_ENABLE)
+       sm501_draw_crt(s);
+}
+
+void sm501_init(MemoryRegion *address_space_mem, uint32_t base,
+                uint32_t local_mem_bytes, qemu_irq irq, CharDriverState *chr)
+{
+    SM501State * s;
+    DeviceState *dev;
+    MemoryRegion *sm501_system_config = g_new(MemoryRegion, 1);
+    MemoryRegion *sm501_disp_ctrl = g_new(MemoryRegion, 1);
+    MemoryRegion *sm501_2d_engine = g_new(MemoryRegion, 1);
+
+    /* allocate management data region */
+    s = (SM501State *)g_malloc0(sizeof(SM501State));
+    s->base = base;
+    s->local_mem_size_index
+       = get_local_mem_size_index(local_mem_bytes);
+    SM501_DPRINTF("local mem size=%x. index=%d\n", get_local_mem_size(s),
+                 s->local_mem_size_index);
+    s->system_control = 0x00100000;
+    s->misc_control = 0x00001000; /* assumes SH, active=low */
+    s->dc_panel_control = 0x00010000;
+    s->dc_crt_control = 0x00010000;
+
+    /* allocate local memory */
+    memory_region_init_ram(&s->local_mem_region, "sm501.local",
+                           local_mem_bytes);
+    vmstate_register_ram_global(&s->local_mem_region);
+    s->local_mem = memory_region_get_ram_ptr(&s->local_mem_region);
+    memory_region_add_subregion(address_space_mem, base, &s->local_mem_region);
+
+    /* map mmio */
+    memory_region_init_io(sm501_system_config, &sm501_system_config_ops, s,
+                          "sm501-system-config", 0x6c);
+    memory_region_add_subregion(address_space_mem, base + MMIO_BASE_OFFSET,
+                                sm501_system_config);
+    memory_region_init_io(sm501_disp_ctrl, &sm501_disp_ctrl_ops, s,
+                          "sm501-disp-ctrl", 0x1000);
+    memory_region_add_subregion(address_space_mem,
+                                base + MMIO_BASE_OFFSET + SM501_DC,
+                                sm501_disp_ctrl);
+    memory_region_init_io(sm501_2d_engine, &sm501_2d_engine_ops, s,
+                          "sm501-2d-engine", 0x54);
+    memory_region_add_subregion(address_space_mem,
+                                base + MMIO_BASE_OFFSET + SM501_2D_ENGINE,
+                                sm501_2d_engine);
+
+    /* bridge to usb host emulation module */
+    dev = qdev_create(NULL, "sysbus-ohci");
+    qdev_prop_set_uint32(dev, "num-ports", 2);
+    qdev_prop_set_taddr(dev, "dma-offset", base);
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0,
+                    base + MMIO_BASE_OFFSET + SM501_USB_HOST);
+    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq);
+
+    /* bridge to serial emulation module */
+    if (chr) {
+        serial_mm_init(address_space_mem,
+                       base + MMIO_BASE_OFFSET + SM501_UART0, 2,
+                       NULL, /* TODO : chain irq to IRL */
+                       115200, chr, DEVICE_NATIVE_ENDIAN);
+    }
+
+    /* create qemu graphic console */
+    s->con = graphic_console_init(sm501_update_display, NULL,
+                                  NULL, NULL, s);
+}
diff --git a/hw/display/sm501_template.h b/hw/display/sm501_template.h
new file mode 100644 (file)
index 0000000..2d4a3d8
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * Pixel drawing function templates for QEMU SM501 Device
+ *
+ * Copyright (c) 2008 Shin-ichiro KAWASAKI
+ *
+ * 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
+#define PIXEL_TYPE uint8_t
+#elif DEPTH == 15 || DEPTH == 16
+#define BPP 2
+#define PIXEL_TYPE uint16_t
+#elif DEPTH == 32
+#define BPP 4
+#define PIXEL_TYPE uint32_t
+#else
+#error unsupport depth
+#endif
+
+#ifdef BGR_FORMAT
+#define PIXEL_NAME glue(DEPTH, bgr)
+#else
+#define PIXEL_NAME DEPTH
+#endif /* BGR_FORMAT */
+
+
+static void glue(draw_line8_, PIXEL_NAME)(
+                 uint8_t *d, const uint8_t *s, int width, const uint32_t *pal)
+{
+    uint8_t v, r, g, b;
+    do {
+       v = ldub_raw(s);
+       r = (pal[v] >> 16) & 0xff;
+       g = (pal[v] >>  8) & 0xff;
+       b = (pal[v] >>  0) & 0xff;
+       ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b);
+       s ++;
+       d += BPP;
+    } while (-- width != 0);
+}
+
+static void glue(draw_line16_, PIXEL_NAME)(
+                uint8_t *d, const uint8_t *s, int width, const uint32_t *pal)
+{
+    uint16_t rgb565;
+    uint8_t r, g, b;
+
+    do {
+       rgb565 = lduw_raw(s);
+       r = ((rgb565 >> 11) & 0x1f) << 3;
+       g = ((rgb565 >>  5) & 0x3f) << 2;
+       b = ((rgb565 >>  0) & 0x1f) << 3;
+       ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b);
+       s += 2;
+       d += BPP;
+    } while (-- width != 0);
+}
+
+static void glue(draw_line32_, PIXEL_NAME)(
+                uint8_t *d, const uint8_t *s, int width, const uint32_t *pal)
+{
+    uint8_t r, g, b;
+
+    do {
+       ldub_raw(s);
+#if defined(TARGET_WORDS_BIGENDIAN)
+        r = s[1];
+        g = s[2];
+        b = s[3];
+#else
+        b = s[0];
+        g = s[1];
+        r = s[2];
+#endif
+       ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b);
+       s += 4;
+       d += BPP;
+    } while (-- width != 0);
+}
+
+/**
+ * Draw hardware cursor image on the given line.
+ */
+static void glue(draw_hwc_line_, PIXEL_NAME)(SM501State * s, int crt,
+                         uint8_t * palette, int c_y, uint8_t *d, int width)
+{
+    int x, i;
+    uint8_t bitset = 0;
+
+    /* get hardware cursor pattern */
+    uint32_t cursor_addr = get_hwc_address(s, crt);
+    assert(0 <= c_y && c_y < SM501_HWC_HEIGHT);
+    cursor_addr += 64 * c_y / 4;  /* 4 pixels per byte */
+    cursor_addr += s->base;
+
+    /* get cursor position */
+    x = get_hwc_x(s, crt);
+    d += x * BPP;
+
+    for (i = 0; i < SM501_HWC_WIDTH && x + i < width; i++) {
+        uint8_t v;
+
+        /* get pixel value */
+        if (i % 4 == 0) {
+            bitset = ldub_phys(cursor_addr);
+            cursor_addr++;
+        }
+        v = bitset & 3;
+        bitset >>= 2;
+
+        /* write pixel */
+        if (v) {
+            v--;
+            uint8_t r = palette[v * 3 + 0];
+            uint8_t g = palette[v * 3 + 1];
+            uint8_t b = palette[v * 3 + 2];
+            ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b);
+        }
+        d += BPP;
+    }
+}
+
+#undef DEPTH
+#undef BPP
+#undef PIXEL_TYPE
+#undef PIXEL_NAME
+#undef BGR_FORMAT
diff --git a/hw/display/ssd0303.c b/hw/display/ssd0303.c
new file mode 100644 (file)
index 0000000..183a878
--- /dev/null
@@ -0,0 +1,322 @@
+/*
+ * SSD0303 OLED controller with OSRAM Pictiva 96x16 display.
+ *
+ * Copyright (c) 2006-2007 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the GPL.
+ */
+
+/* The controller can support a variety of different displays, but we only
+   implement one.  Most of the commends relating to brightness and geometry
+   setup are ignored. */
+#include "hw/i2c/i2c.h"
+#include "ui/console.h"
+
+//#define DEBUG_SSD0303 1
+
+#ifdef DEBUG_SSD0303
+#define DPRINTF(fmt, ...) \
+do { printf("ssd0303: " fmt , ## __VA_ARGS__); } while (0)
+#define BADF(fmt, ...) \
+do { fprintf(stderr, "ssd0303: error: " fmt , ## __VA_ARGS__); exit(1);} while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while(0)
+#define BADF(fmt, ...) \
+do { fprintf(stderr, "ssd0303: error: " fmt , ## __VA_ARGS__);} while (0)
+#endif
+
+/* Scaling factor for pixels.  */
+#define MAGNIFY 4
+
+enum ssd0303_mode
+{
+    SSD0303_IDLE,
+    SSD0303_DATA,
+    SSD0303_CMD
+};
+
+enum ssd0303_cmd {
+    SSD0303_CMD_NONE,
+    SSD0303_CMD_SKIP1
+};
+
+typedef struct {
+    I2CSlave i2c;
+    QemuConsole *con;
+    int row;
+    int col;
+    int start_line;
+    int mirror;
+    int flash;
+    int enabled;
+    int inverse;
+    int redraw;
+    enum ssd0303_mode mode;
+    enum ssd0303_cmd cmd_state;
+    uint8_t framebuffer[132*8];
+} ssd0303_state;
+
+static int ssd0303_recv(I2CSlave *i2c)
+{
+    BADF("Reads not implemented\n");
+    return -1;
+}
+
+static int ssd0303_send(I2CSlave *i2c, uint8_t data)
+{
+    ssd0303_state *s = (ssd0303_state *)i2c;
+    enum ssd0303_cmd old_cmd_state;
+    switch (s->mode) {
+    case SSD0303_IDLE:
+        DPRINTF("byte 0x%02x\n", data);
+        if (data == 0x80)
+            s->mode = SSD0303_CMD;
+        else if (data == 0x40)
+            s->mode = SSD0303_DATA;
+        else
+            BADF("Unexpected byte 0x%x\n", data);
+        break;
+    case SSD0303_DATA:
+        DPRINTF("data 0x%02x\n", data);
+        if (s->col < 132) {
+            s->framebuffer[s->col + s->row * 132] = data;
+            s->col++;
+            s->redraw = 1;
+        }
+        break;
+    case SSD0303_CMD:
+        old_cmd_state = s->cmd_state;
+        s->cmd_state = SSD0303_CMD_NONE;
+        switch (old_cmd_state) {
+        case SSD0303_CMD_NONE:
+            DPRINTF("cmd 0x%02x\n", data);
+            s->mode = SSD0303_IDLE;
+            switch (data) {
+            case 0x00 ... 0x0f: /* Set lower column address.  */
+                s->col = (s->col & 0xf0) | (data & 0xf);
+                break;
+            case 0x10 ... 0x20: /* Set higher column address.  */
+                s->col = (s->col & 0x0f) | ((data & 0xf) << 4);
+                break;
+            case 0x40 ... 0x7f: /* Set start line.  */
+                s->start_line = 0;
+                break;
+            case 0x81: /* Set contrast (Ignored).  */
+                s->cmd_state = SSD0303_CMD_SKIP1;
+                break;
+            case 0xa0: /* Mirror off.  */
+                s->mirror = 0;
+                break;
+            case 0xa1: /* Mirror off.  */
+                s->mirror = 1;
+                break;
+            case 0xa4: /* Entire display off.  */
+                s->flash = 0;
+                break;
+            case 0xa5: /* Entire display on.  */
+                s->flash = 1;
+                break;
+            case 0xa6: /* Inverse off.  */
+                s->inverse = 0;
+                break;
+            case 0xa7: /* Inverse on.  */
+                s->inverse = 1;
+                break;
+            case 0xa8: /* Set multiplied ratio (Ignored).  */
+                s->cmd_state = SSD0303_CMD_SKIP1;
+                break;
+            case 0xad: /* DC-DC power control.  */
+                s->cmd_state = SSD0303_CMD_SKIP1;
+                break;
+            case 0xae: /* Display off.  */
+                s->enabled = 0;
+                break;
+            case 0xaf: /* Display on.  */
+                s->enabled = 1;
+                break;
+            case 0xb0 ... 0xbf: /* Set Page address.  */
+                s->row = data & 7;
+                break;
+            case 0xc0 ... 0xc8: /* Set COM output direction (Ignored).  */
+                break;
+            case 0xd3: /* Set display offset (Ignored).  */
+                s->cmd_state = SSD0303_CMD_SKIP1;
+                break;
+            case 0xd5: /* Set display clock (Ignored).  */
+                s->cmd_state = SSD0303_CMD_SKIP1;
+                break;
+            case 0xd8: /* Set color and power mode (Ignored).  */
+                s->cmd_state = SSD0303_CMD_SKIP1;
+                break;
+            case 0xd9: /* Set pre-charge period (Ignored).  */
+                s->cmd_state = SSD0303_CMD_SKIP1;
+                break;
+            case 0xda: /* Set COM pin configuration (Ignored).  */
+                s->cmd_state = SSD0303_CMD_SKIP1;
+                break;
+            case 0xdb: /* Set VCOM dselect level (Ignored).  */
+                s->cmd_state = SSD0303_CMD_SKIP1;
+                break;
+            case 0xe3: /* no-op.  */
+                break;
+            default:
+                BADF("Unknown command: 0x%x\n", data);
+            }
+            break;
+        case SSD0303_CMD_SKIP1:
+            DPRINTF("skip 0x%02x\n", data);
+            break;
+        }
+        break;
+    }
+    return 0;
+}
+
+static void ssd0303_event(I2CSlave *i2c, enum i2c_event event)
+{
+    ssd0303_state *s = (ssd0303_state *)i2c;
+    switch (event) {
+    case I2C_FINISH:
+        s->mode = SSD0303_IDLE;
+        break;
+    case I2C_START_RECV:
+    case I2C_START_SEND:
+    case I2C_NACK:
+        /* Nothing to do.  */
+        break;
+    }
+}
+
+static void ssd0303_update_display(void *opaque)
+{
+    ssd0303_state *s = (ssd0303_state *)opaque;
+    DisplaySurface *surface = qemu_console_surface(s->con);
+    uint8_t *dest;
+    uint8_t *src;
+    int x;
+    int y;
+    int line;
+    char *colors[2];
+    char colortab[MAGNIFY * 8];
+    int dest_width;
+    uint8_t mask;
+
+    if (!s->redraw)
+        return;
+
+    switch (surface_bits_per_pixel(surface)) {
+    case 0:
+        return;
+    case 15:
+        dest_width = 2;
+        break;
+    case 16:
+        dest_width = 2;
+        break;
+    case 24:
+        dest_width = 3;
+        break;
+    case 32:
+        dest_width = 4;
+        break;
+    default:
+        BADF("Bad color depth\n");
+        return;
+    }
+    dest_width *= MAGNIFY;
+    memset(colortab, 0xff, dest_width);
+    memset(colortab + dest_width, 0, dest_width);
+    if (s->flash) {
+        colors[0] = colortab;
+        colors[1] = colortab;
+    } else if (s->inverse) {
+        colors[0] = colortab;
+        colors[1] = colortab + dest_width;
+    } else {
+        colors[0] = colortab + dest_width;
+        colors[1] = colortab;
+    }
+    dest = surface_data(surface);
+    for (y = 0; y < 16; y++) {
+        line = (y + s->start_line) & 63;
+        src = s->framebuffer + 132 * (line >> 3) + 36;
+        mask = 1 << (line & 7);
+        for (x = 0; x < 96; x++) {
+            memcpy(dest, colors[(*src & mask) != 0], dest_width);
+            dest += dest_width;
+            src++;
+        }
+        for (x = 1; x < MAGNIFY; x++) {
+            memcpy(dest, dest - dest_width * 96, dest_width * 96);
+            dest += dest_width * 96;
+        }
+    }
+    s->redraw = 0;
+    dpy_gfx_update(s->con, 0, 0, 96 * MAGNIFY, 16 * MAGNIFY);
+}
+
+static void ssd0303_invalidate_display(void * opaque)
+{
+    ssd0303_state *s = (ssd0303_state *)opaque;
+    s->redraw = 1;
+}
+
+static const VMStateDescription vmstate_ssd0303 = {
+    .name = "ssd0303_oled",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_INT32(row, ssd0303_state),
+        VMSTATE_INT32(col, ssd0303_state),
+        VMSTATE_INT32(start_line, ssd0303_state),
+        VMSTATE_INT32(mirror, ssd0303_state),
+        VMSTATE_INT32(flash, ssd0303_state),
+        VMSTATE_INT32(enabled, ssd0303_state),
+        VMSTATE_INT32(inverse, ssd0303_state),
+        VMSTATE_INT32(redraw, ssd0303_state),
+        VMSTATE_UINT32(mode, ssd0303_state),
+        VMSTATE_UINT32(cmd_state, ssd0303_state),
+        VMSTATE_BUFFER(framebuffer, ssd0303_state),
+        VMSTATE_I2C_SLAVE(i2c, ssd0303_state),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int ssd0303_init(I2CSlave *i2c)
+{
+    ssd0303_state *s = FROM_I2C_SLAVE(ssd0303_state, i2c);
+
+    s->con = graphic_console_init(ssd0303_update_display,
+                                  ssd0303_invalidate_display,
+                                  NULL, NULL, s);
+    qemu_console_resize(s->con, 96 * MAGNIFY, 16 * MAGNIFY);
+    return 0;
+}
+
+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 const TypeInfo ssd0303_info = {
+    .name          = "ssd0303",
+    .parent        = TYPE_I2C_SLAVE,
+    .instance_size = sizeof(ssd0303_state),
+    .class_init    = ssd0303_class_init,
+};
+
+static void ssd0303_register_types(void)
+{
+    type_register_static(&ssd0303_info);
+}
+
+type_init(ssd0303_register_types)
diff --git a/hw/display/ssd0323.c b/hw/display/ssd0323.c
new file mode 100644 (file)
index 0000000..5cf2f70
--- /dev/null
@@ -0,0 +1,373 @@
+/*
+ * SSD0323 OLED controller with OSRAM Pictiva 128x64 display.
+ *
+ * Copyright (c) 2006-2007 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the GPL.
+ */
+
+/* The controller can support a variety of different displays, but we only
+   implement one.  Most of the commends relating to brightness and geometry
+   setup are ignored. */
+#include "hw/ssi.h"
+#include "ui/console.h"
+
+//#define DEBUG_SSD0323 1
+
+#ifdef DEBUG_SSD0323
+#define DPRINTF(fmt, ...) \
+do { printf("ssd0323: " fmt , ## __VA_ARGS__); } while (0)
+#define BADF(fmt, ...) \
+do { \
+    fprintf(stderr, "ssd0323: error: " fmt , ## __VA_ARGS__); abort(); \
+} while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while(0)
+#define BADF(fmt, ...) \
+do { fprintf(stderr, "ssd0323: error: " fmt , ## __VA_ARGS__);} while (0)
+#endif
+
+/* Scaling factor for pixels.  */
+#define MAGNIFY 4
+
+#define REMAP_SWAP_COLUMN 0x01
+#define REMAP_SWAP_NYBBLE 0x02
+#define REMAP_VERTICAL    0x04
+#define REMAP_SWAP_COM    0x10
+#define REMAP_SPLIT_COM   0x40
+
+enum ssd0323_mode
+{
+    SSD0323_CMD,
+    SSD0323_DATA
+};
+
+typedef struct {
+    SSISlave ssidev;
+    QemuConsole *con;
+
+    int cmd_len;
+    int cmd;
+    int cmd_data[8];
+    int row;
+    int row_start;
+    int row_end;
+    int col;
+    int col_start;
+    int col_end;
+    int redraw;
+    int remap;
+    enum ssd0323_mode mode;
+    uint8_t framebuffer[128 * 80 / 2];
+} ssd0323_state;
+
+static uint32_t ssd0323_transfer(SSISlave *dev, uint32_t data)
+{
+    ssd0323_state *s = FROM_SSI_SLAVE(ssd0323_state, dev);
+
+    switch (s->mode) {
+    case SSD0323_DATA:
+        DPRINTF("data 0x%02x\n", data);
+        s->framebuffer[s->col + s->row * 64] = data;
+        if (s->remap & REMAP_VERTICAL) {
+            s->row++;
+            if (s->row > s->row_end) {
+                s->row = s->row_start;
+                s->col++;
+            }
+            if (s->col > s->col_end) {
+                s->col = s->col_start;
+            }
+        } else {
+            s->col++;
+            if (s->col > s->col_end) {
+                s->row++;
+                s->col = s->col_start;
+            }
+            if (s->row > s->row_end) {
+                s->row = s->row_start;
+            }
+        }
+        s->redraw = 1;
+        break;
+    case SSD0323_CMD:
+        DPRINTF("cmd 0x%02x\n", data);
+        if (s->cmd_len == 0) {
+            s->cmd = data;
+        } else {
+            s->cmd_data[s->cmd_len - 1] = data;
+        }
+        s->cmd_len++;
+        switch (s->cmd) {
+#define DATA(x) if (s->cmd_len <= (x)) return 0
+        case 0x15: /* Set column.  */
+            DATA(2);
+            s->col = s->col_start = s->cmd_data[0] % 64;
+            s->col_end = s->cmd_data[1] % 64;
+            break;
+        case 0x75: /* Set row.  */
+            DATA(2);
+            s->row = s->row_start = s->cmd_data[0] % 80;
+            s->row_end = s->cmd_data[1] % 80;
+            break;
+        case 0x81: /* Set contrast */
+            DATA(1);
+            break;
+        case 0x84: case 0x85: case 0x86: /* Max current.  */
+            DATA(0);
+            break;
+        case 0xa0: /* Set remapping.  */
+            /* FIXME: Implement this.  */
+            DATA(1);
+            s->remap = s->cmd_data[0];
+            break;
+        case 0xa1: /* Set display start line.  */
+        case 0xa2: /* Set display offset.  */
+            /* FIXME: Implement these.  */
+            DATA(1);
+            break;
+        case 0xa4: /* Normal mode.  */
+        case 0xa5: /* All on.  */
+        case 0xa6: /* All off.  */
+        case 0xa7: /* Inverse.  */
+            /* FIXME: Implement these.  */
+            DATA(0);
+            break;
+        case 0xa8: /* Set multiplex ratio.  */
+        case 0xad: /* Set DC-DC converter.  */
+            DATA(1);
+            /* Ignored.  Don't care.  */
+            break;
+        case 0xae: /* Display off.  */
+        case 0xaf: /* Display on.  */
+            DATA(0);
+            /* TODO: Implement power control.  */
+            break;
+        case 0xb1: /* Set phase length.  */
+        case 0xb2: /* Set row period.  */
+        case 0xb3: /* Set clock rate.  */
+        case 0xbc: /* Set precharge.  */
+        case 0xbe: /* Set VCOMH.  */
+        case 0xbf: /* Set segment low.  */
+            DATA(1);
+            /* Ignored.  Don't care.  */
+            break;
+        case 0xb8: /* Set grey scale table.  */
+            /* FIXME: Implement this.  */
+            DATA(8);
+            break;
+        case 0xe3: /* NOP.  */
+            DATA(0);
+            break;
+        case 0xff: /* Nasty hack because we don't handle chip selects
+                      properly.  */
+            break;
+        default:
+            BADF("Unknown command: 0x%x\n", data);
+        }
+        s->cmd_len = 0;
+        return 0;
+    }
+    return 0;
+}
+
+static void ssd0323_update_display(void *opaque)
+{
+    ssd0323_state *s = (ssd0323_state *)opaque;
+    DisplaySurface *surface = qemu_console_surface(s->con);
+    uint8_t *dest;
+    uint8_t *src;
+    int x;
+    int y;
+    int i;
+    int line;
+    char *colors[16];
+    char colortab[MAGNIFY * 64];
+    char *p;
+    int dest_width;
+
+    if (!s->redraw)
+        return;
+
+    switch (surface_bits_per_pixel(surface)) {
+    case 0:
+        return;
+    case 15:
+        dest_width = 2;
+        break;
+    case 16:
+        dest_width = 2;
+        break;
+    case 24:
+        dest_width = 3;
+        break;
+    case 32:
+        dest_width = 4;
+        break;
+    default:
+        BADF("Bad color depth\n");
+        return;
+    }
+    p = colortab;
+    for (i = 0; i < 16; i++) {
+        int n;
+        colors[i] = p;
+        switch (surface_bits_per_pixel(surface)) {
+        case 15:
+            n = i * 2 + (i >> 3);
+            p[0] = n | (n << 5);
+            p[1] = (n << 2) | (n >> 3);
+            break;
+        case 16:
+            n = i * 2 + (i >> 3);
+            p[0] = n | (n << 6) | ((n << 1) & 0x20);
+            p[1] = (n << 3) | (n >> 2);
+            break;
+        case 24:
+        case 32:
+            n = (i << 4) | i;
+            p[0] = p[1] = p[2] = n;
+            break;
+        default:
+            BADF("Bad color depth\n");
+            return;
+        }
+        p += dest_width;
+    }
+    /* TODO: Implement row/column remapping.  */
+    dest = surface_data(surface);
+    for (y = 0; y < 64; y++) {
+        line = y;
+        src = s->framebuffer + 64 * line;
+        for (x = 0; x < 64; x++) {
+            int val;
+            val = *src >> 4;
+            for (i = 0; i < MAGNIFY; i++) {
+                memcpy(dest, colors[val], dest_width);
+                dest += dest_width;
+            }
+            val = *src & 0xf;
+            for (i = 0; i < MAGNIFY; i++) {
+                memcpy(dest, colors[val], dest_width);
+                dest += dest_width;
+            }
+            src++;
+        }
+        for (i = 1; i < MAGNIFY; i++) {
+            memcpy(dest, dest - dest_width * MAGNIFY * 128,
+                   dest_width * 128 * MAGNIFY);
+            dest += dest_width * 128 * MAGNIFY;
+        }
+    }
+    s->redraw = 0;
+    dpy_gfx_update(s->con, 0, 0, 128 * MAGNIFY, 64 * MAGNIFY);
+}
+
+static void ssd0323_invalidate_display(void * opaque)
+{
+    ssd0323_state *s = (ssd0323_state *)opaque;
+    s->redraw = 1;
+}
+
+/* Command/data input.  */
+static void ssd0323_cd(void *opaque, int n, int level)
+{
+    ssd0323_state *s = (ssd0323_state *)opaque;
+    DPRINTF("%s mode\n", level ? "Data" : "Command");
+    s->mode = level ? SSD0323_DATA : SSD0323_CMD;
+}
+
+static void ssd0323_save(QEMUFile *f, void *opaque)
+{
+    SSISlave *ss = SSI_SLAVE(opaque);
+    ssd0323_state *s = (ssd0323_state *)opaque;
+    int i;
+
+    qemu_put_be32(f, s->cmd_len);
+    qemu_put_be32(f, s->cmd);
+    for (i = 0; i < 8; i++)
+        qemu_put_be32(f, s->cmd_data[i]);
+    qemu_put_be32(f, s->row);
+    qemu_put_be32(f, s->row_start);
+    qemu_put_be32(f, s->row_end);
+    qemu_put_be32(f, s->col);
+    qemu_put_be32(f, s->col_start);
+    qemu_put_be32(f, s->col_end);
+    qemu_put_be32(f, s->redraw);
+    qemu_put_be32(f, s->remap);
+    qemu_put_be32(f, s->mode);
+    qemu_put_buffer(f, s->framebuffer, sizeof(s->framebuffer));
+
+    qemu_put_be32(f, ss->cs);
+}
+
+static int ssd0323_load(QEMUFile *f, void *opaque, int version_id)
+{
+    SSISlave *ss = SSI_SLAVE(opaque);
+    ssd0323_state *s = (ssd0323_state *)opaque;
+    int i;
+
+    if (version_id != 1)
+        return -EINVAL;
+
+    s->cmd_len = qemu_get_be32(f);
+    s->cmd = qemu_get_be32(f);
+    for (i = 0; i < 8; i++)
+        s->cmd_data[i] = qemu_get_be32(f);
+    s->row = qemu_get_be32(f);
+    s->row_start = qemu_get_be32(f);
+    s->row_end = qemu_get_be32(f);
+    s->col = qemu_get_be32(f);
+    s->col_start = qemu_get_be32(f);
+    s->col_end = qemu_get_be32(f);
+    s->redraw = qemu_get_be32(f);
+    s->remap = qemu_get_be32(f);
+    s->mode = qemu_get_be32(f);
+    qemu_get_buffer(f, s->framebuffer, sizeof(s->framebuffer));
+
+    ss->cs = qemu_get_be32(f);
+
+    return 0;
+}
+
+static int ssd0323_init(SSISlave *dev)
+{
+    ssd0323_state *s = FROM_SSI_SLAVE(ssd0323_state, dev);
+
+    s->col_end = 63;
+    s->row_end = 79;
+    s->con = graphic_console_init(ssd0323_update_display,
+                                  ssd0323_invalidate_display,
+                                  NULL, NULL, s);
+    qemu_console_resize(s->con, 128 * MAGNIFY, 64 * MAGNIFY);
+
+    qdev_init_gpio_in(&dev->qdev, ssd0323_cd, 1);
+
+    register_savevm(&dev->qdev, "ssd0323_oled", -1, 1,
+                    ssd0323_save, ssd0323_load, s);
+    return 0;
+}
+
+static void ssd0323_class_init(ObjectClass *klass, void *data)
+{
+    SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
+
+    k->init = ssd0323_init;
+    k->transfer = ssd0323_transfer;
+    k->cs_polarity = SSI_CS_HIGH;
+}
+
+static const TypeInfo ssd0323_info = {
+    .name          = "ssd0323",
+    .parent        = TYPE_SSI_SLAVE,
+    .instance_size = sizeof(ssd0323_state),
+    .class_init    = ssd0323_class_init,
+};
+
+static void ssd03232_register_types(void)
+{
+    type_register_static(&ssd0323_info);
+}
+
+type_init(ssd03232_register_types)
diff --git a/hw/display/tc6393xb.c b/hw/display/tc6393xb.c
new file mode 100644 (file)
index 0000000..e252ce9
--- /dev/null
@@ -0,0 +1,593 @@
+/*
+ * Toshiba TC6393XB I/O Controller.
+ * Found in Sharp Zaurus SL-6000 (tosa) or some
+ * Toshiba e-Series PDAs.
+ *
+ * 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/hw.h"
+#include "hw/arm/devices.h"
+#include "hw/block/flash.h"
+#include "ui/console.h"
+#include "ui/pixel_ops.h"
+#include "sysemu/blockdev.h"
+
+#define IRQ_TC6393_NAND                0
+#define IRQ_TC6393_MMC         1
+#define IRQ_TC6393_OHCI                2
+#define IRQ_TC6393_SERIAL      3
+#define IRQ_TC6393_FB          4
+
+#define        TC6393XB_NR_IRQS        8
+
+#define TC6393XB_GPIOS  16
+
+#define SCR_REVID      0x08            /* b Revision ID        */
+#define SCR_ISR                0x50            /* b Interrupt Status   */
+#define SCR_IMR                0x52            /* b Interrupt Mask     */
+#define SCR_IRR                0x54            /* b Interrupt Routing  */
+#define SCR_GPER       0x60            /* w GP Enable          */
+#define SCR_GPI_SR(i)  (0x64 + (i))    /* b3 GPI Status        */
+#define SCR_GPI_IMR(i) (0x68 + (i))    /* b3 GPI INT Mask      */
+#define SCR_GPI_EDER(i)        (0x6c + (i))    /* b3 GPI Edge Detect Enable */
+#define SCR_GPI_LIR(i) (0x70 + (i))    /* b3 GPI Level Invert  */
+#define SCR_GPO_DSR(i) (0x78 + (i))    /* b3 GPO Data Set      */
+#define SCR_GPO_DOECR(i) (0x7c + (i))  /* b3 GPO Data OE Control */
+#define SCR_GP_IARCR(i)        (0x80 + (i))    /* b3 GP Internal Active Register Control */
+#define SCR_GP_IARLCR(i) (0x84 + (i))  /* b3 GP INTERNAL Active Register Level Control */
+#define SCR_GPI_BCR(i) (0x88 + (i))    /* b3 GPI Buffer Control */
+#define SCR_GPA_IARCR  0x8c            /* w GPa Internal Active Register Control */
+#define SCR_GPA_IARLCR 0x90            /* w GPa Internal Active Register Level Control */
+#define SCR_GPA_BCR    0x94            /* w GPa Buffer Control */
+#define SCR_CCR                0x98            /* w Clock Control      */
+#define SCR_PLL2CR     0x9a            /* w PLL2 Control       */
+#define SCR_PLL1CR     0x9c            /* l PLL1 Control       */
+#define SCR_DIARCR     0xa0            /* b Device Internal Active Register Control */
+#define SCR_DBOCR      0xa1            /* b Device Buffer Off Control */
+#define SCR_FER                0xe0            /* b Function Enable    */
+#define SCR_MCR                0xe4            /* w Mode Control       */
+#define SCR_CONFIG     0xfc            /* b Configuration Control */
+#define SCR_DEBUG      0xff            /* b Debug              */
+
+#define NAND_CFG_COMMAND    0x04    /* w Command        */
+#define NAND_CFG_BASE       0x10    /* l Control Base Address */
+#define NAND_CFG_INTP       0x3d    /* b Interrupt Pin  */
+#define NAND_CFG_INTE       0x48    /* b Int Enable     */
+#define NAND_CFG_EC         0x4a    /* b Event Control  */
+#define NAND_CFG_ICC        0x4c    /* b Internal Clock Control */
+#define NAND_CFG_ECCC       0x5b    /* b ECC Control    */
+#define NAND_CFG_NFTC       0x60    /* b NAND Flash Transaction Control */
+#define NAND_CFG_NFM        0x61    /* b NAND Flash Monitor */
+#define NAND_CFG_NFPSC      0x62    /* b NAND Flash Power Supply Control */
+#define NAND_CFG_NFDC       0x63    /* b NAND Flash Detect Control */
+
+#define NAND_DATA   0x00        /* l Data       */
+#define NAND_MODE   0x04        /* b Mode       */
+#define NAND_STATUS 0x05        /* b Status     */
+#define NAND_ISR    0x06        /* b Interrupt Status */
+#define NAND_IMR    0x07        /* b Interrupt Mask */
+
+#define NAND_MODE_WP        0x80
+#define NAND_MODE_CE        0x10
+#define NAND_MODE_ALE       0x02
+#define NAND_MODE_CLE       0x01
+#define NAND_MODE_ECC_MASK  0x60
+#define NAND_MODE_ECC_EN    0x20
+#define NAND_MODE_ECC_READ  0x40
+#define NAND_MODE_ECC_RST   0x60
+
+struct TC6393xbState {
+    MemoryRegion iomem;
+    qemu_irq irq;
+    qemu_irq *sub_irqs;
+    struct {
+        uint8_t ISR;
+        uint8_t IMR;
+        uint8_t IRR;
+        uint16_t GPER;
+        uint8_t GPI_SR[3];
+        uint8_t GPI_IMR[3];
+        uint8_t GPI_EDER[3];
+        uint8_t GPI_LIR[3];
+        uint8_t GP_IARCR[3];
+        uint8_t GP_IARLCR[3];
+        uint8_t GPI_BCR[3];
+        uint16_t GPA_IARCR;
+        uint16_t GPA_IARLCR;
+        uint16_t CCR;
+        uint16_t PLL2CR;
+        uint32_t PLL1CR;
+        uint8_t DIARCR;
+        uint8_t DBOCR;
+        uint8_t FER;
+        uint16_t MCR;
+        uint8_t CONFIG;
+        uint8_t DEBUG;
+    } scr;
+    uint32_t gpio_dir;
+    uint32_t gpio_level;
+    uint32_t prev_level;
+    qemu_irq handler[TC6393XB_GPIOS];
+    qemu_irq *gpio_in;
+
+    struct {
+        uint8_t mode;
+        uint8_t isr;
+        uint8_t imr;
+    } nand;
+    int nand_enable;
+    uint32_t nand_phys;
+    DeviceState *flash;
+    ECCState ecc;
+
+    QemuConsole *con;
+    MemoryRegion vram;
+    uint16_t *vram_ptr;
+    uint32_t scr_width, scr_height; /* in pixels */
+    qemu_irq l3v;
+    unsigned blank : 1,
+             blanked : 1;
+};
+
+qemu_irq *tc6393xb_gpio_in_get(TC6393xbState *s)
+{
+    return s->gpio_in;
+}
+
+static void tc6393xb_gpio_set(void *opaque, int line, int level)
+{
+//    TC6393xbState *s = opaque;
+
+    if (line > TC6393XB_GPIOS) {
+        printf("%s: No GPIO pin %i\n", __FUNCTION__, line);
+        return;
+    }
+
+    // FIXME: how does the chip reflect the GPIO input level change?
+}
+
+void tc6393xb_gpio_out_set(TC6393xbState *s, int line,
+                    qemu_irq handler)
+{
+    if (line >= TC6393XB_GPIOS) {
+        fprintf(stderr, "TC6393xb: no GPIO pin %d\n", line);
+        return;
+    }
+
+    s->handler[line] = handler;
+}
+
+static void tc6393xb_gpio_handler_update(TC6393xbState *s)
+{
+    uint32_t level, diff;
+    int bit;
+
+    level = s->gpio_level & s->gpio_dir;
+
+    for (diff = s->prev_level ^ level; diff; diff ^= 1 << bit) {
+        bit = ffs(diff) - 1;
+        qemu_set_irq(s->handler[bit], (level >> bit) & 1);
+    }
+
+    s->prev_level = level;
+}
+
+qemu_irq tc6393xb_l3v_get(TC6393xbState *s)
+{
+    return s->l3v;
+}
+
+static void tc6393xb_l3v(void *opaque, int line, int level)
+{
+    TC6393xbState *s = opaque;
+    s->blank = !level;
+    fprintf(stderr, "L3V: %d\n", level);
+}
+
+static void tc6393xb_sub_irq(void *opaque, int line, int level) {
+    TC6393xbState *s = opaque;
+    uint8_t isr = s->scr.ISR;
+    if (level)
+        isr |= 1 << line;
+    else
+        isr &= ~(1 << line);
+    s->scr.ISR = isr;
+    qemu_set_irq(s->irq, isr & s->scr.IMR);
+}
+
+#define SCR_REG_B(N)                            \
+    case SCR_ ##N: return s->scr.N
+#define SCR_REG_W(N)                            \
+    case SCR_ ##N: return s->scr.N;             \
+    case SCR_ ##N + 1: return s->scr.N >> 8;
+#define SCR_REG_L(N)                            \
+    case SCR_ ##N: return s->scr.N;             \
+    case SCR_ ##N + 1: return s->scr.N >> 8;    \
+    case SCR_ ##N + 2: return s->scr.N >> 16;   \
+    case SCR_ ##N + 3: return s->scr.N >> 24;
+#define SCR_REG_A(N)                            \
+    case SCR_ ##N(0): return s->scr.N[0];       \
+    case SCR_ ##N(1): return s->scr.N[1];       \
+    case SCR_ ##N(2): return s->scr.N[2]
+
+static uint32_t tc6393xb_scr_readb(TC6393xbState *s, hwaddr addr)
+{
+    switch (addr) {
+        case SCR_REVID:
+            return 3;
+        case SCR_REVID+1:
+            return 0;
+        SCR_REG_B(ISR);
+        SCR_REG_B(IMR);
+        SCR_REG_B(IRR);
+        SCR_REG_W(GPER);
+        SCR_REG_A(GPI_SR);
+        SCR_REG_A(GPI_IMR);
+        SCR_REG_A(GPI_EDER);
+        SCR_REG_A(GPI_LIR);
+        case SCR_GPO_DSR(0):
+        case SCR_GPO_DSR(1):
+        case SCR_GPO_DSR(2):
+            return (s->gpio_level >> ((addr - SCR_GPO_DSR(0)) * 8)) & 0xff;
+        case SCR_GPO_DOECR(0):
+        case SCR_GPO_DOECR(1):
+        case SCR_GPO_DOECR(2):
+            return (s->gpio_dir >> ((addr - SCR_GPO_DOECR(0)) * 8)) & 0xff;
+        SCR_REG_A(GP_IARCR);
+        SCR_REG_A(GP_IARLCR);
+        SCR_REG_A(GPI_BCR);
+        SCR_REG_W(GPA_IARCR);
+        SCR_REG_W(GPA_IARLCR);
+        SCR_REG_W(CCR);
+        SCR_REG_W(PLL2CR);
+        SCR_REG_L(PLL1CR);
+        SCR_REG_B(DIARCR);
+        SCR_REG_B(DBOCR);
+        SCR_REG_B(FER);
+        SCR_REG_W(MCR);
+        SCR_REG_B(CONFIG);
+        SCR_REG_B(DEBUG);
+    }
+    fprintf(stderr, "tc6393xb_scr: unhandled read at %08x\n", (uint32_t) addr);
+    return 0;
+}
+#undef SCR_REG_B
+#undef SCR_REG_W
+#undef SCR_REG_L
+#undef SCR_REG_A
+
+#define SCR_REG_B(N)                                \
+    case SCR_ ##N: s->scr.N = value; return;
+#define SCR_REG_W(N)                                \
+    case SCR_ ##N: s->scr.N = (s->scr.N & ~0xff) | (value & 0xff); return; \
+    case SCR_ ##N + 1: s->scr.N = (s->scr.N & 0xff) | (value << 8); return
+#define SCR_REG_L(N)                                \
+    case SCR_ ##N: s->scr.N = (s->scr.N & ~0xff) | (value & 0xff); return;   \
+    case SCR_ ##N + 1: s->scr.N = (s->scr.N & ~(0xff << 8)) | (value & (0xff << 8)); return;     \
+    case SCR_ ##N + 2: s->scr.N = (s->scr.N & ~(0xff << 16)) | (value & (0xff << 16)); return;   \
+    case SCR_ ##N + 3: s->scr.N = (s->scr.N & ~(0xff << 24)) | (value & (0xff << 24)); return;
+#define SCR_REG_A(N)                                \
+    case SCR_ ##N(0): s->scr.N[0] = value; return;   \
+    case SCR_ ##N(1): s->scr.N[1] = value; return;   \
+    case SCR_ ##N(2): s->scr.N[2] = value; return
+
+static void tc6393xb_scr_writeb(TC6393xbState *s, hwaddr addr, uint32_t value)
+{
+    switch (addr) {
+        SCR_REG_B(ISR);
+        SCR_REG_B(IMR);
+        SCR_REG_B(IRR);
+        SCR_REG_W(GPER);
+        SCR_REG_A(GPI_SR);
+        SCR_REG_A(GPI_IMR);
+        SCR_REG_A(GPI_EDER);
+        SCR_REG_A(GPI_LIR);
+        case SCR_GPO_DSR(0):
+        case SCR_GPO_DSR(1):
+        case SCR_GPO_DSR(2):
+            s->gpio_level = (s->gpio_level & ~(0xff << ((addr - SCR_GPO_DSR(0))*8))) | ((value & 0xff) << ((addr - SCR_GPO_DSR(0))*8));
+            tc6393xb_gpio_handler_update(s);
+            return;
+        case SCR_GPO_DOECR(0):
+        case SCR_GPO_DOECR(1):
+        case SCR_GPO_DOECR(2):
+            s->gpio_dir = (s->gpio_dir & ~(0xff << ((addr - SCR_GPO_DOECR(0))*8))) | ((value & 0xff) << ((addr - SCR_GPO_DOECR(0))*8));
+            tc6393xb_gpio_handler_update(s);
+            return;
+        SCR_REG_A(GP_IARCR);
+        SCR_REG_A(GP_IARLCR);
+        SCR_REG_A(GPI_BCR);
+        SCR_REG_W(GPA_IARCR);
+        SCR_REG_W(GPA_IARLCR);
+        SCR_REG_W(CCR);
+        SCR_REG_W(PLL2CR);
+        SCR_REG_L(PLL1CR);
+        SCR_REG_B(DIARCR);
+        SCR_REG_B(DBOCR);
+        SCR_REG_B(FER);
+        SCR_REG_W(MCR);
+        SCR_REG_B(CONFIG);
+        SCR_REG_B(DEBUG);
+    }
+    fprintf(stderr, "tc6393xb_scr: unhandled write at %08x: %02x\n",
+                                       (uint32_t) addr, value & 0xff);
+}
+#undef SCR_REG_B
+#undef SCR_REG_W
+#undef SCR_REG_L
+#undef SCR_REG_A
+
+static void tc6393xb_nand_irq(TC6393xbState *s) {
+    qemu_set_irq(s->sub_irqs[IRQ_TC6393_NAND],
+            (s->nand.imr & 0x80) && (s->nand.imr & s->nand.isr));
+}
+
+static uint32_t tc6393xb_nand_cfg_readb(TC6393xbState *s, hwaddr addr) {
+    switch (addr) {
+        case NAND_CFG_COMMAND:
+            return s->nand_enable ? 2 : 0;
+        case NAND_CFG_BASE:
+        case NAND_CFG_BASE + 1:
+        case NAND_CFG_BASE + 2:
+        case NAND_CFG_BASE + 3:
+            return s->nand_phys >> (addr - NAND_CFG_BASE);
+    }
+    fprintf(stderr, "tc6393xb_nand_cfg: unhandled read at %08x\n", (uint32_t) addr);
+    return 0;
+}
+static void tc6393xb_nand_cfg_writeb(TC6393xbState *s, hwaddr addr, uint32_t value) {
+    switch (addr) {
+        case NAND_CFG_COMMAND:
+            s->nand_enable = (value & 0x2);
+            return;
+        case NAND_CFG_BASE:
+        case NAND_CFG_BASE + 1:
+        case NAND_CFG_BASE + 2:
+        case NAND_CFG_BASE + 3:
+            s->nand_phys &= ~(0xff << ((addr - NAND_CFG_BASE) * 8));
+            s->nand_phys |= (value & 0xff) << ((addr - NAND_CFG_BASE) * 8);
+            return;
+    }
+    fprintf(stderr, "tc6393xb_nand_cfg: unhandled write at %08x: %02x\n",
+                                       (uint32_t) addr, value & 0xff);
+}
+
+static uint32_t tc6393xb_nand_readb(TC6393xbState *s, hwaddr addr) {
+    switch (addr) {
+        case NAND_DATA + 0:
+        case NAND_DATA + 1:
+        case NAND_DATA + 2:
+        case NAND_DATA + 3:
+            return nand_getio(s->flash);
+        case NAND_MODE:
+            return s->nand.mode;
+        case NAND_STATUS:
+            return 0x14;
+        case NAND_ISR:
+            return s->nand.isr;
+        case NAND_IMR:
+            return s->nand.imr;
+    }
+    fprintf(stderr, "tc6393xb_nand: unhandled read at %08x\n", (uint32_t) addr);
+    return 0;
+}
+static void tc6393xb_nand_writeb(TC6393xbState *s, hwaddr addr, uint32_t value) {
+//    fprintf(stderr, "tc6393xb_nand: write at %08x: %02x\n",
+//                                     (uint32_t) addr, value & 0xff);
+    switch (addr) {
+        case NAND_DATA + 0:
+        case NAND_DATA + 1:
+        case NAND_DATA + 2:
+        case NAND_DATA + 3:
+            nand_setio(s->flash, value);
+            s->nand.isr |= 1;
+            tc6393xb_nand_irq(s);
+            return;
+        case NAND_MODE:
+            s->nand.mode = value;
+            nand_setpins(s->flash,
+                    value & NAND_MODE_CLE,
+                    value & NAND_MODE_ALE,
+                    !(value & NAND_MODE_CE),
+                    value & NAND_MODE_WP,
+                    0); // FIXME: gnd
+            switch (value & NAND_MODE_ECC_MASK) {
+                case NAND_MODE_ECC_RST:
+                    ecc_reset(&s->ecc);
+                    break;
+                case NAND_MODE_ECC_READ:
+                    // FIXME
+                    break;
+                case NAND_MODE_ECC_EN:
+                    ecc_reset(&s->ecc);
+            }
+            return;
+        case NAND_ISR:
+            s->nand.isr = value;
+            tc6393xb_nand_irq(s);
+            return;
+        case NAND_IMR:
+            s->nand.imr = value;
+            tc6393xb_nand_irq(s);
+            return;
+    }
+    fprintf(stderr, "tc6393xb_nand: unhandled write at %08x: %02x\n",
+                                       (uint32_t) addr, value & 0xff);
+}
+
+#define BITS 8
+#include "tc6393xb_template.h"
+#define BITS 15
+#include "tc6393xb_template.h"
+#define BITS 16
+#include "tc6393xb_template.h"
+#define BITS 24
+#include "tc6393xb_template.h"
+#define BITS 32
+#include "tc6393xb_template.h"
+
+static void tc6393xb_draw_graphic(TC6393xbState *s, int full_update)
+{
+    DisplaySurface *surface = qemu_console_surface(s->con);
+
+    switch (surface_bits_per_pixel(surface)) {
+        case 8:
+            tc6393xb_draw_graphic8(s);
+            break;
+        case 15:
+            tc6393xb_draw_graphic15(s);
+            break;
+        case 16:
+            tc6393xb_draw_graphic16(s);
+            break;
+        case 24:
+            tc6393xb_draw_graphic24(s);
+            break;
+        case 32:
+            tc6393xb_draw_graphic32(s);
+            break;
+        default:
+            printf("tc6393xb: unknown depth %d\n",
+                   surface_bits_per_pixel(surface));
+            return;
+    }
+
+    dpy_gfx_update(s->con, 0, 0, s->scr_width, s->scr_height);
+}
+
+static void tc6393xb_draw_blank(TC6393xbState *s, int full_update)
+{
+    DisplaySurface *surface = qemu_console_surface(s->con);
+    int i, w;
+    uint8_t *d;
+
+    if (!full_update)
+        return;
+
+    w = s->scr_width * surface_bytes_per_pixel(surface);
+    d = surface_data(surface);
+    for(i = 0; i < s->scr_height; i++) {
+        memset(d, 0, w);
+        d += surface_stride(surface);
+    }
+
+    dpy_gfx_update(s->con, 0, 0, s->scr_width, s->scr_height);
+}
+
+static void tc6393xb_update_display(void *opaque)
+{
+    TC6393xbState *s = opaque;
+    DisplaySurface *surface = qemu_console_surface(s->con);
+    int full_update;
+
+    if (s->scr_width == 0 || s->scr_height == 0)
+        return;
+
+    full_update = 0;
+    if (s->blanked != s->blank) {
+        s->blanked = s->blank;
+        full_update = 1;
+    }
+    if (s->scr_width != surface_width(surface) ||
+        s->scr_height != surface_height(surface)) {
+        qemu_console_resize(s->con, s->scr_width, s->scr_height);
+        full_update = 1;
+    }
+    if (s->blanked)
+        tc6393xb_draw_blank(s, full_update);
+    else
+        tc6393xb_draw_graphic(s, full_update);
+}
+
+
+static uint64_t tc6393xb_readb(void *opaque, hwaddr addr,
+                               unsigned size)
+{
+    TC6393xbState *s = opaque;
+
+    switch (addr >> 8) {
+        case 0:
+            return tc6393xb_scr_readb(s, addr & 0xff);
+        case 1:
+            return tc6393xb_nand_cfg_readb(s, addr & 0xff);
+    };
+
+    if ((addr &~0xff) == s->nand_phys && s->nand_enable) {
+//        return tc6393xb_nand_readb(s, addr & 0xff);
+        uint8_t d = tc6393xb_nand_readb(s, addr & 0xff);
+//        fprintf(stderr, "tc6393xb_nand: read at %08x: %02hhx\n", (uint32_t) addr, d);
+        return d;
+    }
+
+//    fprintf(stderr, "tc6393xb: unhandled read at %08x\n", (uint32_t) addr);
+    return 0;
+}
+
+static void tc6393xb_writeb(void *opaque, hwaddr addr,
+                            uint64_t value, unsigned size) {
+    TC6393xbState *s = opaque;
+
+    switch (addr >> 8) {
+        case 0:
+            tc6393xb_scr_writeb(s, addr & 0xff, value);
+            return;
+        case 1:
+            tc6393xb_nand_cfg_writeb(s, addr & 0xff, value);
+            return;
+    };
+
+    if ((addr &~0xff) == s->nand_phys && s->nand_enable)
+        tc6393xb_nand_writeb(s, addr & 0xff, value);
+    else
+        fprintf(stderr, "tc6393xb: unhandled write at %08x: %02x\n",
+                (uint32_t) addr, (int)value & 0xff);
+}
+
+TC6393xbState *tc6393xb_init(MemoryRegion *sysmem, uint32_t base, qemu_irq irq)
+{
+    TC6393xbState *s;
+    DriveInfo *nand;
+    static const MemoryRegionOps tc6393xb_ops = {
+        .read = tc6393xb_readb,
+        .write = tc6393xb_writeb,
+        .endianness = DEVICE_NATIVE_ENDIAN,
+        .impl = {
+            .min_access_size = 1,
+            .max_access_size = 1,
+        },
+    };
+
+    s = (TC6393xbState *) g_malloc0(sizeof(TC6393xbState));
+    s->irq = irq;
+    s->gpio_in = qemu_allocate_irqs(tc6393xb_gpio_set, s, TC6393XB_GPIOS);
+
+    s->l3v = *qemu_allocate_irqs(tc6393xb_l3v, s, 1);
+    s->blanked = 1;
+
+    s->sub_irqs = qemu_allocate_irqs(tc6393xb_sub_irq, s, TC6393XB_NR_IRQS);
+
+    nand = drive_get(IF_MTD, 0, 0);
+    s->flash = nand_init(nand ? nand->bdrv : NULL, NAND_MFR_TOSHIBA, 0x76);
+
+    memory_region_init_io(&s->iomem, &tc6393xb_ops, s, "tc6393xb", 0x10000);
+    memory_region_add_subregion(sysmem, base, &s->iomem);
+
+    memory_region_init_ram(&s->vram, "tc6393xb.vram", 0x100000);
+    vmstate_register_ram_global(&s->vram);
+    s->vram_ptr = memory_region_get_ram_ptr(&s->vram);
+    memory_region_add_subregion(sysmem, base + 0x100000, &s->vram);
+    s->scr_width = 480;
+    s->scr_height = 640;
+    s->con = graphic_console_init(tc6393xb_update_display,
+            NULL, /* invalidate */
+            NULL, /* screen_dump */
+            NULL, /* text_update */
+            s);
+
+    return s;
+}
diff --git a/hw/display/tc6393xb_template.h b/hw/display/tc6393xb_template.h
new file mode 100644 (file)
index 0000000..154aafd
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Toshiba TC6393XB I/O Controller.
+ * Found in Sharp Zaurus SL-6000 (tosa) or some
+ * Toshiba e-Series PDAs.
+ *
+ * FB support code. Based on G364 fb emulator
+ *
+ * Copyright (c) 2007 Hervé Poussineau
+ *
+ * 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/>.
+ */
+
+#if BITS == 8
+# define SET_PIXEL(addr, color)        *(uint8_t*)addr = color;
+#elif BITS == 15 || BITS == 16
+# define SET_PIXEL(addr, color)        *(uint16_t*)addr = color;
+#elif BITS == 24
+# define SET_PIXEL(addr, color)        \
+    addr[0] = color; addr[1] = (color) >> 8; addr[2] = (color) >> 16;
+#elif BITS == 32
+# define SET_PIXEL(addr, color)        *(uint32_t*)addr = color;
+#else
+# error unknown bit depth
+#endif
+
+
+static void glue(tc6393xb_draw_graphic, BITS)(TC6393xbState *s)
+{
+    DisplaySurface *surface = qemu_console_surface(s->con);
+    int i;
+    uint16_t *data_buffer;
+    uint8_t *data_display;
+
+    data_buffer = s->vram_ptr;
+    data_display = surface_data(surface);
+    for(i = 0; i < s->scr_height; i++) {
+#if (BITS == 16)
+        memcpy(data_display, data_buffer, s->scr_width * 2);
+        data_buffer += s->scr_width;
+        data_display += surface_stride(surface);
+#else
+        int j;
+        for (j = 0; j < s->scr_width; j++, data_display += BITS / 8, data_buffer++) {
+            uint16_t color = *data_buffer;
+            uint32_t dest_color = glue(rgb_to_pixel, BITS)(
+                           ((color & 0xf800) * 0x108) >> 11,
+                           ((color & 0x7e0) * 0x41) >> 9,
+                           ((color & 0x1f) * 0x21) >> 2
+                           );
+            SET_PIXEL(data_display, dest_color);
+        }
+#endif
+    }
+}
+
+#undef BITS
+#undef SET_PIXEL
diff --git a/hw/display/tcx.c b/hw/display/tcx.c
new file mode 100644 (file)
index 0000000..c44068e
--- /dev/null
@@ -0,0 +1,739 @@
+/*
+ * QEMU TCX Frame buffer
+ *
+ * Copyright (c) 2003-2005 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.
+ */
+
+#include "qemu-common.h"
+#include "ui/console.h"
+#include "ui/pixel_ops.h"
+#include "hw/sysbus.h"
+#include "hw/qdev-addr.h"
+
+#define MAXX 1024
+#define MAXY 768
+#define TCX_DAC_NREGS 16
+#define TCX_THC_NREGS_8  0x081c
+#define TCX_THC_NREGS_24 0x1000
+#define TCX_TEC_NREGS    0x1000
+
+typedef struct TCXState {
+    SysBusDevice busdev;
+    QemuConsole *con;
+    uint8_t *vram;
+    uint32_t *vram24, *cplane;
+    MemoryRegion vram_mem;
+    MemoryRegion vram_8bit;
+    MemoryRegion vram_24bit;
+    MemoryRegion vram_cplane;
+    MemoryRegion dac;
+    MemoryRegion tec;
+    MemoryRegion thc24;
+    MemoryRegion thc8;
+    ram_addr_t vram24_offset, cplane_offset;
+    uint32_t vram_size;
+    uint32_t palette[256];
+    uint8_t r[256], g[256], b[256];
+    uint16_t width, height, depth;
+    uint8_t dac_index, dac_state;
+} TCXState;
+
+static void tcx_screen_dump(void *opaque, const char *filename, bool cswitch,
+                            Error **errp);
+static void tcx24_screen_dump(void *opaque, const char *filename, bool cswitch,
+                            Error **errp);
+
+static void tcx_set_dirty(TCXState *s)
+{
+    memory_region_set_dirty(&s->vram_mem, 0, MAXX * MAXY);
+}
+
+static void tcx24_set_dirty(TCXState *s)
+{
+    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)
+{
+    DisplaySurface *surface = qemu_console_surface(s->con);
+    int i;
+
+    for (i = start; i < end; i++) {
+        switch (surface_bits_per_pixel(surface)) {
+        default:
+        case 8:
+            s->palette[i] = rgb_to_pixel8(s->r[i], s->g[i], s->b[i]);
+            break;
+        case 15:
+            s->palette[i] = rgb_to_pixel15(s->r[i], s->g[i], s->b[i]);
+            break;
+        case 16:
+            s->palette[i] = rgb_to_pixel16(s->r[i], s->g[i], s->b[i]);
+            break;
+        case 32:
+            if (is_surface_bgr(surface)) {
+                s->palette[i] = rgb_to_pixel32bgr(s->r[i], s->g[i], s->b[i]);
+            } else {
+                s->palette[i] = rgb_to_pixel32(s->r[i], s->g[i], s->b[i]);
+            }
+            break;
+        }
+    }
+    if (s->depth == 24) {
+        tcx24_set_dirty(s);
+    } else {
+        tcx_set_dirty(s);
+    }
+}
+
+static void tcx_draw_line32(TCXState *s1, uint8_t *d,
+                            const uint8_t *s, int width)
+{
+    int x;
+    uint8_t val;
+    uint32_t *p = (uint32_t *)d;
+
+    for(x = 0; x < width; x++) {
+        val = *s++;
+        *p++ = s1->palette[val];
+    }
+}
+
+static void tcx_draw_line16(TCXState *s1, uint8_t *d,
+                            const uint8_t *s, int width)
+{
+    int x;
+    uint8_t val;
+    uint16_t *p = (uint16_t *)d;
+
+    for(x = 0; x < width; x++) {
+        val = *s++;
+        *p++ = s1->palette[val];
+    }
+}
+
+static void tcx_draw_line8(TCXState *s1, uint8_t *d,
+                           const uint8_t *s, int width)
+{
+    int x;
+    uint8_t val;
+
+    for(x = 0; x < width; x++) {
+        val = *s++;
+        *d++ = s1->palette[val];
+    }
+}
+
+/*
+  XXX Could be much more optimal:
+  * detect if line/page/whole screen is in 24 bit mode
+  * if destination is also BGR, use memcpy
+  */
+static inline void tcx24_draw_line32(TCXState *s1, uint8_t *d,
+                                     const uint8_t *s, int width,
+                                     const uint32_t *cplane,
+                                     const uint32_t *s24)
+{
+    DisplaySurface *surface = qemu_console_surface(s1->con);
+    int x, bgr, r, g, b;
+    uint8_t val, *p8;
+    uint32_t *p = (uint32_t *)d;
+    uint32_t dval;
+
+    bgr = is_surface_bgr(surface);
+    for(x = 0; x < width; x++, s++, s24++) {
+        if ((be32_to_cpu(*cplane++) & 0xff000000) == 0x03000000) {
+            // 24-bit direct, BGR order
+            p8 = (uint8_t *)s24;
+            p8++;
+            b = *p8++;
+            g = *p8++;
+            r = *p8;
+            if (bgr)
+                dval = rgb_to_pixel32bgr(r, g, b);
+            else
+                dval = rgb_to_pixel32(r, g, b);
+        } else {
+            val = *s;
+            dval = s1->palette[val];
+        }
+        *p++ = dval;
+    }
+}
+
+static inline int check_dirty(TCXState *s, ram_addr_t page, ram_addr_t page24,
+                              ram_addr_t cpage)
+{
+    int ret;
+
+    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;
+}
+
+static inline void reset_dirty(TCXState *ts, ram_addr_t page_min,
+                               ram_addr_t page_max, ram_addr_t page24,
+                              ram_addr_t cpage)
+{
+    memory_region_reset_dirty(&ts->vram_mem,
+                              page_min, page_max + TARGET_PAGE_SIZE,
+                              DIRTY_MEMORY_VGA);
+    memory_region_reset_dirty(&ts->vram_mem,
+                              page24 + page_min * 4,
+                              page24 + page_max * 4 + TARGET_PAGE_SIZE,
+                              DIRTY_MEMORY_VGA);
+    memory_region_reset_dirty(&ts->vram_mem,
+                              cpage + page_min * 4,
+                              cpage + page_max * 4 + TARGET_PAGE_SIZE,
+                              DIRTY_MEMORY_VGA);
+}
+
+/* Fixed line length 1024 allows us to do nice tricks not possible on
+   VGA... */
+static void tcx_update_display(void *opaque)
+{
+    TCXState *ts = opaque;
+    DisplaySurface *surface = qemu_console_surface(ts->con);
+    ram_addr_t page, page_min, page_max;
+    int y, y_start, dd, ds;
+    uint8_t *d, *s;
+    void (*f)(TCXState *s1, uint8_t *dst, const uint8_t *src, int width);
+
+    if (surface_bits_per_pixel(surface) == 0) {
+        return;
+    }
+
+    page = 0;
+    y_start = -1;
+    page_min = -1;
+    page_max = 0;
+    d = surface_data(surface);
+    s = ts->vram;
+    dd = surface_stride(surface);
+    ds = 1024;
+
+    switch (surface_bits_per_pixel(surface)) {
+    case 32:
+        f = tcx_draw_line32;
+        break;
+    case 15:
+    case 16:
+        f = tcx_draw_line16;
+        break;
+    default:
+    case 8:
+        f = tcx_draw_line8;
+        break;
+    case 0:
+        return;
+    }
+
+    for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE) {
+        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)
+                page_min = page;
+            if (page > page_max)
+                page_max = page;
+            f(ts, d, s, ts->width);
+            d += dd;
+            s += ds;
+            f(ts, d, s, ts->width);
+            d += dd;
+            s += ds;
+            f(ts, d, s, ts->width);
+            d += dd;
+            s += ds;
+            f(ts, d, s, ts->width);
+            d += dd;
+            s += ds;
+        } else {
+            if (y_start >= 0) {
+                /* flush to display */
+                dpy_gfx_update(ts->con, 0, y_start,
+                               ts->width, y - y_start);
+                y_start = -1;
+            }
+            d += dd * 4;
+            s += ds * 4;
+        }
+    }
+    if (y_start >= 0) {
+        /* flush to display */
+        dpy_gfx_update(ts->con, 0, y_start,
+                       ts->width, y - y_start);
+    }
+    /* reset modified pages */
+    if (page_max >= page_min) {
+        memory_region_reset_dirty(&ts->vram_mem,
+                                  page_min, page_max + TARGET_PAGE_SIZE,
+                                  DIRTY_MEMORY_VGA);
+    }
+}
+
+static void tcx24_update_display(void *opaque)
+{
+    TCXState *ts = opaque;
+    DisplaySurface *surface = qemu_console_surface(ts->con);
+    ram_addr_t page, page_min, page_max, cpage, page24;
+    int y, y_start, dd, ds;
+    uint8_t *d, *s;
+    uint32_t *cptr, *s24;
+
+    if (surface_bits_per_pixel(surface) != 32) {
+            return;
+    }
+
+    page = 0;
+    page24 = ts->vram24_offset;
+    cpage = ts->cplane_offset;
+    y_start = -1;
+    page_min = -1;
+    page_max = 0;
+    d = surface_data(surface);
+    s = ts->vram;
+    s24 = ts->vram24;
+    cptr = ts->cplane;
+    dd = surface_stride(surface);
+    ds = 1024;
+
+    for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE,
+            page24 += TARGET_PAGE_SIZE, cpage += TARGET_PAGE_SIZE) {
+        if (check_dirty(ts, page, page24, cpage)) {
+            if (y_start < 0)
+                y_start = y;
+            if (page < page_min)
+                page_min = page;
+            if (page > page_max)
+                page_max = page;
+            tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
+            d += dd;
+            s += ds;
+            cptr += ds;
+            s24 += ds;
+            tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
+            d += dd;
+            s += ds;
+            cptr += ds;
+            s24 += ds;
+            tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
+            d += dd;
+            s += ds;
+            cptr += ds;
+            s24 += ds;
+            tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
+            d += dd;
+            s += ds;
+            cptr += ds;
+            s24 += ds;
+        } else {
+            if (y_start >= 0) {
+                /* flush to display */
+                dpy_gfx_update(ts->con, 0, y_start,
+                               ts->width, y - y_start);
+                y_start = -1;
+            }
+            d += dd * 4;
+            s += ds * 4;
+            cptr += ds * 4;
+            s24 += ds * 4;
+        }
+    }
+    if (y_start >= 0) {
+        /* flush to display */
+        dpy_gfx_update(ts->con, 0, y_start,
+                       ts->width, y - y_start);
+    }
+    /* reset modified pages */
+    if (page_max >= page_min) {
+        reset_dirty(ts, page_min, page_max, page24, cpage);
+    }
+}
+
+static void tcx_invalidate_display(void *opaque)
+{
+    TCXState *s = opaque;
+
+    tcx_set_dirty(s);
+    qemu_console_resize(s->con, s->width, s->height);
+}
+
+static void tcx24_invalidate_display(void *opaque)
+{
+    TCXState *s = opaque;
+
+    tcx_set_dirty(s);
+    tcx24_set_dirty(s);
+    qemu_console_resize(s->con, s->width, s->height);
+}
+
+static int vmstate_tcx_post_load(void *opaque, int version_id)
+{
+    TCXState *s = opaque;
+
+    update_palette_entries(s, 0, 256);
+    if (s->depth == 24) {
+        tcx24_set_dirty(s);
+    } else {
+        tcx_set_dirty(s);
+    }
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_tcx = {
+    .name ="tcx",
+    .version_id = 4,
+    .minimum_version_id = 4,
+    .minimum_version_id_old = 4,
+    .post_load = vmstate_tcx_post_load,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT16(height, TCXState),
+        VMSTATE_UINT16(width, TCXState),
+        VMSTATE_UINT16(depth, TCXState),
+        VMSTATE_BUFFER(r, TCXState),
+        VMSTATE_BUFFER(g, TCXState),
+        VMSTATE_BUFFER(b, TCXState),
+        VMSTATE_UINT8(dac_index, TCXState),
+        VMSTATE_UINT8(dac_state, TCXState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void tcx_reset(DeviceState *d)
+{
+    TCXState *s = container_of(d, TCXState, busdev.qdev);
+
+    /* Initialize palette */
+    memset(s->r, 0, 256);
+    memset(s->g, 0, 256);
+    memset(s->b, 0, 256);
+    s->r[255] = s->g[255] = s->b[255] = 255;
+    update_palette_entries(s, 0, 256);
+    memset(s->vram, 0, MAXX*MAXY);
+    memory_region_reset_dirty(&s->vram_mem, 0, MAXX * MAXY * (1 + 4 + 4),
+                              DIRTY_MEMORY_VGA);
+    s->dac_index = 0;
+    s->dac_state = 0;
+}
+
+static uint64_t tcx_dac_readl(void *opaque, hwaddr addr,
+                              unsigned size)
+{
+    return 0;
+}
+
+static void tcx_dac_writel(void *opaque, hwaddr addr, uint64_t val,
+                           unsigned size)
+{
+    TCXState *s = opaque;
+
+    switch (addr) {
+    case 0:
+        s->dac_index = val >> 24;
+        s->dac_state = 0;
+        break;
+    case 4:
+        switch (s->dac_state) {
+        case 0:
+            s->r[s->dac_index] = val >> 24;
+            update_palette_entries(s, s->dac_index, s->dac_index + 1);
+            s->dac_state++;
+            break;
+        case 1:
+            s->g[s->dac_index] = val >> 24;
+            update_palette_entries(s, s->dac_index, s->dac_index + 1);
+            s->dac_state++;
+            break;
+        case 2:
+            s->b[s->dac_index] = val >> 24;
+            update_palette_entries(s, s->dac_index, s->dac_index + 1);
+            s->dac_index = (s->dac_index + 1) & 255; // Index autoincrement
+        default:
+            s->dac_state = 0;
+            break;
+        }
+        break;
+    default:
+        break;
+    }
+}
+
+static const MemoryRegionOps tcx_dac_ops = {
+    .read = tcx_dac_readl,
+    .write = tcx_dac_writel,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static uint64_t dummy_readl(void *opaque, hwaddr addr,
+                            unsigned size)
+{
+    return 0;
+}
+
+static void dummy_writel(void *opaque, hwaddr addr,
+                         uint64_t val, unsigned size)
+{
+}
+
+static const MemoryRegionOps dummy_ops = {
+    .read = dummy_readl,
+    .write = dummy_writel,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static int tcx_init1(SysBusDevice *dev)
+{
+    TCXState *s = FROM_SYSBUS(TCXState, dev);
+    ram_addr_t vram_offset = 0;
+    int size;
+    uint8_t *vram_base;
+
+    memory_region_init_ram(&s->vram_mem, "tcx.vram",
+                           s->vram_size * (1 + 4 + 4));
+    vmstate_register_ram_global(&s->vram_mem);
+    vram_base = memory_region_get_ram_ptr(&s->vram_mem);
+
+    /* 8-bit plane */
+    s->vram = vram_base;
+    size = s->vram_size;
+    memory_region_init_alias(&s->vram_8bit, "tcx.vram.8bit",
+                             &s->vram_mem, vram_offset, size);
+    sysbus_init_mmio(dev, &s->vram_8bit);
+    vram_offset += size;
+    vram_base += size;
+
+    /* DAC */
+    memory_region_init_io(&s->dac, &tcx_dac_ops, s, "tcx.dac", TCX_DAC_NREGS);
+    sysbus_init_mmio(dev, &s->dac);
+
+    /* TEC (dummy) */
+    memory_region_init_io(&s->tec, &dummy_ops, s, "tcx.tec", TCX_TEC_NREGS);
+    sysbus_init_mmio(dev, &s->tec);
+    /* THC: NetBSD writes here even with 8-bit display: dummy */
+    memory_region_init_io(&s->thc24, &dummy_ops, s, "tcx.thc24",
+                          TCX_THC_NREGS_24);
+    sysbus_init_mmio(dev, &s->thc24);
+
+    if (s->depth == 24) {
+        /* 24-bit plane */
+        size = s->vram_size * 4;
+        s->vram24 = (uint32_t *)vram_base;
+        s->vram24_offset = vram_offset;
+        memory_region_init_alias(&s->vram_24bit, "tcx.vram.24bit",
+                                 &s->vram_mem, vram_offset, size);
+        sysbus_init_mmio(dev, &s->vram_24bit);
+        vram_offset += size;
+        vram_base += size;
+
+        /* Control plane */
+        size = s->vram_size * 4;
+        s->cplane = (uint32_t *)vram_base;
+        s->cplane_offset = vram_offset;
+        memory_region_init_alias(&s->vram_cplane, "tcx.vram.cplane",
+                                 &s->vram_mem, vram_offset, size);
+        sysbus_init_mmio(dev, &s->vram_cplane);
+
+        s->con = graphic_console_init(tcx24_update_display,
+                                      tcx24_invalidate_display,
+                                      tcx24_screen_dump, NULL, s);
+    } else {
+        /* THC 8 bit (dummy) */
+        memory_region_init_io(&s->thc8, &dummy_ops, s, "tcx.thc8",
+                              TCX_THC_NREGS_8);
+        sysbus_init_mmio(dev, &s->thc8);
+
+        s->con = graphic_console_init(tcx_update_display,
+                                      tcx_invalidate_display,
+                                      tcx_screen_dump, NULL, s);
+    }
+
+    qemu_console_resize(s->con, s->width, s->height);
+    return 0;
+}
+
+static void tcx_screen_dump(void *opaque, const char *filename, bool cswitch,
+                            Error **errp)
+{
+    TCXState *s = opaque;
+    FILE *f;
+    uint8_t *d, *d1, v;
+    int ret, y, x;
+
+    f = fopen(filename, "wb");
+    if (!f) {
+        error_setg(errp, "failed to open file '%s': %s", filename,
+                   strerror(errno));
+        return;
+    }
+    ret = fprintf(f, "P6\n%d %d\n%d\n", s->width, s->height, 255);
+    if (ret < 0) {
+        goto write_err;
+    }
+    d1 = s->vram;
+    for(y = 0; y < s->height; y++) {
+        d = d1;
+        for(x = 0; x < s->width; x++) {
+            v = *d;
+            ret = fputc(s->r[v], f);
+            if (ret == EOF) {
+                goto write_err;
+            }
+            ret = fputc(s->g[v], f);
+            if (ret == EOF) {
+                goto write_err;
+            }
+            ret = fputc(s->b[v], f);
+            if (ret == EOF) {
+                goto write_err;
+            }
+            d++;
+        }
+        d1 += MAXX;
+    }
+
+out:
+    fclose(f);
+    return;
+
+write_err:
+    error_setg(errp, "failed to write to file '%s': %s", filename,
+               strerror(errno));
+    unlink(filename);
+    goto out;
+}
+
+static void tcx24_screen_dump(void *opaque, const char *filename, bool cswitch,
+                              Error **errp)
+{
+    TCXState *s = opaque;
+    FILE *f;
+    uint8_t *d, *d1, v;
+    uint32_t *s24, *cptr, dval;
+    int ret, y, x;
+
+    f = fopen(filename, "wb");
+    if (!f) {
+        error_setg(errp, "failed to open file '%s': %s", filename,
+                   strerror(errno));
+        return;
+    }
+    ret = fprintf(f, "P6\n%d %d\n%d\n", s->width, s->height, 255);
+    if (ret < 0) {
+        goto write_err;
+    }
+    d1 = s->vram;
+    s24 = s->vram24;
+    cptr = s->cplane;
+    for(y = 0; y < s->height; y++) {
+        d = d1;
+        for(x = 0; x < s->width; x++, d++, s24++) {
+            if ((*cptr++ & 0xff000000) == 0x03000000) { // 24-bit direct
+                dval = *s24 & 0x00ffffff;
+                ret = fputc((dval >> 16) & 0xff, f);
+                if (ret == EOF) {
+                    goto write_err;
+                }
+                ret = fputc((dval >> 8) & 0xff, f);
+                if (ret == EOF) {
+                    goto write_err;
+                }
+                ret = fputc(dval & 0xff, f);
+                if (ret == EOF) {
+                    goto write_err;
+                }
+            } else {
+                v = *d;
+                ret = fputc(s->r[v], f);
+                if (ret == EOF) {
+                    goto write_err;
+                }
+                ret = fputc(s->g[v], f);
+                if (ret == EOF) {
+                    goto write_err;
+                }
+                ret = fputc(s->b[v], f);
+                if (ret == EOF) {
+                    goto write_err;
+                }
+            }
+        }
+        d1 += MAXX;
+    }
+
+out:
+    fclose(f);
+    return;
+
+write_err:
+    error_setg(errp, "failed to write to file '%s': %s", filename,
+               strerror(errno));
+    unlink(filename);
+    goto out;
+}
+
+static Property tcx_properties[] = {
+    DEFINE_PROP_HEX32("vram_size", TCXState, vram_size, -1),
+    DEFINE_PROP_UINT16("width",    TCXState, width,     -1),
+    DEFINE_PROP_UINT16("height",   TCXState, height,    -1),
+    DEFINE_PROP_UINT16("depth",    TCXState, depth,     -1),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void tcx_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = tcx_init1;
+    dc->reset = tcx_reset;
+    dc->vmsd = &vmstate_tcx;
+    dc->props = tcx_properties;
+}
+
+static const TypeInfo tcx_info = {
+    .name          = "SUNW,tcx",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(TCXState),
+    .class_init    = tcx_class_init,
+};
+
+static void tcx_register_types(void)
+{
+    type_register_static(&tcx_info);
+}
+
+type_init(tcx_register_types)
diff --git a/hw/display/vga-isa-mm.c b/hw/display/vga-isa-mm.c
new file mode 100644 (file)
index 0000000..1c50070
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * QEMU ISA MM VGA Emulator.
+ *
+ * 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.
+ */
+#include "hw/hw.h"
+#include "ui/console.h"
+#include "hw/i386/pc.h"
+#include "vga_int.h"
+#include "ui/pixel_ops.h"
+#include "qemu/timer.h"
+
+#define VGA_RAM_SIZE (8192 * 1024)
+
+typedef struct ISAVGAMMState {
+    VGACommonState vga;
+    int it_shift;
+} ISAVGAMMState;
+
+/* Memory mapped interface */
+static uint32_t vga_mm_readb (void *opaque, hwaddr addr)
+{
+    ISAVGAMMState *s = opaque;
+
+    return vga_ioport_read(&s->vga, addr >> s->it_shift) & 0xff;
+}
+
+static void vga_mm_writeb (void *opaque,
+                           hwaddr addr, uint32_t value)
+{
+    ISAVGAMMState *s = opaque;
+
+    vga_ioport_write(&s->vga, addr >> s->it_shift, value & 0xff);
+}
+
+static uint32_t vga_mm_readw (void *opaque, hwaddr addr)
+{
+    ISAVGAMMState *s = opaque;
+
+    return vga_ioport_read(&s->vga, addr >> s->it_shift) & 0xffff;
+}
+
+static void vga_mm_writew (void *opaque,
+                           hwaddr addr, uint32_t value)
+{
+    ISAVGAMMState *s = opaque;
+
+    vga_ioport_write(&s->vga, addr >> s->it_shift, value & 0xffff);
+}
+
+static uint32_t vga_mm_readl (void *opaque, hwaddr addr)
+{
+    ISAVGAMMState *s = opaque;
+
+    return vga_ioport_read(&s->vga, addr >> s->it_shift);
+}
+
+static void vga_mm_writel (void *opaque,
+                           hwaddr addr, uint32_t value)
+{
+    ISAVGAMMState *s = opaque;
+
+    vga_ioport_write(&s->vga, addr >> s->it_shift, value);
+}
+
+static const MemoryRegionOps vga_mm_ctrl_ops = {
+    .old_mmio = {
+        .read = {
+            vga_mm_readb,
+            vga_mm_readw,
+            vga_mm_readl,
+        },
+        .write = {
+            vga_mm_writeb,
+            vga_mm_writew,
+            vga_mm_writel,
+        },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void vga_mm_init(ISAVGAMMState *s, hwaddr vram_base,
+                        hwaddr ctrl_base, int it_shift,
+                        MemoryRegion *address_space)
+{
+    MemoryRegion *s_ioport_ctrl, *vga_io_memory;
+
+    s->it_shift = it_shift;
+    s_ioport_ctrl = g_malloc(sizeof(*s_ioport_ctrl));
+    memory_region_init_io(s_ioport_ctrl, &vga_mm_ctrl_ops, s,
+                          "vga-mm-ctrl", 0x100000);
+    memory_region_set_flush_coalesced(s_ioport_ctrl);
+
+    vga_io_memory = g_malloc(sizeof(*vga_io_memory));
+    /* XXX: endianness? */
+    memory_region_init_io(vga_io_memory, &vga_mem_ops, &s->vga,
+                          "vga-mem", 0x20000);
+
+    vmstate_register(NULL, 0, &vmstate_vga_common, s);
+
+    memory_region_add_subregion(address_space, ctrl_base, s_ioport_ctrl);
+    s->vga.bank_offset = 0;
+    memory_region_add_subregion(address_space,
+                                vram_base + 0x000a0000, vga_io_memory);
+    memory_region_set_coalescing(vga_io_memory);
+}
+
+int isa_vga_mm_init(hwaddr vram_base,
+                    hwaddr ctrl_base, int it_shift,
+                    MemoryRegion *address_space)
+{
+    ISAVGAMMState *s;
+
+    s = g_malloc0(sizeof(*s));
+
+    s->vga.vram_size_mb = VGA_RAM_SIZE >> 20;
+    vga_common_init(&s->vga);
+    vga_mm_init(s, vram_base, ctrl_base, it_shift, address_space);
+
+    s->vga.con = graphic_console_init(s->vga.update, s->vga.invalidate,
+                                      s->vga.screen_dump, s->vga.text_update,
+                                      s);
+
+    vga_init_vbe(&s->vga, address_space);
+    return 0;
+}
diff --git a/hw/display/vga-isa.c b/hw/display/vga-isa.c
new file mode 100644 (file)
index 0000000..90959eb
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * QEMU ISA VGA Emulator.
+ *
+ * see docs/specs/standard-vga.txt for virtual hardware specs.
+ *
+ * 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.
+ */
+#include "hw/hw.h"
+#include "ui/console.h"
+#include "hw/i386/pc.h"
+#include "vga_int.h"
+#include "ui/pixel_ops.h"
+#include "qemu/timer.h"
+#include "hw/loader.h"
+
+typedef struct ISAVGAState {
+    ISADevice dev;
+    struct VGACommonState state;
+} ISAVGAState;
+
+static void vga_reset_isa(DeviceState *dev)
+{
+    ISAVGAState *d = container_of(dev, ISAVGAState, dev.qdev);
+    VGACommonState *s = &d->state;
+
+    vga_common_reset(s);
+}
+
+static int vga_initfn(ISADevice *dev)
+{
+    ISAVGAState *d = DO_UPCAST(ISAVGAState, dev, dev);
+    VGACommonState *s = &d->state;
+    MemoryRegion *vga_io_memory;
+    const MemoryRegionPortio *vga_ports, *vbe_ports;
+
+    vga_common_init(s);
+    s->legacy_address_space = isa_address_space(dev);
+    vga_io_memory = vga_init_io(s, &vga_ports, &vbe_ports);
+    isa_register_portio_list(dev, 0x3b0, vga_ports, s, "vga");
+    if (vbe_ports) {
+        isa_register_portio_list(dev, 0x1ce, vbe_ports, s, "vbe");
+    }
+    memory_region_add_subregion_overlap(isa_address_space(dev),
+                                        isa_mem_base + 0x000a0000,
+                                        vga_io_memory, 1);
+    memory_region_set_coalescing(vga_io_memory);
+    s->con = graphic_console_init(s->update, s->invalidate,
+                                  s->screen_dump, s->text_update, s);
+
+    vga_init_vbe(s, isa_address_space(dev));
+    /* ROM BIOS */
+    rom_add_vga(VGABIOS_FILENAME);
+    return 0;
+}
+
+static Property vga_isa_properties[] = {
+    DEFINE_PROP_UINT32("vgamem_mb", ISAVGAState, state.vram_size_mb, 8),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+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;
+    dc->props = vga_isa_properties;
+}
+
+static const TypeInfo vga_info = {
+    .name          = "isa-vga",
+    .parent        = TYPE_ISA_DEVICE,
+    .instance_size = sizeof(ISAVGAState),
+    .class_init    = vga_class_initfn,
+};
+
+static void vga_register_types(void)
+{
+    type_register_static(&vga_info);
+}
+
+type_init(vga_register_types)
diff --git a/hw/display/vga-pci.c b/hw/display/vga-pci.c
new file mode 100644 (file)
index 0000000..a9c69b6
--- /dev/null
@@ -0,0 +1,215 @@
+/*
+ * QEMU PCI VGA Emulator.
+ *
+ * see docs/specs/standard-vga.txt for virtual hardware specs.
+ *
+ * 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.
+ */
+#include "hw/hw.h"
+#include "ui/console.h"
+#include "hw/pci/pci.h"
+#include "vga_int.h"
+#include "ui/pixel_ops.h"
+#include "qemu/timer.h"
+#include "hw/loader.h"
+
+#define PCI_VGA_IOPORT_OFFSET 0x400
+#define PCI_VGA_IOPORT_SIZE   (0x3e0 - 0x3c0)
+#define PCI_VGA_BOCHS_OFFSET  0x500
+#define PCI_VGA_BOCHS_SIZE    (0x0b * 2)
+#define PCI_VGA_MMIO_SIZE     0x1000
+
+enum vga_pci_flags {
+    PCI_VGA_FLAG_ENABLE_MMIO = 1,
+};
+
+typedef struct PCIVGAState {
+    PCIDevice dev;
+    VGACommonState vga;
+    uint32_t flags;
+    MemoryRegion mmio;
+    MemoryRegion ioport;
+    MemoryRegion bochs;
+} PCIVGAState;
+
+static const VMStateDescription vmstate_vga_pci = {
+    .name = "vga",
+    .version_id = 2,
+    .minimum_version_id = 2,
+    .minimum_version_id_old = 2,
+    .fields      = (VMStateField []) {
+        VMSTATE_PCI_DEVICE(dev, PCIVGAState),
+        VMSTATE_STRUCT(vga, PCIVGAState, 0, vmstate_vga_common, VGACommonState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static uint64_t pci_vga_ioport_read(void *ptr, hwaddr addr,
+                                    unsigned size)
+{
+    PCIVGAState *d = ptr;
+    uint64_t ret = 0;
+
+    switch (size) {
+    case 1:
+        ret = vga_ioport_read(&d->vga, addr);
+        break;
+    case 2:
+        ret  = vga_ioport_read(&d->vga, addr);
+        ret |= vga_ioport_read(&d->vga, addr+1) << 8;
+        break;
+    }
+    return ret;
+}
+
+static void pci_vga_ioport_write(void *ptr, hwaddr addr,
+                                 uint64_t val, unsigned size)
+{
+    PCIVGAState *d = ptr;
+
+    switch (size) {
+    case 1:
+        vga_ioport_write(&d->vga, addr + 0x3c0, val);
+        break;
+    case 2:
+        /*
+         * Update bytes in little endian order.  Allows to update
+         * indexed registers with a single word write because the
+         * index byte is updated first.
+         */
+        vga_ioport_write(&d->vga, addr + 0x3c0, val & 0xff);
+        vga_ioport_write(&d->vga, addr + 0x3c1, (val >> 8) & 0xff);
+        break;
+    }
+}
+
+static const MemoryRegionOps pci_vga_ioport_ops = {
+    .read = pci_vga_ioport_read,
+    .write = pci_vga_ioport_write,
+    .valid.min_access_size = 1,
+    .valid.max_access_size = 4,
+    .impl.min_access_size = 1,
+    .impl.max_access_size = 2,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static uint64_t pci_vga_bochs_read(void *ptr, hwaddr addr,
+                                   unsigned size)
+{
+    PCIVGAState *d = ptr;
+    int index = addr >> 1;
+
+    vbe_ioport_write_index(&d->vga, 0, index);
+    return vbe_ioport_read_data(&d->vga, 0);
+}
+
+static void pci_vga_bochs_write(void *ptr, hwaddr addr,
+                                uint64_t val, unsigned size)
+{
+    PCIVGAState *d = ptr;
+    int index = addr >> 1;
+
+    vbe_ioport_write_index(&d->vga, 0, index);
+    vbe_ioport_write_data(&d->vga, 0, val);
+}
+
+static const MemoryRegionOps pci_vga_bochs_ops = {
+    .read = pci_vga_bochs_read,
+    .write = pci_vga_bochs_write,
+    .valid.min_access_size = 1,
+    .valid.max_access_size = 4,
+    .impl.min_access_size = 2,
+    .impl.max_access_size = 2,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static int pci_std_vga_initfn(PCIDevice *dev)
+{
+    PCIVGAState *d = DO_UPCAST(PCIVGAState, dev, dev);
+    VGACommonState *s = &d->vga;
+
+    /* vga + console init */
+    vga_common_init(s);
+    vga_init(s, pci_address_space(dev), pci_address_space_io(dev), true);
+
+    s->con = graphic_console_init(s->update, s->invalidate,
+                                  s->screen_dump, s->text_update, s);
+
+    /* XXX: VGA_RAM_SIZE must be a power of two */
+    pci_register_bar(&d->dev, 0, PCI_BASE_ADDRESS_MEM_PREFETCH, &s->vram);
+
+    /* mmio bar for vga register access */
+    if (d->flags & (1 << PCI_VGA_FLAG_ENABLE_MMIO)) {
+        memory_region_init(&d->mmio, "vga.mmio", 4096);
+        memory_region_init_io(&d->ioport, &pci_vga_ioport_ops, d,
+                              "vga ioports remapped", PCI_VGA_IOPORT_SIZE);
+        memory_region_init_io(&d->bochs, &pci_vga_bochs_ops, d,
+                              "bochs dispi interface", PCI_VGA_BOCHS_SIZE);
+
+        memory_region_add_subregion(&d->mmio, PCI_VGA_IOPORT_OFFSET,
+                                    &d->ioport);
+        memory_region_add_subregion(&d->mmio, PCI_VGA_BOCHS_OFFSET,
+                                    &d->bochs);
+        pci_register_bar(&d->dev, 2, PCI_BASE_ADDRESS_SPACE_MEMORY, &d->mmio);
+    }
+
+    if (!dev->rom_bar) {
+        /* compatibility with pc-0.13 and older */
+        vga_init_vbe(s, pci_address_space(dev));
+    }
+
+    return 0;
+}
+
+static Property vga_pci_properties[] = {
+    DEFINE_PROP_UINT32("vgamem_mb", PCIVGAState, vga.vram_size_mb, 16),
+    DEFINE_PROP_BIT("mmio", PCIVGAState, flags, PCI_VGA_FLAG_ENABLE_MMIO, true),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void vga_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->no_hotplug = 1;
+    k->init = pci_std_vga_initfn;
+    k->romfile = "vgabios-stdvga.bin";
+    k->vendor_id = PCI_VENDOR_ID_QEMU;
+    k->device_id = PCI_DEVICE_ID_QEMU_VGA;
+    k->class_id = PCI_CLASS_DISPLAY_VGA;
+    dc->vmsd = &vmstate_vga_pci;
+    dc->props = vga_pci_properties;
+}
+
+static const TypeInfo vga_info = {
+    .name          = "VGA",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PCIVGAState),
+    .class_init    = vga_class_init,
+};
+
+static void vga_register_types(void)
+{
+    type_register_static(&vga_info);
+}
+
+type_init(vga_register_types)
diff --git a/hw/display/vga.c b/hw/display/vga.c
new file mode 100644 (file)
index 0000000..c1b67bb
--- /dev/null
@@ -0,0 +1,2457 @@
+/*
+ * QEMU VGA Emulator.
+ *
+ * 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.
+ */
+#include "hw/hw.h"
+#include "vga.h"
+#include "ui/console.h"
+#include "hw/i386/pc.h"
+#include "hw/pci/pci.h"
+#include "vga_int.h"
+#include "ui/pixel_ops.h"
+#include "qemu/timer.h"
+#include "hw/xen/xen.h"
+#include "trace.h"
+
+//#define DEBUG_VGA
+//#define DEBUG_VGA_MEM
+//#define DEBUG_VGA_REG
+
+//#define DEBUG_BOCHS_VBE
+
+/* 16 state changes per vertical frame @60 Hz */
+#define VGA_TEXT_CURSOR_PERIOD_MS       (1000 * 2 * 16 / 60)
+
+/*
+ * 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,
+    0x3d,
+    0x0f,
+    0x3f,
+    0x0e,
+    0x00,
+    0x00,
+    0xff,
+};
+
+const uint8_t gr_mask[16] = {
+    0x0f, /* 0x00 */
+    0x0f, /* 0x01 */
+    0x0f, /* 0x02 */
+    0x1f, /* 0x03 */
+    0x03, /* 0x04 */
+    0x7b, /* 0x05 */
+    0x0f, /* 0x06 */
+    0x0f, /* 0x07 */
+    0xff, /* 0x08 */
+    0x00, /* 0x09 */
+    0x00, /* 0x0a */
+    0x00, /* 0x0b */
+    0x00, /* 0x0c */
+    0x00, /* 0x0d */
+    0x00, /* 0x0e */
+    0x00, /* 0x0f */
+};
+
+#define cbswap_32(__x) \
+((uint32_t)( \
+               (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
+               (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) <<  8) | \
+               (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >>  8) | \
+               (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
+
+#ifdef HOST_WORDS_BIGENDIAN
+#define PAT(x) cbswap_32(x)
+#else
+#define PAT(x) (x)
+#endif
+
+#ifdef HOST_WORDS_BIGENDIAN
+#define BIG 1
+#else
+#define BIG 0
+#endif
+
+#ifdef HOST_WORDS_BIGENDIAN
+#define GET_PLANE(data, p) (((data) >> (24 - (p) * 8)) & 0xff)
+#else
+#define GET_PLANE(data, p) (((data) >> ((p) * 8)) & 0xff)
+#endif
+
+static const uint32_t mask16[16] = {
+    PAT(0x00000000),
+    PAT(0x000000ff),
+    PAT(0x0000ff00),
+    PAT(0x0000ffff),
+    PAT(0x00ff0000),
+    PAT(0x00ff00ff),
+    PAT(0x00ffff00),
+    PAT(0x00ffffff),
+    PAT(0xff000000),
+    PAT(0xff0000ff),
+    PAT(0xff00ff00),
+    PAT(0xff00ffff),
+    PAT(0xffff0000),
+    PAT(0xffff00ff),
+    PAT(0xffffff00),
+    PAT(0xffffffff),
+};
+
+#undef PAT
+
+#ifdef HOST_WORDS_BIGENDIAN
+#define PAT(x) (x)
+#else
+#define PAT(x) cbswap_32(x)
+#endif
+
+static const uint32_t dmask16[16] = {
+    PAT(0x00000000),
+    PAT(0x000000ff),
+    PAT(0x0000ff00),
+    PAT(0x0000ffff),
+    PAT(0x00ff0000),
+    PAT(0x00ff00ff),
+    PAT(0x00ffff00),
+    PAT(0x00ffffff),
+    PAT(0xff000000),
+    PAT(0xff0000ff),
+    PAT(0xff00ff00),
+    PAT(0xff00ffff),
+    PAT(0xffff0000),
+    PAT(0xffff00ff),
+    PAT(0xffffff00),
+    PAT(0xffffffff),
+};
+
+static const uint32_t dmask4[4] = {
+    PAT(0x00000000),
+    PAT(0x0000ffff),
+    PAT(0xffff0000),
+    PAT(0xffffffff),
+};
+
+static uint32_t expand4[256];
+static uint16_t expand2[256];
+static uint8_t expand4to8[16];
+
+static void vga_screen_dump(void *opaque, const char *filename, bool cswitch,
+                            Error **errp);
+
+static void vga_update_memory_access(VGACommonState *s)
+{
+    MemoryRegion *region, *old_region = s->chain4_alias;
+    hwaddr base, offset, size;
+
+    s->chain4_alias = NULL;
+
+    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[VGA_GFX_MISC] >> 2) & 3) {
+        case 0:
+            base = 0xa0000;
+            size = 0x20000;
+            break;
+        case 1:
+            base = 0xa0000;
+            size = 0x10000;
+            offset = s->bank_offset;
+            break;
+        case 2:
+            base = 0xb0000;
+            size = 0x8000;
+            break;
+        case 3:
+        default:
+            base = 0xb8000;
+            size = 0x8000;
+            break;
+        }
+        base += isa_mem_base;
+        region = g_malloc(sizeof(*region));
+        memory_region_init_alias(region, "vga.chain4", &s->vram, offset, size);
+        memory_region_add_subregion_overlap(s->legacy_address_space, base,
+                                            region, 2);
+        s->chain4_alias = region;
+    }
+    if (old_region) {
+        memory_region_del_subregion(s->legacy_address_space, old_region);
+        memory_region_destroy(old_region);
+        g_free(old_region);
+        s->plane_updated = 0xf;
+    }
+}
+
+static void vga_dumb_update_retrace_info(VGACommonState *s)
+{
+    (void) s;
+}
+
+static void vga_precise_update_retrace_info(VGACommonState *s)
+{
+    int htotal_chars;
+    int hretr_start_char;
+    int hretr_skew_chars;
+    int hretr_end_char;
+
+    int vtotal_lines;
+    int vretr_start_line;
+    int vretr_end_line;
+
+    int dots;
+#if 0
+    int div2, sldiv2;
+#endif
+    int clocking_mode;
+    int clock_sel;
+    const int clk_hz[] = {25175000, 28322000, 25175000, 25175000};
+    int64_t chars_per_sec;
+    struct vga_precise_retrace *r = &s->retrace_info.precise;
+
+    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[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[VGA_SEQ_CLOCK_MODE] >> 3) & 1;
+    clock_sel = (s->msr >> 2) & 3;
+    dots = (s->msr & 1) ? 8 : 9;
+
+    chars_per_sec = clk_hz[clock_sel] / dots;
+
+    htotal_chars <<= clocking_mode;
+
+    r->total_chars = vtotal_lines * htotal_chars;
+    if (r->freq) {
+        r->ticks_per_char = get_ticks_per_sec() / (r->total_chars * r->freq);
+    } else {
+        r->ticks_per_char = get_ticks_per_sec() / chars_per_sec;
+    }
+
+    r->vstart = vretr_start_line;
+    r->vend = r->vstart + vretr_end_line + 1;
+
+    r->hstart = hretr_start_char + hretr_skew_chars;
+    r->hend = r->hstart + hretr_end_char + 1;
+    r->htotal = htotal_chars;
+
+#if 0
+    div2 = (s->cr[VGA_CRTC_MODE] >> 2) & 1;
+    sldiv2 = (s->cr[VGA_CRTC_MODE] >> 3) & 1;
+    printf (
+        "hz=%f\n"
+        "htotal = %d\n"
+        "hretr_start = %d\n"
+        "hretr_skew = %d\n"
+        "hretr_end = %d\n"
+        "vtotal = %d\n"
+        "vretr_start = %d\n"
+        "vretr_end = %d\n"
+        "div2 = %d sldiv2 = %d\n"
+        "clocking_mode = %d\n"
+        "clock_sel = %d %d\n"
+        "dots = %d\n"
+        "ticks/char = %" PRId64 "\n"
+        "\n",
+        (double) get_ticks_per_sec() / (r->ticks_per_char * r->total_chars),
+        htotal_chars,
+        hretr_start_char,
+        hretr_skew_chars,
+        hretr_end_char,
+        vtotal_lines,
+        vretr_start_line,
+        vretr_end_line,
+        div2, sldiv2,
+        clocking_mode,
+        clock_sel,
+        clk_hz[clock_sel],
+        dots,
+        r->ticks_per_char
+        );
+#endif
+}
+
+static uint8_t vga_precise_retrace(VGACommonState *s)
+{
+    struct vga_precise_retrace *r = &s->retrace_info.precise;
+    uint8_t val = s->st01 & ~(ST01_V_RETRACE | ST01_DISP_ENABLE);
+
+    if (r->total_chars) {
+        int cur_line, cur_line_char, cur_char;
+        int64_t cur_tick;
+
+        cur_tick = qemu_get_clock_ns(vm_clock);
+
+        cur_char = (cur_tick / r->ticks_per_char) % r->total_chars;
+        cur_line = cur_char / r->htotal;
+
+        if (cur_line >= r->vstart && cur_line <= r->vend) {
+            val |= ST01_V_RETRACE | ST01_DISP_ENABLE;
+        } else {
+            cur_line_char = cur_char % r->htotal;
+            if (cur_line_char >= r->hstart && cur_line_char <= r->hend) {
+                val |= ST01_DISP_ENABLE;
+            }
+        }
+
+        return val;
+    } else {
+        return s->st01 ^ (ST01_V_RETRACE | ST01_DISP_ENABLE);
+    }
+}
+
+static uint8_t vga_dumb_retrace(VGACommonState *s)
+{
+    return s->st01 ^ (ST01_V_RETRACE | ST01_DISP_ENABLE);
+}
+
+int vga_ioport_invalid(VGACommonState *s, uint32_t addr)
+{
+    if (s->msr & VGA_MIS_COLOR) {
+        /* Color */
+        return (addr >= 0x3b0 && addr <= 0x3bf);
+    } else {
+        /* Monochrome */
+        return (addr >= 0x3d0 && addr <= 0x3df);
+    }
+}
+
+uint32_t vga_ioport_read(void *opaque, uint32_t addr)
+{
+    VGACommonState *s = opaque;
+    int val, index;
+
+    qemu_flush_coalesced_mmio_buffer();
+
+    if (vga_ioport_invalid(s, addr)) {
+        val = 0xff;
+    } else {
+        switch(addr) {
+        case VGA_ATT_W:
+            if (s->ar_flip_flop == 0) {
+                val = s->ar_index;
+            } else {
+                val = 0;
+            }
+            break;
+        case VGA_ATT_R:
+            index = s->ar_index & 0x1f;
+            if (index < VGA_ATT_C) {
+                val = s->ar[index];
+            } else {
+                val = 0;
+            }
+            break;
+        case VGA_MIS_W:
+            val = s->st00;
+            break;
+        case VGA_SEQ_I:
+            val = s->sr_index;
+            break;
+        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 VGA_PEL_IR:
+            val = s->dac_state;
+            break;
+        case VGA_PEL_IW:
+            val = s->dac_write_index;
+            break;
+        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 VGA_FTC_R:
+            val = s->fcr;
+            break;
+        case VGA_MIS_R:
+            val = s->msr;
+            break;
+        case VGA_GFX_I:
+            val = s->gr_index;
+            break;
+        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 VGA_CRT_IM:
+        case VGA_CRT_IC:
+            val = s->cr_index;
+            break;
+        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 VGA_IS1_RM:
+        case VGA_IS1_RC:
+            /* just toggle to fool polling */
+            val = s->st01 = s->retrace(s);
+            s->ar_flip_flop = 0;
+            break;
+        default:
+            val = 0x00;
+            break;
+        }
+    }
+#if defined(DEBUG_VGA)
+    printf("VGA: read addr=0x%04x data=0x%02x\n", addr, val);
+#endif
+    return val;
+}
+
+void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
+{
+    VGACommonState *s = opaque;
+    int index;
+
+    qemu_flush_coalesced_mmio_buffer();
+
+    /* check port range access depending on color/monochrome mode */
+    if (vga_ioport_invalid(s, addr)) {
+        return;
+    }
+#ifdef DEBUG_VGA
+    printf("VGA: write addr=0x%04x data=0x%02x\n", addr, val);
+#endif
+
+    switch(addr) {
+    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 VGA_ATC_PALETTE0 ... VGA_ATC_PALETTEF:
+                s->ar[index] = val & 0x3f;
+                break;
+            case VGA_ATC_MODE:
+                s->ar[index] = val & ~0x10;
+                break;
+            case VGA_ATC_OVERSCAN:
+                s->ar[index] = val;
+                break;
+            case VGA_ATC_PLANE_ENABLE:
+                s->ar[index] = val & ~0xc0;
+                break;
+            case VGA_ATC_PEL:
+                s->ar[index] = val & ~0xf0;
+                break;
+            case VGA_ATC_COLOR_PAGE:
+                s->ar[index] = val & ~0xf0;
+                break;
+            default:
+                break;
+            }
+        }
+        s->ar_flip_flop ^= 1;
+        break;
+    case VGA_MIS_W:
+        s->msr = val & ~0x10;
+        s->update_retrace_info(s);
+        break;
+    case VGA_SEQ_I:
+        s->sr_index = val & 7;
+        break;
+    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 == VGA_SEQ_CLOCK_MODE) {
+            s->update_retrace_info(s);
+        }
+        vga_update_memory_access(s);
+        break;
+    case VGA_PEL_IR:
+        s->dac_read_index = val;
+        s->dac_sub_index = 0;
+        s->dac_state = 3;
+        break;
+    case VGA_PEL_IW:
+        s->dac_write_index = val;
+        s->dac_sub_index = 0;
+        s->dac_state = 0;
+        break;
+    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);
+            s->dac_sub_index = 0;
+            s->dac_write_index++;
+        }
+        break;
+    case VGA_GFX_I:
+        s->gr_index = val & 0x0f;
+        break;
+    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 VGA_CRT_IM:
+    case VGA_CRT_IC:
+        s->cr_index = val;
+        break;
+    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[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 == 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 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 VGA_IS1_RM:
+    case VGA_IS1_RC:
+        s->fcr = val & 0x10;
+        break;
+    }
+}
+
+static uint32_t vbe_ioport_read_index(void *opaque, uint32_t addr)
+{
+    VGACommonState *s = opaque;
+    uint32_t val;
+    val = s->vbe_index;
+    return val;
+}
+
+uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr)
+{
+    VGACommonState *s = opaque;
+    uint32_t val;
+
+    if (s->vbe_index < VBE_DISPI_INDEX_NB) {
+        if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_GETCAPS) {
+            switch(s->vbe_index) {
+                /* XXX: do not hardcode ? */
+            case VBE_DISPI_INDEX_XRES:
+                val = VBE_DISPI_MAX_XRES;
+                break;
+            case VBE_DISPI_INDEX_YRES:
+                val = VBE_DISPI_MAX_YRES;
+                break;
+            case VBE_DISPI_INDEX_BPP:
+                val = VBE_DISPI_MAX_BPP;
+                break;
+            default:
+                val = s->vbe_regs[s->vbe_index];
+                break;
+            }
+        } else {
+            val = s->vbe_regs[s->vbe_index];
+        }
+    } else if (s->vbe_index == VBE_DISPI_INDEX_VIDEO_MEMORY_64K) {
+        val = s->vram_size / (64 * 1024);
+    } else {
+        val = 0;
+    }
+#ifdef DEBUG_BOCHS_VBE
+    printf("VBE: read index=0x%x val=0x%x\n", s->vbe_index, val);
+#endif
+    return val;
+}
+
+void vbe_ioport_write_index(void *opaque, uint32_t addr, uint32_t val)
+{
+    VGACommonState *s = opaque;
+    s->vbe_index = val;
+}
+
+void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
+{
+    VGACommonState *s = opaque;
+
+    if (s->vbe_index <= VBE_DISPI_INDEX_NB) {
+#ifdef DEBUG_BOCHS_VBE
+        printf("VBE: write index=0x%x val=0x%x\n", s->vbe_index, val);
+#endif
+        switch(s->vbe_index) {
+        case VBE_DISPI_INDEX_ID:
+            if (val == VBE_DISPI_ID0 ||
+                val == VBE_DISPI_ID1 ||
+                val == VBE_DISPI_ID2 ||
+                val == VBE_DISPI_ID3 ||
+                val == VBE_DISPI_ID4) {
+                s->vbe_regs[s->vbe_index] = val;
+            }
+            break;
+        case VBE_DISPI_INDEX_XRES:
+            if ((val <= VBE_DISPI_MAX_XRES) && ((val & 7) == 0)) {
+                s->vbe_regs[s->vbe_index] = val;
+            }
+            break;
+        case VBE_DISPI_INDEX_YRES:
+            if (val <= VBE_DISPI_MAX_YRES) {
+                s->vbe_regs[s->vbe_index] = val;
+            }
+            break;
+        case VBE_DISPI_INDEX_BPP:
+            if (val == 0)
+                val = 8;
+            if (val == 4 || val == 8 || val == 15 ||
+                val == 16 || val == 24 || val == 32) {
+                s->vbe_regs[s->vbe_index] = val;
+            }
+            break;
+        case VBE_DISPI_INDEX_BANK:
+            if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
+              val &= (s->vbe_bank_mask >> 2);
+            } else {
+              val &= s->vbe_bank_mask;
+            }
+            s->vbe_regs[s->vbe_index] = val;
+            s->bank_offset = (val << 16);
+            vga_update_memory_access(s);
+            break;
+        case VBE_DISPI_INDEX_ENABLE:
+            if ((val & VBE_DISPI_ENABLED) &&
+                !(s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
+                int h, shift_control;
+
+                s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] =
+                    s->vbe_regs[VBE_DISPI_INDEX_XRES];
+                s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] =
+                    s->vbe_regs[VBE_DISPI_INDEX_YRES];
+                s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] = 0;
+                s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] = 0;
+
+                if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
+                    s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 1;
+                else
+                    s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] *
+                        ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
+                s->vbe_start_addr = 0;
+
+                /* clear the screen (should be done in BIOS) */
+                if (!(val & VBE_DISPI_NOCLEARMEM)) {
+                    memset(s->vram_ptr, 0,
+                           s->vbe_regs[VBE_DISPI_INDEX_YRES] * s->vbe_line_offset);
+                }
+
+                /* we initialize the VGA graphic mode (should be done
+                   in BIOS) */
+                /* 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[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[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[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[VGA_SEQ_CLOCK_MODE] &= ~8; /* no double line */
+                } else {
+                    shift_control = 2;
+                    /* 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[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;
+            }
+            s->dac_8bit = (val & VBE_DISPI_8BIT_DAC) > 0;
+            s->vbe_regs[s->vbe_index] = val;
+            vga_update_memory_access(s);
+            break;
+        case VBE_DISPI_INDEX_VIRT_WIDTH:
+            {
+                int w, h, line_offset;
+
+                if (val < s->vbe_regs[VBE_DISPI_INDEX_XRES])
+                    return;
+                w = val;
+                if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
+                    line_offset = w >> 1;
+                else
+                    line_offset = w * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
+                h = s->vram_size / line_offset;
+                /* XXX: support weird bochs semantics ? */
+                if (h < s->vbe_regs[VBE_DISPI_INDEX_YRES])
+                    return;
+                s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = w;
+                s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] = h;
+                s->vbe_line_offset = line_offset;
+            }
+            break;
+        case VBE_DISPI_INDEX_X_OFFSET:
+        case VBE_DISPI_INDEX_Y_OFFSET:
+            {
+                int x;
+                s->vbe_regs[s->vbe_index] = val;
+                s->vbe_start_addr = s->vbe_line_offset * s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET];
+                x = s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET];
+                if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
+                    s->vbe_start_addr += x >> 1;
+                else
+                    s->vbe_start_addr += x * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
+                s->vbe_start_addr >>= 2;
+            }
+            break;
+        default:
+            break;
+        }
+    }
+}
+
+/* called for accesses between 0xa0000 and 0xc0000 */
+uint32_t vga_mem_readb(VGACommonState *s, hwaddr addr)
+{
+    int memory_map_mode, plane;
+    uint32_t ret;
+
+    /* convert to VGA memory offset */
+    memory_map_mode = (s->gr[VGA_GFX_MISC] >> 2) & 3;
+    addr &= 0x1ffff;
+    switch(memory_map_mode) {
+    case 0:
+        break;
+    case 1:
+        if (addr >= 0x10000)
+            return 0xff;
+        addr += s->bank_offset;
+        break;
+    case 2:
+        addr -= 0x10000;
+        if (addr >= 0x8000)
+            return 0xff;
+        break;
+    default:
+    case 3:
+        addr -= 0x18000;
+        if (addr >= 0x8000)
+            return 0xff;
+        break;
+    }
+
+    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[VGA_GFX_MODE] & 0x10) {
+        /* odd/even mode (aka text mode mapping) */
+        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[VGA_GFX_MODE] & 0x08)) {
+            /* read mode 0 */
+            plane = s->gr[VGA_GFX_PLANE_READ];
+            ret = GET_PLANE(s->latch, plane);
+        } else {
+            /* read mode 1 */
+            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;
+        }
+    }
+    return ret;
+}
+
+/* called for accesses between 0xa0000 and 0xc0000 */
+void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val)
+{
+    int memory_map_mode, plane, write_mode, b, func_select, mask;
+    uint32_t write_mask, bit_mask, set_mask;
+
+#ifdef DEBUG_VGA_MEM
+    printf("vga: [0x" TARGET_FMT_plx "] = 0x%02x\n", addr, val);
+#endif
+    /* convert to VGA memory offset */
+    memory_map_mode = (s->gr[VGA_GFX_MISC] >> 2) & 3;
+    addr &= 0x1ffff;
+    switch(memory_map_mode) {
+    case 0:
+        break;
+    case 1:
+        if (addr >= 0x10000)
+            return;
+        addr += s->bank_offset;
+        break;
+    case 2:
+        addr -= 0x10000;
+        if (addr >= 0x8000)
+            return;
+        break;
+    default:
+    case 3:
+        addr -= 0x18000;
+        if (addr >= 0x8000)
+            return;
+        break;
+    }
+
+    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[VGA_SEQ_PLANE_WRITE] & mask) {
+            s->vram_ptr[addr] = val;
+#ifdef DEBUG_VGA_MEM
+            printf("vga: chain4: [0x" TARGET_FMT_plx "]\n", addr);
+#endif
+            s->plane_updated |= mask; /* only used to detect font change */
+            memory_region_set_dirty(&s->vram, addr, 1);
+        }
+    } else if (s->gr[VGA_GFX_MODE] & 0x10) {
+        /* odd/even mode (aka text mode mapping) */
+        plane = (s->gr[VGA_GFX_PLANE_READ] & 2) | (addr & 1);
+        mask = (1 << plane);
+        if (s->sr[VGA_SEQ_PLANE_WRITE] & mask) {
+            addr = ((addr & ~1) << 1) | plane;
+            s->vram_ptr[addr] = val;
+#ifdef DEBUG_VGA_MEM
+            printf("vga: odd/even: [0x" TARGET_FMT_plx "]\n", addr);
+#endif
+            s->plane_updated |= mask; /* only used to detect font change */
+            memory_region_set_dirty(&s->vram, addr, 1);
+        }
+    } else {
+        /* standard VGA latched access */
+        write_mode = s->gr[VGA_GFX_MODE] & 3;
+        switch(write_mode) {
+        default:
+        case 0:
+            /* rotate */
+            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[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[VGA_GFX_BIT_MASK];
+            break;
+        case 3:
+            /* rotate */
+            b = s->gr[VGA_GFX_DATA_ROTATE] & 7;
+            val = (val >> b) | (val << (8 - b));
+
+            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[VGA_GFX_DATA_ROTATE] >> 3;
+        switch(func_select) {
+        case 0:
+        default:
+            /* nothing to do */
+            break;
+        case 1:
+            /* and */
+            val &= s->latch;
+            break;
+        case 2:
+            /* or */
+            val |= s->latch;
+            break;
+        case 3:
+            /* xor */
+            val ^= s->latch;
+            break;
+        }
+
+        /* apply bit mask */
+        bit_mask |= bit_mask << 8;
+        bit_mask |= bit_mask << 16;
+        val = (val & bit_mask) | (s->latch & ~bit_mask);
+
+    do_write:
+        /* mask data according to 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] =
+            (((uint32_t *)s->vram_ptr)[addr] & ~write_mask) |
+            (val & write_mask);
+#ifdef DEBUG_VGA_MEM
+        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, sizeof(uint32_t));
+    }
+}
+
+typedef void vga_draw_glyph8_func(uint8_t *d, int linesize,
+                             const uint8_t *font_ptr, int h,
+                             uint32_t fgcol, uint32_t bgcol);
+typedef void vga_draw_glyph9_func(uint8_t *d, int linesize,
+                                  const uint8_t *font_ptr, int h,
+                                  uint32_t fgcol, uint32_t bgcol, int dup9);
+typedef void vga_draw_line_func(VGACommonState *s1, uint8_t *d,
+                                const uint8_t *s, int width);
+
+#define DEPTH 8
+#include "vga_template.h"
+
+#define DEPTH 15
+#include "vga_template.h"
+
+#define BGR_FORMAT
+#define DEPTH 15
+#include "vga_template.h"
+
+#define DEPTH 16
+#include "vga_template.h"
+
+#define BGR_FORMAT
+#define DEPTH 16
+#include "vga_template.h"
+
+#define DEPTH 32
+#include "vga_template.h"
+
+#define BGR_FORMAT
+#define DEPTH 32
+#include "vga_template.h"
+
+static unsigned int rgb_to_pixel8_dup(unsigned int r, unsigned int g, unsigned b)
+{
+    unsigned int col;
+    col = rgb_to_pixel8(r, g, b);
+    col |= col << 8;
+    col |= col << 16;
+    return col;
+}
+
+static unsigned int rgb_to_pixel15_dup(unsigned int r, unsigned int g, unsigned b)
+{
+    unsigned int col;
+    col = rgb_to_pixel15(r, g, b);
+    col |= col << 16;
+    return col;
+}
+
+static unsigned int rgb_to_pixel15bgr_dup(unsigned int r, unsigned int g,
+                                          unsigned int b)
+{
+    unsigned int col;
+    col = rgb_to_pixel15bgr(r, g, b);
+    col |= col << 16;
+    return col;
+}
+
+static unsigned int rgb_to_pixel16_dup(unsigned int r, unsigned int g, unsigned b)
+{
+    unsigned int col;
+    col = rgb_to_pixel16(r, g, b);
+    col |= col << 16;
+    return col;
+}
+
+static unsigned int rgb_to_pixel16bgr_dup(unsigned int r, unsigned int g,
+                                          unsigned int b)
+{
+    unsigned int col;
+    col = rgb_to_pixel16bgr(r, g, b);
+    col |= col << 16;
+    return col;
+}
+
+static unsigned int rgb_to_pixel32_dup(unsigned int r, unsigned int g, unsigned b)
+{
+    unsigned int col;
+    col = rgb_to_pixel32(r, g, b);
+    return col;
+}
+
+static unsigned int rgb_to_pixel32bgr_dup(unsigned int r, unsigned int g, unsigned b)
+{
+    unsigned int col;
+    col = rgb_to_pixel32bgr(r, g, b);
+    return col;
+}
+
+/* return true if the palette was modified */
+static int update_palette16(VGACommonState *s)
+{
+    int full_update, i;
+    uint32_t v, col, *palette;
+
+    full_update = 0;
+    palette = s->last_palette;
+    for(i = 0; i < 16; i++) {
+        v = s->ar[i];
+        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]),
+                              c6_to_8(s->palette[v + 2]));
+        if (col != palette[i]) {
+            full_update = 1;
+            palette[i] = col;
+        }
+    }
+    return full_update;
+}
+
+/* return true if the palette was modified */
+static int update_palette256(VGACommonState *s)
+{
+    int full_update, i;
+    uint32_t v, col, *palette;
+
+    full_update = 0;
+    palette = s->last_palette;
+    v = 0;
+    for(i = 0; i < 256; i++) {
+        if (s->dac_8bit) {
+          col = s->rgb_to_pixel(s->palette[v],
+                                s->palette[v + 1],
+                                s->palette[v + 2]);
+        } else {
+          col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
+                                c6_to_8(s->palette[v + 1]),
+                                c6_to_8(s->palette[v + 2]));
+        }
+        if (col != palette[i]) {
+            full_update = 1;
+            palette[i] = col;
+        }
+        v += 3;
+    }
+    return full_update;
+}
+
+static void vga_get_offsets(VGACommonState *s,
+                            uint32_t *pline_offset,
+                            uint32_t *pstart_addr,
+                            uint32_t *pline_compare)
+{
+    uint32_t start_addr, line_offset, line_compare;
+
+    if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
+        line_offset = s->vbe_line_offset;
+        start_addr = s->vbe_start_addr;
+        line_compare = 65535;
+    } else {
+        /* compute line_offset in bytes */
+        line_offset = s->cr[VGA_CRTC_OFFSET];
+        line_offset <<= 3;
+
+        /* starting address */
+        start_addr = s->cr[VGA_CRTC_START_LO] |
+            (s->cr[VGA_CRTC_START_HI] << 8);
+
+        /* line compare */
+        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;
+    *pline_compare = line_compare;
+}
+
+/* update start_addr and line_offset. Return TRUE if modified */
+static int update_basic_params(VGACommonState *s)
+{
+    int full_update;
+    uint32_t start_addr, line_offset, line_compare;
+
+    full_update = 0;
+
+    s->get_offsets(s, &line_offset, &start_addr, &line_compare);
+
+    if (line_offset != s->line_offset ||
+        start_addr != s->start_addr ||
+        line_compare != s->line_compare) {
+        s->line_offset = line_offset;
+        s->start_addr = start_addr;
+        s->line_compare = line_compare;
+        full_update = 1;
+    }
+    return full_update;
+}
+
+#define NB_DEPTHS 7
+
+static inline int get_depth_index(DisplaySurface *s)
+{
+    switch (surface_bits_per_pixel(s)) {
+    default:
+    case 8:
+        return 0;
+    case 15:
+        return 1;
+    case 16:
+        return 2;
+    case 32:
+        if (is_surface_bgr(s)) {
+            return 4;
+        } else {
+            return 3;
+        }
+    }
+}
+
+static vga_draw_glyph8_func * const vga_draw_glyph8_table[NB_DEPTHS] = {
+    vga_draw_glyph8_8,
+    vga_draw_glyph8_16,
+    vga_draw_glyph8_16,
+    vga_draw_glyph8_32,
+    vga_draw_glyph8_32,
+    vga_draw_glyph8_16,
+    vga_draw_glyph8_16,
+};
+
+static vga_draw_glyph8_func * const vga_draw_glyph16_table[NB_DEPTHS] = {
+    vga_draw_glyph16_8,
+    vga_draw_glyph16_16,
+    vga_draw_glyph16_16,
+    vga_draw_glyph16_32,
+    vga_draw_glyph16_32,
+    vga_draw_glyph16_16,
+    vga_draw_glyph16_16,
+};
+
+static vga_draw_glyph9_func * const vga_draw_glyph9_table[NB_DEPTHS] = {
+    vga_draw_glyph9_8,
+    vga_draw_glyph9_16,
+    vga_draw_glyph9_16,
+    vga_draw_glyph9_32,
+    vga_draw_glyph9_32,
+    vga_draw_glyph9_16,
+    vga_draw_glyph9_16,
+};
+
+static const uint8_t cursor_glyph[32 * 4] = {
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+};
+
+static void vga_get_text_resolution(VGACommonState *s, int *pwidth, int *pheight,
+                                    int *pcwidth, int *pcheight)
+{
+    int width, cwidth, height, cheight;
+
+    /* total width & height */
+    cheight = (s->cr[VGA_CRTC_MAX_SCAN] & 0x1f) + 1;
+    cwidth = 8;
+    if (!(s->sr[VGA_SEQ_CLOCK_MODE] & VGA_SR01_CHAR_CLK_8DOTS)) {
+        cwidth = 9;
+    }
+    if (s->sr[VGA_SEQ_CLOCK_MODE] & 0x08) {
+        cwidth = 16; /* NOTE: no 18 pixel wide */
+    }
+    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[VGA_CRTC_V_DISP_END] |
+            ((s->cr[VGA_CRTC_OVERFLOW] & 0x02) << 7) |
+            ((s->cr[VGA_CRTC_OVERFLOW] & 0x40) << 3);
+        height = (height + 1) / cheight;
+    }
+
+    *pwidth = width;
+    *pheight = height;
+    *pcwidth = cwidth;
+    *pcheight = cheight;
+}
+
+typedef unsigned int rgb_to_pixel_dup_func(unsigned int r, unsigned int g, unsigned b);
+
+static rgb_to_pixel_dup_func * const rgb_to_pixel_dup_table[NB_DEPTHS] = {
+    rgb_to_pixel8_dup,
+    rgb_to_pixel15_dup,
+    rgb_to_pixel16_dup,
+    rgb_to_pixel32_dup,
+    rgb_to_pixel32bgr_dup,
+    rgb_to_pixel15bgr_dup,
+    rgb_to_pixel16bgr_dup,
+};
+
+/*
+ * Text mode update
+ * Missing:
+ * - double scan
+ * - double width
+ * - underline
+ * - flashing
+ */
+static void vga_draw_text(VGACommonState *s, int full_update)
+{
+    DisplaySurface *surface = qemu_console_surface(s->con);
+    int cx, cy, cheight, cw, ch, cattr, height, width, ch_attr;
+    int cx_min, cx_max, linesize, x_incr, line, line1;
+    uint32_t offset, fgcol, bgcol, v, cursor_offset;
+    uint8_t *d1, *d, *src, *dest, *cursor_ptr;
+    const uint8_t *font_ptr, *font_base[2];
+    int dup9, line_offset, depth_index;
+    uint32_t *palette;
+    uint32_t *ch_attr_ptr;
+    vga_draw_glyph8_func *vga_draw_glyph8;
+    vga_draw_glyph9_func *vga_draw_glyph9;
+    int64_t now = qemu_get_clock_ms(vm_clock);
+
+    /* compute font data address (in plane 2) */
+    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;
+        full_update = 1;
+    }
+    font_base[0] = s->vram_ptr + offset;
+
+    offset = (((v >> 5) & 1) | ((v >> 1) & 6)) * 8192 * 4 + 2;
+    font_base[1] = s->vram_ptr + offset;
+    if (offset != s->font_offsets[1]) {
+        s->font_offsets[1] = offset;
+        full_update = 1;
+    }
+    if (s->plane_updated & (1 << 2) || s->chain4_alias) {
+        /* if the plane 2 was modified since the last display, it
+           indicates the font may have been modified */
+        s->plane_updated = 0;
+        full_update = 1;
+    }
+    full_update |= update_basic_params(s);
+
+    line_offset = s->line_offset;
+
+    vga_get_text_resolution(s, &width, &height, &cw, &cheight);
+    if ((height * width) <= 1) {
+        /* better than nothing: exit if transient size is too small */
+        return;
+    }
+    if ((height * width) > CH_ATTR_SIZE) {
+        /* better than nothing: exit if transient size is too big */
+        return;
+    }
+
+    if (width != s->last_width || height != s->last_height ||
+        cw != s->last_cw || cheight != s->last_ch || s->last_depth) {
+        s->last_scr_width = width * cw;
+        s->last_scr_height = height * cheight;
+        qemu_console_resize(s->con, s->last_scr_width, s->last_scr_height);
+        surface = qemu_console_surface(s->con);
+        dpy_text_resize(s->con, width, height);
+        s->last_depth = 0;
+        s->last_width = width;
+        s->last_height = height;
+        s->last_ch = cheight;
+        s->last_cw = cw;
+        full_update = 1;
+    }
+    s->rgb_to_pixel =
+        rgb_to_pixel_dup_table[get_depth_index(surface)];
+    full_update |= update_palette16(s);
+    palette = s->last_palette;
+    x_incr = cw * surface_bytes_per_pixel(surface);
+
+    if (full_update) {
+        s->full_update_text = 1;
+    }
+    if (s->full_update_gfx) {
+        s->full_update_gfx = 0;
+        full_update |= 1;
+    }
+
+    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[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)
+            s->last_ch_attr[s->cursor_offset] = -1;
+        if (cursor_offset < CH_ATTR_SIZE)
+            s->last_ch_attr[cursor_offset] = -1;
+        s->cursor_offset = cursor_offset;
+        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;
+    if (now >= s->cursor_blink_time) {
+        s->cursor_blink_time = now + VGA_TEXT_CURSOR_PERIOD_MS / 2;
+        s->cursor_visible_phase = !s->cursor_visible_phase;
+    }
+
+    depth_index = get_depth_index(surface);
+    if (cw == 16)
+        vga_draw_glyph8 = vga_draw_glyph16_table[depth_index];
+    else
+        vga_draw_glyph8 = vga_draw_glyph8_table[depth_index];
+    vga_draw_glyph9 = vga_draw_glyph9_table[depth_index];
+
+    dest = surface_data(surface);
+    linesize = surface_stride(surface);
+    ch_attr_ptr = s->last_ch_attr;
+    line = 0;
+    offset = s->start_addr * 4;
+    for(cy = 0; cy < height; cy++) {
+        d1 = dest;
+        src = s->vram_ptr + offset;
+        cx_min = width;
+        cx_max = -1;
+        for(cx = 0; cx < width; cx++) {
+            ch_attr = *(uint16_t *)src;
+            if (full_update || ch_attr != *ch_attr_ptr || src == cursor_ptr) {
+                if (cx < cx_min)
+                    cx_min = cx;
+                if (cx > cx_max)
+                    cx_max = cx;
+                *ch_attr_ptr = ch_attr;
+#ifdef HOST_WORDS_BIGENDIAN
+                ch = ch_attr >> 8;
+                cattr = ch_attr & 0xff;
+#else
+                ch = ch_attr & 0xff;
+                cattr = ch_attr >> 8;
+#endif
+                font_ptr = font_base[(cattr >> 3) & 1];
+                font_ptr += 32 * 4 * ch;
+                bgcol = palette[cattr >> 4];
+                fgcol = palette[cattr & 0x0f];
+                if (cw != 9) {
+                    vga_draw_glyph8(d1, linesize,
+                                    font_ptr, cheight, fgcol, bgcol);
+                } else {
+                    dup9 = 0;
+                    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[VGA_CRTC_CURSOR_START] & 0x20) &&
+                    s->cursor_visible_phase) {
+                    int line_start, line_last, h;
+                    /* draw the cursor */
+                    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;
+                    if (line_last >= line_start && line_start < cheight) {
+                        h = line_last - line_start + 1;
+                        d = d1 + linesize * line_start;
+                        if (cw != 9) {
+                            vga_draw_glyph8(d, linesize,
+                                            cursor_glyph, h, fgcol, bgcol);
+                        } else {
+                            vga_draw_glyph9(d, linesize,
+                                            cursor_glyph, h, fgcol, bgcol, 1);
+                        }
+                    }
+                }
+            }
+            d1 += x_incr;
+            src += 4;
+            ch_attr_ptr++;
+        }
+        if (cx_max != -1) {
+            dpy_gfx_update(s->con, cx_min * cw, cy * cheight,
+                           (cx_max - cx_min + 1) * cw, cheight);
+        }
+        dest += linesize * cheight;
+        line1 = line + cheight;
+        offset += line_offset;
+        if (line < s->line_compare && line1 >= s->line_compare) {
+            offset = 0;
+        }
+        line = line1;
+    }
+}
+
+enum {
+    VGA_DRAW_LINE2,
+    VGA_DRAW_LINE2D2,
+    VGA_DRAW_LINE4,
+    VGA_DRAW_LINE4D2,
+    VGA_DRAW_LINE8D2,
+    VGA_DRAW_LINE8,
+    VGA_DRAW_LINE15,
+    VGA_DRAW_LINE16,
+    VGA_DRAW_LINE24,
+    VGA_DRAW_LINE32,
+    VGA_DRAW_LINE_NB,
+};
+
+static vga_draw_line_func * const vga_draw_line_table[NB_DEPTHS * VGA_DRAW_LINE_NB] = {
+    vga_draw_line2_8,
+    vga_draw_line2_16,
+    vga_draw_line2_16,
+    vga_draw_line2_32,
+    vga_draw_line2_32,
+    vga_draw_line2_16,
+    vga_draw_line2_16,
+
+    vga_draw_line2d2_8,
+    vga_draw_line2d2_16,
+    vga_draw_line2d2_16,
+    vga_draw_line2d2_32,
+    vga_draw_line2d2_32,
+    vga_draw_line2d2_16,
+    vga_draw_line2d2_16,
+
+    vga_draw_line4_8,
+    vga_draw_line4_16,
+    vga_draw_line4_16,
+    vga_draw_line4_32,
+    vga_draw_line4_32,
+    vga_draw_line4_16,
+    vga_draw_line4_16,
+
+    vga_draw_line4d2_8,
+    vga_draw_line4d2_16,
+    vga_draw_line4d2_16,
+    vga_draw_line4d2_32,
+    vga_draw_line4d2_32,
+    vga_draw_line4d2_16,
+    vga_draw_line4d2_16,
+
+    vga_draw_line8d2_8,
+    vga_draw_line8d2_16,
+    vga_draw_line8d2_16,
+    vga_draw_line8d2_32,
+    vga_draw_line8d2_32,
+    vga_draw_line8d2_16,
+    vga_draw_line8d2_16,
+
+    vga_draw_line8_8,
+    vga_draw_line8_16,
+    vga_draw_line8_16,
+    vga_draw_line8_32,
+    vga_draw_line8_32,
+    vga_draw_line8_16,
+    vga_draw_line8_16,
+
+    vga_draw_line15_8,
+    vga_draw_line15_15,
+    vga_draw_line15_16,
+    vga_draw_line15_32,
+    vga_draw_line15_32bgr,
+    vga_draw_line15_15bgr,
+    vga_draw_line15_16bgr,
+
+    vga_draw_line16_8,
+    vga_draw_line16_15,
+    vga_draw_line16_16,
+    vga_draw_line16_32,
+    vga_draw_line16_32bgr,
+    vga_draw_line16_15bgr,
+    vga_draw_line16_16bgr,
+
+    vga_draw_line24_8,
+    vga_draw_line24_15,
+    vga_draw_line24_16,
+    vga_draw_line24_32,
+    vga_draw_line24_32bgr,
+    vga_draw_line24_15bgr,
+    vga_draw_line24_16bgr,
+
+    vga_draw_line32_8,
+    vga_draw_line32_15,
+    vga_draw_line32_16,
+    vga_draw_line32_32,
+    vga_draw_line32_32bgr,
+    vga_draw_line32_15bgr,
+    vga_draw_line32_16bgr,
+};
+
+static int vga_get_bpp(VGACommonState *s)
+{
+    int ret;
+
+    if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
+        ret = s->vbe_regs[VBE_DISPI_INDEX_BPP];
+    } else {
+        ret = 0;
+    }
+    return ret;
+}
+
+static void vga_get_resolution(VGACommonState *s, int *pwidth, int *pheight)
+{
+    int width, height;
+
+    if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
+        width = s->vbe_regs[VBE_DISPI_INDEX_XRES];
+        height = s->vbe_regs[VBE_DISPI_INDEX_YRES];
+    } else {
+        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;
+    *pheight = height;
+}
+
+void vga_invalidate_scanlines(VGACommonState *s, int y1, int y2)
+{
+    int y;
+    if (y1 >= VGA_MAX_HEIGHT)
+        return;
+    if (y2 >= VGA_MAX_HEIGHT)
+        y2 = VGA_MAX_HEIGHT;
+    for(y = y1; y < y2; y++) {
+        s->invalidated_y_table[y >> 5] |= 1 << (y & 0x1f);
+    }
+}
+
+void vga_sync_dirty_bitmap(VGACommonState *s)
+{
+    memory_region_sync_dirty_bitmap(&s->vram);
+}
+
+void vga_dirty_log_start(VGACommonState *s)
+{
+    memory_region_set_log(&s->vram, true, DIRTY_MEMORY_VGA);
+}
+
+void vga_dirty_log_stop(VGACommonState *s)
+{
+    memory_region_set_log(&s->vram, false, DIRTY_MEMORY_VGA);
+}
+
+/*
+ * graphic modes
+ */
+static void vga_draw_graphic(VGACommonState *s, int full_update)
+{
+    DisplaySurface *surface = qemu_console_surface(s->con);
+    int y1, y, update, linesize, y_start, double_scan, mask, depth;
+    int width, height, shift_control, line_offset, bwidth, bits;
+    ram_addr_t page0, page1, page_min, page_max;
+    int disp_width, multi_scan, multi_run;
+    uint8_t *d;
+    uint32_t v, addr1, addr;
+    vga_draw_line_func *vga_draw_line;
+#if defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
+    static const bool byteswap = false;
+#else
+    static const bool byteswap = true;
+#endif
+
+    full_update |= update_basic_params(s);
+
+    if (!full_update)
+        vga_sync_dirty_bitmap(s);
+
+    s->get_resolution(s, &width, &height);
+    disp_width = width;
+
+    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[VGA_CRTC_MAX_SCAN] & 0x1f) + 1) << double_scan)
+            - 1;
+    } else {
+        /* in CGA modes, multi_scan is ignored */
+        /* XXX: is it correct ? */
+        multi_scan = double_scan;
+    }
+    multi_run = multi_scan;
+    if (shift_control != s->shift_control ||
+        double_scan != s->double_scan) {
+        full_update = 1;
+        s->shift_control = shift_control;
+        s->double_scan = double_scan;
+    }
+
+    if (shift_control == 0) {
+        if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) {
+            disp_width <<= 1;
+        }
+    } else if (shift_control == 1) {
+        if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) {
+            disp_width <<= 1;
+        }
+    }
+
+    depth = s->get_bpp(s);
+    if (s->line_offset != s->last_line_offset ||
+        disp_width != s->last_width ||
+        height != s->last_height ||
+        s->last_depth != depth) {
+        if (depth == 32 || (depth == 16 && !byteswap)) {
+            surface = qemu_create_displaysurface_from(disp_width,
+                    height, depth, s->line_offset,
+                    s->vram_ptr + (s->start_addr * 4), byteswap);
+            dpy_gfx_replace_surface(s->con, surface);
+        } else {
+            qemu_console_resize(s->con, disp_width, height);
+            surface = qemu_console_surface(s->con);
+        }
+        s->last_scr_width = disp_width;
+        s->last_scr_height = height;
+        s->last_width = disp_width;
+        s->last_height = height;
+        s->last_line_offset = s->line_offset;
+        s->last_depth = depth;
+        full_update = 1;
+    } else if (is_buffer_shared(surface) &&
+               (full_update || surface_data(surface) != s->vram_ptr
+                + (s->start_addr * 4))) {
+        DisplaySurface *surface;
+        surface = qemu_create_displaysurface_from(disp_width,
+                height, depth, s->line_offset,
+                s->vram_ptr + (s->start_addr * 4), byteswap);
+        dpy_gfx_replace_surface(s->con, surface);
+    }
+
+    s->rgb_to_pixel =
+        rgb_to_pixel_dup_table[get_depth_index(surface)];
+
+    if (shift_control == 0) {
+        full_update |= update_palette16(s);
+        if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) {
+            v = VGA_DRAW_LINE4D2;
+        } else {
+            v = VGA_DRAW_LINE4;
+        }
+        bits = 4;
+    } else if (shift_control == 1) {
+        full_update |= update_palette16(s);
+        if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) {
+            v = VGA_DRAW_LINE2D2;
+        } else {
+            v = VGA_DRAW_LINE2;
+        }
+        bits = 4;
+    } else {
+        switch(s->get_bpp(s)) {
+        default:
+        case 0:
+            full_update |= update_palette256(s);
+            v = VGA_DRAW_LINE8D2;
+            bits = 4;
+            break;
+        case 8:
+            full_update |= update_palette256(s);
+            v = VGA_DRAW_LINE8;
+            bits = 8;
+            break;
+        case 15:
+            v = VGA_DRAW_LINE15;
+            bits = 16;
+            break;
+        case 16:
+            v = VGA_DRAW_LINE16;
+            bits = 16;
+            break;
+        case 24:
+            v = VGA_DRAW_LINE24;
+            bits = 24;
+            break;
+        case 32:
+            v = VGA_DRAW_LINE32;
+            bits = 32;
+            break;
+        }
+    }
+    vga_draw_line = vga_draw_line_table[v * NB_DEPTHS +
+                                        get_depth_index(surface)];
+
+    if (!is_buffer_shared(surface) && s->cursor_invalidate) {
+        s->cursor_invalidate(s);
+    }
+
+    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[VGA_CRTC_MODE],
+           s->line_compare, s->sr[VGA_SEQ_CLOCK_MODE]);
+#endif
+    addr1 = (s->start_addr * 4);
+    bwidth = (width * bits + 7) / 8;
+    y_start = -1;
+    page_min = -1;
+    page_max = 0;
+    d = surface_data(surface);
+    linesize = surface_stride(surface);
+    y1 = 0;
+    for(y = 0; y < height; y++) {
+        addr = addr1;
+        if (!(s->cr[VGA_CRTC_MODE] & 1)) {
+            int shift;
+            /* CGA compatibility handling */
+            shift = 14 + ((s->cr[VGA_CRTC_MODE] >> 6) & 1);
+            addr = (addr & ~(1 << shift)) | ((y1 & 1) << shift);
+        }
+        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);
+        /* explicit invalidation for the hardware cursor */
+        update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1;
+        if (update) {
+            if (y_start < 0)
+                y_start = y;
+            if (page0 < page_min)
+                page_min = page0;
+            if (page1 > page_max)
+                page_max = page1;
+            if (!(is_buffer_shared(surface))) {
+                vga_draw_line(s, d, s->vram_ptr + addr, width);
+                if (s->cursor_draw_line)
+                    s->cursor_draw_line(s, d, y);
+            }
+        } else {
+            if (y_start >= 0) {
+                /* flush to display */
+                dpy_gfx_update(s->con, 0, y_start,
+                               disp_width, y - y_start);
+                y_start = -1;
+            }
+        }
+        if (!multi_run) {
+            mask = (s->cr[VGA_CRTC_MODE] & 3) ^ 3;
+            if ((y1 & mask) == mask)
+                addr1 += line_offset;
+            y1++;
+            multi_run = multi_scan;
+        } else {
+            multi_run--;
+        }
+        /* line compare acts on the displayed lines */
+        if (y == s->line_compare)
+            addr1 = 0;
+        d += linesize;
+    }
+    if (y_start >= 0) {
+        /* flush to display */
+        dpy_gfx_update(s->con, 0, y_start,
+                       disp_width, y - y_start);
+    }
+    /* reset modified pages */
+    if (page_max >= page_min) {
+        memory_region_reset_dirty(&s->vram,
+                                  page_min,
+                                  page_max - page_min,
+                                  DIRTY_MEMORY_VGA);
+    }
+    memset(s->invalidated_y_table, 0, ((height + 31) >> 5) * 4);
+}
+
+static void vga_draw_blank(VGACommonState *s, int full_update)
+{
+    DisplaySurface *surface = qemu_console_surface(s->con);
+    int i, w, val;
+    uint8_t *d;
+
+    if (!full_update)
+        return;
+    if (s->last_scr_width <= 0 || s->last_scr_height <= 0)
+        return;
+
+    s->rgb_to_pixel =
+        rgb_to_pixel_dup_table[get_depth_index(surface)];
+    if (surface_bits_per_pixel(surface) == 8) {
+        val = s->rgb_to_pixel(0, 0, 0);
+    } else {
+        val = 0;
+    }
+    w = s->last_scr_width * surface_bytes_per_pixel(surface);
+    d = surface_data(surface);
+    for(i = 0; i < s->last_scr_height; i++) {
+        memset(d, val, w);
+        d += surface_stride(surface);
+    }
+    dpy_gfx_update(s->con, 0, 0,
+                   s->last_scr_width, s->last_scr_height);
+}
+
+#define GMODE_TEXT     0
+#define GMODE_GRAPH    1
+#define GMODE_BLANK 2
+
+static void vga_update_display(void *opaque)
+{
+    VGACommonState *s = opaque;
+    DisplaySurface *surface = qemu_console_surface(s->con);
+    int full_update, graphic_mode;
+
+    qemu_flush_coalesced_mmio_buffer();
+
+    if (surface_bits_per_pixel(surface) == 0) {
+        /* nothing to do */
+    } else {
+        full_update = 0;
+        if (!(s->ar_index & 0x20)) {
+            graphic_mode = GMODE_BLANK;
+        } else {
+            graphic_mode = s->gr[VGA_GFX_MISC] & VGA_GR06_GRAPHICS_MODE;
+        }
+        if (graphic_mode != s->graphic_mode) {
+            s->graphic_mode = graphic_mode;
+            s->cursor_blink_time = qemu_get_clock_ms(vm_clock);
+            full_update = 1;
+        }
+        switch(graphic_mode) {
+        case GMODE_TEXT:
+            vga_draw_text(s, full_update);
+            break;
+        case GMODE_GRAPH:
+            vga_draw_graphic(s, full_update);
+            break;
+        case GMODE_BLANK:
+        default:
+            vga_draw_blank(s, full_update);
+            break;
+        }
+    }
+}
+
+/* force a full display refresh */
+static void vga_invalidate_display(void *opaque)
+{
+    VGACommonState *s = opaque;
+
+    s->last_width = -1;
+    s->last_height = -1;
+}
+
+void vga_common_reset(VGACommonState *s)
+{
+    s->sr_index = 0;
+    memset(s->sr, '\0', sizeof(s->sr));
+    s->gr_index = 0;
+    memset(s->gr, '\0', sizeof(s->gr));
+    s->ar_index = 0;
+    memset(s->ar, '\0', sizeof(s->ar));
+    s->ar_flip_flop = 0;
+    s->cr_index = 0;
+    memset(s->cr, '\0', sizeof(s->cr));
+    s->msr = 0;
+    s->fcr = 0;
+    s->st00 = 0;
+    s->st01 = 0;
+    s->dac_state = 0;
+    s->dac_sub_index = 0;
+    s->dac_read_index = 0;
+    s->dac_write_index = 0;
+    memset(s->dac_cache, '\0', sizeof(s->dac_cache));
+    s->dac_8bit = 0;
+    memset(s->palette, '\0', sizeof(s->palette));
+    s->bank_offset = 0;
+    s->vbe_index = 0;
+    memset(s->vbe_regs, '\0', sizeof(s->vbe_regs));
+    s->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID5;
+    s->vbe_start_addr = 0;
+    s->vbe_line_offset = 0;
+    s->vbe_bank_mask = (s->vram_size >> 16) - 1;
+    memset(s->font_offsets, '\0', sizeof(s->font_offsets));
+    s->graphic_mode = -1; /* force full update */
+    s->shift_control = 0;
+    s->double_scan = 0;
+    s->line_offset = 0;
+    s->line_compare = 0;
+    s->start_addr = 0;
+    s->plane_updated = 0;
+    s->last_cw = 0;
+    s->last_ch = 0;
+    s->last_width = 0;
+    s->last_height = 0;
+    s->last_scr_width = 0;
+    s->last_scr_height = 0;
+    s->cursor_start = 0;
+    s->cursor_end = 0;
+    s->cursor_offset = 0;
+    memset(s->invalidated_y_table, '\0', sizeof(s->invalidated_y_table));
+    memset(s->last_palette, '\0', sizeof(s->last_palette));
+    memset(s->last_ch_attr, '\0', sizeof(s->last_ch_attr));
+    switch (vga_retrace_method) {
+    case VGA_RETRACE_DUMB:
+        break;
+    case VGA_RETRACE_PRECISE:
+        memset(&s->retrace_info, 0, sizeof (s->retrace_info));
+        break;
+    }
+    vga_update_memory_access(s);
+}
+
+static void vga_reset(void *opaque)
+{
+    VGACommonState *s =  opaque;
+    vga_common_reset(s);
+}
+
+#define TEXTMODE_X(x)  ((x) % width)
+#define TEXTMODE_Y(x)  ((x) / width)
+#define VMEM2CHTYPE(v) ((v & 0xff0007ff) | \
+        ((v & 0x00000800) << 10) | ((v & 0x00007000) >> 1))
+/* relay text rendering to the display driver
+ * instead of doing a full vga_update_display() */
+static void vga_update_text(void *opaque, console_ch_t *chardata)
+{
+    VGACommonState *s =  opaque;
+    int graphic_mode, i, cursor_offset, cursor_visible;
+    int cw, cheight, width, height, size, c_min, c_max;
+    uint32_t *src;
+    console_ch_t *dst, val;
+    char msg_buffer[80];
+    int full_update = 0;
+
+    qemu_flush_coalesced_mmio_buffer();
+
+    if (!(s->ar_index & 0x20)) {
+        graphic_mode = GMODE_BLANK;
+    } else {
+        graphic_mode = s->gr[VGA_GFX_MISC] & VGA_GR06_GRAPHICS_MODE;
+    }
+    if (graphic_mode != s->graphic_mode) {
+        s->graphic_mode = graphic_mode;
+        full_update = 1;
+    }
+    if (s->last_width == -1) {
+        s->last_width = 0;
+        full_update = 1;
+    }
+
+    switch (graphic_mode) {
+    case GMODE_TEXT:
+        /* TODO: update palette */
+        full_update |= update_basic_params(s);
+
+        /* total width & height */
+        cheight = (s->cr[VGA_CRTC_MAX_SCAN] & 0x1f) + 1;
+        cw = 8;
+        if (!(s->sr[VGA_SEQ_CLOCK_MODE] & VGA_SR01_CHAR_CLK_8DOTS)) {
+            cw = 9;
+        }
+        if (s->sr[VGA_SEQ_CLOCK_MODE] & 0x08) {
+            cw = 16; /* NOTE: no 18 pixel wide */
+        }
+        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[VGA_CRTC_V_DISP_END] |
+                ((s->cr[VGA_CRTC_OVERFLOW] & 0x02) << 7) |
+                ((s->cr[VGA_CRTC_OVERFLOW] & 0x40) << 3);
+            height = (height + 1) / cheight;
+        }
+
+        size = (height * width);
+        if (size > CH_ATTR_SIZE) {
+            if (!full_update)
+                return;
+
+            snprintf(msg_buffer, sizeof(msg_buffer), "%i x %i Text mode",
+                     width, height);
+            break;
+        }
+
+        if (width != s->last_width || height != s->last_height ||
+            cw != s->last_cw || cheight != s->last_ch) {
+            s->last_scr_width = width * cw;
+            s->last_scr_height = height * cheight;
+            qemu_console_resize(s->con, s->last_scr_width, s->last_scr_height);
+            dpy_text_resize(s->con, width, height);
+            s->last_depth = 0;
+            s->last_width = width;
+            s->last_height = height;
+            s->last_ch = cheight;
+            s->last_cw = cw;
+            full_update = 1;
+        }
+
+        if (full_update) {
+            s->full_update_gfx = 1;
+        }
+        if (s->full_update_text) {
+            s->full_update_text = 0;
+            full_update |= 1;
+        }
+
+        /* Update "hardware" cursor */
+        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[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_text_cursor(s->con,
+                                TEXTMODE_X(cursor_offset),
+                                TEXTMODE_Y(cursor_offset));
+            else
+                dpy_text_cursor(s->con, -1, -1);
+            s->cursor_offset = cursor_offset;
+            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;
+        dst = chardata;
+
+        if (full_update) {
+            for (i = 0; i < size; src ++, dst ++, i ++)
+                console_write_ch(dst, VMEM2CHTYPE(le32_to_cpu(*src)));
+
+            dpy_text_update(s->con, 0, 0, width, height);
+        } else {
+            c_max = 0;
+
+            for (i = 0; i < size; src ++, dst ++, i ++) {
+                console_write_ch(&val, VMEM2CHTYPE(le32_to_cpu(*src)));
+                if (*dst != val) {
+                    *dst = val;
+                    c_max = i;
+                    break;
+                }
+            }
+            c_min = i;
+            for (; i < size; src ++, dst ++, i ++) {
+                console_write_ch(&val, VMEM2CHTYPE(le32_to_cpu(*src)));
+                if (*dst != val) {
+                    *dst = val;
+                    c_max = i;
+                }
+            }
+
+            if (c_min <= c_max) {
+                i = TEXTMODE_Y(c_min);
+                dpy_text_update(s->con, 0, i, width, TEXTMODE_Y(c_max) - i + 1);
+            }
+        }
+
+        return;
+    case GMODE_GRAPH:
+        if (!full_update)
+            return;
+
+        s->get_resolution(s, &width, &height);
+        snprintf(msg_buffer, sizeof(msg_buffer), "%i x %i Graphic mode",
+                 width, height);
+        break;
+    case GMODE_BLANK:
+    default:
+        if (!full_update)
+            return;
+
+        snprintf(msg_buffer, sizeof(msg_buffer), "VGA Blank mode");
+        break;
+    }
+
+    /* Display a message */
+    s->last_width = 60;
+    s->last_height = height = 3;
+    dpy_text_cursor(s->con, -1, -1);
+    dpy_text_resize(s->con, s->last_width, height);
+
+    for (dst = chardata, i = 0; i < s->last_width * height; i ++)
+        console_write_ch(dst ++, ' ');
+
+    size = strlen(msg_buffer);
+    width = (s->last_width - size) / 2;
+    dst = chardata + s->last_width + width;
+    for (i = 0; i < size; i ++)
+        console_write_ch(dst ++, 0x00200100 | msg_buffer[i]);
+
+    dpy_text_update(s->con, 0, 0, s->last_width, height);
+}
+
+static uint64_t vga_mem_read(void *opaque, hwaddr addr,
+                             unsigned size)
+{
+    VGACommonState *s = opaque;
+
+    return vga_mem_readb(s, addr);
+}
+
+static void vga_mem_write(void *opaque, hwaddr addr,
+                          uint64_t data, unsigned size)
+{
+    VGACommonState *s = opaque;
+
+    return vga_mem_writeb(s, addr, data);
+}
+
+const MemoryRegionOps vga_mem_ops = {
+    .read = vga_mem_read,
+    .write = vga_mem_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+};
+
+static int vga_common_post_load(void *opaque, int version_id)
+{
+    VGACommonState *s = opaque;
+
+    /* force refresh */
+    s->graphic_mode = -1;
+    return 0;
+}
+
+const VMStateDescription vmstate_vga_common = {
+    .name = "vga",
+    .version_id = 2,
+    .minimum_version_id = 2,
+    .minimum_version_id_old = 2,
+    .post_load = vga_common_post_load,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT32(latch, VGACommonState),
+        VMSTATE_UINT8(sr_index, VGACommonState),
+        VMSTATE_PARTIAL_BUFFER(sr, VGACommonState, 8),
+        VMSTATE_UINT8(gr_index, VGACommonState),
+        VMSTATE_PARTIAL_BUFFER(gr, VGACommonState, 16),
+        VMSTATE_UINT8(ar_index, VGACommonState),
+        VMSTATE_BUFFER(ar, VGACommonState),
+        VMSTATE_INT32(ar_flip_flop, VGACommonState),
+        VMSTATE_UINT8(cr_index, VGACommonState),
+        VMSTATE_BUFFER(cr, VGACommonState),
+        VMSTATE_UINT8(msr, VGACommonState),
+        VMSTATE_UINT8(fcr, VGACommonState),
+        VMSTATE_UINT8(st00, VGACommonState),
+        VMSTATE_UINT8(st01, VGACommonState),
+
+        VMSTATE_UINT8(dac_state, VGACommonState),
+        VMSTATE_UINT8(dac_sub_index, VGACommonState),
+        VMSTATE_UINT8(dac_read_index, VGACommonState),
+        VMSTATE_UINT8(dac_write_index, VGACommonState),
+        VMSTATE_BUFFER(dac_cache, VGACommonState),
+        VMSTATE_BUFFER(palette, VGACommonState),
+
+        VMSTATE_INT32(bank_offset, VGACommonState),
+        VMSTATE_UINT8_EQUAL(is_vbe_vmstate, VGACommonState),
+        VMSTATE_UINT16(vbe_index, VGACommonState),
+        VMSTATE_UINT16_ARRAY(vbe_regs, VGACommonState, VBE_DISPI_INDEX_NB),
+        VMSTATE_UINT32(vbe_start_addr, VGACommonState),
+        VMSTATE_UINT32(vbe_line_offset, VGACommonState),
+        VMSTATE_UINT32(vbe_bank_mask, VGACommonState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+void vga_common_init(VGACommonState *s)
+{
+    int i, j, v, b;
+
+    for(i = 0;i < 256; i++) {
+        v = 0;
+        for(j = 0; j < 8; j++) {
+            v |= ((i >> j) & 1) << (j * 4);
+        }
+        expand4[i] = v;
+
+        v = 0;
+        for(j = 0; j < 4; j++) {
+            v |= ((i >> (2 * j)) & 3) << (j * 4);
+        }
+        expand2[i] = v;
+    }
+    for(i = 0; i < 16; i++) {
+        v = 0;
+        for(j = 0; j < 4; j++) {
+            b = ((i >> j) & 1);
+            v |= b << (2 * j);
+            v |= b << (2 * j + 1);
+        }
+        expand4to8[i] = v;
+    }
+
+    /* valid range: 1 MB -> 256 MB */
+    s->vram_size = 1024 * 1024;
+    while (s->vram_size < (s->vram_size_mb << 20) &&
+           s->vram_size < (256 << 20)) {
+        s->vram_size <<= 1;
+    }
+    s->vram_size_mb = s->vram_size >> 20;
+
+    s->is_vbe_vmstate = 1;
+    memory_region_init_ram(&s->vram, "vga.vram", s->vram_size);
+    vmstate_register_ram_global(&s->vram);
+    xen_register_framebuffer(&s->vram);
+    s->vram_ptr = memory_region_get_ram_ptr(&s->vram);
+    s->get_bpp = vga_get_bpp;
+    s->get_offsets = vga_get_offsets;
+    s->get_resolution = vga_get_resolution;
+    s->update = vga_update_display;
+    s->invalidate = vga_invalidate_display;
+    s->screen_dump = vga_screen_dump;
+    s->text_update = vga_update_text;
+    switch (vga_retrace_method) {
+    case VGA_RETRACE_DUMB:
+        s->retrace = vga_dumb_retrace;
+        s->update_retrace_info = vga_dumb_update_retrace_info;
+        break;
+
+    case VGA_RETRACE_PRECISE:
+        s->retrace = vga_precise_retrace;
+        s->update_retrace_info = vga_precise_update_retrace_info;
+        break;
+    }
+    vga_dirty_log_start(s);
+}
+
+static const MemoryRegionPortio vga_portio_list[] = {
+    { 0x04,  2, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3b4 */
+    { 0x0a,  1, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3ba */
+    { 0x10, 16, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3c0 */
+    { 0x24,  2, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3d4 */
+    { 0x2a,  1, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3da */
+    PORTIO_END_OF_LIST(),
+};
+
+static const MemoryRegionPortio vbe_portio_list[] = {
+    { 0, 1, 2, .read = vbe_ioport_read_index, .write = vbe_ioport_write_index },
+# ifdef TARGET_I386
+    { 1, 1, 2, .read = vbe_ioport_read_data, .write = vbe_ioport_write_data },
+# endif
+    { 2, 1, 2, .read = vbe_ioport_read_data, .write = vbe_ioport_write_data },
+    PORTIO_END_OF_LIST(),
+};
+
+/* Used by both ISA and PCI */
+MemoryRegion *vga_init_io(VGACommonState *s,
+                          const MemoryRegionPortio **vga_ports,
+                          const MemoryRegionPortio **vbe_ports)
+{
+    MemoryRegion *vga_mem;
+
+    *vga_ports = vga_portio_list;
+    *vbe_ports = vbe_portio_list;
+
+    vga_mem = g_malloc(sizeof(*vga_mem));
+    memory_region_init_io(vga_mem, &vga_mem_ops, s,
+                          "vga-lowmem", 0x20000);
+    memory_region_set_flush_coalesced(vga_mem);
+
+    return vga_mem;
+}
+
+void vga_init(VGACommonState *s, MemoryRegion *address_space,
+              MemoryRegion *address_space_io, bool init_vga_ports)
+{
+    MemoryRegion *vga_io_memory;
+    const MemoryRegionPortio *vga_ports, *vbe_ports;
+    PortioList *vga_port_list = g_new(PortioList, 1);
+    PortioList *vbe_port_list = g_new(PortioList, 1);
+
+    qemu_register_reset(vga_reset, s);
+
+    s->bank_offset = 0;
+
+    s->legacy_address_space = address_space;
+
+    vga_io_memory = vga_init_io(s, &vga_ports, &vbe_ports);
+    memory_region_add_subregion_overlap(address_space,
+                                        isa_mem_base + 0x000a0000,
+                                        vga_io_memory,
+                                        1);
+    memory_region_set_coalescing(vga_io_memory);
+    if (init_vga_ports) {
+        portio_list_init(vga_port_list, vga_ports, s, "vga");
+        portio_list_add(vga_port_list, address_space_io, 0x3b0);
+    }
+    if (vbe_ports) {
+        portio_list_init(vbe_port_list, vbe_ports, s, "vbe");
+        portio_list_add(vbe_port_list, address_space_io, 0x1ce);
+    }
+}
+
+void vga_init_vbe(VGACommonState *s, MemoryRegion *system_memory)
+{
+    /* With pc-0.12 and below we map both the PCI BAR and the fixed VBE region,
+     * so use an alias to avoid double-mapping the same region.
+     */
+    memory_region_init_alias(&s->vram_vbe, "vram.vbe",
+                             &s->vram, 0, memory_region_size(&s->vram));
+    /* XXX: use optimized standard vga accesses */
+    memory_region_add_subregion(system_memory,
+                                VBE_DISPI_LFB_PHYSICAL_ADDRESS,
+                                &s->vram_vbe);
+    s->vbe_mapped = 1;
+}
+/********************************************************/
+/* vga screen dump */
+
+void ppm_save(const char *filename, struct DisplaySurface *ds, Error **errp)
+{
+    int width = pixman_image_get_width(ds->image);
+    int height = pixman_image_get_height(ds->image);
+    FILE *f;
+    int y;
+    int ret;
+    pixman_image_t *linebuf;
+
+    trace_ppm_save(filename, ds);
+    f = fopen(filename, "wb");
+    if (!f) {
+        error_setg(errp, "failed to open file '%s': %s", filename,
+                   strerror(errno));
+        return;
+    }
+    ret = fprintf(f, "P6\n%d %d\n%d\n", width, height, 255);
+    if (ret < 0) {
+        linebuf = NULL;
+        goto write_err;
+    }
+    linebuf = qemu_pixman_linebuf_create(PIXMAN_BE_r8g8b8, width);
+    for (y = 0; y < height; y++) {
+        qemu_pixman_linebuf_fill(linebuf, ds->image, width, 0, y);
+        clearerr(f);
+        ret = fwrite(pixman_image_get_data(linebuf), 1,
+                     pixman_image_get_stride(linebuf), f);
+        (void)ret;
+        if (ferror(f)) {
+            goto write_err;
+        }
+    }
+
+out:
+    qemu_pixman_image_unref(linebuf);
+    fclose(f);
+    return;
+
+write_err:
+    error_setg(errp, "failed to write to file '%s': %s", filename,
+               strerror(errno));
+    unlink(filename);
+    goto out;
+}
+
+/* save the vga display in a PPM image even if no display is
+   available */
+static void vga_screen_dump(void *opaque, const char *filename, bool cswitch,
+                            Error **errp)
+{
+    VGACommonState *s = opaque;
+    DisplaySurface *surface = qemu_console_surface(s->con);
+
+    if (cswitch) {
+        vga_invalidate_display(s);
+    }
+    vga_hw_update();
+    ppm_save(filename, surface, errp);
+}
diff --git a/hw/display/vga.h b/hw/display/vga.h
new file mode 100644 (file)
index 0000000..d917046
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * linux/include/video/vga.h -- standard VGA chipset interaction
+ *
+ * Copyright 1999 Jeff Garzik <jgarzik@pobox.com>
+ *
+ * Copyright history from vga16fb.c:
+ *     Copyright 1999 Ben Pfaff and Petr Vandrovec
+ *     Based on VGA info at http://www.osdever.net/FreeVGA/home.htm
+ *     Based on VESA framebuffer (c) 1998 Gerd Knorr
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License.  See the file COPYING in the main directory of this
+ * archive for more details.
+ *
+ */
+
+#ifndef __linux_video_vga_h__
+#define __linux_video_vga_h__
+
+/* Some of the code below is taken from SVGAlib.  The original,
+   unmodified copyright notice for that code is below. */
+/* VGAlib version 1.2 - (c) 1993 Tommy Frandsen                    */
+/*                                                                 */
+/* This library is free software; you can redistribute it and/or   */
+/* modify it without any restrictions. This library is distributed */
+/* in the hope that it will be useful, but without any warranty.   */
+
+/* Multi-chipset support Copyright 1993 Harm Hanemaayer */
+/* partially copyrighted (C) 1993 by Hartmut Schirmer */
+
+/* VGA data register ports */
+#define VGA_CRT_DC      0x3D5   /* CRT Controller Data Register - color emulation */
+#define VGA_CRT_DM      0x3B5   /* CRT Controller Data Register - mono emulation */
+#define VGA_ATT_R       0x3C1   /* Attribute Controller Data Read Register */
+#define VGA_ATT_W       0x3C0   /* Attribute Controller Data Write Register */
+#define VGA_GFX_D       0x3CF   /* Graphics Controller Data Register */
+#define VGA_SEQ_D       0x3C5   /* Sequencer Data Register */
+#define VGA_MIS_R       0x3CC   /* Misc Output Read Register */
+#define VGA_MIS_W       0x3C2   /* Misc Output Write Register */
+#define VGA_FTC_R       0x3CA   /* Feature Control Read Register */
+#define VGA_IS1_RC      0x3DA   /* Input Status Register 1 - color emulation */
+#define VGA_IS1_RM      0x3BA   /* Input Status Register 1 - mono emulation */
+#define VGA_PEL_D       0x3C9   /* PEL Data Register */
+#define VGA_PEL_MSK     0x3C6   /* PEL mask register */
+
+/* EGA-specific registers */
+#define EGA_GFX_E0      0x3CC   /* Graphics enable processor 0 */
+#define EGA_GFX_E1      0x3CA   /* Graphics enable processor 1 */
+
+/* VGA index register ports */
+#define VGA_CRT_IC      0x3D4   /* CRT Controller Index - color emulation */
+#define VGA_CRT_IM      0x3B4   /* CRT Controller Index - mono emulation */
+#define VGA_ATT_IW      0x3C0   /* Attribute Controller Index & Data Write Register */
+#define VGA_GFX_I       0x3CE   /* Graphics Controller Index */
+#define VGA_SEQ_I       0x3C4   /* Sequencer Index */
+#define VGA_PEL_IW      0x3C8   /* PEL Write Index */
+#define VGA_PEL_IR      0x3C7   /* PEL Read Index */
+
+/* standard VGA indexes max counts */
+#define VGA_CRT_C       0x19    /* Number of CRT Controller Registers */
+#define VGA_ATT_C       0x15    /* Number of Attribute Controller Registers */
+#define VGA_GFX_C       0x09    /* Number of Graphics Controller Registers */
+#define VGA_SEQ_C       0x05    /* Number of Sequencer Registers */
+#define VGA_MIS_C       0x01    /* Number of Misc Output Register */
+
+/* VGA misc register bit masks */
+#define VGA_MIS_COLOR           0x01
+#define VGA_MIS_ENB_MEM_ACCESS  0x02
+#define VGA_MIS_DCLK_28322_720  0x04
+#define VGA_MIS_ENB_PLL_LOAD    (0x04 | 0x08)
+#define VGA_MIS_SEL_HIGH_PAGE   0x20
+
+/* VGA CRT controller register indices */
+#define VGA_CRTC_H_TOTAL        0
+#define VGA_CRTC_H_DISP         1
+#define VGA_CRTC_H_BLANK_START  2
+#define VGA_CRTC_H_BLANK_END    3
+#define VGA_CRTC_H_SYNC_START   4
+#define VGA_CRTC_H_SYNC_END     5
+#define VGA_CRTC_V_TOTAL        6
+#define VGA_CRTC_OVERFLOW       7
+#define VGA_CRTC_PRESET_ROW     8
+#define VGA_CRTC_MAX_SCAN       9
+#define VGA_CRTC_CURSOR_START   0x0A
+#define VGA_CRTC_CURSOR_END     0x0B
+#define VGA_CRTC_START_HI       0x0C
+#define VGA_CRTC_START_LO       0x0D
+#define VGA_CRTC_CURSOR_HI      0x0E
+#define VGA_CRTC_CURSOR_LO      0x0F
+#define VGA_CRTC_V_SYNC_START   0x10
+#define VGA_CRTC_V_SYNC_END     0x11
+#define VGA_CRTC_V_DISP_END     0x12
+#define VGA_CRTC_OFFSET         0x13
+#define VGA_CRTC_UNDERLINE      0x14
+#define VGA_CRTC_V_BLANK_START  0x15
+#define VGA_CRTC_V_BLANK_END    0x16
+#define VGA_CRTC_MODE           0x17
+#define VGA_CRTC_LINE_COMPARE   0x18
+#define VGA_CRTC_REGS           VGA_CRT_C
+
+/* VGA CRT controller bit masks */
+#define VGA_CR11_LOCK_CR0_CR7   0x80 /* lock writes to CR0 - CR7 */
+#define VGA_CR17_H_V_SIGNALS_ENABLED 0x80
+
+/* VGA attribute controller register indices */
+#define VGA_ATC_PALETTE0        0x00
+#define VGA_ATC_PALETTE1        0x01
+#define VGA_ATC_PALETTE2        0x02
+#define VGA_ATC_PALETTE3        0x03
+#define VGA_ATC_PALETTE4        0x04
+#define VGA_ATC_PALETTE5        0x05
+#define VGA_ATC_PALETTE6        0x06
+#define VGA_ATC_PALETTE7        0x07
+#define VGA_ATC_PALETTE8        0x08
+#define VGA_ATC_PALETTE9        0x09
+#define VGA_ATC_PALETTEA        0x0A
+#define VGA_ATC_PALETTEB        0x0B
+#define VGA_ATC_PALETTEC        0x0C
+#define VGA_ATC_PALETTED        0x0D
+#define VGA_ATC_PALETTEE        0x0E
+#define VGA_ATC_PALETTEF        0x0F
+#define VGA_ATC_MODE            0x10
+#define VGA_ATC_OVERSCAN        0x11
+#define VGA_ATC_PLANE_ENABLE    0x12
+#define VGA_ATC_PEL             0x13
+#define VGA_ATC_COLOR_PAGE      0x14
+
+#define VGA_AR_ENABLE_DISPLAY   0x20
+
+/* VGA sequencer register indices */
+#define VGA_SEQ_RESET           0x00
+#define VGA_SEQ_CLOCK_MODE      0x01
+#define VGA_SEQ_PLANE_WRITE     0x02
+#define VGA_SEQ_CHARACTER_MAP   0x03
+#define VGA_SEQ_MEMORY_MODE     0x04
+
+/* VGA sequencer register bit masks */
+#define VGA_SR01_CHAR_CLK_8DOTS 0x01 /* bit 0: character clocks 8 dots wide are generated */
+#define VGA_SR01_SCREEN_OFF     0x20 /* bit 5: Screen is off */
+#define VGA_SR02_ALL_PLANES     0x0F /* bits 3-0: enable access to all planes */
+#define VGA_SR04_EXT_MEM        0x02 /* bit 1: allows complete mem access to 256K */
+#define VGA_SR04_SEQ_MODE       0x04 /* bit 2: directs system to use a sequential addressing mode */
+#define VGA_SR04_CHN_4M         0x08 /* bit 3: selects modulo 4 addressing for CPU access to display memory */
+
+/* VGA graphics controller register indices */
+#define VGA_GFX_SR_VALUE        0x00
+#define VGA_GFX_SR_ENABLE       0x01
+#define VGA_GFX_COMPARE_VALUE   0x02
+#define VGA_GFX_DATA_ROTATE     0x03
+#define VGA_GFX_PLANE_READ      0x04
+#define VGA_GFX_MODE            0x05
+#define VGA_GFX_MISC            0x06
+#define VGA_GFX_COMPARE_MASK    0x07
+#define VGA_GFX_BIT_MASK        0x08
+
+/* VGA graphics controller bit masks */
+#define VGA_GR06_GRAPHICS_MODE  0x01
+
+#endif /* __linux_video_vga_h__ */
diff --git a/hw/display/vga_int.h b/hw/display/vga_int.h
new file mode 100644 (file)
index 0000000..260f7d6
--- /dev/null
@@ -0,0 +1,218 @@
+/*
+ * QEMU internal VGA defines.
+ *
+ * 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_VGA_INT_H
+#define HW_VGA_INT_H 1
+
+#include <hw/hw.h>
+#include "qapi/error.h"
+#include "exec/memory.h"
+
+#define ST01_V_RETRACE      0x08
+#define ST01_DISP_ENABLE    0x01
+
+#define VBE_DISPI_MAX_XRES              16000
+#define VBE_DISPI_MAX_YRES              12000
+#define VBE_DISPI_MAX_BPP               32
+
+#define VBE_DISPI_INDEX_ID              0x0
+#define VBE_DISPI_INDEX_XRES            0x1
+#define VBE_DISPI_INDEX_YRES            0x2
+#define VBE_DISPI_INDEX_BPP             0x3
+#define VBE_DISPI_INDEX_ENABLE          0x4
+#define VBE_DISPI_INDEX_BANK            0x5
+#define VBE_DISPI_INDEX_VIRT_WIDTH      0x6
+#define VBE_DISPI_INDEX_VIRT_HEIGHT     0x7
+#define VBE_DISPI_INDEX_X_OFFSET        0x8
+#define VBE_DISPI_INDEX_Y_OFFSET        0x9
+#define VBE_DISPI_INDEX_NB              0xa /* size of vbe_regs[] */
+#define VBE_DISPI_INDEX_VIDEO_MEMORY_64K 0xa /* read-only, not in vbe_regs */
+
+#define VBE_DISPI_ID0                   0xB0C0
+#define VBE_DISPI_ID1                   0xB0C1
+#define VBE_DISPI_ID2                   0xB0C2
+#define VBE_DISPI_ID3                   0xB0C3
+#define VBE_DISPI_ID4                   0xB0C4
+#define VBE_DISPI_ID5                   0xB0C5
+
+#define VBE_DISPI_DISABLED              0x00
+#define VBE_DISPI_ENABLED               0x01
+#define VBE_DISPI_GETCAPS               0x02
+#define VBE_DISPI_8BIT_DAC              0x20
+#define VBE_DISPI_LFB_ENABLED           0x40
+#define VBE_DISPI_NOCLEARMEM            0x80
+
+#define VBE_DISPI_LFB_PHYSICAL_ADDRESS  0xE0000000
+
+#define CH_ATTR_SIZE (160 * 100)
+#define VGA_MAX_HEIGHT 2048
+
+struct vga_precise_retrace {
+    int64_t ticks_per_char;
+    int64_t total_chars;
+    int htotal;
+    int hstart;
+    int hend;
+    int vstart;
+    int vend;
+    int freq;
+};
+
+union vga_retrace {
+    struct vga_precise_retrace precise;
+};
+
+struct VGACommonState;
+typedef uint8_t (* vga_retrace_fn)(struct VGACommonState *s);
+typedef void (* vga_update_retrace_info_fn)(struct VGACommonState *s);
+
+typedef struct VGACommonState {
+    MemoryRegion *legacy_address_space;
+    uint8_t *vram_ptr;
+    MemoryRegion vram;
+    MemoryRegion vram_vbe;
+    uint32_t vram_size;
+    uint32_t vram_size_mb; /* property */
+    uint32_t latch;
+    MemoryRegion *chain4_alias;
+    uint8_t sr_index;
+    uint8_t sr[256];
+    uint8_t gr_index;
+    uint8_t gr[256];
+    uint8_t ar_index;
+    uint8_t ar[21];
+    int ar_flip_flop;
+    uint8_t cr_index;
+    uint8_t cr[256]; /* CRT registers */
+    uint8_t msr; /* Misc Output Register */
+    uint8_t fcr; /* Feature Control Register */
+    uint8_t st00; /* status 0 */
+    uint8_t st01; /* status 1 */
+    uint8_t dac_state;
+    uint8_t dac_sub_index;
+    uint8_t dac_read_index;
+    uint8_t dac_write_index;
+    uint8_t dac_cache[3]; /* used when writing */
+    int dac_8bit;
+    uint8_t palette[768];
+    int32_t bank_offset;
+    int (*get_bpp)(struct VGACommonState *s);
+    void (*get_offsets)(struct VGACommonState *s,
+                        uint32_t *pline_offset,
+                        uint32_t *pstart_addr,
+                        uint32_t *pline_compare);
+    void (*get_resolution)(struct VGACommonState *s,
+                        int *pwidth,
+                        int *pheight);
+    /* bochs vbe state */
+    uint16_t vbe_index;
+    uint16_t vbe_regs[VBE_DISPI_INDEX_NB];
+    uint32_t vbe_start_addr;
+    uint32_t vbe_line_offset;
+    uint32_t vbe_bank_mask;
+    int vbe_mapped;
+    /* display refresh support */
+    QemuConsole *con;
+    uint32_t font_offsets[2];
+    int graphic_mode;
+    uint8_t shift_control;
+    uint8_t double_scan;
+    uint32_t line_offset;
+    uint32_t line_compare;
+    uint32_t start_addr;
+    uint32_t plane_updated;
+    uint32_t last_line_offset;
+    uint8_t last_cw, last_ch;
+    uint32_t last_width, last_height; /* in chars or pixels */
+    uint32_t last_scr_width, last_scr_height; /* in pixels */
+    uint32_t last_depth; /* in bits */
+    uint8_t cursor_start, cursor_end;
+    bool cursor_visible_phase;
+    int64_t cursor_blink_time;
+    uint32_t cursor_offset;
+    unsigned int (*rgb_to_pixel)(unsigned int r,
+                                 unsigned int g, unsigned b);
+    vga_hw_update_ptr update;
+    vga_hw_invalidate_ptr invalidate;
+    vga_hw_screen_dump_ptr screen_dump;
+    vga_hw_text_update_ptr text_update;
+    bool full_update_text;
+    bool full_update_gfx;
+    /* hardware mouse cursor support */
+    uint32_t invalidated_y_table[VGA_MAX_HEIGHT / 32];
+    void (*cursor_invalidate)(struct VGACommonState *s);
+    void (*cursor_draw_line)(struct VGACommonState *s, uint8_t *d, int y);
+    /* tell for each page if it has been updated since the last time */
+    uint32_t last_palette[256];
+    uint32_t last_ch_attr[CH_ATTR_SIZE]; /* XXX: make it dynamic */
+    /* retrace */
+    vga_retrace_fn retrace;
+    vga_update_retrace_info_fn update_retrace_info;
+    union vga_retrace retrace_info;
+    uint8_t is_vbe_vmstate;
+} VGACommonState;
+
+static inline int c6_to_8(int v)
+{
+    int b;
+    v &= 0x3f;
+    b = v & 1;
+    return (v << 2) | (b << 1) | b;
+}
+
+void vga_common_init(VGACommonState *s);
+void vga_init(VGACommonState *s, MemoryRegion *address_space,
+              MemoryRegion *address_space_io, bool init_vga_ports);
+MemoryRegion *vga_init_io(VGACommonState *s,
+                          const MemoryRegionPortio **vga_ports,
+                          const MemoryRegionPortio **vbe_ports);
+void vga_common_reset(VGACommonState *s);
+
+void vga_sync_dirty_bitmap(VGACommonState *s);
+void vga_dirty_log_start(VGACommonState *s);
+void vga_dirty_log_stop(VGACommonState *s);
+
+extern const VMStateDescription vmstate_vga_common;
+uint32_t vga_ioport_read(void *opaque, uint32_t addr);
+void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val);
+uint32_t vga_mem_readb(VGACommonState *s, hwaddr addr);
+void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val);
+void vga_invalidate_scanlines(VGACommonState *s, int y1, int y2);
+void ppm_save(const char *filename, struct DisplaySurface *ds, Error **errp);
+
+int vga_ioport_invalid(VGACommonState *s, uint32_t addr);
+
+void vga_init_vbe(VGACommonState *s, MemoryRegion *address_space);
+uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr);
+void vbe_ioport_write_index(void *opaque, uint32_t addr, uint32_t val);
+void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val);
+
+extern const uint8_t sr_mask[8];
+extern const uint8_t gr_mask[16];
+
+#define VGABIOS_FILENAME "vgabios.bin"
+#define VGABIOS_CIRRUS_FILENAME "vgabios-cirrus.bin"
+
+extern const MemoryRegionOps vga_mem_ops;
+
+#endif
diff --git a/hw/display/vga_template.h b/hw/display/vga_template.h
new file mode 100644 (file)
index 0000000..f6f6a01
--- /dev/null
@@ -0,0 +1,459 @@
+/*
+ * QEMU 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
+#define PIXEL_TYPE uint8_t
+#elif DEPTH == 15 || DEPTH == 16
+#define BPP 2
+#define PIXEL_TYPE uint16_t
+#elif DEPTH == 32
+#define BPP 4
+#define PIXEL_TYPE uint32_t
+#else
+#error unsupport depth
+#endif
+
+#ifdef BGR_FORMAT
+#define PIXEL_NAME glue(DEPTH, bgr)
+#else
+#define PIXEL_NAME DEPTH
+#endif /* BGR_FORMAT */
+
+#if DEPTH != 15 && !defined(BGR_FORMAT)
+
+static inline void glue(vga_draw_glyph_line_, DEPTH)(uint8_t *d,
+                                                     uint32_t font_data,
+                                                     uint32_t xorcol,
+                                                     uint32_t bgcol)
+{
+#if BPP == 1
+        ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
+        ((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
+#elif BPP == 2
+        ((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol;
+        ((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol;
+        ((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol;
+        ((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
+#else
+        ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
+        ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
+        ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
+        ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
+        ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
+        ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
+        ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
+        ((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
+#endif
+}
+
+static void glue(vga_draw_glyph8_, DEPTH)(uint8_t *d, int linesize,
+                                          const uint8_t *font_ptr, int h,
+                                          uint32_t fgcol, uint32_t bgcol)
+{
+    uint32_t font_data, xorcol;
+
+    xorcol = bgcol ^ fgcol;
+    do {
+        font_data = font_ptr[0];
+        glue(vga_draw_glyph_line_, DEPTH)(d, font_data, xorcol, bgcol);
+        font_ptr += 4;
+        d += linesize;
+    } while (--h);
+}
+
+static void glue(vga_draw_glyph16_, DEPTH)(uint8_t *d, int linesize,
+                                          const uint8_t *font_ptr, int h,
+                                          uint32_t fgcol, uint32_t bgcol)
+{
+    uint32_t font_data, xorcol;
+
+    xorcol = bgcol ^ fgcol;
+    do {
+        font_data = font_ptr[0];
+        glue(vga_draw_glyph_line_, DEPTH)(d,
+                                          expand4to8[font_data >> 4],
+                                          xorcol, bgcol);
+        glue(vga_draw_glyph_line_, DEPTH)(d + 8 * BPP,
+                                          expand4to8[font_data & 0x0f],
+                                          xorcol, bgcol);
+        font_ptr += 4;
+        d += linesize;
+    } while (--h);
+}
+
+static void glue(vga_draw_glyph9_, DEPTH)(uint8_t *d, int linesize,
+                                          const uint8_t *font_ptr, int h,
+                                          uint32_t fgcol, uint32_t bgcol, int dup9)
+{
+    uint32_t font_data, xorcol, v;
+
+    xorcol = bgcol ^ fgcol;
+    do {
+        font_data = font_ptr[0];
+#if BPP == 1
+        cpu_to_32wu((uint32_t *)d, (dmask16[(font_data >> 4)] & xorcol) ^ bgcol);
+        v = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
+        cpu_to_32wu(((uint32_t *)d)+1, v);
+        if (dup9)
+            ((uint8_t *)d)[8] = v >> (24 * (1 - BIG));
+        else
+            ((uint8_t *)d)[8] = bgcol;
+
+#elif BPP == 2
+        cpu_to_32wu(((uint32_t *)d)+0, (dmask4[(font_data >> 6)] & xorcol) ^ bgcol);
+        cpu_to_32wu(((uint32_t *)d)+1, (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol);
+        cpu_to_32wu(((uint32_t *)d)+2, (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol);
+        v = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
+        cpu_to_32wu(((uint32_t *)d)+3, v);
+        if (dup9)
+            ((uint16_t *)d)[8] = v >> (16 * (1 - BIG));
+        else
+            ((uint16_t *)d)[8] = bgcol;
+#else
+        ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
+        ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
+        ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
+        ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
+        ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
+        ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
+        ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
+        v = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
+        ((uint32_t *)d)[7] = v;
+        if (dup9)
+            ((uint32_t *)d)[8] = v;
+        else
+            ((uint32_t *)d)[8] = bgcol;
+#endif
+        font_ptr += 4;
+        d += linesize;
+    } while (--h);
+}
+
+/*
+ * 4 color mode
+ */
+static void glue(vga_draw_line2_, DEPTH)(VGACommonState *s1, uint8_t *d,
+                                         const uint8_t *s, int width)
+{
+    uint32_t plane_mask, *palette, data, v;
+    int x;
+
+    palette = s1->last_palette;
+    plane_mask = mask16[s1->ar[VGA_ATC_PLANE_ENABLE] & 0xf];
+    width >>= 3;
+    for(x = 0; x < width; x++) {
+        data = ((uint32_t *)s)[0];
+        data &= plane_mask;
+        v = expand2[GET_PLANE(data, 0)];
+        v |= expand2[GET_PLANE(data, 2)] << 2;
+        ((PIXEL_TYPE *)d)[0] = palette[v >> 12];
+        ((PIXEL_TYPE *)d)[1] = palette[(v >> 8) & 0xf];
+        ((PIXEL_TYPE *)d)[2] = palette[(v >> 4) & 0xf];
+        ((PIXEL_TYPE *)d)[3] = palette[(v >> 0) & 0xf];
+
+        v = expand2[GET_PLANE(data, 1)];
+        v |= expand2[GET_PLANE(data, 3)] << 2;
+        ((PIXEL_TYPE *)d)[4] = palette[v >> 12];
+        ((PIXEL_TYPE *)d)[5] = palette[(v >> 8) & 0xf];
+        ((PIXEL_TYPE *)d)[6] = palette[(v >> 4) & 0xf];
+        ((PIXEL_TYPE *)d)[7] = palette[(v >> 0) & 0xf];
+        d += BPP * 8;
+        s += 4;
+    }
+}
+
+#if BPP == 1
+#define PUT_PIXEL2(d, n, v) ((uint16_t *)d)[(n)] = (v)
+#elif BPP == 2
+#define PUT_PIXEL2(d, n, v) ((uint32_t *)d)[(n)] = (v)
+#else
+#define PUT_PIXEL2(d, n, v) \
+((uint32_t *)d)[2*(n)] = ((uint32_t *)d)[2*(n)+1] = (v)
+#endif
+
+/*
+ * 4 color mode, dup2 horizontal
+ */
+static void glue(vga_draw_line2d2_, DEPTH)(VGACommonState *s1, uint8_t *d,
+                                           const uint8_t *s, int width)
+{
+    uint32_t plane_mask, *palette, data, v;
+    int x;
+
+    palette = s1->last_palette;
+    plane_mask = mask16[s1->ar[VGA_ATC_PLANE_ENABLE] & 0xf];
+    width >>= 3;
+    for(x = 0; x < width; x++) {
+        data = ((uint32_t *)s)[0];
+        data &= plane_mask;
+        v = expand2[GET_PLANE(data, 0)];
+        v |= expand2[GET_PLANE(data, 2)] << 2;
+        PUT_PIXEL2(d, 0, palette[v >> 12]);
+        PUT_PIXEL2(d, 1, palette[(v >> 8) & 0xf]);
+        PUT_PIXEL2(d, 2, palette[(v >> 4) & 0xf]);
+        PUT_PIXEL2(d, 3, palette[(v >> 0) & 0xf]);
+
+        v = expand2[GET_PLANE(data, 1)];
+        v |= expand2[GET_PLANE(data, 3)] << 2;
+        PUT_PIXEL2(d, 4, palette[v >> 12]);
+        PUT_PIXEL2(d, 5, palette[(v >> 8) & 0xf]);
+        PUT_PIXEL2(d, 6, palette[(v >> 4) & 0xf]);
+        PUT_PIXEL2(d, 7, palette[(v >> 0) & 0xf]);
+        d += BPP * 16;
+        s += 4;
+    }
+}
+
+/*
+ * 16 color mode
+ */
+static void glue(vga_draw_line4_, DEPTH)(VGACommonState *s1, uint8_t *d,
+                                         const uint8_t *s, int width)
+{
+    uint32_t plane_mask, data, v, *palette;
+    int x;
+
+    palette = s1->last_palette;
+    plane_mask = mask16[s1->ar[VGA_ATC_PLANE_ENABLE] & 0xf];
+    width >>= 3;
+    for(x = 0; x < width; x++) {
+        data = ((uint32_t *)s)[0];
+        data &= plane_mask;
+        v = expand4[GET_PLANE(data, 0)];
+        v |= expand4[GET_PLANE(data, 1)] << 1;
+        v |= expand4[GET_PLANE(data, 2)] << 2;
+        v |= expand4[GET_PLANE(data, 3)] << 3;
+        ((PIXEL_TYPE *)d)[0] = palette[v >> 28];
+        ((PIXEL_TYPE *)d)[1] = palette[(v >> 24) & 0xf];
+        ((PIXEL_TYPE *)d)[2] = palette[(v >> 20) & 0xf];
+        ((PIXEL_TYPE *)d)[3] = palette[(v >> 16) & 0xf];
+        ((PIXEL_TYPE *)d)[4] = palette[(v >> 12) & 0xf];
+        ((PIXEL_TYPE *)d)[5] = palette[(v >> 8) & 0xf];
+        ((PIXEL_TYPE *)d)[6] = palette[(v >> 4) & 0xf];
+        ((PIXEL_TYPE *)d)[7] = palette[(v >> 0) & 0xf];
+        d += BPP * 8;
+        s += 4;
+    }
+}
+
+/*
+ * 16 color mode, dup2 horizontal
+ */
+static void glue(vga_draw_line4d2_, DEPTH)(VGACommonState *s1, uint8_t *d,
+                                           const uint8_t *s, int width)
+{
+    uint32_t plane_mask, data, v, *palette;
+    int x;
+
+    palette = s1->last_palette;
+    plane_mask = mask16[s1->ar[VGA_ATC_PLANE_ENABLE] & 0xf];
+    width >>= 3;
+    for(x = 0; x < width; x++) {
+        data = ((uint32_t *)s)[0];
+        data &= plane_mask;
+        v = expand4[GET_PLANE(data, 0)];
+        v |= expand4[GET_PLANE(data, 1)] << 1;
+        v |= expand4[GET_PLANE(data, 2)] << 2;
+        v |= expand4[GET_PLANE(data, 3)] << 3;
+        PUT_PIXEL2(d, 0, palette[v >> 28]);
+        PUT_PIXEL2(d, 1, palette[(v >> 24) & 0xf]);
+        PUT_PIXEL2(d, 2, palette[(v >> 20) & 0xf]);
+        PUT_PIXEL2(d, 3, palette[(v >> 16) & 0xf]);
+        PUT_PIXEL2(d, 4, palette[(v >> 12) & 0xf]);
+        PUT_PIXEL2(d, 5, palette[(v >> 8) & 0xf]);
+        PUT_PIXEL2(d, 6, palette[(v >> 4) & 0xf]);
+        PUT_PIXEL2(d, 7, palette[(v >> 0) & 0xf]);
+        d += BPP * 16;
+        s += 4;
+    }
+}
+
+/*
+ * 256 color mode, double pixels
+ *
+ * XXX: add plane_mask support (never used in standard VGA modes)
+ */
+static void glue(vga_draw_line8d2_, DEPTH)(VGACommonState *s1, uint8_t *d,
+                                           const uint8_t *s, int width)
+{
+    uint32_t *palette;
+    int x;
+
+    palette = s1->last_palette;
+    width >>= 3;
+    for(x = 0; x < width; x++) {
+        PUT_PIXEL2(d, 0, palette[s[0]]);
+        PUT_PIXEL2(d, 1, palette[s[1]]);
+        PUT_PIXEL2(d, 2, palette[s[2]]);
+        PUT_PIXEL2(d, 3, palette[s[3]]);
+        d += BPP * 8;
+        s += 4;
+    }
+}
+
+/*
+ * standard 256 color mode
+ *
+ * XXX: add plane_mask support (never used in standard VGA modes)
+ */
+static void glue(vga_draw_line8_, DEPTH)(VGACommonState *s1, uint8_t *d,
+                                         const uint8_t *s, int width)
+{
+    uint32_t *palette;
+    int x;
+
+    palette = s1->last_palette;
+    width >>= 3;
+    for(x = 0; x < width; x++) {
+        ((PIXEL_TYPE *)d)[0] = palette[s[0]];
+        ((PIXEL_TYPE *)d)[1] = palette[s[1]];
+        ((PIXEL_TYPE *)d)[2] = palette[s[2]];
+        ((PIXEL_TYPE *)d)[3] = palette[s[3]];
+        ((PIXEL_TYPE *)d)[4] = palette[s[4]];
+        ((PIXEL_TYPE *)d)[5] = palette[s[5]];
+        ((PIXEL_TYPE *)d)[6] = palette[s[6]];
+        ((PIXEL_TYPE *)d)[7] = palette[s[7]];
+        d += BPP * 8;
+        s += 8;
+    }
+}
+
+#endif /* DEPTH != 15 */
+
+
+/* XXX: optimize */
+
+/*
+ * 15 bit color
+ */
+static void glue(vga_draw_line15_, PIXEL_NAME)(VGACommonState *s1, uint8_t *d,
+                                          const uint8_t *s, int width)
+{
+#if DEPTH == 15 && defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
+    memcpy(d, s, width * 2);
+#else
+    int w;
+    uint32_t v, r, g, b;
+
+    w = width;
+    do {
+        v = lduw_raw((void *)s);
+        r = (v >> 7) & 0xf8;
+        g = (v >> 2) & 0xf8;
+        b = (v << 3) & 0xf8;
+        ((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b);
+        s += 2;
+        d += BPP;
+    } while (--w != 0);
+#endif
+}
+
+/*
+ * 16 bit color
+ */
+static void glue(vga_draw_line16_, PIXEL_NAME)(VGACommonState *s1, uint8_t *d,
+                                          const uint8_t *s, int width)
+{
+#if DEPTH == 16 && defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
+    memcpy(d, s, width * 2);
+#else
+    int w;
+    uint32_t v, r, g, b;
+
+    w = width;
+    do {
+        v = lduw_raw((void *)s);
+        r = (v >> 8) & 0xf8;
+        g = (v >> 3) & 0xfc;
+        b = (v << 3) & 0xf8;
+        ((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b);
+        s += 2;
+        d += BPP;
+    } while (--w != 0);
+#endif
+}
+
+/*
+ * 24 bit color
+ */
+static void glue(vga_draw_line24_, PIXEL_NAME)(VGACommonState *s1, uint8_t *d,
+                                          const uint8_t *s, int width)
+{
+    int w;
+    uint32_t r, g, b;
+
+    w = width;
+    do {
+#if defined(TARGET_WORDS_BIGENDIAN)
+        r = s[0];
+        g = s[1];
+        b = s[2];
+#else
+        b = s[0];
+        g = s[1];
+        r = s[2];
+#endif
+        ((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b);
+        s += 3;
+        d += BPP;
+    } while (--w != 0);
+}
+
+/*
+ * 32 bit color
+ */
+static void glue(vga_draw_line32_, PIXEL_NAME)(VGACommonState *s1, uint8_t *d,
+                                          const uint8_t *s, int width)
+{
+#if DEPTH == 32 && defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN) && !defined(BGR_FORMAT)
+    memcpy(d, s, width * 4);
+#else
+    int w;
+    uint32_t r, g, b;
+
+    w = width;
+    do {
+#if defined(TARGET_WORDS_BIGENDIAN)
+        r = s[1];
+        g = s[2];
+        b = s[3];
+#else
+        b = s[0];
+        g = s[1];
+        r = s[2];
+#endif
+        ((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b);
+        s += 4;
+        d += BPP;
+    } while (--w != 0);
+#endif
+}
+
+#undef PUT_PIXEL2
+#undef DEPTH
+#undef BPP
+#undef PIXEL_TYPE
+#undef PIXEL_NAME
+#undef BGR_FORMAT
diff --git a/hw/display/vmware_vga.c b/hw/display/vmware_vga.c
new file mode 100644 (file)
index 0000000..bcad47a
--- /dev/null
@@ -0,0 +1,1282 @@
+/*
+ * QEMU VMware-SVGA "chipset".
+ *
+ * Copyright (c) 2007 Andrzej Zaborowski  <balrog@zabor.org>
+ *
+ * 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 "hw/hw.h"
+#include "hw/loader.h"
+#include "ui/console.h"
+#include "hw/pci/pci.h"
+
+#undef VERBOSE
+#define HW_RECT_ACCEL
+#define HW_FILL_ACCEL
+#define HW_MOUSE_ACCEL
+
+#include "vga_int.h"
+
+/* See http://vmware-svga.sf.net/ for some documentation on VMWare SVGA */
+
+struct vmsvga_state_s {
+    VGACommonState vga;
+
+    int invalidated;
+    int depth;
+    int bypp;
+    int enable;
+    int config;
+    struct {
+        int id;
+        int x;
+        int y;
+        int on;
+    } cursor;
+
+    int index;
+    int scratch_size;
+    uint32_t *scratch;
+    int new_width;
+    int new_height;
+    uint32_t guest;
+    uint32_t svgaid;
+    int syncing;
+
+    MemoryRegion fifo_ram;
+    uint8_t *fifo_ptr;
+    unsigned int fifo_size;
+
+    union {
+        uint32_t *fifo;
+        struct QEMU_PACKED {
+            uint32_t min;
+            uint32_t max;
+            uint32_t next_cmd;
+            uint32_t stop;
+            /* Add registers here when adding capabilities.  */
+            uint32_t fifo[0];
+        } *cmd;
+    };
+
+#define REDRAW_FIFO_LEN  512
+    struct vmsvga_rect_s {
+        int x, y, w, h;
+    } redraw_fifo[REDRAW_FIFO_LEN];
+    int redraw_fifo_first, redraw_fifo_last;
+};
+
+struct pci_vmsvga_state_s {
+    PCIDevice card;
+    struct vmsvga_state_s chip;
+    MemoryRegion io_bar;
+};
+
+#define SVGA_MAGIC              0x900000UL
+#define SVGA_MAKE_ID(ver)       (SVGA_MAGIC << 8 | (ver))
+#define SVGA_ID_0               SVGA_MAKE_ID(0)
+#define SVGA_ID_1               SVGA_MAKE_ID(1)
+#define SVGA_ID_2               SVGA_MAKE_ID(2)
+
+#define SVGA_LEGACY_BASE_PORT   0x4560
+#define SVGA_INDEX_PORT         0x0
+#define SVGA_VALUE_PORT         0x1
+#define SVGA_BIOS_PORT          0x2
+
+#define SVGA_VERSION_2
+
+#ifdef SVGA_VERSION_2
+# define SVGA_ID                SVGA_ID_2
+# define SVGA_IO_BASE           SVGA_LEGACY_BASE_PORT
+# define SVGA_IO_MUL            1
+# define SVGA_FIFO_SIZE         0x10000
+# define SVGA_PCI_DEVICE_ID     PCI_DEVICE_ID_VMWARE_SVGA2
+#else
+# define SVGA_ID                SVGA_ID_1
+# define SVGA_IO_BASE           SVGA_LEGACY_BASE_PORT
+# define SVGA_IO_MUL            4
+# define SVGA_FIFO_SIZE         0x10000
+# define SVGA_PCI_DEVICE_ID     PCI_DEVICE_ID_VMWARE_SVGA
+#endif
+
+enum {
+    /* ID 0, 1 and 2 registers */
+    SVGA_REG_ID = 0,
+    SVGA_REG_ENABLE = 1,
+    SVGA_REG_WIDTH = 2,
+    SVGA_REG_HEIGHT = 3,
+    SVGA_REG_MAX_WIDTH = 4,
+    SVGA_REG_MAX_HEIGHT = 5,
+    SVGA_REG_DEPTH = 6,
+    SVGA_REG_BITS_PER_PIXEL = 7,        /* Current bpp in the guest */
+    SVGA_REG_PSEUDOCOLOR = 8,
+    SVGA_REG_RED_MASK = 9,
+    SVGA_REG_GREEN_MASK = 10,
+    SVGA_REG_BLUE_MASK = 11,
+    SVGA_REG_BYTES_PER_LINE = 12,
+    SVGA_REG_FB_START = 13,
+    SVGA_REG_FB_OFFSET = 14,
+    SVGA_REG_VRAM_SIZE = 15,
+    SVGA_REG_FB_SIZE = 16,
+
+    /* ID 1 and 2 registers */
+    SVGA_REG_CAPABILITIES = 17,
+    SVGA_REG_MEM_START = 18,            /* Memory for command FIFO */
+    SVGA_REG_MEM_SIZE = 19,
+    SVGA_REG_CONFIG_DONE = 20,          /* Set when memory area configured */
+    SVGA_REG_SYNC = 21,                 /* Write to force synchronization */
+    SVGA_REG_BUSY = 22,                 /* Read to check if sync is done */
+    SVGA_REG_GUEST_ID = 23,             /* Set guest OS identifier */
+    SVGA_REG_CURSOR_ID = 24,            /* ID of cursor */
+    SVGA_REG_CURSOR_X = 25,             /* Set cursor X position */
+    SVGA_REG_CURSOR_Y = 26,             /* Set cursor Y position */
+    SVGA_REG_CURSOR_ON = 27,            /* Turn cursor on/off */
+    SVGA_REG_HOST_BITS_PER_PIXEL = 28,  /* Current bpp in the host */
+    SVGA_REG_SCRATCH_SIZE = 29,         /* Number of scratch registers */
+    SVGA_REG_MEM_REGS = 30,             /* Number of FIFO registers */
+    SVGA_REG_NUM_DISPLAYS = 31,         /* Number of guest displays */
+    SVGA_REG_PITCHLOCK = 32,            /* Fixed pitch for all modes */
+
+    SVGA_PALETTE_BASE = 1024,           /* Base of SVGA color map */
+    SVGA_PALETTE_END  = SVGA_PALETTE_BASE + 767,
+    SVGA_SCRATCH_BASE = SVGA_PALETTE_BASE + 768,
+};
+
+#define SVGA_CAP_NONE                   0
+#define SVGA_CAP_RECT_FILL              (1 << 0)
+#define SVGA_CAP_RECT_COPY              (1 << 1)
+#define SVGA_CAP_RECT_PAT_FILL          (1 << 2)
+#define SVGA_CAP_LEGACY_OFFSCREEN       (1 << 3)
+#define SVGA_CAP_RASTER_OP              (1 << 4)
+#define SVGA_CAP_CURSOR                 (1 << 5)
+#define SVGA_CAP_CURSOR_BYPASS          (1 << 6)
+#define SVGA_CAP_CURSOR_BYPASS_2        (1 << 7)
+#define SVGA_CAP_8BIT_EMULATION         (1 << 8)
+#define SVGA_CAP_ALPHA_CURSOR           (1 << 9)
+#define SVGA_CAP_GLYPH                  (1 << 10)
+#define SVGA_CAP_GLYPH_CLIPPING         (1 << 11)
+#define SVGA_CAP_OFFSCREEN_1            (1 << 12)
+#define SVGA_CAP_ALPHA_BLEND            (1 << 13)
+#define SVGA_CAP_3D                     (1 << 14)
+#define SVGA_CAP_EXTENDED_FIFO          (1 << 15)
+#define SVGA_CAP_MULTIMON               (1 << 16)
+#define SVGA_CAP_PITCHLOCK              (1 << 17)
+
+/*
+ * FIFO offsets (seen as an array of 32-bit words)
+ */
+enum {
+    /*
+     * The original defined FIFO offsets
+     */
+    SVGA_FIFO_MIN = 0,
+    SVGA_FIFO_MAX,      /* The distance from MIN to MAX must be at least 10K */
+    SVGA_FIFO_NEXT_CMD,
+    SVGA_FIFO_STOP,
+
+    /*
+     * Additional offsets added as of SVGA_CAP_EXTENDED_FIFO
+     */
+    SVGA_FIFO_CAPABILITIES = 4,
+    SVGA_FIFO_FLAGS,
+    SVGA_FIFO_FENCE,
+    SVGA_FIFO_3D_HWVERSION,
+    SVGA_FIFO_PITCHLOCK,
+};
+
+#define SVGA_FIFO_CAP_NONE              0
+#define SVGA_FIFO_CAP_FENCE             (1 << 0)
+#define SVGA_FIFO_CAP_ACCELFRONT        (1 << 1)
+#define SVGA_FIFO_CAP_PITCHLOCK         (1 << 2)
+
+#define SVGA_FIFO_FLAG_NONE             0
+#define SVGA_FIFO_FLAG_ACCELFRONT       (1 << 0)
+
+/* These values can probably be changed arbitrarily.  */
+#define SVGA_SCRATCH_SIZE               0x8000
+#define SVGA_MAX_WIDTH                  2360
+#define SVGA_MAX_HEIGHT                 1770
+
+#ifdef VERBOSE
+# define GUEST_OS_BASE          0x5001
+static const char *vmsvga_guest_id[] = {
+    [0x00] = "Dos",
+    [0x01] = "Windows 3.1",
+    [0x02] = "Windows 95",
+    [0x03] = "Windows 98",
+    [0x04] = "Windows ME",
+    [0x05] = "Windows NT",
+    [0x06] = "Windows 2000",
+    [0x07] = "Linux",
+    [0x08] = "OS/2",
+    [0x09] = "an unknown OS",
+    [0x0a] = "BSD",
+    [0x0b] = "Whistler",
+    [0x0c] = "an unknown OS",
+    [0x0d] = "an unknown OS",
+    [0x0e] = "an unknown OS",
+    [0x0f] = "an unknown OS",
+    [0x10] = "an unknown OS",
+    [0x11] = "an unknown OS",
+    [0x12] = "an unknown OS",
+    [0x13] = "an unknown OS",
+    [0x14] = "an unknown OS",
+    [0x15] = "Windows 2003",
+};
+#endif
+
+enum {
+    SVGA_CMD_INVALID_CMD = 0,
+    SVGA_CMD_UPDATE = 1,
+    SVGA_CMD_RECT_FILL = 2,
+    SVGA_CMD_RECT_COPY = 3,
+    SVGA_CMD_DEFINE_BITMAP = 4,
+    SVGA_CMD_DEFINE_BITMAP_SCANLINE = 5,
+    SVGA_CMD_DEFINE_PIXMAP = 6,
+    SVGA_CMD_DEFINE_PIXMAP_SCANLINE = 7,
+    SVGA_CMD_RECT_BITMAP_FILL = 8,
+    SVGA_CMD_RECT_PIXMAP_FILL = 9,
+    SVGA_CMD_RECT_BITMAP_COPY = 10,
+    SVGA_CMD_RECT_PIXMAP_COPY = 11,
+    SVGA_CMD_FREE_OBJECT = 12,
+    SVGA_CMD_RECT_ROP_FILL = 13,
+    SVGA_CMD_RECT_ROP_COPY = 14,
+    SVGA_CMD_RECT_ROP_BITMAP_FILL = 15,
+    SVGA_CMD_RECT_ROP_PIXMAP_FILL = 16,
+    SVGA_CMD_RECT_ROP_BITMAP_COPY = 17,
+    SVGA_CMD_RECT_ROP_PIXMAP_COPY = 18,
+    SVGA_CMD_DEFINE_CURSOR = 19,
+    SVGA_CMD_DISPLAY_CURSOR = 20,
+    SVGA_CMD_MOVE_CURSOR = 21,
+    SVGA_CMD_DEFINE_ALPHA_CURSOR = 22,
+    SVGA_CMD_DRAW_GLYPH = 23,
+    SVGA_CMD_DRAW_GLYPH_CLIPPED = 24,
+    SVGA_CMD_UPDATE_VERBOSE = 25,
+    SVGA_CMD_SURFACE_FILL = 26,
+    SVGA_CMD_SURFACE_COPY = 27,
+    SVGA_CMD_SURFACE_ALPHA_BLEND = 28,
+    SVGA_CMD_FRONT_ROP_FILL = 29,
+    SVGA_CMD_FENCE = 30,
+};
+
+/* Legal values for the SVGA_REG_CURSOR_ON register in cursor bypass mode */
+enum {
+    SVGA_CURSOR_ON_HIDE = 0,
+    SVGA_CURSOR_ON_SHOW = 1,
+    SVGA_CURSOR_ON_REMOVE_FROM_FB = 2,
+    SVGA_CURSOR_ON_RESTORE_TO_FB = 3,
+};
+
+static inline void vmsvga_update_rect(struct vmsvga_state_s *s,
+                int x, int y, int w, int h)
+{
+    DisplaySurface *surface = qemu_console_surface(s->vga.con);
+    int line;
+    int bypl;
+    int width;
+    int start;
+    uint8_t *src;
+    uint8_t *dst;
+
+    if (x < 0) {
+        fprintf(stderr, "%s: update x was < 0 (%d)\n", __func__, x);
+        w += x;
+        x = 0;
+    }
+    if (w < 0) {
+        fprintf(stderr, "%s: update w was < 0 (%d)\n", __func__, w);
+        w = 0;
+    }
+    if (x + w > surface_width(surface)) {
+        fprintf(stderr, "%s: update width too large x: %d, w: %d\n",
+                __func__, x, w);
+        x = MIN(x, surface_width(surface));
+        w = surface_width(surface) - x;
+    }
+
+    if (y < 0) {
+        fprintf(stderr, "%s: update y was < 0 (%d)\n",  __func__, y);
+        h += y;
+        y = 0;
+    }
+    if (h < 0) {
+        fprintf(stderr, "%s: update h was < 0 (%d)\n",  __func__, h);
+        h = 0;
+    }
+    if (y + h > surface_height(surface)) {
+        fprintf(stderr, "%s: update height too large y: %d, h: %d\n",
+                __func__, y, h);
+        y = MIN(y, surface_height(surface));
+        h = surface_height(surface) - y;
+    }
+
+    bypl = surface_stride(surface);
+    width = surface_bytes_per_pixel(surface) * w;
+    start = surface_bytes_per_pixel(surface) * x + bypl * y;
+    src = s->vga.vram_ptr + start;
+    dst = surface_data(surface) + start;
+
+    for (line = h; line > 0; line--, src += bypl, dst += bypl) {
+        memcpy(dst, src, width);
+    }
+    dpy_gfx_update(s->vga.con, x, y, w, h);
+}
+
+static inline void vmsvga_update_rect_delayed(struct vmsvga_state_s *s,
+                int x, int y, int w, int h)
+{
+    struct vmsvga_rect_s *rect = &s->redraw_fifo[s->redraw_fifo_last++];
+
+    s->redraw_fifo_last &= REDRAW_FIFO_LEN - 1;
+    rect->x = x;
+    rect->y = y;
+    rect->w = w;
+    rect->h = h;
+}
+
+static inline void vmsvga_update_rect_flush(struct vmsvga_state_s *s)
+{
+    struct vmsvga_rect_s *rect;
+
+    if (s->invalidated) {
+        s->redraw_fifo_first = s->redraw_fifo_last;
+        return;
+    }
+    /* Overlapping region updates can be optimised out here - if someone
+     * knows a smart algorithm to do that, please share.  */
+    while (s->redraw_fifo_first != s->redraw_fifo_last) {
+        rect = &s->redraw_fifo[s->redraw_fifo_first++];
+        s->redraw_fifo_first &= REDRAW_FIFO_LEN - 1;
+        vmsvga_update_rect(s, rect->x, rect->y, rect->w, rect->h);
+    }
+}
+
+#ifdef HW_RECT_ACCEL
+static inline void vmsvga_copy_rect(struct vmsvga_state_s *s,
+                int x0, int y0, int x1, int y1, int w, int h)
+{
+    DisplaySurface *surface = qemu_console_surface(s->vga.con);
+    uint8_t *vram = s->vga.vram_ptr;
+    int bypl = surface_stride(surface);
+    int bypp = surface_bytes_per_pixel(surface);
+    int width = bypp * w;
+    int line = h;
+    uint8_t *ptr[2];
+
+    if (y1 > y0) {
+        ptr[0] = vram + bypp * x0 + bypl * (y0 + h - 1);
+        ptr[1] = vram + bypp * x1 + bypl * (y1 + h - 1);
+        for (; line > 0; line --, ptr[0] -= bypl, ptr[1] -= bypl) {
+            memmove(ptr[1], ptr[0], width);
+        }
+    } else {
+        ptr[0] = vram + bypp * x0 + bypl * y0;
+        ptr[1] = vram + bypp * x1 + bypl * y1;
+        for (; line > 0; line --, ptr[0] += bypl, ptr[1] += bypl) {
+            memmove(ptr[1], ptr[0], width);
+        }
+    }
+
+    vmsvga_update_rect_delayed(s, x1, y1, w, h);
+}
+#endif
+
+#ifdef HW_FILL_ACCEL
+static inline void vmsvga_fill_rect(struct vmsvga_state_s *s,
+                uint32_t c, int x, int y, int w, int h)
+{
+    DisplaySurface *surface = qemu_console_surface(s->vga.con);
+    int bypl = surface_stride(surface);
+    int width = surface_bytes_per_pixel(surface) * w;
+    int line = h;
+    int column;
+    uint8_t *fst;
+    uint8_t *dst;
+    uint8_t *src;
+    uint8_t col[4];
+
+    col[0] = c;
+    col[1] = c >> 8;
+    col[2] = c >> 16;
+    col[3] = c >> 24;
+
+    fst = s->vga.vram_ptr + surface_bytes_per_pixel(surface) * x + bypl * y;
+
+    if (line--) {
+        dst = fst;
+        src = col;
+        for (column = width; column > 0; column--) {
+            *(dst++) = *(src++);
+            if (src - col == surface_bytes_per_pixel(surface)) {
+                src = col;
+            }
+        }
+        dst = fst;
+        for (; line > 0; line--) {
+            dst += bypl;
+            memcpy(dst, fst, width);
+        }
+    }
+
+    vmsvga_update_rect_delayed(s, x, y, w, h);
+}
+#endif
+
+struct vmsvga_cursor_definition_s {
+    int width;
+    int height;
+    int id;
+    int bpp;
+    int hot_x;
+    int hot_y;
+    uint32_t mask[1024];
+    uint32_t image[4096];
+};
+
+#define SVGA_BITMAP_SIZE(w, h)          ((((w) + 31) >> 5) * (h))
+#define SVGA_PIXMAP_SIZE(w, h, bpp)     (((((w) * (bpp)) + 31) >> 5) * (h))
+
+#ifdef HW_MOUSE_ACCEL
+static inline void vmsvga_cursor_define(struct vmsvga_state_s *s,
+                struct vmsvga_cursor_definition_s *c)
+{
+    QEMUCursor *qc;
+    int i, pixels;
+
+    qc = cursor_alloc(c->width, c->height);
+    qc->hot_x = c->hot_x;
+    qc->hot_y = c->hot_y;
+    switch (c->bpp) {
+    case 1:
+        cursor_set_mono(qc, 0xffffff, 0x000000, (void *)c->image,
+                        1, (void *)c->mask);
+#ifdef DEBUG
+        cursor_print_ascii_art(qc, "vmware/mono");
+#endif
+        break;
+    case 32:
+        /* fill alpha channel from mask, set color to zero */
+        cursor_set_mono(qc, 0x000000, 0x000000, (void *)c->mask,
+                        1, (void *)c->mask);
+        /* add in rgb values */
+        pixels = c->width * c->height;
+        for (i = 0; i < pixels; i++) {
+            qc->data[i] |= c->image[i] & 0xffffff;
+        }
+#ifdef DEBUG
+        cursor_print_ascii_art(qc, "vmware/32bit");
+#endif
+        break;
+    default:
+        fprintf(stderr, "%s: unhandled bpp %d, using fallback cursor\n",
+                __func__, c->bpp);
+        cursor_put(qc);
+        qc = cursor_builtin_left_ptr();
+    }
+
+    dpy_cursor_define(s->vga.con, qc);
+    cursor_put(qc);
+}
+#endif
+
+#define CMD(f)  le32_to_cpu(s->cmd->f)
+
+static inline int vmsvga_fifo_length(struct vmsvga_state_s *s)
+{
+    int num;
+
+    if (!s->config || !s->enable) {
+        return 0;
+    }
+    num = CMD(next_cmd) - CMD(stop);
+    if (num < 0) {
+        num += CMD(max) - CMD(min);
+    }
+    return num >> 2;
+}
+
+static inline uint32_t vmsvga_fifo_read_raw(struct vmsvga_state_s *s)
+{
+    uint32_t cmd = s->fifo[CMD(stop) >> 2];
+
+    s->cmd->stop = cpu_to_le32(CMD(stop) + 4);
+    if (CMD(stop) >= CMD(max)) {
+        s->cmd->stop = s->cmd->min;
+    }
+    return cmd;
+}
+
+static inline uint32_t vmsvga_fifo_read(struct vmsvga_state_s *s)
+{
+    return le32_to_cpu(vmsvga_fifo_read_raw(s));
+}
+
+static void vmsvga_fifo_run(struct vmsvga_state_s *s)
+{
+    uint32_t cmd, colour;
+    int args, len;
+    int x, y, dx, dy, width, height;
+    struct vmsvga_cursor_definition_s cursor;
+    uint32_t cmd_start;
+
+    len = vmsvga_fifo_length(s);
+    while (len > 0) {
+        /* May need to go back to the start of the command if incomplete */
+        cmd_start = s->cmd->stop;
+
+        switch (cmd = vmsvga_fifo_read(s)) {
+        case SVGA_CMD_UPDATE:
+        case SVGA_CMD_UPDATE_VERBOSE:
+            len -= 5;
+            if (len < 0) {
+                goto rewind;
+            }
+
+            x = vmsvga_fifo_read(s);
+            y = vmsvga_fifo_read(s);
+            width = vmsvga_fifo_read(s);
+            height = vmsvga_fifo_read(s);
+            vmsvga_update_rect_delayed(s, x, y, width, height);
+            break;
+
+        case SVGA_CMD_RECT_FILL:
+            len -= 6;
+            if (len < 0) {
+                goto rewind;
+            }
+
+            colour = vmsvga_fifo_read(s);
+            x = vmsvga_fifo_read(s);
+            y = vmsvga_fifo_read(s);
+            width = vmsvga_fifo_read(s);
+            height = vmsvga_fifo_read(s);
+#ifdef HW_FILL_ACCEL
+            vmsvga_fill_rect(s, colour, x, y, width, height);
+            break;
+#else
+            args = 0;
+            goto badcmd;
+#endif
+
+        case SVGA_CMD_RECT_COPY:
+            len -= 7;
+            if (len < 0) {
+                goto rewind;
+            }
+
+            x = vmsvga_fifo_read(s);
+            y = vmsvga_fifo_read(s);
+            dx = vmsvga_fifo_read(s);
+            dy = vmsvga_fifo_read(s);
+            width = vmsvga_fifo_read(s);
+            height = vmsvga_fifo_read(s);
+#ifdef HW_RECT_ACCEL
+            vmsvga_copy_rect(s, x, y, dx, dy, width, height);
+            break;
+#else
+            args = 0;
+            goto badcmd;
+#endif
+
+        case SVGA_CMD_DEFINE_CURSOR:
+            len -= 8;
+            if (len < 0) {
+                goto rewind;
+            }
+
+            cursor.id = vmsvga_fifo_read(s);
+            cursor.hot_x = vmsvga_fifo_read(s);
+            cursor.hot_y = vmsvga_fifo_read(s);
+            cursor.width = x = vmsvga_fifo_read(s);
+            cursor.height = y = vmsvga_fifo_read(s);
+            vmsvga_fifo_read(s);
+            cursor.bpp = vmsvga_fifo_read(s);
+
+            args = SVGA_BITMAP_SIZE(x, y) + SVGA_PIXMAP_SIZE(x, y, cursor.bpp);
+            if (SVGA_BITMAP_SIZE(x, y) > sizeof cursor.mask ||
+                SVGA_PIXMAP_SIZE(x, y, cursor.bpp) > sizeof cursor.image) {
+                    goto badcmd;
+            }
+
+            len -= args;
+            if (len < 0) {
+                goto rewind;
+            }
+
+            for (args = 0; args < SVGA_BITMAP_SIZE(x, y); args++) {
+                cursor.mask[args] = vmsvga_fifo_read_raw(s);
+            }
+            for (args = 0; args < SVGA_PIXMAP_SIZE(x, y, cursor.bpp); args++) {
+                cursor.image[args] = vmsvga_fifo_read_raw(s);
+            }
+#ifdef HW_MOUSE_ACCEL
+            vmsvga_cursor_define(s, &cursor);
+            break;
+#else
+            args = 0;
+            goto badcmd;
+#endif
+
+        /*
+         * Other commands that we at least know the number of arguments
+         * for so we can avoid FIFO desync if driver uses them illegally.
+         */
+        case SVGA_CMD_DEFINE_ALPHA_CURSOR:
+            len -= 6;
+            if (len < 0) {
+                goto rewind;
+            }
+            vmsvga_fifo_read(s);
+            vmsvga_fifo_read(s);
+            vmsvga_fifo_read(s);
+            x = vmsvga_fifo_read(s);
+            y = vmsvga_fifo_read(s);
+            args = x * y;
+            goto badcmd;
+        case SVGA_CMD_RECT_ROP_FILL:
+            args = 6;
+            goto badcmd;
+        case SVGA_CMD_RECT_ROP_COPY:
+            args = 7;
+            goto badcmd;
+        case SVGA_CMD_DRAW_GLYPH_CLIPPED:
+            len -= 4;
+            if (len < 0) {
+                goto rewind;
+            }
+            vmsvga_fifo_read(s);
+            vmsvga_fifo_read(s);
+            args = 7 + (vmsvga_fifo_read(s) >> 2);
+            goto badcmd;
+        case SVGA_CMD_SURFACE_ALPHA_BLEND:
+            args = 12;
+            goto badcmd;
+
+        /*
+         * Other commands that are not listed as depending on any
+         * CAPABILITIES bits, but are not described in the README either.
+         */
+        case SVGA_CMD_SURFACE_FILL:
+        case SVGA_CMD_SURFACE_COPY:
+        case SVGA_CMD_FRONT_ROP_FILL:
+        case SVGA_CMD_FENCE:
+        case SVGA_CMD_INVALID_CMD:
+            break; /* Nop */
+
+        default:
+            args = 0;
+        badcmd:
+            len -= args;
+            if (len < 0) {
+                goto rewind;
+            }
+            while (args--) {
+                vmsvga_fifo_read(s);
+            }
+            printf("%s: Unknown command 0x%02x in SVGA command FIFO\n",
+                   __func__, cmd);
+            break;
+
+        rewind:
+            s->cmd->stop = cmd_start;
+            break;
+        }
+    }
+
+    s->syncing = 0;
+}
+
+static uint32_t vmsvga_index_read(void *opaque, uint32_t address)
+{
+    struct vmsvga_state_s *s = opaque;
+
+    return s->index;
+}
+
+static void vmsvga_index_write(void *opaque, uint32_t address, uint32_t index)
+{
+    struct vmsvga_state_s *s = opaque;
+
+    s->index = index;
+}
+
+static uint32_t vmsvga_value_read(void *opaque, uint32_t address)
+{
+    uint32_t caps;
+    struct vmsvga_state_s *s = opaque;
+    DisplaySurface *surface = qemu_console_surface(s->vga.con);
+
+    switch (s->index) {
+    case SVGA_REG_ID:
+        return s->svgaid;
+
+    case SVGA_REG_ENABLE:
+        return s->enable;
+
+    case SVGA_REG_WIDTH:
+        return surface_width(surface);
+
+    case SVGA_REG_HEIGHT:
+        return surface_height(surface);
+
+    case SVGA_REG_MAX_WIDTH:
+        return SVGA_MAX_WIDTH;
+
+    case SVGA_REG_MAX_HEIGHT:
+        return SVGA_MAX_HEIGHT;
+
+    case SVGA_REG_DEPTH:
+        return s->depth;
+
+    case SVGA_REG_BITS_PER_PIXEL:
+        return (s->depth + 7) & ~7;
+
+    case SVGA_REG_PSEUDOCOLOR:
+        return 0x0;
+
+    case SVGA_REG_RED_MASK:
+        return surface->pf.rmask;
+
+    case SVGA_REG_GREEN_MASK:
+        return surface->pf.gmask;
+
+    case SVGA_REG_BLUE_MASK:
+        return surface->pf.bmask;
+
+    case SVGA_REG_BYTES_PER_LINE:
+        return s->bypp * s->new_width;
+
+    case SVGA_REG_FB_START: {
+        struct pci_vmsvga_state_s *pci_vmsvga
+            = container_of(s, struct pci_vmsvga_state_s, chip);
+        return pci_get_bar_addr(&pci_vmsvga->card, 1);
+    }
+
+    case SVGA_REG_FB_OFFSET:
+        return 0x0;
+
+    case SVGA_REG_VRAM_SIZE:
+        return s->vga.vram_size; /* No physical VRAM besides the framebuffer */
+
+    case SVGA_REG_FB_SIZE:
+        return s->vga.vram_size;
+
+    case SVGA_REG_CAPABILITIES:
+        caps = SVGA_CAP_NONE;
+#ifdef HW_RECT_ACCEL
+        caps |= SVGA_CAP_RECT_COPY;
+#endif
+#ifdef HW_FILL_ACCEL
+        caps |= SVGA_CAP_RECT_FILL;
+#endif
+#ifdef HW_MOUSE_ACCEL
+        if (dpy_cursor_define_supported(s->vga.con)) {
+            caps |= SVGA_CAP_CURSOR | SVGA_CAP_CURSOR_BYPASS_2 |
+                    SVGA_CAP_CURSOR_BYPASS;
+        }
+#endif
+        return caps;
+
+    case SVGA_REG_MEM_START: {
+        struct pci_vmsvga_state_s *pci_vmsvga
+            = container_of(s, struct pci_vmsvga_state_s, chip);
+        return pci_get_bar_addr(&pci_vmsvga->card, 2);
+    }
+
+    case SVGA_REG_MEM_SIZE:
+        return s->fifo_size;
+
+    case SVGA_REG_CONFIG_DONE:
+        return s->config;
+
+    case SVGA_REG_SYNC:
+    case SVGA_REG_BUSY:
+        return s->syncing;
+
+    case SVGA_REG_GUEST_ID:
+        return s->guest;
+
+    case SVGA_REG_CURSOR_ID:
+        return s->cursor.id;
+
+    case SVGA_REG_CURSOR_X:
+        return s->cursor.x;
+
+    case SVGA_REG_CURSOR_Y:
+        return s->cursor.x;
+
+    case SVGA_REG_CURSOR_ON:
+        return s->cursor.on;
+
+    case SVGA_REG_HOST_BITS_PER_PIXEL:
+        return (s->depth + 7) & ~7;
+
+    case SVGA_REG_SCRATCH_SIZE:
+        return s->scratch_size;
+
+    case SVGA_REG_MEM_REGS:
+    case SVGA_REG_NUM_DISPLAYS:
+    case SVGA_REG_PITCHLOCK:
+    case SVGA_PALETTE_BASE ... SVGA_PALETTE_END:
+        return 0;
+
+    default:
+        if (s->index >= SVGA_SCRATCH_BASE &&
+            s->index < SVGA_SCRATCH_BASE + s->scratch_size) {
+            return s->scratch[s->index - SVGA_SCRATCH_BASE];
+        }
+        printf("%s: Bad register %02x\n", __func__, s->index);
+    }
+
+    return 0;
+}
+
+static void vmsvga_value_write(void *opaque, uint32_t address, uint32_t value)
+{
+    struct vmsvga_state_s *s = opaque;
+
+    switch (s->index) {
+    case SVGA_REG_ID:
+        if (value == SVGA_ID_2 || value == SVGA_ID_1 || value == SVGA_ID_0) {
+            s->svgaid = value;
+        }
+        break;
+
+    case SVGA_REG_ENABLE:
+        s->enable = !!value;
+        s->invalidated = 1;
+        s->vga.invalidate(&s->vga);
+        if (s->enable && s->config) {
+            vga_dirty_log_stop(&s->vga);
+        } else {
+            vga_dirty_log_start(&s->vga);
+        }
+        break;
+
+    case SVGA_REG_WIDTH:
+        if (value <= SVGA_MAX_WIDTH) {
+            s->new_width = value;
+            s->invalidated = 1;
+        } else {
+            printf("%s: Bad width: %i\n", __func__, value);
+        }
+        break;
+
+    case SVGA_REG_HEIGHT:
+        if (value <= SVGA_MAX_HEIGHT) {
+            s->new_height = value;
+            s->invalidated = 1;
+        } else {
+            printf("%s: Bad height: %i\n", __func__, value);
+        }
+        break;
+
+    case SVGA_REG_BITS_PER_PIXEL:
+        if (value != s->depth) {
+            printf("%s: Bad bits per pixel: %i bits\n", __func__, value);
+            s->config = 0;
+        }
+        break;
+
+    case SVGA_REG_CONFIG_DONE:
+        if (value) {
+            s->fifo = (uint32_t *) s->fifo_ptr;
+            /* Check range and alignment.  */
+            if ((CMD(min) | CMD(max) | CMD(next_cmd) | CMD(stop)) & 3) {
+                break;
+            }
+            if (CMD(min) < (uint8_t *) s->cmd->fifo - (uint8_t *) s->fifo) {
+                break;
+            }
+            if (CMD(max) > SVGA_FIFO_SIZE) {
+                break;
+            }
+            if (CMD(max) < CMD(min) + 10 * 1024) {
+                break;
+            }
+            vga_dirty_log_stop(&s->vga);
+        }
+        s->config = !!value;
+        break;
+
+    case SVGA_REG_SYNC:
+        s->syncing = 1;
+        vmsvga_fifo_run(s); /* Or should we just wait for update_display? */
+        break;
+
+    case SVGA_REG_GUEST_ID:
+        s->guest = value;
+#ifdef VERBOSE
+        if (value >= GUEST_OS_BASE && value < GUEST_OS_BASE +
+            ARRAY_SIZE(vmsvga_guest_id)) {
+            printf("%s: guest runs %s.\n", __func__,
+                   vmsvga_guest_id[value - GUEST_OS_BASE]);
+        }
+#endif
+        break;
+
+    case SVGA_REG_CURSOR_ID:
+        s->cursor.id = value;
+        break;
+
+    case SVGA_REG_CURSOR_X:
+        s->cursor.x = value;
+        break;
+
+    case SVGA_REG_CURSOR_Y:
+        s->cursor.y = value;
+        break;
+
+    case SVGA_REG_CURSOR_ON:
+        s->cursor.on |= (value == SVGA_CURSOR_ON_SHOW);
+        s->cursor.on &= (value != SVGA_CURSOR_ON_HIDE);
+#ifdef HW_MOUSE_ACCEL
+        if (value <= SVGA_CURSOR_ON_SHOW) {
+            dpy_mouse_set(s->vga.con, s->cursor.x, s->cursor.y, s->cursor.on);
+        }
+#endif
+        break;
+
+    case SVGA_REG_DEPTH:
+    case SVGA_REG_MEM_REGS:
+    case SVGA_REG_NUM_DISPLAYS:
+    case SVGA_REG_PITCHLOCK:
+    case SVGA_PALETTE_BASE ... SVGA_PALETTE_END:
+        break;
+
+    default:
+        if (s->index >= SVGA_SCRATCH_BASE &&
+                s->index < SVGA_SCRATCH_BASE + s->scratch_size) {
+            s->scratch[s->index - SVGA_SCRATCH_BASE] = value;
+            break;
+        }
+        printf("%s: Bad register %02x\n", __func__, s->index);
+    }
+}
+
+static uint32_t vmsvga_bios_read(void *opaque, uint32_t address)
+{
+    printf("%s: what are we supposed to return?\n", __func__);
+    return 0xcafe;
+}
+
+static void vmsvga_bios_write(void *opaque, uint32_t address, uint32_t data)
+{
+    printf("%s: what are we supposed to do with (%08x)?\n", __func__, data);
+}
+
+static inline void vmsvga_check_size(struct vmsvga_state_s *s)
+{
+    DisplaySurface *surface = qemu_console_surface(s->vga.con);
+
+    if (s->new_width != surface_width(surface) ||
+        s->new_height != surface_height(surface)) {
+        qemu_console_resize(s->vga.con, s->new_width, s->new_height);
+        s->invalidated = 1;
+    }
+}
+
+static void vmsvga_update_display(void *opaque)
+{
+    struct vmsvga_state_s *s = opaque;
+    DisplaySurface *surface = qemu_console_surface(s->vga.con);
+    bool dirty = false;
+
+    if (!s->enable) {
+        s->vga.update(&s->vga);
+        return;
+    }
+
+    vmsvga_check_size(s);
+
+    vmsvga_fifo_run(s);
+    vmsvga_update_rect_flush(s);
+
+    /*
+     * Is it more efficient to look at vram VGA-dirty bits or wait
+     * for the driver to issue SVGA_CMD_UPDATE?
+     */
+    if (memory_region_is_logging(&s->vga.vram)) {
+        vga_sync_dirty_bitmap(&s->vga);
+        dirty = memory_region_get_dirty(&s->vga.vram, 0,
+            surface_stride(surface) * surface_height(surface),
+            DIRTY_MEMORY_VGA);
+    }
+    if (s->invalidated || dirty) {
+        s->invalidated = 0;
+        memcpy(surface_data(surface), s->vga.vram_ptr,
+               surface_stride(surface) * surface_height(surface));
+        dpy_gfx_update(s->vga.con, 0, 0,
+                   surface_width(surface), surface_height(surface));
+    }
+    if (dirty) {
+        memory_region_reset_dirty(&s->vga.vram, 0,
+            surface_stride(surface) * surface_height(surface),
+            DIRTY_MEMORY_VGA);
+    }
+}
+
+static void vmsvga_reset(DeviceState *dev)
+{
+    struct pci_vmsvga_state_s *pci =
+        DO_UPCAST(struct pci_vmsvga_state_s, card.qdev, dev);
+    struct vmsvga_state_s *s = &pci->chip;
+
+    s->index = 0;
+    s->enable = 0;
+    s->config = 0;
+    s->svgaid = SVGA_ID;
+    s->cursor.on = 0;
+    s->redraw_fifo_first = 0;
+    s->redraw_fifo_last = 0;
+    s->syncing = 0;
+
+    vga_dirty_log_start(&s->vga);
+}
+
+static void vmsvga_invalidate_display(void *opaque)
+{
+    struct vmsvga_state_s *s = opaque;
+    if (!s->enable) {
+        s->vga.invalidate(&s->vga);
+        return;
+    }
+
+    s->invalidated = 1;
+}
+
+/* save the vga display in a PPM image even if no display is
+   available */
+static void vmsvga_screen_dump(void *opaque, const char *filename, bool cswitch,
+                               Error **errp)
+{
+    struct vmsvga_state_s *s = opaque;
+    DisplaySurface *surface = qemu_console_surface(s->vga.con);
+
+    if (!s->enable) {
+        s->vga.screen_dump(&s->vga, filename, cswitch, errp);
+        return;
+    }
+
+    if (surface_bits_per_pixel(surface) == 32) {
+        DisplaySurface *ds = qemu_create_displaysurface_from(
+                                 surface_width(surface),
+                                 surface_height(surface),
+                                 32,
+                                 surface_stride(surface),
+                                 s->vga.vram_ptr, false);
+        ppm_save(filename, ds, errp);
+        g_free(ds);
+    }
+}
+
+static void vmsvga_text_update(void *opaque, console_ch_t *chardata)
+{
+    struct vmsvga_state_s *s = opaque;
+
+    if (s->vga.text_update) {
+        s->vga.text_update(&s->vga, chardata);
+    }
+}
+
+static int vmsvga_post_load(void *opaque, int version_id)
+{
+    struct vmsvga_state_s *s = opaque;
+
+    s->invalidated = 1;
+    if (s->config) {
+        s->fifo = (uint32_t *) s->fifo_ptr;
+    }
+    return 0;
+}
+
+static const VMStateDescription vmstate_vmware_vga_internal = {
+    .name = "vmware_vga_internal",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .post_load = vmsvga_post_load,
+    .fields      = (VMStateField[]) {
+        VMSTATE_INT32_EQUAL(depth, struct vmsvga_state_s),
+        VMSTATE_INT32(enable, struct vmsvga_state_s),
+        VMSTATE_INT32(config, struct vmsvga_state_s),
+        VMSTATE_INT32(cursor.id, struct vmsvga_state_s),
+        VMSTATE_INT32(cursor.x, struct vmsvga_state_s),
+        VMSTATE_INT32(cursor.y, struct vmsvga_state_s),
+        VMSTATE_INT32(cursor.on, struct vmsvga_state_s),
+        VMSTATE_INT32(index, struct vmsvga_state_s),
+        VMSTATE_VARRAY_INT32(scratch, struct vmsvga_state_s,
+                             scratch_size, 0, vmstate_info_uint32, uint32_t),
+        VMSTATE_INT32(new_width, struct vmsvga_state_s),
+        VMSTATE_INT32(new_height, struct vmsvga_state_s),
+        VMSTATE_UINT32(guest, struct vmsvga_state_s),
+        VMSTATE_UINT32(svgaid, struct vmsvga_state_s),
+        VMSTATE_INT32(syncing, struct vmsvga_state_s),
+        VMSTATE_UNUSED(4), /* was fb_size */
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_vmware_vga = {
+    .name = "vmware_vga",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields      = (VMStateField[]) {
+        VMSTATE_PCI_DEVICE(card, struct pci_vmsvga_state_s),
+        VMSTATE_STRUCT(chip, struct pci_vmsvga_state_s, 0,
+                       vmstate_vmware_vga_internal, struct vmsvga_state_s),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void vmsvga_init(struct vmsvga_state_s *s,
+                        MemoryRegion *address_space, MemoryRegion *io)
+{
+    DisplaySurface *surface;
+
+    s->scratch_size = SVGA_SCRATCH_SIZE;
+    s->scratch = g_malloc(s->scratch_size * 4);
+
+    s->vga.con = graphic_console_init(vmsvga_update_display,
+                                      vmsvga_invalidate_display,
+                                      vmsvga_screen_dump,
+                                      vmsvga_text_update, s);
+    surface = qemu_console_surface(s->vga.con);
+
+    s->fifo_size = SVGA_FIFO_SIZE;
+    memory_region_init_ram(&s->fifo_ram, "vmsvga.fifo", s->fifo_size);
+    vmstate_register_ram_global(&s->fifo_ram);
+    s->fifo_ptr = memory_region_get_ram_ptr(&s->fifo_ram);
+
+    vga_common_init(&s->vga);
+    vga_init(&s->vga, address_space, io, true);
+    vmstate_register(NULL, 0, &vmstate_vga_common, &s->vga);
+    /* Save some values here in case they are changed later.
+     * This is suspicious and needs more though why it is needed. */
+    s->depth = surface_bits_per_pixel(surface);
+    s->bypp = surface_bytes_per_pixel(surface);
+}
+
+static uint64_t vmsvga_io_read(void *opaque, hwaddr addr, unsigned size)
+{
+    struct vmsvga_state_s *s = opaque;
+
+    switch (addr) {
+    case SVGA_IO_MUL * SVGA_INDEX_PORT: return vmsvga_index_read(s, addr);
+    case SVGA_IO_MUL * SVGA_VALUE_PORT: return vmsvga_value_read(s, addr);
+    case SVGA_IO_MUL * SVGA_BIOS_PORT: return vmsvga_bios_read(s, addr);
+    default: return -1u;
+    }
+}
+
+static void vmsvga_io_write(void *opaque, hwaddr addr,
+                            uint64_t data, unsigned size)
+{
+    struct vmsvga_state_s *s = opaque;
+
+    switch (addr) {
+    case SVGA_IO_MUL * SVGA_INDEX_PORT:
+        vmsvga_index_write(s, addr, data);
+        break;
+    case SVGA_IO_MUL * SVGA_VALUE_PORT:
+        vmsvga_value_write(s, addr, data);
+        break;
+    case SVGA_IO_MUL * SVGA_BIOS_PORT:
+        vmsvga_bios_write(s, addr, data);
+        break;
+    }
+}
+
+static const MemoryRegionOps vmsvga_io_ops = {
+    .read = vmsvga_io_read,
+    .write = vmsvga_io_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static int pci_vmsvga_initfn(PCIDevice *dev)
+{
+    struct pci_vmsvga_state_s *s =
+        DO_UPCAST(struct pci_vmsvga_state_s, card, dev);
+
+    s->card.config[PCI_CACHE_LINE_SIZE] = 0x08;         /* Cache line size */
+    s->card.config[PCI_LATENCY_TIMER] = 0x40;           /* Latency timer */
+    s->card.config[PCI_INTERRUPT_LINE] = 0xff;          /* End */
+
+    memory_region_init_io(&s->io_bar, &vmsvga_io_ops, &s->chip,
+                          "vmsvga-io", 0x10);
+    memory_region_set_flush_coalesced(&s->io_bar);
+    pci_register_bar(&s->card, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io_bar);
+
+    vmsvga_init(&s->chip, pci_address_space(dev), pci_address_space_io(dev));
+
+    pci_register_bar(&s->card, 1, PCI_BASE_ADDRESS_MEM_PREFETCH,
+                     &s->chip.vga.vram);
+    pci_register_bar(&s->card, 2, PCI_BASE_ADDRESS_MEM_PREFETCH,
+                     &s->chip.fifo_ram);
+
+    if (!dev->rom_bar) {
+        /* compatibility with pc-0.13 and older */
+        vga_init_vbe(&s->chip.vga, pci_address_space(dev));
+    }
+
+    return 0;
+}
+
+static Property vga_vmware_properties[] = {
+    DEFINE_PROP_UINT32("vgamem_mb", struct pci_vmsvga_state_s,
+                       chip.vga.vram_size_mb, 16),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void vmsvga_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->no_hotplug = 1;
+    k->init = pci_vmsvga_initfn;
+    k->romfile = "vgabios-vmware.bin";
+    k->vendor_id = PCI_VENDOR_ID_VMWARE;
+    k->device_id = SVGA_PCI_DEVICE_ID;
+    k->class_id = PCI_CLASS_DISPLAY_VGA;
+    k->subsystem_vendor_id = PCI_VENDOR_ID_VMWARE;
+    k->subsystem_id = SVGA_PCI_DEVICE_ID;
+    dc->reset = vmsvga_reset;
+    dc->vmsd = &vmstate_vmware_vga;
+    dc->props = vga_vmware_properties;
+}
+
+static const 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_types(void)
+{
+    type_register_static(&vmsvga_info);
+}
+
+type_init(vmsvga_register_types)
diff --git a/hw/display/xenfb.c b/hw/display/xenfb.c
new file mode 100644 (file)
index 0000000..8e42661
--- /dev/null
@@ -0,0 +1,1021 @@
+/*
+ *  xen paravirt framebuffer backend
+ *
+ *  Copyright IBM, Corp. 2005-2006
+ *  Copyright Red Hat, Inc. 2006-2008
+ *
+ *  Authors:
+ *       Anthony Liguori <aliguori@us.ibm.com>,
+ *       Markus Armbruster <armbru@redhat.com>,
+ *       Daniel P. Berrange <berrange@redhat.com>,
+ *       Pat Campbell <plc@novell.com>,
+ *       Gerd Hoffmann <kraxel@redhat.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; under version 2 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
+ *  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 <stdarg.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+
+#include "hw/hw.h"
+#include "ui/console.h"
+#include "char/char.h"
+#include "hw/xen/xen_backend.h"
+
+#include <xen/event_channel.h>
+#include <xen/io/fbif.h>
+#include <xen/io/kbdif.h>
+#include <xen/io/protocols.h>
+
+#ifndef BTN_LEFT
+#define BTN_LEFT 0x110 /* from <linux/input.h> */
+#endif
+
+/* -------------------------------------------------------------------- */
+
+struct common {
+    struct XenDevice  xendev;  /* must be first */
+    void              *page;
+    QemuConsole       *con;
+};
+
+struct XenInput {
+    struct common c;
+    int abs_pointer_wanted; /* Whether guest supports absolute pointer */
+    int button_state;       /* Last seen pointer button state */
+    int extended;
+    QEMUPutMouseEntry *qmouse;
+};
+
+#define UP_QUEUE 8
+
+struct XenFB {
+    struct common     c;
+    size_t            fb_len;
+    int               row_stride;
+    int               depth;
+    int               width;
+    int               height;
+    int               offset;
+    void              *pixels;
+    int               fbpages;
+    int               feature_update;
+    int               refresh_period;
+    int               bug_trigger;
+    int               have_console;
+    int               do_resize;
+
+    struct {
+       int x,y,w,h;
+    } up_rects[UP_QUEUE];
+    int               up_count;
+    int               up_fullscreen;
+};
+
+/* -------------------------------------------------------------------- */
+
+static int common_bind(struct common *c)
+{
+    int mfn;
+
+    if (xenstore_read_fe_int(&c->xendev, "page-ref", &mfn) == -1)
+       return -1;
+    if (xenstore_read_fe_int(&c->xendev, "event-channel", &c->xendev.remote_port) == -1)
+       return -1;
+
+    c->page = xc_map_foreign_range(xen_xc, c->xendev.dom,
+                                  XC_PAGE_SIZE,
+                                  PROT_READ | PROT_WRITE, mfn);
+    if (c->page == NULL)
+       return -1;
+
+    xen_be_bind_evtchn(&c->xendev);
+    xen_be_printf(&c->xendev, 1, "ring mfn %d, remote-port %d, local-port %d\n",
+                 mfn, c->xendev.remote_port, c->xendev.local_port);
+
+    return 0;
+}
+
+static void common_unbind(struct common *c)
+{
+    xen_be_unbind_evtchn(&c->xendev);
+    if (c->page) {
+       munmap(c->page, XC_PAGE_SIZE);
+       c->page = NULL;
+    }
+}
+
+/* -------------------------------------------------------------------- */
+
+#if 0
+/*
+ * These two tables are not needed any more, but left in here
+ * intentionally as documentation, to show how scancode2linux[]
+ * was generated.
+ *
+ * Tables to map from scancode to Linux input layer keycode.
+ * Scancodes are hardware-specific.  These maps assumes a
+ * standard AT or PS/2 keyboard which is what QEMU feeds us.
+ */
+const unsigned char atkbd_set2_keycode[512] = {
+
+     0, 67, 65, 63, 61, 59, 60, 88,  0, 68, 66, 64, 62, 15, 41,117,
+     0, 56, 42, 93, 29, 16,  2,  0,  0,  0, 44, 31, 30, 17,  3,  0,
+     0, 46, 45, 32, 18,  5,  4, 95,  0, 57, 47, 33, 20, 19,  6,183,
+     0, 49, 48, 35, 34, 21,  7,184,  0,  0, 50, 36, 22,  8,  9,185,
+     0, 51, 37, 23, 24, 11, 10,  0,  0, 52, 53, 38, 39, 25, 12,  0,
+     0, 89, 40,  0, 26, 13,  0,  0, 58, 54, 28, 27,  0, 43,  0, 85,
+     0, 86, 91, 90, 92,  0, 14, 94,  0, 79,124, 75, 71,121,  0,  0,
+    82, 83, 80, 76, 77, 72,  1, 69, 87, 78, 81, 74, 55, 73, 70, 99,
+
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    217,100,255,  0, 97,165,  0,  0,156,  0,  0,  0,  0,  0,  0,125,
+    173,114,  0,113,  0,  0,  0,126,128,  0,  0,140,  0,  0,  0,127,
+    159,  0,115,  0,164,  0,  0,116,158,  0,150,166,  0,  0,  0,142,
+    157,  0,  0,  0,  0,  0,  0,  0,155,  0, 98,  0,  0,163,  0,  0,
+    226,  0,  0,  0,  0,  0,  0,  0,  0,255, 96,  0,  0,  0,143,  0,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,107,  0,105,102,  0,  0,112,
+    110,111,108,112,106,103,  0,119,  0,118,109,  0, 99,104,119,  0,
+
+};
+
+const unsigned char atkbd_unxlate_table[128] = {
+
+      0,118, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85,102, 13,
+     21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 20, 28, 27,
+     35, 43, 52, 51, 59, 66, 75, 76, 82, 14, 18, 93, 26, 34, 33, 42,
+     50, 49, 58, 65, 73, 74, 89,124, 17, 41, 88,  5,  6,  4, 12,  3,
+     11,  2, 10,  1,  9,119,126,108,117,125,123,107,115,116,121,105,
+    114,122,112,113,127, 96, 97,120,  7, 15, 23, 31, 39, 47, 55, 63,
+     71, 79, 86, 94,  8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 87,111,
+     19, 25, 57, 81, 83, 92, 95, 98, 99,100,101,103,104,106,109,110
+
+};
+#endif
+
+/*
+ * for (i = 0; i < 128; i++) {
+ *     scancode2linux[i] = atkbd_set2_keycode[atkbd_unxlate_table[i]];
+ *     scancode2linux[i | 0x80] = atkbd_set2_keycode[atkbd_unxlate_table[i] | 0x80];
+ * }
+ */
+static const unsigned char scancode2linux[512] = {
+      0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
+     16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+     32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+     48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+     64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+     80, 81, 82, 83, 99,  0, 86, 87, 88,117,  0,  0, 95,183,184,185,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     93,  0,  0, 89,  0,  0, 85, 91, 90, 92,  0, 94,  0,124,121,  0,
+
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    165,  0,  0,  0,  0,  0,  0,  0,  0,163,  0,  0, 96, 97,  0,  0,
+    113,140,164,  0,166,  0,  0,  0,  0,  0,255,  0,  0,  0,114,  0,
+    115,  0,150,  0,  0, 98,255, 99,100,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0,  0,  0,119,119,102,103,104,  0,105,112,106,118,107,
+    108,109,110,111,  0,  0,  0,  0,  0,  0,  0,125,126,127,116,142,
+      0,  0,  0,143,  0,217,156,173,128,159,158,157,155,226,  0,112,
+      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+};
+
+/* Send an event to the keyboard frontend driver */
+static int xenfb_kbd_event(struct XenInput *xenfb,
+                          union xenkbd_in_event *event)
+{
+    struct xenkbd_page *page = xenfb->c.page;
+    uint32_t prod;
+
+    if (xenfb->c.xendev.be_state != XenbusStateConnected)
+       return 0;
+    if (!page)
+        return 0;
+
+    prod = page->in_prod;
+    if (prod - page->in_cons == XENKBD_IN_RING_LEN) {
+       errno = EAGAIN;
+       return -1;
+    }
+
+    xen_mb();          /* ensure ring space available */
+    XENKBD_IN_RING_REF(page, prod) = *event;
+    xen_wmb();         /* ensure ring contents visible */
+    page->in_prod = prod + 1;
+    return xen_be_send_notify(&xenfb->c.xendev);
+}
+
+/* Send a keyboard (or mouse button) event */
+static int xenfb_send_key(struct XenInput *xenfb, bool down, int keycode)
+{
+    union xenkbd_in_event event;
+
+    memset(&event, 0, XENKBD_IN_EVENT_SIZE);
+    event.type = XENKBD_TYPE_KEY;
+    event.key.pressed = down ? 1 : 0;
+    event.key.keycode = keycode;
+
+    return xenfb_kbd_event(xenfb, &event);
+}
+
+/* Send a relative mouse movement event */
+static int xenfb_send_motion(struct XenInput *xenfb,
+                            int rel_x, int rel_y, int rel_z)
+{
+    union xenkbd_in_event event;
+
+    memset(&event, 0, XENKBD_IN_EVENT_SIZE);
+    event.type = XENKBD_TYPE_MOTION;
+    event.motion.rel_x = rel_x;
+    event.motion.rel_y = rel_y;
+#if __XEN_LATEST_INTERFACE_VERSION__ >= 0x00030207
+    event.motion.rel_z = rel_z;
+#endif
+
+    return xenfb_kbd_event(xenfb, &event);
+}
+
+/* Send an absolute mouse movement event */
+static int xenfb_send_position(struct XenInput *xenfb,
+                              int abs_x, int abs_y, int z)
+{
+    union xenkbd_in_event event;
+
+    memset(&event, 0, XENKBD_IN_EVENT_SIZE);
+    event.type = XENKBD_TYPE_POS;
+    event.pos.abs_x = abs_x;
+    event.pos.abs_y = abs_y;
+#if __XEN_LATEST_INTERFACE_VERSION__ == 0x00030207
+    event.pos.abs_z = z;
+#endif
+#if __XEN_LATEST_INTERFACE_VERSION__ >= 0x00030208
+    event.pos.rel_z = z;
+#endif
+
+    return xenfb_kbd_event(xenfb, &event);
+}
+
+/*
+ * Send a key event from the client to the guest OS
+ * QEMU gives us a raw scancode from an AT / PS/2 style keyboard.
+ * We have to turn this into a Linux Input layer keycode.
+ *
+ * Extra complexity from the fact that with extended scancodes
+ * (like those produced by arrow keys) this method gets called
+ * twice, but we only want to send a single event. So we have to
+ * track the '0xe0' scancode state & collapse the extended keys
+ * as needed.
+ *
+ * Wish we could just send scancodes straight to the guest which
+ * already has code for dealing with this...
+ */
+static void xenfb_key_event(void *opaque, int scancode)
+{
+    struct XenInput *xenfb = opaque;
+    int down = 1;
+
+    if (scancode == 0xe0) {
+       xenfb->extended = 1;
+       return;
+    } else if (scancode & 0x80) {
+       scancode &= 0x7f;
+       down = 0;
+    }
+    if (xenfb->extended) {
+       scancode |= 0x80;
+       xenfb->extended = 0;
+    }
+    xenfb_send_key(xenfb, down, scancode2linux[scancode]);
+}
+
+/*
+ * Send a mouse event from the client to the guest OS
+ *
+ * The QEMU mouse can be in either relative, or absolute mode.
+ * Movement is sent separately from button state, which has to
+ * be encoded as virtual key events. We also don't actually get
+ * given any button up/down events, so have to track changes in
+ * the button state.
+ */
+static void xenfb_mouse_event(void *opaque,
+                             int dx, int dy, int dz, int button_state)
+{
+    struct XenInput *xenfb = opaque;
+    DisplaySurface *surface = qemu_console_surface(xenfb->c.con);
+    int dw = surface_width(surface);
+    int dh = surface_height(surface);
+    int i;
+
+    if (xenfb->abs_pointer_wanted)
+       xenfb_send_position(xenfb,
+                           dx * (dw - 1) / 0x7fff,
+                           dy * (dh - 1) / 0x7fff,
+                           dz);
+    else
+       xenfb_send_motion(xenfb, dx, dy, dz);
+
+    for (i = 0 ; i < 8 ; i++) {
+       int lastDown = xenfb->button_state & (1 << i);
+       int down = button_state & (1 << i);
+       if (down == lastDown)
+           continue;
+
+       if (xenfb_send_key(xenfb, down, BTN_LEFT+i) < 0)
+           return;
+    }
+    xenfb->button_state = button_state;
+}
+
+static int input_init(struct XenDevice *xendev)
+{
+    xenstore_write_be_int(xendev, "feature-abs-pointer", 1);
+    return 0;
+}
+
+static int input_initialise(struct XenDevice *xendev)
+{
+    struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
+    int rc;
+
+    if (!in->c.con) {
+        xen_be_printf(xendev, 1, "ds not set (yet)\n");
+        return -1;
+    }
+
+    rc = common_bind(&in->c);
+    if (rc != 0)
+       return rc;
+
+    qemu_add_kbd_event_handler(xenfb_key_event, in);
+    return 0;
+}
+
+static void input_connected(struct XenDevice *xendev)
+{
+    struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
+
+    if (xenstore_read_fe_int(xendev, "request-abs-pointer",
+                             &in->abs_pointer_wanted) == -1) {
+        in->abs_pointer_wanted = 0;
+    }
+
+    if (in->qmouse) {
+        qemu_remove_mouse_event_handler(in->qmouse);
+    }
+    in->qmouse = qemu_add_mouse_event_handler(xenfb_mouse_event, in,
+                                             in->abs_pointer_wanted,
+                                             "Xen PVFB Mouse");
+}
+
+static void input_disconnect(struct XenDevice *xendev)
+{
+    struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
+
+    if (in->qmouse) {
+       qemu_remove_mouse_event_handler(in->qmouse);
+       in->qmouse = NULL;
+    }
+    qemu_add_kbd_event_handler(NULL, NULL);
+    common_unbind(&in->c);
+}
+
+static void input_event(struct XenDevice *xendev)
+{
+    struct XenInput *xenfb = container_of(xendev, struct XenInput, c.xendev);
+    struct xenkbd_page *page = xenfb->c.page;
+
+    /* We don't understand any keyboard events, so just ignore them. */
+    if (page->out_prod == page->out_cons)
+       return;
+    page->out_cons = page->out_prod;
+    xen_be_send_notify(&xenfb->c.xendev);
+}
+
+/* -------------------------------------------------------------------- */
+
+static void xenfb_copy_mfns(int mode, int count, unsigned long *dst, void *src)
+{
+    uint32_t *src32 = src;
+    uint64_t *src64 = src;
+    int i;
+
+    for (i = 0; i < count; i++)
+       dst[i] = (mode == 32) ? src32[i] : src64[i];
+}
+
+static int xenfb_map_fb(struct XenFB *xenfb)
+{
+    struct xenfb_page *page = xenfb->c.page;
+    char *protocol = xenfb->c.xendev.protocol;
+    int n_fbdirs;
+    unsigned long *pgmfns = NULL;
+    unsigned long *fbmfns = NULL;
+    void *map, *pd;
+    int mode, ret = -1;
+
+    /* default to native */
+    pd = page->pd;
+    mode = sizeof(unsigned long) * 8;
+
+    if (!protocol) {
+       /*
+        * Undefined protocol, some guesswork needed.
+        *
+        * Old frontends which don't set the protocol use
+        * one page directory only, thus pd[1] must be zero.
+        * pd[1] of the 32bit struct layout and the lower
+        * 32 bits of pd[0] of the 64bit struct layout have
+        * the same location, so we can check that ...
+        */
+       uint32_t *ptr32 = NULL;
+       uint32_t *ptr64 = NULL;
+#if defined(__i386__)
+       ptr32 = (void*)page->pd;
+       ptr64 = ((void*)page->pd) + 4;
+#elif defined(__x86_64__)
+       ptr32 = ((void*)page->pd) - 4;
+       ptr64 = (void*)page->pd;
+#endif
+       if (ptr32) {
+           if (ptr32[1] == 0) {
+               mode = 32;
+               pd   = ptr32;
+           } else {
+               mode = 64;
+               pd   = ptr64;
+           }
+       }
+#if defined(__x86_64__)
+    } else if (strcmp(protocol, XEN_IO_PROTO_ABI_X86_32) == 0) {
+       /* 64bit dom0, 32bit domU */
+       mode = 32;
+       pd   = ((void*)page->pd) - 4;
+#elif defined(__i386__)
+    } else if (strcmp(protocol, XEN_IO_PROTO_ABI_X86_64) == 0) {
+       /* 32bit dom0, 64bit domU */
+       mode = 64;
+       pd   = ((void*)page->pd) + 4;
+#endif
+    }
+
+    if (xenfb->pixels) {
+        munmap(xenfb->pixels, xenfb->fbpages * XC_PAGE_SIZE);
+        xenfb->pixels = NULL;
+    }
+
+    xenfb->fbpages = (xenfb->fb_len + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
+    n_fbdirs = xenfb->fbpages * mode / 8;
+    n_fbdirs = (n_fbdirs + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
+
+    pgmfns = g_malloc0(sizeof(unsigned long) * n_fbdirs);
+    fbmfns = g_malloc0(sizeof(unsigned long) * xenfb->fbpages);
+
+    xenfb_copy_mfns(mode, n_fbdirs, pgmfns, pd);
+    map = xc_map_foreign_pages(xen_xc, xenfb->c.xendev.dom,
+                              PROT_READ, pgmfns, n_fbdirs);
+    if (map == NULL)
+       goto out;
+    xenfb_copy_mfns(mode, xenfb->fbpages, fbmfns, map);
+    munmap(map, n_fbdirs * XC_PAGE_SIZE);
+
+    xenfb->pixels = xc_map_foreign_pages(xen_xc, xenfb->c.xendev.dom,
+                                        PROT_READ | PROT_WRITE, fbmfns, xenfb->fbpages);
+    if (xenfb->pixels == NULL)
+       goto out;
+
+    ret = 0; /* all is fine */
+
+out:
+    g_free(pgmfns);
+    g_free(fbmfns);
+    return ret;
+}
+
+static int xenfb_configure_fb(struct XenFB *xenfb, size_t fb_len_lim,
+                             int width, int height, int depth,
+                             size_t fb_len, int offset, int row_stride)
+{
+    size_t mfn_sz = sizeof(*((struct xenfb_page *)0)->pd);
+    size_t pd_len = sizeof(((struct xenfb_page *)0)->pd) / mfn_sz;
+    size_t fb_pages = pd_len * XC_PAGE_SIZE / mfn_sz;
+    size_t fb_len_max = fb_pages * XC_PAGE_SIZE;
+    int max_width, max_height;
+
+    if (fb_len_lim > fb_len_max) {
+       xen_be_printf(&xenfb->c.xendev, 0, "fb size limit %zu exceeds %zu, corrected\n",
+                     fb_len_lim, fb_len_max);
+       fb_len_lim = fb_len_max;
+    }
+    if (fb_len_lim && fb_len > fb_len_lim) {
+       xen_be_printf(&xenfb->c.xendev, 0, "frontend fb size %zu limited to %zu\n",
+                     fb_len, fb_len_lim);
+       fb_len = fb_len_lim;
+    }
+    if (depth != 8 && depth != 16 && depth != 24 && depth != 32) {
+       xen_be_printf(&xenfb->c.xendev, 0, "can't handle frontend fb depth %d\n",
+                     depth);
+       return -1;
+    }
+    if (row_stride <= 0 || row_stride > fb_len) {
+       xen_be_printf(&xenfb->c.xendev, 0, "invalid frontend stride %d\n", row_stride);
+       return -1;
+    }
+    max_width = row_stride / (depth / 8);
+    if (width < 0 || width > max_width) {
+       xen_be_printf(&xenfb->c.xendev, 0, "invalid frontend width %d limited to %d\n",
+                     width, max_width);
+       width = max_width;
+    }
+    if (offset < 0 || offset >= fb_len) {
+       xen_be_printf(&xenfb->c.xendev, 0, "invalid frontend offset %d (max %zu)\n",
+                     offset, fb_len - 1);
+       return -1;
+    }
+    max_height = (fb_len - offset) / row_stride;
+    if (height < 0 || height > max_height) {
+       xen_be_printf(&xenfb->c.xendev, 0, "invalid frontend height %d limited to %d\n",
+                     height, max_height);
+       height = max_height;
+    }
+    xenfb->fb_len = fb_len;
+    xenfb->row_stride = row_stride;
+    xenfb->depth = depth;
+    xenfb->width = width;
+    xenfb->height = height;
+    xenfb->offset = offset;
+    xenfb->up_fullscreen = 1;
+    xenfb->do_resize = 1;
+    xen_be_printf(&xenfb->c.xendev, 1, "framebuffer %dx%dx%d offset %d stride %d\n",
+                 width, height, depth, offset, row_stride);
+    return 0;
+}
+
+/* A convenient function for munging pixels between different depths */
+#define BLT(SRC_T,DST_T,RSB,GSB,BSB,RDB,GDB,BDB)                        \
+    for (line = y ; line < (y+h) ; line++) {                           \
+       SRC_T *src = (SRC_T *)(xenfb->pixels                            \
+                              + xenfb->offset                          \
+                              + (line * xenfb->row_stride)             \
+                              + (x * xenfb->depth / 8));               \
+       DST_T *dst = (DST_T *)(data                                     \
+                              + (line * linesize)                      \
+                              + (x * bpp / 8));                        \
+       int col;                                                        \
+       const int RSS = 32 - (RSB + GSB + BSB);                         \
+       const int GSS = 32 - (GSB + BSB);                               \
+       const int BSS = 32 - (BSB);                                     \
+       const uint32_t RSM = (~0U) << (32 - RSB);                       \
+       const uint32_t GSM = (~0U) << (32 - GSB);                       \
+       const uint32_t BSM = (~0U) << (32 - BSB);                       \
+       const int RDS = 32 - (RDB + GDB + BDB);                         \
+       const int GDS = 32 - (GDB + BDB);                               \
+       const int BDS = 32 - (BDB);                                     \
+       const uint32_t RDM = (~0U) << (32 - RDB);                       \
+       const uint32_t GDM = (~0U) << (32 - GDB);                       \
+       const uint32_t BDM = (~0U) << (32 - BDB);                       \
+       for (col = x ; col < (x+w) ; col++) {                           \
+           uint32_t spix = *src;                                       \
+           *dst = (((spix << RSS) & RSM & RDM) >> RDS) |               \
+               (((spix << GSS) & GSM & GDM) >> GDS) |                  \
+               (((spix << BSS) & BSM & BDM) >> BDS);                   \
+           src = (SRC_T *) ((unsigned long) src + xenfb->depth / 8);   \
+           dst = (DST_T *) ((unsigned long) dst + bpp / 8);            \
+       }                                                               \
+    }
+
+
+/*
+ * This copies data from the guest framebuffer region, into QEMU's
+ * displaysurface. qemu uses 16 or 32 bpp.  In case the pv framebuffer
+ * uses something else we must convert and copy, otherwise we can
+ * supply the buffer directly and no thing here.
+ */
+static void xenfb_guest_copy(struct XenFB *xenfb, int x, int y, int w, int h)
+{
+    DisplaySurface *surface = qemu_console_surface(xenfb->c.con);
+    int line, oops = 0;
+    int bpp = surface_bits_per_pixel(surface);
+    int linesize = surface_stride(surface);
+    uint8_t *data = surface_data(surface);
+
+    if (!is_buffer_shared(surface)) {
+        switch (xenfb->depth) {
+        case 8:
+            if (bpp == 16) {
+                BLT(uint8_t, uint16_t,   3, 3, 2,   5, 6, 5);
+            } else if (bpp == 32) {
+                BLT(uint8_t, uint32_t,   3, 3, 2,   8, 8, 8);
+            } else {
+                oops = 1;
+            }
+            break;
+        case 24:
+            if (bpp == 16) {
+                BLT(uint32_t, uint16_t,  8, 8, 8,   5, 6, 5);
+            } else if (bpp == 32) {
+                BLT(uint32_t, uint32_t,  8, 8, 8,   8, 8, 8);
+            } else {
+                oops = 1;
+            }
+            break;
+        default:
+            oops = 1;
+       }
+    }
+    if (oops) /* should not happen */
+        xen_be_printf(&xenfb->c.xendev, 0, "%s: oops: convert %d -> %d bpp?\n",
+                      __FUNCTION__, xenfb->depth, bpp);
+
+    dpy_gfx_update(xenfb->c.con, x, y, w, h);
+}
+
+#if 0 /* def XENFB_TYPE_REFRESH_PERIOD */
+static int xenfb_queue_full(struct XenFB *xenfb)
+{
+    struct xenfb_page *page = xenfb->c.page;
+    uint32_t cons, prod;
+
+    if (!page)
+        return 1;
+
+    prod = page->in_prod;
+    cons = page->in_cons;
+    return prod - cons == XENFB_IN_RING_LEN;
+}
+
+static void xenfb_send_event(struct XenFB *xenfb, union xenfb_in_event *event)
+{
+    uint32_t prod;
+    struct xenfb_page *page = xenfb->c.page;
+
+    prod = page->in_prod;
+    /* caller ensures !xenfb_queue_full() */
+    xen_mb();                   /* ensure ring space available */
+    XENFB_IN_RING_REF(page, prod) = *event;
+    xen_wmb();                  /* ensure ring contents visible */
+    page->in_prod = prod + 1;
+
+    xen_be_send_notify(&xenfb->c.xendev);
+}
+
+static void xenfb_send_refresh_period(struct XenFB *xenfb, int period)
+{
+    union xenfb_in_event event;
+
+    memset(&event, 0, sizeof(event));
+    event.type = XENFB_TYPE_REFRESH_PERIOD;
+    event.refresh_period.period = period;
+    xenfb_send_event(xenfb, &event);
+}
+#endif
+
+/*
+ * Periodic update of display.
+ * Also transmit the refresh interval to the frontend.
+ *
+ * Never ever do any qemu display operations
+ * (resize, screen update) outside this function.
+ * Our screen might be inactive.  When asked for
+ * an update we know it is active.
+ */
+static void xenfb_update(void *opaque)
+{
+    struct XenFB *xenfb = opaque;
+    DisplaySurface *surface;
+    int i;
+
+    if (xenfb->c.xendev.be_state != XenbusStateConnected)
+        return;
+
+    if (xenfb->feature_update) {
+#if 0 /* XENFB_TYPE_REFRESH_PERIOD */
+        struct DisplayChangeListener *l;
+        int period = 99999999;
+        int idle = 1;
+
+       if (xenfb_queue_full(xenfb))
+           return;
+
+        QLIST_FOREACH(l, &xenfb->c.ds->listeners, next) {
+            if (l->idle)
+                continue;
+            idle = 0;
+            if (!l->gui_timer_interval) {
+                if (period > GUI_REFRESH_INTERVAL)
+                    period = GUI_REFRESH_INTERVAL;
+            } else {
+                if (period > l->gui_timer_interval)
+                    period = l->gui_timer_interval;
+            }
+        }
+        if (idle)
+           period = XENFB_NO_REFRESH;
+
+       if (xenfb->refresh_period != period) {
+           xenfb_send_refresh_period(xenfb, period);
+           xenfb->refresh_period = period;
+            xen_be_printf(&xenfb->c.xendev, 1, "refresh period: %d\n", period);
+       }
+#else
+       ; /* nothing */
+#endif
+    } else {
+       /* we don't get update notifications, thus use the
+        * sledge hammer approach ... */
+       xenfb->up_fullscreen = 1;
+    }
+
+    /* resize if needed */
+    if (xenfb->do_resize) {
+        xenfb->do_resize = 0;
+        switch (xenfb->depth) {
+        case 16:
+        case 32:
+            /* console.c supported depth -> buffer can be used directly */
+            surface = qemu_create_displaysurface_from
+                (xenfb->width, xenfb->height, xenfb->depth,
+                 xenfb->row_stride, xenfb->pixels + xenfb->offset,
+                 false);
+            break;
+        default:
+            /* we must convert stuff */
+            surface = qemu_create_displaysurface(xenfb->width, xenfb->height);
+            break;
+        }
+        dpy_gfx_replace_surface(xenfb->c.con, surface);
+        xen_be_printf(&xenfb->c.xendev, 1, "update: resizing: %dx%d @ %d bpp%s\n",
+                      xenfb->width, xenfb->height, xenfb->depth,
+                      is_buffer_shared(surface) ? " (shared)" : "");
+        xenfb->up_fullscreen = 1;
+    }
+
+    /* run queued updates */
+    if (xenfb->up_fullscreen) {
+       xen_be_printf(&xenfb->c.xendev, 3, "update: fullscreen\n");
+       xenfb_guest_copy(xenfb, 0, 0, xenfb->width, xenfb->height);
+    } else if (xenfb->up_count) {
+       xen_be_printf(&xenfb->c.xendev, 3, "update: %d rects\n", xenfb->up_count);
+       for (i = 0; i < xenfb->up_count; i++)
+           xenfb_guest_copy(xenfb,
+                            xenfb->up_rects[i].x,
+                            xenfb->up_rects[i].y,
+                            xenfb->up_rects[i].w,
+                            xenfb->up_rects[i].h);
+    } else {
+       xen_be_printf(&xenfb->c.xendev, 3, "update: nothing\n");
+    }
+    xenfb->up_count = 0;
+    xenfb->up_fullscreen = 0;
+}
+
+/* QEMU display state changed, so refresh the framebuffer copy */
+static void xenfb_invalidate(void *opaque)
+{
+    struct XenFB *xenfb = opaque;
+    xenfb->up_fullscreen = 1;
+}
+
+static void xenfb_handle_events(struct XenFB *xenfb)
+{
+    uint32_t prod, cons;
+    struct xenfb_page *page = xenfb->c.page;
+
+    prod = page->out_prod;
+    if (prod == page->out_cons)
+       return;
+    xen_rmb();         /* ensure we see ring contents up to prod */
+    for (cons = page->out_cons; cons != prod; cons++) {
+       union xenfb_out_event *event = &XENFB_OUT_RING_REF(page, cons);
+       int x, y, w, h;
+
+       switch (event->type) {
+       case XENFB_TYPE_UPDATE:
+           if (xenfb->up_count == UP_QUEUE)
+               xenfb->up_fullscreen = 1;
+           if (xenfb->up_fullscreen)
+               break;
+           x = MAX(event->update.x, 0);
+           y = MAX(event->update.y, 0);
+           w = MIN(event->update.width, xenfb->width - x);
+           h = MIN(event->update.height, xenfb->height - y);
+           if (w < 0 || h < 0) {
+                xen_be_printf(&xenfb->c.xendev, 1, "bogus update ignored\n");
+               break;
+           }
+           if (x != event->update.x ||
+                y != event->update.y ||
+               w != event->update.width ||
+               h != event->update.height) {
+                xen_be_printf(&xenfb->c.xendev, 1, "bogus update clipped\n");
+           }
+           if (w == xenfb->width && h > xenfb->height / 2) {
+               /* scroll detector: updated more than 50% of the lines,
+                * don't bother keeping track of the rectangles then */
+               xenfb->up_fullscreen = 1;
+           } else {
+               xenfb->up_rects[xenfb->up_count].x = x;
+               xenfb->up_rects[xenfb->up_count].y = y;
+               xenfb->up_rects[xenfb->up_count].w = w;
+               xenfb->up_rects[xenfb->up_count].h = h;
+               xenfb->up_count++;
+           }
+           break;
+#ifdef XENFB_TYPE_RESIZE
+       case XENFB_TYPE_RESIZE:
+           if (xenfb_configure_fb(xenfb, xenfb->fb_len,
+                                  event->resize.width,
+                                  event->resize.height,
+                                  event->resize.depth,
+                                  xenfb->fb_len,
+                                  event->resize.offset,
+                                  event->resize.stride) < 0)
+               break;
+           xenfb_invalidate(xenfb);
+           break;
+#endif
+       }
+    }
+    xen_mb();          /* ensure we're done with ring contents */
+    page->out_cons = cons;
+}
+
+static int fb_init(struct XenDevice *xendev)
+{
+    struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
+
+    fb->refresh_period = -1;
+
+#ifdef XENFB_TYPE_RESIZE
+    xenstore_write_be_int(xendev, "feature-resize", 1);
+#endif
+    return 0;
+}
+
+static int fb_initialise(struct XenDevice *xendev)
+{
+    struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
+    struct xenfb_page *fb_page;
+    int videoram;
+    int rc;
+
+    if (xenstore_read_fe_int(xendev, "videoram", &videoram) == -1)
+       videoram = 0;
+
+    rc = common_bind(&fb->c);
+    if (rc != 0)
+       return rc;
+
+    fb_page = fb->c.page;
+    rc = xenfb_configure_fb(fb, videoram * 1024 * 1024U,
+                           fb_page->width, fb_page->height, fb_page->depth,
+                           fb_page->mem_length, 0, fb_page->line_length);
+    if (rc != 0)
+       return rc;
+
+    rc = xenfb_map_fb(fb);
+    if (rc != 0)
+       return rc;
+
+#if 0  /* handled in xen_init_display() for now */
+    if (!fb->have_console) {
+        fb->c.ds = graphic_console_init(xenfb_update,
+                                        xenfb_invalidate,
+                                        NULL,
+                                        NULL,
+                                        fb);
+        fb->have_console = 1;
+    }
+#endif
+
+    if (xenstore_read_fe_int(xendev, "feature-update", &fb->feature_update) == -1)
+       fb->feature_update = 0;
+    if (fb->feature_update)
+       xenstore_write_be_int(xendev, "request-update", 1);
+
+    xen_be_printf(xendev, 1, "feature-update=%d, videoram=%d\n",
+                 fb->feature_update, videoram);
+    return 0;
+}
+
+static void fb_disconnect(struct XenDevice *xendev)
+{
+    struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
+
+    /*
+     * FIXME: qemu can't un-init gfx display (yet?).
+     *   Replacing the framebuffer with anonymous shared memory
+     *   instead.  This releases the guest pages and keeps qemu happy.
+     */
+    fb->pixels = mmap(fb->pixels, fb->fbpages * XC_PAGE_SIZE,
+                      PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON,
+                      -1, 0);
+    common_unbind(&fb->c);
+    fb->feature_update = 0;
+    fb->bug_trigger    = 0;
+}
+
+static void fb_frontend_changed(struct XenDevice *xendev, const char *node)
+{
+    struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
+
+    /*
+     * Set state to Connected *again* once the frontend switched
+     * to connected.  We must trigger the watch a second time to
+     * workaround a frontend bug.
+     */
+    if (fb->bug_trigger == 0 && strcmp(node, "state") == 0 &&
+        xendev->fe_state == XenbusStateConnected &&
+        xendev->be_state == XenbusStateConnected) {
+        xen_be_printf(xendev, 2, "re-trigger connected (frontend bug)\n");
+        xen_be_set_state(xendev, XenbusStateConnected);
+        fb->bug_trigger = 1; /* only once */
+    }
+}
+
+static void fb_event(struct XenDevice *xendev)
+{
+    struct XenFB *xenfb = container_of(xendev, struct XenFB, c.xendev);
+
+    xenfb_handle_events(xenfb);
+    xen_be_send_notify(&xenfb->c.xendev);
+}
+
+/* -------------------------------------------------------------------- */
+
+struct XenDevOps xen_kbdmouse_ops = {
+    .size       = sizeof(struct XenInput),
+    .init       = input_init,
+    .initialise = input_initialise,
+    .connected  = input_connected,
+    .disconnect = input_disconnect,
+    .event      = input_event,
+};
+
+struct XenDevOps xen_framebuffer_ops = {
+    .size       = sizeof(struct XenFB),
+    .init       = fb_init,
+    .initialise = fb_initialise,
+    .disconnect = fb_disconnect,
+    .event      = fb_event,
+    .frontend_changed = fb_frontend_changed,
+};
+
+/*
+ * FIXME/TODO: Kill this.
+ * Temporary needed while DisplayState reorganization is in flight.
+ */
+void xen_init_display(int domid)
+{
+    struct XenDevice *xfb, *xin;
+    struct XenFB *fb;
+    struct XenInput *in;
+    int i = 0;
+
+wait_more:
+    i++;
+    main_loop_wait(true);
+    xfb = xen_be_find_xendev("vfb", domid, 0);
+    xin = xen_be_find_xendev("vkbd", domid, 0);
+    if (!xfb || !xin) {
+        if (i < 256) {
+            usleep(10000);
+            goto wait_more;
+        }
+        xen_be_printf(NULL, 1, "displaystate setup failed\n");
+        return;
+    }
+
+    /* vfb */
+    fb = container_of(xfb, struct XenFB, c.xendev);
+    fb->c.con = graphic_console_init(xenfb_update,
+                                     xenfb_invalidate,
+                                     NULL,
+                                     NULL,
+                                     fb);
+    fb->have_console = 1;
+
+    /* vkbd */
+    in = container_of(xin, struct XenInput, c.xendev);
+    in->c.con = fb->c.con;
+
+    /* retry ->init() */
+    xen_be_check_state(xin);
+    xen_be_check_state(xfb);
+}
diff --git a/hw/dma.c b/hw/dma.c
deleted file mode 100644 (file)
index fd1161c..0000000
--- a/hw/dma.c
+++ /dev/null
@@ -1,600 +0,0 @@
-/*
- * QEMU DMA emulation
- *
- * Copyright (c) 2003-2004 Vassili Karpov (malc)
- *
- * 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 "hw/hw.h"
-#include "hw/isa.h"
-#include "qemu/main-loop.h"
-
-/* #define DEBUG_DMA */
-
-#define dolog(...) fprintf (stderr, "dma: " __VA_ARGS__)
-#ifdef DEBUG_DMA
-#define linfo(...) fprintf (stderr, "dma: " __VA_ARGS__)
-#define ldebug(...) fprintf (stderr, "dma: " __VA_ARGS__)
-#else
-#define linfo(...)
-#define ldebug(...)
-#endif
-
-struct dma_regs {
-    int now[2];
-    uint16_t base[2];
-    uint8_t mode;
-    uint8_t page;
-    uint8_t pageh;
-    uint8_t dack;
-    uint8_t eop;
-    DMA_transfer_handler transfer_handler;
-    void *opaque;
-};
-
-#define ADDR 0
-#define COUNT 1
-
-static struct dma_cont {
-    uint8_t status;
-    uint8_t command;
-    uint8_t mask;
-    uint8_t flip_flop;
-    int dshift;
-    struct dma_regs regs[4];
-    qemu_irq *cpu_request_exit;
-    MemoryRegion channel_io;
-    MemoryRegion cont_io;
-} dma_controllers[2];
-
-enum {
-    CMD_MEMORY_TO_MEMORY = 0x01,
-    CMD_FIXED_ADDRESS    = 0x02,
-    CMD_BLOCK_CONTROLLER = 0x04,
-    CMD_COMPRESSED_TIME  = 0x08,
-    CMD_CYCLIC_PRIORITY  = 0x10,
-    CMD_EXTENDED_WRITE   = 0x20,
-    CMD_LOW_DREQ         = 0x40,
-    CMD_LOW_DACK         = 0x80,
-    CMD_NOT_SUPPORTED    = CMD_MEMORY_TO_MEMORY | CMD_FIXED_ADDRESS
-    | CMD_COMPRESSED_TIME | CMD_CYCLIC_PRIORITY | CMD_EXTENDED_WRITE
-    | CMD_LOW_DREQ | CMD_LOW_DACK
-
-};
-
-static void DMA_run (void);
-
-static int channels[8] = {-1, 2, 3, 1, -1, -1, -1, 0};
-
-static void write_page (void *opaque, uint32_t nport, uint32_t data)
-{
-    struct dma_cont *d = opaque;
-    int ichan;
-
-    ichan = channels[nport & 7];
-    if (-1 == ichan) {
-        dolog ("invalid channel %#x %#x\n", nport, data);
-        return;
-    }
-    d->regs[ichan].page = data;
-}
-
-static void write_pageh (void *opaque, uint32_t nport, uint32_t data)
-{
-    struct dma_cont *d = opaque;
-    int ichan;
-
-    ichan = channels[nport & 7];
-    if (-1 == ichan) {
-        dolog ("invalid channel %#x %#x\n", nport, data);
-        return;
-    }
-    d->regs[ichan].pageh = data;
-}
-
-static uint32_t read_page (void *opaque, uint32_t nport)
-{
-    struct dma_cont *d = opaque;
-    int ichan;
-
-    ichan = channels[nport & 7];
-    if (-1 == ichan) {
-        dolog ("invalid channel read %#x\n", nport);
-        return 0;
-    }
-    return d->regs[ichan].page;
-}
-
-static uint32_t read_pageh (void *opaque, uint32_t nport)
-{
-    struct dma_cont *d = opaque;
-    int ichan;
-
-    ichan = channels[nport & 7];
-    if (-1 == ichan) {
-        dolog ("invalid channel read %#x\n", nport);
-        return 0;
-    }
-    return d->regs[ichan].pageh;
-}
-
-static inline void init_chan (struct dma_cont *d, int ichan)
-{
-    struct dma_regs *r;
-
-    r = d->regs + ichan;
-    r->now[ADDR] = r->base[ADDR] << d->dshift;
-    r->now[COUNT] = 0;
-}
-
-static inline int getff (struct dma_cont *d)
-{
-    int ff;
-
-    ff = d->flip_flop;
-    d->flip_flop = !ff;
-    return ff;
-}
-
-static uint64_t read_chan(void *opaque, hwaddr nport, unsigned size)
-{
-    struct dma_cont *d = opaque;
-    int ichan, nreg, iport, ff, val, dir;
-    struct dma_regs *r;
-
-    iport = (nport >> d->dshift) & 0x0f;
-    ichan = iport >> 1;
-    nreg = iport & 1;
-    r = d->regs + ichan;
-
-    dir = ((r->mode >> 5) & 1) ? -1 : 1;
-    ff = getff (d);
-    if (nreg)
-        val = (r->base[COUNT] << d->dshift) - r->now[COUNT];
-    else
-        val = r->now[ADDR] + r->now[COUNT] * dir;
-
-    ldebug ("read_chan %#x -> %d\n", iport, val);
-    return (val >> (d->dshift + (ff << 3))) & 0xff;
-}
-
-static void write_chan(void *opaque, hwaddr nport, uint64_t data,
-                       unsigned size)
-{
-    struct dma_cont *d = opaque;
-    int iport, ichan, nreg;
-    struct dma_regs *r;
-
-    iport = (nport >> d->dshift) & 0x0f;
-    ichan = iport >> 1;
-    nreg = iport & 1;
-    r = d->regs + ichan;
-    if (getff (d)) {
-        r->base[nreg] = (r->base[nreg] & 0xff) | ((data << 8) & 0xff00);
-        init_chan (d, ichan);
-    } else {
-        r->base[nreg] = (r->base[nreg] & 0xff00) | (data & 0xff);
-    }
-}
-
-static void write_cont(void *opaque, hwaddr nport, uint64_t data,
-                       unsigned size)
-{
-    struct dma_cont *d = opaque;
-    int iport, ichan = 0;
-
-    iport = (nport >> d->dshift) & 0x0f;
-    switch (iport) {
-    case 0x00:                  /* command */
-        if ((data != 0) && (data & CMD_NOT_SUPPORTED)) {
-            dolog("command %"PRIx64" not supported\n", data);
-            return;
-        }
-        d->command = data;
-        break;
-
-    case 0x01:
-        ichan = data & 3;
-        if (data & 4) {
-            d->status |= 1 << (ichan + 4);
-        }
-        else {
-            d->status &= ~(1 << (ichan + 4));
-        }
-        d->status &= ~(1 << ichan);
-        DMA_run();
-        break;
-
-    case 0x02:                  /* single mask */
-        if (data & 4)
-            d->mask |= 1 << (data & 3);
-        else
-            d->mask &= ~(1 << (data & 3));
-        DMA_run();
-        break;
-
-    case 0x03:                  /* mode */
-        {
-            ichan = data & 3;
-#ifdef DEBUG_DMA
-            {
-                int op, ai, dir, opmode;
-                op = (data >> 2) & 3;
-                ai = (data >> 4) & 1;
-                dir = (data >> 5) & 1;
-                opmode = (data >> 6) & 3;
-
-                linfo ("ichan %d, op %d, ai %d, dir %d, opmode %d\n",
-                       ichan, op, ai, dir, opmode);
-            }
-#endif
-            d->regs[ichan].mode = data;
-            break;
-        }
-
-    case 0x04:                  /* clear flip flop */
-        d->flip_flop = 0;
-        break;
-
-    case 0x05:                  /* reset */
-        d->flip_flop = 0;
-        d->mask = ~0;
-        d->status = 0;
-        d->command = 0;
-        break;
-
-    case 0x06:                  /* clear mask for all channels */
-        d->mask = 0;
-        DMA_run();
-        break;
-
-    case 0x07:                  /* write mask for all channels */
-        d->mask = data;
-        DMA_run();
-        break;
-
-    default:
-        dolog ("unknown iport %#x\n", iport);
-        break;
-    }
-
-#ifdef DEBUG_DMA
-    if (0xc != iport) {
-        linfo ("write_cont: nport %#06x, ichan % 2d, val %#06x\n",
-               nport, ichan, data);
-    }
-#endif
-}
-
-static uint64_t read_cont(void *opaque, hwaddr nport, unsigned size)
-{
-    struct dma_cont *d = opaque;
-    int iport, val;
-
-    iport = (nport >> d->dshift) & 0x0f;
-    switch (iport) {
-    case 0x00:                  /* status */
-        val = d->status;
-        d->status &= 0xf0;
-        break;
-    case 0x01:                  /* mask */
-        val = d->mask;
-        break;
-    default:
-        val = 0;
-        break;
-    }
-
-    ldebug ("read_cont: nport %#06x, iport %#04x val %#x\n", nport, iport, val);
-    return val;
-}
-
-int DMA_get_channel_mode (int nchan)
-{
-    return dma_controllers[nchan > 3].regs[nchan & 3].mode;
-}
-
-void DMA_hold_DREQ (int nchan)
-{
-    int ncont, ichan;
-
-    ncont = nchan > 3;
-    ichan = nchan & 3;
-    linfo ("held cont=%d chan=%d\n", ncont, ichan);
-    dma_controllers[ncont].status |= 1 << (ichan + 4);
-    DMA_run();
-}
-
-void DMA_release_DREQ (int nchan)
-{
-    int ncont, ichan;
-
-    ncont = nchan > 3;
-    ichan = nchan & 3;
-    linfo ("released cont=%d chan=%d\n", ncont, ichan);
-    dma_controllers[ncont].status &= ~(1 << (ichan + 4));
-    DMA_run();
-}
-
-static void channel_run (int ncont, int ichan)
-{
-    int n;
-    struct dma_regs *r = &dma_controllers[ncont].regs[ichan];
-#ifdef DEBUG_DMA
-    int dir, opmode;
-
-    dir = (r->mode >> 5) & 1;
-    opmode = (r->mode >> 6) & 3;
-
-    if (dir) {
-        dolog ("DMA in address decrement mode\n");
-    }
-    if (opmode != 1) {
-        dolog ("DMA not in single mode select %#x\n", opmode);
-    }
-#endif
-
-    n = r->transfer_handler (r->opaque, ichan + (ncont << 2),
-                             r->now[COUNT], (r->base[COUNT] + 1) << ncont);
-    r->now[COUNT] = n;
-    ldebug ("dma_pos %d size %d\n", n, (r->base[COUNT] + 1) << ncont);
-}
-
-static QEMUBH *dma_bh;
-
-static void DMA_run (void)
-{
-    struct dma_cont *d;
-    int icont, ichan;
-    int rearm = 0;
-    static int running = 0;
-
-    if (running) {
-        rearm = 1;
-        goto out;
-    } else {
-        running = 1;
-    }
-
-    d = dma_controllers;
-
-    for (icont = 0; icont < 2; icont++, d++) {
-        for (ichan = 0; ichan < 4; ichan++) {
-            int mask;
-
-            mask = 1 << ichan;
-
-            if ((0 == (d->mask & mask)) && (0 != (d->status & (mask << 4)))) {
-                channel_run (icont, ichan);
-                rearm = 1;
-            }
-        }
-    }
-
-    running = 0;
-out:
-    if (rearm)
-        qemu_bh_schedule_idle(dma_bh);
-}
-
-static void DMA_run_bh(void *unused)
-{
-    DMA_run();
-}
-
-void DMA_register_channel (int nchan,
-                           DMA_transfer_handler transfer_handler,
-                           void *opaque)
-{
-    struct dma_regs *r;
-    int ichan, ncont;
-
-    ncont = nchan > 3;
-    ichan = nchan & 3;
-
-    r = dma_controllers[ncont].regs + ichan;
-    r->transfer_handler = transfer_handler;
-    r->opaque = opaque;
-}
-
-int DMA_read_memory (int nchan, void *buf, int pos, int len)
-{
-    struct dma_regs *r = &dma_controllers[nchan > 3].regs[nchan & 3];
-    hwaddr addr = ((r->pageh & 0x7f) << 24) | (r->page << 16) | r->now[ADDR];
-
-    if (r->mode & 0x20) {
-        int i;
-        uint8_t *p = buf;
-
-        cpu_physical_memory_read (addr - pos - len, buf, len);
-        /* What about 16bit transfers? */
-        for (i = 0; i < len >> 1; i++) {
-            uint8_t b = p[len - i - 1];
-            p[i] = b;
-        }
-    }
-    else
-        cpu_physical_memory_read (addr + pos, buf, len);
-
-    return len;
-}
-
-int DMA_write_memory (int nchan, void *buf, int pos, int len)
-{
-    struct dma_regs *r = &dma_controllers[nchan > 3].regs[nchan & 3];
-    hwaddr addr = ((r->pageh & 0x7f) << 24) | (r->page << 16) | r->now[ADDR];
-
-    if (r->mode & 0x20) {
-        int i;
-        uint8_t *p = buf;
-
-        cpu_physical_memory_write (addr - pos - len, buf, len);
-        /* What about 16bit transfers? */
-        for (i = 0; i < len; i++) {
-            uint8_t b = p[len - i - 1];
-            p[i] = b;
-        }
-    }
-    else
-        cpu_physical_memory_write (addr + pos, buf, len);
-
-    return len;
-}
-
-/* request the emulator to transfer a new DMA memory block ASAP */
-void DMA_schedule(int nchan)
-{
-    struct dma_cont *d = &dma_controllers[nchan > 3];
-
-    qemu_irq_pulse(*d->cpu_request_exit);
-}
-
-static void dma_reset(void *opaque)
-{
-    struct dma_cont *d = opaque;
-    write_cont(d, (0x05 << d->dshift), 0, 1);
-}
-
-static int dma_phony_handler (void *opaque, int nchan, int dma_pos, int dma_len)
-{
-    dolog ("unregistered DMA channel used nchan=%d dma_pos=%d dma_len=%d\n",
-           nchan, dma_pos, dma_len);
-    return dma_pos;
-}
-
-
-static const MemoryRegionOps channel_io_ops = {
-    .read = read_chan,
-    .write = write_chan,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .impl = {
-        .min_access_size = 1,
-        .max_access_size = 1,
-    },
-};
-
-/* IOport from page_base */
-static const MemoryRegionPortio page_portio_list[] = {
-    { 0x01, 3, 1, .write = write_page, .read = read_page, },
-    { 0x07, 1, 1, .write = write_page, .read = read_page, },
-    PORTIO_END_OF_LIST(),
-};
-
-/* IOport from pageh_base */
-static const MemoryRegionPortio pageh_portio_list[] = {
-    { 0x01, 3, 1, .write = write_pageh, .read = read_pageh, },
-    { 0x07, 3, 1, .write = write_pageh, .read = read_pageh, },
-    PORTIO_END_OF_LIST(),
-};
-
-static const MemoryRegionOps cont_io_ops = {
-    .read = read_cont,
-    .write = write_cont,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .impl = {
-        .min_access_size = 1,
-        .max_access_size = 1,
-    },
-};
-
-/* dshift = 0: 8 bit DMA, 1 = 16 bit DMA */
-static void dma_init2(struct dma_cont *d, int base, int dshift,
-                      int page_base, int pageh_base,
-                      qemu_irq *cpu_request_exit)
-{
-    int i;
-
-    d->dshift = dshift;
-    d->cpu_request_exit = cpu_request_exit;
-
-    memory_region_init_io(&d->channel_io, &channel_io_ops, d,
-                          "dma-chan", 8 << d->dshift);
-    memory_region_add_subregion(isa_address_space_io(NULL),
-                                base, &d->channel_io);
-
-    isa_register_portio_list(NULL, page_base, page_portio_list, d,
-                             "dma-page");
-    if (pageh_base >= 0) {
-        isa_register_portio_list(NULL, pageh_base, pageh_portio_list, d,
-                                 "dma-pageh");
-    }
-
-    memory_region_init_io(&d->cont_io, &cont_io_ops, d, "dma-cont",
-                          8 << d->dshift);
-    memory_region_add_subregion(isa_address_space_io(NULL),
-                                base + (8 << d->dshift), &d->cont_io);
-
-    qemu_register_reset(dma_reset, d);
-    dma_reset(d);
-    for (i = 0; i < ARRAY_SIZE (d->regs); ++i) {
-        d->regs[i].transfer_handler = dma_phony_handler;
-    }
-}
-
-static const VMStateDescription vmstate_dma_regs = {
-    .name = "dma_regs",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField []) {
-        VMSTATE_INT32_ARRAY(now, struct dma_regs, 2),
-        VMSTATE_UINT16_ARRAY(base, struct dma_regs, 2),
-        VMSTATE_UINT8(mode, struct dma_regs),
-        VMSTATE_UINT8(page, struct dma_regs),
-        VMSTATE_UINT8(pageh, struct dma_regs),
-        VMSTATE_UINT8(dack, struct dma_regs),
-        VMSTATE_UINT8(eop, struct dma_regs),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static int dma_post_load(void *opaque, int version_id)
-{
-    DMA_run();
-
-    return 0;
-}
-
-static const VMStateDescription vmstate_dma = {
-    .name = "dma",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .post_load = dma_post_load,
-    .fields      = (VMStateField []) {
-        VMSTATE_UINT8(command, struct dma_cont),
-        VMSTATE_UINT8(mask, struct dma_cont),
-        VMSTATE_UINT8(flip_flop, struct dma_cont),
-        VMSTATE_INT32(dshift, struct dma_cont),
-        VMSTATE_STRUCT_ARRAY(regs, struct dma_cont, 4, 1, vmstate_dma_regs, struct dma_regs),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-void DMA_init(int high_page_enable, qemu_irq *cpu_request_exit)
-{
-    dma_init2(&dma_controllers[0], 0x00, 0, 0x80,
-              high_page_enable ? 0x480 : -1, cpu_request_exit);
-    dma_init2(&dma_controllers[1], 0xc0, 1, 0x88,
-              high_page_enable ? 0x488 : -1, cpu_request_exit);
-    vmstate_register (NULL, 0, &vmstate_dma, &dma_controllers[0]);
-    vmstate_register (NULL, 1, &vmstate_dma, &dma_controllers[1]);
-
-    dma_bh = qemu_bh_new(DMA_run_bh, NULL);
-}
diff --git a/hw/dma/Makefile.objs b/hw/dma/Makefile.objs
new file mode 100644 (file)
index 0000000..0e65ed0
--- /dev/null
@@ -0,0 +1,13 @@
+common-obj-$(CONFIG_PUV3) += puv3_dma.o
+common-obj-$(CONFIG_RC4030) += rc4030.o
+common-obj-$(CONFIG_PL080) += pl080.o
+common-obj-$(CONFIG_PL330) += pl330.o
+common-obj-$(CONFIG_I82374) += i82374.o
+common-obj-$(CONFIG_I8257) += i8257.o
+common-obj-$(CONFIG_XILINX_AXI) += xilinx_axidma.o
+common-obj-$(CONFIG_ETRAXFS) += etraxfs_dma.o
+common-obj-$(CONFIG_STP2000) += sparc32_dma.o
+common-obj-$(CONFIG_SUN4M) += sun4m_iommu.o
+
+obj-$(CONFIG_OMAP) += omap_dma.o soc_dma.o
+obj-$(CONFIG_PXA2XX) += pxa2xx_dma.o
diff --git a/hw/dma/etraxfs_dma.c b/hw/dma/etraxfs_dma.c
new file mode 100644 (file)
index 0000000..6a8c222
--- /dev/null
@@ -0,0 +1,781 @@
+/*
+ * QEMU ETRAX DMA Controller.
+ *
+ * Copyright (c) 2008 Edgar E. Iglesias, Axis Communications AB.
+ *
+ * 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 <stdio.h>
+#include <sys/time.h>
+#include "hw/hw.h"
+#include "exec/address-spaces.h"
+#include "qemu-common.h"
+#include "sysemu/sysemu.h"
+
+#include "hw/cris/etraxfs_dma.h"
+
+#define D(x)
+
+#define RW_DATA           (0x0 / 4)
+#define RW_SAVED_DATA     (0x58 / 4)
+#define RW_SAVED_DATA_BUF (0x5c / 4)
+#define RW_GROUP          (0x60 / 4)
+#define RW_GROUP_DOWN     (0x7c / 4)
+#define RW_CMD            (0x80 / 4)
+#define RW_CFG            (0x84 / 4)
+#define RW_STAT           (0x88 / 4)
+#define RW_INTR_MASK      (0x8c / 4)
+#define RW_ACK_INTR       (0x90 / 4)
+#define R_INTR            (0x94 / 4)
+#define R_MASKED_INTR     (0x98 / 4)
+#define RW_STREAM_CMD     (0x9c / 4)
+
+#define DMA_REG_MAX       (0x100 / 4)
+
+/* descriptors */
+
+// ------------------------------------------------------------ dma_descr_group
+typedef struct dma_descr_group {
+  uint32_t                      next;
+  unsigned                      eol        : 1;
+  unsigned                      tol        : 1;
+  unsigned                      bol        : 1;
+  unsigned                                 : 1;
+  unsigned                      intr       : 1;
+  unsigned                                 : 2;
+  unsigned                      en         : 1;
+  unsigned                                 : 7;
+  unsigned                      dis        : 1;
+  unsigned                      md         : 16;
+  struct dma_descr_group       *up;
+  union {
+    struct dma_descr_context   *context;
+    struct dma_descr_group     *group;
+  }                             down;
+} dma_descr_group;
+
+// ---------------------------------------------------------- dma_descr_context
+typedef struct dma_descr_context {
+  uint32_t                      next;
+  unsigned                      eol        : 1;
+  unsigned                                 : 3;
+  unsigned                      intr       : 1;
+  unsigned                                 : 1;
+  unsigned                      store_mode : 1;
+  unsigned                      en         : 1;
+  unsigned                                 : 7;
+  unsigned                      dis        : 1;
+  unsigned                      md0        : 16;
+  unsigned                      md1;
+  unsigned                      md2;
+  unsigned                      md3;
+  unsigned                      md4;
+  uint32_t                      saved_data;
+  uint32_t                      saved_data_buf;
+} dma_descr_context;
+
+// ------------------------------------------------------------- dma_descr_data
+typedef struct dma_descr_data {
+  uint32_t                      next;
+  uint32_t                      buf;
+  unsigned                      eol        : 1;
+  unsigned                                 : 2;
+  unsigned                      out_eop    : 1;
+  unsigned                      intr       : 1;
+  unsigned                      wait       : 1;
+  unsigned                                 : 2;
+  unsigned                                 : 3;
+  unsigned                      in_eop     : 1;
+  unsigned                                 : 4;
+  unsigned                      md         : 16;
+  uint32_t                      after;
+} dma_descr_data;
+
+/* Constants */
+enum {
+  regk_dma_ack_pkt                         = 0x00000100,
+  regk_dma_anytime                         = 0x00000001,
+  regk_dma_array                           = 0x00000008,
+  regk_dma_burst                           = 0x00000020,
+  regk_dma_client                          = 0x00000002,
+  regk_dma_copy_next                       = 0x00000010,
+  regk_dma_copy_up                         = 0x00000020,
+  regk_dma_data_at_eol                     = 0x00000001,
+  regk_dma_dis_c                           = 0x00000010,
+  regk_dma_dis_g                           = 0x00000020,
+  regk_dma_idle                            = 0x00000001,
+  regk_dma_intern                          = 0x00000004,
+  regk_dma_load_c                          = 0x00000200,
+  regk_dma_load_c_n                        = 0x00000280,
+  regk_dma_load_c_next                     = 0x00000240,
+  regk_dma_load_d                          = 0x00000140,
+  regk_dma_load_g                          = 0x00000300,
+  regk_dma_load_g_down                     = 0x000003c0,
+  regk_dma_load_g_next                     = 0x00000340,
+  regk_dma_load_g_up                       = 0x00000380,
+  regk_dma_next_en                         = 0x00000010,
+  regk_dma_next_pkt                        = 0x00000010,
+  regk_dma_no                              = 0x00000000,
+  regk_dma_only_at_wait                    = 0x00000000,
+  regk_dma_restore                         = 0x00000020,
+  regk_dma_rst                             = 0x00000001,
+  regk_dma_running                         = 0x00000004,
+  regk_dma_rw_cfg_default                  = 0x00000000,
+  regk_dma_rw_cmd_default                  = 0x00000000,
+  regk_dma_rw_intr_mask_default            = 0x00000000,
+  regk_dma_rw_stat_default                 = 0x00000101,
+  regk_dma_rw_stream_cmd_default           = 0x00000000,
+  regk_dma_save_down                       = 0x00000020,
+  regk_dma_save_up                         = 0x00000020,
+  regk_dma_set_reg                         = 0x00000050,
+  regk_dma_set_w_size1                     = 0x00000190,
+  regk_dma_set_w_size2                     = 0x000001a0,
+  regk_dma_set_w_size4                     = 0x000001c0,
+  regk_dma_stopped                         = 0x00000002,
+  regk_dma_store_c                         = 0x00000002,
+  regk_dma_store_descr                     = 0x00000000,
+  regk_dma_store_g                         = 0x00000004,
+  regk_dma_store_md                        = 0x00000001,
+  regk_dma_sw                              = 0x00000008,
+  regk_dma_update_down                     = 0x00000020,
+  regk_dma_yes                             = 0x00000001
+};
+
+enum dma_ch_state
+{
+       RST = 1,
+       STOPPED = 2,
+       RUNNING = 4
+};
+
+struct fs_dma_channel
+{
+       qemu_irq irq;
+       struct etraxfs_dma_client *client;
+
+       /* Internal status.  */
+       int stream_cmd_src;
+       enum dma_ch_state state;
+
+       unsigned int input : 1;
+       unsigned int eol : 1;
+
+       struct dma_descr_group current_g;
+       struct dma_descr_context current_c;
+       struct dma_descr_data current_d;
+
+       /* Control registers.  */
+       uint32_t regs[DMA_REG_MAX];
+};
+
+struct fs_dma_ctrl
+{
+       MemoryRegion mmio;
+       int nr_channels;
+       struct fs_dma_channel *channels;
+
+        QEMUBH *bh;
+};
+
+static void DMA_run(void *opaque);
+static int channel_out_run(struct fs_dma_ctrl *ctrl, int c);
+
+static inline uint32_t channel_reg(struct fs_dma_ctrl *ctrl, int c, int reg)
+{
+       return ctrl->channels[c].regs[reg];
+}
+
+static inline int channel_stopped(struct fs_dma_ctrl *ctrl, int c)
+{
+       return channel_reg(ctrl, c, RW_CFG) & 2;
+}
+
+static inline int channel_en(struct fs_dma_ctrl *ctrl, int c)
+{
+       return (channel_reg(ctrl, c, RW_CFG) & 1)
+               && ctrl->channels[c].client;
+}
+
+static inline int fs_channel(hwaddr addr)
+{
+       /* Every channel has a 0x2000 ctrl register map.  */
+       return addr >> 13;
+}
+
+#ifdef USE_THIS_DEAD_CODE
+static void channel_load_g(struct fs_dma_ctrl *ctrl, int c)
+{
+       hwaddr addr = channel_reg(ctrl, c, RW_GROUP);
+
+       /* Load and decode. FIXME: handle endianness.  */
+       cpu_physical_memory_read (addr, 
+                                 (void *) &ctrl->channels[c].current_g, 
+                                 sizeof ctrl->channels[c].current_g);
+}
+
+static void dump_c(int ch, struct dma_descr_context *c)
+{
+       printf("%s ch=%d\n", __func__, ch);
+       printf("next=%x\n", c->next);
+       printf("saved_data=%x\n", c->saved_data);
+       printf("saved_data_buf=%x\n", c->saved_data_buf);
+       printf("eol=%x\n", (uint32_t) c->eol);
+}
+
+static void dump_d(int ch, struct dma_descr_data *d)
+{
+       printf("%s ch=%d\n", __func__, ch);
+       printf("next=%x\n", d->next);
+       printf("buf=%x\n", d->buf);
+       printf("after=%x\n", d->after);
+       printf("intr=%x\n", (uint32_t) d->intr);
+       printf("out_eop=%x\n", (uint32_t) d->out_eop);
+       printf("in_eop=%x\n", (uint32_t) d->in_eop);
+       printf("eol=%x\n", (uint32_t) d->eol);
+}
+#endif
+
+static void channel_load_c(struct fs_dma_ctrl *ctrl, int c)
+{
+       hwaddr addr = channel_reg(ctrl, c, RW_GROUP_DOWN);
+
+       /* Load and decode. FIXME: handle endianness.  */
+       cpu_physical_memory_read (addr, 
+                                 (void *) &ctrl->channels[c].current_c, 
+                                 sizeof ctrl->channels[c].current_c);
+
+       D(dump_c(c, &ctrl->channels[c].current_c));
+       /* I guess this should update the current pos.  */
+       ctrl->channels[c].regs[RW_SAVED_DATA] =
+               (uint32_t)(unsigned long)ctrl->channels[c].current_c.saved_data;
+       ctrl->channels[c].regs[RW_SAVED_DATA_BUF] =
+               (uint32_t)(unsigned long)ctrl->channels[c].current_c.saved_data_buf;
+}
+
+static void channel_load_d(struct fs_dma_ctrl *ctrl, int c)
+{
+       hwaddr addr = channel_reg(ctrl, c, RW_SAVED_DATA);
+
+       /* Load and decode. FIXME: handle endianness.  */
+       D(printf("%s ch=%d addr=" TARGET_FMT_plx "\n", __func__, c, addr));
+       cpu_physical_memory_read (addr,
+                                 (void *) &ctrl->channels[c].current_d, 
+                                 sizeof ctrl->channels[c].current_d);
+
+       D(dump_d(c, &ctrl->channels[c].current_d));
+       ctrl->channels[c].regs[RW_DATA] = addr;
+}
+
+static void channel_store_c(struct fs_dma_ctrl *ctrl, int c)
+{
+       hwaddr addr = channel_reg(ctrl, c, RW_GROUP_DOWN);
+
+       /* Encode and store. FIXME: handle endianness.  */
+       D(printf("%s ch=%d addr=" TARGET_FMT_plx "\n", __func__, c, addr));
+       D(dump_d(c, &ctrl->channels[c].current_d));
+       cpu_physical_memory_write (addr,
+                                 (void *) &ctrl->channels[c].current_c,
+                                 sizeof ctrl->channels[c].current_c);
+}
+
+static void channel_store_d(struct fs_dma_ctrl *ctrl, int c)
+{
+       hwaddr addr = channel_reg(ctrl, c, RW_SAVED_DATA);
+
+       /* Encode and store. FIXME: handle endianness.  */
+       D(printf("%s ch=%d addr=" TARGET_FMT_plx "\n", __func__, c, addr));
+       cpu_physical_memory_write (addr,
+                                 (void *) &ctrl->channels[c].current_d, 
+                                 sizeof ctrl->channels[c].current_d);
+}
+
+static inline void channel_stop(struct fs_dma_ctrl *ctrl, int c)
+{
+       /* FIXME:  */
+}
+
+static inline void channel_start(struct fs_dma_ctrl *ctrl, int c)
+{
+       if (ctrl->channels[c].client)
+       {
+               ctrl->channels[c].eol = 0;
+               ctrl->channels[c].state = RUNNING;
+               if (!ctrl->channels[c].input)
+                       channel_out_run(ctrl, c);
+       } else
+               printf("WARNING: starting DMA ch %d with no client\n", c);
+
+        qemu_bh_schedule_idle(ctrl->bh);
+}
+
+static void channel_continue(struct fs_dma_ctrl *ctrl, int c)
+{
+       if (!channel_en(ctrl, c) 
+           || channel_stopped(ctrl, c)
+           || ctrl->channels[c].state != RUNNING
+           /* Only reload the current data descriptor if it has eol set.  */
+           || !ctrl->channels[c].current_d.eol) {
+               D(printf("continue failed ch=%d state=%d stopped=%d en=%d eol=%d\n", 
+                        c, ctrl->channels[c].state,
+                        channel_stopped(ctrl, c),
+                        channel_en(ctrl,c),
+                        ctrl->channels[c].eol));
+               D(dump_d(c, &ctrl->channels[c].current_d));
+               return;
+       }
+
+       /* Reload the current descriptor.  */
+       channel_load_d(ctrl, c);
+
+       /* If the current descriptor cleared the eol flag and we had already
+          reached eol state, do the continue.  */
+       if (!ctrl->channels[c].current_d.eol && ctrl->channels[c].eol) {
+               D(printf("continue %d ok %x\n", c,
+                        ctrl->channels[c].current_d.next));
+               ctrl->channels[c].regs[RW_SAVED_DATA] =
+                       (uint32_t)(unsigned long)ctrl->channels[c].current_d.next;
+               channel_load_d(ctrl, c);
+               ctrl->channels[c].regs[RW_SAVED_DATA_BUF] =
+                       (uint32_t)(unsigned long)ctrl->channels[c].current_d.buf;
+
+               channel_start(ctrl, c);
+       }
+       ctrl->channels[c].regs[RW_SAVED_DATA_BUF] =
+               (uint32_t)(unsigned long)ctrl->channels[c].current_d.buf;
+}
+
+static void channel_stream_cmd(struct fs_dma_ctrl *ctrl, int c, uint32_t v)
+{
+       unsigned int cmd = v & ((1 << 10) - 1);
+
+       D(printf("%s ch=%d cmd=%x\n",
+                __func__, c, cmd));
+       if (cmd & regk_dma_load_d) {
+               channel_load_d(ctrl, c);
+               if (cmd & regk_dma_burst)
+                       channel_start(ctrl, c);
+       }
+
+       if (cmd & regk_dma_load_c) {
+               channel_load_c(ctrl, c);
+       }
+}
+
+static void channel_update_irq(struct fs_dma_ctrl *ctrl, int c)
+{
+       D(printf("%s %d\n", __func__, c));
+        ctrl->channels[c].regs[R_INTR] &=
+               ~(ctrl->channels[c].regs[RW_ACK_INTR]);
+
+        ctrl->channels[c].regs[R_MASKED_INTR] =
+               ctrl->channels[c].regs[R_INTR]
+               & ctrl->channels[c].regs[RW_INTR_MASK];
+
+       D(printf("%s: chan=%d masked_intr=%x\n", __func__, 
+                c,
+                ctrl->channels[c].regs[R_MASKED_INTR]));
+
+        qemu_set_irq(ctrl->channels[c].irq,
+                    !!ctrl->channels[c].regs[R_MASKED_INTR]);
+}
+
+static int channel_out_run(struct fs_dma_ctrl *ctrl, int c)
+{
+       uint32_t len;
+       uint32_t saved_data_buf;
+       unsigned char buf[2 * 1024];
+
+       struct dma_context_metadata meta;
+       bool send_context = true;
+
+       if (ctrl->channels[c].eol)
+               return 0;
+
+       do {
+               bool out_eop;
+               D(printf("ch=%d buf=%x after=%x\n",
+                        c,
+                        (uint32_t)ctrl->channels[c].current_d.buf,
+                        (uint32_t)ctrl->channels[c].current_d.after));
+
+               if (send_context) {
+                       if (ctrl->channels[c].client->client.metadata_push) {
+                               meta.metadata = ctrl->channels[c].current_d.md;
+                               ctrl->channels[c].client->client.metadata_push(
+                                       ctrl->channels[c].client->client.opaque,
+                                       &meta);
+                       }
+                       send_context = false;
+               }
+
+               channel_load_d(ctrl, c);
+               saved_data_buf = channel_reg(ctrl, c, RW_SAVED_DATA_BUF);
+               len = (uint32_t)(unsigned long)
+                       ctrl->channels[c].current_d.after;
+               len -= saved_data_buf;
+
+               if (len > sizeof buf)
+                       len = sizeof buf;
+               cpu_physical_memory_read (saved_data_buf, buf, len);
+
+               out_eop = ((saved_data_buf + len) ==
+                          ctrl->channels[c].current_d.after) &&
+                       ctrl->channels[c].current_d.out_eop;
+
+               D(printf("channel %d pushes %x %u bytes eop=%u\n", c,
+                        saved_data_buf, len, out_eop));
+
+               if (ctrl->channels[c].client->client.push)
+                       ctrl->channels[c].client->client.push(
+                               ctrl->channels[c].client->client.opaque,
+                               buf, len, out_eop);
+               else
+                       printf("WARNING: DMA ch%d dataloss,"
+                              " no attached client.\n", c);
+
+               saved_data_buf += len;
+
+               if (saved_data_buf == (uint32_t)(unsigned long)
+                               ctrl->channels[c].current_d.after) {
+                       /* Done. Step to next.  */
+                       if (ctrl->channels[c].current_d.out_eop) {
+                               send_context = true;
+                       }
+                       if (ctrl->channels[c].current_d.intr) {
+                               /* data intr.  */
+                               D(printf("signal intr %d eol=%d\n",
+                                       len, ctrl->channels[c].current_d.eol));
+                               ctrl->channels[c].regs[R_INTR] |= (1 << 2);
+                               channel_update_irq(ctrl, c);
+                       }
+                       channel_store_d(ctrl, c);
+                       if (ctrl->channels[c].current_d.eol) {
+                               D(printf("channel %d EOL\n", c));
+                               ctrl->channels[c].eol = 1;
+
+                               /* Mark the context as disabled.  */
+                               ctrl->channels[c].current_c.dis = 1;
+                               channel_store_c(ctrl, c);
+
+                               channel_stop(ctrl, c);
+                       } else {
+                               ctrl->channels[c].regs[RW_SAVED_DATA] =
+                                       (uint32_t)(unsigned long)ctrl->
+                                               channels[c].current_d.next;
+                               /* Load new descriptor.  */
+                               channel_load_d(ctrl, c);
+                               saved_data_buf = (uint32_t)(unsigned long)
+                                       ctrl->channels[c].current_d.buf;
+                       }
+
+                       ctrl->channels[c].regs[RW_SAVED_DATA_BUF] =
+                                                       saved_data_buf;
+                       D(dump_d(c, &ctrl->channels[c].current_d));
+               }
+               ctrl->channels[c].regs[RW_SAVED_DATA_BUF] = saved_data_buf;
+       } while (!ctrl->channels[c].eol);
+       return 1;
+}
+
+static int channel_in_process(struct fs_dma_ctrl *ctrl, int c, 
+                             unsigned char *buf, int buflen, int eop)
+{
+       uint32_t len;
+       uint32_t saved_data_buf;
+
+       if (ctrl->channels[c].eol == 1)
+               return 0;
+
+       channel_load_d(ctrl, c);
+       saved_data_buf = channel_reg(ctrl, c, RW_SAVED_DATA_BUF);
+       len = (uint32_t)(unsigned long)ctrl->channels[c].current_d.after;
+       len -= saved_data_buf;
+       
+       if (len > buflen)
+               len = buflen;
+
+       cpu_physical_memory_write (saved_data_buf, buf, len);
+       saved_data_buf += len;
+
+       if (saved_data_buf ==
+           (uint32_t)(unsigned long)ctrl->channels[c].current_d.after
+           || eop) {
+               uint32_t r_intr = ctrl->channels[c].regs[R_INTR];
+
+               D(printf("in dscr end len=%d\n", 
+                        ctrl->channels[c].current_d.after
+                        - ctrl->channels[c].current_d.buf));
+               ctrl->channels[c].current_d.after = saved_data_buf;
+
+               /* Done. Step to next.  */
+               if (ctrl->channels[c].current_d.intr) {
+                       /* TODO: signal eop to the client.  */
+                       /* data intr.  */
+                       ctrl->channels[c].regs[R_INTR] |= 3;
+               }
+               if (eop) {
+                       ctrl->channels[c].current_d.in_eop = 1;
+                       ctrl->channels[c].regs[R_INTR] |= 8;
+               }
+               if (r_intr != ctrl->channels[c].regs[R_INTR])
+                       channel_update_irq(ctrl, c);
+
+               channel_store_d(ctrl, c);
+               D(dump_d(c, &ctrl->channels[c].current_d));
+
+               if (ctrl->channels[c].current_d.eol) {
+                       D(printf("channel %d EOL\n", c));
+                       ctrl->channels[c].eol = 1;
+
+                       /* Mark the context as disabled.  */
+                       ctrl->channels[c].current_c.dis = 1;
+                       channel_store_c(ctrl, c);
+
+                       channel_stop(ctrl, c);
+               } else {
+                       ctrl->channels[c].regs[RW_SAVED_DATA] =
+                               (uint32_t)(unsigned long)ctrl->
+                                       channels[c].current_d.next;
+                       /* Load new descriptor.  */
+                       channel_load_d(ctrl, c);
+                       saved_data_buf = (uint32_t)(unsigned long)
+                               ctrl->channels[c].current_d.buf;
+               }
+       }
+
+       ctrl->channels[c].regs[RW_SAVED_DATA_BUF] = saved_data_buf;
+       return len;
+}
+
+static inline int channel_in_run(struct fs_dma_ctrl *ctrl, int c)
+{
+       if (ctrl->channels[c].client->client.pull) {
+               ctrl->channels[c].client->client.pull(
+                       ctrl->channels[c].client->client.opaque);
+               return 1;
+       } else
+               return 0;
+}
+
+static uint32_t dma_rinvalid (void *opaque, hwaddr addr)
+{
+        hw_error("Unsupported short raccess. reg=" TARGET_FMT_plx "\n", addr);
+        return 0;
+}
+
+static uint64_t
+dma_read(void *opaque, hwaddr addr, unsigned int size)
+{
+        struct fs_dma_ctrl *ctrl = opaque;
+       int c;
+       uint32_t r = 0;
+
+       if (size != 4) {
+               dma_rinvalid(opaque, addr);
+       }
+
+       /* Make addr relative to this channel and bounded to nr regs.  */
+       c = fs_channel(addr);
+       addr &= 0xff;
+       addr >>= 2;
+       switch (addr)
+       {
+               case RW_STAT:
+                       r = ctrl->channels[c].state & 7;
+                       r |= ctrl->channels[c].eol << 5;
+                       r |= ctrl->channels[c].stream_cmd_src << 8;
+                       break;
+
+               default:
+                       r = ctrl->channels[c].regs[addr];
+                       D(printf ("%s c=%d addr=" TARGET_FMT_plx "\n",
+                                 __func__, c, addr));
+                       break;
+       }
+       return r;
+}
+
+static void
+dma_winvalid (void *opaque, hwaddr addr, uint32_t value)
+{
+        hw_error("Unsupported short waccess. reg=" TARGET_FMT_plx "\n", addr);
+}
+
+static void
+dma_update_state(struct fs_dma_ctrl *ctrl, int c)
+{
+       if (ctrl->channels[c].regs[RW_CFG] & 2)
+               ctrl->channels[c].state = STOPPED;
+       if (!(ctrl->channels[c].regs[RW_CFG] & 1))
+               ctrl->channels[c].state = RST;
+}
+
+static void
+dma_write(void *opaque, hwaddr addr,
+         uint64_t val64, unsigned int size)
+{
+        struct fs_dma_ctrl *ctrl = opaque;
+       uint32_t value = val64;
+       int c;
+
+       if (size != 4) {
+               dma_winvalid(opaque, addr, value);
+       }
+
+        /* Make addr relative to this channel and bounded to nr regs.  */
+       c = fs_channel(addr);
+        addr &= 0xff;
+        addr >>= 2;
+        switch (addr)
+       {
+               case RW_DATA:
+                       ctrl->channels[c].regs[addr] = value;
+                       break;
+
+               case RW_CFG:
+                       ctrl->channels[c].regs[addr] = value;
+                       dma_update_state(ctrl, c);
+                       break;
+               case RW_CMD:
+                       /* continue.  */
+                       if (value & ~1)
+                               printf("Invalid store to ch=%d RW_CMD %x\n",
+                                      c, value);
+                       ctrl->channels[c].regs[addr] = value;
+                       channel_continue(ctrl, c);
+                       break;
+
+               case RW_SAVED_DATA:
+               case RW_SAVED_DATA_BUF:
+               case RW_GROUP:
+               case RW_GROUP_DOWN:
+                       ctrl->channels[c].regs[addr] = value;
+                       break;
+
+               case RW_ACK_INTR:
+               case RW_INTR_MASK:
+                       ctrl->channels[c].regs[addr] = value;
+                       channel_update_irq(ctrl, c);
+                       if (addr == RW_ACK_INTR)
+                               ctrl->channels[c].regs[RW_ACK_INTR] = 0;
+                       break;
+
+               case RW_STREAM_CMD:
+                       if (value & ~1023)
+                               printf("Invalid store to ch=%d "
+                                      "RW_STREAMCMD %x\n",
+                                      c, value);
+                       ctrl->channels[c].regs[addr] = value;
+                       D(printf("stream_cmd ch=%d\n", c));
+                       channel_stream_cmd(ctrl, c, value);
+                       break;
+
+               default:
+                       D(printf ("%s c=%d " TARGET_FMT_plx "\n",
+                               __func__, c, addr));
+                       break;
+        }
+}
+
+static const MemoryRegionOps dma_ops = {
+       .read = dma_read,
+       .write = dma_write,
+       .endianness = DEVICE_NATIVE_ENDIAN,
+       .valid = {
+               .min_access_size = 1,
+               .max_access_size = 4
+       }
+};
+
+static int etraxfs_dmac_run(void *opaque)
+{
+       struct fs_dma_ctrl *ctrl = opaque;
+       int i;
+       int p = 0;
+
+       for (i = 0; 
+            i < ctrl->nr_channels;
+            i++)
+       {
+               if (ctrl->channels[i].state == RUNNING)
+               {
+                       if (ctrl->channels[i].input) {
+                               p += channel_in_run(ctrl, i);
+                       } else {
+                               p += channel_out_run(ctrl, i);
+                       }
+               }
+       }
+       return p;
+}
+
+int etraxfs_dmac_input(struct etraxfs_dma_client *client, 
+                      void *buf, int len, int eop)
+{
+       return channel_in_process(client->ctrl, client->channel, 
+                                 buf, len, eop);
+}
+
+/* Connect an IRQ line with a channel.  */
+void etraxfs_dmac_connect(void *opaque, int c, qemu_irq *line, int input)
+{
+       struct fs_dma_ctrl *ctrl = opaque;
+       ctrl->channels[c].irq = *line;
+       ctrl->channels[c].input = input;
+}
+
+void etraxfs_dmac_connect_client(void *opaque, int c, 
+                                struct etraxfs_dma_client *cl)
+{
+       struct fs_dma_ctrl *ctrl = opaque;
+       cl->ctrl = ctrl;
+       cl->channel = c;
+       ctrl->channels[c].client = cl;
+}
+
+
+static void DMA_run(void *opaque)
+{
+    struct fs_dma_ctrl *etraxfs_dmac = opaque;
+    int p = 1;
+
+    if (runstate_is_running())
+        p = etraxfs_dmac_run(etraxfs_dmac);
+
+    if (p)
+        qemu_bh_schedule_idle(etraxfs_dmac->bh);
+}
+
+void *etraxfs_dmac_init(hwaddr base, int nr_channels)
+{
+       struct fs_dma_ctrl *ctrl = NULL;
+
+       ctrl = g_malloc0(sizeof *ctrl);
+
+        ctrl->bh = qemu_bh_new(DMA_run, ctrl);
+
+       ctrl->nr_channels = nr_channels;
+       ctrl->channels = g_malloc0(sizeof ctrl->channels[0] * nr_channels);
+
+       memory_region_init_io(&ctrl->mmio, &dma_ops, ctrl, "etraxfs-dma",
+                             nr_channels * 0x2000);
+       memory_region_add_subregion(get_system_memory(), base, &ctrl->mmio);
+
+       return ctrl;
+}
diff --git a/hw/dma/i82374.c b/hw/dma/i82374.c
new file mode 100644 (file)
index 0000000..835639d
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * 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 "hw/isa/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];
+    qemu_irq out;
+} 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, &s->out);
+    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);
+
+    qdev_init_gpio_out(&dev->qdev, &s->out, 1);
+
+    return 0;
+}
+
+static Property i82374_properties[] = {
+    DEFINE_PROP_HEX32("iobase", ISAi82374State, iobase, 0x400),
+    DEFINE_PROP_END_OF_LIST()
+};
+
+static void i82374_class_init(ObjectClass *klass, void *data)
+{
+    ISADeviceClass *k = ISA_DEVICE_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    
+    k->init  = i82374_isa_init;
+    dc->vmsd = &vmstate_isa_i82374;
+    dc->props = i82374_properties;
+}
+
+static const TypeInfo i82374_isa_info = {
+    .name  = "i82374",
+    .parent = TYPE_ISA_DEVICE,
+    .instance_size  = sizeof(ISAi82374State),
+    .class_init = i82374_class_init,
+};
+
+static void i82374_register_types(void)
+{
+    type_register_static(&i82374_isa_info);
+}
+
+type_init(i82374_register_types)
diff --git a/hw/dma/i8257.c b/hw/dma/i8257.c
new file mode 100644 (file)
index 0000000..eb60d45
--- /dev/null
@@ -0,0 +1,600 @@
+/*
+ * QEMU DMA emulation
+ *
+ * Copyright (c) 2003-2004 Vassili Karpov (malc)
+ *
+ * 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 "hw/hw.h"
+#include "hw/isa/isa.h"
+#include "qemu/main-loop.h"
+
+/* #define DEBUG_DMA */
+
+#define dolog(...) fprintf (stderr, "dma: " __VA_ARGS__)
+#ifdef DEBUG_DMA
+#define linfo(...) fprintf (stderr, "dma: " __VA_ARGS__)
+#define ldebug(...) fprintf (stderr, "dma: " __VA_ARGS__)
+#else
+#define linfo(...)
+#define ldebug(...)
+#endif
+
+struct dma_regs {
+    int now[2];
+    uint16_t base[2];
+    uint8_t mode;
+    uint8_t page;
+    uint8_t pageh;
+    uint8_t dack;
+    uint8_t eop;
+    DMA_transfer_handler transfer_handler;
+    void *opaque;
+};
+
+#define ADDR 0
+#define COUNT 1
+
+static struct dma_cont {
+    uint8_t status;
+    uint8_t command;
+    uint8_t mask;
+    uint8_t flip_flop;
+    int dshift;
+    struct dma_regs regs[4];
+    qemu_irq *cpu_request_exit;
+    MemoryRegion channel_io;
+    MemoryRegion cont_io;
+} dma_controllers[2];
+
+enum {
+    CMD_MEMORY_TO_MEMORY = 0x01,
+    CMD_FIXED_ADDRESS    = 0x02,
+    CMD_BLOCK_CONTROLLER = 0x04,
+    CMD_COMPRESSED_TIME  = 0x08,
+    CMD_CYCLIC_PRIORITY  = 0x10,
+    CMD_EXTENDED_WRITE   = 0x20,
+    CMD_LOW_DREQ         = 0x40,
+    CMD_LOW_DACK         = 0x80,
+    CMD_NOT_SUPPORTED    = CMD_MEMORY_TO_MEMORY | CMD_FIXED_ADDRESS
+    | CMD_COMPRESSED_TIME | CMD_CYCLIC_PRIORITY | CMD_EXTENDED_WRITE
+    | CMD_LOW_DREQ | CMD_LOW_DACK
+
+};
+
+static void DMA_run (void);
+
+static int channels[8] = {-1, 2, 3, 1, -1, -1, -1, 0};
+
+static void write_page (void *opaque, uint32_t nport, uint32_t data)
+{
+    struct dma_cont *d = opaque;
+    int ichan;
+
+    ichan = channels[nport & 7];
+    if (-1 == ichan) {
+        dolog ("invalid channel %#x %#x\n", nport, data);
+        return;
+    }
+    d->regs[ichan].page = data;
+}
+
+static void write_pageh (void *opaque, uint32_t nport, uint32_t data)
+{
+    struct dma_cont *d = opaque;
+    int ichan;
+
+    ichan = channels[nport & 7];
+    if (-1 == ichan) {
+        dolog ("invalid channel %#x %#x\n", nport, data);
+        return;
+    }
+    d->regs[ichan].pageh = data;
+}
+
+static uint32_t read_page (void *opaque, uint32_t nport)
+{
+    struct dma_cont *d = opaque;
+    int ichan;
+
+    ichan = channels[nport & 7];
+    if (-1 == ichan) {
+        dolog ("invalid channel read %#x\n", nport);
+        return 0;
+    }
+    return d->regs[ichan].page;
+}
+
+static uint32_t read_pageh (void *opaque, uint32_t nport)
+{
+    struct dma_cont *d = opaque;
+    int ichan;
+
+    ichan = channels[nport & 7];
+    if (-1 == ichan) {
+        dolog ("invalid channel read %#x\n", nport);
+        return 0;
+    }
+    return d->regs[ichan].pageh;
+}
+
+static inline void init_chan (struct dma_cont *d, int ichan)
+{
+    struct dma_regs *r;
+
+    r = d->regs + ichan;
+    r->now[ADDR] = r->base[ADDR] << d->dshift;
+    r->now[COUNT] = 0;
+}
+
+static inline int getff (struct dma_cont *d)
+{
+    int ff;
+
+    ff = d->flip_flop;
+    d->flip_flop = !ff;
+    return ff;
+}
+
+static uint64_t read_chan(void *opaque, hwaddr nport, unsigned size)
+{
+    struct dma_cont *d = opaque;
+    int ichan, nreg, iport, ff, val, dir;
+    struct dma_regs *r;
+
+    iport = (nport >> d->dshift) & 0x0f;
+    ichan = iport >> 1;
+    nreg = iport & 1;
+    r = d->regs + ichan;
+
+    dir = ((r->mode >> 5) & 1) ? -1 : 1;
+    ff = getff (d);
+    if (nreg)
+        val = (r->base[COUNT] << d->dshift) - r->now[COUNT];
+    else
+        val = r->now[ADDR] + r->now[COUNT] * dir;
+
+    ldebug ("read_chan %#x -> %d\n", iport, val);
+    return (val >> (d->dshift + (ff << 3))) & 0xff;
+}
+
+static void write_chan(void *opaque, hwaddr nport, uint64_t data,
+                       unsigned size)
+{
+    struct dma_cont *d = opaque;
+    int iport, ichan, nreg;
+    struct dma_regs *r;
+
+    iport = (nport >> d->dshift) & 0x0f;
+    ichan = iport >> 1;
+    nreg = iport & 1;
+    r = d->regs + ichan;
+    if (getff (d)) {
+        r->base[nreg] = (r->base[nreg] & 0xff) | ((data << 8) & 0xff00);
+        init_chan (d, ichan);
+    } else {
+        r->base[nreg] = (r->base[nreg] & 0xff00) | (data & 0xff);
+    }
+}
+
+static void write_cont(void *opaque, hwaddr nport, uint64_t data,
+                       unsigned size)
+{
+    struct dma_cont *d = opaque;
+    int iport, ichan = 0;
+
+    iport = (nport >> d->dshift) & 0x0f;
+    switch (iport) {
+    case 0x00:                  /* command */
+        if ((data != 0) && (data & CMD_NOT_SUPPORTED)) {
+            dolog("command %"PRIx64" not supported\n", data);
+            return;
+        }
+        d->command = data;
+        break;
+
+    case 0x01:
+        ichan = data & 3;
+        if (data & 4) {
+            d->status |= 1 << (ichan + 4);
+        }
+        else {
+            d->status &= ~(1 << (ichan + 4));
+        }
+        d->status &= ~(1 << ichan);
+        DMA_run();
+        break;
+
+    case 0x02:                  /* single mask */
+        if (data & 4)
+            d->mask |= 1 << (data & 3);
+        else
+            d->mask &= ~(1 << (data & 3));
+        DMA_run();
+        break;
+
+    case 0x03:                  /* mode */
+        {
+            ichan = data & 3;
+#ifdef DEBUG_DMA
+            {
+                int op, ai, dir, opmode;
+                op = (data >> 2) & 3;
+                ai = (data >> 4) & 1;
+                dir = (data >> 5) & 1;
+                opmode = (data >> 6) & 3;
+
+                linfo ("ichan %d, op %d, ai %d, dir %d, opmode %d\n",
+                       ichan, op, ai, dir, opmode);
+            }
+#endif
+            d->regs[ichan].mode = data;
+            break;
+        }
+
+    case 0x04:                  /* clear flip flop */
+        d->flip_flop = 0;
+        break;
+
+    case 0x05:                  /* reset */
+        d->flip_flop = 0;
+        d->mask = ~0;
+        d->status = 0;
+        d->command = 0;
+        break;
+
+    case 0x06:                  /* clear mask for all channels */
+        d->mask = 0;
+        DMA_run();
+        break;
+
+    case 0x07:                  /* write mask for all channels */
+        d->mask = data;
+        DMA_run();
+        break;
+
+    default:
+        dolog ("unknown iport %#x\n", iport);
+        break;
+    }
+
+#ifdef DEBUG_DMA
+    if (0xc != iport) {
+        linfo ("write_cont: nport %#06x, ichan % 2d, val %#06x\n",
+               nport, ichan, data);
+    }
+#endif
+}
+
+static uint64_t read_cont(void *opaque, hwaddr nport, unsigned size)
+{
+    struct dma_cont *d = opaque;
+    int iport, val;
+
+    iport = (nport >> d->dshift) & 0x0f;
+    switch (iport) {
+    case 0x00:                  /* status */
+        val = d->status;
+        d->status &= 0xf0;
+        break;
+    case 0x01:                  /* mask */
+        val = d->mask;
+        break;
+    default:
+        val = 0;
+        break;
+    }
+
+    ldebug ("read_cont: nport %#06x, iport %#04x val %#x\n", nport, iport, val);
+    return val;
+}
+
+int DMA_get_channel_mode (int nchan)
+{
+    return dma_controllers[nchan > 3].regs[nchan & 3].mode;
+}
+
+void DMA_hold_DREQ (int nchan)
+{
+    int ncont, ichan;
+
+    ncont = nchan > 3;
+    ichan = nchan & 3;
+    linfo ("held cont=%d chan=%d\n", ncont, ichan);
+    dma_controllers[ncont].status |= 1 << (ichan + 4);
+    DMA_run();
+}
+
+void DMA_release_DREQ (int nchan)
+{
+    int ncont, ichan;
+
+    ncont = nchan > 3;
+    ichan = nchan & 3;
+    linfo ("released cont=%d chan=%d\n", ncont, ichan);
+    dma_controllers[ncont].status &= ~(1 << (ichan + 4));
+    DMA_run();
+}
+
+static void channel_run (int ncont, int ichan)
+{
+    int n;
+    struct dma_regs *r = &dma_controllers[ncont].regs[ichan];
+#ifdef DEBUG_DMA
+    int dir, opmode;
+
+    dir = (r->mode >> 5) & 1;
+    opmode = (r->mode >> 6) & 3;
+
+    if (dir) {
+        dolog ("DMA in address decrement mode\n");
+    }
+    if (opmode != 1) {
+        dolog ("DMA not in single mode select %#x\n", opmode);
+    }
+#endif
+
+    n = r->transfer_handler (r->opaque, ichan + (ncont << 2),
+                             r->now[COUNT], (r->base[COUNT] + 1) << ncont);
+    r->now[COUNT] = n;
+    ldebug ("dma_pos %d size %d\n", n, (r->base[COUNT] + 1) << ncont);
+}
+
+static QEMUBH *dma_bh;
+
+static void DMA_run (void)
+{
+    struct dma_cont *d;
+    int icont, ichan;
+    int rearm = 0;
+    static int running = 0;
+
+    if (running) {
+        rearm = 1;
+        goto out;
+    } else {
+        running = 1;
+    }
+
+    d = dma_controllers;
+
+    for (icont = 0; icont < 2; icont++, d++) {
+        for (ichan = 0; ichan < 4; ichan++) {
+            int mask;
+
+            mask = 1 << ichan;
+
+            if ((0 == (d->mask & mask)) && (0 != (d->status & (mask << 4)))) {
+                channel_run (icont, ichan);
+                rearm = 1;
+            }
+        }
+    }
+
+    running = 0;
+out:
+    if (rearm)
+        qemu_bh_schedule_idle(dma_bh);
+}
+
+static void DMA_run_bh(void *unused)
+{
+    DMA_run();
+}
+
+void DMA_register_channel (int nchan,
+                           DMA_transfer_handler transfer_handler,
+                           void *opaque)
+{
+    struct dma_regs *r;
+    int ichan, ncont;
+
+    ncont = nchan > 3;
+    ichan = nchan & 3;
+
+    r = dma_controllers[ncont].regs + ichan;
+    r->transfer_handler = transfer_handler;
+    r->opaque = opaque;
+}
+
+int DMA_read_memory (int nchan, void *buf, int pos, int len)
+{
+    struct dma_regs *r = &dma_controllers[nchan > 3].regs[nchan & 3];
+    hwaddr addr = ((r->pageh & 0x7f) << 24) | (r->page << 16) | r->now[ADDR];
+
+    if (r->mode & 0x20) {
+        int i;
+        uint8_t *p = buf;
+
+        cpu_physical_memory_read (addr - pos - len, buf, len);
+        /* What about 16bit transfers? */
+        for (i = 0; i < len >> 1; i++) {
+            uint8_t b = p[len - i - 1];
+            p[i] = b;
+        }
+    }
+    else
+        cpu_physical_memory_read (addr + pos, buf, len);
+
+    return len;
+}
+
+int DMA_write_memory (int nchan, void *buf, int pos, int len)
+{
+    struct dma_regs *r = &dma_controllers[nchan > 3].regs[nchan & 3];
+    hwaddr addr = ((r->pageh & 0x7f) << 24) | (r->page << 16) | r->now[ADDR];
+
+    if (r->mode & 0x20) {
+        int i;
+        uint8_t *p = buf;
+
+        cpu_physical_memory_write (addr - pos - len, buf, len);
+        /* What about 16bit transfers? */
+        for (i = 0; i < len; i++) {
+            uint8_t b = p[len - i - 1];
+            p[i] = b;
+        }
+    }
+    else
+        cpu_physical_memory_write (addr + pos, buf, len);
+
+    return len;
+}
+
+/* request the emulator to transfer a new DMA memory block ASAP */
+void DMA_schedule(int nchan)
+{
+    struct dma_cont *d = &dma_controllers[nchan > 3];
+
+    qemu_irq_pulse(*d->cpu_request_exit);
+}
+
+static void dma_reset(void *opaque)
+{
+    struct dma_cont *d = opaque;
+    write_cont(d, (0x05 << d->dshift), 0, 1);
+}
+
+static int dma_phony_handler (void *opaque, int nchan, int dma_pos, int dma_len)
+{
+    dolog ("unregistered DMA channel used nchan=%d dma_pos=%d dma_len=%d\n",
+           nchan, dma_pos, dma_len);
+    return dma_pos;
+}
+
+
+static const MemoryRegionOps channel_io_ops = {
+    .read = read_chan,
+    .write = write_chan,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+};
+
+/* IOport from page_base */
+static const MemoryRegionPortio page_portio_list[] = {
+    { 0x01, 3, 1, .write = write_page, .read = read_page, },
+    { 0x07, 1, 1, .write = write_page, .read = read_page, },
+    PORTIO_END_OF_LIST(),
+};
+
+/* IOport from pageh_base */
+static const MemoryRegionPortio pageh_portio_list[] = {
+    { 0x01, 3, 1, .write = write_pageh, .read = read_pageh, },
+    { 0x07, 3, 1, .write = write_pageh, .read = read_pageh, },
+    PORTIO_END_OF_LIST(),
+};
+
+static const MemoryRegionOps cont_io_ops = {
+    .read = read_cont,
+    .write = write_cont,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+};
+
+/* dshift = 0: 8 bit DMA, 1 = 16 bit DMA */
+static void dma_init2(struct dma_cont *d, int base, int dshift,
+                      int page_base, int pageh_base,
+                      qemu_irq *cpu_request_exit)
+{
+    int i;
+
+    d->dshift = dshift;
+    d->cpu_request_exit = cpu_request_exit;
+
+    memory_region_init_io(&d->channel_io, &channel_io_ops, d,
+                          "dma-chan", 8 << d->dshift);
+    memory_region_add_subregion(isa_address_space_io(NULL),
+                                base, &d->channel_io);
+
+    isa_register_portio_list(NULL, page_base, page_portio_list, d,
+                             "dma-page");
+    if (pageh_base >= 0) {
+        isa_register_portio_list(NULL, pageh_base, pageh_portio_list, d,
+                                 "dma-pageh");
+    }
+
+    memory_region_init_io(&d->cont_io, &cont_io_ops, d, "dma-cont",
+                          8 << d->dshift);
+    memory_region_add_subregion(isa_address_space_io(NULL),
+                                base + (8 << d->dshift), &d->cont_io);
+
+    qemu_register_reset(dma_reset, d);
+    dma_reset(d);
+    for (i = 0; i < ARRAY_SIZE (d->regs); ++i) {
+        d->regs[i].transfer_handler = dma_phony_handler;
+    }
+}
+
+static const VMStateDescription vmstate_dma_regs = {
+    .name = "dma_regs",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_INT32_ARRAY(now, struct dma_regs, 2),
+        VMSTATE_UINT16_ARRAY(base, struct dma_regs, 2),
+        VMSTATE_UINT8(mode, struct dma_regs),
+        VMSTATE_UINT8(page, struct dma_regs),
+        VMSTATE_UINT8(pageh, struct dma_regs),
+        VMSTATE_UINT8(dack, struct dma_regs),
+        VMSTATE_UINT8(eop, struct dma_regs),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int dma_post_load(void *opaque, int version_id)
+{
+    DMA_run();
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_dma = {
+    .name = "dma",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .post_load = dma_post_load,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT8(command, struct dma_cont),
+        VMSTATE_UINT8(mask, struct dma_cont),
+        VMSTATE_UINT8(flip_flop, struct dma_cont),
+        VMSTATE_INT32(dshift, struct dma_cont),
+        VMSTATE_STRUCT_ARRAY(regs, struct dma_cont, 4, 1, vmstate_dma_regs, struct dma_regs),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+void DMA_init(int high_page_enable, qemu_irq *cpu_request_exit)
+{
+    dma_init2(&dma_controllers[0], 0x00, 0, 0x80,
+              high_page_enable ? 0x480 : -1, cpu_request_exit);
+    dma_init2(&dma_controllers[1], 0xc0, 1, 0x88,
+              high_page_enable ? 0x488 : -1, cpu_request_exit);
+    vmstate_register (NULL, 0, &vmstate_dma, &dma_controllers[0]);
+    vmstate_register (NULL, 1, &vmstate_dma, &dma_controllers[1]);
+
+    dma_bh = qemu_bh_new(DMA_run_bh, NULL);
+}
diff --git a/hw/dma/omap_dma.c b/hw/dma/omap_dma.c
new file mode 100644 (file)
index 0000000..184fcee
--- /dev/null
@@ -0,0 +1,2101 @@
+/*
+ * TI OMAP DMA gigacell.
+ *
+ * Copyright (C) 2006-2008 Andrzej Zaborowski  <balrog@zabor.org>
+ * Copyright (C) 2007-2008 Lauro Ramos Venancio  <lauro.venancio@indt.org.br>
+ *
+ * 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 "qemu/timer.h"
+#include "hw/arm/omap.h"
+#include "hw/irq.h"
+#include "hw/arm/soc_dma.h"
+
+struct omap_dma_channel_s {
+    /* transfer data */
+    int burst[2];
+    int pack[2];
+    int endian[2];
+    int endian_lock[2];
+    int translate[2];
+    enum omap_dma_port port[2];
+    hwaddr addr[2];
+    omap_dma_addressing_t mode[2];
+    uint32_t elements;
+    uint16_t frames;
+    int32_t frame_index[2];
+    int16_t element_index[2];
+    int data_type;
+
+    /* transfer type */
+    int transparent_copy;
+    int constant_fill;
+    uint32_t color;
+    int prefetch;
+
+    /* auto init and linked channel data */
+    int end_prog;
+    int repeat;
+    int auto_init;
+    int link_enabled;
+    int link_next_ch;
+
+    /* interruption data */
+    int interrupts;
+    int status;
+    int cstatus;
+
+    /* state data */
+    int active;
+    int enable;
+    int sync;
+    int src_sync;
+    int pending_request;
+    int waiting_end_prog;
+    uint16_t cpc;
+    int set_update;
+
+    /* sync type */
+    int fs;
+    int bs;
+
+    /* compatibility */
+    int omap_3_1_compatible_disable;
+
+    qemu_irq irq;
+    struct omap_dma_channel_s *sibling;
+
+    struct omap_dma_reg_set_s {
+        hwaddr src, dest;
+        int frame;
+        int element;
+        int pck_element;
+        int frame_delta[2];
+        int elem_delta[2];
+        int frames;
+        int elements;
+        int pck_elements;
+    } active_set;
+
+    struct soc_dma_ch_s *dma;
+
+    /* unused parameters */
+    int write_mode;
+    int priority;
+    int interleave_disabled;
+    int type;
+    int suspend;
+    int buf_disable;
+};
+
+struct omap_dma_s {
+    struct soc_dma_s *dma;
+    MemoryRegion iomem;
+
+    struct omap_mpu_state_s *mpu;
+    omap_clk clk;
+    qemu_irq irq[4];
+    void (*intr_update)(struct omap_dma_s *s);
+    enum omap_dma_model model;
+    int omap_3_1_mapping_disabled;
+
+    uint32_t gcr;
+    uint32_t ocp;
+    uint32_t caps[5];
+    uint32_t irqen[4];
+    uint32_t irqstat[4];
+
+    int chans;
+    struct omap_dma_channel_s ch[32];
+    struct omap_dma_lcd_channel_s lcd_ch;
+};
+
+/* Interrupts */
+#define TIMEOUT_INTR    (1 << 0)
+#define EVENT_DROP_INTR (1 << 1)
+#define HALF_FRAME_INTR (1 << 2)
+#define END_FRAME_INTR  (1 << 3)
+#define LAST_FRAME_INTR (1 << 4)
+#define END_BLOCK_INTR  (1 << 5)
+#define SYNC            (1 << 6)
+#define END_PKT_INTR   (1 << 7)
+#define TRANS_ERR_INTR (1 << 8)
+#define MISALIGN_INTR  (1 << 11)
+
+static inline void omap_dma_interrupts_update(struct omap_dma_s *s)
+{
+    return s->intr_update(s);
+}
+
+static void omap_dma_channel_load(struct omap_dma_channel_s *ch)
+{
+    struct omap_dma_reg_set_s *a = &ch->active_set;
+    int i, normal;
+    int omap_3_1 = !ch->omap_3_1_compatible_disable;
+
+    /*
+     * TODO: verify address ranges and alignment
+     * TODO: port endianness
+     */
+
+    a->src = ch->addr[0];
+    a->dest = ch->addr[1];
+    a->frames = ch->frames;
+    a->elements = ch->elements;
+    a->pck_elements = ch->frame_index[!ch->src_sync];
+    a->frame = 0;
+    a->element = 0;
+    a->pck_element = 0;
+
+    if (unlikely(!ch->elements || !ch->frames)) {
+        printf("%s: bad DMA request\n", __FUNCTION__);
+        return;
+    }
+
+    for (i = 0; i < 2; i ++)
+        switch (ch->mode[i]) {
+        case constant:
+            a->elem_delta[i] = 0;
+            a->frame_delta[i] = 0;
+            break;
+        case post_incremented:
+            a->elem_delta[i] = ch->data_type;
+            a->frame_delta[i] = 0;
+            break;
+        case single_index:
+            a->elem_delta[i] = ch->data_type +
+                    ch->element_index[omap_3_1 ? 0 : i] - 1;
+            a->frame_delta[i] = 0;
+            break;
+        case double_index:
+            a->elem_delta[i] = ch->data_type +
+                    ch->element_index[omap_3_1 ? 0 : i] - 1;
+            a->frame_delta[i] = ch->frame_index[omap_3_1 ? 0 : i] -
+                    ch->element_index[omap_3_1 ? 0 : i];
+            break;
+        default:
+            break;
+        }
+
+    normal = !ch->transparent_copy && !ch->constant_fill &&
+            /* FIFO is big-endian so either (ch->endian[n] == 1) OR
+             * (ch->endian_lock[n] == 1) mean no endianism conversion.  */
+            (ch->endian[0] | ch->endian_lock[0]) ==
+            (ch->endian[1] | ch->endian_lock[1]);
+    for (i = 0; i < 2; i ++) {
+        /* TODO: for a->frame_delta[i] > 0 still use the fast path, just
+         * limit min_elems in omap_dma_transfer_setup to the nearest frame
+         * end.  */
+        if (!a->elem_delta[i] && normal &&
+                        (a->frames == 1 || !a->frame_delta[i]))
+            ch->dma->type[i] = soc_dma_access_const;
+        else if (a->elem_delta[i] == ch->data_type && normal &&
+                        (a->frames == 1 || !a->frame_delta[i]))
+            ch->dma->type[i] = soc_dma_access_linear;
+        else
+            ch->dma->type[i] = soc_dma_access_other;
+
+        ch->dma->vaddr[i] = ch->addr[i];
+    }
+    soc_dma_ch_update(ch->dma);
+}
+
+static void omap_dma_activate_channel(struct omap_dma_s *s,
+                struct omap_dma_channel_s *ch)
+{
+    if (!ch->active) {
+        if (ch->set_update) {
+            /* It's not clear when the active set is supposed to be
+             * loaded from registers.  We're already loading it when the
+             * channel is enabled, and for some guests this is not enough
+             * but that may be also because of a race condition (no
+             * delays in qemu) in the guest code, which we're just
+             * working around here.  */
+            omap_dma_channel_load(ch);
+            ch->set_update = 0;
+        }
+
+        ch->active = 1;
+        soc_dma_set_request(ch->dma, 1);
+        if (ch->sync)
+            ch->status |= SYNC;
+    }
+}
+
+static void omap_dma_deactivate_channel(struct omap_dma_s *s,
+                struct omap_dma_channel_s *ch)
+{
+    /* Update cpc */
+    ch->cpc = ch->active_set.dest & 0xffff;
+
+    if (ch->pending_request && !ch->waiting_end_prog && ch->enable) {
+        /* Don't deactivate the channel */
+        ch->pending_request = 0;
+        return;
+    }
+
+    /* Don't deactive the channel if it is synchronized and the DMA request is
+       active */
+    if (ch->sync && ch->enable && (s->dma->drqbmp & (1 << ch->sync)))
+        return;
+
+    if (ch->active) {
+        ch->active = 0;
+        ch->status &= ~SYNC;
+        soc_dma_set_request(ch->dma, 0);
+    }
+}
+
+static void omap_dma_enable_channel(struct omap_dma_s *s,
+                struct omap_dma_channel_s *ch)
+{
+    if (!ch->enable) {
+        ch->enable = 1;
+        ch->waiting_end_prog = 0;
+        omap_dma_channel_load(ch);
+        /* TODO: theoretically if ch->sync && ch->prefetch &&
+         * !s->dma->drqbmp[ch->sync], we should also activate and fetch
+         * from source and then stall until signalled.  */
+        if ((!ch->sync) || (s->dma->drqbmp & (1 << ch->sync)))
+            omap_dma_activate_channel(s, ch);
+    }
+}
+
+static void omap_dma_disable_channel(struct omap_dma_s *s,
+                struct omap_dma_channel_s *ch)
+{
+    if (ch->enable) {
+        ch->enable = 0;
+        /* Discard any pending request */
+        ch->pending_request = 0;
+        omap_dma_deactivate_channel(s, ch);
+    }
+}
+
+static void omap_dma_channel_end_prog(struct omap_dma_s *s,
+                struct omap_dma_channel_s *ch)
+{
+    if (ch->waiting_end_prog) {
+        ch->waiting_end_prog = 0;
+        if (!ch->sync || ch->pending_request) {
+            ch->pending_request = 0;
+            omap_dma_activate_channel(s, ch);
+        }
+    }
+}
+
+static void omap_dma_interrupts_3_1_update(struct omap_dma_s *s)
+{
+    struct omap_dma_channel_s *ch = s->ch;
+
+    /* First three interrupts are shared between two channels each. */
+    if (ch[0].status | ch[6].status)
+        qemu_irq_raise(ch[0].irq);
+    if (ch[1].status | ch[7].status)
+        qemu_irq_raise(ch[1].irq);
+    if (ch[2].status | ch[8].status)
+        qemu_irq_raise(ch[2].irq);
+    if (ch[3].status)
+        qemu_irq_raise(ch[3].irq);
+    if (ch[4].status)
+        qemu_irq_raise(ch[4].irq);
+    if (ch[5].status)
+        qemu_irq_raise(ch[5].irq);
+}
+
+static void omap_dma_interrupts_3_2_update(struct omap_dma_s *s)
+{
+    struct omap_dma_channel_s *ch = s->ch;
+    int i;
+
+    for (i = s->chans; i; ch ++, i --)
+        if (ch->status)
+            qemu_irq_raise(ch->irq);
+}
+
+static void omap_dma_enable_3_1_mapping(struct omap_dma_s *s)
+{
+    s->omap_3_1_mapping_disabled = 0;
+    s->chans = 9;
+    s->intr_update = omap_dma_interrupts_3_1_update;
+}
+
+static void omap_dma_disable_3_1_mapping(struct omap_dma_s *s)
+{
+    s->omap_3_1_mapping_disabled = 1;
+    s->chans = 16;
+    s->intr_update = omap_dma_interrupts_3_2_update;
+}
+
+static void omap_dma_process_request(struct omap_dma_s *s, int request)
+{
+    int channel;
+    int drop_event = 0;
+    struct omap_dma_channel_s *ch = s->ch;
+
+    for (channel = 0; channel < s->chans; channel ++, ch ++) {
+        if (ch->enable && ch->sync == request) {
+            if (!ch->active)
+                omap_dma_activate_channel(s, ch);
+            else if (!ch->pending_request)
+                ch->pending_request = 1;
+            else {
+                /* Request collision */
+                /* Second request received while processing other request */
+                ch->status |= EVENT_DROP_INTR;
+                drop_event = 1;
+            }
+        }
+    }
+
+    if (drop_event)
+        omap_dma_interrupts_update(s);
+}
+
+static void omap_dma_transfer_generic(struct soc_dma_ch_s *dma)
+{
+    uint8_t value[4];
+    struct omap_dma_channel_s *ch = dma->opaque;
+    struct omap_dma_reg_set_s *a = &ch->active_set;
+    int bytes = dma->bytes;
+#ifdef MULTI_REQ
+    uint16_t status = ch->status;
+#endif
+
+    do {
+        /* Transfer a single element */
+        /* FIXME: check the endianness */
+        if (!ch->constant_fill)
+            cpu_physical_memory_read(a->src, value, ch->data_type);
+        else
+            *(uint32_t *) value = ch->color;
+
+        if (!ch->transparent_copy || *(uint32_t *) value != ch->color)
+            cpu_physical_memory_write(a->dest, value, ch->data_type);
+
+        a->src += a->elem_delta[0];
+        a->dest += a->elem_delta[1];
+        a->element ++;
+
+#ifndef MULTI_REQ
+        if (a->element == a->elements) {
+            /* End of Frame */
+            a->element = 0;
+            a->src += a->frame_delta[0];
+            a->dest += a->frame_delta[1];
+            a->frame ++;
+
+            /* If the channel is async, update cpc */
+            if (!ch->sync)
+                ch->cpc = a->dest & 0xffff;
+        }
+    } while ((bytes -= ch->data_type));
+#else
+        /* If the channel is element synchronized, deactivate it */
+        if (ch->sync && !ch->fs && !ch->bs)
+            omap_dma_deactivate_channel(s, ch);
+
+        /* If it is the last frame, set the LAST_FRAME interrupt */
+        if (a->element == 1 && a->frame == a->frames - 1)
+            if (ch->interrupts & LAST_FRAME_INTR)
+                ch->status |= LAST_FRAME_INTR;
+
+        /* If the half of the frame was reached, set the HALF_FRAME
+           interrupt */
+        if (a->element == (a->elements >> 1))
+            if (ch->interrupts & HALF_FRAME_INTR)
+                ch->status |= HALF_FRAME_INTR;
+
+        if (ch->fs && ch->bs) {
+            a->pck_element ++;
+            /* Check if a full packet has beed transferred.  */
+            if (a->pck_element == a->pck_elements) {
+                a->pck_element = 0;
+
+                /* Set the END_PKT interrupt */
+                if ((ch->interrupts & END_PKT_INTR) && !ch->src_sync)
+                    ch->status |= END_PKT_INTR;
+
+                /* If the channel is packet-synchronized, deactivate it */
+                if (ch->sync)
+                    omap_dma_deactivate_channel(s, ch);
+            }
+        }
+
+        if (a->element == a->elements) {
+            /* End of Frame */
+            a->element = 0;
+            a->src += a->frame_delta[0];
+            a->dest += a->frame_delta[1];
+            a->frame ++;
+
+            /* If the channel is frame synchronized, deactivate it */
+            if (ch->sync && ch->fs && !ch->bs)
+                omap_dma_deactivate_channel(s, ch);
+
+            /* If the channel is async, update cpc */
+            if (!ch->sync)
+                ch->cpc = a->dest & 0xffff;
+
+            /* Set the END_FRAME interrupt */
+            if (ch->interrupts & END_FRAME_INTR)
+                ch->status |= END_FRAME_INTR;
+
+            if (a->frame == a->frames) {
+                /* End of Block */
+                /* Disable the channel */
+
+                if (ch->omap_3_1_compatible_disable) {
+                    omap_dma_disable_channel(s, ch);
+                    if (ch->link_enabled)
+                        omap_dma_enable_channel(s,
+                                        &s->ch[ch->link_next_ch]);
+                } else {
+                    if (!ch->auto_init)
+                        omap_dma_disable_channel(s, ch);
+                    else if (ch->repeat || ch->end_prog)
+                        omap_dma_channel_load(ch);
+                    else {
+                        ch->waiting_end_prog = 1;
+                        omap_dma_deactivate_channel(s, ch);
+                    }
+                }
+
+                if (ch->interrupts & END_BLOCK_INTR)
+                    ch->status |= END_BLOCK_INTR;
+            }
+        }
+    } while (status == ch->status && ch->active);
+
+    omap_dma_interrupts_update(s);
+#endif
+}
+
+enum {
+    omap_dma_intr_element_sync,
+    omap_dma_intr_last_frame,
+    omap_dma_intr_half_frame,
+    omap_dma_intr_frame,
+    omap_dma_intr_frame_sync,
+    omap_dma_intr_packet,
+    omap_dma_intr_packet_sync,
+    omap_dma_intr_block,
+    __omap_dma_intr_last,
+};
+
+static void omap_dma_transfer_setup(struct soc_dma_ch_s *dma)
+{
+    struct omap_dma_port_if_s *src_p, *dest_p;
+    struct omap_dma_reg_set_s *a;
+    struct omap_dma_channel_s *ch = dma->opaque;
+    struct omap_dma_s *s = dma->dma->opaque;
+    int frames, min_elems, elements[__omap_dma_intr_last];
+
+    a = &ch->active_set;
+
+    src_p = &s->mpu->port[ch->port[0]];
+    dest_p = &s->mpu->port[ch->port[1]];
+    if ((!ch->constant_fill && !src_p->addr_valid(s->mpu, a->src)) ||
+                    (!dest_p->addr_valid(s->mpu, a->dest))) {
+#if 0
+        /* Bus time-out */
+        if (ch->interrupts & TIMEOUT_INTR)
+            ch->status |= TIMEOUT_INTR;
+        omap_dma_deactivate_channel(s, ch);
+        continue;
+#endif
+        printf("%s: Bus time-out in DMA%i operation\n",
+                        __FUNCTION__, dma->num);
+    }
+
+    min_elems = INT_MAX;
+
+    /* Check all the conditions that terminate the transfer starting
+     * with those that can occur the soonest.  */
+#define INTR_CHECK(cond, id, nelements)        \
+    if (cond) {                        \
+        elements[id] = nelements;      \
+        if (elements[id] < min_elems)  \
+            min_elems = elements[id];  \
+    } else                             \
+        elements[id] = INT_MAX;
+
+    /* Elements */
+    INTR_CHECK(
+                    ch->sync && !ch->fs && !ch->bs,
+                    omap_dma_intr_element_sync,
+                    1)
+
+    /* Frames */
+    /* TODO: for transfers where entire frames can be read and written
+     * using memcpy() but a->frame_delta is non-zero, try to still do
+     * transfers using soc_dma but limit min_elems to a->elements - ...
+     * See also the TODO in omap_dma_channel_load.  */
+    INTR_CHECK(
+                    (ch->interrupts & LAST_FRAME_INTR) &&
+                    ((a->frame < a->frames - 1) || !a->element),
+                    omap_dma_intr_last_frame,
+                    (a->frames - a->frame - 2) * a->elements +
+                    (a->elements - a->element + 1))
+    INTR_CHECK(
+                    ch->interrupts & HALF_FRAME_INTR,
+                    omap_dma_intr_half_frame,
+                    (a->elements >> 1) +
+                    (a->element >= (a->elements >> 1) ? a->elements : 0) -
+                    a->element)
+    INTR_CHECK(
+                    ch->sync && ch->fs && (ch->interrupts & END_FRAME_INTR),
+                    omap_dma_intr_frame,
+                    a->elements - a->element)
+    INTR_CHECK(
+                    ch->sync && ch->fs && !ch->bs,
+                    omap_dma_intr_frame_sync,
+                    a->elements - a->element)
+
+    /* Packets */
+    INTR_CHECK(
+                    ch->fs && ch->bs &&
+                    (ch->interrupts & END_PKT_INTR) && !ch->src_sync,
+                    omap_dma_intr_packet,
+                    a->pck_elements - a->pck_element)
+    INTR_CHECK(
+                    ch->fs && ch->bs && ch->sync,
+                    omap_dma_intr_packet_sync,
+                    a->pck_elements - a->pck_element)
+
+    /* Blocks */
+    INTR_CHECK(
+                    1,
+                    omap_dma_intr_block,
+                    (a->frames - a->frame - 1) * a->elements +
+                    (a->elements - a->element))
+
+    dma->bytes = min_elems * ch->data_type;
+
+    /* Set appropriate interrupts and/or deactivate channels */
+
+#ifdef MULTI_REQ
+    /* TODO: should all of this only be done if dma->update, and otherwise
+     * inside omap_dma_transfer_generic below - check what's faster.  */
+    if (dma->update) {
+#endif
+
+        /* If the channel is element synchronized, deactivate it */
+        if (min_elems == elements[omap_dma_intr_element_sync])
+            omap_dma_deactivate_channel(s, ch);
+
+        /* If it is the last frame, set the LAST_FRAME interrupt */
+        if (min_elems == elements[omap_dma_intr_last_frame])
+            ch->status |= LAST_FRAME_INTR;
+
+        /* If exactly half of the frame was reached, set the HALF_FRAME
+           interrupt */
+        if (min_elems == elements[omap_dma_intr_half_frame])
+            ch->status |= HALF_FRAME_INTR;
+
+        /* If a full packet has been transferred, set the END_PKT interrupt */
+        if (min_elems == elements[omap_dma_intr_packet])
+            ch->status |= END_PKT_INTR;
+
+        /* If the channel is packet-synchronized, deactivate it */
+        if (min_elems == elements[omap_dma_intr_packet_sync])
+            omap_dma_deactivate_channel(s, ch);
+
+        /* If the channel is frame synchronized, deactivate it */
+        if (min_elems == elements[omap_dma_intr_frame_sync])
+            omap_dma_deactivate_channel(s, ch);
+
+        /* Set the END_FRAME interrupt */
+        if (min_elems == elements[omap_dma_intr_frame])
+            ch->status |= END_FRAME_INTR;
+
+        if (min_elems == elements[omap_dma_intr_block]) {
+            /* End of Block */
+            /* Disable the channel */
+
+            if (ch->omap_3_1_compatible_disable) {
+                omap_dma_disable_channel(s, ch);
+                if (ch->link_enabled)
+                    omap_dma_enable_channel(s, &s->ch[ch->link_next_ch]);
+            } else {
+                if (!ch->auto_init)
+                    omap_dma_disable_channel(s, ch);
+                else if (ch->repeat || ch->end_prog)
+                    omap_dma_channel_load(ch);
+                else {
+                    ch->waiting_end_prog = 1;
+                    omap_dma_deactivate_channel(s, ch);
+                }
+            }
+
+            if (ch->interrupts & END_BLOCK_INTR)
+                ch->status |= END_BLOCK_INTR;
+        }
+
+        /* Update packet number */
+        if (ch->fs && ch->bs) {
+            a->pck_element += min_elems;
+            a->pck_element %= a->pck_elements;
+        }
+
+        /* TODO: check if we really need to update anything here or perhaps we
+         * can skip part of this.  */
+#ifndef MULTI_REQ
+        if (dma->update) {
+#endif
+            a->element += min_elems;
+
+            frames = a->element / a->elements;
+            a->element = a->element % a->elements;
+            a->frame += frames;
+            a->src += min_elems * a->elem_delta[0] + frames * a->frame_delta[0];
+            a->dest += min_elems * a->elem_delta[1] + frames * a->frame_delta[1];
+
+            /* If the channel is async, update cpc */
+            if (!ch->sync && frames)
+                ch->cpc = a->dest & 0xffff;
+
+            /* TODO: if the destination port is IMIF or EMIFF, set the dirty
+             * bits on it.  */
+#ifndef MULTI_REQ
+        }
+#else
+    }
+#endif
+
+    omap_dma_interrupts_update(s);
+}
+
+void omap_dma_reset(struct soc_dma_s *dma)
+{
+    int i;
+    struct omap_dma_s *s = dma->opaque;
+
+    soc_dma_reset(s->dma);
+    if (s->model < omap_dma_4)
+        s->gcr = 0x0004;
+    else
+        s->gcr = 0x00010010;
+    s->ocp = 0x00000000;
+    memset(&s->irqstat, 0, sizeof(s->irqstat));
+    memset(&s->irqen, 0, sizeof(s->irqen));
+    s->lcd_ch.src = emiff;
+    s->lcd_ch.condition = 0;
+    s->lcd_ch.interrupts = 0;
+    s->lcd_ch.dual = 0;
+    if (s->model < omap_dma_4)
+        omap_dma_enable_3_1_mapping(s);
+    for (i = 0; i < s->chans; i ++) {
+        s->ch[i].suspend = 0;
+        s->ch[i].prefetch = 0;
+        s->ch[i].buf_disable = 0;
+        s->ch[i].src_sync = 0;
+        memset(&s->ch[i].burst, 0, sizeof(s->ch[i].burst));
+        memset(&s->ch[i].port, 0, sizeof(s->ch[i].port));
+        memset(&s->ch[i].mode, 0, sizeof(s->ch[i].mode));
+        memset(&s->ch[i].frame_index, 0, sizeof(s->ch[i].frame_index));
+        memset(&s->ch[i].element_index, 0, sizeof(s->ch[i].element_index));
+        memset(&s->ch[i].endian, 0, sizeof(s->ch[i].endian));
+        memset(&s->ch[i].endian_lock, 0, sizeof(s->ch[i].endian_lock));
+        memset(&s->ch[i].translate, 0, sizeof(s->ch[i].translate));
+        s->ch[i].write_mode = 0;
+        s->ch[i].data_type = 0;
+        s->ch[i].transparent_copy = 0;
+        s->ch[i].constant_fill = 0;
+        s->ch[i].color = 0x00000000;
+        s->ch[i].end_prog = 0;
+        s->ch[i].repeat = 0;
+        s->ch[i].auto_init = 0;
+        s->ch[i].link_enabled = 0;
+        if (s->model < omap_dma_4)
+            s->ch[i].interrupts = 0x0003;
+        else
+            s->ch[i].interrupts = 0x0000;
+        s->ch[i].status = 0;
+        s->ch[i].cstatus = 0;
+        s->ch[i].active = 0;
+        s->ch[i].enable = 0;
+        s->ch[i].sync = 0;
+        s->ch[i].pending_request = 0;
+        s->ch[i].waiting_end_prog = 0;
+        s->ch[i].cpc = 0x0000;
+        s->ch[i].fs = 0;
+        s->ch[i].bs = 0;
+        s->ch[i].omap_3_1_compatible_disable = 0;
+        memset(&s->ch[i].active_set, 0, sizeof(s->ch[i].active_set));
+        s->ch[i].priority = 0;
+        s->ch[i].interleave_disabled = 0;
+        s->ch[i].type = 0;
+    }
+}
+
+static int omap_dma_ch_reg_read(struct omap_dma_s *s,
+                struct omap_dma_channel_s *ch, int reg, uint16_t *value)
+{
+    switch (reg) {
+    case 0x00: /* SYS_DMA_CSDP_CH0 */
+        *value = (ch->burst[1] << 14) |
+                (ch->pack[1] << 13) |
+                (ch->port[1] << 9) |
+                (ch->burst[0] << 7) |
+                (ch->pack[0] << 6) |
+                (ch->port[0] << 2) |
+                (ch->data_type >> 1);
+        break;
+
+    case 0x02: /* SYS_DMA_CCR_CH0 */
+        if (s->model <= omap_dma_3_1)
+            *value = 0 << 10;                  /* FIFO_FLUSH reads as 0 */
+        else
+            *value = ch->omap_3_1_compatible_disable << 10;
+        *value |= (ch->mode[1] << 14) |
+                (ch->mode[0] << 12) |
+                (ch->end_prog << 11) |
+                (ch->repeat << 9) |
+                (ch->auto_init << 8) |
+                (ch->enable << 7) |
+                (ch->priority << 6) |
+                (ch->fs << 5) | ch->sync;
+        break;
+
+    case 0x04: /* SYS_DMA_CICR_CH0 */
+        *value = ch->interrupts;
+        break;
+
+    case 0x06: /* SYS_DMA_CSR_CH0 */
+        *value = ch->status;
+        ch->status &= SYNC;
+        if (!ch->omap_3_1_compatible_disable && ch->sibling) {
+            *value |= (ch->sibling->status & 0x3f) << 6;
+            ch->sibling->status &= SYNC;
+        }
+        qemu_irq_lower(ch->irq);
+        break;
+
+    case 0x08: /* SYS_DMA_CSSA_L_CH0 */
+        *value = ch->addr[0] & 0x0000ffff;
+        break;
+
+    case 0x0a: /* SYS_DMA_CSSA_U_CH0 */
+        *value = ch->addr[0] >> 16;
+        break;
+
+    case 0x0c: /* SYS_DMA_CDSA_L_CH0 */
+        *value = ch->addr[1] & 0x0000ffff;
+        break;
+
+    case 0x0e: /* SYS_DMA_CDSA_U_CH0 */
+        *value = ch->addr[1] >> 16;
+        break;
+
+    case 0x10: /* SYS_DMA_CEN_CH0 */
+        *value = ch->elements;
+        break;
+
+    case 0x12: /* SYS_DMA_CFN_CH0 */
+        *value = ch->frames;
+        break;
+
+    case 0x14: /* SYS_DMA_CFI_CH0 */
+        *value = ch->frame_index[0];
+        break;
+
+    case 0x16: /* SYS_DMA_CEI_CH0 */
+        *value = ch->element_index[0];
+        break;
+
+    case 0x18: /* SYS_DMA_CPC_CH0 or DMA_CSAC */
+        if (ch->omap_3_1_compatible_disable)
+            *value = ch->active_set.src & 0xffff;      /* CSAC */
+        else
+            *value = ch->cpc;
+        break;
+
+    case 0x1a: /* DMA_CDAC */
+        *value = ch->active_set.dest & 0xffff; /* CDAC */
+        break;
+
+    case 0x1c: /* DMA_CDEI */
+        *value = ch->element_index[1];
+        break;
+
+    case 0x1e: /* DMA_CDFI */
+        *value = ch->frame_index[1];
+        break;
+
+    case 0x20: /* DMA_COLOR_L */
+        *value = ch->color & 0xffff;
+        break;
+
+    case 0x22: /* DMA_COLOR_U */
+        *value = ch->color >> 16;
+        break;
+
+    case 0x24: /* DMA_CCR2 */
+        *value = (ch->bs << 2) |
+                (ch->transparent_copy << 1) |
+                ch->constant_fill;
+        break;
+
+    case 0x28: /* DMA_CLNK_CTRL */
+        *value = (ch->link_enabled << 15) |
+                (ch->link_next_ch & 0xf);
+        break;
+
+    case 0x2a: /* DMA_LCH_CTRL */
+        *value = (ch->interleave_disabled << 15) |
+                ch->type;
+        break;
+
+    default:
+        return 1;
+    }
+    return 0;
+}
+
+static int omap_dma_ch_reg_write(struct omap_dma_s *s,
+                struct omap_dma_channel_s *ch, int reg, uint16_t value)
+{
+    switch (reg) {
+    case 0x00: /* SYS_DMA_CSDP_CH0 */
+        ch->burst[1] = (value & 0xc000) >> 14;
+        ch->pack[1] = (value & 0x2000) >> 13;
+        ch->port[1] = (enum omap_dma_port) ((value & 0x1e00) >> 9);
+        ch->burst[0] = (value & 0x0180) >> 7;
+        ch->pack[0] = (value & 0x0040) >> 6;
+        ch->port[0] = (enum omap_dma_port) ((value & 0x003c) >> 2);
+        ch->data_type = 1 << (value & 3);
+        if (ch->port[0] >= __omap_dma_port_last)
+            printf("%s: invalid DMA port %i\n", __FUNCTION__,
+                            ch->port[0]);
+        if (ch->port[1] >= __omap_dma_port_last)
+            printf("%s: invalid DMA port %i\n", __FUNCTION__,
+                            ch->port[1]);
+        if ((value & 3) == 3)
+            printf("%s: bad data_type for DMA channel\n", __FUNCTION__);
+        break;
+
+    case 0x02: /* SYS_DMA_CCR_CH0 */
+        ch->mode[1] = (omap_dma_addressing_t) ((value & 0xc000) >> 14);
+        ch->mode[0] = (omap_dma_addressing_t) ((value & 0x3000) >> 12);
+        ch->end_prog = (value & 0x0800) >> 11;
+        if (s->model >= omap_dma_3_2)
+            ch->omap_3_1_compatible_disable  = (value >> 10) & 0x1;
+        ch->repeat = (value & 0x0200) >> 9;
+        ch->auto_init = (value & 0x0100) >> 8;
+        ch->priority = (value & 0x0040) >> 6;
+        ch->fs = (value & 0x0020) >> 5;
+        ch->sync = value & 0x001f;
+
+        if (value & 0x0080)
+            omap_dma_enable_channel(s, ch);
+        else
+            omap_dma_disable_channel(s, ch);
+
+        if (ch->end_prog)
+            omap_dma_channel_end_prog(s, ch);
+
+        break;
+
+    case 0x04: /* SYS_DMA_CICR_CH0 */
+        ch->interrupts = value & 0x3f;
+        break;
+
+    case 0x06: /* SYS_DMA_CSR_CH0 */
+        OMAP_RO_REG((hwaddr) reg);
+        break;
+
+    case 0x08: /* SYS_DMA_CSSA_L_CH0 */
+        ch->addr[0] &= 0xffff0000;
+        ch->addr[0] |= value;
+        break;
+
+    case 0x0a: /* SYS_DMA_CSSA_U_CH0 */
+        ch->addr[0] &= 0x0000ffff;
+        ch->addr[0] |= (uint32_t) value << 16;
+        break;
+
+    case 0x0c: /* SYS_DMA_CDSA_L_CH0 */
+        ch->addr[1] &= 0xffff0000;
+        ch->addr[1] |= value;
+        break;
+
+    case 0x0e: /* SYS_DMA_CDSA_U_CH0 */
+        ch->addr[1] &= 0x0000ffff;
+        ch->addr[1] |= (uint32_t) value << 16;
+        break;
+
+    case 0x10: /* SYS_DMA_CEN_CH0 */
+        ch->elements = value;
+        break;
+
+    case 0x12: /* SYS_DMA_CFN_CH0 */
+        ch->frames = value;
+        break;
+
+    case 0x14: /* SYS_DMA_CFI_CH0 */
+        ch->frame_index[0] = (int16_t) value;
+        break;
+
+    case 0x16: /* SYS_DMA_CEI_CH0 */
+        ch->element_index[0] = (int16_t) value;
+        break;
+
+    case 0x18: /* SYS_DMA_CPC_CH0 or DMA_CSAC */
+        OMAP_RO_REG((hwaddr) reg);
+        break;
+
+    case 0x1c: /* DMA_CDEI */
+        ch->element_index[1] = (int16_t) value;
+        break;
+
+    case 0x1e: /* DMA_CDFI */
+        ch->frame_index[1] = (int16_t) value;
+        break;
+
+    case 0x20: /* DMA_COLOR_L */
+        ch->color &= 0xffff0000;
+        ch->color |= value;
+        break;
+
+    case 0x22: /* DMA_COLOR_U */
+        ch->color &= 0xffff;
+        ch->color |= value << 16;
+        break;
+
+    case 0x24: /* DMA_CCR2 */
+        ch->bs = (value >> 2) & 0x1;
+        ch->transparent_copy = (value >> 1) & 0x1;
+        ch->constant_fill = value & 0x1;
+        break;
+
+    case 0x28: /* DMA_CLNK_CTRL */
+        ch->link_enabled = (value >> 15) & 0x1;
+        if (value & (1 << 14)) {                       /* Stop_Lnk */
+            ch->link_enabled = 0;
+            omap_dma_disable_channel(s, ch);
+        }
+        ch->link_next_ch = value & 0x1f;
+        break;
+
+    case 0x2a: /* DMA_LCH_CTRL */
+        ch->interleave_disabled = (value >> 15) & 0x1;
+        ch->type = value & 0xf;
+        break;
+
+    default:
+        return 1;
+    }
+    return 0;
+}
+
+static int omap_dma_3_2_lcd_write(struct omap_dma_lcd_channel_s *s, int offset,
+                uint16_t value)
+{
+    switch (offset) {
+    case 0xbc0:        /* DMA_LCD_CSDP */
+        s->brust_f2 = (value >> 14) & 0x3;
+        s->pack_f2 = (value >> 13) & 0x1;
+        s->data_type_f2 = (1 << ((value >> 11) & 0x3));
+        s->brust_f1 = (value >> 7) & 0x3;
+        s->pack_f1 = (value >> 6) & 0x1;
+        s->data_type_f1 = (1 << ((value >> 0) & 0x3));
+        break;
+
+    case 0xbc2:        /* DMA_LCD_CCR */
+        s->mode_f2 = (value >> 14) & 0x3;
+        s->mode_f1 = (value >> 12) & 0x3;
+        s->end_prog = (value >> 11) & 0x1;
+        s->omap_3_1_compatible_disable = (value >> 10) & 0x1;
+        s->repeat = (value >> 9) & 0x1;
+        s->auto_init = (value >> 8) & 0x1;
+        s->running = (value >> 7) & 0x1;
+        s->priority = (value >> 6) & 0x1;
+        s->bs = (value >> 4) & 0x1;
+        break;
+
+    case 0xbc4:        /* DMA_LCD_CTRL */
+        s->dst = (value >> 8) & 0x1;
+        s->src = ((value >> 6) & 0x3) << 1;
+        s->condition = 0;
+        /* Assume no bus errors and thus no BUS_ERROR irq bits.  */
+        s->interrupts = (value >> 1) & 1;
+        s->dual = value & 1;
+        break;
+
+    case 0xbc8:        /* TOP_B1_L */
+        s->src_f1_top &= 0xffff0000;
+        s->src_f1_top |= 0x0000ffff & value;
+        break;
+
+    case 0xbca:        /* TOP_B1_U */
+        s->src_f1_top &= 0x0000ffff;
+        s->src_f1_top |= value << 16;
+        break;
+
+    case 0xbcc:        /* BOT_B1_L */
+        s->src_f1_bottom &= 0xffff0000;
+        s->src_f1_bottom |= 0x0000ffff & value;
+        break;
+
+    case 0xbce:        /* BOT_B1_U */
+        s->src_f1_bottom &= 0x0000ffff;
+        s->src_f1_bottom |= (uint32_t) value << 16;
+        break;
+
+    case 0xbd0:        /* TOP_B2_L */
+        s->src_f2_top &= 0xffff0000;
+        s->src_f2_top |= 0x0000ffff & value;
+        break;
+
+    case 0xbd2:        /* TOP_B2_U */
+        s->src_f2_top &= 0x0000ffff;
+        s->src_f2_top |= (uint32_t) value << 16;
+        break;
+
+    case 0xbd4:        /* BOT_B2_L */
+        s->src_f2_bottom &= 0xffff0000;
+        s->src_f2_bottom |= 0x0000ffff & value;
+        break;
+
+    case 0xbd6:        /* BOT_B2_U */
+        s->src_f2_bottom &= 0x0000ffff;
+        s->src_f2_bottom |= (uint32_t) value << 16;
+        break;
+
+    case 0xbd8:        /* DMA_LCD_SRC_EI_B1 */
+        s->element_index_f1 = value;
+        break;
+
+    case 0xbda:        /* DMA_LCD_SRC_FI_B1_L */
+        s->frame_index_f1 &= 0xffff0000;
+        s->frame_index_f1 |= 0x0000ffff & value;
+        break;
+
+    case 0xbf4:        /* DMA_LCD_SRC_FI_B1_U */
+        s->frame_index_f1 &= 0x0000ffff;
+        s->frame_index_f1 |= (uint32_t) value << 16;
+        break;
+
+    case 0xbdc:        /* DMA_LCD_SRC_EI_B2 */
+        s->element_index_f2 = value;
+        break;
+
+    case 0xbde:        /* DMA_LCD_SRC_FI_B2_L */
+        s->frame_index_f2 &= 0xffff0000;
+        s->frame_index_f2 |= 0x0000ffff & value;
+        break;
+
+    case 0xbf6:        /* DMA_LCD_SRC_FI_B2_U */
+        s->frame_index_f2 &= 0x0000ffff;
+        s->frame_index_f2 |= (uint32_t) value << 16;
+        break;
+
+    case 0xbe0:        /* DMA_LCD_SRC_EN_B1 */
+        s->elements_f1 = value;
+        break;
+
+    case 0xbe4:        /* DMA_LCD_SRC_FN_B1 */
+        s->frames_f1 = value;
+        break;
+
+    case 0xbe2:        /* DMA_LCD_SRC_EN_B2 */
+        s->elements_f2 = value;
+        break;
+
+    case 0xbe6:        /* DMA_LCD_SRC_FN_B2 */
+        s->frames_f2 = value;
+        break;
+
+    case 0xbea:        /* DMA_LCD_LCH_CTRL */
+        s->lch_type = value & 0xf;
+        break;
+
+    default:
+        return 1;
+    }
+    return 0;
+}
+
+static int omap_dma_3_2_lcd_read(struct omap_dma_lcd_channel_s *s, int offset,
+                uint16_t *ret)
+{
+    switch (offset) {
+    case 0xbc0:        /* DMA_LCD_CSDP */
+        *ret = (s->brust_f2 << 14) |
+            (s->pack_f2 << 13) |
+            ((s->data_type_f2 >> 1) << 11) |
+            (s->brust_f1 << 7) |
+            (s->pack_f1 << 6) |
+            ((s->data_type_f1 >> 1) << 0);
+        break;
+
+    case 0xbc2:        /* DMA_LCD_CCR */
+        *ret = (s->mode_f2 << 14) |
+            (s->mode_f1 << 12) |
+            (s->end_prog << 11) |
+            (s->omap_3_1_compatible_disable << 10) |
+            (s->repeat << 9) |
+            (s->auto_init << 8) |
+            (s->running << 7) |
+            (s->priority << 6) |
+            (s->bs << 4);
+        break;
+
+    case 0xbc4:        /* DMA_LCD_CTRL */
+        qemu_irq_lower(s->irq);
+        *ret = (s->dst << 8) |
+            ((s->src & 0x6) << 5) |
+            (s->condition << 3) |
+            (s->interrupts << 1) |
+            s->dual;
+        break;
+
+    case 0xbc8:        /* TOP_B1_L */
+        *ret = s->src_f1_top & 0xffff;
+        break;
+
+    case 0xbca:        /* TOP_B1_U */
+        *ret = s->src_f1_top >> 16;
+        break;
+
+    case 0xbcc:        /* BOT_B1_L */
+        *ret = s->src_f1_bottom & 0xffff;
+        break;
+
+    case 0xbce:        /* BOT_B1_U */
+        *ret = s->src_f1_bottom >> 16;
+        break;
+
+    case 0xbd0:        /* TOP_B2_L */
+        *ret = s->src_f2_top & 0xffff;
+        break;
+
+    case 0xbd2:        /* TOP_B2_U */
+        *ret = s->src_f2_top >> 16;
+        break;
+
+    case 0xbd4:        /* BOT_B2_L */
+        *ret = s->src_f2_bottom & 0xffff;
+        break;
+
+    case 0xbd6:        /* BOT_B2_U */
+        *ret = s->src_f2_bottom >> 16;
+        break;
+
+    case 0xbd8:        /* DMA_LCD_SRC_EI_B1 */
+        *ret = s->element_index_f1;
+        break;
+
+    case 0xbda:        /* DMA_LCD_SRC_FI_B1_L */
+        *ret = s->frame_index_f1 & 0xffff;
+        break;
+
+    case 0xbf4:        /* DMA_LCD_SRC_FI_B1_U */
+        *ret = s->frame_index_f1 >> 16;
+        break;
+
+    case 0xbdc:        /* DMA_LCD_SRC_EI_B2 */
+        *ret = s->element_index_f2;
+        break;
+
+    case 0xbde:        /* DMA_LCD_SRC_FI_B2_L */
+        *ret = s->frame_index_f2 & 0xffff;
+        break;
+
+    case 0xbf6:        /* DMA_LCD_SRC_FI_B2_U */
+        *ret = s->frame_index_f2 >> 16;
+        break;
+
+    case 0xbe0:        /* DMA_LCD_SRC_EN_B1 */
+        *ret = s->elements_f1;
+        break;
+
+    case 0xbe4:        /* DMA_LCD_SRC_FN_B1 */
+        *ret = s->frames_f1;
+        break;
+
+    case 0xbe2:        /* DMA_LCD_SRC_EN_B2 */
+        *ret = s->elements_f2;
+        break;
+
+    case 0xbe6:        /* DMA_LCD_SRC_FN_B2 */
+        *ret = s->frames_f2;
+        break;
+
+    case 0xbea:        /* DMA_LCD_LCH_CTRL */
+        *ret = s->lch_type;
+        break;
+
+    default:
+        return 1;
+    }
+    return 0;
+}
+
+static int omap_dma_3_1_lcd_write(struct omap_dma_lcd_channel_s *s, int offset,
+                uint16_t value)
+{
+    switch (offset) {
+    case 0x300:        /* SYS_DMA_LCD_CTRL */
+        s->src = (value & 0x40) ? imif : emiff;
+        s->condition = 0;
+        /* Assume no bus errors and thus no BUS_ERROR irq bits.  */
+        s->interrupts = (value >> 1) & 1;
+        s->dual = value & 1;
+        break;
+
+    case 0x302:        /* SYS_DMA_LCD_TOP_F1_L */
+        s->src_f1_top &= 0xffff0000;
+        s->src_f1_top |= 0x0000ffff & value;
+        break;
+
+    case 0x304:        /* SYS_DMA_LCD_TOP_F1_U */
+        s->src_f1_top &= 0x0000ffff;
+        s->src_f1_top |= value << 16;
+        break;
+
+    case 0x306:        /* SYS_DMA_LCD_BOT_F1_L */
+        s->src_f1_bottom &= 0xffff0000;
+        s->src_f1_bottom |= 0x0000ffff & value;
+        break;
+
+    case 0x308:        /* SYS_DMA_LCD_BOT_F1_U */
+        s->src_f1_bottom &= 0x0000ffff;
+        s->src_f1_bottom |= value << 16;
+        break;
+
+    case 0x30a:        /* SYS_DMA_LCD_TOP_F2_L */
+        s->src_f2_top &= 0xffff0000;
+        s->src_f2_top |= 0x0000ffff & value;
+        break;
+
+    case 0x30c:        /* SYS_DMA_LCD_TOP_F2_U */
+        s->src_f2_top &= 0x0000ffff;
+        s->src_f2_top |= value << 16;
+        break;
+
+    case 0x30e:        /* SYS_DMA_LCD_BOT_F2_L */
+        s->src_f2_bottom &= 0xffff0000;
+        s->src_f2_bottom |= 0x0000ffff & value;
+        break;
+
+    case 0x310:        /* SYS_DMA_LCD_BOT_F2_U */
+        s->src_f2_bottom &= 0x0000ffff;
+        s->src_f2_bottom |= value << 16;
+        break;
+
+    default:
+        return 1;
+    }
+    return 0;
+}
+
+static int omap_dma_3_1_lcd_read(struct omap_dma_lcd_channel_s *s, int offset,
+                uint16_t *ret)
+{
+    int i;
+
+    switch (offset) {
+    case 0x300:        /* SYS_DMA_LCD_CTRL */
+        i = s->condition;
+        s->condition = 0;
+        qemu_irq_lower(s->irq);
+        *ret = ((s->src == imif) << 6) | (i << 3) |
+                (s->interrupts << 1) | s->dual;
+        break;
+
+    case 0x302:        /* SYS_DMA_LCD_TOP_F1_L */
+        *ret = s->src_f1_top & 0xffff;
+        break;
+
+    case 0x304:        /* SYS_DMA_LCD_TOP_F1_U */
+        *ret = s->src_f1_top >> 16;
+        break;
+
+    case 0x306:        /* SYS_DMA_LCD_BOT_F1_L */
+        *ret = s->src_f1_bottom & 0xffff;
+        break;
+
+    case 0x308:        /* SYS_DMA_LCD_BOT_F1_U */
+        *ret = s->src_f1_bottom >> 16;
+        break;
+
+    case 0x30a:        /* SYS_DMA_LCD_TOP_F2_L */
+        *ret = s->src_f2_top & 0xffff;
+        break;
+
+    case 0x30c:        /* SYS_DMA_LCD_TOP_F2_U */
+        *ret = s->src_f2_top >> 16;
+        break;
+
+    case 0x30e:        /* SYS_DMA_LCD_BOT_F2_L */
+        *ret = s->src_f2_bottom & 0xffff;
+        break;
+
+    case 0x310:        /* SYS_DMA_LCD_BOT_F2_U */
+        *ret = s->src_f2_bottom >> 16;
+        break;
+
+    default:
+        return 1;
+    }
+    return 0;
+}
+
+static int omap_dma_sys_write(struct omap_dma_s *s, int offset, uint16_t value)
+{
+    switch (offset) {
+    case 0x400:        /* SYS_DMA_GCR */
+        s->gcr = value;
+        break;
+
+    case 0x404:        /* DMA_GSCR */
+        if (value & 0x8)
+            omap_dma_disable_3_1_mapping(s);
+        else
+            omap_dma_enable_3_1_mapping(s);
+        break;
+
+    case 0x408:        /* DMA_GRST */
+        if (value & 0x1)
+            omap_dma_reset(s->dma);
+        break;
+
+    default:
+        return 1;
+    }
+    return 0;
+}
+
+static int omap_dma_sys_read(struct omap_dma_s *s, int offset,
+                uint16_t *ret)
+{
+    switch (offset) {
+    case 0x400:        /* SYS_DMA_GCR */
+        *ret = s->gcr;
+        break;
+
+    case 0x404:        /* DMA_GSCR */
+        *ret = s->omap_3_1_mapping_disabled << 3;
+        break;
+
+    case 0x408:        /* DMA_GRST */
+        *ret = 0;
+        break;
+
+    case 0x442:        /* DMA_HW_ID */
+    case 0x444:        /* DMA_PCh2_ID */
+    case 0x446:        /* DMA_PCh0_ID */
+    case 0x448:        /* DMA_PCh1_ID */
+    case 0x44a:        /* DMA_PChG_ID */
+    case 0x44c:        /* DMA_PChD_ID */
+        *ret = 1;
+        break;
+
+    case 0x44e:        /* DMA_CAPS_0_U */
+        *ret = (s->caps[0] >> 16) & 0xffff;
+        break;
+    case 0x450:        /* DMA_CAPS_0_L */
+        *ret = (s->caps[0] >>  0) & 0xffff;
+        break;
+
+    case 0x452:        /* DMA_CAPS_1_U */
+        *ret = (s->caps[1] >> 16) & 0xffff;
+        break;
+    case 0x454:        /* DMA_CAPS_1_L */
+        *ret = (s->caps[1] >>  0) & 0xffff;
+        break;
+
+    case 0x456:        /* DMA_CAPS_2 */
+        *ret = s->caps[2];
+        break;
+
+    case 0x458:        /* DMA_CAPS_3 */
+        *ret = s->caps[3];
+        break;
+
+    case 0x45a:        /* DMA_CAPS_4 */
+        *ret = s->caps[4];
+        break;
+
+    case 0x460:        /* DMA_PCh2_SR */
+    case 0x480:        /* DMA_PCh0_SR */
+    case 0x482:        /* DMA_PCh1_SR */
+    case 0x4c0:        /* DMA_PChD_SR_0 */
+        printf("%s: Physical Channel Status Registers not implemented.\n",
+               __FUNCTION__);
+        *ret = 0xff;
+        break;
+
+    default:
+        return 1;
+    }
+    return 0;
+}
+
+static uint64_t omap_dma_read(void *opaque, hwaddr addr,
+                              unsigned size)
+{
+    struct omap_dma_s *s = (struct omap_dma_s *) opaque;
+    int reg, ch;
+    uint16_t ret;
+
+    if (size != 2) {
+        return omap_badwidth_read16(opaque, addr);
+    }
+
+    switch (addr) {
+    case 0x300 ... 0x3fe:
+        if (s->model <= omap_dma_3_1 || !s->omap_3_1_mapping_disabled) {
+            if (omap_dma_3_1_lcd_read(&s->lcd_ch, addr, &ret))
+                break;
+            return ret;
+        }
+        /* Fall through. */
+    case 0x000 ... 0x2fe:
+        reg = addr & 0x3f;
+        ch = (addr >> 6) & 0x0f;
+        if (omap_dma_ch_reg_read(s, &s->ch[ch], reg, &ret))
+            break;
+        return ret;
+
+    case 0x404 ... 0x4fe:
+        if (s->model <= omap_dma_3_1)
+            break;
+        /* Fall through. */
+    case 0x400:
+        if (omap_dma_sys_read(s, addr, &ret))
+            break;
+        return ret;
+
+    case 0xb00 ... 0xbfe:
+        if (s->model == omap_dma_3_2 && s->omap_3_1_mapping_disabled) {
+            if (omap_dma_3_2_lcd_read(&s->lcd_ch, addr, &ret))
+                break;
+            return ret;
+        }
+        break;
+    }
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_dma_write(void *opaque, hwaddr addr,
+                           uint64_t value, unsigned size)
+{
+    struct omap_dma_s *s = (struct omap_dma_s *) opaque;
+    int reg, ch;
+
+    if (size != 2) {
+        return omap_badwidth_write16(opaque, addr, value);
+    }
+
+    switch (addr) {
+    case 0x300 ... 0x3fe:
+        if (s->model <= omap_dma_3_1 || !s->omap_3_1_mapping_disabled) {
+            if (omap_dma_3_1_lcd_write(&s->lcd_ch, addr, value))
+                break;
+            return;
+        }
+        /* Fall through.  */
+    case 0x000 ... 0x2fe:
+        reg = addr & 0x3f;
+        ch = (addr >> 6) & 0x0f;
+        if (omap_dma_ch_reg_write(s, &s->ch[ch], reg, value))
+            break;
+        return;
+
+    case 0x404 ... 0x4fe:
+        if (s->model <= omap_dma_3_1)
+            break;
+    case 0x400:
+        /* Fall through. */
+        if (omap_dma_sys_write(s, addr, value))
+            break;
+        return;
+
+    case 0xb00 ... 0xbfe:
+        if (s->model == omap_dma_3_2 && s->omap_3_1_mapping_disabled) {
+            if (omap_dma_3_2_lcd_write(&s->lcd_ch, addr, value))
+                break;
+            return;
+        }
+        break;
+    }
+
+    OMAP_BAD_REG(addr);
+}
+
+static const MemoryRegionOps omap_dma_ops = {
+    .read = omap_dma_read,
+    .write = omap_dma_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void omap_dma_request(void *opaque, int drq, int req)
+{
+    struct omap_dma_s *s = (struct omap_dma_s *) opaque;
+    /* The request pins are level triggered in QEMU.  */
+    if (req) {
+        if (~s->dma->drqbmp & (1 << drq)) {
+            s->dma->drqbmp |= 1 << drq;
+            omap_dma_process_request(s, drq);
+        }
+    } else
+        s->dma->drqbmp &= ~(1 << drq);
+}
+
+/* XXX: this won't be needed once soc_dma knows about clocks.  */
+static void omap_dma_clk_update(void *opaque, int line, int on)
+{
+    struct omap_dma_s *s = (struct omap_dma_s *) opaque;
+    int i;
+
+    s->dma->freq = omap_clk_getrate(s->clk);
+
+    for (i = 0; i < s->chans; i ++)
+        if (s->ch[i].active)
+            soc_dma_set_request(s->ch[i].dma, on);
+}
+
+static void omap_dma_setcaps(struct omap_dma_s *s)
+{
+    switch (s->model) {
+    default:
+    case omap_dma_3_1:
+        break;
+    case omap_dma_3_2:
+    case omap_dma_4:
+        /* XXX Only available for sDMA */
+        s->caps[0] =
+                (1 << 19) |    /* Constant Fill Capability */
+                (1 << 18);     /* Transparent BLT Capability */
+        s->caps[1] =
+                (1 << 1);      /* 1-bit palettized capability (DMA 3.2 only) */
+        s->caps[2] =
+                (1 << 8) |     /* SEPARATE_SRC_AND_DST_INDEX_CPBLTY */
+                (1 << 7) |     /* DST_DOUBLE_INDEX_ADRS_CPBLTY */
+                (1 << 6) |     /* DST_SINGLE_INDEX_ADRS_CPBLTY */
+                (1 << 5) |     /* DST_POST_INCRMNT_ADRS_CPBLTY */
+                (1 << 4) |     /* DST_CONST_ADRS_CPBLTY */
+                (1 << 3) |     /* SRC_DOUBLE_INDEX_ADRS_CPBLTY */
+                (1 << 2) |     /* SRC_SINGLE_INDEX_ADRS_CPBLTY */
+                (1 << 1) |     /* SRC_POST_INCRMNT_ADRS_CPBLTY */
+                (1 << 0);      /* SRC_CONST_ADRS_CPBLTY */
+        s->caps[3] =
+                (1 << 6) |     /* BLOCK_SYNCHR_CPBLTY (DMA 4 only) */
+                (1 << 7) |     /* PKT_SYNCHR_CPBLTY (DMA 4 only) */
+                (1 << 5) |     /* CHANNEL_CHAINING_CPBLTY */
+                (1 << 4) |     /* LCh_INTERLEAVE_CPBLTY */
+                (1 << 3) |     /* AUTOINIT_REPEAT_CPBLTY (DMA 3.2 only) */
+                (1 << 2) |     /* AUTOINIT_ENDPROG_CPBLTY (DMA 3.2 only) */
+                (1 << 1) |     /* FRAME_SYNCHR_CPBLTY */
+                (1 << 0);      /* ELMNT_SYNCHR_CPBLTY */
+        s->caps[4] =
+                (1 << 7) |     /* PKT_INTERRUPT_CPBLTY (DMA 4 only) */
+                (1 << 6) |     /* SYNC_STATUS_CPBLTY */
+                (1 << 5) |     /* BLOCK_INTERRUPT_CPBLTY */
+                (1 << 4) |     /* LAST_FRAME_INTERRUPT_CPBLTY */
+                (1 << 3) |     /* FRAME_INTERRUPT_CPBLTY */
+                (1 << 2) |     /* HALF_FRAME_INTERRUPT_CPBLTY */
+                (1 << 1) |     /* EVENT_DROP_INTERRUPT_CPBLTY */
+                (1 << 0);      /* TIMEOUT_INTERRUPT_CPBLTY (DMA 3.2 only) */
+        break;
+    }
+}
+
+struct soc_dma_s *omap_dma_init(hwaddr base, qemu_irq *irqs,
+                MemoryRegion *sysmem,
+                qemu_irq lcd_irq, struct omap_mpu_state_s *mpu, omap_clk clk,
+                enum omap_dma_model model)
+{
+    int num_irqs, memsize, i;
+    struct omap_dma_s *s = (struct omap_dma_s *)
+            g_malloc0(sizeof(struct omap_dma_s));
+
+    if (model <= omap_dma_3_1) {
+        num_irqs = 6;
+        memsize = 0x800;
+    } else {
+        num_irqs = 16;
+        memsize = 0xc00;
+    }
+    s->model = model;
+    s->mpu = mpu;
+    s->clk = clk;
+    s->lcd_ch.irq = lcd_irq;
+    s->lcd_ch.mpu = mpu;
+
+    s->dma = soc_dma_init((model <= omap_dma_3_1) ? 9 : 16);
+    s->dma->freq = omap_clk_getrate(clk);
+    s->dma->transfer_fn = omap_dma_transfer_generic;
+    s->dma->setup_fn = omap_dma_transfer_setup;
+    s->dma->drq = qemu_allocate_irqs(omap_dma_request, s, 32);
+    s->dma->opaque = s;
+
+    while (num_irqs --)
+        s->ch[num_irqs].irq = irqs[num_irqs];
+    for (i = 0; i < 3; i ++) {
+        s->ch[i].sibling = &s->ch[i + 6];
+        s->ch[i + 6].sibling = &s->ch[i];
+    }
+    for (i = (model <= omap_dma_3_1) ? 8 : 15; i >= 0; i --) {
+        s->ch[i].dma = &s->dma->ch[i];
+        s->dma->ch[i].opaque = &s->ch[i];
+    }
+
+    omap_dma_setcaps(s);
+    omap_clk_adduser(s->clk, qemu_allocate_irqs(omap_dma_clk_update, s, 1)[0]);
+    omap_dma_reset(s->dma);
+    omap_dma_clk_update(s, 0, 1);
+
+    memory_region_init_io(&s->iomem, &omap_dma_ops, s, "omap.dma", memsize);
+    memory_region_add_subregion(sysmem, base, &s->iomem);
+
+    mpu->drq = s->dma->drq;
+
+    return s->dma;
+}
+
+static void omap_dma_interrupts_4_update(struct omap_dma_s *s)
+{
+    struct omap_dma_channel_s *ch = s->ch;
+    uint32_t bmp, bit;
+
+    for (bmp = 0, bit = 1; bit; ch ++, bit <<= 1)
+        if (ch->status) {
+            bmp |= bit;
+            ch->cstatus |= ch->status;
+            ch->status = 0;
+        }
+    if ((s->irqstat[0] |= s->irqen[0] & bmp))
+        qemu_irq_raise(s->irq[0]);
+    if ((s->irqstat[1] |= s->irqen[1] & bmp))
+        qemu_irq_raise(s->irq[1]);
+    if ((s->irqstat[2] |= s->irqen[2] & bmp))
+        qemu_irq_raise(s->irq[2]);
+    if ((s->irqstat[3] |= s->irqen[3] & bmp))
+        qemu_irq_raise(s->irq[3]);
+}
+
+static uint64_t omap_dma4_read(void *opaque, hwaddr addr,
+                               unsigned size)
+{
+    struct omap_dma_s *s = (struct omap_dma_s *) opaque;
+    int irqn = 0, chnum;
+    struct omap_dma_channel_s *ch;
+
+    if (size == 1) {
+        return omap_badwidth_read16(opaque, addr);
+    }
+
+    switch (addr) {
+    case 0x00: /* DMA4_REVISION */
+        return 0x40;
+
+    case 0x14: /* DMA4_IRQSTATUS_L3 */
+        irqn ++;
+        /* fall through */
+    case 0x10: /* DMA4_IRQSTATUS_L2 */
+        irqn ++;
+        /* fall through */
+    case 0x0c: /* DMA4_IRQSTATUS_L1 */
+        irqn ++;
+        /* fall through */
+    case 0x08: /* DMA4_IRQSTATUS_L0 */
+        return s->irqstat[irqn];
+
+    case 0x24: /* DMA4_IRQENABLE_L3 */
+        irqn ++;
+        /* fall through */
+    case 0x20: /* DMA4_IRQENABLE_L2 */
+        irqn ++;
+        /* fall through */
+    case 0x1c: /* DMA4_IRQENABLE_L1 */
+        irqn ++;
+        /* fall through */
+    case 0x18: /* DMA4_IRQENABLE_L0 */
+        return s->irqen[irqn];
+
+    case 0x28: /* DMA4_SYSSTATUS */
+        return 1;                                              /* RESETDONE */
+
+    case 0x2c: /* DMA4_OCP_SYSCONFIG */
+        return s->ocp;
+
+    case 0x64: /* DMA4_CAPS_0 */
+        return s->caps[0];
+    case 0x6c: /* DMA4_CAPS_2 */
+        return s->caps[2];
+    case 0x70: /* DMA4_CAPS_3 */
+        return s->caps[3];
+    case 0x74: /* DMA4_CAPS_4 */
+        return s->caps[4];
+
+    case 0x78: /* DMA4_GCR */
+        return s->gcr;
+
+    case 0x80 ... 0xfff:
+        addr -= 0x80;
+        chnum = addr / 0x60;
+        ch = s->ch + chnum;
+        addr -= chnum * 0x60;
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+        return 0;
+    }
+
+    /* Per-channel registers */
+    switch (addr) {
+    case 0x00: /* DMA4_CCR */
+        return (ch->buf_disable << 25) |
+                (ch->src_sync << 24) |
+                (ch->prefetch << 23) |
+                ((ch->sync & 0x60) << 14) |
+                (ch->bs << 18) |
+                (ch->transparent_copy << 17) |
+                (ch->constant_fill << 16) |
+                (ch->mode[1] << 14) |
+                (ch->mode[0] << 12) |
+                (0 << 10) | (0 << 9) |
+                (ch->suspend << 8) |
+                (ch->enable << 7) |
+                (ch->priority << 6) |
+                (ch->fs << 5) | (ch->sync & 0x1f);
+
+    case 0x04: /* DMA4_CLNK_CTRL */
+        return (ch->link_enabled << 15) | ch->link_next_ch;
+
+    case 0x08: /* DMA4_CICR */
+        return ch->interrupts;
+
+    case 0x0c: /* DMA4_CSR */
+        return ch->cstatus;
+
+    case 0x10: /* DMA4_CSDP */
+        return (ch->endian[0] << 21) |
+                (ch->endian_lock[0] << 20) |
+                (ch->endian[1] << 19) |
+                (ch->endian_lock[1] << 18) |
+                (ch->write_mode << 16) |
+                (ch->burst[1] << 14) |
+                (ch->pack[1] << 13) |
+                (ch->translate[1] << 9) |
+                (ch->burst[0] << 7) |
+                (ch->pack[0] << 6) |
+                (ch->translate[0] << 2) |
+                (ch->data_type >> 1);
+
+    case 0x14: /* DMA4_CEN */
+        return ch->elements;
+
+    case 0x18: /* DMA4_CFN */
+        return ch->frames;
+
+    case 0x1c: /* DMA4_CSSA */
+        return ch->addr[0];
+
+    case 0x20: /* DMA4_CDSA */
+        return ch->addr[1];
+
+    case 0x24: /* DMA4_CSEI */
+        return ch->element_index[0];
+
+    case 0x28: /* DMA4_CSFI */
+        return ch->frame_index[0];
+
+    case 0x2c: /* DMA4_CDEI */
+        return ch->element_index[1];
+
+    case 0x30: /* DMA4_CDFI */
+        return ch->frame_index[1];
+
+    case 0x34: /* DMA4_CSAC */
+        return ch->active_set.src & 0xffff;
+
+    case 0x38: /* DMA4_CDAC */
+        return ch->active_set.dest & 0xffff;
+
+    case 0x3c: /* DMA4_CCEN */
+        return ch->active_set.element;
+
+    case 0x40: /* DMA4_CCFN */
+        return ch->active_set.frame;
+
+    case 0x44: /* DMA4_COLOR */
+        /* XXX only in sDMA */
+        return ch->color;
+
+    default:
+        OMAP_BAD_REG(addr);
+        return 0;
+    }
+}
+
+static void omap_dma4_write(void *opaque, hwaddr addr,
+                            uint64_t value, unsigned size)
+{
+    struct omap_dma_s *s = (struct omap_dma_s *) opaque;
+    int chnum, irqn = 0;
+    struct omap_dma_channel_s *ch;
+
+    if (size == 1) {
+        return omap_badwidth_write16(opaque, addr, value);
+    }
+
+    switch (addr) {
+    case 0x14: /* DMA4_IRQSTATUS_L3 */
+        irqn ++;
+        /* fall through */
+    case 0x10: /* DMA4_IRQSTATUS_L2 */
+        irqn ++;
+        /* fall through */
+    case 0x0c: /* DMA4_IRQSTATUS_L1 */
+        irqn ++;
+        /* fall through */
+    case 0x08: /* DMA4_IRQSTATUS_L0 */
+        s->irqstat[irqn] &= ~value;
+        if (!s->irqstat[irqn])
+            qemu_irq_lower(s->irq[irqn]);
+        return;
+
+    case 0x24: /* DMA4_IRQENABLE_L3 */
+        irqn ++;
+        /* fall through */
+    case 0x20: /* DMA4_IRQENABLE_L2 */
+        irqn ++;
+        /* fall through */
+    case 0x1c: /* DMA4_IRQENABLE_L1 */
+        irqn ++;
+        /* fall through */
+    case 0x18: /* DMA4_IRQENABLE_L0 */
+        s->irqen[irqn] = value;
+        return;
+
+    case 0x2c: /* DMA4_OCP_SYSCONFIG */
+        if (value & 2)                                         /* SOFTRESET */
+            omap_dma_reset(s->dma);
+        s->ocp = value & 0x3321;
+        if (((s->ocp >> 12) & 3) == 3)                         /* MIDLEMODE */
+            fprintf(stderr, "%s: invalid DMA power mode\n", __FUNCTION__);
+        return;
+
+    case 0x78: /* DMA4_GCR */
+        s->gcr = value & 0x00ff00ff;
+       if ((value & 0xff) == 0x00)             /* MAX_CHANNEL_FIFO_DEPTH */
+            fprintf(stderr, "%s: wrong FIFO depth in GCR\n", __FUNCTION__);
+        return;
+
+    case 0x80 ... 0xfff:
+        addr -= 0x80;
+        chnum = addr / 0x60;
+        ch = s->ch + chnum;
+        addr -= chnum * 0x60;
+        break;
+
+    case 0x00: /* DMA4_REVISION */
+    case 0x28: /* DMA4_SYSSTATUS */
+    case 0x64: /* DMA4_CAPS_0 */
+    case 0x6c: /* DMA4_CAPS_2 */
+    case 0x70: /* DMA4_CAPS_3 */
+    case 0x74: /* DMA4_CAPS_4 */
+        OMAP_RO_REG(addr);
+        return;
+
+    default:
+        OMAP_BAD_REG(addr);
+        return;
+    }
+
+    /* Per-channel registers */
+    switch (addr) {
+    case 0x00: /* DMA4_CCR */
+        ch->buf_disable = (value >> 25) & 1;
+        ch->src_sync = (value >> 24) & 1;      /* XXX For CamDMA must be 1 */
+        if (ch->buf_disable && !ch->src_sync)
+            fprintf(stderr, "%s: Buffering disable is not allowed in "
+                            "destination synchronised mode\n", __FUNCTION__);
+        ch->prefetch = (value >> 23) & 1;
+        ch->bs = (value >> 18) & 1;
+        ch->transparent_copy = (value >> 17) & 1;
+        ch->constant_fill = (value >> 16) & 1;
+        ch->mode[1] = (omap_dma_addressing_t) ((value & 0xc000) >> 14);
+        ch->mode[0] = (omap_dma_addressing_t) ((value & 0x3000) >> 12);
+        ch->suspend = (value & 0x0100) >> 8;
+        ch->priority = (value & 0x0040) >> 6;
+        ch->fs = (value & 0x0020) >> 5;
+        if (ch->fs && ch->bs && ch->mode[0] && ch->mode[1])
+            fprintf(stderr, "%s: For a packet transfer at least one port "
+                            "must be constant-addressed\n", __FUNCTION__);
+        ch->sync = (value & 0x001f) | ((value >> 14) & 0x0060);
+        /* XXX must be 0x01 for CamDMA */
+
+        if (value & 0x0080)
+            omap_dma_enable_channel(s, ch);
+        else
+            omap_dma_disable_channel(s, ch);
+
+        break;
+
+    case 0x04: /* DMA4_CLNK_CTRL */
+        ch->link_enabled = (value >> 15) & 0x1;
+        ch->link_next_ch = value & 0x1f;
+        break;
+
+    case 0x08: /* DMA4_CICR */
+        ch->interrupts = value & 0x09be;
+        break;
+
+    case 0x0c: /* DMA4_CSR */
+        ch->cstatus &= ~value;
+        break;
+
+    case 0x10: /* DMA4_CSDP */
+        ch->endian[0] =(value >> 21) & 1;
+        ch->endian_lock[0] =(value >> 20) & 1;
+        ch->endian[1] =(value >> 19) & 1;
+        ch->endian_lock[1] =(value >> 18) & 1;
+        if (ch->endian[0] != ch->endian[1])
+            fprintf(stderr, "%s: DMA endiannes conversion enable attempt\n",
+                            __FUNCTION__);
+        ch->write_mode = (value >> 16) & 3;
+        ch->burst[1] = (value & 0xc000) >> 14;
+        ch->pack[1] = (value & 0x2000) >> 13;
+        ch->translate[1] = (value & 0x1e00) >> 9;
+        ch->burst[0] = (value & 0x0180) >> 7;
+        ch->pack[0] = (value & 0x0040) >> 6;
+        ch->translate[0] = (value & 0x003c) >> 2;
+        if (ch->translate[0] | ch->translate[1])
+            fprintf(stderr, "%s: bad MReqAddressTranslate sideband signal\n",
+                            __FUNCTION__);
+        ch->data_type = 1 << (value & 3);
+        if ((value & 3) == 3)
+            printf("%s: bad data_type for DMA channel\n", __FUNCTION__);
+        break;
+
+    case 0x14: /* DMA4_CEN */
+        ch->set_update = 1;
+        ch->elements = value & 0xffffff;
+        break;
+
+    case 0x18: /* DMA4_CFN */
+        ch->frames = value & 0xffff;
+        ch->set_update = 1;
+        break;
+
+    case 0x1c: /* DMA4_CSSA */
+        ch->addr[0] = (hwaddr) (uint32_t) value;
+        ch->set_update = 1;
+        break;
+
+    case 0x20: /* DMA4_CDSA */
+        ch->addr[1] = (hwaddr) (uint32_t) value;
+        ch->set_update = 1;
+        break;
+
+    case 0x24: /* DMA4_CSEI */
+        ch->element_index[0] = (int16_t) value;
+        ch->set_update = 1;
+        break;
+
+    case 0x28: /* DMA4_CSFI */
+        ch->frame_index[0] = (int32_t) value;
+        ch->set_update = 1;
+        break;
+
+    case 0x2c: /* DMA4_CDEI */
+        ch->element_index[1] = (int16_t) value;
+        ch->set_update = 1;
+        break;
+
+    case 0x30: /* DMA4_CDFI */
+        ch->frame_index[1] = (int32_t) value;
+        ch->set_update = 1;
+        break;
+
+    case 0x44: /* DMA4_COLOR */
+        /* XXX only in sDMA */
+        ch->color = value;
+        break;
+
+    case 0x34: /* DMA4_CSAC */
+    case 0x38: /* DMA4_CDAC */
+    case 0x3c: /* DMA4_CCEN */
+    case 0x40: /* DMA4_CCFN */
+        OMAP_RO_REG(addr);
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+    }
+}
+
+static const MemoryRegionOps omap_dma4_ops = {
+    .read = omap_dma4_read,
+    .write = omap_dma4_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+struct soc_dma_s *omap_dma4_init(hwaddr base, qemu_irq *irqs,
+                MemoryRegion *sysmem,
+                struct omap_mpu_state_s *mpu, int fifo,
+                int chans, omap_clk iclk, omap_clk fclk)
+{
+    int i;
+    struct omap_dma_s *s = (struct omap_dma_s *)
+            g_malloc0(sizeof(struct omap_dma_s));
+
+    s->model = omap_dma_4;
+    s->chans = chans;
+    s->mpu = mpu;
+    s->clk = fclk;
+
+    s->dma = soc_dma_init(s->chans);
+    s->dma->freq = omap_clk_getrate(fclk);
+    s->dma->transfer_fn = omap_dma_transfer_generic;
+    s->dma->setup_fn = omap_dma_transfer_setup;
+    s->dma->drq = qemu_allocate_irqs(omap_dma_request, s, 64);
+    s->dma->opaque = s;
+    for (i = 0; i < s->chans; i ++) {
+        s->ch[i].dma = &s->dma->ch[i];
+        s->dma->ch[i].opaque = &s->ch[i];
+    }
+
+    memcpy(&s->irq, irqs, sizeof(s->irq));
+    s->intr_update = omap_dma_interrupts_4_update;
+
+    omap_dma_setcaps(s);
+    omap_clk_adduser(s->clk, qemu_allocate_irqs(omap_dma_clk_update, s, 1)[0]);
+    omap_dma_reset(s->dma);
+    omap_dma_clk_update(s, 0, !!s->dma->freq);
+
+    memory_region_init_io(&s->iomem, &omap_dma4_ops, s, "omap.dma4", 0x1000);
+    memory_region_add_subregion(sysmem, base, &s->iomem);
+
+    mpu->drq = s->dma->drq;
+
+    return s->dma;
+}
+
+struct omap_dma_lcd_channel_s *omap_dma_get_lcdch(struct soc_dma_s *dma)
+{
+    struct omap_dma_s *s = dma->opaque;
+
+    return &s->lcd_ch;
+}
diff --git a/hw/dma/pl080.c b/hw/dma/pl080.c
new file mode 100644 (file)
index 0000000..00b66b4
--- /dev/null
@@ -0,0 +1,421 @@
+/*
+ * Arm PrimeCell PL080/PL081 DMA controller
+ *
+ * Copyright (c) 2006 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the GPL.
+ */
+
+#include "hw/sysbus.h"
+
+#define PL080_MAX_CHANNELS 8
+#define PL080_CONF_E    0x1
+#define PL080_CONF_M1   0x2
+#define PL080_CONF_M2   0x4
+
+#define PL080_CCONF_H   0x40000
+#define PL080_CCONF_A   0x20000
+#define PL080_CCONF_L   0x10000
+#define PL080_CCONF_ITC 0x08000
+#define PL080_CCONF_IE  0x04000
+#define PL080_CCONF_E   0x00001
+
+#define PL080_CCTRL_I   0x80000000
+#define PL080_CCTRL_DI  0x08000000
+#define PL080_CCTRL_SI  0x04000000
+#define PL080_CCTRL_D   0x02000000
+#define PL080_CCTRL_S   0x01000000
+
+typedef struct {
+    uint32_t src;
+    uint32_t dest;
+    uint32_t lli;
+    uint32_t ctrl;
+    uint32_t conf;
+} pl080_channel;
+
+typedef struct {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    uint8_t tc_int;
+    uint8_t tc_mask;
+    uint8_t err_int;
+    uint8_t err_mask;
+    uint32_t conf;
+    uint32_t sync;
+    uint32_t req_single;
+    uint32_t req_burst;
+    pl080_channel chan[PL080_MAX_CHANNELS];
+    int nchannels;
+    /* Flag to avoid recursive DMA invocations.  */
+    int running;
+    qemu_irq irq;
+} pl080_state;
+
+static const VMStateDescription vmstate_pl080_channel = {
+    .name = "pl080_channel",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(src, pl080_channel),
+        VMSTATE_UINT32(dest, pl080_channel),
+        VMSTATE_UINT32(lli, pl080_channel),
+        VMSTATE_UINT32(ctrl, pl080_channel),
+        VMSTATE_UINT32(conf, pl080_channel),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_pl080 = {
+    .name = "pl080",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT8(tc_int, pl080_state),
+        VMSTATE_UINT8(tc_mask, pl080_state),
+        VMSTATE_UINT8(err_int, pl080_state),
+        VMSTATE_UINT8(err_mask, pl080_state),
+        VMSTATE_UINT32(conf, pl080_state),
+        VMSTATE_UINT32(sync, pl080_state),
+        VMSTATE_UINT32(req_single, pl080_state),
+        VMSTATE_UINT32(req_burst, pl080_state),
+        VMSTATE_UINT8(tc_int, pl080_state),
+        VMSTATE_UINT8(tc_int, pl080_state),
+        VMSTATE_UINT8(tc_int, pl080_state),
+        VMSTATE_STRUCT_ARRAY(chan, pl080_state, PL080_MAX_CHANNELS,
+                             1, vmstate_pl080_channel, pl080_channel),
+        VMSTATE_INT32(running, pl080_state),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const unsigned char pl080_id[] =
+{ 0x80, 0x10, 0x04, 0x0a, 0x0d, 0xf0, 0x05, 0xb1 };
+
+static const unsigned char pl081_id[] =
+{ 0x81, 0x10, 0x04, 0x0a, 0x0d, 0xf0, 0x05, 0xb1 };
+
+static void pl080_update(pl080_state *s)
+{
+    if ((s->tc_int & s->tc_mask)
+            || (s->err_int & s->err_mask))
+        qemu_irq_raise(s->irq);
+    else
+        qemu_irq_lower(s->irq);
+}
+
+static void pl080_run(pl080_state *s)
+{
+    int c;
+    int flow;
+    pl080_channel *ch;
+    int swidth;
+    int dwidth;
+    int xsize;
+    int n;
+    int src_id;
+    int dest_id;
+    int size;
+    uint8_t buff[4];
+    uint32_t req;
+
+    s->tc_mask = 0;
+    for (c = 0; c < s->nchannels; c++) {
+        if (s->chan[c].conf & PL080_CCONF_ITC)
+            s->tc_mask |= 1 << c;
+        if (s->chan[c].conf & PL080_CCONF_IE)
+            s->err_mask |= 1 << c;
+    }
+
+    if ((s->conf & PL080_CONF_E) == 0)
+        return;
+
+hw_error("DMA active\n");
+    /* If we are already in the middle of a DMA operation then indicate that
+       there may be new DMA requests and return immediately.  */
+    if (s->running) {
+        s->running++;
+        return;
+    }
+    s->running = 1;
+    while (s->running) {
+        for (c = 0; c < s->nchannels; c++) {
+            ch = &s->chan[c];
+again:
+            /* Test if thiws channel has any pending DMA requests.  */
+            if ((ch->conf & (PL080_CCONF_H | PL080_CCONF_E))
+                    != PL080_CCONF_E)
+                continue;
+            flow = (ch->conf >> 11) & 7;
+            if (flow >= 4) {
+                hw_error(
+                    "pl080_run: Peripheral flow control not implemented\n");
+            }
+            src_id = (ch->conf >> 1) & 0x1f;
+            dest_id = (ch->conf >> 6) & 0x1f;
+            size = ch->ctrl & 0xfff;
+            req = s->req_single | s->req_burst;
+            switch (flow) {
+            case 0:
+                break;
+            case 1:
+                if ((req & (1u << dest_id)) == 0)
+                    size = 0;
+                break;
+            case 2:
+                if ((req & (1u << src_id)) == 0)
+                    size = 0;
+                break;
+            case 3:
+                if ((req & (1u << src_id)) == 0
+                        || (req & (1u << dest_id)) == 0)
+                    size = 0;
+                break;
+            }
+            if (!size)
+                continue;
+
+            /* Transfer one element.  */
+            /* ??? Should transfer multiple elements for a burst request.  */
+            /* ??? Unclear what the proper behavior is when source and
+               destination widths are different.  */
+            swidth = 1 << ((ch->ctrl >> 18) & 7);
+            dwidth = 1 << ((ch->ctrl >> 21) & 7);
+            for (n = 0; n < dwidth; n+= swidth) {
+                cpu_physical_memory_read(ch->src, buff + n, swidth);
+                if (ch->ctrl & PL080_CCTRL_SI)
+                    ch->src += swidth;
+            }
+            xsize = (dwidth < swidth) ? swidth : dwidth;
+            /* ??? This may pad the value incorrectly for dwidth < 32.  */
+            for (n = 0; n < xsize; n += dwidth) {
+                cpu_physical_memory_write(ch->dest + n, buff + n, dwidth);
+                if (ch->ctrl & PL080_CCTRL_DI)
+                    ch->dest += swidth;
+            }
+
+            size--;
+            ch->ctrl = (ch->ctrl & 0xfffff000) | size;
+            if (size == 0) {
+                /* Transfer complete.  */
+                if (ch->lli) {
+                    ch->src = ldl_le_phys(ch->lli);
+                    ch->dest = ldl_le_phys(ch->lli + 4);
+                    ch->ctrl = ldl_le_phys(ch->lli + 12);
+                    ch->lli = ldl_le_phys(ch->lli + 8);
+                } else {
+                    ch->conf &= ~PL080_CCONF_E;
+                }
+                if (ch->ctrl & PL080_CCTRL_I) {
+                    s->tc_int |= 1 << c;
+                }
+            }
+            goto again;
+        }
+        if (--s->running)
+            s->running = 1;
+    }
+}
+
+static uint64_t pl080_read(void *opaque, hwaddr offset,
+                           unsigned size)
+{
+    pl080_state *s = (pl080_state *)opaque;
+    uint32_t i;
+    uint32_t mask;
+
+    if (offset >= 0xfe0 && offset < 0x1000) {
+        if (s->nchannels == 8) {
+            return pl080_id[(offset - 0xfe0) >> 2];
+        } else {
+            return pl081_id[(offset - 0xfe0) >> 2];
+        }
+    }
+    if (offset >= 0x100 && offset < 0x200) {
+        i = (offset & 0xe0) >> 5;
+        if (i >= s->nchannels)
+            goto bad_offset;
+        switch (offset >> 2) {
+        case 0: /* SrcAddr */
+            return s->chan[i].src;
+        case 1: /* DestAddr */
+            return s->chan[i].dest;
+        case 2: /* LLI */
+            return s->chan[i].lli;
+        case 3: /* Control */
+            return s->chan[i].ctrl;
+        case 4: /* Configuration */
+            return s->chan[i].conf;
+        default:
+            goto bad_offset;
+        }
+    }
+    switch (offset >> 2) {
+    case 0: /* IntStatus */
+        return (s->tc_int & s->tc_mask) | (s->err_int & s->err_mask);
+    case 1: /* IntTCStatus */
+        return (s->tc_int & s->tc_mask);
+    case 3: /* IntErrorStatus */
+        return (s->err_int & s->err_mask);
+    case 5: /* RawIntTCStatus */
+        return s->tc_int;
+    case 6: /* RawIntErrorStatus */
+        return s->err_int;
+    case 7: /* EnbldChns */
+        mask = 0;
+        for (i = 0; i < s->nchannels; i++) {
+            if (s->chan[i].conf & PL080_CCONF_E)
+                mask |= 1 << i;
+        }
+        return mask;
+    case 8: /* SoftBReq */
+    case 9: /* SoftSReq */
+    case 10: /* SoftLBReq */
+    case 11: /* SoftLSReq */
+        /* ??? Implement these. */
+        return 0;
+    case 12: /* Configuration */
+        return s->conf;
+    case 13: /* Sync */
+        return s->sync;
+    default:
+    bad_offset:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "pl080_read: Bad offset %x\n", (int)offset);
+        return 0;
+    }
+}
+
+static void pl080_write(void *opaque, hwaddr offset,
+                        uint64_t value, unsigned size)
+{
+    pl080_state *s = (pl080_state *)opaque;
+    int i;
+
+    if (offset >= 0x100 && offset < 0x200) {
+        i = (offset & 0xe0) >> 5;
+        if (i >= s->nchannels)
+            goto bad_offset;
+        switch (offset >> 2) {
+        case 0: /* SrcAddr */
+            s->chan[i].src = value;
+            break;
+        case 1: /* DestAddr */
+            s->chan[i].dest = value;
+            break;
+        case 2: /* LLI */
+            s->chan[i].lli = value;
+            break;
+        case 3: /* Control */
+            s->chan[i].ctrl = value;
+            break;
+        case 4: /* Configuration */
+            s->chan[i].conf = value;
+            pl080_run(s);
+            break;
+        }
+    }
+    switch (offset >> 2) {
+    case 2: /* IntTCClear */
+        s->tc_int &= ~value;
+        break;
+    case 4: /* IntErrorClear */
+        s->err_int &= ~value;
+        break;
+    case 8: /* SoftBReq */
+    case 9: /* SoftSReq */
+    case 10: /* SoftLBReq */
+    case 11: /* SoftLSReq */
+        /* ??? Implement these.  */
+        qemu_log_mask(LOG_UNIMP, "pl080_write: Soft DMA not implemented\n");
+        break;
+    case 12: /* Configuration */
+        s->conf = value;
+        if (s->conf & (PL080_CONF_M1 | PL080_CONF_M1)) {
+            qemu_log_mask(LOG_UNIMP,
+                          "pl080_write: Big-endian DMA not implemented\n");
+        }
+        pl080_run(s);
+        break;
+    case 13: /* Sync */
+        s->sync = value;
+        break;
+    default:
+    bad_offset:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "pl080_write: Bad offset %x\n", (int)offset);
+    }
+    pl080_update(s);
+}
+
+static const MemoryRegionOps pl080_ops = {
+    .read = pl080_read,
+    .write = pl080_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int pl08x_init(SysBusDevice *dev, int nchannels)
+{
+    pl080_state *s = FROM_SYSBUS(pl080_state, dev);
+
+    memory_region_init_io(&s->iomem, &pl080_ops, s, "pl080", 0x1000);
+    sysbus_init_mmio(dev, &s->iomem);
+    sysbus_init_irq(dev, &s->irq);
+    s->nchannels = nchannels;
+    return 0;
+}
+
+static int pl080_init(SysBusDevice *dev)
+{
+    return pl08x_init(dev, 8);
+}
+
+static int pl081_init(SysBusDevice *dev)
+{
+    return pl08x_init(dev, 2);
+}
+
+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 const 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 const 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_types(void)
+{
+    type_register_static(&pl080_info);
+    type_register_static(&pl081_info);
+}
+
+type_init(pl080_register_types)
diff --git a/hw/dma/pl330.c b/hw/dma/pl330.c
new file mode 100644 (file)
index 0000000..8b33138
--- /dev/null
@@ -0,0 +1,1653 @@
+/*
+ * ARM PrimeCell PL330 DMA Controller
+ *
+ * Copyright (c) 2009 Samsung Electronics.
+ * Contributed by Kirill Batuzov <batuzovk@ispras.ru>
+ * Copyright (c) 2012 Peter A.G. Crosthwaite (peter.crosthwaite@petalogix.com)
+ * Copyright (c) 2012 PetaLogix Pty Ltd.
+ *
+ * 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; version 2 or later.
+ *
+ * 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 "hw/sysbus.h"
+#include "qemu/timer.h"
+#include "sysemu/dma.h"
+
+#ifndef PL330_ERR_DEBUG
+#define PL330_ERR_DEBUG 0
+#endif
+
+#define DB_PRINT_L(lvl, fmt, args...) do {\
+    if (PL330_ERR_DEBUG >= lvl) {\
+        fprintf(stderr, "PL330: %s:" fmt, __func__, ## args);\
+    } \
+} while (0);
+
+#define DB_PRINT(fmt, args...) DB_PRINT_L(1, fmt, ## args)
+
+#define PL330_PERIPH_NUM            32
+#define PL330_MAX_BURST_LEN         128
+#define PL330_INSN_MAXSIZE          6
+
+#define PL330_FIFO_OK               0
+#define PL330_FIFO_STALL            1
+#define PL330_FIFO_ERR              (-1)
+
+#define PL330_FAULT_UNDEF_INSTR             (1 <<  0)
+#define PL330_FAULT_OPERAND_INVALID         (1 <<  1)
+#define PL330_FAULT_DMAGO_ERR               (1 <<  4)
+#define PL330_FAULT_EVENT_ERR               (1 <<  5)
+#define PL330_FAULT_CH_PERIPH_ERR           (1 <<  6)
+#define PL330_FAULT_CH_RDWR_ERR             (1 <<  7)
+#define PL330_FAULT_ST_DATA_UNAVAILABLE     (1 << 12)
+#define PL330_FAULT_FIFOEMPTY_ERR           (1 << 13)
+#define PL330_FAULT_INSTR_FETCH_ERR         (1 << 16)
+#define PL330_FAULT_DATA_WRITE_ERR          (1 << 17)
+#define PL330_FAULT_DATA_READ_ERR           (1 << 18)
+#define PL330_FAULT_DBG_INSTR               (1 << 30)
+#define PL330_FAULT_LOCKUP_ERR              (1 << 31)
+
+#define PL330_UNTAGGED              0xff
+
+#define PL330_SINGLE                0x0
+#define PL330_BURST                 0x1
+
+#define PL330_WATCHDOG_LIMIT        1024
+
+/* IOMEM mapped registers */
+#define PL330_REG_DSR               0x000
+#define PL330_REG_DPC               0x004
+#define PL330_REG_INTEN             0x020
+#define PL330_REG_INT_EVENT_RIS     0x024
+#define PL330_REG_INTMIS            0x028
+#define PL330_REG_INTCLR            0x02C
+#define PL330_REG_FSRD              0x030
+#define PL330_REG_FSRC              0x034
+#define PL330_REG_FTRD              0x038
+#define PL330_REG_FTR_BASE          0x040
+#define PL330_REG_CSR_BASE          0x100
+#define PL330_REG_CPC_BASE          0x104
+#define PL330_REG_CHANCTRL          0x400
+#define PL330_REG_DBGSTATUS         0xD00
+#define PL330_REG_DBGCMD            0xD04
+#define PL330_REG_DBGINST0          0xD08
+#define PL330_REG_DBGINST1          0xD0C
+#define PL330_REG_CR0_BASE          0xE00
+#define PL330_REG_PERIPH_ID         0xFE0
+
+#define PL330_IOMEM_SIZE    0x1000
+
+#define CFG_BOOT_ADDR 2
+#define CFG_INS 3
+#define CFG_PNS 4
+#define CFG_CRD 5
+
+static const uint32_t pl330_id[] = {
+    0x30, 0x13, 0x24, 0x00, 0x0D, 0xF0, 0x05, 0xB1
+};
+
+/* DMA channel states as they are described in PL330 Technical Reference Manual
+ * Most of them will not be used in emulation.
+ */
+typedef enum  {
+    pl330_chan_stopped = 0,
+    pl330_chan_executing = 1,
+    pl330_chan_cache_miss = 2,
+    pl330_chan_updating_pc = 3,
+    pl330_chan_waiting_event = 4,
+    pl330_chan_at_barrier = 5,
+    pl330_chan_queue_busy = 6,
+    pl330_chan_waiting_periph = 7,
+    pl330_chan_killing = 8,
+    pl330_chan_completing = 9,
+    pl330_chan_fault_completing = 14,
+    pl330_chan_fault = 15,
+} PL330ChanState;
+
+typedef struct PL330State PL330State;
+
+typedef struct PL330Chan {
+    uint32_t src;
+    uint32_t dst;
+    uint32_t pc;
+    uint32_t control;
+    uint32_t status;
+    uint32_t lc[2];
+    uint32_t fault_type;
+    uint32_t watchdog_timer;
+
+    bool ns;
+    uint8_t request_flag;
+    uint8_t wakeup;
+    uint8_t wfp_sbp;
+
+    uint8_t state;
+    uint8_t stall;
+
+    bool is_manager;
+    PL330State *parent;
+    uint8_t tag;
+} PL330Chan;
+
+static const VMStateDescription vmstate_pl330_chan = {
+    .name = "pl330_chan",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(src, PL330Chan),
+        VMSTATE_UINT32(dst, PL330Chan),
+        VMSTATE_UINT32(pc, PL330Chan),
+        VMSTATE_UINT32(control, PL330Chan),
+        VMSTATE_UINT32(status, PL330Chan),
+        VMSTATE_UINT32_ARRAY(lc, PL330Chan, 2),
+        VMSTATE_UINT32(fault_type, PL330Chan),
+        VMSTATE_UINT32(watchdog_timer, PL330Chan),
+        VMSTATE_BOOL(ns, PL330Chan),
+        VMSTATE_UINT8(request_flag, PL330Chan),
+        VMSTATE_UINT8(wakeup, PL330Chan),
+        VMSTATE_UINT8(wfp_sbp, PL330Chan),
+        VMSTATE_UINT8(state, PL330Chan),
+        VMSTATE_UINT8(stall, PL330Chan),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+typedef struct PL330Fifo {
+    uint8_t *buf;
+    uint8_t *tag;
+    uint32_t head;
+    uint32_t num;
+    uint32_t buf_size;
+} PL330Fifo;
+
+static const VMStateDescription vmstate_pl330_fifo = {
+    .name = "pl330_chan",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_VBUFFER_UINT32(buf, PL330Fifo, 1, NULL, 0, buf_size),
+        VMSTATE_VBUFFER_UINT32(tag, PL330Fifo, 1, NULL, 0, buf_size),
+        VMSTATE_UINT32(head, PL330Fifo),
+        VMSTATE_UINT32(num, PL330Fifo),
+        VMSTATE_UINT32(buf_size, PL330Fifo),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+typedef struct PL330QueueEntry {
+    uint32_t addr;
+    uint32_t len;
+    uint8_t n;
+    bool inc;
+    bool z;
+    uint8_t tag;
+    uint8_t seqn;
+} PL330QueueEntry;
+
+static const VMStateDescription vmstate_pl330_queue_entry = {
+    .name = "pl330_queue_entry",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(addr, PL330QueueEntry),
+        VMSTATE_UINT32(len, PL330QueueEntry),
+        VMSTATE_UINT8(n, PL330QueueEntry),
+        VMSTATE_BOOL(inc, PL330QueueEntry),
+        VMSTATE_BOOL(z, PL330QueueEntry),
+        VMSTATE_UINT8(tag, PL330QueueEntry),
+        VMSTATE_UINT8(seqn, PL330QueueEntry),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+typedef struct PL330Queue {
+    PL330State *parent;
+    PL330QueueEntry *queue;
+    uint32_t queue_size;
+} PL330Queue;
+
+static const VMStateDescription vmstate_pl330_queue = {
+    .name = "pl330_queue",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_STRUCT_VARRAY_UINT32(queue, PL330Queue, queue_size, 1,
+                                 vmstate_pl330_queue_entry, PL330QueueEntry),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+struct PL330State {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    qemu_irq irq_abort;
+    qemu_irq *irq;
+
+    /* Config registers. cfg[5] = CfgDn. */
+    uint32_t cfg[6];
+#define EVENT_SEC_STATE 3
+#define PERIPH_SEC_STATE 4
+    /* cfg 0 bits and pieces */
+    uint32_t num_chnls;
+    uint8_t num_periph_req;
+    uint8_t num_events;
+    uint8_t mgr_ns_at_rst;
+    /* cfg 1 bits and pieces */
+    uint8_t i_cache_len;
+    uint8_t num_i_cache_lines;
+    /* CRD bits and pieces */
+    uint8_t data_width;
+    uint8_t wr_cap;
+    uint8_t wr_q_dep;
+    uint8_t rd_cap;
+    uint8_t rd_q_dep;
+    uint16_t data_buffer_dep;
+
+    PL330Chan manager;
+    PL330Chan *chan;
+    PL330Fifo fifo;
+    PL330Queue read_queue;
+    PL330Queue write_queue;
+    uint8_t *lo_seqn;
+    uint8_t *hi_seqn;
+    QEMUTimer *timer; /* is used for restore dma. */
+
+    uint32_t inten;
+    uint32_t int_status;
+    uint32_t ev_status;
+    uint32_t dbg[2];
+    uint8_t debug_status;
+    uint8_t num_faulting;
+    uint8_t periph_busy[PL330_PERIPH_NUM];
+
+};
+
+#define TYPE_PL330 "pl330"
+#define PL330(obj) OBJECT_CHECK(PL330State, (obj), TYPE_PL330)
+
+static const VMStateDescription vmstate_pl330 = {
+    .name = "pl330",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_STRUCT(manager, PL330State, 0, vmstate_pl330_chan, PL330Chan),
+        VMSTATE_STRUCT_VARRAY_UINT32(chan, PL330State, num_chnls, 0,
+                                     vmstate_pl330_chan, PL330Chan),
+        VMSTATE_VBUFFER_UINT32(lo_seqn, PL330State, 1, NULL, 0, num_chnls),
+        VMSTATE_VBUFFER_UINT32(hi_seqn, PL330State, 1, NULL, 0, num_chnls),
+        VMSTATE_STRUCT(fifo, PL330State, 0, vmstate_pl330_fifo, PL330Fifo),
+        VMSTATE_STRUCT(read_queue, PL330State, 0, vmstate_pl330_queue,
+                       PL330Queue),
+        VMSTATE_STRUCT(write_queue, PL330State, 0, vmstate_pl330_queue,
+                       PL330Queue),
+        VMSTATE_TIMER(timer, PL330State),
+        VMSTATE_UINT32(inten, PL330State),
+        VMSTATE_UINT32(int_status, PL330State),
+        VMSTATE_UINT32(ev_status, PL330State),
+        VMSTATE_UINT32_ARRAY(dbg, PL330State, 2),
+        VMSTATE_UINT8(debug_status, PL330State),
+        VMSTATE_UINT8(num_faulting, PL330State),
+        VMSTATE_UINT8_ARRAY(periph_busy, PL330State, PL330_PERIPH_NUM),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+typedef struct PL330InsnDesc {
+    /* OPCODE of the instruction */
+    uint8_t opcode;
+    /* Mask so we can select several sibling instructions, such as
+       DMALD, DMALDS and DMALDB */
+    uint8_t opmask;
+    /* Size of instruction in bytes */
+    uint8_t size;
+    /* Interpreter */
+    void (*exec)(PL330Chan *, uint8_t opcode, uint8_t *args, int len);
+} PL330InsnDesc;
+
+
+/* MFIFO Implementation
+ *
+ * MFIFO is implemented as a cyclic buffer of BUF_SIZE size. Tagged bytes are
+ * stored in this buffer. Data is stored in BUF field, tags - in the
+ * corresponding array elements of TAG field.
+ */
+
+/* Initialize queue. */
+
+static void pl330_fifo_init(PL330Fifo *s, uint32_t size)
+{
+    s->buf = g_malloc0(size);
+    s->tag = g_malloc0(size);
+    s->buf_size = size;
+}
+
+/* Cyclic increment */
+
+static inline int pl330_fifo_inc(PL330Fifo *s, int x)
+{
+    return (x + 1) % s->buf_size;
+}
+
+/* Number of empty bytes in MFIFO */
+
+static inline int pl330_fifo_num_free(PL330Fifo *s)
+{
+    return s->buf_size - s->num;
+}
+
+/* Push LEN bytes of data stored in BUF to MFIFO and tag it with TAG.
+ * Zero returned on success, PL330_FIFO_STALL if there is no enough free
+ * space in MFIFO to store requested amount of data. If push was unsuccessful
+ * no data is stored to MFIFO.
+ */
+
+static int pl330_fifo_push(PL330Fifo *s, uint8_t *buf, int len, uint8_t tag)
+{
+    int i;
+
+    if (s->buf_size - s->num < len) {
+        return PL330_FIFO_STALL;
+    }
+    for (i = 0; i < len; i++) {
+        int push_idx = (s->head + s->num + i) % s->buf_size;
+        s->buf[push_idx] = buf[i];
+        s->tag[push_idx] = tag;
+    }
+    s->num += len;
+    return PL330_FIFO_OK;
+}
+
+/* Get LEN bytes of data from MFIFO and store it to BUF. Tag value of each
+ * byte is verified. Zero returned on success, PL330_FIFO_ERR on tag mismatch
+ * and PL330_FIFO_STALL if there is no enough data in MFIFO. If get was
+ * unsuccessful no data is removed from MFIFO.
+ */
+
+static int pl330_fifo_get(PL330Fifo *s, uint8_t *buf, int len, uint8_t tag)
+{
+    int i;
+
+    if (s->num < len) {
+        return PL330_FIFO_STALL;
+    }
+    for (i = 0; i < len; i++) {
+        if (s->tag[s->head] == tag) {
+            int get_idx = (s->head + i) % s->buf_size;
+            buf[i] = s->buf[get_idx];
+        } else { /* Tag mismatch - Rollback transaction */
+            return PL330_FIFO_ERR;
+        }
+    }
+    s->head = (s->head + len) % s->buf_size;
+    s->num -= len;
+    return PL330_FIFO_OK;
+}
+
+/* Reset MFIFO. This completely erases all data in it. */
+
+static inline void pl330_fifo_reset(PL330Fifo *s)
+{
+    s->head = 0;
+    s->num = 0;
+}
+
+/* Return tag of the first byte stored in MFIFO. If MFIFO is empty
+ * PL330_UNTAGGED is returned.
+ */
+
+static inline uint8_t pl330_fifo_tag(PL330Fifo *s)
+{
+    return (!s->num) ? PL330_UNTAGGED : s->tag[s->head];
+}
+
+/* Returns non-zero if tag TAG is present in fifo or zero otherwise */
+
+static int pl330_fifo_has_tag(PL330Fifo *s, uint8_t tag)
+{
+    int i, n;
+
+    i = s->head;
+    for (n = 0; n < s->num; n++) {
+        if (s->tag[i] == tag) {
+            return 1;
+        }
+        i = pl330_fifo_inc(s, i);
+    }
+    return 0;
+}
+
+/* Remove all entry tagged with TAG from MFIFO */
+
+static void pl330_fifo_tagged_remove(PL330Fifo *s, uint8_t tag)
+{
+    int i, t, n;
+
+    t = i = s->head;
+    for (n = 0; n < s->num; n++) {
+        if (s->tag[i] != tag) {
+            s->buf[t] = s->buf[i];
+            s->tag[t] = s->tag[i];
+            t = pl330_fifo_inc(s, t);
+        } else {
+            s->num = s->num - 1;
+        }
+        i = pl330_fifo_inc(s, i);
+    }
+}
+
+/* Read-Write Queue implementation
+ *
+ * A Read-Write Queue stores up to QUEUE_SIZE instructions (loads or stores).
+ * Each instruction is described by source (for loads) or destination (for
+ * stores) address ADDR, width of data to be loaded/stored LEN, number of
+ * stores/loads to be performed N, INC bit, Z bit and TAG to identify channel
+ * this instruction belongs to. Queue does not store any information about
+ * nature of the instruction: is it load or store. PL330 has different queues
+ * for loads and stores so this is already known at the top level where it
+ * matters.
+ *
+ * Queue works as FIFO for instructions with equivalent tags, but can issue
+ * instructions with different tags in arbitrary order. SEQN field attached to
+ * each instruction helps to achieve this. For each TAG queue contains
+ * instructions with consecutive SEQN values ranging from LO_SEQN[TAG] to
+ * HI_SEQN[TAG]-1 inclusive. SEQN is 8-bit unsigned integer, so SEQN=255 is
+ * followed by SEQN=0.
+ *
+ * Z bit indicates that zeroes should be stored. No MFIFO fetches are performed
+ * in this case.
+ */
+
+static void pl330_queue_reset(PL330Queue *s)
+{
+    int i;
+
+    for (i = 0; i < s->queue_size; i++) {
+        s->queue[i].tag = PL330_UNTAGGED;
+    }
+}
+
+/* Initialize queue */
+static void pl330_queue_init(PL330Queue *s, int size, PL330State *parent)
+{
+    s->parent = parent;
+    s->queue = g_new0(PL330QueueEntry, size);
+    s->queue_size = size;
+}
+
+/* Returns pointer to an empty slot or NULL if queue is full */
+static PL330QueueEntry *pl330_queue_find_empty(PL330Queue *s)
+{
+    int i;
+
+    for (i = 0; i < s->queue_size; i++) {
+        if (s->queue[i].tag == PL330_UNTAGGED) {
+            return &s->queue[i];
+        }
+    }
+    return NULL;
+}
+
+/* Put instruction in queue.
+ * Return value:
+ * - zero - OK
+ * - non-zero - queue is full
+ */
+
+static int pl330_queue_put_insn(PL330Queue *s, uint32_t addr,
+                                int len, int n, bool inc, bool z, uint8_t tag)
+{
+    PL330QueueEntry *entry = pl330_queue_find_empty(s);
+
+    if (!entry) {
+        return 1;
+    }
+    entry->tag = tag;
+    entry->addr = addr;
+    entry->len = len;
+    entry->n = n;
+    entry->z = z;
+    entry->inc = inc;
+    entry->seqn = s->parent->hi_seqn[tag];
+    s->parent->hi_seqn[tag]++;
+    return 0;
+}
+
+/* Returns a pointer to queue slot containing instruction which satisfies
+ *  following conditions:
+ *   - it has valid tag value (not PL330_UNTAGGED)
+ *   - if enforce_seq is set it has to be issuable without violating queue
+ *     logic (see above)
+ *   - if TAG argument is not PL330_UNTAGGED this instruction has tag value
+ *     equivalent to the argument TAG value.
+ *  If such instruction cannot be found NULL is returned.
+ */
+
+static PL330QueueEntry *pl330_queue_find_insn(PL330Queue *s, uint8_t tag,
+                                              bool enforce_seq)
+{
+    int i;
+
+    for (i = 0; i < s->queue_size; i++) {
+        if (s->queue[i].tag != PL330_UNTAGGED) {
+            if ((!enforce_seq ||
+                    s->queue[i].seqn == s->parent->lo_seqn[s->queue[i].tag]) &&
+                    (s->queue[i].tag == tag || tag == PL330_UNTAGGED ||
+                    s->queue[i].z)) {
+                return &s->queue[i];
+            }
+        }
+    }
+    return NULL;
+}
+
+/* Removes instruction from queue. */
+
+static inline void pl330_queue_remove_insn(PL330Queue *s, PL330QueueEntry *e)
+{
+    s->parent->lo_seqn[e->tag]++;
+    e->tag = PL330_UNTAGGED;
+}
+
+/* Removes all instructions tagged with TAG from queue. */
+
+static inline void pl330_queue_remove_tagged(PL330Queue *s, uint8_t tag)
+{
+    int i;
+
+    for (i = 0; i < s->queue_size; i++) {
+        if (s->queue[i].tag == tag) {
+            s->queue[i].tag = PL330_UNTAGGED;
+        }
+    }
+}
+
+/* DMA instruction execution engine */
+
+/* Moves DMA channel to the FAULT state and updates it's status. */
+
+static inline void pl330_fault(PL330Chan *ch, uint32_t flags)
+{
+    DB_PRINT("ch: %p, flags: %x\n", ch, flags);
+    ch->fault_type |= flags;
+    if (ch->state == pl330_chan_fault) {
+        return;
+    }
+    ch->state = pl330_chan_fault;
+    ch->parent->num_faulting++;
+    if (ch->parent->num_faulting == 1) {
+        DB_PRINT("abort interrupt raised\n");
+        qemu_irq_raise(ch->parent->irq_abort);
+    }
+}
+
+/*
+ * For information about instructions see PL330 Technical Reference Manual.
+ *
+ * Arguments:
+ *   CH - channel executing the instruction
+ *   OPCODE - opcode
+ *   ARGS - array of 8-bit arguments
+ *   LEN - number of elements in ARGS array
+ */
+
+static void pl330_dmaaddh(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len)
+{
+    uint16_t im = (((uint16_t)args[1]) << 8) | ((uint16_t)args[0]);
+    uint8_t ra = (opcode >> 1) & 1;
+
+    if (ch->is_manager) {
+        pl330_fault(ch, PL330_FAULT_UNDEF_INSTR);
+        return;
+    }
+    if (ra) {
+        ch->dst += im;
+    } else {
+        ch->src += im;
+    }
+}
+
+static void pl330_dmaend(PL330Chan *ch, uint8_t opcode,
+                         uint8_t *args, int len)
+{
+    PL330State *s = ch->parent;
+
+    if (ch->state == pl330_chan_executing && !ch->is_manager) {
+        /* Wait for all transfers to complete */
+        if (pl330_fifo_has_tag(&s->fifo, ch->tag) ||
+            pl330_queue_find_insn(&s->read_queue, ch->tag, false) != NULL ||
+            pl330_queue_find_insn(&s->write_queue, ch->tag, false) != NULL) {
+
+            ch->stall = 1;
+            return;
+        }
+    }
+    DB_PRINT("DMA ending!\n");
+    pl330_fifo_tagged_remove(&s->fifo, ch->tag);
+    pl330_queue_remove_tagged(&s->read_queue, ch->tag);
+    pl330_queue_remove_tagged(&s->write_queue, ch->tag);
+    ch->state = pl330_chan_stopped;
+}
+
+static void pl330_dmaflushp(PL330Chan *ch, uint8_t opcode,
+                                            uint8_t *args, int len)
+{
+    uint8_t periph_id;
+
+    if (args[0] & 7) {
+        pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
+        return;
+    }
+    periph_id = (args[0] >> 3) & 0x1f;
+    if (periph_id >= ch->parent->num_periph_req) {
+        pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
+        return;
+    }
+    if (ch->ns && !(ch->parent->cfg[CFG_PNS] & (1 << periph_id))) {
+        pl330_fault(ch, PL330_FAULT_CH_PERIPH_ERR);
+        return;
+    }
+    /* Do nothing */
+}
+
+static void pl330_dmago(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len)
+{
+    uint8_t chan_id;
+    uint8_t ns;
+    uint32_t pc;
+    PL330Chan *s;
+
+    DB_PRINT("\n");
+
+    if (!ch->is_manager) {
+        pl330_fault(ch, PL330_FAULT_UNDEF_INSTR);
+        return;
+    }
+    ns = !!(opcode & 2);
+    chan_id = args[0] & 7;
+    if ((args[0] >> 3)) {
+        pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
+        return;
+    }
+    if (chan_id >= ch->parent->num_chnls) {
+        pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
+        return;
+    }
+    pc = (((uint32_t)args[4]) << 24) | (((uint32_t)args[3]) << 16) |
+         (((uint32_t)args[2]) << 8)  | (((uint32_t)args[1]));
+    if (ch->parent->chan[chan_id].state != pl330_chan_stopped) {
+        pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
+        return;
+    }
+    if (ch->ns && !ns) {
+        pl330_fault(ch, PL330_FAULT_DMAGO_ERR);
+        return;
+    }
+    s = &ch->parent->chan[chan_id];
+    s->ns = ns;
+    s->pc = pc;
+    s->state = pl330_chan_executing;
+}
+
+static void pl330_dmald(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len)
+{
+    uint8_t bs = opcode & 3;
+    uint32_t size, num;
+    bool inc;
+
+    if (bs == 2) {
+        pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
+        return;
+    }
+    if ((bs == 1 && ch->request_flag == PL330_BURST) ||
+        (bs == 3 && ch->request_flag == PL330_SINGLE)) {
+        /* Perform NOP */
+        return;
+    }
+    if (bs == 1 && ch->request_flag == PL330_SINGLE) {
+        num = 1;
+    } else {
+        num = ((ch->control >> 4) & 0xf) + 1;
+    }
+    size = (uint32_t)1 << ((ch->control >> 1) & 0x7);
+    inc = !!(ch->control & 1);
+    ch->stall = pl330_queue_put_insn(&ch->parent->read_queue, ch->src,
+                                    size, num, inc, 0, ch->tag);
+    if (!ch->stall) {
+        DB_PRINT("channel:%d address:%08x size:%d num:%d %c\n",
+                 ch->tag, ch->src, size, num, inc ? 'Y' : 'N');
+        ch->src += inc ? size * num - (ch->src & (size - 1)) : 0;
+    }
+}
+
+static void pl330_dmaldp(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len)
+{
+    uint8_t periph_id;
+
+    if (args[0] & 7) {
+        pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
+        return;
+    }
+    periph_id = (args[0] >> 3) & 0x1f;
+    if (periph_id >= ch->parent->num_periph_req) {
+        pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
+        return;
+    }
+    if (ch->ns && !(ch->parent->cfg[CFG_PNS] & (1 << periph_id))) {
+        pl330_fault(ch, PL330_FAULT_CH_PERIPH_ERR);
+        return;
+    }
+    pl330_dmald(ch, opcode, args, len);
+}
+
+static void pl330_dmalp(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len)
+{
+    uint8_t lc = (opcode & 2) >> 1;
+
+    ch->lc[lc] = args[0];
+}
+
+static void pl330_dmakill(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len)
+{
+    if (ch->state == pl330_chan_fault ||
+        ch->state == pl330_chan_fault_completing) {
+        /* This is the only way for a channel to leave the faulting state */
+        ch->fault_type = 0;
+        ch->parent->num_faulting--;
+        if (ch->parent->num_faulting == 0) {
+            DB_PRINT("abort interrupt lowered\n");
+            qemu_irq_lower(ch->parent->irq_abort);
+        }
+    }
+    ch->state = pl330_chan_killing;
+    pl330_fifo_tagged_remove(&ch->parent->fifo, ch->tag);
+    pl330_queue_remove_tagged(&ch->parent->read_queue, ch->tag);
+    pl330_queue_remove_tagged(&ch->parent->write_queue, ch->tag);
+    ch->state = pl330_chan_stopped;
+}
+
+static void pl330_dmalpend(PL330Chan *ch, uint8_t opcode,
+                                    uint8_t *args, int len)
+{
+    uint8_t nf = (opcode & 0x10) >> 4;
+    uint8_t bs = opcode & 3;
+    uint8_t lc = (opcode & 4) >> 2;
+
+    if (bs == 2) {
+        pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
+        return;
+    }
+    if ((bs == 1 && ch->request_flag == PL330_BURST) ||
+        (bs == 3 && ch->request_flag == PL330_SINGLE)) {
+        /* Perform NOP */
+        return;
+    }
+    if (!nf || ch->lc[lc]) {
+        if (nf) {
+            ch->lc[lc]--;
+        }
+        DB_PRINT("loop reiteration\n");
+        ch->pc -= args[0];
+        ch->pc -= len + 1;
+        /* "ch->pc -= args[0] + len + 1" is incorrect when args[0] == 256 */
+    } else {
+        DB_PRINT("loop fallthrough\n");
+    }
+}
+
+
+static void pl330_dmamov(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len)
+{
+    uint8_t rd = args[0] & 7;
+    uint32_t im;
+
+    if ((args[0] >> 3)) {
+        pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
+        return;
+    }
+    im = (((uint32_t)args[4]) << 24) | (((uint32_t)args[3]) << 16) |
+         (((uint32_t)args[2]) << 8)  | (((uint32_t)args[1]));
+    switch (rd) {
+    case 0:
+        ch->src = im;
+        break;
+    case 1:
+        ch->control = im;
+        break;
+    case 2:
+        ch->dst = im;
+        break;
+    default:
+        pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
+        return;
+    }
+}
+
+static void pl330_dmanop(PL330Chan *ch, uint8_t opcode,
+                         uint8_t *args, int len)
+{
+    /* NOP is NOP. */
+}
+
+static void pl330_dmarmb(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len)
+{
+   if (pl330_queue_find_insn(&ch->parent->read_queue, ch->tag, false)) {
+        ch->state = pl330_chan_at_barrier;
+        ch->stall = 1;
+        return;
+    } else {
+        ch->state = pl330_chan_executing;
+    }
+}
+
+static void pl330_dmasev(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len)
+{
+    uint8_t ev_id;
+
+    if (args[0] & 7) {
+        pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
+        return;
+    }
+    ev_id = (args[0] >> 3) & 0x1f;
+    if (ev_id >= ch->parent->num_events) {
+        pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
+        return;
+    }
+    if (ch->ns && !(ch->parent->cfg[CFG_INS] & (1 << ev_id))) {
+        pl330_fault(ch, PL330_FAULT_EVENT_ERR);
+        return;
+    }
+    if (ch->parent->inten & (1 << ev_id)) {
+        ch->parent->int_status |= (1 << ev_id);
+        DB_PRINT("event interrupt raised %d\n", ev_id);
+        qemu_irq_raise(ch->parent->irq[ev_id]);
+    }
+    ch->parent->ev_status |= (1 << ev_id);
+}
+
+static void pl330_dmast(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len)
+{
+    uint8_t bs = opcode & 3;
+    uint32_t size, num;
+    bool inc;
+
+    if (bs == 2) {
+        pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
+        return;
+    }
+    if ((bs == 1 && ch->request_flag == PL330_BURST) ||
+        (bs == 3 && ch->request_flag == PL330_SINGLE)) {
+        /* Perform NOP */
+        return;
+    }
+    num = ((ch->control >> 18) & 0xf) + 1;
+    size = (uint32_t)1 << ((ch->control >> 15) & 0x7);
+    inc = !!((ch->control >> 14) & 1);
+    ch->stall = pl330_queue_put_insn(&ch->parent->write_queue, ch->dst,
+                                    size, num, inc, 0, ch->tag);
+    if (!ch->stall) {
+        DB_PRINT("channel:%d address:%08x size:%d num:%d %c\n",
+                 ch->tag, ch->dst, size, num, inc ? 'Y' : 'N');
+        ch->dst += inc ? size * num - (ch->dst & (size - 1)) : 0;
+    }
+}
+
+static void pl330_dmastp(PL330Chan *ch, uint8_t opcode,
+                         uint8_t *args, int len)
+{
+    uint8_t periph_id;
+
+    if (args[0] & 7) {
+        pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
+        return;
+    }
+    periph_id = (args[0] >> 3) & 0x1f;
+    if (periph_id >= ch->parent->num_periph_req) {
+        pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
+        return;
+    }
+    if (ch->ns && !(ch->parent->cfg[CFG_PNS] & (1 << periph_id))) {
+        pl330_fault(ch, PL330_FAULT_CH_PERIPH_ERR);
+        return;
+    }
+    pl330_dmast(ch, opcode, args, len);
+}
+
+static void pl330_dmastz(PL330Chan *ch, uint8_t opcode,
+                         uint8_t *args, int len)
+{
+    uint32_t size, num;
+    bool inc;
+
+    num = ((ch->control >> 18) & 0xf) + 1;
+    size = (uint32_t)1 << ((ch->control >> 15) & 0x7);
+    inc = !!((ch->control >> 14) & 1);
+    ch->stall = pl330_queue_put_insn(&ch->parent->write_queue, ch->dst,
+                                    size, num, inc, 1, ch->tag);
+    if (inc) {
+        ch->dst += size * num;
+    }
+}
+
+static void pl330_dmawfe(PL330Chan *ch, uint8_t opcode,
+                         uint8_t *args, int len)
+{
+    uint8_t ev_id;
+    int i;
+
+    if (args[0] & 5) {
+        pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
+        return;
+    }
+    ev_id = (args[0] >> 3) & 0x1f;
+    if (ev_id >= ch->parent->num_events) {
+        pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
+        return;
+    }
+    if (ch->ns && !(ch->parent->cfg[CFG_INS] & (1 << ev_id))) {
+        pl330_fault(ch, PL330_FAULT_EVENT_ERR);
+        return;
+    }
+    ch->wakeup = ev_id;
+    ch->state = pl330_chan_waiting_event;
+    if (~ch->parent->inten & ch->parent->ev_status & 1 << ev_id) {
+        ch->state = pl330_chan_executing;
+        /* If anyone else is currently waiting on the same event, let them
+         * clear the ev_status so they pick up event as well
+         */
+        for (i = 0; i < ch->parent->num_chnls; ++i) {
+            PL330Chan *peer = &ch->parent->chan[i];
+            if (peer->state == pl330_chan_waiting_event &&
+                    peer->wakeup == ev_id) {
+                return;
+            }
+        }
+        ch->parent->ev_status &= ~(1 << ev_id);
+    } else {
+        ch->stall = 1;
+    }
+}
+
+static void pl330_dmawfp(PL330Chan *ch, uint8_t opcode,
+                         uint8_t *args, int len)
+{
+    uint8_t bs = opcode & 3;
+    uint8_t periph_id;
+
+    if (args[0] & 7) {
+        pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
+        return;
+    }
+    periph_id = (args[0] >> 3) & 0x1f;
+    if (periph_id >= ch->parent->num_periph_req) {
+        pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
+        return;
+    }
+    if (ch->ns && !(ch->parent->cfg[CFG_PNS] & (1 << periph_id))) {
+        pl330_fault(ch, PL330_FAULT_CH_PERIPH_ERR);
+        return;
+    }
+    switch (bs) {
+    case 0: /* S */
+        ch->request_flag = PL330_SINGLE;
+        ch->wfp_sbp = 0;
+        break;
+    case 1: /* P */
+        ch->request_flag = PL330_BURST;
+        ch->wfp_sbp = 2;
+        break;
+    case 2: /* B */
+        ch->request_flag = PL330_BURST;
+        ch->wfp_sbp = 1;
+        break;
+    default:
+        pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
+        return;
+    }
+
+    if (ch->parent->periph_busy[periph_id]) {
+        ch->state = pl330_chan_waiting_periph;
+        ch->stall = 1;
+    } else if (ch->state == pl330_chan_waiting_periph) {
+        ch->state = pl330_chan_executing;
+    }
+}
+
+static void pl330_dmawmb(PL330Chan *ch, uint8_t opcode,
+                         uint8_t *args, int len)
+{
+    if (pl330_queue_find_insn(&ch->parent->write_queue, ch->tag, false)) {
+        ch->state = pl330_chan_at_barrier;
+        ch->stall = 1;
+        return;
+    } else {
+        ch->state = pl330_chan_executing;
+    }
+}
+
+/* NULL terminated array of the instruction descriptions. */
+static const PL330InsnDesc insn_desc[] = {
+    { .opcode = 0x54, .opmask = 0xFD, .size = 3, .exec = pl330_dmaaddh, },
+    { .opcode = 0x00, .opmask = 0xFF, .size = 1, .exec = pl330_dmaend, },
+    { .opcode = 0x35, .opmask = 0xFF, .size = 2, .exec = pl330_dmaflushp, },
+    { .opcode = 0xA0, .opmask = 0xFD, .size = 6, .exec = pl330_dmago, },
+    { .opcode = 0x04, .opmask = 0xFC, .size = 1, .exec = pl330_dmald, },
+    { .opcode = 0x25, .opmask = 0xFD, .size = 2, .exec = pl330_dmaldp, },
+    { .opcode = 0x20, .opmask = 0xFD, .size = 2, .exec = pl330_dmalp, },
+    /* dmastp  must be before dmalpend in this list, because their maps
+     * are overlapping
+     */
+    { .opcode = 0x29, .opmask = 0xFD, .size = 2, .exec = pl330_dmastp, },
+    { .opcode = 0x28, .opmask = 0xE8, .size = 2, .exec = pl330_dmalpend, },
+    { .opcode = 0x01, .opmask = 0xFF, .size = 1, .exec = pl330_dmakill, },
+    { .opcode = 0xBC, .opmask = 0xFF, .size = 6, .exec = pl330_dmamov, },
+    { .opcode = 0x18, .opmask = 0xFF, .size = 1, .exec = pl330_dmanop, },
+    { .opcode = 0x12, .opmask = 0xFF, .size = 1, .exec = pl330_dmarmb, },
+    { .opcode = 0x34, .opmask = 0xFF, .size = 2, .exec = pl330_dmasev, },
+    { .opcode = 0x08, .opmask = 0xFC, .size = 1, .exec = pl330_dmast, },
+    { .opcode = 0x0C, .opmask = 0xFF, .size = 1, .exec = pl330_dmastz, },
+    { .opcode = 0x36, .opmask = 0xFF, .size = 2, .exec = pl330_dmawfe, },
+    { .opcode = 0x30, .opmask = 0xFC, .size = 2, .exec = pl330_dmawfp, },
+    { .opcode = 0x13, .opmask = 0xFF, .size = 1, .exec = pl330_dmawmb, },
+    { .opcode = 0x00, .opmask = 0x00, .size = 0, .exec = NULL, }
+};
+
+/* Instructions which can be issued via debug registers. */
+static const PL330InsnDesc debug_insn_desc[] = {
+    { .opcode = 0xA0, .opmask = 0xFD, .size = 6, .exec = pl330_dmago, },
+    { .opcode = 0x01, .opmask = 0xFF, .size = 1, .exec = pl330_dmakill, },
+    { .opcode = 0x34, .opmask = 0xFF, .size = 2, .exec = pl330_dmasev, },
+    { .opcode = 0x00, .opmask = 0x00, .size = 0, .exec = NULL, }
+};
+
+static inline const PL330InsnDesc *pl330_fetch_insn(PL330Chan *ch)
+{
+    uint8_t opcode;
+    int i;
+
+    dma_memory_read(&dma_context_memory, ch->pc, &opcode, 1);
+    for (i = 0; insn_desc[i].size; i++) {
+        if ((opcode & insn_desc[i].opmask) == insn_desc[i].opcode) {
+            return &insn_desc[i];
+        }
+    }
+    return NULL;
+}
+
+static inline void pl330_exec_insn(PL330Chan *ch, const PL330InsnDesc *insn)
+{
+    uint8_t buf[PL330_INSN_MAXSIZE];
+
+    assert(insn->size <= PL330_INSN_MAXSIZE);
+    dma_memory_read(&dma_context_memory, ch->pc, buf, insn->size);
+    insn->exec(ch, buf[0], &buf[1], insn->size - 1);
+}
+
+static inline void pl330_update_pc(PL330Chan *ch,
+                                   const PL330InsnDesc *insn)
+{
+    ch->pc += insn->size;
+}
+
+/* Try to execute current instruction in channel CH. Number of executed
+   instructions is returned (0 or 1). */
+static int pl330_chan_exec(PL330Chan *ch)
+{
+    const PL330InsnDesc *insn;
+
+    if (ch->state != pl330_chan_executing &&
+            ch->state != pl330_chan_waiting_periph &&
+            ch->state != pl330_chan_at_barrier &&
+            ch->state != pl330_chan_waiting_event) {
+        DB_PRINT("%d\n", ch->state);
+        return 0;
+    }
+    ch->stall = 0;
+    insn = pl330_fetch_insn(ch);
+    if (!insn) {
+        DB_PRINT("pl330 undefined instruction\n");
+        pl330_fault(ch, PL330_FAULT_UNDEF_INSTR);
+        return 0;
+    }
+    pl330_exec_insn(ch, insn);
+    if (!ch->stall) {
+        pl330_update_pc(ch, insn);
+        ch->watchdog_timer = 0;
+        return 1;
+    /* WDT only active in exec state */
+    } else if (ch->state == pl330_chan_executing) {
+        ch->watchdog_timer++;
+        if (ch->watchdog_timer >= PL330_WATCHDOG_LIMIT) {
+            pl330_fault(ch, PL330_FAULT_LOCKUP_ERR);
+        }
+    }
+    return 0;
+}
+
+/* Try to execute 1 instruction in each channel, one instruction from read
+   queue and one instruction from write queue. Number of successfully executed
+   instructions is returned. */
+static int pl330_exec_cycle(PL330Chan *channel)
+{
+    PL330State *s = channel->parent;
+    PL330QueueEntry *q;
+    int i;
+    int num_exec = 0;
+    int fifo_res = 0;
+    uint8_t buf[PL330_MAX_BURST_LEN];
+
+    /* Execute one instruction in each channel */
+    num_exec += pl330_chan_exec(channel);
+
+    /* Execute one instruction from read queue */
+    q = pl330_queue_find_insn(&s->read_queue, PL330_UNTAGGED, true);
+    if (q != NULL && q->len <= pl330_fifo_num_free(&s->fifo)) {
+        int len = q->len - (q->addr & (q->len - 1));
+
+        dma_memory_read(&dma_context_memory, q->addr, buf, len);
+        if (PL330_ERR_DEBUG > 1) {
+            DB_PRINT("PL330 read from memory @%08x (size = %08x):\n",
+                      q->addr, len);
+            hexdump((char *)buf, stderr, "", len);
+        }
+        fifo_res = pl330_fifo_push(&s->fifo, buf, len, q->tag);
+        if (fifo_res == PL330_FIFO_OK) {
+            if (q->inc) {
+                q->addr += len;
+            }
+            q->n--;
+            if (!q->n) {
+                pl330_queue_remove_insn(&s->read_queue, q);
+            }
+            num_exec++;
+        }
+    }
+
+    /* Execute one instruction from write queue. */
+    q = pl330_queue_find_insn(&s->write_queue, pl330_fifo_tag(&s->fifo), true);
+    if (q != NULL) {
+        int len = q->len - (q->addr & (q->len - 1));
+
+        if (q->z) {
+            for (i = 0; i < len; i++) {
+                buf[i] = 0;
+            }
+        } else {
+            fifo_res = pl330_fifo_get(&s->fifo, buf, len, q->tag);
+        }
+        if (fifo_res == PL330_FIFO_OK || q->z) {
+            dma_memory_write(&dma_context_memory, q->addr, buf, len);
+            if (PL330_ERR_DEBUG > 1) {
+                DB_PRINT("PL330 read from memory @%08x (size = %08x):\n",
+                         q->addr, len);
+                hexdump((char *)buf, stderr, "", len);
+            }
+            if (q->inc) {
+                q->addr += len;
+            }
+            num_exec++;
+        } else if (fifo_res == PL330_FIFO_STALL) {
+            pl330_fault(&channel->parent->chan[q->tag],
+                                PL330_FAULT_FIFOEMPTY_ERR);
+        }
+        q->n--;
+        if (!q->n) {
+            pl330_queue_remove_insn(&s->write_queue, q);
+        }
+    }
+
+    return num_exec;
+}
+
+static int pl330_exec_channel(PL330Chan *channel)
+{
+    int insr_exec = 0;
+
+    /* TODO: Is it all right to execute everything or should we do per-cycle
+       simulation? */
+    while (pl330_exec_cycle(channel)) {
+        insr_exec++;
+    }
+
+    /* Detect deadlock */
+    if (channel->state == pl330_chan_executing) {
+        pl330_fault(channel, PL330_FAULT_LOCKUP_ERR);
+    }
+    /* Situation when one of the queues has deadlocked but all channels
+     * have finished their programs should be impossible.
+     */
+
+    return insr_exec;
+}
+
+static inline void pl330_exec(PL330State *s)
+{
+    DB_PRINT("\n");
+    int i, insr_exec;
+    do {
+        insr_exec = pl330_exec_channel(&s->manager);
+
+        for (i = 0; i < s->num_chnls; i++) {
+            insr_exec += pl330_exec_channel(&s->chan[i]);
+        }
+    } while (insr_exec);
+}
+
+static void pl330_exec_cycle_timer(void *opaque)
+{
+    PL330State *s = (PL330State *)opaque;
+    pl330_exec(s);
+}
+
+/* Stop or restore dma operations */
+
+static void pl330_dma_stop_irq(void *opaque, int irq, int level)
+{
+    PL330State *s = (PL330State *)opaque;
+
+    if (s->periph_busy[irq] != level) {
+        s->periph_busy[irq] = level;
+        qemu_mod_timer(s->timer, qemu_get_clock_ns(vm_clock));
+    }
+}
+
+static void pl330_debug_exec(PL330State *s)
+{
+    uint8_t args[5];
+    uint8_t opcode;
+    uint8_t chan_id;
+    int i;
+    PL330Chan *ch;
+    const PL330InsnDesc *insn;
+
+    s->debug_status = 1;
+    chan_id = (s->dbg[0] >>  8) & 0x07;
+    opcode  = (s->dbg[0] >> 16) & 0xff;
+    args[0] = (s->dbg[0] >> 24) & 0xff;
+    args[1] = (s->dbg[1] >>  0) & 0xff;
+    args[2] = (s->dbg[1] >>  8) & 0xff;
+    args[3] = (s->dbg[1] >> 16) & 0xff;
+    args[4] = (s->dbg[1] >> 24) & 0xff;
+    DB_PRINT("chan id: %d\n", chan_id);
+    if (s->dbg[0] & 1) {
+        ch = &s->chan[chan_id];
+    } else {
+        ch = &s->manager;
+    }
+    insn = NULL;
+    for (i = 0; debug_insn_desc[i].size; i++) {
+        if ((opcode & debug_insn_desc[i].opmask) == debug_insn_desc[i].opcode) {
+            insn = &debug_insn_desc[i];
+        }
+    }
+    if (!insn) {
+        pl330_fault(ch, PL330_FAULT_UNDEF_INSTR | PL330_FAULT_DBG_INSTR);
+        return ;
+    }
+    ch->stall = 0;
+    insn->exec(ch, opcode, args, insn->size - 1);
+    if (ch->fault_type) {
+        ch->fault_type |= PL330_FAULT_DBG_INSTR;
+    }
+    if (ch->stall) {
+        qemu_log_mask(LOG_UNIMP, "pl330: stall of debug instruction not "
+                      "implemented\n");
+    }
+    s->debug_status = 0;
+}
+
+/* IOMEM mapped registers */
+
+static void pl330_iomem_write(void *opaque, hwaddr offset,
+                              uint64_t value, unsigned size)
+{
+    PL330State *s = (PL330State *) opaque;
+    uint32_t i;
+
+    DB_PRINT("addr: %08x data: %08x\n", (unsigned)offset, (unsigned)value);
+
+    switch (offset) {
+    case PL330_REG_INTEN:
+        s->inten = value;
+        break;
+    case PL330_REG_INTCLR:
+        for (i = 0; i < s->num_events; i++) {
+            if (s->int_status & s->inten & value & (1 << i)) {
+                DB_PRINT("event interrupt lowered %d\n", i);
+                qemu_irq_lower(s->irq[i]);
+            }
+        }
+        s->ev_status &= ~(value & s->inten);
+        s->int_status &= ~(value & s->inten);
+        break;
+    case PL330_REG_DBGCMD:
+        if ((value & 3) == 0) {
+            pl330_debug_exec(s);
+            pl330_exec(s);
+        } else {
+            qemu_log_mask(LOG_GUEST_ERROR, "pl330: write of illegal value %u "
+                          "for offset " TARGET_FMT_plx "\n", (unsigned)value,
+                          offset);
+        }
+        break;
+    case PL330_REG_DBGINST0:
+        DB_PRINT("s->dbg[0] = %08x\n", (unsigned)value);
+        s->dbg[0] = value;
+        break;
+    case PL330_REG_DBGINST1:
+        DB_PRINT("s->dbg[1] = %08x\n", (unsigned)value);
+        s->dbg[1] = value;
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR, "pl330: bad write offset " TARGET_FMT_plx
+                      "\n", offset);
+        break;
+    }
+}
+
+static inline uint32_t pl330_iomem_read_imp(void *opaque,
+        hwaddr offset)
+{
+    PL330State *s = (PL330State *)opaque;
+    int chan_id;
+    int i;
+    uint32_t res;
+
+    if (offset >= PL330_REG_PERIPH_ID && offset < PL330_REG_PERIPH_ID + 32) {
+        return pl330_id[(offset - PL330_REG_PERIPH_ID) >> 2];
+    }
+    if (offset >= PL330_REG_CR0_BASE && offset < PL330_REG_CR0_BASE + 24) {
+        return s->cfg[(offset - PL330_REG_CR0_BASE) >> 2];
+    }
+    if (offset >= PL330_REG_CHANCTRL && offset < PL330_REG_DBGSTATUS) {
+        offset -= PL330_REG_CHANCTRL;
+        chan_id = offset >> 5;
+        if (chan_id >= s->num_chnls) {
+            qemu_log_mask(LOG_GUEST_ERROR, "pl330: bad read offset "
+                          TARGET_FMT_plx "\n", offset);
+            return 0;
+        }
+        switch (offset & 0x1f) {
+        case 0x00:
+            return s->chan[chan_id].src;
+        case 0x04:
+            return s->chan[chan_id].dst;
+        case 0x08:
+            return s->chan[chan_id].control;
+        case 0x0C:
+            return s->chan[chan_id].lc[0];
+        case 0x10:
+            return s->chan[chan_id].lc[1];
+        default:
+            qemu_log_mask(LOG_GUEST_ERROR, "pl330: bad read offset "
+                          TARGET_FMT_plx "\n", offset);
+            return 0;
+        }
+    }
+    if (offset >= PL330_REG_CSR_BASE && offset < 0x400) {
+        offset -= PL330_REG_CSR_BASE;
+        chan_id = offset >> 3;
+        if (chan_id >= s->num_chnls) {
+            qemu_log_mask(LOG_GUEST_ERROR, "pl330: bad read offset "
+                          TARGET_FMT_plx "\n", offset);
+            return 0;
+        }
+        switch ((offset >> 2) & 1) {
+        case 0x0:
+            res = (s->chan[chan_id].ns << 21) |
+                    (s->chan[chan_id].wakeup << 4) |
+                    (s->chan[chan_id].state) |
+                    (s->chan[chan_id].wfp_sbp << 14);
+            return res;
+        case 0x1:
+            return s->chan[chan_id].pc;
+        default:
+            qemu_log_mask(LOG_GUEST_ERROR, "pl330: read error\n");
+            return 0;
+        }
+    }
+    if (offset >= PL330_REG_FTR_BASE && offset < 0x100) {
+        offset -= PL330_REG_FTR_BASE;
+        chan_id = offset >> 2;
+        if (chan_id >= s->num_chnls) {
+            qemu_log_mask(LOG_GUEST_ERROR, "pl330: bad read offset "
+                          TARGET_FMT_plx "\n", offset);
+            return 0;
+        }
+        return s->chan[chan_id].fault_type;
+    }
+    switch (offset) {
+    case PL330_REG_DSR:
+        return (s->manager.ns << 9) | (s->manager.wakeup << 4) |
+            (s->manager.state & 0xf);
+    case PL330_REG_DPC:
+        return s->manager.pc;
+    case PL330_REG_INTEN:
+        return s->inten;
+    case PL330_REG_INT_EVENT_RIS:
+        return s->ev_status;
+    case PL330_REG_INTMIS:
+        return s->int_status;
+    case PL330_REG_INTCLR:
+        /* Documentation says that we can't read this register
+         * but linux kernel does it
+         */
+        return 0;
+    case PL330_REG_FSRD:
+        return s->manager.state ? 1 : 0;
+    case PL330_REG_FSRC:
+        res = 0;
+        for (i = 0; i < s->num_chnls; i++) {
+            if (s->chan[i].state == pl330_chan_fault ||
+                s->chan[i].state == pl330_chan_fault_completing) {
+                res |= 1 << i;
+            }
+        }
+        return res;
+    case PL330_REG_FTRD:
+        return s->manager.fault_type;
+    case PL330_REG_DBGSTATUS:
+        return s->debug_status;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR, "pl330: bad read offset "
+                      TARGET_FMT_plx "\n", offset);
+    }
+    return 0;
+}
+
+static uint64_t pl330_iomem_read(void *opaque, hwaddr offset,
+        unsigned size)
+{
+    int ret = pl330_iomem_read_imp(opaque, offset);
+    DB_PRINT("addr: %08x data: %08x\n", (unsigned)offset, ret);
+    return ret;
+}
+
+static const MemoryRegionOps pl330_ops = {
+    .read = pl330_iomem_read,
+    .write = pl330_iomem_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    }
+};
+
+/* Controller logic and initialization */
+
+static void pl330_chan_reset(PL330Chan *ch)
+{
+    ch->src = 0;
+    ch->dst = 0;
+    ch->pc = 0;
+    ch->state = pl330_chan_stopped;
+    ch->watchdog_timer = 0;
+    ch->stall = 0;
+    ch->control = 0;
+    ch->status = 0;
+    ch->fault_type = 0;
+}
+
+static void pl330_reset(DeviceState *d)
+{
+    int i;
+    PL330State *s = PL330(d);
+
+    s->inten = 0;
+    s->int_status = 0;
+    s->ev_status = 0;
+    s->debug_status = 0;
+    s->num_faulting = 0;
+    s->manager.ns = s->mgr_ns_at_rst;
+    pl330_fifo_reset(&s->fifo);
+    pl330_queue_reset(&s->read_queue);
+    pl330_queue_reset(&s->write_queue);
+
+    for (i = 0; i < s->num_chnls; i++) {
+        pl330_chan_reset(&s->chan[i]);
+    }
+    for (i = 0; i < s->num_periph_req; i++) {
+        s->periph_busy[i] = 0;
+    }
+
+    qemu_del_timer(s->timer);
+}
+
+static void pl330_realize(DeviceState *dev, Error **errp)
+{
+    int i;
+    PL330State *s = PL330(dev);
+
+    sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq_abort);
+    memory_region_init_io(&s->iomem, &pl330_ops, s, "dma", PL330_IOMEM_SIZE);
+    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
+
+    s->timer = qemu_new_timer_ns(vm_clock, pl330_exec_cycle_timer, s);
+
+    s->cfg[0] = (s->mgr_ns_at_rst ? 0x4 : 0) |
+                (s->num_periph_req > 0 ? 1 : 0) |
+                ((s->num_chnls - 1) & 0x7) << 4 |
+                ((s->num_periph_req - 1) & 0x1f) << 12 |
+                ((s->num_events - 1) & 0x1f) << 17;
+
+    switch (s->i_cache_len) {
+    case (4):
+        s->cfg[1] |= 2;
+        break;
+    case (8):
+        s->cfg[1] |= 3;
+        break;
+    case (16):
+        s->cfg[1] |= 4;
+        break;
+    case (32):
+        s->cfg[1] |= 5;
+        break;
+    default:
+        error_setg(errp, "Bad value for i-cache_len property: %d\n",
+                   s->i_cache_len);
+        return;
+    }
+    s->cfg[1] |= ((s->num_i_cache_lines - 1) & 0xf) << 4;
+
+    s->chan = g_new0(PL330Chan, s->num_chnls);
+    s->hi_seqn = g_new0(uint8_t, s->num_chnls);
+    s->lo_seqn = g_new0(uint8_t, s->num_chnls);
+    for (i = 0; i < s->num_chnls; i++) {
+        s->chan[i].parent = s;
+        s->chan[i].tag = (uint8_t)i;
+    }
+    s->manager.parent = s;
+    s->manager.tag = s->num_chnls;
+    s->manager.is_manager = true;
+
+    s->irq = g_new0(qemu_irq, s->num_events);
+    for (i = 0; i < s->num_events; i++) {
+        sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq[i]);
+    }
+
+    qdev_init_gpio_in(dev, pl330_dma_stop_irq, PL330_PERIPH_NUM);
+
+    switch (s->data_width) {
+    case (32):
+        s->cfg[CFG_CRD] |= 0x2;
+        break;
+    case (64):
+        s->cfg[CFG_CRD] |= 0x3;
+        break;
+    case (128):
+        s->cfg[CFG_CRD] |= 0x4;
+        break;
+    default:
+        error_setg(errp, "Bad value for data_width property: %d\n",
+                   s->data_width);
+        return;
+    }
+
+    s->cfg[CFG_CRD] |= ((s->wr_cap - 1) & 0x7) << 4 |
+                    ((s->wr_q_dep - 1) & 0xf) << 8 |
+                    ((s->rd_cap - 1) & 0x7) << 12 |
+                    ((s->rd_q_dep - 1) & 0xf) << 16 |
+                    ((s->data_buffer_dep - 1) & 0x1ff) << 20;
+
+    pl330_queue_init(&s->read_queue, s->rd_q_dep, s);
+    pl330_queue_init(&s->write_queue, s->wr_q_dep, s);
+    pl330_fifo_init(&s->fifo, s->data_buffer_dep);
+}
+
+static Property pl330_properties[] = {
+    /* CR0 */
+    DEFINE_PROP_UINT32("num_chnls", PL330State, num_chnls, 8),
+    DEFINE_PROP_UINT8("num_periph_req", PL330State, num_periph_req, 4),
+    DEFINE_PROP_UINT8("num_events", PL330State, num_events, 16),
+    DEFINE_PROP_UINT8("mgr_ns_at_rst", PL330State, mgr_ns_at_rst, 0),
+    /* CR1 */
+    DEFINE_PROP_UINT8("i-cache_len", PL330State, i_cache_len, 4),
+    DEFINE_PROP_UINT8("num_i-cache_lines", PL330State, num_i_cache_lines, 8),
+    /* CR2-4 */
+    DEFINE_PROP_UINT32("boot_addr", PL330State, cfg[CFG_BOOT_ADDR], 0),
+    DEFINE_PROP_UINT32("INS", PL330State, cfg[CFG_INS], 0),
+    DEFINE_PROP_UINT32("PNS", PL330State, cfg[CFG_PNS], 0),
+    /* CRD */
+    DEFINE_PROP_UINT8("data_width", PL330State, data_width, 64),
+    DEFINE_PROP_UINT8("wr_cap", PL330State, wr_cap, 8),
+    DEFINE_PROP_UINT8("wr_q_dep", PL330State, wr_q_dep, 16),
+    DEFINE_PROP_UINT8("rd_cap", PL330State, rd_cap, 8),
+    DEFINE_PROP_UINT8("rd_q_dep", PL330State, rd_q_dep, 16),
+    DEFINE_PROP_UINT16("data_buffer_dep", PL330State, data_buffer_dep, 256),
+
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void pl330_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->realize = pl330_realize;
+    dc->reset = pl330_reset;
+    dc->props = pl330_properties;
+    dc->vmsd = &vmstate_pl330;
+}
+
+static const TypeInfo pl330_type_info = {
+    .name           = TYPE_PL330,
+    .parent         = TYPE_SYS_BUS_DEVICE,
+    .instance_size  = sizeof(PL330State),
+    .class_init      = pl330_class_init,
+};
+
+static void pl330_register_types(void)
+{
+    type_register_static(&pl330_type_info);
+}
+
+type_init(pl330_register_types)
diff --git a/hw/dma/puv3_dma.c b/hw/dma/puv3_dma.c
new file mode 100644 (file)
index 0000000..32844b5
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * DMA device simulation in PKUnity SoC
+ *
+ * Copyright (C) 2010-2012 Guan Xuetao
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation, or any later version.
+ * See the COPYING file in the top-level directory.
+ */
+#include "hw/hw.h"
+#include "hw/sysbus.h"
+
+#undef DEBUG_PUV3
+#include "hw/unicore32/puv3.h"
+
+#define PUV3_DMA_CH_NR          (6)
+#define PUV3_DMA_CH_MASK        (0xff)
+#define PUV3_DMA_CH(offset)     ((offset) >> 8)
+
+typedef struct {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    uint32_t reg_CFG[PUV3_DMA_CH_NR];
+} PUV3DMAState;
+
+static uint64_t puv3_dma_read(void *opaque, hwaddr offset,
+        unsigned size)
+{
+    PUV3DMAState *s = opaque;
+    uint32_t ret = 0;
+
+    assert(PUV3_DMA_CH(offset) < PUV3_DMA_CH_NR);
+
+    switch (offset & PUV3_DMA_CH_MASK) {
+    case 0x10:
+        ret = s->reg_CFG[PUV3_DMA_CH(offset)];
+        break;
+    default:
+        DPRINTF("Bad offset 0x%x\n", offset);
+    }
+    DPRINTF("offset 0x%x, value 0x%x\n", offset, ret);
+
+    return ret;
+}
+
+static void puv3_dma_write(void *opaque, hwaddr offset,
+        uint64_t value, unsigned size)
+{
+    PUV3DMAState *s = opaque;
+
+    assert(PUV3_DMA_CH(offset) < PUV3_DMA_CH_NR);
+
+    switch (offset & PUV3_DMA_CH_MASK) {
+    case 0x10:
+        s->reg_CFG[PUV3_DMA_CH(offset)] = value;
+        break;
+    default:
+        DPRINTF("Bad offset 0x%x\n", offset);
+    }
+    DPRINTF("offset 0x%x, value 0x%x\n", offset, value);
+}
+
+static const MemoryRegionOps puv3_dma_ops = {
+    .read = puv3_dma_read,
+    .write = puv3_dma_write,
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int puv3_dma_init(SysBusDevice *dev)
+{
+    PUV3DMAState *s = FROM_SYSBUS(PUV3DMAState, dev);
+    int i;
+
+    for (i = 0; i < PUV3_DMA_CH_NR; i++) {
+        s->reg_CFG[i] = 0x0;
+    }
+
+    memory_region_init_io(&s->iomem, &puv3_dma_ops, s, "puv3_dma",
+            PUV3_REGS_OFFSET);
+    sysbus_init_mmio(dev, &s->iomem);
+
+    return 0;
+}
+
+static void puv3_dma_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sdc->init = puv3_dma_init;
+}
+
+static const TypeInfo puv3_dma_info = {
+    .name = "puv3_dma",
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(PUV3DMAState),
+    .class_init = puv3_dma_class_init,
+};
+
+static void puv3_dma_register_type(void)
+{
+    type_register_static(&puv3_dma_info);
+}
+
+type_init(puv3_dma_register_type)
diff --git a/hw/dma/pxa2xx_dma.c b/hw/dma/pxa2xx_dma.c
new file mode 100644 (file)
index 0000000..6e4c1f6
--- /dev/null
@@ -0,0 +1,574 @@
+/*
+ * Intel XScale PXA255/270 DMA controller.
+ *
+ * Copyright (c) 2006 Openedhand Ltd.
+ * Copyright (c) 2006 Thorsten Zitterell
+ * Written by Andrzej Zaborowski <balrog@zabor.org>
+ *
+ * This code is licensed under the GPL.
+ */
+
+#include "hw/hw.h"
+#include "hw/arm/pxa.h"
+#include "hw/sysbus.h"
+
+#define PXA255_DMA_NUM_CHANNELS 16
+#define PXA27X_DMA_NUM_CHANNELS 32
+
+#define PXA2XX_DMA_NUM_REQUESTS 75
+
+typedef struct {
+    uint32_t descr;
+    uint32_t src;
+    uint32_t dest;
+    uint32_t cmd;
+    uint32_t state;
+    int request;
+} PXA2xxDMAChannel;
+
+typedef struct PXA2xxDMAState {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    qemu_irq irq;
+
+    uint32_t stopintr;
+    uint32_t eorintr;
+    uint32_t rasintr;
+    uint32_t startintr;
+    uint32_t endintr;
+
+    uint32_t align;
+    uint32_t pio;
+
+    int channels;
+    PXA2xxDMAChannel *chan;
+
+    uint8_t req[PXA2XX_DMA_NUM_REQUESTS];
+
+    /* Flag to avoid recursive DMA invocations.  */
+    int running;
+} PXA2xxDMAState;
+
+#define DCSR0  0x0000  /* DMA Control / Status register for Channel 0 */
+#define DCSR31 0x007c  /* DMA Control / Status register for Channel 31 */
+#define DALGN  0x00a0  /* DMA Alignment register */
+#define DPCSR  0x00a4  /* DMA Programmed I/O Control Status register */
+#define DRQSR0 0x00e0  /* DMA DREQ<0> Status register */
+#define DRQSR1 0x00e4  /* DMA DREQ<1> Status register */
+#define DRQSR2 0x00e8  /* DMA DREQ<2> Status register */
+#define DINT   0x00f0  /* DMA Interrupt register */
+#define DRCMR0 0x0100  /* Request to Channel Map register 0 */
+#define DRCMR63        0x01fc  /* Request to Channel Map register 63 */
+#define D_CH0  0x0200  /* Channel 0 Descriptor start */
+#define DRCMR64        0x1100  /* Request to Channel Map register 64 */
+#define DRCMR74        0x1128  /* Request to Channel Map register 74 */
+
+/* Per-channel register */
+#define DDADR  0x00
+#define DSADR  0x01
+#define DTADR  0x02
+#define DCMD   0x03
+
+/* Bit-field masks */
+#define DRCMR_CHLNUM           0x1f
+#define DRCMR_MAPVLD           (1 << 7)
+#define DDADR_STOP             (1 << 0)
+#define DDADR_BREN             (1 << 1)
+#define DCMD_LEN               0x1fff
+#define DCMD_WIDTH(x)          (1 << ((((x) >> 14) & 3) - 1))
+#define DCMD_SIZE(x)           (4 << (((x) >> 16) & 3))
+#define DCMD_FLYBYT            (1 << 19)
+#define DCMD_FLYBYS            (1 << 20)
+#define DCMD_ENDIRQEN          (1 << 21)
+#define DCMD_STARTIRQEN                (1 << 22)
+#define DCMD_CMPEN             (1 << 25)
+#define DCMD_FLOWTRG           (1 << 28)
+#define DCMD_FLOWSRC           (1 << 29)
+#define DCMD_INCTRGADDR                (1 << 30)
+#define DCMD_INCSRCADDR                (1 << 31)
+#define DCSR_BUSERRINTR                (1 << 0)
+#define DCSR_STARTINTR         (1 << 1)
+#define DCSR_ENDINTR           (1 << 2)
+#define DCSR_STOPINTR          (1 << 3)
+#define DCSR_RASINTR           (1 << 4)
+#define DCSR_REQPEND           (1 << 8)
+#define DCSR_EORINT            (1 << 9)
+#define DCSR_CMPST             (1 << 10)
+#define DCSR_MASKRUN           (1 << 22)
+#define DCSR_RASIRQEN          (1 << 23)
+#define DCSR_CLRCMPST          (1 << 24)
+#define DCSR_SETCMPST          (1 << 25)
+#define DCSR_EORSTOPEN         (1 << 26)
+#define DCSR_EORJMPEN          (1 << 27)
+#define DCSR_EORIRQEN          (1 << 28)
+#define DCSR_STOPIRQEN         (1 << 29)
+#define DCSR_NODESCFETCH       (1 << 30)
+#define DCSR_RUN               (1 << 31)
+
+static inline void pxa2xx_dma_update(PXA2xxDMAState *s, int ch)
+{
+    if (ch >= 0) {
+        if ((s->chan[ch].state & DCSR_STOPIRQEN) &&
+                (s->chan[ch].state & DCSR_STOPINTR))
+            s->stopintr |= 1 << ch;
+        else
+            s->stopintr &= ~(1 << ch);
+
+        if ((s->chan[ch].state & DCSR_EORIRQEN) &&
+                (s->chan[ch].state & DCSR_EORINT))
+            s->eorintr |= 1 << ch;
+        else
+            s->eorintr &= ~(1 << ch);
+
+        if ((s->chan[ch].state & DCSR_RASIRQEN) &&
+                (s->chan[ch].state & DCSR_RASINTR))
+            s->rasintr |= 1 << ch;
+        else
+            s->rasintr &= ~(1 << ch);
+
+        if (s->chan[ch].state & DCSR_STARTINTR)
+            s->startintr |= 1 << ch;
+        else
+            s->startintr &= ~(1 << ch);
+
+        if (s->chan[ch].state & DCSR_ENDINTR)
+            s->endintr |= 1 << ch;
+        else
+            s->endintr &= ~(1 << ch);
+    }
+
+    if (s->stopintr | s->eorintr | s->rasintr | s->startintr | s->endintr)
+        qemu_irq_raise(s->irq);
+    else
+        qemu_irq_lower(s->irq);
+}
+
+static inline void pxa2xx_dma_descriptor_fetch(
+                PXA2xxDMAState *s, int ch)
+{
+    uint32_t desc[4];
+    hwaddr daddr = s->chan[ch].descr & ~0xf;
+    if ((s->chan[ch].descr & DDADR_BREN) && (s->chan[ch].state & DCSR_CMPST))
+        daddr += 32;
+
+    cpu_physical_memory_read(daddr, (uint8_t *) desc, 16);
+    s->chan[ch].descr = desc[DDADR];
+    s->chan[ch].src = desc[DSADR];
+    s->chan[ch].dest = desc[DTADR];
+    s->chan[ch].cmd = desc[DCMD];
+
+    if (s->chan[ch].cmd & DCMD_FLOWSRC)
+        s->chan[ch].src &= ~3;
+    if (s->chan[ch].cmd & DCMD_FLOWTRG)
+        s->chan[ch].dest &= ~3;
+
+    if (s->chan[ch].cmd & (DCMD_CMPEN | DCMD_FLYBYS | DCMD_FLYBYT))
+        printf("%s: unsupported mode in channel %i\n", __FUNCTION__, ch);
+
+    if (s->chan[ch].cmd & DCMD_STARTIRQEN)
+        s->chan[ch].state |= DCSR_STARTINTR;
+}
+
+static void pxa2xx_dma_run(PXA2xxDMAState *s)
+{
+    int c, srcinc, destinc;
+    uint32_t n, size;
+    uint32_t width;
+    uint32_t length;
+    uint8_t buffer[32];
+    PXA2xxDMAChannel *ch;
+
+    if (s->running ++)
+        return;
+
+    while (s->running) {
+        s->running = 1;
+        for (c = 0; c < s->channels; c ++) {
+            ch = &s->chan[c];
+
+            while ((ch->state & DCSR_RUN) && !(ch->state & DCSR_STOPINTR)) {
+                /* Test for pending requests */
+                if ((ch->cmd & (DCMD_FLOWSRC | DCMD_FLOWTRG)) && !ch->request)
+                    break;
+
+                length = ch->cmd & DCMD_LEN;
+                size = DCMD_SIZE(ch->cmd);
+                width = DCMD_WIDTH(ch->cmd);
+
+                srcinc = (ch->cmd & DCMD_INCSRCADDR) ? width : 0;
+                destinc = (ch->cmd & DCMD_INCTRGADDR) ? width : 0;
+
+                while (length) {
+                    size = MIN(length, size);
+
+                    for (n = 0; n < size; n += width) {
+                        cpu_physical_memory_read(ch->src, buffer + n, width);
+                        ch->src += srcinc;
+                    }
+
+                    for (n = 0; n < size; n += width) {
+                        cpu_physical_memory_write(ch->dest, buffer + n, width);
+                        ch->dest += destinc;
+                    }
+
+                    length -= size;
+
+                    if ((ch->cmd & (DCMD_FLOWSRC | DCMD_FLOWTRG)) &&
+                            !ch->request) {
+                        ch->state |= DCSR_EORINT;
+                        if (ch->state & DCSR_EORSTOPEN)
+                            ch->state |= DCSR_STOPINTR;
+                        if ((ch->state & DCSR_EORJMPEN) &&
+                                        !(ch->state & DCSR_NODESCFETCH))
+                            pxa2xx_dma_descriptor_fetch(s, c);
+                        break;
+                   }
+                }
+
+                ch->cmd = (ch->cmd & ~DCMD_LEN) | length;
+
+                /* Is the transfer complete now? */
+                if (!length) {
+                    if (ch->cmd & DCMD_ENDIRQEN)
+                        ch->state |= DCSR_ENDINTR;
+
+                    if ((ch->state & DCSR_NODESCFETCH) ||
+                                (ch->descr & DDADR_STOP) ||
+                                (ch->state & DCSR_EORSTOPEN)) {
+                        ch->state |= DCSR_STOPINTR;
+                        ch->state &= ~DCSR_RUN;
+
+                        break;
+                    }
+
+                    ch->state |= DCSR_STOPINTR;
+                    break;
+                }
+            }
+        }
+
+        s->running --;
+    }
+}
+
+static uint64_t pxa2xx_dma_read(void *opaque, hwaddr offset,
+                                unsigned size)
+{
+    PXA2xxDMAState *s = (PXA2xxDMAState *) opaque;
+    unsigned int channel;
+
+    if (size != 4) {
+        hw_error("%s: Bad access width\n", __FUNCTION__);
+        return 5;
+    }
+
+    switch (offset) {
+    case DRCMR64 ... DRCMR74:
+        offset -= DRCMR64 - DRCMR0 - (64 << 2);
+        /* Fall through */
+    case DRCMR0 ... DRCMR63:
+        channel = (offset - DRCMR0) >> 2;
+        return s->req[channel];
+
+    case DRQSR0:
+    case DRQSR1:
+    case DRQSR2:
+        return 0;
+
+    case DCSR0 ... DCSR31:
+        channel = offset >> 2;
+       if (s->chan[channel].request)
+            return s->chan[channel].state | DCSR_REQPEND;
+        return s->chan[channel].state;
+
+    case DINT:
+        return s->stopintr | s->eorintr | s->rasintr |
+                s->startintr | s->endintr;
+
+    case DALGN:
+        return s->align;
+
+    case DPCSR:
+        return s->pio;
+    }
+
+    if (offset >= D_CH0 && offset < D_CH0 + (s->channels << 4)) {
+        channel = (offset - D_CH0) >> 4;
+        switch ((offset & 0x0f) >> 2) {
+        case DDADR:
+            return s->chan[channel].descr;
+        case DSADR:
+            return s->chan[channel].src;
+        case DTADR:
+            return s->chan[channel].dest;
+        case DCMD:
+            return s->chan[channel].cmd;
+        }
+    }
+
+    hw_error("%s: Bad offset 0x" TARGET_FMT_plx "\n", __FUNCTION__, offset);
+    return 7;
+}
+
+static void pxa2xx_dma_write(void *opaque, hwaddr offset,
+                             uint64_t value, unsigned size)
+{
+    PXA2xxDMAState *s = (PXA2xxDMAState *) opaque;
+    unsigned int channel;
+
+    if (size != 4) {
+        hw_error("%s: Bad access width\n", __FUNCTION__);
+        return;
+    }
+
+    switch (offset) {
+    case DRCMR64 ... DRCMR74:
+        offset -= DRCMR64 - DRCMR0 - (64 << 2);
+        /* Fall through */
+    case DRCMR0 ... DRCMR63:
+        channel = (offset - DRCMR0) >> 2;
+
+        if (value & DRCMR_MAPVLD)
+            if ((value & DRCMR_CHLNUM) > s->channels)
+                hw_error("%s: Bad DMA channel %i\n",
+                         __FUNCTION__, (unsigned)value & DRCMR_CHLNUM);
+
+        s->req[channel] = value;
+        break;
+
+    case DRQSR0:
+    case DRQSR1:
+    case DRQSR2:
+        /* Nothing to do */
+        break;
+
+    case DCSR0 ... DCSR31:
+        channel = offset >> 2;
+        s->chan[channel].state &= 0x0000071f & ~(value &
+                        (DCSR_EORINT | DCSR_ENDINTR |
+                         DCSR_STARTINTR | DCSR_BUSERRINTR));
+        s->chan[channel].state |= value & 0xfc800000;
+
+        if (s->chan[channel].state & DCSR_STOPIRQEN)
+            s->chan[channel].state &= ~DCSR_STOPINTR;
+
+        if (value & DCSR_NODESCFETCH) {
+            /* No-descriptor-fetch mode */
+            if (value & DCSR_RUN) {
+                s->chan[channel].state &= ~DCSR_STOPINTR;
+                pxa2xx_dma_run(s);
+            }
+        } else {
+            /* Descriptor-fetch mode */
+            if (value & DCSR_RUN) {
+                s->chan[channel].state &= ~DCSR_STOPINTR;
+                pxa2xx_dma_descriptor_fetch(s, channel);
+                pxa2xx_dma_run(s);
+            }
+        }
+
+        /* Shouldn't matter as our DMA is synchronous.  */
+        if (!(value & (DCSR_RUN | DCSR_MASKRUN)))
+            s->chan[channel].state |= DCSR_STOPINTR;
+
+        if (value & DCSR_CLRCMPST)
+            s->chan[channel].state &= ~DCSR_CMPST;
+        if (value & DCSR_SETCMPST)
+            s->chan[channel].state |= DCSR_CMPST;
+
+        pxa2xx_dma_update(s, channel);
+        break;
+
+    case DALGN:
+        s->align = value;
+        break;
+
+    case DPCSR:
+        s->pio = value & 0x80000001;
+        break;
+
+    default:
+        if (offset >= D_CH0 && offset < D_CH0 + (s->channels << 4)) {
+            channel = (offset - D_CH0) >> 4;
+            switch ((offset & 0x0f) >> 2) {
+            case DDADR:
+                s->chan[channel].descr = value;
+                break;
+            case DSADR:
+                s->chan[channel].src = value;
+                break;
+            case DTADR:
+                s->chan[channel].dest = value;
+                break;
+            case DCMD:
+                s->chan[channel].cmd = value;
+                break;
+            default:
+                goto fail;
+            }
+
+            break;
+        }
+    fail:
+        hw_error("%s: Bad offset " TARGET_FMT_plx "\n", __FUNCTION__, offset);
+    }
+}
+
+static const MemoryRegionOps pxa2xx_dma_ops = {
+    .read = pxa2xx_dma_read,
+    .write = pxa2xx_dma_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void pxa2xx_dma_request(void *opaque, int req_num, int on)
+{
+    PXA2xxDMAState *s = opaque;
+    int ch;
+    if (req_num < 0 || req_num >= PXA2XX_DMA_NUM_REQUESTS)
+        hw_error("%s: Bad DMA request %i\n", __FUNCTION__, req_num);
+
+    if (!(s->req[req_num] & DRCMR_MAPVLD))
+        return;
+    ch = s->req[req_num] & DRCMR_CHLNUM;
+
+    if (!s->chan[ch].request && on)
+        s->chan[ch].state |= DCSR_RASINTR;
+    else
+        s->chan[ch].state &= ~DCSR_RASINTR;
+    if (s->chan[ch].request && !on)
+        s->chan[ch].state |= DCSR_EORINT;
+
+    s->chan[ch].request = on;
+    if (on) {
+        pxa2xx_dma_run(s);
+        pxa2xx_dma_update(s, ch);
+    }
+}
+
+static int pxa2xx_dma_init(SysBusDevice *dev)
+{
+    int i;
+    PXA2xxDMAState *s;
+    s = FROM_SYSBUS(PXA2xxDMAState, dev);
+
+    if (s->channels <= 0) {
+        return -1;
+    }
+
+    s->chan = g_malloc0(sizeof(PXA2xxDMAChannel) * s->channels);
+
+    memset(s->chan, 0, sizeof(PXA2xxDMAChannel) * s->channels);
+    for (i = 0; i < s->channels; i ++)
+        s->chan[i].state = DCSR_STOPINTR;
+
+    memset(s->req, 0, sizeof(uint8_t) * PXA2XX_DMA_NUM_REQUESTS);
+
+    qdev_init_gpio_in(&dev->qdev, pxa2xx_dma_request, PXA2XX_DMA_NUM_REQUESTS);
+
+    memory_region_init_io(&s->iomem, &pxa2xx_dma_ops, s,
+                          "pxa2xx.dma", 0x00010000);
+    sysbus_init_mmio(dev, &s->iomem);
+    sysbus_init_irq(dev, &s->irq);
+
+    return 0;
+}
+
+DeviceState *pxa27x_dma_init(hwaddr base, qemu_irq irq)
+{
+    DeviceState *dev;
+
+    dev = qdev_create(NULL, "pxa2xx-dma");
+    qdev_prop_set_int32(dev, "channels", PXA27X_DMA_NUM_CHANNELS);
+    qdev_init_nofail(dev);
+
+    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
+    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq);
+
+    return dev;
+}
+
+DeviceState *pxa255_dma_init(hwaddr base, qemu_irq irq)
+{
+    DeviceState *dev;
+
+    dev = qdev_create(NULL, "pxa2xx-dma");
+    qdev_prop_set_int32(dev, "channels", PXA27X_DMA_NUM_CHANNELS);
+    qdev_init_nofail(dev);
+
+    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
+    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq);
+
+    return dev;
+}
+
+static bool is_version_0(void *opaque, int version_id)
+{
+    return version_id == 0;
+}
+
+static VMStateDescription vmstate_pxa2xx_dma_chan = {
+    .name = "pxa2xx_dma_chan",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(descr, PXA2xxDMAChannel),
+        VMSTATE_UINT32(src, PXA2xxDMAChannel),
+        VMSTATE_UINT32(dest, PXA2xxDMAChannel),
+        VMSTATE_UINT32(cmd, PXA2xxDMAChannel),
+        VMSTATE_UINT32(state, PXA2xxDMAChannel),
+        VMSTATE_INT32(request, PXA2xxDMAChannel),
+        VMSTATE_END_OF_LIST(),
+    },
+};
+
+static VMStateDescription vmstate_pxa2xx_dma = {
+    .name = "pxa2xx_dma",
+    .version_id = 1,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields = (VMStateField[]) {
+        VMSTATE_UNUSED_TEST(is_version_0, 4),
+        VMSTATE_UINT32(stopintr, PXA2xxDMAState),
+        VMSTATE_UINT32(eorintr, PXA2xxDMAState),
+        VMSTATE_UINT32(rasintr, PXA2xxDMAState),
+        VMSTATE_UINT32(startintr, PXA2xxDMAState),
+        VMSTATE_UINT32(endintr, PXA2xxDMAState),
+        VMSTATE_UINT32(align, PXA2xxDMAState),
+        VMSTATE_UINT32(pio, PXA2xxDMAState),
+        VMSTATE_BUFFER(req, PXA2xxDMAState),
+        VMSTATE_STRUCT_VARRAY_POINTER_INT32(chan, PXA2xxDMAState, channels,
+                vmstate_pxa2xx_dma_chan, PXA2xxDMAChannel),
+        VMSTATE_END_OF_LIST(),
+    },
+};
+
+static Property pxa2xx_dma_properties[] = {
+    DEFINE_PROP_INT32("channels", PXA2xxDMAState, channels, -1),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void pxa2xx_dma_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = pxa2xx_dma_init;
+    dc->desc = "PXA2xx DMA controller";
+    dc->vmsd = &vmstate_pxa2xx_dma;
+    dc->props = pxa2xx_dma_properties;
+}
+
+static const 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_types(void)
+{
+    type_register_static(&pxa2xx_dma_info);
+}
+
+type_init(pxa2xx_dma_register_types)
diff --git a/hw/dma/rc4030.c b/hw/dma/rc4030.c
new file mode 100644 (file)
index 0000000..03f92f1
--- /dev/null
@@ -0,0 +1,825 @@
+/*
+ * QEMU JAZZ RC4030 chipset
+ *
+ * Copyright (c) 2007-2009 Herve 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 "hw/hw.h"
+#include "hw/mips/mips.h"
+#include "qemu/timer.h"
+
+/********************************************************/
+/* debug rc4030 */
+
+//#define DEBUG_RC4030
+//#define DEBUG_RC4030_DMA
+
+#ifdef DEBUG_RC4030
+#define DPRINTF(fmt, ...) \
+do { printf("rc4030: " fmt , ## __VA_ARGS__); } while (0)
+static const char* irq_names[] = { "parallel", "floppy", "sound", "video",
+            "network", "scsi", "keyboard", "mouse", "serial0", "serial1" };
+#else
+#define DPRINTF(fmt, ...)
+#endif
+
+#define RC4030_ERROR(fmt, ...) \
+do { fprintf(stderr, "rc4030 ERROR: %s: " fmt, __func__ , ## __VA_ARGS__); } while (0)
+
+/********************************************************/
+/* rc4030 emulation                                     */
+
+typedef struct dma_pagetable_entry {
+    int32_t frame;
+    int32_t owner;
+} QEMU_PACKED dma_pagetable_entry;
+
+#define DMA_PAGESIZE    4096
+#define DMA_REG_ENABLE  1
+#define DMA_REG_COUNT   2
+#define DMA_REG_ADDRESS 3
+
+#define DMA_FLAG_ENABLE     0x0001
+#define DMA_FLAG_MEM_TO_DEV 0x0002
+#define DMA_FLAG_TC_INTR    0x0100
+#define DMA_FLAG_MEM_INTR   0x0200
+#define DMA_FLAG_ADDR_INTR  0x0400
+
+typedef struct rc4030State
+{
+    uint32_t config; /* 0x0000: RC4030 config register */
+    uint32_t revision; /* 0x0008: RC4030 Revision register */
+    uint32_t invalid_address_register; /* 0x0010: Invalid Address register */
+
+    /* DMA */
+    uint32_t dma_regs[8][4];
+    uint32_t dma_tl_base; /* 0x0018: DMA transl. table base */
+    uint32_t dma_tl_limit; /* 0x0020: DMA transl. table limit */
+
+    /* cache */
+    uint32_t cache_maint; /* 0x0030: Cache Maintenance */
+    uint32_t remote_failed_address; /* 0x0038: Remote Failed Address */
+    uint32_t memory_failed_address; /* 0x0040: Memory Failed Address */
+    uint32_t cache_ptag; /* 0x0048: I/O Cache Physical Tag */
+    uint32_t cache_ltag; /* 0x0050: I/O Cache Logical Tag */
+    uint32_t cache_bmask; /* 0x0058: I/O Cache Byte Mask */
+
+    uint32_t nmi_interrupt; /* 0x0200: interrupt source */
+    uint32_t offset210;
+    uint32_t nvram_protect; /* 0x0220: NV ram protect register */
+    uint32_t rem_speed[16];
+    uint32_t imr_jazz; /* Local bus int enable mask */
+    uint32_t isr_jazz; /* Local bus int source */
+
+    /* timer */
+    QEMUTimer *periodic_timer;
+    uint32_t itr; /* Interval timer reload */
+
+    qemu_irq timer_irq;
+    qemu_irq jazz_bus_irq;
+
+    MemoryRegion iomem_chipset;
+    MemoryRegion iomem_jazzio;
+} rc4030State;
+
+static void set_next_tick(rc4030State *s)
+{
+    qemu_irq_lower(s->timer_irq);
+    uint32_t tm_hz;
+
+    tm_hz = 1000 / (s->itr + 1);
+
+    qemu_mod_timer(s->periodic_timer, qemu_get_clock_ns(vm_clock) +
+                   get_ticks_per_sec() / tm_hz);
+}
+
+/* called for accesses to rc4030 */
+static uint32_t rc4030_readl(void *opaque, hwaddr addr)
+{
+    rc4030State *s = opaque;
+    uint32_t val;
+
+    addr &= 0x3fff;
+    switch (addr & ~0x3) {
+    /* Global config register */
+    case 0x0000:
+        val = s->config;
+        break;
+    /* Revision register */
+    case 0x0008:
+        val = s->revision;
+        break;
+    /* Invalid Address register */
+    case 0x0010:
+        val = s->invalid_address_register;
+        break;
+    /* DMA transl. table base */
+    case 0x0018:
+        val = s->dma_tl_base;
+        break;
+    /* DMA transl. table limit */
+    case 0x0020:
+        val = s->dma_tl_limit;
+        break;
+    /* Remote Failed Address */
+    case 0x0038:
+        val = s->remote_failed_address;
+        break;
+    /* Memory Failed Address */
+    case 0x0040:
+        val = s->memory_failed_address;
+        break;
+    /* I/O Cache Byte Mask */
+    case 0x0058:
+        val = s->cache_bmask;
+        /* HACK */
+        if (s->cache_bmask == (uint32_t)-1)
+            s->cache_bmask = 0;
+        break;
+    /* Remote Speed Registers */
+    case 0x0070:
+    case 0x0078:
+    case 0x0080:
+    case 0x0088:
+    case 0x0090:
+    case 0x0098:
+    case 0x00a0:
+    case 0x00a8:
+    case 0x00b0:
+    case 0x00b8:
+    case 0x00c0:
+    case 0x00c8:
+    case 0x00d0:
+    case 0x00d8:
+    case 0x00e0:
+    case 0x00e8:
+        val = s->rem_speed[(addr - 0x0070) >> 3];
+        break;
+    /* DMA channel base address */
+    case 0x0100:
+    case 0x0108:
+    case 0x0110:
+    case 0x0118:
+    case 0x0120:
+    case 0x0128:
+    case 0x0130:
+    case 0x0138:
+    case 0x0140:
+    case 0x0148:
+    case 0x0150:
+    case 0x0158:
+    case 0x0160:
+    case 0x0168:
+    case 0x0170:
+    case 0x0178:
+    case 0x0180:
+    case 0x0188:
+    case 0x0190:
+    case 0x0198:
+    case 0x01a0:
+    case 0x01a8:
+    case 0x01b0:
+    case 0x01b8:
+    case 0x01c0:
+    case 0x01c8:
+    case 0x01d0:
+    case 0x01d8:
+    case 0x01e0:
+    case 0x01e8:
+    case 0x01f0:
+    case 0x01f8:
+        {
+            int entry = (addr - 0x0100) >> 5;
+            int idx = (addr & 0x1f) >> 3;
+            val = s->dma_regs[entry][idx];
+        }
+        break;
+    /* Interrupt source */
+    case 0x0200:
+        val = s->nmi_interrupt;
+        break;
+    /* Error type */
+    case 0x0208:
+        val = 0;
+        break;
+    /* Offset 0x0210 */
+    case 0x0210:
+        val = s->offset210;
+        break;
+    /* NV ram protect register */
+    case 0x0220:
+        val = s->nvram_protect;
+        break;
+    /* Interval timer count */
+    case 0x0230:
+        val = 0;
+        qemu_irq_lower(s->timer_irq);
+        break;
+    /* EISA interrupt */
+    case 0x0238:
+        val = 7; /* FIXME: should be read from EISA controller */
+        break;
+    default:
+        RC4030_ERROR("invalid read [" TARGET_FMT_plx "]\n", addr);
+        val = 0;
+        break;
+    }
+
+    if ((addr & ~3) != 0x230) {
+        DPRINTF("read 0x%02x at " TARGET_FMT_plx "\n", val, addr);
+    }
+
+    return val;
+}
+
+static uint32_t rc4030_readw(void *opaque, hwaddr addr)
+{
+    uint32_t v = rc4030_readl(opaque, addr & ~0x3);
+    if (addr & 0x2)
+        return v >> 16;
+    else
+        return v & 0xffff;
+}
+
+static uint32_t rc4030_readb(void *opaque, hwaddr addr)
+{
+    uint32_t v = rc4030_readl(opaque, addr & ~0x3);
+    return (v >> (8 * (addr & 0x3))) & 0xff;
+}
+
+static void rc4030_writel(void *opaque, hwaddr addr, uint32_t val)
+{
+    rc4030State *s = opaque;
+    addr &= 0x3fff;
+
+    DPRINTF("write 0x%02x at " TARGET_FMT_plx "\n", val, addr);
+
+    switch (addr & ~0x3) {
+    /* Global config register */
+    case 0x0000:
+        s->config = val;
+        break;
+    /* DMA transl. table base */
+    case 0x0018:
+        s->dma_tl_base = val;
+        break;
+    /* DMA transl. table limit */
+    case 0x0020:
+        s->dma_tl_limit = val;
+        break;
+    /* DMA transl. table invalidated */
+    case 0x0028:
+        break;
+    /* Cache Maintenance */
+    case 0x0030:
+        s->cache_maint = val;
+        break;
+    /* I/O Cache Physical Tag */
+    case 0x0048:
+        s->cache_ptag = val;
+        break;
+    /* I/O Cache Logical Tag */
+    case 0x0050:
+        s->cache_ltag = val;
+        break;
+    /* I/O Cache Byte Mask */
+    case 0x0058:
+        s->cache_bmask |= val; /* HACK */
+        break;
+    /* I/O Cache Buffer Window */
+    case 0x0060:
+        /* HACK */
+        if (s->cache_ltag == 0x80000001 && s->cache_bmask == 0xf0f0f0f) {
+            hwaddr dest = s->cache_ptag & ~0x1;
+            dest += (s->cache_maint & 0x3) << 3;
+            cpu_physical_memory_write(dest, &val, 4);
+        }
+        break;
+    /* Remote Speed Registers */
+    case 0x0070:
+    case 0x0078:
+    case 0x0080:
+    case 0x0088:
+    case 0x0090:
+    case 0x0098:
+    case 0x00a0:
+    case 0x00a8:
+    case 0x00b0:
+    case 0x00b8:
+    case 0x00c0:
+    case 0x00c8:
+    case 0x00d0:
+    case 0x00d8:
+    case 0x00e0:
+    case 0x00e8:
+        s->rem_speed[(addr - 0x0070) >> 3] = val;
+        break;
+    /* DMA channel base address */
+    case 0x0100:
+    case 0x0108:
+    case 0x0110:
+    case 0x0118:
+    case 0x0120:
+    case 0x0128:
+    case 0x0130:
+    case 0x0138:
+    case 0x0140:
+    case 0x0148:
+    case 0x0150:
+    case 0x0158:
+    case 0x0160:
+    case 0x0168:
+    case 0x0170:
+    case 0x0178:
+    case 0x0180:
+    case 0x0188:
+    case 0x0190:
+    case 0x0198:
+    case 0x01a0:
+    case 0x01a8:
+    case 0x01b0:
+    case 0x01b8:
+    case 0x01c0:
+    case 0x01c8:
+    case 0x01d0:
+    case 0x01d8:
+    case 0x01e0:
+    case 0x01e8:
+    case 0x01f0:
+    case 0x01f8:
+        {
+            int entry = (addr - 0x0100) >> 5;
+            int idx = (addr & 0x1f) >> 3;
+            s->dma_regs[entry][idx] = val;
+        }
+        break;
+    /* Offset 0x0210 */
+    case 0x0210:
+        s->offset210 = val;
+        break;
+    /* Interval timer reload */
+    case 0x0228:
+        s->itr = val;
+        qemu_irq_lower(s->timer_irq);
+        set_next_tick(s);
+        break;
+    /* EISA interrupt */
+    case 0x0238:
+        break;
+    default:
+        RC4030_ERROR("invalid write of 0x%02x at [" TARGET_FMT_plx "]\n", val, addr);
+        break;
+    }
+}
+
+static void rc4030_writew(void *opaque, hwaddr addr, uint32_t val)
+{
+    uint32_t old_val = rc4030_readl(opaque, addr & ~0x3);
+
+    if (addr & 0x2)
+        val = (val << 16) | (old_val & 0x0000ffff);
+    else
+        val = val | (old_val & 0xffff0000);
+    rc4030_writel(opaque, addr & ~0x3, val);
+}
+
+static void rc4030_writeb(void *opaque, hwaddr addr, uint32_t val)
+{
+    uint32_t old_val = rc4030_readl(opaque, addr & ~0x3);
+
+    switch (addr & 3) {
+    case 0:
+        val = val | (old_val & 0xffffff00);
+        break;
+    case 1:
+        val = (val << 8) | (old_val & 0xffff00ff);
+        break;
+    case 2:
+        val = (val << 16) | (old_val & 0xff00ffff);
+        break;
+    case 3:
+        val = (val << 24) | (old_val & 0x00ffffff);
+        break;
+    }
+    rc4030_writel(opaque, addr & ~0x3, val);
+}
+
+static const MemoryRegionOps rc4030_ops = {
+    .old_mmio = {
+        .read = { rc4030_readb, rc4030_readw, rc4030_readl, },
+        .write = { rc4030_writeb, rc4030_writew, rc4030_writel, },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void update_jazz_irq(rc4030State *s)
+{
+    uint16_t pending;
+
+    pending = s->isr_jazz & s->imr_jazz;
+
+#ifdef DEBUG_RC4030
+    if (s->isr_jazz != 0) {
+        uint32_t irq = 0;
+        DPRINTF("pending irqs:");
+        for (irq = 0; irq < ARRAY_SIZE(irq_names); irq++) {
+            if (s->isr_jazz & (1 << irq)) {
+                printf(" %s", irq_names[irq]);
+                if (!(s->imr_jazz & (1 << irq))) {
+                    printf("(ignored)");
+                }
+            }
+        }
+        printf("\n");
+    }
+#endif
+
+    if (pending != 0)
+        qemu_irq_raise(s->jazz_bus_irq);
+    else
+        qemu_irq_lower(s->jazz_bus_irq);
+}
+
+static void rc4030_irq_jazz_request(void *opaque, int irq, int level)
+{
+    rc4030State *s = opaque;
+
+    if (level) {
+        s->isr_jazz |= 1 << irq;
+    } else {
+        s->isr_jazz &= ~(1 << irq);
+    }
+
+    update_jazz_irq(s);
+}
+
+static void rc4030_periodic_timer(void *opaque)
+{
+    rc4030State *s = opaque;
+
+    set_next_tick(s);
+    qemu_irq_raise(s->timer_irq);
+}
+
+static uint32_t jazzio_readw(void *opaque, hwaddr addr)
+{
+    rc4030State *s = opaque;
+    uint32_t val;
+    uint32_t irq;
+    addr &= 0xfff;
+
+    switch (addr) {
+    /* Local bus int source */
+    case 0x00: {
+        uint32_t pending = s->isr_jazz & s->imr_jazz;
+        val = 0;
+        irq = 0;
+        while (pending) {
+            if (pending & 1) {
+                DPRINTF("returning irq %s\n", irq_names[irq]);
+                val = (irq + 1) << 2;
+                break;
+            }
+            irq++;
+            pending >>= 1;
+        }
+        break;
+    }
+    /* Local bus int enable mask */
+    case 0x02:
+        val = s->imr_jazz;
+        break;
+    default:
+        RC4030_ERROR("(jazz io controller) invalid read [" TARGET_FMT_plx "]\n", addr);
+        val = 0;
+    }
+
+    DPRINTF("(jazz io controller) read 0x%04x at " TARGET_FMT_plx "\n", val, addr);
+
+    return val;
+}
+
+static uint32_t jazzio_readb(void *opaque, hwaddr addr)
+{
+    uint32_t v;
+    v = jazzio_readw(opaque, addr & ~0x1);
+    return (v >> (8 * (addr & 0x1))) & 0xff;
+}
+
+static uint32_t jazzio_readl(void *opaque, hwaddr addr)
+{
+    uint32_t v;
+    v = jazzio_readw(opaque, addr);
+    v |= jazzio_readw(opaque, addr + 2) << 16;
+    return v;
+}
+
+static void jazzio_writew(void *opaque, hwaddr addr, uint32_t val)
+{
+    rc4030State *s = opaque;
+    addr &= 0xfff;
+
+    DPRINTF("(jazz io controller) write 0x%04x at " TARGET_FMT_plx "\n", val, addr);
+
+    switch (addr) {
+    /* Local bus int enable mask */
+    case 0x02:
+        s->imr_jazz = val;
+        update_jazz_irq(s);
+        break;
+    default:
+        RC4030_ERROR("(jazz io controller) invalid write of 0x%04x at [" TARGET_FMT_plx "]\n", val, addr);
+        break;
+    }
+}
+
+static void jazzio_writeb(void *opaque, hwaddr addr, uint32_t val)
+{
+    uint32_t old_val = jazzio_readw(opaque, addr & ~0x1);
+
+    switch (addr & 1) {
+    case 0:
+        val = val | (old_val & 0xff00);
+        break;
+    case 1:
+        val = (val << 8) | (old_val & 0x00ff);
+        break;
+    }
+    jazzio_writew(opaque, addr & ~0x1, val);
+}
+
+static void jazzio_writel(void *opaque, hwaddr addr, uint32_t val)
+{
+    jazzio_writew(opaque, addr, val & 0xffff);
+    jazzio_writew(opaque, addr + 2, (val >> 16) & 0xffff);
+}
+
+static const MemoryRegionOps jazzio_ops = {
+    .old_mmio = {
+        .read = { jazzio_readb, jazzio_readw, jazzio_readl, },
+        .write = { jazzio_writeb, jazzio_writew, jazzio_writel, },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void rc4030_reset(void *opaque)
+{
+    rc4030State *s = opaque;
+    int i;
+
+    s->config = 0x410; /* some boards seem to accept 0x104 too */
+    s->revision = 1;
+    s->invalid_address_register = 0;
+
+    memset(s->dma_regs, 0, sizeof(s->dma_regs));
+    s->dma_tl_base = s->dma_tl_limit = 0;
+
+    s->remote_failed_address = s->memory_failed_address = 0;
+    s->cache_maint = 0;
+    s->cache_ptag = s->cache_ltag = 0;
+    s->cache_bmask = 0;
+
+    s->offset210 = 0x18186;
+    s->nvram_protect = 7;
+    for (i = 0; i < 15; i++)
+        s->rem_speed[i] = 7;
+    s->imr_jazz = 0x10; /* XXX: required by firmware, but why? */
+    s->isr_jazz = 0;
+
+    s->itr = 0;
+
+    qemu_irq_lower(s->timer_irq);
+    qemu_irq_lower(s->jazz_bus_irq);
+}
+
+static int rc4030_load(QEMUFile *f, void *opaque, int version_id)
+{
+    rc4030State* s = opaque;
+    int i, j;
+
+    if (version_id != 2)
+        return -EINVAL;
+
+    s->config = qemu_get_be32(f);
+    s->invalid_address_register = qemu_get_be32(f);
+    for (i = 0; i < 8; i++)
+        for (j = 0; j < 4; j++)
+            s->dma_regs[i][j] = qemu_get_be32(f);
+    s->dma_tl_base = qemu_get_be32(f);
+    s->dma_tl_limit = qemu_get_be32(f);
+    s->cache_maint = qemu_get_be32(f);
+    s->remote_failed_address = qemu_get_be32(f);
+    s->memory_failed_address = qemu_get_be32(f);
+    s->cache_ptag = qemu_get_be32(f);
+    s->cache_ltag = qemu_get_be32(f);
+    s->cache_bmask = qemu_get_be32(f);
+    s->offset210 = qemu_get_be32(f);
+    s->nvram_protect = qemu_get_be32(f);
+    for (i = 0; i < 15; i++)
+        s->rem_speed[i] = qemu_get_be32(f);
+    s->imr_jazz = qemu_get_be32(f);
+    s->isr_jazz = qemu_get_be32(f);
+    s->itr = qemu_get_be32(f);
+
+    set_next_tick(s);
+    update_jazz_irq(s);
+
+    return 0;
+}
+
+static void rc4030_save(QEMUFile *f, void *opaque)
+{
+    rc4030State* s = opaque;
+    int i, j;
+
+    qemu_put_be32(f, s->config);
+    qemu_put_be32(f, s->invalid_address_register);
+    for (i = 0; i < 8; i++)
+        for (j = 0; j < 4; j++)
+            qemu_put_be32(f, s->dma_regs[i][j]);
+    qemu_put_be32(f, s->dma_tl_base);
+    qemu_put_be32(f, s->dma_tl_limit);
+    qemu_put_be32(f, s->cache_maint);
+    qemu_put_be32(f, s->remote_failed_address);
+    qemu_put_be32(f, s->memory_failed_address);
+    qemu_put_be32(f, s->cache_ptag);
+    qemu_put_be32(f, s->cache_ltag);
+    qemu_put_be32(f, s->cache_bmask);
+    qemu_put_be32(f, s->offset210);
+    qemu_put_be32(f, s->nvram_protect);
+    for (i = 0; i < 15; i++)
+        qemu_put_be32(f, s->rem_speed[i]);
+    qemu_put_be32(f, s->imr_jazz);
+    qemu_put_be32(f, s->isr_jazz);
+    qemu_put_be32(f, s->itr);
+}
+
+void rc4030_dma_memory_rw(void *opaque, hwaddr addr, uint8_t *buf, int len, int is_write)
+{
+    rc4030State *s = opaque;
+    hwaddr entry_addr;
+    hwaddr phys_addr;
+    dma_pagetable_entry entry;
+    int index;
+    int ncpy, i;
+
+    i = 0;
+    for (;;) {
+        if (i == len) {
+            break;
+        }
+
+        ncpy = DMA_PAGESIZE - (addr & (DMA_PAGESIZE - 1));
+        if (ncpy > len - i)
+            ncpy = len - i;
+
+        /* Get DMA translation table entry */
+        index = addr / DMA_PAGESIZE;
+        if (index >= s->dma_tl_limit / sizeof(dma_pagetable_entry)) {
+            break;
+        }
+        entry_addr = s->dma_tl_base + index * sizeof(dma_pagetable_entry);
+        /* XXX: not sure. should we really use only lowest bits? */
+        entry_addr &= 0x7fffffff;
+        cpu_physical_memory_read(entry_addr, &entry, sizeof(entry));
+
+        /* Read/write data at right place */
+        phys_addr = entry.frame + (addr & (DMA_PAGESIZE - 1));
+        cpu_physical_memory_rw(phys_addr, &buf[i], ncpy, is_write);
+
+        i += ncpy;
+        addr += ncpy;
+    }
+}
+
+static void rc4030_do_dma(void *opaque, int n, uint8_t *buf, int len, int is_write)
+{
+    rc4030State *s = opaque;
+    hwaddr dma_addr;
+    int dev_to_mem;
+
+    s->dma_regs[n][DMA_REG_ENABLE] &= ~(DMA_FLAG_TC_INTR | DMA_FLAG_MEM_INTR | DMA_FLAG_ADDR_INTR);
+
+    /* Check DMA channel consistency */
+    dev_to_mem = (s->dma_regs[n][DMA_REG_ENABLE] & DMA_FLAG_MEM_TO_DEV) ? 0 : 1;
+    if (!(s->dma_regs[n][DMA_REG_ENABLE] & DMA_FLAG_ENABLE) ||
+        (is_write != dev_to_mem)) {
+        s->dma_regs[n][DMA_REG_ENABLE] |= DMA_FLAG_MEM_INTR;
+        s->nmi_interrupt |= 1 << n;
+        return;
+    }
+
+    /* Get start address and len */
+    if (len > s->dma_regs[n][DMA_REG_COUNT])
+        len = s->dma_regs[n][DMA_REG_COUNT];
+    dma_addr = s->dma_regs[n][DMA_REG_ADDRESS];
+
+    /* Read/write data at right place */
+    rc4030_dma_memory_rw(opaque, dma_addr, buf, len, is_write);
+
+    s->dma_regs[n][DMA_REG_ENABLE] |= DMA_FLAG_TC_INTR;
+    s->dma_regs[n][DMA_REG_COUNT] -= len;
+
+#ifdef DEBUG_RC4030_DMA
+    {
+        int i, j;
+        printf("rc4030 dma: Copying %d bytes %s host %p\n",
+            len, is_write ? "from" : "to", buf);
+        for (i = 0; i < len; i += 16) {
+            int n = 16;
+            if (n > len - i) {
+                n = len - i;
+            }
+            for (j = 0; j < n; j++)
+                printf("%02x ", buf[i + j]);
+            while (j++ < 16)
+                printf("   ");
+            printf("| ");
+            for (j = 0; j < n; j++)
+                printf("%c", isprint(buf[i + j]) ? buf[i + j] : '.');
+            printf("\n");
+        }
+    }
+#endif
+}
+
+struct rc4030DMAState {
+    void *opaque;
+    int n;
+};
+
+void rc4030_dma_read(void *dma, uint8_t *buf, int len)
+{
+    rc4030_dma s = dma;
+    rc4030_do_dma(s->opaque, s->n, buf, len, 0);
+}
+
+void rc4030_dma_write(void *dma, uint8_t *buf, int len)
+{
+    rc4030_dma s = dma;
+    rc4030_do_dma(s->opaque, s->n, buf, len, 1);
+}
+
+static rc4030_dma *rc4030_allocate_dmas(void *opaque, int n)
+{
+    rc4030_dma *s;
+    struct rc4030DMAState *p;
+    int i;
+
+    s = (rc4030_dma *)g_malloc0(sizeof(rc4030_dma) * n);
+    p = (struct rc4030DMAState *)g_malloc0(sizeof(struct rc4030DMAState) * n);
+    for (i = 0; i < n; i++) {
+        p->opaque = opaque;
+        p->n = i;
+        s[i] = p;
+        p++;
+    }
+    return s;
+}
+
+void *rc4030_init(qemu_irq timer, qemu_irq jazz_bus,
+                  qemu_irq **irqs, rc4030_dma **dmas,
+                  MemoryRegion *sysmem)
+{
+    rc4030State *s;
+
+    s = g_malloc0(sizeof(rc4030State));
+
+    *irqs = qemu_allocate_irqs(rc4030_irq_jazz_request, s, 16);
+    *dmas = rc4030_allocate_dmas(s, 4);
+
+    s->periodic_timer = qemu_new_timer_ns(vm_clock, rc4030_periodic_timer, s);
+    s->timer_irq = timer;
+    s->jazz_bus_irq = jazz_bus;
+
+    qemu_register_reset(rc4030_reset, s);
+    register_savevm(NULL, "rc4030", 0, 2, rc4030_save, rc4030_load, s);
+    rc4030_reset(s);
+
+    memory_region_init_io(&s->iomem_chipset, &rc4030_ops, s,
+                          "rc4030.chipset", 0x300);
+    memory_region_add_subregion(sysmem, 0x80000000, &s->iomem_chipset);
+    memory_region_init_io(&s->iomem_jazzio, &jazzio_ops, s,
+                          "rc4030.jazzio", 0x00001000);
+    memory_region_add_subregion(sysmem, 0xf0000000, &s->iomem_jazzio);
+
+    return s;
+}
diff --git a/hw/dma/soc_dma.c b/hw/dma/soc_dma.c
new file mode 100644 (file)
index 0000000..5e3491d
--- /dev/null
@@ -0,0 +1,366 @@
+/*
+ * On-chip DMA controller framework.
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ * Written by Andrzej Zaborowski <andrew@openedhand.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 or
+ * (at your option) version 3 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
+ * 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 "qemu/timer.h"
+#include "hw/arm/soc_dma.h"
+
+static void transfer_mem2mem(struct soc_dma_ch_s *ch)
+{
+    memcpy(ch->paddr[0], ch->paddr[1], ch->bytes);
+    ch->paddr[0] += ch->bytes;
+    ch->paddr[1] += ch->bytes;
+}
+
+static void transfer_mem2fifo(struct soc_dma_ch_s *ch)
+{
+    ch->io_fn[1](ch->io_opaque[1], ch->paddr[0], ch->bytes);
+    ch->paddr[0] += ch->bytes;
+}
+
+static void transfer_fifo2mem(struct soc_dma_ch_s *ch)
+{
+    ch->io_fn[0](ch->io_opaque[0], ch->paddr[1], ch->bytes);
+    ch->paddr[1] += ch->bytes;
+}
+
+/* This is further optimisable but isn't very important because often
+ * DMA peripherals forbid this kind of transfers and even when they don't,
+ * oprating systems may not need to use them.  */
+static void *fifo_buf;
+static int fifo_size;
+static void transfer_fifo2fifo(struct soc_dma_ch_s *ch)
+{
+    if (ch->bytes > fifo_size)
+        fifo_buf = g_realloc(fifo_buf, fifo_size = ch->bytes);
+
+    /* Implement as transfer_fifo2linear + transfer_linear2fifo.  */
+    ch->io_fn[0](ch->io_opaque[0], fifo_buf, ch->bytes);
+    ch->io_fn[1](ch->io_opaque[1], fifo_buf, ch->bytes);
+}
+
+struct dma_s {
+    struct soc_dma_s soc;
+    int chnum;
+    uint64_t ch_enable_mask;
+    int64_t channel_freq;
+    int enabled_count;
+
+    struct memmap_entry_s {
+        enum soc_dma_port_type type;
+        hwaddr addr;
+        union {
+           struct {
+               void *opaque;
+               soc_dma_io_t fn;
+               int out;
+           } fifo;
+           struct {
+               void *base;
+               size_t size;
+           } mem;
+        } u;
+    } *memmap;
+    int memmap_size;
+
+    struct soc_dma_ch_s ch[0];
+};
+
+static void soc_dma_ch_schedule(struct soc_dma_ch_s *ch, int delay_bytes)
+{
+    int64_t now = qemu_get_clock_ns(vm_clock);
+    struct dma_s *dma = (struct dma_s *) ch->dma;
+
+    qemu_mod_timer(ch->timer, now + delay_bytes / dma->channel_freq);
+}
+
+static void soc_dma_ch_run(void *opaque)
+{
+    struct soc_dma_ch_s *ch = (struct soc_dma_ch_s *) opaque;
+
+    ch->running = 1;
+    ch->dma->setup_fn(ch);
+    ch->transfer_fn(ch);
+    ch->running = 0;
+
+    if (ch->enable)
+        soc_dma_ch_schedule(ch, ch->bytes);
+    ch->bytes = 0;
+}
+
+static inline struct memmap_entry_s *soc_dma_lookup(struct dma_s *dma,
+                hwaddr addr)
+{
+    struct memmap_entry_s *lo;
+    int hi;
+
+    lo = dma->memmap;
+    hi = dma->memmap_size;
+
+    while (hi > 1) {
+        hi /= 2;
+        if (lo[hi].addr <= addr)
+            lo += hi;
+    }
+
+    return lo;
+}
+
+static inline enum soc_dma_port_type soc_dma_ch_update_type(
+                struct soc_dma_ch_s *ch, int port)
+{
+    struct dma_s *dma = (struct dma_s *) ch->dma;
+    struct memmap_entry_s *entry = soc_dma_lookup(dma, ch->vaddr[port]);
+
+    if (entry->type == soc_dma_port_fifo) {
+        while (entry < dma->memmap + dma->memmap_size &&
+                        entry->u.fifo.out != port)
+            entry ++;
+        if (entry->addr != ch->vaddr[port] || entry->u.fifo.out != port)
+            return soc_dma_port_other;
+
+        if (ch->type[port] != soc_dma_access_const)
+            return soc_dma_port_other;
+
+        ch->io_fn[port] = entry->u.fifo.fn;
+        ch->io_opaque[port] = entry->u.fifo.opaque;
+        return soc_dma_port_fifo;
+    } else if (entry->type == soc_dma_port_mem) {
+        if (entry->addr > ch->vaddr[port] ||
+                        entry->addr + entry->u.mem.size <= ch->vaddr[port])
+            return soc_dma_port_other;
+
+        /* TODO: support constant memory address for source port as used for
+         * drawing solid rectangles by PalmOS(R).  */
+        if (ch->type[port] != soc_dma_access_const)
+            return soc_dma_port_other;
+
+        ch->paddr[port] = (uint8_t *) entry->u.mem.base +
+                (ch->vaddr[port] - entry->addr);
+        /* TODO: save bytes left to the end of the mapping somewhere so we
+         * can check we're not reading beyond it.  */
+        return soc_dma_port_mem;
+    } else
+        return soc_dma_port_other;
+}
+
+void soc_dma_ch_update(struct soc_dma_ch_s *ch)
+{
+    enum soc_dma_port_type src, dst;
+
+    src = soc_dma_ch_update_type(ch, 0);
+    if (src == soc_dma_port_other) {
+        ch->update = 0;
+        ch->transfer_fn = ch->dma->transfer_fn;
+        return;
+    }
+    dst = soc_dma_ch_update_type(ch, 1);
+
+    /* TODO: use src and dst as array indices.  */
+    if (src == soc_dma_port_mem && dst == soc_dma_port_mem)
+        ch->transfer_fn = transfer_mem2mem;
+    else if (src == soc_dma_port_mem && dst == soc_dma_port_fifo)
+        ch->transfer_fn = transfer_mem2fifo;
+    else if (src == soc_dma_port_fifo && dst == soc_dma_port_mem)
+        ch->transfer_fn = transfer_fifo2mem;
+    else if (src == soc_dma_port_fifo && dst == soc_dma_port_fifo)
+        ch->transfer_fn = transfer_fifo2fifo;
+    else
+        ch->transfer_fn = ch->dma->transfer_fn;
+
+    ch->update = (dst != soc_dma_port_other);
+}
+
+static void soc_dma_ch_freq_update(struct dma_s *s)
+{
+    if (s->enabled_count)
+        /* We completely ignore channel priorities and stuff */
+        s->channel_freq = s->soc.freq / s->enabled_count;
+    else {
+        /* TODO: Signal that we want to disable the functional clock and let
+         * the platform code decide what to do with it, i.e. check that
+         * auto-idle is enabled in the clock controller and if we are stopping
+         * the clock, do the same with any parent clocks that had only one
+         * user keeping them on and auto-idle enabled.  */
+    }
+}
+
+void soc_dma_set_request(struct soc_dma_ch_s *ch, int level)
+{
+    struct dma_s *dma = (struct dma_s *) ch->dma;
+
+    dma->enabled_count += level - ch->enable;
+
+    if (level)
+        dma->ch_enable_mask |= 1 << ch->num;
+    else
+        dma->ch_enable_mask &= ~(1 << ch->num);
+
+    if (level != ch->enable) {
+        soc_dma_ch_freq_update(dma);
+        ch->enable = level;
+
+        if (!ch->enable)
+            qemu_del_timer(ch->timer);
+        else if (!ch->running)
+            soc_dma_ch_run(ch);
+        else
+            soc_dma_ch_schedule(ch, 1);
+    }
+}
+
+void soc_dma_reset(struct soc_dma_s *soc)
+{
+    struct dma_s *s = (struct dma_s *) soc;
+
+    s->soc.drqbmp = 0;
+    s->ch_enable_mask = 0;
+    s->enabled_count = 0;
+    soc_dma_ch_freq_update(s);
+}
+
+/* TODO: take a functional-clock argument */
+struct soc_dma_s *soc_dma_init(int n)
+{
+    int i;
+    struct dma_s *s = g_malloc0(sizeof(*s) + n * sizeof(*s->ch));
+
+    s->chnum = n;
+    s->soc.ch = s->ch;
+    for (i = 0; i < n; i ++) {
+        s->ch[i].dma = &s->soc;
+        s->ch[i].num = i;
+        s->ch[i].timer = qemu_new_timer_ns(vm_clock, soc_dma_ch_run, &s->ch[i]);
+    }
+
+    soc_dma_reset(&s->soc);
+    fifo_size = 0;
+
+    return &s->soc;
+}
+
+void soc_dma_port_add_fifo(struct soc_dma_s *soc, hwaddr virt_base,
+                soc_dma_io_t fn, void *opaque, int out)
+{
+    struct memmap_entry_s *entry;
+    struct dma_s *dma = (struct dma_s *) soc;
+
+    dma->memmap = g_realloc(dma->memmap, sizeof(*entry) *
+                    (dma->memmap_size + 1));
+    entry = soc_dma_lookup(dma, virt_base);
+
+    if (dma->memmap_size) {
+        if (entry->type == soc_dma_port_mem) {
+            if (entry->addr <= virt_base &&
+                            entry->addr + entry->u.mem.size > virt_base) {
+                fprintf(stderr, "%s: FIFO at " TARGET_FMT_lx
+                                " collides with RAM region at " TARGET_FMT_lx
+                                "-" TARGET_FMT_lx "\n", __FUNCTION__,
+                                (target_ulong) virt_base,
+                                (target_ulong) entry->addr, (target_ulong)
+                                (entry->addr + entry->u.mem.size));
+                exit(-1);
+            }
+
+            if (entry->addr <= virt_base)
+                entry ++;
+        } else
+            while (entry < dma->memmap + dma->memmap_size &&
+                            entry->addr <= virt_base) {
+                if (entry->addr == virt_base && entry->u.fifo.out == out) {
+                    fprintf(stderr, "%s: FIFO at " TARGET_FMT_lx
+                                    " collides FIFO at " TARGET_FMT_lx "\n",
+                                    __FUNCTION__, (target_ulong) virt_base,
+                                    (target_ulong) entry->addr);
+                    exit(-1);
+                }
+
+                entry ++;
+            }
+
+        memmove(entry + 1, entry,
+                        (uint8_t *) (dma->memmap + dma->memmap_size ++) -
+                        (uint8_t *) entry);
+    } else
+        dma->memmap_size ++;
+
+    entry->addr          = virt_base;
+    entry->type          = soc_dma_port_fifo;
+    entry->u.fifo.fn     = fn;
+    entry->u.fifo.opaque = opaque;
+    entry->u.fifo.out    = out;
+}
+
+void soc_dma_port_add_mem(struct soc_dma_s *soc, uint8_t *phys_base,
+                hwaddr virt_base, size_t size)
+{
+    struct memmap_entry_s *entry;
+    struct dma_s *dma = (struct dma_s *) soc;
+
+    dma->memmap = g_realloc(dma->memmap, sizeof(*entry) *
+                    (dma->memmap_size + 1));
+    entry = soc_dma_lookup(dma, virt_base);
+
+    if (dma->memmap_size) {
+        if (entry->type == soc_dma_port_mem) {
+            if ((entry->addr >= virt_base && entry->addr < virt_base + size) ||
+                            (entry->addr <= virt_base &&
+                             entry->addr + entry->u.mem.size > virt_base)) {
+                fprintf(stderr, "%s: RAM at " TARGET_FMT_lx "-" TARGET_FMT_lx
+                                " collides with RAM region at " TARGET_FMT_lx
+                                "-" TARGET_FMT_lx "\n", __FUNCTION__,
+                                (target_ulong) virt_base,
+                                (target_ulong) (virt_base + size),
+                                (target_ulong) entry->addr, (target_ulong)
+                                (entry->addr + entry->u.mem.size));
+                exit(-1);
+            }
+
+            if (entry->addr <= virt_base)
+                entry ++;
+        } else {
+            if (entry->addr >= virt_base &&
+                            entry->addr < virt_base + size) {
+                fprintf(stderr, "%s: RAM at " TARGET_FMT_lx "-" TARGET_FMT_lx
+                                " collides with FIFO at " TARGET_FMT_lx
+                                "\n", __FUNCTION__,
+                                (target_ulong) virt_base,
+                                (target_ulong) (virt_base + size),
+                                (target_ulong) entry->addr);
+                exit(-1);
+            }
+
+            while (entry < dma->memmap + dma->memmap_size &&
+                            entry->addr <= virt_base)
+                entry ++;
+       }
+
+        memmove(entry + 1, entry,
+                        (uint8_t *) (dma->memmap + dma->memmap_size ++) -
+                        (uint8_t *) entry);
+    } else
+        dma->memmap_size ++;
+
+    entry->addr          = virt_base;
+    entry->type          = soc_dma_port_mem;
+    entry->u.mem.base    = phys_base;
+    entry->u.mem.size    = size;
+}
+
+/* TODO: port removal for ports like PCMCIA memory */
diff --git a/hw/dma/sparc32_dma.c b/hw/dma/sparc32_dma.c
new file mode 100644 (file)
index 0000000..fd21533
--- /dev/null
@@ -0,0 +1,315 @@
+/*
+ * QEMU Sparc32 DMA controller emulation
+ *
+ * Copyright (c) 2006 Fabrice Bellard
+ *
+ * Modifications:
+ *  2010-Feb-14 Artyom Tarasenko : reworked irq generation
+ *
+ * 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 "hw/hw.h"
+#include "hw/sparc/sparc32_dma.h"
+#include "hw/sparc/sun4m.h"
+#include "hw/sysbus.h"
+#include "trace.h"
+
+/*
+ * This is the DMA controller part of chip STP2000 (Master I/O), also
+ * produced as NCR89C100. See
+ * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C100.txt
+ * and
+ * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/DMA2.txt
+ */
+
+#define DMA_REGS 4
+#define DMA_SIZE (4 * sizeof(uint32_t))
+/* We need the mask, because one instance of the device is not page
+   aligned (ledma, start address 0x0010) */
+#define DMA_MASK (DMA_SIZE - 1)
+/* OBP says 0x20 bytes for ledma, the extras are aliased to espdma */
+#define DMA_ETH_SIZE (8 * sizeof(uint32_t))
+#define DMA_MAX_REG_OFFSET (2 * DMA_SIZE - 1)
+
+#define DMA_VER 0xa0000000
+#define DMA_INTR 1
+#define DMA_INTREN 0x10
+#define DMA_WRITE_MEM 0x100
+#define DMA_EN 0x200
+#define DMA_LOADED 0x04000000
+#define DMA_DRAIN_FIFO 0x40
+#define DMA_RESET 0x80
+
+/* XXX SCSI and ethernet should have different read-only bit masks */
+#define DMA_CSR_RO_MASK 0xfe000007
+
+typedef struct DMAState DMAState;
+
+struct DMAState {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    uint32_t dmaregs[DMA_REGS];
+    qemu_irq irq;
+    void *iommu;
+    qemu_irq gpio[2];
+    uint32_t is_ledma;
+};
+
+enum {
+    GPIO_RESET = 0,
+    GPIO_DMA,
+};
+
+/* Note: on sparc, the lance 16 bit bus is swapped */
+void ledma_memory_read(void *opaque, hwaddr addr,
+                       uint8_t *buf, int len, int do_bswap)
+{
+    DMAState *s = opaque;
+    int i;
+
+    addr |= s->dmaregs[3];
+    trace_ledma_memory_read(addr);
+    if (do_bswap) {
+        sparc_iommu_memory_read(s->iommu, addr, buf, len);
+    } else {
+        addr &= ~1;
+        len &= ~1;
+        sparc_iommu_memory_read(s->iommu, addr, buf, len);
+        for(i = 0; i < len; i += 2) {
+            bswap16s((uint16_t *)(buf + i));
+        }
+    }
+}
+
+void ledma_memory_write(void *opaque, hwaddr addr,
+                        uint8_t *buf, int len, int do_bswap)
+{
+    DMAState *s = opaque;
+    int l, i;
+    uint16_t tmp_buf[32];
+
+    addr |= s->dmaregs[3];
+    trace_ledma_memory_write(addr);
+    if (do_bswap) {
+        sparc_iommu_memory_write(s->iommu, addr, buf, len);
+    } else {
+        addr &= ~1;
+        len &= ~1;
+        while (len > 0) {
+            l = len;
+            if (l > sizeof(tmp_buf))
+                l = sizeof(tmp_buf);
+            for(i = 0; i < l; i += 2) {
+                tmp_buf[i >> 1] = bswap16(*(uint16_t *)(buf + i));
+            }
+            sparc_iommu_memory_write(s->iommu, addr, (uint8_t *)tmp_buf, l);
+            len -= l;
+            buf += l;
+            addr += l;
+        }
+    }
+}
+
+static void dma_set_irq(void *opaque, int irq, int level)
+{
+    DMAState *s = opaque;
+    if (level) {
+        s->dmaregs[0] |= DMA_INTR;
+        if (s->dmaregs[0] & DMA_INTREN) {
+            trace_sparc32_dma_set_irq_raise();
+            qemu_irq_raise(s->irq);
+        }
+    } else {
+        if (s->dmaregs[0] & DMA_INTR) {
+            s->dmaregs[0] &= ~DMA_INTR;
+            if (s->dmaregs[0] & DMA_INTREN) {
+                trace_sparc32_dma_set_irq_lower();
+                qemu_irq_lower(s->irq);
+            }
+        }
+    }
+}
+
+void espdma_memory_read(void *opaque, uint8_t *buf, int len)
+{
+    DMAState *s = opaque;
+
+    trace_espdma_memory_read(s->dmaregs[1]);
+    sparc_iommu_memory_read(s->iommu, s->dmaregs[1], buf, len);
+    s->dmaregs[1] += len;
+}
+
+void espdma_memory_write(void *opaque, uint8_t *buf, int len)
+{
+    DMAState *s = opaque;
+
+    trace_espdma_memory_write(s->dmaregs[1]);
+    sparc_iommu_memory_write(s->iommu, s->dmaregs[1], buf, len);
+    s->dmaregs[1] += len;
+}
+
+static uint64_t dma_mem_read(void *opaque, hwaddr addr,
+                             unsigned size)
+{
+    DMAState *s = opaque;
+    uint32_t saddr;
+
+    if (s->is_ledma && (addr > DMA_MAX_REG_OFFSET)) {
+        /* aliased to espdma, but we can't get there from here */
+        /* buggy driver if using undocumented behavior, just return 0 */
+        trace_sparc32_dma_mem_readl(addr, 0);
+        return 0;
+    }
+    saddr = (addr & DMA_MASK) >> 2;
+    trace_sparc32_dma_mem_readl(addr, s->dmaregs[saddr]);
+    return s->dmaregs[saddr];
+}
+
+static void dma_mem_write(void *opaque, hwaddr addr,
+                          uint64_t val, unsigned size)
+{
+    DMAState *s = opaque;
+    uint32_t saddr;
+
+    if (s->is_ledma && (addr > DMA_MAX_REG_OFFSET)) {
+        /* aliased to espdma, but we can't get there from here */
+        trace_sparc32_dma_mem_writel(addr, 0, val);
+        return;
+    }
+    saddr = (addr & DMA_MASK) >> 2;
+    trace_sparc32_dma_mem_writel(addr, s->dmaregs[saddr], val);
+    switch (saddr) {
+    case 0:
+        if (val & DMA_INTREN) {
+            if (s->dmaregs[0] & DMA_INTR) {
+                trace_sparc32_dma_set_irq_raise();
+                qemu_irq_raise(s->irq);
+            }
+        } else {
+            if (s->dmaregs[0] & (DMA_INTR | DMA_INTREN)) {
+                trace_sparc32_dma_set_irq_lower();
+                qemu_irq_lower(s->irq);
+            }
+        }
+        if (val & DMA_RESET) {
+            qemu_irq_raise(s->gpio[GPIO_RESET]);
+            qemu_irq_lower(s->gpio[GPIO_RESET]);
+        } else if (val & DMA_DRAIN_FIFO) {
+            val &= ~DMA_DRAIN_FIFO;
+        } else if (val == 0)
+            val = DMA_DRAIN_FIFO;
+
+        if (val & DMA_EN && !(s->dmaregs[0] & DMA_EN)) {
+            trace_sparc32_dma_enable_raise();
+            qemu_irq_raise(s->gpio[GPIO_DMA]);
+        } else if (!(val & DMA_EN) && !!(s->dmaregs[0] & DMA_EN)) {
+            trace_sparc32_dma_enable_lower();
+            qemu_irq_lower(s->gpio[GPIO_DMA]);
+        }
+
+        val &= ~DMA_CSR_RO_MASK;
+        val |= DMA_VER;
+        s->dmaregs[0] = (s->dmaregs[0] & DMA_CSR_RO_MASK) | val;
+        break;
+    case 1:
+        s->dmaregs[0] |= DMA_LOADED;
+        /* fall through */
+    default:
+        s->dmaregs[saddr] = val;
+        break;
+    }
+}
+
+static const MemoryRegionOps dma_mem_ops = {
+    .read = dma_mem_read,
+    .write = dma_mem_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static void dma_reset(DeviceState *d)
+{
+    DMAState *s = container_of(d, DMAState, busdev.qdev);
+
+    memset(s->dmaregs, 0, DMA_SIZE);
+    s->dmaregs[0] = DMA_VER;
+}
+
+static const VMStateDescription vmstate_dma = {
+    .name ="sparc32_dma",
+    .version_id = 2,
+    .minimum_version_id = 2,
+    .minimum_version_id_old = 2,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT32_ARRAY(dmaregs, DMAState, DMA_REGS),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int sparc32_dma_init1(SysBusDevice *dev)
+{
+    DMAState *s = FROM_SYSBUS(DMAState, dev);
+    int reg_size;
+
+    sysbus_init_irq(dev, &s->irq);
+
+    reg_size = s->is_ledma ? DMA_ETH_SIZE : DMA_SIZE;
+    memory_region_init_io(&s->iomem, &dma_mem_ops, s, "dma", reg_size);
+    sysbus_init_mmio(dev, &s->iomem);
+
+    qdev_init_gpio_in(&dev->qdev, dma_set_irq, 1);
+    qdev_init_gpio_out(&dev->qdev, s->gpio, 2);
+
+    return 0;
+}
+
+static Property sparc32_dma_properties[] = {
+    DEFINE_PROP_PTR("iommu_opaque", DMAState, iommu),
+    DEFINE_PROP_UINT32("is_ledma", DMAState, is_ledma, 0),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void sparc32_dma_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = sparc32_dma_init1;
+    dc->reset = dma_reset;
+    dc->vmsd = &vmstate_dma;
+    dc->props = sparc32_dma_properties;
+}
+
+static const 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_types(void)
+{
+    type_register_static(&sparc32_dma_info);
+}
+
+type_init(sparc32_dma_register_types)
diff --git a/hw/dma/sun4m_iommu.c b/hw/dma/sun4m_iommu.c
new file mode 100644 (file)
index 0000000..8312bff
--- /dev/null
@@ -0,0 +1,387 @@
+/*
+ * QEMU Sun4m iommu emulation
+ *
+ * Copyright (c) 2003-2005 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.
+ */
+
+#include "hw/sparc/sun4m.h"
+#include "hw/sysbus.h"
+#include "trace.h"
+
+/*
+ * I/O MMU used by Sun4m systems
+ *
+ * Chipset docs:
+ * "Sun-4M System Architecture (revision 2.0) by Chuck Narad", 950-1373-01,
+ * http://mediacast.sun.com/users/Barton808/media/Sun4M_SystemArchitecture_edited2.pdf
+ */
+
+#define IOMMU_NREGS         (4*4096/4)
+#define IOMMU_CTRL          (0x0000 >> 2)
+#define IOMMU_CTRL_IMPL     0xf0000000 /* Implementation */
+#define IOMMU_CTRL_VERS     0x0f000000 /* Version */
+#define IOMMU_CTRL_RNGE     0x0000001c /* Mapping RANGE */
+#define IOMMU_RNGE_16MB     0x00000000 /* 0xff000000 -> 0xffffffff */
+#define IOMMU_RNGE_32MB     0x00000004 /* 0xfe000000 -> 0xffffffff */
+#define IOMMU_RNGE_64MB     0x00000008 /* 0xfc000000 -> 0xffffffff */
+#define IOMMU_RNGE_128MB    0x0000000c /* 0xf8000000 -> 0xffffffff */
+#define IOMMU_RNGE_256MB    0x00000010 /* 0xf0000000 -> 0xffffffff */
+#define IOMMU_RNGE_512MB    0x00000014 /* 0xe0000000 -> 0xffffffff */
+#define IOMMU_RNGE_1GB      0x00000018 /* 0xc0000000 -> 0xffffffff */
+#define IOMMU_RNGE_2GB      0x0000001c /* 0x80000000 -> 0xffffffff */
+#define IOMMU_CTRL_ENAB     0x00000001 /* IOMMU Enable */
+#define IOMMU_CTRL_MASK     0x0000001d
+
+#define IOMMU_BASE          (0x0004 >> 2)
+#define IOMMU_BASE_MASK     0x07fffc00
+
+#define IOMMU_TLBFLUSH      (0x0014 >> 2)
+#define IOMMU_TLBFLUSH_MASK 0xffffffff
+
+#define IOMMU_PGFLUSH       (0x0018 >> 2)
+#define IOMMU_PGFLUSH_MASK  0xffffffff
+
+#define IOMMU_AFSR          (0x1000 >> 2)
+#define IOMMU_AFSR_ERR      0x80000000 /* LE, TO, or BE asserted */
+#define IOMMU_AFSR_LE       0x40000000 /* SBUS reports error after
+                                          transaction */
+#define IOMMU_AFSR_TO       0x20000000 /* Write access took more than
+                                          12.8 us. */
+#define IOMMU_AFSR_BE       0x10000000 /* Write access received error
+                                          acknowledge */
+#define IOMMU_AFSR_SIZE     0x0e000000 /* Size of transaction causing error */
+#define IOMMU_AFSR_S        0x01000000 /* Sparc was in supervisor mode */
+#define IOMMU_AFSR_RESV     0x00800000 /* Reserved, forced to 0x8 by
+                                          hardware */
+#define IOMMU_AFSR_ME       0x00080000 /* Multiple errors occurred */
+#define IOMMU_AFSR_RD       0x00040000 /* A read operation was in progress */
+#define IOMMU_AFSR_FAV      0x00020000 /* IOMMU afar has valid contents */
+#define IOMMU_AFSR_MASK     0xff0fffff
+
+#define IOMMU_AFAR          (0x1004 >> 2)
+
+#define IOMMU_AER           (0x1008 >> 2) /* Arbiter Enable Register */
+#define IOMMU_AER_EN_P0_ARB 0x00000001    /* MBus master 0x8 (Always 1) */
+#define IOMMU_AER_EN_P1_ARB 0x00000002    /* MBus master 0x9 */
+#define IOMMU_AER_EN_P2_ARB 0x00000004    /* MBus master 0xa */
+#define IOMMU_AER_EN_P3_ARB 0x00000008    /* MBus master 0xb */
+#define IOMMU_AER_EN_0      0x00010000    /* SBus slot 0 */
+#define IOMMU_AER_EN_1      0x00020000    /* SBus slot 1 */
+#define IOMMU_AER_EN_2      0x00040000    /* SBus slot 2 */
+#define IOMMU_AER_EN_3      0x00080000    /* SBus slot 3 */
+#define IOMMU_AER_EN_F      0x00100000    /* SBus on-board */
+#define IOMMU_AER_SBW       0x80000000    /* S-to-M asynchronous writes */
+#define IOMMU_AER_MASK      0x801f000f
+
+#define IOMMU_SBCFG0        (0x1010 >> 2) /* SBUS configration per-slot */
+#define IOMMU_SBCFG1        (0x1014 >> 2) /* SBUS configration per-slot */
+#define IOMMU_SBCFG2        (0x1018 >> 2) /* SBUS configration per-slot */
+#define IOMMU_SBCFG3        (0x101c >> 2) /* SBUS configration per-slot */
+#define IOMMU_SBCFG_SAB30   0x00010000 /* Phys-address bit 30 when
+                                          bypass enabled */
+#define IOMMU_SBCFG_BA16    0x00000004 /* Slave supports 16 byte bursts */
+#define IOMMU_SBCFG_BA8     0x00000002 /* Slave supports 8 byte bursts */
+#define IOMMU_SBCFG_BYPASS  0x00000001 /* Bypass IOMMU, treat all addresses
+                                          produced by this device as pure
+                                          physical. */
+#define IOMMU_SBCFG_MASK    0x00010003
+
+#define IOMMU_ARBEN         (0x2000 >> 2) /* SBUS arbitration enable */
+#define IOMMU_ARBEN_MASK    0x001f0000
+#define IOMMU_MID           0x00000008
+
+#define IOMMU_MASK_ID       (0x3018 >> 2) /* Mask ID */
+#define IOMMU_MASK_ID_MASK  0x00ffffff
+
+#define IOMMU_MSII_MASK     0x26000000 /* microSPARC II mask number */
+#define IOMMU_TS_MASK       0x23000000 /* turboSPARC mask number */
+
+/* The format of an iopte in the page tables */
+#define IOPTE_PAGE          0xffffff00 /* Physical page number (PA[35:12]) */
+#define IOPTE_CACHE         0x00000080 /* Cached (in vme IOCACHE or
+                                          Viking/MXCC) */
+#define IOPTE_WRITE         0x00000004 /* Writable */
+#define IOPTE_VALID         0x00000002 /* IOPTE is valid */
+#define IOPTE_WAZ           0x00000001 /* Write as zeros */
+
+#define IOMMU_PAGE_SHIFT    12
+#define IOMMU_PAGE_SIZE     (1 << IOMMU_PAGE_SHIFT)
+#define IOMMU_PAGE_MASK     ~(IOMMU_PAGE_SIZE - 1)
+
+typedef struct IOMMUState {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    uint32_t regs[IOMMU_NREGS];
+    hwaddr iostart;
+    qemu_irq irq;
+    uint32_t version;
+} IOMMUState;
+
+static uint64_t iommu_mem_read(void *opaque, hwaddr addr,
+                               unsigned size)
+{
+    IOMMUState *s = opaque;
+    hwaddr saddr;
+    uint32_t ret;
+
+    saddr = addr >> 2;
+    switch (saddr) {
+    default:
+        ret = s->regs[saddr];
+        break;
+    case IOMMU_AFAR:
+    case IOMMU_AFSR:
+        ret = s->regs[saddr];
+        qemu_irq_lower(s->irq);
+        break;
+    }
+    trace_sun4m_iommu_mem_readl(saddr, ret);
+    return ret;
+}
+
+static void iommu_mem_write(void *opaque, hwaddr addr,
+                            uint64_t val, unsigned size)
+{
+    IOMMUState *s = opaque;
+    hwaddr saddr;
+
+    saddr = addr >> 2;
+    trace_sun4m_iommu_mem_writel(saddr, val);
+    switch (saddr) {
+    case IOMMU_CTRL:
+        switch (val & IOMMU_CTRL_RNGE) {
+        case IOMMU_RNGE_16MB:
+            s->iostart = 0xffffffffff000000ULL;
+            break;
+        case IOMMU_RNGE_32MB:
+            s->iostart = 0xfffffffffe000000ULL;
+            break;
+        case IOMMU_RNGE_64MB:
+            s->iostart = 0xfffffffffc000000ULL;
+            break;
+        case IOMMU_RNGE_128MB:
+            s->iostart = 0xfffffffff8000000ULL;
+            break;
+        case IOMMU_RNGE_256MB:
+            s->iostart = 0xfffffffff0000000ULL;
+            break;
+        case IOMMU_RNGE_512MB:
+            s->iostart = 0xffffffffe0000000ULL;
+            break;
+        case IOMMU_RNGE_1GB:
+            s->iostart = 0xffffffffc0000000ULL;
+            break;
+        default:
+        case IOMMU_RNGE_2GB:
+            s->iostart = 0xffffffff80000000ULL;
+            break;
+        }
+        trace_sun4m_iommu_mem_writel_ctrl(s->iostart);
+        s->regs[saddr] = ((val & IOMMU_CTRL_MASK) | s->version);
+        break;
+    case IOMMU_BASE:
+        s->regs[saddr] = val & IOMMU_BASE_MASK;
+        break;
+    case IOMMU_TLBFLUSH:
+        trace_sun4m_iommu_mem_writel_tlbflush(val);
+        s->regs[saddr] = val & IOMMU_TLBFLUSH_MASK;
+        break;
+    case IOMMU_PGFLUSH:
+        trace_sun4m_iommu_mem_writel_pgflush(val);
+        s->regs[saddr] = val & IOMMU_PGFLUSH_MASK;
+        break;
+    case IOMMU_AFAR:
+        s->regs[saddr] = val;
+        qemu_irq_lower(s->irq);
+        break;
+    case IOMMU_AER:
+        s->regs[saddr] = (val & IOMMU_AER_MASK) | IOMMU_AER_EN_P0_ARB;
+        break;
+    case IOMMU_AFSR:
+        s->regs[saddr] = (val & IOMMU_AFSR_MASK) | IOMMU_AFSR_RESV;
+        qemu_irq_lower(s->irq);
+        break;
+    case IOMMU_SBCFG0:
+    case IOMMU_SBCFG1:
+    case IOMMU_SBCFG2:
+    case IOMMU_SBCFG3:
+        s->regs[saddr] = val & IOMMU_SBCFG_MASK;
+        break;
+    case IOMMU_ARBEN:
+        // XXX implement SBus probing: fault when reading unmapped
+        // addresses, fault cause and address stored to MMU/IOMMU
+        s->regs[saddr] = (val & IOMMU_ARBEN_MASK) | IOMMU_MID;
+        break;
+    case IOMMU_MASK_ID:
+        s->regs[saddr] |= val & IOMMU_MASK_ID_MASK;
+        break;
+    default:
+        s->regs[saddr] = val;
+        break;
+    }
+}
+
+static const MemoryRegionOps iommu_mem_ops = {
+    .read = iommu_mem_read,
+    .write = iommu_mem_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static uint32_t iommu_page_get_flags(IOMMUState *s, hwaddr addr)
+{
+    uint32_t ret;
+    hwaddr iopte;
+    hwaddr pa = addr;
+
+    iopte = s->regs[IOMMU_BASE] << 4;
+    addr &= ~s->iostart;
+    iopte += (addr >> (IOMMU_PAGE_SHIFT - 2)) & ~3;
+    ret = ldl_be_phys(iopte);
+    trace_sun4m_iommu_page_get_flags(pa, iopte, ret);
+    return ret;
+}
+
+static hwaddr iommu_translate_pa(hwaddr addr,
+                                             uint32_t pte)
+{
+    hwaddr pa;
+
+    pa = ((pte & IOPTE_PAGE) << 4) + (addr & ~IOMMU_PAGE_MASK);
+    trace_sun4m_iommu_translate_pa(addr, pa, pte);
+    return pa;
+}
+
+static void iommu_bad_addr(IOMMUState *s, hwaddr addr,
+                           int is_write)
+{
+    trace_sun4m_iommu_bad_addr(addr);
+    s->regs[IOMMU_AFSR] = IOMMU_AFSR_ERR | IOMMU_AFSR_LE | IOMMU_AFSR_RESV |
+        IOMMU_AFSR_FAV;
+    if (!is_write)
+        s->regs[IOMMU_AFSR] |= IOMMU_AFSR_RD;
+    s->regs[IOMMU_AFAR] = addr;
+    qemu_irq_raise(s->irq);
+}
+
+void sparc_iommu_memory_rw(void *opaque, hwaddr addr,
+                           uint8_t *buf, int len, int is_write)
+{
+    int l;
+    uint32_t flags;
+    hwaddr page, phys_addr;
+
+    while (len > 0) {
+        page = addr & IOMMU_PAGE_MASK;
+        l = (page + IOMMU_PAGE_SIZE) - addr;
+        if (l > len)
+            l = len;
+        flags = iommu_page_get_flags(opaque, page);
+        if (!(flags & IOPTE_VALID)) {
+            iommu_bad_addr(opaque, page, is_write);
+            return;
+        }
+        phys_addr = iommu_translate_pa(addr, flags);
+        if (is_write) {
+            if (!(flags & IOPTE_WRITE)) {
+                iommu_bad_addr(opaque, page, is_write);
+                return;
+            }
+            cpu_physical_memory_write(phys_addr, buf, l);
+        } else {
+            cpu_physical_memory_read(phys_addr, buf, l);
+        }
+        len -= l;
+        buf += l;
+        addr += l;
+    }
+}
+
+static const VMStateDescription vmstate_iommu = {
+    .name ="iommu",
+    .version_id = 2,
+    .minimum_version_id = 2,
+    .minimum_version_id_old = 2,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT32_ARRAY(regs, IOMMUState, IOMMU_NREGS),
+        VMSTATE_UINT64(iostart, IOMMUState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void iommu_reset(DeviceState *d)
+{
+    IOMMUState *s = container_of(d, IOMMUState, busdev.qdev);
+
+    memset(s->regs, 0, IOMMU_NREGS * 4);
+    s->iostart = 0;
+    s->regs[IOMMU_CTRL] = s->version;
+    s->regs[IOMMU_ARBEN] = IOMMU_MID;
+    s->regs[IOMMU_AFSR] = IOMMU_AFSR_RESV;
+    s->regs[IOMMU_AER] = IOMMU_AER_EN_P0_ARB | IOMMU_AER_EN_P1_ARB;
+    s->regs[IOMMU_MASK_ID] = IOMMU_TS_MASK;
+}
+
+static int iommu_init1(SysBusDevice *dev)
+{
+    IOMMUState *s = FROM_SYSBUS(IOMMUState, dev);
+
+    sysbus_init_irq(dev, &s->irq);
+
+    memory_region_init_io(&s->iomem, &iommu_mem_ops, s, "iommu",
+                          IOMMU_NREGS * sizeof(uint32_t));
+    sysbus_init_mmio(dev, &s->iomem);
+
+    return 0;
+}
+
+static Property iommu_properties[] = {
+    DEFINE_PROP_HEX32("version", IOMMUState, version, 0),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void iommu_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = iommu_init1;
+    dc->reset = iommu_reset;
+    dc->vmsd = &vmstate_iommu;
+    dc->props = iommu_properties;
+}
+
+static const TypeInfo iommu_info = {
+    .name          = "iommu",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(IOMMUState),
+    .class_init    = iommu_class_init,
+};
+
+static void iommu_register_types(void)
+{
+    type_register_static(&iommu_info);
+}
+
+type_init(iommu_register_types)
diff --git a/hw/dma/xilinx_axidma.c b/hw/dma/xilinx_axidma.c
new file mode 100644 (file)
index 0000000..8db1a74
--- /dev/null
@@ -0,0 +1,523 @@
+/*
+ * QEMU model of Xilinx AXI-DMA block.
+ *
+ * Copyright (c) 2011 Edgar E. Iglesias.
+ *
+ * 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 "hw/sysbus.h"
+#include "qemu/timer.h"
+#include "hw/ptimer.h"
+#include "qemu/log.h"
+#include "hw/qdev-addr.h"
+
+#include "hw/stream.h"
+
+#define D(x)
+
+#define R_DMACR             (0x00 / 4)
+#define R_DMASR             (0x04 / 4)
+#define R_CURDESC           (0x08 / 4)
+#define R_TAILDESC          (0x10 / 4)
+#define R_MAX               (0x30 / 4)
+
+enum {
+    DMACR_RUNSTOP = 1,
+    DMACR_TAILPTR_MODE = 2,
+    DMACR_RESET = 4
+};
+
+enum {
+    DMASR_HALTED = 1,
+    DMASR_IDLE  = 2,
+    DMASR_IOC_IRQ  = 1 << 12,
+    DMASR_DLY_IRQ  = 1 << 13,
+
+    DMASR_IRQ_MASK = 7 << 12
+};
+
+struct SDesc {
+    uint64_t nxtdesc;
+    uint64_t buffer_address;
+    uint64_t reserved;
+    uint32_t control;
+    uint32_t status;
+    uint32_t app[6];
+};
+
+enum {
+    SDESC_CTRL_EOF = (1 << 26),
+    SDESC_CTRL_SOF = (1 << 27),
+
+    SDESC_CTRL_LEN_MASK = (1 << 23) - 1
+};
+
+enum {
+    SDESC_STATUS_EOF = (1 << 26),
+    SDESC_STATUS_SOF_BIT = 27,
+    SDESC_STATUS_SOF = (1 << SDESC_STATUS_SOF_BIT),
+    SDESC_STATUS_COMPLETE = (1 << 31)
+};
+
+struct Stream {
+    QEMUBH *bh;
+    ptimer_state *ptimer;
+    qemu_irq irq;
+
+    int nr;
+
+    struct SDesc desc;
+    int pos;
+    unsigned int complete_cnt;
+    uint32_t regs[R_MAX];
+};
+
+struct XilinxAXIDMA {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    uint32_t freqhz;
+    StreamSlave *tx_dev;
+
+    struct Stream streams[2];
+};
+
+/*
+ * Helper calls to extract info from desriptors and other trivial
+ * state from regs.
+ */
+static inline int stream_desc_sof(struct SDesc *d)
+{
+    return d->control & SDESC_CTRL_SOF;
+}
+
+static inline int stream_desc_eof(struct SDesc *d)
+{
+    return d->control & SDESC_CTRL_EOF;
+}
+
+static inline int stream_resetting(struct Stream *s)
+{
+    return !!(s->regs[R_DMACR] & DMACR_RESET);
+}
+
+static inline int stream_running(struct Stream *s)
+{
+    return s->regs[R_DMACR] & DMACR_RUNSTOP;
+}
+
+static inline int stream_halted(struct Stream *s)
+{
+    return s->regs[R_DMASR] & DMASR_HALTED;
+}
+
+static inline int stream_idle(struct Stream *s)
+{
+    return !!(s->regs[R_DMASR] & DMASR_IDLE);
+}
+
+static void stream_reset(struct Stream *s)
+{
+    s->regs[R_DMASR] = DMASR_HALTED;  /* starts up halted.  */
+    s->regs[R_DMACR] = 1 << 16; /* Starts with one in compl threshold.  */
+}
+
+/* Map an offset addr into a channel index.  */
+static inline int streamid_from_addr(hwaddr addr)
+{
+    int sid;
+
+    sid = addr / (0x30);
+    sid &= 1;
+    return sid;
+}
+
+#ifdef DEBUG_ENET
+static void stream_desc_show(struct SDesc *d)
+{
+    qemu_log("buffer_addr  = " PRIx64 "\n", d->buffer_address);
+    qemu_log("nxtdesc      = " PRIx64 "\n", d->nxtdesc);
+    qemu_log("control      = %x\n", d->control);
+    qemu_log("status       = %x\n", d->status);
+}
+#endif
+
+static void stream_desc_load(struct Stream *s, hwaddr addr)
+{
+    struct SDesc *d = &s->desc;
+    int i;
+
+    cpu_physical_memory_read(addr, (void *) d, sizeof *d);
+
+    /* Convert from LE into host endianness.  */
+    d->buffer_address = le64_to_cpu(d->buffer_address);
+    d->nxtdesc = le64_to_cpu(d->nxtdesc);
+    d->control = le32_to_cpu(d->control);
+    d->status = le32_to_cpu(d->status);
+    for (i = 0; i < ARRAY_SIZE(d->app); i++) {
+        d->app[i] = le32_to_cpu(d->app[i]);
+    }
+}
+
+static void stream_desc_store(struct Stream *s, hwaddr addr)
+{
+    struct SDesc *d = &s->desc;
+    int i;
+
+    /* Convert from host endianness into LE.  */
+    d->buffer_address = cpu_to_le64(d->buffer_address);
+    d->nxtdesc = cpu_to_le64(d->nxtdesc);
+    d->control = cpu_to_le32(d->control);
+    d->status = cpu_to_le32(d->status);
+    for (i = 0; i < ARRAY_SIZE(d->app); i++) {
+        d->app[i] = cpu_to_le32(d->app[i]);
+    }
+    cpu_physical_memory_write(addr, (void *) d, sizeof *d);
+}
+
+static void stream_update_irq(struct Stream *s)
+{
+    unsigned int pending, mask, irq;
+
+    pending = s->regs[R_DMASR] & DMASR_IRQ_MASK;
+    mask = s->regs[R_DMACR] & DMASR_IRQ_MASK;
+
+    irq = pending & mask;
+
+    qemu_set_irq(s->irq, !!irq);
+}
+
+static void stream_reload_complete_cnt(struct Stream *s)
+{
+    unsigned int comp_th;
+    comp_th = (s->regs[R_DMACR] >> 16) & 0xff;
+    s->complete_cnt = comp_th;
+}
+
+static void timer_hit(void *opaque)
+{
+    struct Stream *s = opaque;
+
+    stream_reload_complete_cnt(s);
+    s->regs[R_DMASR] |= DMASR_DLY_IRQ;
+    stream_update_irq(s);
+}
+
+static void stream_complete(struct Stream *s)
+{
+    unsigned int comp_delay;
+
+    /* Start the delayed timer.  */
+    comp_delay = s->regs[R_DMACR] >> 24;
+    if (comp_delay) {
+        ptimer_stop(s->ptimer);
+        ptimer_set_count(s->ptimer, comp_delay);
+        ptimer_run(s->ptimer, 1);
+    }
+
+    s->complete_cnt--;
+    if (s->complete_cnt == 0) {
+        /* Raise the IOC irq.  */
+        s->regs[R_DMASR] |= DMASR_IOC_IRQ;
+        stream_reload_complete_cnt(s);
+    }
+}
+
+static void stream_process_mem2s(struct Stream *s,
+                                 StreamSlave *tx_dev)
+{
+    uint32_t prev_d;
+    unsigned char txbuf[16 * 1024];
+    unsigned int txlen;
+    uint32_t app[6];
+
+    if (!stream_running(s) || stream_idle(s)) {
+        return;
+    }
+
+    while (1) {
+        stream_desc_load(s, s->regs[R_CURDESC]);
+
+        if (s->desc.status & SDESC_STATUS_COMPLETE) {
+            s->regs[R_DMASR] |= DMASR_IDLE;
+            break;
+        }
+
+        if (stream_desc_sof(&s->desc)) {
+            s->pos = 0;
+            memcpy(app, s->desc.app, sizeof app);
+        }
+
+        txlen = s->desc.control & SDESC_CTRL_LEN_MASK;
+        if ((txlen + s->pos) > sizeof txbuf) {
+            hw_error("%s: too small internal txbuf! %d\n", __func__,
+                     txlen + s->pos);
+        }
+
+        cpu_physical_memory_read(s->desc.buffer_address,
+                                 txbuf + s->pos, txlen);
+        s->pos += txlen;
+
+        if (stream_desc_eof(&s->desc)) {
+            stream_push(tx_dev, txbuf, s->pos, app);
+            s->pos = 0;
+            stream_complete(s);
+        }
+
+        /* Update the descriptor.  */
+        s->desc.status = txlen | SDESC_STATUS_COMPLETE;
+        stream_desc_store(s, s->regs[R_CURDESC]);
+
+        /* Advance.  */
+        prev_d = s->regs[R_CURDESC];
+        s->regs[R_CURDESC] = s->desc.nxtdesc;
+        if (prev_d == s->regs[R_TAILDESC]) {
+            s->regs[R_DMASR] |= DMASR_IDLE;
+            break;
+        }
+    }
+}
+
+static void stream_process_s2mem(struct Stream *s,
+                                 unsigned char *buf, size_t len, uint32_t *app)
+{
+    uint32_t prev_d;
+    unsigned int rxlen;
+    int pos = 0;
+    int sof = 1;
+
+    if (!stream_running(s) || stream_idle(s)) {
+        return;
+    }
+
+    while (len) {
+        stream_desc_load(s, s->regs[R_CURDESC]);
+
+        if (s->desc.status & SDESC_STATUS_COMPLETE) {
+            s->regs[R_DMASR] |= DMASR_IDLE;
+            break;
+        }
+
+        rxlen = s->desc.control & SDESC_CTRL_LEN_MASK;
+        if (rxlen > len) {
+            /* It fits.  */
+            rxlen = len;
+        }
+
+        cpu_physical_memory_write(s->desc.buffer_address, buf + pos, rxlen);
+        len -= rxlen;
+        pos += rxlen;
+
+        /* Update the descriptor.  */
+        if (!len) {
+            int i;
+
+            stream_complete(s);
+            for (i = 0; i < 5; i++) {
+                s->desc.app[i] = app[i];
+            }
+            s->desc.status |= SDESC_STATUS_EOF;
+        }
+
+        s->desc.status |= sof << SDESC_STATUS_SOF_BIT;
+        s->desc.status |= SDESC_STATUS_COMPLETE;
+        stream_desc_store(s, s->regs[R_CURDESC]);
+        sof = 0;
+
+        /* Advance.  */
+        prev_d = s->regs[R_CURDESC];
+        s->regs[R_CURDESC] = s->desc.nxtdesc;
+        if (prev_d == s->regs[R_TAILDESC]) {
+            s->regs[R_DMASR] |= DMASR_IDLE;
+            break;
+        }
+    }
+}
+
+static void
+axidma_push(StreamSlave *obj, unsigned char *buf, size_t len, uint32_t *app)
+{
+    struct XilinxAXIDMA *d = FROM_SYSBUS(typeof(*d), SYS_BUS_DEVICE(obj));
+    struct Stream *s = &d->streams[1];
+
+    if (!app) {
+        hw_error("No stream app data!\n");
+    }
+    stream_process_s2mem(s, buf, len, app);
+    stream_update_irq(s);
+}
+
+static uint64_t axidma_read(void *opaque, hwaddr addr,
+                            unsigned size)
+{
+    struct XilinxAXIDMA *d = opaque;
+    struct Stream *s;
+    uint32_t r = 0;
+    int sid;
+
+    sid = streamid_from_addr(addr);
+    s = &d->streams[sid];
+
+    addr = addr % 0x30;
+    addr >>= 2;
+    switch (addr) {
+        case R_DMACR:
+            /* Simulate one cycles reset delay.  */
+            s->regs[addr] &= ~DMACR_RESET;
+            r = s->regs[addr];
+            break;
+        case R_DMASR:
+            s->regs[addr] &= 0xffff;
+            s->regs[addr] |= (s->complete_cnt & 0xff) << 16;
+            s->regs[addr] |= (ptimer_get_count(s->ptimer) & 0xff) << 24;
+            r = s->regs[addr];
+            break;
+        default:
+            r = s->regs[addr];
+            D(qemu_log("%s ch=%d addr=" TARGET_FMT_plx " v=%x\n",
+                           __func__, sid, addr * 4, r));
+            break;
+    }
+    return r;
+
+}
+
+static void axidma_write(void *opaque, hwaddr addr,
+                         uint64_t value, unsigned size)
+{
+    struct XilinxAXIDMA *d = opaque;
+    struct Stream *s;
+    int sid;
+
+    sid = streamid_from_addr(addr);
+    s = &d->streams[sid];
+
+    addr = addr % 0x30;
+    addr >>= 2;
+    switch (addr) {
+        case R_DMACR:
+            /* Tailptr mode is always on.  */
+            value |= DMACR_TAILPTR_MODE;
+            /* Remember our previous reset state.  */
+            value |= (s->regs[addr] & DMACR_RESET);
+            s->regs[addr] = value;
+
+            if (value & DMACR_RESET) {
+                stream_reset(s);
+            }
+
+            if ((value & 1) && !stream_resetting(s)) {
+                /* Start processing.  */
+                s->regs[R_DMASR] &= ~(DMASR_HALTED | DMASR_IDLE);
+            }
+            stream_reload_complete_cnt(s);
+            break;
+
+        case R_DMASR:
+            /* Mask away write to clear irq lines.  */
+            value &= ~(value & DMASR_IRQ_MASK);
+            s->regs[addr] = value;
+            break;
+
+        case R_TAILDESC:
+            s->regs[addr] = value;
+            s->regs[R_DMASR] &= ~DMASR_IDLE; /* Not idle.  */
+            if (!sid) {
+                stream_process_mem2s(s, d->tx_dev);
+            }
+            break;
+        default:
+            D(qemu_log("%s: ch=%d addr=" TARGET_FMT_plx " v=%x\n",
+                  __func__, sid, addr * 4, (unsigned)value));
+            s->regs[addr] = value;
+            break;
+    }
+    stream_update_irq(s);
+}
+
+static const MemoryRegionOps axidma_ops = {
+    .read = axidma_read,
+    .write = axidma_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int xilinx_axidma_init(SysBusDevice *dev)
+{
+    struct XilinxAXIDMA *s = FROM_SYSBUS(typeof(*s), dev);
+    int i;
+
+    sysbus_init_irq(dev, &s->streams[0].irq);
+    sysbus_init_irq(dev, &s->streams[1].irq);
+
+    memory_region_init_io(&s->iomem, &axidma_ops, s,
+                          "xlnx.axi-dma", R_MAX * 4 * 2);
+    sysbus_init_mmio(dev, &s->iomem);
+
+    for (i = 0; i < 2; i++) {
+        stream_reset(&s->streams[i]);
+        s->streams[i].nr = i;
+        s->streams[i].bh = qemu_bh_new(timer_hit, &s->streams[i]);
+        s->streams[i].ptimer = ptimer_init(s->streams[i].bh);
+        ptimer_set_freq(s->streams[i].ptimer, s->freqhz);
+    }
+    return 0;
+}
+
+static void xilinx_axidma_initfn(Object *obj)
+{
+    struct XilinxAXIDMA *s = FROM_SYSBUS(typeof(*s), SYS_BUS_DEVICE(obj));
+
+    object_property_add_link(obj, "axistream-connected", TYPE_STREAM_SLAVE,
+                             (Object **) &s->tx_dev, NULL);
+}
+
+static Property axidma_properties[] = {
+    DEFINE_PROP_UINT32("freqhz", struct XilinxAXIDMA, freqhz, 50000000),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void axidma_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+    StreamSlaveClass *ssc = STREAM_SLAVE_CLASS(klass);
+
+    k->init = xilinx_axidma_init;
+    dc->props = axidma_properties;
+    ssc->push = axidma_push;
+}
+
+static const TypeInfo axidma_info = {
+    .name          = "xlnx.axi-dma",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(struct XilinxAXIDMA),
+    .class_init    = axidma_class_init,
+    .instance_init = xilinx_axidma_initfn,
+    .interfaces = (InterfaceInfo[]) {
+        { TYPE_STREAM_SLAVE },
+        { }
+    }
+};
+
+static void xilinx_axidma_register_types(void)
+{
+    type_register_static(&axidma_info);
+}
+
+type_init(xilinx_axidma_register_types)
diff --git a/hw/dp8393x.c b/hw/dp8393x.c
deleted file mode 100644 (file)
index 8b5ca6a..0000000
+++ /dev/null
@@ -1,914 +0,0 @@
-/*
- * QEMU NS SONIC DP8393x netcard
- *
- * Copyright (c) 2008-2009 Herve Poussineau
- *
- * 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 "hw/hw.h"
-#include "qemu/timer.h"
-#include "net/net.h"
-#include "hw/mips.h"
-
-//#define DEBUG_SONIC
-
-/* Calculate CRCs properly on Rx packets */
-#define SONIC_CALCULATE_RXCRC
-
-#if defined(SONIC_CALCULATE_RXCRC)
-/* For crc32 */
-#include <zlib.h>
-#endif
-
-#ifdef DEBUG_SONIC
-#define DPRINTF(fmt, ...) \
-do { printf("sonic: " fmt , ##  __VA_ARGS__); } while (0)
-static const char* reg_names[] = {
-    "CR", "DCR", "RCR", "TCR", "IMR", "ISR", "UTDA", "CTDA",
-    "TPS", "TFC", "TSA0", "TSA1", "TFS", "URDA", "CRDA", "CRBA0",
-    "CRBA1", "RBWC0", "RBWC1", "EOBC", "URRA", "RSA", "REA", "RRP",
-    "RWP", "TRBA0", "TRBA1", "0x1b", "0x1c", "0x1d", "0x1e", "LLFA",
-    "TTDA", "CEP", "CAP2", "CAP1", "CAP0", "CE", "CDP", "CDC",
-    "SR", "WT0", "WT1", "RSC", "CRCT", "FAET", "MPT", "MDT",
-    "0x30", "0x31", "0x32", "0x33", "0x34", "0x35", "0x36", "0x37",
-    "0x38", "0x39", "0x3a", "0x3b", "0x3c", "0x3d", "0x3e", "DCR2" };
-#else
-#define DPRINTF(fmt, ...) do {} while (0)
-#endif
-
-#define SONIC_ERROR(fmt, ...) \
-do { printf("sonic ERROR: %s: " fmt, __func__ , ## __VA_ARGS__); } while (0)
-
-#define SONIC_CR     0x00
-#define SONIC_DCR    0x01
-#define SONIC_RCR    0x02
-#define SONIC_TCR    0x03
-#define SONIC_IMR    0x04
-#define SONIC_ISR    0x05
-#define SONIC_UTDA   0x06
-#define SONIC_CTDA   0x07
-#define SONIC_TPS    0x08
-#define SONIC_TFC    0x09
-#define SONIC_TSA0   0x0a
-#define SONIC_TSA1   0x0b
-#define SONIC_TFS    0x0c
-#define SONIC_URDA   0x0d
-#define SONIC_CRDA   0x0e
-#define SONIC_CRBA0  0x0f
-#define SONIC_CRBA1  0x10
-#define SONIC_RBWC0  0x11
-#define SONIC_RBWC1  0x12
-#define SONIC_EOBC   0x13
-#define SONIC_URRA   0x14
-#define SONIC_RSA    0x15
-#define SONIC_REA    0x16
-#define SONIC_RRP    0x17
-#define SONIC_RWP    0x18
-#define SONIC_TRBA0  0x19
-#define SONIC_TRBA1  0x1a
-#define SONIC_LLFA   0x1f
-#define SONIC_TTDA   0x20
-#define SONIC_CEP    0x21
-#define SONIC_CAP2   0x22
-#define SONIC_CAP1   0x23
-#define SONIC_CAP0   0x24
-#define SONIC_CE     0x25
-#define SONIC_CDP    0x26
-#define SONIC_CDC    0x27
-#define SONIC_SR     0x28
-#define SONIC_WT0    0x29
-#define SONIC_WT1    0x2a
-#define SONIC_RSC    0x2b
-#define SONIC_CRCT   0x2c
-#define SONIC_FAET   0x2d
-#define SONIC_MPT    0x2e
-#define SONIC_MDT    0x2f
-#define SONIC_DCR2   0x3f
-
-#define SONIC_CR_HTX     0x0001
-#define SONIC_CR_TXP     0x0002
-#define SONIC_CR_RXDIS   0x0004
-#define SONIC_CR_RXEN    0x0008
-#define SONIC_CR_STP     0x0010
-#define SONIC_CR_ST      0x0020
-#define SONIC_CR_RST     0x0080
-#define SONIC_CR_RRRA    0x0100
-#define SONIC_CR_LCAM    0x0200
-#define SONIC_CR_MASK    0x03bf
-
-#define SONIC_DCR_DW     0x0020
-#define SONIC_DCR_LBR    0x2000
-#define SONIC_DCR_EXBUS  0x8000
-
-#define SONIC_RCR_PRX    0x0001
-#define SONIC_RCR_LBK    0x0002
-#define SONIC_RCR_FAER   0x0004
-#define SONIC_RCR_CRCR   0x0008
-#define SONIC_RCR_CRS    0x0020
-#define SONIC_RCR_LPKT   0x0040
-#define SONIC_RCR_BC     0x0080
-#define SONIC_RCR_MC     0x0100
-#define SONIC_RCR_LB0    0x0200
-#define SONIC_RCR_LB1    0x0400
-#define SONIC_RCR_AMC    0x0800
-#define SONIC_RCR_PRO    0x1000
-#define SONIC_RCR_BRD    0x2000
-#define SONIC_RCR_RNT    0x4000
-
-#define SONIC_TCR_PTX    0x0001
-#define SONIC_TCR_BCM    0x0002
-#define SONIC_TCR_FU     0x0004
-#define SONIC_TCR_EXC    0x0040
-#define SONIC_TCR_CRSL   0x0080
-#define SONIC_TCR_NCRS   0x0100
-#define SONIC_TCR_EXD    0x0400
-#define SONIC_TCR_CRCI   0x2000
-#define SONIC_TCR_PINT   0x8000
-
-#define SONIC_ISR_RBE    0x0020
-#define SONIC_ISR_RDE    0x0040
-#define SONIC_ISR_TC     0x0080
-#define SONIC_ISR_TXDN   0x0200
-#define SONIC_ISR_PKTRX  0x0400
-#define SONIC_ISR_PINT   0x0800
-#define SONIC_ISR_LCD    0x1000
-
-typedef struct dp8393xState {
-    /* Hardware */
-    int it_shift;
-    qemu_irq irq;
-#ifdef DEBUG_SONIC
-    int irq_level;
-#endif
-    QEMUTimer *watchdog;
-    int64_t wt_last_update;
-    NICConf conf;
-    NICState *nic;
-    MemoryRegion *address_space;
-    MemoryRegion mmio;
-
-    /* Registers */
-    uint8_t cam[16][6];
-    uint16_t regs[0x40];
-
-    /* Temporaries */
-    uint8_t tx_buffer[0x10000];
-    int loopback_packet;
-
-    /* Memory access */
-    void (*memory_rw)(void *opaque, hwaddr addr, uint8_t *buf, int len, int is_write);
-    void* mem_opaque;
-} dp8393xState;
-
-static void dp8393x_update_irq(dp8393xState *s)
-{
-    int level = (s->regs[SONIC_IMR] & s->regs[SONIC_ISR]) ? 1 : 0;
-
-#ifdef DEBUG_SONIC
-    if (level != s->irq_level) {
-        s->irq_level = level;
-        if (level) {
-            DPRINTF("raise irq, isr is 0x%04x\n", s->regs[SONIC_ISR]);
-        } else {
-            DPRINTF("lower irq\n");
-        }
-    }
-#endif
-
-    qemu_set_irq(s->irq, level);
-}
-
-static void do_load_cam(dp8393xState *s)
-{
-    uint16_t data[8];
-    int width, size;
-    uint16_t index = 0;
-
-    width = (s->regs[SONIC_DCR] & SONIC_DCR_DW) ? 2 : 1;
-    size = sizeof(uint16_t) * 4 * width;
-
-    while (s->regs[SONIC_CDC] & 0x1f) {
-        /* Fill current entry */
-        s->memory_rw(s->mem_opaque,
-            (s->regs[SONIC_URRA] << 16) | s->regs[SONIC_CDP],
-            (uint8_t *)data, size, 0);
-        s->cam[index][0] = data[1 * width] & 0xff;
-        s->cam[index][1] = data[1 * width] >> 8;
-        s->cam[index][2] = data[2 * width] & 0xff;
-        s->cam[index][3] = data[2 * width] >> 8;
-        s->cam[index][4] = data[3 * width] & 0xff;
-        s->cam[index][5] = data[3 * width] >> 8;
-        DPRINTF("load cam[%d] with %02x%02x%02x%02x%02x%02x\n", index,
-            s->cam[index][0], s->cam[index][1], s->cam[index][2],
-            s->cam[index][3], s->cam[index][4], s->cam[index][5]);
-        /* Move to next entry */
-        s->regs[SONIC_CDC]--;
-        s->regs[SONIC_CDP] += size;
-        index++;
-    }
-
-    /* Read CAM enable */
-    s->memory_rw(s->mem_opaque,
-        (s->regs[SONIC_URRA] << 16) | s->regs[SONIC_CDP],
-        (uint8_t *)data, size, 0);
-    s->regs[SONIC_CE] = data[0 * width];
-    DPRINTF("load cam done. cam enable mask 0x%04x\n", s->regs[SONIC_CE]);
-
-    /* Done */
-    s->regs[SONIC_CR] &= ~SONIC_CR_LCAM;
-    s->regs[SONIC_ISR] |= SONIC_ISR_LCD;
-    dp8393x_update_irq(s);
-}
-
-static void do_read_rra(dp8393xState *s)
-{
-    uint16_t data[8];
-    int width, size;
-
-    /* Read memory */
-    width = (s->regs[SONIC_DCR] & SONIC_DCR_DW) ? 2 : 1;
-    size = sizeof(uint16_t) * 4 * width;
-    s->memory_rw(s->mem_opaque,
-        (s->regs[SONIC_URRA] << 16) | s->regs[SONIC_RRP],
-        (uint8_t *)data, size, 0);
-
-    /* Update SONIC registers */
-    s->regs[SONIC_CRBA0] = data[0 * width];
-    s->regs[SONIC_CRBA1] = data[1 * width];
-    s->regs[SONIC_RBWC0] = data[2 * width];
-    s->regs[SONIC_RBWC1] = data[3 * width];
-    DPRINTF("CRBA0/1: 0x%04x/0x%04x, RBWC0/1: 0x%04x/0x%04x\n",
-        s->regs[SONIC_CRBA0], s->regs[SONIC_CRBA1],
-        s->regs[SONIC_RBWC0], s->regs[SONIC_RBWC1]);
-
-    /* Go to next entry */
-    s->regs[SONIC_RRP] += size;
-
-    /* Handle wrap */
-    if (s->regs[SONIC_RRP] == s->regs[SONIC_REA]) {
-        s->regs[SONIC_RRP] = s->regs[SONIC_RSA];
-    }
-
-    /* Check resource exhaustion */
-    if (s->regs[SONIC_RRP] == s->regs[SONIC_RWP])
-    {
-        s->regs[SONIC_ISR] |= SONIC_ISR_RBE;
-        dp8393x_update_irq(s);
-    }
-
-    /* Done */
-    s->regs[SONIC_CR] &= ~SONIC_CR_RRRA;
-}
-
-static void do_software_reset(dp8393xState *s)
-{
-    qemu_del_timer(s->watchdog);
-
-    s->regs[SONIC_CR] &= ~(SONIC_CR_LCAM | SONIC_CR_RRRA | SONIC_CR_TXP | SONIC_CR_HTX);
-    s->regs[SONIC_CR] |= SONIC_CR_RST | SONIC_CR_RXDIS;
-}
-
-static void set_next_tick(dp8393xState *s)
-{
-    uint32_t ticks;
-    int64_t delay;
-
-    if (s->regs[SONIC_CR] & SONIC_CR_STP) {
-        qemu_del_timer(s->watchdog);
-        return;
-    }
-
-    ticks = s->regs[SONIC_WT1] << 16 | s->regs[SONIC_WT0];
-    s->wt_last_update = qemu_get_clock_ns(vm_clock);
-    delay = get_ticks_per_sec() * ticks / 5000000;
-    qemu_mod_timer(s->watchdog, s->wt_last_update + delay);
-}
-
-static void update_wt_regs(dp8393xState *s)
-{
-    int64_t elapsed;
-    uint32_t val;
-
-    if (s->regs[SONIC_CR] & SONIC_CR_STP) {
-        qemu_del_timer(s->watchdog);
-        return;
-    }
-
-    elapsed = s->wt_last_update - qemu_get_clock_ns(vm_clock);
-    val = s->regs[SONIC_WT1] << 16 | s->regs[SONIC_WT0];
-    val -= elapsed / 5000000;
-    s->regs[SONIC_WT1] = (val >> 16) & 0xffff;
-    s->regs[SONIC_WT0] = (val >> 0)  & 0xffff;
-    set_next_tick(s);
-
-}
-
-static void do_start_timer(dp8393xState *s)
-{
-    s->regs[SONIC_CR] &= ~SONIC_CR_STP;
-    set_next_tick(s);
-}
-
-static void do_stop_timer(dp8393xState *s)
-{
-    s->regs[SONIC_CR] &= ~SONIC_CR_ST;
-    update_wt_regs(s);
-}
-
-static void do_receiver_enable(dp8393xState *s)
-{
-    s->regs[SONIC_CR] &= ~SONIC_CR_RXDIS;
-}
-
-static void do_receiver_disable(dp8393xState *s)
-{
-    s->regs[SONIC_CR] &= ~SONIC_CR_RXEN;
-}
-
-static void do_transmit_packets(dp8393xState *s)
-{
-    NetClientState *nc = qemu_get_queue(s->nic);
-    uint16_t data[12];
-    int width, size;
-    int tx_len, len;
-    uint16_t i;
-
-    width = (s->regs[SONIC_DCR] & SONIC_DCR_DW) ? 2 : 1;
-
-    while (1) {
-        /* Read memory */
-        DPRINTF("Transmit packet at %08x\n",
-                (s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_CTDA]);
-        size = sizeof(uint16_t) * 6 * width;
-        s->regs[SONIC_TTDA] = s->regs[SONIC_CTDA];
-        s->memory_rw(s->mem_opaque,
-            ((s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_TTDA]) + sizeof(uint16_t) * width,
-            (uint8_t *)data, size, 0);
-        tx_len = 0;
-
-        /* Update registers */
-        s->regs[SONIC_TCR] = data[0 * width] & 0xf000;
-        s->regs[SONIC_TPS] = data[1 * width];
-        s->regs[SONIC_TFC] = data[2 * width];
-        s->regs[SONIC_TSA0] = data[3 * width];
-        s->regs[SONIC_TSA1] = data[4 * width];
-        s->regs[SONIC_TFS] = data[5 * width];
-
-        /* Handle programmable interrupt */
-        if (s->regs[SONIC_TCR] & SONIC_TCR_PINT) {
-            s->regs[SONIC_ISR] |= SONIC_ISR_PINT;
-        } else {
-            s->regs[SONIC_ISR] &= ~SONIC_ISR_PINT;
-        }
-
-        for (i = 0; i < s->regs[SONIC_TFC]; ) {
-            /* Append fragment */
-            len = s->regs[SONIC_TFS];
-            if (tx_len + len > sizeof(s->tx_buffer)) {
-                len = sizeof(s->tx_buffer) - tx_len;
-            }
-            s->memory_rw(s->mem_opaque,
-                (s->regs[SONIC_TSA1] << 16) | s->regs[SONIC_TSA0],
-                &s->tx_buffer[tx_len], len, 0);
-            tx_len += len;
-
-            i++;
-            if (i != s->regs[SONIC_TFC]) {
-                /* Read next fragment details */
-                size = sizeof(uint16_t) * 3 * width;
-                s->memory_rw(s->mem_opaque,
-                    ((s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_TTDA]) + sizeof(uint16_t) * (4 + 3 * i) * width,
-                    (uint8_t *)data, size, 0);
-                s->regs[SONIC_TSA0] = data[0 * width];
-                s->regs[SONIC_TSA1] = data[1 * width];
-                s->regs[SONIC_TFS] = data[2 * width];
-            }
-        }
-
-        /* Handle Ethernet checksum */
-        if (!(s->regs[SONIC_TCR] & SONIC_TCR_CRCI)) {
-            /* Don't append FCS there, to look like slirp packets
-             * which don't have one */
-        } else {
-            /* Remove existing FCS */
-            tx_len -= 4;
-        }
-
-        if (s->regs[SONIC_RCR] & (SONIC_RCR_LB1 | SONIC_RCR_LB0)) {
-            /* Loopback */
-            s->regs[SONIC_TCR] |= SONIC_TCR_CRSL;
-            if (nc->info->can_receive(nc)) {
-                s->loopback_packet = 1;
-                nc->info->receive(nc, s->tx_buffer, tx_len);
-            }
-        } else {
-            /* Transmit packet */
-            qemu_send_packet(nc, s->tx_buffer, tx_len);
-        }
-        s->regs[SONIC_TCR] |= SONIC_TCR_PTX;
-
-        /* Write status */
-        data[0 * width] = s->regs[SONIC_TCR] & 0x0fff; /* status */
-        size = sizeof(uint16_t) * width;
-        s->memory_rw(s->mem_opaque,
-            (s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_TTDA],
-            (uint8_t *)data, size, 1);
-
-        if (!(s->regs[SONIC_CR] & SONIC_CR_HTX)) {
-            /* Read footer of packet */
-            size = sizeof(uint16_t) * width;
-            s->memory_rw(s->mem_opaque,
-                ((s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_TTDA]) + sizeof(uint16_t) * (4 + 3 * s->regs[SONIC_TFC]) * width,
-                (uint8_t *)data, size, 0);
-            s->regs[SONIC_CTDA] = data[0 * width] & ~0x1;
-            if (data[0 * width] & 0x1) {
-                /* EOL detected */
-                break;
-            }
-        }
-    }
-
-    /* Done */
-    s->regs[SONIC_CR] &= ~SONIC_CR_TXP;
-    s->regs[SONIC_ISR] |= SONIC_ISR_TXDN;
-    dp8393x_update_irq(s);
-}
-
-static void do_halt_transmission(dp8393xState *s)
-{
-    /* Nothing to do */
-}
-
-static void do_command(dp8393xState *s, uint16_t command)
-{
-    if ((s->regs[SONIC_CR] & SONIC_CR_RST) && !(command & SONIC_CR_RST)) {
-        s->regs[SONIC_CR] &= ~SONIC_CR_RST;
-        return;
-    }
-
-    s->regs[SONIC_CR] |= (command & SONIC_CR_MASK);
-
-    if (command & SONIC_CR_HTX)
-        do_halt_transmission(s);
-    if (command & SONIC_CR_TXP)
-        do_transmit_packets(s);
-    if (command & SONIC_CR_RXDIS)
-        do_receiver_disable(s);
-    if (command & SONIC_CR_RXEN)
-        do_receiver_enable(s);
-    if (command & SONIC_CR_STP)
-        do_stop_timer(s);
-    if (command & SONIC_CR_ST)
-        do_start_timer(s);
-    if (command & SONIC_CR_RST)
-        do_software_reset(s);
-    if (command & SONIC_CR_RRRA)
-        do_read_rra(s);
-    if (command & SONIC_CR_LCAM)
-        do_load_cam(s);
-}
-
-static uint16_t read_register(dp8393xState *s, int reg)
-{
-    uint16_t val = 0;
-
-    switch (reg) {
-        /* Update data before reading it */
-        case SONIC_WT0:
-        case SONIC_WT1:
-            update_wt_regs(s);
-            val = s->regs[reg];
-            break;
-        /* Accept read to some registers only when in reset mode */
-        case SONIC_CAP2:
-        case SONIC_CAP1:
-        case SONIC_CAP0:
-            if (s->regs[SONIC_CR] & SONIC_CR_RST) {
-                val = s->cam[s->regs[SONIC_CEP] & 0xf][2* (SONIC_CAP0 - reg) + 1] << 8;
-                val |= s->cam[s->regs[SONIC_CEP] & 0xf][2* (SONIC_CAP0 - reg)];
-            }
-            break;
-        /* All other registers have no special contrainst */
-        default:
-            val = s->regs[reg];
-    }
-
-    DPRINTF("read 0x%04x from reg %s\n", val, reg_names[reg]);
-
-    return val;
-}
-
-static void write_register(dp8393xState *s, int reg, uint16_t val)
-{
-    DPRINTF("write 0x%04x to reg %s\n", val, reg_names[reg]);
-
-    switch (reg) {
-        /* Command register */
-        case SONIC_CR:
-            do_command(s, val);
-            break;
-        /* Prevent write to read-only registers */
-        case SONIC_CAP2:
-        case SONIC_CAP1:
-        case SONIC_CAP0:
-        case SONIC_SR:
-        case SONIC_MDT:
-            DPRINTF("writing to reg %d invalid\n", reg);
-            break;
-        /* Accept write to some registers only when in reset mode */
-        case SONIC_DCR:
-            if (s->regs[SONIC_CR] & SONIC_CR_RST) {
-                s->regs[reg] = val & 0xbfff;
-            } else {
-                DPRINTF("writing to DCR invalid\n");
-            }
-            break;
-        case SONIC_DCR2:
-            if (s->regs[SONIC_CR] & SONIC_CR_RST) {
-                s->regs[reg] = val & 0xf017;
-            } else {
-                DPRINTF("writing to DCR2 invalid\n");
-            }
-            break;
-        /* 12 lower bytes are Read Only */
-        case SONIC_TCR:
-            s->regs[reg] = val & 0xf000;
-            break;
-        /* 9 lower bytes are Read Only */
-        case SONIC_RCR:
-            s->regs[reg] = val & 0xffe0;
-            break;
-        /* Ignore most significant bit */
-        case SONIC_IMR:
-            s->regs[reg] = val & 0x7fff;
-            dp8393x_update_irq(s);
-            break;
-        /* Clear bits by writing 1 to them */
-        case SONIC_ISR:
-            val &= s->regs[reg];
-            s->regs[reg] &= ~val;
-            if (val & SONIC_ISR_RBE) {
-                do_read_rra(s);
-            }
-            dp8393x_update_irq(s);
-            break;
-        /* Ignore least significant bit */
-        case SONIC_RSA:
-        case SONIC_REA:
-        case SONIC_RRP:
-        case SONIC_RWP:
-            s->regs[reg] = val & 0xfffe;
-            break;
-        /* Invert written value for some registers */
-        case SONIC_CRCT:
-        case SONIC_FAET:
-        case SONIC_MPT:
-            s->regs[reg] = val ^ 0xffff;
-            break;
-        /* All other registers have no special contrainst */
-        default:
-            s->regs[reg] = val;
-    }
-
-    if (reg == SONIC_WT0 || reg == SONIC_WT1) {
-        set_next_tick(s);
-    }
-}
-
-static void dp8393x_watchdog(void *opaque)
-{
-    dp8393xState *s = opaque;
-
-    if (s->regs[SONIC_CR] & SONIC_CR_STP) {
-        return;
-    }
-
-    s->regs[SONIC_WT1] = 0xffff;
-    s->regs[SONIC_WT0] = 0xffff;
-    set_next_tick(s);
-
-    /* Signal underflow */
-    s->regs[SONIC_ISR] |= SONIC_ISR_TC;
-    dp8393x_update_irq(s);
-}
-
-static uint32_t dp8393x_readw(void *opaque, hwaddr addr)
-{
-    dp8393xState *s = opaque;
-    int reg;
-
-    if ((addr & ((1 << s->it_shift) - 1)) != 0) {
-        return 0;
-    }
-
-    reg = addr >> s->it_shift;
-    return read_register(s, reg);
-}
-
-static uint32_t dp8393x_readb(void *opaque, hwaddr addr)
-{
-    uint16_t v = dp8393x_readw(opaque, addr & ~0x1);
-    return (v >> (8 * (addr & 0x1))) & 0xff;
-}
-
-static uint32_t dp8393x_readl(void *opaque, hwaddr addr)
-{
-    uint32_t v;
-    v = dp8393x_readw(opaque, addr);
-    v |= dp8393x_readw(opaque, addr + 2) << 16;
-    return v;
-}
-
-static void dp8393x_writew(void *opaque, hwaddr addr, uint32_t val)
-{
-    dp8393xState *s = opaque;
-    int reg;
-
-    if ((addr & ((1 << s->it_shift) - 1)) != 0) {
-        return;
-    }
-
-    reg = addr >> s->it_shift;
-
-    write_register(s, reg, (uint16_t)val);
-}
-
-static void dp8393x_writeb(void *opaque, hwaddr addr, uint32_t val)
-{
-    uint16_t old_val = dp8393x_readw(opaque, addr & ~0x1);
-
-    switch (addr & 3) {
-    case 0:
-        val = val | (old_val & 0xff00);
-        break;
-    case 1:
-        val = (val << 8) | (old_val & 0x00ff);
-        break;
-    }
-    dp8393x_writew(opaque, addr & ~0x1, val);
-}
-
-static void dp8393x_writel(void *opaque, hwaddr addr, uint32_t val)
-{
-    dp8393x_writew(opaque, addr, val & 0xffff);
-    dp8393x_writew(opaque, addr + 2, (val >> 16) & 0xffff);
-}
-
-static const MemoryRegionOps dp8393x_ops = {
-    .old_mmio = {
-        .read = { dp8393x_readb, dp8393x_readw, dp8393x_readl, },
-        .write = { dp8393x_writeb, dp8393x_writew, dp8393x_writel, },
-    },
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int nic_can_receive(NetClientState *nc)
-{
-    dp8393xState *s = qemu_get_nic_opaque(nc);
-
-    if (!(s->regs[SONIC_CR] & SONIC_CR_RXEN))
-        return 0;
-    if (s->regs[SONIC_ISR] & SONIC_ISR_RBE)
-        return 0;
-    return 1;
-}
-
-static int receive_filter(dp8393xState *s, const uint8_t * buf, int size)
-{
-    static const uint8_t bcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
-    int i;
-
-    /* Check for runt packet (remember that checksum is not there) */
-    if (size < 64 - 4) {
-        return (s->regs[SONIC_RCR] & SONIC_RCR_RNT) ? 0 : -1;
-    }
-
-    /* Check promiscuous mode */
-    if ((s->regs[SONIC_RCR] & SONIC_RCR_PRO) && (buf[0] & 1) == 0) {
-        return 0;
-    }
-
-    /* Check multicast packets */
-    if ((s->regs[SONIC_RCR] & SONIC_RCR_AMC) && (buf[0] & 1) == 1) {
-        return SONIC_RCR_MC;
-    }
-
-    /* Check broadcast */
-    if ((s->regs[SONIC_RCR] & SONIC_RCR_BRD) && !memcmp(buf, bcast, sizeof(bcast))) {
-        return SONIC_RCR_BC;
-    }
-
-    /* Check CAM */
-    for (i = 0; i < 16; i++) {
-        if (s->regs[SONIC_CE] & (1 << i)) {
-             /* Entry enabled */
-             if (!memcmp(buf, s->cam[i], sizeof(s->cam[i]))) {
-                 return 0;
-             }
-        }
-    }
-
-    return -1;
-}
-
-static ssize_t nic_receive(NetClientState *nc, const uint8_t * buf, size_t size)
-{
-    dp8393xState *s = qemu_get_nic_opaque(nc);
-    uint16_t data[10];
-    int packet_type;
-    uint32_t available, address;
-    int width, rx_len = size;
-    uint32_t checksum;
-
-    width = (s->regs[SONIC_DCR] & SONIC_DCR_DW) ? 2 : 1;
-
-    s->regs[SONIC_RCR] &= ~(SONIC_RCR_PRX | SONIC_RCR_LBK | SONIC_RCR_FAER |
-        SONIC_RCR_CRCR | SONIC_RCR_LPKT | SONIC_RCR_BC | SONIC_RCR_MC);
-
-    packet_type = receive_filter(s, buf, size);
-    if (packet_type < 0) {
-        DPRINTF("packet not for netcard\n");
-        return -1;
-    }
-
-    /* XXX: Check byte ordering */
-
-    /* Check for EOL */
-    if (s->regs[SONIC_LLFA] & 0x1) {
-        /* Are we still in resource exhaustion? */
-        size = sizeof(uint16_t) * 1 * width;
-        address = ((s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA]) + sizeof(uint16_t) * 5 * width;
-        s->memory_rw(s->mem_opaque, address, (uint8_t*)data, size, 0);
-        if (data[0 * width] & 0x1) {
-            /* Still EOL ; stop reception */
-            return -1;
-        } else {
-            s->regs[SONIC_CRDA] = s->regs[SONIC_LLFA];
-        }
-    }
-
-    /* Save current position */
-    s->regs[SONIC_TRBA1] = s->regs[SONIC_CRBA1];
-    s->regs[SONIC_TRBA0] = s->regs[SONIC_CRBA0];
-
-    /* Calculate the ethernet checksum */
-#ifdef SONIC_CALCULATE_RXCRC
-    checksum = cpu_to_le32(crc32(0, buf, rx_len));
-#else
-    checksum = 0;
-#endif
-
-    /* Put packet into RBA */
-    DPRINTF("Receive packet at %08x\n", (s->regs[SONIC_CRBA1] << 16) | s->regs[SONIC_CRBA0]);
-    address = (s->regs[SONIC_CRBA1] << 16) | s->regs[SONIC_CRBA0];
-    s->memory_rw(s->mem_opaque, address, (uint8_t*)buf, rx_len, 1);
-    address += rx_len;
-    s->memory_rw(s->mem_opaque, address, (uint8_t*)&checksum, 4, 1);
-    rx_len += 4;
-    s->regs[SONIC_CRBA1] = address >> 16;
-    s->regs[SONIC_CRBA0] = address & 0xffff;
-    available = (s->regs[SONIC_RBWC1] << 16) | s->regs[SONIC_RBWC0];
-    available -= rx_len / 2;
-    s->regs[SONIC_RBWC1] = available >> 16;
-    s->regs[SONIC_RBWC0] = available & 0xffff;
-
-    /* Update status */
-    if (((s->regs[SONIC_RBWC1] << 16) | s->regs[SONIC_RBWC0]) < s->regs[SONIC_EOBC]) {
-        s->regs[SONIC_RCR] |= SONIC_RCR_LPKT;
-    }
-    s->regs[SONIC_RCR] |= packet_type;
-    s->regs[SONIC_RCR] |= SONIC_RCR_PRX;
-    if (s->loopback_packet) {
-        s->regs[SONIC_RCR] |= SONIC_RCR_LBK;
-        s->loopback_packet = 0;
-    }
-
-    /* Write status to memory */
-    DPRINTF("Write status at %08x\n", (s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA]);
-    data[0 * width] = s->regs[SONIC_RCR]; /* status */
-    data[1 * width] = rx_len; /* byte count */
-    data[2 * width] = s->regs[SONIC_TRBA0]; /* pkt_ptr0 */
-    data[3 * width] = s->regs[SONIC_TRBA1]; /* pkt_ptr1 */
-    data[4 * width] = s->regs[SONIC_RSC]; /* seq_no */
-    size = sizeof(uint16_t) * 5 * width;
-    s->memory_rw(s->mem_opaque, (s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA], (uint8_t *)data, size, 1);
-
-    /* Move to next descriptor */
-    size = sizeof(uint16_t) * width;
-    s->memory_rw(s->mem_opaque,
-        ((s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA]) + sizeof(uint16_t) * 5 * width,
-        (uint8_t *)data, size, 0);
-    s->regs[SONIC_LLFA] = data[0 * width];
-    if (s->regs[SONIC_LLFA] & 0x1) {
-        /* EOL detected */
-        s->regs[SONIC_ISR] |= SONIC_ISR_RDE;
-    } else {
-        data[0 * width] = 0; /* in_use */
-        s->memory_rw(s->mem_opaque,
-            ((s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA]) + sizeof(uint16_t) * 6 * width,
-            (uint8_t *)data, size, 1);
-        s->regs[SONIC_CRDA] = s->regs[SONIC_LLFA];
-        s->regs[SONIC_ISR] |= SONIC_ISR_PKTRX;
-        s->regs[SONIC_RSC] = (s->regs[SONIC_RSC] & 0xff00) | (((s->regs[SONIC_RSC] & 0x00ff) + 1) & 0x00ff);
-
-        if (s->regs[SONIC_RCR] & SONIC_RCR_LPKT) {
-            /* Read next RRA */
-            do_read_rra(s);
-        }
-    }
-
-    /* Done */
-    dp8393x_update_irq(s);
-
-    return size;
-}
-
-static void nic_reset(void *opaque)
-{
-    dp8393xState *s = opaque;
-    qemu_del_timer(s->watchdog);
-
-    s->regs[SONIC_CR] = SONIC_CR_RST | SONIC_CR_STP | SONIC_CR_RXDIS;
-    s->regs[SONIC_DCR] &= ~(SONIC_DCR_EXBUS | SONIC_DCR_LBR);
-    s->regs[SONIC_RCR] &= ~(SONIC_RCR_LB0 | SONIC_RCR_LB1 | SONIC_RCR_BRD | SONIC_RCR_RNT);
-    s->regs[SONIC_TCR] |= SONIC_TCR_NCRS | SONIC_TCR_PTX;
-    s->regs[SONIC_TCR] &= ~SONIC_TCR_BCM;
-    s->regs[SONIC_IMR] = 0;
-    s->regs[SONIC_ISR] = 0;
-    s->regs[SONIC_DCR2] = 0;
-    s->regs[SONIC_EOBC] = 0x02F8;
-    s->regs[SONIC_RSC] = 0;
-    s->regs[SONIC_CE] = 0;
-    s->regs[SONIC_RSC] = 0;
-
-    /* Network cable is connected */
-    s->regs[SONIC_RCR] |= SONIC_RCR_CRS;
-
-    dp8393x_update_irq(s);
-}
-
-static void nic_cleanup(NetClientState *nc)
-{
-    dp8393xState *s = qemu_get_nic_opaque(nc);
-
-    memory_region_del_subregion(s->address_space, &s->mmio);
-    memory_region_destroy(&s->mmio);
-
-    qemu_del_timer(s->watchdog);
-    qemu_free_timer(s->watchdog);
-
-    g_free(s);
-}
-
-static NetClientInfo net_dp83932_info = {
-    .type = NET_CLIENT_OPTIONS_KIND_NIC,
-    .size = sizeof(NICState),
-    .can_receive = nic_can_receive,
-    .receive = nic_receive,
-    .cleanup = nic_cleanup,
-};
-
-void dp83932_init(NICInfo *nd, hwaddr base, int it_shift,
-                  MemoryRegion *address_space,
-                  qemu_irq irq, void* mem_opaque,
-                  void (*memory_rw)(void *opaque, hwaddr addr, uint8_t *buf, int len, int is_write))
-{
-    dp8393xState *s;
-
-    qemu_check_nic_model(nd, "dp83932");
-
-    s = g_malloc0(sizeof(dp8393xState));
-
-    s->address_space = address_space;
-    s->mem_opaque = mem_opaque;
-    s->memory_rw = memory_rw;
-    s->it_shift = it_shift;
-    s->irq = irq;
-    s->watchdog = qemu_new_timer_ns(vm_clock, dp8393x_watchdog, s);
-    s->regs[SONIC_SR] = 0x0004; /* only revision recognized by Linux */
-
-    s->conf.macaddr = nd->macaddr;
-    s->conf.peers.ncs[0] = nd->netdev;
-
-    s->nic = qemu_new_nic(&net_dp83932_info, &s->conf, nd->model, nd->name, s);
-
-    qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
-    qemu_register_reset(nic_reset, s);
-    nic_reset(s);
-
-    memory_region_init_io(&s->mmio, &dp8393x_ops, s,
-                          "dp8393x", 0x40 << it_shift);
-    memory_region_add_subregion(address_space, base, &s->mmio);
-}
diff --git a/hw/ds1225y.c b/hw/ds1225y.c
deleted file mode 100644 (file)
index 488f1d7..0000000
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * QEMU NVRAM emulation for DS1225Y chip
- *
- * Copyright (c) 2007-2008 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 "hw/sysbus.h"
-#include "trace.h"
-
-typedef struct {
-    DeviceState qdev;
-    MemoryRegion iomem;
-    uint32_t chip_size;
-    char *filename;
-    FILE *file;
-    uint8_t *contents;
-} NvRamState;
-
-static uint64_t nvram_read(void *opaque, hwaddr addr, unsigned size)
-{
-    NvRamState *s = opaque;
-    uint32_t val;
-
-    val = s->contents[addr];
-    trace_nvram_read(addr, val);
-    return val;
-}
-
-static void nvram_write(void *opaque, hwaddr addr, uint64_t val,
-                        unsigned size)
-{
-    NvRamState *s = opaque;
-
-    val &= 0xff;
-    trace_nvram_write(addr, s->contents[addr], val);
-
-    s->contents[addr] = val;
-    if (s->file) {
-        fseek(s->file, addr, SEEK_SET);
-        fputc(val, s->file);
-        fflush(s->file);
-    }
-}
-
-static const MemoryRegionOps nvram_ops = {
-    .read = nvram_read,
-    .write = nvram_write,
-    .impl = {
-        .min_access_size = 1,
-        .max_access_size = 1,
-    },
-    .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static int nvram_post_load(void *opaque, int version_id)
-{
-    NvRamState *s = opaque;
-
-    /* Close file, as filename may has changed in load/store process */
-    if (s->file) {
-        fclose(s->file);
-    }
-
-    /* Write back nvram contents */
-    s->file = fopen(s->filename, "wb");
-    if (s->file) {
-        /* Write back contents, as 'wb' mode cleaned the file */
-        if (fwrite(s->contents, s->chip_size, 1, s->file) != 1) {
-            printf("nvram_post_load: short write\n");
-        }
-        fflush(s->file);
-    }
-
-    return 0;
-}
-
-static const VMStateDescription vmstate_nvram = {
-    .name = "nvram",
-    .version_id = 0,
-    .minimum_version_id = 0,
-    .minimum_version_id_old = 0,
-    .post_load = nvram_post_load,
-    .fields = (VMStateField[]) {
-        VMSTATE_VARRAY_UINT32(contents, NvRamState, chip_size, 0,
-                              vmstate_info_uint8, uint8_t),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-typedef struct {
-    SysBusDevice busdev;
-    NvRamState nvram;
-} SysBusNvRamState;
-
-static int nvram_sysbus_initfn(SysBusDevice *dev)
-{
-    NvRamState *s = &FROM_SYSBUS(SysBusNvRamState, dev)->nvram;
-    FILE *file;
-
-    s->contents = g_malloc0(s->chip_size);
-
-    memory_region_init_io(&s->iomem, &nvram_ops, s, "nvram", s->chip_size);
-    sysbus_init_mmio(dev, &s->iomem);
-
-    /* Read current file */
-    file = fopen(s->filename, "rb");
-    if (file) {
-        /* Read nvram contents */
-        if (fread(s->contents, s->chip_size, 1, file) != 1) {
-            printf("nvram_sysbus_initfn: short read\n");
-        }
-        fclose(file);
-    }
-    nvram_post_load(s, 0);
-
-    return 0;
-}
-
-static Property nvram_sysbus_properties[] = {
-    DEFINE_PROP_UINT32("size", SysBusNvRamState, nvram.chip_size, 0x2000),
-    DEFINE_PROP_STRING("filename", SysBusNvRamState, nvram.filename),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void nvram_sysbus_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = nvram_sysbus_initfn;
-    dc->vmsd = &vmstate_nvram;
-    dc->props = nvram_sysbus_properties;
-}
-
-static const 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_types(void)
-{
-    type_register_static(&nvram_sysbus_info);
-}
-
-type_init(nvram_register_types)
diff --git a/hw/ds1338.c b/hw/ds1338.c
deleted file mode 100644 (file)
index ae7ca9f..0000000
+++ /dev/null
@@ -1,236 +0,0 @@
-/*
- * MAXIM DS1338 I2C RTC+NVRAM
- *
- * Copyright (c) 2009 CodeSourcery.
- * 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 "hw/i2c.h"
-
-/* Size of NVRAM including both the user-accessible area and the
- * secondary register area.
- */
-#define NVRAM_SIZE 64
-
-/* Flags definitions */
-#define SECONDS_CH 0x80
-#define HOURS_12   0x40
-#define HOURS_PM   0x20
-#define CTRL_OSF   0x20
-
-typedef struct {
-    I2CSlave i2c;
-    int64_t offset;
-    uint8_t wday_offset;
-    uint8_t nvram[NVRAM_SIZE];
-    int32_t ptr;
-    bool addr_byte;
-} DS1338State;
-
-static const VMStateDescription vmstate_ds1338 = {
-    .name = "ds1338",
-    .version_id = 2,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_I2C_SLAVE(i2c, DS1338State),
-        VMSTATE_INT64(offset, DS1338State),
-        VMSTATE_UINT8_V(wday_offset, DS1338State, 2),
-        VMSTATE_UINT8_ARRAY(nvram, DS1338State, NVRAM_SIZE),
-        VMSTATE_INT32(ptr, DS1338State),
-        VMSTATE_BOOL(addr_byte, DS1338State),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void capture_current_time(DS1338State *s)
-{
-    /* Capture the current time into the secondary registers
-     * which will be actually read by the data transfer operation.
-     */
-    struct tm now;
-    qemu_get_timedate(&now, s->offset);
-    s->nvram[0] = to_bcd(now.tm_sec);
-    s->nvram[1] = to_bcd(now.tm_min);
-    if (s->nvram[2] & HOURS_12) {
-        int tmp = now.tm_hour;
-        if (tmp % 12 == 0) {
-            tmp += 12;
-        }
-        if (tmp <= 12) {
-            s->nvram[2] = HOURS_12 | to_bcd(tmp);
-        } else {
-            s->nvram[2] = HOURS_12 | HOURS_PM | to_bcd(tmp - 12);
-        }
-    } else {
-        s->nvram[2] = to_bcd(now.tm_hour);
-    }
-    s->nvram[3] = (now.tm_wday + s->wday_offset) % 7 + 1;
-    s->nvram[4] = to_bcd(now.tm_mday);
-    s->nvram[5] = to_bcd(now.tm_mon + 1);
-    s->nvram[6] = to_bcd(now.tm_year - 100);
-}
-
-static void inc_regptr(DS1338State *s)
-{
-    /* The register pointer wraps around after 0x3F; wraparound
-     * causes the current time/date to be retransferred into
-     * the secondary registers.
-     */
-    s->ptr = (s->ptr + 1) & (NVRAM_SIZE - 1);
-    if (!s->ptr) {
-        capture_current_time(s);
-    }
-}
-
-static void ds1338_event(I2CSlave *i2c, enum i2c_event event)
-{
-    DS1338State *s = FROM_I2C_SLAVE(DS1338State, i2c);
-
-    switch (event) {
-    case I2C_START_RECV:
-        /* In h/w, capture happens on any START condition, not just a
-         * START_RECV, but there is no need to actually capture on
-         * START_SEND, because the guest can't get at that data
-         * without going through a START_RECV which would overwrite it.
-         */
-        capture_current_time(s);
-        break;
-    case I2C_START_SEND:
-        s->addr_byte = true;
-        break;
-    default:
-        break;
-    }
-}
-
-static int ds1338_recv(I2CSlave *i2c)
-{
-    DS1338State *s = FROM_I2C_SLAVE(DS1338State, i2c);
-    uint8_t res;
-
-    res  = s->nvram[s->ptr];
-    inc_regptr(s);
-    return res;
-}
-
-static int ds1338_send(I2CSlave *i2c, uint8_t data)
-{
-    DS1338State *s = FROM_I2C_SLAVE(DS1338State, i2c);
-    if (s->addr_byte) {
-        s->ptr = data & (NVRAM_SIZE - 1);
-        s->addr_byte = false;
-        return 0;
-    }
-    if (s->ptr < 7) {
-        /* Time register. */
-        struct tm now;
-        qemu_get_timedate(&now, s->offset);
-        switch(s->ptr) {
-        case 0:
-            /* TODO: Implement CH (stop) bit.  */
-            now.tm_sec = from_bcd(data & 0x7f);
-            break;
-        case 1:
-            now.tm_min = from_bcd(data & 0x7f);
-            break;
-        case 2:
-            if (data & HOURS_12) {
-                int tmp = from_bcd(data & (HOURS_PM - 1));
-                if (data & HOURS_PM) {
-                    tmp += 12;
-                }
-                if (tmp % 12 == 0) {
-                    tmp -= 12;
-                }
-                now.tm_hour = tmp;
-            } else {
-                now.tm_hour = from_bcd(data & (HOURS_12 - 1));
-            }
-            break;
-        case 3:
-            {
-                /* The day field is supposed to contain a value in
-                   the range 1-7. Otherwise behavior is undefined.
-                 */
-                int user_wday = (data & 7) - 1;
-                s->wday_offset = (user_wday - now.tm_wday + 7) % 7;
-            }
-            break;
-        case 4:
-            now.tm_mday = from_bcd(data & 0x3f);
-            break;
-        case 5:
-            now.tm_mon = from_bcd(data & 0x1f) - 1;
-            break;
-        case 6:
-            now.tm_year = from_bcd(data) + 100;
-            break;
-        }
-        s->offset = qemu_timedate_diff(&now);
-    } else if (s->ptr == 7) {
-        /* Control register. */
-
-        /* Ensure bits 2, 3 and 6 will read back as zero. */
-        data &= 0xB3;
-
-        /* Attempting to write the OSF flag to logic 1 leaves the
-           value unchanged. */
-        data = (data & ~CTRL_OSF) | (data & s->nvram[s->ptr] & CTRL_OSF);
-
-        s->nvram[s->ptr] = data;
-    } else {
-        s->nvram[s->ptr] = data;
-    }
-    inc_regptr(s);
-    return 0;
-}
-
-static int ds1338_init(I2CSlave *i2c)
-{
-    return 0;
-}
-
-static void ds1338_reset(DeviceState *dev)
-{
-    DS1338State *s = FROM_I2C_SLAVE(DS1338State, I2C_SLAVE(dev));
-
-    /* The clock is running and synchronized with the host */
-    s->offset = 0;
-    s->wday_offset = 0;
-    memset(s->nvram, 0, NVRAM_SIZE);
-    s->ptr = 0;
-    s->addr_byte = false;
-}
-
-static void ds1338_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
-
-    k->init = ds1338_init;
-    k->event = ds1338_event;
-    k->recv = ds1338_recv;
-    k->send = ds1338_send;
-    dc->reset = ds1338_reset;
-    dc->vmsd = &vmstate_ds1338;
-}
-
-static const TypeInfo ds1338_info = {
-    .name          = "ds1338",
-    .parent        = TYPE_I2C_SLAVE,
-    .instance_size = sizeof(DS1338State),
-    .class_init    = ds1338_class_init,
-};
-
-static void ds1338_register_types(void)
-{
-    type_register_static(&ds1338_info);
-}
-
-type_init(ds1338_register_types)
diff --git a/hw/e1000.c b/hw/e1000.c
deleted file mode 100644 (file)
index 3f18041..0000000
+++ /dev/null
@@ -1,1404 +0,0 @@
-/*
- * QEMU e1000 emulation
- *
- * Software developer's manual:
- * http://download.intel.com/design/network/manuals/8254x_GBe_SDM.pdf
- *
- * Nir Peleg, Tutis Systems Ltd. for Qumranet Inc.
- * Copyright (c) 2008 Qumranet
- * Based on work done by:
- * Copyright (c) 2007 Dan Aloni
- * Copyright (c) 2004 Antony T Curtis
- *
- * 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/hw.h"
-#include "hw/pci/pci.h"
-#include "net/net.h"
-#include "net/checksum.h"
-#include "hw/loader.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/dma.h"
-
-#include "hw/e1000_hw.h"
-
-#define E1000_DEBUG
-
-#ifdef E1000_DEBUG
-enum {
-    DEBUG_GENERAL,     DEBUG_IO,       DEBUG_MMIO,     DEBUG_INTERRUPT,
-    DEBUG_RX,          DEBUG_TX,       DEBUG_MDIC,     DEBUG_EEPROM,
-    DEBUG_UNKNOWN,     DEBUG_TXSUM,    DEBUG_TXERR,    DEBUG_RXERR,
-    DEBUG_RXFILTER,     DEBUG_PHY,      DEBUG_NOTYET,
-};
-#define DBGBIT(x)      (1<<DEBUG_##x)
-static int debugflags = DBGBIT(TXERR) | DBGBIT(GENERAL);
-
-#define        DBGOUT(what, fmt, ...) do { \
-    if (debugflags & DBGBIT(what)) \
-        fprintf(stderr, "e1000: " fmt, ## __VA_ARGS__); \
-    } while (0)
-#else
-#define        DBGOUT(what, fmt, ...) do {} while (0)
-#endif
-
-#define IOPORT_SIZE       0x40
-#define PNPMMIO_SIZE      0x20000
-#define MIN_BUF_SIZE      60 /* Min. octets in an ethernet frame sans FCS */
-
-/* this is the size past which hardware will drop packets when setting LPE=0 */
-#define MAXIMUM_ETHERNET_VLAN_SIZE 1522
-/* this is the size past which hardware will drop packets when setting LPE=1 */
-#define MAXIMUM_ETHERNET_LPE_SIZE 16384
-
-/*
- * HW models:
- *  E1000_DEV_ID_82540EM works with Windows and Linux
- *  E1000_DEV_ID_82573L OK with windoze and Linux 2.6.22,
- *     appears to perform better than 82540EM, but breaks with Linux 2.6.18
- *  E1000_DEV_ID_82544GC_COPPER appears to work; not well tested
- *  Others never tested
- */
-enum { E1000_DEVID = E1000_DEV_ID_82540EM };
-
-/*
- * May need to specify additional MAC-to-PHY entries --
- * Intel's Windows driver refuses to initialize unless they match
- */
-enum {
-    PHY_ID2_INIT = E1000_DEVID == E1000_DEV_ID_82573L ?                0xcc2 :
-                   E1000_DEVID == E1000_DEV_ID_82544GC_COPPER ?        0xc30 :
-                   /* default to E1000_DEV_ID_82540EM */       0xc20
-};
-
-typedef struct E1000State_st {
-    PCIDevice dev;
-    NICState *nic;
-    NICConf conf;
-    MemoryRegion mmio;
-    MemoryRegion io;
-
-    uint32_t mac_reg[0x8000];
-    uint16_t phy_reg[0x20];
-    uint16_t eeprom_data[64];
-
-    uint32_t rxbuf_size;
-    uint32_t rxbuf_min_shift;
-    struct e1000_tx {
-        unsigned char header[256];
-        unsigned char vlan_header[4];
-        /* Fields vlan and data must not be reordered or separated. */
-        unsigned char vlan[4];
-        unsigned char data[0x10000];
-        uint16_t size;
-        unsigned char sum_needed;
-        unsigned char vlan_needed;
-        uint8_t ipcss;
-        uint8_t ipcso;
-        uint16_t ipcse;
-        uint8_t tucss;
-        uint8_t tucso;
-        uint16_t tucse;
-        uint8_t hdr_len;
-        uint16_t mss;
-        uint32_t paylen;
-        uint16_t tso_frames;
-        char tse;
-        int8_t ip;
-        int8_t tcp;
-        char cptse;     // current packet tse bit
-    } tx;
-
-    struct {
-        uint32_t val_in;       // shifted in from guest driver
-        uint16_t bitnum_in;
-        uint16_t bitnum_out;
-        uint16_t reading;
-        uint32_t old_eecd;
-    } eecd_state;
-
-    QEMUTimer *autoneg_timer;
-
-/* Compatibility flags for migration to/from qemu 1.3.0 and older */
-#define E1000_FLAG_AUTONEG_BIT 0
-#define E1000_FLAG_AUTONEG (1 << E1000_FLAG_AUTONEG_BIT)
-    uint32_t compat_flags;
-} E1000State;
-
-#define        defreg(x)       x = (E1000_##x>>2)
-enum {
-    defreg(CTRL),      defreg(EECD),   defreg(EERD),   defreg(GPRC),
-    defreg(GPTC),      defreg(ICR),    defreg(ICS),    defreg(IMC),
-    defreg(IMS),       defreg(LEDCTL), defreg(MANC),   defreg(MDIC),
-    defreg(MPC),       defreg(PBA),    defreg(RCTL),   defreg(RDBAH),
-    defreg(RDBAL),     defreg(RDH),    defreg(RDLEN),  defreg(RDT),
-    defreg(STATUS),    defreg(SWSM),   defreg(TCTL),   defreg(TDBAH),
-    defreg(TDBAL),     defreg(TDH),    defreg(TDLEN),  defreg(TDT),
-    defreg(TORH),      defreg(TORL),   defreg(TOTH),   defreg(TOTL),
-    defreg(TPR),       defreg(TPT),    defreg(TXDCTL), defreg(WUFC),
-    defreg(RA),                defreg(MTA),    defreg(CRCERRS),defreg(VFTA),
-    defreg(VET),
-};
-
-static void
-e1000_link_down(E1000State *s)
-{
-    s->mac_reg[STATUS] &= ~E1000_STATUS_LU;
-    s->phy_reg[PHY_STATUS] &= ~MII_SR_LINK_STATUS;
-}
-
-static void
-e1000_link_up(E1000State *s)
-{
-    s->mac_reg[STATUS] |= E1000_STATUS_LU;
-    s->phy_reg[PHY_STATUS] |= MII_SR_LINK_STATUS;
-}
-
-static void
-set_phy_ctrl(E1000State *s, int index, uint16_t val)
-{
-    /*
-     * QEMU 1.3 does not support link auto-negotiation emulation, so if we
-     * migrate during auto negotiation, after migration the link will be
-     * down.
-     */
-    if (!(s->compat_flags & E1000_FLAG_AUTONEG)) {
-        return;
-    }
-    if ((val & MII_CR_AUTO_NEG_EN) && (val & MII_CR_RESTART_AUTO_NEG)) {
-        e1000_link_down(s);
-        s->phy_reg[PHY_STATUS] &= ~MII_SR_AUTONEG_COMPLETE;
-        DBGOUT(PHY, "Start link auto negotiation\n");
-        qemu_mod_timer(s->autoneg_timer, qemu_get_clock_ms(vm_clock) + 500);
-    }
-}
-
-static void
-e1000_autoneg_timer(void *opaque)
-{
-    E1000State *s = opaque;
-    if (!qemu_get_queue(s->nic)->link_down) {
-        e1000_link_up(s);
-    }
-    s->phy_reg[PHY_STATUS] |= MII_SR_AUTONEG_COMPLETE;
-    DBGOUT(PHY, "Auto negotiation is completed\n");
-}
-
-static void (*phyreg_writeops[])(E1000State *, int, uint16_t) = {
-    [PHY_CTRL] = set_phy_ctrl,
-};
-
-enum { NPHYWRITEOPS = ARRAY_SIZE(phyreg_writeops) };
-
-enum { PHY_R = 1, PHY_W = 2, PHY_RW = PHY_R | PHY_W };
-static const char phy_regcap[0x20] = {
-    [PHY_STATUS] = PHY_R,      [M88E1000_EXT_PHY_SPEC_CTRL] = PHY_RW,
-    [PHY_ID1] = PHY_R,         [M88E1000_PHY_SPEC_CTRL] = PHY_RW,
-    [PHY_CTRL] = PHY_RW,       [PHY_1000T_CTRL] = PHY_RW,
-    [PHY_LP_ABILITY] = PHY_R,  [PHY_1000T_STATUS] = PHY_R,
-    [PHY_AUTONEG_ADV] = PHY_RW,        [M88E1000_RX_ERR_CNTR] = PHY_R,
-    [PHY_ID2] = PHY_R,         [M88E1000_PHY_SPEC_STATUS] = PHY_R
-};
-
-static const uint16_t phy_reg_init[] = {
-    [PHY_CTRL] = 0x1140,
-    [PHY_STATUS] = 0x794d, /* link initially up with not completed autoneg */
-    [PHY_ID1] = 0x141,                         [PHY_ID2] = PHY_ID2_INIT,
-    [PHY_1000T_CTRL] = 0x0e00,                 [M88E1000_PHY_SPEC_CTRL] = 0x360,
-    [M88E1000_EXT_PHY_SPEC_CTRL] = 0x0d60,     [PHY_AUTONEG_ADV] = 0xde1,
-    [PHY_LP_ABILITY] = 0x1e0,                  [PHY_1000T_STATUS] = 0x3c00,
-    [M88E1000_PHY_SPEC_STATUS] = 0xac00,
-};
-
-static const uint32_t mac_reg_init[] = {
-    [PBA] =     0x00100030,
-    [LEDCTL] =  0x602,
-    [CTRL] =    E1000_CTRL_SWDPIN2 | E1000_CTRL_SWDPIN0 |
-                E1000_CTRL_SPD_1000 | E1000_CTRL_SLU,
-    [STATUS] =  0x80000000 | E1000_STATUS_GIO_MASTER_ENABLE |
-                E1000_STATUS_ASDV | E1000_STATUS_MTXCKOK |
-                E1000_STATUS_SPEED_1000 | E1000_STATUS_FD |
-                E1000_STATUS_LU,
-    [MANC] =    E1000_MANC_EN_MNG2HOST | E1000_MANC_RCV_TCO_EN |
-                E1000_MANC_ARP_EN | E1000_MANC_0298_EN |
-                E1000_MANC_RMCP_EN,
-};
-
-static void
-set_interrupt_cause(E1000State *s, int index, uint32_t val)
-{
-    if (val && (E1000_DEVID >= E1000_DEV_ID_82547EI_MOBILE)) {
-        /* Only for 8257x */
-        val |= E1000_ICR_INT_ASSERTED;
-    }
-    s->mac_reg[ICR] = val;
-
-    /*
-     * Make sure ICR and ICS registers have the same value.
-     * The spec says that the ICS register is write-only.  However in practice,
-     * on real hardware ICS is readable, and for reads it has the same value as
-     * ICR (except that ICS does not have the clear on read behaviour of ICR).
-     *
-     * The VxWorks PRO/1000 driver uses this behaviour.
-     */
-    s->mac_reg[ICS] = val;
-
-    qemu_set_irq(s->dev.irq[0], (s->mac_reg[IMS] & s->mac_reg[ICR]) != 0);
-}
-
-static void
-set_ics(E1000State *s, int index, uint32_t val)
-{
-    DBGOUT(INTERRUPT, "set_ics %x, ICR %x, IMR %x\n", val, s->mac_reg[ICR],
-        s->mac_reg[IMS]);
-    set_interrupt_cause(s, 0, val | s->mac_reg[ICR]);
-}
-
-static int
-rxbufsize(uint32_t v)
-{
-    v &= E1000_RCTL_BSEX | E1000_RCTL_SZ_16384 | E1000_RCTL_SZ_8192 |
-         E1000_RCTL_SZ_4096 | E1000_RCTL_SZ_2048 | E1000_RCTL_SZ_1024 |
-         E1000_RCTL_SZ_512 | E1000_RCTL_SZ_256;
-    switch (v) {
-    case E1000_RCTL_BSEX | E1000_RCTL_SZ_16384:
-        return 16384;
-    case E1000_RCTL_BSEX | E1000_RCTL_SZ_8192:
-        return 8192;
-    case E1000_RCTL_BSEX | E1000_RCTL_SZ_4096:
-        return 4096;
-    case E1000_RCTL_SZ_1024:
-        return 1024;
-    case E1000_RCTL_SZ_512:
-        return 512;
-    case E1000_RCTL_SZ_256:
-        return 256;
-    }
-    return 2048;
-}
-
-static void e1000_reset(void *opaque)
-{
-    E1000State *d = opaque;
-    uint8_t *macaddr = d->conf.macaddr.a;
-    int i;
-
-    qemu_del_timer(d->autoneg_timer);
-    memset(d->phy_reg, 0, sizeof d->phy_reg);
-    memmove(d->phy_reg, phy_reg_init, sizeof phy_reg_init);
-    memset(d->mac_reg, 0, sizeof d->mac_reg);
-    memmove(d->mac_reg, mac_reg_init, sizeof mac_reg_init);
-    d->rxbuf_min_shift = 1;
-    memset(&d->tx, 0, sizeof d->tx);
-
-    if (qemu_get_queue(d->nic)->link_down) {
-        e1000_link_down(d);
-    }
-
-    /* Some guests expect pre-initialized RAH/RAL (AddrValid flag + MACaddr) */
-    d->mac_reg[RA] = 0;
-    d->mac_reg[RA + 1] = E1000_RAH_AV;
-    for (i = 0; i < 4; i++) {
-        d->mac_reg[RA] |= macaddr[i] << (8 * i);
-        d->mac_reg[RA + 1] |= (i < 2) ? macaddr[i + 4] << (8 * i) : 0;
-    }
-}
-
-static void
-set_ctrl(E1000State *s, int index, uint32_t val)
-{
-    /* RST is self clearing */
-    s->mac_reg[CTRL] = val & ~E1000_CTRL_RST;
-}
-
-static void
-set_rx_control(E1000State *s, int index, uint32_t val)
-{
-    s->mac_reg[RCTL] = val;
-    s->rxbuf_size = rxbufsize(val);
-    s->rxbuf_min_shift = ((val / E1000_RCTL_RDMTS_QUAT) & 3) + 1;
-    DBGOUT(RX, "RCTL: %d, mac_reg[RCTL] = 0x%x\n", s->mac_reg[RDT],
-           s->mac_reg[RCTL]);
-    qemu_flush_queued_packets(qemu_get_queue(s->nic));
-}
-
-static void
-set_mdic(E1000State *s, int index, uint32_t val)
-{
-    uint32_t data = val & E1000_MDIC_DATA_MASK;
-    uint32_t addr = ((val & E1000_MDIC_REG_MASK) >> E1000_MDIC_REG_SHIFT);
-
-    if ((val & E1000_MDIC_PHY_MASK) >> E1000_MDIC_PHY_SHIFT != 1) // phy #
-        val = s->mac_reg[MDIC] | E1000_MDIC_ERROR;
-    else if (val & E1000_MDIC_OP_READ) {
-        DBGOUT(MDIC, "MDIC read reg 0x%x\n", addr);
-        if (!(phy_regcap[addr] & PHY_R)) {
-            DBGOUT(MDIC, "MDIC read reg %x unhandled\n", addr);
-            val |= E1000_MDIC_ERROR;
-        } else
-            val = (val ^ data) | s->phy_reg[addr];
-    } else if (val & E1000_MDIC_OP_WRITE) {
-        DBGOUT(MDIC, "MDIC write reg 0x%x, value 0x%x\n", addr, data);
-        if (!(phy_regcap[addr] & PHY_W)) {
-            DBGOUT(MDIC, "MDIC write reg %x unhandled\n", addr);
-            val |= E1000_MDIC_ERROR;
-        } else {
-            if (addr < NPHYWRITEOPS && phyreg_writeops[addr]) {
-                phyreg_writeops[addr](s, index, data);
-            }
-            s->phy_reg[addr] = data;
-        }
-    }
-    s->mac_reg[MDIC] = val | E1000_MDIC_READY;
-
-    if (val & E1000_MDIC_INT_EN) {
-        set_ics(s, 0, E1000_ICR_MDAC);
-    }
-}
-
-static uint32_t
-get_eecd(E1000State *s, int index)
-{
-    uint32_t ret = E1000_EECD_PRES|E1000_EECD_GNT | s->eecd_state.old_eecd;
-
-    DBGOUT(EEPROM, "reading eeprom bit %d (reading %d)\n",
-           s->eecd_state.bitnum_out, s->eecd_state.reading);
-    if (!s->eecd_state.reading ||
-        ((s->eeprom_data[(s->eecd_state.bitnum_out >> 4) & 0x3f] >>
-          ((s->eecd_state.bitnum_out & 0xf) ^ 0xf))) & 1)
-        ret |= E1000_EECD_DO;
-    return ret;
-}
-
-static void
-set_eecd(E1000State *s, int index, uint32_t val)
-{
-    uint32_t oldval = s->eecd_state.old_eecd;
-
-    s->eecd_state.old_eecd = val & (E1000_EECD_SK | E1000_EECD_CS |
-            E1000_EECD_DI|E1000_EECD_FWE_MASK|E1000_EECD_REQ);
-    if (!(E1000_EECD_CS & val))                        // CS inactive; nothing to do
-       return;
-    if (E1000_EECD_CS & (val ^ oldval)) {      // CS rise edge; reset state
-       s->eecd_state.val_in = 0;
-       s->eecd_state.bitnum_in = 0;
-       s->eecd_state.bitnum_out = 0;
-       s->eecd_state.reading = 0;
-    }
-    if (!(E1000_EECD_SK & (val ^ oldval)))     // no clock edge
-        return;
-    if (!(E1000_EECD_SK & val)) {              // falling edge
-        s->eecd_state.bitnum_out++;
-        return;
-    }
-    s->eecd_state.val_in <<= 1;
-    if (val & E1000_EECD_DI)
-        s->eecd_state.val_in |= 1;
-    if (++s->eecd_state.bitnum_in == 9 && !s->eecd_state.reading) {
-        s->eecd_state.bitnum_out = ((s->eecd_state.val_in & 0x3f)<<4)-1;
-        s->eecd_state.reading = (((s->eecd_state.val_in >> 6) & 7) ==
-            EEPROM_READ_OPCODE_MICROWIRE);
-    }
-    DBGOUT(EEPROM, "eeprom bitnum in %d out %d, reading %d\n",
-           s->eecd_state.bitnum_in, s->eecd_state.bitnum_out,
-           s->eecd_state.reading);
-}
-
-static uint32_t
-flash_eerd_read(E1000State *s, int x)
-{
-    unsigned int index, r = s->mac_reg[EERD] & ~E1000_EEPROM_RW_REG_START;
-
-    if ((s->mac_reg[EERD] & E1000_EEPROM_RW_REG_START) == 0)
-        return (s->mac_reg[EERD]);
-
-    if ((index = r >> E1000_EEPROM_RW_ADDR_SHIFT) > EEPROM_CHECKSUM_REG)
-        return (E1000_EEPROM_RW_REG_DONE | r);
-
-    return ((s->eeprom_data[index] << E1000_EEPROM_RW_REG_DATA) |
-           E1000_EEPROM_RW_REG_DONE | r);
-}
-
-static void
-putsum(uint8_t *data, uint32_t n, uint32_t sloc, uint32_t css, uint32_t cse)
-{
-    uint32_t sum;
-
-    if (cse && cse < n)
-        n = cse + 1;
-    if (sloc < n-1) {
-        sum = net_checksum_add(n-css, data+css);
-        cpu_to_be16wu((uint16_t *)(data + sloc),
-                      net_checksum_finish(sum));
-    }
-}
-
-static inline int
-vlan_enabled(E1000State *s)
-{
-    return ((s->mac_reg[CTRL] & E1000_CTRL_VME) != 0);
-}
-
-static inline int
-vlan_rx_filter_enabled(E1000State *s)
-{
-    return ((s->mac_reg[RCTL] & E1000_RCTL_VFE) != 0);
-}
-
-static inline int
-is_vlan_packet(E1000State *s, const uint8_t *buf)
-{
-    return (be16_to_cpup((uint16_t *)(buf + 12)) ==
-                le16_to_cpup((uint16_t *)(s->mac_reg + VET)));
-}
-
-static inline int
-is_vlan_txd(uint32_t txd_lower)
-{
-    return ((txd_lower & E1000_TXD_CMD_VLE) != 0);
-}
-
-/* FCS aka Ethernet CRC-32. We don't get it from backends and can't
- * fill it in, just pad descriptor length by 4 bytes unless guest
- * told us to strip it off the packet. */
-static inline int
-fcs_len(E1000State *s)
-{
-    return (s->mac_reg[RCTL] & E1000_RCTL_SECRC) ? 0 : 4;
-}
-
-static void
-e1000_send_packet(E1000State *s, const uint8_t *buf, int size)
-{
-    NetClientState *nc = qemu_get_queue(s->nic);
-    if (s->phy_reg[PHY_CTRL] & MII_CR_LOOPBACK) {
-        nc->info->receive(nc, buf, size);
-    } else {
-        qemu_send_packet(nc, buf, size);
-    }
-}
-
-static void
-xmit_seg(E1000State *s)
-{
-    uint16_t len, *sp;
-    unsigned int frames = s->tx.tso_frames, css, sofar, n;
-    struct e1000_tx *tp = &s->tx;
-
-    if (tp->tse && tp->cptse) {
-        css = tp->ipcss;
-        DBGOUT(TXSUM, "frames %d size %d ipcss %d\n",
-               frames, tp->size, css);
-        if (tp->ip) {          // IPv4
-            cpu_to_be16wu((uint16_t *)(tp->data+css+2),
-                          tp->size - css);
-            cpu_to_be16wu((uint16_t *)(tp->data+css+4),
-                          be16_to_cpup((uint16_t *)(tp->data+css+4))+frames);
-        } else                 // IPv6
-            cpu_to_be16wu((uint16_t *)(tp->data+css+4),
-                          tp->size - css);
-        css = tp->tucss;
-        len = tp->size - css;
-        DBGOUT(TXSUM, "tcp %d tucss %d len %d\n", tp->tcp, css, len);
-        if (tp->tcp) {
-            sofar = frames * tp->mss;
-            cpu_to_be32wu((uint32_t *)(tp->data+css+4),        // seq
-                be32_to_cpupu((uint32_t *)(tp->data+css+4))+sofar);
-            if (tp->paylen - sofar > tp->mss)
-                tp->data[css + 13] &= ~9;              // PSH, FIN
-        } else // UDP
-            cpu_to_be16wu((uint16_t *)(tp->data+css+4), len);
-        if (tp->sum_needed & E1000_TXD_POPTS_TXSM) {
-            unsigned int phsum;
-            // add pseudo-header length before checksum calculation
-            sp = (uint16_t *)(tp->data + tp->tucso);
-            phsum = be16_to_cpup(sp) + len;
-            phsum = (phsum >> 16) + (phsum & 0xffff);
-            cpu_to_be16wu(sp, phsum);
-        }
-        tp->tso_frames++;
-    }
-
-    if (tp->sum_needed & E1000_TXD_POPTS_TXSM)
-        putsum(tp->data, tp->size, tp->tucso, tp->tucss, tp->tucse);
-    if (tp->sum_needed & E1000_TXD_POPTS_IXSM)
-        putsum(tp->data, tp->size, tp->ipcso, tp->ipcss, tp->ipcse);
-    if (tp->vlan_needed) {
-        memmove(tp->vlan, tp->data, 4);
-        memmove(tp->data, tp->data + 4, 8);
-        memcpy(tp->data + 8, tp->vlan_header, 4);
-        e1000_send_packet(s, tp->vlan, tp->size + 4);
-    } else
-        e1000_send_packet(s, tp->data, tp->size);
-    s->mac_reg[TPT]++;
-    s->mac_reg[GPTC]++;
-    n = s->mac_reg[TOTL];
-    if ((s->mac_reg[TOTL] += s->tx.size) < n)
-        s->mac_reg[TOTH]++;
-}
-
-static void
-process_tx_desc(E1000State *s, struct e1000_tx_desc *dp)
-{
-    uint32_t txd_lower = le32_to_cpu(dp->lower.data);
-    uint32_t dtype = txd_lower & (E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D);
-    unsigned int split_size = txd_lower & 0xffff, bytes, sz, op;
-    unsigned int msh = 0xfffff, hdr = 0;
-    uint64_t addr;
-    struct e1000_context_desc *xp = (struct e1000_context_desc *)dp;
-    struct e1000_tx *tp = &s->tx;
-
-    if (dtype == E1000_TXD_CMD_DEXT) { // context descriptor
-        op = le32_to_cpu(xp->cmd_and_length);
-        tp->ipcss = xp->lower_setup.ip_fields.ipcss;
-        tp->ipcso = xp->lower_setup.ip_fields.ipcso;
-        tp->ipcse = le16_to_cpu(xp->lower_setup.ip_fields.ipcse);
-        tp->tucss = xp->upper_setup.tcp_fields.tucss;
-        tp->tucso = xp->upper_setup.tcp_fields.tucso;
-        tp->tucse = le16_to_cpu(xp->upper_setup.tcp_fields.tucse);
-        tp->paylen = op & 0xfffff;
-        tp->hdr_len = xp->tcp_seg_setup.fields.hdr_len;
-        tp->mss = le16_to_cpu(xp->tcp_seg_setup.fields.mss);
-        tp->ip = (op & E1000_TXD_CMD_IP) ? 1 : 0;
-        tp->tcp = (op & E1000_TXD_CMD_TCP) ? 1 : 0;
-        tp->tse = (op & E1000_TXD_CMD_TSE) ? 1 : 0;
-        tp->tso_frames = 0;
-        if (tp->tucso == 0) {  // this is probably wrong
-            DBGOUT(TXSUM, "TCP/UDP: cso 0!\n");
-            tp->tucso = tp->tucss + (tp->tcp ? 16 : 6);
-        }
-        return;
-    } else if (dtype == (E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D)) {
-        // data descriptor
-        if (tp->size == 0) {
-            tp->sum_needed = le32_to_cpu(dp->upper.data) >> 8;
-        }
-        tp->cptse = ( txd_lower & E1000_TXD_CMD_TSE ) ? 1 : 0;
-    } else {
-        // legacy descriptor
-        tp->cptse = 0;
-    }
-
-    if (vlan_enabled(s) && is_vlan_txd(txd_lower) &&
-        (tp->cptse || txd_lower & E1000_TXD_CMD_EOP)) {
-        tp->vlan_needed = 1;
-        cpu_to_be16wu((uint16_t *)(tp->vlan_header),
-                      le16_to_cpup((uint16_t *)(s->mac_reg + VET)));
-        cpu_to_be16wu((uint16_t *)(tp->vlan_header + 2),
-                      le16_to_cpu(dp->upper.fields.special));
-    }
-        
-    addr = le64_to_cpu(dp->buffer_addr);
-    if (tp->tse && tp->cptse) {
-        hdr = tp->hdr_len;
-        msh = hdr + tp->mss;
-        do {
-            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);
-            tp->size = sz;
-            addr += bytes;
-            if (sz == msh) {
-                xmit_seg(s);
-                memmove(tp->data, tp->header, hdr);
-                tp->size = hdr;
-            }
-        } while (split_size -= bytes);
-    } else if (!tp->tse && tp->cptse) {
-        // context descriptor TSE is not set, while data descriptor TSE is set
-        DBGOUT(TXERR, "TCP segmentation 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;
-    }
-
-    if (!(txd_lower & E1000_TXD_CMD_EOP))
-        return;
-    if (!(tp->tse && tp->cptse && tp->size < hdr))
-        xmit_seg(s);
-    tp->tso_frames = 0;
-    tp->sum_needed = 0;
-    tp->vlan_needed = 0;
-    tp->size = 0;
-    tp->cptse = 0;
-}
-
-static uint32_t
-txdesc_writeback(E1000State *s, dma_addr_t base, struct e1000_tx_desc *dp)
-{
-    uint32_t txd_upper, txd_lower = le32_to_cpu(dp->lower.data);
-
-    if (!(txd_lower & (E1000_TXD_CMD_RS|E1000_TXD_CMD_RPS)))
-        return 0;
-    txd_upper = (le32_to_cpu(dp->upper.data) | E1000_TXD_STAT_DD) &
-                ~(E1000_TXD_STAT_EC | E1000_TXD_STAT_LC | E1000_TXD_STAT_TU);
-    dp->upper.data = cpu_to_le32(txd_upper);
-    pci_dma_write(&s->dev, base + ((char *)&dp->upper - (char *)dp),
-                  &dp->upper, sizeof(dp->upper));
-    return E1000_ICR_TXDW;
-}
-
-static uint64_t tx_desc_base(E1000State *s)
-{
-    uint64_t bah = s->mac_reg[TDBAH];
-    uint64_t bal = s->mac_reg[TDBAL] & ~0xf;
-
-    return (bah << 32) + bal;
-}
-
-static void
-start_xmit(E1000State *s)
-{
-    dma_addr_t base;
-    struct e1000_tx_desc desc;
-    uint32_t tdh_start = s->mac_reg[TDH], cause = E1000_ICS_TXQE;
-
-    if (!(s->mac_reg[TCTL] & E1000_TCTL_EN)) {
-        DBGOUT(TX, "tx disabled\n");
-        return;
-    }
-
-    while (s->mac_reg[TDH] != s->mac_reg[TDT]) {
-        base = tx_desc_base(s) +
-               sizeof(struct e1000_tx_desc) * s->mac_reg[TDH];
-        pci_dma_read(&s->dev, base, &desc, sizeof(desc));
-
-        DBGOUT(TX, "index %d: %p : %x %x\n", s->mac_reg[TDH],
-               (void *)(intptr_t)desc.buffer_addr, desc.lower.data,
-               desc.upper.data);
-
-        process_tx_desc(s, &desc);
-        cause |= txdesc_writeback(s, base, &desc);
-
-        if (++s->mac_reg[TDH] * sizeof(desc) >= s->mac_reg[TDLEN])
-            s->mac_reg[TDH] = 0;
-        /*
-         * the following could happen only if guest sw assigns
-         * bogus values to TDT/TDLEN.
-         * there's nothing too intelligent we could do about this.
-         */
-        if (s->mac_reg[TDH] == tdh_start) {
-            DBGOUT(TXERR, "TDH wraparound @%x, TDT %x, TDLEN %x\n",
-                   tdh_start, s->mac_reg[TDT], s->mac_reg[TDLEN]);
-            break;
-        }
-    }
-    set_ics(s, 0, cause);
-}
-
-static int
-receive_filter(E1000State *s, const uint8_t *buf, int size)
-{
-    static const uint8_t bcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
-    static const int mta_shift[] = {4, 3, 2, 0};
-    uint32_t f, rctl = s->mac_reg[RCTL], ra[2], *rp;
-
-    if (is_vlan_packet(s, buf) && vlan_rx_filter_enabled(s)) {
-        uint16_t vid = be16_to_cpup((uint16_t *)(buf + 14));
-        uint32_t vfta = le32_to_cpup((uint32_t *)(s->mac_reg + VFTA) +
-                                     ((vid >> 5) & 0x7f));
-        if ((vfta & (1 << (vid & 0x1f))) == 0)
-            return 0;
-    }
-
-    if (rctl & E1000_RCTL_UPE)                 // promiscuous
-        return 1;
-
-    if ((buf[0] & 1) && (rctl & E1000_RCTL_MPE))       // promiscuous mcast
-        return 1;
-
-    if ((rctl & E1000_RCTL_BAM) && !memcmp(buf, bcast, sizeof bcast))
-        return 1;
-
-    for (rp = s->mac_reg + RA; rp < s->mac_reg + RA + 32; rp += 2) {
-        if (!(rp[1] & E1000_RAH_AV))
-            continue;
-        ra[0] = cpu_to_le32(rp[0]);
-        ra[1] = cpu_to_le32(rp[1]);
-        if (!memcmp(buf, (uint8_t *)ra, 6)) {
-            DBGOUT(RXFILTER,
-                   "unicast match[%d]: %02x:%02x:%02x:%02x:%02x:%02x\n",
-                   (int)(rp - s->mac_reg - RA)/2,
-                   buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);
-            return 1;
-        }
-    }
-    DBGOUT(RXFILTER, "unicast mismatch: %02x:%02x:%02x:%02x:%02x:%02x\n",
-           buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);
-
-    f = mta_shift[(rctl >> E1000_RCTL_MO_SHIFT) & 3];
-    f = (((buf[5] << 8) | buf[4]) >> f) & 0xfff;
-    if (s->mac_reg[MTA + (f >> 5)] & (1 << (f & 0x1f)))
-        return 1;
-    DBGOUT(RXFILTER,
-           "dropping, inexact filter mismatch: %02x:%02x:%02x:%02x:%02x:%02x MO %d MTA[%d] %x\n",
-           buf[0], buf[1], buf[2], buf[3], buf[4], buf[5],
-           (rctl >> E1000_RCTL_MO_SHIFT) & 3, f >> 5,
-           s->mac_reg[MTA + (f >> 5)]);
-
-    return 0;
-}
-
-static void
-e1000_set_link_status(NetClientState *nc)
-{
-    E1000State *s = qemu_get_nic_opaque(nc);
-    uint32_t old_status = s->mac_reg[STATUS];
-
-    if (nc->link_down) {
-        e1000_link_down(s);
-    } else {
-        e1000_link_up(s);
-    }
-
-    if (s->mac_reg[STATUS] != old_status)
-        set_ics(s, 0, E1000_ICR_LSC);
-}
-
-static bool e1000_has_rxbufs(E1000State *s, size_t total_size)
-{
-    int bufs;
-    /* Fast-path short packets */
-    if (total_size <= s->rxbuf_size) {
-        return s->mac_reg[RDH] != s->mac_reg[RDT];
-    }
-    if (s->mac_reg[RDH] < s->mac_reg[RDT]) {
-        bufs = s->mac_reg[RDT] - s->mac_reg[RDH];
-    } else if (s->mac_reg[RDH] > s->mac_reg[RDT]) {
-        bufs = s->mac_reg[RDLEN] /  sizeof(struct e1000_rx_desc) +
-            s->mac_reg[RDT] - s->mac_reg[RDH];
-    } else {
-        return false;
-    }
-    return total_size <= bufs * s->rxbuf_size;
-}
-
-static int
-e1000_can_receive(NetClientState *nc)
-{
-    E1000State *s = qemu_get_nic_opaque(nc);
-
-    return (s->mac_reg[STATUS] & E1000_STATUS_LU) &&
-        (s->mac_reg[RCTL] & E1000_RCTL_EN) && e1000_has_rxbufs(s, 1);
-}
-
-static uint64_t rx_desc_base(E1000State *s)
-{
-    uint64_t bah = s->mac_reg[RDBAH];
-    uint64_t bal = s->mac_reg[RDBAL] & ~0xf;
-
-    return (bah << 32) + bal;
-}
-
-static ssize_t
-e1000_receive(NetClientState *nc, const uint8_t *buf, size_t size)
-{
-    E1000State *s = qemu_get_nic_opaque(nc);
-    struct e1000_rx_desc desc;
-    dma_addr_t base;
-    unsigned int n, rdt;
-    uint32_t rdh_start;
-    uint16_t vlan_special = 0;
-    uint8_t vlan_status = 0, vlan_offset = 0;
-    uint8_t min_buf[MIN_BUF_SIZE];
-    size_t desc_offset;
-    size_t desc_size;
-    size_t total_size;
-
-    if (!(s->mac_reg[STATUS] & E1000_STATUS_LU)) {
-        return -1;
-    }
-
-    if (!(s->mac_reg[RCTL] & E1000_RCTL_EN)) {
-        return -1;
-    }
-
-    /* Pad to minimum Ethernet frame length */
-    if (size < sizeof(min_buf)) {
-        memcpy(min_buf, buf, size);
-        memset(&min_buf[size], 0, sizeof(min_buf) - size);
-        buf = min_buf;
-        size = sizeof(min_buf);
-    }
-
-    /* Discard oversized packets if !LPE and !SBP. */
-    if ((size > MAXIMUM_ETHERNET_LPE_SIZE ||
-        (size > MAXIMUM_ETHERNET_VLAN_SIZE
-        && !(s->mac_reg[RCTL] & E1000_RCTL_LPE)))
-        && !(s->mac_reg[RCTL] & E1000_RCTL_SBP)) {
-        return size;
-    }
-
-    if (!receive_filter(s, buf, size))
-        return size;
-
-    if (vlan_enabled(s) && is_vlan_packet(s, buf)) {
-        vlan_special = cpu_to_le16(be16_to_cpup((uint16_t *)(buf + 14)));
-        memmove((uint8_t *)buf + 4, buf, 12);
-        vlan_status = E1000_RXD_STAT_VP;
-        vlan_offset = 4;
-        size -= 4;
-    }
-
-    rdh_start = s->mac_reg[RDH];
-    desc_offset = 0;
-    total_size = size + fcs_len(s);
-    if (!e1000_has_rxbufs(s, total_size)) {
-            set_ics(s, 0, E1000_ICS_RXO);
-            return -1;
-    }
-    do {
-        desc_size = total_size - desc_offset;
-        if (desc_size > s->rxbuf_size) {
-            desc_size = s->rxbuf_size;
-        }
-        base = rx_desc_base(s) + sizeof(desc) * s->mac_reg[RDH];
-        pci_dma_read(&s->dev, base, &desc, sizeof(desc));
-        desc.special = vlan_special;
-        desc.status |= (vlan_status | E1000_RXD_STAT_DD);
-        if (desc.buffer_addr) {
-            if (desc_offset < size) {
-                size_t copy_size = size - desc_offset;
-                if (copy_size > s->rxbuf_size) {
-                    copy_size = s->rxbuf_size;
-                }
-                pci_dma_write(&s->dev, le64_to_cpu(desc.buffer_addr),
-                              buf + desc_offset + vlan_offset, copy_size);
-            }
-            desc_offset += desc_size;
-            desc.length = cpu_to_le16(desc_size);
-            if (desc_offset >= total_size) {
-                desc.status |= E1000_RXD_STAT_EOP | E1000_RXD_STAT_IXSM;
-            } else {
-                /* Guest zeroing out status is not a hardware requirement.
-                   Clear EOP in case guest didn't do it. */
-                desc.status &= ~E1000_RXD_STAT_EOP;
-            }
-        } else { // as per intel docs; skip descriptors with null buf addr
-            DBGOUT(RX, "Null RX descriptor!!\n");
-        }
-        pci_dma_write(&s->dev, base, &desc, sizeof(desc));
-
-        if (++s->mac_reg[RDH] * sizeof(desc) >= s->mac_reg[RDLEN])
-            s->mac_reg[RDH] = 0;
-        /* see comment in start_xmit; same here */
-        if (s->mac_reg[RDH] == rdh_start) {
-            DBGOUT(RXERR, "RDH wraparound @%x, RDT %x, RDLEN %x\n",
-                   rdh_start, s->mac_reg[RDT], s->mac_reg[RDLEN]);
-            set_ics(s, 0, E1000_ICS_RXO);
-            return -1;
-        }
-    } while (desc_offset < total_size);
-
-    s->mac_reg[GPRC]++;
-    s->mac_reg[TPR]++;
-    /* TOR - Total Octets Received:
-     * This register includes bytes received in a packet from the <Destination
-     * Address> field through the <CRC> field, inclusively.
-     */
-    n = s->mac_reg[TORL] + size + /* Always include FCS length. */ 4;
-    if (n < s->mac_reg[TORL])
-        s->mac_reg[TORH]++;
-    s->mac_reg[TORL] = n;
-
-    n = E1000_ICS_RXT0;
-    if ((rdt = s->mac_reg[RDT]) < s->mac_reg[RDH])
-        rdt += s->mac_reg[RDLEN] / sizeof(desc);
-    if (((rdt - s->mac_reg[RDH]) * sizeof(desc)) <= s->mac_reg[RDLEN] >>
-        s->rxbuf_min_shift)
-        n |= E1000_ICS_RXDMT0;
-
-    set_ics(s, 0, n);
-
-    return size;
-}
-
-static uint32_t
-mac_readreg(E1000State *s, int index)
-{
-    return s->mac_reg[index];
-}
-
-static uint32_t
-mac_icr_read(E1000State *s, int index)
-{
-    uint32_t ret = s->mac_reg[ICR];
-
-    DBGOUT(INTERRUPT, "ICR read: %x\n", ret);
-    set_interrupt_cause(s, 0, 0);
-    return ret;
-}
-
-static uint32_t
-mac_read_clr4(E1000State *s, int index)
-{
-    uint32_t ret = s->mac_reg[index];
-
-    s->mac_reg[index] = 0;
-    return ret;
-}
-
-static uint32_t
-mac_read_clr8(E1000State *s, int index)
-{
-    uint32_t ret = s->mac_reg[index];
-
-    s->mac_reg[index] = 0;
-    s->mac_reg[index-1] = 0;
-    return ret;
-}
-
-static void
-mac_writereg(E1000State *s, int index, uint32_t val)
-{
-    s->mac_reg[index] = val;
-}
-
-static void
-set_rdt(E1000State *s, int index, uint32_t val)
-{
-    s->mac_reg[index] = val & 0xffff;
-    if (e1000_has_rxbufs(s, 1)) {
-        qemu_flush_queued_packets(qemu_get_queue(s->nic));
-    }
-}
-
-static void
-set_16bit(E1000State *s, int index, uint32_t val)
-{
-    s->mac_reg[index] = val & 0xffff;
-}
-
-static void
-set_dlen(E1000State *s, int index, uint32_t val)
-{
-    s->mac_reg[index] = val & 0xfff80;
-}
-
-static void
-set_tctl(E1000State *s, int index, uint32_t val)
-{
-    s->mac_reg[index] = val;
-    s->mac_reg[TDT] &= 0xffff;
-    start_xmit(s);
-}
-
-static void
-set_icr(E1000State *s, int index, uint32_t val)
-{
-    DBGOUT(INTERRUPT, "set_icr %x\n", val);
-    set_interrupt_cause(s, 0, s->mac_reg[ICR] & ~val);
-}
-
-static void
-set_imc(E1000State *s, int index, uint32_t val)
-{
-    s->mac_reg[IMS] &= ~val;
-    set_ics(s, 0, 0);
-}
-
-static void
-set_ims(E1000State *s, int index, uint32_t val)
-{
-    s->mac_reg[IMS] |= val;
-    set_ics(s, 0, 0);
-}
-
-#define getreg(x)      [x] = mac_readreg
-static uint32_t (*macreg_readops[])(E1000State *, int) = {
-    getreg(PBA),       getreg(RCTL),   getreg(TDH),    getreg(TXDCTL),
-    getreg(WUFC),      getreg(TDT),    getreg(CTRL),   getreg(LEDCTL),
-    getreg(MANC),      getreg(MDIC),   getreg(SWSM),   getreg(STATUS),
-    getreg(TORL),      getreg(TOTL),   getreg(IMS),    getreg(TCTL),
-    getreg(RDH),       getreg(RDT),    getreg(VET),    getreg(ICS),
-    getreg(TDBAL),     getreg(TDBAH),  getreg(RDBAH),  getreg(RDBAL),
-    getreg(TDLEN),     getreg(RDLEN),
-
-    [TOTH] = mac_read_clr8,    [TORH] = mac_read_clr8, [GPRC] = mac_read_clr4,
-    [GPTC] = mac_read_clr4,    [TPR] = mac_read_clr4,  [TPT] = mac_read_clr4,
-    [ICR] = mac_icr_read,      [EECD] = get_eecd,      [EERD] = flash_eerd_read,
-    [CRCERRS ... MPC] = &mac_readreg,
-    [RA ... RA+31] = &mac_readreg,
-    [MTA ... MTA+127] = &mac_readreg,
-    [VFTA ... VFTA+127] = &mac_readreg,
-};
-enum { NREADOPS = ARRAY_SIZE(macreg_readops) };
-
-#define putreg(x)      [x] = mac_writereg
-static void (*macreg_writeops[])(E1000State *, int, uint32_t) = {
-    putreg(PBA),       putreg(EERD),   putreg(SWSM),   putreg(WUFC),
-    putreg(TDBAL),     putreg(TDBAH),  putreg(TXDCTL), putreg(RDBAH),
-    putreg(RDBAL),     putreg(LEDCTL), putreg(VET),
-    [TDLEN] = set_dlen,        [RDLEN] = set_dlen,     [TCTL] = set_tctl,
-    [TDT] = set_tctl,  [MDIC] = set_mdic,      [ICS] = set_ics,
-    [TDH] = set_16bit, [RDH] = set_16bit,      [RDT] = set_rdt,
-    [IMC] = set_imc,   [IMS] = set_ims,        [ICR] = set_icr,
-    [EECD] = set_eecd, [RCTL] = set_rx_control, [CTRL] = set_ctrl,
-    [RA ... RA+31] = &mac_writereg,
-    [MTA ... MTA+127] = &mac_writereg,
-    [VFTA ... VFTA+127] = &mac_writereg,
-};
-
-enum { NWRITEOPS = ARRAY_SIZE(macreg_writeops) };
-
-static void
-e1000_mmio_write(void *opaque, hwaddr addr, uint64_t val,
-                 unsigned size)
-{
-    E1000State *s = opaque;
-    unsigned int index = (addr & 0x1ffff) >> 2;
-
-    if (index < NWRITEOPS && macreg_writeops[index]) {
-        macreg_writeops[index](s, index, val);
-    } else if (index < NREADOPS && macreg_readops[index]) {
-        DBGOUT(MMIO, "e1000_mmio_writel RO %x: 0x%04"PRIx64"\n", index<<2, val);
-    } else {
-        DBGOUT(UNKNOWN, "MMIO unknown write addr=0x%08x,val=0x%08"PRIx64"\n",
-               index<<2, val);
-    }
-}
-
-static uint64_t
-e1000_mmio_read(void *opaque, hwaddr addr, unsigned size)
-{
-    E1000State *s = opaque;
-    unsigned int index = (addr & 0x1ffff) >> 2;
-
-    if (index < NREADOPS && macreg_readops[index])
-    {
-        return macreg_readops[index](s, index);
-    }
-    DBGOUT(UNKNOWN, "MMIO unknown read addr=0x%08x\n", index<<2);
-    return 0;
-}
-
-static const MemoryRegionOps e1000_mmio_ops = {
-    .read = e1000_mmio_read,
-    .write = e1000_mmio_write,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-    .impl = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-};
-
-static uint64_t e1000_io_read(void *opaque, hwaddr addr,
-                              unsigned size)
-{
-    E1000State *s = opaque;
-
-    (void)s;
-    return 0;
-}
-
-static void e1000_io_write(void *opaque, hwaddr addr,
-                           uint64_t val, unsigned size)
-{
-    E1000State *s = opaque;
-
-    (void)s;
-}
-
-static const MemoryRegionOps e1000_io_ops = {
-    .read = e1000_io_read,
-    .write = e1000_io_write,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static bool is_version_1(void *opaque, int version_id)
-{
-    return version_id == 1;
-}
-
-static void e1000_pre_save(void *opaque)
-{
-    E1000State *s = opaque;
-    NetClientState *nc = qemu_get_queue(s->nic);
-
-    if (!(s->compat_flags & E1000_FLAG_AUTONEG)) {
-        return;
-    }
-
-    /*
-     * If link is down and auto-negotiation is ongoing, complete
-     * auto-negotiation immediately.  This allows is to look at
-     * MII_SR_AUTONEG_COMPLETE to infer link status on load.
-     */
-    if (nc->link_down &&
-        s->phy_reg[PHY_CTRL] & MII_CR_AUTO_NEG_EN &&
-        s->phy_reg[PHY_CTRL] & MII_CR_RESTART_AUTO_NEG) {
-         s->phy_reg[PHY_STATUS] |= MII_SR_AUTONEG_COMPLETE;
-    }
-}
-
-static int e1000_post_load(void *opaque, int version_id)
-{
-    E1000State *s = opaque;
-    NetClientState *nc = qemu_get_queue(s->nic);
-
-    /* nc.link_down can't be migrated, so infer link_down according
-     * to link status bit in mac_reg[STATUS].
-     * Alternatively, restart link negotiation if it was in progress. */
-    nc->link_down = (s->mac_reg[STATUS] & E1000_STATUS_LU) == 0;
-
-    if (!(s->compat_flags & E1000_FLAG_AUTONEG)) {
-        return 0;
-    }
-
-    if (s->phy_reg[PHY_CTRL] & MII_CR_AUTO_NEG_EN &&
-        s->phy_reg[PHY_CTRL] & MII_CR_RESTART_AUTO_NEG &&
-        !(s->phy_reg[PHY_STATUS] & MII_SR_AUTONEG_COMPLETE)) {
-        nc->link_down = false;
-        qemu_mod_timer(s->autoneg_timer, qemu_get_clock_ms(vm_clock) + 500);
-    }
-
-    return 0;
-}
-
-static const VMStateDescription vmstate_e1000 = {
-    .name = "e1000",
-    .version_id = 2,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .pre_save = e1000_pre_save,
-    .post_load = e1000_post_load,
-    .fields      = (VMStateField []) {
-        VMSTATE_PCI_DEVICE(dev, E1000State),
-        VMSTATE_UNUSED_TEST(is_version_1, 4), /* was instance id */
-        VMSTATE_UNUSED(4), /* Was mmio_base.  */
-        VMSTATE_UINT32(rxbuf_size, E1000State),
-        VMSTATE_UINT32(rxbuf_min_shift, E1000State),
-        VMSTATE_UINT32(eecd_state.val_in, E1000State),
-        VMSTATE_UINT16(eecd_state.bitnum_in, E1000State),
-        VMSTATE_UINT16(eecd_state.bitnum_out, E1000State),
-        VMSTATE_UINT16(eecd_state.reading, E1000State),
-        VMSTATE_UINT32(eecd_state.old_eecd, E1000State),
-        VMSTATE_UINT8(tx.ipcss, E1000State),
-        VMSTATE_UINT8(tx.ipcso, E1000State),
-        VMSTATE_UINT16(tx.ipcse, E1000State),
-        VMSTATE_UINT8(tx.tucss, E1000State),
-        VMSTATE_UINT8(tx.tucso, E1000State),
-        VMSTATE_UINT16(tx.tucse, E1000State),
-        VMSTATE_UINT32(tx.paylen, E1000State),
-        VMSTATE_UINT8(tx.hdr_len, E1000State),
-        VMSTATE_UINT16(tx.mss, E1000State),
-        VMSTATE_UINT16(tx.size, E1000State),
-        VMSTATE_UINT16(tx.tso_frames, E1000State),
-        VMSTATE_UINT8(tx.sum_needed, E1000State),
-        VMSTATE_INT8(tx.ip, E1000State),
-        VMSTATE_INT8(tx.tcp, E1000State),
-        VMSTATE_BUFFER(tx.header, E1000State),
-        VMSTATE_BUFFER(tx.data, E1000State),
-        VMSTATE_UINT16_ARRAY(eeprom_data, E1000State, 64),
-        VMSTATE_UINT16_ARRAY(phy_reg, E1000State, 0x20),
-        VMSTATE_UINT32(mac_reg[CTRL], E1000State),
-        VMSTATE_UINT32(mac_reg[EECD], E1000State),
-        VMSTATE_UINT32(mac_reg[EERD], E1000State),
-        VMSTATE_UINT32(mac_reg[GPRC], E1000State),
-        VMSTATE_UINT32(mac_reg[GPTC], E1000State),
-        VMSTATE_UINT32(mac_reg[ICR], E1000State),
-        VMSTATE_UINT32(mac_reg[ICS], E1000State),
-        VMSTATE_UINT32(mac_reg[IMC], E1000State),
-        VMSTATE_UINT32(mac_reg[IMS], E1000State),
-        VMSTATE_UINT32(mac_reg[LEDCTL], E1000State),
-        VMSTATE_UINT32(mac_reg[MANC], E1000State),
-        VMSTATE_UINT32(mac_reg[MDIC], E1000State),
-        VMSTATE_UINT32(mac_reg[MPC], E1000State),
-        VMSTATE_UINT32(mac_reg[PBA], E1000State),
-        VMSTATE_UINT32(mac_reg[RCTL], E1000State),
-        VMSTATE_UINT32(mac_reg[RDBAH], E1000State),
-        VMSTATE_UINT32(mac_reg[RDBAL], E1000State),
-        VMSTATE_UINT32(mac_reg[RDH], E1000State),
-        VMSTATE_UINT32(mac_reg[RDLEN], E1000State),
-        VMSTATE_UINT32(mac_reg[RDT], E1000State),
-        VMSTATE_UINT32(mac_reg[STATUS], E1000State),
-        VMSTATE_UINT32(mac_reg[SWSM], E1000State),
-        VMSTATE_UINT32(mac_reg[TCTL], E1000State),
-        VMSTATE_UINT32(mac_reg[TDBAH], E1000State),
-        VMSTATE_UINT32(mac_reg[TDBAL], E1000State),
-        VMSTATE_UINT32(mac_reg[TDH], E1000State),
-        VMSTATE_UINT32(mac_reg[TDLEN], E1000State),
-        VMSTATE_UINT32(mac_reg[TDT], E1000State),
-        VMSTATE_UINT32(mac_reg[TORH], E1000State),
-        VMSTATE_UINT32(mac_reg[TORL], E1000State),
-        VMSTATE_UINT32(mac_reg[TOTH], E1000State),
-        VMSTATE_UINT32(mac_reg[TOTL], E1000State),
-        VMSTATE_UINT32(mac_reg[TPR], E1000State),
-        VMSTATE_UINT32(mac_reg[TPT], E1000State),
-        VMSTATE_UINT32(mac_reg[TXDCTL], E1000State),
-        VMSTATE_UINT32(mac_reg[WUFC], E1000State),
-        VMSTATE_UINT32(mac_reg[VET], E1000State),
-        VMSTATE_UINT32_SUB_ARRAY(mac_reg, E1000State, RA, 32),
-        VMSTATE_UINT32_SUB_ARRAY(mac_reg, E1000State, MTA, 128),
-        VMSTATE_UINT32_SUB_ARRAY(mac_reg, E1000State, VFTA, 128),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static const uint16_t e1000_eeprom_template[64] = {
-    0x0000, 0x0000, 0x0000, 0x0000,      0xffff, 0x0000,      0x0000, 0x0000,
-    0x3000, 0x1000, 0x6403, E1000_DEVID, 0x8086, E1000_DEVID, 0x8086, 0x3040,
-    0x0008, 0x2000, 0x7e14, 0x0048,      0x1000, 0x00d8,      0x0000, 0x2700,
-    0x6cc9, 0x3150, 0x0722, 0x040b,      0x0984, 0x0000,      0xc000, 0x0706,
-    0x1008, 0x0000, 0x0f04, 0x7fff,      0x4d01, 0xffff,      0xffff, 0xffff,
-    0xffff, 0xffff, 0xffff, 0xffff,      0xffff, 0xffff,      0xffff, 0xffff,
-    0x0100, 0x4000, 0x121c, 0xffff,      0xffff, 0xffff,      0xffff, 0xffff,
-    0xffff, 0xffff, 0xffff, 0xffff,      0xffff, 0xffff,      0xffff, 0x0000,
-};
-
-/* PCI interface */
-
-static void
-e1000_mmio_setup(E1000State *d)
-{
-    int i;
-    const uint32_t excluded_regs[] = {
-        E1000_MDIC, E1000_ICR, E1000_ICS, E1000_IMS,
-        E1000_IMC, E1000_TCTL, E1000_TDT, PNPMMIO_SIZE
-    };
-
-    memory_region_init_io(&d->mmio, &e1000_mmio_ops, d, "e1000-mmio",
-                          PNPMMIO_SIZE);
-    memory_region_add_coalescing(&d->mmio, 0, excluded_regs[0]);
-    for (i = 0; excluded_regs[i] != PNPMMIO_SIZE; i++)
-        memory_region_add_coalescing(&d->mmio, excluded_regs[i] + 4,
-                                     excluded_regs[i+1] - excluded_regs[i] - 4);
-    memory_region_init_io(&d->io, &e1000_io_ops, d, "e1000-io", IOPORT_SIZE);
-}
-
-static void
-e1000_cleanup(NetClientState *nc)
-{
-    E1000State *s = qemu_get_nic_opaque(nc);
-
-    s->nic = NULL;
-}
-
-static void
-pci_e1000_uninit(PCIDevice *dev)
-{
-    E1000State *d = DO_UPCAST(E1000State, dev, dev);
-
-    qemu_del_timer(d->autoneg_timer);
-    qemu_free_timer(d->autoneg_timer);
-    memory_region_destroy(&d->mmio);
-    memory_region_destroy(&d->io);
-    qemu_del_nic(d->nic);
-}
-
-static NetClientInfo net_e1000_info = {
-    .type = NET_CLIENT_OPTIONS_KIND_NIC,
-    .size = sizeof(NICState),
-    .can_receive = e1000_can_receive,
-    .receive = e1000_receive,
-    .cleanup = e1000_cleanup,
-    .link_status_changed = e1000_set_link_status,
-};
-
-static int pci_e1000_init(PCIDevice *pci_dev)
-{
-    E1000State *d = DO_UPCAST(E1000State, dev, pci_dev);
-    uint8_t *pci_conf;
-    uint16_t checksum = 0;
-    int i;
-    uint8_t *macaddr;
-
-    pci_conf = d->dev.config;
-
-    /* TODO: RST# value should be 0, PCI spec 6.2.4 */
-    pci_conf[PCI_CACHE_LINE_SIZE] = 0x10;
-
-    pci_conf[PCI_INTERRUPT_PIN] = 1; /* interrupt pin A */
-
-    e1000_mmio_setup(d);
-
-    pci_register_bar(&d->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &d->mmio);
-
-    pci_register_bar(&d->dev, 1, PCI_BASE_ADDRESS_SPACE_IO, &d->io);
-
-    memmove(d->eeprom_data, e1000_eeprom_template,
-        sizeof e1000_eeprom_template);
-    qemu_macaddr_default_if_unset(&d->conf.macaddr);
-    macaddr = d->conf.macaddr.a;
-    for (i = 0; i < 3; i++)
-        d->eeprom_data[i] = (macaddr[2*i+1]<<8) | macaddr[2*i];
-    for (i = 0; i < EEPROM_CHECKSUM_REG; i++)
-        checksum += d->eeprom_data[i];
-    checksum = (uint16_t) EEPROM_SUM - checksum;
-    d->eeprom_data[EEPROM_CHECKSUM_REG] = checksum;
-
-    d->nic = qemu_new_nic(&net_e1000_info, &d->conf,
-                          object_get_typename(OBJECT(d)), d->dev.qdev.id, d);
-
-    qemu_format_nic_info_str(qemu_get_queue(d->nic), macaddr);
-
-    add_boot_device_path(d->conf.bootindex, &pci_dev->qdev, "/ethernet-phy@0");
-
-    d->autoneg_timer = qemu_new_timer_ms(vm_clock, e1000_autoneg_timer, d);
-
-    return 0;
-}
-
-static void qdev_e1000_reset(DeviceState *dev)
-{
-    E1000State *d = DO_UPCAST(E1000State, dev.qdev, dev);
-    e1000_reset(d);
-}
-
-static Property e1000_properties[] = {
-    DEFINE_NIC_PROPERTIES(E1000State, conf),
-    DEFINE_PROP_BIT("autonegotiation", E1000State,
-                    compat_flags, E1000_FLAG_AUTONEG_BIT, true),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void e1000_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
-    k->init = pci_e1000_init;
-    k->exit = pci_e1000_uninit;
-    k->romfile = "efi-e1000.rom";
-    k->vendor_id = PCI_VENDOR_ID_INTEL;
-    k->device_id = E1000_DEVID;
-    k->revision = 0x03;
-    k->class_id = PCI_CLASS_NETWORK_ETHERNET;
-    dc->desc = "Intel Gigabit Ethernet";
-    dc->reset = qdev_e1000_reset;
-    dc->vmsd = &vmstate_e1000;
-    dc->props = e1000_properties;
-}
-
-static const TypeInfo e1000_info = {
-    .name          = "e1000",
-    .parent        = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(E1000State),
-    .class_init    = e1000_class_init,
-};
-
-static void e1000_register_types(void)
-{
-    type_register_static(&e1000_info);
-}
-
-type_init(e1000_register_types)
diff --git a/hw/e1000_hw.h b/hw/e1000_hw.h
deleted file mode 100644 (file)
index c9cb79e..0000000
+++ /dev/null
@@ -1,893 +0,0 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2006 Intel Corporation.
-
-  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, 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/>.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-/* e1000_hw.h
- * Structures, enums, and macros for the MAC
- */
-
-#ifndef _E1000_HW_H_
-#define _E1000_HW_H_
-
-
-/* PCI Device IDs */
-#define E1000_DEV_ID_82542               0x1000
-#define E1000_DEV_ID_82543GC_FIBER       0x1001
-#define E1000_DEV_ID_82543GC_COPPER      0x1004
-#define E1000_DEV_ID_82544EI_COPPER      0x1008
-#define E1000_DEV_ID_82544EI_FIBER       0x1009
-#define E1000_DEV_ID_82544GC_COPPER      0x100C
-#define E1000_DEV_ID_82544GC_LOM         0x100D
-#define E1000_DEV_ID_82540EM             0x100E
-#define E1000_DEV_ID_82540EM_LOM         0x1015
-#define E1000_DEV_ID_82540EP_LOM         0x1016
-#define E1000_DEV_ID_82540EP             0x1017
-#define E1000_DEV_ID_82540EP_LP          0x101E
-#define E1000_DEV_ID_82545EM_COPPER      0x100F
-#define E1000_DEV_ID_82545EM_FIBER       0x1011
-#define E1000_DEV_ID_82545GM_COPPER      0x1026
-#define E1000_DEV_ID_82545GM_FIBER       0x1027
-#define E1000_DEV_ID_82545GM_SERDES      0x1028
-#define E1000_DEV_ID_82546EB_COPPER      0x1010
-#define E1000_DEV_ID_82546EB_FIBER       0x1012
-#define E1000_DEV_ID_82546EB_QUAD_COPPER 0x101D
-#define E1000_DEV_ID_82541EI             0x1013
-#define E1000_DEV_ID_82541EI_MOBILE      0x1018
-#define E1000_DEV_ID_82541ER_LOM         0x1014
-#define E1000_DEV_ID_82541ER             0x1078
-#define E1000_DEV_ID_82547GI             0x1075
-#define E1000_DEV_ID_82541GI             0x1076
-#define E1000_DEV_ID_82541GI_MOBILE      0x1077
-#define E1000_DEV_ID_82541GI_LF          0x107C
-#define E1000_DEV_ID_82546GB_COPPER      0x1079
-#define E1000_DEV_ID_82546GB_FIBER       0x107A
-#define E1000_DEV_ID_82546GB_SERDES      0x107B
-#define E1000_DEV_ID_82546GB_PCIE        0x108A
-#define E1000_DEV_ID_82546GB_QUAD_COPPER 0x1099
-#define E1000_DEV_ID_82547EI             0x1019
-#define E1000_DEV_ID_82547EI_MOBILE      0x101A
-#define E1000_DEV_ID_82571EB_COPPER      0x105E
-#define E1000_DEV_ID_82571EB_FIBER       0x105F
-#define E1000_DEV_ID_82571EB_SERDES      0x1060
-#define E1000_DEV_ID_82571EB_QUAD_COPPER 0x10A4
-#define E1000_DEV_ID_82571PT_QUAD_COPPER 0x10D5
-#define E1000_DEV_ID_82571EB_QUAD_FIBER  0x10A5
-#define E1000_DEV_ID_82571EB_QUAD_COPPER_LOWPROFILE  0x10BC
-#define E1000_DEV_ID_82571EB_SERDES_DUAL 0x10D9
-#define E1000_DEV_ID_82571EB_SERDES_QUAD 0x10DA
-#define E1000_DEV_ID_82572EI_COPPER      0x107D
-#define E1000_DEV_ID_82572EI_FIBER       0x107E
-#define E1000_DEV_ID_82572EI_SERDES      0x107F
-#define E1000_DEV_ID_82572EI             0x10B9
-#define E1000_DEV_ID_82573E              0x108B
-#define E1000_DEV_ID_82573E_IAMT         0x108C
-#define E1000_DEV_ID_82573L              0x109A
-#define E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3 0x10B5
-#define E1000_DEV_ID_80003ES2LAN_COPPER_DPT     0x1096
-#define E1000_DEV_ID_80003ES2LAN_SERDES_DPT     0x1098
-#define E1000_DEV_ID_80003ES2LAN_COPPER_SPT     0x10BA
-#define E1000_DEV_ID_80003ES2LAN_SERDES_SPT     0x10BB
-
-#define E1000_DEV_ID_ICH8_IGP_M_AMT      0x1049
-#define E1000_DEV_ID_ICH8_IGP_AMT        0x104A
-#define E1000_DEV_ID_ICH8_IGP_C          0x104B
-#define E1000_DEV_ID_ICH8_IFE            0x104C
-#define E1000_DEV_ID_ICH8_IFE_GT         0x10C4
-#define E1000_DEV_ID_ICH8_IFE_G          0x10C5
-#define E1000_DEV_ID_ICH8_IGP_M          0x104D
-
-/* Register Set. (82543, 82544)
- *
- * Registers are defined to be 32 bits and  should be accessed as 32 bit values.
- * These registers are physically located on the NIC, but are mapped into the
- * host memory address space.
- *
- * RW - register is both readable and writable
- * RO - register is read only
- * WO - register is write only
- * R/clr - register is read only and is cleared when read
- * A - register array
- */
-#define E1000_CTRL     0x00000  /* Device Control - RW */
-#define E1000_CTRL_DUP 0x00004  /* Device Control Duplicate (Shadow) - RW */
-#define E1000_STATUS   0x00008  /* Device Status - RO */
-#define E1000_EECD     0x00010  /* EEPROM/Flash Control - RW */
-#define E1000_EERD     0x00014  /* EEPROM Read - RW */
-#define E1000_CTRL_EXT 0x00018  /* Extended Device Control - RW */
-#define E1000_FLA      0x0001C  /* Flash Access - RW */
-#define E1000_MDIC     0x00020  /* MDI Control - RW */
-#define E1000_SCTL     0x00024  /* SerDes Control - RW */
-#define E1000_FEXTNVM  0x00028  /* Future Extended NVM register */
-#define E1000_FCAL     0x00028  /* Flow Control Address Low - RW */
-#define E1000_FCAH     0x0002C  /* Flow Control Address High -RW */
-#define E1000_FCT      0x00030  /* Flow Control Type - RW */
-#define E1000_VET      0x00038  /* VLAN Ether Type - RW */
-#define E1000_ICR      0x000C0  /* Interrupt Cause Read - R/clr */
-#define E1000_ITR      0x000C4  /* Interrupt Throttling Rate - RW */
-#define E1000_ICS      0x000C8  /* Interrupt Cause Set - WO */
-#define E1000_IMS      0x000D0  /* Interrupt Mask Set - RW */
-#define E1000_IMC      0x000D8  /* Interrupt Mask Clear - WO */
-#define E1000_IAM      0x000E0  /* Interrupt Acknowledge Auto Mask */
-#define E1000_RCTL     0x00100  /* RX Control - RW */
-#define E1000_RDTR1    0x02820  /* RX Delay Timer (1) - RW */
-#define E1000_RDBAL1   0x02900  /* RX Descriptor Base Address Low (1) - RW */
-#define E1000_RDBAH1   0x02904  /* RX Descriptor Base Address High (1) - RW */
-#define E1000_RDLEN1   0x02908  /* RX Descriptor Length (1) - RW */
-#define E1000_RDH1     0x02910  /* RX Descriptor Head (1) - RW */
-#define E1000_RDT1     0x02918  /* RX Descriptor Tail (1) - RW */
-#define E1000_FCTTV    0x00170  /* Flow Control Transmit Timer Value - RW */
-#define E1000_TXCW     0x00178  /* TX Configuration Word - RW */
-#define E1000_RXCW     0x00180  /* RX Configuration Word - RO */
-#define E1000_TCTL     0x00400  /* TX Control - RW */
-#define E1000_TCTL_EXT 0x00404  /* Extended TX Control - RW */
-#define E1000_TIPG     0x00410  /* TX Inter-packet gap -RW */
-#define E1000_TBT      0x00448  /* TX Burst Timer - RW */
-#define E1000_AIT      0x00458  /* Adaptive Interframe Spacing Throttle - RW */
-#define E1000_LEDCTL   0x00E00  /* LED Control - RW */
-#define E1000_EXTCNF_CTRL  0x00F00  /* Extended Configuration Control */
-#define E1000_EXTCNF_SIZE  0x00F08  /* Extended Configuration Size */
-#define E1000_PHY_CTRL     0x00F10  /* PHY Control Register in CSR */
-#define FEXTNVM_SW_CONFIG  0x0001
-#define E1000_PBA      0x01000  /* Packet Buffer Allocation - RW */
-#define E1000_PBS      0x01008  /* Packet Buffer Size */
-#define E1000_EEMNGCTL 0x01010  /* MNG EEprom Control */
-#define E1000_FLASH_UPDATES 1000
-#define E1000_EEARBC   0x01024  /* EEPROM Auto Read Bus Control */
-#define E1000_FLASHT   0x01028  /* FLASH Timer Register */
-#define E1000_EEWR     0x0102C  /* EEPROM Write Register - RW */
-#define E1000_FLSWCTL  0x01030  /* FLASH control register */
-#define E1000_FLSWDATA 0x01034  /* FLASH data register */
-#define E1000_FLSWCNT  0x01038  /* FLASH Access Counter */
-#define E1000_FLOP     0x0103C  /* FLASH Opcode Register */
-#define E1000_ERT      0x02008  /* Early Rx Threshold - RW */
-#define E1000_FCRTL    0x02160  /* Flow Control Receive Threshold Low - RW */
-#define E1000_FCRTH    0x02168  /* Flow Control Receive Threshold High - RW */
-#define E1000_PSRCTL   0x02170  /* Packet Split Receive Control - RW */
-#define E1000_RDBAL    0x02800  /* RX Descriptor Base Address Low - RW */
-#define E1000_RDBAH    0x02804  /* RX Descriptor Base Address High - RW */
-#define E1000_RDLEN    0x02808  /* RX Descriptor Length - RW */
-#define E1000_RDH      0x02810  /* RX Descriptor Head - RW */
-#define E1000_RDT      0x02818  /* RX Descriptor Tail - RW */
-#define E1000_RDTR     0x02820  /* RX Delay Timer - RW */
-#define E1000_RDBAL0   E1000_RDBAL /* RX Desc Base Address Low (0) - RW */
-#define E1000_RDBAH0   E1000_RDBAH /* RX Desc Base Address High (0) - RW */
-#define E1000_RDLEN0   E1000_RDLEN /* RX Desc Length (0) - RW */
-#define E1000_RDH0     E1000_RDH   /* RX Desc Head (0) - RW */
-#define E1000_RDT0     E1000_RDT   /* RX Desc Tail (0) - RW */
-#define E1000_RDTR0    E1000_RDTR  /* RX Delay Timer (0) - RW */
-#define E1000_RXDCTL   0x02828  /* RX Descriptor Control queue 0 - RW */
-#define E1000_RXDCTL1  0x02928  /* RX Descriptor Control queue 1 - RW */
-#define E1000_RADV     0x0282C  /* RX Interrupt Absolute Delay Timer - RW */
-#define E1000_RSRPD    0x02C00  /* RX Small Packet Detect - RW */
-#define E1000_RAID     0x02C08  /* Receive Ack Interrupt Delay - RW */
-#define E1000_TXDMAC   0x03000  /* TX DMA Control - RW */
-#define E1000_KABGTXD  0x03004  /* AFE Band Gap Transmit Ref Data */
-#define E1000_TDFH     0x03410  /* TX Data FIFO Head - RW */
-#define E1000_TDFT     0x03418  /* TX Data FIFO Tail - RW */
-#define E1000_TDFHS    0x03420  /* TX Data FIFO Head Saved - RW */
-#define E1000_TDFTS    0x03428  /* TX Data FIFO Tail Saved - RW */
-#define E1000_TDFPC    0x03430  /* TX Data FIFO Packet Count - RW */
-#define E1000_TDBAL    0x03800  /* TX Descriptor Base Address Low - RW */
-#define E1000_TDBAH    0x03804  /* TX Descriptor Base Address High - RW */
-#define E1000_TDLEN    0x03808  /* TX Descriptor Length - RW */
-#define E1000_TDH      0x03810  /* TX Descriptor Head - RW */
-#define E1000_TDT      0x03818  /* TX Descripotr Tail - RW */
-#define E1000_TIDV     0x03820  /* TX Interrupt Delay Value - RW */
-#define E1000_TXDCTL   0x03828  /* TX Descriptor Control - RW */
-#define E1000_TADV     0x0382C  /* TX Interrupt Absolute Delay Val - RW */
-#define E1000_TSPMT    0x03830  /* TCP Segmentation PAD & Min Threshold - RW */
-#define E1000_TARC0    0x03840  /* TX Arbitration Count (0) */
-#define E1000_TDBAL1   0x03900  /* TX Desc Base Address Low (1) - RW */
-#define E1000_TDBAH1   0x03904  /* TX Desc Base Address High (1) - RW */
-#define E1000_TDLEN1   0x03908  /* TX Desc Length (1) - RW */
-#define E1000_TDH1     0x03910  /* TX Desc Head (1) - RW */
-#define E1000_TDT1     0x03918  /* TX Desc Tail (1) - RW */
-#define E1000_TXDCTL1  0x03928  /* TX Descriptor Control (1) - RW */
-#define E1000_TARC1    0x03940  /* TX Arbitration Count (1) */
-#define E1000_CRCERRS  0x04000  /* CRC Error Count - R/clr */
-#define E1000_ALGNERRC 0x04004  /* Alignment Error Count - R/clr */
-#define E1000_SYMERRS  0x04008  /* Symbol Error Count - R/clr */
-#define E1000_RXERRC   0x0400C  /* Receive Error Count - R/clr */
-#define E1000_MPC      0x04010  /* Missed Packet Count - R/clr */
-#define E1000_SCC      0x04014  /* Single Collision Count - R/clr */
-#define E1000_ECOL     0x04018  /* Excessive Collision Count - R/clr */
-#define E1000_MCC      0x0401C  /* Multiple Collision Count - R/clr */
-#define E1000_LATECOL  0x04020  /* Late Collision Count - R/clr */
-#define E1000_COLC     0x04028  /* Collision Count - R/clr */
-#define E1000_DC       0x04030  /* Defer Count - R/clr */
-#define E1000_TNCRS    0x04034  /* TX-No CRS - R/clr */
-#define E1000_SEC      0x04038  /* Sequence Error Count - R/clr */
-#define E1000_CEXTERR  0x0403C  /* Carrier Extension Error Count - R/clr */
-#define E1000_RLEC     0x04040  /* Receive Length Error Count - R/clr */
-#define E1000_XONRXC   0x04048  /* XON RX Count - R/clr */
-#define E1000_XONTXC   0x0404C  /* XON TX Count - R/clr */
-#define E1000_XOFFRXC  0x04050  /* XOFF RX Count - R/clr */
-#define E1000_XOFFTXC  0x04054  /* XOFF TX Count - R/clr */
-#define E1000_FCRUC    0x04058  /* Flow Control RX Unsupported Count- R/clr */
-#define E1000_PRC64    0x0405C  /* Packets RX (64 bytes) - R/clr */
-#define E1000_PRC127   0x04060  /* Packets RX (65-127 bytes) - R/clr */
-#define E1000_PRC255   0x04064  /* Packets RX (128-255 bytes) - R/clr */
-#define E1000_PRC511   0x04068  /* Packets RX (255-511 bytes) - R/clr */
-#define E1000_PRC1023  0x0406C  /* Packets RX (512-1023 bytes) - R/clr */
-#define E1000_PRC1522  0x04070  /* Packets RX (1024-1522 bytes) - R/clr */
-#define E1000_GPRC     0x04074  /* Good Packets RX Count - R/clr */
-#define E1000_BPRC     0x04078  /* Broadcast Packets RX Count - R/clr */
-#define E1000_MPRC     0x0407C  /* Multicast Packets RX Count - R/clr */
-#define E1000_GPTC     0x04080  /* Good Packets TX Count - R/clr */
-#define E1000_GORCL    0x04088  /* Good Octets RX Count Low - R/clr */
-#define E1000_GORCH    0x0408C  /* Good Octets RX Count High - R/clr */
-#define E1000_GOTCL    0x04090  /* Good Octets TX Count Low - R/clr */
-#define E1000_GOTCH    0x04094  /* Good Octets TX Count High - R/clr */
-#define E1000_RNBC     0x040A0  /* RX No Buffers Count - R/clr */
-#define E1000_RUC      0x040A4  /* RX Undersize Count - R/clr */
-#define E1000_RFC      0x040A8  /* RX Fragment Count - R/clr */
-#define E1000_ROC      0x040AC  /* RX Oversize Count - R/clr */
-#define E1000_RJC      0x040B0  /* RX Jabber Count - R/clr */
-#define E1000_MGTPRC   0x040B4  /* Management Packets RX Count - R/clr */
-#define E1000_MGTPDC   0x040B8  /* Management Packets Dropped Count - R/clr */
-#define E1000_MGTPTC   0x040BC  /* Management Packets TX Count - R/clr */
-#define E1000_TORL     0x040C0  /* Total Octets RX Low - R/clr */
-#define E1000_TORH     0x040C4  /* Total Octets RX High - R/clr */
-#define E1000_TOTL     0x040C8  /* Total Octets TX Low - R/clr */
-#define E1000_TOTH     0x040CC  /* Total Octets TX High - R/clr */
-#define E1000_TPR      0x040D0  /* Total Packets RX - R/clr */
-#define E1000_TPT      0x040D4  /* Total Packets TX - R/clr */
-#define E1000_PTC64    0x040D8  /* Packets TX (64 bytes) - R/clr */
-#define E1000_PTC127   0x040DC  /* Packets TX (65-127 bytes) - R/clr */
-#define E1000_PTC255   0x040E0  /* Packets TX (128-255 bytes) - R/clr */
-#define E1000_PTC511   0x040E4  /* Packets TX (256-511 bytes) - R/clr */
-#define E1000_PTC1023  0x040E8  /* Packets TX (512-1023 bytes) - R/clr */
-#define E1000_PTC1522  0x040EC  /* Packets TX (1024-1522 Bytes) - R/clr */
-#define E1000_MPTC     0x040F0  /* Multicast Packets TX Count - R/clr */
-#define E1000_BPTC     0x040F4  /* Broadcast Packets TX Count - R/clr */
-#define E1000_TSCTC    0x040F8  /* TCP Segmentation Context TX - R/clr */
-#define E1000_TSCTFC   0x040FC  /* TCP Segmentation Context TX Fail - R/clr */
-#define E1000_IAC      0x04100  /* Interrupt Assertion Count */
-#define E1000_ICRXPTC  0x04104  /* Interrupt Cause Rx Packet Timer Expire Count */
-#define E1000_ICRXATC  0x04108  /* Interrupt Cause Rx Absolute Timer Expire Count */
-#define E1000_ICTXPTC  0x0410C  /* Interrupt Cause Tx Packet Timer Expire Count */
-#define E1000_ICTXATC  0x04110  /* Interrupt Cause Tx Absolute Timer Expire Count */
-#define E1000_ICTXQEC  0x04118  /* Interrupt Cause Tx Queue Empty Count */
-#define E1000_ICTXQMTC 0x0411C  /* Interrupt Cause Tx Queue Minimum Threshold Count */
-#define E1000_ICRXDMTC 0x04120  /* Interrupt Cause Rx Descriptor Minimum Threshold Count */
-#define E1000_ICRXOC   0x04124  /* Interrupt Cause Receiver Overrun Count */
-#define E1000_RXCSUM   0x05000  /* RX Checksum Control - RW */
-#define E1000_RFCTL    0x05008  /* Receive Filter Control*/
-#define E1000_MTA      0x05200  /* Multicast Table Array - RW Array */
-#define E1000_RA       0x05400  /* Receive Address - RW Array */
-#define E1000_VFTA     0x05600  /* VLAN Filter Table Array - RW Array */
-#define E1000_WUC      0x05800  /* Wakeup Control - RW */
-#define E1000_WUFC     0x05808  /* Wakeup Filter Control - RW */
-#define E1000_WUS      0x05810  /* Wakeup Status - RO */
-#define E1000_MANC     0x05820  /* Management Control - RW */
-#define E1000_IPAV     0x05838  /* IP Address Valid - RW */
-#define E1000_IP4AT    0x05840  /* IPv4 Address Table - RW Array */
-#define E1000_IP6AT    0x05880  /* IPv6 Address Table - RW Array */
-#define E1000_WUPL     0x05900  /* Wakeup Packet Length - RW */
-#define E1000_WUPM     0x05A00  /* Wakeup Packet Memory - RO A */
-#define E1000_FFLT     0x05F00  /* Flexible Filter Length Table - RW Array */
-#define E1000_HOST_IF  0x08800  /* Host Interface */
-#define E1000_FFMT     0x09000  /* Flexible Filter Mask Table - RW Array */
-#define E1000_FFVT     0x09800  /* Flexible Filter Value Table - RW Array */
-
-#define E1000_KUMCTRLSTA 0x00034 /* MAC-PHY interface - RW */
-#define E1000_MDPHYA     0x0003C  /* PHY address - RW */
-#define E1000_MANC2H     0x05860  /* Management Control To Host - RW */
-#define E1000_SW_FW_SYNC 0x05B5C /* Software-Firmware Synchronization - RW */
-
-#define E1000_GCR       0x05B00 /* PCI-Ex Control */
-#define E1000_GSCL_1    0x05B10 /* PCI-Ex Statistic Control #1 */
-#define E1000_GSCL_2    0x05B14 /* PCI-Ex Statistic Control #2 */
-#define E1000_GSCL_3    0x05B18 /* PCI-Ex Statistic Control #3 */
-#define E1000_GSCL_4    0x05B1C /* PCI-Ex Statistic Control #4 */
-#define E1000_FACTPS    0x05B30 /* Function Active and Power State to MNG */
-#define E1000_SWSM      0x05B50 /* SW Semaphore */
-#define E1000_FWSM      0x05B54 /* FW Semaphore */
-#define E1000_FFLT_DBG  0x05F04 /* Debug Register */
-#define E1000_HICR      0x08F00 /* Host Inteface Control */
-
-/* RSS registers */
-#define E1000_CPUVEC    0x02C10 /* CPU Vector Register - RW */
-#define E1000_MRQC      0x05818 /* Multiple Receive Control - RW */
-#define E1000_RETA      0x05C00 /* Redirection Table - RW Array */
-#define E1000_RSSRK     0x05C80 /* RSS Random Key - RW Array */
-#define E1000_RSSIM     0x05864 /* RSS Interrupt Mask */
-#define E1000_RSSIR     0x05868 /* RSS Interrupt Request */
-
-/* PHY 1000 MII Register/Bit Definitions */
-/* PHY Registers defined by IEEE */
-#define PHY_CTRL         0x00 /* Control Register */
-#define PHY_STATUS       0x01 /* Status Regiser */
-#define PHY_ID1          0x02 /* Phy Id Reg (word 1) */
-#define PHY_ID2          0x03 /* Phy Id Reg (word 2) */
-#define PHY_AUTONEG_ADV  0x04 /* Autoneg Advertisement */
-#define PHY_LP_ABILITY   0x05 /* Link Partner Ability (Base Page) */
-#define PHY_AUTONEG_EXP  0x06 /* Autoneg Expansion Reg */
-#define PHY_NEXT_PAGE_TX 0x07 /* Next Page TX */
-#define PHY_LP_NEXT_PAGE 0x08 /* Link Partner Next Page */
-#define PHY_1000T_CTRL   0x09 /* 1000Base-T Control Reg */
-#define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */
-#define PHY_EXT_STATUS   0x0F /* Extended Status Reg */
-
-#define MAX_PHY_REG_ADDRESS        0x1F  /* 5 bit address bus (0-0x1F) */
-#define MAX_PHY_MULTI_PAGE_REG     0xF   /* Registers equal on all pages */
-
-/* M88E1000 Specific Registers */
-#define M88E1000_PHY_SPEC_CTRL     0x10  /* PHY Specific Control Register */
-#define M88E1000_PHY_SPEC_STATUS   0x11  /* PHY Specific Status Register */
-#define M88E1000_INT_ENABLE        0x12  /* Interrupt Enable Register */
-#define M88E1000_INT_STATUS        0x13  /* Interrupt Status Register */
-#define M88E1000_EXT_PHY_SPEC_CTRL 0x14  /* Extended PHY Specific Control */
-#define M88E1000_RX_ERR_CNTR       0x15  /* Receive Error Counter */
-
-#define M88E1000_PHY_EXT_CTRL      0x1A  /* PHY extend control register */
-#define M88E1000_PHY_PAGE_SELECT   0x1D  /* Reg 29 for page number setting */
-#define M88E1000_PHY_GEN_CONTROL   0x1E  /* Its meaning depends on reg 29 */
-#define M88E1000_PHY_VCO_REG_BIT8  0x100 /* Bits 8 & 11 are adjusted for */
-#define M88E1000_PHY_VCO_REG_BIT11 0x800    /* improved BER performance */
-
-/* PHY Control Register */
-#define MII_CR_SPEED_SELECT_MSB 0x0040 /* bits 6,13: 10=1000, 01=100, 00=10 */
-#define MII_CR_COLL_TEST_ENABLE 0x0080 /* Collision test enable */
-#define MII_CR_FULL_DUPLEX      0x0100 /* FDX =1, half duplex =0 */
-#define MII_CR_RESTART_AUTO_NEG 0x0200 /* Restart auto negotiation */
-#define MII_CR_ISOLATE          0x0400 /* Isolate PHY from MII */
-#define MII_CR_POWER_DOWN       0x0800 /* Power down */
-#define MII_CR_AUTO_NEG_EN      0x1000 /* Auto Neg Enable */
-#define MII_CR_SPEED_SELECT_LSB 0x2000 /* bits 6,13: 10=1000, 01=100, 00=10 */
-#define MII_CR_LOOPBACK         0x4000 /* 0 = normal, 1 = loopback */
-#define MII_CR_RESET            0x8000 /* 0 = normal, 1 = PHY reset */
-
-/* PHY Status Register */
-#define MII_SR_EXTENDED_CAPS     0x0001        /* Extended register capabilities */
-#define MII_SR_JABBER_DETECT     0x0002        /* Jabber Detected */
-#define MII_SR_LINK_STATUS       0x0004        /* Link Status 1 = link */
-#define MII_SR_AUTONEG_CAPS      0x0008        /* Auto Neg Capable */
-#define MII_SR_REMOTE_FAULT      0x0010        /* Remote Fault Detect */
-#define MII_SR_AUTONEG_COMPLETE  0x0020        /* Auto Neg Complete */
-#define MII_SR_PREAMBLE_SUPPRESS 0x0040        /* Preamble may be suppressed */
-#define MII_SR_EXTENDED_STATUS   0x0100        /* Ext. status info in Reg 0x0F */
-#define MII_SR_100T2_HD_CAPS     0x0200        /* 100T2 Half Duplex Capable */
-#define MII_SR_100T2_FD_CAPS     0x0400        /* 100T2 Full Duplex Capable */
-#define MII_SR_10T_HD_CAPS       0x0800        /* 10T   Half Duplex Capable */
-#define MII_SR_10T_FD_CAPS       0x1000        /* 10T   Full Duplex Capable */
-#define MII_SR_100X_HD_CAPS      0x2000        /* 100X  Half Duplex Capable */
-#define MII_SR_100X_FD_CAPS      0x4000        /* 100X  Full Duplex Capable */
-#define MII_SR_100T4_CAPS        0x8000        /* 100T4 Capable */
-
-/* Interrupt Cause Read */
-#define E1000_ICR_TXDW          0x00000001 /* Transmit desc written back */
-#define E1000_ICR_TXQE          0x00000002 /* Transmit Queue empty */
-#define E1000_ICR_LSC           0x00000004 /* Link Status Change */
-#define E1000_ICR_RXSEQ         0x00000008 /* rx sequence error */
-#define E1000_ICR_RXDMT0        0x00000010 /* rx desc min. threshold (0) */
-#define E1000_ICR_RXO           0x00000040 /* rx overrun */
-#define E1000_ICR_RXT0          0x00000080 /* rx timer intr (ring 0) */
-#define E1000_ICR_MDAC          0x00000200 /* MDIO access complete */
-#define E1000_ICR_RXCFG         0x00000400 /* RX /c/ ordered set */
-#define E1000_ICR_GPI_EN0       0x00000800 /* GP Int 0 */
-#define E1000_ICR_GPI_EN1       0x00001000 /* GP Int 1 */
-#define E1000_ICR_GPI_EN2       0x00002000 /* GP Int 2 */
-#define E1000_ICR_GPI_EN3       0x00004000 /* GP Int 3 */
-#define E1000_ICR_TXD_LOW       0x00008000
-#define E1000_ICR_SRPD          0x00010000
-#define E1000_ICR_ACK           0x00020000 /* Receive Ack frame */
-#define E1000_ICR_MNG           0x00040000 /* Manageability event */
-#define E1000_ICR_DOCK          0x00080000 /* Dock/Undock */
-#define E1000_ICR_INT_ASSERTED  0x80000000 /* If this bit asserted, the driver should claim the interrupt */
-#define E1000_ICR_RXD_FIFO_PAR0 0x00100000 /* queue 0 Rx descriptor FIFO parity error */
-#define E1000_ICR_TXD_FIFO_PAR0 0x00200000 /* queue 0 Tx descriptor FIFO parity error */
-#define E1000_ICR_HOST_ARB_PAR  0x00400000 /* host arb read buffer parity error */
-#define E1000_ICR_PB_PAR        0x00800000 /* packet buffer parity error */
-#define E1000_ICR_RXD_FIFO_PAR1 0x01000000 /* queue 1 Rx descriptor FIFO parity error */
-#define E1000_ICR_TXD_FIFO_PAR1 0x02000000 /* queue 1 Tx descriptor FIFO parity error */
-#define E1000_ICR_ALL_PARITY    0x03F00000 /* all parity error bits */
-#define E1000_ICR_DSW           0x00000020 /* FW changed the status of DISSW bit in the FWSM */
-#define E1000_ICR_PHYINT        0x00001000 /* LAN connected device generates an interrupt */
-#define E1000_ICR_EPRST         0x00100000 /* ME handware reset occurs */
-
-/* Interrupt Cause Set */
-#define E1000_ICS_TXDW      E1000_ICR_TXDW      /* Transmit desc written back */
-#define E1000_ICS_TXQE      E1000_ICR_TXQE      /* Transmit Queue empty */
-#define E1000_ICS_LSC       E1000_ICR_LSC       /* Link Status Change */
-#define E1000_ICS_RXSEQ     E1000_ICR_RXSEQ     /* rx sequence error */
-#define E1000_ICS_RXDMT0    E1000_ICR_RXDMT0    /* rx desc min. threshold */
-#define E1000_ICS_RXO       E1000_ICR_RXO       /* rx overrun */
-#define E1000_ICS_RXT0      E1000_ICR_RXT0      /* rx timer intr */
-#define E1000_ICS_MDAC      E1000_ICR_MDAC      /* MDIO access complete */
-#define E1000_ICS_RXCFG     E1000_ICR_RXCFG     /* RX /c/ ordered set */
-#define E1000_ICS_GPI_EN0   E1000_ICR_GPI_EN0   /* GP Int 0 */
-#define E1000_ICS_GPI_EN1   E1000_ICR_GPI_EN1   /* GP Int 1 */
-#define E1000_ICS_GPI_EN2   E1000_ICR_GPI_EN2   /* GP Int 2 */
-#define E1000_ICS_GPI_EN3   E1000_ICR_GPI_EN3   /* GP Int 3 */
-#define E1000_ICS_TXD_LOW   E1000_ICR_TXD_LOW
-#define E1000_ICS_SRPD      E1000_ICR_SRPD
-#define E1000_ICS_ACK       E1000_ICR_ACK       /* Receive Ack frame */
-#define E1000_ICS_MNG       E1000_ICR_MNG       /* Manageability event */
-#define E1000_ICS_DOCK      E1000_ICR_DOCK      /* Dock/Undock */
-#define E1000_ICS_RXD_FIFO_PAR0 E1000_ICR_RXD_FIFO_PAR0 /* queue 0 Rx descriptor FIFO parity error */
-#define E1000_ICS_TXD_FIFO_PAR0 E1000_ICR_TXD_FIFO_PAR0 /* queue 0 Tx descriptor FIFO parity error */
-#define E1000_ICS_HOST_ARB_PAR  E1000_ICR_HOST_ARB_PAR  /* host arb read buffer parity error */
-#define E1000_ICS_PB_PAR        E1000_ICR_PB_PAR        /* packet buffer parity error */
-#define E1000_ICS_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* queue 1 Rx descriptor FIFO parity error */
-#define E1000_ICS_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* queue 1 Tx descriptor FIFO parity error */
-#define E1000_ICS_DSW       E1000_ICR_DSW
-#define E1000_ICS_PHYINT    E1000_ICR_PHYINT
-#define E1000_ICS_EPRST     E1000_ICR_EPRST
-
-/* Interrupt Mask Set */
-#define E1000_IMS_TXDW      E1000_ICR_TXDW      /* Transmit desc written back */
-#define E1000_IMS_TXQE      E1000_ICR_TXQE      /* Transmit Queue empty */
-#define E1000_IMS_LSC       E1000_ICR_LSC       /* Link Status Change */
-#define E1000_IMS_RXSEQ     E1000_ICR_RXSEQ     /* rx sequence error */
-#define E1000_IMS_RXDMT0    E1000_ICR_RXDMT0    /* rx desc min. threshold */
-#define E1000_IMS_RXO       E1000_ICR_RXO       /* rx overrun */
-#define E1000_IMS_RXT0      E1000_ICR_RXT0      /* rx timer intr */
-#define E1000_IMS_MDAC      E1000_ICR_MDAC      /* MDIO access complete */
-#define E1000_IMS_RXCFG     E1000_ICR_RXCFG     /* RX /c/ ordered set */
-#define E1000_IMS_GPI_EN0   E1000_ICR_GPI_EN0   /* GP Int 0 */
-#define E1000_IMS_GPI_EN1   E1000_ICR_GPI_EN1   /* GP Int 1 */
-#define E1000_IMS_GPI_EN2   E1000_ICR_GPI_EN2   /* GP Int 2 */
-#define E1000_IMS_GPI_EN3   E1000_ICR_GPI_EN3   /* GP Int 3 */
-#define E1000_IMS_TXD_LOW   E1000_ICR_TXD_LOW
-#define E1000_IMS_SRPD      E1000_ICR_SRPD
-#define E1000_IMS_ACK       E1000_ICR_ACK       /* Receive Ack frame */
-#define E1000_IMS_MNG       E1000_ICR_MNG       /* Manageability event */
-#define E1000_IMS_DOCK      E1000_ICR_DOCK      /* Dock/Undock */
-#define E1000_IMS_RXD_FIFO_PAR0 E1000_ICR_RXD_FIFO_PAR0 /* queue 0 Rx descriptor FIFO parity error */
-#define E1000_IMS_TXD_FIFO_PAR0 E1000_ICR_TXD_FIFO_PAR0 /* queue 0 Tx descriptor FIFO parity error */
-#define E1000_IMS_HOST_ARB_PAR  E1000_ICR_HOST_ARB_PAR  /* host arb read buffer parity error */
-#define E1000_IMS_PB_PAR        E1000_ICR_PB_PAR        /* packet buffer parity error */
-#define E1000_IMS_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* queue 1 Rx descriptor FIFO parity error */
-#define E1000_IMS_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* queue 1 Tx descriptor FIFO parity error */
-#define E1000_IMS_DSW       E1000_ICR_DSW
-#define E1000_IMS_PHYINT    E1000_ICR_PHYINT
-#define E1000_IMS_EPRST     E1000_ICR_EPRST
-
-/* Interrupt Mask Clear */
-#define E1000_IMC_TXDW      E1000_ICR_TXDW      /* Transmit desc written back */
-#define E1000_IMC_TXQE      E1000_ICR_TXQE      /* Transmit Queue empty */
-#define E1000_IMC_LSC       E1000_ICR_LSC       /* Link Status Change */
-#define E1000_IMC_RXSEQ     E1000_ICR_RXSEQ     /* rx sequence error */
-#define E1000_IMC_RXDMT0    E1000_ICR_RXDMT0    /* rx desc min. threshold */
-#define E1000_IMC_RXO       E1000_ICR_RXO       /* rx overrun */
-#define E1000_IMC_RXT0      E1000_ICR_RXT0      /* rx timer intr */
-#define E1000_IMC_MDAC      E1000_ICR_MDAC      /* MDIO access complete */
-#define E1000_IMC_RXCFG     E1000_ICR_RXCFG     /* RX /c/ ordered set */
-#define E1000_IMC_GPI_EN0   E1000_ICR_GPI_EN0   /* GP Int 0 */
-#define E1000_IMC_GPI_EN1   E1000_ICR_GPI_EN1   /* GP Int 1 */
-#define E1000_IMC_GPI_EN2   E1000_ICR_GPI_EN2   /* GP Int 2 */
-#define E1000_IMC_GPI_EN3   E1000_ICR_GPI_EN3   /* GP Int 3 */
-#define E1000_IMC_TXD_LOW   E1000_ICR_TXD_LOW
-#define E1000_IMC_SRPD      E1000_ICR_SRPD
-#define E1000_IMC_ACK       E1000_ICR_ACK       /* Receive Ack frame */
-#define E1000_IMC_MNG       E1000_ICR_MNG       /* Manageability event */
-#define E1000_IMC_DOCK      E1000_ICR_DOCK      /* Dock/Undock */
-#define E1000_IMC_RXD_FIFO_PAR0 E1000_ICR_RXD_FIFO_PAR0 /* queue 0 Rx descriptor FIFO parity error */
-#define E1000_IMC_TXD_FIFO_PAR0 E1000_ICR_TXD_FIFO_PAR0 /* queue 0 Tx descriptor FIFO parity error */
-#define E1000_IMC_HOST_ARB_PAR  E1000_ICR_HOST_ARB_PAR  /* host arb read buffer parity error */
-#define E1000_IMC_PB_PAR        E1000_ICR_PB_PAR        /* packet buffer parity error */
-#define E1000_IMC_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* queue 1 Rx descriptor FIFO parity error */
-#define E1000_IMC_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* queue 1 Tx descriptor FIFO parity error */
-#define E1000_IMC_DSW       E1000_ICR_DSW
-#define E1000_IMC_PHYINT    E1000_ICR_PHYINT
-#define E1000_IMC_EPRST     E1000_ICR_EPRST
-
-/* Receive Control */
-#define E1000_RCTL_RST            0x00000001    /* Software reset */
-#define E1000_RCTL_EN             0x00000002    /* enable */
-#define E1000_RCTL_SBP            0x00000004    /* store bad packet */
-#define E1000_RCTL_UPE            0x00000008    /* unicast promiscuous enable */
-#define E1000_RCTL_MPE            0x00000010    /* multicast promiscuous enab */
-#define E1000_RCTL_LPE            0x00000020    /* long packet enable */
-#define E1000_RCTL_LBM_NO         0x00000000    /* no loopback mode */
-#define E1000_RCTL_LBM_MAC        0x00000040    /* MAC loopback mode */
-#define E1000_RCTL_LBM_SLP        0x00000080    /* serial link loopback mode */
-#define E1000_RCTL_LBM_TCVR       0x000000C0    /* tcvr loopback mode */
-#define E1000_RCTL_DTYP_MASK      0x00000C00    /* Descriptor type mask */
-#define E1000_RCTL_DTYP_PS        0x00000400    /* Packet Split descriptor */
-#define E1000_RCTL_RDMTS_HALF     0x00000000    /* rx desc min threshold size */
-#define E1000_RCTL_RDMTS_QUAT     0x00000100    /* rx desc min threshold size */
-#define E1000_RCTL_RDMTS_EIGTH    0x00000200    /* rx desc min threshold size */
-#define E1000_RCTL_MO_SHIFT       12            /* multicast offset shift */
-#define E1000_RCTL_MO_0           0x00000000    /* multicast offset 11:0 */
-#define E1000_RCTL_MO_1           0x00001000    /* multicast offset 12:1 */
-#define E1000_RCTL_MO_2           0x00002000    /* multicast offset 13:2 */
-#define E1000_RCTL_MO_3           0x00003000    /* multicast offset 15:4 */
-#define E1000_RCTL_MDR            0x00004000    /* multicast desc ring 0 */
-#define E1000_RCTL_BAM            0x00008000    /* broadcast enable */
-/* these buffer sizes are valid if E1000_RCTL_BSEX is 0 */
-#define E1000_RCTL_SZ_2048        0x00000000    /* rx buffer size 2048 */
-#define E1000_RCTL_SZ_1024        0x00010000    /* rx buffer size 1024 */
-#define E1000_RCTL_SZ_512         0x00020000    /* rx buffer size 512 */
-#define E1000_RCTL_SZ_256         0x00030000    /* rx buffer size 256 */
-/* these buffer sizes are valid if E1000_RCTL_BSEX is 1 */
-#define E1000_RCTL_SZ_16384       0x00010000    /* rx buffer size 16384 */
-#define E1000_RCTL_SZ_8192        0x00020000    /* rx buffer size 8192 */
-#define E1000_RCTL_SZ_4096        0x00030000    /* rx buffer size 4096 */
-#define E1000_RCTL_VFE            0x00040000    /* vlan filter enable */
-#define E1000_RCTL_CFIEN          0x00080000    /* canonical form enable */
-#define E1000_RCTL_CFI            0x00100000    /* canonical form indicator */
-#define E1000_RCTL_DPF            0x00400000    /* discard pause frames */
-#define E1000_RCTL_PMCF           0x00800000    /* pass MAC control frames */
-#define E1000_RCTL_BSEX           0x02000000    /* Buffer size extension */
-#define E1000_RCTL_SECRC          0x04000000    /* Strip Ethernet CRC */
-#define E1000_RCTL_FLXBUF_MASK    0x78000000    /* Flexible buffer size */
-#define E1000_RCTL_FLXBUF_SHIFT   27            /* Flexible buffer shift */
-
-
-#define E1000_EEPROM_SWDPIN0   0x0001   /* SWDPIN 0 EEPROM Value */
-#define E1000_EEPROM_LED_LOGIC 0x0020   /* Led Logic Word */
-#define E1000_EEPROM_RW_REG_DATA   16   /* Offset to data in EEPROM read/write registers */
-#define E1000_EEPROM_RW_REG_DONE   0x10 /* Offset to READ/WRITE done bit */
-#define E1000_EEPROM_RW_REG_START  1    /* First bit for telling part to start operation */
-#define E1000_EEPROM_RW_ADDR_SHIFT 8    /* Shift to the address bits */
-#define E1000_EEPROM_POLL_WRITE    1    /* Flag for polling for write complete */
-#define E1000_EEPROM_POLL_READ     0    /* Flag for polling for read complete */
-/* Register Bit Masks */
-/* Device Control */
-#define E1000_CTRL_FD       0x00000001  /* Full duplex.0=half; 1=full */
-#define E1000_CTRL_BEM      0x00000002  /* Endian Mode.0=little,1=big */
-#define E1000_CTRL_PRIOR    0x00000004  /* Priority on PCI. 0=rx,1=fair */
-#define E1000_CTRL_GIO_MASTER_DISABLE 0x00000004 /*Blocks new Master requests */
-#define E1000_CTRL_LRST     0x00000008  /* Link reset. 0=normal,1=reset */
-#define E1000_CTRL_TME      0x00000010  /* Test mode. 0=normal,1=test */
-#define E1000_CTRL_SLE      0x00000020  /* Serial Link on 0=dis,1=en */
-#define E1000_CTRL_ASDE     0x00000020  /* Auto-speed detect enable */
-#define E1000_CTRL_SLU      0x00000040  /* Set link up (Force Link) */
-#define E1000_CTRL_ILOS     0x00000080  /* Invert Loss-Of Signal */
-#define E1000_CTRL_SPD_SEL  0x00000300  /* Speed Select Mask */
-#define E1000_CTRL_SPD_10   0x00000000  /* Force 10Mb */
-#define E1000_CTRL_SPD_100  0x00000100  /* Force 100Mb */
-#define E1000_CTRL_SPD_1000 0x00000200  /* Force 1Gb */
-#define E1000_CTRL_BEM32    0x00000400  /* Big Endian 32 mode */
-#define E1000_CTRL_FRCSPD   0x00000800  /* Force Speed */
-#define E1000_CTRL_FRCDPX   0x00001000  /* Force Duplex */
-#define E1000_CTRL_D_UD_EN  0x00002000  /* Dock/Undock enable */
-#define E1000_CTRL_D_UD_POLARITY 0x00004000 /* Defined polarity of Dock/Undock indication in SDP[0] */
-#define E1000_CTRL_FORCE_PHY_RESET 0x00008000 /* Reset both PHY ports, through PHYRST_N pin */
-#define E1000_CTRL_EXT_LINK_EN 0x00010000 /* enable link status from external LINK_0 and LINK_1 pins */
-#define E1000_CTRL_SWDPIN0  0x00040000  /* SWDPIN 0 value */
-#define E1000_CTRL_SWDPIN1  0x00080000  /* SWDPIN 1 value */
-#define E1000_CTRL_SWDPIN2  0x00100000  /* SWDPIN 2 value */
-#define E1000_CTRL_SWDPIN3  0x00200000  /* SWDPIN 3 value */
-#define E1000_CTRL_SWDPIO0  0x00400000  /* SWDPIN 0 Input or output */
-#define E1000_CTRL_SWDPIO1  0x00800000  /* SWDPIN 1 input or output */
-#define E1000_CTRL_SWDPIO2  0x01000000  /* SWDPIN 2 input or output */
-#define E1000_CTRL_SWDPIO3  0x02000000  /* SWDPIN 3 input or output */
-#define E1000_CTRL_RST      0x04000000  /* Global reset */
-#define E1000_CTRL_RFCE     0x08000000  /* Receive Flow Control enable */
-#define E1000_CTRL_TFCE     0x10000000  /* Transmit flow control enable */
-#define E1000_CTRL_RTE      0x20000000  /* Routing tag enable */
-#define E1000_CTRL_VME      0x40000000  /* IEEE VLAN mode enable */
-#define E1000_CTRL_PHY_RST  0x80000000  /* PHY Reset */
-#define E1000_CTRL_SW2FW_INT 0x02000000  /* Initiate an interrupt to manageability engine */
-
-/* Device Status */
-#define E1000_STATUS_FD         0x00000001      /* Full duplex.0=half,1=full */
-#define E1000_STATUS_LU         0x00000002      /* Link up.0=no,1=link */
-#define E1000_STATUS_FUNC_MASK  0x0000000C      /* PCI Function Mask */
-#define E1000_STATUS_FUNC_SHIFT 2
-#define E1000_STATUS_FUNC_0     0x00000000      /* Function 0 */
-#define E1000_STATUS_FUNC_1     0x00000004      /* Function 1 */
-#define E1000_STATUS_TXOFF      0x00000010      /* transmission paused */
-#define E1000_STATUS_TBIMODE    0x00000020      /* TBI mode */
-#define E1000_STATUS_SPEED_MASK 0x000000C0
-#define E1000_STATUS_SPEED_10   0x00000000      /* Speed 10Mb/s */
-#define E1000_STATUS_SPEED_100  0x00000040      /* Speed 100Mb/s */
-#define E1000_STATUS_SPEED_1000 0x00000080      /* Speed 1000Mb/s */
-#define E1000_STATUS_LAN_INIT_DONE 0x00000200   /* Lan Init Completion
-                                                   by EEPROM/Flash */
-#define E1000_STATUS_ASDV       0x00000300      /* Auto speed detect value */
-#define E1000_STATUS_DOCK_CI    0x00000800      /* Change in Dock/Undock state. Clear on write '0'. */
-#define E1000_STATUS_GIO_MASTER_ENABLE 0x00080000 /* Status of Master requests. */
-#define E1000_STATUS_MTXCKOK    0x00000400      /* MTX clock running OK */
-#define E1000_STATUS_PCI66      0x00000800      /* In 66Mhz slot */
-#define E1000_STATUS_BUS64      0x00001000      /* In 64 bit slot */
-#define E1000_STATUS_PCIX_MODE  0x00002000      /* PCI-X mode */
-#define E1000_STATUS_PCIX_SPEED 0x0000C000      /* PCI-X bus speed */
-#define E1000_STATUS_BMC_SKU_0  0x00100000 /* BMC USB redirect disabled */
-#define E1000_STATUS_BMC_SKU_1  0x00200000 /* BMC SRAM disabled */
-#define E1000_STATUS_BMC_SKU_2  0x00400000 /* BMC SDRAM disabled */
-#define E1000_STATUS_BMC_CRYPTO 0x00800000 /* BMC crypto disabled */
-#define E1000_STATUS_BMC_LITE   0x01000000 /* BMC external code execution disabled */
-#define E1000_STATUS_RGMII_ENABLE 0x02000000 /* RGMII disabled */
-#define E1000_STATUS_FUSE_8       0x04000000
-#define E1000_STATUS_FUSE_9       0x08000000
-#define E1000_STATUS_SERDES0_DIS  0x10000000 /* SERDES disabled on port 0 */
-#define E1000_STATUS_SERDES1_DIS  0x20000000 /* SERDES disabled on port 1 */
-
-/* EEPROM/Flash Control */
-#define E1000_EECD_SK        0x00000001 /* EEPROM Clock */
-#define E1000_EECD_CS        0x00000002 /* EEPROM Chip Select */
-#define E1000_EECD_DI        0x00000004 /* EEPROM Data In */
-#define E1000_EECD_DO        0x00000008 /* EEPROM Data Out */
-#define E1000_EECD_FWE_MASK  0x00000030
-#define E1000_EECD_FWE_DIS   0x00000010 /* Disable FLASH writes */
-#define E1000_EECD_FWE_EN    0x00000020 /* Enable FLASH writes */
-#define E1000_EECD_FWE_SHIFT 4
-#define E1000_EECD_REQ       0x00000040 /* EEPROM Access Request */
-#define E1000_EECD_GNT       0x00000080 /* EEPROM Access Grant */
-#define E1000_EECD_PRES      0x00000100 /* EEPROM Present */
-#define E1000_EECD_SIZE      0x00000200 /* EEPROM Size (0=64 word 1=256 word) */
-#define E1000_EECD_ADDR_BITS 0x00000400 /* EEPROM Addressing bits based on type
-                                         * (0-small, 1-large) */
-#define E1000_EECD_TYPE      0x00002000 /* EEPROM Type (1-SPI, 0-Microwire) */
-#ifndef E1000_EEPROM_GRANT_ATTEMPTS
-#define E1000_EEPROM_GRANT_ATTEMPTS 1000 /* EEPROM # attempts to gain grant */
-#endif
-#define E1000_EECD_AUTO_RD          0x00000200  /* EEPROM Auto Read done */
-#define E1000_EECD_SIZE_EX_MASK     0x00007800  /* EEprom Size */
-#define E1000_EECD_SIZE_EX_SHIFT    11
-#define E1000_EECD_NVADDS    0x00018000 /* NVM Address Size */
-#define E1000_EECD_SELSHAD   0x00020000 /* Select Shadow RAM */
-#define E1000_EECD_INITSRAM  0x00040000 /* Initialize Shadow RAM */
-#define E1000_EECD_FLUPD     0x00080000 /* Update FLASH */
-#define E1000_EECD_AUPDEN    0x00100000 /* Enable Autonomous FLASH update */
-#define E1000_EECD_SHADV     0x00200000 /* Shadow RAM Data Valid */
-#define E1000_EECD_SEC1VAL   0x00400000 /* Sector One Valid */
-#define E1000_EECD_SECVAL_SHIFT      22
-#define E1000_STM_OPCODE     0xDB00
-#define E1000_HICR_FW_RESET  0xC0
-
-#define E1000_SHADOW_RAM_WORDS     2048
-#define E1000_ICH_NVM_SIG_WORD     0x13
-#define E1000_ICH_NVM_SIG_MASK     0xC0
-
-/* MDI Control */
-#define E1000_MDIC_DATA_MASK 0x0000FFFF
-#define E1000_MDIC_REG_MASK  0x001F0000
-#define E1000_MDIC_REG_SHIFT 16
-#define E1000_MDIC_PHY_MASK  0x03E00000
-#define E1000_MDIC_PHY_SHIFT 21
-#define E1000_MDIC_OP_WRITE  0x04000000
-#define E1000_MDIC_OP_READ   0x08000000
-#define E1000_MDIC_READY     0x10000000
-#define E1000_MDIC_INT_EN    0x20000000
-#define E1000_MDIC_ERROR     0x40000000
-
-/* EEPROM Commands - Microwire */
-#define EEPROM_READ_OPCODE_MICROWIRE  0x6  /* EEPROM read opcode */
-#define EEPROM_WRITE_OPCODE_MICROWIRE 0x5  /* EEPROM write opcode */
-#define EEPROM_ERASE_OPCODE_MICROWIRE 0x7  /* EEPROM erase opcode */
-#define EEPROM_EWEN_OPCODE_MICROWIRE  0x13 /* EEPROM erase/write enable */
-#define EEPROM_EWDS_OPCODE_MICROWIRE  0x10 /* EEPROM erast/write disable */
-
-/* EEPROM Word Offsets */
-#define EEPROM_COMPAT                 0x0003
-#define EEPROM_ID_LED_SETTINGS        0x0004
-#define EEPROM_VERSION                0x0005
-#define EEPROM_SERDES_AMPLITUDE       0x0006 /* For SERDES output amplitude adjustment. */
-#define EEPROM_PHY_CLASS_WORD         0x0007
-#define EEPROM_INIT_CONTROL1_REG      0x000A
-#define EEPROM_INIT_CONTROL2_REG      0x000F
-#define EEPROM_SWDEF_PINS_CTRL_PORT_1 0x0010
-#define EEPROM_INIT_CONTROL3_PORT_B   0x0014
-#define EEPROM_INIT_3GIO_3            0x001A
-#define EEPROM_SWDEF_PINS_CTRL_PORT_0 0x0020
-#define EEPROM_INIT_CONTROL3_PORT_A   0x0024
-#define EEPROM_CFG                    0x0012
-#define EEPROM_FLASH_VERSION          0x0032
-#define EEPROM_CHECKSUM_REG           0x003F
-
-#define E1000_EEPROM_CFG_DONE         0x00040000   /* MNG config cycle done */
-#define E1000_EEPROM_CFG_DONE_PORT_1  0x00080000   /* ...for second port */
-
-/* Transmit Descriptor */
-struct e1000_tx_desc {
-    uint64_t buffer_addr;       /* Address of the descriptor's data buffer */
-    union {
-        uint32_t data;
-        struct {
-            uint16_t length;    /* Data buffer length */
-            uint8_t cso;        /* Checksum offset */
-            uint8_t cmd;        /* Descriptor control */
-        } flags;
-    } lower;
-    union {
-        uint32_t data;
-        struct {
-            uint8_t status;     /* Descriptor status */
-            uint8_t css;        /* Checksum start */
-            uint16_t special;
-        } fields;
-    } upper;
-};
-
-/* Transmit Descriptor bit definitions */
-#define E1000_TXD_DTYP_D     0x00100000 /* Data Descriptor */
-#define E1000_TXD_DTYP_C     0x00000000 /* Context Descriptor */
-#define E1000_TXD_POPTS_IXSM 0x01       /* Insert IP checksum */
-#define E1000_TXD_POPTS_TXSM 0x02       /* Insert TCP/UDP checksum */
-#define E1000_TXD_CMD_EOP    0x01000000 /* End of Packet */
-#define E1000_TXD_CMD_IFCS   0x02000000 /* Insert FCS (Ethernet CRC) */
-#define E1000_TXD_CMD_IC     0x04000000 /* Insert Checksum */
-#define E1000_TXD_CMD_RS     0x08000000 /* Report Status */
-#define E1000_TXD_CMD_RPS    0x10000000 /* Report Packet Sent */
-#define E1000_TXD_CMD_DEXT   0x20000000 /* Descriptor extension (0 = legacy) */
-#define E1000_TXD_CMD_VLE    0x40000000 /* Add VLAN tag */
-#define E1000_TXD_CMD_IDE    0x80000000 /* Enable Tidv register */
-#define E1000_TXD_STAT_DD    0x00000001 /* Descriptor Done */
-#define E1000_TXD_STAT_EC    0x00000002 /* Excess Collisions */
-#define E1000_TXD_STAT_LC    0x00000004 /* Late Collisions */
-#define E1000_TXD_STAT_TU    0x00000008 /* Transmit underrun */
-#define E1000_TXD_CMD_TCP    0x01000000 /* TCP packet */
-#define E1000_TXD_CMD_IP     0x02000000 /* IP packet */
-#define E1000_TXD_CMD_TSE    0x04000000 /* TCP Seg enable */
-#define E1000_TXD_STAT_TC    0x00000004 /* Tx Underrun */
-
-/* Transmit Control */
-#define E1000_TCTL_RST    0x00000001    /* software reset */
-#define E1000_TCTL_EN     0x00000002    /* enable tx */
-#define E1000_TCTL_BCE    0x00000004    /* busy check enable */
-#define E1000_TCTL_PSP    0x00000008    /* pad short packets */
-#define E1000_TCTL_CT     0x00000ff0    /* collision threshold */
-#define E1000_TCTL_COLD   0x003ff000    /* collision distance */
-#define E1000_TCTL_SWXOFF 0x00400000    /* SW Xoff transmission */
-#define E1000_TCTL_PBE    0x00800000    /* Packet Burst Enable */
-#define E1000_TCTL_RTLC   0x01000000    /* Re-transmit on late collision */
-#define E1000_TCTL_NRTU   0x02000000    /* No Re-transmit on underrun */
-#define E1000_TCTL_MULR   0x10000000    /* Multiple request support */
-
-/* Receive Descriptor */
-struct e1000_rx_desc {
-    uint64_t buffer_addr; /* Address of the descriptor's data buffer */
-    uint16_t length;     /* Length of data DMAed into data buffer */
-    uint16_t csum;       /* Packet checksum */
-    uint8_t status;      /* Descriptor status */
-    uint8_t errors;      /* Descriptor Errors */
-    uint16_t special;
-};
-
-/* Receive Descriptor bit definitions */
-#define E1000_RXD_STAT_DD       0x01    /* Descriptor Done */
-#define E1000_RXD_STAT_EOP      0x02    /* End of Packet */
-#define E1000_RXD_STAT_IXSM     0x04    /* Ignore checksum */
-#define E1000_RXD_STAT_VP       0x08    /* IEEE VLAN Packet */
-#define E1000_RXD_STAT_UDPCS    0x10    /* UDP xsum caculated */
-#define E1000_RXD_STAT_TCPCS    0x20    /* TCP xsum calculated */
-#define E1000_RXD_STAT_IPCS     0x40    /* IP xsum calculated */
-#define E1000_RXD_STAT_PIF      0x80    /* passed in-exact filter */
-#define E1000_RXD_STAT_IPIDV    0x200   /* IP identification valid */
-#define E1000_RXD_STAT_UDPV     0x400   /* Valid UDP checksum */
-#define E1000_RXD_STAT_ACK      0x8000  /* ACK Packet indication */
-#define E1000_RXD_ERR_CE        0x01    /* CRC Error */
-#define E1000_RXD_ERR_SE        0x02    /* Symbol Error */
-#define E1000_RXD_ERR_SEQ       0x04    /* Sequence Error */
-#define E1000_RXD_ERR_CXE       0x10    /* Carrier Extension Error */
-#define E1000_RXD_ERR_TCPE      0x20    /* TCP/UDP Checksum Error */
-#define E1000_RXD_ERR_IPE       0x40    /* IP Checksum Error */
-#define E1000_RXD_ERR_RXE       0x80    /* Rx Data Error */
-#define E1000_RXD_SPC_VLAN_MASK 0x0FFF  /* VLAN ID is in lower 12 bits */
-#define E1000_RXD_SPC_PRI_MASK  0xE000  /* Priority is in upper 3 bits */
-#define E1000_RXD_SPC_PRI_SHIFT 13
-#define E1000_RXD_SPC_CFI_MASK  0x1000  /* CFI is bit 12 */
-#define E1000_RXD_SPC_CFI_SHIFT 12
-
-#define E1000_RXDEXT_STATERR_CE    0x01000000
-#define E1000_RXDEXT_STATERR_SE    0x02000000
-#define E1000_RXDEXT_STATERR_SEQ   0x04000000
-#define E1000_RXDEXT_STATERR_CXE   0x10000000
-#define E1000_RXDEXT_STATERR_TCPE  0x20000000
-#define E1000_RXDEXT_STATERR_IPE   0x40000000
-#define E1000_RXDEXT_STATERR_RXE   0x80000000
-
-#define E1000_RXDPS_HDRSTAT_HDRSP        0x00008000
-#define E1000_RXDPS_HDRSTAT_HDRLEN_MASK  0x000003FF
-
-/* Receive Address */
-#define E1000_RAH_AV  0x80000000        /* Receive descriptor valid */
-
-/* Offload Context Descriptor */
-struct e1000_context_desc {
-    union {
-        uint32_t ip_config;
-        struct {
-            uint8_t ipcss;      /* IP checksum start */
-            uint8_t ipcso;      /* IP checksum offset */
-            uint16_t ipcse;     /* IP checksum end */
-        } ip_fields;
-    } lower_setup;
-    union {
-        uint32_t tcp_config;
-        struct {
-            uint8_t tucss;      /* TCP checksum start */
-            uint8_t tucso;      /* TCP checksum offset */
-            uint16_t tucse;     /* TCP checksum end */
-        } tcp_fields;
-    } upper_setup;
-    uint32_t cmd_and_length;    /* */
-    union {
-        uint32_t data;
-        struct {
-            uint8_t status;     /* Descriptor status */
-            uint8_t hdr_len;    /* Header length */
-            uint16_t mss;       /* Maximum segment size */
-        } fields;
-    } tcp_seg_setup;
-};
-
-/* Offload data descriptor */
-struct e1000_data_desc {
-    uint64_t buffer_addr;       /* Address of the descriptor's buffer address */
-    union {
-        uint32_t data;
-        struct {
-            uint16_t length;    /* Data buffer length */
-            uint8_t typ_len_ext;        /* */
-            uint8_t cmd;        /* */
-        } flags;
-    } lower;
-    union {
-        uint32_t data;
-        struct {
-            uint8_t status;     /* Descriptor status */
-            uint8_t popts;      /* Packet Options */
-            uint16_t special;   /* */
-        } fields;
-    } upper;
-};
-
-/* Management Control */
-#define E1000_MANC_SMBUS_EN      0x00000001 /* SMBus Enabled - RO */
-#define E1000_MANC_ASF_EN        0x00000002 /* ASF Enabled - RO */
-#define E1000_MANC_R_ON_FORCE    0x00000004 /* Reset on Force TCO - RO */
-#define E1000_MANC_RMCP_EN       0x00000100 /* Enable RCMP 026Fh Filtering */
-#define E1000_MANC_0298_EN       0x00000200 /* Enable RCMP 0298h Filtering */
-#define E1000_MANC_IPV4_EN       0x00000400 /* Enable IPv4 */
-#define E1000_MANC_IPV6_EN       0x00000800 /* Enable IPv6 */
-#define E1000_MANC_SNAP_EN       0x00001000 /* Accept LLC/SNAP */
-#define E1000_MANC_ARP_EN        0x00002000 /* Enable ARP Request Filtering */
-#define E1000_MANC_NEIGHBOR_EN   0x00004000 /* Enable Neighbor Discovery
-                                             * Filtering */
-#define E1000_MANC_ARP_RES_EN    0x00008000 /* Enable ARP response Filtering */
-#define E1000_MANC_TCO_RESET     0x00010000 /* TCO Reset Occurred */
-#define E1000_MANC_RCV_TCO_EN    0x00020000 /* Receive TCO Packets Enabled */
-#define E1000_MANC_REPORT_STATUS 0x00040000 /* Status Reporting Enabled */
-#define E1000_MANC_RCV_ALL       0x00080000 /* Receive All Enabled */
-#define E1000_MANC_BLK_PHY_RST_ON_IDE   0x00040000 /* Block phy resets */
-#define E1000_MANC_EN_MAC_ADDR_FILTER   0x00100000 /* Enable MAC address
-                                                    * filtering */
-#define E1000_MANC_EN_MNG2HOST   0x00200000 /* Enable MNG packets to host
-                                             * memory */
-#define E1000_MANC_EN_IP_ADDR_FILTER    0x00400000 /* Enable IP address
-                                                    * filtering */
-#define E1000_MANC_EN_XSUM_FILTER   0x00800000 /* Enable checksum filtering */
-#define E1000_MANC_BR_EN         0x01000000 /* Enable broadcast filtering */
-#define E1000_MANC_SMB_REQ       0x01000000 /* SMBus Request */
-#define E1000_MANC_SMB_GNT       0x02000000 /* SMBus Grant */
-#define E1000_MANC_SMB_CLK_IN    0x04000000 /* SMBus Clock In */
-#define E1000_MANC_SMB_DATA_IN   0x08000000 /* SMBus Data In */
-#define E1000_MANC_SMB_DATA_OUT  0x10000000 /* SMBus Data Out */
-#define E1000_MANC_SMB_CLK_OUT   0x20000000 /* SMBus Clock Out */
-
-#define E1000_MANC_SMB_DATA_OUT_SHIFT  28 /* SMBus Data Out Shift */
-#define E1000_MANC_SMB_CLK_OUT_SHIFT   29 /* SMBus Clock Out Shift */
-
-/* For checksumming, the sum of all words in the EEPROM should equal 0xBABA. */
-#define EEPROM_SUM 0xBABA
-
-#endif /* _E1000_HW_H_ */
diff --git a/hw/ecc.c b/hw/ecc.c
deleted file mode 100644 (file)
index 8c97c33..0000000
--- a/hw/ecc.c
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Calculate Error-correcting Codes. Used by NAND Flash controllers
- * (not by NAND chips).
- *
- * Copyright (c) 2006 Openedhand Ltd.
- * Written by Andrzej Zaborowski <balrog@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/hw.h"
-#include "hw/flash.h"
-
-/*
- * Pre-calculated 256-way 1 byte column parity.  Table borrowed from Linux.
- */
-static const uint8_t nand_ecc_precalc_table[] = {
-    0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a,
-    0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00,
-    0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f,
-    0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
-    0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c,
-    0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
-    0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59,
-    0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
-    0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33,
-    0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
-    0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56,
-    0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
-    0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55,
-    0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
-    0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30,
-    0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
-    0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30,
-    0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
-    0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55,
-    0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
-    0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56,
-    0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
-    0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33,
-    0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
-    0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59,
-    0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
-    0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c,
-    0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
-    0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f,
-    0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
-    0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a,
-    0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00,
-};
-
-/* Update ECC parity count.  */
-uint8_t ecc_digest(ECCState *s, uint8_t sample)
-{
-    uint8_t idx = nand_ecc_precalc_table[sample];
-
-    s->cp ^= idx & 0x3f;
-    if (idx & 0x40) {
-        s->lp[0] ^= ~s->count;
-        s->lp[1] ^= s->count;
-    }
-    s->count ++;
-
-    return sample;
-}
-
-/* Reinitialise the counters.  */
-void ecc_reset(ECCState *s)
-{
-    s->lp[0] = 0x0000;
-    s->lp[1] = 0x0000;
-    s->cp = 0x00;
-    s->count = 0;
-}
-
-/* Save/restore */
-VMStateDescription vmstate_ecc_state = {
-    .name = "ecc-state",
-    .version_id = 0,
-    .minimum_version_id = 0,
-    .minimum_version_id_old = 0,
-    .fields = (VMStateField []) {
-        VMSTATE_UINT8(cp, ECCState),
-        VMSTATE_UINT16_ARRAY(lp, ECCState, 2),
-        VMSTATE_UINT16(count, ECCState),
-        VMSTATE_END_OF_LIST(),
-    },
-};
diff --git a/hw/eccmemctl.c b/hw/eccmemctl.c
deleted file mode 100644 (file)
index 6f4a407..0000000
+++ /dev/null
@@ -1,340 +0,0 @@
-/*
- * QEMU Sparc Sun4m ECC memory controller emulation
- *
- * Copyright (c) 2007 Robert Reif
- *
- * 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 "hw/sysbus.h"
-#include "trace.h"
-
-/* There are 3 versions of this chip used in SMP sun4m systems:
- * MCC (version 0, implementation 0) SS-600MP
- * EMC (version 0, implementation 1) SS-10
- * SMC (version 0, implementation 2) SS-10SX and SS-20
- *
- * Chipset docs:
- * "Sun-4M System Architecture (revision 2.0) by Chuck Narad", 950-1373-01,
- * http://mediacast.sun.com/users/Barton808/media/Sun4M_SystemArchitecture_edited2.pdf
- */
-
-#define ECC_MCC        0x00000000
-#define ECC_EMC        0x10000000
-#define ECC_SMC        0x20000000
-
-/* Register indexes */
-#define ECC_MER        0               /* Memory Enable Register */
-#define ECC_MDR        1               /* Memory Delay Register */
-#define ECC_MFSR       2               /* Memory Fault Status Register */
-#define ECC_VCR        3               /* Video Configuration Register */
-#define ECC_MFAR0      4               /* Memory Fault Address Register 0 */
-#define ECC_MFAR1      5               /* Memory Fault Address Register 1 */
-#define ECC_DR         6               /* Diagnostic Register */
-#define ECC_ECR0       7               /* Event Count Register 0 */
-#define ECC_ECR1       8               /* Event Count Register 1 */
-
-/* ECC fault control register */
-#define ECC_MER_EE     0x00000001      /* Enable ECC checking */
-#define ECC_MER_EI     0x00000002      /* Enable Interrupts on
-                                          correctable errors */
-#define ECC_MER_MRR0   0x00000004      /* SIMM 0 */
-#define ECC_MER_MRR1   0x00000008      /* SIMM 1 */
-#define ECC_MER_MRR2   0x00000010      /* SIMM 2 */
-#define ECC_MER_MRR3   0x00000020      /* SIMM 3 */
-#define ECC_MER_MRR4   0x00000040      /* SIMM 4 */
-#define ECC_MER_MRR5   0x00000080      /* SIMM 5 */
-#define ECC_MER_MRR6   0x00000100      /* SIMM 6 */
-#define ECC_MER_MRR7   0x00000200      /* SIMM 7 */
-#define ECC_MER_REU    0x00000100      /* Memory Refresh Enable (600MP) */
-#define ECC_MER_MRR    0x000003fc      /* MRR mask */
-#define ECC_MER_A      0x00000400      /* Memory controller addr map select */
-#define ECC_MER_DCI    0x00000800      /* Disables Coherent Invalidate ACK */
-#define ECC_MER_VER    0x0f000000      /* Version */
-#define ECC_MER_IMPL   0xf0000000      /* Implementation */
-#define ECC_MER_MASK_0 0x00000103      /* Version 0 (MCC) mask */
-#define ECC_MER_MASK_1 0x00000bff      /* Version 1 (EMC) mask */
-#define ECC_MER_MASK_2 0x00000bff      /* Version 2 (SMC) mask */
-
-/* ECC memory delay register */
-#define ECC_MDR_RRI    0x000003ff      /* Refresh Request Interval */
-#define ECC_MDR_MI     0x00001c00      /* MIH Delay */
-#define ECC_MDR_CI     0x0000e000      /* Coherent Invalidate Delay */
-#define ECC_MDR_MDL    0x001f0000      /* MBus Master arbitration delay */
-#define ECC_MDR_MDH    0x03e00000      /* MBus Master arbitration delay */
-#define ECC_MDR_GAD    0x7c000000      /* Graphics Arbitration Delay */
-#define ECC_MDR_RSC    0x80000000      /* Refresh load control */
-#define ECC_MDR_MASK   0x7fffffff
-
-/* ECC fault status register */
-#define ECC_MFSR_CE    0x00000001      /* Correctable error */
-#define ECC_MFSR_BS    0x00000002      /* C2 graphics bad slot access */
-#define ECC_MFSR_TO    0x00000004      /* Timeout on write */
-#define ECC_MFSR_UE    0x00000008      /* Uncorrectable error */
-#define ECC_MFSR_DW    0x000000f0      /* Index of double word in block */
-#define ECC_MFSR_SYND  0x0000ff00      /* Syndrome for correctable error */
-#define ECC_MFSR_ME    0x00010000      /* Multiple errors */
-#define ECC_MFSR_C2ERR 0x00020000      /* C2 graphics error */
-
-/* ECC fault address register 0 */
-#define ECC_MFAR0_PADDR 0x0000000f     /* PA[32-35] */
-#define ECC_MFAR0_TYPE  0x000000f0     /* Transaction type */
-#define ECC_MFAR0_SIZE  0x00000700     /* Transaction size */
-#define ECC_MFAR0_CACHE 0x00000800     /* Mapped cacheable */
-#define ECC_MFAR0_LOCK  0x00001000     /* Error occurred in atomic cycle */
-#define ECC_MFAR0_BMODE 0x00002000     /* Boot mode */
-#define ECC_MFAR0_VADDR 0x003fc000     /* VA[12-19] (superset bits) */
-#define ECC_MFAR0_S     0x08000000     /* Supervisor mode */
-#define ECC_MFARO_MID   0xf0000000     /* Module ID */
-
-/* ECC diagnostic register */
-#define ECC_DR_CBX     0x00000001
-#define ECC_DR_CB0     0x00000002
-#define ECC_DR_CB1     0x00000004
-#define ECC_DR_CB2     0x00000008
-#define ECC_DR_CB4     0x00000010
-#define ECC_DR_CB8     0x00000020
-#define ECC_DR_CB16    0x00000040
-#define ECC_DR_CB32    0x00000080
-#define ECC_DR_DMODE   0x00000c00
-
-#define ECC_NREGS      9
-#define ECC_SIZE       (ECC_NREGS * sizeof(uint32_t))
-
-#define ECC_DIAG_SIZE  4
-#define ECC_DIAG_MASK  (ECC_DIAG_SIZE - 1)
-
-typedef struct ECCState {
-    SysBusDevice busdev;
-    MemoryRegion iomem, iomem_diag;
-    qemu_irq irq;
-    uint32_t regs[ECC_NREGS];
-    uint8_t diag[ECC_DIAG_SIZE];
-    uint32_t version;
-} ECCState;
-
-static void ecc_mem_write(void *opaque, hwaddr addr, uint64_t val,
-                          unsigned size)
-{
-    ECCState *s = opaque;
-
-    switch (addr >> 2) {
-    case ECC_MER:
-        if (s->version == ECC_MCC)
-            s->regs[ECC_MER] = (val & ECC_MER_MASK_0);
-        else if (s->version == ECC_EMC)
-            s->regs[ECC_MER] = s->version | (val & ECC_MER_MASK_1);
-        else if (s->version == ECC_SMC)
-            s->regs[ECC_MER] = s->version | (val & ECC_MER_MASK_2);
-        trace_ecc_mem_writel_mer(val);
-        break;
-    case ECC_MDR:
-        s->regs[ECC_MDR] =  val & ECC_MDR_MASK;
-        trace_ecc_mem_writel_mdr(val);
-        break;
-    case ECC_MFSR:
-        s->regs[ECC_MFSR] =  val;
-        qemu_irq_lower(s->irq);
-        trace_ecc_mem_writel_mfsr(val);
-        break;
-    case ECC_VCR:
-        s->regs[ECC_VCR] =  val;
-        trace_ecc_mem_writel_vcr(val);
-        break;
-    case ECC_DR:
-        s->regs[ECC_DR] =  val;
-        trace_ecc_mem_writel_dr(val);
-        break;
-    case ECC_ECR0:
-        s->regs[ECC_ECR0] =  val;
-        trace_ecc_mem_writel_ecr0(val);
-        break;
-    case ECC_ECR1:
-        s->regs[ECC_ECR0] =  val;
-        trace_ecc_mem_writel_ecr1(val);
-        break;
-    }
-}
-
-static uint64_t ecc_mem_read(void *opaque, hwaddr addr,
-                             unsigned size)
-{
-    ECCState *s = opaque;
-    uint32_t ret = 0;
-
-    switch (addr >> 2) {
-    case ECC_MER:
-        ret = s->regs[ECC_MER];
-        trace_ecc_mem_readl_mer(ret);
-        break;
-    case ECC_MDR:
-        ret = s->regs[ECC_MDR];
-        trace_ecc_mem_readl_mdr(ret);
-        break;
-    case ECC_MFSR:
-        ret = s->regs[ECC_MFSR];
-        trace_ecc_mem_readl_mfsr(ret);
-        break;
-    case ECC_VCR:
-        ret = s->regs[ECC_VCR];
-        trace_ecc_mem_readl_vcr(ret);
-        break;
-    case ECC_MFAR0:
-        ret = s->regs[ECC_MFAR0];
-        trace_ecc_mem_readl_mfar0(ret);
-        break;
-    case ECC_MFAR1:
-        ret = s->regs[ECC_MFAR1];
-        trace_ecc_mem_readl_mfar1(ret);
-        break;
-    case ECC_DR:
-        ret = s->regs[ECC_DR];
-        trace_ecc_mem_readl_dr(ret);
-        break;
-    case ECC_ECR0:
-        ret = s->regs[ECC_ECR0];
-        trace_ecc_mem_readl_ecr0(ret);
-        break;
-    case ECC_ECR1:
-        ret = s->regs[ECC_ECR0];
-        trace_ecc_mem_readl_ecr1(ret);
-        break;
-    }
-    return ret;
-}
-
-static const MemoryRegionOps ecc_mem_ops = {
-    .read = ecc_mem_read,
-    .write = ecc_mem_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-};
-
-static void ecc_diag_mem_write(void *opaque, hwaddr addr,
-                               uint64_t val, unsigned size)
-{
-    ECCState *s = opaque;
-
-    trace_ecc_diag_mem_writeb(addr, val);
-    s->diag[addr & ECC_DIAG_MASK] = val;
-}
-
-static uint64_t ecc_diag_mem_read(void *opaque, hwaddr addr,
-                                  unsigned size)
-{
-    ECCState *s = opaque;
-    uint32_t ret = s->diag[(int)addr];
-
-    trace_ecc_diag_mem_readb(addr, ret);
-    return ret;
-}
-
-static const MemoryRegionOps ecc_diag_mem_ops = {
-    .read = ecc_diag_mem_read,
-    .write = ecc_diag_mem_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid = {
-        .min_access_size = 1,
-        .max_access_size = 1,
-    },
-};
-
-static const VMStateDescription vmstate_ecc = {
-    .name ="ECC",
-    .version_id = 3,
-    .minimum_version_id = 3,
-    .minimum_version_id_old = 3,
-    .fields      = (VMStateField []) {
-        VMSTATE_UINT32_ARRAY(regs, ECCState, ECC_NREGS),
-        VMSTATE_BUFFER(diag, ECCState),
-        VMSTATE_UINT32(version, ECCState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void ecc_reset(DeviceState *d)
-{
-    ECCState *s = container_of(d, ECCState, busdev.qdev);
-
-    if (s->version == ECC_MCC)
-        s->regs[ECC_MER] &= ECC_MER_REU;
-    else
-        s->regs[ECC_MER] &= (ECC_MER_VER | ECC_MER_IMPL | ECC_MER_MRR |
-                             ECC_MER_DCI);
-    s->regs[ECC_MDR] = 0x20;
-    s->regs[ECC_MFSR] = 0;
-    s->regs[ECC_VCR] = 0;
-    s->regs[ECC_MFAR0] = 0x07c00000;
-    s->regs[ECC_MFAR1] = 0;
-    s->regs[ECC_DR] = 0;
-    s->regs[ECC_ECR0] = 0;
-    s->regs[ECC_ECR1] = 0;
-}
-
-static int ecc_init1(SysBusDevice *dev)
-{
-    ECCState *s = FROM_SYSBUS(ECCState, dev);
-
-    sysbus_init_irq(dev, &s->irq);
-    s->regs[0] = s->version;
-    memory_region_init_io(&s->iomem, &ecc_mem_ops, s, "ecc", ECC_SIZE);
-    sysbus_init_mmio(dev, &s->iomem);
-
-    if (s->version == ECC_MCC) { // SS-600MP only
-        memory_region_init_io(&s->iomem_diag, &ecc_diag_mem_ops, s,
-                              "ecc.diag", ECC_DIAG_SIZE);
-        sysbus_init_mmio(dev, &s->iomem_diag);
-    }
-
-    return 0;
-}
-
-static Property ecc_properties[] = {
-    DEFINE_PROP_HEX32("version", ECCState, version, -1),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void ecc_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = ecc_init1;
-    dc->reset = ecc_reset;
-    dc->vmsd = &vmstate_ecc;
-    dc->props = ecc_properties;
-}
-
-static const TypeInfo ecc_info = {
-    .name          = "eccmemctl",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(ECCState),
-    .class_init    = ecc_class_init,
-};
-
-
-static void ecc_register_types(void)
-{
-    type_register_static(&ecc_info);
-}
-
-type_init(ecc_register_types)
diff --git a/hw/eepro100.c b/hw/eepro100.c
deleted file mode 100644 (file)
index 68d729c..0000000
+++ /dev/null
@@ -1,2115 +0,0 @@
-/*
- * QEMU i8255x (PRO100) emulation
- *
- * Copyright (C) 2006-2011 Stefan Weil
- *
- * Portions of the code are copies from grub / etherboot eepro100.c
- * and linux e100.c.
- *
- * 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) version 3 or 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/>.
- *
- * Tested features (i82559):
- *      PXE boot (i386 guest, i386 / mips / mipsel / ppc host) ok
- *      Linux networking (i386) ok
- *
- * Untested:
- *      Windows networking
- *
- * References:
- *
- * Intel 8255x 10/100 Mbps Ethernet Controller Family
- * Open Source Software Developer Manual
- *
- * TODO:
- *      * PHY emulation should be separated from nic emulation.
- *        Most nic emulations could share the same phy code.
- *      * i82550 is untested. It is programmed like the i82559.
- *      * i82562 is untested. It is programmed like the i82559.
- *      * Power management (i82558 and later) is not implemented.
- *      * Wake-on-LAN is not implemented.
- */
-
-#include <stddef.h>             /* offsetof */
-#include "hw/hw.h"
-#include "hw/pci/pci.h"
-#include "net/net.h"
-#include "hw/eeprom93xx.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/dma.h"
-
-/* QEMU sends frames smaller than 60 bytes to ethernet nics.
- * Such frames are rejected by real nics and their emulations.
- * To avoid this behaviour, other nic emulations pad received
- * frames. The following definition enables this padding for
- * eepro100, too. We keep the define around in case it might
- * become useful the future if the core networking is ever
- * changed to pad short packets itself. */
-#define CONFIG_PAD_RECEIVED_FRAMES
-
-#define KiB 1024
-
-/* Debug EEPRO100 card. */
-#if 0
-# define DEBUG_EEPRO100
-#endif
-
-#ifdef DEBUG_EEPRO100
-#define logout(fmt, ...) fprintf(stderr, "EE100\t%-24s" fmt, __func__, ## __VA_ARGS__)
-#else
-#define logout(fmt, ...) ((void)0)
-#endif
-
-/* Set flags to 0 to disable debug output. */
-#define INT     1       /* interrupt related actions */
-#define MDI     1       /* mdi related actions */
-#define OTHER   1
-#define RXTX    1
-#define EEPROM  1       /* eeprom related actions */
-
-#define TRACE(flag, command) ((flag) ? (command) : (void)0)
-
-#define missing(text) fprintf(stderr, "eepro100: feature is missing in this emulation: " text "\n")
-
-#define MAX_ETH_FRAME_SIZE 1514
-
-/* This driver supports several different devices which are declared here. */
-#define i82550          0x82550
-#define i82551          0x82551
-#define i82557A         0x82557a
-#define i82557B         0x82557b
-#define i82557C         0x82557c
-#define i82558A         0x82558a
-#define i82558B         0x82558b
-#define i82559A         0x82559a
-#define i82559B         0x82559b
-#define i82559C         0x82559c
-#define i82559ER        0x82559e
-#define i82562          0x82562
-#define i82801          0x82801
-
-/* Use 64 word EEPROM. TODO: could be a runtime option. */
-#define EEPROM_SIZE     64
-
-#define PCI_MEM_SIZE            (4 * KiB)
-#define PCI_IO_SIZE             64
-#define PCI_FLASH_SIZE          (128 * KiB)
-
-#define BIT(n) (1 << (n))
-#define BITS(n, m) (((0xffffffffU << (31 - n)) >> (31 - n + m)) << m)
-
-/* The SCB accepts the following controls for the Tx and Rx units: */
-#define  CU_NOP         0x0000  /* No operation. */
-#define  CU_START       0x0010  /* CU start. */
-#define  CU_RESUME      0x0020  /* CU resume. */
-#define  CU_STATSADDR   0x0040  /* Load dump counters address. */
-#define  CU_SHOWSTATS   0x0050  /* Dump statistical counters. */
-#define  CU_CMD_BASE    0x0060  /* Load CU base address. */
-#define  CU_DUMPSTATS   0x0070  /* Dump and reset statistical counters. */
-#define  CU_SRESUME     0x00a0  /* CU static resume. */
-
-#define  RU_NOP         0x0000
-#define  RX_START       0x0001
-#define  RX_RESUME      0x0002
-#define  RU_ABORT       0x0004
-#define  RX_ADDR_LOAD   0x0006
-#define  RX_RESUMENR    0x0007
-#define INT_MASK        0x0100
-#define DRVR_INT        0x0200  /* Driver generated interrupt. */
-
-typedef struct {
-    const char *name;
-    const char *desc;
-    uint16_t device_id;
-    uint8_t revision;
-    uint16_t subsystem_vendor_id;
-    uint16_t subsystem_id;
-
-    uint32_t device;
-    uint8_t stats_size;
-    bool has_extended_tcb_support;
-    bool power_management;
-} E100PCIDeviceInfo;
-
-/* Offsets to the various registers.
-   All accesses need not be longword aligned. */
-typedef enum {
-    SCBStatus = 0,              /* Status Word. */
-    SCBAck = 1,
-    SCBCmd = 2,                 /* Rx/Command Unit command and status. */
-    SCBIntmask = 3,
-    SCBPointer = 4,             /* General purpose pointer. */
-    SCBPort = 8,                /* Misc. commands and operands.  */
-    SCBflash = 12,              /* Flash memory control. */
-    SCBeeprom = 14,             /* EEPROM control. */
-    SCBCtrlMDI = 16,            /* MDI interface control. */
-    SCBEarlyRx = 20,            /* Early receive byte count. */
-    SCBFlow = 24,               /* Flow Control. */
-    SCBpmdr = 27,               /* Power Management Driver. */
-    SCBgctrl = 28,              /* General Control. */
-    SCBgstat = 29,              /* General Status. */
-} E100RegisterOffset;
-
-/* A speedo3 transmit buffer descriptor with two buffers... */
-typedef struct {
-    uint16_t status;
-    uint16_t command;
-    uint32_t link;              /* void * */
-    uint32_t tbd_array_addr;    /* transmit buffer descriptor array address. */
-    uint16_t tcb_bytes;         /* transmit command block byte count (in lower 14 bits */
-    uint8_t tx_threshold;       /* transmit threshold */
-    uint8_t tbd_count;          /* TBD number */
-#if 0
-    /* This constitutes two "TBD" entries: hdr and data */
-    uint32_t tx_buf_addr0;  /* void *, header of frame to be transmitted.  */
-    int32_t  tx_buf_size0;  /* Length of Tx hdr. */
-    uint32_t tx_buf_addr1;  /* void *, data to be transmitted.  */
-    int32_t  tx_buf_size1;  /* Length of Tx data. */
-#endif
-} eepro100_tx_t;
-
-/* Receive frame descriptor. */
-typedef struct {
-    int16_t status;
-    uint16_t command;
-    uint32_t link;              /* struct RxFD * */
-    uint32_t rx_buf_addr;       /* void * */
-    uint16_t count;
-    uint16_t size;
-    /* Ethernet frame data follows. */
-} eepro100_rx_t;
-
-typedef enum {
-    COMMAND_EL = BIT(15),
-    COMMAND_S = BIT(14),
-    COMMAND_I = BIT(13),
-    COMMAND_NC = BIT(4),
-    COMMAND_SF = BIT(3),
-    COMMAND_CMD = BITS(2, 0),
-} scb_command_bit;
-
-typedef enum {
-    STATUS_C = BIT(15),
-    STATUS_OK = BIT(13),
-} scb_status_bit;
-
-typedef struct {
-    uint32_t tx_good_frames, tx_max_collisions, tx_late_collisions,
-             tx_underruns, tx_lost_crs, tx_deferred, tx_single_collisions,
-             tx_multiple_collisions, tx_total_collisions;
-    uint32_t rx_good_frames, rx_crc_errors, rx_alignment_errors,
-             rx_resource_errors, rx_overrun_errors, rx_cdt_errors,
-             rx_short_frame_errors;
-    uint32_t fc_xmt_pause, fc_rcv_pause, fc_rcv_unsupported;
-    uint16_t xmt_tco_frames, rcv_tco_frames;
-    /* TODO: i82559 has six reserved statistics but a total of 24 dwords. */
-    uint32_t reserved[4];
-} eepro100_stats_t;
-
-typedef enum {
-    cu_idle = 0,
-    cu_suspended = 1,
-    cu_active = 2,
-    cu_lpq_active = 2,
-    cu_hqp_active = 3
-} cu_state_t;
-
-typedef enum {
-    ru_idle = 0,
-    ru_suspended = 1,
-    ru_no_resources = 2,
-    ru_ready = 4
-} ru_state_t;
-
-typedef struct {
-    PCIDevice dev;
-    /* Hash register (multicast mask array, multiple individual addresses). */
-    uint8_t mult[8];
-    MemoryRegion mmio_bar;
-    MemoryRegion io_bar;
-    MemoryRegion flash_bar;
-    NICState *nic;
-    NICConf conf;
-    uint8_t scb_stat;           /* SCB stat/ack byte */
-    uint8_t int_stat;           /* PCI interrupt status */
-    /* region must not be saved by nic_save. */
-    uint16_t mdimem[32];
-    eeprom_t *eeprom;
-    uint32_t device;            /* device variant */
-    /* (cu_base + cu_offset) address the next command block in the command block list. */
-    uint32_t cu_base;           /* CU base address */
-    uint32_t cu_offset;         /* CU address offset */
-    /* (ru_base + ru_offset) address the RFD in the Receive Frame Area. */
-    uint32_t ru_base;           /* RU base address */
-    uint32_t ru_offset;         /* RU address offset */
-    uint32_t statsaddr;         /* pointer to eepro100_stats_t */
-
-    /* Temporary status information (no need to save these values),
-     * used while processing CU commands. */
-    eepro100_tx_t tx;           /* transmit buffer descriptor */
-    uint32_t cb_address;        /* = cu_base + cu_offset */
-
-    /* Statistical counters. Also used for wake-up packet (i82559). */
-    eepro100_stats_t statistics;
-
-    /* Data in mem is always in the byte order of the controller (le).
-     * It must be dword aligned to allow direct access to 32 bit values. */
-    uint8_t mem[PCI_MEM_SIZE] __attribute__((aligned(8)));
-
-    /* Configuration bytes. */
-    uint8_t configuration[22];
-
-    /* vmstate for each particular nic */
-    VMStateDescription *vmstate;
-
-    /* Quasi static device properties (no need to save them). */
-    uint16_t stats_size;
-    bool has_extended_tcb_support;
-} EEPRO100State;
-
-/* Word indices in EEPROM. */
-typedef enum {
-    EEPROM_CNFG_MDIX  = 0x03,
-    EEPROM_ID         = 0x05,
-    EEPROM_PHY_ID     = 0x06,
-    EEPROM_VENDOR_ID  = 0x0c,
-    EEPROM_CONFIG_ASF = 0x0d,
-    EEPROM_DEVICE_ID  = 0x23,
-    EEPROM_SMBUS_ADDR = 0x90,
-} EEPROMOffset;
-
-/* Bit values for EEPROM ID word. */
-typedef enum {
-    EEPROM_ID_MDM = BIT(0),     /* Modem */
-    EEPROM_ID_STB = BIT(1),     /* Standby Enable */
-    EEPROM_ID_WMR = BIT(2),     /* ??? */
-    EEPROM_ID_WOL = BIT(5),     /* Wake on LAN */
-    EEPROM_ID_DPD = BIT(6),     /* Deep Power Down */
-    EEPROM_ID_ALT = BIT(7),     /* */
-    /* BITS(10, 8) device revision */
-    EEPROM_ID_BD = BIT(11),     /* boot disable */
-    EEPROM_ID_ID = BIT(13),     /* id bit */
-    /* BITS(15, 14) signature */
-    EEPROM_ID_VALID = BIT(14),  /* signature for valid eeprom */
-} eeprom_id_bit;
-
-/* Default values for MDI (PHY) registers */
-static const uint16_t eepro100_mdi_default[] = {
-    /* MDI Registers 0 - 6, 7 */
-    0x3000, 0x780d, 0x02a8, 0x0154, 0x05e1, 0x0000, 0x0000, 0x0000,
-    /* MDI Registers 8 - 15 */
-    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
-    /* MDI Registers 16 - 31 */
-    0x0003, 0x0000, 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
-    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
-};
-
-/* Readonly mask for MDI (PHY) registers */
-static const uint16_t eepro100_mdi_mask[] = {
-    0x0000, 0xffff, 0xffff, 0xffff, 0xc01f, 0xffff, 0xffff, 0x0000,
-    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
-    0x0fff, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
-    0xffff, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
-};
-
-#define POLYNOMIAL 0x04c11db6
-
-static E100PCIDeviceInfo *eepro100_get_class(EEPRO100State *s);
-
-/* From FreeBSD (locally modified). */
-static unsigned e100_compute_mcast_idx(const uint8_t *ep)
-{
-    uint32_t crc;
-    int carry, i, j;
-    uint8_t b;
-
-    crc = 0xffffffff;
-    for (i = 0; i < 6; i++) {
-        b = *ep++;
-        for (j = 0; j < 8; j++) {
-            carry = ((crc & 0x80000000L) ? 1 : 0) ^ (b & 0x01);
-            crc <<= 1;
-            b >>= 1;
-            if (carry) {
-                crc = ((crc ^ POLYNOMIAL) | carry);
-            }
-        }
-    }
-    return (crc & BITS(7, 2)) >> 2;
-}
-
-/* Read a 16 bit control/status (CSR) register. */
-static uint16_t e100_read_reg2(EEPRO100State *s, E100RegisterOffset addr)
-{
-    assert(!((uintptr_t)&s->mem[addr] & 1));
-    return le16_to_cpup((uint16_t *)&s->mem[addr]);
-}
-
-/* Read a 32 bit control/status (CSR) register. */
-static uint32_t e100_read_reg4(EEPRO100State *s, E100RegisterOffset addr)
-{
-    assert(!((uintptr_t)&s->mem[addr] & 3));
-    return le32_to_cpup((uint32_t *)&s->mem[addr]);
-}
-
-/* Write a 16 bit control/status (CSR) register. */
-static void e100_write_reg2(EEPRO100State *s, E100RegisterOffset addr,
-                            uint16_t val)
-{
-    assert(!((uintptr_t)&s->mem[addr] & 1));
-    cpu_to_le16w((uint16_t *)&s->mem[addr], val);
-}
-
-/* Read a 32 bit control/status (CSR) register. */
-static void e100_write_reg4(EEPRO100State *s, E100RegisterOffset addr,
-                            uint32_t val)
-{
-    assert(!((uintptr_t)&s->mem[addr] & 3));
-    cpu_to_le32w((uint32_t *)&s->mem[addr], val);
-}
-
-#if defined(DEBUG_EEPRO100)
-static const char *nic_dump(const uint8_t * buf, unsigned size)
-{
-    static char dump[3 * 16 + 1];
-    char *p = &dump[0];
-    if (size > 16) {
-        size = 16;
-    }
-    while (size-- > 0) {
-        p += sprintf(p, " %02x", *buf++);
-    }
-    return dump;
-}
-#endif                          /* DEBUG_EEPRO100 */
-
-enum scb_stat_ack {
-    stat_ack_not_ours = 0x00,
-    stat_ack_sw_gen = 0x04,
-    stat_ack_rnr = 0x10,
-    stat_ack_cu_idle = 0x20,
-    stat_ack_frame_rx = 0x40,
-    stat_ack_cu_cmd_done = 0x80,
-    stat_ack_not_present = 0xFF,
-    stat_ack_rx = (stat_ack_sw_gen | stat_ack_rnr | stat_ack_frame_rx),
-    stat_ack_tx = (stat_ack_cu_idle | stat_ack_cu_cmd_done),
-};
-
-static void disable_interrupt(EEPRO100State * s)
-{
-    if (s->int_stat) {
-        TRACE(INT, logout("interrupt disabled\n"));
-        qemu_irq_lower(s->dev.irq[0]);
-        s->int_stat = 0;
-    }
-}
-
-static void enable_interrupt(EEPRO100State * s)
-{
-    if (!s->int_stat) {
-        TRACE(INT, logout("interrupt enabled\n"));
-        qemu_irq_raise(s->dev.irq[0]);
-        s->int_stat = 1;
-    }
-}
-
-static void eepro100_acknowledge(EEPRO100State * s)
-{
-    s->scb_stat &= ~s->mem[SCBAck];
-    s->mem[SCBAck] = s->scb_stat;
-    if (s->scb_stat == 0) {
-        disable_interrupt(s);
-    }
-}
-
-static void eepro100_interrupt(EEPRO100State * s, uint8_t status)
-{
-    uint8_t mask = ~s->mem[SCBIntmask];
-    s->mem[SCBAck] |= status;
-    status = s->scb_stat = s->mem[SCBAck];
-    status &= (mask | 0x0f);
-#if 0
-    status &= (~s->mem[SCBIntmask] | 0x0xf);
-#endif
-    if (status && (mask & 0x01)) {
-        /* SCB mask and SCB Bit M do not disable interrupt. */
-        enable_interrupt(s);
-    } else if (s->int_stat) {
-        disable_interrupt(s);
-    }
-}
-
-static void eepro100_cx_interrupt(EEPRO100State * s)
-{
-    /* CU completed action command. */
-    /* Transmit not ok (82557 only, not in emulation). */
-    eepro100_interrupt(s, 0x80);
-}
-
-static void eepro100_cna_interrupt(EEPRO100State * s)
-{
-    /* CU left the active state. */
-    eepro100_interrupt(s, 0x20);
-}
-
-static void eepro100_fr_interrupt(EEPRO100State * s)
-{
-    /* RU received a complete frame. */
-    eepro100_interrupt(s, 0x40);
-}
-
-static void eepro100_rnr_interrupt(EEPRO100State * s)
-{
-    /* RU is not ready. */
-    eepro100_interrupt(s, 0x10);
-}
-
-static void eepro100_mdi_interrupt(EEPRO100State * s)
-{
-    /* MDI completed read or write cycle. */
-    eepro100_interrupt(s, 0x08);
-}
-
-static void eepro100_swi_interrupt(EEPRO100State * s)
-{
-    /* Software has requested an interrupt. */
-    eepro100_interrupt(s, 0x04);
-}
-
-#if 0
-static void eepro100_fcp_interrupt(EEPRO100State * s)
-{
-    /* Flow control pause interrupt (82558 and later). */
-    eepro100_interrupt(s, 0x01);
-}
-#endif
-
-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;
-
-    TRACE(OTHER, logout("%p\n", s));
-
-    /* PCI Status */
-    pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_DEVSEL_MEDIUM |
-                                        PCI_STATUS_FAST_BACK);
-    /* PCI Latency Timer */
-    pci_set_byte(pci_conf + PCI_LATENCY_TIMER, 0x20);   /* latency timer = 32 clocks */
-    /* Capability Pointer is set by PCI framework. */
-    /* Interrupt Line */
-    /* Interrupt Pin */
-    pci_set_byte(pci_conf + PCI_INTERRUPT_PIN, 1);      /* interrupt pin A */
-    /* Minimum Grant */
-    pci_set_byte(pci_conf + PCI_MIN_GNT, 0x08);
-    /* Maximum Latency */
-    pci_set_byte(pci_conf + PCI_MAX_LAT, 0x18);
-
-    s->stats_size = info->stats_size;
-    s->has_extended_tcb_support = info->has_extended_tcb_support;
-
-    switch (device) {
-    case i82550:
-    case i82551:
-    case i82557A:
-    case i82557B:
-    case i82557C:
-    case i82558A:
-    case i82558B:
-    case i82559A:
-    case i82559B:
-    case i82559ER:
-    case i82562:
-    case i82801:
-    case i82559C:
-        break;
-    default:
-        logout("Device %X is undefined!\n", device);
-    }
-
-    /* Standard TxCB. */
-    s->configuration[6] |= BIT(4);
-
-    /* Standard statistical counters. */
-    s->configuration[6] |= BIT(5);
-
-    if (s->stats_size == 80) {
-        /* TODO: check TCO Statistical Counters bit. Documentation not clear. */
-        if (s->configuration[6] & BIT(2)) {
-            /* TCO statistical counters. */
-            assert(s->configuration[6] & BIT(5));
-        } else {
-            if (s->configuration[6] & BIT(5)) {
-                /* No extended statistical counters, i82557 compatible. */
-                s->stats_size = 64;
-            } else {
-                /* i82558 compatible. */
-                s->stats_size = 76;
-            }
-        }
-    } else {
-        if (s->configuration[6] & BIT(5)) {
-            /* No extended statistical counters. */
-            s->stats_size = 64;
-        }
-    }
-    assert(s->stats_size > 0 && s->stats_size <= sizeof(s->statistics));
-
-    if (info->power_management) {
-        /* Power Management Capabilities */
-        int cfg_offset = 0xdc;
-        int r = pci_add_capability(&s->dev, PCI_CAP_ID_PM,
-                                   cfg_offset, PCI_PM_SIZEOF);
-        assert(r >= 0);
-        pci_set_word(pci_conf + cfg_offset + PCI_PM_PMC, 0x7e21);
-#if 0 /* TODO: replace dummy code for power management emulation. */
-        /* TODO: Power Management Control / Status. */
-        pci_set_word(pci_conf + cfg_offset + PCI_PM_CTRL, 0x0000);
-        /* TODO: Ethernet Power Consumption Registers (i82559 and later). */
-        pci_set_byte(pci_conf + cfg_offset + PCI_PM_PPB_EXTENSIONS, 0x0000);
-#endif
-    }
-
-#if EEPROM_SIZE > 0
-    if (device == i82557C || device == i82558B || device == i82559C) {
-        /*
-        TODO: get vendor id from EEPROM for i82557C or later.
-        TODO: get device id from EEPROM for i82557C or later.
-        TODO: status bit 4 can be disabled by EEPROM for i82558, i82559.
-        TODO: header type is determined by EEPROM for i82559.
-        TODO: get subsystem id from EEPROM for i82557C or later.
-        TODO: get subsystem vendor id from EEPROM for i82557C or later.
-        TODO: exp. rom baddr depends on a bit in EEPROM for i82558 or later.
-        TODO: capability pointer depends on EEPROM for i82558.
-        */
-        logout("Get device id and revision from EEPROM!!!\n");
-    }
-#endif /* EEPROM_SIZE > 0 */
-}
-
-static void nic_selective_reset(EEPRO100State * s)
-{
-    size_t i;
-    uint16_t *eeprom_contents = eeprom93xx_data(s->eeprom);
-#if 0
-    eeprom93xx_reset(s->eeprom);
-#endif
-    memcpy(eeprom_contents, s->conf.macaddr.a, 6);
-    eeprom_contents[EEPROM_ID] = EEPROM_ID_VALID;
-    if (s->device == i82557B || s->device == i82557C)
-        eeprom_contents[5] = 0x0100;
-    eeprom_contents[EEPROM_PHY_ID] = 1;
-    uint16_t sum = 0;
-    for (i = 0; i < EEPROM_SIZE - 1; i++) {
-        sum += eeprom_contents[i];
-    }
-    eeprom_contents[EEPROM_SIZE - 1] = 0xbaba - sum;
-    TRACE(EEPROM, logout("checksum=0x%04x\n", eeprom_contents[EEPROM_SIZE - 1]));
-
-    memset(s->mem, 0, sizeof(s->mem));
-    e100_write_reg4(s, SCBCtrlMDI, BIT(21));
-
-    assert(sizeof(s->mdimem) == sizeof(eepro100_mdi_default));
-    memcpy(&s->mdimem[0], &eepro100_mdi_default[0], sizeof(s->mdimem));
-}
-
-static void nic_reset(void *opaque)
-{
-    EEPRO100State *s = opaque;
-    TRACE(OTHER, logout("%p\n", s));
-    /* TODO: Clearing of hash register for selective reset, too? */
-    memset(&s->mult[0], 0, sizeof(s->mult));
-    nic_selective_reset(s);
-}
-
-#if defined(DEBUG_EEPRO100)
-static const char * const e100_reg[PCI_IO_SIZE / 4] = {
-    "Command/Status",
-    "General Pointer",
-    "Port",
-    "EEPROM/Flash Control",
-    "MDI Control",
-    "Receive DMA Byte Count",
-    "Flow Control",
-    "General Status/Control"
-};
-
-static char *regname(uint32_t addr)
-{
-    static char buf[32];
-    if (addr < PCI_IO_SIZE) {
-        const char *r = e100_reg[addr / 4];
-        if (r != 0) {
-            snprintf(buf, sizeof(buf), "%s+%u", r, addr % 4);
-        } else {
-            snprintf(buf, sizeof(buf), "0x%02x", addr);
-        }
-    } else {
-        snprintf(buf, sizeof(buf), "??? 0x%08x", addr);
-    }
-    return buf;
-}
-#endif                          /* DEBUG_EEPRO100 */
-
-/*****************************************************************************
- *
- * Command emulation.
- *
- ****************************************************************************/
-
-#if 0
-static uint16_t eepro100_read_command(EEPRO100State * s)
-{
-    uint16_t val = 0xffff;
-    TRACE(OTHER, logout("val=0x%04x\n", val));
-    return val;
-}
-#endif
-
-/* Commands that can be put in a command list entry. */
-enum commands {
-    CmdNOp = 0,
-    CmdIASetup = 1,
-    CmdConfigure = 2,
-    CmdMulticastList = 3,
-    CmdTx = 4,
-    CmdTDR = 5,                 /* load microcode */
-    CmdDump = 6,
-    CmdDiagnose = 7,
-
-    /* And some extra flags: */
-    CmdSuspend = 0x4000,        /* Suspend after completion. */
-    CmdIntr = 0x2000,           /* Interrupt after completion. */
-    CmdTxFlex = 0x0008,         /* Use "Flexible mode" for CmdTx command. */
-};
-
-static cu_state_t get_cu_state(EEPRO100State * s)
-{
-    return ((s->mem[SCBStatus] & BITS(7, 6)) >> 6);
-}
-
-static void set_cu_state(EEPRO100State * s, cu_state_t state)
-{
-    s->mem[SCBStatus] = (s->mem[SCBStatus] & ~BITS(7, 6)) + (state << 6);
-}
-
-static ru_state_t get_ru_state(EEPRO100State * s)
-{
-    return ((s->mem[SCBStatus] & BITS(5, 2)) >> 2);
-}
-
-static void set_ru_state(EEPRO100State * s, ru_state_t state)
-{
-    s->mem[SCBStatus] = (s->mem[SCBStatus] & ~BITS(5, 2)) + (state << 2);
-}
-
-static void dump_statistics(EEPRO100State * s)
-{
-    /* Dump statistical data. Most data is never changed by the emulation
-     * and always 0, so we first just copy the whole block and then those
-     * values which really matter.
-     * Number of data should check configuration!!!
-     */
-    pci_dma_write(&s->dev, s->statsaddr, &s->statistics, s->stats_size);
-    stl_le_pci_dma(&s->dev, s->statsaddr + 0,
-                   s->statistics.tx_good_frames);
-    stl_le_pci_dma(&s->dev, s->statsaddr + 36,
-                   s->statistics.rx_good_frames);
-    stl_le_pci_dma(&s->dev, s->statsaddr + 48,
-                   s->statistics.rx_resource_errors);
-    stl_le_pci_dma(&s->dev, s->statsaddr + 60,
-                   s->statistics.rx_short_frame_errors);
-#if 0
-    stw_le_pci_dma(&s->dev, s->statsaddr + 76, s->statistics.xmt_tco_frames);
-    stw_le_pci_dma(&s->dev, s->statsaddr + 78, s->statistics.rcv_tco_frames);
-    missing("CU dump statistical counters");
-#endif
-}
-
-static void read_cb(EEPRO100State *s)
-{
-    pci_dma_read(&s->dev, s->cb_address, &s->tx, sizeof(s->tx));
-    s->tx.status = le16_to_cpu(s->tx.status);
-    s->tx.command = le16_to_cpu(s->tx.command);
-    s->tx.link = le32_to_cpu(s->tx.link);
-    s->tx.tbd_array_addr = le32_to_cpu(s->tx.tbd_array_addr);
-    s->tx.tcb_bytes = le16_to_cpu(s->tx.tcb_bytes);
-}
-
-static void tx_command(EEPRO100State *s)
-{
-    uint32_t tbd_array = le32_to_cpu(s->tx.tbd_array_addr);
-    uint16_t tcb_bytes = (le16_to_cpu(s->tx.tcb_bytes) & 0x3fff);
-    /* Sends larger than MAX_ETH_FRAME_SIZE are allowed, up to 2600 bytes. */
-    uint8_t buf[2600];
-    uint16_t size = 0;
-    uint32_t tbd_address = s->cb_address + 0x10;
-    TRACE(RXTX, logout
-        ("transmit, TBD array address 0x%08x, TCB byte count 0x%04x, TBD count %u\n",
-         tbd_array, tcb_bytes, s->tx.tbd_count));
-
-    if (tcb_bytes > 2600) {
-        logout("TCB byte count too large, using 2600\n");
-        tcb_bytes = 2600;
-    }
-    if (!((tcb_bytes > 0) || (tbd_array != 0xffffffff))) {
-        logout
-            ("illegal values of TBD array address and TCB byte count!\n");
-    }
-    assert(tcb_bytes <= sizeof(buf));
-    while (size < tcb_bytes) {
-        uint32_t tx_buffer_address = ldl_le_pci_dma(&s->dev, tbd_address);
-        uint16_t tx_buffer_size = lduw_le_pci_dma(&s->dev, tbd_address + 4);
-#if 0
-        uint16_t tx_buffer_el = lduw_le_pci_dma(&s->dev, tbd_address + 6);
-#endif
-        tbd_address += 8;
-        TRACE(RXTX, logout
-            ("TBD (simplified mode): buffer address 0x%08x, size 0x%04x\n",
-             tx_buffer_address, tx_buffer_size));
-        tx_buffer_size = MIN(tx_buffer_size, sizeof(buf) - size);
-        pci_dma_read(&s->dev, tx_buffer_address, &buf[size], tx_buffer_size);
-        size += tx_buffer_size;
-    }
-    if (tbd_array == 0xffffffff) {
-        /* Simplified mode. Was already handled by code above. */
-    } else {
-        /* Flexible mode. */
-        uint8_t tbd_count = 0;
-        if (s->has_extended_tcb_support && !(s->configuration[6] & BIT(4))) {
-            /* Extended Flexible TCB. */
-            for (; tbd_count < 2; tbd_count++) {
-                uint32_t tx_buffer_address = ldl_le_pci_dma(&s->dev,
-                                                            tbd_address);
-                uint16_t tx_buffer_size = lduw_le_pci_dma(&s->dev,
-                                                          tbd_address + 4);
-                uint16_t tx_buffer_el = lduw_le_pci_dma(&s->dev,
-                                                        tbd_address + 6);
-                tbd_address += 8;
-                TRACE(RXTX, logout
-                    ("TBD (extended flexible mode): buffer address 0x%08x, size 0x%04x\n",
-                     tx_buffer_address, tx_buffer_size));
-                tx_buffer_size = MIN(tx_buffer_size, sizeof(buf) - size);
-                pci_dma_read(&s->dev, tx_buffer_address,
-                             &buf[size], tx_buffer_size);
-                size += tx_buffer_size;
-                if (tx_buffer_el & 1) {
-                    break;
-                }
-            }
-        }
-        tbd_address = tbd_array;
-        for (; tbd_count < s->tx.tbd_count; tbd_count++) {
-            uint32_t tx_buffer_address = ldl_le_pci_dma(&s->dev, tbd_address);
-            uint16_t tx_buffer_size = lduw_le_pci_dma(&s->dev, tbd_address + 4);
-            uint16_t tx_buffer_el = lduw_le_pci_dma(&s->dev, tbd_address + 6);
-            tbd_address += 8;
-            TRACE(RXTX, logout
-                ("TBD (flexible mode): buffer address 0x%08x, size 0x%04x\n",
-                 tx_buffer_address, tx_buffer_size));
-            tx_buffer_size = MIN(tx_buffer_size, sizeof(buf) - size);
-            pci_dma_read(&s->dev, tx_buffer_address,
-                         &buf[size], tx_buffer_size);
-            size += tx_buffer_size;
-            if (tx_buffer_el & 1) {
-                break;
-            }
-        }
-    }
-    TRACE(RXTX, logout("%p sending frame, len=%d,%s\n", s, size, nic_dump(buf, size)));
-    qemu_send_packet(qemu_get_queue(s->nic), buf, size);
-    s->statistics.tx_good_frames++;
-    /* Transmit with bad status would raise an CX/TNO interrupt.
-     * (82557 only). Emulation never has bad status. */
-#if 0
-    eepro100_cx_interrupt(s);
-#endif
-}
-
-static void set_multicast_list(EEPRO100State *s)
-{
-    uint16_t multicast_count = s->tx.tbd_array_addr & BITS(13, 0);
-    uint16_t i;
-    memset(&s->mult[0], 0, sizeof(s->mult));
-    TRACE(OTHER, logout("multicast list, multicast count = %u\n", multicast_count));
-    for (i = 0; i < multicast_count; i += 6) {
-        uint8_t multicast_addr[6];
-        pci_dma_read(&s->dev, s->cb_address + 10 + i, multicast_addr, 6);
-        TRACE(OTHER, logout("multicast entry %s\n", nic_dump(multicast_addr, 6)));
-        unsigned mcast_idx = e100_compute_mcast_idx(multicast_addr);
-        assert(mcast_idx < 64);
-        s->mult[mcast_idx >> 3] |= (1 << (mcast_idx & 7));
-    }
-}
-
-static void action_command(EEPRO100State *s)
-{
-    for (;;) {
-        bool bit_el;
-        bool bit_s;
-        bool bit_i;
-        bool bit_nc;
-        uint16_t ok_status = STATUS_OK;
-        s->cb_address = s->cu_base + s->cu_offset;
-        read_cb(s);
-        bit_el = ((s->tx.command & COMMAND_EL) != 0);
-        bit_s = ((s->tx.command & COMMAND_S) != 0);
-        bit_i = ((s->tx.command & COMMAND_I) != 0);
-        bit_nc = ((s->tx.command & COMMAND_NC) != 0);
-#if 0
-        bool bit_sf = ((s->tx.command & COMMAND_SF) != 0);
-#endif
-        s->cu_offset = s->tx.link;
-        TRACE(OTHER,
-              logout("val=(cu start), status=0x%04x, command=0x%04x, link=0x%08x\n",
-                     s->tx.status, s->tx.command, s->tx.link));
-        switch (s->tx.command & COMMAND_CMD) {
-        case CmdNOp:
-            /* Do nothing. */
-            break;
-        case CmdIASetup:
-            pci_dma_read(&s->dev, s->cb_address + 8, &s->conf.macaddr.a[0], 6);
-            TRACE(OTHER, logout("macaddr: %s\n", nic_dump(&s->conf.macaddr.a[0], 6)));
-            break;
-        case CmdConfigure:
-            pci_dma_read(&s->dev, s->cb_address + 8,
-                         &s->configuration[0], sizeof(s->configuration));
-            TRACE(OTHER, logout("configuration: %s\n",
-                                nic_dump(&s->configuration[0], 16)));
-            TRACE(OTHER, logout("configuration: %s\n",
-                                nic_dump(&s->configuration[16],
-                                ARRAY_SIZE(s->configuration) - 16)));
-            if (s->configuration[20] & BIT(6)) {
-                TRACE(OTHER, logout("Multiple IA bit\n"));
-            }
-            break;
-        case CmdMulticastList:
-            set_multicast_list(s);
-            break;
-        case CmdTx:
-            if (bit_nc) {
-                missing("CmdTx: NC = 0");
-                ok_status = 0;
-                break;
-            }
-            tx_command(s);
-            break;
-        case CmdTDR:
-            TRACE(OTHER, logout("load microcode\n"));
-            /* Starting with offset 8, the command contains
-             * 64 dwords microcode which we just ignore here. */
-            break;
-        case CmdDiagnose:
-            TRACE(OTHER, logout("diagnose\n"));
-            /* Make sure error flag is not set. */
-            s->tx.status = 0;
-            break;
-        default:
-            missing("undefined command");
-            ok_status = 0;
-            break;
-        }
-        /* Write new status. */
-        stw_le_pci_dma(&s->dev, s->cb_address,
-                       s->tx.status | ok_status | STATUS_C);
-        if (bit_i) {
-            /* CU completed action. */
-            eepro100_cx_interrupt(s);
-        }
-        if (bit_el) {
-            /* CU becomes idle. Terminate command loop. */
-            set_cu_state(s, cu_idle);
-            eepro100_cna_interrupt(s);
-            break;
-        } else if (bit_s) {
-            /* CU becomes suspended. Terminate command loop. */
-            set_cu_state(s, cu_suspended);
-            eepro100_cna_interrupt(s);
-            break;
-        } else {
-            /* More entries in list. */
-            TRACE(OTHER, logout("CU list with at least one more entry\n"));
-        }
-    }
-    TRACE(OTHER, logout("CU list empty\n"));
-    /* List is empty. Now CU is idle or suspended. */
-}
-
-static void eepro100_cu_command(EEPRO100State * s, uint8_t val)
-{
-    cu_state_t cu_state;
-    switch (val) {
-    case CU_NOP:
-        /* No operation. */
-        break;
-    case CU_START:
-        cu_state = get_cu_state(s);
-        if (cu_state != cu_idle && cu_state != cu_suspended) {
-            /* Intel documentation says that CU must be idle or suspended
-             * for the CU start command. */
-            logout("unexpected CU state is %u\n", cu_state);
-        }
-        set_cu_state(s, cu_active);
-        s->cu_offset = e100_read_reg4(s, SCBPointer);
-        action_command(s);
-        break;
-    case CU_RESUME:
-        if (get_cu_state(s) != cu_suspended) {
-            logout("bad CU resume from CU state %u\n", get_cu_state(s));
-            /* Workaround for bad Linux eepro100 driver which resumes
-             * from idle state. */
-#if 0
-            missing("cu resume");
-#endif
-            set_cu_state(s, cu_suspended);
-        }
-        if (get_cu_state(s) == cu_suspended) {
-            TRACE(OTHER, logout("CU resuming\n"));
-            set_cu_state(s, cu_active);
-            action_command(s);
-        }
-        break;
-    case CU_STATSADDR:
-        /* Load dump counters address. */
-        s->statsaddr = e100_read_reg4(s, SCBPointer);
-        TRACE(OTHER, logout("val=0x%02x (dump counters address)\n", val));
-        if (s->statsaddr & 3) {
-            /* Memory must be Dword aligned. */
-            logout("unaligned dump counters address\n");
-            /* Handling of misaligned addresses is undefined.
-             * Here we align the address by ignoring the lower bits. */
-            /* TODO: Test unaligned dump counter address on real hardware. */
-            s->statsaddr &= ~3;
-        }
-        break;
-    case CU_SHOWSTATS:
-        /* Dump statistical counters. */
-        TRACE(OTHER, logout("val=0x%02x (dump stats)\n", val));
-        dump_statistics(s);
-        stl_le_pci_dma(&s->dev, s->statsaddr + s->stats_size, 0xa005);
-        break;
-    case CU_CMD_BASE:
-        /* Load CU base. */
-        TRACE(OTHER, logout("val=0x%02x (CU base address)\n", val));
-        s->cu_base = e100_read_reg4(s, SCBPointer);
-        break;
-    case CU_DUMPSTATS:
-        /* Dump and reset statistical counters. */
-        TRACE(OTHER, logout("val=0x%02x (dump stats and reset)\n", val));
-        dump_statistics(s);
-        stl_le_pci_dma(&s->dev, s->statsaddr + s->stats_size, 0xa007);
-        memset(&s->statistics, 0, sizeof(s->statistics));
-        break;
-    case CU_SRESUME:
-        /* CU static resume. */
-        missing("CU static resume");
-        break;
-    default:
-        missing("Undefined CU command");
-    }
-}
-
-static void eepro100_ru_command(EEPRO100State * s, uint8_t val)
-{
-    switch (val) {
-    case RU_NOP:
-        /* No operation. */
-        break;
-    case RX_START:
-        /* RU start. */
-        if (get_ru_state(s) != ru_idle) {
-            logout("RU state is %u, should be %u\n", get_ru_state(s), ru_idle);
-#if 0
-            assert(!"wrong RU state");
-#endif
-        }
-        set_ru_state(s, ru_ready);
-        s->ru_offset = e100_read_reg4(s, SCBPointer);
-        qemu_flush_queued_packets(qemu_get_queue(s->nic));
-        TRACE(OTHER, logout("val=0x%02x (rx start)\n", val));
-        break;
-    case RX_RESUME:
-        /* Restart RU. */
-        if (get_ru_state(s) != ru_suspended) {
-            logout("RU state is %u, should be %u\n", get_ru_state(s),
-                   ru_suspended);
-#if 0
-            assert(!"wrong RU state");
-#endif
-        }
-        set_ru_state(s, ru_ready);
-        break;
-    case RU_ABORT:
-        /* RU abort. */
-        if (get_ru_state(s) == ru_ready) {
-            eepro100_rnr_interrupt(s);
-        }
-        set_ru_state(s, ru_idle);
-        break;
-    case RX_ADDR_LOAD:
-        /* Load RU base. */
-        TRACE(OTHER, logout("val=0x%02x (RU base address)\n", val));
-        s->ru_base = e100_read_reg4(s, SCBPointer);
-        break;
-    default:
-        logout("val=0x%02x (undefined RU command)\n", val);
-        missing("Undefined SU command");
-    }
-}
-
-static void eepro100_write_command(EEPRO100State * s, uint8_t val)
-{
-    eepro100_ru_command(s, val & 0x0f);
-    eepro100_cu_command(s, val & 0xf0);
-    if ((val) == 0) {
-        TRACE(OTHER, logout("val=0x%02x\n", val));
-    }
-    /* Clear command byte after command was accepted. */
-    s->mem[SCBCmd] = 0;
-}
-
-/*****************************************************************************
- *
- * EEPROM emulation.
- *
- ****************************************************************************/
-
-#define EEPROM_CS       0x02
-#define EEPROM_SK       0x01
-#define EEPROM_DI       0x04
-#define EEPROM_DO       0x08
-
-static uint16_t eepro100_read_eeprom(EEPRO100State * s)
-{
-    uint16_t val = e100_read_reg2(s, SCBeeprom);
-    if (eeprom93xx_read(s->eeprom)) {
-        val |= EEPROM_DO;
-    } else {
-        val &= ~EEPROM_DO;
-    }
-    TRACE(EEPROM, logout("val=0x%04x\n", val));
-    return val;
-}
-
-static void eepro100_write_eeprom(eeprom_t * eeprom, uint8_t val)
-{
-    TRACE(EEPROM, logout("val=0x%02x\n", val));
-
-    /* mask unwritable bits */
-#if 0
-    val = SET_MASKED(val, 0x31, eeprom->value);
-#endif
-
-    int eecs = ((val & EEPROM_CS) != 0);
-    int eesk = ((val & EEPROM_SK) != 0);
-    int eedi = ((val & EEPROM_DI) != 0);
-    eeprom93xx_write(eeprom, eecs, eesk, eedi);
-}
-
-/*****************************************************************************
- *
- * MDI emulation.
- *
- ****************************************************************************/
-
-#if defined(DEBUG_EEPRO100)
-static const char * const mdi_op_name[] = {
-    "opcode 0",
-    "write",
-    "read",
-    "opcode 3"
-};
-
-static const char * const mdi_reg_name[] = {
-    "Control",
-    "Status",
-    "PHY Identification (Word 1)",
-    "PHY Identification (Word 2)",
-    "Auto-Negotiation Advertisement",
-    "Auto-Negotiation Link Partner Ability",
-    "Auto-Negotiation Expansion"
-};
-
-static const char *reg2name(uint8_t reg)
-{
-    static char buffer[10];
-    const char *p = buffer;
-    if (reg < ARRAY_SIZE(mdi_reg_name)) {
-        p = mdi_reg_name[reg];
-    } else {
-        snprintf(buffer, sizeof(buffer), "reg=0x%02x", reg);
-    }
-    return p;
-}
-#endif                          /* DEBUG_EEPRO100 */
-
-static uint32_t eepro100_read_mdi(EEPRO100State * s)
-{
-    uint32_t val = e100_read_reg4(s, SCBCtrlMDI);
-
-#ifdef DEBUG_EEPRO100
-    uint8_t raiseint = (val & BIT(29)) >> 29;
-    uint8_t opcode = (val & BITS(27, 26)) >> 26;
-    uint8_t phy = (val & BITS(25, 21)) >> 21;
-    uint8_t reg = (val & BITS(20, 16)) >> 16;
-    uint16_t data = (val & BITS(15, 0));
-#endif
-    /* Emulation takes no time to finish MDI transaction. */
-    val |= BIT(28);
-    TRACE(MDI, logout("val=0x%08x (int=%u, %s, phy=%u, %s, data=0x%04x\n",
-                      val, raiseint, mdi_op_name[opcode], phy,
-                      reg2name(reg), data));
-    return val;
-}
-
-static void eepro100_write_mdi(EEPRO100State *s)
-{
-    uint32_t val = e100_read_reg4(s, SCBCtrlMDI);
-    uint8_t raiseint = (val & BIT(29)) >> 29;
-    uint8_t opcode = (val & BITS(27, 26)) >> 26;
-    uint8_t phy = (val & BITS(25, 21)) >> 21;
-    uint8_t reg = (val & BITS(20, 16)) >> 16;
-    uint16_t data = (val & BITS(15, 0));
-    TRACE(MDI, logout("val=0x%08x (int=%u, %s, phy=%u, %s, data=0x%04x\n",
-          val, raiseint, mdi_op_name[opcode], phy, reg2name(reg), data));
-    if (phy != 1) {
-        /* Unsupported PHY address. */
-#if 0
-        logout("phy must be 1 but is %u\n", phy);
-#endif
-        data = 0;
-    } else if (opcode != 1 && opcode != 2) {
-        /* Unsupported opcode. */
-        logout("opcode must be 1 or 2 but is %u\n", opcode);
-        data = 0;
-    } else if (reg > 6) {
-        /* Unsupported register. */
-        logout("register must be 0...6 but is %u\n", reg);
-        data = 0;
-    } else {
-        TRACE(MDI, logout("val=0x%08x (int=%u, %s, phy=%u, %s, data=0x%04x\n",
-                          val, raiseint, mdi_op_name[opcode], phy,
-                          reg2name(reg), data));
-        if (opcode == 1) {
-            /* MDI write */
-            switch (reg) {
-            case 0:            /* Control Register */
-                if (data & 0x8000) {
-                    /* Reset status and control registers to default. */
-                    s->mdimem[0] = eepro100_mdi_default[0];
-                    s->mdimem[1] = eepro100_mdi_default[1];
-                    data = s->mdimem[reg];
-                } else {
-                    /* Restart Auto Configuration = Normal Operation */
-                    data &= ~0x0200;
-                }
-                break;
-            case 1:            /* Status Register */
-                missing("not writable");
-                data = s->mdimem[reg];
-                break;
-            case 2:            /* PHY Identification Register (Word 1) */
-            case 3:            /* PHY Identification Register (Word 2) */
-                missing("not implemented");
-                break;
-            case 4:            /* Auto-Negotiation Advertisement Register */
-            case 5:            /* Auto-Negotiation Link Partner Ability Register */
-                break;
-            case 6:            /* Auto-Negotiation Expansion Register */
-            default:
-                missing("not implemented");
-            }
-            s->mdimem[reg] = data;
-        } else if (opcode == 2) {
-            /* MDI read */
-            switch (reg) {
-            case 0:            /* Control Register */
-                if (data & 0x8000) {
-                    /* Reset status and control registers to default. */
-                    s->mdimem[0] = eepro100_mdi_default[0];
-                    s->mdimem[1] = eepro100_mdi_default[1];
-                }
-                break;
-            case 1:            /* Status Register */
-                s->mdimem[reg] |= 0x0020;
-                break;
-            case 2:            /* PHY Identification Register (Word 1) */
-            case 3:            /* PHY Identification Register (Word 2) */
-            case 4:            /* Auto-Negotiation Advertisement Register */
-                break;
-            case 5:            /* Auto-Negotiation Link Partner Ability Register */
-                s->mdimem[reg] = 0x41fe;
-                break;
-            case 6:            /* Auto-Negotiation Expansion Register */
-                s->mdimem[reg] = 0x0001;
-                break;
-            }
-            data = s->mdimem[reg];
-        }
-        /* Emulation takes no time to finish MDI transaction.
-         * Set MDI bit in SCB status register. */
-        s->mem[SCBAck] |= 0x08;
-        val |= BIT(28);
-        if (raiseint) {
-            eepro100_mdi_interrupt(s);
-        }
-    }
-    val = (val & 0xffff0000) + data;
-    e100_write_reg4(s, SCBCtrlMDI, val);
-}
-
-/*****************************************************************************
- *
- * Port emulation.
- *
- ****************************************************************************/
-
-#define PORT_SOFTWARE_RESET     0
-#define PORT_SELFTEST           1
-#define PORT_SELECTIVE_RESET    2
-#define PORT_DUMP               3
-#define PORT_SELECTION_MASK     3
-
-typedef struct {
-    uint32_t st_sign;           /* Self Test Signature */
-    uint32_t st_result;         /* Self Test Results */
-} eepro100_selftest_t;
-
-static uint32_t eepro100_read_port(EEPRO100State * s)
-{
-    return 0;
-}
-
-static void eepro100_write_port(EEPRO100State *s)
-{
-    uint32_t val = e100_read_reg4(s, SCBPort);
-    uint32_t address = (val & ~PORT_SELECTION_MASK);
-    uint8_t selection = (val & PORT_SELECTION_MASK);
-    switch (selection) {
-    case PORT_SOFTWARE_RESET:
-        nic_reset(s);
-        break;
-    case PORT_SELFTEST:
-        TRACE(OTHER, logout("selftest address=0x%08x\n", address));
-        eepro100_selftest_t data;
-        pci_dma_read(&s->dev, address, (uint8_t *) &data, sizeof(data));
-        data.st_sign = 0xffffffff;
-        data.st_result = 0;
-        pci_dma_write(&s->dev, address, (uint8_t *) &data, sizeof(data));
-        break;
-    case PORT_SELECTIVE_RESET:
-        TRACE(OTHER, logout("selective reset, selftest address=0x%08x\n", address));
-        nic_selective_reset(s);
-        break;
-    default:
-        logout("val=0x%08x\n", val);
-        missing("unknown port selection");
-    }
-}
-
-/*****************************************************************************
- *
- * General hardware emulation.
- *
- ****************************************************************************/
-
-static uint8_t eepro100_read1(EEPRO100State * s, uint32_t addr)
-{
-    uint8_t val = 0;
-    if (addr <= sizeof(s->mem) - sizeof(val)) {
-        val = s->mem[addr];
-    }
-
-    switch (addr) {
-    case SCBStatus:
-    case SCBAck:
-        TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
-        break;
-    case SCBCmd:
-        TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
-#if 0
-        val = eepro100_read_command(s);
-#endif
-        break;
-    case SCBIntmask:
-        TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
-        break;
-    case SCBPort + 3:
-        TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
-        break;
-    case SCBeeprom:
-        val = eepro100_read_eeprom(s);
-        break;
-    case SCBCtrlMDI:
-    case SCBCtrlMDI + 1:
-    case SCBCtrlMDI + 2:
-    case SCBCtrlMDI + 3:
-        val = (uint8_t)(eepro100_read_mdi(s) >> (8 * (addr & 3)));
-        TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
-        break;
-    case SCBpmdr:       /* Power Management Driver Register */
-        val = 0;
-        TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
-        break;
-    case SCBgctrl:      /* General Control Register */
-        TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
-        break;
-    case SCBgstat:      /* General Status Register */
-        /* 100 Mbps full duplex, valid link */
-        val = 0x07;
-        TRACE(OTHER, logout("addr=General Status val=%02x\n", val));
-        break;
-    default:
-        logout("addr=%s val=0x%02x\n", regname(addr), val);
-        missing("unknown byte read");
-    }
-    return val;
-}
-
-static uint16_t eepro100_read2(EEPRO100State * s, uint32_t addr)
-{
-    uint16_t val = 0;
-    if (addr <= sizeof(s->mem) - sizeof(val)) {
-        val = e100_read_reg2(s, addr);
-    }
-
-    switch (addr) {
-    case SCBStatus:
-    case SCBCmd:
-        TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
-        break;
-    case SCBeeprom:
-        val = eepro100_read_eeprom(s);
-        TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
-        break;
-    case SCBCtrlMDI:
-    case SCBCtrlMDI + 2:
-        val = (uint16_t)(eepro100_read_mdi(s) >> (8 * (addr & 3)));
-        TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
-        break;
-    default:
-        logout("addr=%s val=0x%04x\n", regname(addr), val);
-        missing("unknown word read");
-    }
-    return val;
-}
-
-static uint32_t eepro100_read4(EEPRO100State * s, uint32_t addr)
-{
-    uint32_t val = 0;
-    if (addr <= sizeof(s->mem) - sizeof(val)) {
-        val = e100_read_reg4(s, addr);
-    }
-
-    switch (addr) {
-    case SCBStatus:
-        TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val));
-        break;
-    case SCBPointer:
-        TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val));
-        break;
-    case SCBPort:
-        val = eepro100_read_port(s);
-        TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val));
-        break;
-    case SCBflash:
-        val = eepro100_read_eeprom(s);
-        TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val));
-        break;
-    case SCBCtrlMDI:
-        val = eepro100_read_mdi(s);
-        break;
-    default:
-        logout("addr=%s val=0x%08x\n", regname(addr), val);
-        missing("unknown longword read");
-    }
-    return val;
-}
-
-static void eepro100_write1(EEPRO100State * s, uint32_t addr, uint8_t val)
-{
-    /* SCBStatus is readonly. */
-    if (addr > SCBStatus && addr <= sizeof(s->mem) - sizeof(val)) {
-        s->mem[addr] = val;
-    }
-
-    switch (addr) {
-    case SCBStatus:
-        TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
-        break;
-    case SCBAck:
-        TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
-        eepro100_acknowledge(s);
-        break;
-    case SCBCmd:
-        TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
-        eepro100_write_command(s, val);
-        break;
-    case SCBIntmask:
-        TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
-        if (val & BIT(1)) {
-            eepro100_swi_interrupt(s);
-        }
-        eepro100_interrupt(s, 0);
-        break;
-    case SCBPointer:
-    case SCBPointer + 1:
-    case SCBPointer + 2:
-    case SCBPointer + 3:
-        TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
-        break;
-    case SCBPort:
-    case SCBPort + 1:
-    case SCBPort + 2:
-        TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
-        break;
-    case SCBPort + 3:
-        TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
-        eepro100_write_port(s);
-        break;
-    case SCBFlow:       /* does not exist on 82557 */
-    case SCBFlow + 1:
-    case SCBFlow + 2:
-    case SCBpmdr:       /* does not exist on 82557 */
-        TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
-        break;
-    case SCBeeprom:
-        TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
-        eepro100_write_eeprom(s->eeprom, val);
-        break;
-    case SCBCtrlMDI:
-    case SCBCtrlMDI + 1:
-    case SCBCtrlMDI + 2:
-        TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
-        break;
-    case SCBCtrlMDI + 3:
-        TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
-        eepro100_write_mdi(s);
-        break;
-    default:
-        logout("addr=%s val=0x%02x\n", regname(addr), val);
-        missing("unknown byte write");
-    }
-}
-
-static void eepro100_write2(EEPRO100State * s, uint32_t addr, uint16_t val)
-{
-    /* SCBStatus is readonly. */
-    if (addr > SCBStatus && addr <= sizeof(s->mem) - sizeof(val)) {
-        e100_write_reg2(s, addr, val);
-    }
-
-    switch (addr) {
-    case SCBStatus:
-        TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
-        s->mem[SCBAck] = (val >> 8);
-        eepro100_acknowledge(s);
-        break;
-    case SCBCmd:
-        TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
-        eepro100_write_command(s, val);
-        eepro100_write1(s, SCBIntmask, val >> 8);
-        break;
-    case SCBPointer:
-    case SCBPointer + 2:
-        TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
-        break;
-    case SCBPort:
-        TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
-        break;
-    case SCBPort + 2:
-        TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
-        eepro100_write_port(s);
-        break;
-    case SCBeeprom:
-        TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
-        eepro100_write_eeprom(s->eeprom, val);
-        break;
-    case SCBCtrlMDI:
-        TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
-        break;
-    case SCBCtrlMDI + 2:
-        TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
-        eepro100_write_mdi(s);
-        break;
-    default:
-        logout("addr=%s val=0x%04x\n", regname(addr), val);
-        missing("unknown word write");
-    }
-}
-
-static void eepro100_write4(EEPRO100State * s, uint32_t addr, uint32_t val)
-{
-    if (addr <= sizeof(s->mem) - sizeof(val)) {
-        e100_write_reg4(s, addr, val);
-    }
-
-    switch (addr) {
-    case SCBPointer:
-        TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val));
-        break;
-    case SCBPort:
-        TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val));
-        eepro100_write_port(s);
-        break;
-    case SCBflash:
-        TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val));
-        val = val >> 16;
-        eepro100_write_eeprom(s->eeprom, val);
-        break;
-    case SCBCtrlMDI:
-        TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val));
-        eepro100_write_mdi(s);
-        break;
-    default:
-        logout("addr=%s val=0x%08x\n", regname(addr), val);
-        missing("unknown longword write");
-    }
-}
-
-static uint64_t eepro100_read(void *opaque, hwaddr addr,
-                              unsigned size)
-{
-    EEPRO100State *s = opaque;
-
-    switch (size) {
-    case 1: return eepro100_read1(s, addr);
-    case 2: return eepro100_read2(s, addr);
-    case 4: return eepro100_read4(s, addr);
-    default: abort();
-    }
-}
-
-static void eepro100_write(void *opaque, hwaddr addr,
-                           uint64_t data, unsigned size)
-{
-    EEPRO100State *s = opaque;
-
-    switch (size) {
-    case 1:
-        eepro100_write1(s, addr, data);
-        break;
-    case 2:
-        eepro100_write2(s, addr, data);
-        break;
-    case 4:
-        eepro100_write4(s, addr, data);
-        break;
-    default:
-        abort();
-    }
-}
-
-static const MemoryRegionOps eepro100_ops = {
-    .read = eepro100_read,
-    .write = eepro100_write,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static int nic_can_receive(NetClientState *nc)
-{
-    EEPRO100State *s = qemu_get_nic_opaque(nc);
-    TRACE(RXTX, logout("%p\n", s));
-    return get_ru_state(s) == ru_ready;
-#if 0
-    return !eepro100_buffer_full(s);
-#endif
-}
-
-static ssize_t nic_receive(NetClientState *nc, const uint8_t * buf, size_t size)
-{
-    /* TODO:
-     * - Magic packets should set bit 30 in power management driver register.
-     * - Interesting packets should set bit 29 in power management driver register.
-     */
-    EEPRO100State *s = qemu_get_nic_opaque(nc);
-    uint16_t rfd_status = 0xa000;
-#if defined(CONFIG_PAD_RECEIVED_FRAMES)
-    uint8_t min_buf[60];
-#endif
-    static const uint8_t broadcast_macaddr[6] =
-        { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
-
-#if defined(CONFIG_PAD_RECEIVED_FRAMES)
-    /* Pad to minimum Ethernet frame length */
-    if (size < sizeof(min_buf)) {
-        memcpy(min_buf, buf, size);
-        memset(&min_buf[size], 0, sizeof(min_buf) - size);
-        buf = min_buf;
-        size = sizeof(min_buf);
-    }
-#endif
-
-    if (s->configuration[8] & 0x80) {
-        /* CSMA is disabled. */
-        logout("%p received while CSMA is disabled\n", s);
-        return -1;
-#if !defined(CONFIG_PAD_RECEIVED_FRAMES)
-    } else if (size < 64 && (s->configuration[7] & BIT(0))) {
-        /* Short frame and configuration byte 7/0 (discard short receive) set:
-         * Short frame is discarded */
-        logout("%p received short frame (%zu byte)\n", s, size);
-        s->statistics.rx_short_frame_errors++;
-        return -1;
-#endif
-    } else if ((size > MAX_ETH_FRAME_SIZE + 4) && !(s->configuration[18] & BIT(3))) {
-        /* Long frame and configuration byte 18/3 (long receive ok) not set:
-         * Long frames are discarded. */
-        logout("%p received long frame (%zu byte), ignored\n", s, size);
-        return -1;
-    } else if (memcmp(buf, s->conf.macaddr.a, 6) == 0) {       /* !!! */
-        /* Frame matches individual address. */
-        /* TODO: check configuration byte 15/4 (ignore U/L). */
-        TRACE(RXTX, logout("%p received frame for me, len=%zu\n", s, size));
-    } else if (memcmp(buf, broadcast_macaddr, 6) == 0) {
-        /* Broadcast frame. */
-        TRACE(RXTX, logout("%p received broadcast, len=%zu\n", s, size));
-        rfd_status |= 0x0002;
-    } else if (buf[0] & 0x01) {
-        /* Multicast frame. */
-        TRACE(RXTX, logout("%p received multicast, len=%zu,%s\n", s, size, nic_dump(buf, size)));
-        if (s->configuration[21] & BIT(3)) {
-          /* Multicast all bit is set, receive all multicast frames. */
-        } else {
-          unsigned mcast_idx = e100_compute_mcast_idx(buf);
-          assert(mcast_idx < 64);
-          if (s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7))) {
-            /* Multicast frame is allowed in hash table. */
-          } else if (s->configuration[15] & BIT(0)) {
-              /* Promiscuous: receive all. */
-              rfd_status |= 0x0004;
-          } else {
-              TRACE(RXTX, logout("%p multicast ignored\n", s));
-              return -1;
-          }
-        }
-        /* TODO: Next not for promiscuous mode? */
-        rfd_status |= 0x0002;
-    } else if (s->configuration[15] & BIT(0)) {
-        /* Promiscuous: receive all. */
-        TRACE(RXTX, logout("%p received frame in promiscuous mode, len=%zu\n", s, size));
-        rfd_status |= 0x0004;
-    } else if (s->configuration[20] & BIT(6)) {
-        /* Multiple IA bit set. */
-        unsigned mcast_idx = compute_mcast_idx(buf);
-        assert(mcast_idx < 64);
-        if (s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7))) {
-            TRACE(RXTX, logout("%p accepted, multiple IA bit set\n", s));
-        } else {
-            TRACE(RXTX, logout("%p frame ignored, multiple IA bit set\n", s));
-            return -1;
-        }
-    } else {
-        TRACE(RXTX, logout("%p received frame, ignored, len=%zu,%s\n", s, size,
-              nic_dump(buf, size)));
-        return size;
-    }
-
-    if (get_ru_state(s) != ru_ready) {
-        /* No resources available. */
-        logout("no resources, state=%u\n", get_ru_state(s));
-        /* TODO: RNR interrupt only at first failed frame? */
-        eepro100_rnr_interrupt(s);
-        s->statistics.rx_resource_errors++;
-#if 0
-        assert(!"no resources");
-#endif
-        return -1;
-    }
-    /* !!! */
-    eepro100_rx_t rx;
-    pci_dma_read(&s->dev, s->ru_base + s->ru_offset,
-                 &rx, sizeof(eepro100_rx_t));
-    uint16_t rfd_command = le16_to_cpu(rx.command);
-    uint16_t rfd_size = le16_to_cpu(rx.size);
-
-    if (size > rfd_size) {
-        logout("Receive buffer (%" PRId16 " bytes) too small for data "
-            "(%zu bytes); data truncated\n", rfd_size, size);
-        size = rfd_size;
-    }
-#if !defined(CONFIG_PAD_RECEIVED_FRAMES)
-    if (size < 64) {
-        rfd_status |= 0x0080;
-    }
-#endif
-    TRACE(OTHER, logout("command 0x%04x, link 0x%08x, addr 0x%08x, size %u\n",
-          rfd_command, rx.link, rx.rx_buf_addr, rfd_size));
-    stw_le_pci_dma(&s->dev, s->ru_base + s->ru_offset +
-                offsetof(eepro100_rx_t, status), rfd_status);
-    stw_le_pci_dma(&s->dev, s->ru_base + s->ru_offset +
-                offsetof(eepro100_rx_t, count), size);
-    /* Early receive interrupt not supported. */
-#if 0
-    eepro100_er_interrupt(s);
-#endif
-    /* Receive CRC Transfer not supported. */
-    if (s->configuration[18] & BIT(2)) {
-        missing("Receive CRC Transfer");
-        return -1;
-    }
-    /* TODO: check stripping enable bit. */
-#if 0
-    assert(!(s->configuration[17] & BIT(0)));
-#endif
-    pci_dma_write(&s->dev, s->ru_base + s->ru_offset +
-                  sizeof(eepro100_rx_t), buf, size);
-    s->statistics.rx_good_frames++;
-    eepro100_fr_interrupt(s);
-    s->ru_offset = le32_to_cpu(rx.link);
-    if (rfd_command & COMMAND_EL) {
-        /* EL bit is set, so this was the last frame. */
-        logout("receive: Running out of frames\n");
-        set_ru_state(s, ru_no_resources);
-        eepro100_rnr_interrupt(s);
-    }
-    if (rfd_command & COMMAND_S) {
-        /* S bit is set. */
-        set_ru_state(s, ru_suspended);
-    }
-    return size;
-}
-
-static const VMStateDescription vmstate_eepro100 = {
-    .version_id = 3,
-    .minimum_version_id = 2,
-    .minimum_version_id_old = 2,
-    .fields      = (VMStateField []) {
-        VMSTATE_PCI_DEVICE(dev, EEPRO100State),
-        VMSTATE_UNUSED(32),
-        VMSTATE_BUFFER(mult, EEPRO100State),
-        VMSTATE_BUFFER(mem, EEPRO100State),
-        /* Save all members of struct between scb_stat and mem. */
-        VMSTATE_UINT8(scb_stat, EEPRO100State),
-        VMSTATE_UINT8(int_stat, EEPRO100State),
-        VMSTATE_UNUSED(3*4),
-        VMSTATE_MACADDR(conf.macaddr, EEPRO100State),
-        VMSTATE_UNUSED(19*4),
-        VMSTATE_UINT16_ARRAY(mdimem, EEPRO100State, 32),
-        /* The eeprom should be saved and restored by its own routines. */
-        VMSTATE_UINT32(device, EEPRO100State),
-        /* TODO check device. */
-        VMSTATE_UINT32(cu_base, EEPRO100State),
-        VMSTATE_UINT32(cu_offset, EEPRO100State),
-        VMSTATE_UINT32(ru_base, EEPRO100State),
-        VMSTATE_UINT32(ru_offset, EEPRO100State),
-        VMSTATE_UINT32(statsaddr, EEPRO100State),
-        /* Save eepro100_stats_t statistics. */
-        VMSTATE_UINT32(statistics.tx_good_frames, EEPRO100State),
-        VMSTATE_UINT32(statistics.tx_max_collisions, EEPRO100State),
-        VMSTATE_UINT32(statistics.tx_late_collisions, EEPRO100State),
-        VMSTATE_UINT32(statistics.tx_underruns, EEPRO100State),
-        VMSTATE_UINT32(statistics.tx_lost_crs, EEPRO100State),
-        VMSTATE_UINT32(statistics.tx_deferred, EEPRO100State),
-        VMSTATE_UINT32(statistics.tx_single_collisions, EEPRO100State),
-        VMSTATE_UINT32(statistics.tx_multiple_collisions, EEPRO100State),
-        VMSTATE_UINT32(statistics.tx_total_collisions, EEPRO100State),
-        VMSTATE_UINT32(statistics.rx_good_frames, EEPRO100State),
-        VMSTATE_UINT32(statistics.rx_crc_errors, EEPRO100State),
-        VMSTATE_UINT32(statistics.rx_alignment_errors, EEPRO100State),
-        VMSTATE_UINT32(statistics.rx_resource_errors, EEPRO100State),
-        VMSTATE_UINT32(statistics.rx_overrun_errors, EEPRO100State),
-        VMSTATE_UINT32(statistics.rx_cdt_errors, EEPRO100State),
-        VMSTATE_UINT32(statistics.rx_short_frame_errors, EEPRO100State),
-        VMSTATE_UINT32(statistics.fc_xmt_pause, EEPRO100State),
-        VMSTATE_UINT32(statistics.fc_rcv_pause, EEPRO100State),
-        VMSTATE_UINT32(statistics.fc_rcv_unsupported, EEPRO100State),
-        VMSTATE_UINT16(statistics.xmt_tco_frames, EEPRO100State),
-        VMSTATE_UINT16(statistics.rcv_tco_frames, EEPRO100State),
-        /* Configuration bytes. */
-        VMSTATE_BUFFER(configuration, EEPRO100State),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void nic_cleanup(NetClientState *nc)
-{
-    EEPRO100State *s = qemu_get_nic_opaque(nc);
-
-    s->nic = NULL;
-}
-
-static void pci_nic_uninit(PCIDevice *pci_dev)
-{
-    EEPRO100State *s = DO_UPCAST(EEPRO100State, dev, pci_dev);
-
-    memory_region_destroy(&s->mmio_bar);
-    memory_region_destroy(&s->io_bar);
-    memory_region_destroy(&s->flash_bar);
-    vmstate_unregister(&pci_dev->qdev, s->vmstate, s);
-    eeprom93xx_free(&pci_dev->qdev, s->eeprom);
-    qemu_del_nic(s->nic);
-}
-
-static NetClientInfo net_eepro100_info = {
-    .type = NET_CLIENT_OPTIONS_KIND_NIC,
-    .size = sizeof(NICState),
-    .can_receive = nic_can_receive,
-    .receive = nic_receive,
-    .cleanup = nic_cleanup,
-};
-
-static int e100_nic_init(PCIDevice *pci_dev)
-{
-    EEPRO100State *s = DO_UPCAST(EEPRO100State, dev, pci_dev);
-    E100PCIDeviceInfo *info = eepro100_get_class(s);
-
-    TRACE(OTHER, logout("\n"));
-
-    s->device = info->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. */
-    s->eeprom = eeprom93xx_new(&pci_dev->qdev, EEPROM_SIZE);
-
-    /* Handler for memory-mapped I/O */
-    memory_region_init_io(&s->mmio_bar, &eepro100_ops, s, "eepro100-mmio",
-                          PCI_MEM_SIZE);
-    pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_MEM_PREFETCH, &s->mmio_bar);
-    memory_region_init_io(&s->io_bar, &eepro100_ops, s, "eepro100-io",
-                          PCI_IO_SIZE);
-    pci_register_bar(&s->dev, 1, PCI_BASE_ADDRESS_SPACE_IO, &s->io_bar);
-    /* FIXME: flash aliases to mmio?! */
-    memory_region_init_io(&s->flash_bar, &eepro100_ops, s, "eepro100-flash",
-                          PCI_FLASH_SIZE);
-    pci_register_bar(&s->dev, 2, 0, &s->flash_bar);
-
-    qemu_macaddr_default_if_unset(&s->conf.macaddr);
-    logout("macaddr: %s\n", nic_dump(&s->conf.macaddr.a[0], 6));
-
-    nic_reset(s);
-
-    s->nic = qemu_new_nic(&net_eepro100_info, &s->conf,
-                          object_get_typename(OBJECT(pci_dev)), pci_dev->qdev.id, s);
-
-    qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
-    TRACE(OTHER, logout("%s\n", qemu_get_queue(s->nic)->info_str));
-
-    qemu_register_reset(nic_reset, s);
-
-    s->vmstate = g_malloc(sizeof(vmstate_eepro100));
-    memcpy(s->vmstate, &vmstate_eepro100, sizeof(vmstate_eepro100));
-    s->vmstate->name = qemu_get_queue(s->nic)->model;
-    vmstate_register(&pci_dev->qdev, -1, s->vmstate, s);
-
-    add_boot_device_path(s->conf.bootindex, &pci_dev->qdev, "/ethernet-phy@0");
-
-    return 0;
-}
-
-static E100PCIDeviceInfo e100_devices[] = {
-    {
-        .name = "i82550",
-        .desc = "Intel i82550 Ethernet",
-        .device = i82550,
-        /* TODO: check device id. */
-        .device_id = PCI_DEVICE_ID_INTEL_82551IT,
-        /* Revision ID: 0x0c, 0x0d, 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,
-    },{
-        .name = "i82551",
-        .desc = "Intel i82551 Ethernet",
-        .device = i82551,
-        .device_id = PCI_DEVICE_ID_INTEL_82551IT,
-        /* Revision ID: 0x0f, 0x10. */
-        .revision = 0x0f,
-        /* TODO: check size of statistical counters. */
-        .stats_size = 80,
-        .has_extended_tcb_support = true,
-        .power_management = true,
-    },{
-        .name = "i82557a",
-        .desc = "Intel i82557A Ethernet",
-        .device = i82557A,
-        .device_id = PCI_DEVICE_ID_INTEL_82557,
-        .revision = 0x01,
-        .power_management = false,
-    },{
-        .name = "i82557b",
-        .desc = "Intel i82557B Ethernet",
-        .device = i82557B,
-        .device_id = PCI_DEVICE_ID_INTEL_82557,
-        .revision = 0x02,
-        .power_management = false,
-    },{
-        .name = "i82557c",
-        .desc = "Intel i82557C Ethernet",
-        .device = i82557C,
-        .device_id = PCI_DEVICE_ID_INTEL_82557,
-        .revision = 0x03,
-        .power_management = false,
-    },{
-        .name = "i82558a",
-        .desc = "Intel i82558A Ethernet",
-        .device = i82558A,
-        .device_id = PCI_DEVICE_ID_INTEL_82557,
-        .revision = 0x04,
-        .stats_size = 76,
-        .has_extended_tcb_support = true,
-        .power_management = true,
-    },{
-        .name = "i82558b",
-        .desc = "Intel i82558B Ethernet",
-        .device = i82558B,
-        .device_id = PCI_DEVICE_ID_INTEL_82557,
-        .revision = 0x05,
-        .stats_size = 76,
-        .has_extended_tcb_support = true,
-        .power_management = true,
-    },{
-        .name = "i82559a",
-        .desc = "Intel i82559A Ethernet",
-        .device = i82559A,
-        .device_id = PCI_DEVICE_ID_INTEL_82557,
-        .revision = 0x06,
-        .stats_size = 80,
-        .has_extended_tcb_support = true,
-        .power_management = true,
-    },{
-        .name = "i82559b",
-        .desc = "Intel i82559B Ethernet",
-        .device = i82559B,
-        .device_id = PCI_DEVICE_ID_INTEL_82557,
-        .revision = 0x07,
-        .stats_size = 80,
-        .has_extended_tcb_support = true,
-        .power_management = true,
-    },{
-        .name = "i82559c",
-        .desc = "Intel i82559C Ethernet",
-        .device = i82559C,
-        .device_id = PCI_DEVICE_ID_INTEL_82557,
-#if 0
-        .revision = 0x08,
-#endif
-        /* TODO: Windows wants revision id 0x0c. */
-        .revision = 0x0c,
-#if EEPROM_SIZE > 0
-        .subsystem_vendor_id = PCI_VENDOR_ID_INTEL,
-        .subsystem_id = 0x0040,
-#endif
-        .stats_size = 80,
-        .has_extended_tcb_support = true,
-        .power_management = true,
-    },{
-        .name = "i82559er",
-        .desc = "Intel i82559ER Ethernet",
-        .device = i82559ER,
-        .device_id = PCI_DEVICE_ID_INTEL_82551IT,
-        .revision = 0x09,
-        .stats_size = 80,
-        .has_extended_tcb_support = true,
-        .power_management = true,
-    },{
-        .name = "i82562",
-        .desc = "Intel i82562 Ethernet",
-        .device = i82562,
-        /* TODO: check device id. */
-        .device_id = PCI_DEVICE_ID_INTEL_82551IT,
-        /* TODO: wrong revision id. */
-        .revision = 0x0e,
-        .stats_size = 80,
-        .has_extended_tcb_support = true,
-        .power_management = true,
-    },{
-        /* Toshiba Tecra 8200. */
-        .name = "i82801",
-        .desc = "Intel i82801 Ethernet",
-        .device = i82801,
-        .device_id = 0x2449,
-        .revision = 0x03,
-        .stats_size = 80,
-        .has_extended_tcb_support = true,
-        .power_management = true,
-    }
-};
-
-static E100PCIDeviceInfo *eepro100_get_class_by_name(const char *typename)
-{
-    E100PCIDeviceInfo *info = NULL;
-    int i;
-
-    /* This is admittedly awkward but also temporary.  QOM allows for
-     * parameterized typing and for subclassing both of which would suitable
-     * handle what's going on here.  But class_data is already being used as
-     * a stop-gap hack to allow incremental qdev conversion so we cannot use it
-     * right now.  Once we merge the final QOM series, we can come back here and
-     * do this in a much more elegant fashion.
-     */
-    for (i = 0; i < ARRAY_SIZE(e100_devices); i++) {
-        if (strcmp(e100_devices[i].name, typename) == 0) {
-            info = &e100_devices[i];
-            break;
-        }
-    }
-    assert(info != NULL);
-
-    return info;
-}
-
-static E100PCIDeviceInfo *eepro100_get_class(EEPRO100State *s)
-{
-    return eepro100_get_class_by_name(object_get_typename(OBJECT(s)));
-}
-
-static Property e100_properties[] = {
-    DEFINE_NIC_PROPERTIES(EEPRO100State, conf),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void eepro100_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-    E100PCIDeviceInfo *info;
-
-    info = eepro100_get_class_by_name(object_class_get_name(klass));
-
-    dc->props = e100_properties;
-    dc->desc = info->desc;
-    k->vendor_id = PCI_VENDOR_ID_INTEL;
-    k->class_id = PCI_CLASS_NETWORK_ETHERNET;
-    k->romfile = "pxe-eepro100.rom";
-    k->init = e100_nic_init;
-    k->exit = pci_nic_uninit;
-    k->device_id = info->device_id;
-    k->revision = info->revision;
-    k->subsystem_vendor_id = info->subsystem_vendor_id;
-    k->subsystem_id = info->subsystem_id;
-}
-
-static void eepro100_register_types(void)
-{
-    size_t i;
-    for (i = 0; i < ARRAY_SIZE(e100_devices); i++) {
-        TypeInfo type_info = {};
-        E100PCIDeviceInfo *info = &e100_devices[i];
-
-        type_info.name = info->name;
-        type_info.parent = TYPE_PCI_DEVICE;
-        type_info.class_init = eepro100_class_init;
-        type_info.instance_size = sizeof(EEPRO100State);
-        
-        type_register(&type_info);
-    }
-}
-
-type_init(eepro100_register_types)
diff --git a/hw/eeprom93xx.c b/hw/eeprom93xx.c
deleted file mode 100644 (file)
index 39f5605..0000000
+++ /dev/null
@@ -1,337 +0,0 @@
-/*
- * QEMU EEPROM 93xx emulation
- *
- * Copyright (c) 2006-2007 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
- * 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/>.
- */
-
-/* Emulation for serial EEPROMs:
- * NMC93C06 256-Bit (16 x 16)
- * NMC93C46 1024-Bit (64 x 16)
- * NMC93C56 2028 Bit (128 x 16)
- * NMC93C66 4096 Bit (256 x 16)
- * Compatible devices include FM93C46 and others.
- *
- * Other drivers use these interface functions:
- * eeprom93xx_new   - add a new EEPROM (with 16, 64 or 256 words)
- * eeprom93xx_free  - destroy EEPROM
- * eeprom93xx_read  - read data from the EEPROM
- * eeprom93xx_write - write data to the EEPROM
- * eeprom93xx_data  - get EEPROM data array for external manipulation
- *
- * Todo list:
- * - No emulation of EEPROM timings.
- */
-
-#include "hw/hw.h"
-#include "hw/eeprom93xx.h"
-
-/* Debug EEPROM emulation. */
-//~ #define DEBUG_EEPROM
-
-#ifdef DEBUG_EEPROM
-#define logout(fmt, ...) fprintf(stderr, "EEPROM\t%-24s" fmt, __func__, ## __VA_ARGS__)
-#else
-#define logout(fmt, ...) ((void)0)
-#endif
-
-#define EEPROM_INSTANCE  0
-#define OLD_EEPROM_VERSION 20061112
-#define EEPROM_VERSION (OLD_EEPROM_VERSION + 1)
-
-#if 0
-typedef enum {
-  eeprom_read  = 0x80,   /* read register xx */
-  eeprom_write = 0x40,   /* write register xx */
-  eeprom_erase = 0xc0,   /* erase register xx */
-  eeprom_ewen  = 0x30,   /* erase / write enable */
-  eeprom_ewds  = 0x00,   /* erase / write disable */
-  eeprom_eral  = 0x20,   /* erase all registers */
-  eeprom_wral  = 0x10,   /* write all registers */
-  eeprom_amask = 0x0f,
-  eeprom_imask = 0xf0
-} eeprom_instruction_t;
-#endif
-
-#ifdef DEBUG_EEPROM
-static const char *opstring[] = {
-  "extended", "write", "read", "erase"
-};
-#endif
-
-struct _eeprom_t {
-    uint8_t  tick;
-    uint8_t  address;
-    uint8_t  command;
-    uint8_t  writable;
-
-    uint8_t eecs;
-    uint8_t eesk;
-    uint8_t eedo;
-
-    uint8_t  addrbits;
-    uint16_t size;
-    uint16_t data;
-    uint16_t contents[0];
-};
-
-/* Code for saving and restoring of EEPROM state. */
-
-/* Restore an uint16_t from an uint8_t
-   This is a Big hack, but it is how the old state did it.
- */
-
-static int get_uint16_from_uint8(QEMUFile *f, void *pv, size_t size)
-{
-    uint16_t *v = pv;
-    *v = qemu_get_ubyte(f);
-    return 0;
-}
-
-static void put_unused(QEMUFile *f, void *pv, size_t size)
-{
-    fprintf(stderr, "uint16_from_uint8 is used only for backwards compatibility.\n");
-    fprintf(stderr, "Never should be used to write a new state.\n");
-    exit(0);
-}
-
-static const VMStateInfo vmstate_hack_uint16_from_uint8 = {
-    .name = "uint16_from_uint8",
-    .get  = get_uint16_from_uint8,
-    .put  = put_unused,
-};
-
-#define VMSTATE_UINT16_HACK_TEST(_f, _s, _t)                           \
-    VMSTATE_SINGLE_TEST(_f, _s, _t, 0, vmstate_hack_uint16_from_uint8, uint16_t)
-
-static bool is_old_eeprom_version(void *opaque, int version_id)
-{
-    return version_id == OLD_EEPROM_VERSION;
-}
-
-static const VMStateDescription vmstate_eeprom = {
-    .name = "eeprom",
-    .version_id = EEPROM_VERSION,
-    .minimum_version_id = OLD_EEPROM_VERSION,
-    .minimum_version_id_old = OLD_EEPROM_VERSION,
-    .fields      = (VMStateField []) {
-        VMSTATE_UINT8(tick, eeprom_t),
-        VMSTATE_UINT8(address, eeprom_t),
-        VMSTATE_UINT8(command, eeprom_t),
-        VMSTATE_UINT8(writable, eeprom_t),
-
-        VMSTATE_UINT8(eecs, eeprom_t),
-        VMSTATE_UINT8(eesk, eeprom_t),
-        VMSTATE_UINT8(eedo, eeprom_t),
-
-        VMSTATE_UINT8(addrbits, eeprom_t),
-        VMSTATE_UINT16_HACK_TEST(size, eeprom_t, is_old_eeprom_version),
-        VMSTATE_UNUSED_TEST(is_old_eeprom_version, 1),
-        VMSTATE_UINT16_EQUAL_V(size, eeprom_t, EEPROM_VERSION),
-        VMSTATE_UINT16(data, eeprom_t),
-        VMSTATE_VARRAY_UINT16_UNSAFE(contents, eeprom_t, size, 0,
-                                     vmstate_info_uint16, uint16_t),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-void eeprom93xx_write(eeprom_t *eeprom, int eecs, int eesk, int eedi)
-{
-    uint8_t tick = eeprom->tick;
-    uint8_t eedo = eeprom->eedo;
-    uint16_t address = eeprom->address;
-    uint8_t command = eeprom->command;
-
-    logout("CS=%u SK=%u DI=%u DO=%u, tick = %u\n",
-           eecs, eesk, eedi, eedo, tick);
-
-    if (! eeprom->eecs && eecs) {
-        /* Start chip select cycle. */
-        logout("Cycle start, waiting for 1st start bit (0)\n");
-        tick = 0;
-        command = 0x0;
-        address = 0x0;
-    } else if (eeprom->eecs && ! eecs) {
-        /* End chip select cycle. This triggers write / erase. */
-        if (eeprom->writable) {
-            uint8_t subcommand = address >> (eeprom->addrbits - 2);
-            if (command == 0 && subcommand == 2) {
-                /* Erase all. */
-                for (address = 0; address < eeprom->size; address++) {
-                    eeprom->contents[address] = 0xffff;
-                }
-            } else if (command == 3) {
-                /* Erase word. */
-                eeprom->contents[address] = 0xffff;
-            } else if (tick >= 2 + 2 + eeprom->addrbits + 16) {
-                if (command == 1) {
-                    /* Write word. */
-                    eeprom->contents[address] &= eeprom->data;
-                } else if (command == 0 && subcommand == 1) {
-                    /* Write all. */
-                    for (address = 0; address < eeprom->size; address++) {
-                        eeprom->contents[address] &= eeprom->data;
-                    }
-                }
-            }
-        }
-        /* Output DO is tristate, read results in 1. */
-        eedo = 1;
-    } else if (eecs && ! eeprom->eesk && eesk) {
-        /* Raising edge of clock shifts data in. */
-        if (tick == 0) {
-            /* Wait for 1st start bit. */
-            if (eedi == 0) {
-                logout("Got correct 1st start bit, waiting for 2nd start bit (1)\n");
-                tick++;
-            } else {
-                logout("wrong 1st start bit (is 1, should be 0)\n");
-                tick = 2;
-                //~ assert(!"wrong start bit");
-            }
-        } else if (tick == 1) {
-            /* Wait for 2nd start bit. */
-            if (eedi != 0) {
-                logout("Got correct 2nd start bit, getting command + address\n");
-                tick++;
-            } else {
-                logout("1st start bit is longer than needed\n");
-            }
-        } else if (tick < 2 + 2) {
-            /* Got 2 start bits, transfer 2 opcode bits. */
-            tick++;
-            command <<= 1;
-            if (eedi) {
-                command += 1;
-            }
-        } else if (tick < 2 + 2 + eeprom->addrbits) {
-            /* Got 2 start bits and 2 opcode bits, transfer all address bits. */
-            tick++;
-            address = ((address << 1) | eedi);
-            if (tick == 2 + 2 + eeprom->addrbits) {
-                logout("%s command, address = 0x%02x (value 0x%04x)\n",
-                       opstring[command], address, eeprom->contents[address]);
-                if (command == 2) {
-                    eedo = 0;
-                }
-                address = address % eeprom->size;
-                if (command == 0) {
-                    /* Command code in upper 2 bits of address. */
-                    switch (address >> (eeprom->addrbits - 2)) {
-                        case 0:
-                            logout("write disable command\n");
-                            eeprom->writable = 0;
-                            break;
-                        case 1:
-                            logout("write all command\n");
-                            break;
-                        case 2:
-                            logout("erase all command\n");
-                            break;
-                        case 3:
-                            logout("write enable command\n");
-                            eeprom->writable = 1;
-                            break;
-                    }
-                } else {
-                    /* Read, write or erase word. */
-                    eeprom->data = eeprom->contents[address];
-                }
-            }
-        } else if (tick < 2 + 2 + eeprom->addrbits + 16) {
-            /* Transfer 16 data bits. */
-            tick++;
-            if (command == 2) {
-                /* Read word. */
-                eedo = ((eeprom->data & 0x8000) != 0);
-            }
-            eeprom->data <<= 1;
-            eeprom->data += eedi;
-        } else {
-            logout("additional unneeded tick, not processed\n");
-        }
-    }
-    /* Save status of EEPROM. */
-    eeprom->tick = tick;
-    eeprom->eecs = eecs;
-    eeprom->eesk = eesk;
-    eeprom->eedo = eedo;
-    eeprom->address = address;
-    eeprom->command = command;
-}
-
-uint16_t eeprom93xx_read(eeprom_t *eeprom)
-{
-    /* Return status of pin DO (0 or 1). */
-    logout("CS=%u DO=%u\n", eeprom->eecs, eeprom->eedo);
-    return (eeprom->eedo);
-}
-
-#if 0
-void eeprom93xx_reset(eeprom_t *eeprom)
-{
-    /* prepare eeprom */
-    logout("eeprom = 0x%p\n", eeprom);
-    eeprom->tick = 0;
-    eeprom->command = 0;
-}
-#endif
-
-eeprom_t *eeprom93xx_new(DeviceState *dev, uint16_t nwords)
-{
-    /* Add a new EEPROM (with 16, 64 or 256 words). */
-    eeprom_t *eeprom;
-    uint8_t addrbits;
-
-    switch (nwords) {
-        case 16:
-        case 64:
-            addrbits = 6;
-            break;
-        case 128:
-        case 256:
-            addrbits = 8;
-            break;
-        default:
-            assert(!"Unsupported EEPROM size, fallback to 64 words!");
-            nwords = 64;
-            addrbits = 6;
-    }
-
-    eeprom = (eeprom_t *)g_malloc0(sizeof(*eeprom) + nwords * 2);
-    eeprom->size = nwords;
-    eeprom->addrbits = addrbits;
-    /* Output DO is tristate, read results in 1. */
-    eeprom->eedo = 1;
-    logout("eeprom = 0x%p, nwords = %u\n", eeprom, nwords);
-    vmstate_register(dev, 0, &vmstate_eeprom, eeprom);
-    return eeprom;
-}
-
-void eeprom93xx_free(DeviceState *dev, eeprom_t *eeprom)
-{
-    /* Destroy EEPROM. */
-    logout("eeprom = 0x%p\n", eeprom);
-    vmstate_unregister(dev, &vmstate_eeprom, eeprom);
-    g_free(eeprom);
-}
-
-uint16_t *eeprom93xx_data(eeprom_t *eeprom)
-{
-    /* Get EEPROM data array. */
-    return &eeprom->contents[0];
-}
-
-/* eof */
diff --git a/hw/eeprom93xx.h b/hw/eeprom93xx.h
deleted file mode 100644 (file)
index 8ba0e28..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * QEMU EEPROM 93xx emulation
- *
- * Copyright (c) 2006-2007 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
- * 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 EEPROM93XX_H
-#define EEPROM93XX_H
-
-typedef struct _eeprom_t eeprom_t;
-
-/* Create a new EEPROM with (nwords * 2) bytes. */
-eeprom_t *eeprom93xx_new(DeviceState *dev, uint16_t nwords);
-
-/* Destroy an existing EEPROM. */
-void eeprom93xx_free(DeviceState *dev, eeprom_t *eeprom);
-
-/* Read from the EEPROM. */
-uint16_t eeprom93xx_read(eeprom_t *eeprom);
-
-/* Write to the EEPROM. */
-void eeprom93xx_write(eeprom_t *eeprom, int eecs, int eesk, int eedi);
-
-/* Get EEPROM data array. */
-uint16_t *eeprom93xx_data(eeprom_t *eeprom);
-
-#endif /* EEPROM93XX_H */
diff --git a/hw/elf_ops.h b/hw/elf_ops.h
deleted file mode 100644 (file)
index acc701e..0000000
+++ /dev/null
@@ -1,309 +0,0 @@
-static void glue(bswap_ehdr, SZ)(struct elfhdr *ehdr)
-{
-    bswap16s(&ehdr->e_type);                   /* Object file type */
-    bswap16s(&ehdr->e_machine);                /* Architecture */
-    bswap32s(&ehdr->e_version);                /* Object file version */
-    bswapSZs(&ehdr->e_entry);          /* Entry point virtual address */
-    bswapSZs(&ehdr->e_phoff);          /* Program header table file offset */
-    bswapSZs(&ehdr->e_shoff);          /* Section header table file offset */
-    bswap32s(&ehdr->e_flags);          /* Processor-specific flags */
-    bswap16s(&ehdr->e_ehsize);         /* ELF header size in bytes */
-    bswap16s(&ehdr->e_phentsize);              /* Program header table entry size */
-    bswap16s(&ehdr->e_phnum);          /* Program header table entry count */
-    bswap16s(&ehdr->e_shentsize);              /* Section header table entry size */
-    bswap16s(&ehdr->e_shnum);          /* Section header table entry count */
-    bswap16s(&ehdr->e_shstrndx);               /* Section header string table index */
-}
-
-static void glue(bswap_phdr, SZ)(struct elf_phdr *phdr)
-{
-    bswap32s(&phdr->p_type);                   /* Segment type */
-    bswapSZs(&phdr->p_offset);         /* Segment file offset */
-    bswapSZs(&phdr->p_vaddr);          /* Segment virtual address */
-    bswapSZs(&phdr->p_paddr);          /* Segment physical address */
-    bswapSZs(&phdr->p_filesz);         /* Segment size in file */
-    bswapSZs(&phdr->p_memsz);          /* Segment size in memory */
-    bswap32s(&phdr->p_flags);          /* Segment flags */
-    bswapSZs(&phdr->p_align);          /* Segment alignment */
-}
-
-static void glue(bswap_shdr, SZ)(struct elf_shdr *shdr)
-{
-    bswap32s(&shdr->sh_name);
-    bswap32s(&shdr->sh_type);
-    bswapSZs(&shdr->sh_flags);
-    bswapSZs(&shdr->sh_addr);
-    bswapSZs(&shdr->sh_offset);
-    bswapSZs(&shdr->sh_size);
-    bswap32s(&shdr->sh_link);
-    bswap32s(&shdr->sh_info);
-    bswapSZs(&shdr->sh_addralign);
-    bswapSZs(&shdr->sh_entsize);
-}
-
-static void glue(bswap_sym, SZ)(struct elf_sym *sym)
-{
-    bswap32s(&sym->st_name);
-    bswapSZs(&sym->st_value);
-    bswapSZs(&sym->st_size);
-    bswap16s(&sym->st_shndx);
-}
-
-static struct elf_shdr *glue(find_section, SZ)(struct elf_shdr *shdr_table,
-                                               int n, int type)
-{
-    int i;
-    for(i=0;i<n;i++) {
-        if (shdr_table[i].sh_type == type)
-            return shdr_table + i;
-    }
-    return NULL;
-}
-
-static int glue(symfind, SZ)(const void *s0, const void *s1)
-{
-    hwaddr addr = *(hwaddr *)s0;
-    struct elf_sym *sym = (struct elf_sym *)s1;
-    int result = 0;
-    if (addr < sym->st_value) {
-        result = -1;
-    } else if (addr >= sym->st_value + sym->st_size) {
-        result = 1;
-    }
-    return result;
-}
-
-static const char *glue(lookup_symbol, SZ)(struct syminfo *s,
-                                           hwaddr orig_addr)
-{
-    struct elf_sym *syms = glue(s->disas_symtab.elf, SZ);
-    struct elf_sym *sym;
-
-    sym = bsearch(&orig_addr, syms, s->disas_num_syms, sizeof(*syms),
-                  glue(symfind, SZ));
-    if (sym != NULL) {
-        return s->disas_strtab + sym->st_name;
-    }
-
-    return "";
-}
-
-static int glue(symcmp, SZ)(const void *s0, const void *s1)
-{
-    struct elf_sym *sym0 = (struct elf_sym *)s0;
-    struct elf_sym *sym1 = (struct elf_sym *)s1;
-    return (sym0->st_value < sym1->st_value)
-        ? -1
-        : ((sym0->st_value > sym1->st_value) ? 1 : 0);
-}
-
-static int glue(load_symbols, SZ)(struct elfhdr *ehdr, int fd, int must_swab,
-                                  int clear_lsb)
-{
-    struct elf_shdr *symtab, *strtab, *shdr_table = NULL;
-    struct elf_sym *syms = NULL;
-    struct syminfo *s;
-    int nsyms, i;
-    char *str = NULL;
-
-    shdr_table = load_at(fd, ehdr->e_shoff,
-                         sizeof(struct elf_shdr) * ehdr->e_shnum);
-    if (!shdr_table)
-        return -1;
-
-    if (must_swab) {
-        for (i = 0; i < ehdr->e_shnum; i++) {
-            glue(bswap_shdr, SZ)(shdr_table + i);
-        }
-    }
-
-    symtab = glue(find_section, SZ)(shdr_table, ehdr->e_shnum, SHT_SYMTAB);
-    if (!symtab)
-        goto fail;
-    syms = load_at(fd, symtab->sh_offset, symtab->sh_size);
-    if (!syms)
-        goto fail;
-
-    nsyms = symtab->sh_size / sizeof(struct elf_sym);
-
-    i = 0;
-    while (i < nsyms) {
-        if (must_swab)
-            glue(bswap_sym, SZ)(&syms[i]);
-        /* We are only interested in function symbols.
-           Throw everything else away.  */
-        if (syms[i].st_shndx == SHN_UNDEF ||
-                syms[i].st_shndx >= SHN_LORESERVE ||
-                ELF_ST_TYPE(syms[i].st_info) != STT_FUNC) {
-            nsyms--;
-            if (i < nsyms) {
-                syms[i] = syms[nsyms];
-            }
-            continue;
-        }
-        if (clear_lsb) {
-            /* The bottom address bit marks a Thumb or MIPS16 symbol.  */
-            syms[i].st_value &= ~(glue(glue(Elf, SZ), _Addr))1;
-        }
-        i++;
-    }
-    if (nsyms) {
-        syms = g_realloc(syms, nsyms * sizeof(*syms));
-
-        qsort(syms, nsyms, sizeof(*syms), glue(symcmp, SZ));
-        for (i = 0; i < nsyms - 1; i++) {
-            if (syms[i].st_size == 0) {
-                syms[i].st_size = syms[i + 1].st_value - syms[i].st_value;
-            }
-        }
-    } else {
-        g_free(syms);
-        syms = NULL;
-    }
-
-    /* String table */
-    if (symtab->sh_link >= ehdr->e_shnum)
-        goto fail;
-    strtab = &shdr_table[symtab->sh_link];
-
-    str = load_at(fd, strtab->sh_offset, strtab->sh_size);
-    if (!str)
-        goto fail;
-
-    /* Commit */
-    s = g_malloc0(sizeof(*s));
-    s->lookup_symbol = glue(lookup_symbol, SZ);
-    glue(s->disas_symtab.elf, SZ) = syms;
-    s->disas_num_syms = nsyms;
-    s->disas_strtab = str;
-    s->next = syminfos;
-    syminfos = s;
-    g_free(shdr_table);
-    return 0;
- fail:
-    g_free(syms);
-    g_free(str);
-    g_free(shdr_table);
-    return -1;
-}
-
-static int glue(load_elf, SZ)(const char *name, int fd,
-                              uint64_t (*translate_fn)(void *, uint64_t),
-                              void *translate_opaque,
-                              int must_swab, uint64_t *pentry,
-                              uint64_t *lowaddr, uint64_t *highaddr,
-                              int elf_machine, int clear_lsb)
-{
-    struct elfhdr ehdr;
-    struct elf_phdr *phdr = NULL, *ph;
-    int size, i, total_size;
-    elf_word mem_size, file_size;
-    uint64_t addr, low = (uint64_t)-1, high = 0;
-    uint8_t *data = NULL;
-    char label[128];
-
-    if (read(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr))
-        goto fail;
-    if (must_swab) {
-        glue(bswap_ehdr, SZ)(&ehdr);
-    }
-
-    switch (elf_machine) {
-        case EM_PPC64:
-            if (EM_PPC64 != ehdr.e_machine)
-                if (EM_PPC != ehdr.e_machine)
-                    goto fail;
-            break;
-        case EM_X86_64:
-            if (EM_X86_64 != ehdr.e_machine)
-                if (EM_386 != ehdr.e_machine)
-                    goto fail;
-            break;
-        case EM_MICROBLAZE:
-            if (EM_MICROBLAZE != ehdr.e_machine)
-                if (EM_MICROBLAZE_OLD != ehdr.e_machine)
-                    goto fail;
-            break;
-        default:
-            if (elf_machine != ehdr.e_machine)
-                goto fail;
-    }
-
-    if (pentry)
-       *pentry = (uint64_t)(elf_sword)ehdr.e_entry;
-
-    glue(load_symbols, SZ)(&ehdr, fd, must_swab, clear_lsb);
-
-    size = ehdr.e_phnum * sizeof(phdr[0]);
-    lseek(fd, ehdr.e_phoff, SEEK_SET);
-    phdr = g_malloc0(size);
-    if (!phdr)
-        goto fail;
-    if (read(fd, phdr, size) != size)
-        goto fail;
-    if (must_swab) {
-        for(i = 0; i < ehdr.e_phnum; i++) {
-            ph = &phdr[i];
-            glue(bswap_phdr, SZ)(ph);
-        }
-    }
-
-    total_size = 0;
-    for(i = 0; i < ehdr.e_phnum; i++) {
-        ph = &phdr[i];
-        if (ph->p_type == PT_LOAD) {
-            mem_size = ph->p_memsz; /* Size of the ROM */
-            file_size = ph->p_filesz; /* Size of the allocated data */
-            data = g_malloc0(file_size);
-            if (ph->p_filesz > 0) {
-                if (lseek(fd, ph->p_offset, SEEK_SET) < 0) {
-                    goto fail;
-                }
-                if (read(fd, data, file_size) != file_size) {
-                    goto fail;
-                }
-            }
-            /* address_offset is hack for kernel images that are
-               linked at the wrong physical address.  */
-            if (translate_fn) {
-                addr = translate_fn(translate_opaque, ph->p_paddr);
-            } else {
-                addr = ph->p_paddr;
-            }
-
-            /* the entry pointer in the ELF header is a virtual
-             * address, if the text segments paddr and vaddr differ
-             * we need to adjust the entry */
-            if (pentry && !translate_fn &&
-                    ph->p_vaddr != ph->p_paddr &&
-                    ehdr.e_entry >= ph->p_vaddr &&
-                    ehdr.e_entry < ph->p_vaddr + ph->p_filesz &&
-                    ph->p_flags & PF_X) {
-                *pentry = ehdr.e_entry - ph->p_vaddr + ph->p_paddr;
-            }
-
-            snprintf(label, sizeof(label), "phdr #%d: %s", i, name);
-
-            /* rom_add_elf_program() seize the ownership of 'data' */
-            rom_add_elf_program(label, data, file_size, mem_size, addr);
-
-            total_size += mem_size;
-            if (addr < low)
-                low = addr;
-            if ((addr + mem_size) > high)
-                high = addr + mem_size;
-
-            data = NULL;
-        }
-    }
-    g_free(phdr);
-    if (lowaddr)
-        *lowaddr = (uint64_t)(elf_sword)low;
-    if (highaddr)
-        *highaddr = (uint64_t)(elf_sword)high;
-    return total_size;
- fail:
-    g_free(data);
-    g_free(phdr);
-    return -1;
-}
diff --git a/hw/empty_slot.c b/hw/empty_slot.c
deleted file mode 100644 (file)
index 5234a4d..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * QEMU Empty Slot
- *
- * The empty_slot device emulates known to a bus but not connected devices.
- *
- * Copyright (c) 2010 Artyom Tarasenko
- *
- * This code is licensed under the GNU GPL v2 or (at your option) any later
- * version.
- */
-
-#include "hw/hw.h"
-#include "hw/sysbus.h"
-#include "hw/empty_slot.h"
-
-//#define DEBUG_EMPTY_SLOT
-
-#ifdef DEBUG_EMPTY_SLOT
-#define DPRINTF(fmt, ...)                                       \
-    do { printf("empty_slot: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...) do {} while (0)
-#endif
-
-typedef struct EmptySlot {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-    uint64_t size;
-} EmptySlot;
-
-static uint64_t empty_slot_read(void *opaque, hwaddr addr,
-                                unsigned size)
-{
-    DPRINTF("read from " TARGET_FMT_plx "\n", addr);
-    return 0;
-}
-
-static void empty_slot_write(void *opaque, hwaddr addr,
-                             uint64_t val, unsigned size)
-{
-    DPRINTF("write 0x%x to " TARGET_FMT_plx "\n", (unsigned)val, addr);
-}
-
-static const MemoryRegionOps empty_slot_ops = {
-    .read = empty_slot_read,
-    .write = empty_slot_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-void empty_slot_init(hwaddr addr, uint64_t slot_size)
-{
-    if (slot_size > 0) {
-        /* Only empty slots larger than 0 byte need handling. */
-        DeviceState *dev;
-        SysBusDevice *s;
-        EmptySlot *e;
-
-        dev = qdev_create(NULL, "empty_slot");
-        s = SYS_BUS_DEVICE(dev);
-        e = FROM_SYSBUS(EmptySlot, s);
-        e->size = slot_size;
-
-        qdev_init_nofail(dev);
-
-        sysbus_mmio_map(s, 0, addr);
-    }
-}
-
-static int empty_slot_init1(SysBusDevice *dev)
-{
-    EmptySlot *s = FROM_SYSBUS(EmptySlot, dev);
-
-    memory_region_init_io(&s->iomem, &empty_slot_ops, s,
-                          "empty-slot", s->size);
-    sysbus_init_mmio(dev, &s->iomem);
-    return 0;
-}
-
-static void empty_slot_class_init(ObjectClass *klass, void *data)
-{
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = empty_slot_init1;
-}
-
-static const 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_types(void)
-{
-    type_register_static(&empty_slot_info);
-}
-
-type_init(empty_slot_register_types)
diff --git a/hw/empty_slot.h b/hw/empty_slot.h
deleted file mode 100644 (file)
index 6079602..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef HW_EMPTY_SLOT_H
-#define HW_EMPTY_SLOT_H 1
-
-/* empty_slot.c */
-void empty_slot_init(hwaddr addr, uint64_t slot_size);
-
-#endif
diff --git a/hw/es1370.c b/hw/es1370.c
deleted file mode 100644 (file)
index e64cf23..0000000
+++ /dev/null
@@ -1,1089 +0,0 @@
-/*
- * QEMU ES1370 emulation
- *
- * Copyright (c) 2005 Vassili Karpov (malc)
- *
- * 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.
- */
-
-/* #define DEBUG_ES1370 */
-/* #define VERBOSE_ES1370 */
-#define SILENT_ES1370
-
-#include "hw/hw.h"
-#include "hw/audiodev.h"
-#include "audio/audio.h"
-#include "hw/pci/pci.h"
-#include "sysemu/dma.h"
-
-/* Missing stuff:
-   SCTRL_P[12](END|ST)INC
-   SCTRL_P1SCTRLD
-   SCTRL_P2DACSEN
-   CTRL_DAC_SYNC
-   MIDI
-   non looped mode
-   surely more
-*/
-
-/*
-  Following macros and samplerate array were copied verbatim from
-  Linux kernel 2.4.30: drivers/sound/es1370.c
-
-  Copyright (C) 1998-2001, 2003 Thomas Sailer (t.sailer@alumni.ethz.ch)
-*/
-
-/* Start blatant GPL violation */
-
-#define ES1370_REG_CONTROL        0x00
-#define ES1370_REG_STATUS         0x04
-#define ES1370_REG_UART_DATA      0x08
-#define ES1370_REG_UART_STATUS    0x09
-#define ES1370_REG_UART_CONTROL   0x09
-#define ES1370_REG_UART_TEST      0x0a
-#define ES1370_REG_MEMPAGE        0x0c
-#define ES1370_REG_CODEC          0x10
-#define ES1370_REG_SERIAL_CONTROL 0x20
-#define ES1370_REG_DAC1_SCOUNT    0x24
-#define ES1370_REG_DAC2_SCOUNT    0x28
-#define ES1370_REG_ADC_SCOUNT     0x2c
-
-#define ES1370_REG_DAC1_FRAMEADR    0xc30
-#define ES1370_REG_DAC1_FRAMECNT    0xc34
-#define ES1370_REG_DAC2_FRAMEADR    0xc38
-#define ES1370_REG_DAC2_FRAMECNT    0xc3c
-#define ES1370_REG_ADC_FRAMEADR     0xd30
-#define ES1370_REG_ADC_FRAMECNT     0xd34
-#define ES1370_REG_PHANTOM_FRAMEADR 0xd38
-#define ES1370_REG_PHANTOM_FRAMECNT 0xd3c
-
-static const unsigned dac1_samplerate[] = { 5512, 11025, 22050, 44100 };
-
-#define DAC2_SRTODIV(x) (((1411200+(x)/2)/(x))-2)
-#define DAC2_DIVTOSR(x) (1411200/((x)+2))
-
-#define CTRL_ADC_STOP   0x80000000  /* 1 = ADC stopped */
-#define CTRL_XCTL1      0x40000000  /* electret mic bias */
-#define CTRL_OPEN       0x20000000  /* no function, can be read and written */
-#define CTRL_PCLKDIV    0x1fff0000  /* ADC/DAC2 clock divider */
-#define CTRL_SH_PCLKDIV 16
-#define CTRL_MSFMTSEL   0x00008000  /* MPEG serial data fmt: 0 = Sony, 1 = I2S */
-#define CTRL_M_SBB      0x00004000  /* DAC2 clock: 0 = PCLKDIV, 1 = MPEG */
-#define CTRL_WTSRSEL    0x00003000  /* DAC1 clock freq: 0=5512, 1=11025, 2=22050, 3=44100 */
-#define CTRL_SH_WTSRSEL 12
-#define CTRL_DAC_SYNC   0x00000800  /* 1 = DAC2 runs off DAC1 clock */
-#define CTRL_CCB_INTRM  0x00000400  /* 1 = CCB "voice" ints enabled */
-#define CTRL_M_CB       0x00000200  /* recording source: 0 = ADC, 1 = MPEG */
-#define CTRL_XCTL0      0x00000100  /* 0 = Line in, 1 = Line out */
-#define CTRL_BREQ       0x00000080  /* 1 = test mode (internal mem test) */
-#define CTRL_DAC1_EN    0x00000040  /* enable DAC1 */
-#define CTRL_DAC2_EN    0x00000020  /* enable DAC2 */
-#define CTRL_ADC_EN     0x00000010  /* enable ADC */
-#define CTRL_UART_EN    0x00000008  /* enable MIDI uart */
-#define CTRL_JYSTK_EN   0x00000004  /* enable Joystick port (presumably at address 0x200) */
-#define CTRL_CDC_EN     0x00000002  /* enable serial (CODEC) interface */
-#define CTRL_SERR_DIS   0x00000001  /* 1 = disable PCI SERR signal */
-
-#define STAT_INTR       0x80000000  /* wired or of all interrupt bits */
-#define STAT_CSTAT      0x00000400  /* 1 = codec busy or codec write in progress */
-#define STAT_CBUSY      0x00000200  /* 1 = codec busy */
-#define STAT_CWRIP      0x00000100  /* 1 = codec write in progress */
-#define STAT_VC         0x00000060  /* CCB int source, 0=DAC1, 1=DAC2, 2=ADC, 3=undef */
-#define STAT_SH_VC      5
-#define STAT_MCCB       0x00000010  /* CCB int pending */
-#define STAT_UART       0x00000008  /* UART int pending */
-#define STAT_DAC1       0x00000004  /* DAC1 int pending */
-#define STAT_DAC2       0x00000002  /* DAC2 int pending */
-#define STAT_ADC        0x00000001  /* ADC int pending */
-
-#define USTAT_RXINT     0x80        /* UART rx int pending */
-#define USTAT_TXINT     0x04        /* UART tx int pending */
-#define USTAT_TXRDY     0x02        /* UART tx ready */
-#define USTAT_RXRDY     0x01        /* UART rx ready */
-
-#define UCTRL_RXINTEN   0x80        /* 1 = enable RX ints */
-#define UCTRL_TXINTEN   0x60        /* TX int enable field mask */
-#define UCTRL_ENA_TXINT 0x20        /* enable TX int */
-#define UCTRL_CNTRL     0x03        /* control field */
-#define UCTRL_CNTRL_SWR 0x03        /* software reset command */
-
-#define SCTRL_P2ENDINC    0x00380000  /*  */
-#define SCTRL_SH_P2ENDINC 19
-#define SCTRL_P2STINC     0x00070000  /*  */
-#define SCTRL_SH_P2STINC  16
-#define SCTRL_R1LOOPSEL   0x00008000  /* 0 = loop mode */
-#define SCTRL_P2LOOPSEL   0x00004000  /* 0 = loop mode */
-#define SCTRL_P1LOOPSEL   0x00002000  /* 0 = loop mode */
-#define SCTRL_P2PAUSE     0x00001000  /* 1 = pause mode */
-#define SCTRL_P1PAUSE     0x00000800  /* 1 = pause mode */
-#define SCTRL_R1INTEN     0x00000400  /* enable interrupt */
-#define SCTRL_P2INTEN     0x00000200  /* enable interrupt */
-#define SCTRL_P1INTEN     0x00000100  /* enable interrupt */
-#define SCTRL_P1SCTRLD    0x00000080  /* reload sample count register for DAC1 */
-#define SCTRL_P2DACSEN    0x00000040  /* 1 = DAC2 play back last sample when disabled */
-#define SCTRL_R1SEB       0x00000020  /* 1 = 16bit */
-#define SCTRL_R1SMB       0x00000010  /* 1 = stereo */
-#define SCTRL_R1FMT       0x00000030  /* format mask */
-#define SCTRL_SH_R1FMT    4
-#define SCTRL_P2SEB       0x00000008  /* 1 = 16bit */
-#define SCTRL_P2SMB       0x00000004  /* 1 = stereo */
-#define SCTRL_P2FMT       0x0000000c  /* format mask */
-#define SCTRL_SH_P2FMT    2
-#define SCTRL_P1SEB       0x00000002  /* 1 = 16bit */
-#define SCTRL_P1SMB       0x00000001  /* 1 = stereo */
-#define SCTRL_P1FMT       0x00000003  /* format mask */
-#define SCTRL_SH_P1FMT    0
-
-/* End blatant GPL violation */
-
-#define NB_CHANNELS 3
-#define DAC1_CHANNEL 0
-#define DAC2_CHANNEL 1
-#define ADC_CHANNEL 2
-
-#define IO_READ_PROTO(n) \
-static uint32_t n (void *opaque, uint32_t addr)
-#define IO_WRITE_PROTO(n) \
-static void n (void *opaque, uint32_t addr, uint32_t val)
-
-static void es1370_dac1_callback (void *opaque, int free);
-static void es1370_dac2_callback (void *opaque, int free);
-static void es1370_adc_callback (void *opaque, int avail);
-
-#ifdef DEBUG_ES1370
-
-#define ldebug(...) AUD_log ("es1370", __VA_ARGS__)
-
-static void print_ctl (uint32_t val)
-{
-    char buf[1024];
-
-    buf[0] = '\0';
-#define a(n) if (val & CTRL_##n) strcat (buf, " "#n)
-    a (ADC_STOP);
-    a (XCTL1);
-    a (OPEN);
-    a (MSFMTSEL);
-    a (M_SBB);
-    a (DAC_SYNC);
-    a (CCB_INTRM);
-    a (M_CB);
-    a (XCTL0);
-    a (BREQ);
-    a (DAC1_EN);
-    a (DAC2_EN);
-    a (ADC_EN);
-    a (UART_EN);
-    a (JYSTK_EN);
-    a (CDC_EN);
-    a (SERR_DIS);
-#undef a
-    AUD_log ("es1370", "ctl - PCLKDIV %d(DAC2 freq %d), freq %d,%s\n",
-             (val & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV,
-             DAC2_DIVTOSR ((val & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV),
-             dac1_samplerate[(val & CTRL_WTSRSEL) >> CTRL_SH_WTSRSEL],
-             buf);
-}
-
-static void print_sctl (uint32_t val)
-{
-    static const char *fmt_names[] = {"8M", "8S", "16M", "16S"};
-    char buf[1024];
-
-    buf[0] = '\0';
-
-#define a(n) if (val & SCTRL_##n) strcat (buf, " "#n)
-#define b(n) if (!(val & SCTRL_##n)) strcat (buf, " "#n)
-    b (R1LOOPSEL);
-    b (P2LOOPSEL);
-    b (P1LOOPSEL);
-    a (P2PAUSE);
-    a (P1PAUSE);
-    a (R1INTEN);
-    a (P2INTEN);
-    a (P1INTEN);
-    a (P1SCTRLD);
-    a (P2DACSEN);
-    if (buf[0]) {
-        strcat (buf, "\n        ");
-    }
-    else {
-        buf[0] = ' ';
-        buf[1] = '\0';
-    }
-#undef b
-#undef a
-    AUD_log ("es1370",
-             "%s"
-             "p2_end_inc %d, p2_st_inc %d, r1_fmt %s, p2_fmt %s, p1_fmt %s\n",
-             buf,
-             (val & SCTRL_P2ENDINC) >> SCTRL_SH_P2ENDINC,
-             (val & SCTRL_P2STINC) >> SCTRL_SH_P2STINC,
-             fmt_names [(val >> SCTRL_SH_R1FMT) & 3],
-             fmt_names [(val >> SCTRL_SH_P2FMT) & 3],
-             fmt_names [(val >> SCTRL_SH_P1FMT) & 3]
-        );
-}
-#else
-#define ldebug(...)
-#define print_ctl(...)
-#define print_sctl(...)
-#endif
-
-#ifdef VERBOSE_ES1370
-#define dolog(...) AUD_log ("es1370", __VA_ARGS__)
-#else
-#define dolog(...)
-#endif
-
-#ifndef SILENT_ES1370
-#define lwarn(...) AUD_log ("es1370: warning", __VA_ARGS__)
-#else
-#define lwarn(...)
-#endif
-
-struct chan {
-    uint32_t shift;
-    uint32_t leftover;
-    uint32_t scount;
-    uint32_t frame_addr;
-    uint32_t frame_cnt;
-};
-
-typedef struct ES1370State {
-    PCIDevice dev;
-    QEMUSoundCard card;
-    MemoryRegion io;
-    struct chan chan[NB_CHANNELS];
-    SWVoiceOut *dac_voice[2];
-    SWVoiceIn *adc_voice;
-
-    uint32_t ctl;
-    uint32_t status;
-    uint32_t mempage;
-    uint32_t codec;
-    uint32_t sctl;
-} ES1370State;
-
-struct chan_bits {
-    uint32_t ctl_en;
-    uint32_t stat_int;
-    uint32_t sctl_pause;
-    uint32_t sctl_inten;
-    uint32_t sctl_fmt;
-    uint32_t sctl_sh_fmt;
-    uint32_t sctl_loopsel;
-    void (*calc_freq) (ES1370State *s, uint32_t ctl,
-                       uint32_t *old_freq, uint32_t *new_freq);
-};
-
-static void es1370_dac1_calc_freq (ES1370State *s, uint32_t ctl,
-                                   uint32_t *old_freq, uint32_t *new_freq);
-static void es1370_dac2_and_adc_calc_freq (ES1370State *s, uint32_t ctl,
-                                           uint32_t *old_freq,
-                                           uint32_t *new_freq);
-
-static const struct chan_bits es1370_chan_bits[] = {
-    {CTRL_DAC1_EN, STAT_DAC1, SCTRL_P1PAUSE, SCTRL_P1INTEN,
-     SCTRL_P1FMT, SCTRL_SH_P1FMT, SCTRL_P1LOOPSEL,
-     es1370_dac1_calc_freq},
-
-    {CTRL_DAC2_EN, STAT_DAC2, SCTRL_P2PAUSE, SCTRL_P2INTEN,
-     SCTRL_P2FMT, SCTRL_SH_P2FMT, SCTRL_P2LOOPSEL,
-     es1370_dac2_and_adc_calc_freq},
-
-    {CTRL_ADC_EN, STAT_ADC, 0, SCTRL_R1INTEN,
-     SCTRL_R1FMT, SCTRL_SH_R1FMT, SCTRL_R1LOOPSEL,
-     es1370_dac2_and_adc_calc_freq}
-};
-
-static void es1370_update_status (ES1370State *s, uint32_t new_status)
-{
-    uint32_t level = new_status & (STAT_DAC1 | STAT_DAC2 | STAT_ADC);
-
-    if (level) {
-        s->status = new_status | STAT_INTR;
-    }
-    else {
-        s->status = new_status & ~STAT_INTR;
-    }
-    qemu_set_irq (s->dev.irq[0], !!level);
-}
-
-static void es1370_reset (ES1370State *s)
-{
-    size_t i;
-
-    s->ctl = 1;
-    s->status = 0x60;
-    s->mempage = 0;
-    s->codec = 0;
-    s->sctl = 0;
-
-    for (i = 0; i < NB_CHANNELS; ++i) {
-        struct chan *d = &s->chan[i];
-        d->scount = 0;
-        d->leftover = 0;
-        if (i == ADC_CHANNEL) {
-            AUD_close_in (&s->card, s->adc_voice);
-            s->adc_voice = NULL;
-        }
-        else {
-            AUD_close_out (&s->card, s->dac_voice[i]);
-            s->dac_voice[i] = NULL;
-        }
-    }
-    qemu_irq_lower (s->dev.irq[0]);
-}
-
-static void es1370_maybe_lower_irq (ES1370State *s, uint32_t sctl)
-{
-    uint32_t new_status = s->status;
-
-    if (!(sctl & SCTRL_P1INTEN) && (s->sctl & SCTRL_P1INTEN)) {
-        new_status &= ~STAT_DAC1;
-    }
-
-    if (!(sctl & SCTRL_P2INTEN) && (s->sctl & SCTRL_P2INTEN)) {
-        new_status &= ~STAT_DAC2;
-    }
-
-    if (!(sctl & SCTRL_R1INTEN) && (s->sctl & SCTRL_R1INTEN)) {
-        new_status &= ~STAT_ADC;
-    }
-
-    if (new_status != s->status) {
-        es1370_update_status (s, new_status);
-    }
-}
-
-static void es1370_dac1_calc_freq (ES1370State *s, uint32_t ctl,
-                                   uint32_t *old_freq, uint32_t *new_freq)
-
-{
-    *old_freq = dac1_samplerate[(s->ctl & CTRL_WTSRSEL) >> CTRL_SH_WTSRSEL];
-    *new_freq = dac1_samplerate[(ctl & CTRL_WTSRSEL) >> CTRL_SH_WTSRSEL];
-}
-
-static void es1370_dac2_and_adc_calc_freq (ES1370State *s, uint32_t ctl,
-                                           uint32_t *old_freq,
-                                           uint32_t *new_freq)
-
-{
-    uint32_t old_pclkdiv, new_pclkdiv;
-
-    new_pclkdiv = (ctl & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV;
-    old_pclkdiv = (s->ctl & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV;
-    *new_freq = DAC2_DIVTOSR (new_pclkdiv);
-    *old_freq = DAC2_DIVTOSR (old_pclkdiv);
-}
-
-static void es1370_update_voices (ES1370State *s, uint32_t ctl, uint32_t sctl)
-{
-    size_t i;
-    uint32_t old_freq, new_freq, old_fmt, new_fmt;
-
-    for (i = 0; i < NB_CHANNELS; ++i) {
-        struct chan *d = &s->chan[i];
-        const struct chan_bits *b = &es1370_chan_bits[i];
-
-        new_fmt = (sctl & b->sctl_fmt) >> b->sctl_sh_fmt;
-        old_fmt = (s->sctl & b->sctl_fmt) >> b->sctl_sh_fmt;
-
-        b->calc_freq (s, ctl, &old_freq, &new_freq);
-
-        if ((old_fmt != new_fmt) || (old_freq != new_freq)) {
-            d->shift = (new_fmt & 1) + (new_fmt >> 1);
-            ldebug ("channel %zu, freq = %d, nchannels %d, fmt %d, shift %d\n",
-                    i,
-                    new_freq,
-                    1 << (new_fmt & 1),
-                    (new_fmt & 2) ? AUD_FMT_S16 : AUD_FMT_U8,
-                    d->shift);
-            if (new_freq) {
-                struct audsettings as;
-
-                as.freq = new_freq;
-                as.nchannels = 1 << (new_fmt & 1);
-                as.fmt = (new_fmt & 2) ? AUD_FMT_S16 : AUD_FMT_U8;
-                as.endianness = 0;
-
-                if (i == ADC_CHANNEL) {
-                    s->adc_voice =
-                        AUD_open_in (
-                            &s->card,
-                            s->adc_voice,
-                            "es1370.adc",
-                            s,
-                            es1370_adc_callback,
-                            &as
-                            );
-                }
-                else {
-                    s->dac_voice[i] =
-                        AUD_open_out (
-                            &s->card,
-                            s->dac_voice[i],
-                            i ? "es1370.dac2" : "es1370.dac1",
-                            s,
-                            i ? es1370_dac2_callback : es1370_dac1_callback,
-                            &as
-                            );
-                }
-            }
-        }
-
-        if (((ctl ^ s->ctl) & b->ctl_en)
-            || ((sctl ^ s->sctl) & b->sctl_pause)) {
-            int on = (ctl & b->ctl_en) && !(sctl & b->sctl_pause);
-
-            if (i == ADC_CHANNEL) {
-                AUD_set_active_in (s->adc_voice, on);
-            }
-            else {
-                AUD_set_active_out (s->dac_voice[i], on);
-            }
-        }
-    }
-
-    s->ctl = ctl;
-    s->sctl = sctl;
-}
-
-static inline uint32_t es1370_fixup (ES1370State *s, uint32_t addr)
-{
-    addr &= 0xff;
-    if (addr >= 0x30 && addr <= 0x3f)
-        addr |= s->mempage << 8;
-    return addr;
-}
-
-IO_WRITE_PROTO (es1370_writeb)
-{
-    ES1370State *s = opaque;
-    uint32_t shift, mask;
-
-    addr = es1370_fixup (s, addr);
-
-    switch (addr) {
-    case ES1370_REG_CONTROL:
-    case ES1370_REG_CONTROL + 1:
-    case ES1370_REG_CONTROL + 2:
-    case ES1370_REG_CONTROL + 3:
-        shift = (addr - ES1370_REG_CONTROL) << 3;
-        mask = 0xff << shift;
-        val = (s->ctl & ~mask) | ((val & 0xff) << shift);
-        es1370_update_voices (s, val, s->sctl);
-        print_ctl (val);
-        break;
-    case ES1370_REG_MEMPAGE:
-        s->mempage = val;
-        break;
-    case ES1370_REG_SERIAL_CONTROL:
-    case ES1370_REG_SERIAL_CONTROL + 1:
-    case ES1370_REG_SERIAL_CONTROL + 2:
-    case ES1370_REG_SERIAL_CONTROL + 3:
-        shift = (addr - ES1370_REG_SERIAL_CONTROL) << 3;
-        mask = 0xff << shift;
-        val = (s->sctl & ~mask) | ((val & 0xff) << shift);
-        es1370_maybe_lower_irq (s, val);
-        es1370_update_voices (s, s->ctl, val);
-        print_sctl (val);
-        break;
-    default:
-        lwarn ("writeb %#x <- %#x\n", addr, val);
-        break;
-    }
-}
-
-IO_WRITE_PROTO (es1370_writew)
-{
-    ES1370State *s = opaque;
-    addr = es1370_fixup (s, addr);
-    uint32_t shift, mask;
-    struct chan *d = &s->chan[0];
-
-    switch (addr) {
-    case ES1370_REG_CODEC:
-        dolog ("ignored codec write address %#x, data %#x\n",
-               (val >> 8) & 0xff, val & 0xff);
-        s->codec = val;
-        break;
-
-    case ES1370_REG_CONTROL:
-    case ES1370_REG_CONTROL + 2:
-        shift = (addr != ES1370_REG_CONTROL) << 4;
-        mask = 0xffff << shift;
-        val = (s->ctl & ~mask) | ((val & 0xffff) << shift);
-        es1370_update_voices (s, val, s->sctl);
-        print_ctl (val);
-        break;
-
-    case ES1370_REG_ADC_SCOUNT:
-        d++;
-    case ES1370_REG_DAC2_SCOUNT:
-        d++;
-    case ES1370_REG_DAC1_SCOUNT:
-        d->scount = (d->scount & ~0xffff) | (val & 0xffff);
-        break;
-
-    default:
-        lwarn ("writew %#x <- %#x\n", addr, val);
-        break;
-    }
-}
-
-IO_WRITE_PROTO (es1370_writel)
-{
-    ES1370State *s = opaque;
-    struct chan *d = &s->chan[0];
-
-    addr = es1370_fixup (s, addr);
-
-    switch (addr) {
-    case ES1370_REG_CONTROL:
-        es1370_update_voices (s, val, s->sctl);
-        print_ctl (val);
-        break;
-
-    case ES1370_REG_MEMPAGE:
-        s->mempage = val & 0xf;
-        break;
-
-    case ES1370_REG_SERIAL_CONTROL:
-        es1370_maybe_lower_irq (s, val);
-        es1370_update_voices (s, s->ctl, val);
-        print_sctl (val);
-        break;
-
-    case ES1370_REG_ADC_SCOUNT:
-        d++;
-    case ES1370_REG_DAC2_SCOUNT:
-        d++;
-    case ES1370_REG_DAC1_SCOUNT:
-        d->scount = (val & 0xffff) | (d->scount & ~0xffff);
-        ldebug ("chan %td CURR_SAMP_CT %d, SAMP_CT %d\n",
-                d - &s->chan[0], val >> 16, (val & 0xffff));
-        break;
-
-    case ES1370_REG_ADC_FRAMEADR:
-        d++;
-    case ES1370_REG_DAC2_FRAMEADR:
-        d++;
-    case ES1370_REG_DAC1_FRAMEADR:
-        d->frame_addr = val;
-        ldebug ("chan %td frame address %#x\n", d - &s->chan[0], val);
-        break;
-
-    case ES1370_REG_PHANTOM_FRAMECNT:
-        lwarn ("writing to phantom frame count %#x\n", val);
-        break;
-    case ES1370_REG_PHANTOM_FRAMEADR:
-        lwarn ("writing to phantom frame address %#x\n", val);
-        break;
-
-    case ES1370_REG_ADC_FRAMECNT:
-        d++;
-    case ES1370_REG_DAC2_FRAMECNT:
-        d++;
-    case ES1370_REG_DAC1_FRAMECNT:
-        d->frame_cnt = val;
-        d->leftover = 0;
-        ldebug ("chan %td frame count %d, buffer size %d\n",
-                d - &s->chan[0], val >> 16, val & 0xffff);
-        break;
-
-    default:
-        lwarn ("writel %#x <- %#x\n", addr, val);
-        break;
-    }
-}
-
-IO_READ_PROTO (es1370_readb)
-{
-    ES1370State *s = opaque;
-    uint32_t val;
-
-    addr = es1370_fixup (s, addr);
-
-    switch (addr) {
-    case 0x1b:                  /* Legacy */
-        lwarn ("Attempt to read from legacy register\n");
-        val = 5;
-        break;
-    case ES1370_REG_MEMPAGE:
-        val = s->mempage;
-        break;
-    case ES1370_REG_CONTROL + 0:
-    case ES1370_REG_CONTROL + 1:
-    case ES1370_REG_CONTROL + 2:
-    case ES1370_REG_CONTROL + 3:
-        val = s->ctl >> ((addr - ES1370_REG_CONTROL) << 3);
-        break;
-    case ES1370_REG_STATUS + 0:
-    case ES1370_REG_STATUS + 1:
-    case ES1370_REG_STATUS + 2:
-    case ES1370_REG_STATUS + 3:
-        val = s->status >> ((addr - ES1370_REG_STATUS) << 3);
-        break;
-    default:
-        val = ~0;
-        lwarn ("readb %#x -> %#x\n", addr, val);
-        break;
-    }
-    return val;
-}
-
-IO_READ_PROTO (es1370_readw)
-{
-    ES1370State *s = opaque;
-    struct chan *d = &s->chan[0];
-    uint32_t val;
-
-    addr = es1370_fixup (s, addr);
-
-    switch (addr) {
-    case ES1370_REG_ADC_SCOUNT + 2:
-        d++;
-    case ES1370_REG_DAC2_SCOUNT + 2:
-        d++;
-    case ES1370_REG_DAC1_SCOUNT + 2:
-        val = d->scount >> 16;
-        break;
-
-    case ES1370_REG_ADC_FRAMECNT:
-        d++;
-    case ES1370_REG_DAC2_FRAMECNT:
-        d++;
-    case ES1370_REG_DAC1_FRAMECNT:
-        val = d->frame_cnt & 0xffff;
-        break;
-
-    case ES1370_REG_ADC_FRAMECNT + 2:
-        d++;
-    case ES1370_REG_DAC2_FRAMECNT + 2:
-        d++;
-    case ES1370_REG_DAC1_FRAMECNT + 2:
-        val = d->frame_cnt >> 16;
-        break;
-
-    default:
-        val = ~0;
-        lwarn ("readw %#x -> %#x\n", addr, val);
-        break;
-    }
-
-    return val;
-}
-
-IO_READ_PROTO (es1370_readl)
-{
-    ES1370State *s = opaque;
-    uint32_t val;
-    struct chan *d = &s->chan[0];
-
-    addr = es1370_fixup (s, addr);
-
-    switch (addr) {
-    case ES1370_REG_CONTROL:
-        val = s->ctl;
-        break;
-    case ES1370_REG_STATUS:
-        val = s->status;
-        break;
-    case ES1370_REG_MEMPAGE:
-        val = s->mempage;
-        break;
-    case ES1370_REG_CODEC:
-        val = s->codec;
-        break;
-    case ES1370_REG_SERIAL_CONTROL:
-        val = s->sctl;
-        break;
-
-    case ES1370_REG_ADC_SCOUNT:
-        d++;
-    case ES1370_REG_DAC2_SCOUNT:
-        d++;
-    case ES1370_REG_DAC1_SCOUNT:
-        val = d->scount;
-#ifdef DEBUG_ES1370
-        {
-            uint32_t curr_count = d->scount >> 16;
-            uint32_t count = d->scount & 0xffff;
-
-            curr_count <<= d->shift;
-            count <<= d->shift;
-            dolog ("read scount curr %d, total %d\n", curr_count, count);
-        }
-#endif
-        break;
-
-    case ES1370_REG_ADC_FRAMECNT:
-        d++;
-    case ES1370_REG_DAC2_FRAMECNT:
-        d++;
-    case ES1370_REG_DAC1_FRAMECNT:
-        val = d->frame_cnt;
-#ifdef DEBUG_ES1370
-        {
-            uint32_t size = ((d->frame_cnt & 0xffff) + 1) << 2;
-            uint32_t curr = ((d->frame_cnt >> 16) + 1) << 2;
-            if (curr > size) {
-                dolog ("read framecnt curr %d, size %d %d\n", curr, size,
-                       curr > size);
-            }
-        }
-#endif
-        break;
-
-    case ES1370_REG_ADC_FRAMEADR:
-        d++;
-    case ES1370_REG_DAC2_FRAMEADR:
-        d++;
-    case ES1370_REG_DAC1_FRAMEADR:
-        val = d->frame_addr;
-        break;
-
-    case ES1370_REG_PHANTOM_FRAMECNT:
-        val = ~0U;
-        lwarn ("reading from phantom frame count\n");
-        break;
-    case ES1370_REG_PHANTOM_FRAMEADR:
-        val = ~0U;
-        lwarn ("reading from phantom frame address\n");
-        break;
-
-    default:
-        val = ~0U;
-        lwarn ("readl %#x -> %#x\n", addr, val);
-        break;
-    }
-    return val;
-}
-
-static void es1370_transfer_audio (ES1370State *s, struct chan *d, int loop_sel,
-                                   int max, int *irq)
-{
-    uint8_t tmpbuf[4096];
-    uint32_t addr = d->frame_addr;
-    int sc = d->scount & 0xffff;
-    int csc = d->scount >> 16;
-    int csc_bytes = (csc + 1) << d->shift;
-    int cnt = d->frame_cnt >> 16;
-    int size = d->frame_cnt & 0xffff;
-    int left = ((size - cnt + 1) << 2) + d->leftover;
-    int transferred = 0;
-    int temp = audio_MIN (max, audio_MIN (left, csc_bytes));
-    int index = d - &s->chan[0];
-
-    addr += (cnt << 2) + d->leftover;
-
-    if (index == ADC_CHANNEL) {
-        while (temp) {
-            int acquired, to_copy;
-
-            to_copy = audio_MIN ((size_t) temp, sizeof (tmpbuf));
-            acquired = AUD_read (s->adc_voice, tmpbuf, to_copy);
-            if (!acquired)
-                break;
-
-            pci_dma_write (&s->dev, addr, tmpbuf, acquired);
-
-            temp -= acquired;
-            addr += acquired;
-            transferred += acquired;
-        }
-    }
-    else {
-        SWVoiceOut *voice = s->dac_voice[index];
-
-        while (temp) {
-            int copied, to_copy;
-
-            to_copy = audio_MIN ((size_t) temp, sizeof (tmpbuf));
-            pci_dma_read (&s->dev, addr, tmpbuf, to_copy);
-            copied = AUD_write (voice, tmpbuf, to_copy);
-            if (!copied)
-                break;
-            temp -= copied;
-            addr += copied;
-            transferred += copied;
-        }
-    }
-
-    if (csc_bytes == transferred) {
-        *irq = 1;
-        d->scount = sc | (sc << 16);
-        ldebug ("sc = %d, rate = %f\n",
-                (sc + 1) << d->shift,
-                (sc + 1) / (double) 44100);
-    }
-    else {
-        *irq = 0;
-        d->scount = sc | (((csc_bytes - transferred - 1) >> d->shift) << 16);
-    }
-
-    cnt += (transferred + d->leftover) >> 2;
-
-    if (s->sctl & loop_sel) {
-        /* Bah, how stupid is that having a 0 represent true value?
-           i just spent few hours on this shit */
-        AUD_log ("es1370: warning", "non looping mode\n");
-    }
-    else {
-        d->frame_cnt = size;
-
-        if ((uint32_t) cnt <= d->frame_cnt)
-            d->frame_cnt |= cnt << 16;
-    }
-
-    d->leftover = (transferred + d->leftover) & 3;
-}
-
-static void es1370_run_channel (ES1370State *s, size_t chan, int free_or_avail)
-{
-    uint32_t new_status = s->status;
-    int max_bytes, irq;
-    struct chan *d = &s->chan[chan];
-    const struct chan_bits *b = &es1370_chan_bits[chan];
-
-    if (!(s->ctl & b->ctl_en) || (s->sctl & b->sctl_pause)) {
-        return;
-    }
-
-    max_bytes = free_or_avail;
-    max_bytes &= ~((1 << d->shift) - 1);
-    if (!max_bytes) {
-        return;
-    }
-
-    es1370_transfer_audio (s, d, b->sctl_loopsel, max_bytes, &irq);
-
-    if (irq) {
-        if (s->sctl & b->sctl_inten) {
-            new_status |= b->stat_int;
-        }
-    }
-
-    if (new_status != s->status) {
-        es1370_update_status (s, new_status);
-    }
-}
-
-static void es1370_dac1_callback (void *opaque, int free)
-{
-    ES1370State *s = opaque;
-
-    es1370_run_channel (s, DAC1_CHANNEL, free);
-}
-
-static void es1370_dac2_callback (void *opaque, int free)
-{
-    ES1370State *s = opaque;
-
-    es1370_run_channel (s, DAC2_CHANNEL, free);
-}
-
-static void es1370_adc_callback (void *opaque, int avail)
-{
-    ES1370State *s = opaque;
-
-    es1370_run_channel (s, ADC_CHANNEL, avail);
-}
-
-static uint64_t es1370_read(void *opaque, hwaddr addr,
-                            unsigned size)
-{
-    switch (size) {
-    case 1:
-        return es1370_readb(opaque, addr);
-    case 2:
-        return es1370_readw(opaque, addr);
-    case 4:
-        return es1370_readl(opaque, addr);
-    default:
-        return -1;
-    }
-}
-
-static void es1370_write(void *opaque, hwaddr addr, uint64_t val,
-                      unsigned size)
-{
-    switch (size) {
-    case 1:
-        es1370_writeb(opaque, addr, val);
-        break;
-    case 2:
-        es1370_writew(opaque, addr, val);
-        break;
-    case 4:
-        es1370_writel(opaque, addr, val);
-        break;
-    }
-}
-
-static const MemoryRegionOps es1370_io_ops = {
-    .read = es1370_read,
-    .write = es1370_write,
-    .impl = {
-        .min_access_size = 1,
-        .max_access_size = 4,
-    },
-    .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static const VMStateDescription vmstate_es1370_channel = {
-    .name = "es1370_channel",
-    .version_id = 2,
-    .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 ()
-    }
-};
-
-static int es1370_post_load (void *opaque, int version_id)
-{
-    uint32_t ctl, sctl;
-    ES1370State *s = opaque;
-    size_t i;
-
-    for (i = 0; i < NB_CHANNELS; ++i) {
-        if (i == ADC_CHANNEL) {
-            if (s->adc_voice) {
-                AUD_close_in (&s->card, s->adc_voice);
-                s->adc_voice = NULL;
-            }
-        }
-        else {
-            if (s->dac_voice[i]) {
-                AUD_close_out (&s->card, s->dac_voice[i]);
-                s->dac_voice[i] = NULL;
-            }
-        }
-    }
-
-    ctl = s->ctl;
-    sctl = s->sctl;
-    s->ctl = 0;
-    s->sctl = 0;
-    es1370_update_voices (s, ctl, sctl);
-    return 0;
-}
-
-static const VMStateDescription vmstate_es1370 = {
-    .name = "es1370",
-    .version_id = 2,
-    .minimum_version_id = 2,
-    .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 ()
-    }
-};
-
-static void es1370_on_reset (void *opaque)
-{
-    ES1370State *s = opaque;
-    es1370_reset (s);
-}
-
-static int es1370_initfn (PCIDevice *dev)
-{
-    ES1370State *s = DO_UPCAST (ES1370State, dev, dev);
-    uint8_t *c = s->dev.config;
-
-    c[PCI_STATUS + 1] = PCI_STATUS_DEVSEL_SLOW >> 8;
-
-#if 0
-    c[PCI_CAPABILITY_LIST] = 0xdc;
-    c[PCI_INTERRUPT_LINE] = 10;
-    c[0xdc] = 0x00;
-#endif
-
-    c[PCI_INTERRUPT_PIN] = 1;
-    c[PCI_MIN_GNT] = 0x0c;
-    c[PCI_MAX_LAT] = 0x80;
-
-    memory_region_init_io (&s->io, &es1370_io_ops, s, "es1370", 256);
-    pci_register_bar (&s->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io);
-    qemu_register_reset (es1370_on_reset, s);
-
-    AUD_register_card ("es1370", &s->card);
-    es1370_reset (s);
-    return 0;
-}
-
-static void es1370_exitfn (PCIDevice *dev)
-{
-    ES1370State *s = DO_UPCAST (ES1370State, dev, dev);
-
-    memory_region_destroy (&s->io);
-}
-
-int es1370_init (PCIBus *bus)
-{
-    pci_create_simple (bus, -1, "ES1370");
-    return 0;
-}
-
-static void es1370_class_init (ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS (klass);
-    PCIDeviceClass *k = PCI_DEVICE_CLASS (klass);
-
-    k->init = es1370_initfn;
-    k->exit = es1370_exitfn;
-    k->vendor_id = PCI_VENDOR_ID_ENSONIQ;
-    k->device_id = PCI_DEVICE_ID_ENSONIQ_ES1370;
-    k->class_id = PCI_CLASS_MULTIMEDIA_AUDIO;
-    k->subsystem_vendor_id = 0x4942;
-    k->subsystem_id = 0x4c4c;
-    dc->desc = "ENSONIQ AudioPCI ES1370";
-    dc->vmsd = &vmstate_es1370;
-}
-
-static const TypeInfo es1370_info = {
-    .name          = "ES1370",
-    .parent        = TYPE_PCI_DEVICE,
-    .instance_size = sizeof (ES1370State),
-    .class_init    = es1370_class_init,
-};
-
-static void es1370_register_types (void)
-{
-    type_register_static (&es1370_info);
-}
-
-type_init (es1370_register_types)
-
diff --git a/hw/escc.c b/hw/escc.c
deleted file mode 100644 (file)
index baf0219..0000000
--- a/hw/escc.c
+++ /dev/null
@@ -1,938 +0,0 @@
-/*
- * QEMU ESCC (Z8030/Z8530/Z85C30/SCC/ESCC) serial port emulation
- *
- * Copyright (c) 2003-2005 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.
- */
-
-#include "hw/hw.h"
-#include "hw/sysbus.h"
-#include "hw/escc.h"
-#include "char/char.h"
-#include "ui/console.h"
-#include "trace.h"
-
-/*
- * Chipset docs:
- * "Z80C30/Z85C30/Z80230/Z85230/Z85233 SCC/ESCC User Manual",
- * http://www.zilog.com/docs/serial/scc_escc_um.pdf
- *
- * On Sparc32 this is the serial port, mouse and keyboard part of chip STP2001
- * (Slave I/O), also produced as NCR89C105. See
- * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
- *
- * The serial ports implement full AMD AM8530 or Zilog Z8530 chips,
- * mouse and keyboard ports don't implement all functions and they are
- * only asynchronous. There is no DMA.
- *
- * Z85C30 is also used on PowerMacs. There are some small differences
- * between Sparc version (sunzilog) and PowerMac (pmac):
- *  Offset between control and data registers
- *  There is some kind of lockup bug, but we can ignore it
- *  CTS is inverted
- *  DMA on pmac using DBDMA chip
- *  pmac can do IRDA and faster rates, sunzilog can only do 38400
- *  pmac baud rate generator clock is 3.6864 MHz, sunzilog 4.9152 MHz
- */
-
-/*
- * Modifications:
- *  2006-Aug-10  Igor Kovalenko :   Renamed KBDQueue to SERIOQueue, implemented
- *                                  serial mouse queue.
- *                                  Implemented serial mouse protocol.
- *
- *  2010-May-23  Artyom Tarasenko:  Reworked IUS logic
- */
-
-typedef enum {
-    chn_a, chn_b,
-} ChnID;
-
-#define CHN_C(s) ((s)->chn == chn_b? 'b' : 'a')
-
-typedef enum {
-    ser, kbd, mouse,
-} ChnType;
-
-#define SERIO_QUEUE_SIZE 256
-
-typedef struct {
-    uint8_t data[SERIO_QUEUE_SIZE];
-    int rptr, wptr, count;
-} SERIOQueue;
-
-#define SERIAL_REGS 16
-typedef struct ChannelState {
-    qemu_irq irq;
-    uint32_t rxint, txint, rxint_under_svc, txint_under_svc;
-    struct ChannelState *otherchn;
-    uint32_t reg;
-    uint8_t wregs[SERIAL_REGS], rregs[SERIAL_REGS];
-    SERIOQueue queue;
-    CharDriverState *chr;
-    int e0_mode, led_mode, caps_lock_mode, num_lock_mode;
-    int disabled;
-    int clock;
-    uint32_t vmstate_dummy;
-    ChnID chn; // this channel, A (base+4) or B (base+0)
-    ChnType type;
-    uint8_t rx, tx;
-} ChannelState;
-
-struct SerialState {
-    SysBusDevice busdev;
-    struct ChannelState chn[2];
-    uint32_t it_shift;
-    MemoryRegion mmio;
-    uint32_t disabled;
-    uint32_t frequency;
-};
-
-#define SERIAL_CTRL 0
-#define SERIAL_DATA 1
-
-#define W_CMD     0
-#define CMD_PTR_MASK   0x07
-#define CMD_CMD_MASK   0x38
-#define CMD_HI         0x08
-#define CMD_CLR_TXINT  0x28
-#define CMD_CLR_IUS    0x38
-#define W_INTR    1
-#define INTR_INTALL    0x01
-#define INTR_TXINT     0x02
-#define INTR_RXMODEMSK 0x18
-#define INTR_RXINT1ST  0x08
-#define INTR_RXINTALL  0x10
-#define W_IVEC    2
-#define W_RXCTRL  3
-#define RXCTRL_RXEN    0x01
-#define W_TXCTRL1 4
-#define TXCTRL1_PAREN  0x01
-#define TXCTRL1_PAREV  0x02
-#define TXCTRL1_1STOP  0x04
-#define TXCTRL1_1HSTOP 0x08
-#define TXCTRL1_2STOP  0x0c
-#define TXCTRL1_STPMSK 0x0c
-#define TXCTRL1_CLK1X  0x00
-#define TXCTRL1_CLK16X 0x40
-#define TXCTRL1_CLK32X 0x80
-#define TXCTRL1_CLK64X 0xc0
-#define TXCTRL1_CLKMSK 0xc0
-#define W_TXCTRL2 5
-#define TXCTRL2_TXEN   0x08
-#define TXCTRL2_BITMSK 0x60
-#define TXCTRL2_5BITS  0x00
-#define TXCTRL2_7BITS  0x20
-#define TXCTRL2_6BITS  0x40
-#define TXCTRL2_8BITS  0x60
-#define W_SYNC1   6
-#define W_SYNC2   7
-#define W_TXBUF   8
-#define W_MINTR   9
-#define MINTR_STATUSHI 0x10
-#define MINTR_RST_MASK 0xc0
-#define MINTR_RST_B    0x40
-#define MINTR_RST_A    0x80
-#define MINTR_RST_ALL  0xc0
-#define W_MISC1  10
-#define W_CLOCK  11
-#define CLOCK_TRXC     0x08
-#define W_BRGLO  12
-#define W_BRGHI  13
-#define W_MISC2  14
-#define MISC2_PLLDIS   0x30
-#define W_EXTINT 15
-#define EXTINT_DCD     0x08
-#define EXTINT_SYNCINT 0x10
-#define EXTINT_CTSINT  0x20
-#define EXTINT_TXUNDRN 0x40
-#define EXTINT_BRKINT  0x80
-
-#define R_STATUS  0
-#define STATUS_RXAV    0x01
-#define STATUS_ZERO    0x02
-#define STATUS_TXEMPTY 0x04
-#define STATUS_DCD     0x08
-#define STATUS_SYNC    0x10
-#define STATUS_CTS     0x20
-#define STATUS_TXUNDRN 0x40
-#define STATUS_BRK     0x80
-#define R_SPEC    1
-#define SPEC_ALLSENT   0x01
-#define SPEC_BITS8     0x06
-#define R_IVEC    2
-#define IVEC_TXINTB    0x00
-#define IVEC_LONOINT   0x06
-#define IVEC_LORXINTA  0x0c
-#define IVEC_LORXINTB  0x04
-#define IVEC_LOTXINTA  0x08
-#define IVEC_HINOINT   0x60
-#define IVEC_HIRXINTA  0x30
-#define IVEC_HIRXINTB  0x20
-#define IVEC_HITXINTA  0x10
-#define R_INTR    3
-#define INTR_EXTINTB   0x01
-#define INTR_TXINTB    0x02
-#define INTR_RXINTB    0x04
-#define INTR_EXTINTA   0x08
-#define INTR_TXINTA    0x10
-#define INTR_RXINTA    0x20
-#define R_IPEN    4
-#define R_TXCTRL1 5
-#define R_TXCTRL2 6
-#define R_BC      7
-#define R_RXBUF   8
-#define R_RXCTRL  9
-#define R_MISC   10
-#define R_MISC1  11
-#define R_BRGLO  12
-#define R_BRGHI  13
-#define R_MISC1I 14
-#define R_EXTINT 15
-
-static void handle_kbd_command(ChannelState *s, int val);
-static int serial_can_receive(void *opaque);
-static void serial_receive_byte(ChannelState *s, int ch);
-
-static void clear_queue(void *opaque)
-{
-    ChannelState *s = opaque;
-    SERIOQueue *q = &s->queue;
-    q->rptr = q->wptr = q->count = 0;
-}
-
-static void put_queue(void *opaque, int b)
-{
-    ChannelState *s = opaque;
-    SERIOQueue *q = &s->queue;
-
-    trace_escc_put_queue(CHN_C(s), b);
-    if (q->count >= SERIO_QUEUE_SIZE)
-        return;
-    q->data[q->wptr] = b;
-    if (++q->wptr == SERIO_QUEUE_SIZE)
-        q->wptr = 0;
-    q->count++;
-    serial_receive_byte(s, 0);
-}
-
-static uint32_t get_queue(void *opaque)
-{
-    ChannelState *s = opaque;
-    SERIOQueue *q = &s->queue;
-    int val;
-
-    if (q->count == 0) {
-        return 0;
-    } else {
-        val = q->data[q->rptr];
-        if (++q->rptr == SERIO_QUEUE_SIZE)
-            q->rptr = 0;
-        q->count--;
-    }
-    trace_escc_get_queue(CHN_C(s), val);
-    if (q->count > 0)
-        serial_receive_byte(s, 0);
-    return val;
-}
-
-static int escc_update_irq_chn(ChannelState *s)
-{
-    if ((((s->wregs[W_INTR] & INTR_TXINT) && (s->txint == 1)) ||
-         // tx ints enabled, pending
-         ((((s->wregs[W_INTR] & INTR_RXMODEMSK) == INTR_RXINT1ST) ||
-           ((s->wregs[W_INTR] & INTR_RXMODEMSK) == INTR_RXINTALL)) &&
-          s->rxint == 1) || // rx ints enabled, pending
-         ((s->wregs[W_EXTINT] & EXTINT_BRKINT) &&
-          (s->rregs[R_STATUS] & STATUS_BRK)))) { // break int e&p
-        return 1;
-    }
-    return 0;
-}
-
-static void escc_update_irq(ChannelState *s)
-{
-    int irq;
-
-    irq = escc_update_irq_chn(s);
-    irq |= escc_update_irq_chn(s->otherchn);
-
-    trace_escc_update_irq(irq);
-    qemu_set_irq(s->irq, irq);
-}
-
-static void escc_reset_chn(ChannelState *s)
-{
-    int i;
-
-    s->reg = 0;
-    for (i = 0; i < SERIAL_REGS; i++) {
-        s->rregs[i] = 0;
-        s->wregs[i] = 0;
-    }
-    s->wregs[W_TXCTRL1] = TXCTRL1_1STOP; // 1X divisor, 1 stop bit, no parity
-    s->wregs[W_MINTR] = MINTR_RST_ALL;
-    s->wregs[W_CLOCK] = CLOCK_TRXC; // Synch mode tx clock = TRxC
-    s->wregs[W_MISC2] = MISC2_PLLDIS; // PLL disabled
-    s->wregs[W_EXTINT] = EXTINT_DCD | EXTINT_SYNCINT | EXTINT_CTSINT |
-        EXTINT_TXUNDRN | EXTINT_BRKINT; // Enable most interrupts
-    if (s->disabled)
-        s->rregs[R_STATUS] = STATUS_TXEMPTY | STATUS_DCD | STATUS_SYNC |
-            STATUS_CTS | STATUS_TXUNDRN;
-    else
-        s->rregs[R_STATUS] = STATUS_TXEMPTY | STATUS_TXUNDRN;
-    s->rregs[R_SPEC] = SPEC_BITS8 | SPEC_ALLSENT;
-
-    s->rx = s->tx = 0;
-    s->rxint = s->txint = 0;
-    s->rxint_under_svc = s->txint_under_svc = 0;
-    s->e0_mode = s->led_mode = s->caps_lock_mode = s->num_lock_mode = 0;
-    clear_queue(s);
-}
-
-static void escc_reset(DeviceState *d)
-{
-    SerialState *s = container_of(d, SerialState, busdev.qdev);
-
-    escc_reset_chn(&s->chn[0]);
-    escc_reset_chn(&s->chn[1]);
-}
-
-static inline void set_rxint(ChannelState *s)
-{
-    s->rxint = 1;
-    /* XXX: missing daisy chainnig: chn_b rx should have a lower priority
-       than chn_a rx/tx/special_condition service*/
-    s->rxint_under_svc = 1;
-    if (s->chn == chn_a) {
-        s->rregs[R_INTR] |= INTR_RXINTA;
-        if (s->wregs[W_MINTR] & MINTR_STATUSHI)
-            s->otherchn->rregs[R_IVEC] = IVEC_HIRXINTA;
-        else
-            s->otherchn->rregs[R_IVEC] = IVEC_LORXINTA;
-    } else {
-        s->otherchn->rregs[R_INTR] |= INTR_RXINTB;
-        if (s->wregs[W_MINTR] & MINTR_STATUSHI)
-            s->rregs[R_IVEC] = IVEC_HIRXINTB;
-        else
-            s->rregs[R_IVEC] = IVEC_LORXINTB;
-    }
-    escc_update_irq(s);
-}
-
-static inline void set_txint(ChannelState *s)
-{
-    s->txint = 1;
-    if (!s->rxint_under_svc) {
-        s->txint_under_svc = 1;
-        if (s->chn == chn_a) {
-            if (s->wregs[W_INTR] & INTR_TXINT) {
-                s->rregs[R_INTR] |= INTR_TXINTA;
-            }
-            if (s->wregs[W_MINTR] & MINTR_STATUSHI)
-                s->otherchn->rregs[R_IVEC] = IVEC_HITXINTA;
-            else
-                s->otherchn->rregs[R_IVEC] = IVEC_LOTXINTA;
-        } else {
-            s->rregs[R_IVEC] = IVEC_TXINTB;
-            if (s->wregs[W_INTR] & INTR_TXINT) {
-                s->otherchn->rregs[R_INTR] |= INTR_TXINTB;
-            }
-        }
-    escc_update_irq(s);
-    }
-}
-
-static inline void clr_rxint(ChannelState *s)
-{
-    s->rxint = 0;
-    s->rxint_under_svc = 0;
-    if (s->chn == chn_a) {
-        if (s->wregs[W_MINTR] & MINTR_STATUSHI)
-            s->otherchn->rregs[R_IVEC] = IVEC_HINOINT;
-        else
-            s->otherchn->rregs[R_IVEC] = IVEC_LONOINT;
-        s->rregs[R_INTR] &= ~INTR_RXINTA;
-    } else {
-        if (s->wregs[W_MINTR] & MINTR_STATUSHI)
-            s->rregs[R_IVEC] = IVEC_HINOINT;
-        else
-            s->rregs[R_IVEC] = IVEC_LONOINT;
-        s->otherchn->rregs[R_INTR] &= ~INTR_RXINTB;
-    }
-    if (s->txint)
-        set_txint(s);
-    escc_update_irq(s);
-}
-
-static inline void clr_txint(ChannelState *s)
-{
-    s->txint = 0;
-    s->txint_under_svc = 0;
-    if (s->chn == chn_a) {
-        if (s->wregs[W_MINTR] & MINTR_STATUSHI)
-            s->otherchn->rregs[R_IVEC] = IVEC_HINOINT;
-        else
-            s->otherchn->rregs[R_IVEC] = IVEC_LONOINT;
-        s->rregs[R_INTR] &= ~INTR_TXINTA;
-    } else {
-        s->otherchn->rregs[R_INTR] &= ~INTR_TXINTB;
-        if (s->wregs[W_MINTR] & MINTR_STATUSHI)
-            s->rregs[R_IVEC] = IVEC_HINOINT;
-        else
-            s->rregs[R_IVEC] = IVEC_LONOINT;
-        s->otherchn->rregs[R_INTR] &= ~INTR_TXINTB;
-    }
-    if (s->rxint)
-        set_rxint(s);
-    escc_update_irq(s);
-}
-
-static void escc_update_parameters(ChannelState *s)
-{
-    int speed, parity, data_bits, stop_bits;
-    QEMUSerialSetParams ssp;
-
-    if (!s->chr || s->type != ser)
-        return;
-
-    if (s->wregs[W_TXCTRL1] & TXCTRL1_PAREN) {
-        if (s->wregs[W_TXCTRL1] & TXCTRL1_PAREV)
-            parity = 'E';
-        else
-            parity = 'O';
-    } else {
-        parity = 'N';
-    }
-    if ((s->wregs[W_TXCTRL1] & TXCTRL1_STPMSK) == TXCTRL1_2STOP)
-        stop_bits = 2;
-    else
-        stop_bits = 1;
-    switch (s->wregs[W_TXCTRL2] & TXCTRL2_BITMSK) {
-    case TXCTRL2_5BITS:
-        data_bits = 5;
-        break;
-    case TXCTRL2_7BITS:
-        data_bits = 7;
-        break;
-    case TXCTRL2_6BITS:
-        data_bits = 6;
-        break;
-    default:
-    case TXCTRL2_8BITS:
-        data_bits = 8;
-        break;
-    }
-    speed = s->clock / ((s->wregs[W_BRGLO] | (s->wregs[W_BRGHI] << 8)) + 2);
-    switch (s->wregs[W_TXCTRL1] & TXCTRL1_CLKMSK) {
-    case TXCTRL1_CLK1X:
-        break;
-    case TXCTRL1_CLK16X:
-        speed /= 16;
-        break;
-    case TXCTRL1_CLK32X:
-        speed /= 32;
-        break;
-    default:
-    case TXCTRL1_CLK64X:
-        speed /= 64;
-        break;
-    }
-    ssp.speed = speed;
-    ssp.parity = parity;
-    ssp.data_bits = data_bits;
-    ssp.stop_bits = stop_bits;
-    trace_escc_update_parameters(CHN_C(s), speed, parity, data_bits, stop_bits);
-    qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
-}
-
-static void escc_mem_write(void *opaque, hwaddr addr,
-                           uint64_t val, unsigned size)
-{
-    SerialState *serial = opaque;
-    ChannelState *s;
-    uint32_t saddr;
-    int newreg, channel;
-
-    val &= 0xff;
-    saddr = (addr >> serial->it_shift) & 1;
-    channel = (addr >> (serial->it_shift + 1)) & 1;
-    s = &serial->chn[channel];
-    switch (saddr) {
-    case SERIAL_CTRL:
-        trace_escc_mem_writeb_ctrl(CHN_C(s), s->reg, val & 0xff);
-        newreg = 0;
-        switch (s->reg) {
-        case W_CMD:
-            newreg = val & CMD_PTR_MASK;
-            val &= CMD_CMD_MASK;
-            switch (val) {
-            case CMD_HI:
-                newreg |= CMD_HI;
-                break;
-            case CMD_CLR_TXINT:
-                clr_txint(s);
-                break;
-            case CMD_CLR_IUS:
-                if (s->rxint_under_svc) {
-                    s->rxint_under_svc = 0;
-                    if (s->txint) {
-                        set_txint(s);
-                    }
-                } else if (s->txint_under_svc) {
-                    s->txint_under_svc = 0;
-                }
-                escc_update_irq(s);
-                break;
-            default:
-                break;
-            }
-            break;
-        case W_INTR ... W_RXCTRL:
-        case W_SYNC1 ... W_TXBUF:
-        case W_MISC1 ... W_CLOCK:
-        case W_MISC2 ... W_EXTINT:
-            s->wregs[s->reg] = val;
-            break;
-        case W_TXCTRL1:
-        case W_TXCTRL2:
-            s->wregs[s->reg] = val;
-            escc_update_parameters(s);
-            break;
-        case W_BRGLO:
-        case W_BRGHI:
-            s->wregs[s->reg] = val;
-            s->rregs[s->reg] = val;
-            escc_update_parameters(s);
-            break;
-        case W_MINTR:
-            switch (val & MINTR_RST_MASK) {
-            case 0:
-            default:
-                break;
-            case MINTR_RST_B:
-                escc_reset_chn(&serial->chn[0]);
-                return;
-            case MINTR_RST_A:
-                escc_reset_chn(&serial->chn[1]);
-                return;
-            case MINTR_RST_ALL:
-                escc_reset(&serial->busdev.qdev);
-                return;
-            }
-            break;
-        default:
-            break;
-        }
-        if (s->reg == 0)
-            s->reg = newreg;
-        else
-            s->reg = 0;
-        break;
-    case SERIAL_DATA:
-        trace_escc_mem_writeb_data(CHN_C(s), val);
-        s->tx = val;
-        if (s->wregs[W_TXCTRL2] & TXCTRL2_TXEN) { // tx enabled
-            if (s->chr)
-                qemu_chr_fe_write(s->chr, &s->tx, 1);
-            else if (s->type == kbd && !s->disabled) {
-                handle_kbd_command(s, val);
-            }
-        }
-        s->rregs[R_STATUS] |= STATUS_TXEMPTY; // Tx buffer empty
-        s->rregs[R_SPEC] |= SPEC_ALLSENT; // All sent
-        set_txint(s);
-        break;
-    default:
-        break;
-    }
-}
-
-static uint64_t escc_mem_read(void *opaque, hwaddr addr,
-                              unsigned size)
-{
-    SerialState *serial = opaque;
-    ChannelState *s;
-    uint32_t saddr;
-    uint32_t ret;
-    int channel;
-
-    saddr = (addr >> serial->it_shift) & 1;
-    channel = (addr >> (serial->it_shift + 1)) & 1;
-    s = &serial->chn[channel];
-    switch (saddr) {
-    case SERIAL_CTRL:
-        trace_escc_mem_readb_ctrl(CHN_C(s), s->reg, s->rregs[s->reg]);
-        ret = s->rregs[s->reg];
-        s->reg = 0;
-        return ret;
-    case SERIAL_DATA:
-        s->rregs[R_STATUS] &= ~STATUS_RXAV;
-        clr_rxint(s);
-        if (s->type == kbd || s->type == mouse)
-            ret = get_queue(s);
-        else
-            ret = s->rx;
-        trace_escc_mem_readb_data(CHN_C(s), ret);
-        if (s->chr)
-            qemu_chr_accept_input(s->chr);
-        return ret;
-    default:
-        break;
-    }
-    return 0;
-}
-
-static const MemoryRegionOps escc_mem_ops = {
-    .read = escc_mem_read,
-    .write = escc_mem_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid = {
-        .min_access_size = 1,
-        .max_access_size = 1,
-    },
-};
-
-static int serial_can_receive(void *opaque)
-{
-    ChannelState *s = opaque;
-    int ret;
-
-    if (((s->wregs[W_RXCTRL] & RXCTRL_RXEN) == 0) // Rx not enabled
-        || ((s->rregs[R_STATUS] & STATUS_RXAV) == STATUS_RXAV))
-        // char already available
-        ret = 0;
-    else
-        ret = 1;
-    return ret;
-}
-
-static void serial_receive_byte(ChannelState *s, int ch)
-{
-    trace_escc_serial_receive_byte(CHN_C(s), ch);
-    s->rregs[R_STATUS] |= STATUS_RXAV;
-    s->rx = ch;
-    set_rxint(s);
-}
-
-static void serial_receive_break(ChannelState *s)
-{
-    s->rregs[R_STATUS] |= STATUS_BRK;
-    escc_update_irq(s);
-}
-
-static void serial_receive1(void *opaque, const uint8_t *buf, int size)
-{
-    ChannelState *s = opaque;
-    serial_receive_byte(s, buf[0]);
-}
-
-static void serial_event(void *opaque, int event)
-{
-    ChannelState *s = opaque;
-    if (event == CHR_EVENT_BREAK)
-        serial_receive_break(s);
-}
-
-static const VMStateDescription vmstate_escc_chn = {
-    .name ="escc_chn",
-    .version_id = 2,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField []) {
-        VMSTATE_UINT32(vmstate_dummy, ChannelState),
-        VMSTATE_UINT32(reg, ChannelState),
-        VMSTATE_UINT32(rxint, ChannelState),
-        VMSTATE_UINT32(txint, ChannelState),
-        VMSTATE_UINT32(rxint_under_svc, ChannelState),
-        VMSTATE_UINT32(txint_under_svc, ChannelState),
-        VMSTATE_UINT8(rx, ChannelState),
-        VMSTATE_UINT8(tx, ChannelState),
-        VMSTATE_BUFFER(wregs, ChannelState),
-        VMSTATE_BUFFER(rregs, ChannelState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static const VMStateDescription vmstate_escc = {
-    .name ="escc",
-    .version_id = 2,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField []) {
-        VMSTATE_STRUCT_ARRAY(chn, SerialState, 2, 2, vmstate_escc_chn,
-                             ChannelState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-MemoryRegion *escc_init(hwaddr base, qemu_irq irqA, qemu_irq irqB,
-              CharDriverState *chrA, CharDriverState *chrB,
-              int clock, int it_shift)
-{
-    DeviceState *dev;
-    SysBusDevice *s;
-    SerialState *d;
-
-    dev = qdev_create(NULL, "escc");
-    qdev_prop_set_uint32(dev, "disabled", 0);
-    qdev_prop_set_uint32(dev, "frequency", clock);
-    qdev_prop_set_uint32(dev, "it_shift", it_shift);
-    qdev_prop_set_chr(dev, "chrB", chrB);
-    qdev_prop_set_chr(dev, "chrA", chrA);
-    qdev_prop_set_uint32(dev, "chnBtype", ser);
-    qdev_prop_set_uint32(dev, "chnAtype", ser);
-    qdev_init_nofail(dev);
-    s = SYS_BUS_DEVICE(dev);
-    sysbus_connect_irq(s, 0, irqB);
-    sysbus_connect_irq(s, 1, irqA);
-    if (base) {
-        sysbus_mmio_map(s, 0, base);
-    }
-
-    d = FROM_SYSBUS(SerialState, s);
-    return &d->mmio;
-}
-
-static const uint8_t keycodes[128] = {
-    127, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 43, 53,
-    54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 89, 76, 77, 78,
-    79, 80, 81, 82, 83, 84, 85, 86, 87, 42, 99, 88, 100, 101, 102, 103,
-    104, 105, 106, 107, 108, 109, 110, 47, 19, 121, 119, 5, 6, 8, 10, 12,
-    14, 16, 17, 18, 7, 98, 23, 68, 69, 70, 71, 91, 92, 93, 125, 112,
-    113, 114, 94, 50, 0, 0, 124, 9, 11, 0, 0, 0, 0, 0, 0, 0,
-    90, 0, 46, 22, 13, 111, 52, 20, 96, 24, 28, 74, 27, 123, 44, 66,
-    0, 45, 2, 4, 48, 0, 0, 21, 0, 0, 0, 0, 0, 120, 122, 67,
-};
-
-static const uint8_t e0_keycodes[128] = {
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 90, 76, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 109, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 68, 69, 70, 0, 91, 0, 93, 0, 112,
-    113, 114, 94, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    1, 3, 25, 26, 49, 52, 72, 73, 97, 99, 111, 118, 120, 122, 67, 0,
-};
-
-static void sunkbd_event(void *opaque, int ch)
-{
-    ChannelState *s = opaque;
-    int release = ch & 0x80;
-
-    trace_escc_sunkbd_event_in(ch);
-    switch (ch) {
-    case 58: // Caps lock press
-        s->caps_lock_mode ^= 1;
-        if (s->caps_lock_mode == 2)
-            return; // Drop second press
-        break;
-    case 69: // Num lock press
-        s->num_lock_mode ^= 1;
-        if (s->num_lock_mode == 2)
-            return; // Drop second press
-        break;
-    case 186: // Caps lock release
-        s->caps_lock_mode ^= 2;
-        if (s->caps_lock_mode == 3)
-            return; // Drop first release
-        break;
-    case 197: // Num lock release
-        s->num_lock_mode ^= 2;
-        if (s->num_lock_mode == 3)
-            return; // Drop first release
-        break;
-    case 0xe0:
-        s->e0_mode = 1;
-        return;
-    default:
-        break;
-    }
-    if (s->e0_mode) {
-        s->e0_mode = 0;
-        ch = e0_keycodes[ch & 0x7f];
-    } else {
-        ch = keycodes[ch & 0x7f];
-    }
-    trace_escc_sunkbd_event_out(ch);
-    put_queue(s, ch | release);
-}
-
-static void handle_kbd_command(ChannelState *s, int val)
-{
-    trace_escc_kbd_command(val);
-    if (s->led_mode) { // Ignore led byte
-        s->led_mode = 0;
-        return;
-    }
-    switch (val) {
-    case 1: // Reset, return type code
-        clear_queue(s);
-        put_queue(s, 0xff);
-        put_queue(s, 4); // Type 4
-        put_queue(s, 0x7f);
-        break;
-    case 0xe: // Set leds
-        s->led_mode = 1;
-        break;
-    case 7: // Query layout
-    case 0xf:
-        clear_queue(s);
-        put_queue(s, 0xfe);
-        put_queue(s, 0); // XXX, layout?
-        break;
-    default:
-        break;
-    }
-}
-
-static void sunmouse_event(void *opaque,
-                               int dx, int dy, int dz, int buttons_state)
-{
-    ChannelState *s = opaque;
-    int ch;
-
-    trace_escc_sunmouse_event(dx, dy, buttons_state);
-    ch = 0x80 | 0x7; /* protocol start byte, no buttons pressed */
-
-    if (buttons_state & MOUSE_EVENT_LBUTTON)
-        ch ^= 0x4;
-    if (buttons_state & MOUSE_EVENT_MBUTTON)
-        ch ^= 0x2;
-    if (buttons_state & MOUSE_EVENT_RBUTTON)
-        ch ^= 0x1;
-
-    put_queue(s, ch);
-
-    ch = dx;
-
-    if (ch > 127)
-        ch = 127;
-    else if (ch < -127)
-        ch = -127;
-
-    put_queue(s, ch & 0xff);
-
-    ch = -dy;
-
-    if (ch > 127)
-        ch = 127;
-    else if (ch < -127)
-        ch = -127;
-
-    put_queue(s, ch & 0xff);
-
-    // MSC protocol specify two extra motion bytes
-
-    put_queue(s, 0);
-    put_queue(s, 0);
-}
-
-void slavio_serial_ms_kbd_init(hwaddr base, qemu_irq irq,
-                               int disabled, int clock, int it_shift)
-{
-    DeviceState *dev;
-    SysBusDevice *s;
-
-    dev = qdev_create(NULL, "escc");
-    qdev_prop_set_uint32(dev, "disabled", disabled);
-    qdev_prop_set_uint32(dev, "frequency", clock);
-    qdev_prop_set_uint32(dev, "it_shift", it_shift);
-    qdev_prop_set_chr(dev, "chrB", NULL);
-    qdev_prop_set_chr(dev, "chrA", NULL);
-    qdev_prop_set_uint32(dev, "chnBtype", mouse);
-    qdev_prop_set_uint32(dev, "chnAtype", kbd);
-    qdev_init_nofail(dev);
-    s = SYS_BUS_DEVICE(dev);
-    sysbus_connect_irq(s, 0, irq);
-    sysbus_connect_irq(s, 1, irq);
-    sysbus_mmio_map(s, 0, base);
-}
-
-static int escc_init1(SysBusDevice *dev)
-{
-    SerialState *s = FROM_SYSBUS(SerialState, dev);
-    unsigned int i;
-
-    s->chn[0].disabled = s->disabled;
-    s->chn[1].disabled = s->disabled;
-    for (i = 0; i < 2; i++) {
-        sysbus_init_irq(dev, &s->chn[i].irq);
-        s->chn[i].chn = 1 - i;
-        s->chn[i].clock = s->frequency / 2;
-        if (s->chn[i].chr) {
-            qemu_chr_add_handlers(s->chn[i].chr, serial_can_receive,
-                                  serial_receive1, serial_event, &s->chn[i]);
-        }
-    }
-    s->chn[0].otherchn = &s->chn[1];
-    s->chn[1].otherchn = &s->chn[0];
-
-    memory_region_init_io(&s->mmio, &escc_mem_ops, s, "escc",
-                          ESCC_SIZE << s->it_shift);
-    sysbus_init_mmio(dev, &s->mmio);
-
-    if (s->chn[0].type == mouse) {
-        qemu_add_mouse_event_handler(sunmouse_event, &s->chn[0], 0,
-                                     "QEMU Sun Mouse");
-    }
-    if (s->chn[1].type == kbd) {
-        qemu_add_kbd_event_handler(sunkbd_event, &s->chn[1]);
-    }
-
-    return 0;
-}
-
-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("chnBtype",  SerialState, chn[0].type, 0),
-    DEFINE_PROP_UINT32("chnAtype",  SerialState, chn[1].type, 0),
-    DEFINE_PROP_CHR("chrB", SerialState, chn[0].chr),
-    DEFINE_PROP_CHR("chrA", SerialState, chn[1].chr),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void escc_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = escc_init1;
-    dc->reset = escc_reset;
-    dc->vmsd = &vmstate_escc;
-    dc->props = escc_properties;
-}
-
-static const TypeInfo escc_info = {
-    .name          = "escc",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(SerialState),
-    .class_init    = escc_class_init,
-};
-
-static void escc_register_types(void)
-{
-    type_register_static(&escc_info);
-}
-
-type_init(escc_register_types)
diff --git a/hw/escc.h b/hw/escc.h
deleted file mode 100644 (file)
index bda3213..0000000
--- a/hw/escc.h
+++ /dev/null
@@ -1,13 +0,0 @@
-#ifndef HW_ESCC_H
-#define HW_ESCC_H 1
-
-/* escc.c */
-#define ESCC_SIZE 4
-MemoryRegion *escc_init(hwaddr base, qemu_irq irqA, qemu_irq irqB,
-              CharDriverState *chrA, CharDriverState *chrB,
-              int clock, int it_shift);
-
-void slavio_serial_ms_kbd_init(hwaddr base, qemu_irq irq,
-                               int disabled, int clock, int it_shift);
-
-#endif
diff --git a/hw/esp-pci.c b/hw/esp-pci.c
deleted file mode 100644 (file)
index 7599b39..0000000
+++ /dev/null
@@ -1,518 +0,0 @@
-/*
- * QEMU ESP/NCR53C9x emulation
- *
- * Copyright (c) 2005-2006 Fabrice Bellard
- * Copyright (c) 2012 Herve 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 "hw/pci/pci.h"
-#include "hw/eeprom93xx.h"
-#include "hw/esp.h"
-#include "trace.h"
-#include "qemu/log.h"
-
-#define TYPE_AM53C974_DEVICE "am53c974"
-
-#define DMA_CMD   0x0
-#define DMA_STC   0x1
-#define DMA_SPA   0x2
-#define DMA_WBC   0x3
-#define DMA_WAC   0x4
-#define DMA_STAT  0x5
-#define DMA_SMDLA 0x6
-#define DMA_WMAC  0x7
-
-#define DMA_CMD_MASK   0x03
-#define DMA_CMD_DIAG   0x04
-#define DMA_CMD_MDL    0x10
-#define DMA_CMD_INTE_P 0x20
-#define DMA_CMD_INTE_D 0x40
-#define DMA_CMD_DIR    0x80
-
-#define DMA_STAT_PWDN    0x01
-#define DMA_STAT_ERROR   0x02
-#define DMA_STAT_ABORT   0x04
-#define DMA_STAT_DONE    0x08
-#define DMA_STAT_SCSIINT 0x10
-#define DMA_STAT_BCMBLT  0x20
-
-#define SBAC_STATUS 0x1000
-
-typedef struct PCIESPState {
-    PCIDevice dev;
-    MemoryRegion io;
-    uint32_t dma_regs[8];
-    uint32_t sbac;
-    ESPState esp;
-} PCIESPState;
-
-static void esp_pci_handle_idle(PCIESPState *pci, uint32_t val)
-{
-    trace_esp_pci_dma_idle(val);
-    esp_dma_enable(&pci->esp, 0, 0);
-}
-
-static void esp_pci_handle_blast(PCIESPState *pci, uint32_t val)
-{
-    trace_esp_pci_dma_blast(val);
-    qemu_log_mask(LOG_UNIMP, "am53c974: cmd BLAST not implemented\n");
-}
-
-static void esp_pci_handle_abort(PCIESPState *pci, uint32_t val)
-{
-    trace_esp_pci_dma_abort(val);
-    if (pci->esp.current_req) {
-        scsi_req_cancel(pci->esp.current_req);
-    }
-}
-
-static void esp_pci_handle_start(PCIESPState *pci, uint32_t val)
-{
-    trace_esp_pci_dma_start(val);
-
-    pci->dma_regs[DMA_WBC] = pci->dma_regs[DMA_STC];
-    pci->dma_regs[DMA_WAC] = pci->dma_regs[DMA_SPA];
-    pci->dma_regs[DMA_WMAC] = pci->dma_regs[DMA_SMDLA];
-
-    pci->dma_regs[DMA_STAT] &= ~(DMA_STAT_BCMBLT | DMA_STAT_SCSIINT
-                               | DMA_STAT_DONE | DMA_STAT_ABORT
-                               | DMA_STAT_ERROR | DMA_STAT_PWDN);
-
-    esp_dma_enable(&pci->esp, 0, 1);
-}
-
-static void esp_pci_dma_write(PCIESPState *pci, uint32_t saddr, uint32_t val)
-{
-    trace_esp_pci_dma_write(saddr, pci->dma_regs[saddr], val);
-    switch (saddr) {
-    case DMA_CMD:
-        pci->dma_regs[saddr] = val;
-        switch (val & DMA_CMD_MASK) {
-        case 0x0: /* IDLE */
-            esp_pci_handle_idle(pci, val);
-            break;
-        case 0x1: /* BLAST */
-            esp_pci_handle_blast(pci, val);
-            break;
-        case 0x2: /* ABORT */
-            esp_pci_handle_abort(pci, val);
-            break;
-        case 0x3: /* START */
-            esp_pci_handle_start(pci, val);
-            break;
-        default: /* can't happen */
-            abort();
-        }
-        break;
-    case DMA_STC:
-    case DMA_SPA:
-    case DMA_SMDLA:
-        pci->dma_regs[saddr] = val;
-        break;
-    case DMA_STAT:
-        if (!(pci->sbac & SBAC_STATUS)) {
-            /* clear some bits on write */
-            uint32_t mask = DMA_STAT_ERROR | DMA_STAT_ABORT | DMA_STAT_DONE;
-            pci->dma_regs[DMA_STAT] &= ~(val & mask);
-        }
-        break;
-    default:
-        trace_esp_pci_error_invalid_write_dma(val, saddr);
-        return;
-    }
-}
-
-static uint32_t esp_pci_dma_read(PCIESPState *pci, uint32_t saddr)
-{
-    uint32_t val;
-
-    val = pci->dma_regs[saddr];
-    if (saddr == DMA_STAT) {
-        if (pci->esp.rregs[ESP_RSTAT] & STAT_INT) {
-            val |= DMA_STAT_SCSIINT;
-        }
-        if (pci->sbac & SBAC_STATUS) {
-            pci->dma_regs[DMA_STAT] &= ~(DMA_STAT_ERROR | DMA_STAT_ABORT |
-                                         DMA_STAT_DONE);
-        }
-    }
-
-    trace_esp_pci_dma_read(saddr, val);
-    return val;
-}
-
-static void esp_pci_io_write(void *opaque, hwaddr addr,
-                             uint64_t val, unsigned int size)
-{
-    PCIESPState *pci = opaque;
-
-    if (size < 4 || addr & 3) {
-        /* need to upgrade request: we only support 4-bytes accesses */
-        uint32_t current = 0, mask;
-        int shift;
-
-        if (addr < 0x40) {
-            current = pci->esp.wregs[addr >> 2];
-        } else if (addr < 0x60) {
-            current = pci->dma_regs[(addr - 0x40) >> 2];
-        } else if (addr < 0x74) {
-            current = pci->sbac;
-        }
-
-        shift = (4 - size) * 8;
-        mask = (~(uint32_t)0 << shift) >> shift;
-
-        shift = ((4 - (addr & 3)) & 3) * 8;
-        val <<= shift;
-        val |= current & ~(mask << shift);
-        addr &= ~3;
-        size = 4;
-    }
-
-    if (addr < 0x40) {
-        /* SCSI core reg */
-        esp_reg_write(&pci->esp, addr >> 2, val);
-    } else if (addr < 0x60) {
-        /* PCI DMA CCB */
-        esp_pci_dma_write(pci, (addr - 0x40) >> 2, val);
-    } else if (addr == 0x70) {
-        /* DMA SCSI Bus and control */
-        trace_esp_pci_sbac_write(pci->sbac, val);
-        pci->sbac = val;
-    } else {
-        trace_esp_pci_error_invalid_write((int)addr);
-    }
-}
-
-static uint64_t esp_pci_io_read(void *opaque, hwaddr addr,
-                                unsigned int size)
-{
-    PCIESPState *pci = opaque;
-    uint32_t ret;
-
-    if (addr < 0x40) {
-        /* SCSI core reg */
-        ret = esp_reg_read(&pci->esp, addr >> 2);
-    } else if (addr < 0x60) {
-        /* PCI DMA CCB */
-        ret = esp_pci_dma_read(pci, (addr - 0x40) >> 2);
-    } else if (addr == 0x70) {
-        /* DMA SCSI Bus and control */
-        trace_esp_pci_sbac_read(pci->sbac);
-        ret = pci->sbac;
-    } else {
-        /* Invalid region */
-        trace_esp_pci_error_invalid_read((int)addr);
-        ret = 0;
-    }
-
-    /* give only requested data */
-    ret >>= (addr & 3) * 8;
-    ret &= ~(~(uint64_t)0 << (8 * size));
-
-    return ret;
-}
-
-static void esp_pci_dma_memory_rw(PCIESPState *pci, uint8_t *buf, int len,
-                                  DMADirection dir)
-{
-    dma_addr_t addr;
-    DMADirection expected_dir;
-
-    if (pci->dma_regs[DMA_CMD] & DMA_CMD_DIR) {
-        expected_dir = DMA_DIRECTION_FROM_DEVICE;
-    } else {
-        expected_dir = DMA_DIRECTION_TO_DEVICE;
-    }
-
-    if (dir != expected_dir) {
-        trace_esp_pci_error_invalid_dma_direction();
-        return;
-    }
-
-    if (pci->dma_regs[DMA_STAT] & DMA_CMD_MDL) {
-        qemu_log_mask(LOG_UNIMP, "am53c974: MDL transfer not implemented\n");
-    }
-
-    addr = pci->dma_regs[DMA_SPA];
-    if (pci->dma_regs[DMA_WBC] < len) {
-        len = pci->dma_regs[DMA_WBC];
-    }
-
-    pci_dma_rw(&pci->dev, addr, buf, len, dir);
-
-    /* update status registers */
-    pci->dma_regs[DMA_WBC] -= len;
-    pci->dma_regs[DMA_WAC] += len;
-}
-
-static void esp_pci_dma_memory_read(void *opaque, uint8_t *buf, int len)
-{
-    PCIESPState *pci = opaque;
-    esp_pci_dma_memory_rw(pci, buf, len, DMA_DIRECTION_TO_DEVICE);
-}
-
-static void esp_pci_dma_memory_write(void *opaque, uint8_t *buf, int len)
-{
-    PCIESPState *pci = opaque;
-    esp_pci_dma_memory_rw(pci, buf, len, DMA_DIRECTION_FROM_DEVICE);
-}
-
-static const MemoryRegionOps esp_pci_io_ops = {
-    .read = esp_pci_io_read,
-    .write = esp_pci_io_write,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-    .impl = {
-        .min_access_size = 1,
-        .max_access_size = 4,
-    },
-};
-
-static void esp_pci_hard_reset(DeviceState *dev)
-{
-    PCIESPState *pci = DO_UPCAST(PCIESPState, dev.qdev, dev);
-    esp_hard_reset(&pci->esp);
-    pci->dma_regs[DMA_CMD] &= ~(DMA_CMD_DIR | DMA_CMD_INTE_D | DMA_CMD_INTE_P
-                              | DMA_CMD_MDL | DMA_CMD_DIAG | DMA_CMD_MASK);
-    pci->dma_regs[DMA_WBC] &= ~0xffff;
-    pci->dma_regs[DMA_WAC] = 0xffffffff;
-    pci->dma_regs[DMA_STAT] &= ~(DMA_STAT_BCMBLT | DMA_STAT_SCSIINT
-                               | DMA_STAT_DONE | DMA_STAT_ABORT
-                               | DMA_STAT_ERROR);
-    pci->dma_regs[DMA_WMAC] = 0xfffffffd;
-}
-
-static const VMStateDescription vmstate_esp_pci_scsi = {
-    .name = "pciespscsi",
-    .version_id = 0,
-    .minimum_version_id = 0,
-    .minimum_version_id_old = 0,
-    .fields = (VMStateField[]) {
-        VMSTATE_PCI_DEVICE(dev, PCIESPState),
-        VMSTATE_BUFFER_UNSAFE(dma_regs, PCIESPState, 0, 8 * sizeof(uint32_t)),
-        VMSTATE_STRUCT(esp, PCIESPState, 0, vmstate_esp, ESPState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void esp_pci_command_complete(SCSIRequest *req, uint32_t status,
-                                     size_t resid)
-{
-    ESPState *s = req->hba_private;
-    PCIESPState *pci = container_of(s, PCIESPState, esp);
-
-    esp_command_complete(req, status, resid);
-    pci->dma_regs[DMA_WBC] = 0;
-    pci->dma_regs[DMA_STAT] |= DMA_STAT_DONE;
-}
-
-static const struct SCSIBusInfo esp_pci_scsi_info = {
-    .tcq = false,
-    .max_target = ESP_MAX_DEVS,
-    .max_lun = 7,
-
-    .transfer_data = esp_transfer_data,
-    .complete = esp_pci_command_complete,
-    .cancel = esp_request_cancelled,
-};
-
-static int esp_pci_scsi_init(PCIDevice *dev)
-{
-    PCIESPState *pci = DO_UPCAST(PCIESPState, dev, dev);
-    ESPState *s = &pci->esp;
-    uint8_t *pci_conf;
-
-    pci_conf = pci->dev.config;
-
-    /* Interrupt pin A */
-    pci_conf[PCI_INTERRUPT_PIN] = 0x01;
-
-    s->dma_memory_read = esp_pci_dma_memory_read;
-    s->dma_memory_write = esp_pci_dma_memory_write;
-    s->dma_opaque = pci;
-    s->chip_id = TCHI_AM53C974;
-    memory_region_init_io(&pci->io, &esp_pci_io_ops, pci, "esp-io", 0x80);
-
-    pci_register_bar(&pci->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &pci->io);
-    s->irq = pci->dev.irq[0];
-
-    scsi_bus_new(&s->bus, &dev->qdev, &esp_pci_scsi_info);
-    if (!dev->qdev.hotplugged) {
-        return scsi_bus_legacy_handle_cmdline(&s->bus);
-    }
-    return 0;
-}
-
-static void esp_pci_scsi_uninit(PCIDevice *d)
-{
-    PCIESPState *pci = DO_UPCAST(PCIESPState, dev, d);
-
-    memory_region_destroy(&pci->io);
-}
-
-static void esp_pci_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
-    k->init = esp_pci_scsi_init;
-    k->exit = esp_pci_scsi_uninit;
-    k->vendor_id = PCI_VENDOR_ID_AMD;
-    k->device_id = PCI_DEVICE_ID_AMD_SCSI;
-    k->revision = 0x10;
-    k->class_id = PCI_CLASS_STORAGE_SCSI;
-    dc->desc = "AMD Am53c974 PCscsi-PCI SCSI adapter";
-    dc->reset = esp_pci_hard_reset;
-    dc->vmsd = &vmstate_esp_pci_scsi;
-}
-
-static const TypeInfo esp_pci_info = {
-    .name = TYPE_AM53C974_DEVICE,
-    .parent = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(PCIESPState),
-    .class_init = esp_pci_class_init,
-};
-
-typedef struct {
-    PCIESPState pci;
-    eeprom_t *eeprom;
-} DC390State;
-
-#define TYPE_DC390_DEVICE "dc390"
-#define DC390(obj) \
-    OBJECT_CHECK(DC390State, obj, TYPE_DC390_DEVICE)
-
-#define EE_ADAPT_SCSI_ID 64
-#define EE_MODE2         65
-#define EE_DELAY         66
-#define EE_TAG_CMD_NUM   67
-#define EE_ADAPT_OPTIONS 68
-#define EE_BOOT_SCSI_ID  69
-#define EE_BOOT_SCSI_LUN 70
-#define EE_CHKSUM1       126
-#define EE_CHKSUM2       127
-
-#define EE_ADAPT_OPTION_F6_F8_AT_BOOT   0x01
-#define EE_ADAPT_OPTION_BOOT_FROM_CDROM 0x02
-#define EE_ADAPT_OPTION_INT13           0x04
-#define EE_ADAPT_OPTION_SCAM_SUPPORT    0x08
-
-
-static uint32_t dc390_read_config(PCIDevice *dev, uint32_t addr, int l)
-{
-    DC390State *pci = DC390(dev);
-    uint32_t val;
-
-    val = pci_default_read_config(dev, addr, l);
-
-    if (addr == 0x00 && l == 1) {
-        /* First byte of address space is AND-ed with EEPROM DO line */
-        if (!eeprom93xx_read(pci->eeprom)) {
-            val &= ~0xff;
-        }
-    }
-
-    return val;
-}
-
-static void dc390_write_config(PCIDevice *dev,
-                               uint32_t addr, uint32_t val, int l)
-{
-    DC390State *pci = DC390(dev);
-    if (addr == 0x80) {
-        /* EEPROM write */
-        int eesk = val & 0x80 ? 1 : 0;
-        int eedi = val & 0x40 ? 1 : 0;
-        eeprom93xx_write(pci->eeprom, 1, eesk, eedi);
-    } else if (addr == 0xc0) {
-        /* EEPROM CS low */
-        eeprom93xx_write(pci->eeprom, 0, 0, 0);
-    } else {
-        pci_default_write_config(dev, addr, val, l);
-    }
-}
-
-static int dc390_scsi_init(PCIDevice *dev)
-{
-    DC390State *pci = DC390(dev);
-    uint8_t *contents;
-    uint16_t chksum = 0;
-    int i, ret;
-
-    /* init base class */
-    ret = esp_pci_scsi_init(dev);
-    if (ret < 0) {
-        return ret;
-    }
-
-    /* EEPROM */
-    pci->eeprom = eeprom93xx_new(DEVICE(dev), 64);
-
-    /* set default eeprom values */
-    contents = (uint8_t *)eeprom93xx_data(pci->eeprom);
-
-    for (i = 0; i < 16; i++) {
-        contents[i * 2] = 0x57;
-        contents[i * 2 + 1] = 0x00;
-    }
-    contents[EE_ADAPT_SCSI_ID] = 7;
-    contents[EE_MODE2] = 0x0f;
-    contents[EE_TAG_CMD_NUM] = 0x04;
-    contents[EE_ADAPT_OPTIONS] = EE_ADAPT_OPTION_F6_F8_AT_BOOT
-                               | EE_ADAPT_OPTION_BOOT_FROM_CDROM
-                               | EE_ADAPT_OPTION_INT13;
-
-    /* update eeprom checksum */
-    for (i = 0; i < EE_CHKSUM1; i += 2) {
-        chksum += contents[i] + (((uint16_t)contents[i + 1]) << 8);
-    }
-    chksum = 0x1234 - chksum;
-    contents[EE_CHKSUM1] = chksum & 0xff;
-    contents[EE_CHKSUM2] = chksum >> 8;
-
-    return 0;
-}
-
-static void dc390_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
-    k->init = dc390_scsi_init;
-    k->config_read = dc390_read_config;
-    k->config_write = dc390_write_config;
-    dc->desc = "Tekram DC-390 SCSI adapter";
-}
-
-static const TypeInfo dc390_info = {
-    .name = "dc390",
-    .parent = TYPE_AM53C974_DEVICE,
-    .instance_size = sizeof(DC390State),
-    .class_init = dc390_class_init,
-};
-
-static void esp_pci_register_types(void)
-{
-    type_register_static(&esp_pci_info);
-    type_register_static(&dc390_info);
-}
-
-type_init(esp_pci_register_types)
diff --git a/hw/esp.c b/hw/esp.c
deleted file mode 100644 (file)
index 5365eac..0000000
--- a/hw/esp.c
+++ /dev/null
@@ -1,727 +0,0 @@
-/*
- * QEMU ESP/NCR53C9x emulation
- *
- * Copyright (c) 2005-2006 Fabrice Bellard
- * Copyright (c) 2012 Herve 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 "hw/sysbus.h"
-#include "hw/esp.h"
-#include "trace.h"
-#include "qemu/log.h"
-
-/*
- * On Sparc32, this is the ESP (NCR53C90) part of chip STP2000 (Master I/O),
- * also produced as NCR89C100. See
- * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C100.txt
- * and
- * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR53C9X.txt
- */
-
-static void esp_raise_irq(ESPState *s)
-{
-    if (!(s->rregs[ESP_RSTAT] & STAT_INT)) {
-        s->rregs[ESP_RSTAT] |= STAT_INT;
-        qemu_irq_raise(s->irq);
-        trace_esp_raise_irq();
-    }
-}
-
-static void esp_lower_irq(ESPState *s)
-{
-    if (s->rregs[ESP_RSTAT] & STAT_INT) {
-        s->rregs[ESP_RSTAT] &= ~STAT_INT;
-        qemu_irq_lower(s->irq);
-        trace_esp_lower_irq();
-    }
-}
-
-void esp_dma_enable(ESPState *s, int irq, int level)
-{
-    if (level) {
-        s->dma_enabled = 1;
-        trace_esp_dma_enable();
-        if (s->dma_cb) {
-            s->dma_cb(s);
-            s->dma_cb = NULL;
-        }
-    } else {
-        trace_esp_dma_disable();
-        s->dma_enabled = 0;
-    }
-}
-
-void esp_request_cancelled(SCSIRequest *req)
-{
-    ESPState *s = req->hba_private;
-
-    if (req == s->current_req) {
-        scsi_req_unref(s->current_req);
-        s->current_req = NULL;
-        s->current_dev = NULL;
-    }
-}
-
-static uint32_t get_cmd(ESPState *s, uint8_t *buf)
-{
-    uint32_t dmalen;
-    int target;
-
-    target = s->wregs[ESP_WBUSID] & BUSID_DID;
-    if (s->dma) {
-        dmalen = s->rregs[ESP_TCLO];
-        dmalen |= s->rregs[ESP_TCMID] << 8;
-        dmalen |= s->rregs[ESP_TCHI] << 16;
-        s->dma_memory_read(s->dma_opaque, buf, dmalen);
-    } else {
-        dmalen = s->ti_size;
-        memcpy(buf, s->ti_buf, dmalen);
-        buf[0] = buf[2] >> 5;
-    }
-    trace_esp_get_cmd(dmalen, target);
-
-    s->ti_size = 0;
-    s->ti_rptr = 0;
-    s->ti_wptr = 0;
-
-    if (s->current_req) {
-        /* Started a new command before the old one finished.  Cancel it.  */
-        scsi_req_cancel(s->current_req);
-        s->async_len = 0;
-    }
-
-    s->current_dev = scsi_device_find(&s->bus, 0, target, 0);
-    if (!s->current_dev) {
-        // No such drive
-        s->rregs[ESP_RSTAT] = 0;
-        s->rregs[ESP_RINTR] = INTR_DC;
-        s->rregs[ESP_RSEQ] = SEQ_0;
-        esp_raise_irq(s);
-        return 0;
-    }
-    return dmalen;
-}
-
-static void do_busid_cmd(ESPState *s, uint8_t *buf, uint8_t busid)
-{
-    int32_t datalen;
-    int lun;
-    SCSIDevice *current_lun;
-
-    trace_esp_do_busid_cmd(busid);
-    lun = busid & 7;
-    current_lun = scsi_device_find(&s->bus, 0, s->current_dev->id, lun);
-    s->current_req = scsi_req_new(current_lun, 0, lun, buf, s);
-    datalen = scsi_req_enqueue(s->current_req);
-    s->ti_size = datalen;
-    if (datalen != 0) {
-        s->rregs[ESP_RSTAT] = STAT_TC;
-        s->dma_left = 0;
-        s->dma_counter = 0;
-        if (datalen > 0) {
-            s->rregs[ESP_RSTAT] |= STAT_DI;
-        } else {
-            s->rregs[ESP_RSTAT] |= STAT_DO;
-        }
-        scsi_req_continue(s->current_req);
-    }
-    s->rregs[ESP_RINTR] = INTR_BS | INTR_FC;
-    s->rregs[ESP_RSEQ] = SEQ_CD;
-    esp_raise_irq(s);
-}
-
-static void do_cmd(ESPState *s, uint8_t *buf)
-{
-    uint8_t busid = buf[0];
-
-    do_busid_cmd(s, &buf[1], busid);
-}
-
-static void handle_satn(ESPState *s)
-{
-    uint8_t buf[32];
-    int len;
-
-    if (s->dma && !s->dma_enabled) {
-        s->dma_cb = handle_satn;
-        return;
-    }
-    len = get_cmd(s, buf);
-    if (len)
-        do_cmd(s, buf);
-}
-
-static void handle_s_without_atn(ESPState *s)
-{
-    uint8_t buf[32];
-    int len;
-
-    if (s->dma && !s->dma_enabled) {
-        s->dma_cb = handle_s_without_atn;
-        return;
-    }
-    len = get_cmd(s, buf);
-    if (len) {
-        do_busid_cmd(s, buf, 0);
-    }
-}
-
-static void handle_satn_stop(ESPState *s)
-{
-    if (s->dma && !s->dma_enabled) {
-        s->dma_cb = handle_satn_stop;
-        return;
-    }
-    s->cmdlen = get_cmd(s, s->cmdbuf);
-    if (s->cmdlen) {
-        trace_esp_handle_satn_stop(s->cmdlen);
-        s->do_cmd = 1;
-        s->rregs[ESP_RSTAT] = STAT_TC | STAT_CD;
-        s->rregs[ESP_RINTR] = INTR_BS | INTR_FC;
-        s->rregs[ESP_RSEQ] = SEQ_CD;
-        esp_raise_irq(s);
-    }
-}
-
-static void write_response(ESPState *s)
-{
-    trace_esp_write_response(s->status);
-    s->ti_buf[0] = s->status;
-    s->ti_buf[1] = 0;
-    if (s->dma) {
-        s->dma_memory_write(s->dma_opaque, s->ti_buf, 2);
-        s->rregs[ESP_RSTAT] = STAT_TC | STAT_ST;
-        s->rregs[ESP_RINTR] = INTR_BS | INTR_FC;
-        s->rregs[ESP_RSEQ] = SEQ_CD;
-    } else {
-        s->ti_size = 2;
-        s->ti_rptr = 0;
-        s->ti_wptr = 0;
-        s->rregs[ESP_RFLAGS] = 2;
-    }
-    esp_raise_irq(s);
-}
-
-static void esp_dma_done(ESPState *s)
-{
-    s->rregs[ESP_RSTAT] |= STAT_TC;
-    s->rregs[ESP_RINTR] = INTR_BS;
-    s->rregs[ESP_RSEQ] = 0;
-    s->rregs[ESP_RFLAGS] = 0;
-    s->rregs[ESP_TCLO] = 0;
-    s->rregs[ESP_TCMID] = 0;
-    s->rregs[ESP_TCHI] = 0;
-    esp_raise_irq(s);
-}
-
-static void esp_do_dma(ESPState *s)
-{
-    uint32_t len;
-    int to_device;
-
-    to_device = (s->ti_size < 0);
-    len = s->dma_left;
-    if (s->do_cmd) {
-        trace_esp_do_dma(s->cmdlen, len);
-        s->dma_memory_read(s->dma_opaque, &s->cmdbuf[s->cmdlen], len);
-        s->ti_size = 0;
-        s->cmdlen = 0;
-        s->do_cmd = 0;
-        do_cmd(s, s->cmdbuf);
-        return;
-    }
-    if (s->async_len == 0) {
-        /* Defer until data is available.  */
-        return;
-    }
-    if (len > s->async_len) {
-        len = s->async_len;
-    }
-    if (to_device) {
-        s->dma_memory_read(s->dma_opaque, s->async_buf, len);
-    } else {
-        s->dma_memory_write(s->dma_opaque, s->async_buf, len);
-    }
-    s->dma_left -= len;
-    s->async_buf += len;
-    s->async_len -= len;
-    if (to_device)
-        s->ti_size += len;
-    else
-        s->ti_size -= len;
-    if (s->async_len == 0) {
-        scsi_req_continue(s->current_req);
-        /* If there is still data to be read from the device then
-           complete the DMA operation immediately.  Otherwise defer
-           until the scsi layer has completed.  */
-        if (to_device || s->dma_left != 0 || s->ti_size == 0) {
-            return;
-        }
-    }
-
-    /* Partially filled a scsi buffer. Complete immediately.  */
-    esp_dma_done(s);
-}
-
-void esp_command_complete(SCSIRequest *req, uint32_t status,
-                                 size_t resid)
-{
-    ESPState *s = req->hba_private;
-
-    trace_esp_command_complete();
-    if (s->ti_size != 0) {
-        trace_esp_command_complete_unexpected();
-    }
-    s->ti_size = 0;
-    s->dma_left = 0;
-    s->async_len = 0;
-    if (status) {
-        trace_esp_command_complete_fail();
-    }
-    s->status = status;
-    s->rregs[ESP_RSTAT] = STAT_ST;
-    esp_dma_done(s);
-    if (s->current_req) {
-        scsi_req_unref(s->current_req);
-        s->current_req = NULL;
-        s->current_dev = NULL;
-    }
-}
-
-void esp_transfer_data(SCSIRequest *req, uint32_t len)
-{
-    ESPState *s = req->hba_private;
-
-    trace_esp_transfer_data(s->dma_left, s->ti_size);
-    s->async_len = len;
-    s->async_buf = scsi_req_get_buf(req);
-    if (s->dma_left) {
-        esp_do_dma(s);
-    } else if (s->dma_counter != 0 && s->ti_size <= 0) {
-        /* If this was the last part of a DMA transfer then the
-           completion interrupt is deferred to here.  */
-        esp_dma_done(s);
-    }
-}
-
-static void handle_ti(ESPState *s)
-{
-    uint32_t dmalen, minlen;
-
-    if (s->dma && !s->dma_enabled) {
-        s->dma_cb = handle_ti;
-        return;
-    }
-
-    dmalen = s->rregs[ESP_TCLO];
-    dmalen |= s->rregs[ESP_TCMID] << 8;
-    dmalen |= s->rregs[ESP_TCHI] << 16;
-    if (dmalen==0) {
-      dmalen=0x10000;
-    }
-    s->dma_counter = dmalen;
-
-    if (s->do_cmd)
-        minlen = (dmalen < 32) ? dmalen : 32;
-    else if (s->ti_size < 0)
-        minlen = (dmalen < -s->ti_size) ? dmalen : -s->ti_size;
-    else
-        minlen = (dmalen < s->ti_size) ? dmalen : s->ti_size;
-    trace_esp_handle_ti(minlen);
-    if (s->dma) {
-        s->dma_left = minlen;
-        s->rregs[ESP_RSTAT] &= ~STAT_TC;
-        esp_do_dma(s);
-    } else if (s->do_cmd) {
-        trace_esp_handle_ti_cmd(s->cmdlen);
-        s->ti_size = 0;
-        s->cmdlen = 0;
-        s->do_cmd = 0;
-        do_cmd(s, s->cmdbuf);
-        return;
-    }
-}
-
-void esp_hard_reset(ESPState *s)
-{
-    memset(s->rregs, 0, ESP_REGS);
-    memset(s->wregs, 0, ESP_REGS);
-    s->rregs[ESP_TCHI] = s->chip_id;
-    s->ti_size = 0;
-    s->ti_rptr = 0;
-    s->ti_wptr = 0;
-    s->dma = 0;
-    s->do_cmd = 0;
-    s->dma_cb = NULL;
-
-    s->rregs[ESP_CFG1] = 7;
-}
-
-static void esp_soft_reset(ESPState *s)
-{
-    qemu_irq_lower(s->irq);
-    esp_hard_reset(s);
-}
-
-static void parent_esp_reset(ESPState *s, int irq, int level)
-{
-    if (level) {
-        esp_soft_reset(s);
-    }
-}
-
-uint64_t esp_reg_read(ESPState *s, uint32_t saddr)
-{
-    uint32_t old_val;
-
-    trace_esp_mem_readb(saddr, s->rregs[saddr]);
-    switch (saddr) {
-    case ESP_FIFO:
-        if (s->ti_size > 0) {
-            s->ti_size--;
-            if ((s->rregs[ESP_RSTAT] & STAT_PIO_MASK) == 0) {
-                /* Data out.  */
-                qemu_log_mask(LOG_UNIMP,
-                              "esp: PIO data read not implemented\n");
-                s->rregs[ESP_FIFO] = 0;
-            } else {
-                s->rregs[ESP_FIFO] = s->ti_buf[s->ti_rptr++];
-            }
-            esp_raise_irq(s);
-        }
-        if (s->ti_size == 0) {
-            s->ti_rptr = 0;
-            s->ti_wptr = 0;
-        }
-        break;
-    case ESP_RINTR:
-        /* Clear sequence step, interrupt register and all status bits
-           except TC */
-        old_val = s->rregs[ESP_RINTR];
-        s->rregs[ESP_RINTR] = 0;
-        s->rregs[ESP_RSTAT] &= ~STAT_TC;
-        s->rregs[ESP_RSEQ] = SEQ_CD;
-        esp_lower_irq(s);
-
-        return old_val;
-    default:
-        break;
-    }
-    return s->rregs[saddr];
-}
-
-void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val)
-{
-    trace_esp_mem_writeb(saddr, s->wregs[saddr], val);
-    switch (saddr) {
-    case ESP_TCLO:
-    case ESP_TCMID:
-    case ESP_TCHI:
-        s->rregs[ESP_RSTAT] &= ~STAT_TC;
-        break;
-    case ESP_FIFO:
-        if (s->do_cmd) {
-            s->cmdbuf[s->cmdlen++] = val & 0xff;
-        } else if (s->ti_size == TI_BUFSZ - 1) {
-            trace_esp_error_fifo_overrun();
-        } else {
-            s->ti_size++;
-            s->ti_buf[s->ti_wptr++] = val & 0xff;
-        }
-        break;
-    case ESP_CMD:
-        s->rregs[saddr] = val;
-        if (val & CMD_DMA) {
-            s->dma = 1;
-            /* Reload DMA counter.  */
-            s->rregs[ESP_TCLO] = s->wregs[ESP_TCLO];
-            s->rregs[ESP_TCMID] = s->wregs[ESP_TCMID];
-            s->rregs[ESP_TCHI] = s->wregs[ESP_TCHI];
-        } else {
-            s->dma = 0;
-        }
-        switch(val & CMD_CMD) {
-        case CMD_NOP:
-            trace_esp_mem_writeb_cmd_nop(val);
-            break;
-        case CMD_FLUSH:
-            trace_esp_mem_writeb_cmd_flush(val);
-            //s->ti_size = 0;
-            s->rregs[ESP_RINTR] = INTR_FC;
-            s->rregs[ESP_RSEQ] = 0;
-            s->rregs[ESP_RFLAGS] = 0;
-            break;
-        case CMD_RESET:
-            trace_esp_mem_writeb_cmd_reset(val);
-            esp_soft_reset(s);
-            break;
-        case CMD_BUSRESET:
-            trace_esp_mem_writeb_cmd_bus_reset(val);
-            s->rregs[ESP_RINTR] = INTR_RST;
-            if (!(s->wregs[ESP_CFG1] & CFG1_RESREPT)) {
-                esp_raise_irq(s);
-            }
-            break;
-        case CMD_TI:
-            handle_ti(s);
-            break;
-        case CMD_ICCS:
-            trace_esp_mem_writeb_cmd_iccs(val);
-            write_response(s);
-            s->rregs[ESP_RINTR] = INTR_FC;
-            s->rregs[ESP_RSTAT] |= STAT_MI;
-            break;
-        case CMD_MSGACC:
-            trace_esp_mem_writeb_cmd_msgacc(val);
-            s->rregs[ESP_RINTR] = INTR_DC;
-            s->rregs[ESP_RSEQ] = 0;
-            s->rregs[ESP_RFLAGS] = 0;
-            esp_raise_irq(s);
-            break;
-        case CMD_PAD:
-            trace_esp_mem_writeb_cmd_pad(val);
-            s->rregs[ESP_RSTAT] = STAT_TC;
-            s->rregs[ESP_RINTR] = INTR_FC;
-            s->rregs[ESP_RSEQ] = 0;
-            break;
-        case CMD_SATN:
-            trace_esp_mem_writeb_cmd_satn(val);
-            break;
-        case CMD_RSTATN:
-            trace_esp_mem_writeb_cmd_rstatn(val);
-            break;
-        case CMD_SEL:
-            trace_esp_mem_writeb_cmd_sel(val);
-            handle_s_without_atn(s);
-            break;
-        case CMD_SELATN:
-            trace_esp_mem_writeb_cmd_selatn(val);
-            handle_satn(s);
-            break;
-        case CMD_SELATNS:
-            trace_esp_mem_writeb_cmd_selatns(val);
-            handle_satn_stop(s);
-            break;
-        case CMD_ENSEL:
-            trace_esp_mem_writeb_cmd_ensel(val);
-            s->rregs[ESP_RINTR] = 0;
-            break;
-        case CMD_DISSEL:
-            trace_esp_mem_writeb_cmd_dissel(val);
-            s->rregs[ESP_RINTR] = 0;
-            esp_raise_irq(s);
-            break;
-        default:
-            trace_esp_error_unhandled_command(val);
-            break;
-        }
-        break;
-    case ESP_WBUSID ... ESP_WSYNO:
-        break;
-    case ESP_CFG1:
-    case ESP_CFG2: case ESP_CFG3:
-    case ESP_RES3: case ESP_RES4:
-        s->rregs[saddr] = val;
-        break;
-    case ESP_WCCF ... ESP_WTEST:
-        break;
-    default:
-        trace_esp_error_invalid_write(val, saddr);
-        return;
-    }
-    s->wregs[saddr] = val;
-}
-
-static bool esp_mem_accepts(void *opaque, hwaddr addr,
-                            unsigned size, bool is_write)
-{
-    return (size == 1) || (is_write && size == 4);
-}
-
-const VMStateDescription vmstate_esp = {
-    .name ="esp",
-    .version_id = 3,
-    .minimum_version_id = 3,
-    .minimum_version_id_old = 3,
-    .fields      = (VMStateField []) {
-        VMSTATE_BUFFER(rregs, ESPState),
-        VMSTATE_BUFFER(wregs, ESPState),
-        VMSTATE_INT32(ti_size, ESPState),
-        VMSTATE_UINT32(ti_rptr, ESPState),
-        VMSTATE_UINT32(ti_wptr, ESPState),
-        VMSTATE_BUFFER(ti_buf, ESPState),
-        VMSTATE_UINT32(status, ESPState),
-        VMSTATE_UINT32(dma, ESPState),
-        VMSTATE_BUFFER(cmdbuf, ESPState),
-        VMSTATE_UINT32(cmdlen, ESPState),
-        VMSTATE_UINT32(do_cmd, ESPState),
-        VMSTATE_UINT32(dma_left, ESPState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-typedef struct {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-    uint32_t it_shift;
-    ESPState esp;
-} SysBusESPState;
-
-static void sysbus_esp_mem_write(void *opaque, hwaddr addr,
-                                 uint64_t val, unsigned int size)
-{
-    SysBusESPState *sysbus = opaque;
-    uint32_t saddr;
-
-    saddr = addr >> sysbus->it_shift;
-    esp_reg_write(&sysbus->esp, saddr, val);
-}
-
-static uint64_t sysbus_esp_mem_read(void *opaque, hwaddr addr,
-                                    unsigned int size)
-{
-    SysBusESPState *sysbus = opaque;
-    uint32_t saddr;
-
-    saddr = addr >> sysbus->it_shift;
-    return esp_reg_read(&sysbus->esp, saddr);
-}
-
-static const MemoryRegionOps sysbus_esp_mem_ops = {
-    .read = sysbus_esp_mem_read,
-    .write = sysbus_esp_mem_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid.accepts = esp_mem_accepts,
-};
-
-void esp_init(hwaddr espaddr, int it_shift,
-              ESPDMAMemoryReadWriteFunc dma_memory_read,
-              ESPDMAMemoryReadWriteFunc dma_memory_write,
-              void *dma_opaque, qemu_irq irq, qemu_irq *reset,
-              qemu_irq *dma_enable)
-{
-    DeviceState *dev;
-    SysBusDevice *s;
-    SysBusESPState *sysbus;
-    ESPState *esp;
-
-    dev = qdev_create(NULL, "esp");
-    sysbus = DO_UPCAST(SysBusESPState, busdev.qdev, dev);
-    esp = &sysbus->esp;
-    esp->dma_memory_read = dma_memory_read;
-    esp->dma_memory_write = dma_memory_write;
-    esp->dma_opaque = dma_opaque;
-    sysbus->it_shift = it_shift;
-    /* XXX for now until rc4030 has been changed to use DMA enable signal */
-    esp->dma_enabled = 1;
-    qdev_init_nofail(dev);
-    s = SYS_BUS_DEVICE(dev);
-    sysbus_connect_irq(s, 0, irq);
-    sysbus_mmio_map(s, 0, espaddr);
-    *reset = qdev_get_gpio_in(dev, 0);
-    *dma_enable = qdev_get_gpio_in(dev, 1);
-}
-
-static const struct SCSIBusInfo esp_scsi_info = {
-    .tcq = false,
-    .max_target = ESP_MAX_DEVS,
-    .max_lun = 7,
-
-    .transfer_data = esp_transfer_data,
-    .complete = esp_command_complete,
-    .cancel = esp_request_cancelled
-};
-
-static void sysbus_esp_gpio_demux(void *opaque, int irq, int level)
-{
-    DeviceState *d = opaque;
-    SysBusESPState *sysbus = container_of(d, SysBusESPState, busdev.qdev);
-    ESPState *s = &sysbus->esp;
-
-    switch (irq) {
-    case 0:
-        parent_esp_reset(s, irq, level);
-        break;
-    case 1:
-        esp_dma_enable(opaque, irq, level);
-        break;
-    }
-}
-
-static int sysbus_esp_init(SysBusDevice *dev)
-{
-    SysBusESPState *sysbus = FROM_SYSBUS(SysBusESPState, dev);
-    ESPState *s = &sysbus->esp;
-
-    sysbus_init_irq(dev, &s->irq);
-    assert(sysbus->it_shift != -1);
-
-    s->chip_id = TCHI_FAS100A;
-    memory_region_init_io(&sysbus->iomem, &sysbus_esp_mem_ops, sysbus,
-                          "esp", ESP_REGS << sysbus->it_shift);
-    sysbus_init_mmio(dev, &sysbus->iomem);
-
-    qdev_init_gpio_in(&dev->qdev, sysbus_esp_gpio_demux, 2);
-
-    scsi_bus_new(&s->bus, &dev->qdev, &esp_scsi_info);
-    return scsi_bus_legacy_handle_cmdline(&s->bus);
-}
-
-static void sysbus_esp_hard_reset(DeviceState *dev)
-{
-    SysBusESPState *sysbus = DO_UPCAST(SysBusESPState, busdev.qdev, dev);
-    esp_hard_reset(&sysbus->esp);
-}
-
-static const VMStateDescription vmstate_sysbus_esp_scsi = {
-    .name = "sysbusespscsi",
-    .version_id = 0,
-    .minimum_version_id = 0,
-    .minimum_version_id_old = 0,
-    .fields = (VMStateField[]) {
-        VMSTATE_STRUCT(esp, SysBusESPState, 0, vmstate_esp, ESPState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void sysbus_esp_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = sysbus_esp_init;
-    dc->reset = sysbus_esp_hard_reset;
-    dc->vmsd = &vmstate_sysbus_esp_scsi;
-}
-
-static const TypeInfo sysbus_esp_info = {
-    .name          = "esp",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(SysBusESPState),
-    .class_init    = sysbus_esp_class_init,
-};
-
-static void esp_register_types(void)
-{
-    type_register_static(&sysbus_esp_info);
-}
-
-type_init(esp_register_types)
diff --git a/hw/esp.h b/hw/esp.h
deleted file mode 100644 (file)
index 830673b..0000000
--- a/hw/esp.h
+++ /dev/null
@@ -1,132 +0,0 @@
-#ifndef QEMU_HW_ESP_H
-#define QEMU_HW_ESP_H
-
-#include "hw/scsi.h"
-
-/* esp.c */
-#define ESP_MAX_DEVS 7
-typedef void (*ESPDMAMemoryReadWriteFunc)(void *opaque, uint8_t *buf, int len);
-void esp_init(hwaddr espaddr, int it_shift,
-              ESPDMAMemoryReadWriteFunc dma_memory_read,
-              ESPDMAMemoryReadWriteFunc dma_memory_write,
-              void *dma_opaque, qemu_irq irq, qemu_irq *reset,
-              qemu_irq *dma_enable);
-
-#define ESP_REGS 16
-#define TI_BUFSZ 16
-
-typedef struct ESPState ESPState;
-
-struct ESPState {
-    uint8_t rregs[ESP_REGS];
-    uint8_t wregs[ESP_REGS];
-    qemu_irq irq;
-    uint8_t chip_id;
-    int32_t ti_size;
-    uint32_t ti_rptr, ti_wptr;
-    uint32_t status;
-    uint32_t dma;
-    uint8_t ti_buf[TI_BUFSZ];
-    SCSIBus bus;
-    SCSIDevice *current_dev;
-    SCSIRequest *current_req;
-    uint8_t cmdbuf[TI_BUFSZ];
-    uint32_t cmdlen;
-    uint32_t do_cmd;
-
-    /* The amount of data left in the current DMA transfer.  */
-    uint32_t dma_left;
-    /* The size of the current DMA transfer.  Zero if no transfer is in
-       progress.  */
-    uint32_t dma_counter;
-    int dma_enabled;
-
-    uint32_t async_len;
-    uint8_t *async_buf;
-
-    ESPDMAMemoryReadWriteFunc dma_memory_read;
-    ESPDMAMemoryReadWriteFunc dma_memory_write;
-    void *dma_opaque;
-    void (*dma_cb)(ESPState *s);
-};
-
-#define ESP_TCLO   0x0
-#define ESP_TCMID  0x1
-#define ESP_FIFO   0x2
-#define ESP_CMD    0x3
-#define ESP_RSTAT  0x4
-#define ESP_WBUSID 0x4
-#define ESP_RINTR  0x5
-#define ESP_WSEL   0x5
-#define ESP_RSEQ   0x6
-#define ESP_WSYNTP 0x6
-#define ESP_RFLAGS 0x7
-#define ESP_WSYNO  0x7
-#define ESP_CFG1   0x8
-#define ESP_RRES1  0x9
-#define ESP_WCCF   0x9
-#define ESP_RRES2  0xa
-#define ESP_WTEST  0xa
-#define ESP_CFG2   0xb
-#define ESP_CFG3   0xc
-#define ESP_RES3   0xd
-#define ESP_TCHI   0xe
-#define ESP_RES4   0xf
-
-#define CMD_DMA 0x80
-#define CMD_CMD 0x7f
-
-#define CMD_NOP      0x00
-#define CMD_FLUSH    0x01
-#define CMD_RESET    0x02
-#define CMD_BUSRESET 0x03
-#define CMD_TI       0x10
-#define CMD_ICCS     0x11
-#define CMD_MSGACC   0x12
-#define CMD_PAD      0x18
-#define CMD_SATN     0x1a
-#define CMD_RSTATN   0x1b
-#define CMD_SEL      0x41
-#define CMD_SELATN   0x42
-#define CMD_SELATNS  0x43
-#define CMD_ENSEL    0x44
-#define CMD_DISSEL   0x45
-
-#define STAT_DO 0x00
-#define STAT_DI 0x01
-#define STAT_CD 0x02
-#define STAT_ST 0x03
-#define STAT_MO 0x06
-#define STAT_MI 0x07
-#define STAT_PIO_MASK 0x06
-
-#define STAT_TC 0x10
-#define STAT_PE 0x20
-#define STAT_GE 0x40
-#define STAT_INT 0x80
-
-#define BUSID_DID 0x07
-
-#define INTR_FC 0x08
-#define INTR_BS 0x10
-#define INTR_DC 0x20
-#define INTR_RST 0x80
-
-#define SEQ_0 0x0
-#define SEQ_CD 0x4
-
-#define CFG1_RESREPT 0x40
-
-#define TCHI_FAS100A 0x4
-#define TCHI_AM53C974 0x12
-
-void esp_dma_enable(ESPState *s, int irq, int level);
-void esp_request_cancelled(SCSIRequest *req);
-void esp_command_complete(SCSIRequest *req, uint32_t status, size_t resid);
-void esp_transfer_data(SCSIRequest *req, uint32_t len);
-void esp_hard_reset(ESPState *s);
-uint64_t esp_reg_read(ESPState *s, uint32_t saddr);
-void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val);
-extern const VMStateDescription vmstate_esp;
-
-#endif
diff --git a/hw/etraxfs.h b/hw/etraxfs.h
deleted file mode 100644 (file)
index 0df4fdd..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * QEMU ETRAX System Emulator
- *
- * Copyright (c) 2008 Edgar E. Iglesias, Axis Communications AB.
- *
- * 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_EXTRAXFS_H
-#define HW_EXTRAXFS_H 1
-
-#include "net/net.h"
-#include "hw/etraxfs_dma.h"
-
-qemu_irq *cris_pic_init_cpu(CPUCRISState *env);
-
-/* Instantiate an ETRAXFS Ethernet MAC.  */
-static inline DeviceState *
-etraxfs_eth_init(NICInfo *nd, hwaddr base, int phyaddr,
-                 void *dma_out, void *dma_in)
-{
-    DeviceState *dev;
-    qemu_check_nic_model(nd, "fseth");
-
-    dev = qdev_create(NULL, "etraxfs-eth");
-    qdev_set_nic_properties(dev, nd);
-    qdev_prop_set_uint32(dev, "phyaddr", phyaddr);
-    qdev_prop_set_ptr(dev, "dma_out", dma_out);
-    qdev_prop_set_ptr(dev, "dma_in", dma_in);
-    qdev_init_nofail(dev);
-    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
-    return dev;
-}
-
-#endif
diff --git a/hw/etraxfs_dma.c b/hw/etraxfs_dma.c
deleted file mode 100644 (file)
index a84ec1f..0000000
+++ /dev/null
@@ -1,781 +0,0 @@
-/*
- * QEMU ETRAX DMA Controller.
- *
- * Copyright (c) 2008 Edgar E. Iglesias, Axis Communications AB.
- *
- * 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 <stdio.h>
-#include <sys/time.h>
-#include "hw/hw.h"
-#include "exec/address-spaces.h"
-#include "qemu-common.h"
-#include "sysemu/sysemu.h"
-
-#include "hw/etraxfs_dma.h"
-
-#define D(x)
-
-#define RW_DATA           (0x0 / 4)
-#define RW_SAVED_DATA     (0x58 / 4)
-#define RW_SAVED_DATA_BUF (0x5c / 4)
-#define RW_GROUP          (0x60 / 4)
-#define RW_GROUP_DOWN     (0x7c / 4)
-#define RW_CMD            (0x80 / 4)
-#define RW_CFG            (0x84 / 4)
-#define RW_STAT           (0x88 / 4)
-#define RW_INTR_MASK      (0x8c / 4)
-#define RW_ACK_INTR       (0x90 / 4)
-#define R_INTR            (0x94 / 4)
-#define R_MASKED_INTR     (0x98 / 4)
-#define RW_STREAM_CMD     (0x9c / 4)
-
-#define DMA_REG_MAX       (0x100 / 4)
-
-/* descriptors */
-
-// ------------------------------------------------------------ dma_descr_group
-typedef struct dma_descr_group {
-  uint32_t                      next;
-  unsigned                      eol        : 1;
-  unsigned                      tol        : 1;
-  unsigned                      bol        : 1;
-  unsigned                                 : 1;
-  unsigned                      intr       : 1;
-  unsigned                                 : 2;
-  unsigned                      en         : 1;
-  unsigned                                 : 7;
-  unsigned                      dis        : 1;
-  unsigned                      md         : 16;
-  struct dma_descr_group       *up;
-  union {
-    struct dma_descr_context   *context;
-    struct dma_descr_group     *group;
-  }                             down;
-} dma_descr_group;
-
-// ---------------------------------------------------------- dma_descr_context
-typedef struct dma_descr_context {
-  uint32_t                      next;
-  unsigned                      eol        : 1;
-  unsigned                                 : 3;
-  unsigned                      intr       : 1;
-  unsigned                                 : 1;
-  unsigned                      store_mode : 1;
-  unsigned                      en         : 1;
-  unsigned                                 : 7;
-  unsigned                      dis        : 1;
-  unsigned                      md0        : 16;
-  unsigned                      md1;
-  unsigned                      md2;
-  unsigned                      md3;
-  unsigned                      md4;
-  uint32_t                      saved_data;
-  uint32_t                      saved_data_buf;
-} dma_descr_context;
-
-// ------------------------------------------------------------- dma_descr_data
-typedef struct dma_descr_data {
-  uint32_t                      next;
-  uint32_t                      buf;
-  unsigned                      eol        : 1;
-  unsigned                                 : 2;
-  unsigned                      out_eop    : 1;
-  unsigned                      intr       : 1;
-  unsigned                      wait       : 1;
-  unsigned                                 : 2;
-  unsigned                                 : 3;
-  unsigned                      in_eop     : 1;
-  unsigned                                 : 4;
-  unsigned                      md         : 16;
-  uint32_t                      after;
-} dma_descr_data;
-
-/* Constants */
-enum {
-  regk_dma_ack_pkt                         = 0x00000100,
-  regk_dma_anytime                         = 0x00000001,
-  regk_dma_array                           = 0x00000008,
-  regk_dma_burst                           = 0x00000020,
-  regk_dma_client                          = 0x00000002,
-  regk_dma_copy_next                       = 0x00000010,
-  regk_dma_copy_up                         = 0x00000020,
-  regk_dma_data_at_eol                     = 0x00000001,
-  regk_dma_dis_c                           = 0x00000010,
-  regk_dma_dis_g                           = 0x00000020,
-  regk_dma_idle                            = 0x00000001,
-  regk_dma_intern                          = 0x00000004,
-  regk_dma_load_c                          = 0x00000200,
-  regk_dma_load_c_n                        = 0x00000280,
-  regk_dma_load_c_next                     = 0x00000240,
-  regk_dma_load_d                          = 0x00000140,
-  regk_dma_load_g                          = 0x00000300,
-  regk_dma_load_g_down                     = 0x000003c0,
-  regk_dma_load_g_next                     = 0x00000340,
-  regk_dma_load_g_up                       = 0x00000380,
-  regk_dma_next_en                         = 0x00000010,
-  regk_dma_next_pkt                        = 0x00000010,
-  regk_dma_no                              = 0x00000000,
-  regk_dma_only_at_wait                    = 0x00000000,
-  regk_dma_restore                         = 0x00000020,
-  regk_dma_rst                             = 0x00000001,
-  regk_dma_running                         = 0x00000004,
-  regk_dma_rw_cfg_default                  = 0x00000000,
-  regk_dma_rw_cmd_default                  = 0x00000000,
-  regk_dma_rw_intr_mask_default            = 0x00000000,
-  regk_dma_rw_stat_default                 = 0x00000101,
-  regk_dma_rw_stream_cmd_default           = 0x00000000,
-  regk_dma_save_down                       = 0x00000020,
-  regk_dma_save_up                         = 0x00000020,
-  regk_dma_set_reg                         = 0x00000050,
-  regk_dma_set_w_size1                     = 0x00000190,
-  regk_dma_set_w_size2                     = 0x000001a0,
-  regk_dma_set_w_size4                     = 0x000001c0,
-  regk_dma_stopped                         = 0x00000002,
-  regk_dma_store_c                         = 0x00000002,
-  regk_dma_store_descr                     = 0x00000000,
-  regk_dma_store_g                         = 0x00000004,
-  regk_dma_store_md                        = 0x00000001,
-  regk_dma_sw                              = 0x00000008,
-  regk_dma_update_down                     = 0x00000020,
-  regk_dma_yes                             = 0x00000001
-};
-
-enum dma_ch_state
-{
-       RST = 1,
-       STOPPED = 2,
-       RUNNING = 4
-};
-
-struct fs_dma_channel
-{
-       qemu_irq irq;
-       struct etraxfs_dma_client *client;
-
-       /* Internal status.  */
-       int stream_cmd_src;
-       enum dma_ch_state state;
-
-       unsigned int input : 1;
-       unsigned int eol : 1;
-
-       struct dma_descr_group current_g;
-       struct dma_descr_context current_c;
-       struct dma_descr_data current_d;
-
-       /* Control registers.  */
-       uint32_t regs[DMA_REG_MAX];
-};
-
-struct fs_dma_ctrl
-{
-       MemoryRegion mmio;
-       int nr_channels;
-       struct fs_dma_channel *channels;
-
-        QEMUBH *bh;
-};
-
-static void DMA_run(void *opaque);
-static int channel_out_run(struct fs_dma_ctrl *ctrl, int c);
-
-static inline uint32_t channel_reg(struct fs_dma_ctrl *ctrl, int c, int reg)
-{
-       return ctrl->channels[c].regs[reg];
-}
-
-static inline int channel_stopped(struct fs_dma_ctrl *ctrl, int c)
-{
-       return channel_reg(ctrl, c, RW_CFG) & 2;
-}
-
-static inline int channel_en(struct fs_dma_ctrl *ctrl, int c)
-{
-       return (channel_reg(ctrl, c, RW_CFG) & 1)
-               && ctrl->channels[c].client;
-}
-
-static inline int fs_channel(hwaddr addr)
-{
-       /* Every channel has a 0x2000 ctrl register map.  */
-       return addr >> 13;
-}
-
-#ifdef USE_THIS_DEAD_CODE
-static void channel_load_g(struct fs_dma_ctrl *ctrl, int c)
-{
-       hwaddr addr = channel_reg(ctrl, c, RW_GROUP);
-
-       /* Load and decode. FIXME: handle endianness.  */
-       cpu_physical_memory_read (addr, 
-                                 (void *) &ctrl->channels[c].current_g, 
-                                 sizeof ctrl->channels[c].current_g);
-}
-
-static void dump_c(int ch, struct dma_descr_context *c)
-{
-       printf("%s ch=%d\n", __func__, ch);
-       printf("next=%x\n", c->next);
-       printf("saved_data=%x\n", c->saved_data);
-       printf("saved_data_buf=%x\n", c->saved_data_buf);
-       printf("eol=%x\n", (uint32_t) c->eol);
-}
-
-static void dump_d(int ch, struct dma_descr_data *d)
-{
-       printf("%s ch=%d\n", __func__, ch);
-       printf("next=%x\n", d->next);
-       printf("buf=%x\n", d->buf);
-       printf("after=%x\n", d->after);
-       printf("intr=%x\n", (uint32_t) d->intr);
-       printf("out_eop=%x\n", (uint32_t) d->out_eop);
-       printf("in_eop=%x\n", (uint32_t) d->in_eop);
-       printf("eol=%x\n", (uint32_t) d->eol);
-}
-#endif
-
-static void channel_load_c(struct fs_dma_ctrl *ctrl, int c)
-{
-       hwaddr addr = channel_reg(ctrl, c, RW_GROUP_DOWN);
-
-       /* Load and decode. FIXME: handle endianness.  */
-       cpu_physical_memory_read (addr, 
-                                 (void *) &ctrl->channels[c].current_c, 
-                                 sizeof ctrl->channels[c].current_c);
-
-       D(dump_c(c, &ctrl->channels[c].current_c));
-       /* I guess this should update the current pos.  */
-       ctrl->channels[c].regs[RW_SAVED_DATA] =
-               (uint32_t)(unsigned long)ctrl->channels[c].current_c.saved_data;
-       ctrl->channels[c].regs[RW_SAVED_DATA_BUF] =
-               (uint32_t)(unsigned long)ctrl->channels[c].current_c.saved_data_buf;
-}
-
-static void channel_load_d(struct fs_dma_ctrl *ctrl, int c)
-{
-       hwaddr addr = channel_reg(ctrl, c, RW_SAVED_DATA);
-
-       /* Load and decode. FIXME: handle endianness.  */
-       D(printf("%s ch=%d addr=" TARGET_FMT_plx "\n", __func__, c, addr));
-       cpu_physical_memory_read (addr,
-                                 (void *) &ctrl->channels[c].current_d, 
-                                 sizeof ctrl->channels[c].current_d);
-
-       D(dump_d(c, &ctrl->channels[c].current_d));
-       ctrl->channels[c].regs[RW_DATA] = addr;
-}
-
-static void channel_store_c(struct fs_dma_ctrl *ctrl, int c)
-{
-       hwaddr addr = channel_reg(ctrl, c, RW_GROUP_DOWN);
-
-       /* Encode and store. FIXME: handle endianness.  */
-       D(printf("%s ch=%d addr=" TARGET_FMT_plx "\n", __func__, c, addr));
-       D(dump_d(c, &ctrl->channels[c].current_d));
-       cpu_physical_memory_write (addr,
-                                 (void *) &ctrl->channels[c].current_c,
-                                 sizeof ctrl->channels[c].current_c);
-}
-
-static void channel_store_d(struct fs_dma_ctrl *ctrl, int c)
-{
-       hwaddr addr = channel_reg(ctrl, c, RW_SAVED_DATA);
-
-       /* Encode and store. FIXME: handle endianness.  */
-       D(printf("%s ch=%d addr=" TARGET_FMT_plx "\n", __func__, c, addr));
-       cpu_physical_memory_write (addr,
-                                 (void *) &ctrl->channels[c].current_d, 
-                                 sizeof ctrl->channels[c].current_d);
-}
-
-static inline void channel_stop(struct fs_dma_ctrl *ctrl, int c)
-{
-       /* FIXME:  */
-}
-
-static inline void channel_start(struct fs_dma_ctrl *ctrl, int c)
-{
-       if (ctrl->channels[c].client)
-       {
-               ctrl->channels[c].eol = 0;
-               ctrl->channels[c].state = RUNNING;
-               if (!ctrl->channels[c].input)
-                       channel_out_run(ctrl, c);
-       } else
-               printf("WARNING: starting DMA ch %d with no client\n", c);
-
-        qemu_bh_schedule_idle(ctrl->bh);
-}
-
-static void channel_continue(struct fs_dma_ctrl *ctrl, int c)
-{
-       if (!channel_en(ctrl, c) 
-           || channel_stopped(ctrl, c)
-           || ctrl->channels[c].state != RUNNING
-           /* Only reload the current data descriptor if it has eol set.  */
-           || !ctrl->channels[c].current_d.eol) {
-               D(printf("continue failed ch=%d state=%d stopped=%d en=%d eol=%d\n", 
-                        c, ctrl->channels[c].state,
-                        channel_stopped(ctrl, c),
-                        channel_en(ctrl,c),
-                        ctrl->channels[c].eol));
-               D(dump_d(c, &ctrl->channels[c].current_d));
-               return;
-       }
-
-       /* Reload the current descriptor.  */
-       channel_load_d(ctrl, c);
-
-       /* If the current descriptor cleared the eol flag and we had already
-          reached eol state, do the continue.  */
-       if (!ctrl->channels[c].current_d.eol && ctrl->channels[c].eol) {
-               D(printf("continue %d ok %x\n", c,
-                        ctrl->channels[c].current_d.next));
-               ctrl->channels[c].regs[RW_SAVED_DATA] =
-                       (uint32_t)(unsigned long)ctrl->channels[c].current_d.next;
-               channel_load_d(ctrl, c);
-               ctrl->channels[c].regs[RW_SAVED_DATA_BUF] =
-                       (uint32_t)(unsigned long)ctrl->channels[c].current_d.buf;
-
-               channel_start(ctrl, c);
-       }
-       ctrl->channels[c].regs[RW_SAVED_DATA_BUF] =
-               (uint32_t)(unsigned long)ctrl->channels[c].current_d.buf;
-}
-
-static void channel_stream_cmd(struct fs_dma_ctrl *ctrl, int c, uint32_t v)
-{
-       unsigned int cmd = v & ((1 << 10) - 1);
-
-       D(printf("%s ch=%d cmd=%x\n",
-                __func__, c, cmd));
-       if (cmd & regk_dma_load_d) {
-               channel_load_d(ctrl, c);
-               if (cmd & regk_dma_burst)
-                       channel_start(ctrl, c);
-       }
-
-       if (cmd & regk_dma_load_c) {
-               channel_load_c(ctrl, c);
-       }
-}
-
-static void channel_update_irq(struct fs_dma_ctrl *ctrl, int c)
-{
-       D(printf("%s %d\n", __func__, c));
-        ctrl->channels[c].regs[R_INTR] &=
-               ~(ctrl->channels[c].regs[RW_ACK_INTR]);
-
-        ctrl->channels[c].regs[R_MASKED_INTR] =
-               ctrl->channels[c].regs[R_INTR]
-               & ctrl->channels[c].regs[RW_INTR_MASK];
-
-       D(printf("%s: chan=%d masked_intr=%x\n", __func__, 
-                c,
-                ctrl->channels[c].regs[R_MASKED_INTR]));
-
-        qemu_set_irq(ctrl->channels[c].irq,
-                    !!ctrl->channels[c].regs[R_MASKED_INTR]);
-}
-
-static int channel_out_run(struct fs_dma_ctrl *ctrl, int c)
-{
-       uint32_t len;
-       uint32_t saved_data_buf;
-       unsigned char buf[2 * 1024];
-
-       struct dma_context_metadata meta;
-       bool send_context = true;
-
-       if (ctrl->channels[c].eol)
-               return 0;
-
-       do {
-               bool out_eop;
-               D(printf("ch=%d buf=%x after=%x\n",
-                        c,
-                        (uint32_t)ctrl->channels[c].current_d.buf,
-                        (uint32_t)ctrl->channels[c].current_d.after));
-
-               if (send_context) {
-                       if (ctrl->channels[c].client->client.metadata_push) {
-                               meta.metadata = ctrl->channels[c].current_d.md;
-                               ctrl->channels[c].client->client.metadata_push(
-                                       ctrl->channels[c].client->client.opaque,
-                                       &meta);
-                       }
-                       send_context = false;
-               }
-
-               channel_load_d(ctrl, c);
-               saved_data_buf = channel_reg(ctrl, c, RW_SAVED_DATA_BUF);
-               len = (uint32_t)(unsigned long)
-                       ctrl->channels[c].current_d.after;
-               len -= saved_data_buf;
-
-               if (len > sizeof buf)
-                       len = sizeof buf;
-               cpu_physical_memory_read (saved_data_buf, buf, len);
-
-               out_eop = ((saved_data_buf + len) ==
-                          ctrl->channels[c].current_d.after) &&
-                       ctrl->channels[c].current_d.out_eop;
-
-               D(printf("channel %d pushes %x %u bytes eop=%u\n", c,
-                        saved_data_buf, len, out_eop));
-
-               if (ctrl->channels[c].client->client.push)
-                       ctrl->channels[c].client->client.push(
-                               ctrl->channels[c].client->client.opaque,
-                               buf, len, out_eop);
-               else
-                       printf("WARNING: DMA ch%d dataloss,"
-                              " no attached client.\n", c);
-
-               saved_data_buf += len;
-
-               if (saved_data_buf == (uint32_t)(unsigned long)
-                               ctrl->channels[c].current_d.after) {
-                       /* Done. Step to next.  */
-                       if (ctrl->channels[c].current_d.out_eop) {
-                               send_context = true;
-                       }
-                       if (ctrl->channels[c].current_d.intr) {
-                               /* data intr.  */
-                               D(printf("signal intr %d eol=%d\n",
-                                       len, ctrl->channels[c].current_d.eol));
-                               ctrl->channels[c].regs[R_INTR] |= (1 << 2);
-                               channel_update_irq(ctrl, c);
-                       }
-                       channel_store_d(ctrl, c);
-                       if (ctrl->channels[c].current_d.eol) {
-                               D(printf("channel %d EOL\n", c));
-                               ctrl->channels[c].eol = 1;
-
-                               /* Mark the context as disabled.  */
-                               ctrl->channels[c].current_c.dis = 1;
-                               channel_store_c(ctrl, c);
-
-                               channel_stop(ctrl, c);
-                       } else {
-                               ctrl->channels[c].regs[RW_SAVED_DATA] =
-                                       (uint32_t)(unsigned long)ctrl->
-                                               channels[c].current_d.next;
-                               /* Load new descriptor.  */
-                               channel_load_d(ctrl, c);
-                               saved_data_buf = (uint32_t)(unsigned long)
-                                       ctrl->channels[c].current_d.buf;
-                       }
-
-                       ctrl->channels[c].regs[RW_SAVED_DATA_BUF] =
-                                                       saved_data_buf;
-                       D(dump_d(c, &ctrl->channels[c].current_d));
-               }
-               ctrl->channels[c].regs[RW_SAVED_DATA_BUF] = saved_data_buf;
-       } while (!ctrl->channels[c].eol);
-       return 1;
-}
-
-static int channel_in_process(struct fs_dma_ctrl *ctrl, int c, 
-                             unsigned char *buf, int buflen, int eop)
-{
-       uint32_t len;
-       uint32_t saved_data_buf;
-
-       if (ctrl->channels[c].eol == 1)
-               return 0;
-
-       channel_load_d(ctrl, c);
-       saved_data_buf = channel_reg(ctrl, c, RW_SAVED_DATA_BUF);
-       len = (uint32_t)(unsigned long)ctrl->channels[c].current_d.after;
-       len -= saved_data_buf;
-       
-       if (len > buflen)
-               len = buflen;
-
-       cpu_physical_memory_write (saved_data_buf, buf, len);
-       saved_data_buf += len;
-
-       if (saved_data_buf ==
-           (uint32_t)(unsigned long)ctrl->channels[c].current_d.after
-           || eop) {
-               uint32_t r_intr = ctrl->channels[c].regs[R_INTR];
-
-               D(printf("in dscr end len=%d\n", 
-                        ctrl->channels[c].current_d.after
-                        - ctrl->channels[c].current_d.buf));
-               ctrl->channels[c].current_d.after = saved_data_buf;
-
-               /* Done. Step to next.  */
-               if (ctrl->channels[c].current_d.intr) {
-                       /* TODO: signal eop to the client.  */
-                       /* data intr.  */
-                       ctrl->channels[c].regs[R_INTR] |= 3;
-               }
-               if (eop) {
-                       ctrl->channels[c].current_d.in_eop = 1;
-                       ctrl->channels[c].regs[R_INTR] |= 8;
-               }
-               if (r_intr != ctrl->channels[c].regs[R_INTR])
-                       channel_update_irq(ctrl, c);
-
-               channel_store_d(ctrl, c);
-               D(dump_d(c, &ctrl->channels[c].current_d));
-
-               if (ctrl->channels[c].current_d.eol) {
-                       D(printf("channel %d EOL\n", c));
-                       ctrl->channels[c].eol = 1;
-
-                       /* Mark the context as disabled.  */
-                       ctrl->channels[c].current_c.dis = 1;
-                       channel_store_c(ctrl, c);
-
-                       channel_stop(ctrl, c);
-               } else {
-                       ctrl->channels[c].regs[RW_SAVED_DATA] =
-                               (uint32_t)(unsigned long)ctrl->
-                                       channels[c].current_d.next;
-                       /* Load new descriptor.  */
-                       channel_load_d(ctrl, c);
-                       saved_data_buf = (uint32_t)(unsigned long)
-                               ctrl->channels[c].current_d.buf;
-               }
-       }
-
-       ctrl->channels[c].regs[RW_SAVED_DATA_BUF] = saved_data_buf;
-       return len;
-}
-
-static inline int channel_in_run(struct fs_dma_ctrl *ctrl, int c)
-{
-       if (ctrl->channels[c].client->client.pull) {
-               ctrl->channels[c].client->client.pull(
-                       ctrl->channels[c].client->client.opaque);
-               return 1;
-       } else
-               return 0;
-}
-
-static uint32_t dma_rinvalid (void *opaque, hwaddr addr)
-{
-        hw_error("Unsupported short raccess. reg=" TARGET_FMT_plx "\n", addr);
-        return 0;
-}
-
-static uint64_t
-dma_read(void *opaque, hwaddr addr, unsigned int size)
-{
-        struct fs_dma_ctrl *ctrl = opaque;
-       int c;
-       uint32_t r = 0;
-
-       if (size != 4) {
-               dma_rinvalid(opaque, addr);
-       }
-
-       /* Make addr relative to this channel and bounded to nr regs.  */
-       c = fs_channel(addr);
-       addr &= 0xff;
-       addr >>= 2;
-       switch (addr)
-       {
-               case RW_STAT:
-                       r = ctrl->channels[c].state & 7;
-                       r |= ctrl->channels[c].eol << 5;
-                       r |= ctrl->channels[c].stream_cmd_src << 8;
-                       break;
-
-               default:
-                       r = ctrl->channels[c].regs[addr];
-                       D(printf ("%s c=%d addr=" TARGET_FMT_plx "\n",
-                                 __func__, c, addr));
-                       break;
-       }
-       return r;
-}
-
-static void
-dma_winvalid (void *opaque, hwaddr addr, uint32_t value)
-{
-        hw_error("Unsupported short waccess. reg=" TARGET_FMT_plx "\n", addr);
-}
-
-static void
-dma_update_state(struct fs_dma_ctrl *ctrl, int c)
-{
-       if (ctrl->channels[c].regs[RW_CFG] & 2)
-               ctrl->channels[c].state = STOPPED;
-       if (!(ctrl->channels[c].regs[RW_CFG] & 1))
-               ctrl->channels[c].state = RST;
-}
-
-static void
-dma_write(void *opaque, hwaddr addr,
-         uint64_t val64, unsigned int size)
-{
-        struct fs_dma_ctrl *ctrl = opaque;
-       uint32_t value = val64;
-       int c;
-
-       if (size != 4) {
-               dma_winvalid(opaque, addr, value);
-       }
-
-        /* Make addr relative to this channel and bounded to nr regs.  */
-       c = fs_channel(addr);
-        addr &= 0xff;
-        addr >>= 2;
-        switch (addr)
-       {
-               case RW_DATA:
-                       ctrl->channels[c].regs[addr] = value;
-                       break;
-
-               case RW_CFG:
-                       ctrl->channels[c].regs[addr] = value;
-                       dma_update_state(ctrl, c);
-                       break;
-               case RW_CMD:
-                       /* continue.  */
-                       if (value & ~1)
-                               printf("Invalid store to ch=%d RW_CMD %x\n",
-                                      c, value);
-                       ctrl->channels[c].regs[addr] = value;
-                       channel_continue(ctrl, c);
-                       break;
-
-               case RW_SAVED_DATA:
-               case RW_SAVED_DATA_BUF:
-               case RW_GROUP:
-               case RW_GROUP_DOWN:
-                       ctrl->channels[c].regs[addr] = value;
-                       break;
-
-               case RW_ACK_INTR:
-               case RW_INTR_MASK:
-                       ctrl->channels[c].regs[addr] = value;
-                       channel_update_irq(ctrl, c);
-                       if (addr == RW_ACK_INTR)
-                               ctrl->channels[c].regs[RW_ACK_INTR] = 0;
-                       break;
-
-               case RW_STREAM_CMD:
-                       if (value & ~1023)
-                               printf("Invalid store to ch=%d "
-                                      "RW_STREAMCMD %x\n",
-                                      c, value);
-                       ctrl->channels[c].regs[addr] = value;
-                       D(printf("stream_cmd ch=%d\n", c));
-                       channel_stream_cmd(ctrl, c, value);
-                       break;
-
-               default:
-                       D(printf ("%s c=%d " TARGET_FMT_plx "\n",
-                               __func__, c, addr));
-                       break;
-        }
-}
-
-static const MemoryRegionOps dma_ops = {
-       .read = dma_read,
-       .write = dma_write,
-       .endianness = DEVICE_NATIVE_ENDIAN,
-       .valid = {
-               .min_access_size = 1,
-               .max_access_size = 4
-       }
-};
-
-static int etraxfs_dmac_run(void *opaque)
-{
-       struct fs_dma_ctrl *ctrl = opaque;
-       int i;
-       int p = 0;
-
-       for (i = 0; 
-            i < ctrl->nr_channels;
-            i++)
-       {
-               if (ctrl->channels[i].state == RUNNING)
-               {
-                       if (ctrl->channels[i].input) {
-                               p += channel_in_run(ctrl, i);
-                       } else {
-                               p += channel_out_run(ctrl, i);
-                       }
-               }
-       }
-       return p;
-}
-
-int etraxfs_dmac_input(struct etraxfs_dma_client *client, 
-                      void *buf, int len, int eop)
-{
-       return channel_in_process(client->ctrl, client->channel, 
-                                 buf, len, eop);
-}
-
-/* Connect an IRQ line with a channel.  */
-void etraxfs_dmac_connect(void *opaque, int c, qemu_irq *line, int input)
-{
-       struct fs_dma_ctrl *ctrl = opaque;
-       ctrl->channels[c].irq = *line;
-       ctrl->channels[c].input = input;
-}
-
-void etraxfs_dmac_connect_client(void *opaque, int c, 
-                                struct etraxfs_dma_client *cl)
-{
-       struct fs_dma_ctrl *ctrl = opaque;
-       cl->ctrl = ctrl;
-       cl->channel = c;
-       ctrl->channels[c].client = cl;
-}
-
-
-static void DMA_run(void *opaque)
-{
-    struct fs_dma_ctrl *etraxfs_dmac = opaque;
-    int p = 1;
-
-    if (runstate_is_running())
-        p = etraxfs_dmac_run(etraxfs_dmac);
-
-    if (p)
-        qemu_bh_schedule_idle(etraxfs_dmac->bh);
-}
-
-void *etraxfs_dmac_init(hwaddr base, int nr_channels)
-{
-       struct fs_dma_ctrl *ctrl = NULL;
-
-       ctrl = g_malloc0(sizeof *ctrl);
-
-        ctrl->bh = qemu_bh_new(DMA_run, ctrl);
-
-       ctrl->nr_channels = nr_channels;
-       ctrl->channels = g_malloc0(sizeof ctrl->channels[0] * nr_channels);
-
-       memory_region_init_io(&ctrl->mmio, &dma_ops, ctrl, "etraxfs-dma",
-                             nr_channels * 0x2000);
-       memory_region_add_subregion(get_system_memory(), base, &ctrl->mmio);
-
-       return ctrl;
-}
diff --git a/hw/etraxfs_dma.h b/hw/etraxfs_dma.h
deleted file mode 100644 (file)
index 38104a6..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-#ifndef HW_ETRAXFS_DMA_H
-#define HW_ETRAXFS_DMA_H 1
-
-struct dma_context_metadata {
-       /* data descriptor md */
-       uint16_t metadata;
-};
-
-struct etraxfs_dma_client
-{
-       /* DMA controller. */
-       int channel;
-       void *ctrl;
-
-       /* client.  */
-       struct {
-               int (*push)(void *opaque, unsigned char *buf,
-                           int len, bool eop);
-               void (*pull)(void *opaque);
-               void (*metadata_push)(void *opaque,
-                                     const struct dma_context_metadata *md);
-               void *opaque;
-       } client;
-};
-
-void *etraxfs_dmac_init(hwaddr base, int nr_channels);
-void etraxfs_dmac_connect(void *opaque, int channel, qemu_irq *line,
-                         int input);
-void etraxfs_dmac_connect_client(void *opaque, int c, 
-                                struct etraxfs_dma_client *cl);
-int etraxfs_dmac_input(struct etraxfs_dma_client *client, 
-                      void *buf, int len, int eop);
-
-#endif
diff --git a/hw/etraxfs_eth.c b/hw/etraxfs_eth.c
deleted file mode 100644 (file)
index 591bee2..0000000
+++ /dev/null
@@ -1,656 +0,0 @@
-/*
- * QEMU ETRAX Ethernet Controller.
- *
- * Copyright (c) 2008 Edgar E. Iglesias, Axis Communications AB.
- *
- * 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 <stdio.h>
-#include "hw/sysbus.h"
-#include "net/net.h"
-#include "hw/etraxfs.h"
-
-#define D(x)
-
-/* Advertisement control register. */
-#define ADVERTISE_10HALF        0x0020  /* Try for 10mbps half-duplex  */
-#define ADVERTISE_10FULL        0x0040  /* Try for 10mbps full-duplex  */
-#define ADVERTISE_100HALF       0x0080  /* Try for 100mbps half-duplex */
-#define ADVERTISE_100FULL       0x0100  /* Try for 100mbps full-duplex */
-
-/*
- * The MDIO extensions in the TDK PHY model were reversed engineered from the
- * linux driver (PHYID and Diagnostics reg).
- * TODO: Add friendly names for the register nums.
- */
-struct qemu_phy
-{
-    uint32_t regs[32];
-
-    int link;
-
-    unsigned int (*read)(struct qemu_phy *phy, unsigned int req);
-    void (*write)(struct qemu_phy *phy, unsigned int req, unsigned int data);
-};
-
-static unsigned int tdk_read(struct qemu_phy *phy, unsigned int req)
-{
-    int regnum;
-    unsigned r = 0;
-
-    regnum = req & 0x1f;
-
-    switch (regnum) {
-    case 1:
-        if (!phy->link) {
-            break;
-        }
-        /* MR1.     */
-        /* Speeds and modes.  */
-        r |= (1 << 13) | (1 << 14);
-        r |= (1 << 11) | (1 << 12);
-        r |= (1 << 5); /* Autoneg complete.  */
-        r |= (1 << 3); /* Autoneg able.     */
-        r |= (1 << 2); /* link.     */
-        break;
-    case 5:
-        /* Link partner ability.
-           We are kind; always agree with whatever best mode
-           the guest advertises.  */
-        r = 1 << 14; /* Success.  */
-        /* Copy advertised modes.  */
-        r |= phy->regs[4] & (15 << 5);
-        /* Autoneg support.  */
-        r |= 1;
-        break;
-    case 18:
-    {
-        /* Diagnostics reg.  */
-        int duplex = 0;
-        int speed_100 = 0;
-
-        if (!phy->link) {
-            break;
-        }
-
-        /* Are we advertising 100 half or 100 duplex ? */
-        speed_100 = !!(phy->regs[4] & ADVERTISE_100HALF);
-        speed_100 |= !!(phy->regs[4] & ADVERTISE_100FULL);
-
-        /* Are we advertising 10 duplex or 100 duplex ? */
-        duplex = !!(phy->regs[4] & ADVERTISE_100FULL);
-        duplex |= !!(phy->regs[4] & ADVERTISE_10FULL);
-        r = (speed_100 << 10) | (duplex << 11);
-    }
-    break;
-
-    default:
-        r = phy->regs[regnum];
-        break;
-    }
-    D(printf("\n%s %x = reg[%d]\n", __func__, r, regnum));
-    return r;
-}
-
-static void
-tdk_write(struct qemu_phy *phy, unsigned int req, unsigned int data)
-{
-    int regnum;
-
-    regnum = req & 0x1f;
-    D(printf("%s reg[%d] = %x\n", __func__, regnum, data));
-    switch (regnum) {
-    default:
-        phy->regs[regnum] = data;
-        break;
-    }
-}
-
-static void
-tdk_init(struct qemu_phy *phy)
-{
-    phy->regs[0] = 0x3100;
-    /* PHY Id.  */
-    phy->regs[2] = 0x0300;
-    phy->regs[3] = 0xe400;
-    /* Autonegotiation advertisement reg.  */
-    phy->regs[4] = 0x01E1;
-    phy->link = 1;
-
-    phy->read = tdk_read;
-    phy->write = tdk_write;
-}
-
-struct qemu_mdio
-{
-    /* bus.     */
-    int mdc;
-    int mdio;
-
-    /* decoder.  */
-    enum {
-        PREAMBLE,
-        SOF,
-        OPC,
-        ADDR,
-        REQ,
-        TURNAROUND,
-        DATA
-    } state;
-    unsigned int drive;
-
-    unsigned int cnt;
-    unsigned int addr;
-    unsigned int opc;
-    unsigned int req;
-    unsigned int data;
-
-    struct qemu_phy *devs[32];
-};
-
-static void
-mdio_attach(struct qemu_mdio *bus, struct qemu_phy *phy, unsigned int addr)
-{
-    bus->devs[addr & 0x1f] = phy;
-}
-
-#ifdef USE_THIS_DEAD_CODE
-static void
-mdio_detach(struct qemu_mdio *bus, struct qemu_phy *phy, unsigned int addr)
-{
-    bus->devs[addr & 0x1f] = NULL;
-}
-#endif
-
-static void mdio_read_req(struct qemu_mdio *bus)
-{
-    struct qemu_phy *phy;
-
-    phy = bus->devs[bus->addr];
-    if (phy && phy->read) {
-        bus->data = phy->read(phy, bus->req);
-    } else {
-        bus->data = 0xffff;
-    }
-}
-
-static void mdio_write_req(struct qemu_mdio *bus)
-{
-    struct qemu_phy *phy;
-
-    phy = bus->devs[bus->addr];
-    if (phy && phy->write) {
-        phy->write(phy, bus->req, bus->data);
-    }
-}
-
-static void mdio_cycle(struct qemu_mdio *bus)
-{
-    bus->cnt++;
-
-    D(printf("mdc=%d mdio=%d state=%d cnt=%d drv=%d\n",
-        bus->mdc, bus->mdio, bus->state, bus->cnt, bus->drive));
-#if 0
-    if (bus->mdc) {
-        printf("%d", bus->mdio);
-    }
-#endif
-    switch (bus->state) {
-    case PREAMBLE:
-        if (bus->mdc) {
-            if (bus->cnt >= (32 * 2) && !bus->mdio) {
-                bus->cnt = 0;
-                bus->state = SOF;
-                bus->data = 0;
-            }
-        }
-        break;
-    case SOF:
-        if (bus->mdc) {
-            if (bus->mdio != 1) {
-                printf("WARNING: no SOF\n");
-            }
-            if (bus->cnt == 1*2) {
-                bus->cnt = 0;
-                bus->opc = 0;
-                bus->state = OPC;
-            }
-        }
-        break;
-    case OPC:
-        if (bus->mdc) {
-            bus->opc <<= 1;
-            bus->opc |= bus->mdio & 1;
-            if (bus->cnt == 2*2) {
-                bus->cnt = 0;
-                bus->addr = 0;
-                bus->state = ADDR;
-            }
-        }
-        break;
-    case ADDR:
-        if (bus->mdc) {
-            bus->addr <<= 1;
-            bus->addr |= bus->mdio & 1;
-
-            if (bus->cnt == 5*2) {
-                bus->cnt = 0;
-                bus->req = 0;
-                bus->state = REQ;
-            }
-        }
-        break;
-    case REQ:
-        if (bus->mdc) {
-            bus->req <<= 1;
-            bus->req |= bus->mdio & 1;
-            if (bus->cnt == 5*2) {
-                bus->cnt = 0;
-                bus->state = TURNAROUND;
-            }
-        }
-        break;
-    case TURNAROUND:
-        if (bus->mdc && bus->cnt == 2*2) {
-            bus->mdio = 0;
-            bus->cnt = 0;
-
-            if (bus->opc == 2) {
-                bus->drive = 1;
-                mdio_read_req(bus);
-                bus->mdio = bus->data & 1;
-            }
-            bus->state = DATA;
-        }
-        break;
-    case DATA:
-        if (!bus->mdc) {
-            if (bus->drive) {
-                bus->mdio = !!(bus->data & (1 << 15));
-                bus->data <<= 1;
-            }
-        } else {
-            if (!bus->drive) {
-                bus->data <<= 1;
-                bus->data |= bus->mdio;
-            }
-            if (bus->cnt == 16 * 2) {
-                bus->cnt = 0;
-                bus->state = PREAMBLE;
-                if (!bus->drive) {
-                    mdio_write_req(bus);
-                }
-                bus->drive = 0;
-            }
-        }
-        break;
-    default:
-        break;
-    }
-}
-
-/* ETRAX-FS Ethernet MAC block starts here.  */
-
-#define RW_MA0_LO      0x00
-#define RW_MA0_HI      0x01
-#define RW_MA1_LO      0x02
-#define RW_MA1_HI      0x03
-#define RW_GA_LO      0x04
-#define RW_GA_HI      0x05
-#define RW_GEN_CTRL      0x06
-#define RW_REC_CTRL      0x07
-#define RW_TR_CTRL      0x08
-#define RW_CLR_ERR      0x09
-#define RW_MGM_CTRL      0x0a
-#define R_STAT          0x0b
-#define FS_ETH_MAX_REGS      0x17
-
-struct fs_eth
-{
-    SysBusDevice busdev;
-    MemoryRegion mmio;
-    NICState *nic;
-    NICConf conf;
-
-    /* Two addrs in the filter.  */
-    uint8_t macaddr[2][6];
-    uint32_t regs[FS_ETH_MAX_REGS];
-
-    union {
-        void *vdma_out;
-        struct etraxfs_dma_client *dma_out;
-    };
-    union {
-        void *vdma_in;
-        struct etraxfs_dma_client *dma_in;
-    };
-
-    /* MDIO bus.  */
-    struct qemu_mdio mdio_bus;
-    unsigned int phyaddr;
-    int duplex_mismatch;
-
-    /* PHY.     */
-    struct qemu_phy phy;
-};
-
-static void eth_validate_duplex(struct fs_eth *eth)
-{
-    struct qemu_phy *phy;
-    unsigned int phy_duplex;
-    unsigned int mac_duplex;
-    int new_mm = 0;
-
-    phy = eth->mdio_bus.devs[eth->phyaddr];
-    phy_duplex = !!(phy->read(phy, 18) & (1 << 11));
-    mac_duplex = !!(eth->regs[RW_REC_CTRL] & 128);
-
-    if (mac_duplex != phy_duplex) {
-        new_mm = 1;
-    }
-
-    if (eth->regs[RW_GEN_CTRL] & 1) {
-        if (new_mm != eth->duplex_mismatch) {
-            if (new_mm) {
-                printf("HW: WARNING ETH duplex mismatch MAC=%d PHY=%d\n",
-                       mac_duplex, phy_duplex);
-            } else {
-                printf("HW: ETH duplex ok.\n");
-            }
-        }
-        eth->duplex_mismatch = new_mm;
-    }
-}
-
-static uint64_t
-eth_read(void *opaque, hwaddr addr, unsigned int size)
-{
-    struct fs_eth *eth = opaque;
-    uint32_t r = 0;
-
-    addr >>= 2;
-
-    switch (addr) {
-    case R_STAT:
-        r = eth->mdio_bus.mdio & 1;
-        break;
-    default:
-        r = eth->regs[addr];
-        D(printf("%s %x\n", __func__, addr * 4));
-        break;
-    }
-    return r;
-}
-
-static void eth_update_ma(struct fs_eth *eth, int ma)
-{
-    int reg;
-    int i = 0;
-
-    ma &= 1;
-
-    reg = RW_MA0_LO;
-    if (ma) {
-        reg = RW_MA1_LO;
-    }
-
-    eth->macaddr[ma][i++] = eth->regs[reg];
-    eth->macaddr[ma][i++] = eth->regs[reg] >> 8;
-    eth->macaddr[ma][i++] = eth->regs[reg] >> 16;
-    eth->macaddr[ma][i++] = eth->regs[reg] >> 24;
-    eth->macaddr[ma][i++] = eth->regs[reg + 1];
-    eth->macaddr[ma][i] = eth->regs[reg + 1] >> 8;
-
-    D(printf("set mac%d=%x.%x.%x.%x.%x.%x\n", ma,
-             eth->macaddr[ma][0], eth->macaddr[ma][1],
-             eth->macaddr[ma][2], eth->macaddr[ma][3],
-             eth->macaddr[ma][4], eth->macaddr[ma][5]));
-}
-
-static void
-eth_write(void *opaque, hwaddr addr,
-          uint64_t val64, unsigned int size)
-{
-    struct fs_eth *eth = opaque;
-    uint32_t value = val64;
-
-    addr >>= 2;
-    switch (addr) {
-    case RW_MA0_LO:
-    case RW_MA0_HI:
-        eth->regs[addr] = value;
-        eth_update_ma(eth, 0);
-        break;
-    case RW_MA1_LO:
-    case RW_MA1_HI:
-        eth->regs[addr] = value;
-        eth_update_ma(eth, 1);
-        break;
-
-    case RW_MGM_CTRL:
-        /* Attach an MDIO/PHY abstraction.  */
-        if (value & 2) {
-            eth->mdio_bus.mdio = value & 1;
-        }
-        if (eth->mdio_bus.mdc != (value & 4)) {
-            mdio_cycle(&eth->mdio_bus);
-            eth_validate_duplex(eth);
-        }
-        eth->mdio_bus.mdc = !!(value & 4);
-        eth->regs[addr] = value;
-        break;
-
-    case RW_REC_CTRL:
-        eth->regs[addr] = value;
-        eth_validate_duplex(eth);
-        break;
-
-    default:
-        eth->regs[addr] = value;
-        D(printf("%s %x %x\n", __func__, addr, value));
-        break;
-    }
-}
-
-/* The ETRAX FS has a groupt address table (GAT) which works like a k=1 bloom
-   filter dropping group addresses we have not joined.    The filter has 64
-   bits (m). The has function is a simple nible xor of the group addr.    */
-static int eth_match_groupaddr(struct fs_eth *eth, const unsigned char *sa)
-{
-    unsigned int hsh;
-    int m_individual = eth->regs[RW_REC_CTRL] & 4;
-    int match;
-
-    /* First bit on the wire of a MAC address signals multicast or
-       physical address.  */
-    if (!m_individual && !(sa[0] & 1)) {
-        return 0;
-    }
-
-    /* Calculate the hash index for the GA registers. */
-    hsh = 0;
-    hsh ^= (*sa) & 0x3f;
-    hsh ^= ((*sa) >> 6) & 0x03;
-    ++sa;
-    hsh ^= ((*sa) << 2) & 0x03c;
-    hsh ^= ((*sa) >> 4) & 0xf;
-    ++sa;
-    hsh ^= ((*sa) << 4) & 0x30;
-    hsh ^= ((*sa) >> 2) & 0x3f;
-    ++sa;
-    hsh ^= (*sa) & 0x3f;
-    hsh ^= ((*sa) >> 6) & 0x03;
-    ++sa;
-    hsh ^= ((*sa) << 2) & 0x03c;
-    hsh ^= ((*sa) >> 4) & 0xf;
-    ++sa;
-    hsh ^= ((*sa) << 4) & 0x30;
-    hsh ^= ((*sa) >> 2) & 0x3f;
-
-    hsh &= 63;
-    if (hsh > 31) {
-        match = eth->regs[RW_GA_HI] & (1 << (hsh - 32));
-    } else {
-        match = eth->regs[RW_GA_LO] & (1 << hsh);
-    }
-    D(printf("hsh=%x ga=%x.%x mtch=%d\n", hsh,
-             eth->regs[RW_GA_HI], eth->regs[RW_GA_LO], match));
-    return match;
-}
-
-static int eth_can_receive(NetClientState *nc)
-{
-    return 1;
-}
-
-static ssize_t eth_receive(NetClientState *nc, const uint8_t *buf, size_t size)
-{
-    unsigned char sa_bcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
-    struct fs_eth *eth = qemu_get_nic_opaque(nc);
-    int use_ma0 = eth->regs[RW_REC_CTRL] & 1;
-    int use_ma1 = eth->regs[RW_REC_CTRL] & 2;
-    int r_bcast = eth->regs[RW_REC_CTRL] & 8;
-
-    if (size < 12) {
-        return -1;
-    }
-
-    D(printf("%x.%x.%x.%x.%x.%x ma=%d %d bc=%d\n",
-         buf[0], buf[1], buf[2], buf[3], buf[4], buf[5],
-         use_ma0, use_ma1, r_bcast));
-
-    /* Does the frame get through the address filters?  */
-    if ((!use_ma0 || memcmp(buf, eth->macaddr[0], 6))
-        && (!use_ma1 || memcmp(buf, eth->macaddr[1], 6))
-        && (!r_bcast || memcmp(buf, sa_bcast, 6))
-        && !eth_match_groupaddr(eth, buf)) {
-        return size;
-    }
-
-    /* FIXME: Find another way to pass on the fake csum.  */
-    etraxfs_dmac_input(eth->dma_in, (void *)buf, size + 4, 1);
-
-        return size;
-}
-
-static int eth_tx_push(void *opaque, unsigned char *buf, int len, bool eop)
-{
-    struct fs_eth *eth = opaque;
-
-    D(printf("%s buf=%p len=%d\n", __func__, buf, len));
-    qemu_send_packet(qemu_get_queue(eth->nic), buf, len);
-    return len;
-}
-
-static void eth_set_link(NetClientState *nc)
-{
-    struct fs_eth *eth = qemu_get_nic_opaque(nc);
-    D(printf("%s %d\n", __func__, nc->link_down));
-    eth->phy.link = !nc->link_down;
-}
-
-static const MemoryRegionOps eth_ops = {
-    .read = eth_read,
-    .write = eth_write,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4
-    }
-};
-
-static void eth_cleanup(NetClientState *nc)
-{
-    struct fs_eth *eth = qemu_get_nic_opaque(nc);
-
-    /* Disconnect the client.  */
-    eth->dma_out->client.push = NULL;
-    eth->dma_out->client.opaque = NULL;
-    eth->dma_in->client.opaque = NULL;
-    eth->dma_in->client.pull = NULL;
-        g_free(eth);
-}
-
-static NetClientInfo net_etraxfs_info = {
-    .type = NET_CLIENT_OPTIONS_KIND_NIC,
-    .size = sizeof(NICState),
-    .can_receive = eth_can_receive,
-    .receive = eth_receive,
-    .cleanup = eth_cleanup,
-    .link_status_changed = eth_set_link,
-};
-
-static int fs_eth_init(SysBusDevice *dev)
-{
-    struct fs_eth *s = FROM_SYSBUS(typeof(*s), dev);
-
-    if (!s->dma_out || !s->dma_in) {
-        hw_error("Unconnected ETRAX-FS Ethernet MAC.\n");
-    }
-
-    s->dma_out->client.push = eth_tx_push;
-    s->dma_out->client.opaque = s;
-    s->dma_in->client.opaque = s;
-    s->dma_in->client.pull = NULL;
-
-    memory_region_init_io(&s->mmio, &eth_ops, s, "etraxfs-eth", 0x5c);
-    sysbus_init_mmio(dev, &s->mmio);
-
-    qemu_macaddr_default_if_unset(&s->conf.macaddr);
-    s->nic = qemu_new_nic(&net_etraxfs_info, &s->conf,
-                          object_get_typename(OBJECT(s)), dev->qdev.id, s);
-    qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
-
-
-    tdk_init(&s->phy);
-    mdio_attach(&s->mdio_bus, &s->phy, s->phyaddr);
-    return 0;
-}
-
-static Property etraxfs_eth_properties[] = {
-    DEFINE_PROP_UINT32("phyaddr", struct fs_eth, phyaddr, 1),
-    DEFINE_PROP_PTR("dma_out", struct fs_eth, vdma_out),
-    DEFINE_PROP_PTR("dma_in", struct fs_eth, vdma_in),
-    DEFINE_NIC_PROPERTIES(struct fs_eth, conf),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void etraxfs_eth_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = fs_eth_init;
-    dc->props = etraxfs_eth_properties;
-}
-
-static const 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_types(void)
-{
-    type_register_static(&etraxfs_eth_info);
-}
-
-type_init(etraxfs_eth_register_types)
diff --git a/hw/etraxfs_pic.c b/hw/etraxfs_pic.c
deleted file mode 100644 (file)
index 635103c..0000000
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * QEMU ETRAX Interrupt Controller.
- *
- * Copyright (c) 2008 Edgar E. Iglesias, Axis Communications AB.
- *
- * 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 "hw/sysbus.h"
-#include "hw/hw.h"
-//#include "pc.h"
-//#include "etraxfs.h"
-
-#define D(x)
-
-#define R_RW_MASK   0
-#define R_R_VECT    1
-#define R_R_MASKED_VECT 2
-#define R_R_NMI     3
-#define R_R_GURU    4
-#define R_MAX       5
-
-struct etrax_pic
-{
-    SysBusDevice busdev;
-    MemoryRegion mmio;
-    void *interrupt_vector;
-    qemu_irq parent_irq;
-    qemu_irq parent_nmi;
-    uint32_t regs[R_MAX];
-};
-
-static void pic_update(struct etrax_pic *fs)
-{   
-    uint32_t vector = 0;
-    int i;
-
-    fs->regs[R_R_MASKED_VECT] = fs->regs[R_R_VECT] & fs->regs[R_RW_MASK];
-
-    /* The ETRAX interrupt controller signals interrupts to the core
-       through an interrupt request wire and an irq vector bus. If 
-       multiple interrupts are simultaneously active it chooses vector 
-       0x30 and lets the sw choose the priorities.  */
-    if (fs->regs[R_R_MASKED_VECT]) {
-        uint32_t mv = fs->regs[R_R_MASKED_VECT];
-        for (i = 0; i < 31; i++) {
-            if (mv & 1) {
-                vector = 0x31 + i;
-                /* Check for multiple interrupts.  */
-                if (mv > 1)
-                    vector = 0x30;
-                break;
-            }
-            mv >>= 1;
-        }
-    }
-
-    if (fs->interrupt_vector) {
-        /* hack alert: ptr property */
-        *(uint32_t*)(fs->interrupt_vector) = vector;
-    }
-    qemu_set_irq(fs->parent_irq, !!vector);
-}
-
-static uint64_t
-pic_read(void *opaque, hwaddr addr, unsigned int size)
-{
-    struct etrax_pic *fs = opaque;
-    uint32_t rval;
-
-    rval = fs->regs[addr >> 2];
-    D(printf("%s %x=%x\n", __func__, addr, rval));
-    return rval;
-}
-
-static void pic_write(void *opaque, hwaddr addr,
-                      uint64_t value, unsigned int size)
-{
-    struct etrax_pic *fs = opaque;
-    D(printf("%s addr=%x val=%x\n", __func__, addr, value));
-
-    if (addr == R_RW_MASK) {
-        fs->regs[R_RW_MASK] = value;
-        pic_update(fs);
-    }
-}
-
-static const MemoryRegionOps pic_ops = {
-    .read = pic_read,
-    .write = pic_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4
-    }
-};
-
-static void nmi_handler(void *opaque, int irq, int level)
-{   
-    struct etrax_pic *fs = (void *)opaque;
-    uint32_t mask;
-
-    mask = 1 << irq;
-    if (level)
-        fs->regs[R_R_NMI] |= mask;
-    else
-        fs->regs[R_R_NMI] &= ~mask;
-
-    qemu_set_irq(fs->parent_nmi, !!fs->regs[R_R_NMI]);
-}
-
-static void irq_handler(void *opaque, int irq, int level)
-{   
-    struct etrax_pic *fs = (void *)opaque;
-
-    if (irq >= 30)
-        return nmi_handler(opaque, irq, level);
-
-    irq -= 1;
-    fs->regs[R_R_VECT] &= ~(1 << irq);
-    fs->regs[R_R_VECT] |= (!!level << irq);
-    pic_update(fs);
-}
-
-static int etraxfs_pic_init(SysBusDevice *dev)
-{
-    struct etrax_pic *s = FROM_SYSBUS(typeof (*s), dev);
-
-    qdev_init_gpio_in(&dev->qdev, irq_handler, 32);
-    sysbus_init_irq(dev, &s->parent_irq);
-    sysbus_init_irq(dev, &s->parent_nmi);
-
-    memory_region_init_io(&s->mmio, &pic_ops, s, "etraxfs-pic", R_MAX * 4);
-    sysbus_init_mmio(dev, &s->mmio);
-    return 0;
-}
-
-static Property etraxfs_pic_properties[] = {
-    DEFINE_PROP_PTR("interrupt_vector", struct etrax_pic, interrupt_vector),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void etraxfs_pic_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = etraxfs_pic_init;
-    dc->props = etraxfs_pic_properties;
-}
-
-static const 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_types(void)
-{
-    type_register_static(&etraxfs_pic_info);
-}
-
-type_init(etraxfs_pic_register_types)
diff --git a/hw/etraxfs_ser.c b/hw/etraxfs_ser.c
deleted file mode 100644 (file)
index 7e24d34..0000000
+++ /dev/null
@@ -1,248 +0,0 @@
-/*
- * QEMU ETRAX System Emulator
- *
- * Copyright (c) 2007 Edgar E. Iglesias, Axis Communications AB.
- *
- * 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 "hw/sysbus.h"
-#include "char/char.h"
-#include "qemu/log.h"
-
-#define D(x)
-
-#define RW_TR_CTRL     (0x00 / 4)
-#define RW_TR_DMA_EN   (0x04 / 4)
-#define RW_REC_CTRL    (0x08 / 4)
-#define RW_DOUT        (0x1c / 4)
-#define RS_STAT_DIN    (0x20 / 4)
-#define R_STAT_DIN     (0x24 / 4)
-#define RW_INTR_MASK   (0x2c / 4)
-#define RW_ACK_INTR    (0x30 / 4)
-#define R_INTR         (0x34 / 4)
-#define R_MASKED_INTR  (0x38 / 4)
-#define R_MAX          (0x3c / 4)
-
-#define STAT_DAV     16
-#define STAT_TR_IDLE 22
-#define STAT_TR_RDY  24
-
-struct etrax_serial
-{
-    SysBusDevice busdev;
-    MemoryRegion mmio;
-    CharDriverState *chr;
-    qemu_irq irq;
-
-    int pending_tx;
-
-    uint8_t rx_fifo[16];
-    unsigned int rx_fifo_pos;
-    unsigned int rx_fifo_len;
-
-    /* Control registers.  */
-    uint32_t regs[R_MAX];
-};
-
-static void ser_update_irq(struct etrax_serial *s)
-{
-
-    if (s->rx_fifo_len) {
-        s->regs[R_INTR] |= 8;
-    } else {
-        s->regs[R_INTR] &= ~8;
-    }
-
-    s->regs[R_MASKED_INTR] = s->regs[R_INTR] & s->regs[RW_INTR_MASK];
-    qemu_set_irq(s->irq, !!s->regs[R_MASKED_INTR]);
-}
-
-static uint64_t
-ser_read(void *opaque, hwaddr addr, unsigned int size)
-{
-    struct etrax_serial *s = opaque;
-    D(CPUCRISState *env = s->env);
-    uint32_t r = 0;
-
-    addr >>= 2;
-    switch (addr)
-    {
-        case R_STAT_DIN:
-            r = s->rx_fifo[(s->rx_fifo_pos - s->rx_fifo_len) & 15];
-            if (s->rx_fifo_len) {
-                r |= 1 << STAT_DAV;
-            }
-            r |= 1 << STAT_TR_RDY;
-            r |= 1 << STAT_TR_IDLE;
-            break;
-        case RS_STAT_DIN:
-            r = s->rx_fifo[(s->rx_fifo_pos - s->rx_fifo_len) & 15];
-            if (s->rx_fifo_len) {
-                r |= 1 << STAT_DAV;
-                s->rx_fifo_len--;
-            }
-            r |= 1 << STAT_TR_RDY;
-            r |= 1 << STAT_TR_IDLE;
-            break;
-        default:
-            r = s->regs[addr];
-            D(qemu_log("%s " TARGET_FMT_plx "=%x\n", __func__, addr, r));
-            break;
-    }
-    return r;
-}
-
-static void
-ser_write(void *opaque, hwaddr addr,
-          uint64_t val64, unsigned int size)
-{
-    struct etrax_serial *s = opaque;
-    uint32_t value = val64;
-    unsigned char ch = val64;
-    D(CPUCRISState *env = s->env);
-
-    D(qemu_log("%s " TARGET_FMT_plx "=%x\n",  __func__, addr, value));
-    addr >>= 2;
-    switch (addr)
-    {
-        case RW_DOUT:
-            qemu_chr_fe_write(s->chr, &ch, 1);
-            s->regs[R_INTR] |= 3;
-            s->pending_tx = 1;
-            s->regs[addr] = value;
-            break;
-        case RW_ACK_INTR:
-            if (s->pending_tx) {
-                value &= ~1;
-                s->pending_tx = 0;
-                D(qemu_log("fixedup value=%x r_intr=%x\n",
-                           value, s->regs[R_INTR]));
-            }
-            s->regs[addr] = value;
-            s->regs[R_INTR] &= ~value;
-            D(printf("r_intr=%x\n", s->regs[R_INTR]));
-            break;
-        default:
-            s->regs[addr] = value;
-            break;
-    }
-    ser_update_irq(s);
-}
-
-static const MemoryRegionOps ser_ops = {
-    .read = ser_read,
-    .write = ser_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4
-    }
-};
-
-static void serial_receive(void *opaque, const uint8_t *buf, int size)
-{
-    struct etrax_serial *s = opaque;
-    int i;
-
-    /* Got a byte.  */
-    if (s->rx_fifo_len >= 16) {
-        qemu_log("WARNING: UART dropped char.\n");
-        return;
-    }
-
-    for (i = 0; i < size; i++) { 
-        s->rx_fifo[s->rx_fifo_pos] = buf[i];
-        s->rx_fifo_pos++;
-        s->rx_fifo_pos &= 15;
-        s->rx_fifo_len++;
-    }
-
-    ser_update_irq(s);
-}
-
-static int serial_can_receive(void *opaque)
-{
-    struct etrax_serial *s = opaque;
-    int r;
-
-    /* Is the receiver enabled?  */
-    if (!(s->regs[RW_REC_CTRL] & (1 << 3))) {
-        return 0;
-    }
-
-    r = sizeof(s->rx_fifo) - s->rx_fifo_len;
-    return r;
-}
-
-static void serial_event(void *opaque, int event)
-{
-
-}
-
-static void etraxfs_ser_reset(DeviceState *d)
-{
-    struct etrax_serial *s = container_of(d, typeof(*s), busdev.qdev);
-
-    /* transmitter begins ready and idle.  */
-    s->regs[RS_STAT_DIN] |= (1 << STAT_TR_RDY);
-    s->regs[RS_STAT_DIN] |= (1 << STAT_TR_IDLE);
-
-    s->regs[RW_REC_CTRL] = 0x10000;
-
-}
-
-static int etraxfs_ser_init(SysBusDevice *dev)
-{
-    struct etrax_serial *s = FROM_SYSBUS(typeof (*s), dev);
-
-    sysbus_init_irq(dev, &s->irq);
-    memory_region_init_io(&s->mmio, &ser_ops, s, "etraxfs-serial", R_MAX * 4);
-    sysbus_init_mmio(dev, &s->mmio);
-
-    s->chr = qemu_char_get_next_serial();
-    if (s->chr)
-        qemu_chr_add_handlers(s->chr,
-                      serial_can_receive, serial_receive,
-                      serial_event, s);
-    return 0;
-}
-
-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 const 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_types(void)
-{
-    type_register_static(&etraxfs_ser_info);
-}
-
-type_init(etraxfs_serial_register_types)
diff --git a/hw/etraxfs_timer.c b/hw/etraxfs_timer.c
deleted file mode 100644 (file)
index 3cd9476..0000000
+++ /dev/null
@@ -1,351 +0,0 @@
-/*
- * QEMU ETRAX Timers
- *
- * Copyright (c) 2007 Edgar E. Iglesias, Axis Communications AB.
- *
- * 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 "hw/sysbus.h"
-#include "sysemu/sysemu.h"
-#include "qemu/timer.h"
-#include "hw/ptimer.h"
-
-#define D(x)
-
-#define RW_TMR0_DIV   0x00
-#define R_TMR0_DATA   0x04
-#define RW_TMR0_CTRL  0x08
-#define RW_TMR1_DIV   0x10
-#define R_TMR1_DATA   0x14
-#define RW_TMR1_CTRL  0x18
-#define R_TIME        0x38
-#define RW_WD_CTRL    0x40
-#define R_WD_STAT     0x44
-#define RW_INTR_MASK  0x48
-#define RW_ACK_INTR   0x4c
-#define R_INTR        0x50
-#define R_MASKED_INTR 0x54
-
-struct etrax_timer {
-    SysBusDevice busdev;
-    MemoryRegion mmio;
-    qemu_irq irq;
-    qemu_irq nmi;
-
-    QEMUBH *bh_t0;
-    QEMUBH *bh_t1;
-    QEMUBH *bh_wd;
-    ptimer_state *ptimer_t0;
-    ptimer_state *ptimer_t1;
-    ptimer_state *ptimer_wd;
-
-    int wd_hits;
-
-    /* Control registers.  */
-    uint32_t rw_tmr0_div;
-    uint32_t r_tmr0_data;
-    uint32_t rw_tmr0_ctrl;
-
-    uint32_t rw_tmr1_div;
-    uint32_t r_tmr1_data;
-    uint32_t rw_tmr1_ctrl;
-
-    uint32_t rw_wd_ctrl;
-
-    uint32_t rw_intr_mask;
-    uint32_t rw_ack_intr;
-    uint32_t r_intr;
-    uint32_t r_masked_intr;
-};
-
-static uint64_t
-timer_read(void *opaque, hwaddr addr, unsigned int size)
-{
-    struct etrax_timer *t = opaque;
-    uint32_t r = 0;
-
-    switch (addr) {
-    case R_TMR0_DATA:
-        r = ptimer_get_count(t->ptimer_t0);
-        break;
-    case R_TMR1_DATA:
-        r = ptimer_get_count(t->ptimer_t1);
-        break;
-    case R_TIME:
-        r = qemu_get_clock_ns(vm_clock) / 10;
-        break;
-    case RW_INTR_MASK:
-        r = t->rw_intr_mask;
-        break;
-    case R_MASKED_INTR:
-        r = t->r_intr & t->rw_intr_mask;
-        break;
-    default:
-        D(printf ("%s %x\n", __func__, addr));
-        break;
-    }
-    return r;
-}
-
-static void update_ctrl(struct etrax_timer *t, int tnum)
-{
-    unsigned int op;
-    unsigned int freq;
-    unsigned int freq_hz;
-    unsigned int div;
-    uint32_t ctrl;
-
-    ptimer_state *timer;
-
-    if (tnum == 0) {
-        ctrl = t->rw_tmr0_ctrl;
-        div = t->rw_tmr0_div;
-        timer = t->ptimer_t0;
-    } else {
-        ctrl = t->rw_tmr1_ctrl;
-        div = t->rw_tmr1_div;
-        timer = t->ptimer_t1;
-    }
-
-
-    op = ctrl & 3;
-    freq = ctrl >> 2;
-    freq_hz = 32000000;
-
-    switch (freq)
-    {
-    case 0:
-    case 1:
-        D(printf ("extern or disabled timer clock?\n"));
-        break;
-    case 4: freq_hz =  29493000; break;
-    case 5: freq_hz =  32000000; break;
-    case 6: freq_hz =  32768000; break;
-    case 7: freq_hz = 100000000; break;
-    default:
-        abort();
-        break;
-    }
-
-    D(printf ("freq_hz=%d div=%d\n", freq_hz, div));
-    ptimer_set_freq(timer, freq_hz);
-    ptimer_set_limit(timer, div, 0);
-
-    switch (op)
-    {
-        case 0:
-            /* Load.  */
-            ptimer_set_limit(timer, div, 1);
-            break;
-        case 1:
-            /* Hold.  */
-            ptimer_stop(timer);
-            break;
-        case 2:
-            /* Run.  */
-            ptimer_run(timer, 0);
-            break;
-        default:
-            abort();
-            break;
-    }
-}
-
-static void timer_update_irq(struct etrax_timer *t)
-{
-    t->r_intr &= ~(t->rw_ack_intr);
-    t->r_masked_intr = t->r_intr & t->rw_intr_mask;
-
-    D(printf("%s: masked_intr=%x\n", __func__, t->r_masked_intr));
-    qemu_set_irq(t->irq, !!t->r_masked_intr);
-}
-
-static void timer0_hit(void *opaque)
-{
-    struct etrax_timer *t = opaque;
-    t->r_intr |= 1;
-    timer_update_irq(t);
-}
-
-static void timer1_hit(void *opaque)
-{
-    struct etrax_timer *t = opaque;
-    t->r_intr |= 2;
-    timer_update_irq(t);
-}
-
-static void watchdog_hit(void *opaque)
-{
-    struct etrax_timer *t = opaque;
-    if (t->wd_hits == 0) {
-        /* real hw gives a single tick before reseting but we are
-           a bit friendlier to compensate for our slower execution.  */
-        ptimer_set_count(t->ptimer_wd, 10);
-        ptimer_run(t->ptimer_wd, 1);
-        qemu_irq_raise(t->nmi);
-    }
-    else
-        qemu_system_reset_request();
-
-    t->wd_hits++;
-}
-
-static inline void timer_watchdog_update(struct etrax_timer *t, uint32_t value)
-{
-    unsigned int wd_en = t->rw_wd_ctrl & (1 << 8);
-    unsigned int wd_key = t->rw_wd_ctrl >> 9;
-    unsigned int wd_cnt = t->rw_wd_ctrl & 511;
-    unsigned int new_key = value >> 9 & ((1 << 7) - 1);
-    unsigned int new_cmd = (value >> 8) & 1;
-
-    /* If the watchdog is enabled, they written key must match the
-       complement of the previous.  */
-    wd_key = ~wd_key & ((1 << 7) - 1);
-
-    if (wd_en && wd_key != new_key)
-        return;
-
-    D(printf("en=%d new_key=%x oldkey=%x cmd=%d cnt=%d\n", 
-         wd_en, new_key, wd_key, new_cmd, wd_cnt));
-
-    if (t->wd_hits)
-        qemu_irq_lower(t->nmi);
-
-    t->wd_hits = 0;
-
-    ptimer_set_freq(t->ptimer_wd, 760);
-    if (wd_cnt == 0)
-        wd_cnt = 256;
-    ptimer_set_count(t->ptimer_wd, wd_cnt);
-    if (new_cmd)
-        ptimer_run(t->ptimer_wd, 1);
-    else
-        ptimer_stop(t->ptimer_wd);
-
-    t->rw_wd_ctrl = value;
-}
-
-static void
-timer_write(void *opaque, hwaddr addr,
-            uint64_t val64, unsigned int size)
-{
-    struct etrax_timer *t = opaque;
-    uint32_t value = val64;
-
-    switch (addr)
-    {
-        case RW_TMR0_DIV:
-            t->rw_tmr0_div = value;
-            break;
-        case RW_TMR0_CTRL:
-            D(printf ("RW_TMR0_CTRL=%x\n", value));
-            t->rw_tmr0_ctrl = value;
-            update_ctrl(t, 0);
-            break;
-        case RW_TMR1_DIV:
-            t->rw_tmr1_div = value;
-            break;
-        case RW_TMR1_CTRL:
-            D(printf ("RW_TMR1_CTRL=%x\n", value));
-            t->rw_tmr1_ctrl = value;
-            update_ctrl(t, 1);
-            break;
-        case RW_INTR_MASK:
-            D(printf ("RW_INTR_MASK=%x\n", value));
-            t->rw_intr_mask = value;
-            timer_update_irq(t);
-            break;
-        case RW_WD_CTRL:
-            timer_watchdog_update(t, value);
-            break;
-        case RW_ACK_INTR:
-            t->rw_ack_intr = value;
-            timer_update_irq(t);
-            t->rw_ack_intr = 0;
-            break;
-        default:
-            printf ("%s " TARGET_FMT_plx " %x\n",
-                __func__, addr, value);
-            break;
-    }
-}
-
-static const MemoryRegionOps timer_ops = {
-    .read = timer_read,
-    .write = timer_write,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4
-    }
-};
-
-static void etraxfs_timer_reset(void *opaque)
-{
-    struct etrax_timer *t = opaque;
-
-    ptimer_stop(t->ptimer_t0);
-    ptimer_stop(t->ptimer_t1);
-    ptimer_stop(t->ptimer_wd);
-    t->rw_wd_ctrl = 0;
-    t->r_intr = 0;
-    t->rw_intr_mask = 0;
-    qemu_irq_lower(t->irq);
-}
-
-static int etraxfs_timer_init(SysBusDevice *dev)
-{
-    struct etrax_timer *t = FROM_SYSBUS(typeof (*t), dev);
-
-    t->bh_t0 = qemu_bh_new(timer0_hit, t);
-    t->bh_t1 = qemu_bh_new(timer1_hit, t);
-    t->bh_wd = qemu_bh_new(watchdog_hit, t);
-    t->ptimer_t0 = ptimer_init(t->bh_t0);
-    t->ptimer_t1 = ptimer_init(t->bh_t1);
-    t->ptimer_wd = ptimer_init(t->bh_wd);
-
-    sysbus_init_irq(dev, &t->irq);
-    sysbus_init_irq(dev, &t->nmi);
-
-    memory_region_init_io(&t->mmio, &timer_ops, t, "etraxfs-timer", 0x5c);
-    sysbus_init_mmio(dev, &t->mmio);
-    qemu_register_reset(etraxfs_timer_reset, t);
-    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 const 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_types(void)
-{
-    type_register_static(&etraxfs_timer_info);
-}
-
-type_init(etraxfs_timer_register_types)
diff --git a/hw/exynos4210.h b/hw/exynos4210.h
deleted file mode 100644 (file)
index bb9a1dd..0000000
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- *  Samsung exynos4210 SoC emulation
- *
- *  Copyright (c) 2011 Samsung Electronics Co., Ltd. All rights reserved.
- *    Maksim Kozlov <m.kozlov@samsung.com>
- *    Evgeny Voevodin <e.voevodin@samsung.com>
- *    Igor Mitsyanko <i.mitsyanko@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 "exec/memory.h"
-
-#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.
- */
-#define EXYNOS4210_IRQ_GATE_NINPUTS 2 /* Internal and External GIC */
-
-#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
-
-#define EXYNOS4210_I2C_NUMBER               9
-
-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;
-
-typedef struct Exynos4210State {
-    ARMCPU *cpu[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;
-    i2c_bus *i2c_if[EXYNOS4210_I2C_NUMBER];
-} Exynos4210State;
-
-void exynos4210_write_secondary(ARMCPU *cpu,
-        const struct arm_boot_info *info);
-
-Exynos4210State *exynos4210_init(MemoryRegion *system_mem,
-        unsigned long ram_size);
-
-/* 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);
-
-/*
- * exynos4210 UART
- */
-DeviceState *exynos4210_uart_create(hwaddr addr,
-                                    int fifo_size,
-                                    int channel,
-                                    CharDriverState *chr,
-                                    qemu_irq irq);
-
-#endif /* EXYNOS4210_H_ */
diff --git a/hw/exynos4210_combiner.c b/hw/exynos4210_combiner.c
deleted file mode 100644 (file)
index 5818f10..0000000
+++ /dev/null
@@ -1,455 +0,0 @@
-/*
- * Samsung exynos4210 Interrupt Combiner
- *
- * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd.
- * All rights reserved.
- *
- * Evgeny Voevodin <e.voevodin@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 "hw/sysbus.h"
-
-#include "hw/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, hwaddr 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;
-
-    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, hwaddr 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 */
-
-    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;
-    }
-}
-
-/* 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);
-}
-
-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 const 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_fimd.c b/hw/exynos4210_fimd.c
deleted file mode 100644 (file)
index bf316c6..0000000
+++ /dev/null
@@ -1,1931 +0,0 @@
-/*
- * 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@ispras.ru>
- *
- * Contributed by Mitsyanko Igor <i.mitsyanko@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 "exec/cpu-all.h"
-#include "hw/sysbus.h"
-#include "ui/console.h"
-#include "ui/pixel_ops.h"
-#include "qemu/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 */
-    hwaddr fb_len;       /* Framebuffer length */
-};
-
-typedef struct {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-    QemuConsole *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];
-    hwaddr 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)
-{
-    DisplaySurface *surface = qemu_console_surface(s->console);
-
-    /* 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 || surface_width(surface) != width ||
-            surface_height(surface) != height) {
-        DPRINT_L1("Resolution changed from %ux%u to %ux%u\n",
-           surface_width(surface), surface_height(surface), 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;
-    DisplaySurface *surface = qemu_console_surface(s->console);
-    Exynos4210fimdWindow *w;
-    int i, line;
-    hwaddr 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 || !surface_bits_per_pixel(surface) ||
-            !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 = surface_bits_per_pixel(surface);
-        fimd_update_putpix_qemu(bpp);
-        bpp = (bpp + 1) >> 3;
-        d = surface_data(surface);
-        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_gfx_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, hwaddr 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, hwaddr 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 const 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)
diff --git a/hw/exynos4210_gic.c b/hw/exynos4210_gic.c
deleted file mode 100644 (file)
index 807849c..0000000
+++ /dev/null
@@ -1,462 +0,0 @@
-/*
- * 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@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 "hw/sysbus.h"
-#include "qemu-common.h"
-#include "hw/irq.h"
-#include "hw/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 , EXT_GIC_ID_USB_HOST},
-    /* 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 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);
-}
-
-/*
- * 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 *********/
-
-typedef struct {
-    SysBusDevice busdev;
-    MemoryRegion cpu_container;
-    MemoryRegion dist_container;
-    MemoryRegion cpu_alias[EXYNOS4210_NCPUS];
-    MemoryRegion dist_alias[EXYNOS4210_NCPUS];
-    uint32_t num_cpu;
-    DeviceState *gic;
-} Exynos4210GicState;
-
-static void exynos4210_gic_set_irq(void *opaque, int irq, int level)
-{
-    Exynos4210GicState *s = (Exynos4210GicState *)opaque;
-    qemu_set_irq(qdev_get_gpio_in(s->gic, irq), level);
-}
-
-static int exynos4210_gic_init(SysBusDevice *dev)
-{
-    Exynos4210GicState *s = FROM_SYSBUS(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];
-    SysBusDevice *busdev;
-
-    s->gic = qdev_create(NULL, "arm_gic");
-    qdev_prop_set_uint32(s->gic, "num-cpu", s->num_cpu);
-    qdev_prop_set_uint32(s->gic, "num-irq", EXYNOS4210_GIC_NIRQ);
-    qdev_init_nofail(s->gic);
-    busdev = SYS_BUS_DEVICE(s->gic);
-
-    /* Pass through outbound IRQ lines from the GIC */
-    sysbus_pass_irq(dev, busdev);
-
-    /* Pass through inbound GPIO lines to the GIC */
-    qdev_init_gpio_in(&s->busdev.qdev, exynos4210_gic_set_irq,
-                      EXYNOS4210_GIC_NIRQ - 32);
-
-    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,
-                                 sysbus_mmio_get_region(busdev, 1),
-                                 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,
-                                 sysbus_mmio_get_region(busdev, 0),
-                                 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);
-
-    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 const 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)
-
-/* IRQ OR Gate struct.
- *
- * This device models an OR gate. There are n_in input qdev gpio lines and one
- * output sysbus IRQ line. The output IRQ level is formed as OR between all
- * gpio inputs.
- */
-typedef struct {
-    SysBusDevice busdev;
-
-    uint32_t n_in;      /* inputs amount */
-    uint32_t *level;    /* input levels */
-    qemu_irq out;       /* output IRQ */
-} Exynos4210IRQGateState;
-
-static Property exynos4210_irq_gate_properties[] = {
-    DEFINE_PROP_UINT32("n_in", Exynos4210IRQGateState, n_in, 1),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static const VMStateDescription vmstate_exynos4210_irq_gate = {
-    .name = "exynos4210.irq_gate",
-    .version_id = 2,
-    .minimum_version_id = 2,
-    .minimum_version_id_old = 2,
-    .fields = (VMStateField[]) {
-        VMSTATE_VBUFFER_UINT32(level, Exynos4210IRQGateState, 1, NULL, 0, n_in),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-/* Process a change in IRQ input. */
-static void exynos4210_irq_gate_handler(void *opaque, int irq, int level)
-{
-    Exynos4210IRQGateState *s = (Exynos4210IRQGateState *)opaque;
-    uint32_t i;
-
-    assert(irq < s->n_in);
-
-    s->level[irq] = level;
-
-    for (i = 0; i < s->n_in; i++) {
-        if (s->level[i] >= 1) {
-            qemu_irq_raise(s->out);
-            return;
-        }
-    }
-
-    qemu_irq_lower(s->out);
-}
-
-static void exynos4210_irq_gate_reset(DeviceState *d)
-{
-    Exynos4210IRQGateState *s =
-            DO_UPCAST(Exynos4210IRQGateState, busdev.qdev, d);
-
-    memset(s->level, 0, s->n_in * sizeof(*s->level));
-}
-
-/*
- * IRQ Gate initialization.
- */
-static int exynos4210_irq_gate_init(SysBusDevice *dev)
-{
-    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, s->n_in);
-
-    s->level = g_malloc0(s->n_in * sizeof(*s->level));
-
-    sysbus_init_irq(dev, &s->out);
-
-    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;
-    dc->props = exynos4210_irq_gate_properties;
-}
-
-static const 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)
diff --git a/hw/exynos4210_i2c.c b/hw/exynos4210_i2c.c
deleted file mode 100644 (file)
index 9e42875..0000000
+++ /dev/null
@@ -1,334 +0,0 @@
-/*
- *  Exynos4210 I2C Bus Serial Interface Emulation
- *
- *  Copyright (C) 2012 Samsung Electronics Co Ltd.
- *    Maksim Kozlov, <m.kozlov@samsung.com>
- *    Igor Mitsyanko, <i.mitsyanko@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/timer.h"
-#include "hw/sysbus.h"
-#include "hw/i2c.h"
-
-#ifndef EXYNOS4_I2C_DEBUG
-#define EXYNOS4_I2C_DEBUG                 0
-#endif
-
-#define TYPE_EXYNOS4_I2C                  "exynos4210.i2c"
-#define EXYNOS4_I2C(obj)                  \
-    OBJECT_CHECK(Exynos4210I2CState, (obj), TYPE_EXYNOS4_I2C)
-
-/* Exynos4210 I2C memory map */
-#define EXYNOS4_I2C_MEM_SIZE              0x14
-#define I2CCON_ADDR                       0x00  /* control register */
-#define I2CSTAT_ADDR                      0x04  /* control/status register */
-#define I2CADD_ADDR                       0x08  /* address register */
-#define I2CDS_ADDR                        0x0c  /* data shift register */
-#define I2CLC_ADDR                        0x10  /* line control register */
-
-#define I2CCON_ACK_GEN                    (1 << 7)
-#define I2CCON_INTRS_EN                   (1 << 5)
-#define I2CCON_INT_PEND                   (1 << 4)
-
-#define EXYNOS4_I2C_MODE(reg)             (((reg) >> 6) & 3)
-#define I2C_IN_MASTER_MODE(reg)           (((reg) >> 6) & 2)
-#define I2CMODE_MASTER_Rx                 0x2
-#define I2CMODE_MASTER_Tx                 0x3
-#define I2CSTAT_LAST_BIT                  (1 << 0)
-#define I2CSTAT_OUTPUT_EN                 (1 << 4)
-#define I2CSTAT_START_BUSY                (1 << 5)
-
-
-#if EXYNOS4_I2C_DEBUG
-#define DPRINT(fmt, args...)              \
-    do { fprintf(stderr, "QEMU I2C: "fmt, ## args); } while (0)
-
-static const char *exynos4_i2c_get_regname(unsigned offset)
-{
-    switch (offset) {
-    case I2CCON_ADDR:
-        return "I2CCON";
-    case I2CSTAT_ADDR:
-        return "I2CSTAT";
-    case I2CADD_ADDR:
-        return "I2CADD";
-    case I2CDS_ADDR:
-        return "I2CDS";
-    case I2CLC_ADDR:
-        return "I2CLC";
-    default:
-        return "[?]";
-    }
-}
-
-#else
-#define DPRINT(fmt, args...)              do { } while (0)
-#endif
-
-typedef struct Exynos4210I2CState {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-    i2c_bus *bus;
-    qemu_irq irq;
-
-    uint8_t i2ccon;
-    uint8_t i2cstat;
-    uint8_t i2cadd;
-    uint8_t i2cds;
-    uint8_t i2clc;
-    bool scl_free;
-} Exynos4210I2CState;
-
-static inline void exynos4210_i2c_raise_interrupt(Exynos4210I2CState *s)
-{
-    if (s->i2ccon & I2CCON_INTRS_EN) {
-        s->i2ccon |= I2CCON_INT_PEND;
-        qemu_irq_raise(s->irq);
-    }
-}
-
-static void exynos4210_i2c_data_receive(void *opaque)
-{
-    Exynos4210I2CState *s = (Exynos4210I2CState *)opaque;
-    int ret;
-
-    s->i2cstat &= ~I2CSTAT_LAST_BIT;
-    s->scl_free = false;
-    ret = i2c_recv(s->bus);
-    if (ret < 0 && (s->i2ccon & I2CCON_ACK_GEN)) {
-        s->i2cstat |= I2CSTAT_LAST_BIT;  /* Data is not acknowledged */
-    } else {
-        s->i2cds = ret;
-    }
-    exynos4210_i2c_raise_interrupt(s);
-}
-
-static void exynos4210_i2c_data_send(void *opaque)
-{
-    Exynos4210I2CState *s = (Exynos4210I2CState *)opaque;
-
-    s->i2cstat &= ~I2CSTAT_LAST_BIT;
-    s->scl_free = false;
-    if (i2c_send(s->bus, s->i2cds) < 0 && (s->i2ccon & I2CCON_ACK_GEN)) {
-        s->i2cstat |= I2CSTAT_LAST_BIT;
-    }
-    exynos4210_i2c_raise_interrupt(s);
-}
-
-static uint64_t exynos4210_i2c_read(void *opaque, hwaddr offset,
-                                 unsigned size)
-{
-    Exynos4210I2CState *s = (Exynos4210I2CState *)opaque;
-    uint8_t value;
-
-    switch (offset) {
-    case I2CCON_ADDR:
-        value = s->i2ccon;
-        break;
-    case I2CSTAT_ADDR:
-        value = s->i2cstat;
-        break;
-    case I2CADD_ADDR:
-        value = s->i2cadd;
-        break;
-    case I2CDS_ADDR:
-        value = s->i2cds;
-        s->scl_free = true;
-        if (EXYNOS4_I2C_MODE(s->i2cstat) == I2CMODE_MASTER_Rx &&
-               (s->i2cstat & I2CSTAT_START_BUSY) &&
-               !(s->i2ccon & I2CCON_INT_PEND)) {
-            exynos4210_i2c_data_receive(s);
-        }
-        break;
-    case I2CLC_ADDR:
-        value = s->i2clc;
-        break;
-    default:
-        value = 0;
-        DPRINT("ERROR: Bad read offset 0x%x\n", (unsigned int)offset);
-        break;
-    }
-
-    DPRINT("read %s [0x%02x] -> 0x%02x\n", exynos4_i2c_get_regname(offset),
-            (unsigned int)offset, value);
-    return value;
-}
-
-static void exynos4210_i2c_write(void *opaque, hwaddr offset,
-                              uint64_t value, unsigned size)
-{
-    Exynos4210I2CState *s = (Exynos4210I2CState *)opaque;
-    uint8_t v = value & 0xff;
-
-    DPRINT("write %s [0x%02x] <- 0x%02x\n", exynos4_i2c_get_regname(offset),
-            (unsigned int)offset, v);
-
-    switch (offset) {
-    case I2CCON_ADDR:
-        s->i2ccon = (v & ~I2CCON_INT_PEND) | (s->i2ccon & I2CCON_INT_PEND);
-        if ((s->i2ccon & I2CCON_INT_PEND) && !(v & I2CCON_INT_PEND)) {
-            s->i2ccon &= ~I2CCON_INT_PEND;
-            qemu_irq_lower(s->irq);
-            if (!(s->i2ccon & I2CCON_INTRS_EN)) {
-                s->i2cstat &= ~I2CSTAT_START_BUSY;
-            }
-
-            if (s->i2cstat & I2CSTAT_START_BUSY) {
-                if (s->scl_free) {
-                    if (EXYNOS4_I2C_MODE(s->i2cstat) == I2CMODE_MASTER_Tx) {
-                        exynos4210_i2c_data_send(s);
-                    } else if (EXYNOS4_I2C_MODE(s->i2cstat) ==
-                            I2CMODE_MASTER_Rx) {
-                        exynos4210_i2c_data_receive(s);
-                    }
-                } else {
-                    s->i2ccon |= I2CCON_INT_PEND;
-                    qemu_irq_raise(s->irq);
-                }
-            }
-        }
-        break;
-    case I2CSTAT_ADDR:
-        s->i2cstat =
-                (s->i2cstat & I2CSTAT_START_BUSY) | (v & ~I2CSTAT_START_BUSY);
-
-        if (!(s->i2cstat & I2CSTAT_OUTPUT_EN)) {
-            s->i2cstat &= ~I2CSTAT_START_BUSY;
-            s->scl_free = true;
-            qemu_irq_lower(s->irq);
-            break;
-        }
-
-        /* Nothing to do if in i2c slave mode */
-        if (!I2C_IN_MASTER_MODE(s->i2cstat)) {
-            break;
-        }
-
-        if (v & I2CSTAT_START_BUSY) {
-            s->i2cstat &= ~I2CSTAT_LAST_BIT;
-            s->i2cstat |= I2CSTAT_START_BUSY;    /* Line is busy */
-            s->scl_free = false;
-
-            /* Generate start bit and send slave address */
-            if (i2c_start_transfer(s->bus, s->i2cds >> 1, s->i2cds & 0x1) &&
-                    (s->i2ccon & I2CCON_ACK_GEN)) {
-                s->i2cstat |= I2CSTAT_LAST_BIT;
-            } else if (EXYNOS4_I2C_MODE(s->i2cstat) == I2CMODE_MASTER_Rx) {
-                exynos4210_i2c_data_receive(s);
-            }
-            exynos4210_i2c_raise_interrupt(s);
-        } else {
-            i2c_end_transfer(s->bus);
-            if (!(s->i2ccon & I2CCON_INT_PEND)) {
-                s->i2cstat &= ~I2CSTAT_START_BUSY;
-            }
-            s->scl_free = true;
-        }
-        break;
-    case I2CADD_ADDR:
-        if ((s->i2cstat & I2CSTAT_OUTPUT_EN) == 0) {
-            s->i2cadd = v;
-        }
-        break;
-    case I2CDS_ADDR:
-        if (s->i2cstat & I2CSTAT_OUTPUT_EN) {
-            s->i2cds = v;
-            s->scl_free = true;
-            if (EXYNOS4_I2C_MODE(s->i2cstat) == I2CMODE_MASTER_Tx &&
-                    (s->i2cstat & I2CSTAT_START_BUSY) &&
-                    !(s->i2ccon & I2CCON_INT_PEND)) {
-                exynos4210_i2c_data_send(s);
-            }
-        }
-        break;
-    case I2CLC_ADDR:
-        s->i2clc = v;
-        break;
-    default:
-        DPRINT("ERROR: Bad write offset 0x%x\n", (unsigned int)offset);
-        break;
-    }
-}
-
-static const MemoryRegionOps exynos4210_i2c_ops = {
-    .read = exynos4210_i2c_read,
-    .write = exynos4210_i2c_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static const VMStateDescription exynos4210_i2c_vmstate = {
-    .name = TYPE_EXYNOS4_I2C,
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT8(i2ccon, Exynos4210I2CState),
-        VMSTATE_UINT8(i2cstat, Exynos4210I2CState),
-        VMSTATE_UINT8(i2cds, Exynos4210I2CState),
-        VMSTATE_UINT8(i2cadd, Exynos4210I2CState),
-        VMSTATE_UINT8(i2clc, Exynos4210I2CState),
-        VMSTATE_BOOL(scl_free, Exynos4210I2CState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void exynos4210_i2c_reset(DeviceState *d)
-{
-    Exynos4210I2CState *s = EXYNOS4_I2C(d);
-
-    s->i2ccon  = 0x00;
-    s->i2cstat = 0x00;
-    s->i2cds   = 0xFF;
-    s->i2clc   = 0x00;
-    s->i2cadd  = 0xFF;
-    s->scl_free = true;
-}
-
-static int exynos4210_i2c_realize(SysBusDevice *dev)
-{
-    Exynos4210I2CState *s = EXYNOS4_I2C(dev);
-
-    memory_region_init_io(&s->iomem, &exynos4210_i2c_ops, s, TYPE_EXYNOS4_I2C,
-                          EXYNOS4_I2C_MEM_SIZE);
-    sysbus_init_mmio(dev, &s->iomem);
-    sysbus_init_irq(dev, &s->irq);
-    s->bus = i2c_init_bus(&dev->qdev, "i2c");
-    return 0;
-}
-
-static void exynos4210_i2c_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *sbdc = SYS_BUS_DEVICE_CLASS(klass);
-
-    dc->vmsd = &exynos4210_i2c_vmstate;
-    dc->reset = exynos4210_i2c_reset;
-    sbdc->init = exynos4210_i2c_realize;
-}
-
-static const TypeInfo exynos4210_i2c_type_info = {
-    .name = TYPE_EXYNOS4_I2C,
-    .parent = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(Exynos4210I2CState),
-    .class_init = exynos4210_i2c_class_init,
-};
-
-static void exynos4210_i2c_register_types(void)
-{
-    type_register_static(&exynos4210_i2c_type_info);
-}
-
-type_init(exynos4210_i2c_register_types)
diff --git a/hw/exynos4210_mct.c b/hw/exynos4210_mct.c
deleted file mode 100644 (file)
index 862c962..0000000
+++ /dev/null
@@ -1,1482 +0,0 @@
-/*
- * Samsung exynos4210 Multi Core timer
- *
- * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd.
- * All rights reserved.
- *
- * Evgeny Voevodin <e.voevodin@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 "hw/sysbus.h"
-#include "qemu/timer.h"
-#include "qemu-common.h"
-#include "hw/ptimer.h"
-
-#include "hw/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);
-    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) {
-        distance = MCT_GT_COUNTER_STEP;
-    }
-    exynos4210_gfrc_set_count(&s->g_timer, distance);
-
-    exynos4210_gfrc_start(&s->g_timer);
-}
-
-/*
- * 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 its 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, hwaddr 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, hwaddr 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 const 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)
diff --git a/hw/exynos4210_pmu.c b/hw/exynos4210_pmu.c
deleted file mode 100644 (file)
index ba5aa8d..0000000
+++ /dev/null
@@ -1,499 +0,0 @@
-/*
- *  Exynos4210 Power Management Unit (PMU) Emulation
- *
- *  Copyright (C) 2011 Samsung Electronics Co Ltd.
- *    Maksim Kozlov <m.kozlov@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 "hw/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, hwaddr 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, hwaddr 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 const 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)
diff --git a/hw/exynos4210_pwm.c b/hw/exynos4210_pwm.c
deleted file mode 100644 (file)
index 6d74cd4..0000000
+++ /dev/null
@@ -1,422 +0,0 @@
-/*
- * Samsung exynos4210 Pulse Width Modulation Timer
- *
- * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd.
- * All rights reserved.
- *
- * Evgeny Voevodin <e.voevodin@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 "hw/sysbus.h"
-#include "qemu/timer.h"
-#include "qemu-common.h"
-#include "hw/ptimer.h"
-
-#include "hw/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, hwaddr 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, hwaddr 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 const 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)
diff --git a/hw/exynos4210_rtc.c b/hw/exynos4210_rtc.c
deleted file mode 100644 (file)
index d170ca7..0000000
+++ /dev/null
@@ -1,592 +0,0 @@
-/*
- * Samsung exynos4210 Real Time Clock
- *
- * Copyright (c) 2012 Samsung Electronics Co., Ltd.
- *  Ogurtsov Oleg <o.ogurtsov@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/>.
- *
- */
-
-/* Description:
- * Register RTCCON:
- *  CLKSEL Bit[1] not used
- *  CLKOUTEN Bit[9] not used
- */
-
-#include "hw/sysbus.h"
-#include "qemu/timer.h"
-#include "qemu-common.h"
-#include "hw/ptimer.h"
-
-#include "hw/hw.h"
-#include "qemu/timer.h"
-#include "sysemu/sysemu.h"
-
-#include "hw/exynos4210.h"
-
-#define DEBUG_RTC 0
-
-#if DEBUG_RTC
-#define DPRINTF(fmt, ...) \
-        do { fprintf(stdout, "RTC: [%24s:%5d] " fmt, __func__, __LINE__, \
-                ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...) do {} while (0)
-#endif
-
-#define     EXYNOS4210_RTC_REG_MEM_SIZE     0x0100
-
-#define     INTP            0x0030
-#define     RTCCON          0x0040
-#define     TICCNT          0x0044
-#define     RTCALM          0x0050
-#define     ALMSEC          0x0054
-#define     ALMMIN          0x0058
-#define     ALMHOUR         0x005C
-#define     ALMDAY          0x0060
-#define     ALMMON          0x0064
-#define     ALMYEAR         0x0068
-#define     BCDSEC          0x0070
-#define     BCDMIN          0x0074
-#define     BCDHOUR         0x0078
-#define     BCDDAY          0x007C
-#define     BCDDAYWEEK      0x0080
-#define     BCDMON          0x0084
-#define     BCDYEAR         0x0088
-#define     CURTICNT        0x0090
-
-#define     TICK_TIMER_ENABLE   0x0100
-#define     TICNT_THRESHHOLD    2
-
-
-#define     RTC_ENABLE          0x0001
-
-#define     INTP_TICK_ENABLE    0x0001
-#define     INTP_ALM_ENABLE     0x0002
-
-#define     ALARM_INT_ENABLE    0x0040
-
-#define     RTC_BASE_FREQ       32768
-
-typedef struct Exynos4210RTCState {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-
-    /* registers */
-    uint32_t    reg_intp;
-    uint32_t    reg_rtccon;
-    uint32_t    reg_ticcnt;
-    uint32_t    reg_rtcalm;
-    uint32_t    reg_almsec;
-    uint32_t    reg_almmin;
-    uint32_t    reg_almhour;
-    uint32_t    reg_almday;
-    uint32_t    reg_almmon;
-    uint32_t    reg_almyear;
-    uint32_t    reg_curticcnt;
-
-    ptimer_state    *ptimer;        /* tick timer */
-    ptimer_state    *ptimer_1Hz;    /* clock timer */
-    uint32_t        freq;
-
-    qemu_irq        tick_irq;   /* Time Tick Generator irq */
-    qemu_irq        alm_irq;    /* alarm irq */
-
-    struct tm   current_tm;     /* current time */
-} Exynos4210RTCState;
-
-#define TICCKSEL(value) ((value & (0x0F << 4)) >> 4)
-
-/*** VMState ***/
-static const VMStateDescription vmstate_exynos4210_rtc_state = {
-    .name = "exynos4210.rtc",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT32(reg_intp, Exynos4210RTCState),
-        VMSTATE_UINT32(reg_rtccon, Exynos4210RTCState),
-        VMSTATE_UINT32(reg_ticcnt, Exynos4210RTCState),
-        VMSTATE_UINT32(reg_rtcalm, Exynos4210RTCState),
-        VMSTATE_UINT32(reg_almsec, Exynos4210RTCState),
-        VMSTATE_UINT32(reg_almmin, Exynos4210RTCState),
-        VMSTATE_UINT32(reg_almhour, Exynos4210RTCState),
-        VMSTATE_UINT32(reg_almday, Exynos4210RTCState),
-        VMSTATE_UINT32(reg_almmon, Exynos4210RTCState),
-        VMSTATE_UINT32(reg_almyear, Exynos4210RTCState),
-        VMSTATE_UINT32(reg_curticcnt, Exynos4210RTCState),
-        VMSTATE_PTIMER(ptimer, Exynos4210RTCState),
-        VMSTATE_PTIMER(ptimer_1Hz, Exynos4210RTCState),
-        VMSTATE_UINT32(freq, Exynos4210RTCState),
-        VMSTATE_INT32(current_tm.tm_sec, Exynos4210RTCState),
-        VMSTATE_INT32(current_tm.tm_min, Exynos4210RTCState),
-        VMSTATE_INT32(current_tm.tm_hour, Exynos4210RTCState),
-        VMSTATE_INT32(current_tm.tm_wday, Exynos4210RTCState),
-        VMSTATE_INT32(current_tm.tm_mday, Exynos4210RTCState),
-        VMSTATE_INT32(current_tm.tm_mon, Exynos4210RTCState),
-        VMSTATE_INT32(current_tm.tm_year, Exynos4210RTCState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-#define BCD3DIGITS(x) \
-    ((uint32_t)to_bcd((uint8_t)(x % 100)) + \
-    ((uint32_t)to_bcd((uint8_t)((x % 1000) / 100)) << 8))
-
-static void check_alarm_raise(Exynos4210RTCState *s)
-{
-    unsigned int alarm_raise = 0;
-    struct tm stm = s->current_tm;
-
-    if ((s->reg_rtcalm & 0x01) &&
-        (to_bcd((uint8_t)stm.tm_sec) == (uint8_t)s->reg_almsec)) {
-        alarm_raise = 1;
-    }
-    if ((s->reg_rtcalm & 0x02) &&
-        (to_bcd((uint8_t)stm.tm_min) == (uint8_t)s->reg_almmin)) {
-        alarm_raise = 1;
-    }
-    if ((s->reg_rtcalm & 0x04) &&
-        (to_bcd((uint8_t)stm.tm_hour) == (uint8_t)s->reg_almhour)) {
-        alarm_raise = 1;
-    }
-    if ((s->reg_rtcalm & 0x08) &&
-        (to_bcd((uint8_t)stm.tm_mday) == (uint8_t)s->reg_almday)) {
-        alarm_raise = 1;
-    }
-    if ((s->reg_rtcalm & 0x10) &&
-         (to_bcd((uint8_t)stm.tm_mon) == (uint8_t)s->reg_almmon)) {
-        alarm_raise = 1;
-    }
-    if ((s->reg_rtcalm & 0x20) &&
-        (BCD3DIGITS(stm.tm_year) == s->reg_almyear)) {
-        alarm_raise = 1;
-    }
-
-    if (alarm_raise) {
-        DPRINTF("ALARM IRQ\n");
-        /* set irq status */
-        s->reg_intp |= INTP_ALM_ENABLE;
-        qemu_irq_raise(s->alm_irq);
-    }
-}
-
-/*
- * RTC update frequency
- * Parameters:
- *     reg_value - current RTCCON register or his new value
- */
-static void exynos4210_rtc_update_freq(Exynos4210RTCState *s,
-                                       uint32_t reg_value)
-{
-    uint32_t freq;
-
-    freq = s->freq;
-    /* set frequncy for time generator */
-    s->freq = RTC_BASE_FREQ / (1 << TICCKSEL(reg_value));
-
-    if (freq != s->freq) {
-        ptimer_set_freq(s->ptimer, s->freq);
-        DPRINTF("freq=%dHz\n", s->freq);
-    }
-}
-
-/* month is between 0 and 11. */
-static int get_days_in_month(int month, int year)
-{
-    static const int days_tab[12] = {
-        31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
-    };
-    int d;
-    if ((unsigned)month >= 12) {
-        return 31;
-    }
-    d = days_tab[month];
-    if (month == 1) {
-        if ((year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0)) {
-            d++;
-        }
-    }
-    return d;
-}
-
-/* update 'tm' to the next second */
-static void rtc_next_second(struct tm *tm)
-{
-    int days_in_month;
-
-    tm->tm_sec++;
-    if ((unsigned)tm->tm_sec >= 60) {
-        tm->tm_sec = 0;
-        tm->tm_min++;
-        if ((unsigned)tm->tm_min >= 60) {
-            tm->tm_min = 0;
-            tm->tm_hour++;
-            if ((unsigned)tm->tm_hour >= 24) {
-                tm->tm_hour = 0;
-                /* next day */
-                tm->tm_wday++;
-                if ((unsigned)tm->tm_wday >= 7) {
-                    tm->tm_wday = 0;
-                }
-                days_in_month = get_days_in_month(tm->tm_mon,
-                                                  tm->tm_year + 1900);
-                tm->tm_mday++;
-                if (tm->tm_mday < 1) {
-                    tm->tm_mday = 1;
-                } else if (tm->tm_mday > days_in_month) {
-                    tm->tm_mday = 1;
-                    tm->tm_mon++;
-                    if (tm->tm_mon >= 12) {
-                        tm->tm_mon = 0;
-                        tm->tm_year++;
-                    }
-                }
-            }
-        }
-    }
-}
-
-/*
- * tick handler
- */
-static void exynos4210_rtc_tick(void *opaque)
-{
-    Exynos4210RTCState *s = (Exynos4210RTCState *)opaque;
-
-    DPRINTF("TICK IRQ\n");
-    /* set irq status */
-    s->reg_intp |= INTP_TICK_ENABLE;
-    /* raise IRQ */
-    qemu_irq_raise(s->tick_irq);
-
-    /* restart timer */
-    ptimer_set_count(s->ptimer, s->reg_ticcnt);
-    ptimer_run(s->ptimer, 1);
-}
-
-/*
- * 1Hz clock handler
- */
-static void exynos4210_rtc_1Hz_tick(void *opaque)
-{
-    Exynos4210RTCState *s = (Exynos4210RTCState *)opaque;
-
-    rtc_next_second(&s->current_tm);
-    /* DPRINTF("1Hz tick\n"); */
-
-    /* raise IRQ */
-    if (s->reg_rtcalm & ALARM_INT_ENABLE) {
-        check_alarm_raise(s);
-    }
-
-    ptimer_set_count(s->ptimer_1Hz, RTC_BASE_FREQ);
-    ptimer_run(s->ptimer_1Hz, 1);
-}
-
-/*
- * RTC Read
- */
-static uint64_t exynos4210_rtc_read(void *opaque, hwaddr offset,
-        unsigned size)
-{
-    uint32_t value = 0;
-    Exynos4210RTCState *s = (Exynos4210RTCState *)opaque;
-
-    switch (offset) {
-    case INTP:
-        value = s->reg_intp;
-        break;
-    case RTCCON:
-        value = s->reg_rtccon;
-        break;
-    case TICCNT:
-        value = s->reg_ticcnt;
-        break;
-    case RTCALM:
-        value = s->reg_rtcalm;
-        break;
-    case ALMSEC:
-        value = s->reg_almsec;
-        break;
-    case ALMMIN:
-        value = s->reg_almmin;
-        break;
-    case ALMHOUR:
-        value = s->reg_almhour;
-        break;
-    case ALMDAY:
-        value = s->reg_almday;
-        break;
-    case ALMMON:
-        value = s->reg_almmon;
-        break;
-    case ALMYEAR:
-        value = s->reg_almyear;
-        break;
-
-    case BCDSEC:
-        value = (uint32_t)to_bcd((uint8_t)s->current_tm.tm_sec);
-        break;
-    case BCDMIN:
-        value = (uint32_t)to_bcd((uint8_t)s->current_tm.tm_min);
-        break;
-    case BCDHOUR:
-        value = (uint32_t)to_bcd((uint8_t)s->current_tm.tm_hour);
-        break;
-    case BCDDAYWEEK:
-        value = (uint32_t)to_bcd((uint8_t)s->current_tm.tm_wday);
-        break;
-    case BCDDAY:
-        value = (uint32_t)to_bcd((uint8_t)s->current_tm.tm_mday);
-        break;
-    case BCDMON:
-        value = (uint32_t)to_bcd((uint8_t)s->current_tm.tm_mon + 1);
-        break;
-    case BCDYEAR:
-        value = BCD3DIGITS(s->current_tm.tm_year);
-        break;
-
-    case CURTICNT:
-        s->reg_curticcnt = ptimer_get_count(s->ptimer);
-        value = s->reg_curticcnt;
-        break;
-
-    default:
-        fprintf(stderr,
-                "[exynos4210.rtc: bad read offset " TARGET_FMT_plx "]\n",
-                offset);
-        break;
-    }
-    return value;
-}
-
-/*
- * RTC Write
- */
-static void exynos4210_rtc_write(void *opaque, hwaddr offset,
-        uint64_t value, unsigned size)
-{
-    Exynos4210RTCState *s = (Exynos4210RTCState *)opaque;
-
-    switch (offset) {
-    case INTP:
-        if (value & INTP_ALM_ENABLE) {
-            qemu_irq_lower(s->alm_irq);
-            s->reg_intp &= (~INTP_ALM_ENABLE);
-        }
-        if (value & INTP_TICK_ENABLE) {
-            qemu_irq_lower(s->tick_irq);
-            s->reg_intp &= (~INTP_TICK_ENABLE);
-        }
-        break;
-    case RTCCON:
-        if (value & RTC_ENABLE) {
-            exynos4210_rtc_update_freq(s, value);
-        }
-        if ((value & RTC_ENABLE) > (s->reg_rtccon & RTC_ENABLE)) {
-            /* clock timer */
-            ptimer_set_count(s->ptimer_1Hz, RTC_BASE_FREQ);
-            ptimer_run(s->ptimer_1Hz, 1);
-            DPRINTF("run clock timer\n");
-        }
-        if ((value & RTC_ENABLE) < (s->reg_rtccon & RTC_ENABLE)) {
-            /* tick timer */
-            ptimer_stop(s->ptimer);
-            /* clock timer */
-            ptimer_stop(s->ptimer_1Hz);
-            DPRINTF("stop all timers\n");
-        }
-        if (value & RTC_ENABLE) {
-            if ((value & TICK_TIMER_ENABLE) >
-                (s->reg_rtccon & TICK_TIMER_ENABLE) &&
-                (s->reg_ticcnt)) {
-                ptimer_set_count(s->ptimer, s->reg_ticcnt);
-                ptimer_run(s->ptimer, 1);
-                DPRINTF("run tick timer\n");
-            }
-            if ((value & TICK_TIMER_ENABLE) <
-                (s->reg_rtccon & TICK_TIMER_ENABLE)) {
-                ptimer_stop(s->ptimer);
-            }
-        }
-        s->reg_rtccon = value;
-        break;
-    case TICCNT:
-        if (value > TICNT_THRESHHOLD) {
-            s->reg_ticcnt = value;
-        } else {
-            fprintf(stderr,
-                    "[exynos4210.rtc: bad TICNT value %u ]\n",
-                    (uint32_t)value);
-        }
-        break;
-
-    case RTCALM:
-        s->reg_rtcalm = value;
-        break;
-    case ALMSEC:
-        s->reg_almsec = (value & 0x7f);
-        break;
-    case ALMMIN:
-        s->reg_almmin = (value & 0x7f);
-        break;
-    case ALMHOUR:
-        s->reg_almhour = (value & 0x3f);
-        break;
-    case ALMDAY:
-        s->reg_almday = (value & 0x3f);
-        break;
-    case ALMMON:
-        s->reg_almmon = (value & 0x1f);
-        break;
-    case ALMYEAR:
-        s->reg_almyear = (value & 0x0fff);
-        break;
-
-    case BCDSEC:
-        if (s->reg_rtccon & RTC_ENABLE) {
-            s->current_tm.tm_sec = (int)from_bcd((uint8_t)value);
-        }
-        break;
-    case BCDMIN:
-        if (s->reg_rtccon & RTC_ENABLE) {
-            s->current_tm.tm_min = (int)from_bcd((uint8_t)value);
-        }
-        break;
-    case BCDHOUR:
-        if (s->reg_rtccon & RTC_ENABLE) {
-            s->current_tm.tm_hour = (int)from_bcd((uint8_t)value);
-        }
-        break;
-    case BCDDAYWEEK:
-        if (s->reg_rtccon & RTC_ENABLE) {
-            s->current_tm.tm_wday = (int)from_bcd((uint8_t)value);
-        }
-        break;
-    case BCDDAY:
-        if (s->reg_rtccon & RTC_ENABLE) {
-            s->current_tm.tm_mday = (int)from_bcd((uint8_t)value);
-        }
-        break;
-    case BCDMON:
-        if (s->reg_rtccon & RTC_ENABLE) {
-            s->current_tm.tm_mon = (int)from_bcd((uint8_t)value) - 1;
-        }
-        break;
-    case BCDYEAR:
-        if (s->reg_rtccon & RTC_ENABLE) {
-            /* 3 digits */
-            s->current_tm.tm_year = (int)from_bcd((uint8_t)value) +
-                    (int)from_bcd((uint8_t)((value >> 8) & 0x0f)) * 100;
-        }
-        break;
-
-    default:
-        fprintf(stderr,
-                "[exynos4210.rtc: bad write offset " TARGET_FMT_plx "]\n",
-                offset);
-        break;
-
-    }
-}
-
-/*
- * Set default values to timer fields and registers
- */
-static void exynos4210_rtc_reset(DeviceState *d)
-{
-    Exynos4210RTCState *s = (Exynos4210RTCState *)d;
-
-    qemu_get_timedate(&s->current_tm, 0);
-
-    DPRINTF("Get time from host: %d-%d-%d %2d:%02d:%02d\n",
-            s->current_tm.tm_year, s->current_tm.tm_mon, s->current_tm.tm_mday,
-            s->current_tm.tm_hour, s->current_tm.tm_min, s->current_tm.tm_sec);
-
-    s->reg_intp = 0;
-    s->reg_rtccon = 0;
-    s->reg_ticcnt = 0;
-    s->reg_rtcalm = 0;
-    s->reg_almsec = 0;
-    s->reg_almmin = 0;
-    s->reg_almhour = 0;
-    s->reg_almday = 0;
-    s->reg_almmon = 0;
-    s->reg_almyear = 0;
-
-    s->reg_curticcnt = 0;
-
-    exynos4210_rtc_update_freq(s, s->reg_rtccon);
-    ptimer_stop(s->ptimer);
-    ptimer_stop(s->ptimer_1Hz);
-}
-
-static const MemoryRegionOps exynos4210_rtc_ops = {
-    .read = exynos4210_rtc_read,
-    .write = exynos4210_rtc_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-/*
- * RTC timer initialization
- */
-static int exynos4210_rtc_init(SysBusDevice *dev)
-{
-    Exynos4210RTCState *s = FROM_SYSBUS(Exynos4210RTCState, dev);
-    QEMUBH *bh;
-
-    bh = qemu_bh_new(exynos4210_rtc_tick, s);
-    s->ptimer = ptimer_init(bh);
-    ptimer_set_freq(s->ptimer, RTC_BASE_FREQ);
-    exynos4210_rtc_update_freq(s, 0);
-
-    bh = qemu_bh_new(exynos4210_rtc_1Hz_tick, s);
-    s->ptimer_1Hz = ptimer_init(bh);
-    ptimer_set_freq(s->ptimer_1Hz, RTC_BASE_FREQ);
-
-    sysbus_init_irq(dev, &s->alm_irq);
-    sysbus_init_irq(dev, &s->tick_irq);
-
-    memory_region_init_io(&s->iomem, &exynos4210_rtc_ops, s, "exynos4210-rtc",
-            EXYNOS4210_RTC_REG_MEM_SIZE);
-    sysbus_init_mmio(dev, &s->iomem);
-
-    return 0;
-}
-
-static void exynos4210_rtc_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = exynos4210_rtc_init;
-    dc->reset = exynos4210_rtc_reset;
-    dc->vmsd = &vmstate_exynos4210_rtc_state;
-}
-
-static const TypeInfo exynos4210_rtc_info = {
-    .name          = "exynos4210.rtc",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(Exynos4210RTCState),
-    .class_init    = exynos4210_rtc_class_init,
-};
-
-static void exynos4210_rtc_register_types(void)
-{
-    type_register_static(&exynos4210_rtc_info);
-}
-
-type_init(exynos4210_rtc_register_types)
diff --git a/hw/exynos4210_uart.c b/hw/exynos4210_uart.c
deleted file mode 100644 (file)
index 006f3d4..0000000
+++ /dev/null
@@ -1,676 +0,0 @@
-/*
- *  Exynos4210 UART Emulation
- *
- *  Copyright (C) 2011 Samsung Electronics Co Ltd.
- *    Maksim Kozlov, <m.kozlov@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 "hw/sysbus.h"
-#include "sysemu/sysemu.h"
-#include "char/char.h"
-
-#include "hw/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 */
-    hwaddr  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(hwaddr  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, hwaddr 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, hwaddr 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(hwaddr 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 = SYS_BUS_DEVICE(dev);
-    qdev_init_nofail(dev);
-    if (addr != (hwaddr)-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 const 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)
diff --git a/hw/fdc.c b/hw/fdc.c
deleted file mode 100644 (file)
index a4bb129..0000000
--- a/hw/fdc.c
+++ /dev/null
@@ -1,2284 +0,0 @@
-/*
- * QEMU Floppy disk emulator (Intel 82078)
- *
- * Copyright (c) 2003, 2007 Jocelyn Mayer
- * Copyright (c) 2008 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.
- */
-/*
- * The controller is used in Sun4m systems in a slightly different
- * way. There are changes in DOR register and DMA is not available.
- */
-
-#include "hw/hw.h"
-#include "hw/fdc.h"
-#include "qemu/error-report.h"
-#include "qemu/timer.h"
-#include "hw/isa.h"
-#include "hw/sysbus.h"
-#include "hw/qdev-addr.h"
-#include "sysemu/blockdev.h"
-#include "sysemu/sysemu.h"
-#include "qemu/log.h"
-
-/********************************************************/
-/* debug Floppy devices */
-//#define DEBUG_FLOPPY
-
-#ifdef DEBUG_FLOPPY
-#define FLOPPY_DPRINTF(fmt, ...)                                \
-    do { printf("FLOPPY: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define FLOPPY_DPRINTF(fmt, ...)
-#endif
-
-/********************************************************/
-/* Floppy drive emulation                               */
-
-typedef enum FDriveRate {
-    FDRIVE_RATE_500K = 0x00,  /* 500 Kbps */
-    FDRIVE_RATE_300K = 0x01,  /* 300 Kbps */
-    FDRIVE_RATE_250K = 0x02,  /* 250 Kbps */
-    FDRIVE_RATE_1M   = 0x03,  /*   1 Mbps */
-} FDriveRate;
-
-typedef struct FDFormat {
-    FDriveType drive;
-    uint8_t last_sect;
-    uint8_t max_track;
-    uint8_t max_head;
-    FDriveRate rate;
-} FDFormat;
-
-static const FDFormat fd_formats[] = {
-    /* First entry is default format */
-    /* 1.44 MB 3"1/2 floppy disks */
-    { FDRIVE_DRV_144, 18, 80, 1, FDRIVE_RATE_500K, },
-    { FDRIVE_DRV_144, 20, 80, 1, FDRIVE_RATE_500K, },
-    { FDRIVE_DRV_144, 21, 80, 1, FDRIVE_RATE_500K, },
-    { FDRIVE_DRV_144, 21, 82, 1, FDRIVE_RATE_500K, },
-    { FDRIVE_DRV_144, 21, 83, 1, FDRIVE_RATE_500K, },
-    { FDRIVE_DRV_144, 22, 80, 1, FDRIVE_RATE_500K, },
-    { FDRIVE_DRV_144, 23, 80, 1, FDRIVE_RATE_500K, },
-    { FDRIVE_DRV_144, 24, 80, 1, FDRIVE_RATE_500K, },
-    /* 2.88 MB 3"1/2 floppy disks */
-    { FDRIVE_DRV_288, 36, 80, 1, FDRIVE_RATE_1M, },
-    { FDRIVE_DRV_288, 39, 80, 1, FDRIVE_RATE_1M, },
-    { FDRIVE_DRV_288, 40, 80, 1, FDRIVE_RATE_1M, },
-    { FDRIVE_DRV_288, 44, 80, 1, FDRIVE_RATE_1M, },
-    { FDRIVE_DRV_288, 48, 80, 1, FDRIVE_RATE_1M, },
-    /* 720 kB 3"1/2 floppy disks */
-    { FDRIVE_DRV_144,  9, 80, 1, FDRIVE_RATE_250K, },
-    { FDRIVE_DRV_144, 10, 80, 1, FDRIVE_RATE_250K, },
-    { FDRIVE_DRV_144, 10, 82, 1, FDRIVE_RATE_250K, },
-    { FDRIVE_DRV_144, 10, 83, 1, FDRIVE_RATE_250K, },
-    { FDRIVE_DRV_144, 13, 80, 1, FDRIVE_RATE_250K, },
-    { FDRIVE_DRV_144, 14, 80, 1, FDRIVE_RATE_250K, },
-    /* 1.2 MB 5"1/4 floppy disks */
-    { FDRIVE_DRV_120, 15, 80, 1, FDRIVE_RATE_500K, },
-    { FDRIVE_DRV_120, 18, 80, 1, FDRIVE_RATE_500K, },
-    { FDRIVE_DRV_120, 18, 82, 1, FDRIVE_RATE_500K, },
-    { FDRIVE_DRV_120, 18, 83, 1, FDRIVE_RATE_500K, },
-    { FDRIVE_DRV_120, 20, 80, 1, FDRIVE_RATE_500K, },
-    /* 720 kB 5"1/4 floppy disks */
-    { FDRIVE_DRV_120,  9, 80, 1, FDRIVE_RATE_250K, },
-    { FDRIVE_DRV_120, 11, 80, 1, FDRIVE_RATE_250K, },
-    /* 360 kB 5"1/4 floppy disks */
-    { FDRIVE_DRV_120,  9, 40, 1, FDRIVE_RATE_300K, },
-    { FDRIVE_DRV_120,  9, 40, 0, FDRIVE_RATE_300K, },
-    { FDRIVE_DRV_120, 10, 41, 1, FDRIVE_RATE_300K, },
-    { FDRIVE_DRV_120, 10, 42, 1, FDRIVE_RATE_300K, },
-    /* 320 kB 5"1/4 floppy disks */
-    { FDRIVE_DRV_120,  8, 40, 1, FDRIVE_RATE_250K, },
-    { FDRIVE_DRV_120,  8, 40, 0, FDRIVE_RATE_250K, },
-    /* 360 kB must match 5"1/4 better than 3"1/2... */
-    { FDRIVE_DRV_144,  9, 80, 0, FDRIVE_RATE_250K, },
-    /* end */
-    { FDRIVE_DRV_NONE, -1, -1, 0, 0, },
-};
-
-static void pick_geometry(BlockDriverState *bs, int *nb_heads,
-                          int *max_track, int *last_sect,
-                          FDriveType drive_in, FDriveType *drive,
-                          FDriveRate *rate)
-{
-    const FDFormat *parse;
-    uint64_t nb_sectors, size;
-    int i, first_match, match;
-
-    bdrv_get_geometry(bs, &nb_sectors);
-    match = -1;
-    first_match = -1;
-    for (i = 0; ; i++) {
-        parse = &fd_formats[i];
-        if (parse->drive == FDRIVE_DRV_NONE) {
-            break;
-        }
-        if (drive_in == parse->drive ||
-            drive_in == FDRIVE_DRV_NONE) {
-            size = (parse->max_head + 1) * parse->max_track *
-                parse->last_sect;
-            if (nb_sectors == size) {
-                match = i;
-                break;
-            }
-            if (first_match == -1) {
-                first_match = i;
-            }
-        }
-    }
-    if (match == -1) {
-        if (first_match == -1) {
-            match = 1;
-        } else {
-            match = first_match;
-        }
-        parse = &fd_formats[match];
-    }
-    *nb_heads = parse->max_head + 1;
-    *max_track = parse->max_track;
-    *last_sect = parse->last_sect;
-    *drive = parse->drive;
-    *rate = parse->rate;
-}
-
-#define GET_CUR_DRV(fdctrl) ((fdctrl)->cur_drv)
-#define SET_CUR_DRV(fdctrl, drive) ((fdctrl)->cur_drv = (drive))
-
-/* Will always be a fixed parameter for us */
-#define FD_SECTOR_LEN          512
-#define FD_SECTOR_SC           2   /* Sector size code */
-#define FD_RESET_SENSEI_COUNT  4   /* Number of sense interrupts on RESET */
-
-typedef struct FDCtrl FDCtrl;
-
-/* Floppy disk drive emulation */
-typedef enum FDiskFlags {
-    FDISK_DBL_SIDES  = 0x01,
-} FDiskFlags;
-
-typedef struct FDrive {
-    FDCtrl *fdctrl;
-    BlockDriverState *bs;
-    /* Drive status */
-    FDriveType drive;
-    uint8_t perpendicular;    /* 2.88 MB access mode    */
-    /* Position */
-    uint8_t head;
-    uint8_t track;
-    uint8_t sect;
-    /* Media */
-    FDiskFlags flags;
-    uint8_t last_sect;        /* Nb sector per track    */
-    uint8_t max_track;        /* Nb of tracks           */
-    uint16_t bps;             /* Bytes per sector       */
-    uint8_t ro;               /* Is read-only           */
-    uint8_t media_changed;    /* Is media changed       */
-    uint8_t media_rate;       /* Data rate of medium    */
-} FDrive;
-
-static void fd_init(FDrive *drv)
-{
-    /* Drive */
-    drv->drive = FDRIVE_DRV_NONE;
-    drv->perpendicular = 0;
-    /* Disk */
-    drv->last_sect = 0;
-    drv->max_track = 0;
-}
-
-#define NUM_SIDES(drv) ((drv)->flags & FDISK_DBL_SIDES ? 2 : 1)
-
-static int fd_sector_calc(uint8_t head, uint8_t track, uint8_t sect,
-                          uint8_t last_sect, uint8_t num_sides)
-{
-    return (((track * num_sides) + head) * last_sect) + sect - 1;
-}
-
-/* Returns current position, in sectors, for given drive */
-static int fd_sector(FDrive *drv)
-{
-    return fd_sector_calc(drv->head, drv->track, drv->sect, drv->last_sect,
-                          NUM_SIDES(drv));
-}
-
-/* Seek to a new position:
- * returns 0 if already on right track
- * returns 1 if track changed
- * returns 2 if track is invalid
- * returns 3 if sector is invalid
- * returns 4 if seek is disabled
- */
-static int fd_seek(FDrive *drv, uint8_t head, uint8_t track, uint8_t sect,
-                   int enable_seek)
-{
-    uint32_t sector;
-    int ret;
-
-    if (track > drv->max_track ||
-        (head != 0 && (drv->flags & FDISK_DBL_SIDES) == 0)) {
-        FLOPPY_DPRINTF("try to read %d %02x %02x (max=%d %d %02x %02x)\n",
-                       head, track, sect, 1,
-                       (drv->flags & FDISK_DBL_SIDES) == 0 ? 0 : 1,
-                       drv->max_track, drv->last_sect);
-        return 2;
-    }
-    if (sect > drv->last_sect) {
-        FLOPPY_DPRINTF("try to read %d %02x %02x (max=%d %d %02x %02x)\n",
-                       head, track, sect, 1,
-                       (drv->flags & FDISK_DBL_SIDES) == 0 ? 0 : 1,
-                       drv->max_track, drv->last_sect);
-        return 3;
-    }
-    sector = fd_sector_calc(head, track, sect, drv->last_sect, NUM_SIDES(drv));
-    ret = 0;
-    if (sector != fd_sector(drv)) {
-#if 0
-        if (!enable_seek) {
-            FLOPPY_DPRINTF("error: no implicit seek %d %02x %02x"
-                           " (max=%d %02x %02x)\n",
-                           head, track, sect, 1, drv->max_track,
-                           drv->last_sect);
-            return 4;
-        }
-#endif
-        drv->head = head;
-        if (drv->track != track) {
-            if (drv->bs != NULL && bdrv_is_inserted(drv->bs)) {
-                drv->media_changed = 0;
-            }
-            ret = 1;
-        }
-        drv->track = track;
-        drv->sect = sect;
-    }
-
-    if (drv->bs == NULL || !bdrv_is_inserted(drv->bs)) {
-        ret = 2;
-    }
-
-    return ret;
-}
-
-/* Set drive back to track 0 */
-static void fd_recalibrate(FDrive *drv)
-{
-    FLOPPY_DPRINTF("recalibrate\n");
-    fd_seek(drv, 0, 0, 1, 1);
-}
-
-/* Revalidate a disk drive after a disk change */
-static void fd_revalidate(FDrive *drv)
-{
-    int nb_heads, max_track, last_sect, ro;
-    FDriveType drive;
-    FDriveRate rate;
-
-    FLOPPY_DPRINTF("revalidate\n");
-    if (drv->bs != NULL) {
-        ro = bdrv_is_read_only(drv->bs);
-        pick_geometry(drv->bs, &nb_heads, &max_track,
-                      &last_sect, drv->drive, &drive, &rate);
-        if (!bdrv_is_inserted(drv->bs)) {
-            FLOPPY_DPRINTF("No disk in drive\n");
-        } else {
-            FLOPPY_DPRINTF("Floppy disk (%d h %d t %d s) %s\n", nb_heads,
-                           max_track, last_sect, ro ? "ro" : "rw");
-        }
-        if (nb_heads == 1) {
-            drv->flags &= ~FDISK_DBL_SIDES;
-        } else {
-            drv->flags |= FDISK_DBL_SIDES;
-        }
-        drv->max_track = max_track;
-        drv->last_sect = last_sect;
-        drv->ro = ro;
-        drv->drive = drive;
-        drv->media_rate = rate;
-    } else {
-        FLOPPY_DPRINTF("No drive connected\n");
-        drv->last_sect = 0;
-        drv->max_track = 0;
-        drv->flags &= ~FDISK_DBL_SIDES;
-    }
-}
-
-/********************************************************/
-/* Intel 82078 floppy disk controller emulation          */
-
-static void fdctrl_reset(FDCtrl *fdctrl, int do_irq);
-static void fdctrl_reset_fifo(FDCtrl *fdctrl);
-static int fdctrl_transfer_handler (void *opaque, int nchan,
-                                    int dma_pos, int dma_len);
-static void fdctrl_raise_irq(FDCtrl *fdctrl);
-static FDrive *get_cur_drv(FDCtrl *fdctrl);
-
-static uint32_t fdctrl_read_statusA(FDCtrl *fdctrl);
-static uint32_t fdctrl_read_statusB(FDCtrl *fdctrl);
-static uint32_t fdctrl_read_dor(FDCtrl *fdctrl);
-static void fdctrl_write_dor(FDCtrl *fdctrl, uint32_t value);
-static uint32_t fdctrl_read_tape(FDCtrl *fdctrl);
-static void fdctrl_write_tape(FDCtrl *fdctrl, uint32_t value);
-static uint32_t fdctrl_read_main_status(FDCtrl *fdctrl);
-static void fdctrl_write_rate(FDCtrl *fdctrl, uint32_t value);
-static uint32_t fdctrl_read_data(FDCtrl *fdctrl);
-static void fdctrl_write_data(FDCtrl *fdctrl, uint32_t value);
-static uint32_t fdctrl_read_dir(FDCtrl *fdctrl);
-static void fdctrl_write_ccr(FDCtrl *fdctrl, uint32_t value);
-
-enum {
-    FD_DIR_WRITE   = 0,
-    FD_DIR_READ    = 1,
-    FD_DIR_SCANE   = 2,
-    FD_DIR_SCANL   = 3,
-    FD_DIR_SCANH   = 4,
-    FD_DIR_VERIFY  = 5,
-};
-
-enum {
-    FD_STATE_MULTI  = 0x01,    /* multi track flag */
-    FD_STATE_FORMAT = 0x02,    /* format flag */
-};
-
-enum {
-    FD_REG_SRA = 0x00,
-    FD_REG_SRB = 0x01,
-    FD_REG_DOR = 0x02,
-    FD_REG_TDR = 0x03,
-    FD_REG_MSR = 0x04,
-    FD_REG_DSR = 0x04,
-    FD_REG_FIFO = 0x05,
-    FD_REG_DIR = 0x07,
-    FD_REG_CCR = 0x07,
-};
-
-enum {
-    FD_CMD_READ_TRACK = 0x02,
-    FD_CMD_SPECIFY = 0x03,
-    FD_CMD_SENSE_DRIVE_STATUS = 0x04,
-    FD_CMD_WRITE = 0x05,
-    FD_CMD_READ = 0x06,
-    FD_CMD_RECALIBRATE = 0x07,
-    FD_CMD_SENSE_INTERRUPT_STATUS = 0x08,
-    FD_CMD_WRITE_DELETED = 0x09,
-    FD_CMD_READ_ID = 0x0a,
-    FD_CMD_READ_DELETED = 0x0c,
-    FD_CMD_FORMAT_TRACK = 0x0d,
-    FD_CMD_DUMPREG = 0x0e,
-    FD_CMD_SEEK = 0x0f,
-    FD_CMD_VERSION = 0x10,
-    FD_CMD_SCAN_EQUAL = 0x11,
-    FD_CMD_PERPENDICULAR_MODE = 0x12,
-    FD_CMD_CONFIGURE = 0x13,
-    FD_CMD_LOCK = 0x14,
-    FD_CMD_VERIFY = 0x16,
-    FD_CMD_POWERDOWN_MODE = 0x17,
-    FD_CMD_PART_ID = 0x18,
-    FD_CMD_SCAN_LOW_OR_EQUAL = 0x19,
-    FD_CMD_SCAN_HIGH_OR_EQUAL = 0x1d,
-    FD_CMD_SAVE = 0x2e,
-    FD_CMD_OPTION = 0x33,
-    FD_CMD_RESTORE = 0x4e,
-    FD_CMD_DRIVE_SPECIFICATION_COMMAND = 0x8e,
-    FD_CMD_RELATIVE_SEEK_OUT = 0x8f,
-    FD_CMD_FORMAT_AND_WRITE = 0xcd,
-    FD_CMD_RELATIVE_SEEK_IN = 0xcf,
-};
-
-enum {
-    FD_CONFIG_PRETRK = 0xff, /* Pre-compensation set to track 0 */
-    FD_CONFIG_FIFOTHR = 0x0f, /* FIFO threshold set to 1 byte */
-    FD_CONFIG_POLL  = 0x10, /* Poll enabled */
-    FD_CONFIG_EFIFO = 0x20, /* FIFO disabled */
-    FD_CONFIG_EIS   = 0x40, /* No implied seeks */
-};
-
-enum {
-    FD_SR0_DS0      = 0x01,
-    FD_SR0_DS1      = 0x02,
-    FD_SR0_HEAD     = 0x04,
-    FD_SR0_EQPMT    = 0x10,
-    FD_SR0_SEEK     = 0x20,
-    FD_SR0_ABNTERM  = 0x40,
-    FD_SR0_INVCMD   = 0x80,
-    FD_SR0_RDYCHG   = 0xc0,
-};
-
-enum {
-    FD_SR1_MA       = 0x01, /* Missing address mark */
-    FD_SR1_NW       = 0x02, /* Not writable */
-    FD_SR1_EC       = 0x80, /* End of cylinder */
-};
-
-enum {
-    FD_SR2_SNS      = 0x04, /* Scan not satisfied */
-    FD_SR2_SEH      = 0x08, /* Scan equal hit */
-};
-
-enum {
-    FD_SRA_DIR      = 0x01,
-    FD_SRA_nWP      = 0x02,
-    FD_SRA_nINDX    = 0x04,
-    FD_SRA_HDSEL    = 0x08,
-    FD_SRA_nTRK0    = 0x10,
-    FD_SRA_STEP     = 0x20,
-    FD_SRA_nDRV2    = 0x40,
-    FD_SRA_INTPEND  = 0x80,
-};
-
-enum {
-    FD_SRB_MTR0     = 0x01,
-    FD_SRB_MTR1     = 0x02,
-    FD_SRB_WGATE    = 0x04,
-    FD_SRB_RDATA    = 0x08,
-    FD_SRB_WDATA    = 0x10,
-    FD_SRB_DR0      = 0x20,
-};
-
-enum {
-#if MAX_FD == 4
-    FD_DOR_SELMASK  = 0x03,
-#else
-    FD_DOR_SELMASK  = 0x01,
-#endif
-    FD_DOR_nRESET   = 0x04,
-    FD_DOR_DMAEN    = 0x08,
-    FD_DOR_MOTEN0   = 0x10,
-    FD_DOR_MOTEN1   = 0x20,
-    FD_DOR_MOTEN2   = 0x40,
-    FD_DOR_MOTEN3   = 0x80,
-};
-
-enum {
-#if MAX_FD == 4
-    FD_TDR_BOOTSEL  = 0x0c,
-#else
-    FD_TDR_BOOTSEL  = 0x04,
-#endif
-};
-
-enum {
-    FD_DSR_DRATEMASK= 0x03,
-    FD_DSR_PWRDOWN  = 0x40,
-    FD_DSR_SWRESET  = 0x80,
-};
-
-enum {
-    FD_MSR_DRV0BUSY = 0x01,
-    FD_MSR_DRV1BUSY = 0x02,
-    FD_MSR_DRV2BUSY = 0x04,
-    FD_MSR_DRV3BUSY = 0x08,
-    FD_MSR_CMDBUSY  = 0x10,
-    FD_MSR_NONDMA   = 0x20,
-    FD_MSR_DIO      = 0x40,
-    FD_MSR_RQM      = 0x80,
-};
-
-enum {
-    FD_DIR_DSKCHG   = 0x80,
-};
-
-#define FD_MULTI_TRACK(state) ((state) & FD_STATE_MULTI)
-#define FD_FORMAT_CMD(state) ((state) & FD_STATE_FORMAT)
-
-struct FDCtrl {
-    MemoryRegion iomem;
-    qemu_irq irq;
-    /* Controller state */
-    QEMUTimer *result_timer;
-    int dma_chann;
-    /* Controller's identification */
-    uint8_t version;
-    /* HW */
-    uint8_t sra;
-    uint8_t srb;
-    uint8_t dor;
-    uint8_t dor_vmstate; /* only used as temp during vmstate */
-    uint8_t tdr;
-    uint8_t dsr;
-    uint8_t msr;
-    uint8_t cur_drv;
-    uint8_t status0;
-    uint8_t status1;
-    uint8_t status2;
-    /* Command FIFO */
-    uint8_t *fifo;
-    int32_t fifo_size;
-    uint32_t data_pos;
-    uint32_t data_len;
-    uint8_t data_state;
-    uint8_t data_dir;
-    uint8_t eot; /* last wanted sector */
-    /* States kept only to be returned back */
-    /* precompensation */
-    uint8_t precomp_trk;
-    uint8_t config;
-    uint8_t lock;
-    /* Power down config (also with status regB access mode */
-    uint8_t pwrd;
-    /* Floppy drives */
-    uint8_t num_floppies;
-    /* Sun4m quirks? */
-    int sun4m;
-    FDrive drives[MAX_FD];
-    int reset_sensei;
-    uint32_t check_media_rate;
-    /* Timers state */
-    uint8_t timer0;
-    uint8_t timer1;
-};
-
-typedef struct FDCtrlSysBus {
-    SysBusDevice busdev;
-    struct FDCtrl state;
-} FDCtrlSysBus;
-
-typedef struct FDCtrlISABus {
-    ISADevice busdev;
-    uint32_t iobase;
-    uint32_t irq;
-    uint32_t dma;
-    struct FDCtrl state;
-    int32_t bootindexA;
-    int32_t bootindexB;
-} FDCtrlISABus;
-
-static uint32_t fdctrl_read (void *opaque, uint32_t reg)
-{
-    FDCtrl *fdctrl = opaque;
-    uint32_t retval;
-
-    reg &= 7;
-    switch (reg) {
-    case FD_REG_SRA:
-        retval = fdctrl_read_statusA(fdctrl);
-        break;
-    case FD_REG_SRB:
-        retval = fdctrl_read_statusB(fdctrl);
-        break;
-    case FD_REG_DOR:
-        retval = fdctrl_read_dor(fdctrl);
-        break;
-    case FD_REG_TDR:
-        retval = fdctrl_read_tape(fdctrl);
-        break;
-    case FD_REG_MSR:
-        retval = fdctrl_read_main_status(fdctrl);
-        break;
-    case FD_REG_FIFO:
-        retval = fdctrl_read_data(fdctrl);
-        break;
-    case FD_REG_DIR:
-        retval = fdctrl_read_dir(fdctrl);
-        break;
-    default:
-        retval = (uint32_t)(-1);
-        break;
-    }
-    FLOPPY_DPRINTF("read reg%d: 0x%02x\n", reg & 7, retval);
-
-    return retval;
-}
-
-static void fdctrl_write (void *opaque, uint32_t reg, uint32_t value)
-{
-    FDCtrl *fdctrl = opaque;
-
-    FLOPPY_DPRINTF("write reg%d: 0x%02x\n", reg & 7, value);
-
-    reg &= 7;
-    switch (reg) {
-    case FD_REG_DOR:
-        fdctrl_write_dor(fdctrl, value);
-        break;
-    case FD_REG_TDR:
-        fdctrl_write_tape(fdctrl, value);
-        break;
-    case FD_REG_DSR:
-        fdctrl_write_rate(fdctrl, value);
-        break;
-    case FD_REG_FIFO:
-        fdctrl_write_data(fdctrl, value);
-        break;
-    case FD_REG_CCR:
-        fdctrl_write_ccr(fdctrl, value);
-        break;
-    default:
-        break;
-    }
-}
-
-static uint64_t fdctrl_read_mem (void *opaque, hwaddr reg,
-                                 unsigned ize)
-{
-    return fdctrl_read(opaque, (uint32_t)reg);
-}
-
-static void fdctrl_write_mem (void *opaque, hwaddr reg,
-                              uint64_t value, unsigned size)
-{
-    fdctrl_write(opaque, (uint32_t)reg, value);
-}
-
-static const MemoryRegionOps fdctrl_mem_ops = {
-    .read = fdctrl_read_mem,
-    .write = fdctrl_write_mem,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static const MemoryRegionOps fdctrl_mem_strict_ops = {
-    .read = fdctrl_read_mem,
-    .write = fdctrl_write_mem,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid = {
-        .min_access_size = 1,
-        .max_access_size = 1,
-    },
-};
-
-static bool fdrive_media_changed_needed(void *opaque)
-{
-    FDrive *drive = opaque;
-
-    return (drive->bs != NULL && drive->media_changed != 1);
-}
-
-static const VMStateDescription vmstate_fdrive_media_changed = {
-    .name = "fdrive/media_changed",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField[]) {
-        VMSTATE_UINT8(media_changed, FDrive),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static bool fdrive_media_rate_needed(void *opaque)
-{
-    FDrive *drive = opaque;
-
-    return drive->fdctrl->check_media_rate;
-}
-
-static const VMStateDescription vmstate_fdrive_media_rate = {
-    .name = "fdrive/media_rate",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField[]) {
-        VMSTATE_UINT8(media_rate, FDrive),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static const VMStateDescription vmstate_fdrive = {
-    .name = "fdrive",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField[]) {
-        VMSTATE_UINT8(head, FDrive),
-        VMSTATE_UINT8(track, FDrive),
-        VMSTATE_UINT8(sect, FDrive),
-        VMSTATE_END_OF_LIST()
-    },
-    .subsections = (VMStateSubsection[]) {
-        {
-            .vmsd = &vmstate_fdrive_media_changed,
-            .needed = &fdrive_media_changed_needed,
-        } , {
-            .vmsd = &vmstate_fdrive_media_rate,
-            .needed = &fdrive_media_rate_needed,
-        } , {
-            /* empty */
-        }
-    }
-};
-
-static void fdc_pre_save(void *opaque)
-{
-    FDCtrl *s = opaque;
-
-    s->dor_vmstate = s->dor | GET_CUR_DRV(s);
-}
-
-static int fdc_post_load(void *opaque, int version_id)
-{
-    FDCtrl *s = opaque;
-
-    SET_CUR_DRV(s, s->dor_vmstate & FD_DOR_SELMASK);
-    s->dor = s->dor_vmstate & ~FD_DOR_SELMASK;
-    return 0;
-}
-
-static const VMStateDescription vmstate_fdc = {
-    .name = "fdc",
-    .version_id = 2,
-    .minimum_version_id = 2,
-    .minimum_version_id_old = 2,
-    .pre_save = fdc_pre_save,
-    .post_load = fdc_post_load,
-    .fields      = (VMStateField []) {
-        /* Controller State */
-        VMSTATE_UINT8(sra, FDCtrl),
-        VMSTATE_UINT8(srb, FDCtrl),
-        VMSTATE_UINT8(dor_vmstate, FDCtrl),
-        VMSTATE_UINT8(tdr, FDCtrl),
-        VMSTATE_UINT8(dsr, FDCtrl),
-        VMSTATE_UINT8(msr, FDCtrl),
-        VMSTATE_UINT8(status0, FDCtrl),
-        VMSTATE_UINT8(status1, FDCtrl),
-        VMSTATE_UINT8(status2, FDCtrl),
-        /* Command FIFO */
-        VMSTATE_VARRAY_INT32(fifo, FDCtrl, fifo_size, 0, vmstate_info_uint8,
-                             uint8_t),
-        VMSTATE_UINT32(data_pos, FDCtrl),
-        VMSTATE_UINT32(data_len, FDCtrl),
-        VMSTATE_UINT8(data_state, FDCtrl),
-        VMSTATE_UINT8(data_dir, FDCtrl),
-        VMSTATE_UINT8(eot, FDCtrl),
-        /* States kept only to be returned back */
-        VMSTATE_UINT8(timer0, FDCtrl),
-        VMSTATE_UINT8(timer1, FDCtrl),
-        VMSTATE_UINT8(precomp_trk, FDCtrl),
-        VMSTATE_UINT8(config, FDCtrl),
-        VMSTATE_UINT8(lock, FDCtrl),
-        VMSTATE_UINT8(pwrd, FDCtrl),
-        VMSTATE_UINT8_EQUAL(num_floppies, FDCtrl),
-        VMSTATE_STRUCT_ARRAY(drives, FDCtrl, MAX_FD, 1,
-                             vmstate_fdrive, FDrive),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void fdctrl_external_reset_sysbus(DeviceState *d)
-{
-    FDCtrlSysBus *sys = container_of(d, FDCtrlSysBus, busdev.qdev);
-    FDCtrl *s = &sys->state;
-
-    fdctrl_reset(s, 0);
-}
-
-static void fdctrl_external_reset_isa(DeviceState *d)
-{
-    FDCtrlISABus *isa = container_of(d, FDCtrlISABus, busdev.qdev);
-    FDCtrl *s = &isa->state;
-
-    fdctrl_reset(s, 0);
-}
-
-static void fdctrl_handle_tc(void *opaque, int irq, int level)
-{
-    //FDCtrl *s = opaque;
-
-    if (level) {
-        // XXX
-        FLOPPY_DPRINTF("TC pulsed\n");
-    }
-}
-
-/* Change IRQ state */
-static void fdctrl_reset_irq(FDCtrl *fdctrl)
-{
-    fdctrl->status0 = 0;
-    if (!(fdctrl->sra & FD_SRA_INTPEND))
-        return;
-    FLOPPY_DPRINTF("Reset interrupt\n");
-    qemu_set_irq(fdctrl->irq, 0);
-    fdctrl->sra &= ~FD_SRA_INTPEND;
-}
-
-static void fdctrl_raise_irq(FDCtrl *fdctrl)
-{
-    /* Sparc mutation */
-    if (fdctrl->sun4m && (fdctrl->msr & FD_MSR_CMDBUSY)) {
-        /* XXX: not sure */
-        fdctrl->msr &= ~FD_MSR_CMDBUSY;
-        fdctrl->msr |= FD_MSR_RQM | FD_MSR_DIO;
-        return;
-    }
-    if (!(fdctrl->sra & FD_SRA_INTPEND)) {
-        qemu_set_irq(fdctrl->irq, 1);
-        fdctrl->sra |= FD_SRA_INTPEND;
-    }
-
-    fdctrl->reset_sensei = 0;
-    FLOPPY_DPRINTF("Set interrupt status to 0x%02x\n", fdctrl->status0);
-}
-
-/* Reset controller */
-static void fdctrl_reset(FDCtrl *fdctrl, int do_irq)
-{
-    int i;
-
-    FLOPPY_DPRINTF("reset controller\n");
-    fdctrl_reset_irq(fdctrl);
-    /* Initialise controller */
-    fdctrl->sra = 0;
-    fdctrl->srb = 0xc0;
-    if (!fdctrl->drives[1].bs)
-        fdctrl->sra |= FD_SRA_nDRV2;
-    fdctrl->cur_drv = 0;
-    fdctrl->dor = FD_DOR_nRESET;
-    fdctrl->dor |= (fdctrl->dma_chann != -1) ? FD_DOR_DMAEN : 0;
-    fdctrl->msr = FD_MSR_RQM;
-    /* FIFO state */
-    fdctrl->data_pos = 0;
-    fdctrl->data_len = 0;
-    fdctrl->data_state = 0;
-    fdctrl->data_dir = FD_DIR_WRITE;
-    for (i = 0; i < MAX_FD; i++)
-        fd_recalibrate(&fdctrl->drives[i]);
-    fdctrl_reset_fifo(fdctrl);
-    if (do_irq) {
-        fdctrl->status0 |= FD_SR0_RDYCHG;
-        fdctrl_raise_irq(fdctrl);
-        fdctrl->reset_sensei = FD_RESET_SENSEI_COUNT;
-    }
-}
-
-static inline FDrive *drv0(FDCtrl *fdctrl)
-{
-    return &fdctrl->drives[(fdctrl->tdr & FD_TDR_BOOTSEL) >> 2];
-}
-
-static inline FDrive *drv1(FDCtrl *fdctrl)
-{
-    if ((fdctrl->tdr & FD_TDR_BOOTSEL) < (1 << 2))
-        return &fdctrl->drives[1];
-    else
-        return &fdctrl->drives[0];
-}
-
-#if MAX_FD == 4
-static inline FDrive *drv2(FDCtrl *fdctrl)
-{
-    if ((fdctrl->tdr & FD_TDR_BOOTSEL) < (2 << 2))
-        return &fdctrl->drives[2];
-    else
-        return &fdctrl->drives[1];
-}
-
-static inline FDrive *drv3(FDCtrl *fdctrl)
-{
-    if ((fdctrl->tdr & FD_TDR_BOOTSEL) < (3 << 2))
-        return &fdctrl->drives[3];
-    else
-        return &fdctrl->drives[2];
-}
-#endif
-
-static FDrive *get_cur_drv(FDCtrl *fdctrl)
-{
-    switch (fdctrl->cur_drv) {
-        case 0: return drv0(fdctrl);
-        case 1: return drv1(fdctrl);
-#if MAX_FD == 4
-        case 2: return drv2(fdctrl);
-        case 3: return drv3(fdctrl);
-#endif
-        default: return NULL;
-    }
-}
-
-/* Status A register : 0x00 (read-only) */
-static uint32_t fdctrl_read_statusA(FDCtrl *fdctrl)
-{
-    uint32_t retval = fdctrl->sra;
-
-    FLOPPY_DPRINTF("status register A: 0x%02x\n", retval);
-
-    return retval;
-}
-
-/* Status B register : 0x01 (read-only) */
-static uint32_t fdctrl_read_statusB(FDCtrl *fdctrl)
-{
-    uint32_t retval = fdctrl->srb;
-
-    FLOPPY_DPRINTF("status register B: 0x%02x\n", retval);
-
-    return retval;
-}
-
-/* Digital output register : 0x02 */
-static uint32_t fdctrl_read_dor(FDCtrl *fdctrl)
-{
-    uint32_t retval = fdctrl->dor;
-
-    /* Selected drive */
-    retval |= fdctrl->cur_drv;
-    FLOPPY_DPRINTF("digital output register: 0x%02x\n", retval);
-
-    return retval;
-}
-
-static void fdctrl_write_dor(FDCtrl *fdctrl, uint32_t value)
-{
-    FLOPPY_DPRINTF("digital output register set to 0x%02x\n", value);
-
-    /* Motors */
-    if (value & FD_DOR_MOTEN0)
-        fdctrl->srb |= FD_SRB_MTR0;
-    else
-        fdctrl->srb &= ~FD_SRB_MTR0;
-    if (value & FD_DOR_MOTEN1)
-        fdctrl->srb |= FD_SRB_MTR1;
-    else
-        fdctrl->srb &= ~FD_SRB_MTR1;
-
-    /* Drive */
-    if (value & 1)
-        fdctrl->srb |= FD_SRB_DR0;
-    else
-        fdctrl->srb &= ~FD_SRB_DR0;
-
-    /* Reset */
-    if (!(value & FD_DOR_nRESET)) {
-        if (fdctrl->dor & FD_DOR_nRESET) {
-            FLOPPY_DPRINTF("controller enter RESET state\n");
-        }
-    } else {
-        if (!(fdctrl->dor & FD_DOR_nRESET)) {
-            FLOPPY_DPRINTF("controller out of RESET state\n");
-            fdctrl_reset(fdctrl, 1);
-            fdctrl->dsr &= ~FD_DSR_PWRDOWN;
-        }
-    }
-    /* Selected drive */
-    fdctrl->cur_drv = value & FD_DOR_SELMASK;
-
-    fdctrl->dor = value;
-}
-
-/* Tape drive register : 0x03 */
-static uint32_t fdctrl_read_tape(FDCtrl *fdctrl)
-{
-    uint32_t retval = fdctrl->tdr;
-
-    FLOPPY_DPRINTF("tape drive register: 0x%02x\n", retval);
-
-    return retval;
-}
-
-static void fdctrl_write_tape(FDCtrl *fdctrl, uint32_t value)
-{
-    /* Reset mode */
-    if (!(fdctrl->dor & FD_DOR_nRESET)) {
-        FLOPPY_DPRINTF("Floppy controller in RESET state !\n");
-        return;
-    }
-    FLOPPY_DPRINTF("tape drive register set to 0x%02x\n", value);
-    /* Disk boot selection indicator */
-    fdctrl->tdr = value & FD_TDR_BOOTSEL;
-    /* Tape indicators: never allow */
-}
-
-/* Main status register : 0x04 (read) */
-static uint32_t fdctrl_read_main_status(FDCtrl *fdctrl)
-{
-    uint32_t retval = fdctrl->msr;
-
-    fdctrl->dsr &= ~FD_DSR_PWRDOWN;
-    fdctrl->dor |= FD_DOR_nRESET;
-
-    /* Sparc mutation */
-    if (fdctrl->sun4m) {
-        retval |= FD_MSR_DIO;
-        fdctrl_reset_irq(fdctrl);
-    };
-
-    FLOPPY_DPRINTF("main status register: 0x%02x\n", retval);
-
-    return retval;
-}
-
-/* Data select rate register : 0x04 (write) */
-static void fdctrl_write_rate(FDCtrl *fdctrl, uint32_t value)
-{
-    /* Reset mode */
-    if (!(fdctrl->dor & FD_DOR_nRESET)) {
-        FLOPPY_DPRINTF("Floppy controller in RESET state !\n");
-        return;
-    }
-    FLOPPY_DPRINTF("select rate register set to 0x%02x\n", value);
-    /* Reset: autoclear */
-    if (value & FD_DSR_SWRESET) {
-        fdctrl->dor &= ~FD_DOR_nRESET;
-        fdctrl_reset(fdctrl, 1);
-        fdctrl->dor |= FD_DOR_nRESET;
-    }
-    if (value & FD_DSR_PWRDOWN) {
-        fdctrl_reset(fdctrl, 1);
-    }
-    fdctrl->dsr = value;
-}
-
-/* Configuration control register: 0x07 (write) */
-static void fdctrl_write_ccr(FDCtrl *fdctrl, uint32_t value)
-{
-    /* Reset mode */
-    if (!(fdctrl->dor & FD_DOR_nRESET)) {
-        FLOPPY_DPRINTF("Floppy controller in RESET state !\n");
-        return;
-    }
-    FLOPPY_DPRINTF("configuration control register set to 0x%02x\n", value);
-
-    /* Only the rate selection bits used in AT mode, and we
-     * store those in the DSR.
-     */
-    fdctrl->dsr = (fdctrl->dsr & ~FD_DSR_DRATEMASK) |
-                  (value & FD_DSR_DRATEMASK);
-}
-
-static int fdctrl_media_changed(FDrive *drv)
-{
-    return drv->media_changed;
-}
-
-/* Digital input register : 0x07 (read-only) */
-static uint32_t fdctrl_read_dir(FDCtrl *fdctrl)
-{
-    uint32_t retval = 0;
-
-    if (fdctrl_media_changed(get_cur_drv(fdctrl))) {
-        retval |= FD_DIR_DSKCHG;
-    }
-    if (retval != 0) {
-        FLOPPY_DPRINTF("Floppy digital input register: 0x%02x\n", retval);
-    }
-
-    return retval;
-}
-
-/* FIFO state control */
-static void fdctrl_reset_fifo(FDCtrl *fdctrl)
-{
-    fdctrl->data_dir = FD_DIR_WRITE;
-    fdctrl->data_pos = 0;
-    fdctrl->msr &= ~(FD_MSR_CMDBUSY | FD_MSR_DIO);
-}
-
-/* Set FIFO status for the host to read */
-static void fdctrl_set_fifo(FDCtrl *fdctrl, int fifo_len)
-{
-    fdctrl->data_dir = FD_DIR_READ;
-    fdctrl->data_len = fifo_len;
-    fdctrl->data_pos = 0;
-    fdctrl->msr |= FD_MSR_CMDBUSY | FD_MSR_RQM | FD_MSR_DIO;
-}
-
-/* Set an error: unimplemented/unknown command */
-static void fdctrl_unimplemented(FDCtrl *fdctrl, int direction)
-{
-    qemu_log_mask(LOG_UNIMP, "fdc: unimplemented command 0x%02x\n",
-                  fdctrl->fifo[0]);
-    fdctrl->fifo[0] = FD_SR0_INVCMD;
-    fdctrl_set_fifo(fdctrl, 1);
-}
-
-/* Seek to next sector
- * returns 0 when end of track reached (for DBL_SIDES on head 1)
- * otherwise returns 1
- */
-static int fdctrl_seek_to_next_sect(FDCtrl *fdctrl, FDrive *cur_drv)
-{
-    FLOPPY_DPRINTF("seek to next sector (%d %02x %02x => %d)\n",
-                   cur_drv->head, cur_drv->track, cur_drv->sect,
-                   fd_sector(cur_drv));
-    /* XXX: cur_drv->sect >= cur_drv->last_sect should be an
-       error in fact */
-    uint8_t new_head = cur_drv->head;
-    uint8_t new_track = cur_drv->track;
-    uint8_t new_sect = cur_drv->sect;
-
-    int ret = 1;
-
-    if (new_sect >= cur_drv->last_sect ||
-        new_sect == fdctrl->eot) {
-        new_sect = 1;
-        if (FD_MULTI_TRACK(fdctrl->data_state)) {
-            if (new_head == 0 &&
-                (cur_drv->flags & FDISK_DBL_SIDES) != 0) {
-                new_head = 1;
-            } else {
-                new_head = 0;
-                new_track++;
-                fdctrl->status0 |= FD_SR0_SEEK;
-                if ((cur_drv->flags & FDISK_DBL_SIDES) == 0) {
-                    ret = 0;
-                }
-            }
-        } else {
-            fdctrl->status0 |= FD_SR0_SEEK;
-            new_track++;
-            ret = 0;
-        }
-        if (ret == 1) {
-            FLOPPY_DPRINTF("seek to next track (%d %02x %02x => %d)\n",
-                    new_head, new_track, new_sect, fd_sector(cur_drv));
-        }
-    } else {
-        new_sect++;
-    }
-    fd_seek(cur_drv, new_head, new_track, new_sect, 1);
-    return ret;
-}
-
-/* Callback for transfer end (stop or abort) */
-static void fdctrl_stop_transfer(FDCtrl *fdctrl, uint8_t status0,
-                                 uint8_t status1, uint8_t status2)
-{
-    FDrive *cur_drv;
-    cur_drv = get_cur_drv(fdctrl);
-
-    fdctrl->status0 &= ~(FD_SR0_DS0 | FD_SR0_DS1 | FD_SR0_HEAD);
-    fdctrl->status0 |= GET_CUR_DRV(fdctrl);
-    if (cur_drv->head) {
-        fdctrl->status0 |= FD_SR0_HEAD;
-    }
-    fdctrl->status0 |= status0;
-
-    FLOPPY_DPRINTF("transfer status: %02x %02x %02x (%02x)\n",
-                   status0, status1, status2, fdctrl->status0);
-    fdctrl->fifo[0] = fdctrl->status0;
-    fdctrl->fifo[1] = status1;
-    fdctrl->fifo[2] = status2;
-    fdctrl->fifo[3] = cur_drv->track;
-    fdctrl->fifo[4] = cur_drv->head;
-    fdctrl->fifo[5] = cur_drv->sect;
-    fdctrl->fifo[6] = FD_SECTOR_SC;
-    fdctrl->data_dir = FD_DIR_READ;
-    if (!(fdctrl->msr & FD_MSR_NONDMA)) {
-        DMA_release_DREQ(fdctrl->dma_chann);
-    }
-    fdctrl->msr |= FD_MSR_RQM | FD_MSR_DIO;
-    fdctrl->msr &= ~FD_MSR_NONDMA;
-
-    fdctrl_set_fifo(fdctrl, 7);
-    fdctrl_raise_irq(fdctrl);
-}
-
-/* Prepare a data transfer (either DMA or FIFO) */
-static void fdctrl_start_transfer(FDCtrl *fdctrl, int direction)
-{
-    FDrive *cur_drv;
-    uint8_t kh, kt, ks;
-
-    SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
-    cur_drv = get_cur_drv(fdctrl);
-    kt = fdctrl->fifo[2];
-    kh = fdctrl->fifo[3];
-    ks = fdctrl->fifo[4];
-    FLOPPY_DPRINTF("Start transfer at %d %d %02x %02x (%d)\n",
-                   GET_CUR_DRV(fdctrl), kh, kt, ks,
-                   fd_sector_calc(kh, kt, ks, cur_drv->last_sect,
-                                  NUM_SIDES(cur_drv)));
-    switch (fd_seek(cur_drv, kh, kt, ks, fdctrl->config & FD_CONFIG_EIS)) {
-    case 2:
-        /* sect too big */
-        fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, 0x00, 0x00);
-        fdctrl->fifo[3] = kt;
-        fdctrl->fifo[4] = kh;
-        fdctrl->fifo[5] = ks;
-        return;
-    case 3:
-        /* track too big */
-        fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, FD_SR1_EC, 0x00);
-        fdctrl->fifo[3] = kt;
-        fdctrl->fifo[4] = kh;
-        fdctrl->fifo[5] = ks;
-        return;
-    case 4:
-        /* No seek enabled */
-        fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, 0x00, 0x00);
-        fdctrl->fifo[3] = kt;
-        fdctrl->fifo[4] = kh;
-        fdctrl->fifo[5] = ks;
-        return;
-    case 1:
-        fdctrl->status0 |= FD_SR0_SEEK;
-        break;
-    default:
-        break;
-    }
-
-    /* Check the data rate. If the programmed data rate does not match
-     * the currently inserted medium, the operation has to fail. */
-    if (fdctrl->check_media_rate &&
-        (fdctrl->dsr & FD_DSR_DRATEMASK) != cur_drv->media_rate) {
-        FLOPPY_DPRINTF("data rate mismatch (fdc=%d, media=%d)\n",
-                       fdctrl->dsr & FD_DSR_DRATEMASK, cur_drv->media_rate);
-        fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, FD_SR1_MA, 0x00);
-        fdctrl->fifo[3] = kt;
-        fdctrl->fifo[4] = kh;
-        fdctrl->fifo[5] = ks;
-        return;
-    }
-
-    /* Set the FIFO state */
-    fdctrl->data_dir = direction;
-    fdctrl->data_pos = 0;
-    assert(fdctrl->msr & FD_MSR_CMDBUSY);
-    if (fdctrl->fifo[0] & 0x80)
-        fdctrl->data_state |= FD_STATE_MULTI;
-    else
-        fdctrl->data_state &= ~FD_STATE_MULTI;
-    if (fdctrl->fifo[5] == 0) {
-        fdctrl->data_len = fdctrl->fifo[8];
-    } else {
-        int tmp;
-        fdctrl->data_len = 128 << (fdctrl->fifo[5] > 7 ? 7 : fdctrl->fifo[5]);
-        tmp = (fdctrl->fifo[6] - ks + 1);
-        if (fdctrl->fifo[0] & 0x80)
-            tmp += fdctrl->fifo[6];
-        fdctrl->data_len *= tmp;
-    }
-    fdctrl->eot = fdctrl->fifo[6];
-    if (fdctrl->dor & FD_DOR_DMAEN) {
-        int dma_mode;
-        /* DMA transfer are enabled. Check if DMA channel is well programmed */
-        dma_mode = DMA_get_channel_mode(fdctrl->dma_chann);
-        dma_mode = (dma_mode >> 2) & 3;
-        FLOPPY_DPRINTF("dma_mode=%d direction=%d (%d - %d)\n",
-                       dma_mode, direction,
-                       (128 << fdctrl->fifo[5]) *
-                       (cur_drv->last_sect - ks + 1), fdctrl->data_len);
-        if (((direction == FD_DIR_SCANE || direction == FD_DIR_SCANL ||
-              direction == FD_DIR_SCANH) && dma_mode == 0) ||
-            (direction == FD_DIR_WRITE && dma_mode == 2) ||
-            (direction == FD_DIR_READ && dma_mode == 1) ||
-            (direction == FD_DIR_VERIFY)) {
-            /* No access is allowed until DMA transfer has completed */
-            fdctrl->msr &= ~FD_MSR_RQM;
-            if (direction != FD_DIR_VERIFY) {
-                /* Now, we just have to wait for the DMA controller to
-                 * recall us...
-                 */
-                DMA_hold_DREQ(fdctrl->dma_chann);
-                DMA_schedule(fdctrl->dma_chann);
-            } else {
-                /* Start transfer */
-                fdctrl_transfer_handler(fdctrl, fdctrl->dma_chann, 0,
-                                        fdctrl->data_len);
-            }
-            return;
-        } else {
-            FLOPPY_DPRINTF("bad dma_mode=%d direction=%d\n", dma_mode,
-                           direction);
-        }
-    }
-    FLOPPY_DPRINTF("start non-DMA transfer\n");
-    fdctrl->msr |= FD_MSR_NONDMA;
-    if (direction != FD_DIR_WRITE)
-        fdctrl->msr |= FD_MSR_DIO;
-    /* IO based transfer: calculate len */
-    fdctrl_raise_irq(fdctrl);
-}
-
-/* Prepare a transfer of deleted data */
-static void fdctrl_start_transfer_del(FDCtrl *fdctrl, int direction)
-{
-    qemu_log_mask(LOG_UNIMP, "fdctrl_start_transfer_del() unimplemented\n");
-
-    /* We don't handle deleted data,
-     * so we don't return *ANYTHING*
-     */
-    fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM | FD_SR0_SEEK, 0x00, 0x00);
-}
-
-/* handlers for DMA transfers */
-static int fdctrl_transfer_handler (void *opaque, int nchan,
-                                    int dma_pos, int dma_len)
-{
-    FDCtrl *fdctrl;
-    FDrive *cur_drv;
-    int len, start_pos, rel_pos;
-    uint8_t status0 = 0x00, status1 = 0x00, status2 = 0x00;
-
-    fdctrl = opaque;
-    if (fdctrl->msr & FD_MSR_RQM) {
-        FLOPPY_DPRINTF("Not in DMA transfer mode !\n");
-        return 0;
-    }
-    cur_drv = get_cur_drv(fdctrl);
-    if (fdctrl->data_dir == FD_DIR_SCANE || fdctrl->data_dir == FD_DIR_SCANL ||
-        fdctrl->data_dir == FD_DIR_SCANH)
-        status2 = FD_SR2_SNS;
-    if (dma_len > fdctrl->data_len)
-        dma_len = fdctrl->data_len;
-    if (cur_drv->bs == NULL) {
-        if (fdctrl->data_dir == FD_DIR_WRITE)
-            fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM | FD_SR0_SEEK, 0x00, 0x00);
-        else
-            fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, 0x00, 0x00);
-        len = 0;
-        goto transfer_error;
-    }
-    rel_pos = fdctrl->data_pos % FD_SECTOR_LEN;
-    for (start_pos = fdctrl->data_pos; fdctrl->data_pos < dma_len;) {
-        len = dma_len - fdctrl->data_pos;
-        if (len + rel_pos > FD_SECTOR_LEN)
-            len = FD_SECTOR_LEN - rel_pos;
-        FLOPPY_DPRINTF("copy %d bytes (%d %d %d) %d pos %d %02x "
-                       "(%d-0x%08x 0x%08x)\n", len, dma_len, fdctrl->data_pos,
-                       fdctrl->data_len, GET_CUR_DRV(fdctrl), cur_drv->head,
-                       cur_drv->track, cur_drv->sect, fd_sector(cur_drv),
-                       fd_sector(cur_drv) * FD_SECTOR_LEN);
-        if (fdctrl->data_dir != FD_DIR_WRITE ||
-            len < FD_SECTOR_LEN || rel_pos != 0) {
-            /* READ & SCAN commands and realign to a sector for WRITE */
-            if (bdrv_read(cur_drv->bs, fd_sector(cur_drv),
-                          fdctrl->fifo, 1) < 0) {
-                FLOPPY_DPRINTF("Floppy: error getting sector %d\n",
-                               fd_sector(cur_drv));
-                /* Sure, image size is too small... */
-                memset(fdctrl->fifo, 0, FD_SECTOR_LEN);
-            }
-        }
-        switch (fdctrl->data_dir) {
-        case FD_DIR_READ:
-            /* READ commands */
-            DMA_write_memory (nchan, fdctrl->fifo + rel_pos,
-                              fdctrl->data_pos, len);
-            break;
-        case FD_DIR_WRITE:
-            /* WRITE commands */
-            if (cur_drv->ro) {
-                /* Handle readonly medium early, no need to do DMA, touch the
-                 * LED or attempt any writes. A real floppy doesn't attempt
-                 * to write to readonly media either. */
-                fdctrl_stop_transfer(fdctrl,
-                                     FD_SR0_ABNTERM | FD_SR0_SEEK, FD_SR1_NW,
-                                     0x00);
-                goto transfer_error;
-            }
-
-            DMA_read_memory (nchan, fdctrl->fifo + rel_pos,
-                             fdctrl->data_pos, len);
-            if (bdrv_write(cur_drv->bs, fd_sector(cur_drv),
-                           fdctrl->fifo, 1) < 0) {
-                FLOPPY_DPRINTF("error writing sector %d\n",
-                               fd_sector(cur_drv));
-                fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM | FD_SR0_SEEK, 0x00, 0x00);
-                goto transfer_error;
-            }
-            break;
-        case FD_DIR_VERIFY:
-            /* VERIFY commands */
-            break;
-        default:
-            /* SCAN commands */
-            {
-                uint8_t tmpbuf[FD_SECTOR_LEN];
-                int ret;
-                DMA_read_memory (nchan, tmpbuf, fdctrl->data_pos, len);
-                ret = memcmp(tmpbuf, fdctrl->fifo + rel_pos, len);
-                if (ret == 0) {
-                    status2 = FD_SR2_SEH;
-                    goto end_transfer;
-                }
-                if ((ret < 0 && fdctrl->data_dir == FD_DIR_SCANL) ||
-                    (ret > 0 && fdctrl->data_dir == FD_DIR_SCANH)) {
-                    status2 = 0x00;
-                    goto end_transfer;
-                }
-            }
-            break;
-        }
-        fdctrl->data_pos += len;
-        rel_pos = fdctrl->data_pos % FD_SECTOR_LEN;
-        if (rel_pos == 0) {
-            /* Seek to next sector */
-            if (!fdctrl_seek_to_next_sect(fdctrl, cur_drv))
-                break;
-        }
-    }
- end_transfer:
-    len = fdctrl->data_pos - start_pos;
-    FLOPPY_DPRINTF("end transfer %d %d %d\n",
-                   fdctrl->data_pos, len, fdctrl->data_len);
-    if (fdctrl->data_dir == FD_DIR_SCANE ||
-        fdctrl->data_dir == FD_DIR_SCANL ||
-        fdctrl->data_dir == FD_DIR_SCANH)
-        status2 = FD_SR2_SEH;
-    fdctrl->data_len -= len;
-    fdctrl_stop_transfer(fdctrl, status0, status1, status2);
- transfer_error:
-
-    return len;
-}
-
-/* Data register : 0x05 */
-static uint32_t fdctrl_read_data(FDCtrl *fdctrl)
-{
-    FDrive *cur_drv;
-    uint32_t retval = 0;
-    int pos;
-
-    cur_drv = get_cur_drv(fdctrl);
-    fdctrl->dsr &= ~FD_DSR_PWRDOWN;
-    if (!(fdctrl->msr & FD_MSR_RQM) || !(fdctrl->msr & FD_MSR_DIO)) {
-        FLOPPY_DPRINTF("error: controller not ready for reading\n");
-        return 0;
-    }
-    pos = fdctrl->data_pos;
-    if (fdctrl->msr & FD_MSR_NONDMA) {
-        pos %= FD_SECTOR_LEN;
-        if (pos == 0) {
-            if (fdctrl->data_pos != 0)
-                if (!fdctrl_seek_to_next_sect(fdctrl, cur_drv)) {
-                    FLOPPY_DPRINTF("error seeking to next sector %d\n",
-                                   fd_sector(cur_drv));
-                    return 0;
-                }
-            if (bdrv_read(cur_drv->bs, fd_sector(cur_drv), fdctrl->fifo, 1) < 0) {
-                FLOPPY_DPRINTF("error getting sector %d\n",
-                               fd_sector(cur_drv));
-                /* Sure, image size is too small... */
-                memset(fdctrl->fifo, 0, FD_SECTOR_LEN);
-            }
-        }
-    }
-    retval = fdctrl->fifo[pos];
-    if (++fdctrl->data_pos == fdctrl->data_len) {
-        fdctrl->data_pos = 0;
-        /* Switch from transfer mode to status mode
-         * then from status mode to command mode
-         */
-        if (fdctrl->msr & FD_MSR_NONDMA) {
-            fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
-        } else {
-            fdctrl_reset_fifo(fdctrl);
-            fdctrl_reset_irq(fdctrl);
-        }
-    }
-    FLOPPY_DPRINTF("data register: 0x%02x\n", retval);
-
-    return retval;
-}
-
-static void fdctrl_format_sector(FDCtrl *fdctrl)
-{
-    FDrive *cur_drv;
-    uint8_t kh, kt, ks;
-
-    SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
-    cur_drv = get_cur_drv(fdctrl);
-    kt = fdctrl->fifo[6];
-    kh = fdctrl->fifo[7];
-    ks = fdctrl->fifo[8];
-    FLOPPY_DPRINTF("format sector at %d %d %02x %02x (%d)\n",
-                   GET_CUR_DRV(fdctrl), kh, kt, ks,
-                   fd_sector_calc(kh, kt, ks, cur_drv->last_sect,
-                                  NUM_SIDES(cur_drv)));
-    switch (fd_seek(cur_drv, kh, kt, ks, fdctrl->config & FD_CONFIG_EIS)) {
-    case 2:
-        /* sect too big */
-        fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, 0x00, 0x00);
-        fdctrl->fifo[3] = kt;
-        fdctrl->fifo[4] = kh;
-        fdctrl->fifo[5] = ks;
-        return;
-    case 3:
-        /* track too big */
-        fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, FD_SR1_EC, 0x00);
-        fdctrl->fifo[3] = kt;
-        fdctrl->fifo[4] = kh;
-        fdctrl->fifo[5] = ks;
-        return;
-    case 4:
-        /* No seek enabled */
-        fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, 0x00, 0x00);
-        fdctrl->fifo[3] = kt;
-        fdctrl->fifo[4] = kh;
-        fdctrl->fifo[5] = ks;
-        return;
-    case 1:
-        fdctrl->status0 |= FD_SR0_SEEK;
-        break;
-    default:
-        break;
-    }
-    memset(fdctrl->fifo, 0, FD_SECTOR_LEN);
-    if (cur_drv->bs == NULL ||
-        bdrv_write(cur_drv->bs, fd_sector(cur_drv), fdctrl->fifo, 1) < 0) {
-        FLOPPY_DPRINTF("error formatting sector %d\n", fd_sector(cur_drv));
-        fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM | FD_SR0_SEEK, 0x00, 0x00);
-    } else {
-        if (cur_drv->sect == cur_drv->last_sect) {
-            fdctrl->data_state &= ~FD_STATE_FORMAT;
-            /* Last sector done */
-            fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
-        } else {
-            /* More to do */
-            fdctrl->data_pos = 0;
-            fdctrl->data_len = 4;
-        }
-    }
-}
-
-static void fdctrl_handle_lock(FDCtrl *fdctrl, int direction)
-{
-    fdctrl->lock = (fdctrl->fifo[0] & 0x80) ? 1 : 0;
-    fdctrl->fifo[0] = fdctrl->lock << 4;
-    fdctrl_set_fifo(fdctrl, 1);
-}
-
-static void fdctrl_handle_dumpreg(FDCtrl *fdctrl, int direction)
-{
-    FDrive *cur_drv = get_cur_drv(fdctrl);
-
-    /* Drives position */
-    fdctrl->fifo[0] = drv0(fdctrl)->track;
-    fdctrl->fifo[1] = drv1(fdctrl)->track;
-#if MAX_FD == 4
-    fdctrl->fifo[2] = drv2(fdctrl)->track;
-    fdctrl->fifo[3] = drv3(fdctrl)->track;
-#else
-    fdctrl->fifo[2] = 0;
-    fdctrl->fifo[3] = 0;
-#endif
-    /* timers */
-    fdctrl->fifo[4] = fdctrl->timer0;
-    fdctrl->fifo[5] = (fdctrl->timer1 << 1) | (fdctrl->dor & FD_DOR_DMAEN ? 1 : 0);
-    fdctrl->fifo[6] = cur_drv->last_sect;
-    fdctrl->fifo[7] = (fdctrl->lock << 7) |
-        (cur_drv->perpendicular << 2);
-    fdctrl->fifo[8] = fdctrl->config;
-    fdctrl->fifo[9] = fdctrl->precomp_trk;
-    fdctrl_set_fifo(fdctrl, 10);
-}
-
-static void fdctrl_handle_version(FDCtrl *fdctrl, int direction)
-{
-    /* Controller's version */
-    fdctrl->fifo[0] = fdctrl->version;
-    fdctrl_set_fifo(fdctrl, 1);
-}
-
-static void fdctrl_handle_partid(FDCtrl *fdctrl, int direction)
-{
-    fdctrl->fifo[0] = 0x41; /* Stepping 1 */
-    fdctrl_set_fifo(fdctrl, 1);
-}
-
-static void fdctrl_handle_restore(FDCtrl *fdctrl, int direction)
-{
-    FDrive *cur_drv = get_cur_drv(fdctrl);
-
-    /* Drives position */
-    drv0(fdctrl)->track = fdctrl->fifo[3];
-    drv1(fdctrl)->track = fdctrl->fifo[4];
-#if MAX_FD == 4
-    drv2(fdctrl)->track = fdctrl->fifo[5];
-    drv3(fdctrl)->track = fdctrl->fifo[6];
-#endif
-    /* timers */
-    fdctrl->timer0 = fdctrl->fifo[7];
-    fdctrl->timer1 = fdctrl->fifo[8];
-    cur_drv->last_sect = fdctrl->fifo[9];
-    fdctrl->lock = fdctrl->fifo[10] >> 7;
-    cur_drv->perpendicular = (fdctrl->fifo[10] >> 2) & 0xF;
-    fdctrl->config = fdctrl->fifo[11];
-    fdctrl->precomp_trk = fdctrl->fifo[12];
-    fdctrl->pwrd = fdctrl->fifo[13];
-    fdctrl_reset_fifo(fdctrl);
-}
-
-static void fdctrl_handle_save(FDCtrl *fdctrl, int direction)
-{
-    FDrive *cur_drv = get_cur_drv(fdctrl);
-
-    fdctrl->fifo[0] = 0;
-    fdctrl->fifo[1] = 0;
-    /* Drives position */
-    fdctrl->fifo[2] = drv0(fdctrl)->track;
-    fdctrl->fifo[3] = drv1(fdctrl)->track;
-#if MAX_FD == 4
-    fdctrl->fifo[4] = drv2(fdctrl)->track;
-    fdctrl->fifo[5] = drv3(fdctrl)->track;
-#else
-    fdctrl->fifo[4] = 0;
-    fdctrl->fifo[5] = 0;
-#endif
-    /* timers */
-    fdctrl->fifo[6] = fdctrl->timer0;
-    fdctrl->fifo[7] = fdctrl->timer1;
-    fdctrl->fifo[8] = cur_drv->last_sect;
-    fdctrl->fifo[9] = (fdctrl->lock << 7) |
-        (cur_drv->perpendicular << 2);
-    fdctrl->fifo[10] = fdctrl->config;
-    fdctrl->fifo[11] = fdctrl->precomp_trk;
-    fdctrl->fifo[12] = fdctrl->pwrd;
-    fdctrl->fifo[13] = 0;
-    fdctrl->fifo[14] = 0;
-    fdctrl_set_fifo(fdctrl, 15);
-}
-
-static void fdctrl_handle_readid(FDCtrl *fdctrl, int direction)
-{
-    FDrive *cur_drv = get_cur_drv(fdctrl);
-
-    cur_drv->head = (fdctrl->fifo[1] >> 2) & 1;
-    qemu_mod_timer(fdctrl->result_timer,
-                   qemu_get_clock_ns(vm_clock) + (get_ticks_per_sec() / 50));
-}
-
-static void fdctrl_handle_format_track(FDCtrl *fdctrl, int direction)
-{
-    FDrive *cur_drv;
-
-    SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
-    cur_drv = get_cur_drv(fdctrl);
-    fdctrl->data_state |= FD_STATE_FORMAT;
-    if (fdctrl->fifo[0] & 0x80)
-        fdctrl->data_state |= FD_STATE_MULTI;
-    else
-        fdctrl->data_state &= ~FD_STATE_MULTI;
-    cur_drv->bps =
-        fdctrl->fifo[2] > 7 ? 16384 : 128 << fdctrl->fifo[2];
-#if 0
-    cur_drv->last_sect =
-        cur_drv->flags & FDISK_DBL_SIDES ? fdctrl->fifo[3] :
-        fdctrl->fifo[3] / 2;
-#else
-    cur_drv->last_sect = fdctrl->fifo[3];
-#endif
-    /* TODO: implement format using DMA expected by the Bochs BIOS
-     * and Linux fdformat (read 3 bytes per sector via DMA and fill
-     * the sector with the specified fill byte
-     */
-    fdctrl->data_state &= ~FD_STATE_FORMAT;
-    fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
-}
-
-static void fdctrl_handle_specify(FDCtrl *fdctrl, int direction)
-{
-    fdctrl->timer0 = (fdctrl->fifo[1] >> 4) & 0xF;
-    fdctrl->timer1 = fdctrl->fifo[2] >> 1;
-    if (fdctrl->fifo[2] & 1)
-        fdctrl->dor &= ~FD_DOR_DMAEN;
-    else
-        fdctrl->dor |= FD_DOR_DMAEN;
-    /* No result back */
-    fdctrl_reset_fifo(fdctrl);
-}
-
-static void fdctrl_handle_sense_drive_status(FDCtrl *fdctrl, int direction)
-{
-    FDrive *cur_drv;
-
-    SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
-    cur_drv = get_cur_drv(fdctrl);
-    cur_drv->head = (fdctrl->fifo[1] >> 2) & 1;
-    /* 1 Byte status back */
-    fdctrl->fifo[0] = (cur_drv->ro << 6) |
-        (cur_drv->track == 0 ? 0x10 : 0x00) |
-        (cur_drv->head << 2) |
-        GET_CUR_DRV(fdctrl) |
-        0x28;
-    fdctrl_set_fifo(fdctrl, 1);
-}
-
-static void fdctrl_handle_recalibrate(FDCtrl *fdctrl, int direction)
-{
-    FDrive *cur_drv;
-
-    SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
-    cur_drv = get_cur_drv(fdctrl);
-    fd_recalibrate(cur_drv);
-    fdctrl_reset_fifo(fdctrl);
-    /* Raise Interrupt */
-    fdctrl->status0 |= FD_SR0_SEEK;
-    fdctrl_raise_irq(fdctrl);
-}
-
-static void fdctrl_handle_sense_interrupt_status(FDCtrl *fdctrl, int direction)
-{
-    FDrive *cur_drv = get_cur_drv(fdctrl);
-
-    if (fdctrl->reset_sensei > 0) {
-        fdctrl->fifo[0] =
-            FD_SR0_RDYCHG + FD_RESET_SENSEI_COUNT - fdctrl->reset_sensei;
-        fdctrl->reset_sensei--;
-    } else if (!(fdctrl->sra & FD_SRA_INTPEND)) {
-        fdctrl->fifo[0] = FD_SR0_INVCMD;
-        fdctrl_set_fifo(fdctrl, 1);
-        return;
-    } else {
-        fdctrl->fifo[0] =
-                (fdctrl->status0 & ~(FD_SR0_HEAD | FD_SR0_DS1 | FD_SR0_DS0))
-                | GET_CUR_DRV(fdctrl);
-    }
-
-    fdctrl->fifo[1] = cur_drv->track;
-    fdctrl_set_fifo(fdctrl, 2);
-    fdctrl_reset_irq(fdctrl);
-    fdctrl->status0 = FD_SR0_RDYCHG;
-}
-
-static void fdctrl_handle_seek(FDCtrl *fdctrl, int direction)
-{
-    FDrive *cur_drv;
-
-    SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
-    cur_drv = get_cur_drv(fdctrl);
-    fdctrl_reset_fifo(fdctrl);
-    /* The seek command just sends step pulses to the drive and doesn't care if
-     * there is a medium inserted of if it's banging the head against the drive.
-     */
-    fd_seek(cur_drv, cur_drv->head, fdctrl->fifo[2], cur_drv->sect, 1);
-    /* Raise Interrupt */
-    fdctrl->status0 |= FD_SR0_SEEK;
-    fdctrl_raise_irq(fdctrl);
-}
-
-static void fdctrl_handle_perpendicular_mode(FDCtrl *fdctrl, int direction)
-{
-    FDrive *cur_drv = get_cur_drv(fdctrl);
-
-    if (fdctrl->fifo[1] & 0x80)
-        cur_drv->perpendicular = fdctrl->fifo[1] & 0x7;
-    /* No result back */
-    fdctrl_reset_fifo(fdctrl);
-}
-
-static void fdctrl_handle_configure(FDCtrl *fdctrl, int direction)
-{
-    fdctrl->config = fdctrl->fifo[2];
-    fdctrl->precomp_trk =  fdctrl->fifo[3];
-    /* No result back */
-    fdctrl_reset_fifo(fdctrl);
-}
-
-static void fdctrl_handle_powerdown_mode(FDCtrl *fdctrl, int direction)
-{
-    fdctrl->pwrd = fdctrl->fifo[1];
-    fdctrl->fifo[0] = fdctrl->fifo[1];
-    fdctrl_set_fifo(fdctrl, 1);
-}
-
-static void fdctrl_handle_option(FDCtrl *fdctrl, int direction)
-{
-    /* No result back */
-    fdctrl_reset_fifo(fdctrl);
-}
-
-static void fdctrl_handle_drive_specification_command(FDCtrl *fdctrl, int direction)
-{
-    FDrive *cur_drv = get_cur_drv(fdctrl);
-
-    if (fdctrl->fifo[fdctrl->data_pos - 1] & 0x80) {
-        /* Command parameters done */
-        if (fdctrl->fifo[fdctrl->data_pos - 1] & 0x40) {
-            fdctrl->fifo[0] = fdctrl->fifo[1];
-            fdctrl->fifo[2] = 0;
-            fdctrl->fifo[3] = 0;
-            fdctrl_set_fifo(fdctrl, 4);
-        } else {
-            fdctrl_reset_fifo(fdctrl);
-        }
-    } else if (fdctrl->data_len > 7) {
-        /* ERROR */
-        fdctrl->fifo[0] = 0x80 |
-            (cur_drv->head << 2) | GET_CUR_DRV(fdctrl);
-        fdctrl_set_fifo(fdctrl, 1);
-    }
-}
-
-static void fdctrl_handle_relative_seek_in(FDCtrl *fdctrl, int direction)
-{
-    FDrive *cur_drv;
-
-    SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
-    cur_drv = get_cur_drv(fdctrl);
-    if (fdctrl->fifo[2] + cur_drv->track >= cur_drv->max_track) {
-        fd_seek(cur_drv, cur_drv->head, cur_drv->max_track - 1,
-                cur_drv->sect, 1);
-    } else {
-        fd_seek(cur_drv, cur_drv->head,
-                cur_drv->track + fdctrl->fifo[2], cur_drv->sect, 1);
-    }
-    fdctrl_reset_fifo(fdctrl);
-    /* Raise Interrupt */
-    fdctrl->status0 |= FD_SR0_SEEK;
-    fdctrl_raise_irq(fdctrl);
-}
-
-static void fdctrl_handle_relative_seek_out(FDCtrl *fdctrl, int direction)
-{
-    FDrive *cur_drv;
-
-    SET_CUR_DRV(fdctrl, fdctrl->fifo[1] & FD_DOR_SELMASK);
-    cur_drv = get_cur_drv(fdctrl);
-    if (fdctrl->fifo[2] > cur_drv->track) {
-        fd_seek(cur_drv, cur_drv->head, 0, cur_drv->sect, 1);
-    } else {
-        fd_seek(cur_drv, cur_drv->head,
-                cur_drv->track - fdctrl->fifo[2], cur_drv->sect, 1);
-    }
-    fdctrl_reset_fifo(fdctrl);
-    /* Raise Interrupt */
-    fdctrl->status0 |= FD_SR0_SEEK;
-    fdctrl_raise_irq(fdctrl);
-}
-
-static const struct {
-    uint8_t value;
-    uint8_t mask;
-    const char* name;
-    int parameters;
-    void (*handler)(FDCtrl *fdctrl, int direction);
-    int direction;
-} handlers[] = {
-    { FD_CMD_READ, 0x1f, "READ", 8, fdctrl_start_transfer, FD_DIR_READ },
-    { FD_CMD_WRITE, 0x3f, "WRITE", 8, fdctrl_start_transfer, FD_DIR_WRITE },
-    { FD_CMD_SEEK, 0xff, "SEEK", 2, fdctrl_handle_seek },
-    { FD_CMD_SENSE_INTERRUPT_STATUS, 0xff, "SENSE INTERRUPT STATUS", 0, fdctrl_handle_sense_interrupt_status },
-    { FD_CMD_RECALIBRATE, 0xff, "RECALIBRATE", 1, fdctrl_handle_recalibrate },
-    { FD_CMD_FORMAT_TRACK, 0xbf, "FORMAT TRACK", 5, fdctrl_handle_format_track },
-    { FD_CMD_READ_TRACK, 0xbf, "READ TRACK", 8, fdctrl_start_transfer, FD_DIR_READ },
-    { FD_CMD_RESTORE, 0xff, "RESTORE", 17, fdctrl_handle_restore }, /* part of READ DELETED DATA */
-    { FD_CMD_SAVE, 0xff, "SAVE", 0, fdctrl_handle_save }, /* part of READ DELETED DATA */
-    { FD_CMD_READ_DELETED, 0x1f, "READ DELETED DATA", 8, fdctrl_start_transfer_del, FD_DIR_READ },
-    { FD_CMD_SCAN_EQUAL, 0x1f, "SCAN EQUAL", 8, fdctrl_start_transfer, FD_DIR_SCANE },
-    { FD_CMD_VERIFY, 0x1f, "VERIFY", 8, fdctrl_start_transfer, FD_DIR_VERIFY },
-    { FD_CMD_SCAN_LOW_OR_EQUAL, 0x1f, "SCAN LOW OR EQUAL", 8, fdctrl_start_transfer, FD_DIR_SCANL },
-    { FD_CMD_SCAN_HIGH_OR_EQUAL, 0x1f, "SCAN HIGH OR EQUAL", 8, fdctrl_start_transfer, FD_DIR_SCANH },
-    { FD_CMD_WRITE_DELETED, 0x3f, "WRITE DELETED DATA", 8, fdctrl_start_transfer_del, FD_DIR_WRITE },
-    { FD_CMD_READ_ID, 0xbf, "READ ID", 1, fdctrl_handle_readid },
-    { FD_CMD_SPECIFY, 0xff, "SPECIFY", 2, fdctrl_handle_specify },
-    { FD_CMD_SENSE_DRIVE_STATUS, 0xff, "SENSE DRIVE STATUS", 1, fdctrl_handle_sense_drive_status },
-    { FD_CMD_PERPENDICULAR_MODE, 0xff, "PERPENDICULAR MODE", 1, fdctrl_handle_perpendicular_mode },
-    { FD_CMD_CONFIGURE, 0xff, "CONFIGURE", 3, fdctrl_handle_configure },
-    { FD_CMD_POWERDOWN_MODE, 0xff, "POWERDOWN MODE", 2, fdctrl_handle_powerdown_mode },
-    { FD_CMD_OPTION, 0xff, "OPTION", 1, fdctrl_handle_option },
-    { FD_CMD_DRIVE_SPECIFICATION_COMMAND, 0xff, "DRIVE SPECIFICATION COMMAND", 5, fdctrl_handle_drive_specification_command },
-    { FD_CMD_RELATIVE_SEEK_OUT, 0xff, "RELATIVE SEEK OUT", 2, fdctrl_handle_relative_seek_out },
-    { FD_CMD_FORMAT_AND_WRITE, 0xff, "FORMAT AND WRITE", 10, fdctrl_unimplemented },
-    { FD_CMD_RELATIVE_SEEK_IN, 0xff, "RELATIVE SEEK IN", 2, fdctrl_handle_relative_seek_in },
-    { FD_CMD_LOCK, 0x7f, "LOCK", 0, fdctrl_handle_lock },
-    { FD_CMD_DUMPREG, 0xff, "DUMPREG", 0, fdctrl_handle_dumpreg },
-    { FD_CMD_VERSION, 0xff, "VERSION", 0, fdctrl_handle_version },
-    { FD_CMD_PART_ID, 0xff, "PART ID", 0, fdctrl_handle_partid },
-    { FD_CMD_WRITE, 0x1f, "WRITE (BeOS)", 8, fdctrl_start_transfer, FD_DIR_WRITE }, /* not in specification ; BeOS 4.5 bug */
-    { 0, 0, "unknown", 0, fdctrl_unimplemented }, /* default handler */
-};
-/* Associate command to an index in the 'handlers' array */
-static uint8_t command_to_handler[256];
-
-static void fdctrl_write_data(FDCtrl *fdctrl, uint32_t value)
-{
-    FDrive *cur_drv;
-    int pos;
-
-    /* Reset mode */
-    if (!(fdctrl->dor & FD_DOR_nRESET)) {
-        FLOPPY_DPRINTF("Floppy controller in RESET state !\n");
-        return;
-    }
-    if (!(fdctrl->msr & FD_MSR_RQM) || (fdctrl->msr & FD_MSR_DIO)) {
-        FLOPPY_DPRINTF("error: controller not ready for writing\n");
-        return;
-    }
-    fdctrl->dsr &= ~FD_DSR_PWRDOWN;
-    /* Is it write command time ? */
-    if (fdctrl->msr & FD_MSR_NONDMA) {
-        /* FIFO data write */
-        pos = fdctrl->data_pos++;
-        pos %= FD_SECTOR_LEN;
-        fdctrl->fifo[pos] = value;
-        if (pos == FD_SECTOR_LEN - 1 ||
-            fdctrl->data_pos == fdctrl->data_len) {
-            cur_drv = get_cur_drv(fdctrl);
-            if (bdrv_write(cur_drv->bs, fd_sector(cur_drv), fdctrl->fifo, 1) < 0) {
-                FLOPPY_DPRINTF("error writing sector %d\n",
-                               fd_sector(cur_drv));
-                return;
-            }
-            if (!fdctrl_seek_to_next_sect(fdctrl, cur_drv)) {
-                FLOPPY_DPRINTF("error seeking to next sector %d\n",
-                               fd_sector(cur_drv));
-                return;
-            }
-        }
-        /* Switch from transfer mode to status mode
-         * then from status mode to command mode
-         */
-        if (fdctrl->data_pos == fdctrl->data_len)
-            fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
-        return;
-    }
-    if (fdctrl->data_pos == 0) {
-        /* Command */
-        pos = command_to_handler[value & 0xff];
-        FLOPPY_DPRINTF("%s command\n", handlers[pos].name);
-        fdctrl->data_len = handlers[pos].parameters + 1;
-        fdctrl->msr |= FD_MSR_CMDBUSY;
-    }
-
-    FLOPPY_DPRINTF("%s: %02x\n", __func__, value);
-    fdctrl->fifo[fdctrl->data_pos++] = value;
-    if (fdctrl->data_pos == fdctrl->data_len) {
-        /* We now have all parameters
-         * and will be able to treat the command
-         */
-        if (fdctrl->data_state & FD_STATE_FORMAT) {
-            fdctrl_format_sector(fdctrl);
-            return;
-        }
-
-        pos = command_to_handler[fdctrl->fifo[0] & 0xff];
-        FLOPPY_DPRINTF("treat %s command\n", handlers[pos].name);
-        (*handlers[pos].handler)(fdctrl, handlers[pos].direction);
-    }
-}
-
-static void fdctrl_result_timer(void *opaque)
-{
-    FDCtrl *fdctrl = opaque;
-    FDrive *cur_drv = get_cur_drv(fdctrl);
-
-    /* Pretend we are spinning.
-     * This is needed for Coherent, which uses READ ID to check for
-     * sector interleaving.
-     */
-    if (cur_drv->last_sect != 0) {
-        cur_drv->sect = (cur_drv->sect % cur_drv->last_sect) + 1;
-    }
-    /* READ_ID can't automatically succeed! */
-    if (fdctrl->check_media_rate &&
-        (fdctrl->dsr & FD_DSR_DRATEMASK) != cur_drv->media_rate) {
-        FLOPPY_DPRINTF("read id rate mismatch (fdc=%d, media=%d)\n",
-                       fdctrl->dsr & FD_DSR_DRATEMASK, cur_drv->media_rate);
-        fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM, FD_SR1_MA, 0x00);
-    } else {
-        fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
-    }
-}
-
-static void fdctrl_change_cb(void *opaque, bool load)
-{
-    FDrive *drive = opaque;
-
-    drive->media_changed = 1;
-    fd_revalidate(drive);
-}
-
-static const BlockDevOps fdctrl_block_ops = {
-    .change_media_cb = fdctrl_change_cb,
-};
-
-/* Init functions */
-static int fdctrl_connect_drives(FDCtrl *fdctrl)
-{
-    unsigned int i;
-    FDrive *drive;
-
-    for (i = 0; i < MAX_FD; i++) {
-        drive = &fdctrl->drives[i];
-        drive->fdctrl = fdctrl;
-
-        if (drive->bs) {
-            if (bdrv_get_on_error(drive->bs, 0) != BLOCKDEV_ON_ERROR_ENOSPC) {
-                error_report("fdc doesn't support drive option werror");
-                return -1;
-            }
-            if (bdrv_get_on_error(drive->bs, 1) != BLOCKDEV_ON_ERROR_REPORT) {
-                error_report("fdc doesn't support drive option rerror");
-                return -1;
-            }
-        }
-
-        fd_init(drive);
-        fdctrl_change_cb(drive, 0);
-        if (drive->bs) {
-            bdrv_set_dev_ops(drive->bs, &fdctrl_block_ops, drive);
-        }
-    }
-    return 0;
-}
-
-ISADevice *fdctrl_init_isa(ISABus *bus, DriveInfo **fds)
-{
-    ISADevice *dev;
-
-    dev = isa_try_create(bus, "isa-fdc");
-    if (!dev) {
-        return NULL;
-    }
-
-    if (fds[0]) {
-        qdev_prop_set_drive_nofail(&dev->qdev, "driveA", fds[0]->bdrv);
-    }
-    if (fds[1]) {
-        qdev_prop_set_drive_nofail(&dev->qdev, "driveB", fds[1]->bdrv);
-    }
-    qdev_init_nofail(&dev->qdev);
-
-    return dev;
-}
-
-void fdctrl_init_sysbus(qemu_irq irq, int dma_chann,
-                        hwaddr mmio_base, DriveInfo **fds)
-{
-    FDCtrl *fdctrl;
-    DeviceState *dev;
-    FDCtrlSysBus *sys;
-
-    dev = qdev_create(NULL, "sysbus-fdc");
-    sys = DO_UPCAST(FDCtrlSysBus, busdev.qdev, dev);
-    fdctrl = &sys->state;
-    fdctrl->dma_chann = dma_chann; /* FIXME */
-    if (fds[0]) {
-        qdev_prop_set_drive_nofail(dev, "driveA", fds[0]->bdrv);
-    }
-    if (fds[1]) {
-        qdev_prop_set_drive_nofail(dev, "driveB", fds[1]->bdrv);
-    }
-    qdev_init_nofail(dev);
-    sysbus_connect_irq(&sys->busdev, 0, irq);
-    sysbus_mmio_map(&sys->busdev, 0, mmio_base);
-}
-
-void sun4m_fdctrl_init(qemu_irq irq, hwaddr io_base,
-                       DriveInfo **fds, qemu_irq *fdc_tc)
-{
-    DeviceState *dev;
-    FDCtrlSysBus *sys;
-
-    dev = qdev_create(NULL, "SUNW,fdtwo");
-    if (fds[0]) {
-        qdev_prop_set_drive_nofail(dev, "drive", fds[0]->bdrv);
-    }
-    qdev_init_nofail(dev);
-    sys = DO_UPCAST(FDCtrlSysBus, busdev.qdev, dev);
-    sysbus_connect_irq(&sys->busdev, 0, irq);
-    sysbus_mmio_map(&sys->busdev, 0, io_base);
-    *fdc_tc = qdev_get_gpio_in(dev, 0);
-}
-
-static int fdctrl_init_common(FDCtrl *fdctrl)
-{
-    int i, j;
-    static int command_tables_inited = 0;
-
-    /* Fill 'command_to_handler' lookup table */
-    if (!command_tables_inited) {
-        command_tables_inited = 1;
-        for (i = ARRAY_SIZE(handlers) - 1; i >= 0; i--) {
-            for (j = 0; j < sizeof(command_to_handler); j++) {
-                if ((j & handlers[i].mask) == handlers[i].value) {
-                    command_to_handler[j] = i;
-                }
-            }
-        }
-    }
-
-    FLOPPY_DPRINTF("init controller\n");
-    fdctrl->fifo = qemu_memalign(512, FD_SECTOR_LEN);
-    fdctrl->fifo_size = 512;
-    fdctrl->result_timer = qemu_new_timer_ns(vm_clock,
-                                          fdctrl_result_timer, fdctrl);
-
-    fdctrl->version = 0x90; /* Intel 82078 controller */
-    fdctrl->config = FD_CONFIG_EIS | FD_CONFIG_EFIFO; /* Implicit seek, polling & FIFO enabled */
-    fdctrl->num_floppies = MAX_FD;
-
-    if (fdctrl->dma_chann != -1)
-        DMA_register_channel(fdctrl->dma_chann, &fdctrl_transfer_handler, fdctrl);
-    return fdctrl_connect_drives(fdctrl);
-}
-
-static const MemoryRegionPortio fdc_portio_list[] = {
-    { 1, 5, 1, .read = fdctrl_read, .write = fdctrl_write },
-    { 7, 1, 1, .read = fdctrl_read, .write = fdctrl_write },
-    PORTIO_END_OF_LIST(),
-};
-
-static int isabus_fdc_init1(ISADevice *dev)
-{
-    FDCtrlISABus *isa = DO_UPCAST(FDCtrlISABus, busdev, dev);
-    FDCtrl *fdctrl = &isa->state;
-    int ret;
-
-    isa_register_portio_list(dev, isa->iobase, fdc_portio_list, fdctrl, "fdc");
-
-    isa_init_irq(&isa->busdev, &fdctrl->irq, isa->irq);
-    fdctrl->dma_chann = isa->dma;
-
-    qdev_set_legacy_instance_id(&dev->qdev, isa->iobase, 2);
-    ret = fdctrl_init_common(fdctrl);
-
-    add_boot_device_path(isa->bootindexA, &dev->qdev, "/floppy@0");
-    add_boot_device_path(isa->bootindexB, &dev->qdev, "/floppy@1");
-
-    return ret;
-}
-
-static int sysbus_fdc_init1(SysBusDevice *dev)
-{
-    FDCtrlSysBus *sys = DO_UPCAST(FDCtrlSysBus, busdev, dev);
-    FDCtrl *fdctrl = &sys->state;
-    int ret;
-
-    memory_region_init_io(&fdctrl->iomem, &fdctrl_mem_ops, fdctrl, "fdc", 0x08);
-    sysbus_init_mmio(dev, &fdctrl->iomem);
-    sysbus_init_irq(dev, &fdctrl->irq);
-    qdev_init_gpio_in(&dev->qdev, fdctrl_handle_tc, 1);
-    fdctrl->dma_chann = -1;
-
-    qdev_set_legacy_instance_id(&dev->qdev, 0 /* io */, 2); /* FIXME */
-    ret = fdctrl_init_common(fdctrl);
-
-    return ret;
-}
-
-static int sun4m_fdc_init1(SysBusDevice *dev)
-{
-    FDCtrl *fdctrl = &(FROM_SYSBUS(FDCtrlSysBus, dev)->state);
-
-    memory_region_init_io(&fdctrl->iomem, &fdctrl_mem_strict_ops, fdctrl,
-                          "fdctrl", 0x08);
-    sysbus_init_mmio(dev, &fdctrl->iomem);
-    sysbus_init_irq(dev, &fdctrl->irq);
-    qdev_init_gpio_in(&dev->qdev, fdctrl_handle_tc, 1);
-
-    fdctrl->sun4m = 1;
-    qdev_set_legacy_instance_id(&dev->qdev, 0 /* io */, 2); /* FIXME */
-    return fdctrl_init_common(fdctrl);
-}
-
-FDriveType isa_fdc_get_drive_type(ISADevice *fdc, int i)
-{
-    FDCtrlISABus *isa = DO_UPCAST(FDCtrlISABus, busdev, fdc);
-
-    return isa->state.drives[i].drive;
-}
-
-static const VMStateDescription vmstate_isa_fdc ={
-    .name = "fdc",
-    .version_id = 2,
-    .minimum_version_id = 2,
-    .fields = (VMStateField []) {
-        VMSTATE_STRUCT(state, FDCtrlISABus, 0, vmstate_fdc, FDCtrl),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static Property isa_fdc_properties[] = {
-    DEFINE_PROP_HEX32("iobase", FDCtrlISABus, iobase, 0x3f0),
-    DEFINE_PROP_UINT32("irq", FDCtrlISABus, irq, 6),
-    DEFINE_PROP_UINT32("dma", FDCtrlISABus, dma, 2),
-    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_BIT("check_media_rate", FDCtrlISABus, state.check_media_rate,
-                    0, true),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void isabus_fdc_class_init1(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
-    ic->init = isabus_fdc_init1;
-    dc->fw_name = "fdc";
-    dc->no_user = 1;
-    dc->reset = fdctrl_external_reset_isa;
-    dc->vmsd = &vmstate_isa_fdc;
-    dc->props = isa_fdc_properties;
-}
-
-static const 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 ={
-    .name = "fdc",
-    .version_id = 2,
-    .minimum_version_id = 2,
-    .fields = (VMStateField []) {
-        VMSTATE_STRUCT(state, FDCtrlSysBus, 0, vmstate_fdc, FDCtrl),
-        VMSTATE_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 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 const TypeInfo sysbus_fdc_info = {
-    .name          = "sysbus-fdc",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(FDCtrlSysBus),
-    .class_init    = sysbus_fdc_class_init,
-};
-
-static Property sun4m_fdc_properties[] = {
-    DEFINE_PROP_DRIVE("drive", FDCtrlSysBus, state.drives[0].bs),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void sun4m_fdc_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = sun4m_fdc_init1;
-    dc->reset = fdctrl_external_reset_sysbus;
-    dc->vmsd = &vmstate_sysbus_fdc;
-    dc->props = sun4m_fdc_properties;
-}
-
-static const 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_types(void)
-{
-    type_register_static(&isa_fdc_info);
-    type_register_static(&sysbus_fdc_info);
-    type_register_static(&sun4m_fdc_info);
-}
-
-type_init(fdc_register_types)
diff --git a/hw/fdc.h b/hw/fdc.h
deleted file mode 100644 (file)
index a8f6f7c..0000000
--- a/hw/fdc.h
+++ /dev/null
@@ -1,24 +0,0 @@
-#ifndef HW_FDC_H
-#define HW_FDC_H
-
-#include "qemu-common.h"
-
-/* fdc.c */
-#define MAX_FD 2
-
-typedef enum FDriveType {
-    FDRIVE_DRV_144  = 0x00,   /* 1.44 MB 3"5 drive      */
-    FDRIVE_DRV_288  = 0x01,   /* 2.88 MB 3"5 drive      */
-    FDRIVE_DRV_120  = 0x02,   /* 1.2  MB 5"25 drive     */
-    FDRIVE_DRV_NONE = 0x03,   /* No drive connected     */
-} FDriveType;
-
-ISADevice *fdctrl_init_isa(ISABus *bus, DriveInfo **fds);
-void fdctrl_init_sysbus(qemu_irq irq, int dma_chann,
-                        hwaddr mmio_base, DriveInfo **fds);
-void sun4m_fdctrl_init(qemu_irq irq, hwaddr io_base,
-                       DriveInfo **fds, qemu_irq *fdc_tc);
-
-FDriveType isa_fdc_get_drive_type(ISADevice *fdc, int i);
-
-#endif
diff --git a/hw/firmware_abi.h b/hw/firmware_abi.h
deleted file mode 100644 (file)
index 5e6e5d4..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-#ifndef FIRMWARE_ABI_H
-#define FIRMWARE_ABI_H
-
-/* OpenBIOS NVRAM partition */
-struct OpenBIOS_nvpart_v1 {
-    uint8_t signature;
-    uint8_t checksum;
-    uint16_t len; // BE, length divided by 16
-    char name[12];
-};
-
-#define OPENBIOS_PART_SYSTEM 0x70
-#define OPENBIOS_PART_FREE 0x7f
-
-static inline void
-OpenBIOS_finish_partition(struct OpenBIOS_nvpart_v1 *header, uint32_t size)
-{
-    unsigned int i, sum;
-    uint8_t *tmpptr;
-
-    // Length divided by 16
-    header->len = cpu_to_be16(size >> 4);
-
-    // Checksum
-    tmpptr = (uint8_t *)header;
-    sum = *tmpptr;
-    for (i = 0; i < 14; i++) {
-        sum += tmpptr[2 + i];
-        sum = (sum + ((sum & 0xff00) >> 8)) & 0xff;
-    }
-    header->checksum = sum & 0xff;
-}
-
-static inline uint32_t
-OpenBIOS_set_var(uint8_t *nvram, uint32_t addr, const char *str)
-{
-    uint32_t len;
-
-    len = strlen(str) + 1;
-    memcpy(&nvram[addr], str, len);
-
-    return addr + len;
-}
-
-/* Sun IDPROM structure at the end of NVRAM */
-/* from http://www.squirrel.com/squirrel/sun-nvram-hostid.faq.html */
-struct Sun_nvram {
-    uint8_t type;       /* always 01 */
-    uint8_t machine_id; /* first byte of host id (machine type) */
-    uint8_t macaddr[6]; /* 6 byte ethernet address (first 3 bytes 08, 00, 20) */
-    uint8_t date[4];    /* date of manufacture */
-    uint8_t hostid[3];  /* remaining 3 bytes of host id (serial number) */
-    uint8_t checksum;   /* bitwise xor of previous bytes */
-};
-
-static inline void
-Sun_init_header(struct Sun_nvram *header, const uint8_t *macaddr, int machine_id)
-{
-    uint8_t tmp, *tmpptr;
-    unsigned int i;
-
-    header->type = 1;
-    header->machine_id = machine_id & 0xff;
-    memcpy(&header->macaddr, macaddr, 6);
-    /* Calculate checksum */
-    tmp = 0;
-    tmpptr = (uint8_t *)header;
-    for (i = 0; i < 15; i++)
-        tmp ^= tmpptr[i];
-
-    header->checksum = tmp;
-}
-#endif /* FIRMWARE_ABI_H */
diff --git a/hw/flash.h b/hw/flash.h
deleted file mode 100644 (file)
index 920d759..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-#ifndef HW_FLASH_H
-#define HW_FLASH_H 1
-
-/* NOR flash devices */
-
-#include "exec/memory.h"
-
-typedef struct pflash_t pflash_t;
-
-/* pflash_cfi01.c */
-pflash_t *pflash_cfi01_register(hwaddr base,
-                                DeviceState *qdev, const char *name,
-                                hwaddr size,
-                                BlockDriverState *bs,
-                                uint32_t sector_len, int nb_blocs, int width,
-                                uint16_t id0, uint16_t id1,
-                                uint16_t id2, uint16_t id3, int be);
-
-/* pflash_cfi02.c */
-pflash_t *pflash_cfi02_register(hwaddr base,
-                                DeviceState *qdev, const char *name,
-                                hwaddr size,
-                                BlockDriverState *bs, uint32_t sector_len,
-                                int nb_blocs, int nb_mappings, int width,
-                                uint16_t id0, uint16_t id1,
-                                uint16_t id2, uint16_t id3,
-                                uint16_t unlock_addr0, uint16_t unlock_addr1,
-                                int be);
-
-MemoryRegion *pflash_cfi01_get_memory(pflash_t *fl);
-
-/* nand.c */
-DeviceState *nand_init(BlockDriverState *bdrv, int manf_id, int chip_id);
-void nand_setpins(DeviceState *dev, uint8_t cle, uint8_t ale,
-                  uint8_t ce, uint8_t wp, uint8_t gnd);
-void nand_getpins(DeviceState *dev, int *rb);
-void nand_setio(DeviceState *dev, uint32_t value);
-uint32_t nand_getio(DeviceState *dev);
-uint32_t nand_getbuswidth(DeviceState *dev);
-
-#define NAND_MFR_TOSHIBA       0x98
-#define NAND_MFR_SAMSUNG       0xec
-#define NAND_MFR_FUJITSU       0x04
-#define NAND_MFR_NATIONAL      0x8f
-#define NAND_MFR_RENESAS       0x07
-#define NAND_MFR_STMICRO       0x20
-#define NAND_MFR_HYNIX         0xad
-#define NAND_MFR_MICRON                0x2c
-
-/* onenand.c */
-void *onenand_raw_otp(DeviceState *onenand_device);
-
-/* ecc.c */
-typedef struct {
-    uint8_t cp;                /* Column parity */
-    uint16_t lp[2];    /* Line parity */
-    uint16_t count;
-} ECCState;
-
-uint8_t ecc_digest(ECCState *s, uint8_t sample);
-void ecc_reset(ECCState *s);
-extern VMStateDescription vmstate_ecc_state;
-
-#endif
diff --git a/hw/fmopl.c b/hw/fmopl.c
deleted file mode 100644 (file)
index e50ba6c..0000000
+++ /dev/null
@@ -1,1395 +0,0 @@
-/*
-**
-** File: fmopl.c -- software implementation of FM sound generator
-**
-** Copyright (C) 1999,2000 Tatsuyuki Satoh , MultiArcadeMachineEmurator development
-**
-** Version 0.37a
-**
-*/
-
-/*
-       preliminary :
-       Problem :
-       note:
-*/
-
-/* This version of fmopl.c is a fork of the MAME one, relicensed under the LGPL.
- *
- * 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.1 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/>.
- */
-
-#define INLINE         static inline
-#define HAS_YM3812     1
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdarg.h>
-#include <math.h>
-//#include "driver.h"          /* use M.A.M.E. */
-#include "hw/fmopl.h"
-
-#ifndef PI
-#define PI 3.14159265358979323846
-#endif
-
-#ifndef ARRAY_SIZE
-#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
-#endif
-
-/* -------------------- for debug --------------------- */
-/* #define OPL_OUTPUT_LOG */
-#ifdef OPL_OUTPUT_LOG
-static FILE *opl_dbg_fp = NULL;
-static FM_OPL *opl_dbg_opl[16];
-static int opl_dbg_maxchip,opl_dbg_chip;
-#endif
-
-/* -------------------- preliminary define section --------------------- */
-/* attack/decay rate time rate */
-#define OPL_ARRATE     141280  /* RATE 4 =  2826.24ms @ 3.6MHz */
-#define OPL_DRRATE    1956000  /* RATE 4 = 39280.64ms @ 3.6MHz */
-
-#define DELTAT_MIXING_LEVEL (1) /* DELTA-T ADPCM MIXING LEVEL */
-
-#define FREQ_BITS 24                   /* frequency turn          */
-
-/* counter bits = 20 , octerve 7 */
-#define FREQ_RATE   (1<<(FREQ_BITS-20))
-#define TL_BITS    (FREQ_BITS+2)
-
-/* final output shift , limit minimum and maximum */
-#define OPL_OUTSB   (TL_BITS+3-16)             /* OPL output final shift 16bit */
-#define OPL_MAXOUT (0x7fff<<OPL_OUTSB)
-#define OPL_MINOUT (-0x8000<<OPL_OUTSB)
-
-/* -------------------- quality selection --------------------- */
-
-/* sinwave entries */
-/* used static memory = SIN_ENT * 4 (byte) */
-#define SIN_ENT 2048
-
-/* output level entries (envelope,sinwave) */
-/* envelope counter lower bits */
-#define ENV_BITS 16
-/* envelope output entries */
-#define EG_ENT   4096
-/* used dynamic memory = EG_ENT*4*4(byte)or EG_ENT*6*4(byte) */
-/* used static  memory = EG_ENT*4 (byte)                     */
-
-#define EG_OFF   ((2*EG_ENT)<<ENV_BITS)  /* OFF          */
-#define EG_DED   EG_OFF
-#define EG_DST   (EG_ENT<<ENV_BITS)      /* DECAY  START */
-#define EG_AED   EG_DST
-#define EG_AST   0                       /* ATTACK START */
-
-#define EG_STEP (96.0/EG_ENT) /* OPL is 0.1875 dB step  */
-
-/* LFO table entries */
-#define VIB_ENT 512
-#define VIB_SHIFT (32-9)
-#define AMS_ENT 512
-#define AMS_SHIFT (32-9)
-
-#define VIB_RATE 256
-
-/* -------------------- local defines , macros --------------------- */
-
-/* register number to channel number , slot offset */
-#define SLOT1 0
-#define SLOT2 1
-
-/* envelope phase */
-#define ENV_MOD_RR  0x00
-#define ENV_MOD_DR  0x01
-#define ENV_MOD_AR  0x02
-
-/* -------------------- tables --------------------- */
-static const int slot_array[32]=
-{
-        0, 2, 4, 1, 3, 5,-1,-1,
-        6, 8,10, 7, 9,11,-1,-1,
-       12,14,16,13,15,17,-1,-1,
-       -1,-1,-1,-1,-1,-1,-1,-1
-};
-
-/* key scale level */
-/* table is 3dB/OCT , DV converts this in TL step at 6dB/OCT */
-#define DV (EG_STEP/2)
-static const UINT32 KSL_TABLE[8*16]=
-{
-       /* OCT 0 */
-        0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV,
-        0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV,
-        0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV,
-        0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV,
-       /* OCT 1 */
-        0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV,
-        0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV,
-        0.000/DV, 0.750/DV, 1.125/DV, 1.500/DV,
-        1.875/DV, 2.250/DV, 2.625/DV, 3.000/DV,
-       /* OCT 2 */
-        0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV,
-        0.000/DV, 1.125/DV, 1.875/DV, 2.625/DV,
-        3.000/DV, 3.750/DV, 4.125/DV, 4.500/DV,
-        4.875/DV, 5.250/DV, 5.625/DV, 6.000/DV,
-       /* OCT 3 */
-        0.000/DV, 0.000/DV, 0.000/DV, 1.875/DV,
-        3.000/DV, 4.125/DV, 4.875/DV, 5.625/DV,
-        6.000/DV, 6.750/DV, 7.125/DV, 7.500/DV,
-        7.875/DV, 8.250/DV, 8.625/DV, 9.000/DV,
-       /* OCT 4 */
-        0.000/DV, 0.000/DV, 3.000/DV, 4.875/DV,
-        6.000/DV, 7.125/DV, 7.875/DV, 8.625/DV,
-        9.000/DV, 9.750/DV,10.125/DV,10.500/DV,
-       10.875/DV,11.250/DV,11.625/DV,12.000/DV,
-       /* OCT 5 */
-        0.000/DV, 3.000/DV, 6.000/DV, 7.875/DV,
-        9.000/DV,10.125/DV,10.875/DV,11.625/DV,
-       12.000/DV,12.750/DV,13.125/DV,13.500/DV,
-       13.875/DV,14.250/DV,14.625/DV,15.000/DV,
-       /* OCT 6 */
-        0.000/DV, 6.000/DV, 9.000/DV,10.875/DV,
-       12.000/DV,13.125/DV,13.875/DV,14.625/DV,
-       15.000/DV,15.750/DV,16.125/DV,16.500/DV,
-       16.875/DV,17.250/DV,17.625/DV,18.000/DV,
-       /* OCT 7 */
-        0.000/DV, 9.000/DV,12.000/DV,13.875/DV,
-       15.000/DV,16.125/DV,16.875/DV,17.625/DV,
-       18.000/DV,18.750/DV,19.125/DV,19.500/DV,
-       19.875/DV,20.250/DV,20.625/DV,21.000/DV
-};
-#undef DV
-
-/* sustain lebel table (3db per step) */
-/* 0 - 15: 0, 3, 6, 9,12,15,18,21,24,27,30,33,36,39,42,93 (dB)*/
-#define SC(db) (db*((3/EG_STEP)*(1<<ENV_BITS)))+EG_DST
-static const INT32 SL_TABLE[16]={
- SC( 0),SC( 1),SC( 2),SC(3 ),SC(4 ),SC(5 ),SC(6 ),SC( 7),
- SC( 8),SC( 9),SC(10),SC(11),SC(12),SC(13),SC(14),SC(31)
-};
-#undef SC
-
-#define TL_MAX (EG_ENT*2) /* limit(tl + ksr + envelope) + sinwave */
-/* TotalLevel : 48 24 12  6  3 1.5 0.75 (dB) */
-/* TL_TABLE[ 0      to TL_MAX          ] : plus  section */
-/* TL_TABLE[ TL_MAX to TL_MAX+TL_MAX-1 ] : minus section */
-static INT32 *TL_TABLE;
-
-/* pointers to TL_TABLE with sinwave output offset */
-static INT32 **SIN_TABLE;
-
-/* LFO table */
-static INT32 *AMS_TABLE;
-static INT32 *VIB_TABLE;
-
-/* envelope output curve table */
-/* attack + decay + OFF */
-static INT32 ENV_CURVE[2*EG_ENT+1];
-
-/* multiple table */
-#define ML 2
-static const UINT32 MUL_TABLE[16]= {
-/* 1/2, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15 */
-   0.50*ML, 1.00*ML, 2.00*ML, 3.00*ML, 4.00*ML, 5.00*ML, 6.00*ML, 7.00*ML,
-   8.00*ML, 9.00*ML,10.00*ML,10.00*ML,12.00*ML,12.00*ML,15.00*ML,15.00*ML
-};
-#undef ML
-
-/* dummy attack / decay rate ( when rate == 0 ) */
-static INT32 RATE_0[16]=
-{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
-
-/* -------------------- static state --------------------- */
-
-/* lock level of common table */
-static int num_lock = 0;
-
-/* work table */
-static void *cur_chip = NULL;  /* current chip point */
-/* currenct chip state */
-/* static OPLSAMPLE  *bufL,*bufR; */
-static OPL_CH *S_CH;
-static OPL_CH *E_CH;
-OPL_SLOT *SLOT7_1,*SLOT7_2,*SLOT8_1,*SLOT8_2;
-
-static INT32 outd[1];
-static INT32 ams;
-static INT32 vib;
-INT32  *ams_table;
-INT32  *vib_table;
-static INT32 amsIncr;
-static INT32 vibIncr;
-static INT32 feedback2;                /* connect for SLOT 2 */
-
-/* log output level */
-#define LOG_ERR  3      /* ERROR       */
-#define LOG_WAR  2      /* WARNING     */
-#define LOG_INF  1      /* INFORMATION */
-
-//#define LOG_LEVEL LOG_INF
-#define LOG_LEVEL      LOG_ERR
-
-//#define LOG(n,x) if( (n)>=LOG_LEVEL ) logerror x
-#define LOG(n,x)
-
-/* --------------------- subroutines  --------------------- */
-
-INLINE int Limit( int val, int max, int min ) {
-       if ( val > max )
-               val = max;
-       else if ( val < min )
-               val = min;
-
-       return val;
-}
-
-/* status set and IRQ handling */
-INLINE void OPL_STATUS_SET(FM_OPL *OPL,int flag)
-{
-       /* set status flag */
-       OPL->status |= flag;
-       if(!(OPL->status & 0x80))
-       {
-               if(OPL->status & OPL->statusmask)
-               {       /* IRQ on */
-                       OPL->status |= 0x80;
-                       /* callback user interrupt handler (IRQ is OFF to ON) */
-                       if(OPL->IRQHandler) (OPL->IRQHandler)(OPL->IRQParam,1);
-               }
-       }
-}
-
-/* status reset and IRQ handling */
-INLINE void OPL_STATUS_RESET(FM_OPL *OPL,int flag)
-{
-       /* reset status flag */
-       OPL->status &=~flag;
-       if((OPL->status & 0x80))
-       {
-               if (!(OPL->status & OPL->statusmask) )
-               {
-                       OPL->status &= 0x7f;
-                       /* callback user interrupt handler (IRQ is ON to OFF) */
-                       if(OPL->IRQHandler) (OPL->IRQHandler)(OPL->IRQParam,0);
-               }
-       }
-}
-
-/* IRQ mask set */
-INLINE void OPL_STATUSMASK_SET(FM_OPL *OPL,int flag)
-{
-       OPL->statusmask = flag;
-       /* IRQ handling check */
-       OPL_STATUS_SET(OPL,0);
-       OPL_STATUS_RESET(OPL,0);
-}
-
-/* ----- key on  ----- */
-INLINE void OPL_KEYON(OPL_SLOT *SLOT)
-{
-       /* sin wave restart */
-       SLOT->Cnt = 0;
-       /* set attack */
-       SLOT->evm = ENV_MOD_AR;
-       SLOT->evs = SLOT->evsa;
-       SLOT->evc = EG_AST;
-       SLOT->eve = EG_AED;
-}
-/* ----- key off ----- */
-INLINE void OPL_KEYOFF(OPL_SLOT *SLOT)
-{
-       if( SLOT->evm > ENV_MOD_RR)
-       {
-               /* set envelope counter from envleope output */
-               SLOT->evm = ENV_MOD_RR;
-               if( !(SLOT->evc&EG_DST) )
-                       //SLOT->evc = (ENV_CURVE[SLOT->evc>>ENV_BITS]<<ENV_BITS) + EG_DST;
-                       SLOT->evc = EG_DST;
-               SLOT->eve = EG_DED;
-               SLOT->evs = SLOT->evsr;
-       }
-}
-
-/* ---------- calcrate Envelope Generator & Phase Generator ---------- */
-/* return : envelope output */
-INLINE UINT32 OPL_CALC_SLOT( OPL_SLOT *SLOT )
-{
-       /* calcrate envelope generator */
-       if( (SLOT->evc+=SLOT->evs) >= SLOT->eve )
-       {
-               switch( SLOT->evm ){
-               case ENV_MOD_AR: /* ATTACK -> DECAY1 */
-                       /* next DR */
-                       SLOT->evm = ENV_MOD_DR;
-                       SLOT->evc = EG_DST;
-                       SLOT->eve = SLOT->SL;
-                       SLOT->evs = SLOT->evsd;
-                       break;
-               case ENV_MOD_DR: /* DECAY -> SL or RR */
-                       SLOT->evc = SLOT->SL;
-                       SLOT->eve = EG_DED;
-                       if(SLOT->eg_typ)
-                       {
-                               SLOT->evs = 0;
-                       }
-                       else
-                       {
-                               SLOT->evm = ENV_MOD_RR;
-                               SLOT->evs = SLOT->evsr;
-                       }
-                       break;
-               case ENV_MOD_RR: /* RR -> OFF */
-                       SLOT->evc = EG_OFF;
-                       SLOT->eve = EG_OFF+1;
-                       SLOT->evs = 0;
-                       break;
-               }
-       }
-       /* calcrate envelope */
-       return SLOT->TLL+ENV_CURVE[SLOT->evc>>ENV_BITS]+(SLOT->ams ? ams : 0);
-}
-
-/* set algorithm connection */
-static void set_algorithm( OPL_CH *CH)
-{
-       INT32 *carrier = &outd[0];
-       CH->connect1 = CH->CON ? carrier : &feedback2;
-       CH->connect2 = carrier;
-}
-
-/* ---------- frequency counter for operater update ---------- */
-INLINE void CALC_FCSLOT(OPL_CH *CH,OPL_SLOT *SLOT)
-{
-       int ksr;
-
-       /* frequency step counter */
-       SLOT->Incr = CH->fc * SLOT->mul;
-       ksr = CH->kcode >> SLOT->KSR;
-
-       if( SLOT->ksr != ksr )
-       {
-               SLOT->ksr = ksr;
-               /* attack , decay rate recalcration */
-               SLOT->evsa = SLOT->AR[ksr];
-               SLOT->evsd = SLOT->DR[ksr];
-               SLOT->evsr = SLOT->RR[ksr];
-       }
-       SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl);
-}
-
-/* set multi,am,vib,EG-TYP,KSR,mul */
-INLINE void set_mul(FM_OPL *OPL,int slot,int v)
-{
-       OPL_CH   *CH   = &OPL->P_CH[slot/2];
-       OPL_SLOT *SLOT = &CH->SLOT[slot&1];
-
-       SLOT->mul    = MUL_TABLE[v&0x0f];
-       SLOT->KSR    = (v&0x10) ? 0 : 2;
-       SLOT->eg_typ = (v&0x20)>>5;
-       SLOT->vib    = (v&0x40);
-       SLOT->ams    = (v&0x80);
-       CALC_FCSLOT(CH,SLOT);
-}
-
-/* set ksl & tl */
-INLINE void set_ksl_tl(FM_OPL *OPL,int slot,int v)
-{
-       OPL_CH   *CH   = &OPL->P_CH[slot/2];
-       OPL_SLOT *SLOT = &CH->SLOT[slot&1];
-       int ksl = v>>6; /* 0 / 1.5 / 3 / 6 db/OCT */
-
-       SLOT->ksl = ksl ? 3-ksl : 31;
-       SLOT->TL  = (v&0x3f)*(0.75/EG_STEP); /* 0.75db step */
-
-       if( !(OPL->mode&0x80) )
-       {       /* not CSM latch total level */
-               SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl);
-       }
-}
-
-/* set attack rate & decay rate  */
-INLINE void set_ar_dr(FM_OPL *OPL,int slot,int v)
-{
-       OPL_CH   *CH   = &OPL->P_CH[slot/2];
-       OPL_SLOT *SLOT = &CH->SLOT[slot&1];
-       int ar = v>>4;
-       int dr = v&0x0f;
-
-       SLOT->AR = ar ? &OPL->AR_TABLE[ar<<2] : RATE_0;
-       SLOT->evsa = SLOT->AR[SLOT->ksr];
-       if( SLOT->evm == ENV_MOD_AR ) SLOT->evs = SLOT->evsa;
-
-       SLOT->DR = dr ? &OPL->DR_TABLE[dr<<2] : RATE_0;
-       SLOT->evsd = SLOT->DR[SLOT->ksr];
-       if( SLOT->evm == ENV_MOD_DR ) SLOT->evs = SLOT->evsd;
-}
-
-/* set sustain level & release rate */
-INLINE void set_sl_rr(FM_OPL *OPL,int slot,int v)
-{
-       OPL_CH   *CH   = &OPL->P_CH[slot/2];
-       OPL_SLOT *SLOT = &CH->SLOT[slot&1];
-       int sl = v>>4;
-       int rr = v & 0x0f;
-
-       SLOT->SL = SL_TABLE[sl];
-       if( SLOT->evm == ENV_MOD_DR ) SLOT->eve = SLOT->SL;
-       SLOT->RR = &OPL->DR_TABLE[rr<<2];
-       SLOT->evsr = SLOT->RR[SLOT->ksr];
-       if( SLOT->evm == ENV_MOD_RR ) SLOT->evs = SLOT->evsr;
-}
-
-/* operator output calcrator */
-#define OP_OUT(slot,env,con)   slot->wavetable[((slot->Cnt+con)/(0x1000000/SIN_ENT))&(SIN_ENT-1)][env]
-/* ---------- calcrate one of channel ---------- */
-INLINE void OPL_CALC_CH( OPL_CH *CH )
-{
-       UINT32 env_out;
-       OPL_SLOT *SLOT;
-
-       feedback2 = 0;
-       /* SLOT 1 */
-       SLOT = &CH->SLOT[SLOT1];
-       env_out=OPL_CALC_SLOT(SLOT);
-       if( env_out < EG_ENT-1 )
-       {
-               /* PG */
-               if(SLOT->vib) SLOT->Cnt += (SLOT->Incr*vib/VIB_RATE);
-               else          SLOT->Cnt += SLOT->Incr;
-               /* connectoion */
-               if(CH->FB)
-               {
-                       int feedback1 = (CH->op1_out[0]+CH->op1_out[1])>>CH->FB;
-                       CH->op1_out[1] = CH->op1_out[0];
-                       *CH->connect1 += CH->op1_out[0] = OP_OUT(SLOT,env_out,feedback1);
-               }
-               else
-               {
-                       *CH->connect1 += OP_OUT(SLOT,env_out,0);
-               }
-       }else
-       {
-               CH->op1_out[1] = CH->op1_out[0];
-               CH->op1_out[0] = 0;
-       }
-       /* SLOT 2 */
-       SLOT = &CH->SLOT[SLOT2];
-       env_out=OPL_CALC_SLOT(SLOT);
-       if( env_out < EG_ENT-1 )
-       {
-               /* PG */
-               if(SLOT->vib) SLOT->Cnt += (SLOT->Incr*vib/VIB_RATE);
-               else          SLOT->Cnt += SLOT->Incr;
-               /* connectoion */
-               outd[0] += OP_OUT(SLOT,env_out, feedback2);
-       }
-}
-
-/* ---------- calcrate rhythm block ---------- */
-#define WHITE_NOISE_db 6.0
-INLINE void OPL_CALC_RH( OPL_CH *CH )
-{
-       UINT32 env_tam,env_sd,env_top,env_hh;
-       int whitenoise = (rand()&1)*(WHITE_NOISE_db/EG_STEP);
-       INT32 tone8;
-
-       OPL_SLOT *SLOT;
-       int env_out;
-
-       /* BD : same as FM serial mode and output level is large */
-       feedback2 = 0;
-       /* SLOT 1 */
-       SLOT = &CH[6].SLOT[SLOT1];
-       env_out=OPL_CALC_SLOT(SLOT);
-       if( env_out < EG_ENT-1 )
-       {
-               /* PG */
-               if(SLOT->vib) SLOT->Cnt += (SLOT->Incr*vib/VIB_RATE);
-               else          SLOT->Cnt += SLOT->Incr;
-               /* connectoion */
-               if(CH[6].FB)
-               {
-                       int feedback1 = (CH[6].op1_out[0]+CH[6].op1_out[1])>>CH[6].FB;
-                       CH[6].op1_out[1] = CH[6].op1_out[0];
-                       feedback2 = CH[6].op1_out[0] = OP_OUT(SLOT,env_out,feedback1);
-               }
-               else
-               {
-                       feedback2 = OP_OUT(SLOT,env_out,0);
-               }
-       }else
-       {
-               feedback2 = 0;
-               CH[6].op1_out[1] = CH[6].op1_out[0];
-               CH[6].op1_out[0] = 0;
-       }
-       /* SLOT 2 */
-       SLOT = &CH[6].SLOT[SLOT2];
-       env_out=OPL_CALC_SLOT(SLOT);
-       if( env_out < EG_ENT-1 )
-       {
-               /* PG */
-               if(SLOT->vib) SLOT->Cnt += (SLOT->Incr*vib/VIB_RATE);
-               else          SLOT->Cnt += SLOT->Incr;
-               /* connectoion */
-               outd[0] += OP_OUT(SLOT,env_out, feedback2)*2;
-       }
-
-       // SD  (17) = mul14[fnum7] + white noise
-       // TAM (15) = mul15[fnum8]
-       // TOP (18) = fnum6(mul18[fnum8]+whitenoise)
-       // HH  (14) = fnum7(mul18[fnum8]+whitenoise) + white noise
-       env_sd =OPL_CALC_SLOT(SLOT7_2) + whitenoise;
-       env_tam=OPL_CALC_SLOT(SLOT8_1);
-       env_top=OPL_CALC_SLOT(SLOT8_2);
-       env_hh =OPL_CALC_SLOT(SLOT7_1) + whitenoise;
-
-       /* PG */
-       if(SLOT7_1->vib) SLOT7_1->Cnt += (2*SLOT7_1->Incr*vib/VIB_RATE);
-       else             SLOT7_1->Cnt += 2*SLOT7_1->Incr;
-       if(SLOT7_2->vib) SLOT7_2->Cnt += ((CH[7].fc*8)*vib/VIB_RATE);
-       else             SLOT7_2->Cnt += (CH[7].fc*8);
-       if(SLOT8_1->vib) SLOT8_1->Cnt += (SLOT8_1->Incr*vib/VIB_RATE);
-       else             SLOT8_1->Cnt += SLOT8_1->Incr;
-       if(SLOT8_2->vib) SLOT8_2->Cnt += ((CH[8].fc*48)*vib/VIB_RATE);
-       else             SLOT8_2->Cnt += (CH[8].fc*48);
-
-       tone8 = OP_OUT(SLOT8_2,whitenoise,0 );
-
-       /* SD */
-       if( env_sd < EG_ENT-1 )
-               outd[0] += OP_OUT(SLOT7_1,env_sd, 0)*8;
-       /* TAM */
-       if( env_tam < EG_ENT-1 )
-               outd[0] += OP_OUT(SLOT8_1,env_tam, 0)*2;
-       /* TOP-CY */
-       if( env_top < EG_ENT-1 )
-               outd[0] += OP_OUT(SLOT7_2,env_top,tone8)*2;
-       /* HH */
-       if( env_hh  < EG_ENT-1 )
-               outd[0] += OP_OUT(SLOT7_2,env_hh,tone8)*2;
-}
-
-/* ----------- initialize time tabls ----------- */
-static void init_timetables( FM_OPL *OPL , int ARRATE , int DRRATE )
-{
-       int i;
-       double rate;
-
-       /* make attack rate & decay rate tables */
-       for (i = 0;i < 4;i++) OPL->AR_TABLE[i] = OPL->DR_TABLE[i] = 0;
-       for (i = 4;i <= 60;i++){
-               rate  = OPL->freqbase;                                          /* frequency rate */
-               if( i < 60 ) rate *= 1.0+(i&3)*0.25;            /* b0-1 : x1 , x1.25 , x1.5 , x1.75 */
-               rate *= 1<<((i>>2)-1);                                          /* b2-5 : shift bit */
-               rate *= (double)(EG_ENT<<ENV_BITS);
-               OPL->AR_TABLE[i] = rate / ARRATE;
-               OPL->DR_TABLE[i] = rate / DRRATE;
-       }
-       for (i = 60; i < ARRAY_SIZE(OPL->AR_TABLE); i++)
-       {
-               OPL->AR_TABLE[i] = EG_AED-1;
-               OPL->DR_TABLE[i] = OPL->DR_TABLE[60];
-       }
-#if 0
-       for (i = 0;i < 64 ;i++){        /* make for overflow area */
-               LOG(LOG_WAR, ("rate %2d , ar %f ms , dr %f ms\n", i,
-                       ((double)(EG_ENT<<ENV_BITS) / OPL->AR_TABLE[i]) * (1000.0 / OPL->rate),
-                       ((double)(EG_ENT<<ENV_BITS) / OPL->DR_TABLE[i]) * (1000.0 / OPL->rate) ));
-       }
-#endif
-}
-
-/* ---------- generic table initialize ---------- */
-static int OPLOpenTable( void )
-{
-       int s,t;
-       double rate;
-       int i,j;
-       double pom;
-
-       /* allocate dynamic tables */
-       if( (TL_TABLE = malloc(TL_MAX*2*sizeof(INT32))) == NULL)
-               return 0;
-       if( (SIN_TABLE = malloc(SIN_ENT*4 *sizeof(INT32 *))) == NULL)
-       {
-               free(TL_TABLE);
-               return 0;
-       }
-       if( (AMS_TABLE = malloc(AMS_ENT*2 *sizeof(INT32))) == NULL)
-       {
-               free(TL_TABLE);
-               free(SIN_TABLE);
-               return 0;
-       }
-       if( (VIB_TABLE = malloc(VIB_ENT*2 *sizeof(INT32))) == NULL)
-       {
-               free(TL_TABLE);
-               free(SIN_TABLE);
-               free(AMS_TABLE);
-               return 0;
-       }
-       /* make total level table */
-       for (t = 0;t < EG_ENT-1 ;t++){
-               rate = ((1<<TL_BITS)-1)/pow(10,EG_STEP*t/20);   /* dB -> voltage */
-               TL_TABLE[       t] =  (int)rate;
-               TL_TABLE[TL_MAX+t] = -TL_TABLE[t];
-/*             LOG(LOG_INF,("TotalLevel(%3d) = %x\n",t,TL_TABLE[t]));*/
-       }
-       /* fill volume off area */
-       for ( t = EG_ENT-1; t < TL_MAX ;t++){
-               TL_TABLE[t] = TL_TABLE[TL_MAX+t] = 0;
-       }
-
-       /* make sinwave table (total level offet) */
-       /* degree 0 = degree 180                   = off */
-       SIN_TABLE[0] = SIN_TABLE[SIN_ENT/2]         = &TL_TABLE[EG_ENT-1];
-       for (s = 1;s <= SIN_ENT/4;s++){
-               pom = sin(2*PI*s/SIN_ENT); /* sin     */
-               pom = 20*log10(1/pom);     /* decibel */
-               j = pom / EG_STEP;         /* TL_TABLE steps */
-
-        /* degree 0   -  90    , degree 180 -  90 : plus section */
-               SIN_TABLE[          s] = SIN_TABLE[SIN_ENT/2-s] = &TL_TABLE[j];
-        /* degree 180 - 270    , degree 360 - 270 : minus section */
-               SIN_TABLE[SIN_ENT/2+s] = SIN_TABLE[SIN_ENT  -s] = &TL_TABLE[TL_MAX+j];
-/*             LOG(LOG_INF,("sin(%3d) = %f:%f db\n",s,pom,(double)j * EG_STEP));*/
-       }
-       for (s = 0;s < SIN_ENT;s++)
-       {
-               SIN_TABLE[SIN_ENT*1+s] = s<(SIN_ENT/2) ? SIN_TABLE[s] : &TL_TABLE[EG_ENT];
-               SIN_TABLE[SIN_ENT*2+s] = SIN_TABLE[s % (SIN_ENT/2)];
-               SIN_TABLE[SIN_ENT*3+s] = (s/(SIN_ENT/4))&1 ? &TL_TABLE[EG_ENT] : SIN_TABLE[SIN_ENT*2+s];
-       }
-
-       /* envelope counter -> envelope output table */
-       for (i=0; i<EG_ENT; i++)
-       {
-               /* ATTACK curve */
-               pom = pow( ((double)(EG_ENT-1-i)/EG_ENT) , 8 ) * EG_ENT;
-               /* if( pom >= EG_ENT ) pom = EG_ENT-1; */
-               ENV_CURVE[i] = (int)pom;
-               /* DECAY ,RELEASE curve */
-               ENV_CURVE[(EG_DST>>ENV_BITS)+i]= i;
-       }
-       /* off */
-       ENV_CURVE[EG_OFF>>ENV_BITS]= EG_ENT-1;
-       /* make LFO ams table */
-       for (i=0; i<AMS_ENT; i++)
-       {
-               pom = (1.0+sin(2*PI*i/AMS_ENT))/2; /* sin */
-               AMS_TABLE[i]         = (1.0/EG_STEP)*pom; /* 1dB   */
-               AMS_TABLE[AMS_ENT+i] = (4.8/EG_STEP)*pom; /* 4.8dB */
-       }
-       /* make LFO vibrate table */
-       for (i=0; i<VIB_ENT; i++)
-       {
-               /* 100cent = 1seminote = 6% ?? */
-               pom = (double)VIB_RATE*0.06*sin(2*PI*i/VIB_ENT); /* +-100sect step */
-               VIB_TABLE[i]         = VIB_RATE + (pom*0.07); /* +- 7cent */
-               VIB_TABLE[VIB_ENT+i] = VIB_RATE + (pom*0.14); /* +-14cent */
-               /* LOG(LOG_INF,("vib %d=%d\n",i,VIB_TABLE[VIB_ENT+i])); */
-       }
-       return 1;
-}
-
-
-static void OPLCloseTable( void )
-{
-       free(TL_TABLE);
-       free(SIN_TABLE);
-       free(AMS_TABLE);
-       free(VIB_TABLE);
-}
-
-/* CSM Key Control */
-INLINE void CSMKeyControll(OPL_CH *CH)
-{
-       OPL_SLOT *slot1 = &CH->SLOT[SLOT1];
-       OPL_SLOT *slot2 = &CH->SLOT[SLOT2];
-       /* all key off */
-       OPL_KEYOFF(slot1);
-       OPL_KEYOFF(slot2);
-       /* total level latch */
-       slot1->TLL = slot1->TL + (CH->ksl_base>>slot1->ksl);
-       slot1->TLL = slot1->TL + (CH->ksl_base>>slot1->ksl);
-       /* key on */
-       CH->op1_out[0] = CH->op1_out[1] = 0;
-       OPL_KEYON(slot1);
-       OPL_KEYON(slot2);
-}
-
-/* ---------- opl initialize ---------- */
-static void OPL_initialize(FM_OPL *OPL)
-{
-       int fn;
-
-       /* frequency base */
-       OPL->freqbase = (OPL->rate) ? ((double)OPL->clock / OPL->rate) / 72  : 0;
-       /* Timer base time */
-       OPL->TimerBase = 1.0/((double)OPL->clock / 72.0 );
-       /* make time tables */
-       init_timetables( OPL , OPL_ARRATE , OPL_DRRATE );
-       /* make fnumber -> increment counter table */
-       for( fn=0 ; fn < 1024 ; fn++ )
-       {
-               OPL->FN_TABLE[fn] = OPL->freqbase * fn * FREQ_RATE * (1<<7) / 2;
-       }
-       /* LFO freq.table */
-       OPL->amsIncr = OPL->rate ? (double)AMS_ENT*(1<<AMS_SHIFT) / OPL->rate * 3.7 * ((double)OPL->clock/3600000) : 0;
-       OPL->vibIncr = OPL->rate ? (double)VIB_ENT*(1<<VIB_SHIFT) / OPL->rate * 6.4 * ((double)OPL->clock/3600000) : 0;
-}
-
-/* ---------- write a OPL registers ---------- */
-static void OPLWriteReg(FM_OPL *OPL, int r, int v)
-{
-       OPL_CH *CH;
-       int slot;
-       int block_fnum;
-
-       switch(r&0xe0)
-       {
-       case 0x00: /* 00-1f:control */
-               switch(r&0x1f)
-               {
-               case 0x01:
-                       /* wave selector enable */
-                       if(OPL->type&OPL_TYPE_WAVESEL)
-                       {
-                               OPL->wavesel = v&0x20;
-                               if(!OPL->wavesel)
-                               {
-                                       /* preset compatible mode */
-                                       int c;
-                                       for(c=0;c<OPL->max_ch;c++)
-                                       {
-                                               OPL->P_CH[c].SLOT[SLOT1].wavetable = &SIN_TABLE[0];
-                                               OPL->P_CH[c].SLOT[SLOT2].wavetable = &SIN_TABLE[0];
-                                       }
-                               }
-                       }
-                       return;
-               case 0x02:      /* Timer 1 */
-                       OPL->T[0] = (256-v)*4;
-                       break;
-               case 0x03:      /* Timer 2 */
-                       OPL->T[1] = (256-v)*16;
-                       return;
-               case 0x04:      /* IRQ clear / mask and Timer enable */
-                       if(v&0x80)
-                       {       /* IRQ flag clear */
-                               OPL_STATUS_RESET(OPL,0x7f);
-                       }
-                       else
-                       {       /* set IRQ mask ,timer enable*/
-                               UINT8 st1 = v&1;
-                               UINT8 st2 = (v>>1)&1;
-                               /* IRQRST,T1MSK,t2MSK,EOSMSK,BRMSK,x,ST2,ST1 */
-                               OPL_STATUS_RESET(OPL,v&0x78);
-                               OPL_STATUSMASK_SET(OPL,((~v)&0x78)|0x01);
-                               /* timer 2 */
-                               if(OPL->st[1] != st2)
-                               {
-                                       double interval = st2 ? (double)OPL->T[1]*OPL->TimerBase : 0.0;
-                                       OPL->st[1] = st2;
-                                       if (OPL->TimerHandler) (OPL->TimerHandler)(OPL->TimerParam+1,interval);
-                               }
-                               /* timer 1 */
-                               if(OPL->st[0] != st1)
-                               {
-                                       double interval = st1 ? (double)OPL->T[0]*OPL->TimerBase : 0.0;
-                                       OPL->st[0] = st1;
-                                       if (OPL->TimerHandler) (OPL->TimerHandler)(OPL->TimerParam+0,interval);
-                               }
-                       }
-                       return;
-#if BUILD_Y8950
-               case 0x06:              /* Key Board OUT */
-                       if(OPL->type&OPL_TYPE_KEYBOARD)
-                       {
-                               if(OPL->keyboardhandler_w)
-                                       OPL->keyboardhandler_w(OPL->keyboard_param,v);
-                               else
-                                       LOG(LOG_WAR,("OPL:write unmapped KEYBOARD port\n"));
-                       }
-                       return;
-               case 0x07:      /* DELTA-T control : START,REC,MEMDATA,REPT,SPOFF,x,x,RST */
-                       if(OPL->type&OPL_TYPE_ADPCM)
-                               YM_DELTAT_ADPCM_Write(OPL->deltat,r-0x07,v);
-                       return;
-               case 0x08:      /* MODE,DELTA-T : CSM,NOTESEL,x,x,smpl,da/ad,64k,rom */
-                       OPL->mode = v;
-                       v&=0x1f;        /* for DELTA-T unit */
-               case 0x09:              /* START ADD */
-               case 0x0a:
-               case 0x0b:              /* STOP ADD  */
-               case 0x0c:
-               case 0x0d:              /* PRESCALE   */
-               case 0x0e:
-               case 0x0f:              /* ADPCM data */
-               case 0x10:              /* DELTA-N    */
-               case 0x11:              /* DELTA-N    */
-               case 0x12:              /* EG-CTRL    */
-                       if(OPL->type&OPL_TYPE_ADPCM)
-                               YM_DELTAT_ADPCM_Write(OPL->deltat,r-0x07,v);
-                       return;
-#if 0
-               case 0x15:              /* DAC data    */
-               case 0x16:
-               case 0x17:              /* SHIFT    */
-                       return;
-               case 0x18:              /* I/O CTRL (Direction) */
-                       if(OPL->type&OPL_TYPE_IO)
-                               OPL->portDirection = v&0x0f;
-                       return;
-               case 0x19:              /* I/O DATA */
-                       if(OPL->type&OPL_TYPE_IO)
-                       {
-                               OPL->portLatch = v;
-                               if(OPL->porthandler_w)
-                                       OPL->porthandler_w(OPL->port_param,v&OPL->portDirection);
-                       }
-                       return;
-               case 0x1a:              /* PCM data */
-                       return;
-#endif
-#endif
-               }
-               break;
-       case 0x20:      /* am,vib,ksr,eg type,mul */
-               slot = slot_array[r&0x1f];
-               if(slot == -1) return;
-               set_mul(OPL,slot,v);
-               return;
-       case 0x40:
-               slot = slot_array[r&0x1f];
-               if(slot == -1) return;
-               set_ksl_tl(OPL,slot,v);
-               return;
-       case 0x60:
-               slot = slot_array[r&0x1f];
-               if(slot == -1) return;
-               set_ar_dr(OPL,slot,v);
-               return;
-       case 0x80:
-               slot = slot_array[r&0x1f];
-               if(slot == -1) return;
-               set_sl_rr(OPL,slot,v);
-               return;
-       case 0xa0:
-               switch(r)
-               {
-               case 0xbd:
-                       /* amsep,vibdep,r,bd,sd,tom,tc,hh */
-                       {
-                       UINT8 rkey = OPL->rhythm^v;
-                       OPL->ams_table = &AMS_TABLE[v&0x80 ? AMS_ENT : 0];
-                       OPL->vib_table = &VIB_TABLE[v&0x40 ? VIB_ENT : 0];
-                       OPL->rhythm  = v&0x3f;
-                       if(OPL->rhythm&0x20)
-                       {
-#if 0
-                               usrintf_showmessage("OPL Rhythm mode select");
-#endif
-                               /* BD key on/off */
-                               if(rkey&0x10)
-                               {
-                                       if(v&0x10)
-                                       {
-                                               OPL->P_CH[6].op1_out[0] = OPL->P_CH[6].op1_out[1] = 0;
-                                               OPL_KEYON(&OPL->P_CH[6].SLOT[SLOT1]);
-                                               OPL_KEYON(&OPL->P_CH[6].SLOT[SLOT2]);
-                                       }
-                                       else
-                                       {
-                                               OPL_KEYOFF(&OPL->P_CH[6].SLOT[SLOT1]);
-                                               OPL_KEYOFF(&OPL->P_CH[6].SLOT[SLOT2]);
-                                       }
-                               }
-                               /* SD key on/off */
-                               if(rkey&0x08)
-                               {
-                                       if(v&0x08) OPL_KEYON(&OPL->P_CH[7].SLOT[SLOT2]);
-                                       else       OPL_KEYOFF(&OPL->P_CH[7].SLOT[SLOT2]);
-                               }/* TAM key on/off */
-                               if(rkey&0x04)
-                               {
-                                       if(v&0x04) OPL_KEYON(&OPL->P_CH[8].SLOT[SLOT1]);
-                                       else       OPL_KEYOFF(&OPL->P_CH[8].SLOT[SLOT1]);
-                               }
-                               /* TOP-CY key on/off */
-                               if(rkey&0x02)
-                               {
-                                       if(v&0x02) OPL_KEYON(&OPL->P_CH[8].SLOT[SLOT2]);
-                                       else       OPL_KEYOFF(&OPL->P_CH[8].SLOT[SLOT2]);
-                               }
-                               /* HH key on/off */
-                               if(rkey&0x01)
-                               {
-                                       if(v&0x01) OPL_KEYON(&OPL->P_CH[7].SLOT[SLOT1]);
-                                       else       OPL_KEYOFF(&OPL->P_CH[7].SLOT[SLOT1]);
-                               }
-                       }
-                       }
-                       return;
-               }
-               /* keyon,block,fnum */
-               if( (r&0x0f) > 8) return;
-               CH = &OPL->P_CH[r&0x0f];
-               if(!(r&0x10))
-               {       /* a0-a8 */
-                       block_fnum  = (CH->block_fnum&0x1f00) | v;
-               }
-               else
-               {       /* b0-b8 */
-                       int keyon = (v>>5)&1;
-                       block_fnum = ((v&0x1f)<<8) | (CH->block_fnum&0xff);
-                       if(CH->keyon != keyon)
-                       {
-                               if( (CH->keyon=keyon) )
-                               {
-                                       CH->op1_out[0] = CH->op1_out[1] = 0;
-                                       OPL_KEYON(&CH->SLOT[SLOT1]);
-                                       OPL_KEYON(&CH->SLOT[SLOT2]);
-                               }
-                               else
-                               {
-                                       OPL_KEYOFF(&CH->SLOT[SLOT1]);
-                                       OPL_KEYOFF(&CH->SLOT[SLOT2]);
-                               }
-                       }
-               }
-               /* update */
-               if(CH->block_fnum != block_fnum)
-               {
-                       int blockRv = 7-(block_fnum>>10);
-                       int fnum   = block_fnum&0x3ff;
-                       CH->block_fnum = block_fnum;
-
-                       CH->ksl_base = KSL_TABLE[block_fnum>>6];
-                       CH->fc = OPL->FN_TABLE[fnum]>>blockRv;
-                       CH->kcode = CH->block_fnum>>9;
-                       if( (OPL->mode&0x40) && CH->block_fnum&0x100) CH->kcode |=1;
-                       CALC_FCSLOT(CH,&CH->SLOT[SLOT1]);
-                       CALC_FCSLOT(CH,&CH->SLOT[SLOT2]);
-               }
-               return;
-       case 0xc0:
-               /* FB,C */
-               if( (r&0x0f) > 8) return;
-               CH = &OPL->P_CH[r&0x0f];
-               {
-               int feedback = (v>>1)&7;
-               CH->FB   = feedback ? (8+1) - feedback : 0;
-               CH->CON = v&1;
-               set_algorithm(CH);
-               }
-               return;
-       case 0xe0: /* wave type */
-               slot = slot_array[r&0x1f];
-               if(slot == -1) return;
-               CH = &OPL->P_CH[slot/2];
-               if(OPL->wavesel)
-               {
-                       /* LOG(LOG_INF,("OPL SLOT %d wave select %d\n",slot,v&3)); */
-                       CH->SLOT[slot&1].wavetable = &SIN_TABLE[(v&0x03)*SIN_ENT];
-               }
-               return;
-       }
-}
-
-/* lock/unlock for common table */
-static int OPL_LockTable(void)
-{
-       num_lock++;
-       if(num_lock>1) return 0;
-       /* first time */
-       cur_chip = NULL;
-       /* allocate total level table (128kb space) */
-       if( !OPLOpenTable() )
-       {
-               num_lock--;
-               return -1;
-       }
-       return 0;
-}
-
-static void OPL_UnLockTable(void)
-{
-       if(num_lock) num_lock--;
-       if(num_lock) return;
-       /* last time */
-       cur_chip = NULL;
-       OPLCloseTable();
-}
-
-#if (BUILD_YM3812 || BUILD_YM3526)
-/*******************************************************************************/
-/*             YM3812 local section                                                   */
-/*******************************************************************************/
-
-/* ---------- update one of chip ----------- */
-void YM3812UpdateOne(FM_OPL *OPL, INT16 *buffer, int length)
-{
-    int i;
-       int data;
-       OPLSAMPLE *buf = buffer;
-       UINT32 amsCnt  = OPL->amsCnt;
-       UINT32 vibCnt  = OPL->vibCnt;
-       UINT8 rhythm = OPL->rhythm&0x20;
-       OPL_CH *CH,*R_CH;
-
-       if( (void *)OPL != cur_chip ){
-               cur_chip = (void *)OPL;
-               /* channel pointers */
-               S_CH = OPL->P_CH;
-               E_CH = &S_CH[9];
-               /* rhythm slot */
-               SLOT7_1 = &S_CH[7].SLOT[SLOT1];
-               SLOT7_2 = &S_CH[7].SLOT[SLOT2];
-               SLOT8_1 = &S_CH[8].SLOT[SLOT1];
-               SLOT8_2 = &S_CH[8].SLOT[SLOT2];
-               /* LFO state */
-               amsIncr = OPL->amsIncr;
-               vibIncr = OPL->vibIncr;
-               ams_table = OPL->ams_table;
-               vib_table = OPL->vib_table;
-       }
-       R_CH = rhythm ? &S_CH[6] : E_CH;
-    for( i=0; i < length ; i++ )
-       {
-               /*            channel A         channel B         channel C      */
-               /* LFO */
-               ams = ams_table[(amsCnt+=amsIncr)>>AMS_SHIFT];
-               vib = vib_table[(vibCnt+=vibIncr)>>VIB_SHIFT];
-               outd[0] = 0;
-               /* FM part */
-               for(CH=S_CH ; CH < R_CH ; CH++)
-                       OPL_CALC_CH(CH);
-               /* Rythn part */
-               if(rhythm)
-                       OPL_CALC_RH(S_CH);
-               /* limit check */
-               data = Limit( outd[0] , OPL_MAXOUT, OPL_MINOUT );
-               /* store to sound buffer */
-               buf[i] = data >> OPL_OUTSB;
-       }
-
-       OPL->amsCnt = amsCnt;
-       OPL->vibCnt = vibCnt;
-#ifdef OPL_OUTPUT_LOG
-       if(opl_dbg_fp)
-       {
-               for(opl_dbg_chip=0;opl_dbg_chip<opl_dbg_maxchip;opl_dbg_chip++)
-                       if( opl_dbg_opl[opl_dbg_chip] == OPL) break;
-               fprintf(opl_dbg_fp,"%c%c%c",0x20+opl_dbg_chip,length&0xff,length/256);
-       }
-#endif
-}
-#endif /* (BUILD_YM3812 || BUILD_YM3526) */
-
-#if BUILD_Y8950
-
-void Y8950UpdateOne(FM_OPL *OPL, INT16 *buffer, int length)
-{
-    int i;
-       int data;
-       OPLSAMPLE *buf = buffer;
-       UINT32 amsCnt  = OPL->amsCnt;
-       UINT32 vibCnt  = OPL->vibCnt;
-       UINT8 rhythm = OPL->rhythm&0x20;
-       OPL_CH *CH,*R_CH;
-       YM_DELTAT *DELTAT = OPL->deltat;
-
-       /* setup DELTA-T unit */
-       YM_DELTAT_DECODE_PRESET(DELTAT);
-
-       if( (void *)OPL != cur_chip ){
-               cur_chip = (void *)OPL;
-               /* channel pointers */
-               S_CH = OPL->P_CH;
-               E_CH = &S_CH[9];
-               /* rhythm slot */
-               SLOT7_1 = &S_CH[7].SLOT[SLOT1];
-               SLOT7_2 = &S_CH[7].SLOT[SLOT2];
-               SLOT8_1 = &S_CH[8].SLOT[SLOT1];
-               SLOT8_2 = &S_CH[8].SLOT[SLOT2];
-               /* LFO state */
-               amsIncr = OPL->amsIncr;
-               vibIncr = OPL->vibIncr;
-               ams_table = OPL->ams_table;
-               vib_table = OPL->vib_table;
-       }
-       R_CH = rhythm ? &S_CH[6] : E_CH;
-    for( i=0; i < length ; i++ )
-       {
-               /*            channel A         channel B         channel C      */
-               /* LFO */
-               ams = ams_table[(amsCnt+=amsIncr)>>AMS_SHIFT];
-               vib = vib_table[(vibCnt+=vibIncr)>>VIB_SHIFT];
-               outd[0] = 0;
-               /* deltaT ADPCM */
-               if( DELTAT->portstate )
-                       YM_DELTAT_ADPCM_CALC(DELTAT);
-               /* FM part */
-               for(CH=S_CH ; CH < R_CH ; CH++)
-                       OPL_CALC_CH(CH);
-               /* Rythn part */
-               if(rhythm)
-                       OPL_CALC_RH(S_CH);
-               /* limit check */
-               data = Limit( outd[0] , OPL_MAXOUT, OPL_MINOUT );
-               /* store to sound buffer */
-               buf[i] = data >> OPL_OUTSB;
-       }
-       OPL->amsCnt = amsCnt;
-       OPL->vibCnt = vibCnt;
-       /* deltaT START flag */
-       if( !DELTAT->portstate )
-               OPL->status &= 0xfe;
-}
-#endif
-
-/* ---------- reset one of chip ---------- */
-void OPLResetChip(FM_OPL *OPL)
-{
-       int c,s;
-       int i;
-
-       /* reset chip */
-       OPL->mode   = 0;        /* normal mode */
-       OPL_STATUS_RESET(OPL,0x7f);
-       /* reset with register write */
-       OPLWriteReg(OPL,0x01,0); /* wabesel disable */
-       OPLWriteReg(OPL,0x02,0); /* Timer1 */
-       OPLWriteReg(OPL,0x03,0); /* Timer2 */
-       OPLWriteReg(OPL,0x04,0); /* IRQ mask clear */
-       for(i = 0xff ; i >= 0x20 ; i-- ) OPLWriteReg(OPL,i,0);
-       /* reset OPerator paramater */
-       for( c = 0 ; c < OPL->max_ch ; c++ )
-       {
-               OPL_CH *CH = &OPL->P_CH[c];
-               /* OPL->P_CH[c].PAN = OPN_CENTER; */
-               for(s = 0 ; s < 2 ; s++ )
-               {
-                       /* wave table */
-                       CH->SLOT[s].wavetable = &SIN_TABLE[0];
-                       /* CH->SLOT[s].evm = ENV_MOD_RR; */
-                       CH->SLOT[s].evc = EG_OFF;
-                       CH->SLOT[s].eve = EG_OFF+1;
-                       CH->SLOT[s].evs = 0;
-               }
-       }
-#if BUILD_Y8950
-       if(OPL->type&OPL_TYPE_ADPCM)
-       {
-               YM_DELTAT *DELTAT = OPL->deltat;
-
-               DELTAT->freqbase = OPL->freqbase;
-               DELTAT->output_pointer = outd;
-               DELTAT->portshift = 5;
-               DELTAT->output_range = DELTAT_MIXING_LEVEL<<TL_BITS;
-               YM_DELTAT_ADPCM_Reset(DELTAT,0);
-       }
-#endif
-}
-
-/* ----------  Create one of vietual YM3812 ----------       */
-/* 'rate'  is sampling rate and 'bufsiz' is the size of the  */
-FM_OPL *OPLCreate(int type, int clock, int rate)
-{
-       char *ptr;
-       FM_OPL *OPL;
-       int state_size;
-       int max_ch = 9; /* normaly 9 channels */
-
-       if( OPL_LockTable() ==-1) return NULL;
-       /* allocate OPL state space */
-       state_size  = sizeof(FM_OPL);
-       state_size += sizeof(OPL_CH)*max_ch;
-#if BUILD_Y8950
-       if(type&OPL_TYPE_ADPCM) state_size+= sizeof(YM_DELTAT);
-#endif
-       /* allocate memory block */
-       ptr = malloc(state_size);
-       if(ptr==NULL) return NULL;
-       /* clear */
-       memset(ptr,0,state_size);
-       OPL        = (FM_OPL *)ptr; ptr+=sizeof(FM_OPL);
-       OPL->P_CH  = (OPL_CH *)ptr; ptr+=sizeof(OPL_CH)*max_ch;
-#if BUILD_Y8950
-       if(type&OPL_TYPE_ADPCM) OPL->deltat = (YM_DELTAT *)ptr; ptr+=sizeof(YM_DELTAT);
-#endif
-       /* set channel state pointer */
-       OPL->type  = type;
-       OPL->clock = clock;
-       OPL->rate  = rate;
-       OPL->max_ch = max_ch;
-       /* init grobal tables */
-       OPL_initialize(OPL);
-       /* reset chip */
-       OPLResetChip(OPL);
-#ifdef OPL_OUTPUT_LOG
-       if(!opl_dbg_fp)
-       {
-               opl_dbg_fp = fopen("opllog.opl","wb");
-               opl_dbg_maxchip = 0;
-       }
-       if(opl_dbg_fp)
-       {
-               opl_dbg_opl[opl_dbg_maxchip] = OPL;
-               fprintf(opl_dbg_fp,"%c%c%c%c%c%c",0x00+opl_dbg_maxchip,
-                       type,
-                       clock&0xff,
-                       (clock/0x100)&0xff,
-                       (clock/0x10000)&0xff,
-                       (clock/0x1000000)&0xff);
-               opl_dbg_maxchip++;
-       }
-#endif
-       return OPL;
-}
-
-/* ----------  Destroy one of vietual YM3812 ----------       */
-void OPLDestroy(FM_OPL *OPL)
-{
-#ifdef OPL_OUTPUT_LOG
-       if(opl_dbg_fp)
-       {
-               fclose(opl_dbg_fp);
-               opl_dbg_fp = NULL;
-       }
-#endif
-       OPL_UnLockTable();
-       free(OPL);
-}
-
-/* ----------  Option handlers ----------       */
-
-void OPLSetTimerHandler(FM_OPL *OPL,OPL_TIMERHANDLER TimerHandler,int channelOffset)
-{
-       OPL->TimerHandler   = TimerHandler;
-       OPL->TimerParam = channelOffset;
-}
-void OPLSetIRQHandler(FM_OPL *OPL,OPL_IRQHANDLER IRQHandler,int param)
-{
-       OPL->IRQHandler     = IRQHandler;
-       OPL->IRQParam = param;
-}
-void OPLSetUpdateHandler(FM_OPL *OPL,OPL_UPDATEHANDLER UpdateHandler,int param)
-{
-       OPL->UpdateHandler = UpdateHandler;
-       OPL->UpdateParam = param;
-}
-#if BUILD_Y8950
-void OPLSetPortHandler(FM_OPL *OPL,OPL_PORTHANDLER_W PortHandler_w,OPL_PORTHANDLER_R PortHandler_r,int param)
-{
-       OPL->porthandler_w = PortHandler_w;
-       OPL->porthandler_r = PortHandler_r;
-       OPL->port_param = param;
-}
-
-void OPLSetKeyboardHandler(FM_OPL *OPL,OPL_PORTHANDLER_W KeyboardHandler_w,OPL_PORTHANDLER_R KeyboardHandler_r,int param)
-{
-       OPL->keyboardhandler_w = KeyboardHandler_w;
-       OPL->keyboardhandler_r = KeyboardHandler_r;
-       OPL->keyboard_param = param;
-}
-#endif
-/* ---------- YM3812 I/O interface ---------- */
-int OPLWrite(FM_OPL *OPL,int a,int v)
-{
-       if( !(a&1) )
-       {       /* address port */
-               OPL->address = v & 0xff;
-       }
-       else
-       {       /* data port */
-               if(OPL->UpdateHandler) OPL->UpdateHandler(OPL->UpdateParam,0);
-#ifdef OPL_OUTPUT_LOG
-       if(opl_dbg_fp)
-       {
-               for(opl_dbg_chip=0;opl_dbg_chip<opl_dbg_maxchip;opl_dbg_chip++)
-                       if( opl_dbg_opl[opl_dbg_chip] == OPL) break;
-               fprintf(opl_dbg_fp,"%c%c%c",0x10+opl_dbg_chip,OPL->address,v);
-       }
-#endif
-               OPLWriteReg(OPL,OPL->address,v);
-       }
-       return OPL->status>>7;
-}
-
-unsigned char OPLRead(FM_OPL *OPL,int a)
-{
-       if( !(a&1) )
-       {       /* status port */
-               return OPL->status & (OPL->statusmask|0x80);
-       }
-       /* data port */
-       switch(OPL->address)
-       {
-       case 0x05: /* KeyBoard IN */
-               if(OPL->type&OPL_TYPE_KEYBOARD)
-               {
-                       if(OPL->keyboardhandler_r)
-                               return OPL->keyboardhandler_r(OPL->keyboard_param);
-                       else {
-                               LOG(LOG_WAR,("OPL:read unmapped KEYBOARD port\n"));
-                       }
-               }
-               return 0;
-#if 0
-       case 0x0f: /* ADPCM-DATA  */
-               return 0;
-#endif
-       case 0x19: /* I/O DATA    */
-               if(OPL->type&OPL_TYPE_IO)
-               {
-                       if(OPL->porthandler_r)
-                               return OPL->porthandler_r(OPL->port_param);
-                       else {
-                               LOG(LOG_WAR,("OPL:read unmapped I/O port\n"));
-                       }
-               }
-               return 0;
-       case 0x1a: /* PCM-DATA    */
-               return 0;
-       }
-       return 0;
-}
-
-int OPLTimerOver(FM_OPL *OPL,int c)
-{
-       if( c )
-       {       /* Timer B */
-               OPL_STATUS_SET(OPL,0x20);
-       }
-       else
-       {       /* Timer A */
-               OPL_STATUS_SET(OPL,0x40);
-               /* CSM mode key,TL control */
-               if( OPL->mode & 0x80 )
-               {       /* CSM mode total level latch and auto key on */
-                       int ch;
-                       if(OPL->UpdateHandler) OPL->UpdateHandler(OPL->UpdateParam,0);
-                       for(ch=0;ch<9;ch++)
-                               CSMKeyControll( &OPL->P_CH[ch] );
-               }
-       }
-       /* reload timer */
-       if (OPL->TimerHandler) (OPL->TimerHandler)(OPL->TimerParam+c,(double)OPL->T[c]*OPL->TimerBase);
-       return OPL->status>>7;
-}
diff --git a/hw/fmopl.h b/hw/fmopl.h
deleted file mode 100644 (file)
index 24ba5f4..0000000
+++ /dev/null
@@ -1,174 +0,0 @@
-#ifndef __FMOPL_H_
-#define __FMOPL_H_
-
-/* --- select emulation chips --- */
-#define BUILD_YM3812 (HAS_YM3812)
-//#define BUILD_YM3526 (HAS_YM3526)
-//#define BUILD_Y8950  (HAS_Y8950)
-
-/* --- system optimize --- */
-/* select bit size of output : 8 or 16 */
-#define OPL_OUTPUT_BIT 16
-
-/* compiler dependence */
-#ifndef OSD_CPU_H
-#define OSD_CPU_H
-typedef unsigned char  UINT8;   /* unsigned  8bit */
-typedef unsigned short UINT16;  /* unsigned 16bit */
-typedef unsigned int   UINT32;  /* unsigned 32bit */
-typedef signed char            INT8;    /* signed  8bit   */
-typedef signed short   INT16;   /* signed 16bit   */
-typedef signed int             INT32;   /* signed 32bit   */
-#endif
-
-#if (OPL_OUTPUT_BIT==16)
-typedef INT16 OPLSAMPLE;
-#endif
-#if (OPL_OUTPUT_BIT==8)
-typedef unsigned char  OPLSAMPLE;
-#endif
-
-
-#if BUILD_Y8950
-#include "ymdeltat.h"
-#endif
-
-typedef void (*OPL_TIMERHANDLER)(int channel,double interval_Sec);
-typedef void (*OPL_IRQHANDLER)(int param,int irq);
-typedef void (*OPL_UPDATEHANDLER)(int param,int min_interval_us);
-typedef void (*OPL_PORTHANDLER_W)(int param,unsigned char data);
-typedef unsigned char (*OPL_PORTHANDLER_R)(int param);
-
-/* !!!!! here is private section , do not access there member direct !!!!! */
-
-#define OPL_TYPE_WAVESEL   0x01  /* waveform select    */
-#define OPL_TYPE_ADPCM     0x02  /* DELTA-T ADPCM unit */
-#define OPL_TYPE_KEYBOARD  0x04  /* keyboard interface */
-#define OPL_TYPE_IO        0x08  /* I/O port */
-
-/* Saving is necessary for member of the 'R' mark for suspend/resume */
-/* ---------- OPL one of slot  ---------- */
-typedef struct fm_opl_slot {
-       INT32 TL;               /* total level     :TL << 8            */
-       INT32 TLL;              /* adjusted now TL                     */
-       UINT8  KSR;             /* key scale rate  :(shift down bit)   */
-       INT32 *AR;              /* attack rate     :&AR_TABLE[AR<<2]   */
-       INT32 *DR;              /* decay rate      :&DR_TALBE[DR<<2]   */
-       INT32 SL;               /* sustin level    :SL_TALBE[SL]       */
-       INT32 *RR;              /* release rate    :&DR_TABLE[RR<<2]   */
-       UINT8 ksl;              /* keyscale level  :(shift down bits)  */
-       UINT8 ksr;              /* key scale rate  :kcode>>KSR         */
-       UINT32 mul;             /* multiple        :ML_TABLE[ML]       */
-       UINT32 Cnt;             /* frequency count :                   */
-       UINT32 Incr;    /* frequency step  :                   */
-       /* envelope generator state */
-       UINT8 eg_typ;   /* envelope type flag                  */
-       UINT8 evm;              /* envelope phase                      */
-       INT32 evc;              /* envelope counter                    */
-       INT32 eve;              /* envelope counter end point          */
-       INT32 evs;              /* envelope counter step               */
-       INT32 evsa;     /* envelope step for AR :AR[ksr]           */
-       INT32 evsd;     /* envelope step for DR :DR[ksr]           */
-       INT32 evsr;     /* envelope step for RR :RR[ksr]           */
-       /* LFO */
-       UINT8 ams;              /* ams flag                            */
-       UINT8 vib;              /* vibrate flag                        */
-       /* wave selector */
-       INT32 **wavetable;
-}OPL_SLOT;
-
-/* ---------- OPL one of channel  ---------- */
-typedef struct fm_opl_channel {
-       OPL_SLOT SLOT[2];
-       UINT8 CON;                      /* connection type                     */
-       UINT8 FB;                       /* feed back       :(shift down bit)   */
-       INT32 *connect1;        /* slot1 output pointer                */
-       INT32 *connect2;        /* slot2 output pointer                */
-       INT32 op1_out[2];       /* slot1 output for selfeedback        */
-       /* phase generator state */
-       UINT32  block_fnum;     /* block+fnum      :                   */
-       UINT8 kcode;            /* key code        : KeyScaleCode      */
-       UINT32  fc;                     /* Freq. Increment base                */
-       UINT32  ksl_base;       /* KeyScaleLevel Base step             */
-       UINT8 keyon;            /* key on/off flag                     */
-} OPL_CH;
-
-/* OPL state */
-typedef struct fm_opl_f {
-       UINT8 type;                     /* chip type                         */
-       int clock;                      /* master clock  (Hz)                */
-       int rate;                       /* sampling rate (Hz)                */
-       double freqbase;        /* frequency base                    */
-       double TimerBase;       /* Timer base time (==sampling time) */
-       UINT8 address;          /* address register                  */
-       UINT8 status;           /* status flag                       */
-       UINT8 statusmask;       /* status mask                       */
-       UINT32 mode;            /* Reg.08 : CSM , notesel,etc.       */
-       /* Timer */
-       int T[2];                       /* timer counter                     */
-       UINT8 st[2];            /* timer enable                      */
-       /* FM channel slots */
-       OPL_CH *P_CH;           /* pointer of CH                     */
-       int     max_ch;                 /* maximum channel                   */
-       /* Rhythm sention */
-       UINT8 rhythm;           /* Rhythm mode , key flag */
-#if BUILD_Y8950
-       /* Delta-T ADPCM unit (Y8950) */
-       YM_DELTAT *deltat;                      /* DELTA-T ADPCM       */
-#endif
-       /* Keyboard / I/O interface unit (Y8950) */
-       UINT8 portDirection;
-       UINT8 portLatch;
-       OPL_PORTHANDLER_R porthandler_r;
-       OPL_PORTHANDLER_W porthandler_w;
-       int port_param;
-       OPL_PORTHANDLER_R keyboardhandler_r;
-       OPL_PORTHANDLER_W keyboardhandler_w;
-       int keyboard_param;
-       /* time tables */
-       INT32 AR_TABLE[75];     /* atttack rate tables */
-       INT32 DR_TABLE[75];     /* decay rate tables   */
-       UINT32 FN_TABLE[1024];  /* fnumber -> increment counter */
-       /* LFO */
-       INT32 *ams_table;
-       INT32 *vib_table;
-       INT32 amsCnt;
-       INT32 amsIncr;
-       INT32 vibCnt;
-       INT32 vibIncr;
-       /* wave selector enable flag */
-       UINT8 wavesel;
-       /* external event callback handler */
-       OPL_TIMERHANDLER  TimerHandler;         /* TIMER handler   */
-       int TimerParam;                                         /* TIMER parameter */
-       OPL_IRQHANDLER    IRQHandler;           /* IRQ handler    */
-       int IRQParam;                                           /* IRQ parameter  */
-       OPL_UPDATEHANDLER UpdateHandler;        /* stream update handler   */
-       int UpdateParam;                                        /* stream update parameter */
-} FM_OPL;
-
-/* ---------- Generic interface section ---------- */
-#define OPL_TYPE_YM3526 (0)
-#define OPL_TYPE_YM3812 (OPL_TYPE_WAVESEL)
-#define OPL_TYPE_Y8950  (OPL_TYPE_ADPCM|OPL_TYPE_KEYBOARD|OPL_TYPE_IO)
-
-FM_OPL *OPLCreate(int type, int clock, int rate);
-void OPLDestroy(FM_OPL *OPL);
-void OPLSetTimerHandler(FM_OPL *OPL,OPL_TIMERHANDLER TimerHandler,int channelOffset);
-void OPLSetIRQHandler(FM_OPL *OPL,OPL_IRQHANDLER IRQHandler,int param);
-void OPLSetUpdateHandler(FM_OPL *OPL,OPL_UPDATEHANDLER UpdateHandler,int param);
-/* Y8950 port handlers */
-void OPLSetPortHandler(FM_OPL *OPL,OPL_PORTHANDLER_W PortHandler_w,OPL_PORTHANDLER_R PortHandler_r,int param);
-void OPLSetKeyboardHandler(FM_OPL *OPL,OPL_PORTHANDLER_W KeyboardHandler_w,OPL_PORTHANDLER_R KeyboardHandler_r,int param);
-
-void OPLResetChip(FM_OPL *OPL);
-int OPLWrite(FM_OPL *OPL,int a,int v);
-unsigned char OPLRead(FM_OPL *OPL,int a);
-int OPLTimerOver(FM_OPL *OPL,int c);
-
-/* YM3626/YM3812 local section */
-void YM3812UpdateOne(FM_OPL *OPL, INT16 *buffer, int length);
-
-void Y8950UpdateOne(FM_OPL *OPL, INT16 *buffer, int length);
-
-#endif
diff --git a/hw/framebuffer.c b/hw/framebuffer.c
deleted file mode 100644 (file)
index 7326a98..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Framebuffer device helper routines
- *
- * Copyright (c) 2009 CodeSourcery
- * Written by Paul Brook <paul@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:
-   - Do something similar for framebuffers with local ram
-   - Handle rotation here instead of hacking dest_pitch
-   - Use common pixel conversion routines instead of per-device drawfn
-   - Remove all DisplayState knowledge from devices.
- */
-
-#include "hw/hw.h"
-#include "ui/console.h"
-#include "hw/framebuffer.h"
-
-/* Render an image from a shared memory framebuffer.  */
-   
-void framebuffer_update_display(
-    DisplaySurface *ds,
-    MemoryRegion *address_space,
-    hwaddr base,
-    int cols, /* Width in pixels.  */
-    int rows, /* Height in pixels.  */
-    int src_width, /* Length of source line, in bytes.  */
-    int dest_row_pitch, /* Bytes between adjacent horizontal output pixels.  */
-    int dest_col_pitch, /* Bytes between adjacent vertical output pixels.  */
-    int invalidate, /* nonzero to redraw the whole image.  */
-    drawfn fn,
-    void *opaque,
-    int *first_row, /* Input and output.  */
-    int *last_row /* Output only */)
-{
-    hwaddr src_len;
-    uint8_t *dest;
-    uint8_t *src;
-    uint8_t *src_base;
-    int first, last = 0;
-    int dirty;
-    int i;
-    ram_addr_t addr;
-    MemoryRegionSection mem_section;
-    MemoryRegion *mem;
-
-    i = *first_row;
-    *first_row = -1;
-    src_len = src_width * rows;
-
-    mem_section = memory_region_find(address_space, base, src_len);
-    if (mem_section.size != src_len || !memory_region_is_ram(mem_section.mr)) {
-        return;
-    }
-    mem = mem_section.mr;
-    assert(mem);
-    assert(mem_section.offset_within_address_space == base);
-
-    memory_region_sync_dirty_bitmap(mem);
-    src_base = cpu_physical_memory_map(base, &src_len, 0);
-    /* If we can't map the framebuffer then bail.  We could try harder,
-       but it's not really worth it as dirty flag tracking will probably
-       already have failed above.  */
-    if (!src_base)
-        return;
-    if (src_len != src_width * rows) {
-        cpu_physical_memory_unmap(src_base, src_len, 0, 0);
-        return;
-    }
-    src = src_base;
-    dest = surface_data(ds);
-    if (dest_col_pitch < 0)
-        dest -= dest_col_pitch * (cols - 1);
-    if (dest_row_pitch < 0) {
-        dest -= dest_row_pitch * (rows - 1);
-    }
-    first = -1;
-    addr = mem_section.offset_within_region;
-
-    addr += i * src_width;
-    src += i * src_width;
-    dest += i * dest_row_pitch;
-
-    for (; i < rows; i++) {
-        dirty = memory_region_get_dirty(mem, addr, src_width,
-                                             DIRTY_MEMORY_VGA);
-        if (dirty || invalidate) {
-            fn(opaque, dest, src, cols, dest_col_pitch);
-            if (first == -1)
-                first = i;
-            last = i;
-        }
-        addr += src_width;
-        src += src_width;
-        dest += dest_row_pitch;
-    }
-    cpu_physical_memory_unmap(src_base, src_len, 0, 0);
-    if (first < 0) {
-        return;
-    }
-    memory_region_reset_dirty(mem, mem_section.offset_within_region, src_len,
-                              DIRTY_MEMORY_VGA);
-    *first_row = first;
-    *last_row = last;
-}
diff --git a/hw/framebuffer.h b/hw/framebuffer.h
deleted file mode 100644 (file)
index 6eae035..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-#ifndef QEMU_FRAMEBUFFER_H
-#define QEMU_FRAMEBUFFER_H
-
-#include "exec/memory.h"
-
-/* Framebuffer device helper routines.  */
-
-typedef void (*drawfn)(void *, uint8_t *, const uint8_t *, int, int);
-
-void framebuffer_update_display(
-    DisplaySurface *ds,
-    MemoryRegion *address_space,
-    hwaddr base,
-    int cols,
-    int rows,
-    int src_width,
-    int dest_row_pitch,
-    int dest_col_pitch,
-    int invalidate,
-    drawfn fn,
-    void *opaque,
-    int *first_row,
-    int *last_row);
-
-#endif
diff --git a/hw/fw_cfg.c b/hw/fw_cfg.c
deleted file mode 100644 (file)
index 63a1998..0000000
+++ /dev/null
@@ -1,574 +0,0 @@
-/*
- * QEMU Firmware configuration device emulation
- *
- * Copyright (c) 2008 Gleb Natapov
- *
- * 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 "hw/hw.h"
-#include "sysemu/sysemu.h"
-#include "hw/isa.h"
-#include "hw/fw_cfg.h"
-#include "hw/sysbus.h"
-#include "trace.h"
-#include "qemu/error-report.h"
-#include "qemu/config-file.h"
-
-#define FW_CFG_SIZE 2
-#define FW_CFG_DATA_SIZE 1
-
-typedef struct FWCfgEntry {
-    uint32_t len;
-    uint8_t *data;
-    void *callback_opaque;
-    FWCfgCallback callback;
-} FWCfgEntry;
-
-struct FWCfgState {
-    SysBusDevice busdev;
-    MemoryRegion ctl_iomem, data_iomem, comb_iomem;
-    uint32_t ctl_iobase, data_iobase;
-    FWCfgEntry entries[2][FW_CFG_MAX_ENTRY];
-    FWCfgFiles *files;
-    uint16_t cur_entry;
-    uint32_t cur_offset;
-    Notifier machine_ready;
-};
-
-#define JPG_FILE 0
-#define BMP_FILE 1
-
-static char *read_splashfile(char *filename, size_t *file_sizep,
-                             int *file_typep)
-{
-    GError *err = NULL;
-    gboolean res;
-    gchar *content;
-    int file_type;
-    unsigned int filehead;
-    int bmp_bpp;
-
-    res = g_file_get_contents(filename, &content, file_sizep, &err);
-    if (res == FALSE) {
-        error_report("failed to read splash file '%s'", filename);
-        g_error_free(err);
-        return NULL;
-    }
-
-    /* check file size */
-    if (*file_sizep < 30) {
-        goto error;
-    }
-
-    /* check magic ID */
-    filehead = ((content[0] & 0xff) + (content[1] << 8)) & 0xffff;
-    if (filehead == 0xd8ff) {
-        file_type = JPG_FILE;
-    } else if (filehead == 0x4d42) {
-        file_type = BMP_FILE;
-    } else {
-        goto error;
-    }
-
-    /* check BMP bpp */
-    if (file_type == BMP_FILE) {
-        bmp_bpp = (content[28] + (content[29] << 8)) & 0xffff;
-        if (bmp_bpp != 24) {
-            goto error;
-        }
-    }
-
-    /* return values */
-    *file_typep = file_type;
-
-    return content;
-
-error:
-    error_report("splash file '%s' format not recognized; must be JPEG "
-                 "or 24 bit BMP", filename);
-    g_free(content);
-    return NULL;
-}
-
-static void fw_cfg_bootsplash(FWCfgState *s)
-{
-    int boot_splash_time = -1;
-    const char *boot_splash_filename = NULL;
-    char *p;
-    char *filename, *file_data;
-    size_t file_size;
-    int file_type;
-    const char *temp;
-
-    /* get user configuration */
-    QemuOptsList *plist = qemu_find_opts("boot-opts");
-    QemuOpts *opts = QTAILQ_FIRST(&plist->head);
-    if (opts != NULL) {
-        temp = qemu_opt_get(opts, "splash");
-        if (temp != NULL) {
-            boot_splash_filename = temp;
-        }
-        temp = qemu_opt_get(opts, "splash-time");
-        if (temp != NULL) {
-            p = (char *)temp;
-            boot_splash_time = strtol(p, (char **)&p, 10);
-        }
-    }
-
-    /* insert splash time if user configurated */
-    if (boot_splash_time >= 0) {
-        /* validate the input */
-        if (boot_splash_time > 0xffff) {
-            error_report("splash time is big than 65535, force it to 65535.");
-            boot_splash_time = 0xffff;
-        }
-        /* use little endian format */
-        qemu_extra_params_fw[0] = (uint8_t)(boot_splash_time & 0xff);
-        qemu_extra_params_fw[1] = (uint8_t)((boot_splash_time >> 8) & 0xff);
-        fw_cfg_add_file(s, "etc/boot-menu-wait", qemu_extra_params_fw, 2);
-    }
-
-    /* insert splash file if user configurated */
-    if (boot_splash_filename != NULL) {
-        filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, boot_splash_filename);
-        if (filename == NULL) {
-            error_report("failed to find file '%s'.", boot_splash_filename);
-            return;
-        }
-
-        /* loading file data */
-        file_data = read_splashfile(filename, &file_size, &file_type);
-        if (file_data == NULL) {
-            g_free(filename);
-            return;
-        }
-        if (boot_splash_filedata != NULL) {
-            g_free(boot_splash_filedata);
-        }
-        boot_splash_filedata = (uint8_t *)file_data;
-        boot_splash_filedata_size = file_size;
-
-        /* insert data */
-        if (file_type == JPG_FILE) {
-            fw_cfg_add_file(s, "bootsplash.jpg",
-                    boot_splash_filedata, boot_splash_filedata_size);
-        } else {
-            fw_cfg_add_file(s, "bootsplash.bmp",
-                    boot_splash_filedata, boot_splash_filedata_size);
-        }
-        g_free(filename);
-    }
-}
-
-static void fw_cfg_reboot(FWCfgState *s)
-{
-    int reboot_timeout = -1;
-    char *p;
-    const char *temp;
-
-    /* get user configuration */
-    QemuOptsList *plist = qemu_find_opts("boot-opts");
-    QemuOpts *opts = QTAILQ_FIRST(&plist->head);
-    if (opts != NULL) {
-        temp = qemu_opt_get(opts, "reboot-timeout");
-        if (temp != NULL) {
-            p = (char *)temp;
-            reboot_timeout = strtol(p, (char **)&p, 10);
-        }
-    }
-    /* validate the input */
-    if (reboot_timeout > 0xffff) {
-        error_report("reboot timeout is larger than 65535, force it to 65535.");
-        reboot_timeout = 0xffff;
-    }
-    fw_cfg_add_file(s, "etc/boot-fail-wait", g_memdup(&reboot_timeout, 4), 4);
-}
-
-static void fw_cfg_write(FWCfgState *s, uint8_t value)
-{
-    int arch = !!(s->cur_entry & FW_CFG_ARCH_LOCAL);
-    FWCfgEntry *e = &s->entries[arch][s->cur_entry & FW_CFG_ENTRY_MASK];
-
-    trace_fw_cfg_write(s, value);
-
-    if (s->cur_entry & FW_CFG_WRITE_CHANNEL && e->callback &&
-        s->cur_offset < e->len) {
-        e->data[s->cur_offset++] = value;
-        if (s->cur_offset == e->len) {
-            e->callback(e->callback_opaque, e->data);
-            s->cur_offset = 0;
-        }
-    }
-}
-
-static int fw_cfg_select(FWCfgState *s, uint16_t key)
-{
-    int ret;
-
-    s->cur_offset = 0;
-    if ((key & FW_CFG_ENTRY_MASK) >= FW_CFG_MAX_ENTRY) {
-        s->cur_entry = FW_CFG_INVALID;
-        ret = 0;
-    } else {
-        s->cur_entry = key;
-        ret = 1;
-    }
-
-    trace_fw_cfg_select(s, key, ret);
-    return ret;
-}
-
-static uint8_t fw_cfg_read(FWCfgState *s)
-{
-    int arch = !!(s->cur_entry & FW_CFG_ARCH_LOCAL);
-    FWCfgEntry *e = &s->entries[arch][s->cur_entry & FW_CFG_ENTRY_MASK];
-    uint8_t ret;
-
-    if (s->cur_entry == FW_CFG_INVALID || !e->data || s->cur_offset >= e->len)
-        ret = 0;
-    else
-        ret = e->data[s->cur_offset++];
-
-    trace_fw_cfg_read(s, ret);
-    return ret;
-}
-
-static uint64_t fw_cfg_data_mem_read(void *opaque, hwaddr addr,
-                                     unsigned size)
-{
-    return fw_cfg_read(opaque);
-}
-
-static void fw_cfg_data_mem_write(void *opaque, hwaddr addr,
-                                  uint64_t value, unsigned size)
-{
-    fw_cfg_write(opaque, (uint8_t)value);
-}
-
-static void fw_cfg_ctl_mem_write(void *opaque, hwaddr addr,
-                                 uint64_t value, unsigned size)
-{
-    fw_cfg_select(opaque, (uint16_t)value);
-}
-
-static bool fw_cfg_ctl_mem_valid(void *opaque, hwaddr addr,
-                                 unsigned size, bool is_write)
-{
-    return is_write && size == 2;
-}
-
-static uint64_t fw_cfg_comb_read(void *opaque, hwaddr addr,
-                                 unsigned size)
-{
-    return fw_cfg_read(opaque);
-}
-
-static void fw_cfg_comb_write(void *opaque, hwaddr addr,
-                              uint64_t value, unsigned size)
-{
-    switch (size) {
-    case 1:
-        fw_cfg_write(opaque, (uint8_t)value);
-        break;
-    case 2:
-        fw_cfg_select(opaque, (uint16_t)value);
-        break;
-    }
-}
-
-static bool fw_cfg_comb_valid(void *opaque, hwaddr addr,
-                                  unsigned size, bool is_write)
-{
-    return (size == 1) || (is_write && size == 2);
-}
-
-static const MemoryRegionOps fw_cfg_ctl_mem_ops = {
-    .write = fw_cfg_ctl_mem_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid.accepts = fw_cfg_ctl_mem_valid,
-};
-
-static const MemoryRegionOps fw_cfg_data_mem_ops = {
-    .read = fw_cfg_data_mem_read,
-    .write = fw_cfg_data_mem_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid = {
-        .min_access_size = 1,
-        .max_access_size = 1,
-    },
-};
-
-static const MemoryRegionOps fw_cfg_comb_mem_ops = {
-    .read = fw_cfg_comb_read,
-    .write = fw_cfg_comb_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid.accepts = fw_cfg_comb_valid,
-};
-
-static void fw_cfg_reset(DeviceState *d)
-{
-    FWCfgState *s = DO_UPCAST(FWCfgState, busdev.qdev, d);
-
-    fw_cfg_select(s, 0);
-}
-
-/* Save restore 32 bit int as uint16_t
-   This is a Big hack, but it is how the old state did it.
-   Or we broke compatibility in the state, or we can't use struct tm
- */
-
-static int get_uint32_as_uint16(QEMUFile *f, void *pv, size_t size)
-{
-    uint32_t *v = pv;
-    *v = qemu_get_be16(f);
-    return 0;
-}
-
-static void put_unused(QEMUFile *f, void *pv, size_t size)
-{
-    fprintf(stderr, "uint32_as_uint16 is only used for backward compatibility.\n");
-    fprintf(stderr, "This functions shouldn't be called.\n");
-}
-
-static const VMStateInfo vmstate_hack_uint32_as_uint16 = {
-    .name = "int32_as_uint16",
-    .get  = get_uint32_as_uint16,
-    .put  = put_unused,
-};
-
-#define VMSTATE_UINT16_HACK(_f, _s, _t)                                    \
-    VMSTATE_SINGLE_TEST(_f, _s, _t, 0, vmstate_hack_uint32_as_uint16, uint32_t)
-
-
-static bool is_version_1(void *opaque, int version_id)
-{
-    return version_id == 1;
-}
-
-static const VMStateDescription vmstate_fw_cfg = {
-    .name = "fw_cfg",
-    .version_id = 2,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField []) {
-        VMSTATE_UINT16(cur_entry, FWCfgState),
-        VMSTATE_UINT16_HACK(cur_offset, FWCfgState, is_version_1),
-        VMSTATE_UINT32_V(cur_offset, FWCfgState, 2),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-void fw_cfg_add_bytes(FWCfgState *s, uint16_t key, void *data, size_t len)
-{
-    int arch = !!(key & FW_CFG_ARCH_LOCAL);
-
-    key &= FW_CFG_ENTRY_MASK;
-
-    assert(key < FW_CFG_MAX_ENTRY && len < UINT32_MAX);
-
-    s->entries[arch][key].data = data;
-    s->entries[arch][key].len = (uint32_t)len;
-}
-
-void fw_cfg_add_string(FWCfgState *s, uint16_t key, const char *value)
-{
-    size_t sz = strlen(value) + 1;
-
-    return fw_cfg_add_bytes(s, key, g_memdup(value, sz), sz);
-}
-
-void fw_cfg_add_i16(FWCfgState *s, uint16_t key, uint16_t value)
-{
-    uint16_t *copy;
-
-    copy = g_malloc(sizeof(value));
-    *copy = cpu_to_le16(value);
-    fw_cfg_add_bytes(s, key, copy, sizeof(value));
-}
-
-void fw_cfg_add_i32(FWCfgState *s, uint16_t key, uint32_t value)
-{
-    uint32_t *copy;
-
-    copy = g_malloc(sizeof(value));
-    *copy = cpu_to_le32(value);
-    fw_cfg_add_bytes(s, key, copy, sizeof(value));
-}
-
-void fw_cfg_add_i64(FWCfgState *s, uint16_t key, uint64_t value)
-{
-    uint64_t *copy;
-
-    copy = g_malloc(sizeof(value));
-    *copy = cpu_to_le64(value);
-    fw_cfg_add_bytes(s, key, copy, sizeof(value));
-}
-
-void fw_cfg_add_callback(FWCfgState *s, uint16_t key, FWCfgCallback callback,
-                         void *callback_opaque, void *data, size_t len)
-{
-    int arch = !!(key & FW_CFG_ARCH_LOCAL);
-
-    assert(key & FW_CFG_WRITE_CHANNEL);
-
-    key &= FW_CFG_ENTRY_MASK;
-
-    assert(key < FW_CFG_MAX_ENTRY && len <= UINT32_MAX);
-
-    s->entries[arch][key].data = data;
-    s->entries[arch][key].len = (uint32_t)len;
-    s->entries[arch][key].callback_opaque = callback_opaque;
-    s->entries[arch][key].callback = callback;
-}
-
-void fw_cfg_add_file(FWCfgState *s,  const char *filename,
-                     void *data, size_t len)
-{
-    int i, index;
-    size_t dsize;
-
-    if (!s->files) {
-        dsize = sizeof(uint32_t) + sizeof(FWCfgFile) * FW_CFG_FILE_SLOTS;
-        s->files = g_malloc0(dsize);
-        fw_cfg_add_bytes(s, FW_CFG_FILE_DIR, s->files, dsize);
-    }
-
-    index = be32_to_cpu(s->files->count);
-    assert(index < FW_CFG_FILE_SLOTS);
-
-    fw_cfg_add_bytes(s, FW_CFG_FILE_FIRST + index, data, len);
-
-    pstrcpy(s->files->f[index].name, sizeof(s->files->f[index].name),
-            filename);
-    for (i = 0; i < index; i++) {
-        if (strcmp(s->files->f[index].name, s->files->f[i].name) == 0) {
-            trace_fw_cfg_add_file_dupe(s, s->files->f[index].name);
-            return;
-        }
-    }
-
-    s->files->f[index].size   = cpu_to_be32(len);
-    s->files->f[index].select = cpu_to_be16(FW_CFG_FILE_FIRST + index);
-    trace_fw_cfg_add_file(s, index, s->files->f[index].name, len);
-
-    s->files->count = cpu_to_be32(index+1);
-}
-
-static void fw_cfg_machine_ready(struct Notifier *n, void *data)
-{
-    size_t len;
-    FWCfgState *s = container_of(n, FWCfgState, machine_ready);
-    char *bootindex = get_boot_devices_list(&len);
-
-    fw_cfg_add_file(s, "bootorder", (uint8_t*)bootindex, len);
-}
-
-FWCfgState *fw_cfg_init(uint32_t ctl_port, uint32_t data_port,
-                        hwaddr ctl_addr, hwaddr data_addr)
-{
-    DeviceState *dev;
-    SysBusDevice *d;
-    FWCfgState *s;
-
-    dev = qdev_create(NULL, "fw_cfg");
-    qdev_prop_set_uint32(dev, "ctl_iobase", ctl_port);
-    qdev_prop_set_uint32(dev, "data_iobase", data_port);
-    qdev_init_nofail(dev);
-    d = SYS_BUS_DEVICE(dev);
-
-    s = DO_UPCAST(FWCfgState, busdev.qdev, dev);
-
-    if (ctl_addr) {
-        sysbus_mmio_map(d, 0, ctl_addr);
-    }
-    if (data_addr) {
-        sysbus_mmio_map(d, 1, data_addr);
-    }
-    fw_cfg_add_bytes(s, FW_CFG_SIGNATURE, (char *)"QEMU", 4);
-    fw_cfg_add_bytes(s, FW_CFG_UUID, qemu_uuid, 16);
-    fw_cfg_add_i16(s, FW_CFG_NOGRAPHIC, (uint16_t)(display_type == DT_NOGRAPHIC));
-    fw_cfg_add_i16(s, FW_CFG_NB_CPUS, (uint16_t)smp_cpus);
-    fw_cfg_add_i16(s, FW_CFG_BOOT_MENU, (uint16_t)boot_menu);
-    fw_cfg_bootsplash(s);
-    fw_cfg_reboot(s);
-
-    s->machine_ready.notify = fw_cfg_machine_ready;
-    qemu_add_machine_init_done_notifier(&s->machine_ready);
-
-    return s;
-}
-
-static int fw_cfg_init1(SysBusDevice *dev)
-{
-    FWCfgState *s = FROM_SYSBUS(FWCfgState, dev);
-
-    memory_region_init_io(&s->ctl_iomem, &fw_cfg_ctl_mem_ops, s,
-                          "fwcfg.ctl", FW_CFG_SIZE);
-    sysbus_init_mmio(dev, &s->ctl_iomem);
-    memory_region_init_io(&s->data_iomem, &fw_cfg_data_mem_ops, s,
-                          "fwcfg.data", FW_CFG_DATA_SIZE);
-    sysbus_init_mmio(dev, &s->data_iomem);
-    /* In case ctl and data overlap: */
-    memory_region_init_io(&s->comb_iomem, &fw_cfg_comb_mem_ops, s,
-                          "fwcfg", FW_CFG_SIZE);
-
-    if (s->ctl_iobase + 1 == s->data_iobase) {
-        sysbus_add_io(dev, s->ctl_iobase, &s->comb_iomem);
-    } else {
-        if (s->ctl_iobase) {
-            sysbus_add_io(dev, s->ctl_iobase, &s->ctl_iomem);
-        }
-        if (s->data_iobase) {
-            sysbus_add_io(dev, s->data_iobase, &s->data_iomem);
-        }
-    }
-    return 0;
-}
-
-static Property fw_cfg_properties[] = {
-    DEFINE_PROP_HEX32("ctl_iobase", FWCfgState, ctl_iobase, -1),
-    DEFINE_PROP_HEX32("data_iobase", FWCfgState, data_iobase, -1),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void fw_cfg_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = fw_cfg_init1;
-    dc->no_user = 1;
-    dc->reset = fw_cfg_reset;
-    dc->vmsd = &vmstate_fw_cfg;
-    dc->props = fw_cfg_properties;
-}
-
-static const 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_types(void)
-{
-    type_register_static(&fw_cfg_info);
-}
-
-type_init(fw_cfg_register_types)
diff --git a/hw/fw_cfg.h b/hw/fw_cfg.h
deleted file mode 100644 (file)
index 05c8df1..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-#ifndef FW_CFG_H
-#define FW_CFG_H
-
-#define FW_CFG_SIGNATURE        0x00
-#define FW_CFG_ID               0x01
-#define FW_CFG_UUID             0x02
-#define FW_CFG_RAM_SIZE         0x03
-#define FW_CFG_NOGRAPHIC        0x04
-#define FW_CFG_NB_CPUS          0x05
-#define FW_CFG_MACHINE_ID       0x06
-#define FW_CFG_KERNEL_ADDR      0x07
-#define FW_CFG_KERNEL_SIZE      0x08
-#define FW_CFG_KERNEL_CMDLINE   0x09
-#define FW_CFG_INITRD_ADDR      0x0a
-#define FW_CFG_INITRD_SIZE      0x0b
-#define FW_CFG_BOOT_DEVICE      0x0c
-#define FW_CFG_NUMA             0x0d
-#define FW_CFG_BOOT_MENU        0x0e
-#define FW_CFG_MAX_CPUS         0x0f
-#define FW_CFG_KERNEL_ENTRY     0x10
-#define FW_CFG_KERNEL_DATA      0x11
-#define FW_CFG_INITRD_DATA      0x12
-#define FW_CFG_CMDLINE_ADDR     0x13
-#define FW_CFG_CMDLINE_SIZE     0x14
-#define FW_CFG_CMDLINE_DATA     0x15
-#define FW_CFG_SETUP_ADDR       0x16
-#define FW_CFG_SETUP_SIZE       0x17
-#define FW_CFG_SETUP_DATA       0x18
-#define FW_CFG_FILE_DIR         0x19
-
-#define FW_CFG_FILE_FIRST       0x20
-#define FW_CFG_FILE_SLOTS       0x10
-#define FW_CFG_MAX_ENTRY        (FW_CFG_FILE_FIRST+FW_CFG_FILE_SLOTS)
-
-#define FW_CFG_WRITE_CHANNEL    0x4000
-#define FW_CFG_ARCH_LOCAL       0x8000
-#define FW_CFG_ENTRY_MASK       ~(FW_CFG_WRITE_CHANNEL | FW_CFG_ARCH_LOCAL)
-
-#define FW_CFG_INVALID          0xffff
-
-#ifndef NO_QEMU_PROTOS
-typedef struct FWCfgFile {
-    uint32_t  size;        /* file size */
-    uint16_t  select;      /* write this to 0x510 to read it */
-    uint16_t  reserved;
-    char      name[56];
-} FWCfgFile;
-
-typedef struct FWCfgFiles {
-    uint32_t  count;
-    FWCfgFile f[];
-} FWCfgFiles;
-
-typedef void (*FWCfgCallback)(void *opaque, uint8_t *data);
-
-typedef struct FWCfgState FWCfgState;
-void fw_cfg_add_bytes(FWCfgState *s, uint16_t key, void *data, size_t len);
-void fw_cfg_add_string(FWCfgState *s, uint16_t key, const char *value);
-void fw_cfg_add_i16(FWCfgState *s, uint16_t key, uint16_t value);
-void fw_cfg_add_i32(FWCfgState *s, uint16_t key, uint32_t value);
-void fw_cfg_add_i64(FWCfgState *s, uint16_t key, uint64_t value);
-void fw_cfg_add_callback(FWCfgState *s, uint16_t key, FWCfgCallback callback,
-                         void *callback_opaque, void *data, size_t len);
-void fw_cfg_add_file(FWCfgState *s, const char *filename, void *data,
-                     size_t len);
-FWCfgState *fw_cfg_init(uint32_t ctl_port, uint32_t data_port,
-                        hwaddr crl_addr, hwaddr data_addr);
-
-#endif /* NO_QEMU_PROTOS */
-
-#endif
diff --git a/hw/g364fb.c b/hw/g364fb.c
deleted file mode 100644 (file)
index f7014e9..0000000
+++ /dev/null
@@ -1,617 +0,0 @@
-/*
- * QEMU G364 framebuffer Emulator.
- *
- * Copyright (c) 2007-2011 Herve Poussineau
- *
- * 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 "hw/hw.h"
-#include "ui/console.h"
-#include "ui/pixel_ops.h"
-#include "trace.h"
-#include "hw/sysbus.h"
-
-typedef struct G364State {
-    /* hardware */
-    uint8_t *vram;
-    uint32_t vram_size;
-    qemu_irq irq;
-    MemoryRegion mem_vram;
-    MemoryRegion mem_ctrl;
-    /* registers */
-    uint8_t color_palette[256][3];
-    uint8_t cursor_palette[3][3];
-    uint16_t cursor[512];
-    uint32_t cursor_position;
-    uint32_t ctla;
-    uint32_t top_of_screen;
-    uint32_t width, height; /* in pixels */
-    /* display refresh support */
-    QemuConsole *con;
-    int depth;
-    int blanked;
-} G364State;
-
-#define REG_BOOT     0x000000
-#define REG_DISPLAY  0x000118
-#define REG_VDISPLAY 0x000150
-#define REG_CTLA     0x000300
-#define REG_TOP      0x000400
-#define REG_CURS_PAL 0x000508
-#define REG_CURS_POS 0x000638
-#define REG_CLR_PAL  0x000800
-#define REG_CURS_PAT 0x001000
-#define REG_RESET    0x100000
-
-#define CTLA_FORCE_BLANK 0x00000400
-#define CTLA_NO_CURSOR   0x00800000
-
-#define G364_PAGE_SIZE 4096
-
-static inline int check_dirty(G364State *s, ram_addr_t page)
-{
-    return memory_region_get_dirty(&s->mem_vram, page, G364_PAGE_SIZE,
-                                   DIRTY_MEMORY_VGA);
-}
-
-static inline void reset_dirty(G364State *s,
-                               ram_addr_t page_min, ram_addr_t page_max)
-{
-    memory_region_reset_dirty(&s->mem_vram,
-                              page_min,
-                              page_max + G364_PAGE_SIZE - page_min - 1,
-                              DIRTY_MEMORY_VGA);
-}
-
-static void g364fb_draw_graphic8(G364State *s)
-{
-    DisplaySurface *surface = qemu_console_surface(s->con);
-    int i, w;
-    uint8_t *vram;
-    uint8_t *data_display, *dd;
-    ram_addr_t page, page_min, page_max;
-    int x, y;
-    int xmin, xmax;
-    int ymin, ymax;
-    int xcursor, ycursor;
-    unsigned int (*rgb_to_pixel)(unsigned int r, unsigned int g, unsigned int b);
-
-    switch (surface_bits_per_pixel(surface)) {
-        case 8:
-            rgb_to_pixel = rgb_to_pixel8;
-            w = 1;
-            break;
-        case 15:
-            rgb_to_pixel = rgb_to_pixel15;
-            w = 2;
-            break;
-        case 16:
-            rgb_to_pixel = rgb_to_pixel16;
-            w = 2;
-            break;
-        case 32:
-            rgb_to_pixel = rgb_to_pixel32;
-            w = 4;
-            break;
-        default:
-            hw_error("g364: unknown host depth %d",
-                     surface_bits_per_pixel(surface));
-            return;
-    }
-
-    page = 0;
-    page_min = (ram_addr_t)-1;
-    page_max = 0;
-
-    x = y = 0;
-    xmin = s->width;
-    xmax = 0;
-    ymin = s->height;
-    ymax = 0;
-
-    if (!(s->ctla & CTLA_NO_CURSOR)) {
-        xcursor = s->cursor_position >> 12;
-        ycursor = s->cursor_position & 0xfff;
-    } else {
-        xcursor = ycursor = -65;
-    }
-
-    vram = s->vram + s->top_of_screen;
-    /* XXX: out of range in vram? */
-    data_display = dd = surface_data(surface);
-    while (y < s->height) {
-        if (check_dirty(s, page)) {
-            if (y < ymin)
-                ymin = ymax = y;
-            if (page_min == (ram_addr_t)-1)
-                page_min = page;
-            page_max = page;
-            if (x < xmin)
-                xmin = x;
-            for (i = 0; i < G364_PAGE_SIZE; i++) {
-                uint8_t index;
-                unsigned int color;
-                if (unlikely((y >= ycursor && y < ycursor + 64) &&
-                    (x >= xcursor && x < xcursor + 64))) {
-                    /* pointer area */
-                    int xdiff = x - xcursor;
-                    uint16_t curs = s->cursor[(y - ycursor) * 8 + xdiff / 8];
-                    int op = (curs >> ((xdiff & 7) * 2)) & 3;
-                    if (likely(op == 0)) {
-                        /* transparent */
-                        index = *vram;
-                        color = (*rgb_to_pixel)(
-                            s->color_palette[index][0],
-                            s->color_palette[index][1],
-                            s->color_palette[index][2]);
-                    } else {
-                        /* get cursor color */
-                        index = op - 1;
-                        color = (*rgb_to_pixel)(
-                            s->cursor_palette[index][0],
-                            s->cursor_palette[index][1],
-                            s->cursor_palette[index][2]);
-                    }
-                } else {
-                    /* normal area */
-                    index = *vram;
-                    color = (*rgb_to_pixel)(
-                        s->color_palette[index][0],
-                        s->color_palette[index][1],
-                        s->color_palette[index][2]);
-                }
-                memcpy(dd, &color, w);
-                dd += w;
-                x++;
-                vram++;
-                if (x == s->width) {
-                    xmax = s->width - 1;
-                    y++;
-                    if (y == s->height) {
-                        ymax = s->height - 1;
-                        goto done;
-                    }
-                    data_display = dd = data_display + surface_stride(surface);
-                    xmin = 0;
-                    x = 0;
-                }
-            }
-            if (x > xmax)
-                xmax = x;
-            if (y > ymax)
-                ymax = y;
-        } else {
-            int dy;
-            if (page_min != (ram_addr_t)-1) {
-                reset_dirty(s, page_min, page_max);
-                page_min = (ram_addr_t)-1;
-                page_max = 0;
-                dpy_gfx_update(s->con, xmin, ymin,
-                               xmax - xmin + 1, ymax - ymin + 1);
-                xmin = s->width;
-                xmax = 0;
-                ymin = s->height;
-                ymax = 0;
-            }
-            x += G364_PAGE_SIZE;
-            dy = x / s->width;
-            x = x % s->width;
-            y += dy;
-            vram += G364_PAGE_SIZE;
-            data_display += dy * surface_stride(surface);
-            dd = data_display + x * w;
-        }
-        page += G364_PAGE_SIZE;
-    }
-
-done:
-    if (page_min != (ram_addr_t)-1) {
-        dpy_gfx_update(s->con, xmin, ymin, xmax - xmin + 1, ymax - ymin + 1);
-        reset_dirty(s, page_min, page_max);
-    }
-}
-
-static void g364fb_draw_blank(G364State *s)
-{
-    DisplaySurface *surface = qemu_console_surface(s->con);
-    int i, w;
-    uint8_t *d;
-
-    if (s->blanked) {
-        /* Screen is already blank. No need to redraw it */
-        return;
-    }
-
-    w = s->width * surface_bytes_per_pixel(surface);
-    d = surface_data(surface);
-    for (i = 0; i < s->height; i++) {
-        memset(d, 0, w);
-        d += surface_stride(surface);
-    }
-
-    dpy_gfx_update(s->con, 0, 0, s->width, s->height);
-    s->blanked = 1;
-}
-
-static void g364fb_update_display(void *opaque)
-{
-    G364State *s = opaque;
-    DisplaySurface *surface = qemu_console_surface(s->con);
-
-    qemu_flush_coalesced_mmio_buffer();
-
-    if (s->width == 0 || s->height == 0)
-        return;
-
-    if (s->width != surface_width(surface) ||
-        s->height != surface_height(surface)) {
-        qemu_console_resize(s->con, s->width, s->height);
-    }
-
-    if (s->ctla & CTLA_FORCE_BLANK) {
-        g364fb_draw_blank(s);
-    } else if (s->depth == 8) {
-        g364fb_draw_graphic8(s);
-    } else {
-        error_report("g364: unknown guest depth %d", s->depth);
-    }
-
-    qemu_irq_raise(s->irq);
-}
-
-static inline void g364fb_invalidate_display(void *opaque)
-{
-    G364State *s = opaque;
-
-    s->blanked = 0;
-    memory_region_set_dirty(&s->mem_vram, 0, s->vram_size);
-}
-
-static void g364fb_reset(G364State *s)
-{
-    qemu_irq_lower(s->irq);
-
-    memset(s->color_palette, 0, sizeof(s->color_palette));
-    memset(s->cursor_palette, 0, sizeof(s->cursor_palette));
-    memset(s->cursor, 0, sizeof(s->cursor));
-    s->cursor_position = 0;
-    s->ctla = 0;
-    s->top_of_screen = 0;
-    s->width = s->height = 0;
-    memset(s->vram, 0, s->vram_size);
-    g364fb_invalidate_display(s);
-}
-
-static void g364fb_screen_dump(void *opaque, const char *filename, bool cswitch,
-                               Error **errp)
-{
-    G364State *s = opaque;
-    int ret, y, x;
-    uint8_t index;
-    uint8_t *data_buffer;
-    FILE *f;
-
-    qemu_flush_coalesced_mmio_buffer();
-
-    if (s->depth != 8) {
-        error_setg(errp, "g364: unknown guest depth %d", s->depth);
-        return;
-    }
-
-    f = fopen(filename, "wb");
-    if (!f) {
-        error_setg(errp, "failed to open file '%s': %s", filename,
-                   strerror(errno));
-        return;
-    }
-
-    if (s->ctla & CTLA_FORCE_BLANK) {
-        /* blank screen */
-        ret = fprintf(f, "P4\n%d %d\n", s->width, s->height);
-        if (ret < 0) {
-            goto write_err;
-        }
-        for (y = 0; y < s->height; y++)
-            for (x = 0; x < s->width; x++) {
-                ret = fputc(0, f);
-                if (ret == EOF) {
-                    goto write_err;
-                }
-            }
-    } else {
-        data_buffer = s->vram + s->top_of_screen;
-        ret = fprintf(f, "P6\n%d %d\n%d\n", s->width, s->height, 255);
-        if (ret < 0) {
-            goto write_err;
-        }
-        for (y = 0; y < s->height; y++)
-            for (x = 0; x < s->width; x++, data_buffer++) {
-                index = *data_buffer;
-                ret = fputc(s->color_palette[index][0], f);
-                if (ret == EOF) {
-                    goto write_err;
-                }
-                ret = fputc(s->color_palette[index][1], f);
-                if (ret == EOF) {
-                    goto write_err;
-                }
-                ret = fputc(s->color_palette[index][2], f);
-                if (ret == EOF) {
-                    goto write_err;
-                }
-        }
-    }
-
-out:
-    fclose(f);
-    return;
-
-write_err:
-    error_setg(errp, "failed to write to file '%s': %s", filename,
-               strerror(errno));
-    unlink(filename);
-    goto out;
-}
-
-/* called for accesses to io ports */
-static uint64_t g364fb_ctrl_read(void *opaque,
-                                 hwaddr addr,
-                                 unsigned int size)
-{
-    G364State *s = opaque;
-    uint32_t val;
-
-    if (addr >= REG_CURS_PAT && addr < REG_CURS_PAT + 0x1000) {
-        /* cursor pattern */
-        int idx = (addr - REG_CURS_PAT) >> 3;
-        val = s->cursor[idx];
-    } else if (addr >= REG_CURS_PAL && addr < REG_CURS_PAL + 0x18) {
-        /* cursor palette */
-        int idx = (addr - REG_CURS_PAL) >> 3;
-        val = ((uint32_t)s->cursor_palette[idx][0] << 16);
-        val |= ((uint32_t)s->cursor_palette[idx][1] << 8);
-        val |= ((uint32_t)s->cursor_palette[idx][2] << 0);
-    } else {
-        switch (addr) {
-            case REG_DISPLAY:
-                val = s->width / 4;
-                break;
-            case REG_VDISPLAY:
-                val = s->height * 2;
-                break;
-            case REG_CTLA:
-                val = s->ctla;
-                break;
-            default:
-            {
-                error_report("g364: invalid read at [" TARGET_FMT_plx "]",
-                             addr);
-                val = 0;
-                break;
-            }
-        }
-    }
-
-    trace_g364fb_read(addr, val);
-
-    return val;
-}
-
-static void g364fb_update_depth(G364State *s)
-{
-    static const int depths[8] = { 1, 2, 4, 8, 15, 16, 0 };
-    s->depth = depths[(s->ctla & 0x00700000) >> 20];
-}
-
-static void g364_invalidate_cursor_position(G364State *s)
-{
-    DisplaySurface *surface = qemu_console_surface(s->con);
-    int ymin, ymax, start, end;
-
-    /* invalidate only near the cursor */
-    ymin = s->cursor_position & 0xfff;
-    ymax = MIN(s->height, ymin + 64);
-    start = ymin * surface_stride(surface);
-    end = (ymax + 1) * surface_stride(surface);
-
-    memory_region_set_dirty(&s->mem_vram, start, end - start);
-}
-
-static void g364fb_ctrl_write(void *opaque,
-                              hwaddr addr,
-                              uint64_t val,
-                              unsigned int size)
-{
-    G364State *s = opaque;
-
-    trace_g364fb_write(addr, val);
-
-    if (addr >= REG_CLR_PAL && addr < REG_CLR_PAL + 0x800) {
-        /* color palette */
-        int idx = (addr - REG_CLR_PAL) >> 3;
-        s->color_palette[idx][0] = (val >> 16) & 0xff;
-        s->color_palette[idx][1] = (val >> 8) & 0xff;
-        s->color_palette[idx][2] = val & 0xff;
-        g364fb_invalidate_display(s);
-    } else if (addr >= REG_CURS_PAT && addr < REG_CURS_PAT + 0x1000) {
-        /* cursor pattern */
-        int idx = (addr - REG_CURS_PAT) >> 3;
-        s->cursor[idx] = val;
-        g364fb_invalidate_display(s);
-    } else if (addr >= REG_CURS_PAL && addr < REG_CURS_PAL + 0x18) {
-        /* cursor palette */
-        int idx = (addr - REG_CURS_PAL) >> 3;
-        s->cursor_palette[idx][0] = (val >> 16) & 0xff;
-        s->cursor_palette[idx][1] = (val >> 8) & 0xff;
-        s->cursor_palette[idx][2] = val & 0xff;
-        g364fb_invalidate_display(s);
-    } else {
-        switch (addr) {
-        case REG_BOOT: /* Boot timing */
-        case 0x00108: /* Line timing: half sync */
-        case 0x00110: /* Line timing: back porch */
-        case 0x00120: /* Line timing: short display */
-        case 0x00128: /* Frame timing: broad pulse */
-        case 0x00130: /* Frame timing: v sync */
-        case 0x00138: /* Frame timing: v preequalise */
-        case 0x00140: /* Frame timing: v postequalise */
-        case 0x00148: /* Frame timing: v blank */
-        case 0x00158: /* Line timing: line time */
-        case 0x00160: /* Frame store: line start */
-        case 0x00168: /* vram cycle: mem init */
-        case 0x00170: /* vram cycle: transfer delay */
-        case 0x00200: /* vram cycle: mask register */
-            /* ignore */
-            break;
-        case REG_TOP:
-            s->top_of_screen = val;
-            g364fb_invalidate_display(s);
-            break;
-        case REG_DISPLAY:
-            s->width = val * 4;
-            break;
-        case REG_VDISPLAY:
-            s->height = val / 2;
-            break;
-        case REG_CTLA:
-            s->ctla = val;
-            g364fb_update_depth(s);
-            g364fb_invalidate_display(s);
-            break;
-        case REG_CURS_POS:
-            g364_invalidate_cursor_position(s);
-            s->cursor_position = val;
-            g364_invalidate_cursor_position(s);
-            break;
-        case REG_RESET:
-            g364fb_reset(s);
-            break;
-        default:
-            error_report("g364: invalid write of 0x%" PRIx64
-                         " at [" TARGET_FMT_plx "]", val, addr);
-            break;
-        }
-    }
-    qemu_irq_lower(s->irq);
-}
-
-static const MemoryRegionOps g364fb_ctrl_ops = {
-    .read = g364fb_ctrl_read,
-    .write = g364fb_ctrl_write,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-    .impl.min_access_size = 4,
-    .impl.max_access_size = 4,
-};
-
-static int g364fb_post_load(void *opaque, int version_id)
-{
-    G364State *s = opaque;
-
-    /* force refresh */
-    g364fb_update_depth(s);
-    g364fb_invalidate_display(s);
-
-    return 0;
-}
-
-static const VMStateDescription vmstate_g364fb = {
-    .name = "g364fb",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .post_load = g364fb_post_load,
-    .fields = (VMStateField[]) {
-        VMSTATE_VBUFFER_UINT32(vram, G364State, 1, NULL, 0, vram_size),
-        VMSTATE_BUFFER_UNSAFE(color_palette, G364State, 0, 256 * 3),
-        VMSTATE_BUFFER_UNSAFE(cursor_palette, G364State, 0, 9),
-        VMSTATE_UINT16_ARRAY(cursor, G364State, 512),
-        VMSTATE_UINT32(cursor_position, G364State),
-        VMSTATE_UINT32(ctla, G364State),
-        VMSTATE_UINT32(top_of_screen, G364State),
-        VMSTATE_UINT32(width, G364State),
-        VMSTATE_UINT32(height, G364State),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void g364fb_init(DeviceState *dev, G364State *s)
-{
-    s->vram = g_malloc0(s->vram_size);
-
-    s->con = graphic_console_init(g364fb_update_display,
-                                  g364fb_invalidate_display,
-                                  g364fb_screen_dump, NULL, s);
-
-    memory_region_init_io(&s->mem_ctrl, &g364fb_ctrl_ops, s, "ctrl", 0x180000);
-    memory_region_init_ram_ptr(&s->mem_vram, "vram",
-                               s->vram_size, s->vram);
-    vmstate_register_ram(&s->mem_vram, dev);
-    memory_region_set_coalescing(&s->mem_vram);
-}
-
-typedef struct {
-    SysBusDevice busdev;
-    G364State g364;
-} G364SysBusState;
-
-static int g364fb_sysbus_init(SysBusDevice *dev)
-{
-    G364State *s = &FROM_SYSBUS(G364SysBusState, dev)->g364;
-
-    g364fb_init(&dev->qdev, s);
-    sysbus_init_irq(dev, &s->irq);
-    sysbus_init_mmio(dev, &s->mem_ctrl);
-    sysbus_init_mmio(dev, &s->mem_vram);
-
-    return 0;
-}
-
-static void g364fb_sysbus_reset(DeviceState *d)
-{
-    G364SysBusState *s = DO_UPCAST(G364SysBusState, busdev.qdev, d);
-    g364fb_reset(&s->g364);
-}
-
-static Property g364fb_sysbus_properties[] = {
-    DEFINE_PROP_HEX32("vram_size", G364SysBusState, g364.vram_size,
-    8 * 1024 * 1024),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void g364fb_sysbus_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = g364fb_sysbus_init;
-    dc->desc = "G364 framebuffer";
-    dc->reset = g364fb_sysbus_reset;
-    dc->vmsd = &vmstate_g364fb;
-    dc->props = g364fb_sysbus_properties;
-}
-
-static const 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_types(void)
-{
-    type_register_static(&g364fb_sysbus_info);
-}
-
-type_init(g364fb_register_types)
diff --git a/hw/gpio/Makefile.objs b/hw/gpio/Makefile.objs
new file mode 100644 (file)
index 0000000..2c8b51f
--- /dev/null
@@ -0,0 +1,6 @@
+common-obj-$(CONFIG_MAX7310) += max7310.o
+common-obj-$(CONFIG_PL061) += pl061.o
+common-obj-$(CONFIG_PUV3) += puv3_gpio.o
+common-obj-$(CONFIG_ZAURUS) += zaurus.o
+
+obj-$(CONFIG_OMAP) += omap_gpio.o
diff --git a/hw/gpio/max7310.c b/hw/gpio/max7310.c
new file mode 100644 (file)
index 0000000..59b2877
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+ * MAX7310 8-port GPIO expansion chip.
+ *
+ * Copyright (c) 2006 Openedhand Ltd.
+ * Written by Andrzej Zaborowski <balrog@zabor.org>
+ *
+ * This file is licensed under GNU GPL.
+ */
+
+#include "hw/i2c/i2c.h"
+
+typedef struct {
+    I2CSlave i2c;
+    int i2c_command_byte;
+    int len;
+
+    uint8_t level;
+    uint8_t direction;
+    uint8_t polarity;
+    uint8_t status;
+    uint8_t command;
+    qemu_irq handler[8];
+    qemu_irq *gpio_in;
+} MAX7310State;
+
+static void max7310_reset(DeviceState *dev)
+{
+    MAX7310State *s = FROM_I2C_SLAVE(MAX7310State, I2C_SLAVE(dev));
+    s->level &= s->direction;
+    s->direction = 0xff;
+    s->polarity = 0xf0;
+    s->status = 0x01;
+    s->command = 0x00;
+}
+
+static int max7310_rx(I2CSlave *i2c)
+{
+    MAX7310State *s = (MAX7310State *) i2c;
+
+    switch (s->command) {
+    case 0x00: /* Input port */
+        return s->level ^ s->polarity;
+        break;
+
+    case 0x01: /* Output port */
+        return s->level & ~s->direction;
+        break;
+
+    case 0x02: /* Polarity inversion */
+        return s->polarity;
+
+    case 0x03: /* Configuration */
+        return s->direction;
+
+    case 0x04: /* Timeout */
+        return s->status;
+        break;
+
+    case 0xff: /* Reserved */
+        return 0xff;
+
+    default:
+#ifdef VERBOSE
+        printf("%s: unknown register %02x\n", __FUNCTION__, s->command);
+#endif
+        break;
+    }
+    return 0xff;
+}
+
+static int max7310_tx(I2CSlave *i2c, uint8_t data)
+{
+    MAX7310State *s = (MAX7310State *) i2c;
+    uint8_t diff;
+    int line;
+
+    if (s->len ++ > 1) {
+#ifdef VERBOSE
+        printf("%s: message too long (%i bytes)\n", __FUNCTION__, s->len);
+#endif
+        return 1;
+    }
+
+    if (s->i2c_command_byte) {
+        s->command = data;
+        s->i2c_command_byte = 0;
+        return 0;
+    }
+
+    switch (s->command) {
+    case 0x01: /* Output port */
+        for (diff = (data ^ s->level) & ~s->direction; diff;
+                        diff &= ~(1 << line)) {
+            line = ffs(diff) - 1;
+            if (s->handler[line])
+                qemu_set_irq(s->handler[line], (data >> line) & 1);
+        }
+        s->level = (s->level & s->direction) | (data & ~s->direction);
+        break;
+
+    case 0x02: /* Polarity inversion */
+        s->polarity = data;
+        break;
+
+    case 0x03: /* Configuration */
+        s->level &= ~(s->direction ^ data);
+        s->direction = data;
+        break;
+
+    case 0x04: /* Timeout */
+        s->status = data;
+        break;
+
+    case 0x00: /* Input port - ignore writes */
+       break;
+    default:
+#ifdef VERBOSE
+        printf("%s: unknown register %02x\n", __FUNCTION__, s->command);
+#endif
+        return 1;
+    }
+
+    return 0;
+}
+
+static void max7310_event(I2CSlave *i2c, enum i2c_event event)
+{
+    MAX7310State *s = (MAX7310State *) i2c;
+    s->len = 0;
+
+    switch (event) {
+    case I2C_START_SEND:
+        s->i2c_command_byte = 1;
+        break;
+    case I2C_FINISH:
+#ifdef VERBOSE
+        if (s->len == 1)
+            printf("%s: message too short (%i bytes)\n", __FUNCTION__, s->len);
+#endif
+        break;
+    default:
+        break;
+    }
+}
+
+static const VMStateDescription vmstate_max7310 = {
+    .name = "max7310",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields      = (VMStateField []) {
+        VMSTATE_INT32(i2c_command_byte, MAX7310State),
+        VMSTATE_INT32(len, MAX7310State),
+        VMSTATE_UINT8(level, MAX7310State),
+        VMSTATE_UINT8(direction, MAX7310State),
+        VMSTATE_UINT8(polarity, MAX7310State),
+        VMSTATE_UINT8(status, MAX7310State),
+        VMSTATE_UINT8(command, MAX7310State),
+        VMSTATE_I2C_SLAVE(i2c, MAX7310State),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void max7310_gpio_set(void *opaque, int line, int level)
+{
+    MAX7310State *s = (MAX7310State *) opaque;
+    if (line >= ARRAY_SIZE(s->handler) || line  < 0)
+        hw_error("bad GPIO line");
+
+    if (level)
+        s->level |= s->direction & (1 << line);
+    else
+        s->level &= ~(s->direction & (1 << line));
+}
+
+/* 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(I2CSlave *i2c)
+{
+    MAX7310State *s = FROM_I2C_SLAVE(MAX7310State, i2c);
+
+    qdev_init_gpio_in(&i2c->qdev, max7310_gpio_set, 8);
+    qdev_init_gpio_out(&i2c->qdev, s->handler, 8);
+
+    return 0;
+}
+
+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 const TypeInfo max7310_info = {
+    .name          = "max7310",
+    .parent        = TYPE_I2C_SLAVE,
+    .instance_size = sizeof(MAX7310State),
+    .class_init    = max7310_class_init,
+};
+
+static void max7310_register_types(void)
+{
+    type_register_static(&max7310_info);
+}
+
+type_init(max7310_register_types)
diff --git a/hw/gpio/omap_gpio.c b/hw/gpio/omap_gpio.c
new file mode 100644 (file)
index 0000000..f5eeaea
--- /dev/null
@@ -0,0 +1,792 @@
+/*
+ * TI OMAP processors GPIO emulation.
+ *
+ * Copyright (C) 2006-2008 Andrzej Zaborowski  <balrog@zabor.org>
+ * Copyright (C) 2007-2009 Nokia Corporation
+ *
+ * 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 or
+ * (at your option) version 3 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
+ * 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 "hw/hw.h"
+#include "hw/arm/omap.h"
+#include "hw/sysbus.h"
+
+struct omap_gpio_s {
+    qemu_irq irq;
+    qemu_irq handler[16];
+
+    uint16_t inputs;
+    uint16_t outputs;
+    uint16_t dir;
+    uint16_t edge;
+    uint16_t mask;
+    uint16_t ints;
+    uint16_t pins;
+};
+
+struct omap_gpif_s {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    int mpu_model;
+    void *clk;
+    struct omap_gpio_s omap1;
+};
+
+/* General-Purpose I/O of OMAP1 */
+static void omap_gpio_set(void *opaque, int line, int level)
+{
+    struct omap_gpio_s *s = &((struct omap_gpif_s *) opaque)->omap1;
+    uint16_t prev = s->inputs;
+
+    if (level)
+        s->inputs |= 1 << line;
+    else
+        s->inputs &= ~(1 << line);
+
+    if (((s->edge & s->inputs & ~prev) | (~s->edge & ~s->inputs & prev)) &
+                    (1 << line) & s->dir & ~s->mask) {
+        s->ints |= 1 << line;
+        qemu_irq_raise(s->irq);
+    }
+}
+
+static uint64_t omap_gpio_read(void *opaque, hwaddr addr,
+                               unsigned size)
+{
+    struct omap_gpio_s *s = (struct omap_gpio_s *) opaque;
+    int offset = addr & OMAP_MPUI_REG_MASK;
+
+    if (size != 2) {
+        return omap_badwidth_read16(opaque, addr);
+    }
+
+    switch (offset) {
+    case 0x00: /* DATA_INPUT */
+        return s->inputs & s->pins;
+
+    case 0x04: /* DATA_OUTPUT */
+        return s->outputs;
+
+    case 0x08: /* DIRECTION_CONTROL */
+        return s->dir;
+
+    case 0x0c: /* INTERRUPT_CONTROL */
+        return s->edge;
+
+    case 0x10: /* INTERRUPT_MASK */
+        return s->mask;
+
+    case 0x14: /* INTERRUPT_STATUS */
+        return s->ints;
+
+    case 0x18: /* PIN_CONTROL (not in OMAP310) */
+        OMAP_BAD_REG(addr);
+        return s->pins;
+    }
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_gpio_write(void *opaque, hwaddr addr,
+                            uint64_t value, unsigned size)
+{
+    struct omap_gpio_s *s = (struct omap_gpio_s *) opaque;
+    int offset = addr & OMAP_MPUI_REG_MASK;
+    uint16_t diff;
+    int ln;
+
+    if (size != 2) {
+        return omap_badwidth_write16(opaque, addr, value);
+    }
+
+    switch (offset) {
+    case 0x00: /* DATA_INPUT */
+        OMAP_RO_REG(addr);
+        return;
+
+    case 0x04: /* DATA_OUTPUT */
+        diff = (s->outputs ^ value) & ~s->dir;
+        s->outputs = value;
+        while ((ln = ffs(diff))) {
+            ln --;
+            if (s->handler[ln])
+                qemu_set_irq(s->handler[ln], (value >> ln) & 1);
+            diff &= ~(1 << ln);
+        }
+        break;
+
+    case 0x08: /* DIRECTION_CONTROL */
+        diff = s->outputs & (s->dir ^ value);
+        s->dir = value;
+
+        value = s->outputs & ~s->dir;
+        while ((ln = ffs(diff))) {
+            ln --;
+            if (s->handler[ln])
+                qemu_set_irq(s->handler[ln], (value >> ln) & 1);
+            diff &= ~(1 << ln);
+        }
+        break;
+
+    case 0x0c: /* INTERRUPT_CONTROL */
+        s->edge = value;
+        break;
+
+    case 0x10: /* INTERRUPT_MASK */
+        s->mask = value;
+        break;
+
+    case 0x14: /* INTERRUPT_STATUS */
+        s->ints &= ~value;
+        if (!s->ints)
+            qemu_irq_lower(s->irq);
+        break;
+
+    case 0x18: /* PIN_CONTROL (not in OMAP310 TRM) */
+        OMAP_BAD_REG(addr);
+        s->pins = value;
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+        return;
+    }
+}
+
+/* *Some* sources say the memory region is 32-bit.  */
+static const MemoryRegionOps omap_gpio_ops = {
+    .read = omap_gpio_read,
+    .write = omap_gpio_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void omap_gpio_reset(struct omap_gpio_s *s)
+{
+    s->inputs = 0;
+    s->outputs = ~0;
+    s->dir = ~0;
+    s->edge = ~0;
+    s->mask = ~0;
+    s->ints = 0;
+    s->pins = ~0;
+}
+
+struct omap2_gpio_s {
+    qemu_irq irq[2];
+    qemu_irq wkup;
+    qemu_irq *handler;
+    MemoryRegion iomem;
+
+    uint8_t revision;
+    uint8_t config[2];
+    uint32_t inputs;
+    uint32_t outputs;
+    uint32_t dir;
+    uint32_t level[2];
+    uint32_t edge[2];
+    uint32_t mask[2];
+    uint32_t wumask;
+    uint32_t ints[2];
+    uint32_t debounce;
+    uint8_t delay;
+};
+
+struct omap2_gpif_s {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    int mpu_model;
+    void *iclk;
+    void *fclk[6];
+    int modulecount;
+    struct omap2_gpio_s *modules;
+    qemu_irq *handler;
+    int autoidle;
+    int gpo;
+};
+
+/* General-Purpose Interface of OMAP2/3 */
+static inline void omap2_gpio_module_int_update(struct omap2_gpio_s *s,
+                                                int line)
+{
+    qemu_set_irq(s->irq[line], s->ints[line] & s->mask[line]);
+}
+
+static void omap2_gpio_module_wake(struct omap2_gpio_s *s, int line)
+{
+    if (!(s->config[0] & (1 << 2)))                    /* ENAWAKEUP */
+        return;
+    if (!(s->config[0] & (3 << 3)))                    /* Force Idle */
+        return;
+    if (!(s->wumask & (1 << line)))
+        return;
+
+    qemu_irq_raise(s->wkup);
+}
+
+static inline void omap2_gpio_module_out_update(struct omap2_gpio_s *s,
+                uint32_t diff)
+{
+    int ln;
+
+    s->outputs ^= diff;
+    diff &= ~s->dir;
+    while ((ln = ffs(diff))) {
+        ln --;
+        qemu_set_irq(s->handler[ln], (s->outputs >> ln) & 1);
+        diff &= ~(1 << ln);
+    }
+}
+
+static void omap2_gpio_module_level_update(struct omap2_gpio_s *s, int line)
+{
+    s->ints[line] |= s->dir &
+            ((s->inputs & s->level[1]) | (~s->inputs & s->level[0]));
+    omap2_gpio_module_int_update(s, line);
+}
+
+static inline void omap2_gpio_module_int(struct omap2_gpio_s *s, int line)
+{
+    s->ints[0] |= 1 << line;
+    omap2_gpio_module_int_update(s, 0);
+    s->ints[1] |= 1 << line;
+    omap2_gpio_module_int_update(s, 1);
+    omap2_gpio_module_wake(s, line);
+}
+
+static void omap2_gpio_set(void *opaque, int line, int level)
+{
+    struct omap2_gpif_s *p = opaque;
+    struct omap2_gpio_s *s = &p->modules[line >> 5];
+
+    line &= 31;
+    if (level) {
+        if (s->dir & (1 << line) & ((~s->inputs & s->edge[0]) | s->level[1]))
+            omap2_gpio_module_int(s, line);
+        s->inputs |= 1 << line;
+    } else {
+        if (s->dir & (1 << line) & ((s->inputs & s->edge[1]) | s->level[0]))
+            omap2_gpio_module_int(s, line);
+        s->inputs &= ~(1 << line);
+    }
+}
+
+static void omap2_gpio_module_reset(struct omap2_gpio_s *s)
+{
+    s->config[0] = 0;
+    s->config[1] = 2;
+    s->ints[0] = 0;
+    s->ints[1] = 0;
+    s->mask[0] = 0;
+    s->mask[1] = 0;
+    s->wumask = 0;
+    s->dir = ~0;
+    s->level[0] = 0;
+    s->level[1] = 0;
+    s->edge[0] = 0;
+    s->edge[1] = 0;
+    s->debounce = 0;
+    s->delay = 0;
+}
+
+static uint32_t omap2_gpio_module_read(void *opaque, hwaddr addr)
+{
+    struct omap2_gpio_s *s = (struct omap2_gpio_s *) opaque;
+
+    switch (addr) {
+    case 0x00: /* GPIO_REVISION */
+        return s->revision;
+
+    case 0x10: /* GPIO_SYSCONFIG */
+        return s->config[0];
+
+    case 0x14: /* GPIO_SYSSTATUS */
+        return 0x01;
+
+    case 0x18: /* GPIO_IRQSTATUS1 */
+        return s->ints[0];
+
+    case 0x1c: /* GPIO_IRQENABLE1 */
+    case 0x60: /* GPIO_CLEARIRQENABLE1 */
+    case 0x64: /* GPIO_SETIRQENABLE1 */
+        return s->mask[0];
+
+    case 0x20: /* GPIO_WAKEUPENABLE */
+    case 0x80: /* GPIO_CLEARWKUENA */
+    case 0x84: /* GPIO_SETWKUENA */
+        return s->wumask;
+
+    case 0x28: /* GPIO_IRQSTATUS2 */
+        return s->ints[1];
+
+    case 0x2c: /* GPIO_IRQENABLE2 */
+    case 0x70: /* GPIO_CLEARIRQENABLE2 */
+    case 0x74: /* GPIO_SETIREQNEABLE2 */
+        return s->mask[1];
+
+    case 0x30: /* GPIO_CTRL */
+        return s->config[1];
+
+    case 0x34: /* GPIO_OE */
+        return s->dir;
+
+    case 0x38: /* GPIO_DATAIN */
+        return s->inputs;
+
+    case 0x3c: /* GPIO_DATAOUT */
+    case 0x90: /* GPIO_CLEARDATAOUT */
+    case 0x94: /* GPIO_SETDATAOUT */
+        return s->outputs;
+
+    case 0x40: /* GPIO_LEVELDETECT0 */
+        return s->level[0];
+
+    case 0x44: /* GPIO_LEVELDETECT1 */
+        return s->level[1];
+
+    case 0x48: /* GPIO_RISINGDETECT */
+        return s->edge[0];
+
+    case 0x4c: /* GPIO_FALLINGDETECT */
+        return s->edge[1];
+
+    case 0x50: /* GPIO_DEBOUNCENABLE */
+        return s->debounce;
+
+    case 0x54: /* GPIO_DEBOUNCINGTIME */
+        return s->delay;
+    }
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap2_gpio_module_write(void *opaque, hwaddr addr,
+                uint32_t value)
+{
+    struct omap2_gpio_s *s = (struct omap2_gpio_s *) opaque;
+    uint32_t diff;
+    int ln;
+
+    switch (addr) {
+    case 0x00: /* GPIO_REVISION */
+    case 0x14: /* GPIO_SYSSTATUS */
+    case 0x38: /* GPIO_DATAIN */
+        OMAP_RO_REG(addr);
+        break;
+
+    case 0x10: /* GPIO_SYSCONFIG */
+        if (((value >> 3) & 3) == 3)
+            fprintf(stderr, "%s: bad IDLEMODE value\n", __FUNCTION__);
+        if (value & 2)
+            omap2_gpio_module_reset(s);
+        s->config[0] = value & 0x1d;
+        break;
+
+    case 0x18: /* GPIO_IRQSTATUS1 */
+        if (s->ints[0] & value) {
+            s->ints[0] &= ~value;
+            omap2_gpio_module_level_update(s, 0);
+        }
+        break;
+
+    case 0x1c: /* GPIO_IRQENABLE1 */
+        s->mask[0] = value;
+        omap2_gpio_module_int_update(s, 0);
+        break;
+
+    case 0x20: /* GPIO_WAKEUPENABLE */
+        s->wumask = value;
+        break;
+
+    case 0x28: /* GPIO_IRQSTATUS2 */
+        if (s->ints[1] & value) {
+            s->ints[1] &= ~value;
+            omap2_gpio_module_level_update(s, 1);
+        }
+        break;
+
+    case 0x2c: /* GPIO_IRQENABLE2 */
+        s->mask[1] = value;
+        omap2_gpio_module_int_update(s, 1);
+        break;
+
+    case 0x30: /* GPIO_CTRL */
+        s->config[1] = value & 7;
+        break;
+
+    case 0x34: /* GPIO_OE */
+        diff = s->outputs & (s->dir ^ value);
+        s->dir = value;
+
+        value = s->outputs & ~s->dir;
+        while ((ln = ffs(diff))) {
+            diff &= ~(1 <<-- ln);
+            qemu_set_irq(s->handler[ln], (value >> ln) & 1);
+        }
+
+        omap2_gpio_module_level_update(s, 0);
+        omap2_gpio_module_level_update(s, 1);
+        break;
+
+    case 0x3c: /* GPIO_DATAOUT */
+        omap2_gpio_module_out_update(s, s->outputs ^ value);
+        break;
+
+    case 0x40: /* GPIO_LEVELDETECT0 */
+        s->level[0] = value;
+        omap2_gpio_module_level_update(s, 0);
+        omap2_gpio_module_level_update(s, 1);
+        break;
+
+    case 0x44: /* GPIO_LEVELDETECT1 */
+        s->level[1] = value;
+        omap2_gpio_module_level_update(s, 0);
+        omap2_gpio_module_level_update(s, 1);
+        break;
+
+    case 0x48: /* GPIO_RISINGDETECT */
+        s->edge[0] = value;
+        break;
+
+    case 0x4c: /* GPIO_FALLINGDETECT */
+        s->edge[1] = value;
+        break;
+
+    case 0x50: /* GPIO_DEBOUNCENABLE */
+        s->debounce = value;
+        break;
+
+    case 0x54: /* GPIO_DEBOUNCINGTIME */
+        s->delay = value;
+        break;
+
+    case 0x60: /* GPIO_CLEARIRQENABLE1 */
+        s->mask[0] &= ~value;
+        omap2_gpio_module_int_update(s, 0);
+        break;
+
+    case 0x64: /* GPIO_SETIRQENABLE1 */
+        s->mask[0] |= value;
+        omap2_gpio_module_int_update(s, 0);
+        break;
+
+    case 0x70: /* GPIO_CLEARIRQENABLE2 */
+        s->mask[1] &= ~value;
+        omap2_gpio_module_int_update(s, 1);
+        break;
+
+    case 0x74: /* GPIO_SETIREQNEABLE2 */
+        s->mask[1] |= value;
+        omap2_gpio_module_int_update(s, 1);
+        break;
+
+    case 0x80: /* GPIO_CLEARWKUENA */
+        s->wumask &= ~value;
+        break;
+
+    case 0x84: /* GPIO_SETWKUENA */
+        s->wumask |= value;
+        break;
+
+    case 0x90: /* GPIO_CLEARDATAOUT */
+        omap2_gpio_module_out_update(s, s->outputs & value);
+        break;
+
+    case 0x94: /* GPIO_SETDATAOUT */
+        omap2_gpio_module_out_update(s, ~s->outputs & value);
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+        return;
+    }
+}
+
+static uint32_t omap2_gpio_module_readp(void *opaque, hwaddr addr)
+{
+    return omap2_gpio_module_read(opaque, addr & ~3) >> ((addr & 3) << 3);
+}
+
+static void omap2_gpio_module_writep(void *opaque, hwaddr addr,
+                uint32_t value)
+{
+    uint32_t cur = 0;
+    uint32_t mask = 0xffff;
+
+    switch (addr & ~3) {
+    case 0x00: /* GPIO_REVISION */
+    case 0x14: /* GPIO_SYSSTATUS */
+    case 0x38: /* GPIO_DATAIN */
+        OMAP_RO_REG(addr);
+        break;
+
+    case 0x10: /* GPIO_SYSCONFIG */
+    case 0x1c: /* GPIO_IRQENABLE1 */
+    case 0x20: /* GPIO_WAKEUPENABLE */
+    case 0x2c: /* GPIO_IRQENABLE2 */
+    case 0x30: /* GPIO_CTRL */
+    case 0x34: /* GPIO_OE */
+    case 0x3c: /* GPIO_DATAOUT */
+    case 0x40: /* GPIO_LEVELDETECT0 */
+    case 0x44: /* GPIO_LEVELDETECT1 */
+    case 0x48: /* GPIO_RISINGDETECT */
+    case 0x4c: /* GPIO_FALLINGDETECT */
+    case 0x50: /* GPIO_DEBOUNCENABLE */
+    case 0x54: /* GPIO_DEBOUNCINGTIME */
+        cur = omap2_gpio_module_read(opaque, addr & ~3) &
+                ~(mask << ((addr & 3) << 3));
+
+        /* Fall through.  */
+    case 0x18: /* GPIO_IRQSTATUS1 */
+    case 0x28: /* GPIO_IRQSTATUS2 */
+    case 0x60: /* GPIO_CLEARIRQENABLE1 */
+    case 0x64: /* GPIO_SETIRQENABLE1 */
+    case 0x70: /* GPIO_CLEARIRQENABLE2 */
+    case 0x74: /* GPIO_SETIREQNEABLE2 */
+    case 0x80: /* GPIO_CLEARWKUENA */
+    case 0x84: /* GPIO_SETWKUENA */
+    case 0x90: /* GPIO_CLEARDATAOUT */
+    case 0x94: /* GPIO_SETDATAOUT */
+        value <<= (addr & 3) << 3;
+        omap2_gpio_module_write(opaque, addr, cur | value);
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+        return;
+    }
+}
+
+static const MemoryRegionOps omap2_gpio_module_ops = {
+    .old_mmio = {
+        .read = {
+            omap2_gpio_module_readp,
+            omap2_gpio_module_readp,
+            omap2_gpio_module_read,
+        },
+        .write = {
+            omap2_gpio_module_writep,
+            omap2_gpio_module_writep,
+            omap2_gpio_module_write,
+        },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void omap_gpif_reset(DeviceState *dev)
+{
+    struct omap_gpif_s *s = FROM_SYSBUS(struct omap_gpif_s,
+                    SYS_BUS_DEVICE(dev));
+    omap_gpio_reset(&s->omap1);
+}
+
+static void omap2_gpif_reset(DeviceState *dev)
+{
+    int i;
+    struct omap2_gpif_s *s = FROM_SYSBUS(struct omap2_gpif_s,
+                    SYS_BUS_DEVICE(dev));
+    for (i = 0; i < s->modulecount; i++) {
+        omap2_gpio_module_reset(&s->modules[i]);
+    }
+    s->autoidle = 0;
+    s->gpo = 0;
+}
+
+static uint64_t omap2_gpif_top_read(void *opaque, hwaddr addr,
+                                    unsigned size)
+{
+    struct omap2_gpif_s *s = (struct omap2_gpif_s *) opaque;
+
+    switch (addr) {
+    case 0x00: /* IPGENERICOCPSPL_REVISION */
+        return 0x18;
+
+    case 0x10: /* IPGENERICOCPSPL_SYSCONFIG */
+        return s->autoidle;
+
+    case 0x14: /* IPGENERICOCPSPL_SYSSTATUS */
+        return 0x01;
+
+    case 0x18: /* IPGENERICOCPSPL_IRQSTATUS */
+        return 0x00;
+
+    case 0x40: /* IPGENERICOCPSPL_GPO */
+        return s->gpo;
+
+    case 0x50: /* IPGENERICOCPSPL_GPI */
+        return 0x00;
+    }
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap2_gpif_top_write(void *opaque, hwaddr addr,
+                                 uint64_t value, unsigned size)
+{
+    struct omap2_gpif_s *s = (struct omap2_gpif_s *) opaque;
+
+    switch (addr) {
+    case 0x00: /* IPGENERICOCPSPL_REVISION */
+    case 0x14: /* IPGENERICOCPSPL_SYSSTATUS */
+    case 0x18: /* IPGENERICOCPSPL_IRQSTATUS */
+    case 0x50: /* IPGENERICOCPSPL_GPI */
+        OMAP_RO_REG(addr);
+        break;
+
+    case 0x10: /* IPGENERICOCPSPL_SYSCONFIG */
+        if (value & (1 << 1))                                  /* SOFTRESET */
+            omap2_gpif_reset(&s->busdev.qdev);
+        s->autoidle = value & 1;
+        break;
+
+    case 0x40: /* IPGENERICOCPSPL_GPO */
+        s->gpo = value & 1;
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+        return;
+    }
+}
+
+static const MemoryRegionOps omap2_gpif_top_ops = {
+    .read = omap2_gpif_top_read,
+    .write = omap2_gpif_top_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int omap_gpio_init(SysBusDevice *dev)
+{
+    struct omap_gpif_s *s = FROM_SYSBUS(struct omap_gpif_s, dev);
+    if (!s->clk) {
+        hw_error("omap-gpio: clk not connected\n");
+    }
+    qdev_init_gpio_in(&dev->qdev, omap_gpio_set, 16);
+    qdev_init_gpio_out(&dev->qdev, s->omap1.handler, 16);
+    sysbus_init_irq(dev, &s->omap1.irq);
+    memory_region_init_io(&s->iomem, &omap_gpio_ops, &s->omap1,
+                          "omap.gpio", 0x1000);
+    sysbus_init_mmio(dev, &s->iomem);
+    return 0;
+}
+
+static int omap2_gpio_init(SysBusDevice *dev)
+{
+    int i;
+    struct omap2_gpif_s *s = FROM_SYSBUS(struct omap2_gpif_s, dev);
+    if (!s->iclk) {
+        hw_error("omap2-gpio: iclk not connected\n");
+    }
+    if (s->mpu_model < omap3430) {
+        s->modulecount = (s->mpu_model < omap2430) ? 4 : 5;
+        memory_region_init_io(&s->iomem, &omap2_gpif_top_ops, s,
+                              "omap2.gpio", 0x1000);
+        sysbus_init_mmio(dev, &s->iomem);
+    } else {
+        s->modulecount = 6;
+    }
+    s->modules = g_malloc0(s->modulecount * sizeof(struct omap2_gpio_s));
+    s->handler = g_malloc0(s->modulecount * 32 * sizeof(qemu_irq));
+    qdev_init_gpio_in(&dev->qdev, omap2_gpio_set, s->modulecount * 32);
+    qdev_init_gpio_out(&dev->qdev, s->handler, s->modulecount * 32);
+    for (i = 0; i < s->modulecount; i++) {
+        struct omap2_gpio_s *m = &s->modules[i];
+        if (!s->fclk[i]) {
+            hw_error("omap2-gpio: fclk%d not connected\n", i);
+        }
+        m->revision = (s->mpu_model < omap3430) ? 0x18 : 0x25;
+        m->handler = &s->handler[i * 32];
+        sysbus_init_irq(dev, &m->irq[0]); /* mpu irq */
+        sysbus_init_irq(dev, &m->irq[1]); /* dsp irq */
+        sysbus_init_irq(dev, &m->wkup);
+        memory_region_init_io(&m->iomem, &omap2_gpio_module_ops, m,
+                              "omap.gpio-module", 0x1000);
+        sysbus_init_mmio(dev, &m->iomem);
+    }
+    return 0;
+}
+
+/* Using qdev pointer properties for the clocks is not ideal.
+ * qdev should support a generic means of defining a 'port' with
+ * an arbitrary interface for connecting two devices. Then we
+ * could reframe the omap clock API in terms of clock ports,
+ * and get some type safety. For now the best qdev provides is
+ * passing an arbitrary pointer.
+ * (It's not possible to pass in the string which is the clock
+ * name, because this device does not have the necessary information
+ * (ie the struct omap_mpu_state_s*) to do the clockname to pointer
+ * translation.)
+ */
+
+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 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 const TypeInfo omap_gpio_info = {
+    .name          = "omap-gpio",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(struct omap_gpif_s),
+    .class_init    = omap_gpio_class_init,
+};
+
+static Property omap2_gpio_properties[] = {
+    DEFINE_PROP_INT32("mpu_model", struct omap2_gpif_s, mpu_model, 0),
+    DEFINE_PROP_PTR("iclk", struct omap2_gpif_s, iclk),
+    DEFINE_PROP_PTR("fclk0", struct omap2_gpif_s, fclk[0]),
+    DEFINE_PROP_PTR("fclk1", struct omap2_gpif_s, fclk[1]),
+    DEFINE_PROP_PTR("fclk2", struct omap2_gpif_s, fclk[2]),
+    DEFINE_PROP_PTR("fclk3", struct omap2_gpif_s, fclk[3]),
+    DEFINE_PROP_PTR("fclk4", struct omap2_gpif_s, fclk[4]),
+    DEFINE_PROP_PTR("fclk5", struct omap2_gpif_s, fclk[5]),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void omap2_gpio_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = omap2_gpio_init;
+    dc->reset = omap2_gpif_reset;
+    dc->props = omap2_gpio_properties;
+}
+
+static const 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_types(void)
+{
+    type_register_static(&omap_gpio_info);
+    type_register_static(&omap2_gpio_info);
+}
+
+type_init(omap_gpio_register_types)
diff --git a/hw/gpio/pl061.c b/hw/gpio/pl061.c
new file mode 100644 (file)
index 0000000..74bc109
--- /dev/null
@@ -0,0 +1,336 @@
+/*
+ * Arm PrimeCell PL061 General Purpose IO with additional
+ * Luminary Micro Stellaris bits.
+ *
+ * Copyright (c) 2007 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the GPL.
+ */
+
+#include "hw/sysbus.h"
+
+//#define DEBUG_PL061 1
+
+#ifdef DEBUG_PL061
+#define DPRINTF(fmt, ...) \
+do { printf("pl061: " fmt , ## __VA_ARGS__); } while (0)
+#define BADF(fmt, ...) \
+do { fprintf(stderr, "pl061: error: " fmt , ## __VA_ARGS__); exit(1);} while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while(0)
+#define BADF(fmt, ...) \
+do { fprintf(stderr, "pl061: error: " fmt , ## __VA_ARGS__);} while (0)
+#endif
+
+static const uint8_t pl061_id[12] =
+  { 0x00, 0x00, 0x00, 0x00, 0x61, 0x10, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
+static const uint8_t pl061_id_luminary[12] =
+  { 0x00, 0x00, 0x00, 0x00, 0x61, 0x00, 0x18, 0x01, 0x0d, 0xf0, 0x05, 0xb1 };
+
+typedef struct {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    uint32_t locked;
+    uint32_t data;
+    uint32_t old_data;
+    uint32_t dir;
+    uint32_t isense;
+    uint32_t ibe;
+    uint32_t iev;
+    uint32_t im;
+    uint32_t istate;
+    uint32_t afsel;
+    uint32_t dr2r;
+    uint32_t dr4r;
+    uint32_t dr8r;
+    uint32_t odr;
+    uint32_t pur;
+    uint32_t pdr;
+    uint32_t slr;
+    uint32_t den;
+    uint32_t cr;
+    uint32_t float_high;
+    uint32_t amsel;
+    qemu_irq irq;
+    qemu_irq out[8];
+    const unsigned char *id;
+} pl061_state;
+
+static const VMStateDescription vmstate_pl061 = {
+    .name = "pl061",
+    .version_id = 2,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(locked, pl061_state),
+        VMSTATE_UINT32(data, pl061_state),
+        VMSTATE_UINT32(old_data, pl061_state),
+        VMSTATE_UINT32(dir, pl061_state),
+        VMSTATE_UINT32(isense, pl061_state),
+        VMSTATE_UINT32(ibe, pl061_state),
+        VMSTATE_UINT32(iev, pl061_state),
+        VMSTATE_UINT32(im, pl061_state),
+        VMSTATE_UINT32(istate, pl061_state),
+        VMSTATE_UINT32(afsel, pl061_state),
+        VMSTATE_UINT32(dr2r, pl061_state),
+        VMSTATE_UINT32(dr4r, pl061_state),
+        VMSTATE_UINT32(dr8r, pl061_state),
+        VMSTATE_UINT32(odr, pl061_state),
+        VMSTATE_UINT32(pur, pl061_state),
+        VMSTATE_UINT32(pdr, pl061_state),
+        VMSTATE_UINT32(slr, pl061_state),
+        VMSTATE_UINT32(den, pl061_state),
+        VMSTATE_UINT32(cr, pl061_state),
+        VMSTATE_UINT32(float_high, pl061_state),
+        VMSTATE_UINT32_V(amsel, pl061_state, 2),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void pl061_update(pl061_state *s)
+{
+    uint8_t changed;
+    uint8_t mask;
+    uint8_t out;
+    int i;
+
+    /* Outputs float high.  */
+    /* FIXME: This is board dependent.  */
+    out = (s->data & s->dir) | ~s->dir;
+    changed = s->old_data ^ out;
+    if (!changed)
+        return;
+
+    s->old_data = out;
+    for (i = 0; i < 8; i++) {
+        mask = 1 << i;
+        if (changed & mask) {
+            DPRINTF("Set output %d = %d\n", i, (out & mask) != 0);
+            qemu_set_irq(s->out[i], (out & mask) != 0);
+        }
+    }
+
+    /* FIXME: Implement input interrupts.  */
+}
+
+static uint64_t pl061_read(void *opaque, hwaddr offset,
+                           unsigned size)
+{
+    pl061_state *s = (pl061_state *)opaque;
+
+    if (offset >= 0xfd0 && offset < 0x1000) {
+        return s->id[(offset - 0xfd0) >> 2];
+    }
+    if (offset < 0x400) {
+        return s->data & (offset >> 2);
+    }
+    switch (offset) {
+    case 0x400: /* Direction */
+        return s->dir;
+    case 0x404: /* Interrupt sense */
+        return s->isense;
+    case 0x408: /* Interrupt both edges */
+        return s->ibe;
+    case 0x40c: /* Interrupt event */
+        return s->iev;
+    case 0x410: /* Interrupt mask */
+        return s->im;
+    case 0x414: /* Raw interrupt status */
+        return s->istate;
+    case 0x418: /* Masked interrupt status */
+        return s->istate | s->im;
+    case 0x420: /* Alternate function select */
+        return s->afsel;
+    case 0x500: /* 2mA drive */
+        return s->dr2r;
+    case 0x504: /* 4mA drive */
+        return s->dr4r;
+    case 0x508: /* 8mA drive */
+        return s->dr8r;
+    case 0x50c: /* Open drain */
+        return s->odr;
+    case 0x510: /* Pull-up */
+        return s->pur;
+    case 0x514: /* Pull-down */
+        return s->pdr;
+    case 0x518: /* Slew rate control */
+        return s->slr;
+    case 0x51c: /* Digital enable */
+        return s->den;
+    case 0x520: /* Lock */
+        return s->locked;
+    case 0x524: /* Commit */
+        return s->cr;
+    case 0x528: /* Analog mode select */
+        return s->amsel;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "pl061_read: Bad offset %x\n", (int)offset);
+        return 0;
+    }
+}
+
+static void pl061_write(void *opaque, hwaddr offset,
+                        uint64_t value, unsigned size)
+{
+    pl061_state *s = (pl061_state *)opaque;
+    uint8_t mask;
+
+    if (offset < 0x400) {
+        mask = (offset >> 2) & s->dir;
+        s->data = (s->data & ~mask) | (value & mask);
+        pl061_update(s);
+        return;
+    }
+    switch (offset) {
+    case 0x400: /* Direction */
+        s->dir = value & 0xff;
+        break;
+    case 0x404: /* Interrupt sense */
+        s->isense = value & 0xff;
+        break;
+    case 0x408: /* Interrupt both edges */
+        s->ibe = value & 0xff;
+        break;
+    case 0x40c: /* Interrupt event */
+        s->iev = value & 0xff;
+        break;
+    case 0x410: /* Interrupt mask */
+        s->im = value & 0xff;
+        break;
+    case 0x41c: /* Interrupt clear */
+        s->istate &= ~value;
+        break;
+    case 0x420: /* Alternate function select */
+        mask = s->cr;
+        s->afsel = (s->afsel & ~mask) | (value & mask);
+        break;
+    case 0x500: /* 2mA drive */
+        s->dr2r = value & 0xff;
+        break;
+    case 0x504: /* 4mA drive */
+        s->dr4r = value & 0xff;
+        break;
+    case 0x508: /* 8mA drive */
+        s->dr8r = value & 0xff;
+        break;
+    case 0x50c: /* Open drain */
+        s->odr = value & 0xff;
+        break;
+    case 0x510: /* Pull-up */
+        s->pur = value & 0xff;
+        break;
+    case 0x514: /* Pull-down */
+        s->pdr = value & 0xff;
+        break;
+    case 0x518: /* Slew rate control */
+        s->slr = value & 0xff;
+        break;
+    case 0x51c: /* Digital enable */
+        s->den = value & 0xff;
+        break;
+    case 0x520: /* Lock */
+        s->locked = (value != 0xacce551);
+        break;
+    case 0x524: /* Commit */
+        if (!s->locked)
+            s->cr = value & 0xff;
+        break;
+    case 0x528:
+        s->amsel = value & 0xff;
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "pl061_write: Bad offset %x\n", (int)offset);
+    }
+    pl061_update(s);
+}
+
+static void pl061_reset(pl061_state *s)
+{
+  s->locked = 1;
+  s->cr = 0xff;
+}
+
+static void pl061_set_irq(void * opaque, int irq, int level)
+{
+    pl061_state *s = (pl061_state *)opaque;
+    uint8_t mask;
+
+    mask = 1 << irq;
+    if ((s->dir & mask) == 0) {
+        s->data &= ~mask;
+        if (level)
+            s->data |= mask;
+        pl061_update(s);
+    }
+}
+
+static const MemoryRegionOps pl061_ops = {
+    .read = pl061_read,
+    .write = pl061_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int pl061_init(SysBusDevice *dev, const unsigned char *id)
+{
+    pl061_state *s = FROM_SYSBUS(pl061_state, dev);
+    s->id = id;
+    memory_region_init_io(&s->iomem, &pl061_ops, s, "pl061", 0x1000);
+    sysbus_init_mmio(dev, &s->iomem);
+    sysbus_init_irq(dev, &s->irq);
+    qdev_init_gpio_in(&dev->qdev, pl061_set_irq, 8);
+    qdev_init_gpio_out(&dev->qdev, s->out, 8);
+    pl061_reset(s);
+    return 0;
+}
+
+static int pl061_init_luminary(SysBusDevice *dev)
+{
+    return pl061_init(dev, pl061_id_luminary);
+}
+
+static int pl061_init_arm(SysBusDevice *dev)
+{
+    return pl061_init(dev, pl061_id);
+}
+
+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 const 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 const 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_types(void)
+{
+    type_register_static(&pl061_info);
+    type_register_static(&pl061_luminary_info);
+}
+
+type_init(pl061_register_types)
diff --git a/hw/gpio/puv3_gpio.c b/hw/gpio/puv3_gpio.c
new file mode 100644 (file)
index 0000000..5bab97e
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * GPIO device simulation in PKUnity SoC
+ *
+ * Copyright (C) 2010-2012 Guan Xuetao
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation, or any later version.
+ * See the COPYING file in the top-level directory.
+ */
+#include "hw/hw.h"
+#include "hw/sysbus.h"
+
+#undef DEBUG_PUV3
+#include "hw/unicore32/puv3.h"
+
+typedef struct {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    qemu_irq irq[9];
+
+    uint32_t reg_GPLR;
+    uint32_t reg_GPDR;
+    uint32_t reg_GPIR;
+} PUV3GPIOState;
+
+static uint64_t puv3_gpio_read(void *opaque, hwaddr offset,
+        unsigned size)
+{
+    PUV3GPIOState *s = opaque;
+    uint32_t ret = 0;
+
+    switch (offset) {
+    case 0x00:
+        ret = s->reg_GPLR;
+        break;
+    case 0x04:
+        ret = s->reg_GPDR;
+        break;
+    case 0x20:
+        ret = s->reg_GPIR;
+        break;
+    default:
+        DPRINTF("Bad offset 0x%x\n", offset);
+    }
+    DPRINTF("offset 0x%x, value 0x%x\n", offset, ret);
+
+    return ret;
+}
+
+static void puv3_gpio_write(void *opaque, hwaddr offset,
+        uint64_t value, unsigned size)
+{
+    PUV3GPIOState *s = opaque;
+
+    DPRINTF("offset 0x%x, value 0x%x\n", offset, value);
+    switch (offset) {
+    case 0x04:
+        s->reg_GPDR = value;
+        break;
+    case 0x08:
+        if (s->reg_GPDR & value) {
+            s->reg_GPLR |= value;
+        } else {
+            DPRINTF("Write gpio input port error!");
+        }
+        break;
+    case 0x0c:
+        if (s->reg_GPDR & value) {
+            s->reg_GPLR &= ~value;
+        } else {
+            DPRINTF("Write gpio input port error!");
+        }
+        break;
+    case 0x10: /* GRER */
+    case 0x14: /* GFER */
+    case 0x18: /* GEDR */
+        break;
+    case 0x20: /* GPIR */
+        s->reg_GPIR = value;
+        break;
+    default:
+        DPRINTF("Bad offset 0x%x\n", offset);
+    }
+}
+
+static const MemoryRegionOps puv3_gpio_ops = {
+    .read = puv3_gpio_read,
+    .write = puv3_gpio_write,
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int puv3_gpio_init(SysBusDevice *dev)
+{
+    PUV3GPIOState *s = FROM_SYSBUS(PUV3GPIOState, dev);
+
+    s->reg_GPLR = 0;
+    s->reg_GPDR = 0;
+
+    /* FIXME: these irqs not handled yet */
+    sysbus_init_irq(dev, &s->irq[PUV3_IRQS_GPIOLOW0]);
+    sysbus_init_irq(dev, &s->irq[PUV3_IRQS_GPIOLOW1]);
+    sysbus_init_irq(dev, &s->irq[PUV3_IRQS_GPIOLOW2]);
+    sysbus_init_irq(dev, &s->irq[PUV3_IRQS_GPIOLOW3]);
+    sysbus_init_irq(dev, &s->irq[PUV3_IRQS_GPIOLOW4]);
+    sysbus_init_irq(dev, &s->irq[PUV3_IRQS_GPIOLOW5]);
+    sysbus_init_irq(dev, &s->irq[PUV3_IRQS_GPIOLOW6]);
+    sysbus_init_irq(dev, &s->irq[PUV3_IRQS_GPIOLOW7]);
+    sysbus_init_irq(dev, &s->irq[PUV3_IRQS_GPIOHIGH]);
+
+    memory_region_init_io(&s->iomem, &puv3_gpio_ops, s, "puv3_gpio",
+            PUV3_REGS_OFFSET);
+    sysbus_init_mmio(dev, &s->iomem);
+
+    return 0;
+}
+
+static void puv3_gpio_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sdc->init = puv3_gpio_init;
+}
+
+static const TypeInfo puv3_gpio_info = {
+    .name = "puv3_gpio",
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(PUV3GPIOState),
+    .class_init = puv3_gpio_class_init,
+};
+
+static void puv3_gpio_register_type(void)
+{
+    type_register_static(&puv3_gpio_info);
+}
+
+type_init(puv3_gpio_register_type)
diff --git a/hw/gpio/zaurus.c b/hw/gpio/zaurus.c
new file mode 100644 (file)
index 0000000..d853ea1
--- /dev/null
@@ -0,0 +1,292 @@
+/*
+ * Copyright (c) 2006-2008 Openedhand Ltd.
+ * Written by Andrzej Zaborowski <balrog@zabor.org>
+ *
+ * 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 or
+ * (at your option) version 3 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
+ * 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 "hw/hw.h"
+#include "hw/arm/sharpsl.h"
+#include "hw/sysbus.h"
+
+#undef REG_FMT
+#define REG_FMT                        "0x%02lx"
+
+/* SCOOP devices */
+
+typedef struct ScoopInfo ScoopInfo;
+struct ScoopInfo {
+    SysBusDevice busdev;
+    qemu_irq handler[16];
+    MemoryRegion iomem;
+    uint16_t status;
+    uint16_t power;
+    uint32_t gpio_level;
+    uint32_t gpio_dir;
+    uint32_t prev_level;
+
+    uint16_t mcr;
+    uint16_t cdr;
+    uint16_t ccr;
+    uint16_t irr;
+    uint16_t imr;
+    uint16_t isr;
+};
+
+#define SCOOP_MCR      0x00
+#define SCOOP_CDR      0x04
+#define SCOOP_CSR      0x08
+#define SCOOP_CPR      0x0c
+#define SCOOP_CCR      0x10
+#define SCOOP_IRR_IRM  0x14
+#define SCOOP_IMR      0x18
+#define SCOOP_ISR      0x1c
+#define SCOOP_GPCR     0x20
+#define SCOOP_GPWR     0x24
+#define SCOOP_GPRR     0x28
+
+static inline void scoop_gpio_handler_update(ScoopInfo *s) {
+    uint32_t level, diff;
+    int bit;
+    level = s->gpio_level & s->gpio_dir;
+
+    for (diff = s->prev_level ^ level; diff; diff ^= 1 << bit) {
+        bit = ffs(diff) - 1;
+        qemu_set_irq(s->handler[bit], (level >> bit) & 1);
+    }
+
+    s->prev_level = level;
+}
+
+static uint64_t scoop_read(void *opaque, hwaddr addr,
+                           unsigned size)
+{
+    ScoopInfo *s = (ScoopInfo *) opaque;
+
+    switch (addr & 0x3f) {
+    case SCOOP_MCR:
+        return s->mcr;
+    case SCOOP_CDR:
+        return s->cdr;
+    case SCOOP_CSR:
+        return s->status;
+    case SCOOP_CPR:
+        return s->power;
+    case SCOOP_CCR:
+        return s->ccr;
+    case SCOOP_IRR_IRM:
+        return s->irr;
+    case SCOOP_IMR:
+        return s->imr;
+    case SCOOP_ISR:
+        return s->isr;
+    case SCOOP_GPCR:
+        return s->gpio_dir;
+    case SCOOP_GPWR:
+    case SCOOP_GPRR:
+        return s->gpio_level;
+    default:
+        zaurus_printf("Bad register offset " REG_FMT "\n", (unsigned long)addr);
+    }
+
+    return 0;
+}
+
+static void scoop_write(void *opaque, hwaddr addr,
+                        uint64_t value, unsigned size)
+{
+    ScoopInfo *s = (ScoopInfo *) opaque;
+    value &= 0xffff;
+
+    switch (addr & 0x3f) {
+    case SCOOP_MCR:
+        s->mcr = value;
+        break;
+    case SCOOP_CDR:
+        s->cdr = value;
+        break;
+    case SCOOP_CPR:
+        s->power = value;
+        if (value & 0x80)
+            s->power |= 0x8040;
+        break;
+    case SCOOP_CCR:
+        s->ccr = value;
+        break;
+    case SCOOP_IRR_IRM:
+        s->irr = value;
+        break;
+    case SCOOP_IMR:
+        s->imr = value;
+        break;
+    case SCOOP_ISR:
+        s->isr = value;
+        break;
+    case SCOOP_GPCR:
+        s->gpio_dir = value;
+        scoop_gpio_handler_update(s);
+        break;
+    case SCOOP_GPWR:
+    case SCOOP_GPRR:   /* GPRR is probably R/O in real HW */
+        s->gpio_level = value & s->gpio_dir;
+        scoop_gpio_handler_update(s);
+        break;
+    default:
+        zaurus_printf("Bad register offset " REG_FMT "\n", (unsigned long)addr);
+    }
+}
+
+static const MemoryRegionOps scoop_ops = {
+    .read = scoop_read,
+    .write = scoop_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void scoop_gpio_set(void *opaque, int line, int level)
+{
+    ScoopInfo *s = (ScoopInfo *) opaque;
+
+    if (level)
+        s->gpio_level |= (1 << line);
+    else
+        s->gpio_level &= ~(1 << line);
+}
+
+static int scoop_init(SysBusDevice *dev)
+{
+    ScoopInfo *s = FROM_SYSBUS(ScoopInfo, dev);
+
+    s->status = 0x02;
+    qdev_init_gpio_out(&s->busdev.qdev, s->handler, 16);
+    qdev_init_gpio_in(&s->busdev.qdev, scoop_gpio_set, 16);
+    memory_region_init_io(&s->iomem, &scoop_ops, s, "scoop", 0x1000);
+
+    sysbus_init_mmio(dev, &s->iomem);
+
+    return 0;
+}
+
+static int scoop_post_load(void *opaque, int version_id)
+{
+    ScoopInfo *s = (ScoopInfo *) opaque;
+    int i;
+    uint32_t level;
+
+    level = s->gpio_level & s->gpio_dir;
+
+    for (i = 0; i < 16; i++) {
+        qemu_set_irq(s->handler[i], (level >> i) & 1);
+    }
+
+    s->prev_level = level;
+
+    return 0;
+}
+
+static bool is_version_0 (void *opaque, int version_id)
+{
+    return version_id == 0;
+}
+
+static const VMStateDescription vmstate_scoop_regs = {
+    .name = "scoop",
+    .version_id = 1,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .post_load = scoop_post_load,
+    .fields = (VMStateField []) {
+        VMSTATE_UINT16(status, ScoopInfo),
+        VMSTATE_UINT16(power, ScoopInfo),
+        VMSTATE_UINT32(gpio_level, ScoopInfo),
+        VMSTATE_UINT32(gpio_dir, ScoopInfo),
+        VMSTATE_UINT32(prev_level, ScoopInfo),
+        VMSTATE_UINT16(mcr, ScoopInfo),
+        VMSTATE_UINT16(cdr, ScoopInfo),
+        VMSTATE_UINT16(ccr, ScoopInfo),
+        VMSTATE_UINT16(irr, ScoopInfo),
+        VMSTATE_UINT16(imr, ScoopInfo),
+        VMSTATE_UINT16(isr, ScoopInfo),
+        VMSTATE_UNUSED_TEST(is_version_0, 2),
+        VMSTATE_END_OF_LIST(),
+    },
+};
+
+static Property scoop_sysbus_properties[] = {
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void scoop_sysbus_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = scoop_init;
+    dc->desc = "Scoop2 Sharp custom ASIC";
+    dc->vmsd = &vmstate_scoop_regs;
+    dc->props = scoop_sysbus_properties;
+}
+
+static const 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_types(void)
+{
+    type_register_static(&scoop_sysbus_info);
+}
+
+type_init(scoop_register_types)
+
+/* Write the bootloader parameters memory area.  */
+
+#define MAGIC_CHG(a, b, c, d)  ((d << 24) | (c << 16) | (b << 8) | a)
+
+static struct QEMU_PACKED sl_param_info {
+    uint32_t comadj_keyword;
+    int32_t comadj;
+
+    uint32_t uuid_keyword;
+    char uuid[16];
+
+    uint32_t touch_keyword;
+    int32_t touch_xp;
+    int32_t touch_yp;
+    int32_t touch_xd;
+    int32_t touch_yd;
+
+    uint32_t adadj_keyword;
+    int32_t adadj;
+
+    uint32_t phad_keyword;
+    int32_t phadadj;
+} zaurus_bootparam = {
+    .comadj_keyword    = MAGIC_CHG('C', 'M', 'A', 'D'),
+    .comadj            = 125,
+    .uuid_keyword      = MAGIC_CHG('U', 'U', 'I', 'D'),
+    .uuid              = { -1 },
+    .touch_keyword     = MAGIC_CHG('T', 'U', 'C', 'H'),
+    .touch_xp          = -1,
+    .adadj_keyword     = MAGIC_CHG('B', 'V', 'A', 'D'),
+    .adadj             = -1,
+    .phad_keyword      = MAGIC_CHG('P', 'H', 'A', 'D'),
+    .phadadj           = 0x01,
+};
+
+void sl_bootparam_write(hwaddr ptr)
+{
+    cpu_physical_memory_write(ptr, (void *)&zaurus_bootparam,
+                              sizeof(struct sl_param_info));
+}
diff --git a/hw/grackle_pci.c b/hw/grackle_pci.c
deleted file mode 100644 (file)
index 69344d9..0000000
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * QEMU Grackle PCI host (heathrow OldWorld PowerMac)
- *
- * Copyright (c) 2006-2007 Fabrice Bellard
- * Copyright (c) 2007 Jocelyn Mayer
- *
- * 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 "hw/pci/pci_host.h"
-#include "hw/ppc/mac.h"
-#include "hw/pci/pci.h"
-
-/* debug Grackle */
-//#define DEBUG_GRACKLE
-
-#ifdef DEBUG_GRACKLE
-#define GRACKLE_DPRINTF(fmt, ...)                               \
-    do { printf("GRACKLE: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define GRACKLE_DPRINTF(fmt, ...)
-#endif
-
-#define GRACKLE_PCI_HOST_BRIDGE(obj) \
-    OBJECT_CHECK(GrackleState, (obj), TYPE_GRACKLE_PCI_HOST_BRIDGE)
-
-typedef struct GrackleState {
-    PCIHostState parent_obj;
-
-    MemoryRegion pci_mmio;
-    MemoryRegion pci_hole;
-} GrackleState;
-
-/* Don't know if this matches real hardware, but it agrees with OHW.  */
-static int pci_grackle_map_irq(PCIDevice *pci_dev, int irq_num)
-{
-    return (irq_num + (pci_dev->devfn >> 3)) & 3;
-}
-
-static void pci_grackle_set_irq(void *opaque, int irq_num, int level)
-{
-    qemu_irq *pic = opaque;
-
-    GRACKLE_DPRINTF("set_irq num %d level %d\n", irq_num, level);
-    qemu_set_irq(pic[irq_num + 0x15], level);
-}
-
-PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic,
-                         MemoryRegion *address_space_mem,
-                         MemoryRegion *address_space_io)
-{
-    DeviceState *dev;
-    SysBusDevice *s;
-    PCIHostState *phb;
-    GrackleState *d;
-
-    dev = qdev_create(NULL, TYPE_GRACKLE_PCI_HOST_BRIDGE);
-    qdev_init_nofail(dev);
-    s = SYS_BUS_DEVICE(dev);
-    phb = PCI_HOST_BRIDGE(dev);
-    d = GRACKLE_PCI_HOST_BRIDGE(dev);
-
-    memory_region_init(&d->pci_mmio, "pci-mmio", 0x100000000ULL);
-    memory_region_init_alias(&d->pci_hole, "pci-hole", &d->pci_mmio,
-                             0x80000000ULL, 0x7e000000ULL);
-    memory_region_add_subregion(address_space_mem, 0x80000000ULL,
-                                &d->pci_hole);
-
-    phb->bus = pci_register_bus(dev, "pci",
-                                pci_grackle_set_irq,
-                                pci_grackle_map_irq,
-                                pic,
-                                &d->pci_mmio,
-                                address_space_io,
-                                0, 4, TYPE_PCI_BUS);
-
-    pci_create_simple(phb->bus, 0, "grackle");
-
-    sysbus_mmio_map(s, 0, base);
-    sysbus_mmio_map(s, 1, base + 0x00200000);
-
-    return phb->bus;
-}
-
-static int pci_grackle_init_device(SysBusDevice *dev)
-{
-    PCIHostState *phb;
-
-    phb = PCI_HOST_BRIDGE(dev);
-
-    memory_region_init_io(&phb->conf_mem, &pci_host_conf_le_ops,
-                          dev, "pci-conf-idx", 0x1000);
-    memory_region_init_io(&phb->data_mem, &pci_host_data_le_ops,
-                          dev, "pci-data-idx", 0x1000);
-    sysbus_init_mmio(dev, &phb->conf_mem);
-    sysbus_init_mmio(dev, &phb->data_mem);
-
-    return 0;
-}
-
-static int grackle_pci_host_init(PCIDevice *d)
-{
-    d->config[0x09] = 0x01;
-    return 0;
-}
-
-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 const 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 const TypeInfo grackle_pci_host_info = {
-    .name          = TYPE_GRACKLE_PCI_HOST_BRIDGE,
-    .parent        = TYPE_PCI_HOST_BRIDGE,
-    .instance_size = sizeof(GrackleState),
-    .class_init    = pci_grackle_class_init,
-};
-
-static void grackle_register_types(void)
-{
-    type_register_static(&grackle_pci_info);
-    type_register_static(&grackle_pci_host_info);
-}
-
-type_init(grackle_register_types)
diff --git a/hw/grlib.h b/hw/grlib.h
deleted file mode 100644 (file)
index 470ce72..0000000
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * QEMU GRLIB Components
- *
- * Copyright (c) 2010-2011 AdaCore
- *
- * 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 _GRLIB_H_
-#define _GRLIB_H_
-
-#include "hw/qdev.h"
-#include "hw/sysbus.h"
-
-/* Emulation of GrLib device is base on the GRLIB IP Core User's Manual:
- * http://www.gaisler.com/products/grlib/grip.pdf
- */
-
-/* IRQMP */
-
-typedef void (*set_pil_in_fn) (void *opaque, uint32_t pil_in);
-
-void grlib_irqmp_set_irq(void *opaque, int irq, int level);
-
-void grlib_irqmp_ack(DeviceState *dev, int intno);
-
-static inline
-DeviceState *grlib_irqmp_create(hwaddr   base,
-                                CPUSPARCState            *env,
-                                qemu_irq           **cpu_irqs,
-                                uint32_t             nr_irqs,
-                                set_pil_in_fn        set_pil_in)
-{
-    DeviceState *dev;
-
-    assert(cpu_irqs != NULL);
-
-    dev = qdev_create(NULL, "grlib,irqmp");
-    qdev_prop_set_ptr(dev, "set_pil_in", set_pil_in);
-    qdev_prop_set_ptr(dev, "set_pil_in_opaque", env);
-
-    if (qdev_init(dev)) {
-        return NULL;
-    }
-
-    env->irq_manager = dev;
-
-    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
-
-    *cpu_irqs = qemu_allocate_irqs(grlib_irqmp_set_irq,
-                                   dev,
-                                   nr_irqs);
-
-    return dev;
-}
-
-/* GPTimer */
-
-static inline
-DeviceState *grlib_gptimer_create(hwaddr  base,
-                                  uint32_t            nr_timers,
-                                  uint32_t            freq,
-                                  qemu_irq           *cpu_irqs,
-                                  int                 base_irq)
-{
-    DeviceState *dev;
-    int i;
-
-    dev = qdev_create(NULL, "grlib,gptimer");
-    qdev_prop_set_uint32(dev, "nr-timers", nr_timers);
-    qdev_prop_set_uint32(dev, "frequency", freq);
-    qdev_prop_set_uint32(dev, "irq-line", base_irq);
-
-    if (qdev_init(dev)) {
-        return NULL;
-    }
-
-    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
-
-    for (i = 0; i < nr_timers; i++) {
-        sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, cpu_irqs[base_irq + i]);
-    }
-
-    return dev;
-}
-
-/* APB UART */
-
-static inline
-DeviceState *grlib_apbuart_create(hwaddr  base,
-                                  CharDriverState    *serial,
-                                  qemu_irq            irq)
-{
-    DeviceState *dev;
-
-    dev = qdev_create(NULL, "grlib,apbuart");
-    qdev_prop_set_chr(dev, "chrdev", serial);
-
-    if (qdev_init(dev)) {
-        return NULL;
-    }
-
-    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
-
-    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq);
-
-    return dev;
-}
-
-#endif /* ! _GRLIB_H_ */
diff --git a/hw/grlib_apbuart.c b/hw/grlib_apbuart.c
deleted file mode 100644 (file)
index 62f7990..0000000
+++ /dev/null
@@ -1,293 +0,0 @@
-/*
- * QEMU GRLIB APB UART Emulator
- *
- * Copyright (c) 2010-2011 AdaCore
- *
- * 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 "hw/sysbus.h"
-#include "char/char.h"
-
-#include "trace.h"
-
-#define UART_REG_SIZE 20     /* Size of memory mapped registers */
-
-/* UART status register fields */
-#define UART_DATA_READY           (1 <<  0)
-#define UART_TRANSMIT_SHIFT_EMPTY (1 <<  1)
-#define UART_TRANSMIT_FIFO_EMPTY  (1 <<  2)
-#define UART_BREAK_RECEIVED       (1 <<  3)
-#define UART_OVERRUN              (1 <<  4)
-#define UART_PARITY_ERROR         (1 <<  5)
-#define UART_FRAMING_ERROR        (1 <<  6)
-#define UART_TRANSMIT_FIFO_HALF   (1 <<  7)
-#define UART_RECEIVE_FIFO_HALF    (1 <<  8)
-#define UART_TRANSMIT_FIFO_FULL   (1 <<  9)
-#define UART_RECEIVE_FIFO_FULL    (1 << 10)
-
-/* UART control register fields */
-#define UART_RECEIVE_ENABLE          (1 <<  0)
-#define UART_TRANSMIT_ENABLE         (1 <<  1)
-#define UART_RECEIVE_INTERRUPT       (1 <<  2)
-#define UART_TRANSMIT_INTERRUPT      (1 <<  3)
-#define UART_PARITY_SELECT           (1 <<  4)
-#define UART_PARITY_ENABLE           (1 <<  5)
-#define UART_FLOW_CONTROL            (1 <<  6)
-#define UART_LOOPBACK                (1 <<  7)
-#define UART_EXTERNAL_CLOCK          (1 <<  8)
-#define UART_RECEIVE_FIFO_INTERRUPT  (1 <<  9)
-#define UART_TRANSMIT_FIFO_INTERRUPT (1 << 10)
-#define UART_FIFO_DEBUG_MODE         (1 << 11)
-#define UART_OUTPUT_ENABLE           (1 << 12)
-#define UART_FIFO_AVAILABLE          (1 << 31)
-
-/* Memory mapped register offsets */
-#define DATA_OFFSET       0x00
-#define STATUS_OFFSET     0x04
-#define CONTROL_OFFSET    0x08
-#define SCALER_OFFSET     0x0C  /* not supported */
-#define FIFO_DEBUG_OFFSET 0x10  /* not supported */
-
-#define FIFO_LENGTH 1024
-
-typedef struct UART {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-    qemu_irq irq;
-
-    CharDriverState *chr;
-
-    /* registers */
-    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 FIFO_LENGTH - uart->len;
-}
-
-static void grlib_apbuart_receive(void *opaque, const uint8_t *buf, int size)
-{
-    UART *uart = opaque;
-
-    if (uart->control & UART_RECEIVE_ENABLE) {
-        uart_add_to_fifo(uart, buf, size);
-
-        uart->status |= UART_DATA_READY;
-
-        if (uart->control & UART_RECEIVE_INTERRUPT) {
-            qemu_irq_pulse(uart->irq);
-        }
-    }
-}
-
-static void grlib_apbuart_event(void *opaque, int event)
-{
-    trace_grlib_apbuart_event(event);
-}
-
-
-static uint64_t grlib_apbuart_read(void *opaque, hwaddr 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, hwaddr addr,
-                                uint64_t value, unsigned size)
-{
-    UART          *uart = opaque;
-    unsigned char  c    = 0;
-
-    addr &= 0xff;
-
-    /* Unit registers */
-    switch (addr) {
-    case DATA_OFFSET:
-    case DATA_OFFSET + 3:       /* When only one byte write */
-        /* Transmit when character device available and transmitter enabled */
-        if ((uart->chr) && (uart->control & UART_TRANSMIT_ENABLE)) {
-            c = value & 0xFF;
-            qemu_chr_fe_write(uart->chr, &c, 1);
-            /* Generate interrupt */
-            if (uart->control & UART_TRANSMIT_INTERRUPT) {
-                qemu_irq_pulse(uart->irq);
-            }
-        }
-        return;
-
-    case STATUS_OFFSET:
-        /* Read Only */
-        return;
-
-    case CONTROL_OFFSET:
-        uart->control = value;
-        return;
-
-    case SCALER_OFFSET:
-        /* Not supported */
-        return;
-
-    default:
-        break;
-    }
-
-    trace_grlib_apbuart_writel_unknown(addr, value);
-}
-
-static const MemoryRegionOps grlib_apbuart_ops = {
-    .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);
-
-    qemu_chr_add_handlers(uart->chr,
-                          grlib_apbuart_can_receive,
-                          grlib_apbuart_receive,
-                          grlib_apbuart_event,
-                          uart);
-
-    sysbus_init_irq(dev, &uart->irq);
-
-    memory_region_init_io(&uart->iomem, &grlib_apbuart_ops, uart,
-                          "uart", UART_REG_SIZE);
-
-    sysbus_init_mmio(dev, &uart->iomem);
-
-    return 0;
-}
-
-static void grlib_apbuart_reset(DeviceState *d)
-{
-    UART *uart = container_of(d, UART, busdev.qdev);
-
-    /* Transmitter FIFO and shift registers are always empty in QEMU */
-    uart->status =  UART_TRANSMIT_FIFO_EMPTY | UART_TRANSMIT_SHIFT_EMPTY;
-    /* Everything is off */
-    uart->control = 0;
-    /* Flush receive FIFO */
-    uart->len = 0;
-    uart->current = 0;
-}
-
-static Property grlib_apbuart_properties[] = {
-    DEFINE_PROP_CHR("chrdev", UART, chr),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void grlib_apbuart_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = grlib_apbuart_init;
-    dc->reset = grlib_apbuart_reset;
-    dc->props = grlib_apbuart_properties;
-}
-
-static const TypeInfo grlib_apbuart_info = {
-    .name          = "grlib,apbuart",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(UART),
-    .class_init    = grlib_apbuart_class_init,
-};
-
-static void grlib_apbuart_register_types(void)
-{
-    type_register_static(&grlib_apbuart_info);
-}
-
-type_init(grlib_apbuart_register_types)
diff --git a/hw/grlib_gptimer.c b/hw/grlib_gptimer.c
deleted file mode 100644 (file)
index 7043a34..0000000
+++ /dev/null
@@ -1,404 +0,0 @@
-/*
- * QEMU GRLIB GPTimer Emulator
- *
- * Copyright (c) 2010-2011 AdaCore
- *
- * 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 "hw/sysbus.h"
-#include "qemu/timer.h"
-#include "hw/ptimer.h"
-
-#include "trace.h"
-
-#define UNIT_REG_SIZE    16     /* Size of memory mapped regs for the unit */
-#define GPTIMER_REG_SIZE 16     /* Size of memory mapped regs for a GPTimer */
-
-#define GPTIMER_MAX_TIMERS 8
-
-/* GPTimer Config register fields */
-#define GPTIMER_ENABLE      (1 << 0)
-#define GPTIMER_RESTART     (1 << 1)
-#define GPTIMER_LOAD        (1 << 2)
-#define GPTIMER_INT_ENABLE  (1 << 3)
-#define GPTIMER_INT_PENDING (1 << 4)
-#define GPTIMER_CHAIN       (1 << 5) /* Not supported */
-#define GPTIMER_DEBUG_HALT  (1 << 6) /* Not supported */
-
-/* Memory mapped register offsets */
-#define SCALER_OFFSET         0x00
-#define SCALER_RELOAD_OFFSET  0x04
-#define CONFIG_OFFSET         0x08
-#define COUNTER_OFFSET        0x00
-#define COUNTER_RELOAD_OFFSET 0x04
-#define TIMER_BASE            0x10
-
-typedef struct GPTimer     GPTimer;
-typedef struct GPTimerUnit GPTimerUnit;
-
-struct GPTimer {
-    QEMUBH *bh;
-    struct ptimer_state *ptimer;
-
-    qemu_irq     irq;
-    int          id;
-    GPTimerUnit *unit;
-
-    /* registers */
-    uint32_t counter;
-    uint32_t reload;
-    uint32_t config;
-};
-
-struct GPTimerUnit {
-    SysBusDevice  busdev;
-    MemoryRegion iomem;
-
-    uint32_t nr_timers;         /* Number of timers available */
-    uint32_t freq_hz;           /* System frequency */
-    uint32_t irq_line;          /* Base irq line */
-
-    GPTimer *timers;
-
-    /* registers */
-    uint32_t scaler;
-    uint32_t reload;
-    uint32_t config;
-};
-
-static void grlib_gptimer_enable(GPTimer *timer)
-{
-    assert(timer != NULL);
-
-
-    ptimer_stop(timer->ptimer);
-
-    if (!(timer->config & GPTIMER_ENABLE)) {
-        /* Timer disabled */
-        trace_grlib_gptimer_disabled(timer->id, timer->config);
-        return;
-    }
-
-    /* ptimer is triggered when the counter reach 0 but GPTimer is triggered at
-       underflow. Set count + 1 to simulate the GPTimer behavior. */
-
-    trace_grlib_gptimer_enable(timer->id, timer->counter + 1);
-
-    ptimer_set_count(timer->ptimer, timer->counter + 1);
-    ptimer_run(timer->ptimer, 1);
-}
-
-static void grlib_gptimer_restart(GPTimer *timer)
-{
-    assert(timer != NULL);
-
-    trace_grlib_gptimer_restart(timer->id, timer->reload);
-
-    timer->counter = timer->reload;
-    grlib_gptimer_enable(timer);
-}
-
-static void grlib_gptimer_set_scaler(GPTimerUnit *unit, uint32_t scaler)
-{
-    int i = 0;
-    uint32_t value = 0;
-
-    assert(unit != NULL);
-
-    if (scaler > 0) {
-        value = unit->freq_hz / (scaler + 1);
-    } else {
-        value = unit->freq_hz;
-    }
-
-    trace_grlib_gptimer_set_scaler(scaler, value);
-
-    for (i = 0; i < unit->nr_timers; i++) {
-        ptimer_set_freq(unit->timers[i].ptimer, value);
-    }
-}
-
-static void grlib_gptimer_hit(void *opaque)
-{
-    GPTimer *timer = opaque;
-    assert(timer != NULL);
-
-    trace_grlib_gptimer_hit(timer->id);
-
-    /* Timer expired */
-
-    if (timer->config & GPTIMER_INT_ENABLE) {
-        /* Set the pending bit (only unset by write in the config register) */
-        timer->config |= GPTIMER_INT_PENDING;
-        qemu_irq_pulse(timer->irq);
-    }
-
-    if (timer->config & GPTIMER_RESTART) {
-        grlib_gptimer_restart(timer);
-    }
-}
-
-static uint64_t grlib_gptimer_read(void *opaque, hwaddr addr,
-                                   unsigned size)
-{
-    GPTimerUnit        *unit  = opaque;
-    hwaddr  timer_addr;
-    int                 id;
-    uint32_t            value = 0;
-
-    addr &= 0xff;
-
-    /* Unit registers */
-    switch (addr) {
-    case SCALER_OFFSET:
-        trace_grlib_gptimer_readl(-1, addr, unit->scaler);
-        return unit->scaler;
-
-    case SCALER_RELOAD_OFFSET:
-        trace_grlib_gptimer_readl(-1, addr, unit->reload);
-        return unit->reload;
-
-    case CONFIG_OFFSET:
-        trace_grlib_gptimer_readl(-1, addr, unit->config);
-        return unit->config;
-
-    default:
-        break;
-    }
-
-    timer_addr = (addr % TIMER_BASE);
-    id         = (addr - TIMER_BASE) / TIMER_BASE;
-
-    if (id >= 0 && id < unit->nr_timers) {
-
-        /* GPTimer registers */
-        switch (timer_addr) {
-        case COUNTER_OFFSET:
-            value = ptimer_get_count(unit->timers[id].ptimer);
-            trace_grlib_gptimer_readl(id, addr, value);
-            return value;
-
-        case COUNTER_RELOAD_OFFSET:
-            value = unit->timers[id].reload;
-            trace_grlib_gptimer_readl(id, addr, value);
-            return value;
-
-        case CONFIG_OFFSET:
-            trace_grlib_gptimer_readl(id, addr, unit->timers[id].config);
-            return unit->timers[id].config;
-
-        default:
-            break;
-        }
-
-    }
-
-    trace_grlib_gptimer_readl(-1, addr, 0);
-    return 0;
-}
-
-static void grlib_gptimer_write(void *opaque, hwaddr addr,
-                                uint64_t value, unsigned size)
-{
-    GPTimerUnit        *unit = opaque;
-    hwaddr  timer_addr;
-    int                 id;
-
-    addr &= 0xff;
-
-    /* Unit registers */
-    switch (addr) {
-    case SCALER_OFFSET:
-        value &= 0xFFFF; /* clean up the value */
-        unit->scaler = value;
-        trace_grlib_gptimer_writel(-1, addr, unit->scaler);
-        return;
-
-    case SCALER_RELOAD_OFFSET:
-        value &= 0xFFFF; /* clean up the value */
-        unit->reload = value;
-        trace_grlib_gptimer_writel(-1, addr, unit->reload);
-        grlib_gptimer_set_scaler(unit, value);
-        return;
-
-    case CONFIG_OFFSET:
-        /* Read Only (disable timer freeze not supported) */
-        trace_grlib_gptimer_writel(-1, addr, 0);
-        return;
-
-    default:
-        break;
-    }
-
-    timer_addr = (addr % TIMER_BASE);
-    id         = (addr - TIMER_BASE) / TIMER_BASE;
-
-    if (id >= 0 && id < unit->nr_timers) {
-
-        /* GPTimer registers */
-        switch (timer_addr) {
-        case COUNTER_OFFSET:
-            trace_grlib_gptimer_writel(id, addr, value);
-            unit->timers[id].counter = value;
-            grlib_gptimer_enable(&unit->timers[id]);
-            return;
-
-        case COUNTER_RELOAD_OFFSET:
-            trace_grlib_gptimer_writel(id, addr, value);
-            unit->timers[id].reload = value;
-            return;
-
-        case CONFIG_OFFSET:
-            trace_grlib_gptimer_writel(id, addr, value);
-
-            if (value & GPTIMER_INT_PENDING) {
-                /* clear pending bit */
-                value &= ~GPTIMER_INT_PENDING;
-            } else {
-                /* keep pending bit */
-                value |= unit->timers[id].config & GPTIMER_INT_PENDING;
-            }
-
-            unit->timers[id].config = value;
-
-            /* gptimer_restart calls gptimer_enable, so if "enable" and "load"
-               bits are present, we just have to call restart. */
-
-            if (value & GPTIMER_LOAD) {
-                grlib_gptimer_restart(&unit->timers[id]);
-            } else if (value & GPTIMER_ENABLE) {
-                grlib_gptimer_enable(&unit->timers[id]);
-            }
-
-            /* These fields must always be read as 0 */
-            value &= ~(GPTIMER_LOAD & GPTIMER_DEBUG_HALT);
-
-            unit->timers[id].config = value;
-            return;
-
-        default:
-            break;
-        }
-
-    }
-
-    trace_grlib_gptimer_writel(-1, addr, value);
-}
-
-static const MemoryRegionOps grlib_gptimer_ops = {
-    .read = grlib_gptimer_read,
-    .write = grlib_gptimer_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-};
-
-static void grlib_gptimer_reset(DeviceState *d)
-{
-    GPTimerUnit *unit = container_of(d, GPTimerUnit, busdev.qdev);
-    int          i    = 0;
-
-    assert(unit != NULL);
-
-    unit->scaler = 0;
-    unit->reload = 0;
-    unit->config = 0;
-
-    unit->config  = unit->nr_timers;
-    unit->config |= unit->irq_line << 3;
-    unit->config |= 1 << 8;     /* separate interrupt */
-    unit->config |= 1 << 9;     /* Disable timer freeze */
-
-
-    for (i = 0; i < unit->nr_timers; i++) {
-        GPTimer *timer = &unit->timers[i];
-
-        timer->counter = 0;
-        timer->reload = 0;
-        timer->config = 0;
-        ptimer_stop(timer->ptimer);
-        ptimer_set_count(timer->ptimer, 0);
-        ptimer_set_freq(timer->ptimer, unit->freq_hz);
-    }
-}
-
-static int grlib_gptimer_init(SysBusDevice *dev)
-{
-    GPTimerUnit  *unit = FROM_SYSBUS(typeof(*unit), dev);
-    unsigned int  i;
-
-    assert(unit->nr_timers > 0);
-    assert(unit->nr_timers <= GPTIMER_MAX_TIMERS);
-
-    unit->timers = g_malloc0(sizeof unit->timers[0] * unit->nr_timers);
-
-    for (i = 0; i < unit->nr_timers; i++) {
-        GPTimer *timer = &unit->timers[i];
-
-        timer->unit   = unit;
-        timer->bh     = qemu_bh_new(grlib_gptimer_hit, timer);
-        timer->ptimer = ptimer_init(timer->bh);
-        timer->id     = i;
-
-        /* One IRQ line for each timer */
-        sysbus_init_irq(dev, &timer->irq);
-
-        ptimer_set_freq(timer->ptimer, unit->freq_hz);
-    }
-
-    memory_region_init_io(&unit->iomem, &grlib_gptimer_ops, unit, "gptimer",
-                          UNIT_REG_SIZE + GPTIMER_REG_SIZE * unit->nr_timers);
-
-    sysbus_init_mmio(dev, &unit->iomem);
-    return 0;
-}
-
-static Property grlib_gptimer_properties[] = {
-    DEFINE_PROP_UINT32("frequency", GPTimerUnit, freq_hz,   40000000),
-    DEFINE_PROP_UINT32("irq-line",  GPTimerUnit, irq_line,  8),
-    DEFINE_PROP_UINT32("nr-timers", GPTimerUnit, nr_timers, 2),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void grlib_gptimer_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = grlib_gptimer_init;
-    dc->reset = grlib_gptimer_reset;
-    dc->props = grlib_gptimer_properties;
-}
-
-static const 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_types(void)
-{
-    type_register_static(&grlib_gptimer_info);
-}
-
-type_init(grlib_gptimer_register_types)
diff --git a/hw/grlib_irqmp.c b/hw/grlib_irqmp.c
deleted file mode 100644 (file)
index 7ee469d..0000000
+++ /dev/null
@@ -1,385 +0,0 @@
-/*
- * QEMU GRLIB IRQMP Emulator
- *
- * (Multiprocessor and extended interrupt not supported)
- *
- * Copyright (c) 2010-2011 AdaCore
- *
- * 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 "hw/sysbus.h"
-#include "cpu.h"
-
-#include "hw/grlib.h"
-
-#include "trace.h"
-
-#define IRQMP_MAX_CPU 16
-#define IRQMP_REG_SIZE 256      /* Size of memory mapped registers */
-
-/* Memory mapped register offsets */
-#define LEVEL_OFFSET     0x00
-#define PENDING_OFFSET   0x04
-#define FORCE0_OFFSET    0x08
-#define CLEAR_OFFSET     0x0C
-#define MP_STATUS_OFFSET 0x10
-#define BROADCAST_OFFSET 0x14
-#define MASK_OFFSET      0x40
-#define FORCE_OFFSET     0x80
-#define EXTENDED_OFFSET  0xC0
-
-typedef struct IRQMPState IRQMPState;
-
-typedef struct IRQMP {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-
-    void *set_pil_in;
-    void *set_pil_in_opaque;
-
-    IRQMPState *state;
-} IRQMP;
-
-struct IRQMPState {
-    uint32_t level;
-    uint32_t pending;
-    uint32_t clear;
-    uint32_t broadcast;
-
-    uint32_t mask[IRQMP_MAX_CPU];
-    uint32_t force[IRQMP_MAX_CPU];
-    uint32_t extended[IRQMP_MAX_CPU];
-
-    IRQMP    *parent;
-};
-
-static void grlib_irqmp_check_irqs(IRQMPState *state)
-{
-    uint32_t      pend   = 0;
-    uint32_t      level0 = 0;
-    uint32_t      level1 = 0;
-    set_pil_in_fn set_pil_in;
-
-    assert(state != NULL);
-    assert(state->parent != NULL);
-
-    /* IRQ for CPU 0 (no SMP support) */
-    pend = (state->pending | state->force[0])
-        & state->mask[0];
-
-    level0 = pend & ~state->level;
-    level1 = pend &  state->level;
-
-    trace_grlib_irqmp_check_irqs(state->pending, state->force[0],
-                                 state->mask[0], level1, level0);
-
-    set_pil_in = (set_pil_in_fn)state->parent->set_pil_in;
-
-    /* Trigger level1 interrupt first and level0 if there is no level1 */
-    if (level1 != 0) {
-        set_pil_in(state->parent->set_pil_in_opaque, level1);
-    } else {
-        set_pil_in(state->parent->set_pil_in_opaque, level0);
-    }
-}
-
-void grlib_irqmp_ack(DeviceState *dev, int intno)
-{
-    SysBusDevice *sdev;
-    IRQMP        *irqmp;
-    IRQMPState   *state;
-    uint32_t      mask;
-
-    assert(dev != NULL);
-
-    sdev = SYS_BUS_DEVICE(dev);
-    assert(sdev != NULL);
-
-    irqmp = FROM_SYSBUS(typeof(*irqmp), sdev);
-    assert(irqmp != NULL);
-
-    state = irqmp->state;
-    assert(state != NULL);
-
-    intno &= 15;
-    mask = 1 << intno;
-
-    trace_grlib_irqmp_ack(intno);
-
-    /* Clear registers */
-    state->pending  &= ~mask;
-    state->force[0] &= ~mask; /* Only CPU 0 (No SMP support) */
-
-    grlib_irqmp_check_irqs(state);
-}
-
-void grlib_irqmp_set_irq(void *opaque, int irq, int level)
-{
-    IRQMP      *irqmp;
-    IRQMPState *s;
-    int         i = 0;
-
-    assert(opaque != NULL);
-
-    irqmp = FROM_SYSBUS(typeof(*irqmp), SYS_BUS_DEVICE(opaque));
-    assert(irqmp != NULL);
-
-    s = irqmp->state;
-    assert(s         != NULL);
-    assert(s->parent != NULL);
-
-
-    if (level) {
-        trace_grlib_irqmp_set_irq(irq);
-
-        if (s->broadcast & 1 << irq) {
-            /* Broadcasted IRQ */
-            for (i = 0; i < IRQMP_MAX_CPU; i++) {
-                s->force[i] |= 1 << irq;
-            }
-        } else {
-            s->pending |= 1 << irq;
-        }
-        grlib_irqmp_check_irqs(s);
-
-    }
-}
-
-static uint64_t grlib_irqmp_read(void *opaque, hwaddr addr,
-                                 unsigned size)
-{
-    IRQMP      *irqmp = opaque;
-    IRQMPState *state;
-
-    assert(irqmp != NULL);
-    state = irqmp->state;
-    assert(state != NULL);
-
-    addr &= 0xff;
-
-    /* global registers */
-    switch (addr) {
-    case LEVEL_OFFSET:
-        return state->level;
-
-    case PENDING_OFFSET:
-        return state->pending;
-
-    case FORCE0_OFFSET:
-        /* This register is an "alias" for the force register of CPU 0 */
-        return state->force[0];
-
-    case CLEAR_OFFSET:
-    case MP_STATUS_OFFSET:
-        /* Always read as 0 */
-        return 0;
-
-    case BROADCAST_OFFSET:
-        return state->broadcast;
-
-    default:
-        break;
-    }
-
-    /* mask registers */
-    if (addr >= MASK_OFFSET && addr < FORCE_OFFSET) {
-        int cpu = (addr - MASK_OFFSET) / 4;
-        assert(cpu >= 0 && cpu < IRQMP_MAX_CPU);
-
-        return state->mask[cpu];
-    }
-
-    /* force registers */
-    if (addr >= FORCE_OFFSET && addr < EXTENDED_OFFSET) {
-        int cpu = (addr - FORCE_OFFSET) / 4;
-        assert(cpu >= 0 && cpu < IRQMP_MAX_CPU);
-
-        return state->force[cpu];
-    }
-
-    /* extended (not supported) */
-    if (addr >= EXTENDED_OFFSET && addr < IRQMP_REG_SIZE) {
-        int cpu = (addr - EXTENDED_OFFSET) / 4;
-        assert(cpu >= 0 && cpu < IRQMP_MAX_CPU);
-
-        return state->extended[cpu];
-    }
-
-    trace_grlib_irqmp_readl_unknown(addr);
-    return 0;
-}
-
-static void grlib_irqmp_write(void *opaque, hwaddr addr,
-                              uint64_t value, unsigned size)
-{
-    IRQMP      *irqmp = opaque;
-    IRQMPState *state;
-
-    assert(irqmp != NULL);
-    state = irqmp->state;
-    assert(state != NULL);
-
-    addr &= 0xff;
-
-    /* global registers */
-    switch (addr) {
-    case LEVEL_OFFSET:
-        value &= 0xFFFF << 1; /* clean up the value */
-        state->level = value;
-        return;
-
-    case PENDING_OFFSET:
-        /* Read Only */
-        return;
-
-    case FORCE0_OFFSET:
-        /* This register is an "alias" for the force register of CPU 0 */
-
-        value &= 0xFFFE; /* clean up the value */
-        state->force[0] = value;
-        grlib_irqmp_check_irqs(irqmp->state);
-        return;
-
-    case CLEAR_OFFSET:
-        value &= ~1; /* clean up the value */
-        state->pending &= ~value;
-        return;
-
-    case MP_STATUS_OFFSET:
-        /* Read Only (no SMP support) */
-        return;
-
-    case BROADCAST_OFFSET:
-        value &= 0xFFFE; /* clean up the value */
-        state->broadcast = value;
-        return;
-
-    default:
-        break;
-    }
-
-    /* mask registers */
-    if (addr >= MASK_OFFSET && addr < FORCE_OFFSET) {
-        int cpu = (addr - MASK_OFFSET) / 4;
-        assert(cpu >= 0 && cpu < IRQMP_MAX_CPU);
-
-        value &= ~1; /* clean up the value */
-        state->mask[cpu] = value;
-        grlib_irqmp_check_irqs(irqmp->state);
-        return;
-    }
-
-    /* force registers */
-    if (addr >= FORCE_OFFSET && addr < EXTENDED_OFFSET) {
-        int cpu = (addr - FORCE_OFFSET) / 4;
-        assert(cpu >= 0 && cpu < IRQMP_MAX_CPU);
-
-        uint32_t force = value & 0xFFFE;
-        uint32_t clear = (value >> 16) & 0xFFFE;
-        uint32_t old   = state->force[cpu];
-
-        state->force[cpu] = (old | force) & ~clear;
-        grlib_irqmp_check_irqs(irqmp->state);
-        return;
-    }
-
-    /* extended (not supported) */
-    if (addr >= EXTENDED_OFFSET && addr < IRQMP_REG_SIZE) {
-        int cpu = (addr - EXTENDED_OFFSET) / 4;
-        assert(cpu >= 0 && cpu < IRQMP_MAX_CPU);
-
-        value &= 0xF; /* clean up the value */
-        state->extended[cpu] = value;
-        return;
-    }
-
-    trace_grlib_irqmp_writel_unknown(addr, value);
-}
-
-static const MemoryRegionOps grlib_irqmp_ops = {
-    .read = grlib_irqmp_read,
-    .write = grlib_irqmp_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-};
-
-static void grlib_irqmp_reset(DeviceState *d)
-{
-    IRQMP *irqmp = container_of(d, IRQMP, busdev.qdev);
-    assert(irqmp        != NULL);
-    assert(irqmp->state != NULL);
-
-    memset(irqmp->state, 0, sizeof *irqmp->state);
-    irqmp->state->parent = irqmp;
-}
-
-static int grlib_irqmp_init(SysBusDevice *dev)
-{
-    IRQMP *irqmp = FROM_SYSBUS(typeof(*irqmp), dev);
-
-    assert(irqmp != NULL);
-
-    /* Check parameters */
-    if (irqmp->set_pil_in == NULL) {
-        return -1;
-    }
-
-    memory_region_init_io(&irqmp->iomem, &grlib_irqmp_ops, irqmp,
-                          "irqmp", IRQMP_REG_SIZE);
-
-    irqmp->state = g_malloc0(sizeof *irqmp->state);
-
-    sysbus_init_mmio(dev, &irqmp->iomem);
-
-    return 0;
-}
-
-static Property grlib_irqmp_properties[] = {
-    DEFINE_PROP_PTR("set_pil_in", IRQMP, set_pil_in),
-    DEFINE_PROP_PTR("set_pil_in_opaque", IRQMP, set_pil_in_opaque),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void grlib_irqmp_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = grlib_irqmp_init;
-    dc->reset = grlib_irqmp_reset;
-    dc->props = grlib_irqmp_properties;
-}
-
-static const 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_types(void)
-{
-    type_register_static(&grlib_irqmp_info);
-}
-
-type_init(grlib_irqmp_register_types)
diff --git a/hw/gt64xxx.c b/hw/gt64xxx.c
deleted file mode 100644 (file)
index 37be9c2..0000000
+++ /dev/null
@@ -1,1188 +0,0 @@
-/*
- * QEMU GT64120 PCI host
- *
- * Copyright (c) 2006,2007 Aurelien Jarno
- *
- * 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 "hw/hw.h"
-#include "hw/mips.h"
-#include "hw/pci/pci.h"
-#include "hw/pci/pci_host.h"
-#include "hw/pc.h"
-#include "exec/address-spaces.h"
-
-//#define DEBUG
-
-#ifdef DEBUG
-#define DPRINTF(fmt, ...) fprintf(stderr, "%s: " fmt, __FUNCTION__, ##__VA_ARGS__)
-#else
-#define DPRINTF(fmt, ...)
-#endif
-
-#define GT_REGS                        (0x1000 >> 2)
-
-/* CPU Configuration */
-#define GT_CPU                 (0x000 >> 2)
-#define GT_MULTI               (0x120 >> 2)
-
-/* CPU Address Decode */
-#define GT_SCS10LD             (0x008 >> 2)
-#define GT_SCS10HD             (0x010 >> 2)
-#define GT_SCS32LD             (0x018 >> 2)
-#define GT_SCS32HD             (0x020 >> 2)
-#define GT_CS20LD              (0x028 >> 2)
-#define GT_CS20HD              (0x030 >> 2)
-#define GT_CS3BOOTLD           (0x038 >> 2)
-#define GT_CS3BOOTHD           (0x040 >> 2)
-#define GT_PCI0IOLD                    (0x048 >> 2)
-#define GT_PCI0IOHD                    (0x050 >> 2)
-#define GT_PCI0M0LD                    (0x058 >> 2)
-#define GT_PCI0M0HD                    (0x060 >> 2)
-#define GT_PCI0M1LD                    (0x080 >> 2)
-#define GT_PCI0M1HD                    (0x088 >> 2)
-#define GT_PCI1IOLD                    (0x090 >> 2)
-#define GT_PCI1IOHD                    (0x098 >> 2)
-#define GT_PCI1M0LD                    (0x0a0 >> 2)
-#define GT_PCI1M0HD                    (0x0a8 >> 2)
-#define GT_PCI1M1LD                    (0x0b0 >> 2)
-#define GT_PCI1M1HD                    (0x0b8 >> 2)
-#define GT_ISD                 (0x068 >> 2)
-
-#define GT_SCS10AR             (0x0d0 >> 2)
-#define GT_SCS32AR             (0x0d8 >> 2)
-#define GT_CS20R               (0x0e0 >> 2)
-#define GT_CS3BOOTR                    (0x0e8 >> 2)
-
-#define GT_PCI0IOREMAP         (0x0f0 >> 2)
-#define GT_PCI0M0REMAP         (0x0f8 >> 2)
-#define GT_PCI0M1REMAP         (0x100 >> 2)
-#define GT_PCI1IOREMAP         (0x108 >> 2)
-#define GT_PCI1M0REMAP         (0x110 >> 2)
-#define GT_PCI1M1REMAP         (0x118 >> 2)
-
-/* CPU Error Report */
-#define GT_CPUERR_ADDRLO       (0x070 >> 2)
-#define GT_CPUERR_ADDRHI       (0x078 >> 2)
-#define GT_CPUERR_DATALO       (0x128 >> 2)            /* GT-64120A only  */
-#define GT_CPUERR_DATAHI       (0x130 >> 2)            /* GT-64120A only  */
-#define GT_CPUERR_PARITY       (0x138 >> 2)            /* GT-64120A only  */
-
-/* CPU Sync Barrier */
-#define GT_PCI0SYNC                    (0x0c0 >> 2)
-#define GT_PCI1SYNC                    (0x0c8 >> 2)
-
-/* SDRAM and Device Address Decode */
-#define GT_SCS0LD              (0x400 >> 2)
-#define GT_SCS0HD              (0x404 >> 2)
-#define GT_SCS1LD              (0x408 >> 2)
-#define GT_SCS1HD              (0x40c >> 2)
-#define GT_SCS2LD              (0x410 >> 2)
-#define GT_SCS2HD              (0x414 >> 2)
-#define GT_SCS3LD              (0x418 >> 2)
-#define GT_SCS3HD              (0x41c >> 2)
-#define GT_CS0LD               (0x420 >> 2)
-#define GT_CS0HD               (0x424 >> 2)
-#define GT_CS1LD               (0x428 >> 2)
-#define GT_CS1HD               (0x42c >> 2)
-#define GT_CS2LD               (0x430 >> 2)
-#define GT_CS2HD               (0x434 >> 2)
-#define GT_CS3LD               (0x438 >> 2)
-#define GT_CS3HD               (0x43c >> 2)
-#define GT_BOOTLD              (0x440 >> 2)
-#define GT_BOOTHD              (0x444 >> 2)
-#define GT_ADERR               (0x470 >> 2)
-
-/* SDRAM Configuration */
-#define GT_SDRAM_CFG           (0x448 >> 2)
-#define GT_SDRAM_OPMODE        (0x474 >> 2)
-#define GT_SDRAM_BM                    (0x478 >> 2)
-#define GT_SDRAM_ADDRDECODE            (0x47c >> 2)
-
-/* SDRAM Parameters */
-#define GT_SDRAM_B0                    (0x44c >> 2)
-#define GT_SDRAM_B1                    (0x450 >> 2)
-#define GT_SDRAM_B2                    (0x454 >> 2)
-#define GT_SDRAM_B3                    (0x458 >> 2)
-
-/* Device Parameters */
-#define GT_DEV_B0              (0x45c >> 2)
-#define GT_DEV_B1              (0x460 >> 2)
-#define GT_DEV_B2              (0x464 >> 2)
-#define GT_DEV_B3              (0x468 >> 2)
-#define GT_DEV_BOOT                    (0x46c >> 2)
-
-/* ECC */
-#define GT_ECC_ERRDATALO       (0x480 >> 2)            /* GT-64120A only  */
-#define GT_ECC_ERRDATAHI       (0x484 >> 2)            /* GT-64120A only  */
-#define GT_ECC_MEM             (0x488 >> 2)            /* GT-64120A only  */
-#define GT_ECC_CALC            (0x48c >> 2)            /* GT-64120A only  */
-#define GT_ECC_ERRADDR         (0x490 >> 2)            /* GT-64120A only  */
-
-/* DMA Record */
-#define GT_DMA0_CNT                    (0x800 >> 2)
-#define GT_DMA1_CNT                    (0x804 >> 2)
-#define GT_DMA2_CNT                    (0x808 >> 2)
-#define GT_DMA3_CNT                    (0x80c >> 2)
-#define GT_DMA0_SA             (0x810 >> 2)
-#define GT_DMA1_SA             (0x814 >> 2)
-#define GT_DMA2_SA             (0x818 >> 2)
-#define GT_DMA3_SA             (0x81c >> 2)
-#define GT_DMA0_DA             (0x820 >> 2)
-#define GT_DMA1_DA             (0x824 >> 2)
-#define GT_DMA2_DA             (0x828 >> 2)
-#define GT_DMA3_DA             (0x82c >> 2)
-#define GT_DMA0_NEXT           (0x830 >> 2)
-#define GT_DMA1_NEXT           (0x834 >> 2)
-#define GT_DMA2_NEXT           (0x838 >> 2)
-#define GT_DMA3_NEXT           (0x83c >> 2)
-#define GT_DMA0_CUR                    (0x870 >> 2)
-#define GT_DMA1_CUR                    (0x874 >> 2)
-#define GT_DMA2_CUR                    (0x878 >> 2)
-#define GT_DMA3_CUR                    (0x87c >> 2)
-
-/* DMA Channel Control */
-#define GT_DMA0_CTRL           (0x840 >> 2)
-#define GT_DMA1_CTRL           (0x844 >> 2)
-#define GT_DMA2_CTRL           (0x848 >> 2)
-#define GT_DMA3_CTRL           (0x84c >> 2)
-
-/* DMA Arbiter */
-#define GT_DMA_ARB             (0x860 >> 2)
-
-/* Timer/Counter */
-#define GT_TC0                 (0x850 >> 2)
-#define GT_TC1                 (0x854 >> 2)
-#define GT_TC2                 (0x858 >> 2)
-#define GT_TC3                 (0x85c >> 2)
-#define GT_TC_CONTROL          (0x864 >> 2)
-
-/* PCI Internal */
-#define GT_PCI0_CMD                    (0xc00 >> 2)
-#define GT_PCI0_TOR                    (0xc04 >> 2)
-#define GT_PCI0_BS_SCS10       (0xc08 >> 2)
-#define GT_PCI0_BS_SCS32       (0xc0c >> 2)
-#define GT_PCI0_BS_CS20        (0xc10 >> 2)
-#define GT_PCI0_BS_CS3BT       (0xc14 >> 2)
-#define GT_PCI1_IACK           (0xc30 >> 2)
-#define GT_PCI0_IACK           (0xc34 >> 2)
-#define GT_PCI0_BARE           (0xc3c >> 2)
-#define GT_PCI0_PREFMBR        (0xc40 >> 2)
-#define GT_PCI0_SCS10_BAR      (0xc48 >> 2)
-#define GT_PCI0_SCS32_BAR      (0xc4c >> 2)
-#define GT_PCI0_CS20_BAR       (0xc50 >> 2)
-#define GT_PCI0_CS3BT_BAR      (0xc54 >> 2)
-#define GT_PCI0_SSCS10_BAR     (0xc58 >> 2)
-#define GT_PCI0_SSCS32_BAR     (0xc5c >> 2)
-#define GT_PCI0_SCS3BT_BAR     (0xc64 >> 2)
-#define GT_PCI1_CMD                    (0xc80 >> 2)
-#define GT_PCI1_TOR                    (0xc84 >> 2)
-#define GT_PCI1_BS_SCS10       (0xc88 >> 2)
-#define GT_PCI1_BS_SCS32       (0xc8c >> 2)
-#define GT_PCI1_BS_CS20        (0xc90 >> 2)
-#define GT_PCI1_BS_CS3BT       (0xc94 >> 2)
-#define GT_PCI1_BARE           (0xcbc >> 2)
-#define GT_PCI1_PREFMBR        (0xcc0 >> 2)
-#define GT_PCI1_SCS10_BAR      (0xcc8 >> 2)
-#define GT_PCI1_SCS32_BAR      (0xccc >> 2)
-#define GT_PCI1_CS20_BAR       (0xcd0 >> 2)
-#define GT_PCI1_CS3BT_BAR      (0xcd4 >> 2)
-#define GT_PCI1_SSCS10_BAR     (0xcd8 >> 2)
-#define GT_PCI1_SSCS32_BAR     (0xcdc >> 2)
-#define GT_PCI1_SCS3BT_BAR     (0xce4 >> 2)
-#define GT_PCI1_CFGADDR        (0xcf0 >> 2)
-#define GT_PCI1_CFGDATA        (0xcf4 >> 2)
-#define GT_PCI0_CFGADDR        (0xcf8 >> 2)
-#define GT_PCI0_CFGDATA        (0xcfc >> 2)
-
-/* Interrupts */
-#define GT_INTRCAUSE           (0xc18 >> 2)
-#define GT_INTRMASK                    (0xc1c >> 2)
-#define GT_PCI0_ICMASK         (0xc24 >> 2)
-#define GT_PCI0_SERR0MASK      (0xc28 >> 2)
-#define GT_CPU_INTSEL          (0xc70 >> 2)
-#define GT_PCI0_INTSEL         (0xc74 >> 2)
-#define GT_HINTRCAUSE          (0xc98 >> 2)
-#define GT_HINTRMASK           (0xc9c >> 2)
-#define GT_PCI0_HICMASK        (0xca4 >> 2)
-#define GT_PCI1_SERR1MASK      (0xca8 >> 2)
-
-#define PCI_MAPPING_ENTRY(regname)            \
-    hwaddr regname ##_start;      \
-    hwaddr regname ##_length;     \
-    MemoryRegion regname ##_mem
-
-#define TYPE_GT64120_PCI_HOST_BRIDGE "gt64120"
-
-#define GT64120_PCI_HOST_BRIDGE(obj) \
-    OBJECT_CHECK(GT64120State, (obj), TYPE_GT64120_PCI_HOST_BRIDGE)
-
-typedef struct GT64120State {
-    PCIHostState parent_obj;
-
-    uint32_t regs[GT_REGS];
-    PCI_MAPPING_ENTRY(PCI0IO);
-    PCI_MAPPING_ENTRY(ISD);
-} GT64120State;
-
-/* Adjust range to avoid touching space which isn't mappable via PCI */
-/* XXX: Hardcoded values for Malta: 0x1e000000 - 0x1f100000
-                                    0x1fc00000 - 0x1fd00000  */
-static void check_reserved_space (hwaddr *start,
-                                  hwaddr *length)
-{
-    hwaddr begin = *start;
-    hwaddr end = *start + *length;
-
-    if (end >= 0x1e000000LL && end < 0x1f100000LL)
-        end = 0x1e000000LL;
-    if (begin >= 0x1e000000LL && begin < 0x1f100000LL)
-        begin = 0x1f100000LL;
-    if (end >= 0x1fc00000LL && end < 0x1fd00000LL)
-        end = 0x1fc00000LL;
-    if (begin >= 0x1fc00000LL && begin < 0x1fd00000LL)
-        begin = 0x1fd00000LL;
-    /* XXX: This is broken when a reserved range splits the requested range */
-    if (end >= 0x1f100000LL && begin < 0x1e000000LL)
-        end = 0x1e000000LL;
-    if (end >= 0x1fd00000LL && begin < 0x1fc00000LL)
-        end = 0x1fc00000LL;
-
-    *start = begin;
-    *length = end - begin;
-}
-
-static void gt64120_isd_mapping(GT64120State *s)
-{
-    hwaddr start = s->regs[GT_ISD] << 21;
-    hwaddr length = 0x1000;
-
-    if (s->ISD_length) {
-        memory_region_del_subregion(get_system_memory(), &s->ISD_mem);
-    }
-    check_reserved_space(&start, &length);
-    length = 0x1000;
-    /* Map new address */
-    DPRINTF("ISD: "TARGET_FMT_plx"@"TARGET_FMT_plx
-        " -> "TARGET_FMT_plx"@"TARGET_FMT_plx"\n",
-        s->ISD_length, s->ISD_start, length, start);
-    s->ISD_start = start;
-    s->ISD_length = length;
-    memory_region_add_subregion(get_system_memory(), s->ISD_start, &s->ISD_mem);
-}
-
-static void gt64120_pci_mapping(GT64120State *s)
-{
-    /* Update IO mapping */
-    if ((s->regs[GT_PCI0IOLD] & 0x7f) <= s->regs[GT_PCI0IOHD])
-    {
-      /* Unmap old IO address */
-      if (s->PCI0IO_length)
-      {
-          memory_region_del_subregion(get_system_memory(), &s->PCI0IO_mem);
-          memory_region_destroy(&s->PCI0IO_mem);
-      }
-      /* Map new IO address */
-      s->PCI0IO_start = s->regs[GT_PCI0IOLD] << 21;
-      s->PCI0IO_length = ((s->regs[GT_PCI0IOHD] + 1) - (s->regs[GT_PCI0IOLD] & 0x7f)) << 21;
-      isa_mem_base = s->PCI0IO_start;
-      if (s->PCI0IO_length) {
-          isa_mmio_setup(&s->PCI0IO_mem, s->PCI0IO_length);
-          memory_region_add_subregion(get_system_memory(), s->PCI0IO_start,
-                                      &s->PCI0IO_mem);
-      }
-    }
-}
-
-static void gt64120_writel (void *opaque, hwaddr addr,
-                            uint64_t val, unsigned size)
-{
-    GT64120State *s = opaque;
-    PCIHostState *phb = PCI_HOST_BRIDGE(s);
-    uint32_t saddr;
-
-    if (!(s->regs[GT_CPU] & 0x00001000))
-        val = bswap32(val);
-
-    saddr = (addr & 0xfff) >> 2;
-    switch (saddr) {
-
-    /* CPU Configuration */
-    case GT_CPU:
-        s->regs[GT_CPU] = val;
-        break;
-    case GT_MULTI:
-       /* Read-only register as only one GT64xxx is present on the CPU bus */
-        break;
-
-    /* CPU Address Decode */
-    case GT_PCI0IOLD:
-        s->regs[GT_PCI0IOLD]    = val & 0x00007fff;
-        s->regs[GT_PCI0IOREMAP] = val & 0x000007ff;
-        gt64120_pci_mapping(s);
-        break;
-    case GT_PCI0M0LD:
-        s->regs[GT_PCI0M0LD]    = val & 0x00007fff;
-        s->regs[GT_PCI0M0REMAP] = val & 0x000007ff;
-        break;
-    case GT_PCI0M1LD:
-        s->regs[GT_PCI0M1LD]    = val & 0x00007fff;
-        s->regs[GT_PCI0M1REMAP] = val & 0x000007ff;
-        break;
-    case GT_PCI1IOLD:
-        s->regs[GT_PCI1IOLD]    = val & 0x00007fff;
-        s->regs[GT_PCI1IOREMAP] = val & 0x000007ff;
-        break;
-    case GT_PCI1M0LD:
-        s->regs[GT_PCI1M0LD]    = val & 0x00007fff;
-        s->regs[GT_PCI1M0REMAP] = val & 0x000007ff;
-        break;
-    case GT_PCI1M1LD:
-        s->regs[GT_PCI1M1LD]    = val & 0x00007fff;
-        s->regs[GT_PCI1M1REMAP] = val & 0x000007ff;
-        break;
-    case GT_PCI0IOHD:
-        s->regs[saddr] = val & 0x0000007f;
-        gt64120_pci_mapping(s);
-        break;
-    case GT_PCI0M0HD:
-    case GT_PCI0M1HD:
-    case GT_PCI1IOHD:
-    case GT_PCI1M0HD:
-    case GT_PCI1M1HD:
-        s->regs[saddr] = val & 0x0000007f;
-        break;
-    case GT_ISD:
-        s->regs[saddr] = val & 0x00007fff;
-        gt64120_isd_mapping(s);
-        break;
-
-    case GT_PCI0IOREMAP:
-    case GT_PCI0M0REMAP:
-    case GT_PCI0M1REMAP:
-    case GT_PCI1IOREMAP:
-    case GT_PCI1M0REMAP:
-    case GT_PCI1M1REMAP:
-        s->regs[saddr] = val & 0x000007ff;
-        break;
-
-    /* CPU Error Report */
-    case GT_CPUERR_ADDRLO:
-    case GT_CPUERR_ADDRHI:
-    case GT_CPUERR_DATALO:
-    case GT_CPUERR_DATAHI:
-    case GT_CPUERR_PARITY:
-       /* Read-only registers, do nothing */
-        break;
-
-    /* CPU Sync Barrier */
-    case GT_PCI0SYNC:
-    case GT_PCI1SYNC:
-       /* Read-only registers, do nothing */
-        break;
-
-    /* SDRAM and Device Address Decode */
-    case GT_SCS0LD:
-    case GT_SCS0HD:
-    case GT_SCS1LD:
-    case GT_SCS1HD:
-    case GT_SCS2LD:
-    case GT_SCS2HD:
-    case GT_SCS3LD:
-    case GT_SCS3HD:
-    case GT_CS0LD:
-    case GT_CS0HD:
-    case GT_CS1LD:
-    case GT_CS1HD:
-    case GT_CS2LD:
-    case GT_CS2HD:
-    case GT_CS3LD:
-    case GT_CS3HD:
-    case GT_BOOTLD:
-    case GT_BOOTHD:
-    case GT_ADERR:
-    /* SDRAM Configuration */
-    case GT_SDRAM_CFG:
-    case GT_SDRAM_OPMODE:
-    case GT_SDRAM_BM:
-    case GT_SDRAM_ADDRDECODE:
-        /* Accept and ignore SDRAM interleave configuration */
-        s->regs[saddr] = val;
-        break;
-
-    /* Device Parameters */
-    case GT_DEV_B0:
-    case GT_DEV_B1:
-    case GT_DEV_B2:
-    case GT_DEV_B3:
-    case GT_DEV_BOOT:
-        /* Not implemented */
-        DPRINTF ("Unimplemented device register offset 0x%x\n", saddr << 2);
-        break;
-
-    /* ECC */
-    case GT_ECC_ERRDATALO:
-    case GT_ECC_ERRDATAHI:
-    case GT_ECC_MEM:
-    case GT_ECC_CALC:
-    case GT_ECC_ERRADDR:
-        /* Read-only registers, do nothing */
-        break;
-
-    /* DMA Record */
-    case GT_DMA0_CNT:
-    case GT_DMA1_CNT:
-    case GT_DMA2_CNT:
-    case GT_DMA3_CNT:
-    case GT_DMA0_SA:
-    case GT_DMA1_SA:
-    case GT_DMA2_SA:
-    case GT_DMA3_SA:
-    case GT_DMA0_DA:
-    case GT_DMA1_DA:
-    case GT_DMA2_DA:
-    case GT_DMA3_DA:
-    case GT_DMA0_NEXT:
-    case GT_DMA1_NEXT:
-    case GT_DMA2_NEXT:
-    case GT_DMA3_NEXT:
-    case GT_DMA0_CUR:
-    case GT_DMA1_CUR:
-    case GT_DMA2_CUR:
-    case GT_DMA3_CUR:
-        /* Not implemented */
-        DPRINTF ("Unimplemented DMA register offset 0x%x\n", saddr << 2);
-        break;
-
-    /* DMA Channel Control */
-    case GT_DMA0_CTRL:
-    case GT_DMA1_CTRL:
-    case GT_DMA2_CTRL:
-    case GT_DMA3_CTRL:
-        /* Not implemented */
-        DPRINTF ("Unimplemented DMA register offset 0x%x\n", saddr << 2);
-        break;
-
-    /* DMA Arbiter */
-    case GT_DMA_ARB:
-        /* Not implemented */
-        DPRINTF ("Unimplemented DMA register offset 0x%x\n", saddr << 2);
-        break;
-
-    /* Timer/Counter */
-    case GT_TC0:
-    case GT_TC1:
-    case GT_TC2:
-    case GT_TC3:
-    case GT_TC_CONTROL:
-        /* Not implemented */
-        DPRINTF ("Unimplemented timer register offset 0x%x\n", saddr << 2);
-        break;
-
-    /* PCI Internal */
-    case GT_PCI0_CMD:
-    case GT_PCI1_CMD:
-        s->regs[saddr] = val & 0x0401fc0f;
-        break;
-    case GT_PCI0_TOR:
-    case GT_PCI0_BS_SCS10:
-    case GT_PCI0_BS_SCS32:
-    case GT_PCI0_BS_CS20:
-    case GT_PCI0_BS_CS3BT:
-    case GT_PCI1_IACK:
-    case GT_PCI0_IACK:
-    case GT_PCI0_BARE:
-    case GT_PCI0_PREFMBR:
-    case GT_PCI0_SCS10_BAR:
-    case GT_PCI0_SCS32_BAR:
-    case GT_PCI0_CS20_BAR:
-    case GT_PCI0_CS3BT_BAR:
-    case GT_PCI0_SSCS10_BAR:
-    case GT_PCI0_SSCS32_BAR:
-    case GT_PCI0_SCS3BT_BAR:
-    case GT_PCI1_TOR:
-    case GT_PCI1_BS_SCS10:
-    case GT_PCI1_BS_SCS32:
-    case GT_PCI1_BS_CS20:
-    case GT_PCI1_BS_CS3BT:
-    case GT_PCI1_BARE:
-    case GT_PCI1_PREFMBR:
-    case GT_PCI1_SCS10_BAR:
-    case GT_PCI1_SCS32_BAR:
-    case GT_PCI1_CS20_BAR:
-    case GT_PCI1_CS3BT_BAR:
-    case GT_PCI1_SSCS10_BAR:
-    case GT_PCI1_SSCS32_BAR:
-    case GT_PCI1_SCS3BT_BAR:
-    case GT_PCI1_CFGADDR:
-    case GT_PCI1_CFGDATA:
-        /* not implemented */
-        break;
-    case GT_PCI0_CFGADDR:
-        phb->config_reg = val & 0x80fffffc;
-        break;
-    case GT_PCI0_CFGDATA:
-        if (!(s->regs[GT_PCI0_CMD] & 1) && (phb->config_reg & 0x00fff800)) {
-            val = bswap32(val);
-        }
-        if (phb->config_reg & (1u << 31)) {
-            pci_data_write(phb->bus, phb->config_reg, val, 4);
-        }
-        break;
-
-    /* Interrupts */
-    case GT_INTRCAUSE:
-        /* not really implemented */
-        s->regs[saddr] = ~(~(s->regs[saddr]) | ~(val & 0xfffffffe));
-        s->regs[saddr] |= !!(s->regs[saddr] & 0xfffffffe);
-        DPRINTF("INTRCAUSE %" PRIx64 "\n", val);
-        break;
-    case GT_INTRMASK:
-        s->regs[saddr] = val & 0x3c3ffffe;
-        DPRINTF("INTRMASK %" PRIx64 "\n", val);
-        break;
-    case GT_PCI0_ICMASK:
-        s->regs[saddr] = val & 0x03fffffe;
-        DPRINTF("ICMASK %" PRIx64 "\n", val);
-        break;
-    case GT_PCI0_SERR0MASK:
-        s->regs[saddr] = val & 0x0000003f;
-        DPRINTF("SERR0MASK %" PRIx64 "\n", val);
-        break;
-
-    /* Reserved when only PCI_0 is configured. */
-    case GT_HINTRCAUSE:
-    case GT_CPU_INTSEL:
-    case GT_PCI0_INTSEL:
-    case GT_HINTRMASK:
-    case GT_PCI0_HICMASK:
-    case GT_PCI1_SERR1MASK:
-        /* not implemented */
-        break;
-
-    /* SDRAM Parameters */
-    case GT_SDRAM_B0:
-    case GT_SDRAM_B1:
-    case GT_SDRAM_B2:
-    case GT_SDRAM_B3:
-        /* We don't simulate electrical parameters of the SDRAM.
-           Accept, but ignore the values. */
-        s->regs[saddr] = val;
-        break;
-
-    default:
-        DPRINTF ("Bad register offset 0x%x\n", (int)addr);
-        break;
-    }
-}
-
-static uint64_t gt64120_readl (void *opaque,
-                               hwaddr addr, unsigned size)
-{
-    GT64120State *s = opaque;
-    PCIHostState *phb = PCI_HOST_BRIDGE(s);
-    uint32_t val;
-    uint32_t saddr;
-
-    saddr = (addr & 0xfff) >> 2;
-    switch (saddr) {
-
-    /* CPU Configuration */
-    case GT_MULTI:
-        /* Only one GT64xxx is present on the CPU bus, return
-           the initial value */
-        val = s->regs[saddr];
-        break;
-
-    /* CPU Error Report */
-    case GT_CPUERR_ADDRLO:
-    case GT_CPUERR_ADDRHI:
-    case GT_CPUERR_DATALO:
-    case GT_CPUERR_DATAHI:
-    case GT_CPUERR_PARITY:
-        /* Emulated memory has no error, always return the initial
-           values */
-        val = s->regs[saddr];
-        break;
-
-    /* CPU Sync Barrier */
-    case GT_PCI0SYNC:
-    case GT_PCI1SYNC:
-        /* Reading those register should empty all FIFO on the PCI
-           bus, which are not emulated. The return value should be
-           a random value that should be ignored. */
-        val = 0xc000ffee;
-        break;
-
-    /* ECC */
-    case GT_ECC_ERRDATALO:
-    case GT_ECC_ERRDATAHI:
-    case GT_ECC_MEM:
-    case GT_ECC_CALC:
-    case GT_ECC_ERRADDR:
-        /* Emulated memory has no error, always return the initial
-           values */
-        val = s->regs[saddr];
-        break;
-
-    case GT_CPU:
-    case GT_SCS10LD:
-    case GT_SCS10HD:
-    case GT_SCS32LD:
-    case GT_SCS32HD:
-    case GT_CS20LD:
-    case GT_CS20HD:
-    case GT_CS3BOOTLD:
-    case GT_CS3BOOTHD:
-    case GT_SCS10AR:
-    case GT_SCS32AR:
-    case GT_CS20R:
-    case GT_CS3BOOTR:
-    case GT_PCI0IOLD:
-    case GT_PCI0M0LD:
-    case GT_PCI0M1LD:
-    case GT_PCI1IOLD:
-    case GT_PCI1M0LD:
-    case GT_PCI1M1LD:
-    case GT_PCI0IOHD:
-    case GT_PCI0M0HD:
-    case GT_PCI0M1HD:
-    case GT_PCI1IOHD:
-    case GT_PCI1M0HD:
-    case GT_PCI1M1HD:
-    case GT_PCI0IOREMAP:
-    case GT_PCI0M0REMAP:
-    case GT_PCI0M1REMAP:
-    case GT_PCI1IOREMAP:
-    case GT_PCI1M0REMAP:
-    case GT_PCI1M1REMAP:
-    case GT_ISD:
-        val = s->regs[saddr];
-        break;
-    case GT_PCI0_IACK:
-        /* Read the IRQ number */
-        val = pic_read_irq(isa_pic);
-        break;
-
-    /* SDRAM and Device Address Decode */
-    case GT_SCS0LD:
-    case GT_SCS0HD:
-    case GT_SCS1LD:
-    case GT_SCS1HD:
-    case GT_SCS2LD:
-    case GT_SCS2HD:
-    case GT_SCS3LD:
-    case GT_SCS3HD:
-    case GT_CS0LD:
-    case GT_CS0HD:
-    case GT_CS1LD:
-    case GT_CS1HD:
-    case GT_CS2LD:
-    case GT_CS2HD:
-    case GT_CS3LD:
-    case GT_CS3HD:
-    case GT_BOOTLD:
-    case GT_BOOTHD:
-    case GT_ADERR:
-        val = s->regs[saddr];
-        break;
-
-    /* SDRAM Configuration */
-    case GT_SDRAM_CFG:
-    case GT_SDRAM_OPMODE:
-    case GT_SDRAM_BM:
-    case GT_SDRAM_ADDRDECODE:
-        val = s->regs[saddr];
-        break;
-
-    /* SDRAM Parameters */
-    case GT_SDRAM_B0:
-    case GT_SDRAM_B1:
-    case GT_SDRAM_B2:
-    case GT_SDRAM_B3:
-        /* We don't simulate electrical parameters of the SDRAM.
-           Just return the last written value. */
-        val = s->regs[saddr];
-        break;
-
-    /* Device Parameters */
-    case GT_DEV_B0:
-    case GT_DEV_B1:
-    case GT_DEV_B2:
-    case GT_DEV_B3:
-    case GT_DEV_BOOT:
-        val = s->regs[saddr];
-        break;
-
-    /* DMA Record */
-    case GT_DMA0_CNT:
-    case GT_DMA1_CNT:
-    case GT_DMA2_CNT:
-    case GT_DMA3_CNT:
-    case GT_DMA0_SA:
-    case GT_DMA1_SA:
-    case GT_DMA2_SA:
-    case GT_DMA3_SA:
-    case GT_DMA0_DA:
-    case GT_DMA1_DA:
-    case GT_DMA2_DA:
-    case GT_DMA3_DA:
-    case GT_DMA0_NEXT:
-    case GT_DMA1_NEXT:
-    case GT_DMA2_NEXT:
-    case GT_DMA3_NEXT:
-    case GT_DMA0_CUR:
-    case GT_DMA1_CUR:
-    case GT_DMA2_CUR:
-    case GT_DMA3_CUR:
-        val = s->regs[saddr];
-        break;
-
-    /* DMA Channel Control */
-    case GT_DMA0_CTRL:
-    case GT_DMA1_CTRL:
-    case GT_DMA2_CTRL:
-    case GT_DMA3_CTRL:
-        val = s->regs[saddr];
-        break;
-
-    /* DMA Arbiter */
-    case GT_DMA_ARB:
-        val = s->regs[saddr];
-        break;
-
-    /* Timer/Counter */
-    case GT_TC0:
-    case GT_TC1:
-    case GT_TC2:
-    case GT_TC3:
-    case GT_TC_CONTROL:
-        val = s->regs[saddr];
-        break;
-
-    /* PCI Internal */
-    case GT_PCI0_CFGADDR:
-        val = phb->config_reg;
-        break;
-    case GT_PCI0_CFGDATA:
-        if (!(phb->config_reg & (1 << 31))) {
-            val = 0xffffffff;
-        } else {
-            val = pci_data_read(phb->bus, phb->config_reg, 4);
-        }
-        if (!(s->regs[GT_PCI0_CMD] & 1) && (phb->config_reg & 0x00fff800)) {
-            val = bswap32(val);
-        }
-        break;
-
-    case GT_PCI0_CMD:
-    case GT_PCI0_TOR:
-    case GT_PCI0_BS_SCS10:
-    case GT_PCI0_BS_SCS32:
-    case GT_PCI0_BS_CS20:
-    case GT_PCI0_BS_CS3BT:
-    case GT_PCI1_IACK:
-    case GT_PCI0_BARE:
-    case GT_PCI0_PREFMBR:
-    case GT_PCI0_SCS10_BAR:
-    case GT_PCI0_SCS32_BAR:
-    case GT_PCI0_CS20_BAR:
-    case GT_PCI0_CS3BT_BAR:
-    case GT_PCI0_SSCS10_BAR:
-    case GT_PCI0_SSCS32_BAR:
-    case GT_PCI0_SCS3BT_BAR:
-    case GT_PCI1_CMD:
-    case GT_PCI1_TOR:
-    case GT_PCI1_BS_SCS10:
-    case GT_PCI1_BS_SCS32:
-    case GT_PCI1_BS_CS20:
-    case GT_PCI1_BS_CS3BT:
-    case GT_PCI1_BARE:
-    case GT_PCI1_PREFMBR:
-    case GT_PCI1_SCS10_BAR:
-    case GT_PCI1_SCS32_BAR:
-    case GT_PCI1_CS20_BAR:
-    case GT_PCI1_CS3BT_BAR:
-    case GT_PCI1_SSCS10_BAR:
-    case GT_PCI1_SSCS32_BAR:
-    case GT_PCI1_SCS3BT_BAR:
-    case GT_PCI1_CFGADDR:
-    case GT_PCI1_CFGDATA:
-        val = s->regs[saddr];
-        break;
-
-    /* Interrupts */
-    case GT_INTRCAUSE:
-        val = s->regs[saddr];
-        DPRINTF("INTRCAUSE %x\n", val);
-        break;
-    case GT_INTRMASK:
-        val = s->regs[saddr];
-        DPRINTF("INTRMASK %x\n", val);
-        break;
-    case GT_PCI0_ICMASK:
-        val = s->regs[saddr];
-        DPRINTF("ICMASK %x\n", val);
-        break;
-    case GT_PCI0_SERR0MASK:
-        val = s->regs[saddr];
-        DPRINTF("SERR0MASK %x\n", val);
-        break;
-
-    /* Reserved when only PCI_0 is configured. */
-    case GT_HINTRCAUSE:
-    case GT_CPU_INTSEL:
-    case GT_PCI0_INTSEL:
-    case GT_HINTRMASK:
-    case GT_PCI0_HICMASK:
-    case GT_PCI1_SERR1MASK:
-        val = s->regs[saddr];
-        break;
-
-    default:
-        val = s->regs[saddr];
-        DPRINTF ("Bad register offset 0x%x\n", (int)addr);
-        break;
-    }
-
-    if (!(s->regs[GT_CPU] & 0x00001000))
-        val = bswap32(val);
-
-    return val;
-}
-
-static const MemoryRegionOps isd_mem_ops = {
-    .read = gt64120_readl,
-    .write = gt64120_writel,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int gt64120_pci_map_irq(PCIDevice *pci_dev, int irq_num)
-{
-    int slot;
-
-    slot = (pci_dev->devfn >> 3);
-
-    switch (slot) {
-      /* PIIX4 USB */
-      case 10:
-        return 3;
-      /* AMD 79C973 Ethernet */
-      case 11:
-        return 1;
-      /* Crystal 4281 Sound */
-      case 12:
-        return 2;
-      /* PCI slot 1 to 4 */
-      case 18 ... 21:
-        return ((slot - 18) + irq_num) & 0x03;
-      /* Unknown device, don't do any translation */
-      default:
-        return irq_num;
-    }
-}
-
-static int pci_irq_levels[4];
-
-static void gt64120_pci_set_irq(void *opaque, int irq_num, int level)
-{
-    int i, pic_irq, pic_level;
-    qemu_irq *pic = opaque;
-
-    pci_irq_levels[irq_num] = level;
-
-    /* now we change the pic irq level according to the piix irq mappings */
-    /* XXX: optimize */
-    pic_irq = piix4_dev->config[0x60 + irq_num];
-    if (pic_irq < 16) {
-        /* The pic level is the logical OR of all the PCI irqs mapped
-           to it */
-        pic_level = 0;
-        for (i = 0; i < 4; i++) {
-            if (pic_irq == piix4_dev->config[0x60 + i])
-                pic_level |= pci_irq_levels[i];
-        }
-        qemu_set_irq(pic[pic_irq], pic_level);
-    }
-}
-
-
-static void gt64120_reset(void *opaque)
-{
-    GT64120State *s = opaque;
-
-    /* FIXME: Malta specific hw assumptions ahead */
-
-    /* CPU Configuration */
-#ifdef TARGET_WORDS_BIGENDIAN
-    s->regs[GT_CPU]           = 0x00000000;
-#else
-    s->regs[GT_CPU]           = 0x00001000;
-#endif
-    s->regs[GT_MULTI]         = 0x00000003;
-
-    /* CPU Address decode */
-    s->regs[GT_SCS10LD]       = 0x00000000;
-    s->regs[GT_SCS10HD]       = 0x00000007;
-    s->regs[GT_SCS32LD]       = 0x00000008;
-    s->regs[GT_SCS32HD]       = 0x0000000f;
-    s->regs[GT_CS20LD]        = 0x000000e0;
-    s->regs[GT_CS20HD]        = 0x00000070;
-    s->regs[GT_CS3BOOTLD]     = 0x000000f8;
-    s->regs[GT_CS3BOOTHD]     = 0x0000007f;
-
-    s->regs[GT_PCI0IOLD]      = 0x00000080;
-    s->regs[GT_PCI0IOHD]      = 0x0000000f;
-    s->regs[GT_PCI0M0LD]      = 0x00000090;
-    s->regs[GT_PCI0M0HD]      = 0x0000001f;
-    s->regs[GT_ISD]           = 0x000000a0;
-    s->regs[GT_PCI0M1LD]      = 0x00000790;
-    s->regs[GT_PCI0M1HD]      = 0x0000001f;
-    s->regs[GT_PCI1IOLD]      = 0x00000100;
-    s->regs[GT_PCI1IOHD]      = 0x0000000f;
-    s->regs[GT_PCI1M0LD]      = 0x00000110;
-    s->regs[GT_PCI1M0HD]      = 0x0000001f;
-    s->regs[GT_PCI1M1LD]      = 0x00000120;
-    s->regs[GT_PCI1M1HD]      = 0x0000002f;
-
-    s->regs[GT_SCS10AR]       = 0x00000000;
-    s->regs[GT_SCS32AR]       = 0x00000008;
-    s->regs[GT_CS20R]         = 0x000000e0;
-    s->regs[GT_CS3BOOTR]      = 0x000000f8;
-
-    s->regs[GT_PCI0IOREMAP]   = 0x00000080;
-    s->regs[GT_PCI0M0REMAP]   = 0x00000090;
-    s->regs[GT_PCI0M1REMAP]   = 0x00000790;
-    s->regs[GT_PCI1IOREMAP]   = 0x00000100;
-    s->regs[GT_PCI1M0REMAP]   = 0x00000110;
-    s->regs[GT_PCI1M1REMAP]   = 0x00000120;
-
-    /* CPU Error Report */
-    s->regs[GT_CPUERR_ADDRLO] = 0x00000000;
-    s->regs[GT_CPUERR_ADDRHI] = 0x00000000;
-    s->regs[GT_CPUERR_DATALO] = 0xffffffff;
-    s->regs[GT_CPUERR_DATAHI] = 0xffffffff;
-    s->regs[GT_CPUERR_PARITY] = 0x000000ff;
-
-    /* CPU Sync Barrier */
-    s->regs[GT_PCI0SYNC]      = 0x00000000;
-    s->regs[GT_PCI1SYNC]      = 0x00000000;
-
-    /* SDRAM and Device Address Decode */
-    s->regs[GT_SCS0LD]        = 0x00000000;
-    s->regs[GT_SCS0HD]        = 0x00000007;
-    s->regs[GT_SCS1LD]        = 0x00000008;
-    s->regs[GT_SCS1HD]        = 0x0000000f;
-    s->regs[GT_SCS2LD]        = 0x00000010;
-    s->regs[GT_SCS2HD]        = 0x00000017;
-    s->regs[GT_SCS3LD]        = 0x00000018;
-    s->regs[GT_SCS3HD]        = 0x0000001f;
-    s->regs[GT_CS0LD]         = 0x000000c0;
-    s->regs[GT_CS0HD]         = 0x000000c7;
-    s->regs[GT_CS1LD]         = 0x000000c8;
-    s->regs[GT_CS1HD]         = 0x000000cf;
-    s->regs[GT_CS2LD]         = 0x000000d0;
-    s->regs[GT_CS2HD]         = 0x000000df;
-    s->regs[GT_CS3LD]         = 0x000000f0;
-    s->regs[GT_CS3HD]         = 0x000000fb;
-    s->regs[GT_BOOTLD]        = 0x000000fc;
-    s->regs[GT_BOOTHD]        = 0x000000ff;
-    s->regs[GT_ADERR]         = 0xffffffff;
-
-    /* SDRAM Configuration */
-    s->regs[GT_SDRAM_CFG]     = 0x00000200;
-    s->regs[GT_SDRAM_OPMODE]  = 0x00000000;
-    s->regs[GT_SDRAM_BM]      = 0x00000007;
-    s->regs[GT_SDRAM_ADDRDECODE] = 0x00000002;
-
-    /* SDRAM Parameters */
-    s->regs[GT_SDRAM_B0]      = 0x00000005;
-    s->regs[GT_SDRAM_B1]      = 0x00000005;
-    s->regs[GT_SDRAM_B2]      = 0x00000005;
-    s->regs[GT_SDRAM_B3]      = 0x00000005;
-
-    /* ECC */
-    s->regs[GT_ECC_ERRDATALO] = 0x00000000;
-    s->regs[GT_ECC_ERRDATAHI] = 0x00000000;
-    s->regs[GT_ECC_MEM]       = 0x00000000;
-    s->regs[GT_ECC_CALC]      = 0x00000000;
-    s->regs[GT_ECC_ERRADDR]   = 0x00000000;
-
-    /* Device Parameters */
-    s->regs[GT_DEV_B0]        = 0x386fffff;
-    s->regs[GT_DEV_B1]        = 0x386fffff;
-    s->regs[GT_DEV_B2]        = 0x386fffff;
-    s->regs[GT_DEV_B3]        = 0x386fffff;
-    s->regs[GT_DEV_BOOT]      = 0x146fffff;
-
-    /* DMA registers are all zeroed at reset */
-
-    /* Timer/Counter */
-    s->regs[GT_TC0]           = 0xffffffff;
-    s->regs[GT_TC1]           = 0x00ffffff;
-    s->regs[GT_TC2]           = 0x00ffffff;
-    s->regs[GT_TC3]           = 0x00ffffff;
-    s->regs[GT_TC_CONTROL]    = 0x00000000;
-
-    /* PCI Internal */
-#ifdef TARGET_WORDS_BIGENDIAN
-    s->regs[GT_PCI0_CMD]      = 0x00000000;
-#else
-    s->regs[GT_PCI0_CMD]      = 0x00010001;
-#endif
-    s->regs[GT_PCI0_TOR]      = 0x0000070f;
-    s->regs[GT_PCI0_BS_SCS10] = 0x00fff000;
-    s->regs[GT_PCI0_BS_SCS32] = 0x00fff000;
-    s->regs[GT_PCI0_BS_CS20]  = 0x01fff000;
-    s->regs[GT_PCI0_BS_CS3BT] = 0x00fff000;
-    s->regs[GT_PCI1_IACK]     = 0x00000000;
-    s->regs[GT_PCI0_IACK]     = 0x00000000;
-    s->regs[GT_PCI0_BARE]     = 0x0000000f;
-    s->regs[GT_PCI0_PREFMBR]  = 0x00000040;
-    s->regs[GT_PCI0_SCS10_BAR] = 0x00000000;
-    s->regs[GT_PCI0_SCS32_BAR] = 0x01000000;
-    s->regs[GT_PCI0_CS20_BAR] = 0x1c000000;
-    s->regs[GT_PCI0_CS3BT_BAR] = 0x1f000000;
-    s->regs[GT_PCI0_SSCS10_BAR] = 0x00000000;
-    s->regs[GT_PCI0_SSCS32_BAR] = 0x01000000;
-    s->regs[GT_PCI0_SCS3BT_BAR] = 0x1f000000;
-#ifdef TARGET_WORDS_BIGENDIAN
-    s->regs[GT_PCI1_CMD]      = 0x00000000;
-#else
-    s->regs[GT_PCI1_CMD]      = 0x00010001;
-#endif
-    s->regs[GT_PCI1_TOR]      = 0x0000070f;
-    s->regs[GT_PCI1_BS_SCS10] = 0x00fff000;
-    s->regs[GT_PCI1_BS_SCS32] = 0x00fff000;
-    s->regs[GT_PCI1_BS_CS20]  = 0x01fff000;
-    s->regs[GT_PCI1_BS_CS3BT] = 0x00fff000;
-    s->regs[GT_PCI1_BARE]     = 0x0000000f;
-    s->regs[GT_PCI1_PREFMBR]  = 0x00000040;
-    s->regs[GT_PCI1_SCS10_BAR] = 0x00000000;
-    s->regs[GT_PCI1_SCS32_BAR] = 0x01000000;
-    s->regs[GT_PCI1_CS20_BAR] = 0x1c000000;
-    s->regs[GT_PCI1_CS3BT_BAR] = 0x1f000000;
-    s->regs[GT_PCI1_SSCS10_BAR] = 0x00000000;
-    s->regs[GT_PCI1_SSCS32_BAR] = 0x01000000;
-    s->regs[GT_PCI1_SCS3BT_BAR] = 0x1f000000;
-    s->regs[GT_PCI1_CFGADDR]  = 0x00000000;
-    s->regs[GT_PCI1_CFGDATA]  = 0x00000000;
-    s->regs[GT_PCI0_CFGADDR]  = 0x00000000;
-
-    /* Interrupt registers are all zeroed at reset */
-
-    gt64120_isd_mapping(s);
-    gt64120_pci_mapping(s);
-}
-
-PCIBus *gt64120_register(qemu_irq *pic)
-{
-    GT64120State *d;
-    PCIHostState *phb;
-    DeviceState *dev;
-
-    dev = qdev_create(NULL, TYPE_GT64120_PCI_HOST_BRIDGE);
-    qdev_init_nofail(dev);
-    d = GT64120_PCI_HOST_BRIDGE(dev);
-    phb = PCI_HOST_BRIDGE(dev);
-    phb->bus = pci_register_bus(dev, "pci",
-                                gt64120_pci_set_irq, gt64120_pci_map_irq,
-                                pic,
-                                get_system_memory(),
-                                get_system_io(),
-                                PCI_DEVFN(18, 0), 4, TYPE_PCI_BUS);
-    memory_region_init_io(&d->ISD_mem, &isd_mem_ops, d, "isd-mem", 0x1000);
-
-    pci_create_simple(phb->bus, PCI_DEVFN(0, 0), "gt64120_pci");
-    return phb->bus;
-}
-
-static int gt64120_init(SysBusDevice *dev)
-{
-    GT64120State *s;
-
-    s = GT64120_PCI_HOST_BRIDGE(dev);
-
-    /* FIXME: This value is computed from registers during reset, but some
-       devices (e.g. VGA card) need to know it when they are registered.
-       This also mean that changing the register to change the mapping
-       does not fully work. */
-    isa_mem_base = 0x10000000;
-    qemu_register_reset(gt64120_reset, s);
-    return 0;
-}
-
-static int gt64120_pci_init(PCIDevice *d)
-{
-    /* FIXME: Malta specific hw assumptions ahead */
-    pci_set_word(d->config + PCI_COMMAND, 0);
-    pci_set_word(d->config + PCI_STATUS,
-                 PCI_STATUS_FAST_BACK | PCI_STATUS_DEVSEL_MEDIUM);
-    pci_config_set_prog_interface(d->config, 0);
-    pci_set_long(d->config + PCI_BASE_ADDRESS_0, 0x00000008);
-    pci_set_long(d->config + PCI_BASE_ADDRESS_1, 0x01000008);
-    pci_set_long(d->config + PCI_BASE_ADDRESS_2, 0x1c000000);
-    pci_set_long(d->config + PCI_BASE_ADDRESS_3, 0x1f000000);
-    pci_set_long(d->config + PCI_BASE_ADDRESS_4, 0x14000000);
-    pci_set_long(d->config + PCI_BASE_ADDRESS_5, 0x14000001);
-    pci_set_byte(d->config + 0x3d, 0x01);
-
-    return 0;
-}
-
-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 const TypeInfo gt64120_pci_info = {
-    .name          = "gt64120_pci",
-    .parent        = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(PCIDevice),
-    .class_init    = gt64120_pci_class_init,
-};
-
-static void gt64120_class_init(ObjectClass *klass, void *data)
-{
-    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
-
-    sdc->init = gt64120_init;
-}
-
-static const TypeInfo gt64120_info = {
-    .name          = TYPE_GT64120_PCI_HOST_BRIDGE,
-    .parent        = TYPE_PCI_HOST_BRIDGE,
-    .instance_size = sizeof(GT64120State),
-    .class_init    = gt64120_class_init,
-};
-
-static void gt64120_pci_register_types(void)
-{
-    type_register_static(&gt64120_info);
-    type_register_static(&gt64120_pci_info);
-}
-
-type_init(gt64120_pci_register_types)
diff --git a/hw/gus.c b/hw/gus.c
deleted file mode 100644 (file)
index d268224..0000000
--- a/hw/gus.c
+++ /dev/null
@@ -1,332 +0,0 @@
-/*
- * QEMU Proxy for Gravis Ultrasound GF1 emulation by Tibor "TS" Schütz
- *
- * Copyright (c) 2002-2005 Vassili Karpov (malc)
- *
- * 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 "hw/hw.h"
-#include "hw/audiodev.h"
-#include "audio/audio.h"
-#include "hw/isa.h"
-#include "hw/gusemu.h"
-#include "hw/gustate.h"
-
-#define dolog(...) AUD_log ("audio", __VA_ARGS__)
-#ifdef DEBUG
-#define ldebug(...) dolog (__VA_ARGS__)
-#else
-#define ldebug(...)
-#endif
-
-#ifdef HOST_WORDS_BIGENDIAN
-#define GUS_ENDIANNESS 1
-#else
-#define GUS_ENDIANNESS 0
-#endif
-
-#define IO_READ_PROTO(name) \
-    static uint32_t name (void *opaque, uint32_t nport)
-#define IO_WRITE_PROTO(name) \
-    static void name (void *opaque, uint32_t nport, uint32_t val)
-
-typedef struct GUSState {
-    ISADevice dev;
-    GUSEmuState emu;
-    QEMUSoundCard card;
-    uint32_t freq;
-    uint32_t port;
-    int pos, left, shift, irqs;
-    GUSsample *mixbuf;
-    uint8_t himem[1024 * 1024 + 32 + 4096];
-    int samples;
-    SWVoiceOut *voice;
-    int64_t last_ticks;
-    qemu_irq pic;
-} GUSState;
-
-IO_READ_PROTO (gus_readb)
-{
-    GUSState *s = opaque;
-
-    return gus_read (&s->emu, nport, 1);
-}
-
-IO_READ_PROTO (gus_readw)
-{
-    GUSState *s = opaque;
-
-    return gus_read (&s->emu, nport, 2);
-}
-
-IO_WRITE_PROTO (gus_writeb)
-{
-    GUSState *s = opaque;
-
-    gus_write (&s->emu, nport, 1, val);
-}
-
-IO_WRITE_PROTO (gus_writew)
-{
-    GUSState *s = opaque;
-
-    gus_write (&s->emu, nport, 2, val);
-}
-
-static int write_audio (GUSState *s, int samples)
-{
-    int net = 0;
-    int pos = s->pos;
-
-    while (samples) {
-        int nbytes, wbytes, wsampl;
-
-        nbytes = samples << s->shift;
-        wbytes = AUD_write (
-            s->voice,
-            s->mixbuf + (pos << (s->shift - 1)),
-            nbytes
-            );
-
-        if (wbytes) {
-            wsampl = wbytes >> s->shift;
-
-            samples -= wsampl;
-            pos = (pos + wsampl) % s->samples;
-
-            net += wsampl;
-        }
-        else {
-            break;
-        }
-    }
-
-    return net;
-}
-
-static void GUS_callback (void *opaque, int free)
-{
-    int samples, to_play, net = 0;
-    GUSState *s = opaque;
-
-    samples = free >> s->shift;
-    to_play = audio_MIN (samples, s->left);
-
-    while (to_play) {
-        int written = write_audio (s, to_play);
-
-        if (!written) {
-            goto reset;
-        }
-
-        s->left -= written;
-        to_play -= written;
-        samples -= written;
-        net += written;
-    }
-
-    samples = audio_MIN (samples, s->samples);
-    if (samples) {
-        gus_mixvoices (&s->emu, s->freq, samples, s->mixbuf);
-
-        while (samples) {
-            int written = write_audio (s, samples);
-            if (!written) {
-                break;
-            }
-            samples -= written;
-            net += written;
-        }
-    }
-    s->left = samples;
-
- reset:
-    gus_irqgen (&s->emu, muldiv64 (net, 1000000, s->freq));
-}
-
-int GUS_irqrequest (GUSEmuState *emu, int hwirq, int n)
-{
-    GUSState *s = emu->opaque;
-    /* qemu_irq_lower (s->pic); */
-    qemu_irq_raise (s->pic);
-    s->irqs += n;
-    ldebug ("irqrequest %d %d %d\n", hwirq, n, s->irqs);
-    return n;
-}
-
-void GUS_irqclear (GUSEmuState *emu, int hwirq)
-{
-    GUSState *s = emu->opaque;
-    ldebug ("irqclear %d %d\n", hwirq, s->irqs);
-    qemu_irq_lower (s->pic);
-    s->irqs -= 1;
-#ifdef IRQ_STORM
-    if (s->irqs > 0) {
-        qemu_irq_raise (s->pic[hwirq]);
-    }
-#endif
-}
-
-void GUS_dmarequest (GUSEmuState *der)
-{
-    /* GUSState *s = (GUSState *) der; */
-    ldebug ("dma request %d\n", der->gusdma);
-    DMA_hold_DREQ (der->gusdma);
-}
-
-static int GUS_read_DMA (void *opaque, int nchan, int dma_pos, int dma_len)
-{
-    GUSState *s = opaque;
-    char tmpbuf[4096];
-    int pos = dma_pos, mode, left = dma_len - dma_pos;
-
-    ldebug ("read DMA %#x %d\n", dma_pos, dma_len);
-    mode = DMA_get_channel_mode (s->emu.gusdma);
-    while (left) {
-        int to_copy = audio_MIN ((size_t) left, sizeof (tmpbuf));
-        int copied;
-
-        ldebug ("left=%d to_copy=%d pos=%d\n", left, to_copy, pos);
-        copied = DMA_read_memory (nchan, tmpbuf, pos, to_copy);
-        gus_dma_transferdata (&s->emu, tmpbuf, copied, left == copied);
-        left -= copied;
-        pos += copied;
-    }
-
-    if (0 == ((mode >> 4) & 1)) {
-        DMA_release_DREQ (s->emu.gusdma);
-    }
-    return dma_len;
-}
-
-static const VMStateDescription vmstate_gus = {
-    .name = "gus",
-    .version_id = 2,
-    .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 ()
-    }
-};
-
-static const MemoryRegionPortio gus_portio_list1[] = {
-    {0x000,  1, 1, .write = gus_writeb },
-    {0x000,  1, 2, .write = gus_writew },
-    {0x006, 10, 1, .read = gus_readb, .write = gus_writeb },
-    {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 (),
-};
-
-static const MemoryRegionPortio gus_portio_list2[] = {
-    {0, 1, 1, .read = gus_readb },
-    {0, 1, 2, .read = gus_readw },
-    PORTIO_END_OF_LIST (),
-};
-
-static int gus_initfn (ISADevice *dev)
-{
-    GUSState *s = DO_UPCAST (GUSState, dev, dev);
-    struct audsettings as;
-
-    AUD_register_card ("gus", &s->card);
-
-    as.freq = s->freq;
-    as.nchannels = 2;
-    as.fmt = AUD_FMT_S16;
-    as.endianness = GUS_ENDIANNESS;
-
-    s->voice = AUD_open_out (
-        &s->card,
-        NULL,
-        "gus",
-        s,
-        GUS_callback,
-        &as
-        );
-
-    if (!s->voice) {
-        AUD_remove_card (&s->card);
-        return -1;
-    }
-
-    s->shift = 2;
-    s->samples = AUD_get_buffer_size_out (s->voice) >> s->shift;
-    s->mixbuf = g_malloc0 (s->samples << s->shift);
-
-    isa_register_portio_list (dev, s->port, gus_portio_list1, s, "gus");
-    isa_register_portio_list (dev, (s->port + 0x100) & 0xf00,
-                              gus_portio_list2, s, "gus");
-
-    DMA_register_channel (s->emu.gusdma, GUS_read_DMA, s);
-    s->emu.himemaddr = s->himem;
-    s->emu.gusdatapos = s->emu.himemaddr + 1024 * 1024 + 32;
-    s->emu.opaque = s;
-    isa_init_irq (dev, &s->pic, s->emu.gusirq);
-
-    AUD_set_active_out (s->voice, 1);
-
-    return 0;
-}
-
-int GUS_init (ISABus *bus)
-{
-    isa_create_simple (bus, "gus");
-    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 const TypeInfo gus_info = {
-    .name          = "gus",
-    .parent        = TYPE_ISA_DEVICE,
-    .instance_size = sizeof (GUSState),
-    .class_init    = gus_class_initfn,
-};
-
-static void gus_register_types (void)
-{
-    type_register_static (&gus_info);
-}
-
-type_init (gus_register_types)
diff --git a/hw/gusemu.h b/hw/gusemu.h
deleted file mode 100644 (file)
index 331bb6f..0000000
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * GUSEMU32 - API
- *
- * Copyright (C) 2000-2007 Tibor "TS" Schütz
- *
- * 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 GUSEMU_H
-#define GUSEMU_H
-
-/* data types (need to be adjusted if neither a VC6 nor a C99 compatible compiler is used) */
-
-#if defined _WIN32 && defined _MSC_VER /* doesn't support other win32 compilers yet, do it yourself... */
- typedef unsigned char GUSbyte;
- typedef unsigned short GUSword;
- typedef unsigned int GUSdword;
- typedef signed char GUSchar;
- typedef signed short GUSsample;
-#else
- #include <stdint.h>
- typedef int8_t GUSchar;
- typedef uint8_t GUSbyte;
- typedef uint16_t GUSword;
- typedef uint32_t GUSdword;
- typedef int16_t GUSsample;
-#endif
-
-typedef struct _GUSEmuState
-{
- GUSbyte *himemaddr; /* 1024*1024 bytes used for storing uploaded samples (+32 additional bytes for read padding) */
- GUSbyte *gusdatapos; /* (gusdataend-gusdata) bytes used for storing emulated GF1/mixer register states (32*32+4 bytes in initial GUSemu32 version) */
- uint32_t gusirq;
- uint32_t gusdma;
- unsigned int timer1fraction;
- unsigned int timer2fraction;
- void *opaque;
-} GUSEmuState;
-
-/* ** Callback functions needed: */
-/* NMI is defined as hwirq=-1 (not supported (yet?)) */
-/* GUS_irqrequest returns the number of IRQs actually scheduled into the virtual machine */
-/* Level triggered IRQ simulations normally return 1 */
-/* Event triggered IRQ simulation can safely ignore GUS_irqclear calls */
-int  GUS_irqrequest(GUSEmuState *state, int hwirq, int num);/* needed in both mixer and bus emulation functions. */
-void GUS_irqclear(  GUSEmuState *state, int hwirq); /* used by gus_write() only - can be left empty for mixer functions */
-void GUS_dmarequest(GUSEmuState *state);            /* used by gus_write() only - can be left empty for mixer functions */
-
-/* ** ISA bus interface functions: */
-
-/* Port I/O handlers */
-/* support the following ports: */
-/* 2x0,2x6,2x8...2xF,3x0...3x7;  */
-/* optional: 388,389 (at least writes should be forwarded or some GUS detection algorithms will fail) */
-/* data is passed in host byte order */
-unsigned int gus_read( GUSEmuState *state, int port, int size);
-void         gus_write(GUSEmuState *state, int port, int size, unsigned int data);
-/* size is given in bytes (1 for byte, 2 for word) */
-
-/* DMA data transfer function */
-/* data pointed to is passed in native x86 order */
-void gus_dma_transferdata(GUSEmuState *state, char *dma_addr, unsigned int count, int TC);
-/* Called back by GUS_start_DMA as soon as the emulated DMA controller is ready for a transfer to or from GUS */
-/* (might be immediately if the DMA controller was programmed first) */
-/* dma_addr is an already translated address directly pointing to the beginning of the memory block */
-/* do not forget to update DMA states after the call, including the DREQ and TC flags */
-/* it is possible to break down a single transfer into multiple ones, but take care that: */
-/* -dma_count is actually count-1 */
-/* -before and during a transfer, DREQ is set and TC cleared */
-/* -when calling gus_dma_transferdata(), TC is only set true for call transferring the last byte */
-/* -after the last transfer, DREQ is cleared and TC is set */
-
-/* ** GF1 mixer emulation functions: */
-/* Usually, gus_irqgen should be called directly after gus_mixvoices if you can meet the recommended ranges. */
-/* If the interrupts are executed immediately (i.e., are synchronous), it may be useful to break this */
-/* down into a sequence of gus_mixvoice();gus_irqgen(); calls while mixing an audio block. */
-/* If the interrupts are asynchronous, it may be needed to use a separate thread mixing into a temporary */
-/* audio buffer in order to avoid quality loss caused by large numsamples and elapsed_time values. */
-
-void gus_mixvoices(GUSEmuState *state, unsigned int playback_freq, unsigned int numsamples, GUSsample *bufferpos);
-/* recommended range: 10 < numsamples < 100 */
-/* lower values may result in increased rounding error, higher values often cause audible timing delays */
-
-void gus_irqgen(GUSEmuState *state, unsigned int elapsed_time);
-/* recommended range: 80us < elapsed_time < max(1000us, numsamples/playback_freq) */
-/* lower values won´t provide any benefit at all, higher values can cause audible timing delays */
-/* note: masked timers are also calculated by this function, thus it might be needed even without any IRQs in use! */
-
-#endif  /* gusemu.h */
diff --git a/hw/gusemu_hal.c b/hw/gusemu_hal.c
deleted file mode 100644 (file)
index 0eee617..0000000
+++ /dev/null
@@ -1,554 +0,0 @@
-/*
- * GUSEMU32 - bus interface part
- *
- * Copyright (C) 2000-2007 Tibor "TS" Schütz
- *
- * 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.
- */
-
-/*
- * TODO: check mixer: see 7.20 of sdk for panning pos (applies to all gus models?)?
- */
-
-#include "hw/gustate.h"
-#include "hw/gusemu.h"
-
-#define GUSregb(position) (*            (gusptr+(position)))
-#define GUSregw(position) (*(GUSword *) (gusptr+(position)))
-#define GUSregd(position) (*(GUSdword *)(gusptr+(position)))
-
-/* size given in bytes */
-unsigned int gus_read(GUSEmuState * state, int port, int size)
-{
-    int             value_read = 0;
-
-    GUSbyte        *gusptr;
-    gusptr = state->gusdatapos;
-    GUSregd(portaccesses)++;
-
-    switch (port & 0xff0f)
-    {
-        /* MixerCtrlReg (read not supported on GUS classic) */
-        /* case 0x200: return GUSregb(MixerCtrlReg2x0); */
-    case 0x206:                          /* IRQstatReg / SB2x6IRQ */
-        /* adlib/sb bits set in port handlers */
-        /* timer/voice bits set in gus_irqgen() */
-        /* dma bit set in gus_dma_transferdata */
-        /* midi not implemented yet */
-        return GUSregb(IRQStatReg2x6);
-    /* case 0x308:                       */ /* AdLib388 */
-    case 0x208:
-        if (GUSregb(GUS45TimerCtrl) & 1)
-            return GUSregb(TimerStatus2x8);
-        return GUSregb(AdLibStatus2x8);  /* AdLibStatus */
-    case 0x309:                          /* AdLib389 */
-    case 0x209:
-        return GUSregb(AdLibData2x9);    /* AdLibData */
-    case 0x20A:
-        return GUSregb(AdLibCommand2xA); /* AdLib2x8_2xA */
-
-#if 0
-    case 0x20B:                          /* GUS hidden registers (read not supported on GUS classic) */
-        switch (GUSregb(RegCtrl_2xF) & 0x07)
-        {
-        case 0:                                 /* IRQ/DMA select */
-            if (GUSregb(MixerCtrlReg2x0) & 0x40)
-                return GUSregb(IRQ_2xB);        /* control register select bit */
-            else
-                return GUSregb(DMA_2xB);
-            /* case 1-5:                        */ /* general purpose emulation regs  */
-            /*  return ...                      */ /* + status reset reg (write only) */
-        case 6:
-            return GUSregb(Jumper_2xB);         /* Joystick/MIDI enable (JumperReg) */
-        default:;
-        }
-        break;
-#endif
-
-    case 0x20C:                          /* SB2xCd */
-        value_read = GUSregb(SB2xCd);
-        if (GUSregb(StatRead_2xF) & 0x20)
-            GUSregb(SB2xCd) ^= 0x80; /* toggle MSB on read */
-        return value_read;
-        /* case 0x20D:                   */ /* SB2xD is write only -> 2xE writes to it*/
-    case 0x20E:
-        if (GUSregb(RegCtrl_2xF) & 0x80) /* 2xE read IRQ enabled? */
-        {
-            GUSregb(StatRead_2xF) |= 0x80;
-            GUS_irqrequest(state, state->gusirq, 1);
-        }
-        return GUSregb(SB2xE);           /* SB2xE */
-    case 0x20F:                          /* StatRead_2xF */
-        /*set/clear fixed bits */
-        /*value_read = (GUSregb(StatRead_2xF) & 0xf9)|1; */ /*(LSB not set on GUS classic!)*/
-        value_read = (GUSregb(StatRead_2xF) & 0xf9);
-        if (GUSregb(MixerCtrlReg2x0) & 0x08)
-            value_read |= 2;    /* DMA/IRQ enabled flag */
-        return value_read;
-    /* case 0x300:                      */ /* MIDI (not implemented) */
-    /* case 0x301:                      */ /* MIDI (not implemented) */
-    case 0x302:
-        return GUSregb(VoiceSelReg3x2); /* VoiceSelReg */
-    case 0x303:
-        return GUSregb(FunkSelReg3x3);  /* FunkSelReg */
-    case 0x304:                         /* DataRegLoByte3x4 + DataRegWord3x4 */
-    case 0x305:                         /* DataRegHiByte3x5 */
-        switch (GUSregb(FunkSelReg3x3))
-        {
-    /* common functions */
-        case 0x41:                      /* DramDMAContrReg */
-            value_read = GUSregb(GUS41DMACtrl); /* &0xfb */
-            GUSregb(GUS41DMACtrl) &= 0xbb;
-            if (state->gusdma >= 4)
-                value_read |= 0x04;
-            if (GUSregb(IRQStatReg2x6) & 0x80)
-            {
-                value_read |= 0x40;
-                GUSregb(IRQStatReg2x6) &= 0x7f;
-                if (!GUSregb(IRQStatReg2x6))
-                    GUS_irqclear(state, state->gusirq);
-            }
-            return (GUSbyte) value_read;
-            /* DramDMAmemPosReg */
-            /* case 0x42: value_read=GUSregw(GUS42DMAStart); break;*/
-            /* 43h+44h write only */
-        case 0x45:
-            return GUSregb(GUS45TimerCtrl);         /* TimerCtrlReg */
-            /* 46h+47h write only */
-            /* 48h: samp freq - write only */
-        case 0x49:
-            return GUSregb(GUS49SampCtrl) & 0xbf;   /* SampCtrlReg */
-        /* case 4bh:                                */ /* joystick trim not supported */
-        /* case 0x4c: return GUSregb(GUS4cReset);   */ /* GUSreset: write only*/
-    /* voice specific functions */
-        case 0x80:
-        case 0x81:
-        case 0x82:
-        case 0x83:
-        case 0x84:
-        case 0x85:
-        case 0x86:
-        case 0x87:
-        case 0x88:
-        case 0x89:
-        case 0x8a:
-        case 0x8b:
-        case 0x8c:
-        case 0x8d:
-            {
-                int             offset = 2 * (GUSregb(FunkSelReg3x3) & 0x0f);
-                offset += ((int) GUSregb(VoiceSelReg3x2) & 0x1f) << 5; /* = Voice*32 + Funktion*2 */
-                value_read = GUSregw(offset);
-            }
-            break;
-    /* voice unspecific functions */
-        case 0x8e:                                  /* NumVoice */
-            return GUSregb(NumVoices);
-        case 0x8f:                                  /* irqstatreg */
-            /* (pseudo IRQ-FIFO is processed during a gus_write(0x3X3,0x8f)) */
-            return GUSregb(SynVoiceIRQ8f);
-        default:
-            return 0xffff;
-        }
-        if (size == 1)
-        {
-            if ((port & 0xff0f) == 0x305)
-                value_read = value_read >> 8;
-            value_read &= 0xff;
-        }
-        return (GUSword) value_read;
-    /* case 0x306:                                  */ /* Mixer/Version info */
-        /*  return 0xff; */ /* Pre 3.6 boards, ICS mixer NOT present */
-    case 0x307:                                     /* DRAMaccess */
-        {
-            GUSbyte        *adr;
-            adr = state->himemaddr + (GUSregd(GUSDRAMPOS24bit) & 0xfffff);
-            return *adr;
-        }
-    default:;
-    }
-    return 0xffff;
-}
-
-void gus_write(GUSEmuState * state, int port, int size, unsigned int data)
-{
-    GUSbyte        *gusptr;
-    gusptr = state->gusdatapos;
-    GUSregd(portaccesses)++;
-
-    switch (port & 0xff0f)
-    {
-    case 0x200:                 /* MixerCtrlReg */
-        GUSregb(MixerCtrlReg2x0) = (GUSbyte) data;
-        break;
-    case 0x206:                 /* IRQstatReg / SB2x6IRQ */
-        if (GUSregb(GUS45TimerCtrl) & 0x20) /* SB IRQ enabled? -> set 2x6IRQ bit */
-        {
-            GUSregb(TimerStatus2x8) |= 0x08;
-            GUSregb(IRQStatReg2x6) = 0x10;
-            GUS_irqrequest(state, state->gusirq, 1);
-        }
-        break;
-    case 0x308:                /* AdLib 388h */
-    case 0x208:                /* AdLibCommandReg */
-        GUSregb(AdLibCommand2xA) = (GUSbyte) data;
-        break;
-    case 0x309:                /* AdLib 389h */
-    case 0x209:                /* AdLibDataReg */
-        if ((GUSregb(AdLibCommand2xA) == 0x04) && (!(GUSregb(GUS45TimerCtrl) & 1))) /* GUS auto timer mode enabled? */
-        {
-            if (data & 0x80)
-                GUSregb(TimerStatus2x8) &= 0x1f; /* AdLib IRQ reset? -> clear maskable adl. timer int regs */
-            else
-                GUSregb(TimerDataReg2x9) = (GUSbyte) data;
-        }
-        else
-        {
-            GUSregb(AdLibData2x9) = (GUSbyte) data;
-            if (GUSregb(GUS45TimerCtrl) & 0x02)
-            {
-                GUSregb(TimerStatus2x8) |= 0x01;
-                GUSregb(IRQStatReg2x6) = 0x10;
-                GUS_irqrequest(state, state->gusirq, 1);
-            }
-        }
-        break;
-    case 0x20A:
-        GUSregb(AdLibStatus2x8) = (GUSbyte) data;
-        break;                 /* AdLibStatus2x8 */
-    case 0x20B:                /* GUS hidden registers */
-        switch (GUSregb(RegCtrl_2xF) & 0x7)
-        {
-        case 0:
-            if (GUSregb(MixerCtrlReg2x0) & 0x40)
-                GUSregb(IRQ_2xB) = (GUSbyte) data; /* control register select bit */
-            else
-                GUSregb(DMA_2xB) = (GUSbyte) data;
-            break;
-            /* case 1-4: general purpose emulation regs */
-        case 5:                                    /* clear stat reg 2xF */
-            GUSregb(StatRead_2xF) = 0; /* ToDo: is this identical with GUS classic? */
-            if (!GUSregb(IRQStatReg2x6))
-                GUS_irqclear(state, state->gusirq);
-            break;
-        case 6:                                    /* Jumper reg (Joystick/MIDI enable) */
-            GUSregb(Jumper_2xB) = (GUSbyte) data;
-            break;
-        default:;
-        }
-        break;
-    case 0x20C:                /* SB2xCd */
-        if (GUSregb(GUS45TimerCtrl) & 0x20)
-        {
-            GUSregb(TimerStatus2x8) |= 0x10; /* SB IRQ enabled? -> set 2xCIRQ bit */
-            GUSregb(IRQStatReg2x6) = 0x10;
-            GUS_irqrequest(state, state->gusirq, 1);
-        }
-    case 0x20D:                /* SB2xCd no IRQ */
-        GUSregb(SB2xCd) = (GUSbyte) data;
-        break;
-    case 0x20E:                /* SB2xE */
-        GUSregb(SB2xE) = (GUSbyte) data;
-        break;
-    case 0x20F:
-        GUSregb(RegCtrl_2xF) = (GUSbyte) data;
-        break;                 /* CtrlReg2xF */
-    case 0x302:                /* VoiceSelReg */
-        GUSregb(VoiceSelReg3x2) = (GUSbyte) data;
-        break;
-    case 0x303:                /* FunkSelReg */
-        GUSregb(FunkSelReg3x3) = (GUSbyte) data;
-        if ((GUSbyte) data == 0x8f) /* set irqstatreg, get voicereg and clear IRQ */
-        {
-            int             voice;
-            if (GUSregd(voicewavetableirq)) /* WavetableIRQ */
-            {
-                for (voice = 0; voice < 31; voice++)
-                {
-                    if (GUSregd(voicewavetableirq) & (1 << voice))
-                    {
-                        GUSregd(voicewavetableirq) ^= (1 << voice); /* clear IRQ bit */
-                        GUSregb(voice << 5) &= 0x7f; /* clear voice reg irq bit */
-                        if (!GUSregd(voicewavetableirq))
-                            GUSregb(IRQStatReg2x6) &= 0xdf;
-                        if (!GUSregb(IRQStatReg2x6))
-                            GUS_irqclear(state, state->gusirq);
-                        GUSregb(SynVoiceIRQ8f) = voice | 0x60; /* (bit==0 => IRQ wartend) */
-                        return;
-                    }
-                }
-            }
-            else if (GUSregd(voicevolrampirq)) /* VolRamp IRQ */
-            {
-                for (voice = 0; voice < 31; voice++)
-                {
-                    if (GUSregd(voicevolrampirq) & (1 << voice))
-                    {
-                        GUSregd(voicevolrampirq) ^= (1 << voice); /* clear IRQ bit */
-                        GUSregb((voice << 5) + VSRVolRampControl) &= 0x7f; /* clear voice volume reg irq bit */
-                        if (!GUSregd(voicevolrampirq))
-                            GUSregb(IRQStatReg2x6) &= 0xbf;
-                        if (!GUSregb(IRQStatReg2x6))
-                            GUS_irqclear(state, state->gusirq);
-                        GUSregb(SynVoiceIRQ8f) = voice | 0x80; /* (bit==0 => IRQ wartend) */
-                        return;
-                    }
-                }
-            }
-            GUSregb(SynVoiceIRQ8f) = 0xe8; /* kein IRQ wartet */
-        }
-        break;
-    case 0x304:
-    case 0x305:
-        {
-            GUSword         writedata = (GUSword) data;
-            GUSword         readmask = 0x0000;
-            if (size == 1)
-            {
-                readmask = 0xff00;
-                writedata &= 0xff;
-                if ((port & 0xff0f) == 0x305)
-                {
-                    writedata = (GUSword) (writedata << 8);
-                    readmask = 0x00ff;
-                }
-            }
-            switch (GUSregb(FunkSelReg3x3))
-            {
-                /* voice specific functions */
-            case 0x00:
-            case 0x01:
-            case 0x02:
-            case 0x03:
-            case 0x04:
-            case 0x05:
-            case 0x06:
-            case 0x07:
-            case 0x08:
-            case 0x09:
-            case 0x0a:
-            case 0x0b:
-            case 0x0c:
-            case 0x0d:
-                {
-                    int             offset;
-                    if (!(GUSregb(GUS4cReset) & 0x01))
-                        break;  /* reset flag active? */
-                    offset = 2 * (GUSregb(FunkSelReg3x3) & 0x0f);
-                    offset += (GUSregb(VoiceSelReg3x2) & 0x1f) << 5; /*  = Voice*32 + Funktion*2 */
-                    GUSregw(offset) = (GUSword) ((GUSregw(offset) & readmask) | writedata);
-                }
-                break;
-                /* voice unspecific functions */
-            case 0x0e:         /* NumVoices */
-                GUSregb(NumVoices) = (GUSbyte) data;
-                break;
-            /* case 0x0f:      */ /* read only */
-                /* common functions */
-            case 0x41:         /* DramDMAContrReg */
-                GUSregb(GUS41DMACtrl) = (GUSbyte) data;
-                if (data & 0x01)
-                    GUS_dmarequest(state);
-                break;
-            case 0x42:         /* DramDMAmemPosReg */
-                GUSregw(GUS42DMAStart) = (GUSregw(GUS42DMAStart) & readmask) | writedata;
-                GUSregb(GUS50DMAHigh) &= 0xf; /* compatibility stuff... */
-                break;
-            case 0x43:         /* DRAMaddrLo */
-                GUSregd(GUSDRAMPOS24bit) =
-                    (GUSregd(GUSDRAMPOS24bit) & (readmask | 0xff0000)) | writedata;
-                break;
-            case 0x44:         /* DRAMaddrHi */
-                GUSregd(GUSDRAMPOS24bit) =
-                    (GUSregd(GUSDRAMPOS24bit) & 0xffff) | ((data & 0x0f) << 16);
-                break;
-            case 0x45:         /* TCtrlReg */
-                GUSregb(GUS45TimerCtrl) = (GUSbyte) data;
-                if (!(data & 0x20))
-                    GUSregb(TimerStatus2x8) &= 0xe7;    /* sb IRQ dis? -> clear 2x8/2xC sb IRQ flags */
-                if (!(data & 0x02))
-                    GUSregb(TimerStatus2x8) &= 0xfe;    /* adlib data IRQ dis? -> clear 2x8 adlib IRQ flag */
-                if (!(GUSregb(TimerStatus2x8) & 0x19))
-                    GUSregb(IRQStatReg2x6) &= 0xef;     /* 0xe6; $$clear IRQ if both IRQ bits are inactive or cleared */
-                /* catch up delayed timer IRQs: */
-                if ((GUSregw(TimerIRQs) > 1) && (GUSregb(TimerDataReg2x9) & 3))
-                {
-                    if (GUSregb(TimerDataReg2x9) & 1)   /* start timer 1 (80us decrement rate) */
-                    {
-                        if (!(GUSregb(TimerDataReg2x9) & 0x40))
-                            GUSregb(TimerStatus2x8) |= 0xc0;    /* maskable bits */
-                        if (data & 4) /* timer1 irq enable */
-                        {
-                            GUSregb(TimerStatus2x8) |= 4;       /* nonmaskable bit */
-                            GUSregb(IRQStatReg2x6) |= 4;        /* timer 1 irq pending */
-                        }
-                    }
-                    if (GUSregb(TimerDataReg2x9) & 2)   /* start timer 2 (320us decrement rate) */
-                    {
-                        if (!(GUSregb(TimerDataReg2x9) & 0x20))
-                            GUSregb(TimerStatus2x8) |= 0xa0;    /* maskable bits */
-                        if (data & 8) /* timer2 irq enable */
-                        {
-                            GUSregb(TimerStatus2x8) |= 2;       /* nonmaskable bit */
-                            GUSregb(IRQStatReg2x6) |= 8;        /* timer 2 irq pending */
-                        }
-                    }
-                    GUSregw(TimerIRQs)--;
-                    if (GUSregw(BusyTimerIRQs) > 1)
-                        GUSregw(BusyTimerIRQs)--;
-                    else
-                        GUSregw(BusyTimerIRQs) =
-                            GUS_irqrequest(state, state->gusirq, GUSregw(TimerIRQs));
-                }
-                else
-                    GUSregw(TimerIRQs) = 0;
-
-                if (!(data & 0x04))
-                {
-                    GUSregb(TimerStatus2x8) &= 0xfb; /* clear non-maskable timer1 bit */
-                    GUSregb(IRQStatReg2x6)  &= 0xfb;
-                }
-                if (!(data & 0x08))
-                {
-                    GUSregb(TimerStatus2x8) &= 0xfd; /* clear non-maskable timer2 bit */
-                    GUSregb(IRQStatReg2x6)  &= 0xf7;
-                }
-                if (!GUSregb(IRQStatReg2x6))
-                    GUS_irqclear(state, state->gusirq);
-                break;
-            case 0x46:          /* Counter1 */
-                GUSregb(GUS46Counter1) = (GUSbyte) data;
-                break;
-            case 0x47:          /* Counter2 */
-                GUSregb(GUS47Counter2) = (GUSbyte) data;
-                break;
-            /* case 0x48:       */ /* sampling freq reg not emulated (same as interwave) */
-            case 0x49:          /* SampCtrlReg */
-                GUSregb(GUS49SampCtrl) = (GUSbyte) data;
-                break;
-            /* case 0x4b:       */ /* joystick trim not emulated */
-            case 0x4c:          /* GUSreset */
-                GUSregb(GUS4cReset) = (GUSbyte) data;
-                if (!(GUSregb(GUS4cReset) & 1)) /* reset... */
-                {
-                    GUSregd(voicewavetableirq) = 0;
-                    GUSregd(voicevolrampirq) = 0;
-                    GUSregw(TimerIRQs) = 0;
-                    GUSregw(BusyTimerIRQs) = 0;
-                    GUSregb(NumVoices) = 0xcd;
-                    GUSregb(IRQStatReg2x6) = 0;
-                    GUSregb(TimerStatus2x8) = 0;
-                    GUSregb(AdLibData2x9) = 0;
-                    GUSregb(TimerDataReg2x9) = 0;
-                    GUSregb(GUS41DMACtrl) = 0;
-                    GUSregb(GUS45TimerCtrl) = 0;
-                    GUSregb(GUS49SampCtrl) = 0;
-                    GUSregb(GUS4cReset) &= 0xf9; /* clear IRQ and DAC enable bits */
-                    GUS_irqclear(state, state->gusirq);
-                }
-                /* IRQ enable bit checked elsewhere */
-                /* EnableDAC bit may be used by external callers */
-                break;
-            }
-        }
-        break;
-    case 0x307:                /* DRAMaccess */
-        {
-            GUSbyte        *adr;
-            adr = state->himemaddr + (GUSregd(GUSDRAMPOS24bit) & 0xfffff);
-            *adr = (GUSbyte) data;
-        }
-        break;
-    }
-}
-
-/* Attention when breaking up a single DMA transfer to multiple ones:
- * it may lead to multiple terminal count interrupts and broken transfers:
- *
- * 1. Whenever you transfer a piece of data, the gusemu callback is invoked
- * 2. The callback may generate a TC irq (if the register was set up to do so)
- * 3. The irq may result in the program using the GUS to reprogram the GUS
- *
- * Some programs also decide to upload by just checking if TC occurs
- * (via interrupt or a cleared GUS dma flag)
- * and then start the next transfer, without checking DMA state
- *
- * Thus: Always make sure to set the TC flag correctly!
- *
- * Note that the genuine GUS had a granularity of 16 bytes/words for low/high DMA
- * while later cards had atomic granularity provided by an additional GUS50DMAHigh register
- * GUSemu also uses this register to support byte-granular transfers for better compatibility
- * with emulators other than GUSemu32
- */
-
-void gus_dma_transferdata(GUSEmuState * state, char *dma_addr, unsigned int count, int TC)
-{
-    /* this function gets called by the callback function as soon as a DMA transfer is about to start
-     * dma_addr is a translated address within accessible memory, not the physical one,
-     * count is (real dma count register)+1
-     * note that the amount of bytes transferred is fully determined by values in the DMA registers
-     * do not forget to update DMA states after transferring the entire block:
-     * DREQ cleared & TC asserted after the _whole_ transfer */
-
-    char           *srcaddr;
-    char           *destaddr;
-    char            msbmask = 0;
-    GUSbyte        *gusptr;
-    gusptr = state->gusdatapos;
-
-    srcaddr = dma_addr; /* system memory address */
-    {
-        int             offset = (GUSregw(GUS42DMAStart) << 4) + (GUSregb(GUS50DMAHigh) & 0xf);
-        if (state->gusdma >= 4)
-            offset = (offset & 0xc0000) + (2 * (offset & 0x1fff0)); /* 16 bit address translation */
-        destaddr = (char *) state->himemaddr + offset; /* wavetable RAM address */
-    }
-
-    GUSregw(GUS42DMAStart) += (GUSword)  (count >> 4);                           /* ToDo: add 16bit GUS page limit? */
-    GUSregb(GUS50DMAHigh)   = (GUSbyte) ((count + GUSregb(GUS50DMAHigh)) & 0xf); /* ToDo: add 16bit GUS page limit? */
-
-    if (GUSregb(GUS41DMACtrl) & 0x02)   /* direction, 0 := sysram->gusram */
-    {
-        char           *tmpaddr = destaddr;
-        destaddr = srcaddr;
-        srcaddr = tmpaddr;
-    }
-
-    if ((GUSregb(GUS41DMACtrl) & 0x80) && (!(GUSregb(GUS41DMACtrl) & 0x02)))
-        msbmask = (const char) 0x80;    /* invert MSB */
-    for (; count > 0; count--)
-    {
-        if (GUSregb(GUS41DMACtrl) & 0x40)
-            *(destaddr++) = *(srcaddr++);               /* 16 bit lobyte */
-        else
-            *(destaddr++) = (msbmask ^ (*(srcaddr++))); /* 8 bit */
-        if (state->gusdma >= 4)
-            *(destaddr++) = (msbmask ^ (*(srcaddr++))); /* 16 bit hibyte */
-    }
-
-    if (TC)
-    {
-        (GUSregb(GUS41DMACtrl)) &= 0xfe;        /* clear DMA request bit */
-        if (GUSregb(GUS41DMACtrl) & 0x20)       /* DMA terminal count IRQ */
-        {
-            GUSregb(IRQStatReg2x6) |= 0x80;
-            GUS_irqrequest(state, state->gusirq, 1);
-        }
-    }
-}
diff --git a/hw/gusemu_mixer.c b/hw/gusemu_mixer.c
deleted file mode 100644 (file)
index 816c58a..0000000
+++ /dev/null
@@ -1,240 +0,0 @@
-/*
- * GUSEMU32 - mixing engine (similar to Interwave GF1 compatibility)
- *
- * Copyright (C) 2000-2007 Tibor "TS" Schütz
- *
- * 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 "hw/gusemu.h"
-#include "hw/gustate.h"
-
-#define GUSregb(position)  (*            (gusptr+(position)))
-#define GUSregw(position)  (*(GUSword *) (gusptr+(position)))
-#define GUSregd(position)  (*(GUSdword *)(gusptr+(position)))
-
-#define GUSvoice(position) (*(GUSword *)(voiceptr+(position)))
-
-/* samples are always 16bit stereo (4 bytes each, first right then left interleaved) */
-void gus_mixvoices(GUSEmuState * state, unsigned int playback_freq, unsigned int numsamples,
-                   GUSsample *bufferpos)
-{
-    /* note that byte registers are stored in the upper half of each voice register! */
-    GUSbyte        *gusptr;
-    int             Voice;
-    GUSword        *voiceptr;
-
-    unsigned int    count;
-    for (count = 0; count < numsamples * 2; count++)
-        *(bufferpos + count) = 0;       /* clear */
-
-    gusptr = state->gusdatapos;
-    voiceptr = (GUSword *) gusptr;
-    if (!(GUSregb(GUS4cReset) & 0x01))  /* reset flag active? */
-        return;
-
-    for (Voice = 0; Voice <= (GUSregb(NumVoices) & 31); Voice++)
-    {
-        if (GUSvoice(wVSRControl)        &  0x200)
-            GUSvoice(wVSRControl)        |= 0x100; /* voice stop request */
-        if (GUSvoice(wVSRVolRampControl) &  0x200)
-            GUSvoice(wVSRVolRampControl) |= 0x100; /* Volume ramp stop request */
-        if (!(GUSvoice(wVSRControl) & GUSvoice(wVSRVolRampControl) & 0x100)) /* neither voice nor volume calculation active - save some time here ;) */
-        {
-            unsigned int    sample;
-
-            unsigned int    LoopStart = (GUSvoice(wVSRLoopStartHi) << 16) | GUSvoice(wVSRLoopStartLo); /* 23.9 format */
-            unsigned int    LoopEnd   = (GUSvoice(wVSRLoopEndHi)   << 16) | GUSvoice(wVSRLoopEndLo);   /* 23.9 format */
-            unsigned int    CurrPos   = (GUSvoice(wVSRCurrPosHi)   << 16) | GUSvoice(wVSRCurrPosLo);   /* 23.9 format */
-            int             VoiceIncrement = ((((unsigned long) GUSvoice(wVSRFreq) * 44100) / playback_freq) * (14 >> 1)) /
-                                             ((GUSregb(NumVoices) & 31) + 1); /* 6.10 increment/frame to 23.9 increment/sample */
-
-            int             PanningPos = (GUSvoice(wVSRPanning) >> 8) & 0xf;
-
-            unsigned int    Volume32   = 32 * GUSvoice(wVSRCurrVol); /* 32 times larger than original gus for maintaining precision while ramping */
-            unsigned int    StartVol32 = (GUSvoice(wVSRVolRampStartVol) & 0xff00) * 32;
-            unsigned int    EndVol32   = (GUSvoice(wVSRVolRampEndVol)   & 0xff00) * 32;
-            int             VolumeIncrement32 = (32 * 16 * (GUSvoice(wVSRVolRampRate) & 0x3f00) >> 8) >> ((((GUSvoice(wVSRVolRampRate) & 0xc000) >> 8) >> 6) * 3); /* including 1/8/64/512 volume speed divisor */
-            VolumeIncrement32 = (((VolumeIncrement32 * 44100 / 2) / playback_freq) * 14) / ((GUSregb(NumVoices) & 31) + 1); /* adjust ramping speed to playback speed */
-
-            if (GUSvoice(wVSRControl) & 0x4000)
-                VoiceIncrement    = -VoiceIncrement;    /* reverse playback */
-            if (GUSvoice(wVSRVolRampControl) & 0x4000)
-                VolumeIncrement32 = -VolumeIncrement32; /* reverse ramping */
-
-            for (sample = 0; sample < numsamples; sample++)
-            {
-                int             sample1, sample2, Volume;
-                if (GUSvoice(wVSRControl) & 0x400)      /* 16bit */
-                {
-                    int offset = ((CurrPos >> 9) & 0xc0000) + (((CurrPos >> 9) & 0x1ffff) << 1);
-                    GUSchar *adr;
-                    adr = (GUSchar *) state->himemaddr + offset;
-                    sample1 = (*adr & 0xff) + (*(adr + 1) * 256);
-                    sample2 = (*(adr + 2) & 0xff) + (*(adr + 2 + 1) * 256);
-                }
-                else            /* 8bit */
-                {
-                    int offset = (CurrPos >> 9) & 0xfffff;
-                    GUSchar *adr;
-                    adr = (GUSchar *) state->himemaddr + offset;
-                    sample1 = (*adr) * 256;
-                    sample2 = (*(adr + 1)) * 256;
-                }
-
-                Volume = ((((Volume32 >> (4 + 5)) & 0xff) + 256) << (Volume32 >> ((4 + 8) + 5))) / 512; /* semi-logarithmic volume, +5 due to additional precision */
-                sample1 = (((sample1 * Volume) >> 16) * (512 - (CurrPos % 512))) / 512;
-                sample2 = (((sample2 * Volume) >> 16) * (CurrPos % 512)) / 512;
-                sample1 += sample2;
-
-                if (!(GUSvoice(wVSRVolRampControl) & 0x100))
-                {
-                    Volume32 += VolumeIncrement32;
-                    if ((GUSvoice(wVSRVolRampControl) & 0x4000) ? (Volume32 <= StartVol32) : (Volume32 >= EndVol32)) /* ramp up boundary cross */
-                    {
-                        if (GUSvoice(wVSRVolRampControl) & 0x2000)
-                            GUSvoice(wVSRVolRampControl) |= 0x8000;     /* volramp IRQ enabled? -> IRQ wait flag */
-                        if (GUSvoice(wVSRVolRampControl) & 0x800)       /* loop enabled */
-                        {
-                            if (GUSvoice(wVSRVolRampControl) & 0x1000)  /* bidir. loop */
-                            {
-                                GUSvoice(wVSRVolRampControl) ^= 0x4000; /* toggle dir */
-                                VolumeIncrement32 = -VolumeIncrement32;
-                            }
-                            else
-                                Volume32 = (GUSvoice(wVSRVolRampControl) & 0x4000) ? EndVol32 : StartVol32; /* unidir. loop ramp */
-                        }
-                        else
-                        {
-                            GUSvoice(wVSRVolRampControl) |= 0x100;
-                            Volume32 =
-                                (GUSvoice(wVSRVolRampControl) & 0x4000) ? StartVol32 : EndVol32;
-                        }
-                    }
-                }
-                if ((GUSvoice(wVSRVolRampControl) & 0xa000) == 0xa000)  /* volramp IRQ set and enabled? */
-                {
-                    GUSregd(voicevolrampirq) |= 1 << Voice;             /* set irq slot */
-                }
-                else
-                {
-                    GUSregd(voicevolrampirq) &= (~(1 << Voice));        /* clear irq slot */
-                    GUSvoice(wVSRVolRampControl) &= 0x7f00;
-                }
-
-                if (!(GUSvoice(wVSRControl) & 0x100))
-                {
-                    CurrPos += VoiceIncrement;
-                    if ((GUSvoice(wVSRControl) & 0x4000) ? (CurrPos <= LoopStart) : (CurrPos >= LoopEnd)) /* playback boundary cross */
-                    {
-                        if (GUSvoice(wVSRControl) & 0x2000)
-                            GUSvoice(wVSRControl) |= 0x8000;       /* voice IRQ enabled -> IRQ wait flag */
-                        if (GUSvoice(wVSRControl) & 0x800)         /* loop enabled */
-                        {
-                            if (GUSvoice(wVSRControl) & 0x1000)    /* pingpong loop */
-                            {
-                                GUSvoice(wVSRControl) ^= 0x4000;   /* toggle dir */
-                                VoiceIncrement = -VoiceIncrement;
-                            }
-                            else
-                                CurrPos = (GUSvoice(wVSRControl) & 0x4000) ? LoopEnd : LoopStart; /* unidir. loop */
-                        }
-                        else if (!(GUSvoice(wVSRVolRampControl) & 0x400))
-                            GUSvoice(wVSRControl) |= 0x100;        /* loop disabled, rollover check */
-                    }
-                }
-                if ((GUSvoice(wVSRControl) & 0xa000) == 0xa000)    /* wavetable IRQ set and enabled? */
-                {
-                    GUSregd(voicewavetableirq) |= 1 << Voice;      /* set irq slot */
-                }
-                else
-                {
-                    GUSregd(voicewavetableirq) &= (~(1 << Voice)); /* clear irq slot */
-                    GUSvoice(wVSRControl) &= 0x7f00;
-                }
-
-                /* mix samples into buffer */
-                *(bufferpos + 2 * sample)     += (GUSsample) ((sample1 * PanningPos) >> 4);        /* right */
-                *(bufferpos + 2 * sample + 1) += (GUSsample) ((sample1 * (15 - PanningPos)) >> 4); /* left */
-            }
-            /* write back voice and volume */
-            GUSvoice(wVSRCurrVol)   = Volume32 / 32;
-            GUSvoice(wVSRCurrPosHi) = CurrPos >> 16;
-            GUSvoice(wVSRCurrPosLo) = CurrPos & 0xffff;
-        }
-        voiceptr += 16; /* next voice */
-    }
-}
-
-void gus_irqgen(GUSEmuState * state, unsigned int elapsed_time)
-/* time given in microseconds */
-{
-    int             requestedIRQs = 0;
-    GUSbyte        *gusptr;
-    gusptr = state->gusdatapos;
-    if (GUSregb(TimerDataReg2x9) & 1) /* start timer 1 (80us decrement rate) */
-    {
-        unsigned int    timer1fraction = state->timer1fraction;
-        int             newtimerirqs;
-        newtimerirqs          = (elapsed_time + timer1fraction) / (80 * (256 - GUSregb(GUS46Counter1)));
-        state->timer1fraction = (elapsed_time + timer1fraction) % (80 * (256 - GUSregb(GUS46Counter1)));
-        if (newtimerirqs)
-        {
-            if (!(GUSregb(TimerDataReg2x9) & 0x40))
-                GUSregb(TimerStatus2x8) |= 0xc0; /* maskable bits */
-            if (GUSregb(GUS45TimerCtrl) & 4)     /* timer1 irq enable */
-            {
-                GUSregb(TimerStatus2x8) |= 4;    /* nonmaskable bit */
-                GUSregb(IRQStatReg2x6)  |= 4;    /* timer 1 irq pending */
-                GUSregw(TimerIRQs) += newtimerirqs;
-                requestedIRQs += newtimerirqs;
-            }
-        }
-    }
-    if (GUSregb(TimerDataReg2x9) & 2) /* start timer 2 (320us decrement rate) */
-    {
-        unsigned int timer2fraction = state->timer2fraction;
-        int             newtimerirqs;
-        newtimerirqs          = (elapsed_time + timer2fraction) / (320 * (256 - GUSregb(GUS47Counter2)));
-        state->timer2fraction = (elapsed_time + timer2fraction) % (320 * (256 - GUSregb(GUS47Counter2)));
-        if (newtimerirqs)
-        {
-            if (!(GUSregb(TimerDataReg2x9) & 0x20))
-                GUSregb(TimerStatus2x8) |= 0xa0; /* maskable bits */
-            if (GUSregb(GUS45TimerCtrl) & 8)     /* timer2 irq enable */
-            {
-                GUSregb(TimerStatus2x8) |= 2;    /* nonmaskable bit */
-                GUSregb(IRQStatReg2x6)  |= 8;    /* timer 2 irq pending */
-                GUSregw(TimerIRQs) += newtimerirqs;
-                requestedIRQs += newtimerirqs;
-            }
-        }
-    }
-    if (GUSregb(GUS4cReset) & 0x4) /* synth IRQ enable */
-    {
-        if (GUSregd(voicewavetableirq))
-            GUSregb(IRQStatReg2x6) |= 0x20;
-        if (GUSregd(voicevolrampirq))
-            GUSregb(IRQStatReg2x6) |= 0x40;
-    }
-    if ((!requestedIRQs) && GUSregb(IRQStatReg2x6))
-        requestedIRQs++;
-    if (GUSregb(IRQStatReg2x6))
-        GUSregw(BusyTimerIRQs) = GUS_irqrequest(state, state->gusirq, requestedIRQs);
-}
diff --git a/hw/gustate.h b/hw/gustate.h
deleted file mode 100644 (file)
index ece903a..0000000
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * GUSEMU32 - persistent GUS register state
- *
- * Copyright (C) 2000-2007 Tibor "TS" Schütz
- *
- * 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 GUSTATE_H
-#define GUSTATE_H
-
-/*state block offset*/
-#define gusdata (0)
-
-/* data stored using this structure is in host byte order! */
-
-/*access type*/
-#define PortRead  (0)
-#define PortWrite (1)
-
-#define Port8Bitacc  (0)
-#define Port16Bitacc (1)
-
-/*voice register offsets (in bytes)*/
-#define VSRegs (0)
-#define VSRControl          (0)
-#define VSRegsEnd (VSRControl+VSRegs + 32*(16*2))
-#define VSRFreq             (2)
-#define VSRLoopStartHi      (4)
-#define VSRLoopStartLo      (6)
-#define VSRLoopEndHi        (8)
-#define VSRLoopEndLo       (10)
-#define VSRVolRampRate     (12)
-#define VSRVolRampStartVol (14)
-#define VSRVolRampEndVol   (16)
-#define VSRCurrVol         (18)
-#define VSRCurrPosHi       (20)
-#define VSRCurrPosLo       (22)
-#define VSRPanning         (24)
-#define VSRVolRampControl  (26)
-
-/*voice register offsets (in words)*/
-#define wVSRegs (0)
-#define wVSRControl         (0)
-#define wVSRegsEnd (wVSRControl+wVSRegs + 32*(16))
-#define wVSRFreq            (1)
-#define wVSRLoopStartHi     (2)
-#define wVSRLoopStartLo     (3)
-#define wVSRLoopEndHi       (4)
-#define wVSRLoopEndLo       (5)
-#define wVSRVolRampRate     (6)
-#define wVSRVolRampStartVol (7)
-#define wVSRVolRampEndVol   (8)
-#define wVSRCurrVol         (9)
-#define wVSRCurrPosHi      (10)
-#define wVSRCurrPosLo      (11)
-#define wVSRPanning        (12)
-#define wVSRVolRampControl (13)
-
-/*GUS register state block: 32 voices, padding filled with remaining registers*/
-#define DataRegLoByte3x4  (VSRVolRampControl+2)
-#define  DataRegWord3x4 (DataRegLoByte3x4)
-#define DataRegHiByte3x5  (VSRVolRampControl+2       +1)
-#define DMA_2xB (VSRVolRampControl+2+2)
-#define IRQ_2xB (VSRVolRampControl+2+3)
-
-#define RegCtrl_2xF       (VSRVolRampControl+2+(16*2))
-#define Jumper_2xB        (VSRVolRampControl+2+(16*2)+1)
-#define GUS42DMAStart     (VSRVolRampControl+2+(16*2)+2)
-
-#define GUS43DRAMIOlo     (VSRVolRampControl+2+(16*2)*2)
-#define  GUSDRAMPOS24bit (GUS43DRAMIOlo)
-#define GUS44DRAMIOhi     (VSRVolRampControl+2+(16*2)*2+2)
-
-#define voicewavetableirq (VSRVolRampControl+2+(16*2)*3) /* voice IRQ pseudoqueue: 1 bit per voice */
-
-#define voicevolrampirq   (VSRVolRampControl+2+(16*2)*4) /* voice IRQ pseudoqueue: 1 bit per voice */
-
-#define startvoices       (VSRVolRampControl+2+(16*2)*5) /* statistics / optimizations */
-
-#define IRQStatReg2x6     (VSRVolRampControl+2+(16*2)*6)
-#define TimerStatus2x8    (VSRVolRampControl+2+(16*2)*6+1)
-#define TimerDataReg2x9   (VSRVolRampControl+2+(16*2)*6+2)
-#define MixerCtrlReg2x0   (VSRVolRampControl+2+(16*2)*6+3)
-
-#define VoiceSelReg3x2    (VSRVolRampControl+2+(16*2)*7)
-#define FunkSelReg3x3     (VSRVolRampControl+2+(16*2)*7+1)
-#define AdLibStatus2x8    (VSRVolRampControl+2+(16*2)*7+2)
-#define StatRead_2xF      (VSRVolRampControl+2+(16*2)*7+3)
-
-#define GUS48SampSpeed    (VSRVolRampControl+2+(16*2)*8)
-#define GUS41DMACtrl      (VSRVolRampControl+2+(16*2)*8+1)
-#define GUS45TimerCtrl    (VSRVolRampControl+2+(16*2)*8+2)
-#define GUS46Counter1     (VSRVolRampControl+2+(16*2)*8+3)
-
-#define GUS47Counter2     (VSRVolRampControl+2+(16*2)*9)
-#define GUS49SampCtrl     (VSRVolRampControl+2+(16*2)*9+1)
-#define GUS4cReset        (VSRVolRampControl+2+(16*2)*9+2)
-#define NumVoices         (VSRVolRampControl+2+(16*2)*9+3)
-
-#define TimerIRQs         (VSRVolRampControl+2+(16*2)*10)   /* delayed IRQ, statistics */
-#define BusyTimerIRQs     (VSRVolRampControl+2+(16*2)*10+2) /* delayed IRQ, statistics */
-
-#define AdLibCommand2xA   (VSRVolRampControl+2+(16*2)*11)
-#define AdLibData2x9      (VSRVolRampControl+2+(16*2)*11+1)
-#define SB2xCd            (VSRVolRampControl+2+(16*2)*11+2)
-#define SB2xE             (VSRVolRampControl+2+(16*2)*11+3)
-
-#define SynVoiceIRQ8f     (VSRVolRampControl+2+(16*2)*12)
-#define GUS50DMAHigh      (VSRVolRampControl+2+(16*2)*12+1)
-
-#define portaccesses (VSRegsEnd) /* statistics / suspend mode */
-
-#define gusdataend (VSRegsEnd+4)
-
-#endif  /* gustate.h */
diff --git a/hw/hd-geometry.c b/hw/hd-geometry.c
deleted file mode 100644 (file)
index c305143..0000000
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * Hard disk geometry utilities
- *
- * Copyright (C) 2012 Red Hat, Inc.
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- *
- * This file incorporates work covered by the following copyright and
- * permission notice:
- *
- * 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.
- */
-
-#include "block/block.h"
-#include "hw/block-common.h"
-#include "trace.h"
-
-struct partition {
-        uint8_t boot_ind;           /* 0x80 - active */
-        uint8_t head;               /* starting head */
-        uint8_t sector;             /* starting sector */
-        uint8_t cyl;                /* starting cylinder */
-        uint8_t sys_ind;            /* What partition type */
-        uint8_t end_head;           /* end head */
-        uint8_t end_sector;         /* end sector */
-        uint8_t end_cyl;            /* end cylinder */
-        uint32_t start_sect;        /* starting sector counting from 0 */
-        uint32_t nr_sects;          /* nr of sectors in partition */
-} QEMU_PACKED;
-
-/* try to guess the disk logical geometry from the MSDOS partition table.
-   Return 0 if OK, -1 if could not guess */
-static int guess_disk_lchs(BlockDriverState *bs,
-                           int *pcylinders, int *pheads, int *psectors)
-{
-    uint8_t buf[BDRV_SECTOR_SIZE];
-    int i, heads, sectors, cylinders;
-    struct partition *p;
-    uint32_t nr_sects;
-    uint64_t nb_sectors;
-
-    bdrv_get_geometry(bs, &nb_sectors);
-
-    /**
-     * The function will be invoked during startup not only in sync I/O mode,
-     * but also in async I/O mode. So the I/O throttling function has to
-     * be disabled temporarily here, not permanently.
-     */
-    if (bdrv_read_unthrottled(bs, 0, buf, 1) < 0) {
-        return -1;
-    }
-    /* test msdos magic */
-    if (buf[510] != 0x55 || buf[511] != 0xaa) {
-        return -1;
-    }
-    for (i = 0; i < 4; i++) {
-        p = ((struct partition *)(buf + 0x1be)) + i;
-        nr_sects = le32_to_cpu(p->nr_sects);
-        if (nr_sects && p->end_head) {
-            /* We make the assumption that the partition terminates on
-               a cylinder boundary */
-            heads = p->end_head + 1;
-            sectors = p->end_sector & 63;
-            if (sectors == 0) {
-                continue;
-            }
-            cylinders = nb_sectors / (heads * sectors);
-            if (cylinders < 1 || cylinders > 16383) {
-                continue;
-            }
-            *pheads = heads;
-            *psectors = sectors;
-            *pcylinders = cylinders;
-            trace_hd_geometry_lchs_guess(bs, cylinders, heads, sectors);
-            return 0;
-        }
-    }
-    return -1;
-}
-
-static void guess_chs_for_size(BlockDriverState *bs,
-                uint32_t *pcyls, uint32_t *pheads, uint32_t *psecs)
-{
-    uint64_t nb_sectors;
-    int cylinders;
-
-    bdrv_get_geometry(bs, &nb_sectors);
-
-    cylinders = nb_sectors / (16 * 63);
-    if (cylinders > 16383) {
-        cylinders = 16383;
-    } else if (cylinders < 2) {
-        cylinders = 2;
-    }
-    *pcyls = cylinders;
-    *pheads = 16;
-    *psecs = 63;
-}
-
-void hd_geometry_guess(BlockDriverState *bs,
-                       uint32_t *pcyls, uint32_t *pheads, uint32_t *psecs,
-                       int *ptrans)
-{
-    int cylinders, heads, secs, translation;
-
-    if (guess_disk_lchs(bs, &cylinders, &heads, &secs) < 0) {
-        /* no LCHS guess: use a standard physical disk geometry  */
-        guess_chs_for_size(bs, pcyls, pheads, psecs);
-        translation = hd_bios_chs_auto_trans(*pcyls, *pheads, *psecs);
-    } else if (heads > 16) {
-        /* LCHS guess with heads > 16 means that a BIOS LBA
-           translation was active, so a standard physical disk
-           geometry is OK */
-        guess_chs_for_size(bs, pcyls, pheads, psecs);
-        translation = *pcyls * *pheads <= 131072
-            ? BIOS_ATA_TRANSLATION_LARGE
-            : BIOS_ATA_TRANSLATION_LBA;
-    } else {
-        /* LCHS guess with heads <= 16: use as physical geometry */
-        *pcyls = cylinders;
-        *pheads = heads;
-        *psecs = secs;
-        /* disable any translation to be in sync with
-           the logical geometry */
-        translation = BIOS_ATA_TRANSLATION_NONE;
-    }
-    if (ptrans) {
-        *ptrans = translation;
-    }
-    trace_hd_geometry_guess(bs, *pcyls, *pheads, *psecs, translation);
-}
-
-int hd_bios_chs_auto_trans(uint32_t cyls, uint32_t heads, uint32_t secs)
-{
-    return cyls <= 1024 && heads <= 16 && secs <= 63
-        ? BIOS_ATA_TRANSLATION_NONE
-        : BIOS_ATA_TRANSLATION_LBA;
-}
diff --git a/hw/hda-audio.c b/hw/hda-audio.c
deleted file mode 100644 (file)
index 6bdd820..0000000
+++ /dev/null
@@ -1,1098 +0,0 @@
-/*
- * Copyright (C) 2010 Red Hat, Inc.
- *
- * written by Gerd Hoffmann <kraxel@redhat.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 or
- * (at your option) version 3 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
- * 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 "hw/hw.h"
-#include "hw/pci/pci.h"
-#include "hw/intel-hda.h"
-#include "hw/intel-hda-defs.h"
-#include "audio/audio.h"
-
-/* -------------------------------------------------------------------------- */
-
-typedef struct desc_param {
-    uint32_t id;
-    uint32_t val;
-} desc_param;
-
-typedef struct desc_node {
-    uint32_t nid;
-    const char *name;
-    const desc_param *params;
-    uint32_t nparams;
-    uint32_t config;
-    uint32_t pinctl;
-    uint32_t *conn;
-    uint32_t stindex;
-} desc_node;
-
-typedef struct desc_codec {
-    const char *name;
-    uint32_t iid;
-    const desc_node *nodes;
-    uint32_t nnodes;
-} desc_codec;
-
-static const desc_param* hda_codec_find_param(const desc_node *node, uint32_t id)
-{
-    int i;
-
-    for (i = 0; i < node->nparams; i++) {
-        if (node->params[i].id == id) {
-            return &node->params[i];
-        }
-    }
-    return NULL;
-}
-
-static const desc_node* hda_codec_find_node(const desc_codec *codec, uint32_t nid)
-{
-    int i;
-
-    for (i = 0; i < codec->nnodes; i++) {
-        if (codec->nodes[i].nid == nid) {
-            return &codec->nodes[i];
-        }
-    }
-    return NULL;
-}
-
-static void hda_codec_parse_fmt(uint32_t format, struct audsettings *as)
-{
-    if (format & AC_FMT_TYPE_NON_PCM) {
-        return;
-    }
-
-    as->freq = (format & AC_FMT_BASE_44K) ? 44100 : 48000;
-
-    switch ((format & AC_FMT_MULT_MASK) >> AC_FMT_MULT_SHIFT) {
-    case 1: as->freq *= 2; break;
-    case 2: as->freq *= 3; break;
-    case 3: as->freq *= 4; break;
-    }
-
-    switch ((format & AC_FMT_DIV_MASK) >> AC_FMT_DIV_SHIFT) {
-    case 1: as->freq /= 2; break;
-    case 2: as->freq /= 3; break;
-    case 3: as->freq /= 4; break;
-    case 4: as->freq /= 5; break;
-    case 5: as->freq /= 6; break;
-    case 6: as->freq /= 7; break;
-    case 7: as->freq /= 8; break;
-    }
-
-    switch (format & AC_FMT_BITS_MASK) {
-    case AC_FMT_BITS_8:  as->fmt = AUD_FMT_S8;  break;
-    case AC_FMT_BITS_16: as->fmt = AUD_FMT_S16; break;
-    case AC_FMT_BITS_32: as->fmt = AUD_FMT_S32; break;
-    }
-
-    as->nchannels = ((format & AC_FMT_CHAN_MASK) >> AC_FMT_CHAN_SHIFT) + 1;
-}
-
-/* -------------------------------------------------------------------------- */
-/*
- * HDA codec descriptions
- */
-
-/* some defines */
-
-#define QEMU_HDA_ID_VENDOR  0x1af4
-#define QEMU_HDA_PCM_FORMATS (AC_SUPPCM_BITS_16 |       \
-                              0x1fc /* 16 -> 96 kHz */)
-#define QEMU_HDA_AMP_NONE    (0)
-#define QEMU_HDA_AMP_STEPS   0x4a
-
-#ifdef CONFIG_MIXEMU
-# define QEMU_HDA_ID_OUTPUT  ((QEMU_HDA_ID_VENDOR << 16) | 0x12)
-# define QEMU_HDA_ID_DUPLEX  ((QEMU_HDA_ID_VENDOR << 16) | 0x22)
-# define QEMU_HDA_ID_MICRO   ((QEMU_HDA_ID_VENDOR << 16) | 0x32)
-# define QEMU_HDA_AMP_CAPS                                              \
-    (AC_AMPCAP_MUTE |                                                   \
-     (QEMU_HDA_AMP_STEPS << AC_AMPCAP_OFFSET_SHIFT)    |                \
-     (QEMU_HDA_AMP_STEPS << AC_AMPCAP_NUM_STEPS_SHIFT) |                \
-     (3                  << AC_AMPCAP_STEP_SIZE_SHIFT))
-#else
-# define QEMU_HDA_ID_OUTPUT  ((QEMU_HDA_ID_VENDOR << 16) | 0x11)
-# define QEMU_HDA_ID_DUPLEX  ((QEMU_HDA_ID_VENDOR << 16) | 0x21)
-# define QEMU_HDA_ID_MICRO   ((QEMU_HDA_ID_VENDOR << 16) | 0x31)
-# define QEMU_HDA_AMP_CAPS   QEMU_HDA_AMP_NONE
-#endif
-
-/* common: audio output widget */
-static const desc_param common_params_audio_dac[] = {
-    {
-        .id  = AC_PAR_AUDIO_WIDGET_CAP,
-        .val = ((AC_WID_AUD_OUT << AC_WCAP_TYPE_SHIFT) |
-                AC_WCAP_FORMAT_OVRD |
-                AC_WCAP_AMP_OVRD |
-                AC_WCAP_OUT_AMP |
-                AC_WCAP_STEREO),
-    },{
-        .id  = AC_PAR_PCM,
-        .val = QEMU_HDA_PCM_FORMATS,
-    },{
-        .id  = AC_PAR_STREAM,
-        .val = AC_SUPFMT_PCM,
-    },{
-        .id  = AC_PAR_AMP_IN_CAP,
-        .val = QEMU_HDA_AMP_NONE,
-    },{
-        .id  = AC_PAR_AMP_OUT_CAP,
-        .val = QEMU_HDA_AMP_CAPS,
-    },
-};
-
-/* common: audio input widget */
-static const desc_param common_params_audio_adc[] = {
-    {
-        .id  = AC_PAR_AUDIO_WIDGET_CAP,
-        .val = ((AC_WID_AUD_IN << AC_WCAP_TYPE_SHIFT) |
-                AC_WCAP_CONN_LIST |
-                AC_WCAP_FORMAT_OVRD |
-                AC_WCAP_AMP_OVRD |
-                AC_WCAP_IN_AMP |
-                AC_WCAP_STEREO),
-    },{
-        .id  = AC_PAR_CONNLIST_LEN,
-        .val = 1,
-    },{
-        .id  = AC_PAR_PCM,
-        .val = QEMU_HDA_PCM_FORMATS,
-    },{
-        .id  = AC_PAR_STREAM,
-        .val = AC_SUPFMT_PCM,
-    },{
-        .id  = AC_PAR_AMP_IN_CAP,
-        .val = QEMU_HDA_AMP_CAPS,
-    },{
-        .id  = AC_PAR_AMP_OUT_CAP,
-        .val = QEMU_HDA_AMP_NONE,
-    },
-};
-
-/* common: pin widget (line-out) */
-static const desc_param common_params_audio_lineout[] = {
-    {
-        .id  = AC_PAR_AUDIO_WIDGET_CAP,
-        .val = ((AC_WID_PIN << AC_WCAP_TYPE_SHIFT) |
-                AC_WCAP_CONN_LIST |
-                AC_WCAP_STEREO),
-    },{
-        .id  = AC_PAR_PIN_CAP,
-        .val = AC_PINCAP_OUT,
-    },{
-        .id  = AC_PAR_CONNLIST_LEN,
-        .val = 1,
-    },{
-        .id  = AC_PAR_AMP_IN_CAP,
-        .val = QEMU_HDA_AMP_NONE,
-    },{
-        .id  = AC_PAR_AMP_OUT_CAP,
-        .val = QEMU_HDA_AMP_NONE,
-    },
-};
-
-/* common: pin widget (line-in) */
-static const desc_param common_params_audio_linein[] = {
-    {
-        .id  = AC_PAR_AUDIO_WIDGET_CAP,
-        .val = ((AC_WID_PIN << AC_WCAP_TYPE_SHIFT) |
-                AC_WCAP_STEREO),
-    },{
-        .id  = AC_PAR_PIN_CAP,
-        .val = AC_PINCAP_IN,
-    },{
-        .id  = AC_PAR_AMP_IN_CAP,
-        .val = QEMU_HDA_AMP_NONE,
-    },{
-        .id  = AC_PAR_AMP_OUT_CAP,
-        .val = QEMU_HDA_AMP_NONE,
-    },
-};
-
-/* output: root node */
-static const desc_param output_params_root[] = {
-    {
-        .id  = AC_PAR_VENDOR_ID,
-        .val = QEMU_HDA_ID_OUTPUT,
-    },{
-        .id  = AC_PAR_SUBSYSTEM_ID,
-        .val = QEMU_HDA_ID_OUTPUT,
-    },{
-        .id  = AC_PAR_REV_ID,
-        .val = 0x00100101,
-    },{
-        .id  = AC_PAR_NODE_COUNT,
-        .val = 0x00010001,
-    },
-};
-
-/* output: audio function */
-static const desc_param output_params_audio_func[] = {
-    {
-        .id  = AC_PAR_FUNCTION_TYPE,
-        .val = AC_GRP_AUDIO_FUNCTION,
-    },{
-        .id  = AC_PAR_SUBSYSTEM_ID,
-        .val = QEMU_HDA_ID_OUTPUT,
-    },{
-        .id  = AC_PAR_NODE_COUNT,
-        .val = 0x00020002,
-    },{
-        .id  = AC_PAR_PCM,
-        .val = QEMU_HDA_PCM_FORMATS,
-    },{
-        .id  = AC_PAR_STREAM,
-        .val = AC_SUPFMT_PCM,
-    },{
-        .id  = AC_PAR_AMP_IN_CAP,
-        .val = QEMU_HDA_AMP_NONE,
-    },{
-        .id  = AC_PAR_AMP_OUT_CAP,
-        .val = QEMU_HDA_AMP_NONE,
-    },{
-        .id  = AC_PAR_GPIO_CAP,
-        .val = 0,
-    },{
-        .id  = AC_PAR_AUDIO_FG_CAP,
-        .val = 0x00000808,
-    },{
-        .id  = AC_PAR_POWER_STATE,
-        .val = 0,
-    },
-};
-
-/* output: nodes */
-static const desc_node output_nodes[] = {
-    {
-        .nid     = AC_NODE_ROOT,
-        .name    = "root",
-        .params  = output_params_root,
-        .nparams = ARRAY_SIZE(output_params_root),
-    },{
-        .nid     = 1,
-        .name    = "func",
-        .params  = output_params_audio_func,
-        .nparams = ARRAY_SIZE(output_params_audio_func),
-    },{
-        .nid     = 2,
-        .name    = "dac",
-        .params  = common_params_audio_dac,
-        .nparams = ARRAY_SIZE(common_params_audio_dac),
-        .stindex = 0,
-    },{
-        .nid     = 3,
-        .name    = "out",
-        .params  = common_params_audio_lineout,
-        .nparams = ARRAY_SIZE(common_params_audio_lineout),
-        .config  = ((AC_JACK_PORT_COMPLEX << AC_DEFCFG_PORT_CONN_SHIFT) |
-                    (AC_JACK_LINE_OUT     << AC_DEFCFG_DEVICE_SHIFT)    |
-                    (AC_JACK_CONN_UNKNOWN << AC_DEFCFG_CONN_TYPE_SHIFT) |
-                    (AC_JACK_COLOR_GREEN  << AC_DEFCFG_COLOR_SHIFT)     |
-                    0x10),
-        .pinctl  = AC_PINCTL_OUT_EN,
-        .conn    = (uint32_t[]) { 2 },
-    }
-};
-
-/* output: codec */
-static const desc_codec output = {
-    .name   = "output",
-    .iid    = QEMU_HDA_ID_OUTPUT,
-    .nodes  = output_nodes,
-    .nnodes = ARRAY_SIZE(output_nodes),
-};
-
-/* duplex: root node */
-static const desc_param duplex_params_root[] = {
-    {
-        .id  = AC_PAR_VENDOR_ID,
-        .val = QEMU_HDA_ID_DUPLEX,
-    },{
-        .id  = AC_PAR_SUBSYSTEM_ID,
-        .val = QEMU_HDA_ID_DUPLEX,
-    },{
-        .id  = AC_PAR_REV_ID,
-        .val = 0x00100101,
-    },{
-        .id  = AC_PAR_NODE_COUNT,
-        .val = 0x00010001,
-    },
-};
-
-/* duplex: audio function */
-static const desc_param duplex_params_audio_func[] = {
-    {
-        .id  = AC_PAR_FUNCTION_TYPE,
-        .val = AC_GRP_AUDIO_FUNCTION,
-    },{
-        .id  = AC_PAR_SUBSYSTEM_ID,
-        .val = QEMU_HDA_ID_DUPLEX,
-    },{
-        .id  = AC_PAR_NODE_COUNT,
-        .val = 0x00020004,
-    },{
-        .id  = AC_PAR_PCM,
-        .val = QEMU_HDA_PCM_FORMATS,
-    },{
-        .id  = AC_PAR_STREAM,
-        .val = AC_SUPFMT_PCM,
-    },{
-        .id  = AC_PAR_AMP_IN_CAP,
-        .val = QEMU_HDA_AMP_NONE,
-    },{
-        .id  = AC_PAR_AMP_OUT_CAP,
-        .val = QEMU_HDA_AMP_NONE,
-    },{
-        .id  = AC_PAR_GPIO_CAP,
-        .val = 0,
-    },{
-        .id  = AC_PAR_AUDIO_FG_CAP,
-        .val = 0x00000808,
-    },{
-        .id  = AC_PAR_POWER_STATE,
-        .val = 0,
-    },
-};
-
-/* duplex: nodes */
-static const desc_node duplex_nodes[] = {
-    {
-        .nid     = AC_NODE_ROOT,
-        .name    = "root",
-        .params  = duplex_params_root,
-        .nparams = ARRAY_SIZE(duplex_params_root),
-    },{
-        .nid     = 1,
-        .name    = "func",
-        .params  = duplex_params_audio_func,
-        .nparams = ARRAY_SIZE(duplex_params_audio_func),
-    },{
-        .nid     = 2,
-        .name    = "dac",
-        .params  = common_params_audio_dac,
-        .nparams = ARRAY_SIZE(common_params_audio_dac),
-        .stindex = 0,
-    },{
-        .nid     = 3,
-        .name    = "out",
-        .params  = common_params_audio_lineout,
-        .nparams = ARRAY_SIZE(common_params_audio_lineout),
-        .config  = ((AC_JACK_PORT_COMPLEX << AC_DEFCFG_PORT_CONN_SHIFT) |
-                    (AC_JACK_LINE_OUT     << AC_DEFCFG_DEVICE_SHIFT)    |
-                    (AC_JACK_CONN_UNKNOWN << AC_DEFCFG_CONN_TYPE_SHIFT) |
-                    (AC_JACK_COLOR_GREEN  << AC_DEFCFG_COLOR_SHIFT)     |
-                    0x10),
-        .pinctl  = AC_PINCTL_OUT_EN,
-        .conn    = (uint32_t[]) { 2 },
-    },{
-        .nid     = 4,
-        .name    = "adc",
-        .params  = common_params_audio_adc,
-        .nparams = ARRAY_SIZE(common_params_audio_adc),
-        .stindex = 1,
-        .conn    = (uint32_t[]) { 5 },
-    },{
-        .nid     = 5,
-        .name    = "in",
-        .params  = common_params_audio_linein,
-        .nparams = ARRAY_SIZE(common_params_audio_linein),
-        .config  = ((AC_JACK_PORT_COMPLEX << AC_DEFCFG_PORT_CONN_SHIFT) |
-                    (AC_JACK_LINE_IN      << AC_DEFCFG_DEVICE_SHIFT)    |
-                    (AC_JACK_CONN_UNKNOWN << AC_DEFCFG_CONN_TYPE_SHIFT) |
-                    (AC_JACK_COLOR_RED    << AC_DEFCFG_COLOR_SHIFT)     |
-                    0x20),
-        .pinctl  = AC_PINCTL_IN_EN,
-    }
-};
-
-/* duplex: codec */
-static const desc_codec duplex = {
-    .name   = "duplex",
-    .iid    = QEMU_HDA_ID_DUPLEX,
-    .nodes  = duplex_nodes,
-    .nnodes = ARRAY_SIZE(duplex_nodes),
-};
-
-/* micro: root node */
-static const desc_param micro_params_root[] = {
-    {
-        .id  = AC_PAR_VENDOR_ID,
-        .val = QEMU_HDA_ID_MICRO,
-    },{
-        .id  = AC_PAR_SUBSYSTEM_ID,
-        .val = QEMU_HDA_ID_MICRO,
-    },{
-        .id  = AC_PAR_REV_ID,
-        .val = 0x00100101,
-    },{
-        .id  = AC_PAR_NODE_COUNT,
-        .val = 0x00010001,
-    },
-};
-
-/* micro: audio function */
-static const desc_param micro_params_audio_func[] = {
-    {
-        .id  = AC_PAR_FUNCTION_TYPE,
-        .val = AC_GRP_AUDIO_FUNCTION,
-    },{
-        .id  = AC_PAR_SUBSYSTEM_ID,
-        .val = QEMU_HDA_ID_MICRO,
-    },{
-        .id  = AC_PAR_NODE_COUNT,
-        .val = 0x00020004,
-    },{
-        .id  = AC_PAR_PCM,
-        .val = QEMU_HDA_PCM_FORMATS,
-    },{
-        .id  = AC_PAR_STREAM,
-        .val = AC_SUPFMT_PCM,
-    },{
-        .id  = AC_PAR_AMP_IN_CAP,
-        .val = QEMU_HDA_AMP_NONE,
-    },{
-        .id  = AC_PAR_AMP_OUT_CAP,
-        .val = QEMU_HDA_AMP_NONE,
-    },{
-        .id  = AC_PAR_GPIO_CAP,
-        .val = 0,
-    },{
-        .id  = AC_PAR_AUDIO_FG_CAP,
-        .val = 0x00000808,
-    },{
-        .id  = AC_PAR_POWER_STATE,
-        .val = 0,
-    },
-};
-
-/* micro: nodes */
-static const desc_node micro_nodes[] = {
-    {
-        .nid     = AC_NODE_ROOT,
-        .name    = "root",
-        .params  = micro_params_root,
-        .nparams = ARRAY_SIZE(micro_params_root),
-    },{
-        .nid     = 1,
-        .name    = "func",
-        .params  = micro_params_audio_func,
-        .nparams = ARRAY_SIZE(micro_params_audio_func),
-    },{
-        .nid     = 2,
-        .name    = "dac",
-        .params  = common_params_audio_dac,
-        .nparams = ARRAY_SIZE(common_params_audio_dac),
-        .stindex = 0,
-    },{
-        .nid     = 3,
-        .name    = "out",
-        .params  = common_params_audio_lineout,
-        .nparams = ARRAY_SIZE(common_params_audio_lineout),
-        .config  = ((AC_JACK_PORT_COMPLEX << AC_DEFCFG_PORT_CONN_SHIFT) |
-                    (AC_JACK_SPEAKER      << AC_DEFCFG_DEVICE_SHIFT)    |
-                    (AC_JACK_CONN_UNKNOWN << AC_DEFCFG_CONN_TYPE_SHIFT) |
-                    (AC_JACK_COLOR_GREEN  << AC_DEFCFG_COLOR_SHIFT)     |
-                    0x10),
-        .pinctl  = AC_PINCTL_OUT_EN,
-        .conn    = (uint32_t[]) { 2 },
-    },{
-        .nid     = 4,
-        .name    = "adc",
-        .params  = common_params_audio_adc,
-        .nparams = ARRAY_SIZE(common_params_audio_adc),
-        .stindex = 1,
-        .conn    = (uint32_t[]) { 5 },
-    },{
-        .nid     = 5,
-        .name    = "in",
-        .params  = common_params_audio_linein,
-        .nparams = ARRAY_SIZE(common_params_audio_linein),
-        .config  = ((AC_JACK_PORT_COMPLEX << AC_DEFCFG_PORT_CONN_SHIFT) |
-                    (AC_JACK_MIC_IN       << AC_DEFCFG_DEVICE_SHIFT)    |
-                    (AC_JACK_CONN_UNKNOWN << AC_DEFCFG_CONN_TYPE_SHIFT) |
-                    (AC_JACK_COLOR_RED    << AC_DEFCFG_COLOR_SHIFT)     |
-                    0x20),
-        .pinctl  = AC_PINCTL_IN_EN,
-    }
-};
-
-/* micro: codec */
-static const desc_codec micro = {
-    .name   = "micro",
-    .iid    = QEMU_HDA_ID_MICRO,
-    .nodes  = micro_nodes,
-    .nnodes = ARRAY_SIZE(micro_nodes),
-};
-
-/* -------------------------------------------------------------------------- */
-
-static const char *fmt2name[] = {
-    [ AUD_FMT_U8  ] = "PCM-U8",
-    [ AUD_FMT_S8  ] = "PCM-S8",
-    [ AUD_FMT_U16 ] = "PCM-U16",
-    [ AUD_FMT_S16 ] = "PCM-S16",
-    [ AUD_FMT_U32 ] = "PCM-U32",
-    [ AUD_FMT_S32 ] = "PCM-S32",
-};
-
-typedef struct HDAAudioState HDAAudioState;
-typedef struct HDAAudioStream HDAAudioStream;
-
-struct HDAAudioStream {
-    HDAAudioState *state;
-    const desc_node *node;
-    bool output, running;
-    uint32_t stream;
-    uint32_t channel;
-    uint32_t format;
-    uint32_t gain_left, gain_right;
-    bool mute_left, mute_right;
-    struct audsettings as;
-    union {
-        SWVoiceIn *in;
-        SWVoiceOut *out;
-    } voice;
-    uint8_t buf[HDA_BUFFER_SIZE];
-    uint32_t bpos;
-};
-
-struct HDAAudioState {
-    HDACodecDevice hda;
-    const char *name;
-
-    QEMUSoundCard card;
-    const desc_codec *desc;
-    HDAAudioStream st[4];
-    bool running_compat[16];
-    bool running_real[2 * 16];
-
-    /* properties */
-    uint32_t debug;
-};
-
-static void hda_audio_input_cb(void *opaque, int avail)
-{
-    HDAAudioStream *st = opaque;
-    int recv = 0;
-    int len;
-    bool rc;
-
-    while (avail - recv >= sizeof(st->buf)) {
-        if (st->bpos != sizeof(st->buf)) {
-            len = AUD_read(st->voice.in, st->buf + st->bpos,
-                           sizeof(st->buf) - st->bpos);
-            st->bpos += len;
-            recv += len;
-            if (st->bpos != sizeof(st->buf)) {
-                break;
-            }
-        }
-        rc = hda_codec_xfer(&st->state->hda, st->stream, false,
-                            st->buf, sizeof(st->buf));
-        if (!rc) {
-            break;
-        }
-        st->bpos = 0;
-    }
-}
-
-static void hda_audio_output_cb(void *opaque, int avail)
-{
-    HDAAudioStream *st = opaque;
-    int sent = 0;
-    int len;
-    bool rc;
-
-    while (avail - sent >= sizeof(st->buf)) {
-        if (st->bpos == sizeof(st->buf)) {
-            rc = hda_codec_xfer(&st->state->hda, st->stream, true,
-                                st->buf, sizeof(st->buf));
-            if (!rc) {
-                break;
-            }
-            st->bpos = 0;
-        }
-        len = AUD_write(st->voice.out, st->buf + st->bpos,
-                        sizeof(st->buf) - st->bpos);
-        st->bpos += len;
-        sent += len;
-        if (st->bpos != sizeof(st->buf)) {
-            break;
-        }
-    }
-}
-
-static void hda_audio_set_running(HDAAudioStream *st, bool running)
-{
-    if (st->node == NULL) {
-        return;
-    }
-    if (st->running == running) {
-        return;
-    }
-    st->running = running;
-    dprint(st->state, 1, "%s: %s (stream %d)\n", st->node->name,
-           st->running ? "on" : "off", st->stream);
-    if (st->output) {
-        AUD_set_active_out(st->voice.out, st->running);
-    } else {
-        AUD_set_active_in(st->voice.in, st->running);
-    }
-}
-
-static void hda_audio_set_amp(HDAAudioStream *st)
-{
-    bool muted;
-    uint32_t left, right;
-
-    if (st->node == NULL) {
-        return;
-    }
-
-    muted = st->mute_left && st->mute_right;
-    left  = st->mute_left  ? 0 : st->gain_left;
-    right = st->mute_right ? 0 : st->gain_right;
-
-    left = left * 255 / QEMU_HDA_AMP_STEPS;
-    right = right * 255 / QEMU_HDA_AMP_STEPS;
-
-    if (st->output) {
-        AUD_set_volume_out(st->voice.out, muted, left, right);
-    } else {
-        AUD_set_volume_in(st->voice.in, muted, left, right);
-    }
-}
-
-static void hda_audio_setup(HDAAudioStream *st)
-{
-    if (st->node == NULL) {
-        return;
-    }
-
-    dprint(st->state, 1, "%s: format: %d x %s @ %d Hz\n",
-           st->node->name, st->as.nchannels,
-           fmt2name[st->as.fmt], st->as.freq);
-
-    if (st->output) {
-        st->voice.out = AUD_open_out(&st->state->card, st->voice.out,
-                                     st->node->name, st,
-                                     hda_audio_output_cb, &st->as);
-    } else {
-        st->voice.in = AUD_open_in(&st->state->card, st->voice.in,
-                                   st->node->name, st,
-                                   hda_audio_input_cb, &st->as);
-    }
-}
-
-static void hda_audio_command(HDACodecDevice *hda, uint32_t nid, uint32_t data)
-{
-    HDAAudioState *a = DO_UPCAST(HDAAudioState, hda, hda);
-    HDAAudioStream *st;
-    const desc_node *node = NULL;
-    const desc_param *param;
-    uint32_t verb, payload, response, count, shift;
-
-    if ((data & 0x70000) == 0x70000) {
-        /* 12/8 id/payload */
-        verb = (data >> 8) & 0xfff;
-        payload = data & 0x00ff;
-    } else {
-        /* 4/16 id/payload */
-        verb = (data >> 8) & 0xf00;
-        payload = data & 0xffff;
-    }
-
-    node = hda_codec_find_node(a->desc, nid);
-    if (node == NULL) {
-        goto fail;
-    }
-    dprint(a, 2, "%s: nid %d (%s), verb 0x%x, payload 0x%x\n",
-           __FUNCTION__, nid, node->name, verb, payload);
-
-    switch (verb) {
-    /* all nodes */
-    case AC_VERB_PARAMETERS:
-        param = hda_codec_find_param(node, payload);
-        if (param == NULL) {
-            goto fail;
-        }
-        hda_codec_response(hda, true, param->val);
-        break;
-    case AC_VERB_GET_SUBSYSTEM_ID:
-        hda_codec_response(hda, true, a->desc->iid);
-        break;
-
-    /* all functions */
-    case AC_VERB_GET_CONNECT_LIST:
-        param = hda_codec_find_param(node, AC_PAR_CONNLIST_LEN);
-        count = param ? param->val : 0;
-        response = 0;
-        shift = 0;
-        while (payload < count && shift < 32) {
-            response |= node->conn[payload] << shift;
-            payload++;
-            shift += 8;
-        }
-        hda_codec_response(hda, true, response);
-        break;
-
-    /* pin widget */
-    case AC_VERB_GET_CONFIG_DEFAULT:
-        hda_codec_response(hda, true, node->config);
-        break;
-    case AC_VERB_GET_PIN_WIDGET_CONTROL:
-        hda_codec_response(hda, true, node->pinctl);
-        break;
-    case AC_VERB_SET_PIN_WIDGET_CONTROL:
-        if (node->pinctl != payload) {
-            dprint(a, 1, "unhandled pin control bit\n");
-        }
-        hda_codec_response(hda, true, 0);
-        break;
-
-    /* audio in/out widget */
-    case AC_VERB_SET_CHANNEL_STREAMID:
-        st = a->st + node->stindex;
-        if (st->node == NULL) {
-            goto fail;
-        }
-        hda_audio_set_running(st, false);
-        st->stream = (payload >> 4) & 0x0f;
-        st->channel = payload & 0x0f;
-        dprint(a, 2, "%s: stream %d, channel %d\n",
-               st->node->name, st->stream, st->channel);
-        hda_audio_set_running(st, a->running_real[st->output * 16 + st->stream]);
-        hda_codec_response(hda, true, 0);
-        break;
-    case AC_VERB_GET_CONV:
-        st = a->st + node->stindex;
-        if (st->node == NULL) {
-            goto fail;
-        }
-        response = st->stream << 4 | st->channel;
-        hda_codec_response(hda, true, response);
-        break;
-    case AC_VERB_SET_STREAM_FORMAT:
-        st = a->st + node->stindex;
-        if (st->node == NULL) {
-            goto fail;
-        }
-        st->format = payload;
-        hda_codec_parse_fmt(st->format, &st->as);
-        hda_audio_setup(st);
-        hda_codec_response(hda, true, 0);
-        break;
-    case AC_VERB_GET_STREAM_FORMAT:
-        st = a->st + node->stindex;
-        if (st->node == NULL) {
-            goto fail;
-        }
-        hda_codec_response(hda, true, st->format);
-        break;
-    case AC_VERB_GET_AMP_GAIN_MUTE:
-        st = a->st + node->stindex;
-        if (st->node == NULL) {
-            goto fail;
-        }
-        if (payload & AC_AMP_GET_LEFT) {
-            response = st->gain_left | (st->mute_left ? AC_AMP_MUTE : 0);
-        } else {
-            response = st->gain_right | (st->mute_right ? AC_AMP_MUTE : 0);
-        }
-        hda_codec_response(hda, true, response);
-        break;
-    case AC_VERB_SET_AMP_GAIN_MUTE:
-        st = a->st + node->stindex;
-        if (st->node == NULL) {
-            goto fail;
-        }
-        dprint(a, 1, "amp (%s): %s%s%s%s index %d  gain %3d %s\n",
-               st->node->name,
-               (payload & AC_AMP_SET_OUTPUT) ? "o" : "-",
-               (payload & AC_AMP_SET_INPUT)  ? "i" : "-",
-               (payload & AC_AMP_SET_LEFT)   ? "l" : "-",
-               (payload & AC_AMP_SET_RIGHT)  ? "r" : "-",
-               (payload & AC_AMP_SET_INDEX) >> AC_AMP_SET_INDEX_SHIFT,
-               (payload & AC_AMP_GAIN),
-               (payload & AC_AMP_MUTE) ? "muted" : "");
-        if (payload & AC_AMP_SET_LEFT) {
-            st->gain_left = payload & AC_AMP_GAIN;
-            st->mute_left = payload & AC_AMP_MUTE;
-        }
-        if (payload & AC_AMP_SET_RIGHT) {
-            st->gain_right = payload & AC_AMP_GAIN;
-            st->mute_right = payload & AC_AMP_MUTE;
-        }
-        hda_audio_set_amp(st);
-        hda_codec_response(hda, true, 0);
-        break;
-
-    /* not supported */
-    case AC_VERB_SET_POWER_STATE:
-    case AC_VERB_GET_POWER_STATE:
-    case AC_VERB_GET_SDI_SELECT:
-        hda_codec_response(hda, true, 0);
-        break;
-    default:
-        goto fail;
-    }
-    return;
-
-fail:
-    dprint(a, 1, "%s: not handled: nid %d (%s), verb 0x%x, payload 0x%x\n",
-           __FUNCTION__, nid, node ? node->name : "?", verb, payload);
-    hda_codec_response(hda, true, 0);
-}
-
-static void hda_audio_stream(HDACodecDevice *hda, uint32_t stnr, bool running, bool output)
-{
-    HDAAudioState *a = DO_UPCAST(HDAAudioState, hda, hda);
-    int s;
-
-    a->running_compat[stnr] = running;
-    a->running_real[output * 16 + stnr] = running;
-    for (s = 0; s < ARRAY_SIZE(a->st); s++) {
-        if (a->st[s].node == NULL) {
-            continue;
-        }
-        if (a->st[s].output != output) {
-            continue;
-        }
-        if (a->st[s].stream != stnr) {
-            continue;
-        }
-        hda_audio_set_running(&a->st[s], running);
-    }
-}
-
-static int hda_audio_init(HDACodecDevice *hda, const struct desc_codec *desc)
-{
-    HDAAudioState *a = DO_UPCAST(HDAAudioState, hda, hda);
-    HDAAudioStream *st;
-    const desc_node *node;
-    const desc_param *param;
-    uint32_t i, type;
-
-    a->desc = desc;
-    a->name = object_get_typename(OBJECT(a));
-    dprint(a, 1, "%s: cad %d\n", __FUNCTION__, a->hda.cad);
-
-    AUD_register_card("hda", &a->card);
-    for (i = 0; i < a->desc->nnodes; i++) {
-        node = a->desc->nodes + i;
-        param = hda_codec_find_param(node, AC_PAR_AUDIO_WIDGET_CAP);
-        if (NULL == param)
-            continue;
-        type = (param->val & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
-        switch (type) {
-        case AC_WID_AUD_OUT:
-        case AC_WID_AUD_IN:
-            assert(node->stindex < ARRAY_SIZE(a->st));
-            st = a->st + node->stindex;
-            st->state = a;
-            st->node = node;
-            if (type == AC_WID_AUD_OUT) {
-                /* unmute output by default */
-                st->gain_left = QEMU_HDA_AMP_STEPS;
-                st->gain_right = QEMU_HDA_AMP_STEPS;
-                st->bpos = sizeof(st->buf);
-                st->output = true;
-            } else {
-                st->output = false;
-            }
-            st->format = AC_FMT_TYPE_PCM | AC_FMT_BITS_16 |
-                (1 << AC_FMT_CHAN_SHIFT);
-            hda_codec_parse_fmt(st->format, &st->as);
-            hda_audio_setup(st);
-            break;
-        }
-    }
-    return 0;
-}
-
-static int hda_audio_exit(HDACodecDevice *hda)
-{
-    HDAAudioState *a = DO_UPCAST(HDAAudioState, hda, hda);
-    HDAAudioStream *st;
-    int i;
-
-    dprint(a, 1, "%s\n", __FUNCTION__);
-    for (i = 0; i < ARRAY_SIZE(a->st); i++) {
-        st = a->st + i;
-        if (st->node == NULL) {
-            continue;
-        }
-        if (st->output) {
-            AUD_close_out(&a->card, st->voice.out);
-        } else {
-            AUD_close_in(&a->card, st->voice.in);
-        }
-    }
-    AUD_remove_card(&a->card);
-    return 0;
-}
-
-static int hda_audio_post_load(void *opaque, int version)
-{
-    HDAAudioState *a = opaque;
-    HDAAudioStream *st;
-    int i;
-
-    dprint(a, 1, "%s\n", __FUNCTION__);
-    if (version == 1) {
-        /* assume running_compat[] is for output streams */
-        for (i = 0; i < ARRAY_SIZE(a->running_compat); i++)
-            a->running_real[16 + i] = a->running_compat[i];
-    }
-
-    for (i = 0; i < ARRAY_SIZE(a->st); i++) {
-        st = a->st + i;
-        if (st->node == NULL)
-            continue;
-        hda_codec_parse_fmt(st->format, &st->as);
-        hda_audio_setup(st);
-        hda_audio_set_amp(st);
-        hda_audio_set_running(st, a->running_real[st->output * 16 + st->stream]);
-    }
-    return 0;
-}
-
-static const VMStateDescription vmstate_hda_audio_stream = {
-    .name = "hda-audio-stream",
-    .version_id = 1,
-    .fields = (VMStateField []) {
-        VMSTATE_UINT32(stream, HDAAudioStream),
-        VMSTATE_UINT32(channel, HDAAudioStream),
-        VMSTATE_UINT32(format, HDAAudioStream),
-        VMSTATE_UINT32(gain_left, HDAAudioStream),
-        VMSTATE_UINT32(gain_right, HDAAudioStream),
-        VMSTATE_BOOL(mute_left, HDAAudioStream),
-        VMSTATE_BOOL(mute_right, HDAAudioStream),
-        VMSTATE_UINT32(bpos, HDAAudioStream),
-        VMSTATE_BUFFER(buf, HDAAudioStream),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static const VMStateDescription vmstate_hda_audio = {
-    .name = "hda-audio",
-    .version_id = 2,
-    .post_load = hda_audio_post_load,
-    .fields = (VMStateField []) {
-        VMSTATE_STRUCT_ARRAY(st, HDAAudioState, 4, 0,
-                             vmstate_hda_audio_stream,
-                             HDAAudioStream),
-        VMSTATE_BOOL_ARRAY(running_compat, HDAAudioState, 16),
-        VMSTATE_BOOL_ARRAY_V(running_real, HDAAudioState, 2 * 16, 2),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static Property hda_audio_properties[] = {
-    DEFINE_PROP_UINT32("debug", HDAAudioState, debug, 0),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static int hda_audio_init_output(HDACodecDevice *hda)
-{
-    return hda_audio_init(hda, &output);
-}
-
-static int hda_audio_init_duplex(HDACodecDevice *hda)
-{
-    return hda_audio_init(hda, &duplex);
-}
-
-static int hda_audio_init_micro(HDACodecDevice *hda)
-{
-    return hda_audio_init(hda, &micro);
-}
-
-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 (line-out)";
-    dc->vmsd = &vmstate_hda_audio;
-    dc->props = hda_audio_properties;
-}
-
-static const 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 (line-out, line-in)";
-    dc->vmsd = &vmstate_hda_audio;
-    dc->props = hda_audio_properties;
-}
-
-static const 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_micro_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    HDACodecDeviceClass *k = HDA_CODEC_DEVICE_CLASS(klass);
-
-    k->init = hda_audio_init_micro;
-    k->exit = hda_audio_exit;
-    k->command = hda_audio_command;
-    k->stream = hda_audio_stream;
-    dc->desc = "HDA Audio Codec, duplex (speaker, microphone)";
-    dc->vmsd = &vmstate_hda_audio;
-    dc->props = hda_audio_properties;
-}
-
-static const TypeInfo hda_audio_micro_info = {
-    .name          = "hda-micro",
-    .parent        = TYPE_HDA_CODEC_DEVICE,
-    .instance_size = sizeof(HDAAudioState),
-    .class_init    = hda_audio_micro_class_init,
-};
-
-static void hda_audio_register_types(void)
-{
-    type_register_static(&hda_audio_output_info);
-    type_register_static(&hda_audio_duplex_info);
-    type_register_static(&hda_audio_micro_info);
-}
-
-type_init(hda_audio_register_types)
diff --git a/hw/heathrow_pic.c b/hw/heathrow_pic.c
deleted file mode 100644 (file)
index beb9661..0000000
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- * Heathrow PIC support (OldWorld PowerMac)
- *
- * Copyright (c) 2005-2007 Fabrice Bellard
- * Copyright (c) 2007 Jocelyn Mayer
- *
- * 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 "hw/hw.h"
-#include "hw/ppc/mac.h"
-
-/* debug PIC */
-//#define DEBUG_PIC
-
-#ifdef DEBUG_PIC
-#define PIC_DPRINTF(fmt, ...)                                   \
-    do { printf("PIC: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define PIC_DPRINTF(fmt, ...)
-#endif
-
-typedef struct HeathrowPIC {
-    uint32_t events;
-    uint32_t mask;
-    uint32_t levels;
-    uint32_t level_triggered;
-} HeathrowPIC;
-
-typedef struct HeathrowPICS {
-    MemoryRegion mem;
-    HeathrowPIC pics[2];
-    qemu_irq *irqs;
-} HeathrowPICS;
-
-static inline int check_irq(HeathrowPIC *pic)
-{
-    return (pic->events | (pic->levels & pic->level_triggered)) & pic->mask;
-}
-
-/* update the CPU irq state */
-static void heathrow_pic_update(HeathrowPICS *s)
-{
-    if (check_irq(&s->pics[0]) || check_irq(&s->pics[1])) {
-        qemu_irq_raise(s->irqs[0]);
-    } else {
-        qemu_irq_lower(s->irqs[0]);
-    }
-}
-
-static void pic_write(void *opaque, hwaddr addr,
-                      uint64_t value, unsigned size)
-{
-    HeathrowPICS *s = opaque;
-    HeathrowPIC *pic;
-    unsigned int n;
-
-    n = ((addr & 0xfff) - 0x10) >> 4;
-    PIC_DPRINTF("writel: " TARGET_FMT_plx " %u: %08x\n", addr, n, value);
-    if (n >= 2)
-        return;
-    pic = &s->pics[n];
-    switch(addr & 0xf) {
-    case 0x04:
-        pic->mask = value;
-        heathrow_pic_update(s);
-        break;
-    case 0x08:
-        /* do not reset level triggered IRQs */
-        value &= ~pic->level_triggered;
-        pic->events &= ~value;
-        heathrow_pic_update(s);
-        break;
-    default:
-        break;
-    }
-}
-
-static uint64_t pic_read(void *opaque, hwaddr addr,
-                         unsigned size)
-{
-    HeathrowPICS *s = opaque;
-    HeathrowPIC *pic;
-    unsigned int n;
-    uint32_t value;
-
-    n = ((addr & 0xfff) - 0x10) >> 4;
-    if (n >= 2) {
-        value = 0;
-    } else {
-        pic = &s->pics[n];
-        switch(addr & 0xf) {
-        case 0x0:
-            value = pic->events;
-            break;
-        case 0x4:
-            value = pic->mask;
-            break;
-        case 0xc:
-            value = pic->levels;
-            break;
-        default:
-            value = 0;
-            break;
-        }
-    }
-    PIC_DPRINTF("readl: " TARGET_FMT_plx " %u: %08x\n", addr, n, value);
-    return value;
-}
-
-static const MemoryRegionOps heathrow_pic_ops = {
-    .read = pic_read,
-    .write = pic_write,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static void heathrow_pic_set_irq(void *opaque, int num, int level)
-{
-    HeathrowPICS *s = opaque;
-    HeathrowPIC *pic;
-    unsigned int irq_bit;
-
-#if defined(DEBUG)
-    {
-        static int last_level[64];
-        if (last_level[num] != level) {
-            PIC_DPRINTF("set_irq: num=0x%02x level=%d\n", num, level);
-            last_level[num] = level;
-        }
-    }
-#endif
-    pic = &s->pics[1 - (num >> 5)];
-    irq_bit = 1 << (num & 0x1f);
-    if (level) {
-        pic->events |= irq_bit & ~pic->level_triggered;
-        pic->levels |= irq_bit;
-    } else {
-        pic->levels &= ~irq_bit;
-    }
-    heathrow_pic_update(s);
-}
-
-static const VMStateDescription vmstate_heathrow_pic_one = {
-    .name = "heathrow_pic_one",
-    .version_id = 0,
-    .minimum_version_id = 0,
-    .minimum_version_id_old = 0,
-    .fields      = (VMStateField[]) {
-        VMSTATE_UINT32(events, HeathrowPIC),
-        VMSTATE_UINT32(mask, HeathrowPIC),
-        VMSTATE_UINT32(levels, HeathrowPIC),
-        VMSTATE_UINT32(level_triggered, HeathrowPIC),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static const VMStateDescription vmstate_heathrow_pic = {
-    .name = "heathrow_pic",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField[]) {
-        VMSTATE_STRUCT_ARRAY(pics, HeathrowPICS, 2, 1,
-                             vmstate_heathrow_pic_one, HeathrowPIC),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void heathrow_pic_reset_one(HeathrowPIC *s)
-{
-    memset(s, '\0', sizeof(HeathrowPIC));
-}
-
-static void heathrow_pic_reset(void *opaque)
-{
-    HeathrowPICS *s = opaque;
-
-    heathrow_pic_reset_one(&s->pics[0]);
-    heathrow_pic_reset_one(&s->pics[1]);
-
-    s->pics[0].level_triggered = 0;
-    s->pics[1].level_triggered = 0x1ff00000;
-}
-
-qemu_irq *heathrow_pic_init(MemoryRegion **pmem,
-                            int nb_cpus, qemu_irq **irqs)
-{
-    HeathrowPICS *s;
-
-    s = g_malloc0(sizeof(HeathrowPICS));
-    /* only 1 CPU */
-    s->irqs = irqs[0];
-    memory_region_init_io(&s->mem, &heathrow_pic_ops, s,
-                          "heathrow-pic", 0x1000);
-    *pmem = &s->mem;
-
-    vmstate_register(NULL, -1, &vmstate_heathrow_pic, s);
-    qemu_register_reset(heathrow_pic_reset, s);
-    return qemu_allocate_irqs(heathrow_pic_set_irq, s, 64);
-}
diff --git a/hw/hid.c b/hw/hid.c
deleted file mode 100644 (file)
index 28b3474..0000000
--- a/hw/hid.c
+++ /dev/null
@@ -1,498 +0,0 @@
-/*
- * QEMU HID devices
- *
- * Copyright (c) 2005 Fabrice Bellard
- * Copyright (c) 2007 OpenMoko, Inc.  (andrew@openedhand.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.
- */
-#include "hw/hw.h"
-#include "ui/console.h"
-#include "qemu/timer.h"
-#include "hw/hid.h"
-
-#define HID_USAGE_ERROR_ROLLOVER        0x01
-#define HID_USAGE_POSTFAIL              0x02
-#define HID_USAGE_ERROR_UNDEFINED       0x03
-
-/* Indices are QEMU keycodes, values are from HID Usage Table.  Indices
- * above 0x80 are for keys that come after 0xe0 or 0xe1+0x1d or 0xe1+0x9d.  */
-static const uint8_t hid_usage_keys[0x100] = {
-    0x00, 0x29, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
-    0x24, 0x25, 0x26, 0x27, 0x2d, 0x2e, 0x2a, 0x2b,
-    0x14, 0x1a, 0x08, 0x15, 0x17, 0x1c, 0x18, 0x0c,
-    0x12, 0x13, 0x2f, 0x30, 0x28, 0xe0, 0x04, 0x16,
-    0x07, 0x09, 0x0a, 0x0b, 0x0d, 0x0e, 0x0f, 0x33,
-    0x34, 0x35, 0xe1, 0x31, 0x1d, 0x1b, 0x06, 0x19,
-    0x05, 0x11, 0x10, 0x36, 0x37, 0x38, 0xe5, 0x55,
-    0xe2, 0x2c, 0x32, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e,
-    0x3f, 0x40, 0x41, 0x42, 0x43, 0x53, 0x47, 0x5f,
-    0x60, 0x61, 0x56, 0x5c, 0x5d, 0x5e, 0x57, 0x59,
-    0x5a, 0x5b, 0x62, 0x63, 0x00, 0x00, 0x00, 0x44,
-    0x45, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e,
-    0xe8, 0xe9, 0x71, 0x72, 0x73, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0xe3, 0xe7, 0x65,
-
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x58, 0xe4, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x46,
-    0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x4a,
-    0x52, 0x4b, 0x00, 0x50, 0x00, 0x4f, 0x00, 0x4d,
-    0x51, 0x4e, 0x49, 0x4c, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0xe3, 0xe7, 0x65, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-};
-
-bool hid_has_events(HIDState *hs)
-{
-    return hs->n > 0 || hs->idle_pending;
-}
-
-static void hid_idle_timer(void *opaque)
-{
-    HIDState *hs = opaque;
-
-    hs->idle_pending = true;
-    hs->event(hs);
-}
-
-static void hid_del_idle_timer(HIDState *hs)
-{
-    if (hs->idle_timer) {
-        qemu_del_timer(hs->idle_timer);
-        qemu_free_timer(hs->idle_timer);
-        hs->idle_timer = NULL;
-    }
-}
-
-void hid_set_next_idle(HIDState *hs)
-{
-    if (hs->idle) {
-        uint64_t expire_time = qemu_get_clock_ns(vm_clock) +
-                               get_ticks_per_sec() * hs->idle * 4 / 1000;
-        if (!hs->idle_timer) {
-            hs->idle_timer = qemu_new_timer_ns(vm_clock, hid_idle_timer, hs);
-        }
-        qemu_mod_timer_ns(hs->idle_timer, expire_time);
-    } else {
-        hid_del_idle_timer(hs);
-    }
-}
-
-static void hid_pointer_event_clear(HIDPointerEvent *e, int buttons)
-{
-    e->xdx = e->ydy = e->dz = 0;
-    e->buttons_state = buttons;
-}
-
-static void hid_pointer_event_combine(HIDPointerEvent *e, int xyrel,
-                                      int x1, int y1, int z1) {
-    if (xyrel) {
-        e->xdx += x1;
-        e->ydy += y1;
-    } else {
-        e->xdx = x1;
-        e->ydy = y1;
-        /* Windows drivers do not like the 0/0 position and ignore such
-         * events. */
-        if (!(x1 | y1)) {
-            e->xdx = 1;
-        }
-    }
-    e->dz += z1;
-}
-
-static void hid_pointer_event(void *opaque,
-                              int x1, int y1, int z1, int buttons_state)
-{
-    HIDState *hs = opaque;
-    unsigned use_slot = (hs->head + hs->n - 1) & QUEUE_MASK;
-    unsigned previous_slot = (use_slot - 1) & QUEUE_MASK;
-
-    /* We combine events where feasible to keep the queue small.  We shouldn't
-     * combine anything with the first event of a particular button state, as
-     * that would change the location of the button state change.  When the
-     * queue is empty, a second event is needed because we don't know if
-     * the first event changed the button state.  */
-    if (hs->n == QUEUE_LENGTH) {
-        /* Queue full.  Discard old button state, combine motion normally.  */
-        hs->ptr.queue[use_slot].buttons_state = buttons_state;
-    } else if (hs->n < 2 ||
-               hs->ptr.queue[use_slot].buttons_state != buttons_state ||
-               hs->ptr.queue[previous_slot].buttons_state !=
-               hs->ptr.queue[use_slot].buttons_state) {
-        /* Cannot or should not combine, so add an empty item to the queue.  */
-        QUEUE_INCR(use_slot);
-        hs->n++;
-        hid_pointer_event_clear(&hs->ptr.queue[use_slot], buttons_state);
-    }
-    hid_pointer_event_combine(&hs->ptr.queue[use_slot],
-                              hs->kind == HID_MOUSE,
-                              x1, y1, z1);
-    hs->event(hs);
-}
-
-static void hid_keyboard_event(void *opaque, int keycode)
-{
-    HIDState *hs = opaque;
-    int slot;
-
-    if (hs->n == QUEUE_LENGTH) {
-        fprintf(stderr, "usb-kbd: warning: key event queue full\n");
-        return;
-    }
-    slot = (hs->head + hs->n) & QUEUE_MASK; hs->n++;
-    hs->kbd.keycodes[slot] = keycode;
-    hs->event(hs);
-}
-
-static void hid_keyboard_process_keycode(HIDState *hs)
-{
-    uint8_t hid_code, key;
-    int i, keycode, slot;
-
-    if (hs->n == 0) {
-        return;
-    }
-    slot = hs->head & QUEUE_MASK; QUEUE_INCR(hs->head); hs->n--;
-    keycode = hs->kbd.keycodes[slot];
-
-    key = keycode & 0x7f;
-    hid_code = hid_usage_keys[key | ((hs->kbd.modifiers >> 1) & (1 << 7))];
-    hs->kbd.modifiers &= ~(1 << 8);
-
-    switch (hid_code) {
-    case 0x00:
-        return;
-
-    case 0xe0:
-        if (hs->kbd.modifiers & (1 << 9)) {
-            hs->kbd.modifiers ^= 3 << 8;
-            return;
-        }
-    case 0xe1 ... 0xe7:
-        if (keycode & (1 << 7)) {
-            hs->kbd.modifiers &= ~(1 << (hid_code & 0x0f));
-            return;
-        }
-    case 0xe8 ... 0xef:
-        hs->kbd.modifiers |= 1 << (hid_code & 0x0f);
-        return;
-    }
-
-    if (keycode & (1 << 7)) {
-        for (i = hs->kbd.keys - 1; i >= 0; i--) {
-            if (hs->kbd.key[i] == hid_code) {
-                hs->kbd.key[i] = hs->kbd.key[-- hs->kbd.keys];
-                hs->kbd.key[hs->kbd.keys] = 0x00;
-                break;
-            }
-        }
-        if (i < 0) {
-            return;
-        }
-    } else {
-        for (i = hs->kbd.keys - 1; i >= 0; i--) {
-            if (hs->kbd.key[i] == hid_code) {
-                break;
-            }
-        }
-        if (i < 0) {
-            if (hs->kbd.keys < sizeof(hs->kbd.key)) {
-                hs->kbd.key[hs->kbd.keys++] = hid_code;
-            }
-        } else {
-            return;
-        }
-    }
-}
-
-static inline int int_clamp(int val, int vmin, int vmax)
-{
-    if (val < vmin) {
-        return vmin;
-    } else if (val > vmax) {
-        return vmax;
-    } else {
-        return val;
-    }
-}
-
-void hid_pointer_activate(HIDState *hs)
-{
-    if (!hs->ptr.mouse_grabbed) {
-        qemu_activate_mouse_event_handler(hs->ptr.eh_entry);
-        hs->ptr.mouse_grabbed = 1;
-    }
-}
-
-int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len)
-{
-    int dx, dy, dz, b, l;
-    int index;
-    HIDPointerEvent *e;
-
-    hs->idle_pending = false;
-
-    hid_pointer_activate(hs);
-
-    /* When the buffer is empty, return the last event.  Relative
-       movements will all be zero.  */
-    index = (hs->n ? hs->head : hs->head - 1);
-    e = &hs->ptr.queue[index & QUEUE_MASK];
-
-    if (hs->kind == HID_MOUSE) {
-        dx = int_clamp(e->xdx, -127, 127);
-        dy = int_clamp(e->ydy, -127, 127);
-        e->xdx -= dx;
-        e->ydy -= dy;
-    } else {
-        dx = e->xdx;
-        dy = e->ydy;
-    }
-    dz = int_clamp(e->dz, -127, 127);
-    e->dz -= dz;
-
-    b = 0;
-    if (e->buttons_state & MOUSE_EVENT_LBUTTON) {
-        b |= 0x01;
-    }
-    if (e->buttons_state & MOUSE_EVENT_RBUTTON) {
-        b |= 0x02;
-    }
-    if (e->buttons_state & MOUSE_EVENT_MBUTTON) {
-        b |= 0x04;
-    }
-
-    if (hs->n &&
-        !e->dz &&
-        (hs->kind == HID_TABLET || (!e->xdx && !e->ydy))) {
-        /* that deals with this event */
-        QUEUE_INCR(hs->head);
-        hs->n--;
-    }
-
-    /* Appears we have to invert the wheel direction */
-    dz = 0 - dz;
-    l = 0;
-    switch (hs->kind) {
-    case HID_MOUSE:
-        if (len > l) {
-            buf[l++] = b;
-        }
-        if (len > l) {
-            buf[l++] = dx;
-        }
-        if (len > l) {
-            buf[l++] = dy;
-        }
-        if (len > l) {
-            buf[l++] = dz;
-        }
-        break;
-
-    case HID_TABLET:
-        if (len > l) {
-            buf[l++] = b;
-        }
-        if (len > l) {
-            buf[l++] = dx & 0xff;
-        }
-        if (len > l) {
-            buf[l++] = dx >> 8;
-        }
-        if (len > l) {
-            buf[l++] = dy & 0xff;
-        }
-        if (len > l) {
-            buf[l++] = dy >> 8;
-        }
-        if (len > l) {
-            buf[l++] = dz;
-        }
-        break;
-
-    default:
-        abort();
-    }
-
-    return l;
-}
-
-int hid_keyboard_poll(HIDState *hs, uint8_t *buf, int len)
-{
-    hs->idle_pending = false;
-
-    if (len < 2) {
-        return 0;
-    }
-
-    hid_keyboard_process_keycode(hs);
-
-    buf[0] = hs->kbd.modifiers & 0xff;
-    buf[1] = 0;
-    if (hs->kbd.keys > 6) {
-        memset(buf + 2, HID_USAGE_ERROR_ROLLOVER, MIN(8, len) - 2);
-    } else {
-        memcpy(buf + 2, hs->kbd.key, MIN(8, len) - 2);
-    }
-
-    return MIN(8, len);
-}
-
-int hid_keyboard_write(HIDState *hs, uint8_t *buf, int len)
-{
-    if (len > 0) {
-        int ledstate = 0;
-        /* 0x01: Num Lock LED
-         * 0x02: Caps Lock LED
-         * 0x04: Scroll Lock LED
-         * 0x08: Compose LED
-         * 0x10: Kana LED */
-        hs->kbd.leds = buf[0];
-        if (hs->kbd.leds & 0x04) {
-            ledstate |= QEMU_SCROLL_LOCK_LED;
-        }
-        if (hs->kbd.leds & 0x01) {
-            ledstate |= QEMU_NUM_LOCK_LED;
-        }
-        if (hs->kbd.leds & 0x02) {
-            ledstate |= QEMU_CAPS_LOCK_LED;
-        }
-        kbd_put_ledstate(ledstate);
-    }
-    return 0;
-}
-
-void hid_reset(HIDState *hs)
-{
-    switch (hs->kind) {
-    case HID_KEYBOARD:
-        memset(hs->kbd.keycodes, 0, sizeof(hs->kbd.keycodes));
-        memset(hs->kbd.key, 0, sizeof(hs->kbd.key));
-        hs->kbd.keys = 0;
-        break;
-    case HID_MOUSE:
-    case HID_TABLET:
-        memset(hs->ptr.queue, 0, sizeof(hs->ptr.queue));
-        break;
-    }
-    hs->head = 0;
-    hs->n = 0;
-    hs->protocol = 1;
-    hs->idle = 0;
-    hs->idle_pending = false;
-    hid_del_idle_timer(hs);
-}
-
-void hid_free(HIDState *hs)
-{
-    switch (hs->kind) {
-    case HID_KEYBOARD:
-        qemu_remove_kbd_event_handler();
-        break;
-    case HID_MOUSE:
-    case HID_TABLET:
-        qemu_remove_mouse_event_handler(hs->ptr.eh_entry);
-        break;
-    }
-    hid_del_idle_timer(hs);
-}
-
-void hid_init(HIDState *hs, int kind, HIDEventFunc event)
-{
-    hs->kind = kind;
-    hs->event = event;
-
-    if (hs->kind == HID_KEYBOARD) {
-        qemu_add_kbd_event_handler(hid_keyboard_event, hs);
-    } else if (hs->kind == HID_MOUSE) {
-        hs->ptr.eh_entry = qemu_add_mouse_event_handler(hid_pointer_event, hs,
-                                                        0, "QEMU HID Mouse");
-    } else if (hs->kind == HID_TABLET) {
-        hs->ptr.eh_entry = qemu_add_mouse_event_handler(hid_pointer_event, hs,
-                                                        1, "QEMU HID Tablet");
-    }
-}
-
-static int hid_post_load(void *opaque, int version_id)
-{
-    HIDState *s = opaque;
-
-    hid_set_next_idle(s);
-    return 0;
-}
-
-static const VMStateDescription vmstate_hid_ptr_queue = {
-    .name = "HIDPointerEventQueue",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_INT32(xdx, HIDPointerEvent),
-        VMSTATE_INT32(ydy, HIDPointerEvent),
-        VMSTATE_INT32(dz, HIDPointerEvent),
-        VMSTATE_INT32(buttons_state, HIDPointerEvent),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-const VMStateDescription vmstate_hid_ptr_device = {
-    .name = "HIDPointerDevice",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .post_load = hid_post_load,
-    .fields = (VMStateField[]) {
-        VMSTATE_STRUCT_ARRAY(ptr.queue, HIDState, QUEUE_LENGTH, 0,
-                             vmstate_hid_ptr_queue, HIDPointerEvent),
-        VMSTATE_UINT32(head, HIDState),
-        VMSTATE_UINT32(n, HIDState),
-        VMSTATE_INT32(protocol, HIDState),
-        VMSTATE_UINT8(idle, HIDState),
-        VMSTATE_END_OF_LIST(),
-    }
-};
-
-const VMStateDescription vmstate_hid_keyboard_device = {
-    .name = "HIDKeyboardDevice",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .post_load = hid_post_load,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT32_ARRAY(kbd.keycodes, HIDState, QUEUE_LENGTH),
-        VMSTATE_UINT32(head, HIDState),
-        VMSTATE_UINT32(n, HIDState),
-        VMSTATE_UINT16(kbd.modifiers, HIDState),
-        VMSTATE_UINT8(kbd.leds, HIDState),
-        VMSTATE_UINT8_ARRAY(kbd.key, HIDState, 16),
-        VMSTATE_INT32(kbd.keys, HIDState),
-        VMSTATE_INT32(protocol, HIDState),
-        VMSTATE_UINT8(idle, HIDState),
-        VMSTATE_END_OF_LIST(),
-    }
-};
diff --git a/hw/hid.h b/hw/hid.h
deleted file mode 100644 (file)
index 56c71ed..0000000
--- a/hw/hid.h
+++ /dev/null
@@ -1,83 +0,0 @@
-#ifndef QEMU_HID_H
-#define QEMU_HID_H
-
-#include "migration/vmstate.h"
-
-#define HID_MOUSE     1
-#define HID_TABLET    2
-#define HID_KEYBOARD  3
-
-typedef struct HIDPointerEvent {
-    int32_t xdx, ydy; /* relative iff it's a mouse, otherwise absolute */
-    int32_t dz, buttons_state;
-} HIDPointerEvent;
-
-#define QUEUE_LENGTH    16 /* should be enough for a triple-click */
-#define QUEUE_MASK      (QUEUE_LENGTH-1u)
-#define QUEUE_INCR(v)   ((v)++, (v) &= QUEUE_MASK)
-
-typedef struct HIDState HIDState;
-typedef void (*HIDEventFunc)(HIDState *s);
-
-typedef struct HIDMouseState {
-    HIDPointerEvent queue[QUEUE_LENGTH];
-    int mouse_grabbed;
-    QEMUPutMouseEntry *eh_entry;
-} HIDMouseState;
-
-typedef struct HIDKeyboardState {
-    uint32_t keycodes[QUEUE_LENGTH];
-    uint16_t modifiers;
-    uint8_t leds;
-    uint8_t key[16];
-    int32_t keys;
-} HIDKeyboardState;
-
-struct HIDState {
-    union {
-        HIDMouseState ptr;
-        HIDKeyboardState kbd;
-    };
-    uint32_t head; /* index into circular queue */
-    uint32_t n;
-    int kind;
-    int32_t protocol;
-    uint8_t idle;
-    bool idle_pending;
-    QEMUTimer *idle_timer;
-    HIDEventFunc event;
-};
-
-void hid_init(HIDState *hs, int kind, HIDEventFunc event);
-void hid_reset(HIDState *hs);
-void hid_free(HIDState *hs);
-
-bool hid_has_events(HIDState *hs);
-void hid_set_next_idle(HIDState *hs);
-void hid_pointer_activate(HIDState *hs);
-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/hpet.c b/hw/hpet.c
deleted file mode 100644 (file)
index 6bfbf3a..0000000
--- a/hw/hpet.c
+++ /dev/null
@@ -1,760 +0,0 @@
-/*
- *  High Precisition Event Timer emulation
- *
- *  Copyright (c) 2007 Alexander Graf
- *  Copyright (c) 2008 IBM Corporation
- *
- *  Authors: Beth Kon <bkon@us.ibm.com>
- *
- * 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/>.
- *
- * *****************************************************************
- *
- * This driver attempts to emulate an HPET device in software.
- */
-
-#include "hw/hw.h"
-#include "hw/pc.h"
-#include "ui/console.h"
-#include "qemu/timer.h"
-#include "hw/hpet_emul.h"
-#include "hw/sysbus.h"
-#include "hw/mc146818rtc.h"
-#include "hw/i8254.h"
-
-//#define HPET_DEBUG
-#ifdef HPET_DEBUG
-#define DPRINTF printf
-#else
-#define DPRINTF(...)
-#endif
-
-#define HPET_MSI_SUPPORT        0
-
-struct HPETState;
-typedef struct HPETTimer {  /* timers */
-    uint8_t tn;             /*timer number*/
-    QEMUTimer *qemu_timer;
-    struct HPETState *state;
-    /* Memory-mapped, software visible timer registers */
-    uint64_t config;        /* configuration/cap */
-    uint64_t cmp;           /* comparator */
-    uint64_t fsb;           /* FSB route */
-    /* Hidden register state */
-    uint64_t period;        /* Last value written to comparator */
-    uint8_t wrap_flag;      /* timer pop will indicate wrap for one-shot 32-bit
-                             * mode. Next pop will be actual timer expiration.
-                             */
-} HPETTimer;
-
-typedef struct HPETState {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-    uint64_t hpet_offset;
-    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];
-
-    /* Memory-mapped, software visible registers */
-    uint64_t capability;        /* capabilities */
-    uint64_t config;            /* configuration */
-    uint64_t isr;               /* interrupt status reg */
-    uint64_t hpet_counter;      /* main counter */
-    uint8_t  hpet_id;           /* instance id */
-} HPETState;
-
-static uint32_t hpet_in_legacy_mode(HPETState *s)
-{
-    return s->config & HPET_CFG_LEGACY;
-}
-
-static uint32_t timer_int_route(struct HPETTimer *timer)
-{
-    return (timer->config & HPET_TN_INT_ROUTE_MASK) >> HPET_TN_INT_ROUTE_SHIFT;
-}
-
-static uint32_t timer_fsb_route(HPETTimer *t)
-{
-    return t->config & HPET_TN_FSB_ENABLE;
-}
-
-static uint32_t hpet_enabled(HPETState *s)
-{
-    return s->config & HPET_CFG_ENABLE;
-}
-
-static uint32_t timer_is_periodic(HPETTimer *t)
-{
-    return t->config & HPET_TN_PERIODIC;
-}
-
-static uint32_t timer_enabled(HPETTimer *t)
-{
-    return t->config & HPET_TN_ENABLE;
-}
-
-static uint32_t hpet_time_after(uint64_t a, uint64_t b)
-{
-    return ((int32_t)(b) - (int32_t)(a) < 0);
-}
-
-static uint32_t hpet_time_after64(uint64_t a, uint64_t b)
-{
-    return ((int64_t)(b) - (int64_t)(a) < 0);
-}
-
-static uint64_t ticks_to_ns(uint64_t value)
-{
-    return (muldiv64(value, HPET_CLK_PERIOD, FS_PER_NS));
-}
-
-static uint64_t ns_to_ticks(uint64_t value)
-{
-    return (muldiv64(value, FS_PER_NS, HPET_CLK_PERIOD));
-}
-
-static uint64_t hpet_fixup_reg(uint64_t new, uint64_t old, uint64_t mask)
-{
-    new &= mask;
-    new |= old & ~mask;
-    return new;
-}
-
-static int activating_bit(uint64_t old, uint64_t new, uint64_t mask)
-{
-    return (!(old & mask) && (new & mask));
-}
-
-static int deactivating_bit(uint64_t old, uint64_t new, uint64_t mask)
-{
-    return ((old & mask) && !(new & mask));
-}
-
-static uint64_t hpet_get_ticks(HPETState *s)
-{
-    return ns_to_ticks(qemu_get_clock_ns(vm_clock) + s->hpet_offset);
-}
-
-/*
- * calculate diff between comparator value and current ticks
- */
-static inline uint64_t hpet_calculate_diff(HPETTimer *t, uint64_t current)
-{
-
-    if (t->config & HPET_TN_32BIT) {
-        uint32_t diff, cmp;
-
-        cmp = (uint32_t)t->cmp;
-        diff = cmp - (uint32_t)current;
-        diff = (int32_t)diff > 0 ? diff : (uint32_t)1;
-        return (uint64_t)diff;
-    } else {
-        uint64_t diff, cmp;
-
-        cmp = t->cmp;
-        diff = cmp - current;
-        diff = (int64_t)diff > 0 ? diff : (uint64_t)1;
-        return diff;
-    }
-}
-
-static void update_irq(struct HPETTimer *timer, int set)
-{
-    uint64_t mask;
-    HPETState *s;
-    int route;
-
-    if (timer->tn <= 1 && hpet_in_legacy_mode(timer->state)) {
-        /* if LegacyReplacementRoute bit is set, HPET specification requires
-         * timer0 be routed to IRQ0 in NON-APIC or IRQ2 in the I/O APIC,
-         * timer1 be routed to IRQ8 in NON-APIC or IRQ8 in the I/O APIC.
-         */
-        route = (timer->tn == 0) ? 0 : RTC_ISA_IRQ;
-    } else {
-        route = timer_int_route(timer);
-    }
-    s = timer->state;
-    mask = 1 << timer->tn;
-    if (!set || !timer_enabled(timer) || !hpet_enabled(timer->state)) {
-        s->isr &= ~mask;
-        if (!timer_fsb_route(timer)) {
-            qemu_irq_lower(s->irqs[route]);
-        }
-    } else if (timer_fsb_route(timer)) {
-        stl_le_phys(timer->fsb >> 32, timer->fsb & 0xffffffff);
-    } else if (timer->config & HPET_TN_TYPE_LEVEL) {
-        s->isr |= mask;
-        qemu_irq_raise(s->irqs[route]);
-    } else {
-        s->isr &= ~mask;
-        qemu_irq_pulse(s->irqs[route]);
-    }
-}
-
-static void hpet_pre_save(void *opaque)
-{
-    HPETState *s = opaque;
-
-    /* save current counter value */
-    s->hpet_counter = hpet_get_ticks(s);
-}
-
-static int hpet_pre_load(void *opaque)
-{
-    HPETState *s = opaque;
-
-    /* version 1 only supports 3, later versions will load the actual value */
-    s->num_timers = HPET_MIN_TIMERS;
-    return 0;
-}
-
-static int hpet_post_load(void *opaque, int version_id)
-{
-    HPETState *s = opaque;
-
-    /* Recalculate the offset between the main counter and guest time */
-    s->hpet_offset = ticks_to_ns(s->hpet_counter) - qemu_get_clock_ns(vm_clock);
-
-    /* Push number of timers into capability returned via HPET_ID */
-    s->capability &= ~HPET_ID_NUM_TIM_MASK;
-    s->capability |= (s->num_timers - 1) << HPET_ID_NUM_TIM_SHIFT;
-    hpet_cfg.hpet[s->hpet_id].event_timer_block_id = (uint32_t)s->capability;
-
-    /* Derive HPET_MSI_SUPPORT from the capability of the first timer. */
-    s->flags &= ~(1 << HPET_MSI_SUPPORT);
-    if (s->timer[0].config & HPET_TN_FSB_CAP) {
-        s->flags |= 1 << HPET_MSI_SUPPORT;
-    }
-    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,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField []) {
-        VMSTATE_UINT8(tn, HPETTimer),
-        VMSTATE_UINT64(config, HPETTimer),
-        VMSTATE_UINT64(cmp, HPETTimer),
-        VMSTATE_UINT64(fsb, HPETTimer),
-        VMSTATE_UINT64(period, HPETTimer),
-        VMSTATE_UINT8(wrap_flag, HPETTimer),
-        VMSTATE_TIMER(qemu_timer, HPETTimer),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static const VMStateDescription vmstate_hpet = {
-    .name = "hpet",
-    .version_id = 2,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .pre_save = hpet_pre_save,
-    .pre_load = hpet_pre_load,
-    .post_load = hpet_post_load,
-    .fields      = (VMStateField []) {
-        VMSTATE_UINT64(config, HPETState),
-        VMSTATE_UINT64(isr, HPETState),
-        VMSTATE_UINT64(hpet_counter, HPETState),
-        VMSTATE_UINT8_V(num_timers, HPETState, 2),
-        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 */
-        }
-    }
-};
-
-/*
- * timer expiration callback
- */
-static void hpet_timer(void *opaque)
-{
-    HPETTimer *t = opaque;
-    uint64_t diff;
-
-    uint64_t period = t->period;
-    uint64_t cur_tick = hpet_get_ticks(t->state);
-
-    if (timer_is_periodic(t) && period != 0) {
-        if (t->config & HPET_TN_32BIT) {
-            while (hpet_time_after(cur_tick, t->cmp)) {
-                t->cmp = (uint32_t)(t->cmp + t->period);
-            }
-        } else {
-            while (hpet_time_after64(cur_tick, t->cmp)) {
-                t->cmp += period;
-            }
-        }
-        diff = hpet_calculate_diff(t, cur_tick);
-        qemu_mod_timer(t->qemu_timer,
-                       qemu_get_clock_ns(vm_clock) + (int64_t)ticks_to_ns(diff));
-    } else if (t->config & HPET_TN_32BIT && !timer_is_periodic(t)) {
-        if (t->wrap_flag) {
-            diff = hpet_calculate_diff(t, cur_tick);
-            qemu_mod_timer(t->qemu_timer, qemu_get_clock_ns(vm_clock) +
-                           (int64_t)ticks_to_ns(diff));
-            t->wrap_flag = 0;
-        }
-    }
-    update_irq(t, 1);
-}
-
-static void hpet_set_timer(HPETTimer *t)
-{
-    uint64_t diff;
-    uint32_t wrap_diff;  /* how many ticks until we wrap? */
-    uint64_t cur_tick = hpet_get_ticks(t->state);
-
-    /* whenever new timer is being set up, make sure wrap_flag is 0 */
-    t->wrap_flag = 0;
-    diff = hpet_calculate_diff(t, cur_tick);
-
-    /* hpet spec says in one-shot 32-bit mode, generate an interrupt when
-     * counter wraps in addition to an interrupt with comparator match.
-     */
-    if (t->config & HPET_TN_32BIT && !timer_is_periodic(t)) {
-        wrap_diff = 0xffffffff - (uint32_t)cur_tick;
-        if (wrap_diff < (uint32_t)diff) {
-            diff = wrap_diff;
-            t->wrap_flag = 1;
-        }
-    }
-    qemu_mod_timer(t->qemu_timer,
-                   qemu_get_clock_ns(vm_clock) + (int64_t)ticks_to_ns(diff));
-}
-
-static void hpet_del_timer(HPETTimer *t)
-{
-    qemu_del_timer(t->qemu_timer);
-    update_irq(t, 0);
-}
-
-#ifdef HPET_DEBUG
-static uint32_t hpet_ram_readb(void *opaque, hwaddr addr)
-{
-    printf("qemu: hpet_read b at %" PRIx64 "\n", addr);
-    return 0;
-}
-
-static uint32_t hpet_ram_readw(void *opaque, hwaddr addr)
-{
-    printf("qemu: hpet_read w at %" PRIx64 "\n", addr);
-    return 0;
-}
-#endif
-
-static uint64_t hpet_ram_read(void *opaque, hwaddr addr,
-                              unsigned size)
-{
-    HPETState *s = opaque;
-    uint64_t cur_tick, index;
-
-    DPRINTF("qemu: Enter hpet_ram_readl at %" PRIx64 "\n", addr);
-    index = addr;
-    /*address range of all TN regs*/
-    if (index >= 0x100 && index <= 0x3ff) {
-        uint8_t timer_id = (addr - 0x100) / 0x20;
-        HPETTimer *timer = &s->timer[timer_id];
-
-        if (timer_id > s->num_timers) {
-            DPRINTF("qemu: timer id out of range\n");
-            return 0;
-        }
-
-        switch ((addr - 0x100) % 0x20) {
-        case HPET_TN_CFG:
-            return timer->config;
-        case HPET_TN_CFG + 4: // Interrupt capabilities
-            return timer->config >> 32;
-        case HPET_TN_CMP: // comparator register
-            return timer->cmp;
-        case HPET_TN_CMP + 4:
-            return timer->cmp >> 32;
-        case HPET_TN_ROUTE:
-            return timer->fsb;
-        case HPET_TN_ROUTE + 4:
-            return timer->fsb >> 32;
-        default:
-            DPRINTF("qemu: invalid hpet_ram_readl\n");
-            break;
-        }
-    } else {
-        switch (index) {
-        case HPET_ID:
-            return s->capability;
-        case HPET_PERIOD:
-            return s->capability >> 32;
-        case HPET_CFG:
-            return s->config;
-        case HPET_CFG + 4:
-            DPRINTF("qemu: invalid HPET_CFG + 4 hpet_ram_readl\n");
-            return 0;
-        case HPET_COUNTER:
-            if (hpet_enabled(s)) {
-                cur_tick = hpet_get_ticks(s);
-            } else {
-                cur_tick = s->hpet_counter;
-            }
-            DPRINTF("qemu: reading counter  = %" PRIx64 "\n", cur_tick);
-            return cur_tick;
-        case HPET_COUNTER + 4:
-            if (hpet_enabled(s)) {
-                cur_tick = hpet_get_ticks(s);
-            } else {
-                cur_tick = s->hpet_counter;
-            }
-            DPRINTF("qemu: reading counter + 4  = %" PRIx64 "\n", cur_tick);
-            return cur_tick >> 32;
-        case HPET_STATUS:
-            return s->isr;
-        default:
-            DPRINTF("qemu: invalid hpet_ram_readl\n");
-            break;
-        }
-    }
-    return 0;
-}
-
-static void hpet_ram_write(void *opaque, hwaddr addr,
-                           uint64_t value, unsigned size)
-{
-    int i;
-    HPETState *s = opaque;
-    uint64_t old_val, new_val, val, index;
-
-    DPRINTF("qemu: Enter hpet_ram_writel at %" PRIx64 " = %#x\n", addr, value);
-    index = addr;
-    old_val = hpet_ram_read(opaque, addr, 4);
-    new_val = value;
-
-    /*address range of all TN regs*/
-    if (index >= 0x100 && index <= 0x3ff) {
-        uint8_t timer_id = (addr - 0x100) / 0x20;
-        HPETTimer *timer = &s->timer[timer_id];
-
-        DPRINTF("qemu: hpet_ram_writel timer_id = %#x\n", timer_id);
-        if (timer_id > s->num_timers) {
-            DPRINTF("qemu: timer id out of range\n");
-            return;
-        }
-        switch ((addr - 0x100) % 0x20) {
-        case HPET_TN_CFG:
-            DPRINTF("qemu: hpet_ram_writel HPET_TN_CFG\n");
-            if (activating_bit(old_val, new_val, HPET_TN_FSB_ENABLE)) {
-                update_irq(timer, 0);
-            }
-            val = hpet_fixup_reg(new_val, old_val, HPET_TN_CFG_WRITE_MASK);
-            timer->config = (timer->config & 0xffffffff00000000ULL) | val;
-            if (new_val & HPET_TN_32BIT) {
-                timer->cmp = (uint32_t)timer->cmp;
-                timer->period = (uint32_t)timer->period;
-            }
-            if (activating_bit(old_val, new_val, HPET_TN_ENABLE)) {
-                hpet_set_timer(timer);
-            } else if (deactivating_bit(old_val, new_val, HPET_TN_ENABLE)) {
-                hpet_del_timer(timer);
-            }
-            break;
-        case HPET_TN_CFG + 4: // Interrupt capabilities
-            DPRINTF("qemu: invalid HPET_TN_CFG+4 write\n");
-            break;
-        case HPET_TN_CMP: // comparator register
-            DPRINTF("qemu: hpet_ram_writel HPET_TN_CMP\n");
-            if (timer->config & HPET_TN_32BIT) {
-                new_val = (uint32_t)new_val;
-            }
-            if (!timer_is_periodic(timer)
-                || (timer->config & HPET_TN_SETVAL)) {
-                timer->cmp = (timer->cmp & 0xffffffff00000000ULL) | new_val;
-            }
-            if (timer_is_periodic(timer)) {
-                /*
-                 * FIXME: Clamp period to reasonable min value?
-                 * Clamp period to reasonable max value
-                 */
-                new_val &= (timer->config & HPET_TN_32BIT ? ~0u : ~0ull) >> 1;
-                timer->period =
-                    (timer->period & 0xffffffff00000000ULL) | new_val;
-            }
-            timer->config &= ~HPET_TN_SETVAL;
-            if (hpet_enabled(s)) {
-                hpet_set_timer(timer);
-            }
-            break;
-        case HPET_TN_CMP + 4: // comparator register high order
-            DPRINTF("qemu: hpet_ram_writel HPET_TN_CMP + 4\n");
-            if (!timer_is_periodic(timer)
-                || (timer->config & HPET_TN_SETVAL)) {
-                timer->cmp = (timer->cmp & 0xffffffffULL) | new_val << 32;
-            } else {
-                /*
-                 * FIXME: Clamp period to reasonable min value?
-                 * Clamp period to reasonable max value
-                 */
-                new_val &= (timer->config & HPET_TN_32BIT ? ~0u : ~0ull) >> 1;
-                timer->period =
-                    (timer->period & 0xffffffffULL) | new_val << 32;
-                }
-                timer->config &= ~HPET_TN_SETVAL;
-                if (hpet_enabled(s)) {
-                    hpet_set_timer(timer);
-                }
-                break;
-        case HPET_TN_ROUTE:
-            timer->fsb = (timer->fsb & 0xffffffff00000000ULL) | new_val;
-            break;
-        case HPET_TN_ROUTE + 4:
-            timer->fsb = (new_val << 32) | (timer->fsb & 0xffffffff);
-            break;
-        default:
-            DPRINTF("qemu: invalid hpet_ram_writel\n");
-            break;
-        }
-        return;
-    } else {
-        switch (index) {
-        case HPET_ID:
-            return;
-        case HPET_CFG:
-            val = hpet_fixup_reg(new_val, old_val, HPET_CFG_WRITE_MASK);
-            s->config = (s->config & 0xffffffff00000000ULL) | val;
-            if (activating_bit(old_val, new_val, HPET_CFG_ENABLE)) {
-                /* Enable main counter and interrupt generation. */
-                s->hpet_offset =
-                    ticks_to_ns(s->hpet_counter) - qemu_get_clock_ns(vm_clock);
-                for (i = 0; i < s->num_timers; i++) {
-                    if ((&s->timer[i])->cmp != ~0ULL) {
-                        hpet_set_timer(&s->timer[i]);
-                    }
-                }
-            } else if (deactivating_bit(old_val, new_val, HPET_CFG_ENABLE)) {
-                /* Halt main counter and disable interrupt generation. */
-                s->hpet_counter = hpet_get_ticks(s);
-                for (i = 0; i < s->num_timers; i++) {
-                    hpet_del_timer(&s->timer[i]);
-                }
-            }
-            /* i8254 and RTC output pins are disabled
-             * when HPET is in legacy mode */
-            if (activating_bit(old_val, new_val, HPET_CFG_LEGACY)) {
-                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)) {
-                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;
-        case HPET_CFG + 4:
-            DPRINTF("qemu: invalid HPET_CFG+4 write\n");
-            break;
-        case HPET_STATUS:
-            val = new_val & s->isr;
-            for (i = 0; i < s->num_timers; i++) {
-                if (val & (1 << i)) {
-                    update_irq(&s->timer[i], 0);
-                }
-            }
-            break;
-        case HPET_COUNTER:
-            if (hpet_enabled(s)) {
-                DPRINTF("qemu: Writing counter while HPET enabled!\n");
-            }
-            s->hpet_counter =
-                (s->hpet_counter & 0xffffffff00000000ULL) | value;
-            DPRINTF("qemu: HPET counter written. ctr = %#x -> %" PRIx64 "\n",
-                    value, s->hpet_counter);
-            break;
-        case HPET_COUNTER + 4:
-            if (hpet_enabled(s)) {
-                DPRINTF("qemu: Writing counter while HPET enabled!\n");
-            }
-            s->hpet_counter =
-                (s->hpet_counter & 0xffffffffULL) | (((uint64_t)value) << 32);
-            DPRINTF("qemu: HPET counter + 4 written. ctr = %#x -> %" PRIx64 "\n",
-                    value, s->hpet_counter);
-            break;
-        default:
-            DPRINTF("qemu: invalid hpet_ram_writel\n");
-            break;
-        }
-    }
-}
-
-static const MemoryRegionOps hpet_ram_ops = {
-    .read = hpet_ram_read,
-    .write = hpet_ram_write,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void hpet_reset(DeviceState *d)
-{
-    HPETState *s = FROM_SYSBUS(HPETState, SYS_BUS_DEVICE(d));
-    int i;
-
-    for (i = 0; i < s->num_timers; i++) {
-        HPETTimer *timer = &s->timer[i];
-
-        hpet_del_timer(timer);
-        timer->cmp = ~0ULL;
-        timer->config = HPET_TN_PERIODIC_CAP | HPET_TN_SIZE_CAP;
-        if (s->flags & (1 << HPET_MSI_SUPPORT)) {
-            timer->config |= HPET_TN_FSB_CAP;
-        }
-        /* advertise availability of ioapic inti2 */
-        timer->config |=  0x00000004ULL << 32;
-        timer->period = 0ULL;
-        timer->wrap_flag = 0;
-    }
-
-    qemu_set_irq(s->pit_enabled, 1);
-    s->hpet_counter = 0ULL;
-    s->hpet_offset = 0ULL;
-    s->config = 0ULL;
-    hpet_cfg.hpet[s->hpet_id].event_timer_block_id = (uint32_t)s->capability;
-    hpet_cfg.hpet[s->hpet_id].address = SYS_BUS_DEVICE(d)->mmio[0].addr;
-
-    /* to document that the RTC lowers its output on reset as well */
-    s->rtc_irq_level = 0;
-}
-
-static void hpet_handle_legacy_irq(void *opaque, int n, int level)
-{
-    HPETState *s = FROM_SYSBUS(HPETState, opaque);
-
-    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);
-        }
-    }
-}
-
-static int hpet_init(SysBusDevice *dev)
-{
-    HPETState *s = FROM_SYSBUS(HPETState, dev);
-    int i;
-    HPETTimer *timer;
-
-    if (hpet_cfg.count == UINT8_MAX) {
-        /* first instance */
-        hpet_cfg.count = 0;
-    }
-
-    if (hpet_cfg.count == 8) {
-        fprintf(stderr, "Only 8 instances of HPET is allowed\n");
-        return -1;
-    }
-
-    s->hpet_id = hpet_cfg.count++;
-
-    for (i = 0; i < HPET_NUM_IRQ_ROUTES; i++) {
-        sysbus_init_irq(dev, &s->irqs[i]);
-    }
-
-    if (s->num_timers < HPET_MIN_TIMERS) {
-        s->num_timers = HPET_MIN_TIMERS;
-    } else if (s->num_timers > HPET_MAX_TIMERS) {
-        s->num_timers = HPET_MAX_TIMERS;
-    }
-    for (i = 0; i < HPET_MAX_TIMERS; i++) {
-        timer = &s->timer[i];
-        timer->qemu_timer = qemu_new_timer_ns(vm_clock, hpet_timer, timer);
-        timer->tn = i;
-        timer->state = s;
-    }
-
-    /* 64-bit main counter; LegacyReplacementRoute. */
-    s->capability = 0x8086a001ULL;
-    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_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);
-    sysbus_init_mmio(dev, &s->iomem);
-    return 0;
-}
-
-static Property hpet_device_properties[] = {
-    DEFINE_PROP_UINT8("timers", HPETState, num_timers, HPET_MIN_TIMERS),
-    DEFINE_PROP_BIT("msi", HPETState, flags, HPET_MSI_SUPPORT, false),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void hpet_device_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = hpet_init;
-    dc->no_user = 1;
-    dc->reset = hpet_reset;
-    dc->vmsd = &vmstate_hpet;
-    dc->props = hpet_device_properties;
-}
-
-static const 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_types(void)
-{
-    type_register_static(&hpet_device_info);
-}
-
-type_init(hpet_register_types)
diff --git a/hw/hpet_emul.h b/hw/hpet_emul.h
deleted file mode 100644 (file)
index 757f79f..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * QEMU Emulated HPET support
- *
- * Copyright IBM, Corp. 2008
- *
- * Authors:
- *  Beth Kon   <bkon@us.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2.  See
- * the COPYING file in the top-level directory.
- *
- */
-#ifndef QEMU_HPET_EMUL_H
-#define QEMU_HPET_EMUL_H
-
-#define HPET_BASE               0xfed00000
-#define HPET_CLK_PERIOD         10000000ULL /* 10000000 femtoseconds == 10ns*/
-
-#define FS_PER_NS 1000000
-#define HPET_MIN_TIMERS         3
-#define HPET_MAX_TIMERS         32
-
-#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
-
-#define HPET_ID         0x000
-#define HPET_PERIOD     0x004
-#define HPET_CFG        0x010
-#define HPET_STATUS     0x020
-#define HPET_COUNTER    0x0f0
-#define HPET_TN_CFG     0x000
-#define HPET_TN_CMP     0x008
-#define HPET_TN_ROUTE   0x010
-#define HPET_CFG_WRITE_MASK  0x3
-
-#define HPET_ID_NUM_TIM_SHIFT   8
-#define HPET_ID_NUM_TIM_MASK    0x1f00
-
-#define HPET_TN_TYPE_LEVEL       0x002
-#define HPET_TN_ENABLE           0x004
-#define HPET_TN_PERIODIC         0x008
-#define HPET_TN_PERIODIC_CAP     0x010
-#define HPET_TN_SIZE_CAP         0x020
-#define HPET_TN_SETVAL           0x040
-#define HPET_TN_32BIT            0x100
-#define HPET_TN_INT_ROUTE_MASK  0x3e00
-#define HPET_TN_FSB_ENABLE      0x4000
-#define HPET_TN_FSB_CAP         0x8000
-#define HPET_TN_CFG_WRITE_MASK  0x7f4e
-#define HPET_TN_INT_ROUTE_SHIFT      9
-#define HPET_TN_INT_ROUTE_CAP_SHIFT 32
-#define HPET_TN_CFG_BITS_READONLY_OR_RESERVED 0xffff80b1U
-
-struct hpet_fw_entry
-{
-    uint32_t event_timer_block_id;
-    uint64_t address;
-    uint16_t min_tick;
-    uint8_t page_prot;
-} QEMU_PACKED;
-
-struct hpet_fw_config
-{
-    uint8_t count;
-    struct hpet_fw_entry hpet[8];
-} QEMU_PACKED;
-
-extern struct hpet_fw_config hpet_cfg;
-#endif
diff --git a/hw/hw.h b/hw/hw.h
deleted file mode 100644 (file)
index 1fb9afa..0000000
--- a/hw/hw.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/* Declarations for use by hardware emulation.  */
-#ifndef QEMU_HW_H
-#define QEMU_HW_H
-
-#include "qemu-common.h"
-
-#if !defined(CONFIG_USER_ONLY) && !defined(NEED_CPU_H)
-#include "exec/cpu-common.h"
-#endif
-
-#include "exec/ioport.h"
-#include "hw/irq.h"
-#include "block/aio.h"
-#include "migration/qemu-file.h"
-#include "migration/vmstate.h"
-#include "qemu/log.h"
-
-#ifdef NEED_CPU_H
-#if TARGET_LONG_BITS == 64
-#define qemu_put_betl qemu_put_be64
-#define qemu_get_betl qemu_get_be64
-#define qemu_put_betls qemu_put_be64s
-#define qemu_get_betls qemu_get_be64s
-#define qemu_put_sbetl qemu_put_sbe64
-#define qemu_get_sbetl qemu_get_sbe64
-#define qemu_put_sbetls qemu_put_sbe64s
-#define qemu_get_sbetls qemu_get_sbe64s
-#else
-#define qemu_put_betl qemu_put_be32
-#define qemu_get_betl qemu_get_be32
-#define qemu_put_betls qemu_put_be32s
-#define qemu_get_betls qemu_get_be32s
-#define qemu_put_sbetl qemu_put_sbe32
-#define qemu_get_sbetl qemu_get_sbe32
-#define qemu_put_sbetls qemu_put_sbe32s
-#define qemu_get_sbetls qemu_get_sbe32s
-#endif
-#endif
-
-typedef void QEMUResetHandler(void *opaque);
-
-void qemu_register_reset(QEMUResetHandler *func, void *opaque);
-void qemu_unregister_reset(QEMUResetHandler *func, void *opaque);
-
-/* handler to set the boot_device order for a specific type of QEMUMachine */
-/* return 0 if success */
-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);
-
-#ifdef NEED_CPU_H
-#if TARGET_LONG_BITS == 64
-#define VMSTATE_UINTTL_V(_f, _s, _v)                                  \
-    VMSTATE_UINT64_V(_f, _s, _v)
-#define VMSTATE_UINTTL_EQUAL_V(_f, _s, _v)                            \
-    VMSTATE_UINT64_EQUAL_V(_f, _s, _v)
-#define VMSTATE_UINTTL_ARRAY_V(_f, _s, _n, _v)                        \
-    VMSTATE_UINT64_ARRAY_V(_f, _s, _n, _v)
-#else
-#define VMSTATE_UINTTL_V(_f, _s, _v)                                  \
-    VMSTATE_UINT32_V(_f, _s, _v)
-#define VMSTATE_UINTTL_EQUAL_V(_f, _s, _v)                            \
-    VMSTATE_UINT32_EQUAL_V(_f, _s, _v)
-#define VMSTATE_UINTTL_ARRAY_V(_f, _s, _n, _v)                        \
-    VMSTATE_UINT32_ARRAY_V(_f, _s, _n, _v)
-#endif
-#define VMSTATE_UINTTL(_f, _s)                                        \
-    VMSTATE_UINTTL_V(_f, _s, 0)
-#define VMSTATE_UINTTL_EQUAL(_f, _s)                                  \
-    VMSTATE_UINTTL_EQUAL_V(_f, _s, 0)
-#define VMSTATE_UINTTL_ARRAY(_f, _s, _n)                              \
-    VMSTATE_UINTTL_ARRAY_V(_f, _s, _n, 0)
-
-#endif
-
-#endif
diff --git a/hw/i2c.c b/hw/i2c.c
deleted file mode 100644 (file)
index ad361cc..0000000
--- a/hw/i2c.c
+++ /dev/null
@@ -1,246 +0,0 @@
-/*
- * QEMU I2C bus interface.
- *
- * Copyright (c) 2007 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the LGPL.
- */
-
-#include "hw/i2c.h"
-
-struct i2c_bus
-{
-    BusState qbus;
-    I2CSlave *current_dev;
-    I2CSlave *dev;
-    uint8_t saved_address;
-};
-
-static Property i2c_props[] = {
-    DEFINE_PROP_UINT8("address", struct I2CSlave, address, 0),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-#define TYPE_I2C_BUS "i2c-bus"
-#define I2C_BUS(obj) OBJECT_CHECK(i2c_bus, (obj), TYPE_I2C_BUS)
-
-static const TypeInfo i2c_bus_info = {
-    .name = TYPE_I2C_BUS,
-    .parent = TYPE_BUS,
-    .instance_size = sizeof(i2c_bus),
-};
-
-static void i2c_bus_pre_save(void *opaque)
-{
-    i2c_bus *bus = opaque;
-
-    bus->saved_address = bus->current_dev ? bus->current_dev->address : -1;
-}
-
-static int i2c_bus_post_load(void *opaque, int version_id)
-{
-    i2c_bus *bus = opaque;
-
-    /* The bus is loaded before attached devices, so load and save the
-       current device id.  Devices will check themselves as loaded.  */
-    bus->current_dev = NULL;
-    return 0;
-}
-
-static const VMStateDescription vmstate_i2c_bus = {
-    .name = "i2c_bus",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .pre_save = i2c_bus_pre_save,
-    .post_load = i2c_bus_post_load,
-    .fields      = (VMStateField []) {
-        VMSTATE_UINT8(saved_address, i2c_bus),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-/* Create a new I2C bus.  */
-i2c_bus *i2c_init_bus(DeviceState *parent, const char *name)
-{
-    i2c_bus *bus;
-
-    bus = FROM_QBUS(i2c_bus, qbus_create(TYPE_I2C_BUS, parent, name));
-    vmstate_register(NULL, -1, &vmstate_i2c_bus, bus);
-    return bus;
-}
-
-void i2c_set_slave_address(I2CSlave *dev, uint8_t address)
-{
-    dev->address = address;
-}
-
-/* Return nonzero if bus is busy.  */
-int i2c_bus_busy(i2c_bus *bus)
-{
-    return bus->current_dev != NULL;
-}
-
-/* Returns non-zero if the address is not valid.  */
-/* TODO: Make this handle multiple masters.  */
-int i2c_start_transfer(i2c_bus *bus, uint8_t address, int recv)
-{
-    BusChild *kid;
-    I2CSlave *slave = NULL;
-    I2CSlaveClass *sc;
-
-    QTAILQ_FOREACH(kid, &bus->qbus.children, sibling) {
-        DeviceState *qdev = kid->child;
-        I2CSlave *candidate = I2C_SLAVE(qdev);
-        if (candidate->address == address) {
-            slave = candidate;
-            break;
-        }
-    }
-
-    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;
-    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) {
-        return;
-    }
-
-    sc = I2C_SLAVE_GET_CLASS(dev);
-    if (sc->event) {
-        sc->event(dev, I2C_FINISH);
-    }
-
-    bus->current_dev = NULL;
-}
-
-int i2c_send(i2c_bus *bus, uint8_t data)
-{
-    I2CSlave *dev = bus->current_dev;
-    I2CSlaveClass *sc;
-
-    if (!dev) {
-        return -1;
-    }
-
-    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) {
-        return -1;
-    }
-
-    sc = I2C_SLAVE_GET_CLASS(dev);
-    if (sc->recv) {
-        return sc->recv(dev);
-    }
-
-    return -1;
-}
-
-void i2c_nack(i2c_bus *bus)
-{
-    I2CSlave *dev = bus->current_dev;
-    I2CSlaveClass *sc;
-
-    if (!dev) {
-        return;
-    }
-
-    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)
-{
-    I2CSlave *dev = opaque;
-    i2c_bus *bus;
-    bus = FROM_QBUS(i2c_bus, qdev_get_parent_bus(&dev->qdev));
-    if (bus->saved_address == dev->address) {
-        bus->current_dev = dev;
-    }
-    return 0;
-}
-
-const VMStateDescription vmstate_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, I2CSlave),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static int i2c_slave_qdev_init(DeviceState *dev)
-{
-    I2CSlave *s = I2C_SLAVE(dev);
-    I2CSlaveClass *sc = I2C_SLAVE_GET_CLASS(s);
-
-    return sc->init(s);
-}
-
-DeviceState *i2c_create_slave(i2c_bus *bus, const char *name, uint8_t addr)
-{
-    DeviceState *dev;
-
-    dev = qdev_create(&bus->qbus, name);
-    qdev_prop_set_uint8(dev, "address", addr);
-    qdev_init_nofail(dev);
-    return dev;
-}
-
-static void i2c_slave_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *k = DEVICE_CLASS(klass);
-    k->init = i2c_slave_qdev_init;
-    k->bus_type = TYPE_I2C_BUS;
-    k->props = i2c_props;
-}
-
-static const 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_types(void)
-{
-    type_register_static(&i2c_bus_info);
-    type_register_static(&i2c_slave_type_info);
-}
-
-type_init(i2c_slave_register_types)
diff --git a/hw/i2c.h b/hw/i2c.h
deleted file mode 100644 (file)
index 461392f..0000000
--- a/hw/i2c.h
+++ /dev/null
@@ -1,88 +0,0 @@
-#ifndef QEMU_I2C_H
-#define QEMU_I2C_H
-
-#include "hw/qdev.h"
-
-/* The QEMU I2C implementation only supports simple transfers that complete
-   immediately.  It does not support slave devices that need to be able to
-   defer their response (eg. CPU slave interfaces where the data is supplied
-   by the device driver in response to an interrupt).  */
-
-enum i2c_event {
-    I2C_START_RECV,
-    I2C_START_SEND,
-    I2C_FINISH,
-    I2C_NACK /* Masker NACKed a receive byte.  */
-};
-
-typedef struct I2CSlave I2CSlave;
-
-#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);
-
-    /* Master to slave.  */
-    int (*send)(I2CSlave *s, uint8_t data);
-
-    /* Slave to master.  */
-    int (*recv)(I2CSlave *s);
-
-    /* Notify the slave of a bus state change.  */
-    void (*event)(I2CSlave *s, enum i2c_event event);
-} I2CSlaveClass;
-
-struct I2CSlave
-{
-    DeviceState qdev;
-
-    /* Remaining fields for internal use by the I2C code.  */
-    uint8_t address;
-};
-
-i2c_bus *i2c_init_bus(DeviceState *parent, const char *name);
-void i2c_set_slave_address(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);
-void i2c_nack(i2c_bus *bus);
-int i2c_send(i2c_bus *bus, uint8_t data);
-int i2c_recv(i2c_bus *bus);
-
-#define FROM_I2C_SLAVE(type, dev) DO_UPCAST(type, i2c, dev)
-
-DeviceState *i2c_create_slave(i2c_bus *bus, const char *name, uint8_t addr);
-
-/* wm8750.c */
-void wm8750_data_req_set(DeviceState *dev,
-                void (*data_req)(void *, int, int), void *opaque);
-void wm8750_dac_dat(void *opaque, uint32_t sample);
-uint32_t wm8750_adc_dat(void *opaque);
-void *wm8750_dac_buffer(void *opaque, int samples);
-void wm8750_dac_commit(void *opaque);
-void wm8750_set_bclk_in(void *opaque, int new_hz);
-
-/* 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(I2CSlave),                                  \
-    .vmsd       = &vmstate_i2c_slave,                                \
-    .flags      = VMS_STRUCT,                                        \
-    .offset     = vmstate_offset_value(_state, _field, I2CSlave),    \
-}
-
-#endif
diff --git a/hw/i2c/Makefile.objs b/hw/i2c/Makefile.objs
new file mode 100644 (file)
index 0000000..648278e
--- /dev/null
@@ -0,0 +1,7 @@
+common-obj-y += core.o smbus.o smbus_eeprom.o
+common-obj-$(CONFIG_VERSATILE_I2C) += versatile_i2c.o
+common-obj-$(CONFIG_ACPI) += smbus_ich9.o
+common-obj-$(CONFIG_APM) += pm_smbus.o
+common-obj-$(CONFIG_BITBANG_I2C) += bitbang_i2c.o
+common-obj-$(CONFIG_EXYNOS4) += exynos4210_i2c.o
+obj-$(CONFIG_OMAP) += omap_i2c.o
diff --git a/hw/i2c/bitbang_i2c.c b/hw/i2c/bitbang_i2c.c
new file mode 100644 (file)
index 0000000..854b8e1
--- /dev/null
@@ -0,0 +1,245 @@
+/*
+ * Bit-Bang i2c emulation extracted from
+ * Marvell MV88W8618 / Freecom MusicPal emulation.
+ *
+ * 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/hw.h"
+#include "bitbang_i2c.h"
+#include "hw/sysbus.h"
+
+//#define DEBUG_BITBANG_I2C
+
+#ifdef DEBUG_BITBANG_I2C
+#define DPRINTF(fmt, ...) \
+do { printf("bitbang_i2c: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while(0)
+#endif
+
+typedef enum bitbang_i2c_state {
+    STOPPED = 0,
+    SENDING_BIT7,
+    SENDING_BIT6,
+    SENDING_BIT5,
+    SENDING_BIT4,
+    SENDING_BIT3,
+    SENDING_BIT2,
+    SENDING_BIT1,
+    SENDING_BIT0,
+    WAITING_FOR_ACK,
+    RECEIVING_BIT7,
+    RECEIVING_BIT6,
+    RECEIVING_BIT5,
+    RECEIVING_BIT4,
+    RECEIVING_BIT3,
+    RECEIVING_BIT2,
+    RECEIVING_BIT1,
+    RECEIVING_BIT0,
+    SENDING_ACK,
+    SENT_NACK
+} bitbang_i2c_state;
+
+struct bitbang_i2c_interface {
+    i2c_bus *bus;
+    bitbang_i2c_state state;
+    int last_data;
+    int last_clock;
+    int device_out;
+    uint8_t buffer;
+    int current_addr;
+};
+
+static void bitbang_i2c_enter_stop(bitbang_i2c_interface *i2c)
+{
+    DPRINTF("STOP\n");
+    if (i2c->current_addr >= 0)
+        i2c_end_transfer(i2c->bus);
+    i2c->current_addr = -1;
+    i2c->state = STOPPED;
+}
+
+/* Set device data pin.  */
+static int bitbang_i2c_ret(bitbang_i2c_interface *i2c, int level)
+{
+    i2c->device_out = level;
+    //DPRINTF("%d %d %d\n", i2c->last_clock, i2c->last_data, i2c->device_out);
+    return level & i2c->last_data;
+}
+
+/* Leave device data pin unodified.  */
+static int bitbang_i2c_nop(bitbang_i2c_interface *i2c)
+{
+    return bitbang_i2c_ret(i2c, i2c->device_out);
+}
+
+/* Returns data line level.  */
+int bitbang_i2c_set(bitbang_i2c_interface *i2c, int line, int level)
+{
+    int data;
+
+    if (level != 0 && level != 1) {
+        abort();
+    }
+
+    if (line == BITBANG_I2C_SDA) {
+        if (level == i2c->last_data) {
+            return bitbang_i2c_nop(i2c);
+        }
+        i2c->last_data = level;
+        if (i2c->last_clock == 0) {
+            return bitbang_i2c_nop(i2c);
+        }
+        if (level == 0) {
+            DPRINTF("START\n");
+            /* START condition.  */
+            i2c->state = SENDING_BIT7;
+            i2c->current_addr = -1;
+        } else {
+            /* STOP condition.  */
+            bitbang_i2c_enter_stop(i2c);
+        }
+        return bitbang_i2c_ret(i2c, 1);
+    }
+
+    data = i2c->last_data;
+    if (i2c->last_clock == level) {
+        return bitbang_i2c_nop(i2c);
+    }
+    i2c->last_clock = level;
+    if (level == 0) {
+        /* State is set/read at the start of the clock pulse.
+           release the data line at the end.  */
+        return bitbang_i2c_ret(i2c, 1);
+    }
+    switch (i2c->state) {
+    case STOPPED:
+    case SENT_NACK:
+        return bitbang_i2c_ret(i2c, 1);
+
+    case SENDING_BIT7 ... SENDING_BIT0:
+        i2c->buffer = (i2c->buffer << 1) | data;
+        /* will end up in WAITING_FOR_ACK */
+        i2c->state++; 
+        return bitbang_i2c_ret(i2c, 1);
+
+    case WAITING_FOR_ACK:
+        if (i2c->current_addr < 0) {
+            i2c->current_addr = i2c->buffer;
+            DPRINTF("Address 0x%02x\n", i2c->current_addr);
+            i2c_start_transfer(i2c->bus, i2c->current_addr >> 1,
+                               i2c->current_addr & 1);
+        } else {
+            DPRINTF("Sent 0x%02x\n", i2c->buffer);
+            i2c_send(i2c->bus, i2c->buffer);
+        }
+        if (i2c->current_addr & 1) {
+            i2c->state = RECEIVING_BIT7;
+        } else {
+            i2c->state = SENDING_BIT7;
+        }
+        return bitbang_i2c_ret(i2c, 0);
+
+    case RECEIVING_BIT7:
+        i2c->buffer = i2c_recv(i2c->bus);
+        DPRINTF("RX byte 0x%02x\n", i2c->buffer);
+        /* Fall through... */
+    case RECEIVING_BIT6 ... RECEIVING_BIT0:
+        data = i2c->buffer >> 7;
+        /* will end up in SENDING_ACK */
+        i2c->state++;
+        i2c->buffer <<= 1;
+        return bitbang_i2c_ret(i2c, data);
+
+    case SENDING_ACK:
+        i2c->state = RECEIVING_BIT7;
+        if (data != 0) {
+            DPRINTF("NACKED\n");
+            i2c->state = SENT_NACK;
+            i2c_nack(i2c->bus);
+        } else {
+            DPRINTF("ACKED\n");
+        }
+        return bitbang_i2c_ret(i2c, 1);
+    }
+    abort();
+}
+
+bitbang_i2c_interface *bitbang_i2c_init(i2c_bus *bus)
+{
+    bitbang_i2c_interface *s;
+
+    s = g_malloc0(sizeof(bitbang_i2c_interface));
+
+    s->bus = bus;
+    s->last_data = 1;
+    s->last_clock = 1;
+    s->device_out = 1;
+
+    return s;
+}
+
+/* GPIO interface.  */
+typedef struct {
+    SysBusDevice busdev;
+    MemoryRegion dummy_iomem;
+    bitbang_i2c_interface *bitbang;
+    int last_level;
+    qemu_irq out;
+} GPIOI2CState;
+
+static void bitbang_i2c_gpio_set(void *opaque, int irq, int level)
+{
+    GPIOI2CState *s = opaque;
+
+    level = bitbang_i2c_set(s->bitbang, irq, level);
+    if (level != s->last_level) {
+        s->last_level = level;
+        qemu_set_irq(s->out, level);
+    }
+}
+
+static int gpio_i2c_init(SysBusDevice *dev)
+{
+    GPIOI2CState *s = FROM_SYSBUS(GPIOI2CState, dev);
+    i2c_bus *bus;
+
+    memory_region_init(&s->dummy_iomem, "gpio_i2c", 0);
+    sysbus_init_mmio(dev, &s->dummy_iomem);
+
+    bus = i2c_init_bus(&dev->qdev, "i2c");
+    s->bitbang = bitbang_i2c_init(bus);
+
+    qdev_init_gpio_in(&dev->qdev, bitbang_i2c_gpio_set, 2);
+    qdev_init_gpio_out(&dev->qdev, &s->out, 1);
+
+    return 0;
+}
+
+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 const 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_types(void)
+{
+    type_register_static(&gpio_i2c_info);
+}
+
+type_init(bitbang_i2c_register_types)
diff --git a/hw/i2c/bitbang_i2c.h b/hw/i2c/bitbang_i2c.h
new file mode 100644 (file)
index 0000000..2866ac3
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef BITBANG_I2C_H
+#define BITBANG_I2C_H
+
+#include "hw/i2c/i2c.h"
+
+typedef struct bitbang_i2c_interface bitbang_i2c_interface;
+
+#define BITBANG_I2C_SDA 0
+#define BITBANG_I2C_SCL 1
+
+bitbang_i2c_interface *bitbang_i2c_init(i2c_bus *bus);
+int bitbang_i2c_set(bitbang_i2c_interface *i2c, int line, int level);
+
+#endif
diff --git a/hw/i2c/core.c b/hw/i2c/core.c
new file mode 100644 (file)
index 0000000..0c4fc1d
--- /dev/null
@@ -0,0 +1,246 @@
+/*
+ * QEMU I2C bus interface.
+ *
+ * Copyright (c) 2007 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the LGPL.
+ */
+
+#include "hw/i2c/i2c.h"
+
+struct i2c_bus
+{
+    BusState qbus;
+    I2CSlave *current_dev;
+    I2CSlave *dev;
+    uint8_t saved_address;
+};
+
+static Property i2c_props[] = {
+    DEFINE_PROP_UINT8("address", struct I2CSlave, address, 0),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+#define TYPE_I2C_BUS "i2c-bus"
+#define I2C_BUS(obj) OBJECT_CHECK(i2c_bus, (obj), TYPE_I2C_BUS)
+
+static const TypeInfo i2c_bus_info = {
+    .name = TYPE_I2C_BUS,
+    .parent = TYPE_BUS,
+    .instance_size = sizeof(i2c_bus),
+};
+
+static void i2c_bus_pre_save(void *opaque)
+{
+    i2c_bus *bus = opaque;
+
+    bus->saved_address = bus->current_dev ? bus->current_dev->address : -1;
+}
+
+static int i2c_bus_post_load(void *opaque, int version_id)
+{
+    i2c_bus *bus = opaque;
+
+    /* The bus is loaded before attached devices, so load and save the
+       current device id.  Devices will check themselves as loaded.  */
+    bus->current_dev = NULL;
+    return 0;
+}
+
+static const VMStateDescription vmstate_i2c_bus = {
+    .name = "i2c_bus",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .pre_save = i2c_bus_pre_save,
+    .post_load = i2c_bus_post_load,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT8(saved_address, i2c_bus),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+/* Create a new I2C bus.  */
+i2c_bus *i2c_init_bus(DeviceState *parent, const char *name)
+{
+    i2c_bus *bus;
+
+    bus = FROM_QBUS(i2c_bus, qbus_create(TYPE_I2C_BUS, parent, name));
+    vmstate_register(NULL, -1, &vmstate_i2c_bus, bus);
+    return bus;
+}
+
+void i2c_set_slave_address(I2CSlave *dev, uint8_t address)
+{
+    dev->address = address;
+}
+
+/* Return nonzero if bus is busy.  */
+int i2c_bus_busy(i2c_bus *bus)
+{
+    return bus->current_dev != NULL;
+}
+
+/* Returns non-zero if the address is not valid.  */
+/* TODO: Make this handle multiple masters.  */
+int i2c_start_transfer(i2c_bus *bus, uint8_t address, int recv)
+{
+    BusChild *kid;
+    I2CSlave *slave = NULL;
+    I2CSlaveClass *sc;
+
+    QTAILQ_FOREACH(kid, &bus->qbus.children, sibling) {
+        DeviceState *qdev = kid->child;
+        I2CSlave *candidate = I2C_SLAVE(qdev);
+        if (candidate->address == address) {
+            slave = candidate;
+            break;
+        }
+    }
+
+    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;
+    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) {
+        return;
+    }
+
+    sc = I2C_SLAVE_GET_CLASS(dev);
+    if (sc->event) {
+        sc->event(dev, I2C_FINISH);
+    }
+
+    bus->current_dev = NULL;
+}
+
+int i2c_send(i2c_bus *bus, uint8_t data)
+{
+    I2CSlave *dev = bus->current_dev;
+    I2CSlaveClass *sc;
+
+    if (!dev) {
+        return -1;
+    }
+
+    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) {
+        return -1;
+    }
+
+    sc = I2C_SLAVE_GET_CLASS(dev);
+    if (sc->recv) {
+        return sc->recv(dev);
+    }
+
+    return -1;
+}
+
+void i2c_nack(i2c_bus *bus)
+{
+    I2CSlave *dev = bus->current_dev;
+    I2CSlaveClass *sc;
+
+    if (!dev) {
+        return;
+    }
+
+    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)
+{
+    I2CSlave *dev = opaque;
+    i2c_bus *bus;
+    bus = FROM_QBUS(i2c_bus, qdev_get_parent_bus(&dev->qdev));
+    if (bus->saved_address == dev->address) {
+        bus->current_dev = dev;
+    }
+    return 0;
+}
+
+const VMStateDescription vmstate_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, I2CSlave),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int i2c_slave_qdev_init(DeviceState *dev)
+{
+    I2CSlave *s = I2C_SLAVE(dev);
+    I2CSlaveClass *sc = I2C_SLAVE_GET_CLASS(s);
+
+    return sc->init(s);
+}
+
+DeviceState *i2c_create_slave(i2c_bus *bus, const char *name, uint8_t addr)
+{
+    DeviceState *dev;
+
+    dev = qdev_create(&bus->qbus, name);
+    qdev_prop_set_uint8(dev, "address", addr);
+    qdev_init_nofail(dev);
+    return dev;
+}
+
+static void i2c_slave_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *k = DEVICE_CLASS(klass);
+    k->init = i2c_slave_qdev_init;
+    k->bus_type = TYPE_I2C_BUS;
+    k->props = i2c_props;
+}
+
+static const 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_types(void)
+{
+    type_register_static(&i2c_bus_info);
+    type_register_static(&i2c_slave_type_info);
+}
+
+type_init(i2c_slave_register_types)
diff --git a/hw/i2c/exynos4210_i2c.c b/hw/i2c/exynos4210_i2c.c
new file mode 100644 (file)
index 0000000..196f889
--- /dev/null
@@ -0,0 +1,334 @@
+/*
+ *  Exynos4210 I2C Bus Serial Interface Emulation
+ *
+ *  Copyright (C) 2012 Samsung Electronics Co Ltd.
+ *    Maksim Kozlov, <m.kozlov@samsung.com>
+ *    Igor Mitsyanko, <i.mitsyanko@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/timer.h"
+#include "hw/sysbus.h"
+#include "hw/i2c/i2c.h"
+
+#ifndef EXYNOS4_I2C_DEBUG
+#define EXYNOS4_I2C_DEBUG                 0
+#endif
+
+#define TYPE_EXYNOS4_I2C                  "exynos4210.i2c"
+#define EXYNOS4_I2C(obj)                  \
+    OBJECT_CHECK(Exynos4210I2CState, (obj), TYPE_EXYNOS4_I2C)
+
+/* Exynos4210 I2C memory map */
+#define EXYNOS4_I2C_MEM_SIZE              0x14
+#define I2CCON_ADDR                       0x00  /* control register */
+#define I2CSTAT_ADDR                      0x04  /* control/status register */
+#define I2CADD_ADDR                       0x08  /* address register */
+#define I2CDS_ADDR                        0x0c  /* data shift register */
+#define I2CLC_ADDR                        0x10  /* line control register */
+
+#define I2CCON_ACK_GEN                    (1 << 7)
+#define I2CCON_INTRS_EN                   (1 << 5)
+#define I2CCON_INT_PEND                   (1 << 4)
+
+#define EXYNOS4_I2C_MODE(reg)             (((reg) >> 6) & 3)
+#define I2C_IN_MASTER_MODE(reg)           (((reg) >> 6) & 2)
+#define I2CMODE_MASTER_Rx                 0x2
+#define I2CMODE_MASTER_Tx                 0x3
+#define I2CSTAT_LAST_BIT                  (1 << 0)
+#define I2CSTAT_OUTPUT_EN                 (1 << 4)
+#define I2CSTAT_START_BUSY                (1 << 5)
+
+
+#if EXYNOS4_I2C_DEBUG
+#define DPRINT(fmt, args...)              \
+    do { fprintf(stderr, "QEMU I2C: "fmt, ## args); } while (0)
+
+static const char *exynos4_i2c_get_regname(unsigned offset)
+{
+    switch (offset) {
+    case I2CCON_ADDR:
+        return "I2CCON";
+    case I2CSTAT_ADDR:
+        return "I2CSTAT";
+    case I2CADD_ADDR:
+        return "I2CADD";
+    case I2CDS_ADDR:
+        return "I2CDS";
+    case I2CLC_ADDR:
+        return "I2CLC";
+    default:
+        return "[?]";
+    }
+}
+
+#else
+#define DPRINT(fmt, args...)              do { } while (0)
+#endif
+
+typedef struct Exynos4210I2CState {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    i2c_bus *bus;
+    qemu_irq irq;
+
+    uint8_t i2ccon;
+    uint8_t i2cstat;
+    uint8_t i2cadd;
+    uint8_t i2cds;
+    uint8_t i2clc;
+    bool scl_free;
+} Exynos4210I2CState;
+
+static inline void exynos4210_i2c_raise_interrupt(Exynos4210I2CState *s)
+{
+    if (s->i2ccon & I2CCON_INTRS_EN) {
+        s->i2ccon |= I2CCON_INT_PEND;
+        qemu_irq_raise(s->irq);
+    }
+}
+
+static void exynos4210_i2c_data_receive(void *opaque)
+{
+    Exynos4210I2CState *s = (Exynos4210I2CState *)opaque;
+    int ret;
+
+    s->i2cstat &= ~I2CSTAT_LAST_BIT;
+    s->scl_free = false;
+    ret = i2c_recv(s->bus);
+    if (ret < 0 && (s->i2ccon & I2CCON_ACK_GEN)) {
+        s->i2cstat |= I2CSTAT_LAST_BIT;  /* Data is not acknowledged */
+    } else {
+        s->i2cds = ret;
+    }
+    exynos4210_i2c_raise_interrupt(s);
+}
+
+static void exynos4210_i2c_data_send(void *opaque)
+{
+    Exynos4210I2CState *s = (Exynos4210I2CState *)opaque;
+
+    s->i2cstat &= ~I2CSTAT_LAST_BIT;
+    s->scl_free = false;
+    if (i2c_send(s->bus, s->i2cds) < 0 && (s->i2ccon & I2CCON_ACK_GEN)) {
+        s->i2cstat |= I2CSTAT_LAST_BIT;
+    }
+    exynos4210_i2c_raise_interrupt(s);
+}
+
+static uint64_t exynos4210_i2c_read(void *opaque, hwaddr offset,
+                                 unsigned size)
+{
+    Exynos4210I2CState *s = (Exynos4210I2CState *)opaque;
+    uint8_t value;
+
+    switch (offset) {
+    case I2CCON_ADDR:
+        value = s->i2ccon;
+        break;
+    case I2CSTAT_ADDR:
+        value = s->i2cstat;
+        break;
+    case I2CADD_ADDR:
+        value = s->i2cadd;
+        break;
+    case I2CDS_ADDR:
+        value = s->i2cds;
+        s->scl_free = true;
+        if (EXYNOS4_I2C_MODE(s->i2cstat) == I2CMODE_MASTER_Rx &&
+               (s->i2cstat & I2CSTAT_START_BUSY) &&
+               !(s->i2ccon & I2CCON_INT_PEND)) {
+            exynos4210_i2c_data_receive(s);
+        }
+        break;
+    case I2CLC_ADDR:
+        value = s->i2clc;
+        break;
+    default:
+        value = 0;
+        DPRINT("ERROR: Bad read offset 0x%x\n", (unsigned int)offset);
+        break;
+    }
+
+    DPRINT("read %s [0x%02x] -> 0x%02x\n", exynos4_i2c_get_regname(offset),
+            (unsigned int)offset, value);
+    return value;
+}
+
+static void exynos4210_i2c_write(void *opaque, hwaddr offset,
+                              uint64_t value, unsigned size)
+{
+    Exynos4210I2CState *s = (Exynos4210I2CState *)opaque;
+    uint8_t v = value & 0xff;
+
+    DPRINT("write %s [0x%02x] <- 0x%02x\n", exynos4_i2c_get_regname(offset),
+            (unsigned int)offset, v);
+
+    switch (offset) {
+    case I2CCON_ADDR:
+        s->i2ccon = (v & ~I2CCON_INT_PEND) | (s->i2ccon & I2CCON_INT_PEND);
+        if ((s->i2ccon & I2CCON_INT_PEND) && !(v & I2CCON_INT_PEND)) {
+            s->i2ccon &= ~I2CCON_INT_PEND;
+            qemu_irq_lower(s->irq);
+            if (!(s->i2ccon & I2CCON_INTRS_EN)) {
+                s->i2cstat &= ~I2CSTAT_START_BUSY;
+            }
+
+            if (s->i2cstat & I2CSTAT_START_BUSY) {
+                if (s->scl_free) {
+                    if (EXYNOS4_I2C_MODE(s->i2cstat) == I2CMODE_MASTER_Tx) {
+                        exynos4210_i2c_data_send(s);
+                    } else if (EXYNOS4_I2C_MODE(s->i2cstat) ==
+                            I2CMODE_MASTER_Rx) {
+                        exynos4210_i2c_data_receive(s);
+                    }
+                } else {
+                    s->i2ccon |= I2CCON_INT_PEND;
+                    qemu_irq_raise(s->irq);
+                }
+            }
+        }
+        break;
+    case I2CSTAT_ADDR:
+        s->i2cstat =
+                (s->i2cstat & I2CSTAT_START_BUSY) | (v & ~I2CSTAT_START_BUSY);
+
+        if (!(s->i2cstat & I2CSTAT_OUTPUT_EN)) {
+            s->i2cstat &= ~I2CSTAT_START_BUSY;
+            s->scl_free = true;
+            qemu_irq_lower(s->irq);
+            break;
+        }
+
+        /* Nothing to do if in i2c slave mode */
+        if (!I2C_IN_MASTER_MODE(s->i2cstat)) {
+            break;
+        }
+
+        if (v & I2CSTAT_START_BUSY) {
+            s->i2cstat &= ~I2CSTAT_LAST_BIT;
+            s->i2cstat |= I2CSTAT_START_BUSY;    /* Line is busy */
+            s->scl_free = false;
+
+            /* Generate start bit and send slave address */
+            if (i2c_start_transfer(s->bus, s->i2cds >> 1, s->i2cds & 0x1) &&
+                    (s->i2ccon & I2CCON_ACK_GEN)) {
+                s->i2cstat |= I2CSTAT_LAST_BIT;
+            } else if (EXYNOS4_I2C_MODE(s->i2cstat) == I2CMODE_MASTER_Rx) {
+                exynos4210_i2c_data_receive(s);
+            }
+            exynos4210_i2c_raise_interrupt(s);
+        } else {
+            i2c_end_transfer(s->bus);
+            if (!(s->i2ccon & I2CCON_INT_PEND)) {
+                s->i2cstat &= ~I2CSTAT_START_BUSY;
+            }
+            s->scl_free = true;
+        }
+        break;
+    case I2CADD_ADDR:
+        if ((s->i2cstat & I2CSTAT_OUTPUT_EN) == 0) {
+            s->i2cadd = v;
+        }
+        break;
+    case I2CDS_ADDR:
+        if (s->i2cstat & I2CSTAT_OUTPUT_EN) {
+            s->i2cds = v;
+            s->scl_free = true;
+            if (EXYNOS4_I2C_MODE(s->i2cstat) == I2CMODE_MASTER_Tx &&
+                    (s->i2cstat & I2CSTAT_START_BUSY) &&
+                    !(s->i2ccon & I2CCON_INT_PEND)) {
+                exynos4210_i2c_data_send(s);
+            }
+        }
+        break;
+    case I2CLC_ADDR:
+        s->i2clc = v;
+        break;
+    default:
+        DPRINT("ERROR: Bad write offset 0x%x\n", (unsigned int)offset);
+        break;
+    }
+}
+
+static const MemoryRegionOps exynos4210_i2c_ops = {
+    .read = exynos4210_i2c_read,
+    .write = exynos4210_i2c_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static const VMStateDescription exynos4210_i2c_vmstate = {
+    .name = TYPE_EXYNOS4_I2C,
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT8(i2ccon, Exynos4210I2CState),
+        VMSTATE_UINT8(i2cstat, Exynos4210I2CState),
+        VMSTATE_UINT8(i2cds, Exynos4210I2CState),
+        VMSTATE_UINT8(i2cadd, Exynos4210I2CState),
+        VMSTATE_UINT8(i2clc, Exynos4210I2CState),
+        VMSTATE_BOOL(scl_free, Exynos4210I2CState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void exynos4210_i2c_reset(DeviceState *d)
+{
+    Exynos4210I2CState *s = EXYNOS4_I2C(d);
+
+    s->i2ccon  = 0x00;
+    s->i2cstat = 0x00;
+    s->i2cds   = 0xFF;
+    s->i2clc   = 0x00;
+    s->i2cadd  = 0xFF;
+    s->scl_free = true;
+}
+
+static int exynos4210_i2c_realize(SysBusDevice *dev)
+{
+    Exynos4210I2CState *s = EXYNOS4_I2C(dev);
+
+    memory_region_init_io(&s->iomem, &exynos4210_i2c_ops, s, TYPE_EXYNOS4_I2C,
+                          EXYNOS4_I2C_MEM_SIZE);
+    sysbus_init_mmio(dev, &s->iomem);
+    sysbus_init_irq(dev, &s->irq);
+    s->bus = i2c_init_bus(&dev->qdev, "i2c");
+    return 0;
+}
+
+static void exynos4210_i2c_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *sbdc = SYS_BUS_DEVICE_CLASS(klass);
+
+    dc->vmsd = &exynos4210_i2c_vmstate;
+    dc->reset = exynos4210_i2c_reset;
+    sbdc->init = exynos4210_i2c_realize;
+}
+
+static const TypeInfo exynos4210_i2c_type_info = {
+    .name = TYPE_EXYNOS4_I2C,
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(Exynos4210I2CState),
+    .class_init = exynos4210_i2c_class_init,
+};
+
+static void exynos4210_i2c_register_types(void)
+{
+    type_register_static(&exynos4210_i2c_type_info);
+}
+
+type_init(exynos4210_i2c_register_types)
diff --git a/hw/i2c/omap_i2c.c b/hw/i2c/omap_i2c.c
new file mode 100644 (file)
index 0000000..efb2254
--- /dev/null
@@ -0,0 +1,492 @@
+/*
+ * TI OMAP on-chip I2C controller.  Only "new I2C" mode supported.
+ *
+ * Copyright (C) 2007 Andrzej Zaborowski  <balrog@zabor.org>
+ *
+ * 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 "hw/hw.h"
+#include "hw/i2c/i2c.h"
+#include "hw/arm/omap.h"
+#include "hw/sysbus.h"
+
+
+typedef struct OMAPI2CState {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    qemu_irq irq;
+    qemu_irq drq[2];
+    i2c_bus *bus;
+
+    uint8_t revision;
+    void *iclk;
+    void *fclk;
+
+    uint8_t mask;
+    uint16_t stat;
+    uint16_t dma;
+    uint16_t count;
+    int count_cur;
+    uint32_t fifo;
+    int rxlen;
+    int txlen;
+    uint16_t control;
+    uint16_t addr[2];
+    uint8_t divider;
+    uint8_t times[2];
+    uint16_t test;
+} OMAPI2CState;
+
+#define OMAP2_INTR_REV 0x34
+#define OMAP2_GC_REV   0x34
+
+static void omap_i2c_interrupts_update(OMAPI2CState *s)
+{
+    qemu_set_irq(s->irq, s->stat & s->mask);
+    if ((s->dma >> 15) & 1)                                    /* RDMA_EN */
+        qemu_set_irq(s->drq[0], (s->stat >> 3) & 1);           /* RRDY */
+    if ((s->dma >> 7) & 1)                                     /* XDMA_EN */
+        qemu_set_irq(s->drq[1], (s->stat >> 4) & 1);           /* XRDY */
+}
+
+static void omap_i2c_fifo_run(OMAPI2CState *s)
+{
+    int ack = 1;
+
+    if (!i2c_bus_busy(s->bus))
+        return;
+
+    if ((s->control >> 2) & 1) {                               /* RM */
+        if ((s->control >> 1) & 1) {                           /* STP */
+            i2c_end_transfer(s->bus);
+            s->control &= ~(1 << 1);                           /* STP */
+            s->count_cur = s->count;
+            s->txlen = 0;
+        } else if ((s->control >> 9) & 1) {                    /* TRX */
+            while (ack && s->txlen)
+                ack = (i2c_send(s->bus,
+                                        (s->fifo >> ((-- s->txlen) << 3)) &
+                                        0xff) >= 0);
+            s->stat |= 1 << 4;                                 /* XRDY */
+        } else {
+            while (s->rxlen < 4)
+                s->fifo |= i2c_recv(s->bus) << ((s->rxlen ++) << 3);
+            s->stat |= 1 << 3;                                 /* RRDY */
+        }
+    } else {
+        if ((s->control >> 9) & 1) {                           /* TRX */
+            while (ack && s->count_cur && s->txlen) {
+                ack = (i2c_send(s->bus,
+                                        (s->fifo >> ((-- s->txlen) << 3)) &
+                                        0xff) >= 0);
+                s->count_cur --;
+            }
+            if (ack && s->count_cur)
+                s->stat |= 1 << 4;                             /* XRDY */
+            else
+                s->stat &= ~(1 << 4);                          /* XRDY */
+            if (!s->count_cur) {
+                s->stat |= 1 << 2;                             /* ARDY */
+                s->control &= ~(1 << 10);                      /* MST */
+            }
+        } else {
+            while (s->count_cur && s->rxlen < 4) {
+                s->fifo |= i2c_recv(s->bus) << ((s->rxlen ++) << 3);
+                s->count_cur --;
+            }
+            if (s->rxlen)
+                s->stat |= 1 << 3;                             /* RRDY */
+            else
+                s->stat &= ~(1 << 3);                          /* RRDY */
+        }
+        if (!s->count_cur) {
+            if ((s->control >> 1) & 1) {                       /* STP */
+                i2c_end_transfer(s->bus);
+                s->control &= ~(1 << 1);                       /* STP */
+                s->count_cur = s->count;
+                s->txlen = 0;
+            } else {
+                s->stat |= 1 << 2;                             /* ARDY */
+                s->control &= ~(1 << 10);                      /* MST */
+            }
+        }
+    }
+
+    s->stat |= (!ack) << 1;                                    /* NACK */
+    if (!ack)
+        s->control &= ~(1 << 1);                               /* STP */
+}
+
+static void omap_i2c_reset(DeviceState *dev)
+{
+    OMAPI2CState *s = FROM_SYSBUS(OMAPI2CState,
+                                  SYS_BUS_DEVICE(dev));
+    s->mask = 0;
+    s->stat = 0;
+    s->dma = 0;
+    s->count = 0;
+    s->count_cur = 0;
+    s->fifo = 0;
+    s->rxlen = 0;
+    s->txlen = 0;
+    s->control = 0;
+    s->addr[0] = 0;
+    s->addr[1] = 0;
+    s->divider = 0;
+    s->times[0] = 0;
+    s->times[1] = 0;
+    s->test = 0;
+}
+
+static uint32_t omap_i2c_read(void *opaque, hwaddr addr)
+{
+    OMAPI2CState *s = opaque;
+    int offset = addr & OMAP_MPUI_REG_MASK;
+    uint16_t ret;
+
+    switch (offset) {
+    case 0x00: /* I2C_REV */
+        return s->revision;                                    /* REV */
+
+    case 0x04: /* I2C_IE */
+        return s->mask;
+
+    case 0x08: /* I2C_STAT */
+        return s->stat | (i2c_bus_busy(s->bus) << 12);
+
+    case 0x0c: /* I2C_IV */
+        if (s->revision >= OMAP2_INTR_REV)
+            break;
+        ret = ffs(s->stat & s->mask);
+        if (ret)
+            s->stat ^= 1 << (ret - 1);
+        omap_i2c_interrupts_update(s);
+        return ret;
+
+    case 0x10: /* I2C_SYSS */
+        return (s->control >> 15) & 1;                         /* I2C_EN */
+
+    case 0x14: /* I2C_BUF */
+        return s->dma;
+
+    case 0x18: /* I2C_CNT */
+        return s->count_cur;                                   /* DCOUNT */
+
+    case 0x1c: /* I2C_DATA */
+        ret = 0;
+        if (s->control & (1 << 14)) {                          /* BE */
+            ret |= ((s->fifo >> 0) & 0xff) << 8;
+            ret |= ((s->fifo >> 8) & 0xff) << 0;
+        } else {
+            ret |= ((s->fifo >> 8) & 0xff) << 8;
+            ret |= ((s->fifo >> 0) & 0xff) << 0;
+        }
+        if (s->rxlen == 1) {
+            s->stat |= 1 << 15;                                        /* SBD */
+            s->rxlen = 0;
+        } else if (s->rxlen > 1) {
+            if (s->rxlen > 2)
+                s->fifo >>= 16;
+            s->rxlen -= 2;
+        } else {
+            /* XXX: remote access (qualifier) error - what's that?  */
+        }
+        if (!s->rxlen) {
+            s->stat &= ~(1 << 3);                              /* RRDY */
+            if (((s->control >> 10) & 1) &&                    /* MST */
+                            ((~s->control >> 9) & 1)) {                /* TRX */
+                s->stat |= 1 << 2;                             /* ARDY */
+                s->control &= ~(1 << 10);                      /* MST */
+            }
+        }
+        s->stat &= ~(1 << 11);                                 /* ROVR */
+        omap_i2c_fifo_run(s);
+        omap_i2c_interrupts_update(s);
+        return ret;
+
+    case 0x20: /* I2C_SYSC */
+        return 0;
+
+    case 0x24: /* I2C_CON */
+        return s->control;
+
+    case 0x28: /* I2C_OA */
+        return s->addr[0];
+
+    case 0x2c: /* I2C_SA */
+        return s->addr[1];
+
+    case 0x30: /* I2C_PSC */
+        return s->divider;
+
+    case 0x34: /* I2C_SCLL */
+        return s->times[0];
+
+    case 0x38: /* I2C_SCLH */
+        return s->times[1];
+
+    case 0x3c: /* I2C_SYSTEST */
+        if (s->test & (1 << 15)) {                             /* ST_EN */
+            s->test ^= 0xa;
+            return s->test;
+        } else
+            return s->test & ~0x300f;
+    }
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_i2c_write(void *opaque, hwaddr addr,
+                uint32_t value)
+{
+    OMAPI2CState *s = opaque;
+    int offset = addr & OMAP_MPUI_REG_MASK;
+    int nack;
+
+    switch (offset) {
+    case 0x00: /* I2C_REV */
+    case 0x0c: /* I2C_IV */
+    case 0x10: /* I2C_SYSS */
+        OMAP_RO_REG(addr);
+        return;
+
+    case 0x04: /* I2C_IE */
+        s->mask = value & (s->revision < OMAP2_GC_REV ? 0x1f : 0x3f);
+        break;
+
+    case 0x08: /* I2C_STAT */
+        if (s->revision < OMAP2_INTR_REV) {
+            OMAP_RO_REG(addr);
+            return;
+        }
+
+        /* RRDY and XRDY are reset by hardware. (in all versions???) */
+        s->stat &= ~(value & 0x27);
+        omap_i2c_interrupts_update(s);
+        break;
+
+    case 0x14: /* I2C_BUF */
+        s->dma = value & 0x8080;
+        if (value & (1 << 15))                                 /* RDMA_EN */
+            s->mask &= ~(1 << 3);                              /* RRDY_IE */
+        if (value & (1 << 7))                                  /* XDMA_EN */
+            s->mask &= ~(1 << 4);                              /* XRDY_IE */
+        break;
+
+    case 0x18: /* I2C_CNT */
+        s->count = value;                                      /* DCOUNT */
+        break;
+
+    case 0x1c: /* I2C_DATA */
+        if (s->txlen > 2) {
+            /* XXX: remote access (qualifier) error - what's that?  */
+            break;
+        }
+        s->fifo <<= 16;
+        s->txlen += 2;
+        if (s->control & (1 << 14)) {                          /* BE */
+            s->fifo |= ((value >> 8) & 0xff) << 8;
+            s->fifo |= ((value >> 0) & 0xff) << 0;
+        } else {
+            s->fifo |= ((value >> 0) & 0xff) << 8;
+            s->fifo |= ((value >> 8) & 0xff) << 0;
+        }
+        s->stat &= ~(1 << 10);                                 /* XUDF */
+        if (s->txlen > 2)
+            s->stat &= ~(1 << 4);                              /* XRDY */
+        omap_i2c_fifo_run(s);
+        omap_i2c_interrupts_update(s);
+        break;
+
+    case 0x20: /* I2C_SYSC */
+        if (s->revision < OMAP2_INTR_REV) {
+            OMAP_BAD_REG(addr);
+            return;
+        }
+
+        if (value & 2)
+            omap_i2c_reset(&s->busdev.qdev);
+        break;
+
+    case 0x24: /* I2C_CON */
+        s->control = value & 0xcf87;
+        if (~value & (1 << 15)) {                              /* I2C_EN */
+            if (s->revision < OMAP2_INTR_REV)
+                omap_i2c_reset(&s->busdev.qdev);
+            break;
+        }
+        if ((value & (1 << 15)) && !(value & (1 << 10))) {     /* MST */
+            fprintf(stderr, "%s: I^2C slave mode not supported\n",
+                            __FUNCTION__);
+            break;
+        }
+        if ((value & (1 << 15)) && value & (1 << 8)) {         /* XA */
+            fprintf(stderr, "%s: 10-bit addressing mode not supported\n",
+                            __FUNCTION__);
+            break;
+        }
+        if ((value & (1 << 15)) && value & (1 << 0)) {         /* STT */
+            nack = !!i2c_start_transfer(s->bus, s->addr[1],    /* SA */
+                            (~value >> 9) & 1);                        /* TRX */
+            s->stat |= nack << 1;                              /* NACK */
+            s->control &= ~(1 << 0);                           /* STT */
+            s->fifo = 0;
+            if (nack)
+                s->control &= ~(1 << 1);                       /* STP */
+            else {
+                s->count_cur = s->count;
+                omap_i2c_fifo_run(s);
+            }
+            omap_i2c_interrupts_update(s);
+        }
+        break;
+
+    case 0x28: /* I2C_OA */
+        s->addr[0] = value & 0x3ff;
+        break;
+
+    case 0x2c: /* I2C_SA */
+        s->addr[1] = value & 0x3ff;
+        break;
+
+    case 0x30: /* I2C_PSC */
+        s->divider = value;
+        break;
+
+    case 0x34: /* I2C_SCLL */
+        s->times[0] = value;
+        break;
+
+    case 0x38: /* I2C_SCLH */
+        s->times[1] = value;
+        break;
+
+    case 0x3c: /* I2C_SYSTEST */
+        s->test = value & 0xf80f;
+        if (value & (1 << 11))                                 /* SBB */
+            if (s->revision >= OMAP2_INTR_REV) {
+                s->stat |= 0x3f;
+                omap_i2c_interrupts_update(s);
+            }
+        if (value & (1 << 15))                                 /* ST_EN */
+            fprintf(stderr, "%s: System Test not supported\n", __FUNCTION__);
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+        return;
+    }
+}
+
+static void omap_i2c_writeb(void *opaque, hwaddr addr,
+                uint32_t value)
+{
+    OMAPI2CState *s = opaque;
+    int offset = addr & OMAP_MPUI_REG_MASK;
+
+    switch (offset) {
+    case 0x1c: /* I2C_DATA */
+        if (s->txlen > 2) {
+            /* XXX: remote access (qualifier) error - what's that?  */
+            break;
+        }
+        s->fifo <<= 8;
+        s->txlen += 1;
+        s->fifo |= value & 0xff;
+        s->stat &= ~(1 << 10);                                 /* XUDF */
+        if (s->txlen > 2)
+            s->stat &= ~(1 << 4);                              /* XRDY */
+        omap_i2c_fifo_run(s);
+        omap_i2c_interrupts_update(s);
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+        return;
+    }
+}
+
+static const MemoryRegionOps omap_i2c_ops = {
+    .old_mmio = {
+        .read = {
+            omap_badwidth_read16,
+            omap_i2c_read,
+            omap_badwidth_read16,
+        },
+        .write = {
+            omap_i2c_writeb, /* Only the last fifo write can be 8 bit.  */
+            omap_i2c_write,
+            omap_badwidth_write16,
+        },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int omap_i2c_init(SysBusDevice *dev)
+{
+    OMAPI2CState *s = FROM_SYSBUS(OMAPI2CState, dev);
+
+    if (!s->fclk) {
+        hw_error("omap_i2c: fclk not connected\n");
+    }
+    if (s->revision >= OMAP2_INTR_REV && !s->iclk) {
+        /* Note that OMAP1 doesn't have a separate interface clock */
+        hw_error("omap_i2c: iclk not connected\n");
+    }
+    sysbus_init_irq(dev, &s->irq);
+    sysbus_init_irq(dev, &s->drq[0]);
+    sysbus_init_irq(dev, &s->drq[1]);
+    memory_region_init_io(&s->iomem, &omap_i2c_ops, s, "omap.i2c",
+                          (s->revision < OMAP2_INTR_REV) ? 0x800 : 0x1000);
+    sysbus_init_mmio(dev, &s->iomem);
+    s->bus = i2c_init_bus(&dev->qdev, NULL);
+    return 0;
+}
+
+static Property omap_i2c_properties[] = {
+    DEFINE_PROP_UINT8("revision", OMAPI2CState, revision, 0),
+    DEFINE_PROP_PTR("iclk", OMAPI2CState, iclk),
+    DEFINE_PROP_PTR("fclk", OMAPI2CState, fclk),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void omap_i2c_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+    k->init = omap_i2c_init;
+    dc->props = omap_i2c_properties;
+    dc->reset = omap_i2c_reset;
+}
+
+static const TypeInfo omap_i2c_info = {
+    .name = "omap_i2c",
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(OMAPI2CState),
+    .class_init = omap_i2c_class_init,
+};
+
+static void omap_i2c_register_types(void)
+{
+    type_register_static(&omap_i2c_info);
+}
+
+i2c_bus *omap_i2c_bus(DeviceState *omap_i2c)
+{
+    OMAPI2CState *s = FROM_SYSBUS(OMAPI2CState, SYS_BUS_DEVICE(omap_i2c));
+    return s->bus;
+}
+
+type_init(omap_i2c_register_types)
diff --git a/hw/i2c/pm_smbus.c b/hw/i2c/pm_smbus.c
new file mode 100644 (file)
index 0000000..0b5bb89
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ * PC SMBus implementation
+ * splitted from acpi.c
+ *
+ * Copyright (c) 2006 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * 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/hw.h"
+#include "hw/i386/pc.h"
+#include "hw/i2c/pm_smbus.h"
+#include "hw/i2c/smbus.h"
+
+/* no save/load? */
+
+#define SMBHSTSTS       0x00
+#define SMBHSTCNT       0x02
+#define SMBHSTCMD       0x03
+#define SMBHSTADD       0x04
+#define SMBHSTDAT0      0x05
+#define SMBHSTDAT1      0x06
+#define SMBBLKDAT       0x07
+
+//#define DEBUG
+
+#ifdef DEBUG
+# define SMBUS_DPRINTF(format, ...)     printf(format, ## __VA_ARGS__)
+#else
+# define SMBUS_DPRINTF(format, ...)     do { } while (0)
+#endif
+
+
+static void smb_transaction(PMSMBus *s)
+{
+    uint8_t prot = (s->smb_ctl >> 2) & 0x07;
+    uint8_t read = s->smb_addr & 0x01;
+    uint8_t cmd = s->smb_cmd;
+    uint8_t addr = s->smb_addr >> 1;
+    i2c_bus *bus = s->smbus;
+
+    SMBUS_DPRINTF("SMBus trans addr=0x%02x prot=0x%02x\n", addr, prot);
+    switch(prot) {
+    case 0x0:
+        smbus_quick_command(bus, addr, read);
+        break;
+    case 0x1:
+        if (read) {
+            s->smb_data0 = smbus_receive_byte(bus, addr);
+        } else {
+            smbus_send_byte(bus, addr, cmd);
+        }
+        break;
+    case 0x2:
+        if (read) {
+            s->smb_data0 = smbus_read_byte(bus, addr, cmd);
+        } else {
+            smbus_write_byte(bus, addr, cmd, s->smb_data0);
+        }
+        break;
+    case 0x3:
+        if (read) {
+            uint16_t val;
+            val = smbus_read_word(bus, addr, cmd);
+            s->smb_data0 = val;
+            s->smb_data1 = val >> 8;
+        } else {
+            smbus_write_word(bus, addr, cmd, (s->smb_data1 << 8) | s->smb_data0);
+        }
+        break;
+    case 0x5:
+        if (read) {
+            s->smb_data0 = smbus_read_block(bus, addr, cmd, s->smb_data);
+        } else {
+            smbus_write_block(bus, addr, cmd, s->smb_data, s->smb_data0);
+        }
+        break;
+    default:
+        goto error;
+    }
+    return;
+
+  error:
+    s->smb_stat |= 0x04;
+}
+
+static void smb_ioport_writeb(void *opaque, hwaddr addr, uint64_t val,
+                              unsigned width)
+{
+    PMSMBus *s = opaque;
+
+    SMBUS_DPRINTF("SMB writeb port=0x%04x val=0x%02x\n", addr, val);
+    switch(addr) {
+    case SMBHSTSTS:
+        s->smb_stat = 0;
+        s->smb_index = 0;
+        break;
+    case SMBHSTCNT:
+        s->smb_ctl = val;
+        if (val & 0x40)
+            smb_transaction(s);
+        break;
+    case SMBHSTCMD:
+        s->smb_cmd = val;
+        break;
+    case SMBHSTADD:
+        s->smb_addr = val;
+        break;
+    case SMBHSTDAT0:
+        s->smb_data0 = val;
+        break;
+    case SMBHSTDAT1:
+        s->smb_data1 = val;
+        break;
+    case SMBBLKDAT:
+        s->smb_data[s->smb_index++] = val;
+        if (s->smb_index > 31)
+            s->smb_index = 0;
+        break;
+    default:
+        break;
+    }
+}
+
+static uint64_t smb_ioport_readb(void *opaque, hwaddr addr, unsigned width)
+{
+    PMSMBus *s = opaque;
+    uint32_t val;
+
+    switch(addr) {
+    case SMBHSTSTS:
+        val = s->smb_stat;
+        break;
+    case SMBHSTCNT:
+        s->smb_index = 0;
+        val = s->smb_ctl & 0x1f;
+        break;
+    case SMBHSTCMD:
+        val = s->smb_cmd;
+        break;
+    case SMBHSTADD:
+        val = s->smb_addr;
+        break;
+    case SMBHSTDAT0:
+        val = s->smb_data0;
+        break;
+    case SMBHSTDAT1:
+        val = s->smb_data1;
+        break;
+    case SMBBLKDAT:
+        val = s->smb_data[s->smb_index++];
+        if (s->smb_index > 31)
+            s->smb_index = 0;
+        break;
+    default:
+        val = 0;
+        break;
+    }
+    SMBUS_DPRINTF("SMB readb port=0x%04x val=0x%02x\n", addr, val);
+    return val;
+}
+
+static const MemoryRegionOps pm_smbus_ops = {
+    .read = smb_ioport_readb,
+    .write = smb_ioport_writeb,
+    .valid.min_access_size = 1,
+    .valid.max_access_size = 1,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+void pm_smbus_init(DeviceState *parent, PMSMBus *smb)
+{
+    smb->smbus = i2c_init_bus(parent, "i2c");
+    memory_region_init_io(&smb->io, &pm_smbus_ops, smb, "pm-smbus", 64);
+}
diff --git a/hw/i2c/smbus.c b/hw/i2c/smbus.c
new file mode 100644 (file)
index 0000000..25d2d04
--- /dev/null
@@ -0,0 +1,335 @@
+/*
+ * QEMU SMBus device emulation.
+ *
+ * Copyright (c) 2007 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the LGPL.
+ */
+
+/* TODO: Implement PEC.  */
+
+#include "hw/hw.h"
+#include "hw/i2c/i2c.h"
+#include "hw/i2c/smbus.h"
+
+//#define DEBUG_SMBUS 1
+
+#ifdef DEBUG_SMBUS
+#define DPRINTF(fmt, ...) \
+do { printf("smbus(%02x): " fmt , dev->i2c.address, ## __VA_ARGS__); } while (0)
+#define BADF(fmt, ...) \
+do { fprintf(stderr, "smbus: error: " fmt , ## __VA_ARGS__); exit(1);} while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while(0)
+#define BADF(fmt, ...) \
+do { fprintf(stderr, "smbus: error: " fmt , ## __VA_ARGS__);} while (0)
+#endif
+
+enum {
+    SMBUS_IDLE,
+    SMBUS_WRITE_DATA,
+    SMBUS_RECV_BYTE,
+    SMBUS_READ_DATA,
+    SMBUS_DONE,
+    SMBUS_CONFUSED = -1
+};
+
+static void smbus_do_quick_cmd(SMBusDevice *dev, int recv)
+{
+    SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev);
+
+    DPRINTF("Quick Command %d\n", recv);
+    if (sc->quick_cmd) {
+        sc->quick_cmd(dev, recv);
+    }
+}
+
+static void smbus_do_write(SMBusDevice *dev)
+{
+    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 (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 (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 = SMBUS_DEVICE(s);
+
+    switch (event) {
+    case I2C_START_SEND:
+        switch (dev->mode) {
+        case SMBUS_IDLE:
+            DPRINTF("Incoming data\n");
+            dev->mode = SMBUS_WRITE_DATA;
+            break;
+        default:
+            BADF("Unexpected send start condition in state %d\n", dev->mode);
+            dev->mode = SMBUS_CONFUSED;
+            break;
+        }
+        break;
+
+    case I2C_START_RECV:
+        switch (dev->mode) {
+        case SMBUS_IDLE:
+            DPRINTF("Read mode\n");
+            dev->mode = SMBUS_RECV_BYTE;
+            break;
+        case SMBUS_WRITE_DATA:
+            if (dev->data_len == 0) {
+                BADF("Read after write with no data\n");
+                dev->mode = SMBUS_CONFUSED;
+            } else {
+                if (dev->data_len > 1) {
+                    smbus_do_write(dev);
+                } else {
+                    dev->command = dev->data_buf[0];
+                    DPRINTF("%02x: Command %d\n", dev->i2c.address,
+                            dev->command);
+                }
+                DPRINTF("Read mode\n");
+                dev->data_len = 0;
+                dev->mode = SMBUS_READ_DATA;
+            }
+            break;
+        default:
+            BADF("Unexpected recv start condition in state %d\n", dev->mode);
+            dev->mode = SMBUS_CONFUSED;
+            break;
+        }
+        break;
+
+    case I2C_FINISH:
+        switch (dev->mode) {
+        case SMBUS_WRITE_DATA:
+            smbus_do_write(dev);
+            break;
+        case SMBUS_RECV_BYTE:
+            smbus_do_quick_cmd(dev, 1);
+            break;
+        case SMBUS_READ_DATA:
+            BADF("Unexpected stop during receive\n");
+            break;
+        default:
+            /* Nothing to do.  */
+            break;
+        }
+        dev->mode = SMBUS_IDLE;
+        dev->data_len = 0;
+        break;
+
+    case I2C_NACK:
+        switch (dev->mode) {
+        case SMBUS_DONE:
+            /* Nothing to do.  */
+            break;
+        case SMBUS_READ_DATA:
+            dev->mode = SMBUS_DONE;
+            break;
+        default:
+            BADF("Unexpected NACK in state %d\n", dev->mode);
+            dev->mode = SMBUS_CONFUSED;
+            break;
+        }
+    }
+}
+
+static int smbus_i2c_recv(I2CSlave *s)
+{
+    SMBusDevice *dev = SMBUS_DEVICE(s);
+    SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev);
+    int ret;
+
+    switch (dev->mode) {
+    case SMBUS_RECV_BYTE:
+        if (sc->receive_byte) {
+            ret = sc->receive_byte(dev);
+        } else {
+            ret = 0;
+        }
+        DPRINTF("Receive Byte %02x\n", ret);
+        dev->mode = SMBUS_DONE;
+        break;
+    case SMBUS_READ_DATA:
+        if (sc->read_data) {
+            ret = sc->read_data(dev, dev->command, dev->data_len);
+            dev->data_len++;
+        } else {
+            ret = 0;
+        }
+        DPRINTF("Read data %02x\n", ret);
+        break;
+    default:
+        BADF("Unexpected read in state %d\n", dev->mode);
+        dev->mode = SMBUS_CONFUSED;
+        ret = 0;
+        break;
+    }
+    return ret;
+}
+
+static int smbus_i2c_send(I2CSlave *s, uint8_t data)
+{
+    SMBusDevice *dev = SMBUS_DEVICE(s);
+
+    switch (dev->mode) {
+    case SMBUS_WRITE_DATA:
+        DPRINTF("Write data %02x\n", data);
+        dev->data_buf[dev->data_len++] = data;
+        break;
+    default:
+        BADF("Unexpected write in state %d\n", dev->mode);
+        break;
+    }
+    return 0;
+}
+
+static int smbus_device_init(I2CSlave *i2c)
+{
+    SMBusDevice *dev = SMBUS_DEVICE(i2c);
+    SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev);
+
+    return sc->init(dev);
+}
+
+/* Master device commands.  */
+void smbus_quick_command(i2c_bus *bus, uint8_t addr, int read)
+{
+    i2c_start_transfer(bus, addr, read);
+    i2c_end_transfer(bus);
+}
+
+uint8_t smbus_receive_byte(i2c_bus *bus, uint8_t addr)
+{
+    uint8_t data;
+
+    i2c_start_transfer(bus, addr, 1);
+    data = i2c_recv(bus);
+    i2c_nack(bus);
+    i2c_end_transfer(bus);
+    return data;
+}
+
+void smbus_send_byte(i2c_bus *bus, uint8_t addr, uint8_t data)
+{
+    i2c_start_transfer(bus, addr, 0);
+    i2c_send(bus, data);
+    i2c_end_transfer(bus);
+}
+
+uint8_t smbus_read_byte(i2c_bus *bus, uint8_t addr, uint8_t command)
+{
+    uint8_t data;
+    i2c_start_transfer(bus, addr, 0);
+    i2c_send(bus, command);
+    i2c_start_transfer(bus, addr, 1);
+    data = i2c_recv(bus);
+    i2c_nack(bus);
+    i2c_end_transfer(bus);
+    return data;
+}
+
+void smbus_write_byte(i2c_bus *bus, uint8_t addr, uint8_t command, uint8_t data)
+{
+    i2c_start_transfer(bus, addr, 0);
+    i2c_send(bus, command);
+    i2c_send(bus, data);
+    i2c_end_transfer(bus);
+}
+
+uint16_t smbus_read_word(i2c_bus *bus, uint8_t addr, uint8_t command)
+{
+    uint16_t data;
+    i2c_start_transfer(bus, addr, 0);
+    i2c_send(bus, command);
+    i2c_start_transfer(bus, addr, 1);
+    data = i2c_recv(bus);
+    data |= i2c_recv(bus) << 8;
+    i2c_nack(bus);
+    i2c_end_transfer(bus);
+    return data;
+}
+
+void smbus_write_word(i2c_bus *bus, uint8_t addr, uint8_t command, uint16_t data)
+{
+    i2c_start_transfer(bus, addr, 0);
+    i2c_send(bus, command);
+    i2c_send(bus, data & 0xff);
+    i2c_send(bus, data >> 8);
+    i2c_end_transfer(bus);
+}
+
+int smbus_read_block(i2c_bus *bus, uint8_t addr, uint8_t command, uint8_t *data)
+{
+    int len;
+    int i;
+
+    i2c_start_transfer(bus, addr, 0);
+    i2c_send(bus, command);
+    i2c_start_transfer(bus, addr, 1);
+    len = i2c_recv(bus);
+    if (len > 32)
+        len = 0;
+    for (i = 0; i < len; i++)
+        data[i] = i2c_recv(bus);
+    i2c_nack(bus);
+    i2c_end_transfer(bus);
+    return len;
+}
+
+void smbus_write_block(i2c_bus *bus, uint8_t addr, uint8_t command, uint8_t *data,
+                       int len)
+{
+    int i;
+
+    if (len > 32)
+        len = 32;
+
+    i2c_start_transfer(bus, addr, 0);
+    i2c_send(bus, command);
+    i2c_send(bus, len);
+    for (i = 0; i < len; i++)
+        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 const 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_types(void)
+{
+    type_register_static(&smbus_device_type_info);
+}
+
+type_init(smbus_device_register_types)
diff --git a/hw/i2c/smbus_eeprom.c b/hw/i2c/smbus_eeprom.c
new file mode 100644 (file)
index 0000000..0154283
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * QEMU SMBus EEPROM device
+ *
+ * Copyright (c) 2007 Arastra, 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 "hw/hw.h"
+#include "hw/i2c/i2c.h"
+#include "hw/i2c/smbus.h"
+
+//#define DEBUG
+
+typedef struct SMBusEEPROMDevice {
+    SMBusDevice smbusdev;
+    void *data;
+    uint8_t offset;
+} SMBusEEPROMDevice;
+
+static void eeprom_quick_cmd(SMBusDevice *dev, uint8_t read)
+{
+#ifdef DEBUG
+    printf("eeprom_quick_cmd: addr=0x%02x read=%d\n", dev->i2c.address, read);
+#endif
+}
+
+static void eeprom_send_byte(SMBusDevice *dev, uint8_t val)
+{
+    SMBusEEPROMDevice *eeprom = (SMBusEEPROMDevice *) dev;
+#ifdef DEBUG
+    printf("eeprom_send_byte: addr=0x%02x val=0x%02x\n",
+           dev->i2c.address, val);
+#endif
+    eeprom->offset = val;
+}
+
+static uint8_t eeprom_receive_byte(SMBusDevice *dev)
+{
+    SMBusEEPROMDevice *eeprom = (SMBusEEPROMDevice *) dev;
+    uint8_t *data = eeprom->data;
+    uint8_t val = data[eeprom->offset++];
+#ifdef DEBUG
+    printf("eeprom_receive_byte: addr=0x%02x val=0x%02x\n",
+           dev->i2c.address, val);
+#endif
+    return val;
+}
+
+static void eeprom_write_data(SMBusDevice *dev, uint8_t cmd, uint8_t *buf, int len)
+{
+    SMBusEEPROMDevice *eeprom = (SMBusEEPROMDevice *) dev;
+    int n;
+#ifdef DEBUG
+    printf("eeprom_write_byte: addr=0x%02x cmd=0x%02x val=0x%02x\n",
+           dev->i2c.address, cmd, buf[0]);
+#endif
+    /* An page write operation is not a valid SMBus command.
+       It is a block write without a length byte.  Fortunately we
+       get the full block anyway.  */
+    /* TODO: Should this set the current location?  */
+    if (cmd + len > 256)
+        n = 256 - cmd;
+    else
+        n = len;
+    memcpy(eeprom->data + cmd, buf, n);
+    len -= n;
+    if (len)
+        memcpy(eeprom->data, buf + n, len);
+}
+
+static uint8_t eeprom_read_data(SMBusDevice *dev, uint8_t cmd, int n)
+{
+    SMBusEEPROMDevice *eeprom = (SMBusEEPROMDevice *) dev;
+    /* If this is the first byte then set the current position.  */
+    if (n == 0)
+        eeprom->offset = cmd;
+    /* As with writes, we implement block reads without the
+       SMBus length byte.  */
+    return eeprom_receive_byte(dev);
+}
+
+static int smbus_eeprom_initfn(SMBusDevice *dev)
+{
+    SMBusEEPROMDevice *eeprom = (SMBusEEPROMDevice *)dev;
+
+    eeprom->offset = 0;
+    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;
+    sc->quick_cmd = eeprom_quick_cmd;
+    sc->send_byte = eeprom_send_byte;
+    sc->receive_byte = eeprom_receive_byte;
+    sc->write_data = eeprom_write_data;
+    sc->read_data = eeprom_read_data;
+    dc->props = smbus_eeprom_properties;
+}
+
+static const 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_types(void)
+{
+    type_register_static(&smbus_eeprom_info);
+}
+
+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)
+{
+    int i;
+    uint8_t *eeprom_buf = g_malloc0(8 * 256); /* XXX: make this persistent */
+    if (eeprom_spd_size > 0) {
+        memcpy(eeprom_buf, eeprom_spd, eeprom_spd_size);
+    }
+
+    for (i = 0; i < nb_eeprom; i++) {
+        DeviceState *eeprom;
+        eeprom = qdev_create((BusState *)smbus, "smbus-eeprom");
+        qdev_prop_set_uint8(eeprom, "address", 0x50 + i);
+        qdev_prop_set_ptr(eeprom, "data", eeprom_buf + (i * 256));
+        qdev_init_nofail(eeprom);
+    }
+}
diff --git a/hw/i2c/smbus_ich9.c b/hw/i2c/smbus_ich9.c
new file mode 100644 (file)
index 0000000..ca22978
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * ACPI implementation
+ *
+ * Copyright (c) 2006 Fabrice Bellard
+ * Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp>
+ *               VA Linux Systems Japan K.K.
+ * Copyright (C) 2012 Jason Baron <jbaron@redhat.com>
+ *
+ * This is based on acpi.c, but heavily rewritten.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * 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/>
+ *
+ * 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/hw.h"
+#include "hw/i386/pc.h"
+#include "hw/i2c/pm_smbus.h"
+#include "hw/pci/pci.h"
+#include "sysemu/sysemu.h"
+#include "hw/i2c/i2c.h"
+#include "hw/i2c/smbus.h"
+
+#include "hw/i386/ich9.h"
+
+#define TYPE_ICH9_SMB_DEVICE "ICH9 SMB"
+#define ICH9_SMB_DEVICE(obj) \
+     OBJECT_CHECK(ICH9SMBState, (obj), TYPE_ICH9_SMB_DEVICE)
+
+typedef struct ICH9SMBState {
+    PCIDevice dev;
+
+    PMSMBus smb;
+} ICH9SMBState;
+
+static const VMStateDescription vmstate_ich9_smbus = {
+    .name = "ich9_smb",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_PCI_DEVICE(dev, struct ICH9SMBState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void ich9_smbus_write_config(PCIDevice *d, uint32_t address,
+                                    uint32_t val, int len)
+{
+    ICH9SMBState *s = ICH9_SMB_DEVICE(d);
+
+    pci_default_write_config(d, address, val, len);
+    if (range_covers_byte(address, len, ICH9_SMB_HOSTC)) {
+        uint8_t hostc = s->dev.config[ICH9_SMB_HOSTC];
+        if ((hostc & ICH9_SMB_HOSTC_HST_EN) &&
+            !(hostc & ICH9_SMB_HOSTC_I2C_EN)) {
+            memory_region_set_enabled(&s->smb.io, true);
+        } else {
+            memory_region_set_enabled(&s->smb.io, false);
+        }
+    }
+}
+
+static int ich9_smbus_initfn(PCIDevice *d)
+{
+    ICH9SMBState *s = ICH9_SMB_DEVICE(d);
+
+    /* TODO? D31IP.SMIP in chipset configuration space */
+    pci_config_set_interrupt_pin(d->config, 0x01); /* interrupt pin 1 */
+
+    pci_set_byte(d->config + ICH9_SMB_HOSTC, 0);
+    /* TODO bar0, bar1: 64bit BAR support*/
+
+    pm_smbus_init(&d->qdev, &s->smb);
+    pci_register_bar(d, ICH9_SMB_SMB_BASE_BAR, PCI_BASE_ADDRESS_SPACE_IO,
+                     &s->smb.io);
+    return 0;
+}
+
+static void ich9_smb_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->vendor_id = PCI_VENDOR_ID_INTEL;
+    k->device_id = PCI_DEVICE_ID_INTEL_ICH9_6;
+    k->revision = ICH9_A2_SMB_REVISION;
+    k->class_id = PCI_CLASS_SERIAL_SMBUS;
+    dc->no_user = 1;
+    dc->vmsd = &vmstate_ich9_smbus;
+    dc->desc = "ICH9 SMBUS Bridge";
+    k->init = ich9_smbus_initfn;
+    k->config_write = ich9_smbus_write_config;
+}
+
+i2c_bus *ich9_smb_init(PCIBus *bus, int devfn, uint32_t smb_io_base)
+{
+    PCIDevice *d =
+        pci_create_simple_multifunction(bus, devfn, true, TYPE_ICH9_SMB_DEVICE);
+    ICH9SMBState *s = ICH9_SMB_DEVICE(d);
+    return s->smb.smbus;
+}
+
+static const TypeInfo ich9_smb_info = {
+    .name   = TYPE_ICH9_SMB_DEVICE,
+    .parent = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(ICH9SMBState),
+    .class_init = ich9_smb_class_init,
+};
+
+static void ich9_smb_register(void)
+{
+    type_register_static(&ich9_smb_info);
+}
+
+type_init(ich9_smb_register);
diff --git a/hw/i2c/versatile_i2c.c b/hw/i2c/versatile_i2c.c
new file mode 100644 (file)
index 0000000..e09c83d
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * ARM Versatile I2C controller
+ *
+ * Copyright (c) 2006-2007 CodeSourcery.
+ * Copyright (c) 2012 Oskar Andero <oskar.andero@gmail.com>
+ *
+ * This file is derived from hw/realview.c by Paul Brook
+ *
+ * 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 "hw/sysbus.h"
+#include "bitbang_i2c.h"
+
+typedef struct {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    bitbang_i2c_interface *bitbang;
+    int out;
+    int in;
+} VersatileI2CState;
+
+static uint64_t versatile_i2c_read(void *opaque, hwaddr offset,
+                                   unsigned size)
+{
+    VersatileI2CState *s = (VersatileI2CState *)opaque;
+
+    if (offset == 0) {
+        return (s->out & 1) | (s->in << 1);
+    } else {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: Bad offset 0x%x\n", __func__, (int)offset);
+        return -1;
+    }
+}
+
+static void versatile_i2c_write(void *opaque, hwaddr offset,
+                                uint64_t value, unsigned size)
+{
+    VersatileI2CState *s = (VersatileI2CState *)opaque;
+
+    switch (offset) {
+    case 0:
+        s->out |= value & 3;
+        break;
+    case 4:
+        s->out &= ~value;
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: Bad offset 0x%x\n", __func__, (int)offset);
+    }
+    bitbang_i2c_set(s->bitbang, BITBANG_I2C_SCL, (s->out & 1) != 0);
+    s->in = bitbang_i2c_set(s->bitbang, BITBANG_I2C_SDA, (s->out & 2) != 0);
+}
+
+static const MemoryRegionOps versatile_i2c_ops = {
+    .read = versatile_i2c_read,
+    .write = versatile_i2c_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int versatile_i2c_init(SysBusDevice *dev)
+{
+    VersatileI2CState *s = FROM_SYSBUS(VersatileI2CState, dev);
+    i2c_bus *bus;
+
+    bus = i2c_init_bus(&dev->qdev, "i2c");
+    s->bitbang = bitbang_i2c_init(bus);
+    memory_region_init_io(&s->iomem, &versatile_i2c_ops, s,
+                          "versatile_i2c", 0x1000);
+    sysbus_init_mmio(dev, &s->iomem);
+    return 0;
+}
+
+static void versatile_i2c_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = versatile_i2c_init;
+}
+
+static const TypeInfo versatile_i2c_info = {
+    .name          = "versatile_i2c",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(VersatileI2CState),
+    .class_init    = versatile_i2c_class_init,
+};
+
+static void versatile_i2c_register_types(void)
+{
+    type_register_static(&versatile_i2c_info);
+}
+
+type_init(versatile_i2c_register_types)
index a78c0b2921617a7ad9111197344a9abdc00f303b..205d22e4aa88fb25dd0d7ed4fde22913c3745b1a 100644 (file)
@@ -1,20 +1,4 @@
-obj-y += mc146818rtc.o
-obj-y += apic_common.o apic.o
-obj-y += sga.o ioapic_common.o ioapic.o piix_pci.o
-obj-y += vmport.o
-obj-y += pci/pci-hotplug.o wdt_ib700.o
-obj-y += debugcon.o debugexit.o
-obj-y += pc_sysfw.o
-obj-y += lpc_ich9.o q35.o
-obj-$(CONFIG_XEN) += xen_platform.o xen_apic.o
-obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen-host-pci-device.o
-obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen_pt.o xen_pt_config_init.o xen_pt_msi.o
-obj-y += kvm/
-obj-$(CONFIG_SPICE) += qxl.o qxl-logger.o qxl-render.o
-obj-y += pc-testdev.o
-
-obj-y := $(addprefix ../,$(obj-y))
-
+obj-$(CONFIG_KVM) += kvm/
 obj-y += multiboot.o smbios.o
 obj-y += pc.o pc_piix.o pc_q35.o
 obj-$(CONFIG_XEN) += xen_domainbuild.o xen_machine_pv.o
diff --git a/hw/i386/kvm/Makefile.objs b/hw/i386/kvm/Makefile.objs
new file mode 100644 (file)
index 0000000..d8bce20
--- /dev/null
@@ -0,0 +1 @@
+obj-y += clock.o apic.o i8259.o ioapic.o i8254.o pci-assign.o
diff --git a/hw/i386/kvm/apic.c b/hw/i386/kvm/apic.c
new file mode 100644 (file)
index 0000000..c6ff982
--- /dev/null
@@ -0,0 +1,209 @@
+/*
+ * KVM in-kernel APIC support
+ *
+ * Copyright (c) 2011 Siemens AG
+ *
+ * Authors:
+ *  Jan Kiszka          <jan.kiszka@siemens.com>
+ *
+ * This work is licensed under the terms of the GNU GPL version 2.
+ * See the COPYING file in the top-level directory.
+ */
+#include "hw/i386/apic_internal.h"
+#include "hw/pci/msi.h"
+#include "sysemu/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 uint8_t kvm_apic_get_tpr(APICCommonState *s)
+{
+    return s->tpr >> 4;
+}
+
+static void kvm_apic_enable_tpr_reporting(APICCommonState *s, bool enable)
+{
+    struct kvm_tpr_access_ctl ctl = {
+        .enabled = enable
+    };
+
+    kvm_vcpu_ioctl(CPU(s->cpu), KVM_TPR_ACCESS_REPORTING, &ctl);
+}
+
+static void kvm_apic_vapic_base_update(APICCommonState *s)
+{
+    struct kvm_vapic_addr vapid_addr = {
+        .vapic_addr = s->vapic_paddr,
+    };
+    int ret;
+
+    ret = kvm_vcpu_ioctl(CPU(s->cpu), KVM_SET_VAPIC_ADDR, &vapid_addr);
+    if (ret < 0) {
+        fprintf(stderr, "KVM: setting VAPIC address failed (%s)\n",
+                strerror(-ret));
+        abort();
+    }
+}
+
+static void do_inject_external_nmi(void *data)
+{
+    APICCommonState *s = data;
+    CPUState *cpu = CPU(s->cpu);
+    uint32_t lvt;
+    int ret;
+
+    cpu_synchronize_state(&s->cpu->env);
+
+    lvt = s->lvt[APIC_LVT_LINT1];
+    if (!(lvt & APIC_LVT_MASKED) && ((lvt >> 8) & 7) == APIC_DM_NMI) {
+        ret = kvm_vcpu_ioctl(cpu, 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(CPU(s->cpu), do_inject_external_nmi, s);
+}
+
+static uint64_t kvm_apic_mem_read(void *opaque, hwaddr addr,
+                                  unsigned size)
+{
+    return ~(uint64_t)0;
+}
+
+static void kvm_apic_mem_write(void *opaque, hwaddr addr,
+                               uint64_t data, unsigned size)
+{
+    MSIMessage msg = { .address = addr, .data = data };
+    int ret;
+
+    ret = kvm_irqchip_send_msi(kvm_state, msg);
+    if (ret < 0) {
+        fprintf(stderr, "KVM: injection failed, MSI lost (%s)\n",
+                strerror(-ret));
+    }
+}
+
+static const MemoryRegionOps kvm_apic_io_ops = {
+    .read = kvm_apic_mem_read,
+    .write = kvm_apic_mem_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void kvm_apic_init(APICCommonState *s)
+{
+    memory_region_init_io(&s->io_memory, &kvm_apic_io_ops, s, "kvm-apic-msi",
+                          MSI_SPACE_SIZE);
+
+    if (kvm_has_gsi_routing()) {
+        msi_supported = true;
+    }
+}
+
+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->get_tpr = kvm_apic_get_tpr;
+    k->enable_tpr_reporting = kvm_apic_enable_tpr_reporting;
+    k->vapic_base_update = kvm_apic_vapic_base_update;
+    k->external_nmi = kvm_apic_external_nmi;
+}
+
+static const TypeInfo kvm_apic_info = {
+    .name = "kvm-apic",
+    .parent = TYPE_APIC_COMMON,
+    .instance_size = sizeof(APICCommonState),
+    .class_init = kvm_apic_class_init,
+};
+
+static void kvm_apic_register_types(void)
+{
+    type_register_static(&kvm_apic_info);
+}
+
+type_init(kvm_apic_register_types)
diff --git a/hw/i386/kvm/clock.c b/hw/i386/kvm/clock.c
new file mode 100644 (file)
index 0000000..fa40e28
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * QEMU KVM support, paravirtual clock device
+ *
+ * Copyright (C) 2011 Siemens AG
+ *
+ * Authors:
+ *  Jan Kiszka        <jan.kiszka@siemens.com>
+ *
+ * This work is licensed under the terms of the GNU GPL version 2.
+ * See the COPYING file in the top-level directory.
+ *
+ * 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/sysemu.h"
+#include "sysemu/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;
+    CPUArchState *penv = first_cpu;
+    int cap_clock_ctrl = kvm_check_extension(kvm_state, KVM_CAP_KVMCLOCK_CTRL);
+    int ret;
+
+    if (running) {
+        s->clock_valid = false;
+
+        if (!cap_clock_ctrl) {
+            return;
+        }
+        for (penv = first_cpu; penv != NULL; penv = penv->next_cpu) {
+            ret = kvm_vcpu_ioctl(ENV_GET_CPU(penv), KVM_KVMCLOCK_CTRL, 0);
+            if (ret) {
+                if (ret != -EINVAL) {
+                    fprintf(stderr, "%s: %s\n", __func__, strerror(-ret));
+                }
+                return;
+            }
+        }
+    }
+}
+
+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 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 const 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. */
+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_types(void)
+{
+    type_register_static(&kvmclock_info);
+}
+
+type_init(kvmclock_register_types)
diff --git a/hw/i386/kvm/i8254.c b/hw/i386/kvm/i8254.c
new file mode 100644 (file)
index 0000000..da90711
--- /dev/null
@@ -0,0 +1,317 @@
+/*
+ * KVM in-kernel PIT (i8254) support
+ *
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ * Copyright (c) 2012      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 "qemu/timer.h"
+#include "sysemu/sysemu.h"
+#include "hw/timer/i8254.h"
+#include "hw/timer/i8254_internal.h"
+#include "sysemu/kvm.h"
+
+#define KVM_PIT_REINJECT_BIT 0
+
+#define CALIBRATION_ROUNDS   3
+
+typedef struct KVMPITState {
+    PITCommonState pit;
+    LostTickPolicy lost_tick_policy;
+    bool vm_stopped;
+    int64_t kernel_clock_offset;
+} KVMPITState;
+
+static int64_t abs64(int64_t v)
+{
+    return v < 0 ? -v : v;
+}
+
+static void kvm_pit_update_clock_offset(KVMPITState *s)
+{
+    int64_t offset, clock_offset;
+    struct timespec ts;
+    int i;
+
+    /*
+     * Measure the delta between CLOCK_MONOTONIC, the base used for
+     * kvm_pit_channel_state::count_load_time, and vm_clock. Take the
+     * minimum of several samples to filter out scheduling noise.
+     */
+    clock_offset = INT64_MAX;
+    for (i = 0; i < CALIBRATION_ROUNDS; i++) {
+        offset = qemu_get_clock_ns(vm_clock);
+        clock_gettime(CLOCK_MONOTONIC, &ts);
+        offset -= ts.tv_nsec;
+        offset -= (int64_t)ts.tv_sec * 1000000000;
+        if (abs64(offset) < abs64(clock_offset)) {
+            clock_offset = offset;
+        }
+    }
+    s->kernel_clock_offset = clock_offset;
+}
+
+static void kvm_pit_get(PITCommonState *pit)
+{
+    KVMPITState *s = DO_UPCAST(KVMPITState, pit, pit);
+    struct kvm_pit_state2 kpit;
+    struct kvm_pit_channel_state *kchan;
+    struct PITChannelState *sc;
+    int i, ret;
+
+    /* No need to re-read the state if VM is stopped. */
+    if (s->vm_stopped) {
+        return;
+    }
+
+    if (kvm_has_pit_state2()) {
+        ret = kvm_vm_ioctl(kvm_state, KVM_GET_PIT2, &kpit);
+        if (ret < 0) {
+            fprintf(stderr, "KVM_GET_PIT2 failed: %s\n", strerror(ret));
+            abort();
+        }
+        pit->channels[0].irq_disabled = kpit.flags & KVM_PIT_FLAGS_HPET_LEGACY;
+    } else {
+        /*
+         * kvm_pit_state2 is superset of kvm_pit_state struct,
+         * so we can use it for KVM_GET_PIT as well.
+         */
+        ret = kvm_vm_ioctl(kvm_state, KVM_GET_PIT, &kpit);
+        if (ret < 0) {
+            fprintf(stderr, "KVM_GET_PIT failed: %s\n", strerror(ret));
+            abort();
+        }
+    }
+    for (i = 0; i < 3; i++) {
+        kchan = &kpit.channels[i];
+        sc = &pit->channels[i];
+        sc->count = kchan->count;
+        sc->latched_count = kchan->latched_count;
+        sc->count_latched = kchan->count_latched;
+        sc->status_latched = kchan->status_latched;
+        sc->status = kchan->status;
+        sc->read_state = kchan->read_state;
+        sc->write_state = kchan->write_state;
+        sc->write_latch = kchan->write_latch;
+        sc->rw_mode = kchan->rw_mode;
+        sc->mode = kchan->mode;
+        sc->bcd = kchan->bcd;
+        sc->gate = kchan->gate;
+        sc->count_load_time = kchan->count_load_time + s->kernel_clock_offset;
+    }
+
+    sc = &pit->channels[0];
+    sc->next_transition_time =
+        pit_get_next_transition_time(sc, sc->count_load_time);
+}
+
+static void kvm_pit_put(PITCommonState *pit)
+{
+    KVMPITState *s = DO_UPCAST(KVMPITState, pit, pit);
+    struct kvm_pit_state2 kpit;
+    struct kvm_pit_channel_state *kchan;
+    struct PITChannelState *sc;
+    int i, ret;
+
+    /* The offset keeps changing as long as the VM is stopped. */
+    if (s->vm_stopped) {
+        kvm_pit_update_clock_offset(s);
+    }
+
+    kpit.flags = pit->channels[0].irq_disabled ? KVM_PIT_FLAGS_HPET_LEGACY : 0;
+    for (i = 0; i < 3; i++) {
+        kchan = &kpit.channels[i];
+        sc = &pit->channels[i];
+        kchan->count = sc->count;
+        kchan->latched_count = sc->latched_count;
+        kchan->count_latched = sc->count_latched;
+        kchan->status_latched = sc->status_latched;
+        kchan->status = sc->status;
+        kchan->read_state = sc->read_state;
+        kchan->write_state = sc->write_state;
+        kchan->write_latch = sc->write_latch;
+        kchan->rw_mode = sc->rw_mode;
+        kchan->mode = sc->mode;
+        kchan->bcd = sc->bcd;
+        kchan->gate = sc->gate;
+        kchan->count_load_time = sc->count_load_time - s->kernel_clock_offset;
+    }
+
+    ret = kvm_vm_ioctl(kvm_state,
+                       kvm_has_pit_state2() ? KVM_SET_PIT2 : KVM_SET_PIT,
+                       &kpit);
+    if (ret < 0) {
+        fprintf(stderr, "%s failed: %s\n",
+                kvm_has_pit_state2() ? "KVM_SET_PIT2" : "KVM_SET_PIT",
+                strerror(ret));
+        abort();
+    }
+}
+
+static void kvm_pit_set_gate(PITCommonState *s, PITChannelState *sc, int val)
+{
+    kvm_pit_get(s);
+
+    switch (sc->mode) {
+    default:
+    case 0:
+    case 4:
+        /* XXX: just disable/enable counting */
+        break;
+    case 1:
+    case 2:
+    case 3:
+    case 5:
+        if (sc->gate < val) {
+            /* restart counting on rising edge */
+            sc->count_load_time = qemu_get_clock_ns(vm_clock);
+        }
+        break;
+    }
+    sc->gate = val;
+
+    kvm_pit_put(s);
+}
+
+static void kvm_pit_get_channel_info(PITCommonState *s, PITChannelState *sc,
+                                     PITChannelInfo *info)
+{
+    kvm_pit_get(s);
+
+    pit_get_channel_info_common(s, sc, info);
+}
+
+static void kvm_pit_reset(DeviceState *dev)
+{
+    PITCommonState *s = DO_UPCAST(PITCommonState, dev.qdev, dev);
+
+    pit_reset_common(s);
+
+    kvm_pit_put(s);
+}
+
+static void kvm_pit_irq_control(void *opaque, int n, int enable)
+{
+    PITCommonState *pit = opaque;
+    PITChannelState *s = &pit->channels[0];
+
+    kvm_pit_get(pit);
+
+    s->irq_disabled = !enable;
+
+    kvm_pit_put(pit);
+}
+
+static void kvm_pit_vm_state_change(void *opaque, int running,
+                                    RunState state)
+{
+    KVMPITState *s = opaque;
+
+    if (running) {
+        kvm_pit_update_clock_offset(s);
+        s->vm_stopped = false;
+    } else {
+        kvm_pit_update_clock_offset(s);
+        kvm_pit_get(&s->pit);
+        s->vm_stopped = true;
+    }
+}
+
+static int kvm_pit_initfn(PITCommonState *pit)
+{
+    KVMPITState *s = DO_UPCAST(KVMPITState, pit, pit);
+    struct kvm_pit_config config = {
+        .flags = 0,
+    };
+    int ret;
+
+    if (kvm_check_extension(kvm_state, KVM_CAP_PIT2)) {
+        ret = kvm_vm_ioctl(kvm_state, KVM_CREATE_PIT2, &config);
+    } else {
+        ret = kvm_vm_ioctl(kvm_state, KVM_CREATE_PIT);
+    }
+    if (ret < 0) {
+        fprintf(stderr, "Create kernel PIC irqchip failed: %s\n",
+                strerror(ret));
+        return ret;
+    }
+    switch (s->lost_tick_policy) {
+    case LOST_TICK_DELAY:
+        break; /* enabled by default */
+    case LOST_TICK_DISCARD:
+        if (kvm_check_extension(kvm_state, KVM_CAP_REINJECT_CONTROL)) {
+            struct kvm_reinject_control control = { .pit_reinject = 0 };
+
+            ret = kvm_vm_ioctl(kvm_state, KVM_REINJECT_CONTROL, &control);
+            if (ret < 0) {
+                fprintf(stderr,
+                        "Can't disable in-kernel PIT reinjection: %s\n",
+                        strerror(ret));
+                return ret;
+            }
+        }
+        break;
+    default:
+        return -EINVAL;
+    }
+
+    memory_region_init_reservation(&pit->ioports, "kvm-pit", 4);
+
+    qdev_init_gpio_in(&pit->dev.qdev, kvm_pit_irq_control, 1);
+
+    qemu_add_vm_change_state_handler(kvm_pit_vm_state_change, s);
+
+    return 0;
+}
+
+static Property kvm_pit_properties[] = {
+    DEFINE_PROP_HEX32("iobase", KVMPITState, pit.iobase,  -1),
+    DEFINE_PROP_LOSTTICKPOLICY("lost_tick_policy", KVMPITState,
+                               lost_tick_policy, LOST_TICK_DELAY),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void kvm_pit_class_init(ObjectClass *klass, void *data)
+{
+    PITCommonClass *k = PIT_COMMON_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    k->init = kvm_pit_initfn;
+    k->set_channel_gate = kvm_pit_set_gate;
+    k->get_channel_info = kvm_pit_get_channel_info;
+    k->pre_save = kvm_pit_get;
+    k->post_load = kvm_pit_put;
+    dc->reset = kvm_pit_reset;
+    dc->props = kvm_pit_properties;
+}
+
+static const TypeInfo kvm_pit_info = {
+    .name          = "kvm-pit",
+    .parent        = TYPE_PIT_COMMON,
+    .instance_size = sizeof(KVMPITState),
+    .class_init = kvm_pit_class_init,
+};
+
+static void kvm_pit_register(void)
+{
+    type_register_static(&kvm_pit_info);
+}
+
+type_init(kvm_pit_register)
diff --git a/hw/i386/kvm/i8259.c b/hw/i386/kvm/i8259.c
new file mode 100644 (file)
index 0000000..ea77be8
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * KVM in-kernel PIC (i8259) support
+ *
+ * Copyright (c) 2011 Siemens AG
+ *
+ * Authors:
+ *  Jan Kiszka          <jan.kiszka@siemens.com>
+ *
+ * This work is licensed under the terms of the GNU GPL version 2.
+ * See the COPYING file in the top-level directory.
+ */
+#include "hw/isa/i8259_internal.h"
+#include "hw/i386/apic_internal.h"
+#include "sysemu/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);
+
+    s->elcr = 0;
+    pic_reset_common(s);
+
+    kvm_pic_put(s);
+}
+
+static void kvm_pic_set_irq(void *opaque, int irq, int level)
+{
+    int delivered;
+
+    delivered = kvm_set_irq(kvm_state, irq, level);
+    apic_report_irq_delivered(delivered);
+}
+
+static void kvm_pic_init(PICCommonState *s)
+{
+    memory_region_init_reservation(&s->base_io, "kvm-pic", 2);
+    memory_region_init_reservation(&s->elcr_io, "kvm-elcr", 1);
+}
+
+qemu_irq *kvm_i8259_init(ISABus *bus)
+{
+    i8259_init_chip("kvm-i8259", bus, true);
+    i8259_init_chip("kvm-i8259", bus, false);
+
+    return qemu_allocate_irqs(kvm_pic_set_irq, NULL, ISA_NUM_IRQS);
+}
+
+static void kvm_i8259_class_init(ObjectClass *klass, void *data)
+{
+    PICCommonClass *k = PIC_COMMON_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->reset     = kvm_pic_reset;
+    k->init       = kvm_pic_init;
+    k->pre_save   = kvm_pic_get;
+    k->post_load  = kvm_pic_put;
+}
+
+static const TypeInfo kvm_i8259_info = {
+    .name  = "kvm-i8259",
+    .parent = TYPE_PIC_COMMON,
+    .instance_size = sizeof(PICCommonState),
+    .class_init = kvm_i8259_class_init,
+};
+
+static void kvm_pic_register_types(void)
+{
+    type_register_static(&kvm_i8259_info);
+}
+
+type_init(kvm_pic_register_types)
diff --git a/hw/i386/kvm/ioapic.c b/hw/i386/kvm/ioapic.c
new file mode 100644 (file)
index 0000000..a3bd519
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * KVM in-kernel IOPIC support
+ *
+ * Copyright (c) 2011 Siemens AG
+ *
+ * Authors:
+ *  Jan Kiszka          <jan.kiszka@siemens.com>
+ *
+ * This work is licensed under the terms of the GNU GPL version 2.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "hw/i386/pc.h"
+#include "hw/i386/ioapic_internal.h"
+#include "hw/i386/apic_internal.h"
+#include "sysemu/kvm.h"
+
+/* PC Utility function */
+void kvm_pc_setup_irq_routing(bool pci_enabled)
+{
+    KVMState *s = kvm_state;
+    int i;
+
+    if (kvm_check_extension(s, KVM_CAP_IRQ_ROUTING)) {
+        for (i = 0; i < 8; ++i) {
+            if (i == 2) {
+                continue;
+            }
+            kvm_irqchip_add_irq_route(s, i, KVM_IRQCHIP_PIC_MASTER, i);
+        }
+        for (i = 8; i < 16; ++i) {
+            kvm_irqchip_add_irq_route(s, i, KVM_IRQCHIP_PIC_SLAVE, i - 8);
+        }
+        if (pci_enabled) {
+            for (i = 0; i < 24; ++i) {
+                if (i == 0) {
+                    kvm_irqchip_add_irq_route(s, i, KVM_IRQCHIP_IOAPIC, 2);
+                } else if (i != 2) {
+                    kvm_irqchip_add_irq_route(s, i, KVM_IRQCHIP_IOAPIC, i);
+                }
+            }
+        }
+    }
+}
+
+void kvm_pc_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);
+    }
+}
+
+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_set_irq(kvm_state, s->kvm_gsi_base + irq, level);
+    apic_report_irq_delivered(delivered);
+}
+
+static void kvm_ioapic_init(IOAPICCommonState *s, int instance_no)
+{
+    memory_region_init_reservation(&s->io_memory, "kvm-ioapic", 0x1000);
+
+    qdev_init_gpio_in(&s->busdev.qdev, kvm_ioapic_set_irq, IOAPIC_NUM_PINS);
+}
+
+static Property kvm_ioapic_properties[] = {
+    DEFINE_PROP_UINT32("gsi_base", KVMIOAPICState, kvm_gsi_base, 0),
+    DEFINE_PROP_END_OF_LIST()
+};
+
+static void kvm_ioapic_class_init(ObjectClass *klass, void *data)
+{
+    IOAPICCommonClass *k = IOAPIC_COMMON_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    k->init      = kvm_ioapic_init;
+    k->pre_save  = kvm_ioapic_get;
+    k->post_load = kvm_ioapic_put;
+    dc->reset    = kvm_ioapic_reset;
+    dc->props    = kvm_ioapic_properties;
+}
+
+static const TypeInfo kvm_ioapic_info = {
+    .name  = "kvm-ioapic",
+    .parent = TYPE_IOAPIC_COMMON,
+    .instance_size = sizeof(KVMIOAPICState),
+    .class_init = kvm_ioapic_class_init,
+};
+
+static void kvm_ioapic_register_types(void)
+{
+    type_register_static(&kvm_ioapic_info);
+}
+
+type_init(kvm_ioapic_register_types)
diff --git a/hw/i386/kvm/pci-assign.c b/hw/i386/kvm/pci-assign.c
new file mode 100644 (file)
index 0000000..c1e08ec
--- /dev/null
@@ -0,0 +1,1924 @@
+/*
+ * Copyright (c) 2007, Neocleus Corporation.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ *
+ *  Assign a PCI device from the host to a guest VM.
+ *
+ *  This implementation uses the classic device assignment interface of KVM
+ *  and is only available on x86 hosts. It is expected to be obsoleted by VFIO
+ *  based device assignment.
+ *
+ *  Adapted for KVM (qemu-kvm) by Qumranet. QEMU version was based on qemu-kvm
+ *  revision 4144fe9d48. See its repository for the history.
+ *
+ *  Copyright (c) 2007, Neocleus, Alex Novik (alex@neocleus.com)
+ *  Copyright (c) 2007, Neocleus, Guy Zana (guy@neocleus.com)
+ *  Copyright (C) 2008, Qumranet, Amit Shah (amit.shah@qumranet.com)
+ *  Copyright (C) 2008, Red Hat, Amit Shah (amit.shah@redhat.com)
+ *  Copyright (C) 2008, IBM, Muli Ben-Yehuda (muli@il.ibm.com)
+ */
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/io.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "hw/hw.h"
+#include "hw/i386/pc.h"
+#include "qemu/error-report.h"
+#include "ui/console.h"
+#include "hw/loader.h"
+#include "monitor/monitor.h"
+#include "qemu/range.h"
+#include "sysemu/sysemu.h"
+#include "hw/pci/pci.h"
+#include "hw/pci/msi.h"
+#include "kvm_i386.h"
+
+#define MSIX_PAGE_SIZE 0x1000
+
+/* From linux/ioport.h */
+#define IORESOURCE_IO       0x00000100  /* Resource type */
+#define IORESOURCE_MEM      0x00000200
+#define IORESOURCE_IRQ      0x00000400
+#define IORESOURCE_DMA      0x00000800
+#define IORESOURCE_PREFETCH 0x00002000  /* No side effects */
+#define IORESOURCE_MEM_64   0x00100000
+
+//#define DEVICE_ASSIGNMENT_DEBUG
+
+#ifdef DEVICE_ASSIGNMENT_DEBUG
+#define DEBUG(fmt, ...)                                       \
+    do {                                                      \
+        fprintf(stderr, "%s: " fmt, __func__ , __VA_ARGS__);  \
+    } while (0)
+#else
+#define DEBUG(fmt, ...)
+#endif
+
+typedef struct PCIRegion {
+    int type;           /* Memory or port I/O */
+    int valid;
+    uint64_t base_addr;
+    uint64_t size;    /* size of the region */
+    int resource_fd;
+} PCIRegion;
+
+typedef struct PCIDevRegions {
+    uint8_t bus, dev, func; /* Bus inside domain, device and function */
+    int irq;                /* IRQ number */
+    uint16_t region_number; /* number of active regions */
+
+    /* Port I/O or MMIO Regions */
+    PCIRegion regions[PCI_NUM_REGIONS - 1];
+    int config_fd;
+} PCIDevRegions;
+
+typedef struct AssignedDevRegion {
+    MemoryRegion container;
+    MemoryRegion real_iomem;
+    union {
+        uint8_t *r_virtbase; /* mmapped access address for memory regions */
+        uint32_t r_baseport; /* the base guest port for I/O regions */
+    } u;
+    pcibus_t e_size;    /* emulated size of region in bytes */
+    pcibus_t r_size;    /* real size of region in bytes */
+    PCIRegion *region;
+} AssignedDevRegion;
+
+#define ASSIGNED_DEVICE_PREFER_MSI_BIT  0
+#define ASSIGNED_DEVICE_SHARE_INTX_BIT  1
+
+#define ASSIGNED_DEVICE_PREFER_MSI_MASK (1 << ASSIGNED_DEVICE_PREFER_MSI_BIT)
+#define ASSIGNED_DEVICE_SHARE_INTX_MASK (1 << ASSIGNED_DEVICE_SHARE_INTX_BIT)
+
+typedef struct MSIXTableEntry {
+    uint32_t addr_lo;
+    uint32_t addr_hi;
+    uint32_t data;
+    uint32_t ctrl;
+} MSIXTableEntry;
+
+typedef enum AssignedIRQType {
+    ASSIGNED_IRQ_NONE = 0,
+    ASSIGNED_IRQ_INTX_HOST_INTX,
+    ASSIGNED_IRQ_INTX_HOST_MSI,
+    ASSIGNED_IRQ_MSI,
+    ASSIGNED_IRQ_MSIX
+} AssignedIRQType;
+
+typedef struct AssignedDevice {
+    PCIDevice dev;
+    PCIHostDeviceAddress host;
+    uint32_t dev_id;
+    uint32_t features;
+    int intpin;
+    AssignedDevRegion v_addrs[PCI_NUM_REGIONS - 1];
+    PCIDevRegions real_device;
+    PCIINTxRoute intx_route;
+    AssignedIRQType assigned_irq_type;
+    struct {
+#define ASSIGNED_DEVICE_CAP_MSI (1 << 0)
+#define ASSIGNED_DEVICE_CAP_MSIX (1 << 1)
+        uint32_t available;
+#define ASSIGNED_DEVICE_MSI_ENABLED (1 << 0)
+#define ASSIGNED_DEVICE_MSIX_ENABLED (1 << 1)
+#define ASSIGNED_DEVICE_MSIX_MASKED (1 << 2)
+        uint32_t state;
+    } cap;
+    uint8_t emulate_config_read[PCI_CONFIG_SPACE_SIZE];
+    uint8_t emulate_config_write[PCI_CONFIG_SPACE_SIZE];
+    int msi_virq_nr;
+    int *msi_virq;
+    MSIXTableEntry *msix_table;
+    hwaddr msix_table_addr;
+    uint16_t msix_max;
+    MemoryRegion mmio;
+    char *configfd_name;
+    int32_t bootindex;
+} AssignedDevice;
+
+static void assigned_dev_update_irq_routing(PCIDevice *dev);
+
+static void assigned_dev_load_option_rom(AssignedDevice *dev);
+
+static void assigned_dev_unregister_msix_mmio(AssignedDevice *dev);
+
+static uint64_t assigned_dev_ioport_rw(AssignedDevRegion *dev_region,
+                                       hwaddr addr, int size,
+                                       uint64_t *data)
+{
+    uint64_t val = 0;
+    int fd = dev_region->region->resource_fd;
+
+    if (fd >= 0) {
+        if (data) {
+            DEBUG("pwrite data=%" PRIx64 ", size=%d, e_phys=" TARGET_FMT_plx
+                  ", addr="TARGET_FMT_plx"\n", *data, size, addr, addr);
+            if (pwrite(fd, data, size, addr) != size) {
+                error_report("%s - pwrite failed %s",
+                             __func__, strerror(errno));
+            }
+        } else {
+            if (pread(fd, &val, size, addr) != size) {
+                error_report("%s - pread failed %s",
+                             __func__, strerror(errno));
+                val = (1UL << (size * 8)) - 1;
+            }
+            DEBUG("pread val=%" PRIx64 ", size=%d, e_phys=" TARGET_FMT_plx
+                  ", addr=" TARGET_FMT_plx "\n", val, size, addr, addr);
+        }
+    } else {
+        uint32_t port = addr + dev_region->u.r_baseport;
+
+        if (data) {
+            DEBUG("out data=%" PRIx64 ", size=%d, e_phys=" TARGET_FMT_plx
+                  ", host=%x\n", *data, size, addr, port);
+            switch (size) {
+            case 1:
+                outb(*data, port);
+                break;
+            case 2:
+                outw(*data, port);
+                break;
+            case 4:
+                outl(*data, port);
+                break;
+            }
+        } else {
+            switch (size) {
+            case 1:
+                val = inb(port);
+                break;
+            case 2:
+                val = inw(port);
+                break;
+            case 4:
+                val = inl(port);
+                break;
+            }
+            DEBUG("in data=%" PRIx64 ", size=%d, e_phys=" TARGET_FMT_plx
+                  ", host=%x\n", val, size, addr, port);
+        }
+    }
+    return val;
+}
+
+static void assigned_dev_ioport_write(void *opaque, hwaddr addr,
+                                      uint64_t data, unsigned size)
+{
+    assigned_dev_ioport_rw(opaque, addr, size, &data);
+}
+
+static uint64_t assigned_dev_ioport_read(void *opaque,
+                                         hwaddr addr, unsigned size)
+{
+    return assigned_dev_ioport_rw(opaque, addr, size, NULL);
+}
+
+static uint32_t slow_bar_readb(void *opaque, hwaddr addr)
+{
+    AssignedDevRegion *d = opaque;
+    uint8_t *in = d->u.r_virtbase + addr;
+    uint32_t r;
+
+    r = *in;
+    DEBUG("slow_bar_readl addr=0x" TARGET_FMT_plx " val=0x%08x\n", addr, r);
+
+    return r;
+}
+
+static uint32_t slow_bar_readw(void *opaque, hwaddr addr)
+{
+    AssignedDevRegion *d = opaque;
+    uint16_t *in = (uint16_t *)(d->u.r_virtbase + addr);
+    uint32_t r;
+
+    r = *in;
+    DEBUG("slow_bar_readl addr=0x" TARGET_FMT_plx " val=0x%08x\n", addr, r);
+
+    return r;
+}
+
+static uint32_t slow_bar_readl(void *opaque, hwaddr addr)
+{
+    AssignedDevRegion *d = opaque;
+    uint32_t *in = (uint32_t *)(d->u.r_virtbase + addr);
+    uint32_t r;
+
+    r = *in;
+    DEBUG("slow_bar_readl addr=0x" TARGET_FMT_plx " val=0x%08x\n", addr, r);
+
+    return r;
+}
+
+static void slow_bar_writeb(void *opaque, hwaddr addr, uint32_t val)
+{
+    AssignedDevRegion *d = opaque;
+    uint8_t *out = d->u.r_virtbase + addr;
+
+    DEBUG("slow_bar_writeb addr=0x" TARGET_FMT_plx " val=0x%02x\n", addr, val);
+    *out = val;
+}
+
+static void slow_bar_writew(void *opaque, hwaddr addr, uint32_t val)
+{
+    AssignedDevRegion *d = opaque;
+    uint16_t *out = (uint16_t *)(d->u.r_virtbase + addr);
+
+    DEBUG("slow_bar_writew addr=0x" TARGET_FMT_plx " val=0x%04x\n", addr, val);
+    *out = val;
+}
+
+static void slow_bar_writel(void *opaque, hwaddr addr, uint32_t val)
+{
+    AssignedDevRegion *d = opaque;
+    uint32_t *out = (uint32_t *)(d->u.r_virtbase + addr);
+
+    DEBUG("slow_bar_writel addr=0x" TARGET_FMT_plx " val=0x%08x\n", addr, val);
+    *out = val;
+}
+
+static const MemoryRegionOps slow_bar_ops = {
+    .old_mmio = {
+        .read = { slow_bar_readb, slow_bar_readw, slow_bar_readl, },
+        .write = { slow_bar_writeb, slow_bar_writew, slow_bar_writel, },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void assigned_dev_iomem_setup(PCIDevice *pci_dev, int region_num,
+                                     pcibus_t e_size)
+{
+    AssignedDevice *r_dev = DO_UPCAST(AssignedDevice, dev, pci_dev);
+    AssignedDevRegion *region = &r_dev->v_addrs[region_num];
+    PCIRegion *real_region = &r_dev->real_device.regions[region_num];
+
+    if (e_size > 0) {
+        memory_region_init(&region->container, "assigned-dev-container",
+                           e_size);
+        memory_region_add_subregion(&region->container, 0, &region->real_iomem);
+
+        /* deal with MSI-X MMIO page */
+        if (real_region->base_addr <= r_dev->msix_table_addr &&
+                real_region->base_addr + real_region->size >
+                r_dev->msix_table_addr) {
+            uint64_t offset = r_dev->msix_table_addr - real_region->base_addr;
+
+            memory_region_add_subregion_overlap(&region->container,
+                                                offset,
+                                                &r_dev->mmio,
+                                                1);
+        }
+    }
+}
+
+static const MemoryRegionOps assigned_dev_ioport_ops = {
+    .read = assigned_dev_ioport_read,
+    .write = assigned_dev_ioport_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void assigned_dev_ioport_setup(PCIDevice *pci_dev, int region_num,
+                                      pcibus_t size)
+{
+    AssignedDevice *r_dev = DO_UPCAST(AssignedDevice, dev, pci_dev);
+    AssignedDevRegion *region = &r_dev->v_addrs[region_num];
+
+    region->e_size = size;
+    memory_region_init(&region->container, "assigned-dev-container", size);
+    memory_region_init_io(&region->real_iomem, &assigned_dev_ioport_ops,
+                          r_dev->v_addrs + region_num,
+                          "assigned-dev-iomem", size);
+    memory_region_add_subregion(&region->container, 0, &region->real_iomem);
+}
+
+static uint32_t assigned_dev_pci_read(PCIDevice *d, int pos, int len)
+{
+    AssignedDevice *pci_dev = DO_UPCAST(AssignedDevice, dev, d);
+    uint32_t val;
+    ssize_t ret;
+    int fd = pci_dev->real_device.config_fd;
+
+again:
+    ret = pread(fd, &val, len, pos);
+    if (ret != len) {
+        if ((ret < 0) && (errno == EINTR || errno == EAGAIN)) {
+            goto again;
+        }
+
+        hw_error("pci read failed, ret = %zd errno = %d\n", ret, errno);
+    }
+
+    return val;
+}
+
+static uint8_t assigned_dev_pci_read_byte(PCIDevice *d, int pos)
+{
+    return (uint8_t)assigned_dev_pci_read(d, pos, 1);
+}
+
+static void assigned_dev_pci_write(PCIDevice *d, int pos, uint32_t val, int len)
+{
+    AssignedDevice *pci_dev = DO_UPCAST(AssignedDevice, dev, d);
+    ssize_t ret;
+    int fd = pci_dev->real_device.config_fd;
+
+again:
+    ret = pwrite(fd, &val, len, pos);
+    if (ret != len) {
+        if ((ret < 0) && (errno == EINTR || errno == EAGAIN)) {
+            goto again;
+        }
+
+        hw_error("pci write failed, ret = %zd errno = %d\n", ret, errno);
+    }
+}
+
+static void assigned_dev_emulate_config_read(AssignedDevice *dev,
+                                             uint32_t offset, uint32_t len)
+{
+    memset(dev->emulate_config_read + offset, 0xff, len);
+}
+
+static void assigned_dev_direct_config_read(AssignedDevice *dev,
+                                            uint32_t offset, uint32_t len)
+{
+    memset(dev->emulate_config_read + offset, 0, len);
+}
+
+static void assigned_dev_direct_config_write(AssignedDevice *dev,
+                                             uint32_t offset, uint32_t len)
+{
+    memset(dev->emulate_config_write + offset, 0, len);
+}
+
+static uint8_t pci_find_cap_offset(PCIDevice *d, uint8_t cap, uint8_t start)
+{
+    int id;
+    int max_cap = 48;
+    int pos = start ? start : PCI_CAPABILITY_LIST;
+    int status;
+
+    status = assigned_dev_pci_read_byte(d, PCI_STATUS);
+    if ((status & PCI_STATUS_CAP_LIST) == 0) {
+        return 0;
+    }
+
+    while (max_cap--) {
+        pos = assigned_dev_pci_read_byte(d, pos);
+        if (pos < 0x40) {
+            break;
+        }
+
+        pos &= ~3;
+        id = assigned_dev_pci_read_byte(d, pos + PCI_CAP_LIST_ID);
+
+        if (id == 0xff) {
+            break;
+        }
+        if (id == cap) {
+            return pos;
+        }
+
+        pos += PCI_CAP_LIST_NEXT;
+    }
+    return 0;
+}
+
+static int assigned_dev_register_regions(PCIRegion *io_regions,
+                                         unsigned long regions_num,
+                                         AssignedDevice *pci_dev)
+{
+    uint32_t i;
+    PCIRegion *cur_region = io_regions;
+
+    for (i = 0; i < regions_num; i++, cur_region++) {
+        if (!cur_region->valid) {
+            continue;
+        }
+
+        /* handle memory io regions */
+        if (cur_region->type & IORESOURCE_MEM) {
+            int t = PCI_BASE_ADDRESS_SPACE_MEMORY;
+            if (cur_region->type & IORESOURCE_PREFETCH) {
+                t |= PCI_BASE_ADDRESS_MEM_PREFETCH;
+            }
+            if (cur_region->type & IORESOURCE_MEM_64) {
+                t |= PCI_BASE_ADDRESS_MEM_TYPE_64;
+            }
+
+            /* map physical memory */
+            pci_dev->v_addrs[i].u.r_virtbase = mmap(NULL, cur_region->size,
+                                                    PROT_WRITE | PROT_READ,
+                                                    MAP_SHARED,
+                                                    cur_region->resource_fd,
+                                                    (off_t)0);
+
+            if (pci_dev->v_addrs[i].u.r_virtbase == MAP_FAILED) {
+                pci_dev->v_addrs[i].u.r_virtbase = NULL;
+                error_report("%s: Error: Couldn't mmap 0x%" PRIx64 "!",
+                             __func__, cur_region->base_addr);
+                return -1;
+            }
+
+            pci_dev->v_addrs[i].r_size = cur_region->size;
+            pci_dev->v_addrs[i].e_size = 0;
+
+            /* add offset */
+            pci_dev->v_addrs[i].u.r_virtbase +=
+                (cur_region->base_addr & 0xFFF);
+
+            if (cur_region->size & 0xFFF) {
+                error_report("PCI region %d at address 0x%" PRIx64 " has "
+                             "size 0x%" PRIx64 ", which is not a multiple of "
+                             "4K.  You might experience some performance hit "
+                             "due to that.",
+                             i, cur_region->base_addr, cur_region->size);
+                memory_region_init_io(&pci_dev->v_addrs[i].real_iomem,
+                                      &slow_bar_ops, &pci_dev->v_addrs[i],
+                                      "assigned-dev-slow-bar",
+                                      cur_region->size);
+            } else {
+                void *virtbase = pci_dev->v_addrs[i].u.r_virtbase;
+                char name[32];
+                snprintf(name, sizeof(name), "%s.bar%d",
+                         object_get_typename(OBJECT(pci_dev)), i);
+                memory_region_init_ram_ptr(&pci_dev->v_addrs[i].real_iomem,
+                                           name, cur_region->size,
+                                           virtbase);
+                vmstate_register_ram(&pci_dev->v_addrs[i].real_iomem,
+                                     &pci_dev->dev.qdev);
+            }
+
+            assigned_dev_iomem_setup(&pci_dev->dev, i, cur_region->size);
+            pci_register_bar((PCIDevice *) pci_dev, i, t,
+                             &pci_dev->v_addrs[i].container);
+            continue;
+        } else {
+            /* handle port io regions */
+            uint32_t val;
+            int ret;
+
+            /* Test kernel support for ioport resource read/write.  Old
+             * kernels return EIO.  New kernels only allow 1/2/4 byte reads
+             * so should return EINVAL for a 3 byte read */
+            ret = pread(pci_dev->v_addrs[i].region->resource_fd, &val, 3, 0);
+            if (ret >= 0) {
+                error_report("Unexpected return from I/O port read: %d", ret);
+                abort();
+            } else if (errno != EINVAL) {
+                error_report("Kernel doesn't support ioport resource "
+                             "access, hiding this region.");
+                close(pci_dev->v_addrs[i].region->resource_fd);
+                cur_region->valid = 0;
+                continue;
+            }
+
+            pci_dev->v_addrs[i].u.r_baseport = cur_region->base_addr;
+            pci_dev->v_addrs[i].r_size = cur_region->size;
+            pci_dev->v_addrs[i].e_size = 0;
+
+            assigned_dev_ioport_setup(&pci_dev->dev, i, cur_region->size);
+            pci_register_bar((PCIDevice *) pci_dev, i,
+                             PCI_BASE_ADDRESS_SPACE_IO,
+                             &pci_dev->v_addrs[i].container);
+        }
+    }
+
+    /* success */
+    return 0;
+}
+
+static int get_real_id(const char *devpath, const char *idname, uint16_t *val)
+{
+    FILE *f;
+    char name[128];
+    long id;
+
+    snprintf(name, sizeof(name), "%s%s", devpath, idname);
+    f = fopen(name, "r");
+    if (f == NULL) {
+        error_report("%s: %s: %m", __func__, name);
+        return -1;
+    }
+    if (fscanf(f, "%li\n", &id) == 1) {
+        *val = id;
+    } else {
+        return -1;
+    }
+    fclose(f);
+
+    return 0;
+}
+
+static int get_real_vendor_id(const char *devpath, uint16_t *val)
+{
+    return get_real_id(devpath, "vendor", val);
+}
+
+static int get_real_device_id(const char *devpath, uint16_t *val)
+{
+    return get_real_id(devpath, "device", val);
+}
+
+static int get_real_device(AssignedDevice *pci_dev, uint16_t r_seg,
+                           uint8_t r_bus, uint8_t r_dev, uint8_t r_func)
+{
+    char dir[128], name[128];
+    int fd, r = 0, v;
+    FILE *f;
+    uint64_t start, end, size, flags;
+    uint16_t id;
+    PCIRegion *rp;
+    PCIDevRegions *dev = &pci_dev->real_device;
+
+    dev->region_number = 0;
+
+    snprintf(dir, sizeof(dir), "/sys/bus/pci/devices/%04x:%02x:%02x.%x/",
+             r_seg, r_bus, r_dev, r_func);
+
+    snprintf(name, sizeof(name), "%sconfig", dir);
+
+    if (pci_dev->configfd_name && *pci_dev->configfd_name) {
+        dev->config_fd = monitor_handle_fd_param(cur_mon, pci_dev->configfd_name);
+        if (dev->config_fd < 0) {
+            return 1;
+        }
+    } else {
+        dev->config_fd = open(name, O_RDWR);
+
+        if (dev->config_fd == -1) {
+            error_report("%s: %s: %m", __func__, name);
+            return 1;
+        }
+    }
+again:
+    r = read(dev->config_fd, pci_dev->dev.config,
+             pci_config_size(&pci_dev->dev));
+    if (r < 0) {
+        if (errno == EINTR || errno == EAGAIN) {
+            goto again;
+        }
+        error_report("%s: read failed, errno = %d", __func__, errno);
+    }
+
+    /* Restore or clear multifunction, this is always controlled by qemu */
+    if (pci_dev->dev.cap_present & QEMU_PCI_CAP_MULTIFUNCTION) {
+        pci_dev->dev.config[PCI_HEADER_TYPE] |= PCI_HEADER_TYPE_MULTI_FUNCTION;
+    } else {
+        pci_dev->dev.config[PCI_HEADER_TYPE] &= ~PCI_HEADER_TYPE_MULTI_FUNCTION;
+    }
+
+    /* Clear host resource mapping info.  If we choose not to register a
+     * BAR, such as might be the case with the option ROM, we can get
+     * confusing, unwritable, residual addresses from the host here. */
+    memset(&pci_dev->dev.config[PCI_BASE_ADDRESS_0], 0, 24);
+    memset(&pci_dev->dev.config[PCI_ROM_ADDRESS], 0, 4);
+
+    snprintf(name, sizeof(name), "%sresource", dir);
+
+    f = fopen(name, "r");
+    if (f == NULL) {
+        error_report("%s: %s: %m", __func__, name);
+        return 1;
+    }
+
+    for (r = 0; r < PCI_ROM_SLOT; r++) {
+        if (fscanf(f, "%" SCNi64 " %" SCNi64 " %" SCNi64 "\n",
+                   &start, &end, &flags) != 3) {
+            break;
+        }
+
+        rp = dev->regions + r;
+        rp->valid = 0;
+        rp->resource_fd = -1;
+        size = end - start + 1;
+        flags &= IORESOURCE_IO | IORESOURCE_MEM | IORESOURCE_PREFETCH
+                 | IORESOURCE_MEM_64;
+        if (size == 0 || (flags & ~IORESOURCE_PREFETCH) == 0) {
+            continue;
+        }
+        if (flags & IORESOURCE_MEM) {
+            flags &= ~IORESOURCE_IO;
+        } else {
+            flags &= ~IORESOURCE_PREFETCH;
+        }
+        snprintf(name, sizeof(name), "%sresource%d", dir, r);
+        fd = open(name, O_RDWR);
+        if (fd == -1) {
+            continue;
+        }
+        rp->resource_fd = fd;
+
+        rp->type = flags;
+        rp->valid = 1;
+        rp->base_addr = start;
+        rp->size = size;
+        pci_dev->v_addrs[r].region = rp;
+        DEBUG("region %d size %" PRIu64 " start 0x%" PRIx64
+              " type %d resource_fd %d\n",
+              r, rp->size, start, rp->type, rp->resource_fd);
+    }
+
+    fclose(f);
+
+    /* read and fill vendor ID */
+    v = get_real_vendor_id(dir, &id);
+    if (v) {
+        return 1;
+    }
+    pci_dev->dev.config[0] = id & 0xff;
+    pci_dev->dev.config[1] = (id & 0xff00) >> 8;
+
+    /* read and fill device ID */
+    v = get_real_device_id(dir, &id);
+    if (v) {
+        return 1;
+    }
+    pci_dev->dev.config[2] = id & 0xff;
+    pci_dev->dev.config[3] = (id & 0xff00) >> 8;
+
+    pci_word_test_and_clear_mask(pci_dev->emulate_config_write + PCI_COMMAND,
+                                 PCI_COMMAND_MASTER | PCI_COMMAND_INTX_DISABLE);
+
+    dev->region_number = r;
+    return 0;
+}
+
+static void free_msi_virqs(AssignedDevice *dev)
+{
+    int i;
+
+    for (i = 0; i < dev->msi_virq_nr; i++) {
+        if (dev->msi_virq[i] >= 0) {
+            kvm_irqchip_release_virq(kvm_state, dev->msi_virq[i]);
+            dev->msi_virq[i] = -1;
+        }
+    }
+    g_free(dev->msi_virq);
+    dev->msi_virq = NULL;
+    dev->msi_virq_nr = 0;
+}
+
+static void free_assigned_device(AssignedDevice *dev)
+{
+    int i;
+
+    if (dev->cap.available & ASSIGNED_DEVICE_CAP_MSIX) {
+        assigned_dev_unregister_msix_mmio(dev);
+    }
+    for (i = 0; i < dev->real_device.region_number; i++) {
+        PCIRegion *pci_region = &dev->real_device.regions[i];
+        AssignedDevRegion *region = &dev->v_addrs[i];
+
+        if (!pci_region->valid) {
+            continue;
+        }
+        if (pci_region->type & IORESOURCE_IO) {
+            if (region->u.r_baseport) {
+                memory_region_del_subregion(&region->container,
+                                            &region->real_iomem);
+                memory_region_destroy(&region->real_iomem);
+                memory_region_destroy(&region->container);
+            }
+        } else if (pci_region->type & IORESOURCE_MEM) {
+            if (region->u.r_virtbase) {
+                memory_region_del_subregion(&region->container,
+                                            &region->real_iomem);
+
+                /* Remove MSI-X table subregion */
+                if (pci_region->base_addr <= dev->msix_table_addr &&
+                    pci_region->base_addr + pci_region->size >
+                    dev->msix_table_addr) {
+                    memory_region_del_subregion(&region->container,
+                                                &dev->mmio);
+                }
+
+                memory_region_destroy(&region->real_iomem);
+                memory_region_destroy(&region->container);
+                if (munmap(region->u.r_virtbase,
+                           (pci_region->size + 0xFFF) & 0xFFFFF000)) {
+                    error_report("Failed to unmap assigned device region: %s",
+                                 strerror(errno));
+                }
+            }
+        }
+        if (pci_region->resource_fd >= 0) {
+            close(pci_region->resource_fd);
+        }
+    }
+
+    if (dev->real_device.config_fd >= 0) {
+        close(dev->real_device.config_fd);
+    }
+
+    free_msi_virqs(dev);
+}
+
+static void assign_failed_examine(AssignedDevice *dev)
+{
+    char name[PATH_MAX], dir[PATH_MAX], driver[PATH_MAX] = {}, *ns;
+    uint16_t vendor_id, device_id;
+    int r;
+
+    snprintf(dir, sizeof(dir), "/sys/bus/pci/devices/%04x:%02x:%02x.%01x/",
+            dev->host.domain, dev->host.bus, dev->host.slot,
+            dev->host.function);
+
+    snprintf(name, sizeof(name), "%sdriver", dir);
+
+    r = readlink(name, driver, sizeof(driver));
+    if ((r <= 0) || r >= sizeof(driver)) {
+        goto fail;
+    }
+
+    ns = strrchr(driver, '/');
+    if (!ns) {
+        goto fail;
+    }
+
+    ns++;
+
+    if (get_real_vendor_id(dir, &vendor_id) ||
+        get_real_device_id(dir, &device_id)) {
+        goto fail;
+    }
+
+    error_report("*** The driver '%s' is occupying your device "
+                 "%04x:%02x:%02x.%x.",
+                 ns, dev->host.domain, dev->host.bus, dev->host.slot,
+                 dev->host.function);
+    error_report("***");
+    error_report("*** You can try the following commands to free it:");
+    error_report("***");
+    error_report("*** $ echo \"%04x %04x\" > /sys/bus/pci/drivers/pci-stub/"
+                 "new_id", vendor_id, device_id);
+    error_report("*** $ echo \"%04x:%02x:%02x.%x\" > /sys/bus/pci/drivers/"
+                 "%s/unbind",
+                 dev->host.domain, dev->host.bus, dev->host.slot,
+                 dev->host.function, ns);
+    error_report("*** $ echo \"%04x:%02x:%02x.%x\" > /sys/bus/pci/drivers/"
+                 "pci-stub/bind",
+                 dev->host.domain, dev->host.bus, dev->host.slot,
+                 dev->host.function);
+    error_report("*** $ echo \"%04x %04x\" > /sys/bus/pci/drivers/pci-stub"
+                 "/remove_id", vendor_id, device_id);
+    error_report("***");
+
+    return;
+
+fail:
+    error_report("Couldn't find out why.");
+}
+
+static int assign_device(AssignedDevice *dev)
+{
+    uint32_t flags = KVM_DEV_ASSIGN_ENABLE_IOMMU;
+    int r;
+
+    /* Only pass non-zero PCI segment to capable module */
+    if (!kvm_check_extension(kvm_state, KVM_CAP_PCI_SEGMENT) &&
+        dev->host.domain) {
+        error_report("Can't assign device inside non-zero PCI segment "
+                     "as this KVM module doesn't support it.");
+        return -ENODEV;
+    }
+
+    if (!kvm_check_extension(kvm_state, KVM_CAP_IOMMU)) {
+        error_report("No IOMMU found.  Unable to assign device \"%s\"",
+                     dev->dev.qdev.id);
+        return -ENODEV;
+    }
+
+    if (dev->features & ASSIGNED_DEVICE_SHARE_INTX_MASK &&
+        kvm_has_intx_set_mask()) {
+        flags |= KVM_DEV_ASSIGN_PCI_2_3;
+    }
+
+    r = kvm_device_pci_assign(kvm_state, &dev->host, flags, &dev->dev_id);
+    if (r < 0) {
+        error_report("Failed to assign device \"%s\" : %s",
+                     dev->dev.qdev.id, strerror(-r));
+
+        switch (r) {
+        case -EBUSY:
+            assign_failed_examine(dev);
+            break;
+        default:
+            break;
+        }
+    }
+    return r;
+}
+
+static bool check_irqchip_in_kernel(void)
+{
+    if (kvm_irqchip_in_kernel()) {
+        return true;
+    }
+    error_report("pci-assign: error: requires KVM with in-kernel irqchip "
+                 "enabled");
+    return false;
+}
+
+static int assign_intx(AssignedDevice *dev)
+{
+    AssignedIRQType new_type;
+    PCIINTxRoute intx_route;
+    bool intx_host_msi;
+    int r;
+
+    /* Interrupt PIN 0 means don't use INTx */
+    if (assigned_dev_pci_read_byte(&dev->dev, PCI_INTERRUPT_PIN) == 0) {
+        pci_device_set_intx_routing_notifier(&dev->dev, NULL);
+        return 0;
+    }
+
+    if (!check_irqchip_in_kernel()) {
+        return -ENOTSUP;
+    }
+
+    pci_device_set_intx_routing_notifier(&dev->dev,
+                                         assigned_dev_update_irq_routing);
+
+    intx_route = pci_device_route_intx_to_irq(&dev->dev, dev->intpin);
+    assert(intx_route.mode != PCI_INTX_INVERTED);
+
+    if (!pci_intx_route_changed(&dev->intx_route, &intx_route)) {
+        return 0;
+    }
+
+    switch (dev->assigned_irq_type) {
+    case ASSIGNED_IRQ_INTX_HOST_INTX:
+    case ASSIGNED_IRQ_INTX_HOST_MSI:
+        intx_host_msi = dev->assigned_irq_type == ASSIGNED_IRQ_INTX_HOST_MSI;
+        r = kvm_device_intx_deassign(kvm_state, dev->dev_id, intx_host_msi);
+        break;
+    case ASSIGNED_IRQ_MSI:
+        r = kvm_device_msi_deassign(kvm_state, dev->dev_id);
+        break;
+    case ASSIGNED_IRQ_MSIX:
+        r = kvm_device_msix_deassign(kvm_state, dev->dev_id);
+        break;
+    default:
+        r = 0;
+        break;
+    }
+    if (r) {
+        perror("assign_intx: deassignment of previous interrupt failed");
+    }
+    dev->assigned_irq_type = ASSIGNED_IRQ_NONE;
+
+    if (intx_route.mode == PCI_INTX_DISABLED) {
+        dev->intx_route = intx_route;
+        return 0;
+    }
+
+retry:
+    if (dev->features & ASSIGNED_DEVICE_PREFER_MSI_MASK &&
+        dev->cap.available & ASSIGNED_DEVICE_CAP_MSI) {
+        intx_host_msi = true;
+        new_type = ASSIGNED_IRQ_INTX_HOST_MSI;
+    } else {
+        intx_host_msi = false;
+        new_type = ASSIGNED_IRQ_INTX_HOST_INTX;
+    }
+
+    r = kvm_device_intx_assign(kvm_state, dev->dev_id, intx_host_msi,
+                               intx_route.irq);
+    if (r < 0) {
+        if (r == -EIO && !(dev->features & ASSIGNED_DEVICE_PREFER_MSI_MASK) &&
+            dev->cap.available & ASSIGNED_DEVICE_CAP_MSI) {
+            /* Retry with host-side MSI. There might be an IRQ conflict and
+             * either the kernel or the device doesn't support sharing. */
+            error_report("Host-side INTx sharing not supported, "
+                         "using MSI instead");
+            error_printf("Some devices do not work properly in this mode.\n");
+            dev->features |= ASSIGNED_DEVICE_PREFER_MSI_MASK;
+            goto retry;
+        }
+        error_report("Failed to assign irq for \"%s\": %s",
+                     dev->dev.qdev.id, strerror(-r));
+        error_report("Perhaps you are assigning a device "
+                     "that shares an IRQ with another device?");
+        return r;
+    }
+
+    dev->intx_route = intx_route;
+    dev->assigned_irq_type = new_type;
+    return r;
+}
+
+static void deassign_device(AssignedDevice *dev)
+{
+    int r;
+
+    r = kvm_device_pci_deassign(kvm_state, dev->dev_id);
+    assert(r == 0);
+}
+
+/* The pci config space got updated. Check if irq numbers have changed
+ * for our devices
+ */
+static void assigned_dev_update_irq_routing(PCIDevice *dev)
+{
+    AssignedDevice *assigned_dev = DO_UPCAST(AssignedDevice, dev, dev);
+    Error *err = NULL;
+    int r;
+
+    r = assign_intx(assigned_dev);
+    if (r < 0) {
+        qdev_unplug(&dev->qdev, &err);
+        assert(!err);
+    }
+}
+
+static void assigned_dev_update_msi(PCIDevice *pci_dev)
+{
+    AssignedDevice *assigned_dev = DO_UPCAST(AssignedDevice, dev, pci_dev);
+    uint8_t ctrl_byte = pci_get_byte(pci_dev->config + pci_dev->msi_cap +
+                                     PCI_MSI_FLAGS);
+    int r;
+
+    /* Some guests gratuitously disable MSI even if they're not using it,
+     * try to catch this by only deassigning irqs if the guest is using
+     * MSI or intends to start. */
+    if (assigned_dev->assigned_irq_type == ASSIGNED_IRQ_MSI ||
+        (ctrl_byte & PCI_MSI_FLAGS_ENABLE)) {
+        r = kvm_device_msi_deassign(kvm_state, assigned_dev->dev_id);
+        /* -ENXIO means no assigned irq */
+        if (r && r != -ENXIO) {
+            perror("assigned_dev_update_msi: deassign irq");
+        }
+
+        free_msi_virqs(assigned_dev);
+
+        assigned_dev->assigned_irq_type = ASSIGNED_IRQ_NONE;
+        pci_device_set_intx_routing_notifier(pci_dev, NULL);
+    }
+
+    if (ctrl_byte & PCI_MSI_FLAGS_ENABLE) {
+        MSIMessage msg = msi_get_message(pci_dev, 0);
+        int virq;
+
+        virq = kvm_irqchip_add_msi_route(kvm_state, msg);
+        if (virq < 0) {
+            perror("assigned_dev_update_msi: kvm_irqchip_add_msi_route");
+            return;
+        }
+
+        assigned_dev->msi_virq = g_malloc(sizeof(*assigned_dev->msi_virq));
+        assigned_dev->msi_virq_nr = 1;
+        assigned_dev->msi_virq[0] = virq;
+        if (kvm_device_msi_assign(kvm_state, assigned_dev->dev_id, virq) < 0) {
+            perror("assigned_dev_update_msi: kvm_device_msi_assign");
+        }
+
+        assigned_dev->intx_route.mode = PCI_INTX_DISABLED;
+        assigned_dev->intx_route.irq = -1;
+        assigned_dev->assigned_irq_type = ASSIGNED_IRQ_MSI;
+    } else {
+        assign_intx(assigned_dev);
+    }
+}
+
+static bool assigned_dev_msix_masked(MSIXTableEntry *entry)
+{
+    return (entry->ctrl & cpu_to_le32(0x1)) != 0;
+}
+
+/*
+ * When MSI-X is first enabled the vector table typically has all the
+ * vectors masked, so we can't use that as the obvious test to figure out
+ * how many vectors to initially enable.  Instead we look at the data field
+ * because this is what worked for pci-assign for a long time.  This makes
+ * sure the physical MSI-X state tracks the guest's view, which is important
+ * for some VF/PF and PF/fw communication channels.
+ */
+static bool assigned_dev_msix_skipped(MSIXTableEntry *entry)
+{
+    return !entry->data;
+}
+
+static int assigned_dev_update_msix_mmio(PCIDevice *pci_dev)
+{
+    AssignedDevice *adev = DO_UPCAST(AssignedDevice, dev, pci_dev);
+    uint16_t entries_nr = 0;
+    int i, r = 0;
+    MSIXTableEntry *entry = adev->msix_table;
+    MSIMessage msg;
+
+    /* Get the usable entry number for allocating */
+    for (i = 0; i < adev->msix_max; i++, entry++) {
+        if (assigned_dev_msix_skipped(entry)) {
+            continue;
+        }
+        entries_nr++;
+    }
+
+    DEBUG("MSI-X entries: %d\n", entries_nr);
+
+    /* It's valid to enable MSI-X with all entries masked */
+    if (!entries_nr) {
+        return 0;
+    }
+
+    r = kvm_device_msix_init_vectors(kvm_state, adev->dev_id, entries_nr);
+    if (r != 0) {
+        error_report("fail to set MSI-X entry number for MSIX! %s",
+                     strerror(-r));
+        return r;
+    }
+
+    free_msi_virqs(adev);
+
+    adev->msi_virq_nr = adev->msix_max;
+    adev->msi_virq = g_malloc(adev->msix_max * sizeof(*adev->msi_virq));
+
+    entry = adev->msix_table;
+    for (i = 0; i < adev->msix_max; i++, entry++) {
+        adev->msi_virq[i] = -1;
+
+        if (assigned_dev_msix_skipped(entry)) {
+            continue;
+        }
+
+        msg.address = entry->addr_lo | ((uint64_t)entry->addr_hi << 32);
+        msg.data = entry->data;
+        r = kvm_irqchip_add_msi_route(kvm_state, msg);
+        if (r < 0) {
+            return r;
+        }
+        adev->msi_virq[i] = r;
+
+        DEBUG("MSI-X vector %d, gsi %d, addr %08x_%08x, data %08x\n", i,
+              r, entry->addr_hi, entry->addr_lo, entry->data);
+
+        r = kvm_device_msix_set_vector(kvm_state, adev->dev_id, i,
+                                       adev->msi_virq[i]);
+        if (r) {
+            error_report("fail to set MSI-X entry! %s", strerror(-r));
+            break;
+        }
+    }
+
+    return r;
+}
+
+static void assigned_dev_update_msix(PCIDevice *pci_dev)
+{
+    AssignedDevice *assigned_dev = DO_UPCAST(AssignedDevice, dev, pci_dev);
+    uint16_t ctrl_word = pci_get_word(pci_dev->config + pci_dev->msix_cap +
+                                      PCI_MSIX_FLAGS);
+    int r;
+
+    /* Some guests gratuitously disable MSIX even if they're not using it,
+     * try to catch this by only deassigning irqs if the guest is using
+     * MSIX or intends to start. */
+    if ((assigned_dev->assigned_irq_type == ASSIGNED_IRQ_MSIX) ||
+        (ctrl_word & PCI_MSIX_FLAGS_ENABLE)) {
+        r = kvm_device_msix_deassign(kvm_state, assigned_dev->dev_id);
+        /* -ENXIO means no assigned irq */
+        if (r && r != -ENXIO) {
+            perror("assigned_dev_update_msix: deassign irq");
+        }
+
+        free_msi_virqs(assigned_dev);
+
+        assigned_dev->assigned_irq_type = ASSIGNED_IRQ_NONE;
+        pci_device_set_intx_routing_notifier(pci_dev, NULL);
+    }
+
+    if (ctrl_word & PCI_MSIX_FLAGS_ENABLE) {
+        if (assigned_dev_update_msix_mmio(pci_dev) < 0) {
+            perror("assigned_dev_update_msix_mmio");
+            return;
+        }
+
+        if (assigned_dev->msi_virq_nr > 0) {
+            if (kvm_device_msix_assign(kvm_state, assigned_dev->dev_id) < 0) {
+                perror("assigned_dev_enable_msix: assign irq");
+                return;
+            }
+        }
+        assigned_dev->intx_route.mode = PCI_INTX_DISABLED;
+        assigned_dev->intx_route.irq = -1;
+        assigned_dev->assigned_irq_type = ASSIGNED_IRQ_MSIX;
+    } else {
+        assign_intx(assigned_dev);
+    }
+}
+
+static uint32_t assigned_dev_pci_read_config(PCIDevice *pci_dev,
+                                             uint32_t address, int len)
+{
+    AssignedDevice *assigned_dev = DO_UPCAST(AssignedDevice, dev, pci_dev);
+    uint32_t virt_val = pci_default_read_config(pci_dev, address, len);
+    uint32_t real_val, emulate_mask, full_emulation_mask;
+
+    emulate_mask = 0;
+    memcpy(&emulate_mask, assigned_dev->emulate_config_read + address, len);
+    emulate_mask = le32_to_cpu(emulate_mask);
+
+    full_emulation_mask = 0xffffffff >> (32 - len * 8);
+
+    if (emulate_mask != full_emulation_mask) {
+        real_val = assigned_dev_pci_read(pci_dev, address, len);
+        return (virt_val & emulate_mask) | (real_val & ~emulate_mask);
+    } else {
+        return virt_val;
+    }
+}
+
+static void assigned_dev_pci_write_config(PCIDevice *pci_dev, uint32_t address,
+                                          uint32_t val, int len)
+{
+    AssignedDevice *assigned_dev = DO_UPCAST(AssignedDevice, dev, pci_dev);
+    uint16_t old_cmd = pci_get_word(pci_dev->config + PCI_COMMAND);
+    uint32_t emulate_mask, full_emulation_mask;
+    int ret;
+
+    pci_default_write_config(pci_dev, address, val, len);
+
+    if (kvm_has_intx_set_mask() &&
+        range_covers_byte(address, len, PCI_COMMAND + 1)) {
+        bool intx_masked = (pci_get_word(pci_dev->config + PCI_COMMAND) &
+                            PCI_COMMAND_INTX_DISABLE);
+
+        if (intx_masked != !!(old_cmd & PCI_COMMAND_INTX_DISABLE)) {
+            ret = kvm_device_intx_set_mask(kvm_state, assigned_dev->dev_id,
+                                           intx_masked);
+            if (ret) {
+                perror("assigned_dev_pci_write_config: set intx mask");
+            }
+        }
+    }
+    if (assigned_dev->cap.available & ASSIGNED_DEVICE_CAP_MSI) {
+        if (range_covers_byte(address, len,
+                              pci_dev->msi_cap + PCI_MSI_FLAGS)) {
+            assigned_dev_update_msi(pci_dev);
+        }
+    }
+    if (assigned_dev->cap.available & ASSIGNED_DEVICE_CAP_MSIX) {
+        if (range_covers_byte(address, len,
+                              pci_dev->msix_cap + PCI_MSIX_FLAGS + 1)) {
+            assigned_dev_update_msix(pci_dev);
+        }
+    }
+
+    emulate_mask = 0;
+    memcpy(&emulate_mask, assigned_dev->emulate_config_write + address, len);
+    emulate_mask = le32_to_cpu(emulate_mask);
+
+    full_emulation_mask = 0xffffffff >> (32 - len * 8);
+
+    if (emulate_mask != full_emulation_mask) {
+        if (emulate_mask) {
+            val &= ~emulate_mask;
+            val |= assigned_dev_pci_read(pci_dev, address, len) & emulate_mask;
+        }
+        assigned_dev_pci_write(pci_dev, address, val, len);
+    }
+}
+
+static void assigned_dev_setup_cap_read(AssignedDevice *dev, uint32_t offset,
+                                        uint32_t len)
+{
+    assigned_dev_direct_config_read(dev, offset, len);
+    assigned_dev_emulate_config_read(dev, offset + PCI_CAP_LIST_NEXT, 1);
+}
+
+static int assigned_device_pci_cap_init(PCIDevice *pci_dev)
+{
+    AssignedDevice *dev = DO_UPCAST(AssignedDevice, dev, pci_dev);
+    PCIRegion *pci_region = dev->real_device.regions;
+    int ret, pos;
+
+    /* Clear initial capabilities pointer and status copied from hw */
+    pci_set_byte(pci_dev->config + PCI_CAPABILITY_LIST, 0);
+    pci_set_word(pci_dev->config + PCI_STATUS,
+                 pci_get_word(pci_dev->config + PCI_STATUS) &
+                 ~PCI_STATUS_CAP_LIST);
+
+    /* Expose MSI capability
+     * MSI capability is the 1st capability in capability config */
+    pos = pci_find_cap_offset(pci_dev, PCI_CAP_ID_MSI, 0);
+    if (pos != 0 && kvm_check_extension(kvm_state, KVM_CAP_ASSIGN_DEV_IRQ)) {
+        if (!check_irqchip_in_kernel()) {
+            return -ENOTSUP;
+        }
+        dev->cap.available |= ASSIGNED_DEVICE_CAP_MSI;
+        /* Only 32-bit/no-mask currently supported */
+        ret = pci_add_capability(pci_dev, PCI_CAP_ID_MSI, pos, 10);
+        if (ret < 0) {
+            return ret;
+        }
+        pci_dev->msi_cap = pos;
+
+        pci_set_word(pci_dev->config + pos + PCI_MSI_FLAGS,
+                     pci_get_word(pci_dev->config + pos + PCI_MSI_FLAGS) &
+                     PCI_MSI_FLAGS_QMASK);
+        pci_set_long(pci_dev->config + pos + PCI_MSI_ADDRESS_LO, 0);
+        pci_set_word(pci_dev->config + pos + PCI_MSI_DATA_32, 0);
+
+        /* Set writable fields */
+        pci_set_word(pci_dev->wmask + pos + PCI_MSI_FLAGS,
+                     PCI_MSI_FLAGS_QSIZE | PCI_MSI_FLAGS_ENABLE);
+        pci_set_long(pci_dev->wmask + pos + PCI_MSI_ADDRESS_LO, 0xfffffffc);
+        pci_set_word(pci_dev->wmask + pos + PCI_MSI_DATA_32, 0xffff);
+    }
+    /* Expose MSI-X capability */
+    pos = pci_find_cap_offset(pci_dev, PCI_CAP_ID_MSIX, 0);
+    if (pos != 0 && kvm_device_msix_supported(kvm_state)) {
+        int bar_nr;
+        uint32_t msix_table_entry;
+
+        if (!check_irqchip_in_kernel()) {
+            return -ENOTSUP;
+        }
+        dev->cap.available |= ASSIGNED_DEVICE_CAP_MSIX;
+        ret = pci_add_capability(pci_dev, PCI_CAP_ID_MSIX, pos, 12);
+        if (ret < 0) {
+            return ret;
+        }
+        pci_dev->msix_cap = pos;
+
+        pci_set_word(pci_dev->config + pos + PCI_MSIX_FLAGS,
+                     pci_get_word(pci_dev->config + pos + PCI_MSIX_FLAGS) &
+                     PCI_MSIX_FLAGS_QSIZE);
+
+        /* Only enable and function mask bits are writable */
+        pci_set_word(pci_dev->wmask + pos + PCI_MSIX_FLAGS,
+                     PCI_MSIX_FLAGS_ENABLE | PCI_MSIX_FLAGS_MASKALL);
+
+        msix_table_entry = pci_get_long(pci_dev->config + pos + PCI_MSIX_TABLE);
+        bar_nr = msix_table_entry & PCI_MSIX_FLAGS_BIRMASK;
+        msix_table_entry &= ~PCI_MSIX_FLAGS_BIRMASK;
+        dev->msix_table_addr = pci_region[bar_nr].base_addr + msix_table_entry;
+        dev->msix_max = pci_get_word(pci_dev->config + pos + PCI_MSIX_FLAGS);
+        dev->msix_max &= PCI_MSIX_FLAGS_QSIZE;
+        dev->msix_max += 1;
+    }
+
+    /* Minimal PM support, nothing writable, device appears to NAK changes */
+    pos = pci_find_cap_offset(pci_dev, PCI_CAP_ID_PM, 0);
+    if (pos) {
+        uint16_t pmc;
+
+        ret = pci_add_capability(pci_dev, PCI_CAP_ID_PM, pos, PCI_PM_SIZEOF);
+        if (ret < 0) {
+            return ret;
+        }
+
+        assigned_dev_setup_cap_read(dev, pos, PCI_PM_SIZEOF);
+
+        pmc = pci_get_word(pci_dev->config + pos + PCI_CAP_FLAGS);
+        pmc &= (PCI_PM_CAP_VER_MASK | PCI_PM_CAP_DSI);
+        pci_set_word(pci_dev->config + pos + PCI_CAP_FLAGS, pmc);
+
+        /* assign_device will bring the device up to D0, so we don't need
+         * to worry about doing that ourselves here. */
+        pci_set_word(pci_dev->config + pos + PCI_PM_CTRL,
+                     PCI_PM_CTRL_NO_SOFT_RESET);
+
+        pci_set_byte(pci_dev->config + pos + PCI_PM_PPB_EXTENSIONS, 0);
+        pci_set_byte(pci_dev->config + pos + PCI_PM_DATA_REGISTER, 0);
+    }
+
+    pos = pci_find_cap_offset(pci_dev, PCI_CAP_ID_EXP, 0);
+    if (pos) {
+        uint8_t version, size = 0;
+        uint16_t type, devctl, lnksta;
+        uint32_t devcap, lnkcap;
+
+        version = pci_get_byte(pci_dev->config + pos + PCI_EXP_FLAGS);
+        version &= PCI_EXP_FLAGS_VERS;
+        if (version == 1) {
+            size = 0x14;
+        } else if (version == 2) {
+            /*
+             * Check for non-std size, accept reduced size to 0x34,
+             * which is what bcm5761 implemented, violating the
+             * PCIe v3.0 spec that regs should exist and be read as 0,
+             * not optionally provided and shorten the struct size.
+             */
+            size = MIN(0x3c, PCI_CONFIG_SPACE_SIZE - pos);
+            if (size < 0x34) {
+                error_report("%s: Invalid size PCIe cap-id 0x%x",
+                             __func__, PCI_CAP_ID_EXP);
+                return -EINVAL;
+            } else if (size != 0x3c) {
+                error_report("WARNING, %s: PCIe cap-id 0x%x has "
+                             "non-standard size 0x%x; std size should be 0x3c",
+                             __func__, PCI_CAP_ID_EXP, size);
+            }
+        } else if (version == 0) {
+            uint16_t vid, did;
+            vid = pci_get_word(pci_dev->config + PCI_VENDOR_ID);
+            did = pci_get_word(pci_dev->config + PCI_DEVICE_ID);
+            if (vid == PCI_VENDOR_ID_INTEL && did == 0x10ed) {
+                /*
+                 * quirk for Intel 82599 VF with invalid PCIe capability
+                 * version, should really be version 2 (same as PF)
+                 */
+                size = 0x3c;
+            }
+        }
+
+        if (size == 0) {
+            error_report("%s: Unsupported PCI express capability version %d",
+                         __func__, version);
+            return -EINVAL;
+        }
+
+        ret = pci_add_capability(pci_dev, PCI_CAP_ID_EXP, pos, size);
+        if (ret < 0) {
+            return ret;
+        }
+
+        assigned_dev_setup_cap_read(dev, pos, size);
+
+        type = pci_get_word(pci_dev->config + pos + PCI_EXP_FLAGS);
+        type = (type & PCI_EXP_FLAGS_TYPE) >> 4;
+        if (type != PCI_EXP_TYPE_ENDPOINT &&
+            type != PCI_EXP_TYPE_LEG_END && type != PCI_EXP_TYPE_RC_END) {
+            error_report("Device assignment only supports endpoint assignment,"
+                         " device type %d", type);
+            return -EINVAL;
+        }
+
+        /* capabilities, pass existing read-only copy
+         * PCI_EXP_FLAGS_IRQ: updated by hardware, should be direct read */
+
+        /* device capabilities: hide FLR */
+        devcap = pci_get_long(pci_dev->config + pos + PCI_EXP_DEVCAP);
+        devcap &= ~PCI_EXP_DEVCAP_FLR;
+        pci_set_long(pci_dev->config + pos + PCI_EXP_DEVCAP, devcap);
+
+        /* device control: clear all error reporting enable bits, leaving
+         *                 only a few host values.  Note, these are
+         *                 all writable, but not passed to hw.
+         */
+        devctl = pci_get_word(pci_dev->config + pos + PCI_EXP_DEVCTL);
+        devctl = (devctl & (PCI_EXP_DEVCTL_READRQ | PCI_EXP_DEVCTL_PAYLOAD)) |
+                  PCI_EXP_DEVCTL_RELAX_EN | PCI_EXP_DEVCTL_NOSNOOP_EN;
+        pci_set_word(pci_dev->config + pos + PCI_EXP_DEVCTL, devctl);
+        devctl = PCI_EXP_DEVCTL_BCR_FLR | PCI_EXP_DEVCTL_AUX_PME;
+        pci_set_word(pci_dev->wmask + pos + PCI_EXP_DEVCTL, ~devctl);
+
+        /* Clear device status */
+        pci_set_word(pci_dev->config + pos + PCI_EXP_DEVSTA, 0);
+
+        /* Link capabilities, expose links and latencues, clear reporting */
+        lnkcap = pci_get_long(pci_dev->config + pos + PCI_EXP_LNKCAP);
+        lnkcap &= (PCI_EXP_LNKCAP_SLS | PCI_EXP_LNKCAP_MLW |
+                   PCI_EXP_LNKCAP_ASPMS | PCI_EXP_LNKCAP_L0SEL |
+                   PCI_EXP_LNKCAP_L1EL);
+        pci_set_long(pci_dev->config + pos + PCI_EXP_LNKCAP, lnkcap);
+
+        /* Link control, pass existing read-only copy.  Should be writable? */
+
+        /* Link status, only expose current speed and width */
+        lnksta = pci_get_word(pci_dev->config + pos + PCI_EXP_LNKSTA);
+        lnksta &= (PCI_EXP_LNKSTA_CLS | PCI_EXP_LNKSTA_NLW);
+        pci_set_word(pci_dev->config + pos + PCI_EXP_LNKSTA, lnksta);
+
+        if (version >= 2) {
+            /* Slot capabilities, control, status - not needed for endpoints */
+            pci_set_long(pci_dev->config + pos + PCI_EXP_SLTCAP, 0);
+            pci_set_word(pci_dev->config + pos + PCI_EXP_SLTCTL, 0);
+            pci_set_word(pci_dev->config + pos + PCI_EXP_SLTSTA, 0);
+
+            /* Root control, capabilities, status - not needed for endpoints */
+            pci_set_word(pci_dev->config + pos + PCI_EXP_RTCTL, 0);
+            pci_set_word(pci_dev->config + pos + PCI_EXP_RTCAP, 0);
+            pci_set_long(pci_dev->config + pos + PCI_EXP_RTSTA, 0);
+
+            /* Device capabilities/control 2, pass existing read-only copy */
+            /* Link control 2, pass existing read-only copy */
+        }
+    }
+
+    pos = pci_find_cap_offset(pci_dev, PCI_CAP_ID_PCIX, 0);
+    if (pos) {
+        uint16_t cmd;
+        uint32_t status;
+
+        /* Only expose the minimum, 8 byte capability */
+        ret = pci_add_capability(pci_dev, PCI_CAP_ID_PCIX, pos, 8);
+        if (ret < 0) {
+            return ret;
+        }
+
+        assigned_dev_setup_cap_read(dev, pos, 8);
+
+        /* Command register, clear upper bits, including extended modes */
+        cmd = pci_get_word(pci_dev->config + pos + PCI_X_CMD);
+        cmd &= (PCI_X_CMD_DPERR_E | PCI_X_CMD_ERO | PCI_X_CMD_MAX_READ |
+                PCI_X_CMD_MAX_SPLIT);
+        pci_set_word(pci_dev->config + pos + PCI_X_CMD, cmd);
+
+        /* Status register, update with emulated PCI bus location, clear
+         * error bits, leave the rest. */
+        status = pci_get_long(pci_dev->config + pos + PCI_X_STATUS);
+        status &= ~(PCI_X_STATUS_BUS | PCI_X_STATUS_DEVFN);
+        status |= (pci_bus_num(pci_dev->bus) << 8) | pci_dev->devfn;
+        status &= ~(PCI_X_STATUS_SPL_DISC | PCI_X_STATUS_UNX_SPL |
+                    PCI_X_STATUS_SPL_ERR);
+        pci_set_long(pci_dev->config + pos + PCI_X_STATUS, status);
+    }
+
+    pos = pci_find_cap_offset(pci_dev, PCI_CAP_ID_VPD, 0);
+    if (pos) {
+        /* Direct R/W passthrough */
+        ret = pci_add_capability(pci_dev, PCI_CAP_ID_VPD, pos, 8);
+        if (ret < 0) {
+            return ret;
+        }
+
+        assigned_dev_setup_cap_read(dev, pos, 8);
+
+        /* direct write for cap content */
+        assigned_dev_direct_config_write(dev, pos + 2, 6);
+    }
+
+    /* Devices can have multiple vendor capabilities, get them all */
+    for (pos = 0; (pos = pci_find_cap_offset(pci_dev, PCI_CAP_ID_VNDR, pos));
+        pos += PCI_CAP_LIST_NEXT) {
+        uint8_t len = pci_get_byte(pci_dev->config + pos + PCI_CAP_FLAGS);
+        /* Direct R/W passthrough */
+        ret = pci_add_capability(pci_dev, PCI_CAP_ID_VNDR, pos, len);
+        if (ret < 0) {
+            return ret;
+        }
+
+        assigned_dev_setup_cap_read(dev, pos, len);
+
+        /* direct write for cap content */
+        assigned_dev_direct_config_write(dev, pos + 2, len - 2);
+    }
+
+    /* If real and virtual capability list status bits differ, virtualize the
+     * access. */
+    if ((pci_get_word(pci_dev->config + PCI_STATUS) & PCI_STATUS_CAP_LIST) !=
+        (assigned_dev_pci_read_byte(pci_dev, PCI_STATUS) &
+         PCI_STATUS_CAP_LIST)) {
+        dev->emulate_config_read[PCI_STATUS] |= PCI_STATUS_CAP_LIST;
+    }
+
+    return 0;
+}
+
+static uint64_t
+assigned_dev_msix_mmio_read(void *opaque, hwaddr addr,
+                            unsigned size)
+{
+    AssignedDevice *adev = opaque;
+    uint64_t val;
+
+    memcpy(&val, (void *)((uint8_t *)adev->msix_table + addr), size);
+
+    return val;
+}
+
+static void assigned_dev_msix_mmio_write(void *opaque, hwaddr addr,
+                                         uint64_t val, unsigned size)
+{
+    AssignedDevice *adev = opaque;
+    PCIDevice *pdev = &adev->dev;
+    uint16_t ctrl;
+    MSIXTableEntry orig;
+    int i = addr >> 4;
+
+    if (i >= adev->msix_max) {
+        return; /* Drop write */
+    }
+
+    ctrl = pci_get_word(pdev->config + pdev->msix_cap + PCI_MSIX_FLAGS);
+
+    DEBUG("write to MSI-X table offset 0x%lx, val 0x%lx\n", addr, val);
+
+    if (ctrl & PCI_MSIX_FLAGS_ENABLE) {
+        orig = adev->msix_table[i];
+    }
+
+    memcpy((uint8_t *)adev->msix_table + addr, &val, size);
+
+    if (ctrl & PCI_MSIX_FLAGS_ENABLE) {
+        MSIXTableEntry *entry = &adev->msix_table[i];
+
+        if (!assigned_dev_msix_masked(&orig) &&
+            assigned_dev_msix_masked(entry)) {
+            /*
+             * Vector masked, disable it
+             *
+             * XXX It's not clear if we can or should actually attempt
+             * to mask or disable the interrupt.  KVM doesn't have
+             * support for pending bits and kvm_assign_set_msix_entry
+             * doesn't modify the device hardware mask.  Interrupts
+             * while masked are simply not injected to the guest, so
+             * are lost.  Can we get away with always injecting an
+             * interrupt on unmask?
+             */
+        } else if (assigned_dev_msix_masked(&orig) &&
+                   !assigned_dev_msix_masked(entry)) {
+            /* Vector unmasked */
+            if (i >= adev->msi_virq_nr || adev->msi_virq[i] < 0) {
+                /* Previously unassigned vector, start from scratch */
+                assigned_dev_update_msix(pdev);
+                return;
+            } else {
+                /* Update an existing, previously masked vector */
+                MSIMessage msg;
+                int ret;
+
+                msg.address = entry->addr_lo |
+                    ((uint64_t)entry->addr_hi << 32);
+                msg.data = entry->data;
+
+                ret = kvm_irqchip_update_msi_route(kvm_state,
+                                                   adev->msi_virq[i], msg);
+                if (ret) {
+                    error_report("Error updating irq routing entry (%d)", ret);
+                }
+            }
+        }
+    }
+}
+
+static const MemoryRegionOps assigned_dev_msix_mmio_ops = {
+    .read = assigned_dev_msix_mmio_read,
+    .write = assigned_dev_msix_mmio_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 8,
+    },
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 8,
+    },
+};
+
+static void assigned_dev_msix_reset(AssignedDevice *dev)
+{
+    MSIXTableEntry *entry;
+    int i;
+
+    if (!dev->msix_table) {
+        return;
+    }
+
+    memset(dev->msix_table, 0, MSIX_PAGE_SIZE);
+
+    for (i = 0, entry = dev->msix_table; i < dev->msix_max; i++, entry++) {
+        entry->ctrl = cpu_to_le32(0x1); /* Masked */
+    }
+}
+
+static int assigned_dev_register_msix_mmio(AssignedDevice *dev)
+{
+    dev->msix_table = mmap(NULL, MSIX_PAGE_SIZE, PROT_READ|PROT_WRITE,
+                           MAP_ANONYMOUS|MAP_PRIVATE, 0, 0);
+    if (dev->msix_table == MAP_FAILED) {
+        error_report("fail allocate msix_table! %s", strerror(errno));
+        return -EFAULT;
+    }
+
+    assigned_dev_msix_reset(dev);
+
+    memory_region_init_io(&dev->mmio, &assigned_dev_msix_mmio_ops, dev,
+                          "assigned-dev-msix", MSIX_PAGE_SIZE);
+    return 0;
+}
+
+static void assigned_dev_unregister_msix_mmio(AssignedDevice *dev)
+{
+    if (!dev->msix_table) {
+        return;
+    }
+
+    memory_region_destroy(&dev->mmio);
+
+    if (munmap(dev->msix_table, MSIX_PAGE_SIZE) == -1) {
+        error_report("error unmapping msix_table! %s", strerror(errno));
+    }
+    dev->msix_table = NULL;
+}
+
+static const VMStateDescription vmstate_assigned_device = {
+    .name = "pci-assign",
+    .unmigratable = 1,
+};
+
+static void reset_assigned_device(DeviceState *dev)
+{
+    PCIDevice *pci_dev = DO_UPCAST(PCIDevice, qdev, dev);
+    AssignedDevice *adev = DO_UPCAST(AssignedDevice, dev, pci_dev);
+    char reset_file[64];
+    const char reset[] = "1";
+    int fd, ret;
+
+    /*
+     * If a guest is reset without being shutdown, MSI/MSI-X can still
+     * be running.  We want to return the device to a known state on
+     * reset, so disable those here.  We especially do not want MSI-X
+     * enabled since it lives in MMIO space, which is about to get
+     * disabled.
+     */
+    if (adev->assigned_irq_type == ASSIGNED_IRQ_MSIX) {
+        uint16_t ctrl = pci_get_word(pci_dev->config +
+                                     pci_dev->msix_cap + PCI_MSIX_FLAGS);
+
+        pci_set_word(pci_dev->config + pci_dev->msix_cap + PCI_MSIX_FLAGS,
+                     ctrl & ~PCI_MSIX_FLAGS_ENABLE);
+        assigned_dev_update_msix(pci_dev);
+    } else if (adev->assigned_irq_type == ASSIGNED_IRQ_MSI) {
+        uint8_t ctrl = pci_get_byte(pci_dev->config +
+                                    pci_dev->msi_cap + PCI_MSI_FLAGS);
+
+        pci_set_byte(pci_dev->config + pci_dev->msi_cap + PCI_MSI_FLAGS,
+                     ctrl & ~PCI_MSI_FLAGS_ENABLE);
+        assigned_dev_update_msi(pci_dev);
+    }
+
+    snprintf(reset_file, sizeof(reset_file),
+             "/sys/bus/pci/devices/%04x:%02x:%02x.%01x/reset",
+             adev->host.domain, adev->host.bus, adev->host.slot,
+             adev->host.function);
+
+    /*
+     * Issue a device reset via pci-sysfs.  Note that we use write(2) here
+     * and ignore the return value because some kernels have a bug that
+     * returns 0 rather than bytes written on success, sending us into an
+     * infinite retry loop using other write mechanisms.
+     */
+    fd = open(reset_file, O_WRONLY);
+    if (fd != -1) {
+        ret = write(fd, reset, strlen(reset));
+        (void)ret;
+        close(fd);
+    }
+
+    /*
+     * When a 0 is written to the bus master register, the device is logically
+     * disconnected from the PCI bus. This avoids further DMA transfers.
+     */
+    assigned_dev_pci_write_config(pci_dev, PCI_COMMAND, 0, 1);
+}
+
+static int assigned_initfn(struct PCIDevice *pci_dev)
+{
+    AssignedDevice *dev = DO_UPCAST(AssignedDevice, dev, pci_dev);
+    uint8_t e_intx;
+    int r;
+
+    if (!kvm_enabled()) {
+        error_report("pci-assign: error: requires KVM support");
+        return -1;
+    }
+
+    if (!dev->host.domain && !dev->host.bus && !dev->host.slot &&
+        !dev->host.function) {
+        error_report("pci-assign: error: no host device specified");
+        return -1;
+    }
+
+    /*
+     * Set up basic config space access control. Will be further refined during
+     * device initialization.
+     */
+    assigned_dev_emulate_config_read(dev, 0, PCI_CONFIG_SPACE_SIZE);
+    assigned_dev_direct_config_read(dev, PCI_STATUS, 2);
+    assigned_dev_direct_config_read(dev, PCI_REVISION_ID, 1);
+    assigned_dev_direct_config_read(dev, PCI_CLASS_PROG, 3);
+    assigned_dev_direct_config_read(dev, PCI_CACHE_LINE_SIZE, 1);
+    assigned_dev_direct_config_read(dev, PCI_LATENCY_TIMER, 1);
+    assigned_dev_direct_config_read(dev, PCI_BIST, 1);
+    assigned_dev_direct_config_read(dev, PCI_CARDBUS_CIS, 4);
+    assigned_dev_direct_config_read(dev, PCI_SUBSYSTEM_VENDOR_ID, 2);
+    assigned_dev_direct_config_read(dev, PCI_SUBSYSTEM_ID, 2);
+    assigned_dev_direct_config_read(dev, PCI_CAPABILITY_LIST + 1, 7);
+    assigned_dev_direct_config_read(dev, PCI_MIN_GNT, 1);
+    assigned_dev_direct_config_read(dev, PCI_MAX_LAT, 1);
+    memcpy(dev->emulate_config_write, dev->emulate_config_read,
+           sizeof(dev->emulate_config_read));
+
+    if (get_real_device(dev, dev->host.domain, dev->host.bus,
+                        dev->host.slot, dev->host.function)) {
+        error_report("pci-assign: Error: Couldn't get real device (%s)!",
+                     dev->dev.qdev.id);
+        goto out;
+    }
+
+    if (assigned_device_pci_cap_init(pci_dev) < 0) {
+        goto out;
+    }
+
+    /* intercept MSI-X entry page in the MMIO */
+    if (dev->cap.available & ASSIGNED_DEVICE_CAP_MSIX) {
+        if (assigned_dev_register_msix_mmio(dev)) {
+            goto out;
+        }
+    }
+
+    /* handle real device's MMIO/PIO BARs */
+    if (assigned_dev_register_regions(dev->real_device.regions,
+                                      dev->real_device.region_number,
+                                      dev)) {
+        goto out;
+    }
+
+    /* handle interrupt routing */
+    e_intx = dev->dev.config[PCI_INTERRUPT_PIN] - 1;
+    dev->intpin = e_intx;
+    dev->intx_route.mode = PCI_INTX_DISABLED;
+    dev->intx_route.irq = -1;
+
+    /* assign device to guest */
+    r = assign_device(dev);
+    if (r < 0) {
+        goto out;
+    }
+
+    /* assign legacy INTx to the device */
+    r = assign_intx(dev);
+    if (r < 0) {
+        goto assigned_out;
+    }
+
+    assigned_dev_load_option_rom(dev);
+
+    add_boot_device_path(dev->bootindex, &pci_dev->qdev, NULL);
+
+    return 0;
+
+assigned_out:
+    deassign_device(dev);
+out:
+    free_assigned_device(dev);
+    return -1;
+}
+
+static void assigned_exitfn(struct PCIDevice *pci_dev)
+{
+    AssignedDevice *dev = DO_UPCAST(AssignedDevice, dev, pci_dev);
+
+    deassign_device(dev);
+    free_assigned_device(dev);
+}
+
+static Property assigned_dev_properties[] = {
+    DEFINE_PROP_PCI_HOST_DEVADDR("host", AssignedDevice, host),
+    DEFINE_PROP_BIT("prefer_msi", AssignedDevice, features,
+                    ASSIGNED_DEVICE_PREFER_MSI_BIT, false),
+    DEFINE_PROP_BIT("share_intx", AssignedDevice, features,
+                    ASSIGNED_DEVICE_SHARE_INTX_BIT, true),
+    DEFINE_PROP_INT32("bootindex", AssignedDevice, bootindex, -1),
+    DEFINE_PROP_STRING("configfd", AssignedDevice, configfd_name),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void assign_class_init(ObjectClass *klass, void *data)
+{
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    k->init         = assigned_initfn;
+    k->exit         = assigned_exitfn;
+    k->config_read  = assigned_dev_pci_read_config;
+    k->config_write = assigned_dev_pci_write_config;
+    dc->props       = assigned_dev_properties;
+    dc->vmsd        = &vmstate_assigned_device;
+    dc->reset       = reset_assigned_device;
+    dc->desc        = "KVM-based PCI passthrough";
+}
+
+static const TypeInfo assign_info = {
+    .name               = "kvm-pci-assign",
+    .parent             = TYPE_PCI_DEVICE,
+    .instance_size      = sizeof(AssignedDevice),
+    .class_init         = assign_class_init,
+};
+
+static void assign_register_types(void)
+{
+    type_register_static(&assign_info);
+}
+
+type_init(assign_register_types)
+
+/*
+ * Scan the assigned devices for the devices that have an option ROM, and then
+ * load the corresponding ROM data to RAM. If an error occurs while loading an
+ * option ROM, we just ignore that option ROM and continue with the next one.
+ */
+static void assigned_dev_load_option_rom(AssignedDevice *dev)
+{
+    char name[32], rom_file[64];
+    FILE *fp;
+    uint8_t val;
+    struct stat st;
+    void *ptr;
+
+    /* If loading ROM from file, pci handles it */
+    if (dev->dev.romfile || !dev->dev.rom_bar) {
+        return;
+    }
+
+    snprintf(rom_file, sizeof(rom_file),
+             "/sys/bus/pci/devices/%04x:%02x:%02x.%01x/rom",
+             dev->host.domain, dev->host.bus, dev->host.slot,
+             dev->host.function);
+
+    if (stat(rom_file, &st)) {
+        return;
+    }
+
+    if (access(rom_file, F_OK)) {
+        error_report("pci-assign: Insufficient privileges for %s", rom_file);
+        return;
+    }
+
+    /* Write "1" to the ROM file to enable it */
+    fp = fopen(rom_file, "r+");
+    if (fp == NULL) {
+        return;
+    }
+    val = 1;
+    if (fwrite(&val, 1, 1, fp) != 1) {
+        goto close_rom;
+    }
+    fseek(fp, 0, SEEK_SET);
+
+    snprintf(name, sizeof(name), "%s.rom",
+            object_get_typename(OBJECT(dev)));
+    memory_region_init_ram(&dev->dev.rom, name, st.st_size);
+    vmstate_register_ram(&dev->dev.rom, &dev->dev.qdev);
+    ptr = memory_region_get_ram_ptr(&dev->dev.rom);
+    memset(ptr, 0xff, st.st_size);
+
+    if (!fread(ptr, 1, st.st_size, fp)) {
+        error_report("pci-assign: Cannot read from host %s", rom_file);
+        error_printf("Device option ROM contents are probably invalid "
+                     "(check dmesg).\nSkip option ROM probe with rombar=0, "
+                     "or load from file with romfile=\n");
+        memory_region_destroy(&dev->dev.rom);
+        goto close_rom;
+    }
+
+    pci_register_bar(&dev->dev, PCI_ROM_SLOT, 0, &dev->dev.rom);
+    dev->dev.has_rom = true;
+close_rom:
+    /* Write "0" to disable ROM */
+    fseek(fp, 0, SEEK_SET);
+    val = 0;
+    if (!fwrite(&val, 1, 1, fp)) {
+        DEBUG("%s\n", "Failed to disable pci-sysfs rom file");
+    }
+    fclose(fp);
+}
index cc95e5c3f054a1d665bbc1eec9df4b1dc6f41df6..ed9b448d07253846ab87eb9cd42fc84a25d2ee7c 100644 (file)
@@ -11,7 +11,7 @@
 #include "sysemu/sysemu.h"
 #include "sysemu/cpus.h"
 #include "sysemu/kvm.h"
-#include "hw/apic_internal.h"
+#include "hw/i386/apic_internal.h"
 
 #define VAPIC_IO_PORT           0x7e
 
index 3cb228f0ca67952739448b95ee58bdbf943b0bb2..d696507940e57ed9fac9fe37d4118809e2dca87e 100644 (file)
@@ -23,8 +23,8 @@
  */
 
 #include "hw/hw.h"
-#include "hw/fw_cfg.h"
-#include "hw/multiboot.h"
+#include "hw/nvram/fw_cfg.h"
+#include "multiboot.h"
 #include "hw/loader.h"
 #include "elf.h"
 #include "sysemu/sysemu.h"
diff --git a/hw/i386/multiboot.h b/hw/i386/multiboot.h
new file mode 100644 (file)
index 0000000..98fb1b7
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef QEMU_MULTIBOOT_H
+#define QEMU_MULTIBOOT_H
+
+int load_multiboot(void *fw_cfg,
+                   FILE *f,
+                   const char *kernel_filename,
+                   const char *initrd_filename,
+                   const char *kernel_cmdline,
+                   int kernel_file_size,
+                   uint8_t *header);
+
+#endif
index ebbf05922545f056048c1c7d734abc6048cbe60b..8d75b3421876f07f71f1238cf819c399913efbb2 100644 (file)
  * THE SOFTWARE.
  */
 #include "hw/hw.h"
-#include "hw/pc.h"
-#include "hw/serial.h"
-#include "hw/apic.h"
-#include "hw/fdc.h"
+#include "hw/i386/pc.h"
+#include "hw/char/serial.h"
+#include "hw/i386/apic.h"
+#include "hw/block/fdc.h"
 #include "hw/ide.h"
 #include "hw/pci/pci.h"
 #include "monitor/monitor.h"
-#include "hw/fw_cfg.h"
-#include "hw/hpet_emul.h"
-#include "hw/smbios.h"
+#include "hw/nvram/fw_cfg.h"
+#include "hw/timer/hpet.h"
+#include "hw/i386/smbios.h"
 #include "hw/loader.h"
 #include "elf.h"
-#include "hw/multiboot.h"
-#include "hw/mc146818rtc.h"
-#include "hw/i8254.h"
-#include "hw/pcspk.h"
+#include "multiboot.h"
+#include "hw/timer/mc146818rtc.h"
+#include "hw/timer/i8254.h"
+#include "hw/audio/pcspk.h"
 #include "hw/pci/msi.h"
 #include "hw/sysbus.h"
 #include "sysemu/sysemu.h"
 #include "sysemu/kvm.h"
 #include "kvm_i386.h"
-#include "hw/xen.h"
+#include "hw/xen/xen.h"
 #include "sysemu/blockdev.h"
-#include "hw/block-common.h"
+#include "hw/block/block.h"
 #include "ui/qemu-spice.h"
 #include "exec/memory.h"
 #include "exec/address-spaces.h"
index 0abc9f11e388fd169784a8de4b259ac0729fbff1..cff8013b830c78859b5197de88f828baa53007d3 100644 (file)
@@ -25,8 +25,8 @@
 #include <glib.h>
 
 #include "hw/hw.h"
-#include "hw/pc.h"
-#include "hw/apic.h"
+#include "hw/i386/pc.h"
+#include "hw/i386/apic.h"
 #include "hw/pci/pci.h"
 #include "hw/pci/pci_ids.h"
 #include "hw/usb.h"
@@ -39,8 +39,8 @@
 #include "hw/sysbus.h"
 #include "sysemu/arch_init.h"
 #include "sysemu/blockdev.h"
-#include "hw/smbus.h"
-#include "hw/xen.h"
+#include "hw/i2c/smbus.h"
+#include "hw/xen/xen.h"
 #include "exec/memory.h"
 #include "exec/address-spaces.h"
 #include "cpu.h"
index 4f5f34730900bf4ce62ca3bf4205364cee279474..6ac1a89ad71b1e90c6dd74d535130c7e2b1e7775 100644 (file)
  */
 #include "hw/hw.h"
 #include "sysemu/arch_init.h"
-#include "hw/smbus.h"
+#include "hw/i2c/smbus.h"
 #include "hw/boards.h"
-#include "hw/mc146818rtc.h"
-#include "hw/xen.h"
+#include "hw/timer/mc146818rtc.h"
+#include "hw/xen/xen.h"
 #include "sysemu/kvm.h"
 #include "hw/kvm/clock.h"
-#include "hw/q35.h"
+#include "hw/pci-host/q35.h"
 #include "exec/address-spaces.h"
-#include "hw/ich9.h"
+#include "hw/i386/ich9.h"
 #include "hw/ide/pci.h"
 #include "hw/ide/ahci.h"
 #include "hw/usb.h"
index 672ee9b0e7b5b5e7b62f5f84daab935e704ee092..c00bb2fad8372867d5de061ca806e9be686f53a0 100644 (file)
@@ -14,7 +14,7 @@
  */
 
 #include "sysemu/sysemu.h"
-#include "hw/smbios.h"
+#include "hw/i386/smbios.h"
 #include "hw/loader.h"
 
 /*
index d477061545849f3bab43fbc6b5ebff2038cadbcf..4e2cf95ae52b847051a186e4e32c28751af3fb26 100644 (file)
@@ -1,6 +1,6 @@
 #include <signal.h>
-#include "hw/xen_backend.h"
-#include "hw/xen_domainbuild.h"
+#include "hw/xen/xen_backend.h"
+#include "xen_domainbuild.h"
 #include "qemu/timer.h"
 #include "qemu/log.h"
 
diff --git a/hw/i386/xen_domainbuild.h b/hw/i386/xen_domainbuild.h
new file mode 100644 (file)
index 0000000..29a91ea
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef QEMU_HW_XEN_DOMAINBUILD_H
+#define QEMU_HW_XEN_DOMAINBUILD_H 1
+
+#include "hw/xen/xen_common.h"
+
+int xenstore_domain_init1(const char *kernel, const char *ramdisk,
+                          const char *cmdline);
+int xenstore_domain_init2(int xenstore_port, int xenstore_mfn,
+                          int console_port, int console_mfn);
+int xen_domain_build_pv(const char *kernel, const char *ramdisk,
+                        const char *cmdline);
+
+#endif /* QEMU_HW_XEN_DOMAINBUILD_H */
index 37ba34e5a903bcd76565b87afebec1eb2441d909..f829a52232c4f435465bf8b5bd8e360482571b78 100644 (file)
  */
 
 #include "hw/hw.h"
-#include "hw/pc.h"
+#include "hw/i386/pc.h"
 #include "hw/boards.h"
-#include "hw/xen_backend.h"
-#include "hw/xen_domainbuild.h"
+#include "hw/xen/xen_backend.h"
+#include "xen_domainbuild.h"
 #include "sysemu/blockdev.h"
 
 static void xen_init_pv(QEMUMachineInitArgs *args)
diff --git a/hw/i82374.c b/hw/i82374.c
deleted file mode 100644 (file)
index 22115e4..0000000
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * 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 "hw/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];
-    qemu_irq out;
-} 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, &s->out);
-    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);
-
-    qdev_init_gpio_out(&dev->qdev, &s->out, 1);
-
-    return 0;
-}
-
-static Property i82374_properties[] = {
-    DEFINE_PROP_HEX32("iobase", ISAi82374State, iobase, 0x400),
-    DEFINE_PROP_END_OF_LIST()
-};
-
-static void i82374_class_init(ObjectClass *klass, void *data)
-{
-    ISADeviceClass *k = ISA_DEVICE_CLASS(klass);
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    
-    k->init  = i82374_isa_init;
-    dc->vmsd = &vmstate_isa_i82374;
-    dc->props = i82374_properties;
-}
-
-static const TypeInfo i82374_isa_info = {
-    .name  = "i82374",
-    .parent = TYPE_ISA_DEVICE,
-    .instance_size  = sizeof(ISAi82374State),
-    .class_init = i82374_class_init,
-};
-
-static void i82374_register_types(void)
-{
-    type_register_static(&i82374_isa_info);
-}
-
-type_init(i82374_register_types)
diff --git a/hw/i82378.c b/hw/i82378.c
deleted file mode 100644 (file)
index 6f8c48b..0000000
+++ /dev/null
@@ -1,277 +0,0 @@
-/*
- * 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 "hw/pci/pci.h"
-#include "hw/pc.h"
-#include "hw/i8254.h"
-#include "hw/pcspk.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, hwaddr 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, hwaddr 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, hwaddr 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, hwaddr 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;
-    ISADevice *isa;
-    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, NULL);
-
-    /* speaker */
-    pcspk_init(isabus, pit);
-
-    /* 2 82C37 (dma) */
-    isa = isa_create_simple(isabus, "i82374");
-    qdev_connect_gpio_out(&isa->qdev, 0, s->out[1]);
-
-    /* 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);
-    pci_register_bar(dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mem);
-
-    /* Make I/O address read only */
-    pci_set_word(dev->wmask + PCI_COMMAND, PCI_COMMAND_SPECIAL);
-    pci_set_long(dev->wmask + PCI_BASE_ADDRESS_0, 0);
-    pci_set_long(pci_conf + PCI_BASE_ADDRESS_0, pci->isa_io_base);
-
-    isa_mem_base = pci->isa_mem_base;
-    isa_bus_new(&dev->qdev, pci_address_space_io(dev));
-
-    i82378_init(&dev->qdev, s);
-
-    return 0;
-}
-
-static Property i82378_properties[] = {
-    DEFINE_PROP_HEX32("iobase", PCIi82378State, isa_io_base, 0x80000000),
-    DEFINE_PROP_HEX32("membase", PCIi82378State, isa_mem_base, 0xc0000000),
-    DEFINE_PROP_END_OF_LIST()
-};
-
-static void pci_i82378_class_init(ObjectClass *klass, void *data)
-{
-    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-    DeviceClass *dc = DEVICE_CLASS(klass);
-
-    k->init = pci_i82378_init;
-    k->vendor_id = PCI_VENDOR_ID_INTEL;
-    k->device_id = PCI_DEVICE_ID_INTEL_82378;
-    k->revision = 0x03;
-    k->class_id = PCI_CLASS_BRIDGE_ISA;
-    k->subsystem_vendor_id = 0x0;
-    k->subsystem_id = 0x0;
-    dc->vmsd = &vmstate_pci_i82378;
-    dc->props = i82378_properties;
-}
-
-static const TypeInfo pci_i82378_info = {
-    .name = "i82378",
-    .parent = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(PCIi82378State),
-    .class_init = pci_i82378_class_init,
-};
-
-static void i82378_register_types(void)
-{
-    type_register_static(&pci_i82378_info);
-}
-
-type_init(i82378_register_types)
diff --git a/hw/i8254.c b/hw/i8254.c
deleted file mode 100644 (file)
index 67bfc6a..0000000
+++ /dev/null
@@ -1,362 +0,0 @@
-/*
- * 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.
- */
-#include "hw/hw.h"
-#include "hw/pc.h"
-#include "hw/isa.h"
-#include "qemu/timer.h"
-#include "hw/i8254.h"
-#include "hw/i8254_internal.h"
-
-//#define DEBUG_PIT
-
-#define RW_STATE_LSB 1
-#define RW_STATE_MSB 2
-#define RW_STATE_WORD0 3
-#define RW_STATE_WORD1 4
-
-static void pit_irq_timer_update(PITChannelState *s, int64_t current_time);
-
-static int pit_get_count(PITChannelState *s)
-{
-    uint64_t d;
-    int counter;
-
-    d = muldiv64(qemu_get_clock_ns(vm_clock) - s->count_load_time, PIT_FREQ,
-                 get_ticks_per_sec());
-    switch(s->mode) {
-    case 0:
-    case 1:
-    case 4:
-    case 5:
-        counter = (s->count - d) & 0xffff;
-        break;
-    case 3:
-        /* XXX: may be incorrect for odd counts */
-        counter = s->count - ((2 * d) % s->count);
-        break;
-    default:
-        counter = s->count - (d % s->count);
-        break;
-    }
-    return counter;
-}
-
-/* val must be 0 or 1 */
-static void pit_set_channel_gate(PITCommonState *s, PITChannelState *sc,
-                                 int val)
-{
-    switch (sc->mode) {
-    default:
-    case 0:
-    case 4:
-        /* XXX: just disable/enable counting */
-        break;
-    case 1:
-    case 5:
-        if (sc->gate < val) {
-            /* restart counting on rising edge */
-            sc->count_load_time = qemu_get_clock_ns(vm_clock);
-            pit_irq_timer_update(sc, sc->count_load_time);
-        }
-        break;
-    case 2:
-    case 3:
-        if (sc->gate < val) {
-            /* restart counting on rising edge */
-            sc->count_load_time = qemu_get_clock_ns(vm_clock);
-            pit_irq_timer_update(sc, sc->count_load_time);
-        }
-        /* XXX: disable/enable counting */
-        break;
-    }
-    sc->gate = val;
-}
-
-static inline void pit_load_count(PITChannelState *s, int val)
-{
-    if (val == 0)
-        val = 0x10000;
-    s->count_load_time = qemu_get_clock_ns(vm_clock);
-    s->count = val;
-    pit_irq_timer_update(s, s->count_load_time);
-}
-
-/* if already latched, do not latch again */
-static void pit_latch_count(PITChannelState *s)
-{
-    if (!s->count_latched) {
-        s->latched_count = pit_get_count(s);
-        s->count_latched = s->rw_mode;
-    }
-}
-
-static void pit_ioport_write(void *opaque, hwaddr addr,
-                             uint64_t val, unsigned size)
-{
-    PITCommonState *pit = opaque;
-    int channel, access;
-    PITChannelState *s;
-
-    addr &= 3;
-    if (addr == 3) {
-        channel = val >> 6;
-        if (channel == 3) {
-            /* read back command */
-            for(channel = 0; channel < 3; channel++) {
-                s = &pit->channels[channel];
-                if (val & (2 << channel)) {
-                    if (!(val & 0x20)) {
-                        pit_latch_count(s);
-                    }
-                    if (!(val & 0x10) && !s->status_latched) {
-                        /* status latch */
-                        /* XXX: add BCD and null count */
-                        s->status =
-                            (pit_get_out(s,
-                                         qemu_get_clock_ns(vm_clock)) << 7) |
-                            (s->rw_mode << 4) |
-                            (s->mode << 1) |
-                            s->bcd;
-                        s->status_latched = 1;
-                    }
-                }
-            }
-        } else {
-            s = &pit->channels[channel];
-            access = (val >> 4) & 3;
-            if (access == 0) {
-                pit_latch_count(s);
-            } else {
-                s->rw_mode = access;
-                s->read_state = access;
-                s->write_state = access;
-
-                s->mode = (val >> 1) & 7;
-                s->bcd = val & 1;
-                /* XXX: update irq timer ? */
-            }
-        }
-    } else {
-        s = &pit->channels[addr];
-        switch(s->write_state) {
-        default:
-        case RW_STATE_LSB:
-            pit_load_count(s, val);
-            break;
-        case RW_STATE_MSB:
-            pit_load_count(s, val << 8);
-            break;
-        case RW_STATE_WORD0:
-            s->write_latch = val;
-            s->write_state = RW_STATE_WORD1;
-            break;
-        case RW_STATE_WORD1:
-            pit_load_count(s, s->write_latch | (val << 8));
-            s->write_state = RW_STATE_WORD0;
-            break;
-        }
-    }
-}
-
-static uint64_t pit_ioport_read(void *opaque, hwaddr addr,
-                                unsigned size)
-{
-    PITCommonState *pit = opaque;
-    int ret, count;
-    PITChannelState *s;
-
-    addr &= 3;
-    s = &pit->channels[addr];
-    if (s->status_latched) {
-        s->status_latched = 0;
-        ret = s->status;
-    } else if (s->count_latched) {
-        switch(s->count_latched) {
-        default:
-        case RW_STATE_LSB:
-            ret = s->latched_count & 0xff;
-            s->count_latched = 0;
-            break;
-        case RW_STATE_MSB:
-            ret = s->latched_count >> 8;
-            s->count_latched = 0;
-            break;
-        case RW_STATE_WORD0:
-            ret = s->latched_count & 0xff;
-            s->count_latched = RW_STATE_MSB;
-            break;
-        }
-    } else {
-        switch(s->read_state) {
-        default:
-        case RW_STATE_LSB:
-            count = pit_get_count(s);
-            ret = count & 0xff;
-            break;
-        case RW_STATE_MSB:
-            count = pit_get_count(s);
-            ret = (count >> 8) & 0xff;
-            break;
-        case RW_STATE_WORD0:
-            count = pit_get_count(s);
-            ret = count & 0xff;
-            s->read_state = RW_STATE_WORD1;
-            break;
-        case RW_STATE_WORD1:
-            count = pit_get_count(s);
-            ret = (count >> 8) & 0xff;
-            s->read_state = RW_STATE_WORD0;
-            break;
-        }
-    }
-    return ret;
-}
-
-static void pit_irq_timer_update(PITChannelState *s, int64_t current_time)
-{
-    int64_t expire_time;
-    int irq_level;
-
-    if (!s->irq_timer || s->irq_disabled) {
-        return;
-    }
-    expire_time = pit_get_next_transition_time(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",
-           irq_level,
-           (double)(expire_time - current_time) / get_ticks_per_sec());
-#endif
-    s->next_transition_time = expire_time;
-    if (expire_time != -1)
-        qemu_mod_timer(s->irq_timer, expire_time);
-    else
-        qemu_del_timer(s->irq_timer);
-}
-
-static void pit_irq_timer(void *opaque)
-{
-    PITChannelState *s = opaque;
-
-    pit_irq_timer_update(s, s->next_transition_time);
-}
-
-static void pit_reset(DeviceState *dev)
-{
-    PITCommonState *pit = DO_UPCAST(PITCommonState, dev.qdev, dev);
-    PITChannelState *s;
-
-    pit_reset_common(pit);
-
-    s = &pit->channels[0];
-    if (!s->irq_disabled) {
-        qemu_mod_timer(s->irq_timer, s->next_transition_time);
-    }
-}
-
-/* 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)
-{
-    PITCommonState *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 MemoryRegionOps pit_ioport_ops = {
-    .read = pit_ioport_read,
-    .write = pit_ioport_write,
-    .impl = {
-        .min_access_size = 1,
-        .max_access_size = 1,
-    },
-    .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static void pit_post_load(PITCommonState *s)
-{
-    PITChannelState *sc = &s->channels[0];
-
-    if (sc->next_transition_time != -1) {
-        qemu_mod_timer(sc->irq_timer, sc->next_transition_time);
-    } else {
-        qemu_del_timer(sc->irq_timer);
-    }
-}
-
-static int pit_initfn(PITCommonState *pit)
-{
-    PITChannelState *s;
-
-    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);
-    qdev_init_gpio_out(&pit->dev.qdev, &s->irq, 1);
-
-    memory_region_init_io(&pit->ioports, &pit_ioport_ops, pit, "pit", 4);
-
-    qdev_init_gpio_in(&pit->dev.qdev, pit_irq_control, 1);
-
-    return 0;
-}
-
-static Property pit_properties[] = {
-    DEFINE_PROP_HEX32("iobase", PITCommonState, iobase,  -1),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void pit_class_initfn(ObjectClass *klass, void *data)
-{
-    PITCommonClass *k = PIT_COMMON_CLASS(klass);
-    DeviceClass *dc = DEVICE_CLASS(klass);
-
-    k->init = pit_initfn;
-    k->set_channel_gate = pit_set_channel_gate;
-    k->get_channel_info = pit_get_channel_info_common;
-    k->post_load = pit_post_load;
-    dc->reset = pit_reset;
-    dc->props = pit_properties;
-}
-
-static const TypeInfo pit_info = {
-    .name          = "isa-pit",
-    .parent        = TYPE_PIT_COMMON,
-    .instance_size = sizeof(PITCommonState),
-    .class_init    = pit_class_initfn,
-};
-
-static void pit_register_types(void)
-{
-    type_register_static(&pit_info);
-}
-
-type_init(pit_register_types)
diff --git a/hw/i8254.h b/hw/i8254.h
deleted file mode 100644 (file)
index 7d4432e..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * 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/hw.h"
-#include "hw/isa.h"
-
-#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)
-{
-    ISADevice *dev;
-
-    dev = isa_create(bus, "isa-pit");
-    qdev_prop_set_uint32(&dev->qdev, "iobase", base);
-    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;
-}
-
-static inline ISADevice *kvm_pit_init(ISABus *bus, int base)
-{
-    ISADevice *dev;
-
-    dev = isa_create(bus, "kvm-pit");
-    qdev_prop_set_uint32(&dev->qdev, "iobase", base);
-    qdev_init_nofail(&dev->qdev);
-
-    return dev;
-}
-
-void pit_set_gate(ISADevice *dev, int channel, int val);
-void pit_get_channel_info(ISADevice *dev, int channel, PITChannelInfo *info);
-
-#endif /* !HW_I8254_H */
diff --git a/hw/i8254_common.c b/hw/i8254_common.c
deleted file mode 100644 (file)
index c6c0c80..0000000
+++ /dev/null
@@ -1,311 +0,0 @@
-/*
- * QEMU 8253/8254 - common bits of emulated and KVM kernel model
- *
- * Copyright (c) 2003-2004 Fabrice Bellard
- * Copyright (c) 2012      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 "hw/hw.h"
-#include "hw/pc.h"
-#include "hw/isa.h"
-#include "qemu/timer.h"
-#include "hw/i8254.h"
-#include "hw/i8254_internal.h"
-
-/* val must be 0 or 1 */
-void pit_set_gate(ISADevice *dev, int channel, int val)
-{
-    PITCommonState *pit = PIT_COMMON(dev);
-    PITChannelState *s = &pit->channels[channel];
-    PITCommonClass *c = PIT_COMMON_GET_CLASS(pit);
-
-    c->set_channel_gate(pit, s, val);
-}
-
-/* get pit output bit */
-int pit_get_out(PITChannelState *s, int64_t current_time)
-{
-    uint64_t d;
-    int out;
-
-    d = muldiv64(current_time - s->count_load_time, PIT_FREQ,
-                 get_ticks_per_sec());
-    switch (s->mode) {
-    default:
-    case 0:
-        out = (d >= s->count);
-        break;
-    case 1:
-        out = (d < s->count);
-        break;
-    case 2:
-        if ((d % s->count) == 0 && d != 0) {
-            out = 1;
-        } else {
-            out = 0;
-        }
-        break;
-    case 3:
-        out = (d % s->count) < ((s->count + 1) >> 1);
-        break;
-    case 4:
-    case 5:
-        out = (d == s->count);
-        break;
-    }
-    return out;
-}
-
-/* return -1 if no transition will occur.  */
-int64_t pit_get_next_transition_time(PITChannelState *s, int64_t current_time)
-{
-    uint64_t d, next_time, base;
-    int period2;
-
-    d = muldiv64(current_time - s->count_load_time, PIT_FREQ,
-                 get_ticks_per_sec());
-    switch (s->mode) {
-    default:
-    case 0:
-    case 1:
-        if (d < s->count) {
-            next_time = s->count;
-        } else {
-            return -1;
-        }
-        break;
-    case 2:
-        base = (d / s->count) * s->count;
-        if ((d - base) == 0 && d != 0) {
-            next_time = base + s->count;
-        } else {
-            next_time = base + s->count + 1;
-        }
-        break;
-    case 3:
-        base = (d / s->count) * s->count;
-        period2 = ((s->count + 1) >> 1);
-        if ((d - base) < period2) {
-            next_time = base + period2;
-        } else {
-            next_time = base + s->count;
-        }
-        break;
-    case 4:
-    case 5:
-        if (d < s->count) {
-            next_time = s->count;
-        } else if (d == s->count) {
-            next_time = s->count + 1;
-        } else {
-            return -1;
-        }
-        break;
-    }
-    /* convert to timer units */
-    next_time = s->count_load_time + muldiv64(next_time, get_ticks_per_sec(),
-                                              PIT_FREQ);
-    /* fix potential rounding problems */
-    /* XXX: better solution: use a clock at PIT_FREQ Hz */
-    if (next_time <= current_time) {
-        next_time = current_time + 1;
-    }
-    return next_time;
-}
-
-void pit_get_channel_info_common(PITCommonState *s, PITChannelState *sc,
-                                 PITChannelInfo *info)
-{
-    info->gate = sc->gate;
-    info->mode = sc->mode;
-    info->initial_count = sc->count;
-    info->out = pit_get_out(sc, qemu_get_clock_ns(vm_clock));
-}
-
-void pit_get_channel_info(ISADevice *dev, int channel, PITChannelInfo *info)
-{
-    PITCommonState *pit = PIT_COMMON(dev);
-    PITChannelState *s = &pit->channels[channel];
-    PITCommonClass *c = PIT_COMMON_GET_CLASS(pit);
-
-    c->get_channel_info(pit, s, info);
-}
-
-void pit_reset_common(PITCommonState *pit)
-{
-    PITChannelState *s;
-    int i;
-
-    for (i = 0; i < 3; i++) {
-        s = &pit->channels[i];
-        s->mode = 3;
-        s->gate = (i != 2);
-        s->count_load_time = qemu_get_clock_ns(vm_clock);
-        s->count = 0x10000;
-        if (i == 0 && !s->irq_disabled) {
-            s->next_transition_time =
-                pit_get_next_transition_time(s, s->count_load_time);
-        }
-    }
-}
-
-static int pit_init_common(ISADevice *dev)
-{
-    PITCommonState *pit = PIT_COMMON(dev);
-    PITCommonClass *c = PIT_COMMON_GET_CLASS(pit);
-    int ret;
-
-    ret = c->init(pit);
-    if (ret < 0) {
-        return ret;
-    }
-
-    isa_register_ioport(dev, &pit->ioports, pit->iobase);
-
-    qdev_set_legacy_instance_id(&dev->qdev, pit->iobase, 2);
-
-    return 0;
-}
-
-static const VMStateDescription vmstate_pit_channel = {
-    .name = "pit channel",
-    .version_id = 2,
-    .minimum_version_id = 2,
-    .minimum_version_id_old = 2,
-    .fields = (VMStateField[]) {
-        VMSTATE_INT32(count, PITChannelState),
-        VMSTATE_UINT16(latched_count, PITChannelState),
-        VMSTATE_UINT8(count_latched, PITChannelState),
-        VMSTATE_UINT8(status_latched, PITChannelState),
-        VMSTATE_UINT8(status, PITChannelState),
-        VMSTATE_UINT8(read_state, PITChannelState),
-        VMSTATE_UINT8(write_state, PITChannelState),
-        VMSTATE_UINT8(write_latch, PITChannelState),
-        VMSTATE_UINT8(rw_mode, PITChannelState),
-        VMSTATE_UINT8(mode, PITChannelState),
-        VMSTATE_UINT8(bcd, PITChannelState),
-        VMSTATE_UINT8(gate, PITChannelState),
-        VMSTATE_INT64(count_load_time, PITChannelState),
-        VMSTATE_INT64(next_transition_time, PITChannelState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static int pit_load_old(QEMUFile *f, void *opaque, int version_id)
-{
-    PITCommonState *pit = opaque;
-    PITCommonClass *c = PIT_COMMON_GET_CLASS(pit);
-    PITChannelState *s;
-    int i;
-
-    if (version_id != 1) {
-        return -EINVAL;
-    }
-
-    for (i = 0; i < 3; i++) {
-        s = &pit->channels[i];
-        s->count = qemu_get_be32(f);
-        qemu_get_be16s(f, &s->latched_count);
-        qemu_get_8s(f, &s->count_latched);
-        qemu_get_8s(f, &s->status_latched);
-        qemu_get_8s(f, &s->status);
-        qemu_get_8s(f, &s->read_state);
-        qemu_get_8s(f, &s->write_state);
-        qemu_get_8s(f, &s->write_latch);
-        qemu_get_8s(f, &s->rw_mode);
-        qemu_get_8s(f, &s->mode);
-        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 (i == 0) {
-            s->next_transition_time = qemu_get_be64(f);
-        }
-    }
-    if (c->post_load) {
-        c->post_load(pit);
-    }
-    return 0;
-}
-
-static void pit_dispatch_pre_save(void *opaque)
-{
-    PITCommonState *s = opaque;
-    PITCommonClass *c = PIT_COMMON_GET_CLASS(s);
-
-    if (c->pre_save) {
-        c->pre_save(s);
-    }
-}
-
-static int pit_dispatch_post_load(void *opaque, int version_id)
-{
-    PITCommonState *s = opaque;
-    PITCommonClass *c = PIT_COMMON_GET_CLASS(s);
-
-    if (c->post_load) {
-        c->post_load(s);
-    }
-    return 0;
-}
-
-static const VMStateDescription vmstate_pit_common = {
-    .name = "i8254",
-    .version_id = 3,
-    .minimum_version_id = 2,
-    .minimum_version_id_old = 1,
-    .load_state_old = pit_load_old,
-    .pre_save = pit_dispatch_pre_save,
-    .post_load = pit_dispatch_post_load,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT32_V(channels[0].irq_disabled, PITCommonState, 3),
-        VMSTATE_STRUCT_ARRAY(channels, PITCommonState, 3, 2,
-                             vmstate_pit_channel, PITChannelState),
-        VMSTATE_INT64(channels[0].next_transition_time,
-                      PITCommonState), /* formerly irq_timer */
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void pit_common_class_init(ObjectClass *klass, void *data)
-{
-    ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
-    DeviceClass *dc = DEVICE_CLASS(klass);
-
-    ic->init = pit_init_common;
-    dc->vmsd = &vmstate_pit_common;
-    dc->no_user = 1;
-}
-
-static const TypeInfo pit_common_type = {
-    .name          = TYPE_PIT_COMMON,
-    .parent        = TYPE_ISA_DEVICE,
-    .instance_size = sizeof(PITCommonState),
-    .class_size    = sizeof(PITCommonClass),
-    .class_init    = pit_common_class_init,
-    .abstract      = true,
-};
-
-static void register_devices(void)
-{
-    type_register_static(&pit_common_type);
-}
-
-type_init(register_devices);
diff --git a/hw/i8254_internal.h b/hw/i8254_internal.h
deleted file mode 100644 (file)
index 30d5b1b..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * QEMU 8253/8254 - 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_I8254_INTERNAL_H
-#define QEMU_I8254_INTERNAL_H
-
-#include "hw/hw.h"
-#include "hw/pc.h"
-#include "hw/isa.h"
-
-typedef struct PITChannelState {
-    int count; /* can be 65536 */
-    uint16_t latched_count;
-    uint8_t count_latched;
-    uint8_t status_latched;
-    uint8_t status;
-    uint8_t read_state;
-    uint8_t write_state;
-    uint8_t write_latch;
-    uint8_t rw_mode;
-    uint8_t mode;
-    uint8_t bcd; /* not supported */
-    uint8_t gate; /* timer start */
-    int64_t count_load_time;
-    /* irq handling */
-    int64_t next_transition_time;
-    QEMUTimer *irq_timer;
-    qemu_irq irq;
-    uint32_t irq_disabled;
-} PITChannelState;
-
-typedef struct PITCommonState {
-    ISADevice dev;
-    MemoryRegion ioports;
-    uint32_t iobase;
-    PITChannelState channels[3];
-} PITCommonState;
-
-#define TYPE_PIT_COMMON "pit-common"
-#define PIT_COMMON(obj) \
-     OBJECT_CHECK(PITCommonState, (obj), TYPE_PIT_COMMON)
-#define PIT_COMMON_CLASS(klass) \
-     OBJECT_CLASS_CHECK(PITCommonClass, (klass), TYPE_PIT_COMMON)
-#define PIT_COMMON_GET_CLASS(obj) \
-     OBJECT_GET_CLASS(PITCommonClass, (obj), TYPE_PIT_COMMON)
-
-typedef struct PITCommonClass {
-    ISADeviceClass parent_class;
-
-    int (*init)(PITCommonState *s);
-    void (*set_channel_gate)(PITCommonState *s, PITChannelState *sc, int val);
-    void (*get_channel_info)(PITCommonState *s, PITChannelState *sc,
-                             PITChannelInfo *info);
-    void (*pre_save)(PITCommonState *s);
-    void (*post_load)(PITCommonState *s);
-} PITCommonClass;
-
-int pit_get_out(PITChannelState *s, int64_t current_time);
-int64_t pit_get_next_transition_time(PITChannelState *s, int64_t current_time);
-void pit_get_channel_info_common(PITCommonState *s, PITChannelState *sc,
-                                 PITChannelInfo *info);
-void pit_reset_common(PITCommonState *s);
-
-#endif /* !QEMU_I8254_INTERNAL_H */
diff --git a/hw/i8259.c b/hw/i8259.c
deleted file mode 100644 (file)
index 1d82752..0000000
+++ /dev/null
@@ -1,496 +0,0 @@
-/*
- * QEMU 8259 interrupt controller 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.
- */
-#include "hw/hw.h"
-#include "hw/pc.h"
-#include "hw/isa.h"
-#include "monitor/monitor.h"
-#include "qemu/timer.h"
-#include "hw/i8259_internal.h"
-
-/* debug PIC */
-//#define DEBUG_PIC
-
-#ifdef DEBUG_PIC
-#define DPRINTF(fmt, ...)                                       \
-    do { printf("pic: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...)
-#endif
-
-//#define DEBUG_IRQ_LATENCY
-//#define DEBUG_IRQ_COUNT
-
-#if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT)
-static int irq_level[16];
-#endif
-#ifdef DEBUG_IRQ_COUNT
-static uint64_t irq_count[16];
-#endif
-#ifdef DEBUG_IRQ_LATENCY
-static int64_t irq_time[16];
-#endif
-DeviceState *isa_pic;
-static PICCommonState *slave_pic;
-
-/* return the highest priority found in mask (highest = smallest
-   number). Return 8 if no irq */
-static int get_priority(PICCommonState *s, int mask)
-{
-    int priority;
-
-    if (mask == 0) {
-        return 8;
-    }
-    priority = 0;
-    while ((mask & (1 << ((priority + s->priority_add) & 7))) == 0) {
-        priority++;
-    }
-    return priority;
-}
-
-/* return the pic wanted interrupt. return -1 if none */
-static int pic_get_irq(PICCommonState *s)
-{
-    int mask, cur_priority, priority;
-
-    mask = s->irr & ~s->imr;
-    priority = get_priority(s, mask);
-    if (priority == 8) {
-        return -1;
-    }
-    /* compute current priority. If special fully nested mode on the
-       master, the IRQ coming from the slave is not taken into account
-       for the priority computation. */
-    mask = s->isr;
-    if (s->special_mask) {
-        mask &= ~s->imr;
-    }
-    if (s->special_fully_nested_mode && s->master) {
-        mask &= ~(1 << 2);
-    }
-    cur_priority = get_priority(s, mask);
-    if (priority < cur_priority) {
-        /* higher priority found: an irq should be generated */
-        return (priority + s->priority_add) & 7;
-    } else {
-        return -1;
-    }
-}
-
-/* Update INT output. Must be called every time the output may have changed. */
-static void pic_update_irq(PICCommonState *s)
-{
-    int irq;
-
-    irq = pic_get_irq(s);
-    if (irq >= 0) {
-        DPRINTF("pic%d: imr=%x irr=%x padd=%d\n",
-                s->master ? 0 : 1, s->imr, s->irr, s->priority_add);
-        qemu_irq_raise(s->int_out[0]);
-    } else {
-        qemu_irq_lower(s->int_out[0]);
-    }
-}
-
-/* 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)
-{
-    PICCommonState *s = opaque;
-    int mask = 1 << irq;
-
-#if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT) || \
-    defined(DEBUG_IRQ_LATENCY)
-    int irq_index = s->master ? irq : irq + 8;
-#endif
-#if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT)
-    if (level != irq_level[irq_index]) {
-        DPRINTF("pic_set_irq: irq=%d level=%d\n", irq_index, level);
-        irq_level[irq_index] = level;
-#ifdef DEBUG_IRQ_COUNT
-        if (level == 1) {
-            irq_count[irq_index]++;
-        }
-#endif
-    }
-#endif
-#ifdef DEBUG_IRQ_LATENCY
-    if (level) {
-        irq_time[irq_index] = qemu_get_clock_ns(vm_clock);
-    }
-#endif
-
-    if (s->elcr & mask) {
-        /* level triggered */
-        if (level) {
-            s->irr |= mask;
-            s->last_irr |= mask;
-        } else {
-            s->irr &= ~mask;
-            s->last_irr &= ~mask;
-        }
-    } else {
-        /* edge triggered */
-        if (level) {
-            if ((s->last_irr & mask) == 0) {
-                s->irr |= mask;
-            }
-            s->last_irr |= mask;
-        } else {
-            s->last_irr &= ~mask;
-        }
-    }
-    pic_update_irq(s);
-}
-
-/* acknowledge interrupt 'irq' */
-static void pic_intack(PICCommonState *s, int irq)
-{
-    if (s->auto_eoi) {
-        if (s->rotate_on_auto_eoi) {
-            s->priority_add = (irq + 1) & 7;
-        }
-    } else {
-        s->isr |= (1 << irq);
-    }
-    /* We don't clear a level sensitive interrupt here */
-    if (!(s->elcr & (1 << irq))) {
-        s->irr &= ~(1 << irq);
-    }
-    pic_update_irq(s);
-}
-
-int pic_read_irq(DeviceState *d)
-{
-    PICCommonState *s = DO_UPCAST(PICCommonState, dev.qdev, d);
-    int irq, irq2, intno;
-
-    irq = pic_get_irq(s);
-    if (irq >= 0) {
-        if (irq == 2) {
-            irq2 = pic_get_irq(slave_pic);
-            if (irq2 >= 0) {
-                pic_intack(slave_pic, irq2);
-            } else {
-                /* spurious IRQ on slave controller */
-                irq2 = 7;
-            }
-            intno = slave_pic->irq_base + irq2;
-        } else {
-            intno = s->irq_base + irq;
-        }
-        pic_intack(s, irq);
-    } else {
-        /* spurious IRQ on host controller */
-        irq = 7;
-        intno = s->irq_base + irq;
-    }
-
-#if defined(DEBUG_PIC) || defined(DEBUG_IRQ_LATENCY)
-    if (irq == 2) {
-        irq = irq2 + 8;
-    }
-#endif
-#ifdef DEBUG_IRQ_LATENCY
-    printf("IRQ%d latency=%0.3fus\n",
-           irq,
-           (double)(qemu_get_clock_ns(vm_clock) -
-                    irq_time[irq]) * 1000000.0 / get_ticks_per_sec());
-#endif
-    DPRINTF("pic_interrupt: irq=%d\n", irq);
-    return intno;
-}
-
-static void pic_init_reset(PICCommonState *s)
-{
-    pic_reset_common(s);
-    pic_update_irq(s);
-}
-
-static void pic_reset(DeviceState *dev)
-{
-    PICCommonState *s = DO_UPCAST(PICCommonState, dev.qdev, dev);
-
-    s->elcr = 0;
-    pic_init_reset(s);
-}
-
-static void pic_ioport_write(void *opaque, hwaddr addr64,
-                             uint64_t val64, unsigned size)
-{
-    PICCommonState *s = opaque;
-    uint32_t addr = addr64;
-    uint32_t val = val64;
-    int priority, cmd, irq;
-
-    DPRINTF("write: addr=0x%02x val=0x%02x\n", addr, val);
-    if (addr == 0) {
-        if (val & 0x10) {
-            pic_init_reset(s);
-            s->init_state = 1;
-            s->init4 = val & 1;
-            s->single_mode = val & 2;
-            if (val & 0x08) {
-                hw_error("level sensitive irq not supported");
-            }
-        } else if (val & 0x08) {
-            if (val & 0x04) {
-                s->poll = 1;
-            }
-            if (val & 0x02) {
-                s->read_reg_select = val & 1;
-            }
-            if (val & 0x40) {
-                s->special_mask = (val >> 5) & 1;
-            }
-        } else {
-            cmd = val >> 5;
-            switch (cmd) {
-            case 0:
-            case 4:
-                s->rotate_on_auto_eoi = cmd >> 2;
-                break;
-            case 1: /* end of interrupt */
-            case 5:
-                priority = get_priority(s, s->isr);
-                if (priority != 8) {
-                    irq = (priority + s->priority_add) & 7;
-                    s->isr &= ~(1 << irq);
-                    if (cmd == 5) {
-                        s->priority_add = (irq + 1) & 7;
-                    }
-                    pic_update_irq(s);
-                }
-                break;
-            case 3:
-                irq = val & 7;
-                s->isr &= ~(1 << irq);
-                pic_update_irq(s);
-                break;
-            case 6:
-                s->priority_add = (val + 1) & 7;
-                pic_update_irq(s);
-                break;
-            case 7:
-                irq = val & 7;
-                s->isr &= ~(1 << irq);
-                s->priority_add = (irq + 1) & 7;
-                pic_update_irq(s);
-                break;
-            default:
-                /* no operation */
-                break;
-            }
-        }
-    } else {
-        switch (s->init_state) {
-        case 0:
-            /* normal mode */
-            s->imr = val;
-            pic_update_irq(s);
-            break;
-        case 1:
-            s->irq_base = val & 0xf8;
-            s->init_state = s->single_mode ? (s->init4 ? 3 : 0) : 2;
-            break;
-        case 2:
-            if (s->init4) {
-                s->init_state = 3;
-            } else {
-                s->init_state = 0;
-            }
-            break;
-        case 3:
-            s->special_fully_nested_mode = (val >> 4) & 1;
-            s->auto_eoi = (val >> 1) & 1;
-            s->init_state = 0;
-            break;
-        }
-    }
-}
-
-static uint64_t pic_ioport_read(void *opaque, hwaddr addr,
-                                unsigned size)
-{
-    PICCommonState *s = opaque;
-    int ret;
-
-    if (s->poll) {
-        ret = pic_get_irq(s);
-        if (ret >= 0) {
-            pic_intack(s, ret);
-            ret |= 0x80;
-        } else {
-            ret = 0;
-        }
-        s->poll = 0;
-    } else {
-        if (addr == 0) {
-            if (s->read_reg_select) {
-                ret = s->isr;
-            } else {
-                ret = s->irr;
-            }
-        } else {
-            ret = s->imr;
-        }
-    }
-    DPRINTF("read: addr=0x%02x val=0x%02x\n", addr, ret);
-    return ret;
-}
-
-int pic_get_output(DeviceState *d)
-{
-    PICCommonState *s = DO_UPCAST(PICCommonState, dev.qdev, d);
-
-    return (pic_get_irq(s) >= 0);
-}
-
-static void elcr_ioport_write(void *opaque, hwaddr addr,
-                              uint64_t val, unsigned size)
-{
-    PICCommonState *s = opaque;
-    s->elcr = val & s->elcr_mask;
-}
-
-static uint64_t elcr_ioport_read(void *opaque, hwaddr addr,
-                                 unsigned size)
-{
-    PICCommonState *s = opaque;
-    return s->elcr;
-}
-
-static const MemoryRegionOps pic_base_ioport_ops = {
-    .read = pic_ioport_read,
-    .write = pic_ioport_write,
-    .impl = {
-        .min_access_size = 1,
-        .max_access_size = 1,
-    },
-};
-
-static const MemoryRegionOps pic_elcr_ioport_ops = {
-    .read = elcr_ioport_read,
-    .write = elcr_ioport_write,
-    .impl = {
-        .min_access_size = 1,
-        .max_access_size = 1,
-    },
-};
-
-static void pic_init(PICCommonState *s)
-{
-    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);
-
-    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, const QDict *qdict)
-{
-    int i;
-    PICCommonState *s;
-
-    if (!isa_pic) {
-        return;
-    }
-    for (i = 0; i < 2; i++) {
-        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,
-                       s->irq_base, s->read_reg_select, s->elcr,
-                       s->special_fully_nested_mode);
-    }
-}
-
-void irq_info(Monitor *mon, const QDict *qdict)
-{
-#ifndef DEBUG_IRQ_COUNT
-    monitor_printf(mon, "irq statistic code not compiled.\n");
-#else
-    int i;
-    int64_t count;
-
-    monitor_printf(mon, "IRQ statistics:\n");
-    for (i = 0; i < 16; i++) {
-        count = irq_count[i];
-        if (count > 0) {
-            monitor_printf(mon, "%2d: %" PRId64 "\n", i, count);
-        }
-    }
-#endif
-}
-
-qemu_irq *i8259_init(ISABus *bus, qemu_irq parent_irq)
-{
-    qemu_irq *irq_set;
-    ISADevice *dev;
-    int i;
-
-    irq_set = g_malloc(ISA_NUM_IRQS * sizeof(qemu_irq));
-
-    dev = i8259_init_chip("isa-i8259", bus, true);
-
-    qdev_connect_gpio_out(&dev->qdev, 0, parent_irq);
-    for (i = 0 ; i < 8; i++) {
-        irq_set[i] = qdev_get_gpio_in(&dev->qdev, i);
-    }
-
-    isa_pic = &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(PICCommonState, dev, dev);
-
-    return irq_set;
-}
-
-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 const TypeInfo i8259_info = {
-    .name       = "isa-i8259",
-    .instance_size = sizeof(PICCommonState),
-    .parent     = TYPE_PIC_COMMON,
-    .class_init = i8259_class_init,
-};
-
-static void pic_register_types(void)
-{
-    type_register_static(&i8259_info);
-}
-
-type_init(pic_register_types)
diff --git a/hw/i8259_common.c b/hw/i8259_common.c
deleted file mode 100644 (file)
index 98052db..0000000
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * 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 "hw/pc.h"
-#include "hw/i8259_internal.h"
-
-void pic_reset_common(PICCommonState *s)
-{
-    s->last_irr = 0;
-    s->irr &= s->elcr;
-    s->imr = 0;
-    s->isr = 0;
-    s->priority_add = 0;
-    s->irq_base = 0;
-    s->read_reg_select = 0;
-    s->poll = 0;
-    s->special_mask = 0;
-    s->init_state = 0;
-    s->auto_eoi = 0;
-    s->rotate_on_auto_eoi = 0;
-    s->special_fully_nested_mode = 0;
-    s->init4 = 0;
-    s->single_mode = 0;
-    /* Note: ELCR is not reset */
-}
-
-static void pic_dispatch_pre_save(void *opaque)
-{
-    PICCommonState *s = opaque;
-    PICCommonClass *info = PIC_COMMON_GET_CLASS(s);
-
-    if (info->pre_save) {
-        info->pre_save(s);
-    }
-}
-
-static int pic_dispatch_post_load(void *opaque, int version_id)
-{
-    PICCommonState *s = opaque;
-    PICCommonClass *info = PIC_COMMON_GET_CLASS(s);
-
-    if (info->post_load) {
-        info->post_load(s);
-    }
-    return 0;
-}
-
-static int pic_init_common(ISADevice *dev)
-{
-    PICCommonState *s = DO_UPCAST(PICCommonState, dev, dev);
-    PICCommonClass *info = PIC_COMMON_GET_CLASS(s);
-
-    info->init(s);
-
-    isa_register_ioport(NULL, &s->base_io, s->iobase);
-    if (s->elcr_addr != -1) {
-        isa_register_ioport(NULL, &s->elcr_io, s->elcr_addr);
-    }
-
-    qdev_set_legacy_instance_id(&s->dev.qdev, s->iobase, 1);
-
-    return 0;
-}
-
-ISADevice *i8259_init_chip(const char *name, ISABus *bus, bool master)
-{
-    ISADevice *dev;
-
-    dev = isa_create(bus, name);
-    qdev_prop_set_uint32(&dev->qdev, "iobase", master ? 0x20 : 0xa0);
-    qdev_prop_set_uint32(&dev->qdev, "elcr_addr", master ? 0x4d0 : 0x4d1);
-    qdev_prop_set_uint8(&dev->qdev, "elcr_mask", master ? 0xf8 : 0xde);
-    qdev_prop_set_bit(&dev->qdev, "master", master);
-    qdev_init_nofail(&dev->qdev);
-
-    return dev;
-}
-
-static const VMStateDescription vmstate_pic_common = {
-    .name = "i8259",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .pre_save = pic_dispatch_pre_save,
-    .post_load = pic_dispatch_post_load,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT8(last_irr, PICCommonState),
-        VMSTATE_UINT8(irr, PICCommonState),
-        VMSTATE_UINT8(imr, PICCommonState),
-        VMSTATE_UINT8(isr, PICCommonState),
-        VMSTATE_UINT8(priority_add, PICCommonState),
-        VMSTATE_UINT8(irq_base, PICCommonState),
-        VMSTATE_UINT8(read_reg_select, PICCommonState),
-        VMSTATE_UINT8(poll, PICCommonState),
-        VMSTATE_UINT8(special_mask, PICCommonState),
-        VMSTATE_UINT8(init_state, PICCommonState),
-        VMSTATE_UINT8(auto_eoi, PICCommonState),
-        VMSTATE_UINT8(rotate_on_auto_eoi, PICCommonState),
-        VMSTATE_UINT8(special_fully_nested_mode, PICCommonState),
-        VMSTATE_UINT8(init4, PICCommonState),
-        VMSTATE_UINT8(single_mode, PICCommonState),
-        VMSTATE_UINT8(elcr, PICCommonState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static Property pic_properties_common[] = {
-    DEFINE_PROP_HEX32("iobase", PICCommonState, iobase,  -1),
-    DEFINE_PROP_HEX32("elcr_addr", PICCommonState, elcr_addr,  -1),
-    DEFINE_PROP_HEX8("elcr_mask", PICCommonState, elcr_mask,  -1),
-    DEFINE_PROP_BIT("master", PICCommonState, master,  0, false),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void pic_common_class_init(ObjectClass *klass, void *data)
-{
-    ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
-    DeviceClass *dc = DEVICE_CLASS(klass);
-
-    dc->vmsd = &vmstate_pic_common;
-    dc->no_user = 1;
-    dc->props = pic_properties_common;
-    ic->init = pic_init_common;
-}
-
-static const 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_types(void)
-{
-    type_register_static(&pic_common_type);
-}
-
-type_init(register_types);
diff --git a/hw/i8259_internal.h b/hw/i8259_internal.h
deleted file mode 100644 (file)
index 2813ec1..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * 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/hw.h"
-#include "hw/pc.h"
-#include "hw/isa.h"
-
-typedef struct PICCommonState PICCommonState;
-
-#define TYPE_PIC_COMMON "pic-common"
-#define PIC_COMMON(obj) \
-     OBJECT_CHECK(PICCommonState, (obj), TYPE_PIC_COMMON)
-#define PIC_COMMON_CLASS(klass) \
-     OBJECT_CLASS_CHECK(PICCommonClass, (klass), TYPE_PIC_COMMON)
-#define PIC_COMMON_GET_CLASS(obj) \
-     OBJECT_GET_CLASS(PICCommonClass, (obj), TYPE_PIC_COMMON)
-
-typedef struct PICCommonClass
-{
-    ISADeviceClass parent_class;
-    void (*init)(PICCommonState *s);
-    void (*pre_save)(PICCommonState *s);
-    void (*post_load)(PICCommonState *s);
-} PICCommonClass;
-
-struct PICCommonState {
-    ISADevice dev;
-    uint8_t last_irr; /* edge detection */
-    uint8_t irr; /* interrupt request register */
-    uint8_t imr; /* interrupt mask register */
-    uint8_t isr; /* interrupt service register */
-    uint8_t priority_add; /* highest irq priority */
-    uint8_t irq_base;
-    uint8_t read_reg_select;
-    uint8_t poll;
-    uint8_t special_mask;
-    uint8_t init_state;
-    uint8_t auto_eoi;
-    uint8_t rotate_on_auto_eoi;
-    uint8_t special_fully_nested_mode;
-    uint8_t init4; /* true if 4 byte init */
-    uint8_t single_mode; /* true if slave pic is not initialized */
-    uint8_t elcr; /* PIIX edge/trigger selection*/
-    uint8_t elcr_mask;
-    qemu_irq int_out[1];
-    uint32_t master; /* reflects /SP input pin */
-    uint32_t iobase;
-    uint32_t elcr_addr;
-    MemoryRegion base_io;
-    MemoryRegion elcr_io;
-};
-
-void pic_reset_common(PICCommonState *s);
-
-ISADevice *i8259_init_chip(const char *name, ISABus *bus, bool master);
-
-
-#endif /* !QEMU_I8259_INTERNAL_H */
diff --git a/hw/i82801b11.c b/hw/i82801b11.c
deleted file mode 100644 (file)
index 8b4a9c6..0000000
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright (c) 2006 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.
- */
-/*
- * QEMU i82801b11 dmi-to-pci Bridge Emulation
- *
- *  Copyright (c) 2009, 2010, 2011
- *                Isaku Yamahata <yamahata at valinux co jp>
- *                VA Linux Systems Japan K.K.
- *  Copyright (C) 2012 Jason Baron <jbaron@redhat.com>
- *
- * 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/pci/pci.h"
-#include "hw/ich9.h"
-
-
-/*****************************************************************************/
-/* ICH9 DMI-to-PCI bridge */
-#define I82801ba_SSVID_OFFSET   0x50
-#define I82801ba_SSVID_SVID     0
-#define I82801ba_SSVID_SSID     0
-
-typedef struct I82801b11Bridge {
-    PCIBridge br;
-} I82801b11Bridge;
-
-static int i82801b11_bridge_initfn(PCIDevice *d)
-{
-    int rc;
-
-    rc = pci_bridge_initfn(d, TYPE_PCI_BUS);
-    if (rc < 0) {
-        return rc;
-    }
-
-    rc = pci_bridge_ssvid_init(d, I82801ba_SSVID_OFFSET,
-                               I82801ba_SSVID_SVID, I82801ba_SSVID_SSID);
-    if (rc < 0) {
-        goto err_bridge;
-    }
-    pci_config_set_prog_interface(d->config, PCI_CLASS_BRDIGE_PCI_INF_SUB);
-    return 0;
-
-err_bridge:
-    pci_bridge_exitfn(d);
-
-    return rc;
-}
-
-static void i82801b11_bridge_class_init(ObjectClass *klass, void *data)
-{
-    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
-    k->is_bridge = 1;
-    k->vendor_id = PCI_VENDOR_ID_INTEL;
-    k->device_id = PCI_DEVICE_ID_INTEL_82801BA_11;
-    k->revision = ICH9_D2P_A2_REVISION;
-    k->init = i82801b11_bridge_initfn;
-}
-
-static const TypeInfo i82801b11_bridge_info = {
-    .name          = "i82801b11-bridge",
-    .parent        = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(I82801b11Bridge),
-    .class_init    = i82801b11_bridge_class_init,
-};
-
-PCIBus *ich9_d2pbr_init(PCIBus *bus, int devfn, int sec_bus)
-{
-    PCIDevice *d;
-    PCIBridge *br;
-    char buf[16];
-    DeviceState *qdev;
-
-    d = pci_create_multifunction(bus, devfn, true, "i82801b11-bridge");
-    if (!d) {
-        return NULL;
-    }
-    br = DO_UPCAST(PCIBridge, dev, d);
-    qdev = &br->dev.qdev;
-
-    snprintf(buf, sizeof(buf), "pci.%d", sec_bus);
-    pci_bridge_map_irq(br, buf, pci_swizzle_map_irq_fn);
-    qdev_init_nofail(qdev);
-
-    return pci_bridge_get_sec_bus(br);
-}
-
-static void d2pbr_register(void)
-{
-    type_register_static(&i82801b11_bridge_info);
-}
-
-type_init(d2pbr_register);
diff --git a/hw/ich9.h b/hw/ich9.h
deleted file mode 100644 (file)
index e7d2df7..0000000
--- a/hw/ich9.h
+++ /dev/null
@@ -1,220 +0,0 @@
-#ifndef HW_ICH9_H
-#define HW_ICH9_H
-
-#include "hw/hw.h"
-#include "qemu/range.h"
-#include "hw/isa.h"
-#include "hw/sysbus.h"
-#include "hw/pc.h"
-#include "hw/apm.h"
-#include "hw/ioapic.h"
-#include "hw/pci/pci.h"
-#include "hw/pci/pcie_host.h"
-#include "hw/pci/pci_bridge.h"
-#include "hw/acpi.h"
-#include "hw/acpi_ich9.h"
-#include "hw/pam.h"
-#include "hw/pci/pci_bus.h"
-
-void ich9_lpc_set_irq(void *opaque, int irq_num, int level);
-int ich9_lpc_map_irq(PCIDevice *pci_dev, int intx);
-PCIINTxRoute ich9_route_intx_pin_to_irq(void *opaque, int pirq_pin);
-void ich9_lpc_pm_init(PCIDevice *pci_lpc, qemu_irq cmos_s3);
-PCIBus *ich9_d2pbr_init(PCIBus *bus, int devfn, int sec_bus);
-i2c_bus *ich9_smb_init(PCIBus *bus, int devfn, uint32_t smb_io_base);
-
-#define ICH9_CC_SIZE                            (16 * 1024)     /* 16KB */
-
-#define TYPE_ICH9_LPC_DEVICE "ICH9 LPC"
-#define ICH9_LPC_DEVICE(obj) \
-     OBJECT_CHECK(ICH9LPCState, (obj), TYPE_ICH9_LPC_DEVICE)
-
-typedef struct ICH9LPCState {
-    /* ICH9 LPC PCI to ISA bridge */
-    PCIDevice d;
-
-    /* (pci device, intx) -> pirq
-     * In real chipset case, the unused slots are never used
-     * as ICH9 supports only D25-D32 irq routing.
-     * On the other hand in qemu case, any slot/function can be populated
-     * via command line option.
-     * So fallback interrupt routing for any devices in any slots is necessary.
-    */
-    uint8_t irr[PCI_SLOT_MAX][PCI_NUM_PINS];
-
-    APMState apm;
-    ICH9LPCPMRegs pm;
-    uint32_t sci_level; /* track sci level */
-
-    /* 10.1 Chipset Configuration registers(Memory Space)
-     which is pointed by RCBA */
-    uint8_t chip_config[ICH9_CC_SIZE];
-
-    /*
-     * 13.7.5 RST_CNT---Reset Control Register (LPC I/F---D31:F0)
-     *
-     * register contents and IO memory region
-     */
-    uint8_t rst_cnt;
-    MemoryRegion rst_cnt_mem;
-
-    /* isa bus */
-    ISABus *isa_bus;
-    MemoryRegion rbca_mem;
-    Notifier machine_ready;
-
-    qemu_irq *pic;
-    qemu_irq *ioapic;
-} ICH9LPCState;
-
-#define Q35_MASK(bit, ms_bit, ls_bit) \
-((uint##bit##_t)(((1ULL << ((ms_bit) + 1)) - 1) & ~((1ULL << ls_bit) - 1)))
-
-/* ICH9: Chipset Configuration Registers */
-#define ICH9_CC_ADDR_MASK                       (ICH9_CC_SIZE - 1)
-
-#define ICH9_CC
-#define ICH9_CC_D28IP                           0x310C
-#define ICH9_CC_D28IP_SHIFT                     4
-#define ICH9_CC_D28IP_MASK                      0xf
-#define ICH9_CC_D28IP_DEFAULT                   0x00214321
-#define ICH9_CC_D31IR                           0x3140
-#define ICH9_CC_D30IR                           0x3142
-#define ICH9_CC_D29IR                           0x3144
-#define ICH9_CC_D28IR                           0x3146
-#define ICH9_CC_D27IR                           0x3148
-#define ICH9_CC_D26IR                           0x314C
-#define ICH9_CC_D25IR                           0x3150
-#define ICH9_CC_DIR_DEFAULT                     0x3210
-#define ICH9_CC_D30IR_DEFAULT                   0x0
-#define ICH9_CC_DIR_SHIFT                       4
-#define ICH9_CC_DIR_MASK                        0x7
-#define ICH9_CC_OIC                             0x31FF
-#define ICH9_CC_OIC_AEN                         0x1
-
-/* D28:F[0-5] */
-#define ICH9_PCIE_DEV                           28
-#define ICH9_PCIE_FUNC_MAX                      6
-
-
-/* D29:F0 USB UHCI Controller #1 */
-#define ICH9_USB_UHCI1_DEV                      29
-#define ICH9_USB_UHCI1_FUNC                     0
-
-/* D30:F0 DMI-to-PCI brdige */
-#define ICH9_D2P_BRIDGE                         "ICH9 D2P BRIDGE"
-#define ICH9_D2P_BRIDGE_SAVEVM_VERSION          0
-
-#define ICH9_D2P_BRIDGE_DEV                     30
-#define ICH9_D2P_BRIDGE_FUNC                    0
-
-#define ICH9_D2P_SECONDARY_DEFAULT              (256 - 8)
-
-#define ICH9_D2P_A2_REVISION                    0x92
-
-/* D31:F0 LPC Processor Interface */
-#define ICH9_RST_CNT_IOPORT                     0xCF9
-
-/* D31:F1 LPC controller */
-#define ICH9_A2_LPC                             "ICH9 A2 LPC"
-#define ICH9_A2_LPC_SAVEVM_VERSION              0
-
-#define ICH9_LPC_DEV                            31
-#define ICH9_LPC_FUNC                           0
-
-#define ICH9_A2_LPC_REVISION                    0x2
-#define ICH9_LPC_NB_PIRQS                       8       /* PCI A-H */
-
-#define ICH9_LPC_PMBASE                         0x40
-#define ICH9_LPC_PMBASE_BASE_ADDRESS_MASK       Q35_MASK(32, 15, 7)
-#define ICH9_LPC_PMBASE_RTE                     0x1
-#define ICH9_LPC_PMBASE_DEFAULT                 0x1
-#define ICH9_LPC_ACPI_CTRL                      0x44
-#define ICH9_LPC_ACPI_CTRL_ACPI_EN              0x80
-#define ICH9_LPC_ACPI_CTRL_SCI_IRQ_SEL_MASK     Q35_MASK(8, 2, 0)
-#define ICH9_LPC_ACPI_CTRL_9                    0x0
-#define ICH9_LPC_ACPI_CTRL_10                   0x1
-#define ICH9_LPC_ACPI_CTRL_11                   0x2
-#define ICH9_LPC_ACPI_CTRL_20                   0x4
-#define ICH9_LPC_ACPI_CTRL_21                   0x5
-#define ICH9_LPC_ACPI_CTRL_DEFAULT              0x0
-
-#define ICH9_LPC_PIRQA_ROUT                     0x60
-#define ICH9_LPC_PIRQB_ROUT                     0x61
-#define ICH9_LPC_PIRQC_ROUT                     0x62
-#define ICH9_LPC_PIRQD_ROUT                     0x63
-
-#define ICH9_LPC_PIRQE_ROUT                     0x68
-#define ICH9_LPC_PIRQF_ROUT                     0x69
-#define ICH9_LPC_PIRQG_ROUT                     0x6a
-#define ICH9_LPC_PIRQH_ROUT                     0x6b
-
-#define ICH9_LPC_PIRQ_ROUT_IRQEN                0x80
-#define ICH9_LPC_PIRQ_ROUT_MASK                 Q35_MASK(8, 3, 0)
-#define ICH9_LPC_PIRQ_ROUT_DEFAULT              0x80
-
-#define ICH9_LPC_RCBA                           0xf0
-#define ICH9_LPC_RCBA_BA_MASK                   Q35_MASK(32, 31, 14)
-#define ICH9_LPC_RCBA_EN                        0x1
-#define ICH9_LPC_RCBA_DEFAULT                   0x0
-
-#define ICH9_LPC_PIC_NUM_PINS                   16
-#define ICH9_LPC_IOAPIC_NUM_PINS                24
-
-/* D31:F2 SATA Controller #1 */
-#define ICH9_SATA1_DEV                          31
-#define ICH9_SATA1_FUNC                         2
-
-/* D30:F1 power management I/O registers
-   offset from the address ICH9_LPC_PMBASE */
-
-/* ICH9 LPC PM I/O registers are 128 ports and 128-aligned */
-#define ICH9_PMIO_SIZE                          128
-#define ICH9_PMIO_MASK                          (ICH9_PMIO_SIZE - 1)
-
-#define ICH9_PMIO_PM1_STS                       0x00
-#define ICH9_PMIO_PM1_EN                        0x02
-#define ICH9_PMIO_PM1_CNT                       0x04
-#define ICH9_PMIO_PM1_TMR                       0x08
-#define ICH9_PMIO_GPE0_STS                      0x20
-#define ICH9_PMIO_GPE0_EN                       0x28
-#define ICH9_PMIO_GPE0_LEN                      16
-#define ICH9_PMIO_SMI_EN                        0x30
-#define ICH9_PMIO_SMI_EN_APMC_EN                (1 << 5)
-#define ICH9_PMIO_SMI_STS                       0x34
-
-/* FADT ACPI_ENABLE/ACPI_DISABLE */
-#define ICH9_APM_ACPI_ENABLE                    0x2
-#define ICH9_APM_ACPI_DISABLE                   0x3
-
-
-/* D31:F3 SMBus controller */
-#define ICH9_A2_SMB_REVISION                    0x02
-#define ICH9_SMB_PI                             0x00
-
-#define ICH9_SMB_SMBMBAR0                       0x10
-#define ICH9_SMB_SMBMBAR1                       0x14
-#define ICH9_SMB_SMBM_BAR                       0
-#define ICH9_SMB_SMBM_SIZE                      (1 << 8)
-#define ICH9_SMB_SMB_BASE                       0x20
-#define ICH9_SMB_SMB_BASE_BAR                   4
-#define ICH9_SMB_SMB_BASE_SIZE                  (1 << 5)
-#define ICH9_SMB_HOSTC                          0x40
-#define ICH9_SMB_HOSTC_SSRESET                  ((uint8_t)(1 << 3))
-#define ICH9_SMB_HOSTC_I2C_EN                   ((uint8_t)(1 << 2))
-#define ICH9_SMB_HOSTC_SMB_SMI_EN               ((uint8_t)(1 << 1))
-#define ICH9_SMB_HOSTC_HST_EN                   ((uint8_t)(1 << 0))
-
-/* D31:F3 SMBus I/O and memory mapped I/O registers */
-#define ICH9_SMB_DEV                            31
-#define ICH9_SMB_FUNC                           3
-
-#define ICH9_SMB_HST_STS                        0x00
-#define ICH9_SMB_HST_CNT                        0x02
-#define ICH9_SMB_HST_CMD                        0x03
-#define ICH9_SMB_XMIT_SLVA                      0x04
-#define ICH9_SMB_HST_D0                         0x05
-#define ICH9_SMB_HST_D1                         0x06
-#define ICH9_SMB_HOST_BLOCK_DB                  0x07
-
-#endif /* HW_ICH9_H */
diff --git a/hw/ide.h b/hw/ide.h
deleted file mode 100644 (file)
index 35444a3..0000000
--- a/hw/ide.h
+++ /dev/null
@@ -1,32 +0,0 @@
-#ifndef HW_IDE_H
-#define HW_IDE_H
-
-#include "hw/isa.h"
-#include "hw/pci/pci.h"
-#include "exec/memory.h"
-
-#define MAX_IDE_DEVS   2
-
-/* ide-isa.c */
-ISADevice *isa_ide_init(ISABus *bus, int iobase, int iobase2, int isairq,
-                        DriveInfo *hd0, DriveInfo *hd1);
-
-/* ide-pci.c */
-void pci_cmd646_ide_init(PCIBus *bus, DriveInfo **hd_table,
-                         int secondary_ide_enabled);
-PCIDevice *pci_piix3_xen_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn);
-PCIDevice *pci_piix3_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn);
-PCIDevice *pci_piix4_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn);
-void vt82c686b_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn);
-
-/* ide-mmio.c */
-void mmio_ide_init_drives(DeviceState *dev, DriveInfo *hd0, DriveInfo *hd1);
-
-int ide_get_geometry(BusState *bus, int unit,
-                     int16_t *cyls, int8_t *heads, int8_t *secs);
-int ide_get_bios_chs_trans(BusState *bus, int unit);
-
-/* ide/core.c */
-void ide_drive_get(DriveInfo **hd, int max_bus);
-
-#endif /* HW_IDE_H */
index 5c8c22aad7d727f096c9d11384492d4a19a32cbc..729e9bd0db9dc654270b02a501f3d48127f65b43 100644 (file)
@@ -5,6 +5,8 @@ common-obj-$(CONFIG_IDE_ISA) += isa.o
 common-obj-$(CONFIG_IDE_PIIX) += piix.o
 common-obj-$(CONFIG_IDE_CMD646) += cmd646.o
 common-obj-$(CONFIG_IDE_MACIO) += macio.o
+common-obj-$(CONFIG_IDE_MMIO) += mmio.o
 common-obj-$(CONFIG_IDE_VIA) += via.o
+common-obj-$(CONFIG_MICRODRIVE) += microdrive.o
 common-obj-$(CONFIG_AHCI) += ahci.o
 common-obj-$(CONFIG_AHCI) += ich.o
index ad0094f532ef7750f85f3f8bcb43e7ee1cddde8b..d0ae8afba2d47113e9094e0214f936cbd981fc2c 100644 (file)
@@ -23,7 +23,7 @@
 
 #include <hw/hw.h>
 #include <hw/pci/msi.h>
-#include <hw/pc.h>
+#include <hw/i386/pc.h>
 #include <hw/pci/pci.h>
 #include <hw/sysbus.h>
 
index 861fd2bec31d636cc28b936e89e9ceecf269bffe..05e60b1cdce6d1a644b65cd1b75ef7138b776386 100644 (file)
@@ -24,7 +24,7 @@
  */
 
 #include "hw/ide/internal.h"
-#include "hw/scsi.h"
+#include "hw/scsi/scsi.h"
 
 static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret);
 
index 745ef94deb04e79189726b78173c752151d281c4..541d4ef3358c40b87a9b49b629dcee59297d73f3 100644 (file)
@@ -23,9 +23,9 @@
  * THE SOFTWARE.
  */
 #include <hw/hw.h>
-#include <hw/pc.h>
+#include <hw/i386/pc.h>
 #include <hw/pci/pci.h>
-#include <hw/isa.h>
+#include <hw/isa/isa.h>
 #include "block/block.h"
 #include "sysemu/sysemu.h"
 #include "sysemu/dma.h"
index 3743dc3b55e7570cf6f0b45a30206abff5010d89..87d67b7bcbf399cd0cc1ab149612b81f486780c2 100644 (file)
  * THE SOFTWARE.
  */
 #include <hw/hw.h>
-#include <hw/pc.h>
+#include <hw/i386/pc.h>
 #include <hw/pci/pci.h>
-#include <hw/isa.h>
+#include <hw/isa/isa.h>
 #include "qemu/error-report.h"
 #include "qemu/timer.h"
 #include "sysemu/sysemu.h"
 #include "sysemu/dma.h"
-#include "hw/block-common.h"
+#include "hw/block/block.h"
 #include "sysemu/blockdev.h"
 
 #include <hw/ide/internal.h>
index cc30adc701af46e785da0796e172f8dbf26c5b88..ed1f1a287e8978fa8d47c20f6661c8f27f31b17e 100644 (file)
@@ -62,9 +62,9 @@
 
 #include <hw/hw.h>
 #include <hw/pci/msi.h>
-#include <hw/pc.h>
+#include <hw/i386/pc.h>
 #include <hw/pci/pci.h>
-#include <hw/isa.h>
+#include <hw/isa/isa.h>
 #include "block/block.h"
 #include "sysemu/dma.h"
 
index d80360e85bbfaf54d58bafe01071dd013fe3b2f6..2c89b50c5ece5c3bfbaeea19a2cf76a2d725b7ea 100644 (file)
@@ -7,12 +7,12 @@
  * non-internal declarations are in hw/ide.h
  */
 #include <hw/ide.h>
-#include <hw/isa.h>
+#include <hw/isa/isa.h>
 #include "exec/iorange.h"
 #include "sysemu/dma.h"
 #include "sysemu/sysemu.h"
-#include "hw/block-common.h"
-#include "hw/scsi-defs.h"
+#include "hw/block/block.h"
+#include "block/scsi.h"
 
 /* debug IDE devices */
 //#define DEBUG_IDE
index fb7bb8201db3269128fa10900e4851029f4d9782..e0d47bf7cfada983b8b86eade1f712c5e217b00a 100644 (file)
@@ -23,8 +23,8 @@
  * THE SOFTWARE.
  */
 #include <hw/hw.h>
-#include <hw/pc.h>
-#include <hw/isa.h>
+#include <hw/i386/pc.h>
+#include <hw/isa/isa.h>
 #include "block/block.h"
 #include "sysemu/dma.h"
 
index 375c46f9daffc85cffc86a792628e05a9a972d4f..64b2406ab010daf49253da55d700b1cae58a83fa 100644 (file)
@@ -24,7 +24,7 @@
  */
 #include "hw/hw.h"
 #include "hw/ppc/mac.h"
-#include "hw/mac_dbdma.h"
+#include "hw/ppc/mac_dbdma.h"
 #include "block/block.h"
 #include "sysemu/dma.h"
 
index 642774ef98fc16054338c8e897e5c56f8c51dd70..92c1df0460f51b3cdfe7a4680f2fc6eadeb2c757 100644 (file)
@@ -23,7 +23,7 @@
  * THE SOFTWARE.
  */
 #include <hw/hw.h>
-#include <hw/pc.h>
+#include <hw/i386/pc.h>
 #include <hw/pcmcia.h>
 #include "block/block.h"
 #include "sysemu/dma.h"
index 59fd53992a3d2f830be1b67118b3e71ace6bccff..a310975391f6eff7eadbe3f7168d0fd6b32149b4 100644 (file)
@@ -23,9 +23,9 @@
  * THE SOFTWARE.
  */
 #include <hw/hw.h>
-#include <hw/pc.h>
+#include <hw/i386/pc.h>
 #include <hw/pci/pci.h>
-#include <hw/isa.h>
+#include <hw/isa/isa.h>
 #include "block/block.h"
 #include "sysemu/dma.h"
 
index 4d3e82266c3a6ab6f6efca5c06eedd8a43a22b9d..1de284d0e3da3728d95f11472c99c98039e768ac 100644 (file)
@@ -24,9 +24,9 @@
  */
 
 #include <hw/hw.h>
-#include <hw/pc.h>
+#include <hw/i386/pc.h>
 #include <hw/pci/pci.h>
-#include <hw/isa.h>
+#include <hw/isa/isa.h>
 #include "sysemu/blockdev.h"
 #include "sysemu/sysemu.h"
 #include "sysemu/dma.h"
index fd06da7003aac407c19921efe6de9daa59f1c1e4..8a9a89176989b447a89b44302668c4706e6e85a6 100644 (file)
@@ -21,7 +21,7 @@
 #include "qemu/error-report.h"
 #include <hw/ide/internal.h>
 #include "sysemu/blockdev.h"
-#include "hw/block-common.h"
+#include "hw/block/block.h"
 #include "sysemu/sysemu.h"
 
 /* --------------------------------- */
index f40c1adc8cfc9a6937b78b85140f69286a0af97e..9d6a644391a9372e3db1f5f62d92b0837aa64ec5 100644 (file)
@@ -24,9 +24,9 @@
  * THE SOFTWARE.
  */
 #include <hw/hw.h>
-#include <hw/pc.h>
+#include <hw/i386/pc.h>
 #include <hw/pci/pci.h>
-#include <hw/isa.h>
+#include <hw/isa/isa.h>
 #include "block/block.h"
 #include "sysemu/sysemu.h"
 #include "sysemu/dma.h"
diff --git a/hw/imx.h b/hw/imx.h
deleted file mode 100644 (file)
index ea9e093..0000000
--- a/hw/imx.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * i.MX31 emulation
- *
- * Copyright (C) 2012 Peter Chubb
- * NICTA
- *
- * This code is released under the GPL, version 2.0 or later
- * See the file `../COPYING' for details.
- */
-
-#ifndef IMX_H
-#define IMX_H
-
-void imx_serial_create(int uart, const hwaddr addr, qemu_irq irq);
-
-typedef enum  {
-    NOCLK,
-    MCU,
-    HSP,
-    IPG,
-    CLK_32k
-} IMXClk;
-
-uint32_t imx_clock_frequency(DeviceState *s, IMXClk clock);
-
-void imx_timerp_create(const hwaddr addr,
-                      qemu_irq irq,
-                      DeviceState *ccm);
-void imx_timerg_create(const hwaddr addr,
-                      qemu_irq irq,
-                      DeviceState *ccm);
-
-
-#endif /* IMX_H */
diff --git a/hw/imx_avic.c b/hw/imx_avic.c
deleted file mode 100644 (file)
index 4e280b6..0000000
+++ /dev/null
@@ -1,408 +0,0 @@
-/*
- * i.MX31 Vectored Interrupt Controller
- *
- * Note this is NOT the PL192 provided by ARM, but
- * a custom implementation by Freescale.
- *
- * Copyright (c) 2008 OKL
- * Copyright (c) 2011 NICTA Pty Ltd
- * Originally written by Hans Jiang
- *
- * This code is licensed under the GPL version 2 or later.  See
- * the COPYING file in the top-level directory.
- *
- * TODO: implement vectors.
- */
-
-#include "hw/hw.h"
-#include "hw/sysbus.h"
-#include "qemu/host-utils.h"
-
-#define DEBUG_INT 1
-#undef DEBUG_INT /* comment out for debugging */
-
-#ifdef DEBUG_INT
-#define DPRINTF(fmt, args...) \
-do { printf("imx_avic: " fmt , ##args); } while (0)
-#else
-#define DPRINTF(fmt, args...) do {} while (0)
-#endif
-
-/*
- * Define to 1 for messages about attempts to
- * access unimplemented registers or similar.
- */
-#define DEBUG_IMPLEMENTATION 1
-#if DEBUG_IMPLEMENTATION
-#  define IPRINTF(fmt, args...) \
-    do  { fprintf(stderr, "imx_avic: " fmt, ##args); } while (0)
-#else
-#  define IPRINTF(fmt, args...) do {} while (0)
-#endif
-
-#define IMX_AVIC_NUM_IRQS 64
-
-/* Interrupt Control Bits */
-#define ABFLAG (1<<25)
-#define ABFEN (1<<24)
-#define NIDIS (1<<22) /* Normal Interrupt disable */
-#define FIDIS (1<<21) /* Fast interrupt disable */
-#define NIAD  (1<<20) /* Normal Interrupt Arbiter Rise ARM level */
-#define FIAD  (1<<19) /* Fast Interrupt Arbiter Rise ARM level */
-#define NM    (1<<18) /* Normal interrupt mode */
-
-
-#define PRIO_PER_WORD (sizeof(uint32_t) * 8 / 4)
-#define PRIO_WORDS (IMX_AVIC_NUM_IRQS/PRIO_PER_WORD)
-
-typedef struct {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-    uint64_t pending;
-    uint64_t enabled;
-    uint64_t is_fiq;
-    uint32_t intcntl;
-    uint32_t intmask;
-    qemu_irq irq;
-    qemu_irq fiq;
-    uint32_t prio[PRIO_WORDS]; /* Priorities are 4-bits each */
-} IMXAVICState;
-
-static const VMStateDescription vmstate_imx_avic = {
-    .name = "imx-avic",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT64(pending, IMXAVICState),
-        VMSTATE_UINT64(enabled, IMXAVICState),
-        VMSTATE_UINT64(is_fiq, IMXAVICState),
-        VMSTATE_UINT32(intcntl, IMXAVICState),
-        VMSTATE_UINT32(intmask, IMXAVICState),
-        VMSTATE_UINT32_ARRAY(prio, IMXAVICState, PRIO_WORDS),
-        VMSTATE_END_OF_LIST()
-    },
-};
-
-
-
-static inline int imx_avic_prio(IMXAVICState *s, int irq)
-{
-    uint32_t word = irq / PRIO_PER_WORD;
-    uint32_t part = 4 * (irq % PRIO_PER_WORD);
-    return 0xf & (s->prio[word] >> part);
-}
-
-static inline void imx_avic_set_prio(IMXAVICState *s, int irq, int prio)
-{
-    uint32_t word = irq / PRIO_PER_WORD;
-    uint32_t part = 4 * (irq % PRIO_PER_WORD);
-    uint32_t mask = ~(0xf << part);
-    s->prio[word] &= mask;
-    s->prio[word] |= prio << part;
-}
-
-/* Update interrupts.  */
-static void imx_avic_update(IMXAVICState *s)
-{
-    int i;
-    uint64_t new = s->pending & s->enabled;
-    uint64_t flags;
-
-    flags = new & s->is_fiq;
-    qemu_set_irq(s->fiq, !!flags);
-
-    flags = new & ~s->is_fiq;
-    if (!flags || (s->intmask == 0x1f)) {
-        qemu_set_irq(s->irq, !!flags);
-        return;
-    }
-
-    /*
-     * Take interrupt if there's a pending interrupt with
-     * priority higher than the value of intmask
-     */
-    for (i = 0; i < IMX_AVIC_NUM_IRQS; i++) {
-        if (flags & (1UL << i)) {
-            if (imx_avic_prio(s, i) > s->intmask) {
-                qemu_set_irq(s->irq, 1);
-                return;
-            }
-        }
-    }
-    qemu_set_irq(s->irq, 0);
-}
-
-static void imx_avic_set_irq(void *opaque, int irq, int level)
-{
-    IMXAVICState *s = (IMXAVICState *)opaque;
-
-    if (level) {
-        DPRINTF("Raising IRQ %d, prio %d\n",
-                irq, imx_avic_prio(s, irq));
-        s->pending |= (1ULL << irq);
-    } else {
-        DPRINTF("Clearing IRQ %d, prio %d\n",
-                irq, imx_avic_prio(s, irq));
-        s->pending &= ~(1ULL << irq);
-    }
-
-    imx_avic_update(s);
-}
-
-
-static uint64_t imx_avic_read(void *opaque,
-                             hwaddr offset, unsigned size)
-{
-    IMXAVICState *s = (IMXAVICState *)opaque;
-
-
-    DPRINTF("read(offset = 0x%x)\n", offset >> 2);
-    switch (offset >> 2) {
-    case 0: /* INTCNTL */
-        return s->intcntl;
-
-    case 1: /* Normal Interrupt Mask Register, NIMASK */
-        return s->intmask;
-
-    case 2: /* Interrupt Enable Number Register, INTENNUM */
-    case 3: /* Interrupt Disable Number Register, INTDISNUM */
-        return 0;
-
-    case 4: /* Interrupt Enabled Number Register High */
-        return s->enabled >> 32;
-
-    case 5: /* Interrupt Enabled Number Register Low */
-        return s->enabled & 0xffffffffULL;
-
-    case 6: /* Interrupt Type Register High */
-        return s->is_fiq >> 32;
-
-    case 7: /* Interrupt Type Register Low */
-        return s->is_fiq & 0xffffffffULL;
-
-    case 8: /* Normal Interrupt Priority Register 7 */
-    case 9: /* Normal Interrupt Priority Register 6 */
-    case 10:/* Normal Interrupt Priority Register 5 */
-    case 11:/* Normal Interrupt Priority Register 4 */
-    case 12:/* Normal Interrupt Priority Register 3 */
-    case 13:/* Normal Interrupt Priority Register 2 */
-    case 14:/* Normal Interrupt Priority Register 1 */
-    case 15:/* Normal Interrupt Priority Register 0 */
-        return s->prio[15-(offset>>2)];
-
-    case 16: /* Normal interrupt vector and status register */
-    {
-        /*
-         * This returns the highest priority
-         * outstanding interrupt.  Where there is more than
-         * one pending IRQ with the same priority,
-         * take the highest numbered one.
-         */
-        uint64_t flags = s->pending & s->enabled & ~s->is_fiq;
-        int i;
-        int prio = -1;
-        int irq = -1;
-        for (i = 63; i >= 0; --i) {
-            if (flags & (1ULL<<i)) {
-                int irq_prio = imx_avic_prio(s, i);
-                if (irq_prio > prio) {
-                    irq = i;
-                    prio = irq_prio;
-                }
-            }
-        }
-        if (irq >= 0) {
-            imx_avic_set_irq(s, irq, 0);
-            return irq << 16 | prio;
-        }
-        return 0xffffffffULL;
-    }
-    case 17:/* Fast Interrupt vector and status register */
-    {
-        uint64_t flags = s->pending & s->enabled & s->is_fiq;
-        int i = ctz64(flags);
-        if (i < 64) {
-            imx_avic_set_irq(opaque, i, 0);
-            return i;
-        }
-        return 0xffffffffULL;
-    }
-    case 18:/* Interrupt source register high */
-        return s->pending >> 32;
-
-    case 19:/* Interrupt source register low */
-        return s->pending & 0xffffffffULL;
-
-    case 20:/* Interrupt Force Register high */
-    case 21:/* Interrupt Force Register low */
-        return 0;
-
-    case 22:/* Normal Interrupt Pending Register High */
-        return (s->pending & s->enabled & ~s->is_fiq) >> 32;
-
-    case 23:/* Normal Interrupt Pending Register Low */
-        return (s->pending & s->enabled & ~s->is_fiq) & 0xffffffffULL;
-
-    case 24: /* Fast Interrupt Pending Register High  */
-        return (s->pending & s->enabled & s->is_fiq) >> 32;
-
-    case 25: /* Fast Interrupt Pending Register Low  */
-        return (s->pending & s->enabled & s->is_fiq) & 0xffffffffULL;
-
-    case 0x40:            /* AVIC vector 0, use for WFI WAR */
-        return 0x4;
-
-    default:
-        IPRINTF("imx_avic_read: Bad offset 0x%x\n", (int)offset);
-        return 0;
-    }
-}
-
-static void imx_avic_write(void *opaque, hwaddr offset,
-                          uint64_t val, unsigned size)
-{
-    IMXAVICState *s = (IMXAVICState *)opaque;
-
-    /* Vector Registers not yet supported */
-    if (offset >= 0x100 && offset <= 0x2fc) {
-        IPRINTF("imx_avic_write to vector register %d ignored\n",
-                (unsigned int)((offset - 0x100) >> 2));
-        return;
-    }
-
-    DPRINTF("imx_avic_write(0x%x) = %x\n",
-            (unsigned int)offset>>2, (unsigned int)val);
-    switch (offset >> 2) {
-    case 0: /* Interrupt Control Register, INTCNTL */
-        s->intcntl = val & (ABFEN | NIDIS | FIDIS | NIAD | FIAD | NM);
-        if (s->intcntl & ABFEN) {
-            s->intcntl &= ~(val & ABFLAG);
-        }
-        break;
-
-    case 1: /* Normal Interrupt Mask Register, NIMASK */
-        s->intmask = val & 0x1f;
-        break;
-
-    case 2: /* Interrupt Enable Number Register, INTENNUM */
-        DPRINTF("enable(%d)\n", (int)val);
-        val &= 0x3f;
-        s->enabled |= (1ULL << val);
-        break;
-
-    case 3: /* Interrupt Disable Number Register, INTDISNUM */
-        DPRINTF("disable(%d)\n", (int)val);
-        val &= 0x3f;
-        s->enabled &= ~(1ULL << val);
-        break;
-
-    case 4: /* Interrupt Enable Number Register High */
-        s->enabled = (s->enabled & 0xffffffffULL) | (val << 32);
-        break;
-
-    case 5: /* Interrupt Enable Number Register Low */
-        s->enabled = (s->enabled & 0xffffffff00000000ULL) | val;
-        break;
-
-    case 6: /* Interrupt Type Register High */
-        s->is_fiq = (s->is_fiq & 0xffffffffULL) | (val << 32);
-        break;
-
-    case 7: /* Interrupt Type Register Low */
-        s->is_fiq = (s->is_fiq & 0xffffffff00000000ULL) | val;
-        break;
-
-    case 8: /* Normal Interrupt Priority Register 7 */
-    case 9: /* Normal Interrupt Priority Register 6 */
-    case 10:/* Normal Interrupt Priority Register 5 */
-    case 11:/* Normal Interrupt Priority Register 4 */
-    case 12:/* Normal Interrupt Priority Register 3 */
-    case 13:/* Normal Interrupt Priority Register 2 */
-    case 14:/* Normal Interrupt Priority Register 1 */
-    case 15:/* Normal Interrupt Priority Register 0 */
-        s->prio[15-(offset>>2)] = val;
-        break;
-
-        /* Read-only registers, writes ignored */
-    case 16:/* Normal Interrupt Vector and Status register */
-    case 17:/* Fast Interrupt vector and status register */
-    case 18:/* Interrupt source register high */
-    case 19:/* Interrupt source register low */
-        return;
-
-    case 20:/* Interrupt Force Register high */
-        s->pending = (s->pending & 0xffffffffULL) | (val << 32);
-        break;
-
-    case 21:/* Interrupt Force Register low */
-        s->pending = (s->pending & 0xffffffff00000000ULL) | val;
-        break;
-
-    case 22:/* Normal Interrupt Pending Register High */
-    case 23:/* Normal Interrupt Pending Register Low */
-    case 24: /* Fast Interrupt Pending Register High  */
-    case 25: /* Fast Interrupt Pending Register Low  */
-        return;
-
-    default:
-        IPRINTF("imx_avic_write: Bad offset %x\n", (int)offset);
-    }
-    imx_avic_update(s);
-}
-
-static const MemoryRegionOps imx_avic_ops = {
-    .read = imx_avic_read,
-    .write = imx_avic_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void imx_avic_reset(DeviceState *dev)
-{
-    IMXAVICState *s = container_of(dev, IMXAVICState, busdev.qdev);
-    s->pending = 0;
-    s->enabled = 0;
-    s->is_fiq = 0;
-    s->intmask = 0x1f;
-    s->intcntl = 0;
-    memset(s->prio, 0, sizeof s->prio);
-}
-
-static int imx_avic_init(SysBusDevice *dev)
-{
-    IMXAVICState *s = FROM_SYSBUS(IMXAVICState, dev);;
-
-    memory_region_init_io(&s->iomem, &imx_avic_ops, s, "imx_avic", 0x1000);
-    sysbus_init_mmio(dev, &s->iomem);
-
-    qdev_init_gpio_in(&dev->qdev, imx_avic_set_irq, IMX_AVIC_NUM_IRQS);
-    sysbus_init_irq(dev, &s->irq);
-    sysbus_init_irq(dev, &s->fiq);
-
-    return 0;
-}
-
-
-static void imx_avic_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-    k->init = imx_avic_init;
-    dc->vmsd = &vmstate_imx_avic;
-    dc->reset = imx_avic_reset;
-    dc->desc = "i.MX Advanced Vector Interrupt Controller";
-}
-
-static const TypeInfo imx_avic_info = {
-    .name = "imx_avic",
-    .parent = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(IMXAVICState),
-    .class_init = imx_avic_class_init,
-};
-
-static void imx_avic_register_types(void)
-{
-    type_register_static(&imx_avic_info);
-}
-
-type_init(imx_avic_register_types)
diff --git a/hw/imx_ccm.c b/hw/imx_ccm.c
deleted file mode 100644 (file)
index ad7aad3..0000000
+++ /dev/null
@@ -1,321 +0,0 @@
-/*
- * IMX31 Clock Control Module
- *
- * Copyright (C) 2012 NICTA
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- *
- * To get the timer frequencies right, we need to emulate at least part of
- * the CCM.
- */
-
-#include "hw/hw.h"
-#include "hw/sysbus.h"
-#include "sysemu/sysemu.h"
-#include "hw/imx.h"
-
-#define CKIH_FREQ 26000000 /* 26MHz crystal input */
-#define CKIL_FREQ    32768 /* nominal 32khz clock */
-
-
-//#define DEBUG_CCM 1
-#ifdef DEBUG_CCM
-#define DPRINTF(fmt, args...) \
-do { printf("imx_ccm: " fmt , ##args); } while (0)
-#else
-#define DPRINTF(fmt, args...) do {} while (0)
-#endif
-
-static int imx_ccm_post_load(void *opaque, int version_id);
-
-typedef struct {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-
-    uint32_t ccmr;
-    uint32_t pdr0;
-    uint32_t pdr1;
-    uint32_t mpctl;
-    uint32_t spctl;
-    uint32_t cgr[3];
-    uint32_t pmcr0;
-    uint32_t pmcr1;
-
-    /* Frequencies precalculated on register changes */
-    uint32_t pll_refclk_freq;
-    uint32_t mcu_clk_freq;
-    uint32_t hsp_clk_freq;
-    uint32_t ipg_clk_freq;
-} IMXCCMState;
-
-static const VMStateDescription vmstate_imx_ccm = {
-    .name = "imx-ccm",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT32(ccmr, IMXCCMState),
-        VMSTATE_UINT32(pdr0, IMXCCMState),
-        VMSTATE_UINT32(pdr1, IMXCCMState),
-        VMSTATE_UINT32(mpctl, IMXCCMState),
-        VMSTATE_UINT32(spctl, IMXCCMState),
-        VMSTATE_UINT32_ARRAY(cgr, IMXCCMState, 3),
-        VMSTATE_UINT32(pmcr0, IMXCCMState),
-        VMSTATE_UINT32(pmcr1, IMXCCMState),
-        VMSTATE_UINT32(pll_refclk_freq, IMXCCMState),
-    },
-    .post_load = imx_ccm_post_load,
-};
-
-/* CCMR */
-#define CCMR_FPME (1<<0)
-#define CCMR_MPE  (1<<3)
-#define CCMR_MDS  (1<<7)
-#define CCMR_FPMF (1<<26)
-#define CCMR_PRCS (3<<1)
-
-/* PDR0 */
-#define PDR0_MCU_PODF_SHIFT (0)
-#define PDR0_MCU_PODF_MASK (0x7)
-#define PDR0_MAX_PODF_SHIFT (3)
-#define PDR0_MAX_PODF_MASK (0x7)
-#define PDR0_IPG_PODF_SHIFT (6)
-#define PDR0_IPG_PODF_MASK (0x3)
-#define PDR0_NFC_PODF_SHIFT (8)
-#define PDR0_NFC_PODF_MASK (0x7)
-#define PDR0_HSP_PODF_SHIFT (11)
-#define PDR0_HSP_PODF_MASK (0x7)
-#define PDR0_PER_PODF_SHIFT (16)
-#define PDR0_PER_PODF_MASK (0x1f)
-#define PDR0_CSI_PODF_SHIFT (23)
-#define PDR0_CSI_PODF_MASK (0x1ff)
-
-#define EXTRACT(value, name) (((value) >> PDR0_##name##_PODF_SHIFT) \
-                              & PDR0_##name##_PODF_MASK)
-#define INSERT(value, name) (((value) & PDR0_##name##_PODF_MASK) << \
-                             PDR0_##name##_PODF_SHIFT)
-/* PLL control registers */
-#define PD(v) (((v) >> 26) & 0xf)
-#define MFD(v) (((v) >> 16) & 0x3ff)
-#define MFI(v) (((v) >> 10) & 0xf);
-#define MFN(v) ((v) & 0x3ff)
-
-#define PLL_PD(x)               (((x) & 0xf) << 26)
-#define PLL_MFD(x)              (((x) & 0x3ff) << 16)
-#define PLL_MFI(x)              (((x) & 0xf) << 10)
-#define PLL_MFN(x)              (((x) & 0x3ff) << 0)
-
-uint32_t imx_clock_frequency(DeviceState *dev, IMXClk clock)
-{
-    IMXCCMState *s = container_of(dev, IMXCCMState, busdev.qdev);
-
-    switch (clock) {
-    case NOCLK:
-        return 0;
-    case MCU:
-        return s->mcu_clk_freq;
-    case HSP:
-        return s->hsp_clk_freq;
-    case IPG:
-        return s->ipg_clk_freq;
-    case CLK_32k:
-        return CKIL_FREQ;
-    }
-    return 0;
-}
-
-/*
- * Calculate PLL output frequency
- */
-static uint32_t calc_pll(uint32_t pllreg, uint32_t base_freq)
-{
-    int32_t mfn = MFN(pllreg);  /* Numerator */
-    uint32_t mfi = MFI(pllreg); /* Integer part */
-    uint32_t mfd = 1 + MFD(pllreg); /* Denominator */
-    uint32_t pd = 1 + PD(pllreg);   /* Pre-divider */
-
-    if (mfi < 5) {
-        mfi = 5;
-    }
-    /* mfn is 10-bit signed twos-complement */
-    mfn <<= 32 - 10;
-    mfn >>= 32 - 10;
-
-    return ((2 * (base_freq >> 10) * (mfi * mfd + mfn)) /
-            (mfd * pd)) << 10;
-}
-
-static void update_clocks(IMXCCMState *s)
-{
-    /*
-     * If we ever emulate more clocks, this should switch to a data-driven
-     * approach
-     */
-
-    if ((s->ccmr & CCMR_PRCS) == 1) {
-        s->pll_refclk_freq = CKIL_FREQ * 1024;
-    } else {
-        s->pll_refclk_freq = CKIH_FREQ;
-    }
-
-    /* ipg_clk_arm aka MCU clock */
-    if ((s->ccmr & CCMR_MDS) || !(s->ccmr & CCMR_MPE)) {
-        s->mcu_clk_freq = s->pll_refclk_freq;
-    } else {
-        s->mcu_clk_freq = calc_pll(s->mpctl, s->pll_refclk_freq);
-    }
-
-    /* High-speed clock */
-    s->hsp_clk_freq = s->mcu_clk_freq / (1 + EXTRACT(s->pdr0, HSP));
-    s->ipg_clk_freq = s->hsp_clk_freq / (1 + EXTRACT(s->pdr0, IPG));
-
-    DPRINTF("Clocks: mcu %uMHz, HSP %uMHz, IPG %uHz\n",
-            s->mcu_clk_freq / 1000000,
-            s->hsp_clk_freq / 1000000,
-            s->ipg_clk_freq);
-}
-
-static void imx_ccm_reset(DeviceState *dev)
-{
-    IMXCCMState *s = container_of(dev, IMXCCMState, busdev.qdev);
-
-    s->ccmr = 0x074b0b7b;
-    s->pdr0 = 0xff870b48;
-    s->pdr1 = 0x49fcfe7f;
-    s->mpctl = PLL_PD(1) | PLL_MFD(0) | PLL_MFI(6) | PLL_MFN(0);
-    s->cgr[0] = s->cgr[1] = s->cgr[2] = 0xffffffff;
-    s->spctl = PLL_PD(1) | PLL_MFD(4) | PLL_MFI(0xc) | PLL_MFN(1);
-    s->pmcr0 = 0x80209828;
-
-    update_clocks(s);
-}
-
-static uint64_t imx_ccm_read(void *opaque, hwaddr offset,
-                                unsigned size)
-{
-    IMXCCMState *s = (IMXCCMState *)opaque;
-
-    DPRINTF("read(offset=%x)", offset >> 2);
-    switch (offset >> 2) {
-    case 0: /* CCMR */
-        DPRINTF(" ccmr = 0x%x\n", s->ccmr);
-        return s->ccmr;
-    case 1:
-        DPRINTF(" pdr0 = 0x%x\n", s->pdr0);
-        return s->pdr0;
-    case 2:
-        DPRINTF(" pdr1 = 0x%x\n", s->pdr1);
-        return s->pdr1;
-    case 4:
-        DPRINTF(" mpctl = 0x%x\n", s->mpctl);
-        return s->mpctl;
-    case 6:
-        DPRINTF(" spctl = 0x%x\n", s->spctl);
-        return s->spctl;
-    case 8:
-        DPRINTF(" cgr0 = 0x%x\n", s->cgr[0]);
-        return s->cgr[0];
-    case 9:
-        DPRINTF(" cgr1 = 0x%x\n", s->cgr[1]);
-        return s->cgr[1];
-    case 10:
-        DPRINTF(" cgr2 = 0x%x\n", s->cgr[2]);
-        return s->cgr[2];
-    case 18: /* LTR1 */
-        return 0x00004040;
-    case 23:
-        DPRINTF(" pcmr0 = 0x%x\n", s->pmcr0);
-        return s->pmcr0;
-    }
-    DPRINTF(" return 0\n");
-    return 0;
-}
-
-static void imx_ccm_write(void *opaque, hwaddr offset,
-                          uint64_t value, unsigned size)
-{
-    IMXCCMState *s = (IMXCCMState *)opaque;
-
-    DPRINTF("write(offset=%x, value = %x)\n",
-            offset >> 2, (unsigned int)value);
-    switch (offset >> 2) {
-    case 0:
-        s->ccmr = CCMR_FPMF | (value & 0x3b6fdfff);
-        break;
-    case 1:
-        s->pdr0 = value & 0xff9f3fff;
-        break;
-    case 2:
-        s->pdr1 = value;
-        break;
-    case 4:
-        s->mpctl = value & 0xbfff3fff;
-        break;
-    case 6:
-        s->spctl = value & 0xbfff3fff;
-        break;
-    case 8:
-        s->cgr[0] = value;
-        return;
-    case 9:
-        s->cgr[1] = value;
-        return;
-    case 10:
-        s->cgr[2] = value;
-        return;
-
-    default:
-        return;
-    }
-    update_clocks(s);
-}
-
-static const struct MemoryRegionOps imx_ccm_ops = {
-    .read = imx_ccm_read,
-    .write = imx_ccm_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int imx_ccm_init(SysBusDevice *dev)
-{
-    IMXCCMState *s = FROM_SYSBUS(typeof(*s), dev);
-
-    memory_region_init_io(&s->iomem, &imx_ccm_ops, s, "imx_ccm", 0x1000);
-    sysbus_init_mmio(dev, &s->iomem);
-
-    return 0;
-}
-
-static int imx_ccm_post_load(void *opaque, int version_id)
-{
-    IMXCCMState *s = (IMXCCMState *)opaque;
-
-    update_clocks(s);
-    return 0;
-}
-
-static void imx_ccm_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
-
-    sbc->init = imx_ccm_init;
-    dc->reset = imx_ccm_reset;
-    dc->vmsd = &vmstate_imx_ccm;
-    dc->desc = "i.MX Clock Control Module";
-}
-
-static const TypeInfo imx_ccm_info = {
-    .name = "imx_ccm",
-    .parent = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(IMXCCMState),
-    .class_init = imx_ccm_class_init,
-};
-
-static void imx_ccm_register_types(void)
-{
-    type_register_static(&imx_ccm_info);
-}
-
-type_init(imx_ccm_register_types)
diff --git a/hw/imx_serial.c b/hw/imx_serial.c
deleted file mode 100644 (file)
index 746723c..0000000
+++ /dev/null
@@ -1,467 +0,0 @@
-/*
- * IMX31 UARTS
- *
- * Copyright (c) 2008 OKL
- * Originally Written by Hans Jiang
- * Copyright (c) 2011 NICTA Pty Ltd.
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- *
- * This is a `bare-bones' implementation of the IMX series serial ports.
- * TODO:
- *  -- implement FIFOs.  The real hardware has 32 word transmit
- *                       and receive FIFOs; we currently use a 1-char buffer
- *  -- implement DMA
- *  -- implement BAUD-rate and modem lines, for when the backend
- *     is a real serial device.
- */
-
-#include "hw/hw.h"
-#include "hw/sysbus.h"
-#include "sysemu/sysemu.h"
-#include "char/char.h"
-#include "hw/imx.h"
-
-//#define DEBUG_SERIAL 1
-#ifdef DEBUG_SERIAL
-#define DPRINTF(fmt, args...) \
-do { printf("imx_serial: " fmt , ##args); } while (0)
-#else
-#define DPRINTF(fmt, args...) do {} while (0)
-#endif
-
-/*
- * Define to 1 for messages about attempts to
- * access unimplemented registers or similar.
- */
-//#define DEBUG_IMPLEMENTATION 1
-#ifdef DEBUG_IMPLEMENTATION
-#  define IPRINTF(fmt, args...) \
-    do  { fprintf(stderr, "imx_serial: " fmt, ##args); } while (0)
-#else
-#  define IPRINTF(fmt, args...) do {} while (0)
-#endif
-
-typedef struct {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-    int32_t readbuff;
-
-    uint32_t usr1;
-    uint32_t usr2;
-    uint32_t ucr1;
-    uint32_t ucr2;
-    uint32_t uts1;
-
-    /*
-     * The registers below are implemented just so that the
-     * guest OS sees what it has written
-     */
-    uint32_t onems;
-    uint32_t ufcr;
-    uint32_t ubmr;
-    uint32_t ubrc;
-    uint32_t ucr3;
-
-    qemu_irq irq;
-    CharDriverState *chr;
-} IMXSerialState;
-
-static const VMStateDescription vmstate_imx_serial = {
-    .name = "imx-serial",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_INT32(readbuff, IMXSerialState),
-        VMSTATE_UINT32(usr1, IMXSerialState),
-        VMSTATE_UINT32(usr2, IMXSerialState),
-        VMSTATE_UINT32(ucr1, IMXSerialState),
-        VMSTATE_UINT32(uts1, IMXSerialState),
-        VMSTATE_UINT32(onems, IMXSerialState),
-        VMSTATE_UINT32(ufcr, IMXSerialState),
-        VMSTATE_UINT32(ubmr, IMXSerialState),
-        VMSTATE_UINT32(ubrc, IMXSerialState),
-        VMSTATE_UINT32(ucr3, IMXSerialState),
-        VMSTATE_END_OF_LIST()
-    },
-};
-
-
-#define URXD_CHARRDY    (1<<15)   /* character read is valid */
-#define URXD_ERR        (1<<14)   /* Character has error */
-#define URXD_BRK        (1<<11)   /* Break received */
-
-#define USR1_PARTYER    (1<<15)   /* Parity Error */
-#define USR1_RTSS       (1<<14)   /* RTS pin status */
-#define USR1_TRDY       (1<<13)   /* Tx ready */
-#define USR1_RTSD       (1<<12)   /* RTS delta: pin changed state */
-#define USR1_ESCF       (1<<11)   /* Escape sequence interrupt */
-#define USR1_FRAMERR    (1<<10)   /* Framing error  */
-#define USR1_RRDY       (1<<9)    /* receiver ready */
-#define USR1_AGTIM      (1<<8)    /* Aging timer interrupt */
-#define USR1_DTRD       (1<<7)    /* DTR changed */
-#define USR1_RXDS       (1<<6)    /* Receiver is idle */
-#define USR1_AIRINT     (1<<5)    /* Aysnch IR interrupt */
-#define USR1_AWAKE      (1<<4)    /* Falling edge detected on RXd pin */
-
-#define USR2_ADET       (1<<15)   /* Autobaud complete */
-#define USR2_TXFE       (1<<14)   /* Transmit FIFO empty */
-#define USR2_DTRF       (1<<13)   /* DTR/DSR transition */
-#define USR2_IDLE       (1<<12)   /* UART has been idle for too long */
-#define USR2_ACST       (1<<11)   /* Autobaud counter stopped */
-#define USR2_RIDELT     (1<<10)   /* Ring Indicator delta */
-#define USR2_RIIN       (1<<9)    /* Ring Indicator Input */
-#define USR2_IRINT      (1<<8)    /* Serial Infrared Interrupt */
-#define USR2_WAKE       (1<<7)    /* Start bit detected */
-#define USR2_DCDDELT    (1<<6)    /* Data Carrier Detect delta */
-#define USR2_DCDIN      (1<<5)    /* Data Carrier Detect Input */
-#define USR2_RTSF       (1<<4)    /* RTS transition */
-#define USR2_TXDC       (1<<3)    /* Transmission complete */
-#define USR2_BRCD       (1<<2)    /* Break condition detected */
-#define USR2_ORE        (1<<1)    /* Overrun error */
-#define USR2_RDR        (1<<0)    /* Receive data ready */
-
-#define UCR1_TRDYEN     (1<<13)   /* Tx Ready Interrupt Enable */
-#define UCR1_RRDYEN     (1<<9)    /* Rx Ready Interrupt Enable */
-#define UCR1_TXMPTYEN   (1<<6)    /* Tx Empty Interrupt Enable */
-#define UCR1_UARTEN     (1<<0)    /* UART Enable */
-
-#define UCR2_TXEN       (1<<2)    /* Transmitter enable */
-#define UCR2_RXEN       (1<<1)    /* Receiver enable */
-#define UCR2_SRST       (1<<0)    /* Reset complete */
-
-#define UTS1_TXEMPTY    (1<<6)
-#define UTS1_RXEMPTY    (1<<5)
-#define UTS1_TXFULL     (1<<4)
-#define UTS1_RXFULL     (1<<3)
-
-static void imx_update(IMXSerialState *s)
-{
-    uint32_t flags;
-
-    flags = (s->usr1 & s->ucr1) & (USR1_TRDY|USR1_RRDY);
-    if (!(s->ucr1 & UCR1_TXMPTYEN)) {
-        flags &= ~USR1_TRDY;
-    }
-
-    qemu_set_irq(s->irq, !!flags);
-}
-
-static void imx_serial_reset(IMXSerialState *s)
-{
-
-    s->usr1 = USR1_TRDY | USR1_RXDS;
-    /*
-     * Fake attachment of a terminal: assert RTS.
-     */
-    s->usr1 |= USR1_RTSS;
-    s->usr2 = USR2_TXFE | USR2_TXDC | USR2_DCDIN;
-    s->uts1 = UTS1_RXEMPTY | UTS1_TXEMPTY;
-    s->ucr1 = 0;
-    s->ucr2 = UCR2_SRST;
-    s->ucr3 = 0x700;
-    s->ubmr = 0;
-    s->ubrc = 4;
-    s->readbuff = URXD_ERR;
-}
-
-static void imx_serial_reset_at_boot(DeviceState *dev)
-{
-    IMXSerialState *s = container_of(dev, IMXSerialState, busdev.qdev);
-
-    imx_serial_reset(s);
-
-    /*
-     * enable the uart on boot, so messages from the linux decompresser
-     * are visible.  On real hardware this is done by the boot rom
-     * before anything else is loaded.
-     */
-    s->ucr1 = UCR1_UARTEN;
-    s->ucr2 = UCR2_TXEN;
-
-}
-
-static uint64_t imx_serial_read(void *opaque, hwaddr offset,
-                                unsigned size)
-{
-    IMXSerialState *s = (IMXSerialState *)opaque;
-    uint32_t c;
-
-    DPRINTF("read(offset=%x)\n", offset >> 2);
-    switch (offset >> 2) {
-    case 0x0: /* URXD */
-        c = s->readbuff;
-        if (!(s->uts1 & UTS1_RXEMPTY)) {
-            /* Character is valid */
-            c |= URXD_CHARRDY;
-            s->usr1 &= ~USR1_RRDY;
-            s->usr2 &= ~USR2_RDR;
-            s->uts1 |= UTS1_RXEMPTY;
-            imx_update(s);
-            qemu_chr_accept_input(s->chr);
-        }
-        return c;
-
-    case 0x20: /* UCR1 */
-        return s->ucr1;
-
-    case 0x21: /* UCR2 */
-        return s->ucr2;
-
-    case 0x25: /* USR1 */
-        return s->usr1;
-
-    case 0x26: /* USR2 */
-        return s->usr2;
-
-    case 0x2A: /* BRM Modulator */
-        return s->ubmr;
-
-    case 0x2B: /* Baud Rate Count */
-        return s->ubrc;
-
-    case 0x2d: /* Test register */
-        return s->uts1;
-
-    case 0x24: /* UFCR */
-        return s->ufcr;
-
-    case 0x2c:
-        return s->onems;
-
-    case 0x22: /* UCR3 */
-        return s->ucr3;
-
-    case 0x23: /* UCR4 */
-    case 0x29: /* BRM Incremental */
-        return 0x0; /* TODO */
-
-    default:
-        IPRINTF("imx_serial_read: bad offset: 0x%x\n", (int)offset);
-        return 0;
-    }
-}
-
-static void imx_serial_write(void *opaque, hwaddr offset,
-                      uint64_t value, unsigned size)
-{
-    IMXSerialState *s = (IMXSerialState *)opaque;
-    unsigned char ch;
-
-    DPRINTF("write(offset=%x, value = %x) to %s\n",
-            offset >> 2,
-            (unsigned int)value, s->chr ? s->chr->label : "NODEV");
-
-    switch (offset >> 2) {
-    case 0x10: /* UTXD */
-        ch = value;
-        if (s->ucr2 & UCR2_TXEN) {
-            if (s->chr) {
-                qemu_chr_fe_write(s->chr, &ch, 1);
-            }
-            s->usr1 &= ~USR1_TRDY;
-            imx_update(s);
-            s->usr1 |= USR1_TRDY;
-            imx_update(s);
-        }
-        break;
-
-    case 0x20: /* UCR1 */
-        s->ucr1 = value & 0xffff;
-        DPRINTF("write(ucr1=%x)\n", (unsigned int)value);
-        imx_update(s);
-        break;
-
-    case 0x21: /* UCR2 */
-        /*
-         * Only a few bits in control register 2 are implemented as yet.
-         * If it's intended to use a real serial device as a back-end, this
-         * register will have to be implemented more fully.
-         */
-        if (!(value & UCR2_SRST)) {
-            imx_serial_reset(s);
-            imx_update(s);
-            value |= UCR2_SRST;
-        }
-        if (value & UCR2_RXEN) {
-            if (!(s->ucr2 & UCR2_RXEN)) {
-                qemu_chr_accept_input(s->chr);
-            }
-        }
-        s->ucr2 = value & 0xffff;
-        break;
-
-    case 0x25: /* USR1 */
-        value &= USR1_AWAKE | USR1_AIRINT | USR1_DTRD | USR1_AGTIM |
-            USR1_FRAMERR | USR1_ESCF | USR1_RTSD | USR1_PARTYER;
-        s->usr1 &= ~value;
-        break;
-
-    case 0x26: /* USR2 */
-       /*
-        * Writing 1 to some bits clears them; all other
-        * values are ignored
-        */
-        value &= USR2_ADET | USR2_DTRF | USR2_IDLE | USR2_ACST |
-            USR2_RIDELT | USR2_IRINT | USR2_WAKE |
-            USR2_DCDDELT | USR2_RTSF | USR2_BRCD | USR2_ORE;
-        s->usr2 &= ~value;
-        break;
-
-        /*
-         * Linux expects to see what it writes to these registers
-         * We don't currently alter the baud rate
-         */
-    case 0x29: /* UBIR */
-        s->ubrc = value & 0xffff;
-        break;
-
-    case 0x2a: /* UBMR */
-        s->ubmr = value & 0xffff;
-        break;
-
-    case 0x2c: /* One ms reg */
-        s->onems = value & 0xffff;
-        break;
-
-    case 0x24: /* FIFO control register */
-        s->ufcr = value & 0xffff;
-        break;
-
-    case 0x22: /* UCR3 */
-        s->ucr3 = value & 0xffff;
-        break;
-
-    case 0x2d: /* UTS1 */
-    case 0x23: /* UCR4 */
-        IPRINTF("Unimplemented Register %x written to\n", offset >> 2);
-        /* TODO */
-        break;
-
-    default:
-        IPRINTF("imx_serial_write: Bad offset 0x%x\n", (int)offset);
-    }
-}
-
-static int imx_can_receive(void *opaque)
-{
-    IMXSerialState *s = (IMXSerialState *)opaque;
-    return !(s->usr1 & USR1_RRDY);
-}
-
-static void imx_put_data(void *opaque, uint32_t value)
-{
-    IMXSerialState *s = (IMXSerialState *)opaque;
-    DPRINTF("received char\n");
-    s->usr1 |= USR1_RRDY;
-    s->usr2 |= USR2_RDR;
-    s->uts1 &= ~UTS1_RXEMPTY;
-    s->readbuff = value;
-    imx_update(s);
-}
-
-static void imx_receive(void *opaque, const uint8_t *buf, int size)
-{
-    imx_put_data(opaque, *buf);
-}
-
-static void imx_event(void *opaque, int event)
-{
-    if (event == CHR_EVENT_BREAK) {
-        imx_put_data(opaque, URXD_BRK);
-    }
-}
-
-
-static const struct MemoryRegionOps imx_serial_ops = {
-    .read = imx_serial_read,
-    .write = imx_serial_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int imx_serial_init(SysBusDevice *dev)
-{
-    IMXSerialState *s = FROM_SYSBUS(IMXSerialState, dev);
-
-
-    memory_region_init_io(&s->iomem, &imx_serial_ops, s, "imx-serial", 0x1000);
-    sysbus_init_mmio(dev, &s->iomem);
-    sysbus_init_irq(dev, &s->irq);
-
-    if (s->chr) {
-        qemu_chr_add_handlers(s->chr, imx_can_receive, imx_receive,
-                              imx_event, s);
-    } else {
-        DPRINTF("No char dev for uart at 0x%lx\n",
-                (unsigned long)s->iomem.ram_addr);
-    }
-
-    return 0;
-}
-
-void imx_serial_create(int uart, const hwaddr addr, qemu_irq irq)
-{
-    DeviceState *dev;
-    SysBusDevice *bus;
-    CharDriverState *chr;
-    const char chr_name[] = "serial";
-    char label[ARRAY_SIZE(chr_name) + 1];
-
-    dev = qdev_create(NULL, "imx-serial");
-
-    if (uart >= MAX_SERIAL_PORTS) {
-        hw_error("Cannot assign uart %d: QEMU supports only %d ports\n",
-                 uart, MAX_SERIAL_PORTS);
-    }
-    chr = serial_hds[uart];
-    if (!chr) {
-        snprintf(label, ARRAY_SIZE(label), "%s%d", chr_name, uart);
-        chr = qemu_chr_new(label, "null", NULL);
-        if (!(chr)) {
-            hw_error("Can't assign serial port to imx-uart%d.\n", uart);
-        }
-    }
-
-    qdev_prop_set_chr(dev, "chardev", chr);
-    bus = SYS_BUS_DEVICE(dev);
-    qdev_init_nofail(dev);
-    if (addr != (hwaddr)-1) {
-        sysbus_mmio_map(bus, 0, addr);
-    }
-    sysbus_connect_irq(bus, 0, irq);
-
-}
-
-
-static Property imx32_serial_properties[] = {
-    DEFINE_PROP_CHR("chardev", IMXSerialState, chr),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void imx_serial_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = imx_serial_init;
-    dc->vmsd = &vmstate_imx_serial;
-    dc->reset = imx_serial_reset_at_boot;
-    dc->desc = "i.MX series UART";
-    dc->props = imx32_serial_properties;
-}
-
-static const TypeInfo imx_serial_info = {
-    .name = "imx-serial",
-    .parent = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(IMXSerialState),
-    .class_init = imx_serial_class_init,
-};
-
-static void imx_serial_register_types(void)
-{
-    type_register_static(&imx_serial_info);
-}
-
-type_init(imx_serial_register_types)
diff --git a/hw/imx_timer.c b/hw/imx_timer.c
deleted file mode 100644 (file)
index a8c3111..0000000
+++ /dev/null
@@ -1,689 +0,0 @@
-/*
- * IMX31 Timer
- *
- * Copyright (c) 2008 OK Labs
- * Copyright (c) 2011 NICTA Pty Ltd
- * Originally written by Hans Jiang
- * Updated by Peter Chubb
- *
- * This code is licensed under GPL version 2 or later.  See
- * the COPYING file in the top-level directory.
- *
- */
-
-#include "hw/hw.h"
-#include "qemu/timer.h"
-#include "hw/ptimer.h"
-#include "hw/sysbus.h"
-#include "hw/imx.h"
-
-//#define DEBUG_TIMER 1
-#ifdef DEBUG_TIMER
-#  define DPRINTF(fmt, args...) \
-      do { printf("imx_timer: " fmt , ##args); } while (0)
-#else
-#  define DPRINTF(fmt, args...) do {} while (0)
-#endif
-
-/*
- * Define to 1 for messages about attempts to
- * access unimplemented registers or similar.
- */
-#define DEBUG_IMPLEMENTATION 1
-#if DEBUG_IMPLEMENTATION
-#  define IPRINTF(fmt, args...)                                         \
-    do  { fprintf(stderr, "imx_timer: " fmt, ##args); } while (0)
-#else
-#  define IPRINTF(fmt, args...) do {} while (0)
-#endif
-
-/*
- * GPT : General purpose timer
- *
- * This timer counts up continuously while it is enabled, resetting itself
- * to 0 when it reaches TIMER_MAX (in freerun mode) or when it
- * reaches the value of ocr1 (in periodic mode).  WE simulate this using a
- * QEMU ptimer counting down from ocr1 and reloading from ocr1 in
- * periodic mode, or counting from ocr1 to zero, then TIMER_MAX - ocr1.
- * waiting_rov is set when counting from TIMER_MAX.
- *
- * In the real hardware, there are three comparison registers that can
- * trigger interrupts, and compare channel 1 can be used to
- * force-reset the timer. However, this is a `bare-bones'
- * implementation: only what Linux 3.x uses has been implemented
- * (free-running timer from 0 to OCR1 or TIMER_MAX) .
- */
-
-
-#define TIMER_MAX  0XFFFFFFFFUL
-
-/* Control register.  Not all of these bits have any effect (yet) */
-#define GPT_CR_EN     (1 << 0)  /* GPT Enable */
-#define GPT_CR_ENMOD  (1 << 1)  /* GPT Enable Mode */
-#define GPT_CR_DBGEN  (1 << 2)  /* GPT Debug mode enable */
-#define GPT_CR_WAITEN (1 << 3)  /* GPT Wait Mode Enable  */
-#define GPT_CR_DOZEN  (1 << 4)  /* GPT Doze mode enable */
-#define GPT_CR_STOPEN (1 << 5)  /* GPT Stop Mode Enable */
-#define GPT_CR_CLKSRC_SHIFT (6)
-#define GPT_CR_CLKSRC_MASK  (0x7)
-
-#define GPT_CR_FRR    (1 << 9)  /* Freerun or Restart */
-#define GPT_CR_SWR    (1 << 15) /* Software Reset */
-#define GPT_CR_IM1    (3 << 16) /* Input capture channel 1 mode (2 bits) */
-#define GPT_CR_IM2    (3 << 18) /* Input capture channel 2 mode (2 bits) */
-#define GPT_CR_OM1    (7 << 20) /* Output Compare Channel 1 Mode (3 bits) */
-#define GPT_CR_OM2    (7 << 23) /* Output Compare Channel 2 Mode (3 bits) */
-#define GPT_CR_OM3    (7 << 26) /* Output Compare Channel 3 Mode (3 bits) */
-#define GPT_CR_FO1    (1 << 29) /* Force Output Compare Channel 1 */
-#define GPT_CR_FO2    (1 << 30) /* Force Output Compare Channel 2 */
-#define GPT_CR_FO3    (1 << 31) /* Force Output Compare Channel 3 */
-
-#define GPT_SR_OF1  (1 << 0)
-#define GPT_SR_ROV  (1 << 5)
-
-#define GPT_IR_OF1IE  (1 << 0)
-#define GPT_IR_ROVIE  (1 << 5)
-
-typedef struct {
-    SysBusDevice busdev;
-    ptimer_state *timer;
-    MemoryRegion iomem;
-    DeviceState *ccm;
-
-    uint32_t cr;
-    uint32_t pr;
-    uint32_t sr;
-    uint32_t ir;
-    uint32_t ocr1;
-    uint32_t cnt;
-
-    uint32_t waiting_rov;
-    qemu_irq irq;
-} IMXTimerGState;
-
-static const VMStateDescription vmstate_imx_timerg = {
-    .name = "imx-timerg",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField[]) {
-        VMSTATE_UINT32(cr, IMXTimerGState),
-        VMSTATE_UINT32(pr, IMXTimerGState),
-        VMSTATE_UINT32(sr, IMXTimerGState),
-        VMSTATE_UINT32(ir, IMXTimerGState),
-        VMSTATE_UINT32(ocr1, IMXTimerGState),
-        VMSTATE_UINT32(cnt, IMXTimerGState),
-        VMSTATE_UINT32(waiting_rov, IMXTimerGState),
-        VMSTATE_PTIMER(timer, IMXTimerGState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static const IMXClk imx_timerg_clocks[] = {
-    NOCLK,    /* 000 No clock source */
-    IPG,      /* 001 ipg_clk, 532MHz*/
-    IPG,      /* 010 ipg_clk_highfreq */
-    NOCLK,    /* 011 not defined */
-    CLK_32k,  /* 100 ipg_clk_32k */
-    NOCLK,    /* 101 not defined */
-    NOCLK,    /* 110 not defined */
-    NOCLK,    /* 111 not defined */
-};
-
-
-static void imx_timerg_set_freq(IMXTimerGState *s)
-{
-    int clksrc;
-    uint32_t freq;
-
-    clksrc = (s->cr >> GPT_CR_CLKSRC_SHIFT) & GPT_CR_CLKSRC_MASK;
-    freq = imx_clock_frequency(s->ccm, imx_timerg_clocks[clksrc]) / (1 + s->pr);
-
-    DPRINTF("Setting gtimer clksrc %d to frequency %d\n", clksrc, freq);
-    if (freq) {
-        ptimer_set_freq(s->timer, freq);
-    }
-}
-
-static void imx_timerg_update(IMXTimerGState *s)
-{
-    uint32_t flags = s->sr & s->ir & (GPT_SR_OF1 | GPT_SR_ROV);
-
-    DPRINTF("g-timer SR: %s %s IR=%s %s, %s\n",
-            s->sr & GPT_SR_OF1 ? "OF1" : "",
-            s->sr & GPT_SR_ROV ? "ROV" : "",
-            s->ir & GPT_SR_OF1 ? "OF1" : "",
-            s->ir & GPT_SR_ROV ? "ROV" : "",
-            s->cr & GPT_CR_EN ? "CR_EN" : "Not Enabled");
-
-
-    qemu_set_irq(s->irq, (s->cr & GPT_CR_EN) && flags);
-}
-
-static uint32_t imx_timerg_update_counts(IMXTimerGState *s)
-{
-    uint64_t target = s->waiting_rov ? TIMER_MAX : s->ocr1;
-    uint64_t cnt = ptimer_get_count(s->timer);
-    s->cnt = target - cnt;
-    return s->cnt;
-}
-
-static void imx_timerg_reload(IMXTimerGState *s, uint32_t timeout)
-{
-    uint64_t diff_cnt;
-
-    if (!(s->cr & GPT_CR_FRR)) {
-        IPRINTF("IMX_timerg_reload --- called in reset-mode\n");
-        return;
-    }
-
-    /*
-     * For small timeouts, qemu sometimes runs too slow.
-     * Better deliver a late interrupt than none.
-     *
-     * In Reset mode (FRR bit clear)
-     * the ptimer reloads itself from OCR1;
-     * in free-running mode we need to fake
-     * running from 0 to ocr1 to TIMER_MAX
-     */
-    if (timeout > s->cnt) {
-        diff_cnt = timeout - s->cnt;
-    } else {
-        diff_cnt = 0;
-    }
-    ptimer_set_count(s->timer, diff_cnt);
-}
-
-static uint64_t imx_timerg_read(void *opaque, hwaddr offset,
-                                unsigned size)
-{
-    IMXTimerGState *s = (IMXTimerGState *)opaque;
-
-    DPRINTF("g-read(offset=%x)", offset >> 2);
-    switch (offset >> 2) {
-    case 0: /* Control Register */
-        DPRINTF(" cr = %x\n", s->cr);
-        return s->cr;
-
-    case 1: /* prescaler */
-        DPRINTF(" pr = %x\n", s->pr);
-        return s->pr;
-
-    case 2: /* Status Register */
-        DPRINTF(" sr = %x\n", s->sr);
-        return s->sr;
-
-    case 3: /* Interrupt Register */
-        DPRINTF(" ir = %x\n", s->ir);
-        return s->ir;
-
-    case 4: /* Output Compare Register 1 */
-        DPRINTF(" ocr1 = %x\n", s->ocr1);
-        return s->ocr1;
-
-
-    case 9: /* cnt */
-        imx_timerg_update_counts(s);
-        DPRINTF(" cnt = %x\n", s->cnt);
-        return s->cnt;
-    }
-
-    IPRINTF("imx_timerg_read: Bad offset %x\n",
-            (int)offset >> 2);
-    return 0;
-}
-
-static void imx_timerg_reset(DeviceState *dev)
-{
-    IMXTimerGState *s = container_of(dev, IMXTimerGState, busdev.qdev);
-
-    /*
-     * Soft reset doesn't touch some bits; hard reset clears them
-     */
-    s->cr &= ~(GPT_CR_EN|GPT_CR_DOZEN|GPT_CR_WAITEN|GPT_CR_DBGEN);
-    s->sr = 0;
-    s->pr = 0;
-    s->ir = 0;
-    s->cnt = 0;
-    s->ocr1 = TIMER_MAX;
-    ptimer_stop(s->timer);
-    ptimer_set_limit(s->timer, TIMER_MAX, 1);
-    imx_timerg_set_freq(s);
-}
-
-static void imx_timerg_write(void *opaque, hwaddr offset,
-                             uint64_t value, unsigned size)
-{
-    IMXTimerGState *s = (IMXTimerGState *)opaque;
-    DPRINTF("g-write(offset=%x, value = 0x%x)\n", (unsigned int)offset >> 2,
-            (unsigned int)value);
-
-    switch (offset >> 2) {
-    case 0: {
-        uint32_t oldcr = s->cr;
-        /* CR */
-        if (value & GPT_CR_SWR) { /* force reset */
-            value &= ~GPT_CR_SWR;
-            imx_timerg_reset(&s->busdev.qdev);
-            imx_timerg_update(s);
-        }
-
-        s->cr = value & ~0x7c00;
-        imx_timerg_set_freq(s);
-        if ((oldcr ^ value) & GPT_CR_EN) {
-            if (value & GPT_CR_EN) {
-                if (value & GPT_CR_ENMOD) {
-                    ptimer_set_count(s->timer, s->ocr1);
-                    s->cnt = 0;
-                }
-                ptimer_run(s->timer,
-                           (value & GPT_CR_FRR) && (s->ocr1 != TIMER_MAX));
-            } else {
-                ptimer_stop(s->timer);
-            };
-        }
-        return;
-    }
-
-    case 1: /* Prescaler */
-        s->pr = value & 0xfff;
-        imx_timerg_set_freq(s);
-        return;
-
-    case 2: /* SR */
-        /*
-         * No point in implementing the status register bits to do with
-         * external interrupt sources.
-         */
-        value &= GPT_SR_OF1 | GPT_SR_ROV;
-        s->sr &= ~value;
-        imx_timerg_update(s);
-        return;
-
-    case 3: /* IR -- interrupt register */
-        s->ir = value & 0x3f;
-        imx_timerg_update(s);
-        return;
-
-    case 4: /* OCR1 -- output compare register */
-        /* In non-freerun mode, reset count when this register is written */
-        if (!(s->cr & GPT_CR_FRR)) {
-            s->waiting_rov = 0;
-            ptimer_set_limit(s->timer, value, 1);
-        } else {
-            imx_timerg_update_counts(s);
-            if (value > s->cnt) {
-                s->waiting_rov = 0;
-                imx_timerg_reload(s, value);
-            } else {
-                s->waiting_rov = 1;
-                imx_timerg_reload(s, TIMER_MAX - s->cnt);
-            }
-        }
-        s->ocr1 = value;
-        return;
-
-    default:
-        IPRINTF("imx_timerg_write: Bad offset %x\n",
-                (int)offset >> 2);
-    }
-}
-
-static void imx_timerg_timeout(void *opaque)
-{
-    IMXTimerGState *s = (IMXTimerGState *)opaque;
-
-    DPRINTF("imx_timerg_timeout, waiting rov=%d\n", s->waiting_rov);
-    if (s->cr & GPT_CR_FRR) {
-        /*
-         * Free running timer from 0 -> TIMERMAX
-         * Generates interrupt at TIMER_MAX and at cnt==ocr1
-         * If ocr1 == TIMER_MAX, then no need to reload timer.
-         */
-        if (s->ocr1 == TIMER_MAX) {
-            DPRINTF("s->ocr1 == TIMER_MAX, FRR\n");
-            s->sr |= GPT_SR_OF1 | GPT_SR_ROV;
-            imx_timerg_update(s);
-            return;
-        }
-
-        if (s->waiting_rov) {
-            /*
-             * We were waiting for cnt==TIMER_MAX
-             */
-            s->sr |= GPT_SR_ROV;
-            s->waiting_rov = 0;
-            s->cnt = 0;
-            imx_timerg_reload(s, s->ocr1);
-        } else {
-            /* Must have got a cnt==ocr1 timeout. */
-            s->sr |= GPT_SR_OF1;
-            s->cnt = s->ocr1;
-            s->waiting_rov = 1;
-            imx_timerg_reload(s, TIMER_MAX);
-        }
-        imx_timerg_update(s);
-        return;
-    }
-
-    s->sr |= GPT_SR_OF1;
-    imx_timerg_update(s);
-}
-
-static const MemoryRegionOps imx_timerg_ops = {
-    .read = imx_timerg_read,
-    .write = imx_timerg_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-
-static int imx_timerg_init(SysBusDevice *dev)
-{
-    IMXTimerGState *s = FROM_SYSBUS(IMXTimerGState, dev);
-    QEMUBH *bh;
-
-    sysbus_init_irq(dev, &s->irq);
-    memory_region_init_io(&s->iomem, &imx_timerg_ops,
-                          s, "imxg-timer",
-                          0x00001000);
-    sysbus_init_mmio(dev, &s->iomem);
-
-    bh = qemu_bh_new(imx_timerg_timeout, s);
-    s->timer = ptimer_init(bh);
-
-    /* Hard reset resets extra bits in CR */
-    s->cr = 0;
-    return 0;
-}
-
-
-
-/*
- * EPIT: Enhanced periodic interrupt timer
- */
-
-#define CR_EN       (1 << 0)
-#define CR_ENMOD    (1 << 1)
-#define CR_OCIEN    (1 << 2)
-#define CR_RLD      (1 << 3)
-#define CR_PRESCALE_SHIFT (4)
-#define CR_PRESCALE_MASK  (0xfff)
-#define CR_SWR      (1 << 16)
-#define CR_IOVW     (1 << 17)
-#define CR_DBGEN    (1 << 18)
-#define CR_EPIT     (1 << 19)
-#define CR_DOZEN    (1 << 20)
-#define CR_STOPEN   (1 << 21)
-#define CR_CLKSRC_SHIFT (24)
-#define CR_CLKSRC_MASK  (0x3 << CR_CLKSRC_SHIFT)
-
-
-/*
- * Exact clock frequencies vary from board to board.
- * These are typical.
- */
-static const IMXClk imx_timerp_clocks[] =  {
-    0,        /* disabled */
-    IPG, /* ipg_clk, ~532MHz */
-    IPG, /* ipg_clk_highfreq */
-    CLK_32k,    /* ipg_clk_32k -- ~32kHz */
-};
-
-typedef struct {
-    SysBusDevice busdev;
-    ptimer_state *timer;
-    MemoryRegion iomem;
-    DeviceState *ccm;
-
-    uint32_t cr;
-    uint32_t lr;
-    uint32_t cmp;
-
-    uint32_t freq;
-    int int_level;
-    qemu_irq irq;
-} IMXTimerPState;
-
-/*
- * Update interrupt status
- */
-static void imx_timerp_update(IMXTimerPState *s)
-{
-    if (s->int_level && (s->cr & CR_OCIEN)) {
-        qemu_irq_raise(s->irq);
-    } else {
-        qemu_irq_lower(s->irq);
-    }
-}
-
-static void imx_timerp_reset(DeviceState *dev)
-{
-    IMXTimerPState *s = container_of(dev, IMXTimerPState, busdev.qdev);
-
-    s->cr = 0;
-    s->lr = TIMER_MAX;
-    s->int_level = 0;
-    s->cmp = 0;
-    ptimer_stop(s->timer);
-    ptimer_set_count(s->timer, TIMER_MAX);
-}
-
-static uint64_t imx_timerp_read(void *opaque, hwaddr offset,
-                                unsigned size)
-{
-    IMXTimerPState *s = (IMXTimerPState *)opaque;
-
-    DPRINTF("p-read(offset=%x)", offset >> 2);
-    switch (offset >> 2) {
-    case 0: /* Control Register */
-        DPRINTF("cr %x\n", s->cr);
-        return s->cr;
-
-    case 1: /* Status Register */
-        DPRINTF("int_level %x\n", s->int_level);
-        return s->int_level;
-
-    case 2: /* LR - ticks*/
-        DPRINTF("lr %x\n", s->lr);
-        return s->lr;
-
-    case 3: /* CMP */
-        DPRINTF("cmp %x\n", s->cmp);
-        return s->cmp;
-
-    case 4: /* CNT */
-        return ptimer_get_count(s->timer);
-    }
-    IPRINTF("imx_timerp_read: Bad offset %x\n",
-            (int)offset >> 2);
-    return 0;
-}
-
-static void set_timerp_freq(IMXTimerPState *s)
-{
-    int clksrc;
-    unsigned prescaler;
-    uint32_t freq;
-
-    clksrc = (s->cr & CR_CLKSRC_MASK) >> CR_CLKSRC_SHIFT;
-    prescaler = 1 + ((s->cr >> CR_PRESCALE_SHIFT) & CR_PRESCALE_MASK);
-    freq = imx_clock_frequency(s->ccm, imx_timerp_clocks[clksrc]) / prescaler;
-
-    s->freq = freq;
-    DPRINTF("Setting ptimer frequency to %u\n", freq);
-
-    if (freq) {
-        ptimer_set_freq(s->timer, freq);
-    }
-}
-
-static void imx_timerp_write(void *opaque, hwaddr offset,
-                             uint64_t value, unsigned size)
-{
-    IMXTimerPState *s = (IMXTimerPState *)opaque;
-    DPRINTF("p-write(offset=%x, value = %x)\n", (unsigned int)offset >> 2,
-            (unsigned int)value);
-
-    switch (offset >> 2) {
-    case 0: /* CR */
-        if (value & CR_SWR) {
-            imx_timerp_reset(&s->busdev.qdev);
-            value &= ~CR_SWR;
-        }
-        s->cr = value & 0x03ffffff;
-        set_timerp_freq(s);
-
-        if (s->freq && (s->cr & CR_EN)) {
-            if (!(s->cr & CR_ENMOD)) {
-                ptimer_set_count(s->timer, s->lr);
-            }
-            ptimer_run(s->timer, 0);
-        } else {
-            ptimer_stop(s->timer);
-        }
-        break;
-
-    case 1: /* SR - ACK*/
-        s->int_level = 0;
-        imx_timerp_update(s);
-        break;
-
-    case 2: /* LR - set ticks */
-        s->lr = value;
-        ptimer_set_limit(s->timer, value, !!(s->cr & CR_IOVW));
-        break;
-
-    case 3: /* CMP */
-        s->cmp = value;
-        if (value) {
-            IPRINTF(
-                "Values for EPIT comparison other than zero not supported\n"
-            );
-        }
-        break;
-
-    default:
-        IPRINTF("imx_timerp_write: Bad offset %x\n",
-                   (int)offset >> 2);
-    }
-}
-
-static void imx_timerp_tick(void *opaque)
-{
-    IMXTimerPState *s = (IMXTimerPState *)opaque;
-
-   DPRINTF("imxp tick\n");
-    if (!(s->cr & CR_RLD)) {
-        ptimer_set_count(s->timer, TIMER_MAX);
-    }
-    s->int_level = 1;
-    imx_timerp_update(s);
-}
-
-void imx_timerp_create(const hwaddr addr,
-                              qemu_irq irq,
-                              DeviceState *ccm)
-{
-    IMXTimerPState *pp;
-    DeviceState *dev;
-
-    dev = sysbus_create_simple("imx_timerp", addr, irq);
-    pp = container_of(dev, IMXTimerPState, busdev.qdev);
-    pp->ccm = ccm;
-}
-
-static const MemoryRegionOps imx_timerp_ops = {
-  .read = imx_timerp_read,
-  .write = imx_timerp_write,
-  .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static const VMStateDescription vmstate_imx_timerp = {
-    .name = "imx-timerp",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField[]) {
-        VMSTATE_UINT32(cr, IMXTimerPState),
-        VMSTATE_UINT32(lr, IMXTimerPState),
-        VMSTATE_UINT32(cmp, IMXTimerPState),
-        VMSTATE_UINT32(freq, IMXTimerPState),
-        VMSTATE_INT32(int_level, IMXTimerPState),
-        VMSTATE_PTIMER(timer, IMXTimerPState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static int imx_timerp_init(SysBusDevice *dev)
-{
-    IMXTimerPState *s = FROM_SYSBUS(IMXTimerPState, dev);
-    QEMUBH *bh;
-
-    DPRINTF("imx_timerp_init\n");
-
-    sysbus_init_irq(dev, &s->irq);
-    memory_region_init_io(&s->iomem, &imx_timerp_ops,
-                          s, "imxp-timer",
-                          0x00001000);
-    sysbus_init_mmio(dev, &s->iomem);
-
-    bh = qemu_bh_new(imx_timerp_tick, s);
-    s->timer = ptimer_init(bh);
-
-    return 0;
-}
-
-
-void imx_timerg_create(const hwaddr addr,
-                              qemu_irq irq,
-                              DeviceState *ccm)
-{
-    IMXTimerGState *pp;
-    DeviceState *dev;
-
-    dev = sysbus_create_simple("imx_timerg", addr, irq);
-    pp = container_of(dev, IMXTimerGState, busdev.qdev);
-    pp->ccm = ccm;
-}
-
-static void imx_timerg_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc  = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-    k->init = imx_timerg_init;
-    dc->vmsd = &vmstate_imx_timerg;
-    dc->reset = imx_timerg_reset;
-    dc->desc = "i.MX general timer";
-}
-
-static void imx_timerp_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc  = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-    k->init = imx_timerp_init;
-    dc->vmsd = &vmstate_imx_timerp;
-    dc->reset = imx_timerp_reset;
-    dc->desc = "i.MX periodic timer";
-}
-
-static const TypeInfo imx_timerp_info = {
-    .name = "imx_timerp",
-    .parent = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(IMXTimerPState),
-    .class_init = imx_timerp_class_init,
-};
-
-static const TypeInfo imx_timerg_info = {
-    .name = "imx_timerg",
-    .parent = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(IMXTimerGState),
-    .class_init = imx_timerg_class_init,
-};
-
-static void imx_timer_register_types(void)
-{
-    type_register_static(&imx_timerp_info);
-    type_register_static(&imx_timerg_info);
-}
-
-type_init(imx_timer_register_types)
diff --git a/hw/input/Makefile.objs b/hw/input/Makefile.objs
new file mode 100644 (file)
index 0000000..e8c80b9
--- /dev/null
@@ -0,0 +1,13 @@
+common-obj-$(CONFIG_ADB) += adb.o
+common-obj-y += hid.o
+common-obj-$(CONFIG_LM832X) += lm832x.o
+common-obj-$(CONFIG_PCKBD) += pckbd.o
+common-obj-$(CONFIG_PL050) += pl050.o
+common-obj-y += ps2.o
+common-obj-$(CONFIG_STELLARIS_INPUT) += stellaris_input.o
+common-obj-$(CONFIG_TSC2005) += tsc2005.o
+common-obj-$(CONFIG_VMMOUSE) += vmmouse.o
+
+obj-$(CONFIG_MILKYMIST) += milkymist-softusb.o
+obj-$(CONFIG_PXA2XX) += pxa2xx_keypad.o
+obj-$(CONFIG_TSC210X) += tsc210x.o
diff --git a/hw/input/adb.c b/hw/input/adb.c
new file mode 100644 (file)
index 0000000..a75d3fd
--- /dev/null
@@ -0,0 +1,581 @@
+/*
+ * QEMU ADB support
+ *
+ * Copyright (c) 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.
+ */
+#include "hw/hw.h"
+#include "hw/input/adb.h"
+#include "ui/console.h"
+
+/* debug ADB */
+//#define DEBUG_ADB
+
+#ifdef DEBUG_ADB
+#define ADB_DPRINTF(fmt, ...) \
+do { printf("ADB: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define ADB_DPRINTF(fmt, ...)
+#endif
+
+/* ADB commands */
+#define ADB_BUSRESET           0x00
+#define ADB_FLUSH               0x01
+#define ADB_WRITEREG           0x08
+#define ADB_READREG            0x0c
+
+/* ADB device commands */
+#define ADB_CMD_SELF_TEST              0xff
+#define ADB_CMD_CHANGE_ID              0xfe
+#define ADB_CMD_CHANGE_ID_AND_ACT      0xfd
+#define ADB_CMD_CHANGE_ID_AND_ENABLE   0x00
+
+/* ADB default device IDs (upper 4 bits of ADB command byte) */
+#define ADB_DEVID_DONGLE   1
+#define ADB_DEVID_KEYBOARD 2
+#define ADB_DEVID_MOUSE    3
+#define ADB_DEVID_TABLET   4
+#define ADB_DEVID_MODEM    5
+#define ADB_DEVID_MISC     7
+
+/* error codes */
+#define ADB_RET_NOTPRESENT (-2)
+
+static void adb_device_reset(ADBDevice *d)
+{
+    qdev_reset_all(DEVICE(d));
+}
+
+int adb_request(ADBBusState *s, uint8_t *obuf, const uint8_t *buf, int len)
+{
+    ADBDevice *d;
+    int devaddr, cmd, i;
+
+    cmd = buf[0] & 0xf;
+    if (cmd == ADB_BUSRESET) {
+        for(i = 0; i < s->nb_devices; i++) {
+            d = s->devices[i];
+            adb_device_reset(d);
+        }
+        return 0;
+    }
+    devaddr = buf[0] >> 4;
+    for(i = 0; i < s->nb_devices; i++) {
+        d = s->devices[i];
+        if (d->devaddr == devaddr) {
+            ADBDeviceClass *adc = ADB_DEVICE_GET_CLASS(d);
+            return adc->devreq(d, obuf, buf, len);
+        }
+    }
+    return ADB_RET_NOTPRESENT;
+}
+
+/* XXX: move that to cuda ? */
+int adb_poll(ADBBusState *s, uint8_t *obuf)
+{
+    ADBDevice *d;
+    int olen, i;
+    uint8_t buf[1];
+
+    olen = 0;
+    for(i = 0; i < s->nb_devices; i++) {
+        if (s->poll_index >= s->nb_devices)
+            s->poll_index = 0;
+        d = s->devices[s->poll_index];
+        buf[0] = ADB_READREG | (d->devaddr << 4);
+        olen = adb_request(s, obuf + 1, buf, 1);
+        /* if there is data, we poll again the same device */
+        if (olen > 0) {
+            obuf[0] = buf[0];
+            olen++;
+            break;
+        }
+        s->poll_index++;
+    }
+    return olen;
+}
+
+static const TypeInfo adb_bus_type_info = {
+    .name = TYPE_ADB_BUS,
+    .parent = TYPE_BUS,
+    .instance_size = sizeof(ADBBusState),
+};
+
+static void adb_device_realizefn(DeviceState *dev, Error **errp)
+{
+    ADBDevice *d = ADB_DEVICE(dev);
+    ADBBusState *bus = ADB_BUS(qdev_get_parent_bus(dev));
+
+    if (bus->nb_devices >= MAX_ADB_DEVICES) {
+        return;
+    }
+
+    bus->devices[bus->nb_devices++] = d;
+}
+
+static void adb_device_class_init(ObjectClass *oc, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(oc);
+
+    dc->realize = adb_device_realizefn;
+    dc->bus_type = TYPE_ADB_BUS;
+}
+
+static const TypeInfo adb_device_type_info = {
+    .name = TYPE_ADB_DEVICE,
+    .parent = TYPE_DEVICE,
+    .instance_size = sizeof(ADBDevice),
+    .abstract = true,
+    .class_init = adb_device_class_init,
+};
+
+/***************************************************************/
+/* Keyboard ADB device */
+
+#define ADB_KEYBOARD(obj) OBJECT_CHECK(KBDState, (obj), TYPE_ADB_KEYBOARD)
+
+typedef struct KBDState {
+    /*< private >*/
+    ADBDevice parent_obj;
+    /*< public >*/
+
+    uint8_t data[128];
+    int rptr, wptr, count;
+} KBDState;
+
+#define ADB_KEYBOARD_CLASS(class) \
+    OBJECT_CLASS_CHECK(ADBKeyboardClass, (class), TYPE_ADB_KEYBOARD)
+#define ADB_KEYBOARD_GET_CLASS(obj) \
+    OBJECT_GET_CLASS(ADBKeyboardClass, (obj), TYPE_ADB_KEYBOARD)
+
+typedef struct ADBKeyboardClass {
+    /*< private >*/
+    ADBDeviceClass parent_class;
+    /*< public >*/
+
+    DeviceRealize parent_realize;
+} ADBKeyboardClass;
+
+static const uint8_t pc_to_adb_keycode[256] = {
+  0, 53, 18, 19, 20, 21, 23, 22, 26, 28, 25, 29, 27, 24, 51, 48,
+ 12, 13, 14, 15, 17, 16, 32, 34, 31, 35, 33, 30, 36, 54,  0,  1,
+  2,  3,  5,  4, 38, 40, 37, 41, 39, 50, 56, 42,  6,  7,  8,  9,
+ 11, 45, 46, 43, 47, 44,123, 67, 58, 49, 57,122,120, 99,118, 96,
+ 97, 98,100,101,109, 71,107, 89, 91, 92, 78, 86, 87, 88, 69, 83,
+ 84, 85, 82, 65,  0,  0, 10,103,111,  0,  0,110, 81,  0,  0,  0,
+  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+  0,  0,  0, 94,  0, 93,  0,  0,  0,  0,  0,  0,104,102,  0,  0,
+  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 76,125,  0,  0,
+  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,105,  0,  0,  0,  0,  0,
+  0,  0,  0,  0,  0, 75,  0,  0,124,  0,  0,  0,  0,  0,  0,  0,
+  0,  0,  0,  0,  0,  0,  0,115, 62,116,  0, 59,  0, 60,  0,119,
+ 61,121,114,117,  0,  0,  0,  0,  0,  0,  0, 55,126,  0,127,  0,
+  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+  0,  0,  0,  0,  0, 95,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+};
+
+static void adb_kbd_put_keycode(void *opaque, int keycode)
+{
+    KBDState *s = opaque;
+
+    if (s->count < sizeof(s->data)) {
+        s->data[s->wptr] = keycode;
+        if (++s->wptr == sizeof(s->data))
+            s->wptr = 0;
+        s->count++;
+    }
+}
+
+static int adb_kbd_poll(ADBDevice *d, uint8_t *obuf)
+{
+    static int ext_keycode;
+    KBDState *s = ADB_KEYBOARD(d);
+    int adb_keycode, keycode;
+    int olen;
+
+    olen = 0;
+    for(;;) {
+        if (s->count == 0)
+            break;
+        keycode = s->data[s->rptr];
+        if (++s->rptr == sizeof(s->data))
+            s->rptr = 0;
+        s->count--;
+
+        if (keycode == 0xe0) {
+            ext_keycode = 1;
+        } else {
+            if (ext_keycode)
+                adb_keycode =  pc_to_adb_keycode[keycode | 0x80];
+            else
+                adb_keycode =  pc_to_adb_keycode[keycode & 0x7f];
+            obuf[0] = adb_keycode | (keycode & 0x80);
+            /* NOTE: could put a second keycode if needed */
+            obuf[1] = 0xff;
+            olen = 2;
+            ext_keycode = 0;
+            break;
+        }
+    }
+    return olen;
+}
+
+static int adb_kbd_request(ADBDevice *d, uint8_t *obuf,
+                           const uint8_t *buf, int len)
+{
+    KBDState *s = ADB_KEYBOARD(d);
+    int cmd, reg, olen;
+
+    if ((buf[0] & 0x0f) == ADB_FLUSH) {
+        /* flush keyboard fifo */
+        s->wptr = s->rptr = s->count = 0;
+        return 0;
+    }
+
+    cmd = buf[0] & 0xc;
+    reg = buf[0] & 0x3;
+    olen = 0;
+    switch(cmd) {
+    case ADB_WRITEREG:
+        switch(reg) {
+        case 2:
+            /* LED status */
+            break;
+        case 3:
+            switch(buf[2]) {
+            case ADB_CMD_SELF_TEST:
+                break;
+            case ADB_CMD_CHANGE_ID:
+            case ADB_CMD_CHANGE_ID_AND_ACT:
+            case ADB_CMD_CHANGE_ID_AND_ENABLE:
+                d->devaddr = buf[1] & 0xf;
+                break;
+            default:
+                /* XXX: check this */
+                d->devaddr = buf[1] & 0xf;
+                d->handler = buf[2];
+                break;
+            }
+        }
+        break;
+    case ADB_READREG:
+        switch(reg) {
+        case 0:
+            olen = adb_kbd_poll(d, obuf);
+            break;
+        case 1:
+            break;
+        case 2:
+            obuf[0] = 0x00; /* XXX: check this */
+            obuf[1] = 0x07; /* led status */
+            olen = 2;
+            break;
+        case 3:
+            obuf[0] = d->handler;
+            obuf[1] = d->devaddr;
+            olen = 2;
+            break;
+        }
+        break;
+    }
+    return olen;
+}
+
+static const VMStateDescription vmstate_adb_kbd = {
+    .name = "adb_kbd",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_BUFFER(data, KBDState),
+        VMSTATE_INT32(rptr, KBDState),
+        VMSTATE_INT32(wptr, KBDState),
+        VMSTATE_INT32(count, KBDState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void adb_kbd_reset(DeviceState *dev)
+{
+    ADBDevice *d = ADB_DEVICE(dev);
+    KBDState *s = ADB_KEYBOARD(dev);
+
+    d->handler = 1;
+    d->devaddr = ADB_DEVID_KEYBOARD;
+    memset(s->data, 0, sizeof(s->data));
+    s->rptr = 0;
+    s->wptr = 0;
+    s->count = 0;
+}
+
+static void adb_kbd_realizefn(DeviceState *dev, Error **errp)
+{
+    ADBDevice *d = ADB_DEVICE(dev);
+    ADBKeyboardClass *akc = ADB_KEYBOARD_GET_CLASS(dev);
+
+    akc->parent_realize(dev, errp);
+
+    qemu_add_kbd_event_handler(adb_kbd_put_keycode, d);
+}
+
+static void adb_kbd_initfn(Object *obj)
+{
+    ADBDevice *d = ADB_DEVICE(obj);
+
+    d->devaddr = ADB_DEVID_KEYBOARD;
+}
+
+static void adb_kbd_class_init(ObjectClass *oc, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(oc);
+    ADBDeviceClass *adc = ADB_DEVICE_CLASS(oc);
+    ADBKeyboardClass *akc = ADB_KEYBOARD_CLASS(oc);
+
+    akc->parent_realize = dc->realize;
+    dc->realize = adb_kbd_realizefn;
+
+    adc->devreq = adb_kbd_request;
+    dc->reset = adb_kbd_reset;
+    dc->vmsd = &vmstate_adb_kbd;
+}
+
+static const TypeInfo adb_kbd_type_info = {
+    .name = TYPE_ADB_KEYBOARD,
+    .parent = TYPE_ADB_DEVICE,
+    .instance_size = sizeof(KBDState),
+    .instance_init = adb_kbd_initfn,
+    .class_init = adb_kbd_class_init,
+    .class_size = sizeof(ADBKeyboardClass),
+};
+
+/***************************************************************/
+/* Mouse ADB device */
+
+#define ADB_MOUSE(obj) OBJECT_CHECK(MouseState, (obj), TYPE_ADB_MOUSE)
+
+typedef struct MouseState {
+    /*< public >*/
+    ADBDevice parent_obj;
+    /*< private >*/
+
+    int buttons_state, last_buttons_state;
+    int dx, dy, dz;
+} MouseState;
+
+#define ADB_MOUSE_CLASS(class) \
+    OBJECT_CLASS_CHECK(ADBMouseClass, (class), TYPE_ADB_MOUSE)
+#define ADB_MOUSE_GET_CLASS(obj) \
+    OBJECT_GET_CLASS(ADBMouseClass, (obj), TYPE_ADB_MOUSE)
+
+typedef struct ADBMouseClass {
+    /*< public >*/
+    ADBDeviceClass parent_class;
+    /*< private >*/
+
+    DeviceRealize parent_realize;
+} ADBMouseClass;
+
+static void adb_mouse_event(void *opaque,
+                            int dx1, int dy1, int dz1, int buttons_state)
+{
+    MouseState *s = opaque;
+
+    s->dx += dx1;
+    s->dy += dy1;
+    s->dz += dz1;
+    s->buttons_state = buttons_state;
+}
+
+
+static int adb_mouse_poll(ADBDevice *d, uint8_t *obuf)
+{
+    MouseState *s = ADB_MOUSE(d);
+    int dx, dy;
+
+    if (s->last_buttons_state == s->buttons_state &&
+        s->dx == 0 && s->dy == 0)
+        return 0;
+
+    dx = s->dx;
+    if (dx < -63)
+        dx = -63;
+    else if (dx > 63)
+        dx = 63;
+
+    dy = s->dy;
+    if (dy < -63)
+        dy = -63;
+    else if (dy > 63)
+        dy = 63;
+
+    s->dx -= dx;
+    s->dy -= dy;
+    s->last_buttons_state = s->buttons_state;
+
+    dx &= 0x7f;
+    dy &= 0x7f;
+
+    if (!(s->buttons_state & MOUSE_EVENT_LBUTTON))
+        dy |= 0x80;
+    if (!(s->buttons_state & MOUSE_EVENT_RBUTTON))
+        dx |= 0x80;
+
+    obuf[0] = dy;
+    obuf[1] = dx;
+    return 2;
+}
+
+static int adb_mouse_request(ADBDevice *d, uint8_t *obuf,
+                             const uint8_t *buf, int len)
+{
+    MouseState *s = ADB_MOUSE(d);
+    int cmd, reg, olen;
+
+    if ((buf[0] & 0x0f) == ADB_FLUSH) {
+        /* flush mouse fifo */
+        s->buttons_state = s->last_buttons_state;
+        s->dx = 0;
+        s->dy = 0;
+        s->dz = 0;
+        return 0;
+    }
+
+    cmd = buf[0] & 0xc;
+    reg = buf[0] & 0x3;
+    olen = 0;
+    switch(cmd) {
+    case ADB_WRITEREG:
+        ADB_DPRINTF("write reg %d val 0x%2.2x\n", reg, buf[1]);
+        switch(reg) {
+        case 2:
+            break;
+        case 3:
+            switch(buf[2]) {
+            case ADB_CMD_SELF_TEST:
+                break;
+            case ADB_CMD_CHANGE_ID:
+            case ADB_CMD_CHANGE_ID_AND_ACT:
+            case ADB_CMD_CHANGE_ID_AND_ENABLE:
+                d->devaddr = buf[1] & 0xf;
+                break;
+            default:
+                /* XXX: check this */
+                d->devaddr = buf[1] & 0xf;
+                break;
+            }
+        }
+        break;
+    case ADB_READREG:
+        switch(reg) {
+        case 0:
+            olen = adb_mouse_poll(d, obuf);
+            break;
+        case 1:
+            break;
+        case 3:
+            obuf[0] = d->handler;
+            obuf[1] = d->devaddr;
+            olen = 2;
+            break;
+        }
+        ADB_DPRINTF("read reg %d obuf[0] 0x%2.2x obuf[1] 0x%2.2x\n", reg,
+                    obuf[0], obuf[1]);
+        break;
+    }
+    return olen;
+}
+
+static void adb_mouse_reset(DeviceState *dev)
+{
+    ADBDevice *d = ADB_DEVICE(dev);
+    MouseState *s = ADB_MOUSE(dev);
+
+    d->handler = 2;
+    d->devaddr = ADB_DEVID_MOUSE;
+    s->last_buttons_state = s->buttons_state = 0;
+    s->dx = s->dy = s->dz = 0;
+}
+
+static const VMStateDescription vmstate_adb_mouse = {
+    .name = "adb_mouse",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_INT32(buttons_state, MouseState),
+        VMSTATE_INT32(last_buttons_state, MouseState),
+        VMSTATE_INT32(dx, MouseState),
+        VMSTATE_INT32(dy, MouseState),
+        VMSTATE_INT32(dz, MouseState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void adb_mouse_realizefn(DeviceState *dev, Error **errp)
+{
+    MouseState *s = ADB_MOUSE(dev);
+    ADBMouseClass *amc = ADB_MOUSE_GET_CLASS(dev);
+
+    amc->parent_realize(dev, errp);
+
+    qemu_add_mouse_event_handler(adb_mouse_event, s, 0, "QEMU ADB Mouse");
+}
+
+static void adb_mouse_initfn(Object *obj)
+{
+    ADBDevice *d = ADB_DEVICE(obj);
+
+    d->devaddr = ADB_DEVID_MOUSE;
+}
+
+static void adb_mouse_class_init(ObjectClass *oc, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(oc);
+    ADBDeviceClass *adc = ADB_DEVICE_CLASS(oc);
+    ADBMouseClass *amc = ADB_MOUSE_CLASS(oc);
+
+    amc->parent_realize = dc->realize;
+    dc->realize = adb_mouse_realizefn;
+
+    adc->devreq = adb_mouse_request;
+    dc->reset = adb_mouse_reset;
+    dc->vmsd = &vmstate_adb_mouse;
+}
+
+static const TypeInfo adb_mouse_type_info = {
+    .name = TYPE_ADB_MOUSE,
+    .parent = TYPE_ADB_DEVICE,
+    .instance_size = sizeof(MouseState),
+    .instance_init = adb_mouse_initfn,
+    .class_init = adb_mouse_class_init,
+    .class_size = sizeof(ADBMouseClass),
+};
+
+
+static void adb_register_types(void)
+{
+    type_register_static(&adb_bus_type_info);
+    type_register_static(&adb_device_type_info);
+    type_register_static(&adb_kbd_type_info);
+    type_register_static(&adb_mouse_type_info);
+}
+
+type_init(adb_register_types)
diff --git a/hw/input/hid.c b/hw/input/hid.c
new file mode 100644 (file)
index 0000000..5fbde98
--- /dev/null
@@ -0,0 +1,498 @@
+/*
+ * QEMU HID devices
+ *
+ * Copyright (c) 2005 Fabrice Bellard
+ * Copyright (c) 2007 OpenMoko, Inc.  (andrew@openedhand.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.
+ */
+#include "hw/hw.h"
+#include "ui/console.h"
+#include "qemu/timer.h"
+#include "hw/input/hid.h"
+
+#define HID_USAGE_ERROR_ROLLOVER        0x01
+#define HID_USAGE_POSTFAIL              0x02
+#define HID_USAGE_ERROR_UNDEFINED       0x03
+
+/* Indices are QEMU keycodes, values are from HID Usage Table.  Indices
+ * above 0x80 are for keys that come after 0xe0 or 0xe1+0x1d or 0xe1+0x9d.  */
+static const uint8_t hid_usage_keys[0x100] = {
+    0x00, 0x29, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
+    0x24, 0x25, 0x26, 0x27, 0x2d, 0x2e, 0x2a, 0x2b,
+    0x14, 0x1a, 0x08, 0x15, 0x17, 0x1c, 0x18, 0x0c,
+    0x12, 0x13, 0x2f, 0x30, 0x28, 0xe0, 0x04, 0x16,
+    0x07, 0x09, 0x0a, 0x0b, 0x0d, 0x0e, 0x0f, 0x33,
+    0x34, 0x35, 0xe1, 0x31, 0x1d, 0x1b, 0x06, 0x19,
+    0x05, 0x11, 0x10, 0x36, 0x37, 0x38, 0xe5, 0x55,
+    0xe2, 0x2c, 0x32, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e,
+    0x3f, 0x40, 0x41, 0x42, 0x43, 0x53, 0x47, 0x5f,
+    0x60, 0x61, 0x56, 0x5c, 0x5d, 0x5e, 0x57, 0x59,
+    0x5a, 0x5b, 0x62, 0x63, 0x00, 0x00, 0x00, 0x44,
+    0x45, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e,
+    0xe8, 0xe9, 0x71, 0x72, 0x73, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0xe3, 0xe7, 0x65,
+
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x58, 0xe4, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x46,
+    0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x4a,
+    0x52, 0x4b, 0x00, 0x50, 0x00, 0x4f, 0x00, 0x4d,
+    0x51, 0x4e, 0x49, 0x4c, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0xe3, 0xe7, 0x65, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+bool hid_has_events(HIDState *hs)
+{
+    return hs->n > 0 || hs->idle_pending;
+}
+
+static void hid_idle_timer(void *opaque)
+{
+    HIDState *hs = opaque;
+
+    hs->idle_pending = true;
+    hs->event(hs);
+}
+
+static void hid_del_idle_timer(HIDState *hs)
+{
+    if (hs->idle_timer) {
+        qemu_del_timer(hs->idle_timer);
+        qemu_free_timer(hs->idle_timer);
+        hs->idle_timer = NULL;
+    }
+}
+
+void hid_set_next_idle(HIDState *hs)
+{
+    if (hs->idle) {
+        uint64_t expire_time = qemu_get_clock_ns(vm_clock) +
+                               get_ticks_per_sec() * hs->idle * 4 / 1000;
+        if (!hs->idle_timer) {
+            hs->idle_timer = qemu_new_timer_ns(vm_clock, hid_idle_timer, hs);
+        }
+        qemu_mod_timer_ns(hs->idle_timer, expire_time);
+    } else {
+        hid_del_idle_timer(hs);
+    }
+}
+
+static void hid_pointer_event_clear(HIDPointerEvent *e, int buttons)
+{
+    e->xdx = e->ydy = e->dz = 0;
+    e->buttons_state = buttons;
+}
+
+static void hid_pointer_event_combine(HIDPointerEvent *e, int xyrel,
+                                      int x1, int y1, int z1) {
+    if (xyrel) {
+        e->xdx += x1;
+        e->ydy += y1;
+    } else {
+        e->xdx = x1;
+        e->ydy = y1;
+        /* Windows drivers do not like the 0/0 position and ignore such
+         * events. */
+        if (!(x1 | y1)) {
+            e->xdx = 1;
+        }
+    }
+    e->dz += z1;
+}
+
+static void hid_pointer_event(void *opaque,
+                              int x1, int y1, int z1, int buttons_state)
+{
+    HIDState *hs = opaque;
+    unsigned use_slot = (hs->head + hs->n - 1) & QUEUE_MASK;
+    unsigned previous_slot = (use_slot - 1) & QUEUE_MASK;
+
+    /* We combine events where feasible to keep the queue small.  We shouldn't
+     * combine anything with the first event of a particular button state, as
+     * that would change the location of the button state change.  When the
+     * queue is empty, a second event is needed because we don't know if
+     * the first event changed the button state.  */
+    if (hs->n == QUEUE_LENGTH) {
+        /* Queue full.  Discard old button state, combine motion normally.  */
+        hs->ptr.queue[use_slot].buttons_state = buttons_state;
+    } else if (hs->n < 2 ||
+               hs->ptr.queue[use_slot].buttons_state != buttons_state ||
+               hs->ptr.queue[previous_slot].buttons_state !=
+               hs->ptr.queue[use_slot].buttons_state) {
+        /* Cannot or should not combine, so add an empty item to the queue.  */
+        QUEUE_INCR(use_slot);
+        hs->n++;
+        hid_pointer_event_clear(&hs->ptr.queue[use_slot], buttons_state);
+    }
+    hid_pointer_event_combine(&hs->ptr.queue[use_slot],
+                              hs->kind == HID_MOUSE,
+                              x1, y1, z1);
+    hs->event(hs);
+}
+
+static void hid_keyboard_event(void *opaque, int keycode)
+{
+    HIDState *hs = opaque;
+    int slot;
+
+    if (hs->n == QUEUE_LENGTH) {
+        fprintf(stderr, "usb-kbd: warning: key event queue full\n");
+        return;
+    }
+    slot = (hs->head + hs->n) & QUEUE_MASK; hs->n++;
+    hs->kbd.keycodes[slot] = keycode;
+    hs->event(hs);
+}
+
+static void hid_keyboard_process_keycode(HIDState *hs)
+{
+    uint8_t hid_code, key;
+    int i, keycode, slot;
+
+    if (hs->n == 0) {
+        return;
+    }
+    slot = hs->head & QUEUE_MASK; QUEUE_INCR(hs->head); hs->n--;
+    keycode = hs->kbd.keycodes[slot];
+
+    key = keycode & 0x7f;
+    hid_code = hid_usage_keys[key | ((hs->kbd.modifiers >> 1) & (1 << 7))];
+    hs->kbd.modifiers &= ~(1 << 8);
+
+    switch (hid_code) {
+    case 0x00:
+        return;
+
+    case 0xe0:
+        if (hs->kbd.modifiers & (1 << 9)) {
+            hs->kbd.modifiers ^= 3 << 8;
+            return;
+        }
+    case 0xe1 ... 0xe7:
+        if (keycode & (1 << 7)) {
+            hs->kbd.modifiers &= ~(1 << (hid_code & 0x0f));
+            return;
+        }
+    case 0xe8 ... 0xef:
+        hs->kbd.modifiers |= 1 << (hid_code & 0x0f);
+        return;
+    }
+
+    if (keycode & (1 << 7)) {
+        for (i = hs->kbd.keys - 1; i >= 0; i--) {
+            if (hs->kbd.key[i] == hid_code) {
+                hs->kbd.key[i] = hs->kbd.key[-- hs->kbd.keys];
+                hs->kbd.key[hs->kbd.keys] = 0x00;
+                break;
+            }
+        }
+        if (i < 0) {
+            return;
+        }
+    } else {
+        for (i = hs->kbd.keys - 1; i >= 0; i--) {
+            if (hs->kbd.key[i] == hid_code) {
+                break;
+            }
+        }
+        if (i < 0) {
+            if (hs->kbd.keys < sizeof(hs->kbd.key)) {
+                hs->kbd.key[hs->kbd.keys++] = hid_code;
+            }
+        } else {
+            return;
+        }
+    }
+}
+
+static inline int int_clamp(int val, int vmin, int vmax)
+{
+    if (val < vmin) {
+        return vmin;
+    } else if (val > vmax) {
+        return vmax;
+    } else {
+        return val;
+    }
+}
+
+void hid_pointer_activate(HIDState *hs)
+{
+    if (!hs->ptr.mouse_grabbed) {
+        qemu_activate_mouse_event_handler(hs->ptr.eh_entry);
+        hs->ptr.mouse_grabbed = 1;
+    }
+}
+
+int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len)
+{
+    int dx, dy, dz, b, l;
+    int index;
+    HIDPointerEvent *e;
+
+    hs->idle_pending = false;
+
+    hid_pointer_activate(hs);
+
+    /* When the buffer is empty, return the last event.  Relative
+       movements will all be zero.  */
+    index = (hs->n ? hs->head : hs->head - 1);
+    e = &hs->ptr.queue[index & QUEUE_MASK];
+
+    if (hs->kind == HID_MOUSE) {
+        dx = int_clamp(e->xdx, -127, 127);
+        dy = int_clamp(e->ydy, -127, 127);
+        e->xdx -= dx;
+        e->ydy -= dy;
+    } else {
+        dx = e->xdx;
+        dy = e->ydy;
+    }
+    dz = int_clamp(e->dz, -127, 127);
+    e->dz -= dz;
+
+    b = 0;
+    if (e->buttons_state & MOUSE_EVENT_LBUTTON) {
+        b |= 0x01;
+    }
+    if (e->buttons_state & MOUSE_EVENT_RBUTTON) {
+        b |= 0x02;
+    }
+    if (e->buttons_state & MOUSE_EVENT_MBUTTON) {
+        b |= 0x04;
+    }
+
+    if (hs->n &&
+        !e->dz &&
+        (hs->kind == HID_TABLET || (!e->xdx && !e->ydy))) {
+        /* that deals with this event */
+        QUEUE_INCR(hs->head);
+        hs->n--;
+    }
+
+    /* Appears we have to invert the wheel direction */
+    dz = 0 - dz;
+    l = 0;
+    switch (hs->kind) {
+    case HID_MOUSE:
+        if (len > l) {
+            buf[l++] = b;
+        }
+        if (len > l) {
+            buf[l++] = dx;
+        }
+        if (len > l) {
+            buf[l++] = dy;
+        }
+        if (len > l) {
+            buf[l++] = dz;
+        }
+        break;
+
+    case HID_TABLET:
+        if (len > l) {
+            buf[l++] = b;
+        }
+        if (len > l) {
+            buf[l++] = dx & 0xff;
+        }
+        if (len > l) {
+            buf[l++] = dx >> 8;
+        }
+        if (len > l) {
+            buf[l++] = dy & 0xff;
+        }
+        if (len > l) {
+            buf[l++] = dy >> 8;
+        }
+        if (len > l) {
+            buf[l++] = dz;
+        }
+        break;
+
+    default:
+        abort();
+    }
+
+    return l;
+}
+
+int hid_keyboard_poll(HIDState *hs, uint8_t *buf, int len)
+{
+    hs->idle_pending = false;
+
+    if (len < 2) {
+        return 0;
+    }
+
+    hid_keyboard_process_keycode(hs);
+
+    buf[0] = hs->kbd.modifiers & 0xff;
+    buf[1] = 0;
+    if (hs->kbd.keys > 6) {
+        memset(buf + 2, HID_USAGE_ERROR_ROLLOVER, MIN(8, len) - 2);
+    } else {
+        memcpy(buf + 2, hs->kbd.key, MIN(8, len) - 2);
+    }
+
+    return MIN(8, len);
+}
+
+int hid_keyboard_write(HIDState *hs, uint8_t *buf, int len)
+{
+    if (len > 0) {
+        int ledstate = 0;
+        /* 0x01: Num Lock LED
+         * 0x02: Caps Lock LED
+         * 0x04: Scroll Lock LED
+         * 0x08: Compose LED
+         * 0x10: Kana LED */
+        hs->kbd.leds = buf[0];
+        if (hs->kbd.leds & 0x04) {
+            ledstate |= QEMU_SCROLL_LOCK_LED;
+        }
+        if (hs->kbd.leds & 0x01) {
+            ledstate |= QEMU_NUM_LOCK_LED;
+        }
+        if (hs->kbd.leds & 0x02) {
+            ledstate |= QEMU_CAPS_LOCK_LED;
+        }
+        kbd_put_ledstate(ledstate);
+    }
+    return 0;
+}
+
+void hid_reset(HIDState *hs)
+{
+    switch (hs->kind) {
+    case HID_KEYBOARD:
+        memset(hs->kbd.keycodes, 0, sizeof(hs->kbd.keycodes));
+        memset(hs->kbd.key, 0, sizeof(hs->kbd.key));
+        hs->kbd.keys = 0;
+        break;
+    case HID_MOUSE:
+    case HID_TABLET:
+        memset(hs->ptr.queue, 0, sizeof(hs->ptr.queue));
+        break;
+    }
+    hs->head = 0;
+    hs->n = 0;
+    hs->protocol = 1;
+    hs->idle = 0;
+    hs->idle_pending = false;
+    hid_del_idle_timer(hs);
+}
+
+void hid_free(HIDState *hs)
+{
+    switch (hs->kind) {
+    case HID_KEYBOARD:
+        qemu_remove_kbd_event_handler();
+        break;
+    case HID_MOUSE:
+    case HID_TABLET:
+        qemu_remove_mouse_event_handler(hs->ptr.eh_entry);
+        break;
+    }
+    hid_del_idle_timer(hs);
+}
+
+void hid_init(HIDState *hs, int kind, HIDEventFunc event)
+{
+    hs->kind = kind;
+    hs->event = event;
+
+    if (hs->kind == HID_KEYBOARD) {
+        qemu_add_kbd_event_handler(hid_keyboard_event, hs);
+    } else if (hs->kind == HID_MOUSE) {
+        hs->ptr.eh_entry = qemu_add_mouse_event_handler(hid_pointer_event, hs,
+                                                        0, "QEMU HID Mouse");
+    } else if (hs->kind == HID_TABLET) {
+        hs->ptr.eh_entry = qemu_add_mouse_event_handler(hid_pointer_event, hs,
+                                                        1, "QEMU HID Tablet");
+    }
+}
+
+static int hid_post_load(void *opaque, int version_id)
+{
+    HIDState *s = opaque;
+
+    hid_set_next_idle(s);
+    return 0;
+}
+
+static const VMStateDescription vmstate_hid_ptr_queue = {
+    .name = "HIDPointerEventQueue",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_INT32(xdx, HIDPointerEvent),
+        VMSTATE_INT32(ydy, HIDPointerEvent),
+        VMSTATE_INT32(dz, HIDPointerEvent),
+        VMSTATE_INT32(buttons_state, HIDPointerEvent),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+const VMStateDescription vmstate_hid_ptr_device = {
+    .name = "HIDPointerDevice",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .post_load = hid_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_STRUCT_ARRAY(ptr.queue, HIDState, QUEUE_LENGTH, 0,
+                             vmstate_hid_ptr_queue, HIDPointerEvent),
+        VMSTATE_UINT32(head, HIDState),
+        VMSTATE_UINT32(n, HIDState),
+        VMSTATE_INT32(protocol, HIDState),
+        VMSTATE_UINT8(idle, HIDState),
+        VMSTATE_END_OF_LIST(),
+    }
+};
+
+const VMStateDescription vmstate_hid_keyboard_device = {
+    .name = "HIDKeyboardDevice",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .post_load = hid_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(kbd.keycodes, HIDState, QUEUE_LENGTH),
+        VMSTATE_UINT32(head, HIDState),
+        VMSTATE_UINT32(n, HIDState),
+        VMSTATE_UINT16(kbd.modifiers, HIDState),
+        VMSTATE_UINT8(kbd.leds, HIDState),
+        VMSTATE_UINT8_ARRAY(kbd.key, HIDState, 16),
+        VMSTATE_INT32(kbd.keys, HIDState),
+        VMSTATE_INT32(protocol, HIDState),
+        VMSTATE_UINT8(idle, HIDState),
+        VMSTATE_END_OF_LIST(),
+    }
+};
diff --git a/hw/input/lm832x.c b/hw/input/lm832x.c
new file mode 100644 (file)
index 0000000..bacbeb2
--- /dev/null
@@ -0,0 +1,521 @@
+/*
+ * National Semiconductor LM8322/8323 GPIO keyboard & PWM chips.
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ * Written by Andrzej Zaborowski <andrew@openedhand.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 or
+ * (at your option) version 3 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
+ * 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 "hw/hw.h"
+#include "hw/i2c/i2c.h"
+#include "qemu/timer.h"
+#include "ui/console.h"
+
+typedef struct {
+    I2CSlave i2c;
+    uint8_t i2c_dir;
+    uint8_t i2c_cycle;
+    uint8_t reg;
+
+    qemu_irq nirq;
+    uint16_t model;
+
+    struct {
+        qemu_irq out[2];
+        int in[2][2];
+    } mux;
+
+    uint8_t config;
+    uint8_t status;
+    uint8_t acttime;
+    uint8_t error;
+    uint8_t clock;
+
+    struct {
+        uint16_t pull;
+        uint16_t mask;
+        uint16_t dir;
+        uint16_t level;
+        qemu_irq out[16];
+    } gpio;
+
+    struct {
+        uint8_t dbnctime;
+        uint8_t size;
+        uint8_t start;
+        uint8_t len;
+        uint8_t fifo[16];
+    } kbd;
+
+    struct {
+        uint16_t file[256];
+       uint8_t faddr;
+        uint8_t addr[3];
+        QEMUTimer *tm[3];
+    } pwm;
+} LM823KbdState;
+
+#define INT_KEYPAD             (1 << 0)
+#define INT_ERROR              (1 << 3)
+#define INT_NOINIT             (1 << 4)
+#define INT_PWMEND(n)          (1 << (5 + n))
+
+#define ERR_BADPAR             (1 << 0)
+#define ERR_CMDUNK             (1 << 1)
+#define ERR_KEYOVR             (1 << 2)
+#define ERR_FIFOOVR            (1 << 6)
+
+static void lm_kbd_irq_update(LM823KbdState *s)
+{
+    qemu_set_irq(s->nirq, !s->status);
+}
+
+static void lm_kbd_gpio_update(LM823KbdState *s)
+{
+}
+
+static void lm_kbd_reset(LM823KbdState *s)
+{
+    s->config = 0x80;
+    s->status = INT_NOINIT;
+    s->acttime = 125;
+    s->kbd.dbnctime = 3;
+    s->kbd.size = 0x33;
+    s->clock = 0x08;
+
+    lm_kbd_irq_update(s);
+    lm_kbd_gpio_update(s);
+}
+
+static void lm_kbd_error(LM823KbdState *s, int err)
+{
+    s->error |= err;
+    s->status |= INT_ERROR;
+    lm_kbd_irq_update(s);
+}
+
+static void lm_kbd_pwm_tick(LM823KbdState *s, int line)
+{
+}
+
+static void lm_kbd_pwm_start(LM823KbdState *s, int line)
+{
+    lm_kbd_pwm_tick(s, line);
+}
+
+static void lm_kbd_pwm0_tick(void *opaque)
+{
+    lm_kbd_pwm_tick(opaque, 0);
+}
+static void lm_kbd_pwm1_tick(void *opaque)
+{
+    lm_kbd_pwm_tick(opaque, 1);
+}
+static void lm_kbd_pwm2_tick(void *opaque)
+{
+    lm_kbd_pwm_tick(opaque, 2);
+}
+
+enum {
+    LM832x_CMD_READ_ID         = 0x80, /* Read chip ID. */
+    LM832x_CMD_WRITE_CFG       = 0x81, /* Set configuration item. */
+    LM832x_CMD_READ_INT                = 0x82, /* Get interrupt status. */
+    LM832x_CMD_RESET           = 0x83, /* Reset, same as external one */
+    LM823x_CMD_WRITE_PULL_DOWN = 0x84, /* Select GPIO pull-up/down. */
+    LM832x_CMD_WRITE_PORT_SEL  = 0x85, /* Select GPIO in/out. */
+    LM832x_CMD_WRITE_PORT_STATE        = 0x86, /* Set GPIO pull-up/down. */
+    LM832x_CMD_READ_PORT_SEL   = 0x87, /* Get GPIO in/out. */
+    LM832x_CMD_READ_PORT_STATE = 0x88, /* Get GPIO pull-up/down. */
+    LM832x_CMD_READ_FIFO       = 0x89, /* Read byte from FIFO. */
+    LM832x_CMD_RPT_READ_FIFO   = 0x8a, /* Read FIFO (no increment). */
+    LM832x_CMD_SET_ACTIVE      = 0x8b, /* Set active time. */
+    LM832x_CMD_READ_ERROR      = 0x8c, /* Get error status. */
+    LM832x_CMD_READ_ROTATOR    = 0x8e, /* Read rotator status. */
+    LM832x_CMD_SET_DEBOUNCE    = 0x8f, /* Set debouncing time. */
+    LM832x_CMD_SET_KEY_SIZE    = 0x90, /* Set keypad size. */
+    LM832x_CMD_READ_KEY_SIZE   = 0x91, /* Get keypad size. */
+    LM832x_CMD_READ_CFG                = 0x92, /* Get configuration item. */
+    LM832x_CMD_WRITE_CLOCK     = 0x93, /* Set clock config. */
+    LM832x_CMD_READ_CLOCK      = 0x94, /* Get clock config. */
+    LM832x_CMD_PWM_WRITE       = 0x95, /* Write PWM script. */
+    LM832x_CMD_PWM_START       = 0x96, /* Start PWM engine. */
+    LM832x_CMD_PWM_STOP                = 0x97, /* Stop PWM engine. */
+    LM832x_GENERAL_ERROR       = 0xff, /* There was one error.
+                                           Previously was represented by -1
+                                           This is not a command */
+};
+
+#define LM832x_MAX_KPX         8
+#define LM832x_MAX_KPY         12
+
+static uint8_t lm_kbd_read(LM823KbdState *s, int reg, int byte)
+{
+    int ret;
+
+    switch (reg) {
+    case LM832x_CMD_READ_ID:
+        ret = 0x0400;
+        break;
+
+    case LM832x_CMD_READ_INT:
+        ret = s->status;
+        if (!(s->status & INT_NOINIT)) {
+            s->status = 0;
+            lm_kbd_irq_update(s);
+        }
+        break;
+
+    case LM832x_CMD_READ_PORT_SEL:
+        ret = s->gpio.dir;
+        break;
+    case LM832x_CMD_READ_PORT_STATE:
+        ret = s->gpio.mask;
+        break;
+
+    case LM832x_CMD_READ_FIFO:
+        if (s->kbd.len <= 1)
+            return 0x00;
+
+        /* Example response from the two commands after a INT_KEYPAD
+         * interrupt caused by the key 0x3c being pressed:
+         * RPT_READ_FIFO: 55 bc 00 4e ff 0a 50 08 00 29 d9 08 01 c9 01
+         *     READ_FIFO: bc 00 00 4e ff 0a 50 08 00 29 d9 08 01 c9 01
+         * RPT_READ_FIFO: bc 00 00 4e ff 0a 50 08 00 29 d9 08 01 c9 01
+         *
+         * 55 is the code of the key release event serviced in the previous
+         * interrupt handling.
+         *
+         * TODO: find out whether the FIFO is advanced a single character
+         * before reading every byte or the whole size of the FIFO at the
+         * last LM832x_CMD_READ_FIFO.  This affects LM832x_CMD_RPT_READ_FIFO
+         * output in cases where there are more than one event in the FIFO.
+         * Assume 0xbc and 0x3c events are in the FIFO:
+         * RPT_READ_FIFO: 55 bc 3c 00 4e ff 0a 50 08 00 29 d9 08 01 c9
+         *     READ_FIFO: bc 3c 00 00 4e ff 0a 50 08 00 29 d9 08 01 c9
+         * Does RPT_READ_FIFO now return 0xbc and 0x3c or only 0x3c?
+         */
+        s->kbd.start ++;
+        s->kbd.start &= sizeof(s->kbd.fifo) - 1;
+        s->kbd.len --;
+
+        return s->kbd.fifo[s->kbd.start];
+    case LM832x_CMD_RPT_READ_FIFO:
+        if (byte >= s->kbd.len)
+            return 0x00;
+
+        return s->kbd.fifo[(s->kbd.start + byte) & (sizeof(s->kbd.fifo) - 1)];
+
+    case LM832x_CMD_READ_ERROR:
+        return s->error;
+
+    case LM832x_CMD_READ_ROTATOR:
+        return 0;
+
+    case LM832x_CMD_READ_KEY_SIZE:
+        return s->kbd.size;
+
+    case LM832x_CMD_READ_CFG:
+        return s->config & 0xf;
+
+    case LM832x_CMD_READ_CLOCK:
+        return (s->clock & 0xfc) | 2;
+
+    default:
+        lm_kbd_error(s, ERR_CMDUNK);
+        fprintf(stderr, "%s: unknown command %02x\n", __FUNCTION__, reg);
+        return 0x00;
+    }
+
+    return ret >> (byte << 3);
+}
+
+static void lm_kbd_write(LM823KbdState *s, int reg, int byte, uint8_t value)
+{
+    switch (reg) {
+    case LM832x_CMD_WRITE_CFG:
+        s->config = value;
+        /* This must be done whenever s->mux.in is updated (never).  */
+        if ((s->config >> 1) & 1)                      /* MUX1EN */
+            qemu_set_irq(s->mux.out[0], s->mux.in[0][(s->config >> 0) & 1]);
+        if ((s->config >> 3) & 1)                      /* MUX2EN */
+            qemu_set_irq(s->mux.out[0], s->mux.in[0][(s->config >> 2) & 1]);
+        /* TODO: check that this is issued only following the chip reset
+         * and not in the middle of operation and that it is followed by
+         * the GPIO ports re-resablishing through WRITE_PORT_SEL and
+         * WRITE_PORT_STATE (using a timer perhaps) and otherwise output
+         * warnings.  */
+        s->status = 0;
+        lm_kbd_irq_update(s);
+        s->kbd.len = 0;
+        s->kbd.start = 0;
+        s->reg = LM832x_GENERAL_ERROR;
+        break;
+
+    case LM832x_CMD_RESET:
+        if (value == 0xaa)
+            lm_kbd_reset(s);
+        else
+            lm_kbd_error(s, ERR_BADPAR);
+        s->reg = LM832x_GENERAL_ERROR;
+        break;
+
+    case LM823x_CMD_WRITE_PULL_DOWN:
+        if (!byte)
+            s->gpio.pull = value;
+        else {
+            s->gpio.pull |= value << 8;
+            lm_kbd_gpio_update(s);
+            s->reg = LM832x_GENERAL_ERROR;
+        }
+        break;
+    case LM832x_CMD_WRITE_PORT_SEL:
+        if (!byte)
+            s->gpio.dir = value;
+        else {
+            s->gpio.dir |= value << 8;
+            lm_kbd_gpio_update(s);
+            s->reg = LM832x_GENERAL_ERROR;
+        }
+        break;
+    case LM832x_CMD_WRITE_PORT_STATE:
+        if (!byte)
+            s->gpio.mask = value;
+        else {
+            s->gpio.mask |= value << 8;
+            lm_kbd_gpio_update(s);
+            s->reg = LM832x_GENERAL_ERROR;
+        }
+        break;
+
+    case LM832x_CMD_SET_ACTIVE:
+        s->acttime = value;
+        s->reg = LM832x_GENERAL_ERROR;
+        break;
+
+    case LM832x_CMD_SET_DEBOUNCE:
+        s->kbd.dbnctime = value;
+        s->reg = LM832x_GENERAL_ERROR;
+        if (!value)
+            lm_kbd_error(s, ERR_BADPAR);
+        break;
+
+    case LM832x_CMD_SET_KEY_SIZE:
+        s->kbd.size = value;
+        s->reg = LM832x_GENERAL_ERROR;
+        if (
+                        (value & 0xf) < 3 || (value & 0xf) > LM832x_MAX_KPY ||
+                        (value >> 4) < 3 || (value >> 4) > LM832x_MAX_KPX)
+            lm_kbd_error(s, ERR_BADPAR);
+        break;
+
+    case LM832x_CMD_WRITE_CLOCK:
+        s->clock = value;
+        s->reg = LM832x_GENERAL_ERROR;
+        if ((value & 3) && (value & 3) != 3) {
+            lm_kbd_error(s, ERR_BADPAR);
+            fprintf(stderr, "%s: invalid clock setting in RCPWM\n",
+                            __FUNCTION__);
+        }
+        /* TODO: Validate that the command is only issued once */
+        break;
+
+    case LM832x_CMD_PWM_WRITE:
+        if (byte == 0) {
+            if (!(value & 3) || (value >> 2) > 59) {
+                lm_kbd_error(s, ERR_BADPAR);
+                s->reg = LM832x_GENERAL_ERROR;
+                break;
+            }
+
+            s->pwm.faddr = value;
+            s->pwm.file[s->pwm.faddr] = 0;
+        } else if (byte == 1) {
+            s->pwm.file[s->pwm.faddr] |= value << 8;
+        } else if (byte == 2) {
+            s->pwm.file[s->pwm.faddr] |= value << 0;
+            s->reg = LM832x_GENERAL_ERROR;
+        }
+        break;
+    case LM832x_CMD_PWM_START:
+        s->reg = LM832x_GENERAL_ERROR;
+        if (!(value & 3) || (value >> 2) > 59) {
+            lm_kbd_error(s, ERR_BADPAR);
+            break;
+        }
+
+        s->pwm.addr[(value & 3) - 1] = value >> 2;
+        lm_kbd_pwm_start(s, (value & 3) - 1);
+        break;
+    case LM832x_CMD_PWM_STOP:
+        s->reg = LM832x_GENERAL_ERROR;
+        if (!(value & 3)) {
+            lm_kbd_error(s, ERR_BADPAR);
+            break;
+        }
+
+        qemu_del_timer(s->pwm.tm[(value & 3) - 1]);
+        break;
+
+    case LM832x_GENERAL_ERROR:
+        lm_kbd_error(s, ERR_BADPAR);
+        break;
+    default:
+        lm_kbd_error(s, ERR_CMDUNK);
+        fprintf(stderr, "%s: unknown command %02x\n", __FUNCTION__, reg);
+        break;
+    }
+}
+
+static void lm_i2c_event(I2CSlave *i2c, enum i2c_event event)
+{
+    LM823KbdState *s = FROM_I2C_SLAVE(LM823KbdState, i2c);
+
+    switch (event) {
+    case I2C_START_RECV:
+    case I2C_START_SEND:
+        s->i2c_cycle = 0;
+        s->i2c_dir = (event == I2C_START_SEND);
+        break;
+
+    default:
+        break;
+    }
+}
+
+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(I2CSlave *i2c, uint8_t data)
+{
+    LM823KbdState *s = (LM823KbdState *) i2c;
+
+    if (!s->i2c_cycle)
+        s->reg = data;
+    else
+        lm_kbd_write(s, s->reg, s->i2c_cycle - 1, data);
+    s->i2c_cycle ++;
+
+    return 0;
+}
+
+static int lm_kbd_post_load(void *opaque, int version_id)
+{
+    LM823KbdState *s = opaque;
+
+    lm_kbd_irq_update(s);
+    lm_kbd_gpio_update(s);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_lm_kbd = {
+    .name = "LM8323",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .post_load = lm_kbd_post_load,
+    .fields      = (VMStateField []) {
+        VMSTATE_I2C_SLAVE(i2c, LM823KbdState),
+        VMSTATE_UINT8(i2c_dir, LM823KbdState),
+        VMSTATE_UINT8(i2c_cycle, LM823KbdState),
+        VMSTATE_UINT8(reg, LM823KbdState),
+        VMSTATE_UINT8(config, LM823KbdState),
+        VMSTATE_UINT8(status, LM823KbdState),
+        VMSTATE_UINT8(acttime, LM823KbdState),
+        VMSTATE_UINT8(error, LM823KbdState),
+        VMSTATE_UINT8(clock, LM823KbdState),
+        VMSTATE_UINT16(gpio.pull, LM823KbdState),
+        VMSTATE_UINT16(gpio.mask, LM823KbdState),
+        VMSTATE_UINT16(gpio.dir, LM823KbdState),
+        VMSTATE_UINT16(gpio.level, LM823KbdState),
+        VMSTATE_UINT8(kbd.dbnctime, LM823KbdState),
+        VMSTATE_UINT8(kbd.size, LM823KbdState),
+        VMSTATE_UINT8(kbd.start, LM823KbdState),
+        VMSTATE_UINT8(kbd.len, LM823KbdState),
+        VMSTATE_BUFFER(kbd.fifo, LM823KbdState),
+        VMSTATE_UINT16_ARRAY(pwm.file, LM823KbdState, 256),
+        VMSTATE_UINT8(pwm.faddr, LM823KbdState),
+        VMSTATE_BUFFER(pwm.addr, LM823KbdState),
+        VMSTATE_TIMER_ARRAY(pwm.tm, LM823KbdState, 3),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+
+static int lm8323_init(I2CSlave *i2c)
+{
+    LM823KbdState *s = FROM_I2C_SLAVE(LM823KbdState, i2c);
+
+    s->model = 0x8323;
+    s->pwm.tm[0] = qemu_new_timer_ns(vm_clock, lm_kbd_pwm0_tick, s);
+    s->pwm.tm[1] = qemu_new_timer_ns(vm_clock, lm_kbd_pwm1_tick, s);
+    s->pwm.tm[2] = qemu_new_timer_ns(vm_clock, lm_kbd_pwm2_tick, s);
+    qdev_init_gpio_out(&i2c->qdev, &s->nirq, 1);
+
+    lm_kbd_reset(s);
+
+    qemu_register_reset((void *) lm_kbd_reset, s);
+    return 0;
+}
+
+void lm832x_key_event(DeviceState *dev, int key, int state)
+{
+    LM823KbdState *s = FROM_I2C_SLAVE(LM823KbdState, I2C_SLAVE(dev));
+
+    if ((s->status & INT_ERROR) && (s->error & ERR_FIFOOVR))
+        return;
+
+    if (s->kbd.len >= sizeof(s->kbd.fifo)) {
+        lm_kbd_error(s, ERR_FIFOOVR);
+        return;
+    }
+
+    s->kbd.fifo[(s->kbd.start + s->kbd.len ++) & (sizeof(s->kbd.fifo) - 1)] =
+            key | (state << 7);
+
+    /* We never set ERR_KEYOVR because we support multiple keys fine.  */
+    s->status |= INT_KEYPAD;
+    lm_kbd_irq_update(s);
+}
+
+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 const TypeInfo lm8323_info = {
+    .name          = "lm8323",
+    .parent        = TYPE_I2C_SLAVE,
+    .instance_size = sizeof(LM823KbdState),
+    .class_init    = lm8323_class_init,
+};
+
+static void lm832x_register_types(void)
+{
+    type_register_static(&lm8323_info);
+}
+
+type_init(lm832x_register_types)
diff --git a/hw/input/milkymist-softusb.c b/hw/input/milkymist-softusb.c
new file mode 100644 (file)
index 0000000..3edab4f
--- /dev/null
@@ -0,0 +1,334 @@
+/*
+ *  QEMU model of the Milkymist SoftUSB block.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
+ *
+ * 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/>.
+ *
+ *
+ * Specification available at:
+ *   not available yet
+ */
+
+#include "hw/hw.h"
+#include "hw/sysbus.h"
+#include "trace.h"
+#include "ui/console.h"
+#include "hw/input/hid.h"
+#include "qemu/error-report.h"
+
+enum {
+    R_CTRL = 0,
+    R_MAX
+};
+
+enum {
+    CTRL_RESET = (1<<0),
+};
+
+#define COMLOC_DEBUG_PRODUCE 0x1000
+#define COMLOC_DEBUG_BASE    0x1001
+#define COMLOC_MEVT_PRODUCE  0x1101
+#define COMLOC_MEVT_BASE     0x1102
+#define COMLOC_KEVT_PRODUCE  0x1142
+#define COMLOC_KEVT_BASE     0x1143
+
+struct MilkymistSoftUsbState {
+    SysBusDevice busdev;
+    HIDState hid_kbd;
+    HIDState hid_mouse;
+
+    MemoryRegion regs_region;
+    MemoryRegion pmem;
+    MemoryRegion dmem;
+    qemu_irq irq;
+
+    void *pmem_ptr;
+    void *dmem_ptr;
+
+    /* device properties */
+    uint32_t pmem_size;
+    uint32_t dmem_size;
+
+    /* device registers */
+    uint32_t regs[R_MAX];
+
+    /* mouse state */
+    uint8_t mouse_hid_buffer[4];
+
+    /* keyboard state */
+    uint8_t kbd_hid_buffer[8];
+};
+typedef struct MilkymistSoftUsbState MilkymistSoftUsbState;
+
+static uint64_t softusb_read(void *opaque, hwaddr addr,
+                             unsigned size)
+{
+    MilkymistSoftUsbState *s = opaque;
+    uint32_t r = 0;
+
+    addr >>= 2;
+    switch (addr) {
+    case R_CTRL:
+        r = s->regs[addr];
+        break;
+
+    default:
+        error_report("milkymist_softusb: read access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+
+    trace_milkymist_softusb_memory_read(addr << 2, r);
+
+    return r;
+}
+
+static void
+softusb_write(void *opaque, hwaddr addr, uint64_t value,
+              unsigned size)
+{
+    MilkymistSoftUsbState *s = opaque;
+
+    trace_milkymist_softusb_memory_write(addr, value);
+
+    addr >>= 2;
+    switch (addr) {
+    case R_CTRL:
+        s->regs[addr] = value;
+        break;
+
+    default:
+        error_report("milkymist_softusb: write access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+}
+
+static const MemoryRegionOps softusb_mmio_ops = {
+    .read = softusb_read,
+    .write = softusb_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static inline void softusb_read_dmem(MilkymistSoftUsbState *s,
+        uint32_t offset, uint8_t *buf, uint32_t len)
+{
+    if (offset + len >= s->dmem_size) {
+        error_report("milkymist_softusb: read dmem out of bounds "
+                "at offset 0x%x, len %d", offset, len);
+        memset(buf, 0, len);
+        return;
+    }
+
+    memcpy(buf, s->dmem_ptr + offset, len);
+}
+
+static inline void softusb_write_dmem(MilkymistSoftUsbState *s,
+        uint32_t offset, uint8_t *buf, uint32_t len)
+{
+    if (offset + len >= s->dmem_size) {
+        error_report("milkymist_softusb: write dmem out of bounds "
+                "at offset 0x%x, len %d", offset, len);
+        return;
+    }
+
+    memcpy(s->dmem_ptr + offset, buf, len);
+}
+
+static inline void softusb_read_pmem(MilkymistSoftUsbState *s,
+        uint32_t offset, uint8_t *buf, uint32_t len)
+{
+    if (offset + len >= s->pmem_size) {
+        error_report("milkymist_softusb: read pmem out of bounds "
+                "at offset 0x%x, len %d", offset, len);
+        memset(buf, 0, len);
+        return;
+    }
+
+    memcpy(buf, s->pmem_ptr + offset, len);
+}
+
+static inline void softusb_write_pmem(MilkymistSoftUsbState *s,
+        uint32_t offset, uint8_t *buf, uint32_t len)
+{
+    if (offset + len >= s->pmem_size) {
+        error_report("milkymist_softusb: write pmem out of bounds "
+                "at offset 0x%x, len %d", offset, len);
+        return;
+    }
+
+    memcpy(s->pmem_ptr + offset, buf, len);
+}
+
+static void softusb_mouse_changed(MilkymistSoftUsbState *s)
+{
+    uint8_t m;
+
+    softusb_read_dmem(s, COMLOC_MEVT_PRODUCE, &m, 1);
+    trace_milkymist_softusb_mevt(m);
+    softusb_write_dmem(s, COMLOC_MEVT_BASE + 4 * m, s->mouse_hid_buffer, 4);
+    m = (m + 1) & 0xf;
+    softusb_write_dmem(s, COMLOC_MEVT_PRODUCE, &m, 1);
+
+    trace_milkymist_softusb_pulse_irq();
+    qemu_irq_pulse(s->irq);
+}
+
+static void softusb_kbd_changed(MilkymistSoftUsbState *s)
+{
+    uint8_t m;
+
+    softusb_read_dmem(s, COMLOC_KEVT_PRODUCE, &m, 1);
+    trace_milkymist_softusb_kevt(m);
+    softusb_write_dmem(s, COMLOC_KEVT_BASE + 8 * m, s->kbd_hid_buffer, 8);
+    m = (m + 1) & 0x7;
+    softusb_write_dmem(s, COMLOC_KEVT_PRODUCE, &m, 1);
+
+    trace_milkymist_softusb_pulse_irq();
+    qemu_irq_pulse(s->irq);
+}
+
+static void softusb_kbd_hid_datain(HIDState *hs)
+{
+    MilkymistSoftUsbState *s = container_of(hs, MilkymistSoftUsbState, hid_kbd);
+    int len;
+
+    /* if device is in reset, do nothing */
+    if (s->regs[R_CTRL] & CTRL_RESET) {
+        return;
+    }
+
+    len = hid_keyboard_poll(hs, s->kbd_hid_buffer, sizeof(s->kbd_hid_buffer));
+
+    if (len == 8) {
+        softusb_kbd_changed(s);
+    }
+}
+
+static void softusb_mouse_hid_datain(HIDState *hs)
+{
+    MilkymistSoftUsbState *s =
+            container_of(hs, MilkymistSoftUsbState, hid_mouse);
+    int len;
+
+    /* if device is in reset, do nothing */
+    if (s->regs[R_CTRL] & CTRL_RESET) {
+        return;
+    }
+
+    len = hid_pointer_poll(hs, s->mouse_hid_buffer,
+            sizeof(s->mouse_hid_buffer));
+
+    if (len == 4) {
+        softusb_mouse_changed(s);
+    }
+}
+
+static void milkymist_softusb_reset(DeviceState *d)
+{
+    MilkymistSoftUsbState *s =
+            container_of(d, MilkymistSoftUsbState, busdev.qdev);
+    int i;
+
+    for (i = 0; i < R_MAX; i++) {
+        s->regs[i] = 0;
+    }
+    memset(s->kbd_hid_buffer, 0, sizeof(s->kbd_hid_buffer));
+    memset(s->mouse_hid_buffer, 0, sizeof(s->mouse_hid_buffer));
+
+    hid_reset(&s->hid_kbd);
+    hid_reset(&s->hid_mouse);
+
+    /* defaults */
+    s->regs[R_CTRL] = CTRL_RESET;
+}
+
+static int milkymist_softusb_init(SysBusDevice *dev)
+{
+    MilkymistSoftUsbState *s = FROM_SYSBUS(typeof(*s), dev);
+
+    sysbus_init_irq(dev, &s->irq);
+
+    memory_region_init_io(&s->regs_region, &softusb_mmio_ops, s,
+                          "milkymist-softusb", R_MAX * 4);
+    sysbus_init_mmio(dev, &s->regs_region);
+
+    /* register pmem and dmem */
+    memory_region_init_ram(&s->pmem, "milkymist-softusb.pmem",
+                           s->pmem_size);
+    vmstate_register_ram_global(&s->pmem);
+    s->pmem_ptr = memory_region_get_ram_ptr(&s->pmem);
+    sysbus_init_mmio(dev, &s->pmem);
+    memory_region_init_ram(&s->dmem, "milkymist-softusb.dmem",
+                           s->dmem_size);
+    vmstate_register_ram_global(&s->dmem);
+    s->dmem_ptr = memory_region_get_ram_ptr(&s->dmem);
+    sysbus_init_mmio(dev, &s->dmem);
+
+    hid_init(&s->hid_kbd, HID_KEYBOARD, softusb_kbd_hid_datain);
+    hid_init(&s->hid_mouse, HID_MOUSE, softusb_mouse_hid_datain);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_milkymist_softusb = {
+    .name = "milkymist-softusb",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(regs, MilkymistSoftUsbState, R_MAX),
+        VMSTATE_HID_KEYBOARD_DEVICE(hid_kbd, MilkymistSoftUsbState),
+        VMSTATE_HID_POINTER_DEVICE(hid_mouse, MilkymistSoftUsbState),
+        VMSTATE_BUFFER(kbd_hid_buffer, MilkymistSoftUsbState),
+        VMSTATE_BUFFER(mouse_hid_buffer, MilkymistSoftUsbState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static Property milkymist_softusb_properties[] = {
+    DEFINE_PROP_UINT32("pmem_size", MilkymistSoftUsbState, pmem_size, 0x00001000),
+    DEFINE_PROP_UINT32("dmem_size", MilkymistSoftUsbState, dmem_size, 0x00002000),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void milkymist_softusb_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = milkymist_softusb_init;
+    dc->reset = milkymist_softusb_reset;
+    dc->vmsd = &vmstate_milkymist_softusb;
+    dc->props = milkymist_softusb_properties;
+}
+
+static const 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_types(void)
+{
+    type_register_static(&milkymist_softusb_info);
+}
+
+type_init(milkymist_softusb_register_types)
diff --git a/hw/input/pckbd.c b/hw/input/pckbd.c
new file mode 100644 (file)
index 0000000..08ceb9f
--- /dev/null
@@ -0,0 +1,527 @@
+/*
+ * QEMU PC keyboard emulation
+ *
+ * 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.
+ */
+#include "hw/hw.h"
+#include "hw/isa/isa.h"
+#include "hw/i386/pc.h"
+#include "hw/input/ps2.h"
+#include "sysemu/sysemu.h"
+
+/* debug PC keyboard */
+//#define DEBUG_KBD
+#ifdef DEBUG_KBD
+#define DPRINTF(fmt, ...)                                       \
+    do { printf("KBD: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...)
+#endif
+
+/*     Keyboard Controller Commands */
+#define KBD_CCMD_READ_MODE     0x20    /* Read mode bits */
+#define KBD_CCMD_WRITE_MODE    0x60    /* Write mode bits */
+#define KBD_CCMD_GET_VERSION   0xA1    /* Get controller version */
+#define KBD_CCMD_MOUSE_DISABLE 0xA7    /* Disable mouse interface */
+#define KBD_CCMD_MOUSE_ENABLE  0xA8    /* Enable mouse interface */
+#define KBD_CCMD_TEST_MOUSE    0xA9    /* Mouse interface test */
+#define KBD_CCMD_SELF_TEST     0xAA    /* Controller self test */
+#define KBD_CCMD_KBD_TEST      0xAB    /* Keyboard interface test */
+#define KBD_CCMD_KBD_DISABLE   0xAD    /* Keyboard interface disable */
+#define KBD_CCMD_KBD_ENABLE    0xAE    /* Keyboard interface enable */
+#define KBD_CCMD_READ_INPORT    0xC0    /* read input port */
+#define KBD_CCMD_READ_OUTPORT  0xD0    /* read output port */
+#define KBD_CCMD_WRITE_OUTPORT 0xD1    /* write output port */
+#define KBD_CCMD_WRITE_OBUF    0xD2
+#define KBD_CCMD_WRITE_AUX_OBUF        0xD3    /* Write to output buffer as if
+                                          initiated by the auxiliary device */
+#define KBD_CCMD_WRITE_MOUSE   0xD4    /* Write the following byte to the mouse */
+#define KBD_CCMD_DISABLE_A20    0xDD    /* HP vectra only ? */
+#define KBD_CCMD_ENABLE_A20     0xDF    /* HP vectra only ? */
+#define KBD_CCMD_PULSE_BITS_3_0 0xF0    /* Pulse bits 3-0 of the output port P2. */
+#define KBD_CCMD_RESET          0xFE    /* Pulse bit 0 of the output port P2 = CPU reset. */
+#define KBD_CCMD_NO_OP          0xFF    /* Pulse no bits of the output port P2. */
+
+/* Keyboard Commands */
+#define KBD_CMD_SET_LEDS       0xED    /* Set keyboard leds */
+#define KBD_CMD_ECHO           0xEE
+#define KBD_CMD_GET_ID                 0xF2    /* get keyboard ID */
+#define KBD_CMD_SET_RATE       0xF3    /* Set typematic rate */
+#define KBD_CMD_ENABLE         0xF4    /* Enable scanning */
+#define KBD_CMD_RESET_DISABLE  0xF5    /* reset and disable scanning */
+#define KBD_CMD_RESET_ENABLE           0xF6    /* reset and enable scanning */
+#define KBD_CMD_RESET          0xFF    /* Reset */
+
+/* Keyboard Replies */
+#define KBD_REPLY_POR          0xAA    /* Power on reset */
+#define KBD_REPLY_ACK          0xFA    /* Command ACK */
+#define KBD_REPLY_RESEND       0xFE    /* Command NACK, send the cmd again */
+
+/* Status Register Bits */
+#define KBD_STAT_OBF           0x01    /* Keyboard output buffer full */
+#define KBD_STAT_IBF           0x02    /* Keyboard input buffer full */
+#define KBD_STAT_SELFTEST      0x04    /* Self test successful */
+#define KBD_STAT_CMD           0x08    /* Last write was a command write (0=data) */
+#define KBD_STAT_UNLOCKED      0x10    /* Zero if keyboard locked */
+#define KBD_STAT_MOUSE_OBF     0x20    /* Mouse output buffer full */
+#define KBD_STAT_GTO           0x40    /* General receive/xmit timeout */
+#define KBD_STAT_PERR          0x80    /* Parity error */
+
+/* Controller Mode Register Bits */
+#define KBD_MODE_KBD_INT       0x01    /* Keyboard data generate IRQ1 */
+#define KBD_MODE_MOUSE_INT     0x02    /* Mouse data generate IRQ12 */
+#define KBD_MODE_SYS           0x04    /* The system flag (?) */
+#define KBD_MODE_NO_KEYLOCK    0x08    /* The keylock doesn't affect the keyboard if set */
+#define KBD_MODE_DISABLE_KBD   0x10    /* Disable keyboard interface */
+#define KBD_MODE_DISABLE_MOUSE 0x20    /* Disable mouse interface */
+#define KBD_MODE_KCC           0x40    /* Scan code conversion to PC format */
+#define KBD_MODE_RFU           0x80
+
+/* Output Port Bits */
+#define KBD_OUT_RESET           0x01    /* 1=normal mode, 0=reset */
+#define KBD_OUT_A20             0x02    /* x86 only */
+#define KBD_OUT_OBF             0x10    /* Keyboard output buffer full */
+#define KBD_OUT_MOUSE_OBF       0x20    /* Mouse output buffer full */
+
+/* Mouse Commands */
+#define AUX_SET_SCALE11                0xE6    /* Set 1:1 scaling */
+#define AUX_SET_SCALE21                0xE7    /* Set 2:1 scaling */
+#define AUX_SET_RES            0xE8    /* Set resolution */
+#define AUX_GET_SCALE          0xE9    /* Get scaling factor */
+#define AUX_SET_STREAM         0xEA    /* Set stream mode */
+#define AUX_POLL               0xEB    /* Poll */
+#define AUX_RESET_WRAP         0xEC    /* Reset wrap mode */
+#define AUX_SET_WRAP           0xEE    /* Set wrap mode */
+#define AUX_SET_REMOTE         0xF0    /* Set remote mode */
+#define AUX_GET_TYPE           0xF2    /* Get type */
+#define AUX_SET_SAMPLE         0xF3    /* Set sample rate */
+#define AUX_ENABLE_DEV         0xF4    /* Enable aux device */
+#define AUX_DISABLE_DEV                0xF5    /* Disable aux device */
+#define AUX_SET_DEFAULT                0xF6
+#define AUX_RESET              0xFF    /* Reset aux device */
+#define AUX_ACK                        0xFA    /* Command byte ACK. */
+
+#define MOUSE_STATUS_REMOTE     0x40
+#define MOUSE_STATUS_ENABLED    0x20
+#define MOUSE_STATUS_SCALE21    0x10
+
+#define KBD_PENDING_KBD         1
+#define KBD_PENDING_AUX         2
+
+typedef struct KBDState {
+    uint8_t write_cmd; /* if non zero, write data to port 60 is expected */
+    uint8_t status;
+    uint8_t mode;
+    uint8_t outport;
+    /* Bitmask of devices with data available.  */
+    uint8_t pending;
+    void *kbd;
+    void *mouse;
+
+    qemu_irq irq_kbd;
+    qemu_irq irq_mouse;
+    qemu_irq *a20_out;
+    hwaddr mask;
+} KBDState;
+
+/* update irq and KBD_STAT_[MOUSE_]OBF */
+/* XXX: not generating the irqs if KBD_MODE_DISABLE_KBD is set may be
+   incorrect, but it avoids having to simulate exact delays */
+static void kbd_update_irq(KBDState *s)
+{
+    int irq_kbd_level, irq_mouse_level;
+
+    irq_kbd_level = 0;
+    irq_mouse_level = 0;
+    s->status &= ~(KBD_STAT_OBF | KBD_STAT_MOUSE_OBF);
+    s->outport &= ~(KBD_OUT_OBF | KBD_OUT_MOUSE_OBF);
+    if (s->pending) {
+        s->status |= KBD_STAT_OBF;
+        s->outport |= KBD_OUT_OBF;
+        /* kbd data takes priority over aux data.  */
+        if (s->pending == KBD_PENDING_AUX) {
+            s->status |= KBD_STAT_MOUSE_OBF;
+            s->outport |= KBD_OUT_MOUSE_OBF;
+            if (s->mode & KBD_MODE_MOUSE_INT)
+                irq_mouse_level = 1;
+        } else {
+            if ((s->mode & KBD_MODE_KBD_INT) &&
+                !(s->mode & KBD_MODE_DISABLE_KBD))
+                irq_kbd_level = 1;
+        }
+    }
+    qemu_set_irq(s->irq_kbd, irq_kbd_level);
+    qemu_set_irq(s->irq_mouse, irq_mouse_level);
+}
+
+static void kbd_update_kbd_irq(void *opaque, int level)
+{
+    KBDState *s = (KBDState *)opaque;
+
+    if (level)
+        s->pending |= KBD_PENDING_KBD;
+    else
+        s->pending &= ~KBD_PENDING_KBD;
+    kbd_update_irq(s);
+}
+
+static void kbd_update_aux_irq(void *opaque, int level)
+{
+    KBDState *s = (KBDState *)opaque;
+
+    if (level)
+        s->pending |= KBD_PENDING_AUX;
+    else
+        s->pending &= ~KBD_PENDING_AUX;
+    kbd_update_irq(s);
+}
+
+static uint64_t kbd_read_status(void *opaque, hwaddr addr,
+                                unsigned size)
+{
+    KBDState *s = opaque;
+    int val;
+    val = s->status;
+    DPRINTF("kbd: read status=0x%02x\n", val);
+    return val;
+}
+
+static void kbd_queue(KBDState *s, int b, int aux)
+{
+    if (aux)
+        ps2_queue(s->mouse, b);
+    else
+        ps2_queue(s->kbd, b);
+}
+
+static void outport_write(KBDState *s, uint32_t val)
+{
+    DPRINTF("kbd: write outport=0x%02x\n", val);
+    s->outport = val;
+    if (s->a20_out) {
+        qemu_set_irq(*s->a20_out, (val >> 1) & 1);
+    }
+    if (!(val & 1)) {
+        qemu_system_reset_request();
+    }
+}
+
+static void kbd_write_command(void *opaque, hwaddr addr,
+                              uint64_t val, unsigned size)
+{
+    KBDState *s = opaque;
+
+    DPRINTF("kbd: write cmd=0x%02x\n", val);
+
+    /* Bits 3-0 of the output port P2 of the keyboard controller may be pulsed
+     * low for approximately 6 micro seconds. Bits 3-0 of the KBD_CCMD_PULSE
+     * command specify the output port bits to be pulsed.
+     * 0: Bit should be pulsed. 1: Bit should not be modified.
+     * The only useful version of this command is pulsing bit 0,
+     * which does a CPU reset.
+     */
+    if((val & KBD_CCMD_PULSE_BITS_3_0) == KBD_CCMD_PULSE_BITS_3_0) {
+        if(!(val & 1))
+            val = KBD_CCMD_RESET;
+        else
+            val = KBD_CCMD_NO_OP;
+    }
+
+    switch(val) {
+    case KBD_CCMD_READ_MODE:
+        kbd_queue(s, s->mode, 0);
+        break;
+    case KBD_CCMD_WRITE_MODE:
+    case KBD_CCMD_WRITE_OBUF:
+    case KBD_CCMD_WRITE_AUX_OBUF:
+    case KBD_CCMD_WRITE_MOUSE:
+    case KBD_CCMD_WRITE_OUTPORT:
+        s->write_cmd = val;
+        break;
+    case KBD_CCMD_MOUSE_DISABLE:
+        s->mode |= KBD_MODE_DISABLE_MOUSE;
+        break;
+    case KBD_CCMD_MOUSE_ENABLE:
+        s->mode &= ~KBD_MODE_DISABLE_MOUSE;
+        break;
+    case KBD_CCMD_TEST_MOUSE:
+        kbd_queue(s, 0x00, 0);
+        break;
+    case KBD_CCMD_SELF_TEST:
+        s->status |= KBD_STAT_SELFTEST;
+        kbd_queue(s, 0x55, 0);
+        break;
+    case KBD_CCMD_KBD_TEST:
+        kbd_queue(s, 0x00, 0);
+        break;
+    case KBD_CCMD_KBD_DISABLE:
+        s->mode |= KBD_MODE_DISABLE_KBD;
+        kbd_update_irq(s);
+        break;
+    case KBD_CCMD_KBD_ENABLE:
+        s->mode &= ~KBD_MODE_DISABLE_KBD;
+        kbd_update_irq(s);
+        break;
+    case KBD_CCMD_READ_INPORT:
+        kbd_queue(s, 0x00, 0);
+        break;
+    case KBD_CCMD_READ_OUTPORT:
+        kbd_queue(s, s->outport, 0);
+        break;
+    case KBD_CCMD_ENABLE_A20:
+        if (s->a20_out) {
+            qemu_irq_raise(*s->a20_out);
+        }
+        s->outport |= KBD_OUT_A20;
+        break;
+    case KBD_CCMD_DISABLE_A20:
+        if (s->a20_out) {
+            qemu_irq_lower(*s->a20_out);
+        }
+        s->outport &= ~KBD_OUT_A20;
+        break;
+    case KBD_CCMD_RESET:
+        qemu_system_reset_request();
+        break;
+    case KBD_CCMD_NO_OP:
+        /* ignore that */
+        break;
+    default:
+        fprintf(stderr, "qemu: unsupported keyboard cmd=0x%02x\n", (int)val);
+        break;
+    }
+}
+
+static uint64_t kbd_read_data(void *opaque, hwaddr addr,
+                              unsigned size)
+{
+    KBDState *s = opaque;
+    uint32_t val;
+
+    if (s->pending == KBD_PENDING_AUX)
+        val = ps2_read_data(s->mouse);
+    else
+        val = ps2_read_data(s->kbd);
+
+    DPRINTF("kbd: read data=0x%02x\n", val);
+    return val;
+}
+
+static void kbd_write_data(void *opaque, hwaddr addr,
+                           uint64_t val, unsigned size)
+{
+    KBDState *s = opaque;
+
+    DPRINTF("kbd: write data=0x%02x\n", val);
+
+    switch(s->write_cmd) {
+    case 0:
+        ps2_write_keyboard(s->kbd, val);
+        break;
+    case KBD_CCMD_WRITE_MODE:
+        s->mode = val;
+        ps2_keyboard_set_translation(s->kbd, (s->mode & KBD_MODE_KCC) != 0);
+        /* ??? */
+        kbd_update_irq(s);
+        break;
+    case KBD_CCMD_WRITE_OBUF:
+        kbd_queue(s, val, 0);
+        break;
+    case KBD_CCMD_WRITE_AUX_OBUF:
+        kbd_queue(s, val, 1);
+        break;
+    case KBD_CCMD_WRITE_OUTPORT:
+        outport_write(s, val);
+        break;
+    case KBD_CCMD_WRITE_MOUSE:
+        ps2_write_mouse(s->mouse, val);
+        break;
+    default:
+        break;
+    }
+    s->write_cmd = 0;
+}
+
+static void kbd_reset(void *opaque)
+{
+    KBDState *s = opaque;
+
+    s->mode = KBD_MODE_KBD_INT | KBD_MODE_MOUSE_INT;
+    s->status = KBD_STAT_CMD | KBD_STAT_UNLOCKED;
+    s->outport = KBD_OUT_RESET | KBD_OUT_A20;
+}
+
+static const VMStateDescription vmstate_kbd = {
+    .name = "pckbd",
+    .version_id = 3,
+    .minimum_version_id = 3,
+    .minimum_version_id_old = 3,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT8(write_cmd, KBDState),
+        VMSTATE_UINT8(status, KBDState),
+        VMSTATE_UINT8(mode, KBDState),
+        VMSTATE_UINT8(pending, KBDState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+/* Memory mapped interface */
+static uint32_t kbd_mm_readb (void *opaque, hwaddr addr)
+{
+    KBDState *s = opaque;
+
+    if (addr & s->mask)
+        return kbd_read_status(s, 0, 1) & 0xff;
+    else
+        return kbd_read_data(s, 0, 1) & 0xff;
+}
+
+static void kbd_mm_writeb (void *opaque, hwaddr addr, uint32_t value)
+{
+    KBDState *s = opaque;
+
+    if (addr & s->mask)
+        kbd_write_command(s, 0, value & 0xff, 1);
+    else
+        kbd_write_data(s, 0, value & 0xff, 1);
+}
+
+static const MemoryRegionOps i8042_mmio_ops = {
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .old_mmio = {
+        .read = { kbd_mm_readb, kbd_mm_readb, kbd_mm_readb },
+        .write = { kbd_mm_writeb, kbd_mm_writeb, kbd_mm_writeb },
+    },
+};
+
+void i8042_mm_init(qemu_irq kbd_irq, qemu_irq mouse_irq,
+                   MemoryRegion *region, ram_addr_t size,
+                   hwaddr mask)
+{
+    KBDState *s = g_malloc0(sizeof(KBDState));
+
+    s->irq_kbd = kbd_irq;
+    s->irq_mouse = mouse_irq;
+    s->mask = mask;
+
+    vmstate_register(NULL, 0, &vmstate_kbd, s);
+
+    memory_region_init_io(region, &i8042_mmio_ops, s, "i8042", size);
+
+    s->kbd = ps2_kbd_init(kbd_update_kbd_irq, s);
+    s->mouse = ps2_mouse_init(kbd_update_aux_irq, s);
+    qemu_register_reset(kbd_reset, s);
+}
+
+typedef struct ISAKBDState {
+    ISADevice dev;
+    KBDState kbd;
+    MemoryRegion io[2];
+} ISAKBDState;
+
+void i8042_isa_mouse_fake_event(void *opaque)
+{
+    ISADevice *dev = opaque;
+    KBDState *s = &(DO_UPCAST(ISAKBDState, dev, dev)->kbd);
+
+    ps2_mouse_fake_event(s->mouse);
+}
+
+void i8042_setup_a20_line(ISADevice *dev, qemu_irq *a20_out)
+{
+    KBDState *s = &(DO_UPCAST(ISAKBDState, dev, dev)->kbd);
+
+    s->a20_out = a20_out;
+}
+
+static const VMStateDescription vmstate_kbd_isa = {
+    .name = "pckbd",
+    .version_id = 3,
+    .minimum_version_id = 3,
+    .minimum_version_id_old = 3,
+    .fields      = (VMStateField []) {
+        VMSTATE_STRUCT(kbd, ISAKBDState, 0, vmstate_kbd, KBDState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const MemoryRegionOps i8042_data_ops = {
+    .read = kbd_read_data,
+    .write = kbd_write_data,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static const MemoryRegionOps i8042_cmd_ops = {
+    .read = kbd_read_status,
+    .write = kbd_write_command,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static int i8042_initfn(ISADevice *dev)
+{
+    ISAKBDState *isa_s = DO_UPCAST(ISAKBDState, dev, dev);
+    KBDState *s = &isa_s->kbd;
+
+    isa_init_irq(dev, &s->irq_kbd, 1);
+    isa_init_irq(dev, &s->irq_mouse, 12);
+
+    memory_region_init_io(isa_s->io + 0, &i8042_data_ops, s, "i8042-data", 1);
+    isa_register_ioport(dev, isa_s->io + 0, 0x60);
+
+    memory_region_init_io(isa_s->io + 1, &i8042_cmd_ops, s, "i8042-cmd", 1);
+    isa_register_ioport(dev, isa_s->io + 1, 0x64);
+
+    s->kbd = ps2_kbd_init(kbd_update_kbd_irq, s);
+    s->mouse = ps2_mouse_init(kbd_update_aux_irq, s);
+    qemu_register_reset(kbd_reset, s);
+    return 0;
+}
+
+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 const TypeInfo i8042_info = {
+    .name          = "i8042",
+    .parent        = TYPE_ISA_DEVICE,
+    .instance_size = sizeof(ISAKBDState),
+    .class_init    = i8042_class_initfn,
+};
+
+static void i8042_register_types(void)
+{
+    type_register_static(&i8042_info);
+}
+
+type_init(i8042_register_types)
diff --git a/hw/input/pl050.c b/hw/input/pl050.c
new file mode 100644 (file)
index 0000000..7dd8a59
--- /dev/null
@@ -0,0 +1,199 @@
+/*
+ * Arm PrimeCell PL050 Keyboard / Mouse Interface
+ *
+ * Copyright (c) 2006-2007 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the GPL.
+ */
+
+#include "hw/sysbus.h"
+#include "hw/input/ps2.h"
+
+typedef struct {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    void *dev;
+    uint32_t cr;
+    uint32_t clk;
+    uint32_t last;
+    int pending;
+    qemu_irq irq;
+    int is_mouse;
+} pl050_state;
+
+static const VMStateDescription vmstate_pl050 = {
+    .name = "pl050",
+    .version_id = 2,
+    .minimum_version_id = 2,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(cr, pl050_state),
+        VMSTATE_UINT32(clk, pl050_state),
+        VMSTATE_UINT32(last, pl050_state),
+        VMSTATE_INT32(pending, pl050_state),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+#define PL050_TXEMPTY         (1 << 6)
+#define PL050_TXBUSY          (1 << 5)
+#define PL050_RXFULL          (1 << 4)
+#define PL050_RXBUSY          (1 << 3)
+#define PL050_RXPARITY        (1 << 2)
+#define PL050_KMIC            (1 << 1)
+#define PL050_KMID            (1 << 0)
+
+static const unsigned char pl050_id[] =
+{ 0x50, 0x10, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
+
+static void pl050_update(void *opaque, int level)
+{
+    pl050_state *s = (pl050_state *)opaque;
+    int raise;
+
+    s->pending = level;
+    raise = (s->pending && (s->cr & 0x10) != 0)
+            || (s->cr & 0x08) != 0;
+    qemu_set_irq(s->irq, raise);
+}
+
+static uint64_t pl050_read(void *opaque, hwaddr offset,
+                           unsigned size)
+{
+    pl050_state *s = (pl050_state *)opaque;
+    if (offset >= 0xfe0 && offset < 0x1000)
+        return pl050_id[(offset - 0xfe0) >> 2];
+
+    switch (offset >> 2) {
+    case 0: /* KMICR */
+        return s->cr;
+    case 1: /* KMISTAT */
+        {
+            uint8_t val;
+            uint32_t stat;
+
+            val = s->last;
+            val = val ^ (val >> 4);
+            val = val ^ (val >> 2);
+            val = (val ^ (val >> 1)) & 1;
+
+            stat = PL050_TXEMPTY;
+            if (val)
+                stat |= PL050_RXPARITY;
+            if (s->pending)
+                stat |= PL050_RXFULL;
+
+            return stat;
+        }
+    case 2: /* KMIDATA */
+        if (s->pending)
+            s->last = ps2_read_data(s->dev);
+        return s->last;
+    case 3: /* KMICLKDIV */
+        return s->clk;
+    case 4: /* KMIIR */
+        return s->pending | 2;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "pl050_read: Bad offset %x\n", (int)offset);
+        return 0;
+    }
+}
+
+static void pl050_write(void *opaque, hwaddr offset,
+                        uint64_t value, unsigned size)
+{
+    pl050_state *s = (pl050_state *)opaque;
+    switch (offset >> 2) {
+    case 0: /* KMICR */
+        s->cr = value;
+        pl050_update(s, s->pending);
+        /* ??? Need to implement the enable/disable bit.  */
+        break;
+    case 2: /* KMIDATA */
+        /* ??? This should toggle the TX interrupt line.  */
+        /* ??? This means kbd/mouse can block each other.  */
+        if (s->is_mouse) {
+            ps2_write_mouse(s->dev, value);
+        } else {
+            ps2_write_keyboard(s->dev, value);
+        }
+        break;
+    case 3: /* KMICLKDIV */
+        s->clk = value;
+        return;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "pl050_write: Bad offset %x\n", (int)offset);
+    }
+}
+static const MemoryRegionOps pl050_ops = {
+    .read = pl050_read,
+    .write = pl050_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int pl050_init(SysBusDevice *dev, int is_mouse)
+{
+    pl050_state *s = FROM_SYSBUS(pl050_state, dev);
+
+    memory_region_init_io(&s->iomem, &pl050_ops, s, "pl050", 0x1000);
+    sysbus_init_mmio(dev, &s->iomem);
+    sysbus_init_irq(dev, &s->irq);
+    s->is_mouse = is_mouse;
+    if (s->is_mouse)
+        s->dev = ps2_mouse_init(pl050_update, s);
+    else
+        s->dev = ps2_kbd_init(pl050_update, s);
+    return 0;
+}
+
+static int pl050_init_keyboard(SysBusDevice *dev)
+{
+    return pl050_init(dev, 0);
+}
+
+static int pl050_init_mouse(SysBusDevice *dev)
+{
+    return pl050_init(dev, 1);
+}
+
+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 const 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 const 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_types(void)
+{
+    type_register_static(&pl050_kbd_info);
+    type_register_static(&pl050_mouse_info);
+}
+
+type_init(pl050_register_types)
diff --git a/hw/input/ps2.c b/hw/input/ps2.c
new file mode 100644 (file)
index 0000000..3412079
--- /dev/null
@@ -0,0 +1,676 @@
+/*
+ * QEMU PS/2 keyboard/mouse emulation
+ *
+ * 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.
+ */
+#include "hw/hw.h"
+#include "hw/input/ps2.h"
+#include "ui/console.h"
+#include "sysemu/sysemu.h"
+
+/* debug PC keyboard */
+//#define DEBUG_KBD
+
+/* debug PC keyboard : only mouse */
+//#define DEBUG_MOUSE
+
+/* Keyboard Commands */
+#define KBD_CMD_SET_LEDS       0xED    /* Set keyboard leds */
+#define KBD_CMD_ECHO           0xEE
+#define KBD_CMD_SCANCODE       0xF0    /* Get/set scancode set */
+#define KBD_CMD_GET_ID                 0xF2    /* get keyboard ID */
+#define KBD_CMD_SET_RATE       0xF3    /* Set typematic rate */
+#define KBD_CMD_ENABLE         0xF4    /* Enable scanning */
+#define KBD_CMD_RESET_DISABLE  0xF5    /* reset and disable scanning */
+#define KBD_CMD_RESET_ENABLE           0xF6    /* reset and enable scanning */
+#define KBD_CMD_RESET          0xFF    /* Reset */
+
+/* Keyboard Replies */
+#define KBD_REPLY_POR          0xAA    /* Power on reset */
+#define KBD_REPLY_ID           0xAB    /* Keyboard ID */
+#define KBD_REPLY_ACK          0xFA    /* Command ACK */
+#define KBD_REPLY_RESEND       0xFE    /* Command NACK, send the cmd again */
+
+/* Mouse Commands */
+#define AUX_SET_SCALE11                0xE6    /* Set 1:1 scaling */
+#define AUX_SET_SCALE21                0xE7    /* Set 2:1 scaling */
+#define AUX_SET_RES            0xE8    /* Set resolution */
+#define AUX_GET_SCALE          0xE9    /* Get scaling factor */
+#define AUX_SET_STREAM         0xEA    /* Set stream mode */
+#define AUX_POLL               0xEB    /* Poll */
+#define AUX_RESET_WRAP         0xEC    /* Reset wrap mode */
+#define AUX_SET_WRAP           0xEE    /* Set wrap mode */
+#define AUX_SET_REMOTE         0xF0    /* Set remote mode */
+#define AUX_GET_TYPE           0xF2    /* Get type */
+#define AUX_SET_SAMPLE         0xF3    /* Set sample rate */
+#define AUX_ENABLE_DEV         0xF4    /* Enable aux device */
+#define AUX_DISABLE_DEV                0xF5    /* Disable aux device */
+#define AUX_SET_DEFAULT                0xF6
+#define AUX_RESET              0xFF    /* Reset aux device */
+#define AUX_ACK                        0xFA    /* Command byte ACK. */
+
+#define MOUSE_STATUS_REMOTE     0x40
+#define MOUSE_STATUS_ENABLED    0x20
+#define MOUSE_STATUS_SCALE21    0x10
+
+#define PS2_QUEUE_SIZE 256
+
+typedef struct {
+    uint8_t data[PS2_QUEUE_SIZE];
+    int rptr, wptr, count;
+} PS2Queue;
+
+typedef struct {
+    PS2Queue queue;
+    int32_t write_cmd;
+    void (*update_irq)(void *, int);
+    void *update_arg;
+} PS2State;
+
+typedef struct {
+    PS2State common;
+    int scan_enabled;
+    /* QEMU uses translated PC scancodes internally.  To avoid multiple
+       conversions we do the translation (if any) in the PS/2 emulation
+       not the keyboard controller.  */
+    int translate;
+    int scancode_set; /* 1=XT, 2=AT, 3=PS/2 */
+    int ledstate;
+} PS2KbdState;
+
+typedef struct {
+    PS2State common;
+    uint8_t mouse_status;
+    uint8_t mouse_resolution;
+    uint8_t mouse_sample_rate;
+    uint8_t mouse_wrap;
+    uint8_t mouse_type; /* 0 = PS2, 3 = IMPS/2, 4 = IMEX */
+    uint8_t mouse_detect_state;
+    int mouse_dx; /* current values, needed for 'poll' mode */
+    int mouse_dy;
+    int mouse_dz;
+    uint8_t mouse_buttons;
+} PS2MouseState;
+
+/* Table to convert from PC scancodes to raw scancodes.  */
+static const unsigned char ps2_raw_keycode[128] = {
+  0, 118,  22,  30,  38,  37,  46,  54,  61,  62,  70,  69,  78,  85, 102,  13,
+ 21,  29,  36,  45,  44,  53,  60,  67,  68,  77,  84,  91,  90,  20,  28,  27,
+ 35,  43,  52,  51,  59,  66,  75,  76,  82,  14,  18,  93,  26,  34,  33,  42,
+ 50,  49,  58,  65,  73,  74,  89, 124,  17,  41,  88,   5,   6,   4,  12,   3,
+ 11,   2,  10,   1,   9, 119, 126, 108, 117, 125, 123, 107, 115, 116, 121, 105,
+114, 122, 112, 113, 127,  96,  97, 120,   7,  15,  23,  31,  39,  47,  55,  63,
+ 71,  79,  86,  94,   8,  16,  24,  32,  40,  48,  56,  64,  72,  80,  87, 111,
+ 19,  25,  57,  81,  83,  92,  95,  98,  99, 100, 101, 103, 104, 106, 109, 110
+};
+static const unsigned char ps2_raw_keycode_set3[128] = {
+  0,   8,  22,  30,  38,  37,  46,  54,  61,  62,  70,  69,  78,  85, 102,  13,
+ 21,  29,  36,  45,  44,  53,  60,  67,  68,  77,  84,  91,  90,  17,  28,  27,
+ 35,  43,  52,  51,  59,  66,  75,  76,  82,  14,  18,  92,  26,  34,  33,  42,
+ 50,  49,  58,  65,  73,  74,  89, 126,  25,  41,  20,   7,  15,  23,  31,  39,
+ 47,   2,  63,  71,  79, 118,  95, 108, 117, 125, 132, 107, 115, 116, 124, 105,
+114, 122, 112, 113, 127,  96,  97,  86,  94,  15,  23,  31,  39,  47,  55,  63,
+ 71,  79,  86,  94,   8,  16,  24,  32,  40,  48,  56,  64,  72,  80,  87, 111,
+ 19,  25,  57,  81,  83,  92,  95,  98,  99, 100, 101, 103, 104, 106, 109, 110
+};
+
+void ps2_queue(void *opaque, int b)
+{
+    PS2State *s = (PS2State *)opaque;
+    PS2Queue *q = &s->queue;
+
+    if (q->count >= PS2_QUEUE_SIZE)
+        return;
+    q->data[q->wptr] = b;
+    if (++q->wptr == PS2_QUEUE_SIZE)
+        q->wptr = 0;
+    q->count++;
+    s->update_irq(s->update_arg, 1);
+}
+
+/*
+   keycode is expressed as follow:
+   bit 7    - 0 key pressed, 1 = key released
+   bits 6-0 - translated scancode set 2
+ */
+static void ps2_put_keycode(void *opaque, int keycode)
+{
+    PS2KbdState *s = opaque;
+
+    qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER);
+    /* XXX: add support for scancode set 1 */
+    if (!s->translate && keycode < 0xe0 && s->scancode_set > 1) {
+        if (keycode & 0x80) {
+            ps2_queue(&s->common, 0xf0);
+        }
+        if (s->scancode_set == 2) {
+            keycode = ps2_raw_keycode[keycode & 0x7f];
+        } else if (s->scancode_set == 3) {
+            keycode = ps2_raw_keycode_set3[keycode & 0x7f];
+        }
+      }
+    ps2_queue(&s->common, keycode);
+}
+
+uint32_t ps2_read_data(void *opaque)
+{
+    PS2State *s = (PS2State *)opaque;
+    PS2Queue *q;
+    int val, index;
+
+    q = &s->queue;
+    if (q->count == 0) {
+        /* NOTE: if no data left, we return the last keyboard one
+           (needed for EMM386) */
+        /* XXX: need a timer to do things correctly */
+        index = q->rptr - 1;
+        if (index < 0)
+            index = PS2_QUEUE_SIZE - 1;
+        val = q->data[index];
+    } else {
+        val = q->data[q->rptr];
+        if (++q->rptr == PS2_QUEUE_SIZE)
+            q->rptr = 0;
+        q->count--;
+        /* reading deasserts IRQ */
+        s->update_irq(s->update_arg, 0);
+        /* reassert IRQs if data left */
+        s->update_irq(s->update_arg, q->count != 0);
+    }
+    return val;
+}
+
+static void ps2_set_ledstate(PS2KbdState *s, int ledstate)
+{
+    s->ledstate = ledstate;
+    kbd_put_ledstate(ledstate);
+}
+
+static void ps2_reset_keyboard(PS2KbdState *s)
+{
+    s->scan_enabled = 1;
+    s->scancode_set = 2;
+    ps2_set_ledstate(s, 0);
+}
+
+void ps2_write_keyboard(void *opaque, int val)
+{
+    PS2KbdState *s = (PS2KbdState *)opaque;
+
+    switch(s->common.write_cmd) {
+    default:
+    case -1:
+        switch(val) {
+        case 0x00:
+            ps2_queue(&s->common, KBD_REPLY_ACK);
+            break;
+        case 0x05:
+            ps2_queue(&s->common, KBD_REPLY_RESEND);
+            break;
+        case KBD_CMD_GET_ID:
+            ps2_queue(&s->common, KBD_REPLY_ACK);
+            /* We emulate a MF2 AT keyboard here */
+            ps2_queue(&s->common, KBD_REPLY_ID);
+            if (s->translate)
+                ps2_queue(&s->common, 0x41);
+            else
+                ps2_queue(&s->common, 0x83);
+            break;
+        case KBD_CMD_ECHO:
+            ps2_queue(&s->common, KBD_CMD_ECHO);
+            break;
+        case KBD_CMD_ENABLE:
+            s->scan_enabled = 1;
+            ps2_queue(&s->common, KBD_REPLY_ACK);
+            break;
+        case KBD_CMD_SCANCODE:
+        case KBD_CMD_SET_LEDS:
+        case KBD_CMD_SET_RATE:
+            s->common.write_cmd = val;
+            ps2_queue(&s->common, KBD_REPLY_ACK);
+            break;
+        case KBD_CMD_RESET_DISABLE:
+            ps2_reset_keyboard(s);
+            s->scan_enabled = 0;
+            ps2_queue(&s->common, KBD_REPLY_ACK);
+            break;
+        case KBD_CMD_RESET_ENABLE:
+            ps2_reset_keyboard(s);
+            s->scan_enabled = 1;
+            ps2_queue(&s->common, KBD_REPLY_ACK);
+            break;
+        case KBD_CMD_RESET:
+            ps2_reset_keyboard(s);
+            ps2_queue(&s->common, KBD_REPLY_ACK);
+            ps2_queue(&s->common, KBD_REPLY_POR);
+            break;
+        default:
+            ps2_queue(&s->common, KBD_REPLY_ACK);
+            break;
+        }
+        break;
+    case KBD_CMD_SCANCODE:
+        if (val == 0) {
+            if (s->scancode_set == 1)
+                ps2_put_keycode(s, 0x43);
+            else if (s->scancode_set == 2)
+                ps2_put_keycode(s, 0x41);
+            else if (s->scancode_set == 3)
+                ps2_put_keycode(s, 0x3f);
+        } else {
+            if (val >= 1 && val <= 3)
+                s->scancode_set = val;
+            ps2_queue(&s->common, KBD_REPLY_ACK);
+        }
+        s->common.write_cmd = -1;
+        break;
+    case KBD_CMD_SET_LEDS:
+        ps2_set_ledstate(s, val);
+        ps2_queue(&s->common, KBD_REPLY_ACK);
+        s->common.write_cmd = -1;
+        break;
+    case KBD_CMD_SET_RATE:
+        ps2_queue(&s->common, KBD_REPLY_ACK);
+        s->common.write_cmd = -1;
+        break;
+    }
+}
+
+/* Set the scancode translation mode.
+   0 = raw scancodes.
+   1 = translated scancodes (used by qemu internally).  */
+
+void ps2_keyboard_set_translation(void *opaque, int mode)
+{
+    PS2KbdState *s = (PS2KbdState *)opaque;
+    s->translate = mode;
+}
+
+static void ps2_mouse_send_packet(PS2MouseState *s)
+{
+    unsigned int b;
+    int dx1, dy1, dz1;
+
+    dx1 = s->mouse_dx;
+    dy1 = s->mouse_dy;
+    dz1 = s->mouse_dz;
+    /* XXX: increase range to 8 bits ? */
+    if (dx1 > 127)
+        dx1 = 127;
+    else if (dx1 < -127)
+        dx1 = -127;
+    if (dy1 > 127)
+        dy1 = 127;
+    else if (dy1 < -127)
+        dy1 = -127;
+    b = 0x08 | ((dx1 < 0) << 4) | ((dy1 < 0) << 5) | (s->mouse_buttons & 0x07);
+    ps2_queue(&s->common, b);
+    ps2_queue(&s->common, dx1 & 0xff);
+    ps2_queue(&s->common, dy1 & 0xff);
+    /* extra byte for IMPS/2 or IMEX */
+    switch(s->mouse_type) {
+    default:
+        break;
+    case 3:
+        if (dz1 > 127)
+            dz1 = 127;
+        else if (dz1 < -127)
+                dz1 = -127;
+        ps2_queue(&s->common, dz1 & 0xff);
+        break;
+    case 4:
+        if (dz1 > 7)
+            dz1 = 7;
+        else if (dz1 < -7)
+            dz1 = -7;
+        b = (dz1 & 0x0f) | ((s->mouse_buttons & 0x18) << 1);
+        ps2_queue(&s->common, b);
+        break;
+    }
+
+    /* update deltas */
+    s->mouse_dx -= dx1;
+    s->mouse_dy -= dy1;
+    s->mouse_dz -= dz1;
+}
+
+static void ps2_mouse_event(void *opaque,
+                            int dx, int dy, int dz, int buttons_state)
+{
+    PS2MouseState *s = opaque;
+
+    /* check if deltas are recorded when disabled */
+    if (!(s->mouse_status & MOUSE_STATUS_ENABLED))
+        return;
+
+    s->mouse_dx += dx;
+    s->mouse_dy -= dy;
+    s->mouse_dz += dz;
+    /* XXX: SDL sometimes generates nul events: we delete them */
+    if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0 &&
+        s->mouse_buttons == buttons_state)
+       return;
+    s->mouse_buttons = buttons_state;
+
+    if (buttons_state) {
+        qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER);
+    }
+
+    if (!(s->mouse_status & MOUSE_STATUS_REMOTE) &&
+        (s->common.queue.count < (PS2_QUEUE_SIZE - 16))) {
+        for(;;) {
+            /* if not remote, send event. Multiple events are sent if
+               too big deltas */
+            ps2_mouse_send_packet(s);
+            if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0)
+                break;
+        }
+    }
+}
+
+void ps2_mouse_fake_event(void *opaque)
+{
+    ps2_mouse_event(opaque, 1, 0, 0, 0);
+}
+
+void ps2_write_mouse(void *opaque, int val)
+{
+    PS2MouseState *s = (PS2MouseState *)opaque;
+#ifdef DEBUG_MOUSE
+    printf("kbd: write mouse 0x%02x\n", val);
+#endif
+    switch(s->common.write_cmd) {
+    default:
+    case -1:
+        /* mouse command */
+        if (s->mouse_wrap) {
+            if (val == AUX_RESET_WRAP) {
+                s->mouse_wrap = 0;
+                ps2_queue(&s->common, AUX_ACK);
+                return;
+            } else if (val != AUX_RESET) {
+                ps2_queue(&s->common, val);
+                return;
+            }
+        }
+        switch(val) {
+        case AUX_SET_SCALE11:
+            s->mouse_status &= ~MOUSE_STATUS_SCALE21;
+            ps2_queue(&s->common, AUX_ACK);
+            break;
+        case AUX_SET_SCALE21:
+            s->mouse_status |= MOUSE_STATUS_SCALE21;
+            ps2_queue(&s->common, AUX_ACK);
+            break;
+        case AUX_SET_STREAM:
+            s->mouse_status &= ~MOUSE_STATUS_REMOTE;
+            ps2_queue(&s->common, AUX_ACK);
+            break;
+        case AUX_SET_WRAP:
+            s->mouse_wrap = 1;
+            ps2_queue(&s->common, AUX_ACK);
+            break;
+        case AUX_SET_REMOTE:
+            s->mouse_status |= MOUSE_STATUS_REMOTE;
+            ps2_queue(&s->common, AUX_ACK);
+            break;
+        case AUX_GET_TYPE:
+            ps2_queue(&s->common, AUX_ACK);
+            ps2_queue(&s->common, s->mouse_type);
+            break;
+        case AUX_SET_RES:
+        case AUX_SET_SAMPLE:
+            s->common.write_cmd = val;
+            ps2_queue(&s->common, AUX_ACK);
+            break;
+        case AUX_GET_SCALE:
+            ps2_queue(&s->common, AUX_ACK);
+            ps2_queue(&s->common, s->mouse_status);
+            ps2_queue(&s->common, s->mouse_resolution);
+            ps2_queue(&s->common, s->mouse_sample_rate);
+            break;
+        case AUX_POLL:
+            ps2_queue(&s->common, AUX_ACK);
+            ps2_mouse_send_packet(s);
+            break;
+        case AUX_ENABLE_DEV:
+            s->mouse_status |= MOUSE_STATUS_ENABLED;
+            ps2_queue(&s->common, AUX_ACK);
+            break;
+        case AUX_DISABLE_DEV:
+            s->mouse_status &= ~MOUSE_STATUS_ENABLED;
+            ps2_queue(&s->common, AUX_ACK);
+            break;
+        case AUX_SET_DEFAULT:
+            s->mouse_sample_rate = 100;
+            s->mouse_resolution = 2;
+            s->mouse_status = 0;
+            ps2_queue(&s->common, AUX_ACK);
+            break;
+        case AUX_RESET:
+            s->mouse_sample_rate = 100;
+            s->mouse_resolution = 2;
+            s->mouse_status = 0;
+            s->mouse_type = 0;
+            ps2_queue(&s->common, AUX_ACK);
+            ps2_queue(&s->common, 0xaa);
+            ps2_queue(&s->common, s->mouse_type);
+            break;
+        default:
+            break;
+        }
+        break;
+    case AUX_SET_SAMPLE:
+        s->mouse_sample_rate = val;
+        /* detect IMPS/2 or IMEX */
+        switch(s->mouse_detect_state) {
+        default:
+        case 0:
+            if (val == 200)
+                s->mouse_detect_state = 1;
+            break;
+        case 1:
+            if (val == 100)
+                s->mouse_detect_state = 2;
+            else if (val == 200)
+                s->mouse_detect_state = 3;
+            else
+                s->mouse_detect_state = 0;
+            break;
+        case 2:
+            if (val == 80)
+                s->mouse_type = 3; /* IMPS/2 */
+            s->mouse_detect_state = 0;
+            break;
+        case 3:
+            if (val == 80)
+                s->mouse_type = 4; /* IMEX */
+            s->mouse_detect_state = 0;
+            break;
+        }
+        ps2_queue(&s->common, AUX_ACK);
+        s->common.write_cmd = -1;
+        break;
+    case AUX_SET_RES:
+        s->mouse_resolution = val;
+        ps2_queue(&s->common, AUX_ACK);
+        s->common.write_cmd = -1;
+        break;
+    }
+}
+
+static void ps2_common_reset(PS2State *s)
+{
+    PS2Queue *q;
+    s->write_cmd = -1;
+    q = &s->queue;
+    q->rptr = 0;
+    q->wptr = 0;
+    q->count = 0;
+    s->update_irq(s->update_arg, 0);
+}
+
+static void ps2_kbd_reset(void *opaque)
+{
+    PS2KbdState *s = (PS2KbdState *) opaque;
+
+    ps2_common_reset(&s->common);
+    s->scan_enabled = 0;
+    s->translate = 0;
+    s->scancode_set = 0;
+}
+
+static void ps2_mouse_reset(void *opaque)
+{
+    PS2MouseState *s = (PS2MouseState *) opaque;
+
+    ps2_common_reset(&s->common);
+    s->mouse_status = 0;
+    s->mouse_resolution = 0;
+    s->mouse_sample_rate = 0;
+    s->mouse_wrap = 0;
+    s->mouse_type = 0;
+    s->mouse_detect_state = 0;
+    s->mouse_dx = 0;
+    s->mouse_dy = 0;
+    s->mouse_dz = 0;
+    s->mouse_buttons = 0;
+}
+
+static const VMStateDescription vmstate_ps2_common = {
+    .name = "PS2 Common State",
+    .version_id = 3,
+    .minimum_version_id = 2,
+    .minimum_version_id_old = 2,
+    .fields      = (VMStateField []) {
+        VMSTATE_INT32(write_cmd, PS2State),
+        VMSTATE_INT32(queue.rptr, PS2State),
+        VMSTATE_INT32(queue.wptr, PS2State),
+        VMSTATE_INT32(queue.count, PS2State),
+        VMSTATE_BUFFER(queue.data, PS2State),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static bool ps2_keyboard_ledstate_needed(void *opaque)
+{
+    PS2KbdState *s = opaque;
+
+    return s->ledstate != 0; /* 0 is default state */
+}
+
+static int ps2_kbd_ledstate_post_load(void *opaque, int version_id)
+{
+    PS2KbdState *s = opaque;
+
+    kbd_put_ledstate(s->ledstate);
+    return 0;
+}
+
+static const VMStateDescription vmstate_ps2_keyboard_ledstate = {
+    .name = "ps2kbd/ledstate",
+    .version_id = 3,
+    .minimum_version_id = 2,
+    .minimum_version_id_old = 2,
+    .post_load = ps2_kbd_ledstate_post_load,
+    .fields      = (VMStateField []) {
+        VMSTATE_INT32(ledstate, PS2KbdState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int ps2_kbd_post_load(void* opaque, int version_id)
+{
+    PS2KbdState *s = (PS2KbdState*)opaque;
+
+    if (version_id == 2)
+        s->scancode_set=2;
+    return 0;
+}
+
+static const VMStateDescription vmstate_ps2_keyboard = {
+    .name = "ps2kbd",
+    .version_id = 3,
+    .minimum_version_id = 2,
+    .minimum_version_id_old = 2,
+    .post_load = ps2_kbd_post_load,
+    .fields      = (VMStateField []) {
+        VMSTATE_STRUCT(common, PS2KbdState, 0, vmstate_ps2_common, PS2State),
+        VMSTATE_INT32(scan_enabled, PS2KbdState),
+        VMSTATE_INT32(translate, PS2KbdState),
+        VMSTATE_INT32_V(scancode_set, PS2KbdState,3),
+        VMSTATE_END_OF_LIST()
+    },
+    .subsections = (VMStateSubsection []) {
+        {
+            .vmsd = &vmstate_ps2_keyboard_ledstate,
+            .needed = ps2_keyboard_ledstate_needed,
+        }, {
+            /* empty */
+        }
+    }
+};
+
+static const VMStateDescription vmstate_ps2_mouse = {
+    .name = "ps2mouse",
+    .version_id = 2,
+    .minimum_version_id = 2,
+    .minimum_version_id_old = 2,
+    .fields      = (VMStateField []) {
+        VMSTATE_STRUCT(common, PS2MouseState, 0, vmstate_ps2_common, PS2State),
+        VMSTATE_UINT8(mouse_status, PS2MouseState),
+        VMSTATE_UINT8(mouse_resolution, PS2MouseState),
+        VMSTATE_UINT8(mouse_sample_rate, PS2MouseState),
+        VMSTATE_UINT8(mouse_wrap, PS2MouseState),
+        VMSTATE_UINT8(mouse_type, PS2MouseState),
+        VMSTATE_UINT8(mouse_detect_state, PS2MouseState),
+        VMSTATE_INT32(mouse_dx, PS2MouseState),
+        VMSTATE_INT32(mouse_dy, PS2MouseState),
+        VMSTATE_INT32(mouse_dz, PS2MouseState),
+        VMSTATE_UINT8(mouse_buttons, PS2MouseState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg)
+{
+    PS2KbdState *s = (PS2KbdState *)g_malloc0(sizeof(PS2KbdState));
+
+    s->common.update_irq = update_irq;
+    s->common.update_arg = update_arg;
+    s->scancode_set = 2;
+    vmstate_register(NULL, 0, &vmstate_ps2_keyboard, s);
+    qemu_add_kbd_event_handler(ps2_put_keycode, s);
+    qemu_register_reset(ps2_kbd_reset, s);
+    return s;
+}
+
+void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg)
+{
+    PS2MouseState *s = (PS2MouseState *)g_malloc0(sizeof(PS2MouseState));
+
+    s->common.update_irq = update_irq;
+    s->common.update_arg = update_arg;
+    vmstate_register(NULL, 0, &vmstate_ps2_mouse, s);
+    qemu_add_mouse_event_handler(ps2_mouse_event, s, 0, "QEMU PS/2 Mouse");
+    qemu_register_reset(ps2_mouse_reset, s);
+    return s;
+}
diff --git a/hw/input/pxa2xx_keypad.c b/hw/input/pxa2xx_keypad.c
new file mode 100644 (file)
index 0000000..1fd5f20
--- /dev/null
@@ -0,0 +1,335 @@
+/*
+ * Intel PXA27X Keypad Controller emulation.
+ *
+ * Copyright (c) 2007 MontaVista Software, Inc
+ * Written by Armin Kuster <akuster@kama-aina.net>
+ *              or  <Akuster@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/hw.h"
+#include "hw/arm/pxa.h"
+#include "ui/console.h"
+
+/*
+ * Keypad
+ */
+#define KPC         0x00    /* Keypad Interface Control register */
+#define KPDK        0x08    /* Keypad Interface Direct Key register */
+#define KPREC       0x10    /* Keypad Interface Rotary Encoder register */
+#define KPMK        0x18    /* Keypad Interface Matrix Key register */
+#define KPAS        0x20    /* Keypad Interface Automatic Scan register */
+#define KPASMKP0    0x28    /* Keypad Interface Automatic Scan Multiple
+                                Key Presser register 0 */
+#define KPASMKP1    0x30    /* Keypad Interface Automatic Scan Multiple
+                                Key Presser register 1 */
+#define KPASMKP2    0x38    /* Keypad Interface Automatic Scan Multiple
+                                Key Presser register 2 */
+#define KPASMKP3    0x40    /* Keypad Interface Automatic Scan Multiple
+                                Key Presser register 3 */
+#define KPKDI       0x48    /* Keypad Interface Key Debounce Interval
+                                register */
+
+/* Keypad defines */
+#define KPC_AS          (0x1 << 30)  /* Automatic Scan bit */
+#define KPC_ASACT       (0x1 << 29)  /* Automatic Scan on Activity */
+#define KPC_MI          (0x1 << 22)  /* Matrix interrupt bit */
+#define KPC_IMKP        (0x1 << 21)  /* Ignore Multiple Key Press */
+#define KPC_MS7         (0x1 << 20)  /* Matrix scan line 7 */
+#define KPC_MS6         (0x1 << 19)  /* Matrix scan line 6 */
+#define KPC_MS5         (0x1 << 18)  /* Matrix scan line 5 */
+#define KPC_MS4         (0x1 << 17)  /* Matrix scan line 4 */
+#define KPC_MS3         (0x1 << 16)  /* Matrix scan line 3 */
+#define KPC_MS2         (0x1 << 15)  /* Matrix scan line 2 */
+#define KPC_MS1         (0x1 << 14)  /* Matrix scan line 1 */
+#define KPC_MS0         (0x1 << 13)  /* Matrix scan line 0 */
+#define KPC_ME          (0x1 << 12)  /* Matrix Keypad Enable */
+#define KPC_MIE         (0x1 << 11)  /* Matrix Interrupt Enable */
+#define KPC_DK_DEB_SEL  (0x1 <<  9)  /* Direct Keypad Debounce Select */
+#define KPC_DI          (0x1 <<  5)  /* Direct key interrupt bit */
+#define KPC_RE_ZERO_DEB (0x1 <<  4)  /* Rotary Encoder Zero Debounce */
+#define KPC_REE1        (0x1 <<  3)  /* Rotary Encoder1 Enable */
+#define KPC_REE0        (0x1 <<  2)  /* Rotary Encoder0 Enable */
+#define KPC_DE          (0x1 <<  1)  /* Direct Keypad Enable */
+#define KPC_DIE         (0x1 <<  0)  /* Direct Keypad interrupt Enable */
+
+#define KPDK_DKP        (0x1 << 31)
+#define KPDK_DK7        (0x1 <<  7)
+#define KPDK_DK6        (0x1 <<  6)
+#define KPDK_DK5        (0x1 <<  5)
+#define KPDK_DK4        (0x1 <<  4)
+#define KPDK_DK3        (0x1 <<  3)
+#define KPDK_DK2        (0x1 <<  2)
+#define KPDK_DK1        (0x1 <<  1)
+#define KPDK_DK0        (0x1 <<  0)
+
+#define KPREC_OF1       (0x1 << 31)
+#define KPREC_UF1       (0x1 << 30)
+#define KPREC_OF0       (0x1 << 15)
+#define KPREC_UF0       (0x1 << 14)
+
+#define KPMK_MKP        (0x1 << 31)
+#define KPAS_SO         (0x1 << 31)
+#define KPASMKPx_SO     (0x1 << 31)
+
+
+#define KPASMKPx_MKC(row, col)  (1 << (row + 16 * (col % 2)))
+
+#define PXAKBD_MAXROW   8
+#define PXAKBD_MAXCOL   8
+
+struct PXA2xxKeyPadState {
+    MemoryRegion iomem;
+    qemu_irq    irq;
+    struct  keymap *map;
+    int         pressed_cnt;
+    int         alt_code;
+
+    uint32_t    kpc;
+    uint32_t    kpdk;
+    uint32_t    kprec;
+    uint32_t    kpmk;
+    uint32_t    kpas;
+    uint32_t    kpasmkp[4];
+    uint32_t    kpkdi;
+};
+
+static void pxa27x_keypad_find_pressed_key(PXA2xxKeyPadState *kp, int *row, int *col)
+{
+    int i;
+    for (i = 0; i < 4; i++)
+    {
+        *col = i * 2;
+        for (*row = 0; *row < 8; (*row)++) {
+            if (kp->kpasmkp[i] & (1 << *row))
+                return;
+        }
+        *col = i * 2 + 1;
+        for (*row = 0; *row < 8; (*row)++) {
+            if (kp->kpasmkp[i] & (1 << (*row + 16)))
+                return;
+        }
+    }
+}
+
+static void pxa27x_keyboard_event (PXA2xxKeyPadState *kp, int keycode)
+{
+    int row, col, rel, assert_irq = 0;
+    uint32_t val;
+
+    if (keycode == 0xe0) {
+        kp->alt_code = 1;
+        return;
+    }
+
+    if(!(kp->kpc & KPC_ME)) /* skip if not enabled */
+        return;
+
+    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;
+    }
+
+    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;
+        }
+    }
+    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;
+
+    if (assert_irq && (kp->kpc & KPC_MIE)) {
+        kp->kpc |= KPC_MI;
+        qemu_irq_raise(kp->irq);
+    }
+}
+
+static uint64_t pxa2xx_keypad_read(void *opaque, hwaddr offset,
+                                   unsigned size)
+{
+    PXA2xxKeyPadState *s = (PXA2xxKeyPadState *) opaque;
+    uint32_t tmp;
+
+    switch (offset) {
+    case KPC:
+        tmp = s->kpc;
+        if(tmp & KPC_MI)
+            s->kpc &= ~(KPC_MI);
+        if(tmp & KPC_DI)
+            s->kpc &= ~(KPC_DI);
+        qemu_irq_lower(s->irq);
+        return tmp;
+        break;
+    case KPDK:
+        return s->kpdk;
+        break;
+    case KPREC:
+        tmp = s->kprec;
+        if(tmp & KPREC_OF1)
+            s->kprec &= ~(KPREC_OF1);
+        if(tmp & KPREC_UF1)
+            s->kprec &= ~(KPREC_UF1);
+        if(tmp & KPREC_OF0)
+            s->kprec &= ~(KPREC_OF0);
+        if(tmp & KPREC_UF0)
+            s->kprec &= ~(KPREC_UF0);
+        return tmp;
+        break;
+    case KPMK:
+        tmp = s->kpmk;
+        if(tmp & KPMK_MKP)
+            s->kpmk &= ~(KPMK_MKP);
+        return tmp;
+        break;
+    case KPAS:
+        return s->kpas;
+        break;
+    case KPASMKP0:
+        return s->kpasmkp[0];
+        break;
+    case KPASMKP1:
+        return s->kpasmkp[1];
+        break;
+    case KPASMKP2:
+        return s->kpasmkp[2];
+        break;
+    case KPASMKP3:
+        return s->kpasmkp[3];
+        break;
+    case KPKDI:
+        return s->kpkdi;
+        break;
+    default:
+        hw_error("%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset);
+    }
+
+    return 0;
+}
+
+static void pxa2xx_keypad_write(void *opaque, hwaddr offset,
+                                uint64_t value, unsigned size)
+{
+    PXA2xxKeyPadState *s = (PXA2xxKeyPadState *) opaque;
+
+    switch (offset) {
+    case KPC:
+        s->kpc = value;
+        if (s->kpc & KPC_AS) {
+            s->kpc &= ~(KPC_AS);
+        }
+        break;
+    case KPDK:
+        s->kpdk = value;
+        break;
+    case KPREC:
+        s->kprec = value;
+        break;
+    case KPMK:
+        s->kpmk = value;
+        break;
+    case KPAS:
+        s->kpas = value;
+        break;
+    case KPASMKP0:
+        s->kpasmkp[0] = value;
+        break;
+    case KPASMKP1:
+        s->kpasmkp[1] = value;
+        break;
+    case KPASMKP2:
+        s->kpasmkp[2] = value;
+        break;
+    case KPASMKP3:
+        s->kpasmkp[3] = value;
+        break;
+    case KPKDI:
+        s->kpkdi = value;
+        break;
+
+    default:
+        hw_error("%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset);
+    }
+}
+
+static const MemoryRegionOps pxa2xx_keypad_ops = {
+    .read = pxa2xx_keypad_read,
+    .write = pxa2xx_keypad_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static const VMStateDescription vmstate_pxa2xx_keypad = {
+    .name = "pxa2xx_keypad",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32(kpc, PXA2xxKeyPadState),
+        VMSTATE_UINT32(kpdk, PXA2xxKeyPadState),
+        VMSTATE_UINT32(kprec, PXA2xxKeyPadState),
+        VMSTATE_UINT32(kpmk, PXA2xxKeyPadState),
+        VMSTATE_UINT32(kpas, PXA2xxKeyPadState),
+        VMSTATE_UINT32_ARRAY(kpasmkp, PXA2xxKeyPadState, 4),
+        VMSTATE_UINT32(kpkdi, PXA2xxKeyPadState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+PXA2xxKeyPadState *pxa27x_keypad_init(MemoryRegion *sysmem,
+                                      hwaddr base,
+                                      qemu_irq irq)
+{
+    PXA2xxKeyPadState *s;
+
+    s = (PXA2xxKeyPadState *) g_malloc0(sizeof(PXA2xxKeyPadState));
+    s->irq = irq;
+
+    memory_region_init_io(&s->iomem, &pxa2xx_keypad_ops, s,
+                          "pxa2xx-keypad", 0x00100000);
+    memory_region_add_subregion(sysmem, base, &s->iomem);
+
+    vmstate_register(NULL, 0, &vmstate_pxa2xx_keypad, s);
+
+    return s;
+}
+
+void pxa27x_register_keypad(PXA2xxKeyPadState *kp, struct keymap *map,
+        int size)
+{
+    if(!map || size < 0x80) {
+        fprintf(stderr, "%s - No PXA keypad map defined\n", __FUNCTION__);
+        exit(-1);
+    }
+
+    kp->map = map;
+    qemu_add_kbd_event_handler((QEMUPutKBDEvent *) pxa27x_keyboard_event, kp);
+}
diff --git a/hw/input/stellaris_input.c b/hw/input/stellaris_input.c
new file mode 100644 (file)
index 0000000..f83fc3f
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Gamepad style buttons connected to IRQ/GPIO lines
+ *
+ * Copyright (c) 2007 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the GPL.
+ */
+#include "hw/hw.h"
+#include "hw/arm/devices.h"
+#include "ui/console.h"
+
+typedef struct {
+    qemu_irq irq;
+    int keycode;
+    uint8_t pressed;
+} gamepad_button;
+
+typedef struct {
+    gamepad_button *buttons;
+    int num_buttons;
+    int extension;
+} gamepad_state;
+
+static void stellaris_gamepad_put_key(void * opaque, int keycode)
+{
+    gamepad_state *s = (gamepad_state *)opaque;
+    int i;
+    int down;
+
+    if (keycode == 0xe0 && !s->extension) {
+        s->extension = 0x80;
+        return;
+    }
+
+    down = (keycode & 0x80) == 0;
+    keycode = (keycode & 0x7f) | s->extension;
+
+    for (i = 0; i < s->num_buttons; i++) {
+        if (s->buttons[i].keycode == keycode
+                && s->buttons[i].pressed != down) {
+            s->buttons[i].pressed = down;
+            qemu_set_irq(s->buttons[i].irq, down);
+        }
+    }
+
+    s->extension = 0;
+}
+
+static const VMStateDescription vmstate_stellaris_button = {
+    .name = "stellaris_button",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT8(pressed, gamepad_button),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_stellaris_gamepad = {
+    .name = "stellaris_gamepad",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_INT32(extension, gamepad_state),
+        VMSTATE_STRUCT_VARRAY_INT32(buttons, gamepad_state, num_buttons, 0,
+                              vmstate_stellaris_button, gamepad_button),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+/* Returns an array 5 ouput slots.  */
+void stellaris_gamepad_init(int n, qemu_irq *irq, const int *keycode)
+{
+    gamepad_state *s;
+    int i;
+
+    s = (gamepad_state *)g_malloc0(sizeof (gamepad_state));
+    s->buttons = (gamepad_button *)g_malloc0(n * sizeof (gamepad_button));
+    for (i = 0; i < n; i++) {
+        s->buttons[i].irq = irq[i];
+        s->buttons[i].keycode = keycode[i];
+    }
+    s->num_buttons = n;
+    qemu_add_kbd_event_handler(stellaris_gamepad_put_key, s);
+    vmstate_register(NULL, -1, &vmstate_stellaris_gamepad, s);
+}
diff --git a/hw/input/tsc2005.c b/hw/input/tsc2005.c
new file mode 100644 (file)
index 0000000..34ee1fb
--- /dev/null
@@ -0,0 +1,593 @@
+/*
+ * TI TSC2005 emulator.
+ *
+ * Copyright (c) 2006 Andrzej Zaborowski  <balrog@zabor.org>
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * 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 or
+ * (at your option) version 3 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
+ * 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 "hw/hw.h"
+#include "qemu/timer.h"
+#include "ui/console.h"
+#include "hw/arm/devices.h"
+
+#define TSC_CUT_RESOLUTION(value, p)   ((value) >> (16 - (p ? 12 : 10)))
+
+typedef struct {
+    qemu_irq pint;     /* Combination of the nPENIRQ and DAV signals */
+    QEMUTimer *timer;
+    uint16_t model;
+
+    int x, y;
+    int pressure;
+
+    int state, reg, irq, command;
+    uint16_t data, dav;
+
+    int busy;
+    int enabled;
+    int host_mode;
+    int function;
+    int nextfunction;
+    int precision;
+    int nextprecision;
+    int filter;
+    int pin_func;
+    int timing[2];
+    int noise;
+    int reset;
+    int pdst;
+    int pnd0;
+    uint16_t temp_thr[2];
+    uint16_t aux_thr[2];
+
+    int tr[8];
+} TSC2005State;
+
+enum {
+    TSC_MODE_XYZ_SCAN  = 0x0,
+    TSC_MODE_XY_SCAN,
+    TSC_MODE_X,
+    TSC_MODE_Y,
+    TSC_MODE_Z,
+    TSC_MODE_AUX,
+    TSC_MODE_TEMP1,
+    TSC_MODE_TEMP2,
+    TSC_MODE_AUX_SCAN,
+    TSC_MODE_X_TEST,
+    TSC_MODE_Y_TEST,
+    TSC_MODE_TS_TEST,
+    TSC_MODE_RESERVED,
+    TSC_MODE_XX_DRV,
+    TSC_MODE_YY_DRV,
+    TSC_MODE_YX_DRV,
+};
+
+static const uint16_t mode_regs[16] = {
+    0xf000,    /* X, Y, Z scan */
+    0xc000,    /* X, Y scan */
+    0x8000,    /* X */
+    0x4000,    /* Y */
+    0x3000,    /* Z */
+    0x0800,    /* AUX */
+    0x0400,    /* TEMP1 */
+    0x0200,    /* TEMP2 */
+    0x0800,    /* AUX scan */
+    0x0040,    /* X test */
+    0x0020,    /* Y test */
+    0x0080,    /* Short-circuit test */
+    0x0000,    /* Reserved */
+    0x0000,    /* X+, X- drivers */
+    0x0000,    /* Y+, Y- drivers */
+    0x0000,    /* Y+, X- drivers */
+};
+
+#define X_TRANSFORM(s)                 \
+    ((s->y * s->tr[0] - s->x * s->tr[1]) / s->tr[2] + s->tr[3])
+#define Y_TRANSFORM(s)                 \
+    ((s->y * s->tr[4] - s->x * s->tr[5]) / s->tr[6] + s->tr[7])
+#define Z1_TRANSFORM(s)                        \
+    ((400 - ((s)->x >> 7) + ((s)->pressure << 10)) << 4)
+#define Z2_TRANSFORM(s)                        \
+    ((4000 + ((s)->y >> 7) - ((s)->pressure << 10)) << 4)
+
+#define AUX_VAL                                (700 << 4)      /* +/- 3 at 12-bit */
+#define TEMP1_VAL                      (1264 << 4)     /* +/- 5 at 12-bit */
+#define TEMP2_VAL                      (1531 << 4)     /* +/- 5 at 12-bit */
+
+static uint16_t tsc2005_read(TSC2005State *s, int reg)
+{
+    uint16_t ret;
+
+    switch (reg) {
+    case 0x0:  /* X */
+        s->dav &= ~mode_regs[TSC_MODE_X];
+        return TSC_CUT_RESOLUTION(X_TRANSFORM(s), s->precision) +
+                (s->noise & 3);
+    case 0x1:  /* Y */
+        s->dav &= ~mode_regs[TSC_MODE_Y];
+        s->noise ++;
+        return TSC_CUT_RESOLUTION(Y_TRANSFORM(s), s->precision) ^
+                (s->noise & 3);
+    case 0x2:  /* Z1 */
+        s->dav &= 0xdfff;
+        return TSC_CUT_RESOLUTION(Z1_TRANSFORM(s), s->precision) -
+                (s->noise & 3);
+    case 0x3:  /* Z2 */
+        s->dav &= 0xefff;
+        return TSC_CUT_RESOLUTION(Z2_TRANSFORM(s), s->precision) |
+                (s->noise & 3);
+
+    case 0x4:  /* AUX */
+        s->dav &= ~mode_regs[TSC_MODE_AUX];
+        return TSC_CUT_RESOLUTION(AUX_VAL, s->precision);
+
+    case 0x5:  /* TEMP1 */
+        s->dav &= ~mode_regs[TSC_MODE_TEMP1];
+        return TSC_CUT_RESOLUTION(TEMP1_VAL, s->precision) -
+                (s->noise & 5);
+    case 0x6:  /* TEMP2 */
+        s->dav &= 0xdfff;
+        s->dav &= ~mode_regs[TSC_MODE_TEMP2];
+        return TSC_CUT_RESOLUTION(TEMP2_VAL, s->precision) ^
+                (s->noise & 3);
+
+    case 0x7:  /* Status */
+        ret = s->dav | (s->reset << 7) | (s->pdst << 2) | 0x0;
+        s->dav &= ~(mode_regs[TSC_MODE_X_TEST] | mode_regs[TSC_MODE_Y_TEST] |
+                        mode_regs[TSC_MODE_TS_TEST]);
+        s->reset = 1;
+        return ret;
+
+    case 0x8:  /* AUX high treshold */
+        return s->aux_thr[1];
+    case 0x9:  /* AUX low treshold */
+        return s->aux_thr[0];
+
+    case 0xa:  /* TEMP high treshold */
+        return s->temp_thr[1];
+    case 0xb:  /* TEMP low treshold */
+        return s->temp_thr[0];
+
+    case 0xc:  /* CFR0 */
+        return (s->pressure << 15) | ((!s->busy) << 14) |
+                (s->nextprecision << 13) | s->timing[0]; 
+    case 0xd:  /* CFR1 */
+        return s->timing[1];
+    case 0xe:  /* CFR2 */
+        return (s->pin_func << 14) | s->filter;
+
+    case 0xf:  /* Function select status */
+        return s->function >= 0 ? 1 << s->function : 0;
+    }
+
+    /* Never gets here */
+    return 0xffff;
+}
+
+static void tsc2005_write(TSC2005State *s, int reg, uint16_t data)
+{
+    switch (reg) {
+    case 0x8:  /* AUX high treshold */
+        s->aux_thr[1] = data;
+        break;
+    case 0x9:  /* AUX low treshold */
+        s->aux_thr[0] = data;
+        break;
+
+    case 0xa:  /* TEMP high treshold */
+        s->temp_thr[1] = data;
+        break;
+    case 0xb:  /* TEMP low treshold */
+        s->temp_thr[0] = data;
+        break;
+
+    case 0xc:  /* CFR0 */
+        s->host_mode = data >> 15;
+        if (s->enabled != !(data & 0x4000)) {
+            s->enabled = !(data & 0x4000);
+            fprintf(stderr, "%s: touchscreen sense %sabled\n",
+                            __FUNCTION__, s->enabled ? "en" : "dis");
+            if (s->busy && !s->enabled)
+                qemu_del_timer(s->timer);
+            s->busy &= s->enabled;
+        }
+        s->nextprecision = (data >> 13) & 1;
+        s->timing[0] = data & 0x1fff;
+        if ((s->timing[0] >> 11) == 3)
+            fprintf(stderr, "%s: illegal conversion clock setting\n",
+                            __FUNCTION__);
+        break;
+    case 0xd:  /* CFR1 */
+        s->timing[1] = data & 0xf07;
+        break;
+    case 0xe:  /* CFR2 */
+        s->pin_func = (data >> 14) & 3;
+        s->filter = data & 0x3fff;
+        break;
+
+    default:
+        fprintf(stderr, "%s: write into read-only register %x\n",
+                        __FUNCTION__, reg);
+    }
+}
+
+/* This handles most of the chip's logic.  */
+static void tsc2005_pin_update(TSC2005State *s)
+{
+    int64_t expires;
+    int pin_state;
+
+    switch (s->pin_func) {
+    case 0:
+        pin_state = !s->pressure && !!s->dav;
+        break;
+    case 1:
+    case 3:
+    default:
+        pin_state = !s->dav;
+        break;
+    case 2:
+        pin_state = !s->pressure;
+    }
+
+    if (pin_state != s->irq) {
+        s->irq = pin_state;
+        qemu_set_irq(s->pint, s->irq);
+    }
+
+    switch (s->nextfunction) {
+    case TSC_MODE_XYZ_SCAN:
+    case TSC_MODE_XY_SCAN:
+        if (!s->host_mode && s->dav)
+            s->enabled = 0;
+        if (!s->pressure)
+            return;
+        /* Fall through */
+    case TSC_MODE_AUX_SCAN:
+        break;
+
+    case TSC_MODE_X:
+    case TSC_MODE_Y:
+    case TSC_MODE_Z:
+        if (!s->pressure)
+            return;
+        /* Fall through */
+    case TSC_MODE_AUX:
+    case TSC_MODE_TEMP1:
+    case TSC_MODE_TEMP2:
+    case TSC_MODE_X_TEST:
+    case TSC_MODE_Y_TEST:
+    case TSC_MODE_TS_TEST:
+        if (s->dav)
+            s->enabled = 0;
+        break;
+
+    case TSC_MODE_RESERVED:
+    case TSC_MODE_XX_DRV:
+    case TSC_MODE_YY_DRV:
+    case TSC_MODE_YX_DRV:
+    default:
+        return;
+    }
+
+    if (!s->enabled || s->busy)
+        return;
+
+    s->busy = 1;
+    s->precision = s->nextprecision;
+    s->function = s->nextfunction;
+    s->pdst = !s->pnd0;        /* Synchronised on internal clock */
+    expires = qemu_get_clock_ns(vm_clock) + (get_ticks_per_sec() >> 7);
+    qemu_mod_timer(s->timer, expires);
+}
+
+static void tsc2005_reset(TSC2005State *s)
+{
+    s->state = 0;
+    s->pin_func = 0;
+    s->enabled = 0;
+    s->busy = 0;
+    s->nextprecision = 0;
+    s->nextfunction = 0;
+    s->timing[0] = 0;
+    s->timing[1] = 0;
+    s->irq = 0;
+    s->dav = 0;
+    s->reset = 0;
+    s->pdst = 1;
+    s->pnd0 = 0;
+    s->function = -1;
+    s->temp_thr[0] = 0x000;
+    s->temp_thr[1] = 0xfff;
+    s->aux_thr[0] = 0x000;
+    s->aux_thr[1] = 0xfff;
+
+    tsc2005_pin_update(s);
+}
+
+static uint8_t tsc2005_txrx_word(void *opaque, uint8_t value)
+{
+    TSC2005State *s = opaque;
+    uint32_t ret = 0;
+
+    switch (s->state ++) {
+    case 0:
+        if (value & 0x80) {
+            /* Command */
+            if (value & (1 << 1))
+                tsc2005_reset(s);
+            else {
+                s->nextfunction = (value >> 3) & 0xf;
+                s->nextprecision = (value >> 2) & 1;
+                if (s->enabled != !(value & 1)) {
+                    s->enabled = !(value & 1);
+                    fprintf(stderr, "%s: touchscreen sense %sabled\n",
+                                    __FUNCTION__, s->enabled ? "en" : "dis");
+                    if (s->busy && !s->enabled)
+                        qemu_del_timer(s->timer);
+                    s->busy &= s->enabled;
+                }
+                tsc2005_pin_update(s);
+            }
+
+            s->state = 0;
+        } else if (value) {
+            /* Data transfer */
+            s->reg = (value >> 3) & 0xf;
+            s->pnd0 = (value >> 1) & 1;
+            s->command = value & 1;
+
+            if (s->command) {
+                /* Read */
+                s->data = tsc2005_read(s, s->reg);
+                tsc2005_pin_update(s);
+            } else
+                s->data = 0;
+        } else
+            s->state = 0;
+        break;
+
+    case 1:
+        if (s->command)
+            ret = (s->data >> 8) & 0xff;
+        else
+            s->data |= value << 8;
+        break;
+
+    case 2:
+        if (s->command)
+            ret = s->data & 0xff;
+        else {
+            s->data |= value;
+            tsc2005_write(s, s->reg, s->data);
+            tsc2005_pin_update(s);
+        }
+
+        s->state = 0;
+        break;
+    }
+
+    return ret;
+}
+
+uint32_t tsc2005_txrx(void *opaque, uint32_t value, int len)
+{
+    uint32_t ret = 0;
+
+    len &= ~7;
+    while (len > 0) {
+        len -= 8;
+        ret |= tsc2005_txrx_word(opaque, (value >> len) & 0xff) << len;
+    }
+
+    return ret;
+}
+
+static void tsc2005_timer_tick(void *opaque)
+{
+    TSC2005State *s = opaque;
+
+    /* Timer ticked -- a set of conversions has been finished.  */
+
+    if (!s->busy)
+        return;
+
+    s->busy = 0;
+    s->dav |= mode_regs[s->function];
+    s->function = -1;
+    tsc2005_pin_update(s);
+}
+
+static void tsc2005_touchscreen_event(void *opaque,
+                int x, int y, int z, int buttons_state)
+{
+    TSC2005State *s = opaque;
+    int p = s->pressure;
+
+    if (buttons_state) {
+        s->x = x;
+        s->y = y;
+    }
+    s->pressure = !!buttons_state;
+
+    /*
+     * Note: We would get better responsiveness in the guest by
+     * signaling TS events immediately, but for now we simulate
+     * the first conversion delay for sake of correctness.
+     */
+    if (p != s->pressure)
+        tsc2005_pin_update(s);
+}
+
+static void tsc2005_save(QEMUFile *f, void *opaque)
+{
+    TSC2005State *s = (TSC2005State *) opaque;
+    int i;
+
+    qemu_put_be16(f, s->x);
+    qemu_put_be16(f, s->y);
+    qemu_put_byte(f, s->pressure);
+
+    qemu_put_byte(f, s->state);
+    qemu_put_byte(f, s->reg);
+    qemu_put_byte(f, s->command);
+
+    qemu_put_byte(f, s->irq);
+    qemu_put_be16s(f, &s->dav);
+    qemu_put_be16s(f, &s->data);
+
+    qemu_put_timer(f, s->timer);
+    qemu_put_byte(f, s->enabled);
+    qemu_put_byte(f, s->host_mode);
+    qemu_put_byte(f, s->function);
+    qemu_put_byte(f, s->nextfunction);
+    qemu_put_byte(f, s->precision);
+    qemu_put_byte(f, s->nextprecision);
+    qemu_put_be16(f, s->filter);
+    qemu_put_byte(f, s->pin_func);
+    qemu_put_be16(f, s->timing[0]);
+    qemu_put_be16(f, s->timing[1]);
+    qemu_put_be16s(f, &s->temp_thr[0]);
+    qemu_put_be16s(f, &s->temp_thr[1]);
+    qemu_put_be16s(f, &s->aux_thr[0]);
+    qemu_put_be16s(f, &s->aux_thr[1]);
+    qemu_put_be32(f, s->noise);
+    qemu_put_byte(f, s->reset);
+    qemu_put_byte(f, s->pdst);
+    qemu_put_byte(f, s->pnd0);
+
+    for (i = 0; i < 8; i ++)
+        qemu_put_be32(f, s->tr[i]);
+}
+
+static int tsc2005_load(QEMUFile *f, void *opaque, int version_id)
+{
+    TSC2005State *s = (TSC2005State *) opaque;
+    int i;
+
+    s->x = qemu_get_be16(f);
+    s->y = qemu_get_be16(f);
+    s->pressure = qemu_get_byte(f);
+
+    s->state = qemu_get_byte(f);
+    s->reg = qemu_get_byte(f);
+    s->command = qemu_get_byte(f);
+
+    s->irq = qemu_get_byte(f);
+    qemu_get_be16s(f, &s->dav);
+    qemu_get_be16s(f, &s->data);
+
+    qemu_get_timer(f, s->timer);
+    s->enabled = qemu_get_byte(f);
+    s->host_mode = qemu_get_byte(f);
+    s->function = qemu_get_byte(f);
+    s->nextfunction = qemu_get_byte(f);
+    s->precision = qemu_get_byte(f);
+    s->nextprecision = qemu_get_byte(f);
+    s->filter = qemu_get_be16(f);
+    s->pin_func = qemu_get_byte(f);
+    s->timing[0] = qemu_get_be16(f);
+    s->timing[1] = qemu_get_be16(f);
+    qemu_get_be16s(f, &s->temp_thr[0]);
+    qemu_get_be16s(f, &s->temp_thr[1]);
+    qemu_get_be16s(f, &s->aux_thr[0]);
+    qemu_get_be16s(f, &s->aux_thr[1]);
+    s->noise = qemu_get_be32(f);
+    s->reset = qemu_get_byte(f);
+    s->pdst = qemu_get_byte(f);
+    s->pnd0 = qemu_get_byte(f);
+
+    for (i = 0; i < 8; i ++)
+        s->tr[i] = qemu_get_be32(f);
+
+    s->busy = qemu_timer_pending(s->timer);
+    tsc2005_pin_update(s);
+
+    return 0;
+}
+
+void *tsc2005_init(qemu_irq pintdav)
+{
+    TSC2005State *s;
+
+    s = (TSC2005State *)
+            g_malloc0(sizeof(TSC2005State));
+    s->x = 400;
+    s->y = 240;
+    s->pressure = 0;
+    s->precision = s->nextprecision = 0;
+    s->timer = qemu_new_timer_ns(vm_clock, tsc2005_timer_tick, s);
+    s->pint = pintdav;
+    s->model = 0x2005;
+
+    s->tr[0] = 0;
+    s->tr[1] = 1;
+    s->tr[2] = 1;
+    s->tr[3] = 0;
+    s->tr[4] = 1;
+    s->tr[5] = 0;
+    s->tr[6] = 1;
+    s->tr[7] = 0;
+
+    tsc2005_reset(s);
+
+    qemu_add_mouse_event_handler(tsc2005_touchscreen_event, s, 1,
+                    "QEMU TSC2005-driven Touchscreen");
+
+    qemu_register_reset((void *) tsc2005_reset, s);
+    register_savevm(NULL, "tsc2005", -1, 0, tsc2005_save, tsc2005_load, s);
+
+    return s;
+}
+
+/*
+ * Use tslib generated calibration data to generate ADC input values
+ * from the touchscreen.  Assuming 12-bit precision was used during
+ * tslib calibration.
+ */
+void tsc2005_set_transform(void *opaque, MouseTransformInfo *info)
+{
+    TSC2005State *s = (TSC2005State *) opaque;
+
+    /* This version assumes touchscreen X & Y axis are parallel or
+     * perpendicular to LCD's  X & Y axis in some way.  */
+    if (abs(info->a[0]) > abs(info->a[1])) {
+        s->tr[0] = 0;
+        s->tr[1] = -info->a[6] * info->x;
+        s->tr[2] = info->a[0];
+        s->tr[3] = -info->a[2] / info->a[0];
+        s->tr[4] = info->a[6] * info->y;
+        s->tr[5] = 0;
+        s->tr[6] = info->a[4];
+        s->tr[7] = -info->a[5] / info->a[4];
+    } else {
+        s->tr[0] = info->a[6] * info->y;
+        s->tr[1] = 0;
+        s->tr[2] = info->a[1];
+        s->tr[3] = -info->a[2] / info->a[1];
+        s->tr[4] = 0;
+        s->tr[5] = -info->a[6] * info->x;
+        s->tr[6] = info->a[3];
+        s->tr[7] = -info->a[5] / info->a[3];
+    }
+
+    s->tr[0] >>= 11;
+    s->tr[1] >>= 11;
+    s->tr[3] <<= 4;
+    s->tr[4] >>= 11;
+    s->tr[5] >>= 11;
+    s->tr[7] <<= 4;
+}
diff --git a/hw/input/tsc210x.c b/hw/input/tsc210x.c
new file mode 100644 (file)
index 0000000..e6c217c
--- /dev/null
@@ -0,0 +1,1293 @@
+/*
+ * TI TSC2102 (touchscreen/sensors/audio controller) emulator.
+ * TI TSC2301 (touchscreen/sensors/keypad).
+ *
+ * Copyright (c) 2006 Andrzej Zaborowski  <balrog@zabor.org>
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * 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 or
+ * (at your option) version 3 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
+ * 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 "hw/hw.h"
+#include "audio/audio.h"
+#include "qemu/timer.h"
+#include "ui/console.h"
+#include "hw/arm/omap.h"       /* For I2SCodec and uWireSlave */
+#include "hw/arm/devices.h"
+
+#define TSC_DATA_REGISTERS_PAGE                0x0
+#define TSC_CONTROL_REGISTERS_PAGE     0x1
+#define TSC_AUDIO_REGISTERS_PAGE       0x2
+
+#define TSC_VERBOSE
+
+#define TSC_CUT_RESOLUTION(value, p)   ((value) >> (16 - resolution[p]))
+
+typedef struct {
+    qemu_irq pint;
+    qemu_irq kbint;
+    qemu_irq davint;
+    QEMUTimer *timer;
+    QEMUSoundCard card;
+    uWireSlave chip;
+    I2SCodec codec;
+    uint8_t in_fifo[16384];
+    uint8_t out_fifo[16384];
+    uint16_t model;
+
+    int x, y;
+    int pressure;
+
+    int state, page, offset, irq;
+    uint16_t command, dav;
+
+    int busy;
+    int enabled;
+    int host_mode;
+    int function;
+    int nextfunction;
+    int precision;
+    int nextprecision;
+    int filter;
+    int pin_func;
+    int ref;
+    int timing;
+    int noise;
+
+    uint16_t audio_ctrl1;
+    uint16_t audio_ctrl2;
+    uint16_t audio_ctrl3;
+    uint16_t pll[3];
+    uint16_t volume;
+    int64_t volume_change;
+    int softstep;
+    uint16_t dac_power;
+    int64_t powerdown;
+    uint16_t filter_data[0x14];
+
+    const char *name;
+    SWVoiceIn *adc_voice[1];
+    SWVoiceOut *dac_voice[1];
+    int i2s_rx_rate;
+    int i2s_tx_rate;
+
+    int tr[8];
+
+    struct {
+        uint16_t down;
+        uint16_t mask;
+        int scan;
+        int debounce;
+        int mode;
+        int intr;
+    } kb;
+} TSC210xState;
+
+static const int resolution[4] = { 12, 8, 10, 12 };
+
+#define TSC_MODE_NO_SCAN       0x0
+#define TSC_MODE_XY_SCAN       0x1
+#define TSC_MODE_XYZ_SCAN      0x2
+#define TSC_MODE_X             0x3
+#define TSC_MODE_Y             0x4
+#define TSC_MODE_Z             0x5
+#define TSC_MODE_BAT1          0x6
+#define TSC_MODE_BAT2          0x7
+#define TSC_MODE_AUX           0x8
+#define TSC_MODE_AUX_SCAN      0x9
+#define TSC_MODE_TEMP1         0xa
+#define TSC_MODE_PORT_SCAN     0xb
+#define TSC_MODE_TEMP2         0xc
+#define TSC_MODE_XX_DRV                0xd
+#define TSC_MODE_YY_DRV                0xe
+#define TSC_MODE_YX_DRV                0xf
+
+static const uint16_t mode_regs[16] = {
+    0x0000,    /* No scan */
+    0x0600,    /* X, Y scan */
+    0x0780,    /* X, Y, Z scan */
+    0x0400,    /* X */
+    0x0200,    /* Y */
+    0x0180,    /* Z */
+    0x0040,    /* BAT1 */
+    0x0030,    /* BAT2 */
+    0x0010,    /* AUX */
+    0x0010,    /* AUX scan */
+    0x0004,    /* TEMP1 */
+    0x0070,    /* Port scan */
+    0x0002,    /* TEMP2 */
+    0x0000,    /* X+, X- drivers */
+    0x0000,    /* Y+, Y- drivers */
+    0x0000,    /* Y+, X- drivers */
+};
+
+#define X_TRANSFORM(s)                 \
+    ((s->y * s->tr[0] - s->x * s->tr[1]) / s->tr[2] + s->tr[3])
+#define Y_TRANSFORM(s)                 \
+    ((s->y * s->tr[4] - s->x * s->tr[5]) / s->tr[6] + s->tr[7])
+#define Z1_TRANSFORM(s)                        \
+    ((400 - ((s)->x >> 7) + ((s)->pressure << 10)) << 4)
+#define Z2_TRANSFORM(s)                        \
+    ((4000 + ((s)->y >> 7) - ((s)->pressure << 10)) << 4)
+
+#define BAT1_VAL                       0x8660
+#define BAT2_VAL                       0x0000
+#define AUX1_VAL                       0x35c0
+#define AUX2_VAL                       0xffff
+#define TEMP1_VAL                      0x8c70
+#define TEMP2_VAL                      0xa5b0
+
+#define TSC_POWEROFF_DELAY             50
+#define TSC_SOFTSTEP_DELAY             50
+
+static void tsc210x_reset(TSC210xState *s)
+{
+    s->state = 0;
+    s->pin_func = 2;
+    s->enabled = 0;
+    s->busy = 0;
+    s->nextfunction = 0;
+    s->ref = 0;
+    s->timing = 0;
+    s->irq = 0;
+    s->dav = 0;
+
+    s->audio_ctrl1 = 0x0000;
+    s->audio_ctrl2 = 0x4410;
+    s->audio_ctrl3 = 0x0000;
+    s->pll[0] = 0x1004;
+    s->pll[1] = 0x0000;
+    s->pll[2] = 0x1fff;
+    s->volume = 0xffff;
+    s->dac_power = 0x8540;
+    s->softstep = 1;
+    s->volume_change = 0;
+    s->powerdown = 0;
+    s->filter_data[0x00] = 0x6be3;
+    s->filter_data[0x01] = 0x9666;
+    s->filter_data[0x02] = 0x675d;
+    s->filter_data[0x03] = 0x6be3;
+    s->filter_data[0x04] = 0x9666;
+    s->filter_data[0x05] = 0x675d;
+    s->filter_data[0x06] = 0x7d83;
+    s->filter_data[0x07] = 0x84ee;
+    s->filter_data[0x08] = 0x7d83;
+    s->filter_data[0x09] = 0x84ee;
+    s->filter_data[0x0a] = 0x6be3;
+    s->filter_data[0x0b] = 0x9666;
+    s->filter_data[0x0c] = 0x675d;
+    s->filter_data[0x0d] = 0x6be3;
+    s->filter_data[0x0e] = 0x9666;
+    s->filter_data[0x0f] = 0x675d;
+    s->filter_data[0x10] = 0x7d83;
+    s->filter_data[0x11] = 0x84ee;
+    s->filter_data[0x12] = 0x7d83;
+    s->filter_data[0x13] = 0x84ee;
+
+    s->i2s_tx_rate = 0;
+    s->i2s_rx_rate = 0;
+
+    s->kb.scan = 1;
+    s->kb.debounce = 0;
+    s->kb.mask = 0x0000;
+    s->kb.mode = 3;
+    s->kb.intr = 0;
+
+    qemu_set_irq(s->pint, !s->irq);
+    qemu_set_irq(s->davint, !s->dav);
+    qemu_irq_raise(s->kbint);
+}
+
+typedef struct {
+    int rate;
+    int dsor;
+    int fsref;
+} TSC210xRateInfo;
+
+/*  { rate,  dsor,  fsref } */
+static const TSC210xRateInfo tsc2101_rates[] = {
+    /* Fsref / 6.0 */
+    { 7350,    7,      1 },
+    { 8000,    7,      0 },
+    /* Fsref / 5.5 */
+    { 8018,    6,      1 },
+    { 8727,    6,      0 },
+    /* Fsref / 5.0 */
+    { 8820,    5,      1 },
+    { 9600,    5,      0 },
+    /* Fsref / 4.0 */
+    { 11025,   4,      1 },
+    { 12000,   4,      0 },
+    /* Fsref / 3.0 */
+    { 14700,   3,      1 },
+    { 16000,   3,      0 },
+    /* Fsref / 2.0 */
+    { 22050,   2,      1 },
+    { 24000,   2,      0 },
+    /* Fsref / 1.5 */
+    { 29400,   1,      1 },
+    { 32000,   1,      0 },
+    /* Fsref */
+    { 44100,   0,      1 },
+    { 48000,   0,      0 },
+
+    { 0,       0,      0 },
+};
+
+/*  { rate,   dsor, fsref }    */
+static const TSC210xRateInfo tsc2102_rates[] = {
+    /* Fsref / 6.0 */
+    { 7350,    63,     1 },
+    { 8000,    63,     0 },
+    /* Fsref / 6.0 */
+    { 7350,    54,     1 },
+    { 8000,    54,     0 },
+    /* Fsref / 5.0 */
+    { 8820,    45,     1 },
+    { 9600,    45,     0 },
+    /* Fsref / 4.0 */
+    { 11025,   36,     1 },
+    { 12000,   36,     0 },
+    /* Fsref / 3.0 */
+    { 14700,   27,     1 },
+    { 16000,   27,     0 },
+    /* Fsref / 2.0 */
+    { 22050,   18,     1 },
+    { 24000,   18,     0 },
+    /* Fsref / 1.5 */
+    { 29400,   9,      1 },
+    { 32000,   9,      0 },
+    /* Fsref */
+    { 44100,   0,      1 },
+    { 48000,   0,      0 },
+
+    { 0,       0,      0 },
+};
+
+static inline void tsc210x_out_flush(TSC210xState *s, int len)
+{
+    uint8_t *data = s->codec.out.fifo + s->codec.out.start;
+    uint8_t *end = data + len;
+
+    while (data < end)
+        data += AUD_write(s->dac_voice[0], data, end - data) ?: (end - data);
+
+    s->codec.out.len -= len;
+    if (s->codec.out.len)
+        memmove(s->codec.out.fifo, end, s->codec.out.len);
+    s->codec.out.start = 0;
+}
+
+static void tsc210x_audio_out_cb(TSC210xState *s, int free_b)
+{
+    if (s->codec.out.len >= free_b) {
+        tsc210x_out_flush(s, free_b);
+        return;
+    }
+
+    s->codec.out.size = MIN(free_b, 16384);
+    qemu_irq_raise(s->codec.tx_start);
+}
+
+static void tsc2102_audio_rate_update(TSC210xState *s)
+{
+    const TSC210xRateInfo *rate;
+
+    s->codec.tx_rate = 0;
+    s->codec.rx_rate = 0;
+    if (s->dac_power & (1 << 15))                              /* PWDNC */
+        return;
+
+    for (rate = tsc2102_rates; rate->rate; rate ++)
+        if (rate->dsor == (s->audio_ctrl1 & 0x3f) &&           /* DACFS */
+                        rate->fsref == ((s->audio_ctrl3 >> 13) & 1))/* REFFS */
+            break;
+    if (!rate->rate) {
+        printf("%s: unknown sampling rate configured\n", __FUNCTION__);
+        return;
+    }
+
+    s->codec.tx_rate = rate->rate;
+}
+
+static void tsc2102_audio_output_update(TSC210xState *s)
+{
+    int enable;
+    struct audsettings fmt;
+
+    if (s->dac_voice[0]) {
+        tsc210x_out_flush(s, s->codec.out.len);
+        s->codec.out.size = 0;
+        AUD_set_active_out(s->dac_voice[0], 0);
+        AUD_close_out(&s->card, s->dac_voice[0]);
+        s->dac_voice[0] = NULL;
+    }
+    s->codec.cts = 0;
+
+    enable =
+            (~s->dac_power & (1 << 15)) &&                     /* PWDNC */
+            (~s->dac_power & (1 << 10));                       /* DAPWDN */
+    if (!enable || !s->codec.tx_rate)
+        return;
+
+    /* Force our own sampling rate even in slave DAC mode */
+    fmt.endianness = 0;
+    fmt.nchannels = 2;
+    fmt.freq = s->codec.tx_rate;
+    fmt.fmt = AUD_FMT_S16;
+
+    s->dac_voice[0] = AUD_open_out(&s->card, s->dac_voice[0],
+                    "tsc2102.sink", s, (void *) tsc210x_audio_out_cb, &fmt);
+    if (s->dac_voice[0]) {
+        s->codec.cts = 1;
+        AUD_set_active_out(s->dac_voice[0], 1);
+    }
+}
+
+static uint16_t tsc2102_data_register_read(TSC210xState *s, int reg)
+{
+    switch (reg) {
+    case 0x00: /* X */
+        s->dav &= 0xfbff;
+        return TSC_CUT_RESOLUTION(X_TRANSFORM(s), s->precision) +
+                (s->noise & 3);
+
+    case 0x01: /* Y */
+        s->noise ++;
+        s->dav &= 0xfdff;
+        return TSC_CUT_RESOLUTION(Y_TRANSFORM(s), s->precision) ^
+                (s->noise & 3);
+
+    case 0x02: /* Z1 */
+        s->dav &= 0xfeff;
+        return TSC_CUT_RESOLUTION(Z1_TRANSFORM(s), s->precision) -
+                (s->noise & 3);
+
+    case 0x03: /* Z2 */
+        s->dav &= 0xff7f;
+        return TSC_CUT_RESOLUTION(Z2_TRANSFORM(s), s->precision) |
+                (s->noise & 3);
+
+    case 0x04: /* KPData */
+        if ((s->model & 0xff00) == 0x2300) {
+            if (s->kb.intr && (s->kb.mode & 2)) {
+                s->kb.intr = 0;
+                qemu_irq_raise(s->kbint);
+            }
+            return s->kb.down;
+        }
+
+        return 0xffff;
+
+    case 0x05: /* BAT1 */
+        s->dav &= 0xffbf;
+        return TSC_CUT_RESOLUTION(BAT1_VAL, s->precision) +
+                (s->noise & 6);
+
+    case 0x06: /* BAT2 */
+        s->dav &= 0xffdf;
+        return TSC_CUT_RESOLUTION(BAT2_VAL, s->precision);
+
+    case 0x07: /* AUX1 */
+        s->dav &= 0xffef;
+        return TSC_CUT_RESOLUTION(AUX1_VAL, s->precision);
+
+    case 0x08: /* AUX2 */
+        s->dav &= 0xfff7;
+        return 0xffff;
+
+    case 0x09: /* TEMP1 */
+        s->dav &= 0xfffb;
+        return TSC_CUT_RESOLUTION(TEMP1_VAL, s->precision) -
+                (s->noise & 5);
+
+    case 0x0a: /* TEMP2 */
+        s->dav &= 0xfffd;
+        return TSC_CUT_RESOLUTION(TEMP2_VAL, s->precision) ^
+                (s->noise & 3);
+
+    case 0x0b: /* DAC */
+        s->dav &= 0xfffe;
+        return 0xffff;
+
+    default:
+#ifdef TSC_VERBOSE
+        fprintf(stderr, "tsc2102_data_register_read: "
+                        "no such register: 0x%02x\n", reg);
+#endif
+        return 0xffff;
+    }
+}
+
+static uint16_t tsc2102_control_register_read(
+                TSC210xState *s, int reg)
+{
+    switch (reg) {
+    case 0x00: /* TSC ADC */
+        return (s->pressure << 15) | ((!s->busy) << 14) |
+                (s->nextfunction << 10) | (s->nextprecision << 8) | s->filter; 
+
+    case 0x01: /* Status / Keypad Control */
+        if ((s->model & 0xff00) == 0x2100)
+            return (s->pin_func << 14) | ((!s->enabled) << 13) |
+                    (s->host_mode << 12) | ((!!s->dav) << 11) | s->dav;
+        else
+            return (s->kb.intr << 15) | ((s->kb.scan || !s->kb.down) << 14) |
+                    (s->kb.debounce << 11);
+
+    case 0x02: /* DAC Control */
+        if ((s->model & 0xff00) == 0x2300)
+            return s->dac_power & 0x8000;
+        else
+            goto bad_reg;
+
+    case 0x03: /* Reference */
+        return s->ref;
+
+    case 0x04: /* Reset */
+        return 0xffff;
+
+    case 0x05: /* Configuration */
+        return s->timing;
+
+    case 0x06: /* Secondary configuration */
+        if ((s->model & 0xff00) == 0x2100)
+            goto bad_reg;
+        return ((!s->dav) << 15) | ((s->kb.mode & 1) << 14) | s->pll[2];
+
+    case 0x10: /* Keypad Mask */
+        if ((s->model & 0xff00) == 0x2100)
+            goto bad_reg;
+        return s->kb.mask;
+
+    default:
+    bad_reg:
+#ifdef TSC_VERBOSE
+        fprintf(stderr, "tsc2102_control_register_read: "
+                        "no such register: 0x%02x\n", reg);
+#endif
+        return 0xffff;
+    }
+}
+
+static uint16_t tsc2102_audio_register_read(TSC210xState *s, int reg)
+{
+    int l_ch, r_ch;
+    uint16_t val;
+
+    switch (reg) {
+    case 0x00: /* Audio Control 1 */
+        return s->audio_ctrl1;
+
+    case 0x01:
+        return 0xff00;
+
+    case 0x02: /* DAC Volume Control */
+        return s->volume;
+
+    case 0x03:
+        return 0x8b00;
+
+    case 0x04: /* Audio Control 2 */
+        l_ch = 1;
+        r_ch = 1;
+        if (s->softstep && !(s->dac_power & (1 << 10))) {
+            l_ch = (qemu_get_clock_ns(vm_clock) >
+                            s->volume_change + TSC_SOFTSTEP_DELAY);
+            r_ch = (qemu_get_clock_ns(vm_clock) >
+                            s->volume_change + TSC_SOFTSTEP_DELAY);
+        }
+
+        return s->audio_ctrl2 | (l_ch << 3) | (r_ch << 2);
+
+    case 0x05: /* Stereo DAC Power Control */
+        return 0x2aa0 | s->dac_power |
+                (((s->dac_power & (1 << 10)) &&
+                  (qemu_get_clock_ns(vm_clock) >
+                   s->powerdown + TSC_POWEROFF_DELAY)) << 6);
+
+    case 0x06: /* Audio Control 3 */
+        val = s->audio_ctrl3 | 0x0001;
+        s->audio_ctrl3 &= 0xff3f;
+        return val;
+
+    case 0x07: /* LCH_BASS_BOOST_N0 */
+    case 0x08: /* LCH_BASS_BOOST_N1 */
+    case 0x09: /* LCH_BASS_BOOST_N2 */
+    case 0x0a: /* LCH_BASS_BOOST_N3 */
+    case 0x0b: /* LCH_BASS_BOOST_N4 */
+    case 0x0c: /* LCH_BASS_BOOST_N5 */
+    case 0x0d: /* LCH_BASS_BOOST_D1 */
+    case 0x0e: /* LCH_BASS_BOOST_D2 */
+    case 0x0f: /* LCH_BASS_BOOST_D4 */
+    case 0x10: /* LCH_BASS_BOOST_D5 */
+    case 0x11: /* RCH_BASS_BOOST_N0 */
+    case 0x12: /* RCH_BASS_BOOST_N1 */
+    case 0x13: /* RCH_BASS_BOOST_N2 */
+    case 0x14: /* RCH_BASS_BOOST_N3 */
+    case 0x15: /* RCH_BASS_BOOST_N4 */
+    case 0x16: /* RCH_BASS_BOOST_N5 */
+    case 0x17: /* RCH_BASS_BOOST_D1 */
+    case 0x18: /* RCH_BASS_BOOST_D2 */
+    case 0x19: /* RCH_BASS_BOOST_D4 */
+    case 0x1a: /* RCH_BASS_BOOST_D5 */
+        return s->filter_data[reg - 0x07];
+
+    case 0x1b: /* PLL Programmability 1 */
+        return s->pll[0];
+
+    case 0x1c: /* PLL Programmability 2 */
+        return s->pll[1];
+
+    case 0x1d: /* Audio Control 4 */
+        return (!s->softstep) << 14;
+
+    default:
+#ifdef TSC_VERBOSE
+        fprintf(stderr, "tsc2102_audio_register_read: "
+                        "no such register: 0x%02x\n", reg);
+#endif
+        return 0xffff;
+    }
+}
+
+static void tsc2102_data_register_write(
+                TSC210xState *s, int reg, uint16_t value)
+{
+    switch (reg) {
+    case 0x00: /* X */
+    case 0x01: /* Y */
+    case 0x02: /* Z1 */
+    case 0x03: /* Z2 */
+    case 0x05: /* BAT1 */
+    case 0x06: /* BAT2 */
+    case 0x07: /* AUX1 */
+    case 0x08: /* AUX2 */
+    case 0x09: /* TEMP1 */
+    case 0x0a: /* TEMP2 */
+        return;
+
+    default:
+#ifdef TSC_VERBOSE
+        fprintf(stderr, "tsc2102_data_register_write: "
+                        "no such register: 0x%02x\n", reg);
+#endif
+    }
+}
+
+static void tsc2102_control_register_write(
+                TSC210xState *s, int reg, uint16_t value)
+{
+    switch (reg) {
+    case 0x00: /* TSC ADC */
+        s->host_mode = value >> 15;
+        s->enabled = !(value & 0x4000);
+        if (s->busy && !s->enabled)
+            qemu_del_timer(s->timer);
+        s->busy &= s->enabled;
+        s->nextfunction = (value >> 10) & 0xf;
+        s->nextprecision = (value >> 8) & 3;
+        s->filter = value & 0xff;
+        return;
+
+    case 0x01: /* Status / Keypad Control */
+        if ((s->model & 0xff00) == 0x2100)
+            s->pin_func = value >> 14;
+       else {
+            s->kb.scan = (value >> 14) & 1;
+            s->kb.debounce = (value >> 11) & 7;
+            if (s->kb.intr && s->kb.scan) {
+                s->kb.intr = 0;
+                qemu_irq_raise(s->kbint);
+            }
+        }
+        return;
+
+    case 0x02: /* DAC Control */
+        if ((s->model & 0xff00) == 0x2300) {
+            s->dac_power &= 0x7fff;
+            s->dac_power |= 0x8000 & value;
+        } else
+            goto bad_reg;
+        break;
+
+    case 0x03: /* Reference */
+        s->ref = value & 0x1f;
+        return;
+
+    case 0x04: /* Reset */
+        if (value == 0xbb00) {
+            if (s->busy)
+                qemu_del_timer(s->timer);
+            tsc210x_reset(s);
+#ifdef TSC_VERBOSE
+        } else {
+            fprintf(stderr, "tsc2102_control_register_write: "
+                            "wrong value written into RESET\n");
+#endif
+        }
+        return;
+
+    case 0x05: /* Configuration */
+        s->timing = value & 0x3f;
+#ifdef TSC_VERBOSE
+        if (value & ~0x3f)
+            fprintf(stderr, "tsc2102_control_register_write: "
+                            "wrong value written into CONFIG\n");
+#endif
+        return;
+
+    case 0x06: /* Secondary configuration */
+        if ((s->model & 0xff00) == 0x2100)
+            goto bad_reg;
+        s->kb.mode = value >> 14;
+        s->pll[2] = value & 0x3ffff;
+        return;
+
+    case 0x10: /* Keypad Mask */
+        if ((s->model & 0xff00) == 0x2100)
+            goto bad_reg;
+        s->kb.mask = value;
+        return;
+
+    default:
+    bad_reg:
+#ifdef TSC_VERBOSE
+        fprintf(stderr, "tsc2102_control_register_write: "
+                        "no such register: 0x%02x\n", reg);
+#endif
+    }
+}
+
+static void tsc2102_audio_register_write(
+                TSC210xState *s, int reg, uint16_t value)
+{
+    switch (reg) {
+    case 0x00: /* Audio Control 1 */
+        s->audio_ctrl1 = value & 0x0f3f;
+#ifdef TSC_VERBOSE
+        if ((value & ~0x0f3f) || ((value & 7) != ((value >> 3) & 7)))
+            fprintf(stderr, "tsc2102_audio_register_write: "
+                            "wrong value written into Audio 1\n");
+#endif
+        tsc2102_audio_rate_update(s);
+        tsc2102_audio_output_update(s);
+        return;
+
+    case 0x01:
+#ifdef TSC_VERBOSE
+        if (value != 0xff00)
+            fprintf(stderr, "tsc2102_audio_register_write: "
+                            "wrong value written into reg 0x01\n");
+#endif
+        return;
+
+    case 0x02: /* DAC Volume Control */
+        s->volume = value;
+        s->volume_change = qemu_get_clock_ns(vm_clock);
+        return;
+
+    case 0x03:
+#ifdef TSC_VERBOSE
+        if (value != 0x8b00)
+            fprintf(stderr, "tsc2102_audio_register_write: "
+                            "wrong value written into reg 0x03\n");
+#endif
+        return;
+
+    case 0x04: /* Audio Control 2 */
+        s->audio_ctrl2 = value & 0xf7f2;
+#ifdef TSC_VERBOSE
+        if (value & ~0xf7fd)
+            fprintf(stderr, "tsc2102_audio_register_write: "
+                            "wrong value written into Audio 2\n");
+#endif
+        return;
+
+    case 0x05: /* Stereo DAC Power Control */
+        if ((value & ~s->dac_power) & (1 << 10))
+            s->powerdown = qemu_get_clock_ns(vm_clock);
+
+        s->dac_power = value & 0x9543;
+#ifdef TSC_VERBOSE
+        if ((value & ~0x9543) != 0x2aa0)
+            fprintf(stderr, "tsc2102_audio_register_write: "
+                            "wrong value written into Power\n");
+#endif
+        tsc2102_audio_rate_update(s);
+        tsc2102_audio_output_update(s);
+        return;
+
+    case 0x06: /* Audio Control 3 */
+        s->audio_ctrl3 &= 0x00c0;
+        s->audio_ctrl3 |= value & 0xf800;
+#ifdef TSC_VERBOSE
+        if (value & ~0xf8c7)
+            fprintf(stderr, "tsc2102_audio_register_write: "
+                            "wrong value written into Audio 3\n");
+#endif
+        tsc2102_audio_output_update(s);
+        return;
+
+    case 0x07: /* LCH_BASS_BOOST_N0 */
+    case 0x08: /* LCH_BASS_BOOST_N1 */
+    case 0x09: /* LCH_BASS_BOOST_N2 */
+    case 0x0a: /* LCH_BASS_BOOST_N3 */
+    case 0x0b: /* LCH_BASS_BOOST_N4 */
+    case 0x0c: /* LCH_BASS_BOOST_N5 */
+    case 0x0d: /* LCH_BASS_BOOST_D1 */
+    case 0x0e: /* LCH_BASS_BOOST_D2 */
+    case 0x0f: /* LCH_BASS_BOOST_D4 */
+    case 0x10: /* LCH_BASS_BOOST_D5 */
+    case 0x11: /* RCH_BASS_BOOST_N0 */
+    case 0x12: /* RCH_BASS_BOOST_N1 */
+    case 0x13: /* RCH_BASS_BOOST_N2 */
+    case 0x14: /* RCH_BASS_BOOST_N3 */
+    case 0x15: /* RCH_BASS_BOOST_N4 */
+    case 0x16: /* RCH_BASS_BOOST_N5 */
+    case 0x17: /* RCH_BASS_BOOST_D1 */
+    case 0x18: /* RCH_BASS_BOOST_D2 */
+    case 0x19: /* RCH_BASS_BOOST_D4 */
+    case 0x1a: /* RCH_BASS_BOOST_D5 */
+        s->filter_data[reg - 0x07] = value;
+        return;
+
+    case 0x1b: /* PLL Programmability 1 */
+        s->pll[0] = value & 0xfffc;
+#ifdef TSC_VERBOSE
+        if (value & ~0xfffc)
+            fprintf(stderr, "tsc2102_audio_register_write: "
+                            "wrong value written into PLL 1\n");
+#endif
+        return;
+
+    case 0x1c: /* PLL Programmability 2 */
+        s->pll[1] = value & 0xfffc;
+#ifdef TSC_VERBOSE
+        if (value & ~0xfffc)
+            fprintf(stderr, "tsc2102_audio_register_write: "
+                            "wrong value written into PLL 2\n");
+#endif
+        return;
+
+    case 0x1d: /* Audio Control 4 */
+        s->softstep = !(value & 0x4000);
+#ifdef TSC_VERBOSE
+        if (value & ~0x4000)
+            fprintf(stderr, "tsc2102_audio_register_write: "
+                            "wrong value written into Audio 4\n");
+#endif
+        return;
+
+    default:
+#ifdef TSC_VERBOSE
+        fprintf(stderr, "tsc2102_audio_register_write: "
+                        "no such register: 0x%02x\n", reg);
+#endif
+    }
+}
+
+/* This handles most of the chip logic.  */
+static void tsc210x_pin_update(TSC210xState *s)
+{
+    int64_t expires;
+    int pin_state;
+
+    switch (s->pin_func) {
+    case 0:
+        pin_state = s->pressure;
+        break;
+    case 1:
+        pin_state = !!s->dav;
+        break;
+    case 2:
+    default:
+        pin_state = s->pressure && !s->dav;
+    }
+
+    if (!s->enabled)
+        pin_state = 0;
+
+    if (pin_state != s->irq) {
+        s->irq = pin_state;
+        qemu_set_irq(s->pint, !s->irq);
+    }
+
+    switch (s->nextfunction) {
+    case TSC_MODE_XY_SCAN:
+    case TSC_MODE_XYZ_SCAN:
+        if (!s->pressure)
+            return;
+        break;
+
+    case TSC_MODE_X:
+    case TSC_MODE_Y:
+    case TSC_MODE_Z:
+        if (!s->pressure)
+            return;
+        /* Fall through */
+    case TSC_MODE_BAT1:
+    case TSC_MODE_BAT2:
+    case TSC_MODE_AUX:
+    case TSC_MODE_TEMP1:
+    case TSC_MODE_TEMP2:
+        if (s->dav)
+            s->enabled = 0;
+        break;
+
+    case TSC_MODE_AUX_SCAN:
+    case TSC_MODE_PORT_SCAN:
+        break;
+
+    case TSC_MODE_NO_SCAN:
+    case TSC_MODE_XX_DRV:
+    case TSC_MODE_YY_DRV:
+    case TSC_MODE_YX_DRV:
+    default:
+        return;
+    }
+
+    if (!s->enabled || s->busy || s->dav)
+        return;
+
+    s->busy = 1;
+    s->precision = s->nextprecision;
+    s->function = s->nextfunction;
+    expires = qemu_get_clock_ns(vm_clock) + (get_ticks_per_sec() >> 10);
+    qemu_mod_timer(s->timer, expires);
+}
+
+static uint16_t tsc210x_read(TSC210xState *s)
+{
+    uint16_t ret = 0x0000;
+
+    if (!s->command)
+        fprintf(stderr, "tsc210x_read: SPI underrun!\n");
+
+    switch (s->page) {
+    case TSC_DATA_REGISTERS_PAGE:
+        ret = tsc2102_data_register_read(s, s->offset);
+        if (!s->dav)
+            qemu_irq_raise(s->davint);
+        break;
+    case TSC_CONTROL_REGISTERS_PAGE:
+        ret = tsc2102_control_register_read(s, s->offset);
+        break;
+    case TSC_AUDIO_REGISTERS_PAGE:
+        ret = tsc2102_audio_register_read(s, s->offset);
+        break;
+    default:
+        hw_error("tsc210x_read: wrong memory page\n");
+    }
+
+    tsc210x_pin_update(s);
+
+    /* Allow sequential reads.  */
+    s->offset ++;
+    s->state = 0;
+    return ret;
+}
+
+static void tsc210x_write(TSC210xState *s, uint16_t value)
+{
+    /*
+     * This is a two-state state machine for reading
+     * command and data every second time.
+     */
+    if (!s->state) {
+        s->command = value >> 15;
+        s->page = (value >> 11) & 0x0f;
+        s->offset = (value >> 5) & 0x3f;
+        s->state = 1;
+    } else {
+        if (s->command)
+            fprintf(stderr, "tsc210x_write: SPI overrun!\n");
+        else
+            switch (s->page) {
+            case TSC_DATA_REGISTERS_PAGE:
+                tsc2102_data_register_write(s, s->offset, value);
+                break;
+            case TSC_CONTROL_REGISTERS_PAGE:
+                tsc2102_control_register_write(s, s->offset, value);
+                break;
+            case TSC_AUDIO_REGISTERS_PAGE:
+                tsc2102_audio_register_write(s, s->offset, value);
+                break;
+            default:
+                hw_error("tsc210x_write: wrong memory page\n");
+            }
+
+        tsc210x_pin_update(s);
+        s->state = 0;
+    }
+}
+
+uint32_t tsc210x_txrx(void *opaque, uint32_t value, int len)
+{
+    TSC210xState *s = opaque;
+    uint32_t ret = 0;
+
+    if (len != 16)
+        hw_error("%s: FIXME: bad SPI word width %i\n", __FUNCTION__, len);
+
+    /* TODO: sequential reads etc - how do we make sure the host doesn't
+     * unintentionally read out a conversion result from a register while
+     * transmitting the command word of the next command?  */
+    if (!value || (s->state && s->command))
+        ret = tsc210x_read(s);
+    if (value || (s->state && !s->command))
+        tsc210x_write(s, value);
+
+    return ret;
+}
+
+static void tsc210x_timer_tick(void *opaque)
+{
+    TSC210xState *s = opaque;
+
+    /* Timer ticked -- a set of conversions has been finished.  */
+
+    if (!s->busy)
+        return;
+
+    s->busy = 0;
+    s->dav |= mode_regs[s->function];
+    tsc210x_pin_update(s);
+    qemu_irq_lower(s->davint);
+}
+
+static void tsc210x_touchscreen_event(void *opaque,
+                int x, int y, int z, int buttons_state)
+{
+    TSC210xState *s = opaque;
+    int p = s->pressure;
+
+    if (buttons_state) {
+        s->x = x;
+        s->y = y;
+    }
+    s->pressure = !!buttons_state;
+
+    /*
+     * Note: We would get better responsiveness in the guest by
+     * signaling TS events immediately, but for now we simulate
+     * the first conversion delay for sake of correctness.
+     */
+    if (p != s->pressure)
+        tsc210x_pin_update(s);
+}
+
+static void tsc210x_i2s_swallow(TSC210xState *s)
+{
+    if (s->dac_voice[0])
+        tsc210x_out_flush(s, s->codec.out.len);
+    else
+        s->codec.out.len = 0;
+}
+
+static void tsc210x_i2s_set_rate(TSC210xState *s, int in, int out)
+{
+    s->i2s_tx_rate = out;
+    s->i2s_rx_rate = in;
+}
+
+static void tsc210x_save(QEMUFile *f, void *opaque)
+{
+    TSC210xState *s = (TSC210xState *) opaque;
+    int64_t now = qemu_get_clock_ns(vm_clock);
+    int i;
+
+    qemu_put_be16(f, s->x);
+    qemu_put_be16(f, s->y);
+    qemu_put_byte(f, s->pressure);
+
+    qemu_put_byte(f, s->state);
+    qemu_put_byte(f, s->page);
+    qemu_put_byte(f, s->offset);
+    qemu_put_byte(f, s->command);
+
+    qemu_put_byte(f, s->irq);
+    qemu_put_be16s(f, &s->dav);
+
+    qemu_put_timer(f, s->timer);
+    qemu_put_byte(f, s->enabled);
+    qemu_put_byte(f, s->host_mode);
+    qemu_put_byte(f, s->function);
+    qemu_put_byte(f, s->nextfunction);
+    qemu_put_byte(f, s->precision);
+    qemu_put_byte(f, s->nextprecision);
+    qemu_put_byte(f, s->filter);
+    qemu_put_byte(f, s->pin_func);
+    qemu_put_byte(f, s->ref);
+    qemu_put_byte(f, s->timing);
+    qemu_put_be32(f, s->noise);
+
+    qemu_put_be16s(f, &s->audio_ctrl1);
+    qemu_put_be16s(f, &s->audio_ctrl2);
+    qemu_put_be16s(f, &s->audio_ctrl3);
+    qemu_put_be16s(f, &s->pll[0]);
+    qemu_put_be16s(f, &s->pll[1]);
+    qemu_put_be16s(f, &s->volume);
+    qemu_put_sbe64(f, (s->volume_change - now));
+    qemu_put_sbe64(f, (s->powerdown - now));
+    qemu_put_byte(f, s->softstep);
+    qemu_put_be16s(f, &s->dac_power);
+
+    for (i = 0; i < 0x14; i ++)
+        qemu_put_be16s(f, &s->filter_data[i]);
+}
+
+static int tsc210x_load(QEMUFile *f, void *opaque, int version_id)
+{
+    TSC210xState *s = (TSC210xState *) opaque;
+    int64_t now = qemu_get_clock_ns(vm_clock);
+    int i;
+
+    s->x = qemu_get_be16(f);
+    s->y = qemu_get_be16(f);
+    s->pressure = qemu_get_byte(f);
+
+    s->state = qemu_get_byte(f);
+    s->page = qemu_get_byte(f);
+    s->offset = qemu_get_byte(f);
+    s->command = qemu_get_byte(f);
+
+    s->irq = qemu_get_byte(f);
+    qemu_get_be16s(f, &s->dav);
+
+    qemu_get_timer(f, s->timer);
+    s->enabled = qemu_get_byte(f);
+    s->host_mode = qemu_get_byte(f);
+    s->function = qemu_get_byte(f);
+    s->nextfunction = qemu_get_byte(f);
+    s->precision = qemu_get_byte(f);
+    s->nextprecision = qemu_get_byte(f);
+    s->filter = qemu_get_byte(f);
+    s->pin_func = qemu_get_byte(f);
+    s->ref = qemu_get_byte(f);
+    s->timing = qemu_get_byte(f);
+    s->noise = qemu_get_be32(f);
+
+    qemu_get_be16s(f, &s->audio_ctrl1);
+    qemu_get_be16s(f, &s->audio_ctrl2);
+    qemu_get_be16s(f, &s->audio_ctrl3);
+    qemu_get_be16s(f, &s->pll[0]);
+    qemu_get_be16s(f, &s->pll[1]);
+    qemu_get_be16s(f, &s->volume);
+    s->volume_change = qemu_get_sbe64(f) + now;
+    s->powerdown = qemu_get_sbe64(f) + now;
+    s->softstep = qemu_get_byte(f);
+    qemu_get_be16s(f, &s->dac_power);
+
+    for (i = 0; i < 0x14; i ++)
+        qemu_get_be16s(f, &s->filter_data[i]);
+
+    s->busy = qemu_timer_pending(s->timer);
+    qemu_set_irq(s->pint, !s->irq);
+    qemu_set_irq(s->davint, !s->dav);
+
+    return 0;
+}
+
+uWireSlave *tsc2102_init(qemu_irq pint)
+{
+    TSC210xState *s;
+
+    s = (TSC210xState *)
+            g_malloc0(sizeof(TSC210xState));
+    memset(s, 0, sizeof(TSC210xState));
+    s->x = 160;
+    s->y = 160;
+    s->pressure = 0;
+    s->precision = s->nextprecision = 0;
+    s->timer = qemu_new_timer_ns(vm_clock, tsc210x_timer_tick, s);
+    s->pint = pint;
+    s->model = 0x2102;
+    s->name = "tsc2102";
+
+    s->tr[0] = 0;
+    s->tr[1] = 1;
+    s->tr[2] = 1;
+    s->tr[3] = 0;
+    s->tr[4] = 1;
+    s->tr[5] = 0;
+    s->tr[6] = 1;
+    s->tr[7] = 0;
+
+    s->chip.opaque = s;
+    s->chip.send = (void *) tsc210x_write;
+    s->chip.receive = (void *) tsc210x_read;
+
+    s->codec.opaque = s;
+    s->codec.tx_swallow = (void *) tsc210x_i2s_swallow;
+    s->codec.set_rate = (void *) tsc210x_i2s_set_rate;
+    s->codec.in.fifo = s->in_fifo;
+    s->codec.out.fifo = s->out_fifo;
+
+    tsc210x_reset(s);
+
+    qemu_add_mouse_event_handler(tsc210x_touchscreen_event, s, 1,
+                    "QEMU TSC2102-driven Touchscreen");
+
+    AUD_register_card(s->name, &s->card);
+
+    qemu_register_reset((void *) tsc210x_reset, s);
+    register_savevm(NULL, s->name, -1, 0,
+                    tsc210x_save, tsc210x_load, s);
+
+    return &s->chip;
+}
+
+uWireSlave *tsc2301_init(qemu_irq penirq, qemu_irq kbirq, qemu_irq dav)
+{
+    TSC210xState *s;
+
+    s = (TSC210xState *)
+            g_malloc0(sizeof(TSC210xState));
+    memset(s, 0, sizeof(TSC210xState));
+    s->x = 400;
+    s->y = 240;
+    s->pressure = 0;
+    s->precision = s->nextprecision = 0;
+    s->timer = qemu_new_timer_ns(vm_clock, tsc210x_timer_tick, s);
+    s->pint = penirq;
+    s->kbint = kbirq;
+    s->davint = dav;
+    s->model = 0x2301;
+    s->name = "tsc2301";
+
+    s->tr[0] = 0;
+    s->tr[1] = 1;
+    s->tr[2] = 1;
+    s->tr[3] = 0;
+    s->tr[4] = 1;
+    s->tr[5] = 0;
+    s->tr[6] = 1;
+    s->tr[7] = 0;
+
+    s->chip.opaque = s;
+    s->chip.send = (void *) tsc210x_write;
+    s->chip.receive = (void *) tsc210x_read;
+
+    s->codec.opaque = s;
+    s->codec.tx_swallow = (void *) tsc210x_i2s_swallow;
+    s->codec.set_rate = (void *) tsc210x_i2s_set_rate;
+    s->codec.in.fifo = s->in_fifo;
+    s->codec.out.fifo = s->out_fifo;
+
+    tsc210x_reset(s);
+
+    qemu_add_mouse_event_handler(tsc210x_touchscreen_event, s, 1,
+                    "QEMU TSC2301-driven Touchscreen");
+
+    AUD_register_card(s->name, &s->card);
+
+    qemu_register_reset((void *) tsc210x_reset, s);
+    register_savevm(NULL, s->name, -1, 0, tsc210x_save, tsc210x_load, s);
+
+    return &s->chip;
+}
+
+I2SCodec *tsc210x_codec(uWireSlave *chip)
+{
+    TSC210xState *s = (TSC210xState *) chip->opaque;
+
+    return &s->codec;
+}
+
+/*
+ * Use tslib generated calibration data to generate ADC input values
+ * from the touchscreen.  Assuming 12-bit precision was used during
+ * tslib calibration.
+ */
+void tsc210x_set_transform(uWireSlave *chip,
+                MouseTransformInfo *info)
+{
+    TSC210xState *s = (TSC210xState *) chip->opaque;
+#if 0
+    int64_t ltr[8];
+
+    ltr[0] = (int64_t) info->a[1] * info->y;
+    ltr[1] = (int64_t) info->a[4] * info->x;
+    ltr[2] = (int64_t) info->a[1] * info->a[3] -
+            (int64_t) info->a[4] * info->a[0];
+    ltr[3] = (int64_t) info->a[2] * info->a[4] -
+            (int64_t) info->a[5] * info->a[1];
+    ltr[4] = (int64_t) info->a[0] * info->y;
+    ltr[5] = (int64_t) info->a[3] * info->x;
+    ltr[6] = (int64_t) info->a[4] * info->a[0] -
+            (int64_t) info->a[1] * info->a[3];
+    ltr[7] = (int64_t) info->a[2] * info->a[3] -
+            (int64_t) info->a[5] * info->a[0];
+
+    /* Avoid integer overflow */
+    s->tr[0] = ltr[0] >> 11;
+    s->tr[1] = ltr[1] >> 11;
+    s->tr[2] = muldiv64(ltr[2], 1, info->a[6]);
+    s->tr[3] = muldiv64(ltr[3], 1 << 4, ltr[2]);
+    s->tr[4] = ltr[4] >> 11;
+    s->tr[5] = ltr[5] >> 11;
+    s->tr[6] = muldiv64(ltr[6], 1, info->a[6]);
+    s->tr[7] = muldiv64(ltr[7], 1 << 4, ltr[6]);
+#else
+
+    /* This version assumes touchscreen X & Y axis are parallel or
+     * perpendicular to LCD's  X & Y axis in some way.  */
+    if (abs(info->a[0]) > abs(info->a[1])) {
+        s->tr[0] = 0;
+        s->tr[1] = -info->a[6] * info->x;
+        s->tr[2] = info->a[0];
+        s->tr[3] = -info->a[2] / info->a[0];
+        s->tr[4] = info->a[6] * info->y;
+        s->tr[5] = 0;
+        s->tr[6] = info->a[4];
+        s->tr[7] = -info->a[5] / info->a[4];
+    } else {
+        s->tr[0] = info->a[6] * info->y;
+        s->tr[1] = 0;
+        s->tr[2] = info->a[1];
+        s->tr[3] = -info->a[2] / info->a[1];
+        s->tr[4] = 0;
+        s->tr[5] = -info->a[6] * info->x;
+        s->tr[6] = info->a[3];
+        s->tr[7] = -info->a[5] / info->a[3];
+    }
+
+    s->tr[0] >>= 11;
+    s->tr[1] >>= 11;
+    s->tr[3] <<= 4;
+    s->tr[4] >>= 11;
+    s->tr[5] >>= 11;
+    s->tr[7] <<= 4;
+#endif
+}
+
+void tsc210x_key_event(uWireSlave *chip, int key, int down)
+{
+    TSC210xState *s = (TSC210xState *) chip->opaque;
+
+    if (down)
+        s->kb.down |= 1 << key;
+    else
+        s->kb.down &= ~(1 << key);
+
+    if (down && (s->kb.down & ~s->kb.mask) && !s->kb.intr) {
+        s->kb.intr = 1;
+        qemu_irq_lower(s->kbint);
+    } else if (s->kb.intr && !(s->kb.down & ~s->kb.mask) &&
+                    !(s->kb.mode & 1)) {
+        s->kb.intr = 0;
+        qemu_irq_raise(s->kbint);
+    }
+}
diff --git a/hw/input/vmmouse.c b/hw/input/vmmouse.c
new file mode 100644 (file)
index 0000000..f4f9c93
--- /dev/null
@@ -0,0 +1,301 @@
+/*
+ * QEMU VMMouse emulation
+ *
+ * Copyright (C) 2007 Anthony Liguori <anthony@codemonkey.ws>
+ *
+ * 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 "hw/hw.h"
+#include "ui/console.h"
+#include "hw/input/ps2.h"
+#include "hw/i386/pc.h"
+#include "hw/qdev.h"
+
+/* debug only vmmouse */
+//#define DEBUG_VMMOUSE
+
+/* VMMouse Commands */
+#define VMMOUSE_GETVERSION     10
+#define VMMOUSE_DATA           39
+#define VMMOUSE_STATUS         40
+#define VMMOUSE_COMMAND                41
+
+#define VMMOUSE_READ_ID                        0x45414552
+#define VMMOUSE_DISABLE                        0x000000f5
+#define VMMOUSE_REQUEST_RELATIVE       0x4c455252
+#define VMMOUSE_REQUEST_ABSOLUTE       0x53424152
+
+#define VMMOUSE_QUEUE_SIZE     1024
+
+#define VMMOUSE_VERSION                0x3442554a
+
+#ifdef DEBUG_VMMOUSE
+#define DPRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__)
+#else
+#define DPRINTF(fmt, ...) do { } while (0)
+#endif
+
+typedef struct _VMMouseState
+{
+    ISADevice dev;
+    uint32_t queue[VMMOUSE_QUEUE_SIZE];
+    int32_t queue_size;
+    uint16_t nb_queue;
+    uint16_t status;
+    uint8_t absolute;
+    QEMUPutMouseEntry *entry;
+    void *ps2_mouse;
+} VMMouseState;
+
+static uint32_t vmmouse_get_status(VMMouseState *s)
+{
+    DPRINTF("vmmouse_get_status()\n");
+    return (s->status << 16) | s->nb_queue;
+}
+
+static void vmmouse_mouse_event(void *opaque, int x, int y, int dz, int buttons_state)
+{
+    VMMouseState *s = opaque;
+    int buttons = 0;
+
+    if (s->nb_queue > (VMMOUSE_QUEUE_SIZE - 4))
+        return;
+
+    DPRINTF("vmmouse_mouse_event(%d, %d, %d, %d)\n",
+            x, y, dz, buttons_state);
+
+    if ((buttons_state & MOUSE_EVENT_LBUTTON))
+        buttons |= 0x20;
+    if ((buttons_state & MOUSE_EVENT_RBUTTON))
+        buttons |= 0x10;
+    if ((buttons_state & MOUSE_EVENT_MBUTTON))
+        buttons |= 0x08;
+
+    if (s->absolute) {
+        x <<= 1;
+        y <<= 1;
+    }
+
+    s->queue[s->nb_queue++] = buttons;
+    s->queue[s->nb_queue++] = x;
+    s->queue[s->nb_queue++] = y;
+    s->queue[s->nb_queue++] = dz;
+
+    /* need to still generate PS2 events to notify driver to
+       read from queue */
+    i8042_isa_mouse_fake_event(s->ps2_mouse);
+}
+
+static void vmmouse_remove_handler(VMMouseState *s)
+{
+    if (s->entry) {
+        qemu_remove_mouse_event_handler(s->entry);
+        s->entry = NULL;
+    }
+}
+
+static void vmmouse_update_handler(VMMouseState *s, int absolute)
+{
+    if (s->status != 0) {
+        return;
+    }
+    if (s->absolute != absolute) {
+        s->absolute = absolute;
+        vmmouse_remove_handler(s);
+    }
+    if (s->entry == NULL) {
+        s->entry = qemu_add_mouse_event_handler(vmmouse_mouse_event,
+                                                s, s->absolute,
+                                                "vmmouse");
+        qemu_activate_mouse_event_handler(s->entry);
+    }
+}
+
+static void vmmouse_read_id(VMMouseState *s)
+{
+    DPRINTF("vmmouse_read_id()\n");
+
+    if (s->nb_queue == VMMOUSE_QUEUE_SIZE)
+        return;
+
+    s->queue[s->nb_queue++] = VMMOUSE_VERSION;
+    s->status = 0;
+}
+
+static void vmmouse_request_relative(VMMouseState *s)
+{
+    DPRINTF("vmmouse_request_relative()\n");
+    vmmouse_update_handler(s, 0);
+}
+
+static void vmmouse_request_absolute(VMMouseState *s)
+{
+    DPRINTF("vmmouse_request_absolute()\n");
+    vmmouse_update_handler(s, 1);
+}
+
+static void vmmouse_disable(VMMouseState *s)
+{
+    DPRINTF("vmmouse_disable()\n");
+    s->status = 0xffff;
+    vmmouse_remove_handler(s);
+}
+
+static void vmmouse_data(VMMouseState *s, uint32_t *data, uint32_t size)
+{
+    int i;
+
+    DPRINTF("vmmouse_data(%d)\n", size);
+
+    if (size == 0 || size > 6 || size > s->nb_queue) {
+        printf("vmmouse: driver requested too much data %d\n", size);
+        s->status = 0xffff;
+        vmmouse_remove_handler(s);
+        return;
+    }
+
+    for (i = 0; i < size; i++)
+        data[i] = s->queue[i];
+
+    s->nb_queue -= size;
+    if (s->nb_queue)
+        memmove(s->queue, &s->queue[size], sizeof(s->queue[0]) * s->nb_queue);
+}
+
+static uint32_t vmmouse_ioport_read(void *opaque, uint32_t addr)
+{
+    VMMouseState *s = opaque;
+    uint32_t data[6];
+    uint16_t command;
+
+    vmmouse_get_data(data);
+
+    command = data[2] & 0xFFFF;
+
+    switch (command) {
+    case VMMOUSE_STATUS:
+        data[0] = vmmouse_get_status(s);
+        break;
+    case VMMOUSE_COMMAND:
+        switch (data[1]) {
+        case VMMOUSE_DISABLE:
+            vmmouse_disable(s);
+            break;
+        case VMMOUSE_READ_ID:
+            vmmouse_read_id(s);
+            break;
+        case VMMOUSE_REQUEST_RELATIVE:
+            vmmouse_request_relative(s);
+            break;
+        case VMMOUSE_REQUEST_ABSOLUTE:
+            vmmouse_request_absolute(s);
+            break;
+        default:
+            printf("vmmouse: unknown command %x\n", data[1]);
+            break;
+        }
+        break;
+    case VMMOUSE_DATA:
+        vmmouse_data(s, data, data[1]);
+        break;
+    default:
+        printf("vmmouse: unknown command %x\n", command);
+        break;
+    }
+
+    vmmouse_set_data(data);
+    return data[0];
+}
+
+static int vmmouse_post_load(void *opaque, int version_id)
+{
+    VMMouseState *s = opaque;
+
+    vmmouse_remove_handler(s);
+    vmmouse_update_handler(s, s->absolute);
+    return 0;
+}
+
+static const VMStateDescription vmstate_vmmouse = {
+    .name = "vmmouse",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .post_load = vmmouse_post_load,
+    .fields      = (VMStateField []) {
+        VMSTATE_INT32_EQUAL(queue_size, VMMouseState),
+        VMSTATE_UINT32_ARRAY(queue, VMMouseState, VMMOUSE_QUEUE_SIZE),
+        VMSTATE_UINT16(nb_queue, VMMouseState),
+        VMSTATE_UINT16(status, VMMouseState),
+        VMSTATE_UINT8(absolute, VMMouseState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void vmmouse_reset(DeviceState *d)
+{
+    VMMouseState *s = container_of(d, VMMouseState, dev.qdev);
+
+    s->queue_size = VMMOUSE_QUEUE_SIZE;
+
+    vmmouse_disable(s);
+}
+
+static int vmmouse_initfn(ISADevice *dev)
+{
+    VMMouseState *s = DO_UPCAST(VMMouseState, dev, dev);
+
+    DPRINTF("vmmouse_init\n");
+
+    vmport_register(VMMOUSE_STATUS, vmmouse_ioport_read, s);
+    vmport_register(VMMOUSE_COMMAND, vmmouse_ioport_read, s);
+    vmport_register(VMMOUSE_DATA, vmmouse_ioport_read, s);
+
+    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 const TypeInfo vmmouse_info = {
+    .name          = "vmmouse",
+    .parent        = TYPE_ISA_DEVICE,
+    .instance_size = sizeof(VMMouseState),
+    .class_init    = vmmouse_class_initfn,
+};
+
+static void vmmouse_register_types(void)
+{
+    type_register_static(&vmmouse_info);
+}
+
+type_init(vmmouse_register_types)
diff --git a/hw/intc/Makefile.objs b/hw/intc/Makefile.objs
new file mode 100644 (file)
index 0000000..718d97a
--- /dev/null
@@ -0,0 +1,23 @@
+common-obj-$(CONFIG_HEATHROW_PIC) += heathrow_pic.o
+common-obj-$(CONFIG_I8259) += i8259_common.o i8259.o
+common-obj-$(CONFIG_PL190) += pl190.o
+common-obj-$(CONFIG_PUV3) += puv3_intc.o
+common-obj-$(CONFIG_XILINX) += xilinx_intc.o
+common-obj-$(CONFIG_ETRAXFS) += etraxfs_pic.o
+common-obj-$(CONFIG_IMX) += imx_avic.o
+common-obj-$(CONFIG_LM32) += lm32_pic.o
+common-obj-$(CONFIG_REALVIEW) += realview_gic.o
+common-obj-$(CONFIG_SLAVIO) += sbi.o slavio_intctl.o sun4c_intctl.o
+common-obj-$(CONFIG_IOAPIC) += ioapic_common.o
+common-obj-$(CONFIG_ARM_GIC) += arm_gic_common.o
+
+obj-$(CONFIG_APIC) += apic.o apic_common.o
+obj-$(CONFIG_ARM_GIC) += arm_gic.o
+obj-$(CONFIG_ARM_GIC_KVM) += arm_gic_kvm.o
+obj-$(CONFIG_STELLARIS) += armv7m_nvic.o
+obj-$(CONFIG_EXYNOS4) += exynos4210_gic.o exynos4210_combiner.o
+obj-$(CONFIG_GRLIB) += grlib_irqmp.o
+obj-$(CONFIG_IOAPIC) += ioapic.o
+obj-$(CONFIG_OMAP) += omap_intc.o
+obj-$(CONFIG_OPENPIC) += openpic.o
+obj-$(CONFIG_SH4) += sh_intc.o
diff --git a/hw/intc/apic.c b/hw/intc/apic.c
new file mode 100644 (file)
index 0000000..2d79a9e
--- /dev/null
@@ -0,0 +1,911 @@
+/*
+ *  APIC support
+ *
+ *  Copyright (c) 2004-2005 Fabrice Bellard
+ *
+ * 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 "qemu/thread.h"
+#include "hw/i386/apic_internal.h"
+#include "hw/i386/apic.h"
+#include "hw/i386/ioapic.h"
+#include "hw/pci/msi.h"
+#include "qemu/host-utils.h"
+#include "trace.h"
+#include "hw/i386/pc.h"
+#include "hw/i386/apic-msidef.h"
+
+#define MAX_APIC_WORDS 8
+
+#define SYNC_FROM_VAPIC                 0x1
+#define SYNC_TO_VAPIC                   0x2
+#define SYNC_ISR_IRR_TO_VAPIC           0x4
+
+static APICCommonState *local_apics[MAX_APICS + 1];
+
+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);
+
+/* Find first bit starting from msb */
+static int fls_bit(uint32_t value)
+{
+    return 31 - clz32(value);
+}
+
+/* Find first bit starting from lsb */
+static int ffs_bit(uint32_t value)
+{
+    return ctz32(value);
+}
+
+static inline void set_bit(uint32_t *tab, int index)
+{
+    int i, mask;
+    i = index >> 5;
+    mask = 1 << (index & 0x1f);
+    tab[i] |= mask;
+}
+
+static inline void reset_bit(uint32_t *tab, int index)
+{
+    int i, mask;
+    i = index >> 5;
+    mask = 1 << (index & 0x1f);
+    tab[i] &= ~mask;
+}
+
+static inline int get_bit(uint32_t *tab, int index)
+{
+    int i, mask;
+    i = index >> 5;
+    mask = 1 << (index & 0x1f);
+    return !!(tab[i] & mask);
+}
+
+/* return -1 if no bit is set */
+static int get_highest_priority_int(uint32_t *tab)
+{
+    int i;
+    for (i = 7; i >= 0; i--) {
+        if (tab[i] != 0) {
+            return i * 32 + fls_bit(tab[i]);
+        }
+    }
+    return -1;
+}
+
+static void apic_sync_vapic(APICCommonState *s, int sync_type)
+{
+    VAPICState vapic_state;
+    size_t length;
+    off_t start;
+    int vector;
+
+    if (!s->vapic_paddr) {
+        return;
+    }
+    if (sync_type & SYNC_FROM_VAPIC) {
+        cpu_physical_memory_rw(s->vapic_paddr, (void *)&vapic_state,
+                               sizeof(vapic_state), 0);
+        s->tpr = vapic_state.tpr;
+    }
+    if (sync_type & (SYNC_TO_VAPIC | SYNC_ISR_IRR_TO_VAPIC)) {
+        start = offsetof(VAPICState, isr);
+        length = offsetof(VAPICState, enabled) - offsetof(VAPICState, isr);
+
+        if (sync_type & SYNC_TO_VAPIC) {
+            assert(qemu_cpu_is_self(CPU(s->cpu)));
+
+            vapic_state.tpr = s->tpr;
+            vapic_state.enabled = 1;
+            start = 0;
+            length = sizeof(VAPICState);
+        }
+
+        vector = get_highest_priority_int(s->isr);
+        if (vector < 0) {
+            vector = 0;
+        }
+        vapic_state.isr = vector & 0xf0;
+
+        vapic_state.zero = 0;
+
+        vector = get_highest_priority_int(s->irr);
+        if (vector < 0) {
+            vector = 0;
+        }
+        vapic_state.irr = vector & 0xff;
+
+        cpu_physical_memory_write_rom(s->vapic_paddr + start,
+                                      ((void *)&vapic_state) + start, length);
+    }
+}
+
+static void apic_vapic_base_update(APICCommonState *s)
+{
+    apic_sync_vapic(s, SYNC_TO_VAPIC);
+}
+
+static void apic_local_deliver(APICCommonState *s, int vector)
+{
+    uint32_t lvt = s->lvt[vector];
+    int trigger_mode;
+
+    trace_apic_local_deliver(vector, (lvt >> 8) & 7);
+
+    if (lvt & APIC_LVT_MASKED)
+        return;
+
+    switch ((lvt >> 8) & 7) {
+    case APIC_DM_SMI:
+        cpu_interrupt(CPU(s->cpu), CPU_INTERRUPT_SMI);
+        break;
+
+    case APIC_DM_NMI:
+        cpu_interrupt(CPU(s->cpu), CPU_INTERRUPT_NMI);
+        break;
+
+    case APIC_DM_EXTINT:
+        cpu_interrupt(CPU(s->cpu), CPU_INTERRUPT_HARD);
+        break;
+
+    case APIC_DM_FIXED:
+        trigger_mode = APIC_TRIGGER_EDGE;
+        if ((vector == APIC_LVT_LINT0 || vector == APIC_LVT_LINT1) &&
+            (lvt & APIC_LVT_LEVEL_TRIGGER))
+            trigger_mode = APIC_TRIGGER_LEVEL;
+        apic_set_irq(s, lvt & 0xff, trigger_mode);
+    }
+}
+
+void apic_deliver_pic_intr(DeviceState *d, int level)
+{
+    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
+
+    if (level) {
+        apic_local_deliver(s, APIC_LVT_LINT0);
+    } else {
+        uint32_t lvt = s->lvt[APIC_LVT_LINT0];
+
+        switch ((lvt >> 8) & 7) {
+        case APIC_DM_FIXED:
+            if (!(lvt & APIC_LVT_LEVEL_TRIGGER))
+                break;
+            reset_bit(s->irr, lvt & 0xff);
+            /* fall through */
+        case APIC_DM_EXTINT:
+            cpu_reset_interrupt(CPU(s->cpu), CPU_INTERRUPT_HARD);
+            break;
+        }
+    }
+}
+
+static void apic_external_nmi(APICCommonState *s)
+{
+    apic_local_deliver(s, APIC_LVT_LINT1);
+}
+
+#define foreach_apic(apic, deliver_bitmask, code) \
+{\
+    int __i, __j, __mask;\
+    for(__i = 0; __i < MAX_APIC_WORDS; __i++) {\
+        __mask = deliver_bitmask[__i];\
+        if (__mask) {\
+            for(__j = 0; __j < 32; __j++) {\
+                if (__mask & (1 << __j)) {\
+                    apic = local_apics[__i * 32 + __j];\
+                    if (apic) {\
+                        code;\
+                    }\
+                }\
+            }\
+        }\
+    }\
+}
+
+static void apic_bus_deliver(const uint32_t *deliver_bitmask,
+                             uint8_t delivery_mode, uint8_t vector_num,
+                             uint8_t trigger_mode)
+{
+    APICCommonState *apic_iter;
+
+    switch (delivery_mode) {
+        case APIC_DM_LOWPRI:
+            /* XXX: search for focus processor, arbitration */
+            {
+                int i, d;
+                d = -1;
+                for(i = 0; i < MAX_APIC_WORDS; i++) {
+                    if (deliver_bitmask[i]) {
+                        d = i * 32 + ffs_bit(deliver_bitmask[i]);
+                        break;
+                    }
+                }
+                if (d >= 0) {
+                    apic_iter = local_apics[d];
+                    if (apic_iter) {
+                        apic_set_irq(apic_iter, vector_num, trigger_mode);
+                    }
+                }
+            }
+            return;
+
+        case APIC_DM_FIXED:
+            break;
+
+        case APIC_DM_SMI:
+            foreach_apic(apic_iter, deliver_bitmask,
+                cpu_interrupt(CPU(apic_iter->cpu), CPU_INTERRUPT_SMI)
+            );
+            return;
+
+        case APIC_DM_NMI:
+            foreach_apic(apic_iter, deliver_bitmask,
+                cpu_interrupt(CPU(apic_iter->cpu), CPU_INTERRUPT_NMI)
+            );
+            return;
+
+        case APIC_DM_INIT:
+            /* normal INIT IPI sent to processors */
+            foreach_apic(apic_iter, deliver_bitmask,
+                         cpu_interrupt(CPU(apic_iter->cpu),
+                                       CPU_INTERRUPT_INIT)
+            );
+            return;
+
+        case APIC_DM_EXTINT:
+            /* handled in I/O APIC code */
+            break;
+
+        default:
+            return;
+    }
+
+    foreach_apic(apic_iter, deliver_bitmask,
+                 apic_set_irq(apic_iter, vector_num, trigger_mode) );
+}
+
+void apic_deliver_irq(uint8_t dest, uint8_t dest_mode, uint8_t delivery_mode,
+                      uint8_t vector_num, uint8_t trigger_mode)
+{
+    uint32_t deliver_bitmask[MAX_APIC_WORDS];
+
+    trace_apic_deliver_irq(dest, dest_mode, delivery_mode, vector_num,
+                           trigger_mode);
+
+    apic_get_delivery_bitmask(deliver_bitmask, dest, dest_mode);
+    apic_bus_deliver(deliver_bitmask, delivery_mode, vector_num, trigger_mode);
+}
+
+static void apic_set_base(APICCommonState *s, uint64_t val)
+{
+    s->apicbase = (val & 0xfffff000) |
+        (s->apicbase & (MSR_IA32_APICBASE_BSP | MSR_IA32_APICBASE_ENABLE));
+    /* if disabled, cannot be enabled again */
+    if (!(val & MSR_IA32_APICBASE_ENABLE)) {
+        s->apicbase &= ~MSR_IA32_APICBASE_ENABLE;
+        cpu_clear_apic_feature(&s->cpu->env);
+        s->spurious_vec &= ~APIC_SV_ENABLE;
+    }
+}
+
+static void apic_set_tpr(APICCommonState *s, uint8_t val)
+{
+    /* Updates from cr8 are ignored while the VAPIC is active */
+    if (!s->vapic_paddr) {
+        s->tpr = val << 4;
+        apic_update_irq(s);
+    }
+}
+
+static uint8_t apic_get_tpr(APICCommonState *s)
+{
+    apic_sync_vapic(s, SYNC_FROM_VAPIC);
+    return s->tpr >> 4;
+}
+
+static int apic_get_ppr(APICCommonState *s)
+{
+    int tpr, isrv, ppr;
+
+    tpr = (s->tpr >> 4);
+    isrv = get_highest_priority_int(s->isr);
+    if (isrv < 0)
+        isrv = 0;
+    isrv >>= 4;
+    if (tpr >= isrv)
+        ppr = s->tpr;
+    else
+        ppr = isrv << 4;
+    return ppr;
+}
+
+static int apic_get_arb_pri(APICCommonState *s)
+{
+    /* XXX: arbitration */
+    return 0;
+}
+
+
+/*
+ * <0 - low prio interrupt,
+ * 0  - no interrupt,
+ * >0 - interrupt number
+ */
+static int apic_irq_pending(APICCommonState *s)
+{
+    int irrv, ppr;
+    irrv = get_highest_priority_int(s->irr);
+    if (irrv < 0) {
+        return 0;
+    }
+    ppr = apic_get_ppr(s);
+    if (ppr && (irrv & 0xf0) <= (ppr & 0xf0)) {
+        return -1;
+    }
+
+    return irrv;
+}
+
+/* signal the CPU if an irq is pending */
+static void apic_update_irq(APICCommonState *s)
+{
+    CPUState *cpu;
+
+    if (!(s->spurious_vec & APIC_SV_ENABLE)) {
+        return;
+    }
+    cpu = CPU(s->cpu);
+    if (!qemu_cpu_is_self(cpu)) {
+        cpu_interrupt(cpu, CPU_INTERRUPT_POLL);
+    } else if (apic_irq_pending(s) > 0) {
+        cpu_interrupt(cpu, CPU_INTERRUPT_HARD);
+    }
+}
+
+void apic_poll_irq(DeviceState *d)
+{
+    APICCommonState *s = APIC_COMMON(d);
+
+    apic_sync_vapic(s, SYNC_FROM_VAPIC);
+    apic_update_irq(s);
+}
+
+static void apic_set_irq(APICCommonState *s, int vector_num, int trigger_mode)
+{
+    apic_report_irq_delivered(!get_bit(s->irr, vector_num));
+
+    set_bit(s->irr, vector_num);
+    if (trigger_mode)
+        set_bit(s->tmr, vector_num);
+    else
+        reset_bit(s->tmr, vector_num);
+    if (s->vapic_paddr) {
+        apic_sync_vapic(s, SYNC_ISR_IRR_TO_VAPIC);
+        /*
+         * The vcpu thread needs to see the new IRR before we pull its current
+         * TPR value. That way, if we miss a lowering of the TRP, the guest
+         * has the chance to notice the new IRR and poll for IRQs on its own.
+         */
+        smp_wmb();
+        apic_sync_vapic(s, SYNC_FROM_VAPIC);
+    }
+    apic_update_irq(s);
+}
+
+static void apic_eoi(APICCommonState *s)
+{
+    int isrv;
+    isrv = get_highest_priority_int(s->isr);
+    if (isrv < 0)
+        return;
+    reset_bit(s->isr, isrv);
+    if (!(s->spurious_vec & APIC_SV_DIRECTED_IO) && get_bit(s->tmr, isrv)) {
+        ioapic_eoi_broadcast(isrv);
+    }
+    apic_sync_vapic(s, SYNC_FROM_VAPIC | SYNC_TO_VAPIC);
+    apic_update_irq(s);
+}
+
+static int apic_find_dest(uint8_t dest)
+{
+    APICCommonState *apic = local_apics[dest];
+    int i;
+
+    if (apic && apic->id == dest)
+        return dest;  /* shortcut in case apic->id == apic->idx */
+
+    for (i = 0; i < MAX_APICS; i++) {
+        apic = local_apics[i];
+       if (apic && apic->id == dest)
+            return i;
+        if (!apic)
+            break;
+    }
+
+    return -1;
+}
+
+static void apic_get_delivery_bitmask(uint32_t *deliver_bitmask,
+                                      uint8_t dest, uint8_t dest_mode)
+{
+    APICCommonState *apic_iter;
+    int i;
+
+    if (dest_mode == 0) {
+        if (dest == 0xff) {
+            memset(deliver_bitmask, 0xff, MAX_APIC_WORDS * sizeof(uint32_t));
+        } else {
+            int idx = apic_find_dest(dest);
+            memset(deliver_bitmask, 0x00, MAX_APIC_WORDS * sizeof(uint32_t));
+            if (idx >= 0)
+                set_bit(deliver_bitmask, idx);
+        }
+    } else {
+        /* XXX: cluster mode */
+        memset(deliver_bitmask, 0x00, MAX_APIC_WORDS * sizeof(uint32_t));
+        for(i = 0; i < MAX_APICS; i++) {
+            apic_iter = local_apics[i];
+            if (apic_iter) {
+                if (apic_iter->dest_mode == 0xf) {
+                    if (dest & apic_iter->log_dest)
+                        set_bit(deliver_bitmask, i);
+                } else if (apic_iter->dest_mode == 0x0) {
+                    if ((dest & 0xf0) == (apic_iter->log_dest & 0xf0) &&
+                        (dest & apic_iter->log_dest & 0x0f)) {
+                        set_bit(deliver_bitmask, i);
+                    }
+                }
+            } else {
+                break;
+            }
+        }
+    }
+}
+
+static void apic_startup(APICCommonState *s, int vector_num)
+{
+    s->sipi_vector = vector_num;
+    cpu_interrupt(CPU(s->cpu), CPU_INTERRUPT_SIPI);
+}
+
+void apic_sipi(DeviceState *d)
+{
+    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
+
+    cpu_reset_interrupt(CPU(s->cpu), CPU_INTERRUPT_SIPI);
+
+    if (!s->wait_for_sipi)
+        return;
+    cpu_x86_load_seg_cache_sipi(s->cpu, s->sipi_vector);
+    s->wait_for_sipi = 0;
+}
+
+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)
+{
+    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
+    uint32_t deliver_bitmask[MAX_APIC_WORDS];
+    int dest_shorthand = (s->icr[0] >> 18) & 3;
+    APICCommonState *apic_iter;
+
+    switch (dest_shorthand) {
+    case 0:
+        apic_get_delivery_bitmask(deliver_bitmask, dest, dest_mode);
+        break;
+    case 1:
+        memset(deliver_bitmask, 0x00, sizeof(deliver_bitmask));
+        set_bit(deliver_bitmask, s->idx);
+        break;
+    case 2:
+        memset(deliver_bitmask, 0xff, sizeof(deliver_bitmask));
+        break;
+    case 3:
+        memset(deliver_bitmask, 0xff, sizeof(deliver_bitmask));
+        reset_bit(deliver_bitmask, s->idx);
+        break;
+    }
+
+    switch (delivery_mode) {
+        case APIC_DM_INIT:
+            {
+                int trig_mode = (s->icr[0] >> 15) & 1;
+                int level = (s->icr[0] >> 14) & 1;
+                if (level == 0 && trig_mode == 1) {
+                    foreach_apic(apic_iter, deliver_bitmask,
+                                 apic_iter->arb_id = apic_iter->id );
+                    return;
+                }
+            }
+            break;
+
+        case APIC_DM_SIPI:
+            foreach_apic(apic_iter, deliver_bitmask,
+                         apic_startup(apic_iter, vector_num) );
+            return;
+    }
+
+    apic_bus_deliver(deliver_bitmask, delivery_mode, vector_num, trigger_mode);
+}
+
+static bool apic_check_pic(APICCommonState *s)
+{
+    if (!apic_accept_pic_intr(&s->busdev.qdev) || !pic_get_output(isa_pic)) {
+        return false;
+    }
+    apic_deliver_pic_intr(&s->busdev.qdev, 1);
+    return true;
+}
+
+int apic_get_interrupt(DeviceState *d)
+{
+    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
+    int intno;
+
+    /* if the APIC is installed or enabled, we let the 8259 handle the
+       IRQs */
+    if (!s)
+        return -1;
+    if (!(s->spurious_vec & APIC_SV_ENABLE))
+        return -1;
+
+    apic_sync_vapic(s, SYNC_FROM_VAPIC);
+    intno = apic_irq_pending(s);
+
+    if (intno == 0) {
+        apic_sync_vapic(s, SYNC_TO_VAPIC);
+        return -1;
+    } else if (intno < 0) {
+        apic_sync_vapic(s, SYNC_TO_VAPIC);
+        return s->spurious_vec & 0xff;
+    }
+    reset_bit(s->irr, intno);
+    set_bit(s->isr, intno);
+    apic_sync_vapic(s, SYNC_TO_VAPIC);
+
+    /* re-inject if there is still a pending PIC interrupt */
+    apic_check_pic(s);
+
+    apic_update_irq(s);
+
+    return intno;
+}
+
+int apic_accept_pic_intr(DeviceState *d)
+{
+    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
+    uint32_t lvt0;
+
+    if (!s)
+        return -1;
+
+    lvt0 = s->lvt[APIC_LVT_LINT0];
+
+    if ((s->apicbase & MSR_IA32_APICBASE_ENABLE) == 0 ||
+        (lvt0 & APIC_LVT_MASKED) == 0)
+        return 1;
+
+    return 0;
+}
+
+static uint32_t apic_get_current_count(APICCommonState *s)
+{
+    int64_t d;
+    uint32_t val;
+    d = (qemu_get_clock_ns(vm_clock) - s->initial_count_load_time) >>
+        s->count_shift;
+    if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) {
+        /* periodic */
+        val = s->initial_count - (d % ((uint64_t)s->initial_count + 1));
+    } else {
+        if (d >= s->initial_count)
+            val = 0;
+        else
+            val = s->initial_count - d;
+    }
+    return val;
+}
+
+static void apic_timer_update(APICCommonState *s, int64_t current_time)
+{
+    if (apic_next_timer(s, current_time)) {
+        qemu_mod_timer(s->timer, s->next_time);
+    } else {
+        qemu_del_timer(s->timer);
+    }
+}
+
+static void apic_timer(void *opaque)
+{
+    APICCommonState *s = opaque;
+
+    apic_local_deliver(s, APIC_LVT_TIMER);
+    apic_timer_update(s, s->next_time);
+}
+
+static uint32_t apic_mem_readb(void *opaque, hwaddr addr)
+{
+    return 0;
+}
+
+static uint32_t apic_mem_readw(void *opaque, hwaddr addr)
+{
+    return 0;
+}
+
+static void apic_mem_writeb(void *opaque, hwaddr addr, uint32_t val)
+{
+}
+
+static void apic_mem_writew(void *opaque, hwaddr addr, uint32_t val)
+{
+}
+
+static uint32_t apic_mem_readl(void *opaque, hwaddr addr)
+{
+    DeviceState *d;
+    APICCommonState *s;
+    uint32_t val;
+    int index;
+
+    d = cpu_get_current_apic();
+    if (!d) {
+        return 0;
+    }
+    s = DO_UPCAST(APICCommonState, busdev.qdev, d);
+
+    index = (addr >> 4) & 0xff;
+    switch(index) {
+    case 0x02: /* id */
+        val = s->id << 24;
+        break;
+    case 0x03: /* version */
+        val = 0x11 | ((APIC_LVT_NB - 1) << 16); /* version 0x11 */
+        break;
+    case 0x08:
+        apic_sync_vapic(s, SYNC_FROM_VAPIC);
+        if (apic_report_tpr_access) {
+            cpu_report_tpr_access(&s->cpu->env, TPR_ACCESS_READ);
+        }
+        val = s->tpr;
+        break;
+    case 0x09:
+        val = apic_get_arb_pri(s);
+        break;
+    case 0x0a:
+        /* ppr */
+        val = apic_get_ppr(s);
+        break;
+    case 0x0b:
+        val = 0;
+        break;
+    case 0x0d:
+        val = s->log_dest << 24;
+        break;
+    case 0x0e:
+        val = s->dest_mode << 28;
+        break;
+    case 0x0f:
+        val = s->spurious_vec;
+        break;
+    case 0x10 ... 0x17:
+        val = s->isr[index & 7];
+        break;
+    case 0x18 ... 0x1f:
+        val = s->tmr[index & 7];
+        break;
+    case 0x20 ... 0x27:
+        val = s->irr[index & 7];
+        break;
+    case 0x28:
+        val = s->esr;
+        break;
+    case 0x30:
+    case 0x31:
+        val = s->icr[index & 1];
+        break;
+    case 0x32 ... 0x37:
+        val = s->lvt[index - 0x32];
+        break;
+    case 0x38:
+        val = s->initial_count;
+        break;
+    case 0x39:
+        val = apic_get_current_count(s);
+        break;
+    case 0x3e:
+        val = s->divide_conf;
+        break;
+    default:
+        s->esr |= ESR_ILLEGAL_ADDRESS;
+        val = 0;
+        break;
+    }
+    trace_apic_mem_readl(addr, val);
+    return val;
+}
+
+static void apic_send_msi(hwaddr addr, uint32_t data)
+{
+    uint8_t dest = (addr & MSI_ADDR_DEST_ID_MASK) >> MSI_ADDR_DEST_ID_SHIFT;
+    uint8_t vector = (data & MSI_DATA_VECTOR_MASK) >> MSI_DATA_VECTOR_SHIFT;
+    uint8_t dest_mode = (addr >> MSI_ADDR_DEST_MODE_SHIFT) & 0x1;
+    uint8_t trigger_mode = (data >> MSI_DATA_TRIGGER_SHIFT) & 0x1;
+    uint8_t delivery = (data >> MSI_DATA_DELIVERY_MODE_SHIFT) & 0x7;
+    /* XXX: Ignore redirection hint. */
+    apic_deliver_irq(dest, dest_mode, delivery, vector, trigger_mode);
+}
+
+static void apic_mem_writel(void *opaque, hwaddr addr, uint32_t val)
+{
+    DeviceState *d;
+    APICCommonState *s;
+    int index = (addr >> 4) & 0xff;
+    if (addr > 0xfff || !index) {
+        /* MSI and MMIO APIC are at the same memory location,
+         * but actually not on the global bus: MSI is on PCI bus
+         * APIC is connected directly to the CPU.
+         * Mapping them on the global bus happens to work because
+         * MSI registers are reserved in APIC MMIO and vice versa. */
+        apic_send_msi(addr, val);
+        return;
+    }
+
+    d = cpu_get_current_apic();
+    if (!d) {
+        return;
+    }
+    s = DO_UPCAST(APICCommonState, busdev.qdev, d);
+
+    trace_apic_mem_writel(addr, val);
+
+    switch(index) {
+    case 0x02:
+        s->id = (val >> 24);
+        break;
+    case 0x03:
+        break;
+    case 0x08:
+        if (apic_report_tpr_access) {
+            cpu_report_tpr_access(&s->cpu->env, TPR_ACCESS_WRITE);
+        }
+        s->tpr = val;
+        apic_sync_vapic(s, SYNC_TO_VAPIC);
+        apic_update_irq(s);
+        break;
+    case 0x09:
+    case 0x0a:
+        break;
+    case 0x0b: /* EOI */
+        apic_eoi(s);
+        break;
+    case 0x0d:
+        s->log_dest = val >> 24;
+        break;
+    case 0x0e:
+        s->dest_mode = val >> 28;
+        break;
+    case 0x0f:
+        s->spurious_vec = val & 0x1ff;
+        apic_update_irq(s);
+        break;
+    case 0x10 ... 0x17:
+    case 0x18 ... 0x1f:
+    case 0x20 ... 0x27:
+    case 0x28:
+        break;
+    case 0x30:
+        s->icr[0] = val;
+        apic_deliver(d, (s->icr[1] >> 24) & 0xff, (s->icr[0] >> 11) & 1,
+                     (s->icr[0] >> 8) & 7, (s->icr[0] & 0xff),
+                     (s->icr[0] >> 15) & 1);
+        break;
+    case 0x31:
+        s->icr[1] = val;
+        break;
+    case 0x32 ... 0x37:
+        {
+            int n = index - 0x32;
+            s->lvt[n] = val;
+            if (n == APIC_LVT_TIMER) {
+                apic_timer_update(s, qemu_get_clock_ns(vm_clock));
+            } else if (n == APIC_LVT_LINT0 && apic_check_pic(s)) {
+                apic_update_irq(s);
+            }
+        }
+        break;
+    case 0x38:
+        s->initial_count = val;
+        s->initial_count_load_time = qemu_get_clock_ns(vm_clock);
+        apic_timer_update(s, s->initial_count_load_time);
+        break;
+    case 0x39:
+        break;
+    case 0x3e:
+        {
+            int v;
+            s->divide_conf = val & 0xb;
+            v = (s->divide_conf & 3) | ((s->divide_conf >> 1) & 4);
+            s->count_shift = (v + 1) & 7;
+        }
+        break;
+    default:
+        s->esr |= ESR_ILLEGAL_ADDRESS;
+        break;
+    }
+}
+
+static void apic_pre_save(APICCommonState *s)
+{
+    apic_sync_vapic(s, SYNC_FROM_VAPIC);
+}
+
+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, },
+        .write = { apic_mem_writeb, apic_mem_writew, apic_mem_writel, },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void apic_init(APICCommonState *s)
+{
+    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);
+    local_apics[s->idx] = s;
+
+    msi_supported = true;
+}
+
+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->get_tpr = apic_get_tpr;
+    k->vapic_base_update = apic_vapic_base_update;
+    k->external_nmi = apic_external_nmi;
+    k->pre_save = apic_pre_save;
+    k->post_load = apic_post_load;
+}
+
+static const TypeInfo apic_info = {
+    .name          = "apic",
+    .instance_size = sizeof(APICCommonState),
+    .parent        = TYPE_APIC_COMMON,
+    .class_init    = apic_class_init,
+};
+
+static void apic_register_types(void)
+{
+    type_register_static(&apic_info);
+}
+
+type_init(apic_register_types)
diff --git a/hw/intc/apic_common.c b/hw/intc/apic_common.c
new file mode 100644 (file)
index 0000000..e0ae07a
--- /dev/null
@@ -0,0 +1,402 @@
+/*
+ *  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 "hw/i386/apic.h"
+#include "hw/i386/apic_internal.h"
+#include "trace.h"
+#include "sysemu/kvm.h"
+
+static int apic_irq_delivered;
+bool apic_report_tpr_access;
+
+void cpu_set_apic_base(DeviceState *d, uint64_t val)
+{
+    trace_cpu_set_apic_base(val);
+
+    if (d) {
+        APICCommonState *s = APIC_COMMON(d);
+        APICCommonClass *info = APIC_COMMON_GET_CLASS(s);
+        info->set_base(s, val);
+    }
+}
+
+uint64_t cpu_get_apic_base(DeviceState *d)
+{
+    if (d) {
+        APICCommonState *s = APIC_COMMON(d);
+        trace_cpu_get_apic_base((uint64_t)s->apicbase);
+        return s->apicbase;
+    } else {
+        trace_cpu_get_apic_base(MSR_IA32_APICBASE_BSP);
+        return MSR_IA32_APICBASE_BSP;
+    }
+}
+
+void cpu_set_apic_tpr(DeviceState *d, uint8_t val)
+{
+    APICCommonState *s;
+    APICCommonClass *info;
+
+    if (!d) {
+        return;
+    }
+
+    s = APIC_COMMON(d);
+    info = APIC_COMMON_GET_CLASS(s);
+
+    info->set_tpr(s, val);
+}
+
+uint8_t cpu_get_apic_tpr(DeviceState *d)
+{
+    APICCommonState *s;
+    APICCommonClass *info;
+
+    if (!d) {
+        return 0;
+    }
+
+    s = APIC_COMMON(d);
+    info = APIC_COMMON_GET_CLASS(s);
+
+    return info->get_tpr(s);
+}
+
+void apic_enable_tpr_access_reporting(DeviceState *d, bool enable)
+{
+    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
+    APICCommonClass *info = APIC_COMMON_GET_CLASS(s);
+
+    apic_report_tpr_access = enable;
+    if (info->enable_tpr_reporting) {
+        info->enable_tpr_reporting(s, enable);
+    }
+}
+
+void apic_enable_vapic(DeviceState *d, hwaddr paddr)
+{
+    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
+    APICCommonClass *info = APIC_COMMON_GET_CLASS(s);
+
+    s->vapic_paddr = paddr;
+    info->vapic_base_update(s);
+}
+
+void apic_handle_tpr_access_report(DeviceState *d, target_ulong ip,
+                                   TPRAccess access)
+{
+    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
+
+    vapic_report_tpr_access(s->vapic, CPU(s->cpu), ip, access);
+}
+
+void apic_report_irq_delivered(int delivered)
+{
+    apic_irq_delivered += delivered;
+
+    trace_apic_report_irq_delivered(apic_irq_delivered);
+}
+
+void apic_reset_irq_delivered(void)
+{
+    trace_apic_reset_irq_delivered(apic_irq_delivered);
+
+    apic_irq_delivered = 0;
+}
+
+int apic_get_irq_delivered(void)
+{
+    trace_apic_get_irq_delivered(apic_irq_delivered);
+
+    return apic_irq_delivered;
+}
+
+void apic_deliver_nmi(DeviceState *d)
+{
+    APICCommonState *s = APIC_COMMON(d);
+    APICCommonClass *info = APIC_COMMON_GET_CLASS(s);
+
+    info->external_nmi(s);
+}
+
+bool apic_next_timer(APICCommonState *s, int64_t current_time)
+{
+    int64_t d;
+
+    /* We need to store the timer state separately to support APIC
+     * implementations that maintain a non-QEMU timer, e.g. inside the
+     * host kernel. This open-coded state allows us to migrate between
+     * both models. */
+    s->timer_expiry = -1;
+
+    if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_MASKED) {
+        return false;
+    }
+
+    d = (current_time - s->initial_count_load_time) >> s->count_shift;
+
+    if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) {
+        if (!s->initial_count) {
+            return false;
+        }
+        d = ((d / ((uint64_t)s->initial_count + 1)) + 1) *
+            ((uint64_t)s->initial_count + 1);
+    } else {
+        if (d >= s->initial_count) {
+            return false;
+        }
+        d = (uint64_t)s->initial_count + 1;
+    }
+    s->next_time = s->initial_count_load_time + (d << s->count_shift);
+    s->timer_expiry = s->next_time;
+    return true;
+}
+
+void apic_init_reset(DeviceState *d)
+{
+    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
+    int i;
+
+    if (!s) {
+        return;
+    }
+    s->tpr = 0;
+    s->spurious_vec = 0xff;
+    s->log_dest = 0;
+    s->dest_mode = 0xf;
+    memset(s->isr, 0, sizeof(s->isr));
+    memset(s->tmr, 0, sizeof(s->tmr));
+    memset(s->irr, 0, sizeof(s->irr));
+    for (i = 0; i < APIC_LVT_NB; i++) {
+        s->lvt[i] = APIC_LVT_MASKED;
+    }
+    s->esr = 0;
+    memset(s->icr, 0, sizeof(s->icr));
+    s->divide_conf = 0;
+    s->count_shift = 0;
+    s->initial_count = 0;
+    s->initial_count_load_time = 0;
+    s->next_time = 0;
+    s->wait_for_sipi = 1;
+
+    if (s->timer) {
+        qemu_del_timer(s->timer);
+    }
+    s->timer_expiry = -1;
+}
+
+void apic_designate_bsp(DeviceState *d)
+{
+    if (d == NULL) {
+        return;
+    }
+
+    APICCommonState *s = APIC_COMMON(d);
+    s->apicbase |= MSR_IA32_APICBASE_BSP;
+}
+
+static void apic_reset_common(DeviceState *d)
+{
+    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
+    APICCommonClass *info = APIC_COMMON_GET_CLASS(s);
+    bool bsp;
+
+    bsp = cpu_is_bsp(s->cpu);
+    s->apicbase = APIC_DEFAULT_ADDRESS |
+        (bsp ? MSR_IA32_APICBASE_BSP : 0) | MSR_IA32_APICBASE_ENABLE;
+
+    s->vapic_paddr = 0;
+    info->vapic_base_update(s);
+
+    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;
+    APICCommonClass *info = APIC_COMMON_GET_CLASS(s);
+    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) {
+        s->timer_expiry = qemu_get_be64(f);
+    }
+
+    if (info->post_load) {
+        info->post_load(s);
+    }
+    return 0;
+}
+
+static int apic_init_common(SysBusDevice *dev)
+{
+    APICCommonState *s = APIC_COMMON(dev);
+    APICCommonClass *info;
+    static DeviceState *vapic;
+    static int apic_no;
+
+    if (apic_no >= MAX_APICS) {
+        return -1;
+    }
+    s->idx = apic_no++;
+
+    info = APIC_COMMON_GET_CLASS(s);
+    info->init(s);
+
+    sysbus_init_mmio(dev, &s->io_memory);
+
+    /* Note: We need at least 1M to map the VAPIC option ROM */
+    if (!vapic && s->vapic_control & VAPIC_ENABLE_MASK &&
+        ram_size >= 1024 * 1024) {
+        vapic = sysbus_create_simple("kvmvapic", -1, NULL);
+    }
+    s->vapic = vapic;
+    if (apic_report_tpr_access && info->enable_tpr_reporting) {
+        info->enable_tpr_reporting(s, true);
+    }
+
+    return 0;
+}
+
+static void apic_dispatch_pre_save(void *opaque)
+{
+    APICCommonState *s = APIC_COMMON(opaque);
+    APICCommonClass *info = APIC_COMMON_GET_CLASS(s);
+
+    if (info->pre_save) {
+        info->pre_save(s);
+    }
+}
+
+static int apic_dispatch_post_load(void *opaque, int version_id)
+{
+    APICCommonState *s = APIC_COMMON(opaque);
+    APICCommonClass *info = APIC_COMMON_GET_CLASS(s);
+
+    if (info->post_load) {
+        info->post_load(s);
+    }
+    return 0;
+}
+
+static const VMStateDescription vmstate_apic_common = {
+    .name = "apic",
+    .version_id = 3,
+    .minimum_version_id = 3,
+    .minimum_version_id_old = 1,
+    .load_state_old = apic_load_old,
+    .pre_save = apic_dispatch_pre_save,
+    .post_load = apic_dispatch_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(apicbase, APICCommonState),
+        VMSTATE_UINT8(id, APICCommonState),
+        VMSTATE_UINT8(arb_id, APICCommonState),
+        VMSTATE_UINT8(tpr, APICCommonState),
+        VMSTATE_UINT32(spurious_vec, APICCommonState),
+        VMSTATE_UINT8(log_dest, APICCommonState),
+        VMSTATE_UINT8(dest_mode, APICCommonState),
+        VMSTATE_UINT32_ARRAY(isr, APICCommonState, 8),
+        VMSTATE_UINT32_ARRAY(tmr, APICCommonState, 8),
+        VMSTATE_UINT32_ARRAY(irr, APICCommonState, 8),
+        VMSTATE_UINT32_ARRAY(lvt, APICCommonState, APIC_LVT_NB),
+        VMSTATE_UINT32(esr, APICCommonState),
+        VMSTATE_UINT32_ARRAY(icr, APICCommonState, 2),
+        VMSTATE_UINT32(divide_conf, APICCommonState),
+        VMSTATE_INT32(count_shift, APICCommonState),
+        VMSTATE_UINT32(initial_count, APICCommonState),
+        VMSTATE_INT64(initial_count_load_time, APICCommonState),
+        VMSTATE_INT64(next_time, APICCommonState),
+        VMSTATE_INT64(timer_expiry,
+                      APICCommonState), /* open-coded timer state */
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static Property apic_properties_common[] = {
+    DEFINE_PROP_UINT8("id", APICCommonState, id, -1),
+    DEFINE_PROP_BIT("vapic", APICCommonState, vapic_control, VAPIC_ENABLE_BIT,
+                    true),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void apic_common_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sc = SYS_BUS_DEVICE_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->vmsd = &vmstate_apic_common;
+    dc->reset = apic_reset_common;
+    dc->no_user = 1;
+    dc->props = apic_properties_common;
+    sc->init = apic_init_common;
+}
+
+static const TypeInfo apic_common_type = {
+    .name = TYPE_APIC_COMMON,
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(APICCommonState),
+    .class_size = sizeof(APICCommonClass),
+    .class_init = apic_common_class_init,
+    .abstract = true,
+};
+
+static void register_types(void)
+{
+    type_register_static(&apic_common_type);
+}
+
+type_init(register_types)
diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c
new file mode 100644 (file)
index 0000000..bae6572
--- /dev/null
@@ -0,0 +1,723 @@
+/*
+ * ARM Generic/Distributed Interrupt Controller
+ *
+ * Copyright (c) 2006-2007 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the GPL.
+ */
+
+/* This file contains implementation code for the RealView EB interrupt
+ * controller, MPCore distributed interrupt controller and ARMv7-M
+ * Nested Vectored Interrupt Controller.
+ * It is compiled in two ways:
+ *  (1) as a standalone file to produce a sysbus device which is a GIC
+ *  that can be used on the realview board and as one of the builtin
+ *  private peripherals for the ARM MP CPUs (11MPCore, A9, etc)
+ *  (2) by being directly #included into armv7m_nvic.c to produce the
+ *  armv7m_nvic device.
+ */
+
+#include "hw/sysbus.h"
+#include "gic_internal.h"
+
+//#define DEBUG_GIC
+
+#ifdef DEBUG_GIC
+#define DPRINTF(fmt, ...) \
+do { fprintf(stderr, "arm_gic: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while(0)
+#endif
+
+static const uint8_t gic_id[] = {
+    0x90, 0x13, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1
+};
+
+#define NUM_CPU(s) ((s)->num_cpu)
+
+static inline int gic_get_current_cpu(GICState *s)
+{
+    if (s->num_cpu > 1) {
+        CPUState *cpu = ENV_GET_CPU(cpu_single_env);
+        return cpu->cpu_index;
+    }
+    return 0;
+}
+
+/* TODO: Many places that call this routine could be optimized.  */
+/* Update interrupt status after enabled or pending bits have been changed.  */
+void gic_update(GICState *s)
+{
+    int best_irq;
+    int best_prio;
+    int irq;
+    int level;
+    int cpu;
+    int cm;
+
+    for (cpu = 0; cpu < NUM_CPU(s); cpu++) {
+        cm = 1 << cpu;
+        s->current_pending[cpu] = 1023;
+        if (!s->enabled || !s->cpu_enabled[cpu]) {
+            qemu_irq_lower(s->parent_irq[cpu]);
+            return;
+        }
+        best_prio = 0x100;
+        best_irq = 1023;
+        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);
+                    best_irq = irq;
+                }
+            }
+        }
+        level = 0;
+        if (best_prio < s->priority_mask[cpu]) {
+            s->current_pending[cpu] = best_irq;
+            if (best_prio < s->running_priority[cpu]) {
+                DPRINTF("Raised pending IRQ %d (cpu %d)\n", best_irq, cpu);
+                level = 1;
+            }
+        }
+        qemu_set_irq(s->parent_irq[cpu], level);
+    }
+}
+
+void gic_set_pending_private(GICState *s, int cpu, int irq)
+{
+    int cm = 1 << cpu;
+
+    if (GIC_TEST_PENDING(irq, cm))
+        return;
+
+    DPRINTF("Set %d pending cpu %d\n", irq, cpu);
+    GIC_SET_PENDING(irq, cm);
+    gic_update(s);
+}
+
+/* Process a change in an external IRQ input.  */
+static void gic_set_irq(void *opaque, int irq, int level)
+{
+    /* Meaning of the 'irq' parameter:
+     *  [0..N-1] : external interrupts
+     *  [N..N+31] : PPI (internal) interrupts for CPU 0
+     *  [N+32..N+63] : PPI (internal interrupts for CPU 1
+     *  ...
+     */
+    GICState *s = (GICState *)opaque;
+    int cm, target;
+    if (irq < (s->num_irq - GIC_INTERNAL)) {
+        /* The first external input line is internal interrupt 32.  */
+        cm = ALL_CPU_MASK;
+        irq += GIC_INTERNAL;
+        target = GIC_TARGET(irq);
+    } else {
+        int cpu;
+        irq -= (s->num_irq - GIC_INTERNAL);
+        cpu = irq / GIC_INTERNAL;
+        irq %= GIC_INTERNAL;
+        cm = 1 << cpu;
+        target = cm;
+    }
+
+    if (level == GIC_TEST_LEVEL(irq, cm)) {
+        return;
+    }
+
+    if (level) {
+        GIC_SET_LEVEL(irq, cm);
+        if (GIC_TEST_TRIGGER(irq) || GIC_TEST_ENABLED(irq, cm)) {
+            DPRINTF("Set %d pending mask %x\n", irq, target);
+            GIC_SET_PENDING(irq, target);
+        }
+    } else {
+        GIC_CLEAR_LEVEL(irq, cm);
+    }
+    gic_update(s);
+}
+
+static void gic_set_running_irq(GICState *s, int cpu, int irq)
+{
+    s->running_irq[cpu] = irq;
+    if (irq == 1023) {
+        s->running_priority[cpu] = 0x100;
+    } else {
+        s->running_priority[cpu] = GIC_GET_PRIORITY(irq, cpu);
+    }
+    gic_update(s);
+}
+
+uint32_t gic_acknowledge_irq(GICState *s, int cpu)
+{
+    int new_irq;
+    int cm = 1 << cpu;
+    new_irq = s->current_pending[cpu];
+    if (new_irq == 1023
+            || GIC_GET_PRIORITY(new_irq, cpu) >= s->running_priority[cpu]) {
+        DPRINTF("ACK no pending IRQ\n");
+        return 1023;
+    }
+    s->last_active[new_irq][cpu] = s->running_irq[cpu];
+    /* Clear pending flags for both level and edge triggered interrupts.
+       Level triggered IRQs will be reasserted once they become inactive.  */
+    GIC_CLEAR_PENDING(new_irq, GIC_TEST_MODEL(new_irq) ? ALL_CPU_MASK : cm);
+    gic_set_running_irq(s, cpu, new_irq);
+    DPRINTF("ACK %d\n", new_irq);
+    return new_irq;
+}
+
+void gic_complete_irq(GICState *s, int cpu, int irq)
+{
+    int update = 0;
+    int cm = 1 << cpu;
+    DPRINTF("EOI %d\n", irq);
+    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.
+         * 2. If software writes the number of a non-existent interrupt
+         * this must be a subcase of "value written does not match the last
+         * valid interrupt value read from the Interrupt Acknowledge
+         * register" and so this is UNPREDICTABLE. We choose to ignore it.
+         */
+        return;
+    }
+    if (s->running_irq[cpu] == 1023)
+        return; /* No active IRQ.  */
+    /* Mark level triggered interrupts as pending if they are still
+       raised.  */
+    if (!GIC_TEST_TRIGGER(irq) && GIC_TEST_ENABLED(irq, cm)
+        && GIC_TEST_LEVEL(irq, cm) && (GIC_TARGET(irq) & cm) != 0) {
+        DPRINTF("Set %d pending mask %x\n", irq, cm);
+        GIC_SET_PENDING(irq, cm);
+        update = 1;
+    }
+    if (irq != s->running_irq[cpu]) {
+        /* Complete an IRQ that is not currently running.  */
+        int tmp = s->running_irq[cpu];
+        while (s->last_active[tmp][cpu] != 1023) {
+            if (s->last_active[tmp][cpu] == irq) {
+                s->last_active[tmp][cpu] = s->last_active[irq][cpu];
+                break;
+            }
+            tmp = s->last_active[tmp][cpu];
+        }
+        if (update) {
+            gic_update(s);
+        }
+    } else {
+        /* Complete the current running IRQ.  */
+        gic_set_running_irq(s, cpu, s->last_active[s->running_irq[cpu]][cpu]);
+    }
+}
+
+static uint32_t gic_dist_readb(void *opaque, hwaddr offset)
+{
+    GICState *s = (GICState *)opaque;
+    uint32_t res;
+    int irq;
+    int i;
+    int cpu;
+    int cm;
+    int mask;
+
+    cpu = gic_get_current_cpu(s);
+    cm = 1 << cpu;
+    if (offset < 0x100) {
+        if (offset == 0)
+            return s->enabled;
+        if (offset == 4)
+            return ((s->num_irq / 32) - 1) | ((NUM_CPU(s) - 1) << 5);
+        if (offset < 0x08)
+            return 0;
+        if (offset >= 0x80) {
+            /* Interrupt Security , RAZ/WI */
+            return 0;
+        }
+        goto bad_reg;
+    } else if (offset < 0x200) {
+        /* Interrupt Set/Clear Enable.  */
+        if (offset < 0x180)
+            irq = (offset - 0x100) * 8;
+        else
+            irq = (offset - 0x180) * 8;
+        irq += GIC_BASE_IRQ;
+        if (irq >= s->num_irq)
+            goto bad_reg;
+        res = 0;
+        for (i = 0; i < 8; i++) {
+            if (GIC_TEST_ENABLED(irq + i, cm)) {
+                res |= (1 << i);
+            }
+        }
+    } else if (offset < 0x300) {
+        /* Interrupt Set/Clear Pending.  */
+        if (offset < 0x280)
+            irq = (offset - 0x200) * 8;
+        else
+            irq = (offset - 0x280) * 8;
+        irq += GIC_BASE_IRQ;
+        if (irq >= s->num_irq)
+            goto bad_reg;
+        res = 0;
+        mask = (irq < GIC_INTERNAL) ?  cm : ALL_CPU_MASK;
+        for (i = 0; i < 8; i++) {
+            if (GIC_TEST_PENDING(irq + i, mask)) {
+                res |= (1 << i);
+            }
+        }
+    } else if (offset < 0x400) {
+        /* Interrupt Active.  */
+        irq = (offset - 0x300) * 8 + GIC_BASE_IRQ;
+        if (irq >= s->num_irq)
+            goto bad_reg;
+        res = 0;
+        mask = (irq < GIC_INTERNAL) ?  cm : ALL_CPU_MASK;
+        for (i = 0; i < 8; i++) {
+            if (GIC_TEST_ACTIVE(irq + i, mask)) {
+                res |= (1 << i);
+            }
+        }
+    } else if (offset < 0x800) {
+        /* Interrupt Priority.  */
+        irq = (offset - 0x400) + GIC_BASE_IRQ;
+        if (irq >= s->num_irq)
+            goto bad_reg;
+        res = GIC_GET_PRIORITY(irq, cpu);
+    } else if (offset < 0xc00) {
+        /* Interrupt CPU Target.  */
+        if (s->num_cpu == 1 && s->revision != REV_11MPCORE) {
+            /* For uniprocessor GICs these RAZ/WI */
+            res = 0;
+        } else {
+            irq = (offset - 0x800) + GIC_BASE_IRQ;
+            if (irq >= s->num_irq) {
+                goto bad_reg;
+            }
+            if (irq >= 29 && irq <= 31) {
+                res = cm;
+            } else {
+                res = GIC_TARGET(irq);
+            }
+        }
+    } else if (offset < 0xf00) {
+        /* Interrupt Configuration.  */
+        irq = (offset - 0xc00) * 2 + GIC_BASE_IRQ;
+        if (irq >= s->num_irq)
+            goto bad_reg;
+        res = 0;
+        for (i = 0; i < 4; i++) {
+            if (GIC_TEST_MODEL(irq + i))
+                res |= (1 << (i * 2));
+            if (GIC_TEST_TRIGGER(irq + i))
+                res |= (2 << (i * 2));
+        }
+    } else if (offset < 0xfe0) {
+        goto bad_reg;
+    } else /* offset >= 0xfe0 */ {
+        if (offset & 3) {
+            res = 0;
+        } else {
+            res = gic_id[(offset - 0xfe0) >> 2];
+        }
+    }
+    return res;
+bad_reg:
+    qemu_log_mask(LOG_GUEST_ERROR,
+                  "gic_dist_readb: Bad offset %x\n", (int)offset);
+    return 0;
+}
+
+static uint32_t gic_dist_readw(void *opaque, hwaddr offset)
+{
+    uint32_t val;
+    val = gic_dist_readb(opaque, offset);
+    val |= gic_dist_readb(opaque, offset + 1) << 8;
+    return val;
+}
+
+static uint32_t gic_dist_readl(void *opaque, hwaddr offset)
+{
+    uint32_t val;
+    val = gic_dist_readw(opaque, offset);
+    val |= gic_dist_readw(opaque, offset + 2) << 16;
+    return val;
+}
+
+static void gic_dist_writeb(void *opaque, hwaddr offset,
+                            uint32_t value)
+{
+    GICState *s = (GICState *)opaque;
+    int irq;
+    int i;
+    int cpu;
+
+    cpu = gic_get_current_cpu(s);
+    if (offset < 0x100) {
+        if (offset == 0) {
+            s->enabled = (value & 1);
+            DPRINTF("Distribution %sabled\n", s->enabled ? "En" : "Dis");
+        } else if (offset < 4) {
+            /* ignored.  */
+        } else if (offset >= 0x80) {
+            /* Interrupt Security Registers, RAZ/WI */
+        } else {
+            goto bad_reg;
+        }
+    } else if (offset < 0x180) {
+        /* Interrupt Set Enable.  */
+        irq = (offset - 0x100) * 8 + GIC_BASE_IRQ;
+        if (irq >= s->num_irq)
+            goto bad_reg;
+        if (irq < 16)
+          value = 0xff;
+        for (i = 0; i < 8; i++) {
+            if (value & (1 << i)) {
+                int mask =
+                    (irq < GIC_INTERNAL) ? (1 << cpu) : GIC_TARGET(irq + i);
+                int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK;
+
+                if (!GIC_TEST_ENABLED(irq + i, cm)) {
+                    DPRINTF("Enabled IRQ %d\n", irq + i);
+                }
+                GIC_SET_ENABLED(irq + i, cm);
+                /* If a raised level triggered IRQ enabled then mark
+                   is as pending.  */
+                if (GIC_TEST_LEVEL(irq + i, mask)
+                        && !GIC_TEST_TRIGGER(irq + i)) {
+                    DPRINTF("Set %d pending mask %x\n", irq + i, mask);
+                    GIC_SET_PENDING(irq + i, mask);
+                }
+            }
+        }
+    } else if (offset < 0x200) {
+        /* Interrupt Clear Enable.  */
+        irq = (offset - 0x180) * 8 + GIC_BASE_IRQ;
+        if (irq >= s->num_irq)
+            goto bad_reg;
+        if (irq < 16)
+          value = 0;
+        for (i = 0; i < 8; i++) {
+            if (value & (1 << i)) {
+                int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK;
+
+                if (GIC_TEST_ENABLED(irq + i, cm)) {
+                    DPRINTF("Disabled IRQ %d\n", irq + i);
+                }
+                GIC_CLEAR_ENABLED(irq + i, cm);
+            }
+        }
+    } else if (offset < 0x280) {
+        /* Interrupt Set Pending.  */
+        irq = (offset - 0x200) * 8 + GIC_BASE_IRQ;
+        if (irq >= s->num_irq)
+            goto bad_reg;
+        if (irq < 16)
+          irq = 0;
+
+        for (i = 0; i < 8; i++) {
+            if (value & (1 << i)) {
+                GIC_SET_PENDING(irq + i, GIC_TARGET(irq + i));
+            }
+        }
+    } else if (offset < 0x300) {
+        /* Interrupt Clear Pending.  */
+        irq = (offset - 0x280) * 8 + GIC_BASE_IRQ;
+        if (irq >= s->num_irq)
+            goto bad_reg;
+        for (i = 0; i < 8; i++) {
+            /* ??? This currently clears the pending bit for all CPUs, even
+               for per-CPU interrupts.  It's unclear whether this is the
+               corect behavior.  */
+            if (value & (1 << i)) {
+                GIC_CLEAR_PENDING(irq + i, ALL_CPU_MASK);
+            }
+        }
+    } else if (offset < 0x400) {
+        /* Interrupt Active.  */
+        goto bad_reg;
+    } else if (offset < 0x800) {
+        /* Interrupt Priority.  */
+        irq = (offset - 0x400) + GIC_BASE_IRQ;
+        if (irq >= s->num_irq)
+            goto bad_reg;
+        if (irq < GIC_INTERNAL) {
+            s->priority1[irq][cpu] = value;
+        } else {
+            s->priority2[irq - GIC_INTERNAL] = value;
+        }
+    } else if (offset < 0xc00) {
+        /* Interrupt CPU Target. RAZ/WI on uniprocessor GICs, with the
+         * annoying exception of the 11MPCore's GIC.
+         */
+        if (s->num_cpu != 1 || s->revision == REV_11MPCORE) {
+            irq = (offset - 0x800) + GIC_BASE_IRQ;
+            if (irq >= s->num_irq) {
+                goto bad_reg;
+            }
+            if (irq < 29) {
+                value = 0;
+            } else if (irq < GIC_INTERNAL) {
+                value = ALL_CPU_MASK;
+            }
+            s->irq_target[irq] = value & ALL_CPU_MASK;
+        }
+    } else if (offset < 0xf00) {
+        /* Interrupt Configuration.  */
+        irq = (offset - 0xc00) * 4 + GIC_BASE_IRQ;
+        if (irq >= s->num_irq)
+            goto bad_reg;
+        if (irq < GIC_INTERNAL)
+            value |= 0xaa;
+        for (i = 0; i < 4; i++) {
+            if (value & (1 << (i * 2))) {
+                GIC_SET_MODEL(irq + i);
+            } else {
+                GIC_CLEAR_MODEL(irq + i);
+            }
+            if (value & (2 << (i * 2))) {
+                GIC_SET_TRIGGER(irq + i);
+            } else {
+                GIC_CLEAR_TRIGGER(irq + i);
+            }
+        }
+    } else {
+        /* 0xf00 is only handled for 32-bit writes.  */
+        goto bad_reg;
+    }
+    gic_update(s);
+    return;
+bad_reg:
+    qemu_log_mask(LOG_GUEST_ERROR,
+                  "gic_dist_writeb: Bad offset %x\n", (int)offset);
+}
+
+static void gic_dist_writew(void *opaque, hwaddr offset,
+                            uint32_t value)
+{
+    gic_dist_writeb(opaque, offset, value & 0xff);
+    gic_dist_writeb(opaque, offset + 1, value >> 8);
+}
+
+static void gic_dist_writel(void *opaque, hwaddr offset,
+                            uint32_t value)
+{
+    GICState *s = (GICState *)opaque;
+    if (offset == 0xf00) {
+        int cpu;
+        int irq;
+        int mask;
+
+        cpu = gic_get_current_cpu(s);
+        irq = value & 0x3ff;
+        switch ((value >> 24) & 3) {
+        case 0:
+            mask = (value >> 16) & ALL_CPU_MASK;
+            break;
+        case 1:
+            mask = ALL_CPU_MASK ^ (1 << cpu);
+            break;
+        case 2:
+            mask = 1 << cpu;
+            break;
+        default:
+            DPRINTF("Bad Soft Int target filter\n");
+            mask = ALL_CPU_MASK;
+            break;
+        }
+        GIC_SET_PENDING(irq, mask);
+        gic_update(s);
+        return;
+    }
+    gic_dist_writew(opaque, offset, value & 0xffff);
+    gic_dist_writew(opaque, offset + 2, value >> 16);
+}
+
+static const MemoryRegionOps gic_dist_ops = {
+    .old_mmio = {
+        .read = { gic_dist_readb, gic_dist_readw, gic_dist_readl, },
+        .write = { gic_dist_writeb, gic_dist_writew, gic_dist_writel, },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static uint32_t gic_cpu_read(GICState *s, int cpu, int offset)
+{
+    switch (offset) {
+    case 0x00: /* Control */
+        return s->cpu_enabled[cpu];
+    case 0x04: /* Priority mask */
+        return s->priority_mask[cpu];
+    case 0x08: /* Binary Point */
+        /* ??? Not implemented.  */
+        return 0;
+    case 0x0c: /* Acknowledge */
+        return gic_acknowledge_irq(s, cpu);
+    case 0x14: /* Running Priority */
+        return s->running_priority[cpu];
+    case 0x18: /* Highest Pending Interrupt */
+        return s->current_pending[cpu];
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "gic_cpu_read: Bad offset %x\n", (int)offset);
+        return 0;
+    }
+}
+
+static void gic_cpu_write(GICState *s, int cpu, int offset, uint32_t value)
+{
+    switch (offset) {
+    case 0x00: /* Control */
+        s->cpu_enabled[cpu] = (value & 1);
+        DPRINTF("CPU %d %sabled\n", cpu, s->cpu_enabled[cpu] ? "En" : "Dis");
+        break;
+    case 0x04: /* Priority mask */
+        s->priority_mask[cpu] = (value & 0xff);
+        break;
+    case 0x08: /* Binary Point */
+        /* ??? Not implemented.  */
+        break;
+    case 0x10: /* End Of Interrupt */
+        return gic_complete_irq(s, cpu, value & 0x3ff);
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "gic_cpu_write: Bad offset %x\n", (int)offset);
+        return;
+    }
+    gic_update(s);
+}
+
+/* Wrappers to read/write the GIC CPU interface for the current CPU */
+static uint64_t gic_thiscpu_read(void *opaque, hwaddr addr,
+                                 unsigned size)
+{
+    GICState *s = (GICState *)opaque;
+    return gic_cpu_read(s, gic_get_current_cpu(s), addr);
+}
+
+static void gic_thiscpu_write(void *opaque, hwaddr addr,
+                              uint64_t value, unsigned size)
+{
+    GICState *s = (GICState *)opaque;
+    gic_cpu_write(s, gic_get_current_cpu(s), addr, value);
+}
+
+/* Wrappers to read/write the GIC CPU interface for a specific CPU.
+ * These just decode the opaque pointer into GICState* + cpu id.
+ */
+static uint64_t gic_do_cpu_read(void *opaque, hwaddr addr,
+                                unsigned size)
+{
+    GICState **backref = (GICState **)opaque;
+    GICState *s = *backref;
+    int id = (backref - s->backref);
+    return gic_cpu_read(s, id, addr);
+}
+
+static void gic_do_cpu_write(void *opaque, hwaddr addr,
+                             uint64_t value, unsigned size)
+{
+    GICState **backref = (GICState **)opaque;
+    GICState *s = *backref;
+    int id = (backref - s->backref);
+    gic_cpu_write(s, id, addr, value);
+}
+
+static const MemoryRegionOps gic_thiscpu_ops = {
+    .read = gic_thiscpu_read,
+    .write = gic_thiscpu_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static const MemoryRegionOps gic_cpu_ops = {
+    .read = gic_do_cpu_read,
+    .write = gic_do_cpu_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+void gic_init_irqs_and_distributor(GICState *s, int num_irq)
+{
+    int i;
+
+    i = s->num_irq - GIC_INTERNAL;
+    /* For the GIC, also expose incoming GPIO lines for PPIs for each CPU.
+     * GPIO array layout is thus:
+     *  [0..N-1] SPIs
+     *  [N..N+31] PPIs for CPU 0
+     *  [N+32..N+63] PPIs for CPU 1
+     *   ...
+     */
+    if (s->revision != REV_NVIC) {
+        i += (GIC_INTERNAL * s->num_cpu);
+    }
+    qdev_init_gpio_in(&s->busdev.qdev, gic_set_irq, i);
+    for (i = 0; i < NUM_CPU(s); i++) {
+        sysbus_init_irq(&s->busdev, &s->parent_irq[i]);
+    }
+    memory_region_init_io(&s->iomem, &gic_dist_ops, s, "gic_dist", 0x1000);
+}
+
+static void arm_gic_realize(DeviceState *dev, Error **errp)
+{
+    /* Device instance realize function for the GIC sysbus device */
+    int i;
+    GICState *s = ARM_GIC(dev);
+    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+    ARMGICClass *agc = ARM_GIC_GET_CLASS(s);
+
+    agc->parent_realize(dev, errp);
+    if (error_is_set(errp)) {
+        return;
+    }
+
+    gic_init_irqs_and_distributor(s, s->num_irq);
+
+    /* Memory regions for the CPU interfaces (NVIC doesn't have these):
+     * a region for "CPU interface for this core", then a region for
+     * "CPU interface for core 0", "for core 1", ...
+     * NB that the memory region size of 0x100 applies for the 11MPCore
+     * and also cores following the GIC v1 spec (ie A9).
+     * GIC v2 defines a larger memory region (0x1000) so this will need
+     * to be extended when we implement A15.
+     */
+    memory_region_init_io(&s->cpuiomem[0], &gic_thiscpu_ops, s,
+                          "gic_cpu", 0x100);
+    for (i = 0; i < NUM_CPU(s); i++) {
+        s->backref[i] = s;
+        memory_region_init_io(&s->cpuiomem[i+1], &gic_cpu_ops, &s->backref[i],
+                              "gic_cpu", 0x100);
+    }
+    /* Distributor */
+    sysbus_init_mmio(sbd, &s->iomem);
+    /* cpu interfaces (one for "current cpu" plus one per cpu) */
+    for (i = 0; i <= NUM_CPU(s); i++) {
+        sysbus_init_mmio(sbd, &s->cpuiomem[i]);
+    }
+}
+
+static void arm_gic_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    ARMGICClass *agc = ARM_GIC_CLASS(klass);
+
+    dc->no_user = 1;
+    agc->parent_realize = dc->realize;
+    dc->realize = arm_gic_realize;
+}
+
+static const TypeInfo arm_gic_info = {
+    .name = TYPE_ARM_GIC,
+    .parent = TYPE_ARM_GIC_COMMON,
+    .instance_size = sizeof(GICState),
+    .class_init = arm_gic_class_init,
+    .class_size = sizeof(ARMGICClass),
+};
+
+static void arm_gic_register_types(void)
+{
+    type_register_static(&arm_gic_info);
+}
+
+type_init(arm_gic_register_types)
diff --git a/hw/intc/arm_gic_common.c b/hw/intc/arm_gic_common.c
new file mode 100644 (file)
index 0000000..08560f2
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ * ARM GIC support - common bits of emulated and KVM kernel model
+ *
+ * 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 "gic_internal.h"
+
+static void gic_pre_save(void *opaque)
+{
+    GICState *s = (GICState *)opaque;
+    ARMGICCommonClass *c = ARM_GIC_COMMON_GET_CLASS(s);
+
+    if (c->pre_save) {
+        c->pre_save(s);
+    }
+}
+
+static int gic_post_load(void *opaque, int version_id)
+{
+    GICState *s = (GICState *)opaque;
+    ARMGICCommonClass *c = ARM_GIC_COMMON_GET_CLASS(s);
+
+    if (c->post_load) {
+        c->post_load(s);
+    }
+    return 0;
+}
+
+static const VMStateDescription vmstate_gic_irq_state = {
+    .name = "arm_gic_irq_state",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT8(enabled, gic_irq_state),
+        VMSTATE_UINT8(pending, gic_irq_state),
+        VMSTATE_UINT8(active, gic_irq_state),
+        VMSTATE_UINT8(level, gic_irq_state),
+        VMSTATE_BOOL(model, gic_irq_state),
+        VMSTATE_BOOL(trigger, gic_irq_state),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_gic = {
+    .name = "arm_gic",
+    .version_id = 4,
+    .minimum_version_id = 4,
+    .pre_save = gic_pre_save,
+    .post_load = gic_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_BOOL(enabled, GICState),
+        VMSTATE_BOOL_ARRAY(cpu_enabled, GICState, NCPU),
+        VMSTATE_STRUCT_ARRAY(irq_state, GICState, GIC_MAXIRQ, 1,
+                             vmstate_gic_irq_state, gic_irq_state),
+        VMSTATE_UINT8_ARRAY(irq_target, GICState, GIC_MAXIRQ),
+        VMSTATE_UINT8_2DARRAY(priority1, GICState, GIC_INTERNAL, NCPU),
+        VMSTATE_UINT8_ARRAY(priority2, GICState, GIC_MAXIRQ - GIC_INTERNAL),
+        VMSTATE_UINT16_2DARRAY(last_active, GICState, GIC_MAXIRQ, NCPU),
+        VMSTATE_UINT16_ARRAY(priority_mask, GICState, NCPU),
+        VMSTATE_UINT16_ARRAY(running_irq, GICState, NCPU),
+        VMSTATE_UINT16_ARRAY(running_priority, GICState, NCPU),
+        VMSTATE_UINT16_ARRAY(current_pending, GICState, NCPU),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void arm_gic_common_realize(DeviceState *dev, Error **errp)
+{
+    GICState *s = ARM_GIC_COMMON(dev);
+    int num_irq = s->num_irq;
+
+    if (s->num_cpu > NCPU) {
+        error_setg(errp, "requested %u CPUs exceeds GIC maximum %d",
+                   s->num_cpu, NCPU);
+        return;
+    }
+    s->num_irq += GIC_BASE_IRQ;
+    if (s->num_irq > GIC_MAXIRQ) {
+        error_setg(errp,
+                   "requested %u interrupt lines exceeds GIC maximum %d",
+                   num_irq, GIC_MAXIRQ);
+        return;
+    }
+    /* ITLinesNumber is represented as (N / 32) - 1 (see
+     * gic_dist_readb) so this is an implementation imposed
+     * restriction, not an architectural one:
+     */
+    if (s->num_irq < 32 || (s->num_irq % 32)) {
+        error_setg(errp,
+                   "%d interrupt lines unsupported: not divisible by 32",
+                   num_irq);
+        return;
+    }
+}
+
+static void arm_gic_common_reset(DeviceState *dev)
+{
+    GICState *s = FROM_SYSBUS(GICState, SYS_BUS_DEVICE(dev));
+    int i;
+    memset(s->irq_state, 0, GIC_MAXIRQ * sizeof(gic_irq_state));
+    for (i = 0 ; i < s->num_cpu; i++) {
+        if (s->revision == REV_11MPCORE) {
+            s->priority_mask[i] = 0xf0;
+        } else {
+            s->priority_mask[i] = 0;
+        }
+        s->current_pending[i] = 1023;
+        s->running_irq[i] = 1023;
+        s->running_priority[i] = 0x100;
+        s->cpu_enabled[i] = false;
+    }
+    for (i = 0; i < 16; i++) {
+        GIC_SET_ENABLED(i, ALL_CPU_MASK);
+        GIC_SET_TRIGGER(i);
+    }
+    if (s->num_cpu == 1) {
+        /* For uniprocessor GICs all interrupts always target the sole CPU */
+        for (i = 0; i < GIC_MAXIRQ; i++) {
+            s->irq_target[i] = 1;
+        }
+    }
+    s->enabled = false;
+}
+
+static Property arm_gic_common_properties[] = {
+    DEFINE_PROP_UINT32("num-cpu", GICState, num_cpu, 1),
+    DEFINE_PROP_UINT32("num-irq", GICState, num_irq, 32),
+    /* Revision can be 1 or 2 for GIC architecture specification
+     * versions 1 or 2, or 0 to indicate the legacy 11MPCore GIC.
+     * (Internally, 0xffffffff also indicates "not a GIC but an NVIC".)
+     */
+    DEFINE_PROP_UINT32("revision", GICState, revision, 1),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void arm_gic_common_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->reset = arm_gic_common_reset;
+    dc->realize = arm_gic_common_realize;
+    dc->props = arm_gic_common_properties;
+    dc->vmsd = &vmstate_gic;
+    dc->no_user = 1;
+}
+
+static const TypeInfo arm_gic_common_type = {
+    .name = TYPE_ARM_GIC_COMMON,
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(GICState),
+    .class_size = sizeof(ARMGICCommonClass),
+    .class_init = arm_gic_common_class_init,
+    .abstract = true,
+};
+
+static void register_types(void)
+{
+    type_register_static(&arm_gic_common_type);
+}
+
+type_init(register_types)
diff --git a/hw/intc/arm_gic_kvm.c b/hw/intc/arm_gic_kvm.c
new file mode 100644 (file)
index 0000000..b756456
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+ * ARM Generic Interrupt Controller using KVM in-kernel support
+ *
+ * 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 "hw/sysbus.h"
+#include "sysemu/kvm.h"
+#include "kvm_arm.h"
+#include "gic_internal.h"
+
+#define TYPE_KVM_ARM_GIC "kvm-arm-gic"
+#define KVM_ARM_GIC(obj) \
+     OBJECT_CHECK(GICState, (obj), TYPE_KVM_ARM_GIC)
+#define KVM_ARM_GIC_CLASS(klass) \
+     OBJECT_CLASS_CHECK(KVMARMGICClass, (klass), TYPE_KVM_ARM_GIC)
+#define KVM_ARM_GIC_GET_CLASS(obj) \
+     OBJECT_GET_CLASS(KVMARMGICClass, (obj), TYPE_KVM_ARM_GIC)
+
+typedef struct KVMARMGICClass {
+    ARMGICCommonClass parent_class;
+    DeviceRealize parent_realize;
+    void (*parent_reset)(DeviceState *dev);
+} KVMARMGICClass;
+
+static void kvm_arm_gic_set_irq(void *opaque, int irq, int level)
+{
+    /* Meaning of the 'irq' parameter:
+     *  [0..N-1] : external interrupts
+     *  [N..N+31] : PPI (internal) interrupts for CPU 0
+     *  [N+32..N+63] : PPI (internal interrupts for CPU 1
+     *  ...
+     * Convert this to the kernel's desired encoding, which
+     * has separate fields in the irq number for type,
+     * CPU number and interrupt number.
+     */
+    GICState *s = (GICState *)opaque;
+    int kvm_irq, irqtype, cpu;
+
+    if (irq < (s->num_irq - GIC_INTERNAL)) {
+        /* External interrupt. The kernel numbers these like the GIC
+         * hardware, with external interrupt IDs starting after the
+         * internal ones.
+         */
+        irqtype = KVM_ARM_IRQ_TYPE_SPI;
+        cpu = 0;
+        irq += GIC_INTERNAL;
+    } else {
+        /* Internal interrupt: decode into (cpu, interrupt id) */
+        irqtype = KVM_ARM_IRQ_TYPE_PPI;
+        irq -= (s->num_irq - GIC_INTERNAL);
+        cpu = irq / GIC_INTERNAL;
+        irq %= GIC_INTERNAL;
+    }
+    kvm_irq = (irqtype << KVM_ARM_IRQ_TYPE_SHIFT)
+        | (cpu << KVM_ARM_IRQ_VCPU_SHIFT) | irq;
+
+    kvm_set_irq(kvm_state, kvm_irq, !!level);
+}
+
+static void kvm_arm_gic_put(GICState *s)
+{
+    /* TODO: there isn't currently a kernel interface to set the GIC state */
+}
+
+static void kvm_arm_gic_get(GICState *s)
+{
+    /* TODO: there isn't currently a kernel interface to get the GIC state */
+}
+
+static void kvm_arm_gic_reset(DeviceState *dev)
+{
+    GICState *s = ARM_GIC_COMMON(dev);
+    KVMARMGICClass *kgc = KVM_ARM_GIC_GET_CLASS(s);
+
+    kgc->parent_reset(dev);
+    kvm_arm_gic_put(s);
+}
+
+static void kvm_arm_gic_realize(DeviceState *dev, Error **errp)
+{
+    int i;
+    GICState *s = KVM_ARM_GIC(dev);
+    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+    KVMARMGICClass *kgc = KVM_ARM_GIC_GET_CLASS(s);
+
+    kgc->parent_realize(dev, errp);
+    if (error_is_set(errp)) {
+        return;
+    }
+
+    i = s->num_irq - GIC_INTERNAL;
+    /* For the GIC, also expose incoming GPIO lines for PPIs for each CPU.
+     * GPIO array layout is thus:
+     *  [0..N-1] SPIs
+     *  [N..N+31] PPIs for CPU 0
+     *  [N+32..N+63] PPIs for CPU 1
+     *   ...
+     */
+    i += (GIC_INTERNAL * s->num_cpu);
+    qdev_init_gpio_in(dev, kvm_arm_gic_set_irq, i);
+    /* We never use our outbound IRQ lines but provide them so that
+     * we maintain the same interface as the non-KVM GIC.
+     */
+    for (i = 0; i < s->num_cpu; i++) {
+        sysbus_init_irq(sbd, &s->parent_irq[i]);
+    }
+    /* Distributor */
+    memory_region_init_reservation(&s->iomem, "kvm-gic_dist", 0x1000);
+    sysbus_init_mmio(sbd, &s->iomem);
+    kvm_arm_register_device(&s->iomem,
+                            (KVM_ARM_DEVICE_VGIC_V2 << KVM_ARM_DEVICE_ID_SHIFT)
+                            | KVM_VGIC_V2_ADDR_TYPE_DIST);
+    /* CPU interface for current core. Unlike arm_gic, we don't
+     * provide the "interface for core #N" memory regions, because
+     * cores with a VGIC don't have those.
+     */
+    memory_region_init_reservation(&s->cpuiomem[0], "kvm-gic_cpu", 0x1000);
+    sysbus_init_mmio(sbd, &s->cpuiomem[0]);
+    kvm_arm_register_device(&s->cpuiomem[0],
+                            (KVM_ARM_DEVICE_VGIC_V2 << KVM_ARM_DEVICE_ID_SHIFT)
+                            | KVM_VGIC_V2_ADDR_TYPE_CPU);
+}
+
+static void kvm_arm_gic_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    ARMGICCommonClass *agcc = ARM_GIC_COMMON_CLASS(klass);
+    KVMARMGICClass *kgc = KVM_ARM_GIC_CLASS(klass);
+
+    agcc->pre_save = kvm_arm_gic_get;
+    agcc->post_load = kvm_arm_gic_put;
+    kgc->parent_realize = dc->realize;
+    kgc->parent_reset = dc->reset;
+    dc->realize = kvm_arm_gic_realize;
+    dc->reset = kvm_arm_gic_reset;
+    dc->no_user = 1;
+}
+
+static const TypeInfo kvm_arm_gic_info = {
+    .name = TYPE_KVM_ARM_GIC,
+    .parent = TYPE_ARM_GIC_COMMON,
+    .instance_size = sizeof(GICState),
+    .class_init = kvm_arm_gic_class_init,
+    .class_size = sizeof(KVMARMGICClass),
+};
+
+static void kvm_arm_gic_register_types(void)
+{
+    type_register_static(&kvm_arm_gic_info);
+}
+
+type_init(kvm_arm_gic_register_types)
diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c
new file mode 100644 (file)
index 0000000..566b4bf
--- /dev/null
@@ -0,0 +1,553 @@
+/*
+ * ARM Nested Vectored Interrupt Controller
+ *
+ * Copyright (c) 2006-2007 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the GPL.
+ *
+ * The ARMv7M System controller is fairly tightly tied in with the
+ * NVIC.  Much of that is also implemented here.
+ */
+
+#include "hw/sysbus.h"
+#include "qemu/timer.h"
+#include "hw/arm.h"
+#include "exec/address-spaces.h"
+#include "gic_internal.h"
+
+typedef struct {
+    GICState gic;
+    struct {
+        uint32_t control;
+        uint32_t reload;
+        int64_t tick;
+        QEMUTimer *timer;
+    } systick;
+    MemoryRegion sysregmem;
+    MemoryRegion gic_iomem_alias;
+    MemoryRegion container;
+    uint32_t num_irq;
+} nvic_state;
+
+#define TYPE_NVIC "armv7m_nvic"
+/**
+ * NVICClass:
+ * @parent_reset: the parent class' reset handler.
+ *
+ * A model of the v7M NVIC and System Controller
+ */
+typedef struct NVICClass {
+    /*< private >*/
+    ARMGICClass parent_class;
+    /*< public >*/
+    DeviceRealize parent_realize;
+    void (*parent_reset)(DeviceState *dev);
+} NVICClass;
+
+#define NVIC_CLASS(klass) \
+    OBJECT_CLASS_CHECK(NVICClass, (klass), TYPE_NVIC)
+#define NVIC_GET_CLASS(obj) \
+    OBJECT_GET_CLASS(NVICClass, (obj), TYPE_NVIC)
+#define NVIC(obj) \
+    OBJECT_CHECK(nvic_state, (obj), TYPE_NVIC)
+
+static const uint8_t nvic_id[] = {
+    0x00, 0xb0, 0x1b, 0x00, 0x0d, 0xe0, 0x05, 0xb1
+};
+
+/* qemu timers run at 1GHz.   We want something closer to 1MHz.  */
+#define SYSTICK_SCALE 1000ULL
+
+#define SYSTICK_ENABLE    (1 << 0)
+#define SYSTICK_TICKINT   (1 << 1)
+#define SYSTICK_CLKSOURCE (1 << 2)
+#define SYSTICK_COUNTFLAG (1 << 16)
+
+int system_clock_scale;
+
+/* Conversion factor from qemu timer to SysTick frequencies.  */
+static inline int64_t systick_scale(nvic_state *s)
+{
+    if (s->systick.control & SYSTICK_CLKSOURCE)
+        return system_clock_scale;
+    else
+        return 1000;
+}
+
+static void systick_reload(nvic_state *s, int reset)
+{
+    if (reset)
+        s->systick.tick = qemu_get_clock_ns(vm_clock);
+    s->systick.tick += (s->systick.reload + 1) * systick_scale(s);
+    qemu_mod_timer(s->systick.timer, s->systick.tick);
+}
+
+static void systick_timer_tick(void * opaque)
+{
+    nvic_state *s = (nvic_state *)opaque;
+    s->systick.control |= SYSTICK_COUNTFLAG;
+    if (s->systick.control & SYSTICK_TICKINT) {
+        /* Trigger the interrupt.  */
+        armv7m_nvic_set_pending(s, ARMV7M_EXCP_SYSTICK);
+    }
+    if (s->systick.reload == 0) {
+        s->systick.control &= ~SYSTICK_ENABLE;
+    } else {
+        systick_reload(s, 0);
+    }
+}
+
+static void systick_reset(nvic_state *s)
+{
+    s->systick.control = 0;
+    s->systick.reload = 0;
+    s->systick.tick = 0;
+    qemu_del_timer(s->systick.timer);
+}
+
+/* The external routines use the hardware vector numbering, ie. the first
+   IRQ is #16.  The internal GIC routines use #32 as the first IRQ.  */
+void armv7m_nvic_set_pending(void *opaque, int irq)
+{
+    nvic_state *s = (nvic_state *)opaque;
+    if (irq >= 16)
+        irq += 16;
+    gic_set_pending_private(&s->gic, 0, irq);
+}
+
+/* Make pending IRQ active.  */
+int armv7m_nvic_acknowledge_irq(void *opaque)
+{
+    nvic_state *s = (nvic_state *)opaque;
+    uint32_t irq;
+
+    irq = gic_acknowledge_irq(&s->gic, 0);
+    if (irq == 1023)
+        hw_error("Interrupt but no vector\n");
+    if (irq >= 32)
+        irq -= 16;
+    return irq;
+}
+
+void armv7m_nvic_complete_irq(void *opaque, int irq)
+{
+    nvic_state *s = (nvic_state *)opaque;
+    if (irq >= 16)
+        irq += 16;
+    gic_complete_irq(&s->gic, 0, irq);
+}
+
+static uint32_t nvic_readl(nvic_state *s, uint32_t offset)
+{
+    uint32_t val;
+    int irq;
+
+    switch (offset) {
+    case 4: /* Interrupt Control Type.  */
+        return (s->num_irq / 32) - 1;
+    case 0x10: /* SysTick Control and Status.  */
+        val = s->systick.control;
+        s->systick.control &= ~SYSTICK_COUNTFLAG;
+        return val;
+    case 0x14: /* SysTick Reload Value.  */
+        return s->systick.reload;
+    case 0x18: /* SysTick Current Value.  */
+        {
+            int64_t t;
+            if ((s->systick.control & SYSTICK_ENABLE) == 0)
+                return 0;
+            t = qemu_get_clock_ns(vm_clock);
+            if (t >= s->systick.tick)
+                return 0;
+            val = ((s->systick.tick - (t + 1)) / systick_scale(s)) + 1;
+            /* The interrupt in triggered when the timer reaches zero.
+               However the counter is not reloaded until the next clock
+               tick.  This is a hack to return zero during the first tick.  */
+            if (val > s->systick.reload)
+                val = 0;
+            return val;
+        }
+    case 0x1c: /* SysTick Calibration Value.  */
+        return 10000;
+    case 0xd00: /* CPUID Base.  */
+        return cpu_single_env->cp15.c0_cpuid;
+    case 0xd04: /* Interrypt Control State.  */
+        /* VECTACTIVE */
+        val = s->gic.running_irq[0];
+        if (val == 1023) {
+            val = 0;
+        } else if (val >= 32) {
+            val -= 16;
+        }
+        /* RETTOBASE */
+        if (s->gic.running_irq[0] == 1023
+                || s->gic.last_active[s->gic.running_irq[0]][0] == 1023) {
+            val |= (1 << 11);
+        }
+        /* VECTPENDING */
+        if (s->gic.current_pending[0] != 1023)
+            val |= (s->gic.current_pending[0] << 12);
+        /* ISRPENDING */
+        for (irq = 32; irq < s->num_irq; irq++) {
+            if (s->gic.irq_state[irq].pending) {
+                val |= (1 << 22);
+                break;
+            }
+        }
+        /* PENDSTSET */
+        if (s->gic.irq_state[ARMV7M_EXCP_SYSTICK].pending)
+            val |= (1 << 26);
+        /* PENDSVSET */
+        if (s->gic.irq_state[ARMV7M_EXCP_PENDSV].pending)
+            val |= (1 << 28);
+        /* NMIPENDSET */
+        if (s->gic.irq_state[ARMV7M_EXCP_NMI].pending)
+            val |= (1 << 31);
+        return val;
+    case 0xd08: /* Vector Table Offset.  */
+        return cpu_single_env->v7m.vecbase;
+    case 0xd0c: /* Application Interrupt/Reset Control.  */
+        return 0xfa05000;
+    case 0xd10: /* System Control.  */
+        /* TODO: Implement SLEEPONEXIT.  */
+        return 0;
+    case 0xd14: /* Configuration Control.  */
+        /* TODO: Implement Configuration Control bits.  */
+        return 0;
+    case 0xd24: /* System Handler Status.  */
+        val = 0;
+        if (s->gic.irq_state[ARMV7M_EXCP_MEM].active) val |= (1 << 0);
+        if (s->gic.irq_state[ARMV7M_EXCP_BUS].active) val |= (1 << 1);
+        if (s->gic.irq_state[ARMV7M_EXCP_USAGE].active) val |= (1 << 3);
+        if (s->gic.irq_state[ARMV7M_EXCP_SVC].active) val |= (1 << 7);
+        if (s->gic.irq_state[ARMV7M_EXCP_DEBUG].active) val |= (1 << 8);
+        if (s->gic.irq_state[ARMV7M_EXCP_PENDSV].active) val |= (1 << 10);
+        if (s->gic.irq_state[ARMV7M_EXCP_SYSTICK].active) val |= (1 << 11);
+        if (s->gic.irq_state[ARMV7M_EXCP_USAGE].pending) val |= (1 << 12);
+        if (s->gic.irq_state[ARMV7M_EXCP_MEM].pending) val |= (1 << 13);
+        if (s->gic.irq_state[ARMV7M_EXCP_BUS].pending) val |= (1 << 14);
+        if (s->gic.irq_state[ARMV7M_EXCP_SVC].pending) val |= (1 << 15);
+        if (s->gic.irq_state[ARMV7M_EXCP_MEM].enabled) val |= (1 << 16);
+        if (s->gic.irq_state[ARMV7M_EXCP_BUS].enabled) val |= (1 << 17);
+        if (s->gic.irq_state[ARMV7M_EXCP_USAGE].enabled) val |= (1 << 18);
+        return val;
+    case 0xd28: /* Configurable Fault Status.  */
+        /* TODO: Implement Fault Status.  */
+        qemu_log_mask(LOG_UNIMP, "Configurable Fault Status unimplemented\n");
+        return 0;
+    case 0xd2c: /* Hard Fault Status.  */
+    case 0xd30: /* Debug Fault Status.  */
+    case 0xd34: /* Mem Manage Address.  */
+    case 0xd38: /* Bus Fault Address.  */
+    case 0xd3c: /* Aux Fault Status.  */
+        /* TODO: Implement fault status registers.  */
+        qemu_log_mask(LOG_UNIMP, "Fault status registers unimplemented\n");
+        return 0;
+    case 0xd40: /* PFR0.  */
+        return 0x00000030;
+    case 0xd44: /* PRF1.  */
+        return 0x00000200;
+    case 0xd48: /* DFR0.  */
+        return 0x00100000;
+    case 0xd4c: /* AFR0.  */
+        return 0x00000000;
+    case 0xd50: /* MMFR0.  */
+        return 0x00000030;
+    case 0xd54: /* MMFR1.  */
+        return 0x00000000;
+    case 0xd58: /* MMFR2.  */
+        return 0x00000000;
+    case 0xd5c: /* MMFR3.  */
+        return 0x00000000;
+    case 0xd60: /* ISAR0.  */
+        return 0x01141110;
+    case 0xd64: /* ISAR1.  */
+        return 0x02111000;
+    case 0xd68: /* ISAR2.  */
+        return 0x21112231;
+    case 0xd6c: /* ISAR3.  */
+        return 0x01111110;
+    case 0xd70: /* ISAR4.  */
+        return 0x01310102;
+    /* TODO: Implement debug registers.  */
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR, "NVIC: Bad read offset 0x%x\n", offset);
+        return 0;
+    }
+}
+
+static void nvic_writel(nvic_state *s, uint32_t offset, uint32_t value)
+{
+    uint32_t oldval;
+    switch (offset) {
+    case 0x10: /* SysTick Control and Status.  */
+        oldval = s->systick.control;
+        s->systick.control &= 0xfffffff8;
+        s->systick.control |= value & 7;
+        if ((oldval ^ value) & SYSTICK_ENABLE) {
+            int64_t now = qemu_get_clock_ns(vm_clock);
+            if (value & SYSTICK_ENABLE) {
+                if (s->systick.tick) {
+                    s->systick.tick += now;
+                    qemu_mod_timer(s->systick.timer, s->systick.tick);
+                } else {
+                    systick_reload(s, 1);
+                }
+            } else {
+                qemu_del_timer(s->systick.timer);
+                s->systick.tick -= now;
+                if (s->systick.tick < 0)
+                  s->systick.tick = 0;
+            }
+        } else if ((oldval ^ value) & SYSTICK_CLKSOURCE) {
+            /* This is a hack. Force the timer to be reloaded
+               when the reference clock is changed.  */
+            systick_reload(s, 1);
+        }
+        break;
+    case 0x14: /* SysTick Reload Value.  */
+        s->systick.reload = value;
+        break;
+    case 0x18: /* SysTick Current Value.  Writes reload the timer.  */
+        systick_reload(s, 1);
+        s->systick.control &= ~SYSTICK_COUNTFLAG;
+        break;
+    case 0xd04: /* Interrupt Control State.  */
+        if (value & (1 << 31)) {
+            armv7m_nvic_set_pending(s, ARMV7M_EXCP_NMI);
+        }
+        if (value & (1 << 28)) {
+            armv7m_nvic_set_pending(s, ARMV7M_EXCP_PENDSV);
+        } else if (value & (1 << 27)) {
+            s->gic.irq_state[ARMV7M_EXCP_PENDSV].pending = 0;
+            gic_update(&s->gic);
+        }
+        if (value & (1 << 26)) {
+            armv7m_nvic_set_pending(s, ARMV7M_EXCP_SYSTICK);
+        } else if (value & (1 << 25)) {
+            s->gic.irq_state[ARMV7M_EXCP_SYSTICK].pending = 0;
+            gic_update(&s->gic);
+        }
+        break;
+    case 0xd08: /* Vector Table Offset.  */
+        cpu_single_env->v7m.vecbase = value & 0xffffff80;
+        break;
+    case 0xd0c: /* Application Interrupt/Reset Control.  */
+        if ((value >> 16) == 0x05fa) {
+            if (value & 2) {
+                qemu_log_mask(LOG_UNIMP, "VECTCLRACTIVE unimplemented\n");
+            }
+            if (value & 5) {
+                qemu_log_mask(LOG_UNIMP, "AIRCR system reset unimplemented\n");
+            }
+        }
+        break;
+    case 0xd10: /* System Control.  */
+    case 0xd14: /* Configuration Control.  */
+        /* TODO: Implement control registers.  */
+        qemu_log_mask(LOG_UNIMP, "NVIC: SCR and CCR unimplemented\n");
+        break;
+    case 0xd24: /* System Handler Control.  */
+        /* TODO: Real hardware allows you to set/clear the active bits
+           under some circumstances.  We don't implement this.  */
+        s->gic.irq_state[ARMV7M_EXCP_MEM].enabled = (value & (1 << 16)) != 0;
+        s->gic.irq_state[ARMV7M_EXCP_BUS].enabled = (value & (1 << 17)) != 0;
+        s->gic.irq_state[ARMV7M_EXCP_USAGE].enabled = (value & (1 << 18)) != 0;
+        break;
+    case 0xd28: /* Configurable Fault Status.  */
+    case 0xd2c: /* Hard Fault Status.  */
+    case 0xd30: /* Debug Fault Status.  */
+    case 0xd34: /* Mem Manage Address.  */
+    case 0xd38: /* Bus Fault Address.  */
+    case 0xd3c: /* Aux Fault Status.  */
+        qemu_log_mask(LOG_UNIMP,
+                      "NVIC: fault status registers unimplemented\n");
+        break;
+    case 0xf00: /* Software Triggered Interrupt Register */
+        if ((value & 0x1ff) < s->num_irq) {
+            gic_set_pending_private(&s->gic, 0, value & 0x1ff);
+        }
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "NVIC: Bad write offset 0x%x\n", offset);
+    }
+}
+
+static uint64_t nvic_sysreg_read(void *opaque, hwaddr addr,
+                                 unsigned size)
+{
+    nvic_state *s = (nvic_state *)opaque;
+    uint32_t offset = addr;
+    int i;
+    uint32_t val;
+
+    switch (offset) {
+    case 0xd18 ... 0xd23: /* System Handler Priority.  */
+        val = 0;
+        for (i = 0; i < size; i++) {
+            val |= s->gic.priority1[(offset - 0xd14) + i][0] << (i * 8);
+        }
+        return val;
+    case 0xfe0 ... 0xfff: /* ID.  */
+        if (offset & 3) {
+            return 0;
+        }
+        return nvic_id[(offset - 0xfe0) >> 2];
+    }
+    if (size == 4) {
+        return nvic_readl(s, offset);
+    }
+    qemu_log_mask(LOG_GUEST_ERROR,
+                  "NVIC: Bad read of size %d at offset 0x%x\n", size, offset);
+    return 0;
+}
+
+static void nvic_sysreg_write(void *opaque, hwaddr addr,
+                              uint64_t value, unsigned size)
+{
+    nvic_state *s = (nvic_state *)opaque;
+    uint32_t offset = addr;
+    int i;
+
+    switch (offset) {
+    case 0xd18 ... 0xd23: /* System Handler Priority.  */
+        for (i = 0; i < size; i++) {
+            s->gic.priority1[(offset - 0xd14) + i][0] =
+                (value >> (i * 8)) & 0xff;
+        }
+        gic_update(&s->gic);
+        return;
+    }
+    if (size == 4) {
+        nvic_writel(s, offset, value);
+        return;
+    }
+    qemu_log_mask(LOG_GUEST_ERROR,
+                  "NVIC: Bad write of size %d at offset 0x%x\n", size, offset);
+}
+
+static const MemoryRegionOps nvic_sysreg_ops = {
+    .read = nvic_sysreg_read,
+    .write = nvic_sysreg_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static const VMStateDescription vmstate_nvic = {
+    .name = "armv7m_nvic",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32(systick.control, nvic_state),
+        VMSTATE_UINT32(systick.reload, nvic_state),
+        VMSTATE_INT64(systick.tick, nvic_state),
+        VMSTATE_TIMER(systick.timer, nvic_state),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void armv7m_nvic_reset(DeviceState *dev)
+{
+    nvic_state *s = NVIC(dev);
+    NVICClass *nc = NVIC_GET_CLASS(s);
+    nc->parent_reset(dev);
+    /* Common GIC reset resets to disabled; the NVIC doesn't have
+     * per-CPU interfaces so mark our non-existent CPU interface
+     * as enabled by default, and with a priority mask which allows
+     * all interrupts through.
+     */
+    s->gic.cpu_enabled[0] = true;
+    s->gic.priority_mask[0] = 0x100;
+    /* The NVIC as a whole is always enabled. */
+    s->gic.enabled = true;
+    systick_reset(s);
+}
+
+static void armv7m_nvic_realize(DeviceState *dev, Error **errp)
+{
+    nvic_state *s = NVIC(dev);
+    NVICClass *nc = NVIC_GET_CLASS(s);
+
+    /* The NVIC always has only one CPU */
+    s->gic.num_cpu = 1;
+    /* Tell the common code we're an NVIC */
+    s->gic.revision = 0xffffffff;
+    s->num_irq = s->gic.num_irq;
+    nc->parent_realize(dev, errp);
+    if (error_is_set(errp)) {
+        return;
+    }
+    gic_init_irqs_and_distributor(&s->gic, s->num_irq);
+    /* The NVIC and system controller register area looks like this:
+     *  0..0xff : system control registers, including systick
+     *  0x100..0xcff : GIC-like registers
+     *  0xd00..0xfff : system control registers
+     * We use overlaying to put the GIC like registers
+     * over the top of the system control register region.
+     */
+    memory_region_init(&s->container, "nvic", 0x1000);
+    /* The system register region goes at the bottom of the priority
+     * stack as it covers the whole page.
+     */
+    memory_region_init_io(&s->sysregmem, &nvic_sysreg_ops, s,
+                          "nvic_sysregs", 0x1000);
+    memory_region_add_subregion(&s->container, 0, &s->sysregmem);
+    /* Alias the GIC region so we can get only the section of it
+     * we need, and layer it on top of the system register region.
+     */
+    memory_region_init_alias(&s->gic_iomem_alias, "nvic-gic", &s->gic.iomem,
+                             0x100, 0xc00);
+    memory_region_add_subregion_overlap(&s->container, 0x100,
+                                        &s->gic_iomem_alias, 1);
+    /* Map the whole thing into system memory at the location required
+     * by the v7M architecture.
+     */
+    memory_region_add_subregion(get_system_memory(), 0xe000e000, &s->container);
+    s->systick.timer = qemu_new_timer_ns(vm_clock, systick_timer_tick, s);
+}
+
+static void armv7m_nvic_instance_init(Object *obj)
+{
+    /* We have a different default value for the num-irq property
+     * than our superclass. This function runs after qdev init
+     * has set the defaults from the Property array and before
+     * any user-specified property setting, so just modify the
+     * value in the GICState struct.
+     */
+    GICState *s = ARM_GIC_COMMON(obj);
+    /* 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 the num-irq property appropriately.
+     */
+    s->num_irq = 64;
+}
+
+static void armv7m_nvic_class_init(ObjectClass *klass, void *data)
+{
+    NVICClass *nc = NVIC_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    nc->parent_reset = dc->reset;
+    nc->parent_realize = dc->realize;
+    dc->vmsd  = &vmstate_nvic;
+    dc->reset = armv7m_nvic_reset;
+    dc->realize = armv7m_nvic_realize;
+}
+
+static const TypeInfo armv7m_nvic_info = {
+    .name          = TYPE_NVIC,
+    .parent        = TYPE_ARM_GIC_COMMON,
+    .instance_init = armv7m_nvic_instance_init,
+    .instance_size = sizeof(nvic_state),
+    .class_init    = armv7m_nvic_class_init,
+    .class_size    = sizeof(NVICClass),
+};
+
+static void armv7m_nvic_register_types(void)
+{
+    type_register_static(&armv7m_nvic_info);
+}
+
+type_init(armv7m_nvic_register_types)
diff --git a/hw/intc/etraxfs_pic.c b/hw/intc/etraxfs_pic.c
new file mode 100644 (file)
index 0000000..635103c
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+ * QEMU ETRAX Interrupt Controller.
+ *
+ * Copyright (c) 2008 Edgar E. Iglesias, Axis Communications AB.
+ *
+ * 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 "hw/sysbus.h"
+#include "hw/hw.h"
+//#include "pc.h"
+//#include "etraxfs.h"
+
+#define D(x)
+
+#define R_RW_MASK   0
+#define R_R_VECT    1
+#define R_R_MASKED_VECT 2
+#define R_R_NMI     3
+#define R_R_GURU    4
+#define R_MAX       5
+
+struct etrax_pic
+{
+    SysBusDevice busdev;
+    MemoryRegion mmio;
+    void *interrupt_vector;
+    qemu_irq parent_irq;
+    qemu_irq parent_nmi;
+    uint32_t regs[R_MAX];
+};
+
+static void pic_update(struct etrax_pic *fs)
+{   
+    uint32_t vector = 0;
+    int i;
+
+    fs->regs[R_R_MASKED_VECT] = fs->regs[R_R_VECT] & fs->regs[R_RW_MASK];
+
+    /* The ETRAX interrupt controller signals interrupts to the core
+       through an interrupt request wire and an irq vector bus. If 
+       multiple interrupts are simultaneously active it chooses vector 
+       0x30 and lets the sw choose the priorities.  */
+    if (fs->regs[R_R_MASKED_VECT]) {
+        uint32_t mv = fs->regs[R_R_MASKED_VECT];
+        for (i = 0; i < 31; i++) {
+            if (mv & 1) {
+                vector = 0x31 + i;
+                /* Check for multiple interrupts.  */
+                if (mv > 1)
+                    vector = 0x30;
+                break;
+            }
+            mv >>= 1;
+        }
+    }
+
+    if (fs->interrupt_vector) {
+        /* hack alert: ptr property */
+        *(uint32_t*)(fs->interrupt_vector) = vector;
+    }
+    qemu_set_irq(fs->parent_irq, !!vector);
+}
+
+static uint64_t
+pic_read(void *opaque, hwaddr addr, unsigned int size)
+{
+    struct etrax_pic *fs = opaque;
+    uint32_t rval;
+
+    rval = fs->regs[addr >> 2];
+    D(printf("%s %x=%x\n", __func__, addr, rval));
+    return rval;
+}
+
+static void pic_write(void *opaque, hwaddr addr,
+                      uint64_t value, unsigned int size)
+{
+    struct etrax_pic *fs = opaque;
+    D(printf("%s addr=%x val=%x\n", __func__, addr, value));
+
+    if (addr == R_RW_MASK) {
+        fs->regs[R_RW_MASK] = value;
+        pic_update(fs);
+    }
+}
+
+static const MemoryRegionOps pic_ops = {
+    .read = pic_read,
+    .write = pic_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4
+    }
+};
+
+static void nmi_handler(void *opaque, int irq, int level)
+{   
+    struct etrax_pic *fs = (void *)opaque;
+    uint32_t mask;
+
+    mask = 1 << irq;
+    if (level)
+        fs->regs[R_R_NMI] |= mask;
+    else
+        fs->regs[R_R_NMI] &= ~mask;
+
+    qemu_set_irq(fs->parent_nmi, !!fs->regs[R_R_NMI]);
+}
+
+static void irq_handler(void *opaque, int irq, int level)
+{   
+    struct etrax_pic *fs = (void *)opaque;
+
+    if (irq >= 30)
+        return nmi_handler(opaque, irq, level);
+
+    irq -= 1;
+    fs->regs[R_R_VECT] &= ~(1 << irq);
+    fs->regs[R_R_VECT] |= (!!level << irq);
+    pic_update(fs);
+}
+
+static int etraxfs_pic_init(SysBusDevice *dev)
+{
+    struct etrax_pic *s = FROM_SYSBUS(typeof (*s), dev);
+
+    qdev_init_gpio_in(&dev->qdev, irq_handler, 32);
+    sysbus_init_irq(dev, &s->parent_irq);
+    sysbus_init_irq(dev, &s->parent_nmi);
+
+    memory_region_init_io(&s->mmio, &pic_ops, s, "etraxfs-pic", R_MAX * 4);
+    sysbus_init_mmio(dev, &s->mmio);
+    return 0;
+}
+
+static Property etraxfs_pic_properties[] = {
+    DEFINE_PROP_PTR("interrupt_vector", struct etrax_pic, interrupt_vector),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void etraxfs_pic_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = etraxfs_pic_init;
+    dc->props = etraxfs_pic_properties;
+}
+
+static const 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_types(void)
+{
+    type_register_static(&etraxfs_pic_info);
+}
+
+type_init(etraxfs_pic_register_types)
diff --git a/hw/intc/exynos4210_combiner.c b/hw/intc/exynos4210_combiner.c
new file mode 100644 (file)
index 0000000..6874287
--- /dev/null
@@ -0,0 +1,455 @@
+/*
+ * Samsung exynos4210 Interrupt Combiner
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd.
+ * All rights reserved.
+ *
+ * Evgeny Voevodin <e.voevodin@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 "hw/sysbus.h"
+
+#include "hw/arm/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, hwaddr 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;
+
+    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, hwaddr 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 */
+
+    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;
+    }
+}
+
+/* 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);
+}
+
+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 const 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/intc/exynos4210_gic.c b/hw/intc/exynos4210_gic.c
new file mode 100644 (file)
index 0000000..bad6dde
--- /dev/null
@@ -0,0 +1,462 @@
+/*
+ * 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@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 "hw/sysbus.h"
+#include "qemu-common.h"
+#include "hw/irq.h"
+#include "hw/arm/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 , EXT_GIC_ID_USB_HOST},
+    /* 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 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);
+}
+
+/*
+ * 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 *********/
+
+typedef struct {
+    SysBusDevice busdev;
+    MemoryRegion cpu_container;
+    MemoryRegion dist_container;
+    MemoryRegion cpu_alias[EXYNOS4210_NCPUS];
+    MemoryRegion dist_alias[EXYNOS4210_NCPUS];
+    uint32_t num_cpu;
+    DeviceState *gic;
+} Exynos4210GicState;
+
+static void exynos4210_gic_set_irq(void *opaque, int irq, int level)
+{
+    Exynos4210GicState *s = (Exynos4210GicState *)opaque;
+    qemu_set_irq(qdev_get_gpio_in(s->gic, irq), level);
+}
+
+static int exynos4210_gic_init(SysBusDevice *dev)
+{
+    Exynos4210GicState *s = FROM_SYSBUS(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];
+    SysBusDevice *busdev;
+
+    s->gic = qdev_create(NULL, "arm_gic");
+    qdev_prop_set_uint32(s->gic, "num-cpu", s->num_cpu);
+    qdev_prop_set_uint32(s->gic, "num-irq", EXYNOS4210_GIC_NIRQ);
+    qdev_init_nofail(s->gic);
+    busdev = SYS_BUS_DEVICE(s->gic);
+
+    /* Pass through outbound IRQ lines from the GIC */
+    sysbus_pass_irq(dev, busdev);
+
+    /* Pass through inbound GPIO lines to the GIC */
+    qdev_init_gpio_in(&s->busdev.qdev, exynos4210_gic_set_irq,
+                      EXYNOS4210_GIC_NIRQ - 32);
+
+    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,
+                                 sysbus_mmio_get_region(busdev, 1),
+                                 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,
+                                 sysbus_mmio_get_region(busdev, 0),
+                                 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);
+
+    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 const 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)
+
+/* IRQ OR Gate struct.
+ *
+ * This device models an OR gate. There are n_in input qdev gpio lines and one
+ * output sysbus IRQ line. The output IRQ level is formed as OR between all
+ * gpio inputs.
+ */
+typedef struct {
+    SysBusDevice busdev;
+
+    uint32_t n_in;      /* inputs amount */
+    uint32_t *level;    /* input levels */
+    qemu_irq out;       /* output IRQ */
+} Exynos4210IRQGateState;
+
+static Property exynos4210_irq_gate_properties[] = {
+    DEFINE_PROP_UINT32("n_in", Exynos4210IRQGateState, n_in, 1),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static const VMStateDescription vmstate_exynos4210_irq_gate = {
+    .name = "exynos4210.irq_gate",
+    .version_id = 2,
+    .minimum_version_id = 2,
+    .minimum_version_id_old = 2,
+    .fields = (VMStateField[]) {
+        VMSTATE_VBUFFER_UINT32(level, Exynos4210IRQGateState, 1, NULL, 0, n_in),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+/* Process a change in IRQ input. */
+static void exynos4210_irq_gate_handler(void *opaque, int irq, int level)
+{
+    Exynos4210IRQGateState *s = (Exynos4210IRQGateState *)opaque;
+    uint32_t i;
+
+    assert(irq < s->n_in);
+
+    s->level[irq] = level;
+
+    for (i = 0; i < s->n_in; i++) {
+        if (s->level[i] >= 1) {
+            qemu_irq_raise(s->out);
+            return;
+        }
+    }
+
+    qemu_irq_lower(s->out);
+}
+
+static void exynos4210_irq_gate_reset(DeviceState *d)
+{
+    Exynos4210IRQGateState *s =
+            DO_UPCAST(Exynos4210IRQGateState, busdev.qdev, d);
+
+    memset(s->level, 0, s->n_in * sizeof(*s->level));
+}
+
+/*
+ * IRQ Gate initialization.
+ */
+static int exynos4210_irq_gate_init(SysBusDevice *dev)
+{
+    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, s->n_in);
+
+    s->level = g_malloc0(s->n_in * sizeof(*s->level));
+
+    sysbus_init_irq(dev, &s->out);
+
+    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;
+    dc->props = exynos4210_irq_gate_properties;
+}
+
+static const 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)
diff --git a/hw/intc/gic_internal.h b/hw/intc/gic_internal.h
new file mode 100644 (file)
index 0000000..99a3bc3
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * ARM GIC support - internal interfaces
+ *
+ * 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/>.
+ */
+
+#ifndef QEMU_ARM_GIC_INTERNAL_H
+#define QEMU_ARM_GIC_INTERNAL_H
+
+#include "hw/sysbus.h"
+
+/* Maximum number of possible interrupts, determined by the GIC architecture */
+#define GIC_MAXIRQ 1020
+/* First 32 are private to each CPU (SGIs and PPIs). */
+#define GIC_INTERNAL 32
+/* Maximum number of possible CPU interfaces, determined by GIC architecture */
+#define NCPU 8
+
+#define ALL_CPU_MASK ((unsigned)(((1 << NCPU) - 1)))
+
+/* The NVIC has 16 internal vectors.  However these are not exposed
+   through the normal GIC interface.  */
+#define GIC_BASE_IRQ ((s->revision == REV_NVIC) ? 32 : 0)
+
+#define GIC_SET_ENABLED(irq, cm) s->irq_state[irq].enabled |= (cm)
+#define GIC_CLEAR_ENABLED(irq, cm) s->irq_state[irq].enabled &= ~(cm)
+#define GIC_TEST_ENABLED(irq, cm) ((s->irq_state[irq].enabled & (cm)) != 0)
+#define GIC_SET_PENDING(irq, cm) s->irq_state[irq].pending |= (cm)
+#define GIC_CLEAR_PENDING(irq, cm) s->irq_state[irq].pending &= ~(cm)
+#define GIC_TEST_PENDING(irq, cm) ((s->irq_state[irq].pending & (cm)) != 0)
+#define GIC_SET_ACTIVE(irq, cm) s->irq_state[irq].active |= (cm)
+#define GIC_CLEAR_ACTIVE(irq, cm) s->irq_state[irq].active &= ~(cm)
+#define GIC_TEST_ACTIVE(irq, cm) ((s->irq_state[irq].active & (cm)) != 0)
+#define GIC_SET_MODEL(irq) s->irq_state[irq].model = true
+#define GIC_CLEAR_MODEL(irq) s->irq_state[irq].model = false
+#define GIC_TEST_MODEL(irq) s->irq_state[irq].model
+#define GIC_SET_LEVEL(irq, cm) s->irq_state[irq].level = (cm)
+#define GIC_CLEAR_LEVEL(irq, cm) s->irq_state[irq].level &= ~(cm)
+#define GIC_TEST_LEVEL(irq, cm) ((s->irq_state[irq].level & (cm)) != 0)
+#define GIC_SET_TRIGGER(irq) s->irq_state[irq].trigger = true
+#define GIC_CLEAR_TRIGGER(irq) s->irq_state[irq].trigger = false
+#define GIC_TEST_TRIGGER(irq) s->irq_state[irq].trigger
+#define GIC_GET_PRIORITY(irq, cpu) (((irq) < GIC_INTERNAL) ?            \
+                                    s->priority1[irq][cpu] :            \
+                                    s->priority2[(irq) - GIC_INTERNAL])
+#define GIC_TARGET(irq) s->irq_target[irq]
+
+typedef struct gic_irq_state {
+    /* The enable bits are only banked for per-cpu interrupts.  */
+    uint8_t enabled;
+    uint8_t pending;
+    uint8_t active;
+    uint8_t level;
+    bool model; /* 0 = N:N, 1 = 1:N */
+    bool trigger; /* nonzero = edge triggered.  */
+} gic_irq_state;
+
+typedef struct GICState {
+    SysBusDevice busdev;
+    qemu_irq parent_irq[NCPU];
+    bool enabled;
+    bool cpu_enabled[NCPU];
+
+    gic_irq_state irq_state[GIC_MAXIRQ];
+    uint8_t irq_target[GIC_MAXIRQ];
+    uint8_t priority1[GIC_INTERNAL][NCPU];
+    uint8_t priority2[GIC_MAXIRQ - GIC_INTERNAL];
+    uint16_t last_active[GIC_MAXIRQ][NCPU];
+
+    uint16_t priority_mask[NCPU];
+    uint16_t running_irq[NCPU];
+    uint16_t running_priority[NCPU];
+    uint16_t current_pending[NCPU];
+
+    uint32_t num_cpu;
+
+    MemoryRegion iomem; /* Distributor */
+    /* This is just so we can have an opaque pointer which identifies
+     * both this GIC and which CPU interface we should be accessing.
+     */
+    struct GICState *backref[NCPU];
+    MemoryRegion cpuiomem[NCPU+1]; /* CPU interfaces */
+    uint32_t num_irq;
+    uint32_t revision;
+} GICState;
+
+/* The special cases for the revision property: */
+#define REV_11MPCORE 0
+#define REV_NVIC 0xffffffff
+
+void gic_set_pending_private(GICState *s, int cpu, int irq);
+uint32_t gic_acknowledge_irq(GICState *s, int cpu);
+void gic_complete_irq(GICState *s, int cpu, int irq);
+void gic_update(GICState *s);
+void gic_init_irqs_and_distributor(GICState *s, int num_irq);
+
+#define TYPE_ARM_GIC_COMMON "arm_gic_common"
+#define ARM_GIC_COMMON(obj) \
+     OBJECT_CHECK(GICState, (obj), TYPE_ARM_GIC_COMMON)
+#define ARM_GIC_COMMON_CLASS(klass) \
+     OBJECT_CLASS_CHECK(ARMGICCommonClass, (klass), TYPE_ARM_GIC_COMMON)
+#define ARM_GIC_COMMON_GET_CLASS(obj) \
+     OBJECT_GET_CLASS(ARMGICCommonClass, (obj), TYPE_ARM_GIC_COMMON)
+
+typedef struct ARMGICCommonClass {
+    SysBusDeviceClass parent_class;
+    void (*pre_save)(GICState *s);
+    void (*post_load)(GICState *s);
+} ARMGICCommonClass;
+
+#define TYPE_ARM_GIC "arm_gic"
+#define ARM_GIC(obj) \
+     OBJECT_CHECK(GICState, (obj), TYPE_ARM_GIC)
+#define ARM_GIC_CLASS(klass) \
+     OBJECT_CLASS_CHECK(ARMGICClass, (klass), TYPE_ARM_GIC)
+#define ARM_GIC_GET_CLASS(obj) \
+     OBJECT_GET_CLASS(ARMGICClass, (obj), TYPE_ARM_GIC)
+
+typedef struct ARMGICClass {
+    ARMGICCommonClass parent_class;
+    DeviceRealize parent_realize;
+} ARMGICClass;
+
+#endif /* !QEMU_ARM_GIC_INTERNAL_H */
diff --git a/hw/intc/grlib_irqmp.c b/hw/intc/grlib_irqmp.c
new file mode 100644 (file)
index 0000000..68dfe6a
--- /dev/null
@@ -0,0 +1,385 @@
+/*
+ * QEMU GRLIB IRQMP Emulator
+ *
+ * (Multiprocessor and extended interrupt not supported)
+ *
+ * Copyright (c) 2010-2011 AdaCore
+ *
+ * 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 "hw/sysbus.h"
+#include "cpu.h"
+
+#include "hw/sparc/grlib.h"
+
+#include "trace.h"
+
+#define IRQMP_MAX_CPU 16
+#define IRQMP_REG_SIZE 256      /* Size of memory mapped registers */
+
+/* Memory mapped register offsets */
+#define LEVEL_OFFSET     0x00
+#define PENDING_OFFSET   0x04
+#define FORCE0_OFFSET    0x08
+#define CLEAR_OFFSET     0x0C
+#define MP_STATUS_OFFSET 0x10
+#define BROADCAST_OFFSET 0x14
+#define MASK_OFFSET      0x40
+#define FORCE_OFFSET     0x80
+#define EXTENDED_OFFSET  0xC0
+
+typedef struct IRQMPState IRQMPState;
+
+typedef struct IRQMP {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+
+    void *set_pil_in;
+    void *set_pil_in_opaque;
+
+    IRQMPState *state;
+} IRQMP;
+
+struct IRQMPState {
+    uint32_t level;
+    uint32_t pending;
+    uint32_t clear;
+    uint32_t broadcast;
+
+    uint32_t mask[IRQMP_MAX_CPU];
+    uint32_t force[IRQMP_MAX_CPU];
+    uint32_t extended[IRQMP_MAX_CPU];
+
+    IRQMP    *parent;
+};
+
+static void grlib_irqmp_check_irqs(IRQMPState *state)
+{
+    uint32_t      pend   = 0;
+    uint32_t      level0 = 0;
+    uint32_t      level1 = 0;
+    set_pil_in_fn set_pil_in;
+
+    assert(state != NULL);
+    assert(state->parent != NULL);
+
+    /* IRQ for CPU 0 (no SMP support) */
+    pend = (state->pending | state->force[0])
+        & state->mask[0];
+
+    level0 = pend & ~state->level;
+    level1 = pend &  state->level;
+
+    trace_grlib_irqmp_check_irqs(state->pending, state->force[0],
+                                 state->mask[0], level1, level0);
+
+    set_pil_in = (set_pil_in_fn)state->parent->set_pil_in;
+
+    /* Trigger level1 interrupt first and level0 if there is no level1 */
+    if (level1 != 0) {
+        set_pil_in(state->parent->set_pil_in_opaque, level1);
+    } else {
+        set_pil_in(state->parent->set_pil_in_opaque, level0);
+    }
+}
+
+void grlib_irqmp_ack(DeviceState *dev, int intno)
+{
+    SysBusDevice *sdev;
+    IRQMP        *irqmp;
+    IRQMPState   *state;
+    uint32_t      mask;
+
+    assert(dev != NULL);
+
+    sdev = SYS_BUS_DEVICE(dev);
+    assert(sdev != NULL);
+
+    irqmp = FROM_SYSBUS(typeof(*irqmp), sdev);
+    assert(irqmp != NULL);
+
+    state = irqmp->state;
+    assert(state != NULL);
+
+    intno &= 15;
+    mask = 1 << intno;
+
+    trace_grlib_irqmp_ack(intno);
+
+    /* Clear registers */
+    state->pending  &= ~mask;
+    state->force[0] &= ~mask; /* Only CPU 0 (No SMP support) */
+
+    grlib_irqmp_check_irqs(state);
+}
+
+void grlib_irqmp_set_irq(void *opaque, int irq, int level)
+{
+    IRQMP      *irqmp;
+    IRQMPState *s;
+    int         i = 0;
+
+    assert(opaque != NULL);
+
+    irqmp = FROM_SYSBUS(typeof(*irqmp), SYS_BUS_DEVICE(opaque));
+    assert(irqmp != NULL);
+
+    s = irqmp->state;
+    assert(s         != NULL);
+    assert(s->parent != NULL);
+
+
+    if (level) {
+        trace_grlib_irqmp_set_irq(irq);
+
+        if (s->broadcast & 1 << irq) {
+            /* Broadcasted IRQ */
+            for (i = 0; i < IRQMP_MAX_CPU; i++) {
+                s->force[i] |= 1 << irq;
+            }
+        } else {
+            s->pending |= 1 << irq;
+        }
+        grlib_irqmp_check_irqs(s);
+
+    }
+}
+
+static uint64_t grlib_irqmp_read(void *opaque, hwaddr addr,
+                                 unsigned size)
+{
+    IRQMP      *irqmp = opaque;
+    IRQMPState *state;
+
+    assert(irqmp != NULL);
+    state = irqmp->state;
+    assert(state != NULL);
+
+    addr &= 0xff;
+
+    /* global registers */
+    switch (addr) {
+    case LEVEL_OFFSET:
+        return state->level;
+
+    case PENDING_OFFSET:
+        return state->pending;
+
+    case FORCE0_OFFSET:
+        /* This register is an "alias" for the force register of CPU 0 */
+        return state->force[0];
+
+    case CLEAR_OFFSET:
+    case MP_STATUS_OFFSET:
+        /* Always read as 0 */
+        return 0;
+
+    case BROADCAST_OFFSET:
+        return state->broadcast;
+
+    default:
+        break;
+    }
+
+    /* mask registers */
+    if (addr >= MASK_OFFSET && addr < FORCE_OFFSET) {
+        int cpu = (addr - MASK_OFFSET) / 4;
+        assert(cpu >= 0 && cpu < IRQMP_MAX_CPU);
+
+        return state->mask[cpu];
+    }
+
+    /* force registers */
+    if (addr >= FORCE_OFFSET && addr < EXTENDED_OFFSET) {
+        int cpu = (addr - FORCE_OFFSET) / 4;
+        assert(cpu >= 0 && cpu < IRQMP_MAX_CPU);
+
+        return state->force[cpu];
+    }
+
+    /* extended (not supported) */
+    if (addr >= EXTENDED_OFFSET && addr < IRQMP_REG_SIZE) {
+        int cpu = (addr - EXTENDED_OFFSET) / 4;
+        assert(cpu >= 0 && cpu < IRQMP_MAX_CPU);
+
+        return state->extended[cpu];
+    }
+
+    trace_grlib_irqmp_readl_unknown(addr);
+    return 0;
+}
+
+static void grlib_irqmp_write(void *opaque, hwaddr addr,
+                              uint64_t value, unsigned size)
+{
+    IRQMP      *irqmp = opaque;
+    IRQMPState *state;
+
+    assert(irqmp != NULL);
+    state = irqmp->state;
+    assert(state != NULL);
+
+    addr &= 0xff;
+
+    /* global registers */
+    switch (addr) {
+    case LEVEL_OFFSET:
+        value &= 0xFFFF << 1; /* clean up the value */
+        state->level = value;
+        return;
+
+    case PENDING_OFFSET:
+        /* Read Only */
+        return;
+
+    case FORCE0_OFFSET:
+        /* This register is an "alias" for the force register of CPU 0 */
+
+        value &= 0xFFFE; /* clean up the value */
+        state->force[0] = value;
+        grlib_irqmp_check_irqs(irqmp->state);
+        return;
+
+    case CLEAR_OFFSET:
+        value &= ~1; /* clean up the value */
+        state->pending &= ~value;
+        return;
+
+    case MP_STATUS_OFFSET:
+        /* Read Only (no SMP support) */
+        return;
+
+    case BROADCAST_OFFSET:
+        value &= 0xFFFE; /* clean up the value */
+        state->broadcast = value;
+        return;
+
+    default:
+        break;
+    }
+
+    /* mask registers */
+    if (addr >= MASK_OFFSET && addr < FORCE_OFFSET) {
+        int cpu = (addr - MASK_OFFSET) / 4;
+        assert(cpu >= 0 && cpu < IRQMP_MAX_CPU);
+
+        value &= ~1; /* clean up the value */
+        state->mask[cpu] = value;
+        grlib_irqmp_check_irqs(irqmp->state);
+        return;
+    }
+
+    /* force registers */
+    if (addr >= FORCE_OFFSET && addr < EXTENDED_OFFSET) {
+        int cpu = (addr - FORCE_OFFSET) / 4;
+        assert(cpu >= 0 && cpu < IRQMP_MAX_CPU);
+
+        uint32_t force = value & 0xFFFE;
+        uint32_t clear = (value >> 16) & 0xFFFE;
+        uint32_t old   = state->force[cpu];
+
+        state->force[cpu] = (old | force) & ~clear;
+        grlib_irqmp_check_irqs(irqmp->state);
+        return;
+    }
+
+    /* extended (not supported) */
+    if (addr >= EXTENDED_OFFSET && addr < IRQMP_REG_SIZE) {
+        int cpu = (addr - EXTENDED_OFFSET) / 4;
+        assert(cpu >= 0 && cpu < IRQMP_MAX_CPU);
+
+        value &= 0xF; /* clean up the value */
+        state->extended[cpu] = value;
+        return;
+    }
+
+    trace_grlib_irqmp_writel_unknown(addr, value);
+}
+
+static const MemoryRegionOps grlib_irqmp_ops = {
+    .read = grlib_irqmp_read,
+    .write = grlib_irqmp_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static void grlib_irqmp_reset(DeviceState *d)
+{
+    IRQMP *irqmp = container_of(d, IRQMP, busdev.qdev);
+    assert(irqmp        != NULL);
+    assert(irqmp->state != NULL);
+
+    memset(irqmp->state, 0, sizeof *irqmp->state);
+    irqmp->state->parent = irqmp;
+}
+
+static int grlib_irqmp_init(SysBusDevice *dev)
+{
+    IRQMP *irqmp = FROM_SYSBUS(typeof(*irqmp), dev);
+
+    assert(irqmp != NULL);
+
+    /* Check parameters */
+    if (irqmp->set_pil_in == NULL) {
+        return -1;
+    }
+
+    memory_region_init_io(&irqmp->iomem, &grlib_irqmp_ops, irqmp,
+                          "irqmp", IRQMP_REG_SIZE);
+
+    irqmp->state = g_malloc0(sizeof *irqmp->state);
+
+    sysbus_init_mmio(dev, &irqmp->iomem);
+
+    return 0;
+}
+
+static Property grlib_irqmp_properties[] = {
+    DEFINE_PROP_PTR("set_pil_in", IRQMP, set_pil_in),
+    DEFINE_PROP_PTR("set_pil_in_opaque", IRQMP, set_pil_in_opaque),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void grlib_irqmp_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = grlib_irqmp_init;
+    dc->reset = grlib_irqmp_reset;
+    dc->props = grlib_irqmp_properties;
+}
+
+static const 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_types(void)
+{
+    type_register_static(&grlib_irqmp_info);
+}
+
+type_init(grlib_irqmp_register_types)
diff --git a/hw/intc/heathrow_pic.c b/hw/intc/heathrow_pic.c
new file mode 100644 (file)
index 0000000..beb9661
--- /dev/null
@@ -0,0 +1,215 @@
+/*
+ * Heathrow PIC support (OldWorld PowerMac)
+ *
+ * Copyright (c) 2005-2007 Fabrice Bellard
+ * Copyright (c) 2007 Jocelyn Mayer
+ *
+ * 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 "hw/hw.h"
+#include "hw/ppc/mac.h"
+
+/* debug PIC */
+//#define DEBUG_PIC
+
+#ifdef DEBUG_PIC
+#define PIC_DPRINTF(fmt, ...)                                   \
+    do { printf("PIC: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define PIC_DPRINTF(fmt, ...)
+#endif
+
+typedef struct HeathrowPIC {
+    uint32_t events;
+    uint32_t mask;
+    uint32_t levels;
+    uint32_t level_triggered;
+} HeathrowPIC;
+
+typedef struct HeathrowPICS {
+    MemoryRegion mem;
+    HeathrowPIC pics[2];
+    qemu_irq *irqs;
+} HeathrowPICS;
+
+static inline int check_irq(HeathrowPIC *pic)
+{
+    return (pic->events | (pic->levels & pic->level_triggered)) & pic->mask;
+}
+
+/* update the CPU irq state */
+static void heathrow_pic_update(HeathrowPICS *s)
+{
+    if (check_irq(&s->pics[0]) || check_irq(&s->pics[1])) {
+        qemu_irq_raise(s->irqs[0]);
+    } else {
+        qemu_irq_lower(s->irqs[0]);
+    }
+}
+
+static void pic_write(void *opaque, hwaddr addr,
+                      uint64_t value, unsigned size)
+{
+    HeathrowPICS *s = opaque;
+    HeathrowPIC *pic;
+    unsigned int n;
+
+    n = ((addr & 0xfff) - 0x10) >> 4;
+    PIC_DPRINTF("writel: " TARGET_FMT_plx " %u: %08x\n", addr, n, value);
+    if (n >= 2)
+        return;
+    pic = &s->pics[n];
+    switch(addr & 0xf) {
+    case 0x04:
+        pic->mask = value;
+        heathrow_pic_update(s);
+        break;
+    case 0x08:
+        /* do not reset level triggered IRQs */
+        value &= ~pic->level_triggered;
+        pic->events &= ~value;
+        heathrow_pic_update(s);
+        break;
+    default:
+        break;
+    }
+}
+
+static uint64_t pic_read(void *opaque, hwaddr addr,
+                         unsigned size)
+{
+    HeathrowPICS *s = opaque;
+    HeathrowPIC *pic;
+    unsigned int n;
+    uint32_t value;
+
+    n = ((addr & 0xfff) - 0x10) >> 4;
+    if (n >= 2) {
+        value = 0;
+    } else {
+        pic = &s->pics[n];
+        switch(addr & 0xf) {
+        case 0x0:
+            value = pic->events;
+            break;
+        case 0x4:
+            value = pic->mask;
+            break;
+        case 0xc:
+            value = pic->levels;
+            break;
+        default:
+            value = 0;
+            break;
+        }
+    }
+    PIC_DPRINTF("readl: " TARGET_FMT_plx " %u: %08x\n", addr, n, value);
+    return value;
+}
+
+static const MemoryRegionOps heathrow_pic_ops = {
+    .read = pic_read,
+    .write = pic_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void heathrow_pic_set_irq(void *opaque, int num, int level)
+{
+    HeathrowPICS *s = opaque;
+    HeathrowPIC *pic;
+    unsigned int irq_bit;
+
+#if defined(DEBUG)
+    {
+        static int last_level[64];
+        if (last_level[num] != level) {
+            PIC_DPRINTF("set_irq: num=0x%02x level=%d\n", num, level);
+            last_level[num] = level;
+        }
+    }
+#endif
+    pic = &s->pics[1 - (num >> 5)];
+    irq_bit = 1 << (num & 0x1f);
+    if (level) {
+        pic->events |= irq_bit & ~pic->level_triggered;
+        pic->levels |= irq_bit;
+    } else {
+        pic->levels &= ~irq_bit;
+    }
+    heathrow_pic_update(s);
+}
+
+static const VMStateDescription vmstate_heathrow_pic_one = {
+    .name = "heathrow_pic_one",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32(events, HeathrowPIC),
+        VMSTATE_UINT32(mask, HeathrowPIC),
+        VMSTATE_UINT32(levels, HeathrowPIC),
+        VMSTATE_UINT32(level_triggered, HeathrowPIC),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_heathrow_pic = {
+    .name = "heathrow_pic",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_STRUCT_ARRAY(pics, HeathrowPICS, 2, 1,
+                             vmstate_heathrow_pic_one, HeathrowPIC),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void heathrow_pic_reset_one(HeathrowPIC *s)
+{
+    memset(s, '\0', sizeof(HeathrowPIC));
+}
+
+static void heathrow_pic_reset(void *opaque)
+{
+    HeathrowPICS *s = opaque;
+
+    heathrow_pic_reset_one(&s->pics[0]);
+    heathrow_pic_reset_one(&s->pics[1]);
+
+    s->pics[0].level_triggered = 0;
+    s->pics[1].level_triggered = 0x1ff00000;
+}
+
+qemu_irq *heathrow_pic_init(MemoryRegion **pmem,
+                            int nb_cpus, qemu_irq **irqs)
+{
+    HeathrowPICS *s;
+
+    s = g_malloc0(sizeof(HeathrowPICS));
+    /* only 1 CPU */
+    s->irqs = irqs[0];
+    memory_region_init_io(&s->mem, &heathrow_pic_ops, s,
+                          "heathrow-pic", 0x1000);
+    *pmem = &s->mem;
+
+    vmstate_register(NULL, -1, &vmstate_heathrow_pic, s);
+    qemu_register_reset(heathrow_pic_reset, s);
+    return qemu_allocate_irqs(heathrow_pic_set_irq, s, 64);
+}
diff --git a/hw/intc/i8259.c b/hw/intc/i8259.c
new file mode 100644 (file)
index 0000000..ce14bd0
--- /dev/null
@@ -0,0 +1,496 @@
+/*
+ * QEMU 8259 interrupt controller 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.
+ */
+#include "hw/hw.h"
+#include "hw/i386/pc.h"
+#include "hw/isa/isa.h"
+#include "monitor/monitor.h"
+#include "qemu/timer.h"
+#include "hw/isa/i8259_internal.h"
+
+/* debug PIC */
+//#define DEBUG_PIC
+
+#ifdef DEBUG_PIC
+#define DPRINTF(fmt, ...)                                       \
+    do { printf("pic: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...)
+#endif
+
+//#define DEBUG_IRQ_LATENCY
+//#define DEBUG_IRQ_COUNT
+
+#if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT)
+static int irq_level[16];
+#endif
+#ifdef DEBUG_IRQ_COUNT
+static uint64_t irq_count[16];
+#endif
+#ifdef DEBUG_IRQ_LATENCY
+static int64_t irq_time[16];
+#endif
+DeviceState *isa_pic;
+static PICCommonState *slave_pic;
+
+/* return the highest priority found in mask (highest = smallest
+   number). Return 8 if no irq */
+static int get_priority(PICCommonState *s, int mask)
+{
+    int priority;
+
+    if (mask == 0) {
+        return 8;
+    }
+    priority = 0;
+    while ((mask & (1 << ((priority + s->priority_add) & 7))) == 0) {
+        priority++;
+    }
+    return priority;
+}
+
+/* return the pic wanted interrupt. return -1 if none */
+static int pic_get_irq(PICCommonState *s)
+{
+    int mask, cur_priority, priority;
+
+    mask = s->irr & ~s->imr;
+    priority = get_priority(s, mask);
+    if (priority == 8) {
+        return -1;
+    }
+    /* compute current priority. If special fully nested mode on the
+       master, the IRQ coming from the slave is not taken into account
+       for the priority computation. */
+    mask = s->isr;
+    if (s->special_mask) {
+        mask &= ~s->imr;
+    }
+    if (s->special_fully_nested_mode && s->master) {
+        mask &= ~(1 << 2);
+    }
+    cur_priority = get_priority(s, mask);
+    if (priority < cur_priority) {
+        /* higher priority found: an irq should be generated */
+        return (priority + s->priority_add) & 7;
+    } else {
+        return -1;
+    }
+}
+
+/* Update INT output. Must be called every time the output may have changed. */
+static void pic_update_irq(PICCommonState *s)
+{
+    int irq;
+
+    irq = pic_get_irq(s);
+    if (irq >= 0) {
+        DPRINTF("pic%d: imr=%x irr=%x padd=%d\n",
+                s->master ? 0 : 1, s->imr, s->irr, s->priority_add);
+        qemu_irq_raise(s->int_out[0]);
+    } else {
+        qemu_irq_lower(s->int_out[0]);
+    }
+}
+
+/* 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)
+{
+    PICCommonState *s = opaque;
+    int mask = 1 << irq;
+
+#if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT) || \
+    defined(DEBUG_IRQ_LATENCY)
+    int irq_index = s->master ? irq : irq + 8;
+#endif
+#if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT)
+    if (level != irq_level[irq_index]) {
+        DPRINTF("pic_set_irq: irq=%d level=%d\n", irq_index, level);
+        irq_level[irq_index] = level;
+#ifdef DEBUG_IRQ_COUNT
+        if (level == 1) {
+            irq_count[irq_index]++;
+        }
+#endif
+    }
+#endif
+#ifdef DEBUG_IRQ_LATENCY
+    if (level) {
+        irq_time[irq_index] = qemu_get_clock_ns(vm_clock);
+    }
+#endif
+
+    if (s->elcr & mask) {
+        /* level triggered */
+        if (level) {
+            s->irr |= mask;
+            s->last_irr |= mask;
+        } else {
+            s->irr &= ~mask;
+            s->last_irr &= ~mask;
+        }
+    } else {
+        /* edge triggered */
+        if (level) {
+            if ((s->last_irr & mask) == 0) {
+                s->irr |= mask;
+            }
+            s->last_irr |= mask;
+        } else {
+            s->last_irr &= ~mask;
+        }
+    }
+    pic_update_irq(s);
+}
+
+/* acknowledge interrupt 'irq' */
+static void pic_intack(PICCommonState *s, int irq)
+{
+    if (s->auto_eoi) {
+        if (s->rotate_on_auto_eoi) {
+            s->priority_add = (irq + 1) & 7;
+        }
+    } else {
+        s->isr |= (1 << irq);
+    }
+    /* We don't clear a level sensitive interrupt here */
+    if (!(s->elcr & (1 << irq))) {
+        s->irr &= ~(1 << irq);
+    }
+    pic_update_irq(s);
+}
+
+int pic_read_irq(DeviceState *d)
+{
+    PICCommonState *s = DO_UPCAST(PICCommonState, dev.qdev, d);
+    int irq, irq2, intno;
+
+    irq = pic_get_irq(s);
+    if (irq >= 0) {
+        if (irq == 2) {
+            irq2 = pic_get_irq(slave_pic);
+            if (irq2 >= 0) {
+                pic_intack(slave_pic, irq2);
+            } else {
+                /* spurious IRQ on slave controller */
+                irq2 = 7;
+            }
+            intno = slave_pic->irq_base + irq2;
+        } else {
+            intno = s->irq_base + irq;
+        }
+        pic_intack(s, irq);
+    } else {
+        /* spurious IRQ on host controller */
+        irq = 7;
+        intno = s->irq_base + irq;
+    }
+
+#if defined(DEBUG_PIC) || defined(DEBUG_IRQ_LATENCY)
+    if (irq == 2) {
+        irq = irq2 + 8;
+    }
+#endif
+#ifdef DEBUG_IRQ_LATENCY
+    printf("IRQ%d latency=%0.3fus\n",
+           irq,
+           (double)(qemu_get_clock_ns(vm_clock) -
+                    irq_time[irq]) * 1000000.0 / get_ticks_per_sec());
+#endif
+    DPRINTF("pic_interrupt: irq=%d\n", irq);
+    return intno;
+}
+
+static void pic_init_reset(PICCommonState *s)
+{
+    pic_reset_common(s);
+    pic_update_irq(s);
+}
+
+static void pic_reset(DeviceState *dev)
+{
+    PICCommonState *s = DO_UPCAST(PICCommonState, dev.qdev, dev);
+
+    s->elcr = 0;
+    pic_init_reset(s);
+}
+
+static void pic_ioport_write(void *opaque, hwaddr addr64,
+                             uint64_t val64, unsigned size)
+{
+    PICCommonState *s = opaque;
+    uint32_t addr = addr64;
+    uint32_t val = val64;
+    int priority, cmd, irq;
+
+    DPRINTF("write: addr=0x%02x val=0x%02x\n", addr, val);
+    if (addr == 0) {
+        if (val & 0x10) {
+            pic_init_reset(s);
+            s->init_state = 1;
+            s->init4 = val & 1;
+            s->single_mode = val & 2;
+            if (val & 0x08) {
+                hw_error("level sensitive irq not supported");
+            }
+        } else if (val & 0x08) {
+            if (val & 0x04) {
+                s->poll = 1;
+            }
+            if (val & 0x02) {
+                s->read_reg_select = val & 1;
+            }
+            if (val & 0x40) {
+                s->special_mask = (val >> 5) & 1;
+            }
+        } else {
+            cmd = val >> 5;
+            switch (cmd) {
+            case 0:
+            case 4:
+                s->rotate_on_auto_eoi = cmd >> 2;
+                break;
+            case 1: /* end of interrupt */
+            case 5:
+                priority = get_priority(s, s->isr);
+                if (priority != 8) {
+                    irq = (priority + s->priority_add) & 7;
+                    s->isr &= ~(1 << irq);
+                    if (cmd == 5) {
+                        s->priority_add = (irq + 1) & 7;
+                    }
+                    pic_update_irq(s);
+                }
+                break;
+            case 3:
+                irq = val & 7;
+                s->isr &= ~(1 << irq);
+                pic_update_irq(s);
+                break;
+            case 6:
+                s->priority_add = (val + 1) & 7;
+                pic_update_irq(s);
+                break;
+            case 7:
+                irq = val & 7;
+                s->isr &= ~(1 << irq);
+                s->priority_add = (irq + 1) & 7;
+                pic_update_irq(s);
+                break;
+            default:
+                /* no operation */
+                break;
+            }
+        }
+    } else {
+        switch (s->init_state) {
+        case 0:
+            /* normal mode */
+            s->imr = val;
+            pic_update_irq(s);
+            break;
+        case 1:
+            s->irq_base = val & 0xf8;
+            s->init_state = s->single_mode ? (s->init4 ? 3 : 0) : 2;
+            break;
+        case 2:
+            if (s->init4) {
+                s->init_state = 3;
+            } else {
+                s->init_state = 0;
+            }
+            break;
+        case 3:
+            s->special_fully_nested_mode = (val >> 4) & 1;
+            s->auto_eoi = (val >> 1) & 1;
+            s->init_state = 0;
+            break;
+        }
+    }
+}
+
+static uint64_t pic_ioport_read(void *opaque, hwaddr addr,
+                                unsigned size)
+{
+    PICCommonState *s = opaque;
+    int ret;
+
+    if (s->poll) {
+        ret = pic_get_irq(s);
+        if (ret >= 0) {
+            pic_intack(s, ret);
+            ret |= 0x80;
+        } else {
+            ret = 0;
+        }
+        s->poll = 0;
+    } else {
+        if (addr == 0) {
+            if (s->read_reg_select) {
+                ret = s->isr;
+            } else {
+                ret = s->irr;
+            }
+        } else {
+            ret = s->imr;
+        }
+    }
+    DPRINTF("read: addr=0x%02x val=0x%02x\n", addr, ret);
+    return ret;
+}
+
+int pic_get_output(DeviceState *d)
+{
+    PICCommonState *s = DO_UPCAST(PICCommonState, dev.qdev, d);
+
+    return (pic_get_irq(s) >= 0);
+}
+
+static void elcr_ioport_write(void *opaque, hwaddr addr,
+                              uint64_t val, unsigned size)
+{
+    PICCommonState *s = opaque;
+    s->elcr = val & s->elcr_mask;
+}
+
+static uint64_t elcr_ioport_read(void *opaque, hwaddr addr,
+                                 unsigned size)
+{
+    PICCommonState *s = opaque;
+    return s->elcr;
+}
+
+static const MemoryRegionOps pic_base_ioport_ops = {
+    .read = pic_ioport_read,
+    .write = pic_ioport_write,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+};
+
+static const MemoryRegionOps pic_elcr_ioport_ops = {
+    .read = elcr_ioport_read,
+    .write = elcr_ioport_write,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+};
+
+static void pic_init(PICCommonState *s)
+{
+    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);
+
+    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, const QDict *qdict)
+{
+    int i;
+    PICCommonState *s;
+
+    if (!isa_pic) {
+        return;
+    }
+    for (i = 0; i < 2; i++) {
+        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,
+                       s->irq_base, s->read_reg_select, s->elcr,
+                       s->special_fully_nested_mode);
+    }
+}
+
+void irq_info(Monitor *mon, const QDict *qdict)
+{
+#ifndef DEBUG_IRQ_COUNT
+    monitor_printf(mon, "irq statistic code not compiled.\n");
+#else
+    int i;
+    int64_t count;
+
+    monitor_printf(mon, "IRQ statistics:\n");
+    for (i = 0; i < 16; i++) {
+        count = irq_count[i];
+        if (count > 0) {
+            monitor_printf(mon, "%2d: %" PRId64 "\n", i, count);
+        }
+    }
+#endif
+}
+
+qemu_irq *i8259_init(ISABus *bus, qemu_irq parent_irq)
+{
+    qemu_irq *irq_set;
+    ISADevice *dev;
+    int i;
+
+    irq_set = g_malloc(ISA_NUM_IRQS * sizeof(qemu_irq));
+
+    dev = i8259_init_chip("isa-i8259", bus, true);
+
+    qdev_connect_gpio_out(&dev->qdev, 0, parent_irq);
+    for (i = 0 ; i < 8; i++) {
+        irq_set[i] = qdev_get_gpio_in(&dev->qdev, i);
+    }
+
+    isa_pic = &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(PICCommonState, dev, dev);
+
+    return irq_set;
+}
+
+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 const TypeInfo i8259_info = {
+    .name       = "isa-i8259",
+    .instance_size = sizeof(PICCommonState),
+    .parent     = TYPE_PIC_COMMON,
+    .class_init = i8259_class_init,
+};
+
+static void pic_register_types(void)
+{
+    type_register_static(&i8259_info);
+}
+
+type_init(pic_register_types)
diff --git a/hw/intc/i8259_common.c b/hw/intc/i8259_common.c
new file mode 100644 (file)
index 0000000..996ba9d
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ * QEMU 8259 - common bits of emulated and KVM kernel model
+ *
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ * Copyright (c) 2011      Jan Kiszka, Siemens AG
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "hw/i386/pc.h"
+#include "hw/isa/i8259_internal.h"
+
+void pic_reset_common(PICCommonState *s)
+{
+    s->last_irr = 0;
+    s->irr &= s->elcr;
+    s->imr = 0;
+    s->isr = 0;
+    s->priority_add = 0;
+    s->irq_base = 0;
+    s->read_reg_select = 0;
+    s->poll = 0;
+    s->special_mask = 0;
+    s->init_state = 0;
+    s->auto_eoi = 0;
+    s->rotate_on_auto_eoi = 0;
+    s->special_fully_nested_mode = 0;
+    s->init4 = 0;
+    s->single_mode = 0;
+    /* Note: ELCR is not reset */
+}
+
+static void pic_dispatch_pre_save(void *opaque)
+{
+    PICCommonState *s = opaque;
+    PICCommonClass *info = PIC_COMMON_GET_CLASS(s);
+
+    if (info->pre_save) {
+        info->pre_save(s);
+    }
+}
+
+static int pic_dispatch_post_load(void *opaque, int version_id)
+{
+    PICCommonState *s = opaque;
+    PICCommonClass *info = PIC_COMMON_GET_CLASS(s);
+
+    if (info->post_load) {
+        info->post_load(s);
+    }
+    return 0;
+}
+
+static int pic_init_common(ISADevice *dev)
+{
+    PICCommonState *s = DO_UPCAST(PICCommonState, dev, dev);
+    PICCommonClass *info = PIC_COMMON_GET_CLASS(s);
+
+    info->init(s);
+
+    isa_register_ioport(NULL, &s->base_io, s->iobase);
+    if (s->elcr_addr != -1) {
+        isa_register_ioport(NULL, &s->elcr_io, s->elcr_addr);
+    }
+
+    qdev_set_legacy_instance_id(&s->dev.qdev, s->iobase, 1);
+
+    return 0;
+}
+
+ISADevice *i8259_init_chip(const char *name, ISABus *bus, bool master)
+{
+    ISADevice *dev;
+
+    dev = isa_create(bus, name);
+    qdev_prop_set_uint32(&dev->qdev, "iobase", master ? 0x20 : 0xa0);
+    qdev_prop_set_uint32(&dev->qdev, "elcr_addr", master ? 0x4d0 : 0x4d1);
+    qdev_prop_set_uint8(&dev->qdev, "elcr_mask", master ? 0xf8 : 0xde);
+    qdev_prop_set_bit(&dev->qdev, "master", master);
+    qdev_init_nofail(&dev->qdev);
+
+    return dev;
+}
+
+static const VMStateDescription vmstate_pic_common = {
+    .name = "i8259",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .pre_save = pic_dispatch_pre_save,
+    .post_load = pic_dispatch_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT8(last_irr, PICCommonState),
+        VMSTATE_UINT8(irr, PICCommonState),
+        VMSTATE_UINT8(imr, PICCommonState),
+        VMSTATE_UINT8(isr, PICCommonState),
+        VMSTATE_UINT8(priority_add, PICCommonState),
+        VMSTATE_UINT8(irq_base, PICCommonState),
+        VMSTATE_UINT8(read_reg_select, PICCommonState),
+        VMSTATE_UINT8(poll, PICCommonState),
+        VMSTATE_UINT8(special_mask, PICCommonState),
+        VMSTATE_UINT8(init_state, PICCommonState),
+        VMSTATE_UINT8(auto_eoi, PICCommonState),
+        VMSTATE_UINT8(rotate_on_auto_eoi, PICCommonState),
+        VMSTATE_UINT8(special_fully_nested_mode, PICCommonState),
+        VMSTATE_UINT8(init4, PICCommonState),
+        VMSTATE_UINT8(single_mode, PICCommonState),
+        VMSTATE_UINT8(elcr, PICCommonState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static Property pic_properties_common[] = {
+    DEFINE_PROP_HEX32("iobase", PICCommonState, iobase,  -1),
+    DEFINE_PROP_HEX32("elcr_addr", PICCommonState, elcr_addr,  -1),
+    DEFINE_PROP_HEX8("elcr_mask", PICCommonState, elcr_mask,  -1),
+    DEFINE_PROP_BIT("master", PICCommonState, master,  0, false),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void pic_common_class_init(ObjectClass *klass, void *data)
+{
+    ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->vmsd = &vmstate_pic_common;
+    dc->no_user = 1;
+    dc->props = pic_properties_common;
+    ic->init = pic_init_common;
+}
+
+static const 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_types(void)
+{
+    type_register_static(&pic_common_type);
+}
+
+type_init(register_types);
diff --git a/hw/intc/imx_avic.c b/hw/intc/imx_avic.c
new file mode 100644 (file)
index 0000000..4e280b6
--- /dev/null
@@ -0,0 +1,408 @@
+/*
+ * i.MX31 Vectored Interrupt Controller
+ *
+ * Note this is NOT the PL192 provided by ARM, but
+ * a custom implementation by Freescale.
+ *
+ * Copyright (c) 2008 OKL
+ * Copyright (c) 2011 NICTA Pty Ltd
+ * Originally written by Hans Jiang
+ *
+ * This code is licensed under the GPL version 2 or later.  See
+ * the COPYING file in the top-level directory.
+ *
+ * TODO: implement vectors.
+ */
+
+#include "hw/hw.h"
+#include "hw/sysbus.h"
+#include "qemu/host-utils.h"
+
+#define DEBUG_INT 1
+#undef DEBUG_INT /* comment out for debugging */
+
+#ifdef DEBUG_INT
+#define DPRINTF(fmt, args...) \
+do { printf("imx_avic: " fmt , ##args); } while (0)
+#else
+#define DPRINTF(fmt, args...) do {} while (0)
+#endif
+
+/*
+ * Define to 1 for messages about attempts to
+ * access unimplemented registers or similar.
+ */
+#define DEBUG_IMPLEMENTATION 1
+#if DEBUG_IMPLEMENTATION
+#  define IPRINTF(fmt, args...) \
+    do  { fprintf(stderr, "imx_avic: " fmt, ##args); } while (0)
+#else
+#  define IPRINTF(fmt, args...) do {} while (0)
+#endif
+
+#define IMX_AVIC_NUM_IRQS 64
+
+/* Interrupt Control Bits */
+#define ABFLAG (1<<25)
+#define ABFEN (1<<24)
+#define NIDIS (1<<22) /* Normal Interrupt disable */
+#define FIDIS (1<<21) /* Fast interrupt disable */
+#define NIAD  (1<<20) /* Normal Interrupt Arbiter Rise ARM level */
+#define FIAD  (1<<19) /* Fast Interrupt Arbiter Rise ARM level */
+#define NM    (1<<18) /* Normal interrupt mode */
+
+
+#define PRIO_PER_WORD (sizeof(uint32_t) * 8 / 4)
+#define PRIO_WORDS (IMX_AVIC_NUM_IRQS/PRIO_PER_WORD)
+
+typedef struct {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    uint64_t pending;
+    uint64_t enabled;
+    uint64_t is_fiq;
+    uint32_t intcntl;
+    uint32_t intmask;
+    qemu_irq irq;
+    qemu_irq fiq;
+    uint32_t prio[PRIO_WORDS]; /* Priorities are 4-bits each */
+} IMXAVICState;
+
+static const VMStateDescription vmstate_imx_avic = {
+    .name = "imx-avic",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT64(pending, IMXAVICState),
+        VMSTATE_UINT64(enabled, IMXAVICState),
+        VMSTATE_UINT64(is_fiq, IMXAVICState),
+        VMSTATE_UINT32(intcntl, IMXAVICState),
+        VMSTATE_UINT32(intmask, IMXAVICState),
+        VMSTATE_UINT32_ARRAY(prio, IMXAVICState, PRIO_WORDS),
+        VMSTATE_END_OF_LIST()
+    },
+};
+
+
+
+static inline int imx_avic_prio(IMXAVICState *s, int irq)
+{
+    uint32_t word = irq / PRIO_PER_WORD;
+    uint32_t part = 4 * (irq % PRIO_PER_WORD);
+    return 0xf & (s->prio[word] >> part);
+}
+
+static inline void imx_avic_set_prio(IMXAVICState *s, int irq, int prio)
+{
+    uint32_t word = irq / PRIO_PER_WORD;
+    uint32_t part = 4 * (irq % PRIO_PER_WORD);
+    uint32_t mask = ~(0xf << part);
+    s->prio[word] &= mask;
+    s->prio[word] |= prio << part;
+}
+
+/* Update interrupts.  */
+static void imx_avic_update(IMXAVICState *s)
+{
+    int i;
+    uint64_t new = s->pending & s->enabled;
+    uint64_t flags;
+
+    flags = new & s->is_fiq;
+    qemu_set_irq(s->fiq, !!flags);
+
+    flags = new & ~s->is_fiq;
+    if (!flags || (s->intmask == 0x1f)) {
+        qemu_set_irq(s->irq, !!flags);
+        return;
+    }
+
+    /*
+     * Take interrupt if there's a pending interrupt with
+     * priority higher than the value of intmask
+     */
+    for (i = 0; i < IMX_AVIC_NUM_IRQS; i++) {
+        if (flags & (1UL << i)) {
+            if (imx_avic_prio(s, i) > s->intmask) {
+                qemu_set_irq(s->irq, 1);
+                return;
+            }
+        }
+    }
+    qemu_set_irq(s->irq, 0);
+}
+
+static void imx_avic_set_irq(void *opaque, int irq, int level)
+{
+    IMXAVICState *s = (IMXAVICState *)opaque;
+
+    if (level) {
+        DPRINTF("Raising IRQ %d, prio %d\n",
+                irq, imx_avic_prio(s, irq));
+        s->pending |= (1ULL << irq);
+    } else {
+        DPRINTF("Clearing IRQ %d, prio %d\n",
+                irq, imx_avic_prio(s, irq));
+        s->pending &= ~(1ULL << irq);
+    }
+
+    imx_avic_update(s);
+}
+
+
+static uint64_t imx_avic_read(void *opaque,
+                             hwaddr offset, unsigned size)
+{
+    IMXAVICState *s = (IMXAVICState *)opaque;
+
+
+    DPRINTF("read(offset = 0x%x)\n", offset >> 2);
+    switch (offset >> 2) {
+    case 0: /* INTCNTL */
+        return s->intcntl;
+
+    case 1: /* Normal Interrupt Mask Register, NIMASK */
+        return s->intmask;
+
+    case 2: /* Interrupt Enable Number Register, INTENNUM */
+    case 3: /* Interrupt Disable Number Register, INTDISNUM */
+        return 0;
+
+    case 4: /* Interrupt Enabled Number Register High */
+        return s->enabled >> 32;
+
+    case 5: /* Interrupt Enabled Number Register Low */
+        return s->enabled & 0xffffffffULL;
+
+    case 6: /* Interrupt Type Register High */
+        return s->is_fiq >> 32;
+
+    case 7: /* Interrupt Type Register Low */
+        return s->is_fiq & 0xffffffffULL;
+
+    case 8: /* Normal Interrupt Priority Register 7 */
+    case 9: /* Normal Interrupt Priority Register 6 */
+    case 10:/* Normal Interrupt Priority Register 5 */
+    case 11:/* Normal Interrupt Priority Register 4 */
+    case 12:/* Normal Interrupt Priority Register 3 */
+    case 13:/* Normal Interrupt Priority Register 2 */
+    case 14:/* Normal Interrupt Priority Register 1 */
+    case 15:/* Normal Interrupt Priority Register 0 */
+        return s->prio[15-(offset>>2)];
+
+    case 16: /* Normal interrupt vector and status register */
+    {
+        /*
+         * This returns the highest priority
+         * outstanding interrupt.  Where there is more than
+         * one pending IRQ with the same priority,
+         * take the highest numbered one.
+         */
+        uint64_t flags = s->pending & s->enabled & ~s->is_fiq;
+        int i;
+        int prio = -1;
+        int irq = -1;
+        for (i = 63; i >= 0; --i) {
+            if (flags & (1ULL<<i)) {
+                int irq_prio = imx_avic_prio(s, i);
+                if (irq_prio > prio) {
+                    irq = i;
+                    prio = irq_prio;
+                }
+            }
+        }
+        if (irq >= 0) {
+            imx_avic_set_irq(s, irq, 0);
+            return irq << 16 | prio;
+        }
+        return 0xffffffffULL;
+    }
+    case 17:/* Fast Interrupt vector and status register */
+    {
+        uint64_t flags = s->pending & s->enabled & s->is_fiq;
+        int i = ctz64(flags);
+        if (i < 64) {
+            imx_avic_set_irq(opaque, i, 0);
+            return i;
+        }
+        return 0xffffffffULL;
+    }
+    case 18:/* Interrupt source register high */
+        return s->pending >> 32;
+
+    case 19:/* Interrupt source register low */
+        return s->pending & 0xffffffffULL;
+
+    case 20:/* Interrupt Force Register high */
+    case 21:/* Interrupt Force Register low */
+        return 0;
+
+    case 22:/* Normal Interrupt Pending Register High */
+        return (s->pending & s->enabled & ~s->is_fiq) >> 32;
+
+    case 23:/* Normal Interrupt Pending Register Low */
+        return (s->pending & s->enabled & ~s->is_fiq) & 0xffffffffULL;
+
+    case 24: /* Fast Interrupt Pending Register High  */
+        return (s->pending & s->enabled & s->is_fiq) >> 32;
+
+    case 25: /* Fast Interrupt Pending Register Low  */
+        return (s->pending & s->enabled & s->is_fiq) & 0xffffffffULL;
+
+    case 0x40:            /* AVIC vector 0, use for WFI WAR */
+        return 0x4;
+
+    default:
+        IPRINTF("imx_avic_read: Bad offset 0x%x\n", (int)offset);
+        return 0;
+    }
+}
+
+static void imx_avic_write(void *opaque, hwaddr offset,
+                          uint64_t val, unsigned size)
+{
+    IMXAVICState *s = (IMXAVICState *)opaque;
+
+    /* Vector Registers not yet supported */
+    if (offset >= 0x100 && offset <= 0x2fc) {
+        IPRINTF("imx_avic_write to vector register %d ignored\n",
+                (unsigned int)((offset - 0x100) >> 2));
+        return;
+    }
+
+    DPRINTF("imx_avic_write(0x%x) = %x\n",
+            (unsigned int)offset>>2, (unsigned int)val);
+    switch (offset >> 2) {
+    case 0: /* Interrupt Control Register, INTCNTL */
+        s->intcntl = val & (ABFEN | NIDIS | FIDIS | NIAD | FIAD | NM);
+        if (s->intcntl & ABFEN) {
+            s->intcntl &= ~(val & ABFLAG);
+        }
+        break;
+
+    case 1: /* Normal Interrupt Mask Register, NIMASK */
+        s->intmask = val & 0x1f;
+        break;
+
+    case 2: /* Interrupt Enable Number Register, INTENNUM */
+        DPRINTF("enable(%d)\n", (int)val);
+        val &= 0x3f;
+        s->enabled |= (1ULL << val);
+        break;
+
+    case 3: /* Interrupt Disable Number Register, INTDISNUM */
+        DPRINTF("disable(%d)\n", (int)val);
+        val &= 0x3f;
+        s->enabled &= ~(1ULL << val);
+        break;
+
+    case 4: /* Interrupt Enable Number Register High */
+        s->enabled = (s->enabled & 0xffffffffULL) | (val << 32);
+        break;
+
+    case 5: /* Interrupt Enable Number Register Low */
+        s->enabled = (s->enabled & 0xffffffff00000000ULL) | val;
+        break;
+
+    case 6: /* Interrupt Type Register High */
+        s->is_fiq = (s->is_fiq & 0xffffffffULL) | (val << 32);
+        break;
+
+    case 7: /* Interrupt Type Register Low */
+        s->is_fiq = (s->is_fiq & 0xffffffff00000000ULL) | val;
+        break;
+
+    case 8: /* Normal Interrupt Priority Register 7 */
+    case 9: /* Normal Interrupt Priority Register 6 */
+    case 10:/* Normal Interrupt Priority Register 5 */
+    case 11:/* Normal Interrupt Priority Register 4 */
+    case 12:/* Normal Interrupt Priority Register 3 */
+    case 13:/* Normal Interrupt Priority Register 2 */
+    case 14:/* Normal Interrupt Priority Register 1 */
+    case 15:/* Normal Interrupt Priority Register 0 */
+        s->prio[15-(offset>>2)] = val;
+        break;
+
+        /* Read-only registers, writes ignored */
+    case 16:/* Normal Interrupt Vector and Status register */
+    case 17:/* Fast Interrupt vector and status register */
+    case 18:/* Interrupt source register high */
+    case 19:/* Interrupt source register low */
+        return;
+
+    case 20:/* Interrupt Force Register high */
+        s->pending = (s->pending & 0xffffffffULL) | (val << 32);
+        break;
+
+    case 21:/* Interrupt Force Register low */
+        s->pending = (s->pending & 0xffffffff00000000ULL) | val;
+        break;
+
+    case 22:/* Normal Interrupt Pending Register High */
+    case 23:/* Normal Interrupt Pending Register Low */
+    case 24: /* Fast Interrupt Pending Register High  */
+    case 25: /* Fast Interrupt Pending Register Low  */
+        return;
+
+    default:
+        IPRINTF("imx_avic_write: Bad offset %x\n", (int)offset);
+    }
+    imx_avic_update(s);
+}
+
+static const MemoryRegionOps imx_avic_ops = {
+    .read = imx_avic_read,
+    .write = imx_avic_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void imx_avic_reset(DeviceState *dev)
+{
+    IMXAVICState *s = container_of(dev, IMXAVICState, busdev.qdev);
+    s->pending = 0;
+    s->enabled = 0;
+    s->is_fiq = 0;
+    s->intmask = 0x1f;
+    s->intcntl = 0;
+    memset(s->prio, 0, sizeof s->prio);
+}
+
+static int imx_avic_init(SysBusDevice *dev)
+{
+    IMXAVICState *s = FROM_SYSBUS(IMXAVICState, dev);;
+
+    memory_region_init_io(&s->iomem, &imx_avic_ops, s, "imx_avic", 0x1000);
+    sysbus_init_mmio(dev, &s->iomem);
+
+    qdev_init_gpio_in(&dev->qdev, imx_avic_set_irq, IMX_AVIC_NUM_IRQS);
+    sysbus_init_irq(dev, &s->irq);
+    sysbus_init_irq(dev, &s->fiq);
+
+    return 0;
+}
+
+
+static void imx_avic_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+    k->init = imx_avic_init;
+    dc->vmsd = &vmstate_imx_avic;
+    dc->reset = imx_avic_reset;
+    dc->desc = "i.MX Advanced Vector Interrupt Controller";
+}
+
+static const TypeInfo imx_avic_info = {
+    .name = "imx_avic",
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(IMXAVICState),
+    .class_init = imx_avic_class_init,
+};
+
+static void imx_avic_register_types(void)
+{
+    type_register_static(&imx_avic_info);
+}
+
+type_init(imx_avic_register_types)
diff --git a/hw/intc/ioapic.c b/hw/intc/ioapic.c
new file mode 100644 (file)
index 0000000..c6f09f4
--- /dev/null
@@ -0,0 +1,258 @@
+/*
+ *  ioapic.c IOAPIC emulation logic
+ *
+ *  Copyright (c) 2004-2005 Fabrice Bellard
+ *
+ *  Split the ioapic logic from apic.c
+ *  Xiantao Zhang <xiantao.zhang@intel.com>
+ *
+ * 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/hw.h"
+#include "hw/i386/pc.h"
+#include "hw/i386/ioapic.h"
+#include "hw/i386/ioapic_internal.h"
+
+//#define DEBUG_IOAPIC
+
+#ifdef DEBUG_IOAPIC
+#define DPRINTF(fmt, ...)                                       \
+    do { printf("ioapic: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...)
+#endif
+
+static IOAPICCommonState *ioapics[MAX_IOAPICS];
+
+static void ioapic_service(IOAPICCommonState *s)
+{
+    uint8_t i;
+    uint8_t trig_mode;
+    uint8_t vector;
+    uint8_t delivery_mode;
+    uint32_t mask;
+    uint64_t entry;
+    uint8_t dest;
+    uint8_t dest_mode;
+
+    for (i = 0; i < IOAPIC_NUM_PINS; i++) {
+        mask = 1 << i;
+        if (s->irr & mask) {
+            entry = s->ioredtbl[i];
+            if (!(entry & IOAPIC_LVT_MASKED)) {
+                trig_mode = ((entry >> IOAPIC_LVT_TRIGGER_MODE_SHIFT) & 1);
+                dest = entry >> IOAPIC_LVT_DEST_SHIFT;
+                dest_mode = (entry >> IOAPIC_LVT_DEST_MODE_SHIFT) & 1;
+                delivery_mode =
+                    (entry >> IOAPIC_LVT_DELIV_MODE_SHIFT) & IOAPIC_DM_MASK;
+                if (trig_mode == IOAPIC_TRIGGER_EDGE) {
+                    s->irr &= ~mask;
+                } else {
+                    s->ioredtbl[i] |= IOAPIC_LVT_REMOTE_IRR;
+                }
+                if (delivery_mode == IOAPIC_DM_EXTINT) {
+                    vector = pic_read_irq(isa_pic);
+                } else {
+                    vector = entry & IOAPIC_VECTOR_MASK;
+                }
+                apic_deliver_irq(dest, dest_mode, delivery_mode,
+                                 vector, trig_mode);
+            }
+        }
+    }
+}
+
+static void ioapic_set_irq(void *opaque, int vector, int level)
+{
+    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
+     * the cleanest way of doing it but it should work. */
+
+    DPRINTF("%s: %s vec %x\n", __func__, level ? "raise" : "lower", vector);
+    if (vector == 0) {
+        vector = 2;
+    }
+    if (vector >= 0 && vector < IOAPIC_NUM_PINS) {
+        uint32_t mask = 1 << vector;
+        uint64_t entry = s->ioredtbl[vector];
+
+        if (entry & (1 << IOAPIC_LVT_POLARITY_SHIFT)) {
+            level = !level;
+        }
+        if (((entry >> IOAPIC_LVT_TRIGGER_MODE_SHIFT) & 1) ==
+            IOAPIC_TRIGGER_LEVEL) {
+            /* level triggered */
+            if (level) {
+                s->irr |= mask;
+                ioapic_service(s);
+            } else {
+                s->irr &= ~mask;
+            }
+        } else {
+            /* According to the 82093AA manual, we must ignore edge requests
+             * if the input pin is masked. */
+            if (level && !(entry & IOAPIC_LVT_MASKED)) {
+                s->irr |= mask;
+                ioapic_service(s);
+            }
+        }
+    }
+}
+
+void ioapic_eoi_broadcast(int vector)
+{
+    IOAPICCommonState *s;
+    uint64_t entry;
+    int i, n;
+
+    for (i = 0; i < MAX_IOAPICS; i++) {
+        s = ioapics[i];
+        if (!s) {
+            continue;
+        }
+        for (n = 0; n < IOAPIC_NUM_PINS; n++) {
+            entry = s->ioredtbl[n];
+            if ((entry & IOAPIC_LVT_REMOTE_IRR)
+                && (entry & IOAPIC_VECTOR_MASK) == vector) {
+                s->ioredtbl[n] = entry & ~IOAPIC_LVT_REMOTE_IRR;
+                if (!(entry & IOAPIC_LVT_MASKED) && (s->irr & (1 << n))) {
+                    ioapic_service(s);
+                }
+            }
+        }
+    }
+}
+
+static uint64_t
+ioapic_mem_read(void *opaque, hwaddr addr, unsigned int size)
+{
+    IOAPICCommonState *s = opaque;
+    int index;
+    uint32_t val = 0;
+
+    switch (addr & 0xff) {
+    case IOAPIC_IOREGSEL:
+        val = s->ioregsel;
+        break;
+    case IOAPIC_IOWIN:
+        if (size != 4) {
+            break;
+        }
+        switch (s->ioregsel) {
+        case IOAPIC_REG_ID:
+            val = s->id << IOAPIC_ID_SHIFT;
+            break;
+        case IOAPIC_REG_VER:
+            val = IOAPIC_VERSION |
+                ((IOAPIC_NUM_PINS - 1) << IOAPIC_VER_ENTRIES_SHIFT);
+            break;
+        case IOAPIC_REG_ARB:
+            val = 0;
+            break;
+        default:
+            index = (s->ioregsel - IOAPIC_REG_REDTBL_BASE) >> 1;
+            if (index >= 0 && index < IOAPIC_NUM_PINS) {
+                if (s->ioregsel & 1) {
+                    val = s->ioredtbl[index] >> 32;
+                } else {
+                    val = s->ioredtbl[index] & 0xffffffff;
+                }
+            }
+        }
+        DPRINTF("read: %08x = %08x\n", s->ioregsel, val);
+        break;
+    }
+    return val;
+}
+
+static void
+ioapic_mem_write(void *opaque, hwaddr addr, uint64_t val,
+                 unsigned int size)
+{
+    IOAPICCommonState *s = opaque;
+    int index;
+
+    switch (addr & 0xff) {
+    case IOAPIC_IOREGSEL:
+        s->ioregsel = val;
+        break;
+    case IOAPIC_IOWIN:
+        if (size != 4) {
+            break;
+        }
+        DPRINTF("write: %08x = %08" PRIx64 "\n", s->ioregsel, val);
+        switch (s->ioregsel) {
+        case IOAPIC_REG_ID:
+            s->id = (val >> IOAPIC_ID_SHIFT) & IOAPIC_ID_MASK;
+            break;
+        case IOAPIC_REG_VER:
+        case IOAPIC_REG_ARB:
+            break;
+        default:
+            index = (s->ioregsel - IOAPIC_REG_REDTBL_BASE) >> 1;
+            if (index >= 0 && index < IOAPIC_NUM_PINS) {
+                if (s->ioregsel & 1) {
+                    s->ioredtbl[index] &= 0xffffffff;
+                    s->ioredtbl[index] |= (uint64_t)val << 32;
+                } else {
+                    s->ioredtbl[index] &= ~0xffffffffULL;
+                    s->ioredtbl[index] |= val;
+                }
+                ioapic_service(s);
+            }
+        }
+        break;
+    }
+}
+
+static const MemoryRegionOps ioapic_io_ops = {
+    .read = ioapic_mem_read,
+    .write = ioapic_mem_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void ioapic_init(IOAPICCommonState *s, int instance_no)
+{
+    memory_region_init_io(&s->io_memory, &ioapic_io_ops, s, "ioapic", 0x1000);
+
+    qdev_init_gpio_in(&s->busdev.qdev, ioapic_set_irq, IOAPIC_NUM_PINS);
+
+    ioapics[instance_no] = s;
+}
+
+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 const TypeInfo ioapic_info = {
+    .name          = "ioapic",
+    .parent        = TYPE_IOAPIC_COMMON,
+    .instance_size = sizeof(IOAPICCommonState),
+    .class_init    = ioapic_class_init,
+};
+
+static void ioapic_register_types(void)
+{
+    type_register_static(&ioapic_info);
+}
+
+type_init(ioapic_register_types)
diff --git a/hw/intc/ioapic_common.c b/hw/intc/ioapic_common.c
new file mode 100644 (file)
index 0000000..42c7adc
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ *  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 "hw/i386/ioapic.h"
+#include "hw/i386/ioapic_internal.h"
+#include "hw/sysbus.h"
+
+void ioapic_reset_common(DeviceState *dev)
+{
+    IOAPICCommonState *s = IOAPIC_COMMON(dev);
+    int i;
+
+    s->id = 0;
+    s->ioregsel = 0;
+    s->irr = 0;
+    for (i = 0; i < IOAPIC_NUM_PINS; i++) {
+        s->ioredtbl[i] = 1 << IOAPIC_LVT_MASKED_SHIFT;
+    }
+}
+
+static void ioapic_dispatch_pre_save(void *opaque)
+{
+    IOAPICCommonState *s = IOAPIC_COMMON(opaque);
+    IOAPICCommonClass *info = IOAPIC_COMMON_GET_CLASS(s);
+
+    if (info->pre_save) {
+        info->pre_save(s);
+    }
+}
+
+static int ioapic_dispatch_post_load(void *opaque, int version_id)
+{
+    IOAPICCommonState *s = IOAPIC_COMMON(opaque);
+    IOAPICCommonClass *info = IOAPIC_COMMON_GET_CLASS(s);
+
+    if (info->post_load) {
+        info->post_load(s);
+    }
+    return 0;
+}
+
+static int ioapic_init_common(SysBusDevice *dev)
+{
+    IOAPICCommonState *s = FROM_SYSBUS(IOAPICCommonState, dev);
+    IOAPICCommonClass *info;
+    static int ioapic_no;
+
+    if (ioapic_no >= MAX_IOAPICS) {
+        return -1;
+    }
+
+    info = IOAPIC_COMMON_GET_CLASS(s);
+    info->init(s, ioapic_no);
+
+    sysbus_init_mmio(&s->busdev, &s->io_memory);
+    ioapic_no++;
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_ioapic_common = {
+    .name = "ioapic",
+    .version_id = 3,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .pre_save = ioapic_dispatch_pre_save,
+    .post_load = ioapic_dispatch_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT8(id, IOAPICCommonState),
+        VMSTATE_UINT8(ioregsel, IOAPICCommonState),
+        VMSTATE_UNUSED_V(2, 8), /* to account for qemu-kvm's v2 format */
+        VMSTATE_UINT32_V(irr, IOAPICCommonState, 2),
+        VMSTATE_UINT64_ARRAY(ioredtbl, IOAPICCommonState, IOAPIC_NUM_PINS),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void ioapic_common_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sc = SYS_BUS_DEVICE_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    sc->init = ioapic_init_common;
+    dc->vmsd = &vmstate_ioapic_common;
+    dc->no_user = 1;
+}
+
+static const TypeInfo ioapic_common_type = {
+    .name = TYPE_IOAPIC_COMMON,
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(IOAPICCommonState),
+    .class_size = sizeof(IOAPICCommonClass),
+    .class_init = ioapic_common_class_init,
+    .abstract = true,
+};
+
+static void register_types(void)
+{
+    type_register_static(&ioapic_common_type);
+}
+
+type_init(register_types)
diff --git a/hw/intc/lm32_pic.c b/hw/intc/lm32_pic.c
new file mode 100644 (file)
index 0000000..b4e80c8
--- /dev/null
@@ -0,0 +1,199 @@
+/*
+ *  LatticeMico32 CPU interrupt controller logic.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
+ *
+ * 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 <assert.h>
+
+#include "hw/hw.h"
+#include "hw/i386/pc.h"
+#include "monitor/monitor.h"
+#include "hw/sysbus.h"
+#include "trace.h"
+#include "hw/lm32/lm32_pic.h"
+
+struct LM32PicState {
+    SysBusDevice busdev;
+    qemu_irq parent_irq;
+    uint32_t im;        /* interrupt mask */
+    uint32_t ip;        /* interrupt pending */
+    uint32_t irq_state;
+
+    /* statistics */
+    uint32_t stats_irq_count[32];
+};
+typedef struct LM32PicState LM32PicState;
+
+static LM32PicState *pic;
+void lm32_do_pic_info(Monitor *mon, const QDict *qdict)
+{
+    if (pic == NULL) {
+        return;
+    }
+
+    monitor_printf(mon, "lm32-pic: im=%08x ip=%08x irq_state=%08x\n",
+            pic->im, pic->ip, pic->irq_state);
+}
+
+void lm32_irq_info(Monitor *mon, const QDict *qdict)
+{
+    int i;
+    uint32_t count;
+
+    if (pic == NULL) {
+        return;
+    }
+
+    monitor_printf(mon, "IRQ statistics:\n");
+    for (i = 0; i < 32; i++) {
+        count = pic->stats_irq_count[i];
+        if (count > 0) {
+            monitor_printf(mon, "%2d: %u\n", i, count);
+        }
+    }
+}
+
+static void update_irq(LM32PicState *s)
+{
+    s->ip |= s->irq_state;
+
+    if (s->ip & s->im) {
+        trace_lm32_pic_raise_irq();
+        qemu_irq_raise(s->parent_irq);
+    } else {
+        trace_lm32_pic_lower_irq();
+        qemu_irq_lower(s->parent_irq);
+    }
+}
+
+static void irq_handler(void *opaque, int irq, int level)
+{
+    LM32PicState *s = opaque;
+
+    assert(irq < 32);
+    trace_lm32_pic_interrupt(irq, level);
+
+    if (level) {
+        s->irq_state |= (1 << irq);
+        s->stats_irq_count[irq]++;
+    } else {
+        s->irq_state &= ~(1 << irq);
+    }
+
+    update_irq(s);
+}
+
+void lm32_pic_set_im(DeviceState *d, uint32_t im)
+{
+    LM32PicState *s = container_of(d, LM32PicState, busdev.qdev);
+
+    trace_lm32_pic_set_im(im);
+    s->im = im;
+
+    update_irq(s);
+}
+
+void lm32_pic_set_ip(DeviceState *d, uint32_t ip)
+{
+    LM32PicState *s = container_of(d, LM32PicState, busdev.qdev);
+
+    trace_lm32_pic_set_ip(ip);
+
+    /* ack interrupt */
+    s->ip &= ~ip;
+
+    update_irq(s);
+}
+
+uint32_t lm32_pic_get_im(DeviceState *d)
+{
+    LM32PicState *s = container_of(d, LM32PicState, busdev.qdev);
+
+    trace_lm32_pic_get_im(s->im);
+    return s->im;
+}
+
+uint32_t lm32_pic_get_ip(DeviceState *d)
+{
+    LM32PicState *s = container_of(d, LM32PicState, busdev.qdev);
+
+    trace_lm32_pic_get_ip(s->ip);
+    return s->ip;
+}
+
+static void pic_reset(DeviceState *d)
+{
+    LM32PicState *s = container_of(d, LM32PicState, busdev.qdev);
+    int i;
+
+    s->im = 0;
+    s->ip = 0;
+    s->irq_state = 0;
+    for (i = 0; i < 32; i++) {
+        s->stats_irq_count[i] = 0;
+    }
+}
+
+static int lm32_pic_init(SysBusDevice *dev)
+{
+    LM32PicState *s = FROM_SYSBUS(typeof(*s), dev);
+
+    qdev_init_gpio_in(&dev->qdev, irq_handler, 32);
+    sysbus_init_irq(dev, &s->parent_irq);
+
+    pic = s;
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_lm32_pic = {
+    .name = "lm32-pic",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32(im, LM32PicState),
+        VMSTATE_UINT32(ip, LM32PicState),
+        VMSTATE_UINT32(irq_state, LM32PicState),
+        VMSTATE_UINT32_ARRAY(stats_irq_count, LM32PicState, 32),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+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 const 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_types(void)
+{
+    type_register_static(&lm32_pic_info);
+}
+
+type_init(lm32_pic_register_types)
diff --git a/hw/intc/omap_intc.c b/hw/intc/omap_intc.c
new file mode 100644 (file)
index 0000000..875eba4
--- /dev/null
@@ -0,0 +1,649 @@
+/*
+ * TI OMAP interrupt controller emulation.
+ *
+ * Copyright (C) 2006-2008 Andrzej Zaborowski  <balrog@zabor.org>
+ * Copyright (C) 2007-2008 Nokia Corporation
+ *
+ * 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 or
+ * (at your option) version 3 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
+ * 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 "hw/hw.h"
+#include "hw/arm/omap.h"
+#include "hw/sysbus.h"
+
+/* Interrupt Handlers */
+struct omap_intr_handler_bank_s {
+    uint32_t irqs;
+    uint32_t inputs;
+    uint32_t mask;
+    uint32_t fiq;
+    uint32_t sens_edge;
+    uint32_t swi;
+    unsigned char priority[32];
+};
+
+struct omap_intr_handler_s {
+    SysBusDevice busdev;
+    qemu_irq *pins;
+    qemu_irq parent_intr[2];
+    MemoryRegion mmio;
+    void *iclk;
+    void *fclk;
+    unsigned char nbanks;
+    int level_only;
+    uint32_t size;
+
+    uint8_t revision;
+
+    /* state */
+    uint32_t new_agr[2];
+    int sir_intr[2];
+    int autoidle;
+    uint32_t mask;
+    struct omap_intr_handler_bank_s bank[3];
+};
+
+static void omap_inth_sir_update(struct omap_intr_handler_s *s, int is_fiq)
+{
+    int i, j, sir_intr, p_intr, p, f;
+    uint32_t level;
+    sir_intr = 0;
+    p_intr = 255;
+
+    /* Find the interrupt line with the highest dynamic priority.
+     * Note: 0 denotes the hightest priority.
+     * If all interrupts have the same priority, the default order is IRQ_N,
+     * IRQ_N-1,...,IRQ_0. */
+    for (j = 0; j < s->nbanks; ++j) {
+        level = s->bank[j].irqs & ~s->bank[j].mask &
+                (is_fiq ? s->bank[j].fiq : ~s->bank[j].fiq);
+        for (f = ffs(level), i = f - 1, level >>= f - 1; f; i += f,
+                        level >>= f) {
+            p = s->bank[j].priority[i];
+            if (p <= p_intr) {
+                p_intr = p;
+                sir_intr = 32 * j + i;
+            }
+            f = ffs(level >> 1);
+        }
+    }
+    s->sir_intr[is_fiq] = sir_intr;
+}
+
+static inline void omap_inth_update(struct omap_intr_handler_s *s, int is_fiq)
+{
+    int i;
+    uint32_t has_intr = 0;
+
+    for (i = 0; i < s->nbanks; ++i)
+        has_intr |= s->bank[i].irqs & ~s->bank[i].mask &
+                (is_fiq ? s->bank[i].fiq : ~s->bank[i].fiq);
+
+    if (s->new_agr[is_fiq] & has_intr & s->mask) {
+        s->new_agr[is_fiq] = 0;
+        omap_inth_sir_update(s, is_fiq);
+        qemu_set_irq(s->parent_intr[is_fiq], 1);
+    }
+}
+
+#define INT_FALLING_EDGE       0
+#define INT_LOW_LEVEL          1
+
+static void omap_set_intr(void *opaque, int irq, int req)
+{
+    struct omap_intr_handler_s *ih = (struct omap_intr_handler_s *) opaque;
+    uint32_t rise;
+
+    struct omap_intr_handler_bank_s *bank = &ih->bank[irq >> 5];
+    int n = irq & 31;
+
+    if (req) {
+        rise = ~bank->irqs & (1 << n);
+        if (~bank->sens_edge & (1 << n))
+            rise &= ~bank->inputs;
+
+        bank->inputs |= (1 << n);
+        if (rise) {
+            bank->irqs |= rise;
+            omap_inth_update(ih, 0);
+            omap_inth_update(ih, 1);
+        }
+    } else {
+        rise = bank->sens_edge & bank->irqs & (1 << n);
+        bank->irqs &= ~rise;
+        bank->inputs &= ~(1 << n);
+    }
+}
+
+/* Simplified version with no edge detection */
+static void omap_set_intr_noedge(void *opaque, int irq, int req)
+{
+    struct omap_intr_handler_s *ih = (struct omap_intr_handler_s *) opaque;
+    uint32_t rise;
+
+    struct omap_intr_handler_bank_s *bank = &ih->bank[irq >> 5];
+    int n = irq & 31;
+
+    if (req) {
+        rise = ~bank->inputs & (1 << n);
+        if (rise) {
+            bank->irqs |= bank->inputs |= rise;
+            omap_inth_update(ih, 0);
+            omap_inth_update(ih, 1);
+        }
+    } else
+        bank->irqs = (bank->inputs &= ~(1 << n)) | bank->swi;
+}
+
+static uint64_t omap_inth_read(void *opaque, hwaddr addr,
+                               unsigned size)
+{
+    struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque;
+    int i, offset = addr;
+    int bank_no = offset >> 8;
+    int line_no;
+    struct omap_intr_handler_bank_s *bank = &s->bank[bank_no];
+    offset &= 0xff;
+
+    switch (offset) {
+    case 0x00: /* ITR */
+        return bank->irqs;
+
+    case 0x04: /* MIR */
+        return bank->mask;
+
+    case 0x10: /* SIR_IRQ_CODE */
+    case 0x14:  /* SIR_FIQ_CODE */
+        if (bank_no != 0)
+            break;
+        line_no = s->sir_intr[(offset - 0x10) >> 2];
+        bank = &s->bank[line_no >> 5];
+        i = line_no & 31;
+        if (((bank->sens_edge >> i) & 1) == INT_FALLING_EDGE)
+            bank->irqs &= ~(1 << i);
+        return line_no;
+
+    case 0x18: /* CONTROL_REG */
+        if (bank_no != 0)
+            break;
+        return 0;
+
+    case 0x1c: /* ILR0 */
+    case 0x20: /* ILR1 */
+    case 0x24: /* ILR2 */
+    case 0x28: /* ILR3 */
+    case 0x2c: /* ILR4 */
+    case 0x30: /* ILR5 */
+    case 0x34: /* ILR6 */
+    case 0x38: /* ILR7 */
+    case 0x3c: /* ILR8 */
+    case 0x40: /* ILR9 */
+    case 0x44: /* ILR10 */
+    case 0x48: /* ILR11 */
+    case 0x4c: /* ILR12 */
+    case 0x50: /* ILR13 */
+    case 0x54: /* ILR14 */
+    case 0x58: /* ILR15 */
+    case 0x5c: /* ILR16 */
+    case 0x60: /* ILR17 */
+    case 0x64: /* ILR18 */
+    case 0x68: /* ILR19 */
+    case 0x6c: /* ILR20 */
+    case 0x70: /* ILR21 */
+    case 0x74: /* ILR22 */
+    case 0x78: /* ILR23 */
+    case 0x7c: /* ILR24 */
+    case 0x80: /* ILR25 */
+    case 0x84: /* ILR26 */
+    case 0x88: /* ILR27 */
+    case 0x8c: /* ILR28 */
+    case 0x90: /* ILR29 */
+    case 0x94: /* ILR30 */
+    case 0x98: /* ILR31 */
+        i = (offset - 0x1c) >> 2;
+        return (bank->priority[i] << 2) |
+                (((bank->sens_edge >> i) & 1) << 1) |
+                ((bank->fiq >> i) & 1);
+
+    case 0x9c: /* ISR */
+        return 0x00000000;
+
+    }
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_inth_write(void *opaque, hwaddr addr,
+                            uint64_t value, unsigned size)
+{
+    struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque;
+    int i, offset = addr;
+    int bank_no = offset >> 8;
+    struct omap_intr_handler_bank_s *bank = &s->bank[bank_no];
+    offset &= 0xff;
+
+    switch (offset) {
+    case 0x00: /* ITR */
+        /* Important: ignore the clearing if the IRQ is level-triggered and
+           the input bit is 1 */
+        bank->irqs &= value | (bank->inputs & bank->sens_edge);
+        return;
+
+    case 0x04: /* MIR */
+        bank->mask = value;
+        omap_inth_update(s, 0);
+        omap_inth_update(s, 1);
+        return;
+
+    case 0x10: /* SIR_IRQ_CODE */
+    case 0x14: /* SIR_FIQ_CODE */
+        OMAP_RO_REG(addr);
+        break;
+
+    case 0x18: /* CONTROL_REG */
+        if (bank_no != 0)
+            break;
+        if (value & 2) {
+            qemu_set_irq(s->parent_intr[1], 0);
+            s->new_agr[1] = ~0;
+            omap_inth_update(s, 1);
+        }
+        if (value & 1) {
+            qemu_set_irq(s->parent_intr[0], 0);
+            s->new_agr[0] = ~0;
+            omap_inth_update(s, 0);
+        }
+        return;
+
+    case 0x1c: /* ILR0 */
+    case 0x20: /* ILR1 */
+    case 0x24: /* ILR2 */
+    case 0x28: /* ILR3 */
+    case 0x2c: /* ILR4 */
+    case 0x30: /* ILR5 */
+    case 0x34: /* ILR6 */
+    case 0x38: /* ILR7 */
+    case 0x3c: /* ILR8 */
+    case 0x40: /* ILR9 */
+    case 0x44: /* ILR10 */
+    case 0x48: /* ILR11 */
+    case 0x4c: /* ILR12 */
+    case 0x50: /* ILR13 */
+    case 0x54: /* ILR14 */
+    case 0x58: /* ILR15 */
+    case 0x5c: /* ILR16 */
+    case 0x60: /* ILR17 */
+    case 0x64: /* ILR18 */
+    case 0x68: /* ILR19 */
+    case 0x6c: /* ILR20 */
+    case 0x70: /* ILR21 */
+    case 0x74: /* ILR22 */
+    case 0x78: /* ILR23 */
+    case 0x7c: /* ILR24 */
+    case 0x80: /* ILR25 */
+    case 0x84: /* ILR26 */
+    case 0x88: /* ILR27 */
+    case 0x8c: /* ILR28 */
+    case 0x90: /* ILR29 */
+    case 0x94: /* ILR30 */
+    case 0x98: /* ILR31 */
+        i = (offset - 0x1c) >> 2;
+        bank->priority[i] = (value >> 2) & 0x1f;
+        bank->sens_edge &= ~(1 << i);
+        bank->sens_edge |= ((value >> 1) & 1) << i;
+        bank->fiq &= ~(1 << i);
+        bank->fiq |= (value & 1) << i;
+        return;
+
+    case 0x9c: /* ISR */
+        for (i = 0; i < 32; i ++)
+            if (value & (1 << i)) {
+                omap_set_intr(s, 32 * bank_no + i, 1);
+                return;
+            }
+        return;
+    }
+    OMAP_BAD_REG(addr);
+}
+
+static const MemoryRegionOps omap_inth_mem_ops = {
+    .read = omap_inth_read,
+    .write = omap_inth_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static void omap_inth_reset(DeviceState *dev)
+{
+    struct omap_intr_handler_s *s = FROM_SYSBUS(struct omap_intr_handler_s,
+                                                SYS_BUS_DEVICE(dev));
+    int i;
+
+    for (i = 0; i < s->nbanks; ++i){
+        s->bank[i].irqs = 0x00000000;
+        s->bank[i].mask = 0xffffffff;
+        s->bank[i].sens_edge = 0x00000000;
+        s->bank[i].fiq = 0x00000000;
+        s->bank[i].inputs = 0x00000000;
+        s->bank[i].swi = 0x00000000;
+        memset(s->bank[i].priority, 0, sizeof(s->bank[i].priority));
+
+        if (s->level_only)
+            s->bank[i].sens_edge = 0xffffffff;
+    }
+
+    s->new_agr[0] = ~0;
+    s->new_agr[1] = ~0;
+    s->sir_intr[0] = 0;
+    s->sir_intr[1] = 0;
+    s->autoidle = 0;
+    s->mask = ~0;
+
+    qemu_set_irq(s->parent_intr[0], 0);
+    qemu_set_irq(s->parent_intr[1], 0);
+}
+
+static int omap_intc_init(SysBusDevice *dev)
+{
+    struct omap_intr_handler_s *s;
+    s = FROM_SYSBUS(struct omap_intr_handler_s, dev);
+    if (!s->iclk) {
+        hw_error("omap-intc: clk not connected\n");
+    }
+    s->nbanks = 1;
+    sysbus_init_irq(dev, &s->parent_intr[0]);
+    sysbus_init_irq(dev, &s->parent_intr[1]);
+    qdev_init_gpio_in(&dev->qdev, omap_set_intr, s->nbanks * 32);
+    memory_region_init_io(&s->mmio, &omap_inth_mem_ops, s,
+                          "omap-intc", s->size);
+    sysbus_init_mmio(dev, &s->mmio);
+    return 0;
+}
+
+static Property omap_intc_properties[] = {
+    DEFINE_PROP_UINT32("size", struct omap_intr_handler_s, size, 0x100),
+    DEFINE_PROP_PTR("clk", struct omap_intr_handler_s, iclk),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void omap_intc_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = omap_intc_init;
+    dc->reset = omap_inth_reset;
+    dc->props = omap_intc_properties;
+}
+
+static const 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, hwaddr addr,
+                                unsigned size)
+{
+    struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque;
+    int offset = addr;
+    int bank_no, line_no;
+    struct omap_intr_handler_bank_s *bank = NULL;
+
+    if ((offset & 0xf80) == 0x80) {
+        bank_no = (offset & 0x60) >> 5;
+        if (bank_no < s->nbanks) {
+            offset &= ~0x60;
+            bank = &s->bank[bank_no];
+        } else {
+            OMAP_BAD_REG(addr);
+            return 0;
+        }
+    }
+
+    switch (offset) {
+    case 0x00: /* INTC_REVISION */
+        return s->revision;
+
+    case 0x10: /* INTC_SYSCONFIG */
+        return (s->autoidle >> 2) & 1;
+
+    case 0x14: /* INTC_SYSSTATUS */
+        return 1;                                              /* RESETDONE */
+
+    case 0x40: /* INTC_SIR_IRQ */
+        return s->sir_intr[0];
+
+    case 0x44: /* INTC_SIR_FIQ */
+        return s->sir_intr[1];
+
+    case 0x48: /* INTC_CONTROL */
+        return (!s->mask) << 2;                                        /* GLOBALMASK */
+
+    case 0x4c: /* INTC_PROTECTION */
+        return 0;
+
+    case 0x50: /* INTC_IDLE */
+        return s->autoidle & 3;
+
+    /* Per-bank registers */
+    case 0x80: /* INTC_ITR */
+        return bank->inputs;
+
+    case 0x84: /* INTC_MIR */
+        return bank->mask;
+
+    case 0x88: /* INTC_MIR_CLEAR */
+    case 0x8c: /* INTC_MIR_SET */
+        return 0;
+
+    case 0x90: /* INTC_ISR_SET */
+        return bank->swi;
+
+    case 0x94: /* INTC_ISR_CLEAR */
+        return 0;
+
+    case 0x98: /* INTC_PENDING_IRQ */
+        return bank->irqs & ~bank->mask & ~bank->fiq;
+
+    case 0x9c: /* INTC_PENDING_FIQ */
+        return bank->irqs & ~bank->mask & bank->fiq;
+
+    /* Per-line registers */
+    case 0x100 ... 0x300:      /* INTC_ILR */
+        bank_no = (offset - 0x100) >> 7;
+        if (bank_no > s->nbanks)
+            break;
+        bank = &s->bank[bank_no];
+        line_no = (offset & 0x7f) >> 2;
+        return (bank->priority[line_no] << 2) |
+                ((bank->fiq >> line_no) & 1);
+    }
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap2_inth_write(void *opaque, hwaddr addr,
+                             uint64_t value, unsigned size)
+{
+    struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque;
+    int offset = addr;
+    int bank_no, line_no;
+    struct omap_intr_handler_bank_s *bank = NULL;
+
+    if ((offset & 0xf80) == 0x80) {
+        bank_no = (offset & 0x60) >> 5;
+        if (bank_no < s->nbanks) {
+            offset &= ~0x60;
+            bank = &s->bank[bank_no];
+        } else {
+            OMAP_BAD_REG(addr);
+            return;
+        }
+    }
+
+    switch (offset) {
+    case 0x10: /* INTC_SYSCONFIG */
+        s->autoidle &= 4;
+        s->autoidle |= (value & 1) << 2;
+        if (value & 2)                                         /* SOFTRESET */
+            omap_inth_reset(&s->busdev.qdev);
+        return;
+
+    case 0x48: /* INTC_CONTROL */
+        s->mask = (value & 4) ? 0 : ~0;                                /* GLOBALMASK */
+        if (value & 2) {                                       /* NEWFIQAGR */
+            qemu_set_irq(s->parent_intr[1], 0);
+            s->new_agr[1] = ~0;
+            omap_inth_update(s, 1);
+        }
+        if (value & 1) {                                       /* NEWIRQAGR */
+            qemu_set_irq(s->parent_intr[0], 0);
+            s->new_agr[0] = ~0;
+            omap_inth_update(s, 0);
+        }
+        return;
+
+    case 0x4c: /* INTC_PROTECTION */
+        /* TODO: Make a bitmap (or sizeof(char)map) of access privileges
+         * for every register, see Chapter 3 and 4 for privileged mode.  */
+        if (value & 1)
+            fprintf(stderr, "%s: protection mode enable attempt\n",
+                            __FUNCTION__);
+        return;
+
+    case 0x50: /* INTC_IDLE */
+        s->autoidle &= ~3;
+        s->autoidle |= value & 3;
+        return;
+
+    /* Per-bank registers */
+    case 0x84: /* INTC_MIR */
+        bank->mask = value;
+        omap_inth_update(s, 0);
+        omap_inth_update(s, 1);
+        return;
+
+    case 0x88: /* INTC_MIR_CLEAR */
+        bank->mask &= ~value;
+        omap_inth_update(s, 0);
+        omap_inth_update(s, 1);
+        return;
+
+    case 0x8c: /* INTC_MIR_SET */
+        bank->mask |= value;
+        return;
+
+    case 0x90: /* INTC_ISR_SET */
+        bank->irqs |= bank->swi |= value;
+        omap_inth_update(s, 0);
+        omap_inth_update(s, 1);
+        return;
+
+    case 0x94: /* INTC_ISR_CLEAR */
+        bank->swi &= ~value;
+        bank->irqs = bank->swi & bank->inputs;
+        return;
+
+    /* Per-line registers */
+    case 0x100 ... 0x300:      /* INTC_ILR */
+        bank_no = (offset - 0x100) >> 7;
+        if (bank_no > s->nbanks)
+            break;
+        bank = &s->bank[bank_no];
+        line_no = (offset & 0x7f) >> 2;
+        bank->priority[line_no] = (value >> 2) & 0x3f;
+        bank->fiq &= ~(1 << line_no);
+        bank->fiq |= (value & 1) << line_no;
+        return;
+
+    case 0x00: /* INTC_REVISION */
+    case 0x14: /* INTC_SYSSTATUS */
+    case 0x40: /* INTC_SIR_IRQ */
+    case 0x44: /* INTC_SIR_FIQ */
+    case 0x80: /* INTC_ITR */
+    case 0x98: /* INTC_PENDING_IRQ */
+    case 0x9c: /* INTC_PENDING_FIQ */
+        OMAP_RO_REG(addr);
+        return;
+    }
+    OMAP_BAD_REG(addr);
+}
+
+static const MemoryRegionOps omap2_inth_mem_ops = {
+    .read = omap2_inth_read,
+    .write = omap2_inth_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static int omap2_intc_init(SysBusDevice *dev)
+{
+    struct omap_intr_handler_s *s;
+    s = FROM_SYSBUS(struct omap_intr_handler_s, dev);
+    if (!s->iclk) {
+        hw_error("omap2-intc: iclk not connected\n");
+    }
+    if (!s->fclk) {
+        hw_error("omap2-intc: fclk not connected\n");
+    }
+    s->level_only = 1;
+    s->nbanks = 3;
+    sysbus_init_irq(dev, &s->parent_intr[0]);
+    sysbus_init_irq(dev, &s->parent_intr[1]);
+    qdev_init_gpio_in(&dev->qdev, omap_set_intr_noedge, s->nbanks * 32);
+    memory_region_init_io(&s->mmio, &omap2_inth_mem_ops, s,
+                          "omap2-intc", 0x1000);
+    sysbus_init_mmio(dev, &s->mmio);
+    return 0;
+}
+
+static Property omap2_intc_properties[] = {
+    DEFINE_PROP_UINT8("revision", struct omap_intr_handler_s,
+    revision, 0x21),
+    DEFINE_PROP_PTR("iclk", struct omap_intr_handler_s, iclk),
+    DEFINE_PROP_PTR("fclk", struct omap_intr_handler_s, fclk),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void omap2_intc_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = omap2_intc_init;
+    dc->reset = omap_inth_reset;
+    dc->props = omap2_intc_properties;
+}
+
+static const 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_types(void)
+{
+    type_register_static(&omap_intc_info);
+    type_register_static(&omap2_intc_info);
+}
+
+type_init(omap_intc_register_types)
diff --git a/hw/intc/openpic.c b/hw/intc/openpic.c
new file mode 100644 (file)
index 0000000..c788714
--- /dev/null
@@ -0,0 +1,1661 @@
+/*
+ * OpenPIC emulation
+ *
+ * Copyright (c) 2004 Jocelyn Mayer
+ *               2011 Alexander Graf
+ *
+ * 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.
+ */
+/*
+ *
+ * Based on OpenPic implementations:
+ * - Intel GW80314 I/O companion chip developer's manual
+ * - Motorola MPC8245 & MPC8540 user manuals.
+ * - Motorola MCP750 (aka Raven) programmer manual.
+ * - Motorola Harrier programmer manuel
+ *
+ * Serial interrupts, as implemented in Raven chipset are not supported yet.
+ *
+ */
+#include "hw/hw.h"
+#include "hw/ppc/mac.h"
+#include "hw/pci/pci.h"
+#include "hw/ppc/openpic.h"
+#include "hw/sysbus.h"
+#include "hw/pci/msi.h"
+#include "qemu/bitops.h"
+#include "hw/ppc/ppc.h"
+
+//#define DEBUG_OPENPIC
+
+#ifdef DEBUG_OPENPIC
+static const int debug_openpic = 1;
+#else
+static const int debug_openpic = 0;
+#endif
+
+#define DPRINTF(fmt, ...) do { \
+        if (debug_openpic) { \
+            printf(fmt , ## __VA_ARGS__); \
+        } \
+    } while (0)
+
+#define MAX_CPU     32
+#define MAX_SRC     256
+#define MAX_TMR     4
+#define MAX_IPI     4
+#define MAX_MSI     8
+#define MAX_IRQ     (MAX_SRC + MAX_IPI + MAX_TMR)
+#define VID         0x03 /* MPIC version ID */
+
+/* OpenPIC capability flags */
+#define OPENPIC_FLAG_IDR_CRIT     (1 << 0)
+#define OPENPIC_FLAG_ILR          (2 << 0)
+
+/* OpenPIC address map */
+#define OPENPIC_GLB_REG_START        0x0
+#define OPENPIC_GLB_REG_SIZE         0x10F0
+#define OPENPIC_TMR_REG_START        0x10F0
+#define OPENPIC_TMR_REG_SIZE         0x220
+#define OPENPIC_MSI_REG_START        0x1600
+#define OPENPIC_MSI_REG_SIZE         0x200
+#define OPENPIC_SUMMARY_REG_START   0x3800
+#define OPENPIC_SUMMARY_REG_SIZE    0x800
+#define OPENPIC_SRC_REG_START        0x10000
+#define OPENPIC_SRC_REG_SIZE         (MAX_SRC * 0x20)
+#define OPENPIC_CPU_REG_START        0x20000
+#define OPENPIC_CPU_REG_SIZE         0x100 + ((MAX_CPU - 1) * 0x1000)
+
+/* Raven */
+#define RAVEN_MAX_CPU      2
+#define RAVEN_MAX_EXT     48
+#define RAVEN_MAX_IRQ     64
+#define RAVEN_MAX_TMR      MAX_TMR
+#define RAVEN_MAX_IPI      MAX_IPI
+
+/* Interrupt definitions */
+#define RAVEN_FE_IRQ     (RAVEN_MAX_EXT)     /* Internal functional IRQ */
+#define RAVEN_ERR_IRQ    (RAVEN_MAX_EXT + 1) /* Error IRQ */
+#define RAVEN_TMR_IRQ    (RAVEN_MAX_EXT + 2) /* First timer IRQ */
+#define RAVEN_IPI_IRQ    (RAVEN_TMR_IRQ + RAVEN_MAX_TMR) /* First IPI IRQ */
+/* First doorbell IRQ */
+#define RAVEN_DBL_IRQ    (RAVEN_IPI_IRQ + (RAVEN_MAX_CPU * RAVEN_MAX_IPI))
+
+typedef struct FslMpicInfo {
+    int max_ext;
+} FslMpicInfo;
+
+static FslMpicInfo fsl_mpic_20 = {
+    .max_ext = 12,
+};
+
+static FslMpicInfo fsl_mpic_42 = {
+    .max_ext = 12,
+};
+
+#define FRR_NIRQ_SHIFT    16
+#define FRR_NCPU_SHIFT     8
+#define FRR_VID_SHIFT      0
+
+#define VID_REVISION_1_2   2
+#define VID_REVISION_1_3   3
+
+#define VIR_GENERIC      0x00000000 /* Generic Vendor ID */
+
+#define GCR_RESET        0x80000000
+#define GCR_MODE_PASS    0x00000000
+#define GCR_MODE_MIXED   0x20000000
+#define GCR_MODE_PROXY   0x60000000
+
+#define TBCR_CI           0x80000000 /* count inhibit */
+#define TCCR_TOG          0x80000000 /* toggles when decrement to zero */
+
+#define IDR_EP_SHIFT      31
+#define IDR_EP_MASK       (1 << IDR_EP_SHIFT)
+#define IDR_CI0_SHIFT     30
+#define IDR_CI1_SHIFT     29
+#define IDR_P1_SHIFT      1
+#define IDR_P0_SHIFT      0
+
+#define ILR_INTTGT_MASK   0x000000ff
+#define ILR_INTTGT_INT    0x00
+#define ILR_INTTGT_CINT   0x01 /* critical */
+#define ILR_INTTGT_MCP    0x02 /* machine check */
+
+/* The currently supported INTTGT values happen to be the same as QEMU's
+ * openpic output codes, but don't depend on this.  The output codes
+ * could change (unlikely, but...) or support could be added for
+ * more INTTGT values.
+ */
+static const int inttgt_output[][2] = {
+    { ILR_INTTGT_INT, OPENPIC_OUTPUT_INT },
+    { ILR_INTTGT_CINT, OPENPIC_OUTPUT_CINT },
+    { ILR_INTTGT_MCP, OPENPIC_OUTPUT_MCK },
+};
+
+static int inttgt_to_output(int inttgt)
+{
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(inttgt_output); i++) {
+        if (inttgt_output[i][0] == inttgt) {
+            return inttgt_output[i][1];
+        }
+    }
+
+    fprintf(stderr, "%s: unsupported inttgt %d\n", __func__, inttgt);
+    return OPENPIC_OUTPUT_INT;
+}
+
+static int output_to_inttgt(int output)
+{
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(inttgt_output); i++) {
+        if (inttgt_output[i][1] == output) {
+            return inttgt_output[i][0];
+        }
+    }
+
+    abort();
+}
+
+#define MSIIR_OFFSET       0x140
+#define MSIIR_SRS_SHIFT    29
+#define MSIIR_SRS_MASK     (0x7 << MSIIR_SRS_SHIFT)
+#define MSIIR_IBS_SHIFT    24
+#define MSIIR_IBS_MASK     (0x1f << MSIIR_IBS_SHIFT)
+
+static int get_current_cpu(void)
+{
+    CPUState *cpu_single_cpu;
+
+    if (!cpu_single_env) {
+        return -1;
+    }
+
+    cpu_single_cpu = ENV_GET_CPU(cpu_single_env);
+    return cpu_single_cpu->cpu_index;
+}
+
+static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr,
+                                          int idx);
+static void openpic_cpu_write_internal(void *opaque, hwaddr addr,
+                                       uint32_t val, int idx);
+
+typedef enum IRQType {
+    IRQ_TYPE_NORMAL = 0,
+    IRQ_TYPE_FSLINT,        /* FSL internal interrupt -- level only */
+    IRQ_TYPE_FSLSPECIAL,    /* FSL timer/IPI interrupt, edge, no polarity */
+} IRQType;
+
+typedef struct IRQQueue {
+    /* Round up to the nearest 64 IRQs so that the queue length
+     * won't change when moving between 32 and 64 bit hosts.
+     */
+    unsigned long queue[BITS_TO_LONGS((MAX_IRQ + 63) & ~63)];
+    int next;
+    int priority;
+} IRQQueue;
+
+typedef struct IRQSource {
+    uint32_t ivpr;  /* IRQ vector/priority register */
+    uint32_t idr;   /* IRQ destination register */
+    uint32_t destmask; /* bitmap of CPU destinations */
+    int last_cpu;
+    int output;     /* IRQ level, e.g. OPENPIC_OUTPUT_INT */
+    int pending;    /* TRUE if IRQ is pending */
+    IRQType type;
+    bool level:1;   /* level-triggered */
+    bool nomask:1;  /* critical interrupts ignore mask on some FSL MPICs */
+} IRQSource;
+
+#define IVPR_MASK_SHIFT       31
+#define IVPR_MASK_MASK        (1 << IVPR_MASK_SHIFT)
+#define IVPR_ACTIVITY_SHIFT   30
+#define IVPR_ACTIVITY_MASK    (1 << IVPR_ACTIVITY_SHIFT)
+#define IVPR_MODE_SHIFT       29
+#define IVPR_MODE_MASK        (1 << IVPR_MODE_SHIFT)
+#define IVPR_POLARITY_SHIFT   23
+#define IVPR_POLARITY_MASK    (1 << IVPR_POLARITY_SHIFT)
+#define IVPR_SENSE_SHIFT      22
+#define IVPR_SENSE_MASK       (1 << IVPR_SENSE_SHIFT)
+
+#define IVPR_PRIORITY_MASK     (0xF << 16)
+#define IVPR_PRIORITY(_ivprr_) ((int)(((_ivprr_) & IVPR_PRIORITY_MASK) >> 16))
+#define IVPR_VECTOR(opp, _ivprr_) ((_ivprr_) & (opp)->vector_mask)
+
+/* IDR[EP/CI] are only for FSL MPIC prior to v4.0 */
+#define IDR_EP      0x80000000  /* external pin */
+#define IDR_CI      0x40000000  /* critical interrupt */
+
+typedef struct IRQDest {
+    int32_t ctpr; /* CPU current task priority */
+    IRQQueue raised;
+    IRQQueue servicing;
+    qemu_irq *irqs;
+
+    /* Count of IRQ sources asserting on non-INT outputs */
+    uint32_t outputs_active[OPENPIC_OUTPUT_NB];
+} IRQDest;
+
+typedef struct OpenPICState {
+    SysBusDevice busdev;
+    MemoryRegion mem;
+
+    /* Behavior control */
+    FslMpicInfo *fsl;
+    uint32_t model;
+    uint32_t flags;
+    uint32_t nb_irqs;
+    uint32_t vid;
+    uint32_t vir; /* Vendor identification register */
+    uint32_t vector_mask;
+    uint32_t tfrr_reset;
+    uint32_t ivpr_reset;
+    uint32_t idr_reset;
+    uint32_t brr1;
+    uint32_t mpic_mode_mask;
+
+    /* Sub-regions */
+    MemoryRegion sub_io_mem[6];
+
+    /* Global registers */
+    uint32_t frr; /* Feature reporting register */
+    uint32_t gcr; /* Global configuration register  */
+    uint32_t pir; /* Processor initialization register */
+    uint32_t spve; /* Spurious vector register */
+    uint32_t tfrr; /* Timer frequency reporting register */
+    /* Source registers */
+    IRQSource src[MAX_IRQ];
+    /* Local registers per output pin */
+    IRQDest dst[MAX_CPU];
+    uint32_t nb_cpus;
+    /* Timer registers */
+    struct {
+        uint32_t tccr;  /* Global timer current count register */
+        uint32_t tbcr;  /* Global timer base count register */
+    } timers[MAX_TMR];
+    /* Shared MSI registers */
+    struct {
+        uint32_t msir;   /* Shared Message Signaled Interrupt Register */
+    } msi[MAX_MSI];
+    uint32_t max_irq;
+    uint32_t irq_ipi0;
+    uint32_t irq_tim0;
+    uint32_t irq_msi;
+} OpenPICState;
+
+static inline void IRQ_setbit(IRQQueue *q, int n_IRQ)
+{
+    set_bit(n_IRQ, q->queue);
+}
+
+static inline void IRQ_resetbit(IRQQueue *q, int n_IRQ)
+{
+    clear_bit(n_IRQ, q->queue);
+}
+
+static inline int IRQ_testbit(IRQQueue *q, int n_IRQ)
+{
+    return test_bit(n_IRQ, q->queue);
+}
+
+static void IRQ_check(OpenPICState *opp, IRQQueue *q)
+{
+    int irq = -1;
+    int next = -1;
+    int priority = -1;
+
+    for (;;) {
+        irq = find_next_bit(q->queue, opp->max_irq, irq + 1);
+        if (irq == opp->max_irq) {
+            break;
+        }
+
+        DPRINTF("IRQ_check: irq %d set ivpr_pr=%d pr=%d\n",
+                irq, IVPR_PRIORITY(opp->src[irq].ivpr), priority);
+
+        if (IVPR_PRIORITY(opp->src[irq].ivpr) > priority) {
+            next = irq;
+            priority = IVPR_PRIORITY(opp->src[irq].ivpr);
+        }
+    }
+
+    q->next = next;
+    q->priority = priority;
+}
+
+static int IRQ_get_next(OpenPICState *opp, IRQQueue *q)
+{
+    /* XXX: optimize */
+    IRQ_check(opp, q);
+
+    return q->next;
+}
+
+static void IRQ_local_pipe(OpenPICState *opp, int n_CPU, int n_IRQ,
+                           bool active, bool was_active)
+{
+    IRQDest *dst;
+    IRQSource *src;
+    int priority;
+
+    dst = &opp->dst[n_CPU];
+    src = &opp->src[n_IRQ];
+
+    DPRINTF("%s: IRQ %d active %d was %d\n",
+            __func__, n_IRQ, active, was_active);
+
+    if (src->output != OPENPIC_OUTPUT_INT) {
+        DPRINTF("%s: output %d irq %d active %d was %d count %d\n",
+                __func__, src->output, n_IRQ, active, was_active,
+                dst->outputs_active[src->output]);
+
+        /* On Freescale MPIC, critical interrupts ignore priority,
+         * IACK, EOI, etc.  Before MPIC v4.1 they also ignore
+         * masking.
+         */
+        if (active) {
+            if (!was_active && dst->outputs_active[src->output]++ == 0) {
+                DPRINTF("%s: Raise OpenPIC output %d cpu %d irq %d\n",
+                        __func__, src->output, n_CPU, n_IRQ);
+                qemu_irq_raise(dst->irqs[src->output]);
+            }
+        } else {
+            if (was_active && --dst->outputs_active[src->output] == 0) {
+                DPRINTF("%s: Lower OpenPIC output %d cpu %d irq %d\n",
+                        __func__, src->output, n_CPU, n_IRQ);
+                qemu_irq_lower(dst->irqs[src->output]);
+            }
+        }
+
+        return;
+    }
+
+    priority = IVPR_PRIORITY(src->ivpr);
+
+    /* Even if the interrupt doesn't have enough priority,
+     * it is still raised, in case ctpr is lowered later.
+     */
+    if (active) {
+        IRQ_setbit(&dst->raised, n_IRQ);
+    } else {
+        IRQ_resetbit(&dst->raised, n_IRQ);
+    }
+
+    IRQ_check(opp, &dst->raised);
+
+    if (active && priority <= dst->ctpr) {
+        DPRINTF("%s: IRQ %d priority %d too low for ctpr %d on CPU %d\n",
+                __func__, n_IRQ, priority, dst->ctpr, n_CPU);
+        active = 0;
+    }
+
+    if (active) {
+        if (IRQ_get_next(opp, &dst->servicing) >= 0 &&
+                priority <= dst->servicing.priority) {
+            DPRINTF("%s: IRQ %d is hidden by servicing IRQ %d on CPU %d\n",
+                    __func__, n_IRQ, dst->servicing.next, n_CPU);
+        } else {
+            DPRINTF("%s: Raise OpenPIC INT output cpu %d irq %d/%d\n",
+                    __func__, n_CPU, n_IRQ, dst->raised.next);
+            qemu_irq_raise(opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT]);
+        }
+    } else {
+        IRQ_get_next(opp, &dst->servicing);
+        if (dst->raised.priority > dst->ctpr &&
+                dst->raised.priority > dst->servicing.priority) {
+            DPRINTF("%s: IRQ %d inactive, IRQ %d prio %d above %d/%d, CPU %d\n",
+                    __func__, n_IRQ, dst->raised.next, dst->raised.priority,
+                    dst->ctpr, dst->servicing.priority, n_CPU);
+            /* IRQ line stays asserted */
+        } else {
+            DPRINTF("%s: IRQ %d inactive, current prio %d/%d, CPU %d\n",
+                    __func__, n_IRQ, dst->ctpr, dst->servicing.priority, n_CPU);
+            qemu_irq_lower(opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT]);
+        }
+    }
+}
+
+/* update pic state because registers for n_IRQ have changed value */
+static void openpic_update_irq(OpenPICState *opp, int n_IRQ)
+{
+    IRQSource *src;
+    bool active, was_active;
+    int i;
+
+    src = &opp->src[n_IRQ];
+    active = src->pending;
+
+    if ((src->ivpr & IVPR_MASK_MASK) && !src->nomask) {
+        /* Interrupt source is disabled */
+        DPRINTF("%s: IRQ %d is disabled\n", __func__, n_IRQ);
+        active = false;
+    }
+
+    was_active = !!(src->ivpr & IVPR_ACTIVITY_MASK);
+
+    /*
+     * We don't have a similar check for already-active because
+     * ctpr may have changed and we need to withdraw the interrupt.
+     */
+    if (!active && !was_active) {
+        DPRINTF("%s: IRQ %d is already inactive\n", __func__, n_IRQ);
+        return;
+    }
+
+    if (active) {
+        src->ivpr |= IVPR_ACTIVITY_MASK;
+    } else {
+        src->ivpr &= ~IVPR_ACTIVITY_MASK;
+    }
+
+    if (src->destmask == 0) {
+        /* No target */
+        DPRINTF("%s: IRQ %d has no target\n", __func__, n_IRQ);
+        return;
+    }
+
+    if (src->destmask == (1 << src->last_cpu)) {
+        /* Only one CPU is allowed to receive this IRQ */
+        IRQ_local_pipe(opp, src->last_cpu, n_IRQ, active, was_active);
+    } else if (!(src->ivpr & IVPR_MODE_MASK)) {
+        /* Directed delivery mode */
+        for (i = 0; i < opp->nb_cpus; i++) {
+            if (src->destmask & (1 << i)) {
+                IRQ_local_pipe(opp, i, n_IRQ, active, was_active);
+            }
+        }
+    } else {
+        /* Distributed delivery mode */
+        for (i = src->last_cpu + 1; i != src->last_cpu; i++) {
+            if (i == opp->nb_cpus) {
+                i = 0;
+            }
+            if (src->destmask & (1 << i)) {
+                IRQ_local_pipe(opp, i, n_IRQ, active, was_active);
+                src->last_cpu = i;
+                break;
+            }
+        }
+    }
+}
+
+static void openpic_set_irq(void *opaque, int n_IRQ, int level)
+{
+    OpenPICState *opp = opaque;
+    IRQSource *src;
+
+    if (n_IRQ >= MAX_IRQ) {
+        fprintf(stderr, "%s: IRQ %d out of range\n", __func__, n_IRQ);
+        abort();
+    }
+
+    src = &opp->src[n_IRQ];
+    DPRINTF("openpic: set irq %d = %d ivpr=0x%08x\n",
+            n_IRQ, level, src->ivpr);
+    if (src->level) {
+        /* level-sensitive irq */
+        src->pending = level;
+        openpic_update_irq(opp, n_IRQ);
+    } else {
+        /* edge-sensitive irq */
+        if (level) {
+            src->pending = 1;
+            openpic_update_irq(opp, n_IRQ);
+        }
+
+        if (src->output != OPENPIC_OUTPUT_INT) {
+            /* Edge-triggered interrupts shouldn't be used
+             * with non-INT delivery, but just in case,
+             * try to make it do something sane rather than
+             * cause an interrupt storm.  This is close to
+             * what you'd probably see happen in real hardware.
+             */
+            src->pending = 0;
+            openpic_update_irq(opp, n_IRQ);
+        }
+    }
+}
+
+static void openpic_reset(DeviceState *d)
+{
+    OpenPICState *opp = FROM_SYSBUS(typeof(*opp), SYS_BUS_DEVICE(d));
+    int i;
+
+    opp->gcr = GCR_RESET;
+    /* Initialise controller registers */
+    opp->frr = ((opp->nb_irqs - 1) << FRR_NIRQ_SHIFT) |
+               ((opp->nb_cpus - 1) << FRR_NCPU_SHIFT) |
+               (opp->vid << FRR_VID_SHIFT);
+
+    opp->pir = 0;
+    opp->spve = -1 & opp->vector_mask;
+    opp->tfrr = opp->tfrr_reset;
+    /* Initialise IRQ sources */
+    for (i = 0; i < opp->max_irq; i++) {
+        opp->src[i].ivpr = opp->ivpr_reset;
+        opp->src[i].idr  = opp->idr_reset;
+
+        switch (opp->src[i].type) {
+        case IRQ_TYPE_NORMAL:
+            opp->src[i].level = !!(opp->ivpr_reset & IVPR_SENSE_MASK);
+            break;
+
+        case IRQ_TYPE_FSLINT:
+            opp->src[i].ivpr |= IVPR_POLARITY_MASK;
+            break;
+
+        case IRQ_TYPE_FSLSPECIAL:
+            break;
+        }
+    }
+    /* Initialise IRQ destinations */
+    for (i = 0; i < MAX_CPU; i++) {
+        opp->dst[i].ctpr      = 15;
+        memset(&opp->dst[i].raised, 0, sizeof(IRQQueue));
+        opp->dst[i].raised.next = -1;
+        memset(&opp->dst[i].servicing, 0, sizeof(IRQQueue));
+        opp->dst[i].servicing.next = -1;
+    }
+    /* Initialise timers */
+    for (i = 0; i < MAX_TMR; i++) {
+        opp->timers[i].tccr = 0;
+        opp->timers[i].tbcr = TBCR_CI;
+    }
+    /* Go out of RESET state */
+    opp->gcr = 0;
+}
+
+static inline uint32_t read_IRQreg_idr(OpenPICState *opp, int n_IRQ)
+{
+    return opp->src[n_IRQ].idr;
+}
+
+static inline uint32_t read_IRQreg_ilr(OpenPICState *opp, int n_IRQ)
+{
+    if (opp->flags & OPENPIC_FLAG_ILR) {
+        return output_to_inttgt(opp->src[n_IRQ].output);
+    }
+
+    return 0xffffffff;
+}
+
+static inline uint32_t read_IRQreg_ivpr(OpenPICState *opp, int n_IRQ)
+{
+    return opp->src[n_IRQ].ivpr;
+}
+
+static inline void write_IRQreg_idr(OpenPICState *opp, int n_IRQ, uint32_t val)
+{
+    IRQSource *src = &opp->src[n_IRQ];
+    uint32_t normal_mask = (1UL << opp->nb_cpus) - 1;
+    uint32_t crit_mask = 0;
+    uint32_t mask = normal_mask;
+    int crit_shift = IDR_EP_SHIFT - opp->nb_cpus;
+    int i;
+
+    if (opp->flags & OPENPIC_FLAG_IDR_CRIT) {
+        crit_mask = mask << crit_shift;
+        mask |= crit_mask | IDR_EP;
+    }
+
+    src->idr = val & mask;
+    DPRINTF("Set IDR %d to 0x%08x\n", n_IRQ, src->idr);
+
+    if (opp->flags & OPENPIC_FLAG_IDR_CRIT) {
+        if (src->idr & crit_mask) {
+            if (src->idr & normal_mask) {
+                DPRINTF("%s: IRQ configured for multiple output types, using "
+                        "critical\n", __func__);
+            }
+
+            src->output = OPENPIC_OUTPUT_CINT;
+            src->nomask = true;
+            src->destmask = 0;
+
+            for (i = 0; i < opp->nb_cpus; i++) {
+                int n_ci = IDR_CI0_SHIFT - i;
+
+                if (src->idr & (1UL << n_ci)) {
+                    src->destmask |= 1UL << i;
+                }
+            }
+        } else {
+            src->output = OPENPIC_OUTPUT_INT;
+            src->nomask = false;
+            src->destmask = src->idr & normal_mask;
+        }
+    } else {
+        src->destmask = src->idr;
+    }
+}
+
+static inline void write_IRQreg_ilr(OpenPICState *opp, int n_IRQ, uint32_t val)
+{
+    if (opp->flags & OPENPIC_FLAG_ILR) {
+        IRQSource *src = &opp->src[n_IRQ];
+
+        src->output = inttgt_to_output(val & ILR_INTTGT_MASK);
+        DPRINTF("Set ILR %d to 0x%08x, output %d\n", n_IRQ, src->idr,
+                src->output);
+
+        /* TODO: on MPIC v4.0 only, set nomask for non-INT */
+    }
+}
+
+static inline void write_IRQreg_ivpr(OpenPICState *opp, int n_IRQ, uint32_t val)
+{
+    uint32_t mask;
+
+    /* NOTE when implementing newer FSL MPIC models: starting with v4.0,
+     * the polarity bit is read-only on internal interrupts.
+     */
+    mask = IVPR_MASK_MASK | IVPR_PRIORITY_MASK | IVPR_SENSE_MASK |
+           IVPR_POLARITY_MASK | opp->vector_mask;
+
+    /* ACTIVITY bit is read-only */
+    opp->src[n_IRQ].ivpr =
+        (opp->src[n_IRQ].ivpr & IVPR_ACTIVITY_MASK) | (val & mask);
+
+    /* For FSL internal interrupts, The sense bit is reserved and zero,
+     * and the interrupt is always level-triggered.  Timers and IPIs
+     * have no sense or polarity bits, and are edge-triggered.
+     */
+    switch (opp->src[n_IRQ].type) {
+    case IRQ_TYPE_NORMAL:
+        opp->src[n_IRQ].level = !!(opp->src[n_IRQ].ivpr & IVPR_SENSE_MASK);
+        break;
+
+    case IRQ_TYPE_FSLINT:
+        opp->src[n_IRQ].ivpr &= ~IVPR_SENSE_MASK;
+        break;
+
+    case IRQ_TYPE_FSLSPECIAL:
+        opp->src[n_IRQ].ivpr &= ~(IVPR_POLARITY_MASK | IVPR_SENSE_MASK);
+        break;
+    }
+
+    openpic_update_irq(opp, n_IRQ);
+    DPRINTF("Set IVPR %d to 0x%08x -> 0x%08x\n", n_IRQ, val,
+            opp->src[n_IRQ].ivpr);
+}
+
+static void openpic_gcr_write(OpenPICState *opp, uint64_t val)
+{
+    bool mpic_proxy = false;
+
+    if (val & GCR_RESET) {
+        openpic_reset(&opp->busdev.qdev);
+        return;
+    }
+
+    opp->gcr &= ~opp->mpic_mode_mask;
+    opp->gcr |= val & opp->mpic_mode_mask;
+
+    /* Set external proxy mode */
+    if ((val & opp->mpic_mode_mask) == GCR_MODE_PROXY) {
+        mpic_proxy = true;
+    }
+
+    ppce500_set_mpic_proxy(mpic_proxy);
+}
+
+static void openpic_gbl_write(void *opaque, hwaddr addr, uint64_t val,
+                              unsigned len)
+{
+    OpenPICState *opp = opaque;
+    IRQDest *dst;
+    int idx;
+
+    DPRINTF("%s: addr %#" HWADDR_PRIx " <= %08" PRIx64 "\n",
+            __func__, addr, val);
+    if (addr & 0xF) {
+        return;
+    }
+    switch (addr) {
+    case 0x00: /* Block Revision Register1 (BRR1) is Readonly */
+        break;
+    case 0x40:
+    case 0x50:
+    case 0x60:
+    case 0x70:
+    case 0x80:
+    case 0x90:
+    case 0xA0:
+    case 0xB0:
+        openpic_cpu_write_internal(opp, addr, val, get_current_cpu());
+        break;
+    case 0x1000: /* FRR */
+        break;
+    case 0x1020: /* GCR */
+        openpic_gcr_write(opp, val);
+        break;
+    case 0x1080: /* VIR */
+        break;
+    case 0x1090: /* PIR */
+        for (idx = 0; idx < opp->nb_cpus; idx++) {
+            if ((val & (1 << idx)) && !(opp->pir & (1 << idx))) {
+                DPRINTF("Raise OpenPIC RESET output for CPU %d\n", idx);
+                dst = &opp->dst[idx];
+                qemu_irq_raise(dst->irqs[OPENPIC_OUTPUT_RESET]);
+            } else if (!(val & (1 << idx)) && (opp->pir & (1 << idx))) {
+                DPRINTF("Lower OpenPIC RESET output for CPU %d\n", idx);
+                dst = &opp->dst[idx];
+                qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_RESET]);
+            }
+        }
+        opp->pir = val;
+        break;
+    case 0x10A0: /* IPI_IVPR */
+    case 0x10B0:
+    case 0x10C0:
+    case 0x10D0:
+        {
+            int idx;
+            idx = (addr - 0x10A0) >> 4;
+            write_IRQreg_ivpr(opp, opp->irq_ipi0 + idx, val);
+        }
+        break;
+    case 0x10E0: /* SPVE */
+        opp->spve = val & opp->vector_mask;
+        break;
+    default:
+        break;
+    }
+}
+
+static uint64_t openpic_gbl_read(void *opaque, hwaddr addr, unsigned len)
+{
+    OpenPICState *opp = opaque;
+    uint32_t retval;
+
+    DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr);
+    retval = 0xFFFFFFFF;
+    if (addr & 0xF) {
+        return retval;
+    }
+    switch (addr) {
+    case 0x1000: /* FRR */
+        retval = opp->frr;
+        break;
+    case 0x1020: /* GCR */
+        retval = opp->gcr;
+        break;
+    case 0x1080: /* VIR */
+        retval = opp->vir;
+        break;
+    case 0x1090: /* PIR */
+        retval = 0x00000000;
+        break;
+    case 0x00: /* Block Revision Register1 (BRR1) */
+        retval = opp->brr1;
+        break;
+    case 0x40:
+    case 0x50:
+    case 0x60:
+    case 0x70:
+    case 0x80:
+    case 0x90:
+    case 0xA0:
+    case 0xB0:
+        retval = openpic_cpu_read_internal(opp, addr, get_current_cpu());
+        break;
+    case 0x10A0: /* IPI_IVPR */
+    case 0x10B0:
+    case 0x10C0:
+    case 0x10D0:
+        {
+            int idx;
+            idx = (addr - 0x10A0) >> 4;
+            retval = read_IRQreg_ivpr(opp, opp->irq_ipi0 + idx);
+        }
+        break;
+    case 0x10E0: /* SPVE */
+        retval = opp->spve;
+        break;
+    default:
+        break;
+    }
+    DPRINTF("%s: => 0x%08x\n", __func__, retval);
+
+    return retval;
+}
+
+static void openpic_tmr_write(void *opaque, hwaddr addr, uint64_t val,
+                                unsigned len)
+{
+    OpenPICState *opp = opaque;
+    int idx;
+
+    addr += 0x10f0;
+
+    DPRINTF("%s: addr %#" HWADDR_PRIx " <= %08" PRIx64 "\n",
+            __func__, addr, val);
+    if (addr & 0xF) {
+        return;
+    }
+
+    if (addr == 0x10f0) {
+        /* TFRR */
+        opp->tfrr = val;
+        return;
+    }
+
+    idx = (addr >> 6) & 0x3;
+    addr = addr & 0x30;
+
+    switch (addr & 0x30) {
+    case 0x00: /* TCCR */
+        break;
+    case 0x10: /* TBCR */
+        if ((opp->timers[idx].tccr & TCCR_TOG) != 0 &&
+            (val & TBCR_CI) == 0 &&
+            (opp->timers[idx].tbcr & TBCR_CI) != 0) {
+            opp->timers[idx].tccr &= ~TCCR_TOG;
+        }
+        opp->timers[idx].tbcr = val;
+        break;
+    case 0x20: /* TVPR */
+        write_IRQreg_ivpr(opp, opp->irq_tim0 + idx, val);
+        break;
+    case 0x30: /* TDR */
+        write_IRQreg_idr(opp, opp->irq_tim0 + idx, val);
+        break;
+    }
+}
+
+static uint64_t openpic_tmr_read(void *opaque, hwaddr addr, unsigned len)
+{
+    OpenPICState *opp = opaque;
+    uint32_t retval = -1;
+    int idx;
+
+    DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr);
+    if (addr & 0xF) {
+        goto out;
+    }
+    idx = (addr >> 6) & 0x3;
+    if (addr == 0x0) {
+        /* TFRR */
+        retval = opp->tfrr;
+        goto out;
+    }
+    switch (addr & 0x30) {
+    case 0x00: /* TCCR */
+        retval = opp->timers[idx].tccr;
+        break;
+    case 0x10: /* TBCR */
+        retval = opp->timers[idx].tbcr;
+        break;
+    case 0x20: /* TIPV */
+        retval = read_IRQreg_ivpr(opp, opp->irq_tim0 + idx);
+        break;
+    case 0x30: /* TIDE (TIDR) */
+        retval = read_IRQreg_idr(opp, opp->irq_tim0 + idx);
+        break;
+    }
+
+out:
+    DPRINTF("%s: => 0x%08x\n", __func__, retval);
+
+    return retval;
+}
+
+static void openpic_src_write(void *opaque, hwaddr addr, uint64_t val,
+                              unsigned len)
+{
+    OpenPICState *opp = opaque;
+    int idx;
+
+    DPRINTF("%s: addr %#" HWADDR_PRIx " <= %08" PRIx64 "\n",
+            __func__, addr, val);
+
+    addr = addr & 0xffff;
+    idx = addr >> 5;
+
+    switch (addr & 0x1f) {
+    case 0x00:
+        write_IRQreg_ivpr(opp, idx, val);
+        break;
+    case 0x10:
+        write_IRQreg_idr(opp, idx, val);
+        break;
+    case 0x18:
+        write_IRQreg_ilr(opp, idx, val);
+        break;
+    }
+}
+
+static uint64_t openpic_src_read(void *opaque, uint64_t addr, unsigned len)
+{
+    OpenPICState *opp = opaque;
+    uint32_t retval;
+    int idx;
+
+    DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr);
+    retval = 0xFFFFFFFF;
+
+    addr = addr & 0xffff;
+    idx = addr >> 5;
+
+    switch (addr & 0x1f) {
+    case 0x00:
+        retval = read_IRQreg_ivpr(opp, idx);
+        break;
+    case 0x10:
+        retval = read_IRQreg_idr(opp, idx);
+        break;
+    case 0x18:
+        retval = read_IRQreg_ilr(opp, idx);
+        break;
+    }
+
+    DPRINTF("%s: => 0x%08x\n", __func__, retval);
+    return retval;
+}
+
+static void openpic_msi_write(void *opaque, hwaddr addr, uint64_t val,
+                              unsigned size)
+{
+    OpenPICState *opp = opaque;
+    int idx = opp->irq_msi;
+    int srs, ibs;
+
+    DPRINTF("%s: addr %#" HWADDR_PRIx " <= 0x%08" PRIx64 "\n",
+            __func__, addr, val);
+    if (addr & 0xF) {
+        return;
+    }
+
+    switch (addr) {
+    case MSIIR_OFFSET:
+        srs = val >> MSIIR_SRS_SHIFT;
+        idx += srs;
+        ibs = (val & MSIIR_IBS_MASK) >> MSIIR_IBS_SHIFT;
+        opp->msi[srs].msir |= 1 << ibs;
+        openpic_set_irq(opp, idx, 1);
+        break;
+    default:
+        /* most registers are read-only, thus ignored */
+        break;
+    }
+}
+
+static uint64_t openpic_msi_read(void *opaque, hwaddr addr, unsigned size)
+{
+    OpenPICState *opp = opaque;
+    uint64_t r = 0;
+    int i, srs;
+
+    DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr);
+    if (addr & 0xF) {
+        return -1;
+    }
+
+    srs = addr >> 4;
+
+    switch (addr) {
+    case 0x00:
+    case 0x10:
+    case 0x20:
+    case 0x30:
+    case 0x40:
+    case 0x50:
+    case 0x60:
+    case 0x70: /* MSIRs */
+        r = opp->msi[srs].msir;
+        /* Clear on read */
+        opp->msi[srs].msir = 0;
+        openpic_set_irq(opp, opp->irq_msi + srs, 0);
+        break;
+    case 0x120: /* MSISR */
+        for (i = 0; i < MAX_MSI; i++) {
+            r |= (opp->msi[i].msir ? 1 : 0) << i;
+        }
+        break;
+    }
+
+    return r;
+}
+
+static uint64_t openpic_summary_read(void *opaque, hwaddr addr, unsigned size)
+{
+    uint64_t r = 0;
+
+    DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr);
+
+    /* TODO: EISR/EIMR */
+
+    return r;
+}
+
+static void openpic_summary_write(void *opaque, hwaddr addr, uint64_t val,
+                                  unsigned size)
+{
+    DPRINTF("%s: addr %#" HWADDR_PRIx " <= 0x%08" PRIx64 "\n",
+            __func__, addr, val);
+
+    /* TODO: EISR/EIMR */
+}
+
+static void openpic_cpu_write_internal(void *opaque, hwaddr addr,
+                                       uint32_t val, int idx)
+{
+    OpenPICState *opp = opaque;
+    IRQSource *src;
+    IRQDest *dst;
+    int s_IRQ, n_IRQ;
+
+    DPRINTF("%s: cpu %d addr %#" HWADDR_PRIx " <= 0x%08x\n", __func__, idx,
+            addr, val);
+
+    if (idx < 0) {
+        return;
+    }
+
+    if (addr & 0xF) {
+        return;
+    }
+    dst = &opp->dst[idx];
+    addr &= 0xFF0;
+    switch (addr) {
+    case 0x40: /* IPIDR */
+    case 0x50:
+    case 0x60:
+    case 0x70:
+        idx = (addr - 0x40) >> 4;
+        /* we use IDE as mask which CPUs to deliver the IPI to still. */
+        opp->src[opp->irq_ipi0 + idx].destmask |= val;
+        openpic_set_irq(opp, opp->irq_ipi0 + idx, 1);
+        openpic_set_irq(opp, opp->irq_ipi0 + idx, 0);
+        break;
+    case 0x80: /* CTPR */
+        dst->ctpr = val & 0x0000000F;
+
+        DPRINTF("%s: set CPU %d ctpr to %d, raised %d servicing %d\n",
+                __func__, idx, dst->ctpr, dst->raised.priority,
+                dst->servicing.priority);
+
+        if (dst->raised.priority <= dst->ctpr) {
+            DPRINTF("%s: Lower OpenPIC INT output cpu %d due to ctpr\n",
+                    __func__, idx);
+            qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_INT]);
+        } else if (dst->raised.priority > dst->servicing.priority) {
+            DPRINTF("%s: Raise OpenPIC INT output cpu %d irq %d\n",
+                    __func__, idx, dst->raised.next);
+            qemu_irq_raise(dst->irqs[OPENPIC_OUTPUT_INT]);
+        }
+
+        break;
+    case 0x90: /* WHOAMI */
+        /* Read-only register */
+        break;
+    case 0xA0: /* IACK */
+        /* Read-only register */
+        break;
+    case 0xB0: /* EOI */
+        DPRINTF("EOI\n");
+        s_IRQ = IRQ_get_next(opp, &dst->servicing);
+
+        if (s_IRQ < 0) {
+            DPRINTF("%s: EOI with no interrupt in service\n", __func__);
+            break;
+        }
+
+        IRQ_resetbit(&dst->servicing, s_IRQ);
+        /* Set up next servicing IRQ */
+        s_IRQ = IRQ_get_next(opp, &dst->servicing);
+        /* Check queued interrupts. */
+        n_IRQ = IRQ_get_next(opp, &dst->raised);
+        src = &opp->src[n_IRQ];
+        if (n_IRQ != -1 &&
+            (s_IRQ == -1 ||
+             IVPR_PRIORITY(src->ivpr) > dst->servicing.priority)) {
+            DPRINTF("Raise OpenPIC INT output cpu %d irq %d\n",
+                    idx, n_IRQ);
+            qemu_irq_raise(opp->dst[idx].irqs[OPENPIC_OUTPUT_INT]);
+        }
+        break;
+    default:
+        break;
+    }
+}
+
+static void openpic_cpu_write(void *opaque, hwaddr addr, uint64_t val,
+                              unsigned len)
+{
+    openpic_cpu_write_internal(opaque, addr, val, (addr & 0x1f000) >> 12);
+}
+
+
+static uint32_t openpic_iack(OpenPICState *opp, IRQDest *dst, int cpu)
+{
+    IRQSource *src;
+    int retval, irq;
+
+    DPRINTF("Lower OpenPIC INT output\n");
+    qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_INT]);
+
+    irq = IRQ_get_next(opp, &dst->raised);
+    DPRINTF("IACK: irq=%d\n", irq);
+
+    if (irq == -1) {
+        /* No more interrupt pending */
+        return opp->spve;
+    }
+
+    src = &opp->src[irq];
+    if (!(src->ivpr & IVPR_ACTIVITY_MASK) ||
+            !(IVPR_PRIORITY(src->ivpr) > dst->ctpr)) {
+        fprintf(stderr, "%s: bad raised IRQ %d ctpr %d ivpr 0x%08x\n",
+                __func__, irq, dst->ctpr, src->ivpr);
+        openpic_update_irq(opp, irq);
+        retval = opp->spve;
+    } else {
+        /* IRQ enter servicing state */
+        IRQ_setbit(&dst->servicing, irq);
+        retval = IVPR_VECTOR(opp, src->ivpr);
+    }
+
+    if (!src->level) {
+        /* edge-sensitive IRQ */
+        src->ivpr &= ~IVPR_ACTIVITY_MASK;
+        src->pending = 0;
+        IRQ_resetbit(&dst->raised, irq);
+    }
+
+    if ((irq >= opp->irq_ipi0) &&  (irq < (opp->irq_ipi0 + MAX_IPI))) {
+        src->destmask &= ~(1 << cpu);
+        if (src->destmask && !src->level) {
+            /* trigger on CPUs that didn't know about it yet */
+            openpic_set_irq(opp, irq, 1);
+            openpic_set_irq(opp, irq, 0);
+            /* if all CPUs knew about it, set active bit again */
+            src->ivpr |= IVPR_ACTIVITY_MASK;
+        }
+    }
+
+    return retval;
+}
+
+static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr,
+                                          int idx)
+{
+    OpenPICState *opp = opaque;
+    IRQDest *dst;
+    uint32_t retval;
+
+    DPRINTF("%s: cpu %d addr %#" HWADDR_PRIx "\n", __func__, idx, addr);
+    retval = 0xFFFFFFFF;
+
+    if (idx < 0) {
+        return retval;
+    }
+
+    if (addr & 0xF) {
+        return retval;
+    }
+    dst = &opp->dst[idx];
+    addr &= 0xFF0;
+    switch (addr) {
+    case 0x80: /* CTPR */
+        retval = dst->ctpr;
+        break;
+    case 0x90: /* WHOAMI */
+        retval = idx;
+        break;
+    case 0xA0: /* IACK */
+        retval = openpic_iack(opp, dst, idx);
+        break;
+    case 0xB0: /* EOI */
+        retval = 0;
+        break;
+    default:
+        break;
+    }
+    DPRINTF("%s: => 0x%08x\n", __func__, retval);
+
+    return retval;
+}
+
+static uint64_t openpic_cpu_read(void *opaque, hwaddr addr, unsigned len)
+{
+    return openpic_cpu_read_internal(opaque, addr, (addr & 0x1f000) >> 12);
+}
+
+static const MemoryRegionOps openpic_glb_ops_le = {
+    .write = openpic_gbl_write,
+    .read  = openpic_gbl_read,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static const MemoryRegionOps openpic_glb_ops_be = {
+    .write = openpic_gbl_write,
+    .read  = openpic_gbl_read,
+    .endianness = DEVICE_BIG_ENDIAN,
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static const MemoryRegionOps openpic_tmr_ops_le = {
+    .write = openpic_tmr_write,
+    .read  = openpic_tmr_read,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static const MemoryRegionOps openpic_tmr_ops_be = {
+    .write = openpic_tmr_write,
+    .read  = openpic_tmr_read,
+    .endianness = DEVICE_BIG_ENDIAN,
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static const MemoryRegionOps openpic_cpu_ops_le = {
+    .write = openpic_cpu_write,
+    .read  = openpic_cpu_read,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static const MemoryRegionOps openpic_cpu_ops_be = {
+    .write = openpic_cpu_write,
+    .read  = openpic_cpu_read,
+    .endianness = DEVICE_BIG_ENDIAN,
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static const MemoryRegionOps openpic_src_ops_le = {
+    .write = openpic_src_write,
+    .read  = openpic_src_read,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static const MemoryRegionOps openpic_src_ops_be = {
+    .write = openpic_src_write,
+    .read  = openpic_src_read,
+    .endianness = DEVICE_BIG_ENDIAN,
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static const MemoryRegionOps openpic_msi_ops_be = {
+    .read = openpic_msi_read,
+    .write = openpic_msi_write,
+    .endianness = DEVICE_BIG_ENDIAN,
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static const MemoryRegionOps openpic_summary_ops_be = {
+    .read = openpic_summary_read,
+    .write = openpic_summary_write,
+    .endianness = DEVICE_BIG_ENDIAN,
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static void openpic_save_IRQ_queue(QEMUFile* f, IRQQueue *q)
+{
+    unsigned int i;
+
+    for (i = 0; i < ARRAY_SIZE(q->queue); i++) {
+        /* Always put the lower half of a 64-bit long first, in case we
+         * restore on a 32-bit host.  The least significant bits correspond
+         * to lower IRQ numbers in the bitmap.
+         */
+        qemu_put_be32(f, (uint32_t)q->queue[i]);
+#if LONG_MAX > 0x7FFFFFFF
+        qemu_put_be32(f, (uint32_t)(q->queue[i] >> 32));
+#endif
+    }
+
+    qemu_put_sbe32s(f, &q->next);
+    qemu_put_sbe32s(f, &q->priority);
+}
+
+static void openpic_save(QEMUFile* f, void *opaque)
+{
+    OpenPICState *opp = (OpenPICState *)opaque;
+    unsigned int i;
+
+    qemu_put_be32s(f, &opp->gcr);
+    qemu_put_be32s(f, &opp->vir);
+    qemu_put_be32s(f, &opp->pir);
+    qemu_put_be32s(f, &opp->spve);
+    qemu_put_be32s(f, &opp->tfrr);
+
+    qemu_put_be32s(f, &opp->nb_cpus);
+
+    for (i = 0; i < opp->nb_cpus; i++) {
+        qemu_put_sbe32s(f, &opp->dst[i].ctpr);
+        openpic_save_IRQ_queue(f, &opp->dst[i].raised);
+        openpic_save_IRQ_queue(f, &opp->dst[i].servicing);
+        qemu_put_buffer(f, (uint8_t *)&opp->dst[i].outputs_active,
+                        sizeof(opp->dst[i].outputs_active));
+    }
+
+    for (i = 0; i < MAX_TMR; i++) {
+        qemu_put_be32s(f, &opp->timers[i].tccr);
+        qemu_put_be32s(f, &opp->timers[i].tbcr);
+    }
+
+    for (i = 0; i < opp->max_irq; i++) {
+        qemu_put_be32s(f, &opp->src[i].ivpr);
+        qemu_put_be32s(f, &opp->src[i].idr);
+        qemu_get_be32s(f, &opp->src[i].destmask);
+        qemu_put_sbe32s(f, &opp->src[i].last_cpu);
+        qemu_put_sbe32s(f, &opp->src[i].pending);
+    }
+}
+
+static void openpic_load_IRQ_queue(QEMUFile* f, IRQQueue *q)
+{
+    unsigned int i;
+
+    for (i = 0; i < ARRAY_SIZE(q->queue); i++) {
+        unsigned long val;
+
+        val = qemu_get_be32(f);
+#if LONG_MAX > 0x7FFFFFFF
+        val <<= 32;
+        val |= qemu_get_be32(f);
+#endif
+
+        q->queue[i] = val;
+    }
+
+    qemu_get_sbe32s(f, &q->next);
+    qemu_get_sbe32s(f, &q->priority);
+}
+
+static int openpic_load(QEMUFile* f, void *opaque, int version_id)
+{
+    OpenPICState *opp = (OpenPICState *)opaque;
+    unsigned int i;
+
+    if (version_id != 1) {
+        return -EINVAL;
+    }
+
+    qemu_get_be32s(f, &opp->gcr);
+    qemu_get_be32s(f, &opp->vir);
+    qemu_get_be32s(f, &opp->pir);
+    qemu_get_be32s(f, &opp->spve);
+    qemu_get_be32s(f, &opp->tfrr);
+
+    qemu_get_be32s(f, &opp->nb_cpus);
+
+    for (i = 0; i < opp->nb_cpus; i++) {
+        qemu_get_sbe32s(f, &opp->dst[i].ctpr);
+        openpic_load_IRQ_queue(f, &opp->dst[i].raised);
+        openpic_load_IRQ_queue(f, &opp->dst[i].servicing);
+        qemu_get_buffer(f, (uint8_t *)&opp->dst[i].outputs_active,
+                        sizeof(opp->dst[i].outputs_active));
+    }
+
+    for (i = 0; i < MAX_TMR; i++) {
+        qemu_get_be32s(f, &opp->timers[i].tccr);
+        qemu_get_be32s(f, &opp->timers[i].tbcr);
+    }
+
+    for (i = 0; i < opp->max_irq; i++) {
+        uint32_t val;
+
+        val = qemu_get_be32(f);
+        write_IRQreg_idr(opp, i, val);
+        val = qemu_get_be32(f);
+        write_IRQreg_ivpr(opp, i, val);
+
+        qemu_get_be32s(f, &opp->src[i].ivpr);
+        qemu_get_be32s(f, &opp->src[i].idr);
+        qemu_get_be32s(f, &opp->src[i].destmask);
+        qemu_get_sbe32s(f, &opp->src[i].last_cpu);
+        qemu_get_sbe32s(f, &opp->src[i].pending);
+    }
+
+    return 0;
+}
+
+typedef struct MemReg {
+    const char             *name;
+    MemoryRegionOps const  *ops;
+    hwaddr      start_addr;
+    ram_addr_t              size;
+} MemReg;
+
+static void fsl_common_init(OpenPICState *opp)
+{
+    int i;
+    int virq = MAX_SRC;
+
+    opp->vid = VID_REVISION_1_2;
+    opp->vir = VIR_GENERIC;
+    opp->vector_mask = 0xFFFF;
+    opp->tfrr_reset = 0;
+    opp->ivpr_reset = IVPR_MASK_MASK;
+    opp->idr_reset = 1 << 0;
+    opp->max_irq = MAX_IRQ;
+
+    opp->irq_ipi0 = virq;
+    virq += MAX_IPI;
+    opp->irq_tim0 = virq;
+    virq += MAX_TMR;
+
+    assert(virq <= MAX_IRQ);
+
+    opp->irq_msi = 224;
+
+    msi_supported = true;
+    for (i = 0; i < opp->fsl->max_ext; i++) {
+        opp->src[i].level = false;
+    }
+
+    /* Internal interrupts, including message and MSI */
+    for (i = 16; i < MAX_SRC; i++) {
+        opp->src[i].type = IRQ_TYPE_FSLINT;
+        opp->src[i].level = true;
+    }
+
+    /* timers and IPIs */
+    for (i = MAX_SRC; i < virq; i++) {
+        opp->src[i].type = IRQ_TYPE_FSLSPECIAL;
+        opp->src[i].level = false;
+    }
+}
+
+static void map_list(OpenPICState *opp, const MemReg *list, int *count)
+{
+    while (list->name) {
+        assert(*count < ARRAY_SIZE(opp->sub_io_mem));
+
+        memory_region_init_io(&opp->sub_io_mem[*count], list->ops, opp,
+                              list->name, list->size);
+
+        memory_region_add_subregion(&opp->mem, list->start_addr,
+                                    &opp->sub_io_mem[*count]);
+
+        (*count)++;
+        list++;
+    }
+}
+
+static int openpic_init(SysBusDevice *dev)
+{
+    OpenPICState *opp = FROM_SYSBUS(typeof (*opp), dev);
+    int i, j;
+    int list_count = 0;
+    static const MemReg list_le[] = {
+        {"glb", &openpic_glb_ops_le,
+                OPENPIC_GLB_REG_START, OPENPIC_GLB_REG_SIZE},
+        {"tmr", &openpic_tmr_ops_le,
+                OPENPIC_TMR_REG_START, OPENPIC_TMR_REG_SIZE},
+        {"src", &openpic_src_ops_le,
+                OPENPIC_SRC_REG_START, OPENPIC_SRC_REG_SIZE},
+        {"cpu", &openpic_cpu_ops_le,
+                OPENPIC_CPU_REG_START, OPENPIC_CPU_REG_SIZE},
+        {NULL}
+    };
+    static const MemReg list_be[] = {
+        {"glb", &openpic_glb_ops_be,
+                OPENPIC_GLB_REG_START, OPENPIC_GLB_REG_SIZE},
+        {"tmr", &openpic_tmr_ops_be,
+                OPENPIC_TMR_REG_START, OPENPIC_TMR_REG_SIZE},
+        {"src", &openpic_src_ops_be,
+                OPENPIC_SRC_REG_START, OPENPIC_SRC_REG_SIZE},
+        {"cpu", &openpic_cpu_ops_be,
+                OPENPIC_CPU_REG_START, OPENPIC_CPU_REG_SIZE},
+        {NULL}
+    };
+    static const MemReg list_fsl[] = {
+        {"msi", &openpic_msi_ops_be,
+                OPENPIC_MSI_REG_START, OPENPIC_MSI_REG_SIZE},
+        {"summary", &openpic_summary_ops_be,
+                OPENPIC_SUMMARY_REG_START, OPENPIC_SUMMARY_REG_SIZE},
+        {NULL}
+    };
+
+    memory_region_init(&opp->mem, "openpic", 0x40000);
+
+    switch (opp->model) {
+    case OPENPIC_MODEL_FSL_MPIC_20:
+    default:
+        opp->fsl = &fsl_mpic_20;
+        opp->brr1 = 0x00400200;
+        opp->flags |= OPENPIC_FLAG_IDR_CRIT;
+        opp->nb_irqs = 80;
+        opp->mpic_mode_mask = GCR_MODE_MIXED;
+
+        fsl_common_init(opp);
+        map_list(opp, list_be, &list_count);
+        map_list(opp, list_fsl, &list_count);
+
+        break;
+
+    case OPENPIC_MODEL_FSL_MPIC_42:
+        opp->fsl = &fsl_mpic_42;
+        opp->brr1 = 0x00400402;
+        opp->flags |= OPENPIC_FLAG_ILR;
+        opp->nb_irqs = 196;
+        opp->mpic_mode_mask = GCR_MODE_PROXY;
+
+        fsl_common_init(opp);
+        map_list(opp, list_be, &list_count);
+        map_list(opp, list_fsl, &list_count);
+
+        break;
+
+    case OPENPIC_MODEL_RAVEN:
+        opp->nb_irqs = RAVEN_MAX_EXT;
+        opp->vid = VID_REVISION_1_3;
+        opp->vir = VIR_GENERIC;
+        opp->vector_mask = 0xFF;
+        opp->tfrr_reset = 4160000;
+        opp->ivpr_reset = IVPR_MASK_MASK | IVPR_MODE_MASK;
+        opp->idr_reset = 0;
+        opp->max_irq = RAVEN_MAX_IRQ;
+        opp->irq_ipi0 = RAVEN_IPI_IRQ;
+        opp->irq_tim0 = RAVEN_TMR_IRQ;
+        opp->brr1 = -1;
+        opp->mpic_mode_mask = GCR_MODE_MIXED;
+
+        /* Only UP supported today */
+        if (opp->nb_cpus != 1) {
+            return -EINVAL;
+        }
+
+        map_list(opp, list_le, &list_count);
+        break;
+    }
+
+    for (i = 0; i < opp->nb_cpus; i++) {
+        opp->dst[i].irqs = g_new(qemu_irq, OPENPIC_OUTPUT_NB);
+        for (j = 0; j < OPENPIC_OUTPUT_NB; j++) {
+            sysbus_init_irq(dev, &opp->dst[i].irqs[j]);
+        }
+    }
+
+    register_savevm(&opp->busdev.qdev, "openpic", 0, 2,
+                    openpic_save, openpic_load, opp);
+
+    sysbus_init_mmio(dev, &opp->mem);
+    qdev_init_gpio_in(&dev->qdev, openpic_set_irq, opp->max_irq);
+
+    return 0;
+}
+
+static Property openpic_properties[] = {
+    DEFINE_PROP_UINT32("model", OpenPICState, model, OPENPIC_MODEL_FSL_MPIC_20),
+    DEFINE_PROP_UINT32("nb_cpus", OpenPICState, nb_cpus, 1),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void openpic_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = openpic_init;
+    dc->props = openpic_properties;
+    dc->reset = openpic_reset;
+}
+
+static const TypeInfo openpic_info = {
+    .name          = "openpic",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(OpenPICState),
+    .class_init    = openpic_class_init,
+};
+
+static void openpic_register_types(void)
+{
+    type_register_static(&openpic_info);
+}
+
+type_init(openpic_register_types)
diff --git a/hw/intc/pl190.c b/hw/intc/pl190.c
new file mode 100644 (file)
index 0000000..9610673
--- /dev/null
@@ -0,0 +1,289 @@
+/*
+ * Arm PrimeCell PL190 Vector Interrupt Controller
+ *
+ * Copyright (c) 2006 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the GPL.
+ */
+
+#include "hw/sysbus.h"
+
+/* The number of virtual priority levels.  16 user vectors plus the
+   unvectored IRQ.  Chained interrupts would require an additional level
+   if implemented.  */
+
+#define PL190_NUM_PRIO 17
+
+typedef struct {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    uint32_t level;
+    uint32_t soft_level;
+    uint32_t irq_enable;
+    uint32_t fiq_select;
+    uint8_t vect_control[16];
+    uint32_t vect_addr[PL190_NUM_PRIO];
+    /* Mask containing interrupts with higher priority than this one.  */
+    uint32_t prio_mask[PL190_NUM_PRIO + 1];
+    int protected;
+    /* Current priority level.  */
+    int priority;
+    int prev_prio[PL190_NUM_PRIO];
+    qemu_irq irq;
+    qemu_irq fiq;
+} pl190_state;
+
+static const unsigned char pl190_id[] =
+{ 0x90, 0x11, 0x04, 0x00, 0x0D, 0xf0, 0x05, 0xb1 };
+
+static inline uint32_t pl190_irq_level(pl190_state *s)
+{
+    return (s->level | s->soft_level) & s->irq_enable & ~s->fiq_select;
+}
+
+/* Update interrupts.  */
+static void pl190_update(pl190_state *s)
+{
+    uint32_t level = pl190_irq_level(s);
+    int set;
+
+    set = (level & s->prio_mask[s->priority]) != 0;
+    qemu_set_irq(s->irq, set);
+    set = ((s->level | s->soft_level) & s->fiq_select) != 0;
+    qemu_set_irq(s->fiq, set);
+}
+
+static void pl190_set_irq(void *opaque, int irq, int level)
+{
+    pl190_state *s = (pl190_state *)opaque;
+
+    if (level)
+        s->level |= 1u << irq;
+    else
+        s->level &= ~(1u << irq);
+    pl190_update(s);
+}
+
+static void pl190_update_vectors(pl190_state *s)
+{
+    uint32_t mask;
+    int i;
+    int n;
+
+    mask = 0;
+    for (i = 0; i < 16; i++)
+      {
+        s->prio_mask[i] = mask;
+        if (s->vect_control[i] & 0x20)
+          {
+            n = s->vect_control[i] & 0x1f;
+            mask |= 1 << n;
+          }
+      }
+    s->prio_mask[16] = mask;
+    pl190_update(s);
+}
+
+static uint64_t pl190_read(void *opaque, hwaddr offset,
+                           unsigned size)
+{
+    pl190_state *s = (pl190_state *)opaque;
+    int i;
+
+    if (offset >= 0xfe0 && offset < 0x1000) {
+        return pl190_id[(offset - 0xfe0) >> 2];
+    }
+    if (offset >= 0x100 && offset < 0x140) {
+        return s->vect_addr[(offset - 0x100) >> 2];
+    }
+    if (offset >= 0x200 && offset < 0x240) {
+        return s->vect_control[(offset - 0x200) >> 2];
+    }
+    switch (offset >> 2) {
+    case 0: /* IRQSTATUS */
+        return pl190_irq_level(s);
+    case 1: /* FIQSATUS */
+        return (s->level | s->soft_level) & s->fiq_select;
+    case 2: /* RAWINTR */
+        return s->level | s->soft_level;
+    case 3: /* INTSELECT */
+        return s->fiq_select;
+    case 4: /* INTENABLE */
+        return s->irq_enable;
+    case 6: /* SOFTINT */
+        return s->soft_level;
+    case 8: /* PROTECTION */
+        return s->protected;
+    case 12: /* VECTADDR */
+        /* Read vector address at the start of an ISR.  Increases the
+         * current priority level to that of the current interrupt.
+         *
+         * Since an enabled interrupt X at priority P causes prio_mask[Y]
+         * to have bit X set for all Y > P, this loop will stop with
+         * i == the priority of the highest priority set interrupt.
+         */
+        for (i = 0; i < s->priority; i++) {
+            if ((s->level | s->soft_level) & s->prio_mask[i + 1]) {
+                break;
+            }
+        }
+
+        /* Reading this value with no pending interrupts is undefined.
+           We return the default address.  */
+        if (i == PL190_NUM_PRIO)
+          return s->vect_addr[16];
+        if (i < s->priority)
+          {
+            s->prev_prio[i] = s->priority;
+            s->priority = i;
+            pl190_update(s);
+          }
+        return s->vect_addr[s->priority];
+    case 13: /* DEFVECTADDR */
+        return s->vect_addr[16];
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "pl190_read: Bad offset %x\n", (int)offset);
+        return 0;
+    }
+}
+
+static void pl190_write(void *opaque, hwaddr offset,
+                        uint64_t val, unsigned size)
+{
+    pl190_state *s = (pl190_state *)opaque;
+
+    if (offset >= 0x100 && offset < 0x140) {
+        s->vect_addr[(offset - 0x100) >> 2] = val;
+        pl190_update_vectors(s);
+        return;
+    }
+    if (offset >= 0x200 && offset < 0x240) {
+        s->vect_control[(offset - 0x200) >> 2] = val;
+        pl190_update_vectors(s);
+        return;
+    }
+    switch (offset >> 2) {
+    case 0: /* SELECT */
+        /* This is a readonly register, but linux tries to write to it
+           anyway.  Ignore the write.  */
+        break;
+    case 3: /* INTSELECT */
+        s->fiq_select = val;
+        break;
+    case 4: /* INTENABLE */
+        s->irq_enable |= val;
+        break;
+    case 5: /* INTENCLEAR */
+        s->irq_enable &= ~val;
+        break;
+    case 6: /* SOFTINT */
+        s->soft_level |= val;
+        break;
+    case 7: /* SOFTINTCLEAR */
+        s->soft_level &= ~val;
+        break;
+    case 8: /* PROTECTION */
+        /* TODO: Protection (supervisor only access) is not implemented.  */
+        s->protected = val & 1;
+        break;
+    case 12: /* VECTADDR */
+        /* Restore the previous priority level.  The value written is
+           ignored.  */
+        if (s->priority < PL190_NUM_PRIO)
+            s->priority = s->prev_prio[s->priority];
+        break;
+    case 13: /* DEFVECTADDR */
+        s->vect_addr[16] = val;
+        break;
+    case 0xc0: /* ITCR */
+        if (val) {
+            qemu_log_mask(LOG_UNIMP, "pl190: Test mode not implemented\n");
+        }
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                     "pl190_write: Bad offset %x\n", (int)offset);
+        return;
+    }
+    pl190_update(s);
+}
+
+static const MemoryRegionOps pl190_ops = {
+    .read = pl190_read,
+    .write = pl190_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void pl190_reset(DeviceState *d)
+{
+  pl190_state *s = DO_UPCAST(pl190_state, busdev.qdev, d);
+  int i;
+
+  for (i = 0; i < 16; i++)
+    {
+      s->vect_addr[i] = 0;
+      s->vect_control[i] = 0;
+    }
+  s->vect_addr[16] = 0;
+  s->prio_mask[17] = 0xffffffff;
+  s->priority = PL190_NUM_PRIO;
+  pl190_update_vectors(s);
+}
+
+static int pl190_init(SysBusDevice *dev)
+{
+    pl190_state *s = FROM_SYSBUS(pl190_state, dev);
+
+    memory_region_init_io(&s->iomem, &pl190_ops, s, "pl190", 0x1000);
+    sysbus_init_mmio(dev, &s->iomem);
+    qdev_init_gpio_in(&dev->qdev, pl190_set_irq, 32);
+    sysbus_init_irq(dev, &s->irq);
+    sysbus_init_irq(dev, &s->fiq);
+    return 0;
+}
+
+static const VMStateDescription vmstate_pl190 = {
+    .name = "pl190",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(level, pl190_state),
+        VMSTATE_UINT32(soft_level, pl190_state),
+        VMSTATE_UINT32(irq_enable, pl190_state),
+        VMSTATE_UINT32(fiq_select, pl190_state),
+        VMSTATE_UINT8_ARRAY(vect_control, pl190_state, 16),
+        VMSTATE_UINT32_ARRAY(vect_addr, pl190_state, PL190_NUM_PRIO),
+        VMSTATE_UINT32_ARRAY(prio_mask, pl190_state, PL190_NUM_PRIO+1),
+        VMSTATE_INT32(protected, pl190_state),
+        VMSTATE_INT32(priority, pl190_state),
+        VMSTATE_INT32_ARRAY(prev_prio, pl190_state, PL190_NUM_PRIO),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+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 const TypeInfo pl190_info = {
+    .name          = "pl190",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(pl190_state),
+    .class_init    = pl190_class_init,
+};
+
+static void pl190_register_types(void)
+{
+    type_register_static(&pl190_info);
+}
+
+type_init(pl190_register_types)
diff --git a/hw/intc/puv3_intc.c b/hw/intc/puv3_intc.c
new file mode 100644 (file)
index 0000000..0cd5e9e
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * INTC device simulation in PKUnity SoC
+ *
+ * Copyright (C) 2010-2012 Guan Xuetao
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation, or any later version.
+ * See the COPYING file in the top-level directory.
+ */
+#include "hw/sysbus.h"
+
+#undef DEBUG_PUV3
+#include "hw/unicore32/puv3.h"
+
+typedef struct {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    qemu_irq parent_irq;
+
+    uint32_t reg_ICMR;
+    uint32_t reg_ICPR;
+} PUV3INTCState;
+
+/* Update interrupt status after enabled or pending bits have been changed.  */
+static void puv3_intc_update(PUV3INTCState *s)
+{
+    if (s->reg_ICMR & s->reg_ICPR) {
+        qemu_irq_raise(s->parent_irq);
+    } else {
+        qemu_irq_lower(s->parent_irq);
+    }
+}
+
+/* Process a change in an external INTC input. */
+static void puv3_intc_handler(void *opaque, int irq, int level)
+{
+    PUV3INTCState *s = opaque;
+
+    DPRINTF("irq 0x%x, level 0x%x\n", irq, level);
+    if (level) {
+        s->reg_ICPR |= (1 << irq);
+    } else {
+        s->reg_ICPR &= ~(1 << irq);
+    }
+    puv3_intc_update(s);
+}
+
+static uint64_t puv3_intc_read(void *opaque, hwaddr offset,
+        unsigned size)
+{
+    PUV3INTCState *s = opaque;
+    uint32_t ret = 0;
+
+    switch (offset) {
+    case 0x04: /* INTC_ICMR */
+        ret = s->reg_ICMR;
+        break;
+    case 0x0c: /* INTC_ICIP */
+        ret = s->reg_ICPR; /* the same value with ICPR */
+        break;
+    default:
+        DPRINTF("Bad offset %x\n", (int)offset);
+    }
+    DPRINTF("offset 0x%x, value 0x%x\n", offset, ret);
+    return ret;
+}
+
+static void puv3_intc_write(void *opaque, hwaddr offset,
+        uint64_t value, unsigned size)
+{
+    PUV3INTCState *s = opaque;
+
+    DPRINTF("offset 0x%x, value 0x%x\n", offset, value);
+    switch (offset) {
+    case 0x00: /* INTC_ICLR */
+    case 0x14: /* INTC_ICCR */
+        break;
+    case 0x04: /* INTC_ICMR */
+        s->reg_ICMR = value;
+        break;
+    default:
+        DPRINTF("Bad offset 0x%x\n", (int)offset);
+        return;
+    }
+    puv3_intc_update(s);
+}
+
+static const MemoryRegionOps puv3_intc_ops = {
+    .read = puv3_intc_read,
+    .write = puv3_intc_write,
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int puv3_intc_init(SysBusDevice *dev)
+{
+    PUV3INTCState *s = FROM_SYSBUS(PUV3INTCState, dev);
+
+    qdev_init_gpio_in(&s->busdev.qdev, puv3_intc_handler, PUV3_IRQS_NR);
+    sysbus_init_irq(&s->busdev, &s->parent_irq);
+
+    s->reg_ICMR = 0;
+    s->reg_ICPR = 0;
+
+    memory_region_init_io(&s->iomem, &puv3_intc_ops, s, "puv3_intc",
+            PUV3_REGS_OFFSET);
+    sysbus_init_mmio(dev, &s->iomem);
+
+    return 0;
+}
+
+static void puv3_intc_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sdc->init = puv3_intc_init;
+}
+
+static const TypeInfo puv3_intc_info = {
+    .name = "puv3_intc",
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(PUV3INTCState),
+    .class_init = puv3_intc_class_init,
+};
+
+static void puv3_intc_register_type(void)
+{
+    type_register_static(&puv3_intc_info);
+}
+
+type_init(puv3_intc_register_type)
diff --git a/hw/intc/realview_gic.c b/hw/intc/realview_gic.c
new file mode 100644 (file)
index 0000000..0ec30ca
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * ARM RealView Emulation Baseboard Interrupt Controller
+ *
+ * Copyright (c) 2006-2007 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the GPL.
+ */
+
+#include "hw/sysbus.h"
+
+typedef struct {
+    SysBusDevice busdev;
+    DeviceState *gic;
+    MemoryRegion container;
+} RealViewGICState;
+
+static void realview_gic_set_irq(void *opaque, int irq, int level)
+{
+    RealViewGICState *s = (RealViewGICState *)opaque;
+    qemu_set_irq(qdev_get_gpio_in(s->gic, irq), level);
+}
+
+static int realview_gic_init(SysBusDevice *dev)
+{
+    RealViewGICState *s = FROM_SYSBUS(RealViewGICState, dev);
+    SysBusDevice *busdev;
+    /* 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.
+     */
+    int numirq = 96;
+
+    s->gic = qdev_create(NULL, "arm_gic");
+    qdev_prop_set_uint32(s->gic, "num-cpu", 1);
+    qdev_prop_set_uint32(s->gic, "num-irq", numirq);
+    qdev_init_nofail(s->gic);
+    busdev = SYS_BUS_DEVICE(s->gic);
+
+    /* Pass through outbound IRQ lines from the GIC */
+    sysbus_pass_irq(dev, busdev);
+
+    /* Pass through inbound GPIO lines to the GIC */
+    qdev_init_gpio_in(&s->busdev.qdev, realview_gic_set_irq, numirq - 32);
+
+    memory_region_init(&s->container, "realview-gic-container", 0x2000);
+    memory_region_add_subregion(&s->container, 0,
+                                sysbus_mmio_get_region(busdev, 1));
+    memory_region_add_subregion(&s->container, 0x1000,
+                                sysbus_mmio_get_region(busdev, 0));
+    sysbus_init_mmio(dev, &s->container);
+    return 0;
+}
+
+static void realview_gic_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sdc->init = realview_gic_init;
+}
+
+static const 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_types(void)
+{
+    type_register_static(&realview_gic_info);
+}
+
+type_init(realview_gic_register_types)
diff --git a/hw/intc/sbi.c b/hw/intc/sbi.c
new file mode 100644 (file)
index 0000000..8795749
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * QEMU Sparc SBI interrupt controller emulation
+ *
+ * Based on slavio_intctl, copyright (c) 2003-2005 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.
+ */
+
+#include "hw/sysbus.h"
+
+//#define DEBUG_IRQ
+
+#ifdef DEBUG_IRQ
+#define DPRINTF(fmt, ...)                                       \
+    do { printf("IRQ: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...)
+#endif
+
+#define MAX_CPUS 16
+
+#define SBI_NREGS 16
+
+typedef struct SBIState {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    uint32_t regs[SBI_NREGS];
+    uint32_t intreg_pending[MAX_CPUS];
+    qemu_irq cpu_irqs[MAX_CPUS];
+    uint32_t pil_out[MAX_CPUS];
+} SBIState;
+
+#define SBI_SIZE (SBI_NREGS * 4)
+
+static void sbi_set_irq(void *opaque, int irq, int level)
+{
+}
+
+static uint64_t sbi_mem_read(void *opaque, hwaddr addr,
+                             unsigned size)
+{
+    SBIState *s = opaque;
+    uint32_t saddr, ret;
+
+    saddr = addr >> 2;
+    switch (saddr) {
+    default:
+        ret = s->regs[saddr];
+        break;
+    }
+    DPRINTF("read system reg 0x" TARGET_FMT_plx " = %x\n", addr, ret);
+
+    return ret;
+}
+
+static void sbi_mem_write(void *opaque, hwaddr addr,
+                          uint64_t val, unsigned dize)
+{
+    SBIState *s = opaque;
+    uint32_t saddr;
+
+    saddr = addr >> 2;
+    DPRINTF("write system reg 0x" TARGET_FMT_plx " = %x\n", addr, (int)val);
+    switch (saddr) {
+    default:
+        s->regs[saddr] = val;
+        break;
+    }
+}
+
+static const MemoryRegionOps sbi_mem_ops = {
+    .read = sbi_mem_read,
+    .write = sbi_mem_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static const VMStateDescription vmstate_sbi = {
+    .name ="sbi",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT32_ARRAY(intreg_pending, SBIState, MAX_CPUS),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void sbi_reset(DeviceState *d)
+{
+    SBIState *s = container_of(d, SBIState, busdev.qdev);
+    unsigned int i;
+
+    for (i = 0; i < MAX_CPUS; i++) {
+        s->intreg_pending[i] = 0;
+    }
+}
+
+static int sbi_init1(SysBusDevice *dev)
+{
+    SBIState *s = FROM_SYSBUS(SBIState, dev);
+    unsigned int i;
+
+    qdev_init_gpio_in(&dev->qdev, sbi_set_irq, 32 + MAX_CPUS);
+    for (i = 0; i < MAX_CPUS; i++) {
+        sysbus_init_irq(dev, &s->cpu_irqs[i]);
+    }
+
+    memory_region_init_io(&s->iomem, &sbi_mem_ops, s, "sbi", SBI_SIZE);
+    sysbus_init_mmio(dev, &s->iomem);
+
+    return 0;
+}
+
+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 const TypeInfo sbi_info = {
+    .name          = "sbi",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(SBIState),
+    .class_init    = sbi_class_init,
+};
+
+static void sbi_register_types(void)
+{
+    type_register_static(&sbi_info);
+}
+
+type_init(sbi_register_types)
diff --git a/hw/intc/sh_intc.c b/hw/intc/sh_intc.c
new file mode 100644 (file)
index 0000000..050bfb6
--- /dev/null
@@ -0,0 +1,513 @@
+/*
+ * SuperH interrupt controller module
+ *
+ * Copyright (c) 2007 Magnus Damm
+ * Based on sh_timer.c and arm_timer.c by Paul Brook
+ * Copyright (c) 2005-2006 CodeSourcery.
+ *
+ * This code is licensed under the GPL.
+ */
+
+#include "hw/sh4/sh_intc.h"
+#include "hw/hw.h"
+#include "hw/sh4/sh.h"
+
+//#define DEBUG_INTC
+//#define DEBUG_INTC_SOURCES
+
+#define INTC_A7(x) ((x) & 0x1fffffff)
+
+void sh_intc_toggle_source(struct intc_source *source,
+                          int enable_adj, int assert_adj)
+{
+    int enable_changed = 0;
+    int pending_changed = 0;
+    int old_pending;
+
+    if ((source->enable_count == source->enable_max) && (enable_adj == -1))
+        enable_changed = -1;
+
+    source->enable_count += enable_adj;
+
+    if (source->enable_count == source->enable_max)
+        enable_changed = 1;
+
+    source->asserted += assert_adj;
+
+    old_pending = source->pending;
+    source->pending = source->asserted &&
+      (source->enable_count == source->enable_max);
+
+    if (old_pending != source->pending)
+        pending_changed = 1;
+
+    if (pending_changed) {
+        CPUState *cpu = CPU(sh_env_get_cpu(first_cpu));
+        if (source->pending) {
+            source->parent->pending++;
+            if (source->parent->pending == 1) {
+                cpu_interrupt(cpu, CPU_INTERRUPT_HARD);
+            }
+        } else {
+            source->parent->pending--;
+            if (source->parent->pending == 0) {
+                cpu_reset_interrupt(cpu, CPU_INTERRUPT_HARD);
+            }
+       }
+    }
+
+  if (enable_changed || assert_adj || pending_changed) {
+#ifdef DEBUG_INTC_SOURCES
+            printf("sh_intc: (%d/%d/%d/%d) interrupt source 0x%x %s%s%s\n",
+                  source->parent->pending,
+                  source->asserted,
+                  source->enable_count,
+                  source->enable_max,
+                  source->vect,
+                  source->asserted ? "asserted " :
+                  assert_adj ? "deasserted" : "",
+                  enable_changed == 1 ? "enabled " :
+                  enable_changed == -1 ? "disabled " : "",
+                  source->pending ? "pending" : "");
+#endif
+  }
+}
+
+static void sh_intc_set_irq (void *opaque, int n, int level)
+{
+  struct intc_desc *desc = opaque;
+  struct intc_source *source = &(desc->sources[n]);
+
+  if (level && !source->asserted)
+    sh_intc_toggle_source(source, 0, 1);
+  else if (!level && source->asserted)
+    sh_intc_toggle_source(source, 0, -1);
+}
+
+int sh_intc_get_pending_vector(struct intc_desc *desc, int imask)
+{
+    unsigned int i;
+
+    /* slow: use a linked lists of pending sources instead */
+    /* wrong: take interrupt priority into account (one list per priority) */
+
+    if (imask == 0x0f) {
+        return -1; /* FIXME, update code to include priority per source */
+    }
+
+    for (i = 0; i < desc->nr_sources; i++) {
+        struct intc_source *source = desc->sources + i;
+
+       if (source->pending) {
+#ifdef DEBUG_INTC_SOURCES
+            printf("sh_intc: (%d) returning interrupt source 0x%x\n",
+                  desc->pending, source->vect);
+#endif
+            return source->vect;
+       }
+    }
+
+    abort();
+}
+
+#define INTC_MODE_NONE       0
+#define INTC_MODE_DUAL_SET   1
+#define INTC_MODE_DUAL_CLR   2
+#define INTC_MODE_ENABLE_REG 3
+#define INTC_MODE_MASK_REG   4
+#define INTC_MODE_IS_PRIO    8
+
+static unsigned int sh_intc_mode(unsigned long address,
+                                unsigned long set_reg, unsigned long clr_reg)
+{
+    if ((address != INTC_A7(set_reg)) &&
+       (address != INTC_A7(clr_reg)))
+        return INTC_MODE_NONE;
+
+    if (set_reg && clr_reg) {
+        if (address == INTC_A7(set_reg))
+            return INTC_MODE_DUAL_SET;
+       else
+            return INTC_MODE_DUAL_CLR;
+    }
+
+    if (set_reg)
+        return INTC_MODE_ENABLE_REG;
+    else
+        return INTC_MODE_MASK_REG;
+}
+
+static void sh_intc_locate(struct intc_desc *desc,
+                          unsigned long address,
+                          unsigned long **datap,
+                          intc_enum **enums,
+                          unsigned int *first,
+                          unsigned int *width,
+                          unsigned int *modep)
+{
+    unsigned int i, mode;
+
+    /* this is slow but works for now */
+
+    if (desc->mask_regs) {
+        for (i = 0; i < desc->nr_mask_regs; i++) {
+           struct intc_mask_reg *mr = desc->mask_regs + i;
+
+           mode = sh_intc_mode(address, mr->set_reg, mr->clr_reg);
+           if (mode == INTC_MODE_NONE)
+                continue;
+
+           *modep = mode;
+           *datap = &mr->value;
+           *enums = mr->enum_ids;
+           *first = mr->reg_width - 1;
+           *width = 1;
+           return;
+       }
+    }
+
+    if (desc->prio_regs) {
+        for (i = 0; i < desc->nr_prio_regs; i++) {
+           struct intc_prio_reg *pr = desc->prio_regs + i;
+
+           mode = sh_intc_mode(address, pr->set_reg, pr->clr_reg);
+           if (mode == INTC_MODE_NONE)
+                continue;
+
+           *modep = mode | INTC_MODE_IS_PRIO;
+           *datap = &pr->value;
+           *enums = pr->enum_ids;
+           *first = (pr->reg_width / pr->field_width) - 1;
+           *width = pr->field_width;
+           return;
+       }
+    }
+
+    abort();
+}
+
+static void sh_intc_toggle_mask(struct intc_desc *desc, intc_enum id,
+                               int enable, int is_group)
+{
+    struct intc_source *source = desc->sources + id;
+
+    if (!id)
+       return;
+
+    if (!source->next_enum_id && (!source->enable_max || !source->vect)) {
+#ifdef DEBUG_INTC_SOURCES
+        printf("sh_intc: reserved interrupt source %d modified\n", id);
+#endif
+       return;
+    }
+
+    if (source->vect)
+        sh_intc_toggle_source(source, enable ? 1 : -1, 0);
+
+#ifdef DEBUG_INTC
+    else {
+        printf("setting interrupt group %d to %d\n", id, !!enable);
+    }
+#endif
+
+    if ((is_group || !source->vect) && source->next_enum_id) {
+        sh_intc_toggle_mask(desc, source->next_enum_id, enable, 1);
+    }
+
+#ifdef DEBUG_INTC
+    if (!source->vect) {
+        printf("setting interrupt group %d to %d - done\n", id, !!enable);
+    }
+#endif
+}
+
+static uint64_t sh_intc_read(void *opaque, hwaddr offset,
+                             unsigned size)
+{
+    struct intc_desc *desc = opaque;
+    intc_enum *enum_ids = NULL;
+    unsigned int first = 0;
+    unsigned int width = 0;
+    unsigned int mode = 0;
+    unsigned long *valuep;
+
+#ifdef DEBUG_INTC
+    printf("sh_intc_read 0x%lx\n", (unsigned long) offset);
+#endif
+
+    sh_intc_locate(desc, (unsigned long)offset, &valuep, 
+                  &enum_ids, &first, &width, &mode);
+    return *valuep;
+}
+
+static void sh_intc_write(void *opaque, hwaddr offset,
+                          uint64_t value, unsigned size)
+{
+    struct intc_desc *desc = opaque;
+    intc_enum *enum_ids = NULL;
+    unsigned int first = 0;
+    unsigned int width = 0;
+    unsigned int mode = 0;
+    unsigned int k;
+    unsigned long *valuep;
+    unsigned long mask;
+
+#ifdef DEBUG_INTC
+    printf("sh_intc_write 0x%lx 0x%08x\n", (unsigned long) offset, value);
+#endif
+
+    sh_intc_locate(desc, (unsigned long)offset, &valuep, 
+                  &enum_ids, &first, &width, &mode);
+
+    switch (mode) {
+    case INTC_MODE_ENABLE_REG | INTC_MODE_IS_PRIO: break;
+    case INTC_MODE_DUAL_SET: value |= *valuep; break;
+    case INTC_MODE_DUAL_CLR: value = *valuep & ~value; break;
+    default: abort();
+    }
+
+    for (k = 0; k <= first; k++) {
+        mask = ((1 << width) - 1) << ((first - k) * width);
+
+       if ((*valuep & mask) == (value & mask))
+            continue;
+#if 0
+       printf("k = %d, first = %d, enum = %d, mask = 0x%08x\n", 
+              k, first, enum_ids[k], (unsigned int)mask);
+#endif
+        sh_intc_toggle_mask(desc, enum_ids[k], value & mask, 0);
+    }
+
+    *valuep = value;
+
+#ifdef DEBUG_INTC
+    printf("sh_intc_write 0x%lx -> 0x%08x\n", (unsigned long) offset, value);
+#endif
+}
+
+static const MemoryRegionOps sh_intc_ops = {
+    .read = sh_intc_read,
+    .write = sh_intc_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+struct intc_source *sh_intc_source(struct intc_desc *desc, intc_enum id)
+{
+    if (id)
+        return desc->sources + id;
+
+    return NULL;
+}
+
+static unsigned int sh_intc_register(MemoryRegion *sysmem,
+                             struct intc_desc *desc,
+                             const unsigned long address,
+                             const char *type,
+                             const char *action,
+                             const unsigned int index)
+{
+    char name[60];
+    MemoryRegion *iomem, *iomem_p4, *iomem_a7;
+
+    if (!address) {
+        return 0;
+    }
+
+    iomem = &desc->iomem;
+    iomem_p4 = desc->iomem_aliases + index;
+    iomem_a7 = iomem_p4 + 1;
+
+#define SH_INTC_IOMEM_FORMAT "interrupt-controller-%s-%s-%s"
+    snprintf(name, sizeof(name), SH_INTC_IOMEM_FORMAT, type, action, "p4");
+    memory_region_init_alias(iomem_p4, name, iomem, INTC_A7(address), 4);
+    memory_region_add_subregion(sysmem, P4ADDR(address), iomem_p4);
+
+    snprintf(name, sizeof(name), SH_INTC_IOMEM_FORMAT, type, action, "a7");
+    memory_region_init_alias(iomem_a7, name, iomem, INTC_A7(address), 4);
+    memory_region_add_subregion(sysmem, A7ADDR(address), iomem_a7);
+#undef SH_INTC_IOMEM_FORMAT
+
+    /* used to increment aliases index */
+    return 2;
+}
+
+static void sh_intc_register_source(struct intc_desc *desc,
+                                   intc_enum source,
+                                   struct intc_group *groups,
+                                   int nr_groups)
+{
+    unsigned int i, k;
+    struct intc_source *s;
+
+    if (desc->mask_regs) {
+        for (i = 0; i < desc->nr_mask_regs; i++) {
+           struct intc_mask_reg *mr = desc->mask_regs + i;
+
+           for (k = 0; k < ARRAY_SIZE(mr->enum_ids); k++) {
+                if (mr->enum_ids[k] != source)
+                    continue;
+
+               s = sh_intc_source(desc, mr->enum_ids[k]);
+               if (s)
+                    s->enable_max++;
+           }
+       }
+    }
+
+    if (desc->prio_regs) {
+        for (i = 0; i < desc->nr_prio_regs; i++) {
+           struct intc_prio_reg *pr = desc->prio_regs + i;
+
+           for (k = 0; k < ARRAY_SIZE(pr->enum_ids); k++) {
+                if (pr->enum_ids[k] != source)
+                    continue;
+
+               s = sh_intc_source(desc, pr->enum_ids[k]);
+               if (s)
+                    s->enable_max++;
+           }
+       }
+    }
+
+    if (groups) {
+        for (i = 0; i < nr_groups; i++) {
+           struct intc_group *gr = groups + i;
+
+           for (k = 0; k < ARRAY_SIZE(gr->enum_ids); k++) {
+                if (gr->enum_ids[k] != source)
+                    continue;
+
+               s = sh_intc_source(desc, gr->enum_ids[k]);
+               if (s)
+                    s->enable_max++;
+           }
+       }
+    }
+
+}
+
+void sh_intc_register_sources(struct intc_desc *desc,
+                             struct intc_vect *vectors,
+                             int nr_vectors,
+                             struct intc_group *groups,
+                             int nr_groups)
+{
+    unsigned int i, k;
+    struct intc_source *s;
+
+    for (i = 0; i < nr_vectors; i++) {
+       struct intc_vect *vect = vectors + i;
+
+       sh_intc_register_source(desc, vect->enum_id, groups, nr_groups);
+       s = sh_intc_source(desc, vect->enum_id);
+        if (s) {
+            s->vect = vect->vect;
+
+#ifdef DEBUG_INTC_SOURCES
+            printf("sh_intc: registered source %d -> 0x%04x (%d/%d)\n",
+                   vect->enum_id, s->vect, s->enable_count, s->enable_max);
+#endif
+        }
+    }
+
+    if (groups) {
+        for (i = 0; i < nr_groups; i++) {
+           struct intc_group *gr = groups + i;
+
+           s = sh_intc_source(desc, gr->enum_id);
+           s->next_enum_id = gr->enum_ids[0];
+
+           for (k = 1; k < ARRAY_SIZE(gr->enum_ids); k++) {
+                if (!gr->enum_ids[k])
+                    continue;
+
+               s = sh_intc_source(desc, gr->enum_ids[k - 1]);
+               s->next_enum_id = gr->enum_ids[k];
+           }
+
+#ifdef DEBUG_INTC_SOURCES
+           printf("sh_intc: registered group %d (%d/%d)\n",
+                  gr->enum_id, s->enable_count, s->enable_max);
+#endif
+       }
+    }
+}
+
+int sh_intc_init(MemoryRegion *sysmem,
+         struct intc_desc *desc,
+                int nr_sources,
+                struct intc_mask_reg *mask_regs,
+                int nr_mask_regs,
+                struct intc_prio_reg *prio_regs,
+                int nr_prio_regs)
+{
+    unsigned int i, j;
+
+    desc->pending = 0;
+    desc->nr_sources = nr_sources;
+    desc->mask_regs = mask_regs;
+    desc->nr_mask_regs = nr_mask_regs;
+    desc->prio_regs = prio_regs;
+    desc->nr_prio_regs = nr_prio_regs;
+    /* Allocate 4 MemoryRegions per register (2 actions * 2 aliases).
+     **/
+    desc->iomem_aliases = g_new0(MemoryRegion,
+                                 (nr_mask_regs + nr_prio_regs) * 4);
+
+    j = 0;
+    i = sizeof(struct intc_source) * nr_sources;
+    desc->sources = g_malloc0(i);
+
+    for (i = 0; i < desc->nr_sources; i++) {
+        struct intc_source *source = desc->sources + i;
+
+        source->parent = desc;
+    }
+
+    desc->irqs = qemu_allocate_irqs(sh_intc_set_irq, desc, nr_sources);
+    memory_region_init_io(&desc->iomem, &sh_intc_ops, desc,
+                          "interrupt-controller", 0x100000000ULL);
+
+#define INT_REG_PARAMS(reg_struct, type, action, j) \
+        reg_struct->action##_reg, #type, #action, j
+    if (desc->mask_regs) {
+        for (i = 0; i < desc->nr_mask_regs; i++) {
+           struct intc_mask_reg *mr = desc->mask_regs + i;
+
+            j += sh_intc_register(sysmem, desc,
+                                  INT_REG_PARAMS(mr, mask, set, j));
+            j += sh_intc_register(sysmem, desc,
+                                  INT_REG_PARAMS(mr, mask, clr, j));
+       }
+    }
+
+    if (desc->prio_regs) {
+        for (i = 0; i < desc->nr_prio_regs; i++) {
+           struct intc_prio_reg *pr = desc->prio_regs + i;
+
+            j += sh_intc_register(sysmem, desc,
+                                  INT_REG_PARAMS(pr, prio, set, j));
+            j += sh_intc_register(sysmem, desc,
+                                  INT_REG_PARAMS(pr, prio, clr, j));
+       }
+    }
+#undef INT_REG_PARAMS
+
+    return 0;
+}
+
+/* Assert level <n> IRL interrupt. 
+   0:deassert. 1:lowest priority,... 15:highest priority. */
+void sh_intc_set_irl(void *opaque, int n, int level)
+{
+    struct intc_source *s = opaque;
+    int i, irl = level ^ 15;
+    for (i = 0; (s = sh_intc_source(s->parent, s->next_enum_id)); i++) {
+       if (i == irl)
+           sh_intc_toggle_source(s, s->enable_count?0:1, s->asserted?0:1);
+       else
+           if (s->asserted)
+               sh_intc_toggle_source(s, 0, -1);
+    }
+}
diff --git a/hw/intc/slavio_intctl.c b/hw/intc/slavio_intctl.c
new file mode 100644 (file)
index 0000000..b367752
--- /dev/null
@@ -0,0 +1,471 @@
+/*
+ * QEMU Sparc SLAVIO interrupt controller emulation
+ *
+ * Copyright (c) 2003-2005 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.
+ */
+
+#include "hw/sparc/sun4m.h"
+#include "monitor/monitor.h"
+#include "hw/sysbus.h"
+#include "trace.h"
+
+//#define DEBUG_IRQ_COUNT
+
+/*
+ * Registers of interrupt controller in sun4m.
+ *
+ * This is the interrupt controller part of chip STP2001 (Slave I/O), also
+ * produced as NCR89C105. See
+ * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
+ *
+ * There is a system master controller and one for each cpu.
+ *
+ */
+
+#define MAX_CPUS 16
+#define MAX_PILS 16
+
+struct SLAVIO_INTCTLState;
+
+typedef struct SLAVIO_CPUINTCTLState {
+    MemoryRegion iomem;
+    struct SLAVIO_INTCTLState *master;
+    uint32_t intreg_pending;
+    uint32_t cpu;
+    uint32_t irl_out;
+} SLAVIO_CPUINTCTLState;
+
+typedef struct SLAVIO_INTCTLState {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+#ifdef DEBUG_IRQ_COUNT
+    uint64_t irq_count[32];
+#endif
+    qemu_irq cpu_irqs[MAX_CPUS][MAX_PILS];
+    SLAVIO_CPUINTCTLState slaves[MAX_CPUS];
+    uint32_t intregm_pending;
+    uint32_t intregm_disabled;
+    uint32_t target_cpu;
+} SLAVIO_INTCTLState;
+
+#define INTCTL_MAXADDR 0xf
+#define INTCTL_SIZE (INTCTL_MAXADDR + 1)
+#define INTCTLM_SIZE 0x14
+#define MASTER_IRQ_MASK ~0x0fa2007f
+#define MASTER_DISABLE 0x80000000
+#define CPU_SOFTIRQ_MASK 0xfffe0000
+#define CPU_IRQ_INT15_IN (1 << 15)
+#define CPU_IRQ_TIMER_IN (1 << 14)
+
+static void slavio_check_interrupts(SLAVIO_INTCTLState *s, int set_irqs);
+
+// per-cpu interrupt controller
+static uint64_t slavio_intctl_mem_readl(void *opaque, hwaddr addr,
+                                        unsigned size)
+{
+    SLAVIO_CPUINTCTLState *s = opaque;
+    uint32_t saddr, ret;
+
+    saddr = addr >> 2;
+    switch (saddr) {
+    case 0:
+        ret = s->intreg_pending;
+        break;
+    default:
+        ret = 0;
+        break;
+    }
+    trace_slavio_intctl_mem_readl(s->cpu, addr, ret);
+
+    return ret;
+}
+
+static void slavio_intctl_mem_writel(void *opaque, hwaddr addr,
+                                     uint64_t val, unsigned size)
+{
+    SLAVIO_CPUINTCTLState *s = opaque;
+    uint32_t saddr;
+
+    saddr = addr >> 2;
+    trace_slavio_intctl_mem_writel(s->cpu, addr, val);
+    switch (saddr) {
+    case 1: // clear pending softints
+        val &= CPU_SOFTIRQ_MASK | CPU_IRQ_INT15_IN;
+        s->intreg_pending &= ~val;
+        slavio_check_interrupts(s->master, 1);
+        trace_slavio_intctl_mem_writel_clear(s->cpu, val, s->intreg_pending);
+        break;
+    case 2: // set softint
+        val &= CPU_SOFTIRQ_MASK;
+        s->intreg_pending |= val;
+        slavio_check_interrupts(s->master, 1);
+        trace_slavio_intctl_mem_writel_set(s->cpu, val, s->intreg_pending);
+        break;
+    default:
+        break;
+    }
+}
+
+static const MemoryRegionOps slavio_intctl_mem_ops = {
+    .read = slavio_intctl_mem_readl,
+    .write = slavio_intctl_mem_writel,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+// master system interrupt controller
+static uint64_t slavio_intctlm_mem_readl(void *opaque, hwaddr addr,
+                                         unsigned size)
+{
+    SLAVIO_INTCTLState *s = opaque;
+    uint32_t saddr, ret;
+
+    saddr = addr >> 2;
+    switch (saddr) {
+    case 0:
+        ret = s->intregm_pending & ~MASTER_DISABLE;
+        break;
+    case 1:
+        ret = s->intregm_disabled & MASTER_IRQ_MASK;
+        break;
+    case 4:
+        ret = s->target_cpu;
+        break;
+    default:
+        ret = 0;
+        break;
+    }
+    trace_slavio_intctlm_mem_readl(addr, ret);
+
+    return ret;
+}
+
+static void slavio_intctlm_mem_writel(void *opaque, hwaddr addr,
+                                      uint64_t val, unsigned size)
+{
+    SLAVIO_INTCTLState *s = opaque;
+    uint32_t saddr;
+
+    saddr = addr >> 2;
+    trace_slavio_intctlm_mem_writel(addr, val);
+    switch (saddr) {
+    case 2: // clear (enable)
+        // Force clear unused bits
+        val &= MASTER_IRQ_MASK;
+        s->intregm_disabled &= ~val;
+        trace_slavio_intctlm_mem_writel_enable(val, s->intregm_disabled);
+        slavio_check_interrupts(s, 1);
+        break;
+    case 3: // set (disable; doesn't affect pending)
+        // Force clear unused bits
+        val &= MASTER_IRQ_MASK;
+        s->intregm_disabled |= val;
+        slavio_check_interrupts(s, 1);
+        trace_slavio_intctlm_mem_writel_disable(val, s->intregm_disabled);
+        break;
+    case 4:
+        s->target_cpu = val & (MAX_CPUS - 1);
+        slavio_check_interrupts(s, 1);
+        trace_slavio_intctlm_mem_writel_target(s->target_cpu);
+        break;
+    default:
+        break;
+    }
+}
+
+static const MemoryRegionOps slavio_intctlm_mem_ops = {
+    .read = slavio_intctlm_mem_readl,
+    .write = slavio_intctlm_mem_writel,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+void slavio_pic_info(Monitor *mon, DeviceState *dev)
+{
+    SysBusDevice *sd;
+    SLAVIO_INTCTLState *s;
+    int i;
+
+    sd = SYS_BUS_DEVICE(dev);
+    s = FROM_SYSBUS(SLAVIO_INTCTLState, sd);
+    for (i = 0; i < MAX_CPUS; i++) {
+        monitor_printf(mon, "per-cpu %d: pending 0x%08x\n", i,
+                       s->slaves[i].intreg_pending);
+    }
+    monitor_printf(mon, "master: pending 0x%08x, disabled 0x%08x\n",
+                   s->intregm_pending, s->intregm_disabled);
+}
+
+void slavio_irq_info(Monitor *mon, DeviceState *dev)
+{
+#ifndef DEBUG_IRQ_COUNT
+    monitor_printf(mon, "irq statistic code not compiled.\n");
+#else
+    SysBusDevice *sd;
+    SLAVIO_INTCTLState *s;
+    int i;
+    int64_t count;
+
+    sd = SYS_BUS_DEVICE(dev);
+    s = FROM_SYSBUS(SLAVIO_INTCTLState, sd);
+    monitor_printf(mon, "IRQ statistics:\n");
+    for (i = 0; i < 32; i++) {
+        count = s->irq_count[i];
+        if (count > 0)
+            monitor_printf(mon, "%2d: %" PRId64 "\n", i, count);
+    }
+#endif
+}
+
+static const uint32_t intbit_to_level[] = {
+    2, 3, 5, 7, 9, 11, 13, 2,   3, 5, 7, 9, 11, 13, 12, 12,
+    6, 13, 4, 10, 8, 9, 11, 0,  0, 0, 0, 15, 15, 15, 15, 0,
+};
+
+static void slavio_check_interrupts(SLAVIO_INTCTLState *s, int set_irqs)
+{
+    uint32_t pending = s->intregm_pending, pil_pending;
+    unsigned int i, j;
+
+    pending &= ~s->intregm_disabled;
+
+    trace_slavio_check_interrupts(pending, s->intregm_disabled);
+    for (i = 0; i < MAX_CPUS; i++) {
+        pil_pending = 0;
+
+        /* If we are the current interrupt target, get hard interrupts */
+        if (pending && !(s->intregm_disabled & MASTER_DISABLE) &&
+            (i == s->target_cpu)) {
+            for (j = 0; j < 32; j++) {
+                if ((pending & (1 << j)) && intbit_to_level[j]) {
+                    pil_pending |= 1 << intbit_to_level[j];
+                }
+            }
+        }
+
+        /* Calculate current pending hard interrupts for display */
+        s->slaves[i].intreg_pending &= CPU_SOFTIRQ_MASK | CPU_IRQ_INT15_IN |
+            CPU_IRQ_TIMER_IN;
+        if (i == s->target_cpu) {
+            for (j = 0; j < 32; j++) {
+                if ((s->intregm_pending & (1 << j)) && intbit_to_level[j]) {
+                    s->slaves[i].intreg_pending |= 1 << intbit_to_level[j];
+                }
+            }
+        }
+
+        /* Level 15 and CPU timer interrupts are only masked when
+           the MASTER_DISABLE bit is set */
+        if (!(s->intregm_disabled & MASTER_DISABLE)) {
+            pil_pending |= s->slaves[i].intreg_pending &
+                (CPU_IRQ_INT15_IN | CPU_IRQ_TIMER_IN);
+        }
+
+        /* Add soft interrupts */
+        pil_pending |= (s->slaves[i].intreg_pending & CPU_SOFTIRQ_MASK) >> 16;
+
+        if (set_irqs) {
+            /* Since there is not really an interrupt 0 (and pil_pending
+             * and irl_out bit zero are thus always zero) there is no need
+             * to do anything with cpu_irqs[i][0] and it is OK not to do
+             * the j=0 iteration of this loop.
+             */
+            for (j = MAX_PILS-1; j > 0; j--) {
+                if (pil_pending & (1 << j)) {
+                    if (!(s->slaves[i].irl_out & (1 << j))) {
+                        qemu_irq_raise(s->cpu_irqs[i][j]);
+                    }
+                } else {
+                    if (s->slaves[i].irl_out & (1 << j)) {
+                        qemu_irq_lower(s->cpu_irqs[i][j]);
+                    }
+                }
+            }
+        }
+        s->slaves[i].irl_out = pil_pending;
+    }
+}
+
+/*
+ * "irq" here is the bit number in the system interrupt register to
+ * separate serial and keyboard interrupts sharing a level.
+ */
+static void slavio_set_irq(void *opaque, int irq, int level)
+{
+    SLAVIO_INTCTLState *s = opaque;
+    uint32_t mask = 1 << irq;
+    uint32_t pil = intbit_to_level[irq];
+    unsigned int i;
+
+    trace_slavio_set_irq(s->target_cpu, irq, pil, level);
+    if (pil > 0) {
+        if (level) {
+#ifdef DEBUG_IRQ_COUNT
+            s->irq_count[pil]++;
+#endif
+            s->intregm_pending |= mask;
+            if (pil == 15) {
+                for (i = 0; i < MAX_CPUS; i++) {
+                    s->slaves[i].intreg_pending |= 1 << pil;
+                }
+            }
+        } else {
+            s->intregm_pending &= ~mask;
+            if (pil == 15) {
+                for (i = 0; i < MAX_CPUS; i++) {
+                    s->slaves[i].intreg_pending &= ~(1 << pil);
+                }
+            }
+        }
+        slavio_check_interrupts(s, 1);
+    }
+}
+
+static void slavio_set_timer_irq_cpu(void *opaque, int cpu, int level)
+{
+    SLAVIO_INTCTLState *s = opaque;
+
+    trace_slavio_set_timer_irq_cpu(cpu, level);
+
+    if (level) {
+        s->slaves[cpu].intreg_pending |= CPU_IRQ_TIMER_IN;
+    } else {
+        s->slaves[cpu].intreg_pending &= ~CPU_IRQ_TIMER_IN;
+    }
+
+    slavio_check_interrupts(s, 1);
+}
+
+static void slavio_set_irq_all(void *opaque, int irq, int level)
+{
+    if (irq < 32) {
+        slavio_set_irq(opaque, irq, level);
+    } else {
+        slavio_set_timer_irq_cpu(opaque, irq - 32, level);
+    }
+}
+
+static int vmstate_intctl_post_load(void *opaque, int version_id)
+{
+    SLAVIO_INTCTLState *s = opaque;
+
+    slavio_check_interrupts(s, 0);
+    return 0;
+}
+
+static const VMStateDescription vmstate_intctl_cpu = {
+    .name ="slavio_intctl_cpu",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT32(intreg_pending, SLAVIO_CPUINTCTLState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_intctl = {
+    .name ="slavio_intctl",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .post_load = vmstate_intctl_post_load,
+    .fields      = (VMStateField []) {
+        VMSTATE_STRUCT_ARRAY(slaves, SLAVIO_INTCTLState, MAX_CPUS, 1,
+                             vmstate_intctl_cpu, SLAVIO_CPUINTCTLState),
+        VMSTATE_UINT32(intregm_pending, SLAVIO_INTCTLState),
+        VMSTATE_UINT32(intregm_disabled, SLAVIO_INTCTLState),
+        VMSTATE_UINT32(target_cpu, SLAVIO_INTCTLState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void slavio_intctl_reset(DeviceState *d)
+{
+    SLAVIO_INTCTLState *s = container_of(d, SLAVIO_INTCTLState, busdev.qdev);
+    int i;
+
+    for (i = 0; i < MAX_CPUS; i++) {
+        s->slaves[i].intreg_pending = 0;
+        s->slaves[i].irl_out = 0;
+    }
+    s->intregm_disabled = ~MASTER_IRQ_MASK;
+    s->intregm_pending = 0;
+    s->target_cpu = 0;
+    slavio_check_interrupts(s, 0);
+}
+
+static int slavio_intctl_init1(SysBusDevice *dev)
+{
+    SLAVIO_INTCTLState *s = FROM_SYSBUS(SLAVIO_INTCTLState, dev);
+    unsigned int i, j;
+    char slave_name[45];
+
+    qdev_init_gpio_in(&dev->qdev, slavio_set_irq_all, 32 + MAX_CPUS);
+    memory_region_init_io(&s->iomem, &slavio_intctlm_mem_ops, s,
+                          "master-interrupt-controller", INTCTLM_SIZE);
+    sysbus_init_mmio(dev, &s->iomem);
+
+    for (i = 0; i < MAX_CPUS; i++) {
+        snprintf(slave_name, sizeof(slave_name),
+                 "slave-interrupt-controller-%i", i);
+        for (j = 0; j < MAX_PILS; j++) {
+            sysbus_init_irq(dev, &s->cpu_irqs[i][j]);
+        }
+        memory_region_init_io(&s->slaves[i].iomem, &slavio_intctl_mem_ops,
+                              &s->slaves[i], slave_name, INTCTL_SIZE);
+        sysbus_init_mmio(dev, &s->slaves[i].iomem);
+        s->slaves[i].cpu = i;
+        s->slaves[i].master = s;
+    }
+
+    return 0;
+}
+
+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 const 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_types(void)
+{
+    type_register_static(&slavio_intctl_info);
+}
+
+type_init(slavio_intctl_register_types)
diff --git a/hw/intc/sun4c_intctl.c b/hw/intc/sun4c_intctl.c
new file mode 100644 (file)
index 0000000..1096375
--- /dev/null
@@ -0,0 +1,208 @@
+/*
+ * QEMU Sparc Sun4c interrupt controller emulation
+ *
+ * Based on slavio_intctl, copyright (c) 2003-2005 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.
+ */
+
+#include "hw/hw.h"
+#include "hw/sparc/sun4m.h"
+#include "monitor/monitor.h"
+#include "hw/sysbus.h"
+
+//#define DEBUG_IRQ_COUNT
+//#define DEBUG_IRQ
+
+#ifdef DEBUG_IRQ
+#define DPRINTF(fmt, ...)                                       \
+    do { printf("IRQ: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...)
+#endif
+
+/*
+ * Registers of interrupt controller in sun4c.
+ *
+ */
+
+#define MAX_PILS 16
+
+typedef struct Sun4c_INTCTLState {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+#ifdef DEBUG_IRQ_COUNT
+    uint64_t irq_count;
+#endif
+    qemu_irq cpu_irqs[MAX_PILS];
+    const uint32_t *intbit_to_level;
+    uint32_t pil_out;
+    uint8_t reg;
+    uint8_t pending;
+} Sun4c_INTCTLState;
+
+#define INTCTL_SIZE 1
+
+static void sun4c_check_interrupts(void *opaque);
+
+static uint64_t sun4c_intctl_mem_read(void *opaque, hwaddr addr,
+                                      unsigned size)
+{
+    Sun4c_INTCTLState *s = opaque;
+    uint32_t ret;
+
+    ret = s->reg;
+    DPRINTF("read reg 0x" TARGET_FMT_plx " = %x\n", addr, ret);
+
+    return ret;
+}
+
+static void sun4c_intctl_mem_write(void *opaque, hwaddr addr,
+                                   uint64_t val, unsigned size)
+{
+    Sun4c_INTCTLState *s = opaque;
+
+    DPRINTF("write reg 0x" TARGET_FMT_plx " = %x\n", addr, (unsigned)val);
+    val &= 0xbf;
+    s->reg = val;
+    sun4c_check_interrupts(s);
+}
+
+static const MemoryRegionOps sun4c_intctl_mem_ops = {
+    .read = sun4c_intctl_mem_read,
+    .write = sun4c_intctl_mem_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+};
+
+static const uint32_t intbit_to_level[] = { 0, 1, 4, 6, 8, 10, 0, 14, };
+
+static void sun4c_check_interrupts(void *opaque)
+{
+    Sun4c_INTCTLState *s = opaque;
+    uint32_t pil_pending;
+    unsigned int i;
+
+    pil_pending = 0;
+    if (s->pending && !(s->reg & 0x80000000)) {
+        for (i = 0; i < 8; i++) {
+            if (s->pending & (1 << i))
+                pil_pending |= 1 << intbit_to_level[i];
+        }
+    }
+
+    for (i = 0; i < MAX_PILS; i++) {
+        if (pil_pending & (1 << i)) {
+            if (!(s->pil_out & (1 << i)))
+                qemu_irq_raise(s->cpu_irqs[i]);
+        } else {
+            if (s->pil_out & (1 << i))
+                qemu_irq_lower(s->cpu_irqs[i]);
+        }
+    }
+    s->pil_out = pil_pending;
+}
+
+/*
+ * "irq" here is the bit number in the system interrupt register
+ */
+static void sun4c_set_irq(void *opaque, int irq, int level)
+{
+    Sun4c_INTCTLState *s = opaque;
+    uint32_t mask = 1 << irq;
+    uint32_t pil = intbit_to_level[irq];
+
+    DPRINTF("Set irq %d -> pil %d level %d\n", irq, pil,
+            level);
+    if (pil > 0) {
+        if (level) {
+#ifdef DEBUG_IRQ_COUNT
+            s->irq_count++;
+#endif
+            s->pending |= mask;
+        } else {
+            s->pending &= ~mask;
+        }
+        sun4c_check_interrupts(s);
+    }
+}
+
+static const VMStateDescription vmstate_sun4c_intctl = {
+    .name ="sun4c_intctl",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT8(reg, Sun4c_INTCTLState),
+        VMSTATE_UINT8(pending, Sun4c_INTCTLState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void sun4c_intctl_reset(DeviceState *d)
+{
+    Sun4c_INTCTLState *s = container_of(d, Sun4c_INTCTLState, busdev.qdev);
+
+    s->reg = 1;
+    s->pending = 0;
+}
+
+static int sun4c_intctl_init1(SysBusDevice *dev)
+{
+    Sun4c_INTCTLState *s = FROM_SYSBUS(Sun4c_INTCTLState, dev);
+    unsigned int i;
+
+    memory_region_init_io(&s->iomem, &sun4c_intctl_mem_ops, s,
+                          "intctl", INTCTL_SIZE);
+    sysbus_init_mmio(dev, &s->iomem);
+    qdev_init_gpio_in(&dev->qdev, sun4c_set_irq, 8);
+
+    for (i = 0; i < MAX_PILS; i++) {
+        sysbus_init_irq(dev, &s->cpu_irqs[i]);
+    }
+
+    return 0;
+}
+
+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 const 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_types(void)
+{
+    type_register_static(&sun4c_intctl_info);
+}
+
+type_init(sun4c_intctl_register_types)
diff --git a/hw/intc/xilinx_intc.c b/hw/intc/xilinx_intc.c
new file mode 100644 (file)
index 0000000..b106e72
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+ * QEMU Xilinx OPB Interrupt Controller.
+ *
+ * Copyright (c) 2009 Edgar E. Iglesias.
+ *
+ * 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 "hw/sysbus.h"
+#include "hw/hw.h"
+
+#define D(x)
+
+#define R_ISR       0
+#define R_IPR       1
+#define R_IER       2
+#define R_IAR       3
+#define R_SIE       4
+#define R_CIE       5
+#define R_IVR       6
+#define R_MER       7
+#define R_MAX       8
+
+struct xlx_pic
+{
+    SysBusDevice busdev;
+    MemoryRegion mmio;
+    qemu_irq parent_irq;
+
+    /* Configuration reg chosen at synthesis-time. QEMU populates
+       the bits at board-setup.  */
+    uint32_t c_kind_of_intr;
+
+    /* Runtime control registers.  */
+    uint32_t regs[R_MAX];
+};
+
+static void update_irq(struct xlx_pic *p)
+{
+    uint32_t i;
+    /* Update the pending register.  */
+    p->regs[R_IPR] = p->regs[R_ISR] & p->regs[R_IER];
+
+    /* Update the vector register.  */
+    for (i = 0; i < 32; i++) {
+        if (p->regs[R_IPR] & (1 << i))
+            break;
+    }
+    if (i == 32)
+        i = ~0;
+
+    p->regs[R_IVR] = i;
+    if ((p->regs[R_MER] & 1) && p->regs[R_IPR]) {
+        qemu_irq_raise(p->parent_irq);
+    } else {
+        qemu_irq_lower(p->parent_irq);
+    }
+}
+
+static uint64_t
+pic_read(void *opaque, hwaddr addr, unsigned int size)
+{
+    struct xlx_pic *p = opaque;
+    uint32_t r = 0;
+
+    addr >>= 2;
+    switch (addr)
+    {
+        default:
+            if (addr < ARRAY_SIZE(p->regs))
+                r = p->regs[addr];
+            break;
+
+    }
+    D(printf("%s %x=%x\n", __func__, addr * 4, r));
+    return r;
+}
+
+static void
+pic_write(void *opaque, hwaddr addr,
+          uint64_t val64, unsigned int size)
+{
+    struct xlx_pic *p = opaque;
+    uint32_t value = val64;
+
+    addr >>= 2;
+    D(qemu_log("%s addr=%x val=%x\n", __func__, addr * 4, value));
+    switch (addr) 
+    {
+        case R_IAR:
+            p->regs[R_ISR] &= ~value; /* ACK.  */
+            break;
+        case R_SIE:
+            p->regs[R_IER] |= value;  /* Atomic set ie.  */
+            break;
+        case R_CIE:
+            p->regs[R_IER] &= ~value; /* Atomic clear ie.  */
+            break;
+        default:
+            if (addr < ARRAY_SIZE(p->regs))
+                p->regs[addr] = value;
+            break;
+    }
+    update_irq(p);
+}
+
+static const MemoryRegionOps pic_ops = {
+    .read = pic_read,
+    .write = pic_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4
+    }
+};
+
+static void irq_handler(void *opaque, int irq, int level)
+{
+    struct xlx_pic *p = opaque;
+
+    if (!(p->regs[R_MER] & 2)) {
+        qemu_irq_lower(p->parent_irq);
+        return;
+    }
+
+    /* Update source flops. Don't clear unless level triggered.
+       Edge triggered interrupts only go away when explicitely acked to
+       the interrupt controller.  */
+    if (!(p->c_kind_of_intr & (1 << irq)) || level) {
+        p->regs[R_ISR] &= ~(1 << irq);
+        p->regs[R_ISR] |= (level << irq);
+    }
+    update_irq(p);
+}
+
+static int xilinx_intc_init(SysBusDevice *dev)
+{
+    struct xlx_pic *p = FROM_SYSBUS(typeof (*p), dev);
+
+    qdev_init_gpio_in(&dev->qdev, irq_handler, 32);
+    sysbus_init_irq(dev, &p->parent_irq);
+
+    memory_region_init_io(&p->mmio, &pic_ops, p, "xlnx.xps-intc", R_MAX * 4);
+    sysbus_init_mmio(dev, &p->mmio);
+    return 0;
+}
+
+static Property xilinx_intc_properties[] = {
+    DEFINE_PROP_UINT32("kind-of-intr", struct xlx_pic, c_kind_of_intr, 0),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void xilinx_intc_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = xilinx_intc_init;
+    dc->props = xilinx_intc_properties;
+}
+
+static const TypeInfo xilinx_intc_info = {
+    .name          = "xlnx.xps-intc",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(struct xlx_pic),
+    .class_init    = xilinx_intc_class_init,
+};
+
+static void xilinx_intc_register_types(void)
+{
+    type_register_static(&xilinx_intc_info);
+}
+
+type_init(xilinx_intc_register_types)
diff --git a/hw/intel-hda-defs.h b/hw/intel-hda-defs.h
deleted file mode 100644 (file)
index 2e37e5b..0000000
+++ /dev/null
@@ -1,717 +0,0 @@
-#ifndef HW_INTEL_HDA_DEFS_H
-#define HW_INTEL_HDA_DEFS_H
-
-/* qemu */
-#define HDA_BUFFER_SIZE 256
-
-/* --------------------------------------------------------------------- */
-/* from linux/sound/pci/hda/hda_intel.c                                  */
-
-/*
- * registers
- */
-#define ICH6_REG_GCAP                  0x00
-#define   ICH6_GCAP_64OK       (1 << 0)   /* 64bit address support */
-#define   ICH6_GCAP_NSDO       (3 << 1)   /* # of serial data out signals */
-#define   ICH6_GCAP_BSS                (31 << 3)  /* # of bidirectional streams */
-#define   ICH6_GCAP_ISS                (15 << 8)  /* # of input streams */
-#define   ICH6_GCAP_OSS                (15 << 12) /* # of output streams */
-#define ICH6_REG_VMIN                  0x02
-#define ICH6_REG_VMAJ                  0x03
-#define ICH6_REG_OUTPAY                        0x04
-#define ICH6_REG_INPAY                 0x06
-#define ICH6_REG_GCTL                  0x08
-#define   ICH6_GCTL_RESET      (1 << 0)   /* controller reset */
-#define   ICH6_GCTL_FCNTRL     (1 << 1)   /* flush control */
-#define   ICH6_GCTL_UNSOL      (1 << 8)   /* accept unsol. response enable */
-#define ICH6_REG_WAKEEN                        0x0c
-#define ICH6_REG_STATESTS              0x0e
-#define ICH6_REG_GSTS                  0x10
-#define   ICH6_GSTS_FSTS       (1 << 1)   /* flush status */
-#define ICH6_REG_INTCTL                        0x20
-#define ICH6_REG_INTSTS                        0x24
-#define ICH6_REG_WALLCLK               0x30    /* 24Mhz source */
-#define ICH6_REG_SYNC                  0x34
-#define ICH6_REG_CORBLBASE             0x40
-#define ICH6_REG_CORBUBASE             0x44
-#define ICH6_REG_CORBWP                        0x48
-#define ICH6_REG_CORBRP                        0x4a
-#define   ICH6_CORBRP_RST      (1 << 15)  /* read pointer reset */
-#define ICH6_REG_CORBCTL               0x4c
-#define   ICH6_CORBCTL_RUN     (1 << 1)   /* enable DMA */
-#define   ICH6_CORBCTL_CMEIE   (1 << 0)   /* enable memory error irq */
-#define ICH6_REG_CORBSTS               0x4d
-#define   ICH6_CORBSTS_CMEI    (1 << 0)   /* memory error indication */
-#define ICH6_REG_CORBSIZE              0x4e
-
-#define ICH6_REG_RIRBLBASE             0x50
-#define ICH6_REG_RIRBUBASE             0x54
-#define ICH6_REG_RIRBWP                        0x58
-#define   ICH6_RIRBWP_RST      (1 << 15)  /* write pointer reset */
-#define ICH6_REG_RINTCNT               0x5a
-#define ICH6_REG_RIRBCTL               0x5c
-#define   ICH6_RBCTL_IRQ_EN    (1 << 0)   /* enable IRQ */
-#define   ICH6_RBCTL_DMA_EN    (1 << 1)   /* enable DMA */
-#define   ICH6_RBCTL_OVERRUN_EN        (1 << 2)   /* enable overrun irq */
-#define ICH6_REG_RIRBSTS               0x5d
-#define   ICH6_RBSTS_IRQ       (1 << 0)   /* response irq */
-#define   ICH6_RBSTS_OVERRUN   (1 << 2)   /* overrun irq */
-#define ICH6_REG_RIRBSIZE              0x5e
-
-#define ICH6_REG_IC                    0x60
-#define ICH6_REG_IR                    0x64
-#define ICH6_REG_IRS                   0x68
-#define   ICH6_IRS_VALID       (1<<1)
-#define   ICH6_IRS_BUSY                (1<<0)
-
-#define ICH6_REG_DPLBASE               0x70
-#define ICH6_REG_DPUBASE               0x74
-#define   ICH6_DPLBASE_ENABLE  0x1     /* Enable position buffer */
-
-/* SD offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */
-enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
-
-/* stream register offsets from stream base */
-#define ICH6_REG_SD_CTL                        0x00
-#define ICH6_REG_SD_STS                        0x03
-#define ICH6_REG_SD_LPIB               0x04
-#define ICH6_REG_SD_CBL                        0x08
-#define ICH6_REG_SD_LVI                        0x0c
-#define ICH6_REG_SD_FIFOW              0x0e
-#define ICH6_REG_SD_FIFOSIZE           0x10
-#define ICH6_REG_SD_FORMAT             0x12
-#define ICH6_REG_SD_BDLPL              0x18
-#define ICH6_REG_SD_BDLPU              0x1c
-
-/* PCI space */
-#define ICH6_PCIREG_TCSEL      0x44
-
-/*
- * other constants
- */
-
-/* max number of SDs */
-/* ICH, ATI and VIA have 4 playback and 4 capture */
-#define ICH6_NUM_CAPTURE       4
-#define ICH6_NUM_PLAYBACK      4
-
-/* ULI has 6 playback and 5 capture */
-#define ULI_NUM_CAPTURE                5
-#define ULI_NUM_PLAYBACK       6
-
-/* ATI HDMI has 1 playback and 0 capture */
-#define ATIHDMI_NUM_CAPTURE    0
-#define ATIHDMI_NUM_PLAYBACK   1
-
-/* TERA has 4 playback and 3 capture */
-#define TERA_NUM_CAPTURE       3
-#define TERA_NUM_PLAYBACK      4
-
-/* this number is statically defined for simplicity */
-#define MAX_AZX_DEV            16
-
-/* max number of fragments - we may use more if allocating more pages for BDL */
-#define BDL_SIZE               4096
-#define AZX_MAX_BDL_ENTRIES    (BDL_SIZE / 16)
-#define AZX_MAX_FRAG           32
-/* max buffer size - no h/w limit, you can increase as you like */
-#define AZX_MAX_BUF_SIZE       (1024*1024*1024)
-
-/* RIRB int mask: overrun[2], response[0] */
-#define RIRB_INT_RESPONSE      0x01
-#define RIRB_INT_OVERRUN       0x04
-#define RIRB_INT_MASK          0x05
-
-/* STATESTS int mask: S3,SD2,SD1,SD0 */
-#define AZX_MAX_CODECS         8
-#define AZX_DEFAULT_CODECS     4
-#define STATESTS_INT_MASK      ((1 << AZX_MAX_CODECS) - 1)
-
-/* SD_CTL bits */
-#define SD_CTL_STREAM_RESET    0x01    /* stream reset bit */
-#define SD_CTL_DMA_START       0x02    /* stream DMA start bit */
-#define SD_CTL_STRIPE          (3 << 16)       /* stripe control */
-#define SD_CTL_TRAFFIC_PRIO    (1 << 18)       /* traffic priority */
-#define SD_CTL_DIR             (1 << 19)       /* bi-directional stream */
-#define SD_CTL_STREAM_TAG_MASK (0xf << 20)
-#define SD_CTL_STREAM_TAG_SHIFT        20
-
-/* SD_CTL and SD_STS */
-#define SD_INT_DESC_ERR                0x10    /* descriptor error interrupt */
-#define SD_INT_FIFO_ERR                0x08    /* FIFO error interrupt */
-#define SD_INT_COMPLETE                0x04    /* completion interrupt */
-#define SD_INT_MASK            (SD_INT_DESC_ERR|SD_INT_FIFO_ERR|\
-                                SD_INT_COMPLETE)
-
-/* SD_STS */
-#define SD_STS_FIFO_READY      0x20    /* FIFO ready */
-
-/* INTCTL and INTSTS */
-#define ICH6_INT_ALL_STREAM    0xff       /* all stream interrupts */
-#define ICH6_INT_CTRL_EN       0x40000000 /* controller interrupt enable bit */
-#define ICH6_INT_GLOBAL_EN     0x80000000 /* global interrupt enable bit */
-
-/* below are so far hardcoded - should read registers in future */
-#define ICH6_MAX_CORB_ENTRIES  256
-#define ICH6_MAX_RIRB_ENTRIES  256
-
-/* position fix mode */
-enum {
-       POS_FIX_AUTO,
-       POS_FIX_LPIB,
-       POS_FIX_POSBUF,
-};
-
-/* Defines for ATI HD Audio support in SB450 south bridge */
-#define ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR   0x42
-#define ATI_SB450_HDAUDIO_ENABLE_SNOOP      0x02
-
-/* Defines for Nvidia HDA support */
-#define NVIDIA_HDA_TRANSREG_ADDR      0x4e
-#define NVIDIA_HDA_ENABLE_COHBITS     0x0f
-#define NVIDIA_HDA_ISTRM_COH          0x4d
-#define NVIDIA_HDA_OSTRM_COH          0x4c
-#define NVIDIA_HDA_ENABLE_COHBIT      0x01
-
-/* Defines for Intel SCH HDA snoop control */
-#define INTEL_SCH_HDA_DEVC      0x78
-#define INTEL_SCH_HDA_DEVC_NOSNOOP       (0x1<<11)
-
-/* Define IN stream 0 FIFO size offset in VIA controller */
-#define VIA_IN_STREAM0_FIFO_SIZE_OFFSET        0x90
-/* Define VIA HD Audio Device ID*/
-#define VIA_HDAC_DEVICE_ID             0x3288
-
-/* HD Audio class code */
-#define PCI_CLASS_MULTIMEDIA_HD_AUDIO  0x0403
-
-/* --------------------------------------------------------------------- */
-/* from linux/sound/pci/hda/hda_codec.h                                  */
-
-/*
- * nodes
- */
-#define        AC_NODE_ROOT            0x00
-
-/*
- * function group types
- */
-enum {
-       AC_GRP_AUDIO_FUNCTION = 0x01,
-       AC_GRP_MODEM_FUNCTION = 0x02,
-};
-       
-/*
- * widget types
- */
-enum {
-       AC_WID_AUD_OUT,         /* Audio Out */
-       AC_WID_AUD_IN,          /* Audio In */
-       AC_WID_AUD_MIX,         /* Audio Mixer */
-       AC_WID_AUD_SEL,         /* Audio Selector */
-       AC_WID_PIN,             /* Pin Complex */
-       AC_WID_POWER,           /* Power */
-       AC_WID_VOL_KNB,         /* Volume Knob */
-       AC_WID_BEEP,            /* Beep Generator */
-       AC_WID_VENDOR = 0x0f    /* Vendor specific */
-};
-
-/*
- * GET verbs
- */
-#define AC_VERB_GET_STREAM_FORMAT              0x0a00
-#define AC_VERB_GET_AMP_GAIN_MUTE              0x0b00
-#define AC_VERB_GET_PROC_COEF                  0x0c00
-#define AC_VERB_GET_COEF_INDEX                 0x0d00
-#define AC_VERB_PARAMETERS                     0x0f00
-#define AC_VERB_GET_CONNECT_SEL                        0x0f01
-#define AC_VERB_GET_CONNECT_LIST               0x0f02
-#define AC_VERB_GET_PROC_STATE                 0x0f03
-#define AC_VERB_GET_SDI_SELECT                 0x0f04
-#define AC_VERB_GET_POWER_STATE                        0x0f05
-#define AC_VERB_GET_CONV                       0x0f06
-#define AC_VERB_GET_PIN_WIDGET_CONTROL         0x0f07
-#define AC_VERB_GET_UNSOLICITED_RESPONSE       0x0f08
-#define AC_VERB_GET_PIN_SENSE                  0x0f09
-#define AC_VERB_GET_BEEP_CONTROL               0x0f0a
-#define AC_VERB_GET_EAPD_BTLENABLE             0x0f0c
-#define AC_VERB_GET_DIGI_CONVERT_1             0x0f0d
-#define AC_VERB_GET_DIGI_CONVERT_2             0x0f0e /* unused */
-#define AC_VERB_GET_VOLUME_KNOB_CONTROL                0x0f0f
-/* f10-f1a: GPIO */
-#define AC_VERB_GET_GPIO_DATA                  0x0f15
-#define AC_VERB_GET_GPIO_MASK                  0x0f16
-#define AC_VERB_GET_GPIO_DIRECTION             0x0f17
-#define AC_VERB_GET_GPIO_WAKE_MASK             0x0f18
-#define AC_VERB_GET_GPIO_UNSOLICITED_RSP_MASK  0x0f19
-#define AC_VERB_GET_GPIO_STICKY_MASK           0x0f1a
-#define AC_VERB_GET_CONFIG_DEFAULT             0x0f1c
-/* f20: AFG/MFG */
-#define AC_VERB_GET_SUBSYSTEM_ID               0x0f20
-#define AC_VERB_GET_CVT_CHAN_COUNT             0x0f2d
-#define AC_VERB_GET_HDMI_DIP_SIZE              0x0f2e
-#define AC_VERB_GET_HDMI_ELDD                  0x0f2f
-#define AC_VERB_GET_HDMI_DIP_INDEX             0x0f30
-#define AC_VERB_GET_HDMI_DIP_DATA              0x0f31
-#define AC_VERB_GET_HDMI_DIP_XMIT              0x0f32
-#define AC_VERB_GET_HDMI_CP_CTRL               0x0f33
-#define AC_VERB_GET_HDMI_CHAN_SLOT             0x0f34
-
-/*
- * SET verbs
- */
-#define AC_VERB_SET_STREAM_FORMAT              0x200
-#define AC_VERB_SET_AMP_GAIN_MUTE              0x300
-#define AC_VERB_SET_PROC_COEF                  0x400
-#define AC_VERB_SET_COEF_INDEX                 0x500
-#define AC_VERB_SET_CONNECT_SEL                        0x701
-#define AC_VERB_SET_PROC_STATE                 0x703
-#define AC_VERB_SET_SDI_SELECT                 0x704
-#define AC_VERB_SET_POWER_STATE                        0x705
-#define AC_VERB_SET_CHANNEL_STREAMID           0x706
-#define AC_VERB_SET_PIN_WIDGET_CONTROL         0x707
-#define AC_VERB_SET_UNSOLICITED_ENABLE         0x708
-#define AC_VERB_SET_PIN_SENSE                  0x709
-#define AC_VERB_SET_BEEP_CONTROL               0x70a
-#define AC_VERB_SET_EAPD_BTLENABLE             0x70c
-#define AC_VERB_SET_DIGI_CONVERT_1             0x70d
-#define AC_VERB_SET_DIGI_CONVERT_2             0x70e
-#define AC_VERB_SET_VOLUME_KNOB_CONTROL                0x70f
-#define AC_VERB_SET_GPIO_DATA                  0x715
-#define AC_VERB_SET_GPIO_MASK                  0x716
-#define AC_VERB_SET_GPIO_DIRECTION             0x717
-#define AC_VERB_SET_GPIO_WAKE_MASK             0x718
-#define AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK  0x719
-#define AC_VERB_SET_GPIO_STICKY_MASK           0x71a
-#define AC_VERB_SET_CONFIG_DEFAULT_BYTES_0     0x71c
-#define AC_VERB_SET_CONFIG_DEFAULT_BYTES_1     0x71d
-#define AC_VERB_SET_CONFIG_DEFAULT_BYTES_2     0x71e
-#define AC_VERB_SET_CONFIG_DEFAULT_BYTES_3     0x71f
-#define AC_VERB_SET_EAPD                               0x788
-#define AC_VERB_SET_CODEC_RESET                        0x7ff
-#define AC_VERB_SET_CVT_CHAN_COUNT             0x72d
-#define AC_VERB_SET_HDMI_DIP_INDEX             0x730
-#define AC_VERB_SET_HDMI_DIP_DATA              0x731
-#define AC_VERB_SET_HDMI_DIP_XMIT              0x732
-#define AC_VERB_SET_HDMI_CP_CTRL               0x733
-#define AC_VERB_SET_HDMI_CHAN_SLOT             0x734
-
-/*
- * Parameter IDs
- */
-#define AC_PAR_VENDOR_ID               0x00
-#define AC_PAR_SUBSYSTEM_ID            0x01
-#define AC_PAR_REV_ID                  0x02
-#define AC_PAR_NODE_COUNT              0x04
-#define AC_PAR_FUNCTION_TYPE           0x05
-#define AC_PAR_AUDIO_FG_CAP            0x08
-#define AC_PAR_AUDIO_WIDGET_CAP                0x09
-#define AC_PAR_PCM                     0x0a
-#define AC_PAR_STREAM                  0x0b
-#define AC_PAR_PIN_CAP                 0x0c
-#define AC_PAR_AMP_IN_CAP              0x0d
-#define AC_PAR_CONNLIST_LEN            0x0e
-#define AC_PAR_POWER_STATE             0x0f
-#define AC_PAR_PROC_CAP                        0x10
-#define AC_PAR_GPIO_CAP                        0x11
-#define AC_PAR_AMP_OUT_CAP             0x12
-#define AC_PAR_VOL_KNB_CAP             0x13
-#define AC_PAR_HDMI_LPCM_CAP           0x20
-
-/*
- * AC_VERB_PARAMETERS results (32bit)
- */
-
-/* Function Group Type */
-#define AC_FGT_TYPE                    (0xff<<0)
-#define AC_FGT_TYPE_SHIFT              0
-#define AC_FGT_UNSOL_CAP               (1<<8)
-
-/* Audio Function Group Capabilities */
-#define AC_AFG_OUT_DELAY               (0xf<<0)
-#define AC_AFG_IN_DELAY                        (0xf<<8)
-#define AC_AFG_BEEP_GEN                        (1<<16)
-
-/* Audio Widget Capabilities */
-#define AC_WCAP_STEREO                 (1<<0)  /* stereo I/O */
-#define AC_WCAP_IN_AMP                 (1<<1)  /* AMP-in present */
-#define AC_WCAP_OUT_AMP                        (1<<2)  /* AMP-out present */
-#define AC_WCAP_AMP_OVRD               (1<<3)  /* AMP-parameter override */
-#define AC_WCAP_FORMAT_OVRD            (1<<4)  /* format override */
-#define AC_WCAP_STRIPE                 (1<<5)  /* stripe */
-#define AC_WCAP_PROC_WID               (1<<6)  /* Proc Widget */
-#define AC_WCAP_UNSOL_CAP              (1<<7)  /* Unsol capable */
-#define AC_WCAP_CONN_LIST              (1<<8)  /* connection list */
-#define AC_WCAP_DIGITAL                        (1<<9)  /* digital I/O */
-#define AC_WCAP_POWER                  (1<<10) /* power control */
-#define AC_WCAP_LR_SWAP                        (1<<11) /* L/R swap */
-#define AC_WCAP_CP_CAPS                        (1<<12) /* content protection */
-#define AC_WCAP_CHAN_CNT_EXT           (7<<13) /* channel count ext */
-#define AC_WCAP_DELAY                  (0xf<<16)
-#define AC_WCAP_DELAY_SHIFT            16
-#define AC_WCAP_TYPE                   (0xf<<20)
-#define AC_WCAP_TYPE_SHIFT             20
-
-/* supported PCM rates and bits */
-#define AC_SUPPCM_RATES                        (0xfff << 0)
-#define AC_SUPPCM_BITS_8               (1<<16)
-#define AC_SUPPCM_BITS_16              (1<<17)
-#define AC_SUPPCM_BITS_20              (1<<18)
-#define AC_SUPPCM_BITS_24              (1<<19)
-#define AC_SUPPCM_BITS_32              (1<<20)
-
-/* supported PCM stream format */
-#define AC_SUPFMT_PCM                  (1<<0)
-#define AC_SUPFMT_FLOAT32              (1<<1)
-#define AC_SUPFMT_AC3                  (1<<2)
-
-/* GP I/O count */
-#define AC_GPIO_IO_COUNT               (0xff<<0)
-#define AC_GPIO_O_COUNT                        (0xff<<8)
-#define AC_GPIO_O_COUNT_SHIFT          8
-#define AC_GPIO_I_COUNT                        (0xff<<16)
-#define AC_GPIO_I_COUNT_SHIFT          16
-#define AC_GPIO_UNSOLICITED            (1<<30)
-#define AC_GPIO_WAKE                   (1<<31)
-
-/* Converter stream, channel */
-#define AC_CONV_CHANNEL                        (0xf<<0)
-#define AC_CONV_STREAM                 (0xf<<4)
-#define AC_CONV_STREAM_SHIFT           4
-
-/* Input converter SDI select */
-#define AC_SDI_SELECT                  (0xf<<0)
-
-/* stream format id */
-#define AC_FMT_CHAN_SHIFT              0
-#define AC_FMT_CHAN_MASK               (0x0f << 0)
-#define AC_FMT_BITS_SHIFT              4
-#define AC_FMT_BITS_MASK               (7 << 4)
-#define AC_FMT_BITS_8                  (0 << 4)
-#define AC_FMT_BITS_16                 (1 << 4)
-#define AC_FMT_BITS_20                 (2 << 4)
-#define AC_FMT_BITS_24                 (3 << 4)
-#define AC_FMT_BITS_32                 (4 << 4)
-#define AC_FMT_DIV_SHIFT               8
-#define AC_FMT_DIV_MASK                        (7 << 8)
-#define AC_FMT_MULT_SHIFT              11
-#define AC_FMT_MULT_MASK               (7 << 11)
-#define AC_FMT_BASE_SHIFT              14
-#define AC_FMT_BASE_48K                        (0 << 14)
-#define AC_FMT_BASE_44K                        (1 << 14)
-#define AC_FMT_TYPE_SHIFT              15
-#define AC_FMT_TYPE_PCM                        (0 << 15)
-#define AC_FMT_TYPE_NON_PCM            (1 << 15)
-
-/* Unsolicited response control */
-#define AC_UNSOL_TAG                   (0x3f<<0)
-#define AC_UNSOL_ENABLED               (1<<7)
-#define AC_USRSP_EN                    AC_UNSOL_ENABLED
-
-/* Unsolicited responses */
-#define AC_UNSOL_RES_TAG               (0x3f<<26)
-#define AC_UNSOL_RES_TAG_SHIFT         26
-#define AC_UNSOL_RES_SUBTAG            (0x1f<<21)
-#define AC_UNSOL_RES_SUBTAG_SHIFT      21
-#define AC_UNSOL_RES_ELDV              (1<<1)  /* ELD Data valid (for HDMI) */
-#define AC_UNSOL_RES_PD                        (1<<0)  /* pinsense detect */
-#define AC_UNSOL_RES_CP_STATE          (1<<1)  /* content protection */
-#define AC_UNSOL_RES_CP_READY          (1<<0)  /* content protection */
-
-/* Pin widget capabilies */
-#define AC_PINCAP_IMP_SENSE            (1<<0)  /* impedance sense capable */
-#define AC_PINCAP_TRIG_REQ             (1<<1)  /* trigger required */
-#define AC_PINCAP_PRES_DETECT          (1<<2)  /* presence detect capable */
-#define AC_PINCAP_HP_DRV               (1<<3)  /* headphone drive capable */
-#define AC_PINCAP_OUT                  (1<<4)  /* output capable */
-#define AC_PINCAP_IN                   (1<<5)  /* input capable */
-#define AC_PINCAP_BALANCE              (1<<6)  /* balanced I/O capable */
-/* Note: This LR_SWAP pincap is defined in the Realtek ALC883 specification,
- *       but is marked reserved in the Intel HDA specification.
- */
-#define AC_PINCAP_LR_SWAP              (1<<7)  /* L/R swap */
-/* Note: The same bit as LR_SWAP is newly defined as HDMI capability
- *       in HD-audio specification
- */
-#define AC_PINCAP_HDMI                 (1<<7)  /* HDMI pin */
-#define AC_PINCAP_DP                   (1<<24) /* DisplayPort pin, can
-                                                * coexist with AC_PINCAP_HDMI
-                                                */
-#define AC_PINCAP_VREF                 (0x37<<8)
-#define AC_PINCAP_VREF_SHIFT           8
-#define AC_PINCAP_EAPD                 (1<<16) /* EAPD capable */
-#define AC_PINCAP_HBR                  (1<<27) /* High Bit Rate */
-/* Vref status (used in pin cap) */
-#define AC_PINCAP_VREF_HIZ             (1<<0)  /* Hi-Z */
-#define AC_PINCAP_VREF_50              (1<<1)  /* 50% */
-#define AC_PINCAP_VREF_GRD             (1<<2)  /* ground */
-#define AC_PINCAP_VREF_80              (1<<4)  /* 80% */
-#define AC_PINCAP_VREF_100             (1<<5)  /* 100% */
-
-/* Amplifier capabilities */
-#define AC_AMPCAP_OFFSET               (0x7f<<0)  /* 0dB offset */
-#define AC_AMPCAP_OFFSET_SHIFT         0
-#define AC_AMPCAP_NUM_STEPS            (0x7f<<8)  /* number of steps */
-#define AC_AMPCAP_NUM_STEPS_SHIFT      8
-#define AC_AMPCAP_STEP_SIZE            (0x7f<<16) /* step size 0-32dB
-                                                   * in 0.25dB
-                                                   */
-#define AC_AMPCAP_STEP_SIZE_SHIFT      16
-#define AC_AMPCAP_MUTE                 (1<<31)    /* mute capable */
-#define AC_AMPCAP_MUTE_SHIFT           31
-
-/* Connection list */
-#define AC_CLIST_LENGTH                        (0x7f<<0)
-#define AC_CLIST_LONG                  (1<<7)
-
-/* Supported power status */
-#define AC_PWRST_D0SUP                 (1<<0)
-#define AC_PWRST_D1SUP                 (1<<1)
-#define AC_PWRST_D2SUP                 (1<<2)
-#define AC_PWRST_D3SUP                 (1<<3)
-#define AC_PWRST_D3COLDSUP             (1<<4)
-#define AC_PWRST_S3D3COLDSUP           (1<<29)
-#define AC_PWRST_CLKSTOP               (1<<30)
-#define AC_PWRST_EPSS                  (1U<<31)
-
-/* Power state values */
-#define AC_PWRST_SETTING               (0xf<<0)
-#define AC_PWRST_ACTUAL                        (0xf<<4)
-#define AC_PWRST_ACTUAL_SHIFT          4
-#define AC_PWRST_D0                    0x00
-#define AC_PWRST_D1                    0x01
-#define AC_PWRST_D2                    0x02
-#define AC_PWRST_D3                    0x03
-
-/* Processing capabilies */
-#define AC_PCAP_BENIGN                 (1<<0)
-#define AC_PCAP_NUM_COEF               (0xff<<8)
-#define AC_PCAP_NUM_COEF_SHIFT         8
-
-/* Volume knobs capabilities */
-#define AC_KNBCAP_NUM_STEPS            (0x7f<<0)
-#define AC_KNBCAP_DELTA                        (1<<7)
-
-/* HDMI LPCM capabilities */
-#define AC_LPCMCAP_48K_CP_CHNS         (0x0f<<0) /* max channels w/ CP-on */   
-#define AC_LPCMCAP_48K_NO_CHNS         (0x0f<<4) /* max channels w/o CP-on */
-#define AC_LPCMCAP_48K_20BIT           (1<<8)  /* 20b bitrate supported */
-#define AC_LPCMCAP_48K_24BIT           (1<<9)  /* 24b bitrate supported */
-#define AC_LPCMCAP_96K_CP_CHNS         (0x0f<<10) /* max channels w/ CP-on */  
-#define AC_LPCMCAP_96K_NO_CHNS         (0x0f<<14) /* max channels w/o CP-on */
-#define AC_LPCMCAP_96K_20BIT           (1<<18) /* 20b bitrate supported */
-#define AC_LPCMCAP_96K_24BIT           (1<<19) /* 24b bitrate supported */
-#define AC_LPCMCAP_192K_CP_CHNS                (0x0f<<20) /* max channels w/ CP-on */  
-#define AC_LPCMCAP_192K_NO_CHNS                (0x0f<<24) /* max channels w/o CP-on */
-#define AC_LPCMCAP_192K_20BIT          (1<<28) /* 20b bitrate supported */
-#define AC_LPCMCAP_192K_24BIT          (1<<29) /* 24b bitrate supported */
-#define AC_LPCMCAP_44K                 (1<<30) /* 44.1kHz support */
-#define AC_LPCMCAP_44K_MS              (1<<31) /* 44.1kHz-multiplies support */
-
-/*
- * Control Parameters
- */
-
-/* Amp gain/mute */
-#define AC_AMP_MUTE                    (1<<7)
-#define AC_AMP_GAIN                    (0x7f)
-#define AC_AMP_GET_INDEX               (0xf<<0)
-
-#define AC_AMP_GET_LEFT                        (1<<13)
-#define AC_AMP_GET_RIGHT               (0<<13)
-#define AC_AMP_GET_OUTPUT              (1<<15)
-#define AC_AMP_GET_INPUT               (0<<15)
-
-#define AC_AMP_SET_INDEX               (0xf<<8)
-#define AC_AMP_SET_INDEX_SHIFT         8
-#define AC_AMP_SET_RIGHT               (1<<12)
-#define AC_AMP_SET_LEFT                        (1<<13)
-#define AC_AMP_SET_INPUT               (1<<14)
-#define AC_AMP_SET_OUTPUT              (1<<15)
-
-/* DIGITAL1 bits */
-#define AC_DIG1_ENABLE                 (1<<0)
-#define AC_DIG1_V                      (1<<1)
-#define AC_DIG1_VCFG                   (1<<2)
-#define AC_DIG1_EMPHASIS               (1<<3)
-#define AC_DIG1_COPYRIGHT              (1<<4)
-#define AC_DIG1_NONAUDIO               (1<<5)
-#define AC_DIG1_PROFESSIONAL           (1<<6)
-#define AC_DIG1_LEVEL                  (1<<7)
-
-/* DIGITAL2 bits */
-#define AC_DIG2_CC                     (0x7f<<0)
-
-/* Pin widget control - 8bit */
-#define AC_PINCTL_EPT                  (0x3<<0)
-#define AC_PINCTL_EPT_NATIVE           0
-#define AC_PINCTL_EPT_HBR              3
-#define AC_PINCTL_VREFEN               (0x7<<0)
-#define AC_PINCTL_VREF_HIZ             0       /* Hi-Z */
-#define AC_PINCTL_VREF_50              1       /* 50% */
-#define AC_PINCTL_VREF_GRD             2       /* ground */
-#define AC_PINCTL_VREF_80              4       /* 80% */
-#define AC_PINCTL_VREF_100             5       /* 100% */
-#define AC_PINCTL_IN_EN                        (1<<5)
-#define AC_PINCTL_OUT_EN               (1<<6)
-#define AC_PINCTL_HP_EN                        (1<<7)
-
-/* Pin sense - 32bit */
-#define AC_PINSENSE_IMPEDANCE_MASK     (0x7fffffff)
-#define AC_PINSENSE_PRESENCE           (1<<31)
-#define AC_PINSENSE_ELDV               (1<<30) /* ELD valid (HDMI) */
-
-/* EAPD/BTL enable - 32bit */
-#define AC_EAPDBTL_BALANCED            (1<<0)
-#define AC_EAPDBTL_EAPD                        (1<<1)
-#define AC_EAPDBTL_LR_SWAP             (1<<2)
-
-/* HDMI ELD data */
-#define AC_ELDD_ELD_VALID              (1<<31)
-#define AC_ELDD_ELD_DATA               0xff
-
-/* HDMI DIP size */
-#define AC_DIPSIZE_ELD_BUF             (1<<3) /* ELD buf size of packet size */
-#define AC_DIPSIZE_PACK_IDX            (0x07<<0) /* packet index */
-
-/* HDMI DIP index */
-#define AC_DIPIDX_PACK_IDX             (0x07<<5) /* packet idnex */
-#define AC_DIPIDX_BYTE_IDX             (0x1f<<0) /* byte index */
-
-/* HDMI DIP xmit (transmit) control */
-#define AC_DIPXMIT_MASK                        (0x3<<6)
-#define AC_DIPXMIT_DISABLE             (0x0<<6) /* disable xmit */
-#define AC_DIPXMIT_ONCE                        (0x2<<6) /* xmit once then disable */
-#define AC_DIPXMIT_BEST                        (0x3<<6) /* best effort */
-
-/* HDMI content protection (CP) control */
-#define AC_CPCTRL_CES                  (1<<9) /* current encryption state */
-#define AC_CPCTRL_READY                        (1<<8) /* ready bit */
-#define AC_CPCTRL_SUBTAG               (0x1f<<3) /* subtag for unsol-resp */
-#define AC_CPCTRL_STATE                        (3<<0) /* current CP request state */
-
-/* Converter channel <-> HDMI slot mapping */
-#define AC_CVTMAP_HDMI_SLOT            (0xf<<0) /* HDMI slot number */
-#define AC_CVTMAP_CHAN                 (0xf<<4) /* converter channel number */
-
-/* configuration default - 32bit */
-#define AC_DEFCFG_SEQUENCE             (0xf<<0)
-#define AC_DEFCFG_DEF_ASSOC            (0xf<<4)
-#define AC_DEFCFG_ASSOC_SHIFT          4
-#define AC_DEFCFG_MISC                 (0xf<<8)
-#define AC_DEFCFG_MISC_SHIFT           8
-#define AC_DEFCFG_MISC_NO_PRESENCE     (1<<0)
-#define AC_DEFCFG_COLOR                        (0xf<<12)
-#define AC_DEFCFG_COLOR_SHIFT          12
-#define AC_DEFCFG_CONN_TYPE            (0xf<<16)
-#define AC_DEFCFG_CONN_TYPE_SHIFT      16
-#define AC_DEFCFG_DEVICE               (0xf<<20)
-#define AC_DEFCFG_DEVICE_SHIFT         20
-#define AC_DEFCFG_LOCATION             (0x3f<<24)
-#define AC_DEFCFG_LOCATION_SHIFT       24
-#define AC_DEFCFG_PORT_CONN            (0x3<<30)
-#define AC_DEFCFG_PORT_CONN_SHIFT      30
-
-/* device device types (0x0-0xf) */
-enum {
-       AC_JACK_LINE_OUT,
-       AC_JACK_SPEAKER,
-       AC_JACK_HP_OUT,
-       AC_JACK_CD,
-       AC_JACK_SPDIF_OUT,
-       AC_JACK_DIG_OTHER_OUT,
-       AC_JACK_MODEM_LINE_SIDE,
-       AC_JACK_MODEM_HAND_SIDE,
-       AC_JACK_LINE_IN,
-       AC_JACK_AUX,
-       AC_JACK_MIC_IN,
-       AC_JACK_TELEPHONY,
-       AC_JACK_SPDIF_IN,
-       AC_JACK_DIG_OTHER_IN,
-       AC_JACK_OTHER = 0xf,
-};
-
-/* jack connection types (0x0-0xf) */
-enum {
-       AC_JACK_CONN_UNKNOWN,
-       AC_JACK_CONN_1_8,
-       AC_JACK_CONN_1_4,
-       AC_JACK_CONN_ATAPI,
-       AC_JACK_CONN_RCA,
-       AC_JACK_CONN_OPTICAL,
-       AC_JACK_CONN_OTHER_DIGITAL,
-       AC_JACK_CONN_OTHER_ANALOG,
-       AC_JACK_CONN_DIN,
-       AC_JACK_CONN_XLR,
-       AC_JACK_CONN_RJ11,
-       AC_JACK_CONN_COMB,
-       AC_JACK_CONN_OTHER = 0xf,
-};
-
-/* jack colors (0x0-0xf) */
-enum {
-       AC_JACK_COLOR_UNKNOWN,
-       AC_JACK_COLOR_BLACK,
-       AC_JACK_COLOR_GREY,
-       AC_JACK_COLOR_BLUE,
-       AC_JACK_COLOR_GREEN,
-       AC_JACK_COLOR_RED,
-       AC_JACK_COLOR_ORANGE,
-       AC_JACK_COLOR_YELLOW,
-       AC_JACK_COLOR_PURPLE,
-       AC_JACK_COLOR_PINK,
-       AC_JACK_COLOR_WHITE = 0xe,
-       AC_JACK_COLOR_OTHER,
-};
-
-/* Jack location (0x0-0x3f) */
-/* common case */
-enum {
-       AC_JACK_LOC_NONE,
-       AC_JACK_LOC_REAR,
-       AC_JACK_LOC_FRONT,
-       AC_JACK_LOC_LEFT,
-       AC_JACK_LOC_RIGHT,
-       AC_JACK_LOC_TOP,
-       AC_JACK_LOC_BOTTOM,
-};
-/* bits 4-5 */
-enum {
-       AC_JACK_LOC_EXTERNAL = 0x00,
-       AC_JACK_LOC_INTERNAL = 0x10,
-       AC_JACK_LOC_SEPARATE = 0x20,
-       AC_JACK_LOC_OTHER    = 0x30,
-};
-enum {
-       /* external on primary chasis */
-       AC_JACK_LOC_REAR_PANEL = 0x07,
-       AC_JACK_LOC_DRIVE_BAY,
-       /* internal */
-       AC_JACK_LOC_RISER = 0x17,
-       AC_JACK_LOC_HDMI,
-       AC_JACK_LOC_ATAPI,
-       /* others */
-       AC_JACK_LOC_MOBILE_IN = 0x37,
-       AC_JACK_LOC_MOBILE_OUT,
-};
-
-/* Port connectivity (0-3) */
-enum {
-       AC_JACK_PORT_COMPLEX,
-       AC_JACK_PORT_NONE,
-       AC_JACK_PORT_FIXED,
-       AC_JACK_PORT_BOTH,
-};
-
-/* max. connections to a widget */
-#define HDA_MAX_CONNECTIONS    32
-
-/* max. codec address */
-#define HDA_MAX_CODEC_ADDRESS  0x0f
-
-/* max number of PCM devics per card */
-#define HDA_MAX_PCMS           10
-
-/* --------------------------------------------------------------------- */
-
-#endif
diff --git a/hw/intel-hda.c b/hw/intel-hda.c
deleted file mode 100644 (file)
index 728b60f..0000000
+++ /dev/null
@@ -1,1329 +0,0 @@
-/*
- * Copyright (C) 2010 Red Hat, Inc.
- *
- * written by Gerd Hoffmann <kraxel@redhat.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 or
- * (at your option) version 3 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
- * 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 "hw/hw.h"
-#include "hw/pci/pci.h"
-#include "hw/pci/msi.h"
-#include "qemu/timer.h"
-#include "hw/audiodev.h"
-#include "hw/intel-hda.h"
-#include "hw/intel-hda-defs.h"
-#include "sysemu/dma.h"
-
-/* --------------------------------------------------------------------- */
-/* hda bus                                                               */
-
-static Property hda_props[] = {
-    DEFINE_PROP_UINT32("cad", HDACodecDevice, cad, -1),
-    DEFINE_PROP_END_OF_LIST()
-};
-
-static const TypeInfo hda_codec_bus_info = {
-    .name = TYPE_HDA_BUS,
-    .parent = TYPE_BUS,
-    .instance_size = sizeof(HDACodecBus),
-};
-
-void hda_codec_bus_init(DeviceState *dev, HDACodecBus *bus,
-                        hda_codec_response_func response,
-                        hda_codec_xfer_func xfer)
-{
-    qbus_create_inplace(&bus->qbus, TYPE_HDA_BUS, dev, NULL);
-    bus->response = response;
-    bus->xfer = xfer;
-}
-
-static int hda_codec_dev_init(DeviceState *qdev)
-{
-    HDACodecBus *bus = DO_UPCAST(HDACodecBus, qbus, qdev->parent_bus);
-    HDACodecDevice *dev = DO_UPCAST(HDACodecDevice, qdev, qdev);
-    HDACodecDeviceClass *cdc = HDA_CODEC_DEVICE_GET_CLASS(dev);
-
-    if (dev->cad == -1) {
-        dev->cad = bus->next_cad;
-    }
-    if (dev->cad >= 15) {
-        return -1;
-    }
-    bus->next_cad = dev->cad + 1;
-    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 (cdc->exit) {
-        cdc->exit(dev);
-    }
-    return 0;
-}
-
-HDACodecDevice *hda_codec_find(HDACodecBus *bus, uint32_t cad)
-{
-    BusChild *kid;
-    HDACodecDevice *cdev;
-
-    QTAILQ_FOREACH(kid, &bus->qbus.children, sibling) {
-        DeviceState *qdev = kid->child;
-        cdev = DO_UPCAST(HDACodecDevice, qdev, qdev);
-        if (cdev->cad == cad) {
-            return cdev;
-        }
-    }
-    return NULL;
-}
-
-void hda_codec_response(HDACodecDevice *dev, bool solicited, uint32_t response)
-{
-    HDACodecBus *bus = DO_UPCAST(HDACodecBus, qbus, dev->qdev.parent_bus);
-    bus->response(dev, solicited, response);
-}
-
-bool hda_codec_xfer(HDACodecDevice *dev, uint32_t stnr, bool output,
-                    uint8_t *buf, uint32_t len)
-{
-    HDACodecBus *bus = DO_UPCAST(HDACodecBus, qbus, dev->qdev.parent_bus);
-    return bus->xfer(dev, stnr, output, buf, len);
-}
-
-/* --------------------------------------------------------------------- */
-/* intel hda emulation                                                   */
-
-typedef struct IntelHDAStream IntelHDAStream;
-typedef struct IntelHDAState IntelHDAState;
-typedef struct IntelHDAReg IntelHDAReg;
-
-typedef struct bpl {
-    uint64_t addr;
-    uint32_t len;
-    uint32_t flags;
-} bpl;
-
-struct IntelHDAStream {
-    /* registers */
-    uint32_t ctl;
-    uint32_t lpib;
-    uint32_t cbl;
-    uint32_t lvi;
-    uint32_t fmt;
-    uint32_t bdlp_lbase;
-    uint32_t bdlp_ubase;
-
-    /* state */
-    bpl      *bpl;
-    uint32_t bentries;
-    uint32_t bsize, be, bp;
-};
-
-struct IntelHDAState {
-    PCIDevice pci;
-    const char *name;
-    HDACodecBus codecs;
-
-    /* registers */
-    uint32_t g_ctl;
-    uint32_t wake_en;
-    uint32_t state_sts;
-    uint32_t int_ctl;
-    uint32_t int_sts;
-    uint32_t wall_clk;
-
-    uint32_t corb_lbase;
-    uint32_t corb_ubase;
-    uint32_t corb_rp;
-    uint32_t corb_wp;
-    uint32_t corb_ctl;
-    uint32_t corb_sts;
-    uint32_t corb_size;
-
-    uint32_t rirb_lbase;
-    uint32_t rirb_ubase;
-    uint32_t rirb_wp;
-    uint32_t rirb_cnt;
-    uint32_t rirb_ctl;
-    uint32_t rirb_sts;
-    uint32_t rirb_size;
-
-    uint32_t dp_lbase;
-    uint32_t dp_ubase;
-
-    uint32_t icw;
-    uint32_t irr;
-    uint32_t ics;
-
-    /* streams */
-    IntelHDAStream st[8];
-
-    /* state */
-    MemoryRegion mmio;
-    uint32_t rirb_count;
-    int64_t wall_base_ns;
-
-    /* debug logging */
-    const IntelHDAReg *last_reg;
-    uint32_t last_val;
-    uint32_t last_write;
-    uint32_t last_sec;
-    uint32_t repeat_count;
-
-    /* properties */
-    uint32_t debug;
-    uint32_t msi;
-};
-
-struct IntelHDAReg {
-    const char *name;      /* register name */
-    uint32_t   size;       /* size in bytes */
-    uint32_t   reset;      /* reset value */
-    uint32_t   wmask;      /* write mask */
-    uint32_t   wclear;     /* write 1 to clear bits */
-    uint32_t   offset;     /* location in IntelHDAState */
-    uint32_t   shift;      /* byte access entries for dwords */
-    uint32_t   stream;
-    void       (*whandler)(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old);
-    void       (*rhandler)(IntelHDAState *d, const IntelHDAReg *reg);
-};
-
-static void intel_hda_reset(DeviceState *dev);
-
-/* --------------------------------------------------------------------- */
-
-static hwaddr intel_hda_addr(uint32_t lbase, uint32_t ubase)
-{
-    hwaddr addr;
-
-    addr = ((uint64_t)ubase << 32) | lbase;
-    return addr;
-}
-
-static void intel_hda_update_int_sts(IntelHDAState *d)
-{
-    uint32_t sts = 0;
-    uint32_t i;
-
-    /* update controller status */
-    if (d->rirb_sts & ICH6_RBSTS_IRQ) {
-        sts |= (1 << 30);
-    }
-    if (d->rirb_sts & ICH6_RBSTS_OVERRUN) {
-        sts |= (1 << 30);
-    }
-    if (d->state_sts & d->wake_en) {
-        sts |= (1 << 30);
-    }
-
-    /* update stream status */
-    for (i = 0; i < 8; i++) {
-        /* buffer completion interrupt */
-        if (d->st[i].ctl & (1 << 26)) {
-            sts |= (1 << i);
-        }
-    }
-
-    /* update global status */
-    if (sts & d->int_ctl) {
-        sts |= (1 << 31);
-    }
-
-    d->int_sts = sts;
-}
-
-static void intel_hda_update_irq(IntelHDAState *d)
-{
-    int msi = d->msi && msi_enabled(&d->pci);
-    int level;
-
-    intel_hda_update_int_sts(d);
-    if (d->int_sts & (1 << 31) && d->int_ctl & (1 << 31)) {
-        level = 1;
-    } else {
-        level = 0;
-    }
-    dprint(d, 2, "%s: level %d [%s]\n", __FUNCTION__,
-           level, msi ? "msi" : "intx");
-    if (msi) {
-        if (level) {
-            msi_notify(&d->pci, 0);
-        }
-    } else {
-        qemu_set_irq(d->pci.irq[0], level);
-    }
-}
-
-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)) {
-        /* indirect node addressing, not specified in HDA 1.0 */
-        dprint(d, 1, "%s: indirect node addressing (guest bug?)\n", __FUNCTION__);
-        return -1;
-    }
-    nid = (verb >> 20) & 0x7f;
-    data = verb & 0xfffff;
-
-    codec = hda_codec_find(&d->codecs, cad);
-    if (codec == NULL) {
-        dprint(d, 1, "%s: addressed non-existing codec\n", __FUNCTION__);
-        return -1;
-    }
-    cdc = HDA_CODEC_DEVICE_GET_CLASS(codec);
-    cdc->command(codec, nid, data);
-    return 0;
-}
-
-static void intel_hda_corb_run(IntelHDAState *d)
-{
-    hwaddr addr;
-    uint32_t rp, verb;
-
-    if (d->ics & ICH6_IRS_BUSY) {
-        dprint(d, 2, "%s: [icw] verb 0x%08x\n", __FUNCTION__, d->icw);
-        intel_hda_send_command(d, d->icw);
-        return;
-    }
-
-    for (;;) {
-        if (!(d->corb_ctl & ICH6_CORBCTL_RUN)) {
-            dprint(d, 2, "%s: !run\n", __FUNCTION__);
-            return;
-        }
-        if ((d->corb_rp & 0xff) == d->corb_wp) {
-            dprint(d, 2, "%s: corb ring empty\n", __FUNCTION__);
-            return;
-        }
-        if (d->rirb_count == d->rirb_cnt) {
-            dprint(d, 2, "%s: rirb count reached\n", __FUNCTION__);
-            return;
-        }
-
-        rp = (d->corb_rp + 1) & 0xff;
-        addr = intel_hda_addr(d->corb_lbase, d->corb_ubase);
-        verb = ldl_le_pci_dma(&d->pci, addr + 4*rp);
-        d->corb_rp = rp;
-
-        dprint(d, 2, "%s: [rp 0x%x] verb 0x%08x\n", __FUNCTION__, rp, verb);
-        intel_hda_send_command(d, verb);
-    }
-}
-
-static void intel_hda_response(HDACodecDevice *dev, bool solicited, uint32_t response)
-{
-    HDACodecBus *bus = DO_UPCAST(HDACodecBus, qbus, dev->qdev.parent_bus);
-    IntelHDAState *d = container_of(bus, IntelHDAState, codecs);
-    hwaddr addr;
-    uint32_t wp, ex;
-
-    if (d->ics & ICH6_IRS_BUSY) {
-        dprint(d, 2, "%s: [irr] response 0x%x, cad 0x%x\n",
-               __FUNCTION__, response, dev->cad);
-        d->irr = response;
-        d->ics &= ~(ICH6_IRS_BUSY | 0xf0);
-        d->ics |= (ICH6_IRS_VALID | (dev->cad << 4));
-        return;
-    }
-
-    if (!(d->rirb_ctl & ICH6_RBCTL_DMA_EN)) {
-        dprint(d, 1, "%s: rirb dma disabled, drop codec response\n", __FUNCTION__);
-        return;
-    }
-
-    ex = (solicited ? 0 : (1 << 4)) | dev->cad;
-    wp = (d->rirb_wp + 1) & 0xff;
-    addr = intel_hda_addr(d->rirb_lbase, d->rirb_ubase);
-    stl_le_pci_dma(&d->pci, addr + 8*wp, response);
-    stl_le_pci_dma(&d->pci, addr + 8*wp + 4, ex);
-    d->rirb_wp = wp;
-
-    dprint(d, 2, "%s: [wp 0x%x] response 0x%x, extra 0x%x\n",
-           __FUNCTION__, wp, response, ex);
-
-    d->rirb_count++;
-    if (d->rirb_count == d->rirb_cnt) {
-        dprint(d, 2, "%s: rirb count reached (%d)\n", __FUNCTION__, d->rirb_count);
-        if (d->rirb_ctl & ICH6_RBCTL_IRQ_EN) {
-            d->rirb_sts |= ICH6_RBSTS_IRQ;
-            intel_hda_update_irq(d);
-        }
-    } else if ((d->corb_rp & 0xff) == d->corb_wp) {
-        dprint(d, 2, "%s: corb ring empty (%d/%d)\n", __FUNCTION__,
-               d->rirb_count, d->rirb_cnt);
-        if (d->rirb_ctl & ICH6_RBCTL_IRQ_EN) {
-            d->rirb_sts |= ICH6_RBSTS_IRQ;
-            intel_hda_update_irq(d);
-        }
-    }
-}
-
-static bool intel_hda_xfer(HDACodecDevice *dev, uint32_t stnr, bool output,
-                           uint8_t *buf, uint32_t len)
-{
-    HDACodecBus *bus = DO_UPCAST(HDACodecBus, qbus, dev->qdev.parent_bus);
-    IntelHDAState *d = container_of(bus, IntelHDAState, codecs);
-    hwaddr addr;
-    uint32_t s, copy, left;
-    IntelHDAStream *st;
-    bool irq = false;
-
-    st = output ? d->st + 4 : d->st;
-    for (s = 0; s < 4; s++) {
-        if (stnr == ((st[s].ctl >> 20) & 0x0f)) {
-            st = st + s;
-            break;
-        }
-    }
-    if (s == 4) {
-        return false;
-    }
-    if (st->bpl == NULL) {
-        return false;
-    }
-    if (st->ctl & (1 << 26)) {
-        /*
-         * Wait with the next DMA xfer until the guest
-         * has acked the buffer completion interrupt
-         */
-        return false;
-    }
-
-    left = len;
-    while (left > 0) {
-        copy = left;
-        if (copy > st->bsize - st->lpib)
-            copy = st->bsize - st->lpib;
-        if (copy > st->bpl[st->be].len - st->bp)
-            copy = st->bpl[st->be].len - st->bp;
-
-        dprint(d, 3, "dma: entry %d, pos %d/%d, copy %d\n",
-               st->be, st->bp, st->bpl[st->be].len, copy);
-
-        pci_dma_rw(&d->pci, st->bpl[st->be].addr + st->bp, buf, copy, !output);
-        st->lpib += copy;
-        st->bp += copy;
-        buf += copy;
-        left -= copy;
-
-        if (st->bpl[st->be].len == st->bp) {
-            /* bpl entry filled */
-            if (st->bpl[st->be].flags & 0x01) {
-                irq = true;
-            }
-            st->bp = 0;
-            st->be++;
-            if (st->be == st->bentries) {
-                /* bpl wrap around */
-                st->be = 0;
-                st->lpib = 0;
-            }
-        }
-    }
-    if (d->dp_lbase & 0x01) {
-        addr = intel_hda_addr(d->dp_lbase & ~0x01, d->dp_ubase);
-        stl_le_pci_dma(&d->pci, addr + 8*s, st->lpib);
-    }
-    dprint(d, 3, "dma: --\n");
-
-    if (irq) {
-        st->ctl |= (1 << 26); /* buffer completion interrupt */
-        intel_hda_update_irq(d);
-    }
-    return true;
-}
-
-static void intel_hda_parse_bdl(IntelHDAState *d, IntelHDAStream *st)
-{
-    hwaddr addr;
-    uint8_t buf[16];
-    uint32_t i;
-
-    addr = intel_hda_addr(st->bdlp_lbase, st->bdlp_ubase);
-    st->bentries = st->lvi +1;
-    g_free(st->bpl);
-    st->bpl = g_malloc(sizeof(bpl) * st->bentries);
-    for (i = 0; i < st->bentries; i++, addr += 16) {
-        pci_dma_read(&d->pci, addr, buf, 16);
-        st->bpl[i].addr  = le64_to_cpu(*(uint64_t *)buf);
-        st->bpl[i].len   = le32_to_cpu(*(uint32_t *)(buf + 8));
-        st->bpl[i].flags = le32_to_cpu(*(uint32_t *)(buf + 12));
-        dprint(d, 1, "bdl/%d: 0x%" PRIx64 " +0x%x, 0x%x\n",
-               i, st->bpl[i].addr, st->bpl[i].len, st->bpl[i].flags);
-    }
-
-    st->bsize = st->cbl;
-    st->lpib  = 0;
-    st->be    = 0;
-    st->bp    = 0;
-}
-
-static void intel_hda_notify_codecs(IntelHDAState *d, uint32_t stream, bool running, bool output)
-{
-    BusChild *kid;
-    HDACodecDevice *cdev;
-
-    QTAILQ_FOREACH(kid, &d->codecs.qbus.children, sibling) {
-        DeviceState *qdev = kid->child;
-        HDACodecDeviceClass *cdc;
-
-        cdev = DO_UPCAST(HDACodecDevice, qdev, qdev);
-        cdc = HDA_CODEC_DEVICE_GET_CLASS(cdev);
-        if (cdc->stream) {
-            cdc->stream(cdev, stream, running, output);
-        }
-    }
-}
-
-/* --------------------------------------------------------------------- */
-
-static void intel_hda_set_g_ctl(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
-{
-    if ((d->g_ctl & ICH6_GCTL_RESET) == 0) {
-        intel_hda_reset(&d->pci.qdev);
-    }
-}
-
-static void intel_hda_set_wake_en(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
-{
-    intel_hda_update_irq(d);
-}
-
-static void intel_hda_set_state_sts(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
-{
-    intel_hda_update_irq(d);
-}
-
-static void intel_hda_set_int_ctl(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
-{
-    intel_hda_update_irq(d);
-}
-
-static void intel_hda_get_wall_clk(IntelHDAState *d, const IntelHDAReg *reg)
-{
-    int64_t ns;
-
-    ns = qemu_get_clock_ns(vm_clock) - d->wall_base_ns;
-    d->wall_clk = (uint32_t)(ns * 24 / 1000);  /* 24 MHz */
-}
-
-static void intel_hda_set_corb_wp(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
-{
-    intel_hda_corb_run(d);
-}
-
-static void intel_hda_set_corb_ctl(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
-{
-    intel_hda_corb_run(d);
-}
-
-static void intel_hda_set_rirb_wp(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
-{
-    if (d->rirb_wp & ICH6_RIRBWP_RST) {
-        d->rirb_wp = 0;
-    }
-}
-
-static void intel_hda_set_rirb_sts(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
-{
-    intel_hda_update_irq(d);
-
-    if ((old & ICH6_RBSTS_IRQ) && !(d->rirb_sts & ICH6_RBSTS_IRQ)) {
-        /* cleared ICH6_RBSTS_IRQ */
-        d->rirb_count = 0;
-        intel_hda_corb_run(d);
-    }
-}
-
-static void intel_hda_set_ics(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
-{
-    if (d->ics & ICH6_IRS_BUSY) {
-        intel_hda_corb_run(d);
-    }
-}
-
-static void intel_hda_set_st_ctl(IntelHDAState *d, const IntelHDAReg *reg, uint32_t old)
-{
-    bool output = reg->stream >= 4;
-    IntelHDAStream *st = d->st + reg->stream;
-
-    if (st->ctl & 0x01) {
-        /* reset */
-        dprint(d, 1, "st #%d: reset\n", reg->stream);
-        st->ctl = 0;
-    }
-    if ((st->ctl & 0x02) != (old & 0x02)) {
-        uint32_t stnr = (st->ctl >> 20) & 0x0f;
-        /* run bit flipped */
-        if (st->ctl & 0x02) {
-            /* start */
-            dprint(d, 1, "st #%d: start %d (ring buf %d bytes)\n",
-                   reg->stream, stnr, st->cbl);
-            intel_hda_parse_bdl(d, st);
-            intel_hda_notify_codecs(d, stnr, true, output);
-        } else {
-            /* stop */
-            dprint(d, 1, "st #%d: stop %d\n", reg->stream, stnr);
-            intel_hda_notify_codecs(d, stnr, false, output);
-        }
-    }
-    intel_hda_update_irq(d);
-}
-
-/* --------------------------------------------------------------------- */
-
-#define ST_REG(_n, _o) (0x80 + (_n) * 0x20 + (_o))
-
-static const struct IntelHDAReg regtab[] = {
-    /* global */
-    [ ICH6_REG_GCAP ] = {
-        .name     = "GCAP",
-        .size     = 2,
-        .reset    = 0x4401,
-    },
-    [ ICH6_REG_VMIN ] = {
-        .name     = "VMIN",
-        .size     = 1,
-    },
-    [ ICH6_REG_VMAJ ] = {
-        .name     = "VMAJ",
-        .size     = 1,
-        .reset    = 1,
-    },
-    [ ICH6_REG_OUTPAY ] = {
-        .name     = "OUTPAY",
-        .size     = 2,
-        .reset    = 0x3c,
-    },
-    [ ICH6_REG_INPAY ] = {
-        .name     = "INPAY",
-        .size     = 2,
-        .reset    = 0x1d,
-    },
-    [ ICH6_REG_GCTL ] = {
-        .name     = "GCTL",
-        .size     = 4,
-        .wmask    = 0x0103,
-        .offset   = offsetof(IntelHDAState, g_ctl),
-        .whandler = intel_hda_set_g_ctl,
-    },
-    [ ICH6_REG_WAKEEN ] = {
-        .name     = "WAKEEN",
-        .size     = 2,
-        .wmask    = 0x7fff,
-        .offset   = offsetof(IntelHDAState, wake_en),
-        .whandler = intel_hda_set_wake_en,
-    },
-    [ ICH6_REG_STATESTS ] = {
-        .name     = "STATESTS",
-        .size     = 2,
-        .wmask    = 0x7fff,
-        .wclear   = 0x7fff,
-        .offset   = offsetof(IntelHDAState, state_sts),
-        .whandler = intel_hda_set_state_sts,
-    },
-
-    /* interrupts */
-    [ ICH6_REG_INTCTL ] = {
-        .name     = "INTCTL",
-        .size     = 4,
-        .wmask    = 0xc00000ff,
-        .offset   = offsetof(IntelHDAState, int_ctl),
-        .whandler = intel_hda_set_int_ctl,
-    },
-    [ ICH6_REG_INTSTS ] = {
-        .name     = "INTSTS",
-        .size     = 4,
-        .wmask    = 0xc00000ff,
-        .wclear   = 0xc00000ff,
-        .offset   = offsetof(IntelHDAState, int_sts),
-    },
-
-    /* misc */
-    [ ICH6_REG_WALLCLK ] = {
-        .name     = "WALLCLK",
-        .size     = 4,
-        .offset   = offsetof(IntelHDAState, wall_clk),
-        .rhandler = intel_hda_get_wall_clk,
-    },
-    [ ICH6_REG_WALLCLK + 0x2000 ] = {
-        .name     = "WALLCLK(alias)",
-        .size     = 4,
-        .offset   = offsetof(IntelHDAState, wall_clk),
-        .rhandler = intel_hda_get_wall_clk,
-    },
-
-    /* dma engine */
-    [ ICH6_REG_CORBLBASE ] = {
-        .name     = "CORBLBASE",
-        .size     = 4,
-        .wmask    = 0xffffff80,
-        .offset   = offsetof(IntelHDAState, corb_lbase),
-    },
-    [ ICH6_REG_CORBUBASE ] = {
-        .name     = "CORBUBASE",
-        .size     = 4,
-        .wmask    = 0xffffffff,
-        .offset   = offsetof(IntelHDAState, corb_ubase),
-    },
-    [ ICH6_REG_CORBWP ] = {
-        .name     = "CORBWP",
-        .size     = 2,
-        .wmask    = 0xff,
-        .offset   = offsetof(IntelHDAState, corb_wp),
-        .whandler = intel_hda_set_corb_wp,
-    },
-    [ ICH6_REG_CORBRP ] = {
-        .name     = "CORBRP",
-        .size     = 2,
-        .wmask    = 0x80ff,
-        .offset   = offsetof(IntelHDAState, corb_rp),
-    },
-    [ ICH6_REG_CORBCTL ] = {
-        .name     = "CORBCTL",
-        .size     = 1,
-        .wmask    = 0x03,
-        .offset   = offsetof(IntelHDAState, corb_ctl),
-        .whandler = intel_hda_set_corb_ctl,
-    },
-    [ ICH6_REG_CORBSTS ] = {
-        .name     = "CORBSTS",
-        .size     = 1,
-        .wmask    = 0x01,
-        .wclear   = 0x01,
-        .offset   = offsetof(IntelHDAState, corb_sts),
-    },
-    [ ICH6_REG_CORBSIZE ] = {
-        .name     = "CORBSIZE",
-        .size     = 1,
-        .reset    = 0x42,
-        .offset   = offsetof(IntelHDAState, corb_size),
-    },
-    [ ICH6_REG_RIRBLBASE ] = {
-        .name     = "RIRBLBASE",
-        .size     = 4,
-        .wmask    = 0xffffff80,
-        .offset   = offsetof(IntelHDAState, rirb_lbase),
-    },
-    [ ICH6_REG_RIRBUBASE ] = {
-        .name     = "RIRBUBASE",
-        .size     = 4,
-        .wmask    = 0xffffffff,
-        .offset   = offsetof(IntelHDAState, rirb_ubase),
-    },
-    [ ICH6_REG_RIRBWP ] = {
-        .name     = "RIRBWP",
-        .size     = 2,
-        .wmask    = 0x8000,
-        .offset   = offsetof(IntelHDAState, rirb_wp),
-        .whandler = intel_hda_set_rirb_wp,
-    },
-    [ ICH6_REG_RINTCNT ] = {
-        .name     = "RINTCNT",
-        .size     = 2,
-        .wmask    = 0xff,
-        .offset   = offsetof(IntelHDAState, rirb_cnt),
-    },
-    [ ICH6_REG_RIRBCTL ] = {
-        .name     = "RIRBCTL",
-        .size     = 1,
-        .wmask    = 0x07,
-        .offset   = offsetof(IntelHDAState, rirb_ctl),
-    },
-    [ ICH6_REG_RIRBSTS ] = {
-        .name     = "RIRBSTS",
-        .size     = 1,
-        .wmask    = 0x05,
-        .wclear   = 0x05,
-        .offset   = offsetof(IntelHDAState, rirb_sts),
-        .whandler = intel_hda_set_rirb_sts,
-    },
-    [ ICH6_REG_RIRBSIZE ] = {
-        .name     = "RIRBSIZE",
-        .size     = 1,
-        .reset    = 0x42,
-        .offset   = offsetof(IntelHDAState, rirb_size),
-    },
-
-    [ ICH6_REG_DPLBASE ] = {
-        .name     = "DPLBASE",
-        .size     = 4,
-        .wmask    = 0xffffff81,
-        .offset   = offsetof(IntelHDAState, dp_lbase),
-    },
-    [ ICH6_REG_DPUBASE ] = {
-        .name     = "DPUBASE",
-        .size     = 4,
-        .wmask    = 0xffffffff,
-        .offset   = offsetof(IntelHDAState, dp_ubase),
-    },
-
-    [ ICH6_REG_IC ] = {
-        .name     = "ICW",
-        .size     = 4,
-        .wmask    = 0xffffffff,
-        .offset   = offsetof(IntelHDAState, icw),
-    },
-    [ ICH6_REG_IR ] = {
-        .name     = "IRR",
-        .size     = 4,
-        .offset   = offsetof(IntelHDAState, irr),
-    },
-    [ ICH6_REG_IRS ] = {
-        .name     = "ICS",
-        .size     = 2,
-        .wmask    = 0x0003,
-        .wclear   = 0x0002,
-        .offset   = offsetof(IntelHDAState, ics),
-        .whandler = intel_hda_set_ics,
-    },
-
-#define HDA_STREAM(_t, _i)                                            \
-    [ ST_REG(_i, ICH6_REG_SD_CTL) ] = {                               \
-        .stream   = _i,                                               \
-        .name     = _t stringify(_i) " CTL",                          \
-        .size     = 4,                                                \
-        .wmask    = 0x1cff001f,                                       \
-        .offset   = offsetof(IntelHDAState, st[_i].ctl),              \
-        .whandler = intel_hda_set_st_ctl,                             \
-    },                                                                \
-    [ ST_REG(_i, ICH6_REG_SD_CTL) + 2] = {                            \
-        .stream   = _i,                                               \
-        .name     = _t stringify(_i) " CTL(stnr)",                    \
-        .size     = 1,                                                \
-        .shift    = 16,                                               \
-        .wmask    = 0x00ff0000,                                       \
-        .offset   = offsetof(IntelHDAState, st[_i].ctl),              \
-        .whandler = intel_hda_set_st_ctl,                             \
-    },                                                                \
-    [ ST_REG(_i, ICH6_REG_SD_STS)] = {                                \
-        .stream   = _i,                                               \
-        .name     = _t stringify(_i) " CTL(sts)",                     \
-        .size     = 1,                                                \
-        .shift    = 24,                                               \
-        .wmask    = 0x1c000000,                                       \
-        .wclear   = 0x1c000000,                                       \
-        .offset   = offsetof(IntelHDAState, st[_i].ctl),              \
-        .whandler = intel_hda_set_st_ctl,                             \
-    },                                                                \
-    [ ST_REG(_i, ICH6_REG_SD_LPIB) ] = {                              \
-        .stream   = _i,                                               \
-        .name     = _t stringify(_i) " LPIB",                         \
-        .size     = 4,                                                \
-        .offset   = offsetof(IntelHDAState, st[_i].lpib),             \
-    },                                                                \
-    [ ST_REG(_i, ICH6_REG_SD_LPIB) + 0x2000 ] = {                     \
-        .stream   = _i,                                               \
-        .name     = _t stringify(_i) " LPIB(alias)",                  \
-        .size     = 4,                                                \
-        .offset   = offsetof(IntelHDAState, st[_i].lpib),             \
-    },                                                                \
-    [ ST_REG(_i, ICH6_REG_SD_CBL) ] = {                               \
-        .stream   = _i,                                               \
-        .name     = _t stringify(_i) " CBL",                          \
-        .size     = 4,                                                \
-        .wmask    = 0xffffffff,                                       \
-        .offset   = offsetof(IntelHDAState, st[_i].cbl),              \
-    },                                                                \
-    [ ST_REG(_i, ICH6_REG_SD_LVI) ] = {                               \
-        .stream   = _i,                                               \
-        .name     = _t stringify(_i) " LVI",                          \
-        .size     = 2,                                                \
-        .wmask    = 0x00ff,                                           \
-        .offset   = offsetof(IntelHDAState, st[_i].lvi),              \
-    },                                                                \
-    [ ST_REG(_i, ICH6_REG_SD_FIFOSIZE) ] = {                          \
-        .stream   = _i,                                               \
-        .name     = _t stringify(_i) " FIFOS",                        \
-        .size     = 2,                                                \
-        .reset    = HDA_BUFFER_SIZE,                                  \
-    },                                                                \
-    [ ST_REG(_i, ICH6_REG_SD_FORMAT) ] = {                            \
-        .stream   = _i,                                               \
-        .name     = _t stringify(_i) " FMT",                          \
-        .size     = 2,                                                \
-        .wmask    = 0x7f7f,                                           \
-        .offset   = offsetof(IntelHDAState, st[_i].fmt),              \
-    },                                                                \
-    [ ST_REG(_i, ICH6_REG_SD_BDLPL) ] = {                             \
-        .stream   = _i,                                               \
-        .name     = _t stringify(_i) " BDLPL",                        \
-        .size     = 4,                                                \
-        .wmask    = 0xffffff80,                                       \
-        .offset   = offsetof(IntelHDAState, st[_i].bdlp_lbase),       \
-    },                                                                \
-    [ ST_REG(_i, ICH6_REG_SD_BDLPU) ] = {                             \
-        .stream   = _i,                                               \
-        .name     = _t stringify(_i) " BDLPU",                        \
-        .size     = 4,                                                \
-        .wmask    = 0xffffffff,                                       \
-        .offset   = offsetof(IntelHDAState, st[_i].bdlp_ubase),       \
-    },                                                                \
-
-    HDA_STREAM("IN", 0)
-    HDA_STREAM("IN", 1)
-    HDA_STREAM("IN", 2)
-    HDA_STREAM("IN", 3)
-
-    HDA_STREAM("OUT", 4)
-    HDA_STREAM("OUT", 5)
-    HDA_STREAM("OUT", 6)
-    HDA_STREAM("OUT", 7)
-
-};
-
-static const IntelHDAReg *intel_hda_reg_find(IntelHDAState *d, hwaddr addr)
-{
-    const IntelHDAReg *reg;
-
-    if (addr >= sizeof(regtab)/sizeof(regtab[0])) {
-        goto noreg;
-    }
-    reg = regtab+addr;
-    if (reg->name == NULL) {
-        goto noreg;
-    }
-    return reg;
-
-noreg:
-    dprint(d, 1, "unknown register, addr 0x%x\n", (int) addr);
-    return NULL;
-}
-
-static uint32_t *intel_hda_reg_addr(IntelHDAState *d, const IntelHDAReg *reg)
-{
-    uint8_t *addr = (void*)d;
-
-    addr += reg->offset;
-    return (uint32_t*)addr;
-}
-
-static void intel_hda_reg_write(IntelHDAState *d, const IntelHDAReg *reg, uint32_t val,
-                                uint32_t wmask)
-{
-    uint32_t *addr;
-    uint32_t old;
-
-    if (!reg) {
-        return;
-    }
-
-    if (d->debug) {
-        time_t now = time(NULL);
-        if (d->last_write && d->last_reg == reg && d->last_val == val) {
-            d->repeat_count++;
-            if (d->last_sec != now) {
-                dprint(d, 2, "previous register op repeated %d times\n", d->repeat_count);
-                d->last_sec = now;
-                d->repeat_count = 0;
-            }
-        } else {
-            if (d->repeat_count) {
-                dprint(d, 2, "previous register op repeated %d times\n", d->repeat_count);
-            }
-            dprint(d, 2, "write %-16s: 0x%x (%x)\n", reg->name, val, wmask);
-            d->last_write = 1;
-            d->last_reg   = reg;
-            d->last_val   = val;
-            d->last_sec   = now;
-            d->repeat_count = 0;
-        }
-    }
-    assert(reg->offset != 0);
-
-    addr = intel_hda_reg_addr(d, reg);
-    old = *addr;
-
-    if (reg->shift) {
-        val <<= reg->shift;
-        wmask <<= reg->shift;
-    }
-    wmask &= reg->wmask;
-    *addr &= ~wmask;
-    *addr |= wmask & val;
-    *addr &= ~(val & reg->wclear);
-
-    if (reg->whandler) {
-        reg->whandler(d, reg, old);
-    }
-}
-
-static uint32_t intel_hda_reg_read(IntelHDAState *d, const IntelHDAReg *reg,
-                                   uint32_t rmask)
-{
-    uint32_t *addr, ret;
-
-    if (!reg) {
-        return 0;
-    }
-
-    if (reg->rhandler) {
-        reg->rhandler(d, reg);
-    }
-
-    if (reg->offset == 0) {
-        /* constant read-only register */
-        ret = reg->reset;
-    } else {
-        addr = intel_hda_reg_addr(d, reg);
-        ret = *addr;
-        if (reg->shift) {
-            ret >>= reg->shift;
-        }
-        ret &= rmask;
-    }
-    if (d->debug) {
-        time_t now = time(NULL);
-        if (!d->last_write && d->last_reg == reg && d->last_val == ret) {
-            d->repeat_count++;
-            if (d->last_sec != now) {
-                dprint(d, 2, "previous register op repeated %d times\n", d->repeat_count);
-                d->last_sec = now;
-                d->repeat_count = 0;
-            }
-        } else {
-            if (d->repeat_count) {
-                dprint(d, 2, "previous register op repeated %d times\n", d->repeat_count);
-            }
-            dprint(d, 2, "read  %-16s: 0x%x (%x)\n", reg->name, ret, rmask);
-            d->last_write = 0;
-            d->last_reg   = reg;
-            d->last_val   = ret;
-            d->last_sec   = now;
-            d->repeat_count = 0;
-        }
-    }
-    return ret;
-}
-
-static void intel_hda_regs_reset(IntelHDAState *d)
-{
-    uint32_t *addr;
-    int i;
-
-    for (i = 0; i < sizeof(regtab)/sizeof(regtab[0]); i++) {
-        if (regtab[i].name == NULL) {
-            continue;
-        }
-        if (regtab[i].offset == 0) {
-            continue;
-        }
-        addr = intel_hda_reg_addr(d, regtab + i);
-        *addr = regtab[i].reset;
-    }
-}
-
-/* --------------------------------------------------------------------- */
-
-static void intel_hda_mmio_writeb(void *opaque, hwaddr addr, uint32_t val)
-{
-    IntelHDAState *d = opaque;
-    const IntelHDAReg *reg = intel_hda_reg_find(d, addr);
-
-    intel_hda_reg_write(d, reg, val, 0xff);
-}
-
-static void intel_hda_mmio_writew(void *opaque, hwaddr addr, uint32_t val)
-{
-    IntelHDAState *d = opaque;
-    const IntelHDAReg *reg = intel_hda_reg_find(d, addr);
-
-    intel_hda_reg_write(d, reg, val, 0xffff);
-}
-
-static void intel_hda_mmio_writel(void *opaque, hwaddr addr, uint32_t val)
-{
-    IntelHDAState *d = opaque;
-    const IntelHDAReg *reg = intel_hda_reg_find(d, addr);
-
-    intel_hda_reg_write(d, reg, val, 0xffffffff);
-}
-
-static uint32_t intel_hda_mmio_readb(void *opaque, hwaddr addr)
-{
-    IntelHDAState *d = opaque;
-    const IntelHDAReg *reg = intel_hda_reg_find(d, addr);
-
-    return intel_hda_reg_read(d, reg, 0xff);
-}
-
-static uint32_t intel_hda_mmio_readw(void *opaque, hwaddr addr)
-{
-    IntelHDAState *d = opaque;
-    const IntelHDAReg *reg = intel_hda_reg_find(d, addr);
-
-    return intel_hda_reg_read(d, reg, 0xffff);
-}
-
-static uint32_t intel_hda_mmio_readl(void *opaque, hwaddr addr)
-{
-    IntelHDAState *d = opaque;
-    const IntelHDAReg *reg = intel_hda_reg_find(d, addr);
-
-    return intel_hda_reg_read(d, reg, 0xffffffff);
-}
-
-static const MemoryRegionOps intel_hda_mmio_ops = {
-    .old_mmio = {
-        .read = {
-            intel_hda_mmio_readb,
-            intel_hda_mmio_readw,
-            intel_hda_mmio_readl,
-        },
-        .write = {
-            intel_hda_mmio_writeb,
-            intel_hda_mmio_writew,
-            intel_hda_mmio_writel,
-        },
-    },
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-/* --------------------------------------------------------------------- */
-
-static void intel_hda_reset(DeviceState *dev)
-{
-    BusChild *kid;
-    IntelHDAState *d = DO_UPCAST(IntelHDAState, pci.qdev, dev);
-    HDACodecDevice *cdev;
-
-    intel_hda_regs_reset(d);
-    d->wall_base_ns = qemu_get_clock_ns(vm_clock);
-
-    /* reset codecs */
-    QTAILQ_FOREACH(kid, &d->codecs.qbus.children, sibling) {
-        DeviceState *qdev = kid->child;
-        cdev = DO_UPCAST(HDACodecDevice, qdev, qdev);
-        device_reset(DEVICE(cdev));
-        d->state_sts |= (1 << cdev->cad);
-    }
-    intel_hda_update_irq(d);
-}
-
-static int intel_hda_init(PCIDevice *pci)
-{
-    IntelHDAState *d = DO_UPCAST(IntelHDAState, pci, pci);
-    uint8_t *conf = d->pci.config;
-
-    d->name = object_get_typename(OBJECT(d));
-
-    pci_config_set_interrupt_pin(conf, 1);
-
-    /* HDCTL off 0x40 bit 0 selects signaling mode (1-HDA, 0 - Ac97) 18.1.19 */
-    conf[0x40] = 0x01;
-
-    memory_region_init_io(&d->mmio, &intel_hda_mmio_ops, d,
-                          "intel-hda", 0x4000);
-    pci_register_bar(&d->pci, 0, 0, &d->mmio);
-    if (d->msi) {
-        msi_init(&d->pci, 0x50, 1, true, false);
-    }
-
-    hda_codec_bus_init(&d->pci.qdev, &d->codecs,
-                       intel_hda_response, intel_hda_xfer);
-
-    return 0;
-}
-
-static void intel_hda_exit(PCIDevice *pci)
-{
-    IntelHDAState *d = DO_UPCAST(IntelHDAState, pci, pci);
-
-    msi_uninit(&d->pci);
-    memory_region_destroy(&d->mmio);
-}
-
-static int intel_hda_post_load(void *opaque, int version)
-{
-    IntelHDAState* d = opaque;
-    int i;
-
-    dprint(d, 1, "%s\n", __FUNCTION__);
-    for (i = 0; i < ARRAY_SIZE(d->st); i++) {
-        if (d->st[i].ctl & 0x02) {
-            intel_hda_parse_bdl(d, &d->st[i]);
-        }
-    }
-    intel_hda_update_irq(d);
-    return 0;
-}
-
-static const VMStateDescription vmstate_intel_hda_stream = {
-    .name = "intel-hda-stream",
-    .version_id = 1,
-    .fields = (VMStateField []) {
-        VMSTATE_UINT32(ctl, IntelHDAStream),
-        VMSTATE_UINT32(lpib, IntelHDAStream),
-        VMSTATE_UINT32(cbl, IntelHDAStream),
-        VMSTATE_UINT32(lvi, IntelHDAStream),
-        VMSTATE_UINT32(fmt, IntelHDAStream),
-        VMSTATE_UINT32(bdlp_lbase, IntelHDAStream),
-        VMSTATE_UINT32(bdlp_ubase, IntelHDAStream),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static const VMStateDescription vmstate_intel_hda = {
-    .name = "intel-hda",
-    .version_id = 1,
-    .post_load = intel_hda_post_load,
-    .fields = (VMStateField []) {
-        VMSTATE_PCI_DEVICE(pci, IntelHDAState),
-
-        /* registers */
-        VMSTATE_UINT32(g_ctl, IntelHDAState),
-        VMSTATE_UINT32(wake_en, IntelHDAState),
-        VMSTATE_UINT32(state_sts, IntelHDAState),
-        VMSTATE_UINT32(int_ctl, IntelHDAState),
-        VMSTATE_UINT32(int_sts, IntelHDAState),
-        VMSTATE_UINT32(wall_clk, IntelHDAState),
-        VMSTATE_UINT32(corb_lbase, IntelHDAState),
-        VMSTATE_UINT32(corb_ubase, IntelHDAState),
-        VMSTATE_UINT32(corb_rp, IntelHDAState),
-        VMSTATE_UINT32(corb_wp, IntelHDAState),
-        VMSTATE_UINT32(corb_ctl, IntelHDAState),
-        VMSTATE_UINT32(corb_sts, IntelHDAState),
-        VMSTATE_UINT32(corb_size, IntelHDAState),
-        VMSTATE_UINT32(rirb_lbase, IntelHDAState),
-        VMSTATE_UINT32(rirb_ubase, IntelHDAState),
-        VMSTATE_UINT32(rirb_wp, IntelHDAState),
-        VMSTATE_UINT32(rirb_cnt, IntelHDAState),
-        VMSTATE_UINT32(rirb_ctl, IntelHDAState),
-        VMSTATE_UINT32(rirb_sts, IntelHDAState),
-        VMSTATE_UINT32(rirb_size, IntelHDAState),
-        VMSTATE_UINT32(dp_lbase, IntelHDAState),
-        VMSTATE_UINT32(dp_ubase, IntelHDAState),
-        VMSTATE_UINT32(icw, IntelHDAState),
-        VMSTATE_UINT32(irr, IntelHDAState),
-        VMSTATE_UINT32(ics, IntelHDAState),
-        VMSTATE_STRUCT_ARRAY(st, IntelHDAState, 8, 0,
-                             vmstate_intel_hda_stream,
-                             IntelHDAStream),
-
-        /* additional state info */
-        VMSTATE_UINT32(rirb_count, IntelHDAState),
-        VMSTATE_INT64(wall_base_ns, IntelHDAState),
-
-        VMSTATE_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_common(ObjectClass *klass)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
-    k->init = intel_hda_init;
-    k->exit = intel_hda_exit;
-    k->vendor_id = PCI_VENDOR_ID_INTEL;
-    k->class_id = PCI_CLASS_MULTIMEDIA_HD_AUDIO;
-    dc->reset = intel_hda_reset;
-    dc->vmsd = &vmstate_intel_hda;
-    dc->props = intel_hda_properties;
-}
-
-static void intel_hda_class_init_ich6(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
-    intel_hda_class_init_common(klass);
-    k->device_id = 0x2668;
-    k->revision = 1;
-    dc->desc = "Intel HD Audio Controller (ich6)";
-}
-
-static void intel_hda_class_init_ich9(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
-    intel_hda_class_init_common(klass);
-    k->device_id = 0x293e;
-    k->revision = 3;
-    dc->desc = "Intel HD Audio Controller (ich9)";
-}
-
-static const TypeInfo intel_hda_info_ich6 = {
-    .name          = "intel-hda",
-    .parent        = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(IntelHDAState),
-    .class_init    = intel_hda_class_init_ich6,
-};
-
-static const TypeInfo intel_hda_info_ich9 = {
-    .name          = "ich9-intel-hda",
-    .parent        = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(IntelHDAState),
-    .class_init    = intel_hda_class_init_ich9,
-};
-
-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_type = TYPE_HDA_BUS;
-    k->props = hda_props;
-}
-
-static const 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_types(void)
-{
-    type_register_static(&hda_codec_bus_info);
-    type_register_static(&intel_hda_info_ich6);
-    type_register_static(&intel_hda_info_ich9);
-    type_register_static(&hda_codec_device_type_info);
-}
-
-type_init(intel_hda_register_types)
-
-/*
- * create intel hda controller with codec attached to it,
- * so '-soundhw hda' works.
- */
-int intel_hda_and_codec_init(PCIBus *bus)
-{
-    PCIDevice *controller;
-    BusState *hdabus;
-    DeviceState *codec;
-
-    controller = pci_create_simple(bus, -1, "intel-hda");
-    hdabus = QLIST_FIRST(&controller->qdev.child_bus);
-    codec = qdev_create(hdabus, "hda-duplex");
-    qdev_init_nofail(codec);
-    return 0;
-}
-
diff --git a/hw/intel-hda.h b/hw/intel-hda.h
deleted file mode 100644 (file)
index 2544f0a..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-#ifndef HW_INTEL_HDA_H
-#define HW_INTEL_HDA_H
-
-#include "hw/qdev.h"
-
-/* --------------------------------------------------------------------- */
-/* 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)
-
-#define TYPE_HDA_BUS "HDA"
-#define HDA_BUS(obj) OBJECT_CHECK(HDACodecBus, (obj), TYPE_HDA_BUS)
-
-typedef struct HDACodecBus HDACodecBus;
-typedef struct HDACodecDevice HDACodecDevice;
-
-typedef void (*hda_codec_response_func)(HDACodecDevice *dev,
-                                        bool solicited, uint32_t response);
-typedef bool (*hda_codec_xfer_func)(HDACodecDevice *dev,
-                                    uint32_t stnr, bool output,
-                                    uint8_t *buf, uint32_t len);
-
-struct HDACodecBus {
-    BusState qbus;
-    uint32_t next_cad;
-    hda_codec_response_func response;
-    hda_codec_xfer_func xfer;
-};
-
-typedef struct HDACodecDeviceClass
-{
-    DeviceClass parent_class;
-
-    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);
-HDACodecDevice *hda_codec_find(HDACodecBus *bus, uint32_t cad);
-
-void hda_codec_response(HDACodecDevice *dev, bool solicited, uint32_t response);
-bool hda_codec_xfer(HDACodecDevice *dev, uint32_t stnr, bool output,
-                    uint8_t *buf, uint32_t len);
-
-/* --------------------------------------------------------------------- */
-
-#define dprint(_dev, _level, _fmt, ...)                                 \
-    do {                                                                \
-        if (_dev->debug >= _level) {                                    \
-            fprintf(stderr, "%s: ", _dev->name);                        \
-            fprintf(stderr, _fmt, ## __VA_ARGS__);                      \
-        }                                                               \
-    } while (0)
-
-/* --------------------------------------------------------------------- */
-
-#endif
diff --git a/hw/ioapic.c b/hw/ioapic.c
deleted file mode 100644 (file)
index 78629fa..0000000
+++ /dev/null
@@ -1,259 +0,0 @@
-/*
- *  ioapic.c IOAPIC emulation logic
- *
- *  Copyright (c) 2004-2005 Fabrice Bellard
- *
- *  Split the ioapic logic from apic.c
- *  Xiantao Zhang <xiantao.zhang@intel.com>
- *
- * 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/hw.h"
-#include "hw/pc.h"
-#include "hw/apic.h"
-#include "hw/ioapic.h"
-#include "hw/ioapic_internal.h"
-
-//#define DEBUG_IOAPIC
-
-#ifdef DEBUG_IOAPIC
-#define DPRINTF(fmt, ...)                                       \
-    do { printf("ioapic: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...)
-#endif
-
-static IOAPICCommonState *ioapics[MAX_IOAPICS];
-
-static void ioapic_service(IOAPICCommonState *s)
-{
-    uint8_t i;
-    uint8_t trig_mode;
-    uint8_t vector;
-    uint8_t delivery_mode;
-    uint32_t mask;
-    uint64_t entry;
-    uint8_t dest;
-    uint8_t dest_mode;
-
-    for (i = 0; i < IOAPIC_NUM_PINS; i++) {
-        mask = 1 << i;
-        if (s->irr & mask) {
-            entry = s->ioredtbl[i];
-            if (!(entry & IOAPIC_LVT_MASKED)) {
-                trig_mode = ((entry >> IOAPIC_LVT_TRIGGER_MODE_SHIFT) & 1);
-                dest = entry >> IOAPIC_LVT_DEST_SHIFT;
-                dest_mode = (entry >> IOAPIC_LVT_DEST_MODE_SHIFT) & 1;
-                delivery_mode =
-                    (entry >> IOAPIC_LVT_DELIV_MODE_SHIFT) & IOAPIC_DM_MASK;
-                if (trig_mode == IOAPIC_TRIGGER_EDGE) {
-                    s->irr &= ~mask;
-                } else {
-                    s->ioredtbl[i] |= IOAPIC_LVT_REMOTE_IRR;
-                }
-                if (delivery_mode == IOAPIC_DM_EXTINT) {
-                    vector = pic_read_irq(isa_pic);
-                } else {
-                    vector = entry & IOAPIC_VECTOR_MASK;
-                }
-                apic_deliver_irq(dest, dest_mode, delivery_mode,
-                                 vector, trig_mode);
-            }
-        }
-    }
-}
-
-static void ioapic_set_irq(void *opaque, int vector, int level)
-{
-    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
-     * the cleanest way of doing it but it should work. */
-
-    DPRINTF("%s: %s vec %x\n", __func__, level ? "raise" : "lower", vector);
-    if (vector == 0) {
-        vector = 2;
-    }
-    if (vector >= 0 && vector < IOAPIC_NUM_PINS) {
-        uint32_t mask = 1 << vector;
-        uint64_t entry = s->ioredtbl[vector];
-
-        if (entry & (1 << IOAPIC_LVT_POLARITY_SHIFT)) {
-            level = !level;
-        }
-        if (((entry >> IOAPIC_LVT_TRIGGER_MODE_SHIFT) & 1) ==
-            IOAPIC_TRIGGER_LEVEL) {
-            /* level triggered */
-            if (level) {
-                s->irr |= mask;
-                ioapic_service(s);
-            } else {
-                s->irr &= ~mask;
-            }
-        } else {
-            /* According to the 82093AA manual, we must ignore edge requests
-             * if the input pin is masked. */
-            if (level && !(entry & IOAPIC_LVT_MASKED)) {
-                s->irr |= mask;
-                ioapic_service(s);
-            }
-        }
-    }
-}
-
-void ioapic_eoi_broadcast(int vector)
-{
-    IOAPICCommonState *s;
-    uint64_t entry;
-    int i, n;
-
-    for (i = 0; i < MAX_IOAPICS; i++) {
-        s = ioapics[i];
-        if (!s) {
-            continue;
-        }
-        for (n = 0; n < IOAPIC_NUM_PINS; n++) {
-            entry = s->ioredtbl[n];
-            if ((entry & IOAPIC_LVT_REMOTE_IRR)
-                && (entry & IOAPIC_VECTOR_MASK) == vector) {
-                s->ioredtbl[n] = entry & ~IOAPIC_LVT_REMOTE_IRR;
-                if (!(entry & IOAPIC_LVT_MASKED) && (s->irr & (1 << n))) {
-                    ioapic_service(s);
-                }
-            }
-        }
-    }
-}
-
-static uint64_t
-ioapic_mem_read(void *opaque, hwaddr addr, unsigned int size)
-{
-    IOAPICCommonState *s = opaque;
-    int index;
-    uint32_t val = 0;
-
-    switch (addr & 0xff) {
-    case IOAPIC_IOREGSEL:
-        val = s->ioregsel;
-        break;
-    case IOAPIC_IOWIN:
-        if (size != 4) {
-            break;
-        }
-        switch (s->ioregsel) {
-        case IOAPIC_REG_ID:
-            val = s->id << IOAPIC_ID_SHIFT;
-            break;
-        case IOAPIC_REG_VER:
-            val = IOAPIC_VERSION |
-                ((IOAPIC_NUM_PINS - 1) << IOAPIC_VER_ENTRIES_SHIFT);
-            break;
-        case IOAPIC_REG_ARB:
-            val = 0;
-            break;
-        default:
-            index = (s->ioregsel - IOAPIC_REG_REDTBL_BASE) >> 1;
-            if (index >= 0 && index < IOAPIC_NUM_PINS) {
-                if (s->ioregsel & 1) {
-                    val = s->ioredtbl[index] >> 32;
-                } else {
-                    val = s->ioredtbl[index] & 0xffffffff;
-                }
-            }
-        }
-        DPRINTF("read: %08x = %08x\n", s->ioregsel, val);
-        break;
-    }
-    return val;
-}
-
-static void
-ioapic_mem_write(void *opaque, hwaddr addr, uint64_t val,
-                 unsigned int size)
-{
-    IOAPICCommonState *s = opaque;
-    int index;
-
-    switch (addr & 0xff) {
-    case IOAPIC_IOREGSEL:
-        s->ioregsel = val;
-        break;
-    case IOAPIC_IOWIN:
-        if (size != 4) {
-            break;
-        }
-        DPRINTF("write: %08x = %08" PRIx64 "\n", s->ioregsel, val);
-        switch (s->ioregsel) {
-        case IOAPIC_REG_ID:
-            s->id = (val >> IOAPIC_ID_SHIFT) & IOAPIC_ID_MASK;
-            break;
-        case IOAPIC_REG_VER:
-        case IOAPIC_REG_ARB:
-            break;
-        default:
-            index = (s->ioregsel - IOAPIC_REG_REDTBL_BASE) >> 1;
-            if (index >= 0 && index < IOAPIC_NUM_PINS) {
-                if (s->ioregsel & 1) {
-                    s->ioredtbl[index] &= 0xffffffff;
-                    s->ioredtbl[index] |= (uint64_t)val << 32;
-                } else {
-                    s->ioredtbl[index] &= ~0xffffffffULL;
-                    s->ioredtbl[index] |= val;
-                }
-                ioapic_service(s);
-            }
-        }
-        break;
-    }
-}
-
-static const MemoryRegionOps ioapic_io_ops = {
-    .read = ioapic_mem_read,
-    .write = ioapic_mem_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void ioapic_init(IOAPICCommonState *s, int instance_no)
-{
-    memory_region_init_io(&s->io_memory, &ioapic_io_ops, s, "ioapic", 0x1000);
-
-    qdev_init_gpio_in(&s->busdev.qdev, ioapic_set_irq, IOAPIC_NUM_PINS);
-
-    ioapics[instance_no] = s;
-}
-
-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 const TypeInfo ioapic_info = {
-    .name          = "ioapic",
-    .parent        = TYPE_IOAPIC_COMMON,
-    .instance_size = sizeof(IOAPICCommonState),
-    .class_init    = ioapic_class_init,
-};
-
-static void ioapic_register_types(void)
-{
-    type_register_static(&ioapic_info);
-}
-
-type_init(ioapic_register_types)
diff --git a/hw/ioapic.h b/hw/ioapic.h
deleted file mode 100644 (file)
index 86e63da..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- *  ioapic.c IOAPIC emulation logic
- *
- *  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 HW_IOAPIC_H
-#define HW_IOAPIC_H
-
-#define IOAPIC_NUM_PINS 24
-
-void ioapic_eoi_broadcast(int vector);
-
-#endif /* !HW_IOAPIC_H */
diff --git a/hw/ioapic_common.c b/hw/ioapic_common.c
deleted file mode 100644 (file)
index d4aff29..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- *  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 "hw/ioapic.h"
-#include "hw/ioapic_internal.h"
-#include "hw/sysbus.h"
-
-void ioapic_reset_common(DeviceState *dev)
-{
-    IOAPICCommonState *s = IOAPIC_COMMON(dev);
-    int i;
-
-    s->id = 0;
-    s->ioregsel = 0;
-    s->irr = 0;
-    for (i = 0; i < IOAPIC_NUM_PINS; i++) {
-        s->ioredtbl[i] = 1 << IOAPIC_LVT_MASKED_SHIFT;
-    }
-}
-
-static void ioapic_dispatch_pre_save(void *opaque)
-{
-    IOAPICCommonState *s = IOAPIC_COMMON(opaque);
-    IOAPICCommonClass *info = IOAPIC_COMMON_GET_CLASS(s);
-
-    if (info->pre_save) {
-        info->pre_save(s);
-    }
-}
-
-static int ioapic_dispatch_post_load(void *opaque, int version_id)
-{
-    IOAPICCommonState *s = IOAPIC_COMMON(opaque);
-    IOAPICCommonClass *info = IOAPIC_COMMON_GET_CLASS(s);
-
-    if (info->post_load) {
-        info->post_load(s);
-    }
-    return 0;
-}
-
-static int ioapic_init_common(SysBusDevice *dev)
-{
-    IOAPICCommonState *s = FROM_SYSBUS(IOAPICCommonState, dev);
-    IOAPICCommonClass *info;
-    static int ioapic_no;
-
-    if (ioapic_no >= MAX_IOAPICS) {
-        return -1;
-    }
-
-    info = IOAPIC_COMMON_GET_CLASS(s);
-    info->init(s, ioapic_no);
-
-    sysbus_init_mmio(&s->busdev, &s->io_memory);
-    ioapic_no++;
-
-    return 0;
-}
-
-static const VMStateDescription vmstate_ioapic_common = {
-    .name = "ioapic",
-    .version_id = 3,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .pre_save = ioapic_dispatch_pre_save,
-    .post_load = ioapic_dispatch_post_load,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT8(id, IOAPICCommonState),
-        VMSTATE_UINT8(ioregsel, IOAPICCommonState),
-        VMSTATE_UNUSED_V(2, 8), /* to account for qemu-kvm's v2 format */
-        VMSTATE_UINT32_V(irr, IOAPICCommonState, 2),
-        VMSTATE_UINT64_ARRAY(ioredtbl, IOAPICCommonState, IOAPIC_NUM_PINS),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void ioapic_common_class_init(ObjectClass *klass, void *data)
-{
-    SysBusDeviceClass *sc = SYS_BUS_DEVICE_CLASS(klass);
-    DeviceClass *dc = DEVICE_CLASS(klass);
-
-    sc->init = ioapic_init_common;
-    dc->vmsd = &vmstate_ioapic_common;
-    dc->no_user = 1;
-}
-
-static const TypeInfo ioapic_common_type = {
-    .name = TYPE_IOAPIC_COMMON,
-    .parent = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(IOAPICCommonState),
-    .class_size = sizeof(IOAPICCommonClass),
-    .class_init = ioapic_common_class_init,
-    .abstract = true,
-};
-
-static void register_types(void)
-{
-    type_register_static(&ioapic_common_type);
-}
-
-type_init(register_types)
diff --git a/hw/ioapic_internal.h b/hw/ioapic_internal.h
deleted file mode 100644 (file)
index 25576c8..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- *  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/hw.h"
-#include "exec/memory.h"
-#include "hw/sysbus.h"
-
-#define MAX_IOAPICS                     1
-
-#define IOAPIC_VERSION                  0x11
-
-#define IOAPIC_LVT_DEST_SHIFT           56
-#define IOAPIC_LVT_MASKED_SHIFT         16
-#define IOAPIC_LVT_TRIGGER_MODE_SHIFT   15
-#define IOAPIC_LVT_REMOTE_IRR_SHIFT     14
-#define IOAPIC_LVT_POLARITY_SHIFT       13
-#define IOAPIC_LVT_DELIV_STATUS_SHIFT   12
-#define IOAPIC_LVT_DEST_MODE_SHIFT      11
-#define IOAPIC_LVT_DELIV_MODE_SHIFT     8
-
-#define IOAPIC_LVT_MASKED               (1 << IOAPIC_LVT_MASKED_SHIFT)
-#define IOAPIC_LVT_REMOTE_IRR           (1 << IOAPIC_LVT_REMOTE_IRR_SHIFT)
-
-#define IOAPIC_TRIGGER_EDGE             0
-#define IOAPIC_TRIGGER_LEVEL            1
-
-/*io{apic,sapic} delivery mode*/
-#define IOAPIC_DM_FIXED                 0x0
-#define IOAPIC_DM_LOWEST_PRIORITY       0x1
-#define IOAPIC_DM_PMI                   0x2
-#define IOAPIC_DM_NMI                   0x4
-#define IOAPIC_DM_INIT                  0x5
-#define IOAPIC_DM_SIPI                  0x6
-#define IOAPIC_DM_EXTINT                0x7
-#define IOAPIC_DM_MASK                  0x7
-
-#define IOAPIC_VECTOR_MASK              0xff
-
-#define IOAPIC_IOREGSEL                 0x00
-#define IOAPIC_IOWIN                    0x10
-
-#define IOAPIC_REG_ID                   0x00
-#define IOAPIC_REG_VER                  0x01
-#define IOAPIC_REG_ARB                  0x02
-#define IOAPIC_REG_REDTBL_BASE          0x10
-#define IOAPIC_ID                       0x00
-
-#define IOAPIC_ID_SHIFT                 24
-#define IOAPIC_ID_MASK                  0xf
-
-#define IOAPIC_VER_ENTRIES_SHIFT        16
-
-typedef struct IOAPICCommonState IOAPICCommonState;
-
-#define TYPE_IOAPIC_COMMON "ioapic-common"
-#define IOAPIC_COMMON(obj) \
-     OBJECT_CHECK(IOAPICCommonState, (obj), TYPE_IOAPIC_COMMON)
-#define IOAPIC_COMMON_CLASS(klass) \
-     OBJECT_CLASS_CHECK(IOAPICCommonClass, (klass), TYPE_IOAPIC_COMMON)
-#define IOAPIC_COMMON_GET_CLASS(obj) \
-     OBJECT_GET_CLASS(IOAPICCommonClass, (obj), TYPE_IOAPIC_COMMON)
-
-typedef struct IOAPICCommonClass {
-    SysBusDeviceClass parent_class;
-    void (*init)(IOAPICCommonState *s, int instance_no);
-    void (*pre_save)(IOAPICCommonState *s);
-    void (*post_load)(IOAPICCommonState *s);
-} IOAPICCommonClass;
-
-struct IOAPICCommonState {
-    SysBusDevice busdev;
-    MemoryRegion io_memory;
-    uint8_t id;
-    uint8_t ioregsel;
-    uint32_t irr;
-    uint64_t ioredtbl[IOAPIC_NUM_PINS];
-};
-
-void ioapic_reset_common(DeviceState *dev);
-
-#endif /* !QEMU_IOAPIC_INTERNAL_H */
diff --git a/hw/ioh3420.c b/hw/ioh3420.c
deleted file mode 100644 (file)
index 5cff61e..0000000
+++ /dev/null
@@ -1,250 +0,0 @@
-/*
- * ioh3420.c
- * Intel X58 north bridge IOH
- * PCI Express root port device id 3420
- *
- * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
- *                    VA Linux Systems Japan K.K.
- *
- * 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 "hw/pci/pci_ids.h"
-#include "hw/pci/msi.h"
-#include "hw/pci/pcie.h"
-#include "hw/ioh3420.h"
-
-#define PCI_DEVICE_ID_IOH_EPORT         0x3420  /* D0:F0 express mode */
-#define PCI_DEVICE_ID_IOH_REV           0x2
-#define IOH_EP_SSVID_OFFSET             0x40
-#define IOH_EP_SSVID_SVID               PCI_VENDOR_ID_INTEL
-#define IOH_EP_SSVID_SSID               0
-#define IOH_EP_MSI_OFFSET               0x60
-#define IOH_EP_MSI_SUPPORTED_FLAGS      PCI_MSI_FLAGS_MASKBIT
-#define IOH_EP_MSI_NR_VECTOR            2
-#define IOH_EP_EXP_OFFSET               0x90
-#define IOH_EP_AER_OFFSET               0x100
-
-/*
- * If two MSI vector are allocated, Advanced Error Interrupt Message Number
- * is 1. otherwise 0.
- * 17.12.5.10 RPERRSTS,  32:27 bit Advanced Error Interrupt Message Number.
- */
-static uint8_t ioh3420_aer_vector(const PCIDevice *d)
-{
-    switch (msi_nr_vectors_allocated(d)) {
-    case 1:
-        return 0;
-    case 2:
-        return 1;
-    case 4:
-    case 8:
-    case 16:
-    case 32:
-    default:
-        break;
-    }
-    abort();
-    return 0;
-}
-
-static void ioh3420_aer_vector_update(PCIDevice *d)
-{
-    pcie_aer_root_set_vector(d, ioh3420_aer_vector(d));
-}
-
-static void ioh3420_write_config(PCIDevice *d,
-                                   uint32_t address, uint32_t val, int len)
-{
-    uint32_t root_cmd =
-        pci_get_long(d->config + d->exp.aer_cap + PCI_ERR_ROOT_COMMAND);
-
-    pci_bridge_write_config(d, address, val, len);
-    ioh3420_aer_vector_update(d);
-    pcie_cap_slot_write_config(d, address, val, len);
-    pcie_aer_write_config(d, address, val, len);
-    pcie_aer_root_write_config(d, address, val, len, root_cmd);
-}
-
-static void ioh3420_reset(DeviceState *qdev)
-{
-    PCIDevice *d = PCI_DEVICE(qdev);
-
-    ioh3420_aer_vector_update(d);
-    pcie_cap_root_reset(d);
-    pcie_cap_deverr_reset(d);
-    pcie_cap_slot_reset(d);
-    pcie_aer_root_reset(d);
-    pci_bridge_reset(qdev);
-    pci_bridge_disable_base_limit(d);
-}
-
-static int ioh3420_initfn(PCIDevice *d)
-{
-    PCIBridge* br = DO_UPCAST(PCIBridge, dev, d);
-    PCIEPort *p = DO_UPCAST(PCIEPort, br, br);
-    PCIESlot *s = DO_UPCAST(PCIESlot, port, p);
-    int rc;
-
-    rc = pci_bridge_initfn(d, TYPE_PCIE_BUS);
-    if (rc < 0) {
-        return rc;
-    }
-
-    pcie_port_init_reg(d);
-
-    rc = pci_bridge_ssvid_init(d, IOH_EP_SSVID_OFFSET,
-                               IOH_EP_SSVID_SVID, IOH_EP_SSVID_SSID);
-    if (rc < 0) {
-        goto err_bridge;
-    }
-    rc = msi_init(d, IOH_EP_MSI_OFFSET, IOH_EP_MSI_NR_VECTOR,
-                  IOH_EP_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_64BIT,
-                  IOH_EP_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_MASKBIT);
-    if (rc < 0) {
-        goto err_bridge;
-    }
-    rc = pcie_cap_init(d, IOH_EP_EXP_OFFSET, PCI_EXP_TYPE_ROOT_PORT, p->port);
-    if (rc < 0) {
-        goto err_msi;
-    }
-    pcie_cap_deverr_init(d);
-    pcie_cap_slot_init(d, s->slot);
-    pcie_chassis_create(s->chassis);
-    rc = pcie_chassis_add_slot(s);
-    if (rc < 0) {
-        goto err_pcie_cap;
-    }
-    pcie_cap_root_init(d);
-    rc = pcie_aer_init(d, IOH_EP_AER_OFFSET);
-    if (rc < 0) {
-        goto err;
-    }
-    pcie_aer_root_init(d);
-    ioh3420_aer_vector_update(d);
-    return 0;
-
-err:
-    pcie_chassis_del_slot(s);
-err_pcie_cap:
-    pcie_cap_exit(d);
-err_msi:
-    msi_uninit(d);
-err_bridge:
-    pci_bridge_exitfn(d);
-    return rc;
-}
-
-static void ioh3420_exitfn(PCIDevice *d)
-{
-    PCIBridge* br = DO_UPCAST(PCIBridge, dev, d);
-    PCIEPort *p = DO_UPCAST(PCIEPort, br, br);
-    PCIESlot *s = DO_UPCAST(PCIESlot, port, p);
-
-    pcie_aer_exit(d);
-    pcie_chassis_del_slot(s);
-    pcie_cap_exit(d);
-    msi_uninit(d);
-    pci_bridge_exitfn(d);
-}
-
-PCIESlot *ioh3420_init(PCIBus *bus, int devfn, bool multifunction,
-                         const char *bus_name, pci_map_irq_fn map_irq,
-                         uint8_t port, uint8_t chassis, uint16_t slot)
-{
-    PCIDevice *d;
-    PCIBridge *br;
-    DeviceState *qdev;
-
-    d = pci_create_multifunction(bus, devfn, multifunction, "ioh3420");
-    if (!d) {
-        return NULL;
-    }
-    br = DO_UPCAST(PCIBridge, dev, d);
-
-    qdev = &br->dev.qdev;
-    pci_bridge_map_irq(br, bus_name, map_irq);
-    qdev_prop_set_uint8(qdev, "port", port);
-    qdev_prop_set_uint8(qdev, "chassis", chassis);
-    qdev_prop_set_uint16(qdev, "slot", slot);
-    qdev_init_nofail(qdev);
-
-    return DO_UPCAST(PCIESlot, port, DO_UPCAST(PCIEPort, br, br));
-}
-
-static const VMStateDescription vmstate_ioh3420 = {
-    .name = "ioh-3240-express-root-port",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .post_load = pcie_cap_slot_post_load,
-    .fields = (VMStateField[]) {
-        VMSTATE_PCIE_DEVICE(port.br.dev, PCIESlot),
-        VMSTATE_STRUCT(port.br.dev.exp.aer_log, PCIESlot, 0,
-                       vmstate_pcie_aer_log, PCIEAERLog),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static Property ioh3420_properties[] = {
-    DEFINE_PROP_UINT8("port", PCIESlot, port.port, 0),
-    DEFINE_PROP_UINT8("chassis", PCIESlot, chassis, 0),
-    DEFINE_PROP_UINT16("slot", PCIESlot, slot, 0),
-    DEFINE_PROP_UINT16("aer_log_max", PCIESlot,
-    port.br.dev.exp.aer_log.log_max,
-    PCIE_AER_LOG_MAX_DEFAULT),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void ioh3420_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
-    k->is_express = 1;
-    k->is_bridge = 1;
-    k->config_write = ioh3420_write_config;
-    k->init = ioh3420_initfn;
-    k->exit = ioh3420_exitfn;
-    k->vendor_id = PCI_VENDOR_ID_INTEL;
-    k->device_id = PCI_DEVICE_ID_IOH_EPORT;
-    k->revision = PCI_DEVICE_ID_IOH_REV;
-    dc->desc = "Intel IOH device id 3420 PCIE Root Port";
-    dc->reset = ioh3420_reset;
-    dc->vmsd = &vmstate_ioh3420;
-    dc->props = ioh3420_properties;
-}
-
-static const TypeInfo ioh3420_info = {
-    .name          = "ioh3420",
-    .parent        = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(PCIESlot),
-    .class_init    = ioh3420_class_init,
-};
-
-static void ioh3420_register_types(void)
-{
-    type_register_static(&ioh3420_info);
-}
-
-type_init(ioh3420_register_types)
-
-/*
- * Local variables:
- *  c-indent-level: 4
- *  c-basic-offset: 4
- *  tab-width: 8
- *  indent-tab-mode: nil
- * End:
- */
diff --git a/hw/ioh3420.h b/hw/ioh3420.h
deleted file mode 100644 (file)
index 7776e5b..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef QEMU_IOH3420_H
-#define QEMU_IOH3420_H
-
-#include "hw/pci/pcie_port.h"
-
-PCIESlot *ioh3420_init(PCIBus *bus, int devfn, bool multifunction,
-                       const char *bus_name, pci_map_irq_fn map_irq,
-                       uint8_t port, uint8_t chassis, uint16_t slot);
-
-#endif /* QEMU_IOH3420_H */
diff --git a/hw/ipack.c b/hw/ipack.c
deleted file mode 100644 (file)
index b1f46c1..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * QEMU IndustryPack emulation
- *
- * Copyright (C) 2012 Igalia, S.L.
- * Author: Alberto Garcia <agarcia@igalia.com>
- *
- * This code is licensed under the GNU GPL v2 or (at your option) any
- * later version.
- */
-
-#include "hw/ipack.h"
-
-IPackDevice *ipack_device_find(IPackBus *bus, int32_t slot)
-{
-    BusChild *kid;
-
-    QTAILQ_FOREACH(kid, &BUS(bus)->children, sibling) {
-        DeviceState *qdev = kid->child;
-        IPackDevice *ip = IPACK_DEVICE(qdev);
-        if (ip->slot == slot) {
-            return ip;
-        }
-    }
-    return NULL;
-}
-
-void ipack_bus_new_inplace(IPackBus *bus, DeviceState *parent,
-                           const char *name, uint8_t n_slots,
-                           qemu_irq_handler handler)
-{
-    qbus_create_inplace(&bus->qbus, TYPE_IPACK_BUS, parent, name);
-    bus->n_slots = n_slots;
-    bus->set_irq = handler;
-}
-
-static int ipack_device_dev_init(DeviceState *qdev)
-{
-    IPackBus *bus = IPACK_BUS(qdev_get_parent_bus(qdev));
-    IPackDevice *dev = IPACK_DEVICE(qdev);
-    IPackDeviceClass *k = IPACK_DEVICE_GET_CLASS(dev);
-
-    if (dev->slot < 0) {
-        dev->slot = bus->free_slot;
-    }
-    if (dev->slot >= bus->n_slots) {
-        return -1;
-    }
-    bus->free_slot = dev->slot + 1;
-
-    dev->irq = qemu_allocate_irqs(bus->set_irq, dev, 2);
-
-    return k->init(dev);
-}
-
-static int ipack_device_dev_exit(DeviceState *qdev)
-{
-    IPackDevice *dev = IPACK_DEVICE(qdev);
-    IPackDeviceClass *k = IPACK_DEVICE_GET_CLASS(dev);
-
-    if (k->exit) {
-        k->exit(dev);
-    }
-
-    qemu_free_irqs(dev->irq);
-
-    return 0;
-}
-
-static Property ipack_device_props[] = {
-    DEFINE_PROP_INT32("slot", IPackDevice, slot, -1),
-    DEFINE_PROP_END_OF_LIST()
-};
-
-static void ipack_device_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *k = DEVICE_CLASS(klass);
-    k->bus_type = TYPE_IPACK_BUS;
-    k->init = ipack_device_dev_init;
-    k->exit = ipack_device_dev_exit;
-    k->props = ipack_device_props;
-}
-
-const VMStateDescription vmstate_ipack_device = {
-    .name = "ipack_device",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField[]) {
-        VMSTATE_INT32(slot, IPackDevice),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static const TypeInfo ipack_device_info = {
-    .name          = TYPE_IPACK_DEVICE,
-    .parent        = TYPE_DEVICE,
-    .instance_size = sizeof(IPackDevice),
-    .class_size    = sizeof(IPackDeviceClass),
-    .class_init    = ipack_device_class_init,
-    .abstract      = true,
-};
-
-static const TypeInfo ipack_bus_info = {
-    .name = TYPE_IPACK_BUS,
-    .parent = TYPE_BUS,
-    .instance_size = sizeof(IPackBus),
-};
-
-static void ipack_register_types(void)
-{
-    type_register_static(&ipack_device_info);
-    type_register_static(&ipack_bus_info);
-}
-
-type_init(ipack_register_types)
diff --git a/hw/ipack.h b/hw/ipack.h
deleted file mode 100644 (file)
index f2b7a12..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * QEMU IndustryPack emulation
- *
- * Copyright (C) 2012 Igalia, S.L.
- * Author: Alberto Garcia <agarcia@igalia.com>
- *
- * This code is licensed under the GNU GPL v2 or (at your option) any
- * later version.
- */
-
-#ifndef QEMU_IPACK_H
-#define QEMU_IPACK_H
-
-#include "hw/qdev.h"
-
-typedef struct IPackBus IPackBus;
-
-#define TYPE_IPACK_BUS "IndustryPack"
-#define IPACK_BUS(obj) OBJECT_CHECK(IPackBus, (obj), TYPE_IPACK_BUS)
-
-struct IPackBus {
-    BusState qbus;
-    /* All fields are private */
-    uint8_t n_slots;
-    uint8_t free_slot;
-    qemu_irq_handler set_irq;
-};
-
-typedef struct IPackDevice IPackDevice;
-typedef struct IPackDeviceClass IPackDeviceClass;
-
-#define TYPE_IPACK_DEVICE "ipack-device"
-#define IPACK_DEVICE(obj) \
-     OBJECT_CHECK(IPackDevice, (obj), TYPE_IPACK_DEVICE)
-#define IPACK_DEVICE_CLASS(klass)                                        \
-     OBJECT_CLASS_CHECK(IPackDeviceClass, (klass), TYPE_IPACK_DEVICE)
-#define IPACK_DEVICE_GET_CLASS(obj) \
-     OBJECT_GET_CLASS(IPackDeviceClass, (obj), TYPE_IPACK_DEVICE)
-
-struct IPackDeviceClass {
-    DeviceClass parent_class;
-
-    int (*init)(IPackDevice *dev);
-    int (*exit)(IPackDevice *dev);
-
-    uint16_t (*io_read)(IPackDevice *dev, uint8_t addr);
-    void (*io_write)(IPackDevice *dev, uint8_t addr, uint16_t val);
-
-    uint16_t (*id_read)(IPackDevice *dev, uint8_t addr);
-    void (*id_write)(IPackDevice *dev, uint8_t addr, uint16_t val);
-
-    uint16_t (*int_read)(IPackDevice *dev, uint8_t addr);
-    void (*int_write)(IPackDevice *dev, uint8_t addr, uint16_t val);
-
-    uint16_t (*mem_read16)(IPackDevice *dev, uint32_t addr);
-    void (*mem_write16)(IPackDevice *dev, uint32_t addr, uint16_t val);
-
-    uint8_t (*mem_read8)(IPackDevice *dev, uint32_t addr);
-    void (*mem_write8)(IPackDevice *dev, uint32_t addr, uint8_t val);
-};
-
-struct IPackDevice {
-    DeviceState qdev;
-    int32_t slot;
-    /* IRQ objects for the IndustryPack INT0# and INT1# */
-    qemu_irq *irq;
-};
-
-extern const VMStateDescription vmstate_ipack_device;
-
-#define VMSTATE_IPACK_DEVICE(_field, _state)                            \
-    VMSTATE_STRUCT(_field, _state, 1, vmstate_ipack_device, IPackDevice)
-
-IPackDevice *ipack_device_find(IPackBus *bus, int32_t slot);
-void ipack_bus_new_inplace(IPackBus *bus, DeviceState *parent,
-                           const char *name, uint8_t n_slots,
-                           qemu_irq_handler handler);
-
-#endif
diff --git a/hw/ipoctal232.c b/hw/ipoctal232.c
deleted file mode 100644 (file)
index 685fee2..0000000
+++ /dev/null
@@ -1,605 +0,0 @@
-/*
- * QEMU GE IP-Octal 232 IndustryPack emulation
- *
- * Copyright (C) 2012 Igalia, S.L.
- * Author: Alberto Garcia <agarcia@igalia.com>
- *
- * This code is licensed under the GNU GPL v2 or (at your option) any
- * later version.
- */
-
-#include "hw/ipack.h"
-#include "qemu/bitops.h"
-#include "char/char.h"
-
-/* #define DEBUG_IPOCTAL */
-
-#ifdef DEBUG_IPOCTAL
-#define DPRINTF2(fmt, ...) \
-    do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF2(fmt, ...) do { } while (0)
-#endif
-
-#define DPRINTF(fmt, ...) DPRINTF2("IP-Octal: " fmt, ## __VA_ARGS__)
-
-#define RX_FIFO_SIZE 3
-
-/* The IP-Octal has 8 channels (a-h)
-   divided into 4 blocks (A-D) */
-#define N_CHANNELS 8
-#define N_BLOCKS   4
-
-#define REG_MRa  0x01
-#define REG_MRb  0x11
-#define REG_SRa  0x03
-#define REG_SRb  0x13
-#define REG_CSRa 0x03
-#define REG_CSRb 0x13
-#define REG_CRa  0x05
-#define REG_CRb  0x15
-#define REG_RHRa 0x07
-#define REG_RHRb 0x17
-#define REG_THRa 0x07
-#define REG_THRb 0x17
-#define REG_ACR  0x09
-#define REG_ISR  0x0B
-#define REG_IMR  0x0B
-#define REG_OPCR 0x1B
-
-#define CR_ENABLE_RX    BIT(0)
-#define CR_DISABLE_RX   BIT(1)
-#define CR_ENABLE_TX    BIT(2)
-#define CR_DISABLE_TX   BIT(3)
-#define CR_CMD(cr)      ((cr) >> 4)
-#define CR_NO_OP        0
-#define CR_RESET_MR     1
-#define CR_RESET_RX     2
-#define CR_RESET_TX     3
-#define CR_RESET_ERR    4
-#define CR_RESET_BRKINT 5
-#define CR_START_BRK    6
-#define CR_STOP_BRK     7
-#define CR_ASSERT_RTSN  8
-#define CR_NEGATE_RTSN  9
-#define CR_TIMEOUT_ON   10
-#define CR_TIMEOUT_OFF  12
-
-#define SR_RXRDY   BIT(0)
-#define SR_FFULL   BIT(1)
-#define SR_TXRDY   BIT(2)
-#define SR_TXEMT   BIT(3)
-#define SR_OVERRUN BIT(4)
-#define SR_PARITY  BIT(5)
-#define SR_FRAMING BIT(6)
-#define SR_BREAK   BIT(7)
-
-#define ISR_TXRDYA BIT(0)
-#define ISR_RXRDYA BIT(1)
-#define ISR_BREAKA BIT(2)
-#define ISR_CNTRDY BIT(3)
-#define ISR_TXRDYB BIT(4)
-#define ISR_RXRDYB BIT(5)
-#define ISR_BREAKB BIT(6)
-#define ISR_MPICHG BIT(7)
-#define ISR_TXRDY(CH) (((CH) & 1) ? BIT(4) : BIT(0))
-#define ISR_RXRDY(CH) (((CH) & 1) ? BIT(5) : BIT(1))
-#define ISR_BREAK(CH) (((CH) & 1) ? BIT(6) : BIT(2))
-
-typedef struct IPOctalState IPOctalState;
-typedef struct SCC2698Channel SCC2698Channel;
-typedef struct SCC2698Block SCC2698Block;
-
-struct SCC2698Channel {
-    IPOctalState *ipoctal;
-    CharDriverState *dev;
-    bool rx_enabled;
-    uint8_t mr[2];
-    uint8_t mr_idx;
-    uint8_t sr;
-    uint8_t rhr[RX_FIFO_SIZE];
-    uint8_t rhr_idx;
-    uint8_t rx_pending;
-};
-
-struct SCC2698Block {
-    uint8_t imr;
-    uint8_t isr;
-};
-
-struct IPOctalState {
-    IPackDevice dev;
-    SCC2698Channel ch[N_CHANNELS];
-    SCC2698Block blk[N_BLOCKS];
-    uint8_t irq_vector;
-};
-
-#define TYPE_IPOCTAL "ipoctal232"
-
-#define IPOCTAL(obj) \
-    OBJECT_CHECK(IPOctalState, (obj), TYPE_IPOCTAL)
-
-static const VMStateDescription vmstate_scc2698_channel = {
-    .name = "scc2698_channel",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField[]) {
-        VMSTATE_BOOL(rx_enabled, SCC2698Channel),
-        VMSTATE_UINT8_ARRAY(mr, SCC2698Channel, 2),
-        VMSTATE_UINT8(mr_idx, SCC2698Channel),
-        VMSTATE_UINT8(sr, SCC2698Channel),
-        VMSTATE_UINT8_ARRAY(rhr, SCC2698Channel, RX_FIFO_SIZE),
-        VMSTATE_UINT8(rhr_idx, SCC2698Channel),
-        VMSTATE_UINT8(rx_pending, SCC2698Channel),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static const VMStateDescription vmstate_scc2698_block = {
-    .name = "scc2698_block",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField[]) {
-        VMSTATE_UINT8(imr, SCC2698Block),
-        VMSTATE_UINT8(isr, SCC2698Block),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static const VMStateDescription vmstate_ipoctal = {
-    .name = "ipoctal232",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField[]) {
-        VMSTATE_IPACK_DEVICE(dev, IPOctalState),
-        VMSTATE_STRUCT_ARRAY(ch, IPOctalState, N_CHANNELS, 1,
-                             vmstate_scc2698_channel, SCC2698Channel),
-        VMSTATE_STRUCT_ARRAY(blk, IPOctalState, N_BLOCKS, 1,
-                             vmstate_scc2698_block, SCC2698Block),
-        VMSTATE_UINT8(irq_vector, IPOctalState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-/* data[10] is 0x0C, not 0x0B as the doc says */
-static const uint8_t id_prom_data[] = {
-    0x49, 0x50, 0x41, 0x43, 0xF0, 0x22,
-    0xA1, 0x00, 0x00, 0x00, 0x0C, 0xCC
-};
-
-static void update_irq(IPOctalState *dev, unsigned block)
-{
-    /* Blocks A and B interrupt on INT0#, C and D on INT1#.
-       Thus, to get the status we have to check two blocks. */
-    SCC2698Block *blk0 = &dev->blk[block];
-    SCC2698Block *blk1 = &dev->blk[block^1];
-    unsigned intno = block / 2;
-
-    if ((blk0->isr & blk0->imr) || (blk1->isr & blk1->imr)) {
-        qemu_irq_raise(dev->dev.irq[intno]);
-    } else {
-        qemu_irq_lower(dev->dev.irq[intno]);
-    }
-}
-
-static void write_cr(IPOctalState *dev, unsigned channel, uint8_t val)
-{
-    SCC2698Channel *ch = &dev->ch[channel];
-    SCC2698Block *blk = &dev->blk[channel / 2];
-
-    DPRINTF("Write CR%c %u: ", channel + 'a', val);
-
-    /* The lower 4 bits are used to enable and disable Tx and Rx */
-    if (val & CR_ENABLE_RX) {
-        DPRINTF2("Rx on, ");
-        ch->rx_enabled = true;
-    }
-    if (val & CR_DISABLE_RX) {
-        DPRINTF2("Rx off, ");
-        ch->rx_enabled = false;
-    }
-    if (val & CR_ENABLE_TX) {
-        DPRINTF2("Tx on, ");
-        ch->sr |= SR_TXRDY | SR_TXEMT;
-        blk->isr |= ISR_TXRDY(channel);
-    }
-    if (val & CR_DISABLE_TX) {
-        DPRINTF2("Tx off, ");
-        ch->sr &= ~(SR_TXRDY | SR_TXEMT);
-        blk->isr &= ~ISR_TXRDY(channel);
-    }
-
-    DPRINTF2("cmd: ");
-
-    /* The rest of the bits implement different commands */
-    switch (CR_CMD(val)) {
-    case CR_NO_OP:
-        DPRINTF2("none");
-        break;
-    case CR_RESET_MR:
-        DPRINTF2("reset MR");
-        ch->mr_idx = 0;
-        break;
-    case CR_RESET_RX:
-        DPRINTF2("reset Rx");
-        ch->rx_enabled = false;
-        ch->rx_pending = 0;
-        ch->sr &= ~SR_RXRDY;
-        blk->isr &= ~ISR_RXRDY(channel);
-        break;
-    case CR_RESET_TX:
-        DPRINTF2("reset Tx");
-        ch->sr &= ~(SR_TXRDY | SR_TXEMT);
-        blk->isr &= ~ISR_TXRDY(channel);
-        break;
-    case CR_RESET_ERR:
-        DPRINTF2("reset err");
-        ch->sr &= ~(SR_OVERRUN | SR_PARITY | SR_FRAMING | SR_BREAK);
-        break;
-    case CR_RESET_BRKINT:
-        DPRINTF2("reset brk ch int");
-        blk->isr &= ~(ISR_BREAKA | ISR_BREAKB);
-        break;
-    default:
-        DPRINTF2("unsupported 0x%x", CR_CMD(val));
-    }
-
-    DPRINTF2("\n");
-}
-
-static uint16_t io_read(IPackDevice *ip, uint8_t addr)
-{
-    IPOctalState *dev = IPOCTAL(ip);
-    uint16_t ret = 0;
-    /* addr[7:6]: block   (A-D)
-       addr[7:5]: channel (a-h)
-       addr[5:0]: register */
-    unsigned block = addr >> 5;
-    unsigned channel = addr >> 4;
-    /* Big endian, accessed using 8-bit bytes at odd locations */
-    unsigned offset = (addr & 0x1F) ^ 1;
-    SCC2698Channel *ch = &dev->ch[channel];
-    SCC2698Block *blk = &dev->blk[block];
-    uint8_t old_isr = blk->isr;
-
-    switch (offset) {
-
-    case REG_MRa:
-    case REG_MRb:
-        ret = ch->mr[ch->mr_idx];
-        DPRINTF("Read MR%u%c: 0x%x\n", ch->mr_idx + 1, channel + 'a', ret);
-        ch->mr_idx = 1;
-        break;
-
-    case REG_SRa:
-    case REG_SRb:
-        ret = ch->sr;
-        DPRINTF("Read SR%c: 0x%x\n", channel + 'a', ret);
-        break;
-
-    case REG_RHRa:
-    case REG_RHRb:
-        ret = ch->rhr[ch->rhr_idx];
-        if (ch->rx_pending > 0) {
-            ch->rx_pending--;
-            if (ch->rx_pending == 0) {
-                ch->sr &= ~SR_RXRDY;
-                blk->isr &= ~ISR_RXRDY(channel);
-                if (ch->dev) {
-                    qemu_chr_accept_input(ch->dev);
-                }
-            } else {
-                ch->rhr_idx = (ch->rhr_idx + 1) % RX_FIFO_SIZE;
-            }
-            if (ch->sr & SR_BREAK) {
-                ch->sr &= ~SR_BREAK;
-                blk->isr |= ISR_BREAK(channel);
-            }
-        }
-        DPRINTF("Read RHR%c (0x%x)\n", channel + 'a', ret);
-        break;
-
-    case REG_ISR:
-        ret = blk->isr;
-        DPRINTF("Read ISR%c: 0x%x\n", block + 'A', ret);
-        break;
-
-    default:
-        DPRINTF("Read unknown/unsupported register 0x%02x\n", offset);
-    }
-
-    if (old_isr != blk->isr) {
-        update_irq(dev, block);
-    }
-
-    return ret;
-}
-
-static void io_write(IPackDevice *ip, uint8_t addr, uint16_t val)
-{
-    IPOctalState *dev = IPOCTAL(ip);
-    unsigned reg = val & 0xFF;
-    /* addr[7:6]: block   (A-D)
-       addr[7:5]: channel (a-h)
-       addr[5:0]: register */
-    unsigned block = addr >> 5;
-    unsigned channel = addr >> 4;
-    /* Big endian, accessed using 8-bit bytes at odd locations */
-    unsigned offset = (addr & 0x1F) ^ 1;
-    SCC2698Channel *ch = &dev->ch[channel];
-    SCC2698Block *blk = &dev->blk[block];
-    uint8_t old_isr = blk->isr;
-    uint8_t old_imr = blk->imr;
-
-    switch (offset) {
-
-    case REG_MRa:
-    case REG_MRb:
-        ch->mr[ch->mr_idx] = reg;
-        DPRINTF("Write MR%u%c 0x%x\n", ch->mr_idx + 1, channel + 'a', reg);
-        ch->mr_idx = 1;
-        break;
-
-    /* Not implemented */
-    case REG_CSRa:
-    case REG_CSRb:
-        DPRINTF("Write CSR%c: 0x%x\n", channel + 'a', reg);
-        break;
-
-    case REG_CRa:
-    case REG_CRb:
-        write_cr(dev, channel, reg);
-        break;
-
-    case REG_THRa:
-    case REG_THRb:
-        if (ch->sr & SR_TXRDY) {
-            DPRINTF("Write THR%c (0x%x)\n", channel + 'a', reg);
-            if (ch->dev) {
-                uint8_t thr = reg;
-                qemu_chr_fe_write(ch->dev, &thr, 1);
-            }
-        } else {
-            DPRINTF("Write THR%c (0x%x), Tx disabled\n", channel + 'a', reg);
-        }
-        break;
-
-    /* Not implemented */
-    case REG_ACR:
-        DPRINTF("Write ACR%c 0x%x\n", block + 'A', val);
-        break;
-
-    case REG_IMR:
-        DPRINTF("Write IMR%c 0x%x\n", block + 'A', val);
-        blk->imr = reg;
-        break;
-
-    /* Not implemented */
-    case REG_OPCR:
-        DPRINTF("Write OPCR%c 0x%x\n", block + 'A', val);
-        break;
-
-    default:
-        DPRINTF("Write unknown/unsupported register 0x%02x %u\n", offset, val);
-    }
-
-    if (old_isr != blk->isr || old_imr != blk->imr) {
-        update_irq(dev, block);
-    }
-}
-
-static uint16_t id_read(IPackDevice *ip, uint8_t addr)
-{
-    uint16_t ret = 0;
-    unsigned pos = addr / 2; /* The ID PROM data is stored every other byte */
-
-    if (pos < ARRAY_SIZE(id_prom_data)) {
-        ret = id_prom_data[pos];
-    } else {
-        DPRINTF("Attempt to read unavailable PROM data at 0x%x\n",  addr);
-    }
-
-    return ret;
-}
-
-static void id_write(IPackDevice *ip, uint8_t addr, uint16_t val)
-{
-    IPOctalState *dev = IPOCTAL(ip);
-    if (addr == 1) {
-        DPRINTF("Write IRQ vector: %u\n", (unsigned) val);
-        dev->irq_vector = val; /* Undocumented, but the hw works like that */
-    } else {
-        DPRINTF("Attempt to write 0x%x to 0x%x\n", val, addr);
-    }
-}
-
-static uint16_t int_read(IPackDevice *ip, uint8_t addr)
-{
-    IPOctalState *dev = IPOCTAL(ip);
-    /* Read address 0 to ACK INT0# and address 2 to ACK INT1# */
-    if (addr != 0 && addr != 2) {
-        DPRINTF("Attempt to read from 0x%x\n", addr);
-        return 0;
-    } else {
-        /* Update interrupts if necessary */
-        update_irq(dev, addr);
-        return dev->irq_vector;
-    }
-}
-
-static void int_write(IPackDevice *ip, uint8_t addr, uint16_t val)
-{
-    DPRINTF("Attempt to write 0x%x to 0x%x\n", val, addr);
-}
-
-static uint16_t mem_read16(IPackDevice *ip, uint32_t addr)
-{
-    DPRINTF("Attempt to read from 0x%x\n", addr);
-    return 0;
-}
-
-static void mem_write16(IPackDevice *ip, uint32_t addr, uint16_t val)
-{
-    DPRINTF("Attempt to write 0x%x to 0x%x\n", val, addr);
-}
-
-static uint8_t mem_read8(IPackDevice *ip, uint32_t addr)
-{
-    DPRINTF("Attempt to read from 0x%x\n", addr);
-    return 0;
-}
-
-static void mem_write8(IPackDevice *ip, uint32_t addr, uint8_t val)
-{
-    IPOctalState *dev = IPOCTAL(ip);
-    if (addr == 1) {
-        DPRINTF("Write IRQ vector: %u\n", (unsigned) val);
-        dev->irq_vector = val;
-    } else {
-        DPRINTF("Attempt to write 0x%x to 0x%x\n", val, addr);
-    }
-}
-
-static int hostdev_can_receive(void *opaque)
-{
-    SCC2698Channel *ch = opaque;
-    int available_bytes = RX_FIFO_SIZE - ch->rx_pending;
-    return ch->rx_enabled ? available_bytes : 0;
-}
-
-static void hostdev_receive(void *opaque, const uint8_t *buf, int size)
-{
-    SCC2698Channel *ch = opaque;
-    IPOctalState *dev = ch->ipoctal;
-    unsigned pos = ch->rhr_idx + ch->rx_pending;
-    int i;
-
-    assert(size + ch->rx_pending <= RX_FIFO_SIZE);
-
-    /* Copy data to the RxFIFO */
-    for (i = 0; i < size; i++) {
-        pos %= RX_FIFO_SIZE;
-        ch->rhr[pos++] = buf[i];
-    }
-
-    ch->rx_pending += size;
-
-    /* If the RxFIFO was empty raise an interrupt */
-    if (!(ch->sr & SR_RXRDY)) {
-        unsigned block, channel = 0;
-        /* Find channel number to update the ISR register */
-        while (&dev->ch[channel] != ch) {
-            channel++;
-        }
-        block = channel / 2;
-        dev->blk[block].isr |= ISR_RXRDY(channel);
-        ch->sr |= SR_RXRDY;
-        update_irq(dev, block);
-    }
-}
-
-static void hostdev_event(void *opaque, int event)
-{
-    SCC2698Channel *ch = opaque;
-    switch (event) {
-    case CHR_EVENT_OPENED:
-        DPRINTF("Device %s opened\n", ch->dev->label);
-        break;
-    case CHR_EVENT_BREAK: {
-        uint8_t zero = 0;
-        DPRINTF("Device %s received break\n", ch->dev->label);
-
-        if (!(ch->sr & SR_BREAK)) {
-            IPOctalState *dev = ch->ipoctal;
-            unsigned block, channel = 0;
-
-            while (&dev->ch[channel] != ch) {
-                channel++;
-            }
-            block = channel / 2;
-
-            ch->sr |= SR_BREAK;
-            dev->blk[block].isr |= ISR_BREAK(channel);
-        }
-
-        /* Put a zero character in the buffer */
-        hostdev_receive(ch, &zero, 1);
-    }
-        break;
-    default:
-        DPRINTF("Device %s received event %d\n", ch->dev->label, event);
-    }
-}
-
-static int ipoctal_init(IPackDevice *ip)
-{
-    IPOctalState *s = IPOCTAL(ip);
-    unsigned i;
-
-    for (i = 0; i < N_CHANNELS; i++) {
-        SCC2698Channel *ch = &s->ch[i];
-        ch->ipoctal = s;
-
-        /* Redirect IP-Octal channels to host character devices */
-        if (ch->dev) {
-            qemu_chr_add_handlers(ch->dev, hostdev_can_receive,
-                                  hostdev_receive, hostdev_event, ch);
-            DPRINTF("Redirecting channel %u to %s\n", i, ch->dev->label);
-        } else {
-            DPRINTF("Could not redirect channel %u, no chardev set\n", i);
-        }
-    }
-
-    return 0;
-}
-
-static Property ipoctal_properties[] = {
-    DEFINE_PROP_CHR("chardev0", IPOctalState, ch[0].dev),
-    DEFINE_PROP_CHR("chardev1", IPOctalState, ch[1].dev),
-    DEFINE_PROP_CHR("chardev2", IPOctalState, ch[2].dev),
-    DEFINE_PROP_CHR("chardev3", IPOctalState, ch[3].dev),
-    DEFINE_PROP_CHR("chardev4", IPOctalState, ch[4].dev),
-    DEFINE_PROP_CHR("chardev5", IPOctalState, ch[5].dev),
-    DEFINE_PROP_CHR("chardev6", IPOctalState, ch[6].dev),
-    DEFINE_PROP_CHR("chardev7", IPOctalState, ch[7].dev),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void ipoctal_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    IPackDeviceClass *ic = IPACK_DEVICE_CLASS(klass);
-
-    ic->init        = ipoctal_init;
-    ic->io_read     = io_read;
-    ic->io_write    = io_write;
-    ic->id_read     = id_read;
-    ic->id_write    = id_write;
-    ic->int_read    = int_read;
-    ic->int_write   = int_write;
-    ic->mem_read16  = mem_read16;
-    ic->mem_write16 = mem_write16;
-    ic->mem_read8   = mem_read8;
-    ic->mem_write8  = mem_write8;
-
-    dc->desc    = "GE IP-Octal 232 8-channel RS-232 IndustryPack";
-    dc->props   = ipoctal_properties;
-    dc->vmsd    = &vmstate_ipoctal;
-}
-
-static const TypeInfo ipoctal_info = {
-    .name          = TYPE_IPOCTAL,
-    .parent        = TYPE_IPACK_DEVICE,
-    .instance_size = sizeof(IPOctalState),
-    .class_init    = ipoctal_class_init,
-};
-
-static void ipoctal_register_types(void)
-{
-    type_register_static(&ipoctal_info);
-}
-
-type_init(ipoctal_register_types)
diff --git a/hw/irq.c b/hw/irq.c
deleted file mode 100644 (file)
index 2078542..0000000
--- a/hw/irq.c
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * QEMU IRQ/GPIO common code.
- *
- * Copyright (c) 2007 CodeSourcery.
- *
- * 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 "hw/irq.h"
-
-struct IRQState {
-    qemu_irq_handler handler;
-    void *opaque;
-    int n;
-};
-
-void qemu_set_irq(qemu_irq irq, int level)
-{
-    if (!irq)
-        return;
-
-    irq->handler(irq->opaque, irq->n, level);
-}
-
-qemu_irq *qemu_extend_irqs(qemu_irq *old, int n_old, qemu_irq_handler handler,
-                           void *opaque, int n)
-{
-    qemu_irq *s;
-    struct IRQState *p;
-    int i;
-
-    if (!old) {
-        n_old = 0;
-    }
-    s = old ? g_renew(qemu_irq, old, n + n_old) : g_new(qemu_irq, n);
-    p = old ? g_renew(struct IRQState, s[0], n + n_old) :
-                g_new(struct IRQState, n);
-    for (i = 0; i < n + n_old; i++) {
-        if (i >= n_old) {
-            p->handler = handler;
-            p->opaque = opaque;
-            p->n = i;
-        }
-        s[i] = p;
-        p++;
-    }
-    return s;
-}
-
-qemu_irq *qemu_allocate_irqs(qemu_irq_handler handler, void *opaque, int n)
-{
-    return qemu_extend_irqs(NULL, 0, handler, opaque, n);
-}
-
-
-void qemu_free_irqs(qemu_irq *s)
-{
-    g_free(s[0]);
-    g_free(s);
-}
-
-static void qemu_notirq(void *opaque, int line, int level)
-{
-    struct IRQState *irq = opaque;
-
-    irq->handler(irq->opaque, irq->n, !level);
-}
-
-qemu_irq qemu_irq_invert(qemu_irq irq)
-{
-    /* The default state for IRQs is low, so raise the output now.  */
-    qemu_irq_raise(irq);
-    return qemu_allocate_irqs(qemu_notirq, irq, 1)[0];
-}
-
-static void qemu_splitirq(void *opaque, int line, int level)
-{
-    struct IRQState **irq = opaque;
-    irq[0]->handler(irq[0]->opaque, irq[0]->n, level);
-    irq[1]->handler(irq[1]->opaque, irq[1]->n, level);
-}
-
-qemu_irq qemu_irq_split(qemu_irq irq1, qemu_irq irq2)
-{
-    qemu_irq *s = g_malloc0(2 * sizeof(qemu_irq));
-    s[0] = irq1;
-    s[1] = irq2;
-    return qemu_allocate_irqs(qemu_splitirq, s, 1)[0];
-}
-
-static void proxy_irq_handler(void *opaque, int n, int level)
-{
-    qemu_irq **target = opaque;
-
-    if (*target) {
-        qemu_set_irq((*target)[n], level);
-    }
-}
-
-qemu_irq *qemu_irq_proxy(qemu_irq **target, int n)
-{
-    return qemu_allocate_irqs(proxy_irq_handler, target, n);
-}
-
-void qemu_irq_intercept_in(qemu_irq *gpio_in, qemu_irq_handler handler, int n)
-{
-    int i;
-    qemu_irq *old_irqs = qemu_allocate_irqs(NULL, NULL, n);
-    for (i = 0; i < n; i++) {
-        *old_irqs[i] = *gpio_in[i];
-        gpio_in[i]->handler = handler;
-        gpio_in[i]->opaque = old_irqs;
-    }
-}
-
-void qemu_irq_intercept_out(qemu_irq **gpio_out, qemu_irq_handler handler, int n)
-{
-    qemu_irq *old_irqs = *gpio_out;
-    *gpio_out = qemu_allocate_irqs(handler, old_irqs, n);
-}
diff --git a/hw/irq.h b/hw/irq.h
deleted file mode 100644 (file)
index 610e6b7..0000000
--- a/hw/irq.h
+++ /dev/null
@@ -1,57 +0,0 @@
-#ifndef QEMU_IRQ_H
-#define QEMU_IRQ_H
-
-/* Generic IRQ/GPIO pin infrastructure.  */
-
-typedef struct IRQState *qemu_irq;
-
-typedef void (*qemu_irq_handler)(void *opaque, int n, int level);
-
-void qemu_set_irq(qemu_irq irq, int level);
-
-static inline void qemu_irq_raise(qemu_irq irq)
-{
-    qemu_set_irq(irq, 1);
-}
-
-static inline void qemu_irq_lower(qemu_irq irq)
-{
-    qemu_set_irq(irq, 0);
-}
-
-static inline void qemu_irq_pulse(qemu_irq irq)
-{
-    qemu_set_irq(irq, 1);
-    qemu_set_irq(irq, 0);
-}
-
-/* Returns an array of N IRQs. Each IRQ is assigned the argument handler and
- * opaque data.
- */
-qemu_irq *qemu_allocate_irqs(qemu_irq_handler handler, void *opaque, int n);
-
-/* Extends an Array of IRQs. Old IRQs have their handlers and opaque data
- * preserved. New IRQs are assigned the argument handler and opaque data.
- */
-qemu_irq *qemu_extend_irqs(qemu_irq *old, int n_old, qemu_irq_handler handler,
-                                void *opaque, int n);
-
-void qemu_free_irqs(qemu_irq *s);
-
-/* Returns a new IRQ with opposite polarity.  */
-qemu_irq qemu_irq_invert(qemu_irq irq);
-
-/* Returns a new IRQ which feeds into both the passed IRQs */
-qemu_irq qemu_irq_split(qemu_irq irq1, qemu_irq irq2);
-
-/* Returns a new IRQ set which connects 1:1 to another IRQ set, which
- * may be set later.
- */
-qemu_irq *qemu_irq_proxy(qemu_irq **target, int n);
-
-/* For internal use in qtest.  Similar to qemu_irq_split, but operating
-   on an existing vector of qemu_irq.  */
-void qemu_irq_intercept_in(qemu_irq *gpio_in, qemu_irq_handler handler, int n);
-void qemu_irq_intercept_out(qemu_irq **gpio_out, qemu_irq_handler handler, int n);
-
-#endif
diff --git a/hw/isa-bus.c b/hw/isa-bus.c
deleted file mode 100644 (file)
index 67ff8fd..0000000
+++ /dev/null
@@ -1,282 +0,0 @@
-/*
- * isa bus support for qdev.
- *
- * Copyright (c) 2009 Gerd Hoffmann <kraxel@redhat.com>
- *
- * 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/hw.h"
-#include "monitor/monitor.h"
-#include "hw/sysbus.h"
-#include "sysemu/sysemu.h"
-#include "hw/isa.h"
-#include "exec/address-spaces.h"
-
-static ISABus *isabus;
-hwaddr isa_mem_base = 0;
-
-static void isabus_dev_print(Monitor *mon, DeviceState *dev, int indent);
-static char *isabus_get_fw_dev_path(DeviceState *dev);
-
-static void isa_bus_class_init(ObjectClass *klass, void *data)
-{
-    BusClass *k = BUS_CLASS(klass);
-
-    k->print_dev = isabus_dev_print;
-    k->get_fw_dev_path = isabus_get_fw_dev_path;
-}
-
-static const TypeInfo isa_bus_info = {
-    .name = TYPE_ISA_BUS,
-    .parent = TYPE_BUS,
-    .instance_size = sizeof(ISABus),
-    .class_init = isa_bus_class_init,
-};
-
-ISABus *isa_bus_new(DeviceState *dev, MemoryRegion *address_space_io)
-{
-    if (isabus) {
-        fprintf(stderr, "Can't create a second ISA bus\n");
-        return NULL;
-    }
-    if (NULL == dev) {
-        dev = qdev_create(NULL, "isabus-bridge");
-        qdev_init_nofail(dev);
-    }
-
-    isabus = FROM_QBUS(ISABus, qbus_create(TYPE_ISA_BUS, dev, NULL));
-    isabus->address_space_io = address_space_io;
-    return isabus;
-}
-
-void isa_bus_irqs(ISABus *bus, qemu_irq *irqs)
-{
-    if (!bus) {
-        hw_error("Can't set isa irqs with no isa bus present.");
-    }
-    bus->irqs = irqs;
-}
-
-/*
- * isa_get_irq() returns the corresponding qemu_irq entry for the i8259.
- *
- * This function is only for special cases such as the 'ferr', and
- * temporary use for normal devices until they are converted to qdev.
- */
-qemu_irq isa_get_irq(ISADevice *dev, int isairq)
-{
-    assert(!dev || DO_UPCAST(ISABus, qbus, dev->qdev.parent_bus) == isabus);
-    if (isairq < 0 || isairq > 15) {
-        hw_error("isa irq %d invalid", isairq);
-    }
-    return isabus->irqs[isairq];
-}
-
-void isa_init_irq(ISADevice *dev, qemu_irq *p, int isairq)
-{
-    assert(dev->nirqs < ARRAY_SIZE(dev->isairq));
-    dev->isairq[dev->nirqs] = isairq;
-    *p = isa_get_irq(dev, isairq);
-    dev->nirqs++;
-}
-
-static inline void isa_init_ioport(ISADevice *dev, uint16_t ioport)
-{
-    if (dev && (dev->ioport_id == 0 || ioport < dev->ioport_id)) {
-        dev->ioport_id = ioport;
-    }
-}
-
-void isa_register_ioport(ISADevice *dev, MemoryRegion *io, uint16_t start)
-{
-    memory_region_add_subregion(isabus->address_space_io, start, io);
-    isa_init_ioport(dev, start);
-}
-
-void isa_register_portio_list(ISADevice *dev, uint16_t start,
-                              const MemoryRegionPortio *pio_start,
-                              void *opaque, const char *name)
-{
-    PortioList *piolist = g_new(PortioList, 1);
-
-    /* START is how we should treat DEV, regardless of the actual
-       contents of the portio array.  This is how the old code
-       actually handled e.g. the FDC device.  */
-    isa_init_ioport(dev, start);
-
-    portio_list_init(piolist, pio_start, opaque, name);
-    portio_list_add(piolist, isabus->address_space_io, start);
-}
-
-static int isa_qdev_init(DeviceState *qdev)
-{
-    ISADevice *dev = ISA_DEVICE(qdev);
-    ISADeviceClass *klass = ISA_DEVICE_GET_CLASS(dev);
-
-    if (klass->init) {
-        return klass->init(dev);
-    }
-
-    return 0;
-}
-
-static void isa_device_init(Object *obj)
-{
-    ISADevice *dev = ISA_DEVICE(obj);
-
-    dev->isairq[0] = -1;
-    dev->isairq[1] = -1;
-}
-
-ISADevice *isa_create(ISABus *bus, const char *name)
-{
-    DeviceState *dev;
-
-    if (!bus) {
-        hw_error("Tried to create isa device %s with no isa bus present.",
-                 name);
-    }
-    dev = qdev_create(&bus->qbus, name);
-    return ISA_DEVICE(dev);
-}
-
-ISADevice *isa_try_create(ISABus *bus, const char *name)
-{
-    DeviceState *dev;
-
-    if (!bus) {
-        hw_error("Tried to create isa device %s with no isa bus present.",
-                 name);
-    }
-    dev = qdev_try_create(&bus->qbus, name);
-    return ISA_DEVICE(dev);
-}
-
-ISADevice *isa_create_simple(ISABus *bus, const char *name)
-{
-    ISADevice *dev;
-
-    dev = isa_create(bus, name);
-    qdev_init_nofail(&dev->qdev);
-    return dev;
-}
-
-ISADevice *isa_vga_init(ISABus *bus)
-{
-    switch (vga_interface_type) {
-    case VGA_CIRRUS:
-        return isa_create_simple(bus, "isa-cirrus-vga");
-    case VGA_QXL:
-        fprintf(stderr, "%s: qxl: no PCI bus\n", __func__);
-        return NULL;
-    case VGA_STD:
-        return isa_create_simple(bus, "isa-vga");
-    case VGA_VMWARE:
-        fprintf(stderr, "%s: vmware_vga: no PCI bus\n", __func__);
-        return NULL;
-    case VGA_NONE:
-    default:
-        return NULL;
-    }
-}
-
-static void isabus_dev_print(Monitor *mon, DeviceState *dev, int indent)
-{
-    ISADevice *d = ISA_DEVICE(dev);
-
-    if (d->isairq[1] != -1) {
-        monitor_printf(mon, "%*sisa irqs %d,%d\n", indent, "",
-                       d->isairq[0], d->isairq[1]);
-    } else if (d->isairq[0] != -1) {
-        monitor_printf(mon, "%*sisa irq %d\n", indent, "",
-                       d->isairq[0]);
-    }
-}
-
-static int isabus_bridge_init(SysBusDevice *dev)
-{
-    /* nothing */
-    return 0;
-}
-
-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 const 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_type = TYPE_ISA_BUS;
-}
-
-static const TypeInfo isa_device_type_info = {
-    .name = TYPE_ISA_DEVICE,
-    .parent = TYPE_DEVICE,
-    .instance_size = sizeof(ISADevice),
-    .instance_init = isa_device_init,
-    .abstract = true,
-    .class_size = sizeof(ISADeviceClass),
-    .class_init = isa_device_class_init,
-};
-
-static void isabus_register_types(void)
-{
-    type_register_static(&isa_bus_info);
-    type_register_static(&isabus_bridge_info);
-    type_register_static(&isa_device_type_info);
-}
-
-static char *isabus_get_fw_dev_path(DeviceState *dev)
-{
-    ISADevice *d = (ISADevice*)dev;
-    char path[40];
-    int off;
-
-    off = snprintf(path, sizeof(path), "%s", qdev_fw_name(dev));
-    if (d->ioport_id) {
-        snprintf(path + off, sizeof(path) - off, "@%04x", d->ioport_id);
-    }
-
-    return g_strdup(path);
-}
-
-MemoryRegion *isa_address_space(ISADevice *dev)
-{
-    return get_system_memory();
-}
-
-MemoryRegion *isa_address_space_io(ISADevice *dev)
-{
-    if (dev) {
-        return isa_bus_from_device(dev)->address_space_io;
-    }
-
-    return isabus->address_space_io;
-}
-
-type_init(isabus_register_types)
diff --git a/hw/isa.h b/hw/isa.h
deleted file mode 100644 (file)
index 82da37c..0000000
--- a/hw/isa.h
+++ /dev/null
@@ -1,104 +0,0 @@
-#ifndef HW_ISA_H
-#define HW_ISA_H
-
-/* ISA bus */
-
-#include "exec/ioport.h"
-#include "exec/memory.h"
-#include "hw/qdev.h"
-
-#define ISA_NUM_IRQS 16
-
-#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)
-
-#define TYPE_ISA_BUS "ISA"
-#define ISA_BUS(obj) OBJECT_CHECK(ISABus, (obj), TYPE_ISA_BUS)
-
-typedef struct ISADeviceClass {
-    DeviceClass parent_class;
-    int (*init)(ISADevice *dev);
-} ISADeviceClass;
-
-struct ISABus {
-    BusState qbus;
-    MemoryRegion *address_space_io;
-    qemu_irq *irqs;
-};
-
-struct ISADevice {
-    DeviceState qdev;
-    uint32_t isairq[2];
-    int nirqs;
-    int ioport_id;
-};
-
-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);
-MemoryRegion *isa_address_space(ISADevice *dev);
-MemoryRegion *isa_address_space_io(ISADevice *dev);
-ISADevice *isa_create(ISABus *bus, const char *name);
-ISADevice *isa_try_create(ISABus *bus, const char *name);
-ISADevice *isa_create_simple(ISABus *bus, const char *name);
-
-ISADevice *isa_vga_init(ISABus *bus);
-
-/**
- * isa_register_ioport: Install an I/O port region on the ISA bus.
- *
- * Register an I/O port region via memory_region_add_subregion
- * inside the ISA I/O address space.
- *
- * @dev: the ISADevice against which these are registered; may be NULL.
- * @io: the #MemoryRegion being registered.
- * @start: the base I/O port.
- */
-void isa_register_ioport(ISADevice *dev, MemoryRegion *io, uint16_t start);
-
-/**
- * isa_register_portio_list: Initialize a set of ISA io ports
- *
- * Several ISA devices have many dis-joint I/O ports.  Worse, these I/O
- * ports can be interleaved with I/O ports from other devices.  This
- * function makes it easy to create multiple MemoryRegions for a single
- * device and use the legacy portio routines.
- *
- * @dev: the ISADevice against which these are registered; may be NULL.
- * @start: the base I/O port against which the portio->offset is applied.
- * @portio: the ports, sorted by offset.
- * @opaque: passed into the old_portio callbacks.
- * @name: passed into memory_region_init_io.
- */
-void isa_register_portio_list(ISADevice *dev, uint16_t start,
-                              const MemoryRegionPortio *portio,
-                              void *opaque, const char *name);
-
-static inline ISABus *isa_bus_from_device(ISADevice *d)
-{
-    return ISA_BUS(qdev_get_parent_bus(DEVICE(d)));
-}
-
-extern hwaddr isa_mem_base;
-
-void isa_mmio_setup(MemoryRegion *mr, hwaddr size);
-void isa_mmio_init(hwaddr base, hwaddr size);
-
-/* dma.c */
-int DMA_get_channel_mode (int nchan);
-int DMA_read_memory (int nchan, void *buf, int pos, int size);
-int DMA_write_memory (int nchan, void *buf, int pos, int size);
-void DMA_hold_DREQ (int nchan);
-void DMA_release_DREQ (int nchan);
-void DMA_schedule(int nchan);
-void DMA_init(int high_page_enable, qemu_irq *cpu_request_exit);
-void DMA_register_channel (int nchan,
-                           DMA_transfer_handler transfer_handler,
-                           void *opaque);
-#endif
diff --git a/hw/isa/Makefile.objs b/hw/isa/Makefile.objs
new file mode 100644 (file)
index 0000000..193746a
--- /dev/null
@@ -0,0 +1,9 @@
+common-obj-y += isa-bus.o
+common-obj-$(CONFIG_APM) += apm.o
+common-obj-$(CONFIG_I82378) += i82378.o
+common-obj-$(CONFIG_ISA_MMIO) += isa_mmio.o
+common-obj-$(CONFIG_PC87312) += pc87312.o
+common-obj-$(CONFIG_PIIX4) += piix4.o
+common-obj-$(CONFIG_VT82C686) += vt82c686.o
+
+obj-$(CONFIG_LPC_ICH9) += lpc_ich9.o
diff --git a/hw/isa/apm.c b/hw/isa/apm.c
new file mode 100644 (file)
index 0000000..5f21d21
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * QEMU PC APM controller Emulation
+ * This is split out from acpi.c
+ *
+ * Copyright (c) 2006 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * 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/>
+ *
+ * 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/isa/apm.h"
+#include "hw/hw.h"
+#include "hw/pci/pci.h"
+
+//#define DEBUG
+
+#ifdef DEBUG
+# define APM_DPRINTF(format, ...)       printf(format, ## __VA_ARGS__)
+#else
+# define APM_DPRINTF(format, ...)       do { } while (0)
+#endif
+
+/* fixed I/O location */
+#define APM_CNT_IOPORT  0xb2
+#define APM_STS_IOPORT  0xb3
+
+static void apm_ioport_writeb(void *opaque, hwaddr addr, uint64_t val,
+                              unsigned size)
+{
+    APMState *apm = opaque;
+    addr &= 1;
+    APM_DPRINTF("apm_ioport_writeb addr=0x%x val=0x%02x\n", addr, val);
+    if (addr == 0) {
+        apm->apmc = val;
+
+        if (apm->callback) {
+            (apm->callback)(val, apm->arg);
+        }
+    } else {
+        apm->apms = val;
+    }
+}
+
+static uint64_t apm_ioport_readb(void *opaque, hwaddr addr, unsigned size)
+{
+    APMState *apm = opaque;
+    uint32_t val;
+
+    addr &= 1;
+    if (addr == 0) {
+        val = apm->apmc;
+    } else {
+        val = apm->apms;
+    }
+    APM_DPRINTF("apm_ioport_readb addr=0x%x val=0x%02x\n", addr, val);
+    return val;
+}
+
+const VMStateDescription vmstate_apm = {
+    .name = "APM State",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT8(apmc, APMState),
+        VMSTATE_UINT8(apms, APMState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const MemoryRegionOps apm_ops = {
+    .read = apm_ioport_readb,
+    .write = apm_ioport_writeb,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+};
+
+void apm_init(PCIDevice *dev, APMState *apm, apm_ctrl_changed_t callback,
+              void *arg)
+{
+    apm->callback = callback;
+    apm->arg = arg;
+
+    /* ioport 0xb2, 0xb3 */
+    memory_region_init_io(&apm->io, &apm_ops, apm, "apm-io", 2);
+    memory_region_add_subregion(pci_address_space_io(dev), APM_CNT_IOPORT,
+                                &apm->io);
+}
diff --git a/hw/isa/i82378.c b/hw/isa/i82378.c
new file mode 100644 (file)
index 0000000..cced9af
--- /dev/null
@@ -0,0 +1,277 @@
+/*
+ * 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 "hw/pci/pci.h"
+#include "hw/i386/pc.h"
+#include "hw/timer/i8254.h"
+#include "hw/audio/pcspk.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, hwaddr 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, hwaddr 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, hwaddr 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, hwaddr 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;
+    ISADevice *isa;
+    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, NULL);
+
+    /* speaker */
+    pcspk_init(isabus, pit);
+
+    /* 2 82C37 (dma) */
+    isa = isa_create_simple(isabus, "i82374");
+    qdev_connect_gpio_out(&isa->qdev, 0, s->out[1]);
+
+    /* 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);
+    pci_register_bar(dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mem);
+
+    /* Make I/O address read only */
+    pci_set_word(dev->wmask + PCI_COMMAND, PCI_COMMAND_SPECIAL);
+    pci_set_long(dev->wmask + PCI_BASE_ADDRESS_0, 0);
+    pci_set_long(pci_conf + PCI_BASE_ADDRESS_0, pci->isa_io_base);
+
+    isa_mem_base = pci->isa_mem_base;
+    isa_bus_new(&dev->qdev, pci_address_space_io(dev));
+
+    i82378_init(&dev->qdev, s);
+
+    return 0;
+}
+
+static Property i82378_properties[] = {
+    DEFINE_PROP_HEX32("iobase", PCIi82378State, isa_io_base, 0x80000000),
+    DEFINE_PROP_HEX32("membase", PCIi82378State, isa_mem_base, 0xc0000000),
+    DEFINE_PROP_END_OF_LIST()
+};
+
+static void pci_i82378_class_init(ObjectClass *klass, void *data)
+{
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    k->init = pci_i82378_init;
+    k->vendor_id = PCI_VENDOR_ID_INTEL;
+    k->device_id = PCI_DEVICE_ID_INTEL_82378;
+    k->revision = 0x03;
+    k->class_id = PCI_CLASS_BRIDGE_ISA;
+    k->subsystem_vendor_id = 0x0;
+    k->subsystem_id = 0x0;
+    dc->vmsd = &vmstate_pci_i82378;
+    dc->props = i82378_properties;
+}
+
+static const TypeInfo pci_i82378_info = {
+    .name = "i82378",
+    .parent = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PCIi82378State),
+    .class_init = pci_i82378_class_init,
+};
+
+static void i82378_register_types(void)
+{
+    type_register_static(&pci_i82378_info);
+}
+
+type_init(i82378_register_types)
diff --git a/hw/isa/isa-bus.c b/hw/isa/isa-bus.c
new file mode 100644 (file)
index 0000000..7860b17
--- /dev/null
@@ -0,0 +1,282 @@
+/*
+ * isa bus support for qdev.
+ *
+ * Copyright (c) 2009 Gerd Hoffmann <kraxel@redhat.com>
+ *
+ * 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/hw.h"
+#include "monitor/monitor.h"
+#include "hw/sysbus.h"
+#include "sysemu/sysemu.h"
+#include "hw/isa/isa.h"
+#include "exec/address-spaces.h"
+
+static ISABus *isabus;
+hwaddr isa_mem_base = 0;
+
+static void isabus_dev_print(Monitor *mon, DeviceState *dev, int indent);
+static char *isabus_get_fw_dev_path(DeviceState *dev);
+
+static void isa_bus_class_init(ObjectClass *klass, void *data)
+{
+    BusClass *k = BUS_CLASS(klass);
+
+    k->print_dev = isabus_dev_print;
+    k->get_fw_dev_path = isabus_get_fw_dev_path;
+}
+
+static const TypeInfo isa_bus_info = {
+    .name = TYPE_ISA_BUS,
+    .parent = TYPE_BUS,
+    .instance_size = sizeof(ISABus),
+    .class_init = isa_bus_class_init,
+};
+
+ISABus *isa_bus_new(DeviceState *dev, MemoryRegion *address_space_io)
+{
+    if (isabus) {
+        fprintf(stderr, "Can't create a second ISA bus\n");
+        return NULL;
+    }
+    if (NULL == dev) {
+        dev = qdev_create(NULL, "isabus-bridge");
+        qdev_init_nofail(dev);
+    }
+
+    isabus = FROM_QBUS(ISABus, qbus_create(TYPE_ISA_BUS, dev, NULL));
+    isabus->address_space_io = address_space_io;
+    return isabus;
+}
+
+void isa_bus_irqs(ISABus *bus, qemu_irq *irqs)
+{
+    if (!bus) {
+        hw_error("Can't set isa irqs with no isa bus present.");
+    }
+    bus->irqs = irqs;
+}
+
+/*
+ * isa_get_irq() returns the corresponding qemu_irq entry for the i8259.
+ *
+ * This function is only for special cases such as the 'ferr', and
+ * temporary use for normal devices until they are converted to qdev.
+ */
+qemu_irq isa_get_irq(ISADevice *dev, int isairq)
+{
+    assert(!dev || DO_UPCAST(ISABus, qbus, dev->qdev.parent_bus) == isabus);
+    if (isairq < 0 || isairq > 15) {
+        hw_error("isa irq %d invalid", isairq);
+    }
+    return isabus->irqs[isairq];
+}
+
+void isa_init_irq(ISADevice *dev, qemu_irq *p, int isairq)
+{
+    assert(dev->nirqs < ARRAY_SIZE(dev->isairq));
+    dev->isairq[dev->nirqs] = isairq;
+    *p = isa_get_irq(dev, isairq);
+    dev->nirqs++;
+}
+
+static inline void isa_init_ioport(ISADevice *dev, uint16_t ioport)
+{
+    if (dev && (dev->ioport_id == 0 || ioport < dev->ioport_id)) {
+        dev->ioport_id = ioport;
+    }
+}
+
+void isa_register_ioport(ISADevice *dev, MemoryRegion *io, uint16_t start)
+{
+    memory_region_add_subregion(isabus->address_space_io, start, io);
+    isa_init_ioport(dev, start);
+}
+
+void isa_register_portio_list(ISADevice *dev, uint16_t start,
+                              const MemoryRegionPortio *pio_start,
+                              void *opaque, const char *name)
+{
+    PortioList *piolist = g_new(PortioList, 1);
+
+    /* START is how we should treat DEV, regardless of the actual
+       contents of the portio array.  This is how the old code
+       actually handled e.g. the FDC device.  */
+    isa_init_ioport(dev, start);
+
+    portio_list_init(piolist, pio_start, opaque, name);
+    portio_list_add(piolist, isabus->address_space_io, start);
+}
+
+static int isa_qdev_init(DeviceState *qdev)
+{
+    ISADevice *dev = ISA_DEVICE(qdev);
+    ISADeviceClass *klass = ISA_DEVICE_GET_CLASS(dev);
+
+    if (klass->init) {
+        return klass->init(dev);
+    }
+
+    return 0;
+}
+
+static void isa_device_init(Object *obj)
+{
+    ISADevice *dev = ISA_DEVICE(obj);
+
+    dev->isairq[0] = -1;
+    dev->isairq[1] = -1;
+}
+
+ISADevice *isa_create(ISABus *bus, const char *name)
+{
+    DeviceState *dev;
+
+    if (!bus) {
+        hw_error("Tried to create isa device %s with no isa bus present.",
+                 name);
+    }
+    dev = qdev_create(&bus->qbus, name);
+    return ISA_DEVICE(dev);
+}
+
+ISADevice *isa_try_create(ISABus *bus, const char *name)
+{
+    DeviceState *dev;
+
+    if (!bus) {
+        hw_error("Tried to create isa device %s with no isa bus present.",
+                 name);
+    }
+    dev = qdev_try_create(&bus->qbus, name);
+    return ISA_DEVICE(dev);
+}
+
+ISADevice *isa_create_simple(ISABus *bus, const char *name)
+{
+    ISADevice *dev;
+
+    dev = isa_create(bus, name);
+    qdev_init_nofail(&dev->qdev);
+    return dev;
+}
+
+ISADevice *isa_vga_init(ISABus *bus)
+{
+    switch (vga_interface_type) {
+    case VGA_CIRRUS:
+        return isa_create_simple(bus, "isa-cirrus-vga");
+    case VGA_QXL:
+        fprintf(stderr, "%s: qxl: no PCI bus\n", __func__);
+        return NULL;
+    case VGA_STD:
+        return isa_create_simple(bus, "isa-vga");
+    case VGA_VMWARE:
+        fprintf(stderr, "%s: vmware_vga: no PCI bus\n", __func__);
+        return NULL;
+    case VGA_NONE:
+    default:
+        return NULL;
+    }
+}
+
+static void isabus_dev_print(Monitor *mon, DeviceState *dev, int indent)
+{
+    ISADevice *d = ISA_DEVICE(dev);
+
+    if (d->isairq[1] != -1) {
+        monitor_printf(mon, "%*sisa irqs %d,%d\n", indent, "",
+                       d->isairq[0], d->isairq[1]);
+    } else if (d->isairq[0] != -1) {
+        monitor_printf(mon, "%*sisa irq %d\n", indent, "",
+                       d->isairq[0]);
+    }
+}
+
+static int isabus_bridge_init(SysBusDevice *dev)
+{
+    /* nothing */
+    return 0;
+}
+
+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 const 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_type = TYPE_ISA_BUS;
+}
+
+static const TypeInfo isa_device_type_info = {
+    .name = TYPE_ISA_DEVICE,
+    .parent = TYPE_DEVICE,
+    .instance_size = sizeof(ISADevice),
+    .instance_init = isa_device_init,
+    .abstract = true,
+    .class_size = sizeof(ISADeviceClass),
+    .class_init = isa_device_class_init,
+};
+
+static void isabus_register_types(void)
+{
+    type_register_static(&isa_bus_info);
+    type_register_static(&isabus_bridge_info);
+    type_register_static(&isa_device_type_info);
+}
+
+static char *isabus_get_fw_dev_path(DeviceState *dev)
+{
+    ISADevice *d = (ISADevice*)dev;
+    char path[40];
+    int off;
+
+    off = snprintf(path, sizeof(path), "%s", qdev_fw_name(dev));
+    if (d->ioport_id) {
+        snprintf(path + off, sizeof(path) - off, "@%04x", d->ioport_id);
+    }
+
+    return g_strdup(path);
+}
+
+MemoryRegion *isa_address_space(ISADevice *dev)
+{
+    return get_system_memory();
+}
+
+MemoryRegion *isa_address_space_io(ISADevice *dev)
+{
+    if (dev) {
+        return isa_bus_from_device(dev)->address_space_io;
+    }
+
+    return isabus->address_space_io;
+}
+
+type_init(isabus_register_types)
diff --git a/hw/isa/isa_mmio.c b/hw/isa/isa_mmio.c
new file mode 100644 (file)
index 0000000..d4dbf13
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Memory mapped access to ISA IO space.
+ *
+ * Copyright (c) 2006 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.
+ */
+
+#include "hw/hw.h"
+#include "hw/isa/isa.h"
+#include "exec/address-spaces.h"
+
+static void isa_mmio_writeb (void *opaque, hwaddr addr,
+                                  uint32_t val)
+{
+    cpu_outb(addr & IOPORTS_MASK, val);
+}
+
+static void isa_mmio_writew(void *opaque, hwaddr addr,
+                               uint32_t val)
+{
+    cpu_outw(addr & IOPORTS_MASK, val);
+}
+
+static void isa_mmio_writel(void *opaque, hwaddr addr,
+                               uint32_t val)
+{
+    cpu_outl(addr & IOPORTS_MASK, val);
+}
+
+static uint32_t isa_mmio_readb (void *opaque, hwaddr addr)
+{
+    return cpu_inb(addr & IOPORTS_MASK);
+}
+
+static uint32_t isa_mmio_readw(void *opaque, hwaddr addr)
+{
+    return cpu_inw(addr & IOPORTS_MASK);
+}
+
+static uint32_t isa_mmio_readl(void *opaque, hwaddr addr)
+{
+    return cpu_inl(addr & IOPORTS_MASK);
+}
+
+static const MemoryRegionOps isa_mmio_ops = {
+    .old_mmio = {
+        .write = { isa_mmio_writeb, isa_mmio_writew, isa_mmio_writel },
+        .read = { isa_mmio_readb, isa_mmio_readw, isa_mmio_readl, },
+    },
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+void isa_mmio_setup(MemoryRegion *mr, hwaddr size)
+{
+    memory_region_init_io(mr, &isa_mmio_ops, NULL, "isa-mmio", size);
+}
+
+void isa_mmio_init(hwaddr base, hwaddr size)
+{
+    MemoryRegion *mr = g_malloc(sizeof(*mr));
+
+    isa_mmio_setup(mr, size);
+    memory_region_add_subregion(get_system_memory(), base, mr);
+}
diff --git a/hw/isa/lpc_ich9.c b/hw/isa/lpc_ich9.c
new file mode 100644 (file)
index 0000000..d116075
--- /dev/null
@@ -0,0 +1,627 @@
+/*
+ * QEMU ICH9 Emulation
+ *
+ * Copyright (c) 2006 Fabrice Bellard
+ * Copyright (c) 2009, 2010, 2011
+ *               Isaku Yamahata <yamahata at valinux co jp>
+ *               VA Linux Systems Japan K.K.
+ * Copyright (C) 2012 Jason Baron <jbaron@redhat.com>
+ *
+ * This is based on piix_pci.c, but heavily modified.
+ *
+ * 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 "hw/hw.h"
+#include "qemu/range.h"
+#include "hw/isa/isa.h"
+#include "hw/sysbus.h"
+#include "hw/i386/pc.h"
+#include "hw/isa/apm.h"
+#include "hw/i386/ioapic.h"
+#include "hw/pci/pci.h"
+#include "hw/pci/pcie_host.h"
+#include "hw/pci/pci_bridge.h"
+#include "hw/i386/ich9.h"
+#include "hw/acpi/acpi.h"
+#include "hw/acpi/ich9.h"
+#include "hw/pci/pci_bus.h"
+#include "exec/address-spaces.h"
+#include "sysemu/sysemu.h"
+
+static int ich9_lpc_sci_irq(ICH9LPCState *lpc);
+
+/*****************************************************************************/
+/* ICH9 LPC PCI to ISA bridge */
+
+static void ich9_lpc_reset(DeviceState *qdev);
+
+/* chipset configuration register
+ * to access chipset configuration registers, pci_[sg]et_{byte, word, long}
+ * are used.
+ * Although it's not pci configuration space, it's little endian as Intel.
+ */
+
+static void ich9_cc_update_ir(uint8_t irr[PCI_NUM_PINS], uint16_t ir)
+{
+    int intx;
+    for (intx = 0; intx < PCI_NUM_PINS; intx++) {
+        irr[intx] = (ir >> (intx * ICH9_CC_DIR_SHIFT)) & ICH9_CC_DIR_MASK;
+    }
+}
+
+static void ich9_cc_update(ICH9LPCState *lpc)
+{
+    int slot;
+    int pci_intx;
+
+    const int reg_offsets[] = {
+        ICH9_CC_D25IR,
+        ICH9_CC_D26IR,
+        ICH9_CC_D27IR,
+        ICH9_CC_D28IR,
+        ICH9_CC_D29IR,
+        ICH9_CC_D30IR,
+        ICH9_CC_D31IR,
+    };
+    const int *offset;
+
+    /* D{25 - 31}IR, but D30IR is read only to 0. */
+    for (slot = 25, offset = reg_offsets; slot < 32; slot++, offset++) {
+        if (slot == 30) {
+            continue;
+        }
+        ich9_cc_update_ir(lpc->irr[slot],
+                          pci_get_word(lpc->chip_config + *offset));
+    }
+
+    /*
+     * D30: DMI2PCI bridge
+     * It is arbitrarily decided how INTx lines of PCI devicesbehind the bridge
+     * are connected to pirq lines. Our choice is PIRQ[E-H].
+     * INT[A-D] are connected to PIRQ[E-H]
+     */
+    for (pci_intx = 0; pci_intx < PCI_NUM_PINS; pci_intx++) {
+        lpc->irr[30][pci_intx] = pci_intx + 4;
+    }
+}
+
+static void ich9_cc_init(ICH9LPCState *lpc)
+{
+    int slot;
+    int intx;
+
+    /* the default irq routing is arbitrary as long as it matches with
+     * acpi irq routing table.
+     * The one that is incompatible with piix_pci(= bochs) one is
+     * intentionally chosen to let the users know that the different
+     * board is used.
+     *
+     * int[A-D] -> pirq[E-F]
+     * avoid pirq A-D because they are used for pci express port
+     */
+    for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
+        for (intx = 0; intx < PCI_NUM_PINS; intx++) {
+            lpc->irr[slot][intx] = (slot + intx) % 4 + 4;
+        }
+    }
+    ich9_cc_update(lpc);
+}
+
+static void ich9_cc_reset(ICH9LPCState *lpc)
+{
+    uint8_t *c = lpc->chip_config;
+
+    memset(lpc->chip_config, 0, sizeof(lpc->chip_config));
+
+    pci_set_long(c + ICH9_CC_D31IR, ICH9_CC_DIR_DEFAULT);
+    pci_set_long(c + ICH9_CC_D30IR, ICH9_CC_D30IR_DEFAULT);
+    pci_set_long(c + ICH9_CC_D29IR, ICH9_CC_DIR_DEFAULT);
+    pci_set_long(c + ICH9_CC_D28IR, ICH9_CC_DIR_DEFAULT);
+    pci_set_long(c + ICH9_CC_D27IR, ICH9_CC_DIR_DEFAULT);
+    pci_set_long(c + ICH9_CC_D26IR, ICH9_CC_DIR_DEFAULT);
+    pci_set_long(c + ICH9_CC_D25IR, ICH9_CC_DIR_DEFAULT);
+
+    ich9_cc_update(lpc);
+}
+
+static void ich9_cc_addr_len(uint64_t *addr, unsigned *len)
+{
+    *addr &= ICH9_CC_ADDR_MASK;
+    if (*addr + *len >= ICH9_CC_SIZE) {
+        *len = ICH9_CC_SIZE - *addr;
+    }
+}
+
+/* val: little endian */
+static void ich9_cc_write(void *opaque, hwaddr addr,
+                          uint64_t val, unsigned len)
+{
+    ICH9LPCState *lpc = (ICH9LPCState *)opaque;
+
+    ich9_cc_addr_len(&addr, &len);
+    memcpy(lpc->chip_config + addr, &val, len);
+    pci_bus_fire_intx_routing_notifier(lpc->d.bus);
+    ich9_cc_update(lpc);
+}
+
+/* return value: little endian */
+static uint64_t ich9_cc_read(void *opaque, hwaddr addr,
+                              unsigned len)
+{
+    ICH9LPCState *lpc = (ICH9LPCState *)opaque;
+
+    uint32_t val = 0;
+    ich9_cc_addr_len(&addr, &len);
+    memcpy(&val, lpc->chip_config + addr, len);
+    return val;
+}
+
+/* IRQ routing */
+/* */
+static void ich9_lpc_rout(uint8_t pirq_rout, int *pic_irq, int *pic_dis)
+{
+    *pic_irq = pirq_rout & ICH9_LPC_PIRQ_ROUT_MASK;
+    *pic_dis = pirq_rout & ICH9_LPC_PIRQ_ROUT_IRQEN;
+}
+
+static void ich9_lpc_pic_irq(ICH9LPCState *lpc, int pirq_num,
+                             int *pic_irq, int *pic_dis)
+{
+    switch (pirq_num) {
+    case 0 ... 3: /* A-D */
+        ich9_lpc_rout(lpc->d.config[ICH9_LPC_PIRQA_ROUT + pirq_num],
+                      pic_irq, pic_dis);
+        return;
+    case 4 ... 7: /* E-H */
+        ich9_lpc_rout(lpc->d.config[ICH9_LPC_PIRQE_ROUT + (pirq_num - 4)],
+                      pic_irq, pic_dis);
+        return;
+    default:
+        break;
+    }
+    abort();
+}
+
+/* pic_irq: i8254 irq 0-15 */
+static void ich9_lpc_update_pic(ICH9LPCState *lpc, int pic_irq)
+{
+    int i, pic_level;
+
+    /* The pic level is the logical OR of all the PCI irqs mapped to it */
+    pic_level = 0;
+    for (i = 0; i < ICH9_LPC_NB_PIRQS; i++) {
+        int tmp_irq;
+        int tmp_dis;
+        ich9_lpc_pic_irq(lpc, i, &tmp_irq, &tmp_dis);
+        if (!tmp_dis && pic_irq == tmp_irq) {
+            pic_level |= pci_bus_get_irq_level(lpc->d.bus, i);
+        }
+    }
+    if (pic_irq == ich9_lpc_sci_irq(lpc)) {
+        pic_level |= lpc->sci_level;
+    }
+
+    qemu_set_irq(lpc->pic[pic_irq], pic_level);
+}
+
+/* pirq: pirq[A-H] 0-7*/
+static void ich9_lpc_update_by_pirq(ICH9LPCState *lpc, int pirq)
+{
+    int pic_irq;
+    int pic_dis;
+
+    ich9_lpc_pic_irq(lpc, pirq, &pic_irq, &pic_dis);
+    assert(pic_irq < ICH9_LPC_PIC_NUM_PINS);
+    if (pic_dis) {
+        return;
+    }
+
+    ich9_lpc_update_pic(lpc, pic_irq);
+}
+
+/* APIC mode: GSIx: PIRQ[A-H] -> GSI 16, ... no pirq shares same APIC pins. */
+static int ich9_pirq_to_gsi(int pirq)
+{
+    return pirq + ICH9_LPC_PIC_NUM_PINS;
+}
+
+static int ich9_gsi_to_pirq(int gsi)
+{
+    return gsi - ICH9_LPC_PIC_NUM_PINS;
+}
+
+static void ich9_lpc_update_apic(ICH9LPCState *lpc, int gsi)
+{
+    int level = 0;
+
+    if (gsi >= ICH9_LPC_PIC_NUM_PINS) {
+        level |= pci_bus_get_irq_level(lpc->d.bus, ich9_gsi_to_pirq(gsi));
+    }
+    if (gsi == ich9_lpc_sci_irq(lpc)) {
+        level |= lpc->sci_level;
+    }
+
+    qemu_set_irq(lpc->ioapic[gsi], level);
+}
+
+void ich9_lpc_set_irq(void *opaque, int pirq, int level)
+{
+    ICH9LPCState *lpc = opaque;
+
+    assert(0 <= pirq);
+    assert(pirq < ICH9_LPC_NB_PIRQS);
+
+    ich9_lpc_update_apic(lpc, ich9_pirq_to_gsi(pirq));
+    ich9_lpc_update_by_pirq(lpc, pirq);
+}
+
+/* return the pirq number (PIRQ[A-H]:0-7) corresponding to
+ * a given device irq pin.
+ */
+int ich9_lpc_map_irq(PCIDevice *pci_dev, int intx)
+{
+    BusState *bus = qdev_get_parent_bus(&pci_dev->qdev);
+    PCIBus *pci_bus = PCI_BUS(bus);
+    PCIDevice *lpc_pdev =
+            pci_bus->devices[PCI_DEVFN(ICH9_LPC_DEV, ICH9_LPC_FUNC)];
+    ICH9LPCState *lpc = ICH9_LPC_DEVICE(lpc_pdev);
+
+    return lpc->irr[PCI_SLOT(pci_dev->devfn)][intx];
+}
+
+PCIINTxRoute ich9_route_intx_pin_to_irq(void *opaque, int pirq_pin)
+{
+    ICH9LPCState *lpc = opaque;
+    PCIINTxRoute route;
+    int pic_irq;
+    int pic_dis;
+
+    assert(0 <= pirq_pin);
+    assert(pirq_pin < ICH9_LPC_NB_PIRQS);
+
+    route.mode = PCI_INTX_ENABLED;
+    ich9_lpc_pic_irq(lpc, pirq_pin, &pic_irq, &pic_dis);
+    if (!pic_dis) {
+        if (pic_irq < ICH9_LPC_PIC_NUM_PINS) {
+            route.irq = pic_irq;
+        } else {
+            route.mode = PCI_INTX_DISABLED;
+            route.irq = -1;
+        }
+    } else {
+        route.irq = ich9_pirq_to_gsi(pirq_pin);
+    }
+
+    return route;
+}
+
+static int ich9_lpc_sci_irq(ICH9LPCState *lpc)
+{
+    switch (lpc->d.config[ICH9_LPC_ACPI_CTRL] &
+            ICH9_LPC_ACPI_CTRL_SCI_IRQ_SEL_MASK) {
+    case ICH9_LPC_ACPI_CTRL_9:
+        return 9;
+    case ICH9_LPC_ACPI_CTRL_10:
+        return 10;
+    case ICH9_LPC_ACPI_CTRL_11:
+        return 11;
+    case ICH9_LPC_ACPI_CTRL_20:
+        return 20;
+    case ICH9_LPC_ACPI_CTRL_21:
+        return 21;
+    default:
+        /* reserved */
+        break;
+    }
+    return -1;
+}
+
+static void ich9_set_sci(void *opaque, int irq_num, int level)
+{
+    ICH9LPCState *lpc = opaque;
+    int irq;
+
+    assert(irq_num == 0);
+    level = !!level;
+    if (level == lpc->sci_level) {
+        return;
+    }
+    lpc->sci_level = level;
+
+    irq = ich9_lpc_sci_irq(lpc);
+    if (irq < 0) {
+        return;
+    }
+
+    ich9_lpc_update_apic(lpc, irq);
+    if (irq < ICH9_LPC_PIC_NUM_PINS) {
+        ich9_lpc_update_pic(lpc, irq);
+    }
+}
+
+void ich9_lpc_pm_init(PCIDevice *lpc_pci, qemu_irq cmos_s3)
+{
+    ICH9LPCState *lpc = ICH9_LPC_DEVICE(lpc_pci);
+    qemu_irq *sci_irq;
+
+    sci_irq = qemu_allocate_irqs(ich9_set_sci, lpc, 1);
+    ich9_pm_init(lpc_pci, &lpc->pm, sci_irq[0], cmos_s3);
+
+    ich9_lpc_reset(&lpc->d.qdev);
+}
+
+/* APM */
+
+static void ich9_apm_ctrl_changed(uint32_t val, void *arg)
+{
+    ICH9LPCState *lpc = arg;
+
+    /* ACPI specs 3.0, 4.7.2.5 */
+    acpi_pm1_cnt_update(&lpc->pm.acpi_regs,
+                        val == ICH9_APM_ACPI_ENABLE,
+                        val == ICH9_APM_ACPI_DISABLE);
+
+    /* SMI_EN = PMBASE + 30. SMI control and enable register */
+    if (lpc->pm.smi_en & ICH9_PMIO_SMI_EN_APMC_EN) {
+        cpu_interrupt(CPU(x86_env_get_cpu(first_cpu)), CPU_INTERRUPT_SMI);
+    }
+}
+
+/* config:PMBASE */
+static void
+ich9_lpc_pmbase_update(ICH9LPCState *lpc)
+{
+    uint32_t pm_io_base = pci_get_long(lpc->d.config + ICH9_LPC_PMBASE);
+    pm_io_base &= ICH9_LPC_PMBASE_BASE_ADDRESS_MASK;
+
+    ich9_pm_iospace_update(&lpc->pm, pm_io_base);
+}
+
+/* config:RBCA */
+static void ich9_lpc_rcba_update(ICH9LPCState *lpc, uint32_t rbca_old)
+{
+    uint32_t rbca = pci_get_long(lpc->d.config + ICH9_LPC_RCBA);
+
+    if (rbca_old & ICH9_LPC_RCBA_EN) {
+            memory_region_del_subregion(get_system_memory(), &lpc->rbca_mem);
+    }
+    if (rbca & ICH9_LPC_RCBA_EN) {
+            memory_region_add_subregion_overlap(get_system_memory(),
+                                                rbca & ICH9_LPC_RCBA_BA_MASK,
+                                                &lpc->rbca_mem, 1);
+    }
+}
+
+static int ich9_lpc_post_load(void *opaque, int version_id)
+{
+    ICH9LPCState *lpc = opaque;
+
+    ich9_lpc_pmbase_update(lpc);
+    ich9_lpc_rcba_update(lpc, 0 /* disabled ICH9_LPC_RBCA_EN */);
+    return 0;
+}
+
+static void ich9_lpc_config_write(PCIDevice *d,
+                                  uint32_t addr, uint32_t val, int len)
+{
+    ICH9LPCState *lpc = ICH9_LPC_DEVICE(d);
+    uint32_t rbca_old = pci_get_long(d->config + ICH9_LPC_RCBA);
+
+    pci_default_write_config(d, addr, val, len);
+    if (ranges_overlap(addr, len, ICH9_LPC_PMBASE, 4)) {
+        ich9_lpc_pmbase_update(lpc);
+    }
+    if (ranges_overlap(addr, len, ICH9_LPC_RCBA, 4)) {
+        ich9_lpc_rcba_update(lpc, rbca_old);
+    }
+    if (ranges_overlap(addr, len, ICH9_LPC_PIRQA_ROUT, 4)) {
+        pci_bus_fire_intx_routing_notifier(lpc->d.bus);
+    }
+    if (ranges_overlap(addr, len, ICH9_LPC_PIRQE_ROUT, 4)) {
+        pci_bus_fire_intx_routing_notifier(lpc->d.bus);
+    }
+}
+
+static void ich9_lpc_reset(DeviceState *qdev)
+{
+    PCIDevice *d = PCI_DEVICE(qdev);
+    ICH9LPCState *lpc = ICH9_LPC_DEVICE(d);
+    uint32_t rbca_old = pci_get_long(d->config + ICH9_LPC_RCBA);
+    int i;
+
+    for (i = 0; i < 4; i++) {
+        pci_set_byte(d->config + ICH9_LPC_PIRQA_ROUT + i,
+                     ICH9_LPC_PIRQ_ROUT_DEFAULT);
+    }
+    for (i = 0; i < 4; i++) {
+        pci_set_byte(d->config + ICH9_LPC_PIRQE_ROUT + i,
+                     ICH9_LPC_PIRQ_ROUT_DEFAULT);
+    }
+    pci_set_byte(d->config + ICH9_LPC_ACPI_CTRL, ICH9_LPC_ACPI_CTRL_DEFAULT);
+
+    pci_set_long(d->config + ICH9_LPC_PMBASE, ICH9_LPC_PMBASE_DEFAULT);
+    pci_set_long(d->config + ICH9_LPC_RCBA, ICH9_LPC_RCBA_DEFAULT);
+
+    ich9_cc_reset(lpc);
+
+    ich9_lpc_pmbase_update(lpc);
+    ich9_lpc_rcba_update(lpc, rbca_old);
+
+    lpc->sci_level = 0;
+    lpc->rst_cnt = 0;
+}
+
+static const MemoryRegionOps rbca_mmio_ops = {
+    .read = ich9_cc_read,
+    .write = ich9_cc_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void ich9_lpc_machine_ready(Notifier *n, void *opaque)
+{
+    ICH9LPCState *s = container_of(n, ICH9LPCState, machine_ready);
+    uint8_t *pci_conf;
+
+    pci_conf = s->d.config;
+    if (isa_is_ioport_assigned(0x3f8)) {
+        /* com1 */
+        pci_conf[0x82] |= 0x01;
+    }
+    if (isa_is_ioport_assigned(0x2f8)) {
+        /* com2 */
+        pci_conf[0x82] |= 0x02;
+    }
+    if (isa_is_ioport_assigned(0x378)) {
+        /* lpt */
+        pci_conf[0x82] |= 0x04;
+    }
+    if (isa_is_ioport_assigned(0x3f0)) {
+        /* floppy */
+        pci_conf[0x82] |= 0x08;
+    }
+}
+
+/* reset control */
+static void ich9_rst_cnt_write(void *opaque, hwaddr addr, uint64_t val,
+                               unsigned len)
+{
+    ICH9LPCState *lpc = opaque;
+
+    if (val & 4) {
+        qemu_system_reset_request();
+        return;
+    }
+    lpc->rst_cnt = val & 0xA; /* keep FULL_RST (bit 3) and SYS_RST (bit 1) */
+}
+
+static uint64_t ich9_rst_cnt_read(void *opaque, hwaddr addr, unsigned len)
+{
+    ICH9LPCState *lpc = opaque;
+
+    return lpc->rst_cnt;
+}
+
+static const MemoryRegionOps ich9_rst_cnt_ops = {
+    .read = ich9_rst_cnt_read,
+    .write = ich9_rst_cnt_write,
+    .endianness = DEVICE_LITTLE_ENDIAN
+};
+
+static int ich9_lpc_initfn(PCIDevice *d)
+{
+    ICH9LPCState *lpc = ICH9_LPC_DEVICE(d);
+    ISABus *isa_bus;
+
+    isa_bus = isa_bus_new(&d->qdev, get_system_io());
+
+    pci_set_long(d->wmask + ICH9_LPC_PMBASE,
+                 ICH9_LPC_PMBASE_BASE_ADDRESS_MASK);
+
+    memory_region_init_io(&lpc->rbca_mem, &rbca_mmio_ops, lpc,
+                            "lpc-rbca-mmio", ICH9_CC_SIZE);
+
+    lpc->isa_bus = isa_bus;
+
+    ich9_cc_init(lpc);
+    apm_init(d, &lpc->apm, ich9_apm_ctrl_changed, lpc);
+
+    lpc->machine_ready.notify = ich9_lpc_machine_ready;
+    qemu_add_machine_init_done_notifier(&lpc->machine_ready);
+
+    memory_region_init_io(&lpc->rst_cnt_mem, &ich9_rst_cnt_ops, lpc,
+                          "lpc-reset-control", 1);
+    memory_region_add_subregion_overlap(pci_address_space_io(d),
+                                        ICH9_RST_CNT_IOPORT, &lpc->rst_cnt_mem,
+                                        1);
+
+    return 0;
+}
+
+static bool ich9_rst_cnt_needed(void *opaque)
+{
+    ICH9LPCState *lpc = opaque;
+
+    return (lpc->rst_cnt != 0);
+}
+
+static const VMStateDescription vmstate_ich9_rst_cnt = {
+    .name = "ICH9LPC/rst_cnt",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT8(rst_cnt, ICH9LPCState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_ich9_lpc = {
+    .name = "ICH9LPC",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .post_load = ich9_lpc_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_PCI_DEVICE(d, ICH9LPCState),
+        VMSTATE_STRUCT(apm, ICH9LPCState, 0, vmstate_apm, APMState),
+        VMSTATE_STRUCT(pm, ICH9LPCState, 0, vmstate_ich9_pm, ICH9LPCPMRegs),
+        VMSTATE_UINT8_ARRAY(chip_config, ICH9LPCState, ICH9_CC_SIZE),
+        VMSTATE_UINT32(sci_level, ICH9LPCState),
+        VMSTATE_END_OF_LIST()
+    },
+    .subsections = (VMStateSubsection[]) {
+        {
+            .vmsd = &vmstate_ich9_rst_cnt,
+            .needed = ich9_rst_cnt_needed
+        },
+        { 0 }
+    }
+};
+
+static void ich9_lpc_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    dc->reset = ich9_lpc_reset;
+    k->init = ich9_lpc_initfn;
+    dc->vmsd = &vmstate_ich9_lpc;
+    dc->no_user = 1;
+    k->config_write = ich9_lpc_config_write;
+    dc->desc = "ICH9 LPC bridge";
+    k->vendor_id = PCI_VENDOR_ID_INTEL;
+    k->device_id = PCI_DEVICE_ID_INTEL_ICH9_8;
+    k->revision = ICH9_A2_LPC_REVISION;
+    k->class_id = PCI_CLASS_BRIDGE_ISA;
+
+}
+
+static const TypeInfo ich9_lpc_info = {
+    .name       = TYPE_ICH9_LPC_DEVICE,
+    .parent     = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(struct ICH9LPCState),
+    .class_init  = ich9_lpc_class_init,
+};
+
+static void ich9_lpc_register(void)
+{
+    type_register_static(&ich9_lpc_info);
+}
+
+type_init(ich9_lpc_register);
diff --git a/hw/isa/pc87312.c b/hw/isa/pc87312.c
new file mode 100644 (file)
index 0000000..9f5e185
--- /dev/null
@@ -0,0 +1,402 @@
+/*
+ * QEMU National Semiconductor PC87312 (Super I/O)
+ *
+ * Copyright (c) 2010-2012 Herve Poussineau
+ * Copyright (c) 2011-2012 Andreas Färber
+ *
+ * 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 "hw/isa/pc87312.h"
+#include "qemu/error-report.h"
+#include "sysemu/blockdev.h"
+#include "sysemu/sysemu.h"
+#include "char/char.h"
+#include "trace.h"
+
+
+#define REG_FER 0
+#define REG_FAR 1
+#define REG_PTR 2
+
+#define FER_PARALLEL_EN   0x01
+#define FER_UART1_EN      0x02
+#define FER_UART2_EN      0x04
+#define FER_FDC_EN        0x08
+#define FER_FDC_4         0x10
+#define FER_FDC_ADDR      0x20
+#define FER_IDE_EN        0x40
+#define FER_IDE_ADDR      0x80
+
+#define FAR_PARALLEL_ADDR 0x03
+#define FAR_UART1_ADDR    0x0C
+#define FAR_UART2_ADDR    0x30
+#define FAR_UART_3_4      0xC0
+
+#define PTR_POWER_DOWN    0x01
+#define PTR_CLOCK_DOWN    0x02
+#define PTR_PWDN          0x04
+#define PTR_IRQ_5_7       0x08
+#define PTR_UART1_TEST    0x10
+#define PTR_UART2_TEST    0x20
+#define PTR_LOCK_CONF     0x40
+#define PTR_EPP_MODE      0x80
+
+
+/* Parallel port */
+
+static inline bool is_parallel_enabled(PC87312State *s)
+{
+    return s->regs[REG_FER] & FER_PARALLEL_EN;
+}
+
+static const uint32_t parallel_base[] = { 0x378, 0x3bc, 0x278, 0x00 };
+
+static inline uint32_t get_parallel_iobase(PC87312State *s)
+{
+    return parallel_base[s->regs[REG_FAR] & FAR_PARALLEL_ADDR];
+}
+
+static const uint32_t parallel_irq[] = { 5, 7, 5, 0 };
+
+static inline uint32_t get_parallel_irq(PC87312State *s)
+{
+    int idx;
+    idx = (s->regs[REG_FAR] & FAR_PARALLEL_ADDR);
+    if (idx == 0) {
+        return (s->regs[REG_PTR] & PTR_IRQ_5_7) ? 7 : 5;
+    } else {
+        return parallel_irq[idx];
+    }
+}
+
+static inline bool is_parallel_epp(PC87312State *s)
+{
+    return s->regs[REG_PTR] & PTR_EPP_MODE;
+}
+
+
+/* UARTs */
+
+static const uint32_t uart_base[2][4] = {
+    { 0x3e8, 0x338, 0x2e8, 0x220 },
+    { 0x2e8, 0x238, 0x2e0, 0x228 }
+};
+
+static inline uint32_t get_uart_iobase(PC87312State *s, int i)
+{
+    int idx;
+    idx = (s->regs[REG_FAR] >> (2 * i + 2)) & 0x3;
+    if (idx == 0) {
+        return 0x3f8;
+    } else if (idx == 1) {
+        return 0x2f8;
+    } else {
+        return uart_base[idx & 1][(s->regs[REG_FAR] & FAR_UART_3_4) >> 6];
+    }
+}
+
+static inline uint32_t get_uart_irq(PC87312State *s, int i)
+{
+    int idx;
+    idx = (s->regs[REG_FAR] >> (2 * i + 2)) & 0x3;
+    return (idx & 1) ? 3 : 4;
+}
+
+static inline bool is_uart_enabled(PC87312State *s, int i)
+{
+    return s->regs[REG_FER] & (FER_UART1_EN << i);
+}
+
+
+/* Floppy controller */
+
+static inline bool is_fdc_enabled(PC87312State *s)
+{
+    return s->regs[REG_FER] & FER_FDC_EN;
+}
+
+static inline uint32_t get_fdc_iobase(PC87312State *s)
+{
+    return (s->regs[REG_FER] & FER_FDC_ADDR) ? 0x370 : 0x3f0;
+}
+
+
+/* IDE controller */
+
+static inline bool is_ide_enabled(PC87312State *s)
+{
+    return s->regs[REG_FER] & FER_IDE_EN;
+}
+
+static inline uint32_t get_ide_iobase(PC87312State *s)
+{
+    return (s->regs[REG_FER] & FER_IDE_ADDR) ? 0x170 : 0x1f0;
+}
+
+
+static void reconfigure_devices(PC87312State *s)
+{
+    error_report("pc87312: unsupported device reconfiguration (%02x %02x %02x)",
+                 s->regs[REG_FER], s->regs[REG_FAR], s->regs[REG_PTR]);
+}
+
+static void pc87312_soft_reset(PC87312State *s)
+{
+    static const uint8_t fer_init[] = {
+        0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4b, 0x4b,
+        0x4b, 0x4b, 0x4b, 0x4b, 0x0f, 0x0f, 0x0f, 0x0f,
+        0x49, 0x49, 0x49, 0x49, 0x07, 0x07, 0x07, 0x07,
+        0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x08, 0x00,
+    };
+    static const uint8_t far_init[] = {
+        0x10, 0x11, 0x11, 0x39, 0x24, 0x38, 0x00, 0x01,
+        0x01, 0x09, 0x08, 0x08, 0x10, 0x11, 0x39, 0x24,
+        0x00, 0x01, 0x01, 0x00, 0x10, 0x11, 0x39, 0x24,
+        0x10, 0x11, 0x11, 0x39, 0x24, 0x38, 0x10, 0x10,
+    };
+    static const uint8_t ptr_init[] = {
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
+    };
+
+    s->read_id_step = 0;
+    s->selected_index = REG_FER;
+
+    s->regs[REG_FER] = fer_init[s->config & 0x1f];
+    s->regs[REG_FAR] = far_init[s->config & 0x1f];
+    s->regs[REG_PTR] = ptr_init[s->config & 0x1f];
+}
+
+static void pc87312_hard_reset(PC87312State *s)
+{
+    pc87312_soft_reset(s);
+}
+
+static void pc87312_io_write(void *opaque, hwaddr addr, uint64_t val,
+                             unsigned int size)
+{
+    PC87312State *s = opaque;
+
+    trace_pc87312_io_write(addr, val);
+
+    if ((addr & 1) == 0) {
+        /* Index register */
+        s->read_id_step = 2;
+        s->selected_index = val;
+    } else {
+        /* Data register */
+        if (s->selected_index < 3) {
+            s->regs[s->selected_index] = val;
+            reconfigure_devices(s);
+        }
+    }
+}
+
+static uint64_t pc87312_io_read(void *opaque, hwaddr addr, unsigned int size)
+{
+    PC87312State *s = opaque;
+    uint32_t val;
+
+    if ((addr & 1) == 0) {
+        /* Index register */
+        if (s->read_id_step++ == 0) {
+            val = 0x88;
+        } else if (s->read_id_step++ == 1) {
+            val = 0;
+        } else {
+            val = s->selected_index;
+        }
+    } else {
+        /* Data register */
+        if (s->selected_index < 3) {
+            val = s->regs[s->selected_index];
+        } else {
+            /* Invalid selected index */
+            val = 0;
+        }
+    }
+
+    trace_pc87312_io_read(addr, val);
+    return val;
+}
+
+static const MemoryRegionOps pc87312_io_ops = {
+    .read  = pc87312_io_read,
+    .write = pc87312_io_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .valid = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+};
+
+static int pc87312_post_load(void *opaque, int version_id)
+{
+    PC87312State *s = opaque;
+
+    reconfigure_devices(s);
+    return 0;
+}
+
+static void pc87312_reset(DeviceState *d)
+{
+    PC87312State *s = PC87312(d);
+
+    pc87312_soft_reset(s);
+}
+
+static int pc87312_init(ISADevice *dev)
+{
+    PC87312State *s;
+    DeviceState *d;
+    ISADevice *isa;
+    ISABus *bus;
+    CharDriverState *chr;
+    DriveInfo *drive;
+    char name[5];
+    int i;
+
+    s = PC87312(dev);
+    bus = isa_bus_from_device(dev);
+    pc87312_hard_reset(s);
+    isa_register_ioport(dev, &s->io, s->iobase);
+
+    if (is_parallel_enabled(s)) {
+        chr = parallel_hds[0];
+        if (chr == NULL) {
+            chr = qemu_chr_new("par0", "null", NULL);
+        }
+        isa = isa_create(bus, "isa-parallel");
+        d = DEVICE(isa);
+        qdev_prop_set_uint32(d, "index", 0);
+        qdev_prop_set_uint32(d, "iobase", get_parallel_iobase(s));
+        qdev_prop_set_uint32(d, "irq", get_parallel_irq(s));
+        qdev_prop_set_chr(d, "chardev", chr);
+        qdev_init_nofail(d);
+        s->parallel.dev = isa;
+        trace_pc87312_info_parallel(get_parallel_iobase(s),
+                                    get_parallel_irq(s));
+    }
+
+    for (i = 0; i < 2; i++) {
+        if (is_uart_enabled(s, i)) {
+            chr = serial_hds[i];
+            if (chr == NULL) {
+                snprintf(name, sizeof(name), "ser%d", i);
+                chr = qemu_chr_new(name, "null", NULL);
+            }
+            isa = isa_create(bus, "isa-serial");
+            d = DEVICE(isa);
+            qdev_prop_set_uint32(d, "index", i);
+            qdev_prop_set_uint32(d, "iobase", get_uart_iobase(s, i));
+            qdev_prop_set_uint32(d, "irq", get_uart_irq(s, i));
+            qdev_prop_set_chr(d, "chardev", chr);
+            qdev_init_nofail(d);
+            s->uart[i].dev = isa;
+            trace_pc87312_info_serial(i, get_uart_iobase(s, i),
+                                      get_uart_irq(s, i));
+        }
+    }
+
+    if (is_fdc_enabled(s)) {
+        isa = isa_create(bus, "isa-fdc");
+        d = DEVICE(isa);
+        qdev_prop_set_uint32(d, "iobase", get_fdc_iobase(s));
+        qdev_prop_set_uint32(d, "irq", 6);
+        drive = drive_get(IF_FLOPPY, 0, 0);
+        if (drive != NULL) {
+            qdev_prop_set_drive_nofail(d, "driveA", drive->bdrv);
+        }
+        drive = drive_get(IF_FLOPPY, 0, 1);
+        if (drive != NULL) {
+            qdev_prop_set_drive_nofail(d, "driveB", drive->bdrv);
+        }
+        qdev_init_nofail(d);
+        s->fdc.dev = isa;
+        trace_pc87312_info_floppy(get_fdc_iobase(s));
+    }
+
+    if (is_ide_enabled(s)) {
+        isa = isa_create(bus, "isa-ide");
+        d = DEVICE(isa);
+        qdev_prop_set_uint32(d, "iobase", get_ide_iobase(s));
+        qdev_prop_set_uint32(d, "iobase2", get_ide_iobase(s) + 0x206);
+        qdev_prop_set_uint32(d, "irq", 14);
+        qdev_init_nofail(d);
+        s->ide.dev = isa;
+        trace_pc87312_info_ide(get_ide_iobase(s));
+    }
+
+    return 0;
+}
+
+static void pc87312_initfn(Object *obj)
+{
+    PC87312State *s = PC87312(obj);
+
+    memory_region_init_io(&s->io, &pc87312_io_ops, s, "pc87312", 2);
+}
+
+static const VMStateDescription vmstate_pc87312 = {
+    .name = "pc87312",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .post_load = pc87312_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT8(read_id_step, PC87312State),
+        VMSTATE_UINT8(selected_index, PC87312State),
+        VMSTATE_UINT8_ARRAY(regs, PC87312State, 3),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static Property pc87312_properties[] = {
+    DEFINE_PROP_HEX32("iobase", PC87312State, iobase, 0x398),
+    DEFINE_PROP_UINT8("config", PC87312State, config, 1),
+    DEFINE_PROP_END_OF_LIST()
+};
+
+static void pc87312_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+
+    ic->init = pc87312_init;
+    dc->reset = pc87312_reset;
+    dc->vmsd = &vmstate_pc87312;
+    dc->props = pc87312_properties;
+}
+
+static const TypeInfo pc87312_type_info = {
+    .name          = TYPE_PC87312,
+    .parent        = TYPE_ISA_DEVICE,
+    .instance_size = sizeof(PC87312State),
+    .instance_init = pc87312_initfn,
+    .class_init    = pc87312_class_init,
+};
+
+static void pc87312_register_types(void)
+{
+    type_register_static(&pc87312_type_info);
+}
+
+type_init(pc87312_register_types)
diff --git a/hw/isa/piix4.c b/hw/isa/piix4.c
new file mode 100644 (file)
index 0000000..d750413
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * QEMU PIIX4 PCI Bridge Emulation
+ *
+ * Copyright (c) 2006 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.
+ */
+
+#include "hw/hw.h"
+#include "hw/i386/pc.h"
+#include "hw/pci/pci.h"
+#include "hw/isa/isa.h"
+#include "hw/sysbus.h"
+
+PCIDevice *piix4_dev;
+
+typedef struct PIIX4State {
+    PCIDevice dev;
+} PIIX4State;
+
+static void piix4_reset(void *opaque)
+{
+    PIIX4State *d = opaque;
+    uint8_t *pci_conf = d->dev.config;
+
+    pci_conf[0x04] = 0x07; // master, memory and I/O
+    pci_conf[0x05] = 0x00;
+    pci_conf[0x06] = 0x00;
+    pci_conf[0x07] = 0x02; // PCI_status_devsel_medium
+    pci_conf[0x4c] = 0x4d;
+    pci_conf[0x4e] = 0x03;
+    pci_conf[0x4f] = 0x00;
+    pci_conf[0x60] = 0x0a; // PCI A -> IRQ 10
+    pci_conf[0x61] = 0x0a; // PCI B -> IRQ 10
+    pci_conf[0x62] = 0x0b; // PCI C -> IRQ 11
+    pci_conf[0x63] = 0x0b; // PCI D -> IRQ 11
+    pci_conf[0x69] = 0x02;
+    pci_conf[0x70] = 0x80;
+    pci_conf[0x76] = 0x0c;
+    pci_conf[0x77] = 0x0c;
+    pci_conf[0x78] = 0x02;
+    pci_conf[0x79] = 0x00;
+    pci_conf[0x80] = 0x00;
+    pci_conf[0x82] = 0x00;
+    pci_conf[0xa0] = 0x08;
+    pci_conf[0xa2] = 0x00;
+    pci_conf[0xa3] = 0x00;
+    pci_conf[0xa4] = 0x00;
+    pci_conf[0xa5] = 0x00;
+    pci_conf[0xa6] = 0x00;
+    pci_conf[0xa7] = 0x00;
+    pci_conf[0xa8] = 0x0f;
+    pci_conf[0xaa] = 0x00;
+    pci_conf[0xab] = 0x00;
+    pci_conf[0xac] = 0x00;
+    pci_conf[0xae] = 0x00;
+}
+
+static const VMStateDescription vmstate_piix4 = {
+    .name = "PIIX4",
+    .version_id = 2,
+    .minimum_version_id = 2,
+    .minimum_version_id_old = 2,
+    .fields      = (VMStateField[]) {
+        VMSTATE_PCI_DEVICE(dev, PIIX4State),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int piix4_initfn(PCIDevice *dev)
+{
+    PIIX4State *d = DO_UPCAST(PIIX4State, dev, dev);
+
+    isa_bus_new(&d->dev.qdev, pci_address_space_io(dev));
+    piix4_dev = &d->dev;
+    qemu_register_reset(piix4_reset, d);
+    return 0;
+}
+
+int piix4_init(PCIBus *bus, ISABus **isa_bus, int devfn)
+{
+    PCIDevice *d;
+
+    d = pci_create_simple_multifunction(bus, devfn, true, "PIIX4");
+    *isa_bus = DO_UPCAST(ISABus, qbus, qdev_get_child_bus(&d->qdev, "isa.0"));
+    return d->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;
+    k->init = piix4_initfn;
+    k->vendor_id = PCI_VENDOR_ID_INTEL;
+    k->device_id = PCI_DEVICE_ID_INTEL_82371AB_0;
+    k->class_id = PCI_CLASS_BRIDGE_ISA;
+    dc->desc = "ISA bridge";
+    dc->no_user = 1;
+    dc->vmsd = &vmstate_piix4;
+}
+
+static const TypeInfo piix4_info = {
+    .name          = "PIIX4",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PIIX4State),
+    .class_init    = piix4_class_init,
+};
+
+static void piix4_register_types(void)
+{
+    type_register_static(&piix4_info);
+}
+
+type_init(piix4_register_types)
diff --git a/hw/isa/vt82c686.c b/hw/isa/vt82c686.c
new file mode 100644 (file)
index 0000000..5261927
--- /dev/null
@@ -0,0 +1,487 @@
+/*
+ * VT82C686B south bridge support
+ *
+ * Copyright (c) 2008 yajin (yajin@vm-kernel.org)
+ * Copyright (c) 2009 chenming (chenming@rdc.faw.com.cn)
+ * Copyright (c) 2010 Huacai Chen (zltjiangshi@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/hw.h"
+#include "hw/i386/pc.h"
+#include "hw/isa/vt82c686.h"
+#include "hw/i2c/i2c.h"
+#include "hw/i2c/smbus.h"
+#include "hw/pci/pci.h"
+#include "hw/isa/isa.h"
+#include "hw/sysbus.h"
+#include "hw/mips/mips.h"
+#include "hw/isa/apm.h"
+#include "hw/acpi/acpi.h"
+#include "hw/i2c/pm_smbus.h"
+#include "sysemu/sysemu.h"
+#include "qemu/timer.h"
+#include "exec/address-spaces.h"
+
+//#define DEBUG_VT82C686B
+
+#ifdef DEBUG_VT82C686B
+#define DPRINTF(fmt, ...) fprintf(stderr, "%s: " fmt, __FUNCTION__, ##__VA_ARGS__)
+#else
+#define DPRINTF(fmt, ...)
+#endif
+
+typedef struct SuperIOConfig
+{
+    uint8_t config[0xff];
+    uint8_t index;
+    uint8_t data;
+} SuperIOConfig;
+
+typedef struct VT82C686BState {
+    PCIDevice dev;
+    SuperIOConfig superio_conf;
+} VT82C686BState;
+
+static void superio_ioport_writeb(void *opaque, uint32_t addr, uint32_t data)
+{
+    int can_write;
+    SuperIOConfig *superio_conf = opaque;
+
+    DPRINTF("superio_ioport_writeb  address 0x%x  val 0x%x\n", addr, data);
+    if (addr == 0x3f0) {
+        superio_conf->index = data & 0xff;
+    } else {
+        /* 0x3f1 */
+        switch (superio_conf->index) {
+        case 0x00 ... 0xdf:
+        case 0xe4:
+        case 0xe5:
+        case 0xe9 ... 0xed:
+        case 0xf3:
+        case 0xf5:
+        case 0xf7:
+        case 0xf9 ... 0xfb:
+        case 0xfd ... 0xff:
+            can_write = 0;
+            break;
+        default:
+            can_write = 1;
+
+            if (can_write) {
+                switch (superio_conf->index) {
+                case 0xe7:
+                    if ((data & 0xff) != 0xfe) {
+                        DPRINTF("chage uart 1 base. unsupported yet\n");
+                    }
+                    break;
+                case 0xe8:
+                    if ((data & 0xff) != 0xbe) {
+                        DPRINTF("chage uart 2 base. unsupported yet\n");
+                    }
+                    break;
+
+                default:
+                    superio_conf->config[superio_conf->index] = data & 0xff;
+                }
+            }
+        }
+        superio_conf->config[superio_conf->index] = data & 0xff;
+    }
+}
+
+static uint32_t superio_ioport_readb(void *opaque, uint32_t addr)
+{
+    SuperIOConfig *superio_conf = opaque;
+
+    DPRINTF("superio_ioport_readb  address 0x%x\n", addr);
+    return (superio_conf->config[superio_conf->index]);
+}
+
+static void vt82c686b_reset(void * opaque)
+{
+    PCIDevice *d = opaque;
+    uint8_t *pci_conf = d->config;
+    VT82C686BState *vt82c = DO_UPCAST(VT82C686BState, dev, d);
+
+    pci_set_long(pci_conf + PCI_CAPABILITY_LIST, 0x000000c0);
+    pci_set_word(pci_conf + PCI_COMMAND, PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
+                 PCI_COMMAND_MASTER | PCI_COMMAND_SPECIAL);
+    pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_DEVSEL_MEDIUM);
+
+    pci_conf[0x48] = 0x01; /* Miscellaneous Control 3 */
+    pci_conf[0x4a] = 0x04; /* IDE interrupt Routing */
+    pci_conf[0x4f] = 0x03; /* DMA/Master Mem Access Control 3 */
+    pci_conf[0x50] = 0x2d; /* PnP DMA Request Control */
+    pci_conf[0x59] = 0x04;
+    pci_conf[0x5a] = 0x04; /* KBC/RTC Control*/
+    pci_conf[0x5f] = 0x04;
+    pci_conf[0x77] = 0x10; /* GPIO Control 1/2/3/4 */
+
+    vt82c->superio_conf.config[0xe0] = 0x3c;
+    vt82c->superio_conf.config[0xe2] = 0x03;
+    vt82c->superio_conf.config[0xe3] = 0xfc;
+    vt82c->superio_conf.config[0xe6] = 0xde;
+    vt82c->superio_conf.config[0xe7] = 0xfe;
+    vt82c->superio_conf.config[0xe8] = 0xbe;
+}
+
+/* write config pci function0 registers. PCI-ISA bridge */
+static void vt82c686b_write_config(PCIDevice * d, uint32_t address,
+                                   uint32_t val, int len)
+{
+    VT82C686BState *vt686 = DO_UPCAST(VT82C686BState, dev, d);
+
+    DPRINTF("vt82c686b_write_config  address 0x%x  val 0x%x len 0x%x\n",
+           address, val, len);
+
+    pci_default_write_config(d, address, val, len);
+    if (address == 0x85) {  /* enable or disable super IO configure */
+        if (val & 0x2) {
+            /* floppy also uses 0x3f0 and 0x3f1.
+             * But we do not emulate flopy,so just set it here. */
+            isa_unassign_ioport(0x3f0, 2);
+            register_ioport_read(0x3f0, 2, 1, superio_ioport_readb,
+                                 &vt686->superio_conf);
+            register_ioport_write(0x3f0, 2, 1, superio_ioport_writeb,
+                                  &vt686->superio_conf);
+        } else {
+            isa_unassign_ioport(0x3f0, 2);
+        }
+    }
+}
+
+#define ACPI_DBG_IO_ADDR  0xb044
+
+typedef struct VT686PMState {
+    PCIDevice dev;
+    MemoryRegion io;
+    ACPIREGS ar;
+    APMState apm;
+    PMSMBus smb;
+    uint32_t smb_io_base;
+} VT686PMState;
+
+typedef struct VT686AC97State {
+    PCIDevice dev;
+} VT686AC97State;
+
+typedef struct VT686MC97State {
+    PCIDevice dev;
+} VT686MC97State;
+
+static void pm_update_sci(VT686PMState *s)
+{
+    int sci_level, pmsts;
+
+    pmsts = acpi_pm1_evt_get_sts(&s->ar);
+    sci_level = (((pmsts & s->ar.pm1.evt.en) &
+                  (ACPI_BITMASK_RT_CLOCK_ENABLE |
+                   ACPI_BITMASK_POWER_BUTTON_ENABLE |
+                   ACPI_BITMASK_GLOBAL_LOCK_ENABLE |
+                   ACPI_BITMASK_TIMER_ENABLE)) != 0);
+    qemu_set_irq(s->dev.irq[0], sci_level);
+    /* schedule a timer interruption if needed */
+    acpi_pm_tmr_update(&s->ar, (s->ar.pm1.evt.en & ACPI_BITMASK_TIMER_ENABLE) &&
+                       !(pmsts & ACPI_BITMASK_TIMER_STATUS));
+}
+
+static void pm_tmr_timer(ACPIREGS *ar)
+{
+    VT686PMState *s = container_of(ar, VT686PMState, ar);
+    pm_update_sci(s);
+}
+
+static void pm_io_space_update(VT686PMState *s)
+{
+    uint32_t pm_io_base;
+
+    pm_io_base = pci_get_long(s->dev.config + 0x40);
+    pm_io_base &= 0xffc0;
+
+    memory_region_transaction_begin();
+    memory_region_set_enabled(&s->io, s->dev.config[0x80] & 1);
+    memory_region_set_address(&s->io, pm_io_base);
+    memory_region_transaction_commit();
+}
+
+static void pm_write_config(PCIDevice *d,
+                            uint32_t address, uint32_t val, int len)
+{
+    DPRINTF("pm_write_config  address 0x%x  val 0x%x len 0x%x\n",
+           address, val, len);
+    pci_default_write_config(d, address, val, len);
+}
+
+static int vmstate_acpi_post_load(void *opaque, int version_id)
+{
+    VT686PMState *s = opaque;
+
+    pm_io_space_update(s);
+    return 0;
+}
+
+static const VMStateDescription vmstate_acpi = {
+    .name = "vt82c686b_pm",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .post_load = vmstate_acpi_post_load,
+    .fields      = (VMStateField []) {
+        VMSTATE_PCI_DEVICE(dev, VT686PMState),
+        VMSTATE_UINT16(ar.pm1.evt.sts, VT686PMState),
+        VMSTATE_UINT16(ar.pm1.evt.en, VT686PMState),
+        VMSTATE_UINT16(ar.pm1.cnt.cnt, VT686PMState),
+        VMSTATE_STRUCT(apm, VT686PMState, 0, vmstate_apm, APMState),
+        VMSTATE_TIMER(ar.tmr.timer, VT686PMState),
+        VMSTATE_INT64(ar.tmr.overflow_time, VT686PMState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+/*
+ * TODO: vt82c686b_ac97_init() and vt82c686b_mc97_init()
+ * just register a PCI device now, functionalities will be implemented later.
+ */
+
+static int vt82c686b_ac97_initfn(PCIDevice *dev)
+{
+    VT686AC97State *s = DO_UPCAST(VT686AC97State, dev, dev);
+    uint8_t *pci_conf = s->dev.config;
+
+    pci_set_word(pci_conf + PCI_COMMAND, PCI_COMMAND_INVALIDATE |
+                 PCI_COMMAND_PARITY);
+    pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_CAP_LIST |
+                 PCI_STATUS_DEVSEL_MEDIUM);
+    pci_set_long(pci_conf + PCI_INTERRUPT_PIN, 0x03);
+
+    return 0;
+}
+
+void vt82c686b_ac97_init(PCIBus *bus, int devfn)
+{
+    PCIDevice *dev;
+
+    dev = pci_create(bus, devfn, "VT82C686B_AC97");
+    qdev_init_nofail(&dev->qdev);
+}
+
+static void via_ac97_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = vt82c686b_ac97_initfn;
+    k->vendor_id = PCI_VENDOR_ID_VIA;
+    k->device_id = PCI_DEVICE_ID_VIA_AC97;
+    k->revision = 0x50;
+    k->class_id = PCI_CLASS_MULTIMEDIA_AUDIO;
+    dc->desc = "AC97";
+}
+
+static const TypeInfo via_ac97_info = {
+    .name          = "VT82C686B_AC97",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(VT686AC97State),
+    .class_init    = via_ac97_class_init,
+};
+
+static int vt82c686b_mc97_initfn(PCIDevice *dev)
+{
+    VT686MC97State *s = DO_UPCAST(VT686MC97State, dev, dev);
+    uint8_t *pci_conf = s->dev.config;
+
+    pci_set_word(pci_conf + PCI_COMMAND, PCI_COMMAND_INVALIDATE |
+                 PCI_COMMAND_VGA_PALETTE);
+    pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_DEVSEL_MEDIUM);
+    pci_set_long(pci_conf + PCI_INTERRUPT_PIN, 0x03);
+
+    return 0;
+}
+
+void vt82c686b_mc97_init(PCIBus *bus, int devfn)
+{
+    PCIDevice *dev;
+
+    dev = pci_create(bus, devfn, "VT82C686B_MC97");
+    qdev_init_nofail(&dev->qdev);
+}
+
+static void via_mc97_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = vt82c686b_mc97_initfn;
+    k->vendor_id = PCI_VENDOR_ID_VIA;
+    k->device_id = PCI_DEVICE_ID_VIA_MC97;
+    k->class_id = PCI_CLASS_COMMUNICATION_OTHER;
+    k->revision = 0x30;
+    dc->desc = "MC97";
+}
+
+static const TypeInfo via_mc97_info = {
+    .name          = "VT82C686B_MC97",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(VT686MC97State),
+    .class_init    = via_mc97_class_init,
+};
+
+/* vt82c686 pm init */
+static int vt82c686b_pm_initfn(PCIDevice *dev)
+{
+    VT686PMState *s = DO_UPCAST(VT686PMState, dev, dev);
+    uint8_t *pci_conf;
+
+    pci_conf = s->dev.config;
+    pci_set_word(pci_conf + PCI_COMMAND, 0);
+    pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_FAST_BACK |
+                 PCI_STATUS_DEVSEL_MEDIUM);
+
+    /* 0x48-0x4B is Power Management I/O Base */
+    pci_set_long(pci_conf + 0x48, 0x00000001);
+
+    /* SMB ports:0xeee0~0xeeef */
+    s->smb_io_base =((s->smb_io_base & 0xfff0) + 0x0);
+    pci_conf[0x90] = s->smb_io_base | 1;
+    pci_conf[0x91] = s->smb_io_base >> 8;
+    pci_conf[0xd2] = 0x90;
+    pm_smbus_init(&s->dev.qdev, &s->smb);
+    memory_region_add_subregion(get_system_io(), s->smb_io_base, &s->smb.io);
+
+    apm_init(dev, &s->apm, NULL, s);
+
+    memory_region_init(&s->io, "vt82c686-pm", 64);
+    memory_region_set_enabled(&s->io, false);
+    memory_region_add_subregion(get_system_io(), 0, &s->io);
+
+    acpi_pm_tmr_init(&s->ar, pm_tmr_timer, &s->io);
+    acpi_pm1_evt_init(&s->ar, pm_tmr_timer, &s->io);
+    acpi_pm1_cnt_init(&s->ar, &s->io, 2);
+
+    return 0;
+}
+
+i2c_bus *vt82c686b_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
+                       qemu_irq sci_irq)
+{
+    PCIDevice *dev;
+    VT686PMState *s;
+
+    dev = pci_create(bus, devfn, "VT82C686B_PM");
+    qdev_prop_set_uint32(&dev->qdev, "smb_io_base", smb_io_base);
+
+    s = DO_UPCAST(VT686PMState, dev, dev);
+
+    qdev_init_nofail(&dev->qdev);
+
+    return s->smb.smbus;
+}
+
+static Property via_pm_properties[] = {
+    DEFINE_PROP_UINT32("smb_io_base", VT686PMState, smb_io_base, 0),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void via_pm_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = vt82c686b_pm_initfn;
+    k->config_write = pm_write_config;
+    k->vendor_id = PCI_VENDOR_ID_VIA;
+    k->device_id = PCI_DEVICE_ID_VIA_ACPI;
+    k->class_id = PCI_CLASS_BRIDGE_OTHER;
+    k->revision = 0x40;
+    dc->desc = "PM";
+    dc->vmsd = &vmstate_acpi;
+    dc->props = via_pm_properties;
+}
+
+static const TypeInfo via_pm_info = {
+    .name          = "VT82C686B_PM",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(VT686PMState),
+    .class_init    = via_pm_class_init,
+};
+
+static const VMStateDescription vmstate_via = {
+    .name = "vt82c686b",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_PCI_DEVICE(dev, VT82C686BState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+/* init the PCI-to-ISA bridge */
+static int vt82c686b_initfn(PCIDevice *d)
+{
+    uint8_t *pci_conf;
+    uint8_t *wmask;
+    int i;
+
+    isa_bus_new(&d->qdev, pci_address_space_io(d));
+
+    pci_conf = d->config;
+    pci_config_set_prog_interface(pci_conf, 0x0);
+
+    wmask = d->wmask;
+    for (i = 0x00; i < 0xff; i++) {
+       if (i<=0x03 || (i>=0x08 && i<=0x3f)) {
+           wmask[i] = 0x00;
+       }
+    }
+
+    qemu_register_reset(vt82c686b_reset, d);
+
+    return 0;
+}
+
+ISABus *vt82c686b_init(PCIBus *bus, int devfn)
+{
+    PCIDevice *d;
+
+    d = pci_create_simple_multifunction(bus, devfn, true, "VT82C686B");
+
+    return DO_UPCAST(ISABus, qbus, qdev_get_child_bus(&d->qdev, "isa.0"));
+}
+
+static void via_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = vt82c686b_initfn;
+    k->config_write = vt82c686b_write_config;
+    k->vendor_id = PCI_VENDOR_ID_VIA;
+    k->device_id = PCI_DEVICE_ID_VIA_ISA_BRIDGE;
+    k->class_id = PCI_CLASS_BRIDGE_ISA;
+    k->revision = 0x40;
+    dc->desc = "ISA bridge";
+    dc->no_user = 1;
+    dc->vmsd = &vmstate_via;
+}
+
+static const TypeInfo via_info = {
+    .name          = "VT82C686B",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(VT82C686BState),
+    .class_init    = via_class_init,
+};
+
+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);
+}
+
+type_init(vt82c686b_register_types)
diff --git a/hw/isa_mmio.c b/hw/isa_mmio.c
deleted file mode 100644 (file)
index a7860e7..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Memory mapped access to ISA IO space.
- *
- * Copyright (c) 2006 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.
- */
-
-#include "hw/hw.h"
-#include "hw/isa.h"
-#include "exec/address-spaces.h"
-
-static void isa_mmio_writeb (void *opaque, hwaddr addr,
-                                  uint32_t val)
-{
-    cpu_outb(addr & IOPORTS_MASK, val);
-}
-
-static void isa_mmio_writew(void *opaque, hwaddr addr,
-                               uint32_t val)
-{
-    cpu_outw(addr & IOPORTS_MASK, val);
-}
-
-static void isa_mmio_writel(void *opaque, hwaddr addr,
-                               uint32_t val)
-{
-    cpu_outl(addr & IOPORTS_MASK, val);
-}
-
-static uint32_t isa_mmio_readb (void *opaque, hwaddr addr)
-{
-    return cpu_inb(addr & IOPORTS_MASK);
-}
-
-static uint32_t isa_mmio_readw(void *opaque, hwaddr addr)
-{
-    return cpu_inw(addr & IOPORTS_MASK);
-}
-
-static uint32_t isa_mmio_readl(void *opaque, hwaddr addr)
-{
-    return cpu_inl(addr & IOPORTS_MASK);
-}
-
-static const MemoryRegionOps isa_mmio_ops = {
-    .old_mmio = {
-        .write = { isa_mmio_writeb, isa_mmio_writew, isa_mmio_writel },
-        .read = { isa_mmio_readb, isa_mmio_readw, isa_mmio_readl, },
-    },
-    .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-void isa_mmio_setup(MemoryRegion *mr, hwaddr size)
-{
-    memory_region_init_io(mr, &isa_mmio_ops, NULL, "isa-mmio", size);
-}
-
-void isa_mmio_init(hwaddr base, hwaddr size)
-{
-    MemoryRegion *mr = g_malloc(sizeof(*mr));
-
-    isa_mmio_setup(mr, size);
-    memory_region_add_subregion(get_system_memory(), base, mr);
-}
diff --git a/hw/ivshmem.c b/hw/ivshmem.c
deleted file mode 100644 (file)
index af2789e..0000000
+++ /dev/null
@@ -1,826 +0,0 @@
-/*
- * Inter-VM Shared Memory PCI device.
- *
- * Author:
- *      Cam Macdonell <cam@cs.ualberta.ca>
- *
- * Based On: cirrus_vga.c
- *          Copyright (c) 2004 Fabrice Bellard
- *          Copyright (c) 2004 Makoto Suzuki (suzu)
- *
- *      and rtl8139.c
- *          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/hw.h"
-#include "hw/pc.h"
-#include "hw/pci/pci.h"
-#include "hw/pci/msix.h"
-#include "sysemu/kvm.h"
-#include "migration/migration.h"
-#include "qapi/qmp/qerror.h"
-#include "qemu/event_notifier.h"
-#include "char/char.h"
-
-#include <sys/mman.h>
-#include <sys/types.h>
-
-#define PCI_VENDOR_ID_IVSHMEM   PCI_VENDOR_ID_REDHAT_QUMRANET
-#define PCI_DEVICE_ID_IVSHMEM   0x1110
-
-#define IVSHMEM_IOEVENTFD   0
-#define IVSHMEM_MSI     1
-
-#define IVSHMEM_PEER    0
-#define IVSHMEM_MASTER  1
-
-#define IVSHMEM_REG_BAR_SIZE 0x100
-
-//#define DEBUG_IVSHMEM
-#ifdef DEBUG_IVSHMEM
-#define IVSHMEM_DPRINTF(fmt, ...)        \
-    do {printf("IVSHMEM: " fmt, ## __VA_ARGS__); } while (0)
-#else
-#define IVSHMEM_DPRINTF(fmt, ...)
-#endif
-
-typedef struct Peer {
-    int nb_eventfds;
-    EventNotifier *eventfds;
-} Peer;
-
-typedef struct EventfdEntry {
-    PCIDevice *pdev;
-    int vector;
-} EventfdEntry;
-
-typedef struct IVShmemState {
-    PCIDevice dev;
-    uint32_t intrmask;
-    uint32_t intrstatus;
-    uint32_t doorbell;
-
-    CharDriverState **eventfd_chr;
-    CharDriverState *server_chr;
-    MemoryRegion ivshmem_mmio;
-
-    /* We might need to register the BAR before we actually have the memory.
-     * So prepare a container MemoryRegion for the BAR immediately and
-     * add a subregion when we have the memory.
-     */
-    MemoryRegion bar;
-    MemoryRegion ivshmem;
-    uint64_t ivshmem_size; /* size of shared memory region */
-    uint32_t ivshmem_attr;
-    uint32_t ivshmem_64bit;
-    int shm_fd; /* shared memory file descriptor */
-
-    Peer *peers;
-    int nb_peers; /* how many guests we have space for */
-    int max_peer; /* maximum numbered peer */
-
-    int vm_id;
-    uint32_t vectors;
-    uint32_t features;
-    EventfdEntry *eventfd_table;
-
-    Error *migration_blocker;
-
-    char * shmobj;
-    char * sizearg;
-    char * role;
-    int role_val;   /* scalar to avoid multiple string comparisons */
-} IVShmemState;
-
-/* registers for the Inter-VM shared memory device */
-enum ivshmem_registers {
-    INTRMASK = 0,
-    INTRSTATUS = 4,
-    IVPOSITION = 8,
-    DOORBELL = 12,
-};
-
-static inline uint32_t ivshmem_has_feature(IVShmemState *ivs,
-                                                    unsigned int feature) {
-    return (ivs->features & (1 << feature));
-}
-
-static inline bool is_power_of_two(uint64_t x) {
-    return (x & (x - 1)) == 0;
-}
-
-/* accessing registers - based on rtl8139 */
-static void ivshmem_update_irq(IVShmemState *s, int val)
-{
-    int isr;
-    isr = (s->intrstatus & s->intrmask) & 0xffffffff;
-
-    /* don't print ISR resets */
-    if (isr) {
-        IVSHMEM_DPRINTF("Set IRQ to %d (%04x %04x)\n",
-           isr ? 1 : 0, s->intrstatus, s->intrmask);
-    }
-
-    qemu_set_irq(s->dev.irq[0], (isr != 0));
-}
-
-static void ivshmem_IntrMask_write(IVShmemState *s, uint32_t val)
-{
-    IVSHMEM_DPRINTF("IntrMask write(w) val = 0x%04x\n", val);
-
-    s->intrmask = val;
-
-    ivshmem_update_irq(s, val);
-}
-
-static uint32_t ivshmem_IntrMask_read(IVShmemState *s)
-{
-    uint32_t ret = s->intrmask;
-
-    IVSHMEM_DPRINTF("intrmask read(w) val = 0x%04x\n", ret);
-
-    return ret;
-}
-
-static void ivshmem_IntrStatus_write(IVShmemState *s, uint32_t val)
-{
-    IVSHMEM_DPRINTF("IntrStatus write(w) val = 0x%04x\n", val);
-
-    s->intrstatus = val;
-
-    ivshmem_update_irq(s, val);
-}
-
-static uint32_t ivshmem_IntrStatus_read(IVShmemState *s)
-{
-    uint32_t ret = s->intrstatus;
-
-    /* reading ISR clears all interrupts */
-    s->intrstatus = 0;
-
-    ivshmem_update_irq(s, 0);
-
-    return ret;
-}
-
-static void ivshmem_io_write(void *opaque, hwaddr addr,
-                             uint64_t val, unsigned size)
-{
-    IVShmemState *s = opaque;
-
-    uint16_t dest = val >> 16;
-    uint16_t vector = val & 0xff;
-
-    addr &= 0xfc;
-
-    IVSHMEM_DPRINTF("writing to addr " TARGET_FMT_plx "\n", addr);
-    switch (addr)
-    {
-        case INTRMASK:
-            ivshmem_IntrMask_write(s, val);
-            break;
-
-        case INTRSTATUS:
-            ivshmem_IntrStatus_write(s, val);
-            break;
-
-        case DOORBELL:
-            /* check that dest VM ID is reasonable */
-            if (dest > s->max_peer) {
-                IVSHMEM_DPRINTF("Invalid destination VM ID (%d)\n", dest);
-                break;
-            }
-
-            /* check doorbell range */
-            if (vector < s->peers[dest].nb_eventfds) {
-                IVSHMEM_DPRINTF("Notifying VM %d on vector %d\n", dest, vector);
-                event_notifier_set(&s->peers[dest].eventfds[vector]);
-            }
-            break;
-        default:
-            IVSHMEM_DPRINTF("Invalid VM Doorbell VM %d\n", dest);
-    }
-}
-
-static uint64_t ivshmem_io_read(void *opaque, hwaddr addr,
-                                unsigned size)
-{
-
-    IVShmemState *s = opaque;
-    uint32_t ret;
-
-    switch (addr)
-    {
-        case INTRMASK:
-            ret = ivshmem_IntrMask_read(s);
-            break;
-
-        case INTRSTATUS:
-            ret = ivshmem_IntrStatus_read(s);
-            break;
-
-        case IVPOSITION:
-            /* return my VM ID if the memory is mapped */
-            if (s->shm_fd > 0) {
-                ret = s->vm_id;
-            } else {
-                ret = -1;
-            }
-            break;
-
-        default:
-            IVSHMEM_DPRINTF("why are we reading " TARGET_FMT_plx "\n", addr);
-            ret = 0;
-    }
-
-    return ret;
-}
-
-static const MemoryRegionOps ivshmem_mmio_ops = {
-    .read = ivshmem_io_read,
-    .write = ivshmem_io_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .impl = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-};
-
-static void ivshmem_receive(void *opaque, const uint8_t *buf, int size)
-{
-    IVShmemState *s = opaque;
-
-    ivshmem_IntrStatus_write(s, *buf);
-
-    IVSHMEM_DPRINTF("ivshmem_receive 0x%02x\n", *buf);
-}
-
-static int ivshmem_can_receive(void * opaque)
-{
-    return 8;
-}
-
-static void ivshmem_event(void *opaque, int event)
-{
-    IVSHMEM_DPRINTF("ivshmem_event %d\n", event);
-}
-
-static void fake_irqfd(void *opaque, const uint8_t *buf, int size) {
-
-    EventfdEntry *entry = opaque;
-    PCIDevice *pdev = entry->pdev;
-
-    IVSHMEM_DPRINTF("interrupt on vector %p %d\n", pdev, entry->vector);
-    msix_notify(pdev, entry->vector);
-}
-
-static CharDriverState* create_eventfd_chr_device(void * opaque, EventNotifier *n,
-                                                  int vector)
-{
-    /* create a event character device based on the passed eventfd */
-    IVShmemState *s = opaque;
-    CharDriverState * chr;
-    int eventfd = event_notifier_get_fd(n);
-
-    chr = qemu_chr_open_eventfd(eventfd);
-
-    if (chr == NULL) {
-        fprintf(stderr, "creating eventfd for eventfd %d failed\n", eventfd);
-        exit(-1);
-    }
-    qemu_chr_fe_claim_no_fail(chr);
-
-    /* if MSI is supported we need multiple interrupts */
-    if (ivshmem_has_feature(s, IVSHMEM_MSI)) {
-        s->eventfd_table[vector].pdev = &s->dev;
-        s->eventfd_table[vector].vector = vector;
-
-        qemu_chr_add_handlers(chr, ivshmem_can_receive, fake_irqfd,
-                      ivshmem_event, &s->eventfd_table[vector]);
-    } else {
-        qemu_chr_add_handlers(chr, ivshmem_can_receive, ivshmem_receive,
-                      ivshmem_event, s);
-    }
-
-    return chr;
-
-}
-
-static int check_shm_size(IVShmemState *s, int fd) {
-    /* check that the guest isn't going to try and map more memory than the
-     * the object has allocated return -1 to indicate error */
-
-    struct stat buf;
-
-    fstat(fd, &buf);
-
-    if (s->ivshmem_size > buf.st_size) {
-        fprintf(stderr,
-                "IVSHMEM ERROR: Requested memory size greater"
-                " than shared object size (%" PRIu64 " > %" PRIu64")\n",
-                s->ivshmem_size, (uint64_t)buf.st_size);
-        return -1;
-    } else {
-        return 0;
-    }
-}
-
-/* create the shared memory BAR when we are not using the server, so we can
- * create the BAR and map the memory immediately */
-static void create_shared_memory_BAR(IVShmemState *s, int fd) {
-
-    void * ptr;
-
-    s->shm_fd = fd;
-
-    ptr = mmap(0, s->ivshmem_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
-
-    memory_region_init_ram_ptr(&s->ivshmem, "ivshmem.bar2",
-                               s->ivshmem_size, ptr);
-    vmstate_register_ram(&s->ivshmem, &s->dev.qdev);
-    memory_region_add_subregion(&s->bar, 0, &s->ivshmem);
-
-    /* region for shared memory */
-    pci_register_bar(&s->dev, 2, s->ivshmem_attr, &s->bar);
-}
-
-static void ivshmem_add_eventfd(IVShmemState *s, int posn, int i)
-{
-    memory_region_add_eventfd(&s->ivshmem_mmio,
-                              DOORBELL,
-                              4,
-                              true,
-                              (posn << 16) | i,
-                              &s->peers[posn].eventfds[i]);
-}
-
-static void ivshmem_del_eventfd(IVShmemState *s, int posn, int i)
-{
-    memory_region_del_eventfd(&s->ivshmem_mmio,
-                              DOORBELL,
-                              4,
-                              true,
-                              (posn << 16) | i,
-                              &s->peers[posn].eventfds[i]);
-}
-
-static void close_guest_eventfds(IVShmemState *s, int posn)
-{
-    int i, guest_curr_max;
-
-    if (!ivshmem_has_feature(s, IVSHMEM_IOEVENTFD)) {
-        return;
-    }
-
-    guest_curr_max = s->peers[posn].nb_eventfds;
-
-    memory_region_transaction_begin();
-    for (i = 0; i < guest_curr_max; i++) {
-        ivshmem_del_eventfd(s, posn, i);
-    }
-    memory_region_transaction_commit();
-    for (i = 0; i < guest_curr_max; i++) {
-        event_notifier_cleanup(&s->peers[posn].eventfds[i]);
-    }
-
-    g_free(s->peers[posn].eventfds);
-    s->peers[posn].nb_eventfds = 0;
-}
-
-/* this function increase the dynamic storage need to store data about other
- * guests */
-static void increase_dynamic_storage(IVShmemState *s, int new_min_size) {
-
-    int j, old_nb_alloc;
-
-    old_nb_alloc = s->nb_peers;
-
-    while (new_min_size >= s->nb_peers)
-        s->nb_peers = s->nb_peers * 2;
-
-    IVSHMEM_DPRINTF("bumping storage to %d guests\n", s->nb_peers);
-    s->peers = g_realloc(s->peers, s->nb_peers * sizeof(Peer));
-
-    /* zero out new pointers */
-    for (j = old_nb_alloc; j < s->nb_peers; j++) {
-        s->peers[j].eventfds = NULL;
-        s->peers[j].nb_eventfds = 0;
-    }
-}
-
-static void ivshmem_read(void *opaque, const uint8_t * buf, int flags)
-{
-    IVShmemState *s = opaque;
-    int incoming_fd, tmp_fd;
-    int guest_max_eventfd;
-    long incoming_posn;
-
-    memcpy(&incoming_posn, buf, sizeof(long));
-    /* pick off s->server_chr->msgfd and store it, posn should accompany msg */
-    tmp_fd = qemu_chr_fe_get_msgfd(s->server_chr);
-    IVSHMEM_DPRINTF("posn is %ld, fd is %d\n", incoming_posn, tmp_fd);
-
-    /* make sure we have enough space for this guest */
-    if (incoming_posn >= s->nb_peers) {
-        increase_dynamic_storage(s, incoming_posn);
-    }
-
-    if (tmp_fd == -1) {
-        /* if posn is positive and unseen before then this is our posn*/
-        if ((incoming_posn >= 0) &&
-                            (s->peers[incoming_posn].eventfds == NULL)) {
-            /* receive our posn */
-            s->vm_id = incoming_posn;
-            return;
-        } else {
-            /* otherwise an fd == -1 means an existing guest has gone away */
-            IVSHMEM_DPRINTF("posn %ld has gone away\n", incoming_posn);
-            close_guest_eventfds(s, incoming_posn);
-            return;
-        }
-    }
-
-    /* because of the implementation of get_msgfd, we need a dup */
-    incoming_fd = dup(tmp_fd);
-
-    if (incoming_fd == -1) {
-        fprintf(stderr, "could not allocate file descriptor %s\n",
-                                                            strerror(errno));
-        return;
-    }
-
-    /* if the position is -1, then it's shared memory region fd */
-    if (incoming_posn == -1) {
-
-        void * map_ptr;
-
-        s->max_peer = 0;
-
-        if (check_shm_size(s, incoming_fd) == -1) {
-            exit(-1);
-        }
-
-        /* mmap the region and map into the BAR2 */
-        map_ptr = mmap(0, s->ivshmem_size, PROT_READ|PROT_WRITE, MAP_SHARED,
-                                                            incoming_fd, 0);
-        memory_region_init_ram_ptr(&s->ivshmem,
-                                   "ivshmem.bar2", s->ivshmem_size, map_ptr);
-        vmstate_register_ram(&s->ivshmem, &s->dev.qdev);
-
-        IVSHMEM_DPRINTF("guest h/w addr = %" PRIu64 ", size = %" PRIu64 "\n",
-                         s->ivshmem_offset, s->ivshmem_size);
-
-        memory_region_add_subregion(&s->bar, 0, &s->ivshmem);
-
-        /* only store the fd if it is successfully mapped */
-        s->shm_fd = incoming_fd;
-
-        return;
-    }
-
-    /* each guest has an array of eventfds, and we keep track of how many
-     * guests for each VM */
-    guest_max_eventfd = s->peers[incoming_posn].nb_eventfds;
-
-    if (guest_max_eventfd == 0) {
-        /* one eventfd per MSI vector */
-        s->peers[incoming_posn].eventfds = g_new(EventNotifier, s->vectors);
-    }
-
-    /* this is an eventfd for a particular guest VM */
-    IVSHMEM_DPRINTF("eventfds[%ld][%d] = %d\n", incoming_posn,
-                                            guest_max_eventfd, incoming_fd);
-    event_notifier_init_fd(&s->peers[incoming_posn].eventfds[guest_max_eventfd],
-                           incoming_fd);
-
-    /* increment count for particular guest */
-    s->peers[incoming_posn].nb_eventfds++;
-
-    /* keep track of the maximum VM ID */
-    if (incoming_posn > s->max_peer) {
-        s->max_peer = incoming_posn;
-    }
-
-    if (incoming_posn == s->vm_id) {
-        s->eventfd_chr[guest_max_eventfd] = create_eventfd_chr_device(s,
-                   &s->peers[s->vm_id].eventfds[guest_max_eventfd],
-                   guest_max_eventfd);
-    }
-
-    if (ivshmem_has_feature(s, IVSHMEM_IOEVENTFD)) {
-        ivshmem_add_eventfd(s, incoming_posn, guest_max_eventfd);
-    }
-}
-
-/* Select the MSI-X vectors used by device.
- * ivshmem maps events to vectors statically, so
- * we just enable all vectors on init and after reset. */
-static void ivshmem_use_msix(IVShmemState * s)
-{
-    int i;
-
-    if (!msix_present(&s->dev)) {
-        return;
-    }
-
-    for (i = 0; i < s->vectors; i++) {
-        msix_vector_use(&s->dev, i);
-    }
-}
-
-static void ivshmem_reset(DeviceState *d)
-{
-    IVShmemState *s = DO_UPCAST(IVShmemState, dev.qdev, d);
-
-    s->intrstatus = 0;
-    ivshmem_use_msix(s);
-}
-
-static uint64_t ivshmem_get_size(IVShmemState * s) {
-
-    uint64_t value;
-    char *ptr;
-
-    value = strtoull(s->sizearg, &ptr, 10);
-    switch (*ptr) {
-        case 0: case 'M': case 'm':
-            value <<= 20;
-            break;
-        case 'G': case 'g':
-            value <<= 30;
-            break;
-        default:
-            fprintf(stderr, "qemu: invalid ram size: %s\n", s->sizearg);
-            exit(1);
-    }
-
-    /* BARs must be a power of 2 */
-    if (!is_power_of_two(value)) {
-        fprintf(stderr, "ivshmem: size must be power of 2\n");
-        exit(1);
-    }
-
-    return value;
-}
-
-static void ivshmem_setup_msi(IVShmemState * s)
-{
-    if (msix_init_exclusive_bar(&s->dev, s->vectors, 1)) {
-        IVSHMEM_DPRINTF("msix initialization failed\n");
-        exit(1);
-    }
-
-    IVSHMEM_DPRINTF("msix initialized (%d vectors)\n", s->vectors);
-
-    /* allocate QEMU char devices for receiving interrupts */
-    s->eventfd_table = g_malloc0(s->vectors * sizeof(EventfdEntry));
-
-    ivshmem_use_msix(s);
-}
-
-static void ivshmem_save(QEMUFile* f, void *opaque)
-{
-    IVShmemState *proxy = opaque;
-
-    IVSHMEM_DPRINTF("ivshmem_save\n");
-    pci_device_save(&proxy->dev, f);
-
-    if (ivshmem_has_feature(proxy, IVSHMEM_MSI)) {
-        msix_save(&proxy->dev, f);
-    } else {
-        qemu_put_be32(f, proxy->intrstatus);
-        qemu_put_be32(f, proxy->intrmask);
-    }
-
-}
-
-static int ivshmem_load(QEMUFile* f, void *opaque, int version_id)
-{
-    IVSHMEM_DPRINTF("ivshmem_load\n");
-
-    IVShmemState *proxy = opaque;
-    int ret;
-
-    if (version_id > 0) {
-        return -EINVAL;
-    }
-
-    if (proxy->role_val == IVSHMEM_PEER) {
-        fprintf(stderr, "ivshmem: 'peer' devices are not migratable\n");
-        return -EINVAL;
-    }
-
-    ret = pci_device_load(&proxy->dev, f);
-    if (ret) {
-        return ret;
-    }
-
-    if (ivshmem_has_feature(proxy, IVSHMEM_MSI)) {
-        msix_load(&proxy->dev, f);
-       ivshmem_use_msix(proxy);
-    } else {
-        proxy->intrstatus = qemu_get_be32(f);
-        proxy->intrmask = qemu_get_be32(f);
-    }
-
-    return 0;
-}
-
-static void ivshmem_write_config(PCIDevice *pci_dev, uint32_t address,
-                                uint32_t val, int len)
-{
-    pci_default_write_config(pci_dev, address, val, len);
-    msix_write_config(pci_dev, address, val, len);
-}
-
-static int pci_ivshmem_init(PCIDevice *dev)
-{
-    IVShmemState *s = DO_UPCAST(IVShmemState, dev, dev);
-    uint8_t *pci_conf;
-
-    if (s->sizearg == NULL)
-        s->ivshmem_size = 4 << 20; /* 4 MB default */
-    else {
-        s->ivshmem_size = ivshmem_get_size(s);
-    }
-
-    register_savevm(&s->dev.qdev, "ivshmem", 0, 0, ivshmem_save, ivshmem_load,
-                                                                        dev);
-
-    /* IRQFD requires MSI */
-    if (ivshmem_has_feature(s, IVSHMEM_IOEVENTFD) &&
-        !ivshmem_has_feature(s, IVSHMEM_MSI)) {
-        fprintf(stderr, "ivshmem: ioeventfd/irqfd requires MSI\n");
-        exit(1);
-    }
-
-    /* check that role is reasonable */
-    if (s->role) {
-        if (strncmp(s->role, "peer", 5) == 0) {
-            s->role_val = IVSHMEM_PEER;
-        } else if (strncmp(s->role, "master", 7) == 0) {
-            s->role_val = IVSHMEM_MASTER;
-        } else {
-            fprintf(stderr, "ivshmem: 'role' must be 'peer' or 'master'\n");
-            exit(1);
-        }
-    } else {
-        s->role_val = IVSHMEM_MASTER; /* default */
-    }
-
-    if (s->role_val == IVSHMEM_PEER) {
-        error_set(&s->migration_blocker, QERR_DEVICE_FEATURE_BLOCKS_MIGRATION,
-                  "peer mode", "ivshmem");
-        migrate_add_blocker(s->migration_blocker);
-    }
-
-    pci_conf = s->dev.config;
-    pci_conf[PCI_COMMAND] = PCI_COMMAND_IO | PCI_COMMAND_MEMORY;
-
-    pci_config_set_interrupt_pin(pci_conf, 1);
-
-    s->shm_fd = 0;
-
-    memory_region_init_io(&s->ivshmem_mmio, &ivshmem_mmio_ops, s,
-                          "ivshmem-mmio", IVSHMEM_REG_BAR_SIZE);
-
-    /* region for registers*/
-    pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY,
-                     &s->ivshmem_mmio);
-
-    memory_region_init(&s->bar, "ivshmem-bar2-container", s->ivshmem_size);
-    s->ivshmem_attr = PCI_BASE_ADDRESS_SPACE_MEMORY |
-        PCI_BASE_ADDRESS_MEM_PREFETCH;
-    if (s->ivshmem_64bit) {
-        s->ivshmem_attr |= PCI_BASE_ADDRESS_MEM_TYPE_64;
-    }
-
-    if ((s->server_chr != NULL) &&
-                        (strncmp(s->server_chr->filename, "unix:", 5) == 0)) {
-        /* if we get a UNIX socket as the parameter we will talk
-         * to the ivshmem server to receive the memory region */
-
-        if (s->shmobj != NULL) {
-            fprintf(stderr, "WARNING: do not specify both 'chardev' "
-                                                "and 'shm' with ivshmem\n");
-        }
-
-        IVSHMEM_DPRINTF("using shared memory server (socket = %s)\n",
-                                                    s->server_chr->filename);
-
-        if (ivshmem_has_feature(s, IVSHMEM_MSI)) {
-            ivshmem_setup_msi(s);
-        }
-
-        /* we allocate enough space for 16 guests and grow as needed */
-        s->nb_peers = 16;
-        s->vm_id = -1;
-
-        /* allocate/initialize space for interrupt handling */
-        s->peers = g_malloc0(s->nb_peers * sizeof(Peer));
-
-        pci_register_bar(&s->dev, 2, s->ivshmem_attr, &s->bar);
-
-        s->eventfd_chr = g_malloc0(s->vectors * sizeof(CharDriverState *));
-
-        qemu_chr_add_handlers(s->server_chr, ivshmem_can_receive, ivshmem_read,
-                     ivshmem_event, s);
-    } else {
-        /* just map the file immediately, we're not using a server */
-        int fd;
-
-        if (s->shmobj == NULL) {
-            fprintf(stderr, "Must specify 'chardev' or 'shm' to ivshmem\n");
-        }
-
-        IVSHMEM_DPRINTF("using shm_open (shm object = %s)\n", s->shmobj);
-
-        /* try opening with O_EXCL and if it succeeds zero the memory
-         * by truncating to 0 */
-        if ((fd = shm_open(s->shmobj, O_CREAT|O_RDWR|O_EXCL,
-                        S_IRWXU|S_IRWXG|S_IRWXO)) > 0) {
-           /* truncate file to length PCI device's memory */
-            if (ftruncate(fd, s->ivshmem_size) != 0) {
-                fprintf(stderr, "ivshmem: could not truncate shared file\n");
-            }
-
-        } else if ((fd = shm_open(s->shmobj, O_CREAT|O_RDWR,
-                        S_IRWXU|S_IRWXG|S_IRWXO)) < 0) {
-            fprintf(stderr, "ivshmem: could not open shared file\n");
-            exit(-1);
-
-        }
-
-        if (check_shm_size(s, fd) == -1) {
-            exit(-1);
-        }
-
-        create_shared_memory_BAR(s, fd);
-
-    }
-
-    s->dev.config_write = ivshmem_write_config;
-
-    return 0;
-}
-
-static void pci_ivshmem_uninit(PCIDevice *dev)
-{
-    IVShmemState *s = DO_UPCAST(IVShmemState, dev, dev);
-
-    if (s->migration_blocker) {
-        migrate_del_blocker(s->migration_blocker);
-        error_free(s->migration_blocker);
-    }
-
-    memory_region_destroy(&s->ivshmem_mmio);
-    memory_region_del_subregion(&s->bar, &s->ivshmem);
-    vmstate_unregister_ram(&s->ivshmem, &s->dev.qdev);
-    memory_region_destroy(&s->ivshmem);
-    memory_region_destroy(&s->bar);
-    unregister_savevm(&dev->qdev, "ivshmem", s);
-}
-
-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_UINT32("use64", IVShmemState, ivshmem_64bit, 1),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void ivshmem_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
-    k->init = pci_ivshmem_init;
-    k->exit = pci_ivshmem_uninit;
-    k->vendor_id = PCI_VENDOR_ID_IVSHMEM;
-    k->device_id = PCI_DEVICE_ID_IVSHMEM;
-    k->class_id = PCI_CLASS_MEMORY_RAM;
-    dc->reset = ivshmem_reset;
-    dc->props = ivshmem_properties;
-}
-
-static const TypeInfo ivshmem_info = {
-    .name          = "ivshmem",
-    .parent        = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(IVShmemState),
-    .class_init    = ivshmem_class_init,
-};
-
-static void ivshmem_register_types(void)
-{
-    type_register_static(&ivshmem_info);
-}
-
-type_init(ivshmem_register_types)
diff --git a/hw/jazz_led.c b/hw/jazz_led.c
deleted file mode 100644 (file)
index 05528c7..0000000
+++ /dev/null
@@ -1,304 +0,0 @@
-/*
- * QEMU JAZZ LED emulator.
- *
- * Copyright (c) 2007-2012 Herve 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 "qemu-common.h"
-#include "ui/console.h"
-#include "ui/pixel_ops.h"
-#include "trace.h"
-#include "hw/sysbus.h"
-
-typedef enum {
-    REDRAW_NONE = 0, REDRAW_SEGMENTS = 1, REDRAW_BACKGROUND = 2,
-} screen_state_t;
-
-typedef struct LedState {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-    uint8_t segments;
-    QemuConsole *con;
-    screen_state_t state;
-} LedState;
-
-static uint64_t jazz_led_read(void *opaque, hwaddr addr,
-                              unsigned int size)
-{
-    LedState *s = opaque;
-    uint8_t val;
-
-    val = s->segments;
-    trace_jazz_led_read(addr, val);
-
-    return val;
-}
-
-static void jazz_led_write(void *opaque, hwaddr addr,
-                           uint64_t val, unsigned int size)
-{
-    LedState *s = opaque;
-    uint8_t new_val = val & 0xff;
-
-    trace_jazz_led_write(addr, new_val);
-
-    s->segments = new_val;
-    s->state |= REDRAW_SEGMENTS;
-}
-
-static const MemoryRegionOps led_ops = {
-    .read = jazz_led_read,
-    .write = jazz_led_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .impl.min_access_size = 1,
-    .impl.max_access_size = 1,
-};
-
-/***********************************************************/
-/* jazz_led display */
-
-static void draw_horizontal_line(DisplaySurface *ds,
-                                 int posy, int posx1, int posx2,
-                                 uint32_t color)
-{
-    uint8_t *d;
-    int x, bpp;
-
-    bpp = (surface_bits_per_pixel(ds) + 7) >> 3;
-    d = surface_data(ds) + surface_stride(ds) * posy + bpp * posx1;
-    switch(bpp) {
-        case 1:
-            for (x = posx1; x <= posx2; x++) {
-                *((uint8_t *)d) = color;
-                d++;
-            }
-            break;
-        case 2:
-            for (x = posx1; x <= posx2; x++) {
-                *((uint16_t *)d) = color;
-                d += 2;
-            }
-            break;
-        case 4:
-            for (x = posx1; x <= posx2; x++) {
-                *((uint32_t *)d) = color;
-                d += 4;
-            }
-            break;
-    }
-}
-
-static void draw_vertical_line(DisplaySurface *ds,
-                               int posx, int posy1, int posy2,
-                               uint32_t color)
-{
-    uint8_t *d;
-    int y, bpp;
-
-    bpp = (surface_bits_per_pixel(ds) + 7) >> 3;
-    d = surface_data(ds) + surface_stride(ds) * posy1 + bpp * posx;
-    switch(bpp) {
-        case 1:
-            for (y = posy1; y <= posy2; y++) {
-                *((uint8_t *)d) = color;
-                d += surface_stride(ds);
-            }
-            break;
-        case 2:
-            for (y = posy1; y <= posy2; y++) {
-                *((uint16_t *)d) = color;
-                d += surface_stride(ds);
-            }
-            break;
-        case 4:
-            for (y = posy1; y <= posy2; y++) {
-                *((uint32_t *)d) = color;
-                d += surface_stride(ds);
-            }
-            break;
-    }
-}
-
-static void jazz_led_update_display(void *opaque)
-{
-    LedState *s = opaque;
-    DisplaySurface *surface = qemu_console_surface(s->con);
-    uint8_t *d1;
-    uint32_t color_segment, color_led;
-    int y, bpp;
-
-    if (s->state & REDRAW_BACKGROUND) {
-        /* clear screen */
-        bpp = (surface_bits_per_pixel(surface) + 7) >> 3;
-        d1 = surface_data(surface);
-        for (y = 0; y < surface_height(surface); y++) {
-            memset(d1, 0x00, surface_width(surface) * bpp);
-            d1 += surface_stride(surface);
-        }
-    }
-
-    if (s->state & REDRAW_SEGMENTS) {
-        /* set colors according to bpp */
-        switch (surface_bits_per_pixel(surface)) {
-            case 8:
-                color_segment = rgb_to_pixel8(0xaa, 0xaa, 0xaa);
-                color_led = rgb_to_pixel8(0x00, 0xff, 0x00);
-                break;
-            case 15:
-                color_segment = rgb_to_pixel15(0xaa, 0xaa, 0xaa);
-                color_led = rgb_to_pixel15(0x00, 0xff, 0x00);
-                break;
-            case 16:
-                color_segment = rgb_to_pixel16(0xaa, 0xaa, 0xaa);
-                color_led = rgb_to_pixel16(0x00, 0xff, 0x00);
-            case 24:
-                color_segment = rgb_to_pixel24(0xaa, 0xaa, 0xaa);
-                color_led = rgb_to_pixel24(0x00, 0xff, 0x00);
-                break;
-            case 32:
-                color_segment = rgb_to_pixel32(0xaa, 0xaa, 0xaa);
-                color_led = rgb_to_pixel32(0x00, 0xff, 0x00);
-                break;
-            default:
-                return;
-        }
-
-        /* display segments */
-        draw_horizontal_line(surface, 40, 10, 40,
-                             (s->segments & 0x02) ? color_segment : 0);
-        draw_vertical_line(surface, 10, 10, 40,
-                           (s->segments & 0x04) ? color_segment : 0);
-        draw_vertical_line(surface, 10, 40, 70,
-                           (s->segments & 0x08) ? color_segment : 0);
-        draw_horizontal_line(surface, 70, 10, 40,
-                             (s->segments & 0x10) ? color_segment : 0);
-        draw_vertical_line(surface, 40, 40, 70,
-                           (s->segments & 0x20) ? color_segment : 0);
-        draw_vertical_line(surface, 40, 10, 40,
-                           (s->segments & 0x40) ? color_segment : 0);
-        draw_horizontal_line(surface, 10, 10, 40,
-                             (s->segments & 0x80) ? color_segment : 0);
-
-        /* display led */
-        if (!(s->segments & 0x01))
-            color_led = 0; /* black */
-        draw_horizontal_line(surface, 68, 50, 50, color_led);
-        draw_horizontal_line(surface, 69, 49, 51, color_led);
-        draw_horizontal_line(surface, 70, 48, 52, color_led);
-        draw_horizontal_line(surface, 71, 49, 51, color_led);
-        draw_horizontal_line(surface, 72, 50, 50, color_led);
-    }
-
-    s->state = REDRAW_NONE;
-    dpy_gfx_update(s->con, 0, 0,
-                   surface_width(surface), surface_height(surface));
-}
-
-static void jazz_led_invalidate_display(void *opaque)
-{
-    LedState *s = opaque;
-    s->state |= REDRAW_SEGMENTS | REDRAW_BACKGROUND;
-}
-
-static void jazz_led_text_update(void *opaque, console_ch_t *chardata)
-{
-    LedState *s = opaque;
-    char buf[2];
-
-    dpy_text_cursor(s->con, -1, -1);
-    qemu_console_resize(s->con, 2, 1);
-
-    /* TODO: draw the segments */
-    snprintf(buf, 2, "%02hhx\n", s->segments);
-    console_write_ch(chardata++, 0x00200100 | buf[0]);
-    console_write_ch(chardata++, 0x00200100 | buf[1]);
-
-    dpy_text_update(s->con, 0, 0, 2, 1);
-}
-
-static int jazz_led_post_load(void *opaque, int version_id)
-{
-    /* force refresh */
-    jazz_led_invalidate_display(opaque);
-
-    return 0;
-}
-
-static const VMStateDescription vmstate_jazz_led = {
-    .name = "jazz-led",
-    .version_id = 0,
-    .minimum_version_id = 0,
-    .minimum_version_id_old = 0,
-    .post_load = jazz_led_post_load,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT8(segments, LedState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static int jazz_led_init(SysBusDevice *dev)
-{
-    LedState *s = FROM_SYSBUS(LedState, dev);
-
-    memory_region_init_io(&s->iomem, &led_ops, s, "led", 1);
-    sysbus_init_mmio(dev, &s->iomem);
-
-    s->con = graphic_console_init(jazz_led_update_display,
-                                  jazz_led_invalidate_display,
-                                  NULL,
-                                  jazz_led_text_update, s);
-
-    return 0;
-}
-
-static void jazz_led_reset(DeviceState *d)
-{
-    LedState *s = DO_UPCAST(LedState, busdev.qdev, d);
-
-    s->segments = 0;
-    s->state = REDRAW_SEGMENTS | REDRAW_BACKGROUND;
-    qemu_console_resize(s->con, 60, 80);
-}
-
-static void jazz_led_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = jazz_led_init;
-    dc->desc = "Jazz LED display",
-    dc->vmsd = &vmstate_jazz_led;
-    dc->reset = jazz_led_reset;
-}
-
-static const TypeInfo jazz_led_info = {
-    .name          = "jazz-led",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(LedState),
-    .class_init    = jazz_led_class_init,
-};
-
-static void jazz_led_register(void)
-{
-    type_register_static(&jazz_led_info);
-}
-
-type_init(jazz_led_register);
diff --git a/hw/kvm/Makefile.objs b/hw/kvm/Makefile.objs
deleted file mode 100644 (file)
index f620d7f..0000000
+++ /dev/null
@@ -1 +0,0 @@
-obj-$(CONFIG_KVM) += clock.o apic.o i8259.o ioapic.o i8254.o pci-assign.o
diff --git a/hw/kvm/apic.c b/hw/kvm/apic.c
deleted file mode 100644 (file)
index d994ea7..0000000
+++ /dev/null
@@ -1,209 +0,0 @@
-/*
- * KVM in-kernel APIC support
- *
- * Copyright (c) 2011 Siemens AG
- *
- * Authors:
- *  Jan Kiszka          <jan.kiszka@siemens.com>
- *
- * This work is licensed under the terms of the GNU GPL version 2.
- * See the COPYING file in the top-level directory.
- */
-#include "hw/apic_internal.h"
-#include "hw/pci/msi.h"
-#include "sysemu/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 uint8_t kvm_apic_get_tpr(APICCommonState *s)
-{
-    return s->tpr >> 4;
-}
-
-static void kvm_apic_enable_tpr_reporting(APICCommonState *s, bool enable)
-{
-    struct kvm_tpr_access_ctl ctl = {
-        .enabled = enable
-    };
-
-    kvm_vcpu_ioctl(CPU(s->cpu), KVM_TPR_ACCESS_REPORTING, &ctl);
-}
-
-static void kvm_apic_vapic_base_update(APICCommonState *s)
-{
-    struct kvm_vapic_addr vapid_addr = {
-        .vapic_addr = s->vapic_paddr,
-    };
-    int ret;
-
-    ret = kvm_vcpu_ioctl(CPU(s->cpu), KVM_SET_VAPIC_ADDR, &vapid_addr);
-    if (ret < 0) {
-        fprintf(stderr, "KVM: setting VAPIC address failed (%s)\n",
-                strerror(-ret));
-        abort();
-    }
-}
-
-static void do_inject_external_nmi(void *data)
-{
-    APICCommonState *s = data;
-    CPUState *cpu = CPU(s->cpu);
-    uint32_t lvt;
-    int ret;
-
-    cpu_synchronize_state(&s->cpu->env);
-
-    lvt = s->lvt[APIC_LVT_LINT1];
-    if (!(lvt & APIC_LVT_MASKED) && ((lvt >> 8) & 7) == APIC_DM_NMI) {
-        ret = kvm_vcpu_ioctl(cpu, 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(CPU(s->cpu), do_inject_external_nmi, s);
-}
-
-static uint64_t kvm_apic_mem_read(void *opaque, hwaddr addr,
-                                  unsigned size)
-{
-    return ~(uint64_t)0;
-}
-
-static void kvm_apic_mem_write(void *opaque, hwaddr addr,
-                               uint64_t data, unsigned size)
-{
-    MSIMessage msg = { .address = addr, .data = data };
-    int ret;
-
-    ret = kvm_irqchip_send_msi(kvm_state, msg);
-    if (ret < 0) {
-        fprintf(stderr, "KVM: injection failed, MSI lost (%s)\n",
-                strerror(-ret));
-    }
-}
-
-static const MemoryRegionOps kvm_apic_io_ops = {
-    .read = kvm_apic_mem_read,
-    .write = kvm_apic_mem_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void kvm_apic_init(APICCommonState *s)
-{
-    memory_region_init_io(&s->io_memory, &kvm_apic_io_ops, s, "kvm-apic-msi",
-                          MSI_SPACE_SIZE);
-
-    if (kvm_has_gsi_routing()) {
-        msi_supported = true;
-    }
-}
-
-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->get_tpr = kvm_apic_get_tpr;
-    k->enable_tpr_reporting = kvm_apic_enable_tpr_reporting;
-    k->vapic_base_update = kvm_apic_vapic_base_update;
-    k->external_nmi = kvm_apic_external_nmi;
-}
-
-static const TypeInfo kvm_apic_info = {
-    .name = "kvm-apic",
-    .parent = TYPE_APIC_COMMON,
-    .instance_size = sizeof(APICCommonState),
-    .class_init = kvm_apic_class_init,
-};
-
-static void kvm_apic_register_types(void)
-{
-    type_register_static(&kvm_apic_info);
-}
-
-type_init(kvm_apic_register_types)
diff --git a/hw/kvm/arm_gic.c b/hw/kvm/arm_gic.c
deleted file mode 100644 (file)
index 22b40b4..0000000
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * ARM Generic Interrupt Controller using KVM in-kernel support
- *
- * 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 "hw/sysbus.h"
-#include "sysemu/kvm.h"
-#include "kvm_arm.h"
-#include "hw/arm_gic_internal.h"
-
-#define TYPE_KVM_ARM_GIC "kvm-arm-gic"
-#define KVM_ARM_GIC(obj) \
-     OBJECT_CHECK(GICState, (obj), TYPE_KVM_ARM_GIC)
-#define KVM_ARM_GIC_CLASS(klass) \
-     OBJECT_CLASS_CHECK(KVMARMGICClass, (klass), TYPE_KVM_ARM_GIC)
-#define KVM_ARM_GIC_GET_CLASS(obj) \
-     OBJECT_GET_CLASS(KVMARMGICClass, (obj), TYPE_KVM_ARM_GIC)
-
-typedef struct KVMARMGICClass {
-    ARMGICCommonClass parent_class;
-    DeviceRealize parent_realize;
-    void (*parent_reset)(DeviceState *dev);
-} KVMARMGICClass;
-
-static void kvm_arm_gic_set_irq(void *opaque, int irq, int level)
-{
-    /* Meaning of the 'irq' parameter:
-     *  [0..N-1] : external interrupts
-     *  [N..N+31] : PPI (internal) interrupts for CPU 0
-     *  [N+32..N+63] : PPI (internal interrupts for CPU 1
-     *  ...
-     * Convert this to the kernel's desired encoding, which
-     * has separate fields in the irq number for type,
-     * CPU number and interrupt number.
-     */
-    GICState *s = (GICState *)opaque;
-    int kvm_irq, irqtype, cpu;
-
-    if (irq < (s->num_irq - GIC_INTERNAL)) {
-        /* External interrupt. The kernel numbers these like the GIC
-         * hardware, with external interrupt IDs starting after the
-         * internal ones.
-         */
-        irqtype = KVM_ARM_IRQ_TYPE_SPI;
-        cpu = 0;
-        irq += GIC_INTERNAL;
-    } else {
-        /* Internal interrupt: decode into (cpu, interrupt id) */
-        irqtype = KVM_ARM_IRQ_TYPE_PPI;
-        irq -= (s->num_irq - GIC_INTERNAL);
-        cpu = irq / GIC_INTERNAL;
-        irq %= GIC_INTERNAL;
-    }
-    kvm_irq = (irqtype << KVM_ARM_IRQ_TYPE_SHIFT)
-        | (cpu << KVM_ARM_IRQ_VCPU_SHIFT) | irq;
-
-    kvm_set_irq(kvm_state, kvm_irq, !!level);
-}
-
-static void kvm_arm_gic_put(GICState *s)
-{
-    /* TODO: there isn't currently a kernel interface to set the GIC state */
-}
-
-static void kvm_arm_gic_get(GICState *s)
-{
-    /* TODO: there isn't currently a kernel interface to get the GIC state */
-}
-
-static void kvm_arm_gic_reset(DeviceState *dev)
-{
-    GICState *s = ARM_GIC_COMMON(dev);
-    KVMARMGICClass *kgc = KVM_ARM_GIC_GET_CLASS(s);
-
-    kgc->parent_reset(dev);
-    kvm_arm_gic_put(s);
-}
-
-static void kvm_arm_gic_realize(DeviceState *dev, Error **errp)
-{
-    int i;
-    GICState *s = KVM_ARM_GIC(dev);
-    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
-    KVMARMGICClass *kgc = KVM_ARM_GIC_GET_CLASS(s);
-
-    kgc->parent_realize(dev, errp);
-    if (error_is_set(errp)) {
-        return;
-    }
-
-    i = s->num_irq - GIC_INTERNAL;
-    /* For the GIC, also expose incoming GPIO lines for PPIs for each CPU.
-     * GPIO array layout is thus:
-     *  [0..N-1] SPIs
-     *  [N..N+31] PPIs for CPU 0
-     *  [N+32..N+63] PPIs for CPU 1
-     *   ...
-     */
-    i += (GIC_INTERNAL * s->num_cpu);
-    qdev_init_gpio_in(dev, kvm_arm_gic_set_irq, i);
-    /* We never use our outbound IRQ lines but provide them so that
-     * we maintain the same interface as the non-KVM GIC.
-     */
-    for (i = 0; i < s->num_cpu; i++) {
-        sysbus_init_irq(sbd, &s->parent_irq[i]);
-    }
-    /* Distributor */
-    memory_region_init_reservation(&s->iomem, "kvm-gic_dist", 0x1000);
-    sysbus_init_mmio(sbd, &s->iomem);
-    kvm_arm_register_device(&s->iomem,
-                            (KVM_ARM_DEVICE_VGIC_V2 << KVM_ARM_DEVICE_ID_SHIFT)
-                            | KVM_VGIC_V2_ADDR_TYPE_DIST);
-    /* CPU interface for current core. Unlike arm_gic, we don't
-     * provide the "interface for core #N" memory regions, because
-     * cores with a VGIC don't have those.
-     */
-    memory_region_init_reservation(&s->cpuiomem[0], "kvm-gic_cpu", 0x1000);
-    sysbus_init_mmio(sbd, &s->cpuiomem[0]);
-    kvm_arm_register_device(&s->cpuiomem[0],
-                            (KVM_ARM_DEVICE_VGIC_V2 << KVM_ARM_DEVICE_ID_SHIFT)
-                            | KVM_VGIC_V2_ADDR_TYPE_CPU);
-}
-
-static void kvm_arm_gic_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    ARMGICCommonClass *agcc = ARM_GIC_COMMON_CLASS(klass);
-    KVMARMGICClass *kgc = KVM_ARM_GIC_CLASS(klass);
-
-    agcc->pre_save = kvm_arm_gic_get;
-    agcc->post_load = kvm_arm_gic_put;
-    kgc->parent_realize = dc->realize;
-    kgc->parent_reset = dc->reset;
-    dc->realize = kvm_arm_gic_realize;
-    dc->reset = kvm_arm_gic_reset;
-    dc->no_user = 1;
-}
-
-static const TypeInfo kvm_arm_gic_info = {
-    .name = TYPE_KVM_ARM_GIC,
-    .parent = TYPE_ARM_GIC_COMMON,
-    .instance_size = sizeof(GICState),
-    .class_init = kvm_arm_gic_class_init,
-    .class_size = sizeof(KVMARMGICClass),
-};
-
-static void kvm_arm_gic_register_types(void)
-{
-    type_register_static(&kvm_arm_gic_info);
-}
-
-type_init(kvm_arm_gic_register_types)
diff --git a/hw/kvm/clock.c b/hw/kvm/clock.c
deleted file mode 100644 (file)
index fa40e28..0000000
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * QEMU KVM support, paravirtual clock device
- *
- * Copyright (C) 2011 Siemens AG
- *
- * Authors:
- *  Jan Kiszka        <jan.kiszka@siemens.com>
- *
- * This work is licensed under the terms of the GNU GPL version 2.
- * See the COPYING file in the top-level directory.
- *
- * 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/sysemu.h"
-#include "sysemu/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;
-    CPUArchState *penv = first_cpu;
-    int cap_clock_ctrl = kvm_check_extension(kvm_state, KVM_CAP_KVMCLOCK_CTRL);
-    int ret;
-
-    if (running) {
-        s->clock_valid = false;
-
-        if (!cap_clock_ctrl) {
-            return;
-        }
-        for (penv = first_cpu; penv != NULL; penv = penv->next_cpu) {
-            ret = kvm_vcpu_ioctl(ENV_GET_CPU(penv), KVM_KVMCLOCK_CTRL, 0);
-            if (ret) {
-                if (ret != -EINVAL) {
-                    fprintf(stderr, "%s: %s\n", __func__, strerror(-ret));
-                }
-                return;
-            }
-        }
-    }
-}
-
-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 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 const 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. */
-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_types(void)
-{
-    type_register_static(&kvmclock_info);
-}
-
-type_init(kvmclock_register_types)
diff --git a/hw/kvm/clock.h b/hw/kvm/clock.h
deleted file mode 100644 (file)
index 252ea13..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * QEMU KVM support, paravirtual clock device
- *
- * Copyright (C) 2011 Siemens AG
- *
- * Authors:
- *  Jan Kiszka        <jan.kiszka@siemens.com>
- *
- * This work is licensed under the terms of the GNU GPL version 2.
- * See the COPYING file in the top-level directory.
- *
- */
-
-#ifdef CONFIG_KVM
-
-void kvmclock_create(void);
-
-#else /* CONFIG_KVM */
-
-static inline void kvmclock_create(void)
-{
-}
-
-#endif /* !CONFIG_KVM */
diff --git a/hw/kvm/i8254.c b/hw/kvm/i8254.c
deleted file mode 100644 (file)
index 04ad649..0000000
+++ /dev/null
@@ -1,317 +0,0 @@
-/*
- * KVM in-kernel PIT (i8254) support
- *
- * Copyright (c) 2003-2004 Fabrice Bellard
- * Copyright (c) 2012      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 "qemu/timer.h"
-#include "sysemu/sysemu.h"
-#include "hw/i8254.h"
-#include "hw/i8254_internal.h"
-#include "sysemu/kvm.h"
-
-#define KVM_PIT_REINJECT_BIT 0
-
-#define CALIBRATION_ROUNDS   3
-
-typedef struct KVMPITState {
-    PITCommonState pit;
-    LostTickPolicy lost_tick_policy;
-    bool vm_stopped;
-    int64_t kernel_clock_offset;
-} KVMPITState;
-
-static int64_t abs64(int64_t v)
-{
-    return v < 0 ? -v : v;
-}
-
-static void kvm_pit_update_clock_offset(KVMPITState *s)
-{
-    int64_t offset, clock_offset;
-    struct timespec ts;
-    int i;
-
-    /*
-     * Measure the delta between CLOCK_MONOTONIC, the base used for
-     * kvm_pit_channel_state::count_load_time, and vm_clock. Take the
-     * minimum of several samples to filter out scheduling noise.
-     */
-    clock_offset = INT64_MAX;
-    for (i = 0; i < CALIBRATION_ROUNDS; i++) {
-        offset = qemu_get_clock_ns(vm_clock);
-        clock_gettime(CLOCK_MONOTONIC, &ts);
-        offset -= ts.tv_nsec;
-        offset -= (int64_t)ts.tv_sec * 1000000000;
-        if (abs64(offset) < abs64(clock_offset)) {
-            clock_offset = offset;
-        }
-    }
-    s->kernel_clock_offset = clock_offset;
-}
-
-static void kvm_pit_get(PITCommonState *pit)
-{
-    KVMPITState *s = DO_UPCAST(KVMPITState, pit, pit);
-    struct kvm_pit_state2 kpit;
-    struct kvm_pit_channel_state *kchan;
-    struct PITChannelState *sc;
-    int i, ret;
-
-    /* No need to re-read the state if VM is stopped. */
-    if (s->vm_stopped) {
-        return;
-    }
-
-    if (kvm_has_pit_state2()) {
-        ret = kvm_vm_ioctl(kvm_state, KVM_GET_PIT2, &kpit);
-        if (ret < 0) {
-            fprintf(stderr, "KVM_GET_PIT2 failed: %s\n", strerror(ret));
-            abort();
-        }
-        pit->channels[0].irq_disabled = kpit.flags & KVM_PIT_FLAGS_HPET_LEGACY;
-    } else {
-        /*
-         * kvm_pit_state2 is superset of kvm_pit_state struct,
-         * so we can use it for KVM_GET_PIT as well.
-         */
-        ret = kvm_vm_ioctl(kvm_state, KVM_GET_PIT, &kpit);
-        if (ret < 0) {
-            fprintf(stderr, "KVM_GET_PIT failed: %s\n", strerror(ret));
-            abort();
-        }
-    }
-    for (i = 0; i < 3; i++) {
-        kchan = &kpit.channels[i];
-        sc = &pit->channels[i];
-        sc->count = kchan->count;
-        sc->latched_count = kchan->latched_count;
-        sc->count_latched = kchan->count_latched;
-        sc->status_latched = kchan->status_latched;
-        sc->status = kchan->status;
-        sc->read_state = kchan->read_state;
-        sc->write_state = kchan->write_state;
-        sc->write_latch = kchan->write_latch;
-        sc->rw_mode = kchan->rw_mode;
-        sc->mode = kchan->mode;
-        sc->bcd = kchan->bcd;
-        sc->gate = kchan->gate;
-        sc->count_load_time = kchan->count_load_time + s->kernel_clock_offset;
-    }
-
-    sc = &pit->channels[0];
-    sc->next_transition_time =
-        pit_get_next_transition_time(sc, sc->count_load_time);
-}
-
-static void kvm_pit_put(PITCommonState *pit)
-{
-    KVMPITState *s = DO_UPCAST(KVMPITState, pit, pit);
-    struct kvm_pit_state2 kpit;
-    struct kvm_pit_channel_state *kchan;
-    struct PITChannelState *sc;
-    int i, ret;
-
-    /* The offset keeps changing as long as the VM is stopped. */
-    if (s->vm_stopped) {
-        kvm_pit_update_clock_offset(s);
-    }
-
-    kpit.flags = pit->channels[0].irq_disabled ? KVM_PIT_FLAGS_HPET_LEGACY : 0;
-    for (i = 0; i < 3; i++) {
-        kchan = &kpit.channels[i];
-        sc = &pit->channels[i];
-        kchan->count = sc->count;
-        kchan->latched_count = sc->latched_count;
-        kchan->count_latched = sc->count_latched;
-        kchan->status_latched = sc->status_latched;
-        kchan->status = sc->status;
-        kchan->read_state = sc->read_state;
-        kchan->write_state = sc->write_state;
-        kchan->write_latch = sc->write_latch;
-        kchan->rw_mode = sc->rw_mode;
-        kchan->mode = sc->mode;
-        kchan->bcd = sc->bcd;
-        kchan->gate = sc->gate;
-        kchan->count_load_time = sc->count_load_time - s->kernel_clock_offset;
-    }
-
-    ret = kvm_vm_ioctl(kvm_state,
-                       kvm_has_pit_state2() ? KVM_SET_PIT2 : KVM_SET_PIT,
-                       &kpit);
-    if (ret < 0) {
-        fprintf(stderr, "%s failed: %s\n",
-                kvm_has_pit_state2() ? "KVM_SET_PIT2" : "KVM_SET_PIT",
-                strerror(ret));
-        abort();
-    }
-}
-
-static void kvm_pit_set_gate(PITCommonState *s, PITChannelState *sc, int val)
-{
-    kvm_pit_get(s);
-
-    switch (sc->mode) {
-    default:
-    case 0:
-    case 4:
-        /* XXX: just disable/enable counting */
-        break;
-    case 1:
-    case 2:
-    case 3:
-    case 5:
-        if (sc->gate < val) {
-            /* restart counting on rising edge */
-            sc->count_load_time = qemu_get_clock_ns(vm_clock);
-        }
-        break;
-    }
-    sc->gate = val;
-
-    kvm_pit_put(s);
-}
-
-static void kvm_pit_get_channel_info(PITCommonState *s, PITChannelState *sc,
-                                     PITChannelInfo *info)
-{
-    kvm_pit_get(s);
-
-    pit_get_channel_info_common(s, sc, info);
-}
-
-static void kvm_pit_reset(DeviceState *dev)
-{
-    PITCommonState *s = DO_UPCAST(PITCommonState, dev.qdev, dev);
-
-    pit_reset_common(s);
-
-    kvm_pit_put(s);
-}
-
-static void kvm_pit_irq_control(void *opaque, int n, int enable)
-{
-    PITCommonState *pit = opaque;
-    PITChannelState *s = &pit->channels[0];
-
-    kvm_pit_get(pit);
-
-    s->irq_disabled = !enable;
-
-    kvm_pit_put(pit);
-}
-
-static void kvm_pit_vm_state_change(void *opaque, int running,
-                                    RunState state)
-{
-    KVMPITState *s = opaque;
-
-    if (running) {
-        kvm_pit_update_clock_offset(s);
-        s->vm_stopped = false;
-    } else {
-        kvm_pit_update_clock_offset(s);
-        kvm_pit_get(&s->pit);
-        s->vm_stopped = true;
-    }
-}
-
-static int kvm_pit_initfn(PITCommonState *pit)
-{
-    KVMPITState *s = DO_UPCAST(KVMPITState, pit, pit);
-    struct kvm_pit_config config = {
-        .flags = 0,
-    };
-    int ret;
-
-    if (kvm_check_extension(kvm_state, KVM_CAP_PIT2)) {
-        ret = kvm_vm_ioctl(kvm_state, KVM_CREATE_PIT2, &config);
-    } else {
-        ret = kvm_vm_ioctl(kvm_state, KVM_CREATE_PIT);
-    }
-    if (ret < 0) {
-        fprintf(stderr, "Create kernel PIC irqchip failed: %s\n",
-                strerror(ret));
-        return ret;
-    }
-    switch (s->lost_tick_policy) {
-    case LOST_TICK_DELAY:
-        break; /* enabled by default */
-    case LOST_TICK_DISCARD:
-        if (kvm_check_extension(kvm_state, KVM_CAP_REINJECT_CONTROL)) {
-            struct kvm_reinject_control control = { .pit_reinject = 0 };
-
-            ret = kvm_vm_ioctl(kvm_state, KVM_REINJECT_CONTROL, &control);
-            if (ret < 0) {
-                fprintf(stderr,
-                        "Can't disable in-kernel PIT reinjection: %s\n",
-                        strerror(ret));
-                return ret;
-            }
-        }
-        break;
-    default:
-        return -EINVAL;
-    }
-
-    memory_region_init_reservation(&pit->ioports, "kvm-pit", 4);
-
-    qdev_init_gpio_in(&pit->dev.qdev, kvm_pit_irq_control, 1);
-
-    qemu_add_vm_change_state_handler(kvm_pit_vm_state_change, s);
-
-    return 0;
-}
-
-static Property kvm_pit_properties[] = {
-    DEFINE_PROP_HEX32("iobase", KVMPITState, pit.iobase,  -1),
-    DEFINE_PROP_LOSTTICKPOLICY("lost_tick_policy", KVMPITState,
-                               lost_tick_policy, LOST_TICK_DELAY),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void kvm_pit_class_init(ObjectClass *klass, void *data)
-{
-    PITCommonClass *k = PIT_COMMON_CLASS(klass);
-    DeviceClass *dc = DEVICE_CLASS(klass);
-
-    k->init = kvm_pit_initfn;
-    k->set_channel_gate = kvm_pit_set_gate;
-    k->get_channel_info = kvm_pit_get_channel_info;
-    k->pre_save = kvm_pit_get;
-    k->post_load = kvm_pit_put;
-    dc->reset = kvm_pit_reset;
-    dc->props = kvm_pit_properties;
-}
-
-static const TypeInfo kvm_pit_info = {
-    .name          = "kvm-pit",
-    .parent        = TYPE_PIT_COMMON,
-    .instance_size = sizeof(KVMPITState),
-    .class_init = kvm_pit_class_init,
-};
-
-static void kvm_pit_register(void)
-{
-    type_register_static(&kvm_pit_info);
-}
-
-type_init(kvm_pit_register)
diff --git a/hw/kvm/i8259.c b/hw/kvm/i8259.c
deleted file mode 100644 (file)
index 5ae8b68..0000000
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * KVM in-kernel PIC (i8259) support
- *
- * Copyright (c) 2011 Siemens AG
- *
- * Authors:
- *  Jan Kiszka          <jan.kiszka@siemens.com>
- *
- * This work is licensed under the terms of the GNU GPL version 2.
- * See the COPYING file in the top-level directory.
- */
-#include "hw/i8259_internal.h"
-#include "hw/apic_internal.h"
-#include "sysemu/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);
-
-    s->elcr = 0;
-    pic_reset_common(s);
-
-    kvm_pic_put(s);
-}
-
-static void kvm_pic_set_irq(void *opaque, int irq, int level)
-{
-    int delivered;
-
-    delivered = kvm_set_irq(kvm_state, irq, level);
-    apic_report_irq_delivered(delivered);
-}
-
-static void kvm_pic_init(PICCommonState *s)
-{
-    memory_region_init_reservation(&s->base_io, "kvm-pic", 2);
-    memory_region_init_reservation(&s->elcr_io, "kvm-elcr", 1);
-}
-
-qemu_irq *kvm_i8259_init(ISABus *bus)
-{
-    i8259_init_chip("kvm-i8259", bus, true);
-    i8259_init_chip("kvm-i8259", bus, false);
-
-    return qemu_allocate_irqs(kvm_pic_set_irq, NULL, ISA_NUM_IRQS);
-}
-
-static void kvm_i8259_class_init(ObjectClass *klass, void *data)
-{
-    PICCommonClass *k = PIC_COMMON_CLASS(klass);
-    DeviceClass *dc = DEVICE_CLASS(klass);
-
-    dc->reset     = kvm_pic_reset;
-    k->init       = kvm_pic_init;
-    k->pre_save   = kvm_pic_get;
-    k->post_load  = kvm_pic_put;
-}
-
-static const TypeInfo kvm_i8259_info = {
-    .name  = "kvm-i8259",
-    .parent = TYPE_PIC_COMMON,
-    .instance_size = sizeof(PICCommonState),
-    .class_init = kvm_i8259_class_init,
-};
-
-static void kvm_pic_register_types(void)
-{
-    type_register_static(&kvm_i8259_info);
-}
-
-type_init(kvm_pic_register_types)
diff --git a/hw/kvm/ioapic.c b/hw/kvm/ioapic.c
deleted file mode 100644 (file)
index 23877d4..0000000
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * KVM in-kernel IOPIC support
- *
- * Copyright (c) 2011 Siemens AG
- *
- * Authors:
- *  Jan Kiszka          <jan.kiszka@siemens.com>
- *
- * This work is licensed under the terms of the GNU GPL version 2.
- * See the COPYING file in the top-level directory.
- */
-
-#include "hw/pc.h"
-#include "hw/ioapic_internal.h"
-#include "hw/apic_internal.h"
-#include "sysemu/kvm.h"
-
-/* PC Utility function */
-void kvm_pc_setup_irq_routing(bool pci_enabled)
-{
-    KVMState *s = kvm_state;
-    int i;
-
-    if (kvm_check_extension(s, KVM_CAP_IRQ_ROUTING)) {
-        for (i = 0; i < 8; ++i) {
-            if (i == 2) {
-                continue;
-            }
-            kvm_irqchip_add_irq_route(s, i, KVM_IRQCHIP_PIC_MASTER, i);
-        }
-        for (i = 8; i < 16; ++i) {
-            kvm_irqchip_add_irq_route(s, i, KVM_IRQCHIP_PIC_SLAVE, i - 8);
-        }
-        if (pci_enabled) {
-            for (i = 0; i < 24; ++i) {
-                if (i == 0) {
-                    kvm_irqchip_add_irq_route(s, i, KVM_IRQCHIP_IOAPIC, 2);
-                } else if (i != 2) {
-                    kvm_irqchip_add_irq_route(s, i, KVM_IRQCHIP_IOAPIC, i);
-                }
-            }
-        }
-    }
-}
-
-void kvm_pc_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);
-    }
-}
-
-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_set_irq(kvm_state, s->kvm_gsi_base + irq, level);
-    apic_report_irq_delivered(delivered);
-}
-
-static void kvm_ioapic_init(IOAPICCommonState *s, int instance_no)
-{
-    memory_region_init_reservation(&s->io_memory, "kvm-ioapic", 0x1000);
-
-    qdev_init_gpio_in(&s->busdev.qdev, kvm_ioapic_set_irq, IOAPIC_NUM_PINS);
-}
-
-static Property kvm_ioapic_properties[] = {
-    DEFINE_PROP_UINT32("gsi_base", KVMIOAPICState, kvm_gsi_base, 0),
-    DEFINE_PROP_END_OF_LIST()
-};
-
-static void kvm_ioapic_class_init(ObjectClass *klass, void *data)
-{
-    IOAPICCommonClass *k = IOAPIC_COMMON_CLASS(klass);
-    DeviceClass *dc = DEVICE_CLASS(klass);
-
-    k->init      = kvm_ioapic_init;
-    k->pre_save  = kvm_ioapic_get;
-    k->post_load = kvm_ioapic_put;
-    dc->reset    = kvm_ioapic_reset;
-    dc->props    = kvm_ioapic_properties;
-}
-
-static const TypeInfo kvm_ioapic_info = {
-    .name  = "kvm-ioapic",
-    .parent = TYPE_IOAPIC_COMMON,
-    .instance_size = sizeof(KVMIOAPICState),
-    .class_init = kvm_ioapic_class_init,
-};
-
-static void kvm_ioapic_register_types(void)
-{
-    type_register_static(&kvm_ioapic_info);
-}
-
-type_init(kvm_ioapic_register_types)
diff --git a/hw/kvm/pci-assign.c b/hw/kvm/pci-assign.c
deleted file mode 100644 (file)
index da64b5b..0000000
+++ /dev/null
@@ -1,1924 +0,0 @@
-/*
- * Copyright (c) 2007, Neocleus Corporation.
- *
- * This work is licensed under the terms of the GNU GPL, version 2.  See
- * the COPYING file in the top-level directory.
- *
- *
- *  Assign a PCI device from the host to a guest VM.
- *
- *  This implementation uses the classic device assignment interface of KVM
- *  and is only available on x86 hosts. It is expected to be obsoleted by VFIO
- *  based device assignment.
- *
- *  Adapted for KVM (qemu-kvm) by Qumranet. QEMU version was based on qemu-kvm
- *  revision 4144fe9d48. See its repository for the history.
- *
- *  Copyright (c) 2007, Neocleus, Alex Novik (alex@neocleus.com)
- *  Copyright (c) 2007, Neocleus, Guy Zana (guy@neocleus.com)
- *  Copyright (C) 2008, Qumranet, Amit Shah (amit.shah@qumranet.com)
- *  Copyright (C) 2008, Red Hat, Amit Shah (amit.shah@redhat.com)
- *  Copyright (C) 2008, IBM, Muli Ben-Yehuda (muli@il.ibm.com)
- */
-#include <stdio.h>
-#include <unistd.h>
-#include <sys/io.h>
-#include <sys/mman.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include "hw/hw.h"
-#include "hw/pc.h"
-#include "qemu/error-report.h"
-#include "ui/console.h"
-#include "hw/loader.h"
-#include "monitor/monitor.h"
-#include "qemu/range.h"
-#include "sysemu/sysemu.h"
-#include "hw/pci/pci.h"
-#include "hw/pci/msi.h"
-#include "kvm_i386.h"
-
-#define MSIX_PAGE_SIZE 0x1000
-
-/* From linux/ioport.h */
-#define IORESOURCE_IO       0x00000100  /* Resource type */
-#define IORESOURCE_MEM      0x00000200
-#define IORESOURCE_IRQ      0x00000400
-#define IORESOURCE_DMA      0x00000800
-#define IORESOURCE_PREFETCH 0x00002000  /* No side effects */
-#define IORESOURCE_MEM_64   0x00100000
-
-//#define DEVICE_ASSIGNMENT_DEBUG
-
-#ifdef DEVICE_ASSIGNMENT_DEBUG
-#define DEBUG(fmt, ...)                                       \
-    do {                                                      \
-        fprintf(stderr, "%s: " fmt, __func__ , __VA_ARGS__);  \
-    } while (0)
-#else
-#define DEBUG(fmt, ...)
-#endif
-
-typedef struct PCIRegion {
-    int type;           /* Memory or port I/O */
-    int valid;
-    uint64_t base_addr;
-    uint64_t size;    /* size of the region */
-    int resource_fd;
-} PCIRegion;
-
-typedef struct PCIDevRegions {
-    uint8_t bus, dev, func; /* Bus inside domain, device and function */
-    int irq;                /* IRQ number */
-    uint16_t region_number; /* number of active regions */
-
-    /* Port I/O or MMIO Regions */
-    PCIRegion regions[PCI_NUM_REGIONS - 1];
-    int config_fd;
-} PCIDevRegions;
-
-typedef struct AssignedDevRegion {
-    MemoryRegion container;
-    MemoryRegion real_iomem;
-    union {
-        uint8_t *r_virtbase; /* mmapped access address for memory regions */
-        uint32_t r_baseport; /* the base guest port for I/O regions */
-    } u;
-    pcibus_t e_size;    /* emulated size of region in bytes */
-    pcibus_t r_size;    /* real size of region in bytes */
-    PCIRegion *region;
-} AssignedDevRegion;
-
-#define ASSIGNED_DEVICE_PREFER_MSI_BIT  0
-#define ASSIGNED_DEVICE_SHARE_INTX_BIT  1
-
-#define ASSIGNED_DEVICE_PREFER_MSI_MASK (1 << ASSIGNED_DEVICE_PREFER_MSI_BIT)
-#define ASSIGNED_DEVICE_SHARE_INTX_MASK (1 << ASSIGNED_DEVICE_SHARE_INTX_BIT)
-
-typedef struct MSIXTableEntry {
-    uint32_t addr_lo;
-    uint32_t addr_hi;
-    uint32_t data;
-    uint32_t ctrl;
-} MSIXTableEntry;
-
-typedef enum AssignedIRQType {
-    ASSIGNED_IRQ_NONE = 0,
-    ASSIGNED_IRQ_INTX_HOST_INTX,
-    ASSIGNED_IRQ_INTX_HOST_MSI,
-    ASSIGNED_IRQ_MSI,
-    ASSIGNED_IRQ_MSIX
-} AssignedIRQType;
-
-typedef struct AssignedDevice {
-    PCIDevice dev;
-    PCIHostDeviceAddress host;
-    uint32_t dev_id;
-    uint32_t features;
-    int intpin;
-    AssignedDevRegion v_addrs[PCI_NUM_REGIONS - 1];
-    PCIDevRegions real_device;
-    PCIINTxRoute intx_route;
-    AssignedIRQType assigned_irq_type;
-    struct {
-#define ASSIGNED_DEVICE_CAP_MSI (1 << 0)
-#define ASSIGNED_DEVICE_CAP_MSIX (1 << 1)
-        uint32_t available;
-#define ASSIGNED_DEVICE_MSI_ENABLED (1 << 0)
-#define ASSIGNED_DEVICE_MSIX_ENABLED (1 << 1)
-#define ASSIGNED_DEVICE_MSIX_MASKED (1 << 2)
-        uint32_t state;
-    } cap;
-    uint8_t emulate_config_read[PCI_CONFIG_SPACE_SIZE];
-    uint8_t emulate_config_write[PCI_CONFIG_SPACE_SIZE];
-    int msi_virq_nr;
-    int *msi_virq;
-    MSIXTableEntry *msix_table;
-    hwaddr msix_table_addr;
-    uint16_t msix_max;
-    MemoryRegion mmio;
-    char *configfd_name;
-    int32_t bootindex;
-} AssignedDevice;
-
-static void assigned_dev_update_irq_routing(PCIDevice *dev);
-
-static void assigned_dev_load_option_rom(AssignedDevice *dev);
-
-static void assigned_dev_unregister_msix_mmio(AssignedDevice *dev);
-
-static uint64_t assigned_dev_ioport_rw(AssignedDevRegion *dev_region,
-                                       hwaddr addr, int size,
-                                       uint64_t *data)
-{
-    uint64_t val = 0;
-    int fd = dev_region->region->resource_fd;
-
-    if (fd >= 0) {
-        if (data) {
-            DEBUG("pwrite data=%" PRIx64 ", size=%d, e_phys=" TARGET_FMT_plx
-                  ", addr="TARGET_FMT_plx"\n", *data, size, addr, addr);
-            if (pwrite(fd, data, size, addr) != size) {
-                error_report("%s - pwrite failed %s",
-                             __func__, strerror(errno));
-            }
-        } else {
-            if (pread(fd, &val, size, addr) != size) {
-                error_report("%s - pread failed %s",
-                             __func__, strerror(errno));
-                val = (1UL << (size * 8)) - 1;
-            }
-            DEBUG("pread val=%" PRIx64 ", size=%d, e_phys=" TARGET_FMT_plx
-                  ", addr=" TARGET_FMT_plx "\n", val, size, addr, addr);
-        }
-    } else {
-        uint32_t port = addr + dev_region->u.r_baseport;
-
-        if (data) {
-            DEBUG("out data=%" PRIx64 ", size=%d, e_phys=" TARGET_FMT_plx
-                  ", host=%x\n", *data, size, addr, port);
-            switch (size) {
-            case 1:
-                outb(*data, port);
-                break;
-            case 2:
-                outw(*data, port);
-                break;
-            case 4:
-                outl(*data, port);
-                break;
-            }
-        } else {
-            switch (size) {
-            case 1:
-                val = inb(port);
-                break;
-            case 2:
-                val = inw(port);
-                break;
-            case 4:
-                val = inl(port);
-                break;
-            }
-            DEBUG("in data=%" PRIx64 ", size=%d, e_phys=" TARGET_FMT_plx
-                  ", host=%x\n", val, size, addr, port);
-        }
-    }
-    return val;
-}
-
-static void assigned_dev_ioport_write(void *opaque, hwaddr addr,
-                                      uint64_t data, unsigned size)
-{
-    assigned_dev_ioport_rw(opaque, addr, size, &data);
-}
-
-static uint64_t assigned_dev_ioport_read(void *opaque,
-                                         hwaddr addr, unsigned size)
-{
-    return assigned_dev_ioport_rw(opaque, addr, size, NULL);
-}
-
-static uint32_t slow_bar_readb(void *opaque, hwaddr addr)
-{
-    AssignedDevRegion *d = opaque;
-    uint8_t *in = d->u.r_virtbase + addr;
-    uint32_t r;
-
-    r = *in;
-    DEBUG("slow_bar_readl addr=0x" TARGET_FMT_plx " val=0x%08x\n", addr, r);
-
-    return r;
-}
-
-static uint32_t slow_bar_readw(void *opaque, hwaddr addr)
-{
-    AssignedDevRegion *d = opaque;
-    uint16_t *in = (uint16_t *)(d->u.r_virtbase + addr);
-    uint32_t r;
-
-    r = *in;
-    DEBUG("slow_bar_readl addr=0x" TARGET_FMT_plx " val=0x%08x\n", addr, r);
-
-    return r;
-}
-
-static uint32_t slow_bar_readl(void *opaque, hwaddr addr)
-{
-    AssignedDevRegion *d = opaque;
-    uint32_t *in = (uint32_t *)(d->u.r_virtbase + addr);
-    uint32_t r;
-
-    r = *in;
-    DEBUG("slow_bar_readl addr=0x" TARGET_FMT_plx " val=0x%08x\n", addr, r);
-
-    return r;
-}
-
-static void slow_bar_writeb(void *opaque, hwaddr addr, uint32_t val)
-{
-    AssignedDevRegion *d = opaque;
-    uint8_t *out = d->u.r_virtbase + addr;
-
-    DEBUG("slow_bar_writeb addr=0x" TARGET_FMT_plx " val=0x%02x\n", addr, val);
-    *out = val;
-}
-
-static void slow_bar_writew(void *opaque, hwaddr addr, uint32_t val)
-{
-    AssignedDevRegion *d = opaque;
-    uint16_t *out = (uint16_t *)(d->u.r_virtbase + addr);
-
-    DEBUG("slow_bar_writew addr=0x" TARGET_FMT_plx " val=0x%04x\n", addr, val);
-    *out = val;
-}
-
-static void slow_bar_writel(void *opaque, hwaddr addr, uint32_t val)
-{
-    AssignedDevRegion *d = opaque;
-    uint32_t *out = (uint32_t *)(d->u.r_virtbase + addr);
-
-    DEBUG("slow_bar_writel addr=0x" TARGET_FMT_plx " val=0x%08x\n", addr, val);
-    *out = val;
-}
-
-static const MemoryRegionOps slow_bar_ops = {
-    .old_mmio = {
-        .read = { slow_bar_readb, slow_bar_readw, slow_bar_readl, },
-        .write = { slow_bar_writeb, slow_bar_writew, slow_bar_writel, },
-    },
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void assigned_dev_iomem_setup(PCIDevice *pci_dev, int region_num,
-                                     pcibus_t e_size)
-{
-    AssignedDevice *r_dev = DO_UPCAST(AssignedDevice, dev, pci_dev);
-    AssignedDevRegion *region = &r_dev->v_addrs[region_num];
-    PCIRegion *real_region = &r_dev->real_device.regions[region_num];
-
-    if (e_size > 0) {
-        memory_region_init(&region->container, "assigned-dev-container",
-                           e_size);
-        memory_region_add_subregion(&region->container, 0, &region->real_iomem);
-
-        /* deal with MSI-X MMIO page */
-        if (real_region->base_addr <= r_dev->msix_table_addr &&
-                real_region->base_addr + real_region->size >
-                r_dev->msix_table_addr) {
-            uint64_t offset = r_dev->msix_table_addr - real_region->base_addr;
-
-            memory_region_add_subregion_overlap(&region->container,
-                                                offset,
-                                                &r_dev->mmio,
-                                                1);
-        }
-    }
-}
-
-static const MemoryRegionOps assigned_dev_ioport_ops = {
-    .read = assigned_dev_ioport_read,
-    .write = assigned_dev_ioport_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void assigned_dev_ioport_setup(PCIDevice *pci_dev, int region_num,
-                                      pcibus_t size)
-{
-    AssignedDevice *r_dev = DO_UPCAST(AssignedDevice, dev, pci_dev);
-    AssignedDevRegion *region = &r_dev->v_addrs[region_num];
-
-    region->e_size = size;
-    memory_region_init(&region->container, "assigned-dev-container", size);
-    memory_region_init_io(&region->real_iomem, &assigned_dev_ioport_ops,
-                          r_dev->v_addrs + region_num,
-                          "assigned-dev-iomem", size);
-    memory_region_add_subregion(&region->container, 0, &region->real_iomem);
-}
-
-static uint32_t assigned_dev_pci_read(PCIDevice *d, int pos, int len)
-{
-    AssignedDevice *pci_dev = DO_UPCAST(AssignedDevice, dev, d);
-    uint32_t val;
-    ssize_t ret;
-    int fd = pci_dev->real_device.config_fd;
-
-again:
-    ret = pread(fd, &val, len, pos);
-    if (ret != len) {
-        if ((ret < 0) && (errno == EINTR || errno == EAGAIN)) {
-            goto again;
-        }
-
-        hw_error("pci read failed, ret = %zd errno = %d\n", ret, errno);
-    }
-
-    return val;
-}
-
-static uint8_t assigned_dev_pci_read_byte(PCIDevice *d, int pos)
-{
-    return (uint8_t)assigned_dev_pci_read(d, pos, 1);
-}
-
-static void assigned_dev_pci_write(PCIDevice *d, int pos, uint32_t val, int len)
-{
-    AssignedDevice *pci_dev = DO_UPCAST(AssignedDevice, dev, d);
-    ssize_t ret;
-    int fd = pci_dev->real_device.config_fd;
-
-again:
-    ret = pwrite(fd, &val, len, pos);
-    if (ret != len) {
-        if ((ret < 0) && (errno == EINTR || errno == EAGAIN)) {
-            goto again;
-        }
-
-        hw_error("pci write failed, ret = %zd errno = %d\n", ret, errno);
-    }
-}
-
-static void assigned_dev_emulate_config_read(AssignedDevice *dev,
-                                             uint32_t offset, uint32_t len)
-{
-    memset(dev->emulate_config_read + offset, 0xff, len);
-}
-
-static void assigned_dev_direct_config_read(AssignedDevice *dev,
-                                            uint32_t offset, uint32_t len)
-{
-    memset(dev->emulate_config_read + offset, 0, len);
-}
-
-static void assigned_dev_direct_config_write(AssignedDevice *dev,
-                                             uint32_t offset, uint32_t len)
-{
-    memset(dev->emulate_config_write + offset, 0, len);
-}
-
-static uint8_t pci_find_cap_offset(PCIDevice *d, uint8_t cap, uint8_t start)
-{
-    int id;
-    int max_cap = 48;
-    int pos = start ? start : PCI_CAPABILITY_LIST;
-    int status;
-
-    status = assigned_dev_pci_read_byte(d, PCI_STATUS);
-    if ((status & PCI_STATUS_CAP_LIST) == 0) {
-        return 0;
-    }
-
-    while (max_cap--) {
-        pos = assigned_dev_pci_read_byte(d, pos);
-        if (pos < 0x40) {
-            break;
-        }
-
-        pos &= ~3;
-        id = assigned_dev_pci_read_byte(d, pos + PCI_CAP_LIST_ID);
-
-        if (id == 0xff) {
-            break;
-        }
-        if (id == cap) {
-            return pos;
-        }
-
-        pos += PCI_CAP_LIST_NEXT;
-    }
-    return 0;
-}
-
-static int assigned_dev_register_regions(PCIRegion *io_regions,
-                                         unsigned long regions_num,
-                                         AssignedDevice *pci_dev)
-{
-    uint32_t i;
-    PCIRegion *cur_region = io_regions;
-
-    for (i = 0; i < regions_num; i++, cur_region++) {
-        if (!cur_region->valid) {
-            continue;
-        }
-
-        /* handle memory io regions */
-        if (cur_region->type & IORESOURCE_MEM) {
-            int t = PCI_BASE_ADDRESS_SPACE_MEMORY;
-            if (cur_region->type & IORESOURCE_PREFETCH) {
-                t |= PCI_BASE_ADDRESS_MEM_PREFETCH;
-            }
-            if (cur_region->type & IORESOURCE_MEM_64) {
-                t |= PCI_BASE_ADDRESS_MEM_TYPE_64;
-            }
-
-            /* map physical memory */
-            pci_dev->v_addrs[i].u.r_virtbase = mmap(NULL, cur_region->size,
-                                                    PROT_WRITE | PROT_READ,
-                                                    MAP_SHARED,
-                                                    cur_region->resource_fd,
-                                                    (off_t)0);
-
-            if (pci_dev->v_addrs[i].u.r_virtbase == MAP_FAILED) {
-                pci_dev->v_addrs[i].u.r_virtbase = NULL;
-                error_report("%s: Error: Couldn't mmap 0x%" PRIx64 "!",
-                             __func__, cur_region->base_addr);
-                return -1;
-            }
-
-            pci_dev->v_addrs[i].r_size = cur_region->size;
-            pci_dev->v_addrs[i].e_size = 0;
-
-            /* add offset */
-            pci_dev->v_addrs[i].u.r_virtbase +=
-                (cur_region->base_addr & 0xFFF);
-
-            if (cur_region->size & 0xFFF) {
-                error_report("PCI region %d at address 0x%" PRIx64 " has "
-                             "size 0x%" PRIx64 ", which is not a multiple of "
-                             "4K.  You might experience some performance hit "
-                             "due to that.",
-                             i, cur_region->base_addr, cur_region->size);
-                memory_region_init_io(&pci_dev->v_addrs[i].real_iomem,
-                                      &slow_bar_ops, &pci_dev->v_addrs[i],
-                                      "assigned-dev-slow-bar",
-                                      cur_region->size);
-            } else {
-                void *virtbase = pci_dev->v_addrs[i].u.r_virtbase;
-                char name[32];
-                snprintf(name, sizeof(name), "%s.bar%d",
-                         object_get_typename(OBJECT(pci_dev)), i);
-                memory_region_init_ram_ptr(&pci_dev->v_addrs[i].real_iomem,
-                                           name, cur_region->size,
-                                           virtbase);
-                vmstate_register_ram(&pci_dev->v_addrs[i].real_iomem,
-                                     &pci_dev->dev.qdev);
-            }
-
-            assigned_dev_iomem_setup(&pci_dev->dev, i, cur_region->size);
-            pci_register_bar((PCIDevice *) pci_dev, i, t,
-                             &pci_dev->v_addrs[i].container);
-            continue;
-        } else {
-            /* handle port io regions */
-            uint32_t val;
-            int ret;
-
-            /* Test kernel support for ioport resource read/write.  Old
-             * kernels return EIO.  New kernels only allow 1/2/4 byte reads
-             * so should return EINVAL for a 3 byte read */
-            ret = pread(pci_dev->v_addrs[i].region->resource_fd, &val, 3, 0);
-            if (ret >= 0) {
-                error_report("Unexpected return from I/O port read: %d", ret);
-                abort();
-            } else if (errno != EINVAL) {
-                error_report("Kernel doesn't support ioport resource "
-                             "access, hiding this region.");
-                close(pci_dev->v_addrs[i].region->resource_fd);
-                cur_region->valid = 0;
-                continue;
-            }
-
-            pci_dev->v_addrs[i].u.r_baseport = cur_region->base_addr;
-            pci_dev->v_addrs[i].r_size = cur_region->size;
-            pci_dev->v_addrs[i].e_size = 0;
-
-            assigned_dev_ioport_setup(&pci_dev->dev, i, cur_region->size);
-            pci_register_bar((PCIDevice *) pci_dev, i,
-                             PCI_BASE_ADDRESS_SPACE_IO,
-                             &pci_dev->v_addrs[i].container);
-        }
-    }
-
-    /* success */
-    return 0;
-}
-
-static int get_real_id(const char *devpath, const char *idname, uint16_t *val)
-{
-    FILE *f;
-    char name[128];
-    long id;
-
-    snprintf(name, sizeof(name), "%s%s", devpath, idname);
-    f = fopen(name, "r");
-    if (f == NULL) {
-        error_report("%s: %s: %m", __func__, name);
-        return -1;
-    }
-    if (fscanf(f, "%li\n", &id) == 1) {
-        *val = id;
-    } else {
-        return -1;
-    }
-    fclose(f);
-
-    return 0;
-}
-
-static int get_real_vendor_id(const char *devpath, uint16_t *val)
-{
-    return get_real_id(devpath, "vendor", val);
-}
-
-static int get_real_device_id(const char *devpath, uint16_t *val)
-{
-    return get_real_id(devpath, "device", val);
-}
-
-static int get_real_device(AssignedDevice *pci_dev, uint16_t r_seg,
-                           uint8_t r_bus, uint8_t r_dev, uint8_t r_func)
-{
-    char dir[128], name[128];
-    int fd, r = 0, v;
-    FILE *f;
-    uint64_t start, end, size, flags;
-    uint16_t id;
-    PCIRegion *rp;
-    PCIDevRegions *dev = &pci_dev->real_device;
-
-    dev->region_number = 0;
-
-    snprintf(dir, sizeof(dir), "/sys/bus/pci/devices/%04x:%02x:%02x.%x/",
-             r_seg, r_bus, r_dev, r_func);
-
-    snprintf(name, sizeof(name), "%sconfig", dir);
-
-    if (pci_dev->configfd_name && *pci_dev->configfd_name) {
-        dev->config_fd = monitor_handle_fd_param(cur_mon, pci_dev->configfd_name);
-        if (dev->config_fd < 0) {
-            return 1;
-        }
-    } else {
-        dev->config_fd = open(name, O_RDWR);
-
-        if (dev->config_fd == -1) {
-            error_report("%s: %s: %m", __func__, name);
-            return 1;
-        }
-    }
-again:
-    r = read(dev->config_fd, pci_dev->dev.config,
-             pci_config_size(&pci_dev->dev));
-    if (r < 0) {
-        if (errno == EINTR || errno == EAGAIN) {
-            goto again;
-        }
-        error_report("%s: read failed, errno = %d", __func__, errno);
-    }
-
-    /* Restore or clear multifunction, this is always controlled by qemu */
-    if (pci_dev->dev.cap_present & QEMU_PCI_CAP_MULTIFUNCTION) {
-        pci_dev->dev.config[PCI_HEADER_TYPE] |= PCI_HEADER_TYPE_MULTI_FUNCTION;
-    } else {
-        pci_dev->dev.config[PCI_HEADER_TYPE] &= ~PCI_HEADER_TYPE_MULTI_FUNCTION;
-    }
-
-    /* Clear host resource mapping info.  If we choose not to register a
-     * BAR, such as might be the case with the option ROM, we can get
-     * confusing, unwritable, residual addresses from the host here. */
-    memset(&pci_dev->dev.config[PCI_BASE_ADDRESS_0], 0, 24);
-    memset(&pci_dev->dev.config[PCI_ROM_ADDRESS], 0, 4);
-
-    snprintf(name, sizeof(name), "%sresource", dir);
-
-    f = fopen(name, "r");
-    if (f == NULL) {
-        error_report("%s: %s: %m", __func__, name);
-        return 1;
-    }
-
-    for (r = 0; r < PCI_ROM_SLOT; r++) {
-        if (fscanf(f, "%" SCNi64 " %" SCNi64 " %" SCNi64 "\n",
-                   &start, &end, &flags) != 3) {
-            break;
-        }
-
-        rp = dev->regions + r;
-        rp->valid = 0;
-        rp->resource_fd = -1;
-        size = end - start + 1;
-        flags &= IORESOURCE_IO | IORESOURCE_MEM | IORESOURCE_PREFETCH
-                 | IORESOURCE_MEM_64;
-        if (size == 0 || (flags & ~IORESOURCE_PREFETCH) == 0) {
-            continue;
-        }
-        if (flags & IORESOURCE_MEM) {
-            flags &= ~IORESOURCE_IO;
-        } else {
-            flags &= ~IORESOURCE_PREFETCH;
-        }
-        snprintf(name, sizeof(name), "%sresource%d", dir, r);
-        fd = open(name, O_RDWR);
-        if (fd == -1) {
-            continue;
-        }
-        rp->resource_fd = fd;
-
-        rp->type = flags;
-        rp->valid = 1;
-        rp->base_addr = start;
-        rp->size = size;
-        pci_dev->v_addrs[r].region = rp;
-        DEBUG("region %d size %" PRIu64 " start 0x%" PRIx64
-              " type %d resource_fd %d\n",
-              r, rp->size, start, rp->type, rp->resource_fd);
-    }
-
-    fclose(f);
-
-    /* read and fill vendor ID */
-    v = get_real_vendor_id(dir, &id);
-    if (v) {
-        return 1;
-    }
-    pci_dev->dev.config[0] = id & 0xff;
-    pci_dev->dev.config[1] = (id & 0xff00) >> 8;
-
-    /* read and fill device ID */
-    v = get_real_device_id(dir, &id);
-    if (v) {
-        return 1;
-    }
-    pci_dev->dev.config[2] = id & 0xff;
-    pci_dev->dev.config[3] = (id & 0xff00) >> 8;
-
-    pci_word_test_and_clear_mask(pci_dev->emulate_config_write + PCI_COMMAND,
-                                 PCI_COMMAND_MASTER | PCI_COMMAND_INTX_DISABLE);
-
-    dev->region_number = r;
-    return 0;
-}
-
-static void free_msi_virqs(AssignedDevice *dev)
-{
-    int i;
-
-    for (i = 0; i < dev->msi_virq_nr; i++) {
-        if (dev->msi_virq[i] >= 0) {
-            kvm_irqchip_release_virq(kvm_state, dev->msi_virq[i]);
-            dev->msi_virq[i] = -1;
-        }
-    }
-    g_free(dev->msi_virq);
-    dev->msi_virq = NULL;
-    dev->msi_virq_nr = 0;
-}
-
-static void free_assigned_device(AssignedDevice *dev)
-{
-    int i;
-
-    if (dev->cap.available & ASSIGNED_DEVICE_CAP_MSIX) {
-        assigned_dev_unregister_msix_mmio(dev);
-    }
-    for (i = 0; i < dev->real_device.region_number; i++) {
-        PCIRegion *pci_region = &dev->real_device.regions[i];
-        AssignedDevRegion *region = &dev->v_addrs[i];
-
-        if (!pci_region->valid) {
-            continue;
-        }
-        if (pci_region->type & IORESOURCE_IO) {
-            if (region->u.r_baseport) {
-                memory_region_del_subregion(&region->container,
-                                            &region->real_iomem);
-                memory_region_destroy(&region->real_iomem);
-                memory_region_destroy(&region->container);
-            }
-        } else if (pci_region->type & IORESOURCE_MEM) {
-            if (region->u.r_virtbase) {
-                memory_region_del_subregion(&region->container,
-                                            &region->real_iomem);
-
-                /* Remove MSI-X table subregion */
-                if (pci_region->base_addr <= dev->msix_table_addr &&
-                    pci_region->base_addr + pci_region->size >
-                    dev->msix_table_addr) {
-                    memory_region_del_subregion(&region->container,
-                                                &dev->mmio);
-                }
-
-                memory_region_destroy(&region->real_iomem);
-                memory_region_destroy(&region->container);
-                if (munmap(region->u.r_virtbase,
-                           (pci_region->size + 0xFFF) & 0xFFFFF000)) {
-                    error_report("Failed to unmap assigned device region: %s",
-                                 strerror(errno));
-                }
-            }
-        }
-        if (pci_region->resource_fd >= 0) {
-            close(pci_region->resource_fd);
-        }
-    }
-
-    if (dev->real_device.config_fd >= 0) {
-        close(dev->real_device.config_fd);
-    }
-
-    free_msi_virqs(dev);
-}
-
-static void assign_failed_examine(AssignedDevice *dev)
-{
-    char name[PATH_MAX], dir[PATH_MAX], driver[PATH_MAX] = {}, *ns;
-    uint16_t vendor_id, device_id;
-    int r;
-
-    snprintf(dir, sizeof(dir), "/sys/bus/pci/devices/%04x:%02x:%02x.%01x/",
-            dev->host.domain, dev->host.bus, dev->host.slot,
-            dev->host.function);
-
-    snprintf(name, sizeof(name), "%sdriver", dir);
-
-    r = readlink(name, driver, sizeof(driver));
-    if ((r <= 0) || r >= sizeof(driver)) {
-        goto fail;
-    }
-
-    ns = strrchr(driver, '/');
-    if (!ns) {
-        goto fail;
-    }
-
-    ns++;
-
-    if (get_real_vendor_id(dir, &vendor_id) ||
-        get_real_device_id(dir, &device_id)) {
-        goto fail;
-    }
-
-    error_report("*** The driver '%s' is occupying your device "
-                 "%04x:%02x:%02x.%x.",
-                 ns, dev->host.domain, dev->host.bus, dev->host.slot,
-                 dev->host.function);
-    error_report("***");
-    error_report("*** You can try the following commands to free it:");
-    error_report("***");
-    error_report("*** $ echo \"%04x %04x\" > /sys/bus/pci/drivers/pci-stub/"
-                 "new_id", vendor_id, device_id);
-    error_report("*** $ echo \"%04x:%02x:%02x.%x\" > /sys/bus/pci/drivers/"
-                 "%s/unbind",
-                 dev->host.domain, dev->host.bus, dev->host.slot,
-                 dev->host.function, ns);
-    error_report("*** $ echo \"%04x:%02x:%02x.%x\" > /sys/bus/pci/drivers/"
-                 "pci-stub/bind",
-                 dev->host.domain, dev->host.bus, dev->host.slot,
-                 dev->host.function);
-    error_report("*** $ echo \"%04x %04x\" > /sys/bus/pci/drivers/pci-stub"
-                 "/remove_id", vendor_id, device_id);
-    error_report("***");
-
-    return;
-
-fail:
-    error_report("Couldn't find out why.");
-}
-
-static int assign_device(AssignedDevice *dev)
-{
-    uint32_t flags = KVM_DEV_ASSIGN_ENABLE_IOMMU;
-    int r;
-
-    /* Only pass non-zero PCI segment to capable module */
-    if (!kvm_check_extension(kvm_state, KVM_CAP_PCI_SEGMENT) &&
-        dev->host.domain) {
-        error_report("Can't assign device inside non-zero PCI segment "
-                     "as this KVM module doesn't support it.");
-        return -ENODEV;
-    }
-
-    if (!kvm_check_extension(kvm_state, KVM_CAP_IOMMU)) {
-        error_report("No IOMMU found.  Unable to assign device \"%s\"",
-                     dev->dev.qdev.id);
-        return -ENODEV;
-    }
-
-    if (dev->features & ASSIGNED_DEVICE_SHARE_INTX_MASK &&
-        kvm_has_intx_set_mask()) {
-        flags |= KVM_DEV_ASSIGN_PCI_2_3;
-    }
-
-    r = kvm_device_pci_assign(kvm_state, &dev->host, flags, &dev->dev_id);
-    if (r < 0) {
-        error_report("Failed to assign device \"%s\" : %s",
-                     dev->dev.qdev.id, strerror(-r));
-
-        switch (r) {
-        case -EBUSY:
-            assign_failed_examine(dev);
-            break;
-        default:
-            break;
-        }
-    }
-    return r;
-}
-
-static bool check_irqchip_in_kernel(void)
-{
-    if (kvm_irqchip_in_kernel()) {
-        return true;
-    }
-    error_report("pci-assign: error: requires KVM with in-kernel irqchip "
-                 "enabled");
-    return false;
-}
-
-static int assign_intx(AssignedDevice *dev)
-{
-    AssignedIRQType new_type;
-    PCIINTxRoute intx_route;
-    bool intx_host_msi;
-    int r;
-
-    /* Interrupt PIN 0 means don't use INTx */
-    if (assigned_dev_pci_read_byte(&dev->dev, PCI_INTERRUPT_PIN) == 0) {
-        pci_device_set_intx_routing_notifier(&dev->dev, NULL);
-        return 0;
-    }
-
-    if (!check_irqchip_in_kernel()) {
-        return -ENOTSUP;
-    }
-
-    pci_device_set_intx_routing_notifier(&dev->dev,
-                                         assigned_dev_update_irq_routing);
-
-    intx_route = pci_device_route_intx_to_irq(&dev->dev, dev->intpin);
-    assert(intx_route.mode != PCI_INTX_INVERTED);
-
-    if (!pci_intx_route_changed(&dev->intx_route, &intx_route)) {
-        return 0;
-    }
-
-    switch (dev->assigned_irq_type) {
-    case ASSIGNED_IRQ_INTX_HOST_INTX:
-    case ASSIGNED_IRQ_INTX_HOST_MSI:
-        intx_host_msi = dev->assigned_irq_type == ASSIGNED_IRQ_INTX_HOST_MSI;
-        r = kvm_device_intx_deassign(kvm_state, dev->dev_id, intx_host_msi);
-        break;
-    case ASSIGNED_IRQ_MSI:
-        r = kvm_device_msi_deassign(kvm_state, dev->dev_id);
-        break;
-    case ASSIGNED_IRQ_MSIX:
-        r = kvm_device_msix_deassign(kvm_state, dev->dev_id);
-        break;
-    default:
-        r = 0;
-        break;
-    }
-    if (r) {
-        perror("assign_intx: deassignment of previous interrupt failed");
-    }
-    dev->assigned_irq_type = ASSIGNED_IRQ_NONE;
-
-    if (intx_route.mode == PCI_INTX_DISABLED) {
-        dev->intx_route = intx_route;
-        return 0;
-    }
-
-retry:
-    if (dev->features & ASSIGNED_DEVICE_PREFER_MSI_MASK &&
-        dev->cap.available & ASSIGNED_DEVICE_CAP_MSI) {
-        intx_host_msi = true;
-        new_type = ASSIGNED_IRQ_INTX_HOST_MSI;
-    } else {
-        intx_host_msi = false;
-        new_type = ASSIGNED_IRQ_INTX_HOST_INTX;
-    }
-
-    r = kvm_device_intx_assign(kvm_state, dev->dev_id, intx_host_msi,
-                               intx_route.irq);
-    if (r < 0) {
-        if (r == -EIO && !(dev->features & ASSIGNED_DEVICE_PREFER_MSI_MASK) &&
-            dev->cap.available & ASSIGNED_DEVICE_CAP_MSI) {
-            /* Retry with host-side MSI. There might be an IRQ conflict and
-             * either the kernel or the device doesn't support sharing. */
-            error_report("Host-side INTx sharing not supported, "
-                         "using MSI instead");
-            error_printf("Some devices do not work properly in this mode.\n");
-            dev->features |= ASSIGNED_DEVICE_PREFER_MSI_MASK;
-            goto retry;
-        }
-        error_report("Failed to assign irq for \"%s\": %s",
-                     dev->dev.qdev.id, strerror(-r));
-        error_report("Perhaps you are assigning a device "
-                     "that shares an IRQ with another device?");
-        return r;
-    }
-
-    dev->intx_route = intx_route;
-    dev->assigned_irq_type = new_type;
-    return r;
-}
-
-static void deassign_device(AssignedDevice *dev)
-{
-    int r;
-
-    r = kvm_device_pci_deassign(kvm_state, dev->dev_id);
-    assert(r == 0);
-}
-
-/* The pci config space got updated. Check if irq numbers have changed
- * for our devices
- */
-static void assigned_dev_update_irq_routing(PCIDevice *dev)
-{
-    AssignedDevice *assigned_dev = DO_UPCAST(AssignedDevice, dev, dev);
-    Error *err = NULL;
-    int r;
-
-    r = assign_intx(assigned_dev);
-    if (r < 0) {
-        qdev_unplug(&dev->qdev, &err);
-        assert(!err);
-    }
-}
-
-static void assigned_dev_update_msi(PCIDevice *pci_dev)
-{
-    AssignedDevice *assigned_dev = DO_UPCAST(AssignedDevice, dev, pci_dev);
-    uint8_t ctrl_byte = pci_get_byte(pci_dev->config + pci_dev->msi_cap +
-                                     PCI_MSI_FLAGS);
-    int r;
-
-    /* Some guests gratuitously disable MSI even if they're not using it,
-     * try to catch this by only deassigning irqs if the guest is using
-     * MSI or intends to start. */
-    if (assigned_dev->assigned_irq_type == ASSIGNED_IRQ_MSI ||
-        (ctrl_byte & PCI_MSI_FLAGS_ENABLE)) {
-        r = kvm_device_msi_deassign(kvm_state, assigned_dev->dev_id);
-        /* -ENXIO means no assigned irq */
-        if (r && r != -ENXIO) {
-            perror("assigned_dev_update_msi: deassign irq");
-        }
-
-        free_msi_virqs(assigned_dev);
-
-        assigned_dev->assigned_irq_type = ASSIGNED_IRQ_NONE;
-        pci_device_set_intx_routing_notifier(pci_dev, NULL);
-    }
-
-    if (ctrl_byte & PCI_MSI_FLAGS_ENABLE) {
-        MSIMessage msg = msi_get_message(pci_dev, 0);
-        int virq;
-
-        virq = kvm_irqchip_add_msi_route(kvm_state, msg);
-        if (virq < 0) {
-            perror("assigned_dev_update_msi: kvm_irqchip_add_msi_route");
-            return;
-        }
-
-        assigned_dev->msi_virq = g_malloc(sizeof(*assigned_dev->msi_virq));
-        assigned_dev->msi_virq_nr = 1;
-        assigned_dev->msi_virq[0] = virq;
-        if (kvm_device_msi_assign(kvm_state, assigned_dev->dev_id, virq) < 0) {
-            perror("assigned_dev_update_msi: kvm_device_msi_assign");
-        }
-
-        assigned_dev->intx_route.mode = PCI_INTX_DISABLED;
-        assigned_dev->intx_route.irq = -1;
-        assigned_dev->assigned_irq_type = ASSIGNED_IRQ_MSI;
-    } else {
-        assign_intx(assigned_dev);
-    }
-}
-
-static bool assigned_dev_msix_masked(MSIXTableEntry *entry)
-{
-    return (entry->ctrl & cpu_to_le32(0x1)) != 0;
-}
-
-/*
- * When MSI-X is first enabled the vector table typically has all the
- * vectors masked, so we can't use that as the obvious test to figure out
- * how many vectors to initially enable.  Instead we look at the data field
- * because this is what worked for pci-assign for a long time.  This makes
- * sure the physical MSI-X state tracks the guest's view, which is important
- * for some VF/PF and PF/fw communication channels.
- */
-static bool assigned_dev_msix_skipped(MSIXTableEntry *entry)
-{
-    return !entry->data;
-}
-
-static int assigned_dev_update_msix_mmio(PCIDevice *pci_dev)
-{
-    AssignedDevice *adev = DO_UPCAST(AssignedDevice, dev, pci_dev);
-    uint16_t entries_nr = 0;
-    int i, r = 0;
-    MSIXTableEntry *entry = adev->msix_table;
-    MSIMessage msg;
-
-    /* Get the usable entry number for allocating */
-    for (i = 0; i < adev->msix_max; i++, entry++) {
-        if (assigned_dev_msix_skipped(entry)) {
-            continue;
-        }
-        entries_nr++;
-    }
-
-    DEBUG("MSI-X entries: %d\n", entries_nr);
-
-    /* It's valid to enable MSI-X with all entries masked */
-    if (!entries_nr) {
-        return 0;
-    }
-
-    r = kvm_device_msix_init_vectors(kvm_state, adev->dev_id, entries_nr);
-    if (r != 0) {
-        error_report("fail to set MSI-X entry number for MSIX! %s",
-                     strerror(-r));
-        return r;
-    }
-
-    free_msi_virqs(adev);
-
-    adev->msi_virq_nr = adev->msix_max;
-    adev->msi_virq = g_malloc(adev->msix_max * sizeof(*adev->msi_virq));
-
-    entry = adev->msix_table;
-    for (i = 0; i < adev->msix_max; i++, entry++) {
-        adev->msi_virq[i] = -1;
-
-        if (assigned_dev_msix_skipped(entry)) {
-            continue;
-        }
-
-        msg.address = entry->addr_lo | ((uint64_t)entry->addr_hi << 32);
-        msg.data = entry->data;
-        r = kvm_irqchip_add_msi_route(kvm_state, msg);
-        if (r < 0) {
-            return r;
-        }
-        adev->msi_virq[i] = r;
-
-        DEBUG("MSI-X vector %d, gsi %d, addr %08x_%08x, data %08x\n", i,
-              r, entry->addr_hi, entry->addr_lo, entry->data);
-
-        r = kvm_device_msix_set_vector(kvm_state, adev->dev_id, i,
-                                       adev->msi_virq[i]);
-        if (r) {
-            error_report("fail to set MSI-X entry! %s", strerror(-r));
-            break;
-        }
-    }
-
-    return r;
-}
-
-static void assigned_dev_update_msix(PCIDevice *pci_dev)
-{
-    AssignedDevice *assigned_dev = DO_UPCAST(AssignedDevice, dev, pci_dev);
-    uint16_t ctrl_word = pci_get_word(pci_dev->config + pci_dev->msix_cap +
-                                      PCI_MSIX_FLAGS);
-    int r;
-
-    /* Some guests gratuitously disable MSIX even if they're not using it,
-     * try to catch this by only deassigning irqs if the guest is using
-     * MSIX or intends to start. */
-    if ((assigned_dev->assigned_irq_type == ASSIGNED_IRQ_MSIX) ||
-        (ctrl_word & PCI_MSIX_FLAGS_ENABLE)) {
-        r = kvm_device_msix_deassign(kvm_state, assigned_dev->dev_id);
-        /* -ENXIO means no assigned irq */
-        if (r && r != -ENXIO) {
-            perror("assigned_dev_update_msix: deassign irq");
-        }
-
-        free_msi_virqs(assigned_dev);
-
-        assigned_dev->assigned_irq_type = ASSIGNED_IRQ_NONE;
-        pci_device_set_intx_routing_notifier(pci_dev, NULL);
-    }
-
-    if (ctrl_word & PCI_MSIX_FLAGS_ENABLE) {
-        if (assigned_dev_update_msix_mmio(pci_dev) < 0) {
-            perror("assigned_dev_update_msix_mmio");
-            return;
-        }
-
-        if (assigned_dev->msi_virq_nr > 0) {
-            if (kvm_device_msix_assign(kvm_state, assigned_dev->dev_id) < 0) {
-                perror("assigned_dev_enable_msix: assign irq");
-                return;
-            }
-        }
-        assigned_dev->intx_route.mode = PCI_INTX_DISABLED;
-        assigned_dev->intx_route.irq = -1;
-        assigned_dev->assigned_irq_type = ASSIGNED_IRQ_MSIX;
-    } else {
-        assign_intx(assigned_dev);
-    }
-}
-
-static uint32_t assigned_dev_pci_read_config(PCIDevice *pci_dev,
-                                             uint32_t address, int len)
-{
-    AssignedDevice *assigned_dev = DO_UPCAST(AssignedDevice, dev, pci_dev);
-    uint32_t virt_val = pci_default_read_config(pci_dev, address, len);
-    uint32_t real_val, emulate_mask, full_emulation_mask;
-
-    emulate_mask = 0;
-    memcpy(&emulate_mask, assigned_dev->emulate_config_read + address, len);
-    emulate_mask = le32_to_cpu(emulate_mask);
-
-    full_emulation_mask = 0xffffffff >> (32 - len * 8);
-
-    if (emulate_mask != full_emulation_mask) {
-        real_val = assigned_dev_pci_read(pci_dev, address, len);
-        return (virt_val & emulate_mask) | (real_val & ~emulate_mask);
-    } else {
-        return virt_val;
-    }
-}
-
-static void assigned_dev_pci_write_config(PCIDevice *pci_dev, uint32_t address,
-                                          uint32_t val, int len)
-{
-    AssignedDevice *assigned_dev = DO_UPCAST(AssignedDevice, dev, pci_dev);
-    uint16_t old_cmd = pci_get_word(pci_dev->config + PCI_COMMAND);
-    uint32_t emulate_mask, full_emulation_mask;
-    int ret;
-
-    pci_default_write_config(pci_dev, address, val, len);
-
-    if (kvm_has_intx_set_mask() &&
-        range_covers_byte(address, len, PCI_COMMAND + 1)) {
-        bool intx_masked = (pci_get_word(pci_dev->config + PCI_COMMAND) &
-                            PCI_COMMAND_INTX_DISABLE);
-
-        if (intx_masked != !!(old_cmd & PCI_COMMAND_INTX_DISABLE)) {
-            ret = kvm_device_intx_set_mask(kvm_state, assigned_dev->dev_id,
-                                           intx_masked);
-            if (ret) {
-                perror("assigned_dev_pci_write_config: set intx mask");
-            }
-        }
-    }
-    if (assigned_dev->cap.available & ASSIGNED_DEVICE_CAP_MSI) {
-        if (range_covers_byte(address, len,
-                              pci_dev->msi_cap + PCI_MSI_FLAGS)) {
-            assigned_dev_update_msi(pci_dev);
-        }
-    }
-    if (assigned_dev->cap.available & ASSIGNED_DEVICE_CAP_MSIX) {
-        if (range_covers_byte(address, len,
-                              pci_dev->msix_cap + PCI_MSIX_FLAGS + 1)) {
-            assigned_dev_update_msix(pci_dev);
-        }
-    }
-
-    emulate_mask = 0;
-    memcpy(&emulate_mask, assigned_dev->emulate_config_write + address, len);
-    emulate_mask = le32_to_cpu(emulate_mask);
-
-    full_emulation_mask = 0xffffffff >> (32 - len * 8);
-
-    if (emulate_mask != full_emulation_mask) {
-        if (emulate_mask) {
-            val &= ~emulate_mask;
-            val |= assigned_dev_pci_read(pci_dev, address, len) & emulate_mask;
-        }
-        assigned_dev_pci_write(pci_dev, address, val, len);
-    }
-}
-
-static void assigned_dev_setup_cap_read(AssignedDevice *dev, uint32_t offset,
-                                        uint32_t len)
-{
-    assigned_dev_direct_config_read(dev, offset, len);
-    assigned_dev_emulate_config_read(dev, offset + PCI_CAP_LIST_NEXT, 1);
-}
-
-static int assigned_device_pci_cap_init(PCIDevice *pci_dev)
-{
-    AssignedDevice *dev = DO_UPCAST(AssignedDevice, dev, pci_dev);
-    PCIRegion *pci_region = dev->real_device.regions;
-    int ret, pos;
-
-    /* Clear initial capabilities pointer and status copied from hw */
-    pci_set_byte(pci_dev->config + PCI_CAPABILITY_LIST, 0);
-    pci_set_word(pci_dev->config + PCI_STATUS,
-                 pci_get_word(pci_dev->config + PCI_STATUS) &
-                 ~PCI_STATUS_CAP_LIST);
-
-    /* Expose MSI capability
-     * MSI capability is the 1st capability in capability config */
-    pos = pci_find_cap_offset(pci_dev, PCI_CAP_ID_MSI, 0);
-    if (pos != 0 && kvm_check_extension(kvm_state, KVM_CAP_ASSIGN_DEV_IRQ)) {
-        if (!check_irqchip_in_kernel()) {
-            return -ENOTSUP;
-        }
-        dev->cap.available |= ASSIGNED_DEVICE_CAP_MSI;
-        /* Only 32-bit/no-mask currently supported */
-        ret = pci_add_capability(pci_dev, PCI_CAP_ID_MSI, pos, 10);
-        if (ret < 0) {
-            return ret;
-        }
-        pci_dev->msi_cap = pos;
-
-        pci_set_word(pci_dev->config + pos + PCI_MSI_FLAGS,
-                     pci_get_word(pci_dev->config + pos + PCI_MSI_FLAGS) &
-                     PCI_MSI_FLAGS_QMASK);
-        pci_set_long(pci_dev->config + pos + PCI_MSI_ADDRESS_LO, 0);
-        pci_set_word(pci_dev->config + pos + PCI_MSI_DATA_32, 0);
-
-        /* Set writable fields */
-        pci_set_word(pci_dev->wmask + pos + PCI_MSI_FLAGS,
-                     PCI_MSI_FLAGS_QSIZE | PCI_MSI_FLAGS_ENABLE);
-        pci_set_long(pci_dev->wmask + pos + PCI_MSI_ADDRESS_LO, 0xfffffffc);
-        pci_set_word(pci_dev->wmask + pos + PCI_MSI_DATA_32, 0xffff);
-    }
-    /* Expose MSI-X capability */
-    pos = pci_find_cap_offset(pci_dev, PCI_CAP_ID_MSIX, 0);
-    if (pos != 0 && kvm_device_msix_supported(kvm_state)) {
-        int bar_nr;
-        uint32_t msix_table_entry;
-
-        if (!check_irqchip_in_kernel()) {
-            return -ENOTSUP;
-        }
-        dev->cap.available |= ASSIGNED_DEVICE_CAP_MSIX;
-        ret = pci_add_capability(pci_dev, PCI_CAP_ID_MSIX, pos, 12);
-        if (ret < 0) {
-            return ret;
-        }
-        pci_dev->msix_cap = pos;
-
-        pci_set_word(pci_dev->config + pos + PCI_MSIX_FLAGS,
-                     pci_get_word(pci_dev->config + pos + PCI_MSIX_FLAGS) &
-                     PCI_MSIX_FLAGS_QSIZE);
-
-        /* Only enable and function mask bits are writable */
-        pci_set_word(pci_dev->wmask + pos + PCI_MSIX_FLAGS,
-                     PCI_MSIX_FLAGS_ENABLE | PCI_MSIX_FLAGS_MASKALL);
-
-        msix_table_entry = pci_get_long(pci_dev->config + pos + PCI_MSIX_TABLE);
-        bar_nr = msix_table_entry & PCI_MSIX_FLAGS_BIRMASK;
-        msix_table_entry &= ~PCI_MSIX_FLAGS_BIRMASK;
-        dev->msix_table_addr = pci_region[bar_nr].base_addr + msix_table_entry;
-        dev->msix_max = pci_get_word(pci_dev->config + pos + PCI_MSIX_FLAGS);
-        dev->msix_max &= PCI_MSIX_FLAGS_QSIZE;
-        dev->msix_max += 1;
-    }
-
-    /* Minimal PM support, nothing writable, device appears to NAK changes */
-    pos = pci_find_cap_offset(pci_dev, PCI_CAP_ID_PM, 0);
-    if (pos) {
-        uint16_t pmc;
-
-        ret = pci_add_capability(pci_dev, PCI_CAP_ID_PM, pos, PCI_PM_SIZEOF);
-        if (ret < 0) {
-            return ret;
-        }
-
-        assigned_dev_setup_cap_read(dev, pos, PCI_PM_SIZEOF);
-
-        pmc = pci_get_word(pci_dev->config + pos + PCI_CAP_FLAGS);
-        pmc &= (PCI_PM_CAP_VER_MASK | PCI_PM_CAP_DSI);
-        pci_set_word(pci_dev->config + pos + PCI_CAP_FLAGS, pmc);
-
-        /* assign_device will bring the device up to D0, so we don't need
-         * to worry about doing that ourselves here. */
-        pci_set_word(pci_dev->config + pos + PCI_PM_CTRL,
-                     PCI_PM_CTRL_NO_SOFT_RESET);
-
-        pci_set_byte(pci_dev->config + pos + PCI_PM_PPB_EXTENSIONS, 0);
-        pci_set_byte(pci_dev->config + pos + PCI_PM_DATA_REGISTER, 0);
-    }
-
-    pos = pci_find_cap_offset(pci_dev, PCI_CAP_ID_EXP, 0);
-    if (pos) {
-        uint8_t version, size = 0;
-        uint16_t type, devctl, lnksta;
-        uint32_t devcap, lnkcap;
-
-        version = pci_get_byte(pci_dev->config + pos + PCI_EXP_FLAGS);
-        version &= PCI_EXP_FLAGS_VERS;
-        if (version == 1) {
-            size = 0x14;
-        } else if (version == 2) {
-            /*
-             * Check for non-std size, accept reduced size to 0x34,
-             * which is what bcm5761 implemented, violating the
-             * PCIe v3.0 spec that regs should exist and be read as 0,
-             * not optionally provided and shorten the struct size.
-             */
-            size = MIN(0x3c, PCI_CONFIG_SPACE_SIZE - pos);
-            if (size < 0x34) {
-                error_report("%s: Invalid size PCIe cap-id 0x%x",
-                             __func__, PCI_CAP_ID_EXP);
-                return -EINVAL;
-            } else if (size != 0x3c) {
-                error_report("WARNING, %s: PCIe cap-id 0x%x has "
-                             "non-standard size 0x%x; std size should be 0x3c",
-                             __func__, PCI_CAP_ID_EXP, size);
-            }
-        } else if (version == 0) {
-            uint16_t vid, did;
-            vid = pci_get_word(pci_dev->config + PCI_VENDOR_ID);
-            did = pci_get_word(pci_dev->config + PCI_DEVICE_ID);
-            if (vid == PCI_VENDOR_ID_INTEL && did == 0x10ed) {
-                /*
-                 * quirk for Intel 82599 VF with invalid PCIe capability
-                 * version, should really be version 2 (same as PF)
-                 */
-                size = 0x3c;
-            }
-        }
-
-        if (size == 0) {
-            error_report("%s: Unsupported PCI express capability version %d",
-                         __func__, version);
-            return -EINVAL;
-        }
-
-        ret = pci_add_capability(pci_dev, PCI_CAP_ID_EXP, pos, size);
-        if (ret < 0) {
-            return ret;
-        }
-
-        assigned_dev_setup_cap_read(dev, pos, size);
-
-        type = pci_get_word(pci_dev->config + pos + PCI_EXP_FLAGS);
-        type = (type & PCI_EXP_FLAGS_TYPE) >> 4;
-        if (type != PCI_EXP_TYPE_ENDPOINT &&
-            type != PCI_EXP_TYPE_LEG_END && type != PCI_EXP_TYPE_RC_END) {
-            error_report("Device assignment only supports endpoint assignment,"
-                         " device type %d", type);
-            return -EINVAL;
-        }
-
-        /* capabilities, pass existing read-only copy
-         * PCI_EXP_FLAGS_IRQ: updated by hardware, should be direct read */
-
-        /* device capabilities: hide FLR */
-        devcap = pci_get_long(pci_dev->config + pos + PCI_EXP_DEVCAP);
-        devcap &= ~PCI_EXP_DEVCAP_FLR;
-        pci_set_long(pci_dev->config + pos + PCI_EXP_DEVCAP, devcap);
-
-        /* device control: clear all error reporting enable bits, leaving
-         *                 only a few host values.  Note, these are
-         *                 all writable, but not passed to hw.
-         */
-        devctl = pci_get_word(pci_dev->config + pos + PCI_EXP_DEVCTL);
-        devctl = (devctl & (PCI_EXP_DEVCTL_READRQ | PCI_EXP_DEVCTL_PAYLOAD)) |
-                  PCI_EXP_DEVCTL_RELAX_EN | PCI_EXP_DEVCTL_NOSNOOP_EN;
-        pci_set_word(pci_dev->config + pos + PCI_EXP_DEVCTL, devctl);
-        devctl = PCI_EXP_DEVCTL_BCR_FLR | PCI_EXP_DEVCTL_AUX_PME;
-        pci_set_word(pci_dev->wmask + pos + PCI_EXP_DEVCTL, ~devctl);
-
-        /* Clear device status */
-        pci_set_word(pci_dev->config + pos + PCI_EXP_DEVSTA, 0);
-
-        /* Link capabilities, expose links and latencues, clear reporting */
-        lnkcap = pci_get_long(pci_dev->config + pos + PCI_EXP_LNKCAP);
-        lnkcap &= (PCI_EXP_LNKCAP_SLS | PCI_EXP_LNKCAP_MLW |
-                   PCI_EXP_LNKCAP_ASPMS | PCI_EXP_LNKCAP_L0SEL |
-                   PCI_EXP_LNKCAP_L1EL);
-        pci_set_long(pci_dev->config + pos + PCI_EXP_LNKCAP, lnkcap);
-
-        /* Link control, pass existing read-only copy.  Should be writable? */
-
-        /* Link status, only expose current speed and width */
-        lnksta = pci_get_word(pci_dev->config + pos + PCI_EXP_LNKSTA);
-        lnksta &= (PCI_EXP_LNKSTA_CLS | PCI_EXP_LNKSTA_NLW);
-        pci_set_word(pci_dev->config + pos + PCI_EXP_LNKSTA, lnksta);
-
-        if (version >= 2) {
-            /* Slot capabilities, control, status - not needed for endpoints */
-            pci_set_long(pci_dev->config + pos + PCI_EXP_SLTCAP, 0);
-            pci_set_word(pci_dev->config + pos + PCI_EXP_SLTCTL, 0);
-            pci_set_word(pci_dev->config + pos + PCI_EXP_SLTSTA, 0);
-
-            /* Root control, capabilities, status - not needed for endpoints */
-            pci_set_word(pci_dev->config + pos + PCI_EXP_RTCTL, 0);
-            pci_set_word(pci_dev->config + pos + PCI_EXP_RTCAP, 0);
-            pci_set_long(pci_dev->config + pos + PCI_EXP_RTSTA, 0);
-
-            /* Device capabilities/control 2, pass existing read-only copy */
-            /* Link control 2, pass existing read-only copy */
-        }
-    }
-
-    pos = pci_find_cap_offset(pci_dev, PCI_CAP_ID_PCIX, 0);
-    if (pos) {
-        uint16_t cmd;
-        uint32_t status;
-
-        /* Only expose the minimum, 8 byte capability */
-        ret = pci_add_capability(pci_dev, PCI_CAP_ID_PCIX, pos, 8);
-        if (ret < 0) {
-            return ret;
-        }
-
-        assigned_dev_setup_cap_read(dev, pos, 8);
-
-        /* Command register, clear upper bits, including extended modes */
-        cmd = pci_get_word(pci_dev->config + pos + PCI_X_CMD);
-        cmd &= (PCI_X_CMD_DPERR_E | PCI_X_CMD_ERO | PCI_X_CMD_MAX_READ |
-                PCI_X_CMD_MAX_SPLIT);
-        pci_set_word(pci_dev->config + pos + PCI_X_CMD, cmd);
-
-        /* Status register, update with emulated PCI bus location, clear
-         * error bits, leave the rest. */
-        status = pci_get_long(pci_dev->config + pos + PCI_X_STATUS);
-        status &= ~(PCI_X_STATUS_BUS | PCI_X_STATUS_DEVFN);
-        status |= (pci_bus_num(pci_dev->bus) << 8) | pci_dev->devfn;
-        status &= ~(PCI_X_STATUS_SPL_DISC | PCI_X_STATUS_UNX_SPL |
-                    PCI_X_STATUS_SPL_ERR);
-        pci_set_long(pci_dev->config + pos + PCI_X_STATUS, status);
-    }
-
-    pos = pci_find_cap_offset(pci_dev, PCI_CAP_ID_VPD, 0);
-    if (pos) {
-        /* Direct R/W passthrough */
-        ret = pci_add_capability(pci_dev, PCI_CAP_ID_VPD, pos, 8);
-        if (ret < 0) {
-            return ret;
-        }
-
-        assigned_dev_setup_cap_read(dev, pos, 8);
-
-        /* direct write for cap content */
-        assigned_dev_direct_config_write(dev, pos + 2, 6);
-    }
-
-    /* Devices can have multiple vendor capabilities, get them all */
-    for (pos = 0; (pos = pci_find_cap_offset(pci_dev, PCI_CAP_ID_VNDR, pos));
-        pos += PCI_CAP_LIST_NEXT) {
-        uint8_t len = pci_get_byte(pci_dev->config + pos + PCI_CAP_FLAGS);
-        /* Direct R/W passthrough */
-        ret = pci_add_capability(pci_dev, PCI_CAP_ID_VNDR, pos, len);
-        if (ret < 0) {
-            return ret;
-        }
-
-        assigned_dev_setup_cap_read(dev, pos, len);
-
-        /* direct write for cap content */
-        assigned_dev_direct_config_write(dev, pos + 2, len - 2);
-    }
-
-    /* If real and virtual capability list status bits differ, virtualize the
-     * access. */
-    if ((pci_get_word(pci_dev->config + PCI_STATUS) & PCI_STATUS_CAP_LIST) !=
-        (assigned_dev_pci_read_byte(pci_dev, PCI_STATUS) &
-         PCI_STATUS_CAP_LIST)) {
-        dev->emulate_config_read[PCI_STATUS] |= PCI_STATUS_CAP_LIST;
-    }
-
-    return 0;
-}
-
-static uint64_t
-assigned_dev_msix_mmio_read(void *opaque, hwaddr addr,
-                            unsigned size)
-{
-    AssignedDevice *adev = opaque;
-    uint64_t val;
-
-    memcpy(&val, (void *)((uint8_t *)adev->msix_table + addr), size);
-
-    return val;
-}
-
-static void assigned_dev_msix_mmio_write(void *opaque, hwaddr addr,
-                                         uint64_t val, unsigned size)
-{
-    AssignedDevice *adev = opaque;
-    PCIDevice *pdev = &adev->dev;
-    uint16_t ctrl;
-    MSIXTableEntry orig;
-    int i = addr >> 4;
-
-    if (i >= adev->msix_max) {
-        return; /* Drop write */
-    }
-
-    ctrl = pci_get_word(pdev->config + pdev->msix_cap + PCI_MSIX_FLAGS);
-
-    DEBUG("write to MSI-X table offset 0x%lx, val 0x%lx\n", addr, val);
-
-    if (ctrl & PCI_MSIX_FLAGS_ENABLE) {
-        orig = adev->msix_table[i];
-    }
-
-    memcpy((uint8_t *)adev->msix_table + addr, &val, size);
-
-    if (ctrl & PCI_MSIX_FLAGS_ENABLE) {
-        MSIXTableEntry *entry = &adev->msix_table[i];
-
-        if (!assigned_dev_msix_masked(&orig) &&
-            assigned_dev_msix_masked(entry)) {
-            /*
-             * Vector masked, disable it
-             *
-             * XXX It's not clear if we can or should actually attempt
-             * to mask or disable the interrupt.  KVM doesn't have
-             * support for pending bits and kvm_assign_set_msix_entry
-             * doesn't modify the device hardware mask.  Interrupts
-             * while masked are simply not injected to the guest, so
-             * are lost.  Can we get away with always injecting an
-             * interrupt on unmask?
-             */
-        } else if (assigned_dev_msix_masked(&orig) &&
-                   !assigned_dev_msix_masked(entry)) {
-            /* Vector unmasked */
-            if (i >= adev->msi_virq_nr || adev->msi_virq[i] < 0) {
-                /* Previously unassigned vector, start from scratch */
-                assigned_dev_update_msix(pdev);
-                return;
-            } else {
-                /* Update an existing, previously masked vector */
-                MSIMessage msg;
-                int ret;
-
-                msg.address = entry->addr_lo |
-                    ((uint64_t)entry->addr_hi << 32);
-                msg.data = entry->data;
-
-                ret = kvm_irqchip_update_msi_route(kvm_state,
-                                                   adev->msi_virq[i], msg);
-                if (ret) {
-                    error_report("Error updating irq routing entry (%d)", ret);
-                }
-            }
-        }
-    }
-}
-
-static const MemoryRegionOps assigned_dev_msix_mmio_ops = {
-    .read = assigned_dev_msix_mmio_read,
-    .write = assigned_dev_msix_mmio_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 8,
-    },
-    .impl = {
-        .min_access_size = 4,
-        .max_access_size = 8,
-    },
-};
-
-static void assigned_dev_msix_reset(AssignedDevice *dev)
-{
-    MSIXTableEntry *entry;
-    int i;
-
-    if (!dev->msix_table) {
-        return;
-    }
-
-    memset(dev->msix_table, 0, MSIX_PAGE_SIZE);
-
-    for (i = 0, entry = dev->msix_table; i < dev->msix_max; i++, entry++) {
-        entry->ctrl = cpu_to_le32(0x1); /* Masked */
-    }
-}
-
-static int assigned_dev_register_msix_mmio(AssignedDevice *dev)
-{
-    dev->msix_table = mmap(NULL, MSIX_PAGE_SIZE, PROT_READ|PROT_WRITE,
-                           MAP_ANONYMOUS|MAP_PRIVATE, 0, 0);
-    if (dev->msix_table == MAP_FAILED) {
-        error_report("fail allocate msix_table! %s", strerror(errno));
-        return -EFAULT;
-    }
-
-    assigned_dev_msix_reset(dev);
-
-    memory_region_init_io(&dev->mmio, &assigned_dev_msix_mmio_ops, dev,
-                          "assigned-dev-msix", MSIX_PAGE_SIZE);
-    return 0;
-}
-
-static void assigned_dev_unregister_msix_mmio(AssignedDevice *dev)
-{
-    if (!dev->msix_table) {
-        return;
-    }
-
-    memory_region_destroy(&dev->mmio);
-
-    if (munmap(dev->msix_table, MSIX_PAGE_SIZE) == -1) {
-        error_report("error unmapping msix_table! %s", strerror(errno));
-    }
-    dev->msix_table = NULL;
-}
-
-static const VMStateDescription vmstate_assigned_device = {
-    .name = "pci-assign",
-    .unmigratable = 1,
-};
-
-static void reset_assigned_device(DeviceState *dev)
-{
-    PCIDevice *pci_dev = DO_UPCAST(PCIDevice, qdev, dev);
-    AssignedDevice *adev = DO_UPCAST(AssignedDevice, dev, pci_dev);
-    char reset_file[64];
-    const char reset[] = "1";
-    int fd, ret;
-
-    /*
-     * If a guest is reset without being shutdown, MSI/MSI-X can still
-     * be running.  We want to return the device to a known state on
-     * reset, so disable those here.  We especially do not want MSI-X
-     * enabled since it lives in MMIO space, which is about to get
-     * disabled.
-     */
-    if (adev->assigned_irq_type == ASSIGNED_IRQ_MSIX) {
-        uint16_t ctrl = pci_get_word(pci_dev->config +
-                                     pci_dev->msix_cap + PCI_MSIX_FLAGS);
-
-        pci_set_word(pci_dev->config + pci_dev->msix_cap + PCI_MSIX_FLAGS,
-                     ctrl & ~PCI_MSIX_FLAGS_ENABLE);
-        assigned_dev_update_msix(pci_dev);
-    } else if (adev->assigned_irq_type == ASSIGNED_IRQ_MSI) {
-        uint8_t ctrl = pci_get_byte(pci_dev->config +
-                                    pci_dev->msi_cap + PCI_MSI_FLAGS);
-
-        pci_set_byte(pci_dev->config + pci_dev->msi_cap + PCI_MSI_FLAGS,
-                     ctrl & ~PCI_MSI_FLAGS_ENABLE);
-        assigned_dev_update_msi(pci_dev);
-    }
-
-    snprintf(reset_file, sizeof(reset_file),
-             "/sys/bus/pci/devices/%04x:%02x:%02x.%01x/reset",
-             adev->host.domain, adev->host.bus, adev->host.slot,
-             adev->host.function);
-
-    /*
-     * Issue a device reset via pci-sysfs.  Note that we use write(2) here
-     * and ignore the return value because some kernels have a bug that
-     * returns 0 rather than bytes written on success, sending us into an
-     * infinite retry loop using other write mechanisms.
-     */
-    fd = open(reset_file, O_WRONLY);
-    if (fd != -1) {
-        ret = write(fd, reset, strlen(reset));
-        (void)ret;
-        close(fd);
-    }
-
-    /*
-     * When a 0 is written to the bus master register, the device is logically
-     * disconnected from the PCI bus. This avoids further DMA transfers.
-     */
-    assigned_dev_pci_write_config(pci_dev, PCI_COMMAND, 0, 1);
-}
-
-static int assigned_initfn(struct PCIDevice *pci_dev)
-{
-    AssignedDevice *dev = DO_UPCAST(AssignedDevice, dev, pci_dev);
-    uint8_t e_intx;
-    int r;
-
-    if (!kvm_enabled()) {
-        error_report("pci-assign: error: requires KVM support");
-        return -1;
-    }
-
-    if (!dev->host.domain && !dev->host.bus && !dev->host.slot &&
-        !dev->host.function) {
-        error_report("pci-assign: error: no host device specified");
-        return -1;
-    }
-
-    /*
-     * Set up basic config space access control. Will be further refined during
-     * device initialization.
-     */
-    assigned_dev_emulate_config_read(dev, 0, PCI_CONFIG_SPACE_SIZE);
-    assigned_dev_direct_config_read(dev, PCI_STATUS, 2);
-    assigned_dev_direct_config_read(dev, PCI_REVISION_ID, 1);
-    assigned_dev_direct_config_read(dev, PCI_CLASS_PROG, 3);
-    assigned_dev_direct_config_read(dev, PCI_CACHE_LINE_SIZE, 1);
-    assigned_dev_direct_config_read(dev, PCI_LATENCY_TIMER, 1);
-    assigned_dev_direct_config_read(dev, PCI_BIST, 1);
-    assigned_dev_direct_config_read(dev, PCI_CARDBUS_CIS, 4);
-    assigned_dev_direct_config_read(dev, PCI_SUBSYSTEM_VENDOR_ID, 2);
-    assigned_dev_direct_config_read(dev, PCI_SUBSYSTEM_ID, 2);
-    assigned_dev_direct_config_read(dev, PCI_CAPABILITY_LIST + 1, 7);
-    assigned_dev_direct_config_read(dev, PCI_MIN_GNT, 1);
-    assigned_dev_direct_config_read(dev, PCI_MAX_LAT, 1);
-    memcpy(dev->emulate_config_write, dev->emulate_config_read,
-           sizeof(dev->emulate_config_read));
-
-    if (get_real_device(dev, dev->host.domain, dev->host.bus,
-                        dev->host.slot, dev->host.function)) {
-        error_report("pci-assign: Error: Couldn't get real device (%s)!",
-                     dev->dev.qdev.id);
-        goto out;
-    }
-
-    if (assigned_device_pci_cap_init(pci_dev) < 0) {
-        goto out;
-    }
-
-    /* intercept MSI-X entry page in the MMIO */
-    if (dev->cap.available & ASSIGNED_DEVICE_CAP_MSIX) {
-        if (assigned_dev_register_msix_mmio(dev)) {
-            goto out;
-        }
-    }
-
-    /* handle real device's MMIO/PIO BARs */
-    if (assigned_dev_register_regions(dev->real_device.regions,
-                                      dev->real_device.region_number,
-                                      dev)) {
-        goto out;
-    }
-
-    /* handle interrupt routing */
-    e_intx = dev->dev.config[PCI_INTERRUPT_PIN] - 1;
-    dev->intpin = e_intx;
-    dev->intx_route.mode = PCI_INTX_DISABLED;
-    dev->intx_route.irq = -1;
-
-    /* assign device to guest */
-    r = assign_device(dev);
-    if (r < 0) {
-        goto out;
-    }
-
-    /* assign legacy INTx to the device */
-    r = assign_intx(dev);
-    if (r < 0) {
-        goto assigned_out;
-    }
-
-    assigned_dev_load_option_rom(dev);
-
-    add_boot_device_path(dev->bootindex, &pci_dev->qdev, NULL);
-
-    return 0;
-
-assigned_out:
-    deassign_device(dev);
-out:
-    free_assigned_device(dev);
-    return -1;
-}
-
-static void assigned_exitfn(struct PCIDevice *pci_dev)
-{
-    AssignedDevice *dev = DO_UPCAST(AssignedDevice, dev, pci_dev);
-
-    deassign_device(dev);
-    free_assigned_device(dev);
-}
-
-static Property assigned_dev_properties[] = {
-    DEFINE_PROP_PCI_HOST_DEVADDR("host", AssignedDevice, host),
-    DEFINE_PROP_BIT("prefer_msi", AssignedDevice, features,
-                    ASSIGNED_DEVICE_PREFER_MSI_BIT, false),
-    DEFINE_PROP_BIT("share_intx", AssignedDevice, features,
-                    ASSIGNED_DEVICE_SHARE_INTX_BIT, true),
-    DEFINE_PROP_INT32("bootindex", AssignedDevice, bootindex, -1),
-    DEFINE_PROP_STRING("configfd", AssignedDevice, configfd_name),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void assign_class_init(ObjectClass *klass, void *data)
-{
-    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-    DeviceClass *dc = DEVICE_CLASS(klass);
-
-    k->init         = assigned_initfn;
-    k->exit         = assigned_exitfn;
-    k->config_read  = assigned_dev_pci_read_config;
-    k->config_write = assigned_dev_pci_write_config;
-    dc->props       = assigned_dev_properties;
-    dc->vmsd        = &vmstate_assigned_device;
-    dc->reset       = reset_assigned_device;
-    dc->desc        = "KVM-based PCI passthrough";
-}
-
-static const TypeInfo assign_info = {
-    .name               = "kvm-pci-assign",
-    .parent             = TYPE_PCI_DEVICE,
-    .instance_size      = sizeof(AssignedDevice),
-    .class_init         = assign_class_init,
-};
-
-static void assign_register_types(void)
-{
-    type_register_static(&assign_info);
-}
-
-type_init(assign_register_types)
-
-/*
- * Scan the assigned devices for the devices that have an option ROM, and then
- * load the corresponding ROM data to RAM. If an error occurs while loading an
- * option ROM, we just ignore that option ROM and continue with the next one.
- */
-static void assigned_dev_load_option_rom(AssignedDevice *dev)
-{
-    char name[32], rom_file[64];
-    FILE *fp;
-    uint8_t val;
-    struct stat st;
-    void *ptr;
-
-    /* If loading ROM from file, pci handles it */
-    if (dev->dev.romfile || !dev->dev.rom_bar) {
-        return;
-    }
-
-    snprintf(rom_file, sizeof(rom_file),
-             "/sys/bus/pci/devices/%04x:%02x:%02x.%01x/rom",
-             dev->host.domain, dev->host.bus, dev->host.slot,
-             dev->host.function);
-
-    if (stat(rom_file, &st)) {
-        return;
-    }
-
-    if (access(rom_file, F_OK)) {
-        error_report("pci-assign: Insufficient privileges for %s", rom_file);
-        return;
-    }
-
-    /* Write "1" to the ROM file to enable it */
-    fp = fopen(rom_file, "r+");
-    if (fp == NULL) {
-        return;
-    }
-    val = 1;
-    if (fwrite(&val, 1, 1, fp) != 1) {
-        goto close_rom;
-    }
-    fseek(fp, 0, SEEK_SET);
-
-    snprintf(name, sizeof(name), "%s.rom",
-            object_get_typename(OBJECT(dev)));
-    memory_region_init_ram(&dev->dev.rom, name, st.st_size);
-    vmstate_register_ram(&dev->dev.rom, &dev->dev.qdev);
-    ptr = memory_region_get_ram_ptr(&dev->dev.rom);
-    memset(ptr, 0xff, st.st_size);
-
-    if (!fread(ptr, 1, st.st_size, fp)) {
-        error_report("pci-assign: Cannot read from host %s", rom_file);
-        error_printf("Device option ROM contents are probably invalid "
-                     "(check dmesg).\nSkip option ROM probe with rombar=0, "
-                     "or load from file with romfile=\n");
-        memory_region_destroy(&dev->dev.rom);
-        goto close_rom;
-    }
-
-    pci_register_bar(&dev->dev, PCI_ROM_SLOT, 0, &dev->dev.rom);
-    dev->dev.has_rom = true;
-close_rom:
-    /* Write "0" to disable ROM */
-    fseek(fp, 0, SEEK_SET);
-    val = 0;
-    if (!fwrite(&val, 1, 1, fp)) {
-        DEBUG("%s\n", "Failed to disable pci-sysfs rom file");
-    }
-    fclose(fp);
-}
diff --git a/hw/lan9118.c b/hw/lan9118.c
deleted file mode 100644 (file)
index 403fb86..0000000
+++ /dev/null
@@ -1,1399 +0,0 @@
-/*
- * SMSC LAN9118 Ethernet interface emulation
- *
- * Copyright (c) 2009 CodeSourcery, LLC.
- * 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 "hw/sysbus.h"
-#include "net/net.h"
-#include "hw/devices.h"
-#include "sysemu/sysemu.h"
-#include "hw/ptimer.h"
-/* For crc32 */
-#include <zlib.h>
-
-//#define DEBUG_LAN9118
-
-#ifdef DEBUG_LAN9118
-#define DPRINTF(fmt, ...) \
-do { printf("lan9118: " fmt , ## __VA_ARGS__); } while (0)
-#define BADF(fmt, ...) \
-do { hw_error("lan9118: error: " fmt , ## __VA_ARGS__);} while (0)
-#else
-#define DPRINTF(fmt, ...) do {} while(0)
-#define BADF(fmt, ...) \
-do { fprintf(stderr, "lan9118: error: " fmt , ## __VA_ARGS__);} while (0)
-#endif
-
-#define CSR_ID_REV      0x50
-#define CSR_IRQ_CFG     0x54
-#define CSR_INT_STS     0x58
-#define CSR_INT_EN      0x5c
-#define CSR_BYTE_TEST   0x64
-#define CSR_FIFO_INT    0x68
-#define CSR_RX_CFG      0x6c
-#define CSR_TX_CFG      0x70
-#define CSR_HW_CFG      0x74
-#define CSR_RX_DP_CTRL  0x78
-#define CSR_RX_FIFO_INF 0x7c
-#define CSR_TX_FIFO_INF 0x80
-#define CSR_PMT_CTRL    0x84
-#define CSR_GPIO_CFG    0x88
-#define CSR_GPT_CFG     0x8c
-#define CSR_GPT_CNT     0x90
-#define CSR_WORD_SWAP   0x98
-#define CSR_FREE_RUN    0x9c
-#define CSR_RX_DROP     0xa0
-#define CSR_MAC_CSR_CMD 0xa4
-#define CSR_MAC_CSR_DATA 0xa8
-#define CSR_AFC_CFG     0xac
-#define CSR_E2P_CMD     0xb0
-#define CSR_E2P_DATA    0xb4
-
-/* IRQ_CFG */
-#define IRQ_INT         0x00001000
-#define IRQ_EN          0x00000100
-#define IRQ_POL         0x00000010
-#define IRQ_TYPE        0x00000001
-
-/* INT_STS/INT_EN */
-#define SW_INT          0x80000000
-#define TXSTOP_INT      0x02000000
-#define RXSTOP_INT      0x01000000
-#define RXDFH_INT       0x00800000
-#define TX_IOC_INT      0x00200000
-#define RXD_INT         0x00100000
-#define GPT_INT         0x00080000
-#define PHY_INT         0x00040000
-#define PME_INT         0x00020000
-#define TXSO_INT        0x00010000
-#define RWT_INT         0x00008000
-#define RXE_INT         0x00004000
-#define TXE_INT         0x00002000
-#define TDFU_INT        0x00000800
-#define TDFO_INT        0x00000400
-#define TDFA_INT        0x00000200
-#define TSFF_INT        0x00000100
-#define TSFL_INT        0x00000080
-#define RXDF_INT        0x00000040
-#define RDFL_INT        0x00000020
-#define RSFF_INT        0x00000010
-#define RSFL_INT        0x00000008
-#define GPIO2_INT       0x00000004
-#define GPIO1_INT       0x00000002
-#define GPIO0_INT       0x00000001
-#define RESERVED_INT    0x7c001000
-
-#define MAC_CR          1
-#define MAC_ADDRH       2
-#define MAC_ADDRL       3
-#define MAC_HASHH       4
-#define MAC_HASHL       5
-#define MAC_MII_ACC     6
-#define MAC_MII_DATA    7
-#define MAC_FLOW        8
-#define MAC_VLAN1       9 /* TODO */
-#define MAC_VLAN2       10 /* TODO */
-#define MAC_WUFF        11 /* TODO */
-#define MAC_WUCSR       12 /* TODO */
-
-#define MAC_CR_RXALL    0x80000000
-#define MAC_CR_RCVOWN   0x00800000
-#define MAC_CR_LOOPBK   0x00200000
-#define MAC_CR_FDPX     0x00100000
-#define MAC_CR_MCPAS    0x00080000
-#define MAC_CR_PRMS     0x00040000
-#define MAC_CR_INVFILT  0x00020000
-#define MAC_CR_PASSBAD  0x00010000
-#define MAC_CR_HO       0x00008000
-#define MAC_CR_HPFILT   0x00002000
-#define MAC_CR_LCOLL    0x00001000
-#define MAC_CR_BCAST    0x00000800
-#define MAC_CR_DISRTY   0x00000400
-#define MAC_CR_PADSTR   0x00000100
-#define MAC_CR_BOLMT    0x000000c0
-#define MAC_CR_DFCHK    0x00000020
-#define MAC_CR_TXEN     0x00000008
-#define MAC_CR_RXEN     0x00000004
-#define MAC_CR_RESERVED 0x7f404213
-
-#define PHY_INT_ENERGYON            0x80
-#define PHY_INT_AUTONEG_COMPLETE    0x40
-#define PHY_INT_FAULT               0x20
-#define PHY_INT_DOWN                0x10
-#define PHY_INT_AUTONEG_LP          0x08
-#define PHY_INT_PARFAULT            0x04
-#define PHY_INT_AUTONEG_PAGE        0x02
-
-#define GPT_TIMER_EN    0x20000000
-
-enum tx_state {
-    TX_IDLE,
-    TX_B,
-    TX_DATA
-};
-
-typedef struct {
-    /* state is a tx_state but we can't put enums in VMStateDescriptions. */
-    uint32_t state;
-    uint32_t cmd_a;
-    uint32_t cmd_b;
-    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;
-    NICConf conf;
-    qemu_irq irq;
-    MemoryRegion mmio;
-    ptimer_state *timer;
-
-    uint32_t irq_cfg;
-    uint32_t int_sts;
-    uint32_t int_en;
-    uint32_t fifo_int;
-    uint32_t rx_cfg;
-    uint32_t tx_cfg;
-    uint32_t hw_cfg;
-    uint32_t pmt_ctrl;
-    uint32_t gpio_cfg;
-    uint32_t gpt_cfg;
-    uint32_t word_swap;
-    uint32_t free_timer_start;
-    uint32_t mac_cmd;
-    uint32_t mac_data;
-    uint32_t afc_cfg;
-    uint32_t e2p_cmd;
-    uint32_t e2p_data;
-
-    uint32_t mac_cr;
-    uint32_t mac_hashh;
-    uint32_t mac_hashl;
-    uint32_t mac_mii_acc;
-    uint32_t mac_mii_data;
-    uint32_t mac_flow;
-
-    uint32_t phy_status;
-    uint32_t phy_control;
-    uint32_t phy_advertise;
-    uint32_t phy_int;
-    uint32_t phy_int_mask;
-
-    int32_t eeprom_writable;
-    uint8_t eeprom[128];
-
-    int32_t tx_fifo_size;
-    LAN9118Packet *txp;
-    LAN9118Packet tx_packet;
-
-    int32_t tx_status_fifo_used;
-    int32_t tx_status_fifo_head;
-    uint32_t tx_status_fifo[512];
-
-    int32_t rx_status_fifo_size;
-    int32_t rx_status_fifo_used;
-    int32_t rx_status_fifo_head;
-    uint32_t rx_status_fifo[896];
-    int32_t rx_fifo_size;
-    int32_t rx_fifo_used;
-    int32_t rx_fifo_head;
-    uint32_t rx_fifo[3360];
-    int32_t rx_packet_size_head;
-    int32_t rx_packet_size_tail;
-    int32_t rx_packet_size[1024];
-
-    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 = 2,
-    .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_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()
-    }
-};
-
-static void lan9118_update(lan9118_state *s)
-{
-    int level;
-
-    /* TODO: Implement FIFO level IRQs.  */
-    level = (s->int_sts & s->int_en) != 0;
-    if (level) {
-        s->irq_cfg |= IRQ_INT;
-    } else {
-        s->irq_cfg &= ~IRQ_INT;
-    }
-    if ((s->irq_cfg & IRQ_EN) == 0) {
-        level = 0;
-    }
-    if ((s->irq_cfg & (IRQ_TYPE | IRQ_POL)) != (IRQ_TYPE | IRQ_POL)) {
-        /* Interrupt is active low unless we're configured as
-         * active-high polarity, push-pull type.
-         */
-        level = !level;
-    }
-    qemu_set_irq(s->irq, level);
-}
-
-static void lan9118_mac_changed(lan9118_state *s)
-{
-    qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
-}
-
-static void lan9118_reload_eeprom(lan9118_state *s)
-{
-    int i;
-    if (s->eeprom[0] != 0xa5) {
-        s->e2p_cmd &= ~0x10;
-        DPRINTF("MACADDR load failed\n");
-        return;
-    }
-    for (i = 0; i < 6; i++) {
-        s->conf.macaddr.a[i] = s->eeprom[i + 1];
-    }
-    s->e2p_cmd |= 0x10;
-    DPRINTF("MACADDR loaded from eeprom\n");
-    lan9118_mac_changed(s);
-}
-
-static void phy_update_irq(lan9118_state *s)
-{
-    if (s->phy_int & s->phy_int_mask) {
-        s->int_sts |= PHY_INT;
-    } else {
-        s->int_sts &= ~PHY_INT;
-    }
-    lan9118_update(s);
-}
-
-static void phy_update_link(lan9118_state *s)
-{
-    /* Autonegotiation status mirrors link status.  */
-    if (qemu_get_queue(s->nic)->link_down) {
-        s->phy_status &= ~0x0024;
-        s->phy_int |= PHY_INT_DOWN;
-    } else {
-        s->phy_status |= 0x0024;
-        s->phy_int |= PHY_INT_ENERGYON;
-        s->phy_int |= PHY_INT_AUTONEG_COMPLETE;
-    }
-    phy_update_irq(s);
-}
-
-static void lan9118_set_link(NetClientState *nc)
-{
-    phy_update_link(qemu_get_nic_opaque(nc));
-}
-
-static void phy_reset(lan9118_state *s)
-{
-    s->phy_status = 0x7809;
-    s->phy_control = 0x3000;
-    s->phy_advertise = 0x01e1;
-    s->phy_int_mask = 0;
-    s->phy_int = 0;
-    phy_update_link(s);
-}
-
-static void lan9118_reset(DeviceState *d)
-{
-    lan9118_state *s = FROM_SYSBUS(lan9118_state, SYS_BUS_DEVICE(d));
-    s->irq_cfg &= (IRQ_TYPE | IRQ_POL);
-    s->int_sts = 0;
-    s->int_en = 0;
-    s->fifo_int = 0x48000000;
-    s->rx_cfg = 0;
-    s->tx_cfg = 0;
-    s->hw_cfg = s->mode_16bit ? 0x00050000 : 0x00050004;
-    s->pmt_ctrl &= 0x45;
-    s->gpio_cfg = 0;
-    s->txp->fifo_used = 0;
-    s->txp->state = TX_IDLE;
-    s->txp->cmd_a = 0xffffffffu;
-    s->txp->cmd_b = 0xffffffffu;
-    s->txp->len = 0;
-    s->txp->fifo_used = 0;
-    s->tx_fifo_size = 4608;
-    s->tx_status_fifo_used = 0;
-    s->rx_status_fifo_size = 704;
-    s->rx_fifo_size = 2640;
-    s->rx_fifo_used = 0;
-    s->rx_status_fifo_size = 176;
-    s->rx_status_fifo_used = 0;
-    s->rxp_offset = 0;
-    s->rxp_size = 0;
-    s->rxp_pad = 0;
-    s->rx_packet_size_tail = s->rx_packet_size_head;
-    s->rx_packet_size[s->rx_packet_size_head] = 0;
-    s->mac_cmd = 0;
-    s->mac_data = 0;
-    s->afc_cfg = 0;
-    s->e2p_cmd = 0;
-    s->e2p_data = 0;
-    s->free_timer_start = qemu_get_clock_ns(vm_clock) / 40;
-
-    ptimer_stop(s->timer);
-    ptimer_set_count(s->timer, 0xffff);
-    s->gpt_cfg = 0xffff;
-
-    s->mac_cr = MAC_CR_PRMS;
-    s->mac_hashh = 0;
-    s->mac_hashl = 0;
-    s->mac_mii_acc = 0;
-    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;
-    lan9118_reload_eeprom(s);
-}
-
-static int lan9118_can_receive(NetClientState *nc)
-{
-    return 1;
-}
-
-static void rx_fifo_push(lan9118_state *s, uint32_t val)
-{
-    int fifo_pos;
-    fifo_pos = s->rx_fifo_head + s->rx_fifo_used;
-    if (fifo_pos >= s->rx_fifo_size)
-      fifo_pos -= s->rx_fifo_size;
-    s->rx_fifo[fifo_pos] = val;
-    s->rx_fifo_used++;
-}
-
-/* Return nonzero if the packet is accepted by the filter.  */
-static int lan9118_filter(lan9118_state *s, const uint8_t *addr)
-{
-    int multicast;
-    uint32_t hash;
-
-    if (s->mac_cr & MAC_CR_PRMS) {
-        return 1;
-    }
-    if (addr[0] == 0xff && addr[1] == 0xff && addr[2] == 0xff &&
-        addr[3] == 0xff && addr[4] == 0xff && addr[5] == 0xff) {
-        return (s->mac_cr & MAC_CR_BCAST) == 0;
-    }
-
-    multicast = addr[0] & 1;
-    if (multicast &&s->mac_cr & MAC_CR_MCPAS) {
-        return 1;
-    }
-    if (multicast ? (s->mac_cr & MAC_CR_HPFILT) == 0
-                  : (s->mac_cr & MAC_CR_HO) == 0) {
-        /* Exact matching.  */
-        hash = memcmp(addr, s->conf.macaddr.a, 6);
-        if (s->mac_cr & MAC_CR_INVFILT) {
-            return hash != 0;
-        } else {
-            return hash == 0;
-        }
-    } else {
-        /* Hash matching  */
-        hash = compute_mcast_idx(addr);
-        if (hash & 0x20) {
-            return (s->mac_hashh >> (hash & 0x1f)) & 1;
-        } else {
-            return (s->mac_hashl >> (hash & 0x1f)) & 1;
-        }
-    }
-}
-
-static ssize_t lan9118_receive(NetClientState *nc, const uint8_t *buf,
-                               size_t size)
-{
-    lan9118_state *s = qemu_get_nic_opaque(nc);
-    int fifo_len;
-    int offset;
-    int src_pos;
-    int n;
-    int filter;
-    uint32_t val;
-    uint32_t crc;
-    uint32_t status;
-
-    if ((s->mac_cr & MAC_CR_RXEN) == 0) {
-        return -1;
-    }
-
-    if (size >= 2048 || size < 14) {
-        return -1;
-    }
-
-    /* TODO: Implement FIFO overflow notification.  */
-    if (s->rx_status_fifo_used == s->rx_status_fifo_size) {
-        return -1;
-    }
-
-    filter = lan9118_filter(s, buf);
-    if (!filter && (s->mac_cr & MAC_CR_RXALL) == 0) {
-        return size;
-    }
-
-    offset = (s->rx_cfg >> 8) & 0x1f;
-    n = offset & 3;
-    fifo_len = (size + n + 3) >> 2;
-    /* Add a word for the CRC.  */
-    fifo_len++;
-    if (s->rx_fifo_size - s->rx_fifo_used < fifo_len) {
-        return -1;
-    }
-
-    DPRINTF("Got packet len:%d fifo:%d filter:%s\n",
-            (int)size, fifo_len, filter ? "pass" : "fail");
-    val = 0;
-    crc = bswap32(crc32(~0, buf, size));
-    for (src_pos = 0; src_pos < size; src_pos++) {
-        val = (val >> 8) | ((uint32_t)buf[src_pos] << 24);
-        n++;
-        if (n == 4) {
-            n = 0;
-            rx_fifo_push(s, val);
-            val = 0;
-        }
-    }
-    if (n) {
-        val >>= ((4 - n) * 8);
-        val |= crc << (n * 8);
-        rx_fifo_push(s, val);
-        val = crc >> ((4 - n) * 8);
-        rx_fifo_push(s, val);
-    } else {
-        rx_fifo_push(s, crc);
-    }
-    n = s->rx_status_fifo_head + s->rx_status_fifo_used;
-    if (n >= s->rx_status_fifo_size) {
-        n -= s->rx_status_fifo_size;
-    }
-    s->rx_packet_size[s->rx_packet_size_tail] = fifo_len;
-    s->rx_packet_size_tail = (s->rx_packet_size_tail + 1023) & 1023;
-    s->rx_status_fifo_used++;
-
-    status = (size + 4) << 16;
-    if (buf[0] == 0xff && buf[1] == 0xff && buf[2] == 0xff &&
-        buf[3] == 0xff && buf[4] == 0xff && buf[5] == 0xff) {
-        status |= 0x00002000;
-    } else if (buf[0] & 1) {
-        status |= 0x00000400;
-    }
-    if (!filter) {
-        status |= 0x40000000;
-    }
-    s->rx_status_fifo[n] = status;
-
-    if (s->rx_status_fifo_used > (s->fifo_int & 0xff)) {
-        s->int_sts |= RSFL_INT;
-    }
-    lan9118_update(s);
-
-    return size;
-}
-
-static uint32_t rx_fifo_pop(lan9118_state *s)
-{
-    int n;
-    uint32_t val;
-
-    if (s->rxp_size == 0 && s->rxp_pad == 0) {
-        s->rxp_size = s->rx_packet_size[s->rx_packet_size_head];
-        s->rx_packet_size[s->rx_packet_size_head] = 0;
-        if (s->rxp_size != 0) {
-            s->rx_packet_size_head = (s->rx_packet_size_head + 1023) & 1023;
-            s->rxp_offset = (s->rx_cfg >> 10) & 7;
-            n = s->rxp_offset + s->rxp_size;
-            switch (s->rx_cfg >> 30) {
-            case 1:
-                n = (-n) & 3;
-                break;
-            case 2:
-                n = (-n) & 7;
-                break;
-            default:
-                n = 0;
-                break;
-            }
-            s->rxp_pad = n;
-            DPRINTF("Pop packet size:%d offset:%d pad: %d\n",
-                    s->rxp_size, s->rxp_offset, s->rxp_pad);
-        }
-    }
-    if (s->rxp_offset > 0) {
-        s->rxp_offset--;
-        val = 0;
-    } else if (s->rxp_size > 0) {
-        s->rxp_size--;
-        val = s->rx_fifo[s->rx_fifo_head++];
-        if (s->rx_fifo_head >= s->rx_fifo_size) {
-            s->rx_fifo_head -= s->rx_fifo_size;
-        }
-        s->rx_fifo_used--;
-    } else if (s->rxp_pad > 0) {
-        s->rxp_pad--;
-        val =  0;
-    } else {
-        DPRINTF("RX underflow\n");
-        s->int_sts |= RXE_INT;
-        val =  0;
-    }
-    lan9118_update(s);
-    return val;
-}
-
-static void do_tx_packet(lan9118_state *s)
-{
-    int n;
-    uint32_t status;
-
-    /* FIXME: Honor TX disable, and allow queueing of packets.  */
-    if (s->phy_control & 0x4000)  {
-        /* This assumes the receive routine doesn't touch the VLANClient.  */
-        lan9118_receive(qemu_get_queue(s->nic), s->txp->data, s->txp->len);
-    } else {
-        qemu_send_packet(qemu_get_queue(s->nic), s->txp->data, s->txp->len);
-    }
-    s->txp->fifo_used = 0;
-
-    if (s->tx_status_fifo_used == 512) {
-        /* Status FIFO full */
-        return;
-    }
-    /* Add entry to status FIFO.  */
-    status = s->txp->cmd_b & 0xffff0000u;
-    DPRINTF("Sent packet tag:%04x len %d\n", status >> 16, s->txp->len);
-    n = (s->tx_status_fifo_head + s->tx_status_fifo_used) & 511;
-    s->tx_status_fifo[n] = status;
-    s->tx_status_fifo_used++;
-    if (s->tx_status_fifo_used == 512) {
-        s->int_sts |= TSFF_INT;
-        /* TODO: Stop transmission.  */
-    }
-}
-
-static uint32_t rx_status_fifo_pop(lan9118_state *s)
-{
-    uint32_t val;
-
-    val = s->rx_status_fifo[s->rx_status_fifo_head];
-    if (s->rx_status_fifo_used != 0) {
-        s->rx_status_fifo_used--;
-        s->rx_status_fifo_head++;
-        if (s->rx_status_fifo_head >= s->rx_status_fifo_size) {
-            s->rx_status_fifo_head -= s->rx_status_fifo_size;
-        }
-        /* ??? What value should be returned when the FIFO is empty?  */
-        DPRINTF("RX status pop 0x%08x\n", val);
-    }
-    return val;
-}
-
-static uint32_t tx_status_fifo_pop(lan9118_state *s)
-{
-    uint32_t val;
-
-    val = s->tx_status_fifo[s->tx_status_fifo_head];
-    if (s->tx_status_fifo_used != 0) {
-        s->tx_status_fifo_used--;
-        s->tx_status_fifo_head = (s->tx_status_fifo_head + 1) & 511;
-        /* ??? What value should be returned when the FIFO is empty?  */
-    }
-    return val;
-}
-
-static void tx_fifo_push(lan9118_state *s, uint32_t val)
-{
-    int n;
-
-    if (s->txp->fifo_used == s->tx_fifo_size) {
-        s->int_sts |= TDFO_INT;
-        return;
-    }
-    switch (s->txp->state) {
-    case TX_IDLE:
-        s->txp->cmd_a = val & 0x831f37ff;
-        s->txp->fifo_used++;
-        s->txp->state = TX_B;
-        break;
-    case TX_B:
-        if (s->txp->cmd_a & 0x2000) {
-            /* First segment */
-            s->txp->cmd_b = val;
-            s->txp->fifo_used++;
-            s->txp->buffer_size = s->txp->cmd_a & 0x7ff;
-            s->txp->offset = (s->txp->cmd_a >> 16) & 0x1f;
-            /* End alignment does not include command words.  */
-            n = (s->txp->buffer_size + s->txp->offset + 3) >> 2;
-            switch ((n >> 24) & 3) {
-            case 1:
-                n = (-n) & 3;
-                break;
-            case 2:
-                n = (-n) & 7;
-                break;
-            default:
-                n = 0;
-            }
-            s->txp->pad = n;
-            s->txp->len = 0;
-        }
-        DPRINTF("Block len:%d offset:%d pad:%d cmd %08x\n",
-                s->txp->buffer_size, s->txp->offset, s->txp->pad,
-                s->txp->cmd_a);
-        s->txp->state = TX_DATA;
-        break;
-    case TX_DATA:
-        if (s->txp->offset >= 4) {
-            s->txp->offset -= 4;
-            break;
-        }
-        if (s->txp->buffer_size <= 0 && s->txp->pad != 0) {
-            s->txp->pad--;
-        } else {
-            n = 4;
-            while (s->txp->offset) {
-                val >>= 8;
-                n--;
-                s->txp->offset--;
-            }
-            /* Documentation is somewhat unclear on the ordering of bytes
-               in FIFO words.  Empirical results show it to be little-endian.
-               */
-            /* TODO: FIFO overflow checking.  */
-            while (n--) {
-                s->txp->data[s->txp->len] = val & 0xff;
-                s->txp->len++;
-                val >>= 8;
-                s->txp->buffer_size--;
-            }
-            s->txp->fifo_used++;
-        }
-        if (s->txp->buffer_size <= 0 && s->txp->pad == 0) {
-            if (s->txp->cmd_a & 0x1000) {
-                do_tx_packet(s);
-            }
-            if (s->txp->cmd_a & 0x80000000) {
-                s->int_sts |= TX_IOC_INT;
-            }
-            s->txp->state = TX_IDLE;
-        }
-        break;
-    }
-}
-
-static uint32_t do_phy_read(lan9118_state *s, int reg)
-{
-    uint32_t val;
-
-    switch (reg) {
-    case 0: /* Basic Control */
-        return s->phy_control;
-    case 1: /* Basic Status */
-        return s->phy_status;
-    case 2: /* ID1 */
-        return 0x0007;
-    case 3: /* ID2 */
-        return 0xc0d1;
-    case 4: /* Auto-neg advertisement */
-        return s->phy_advertise;
-    case 5: /* Auto-neg Link Partner Ability */
-        return 0x0f71;
-    case 6: /* Auto-neg Expansion */
-        return 1;
-        /* TODO 17, 18, 27, 29, 30, 31 */
-    case 29: /* Interrupt source.  */
-        val = s->phy_int;
-        s->phy_int = 0;
-        phy_update_irq(s);
-        return val;
-    case 30: /* Interrupt mask */
-        return s->phy_int_mask;
-    default:
-        BADF("PHY read reg %d\n", reg);
-        return 0;
-    }
-}
-
-static void do_phy_write(lan9118_state *s, int reg, uint32_t val)
-{
-    switch (reg) {
-    case 0: /* Basic Control */
-        if (val & 0x8000) {
-            phy_reset(s);
-            break;
-        }
-        s->phy_control = val & 0x7980;
-        /* Complete autonegotiation immediately.  */
-        if (val & 0x1000) {
-            s->phy_status |= 0x0020;
-        }
-        break;
-    case 4: /* Auto-neg advertisement */
-        s->phy_advertise = (val & 0x2d7f) | 0x80;
-        break;
-        /* TODO 17, 18, 27, 31 */
-    case 30: /* Interrupt mask */
-        s->phy_int_mask = val & 0xff;
-        phy_update_irq(s);
-        break;
-    default:
-        BADF("PHY write reg %d = 0x%04x\n", reg, val);
-    }
-}
-
-static void do_mac_write(lan9118_state *s, int reg, uint32_t val)
-{
-    switch (reg) {
-    case MAC_CR:
-        if ((s->mac_cr & MAC_CR_RXEN) != 0 && (val & MAC_CR_RXEN) == 0) {
-            s->int_sts |= RXSTOP_INT;
-        }
-        s->mac_cr = val & ~MAC_CR_RESERVED;
-        DPRINTF("MAC_CR: %08x\n", val);
-        break;
-    case MAC_ADDRH:
-        s->conf.macaddr.a[4] = val & 0xff;
-        s->conf.macaddr.a[5] = (val >> 8) & 0xff;
-        lan9118_mac_changed(s);
-        break;
-    case MAC_ADDRL:
-        s->conf.macaddr.a[0] = val & 0xff;
-        s->conf.macaddr.a[1] = (val >> 8) & 0xff;
-        s->conf.macaddr.a[2] = (val >> 16) & 0xff;
-        s->conf.macaddr.a[3] = (val >> 24) & 0xff;
-        lan9118_mac_changed(s);
-        break;
-    case MAC_HASHH:
-        s->mac_hashh = val;
-        break;
-    case MAC_HASHL:
-        s->mac_hashl = val;
-        break;
-    case MAC_MII_ACC:
-        s->mac_mii_acc = val & 0xffc2;
-        if (val & 2) {
-            DPRINTF("PHY write %d = 0x%04x\n",
-                    (val >> 6) & 0x1f, s->mac_mii_data);
-            do_phy_write(s, (val >> 6) & 0x1f, s->mac_mii_data);
-        } else {
-            s->mac_mii_data = do_phy_read(s, (val >> 6) & 0x1f);
-            DPRINTF("PHY read %d = 0x%04x\n",
-                    (val >> 6) & 0x1f, s->mac_mii_data);
-        }
-        break;
-    case MAC_MII_DATA:
-        s->mac_mii_data = val & 0xffff;
-        break;
-    case MAC_FLOW:
-        s->mac_flow = val & 0xffff0000;
-        break;
-    case MAC_VLAN1:
-        /* Writing to this register changes a condition for
-         * FrameTooLong bit in rx_status.  Since we do not set
-         * FrameTooLong anyway, just ignore write to this.
-         */
-        break;
-    default:
-        hw_error("lan9118: Unimplemented MAC register write: %d = 0x%x\n",
-                 s->mac_cmd & 0xf, val);
-    }
-}
-
-static uint32_t do_mac_read(lan9118_state *s, int reg)
-{
-    switch (reg) {
-    case MAC_CR:
-        return s->mac_cr;
-    case MAC_ADDRH:
-        return s->conf.macaddr.a[4] | (s->conf.macaddr.a[5] << 8);
-    case MAC_ADDRL:
-        return s->conf.macaddr.a[0] | (s->conf.macaddr.a[1] << 8)
-               | (s->conf.macaddr.a[2] << 16) | (s->conf.macaddr.a[3] << 24);
-    case MAC_HASHH:
-        return s->mac_hashh;
-        break;
-    case MAC_HASHL:
-        return s->mac_hashl;
-        break;
-    case MAC_MII_ACC:
-        return s->mac_mii_acc;
-    case MAC_MII_DATA:
-        return s->mac_mii_data;
-    case MAC_FLOW:
-        return s->mac_flow;
-    default:
-        hw_error("lan9118: Unimplemented MAC register read: %d\n",
-                 s->mac_cmd & 0xf);
-    }
-}
-
-static void lan9118_eeprom_cmd(lan9118_state *s, int cmd, int addr)
-{
-    s->e2p_cmd = (s->e2p_cmd & 0x10) | (cmd << 28) | addr;
-    switch (cmd) {
-    case 0:
-        s->e2p_data = s->eeprom[addr];
-        DPRINTF("EEPROM Read %d = 0x%02x\n", addr, s->e2p_data);
-        break;
-    case 1:
-        s->eeprom_writable = 0;
-        DPRINTF("EEPROM Write Disable\n");
-        break;
-    case 2: /* EWEN */
-        s->eeprom_writable = 1;
-        DPRINTF("EEPROM Write Enable\n");
-        break;
-    case 3: /* WRITE */
-        if (s->eeprom_writable) {
-            s->eeprom[addr] &= s->e2p_data;
-            DPRINTF("EEPROM Write %d = 0x%02x\n", addr, s->e2p_data);
-        } else {
-            DPRINTF("EEPROM Write %d (ignored)\n", addr);
-        }
-        break;
-    case 4: /* WRAL */
-        if (s->eeprom_writable) {
-            for (addr = 0; addr < 128; addr++) {
-                s->eeprom[addr] &= s->e2p_data;
-            }
-            DPRINTF("EEPROM Write All 0x%02x\n", s->e2p_data);
-        } else {
-            DPRINTF("EEPROM Write All (ignored)\n");
-        }
-        break;
-    case 5: /* ERASE */
-        if (s->eeprom_writable) {
-            s->eeprom[addr] = 0xff;
-            DPRINTF("EEPROM Erase %d\n", addr);
-        } else {
-            DPRINTF("EEPROM Erase %d (ignored)\n", addr);
-        }
-        break;
-    case 6: /* ERAL */
-        if (s->eeprom_writable) {
-            memset(s->eeprom, 0xff, 128);
-            DPRINTF("EEPROM Erase All\n");
-        } else {
-            DPRINTF("EEPROM Erase All (ignored)\n");
-        }
-        break;
-    case 7: /* RELOAD */
-        lan9118_reload_eeprom(s);
-        break;
-    }
-}
-
-static void lan9118_tick(void *opaque)
-{
-    lan9118_state *s = (lan9118_state *)opaque;
-    if (s->int_en & GPT_INT) {
-        s->int_sts |= GPT_INT;
-    }
-    lan9118_update(s);
-}
-
-static void lan9118_writel(void *opaque, hwaddr offset,
-                           uint64_t val, unsigned size)
-{
-    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 */
-        tx_fifo_push(s, val);
-        return;
-    }
-    switch (offset) {
-    case CSR_IRQ_CFG:
-        /* TODO: Implement interrupt deassertion intervals.  */
-        val &= (IRQ_EN | IRQ_POL | IRQ_TYPE);
-        s->irq_cfg = (s->irq_cfg & IRQ_INT) | val;
-        break;
-    case CSR_INT_STS:
-        s->int_sts &= ~val;
-        break;
-    case CSR_INT_EN:
-        s->int_en = val & ~RESERVED_INT;
-        s->int_sts |= val & SW_INT;
-        break;
-    case CSR_FIFO_INT:
-        DPRINTF("FIFO INT levels %08x\n", val);
-        s->fifo_int = val;
-        break;
-    case CSR_RX_CFG:
-        if (val & 0x8000) {
-            /* RX_DUMP */
-            s->rx_fifo_used = 0;
-            s->rx_status_fifo_used = 0;
-            s->rx_packet_size_tail = s->rx_packet_size_head;
-            s->rx_packet_size[s->rx_packet_size_head] = 0;
-        }
-        s->rx_cfg = val & 0xcfff1ff0;
-        break;
-    case CSR_TX_CFG:
-        if (val & 0x8000) {
-            s->tx_status_fifo_used = 0;
-        }
-        if (val & 0x4000) {
-            s->txp->state = TX_IDLE;
-            s->txp->fifo_used = 0;
-            s->txp->cmd_a = 0xffffffff;
-        }
-        s->tx_cfg = val & 6;
-        break;
-    case CSR_HW_CFG:
-        if (val & 1) {
-            /* SRST */
-            lan9118_reset(&s->busdev.qdev);
-        } else {
-            s->hw_cfg = (val & 0x003f300) | (s->hw_cfg & 0x4);
-        }
-        break;
-    case CSR_RX_DP_CTRL:
-        if (val & 0x80000000) {
-            /* Skip forward to next packet.  */
-            s->rxp_pad = 0;
-            s->rxp_offset = 0;
-            if (s->rxp_size == 0) {
-                /* Pop a word to start the next packet.  */
-                rx_fifo_pop(s);
-                s->rxp_pad = 0;
-                s->rxp_offset = 0;
-            }
-            s->rx_fifo_head += s->rxp_size;
-            if (s->rx_fifo_head >= s->rx_fifo_size) {
-                s->rx_fifo_head -= s->rx_fifo_size;
-            }
-        }
-        break;
-    case CSR_PMT_CTRL:
-        if (val & 0x400) {
-            phy_reset(s);
-        }
-        s->pmt_ctrl &= ~0x34e;
-        s->pmt_ctrl |= (val & 0x34e);
-        break;
-    case CSR_GPIO_CFG:
-        /* Probably just enabling LEDs.  */
-        s->gpio_cfg = val & 0x7777071f;
-        break;
-    case CSR_GPT_CFG:
-        if ((s->gpt_cfg ^ val) & GPT_TIMER_EN) {
-            if (val & GPT_TIMER_EN) {
-                ptimer_set_count(s->timer, val & 0xffff);
-                ptimer_run(s->timer, 0);
-            } else {
-                ptimer_stop(s->timer);
-                ptimer_set_count(s->timer, 0xffff);
-            }
-        }
-        s->gpt_cfg = val & (GPT_TIMER_EN | 0xffff);
-        break;
-    case CSR_WORD_SWAP:
-        /* Ignored because we're in 32-bit mode.  */
-        s->word_swap = val;
-        break;
-    case CSR_MAC_CSR_CMD:
-        s->mac_cmd = val & 0x4000000f;
-        if (val & 0x80000000) {
-            if (val & 0x40000000) {
-                s->mac_data = do_mac_read(s, val & 0xf);
-                DPRINTF("MAC read %d = 0x%08x\n", val & 0xf, s->mac_data);
-            } else {
-                DPRINTF("MAC write %d = 0x%08x\n", val & 0xf, s->mac_data);
-                do_mac_write(s, val & 0xf, s->mac_data);
-            }
-        }
-        break;
-    case CSR_MAC_CSR_DATA:
-        s->mac_data = val;
-        break;
-    case CSR_AFC_CFG:
-        s->afc_cfg = val & 0x00ffffff;
-        break;
-    case CSR_E2P_CMD:
-        lan9118_eeprom_cmd(s, (val >> 28) & 7, val & 0x7f);
-        break;
-    case CSR_E2P_DATA:
-        s->e2p_data = val & 0xff;
-        break;
-
-    default:
-        hw_error("lan9118_write: Bad reg 0x%x = %x\n", (int)offset, (int)val);
-        break;
-    }
-    lan9118_update(s);
-}
-
-static void lan9118_writew(void *opaque, hwaddr 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, hwaddr offset,
-                                     uint64_t val, unsigned size)
-{
-    switch (size) {
-    case 2:
-        lan9118_writew(opaque, offset, (uint32_t)val);
-        return;
-    case 4:
-        lan9118_writel(opaque, offset, val, size);
-        return;
-    }
-
-    hw_error("lan9118_write: Bad size 0x%x\n", size);
-}
-
-static uint64_t lan9118_readl(void *opaque, hwaddr offset,
-                              unsigned size)
-{
-    lan9118_state *s = (lan9118_state *)opaque;
-
-    //DPRINTF("Read reg 0x%02x\n", (int)offset);
-    if (offset < 0x20) {
-        /* RX FIFO */
-        return rx_fifo_pop(s);
-    }
-    switch (offset) {
-    case 0x40:
-        return rx_status_fifo_pop(s);
-    case 0x44:
-        return s->rx_status_fifo[s->tx_status_fifo_head];
-    case 0x48:
-        return tx_status_fifo_pop(s);
-    case 0x4c:
-        return s->tx_status_fifo[s->tx_status_fifo_head];
-    case CSR_ID_REV:
-        return 0x01180001;
-    case CSR_IRQ_CFG:
-        return s->irq_cfg;
-    case CSR_INT_STS:
-        return s->int_sts;
-    case CSR_INT_EN:
-        return s->int_en;
-    case CSR_BYTE_TEST:
-        return 0x87654321;
-    case CSR_FIFO_INT:
-        return s->fifo_int;
-    case CSR_RX_CFG:
-        return s->rx_cfg;
-    case CSR_TX_CFG:
-        return s->tx_cfg;
-    case CSR_HW_CFG:
-        return s->hw_cfg;
-    case CSR_RX_DP_CTRL:
-        return 0;
-    case CSR_RX_FIFO_INF:
-        return (s->rx_status_fifo_used << 16) | (s->rx_fifo_used << 2);
-    case CSR_TX_FIFO_INF:
-        return (s->tx_status_fifo_used << 16)
-               | (s->tx_fifo_size - s->txp->fifo_used);
-    case CSR_PMT_CTRL:
-        return s->pmt_ctrl;
-    case CSR_GPIO_CFG:
-        return s->gpio_cfg;
-    case CSR_GPT_CFG:
-        return s->gpt_cfg;
-    case CSR_GPT_CNT:
-        return ptimer_get_count(s->timer);
-    case CSR_WORD_SWAP:
-        return s->word_swap;
-    case CSR_FREE_RUN:
-        return (qemu_get_clock_ns(vm_clock) / 40) - s->free_timer_start;
-    case CSR_RX_DROP:
-        /* TODO: Implement dropped frames counter.  */
-        return 0;
-    case CSR_MAC_CSR_CMD:
-        return s->mac_cmd;
-    case CSR_MAC_CSR_DATA:
-        return s->mac_data;
-    case CSR_AFC_CFG:
-        return s->afc_cfg;
-    case CSR_E2P_CMD:
-        return s->e2p_cmd;
-    case CSR_E2P_DATA:
-        return s->e2p_data;
-    }
-    hw_error("lan9118_read: Bad reg 0x%x\n", (int)offset);
-    return 0;
-}
-
-static uint32_t lan9118_readw(void *opaque, hwaddr 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, hwaddr 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(NetClientState *nc)
-{
-    lan9118_state *s = qemu_get_nic_opaque(nc);
-
-    s->nic = NULL;
-}
-
-static NetClientInfo net_lan9118_info = {
-    .type = NET_CLIENT_OPTIONS_KIND_NIC,
-    .size = sizeof(NICState),
-    .can_receive = lan9118_can_receive,
-    .receive = lan9118_receive,
-    .cleanup = lan9118_cleanup,
-    .link_status_changed = lan9118_set_link,
-};
-
-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, 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);
-
-    s->nic = qemu_new_nic(&net_lan9118_info, &s->conf,
-                          object_get_typename(OBJECT(dev)), dev->qdev.id, s);
-    qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
-    s->eeprom[0] = 0xa5;
-    for (i = 0; i < 6; i++) {
-        s->eeprom[i + 1] = s->conf.macaddr.a[i];
-    }
-    s->pmt_ctrl = 1;
-    s->txp = &s->tx_packet;
-
-    bh = qemu_bh_new(lan9118_tick, s);
-    s->timer = ptimer_init(bh);
-    ptimer_set_freq(s->timer, 10000);
-    ptimer_set_limit(s->timer, 0xffff, 1);
-
-    return 0;
-}
-
-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(),
-};
-
-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 const TypeInfo lan9118_info = {
-    .name          = "lan9118",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(lan9118_state),
-    .class_init    = lan9118_class_init,
-};
-
-static void lan9118_register_types(void)
-{
-    type_register_static(&lan9118_info);
-}
-
-/* Legacy helper function.  Should go away when machine config files are
-   implemented.  */
-void lan9118_init(NICInfo *nd, uint32_t base, qemu_irq irq)
-{
-    DeviceState *dev;
-    SysBusDevice *s;
-
-    qemu_check_nic_model(nd, "lan9118");
-    dev = qdev_create(NULL, "lan9118");
-    qdev_set_nic_properties(dev, nd);
-    qdev_init_nofail(dev);
-    s = SYS_BUS_DEVICE(dev);
-    sysbus_mmio_map(s, 0, base);
-    sysbus_connect_irq(s, 0, irq);
-}
-
-type_init(lan9118_register_types)
diff --git a/hw/lance.c b/hw/lance.c
deleted file mode 100644 (file)
index acfffae..0000000
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * QEMU AMD PC-Net II (Am79C970A) emulation
- *
- * Copyright (c) 2004 Antony T Curtis
- *
- * 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.
- */
-
-/* This software was written to be compatible with the specification:
- * AMD Am79C970A PCnet-PCI II Ethernet Controller Data-Sheet
- * AMD Publication# 19436  Rev:E  Amendment/0  Issue Date: June 2000
- */
-
-/*
- * On Sparc32, this is the Lance (Am7990) part of chip STP2000 (Master I/O), also
- * produced as NCR89C100. See
- * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C100.txt
- * and
- * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR92C990.txt
- */
-
-#include "hw/sysbus.h"
-#include "net/net.h"
-#include "qemu/timer.h"
-#include "qemu/sockets.h"
-#include "hw/sun4m.h"
-#include "hw/pcnet.h"
-#include "trace.h"
-
-typedef struct {
-    SysBusDevice busdev;
-    PCNetState state;
-} SysBusPCNetState;
-
-static void parent_lance_reset(void *opaque, int irq, int level)
-{
-    SysBusPCNetState *d = opaque;
-    if (level)
-        pcnet_h_reset(&d->state);
-}
-
-static void lance_mem_write(void *opaque, hwaddr addr,
-                            uint64_t val, unsigned size)
-{
-    SysBusPCNetState *d = opaque;
-
-    trace_lance_mem_writew(addr, val & 0xffff);
-    pcnet_ioport_writew(&d->state, addr, val & 0xffff);
-}
-
-static uint64_t lance_mem_read(void *opaque, hwaddr addr,
-                               unsigned size)
-{
-    SysBusPCNetState *d = opaque;
-    uint32_t val;
-
-    val = pcnet_ioport_readw(&d->state, addr);
-    trace_lance_mem_readw(addr, val & 0xffff);
-    return val & 0xffff;
-}
-
-static const MemoryRegionOps lance_mem_ops = {
-    .read = lance_mem_read,
-    .write = lance_mem_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid = {
-        .min_access_size = 2,
-        .max_access_size = 2,
-    },
-};
-
-static void lance_cleanup(NetClientState *nc)
-{
-    PCNetState *d = qemu_get_nic_opaque(nc);
-
-    pcnet_common_cleanup(d);
-}
-
-static NetClientInfo net_lance_info = {
-    .type = NET_CLIENT_OPTIONS_KIND_NIC,
-    .size = sizeof(NICState),
-    .can_receive = pcnet_can_receive,
-    .receive = pcnet_receive,
-    .link_status_changed = pcnet_set_link_status,
-    .cleanup = lance_cleanup,
-};
-
-static const VMStateDescription vmstate_lance = {
-    .name = "pcnet",
-    .version_id = 3,
-    .minimum_version_id = 2,
-    .minimum_version_id_old = 2,
-    .fields      = (VMStateField []) {
-        VMSTATE_STRUCT(state, SysBusPCNetState, 0, vmstate_pcnet, PCNetState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static int lance_init(SysBusDevice *dev)
-{
-    SysBusPCNetState *d = FROM_SYSBUS(SysBusPCNetState, dev);
-    PCNetState *s = &d->state;
-
-    memory_region_init_io(&s->mmio, &lance_mem_ops, d, "lance-mmio", 4);
-
-    qdev_init_gpio_in(&dev->qdev, parent_lance_reset, 1);
-
-    sysbus_init_mmio(dev, &s->mmio);
-
-    sysbus_init_irq(dev, &s->irq);
-
-    s->phys_mem_read = ledma_memory_read;
-    s->phys_mem_write = ledma_memory_write;
-    return pcnet_common_init(&dev->qdev, s, &net_lance_info);
-}
-
-static void lance_reset(DeviceState *dev)
-{
-    SysBusPCNetState *d = DO_UPCAST(SysBusPCNetState, busdev.qdev, dev);
-
-    pcnet_h_reset(&d->state);
-}
-
-static Property lance_properties[] = {
-    DEFINE_PROP_PTR("dma", SysBusPCNetState, state.dma_opaque),
-    DEFINE_NIC_PROPERTIES(SysBusPCNetState, state.conf),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void lance_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = lance_init;
-    dc->fw_name = "ethernet";
-    dc->reset = lance_reset;
-    dc->vmsd = &vmstate_lance;
-    dc->props = lance_properties;
-}
-
-static const TypeInfo lance_info = {
-    .name          = "lance",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(SysBusPCNetState),
-    .class_init    = lance_class_init,
-};
-
-static void lance_register_types(void)
-{
-    type_register_static(&lance_info);
-}
-
-type_init(lance_register_types)
diff --git a/hw/lm32.h b/hw/lm32.h
deleted file mode 100644 (file)
index 236686e..0000000
--- a/hw/lm32.h
+++ /dev/null
@@ -1,30 +0,0 @@
-#ifndef HW_LM32_H
-#define HW_LM32_H 1
-
-
-#include "qemu-common.h"
-
-static inline DeviceState *lm32_pic_init(qemu_irq cpu_irq)
-{
-    DeviceState *dev;
-    SysBusDevice *d;
-
-    dev = qdev_create(NULL, "lm32-pic");
-    qdev_init_nofail(dev);
-    d = SYS_BUS_DEVICE(dev);
-    sysbus_connect_irq(d, 0, cpu_irq);
-
-    return dev;
-}
-
-static inline DeviceState *lm32_juart_init(void)
-{
-    DeviceState *dev;
-
-    dev = qdev_create(NULL, "lm32-juart");
-    qdev_init_nofail(dev);
-
-    return dev;
-}
-
-#endif
index 68ca90a3e2b491f2a25b550d664ef7cd36252442..ea6418ae59599d9b9943c5156a9a7c4ce85f7592 100644 (file)
@@ -1,23 +1,3 @@
-# LM32 peripherals
-obj-y += lm32_pic.o
-obj-y += lm32_juart.o
-obj-y += lm32_timer.o
-obj-y += lm32_uart.o
-obj-y += lm32_sys.o
-obj-y += milkymist-ac97.o
-obj-y += milkymist-hpdmc.o
-obj-y += milkymist-memcard.o
-obj-y += milkymist-minimac2.o
-obj-y += milkymist-pfpu.o
-obj-y += milkymist-softusb.o
-obj-y += milkymist-sysctl.o
-obj-$(CONFIG_GLX) += milkymist-tmu2.o
-obj-y += milkymist-uart.o
-obj-y += milkymist-vgafb.o
-obj-y += framebuffer.o
-
-obj-y := $(addprefix ../,$(obj-y))
-
 # LM32 boards
 obj-y += lm32_boards.o
 obj-y += milkymist.o
diff --git a/hw/lm32/lm32.h b/hw/lm32/lm32.h
new file mode 100644 (file)
index 0000000..236686e
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef HW_LM32_H
+#define HW_LM32_H 1
+
+
+#include "qemu-common.h"
+
+static inline DeviceState *lm32_pic_init(qemu_irq cpu_irq)
+{
+    DeviceState *dev;
+    SysBusDevice *d;
+
+    dev = qdev_create(NULL, "lm32-pic");
+    qdev_init_nofail(dev);
+    d = SYS_BUS_DEVICE(dev);
+    sysbus_connect_irq(d, 0, cpu_irq);
+
+    return dev;
+}
+
+static inline DeviceState *lm32_juart_init(void)
+{
+    DeviceState *dev;
+
+    dev = qdev_create(NULL, "lm32-juart");
+    qdev_init_nofail(dev);
+
+    return dev;
+}
+
+#endif
index db9294809273175071057a63d78ae4aaccb14151..6555a97e2e99a151a5967ace35d564591eccf968 100644 (file)
 
 #include "hw/sysbus.h"
 #include "hw/hw.h"
-#include "hw/flash.h"
-#include "hw/devices.h"
+#include "hw/block/flash.h"
+#include "hw/arm/devices.h"
 #include "hw/boards.h"
 #include "hw/loader.h"
 #include "sysemu/blockdev.h"
 #include "elf.h"
-#include "hw/lm32_hwsetup.h"
-#include "hw/lm32.h"
+#include "lm32_hwsetup.h"
+#include "lm32.h"
 #include "exec/address-spaces.h"
 
 typedef struct {
diff --git a/hw/lm32/lm32_hwsetup.h b/hw/lm32/lm32_hwsetup.h
new file mode 100644 (file)
index 0000000..3449bd8
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ *  LatticeMico32 hwsetup helper functions.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
+ *
+ * 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/>.
+ */
+
+/*
+ * These are helper functions for creating the hardware description blob used
+ * in the Theobroma's uClinux port.
+ */
+
+#ifndef QEMU_HW_LM32_HWSETUP_H
+#define QEMU_HW_LM32_HWSETUP_H
+
+#include "qemu-common.h"
+#include "hw/loader.h"
+
+typedef struct {
+    void *data;
+    void *ptr;
+} HWSetup;
+
+enum hwsetup_tag {
+    HWSETUP_TAG_EOL         = 0,
+    HWSETUP_TAG_CPU         = 1,
+    HWSETUP_TAG_ASRAM       = 2,
+    HWSETUP_TAG_FLASH       = 3,
+    HWSETUP_TAG_SDRAM       = 4,
+    HWSETUP_TAG_OCM         = 5,
+    HWSETUP_TAG_DDR_SDRAM   = 6,
+    HWSETUP_TAG_DDR2_SDRAM  = 7,
+    HWSETUP_TAG_TIMER       = 8,
+    HWSETUP_TAG_UART        = 9,
+    HWSETUP_TAG_GPIO        = 10,
+    HWSETUP_TAG_TRISPEEDMAC = 11,
+    HWSETUP_TAG_I2CM        = 12,
+    HWSETUP_TAG_LEDS        = 13,
+    HWSETUP_TAG_7SEG        = 14,
+    HWSETUP_TAG_SPI_S       = 15,
+    HWSETUP_TAG_SPI_M       = 16,
+};
+
+static inline HWSetup *hwsetup_init(void)
+{
+    HWSetup *hw;
+
+    hw = g_malloc(sizeof(HWSetup));
+    hw->data = g_malloc0(TARGET_PAGE_SIZE);
+    hw->ptr = hw->data;
+
+    return hw;
+}
+
+static inline void hwsetup_free(HWSetup *hw)
+{
+    g_free(hw->data);
+    g_free(hw);
+}
+
+static inline void hwsetup_create_rom(HWSetup *hw,
+        hwaddr base)
+{
+    rom_add_blob("hwsetup", hw->data, TARGET_PAGE_SIZE, base);
+}
+
+static inline void hwsetup_add_u8(HWSetup *hw, uint8_t u)
+{
+    stb_p(hw->ptr, u);
+    hw->ptr += 1;
+}
+
+static inline void hwsetup_add_u32(HWSetup *hw, uint32_t u)
+{
+    stl_p(hw->ptr, u);
+    hw->ptr += 4;
+}
+
+static inline void hwsetup_add_tag(HWSetup *hw, enum hwsetup_tag t)
+{
+    stl_p(hw->ptr, t);
+    hw->ptr += 4;
+}
+
+static inline void hwsetup_add_str(HWSetup *hw, const char *str)
+{
+    pstrcpy(hw->ptr, 32, str);
+    hw->ptr += 32;
+}
+
+static inline void hwsetup_add_trailer(HWSetup *hw)
+{
+    hwsetup_add_u32(hw, 8); /* size */
+    hwsetup_add_tag(hw, HWSETUP_TAG_EOL);
+}
+
+static inline void hwsetup_add_cpu(HWSetup *hw,
+        const char *name, uint32_t frequency)
+{
+    hwsetup_add_u32(hw, 44); /* size */
+    hwsetup_add_tag(hw, HWSETUP_TAG_CPU);
+    hwsetup_add_str(hw, name);
+    hwsetup_add_u32(hw, frequency);
+}
+
+static inline void hwsetup_add_flash(HWSetup *hw,
+        const char *name, uint32_t base, uint32_t size)
+{
+    hwsetup_add_u32(hw, 52); /* size */
+    hwsetup_add_tag(hw, HWSETUP_TAG_FLASH);
+    hwsetup_add_str(hw, name);
+    hwsetup_add_u32(hw, base);
+    hwsetup_add_u32(hw, size);
+    hwsetup_add_u8(hw, 8); /* read latency */
+    hwsetup_add_u8(hw, 8); /* write latency */
+    hwsetup_add_u8(hw, 25); /* address width */
+    hwsetup_add_u8(hw, 32); /* data width */
+}
+
+static inline void hwsetup_add_ddr_sdram(HWSetup *hw,
+        const char *name, uint32_t base, uint32_t size)
+{
+    hwsetup_add_u32(hw, 48); /* size */
+    hwsetup_add_tag(hw, HWSETUP_TAG_DDR_SDRAM);
+    hwsetup_add_str(hw, name);
+    hwsetup_add_u32(hw, base);
+    hwsetup_add_u32(hw, size);
+}
+
+static inline void hwsetup_add_timer(HWSetup *hw,
+        const char *name, uint32_t base, uint32_t irq)
+{
+    hwsetup_add_u32(hw, 56); /* size */
+    hwsetup_add_tag(hw, HWSETUP_TAG_TIMER);
+    hwsetup_add_str(hw, name);
+    hwsetup_add_u32(hw, base);
+    hwsetup_add_u8(hw, 1); /* wr_tickcount */
+    hwsetup_add_u8(hw, 1); /* rd_tickcount */
+    hwsetup_add_u8(hw, 1); /* start_stop_control */
+    hwsetup_add_u8(hw, 32); /* counter_width */
+    hwsetup_add_u32(hw, 20); /* reload_ticks */
+    hwsetup_add_u8(hw, irq);
+    hwsetup_add_u8(hw, 0); /* padding */
+    hwsetup_add_u8(hw, 0); /* padding */
+    hwsetup_add_u8(hw, 0); /* padding */
+}
+
+static inline void hwsetup_add_uart(HWSetup *hw,
+        const char *name, uint32_t base, uint32_t irq)
+{
+    hwsetup_add_u32(hw, 56); /* size */
+    hwsetup_add_tag(hw, HWSETUP_TAG_UART);
+    hwsetup_add_str(hw, name);
+    hwsetup_add_u32(hw, base);
+    hwsetup_add_u32(hw, 115200); /* baudrate */
+    hwsetup_add_u8(hw, 8); /* databits */
+    hwsetup_add_u8(hw, 1); /* stopbits */
+    hwsetup_add_u8(hw, 1); /* use_interrupt */
+    hwsetup_add_u8(hw, 1); /* block_on_transmit */
+    hwsetup_add_u8(hw, 1); /* block_on_receive */
+    hwsetup_add_u8(hw, 4); /* rx_buffer_size */
+    hwsetup_add_u8(hw, 4); /* tx_buffer_size */
+    hwsetup_add_u8(hw, irq);
+}
+
+#endif /* QEMU_HW_LM32_HWSETUP_H */
diff --git a/hw/lm32/milkymist-hw.h b/hw/lm32/milkymist-hw.h
new file mode 100644 (file)
index 0000000..4e86c4e
--- /dev/null
@@ -0,0 +1,208 @@
+#ifndef QEMU_HW_MILKYMIST_H
+#define QEMU_HW_MILKYMIST_H
+
+#include "hw/qdev.h"
+#include "hw/qdev-addr.h"
+#include "net/net.h"
+
+static inline DeviceState *milkymist_uart_create(hwaddr base,
+        qemu_irq irq)
+{
+    DeviceState *dev;
+
+    dev = qdev_create(NULL, "milkymist-uart");
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
+    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq);
+
+    return dev;
+}
+
+static inline DeviceState *milkymist_hpdmc_create(hwaddr base)
+{
+    DeviceState *dev;
+
+    dev = qdev_create(NULL, "milkymist-hpdmc");
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
+
+    return dev;
+}
+
+static inline DeviceState *milkymist_memcard_create(hwaddr base)
+{
+    DeviceState *dev;
+
+    dev = qdev_create(NULL, "milkymist-memcard");
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
+
+    return dev;
+}
+
+static inline DeviceState *milkymist_vgafb_create(hwaddr base,
+        uint32_t fb_offset, uint32_t fb_mask)
+{
+    DeviceState *dev;
+
+    dev = qdev_create(NULL, "milkymist-vgafb");
+    qdev_prop_set_uint32(dev, "fb_offset", fb_offset);
+    qdev_prop_set_uint32(dev, "fb_mask", fb_mask);
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
+
+    return dev;
+}
+
+static inline DeviceState *milkymist_sysctl_create(hwaddr base,
+        qemu_irq gpio_irq, qemu_irq timer0_irq, qemu_irq timer1_irq,
+        uint32_t freq_hz, uint32_t system_id, uint32_t capabilities,
+        uint32_t gpio_strappings)
+{
+    DeviceState *dev;
+
+    dev = qdev_create(NULL, "milkymist-sysctl");
+    qdev_prop_set_uint32(dev, "frequency", freq_hz);
+    qdev_prop_set_uint32(dev, "systemid", system_id);
+    qdev_prop_set_uint32(dev, "capabilities", capabilities);
+    qdev_prop_set_uint32(dev, "gpio_strappings", gpio_strappings);
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
+    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, gpio_irq);
+    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, timer0_irq);
+    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 2, timer1_irq);
+
+    return dev;
+}
+
+static inline DeviceState *milkymist_pfpu_create(hwaddr base,
+        qemu_irq irq)
+{
+    DeviceState *dev;
+
+    dev = qdev_create(NULL, "milkymist-pfpu");
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
+    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq);
+    return dev;
+}
+
+#ifdef CONFIG_GLX
+#include <X11/Xlib.h>
+#include <GL/glx.h>
+static const int glx_fbconfig_attr[] = {
+    GLX_GREEN_SIZE, 5,
+    GLX_GREEN_SIZE, 6,
+    GLX_BLUE_SIZE, 5,
+    None
+};
+#endif
+
+static inline DeviceState *milkymist_tmu2_create(hwaddr base,
+        qemu_irq irq)
+{
+#ifdef CONFIG_GLX
+    DeviceState *dev;
+    Display *d;
+    GLXFBConfig *configs;
+    int nelements;
+    int ver_major, ver_minor;
+
+    if (display_type == DT_NOGRAPHIC) {
+        return NULL;
+    }
+
+    /* check that GLX will work */
+    d = XOpenDisplay(NULL);
+    if (d == NULL) {
+        return NULL;
+    }
+
+    if (!glXQueryVersion(d, &ver_major, &ver_minor)) {
+        /* Yeah, sometimes getting the GLX version can fail.
+         * Isn't X beautiful? */
+        XCloseDisplay(d);
+        return NULL;
+    }
+
+    if ((ver_major < 1) || ((ver_major == 1) && (ver_minor < 3))) {
+        printf("Your GLX version is %d.%d,"
+          "but TMU emulation needs at least 1.3. TMU disabled.\n",
+          ver_major, ver_minor);
+        XCloseDisplay(d);
+        return NULL;
+    }
+
+    configs = glXChooseFBConfig(d, 0, glx_fbconfig_attr, &nelements);
+    if (configs == NULL) {
+        XCloseDisplay(d);
+        return NULL;
+    }
+
+    XFree(configs);
+    XCloseDisplay(d);
+
+    dev = qdev_create(NULL, "milkymist-tmu2");
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
+    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq);
+
+    return dev;
+#else
+    return NULL;
+#endif
+}
+
+static inline DeviceState *milkymist_ac97_create(hwaddr base,
+        qemu_irq crrequest_irq, qemu_irq crreply_irq, qemu_irq dmar_irq,
+        qemu_irq dmaw_irq)
+{
+    DeviceState *dev;
+
+    dev = qdev_create(NULL, "milkymist-ac97");
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
+    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, crrequest_irq);
+    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, crreply_irq);
+    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 2, dmar_irq);
+    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 3, dmaw_irq);
+
+    return dev;
+}
+
+static inline DeviceState *milkymist_minimac2_create(hwaddr base,
+        hwaddr buffers_base, qemu_irq rx_irq, qemu_irq tx_irq)
+{
+    DeviceState *dev;
+
+    qemu_check_nic_model(&nd_table[0], "minimac2");
+    dev = qdev_create(NULL, "milkymist-minimac2");
+    qdev_set_nic_properties(dev, &nd_table[0]);
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
+    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 1, buffers_base);
+    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, rx_irq);
+    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, tx_irq);
+
+    return dev;
+}
+
+static inline DeviceState *milkymist_softusb_create(hwaddr base,
+        qemu_irq irq, uint32_t pmem_base, uint32_t pmem_size,
+        uint32_t dmem_base, uint32_t dmem_size)
+{
+    DeviceState *dev;
+
+    dev = qdev_create(NULL, "milkymist-softusb");
+    qdev_prop_set_uint32(dev, "pmem_size", pmem_size);
+    qdev_prop_set_uint32(dev, "dmem_size", dmem_size);
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
+    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 1, pmem_base);
+    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, dmem_base);
+    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq);
+
+    return dev;
+}
+
+#endif /* QEMU_HW_MILKYMIST_H */
index b347cf964cb206cbb97e54a65b9bd108fa8cd7a2..d02ca0cc04ced9f83178b314cdfa5634d8c23eb8 100644 (file)
 
 #include "hw/sysbus.h"
 #include "hw/hw.h"
-#include "hw/flash.h"
+#include "hw/block/flash.h"
 #include "sysemu/sysemu.h"
-#include "hw/devices.h"
+#include "hw/arm/devices.h"
 #include "hw/boards.h"
 #include "hw/loader.h"
 #include "elf.h"
 #include "sysemu/blockdev.h"
-#include "hw/milkymist-hw.h"
-#include "hw/lm32.h"
+#include "milkymist-hw.h"
+#include "lm32.h"
 #include "exec/address-spaces.h"
 
 #define BIOS_FILENAME    "mmone-bios.bin"
diff --git a/hw/lm32_hwsetup.h b/hw/lm32_hwsetup.h
deleted file mode 100644 (file)
index 3449bd8..0000000
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- *  LatticeMico32 hwsetup helper functions.
- *
- *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
- *
- * 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/>.
- */
-
-/*
- * These are helper functions for creating the hardware description blob used
- * in the Theobroma's uClinux port.
- */
-
-#ifndef QEMU_HW_LM32_HWSETUP_H
-#define QEMU_HW_LM32_HWSETUP_H
-
-#include "qemu-common.h"
-#include "hw/loader.h"
-
-typedef struct {
-    void *data;
-    void *ptr;
-} HWSetup;
-
-enum hwsetup_tag {
-    HWSETUP_TAG_EOL         = 0,
-    HWSETUP_TAG_CPU         = 1,
-    HWSETUP_TAG_ASRAM       = 2,
-    HWSETUP_TAG_FLASH       = 3,
-    HWSETUP_TAG_SDRAM       = 4,
-    HWSETUP_TAG_OCM         = 5,
-    HWSETUP_TAG_DDR_SDRAM   = 6,
-    HWSETUP_TAG_DDR2_SDRAM  = 7,
-    HWSETUP_TAG_TIMER       = 8,
-    HWSETUP_TAG_UART        = 9,
-    HWSETUP_TAG_GPIO        = 10,
-    HWSETUP_TAG_TRISPEEDMAC = 11,
-    HWSETUP_TAG_I2CM        = 12,
-    HWSETUP_TAG_LEDS        = 13,
-    HWSETUP_TAG_7SEG        = 14,
-    HWSETUP_TAG_SPI_S       = 15,
-    HWSETUP_TAG_SPI_M       = 16,
-};
-
-static inline HWSetup *hwsetup_init(void)
-{
-    HWSetup *hw;
-
-    hw = g_malloc(sizeof(HWSetup));
-    hw->data = g_malloc0(TARGET_PAGE_SIZE);
-    hw->ptr = hw->data;
-
-    return hw;
-}
-
-static inline void hwsetup_free(HWSetup *hw)
-{
-    g_free(hw->data);
-    g_free(hw);
-}
-
-static inline void hwsetup_create_rom(HWSetup *hw,
-        hwaddr base)
-{
-    rom_add_blob("hwsetup", hw->data, TARGET_PAGE_SIZE, base);
-}
-
-static inline void hwsetup_add_u8(HWSetup *hw, uint8_t u)
-{
-    stb_p(hw->ptr, u);
-    hw->ptr += 1;
-}
-
-static inline void hwsetup_add_u32(HWSetup *hw, uint32_t u)
-{
-    stl_p(hw->ptr, u);
-    hw->ptr += 4;
-}
-
-static inline void hwsetup_add_tag(HWSetup *hw, enum hwsetup_tag t)
-{
-    stl_p(hw->ptr, t);
-    hw->ptr += 4;
-}
-
-static inline void hwsetup_add_str(HWSetup *hw, const char *str)
-{
-    pstrcpy(hw->ptr, 32, str);
-    hw->ptr += 32;
-}
-
-static inline void hwsetup_add_trailer(HWSetup *hw)
-{
-    hwsetup_add_u32(hw, 8); /* size */
-    hwsetup_add_tag(hw, HWSETUP_TAG_EOL);
-}
-
-static inline void hwsetup_add_cpu(HWSetup *hw,
-        const char *name, uint32_t frequency)
-{
-    hwsetup_add_u32(hw, 44); /* size */
-    hwsetup_add_tag(hw, HWSETUP_TAG_CPU);
-    hwsetup_add_str(hw, name);
-    hwsetup_add_u32(hw, frequency);
-}
-
-static inline void hwsetup_add_flash(HWSetup *hw,
-        const char *name, uint32_t base, uint32_t size)
-{
-    hwsetup_add_u32(hw, 52); /* size */
-    hwsetup_add_tag(hw, HWSETUP_TAG_FLASH);
-    hwsetup_add_str(hw, name);
-    hwsetup_add_u32(hw, base);
-    hwsetup_add_u32(hw, size);
-    hwsetup_add_u8(hw, 8); /* read latency */
-    hwsetup_add_u8(hw, 8); /* write latency */
-    hwsetup_add_u8(hw, 25); /* address width */
-    hwsetup_add_u8(hw, 32); /* data width */
-}
-
-static inline void hwsetup_add_ddr_sdram(HWSetup *hw,
-        const char *name, uint32_t base, uint32_t size)
-{
-    hwsetup_add_u32(hw, 48); /* size */
-    hwsetup_add_tag(hw, HWSETUP_TAG_DDR_SDRAM);
-    hwsetup_add_str(hw, name);
-    hwsetup_add_u32(hw, base);
-    hwsetup_add_u32(hw, size);
-}
-
-static inline void hwsetup_add_timer(HWSetup *hw,
-        const char *name, uint32_t base, uint32_t irq)
-{
-    hwsetup_add_u32(hw, 56); /* size */
-    hwsetup_add_tag(hw, HWSETUP_TAG_TIMER);
-    hwsetup_add_str(hw, name);
-    hwsetup_add_u32(hw, base);
-    hwsetup_add_u8(hw, 1); /* wr_tickcount */
-    hwsetup_add_u8(hw, 1); /* rd_tickcount */
-    hwsetup_add_u8(hw, 1); /* start_stop_control */
-    hwsetup_add_u8(hw, 32); /* counter_width */
-    hwsetup_add_u32(hw, 20); /* reload_ticks */
-    hwsetup_add_u8(hw, irq);
-    hwsetup_add_u8(hw, 0); /* padding */
-    hwsetup_add_u8(hw, 0); /* padding */
-    hwsetup_add_u8(hw, 0); /* padding */
-}
-
-static inline void hwsetup_add_uart(HWSetup *hw,
-        const char *name, uint32_t base, uint32_t irq)
-{
-    hwsetup_add_u32(hw, 56); /* size */
-    hwsetup_add_tag(hw, HWSETUP_TAG_UART);
-    hwsetup_add_str(hw, name);
-    hwsetup_add_u32(hw, base);
-    hwsetup_add_u32(hw, 115200); /* baudrate */
-    hwsetup_add_u8(hw, 8); /* databits */
-    hwsetup_add_u8(hw, 1); /* stopbits */
-    hwsetup_add_u8(hw, 1); /* use_interrupt */
-    hwsetup_add_u8(hw, 1); /* block_on_transmit */
-    hwsetup_add_u8(hw, 1); /* block_on_receive */
-    hwsetup_add_u8(hw, 4); /* rx_buffer_size */
-    hwsetup_add_u8(hw, 4); /* tx_buffer_size */
-    hwsetup_add_u8(hw, irq);
-}
-
-#endif /* QEMU_HW_LM32_HWSETUP_H */
diff --git a/hw/lm32_juart.c b/hw/lm32_juart.c
deleted file mode 100644 (file)
index 472e9c2..0000000
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- *  LatticeMico32 JTAG UART model.
- *
- *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
- *
- * 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/hw.h"
-#include "hw/sysbus.h"
-#include "trace.h"
-#include "char/char.h"
-
-#include "hw/lm32_juart.h"
-
-enum {
-    LM32_JUART_MIN_SAVE_VERSION = 0,
-    LM32_JUART_CURRENT_SAVE_VERSION = 0,
-    LM32_JUART_MAX_SAVE_VERSION = 0,
-};
-
-enum {
-    JTX_FULL = (1<<8),
-};
-
-enum {
-    JRX_FULL = (1<<8),
-};
-
-struct LM32JuartState {
-    SysBusDevice busdev;
-    CharDriverState *chr;
-
-    uint32_t jtx;
-    uint32_t jrx;
-};
-typedef struct LM32JuartState LM32JuartState;
-
-uint32_t lm32_juart_get_jtx(DeviceState *d)
-{
-    LM32JuartState *s = container_of(d, LM32JuartState, busdev.qdev);
-
-    trace_lm32_juart_get_jtx(s->jtx);
-    return s->jtx;
-}
-
-uint32_t lm32_juart_get_jrx(DeviceState *d)
-{
-    LM32JuartState *s = container_of(d, LM32JuartState, busdev.qdev);
-
-    trace_lm32_juart_get_jrx(s->jrx);
-    return s->jrx;
-}
-
-void lm32_juart_set_jtx(DeviceState *d, uint32_t jtx)
-{
-    LM32JuartState *s = container_of(d, LM32JuartState, busdev.qdev);
-    unsigned char ch = jtx & 0xff;
-
-    trace_lm32_juart_set_jtx(s->jtx);
-
-    s->jtx = jtx;
-    if (s->chr) {
-        qemu_chr_fe_write(s->chr, &ch, 1);
-    }
-}
-
-void lm32_juart_set_jrx(DeviceState *d, uint32_t jtx)
-{
-    LM32JuartState *s = container_of(d, LM32JuartState, busdev.qdev);
-
-    trace_lm32_juart_set_jrx(s->jrx);
-    s->jrx &= ~JRX_FULL;
-}
-
-static void juart_rx(void *opaque, const uint8_t *buf, int size)
-{
-    LM32JuartState *s = opaque;
-
-    s->jrx = *buf | JRX_FULL;
-}
-
-static int juart_can_rx(void *opaque)
-{
-    LM32JuartState *s = opaque;
-
-    return !(s->jrx & JRX_FULL);
-}
-
-static void juart_event(void *opaque, int event)
-{
-}
-
-static void juart_reset(DeviceState *d)
-{
-    LM32JuartState *s = container_of(d, LM32JuartState, busdev.qdev);
-
-    s->jtx = 0;
-    s->jrx = 0;
-}
-
-static int lm32_juart_init(SysBusDevice *dev)
-{
-    LM32JuartState *s = FROM_SYSBUS(typeof(*s), dev);
-
-    s->chr = qemu_char_get_next_serial();
-    if (s->chr) {
-        qemu_chr_add_handlers(s->chr, juart_can_rx, juart_rx, juart_event, s);
-    }
-
-    return 0;
-}
-
-static const VMStateDescription vmstate_lm32_juart = {
-    .name = "lm32-juart",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField[]) {
-        VMSTATE_UINT32(jtx, LM32JuartState),
-        VMSTATE_UINT32(jrx, LM32JuartState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-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 const 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_types(void)
-{
-    type_register_static(&lm32_juart_info);
-}
-
-type_init(lm32_juart_register_types)
diff --git a/hw/lm32_juart.h b/hw/lm32_juart.h
deleted file mode 100644 (file)
index 67fc586..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-#ifndef QEMU_HW_LM32_JUART_H
-#define QEMU_HW_LM32_JUART_H
-
-#include "qemu-common.h"
-
-uint32_t lm32_juart_get_jtx(DeviceState *d);
-uint32_t lm32_juart_get_jrx(DeviceState *d);
-void lm32_juart_set_jtx(DeviceState *d, uint32_t jtx);
-void lm32_juart_set_jrx(DeviceState *d, uint32_t jrx);
-
-#endif /* QEMU_HW_LM32_JUART_H */
diff --git a/hw/lm32_pic.c b/hw/lm32_pic.c
deleted file mode 100644 (file)
index d17c310..0000000
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- *  LatticeMico32 CPU interrupt controller logic.
- *
- *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
- *
- * 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 <assert.h>
-
-#include "hw/hw.h"
-#include "hw/pc.h"
-#include "monitor/monitor.h"
-#include "hw/sysbus.h"
-#include "trace.h"
-#include "hw/lm32_pic.h"
-
-struct LM32PicState {
-    SysBusDevice busdev;
-    qemu_irq parent_irq;
-    uint32_t im;        /* interrupt mask */
-    uint32_t ip;        /* interrupt pending */
-    uint32_t irq_state;
-
-    /* statistics */
-    uint32_t stats_irq_count[32];
-};
-typedef struct LM32PicState LM32PicState;
-
-static LM32PicState *pic;
-void lm32_do_pic_info(Monitor *mon, const QDict *qdict)
-{
-    if (pic == NULL) {
-        return;
-    }
-
-    monitor_printf(mon, "lm32-pic: im=%08x ip=%08x irq_state=%08x\n",
-            pic->im, pic->ip, pic->irq_state);
-}
-
-void lm32_irq_info(Monitor *mon, const QDict *qdict)
-{
-    int i;
-    uint32_t count;
-
-    if (pic == NULL) {
-        return;
-    }
-
-    monitor_printf(mon, "IRQ statistics:\n");
-    for (i = 0; i < 32; i++) {
-        count = pic->stats_irq_count[i];
-        if (count > 0) {
-            monitor_printf(mon, "%2d: %u\n", i, count);
-        }
-    }
-}
-
-static void update_irq(LM32PicState *s)
-{
-    s->ip |= s->irq_state;
-
-    if (s->ip & s->im) {
-        trace_lm32_pic_raise_irq();
-        qemu_irq_raise(s->parent_irq);
-    } else {
-        trace_lm32_pic_lower_irq();
-        qemu_irq_lower(s->parent_irq);
-    }
-}
-
-static void irq_handler(void *opaque, int irq, int level)
-{
-    LM32PicState *s = opaque;
-
-    assert(irq < 32);
-    trace_lm32_pic_interrupt(irq, level);
-
-    if (level) {
-        s->irq_state |= (1 << irq);
-        s->stats_irq_count[irq]++;
-    } else {
-        s->irq_state &= ~(1 << irq);
-    }
-
-    update_irq(s);
-}
-
-void lm32_pic_set_im(DeviceState *d, uint32_t im)
-{
-    LM32PicState *s = container_of(d, LM32PicState, busdev.qdev);
-
-    trace_lm32_pic_set_im(im);
-    s->im = im;
-
-    update_irq(s);
-}
-
-void lm32_pic_set_ip(DeviceState *d, uint32_t ip)
-{
-    LM32PicState *s = container_of(d, LM32PicState, busdev.qdev);
-
-    trace_lm32_pic_set_ip(ip);
-
-    /* ack interrupt */
-    s->ip &= ~ip;
-
-    update_irq(s);
-}
-
-uint32_t lm32_pic_get_im(DeviceState *d)
-{
-    LM32PicState *s = container_of(d, LM32PicState, busdev.qdev);
-
-    trace_lm32_pic_get_im(s->im);
-    return s->im;
-}
-
-uint32_t lm32_pic_get_ip(DeviceState *d)
-{
-    LM32PicState *s = container_of(d, LM32PicState, busdev.qdev);
-
-    trace_lm32_pic_get_ip(s->ip);
-    return s->ip;
-}
-
-static void pic_reset(DeviceState *d)
-{
-    LM32PicState *s = container_of(d, LM32PicState, busdev.qdev);
-    int i;
-
-    s->im = 0;
-    s->ip = 0;
-    s->irq_state = 0;
-    for (i = 0; i < 32; i++) {
-        s->stats_irq_count[i] = 0;
-    }
-}
-
-static int lm32_pic_init(SysBusDevice *dev)
-{
-    LM32PicState *s = FROM_SYSBUS(typeof(*s), dev);
-
-    qdev_init_gpio_in(&dev->qdev, irq_handler, 32);
-    sysbus_init_irq(dev, &s->parent_irq);
-
-    pic = s;
-
-    return 0;
-}
-
-static const VMStateDescription vmstate_lm32_pic = {
-    .name = "lm32-pic",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField[]) {
-        VMSTATE_UINT32(im, LM32PicState),
-        VMSTATE_UINT32(ip, LM32PicState),
-        VMSTATE_UINT32(irq_state, LM32PicState),
-        VMSTATE_UINT32_ARRAY(stats_irq_count, LM32PicState, 32),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-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 const 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_types(void)
-{
-    type_register_static(&lm32_pic_info);
-}
-
-type_init(lm32_pic_register_types)
diff --git a/hw/lm32_pic.h b/hw/lm32_pic.h
deleted file mode 100644 (file)
index 5556803..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-#ifndef QEMU_HW_LM32_PIC_H
-#define QEMU_HW_LM32_PIC_H
-
-#include "qemu-common.h"
-
-uint32_t lm32_pic_get_ip(DeviceState *d);
-uint32_t lm32_pic_get_im(DeviceState *d);
-void lm32_pic_set_ip(DeviceState *d, uint32_t ip);
-void lm32_pic_set_im(DeviceState *d, uint32_t im);
-
-void lm32_do_pic_info(Monitor *mon, const QDict *qdict);
-void lm32_irq_info(Monitor *mon, const QDict *qdict);
-
-#endif /* QEMU_HW_LM32_PIC_H */
diff --git a/hw/lm32_sys.c b/hw/lm32_sys.c
deleted file mode 100644 (file)
index 33a3b80..0000000
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- *  QEMU model of the LatticeMico32 system control block.
- *
- *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
- *
- * 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/>.
- */
-
-/*
- * This model is mainly intended for testing purposes and doesn't fit to any
- * real hardware. On the one hand it provides a control register (R_CTRL) on
- * the other hand it supports the lm32 tests.
- *
- * A write to the control register causes a system shutdown.
- * Tests first write the pointer to a test name to the test name register
- * (R_TESTNAME) and then write a zero to the pass/fail register (R_PASSFAIL) if
- * the test is passed or any non-zero value to it if the test is failed.
- */
-
-#include "hw/hw.h"
-#include "hw/sysbus.h"
-#include "trace.h"
-#include "qemu/log.h"
-#include "qemu/error-report.h"
-#include "sysemu/sysemu.h"
-#include "qemu/log.h"
-
-enum {
-    R_CTRL = 0,
-    R_PASSFAIL,
-    R_TESTNAME,
-    R_MAX
-};
-
-#define MAX_TESTNAME_LEN 16
-
-struct LM32SysState {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-    uint32_t base;
-    uint32_t regs[R_MAX];
-    uint8_t testname[MAX_TESTNAME_LEN];
-};
-typedef struct LM32SysState LM32SysState;
-
-static void copy_testname(LM32SysState *s)
-{
-    cpu_physical_memory_read(s->regs[R_TESTNAME], s->testname,
-            MAX_TESTNAME_LEN);
-    s->testname[MAX_TESTNAME_LEN - 1] = '\0';
-}
-
-static void sys_write(void *opaque, hwaddr addr,
-                      uint64_t value, unsigned size)
-{
-    LM32SysState *s = opaque;
-    char *testname;
-
-    trace_lm32_sys_memory_write(addr, value);
-
-    addr >>= 2;
-    switch (addr) {
-    case R_CTRL:
-        qemu_system_shutdown_request();
-        break;
-    case R_PASSFAIL:
-        s->regs[addr] = value;
-        testname = (char *)s->testname;
-        qemu_log("TC  %-16s %s\n", testname, (value) ? "FAILED" : "OK");
-        break;
-    case R_TESTNAME:
-        s->regs[addr] = value;
-        copy_testname(s);
-        break;
-
-    default:
-        error_report("lm32_sys: write access to unknown register 0x"
-                TARGET_FMT_plx, addr << 2);
-        break;
-    }
-}
-
-static bool sys_ops_accepts(void *opaque, hwaddr addr,
-                            unsigned size, bool is_write)
-{
-    return is_write && size == 4;
-}
-
-static const MemoryRegionOps sys_ops = {
-    .write = sys_write,
-    .valid.accepts = sys_ops_accepts,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void sys_reset(DeviceState *d)
-{
-    LM32SysState *s = container_of(d, LM32SysState, busdev.qdev);
-    int i;
-
-    for (i = 0; i < R_MAX; i++) {
-        s->regs[i] = 0;
-    }
-    memset(s->testname, 0, MAX_TESTNAME_LEN);
-}
-
-static int lm32_sys_init(SysBusDevice *dev)
-{
-    LM32SysState *s = FROM_SYSBUS(typeof(*s), dev);
-
-    memory_region_init_io(&s->iomem, &sys_ops , s, "sys", R_MAX * 4);
-    sysbus_init_mmio(dev, &s->iomem);
-
-    /* Note: This device is not created in the board initialization,
-     * instead it has to be added with the -device parameter. Therefore,
-     * the device maps itself. */
-    sysbus_mmio_map(dev, 0, s->base);
-
-    return 0;
-}
-
-static const VMStateDescription vmstate_lm32_sys = {
-    .name = "lm32-sys",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField[]) {
-        VMSTATE_UINT32_ARRAY(regs, LM32SysState, R_MAX),
-        VMSTATE_BUFFER(testname, LM32SysState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static Property lm32_sys_properties[] = {
-    DEFINE_PROP_UINT32("base", LM32SysState, base, 0xffff0000),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void lm32_sys_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = lm32_sys_init;
-    dc->reset = sys_reset;
-    dc->vmsd = &vmstate_lm32_sys;
-    dc->props = lm32_sys_properties;
-}
-
-static const 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_types(void)
-{
-    type_register_static(&lm32_sys_info);
-}
-
-type_init(lm32_sys_register_types)
diff --git a/hw/lm32_timer.c b/hw/lm32_timer.c
deleted file mode 100644 (file)
index e06fac7..0000000
+++ /dev/null
@@ -1,230 +0,0 @@
-/*
- *  QEMU model of the LatticeMico32 timer block.
- *
- *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
- *
- * 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/>.
- *
- *
- * Specification available at:
- *   http://www.latticesemi.com/documents/mico32timer.pdf
- */
-
-#include "hw/hw.h"
-#include "hw/sysbus.h"
-#include "trace.h"
-#include "qemu/timer.h"
-#include "hw/ptimer.h"
-#include "qemu/error-report.h"
-
-#define DEFAULT_FREQUENCY (50*1000000)
-
-enum {
-    R_SR = 0,
-    R_CR,
-    R_PERIOD,
-    R_SNAPSHOT,
-    R_MAX
-};
-
-enum {
-    SR_TO    = (1 << 0),
-    SR_RUN   = (1 << 1),
-};
-
-enum {
-    CR_ITO   = (1 << 0),
-    CR_CONT  = (1 << 1),
-    CR_START = (1 << 2),
-    CR_STOP  = (1 << 3),
-};
-
-struct LM32TimerState {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-
-    QEMUBH *bh;
-    ptimer_state *ptimer;
-
-    qemu_irq irq;
-    uint32_t freq_hz;
-
-    uint32_t regs[R_MAX];
-};
-typedef struct LM32TimerState LM32TimerState;
-
-static void timer_update_irq(LM32TimerState *s)
-{
-    int state = (s->regs[R_SR] & SR_TO) && (s->regs[R_CR] & CR_ITO);
-
-    trace_lm32_timer_irq_state(state);
-    qemu_set_irq(s->irq, state);
-}
-
-static uint64_t timer_read(void *opaque, hwaddr addr, unsigned size)
-{
-    LM32TimerState *s = opaque;
-    uint32_t r = 0;
-
-    addr >>= 2;
-    switch (addr) {
-    case R_SR:
-    case R_CR:
-    case R_PERIOD:
-        r = s->regs[addr];
-        break;
-    case R_SNAPSHOT:
-        r = (uint32_t)ptimer_get_count(s->ptimer);
-        break;
-    default:
-        error_report("lm32_timer: read access to unknown register 0x"
-                TARGET_FMT_plx, addr << 2);
-        break;
-    }
-
-    trace_lm32_timer_memory_read(addr << 2, r);
-    return r;
-}
-
-static void timer_write(void *opaque, hwaddr addr,
-                        uint64_t value, unsigned size)
-{
-    LM32TimerState *s = opaque;
-
-    trace_lm32_timer_memory_write(addr, value);
-
-    addr >>= 2;
-    switch (addr) {
-    case R_SR:
-        s->regs[R_SR] &= ~SR_TO;
-        break;
-    case R_CR:
-        s->regs[R_CR] = value;
-        if (s->regs[R_CR] & CR_START) {
-            ptimer_run(s->ptimer, 1);
-        }
-        if (s->regs[R_CR] & CR_STOP) {
-            ptimer_stop(s->ptimer);
-        }
-        break;
-    case R_PERIOD:
-        s->regs[R_PERIOD] = value;
-        ptimer_set_count(s->ptimer, value);
-        break;
-    case R_SNAPSHOT:
-        error_report("lm32_timer: write access to read only register 0x"
-                TARGET_FMT_plx, addr << 2);
-        break;
-    default:
-        error_report("lm32_timer: write access to unknown register 0x"
-                TARGET_FMT_plx, addr << 2);
-        break;
-    }
-    timer_update_irq(s);
-}
-
-static const MemoryRegionOps timer_ops = {
-    .read = timer_read,
-    .write = timer_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-};
-
-static void timer_hit(void *opaque)
-{
-    LM32TimerState *s = opaque;
-
-    trace_lm32_timer_hit();
-
-    s->regs[R_SR] |= SR_TO;
-
-    if (s->regs[R_CR] & CR_CONT) {
-        ptimer_set_count(s->ptimer, s->regs[R_PERIOD]);
-        ptimer_run(s->ptimer, 1);
-    }
-    timer_update_irq(s);
-}
-
-static void timer_reset(DeviceState *d)
-{
-    LM32TimerState *s = container_of(d, LM32TimerState, busdev.qdev);
-    int i;
-
-    for (i = 0; i < R_MAX; i++) {
-        s->regs[i] = 0;
-    }
-    ptimer_stop(s->ptimer);
-}
-
-static int lm32_timer_init(SysBusDevice *dev)
-{
-    LM32TimerState *s = FROM_SYSBUS(typeof(*s), dev);
-
-    sysbus_init_irq(dev, &s->irq);
-
-    s->bh = qemu_bh_new(timer_hit, s);
-    s->ptimer = ptimer_init(s->bh);
-    ptimer_set_freq(s->ptimer, s->freq_hz);
-
-    memory_region_init_io(&s->iomem, &timer_ops, s, "timer", R_MAX * 4);
-    sysbus_init_mmio(dev, &s->iomem);
-
-    return 0;
-}
-
-static const VMStateDescription vmstate_lm32_timer = {
-    .name = "lm32-timer",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField[]) {
-        VMSTATE_PTIMER(ptimer, LM32TimerState),
-        VMSTATE_UINT32(freq_hz, LM32TimerState),
-        VMSTATE_UINT32_ARRAY(regs, LM32TimerState, R_MAX),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static Property lm32_timer_properties[] = {
-    DEFINE_PROP_UINT32("frequency", LM32TimerState, freq_hz, DEFAULT_FREQUENCY),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void lm32_timer_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = lm32_timer_init;
-    dc->reset = timer_reset;
-    dc->vmsd = &vmstate_lm32_timer;
-    dc->props = lm32_timer_properties;
-}
-
-static const 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_types(void)
-{
-    type_register_static(&lm32_timer_info);
-}
-
-type_init(lm32_timer_register_types)
diff --git a/hw/lm32_uart.c b/hw/lm32_uart.c
deleted file mode 100644 (file)
index 32bc37a..0000000
+++ /dev/null
@@ -1,297 +0,0 @@
-/*
- *  QEMU model of the LatticeMico32 UART block.
- *
- *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
- *
- * 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/>.
- *
- *
- * Specification available at:
- *   http://www.latticesemi.com/documents/mico32uart.pdf
- */
-
-
-#include "hw/hw.h"
-#include "hw/sysbus.h"
-#include "trace.h"
-#include "char/char.h"
-#include "qemu/error-report.h"
-
-enum {
-    R_RXTX = 0,
-    R_IER,
-    R_IIR,
-    R_LCR,
-    R_MCR,
-    R_LSR,
-    R_MSR,
-    R_DIV,
-    R_MAX
-};
-
-enum {
-    IER_RBRI = (1<<0),
-    IER_THRI = (1<<1),
-    IER_RLSI = (1<<2),
-    IER_MSI  = (1<<3),
-};
-
-enum {
-    IIR_STAT = (1<<0),
-    IIR_ID0  = (1<<1),
-    IIR_ID1  = (1<<2),
-};
-
-enum {
-    LCR_WLS0 = (1<<0),
-    LCR_WLS1 = (1<<1),
-    LCR_STB  = (1<<2),
-    LCR_PEN  = (1<<3),
-    LCR_EPS  = (1<<4),
-    LCR_SP   = (1<<5),
-    LCR_SB   = (1<<6),
-};
-
-enum {
-    MCR_DTR  = (1<<0),
-    MCR_RTS  = (1<<1),
-};
-
-enum {
-    LSR_DR   = (1<<0),
-    LSR_OE   = (1<<1),
-    LSR_PE   = (1<<2),
-    LSR_FE   = (1<<3),
-    LSR_BI   = (1<<4),
-    LSR_THRE = (1<<5),
-    LSR_TEMT = (1<<6),
-};
-
-enum {
-    MSR_DCTS = (1<<0),
-    MSR_DDSR = (1<<1),
-    MSR_TERI = (1<<2),
-    MSR_DDCD = (1<<3),
-    MSR_CTS  = (1<<4),
-    MSR_DSR  = (1<<5),
-    MSR_RI   = (1<<6),
-    MSR_DCD  = (1<<7),
-};
-
-struct LM32UartState {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-    CharDriverState *chr;
-    qemu_irq irq;
-
-    uint32_t regs[R_MAX];
-};
-typedef struct LM32UartState LM32UartState;
-
-static void uart_update_irq(LM32UartState *s)
-{
-    unsigned int irq;
-
-    if ((s->regs[R_LSR] & (LSR_OE | LSR_PE | LSR_FE | LSR_BI))
-            && (s->regs[R_IER] & IER_RLSI)) {
-        irq = 1;
-        s->regs[R_IIR] = IIR_ID1 | IIR_ID0;
-    } else if ((s->regs[R_LSR] & LSR_DR) && (s->regs[R_IER] & IER_RBRI)) {
-        irq = 1;
-        s->regs[R_IIR] = IIR_ID1;
-    } else if ((s->regs[R_LSR] & LSR_THRE) && (s->regs[R_IER] & IER_THRI)) {
-        irq = 1;
-        s->regs[R_IIR] = IIR_ID0;
-    } else if ((s->regs[R_MSR] & 0x0f) && (s->regs[R_IER] & IER_MSI)) {
-        irq = 1;
-        s->regs[R_IIR] = 0;
-    } else {
-        irq = 0;
-        s->regs[R_IIR] = IIR_STAT;
-    }
-
-    trace_lm32_uart_irq_state(irq);
-    qemu_set_irq(s->irq, irq);
-}
-
-static uint64_t uart_read(void *opaque, hwaddr addr,
-                          unsigned size)
-{
-    LM32UartState *s = opaque;
-    uint32_t r = 0;
-
-    addr >>= 2;
-    switch (addr) {
-    case R_RXTX:
-        r = s->regs[R_RXTX];
-        s->regs[R_LSR] &= ~LSR_DR;
-        uart_update_irq(s);
-        qemu_chr_accept_input(s->chr);
-        break;
-    case R_IIR:
-    case R_LSR:
-    case R_MSR:
-        r = s->regs[addr];
-        break;
-    case R_IER:
-    case R_LCR:
-    case R_MCR:
-    case R_DIV:
-        error_report("lm32_uart: read access to write only register 0x"
-                TARGET_FMT_plx, addr << 2);
-        break;
-    default:
-        error_report("lm32_uart: read access to unknown register 0x"
-                TARGET_FMT_plx, addr << 2);
-        break;
-    }
-
-    trace_lm32_uart_memory_read(addr << 2, r);
-    return r;
-}
-
-static void uart_write(void *opaque, hwaddr addr,
-                       uint64_t value, unsigned size)
-{
-    LM32UartState *s = opaque;
-    unsigned char ch = value;
-
-    trace_lm32_uart_memory_write(addr, value);
-
-    addr >>= 2;
-    switch (addr) {
-    case R_RXTX:
-        if (s->chr) {
-            qemu_chr_fe_write(s->chr, &ch, 1);
-        }
-        break;
-    case R_IER:
-    case R_LCR:
-    case R_MCR:
-    case R_DIV:
-        s->regs[addr] = value;
-        break;
-    case R_IIR:
-    case R_LSR:
-    case R_MSR:
-        error_report("lm32_uart: write access to read only register 0x"
-                TARGET_FMT_plx, addr << 2);
-        break;
-    default:
-        error_report("lm32_uart: write access to unknown register 0x"
-                TARGET_FMT_plx, addr << 2);
-        break;
-    }
-    uart_update_irq(s);
-}
-
-static const MemoryRegionOps uart_ops = {
-    .read = uart_read,
-    .write = uart_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-};
-
-static void uart_rx(void *opaque, const uint8_t *buf, int size)
-{
-    LM32UartState *s = opaque;
-
-    if (s->regs[R_LSR] & LSR_DR) {
-        s->regs[R_LSR] |= LSR_OE;
-    }
-
-    s->regs[R_LSR] |= LSR_DR;
-    s->regs[R_RXTX] = *buf;
-
-    uart_update_irq(s);
-}
-
-static int uart_can_rx(void *opaque)
-{
-    LM32UartState *s = opaque;
-
-    return !(s->regs[R_LSR] & LSR_DR);
-}
-
-static void uart_event(void *opaque, int event)
-{
-}
-
-static void uart_reset(DeviceState *d)
-{
-    LM32UartState *s = container_of(d, LM32UartState, busdev.qdev);
-    int i;
-
-    for (i = 0; i < R_MAX; i++) {
-        s->regs[i] = 0;
-    }
-
-    /* defaults */
-    s->regs[R_LSR] = LSR_THRE | LSR_TEMT;
-}
-
-static int lm32_uart_init(SysBusDevice *dev)
-{
-    LM32UartState *s = FROM_SYSBUS(typeof(*s), dev);
-
-    sysbus_init_irq(dev, &s->irq);
-
-    memory_region_init_io(&s->iomem, &uart_ops, s, "uart", R_MAX * 4);
-    sysbus_init_mmio(dev, &s->iomem);
-
-    s->chr = qemu_char_get_next_serial();
-    if (s->chr) {
-        qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s);
-    }
-
-    return 0;
-}
-
-static const VMStateDescription vmstate_lm32_uart = {
-    .name = "lm32-uart",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField[]) {
-        VMSTATE_UINT32_ARRAY(regs, LM32UartState, R_MAX),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-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 const 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_types(void)
-{
-    type_register_static(&lm32_uart_info);
-}
-
-type_init(lm32_uart_register_types)
diff --git a/hw/lm4549.c b/hw/lm4549.c
deleted file mode 100644 (file)
index 67335cb..0000000
+++ /dev/null
@@ -1,336 +0,0 @@
-/*
- * LM4549 Audio Codec Interface
- *
- * Copyright (c) 2011
- * Written by Mathieu Sonet - www.elasticsheep.com
- *
- * This code is licensed under the GPL.
- *
- * *****************************************************************
- *
- * This driver emulates the LM4549 codec.
- *
- * It supports only one playback voice and no record voice.
- */
-
-#include "hw/hw.h"
-#include "audio/audio.h"
-#include "hw/lm4549.h"
-
-#if 0
-#define LM4549_DEBUG  1
-#endif
-
-#if 0
-#define LM4549_DUMP_DAC_INPUT 1
-#endif
-
-#ifdef LM4549_DEBUG
-#define DPRINTF(fmt, ...) \
-do { printf("lm4549: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...) do {} while (0)
-#endif
-
-#if defined(LM4549_DUMP_DAC_INPUT)
-#include <stdio.h>
-static FILE *fp_dac_input;
-#endif
-
-/* LM4549 register list */
-enum {
-    LM4549_Reset                    = 0x00,
-    LM4549_Master_Volume            = 0x02,
-    LM4549_Line_Out_Volume          = 0x04,
-    LM4549_Master_Volume_Mono       = 0x06,
-    LM4549_PC_Beep_Volume           = 0x0A,
-    LM4549_Phone_Volume             = 0x0C,
-    LM4549_Mic_Volume               = 0x0E,
-    LM4549_Line_In_Volume           = 0x10,
-    LM4549_CD_Volume                = 0x12,
-    LM4549_Video_Volume             = 0x14,
-    LM4549_Aux_Volume               = 0x16,
-    LM4549_PCM_Out_Volume           = 0x18,
-    LM4549_Record_Select            = 0x1A,
-    LM4549_Record_Gain              = 0x1C,
-    LM4549_General_Purpose          = 0x20,
-    LM4549_3D_Control               = 0x22,
-    LM4549_Powerdown_Ctrl_Stat      = 0x26,
-    LM4549_Ext_Audio_ID             = 0x28,
-    LM4549_Ext_Audio_Stat_Ctrl      = 0x2A,
-    LM4549_PCM_Front_DAC_Rate       = 0x2C,
-    LM4549_PCM_ADC_Rate             = 0x32,
-    LM4549_Vendor_ID1               = 0x7C,
-    LM4549_Vendor_ID2               = 0x7E
-};
-
-static void lm4549_reset(lm4549_state *s)
-{
-    uint16_t *regfile = s->regfile;
-
-    regfile[LM4549_Reset]               = 0x0d50;
-    regfile[LM4549_Master_Volume]       = 0x8008;
-    regfile[LM4549_Line_Out_Volume]     = 0x8000;
-    regfile[LM4549_Master_Volume_Mono]  = 0x8000;
-    regfile[LM4549_PC_Beep_Volume]      = 0x0000;
-    regfile[LM4549_Phone_Volume]        = 0x8008;
-    regfile[LM4549_Mic_Volume]          = 0x8008;
-    regfile[LM4549_Line_In_Volume]      = 0x8808;
-    regfile[LM4549_CD_Volume]           = 0x8808;
-    regfile[LM4549_Video_Volume]        = 0x8808;
-    regfile[LM4549_Aux_Volume]          = 0x8808;
-    regfile[LM4549_PCM_Out_Volume]      = 0x8808;
-    regfile[LM4549_Record_Select]       = 0x0000;
-    regfile[LM4549_Record_Gain]         = 0x8000;
-    regfile[LM4549_General_Purpose]     = 0x0000;
-    regfile[LM4549_3D_Control]          = 0x0101;
-    regfile[LM4549_Powerdown_Ctrl_Stat] = 0x000f;
-    regfile[LM4549_Ext_Audio_ID]        = 0x0001;
-    regfile[LM4549_Ext_Audio_Stat_Ctrl] = 0x0000;
-    regfile[LM4549_PCM_Front_DAC_Rate]  = 0xbb80;
-    regfile[LM4549_PCM_ADC_Rate]        = 0xbb80;
-    regfile[LM4549_Vendor_ID1]          = 0x4e53;
-    regfile[LM4549_Vendor_ID2]          = 0x4331;
-}
-
-static void lm4549_audio_transfer(lm4549_state *s)
-{
-    uint32_t written_bytes, written_samples;
-    uint32_t i;
-
-    /* Activate the voice */
-    AUD_set_active_out(s->voice, 1);
-    s->voice_is_active = 1;
-
-    /* Try to write the buffer content */
-    written_bytes = AUD_write(s->voice, s->buffer,
-                              s->buffer_level * sizeof(uint16_t));
-    written_samples = written_bytes >> 1;
-
-#if defined(LM4549_DUMP_DAC_INPUT)
-    fwrite(s->buffer, sizeof(uint8_t), written_bytes, fp_dac_input);
-#endif
-
-    s->buffer_level -= written_samples;
-
-    if (s->buffer_level > 0) {
-        /* Move the data back to the start of the buffer */
-        for (i = 0; i < s->buffer_level; i++) {
-            s->buffer[i] = s->buffer[i + written_samples];
-        }
-    }
-}
-
-static void lm4549_audio_out_callback(void *opaque, int free)
-{
-    lm4549_state *s = (lm4549_state *)opaque;
-    static uint32_t prev_buffer_level;
-
-#ifdef LM4549_DEBUG
-    int size = AUD_get_buffer_size_out(s->voice);
-    DPRINTF("audio_out_callback size = %i free = %i\n", size, free);
-#endif
-
-    /* Detect that no data are consumed
-       => disable the voice */
-    if (s->buffer_level == prev_buffer_level) {
-        AUD_set_active_out(s->voice, 0);
-        s->voice_is_active = 0;
-    }
-    prev_buffer_level = s->buffer_level;
-
-    /* Check if a buffer transfer is pending */
-    if (s->buffer_level == LM4549_BUFFER_SIZE) {
-        lm4549_audio_transfer(s);
-
-        /* Request more data */
-        if (s->data_req_cb != NULL) {
-            (s->data_req_cb)(s->opaque);
-        }
-    }
-}
-
-uint32_t lm4549_read(lm4549_state *s, hwaddr offset)
-{
-    uint16_t *regfile = s->regfile;
-    uint32_t value = 0;
-
-    /* Read the stored value */
-    assert(offset < 128);
-    value = regfile[offset];
-
-    DPRINTF("read [0x%02x] = 0x%04x\n", offset, value);
-
-    return value;
-}
-
-void lm4549_write(lm4549_state *s,
-                  hwaddr offset, uint32_t value)
-{
-    uint16_t *regfile = s->regfile;
-
-    assert(offset < 128);
-    DPRINTF("write [0x%02x] = 0x%04x\n", offset, value);
-
-    switch (offset) {
-    case LM4549_Reset:
-        lm4549_reset(s);
-        break;
-
-    case LM4549_PCM_Front_DAC_Rate:
-        regfile[LM4549_PCM_Front_DAC_Rate] = value;
-        DPRINTF("DAC rate change = %i\n", value);
-
-        /* Re-open a voice with the new sample rate */
-        struct audsettings as;
-        as.freq = value;
-        as.nchannels = 2;
-        as.fmt = AUD_FMT_S16;
-        as.endianness = 0;
-
-        s->voice = AUD_open_out(
-            &s->card,
-            s->voice,
-            "lm4549.out",
-            s,
-            lm4549_audio_out_callback,
-            &as
-        );
-        break;
-
-    case LM4549_Powerdown_Ctrl_Stat:
-        value &= ~0xf;
-        value |= regfile[LM4549_Powerdown_Ctrl_Stat] & 0xf;
-        regfile[LM4549_Powerdown_Ctrl_Stat] = value;
-        break;
-
-    case LM4549_Ext_Audio_ID:
-    case LM4549_Vendor_ID1:
-    case LM4549_Vendor_ID2:
-        DPRINTF("Write to read-only register 0x%x\n", (int)offset);
-        break;
-
-    default:
-        /* Store the new value */
-        regfile[offset] = value;
-        break;
-    }
-}
-
-uint32_t lm4549_write_samples(lm4549_state *s, uint32_t left, uint32_t right)
-{
-    /* The left and right samples are in 20-bit resolution.
-       The LM4549 has 18-bit resolution and only uses the bits [19:2].
-       This model supports 16-bit playback.
-    */
-
-    if (s->buffer_level > LM4549_BUFFER_SIZE - 2) {
-        DPRINTF("write_sample Buffer full\n");
-        return 0;
-    }
-
-    /* Store 16-bit samples in the buffer */
-    s->buffer[s->buffer_level++] = (left >> 4);
-    s->buffer[s->buffer_level++] = (right >> 4);
-
-    if (s->buffer_level == LM4549_BUFFER_SIZE) {
-        /* Trigger the transfer of the buffer to the audio host */
-        lm4549_audio_transfer(s);
-    }
-
-    return 1;
-}
-
-static int lm4549_post_load(void *opaque, int version_id)
-{
-    lm4549_state *s = (lm4549_state *)opaque;
-    uint16_t *regfile = s->regfile;
-
-    /* Re-open a voice with the current sample rate */
-    uint32_t freq = regfile[LM4549_PCM_Front_DAC_Rate];
-
-    DPRINTF("post_load freq = %i\n", freq);
-    DPRINTF("post_load voice_is_active = %i\n", s->voice_is_active);
-
-    struct audsettings as;
-    as.freq = freq;
-    as.nchannels = 2;
-    as.fmt = AUD_FMT_S16;
-    as.endianness = 0;
-
-    s->voice = AUD_open_out(
-        &s->card,
-        s->voice,
-        "lm4549.out",
-        s,
-        lm4549_audio_out_callback,
-        &as
-    );
-
-    /* Request data */
-    if (s->voice_is_active == 1) {
-        lm4549_audio_out_callback(s, AUD_get_buffer_size_out(s->voice));
-    }
-
-    return 0;
-}
-
-void lm4549_init(lm4549_state *s, lm4549_callback data_req_cb, void* opaque)
-{
-    struct audsettings as;
-
-    /* Store the callback and opaque pointer */
-    s->data_req_cb = data_req_cb;
-    s->opaque = opaque;
-
-    /* Init the registers */
-    lm4549_reset(s);
-
-    /* Register an audio card */
-    AUD_register_card("lm4549", &s->card);
-
-    /* Open a default voice */
-    as.freq = 48000;
-    as.nchannels = 2;
-    as.fmt = AUD_FMT_S16;
-    as.endianness = 0;
-
-    s->voice = AUD_open_out(
-        &s->card,
-        s->voice,
-        "lm4549.out",
-        s,
-        lm4549_audio_out_callback,
-        &as
-    );
-
-    AUD_set_volume_out(s->voice, 0, 255, 255);
-
-    s->voice_is_active = 0;
-
-    /* Reset the input buffer */
-    memset(s->buffer, 0x00, sizeof(s->buffer));
-    s->buffer_level = 0;
-
-#if defined(LM4549_DUMP_DAC_INPUT)
-    fp_dac_input = fopen("lm4549_dac_input.pcm", "wb");
-    if (!fp_dac_input) {
-        hw_error("Unable to open lm4549_dac_input.pcm for writing\n");
-    }
-#endif
-}
-
-const VMStateDescription vmstate_lm4549_state = {
-    .name = "lm4549_state",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .post_load = &lm4549_post_load,
-    .fields      = (VMStateField[]) {
-        VMSTATE_UINT32(voice_is_active, lm4549_state),
-        VMSTATE_UINT16_ARRAY(regfile, lm4549_state, 128),
-        VMSTATE_UINT16_ARRAY(buffer, lm4549_state, LM4549_BUFFER_SIZE),
-        VMSTATE_UINT32(buffer_level, lm4549_state),
-        VMSTATE_END_OF_LIST()
-    }
-};
diff --git a/hw/lm4549.h b/hw/lm4549.h
deleted file mode 100644 (file)
index 812a7a4..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * LM4549 Audio Codec Interface
- *
- * Copyright (c) 2011
- * Written by Mathieu Sonet - www.elasticsheep.com
- *
- * This code is licensed under the GPL.
- *
- * *****************************************************************
- */
-
-#ifndef HW_LM4549_H
-#define HW_LM4549_H
-
-#include "audio/audio.h"
-
-typedef void (*lm4549_callback)(void *opaque);
-
-#define LM4549_BUFFER_SIZE (512 * 2) /* 512 16-bit stereo samples */
-
-
-typedef struct {
-    QEMUSoundCard card;
-    SWVoiceOut *voice;
-    uint32_t voice_is_active;
-
-    uint16_t regfile[128];
-    lm4549_callback data_req_cb;
-    void *opaque;
-
-    uint16_t buffer[LM4549_BUFFER_SIZE];
-    uint32_t buffer_level;
-} lm4549_state;
-
-extern const VMStateDescription vmstate_lm4549_state;
-
-
-void lm4549_init(lm4549_state *s, lm4549_callback data_req, void *opaque);
-uint32_t lm4549_read(lm4549_state *s, hwaddr offset);
-void lm4549_write(lm4549_state *s, hwaddr offset, uint32_t value);
-uint32_t lm4549_write_samples(lm4549_state *s, uint32_t left, uint32_t right);
-
-#endif /* #ifndef HW_LM4549_H */
diff --git a/hw/lm832x.c b/hw/lm832x.c
deleted file mode 100644 (file)
index a064dfd..0000000
+++ /dev/null
@@ -1,521 +0,0 @@
-/*
- * National Semiconductor LM8322/8323 GPIO keyboard & PWM chips.
- *
- * Copyright (C) 2008 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.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 or
- * (at your option) version 3 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
- * 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 "hw/hw.h"
-#include "hw/i2c.h"
-#include "qemu/timer.h"
-#include "ui/console.h"
-
-typedef struct {
-    I2CSlave i2c;
-    uint8_t i2c_dir;
-    uint8_t i2c_cycle;
-    uint8_t reg;
-
-    qemu_irq nirq;
-    uint16_t model;
-
-    struct {
-        qemu_irq out[2];
-        int in[2][2];
-    } mux;
-
-    uint8_t config;
-    uint8_t status;
-    uint8_t acttime;
-    uint8_t error;
-    uint8_t clock;
-
-    struct {
-        uint16_t pull;
-        uint16_t mask;
-        uint16_t dir;
-        uint16_t level;
-        qemu_irq out[16];
-    } gpio;
-
-    struct {
-        uint8_t dbnctime;
-        uint8_t size;
-        uint8_t start;
-        uint8_t len;
-        uint8_t fifo[16];
-    } kbd;
-
-    struct {
-        uint16_t file[256];
-       uint8_t faddr;
-        uint8_t addr[3];
-        QEMUTimer *tm[3];
-    } pwm;
-} LM823KbdState;
-
-#define INT_KEYPAD             (1 << 0)
-#define INT_ERROR              (1 << 3)
-#define INT_NOINIT             (1 << 4)
-#define INT_PWMEND(n)          (1 << (5 + n))
-
-#define ERR_BADPAR             (1 << 0)
-#define ERR_CMDUNK             (1 << 1)
-#define ERR_KEYOVR             (1 << 2)
-#define ERR_FIFOOVR            (1 << 6)
-
-static void lm_kbd_irq_update(LM823KbdState *s)
-{
-    qemu_set_irq(s->nirq, !s->status);
-}
-
-static void lm_kbd_gpio_update(LM823KbdState *s)
-{
-}
-
-static void lm_kbd_reset(LM823KbdState *s)
-{
-    s->config = 0x80;
-    s->status = INT_NOINIT;
-    s->acttime = 125;
-    s->kbd.dbnctime = 3;
-    s->kbd.size = 0x33;
-    s->clock = 0x08;
-
-    lm_kbd_irq_update(s);
-    lm_kbd_gpio_update(s);
-}
-
-static void lm_kbd_error(LM823KbdState *s, int err)
-{
-    s->error |= err;
-    s->status |= INT_ERROR;
-    lm_kbd_irq_update(s);
-}
-
-static void lm_kbd_pwm_tick(LM823KbdState *s, int line)
-{
-}
-
-static void lm_kbd_pwm_start(LM823KbdState *s, int line)
-{
-    lm_kbd_pwm_tick(s, line);
-}
-
-static void lm_kbd_pwm0_tick(void *opaque)
-{
-    lm_kbd_pwm_tick(opaque, 0);
-}
-static void lm_kbd_pwm1_tick(void *opaque)
-{
-    lm_kbd_pwm_tick(opaque, 1);
-}
-static void lm_kbd_pwm2_tick(void *opaque)
-{
-    lm_kbd_pwm_tick(opaque, 2);
-}
-
-enum {
-    LM832x_CMD_READ_ID         = 0x80, /* Read chip ID. */
-    LM832x_CMD_WRITE_CFG       = 0x81, /* Set configuration item. */
-    LM832x_CMD_READ_INT                = 0x82, /* Get interrupt status. */
-    LM832x_CMD_RESET           = 0x83, /* Reset, same as external one */
-    LM823x_CMD_WRITE_PULL_DOWN = 0x84, /* Select GPIO pull-up/down. */
-    LM832x_CMD_WRITE_PORT_SEL  = 0x85, /* Select GPIO in/out. */
-    LM832x_CMD_WRITE_PORT_STATE        = 0x86, /* Set GPIO pull-up/down. */
-    LM832x_CMD_READ_PORT_SEL   = 0x87, /* Get GPIO in/out. */
-    LM832x_CMD_READ_PORT_STATE = 0x88, /* Get GPIO pull-up/down. */
-    LM832x_CMD_READ_FIFO       = 0x89, /* Read byte from FIFO. */
-    LM832x_CMD_RPT_READ_FIFO   = 0x8a, /* Read FIFO (no increment). */
-    LM832x_CMD_SET_ACTIVE      = 0x8b, /* Set active time. */
-    LM832x_CMD_READ_ERROR      = 0x8c, /* Get error status. */
-    LM832x_CMD_READ_ROTATOR    = 0x8e, /* Read rotator status. */
-    LM832x_CMD_SET_DEBOUNCE    = 0x8f, /* Set debouncing time. */
-    LM832x_CMD_SET_KEY_SIZE    = 0x90, /* Set keypad size. */
-    LM832x_CMD_READ_KEY_SIZE   = 0x91, /* Get keypad size. */
-    LM832x_CMD_READ_CFG                = 0x92, /* Get configuration item. */
-    LM832x_CMD_WRITE_CLOCK     = 0x93, /* Set clock config. */
-    LM832x_CMD_READ_CLOCK      = 0x94, /* Get clock config. */
-    LM832x_CMD_PWM_WRITE       = 0x95, /* Write PWM script. */
-    LM832x_CMD_PWM_START       = 0x96, /* Start PWM engine. */
-    LM832x_CMD_PWM_STOP                = 0x97, /* Stop PWM engine. */
-    LM832x_GENERAL_ERROR       = 0xff, /* There was one error.
-                                           Previously was represented by -1
-                                           This is not a command */
-};
-
-#define LM832x_MAX_KPX         8
-#define LM832x_MAX_KPY         12
-
-static uint8_t lm_kbd_read(LM823KbdState *s, int reg, int byte)
-{
-    int ret;
-
-    switch (reg) {
-    case LM832x_CMD_READ_ID:
-        ret = 0x0400;
-        break;
-
-    case LM832x_CMD_READ_INT:
-        ret = s->status;
-        if (!(s->status & INT_NOINIT)) {
-            s->status = 0;
-            lm_kbd_irq_update(s);
-        }
-        break;
-
-    case LM832x_CMD_READ_PORT_SEL:
-        ret = s->gpio.dir;
-        break;
-    case LM832x_CMD_READ_PORT_STATE:
-        ret = s->gpio.mask;
-        break;
-
-    case LM832x_CMD_READ_FIFO:
-        if (s->kbd.len <= 1)
-            return 0x00;
-
-        /* Example response from the two commands after a INT_KEYPAD
-         * interrupt caused by the key 0x3c being pressed:
-         * RPT_READ_FIFO: 55 bc 00 4e ff 0a 50 08 00 29 d9 08 01 c9 01
-         *     READ_FIFO: bc 00 00 4e ff 0a 50 08 00 29 d9 08 01 c9 01
-         * RPT_READ_FIFO: bc 00 00 4e ff 0a 50 08 00 29 d9 08 01 c9 01
-         *
-         * 55 is the code of the key release event serviced in the previous
-         * interrupt handling.
-         *
-         * TODO: find out whether the FIFO is advanced a single character
-         * before reading every byte or the whole size of the FIFO at the
-         * last LM832x_CMD_READ_FIFO.  This affects LM832x_CMD_RPT_READ_FIFO
-         * output in cases where there are more than one event in the FIFO.
-         * Assume 0xbc and 0x3c events are in the FIFO:
-         * RPT_READ_FIFO: 55 bc 3c 00 4e ff 0a 50 08 00 29 d9 08 01 c9
-         *     READ_FIFO: bc 3c 00 00 4e ff 0a 50 08 00 29 d9 08 01 c9
-         * Does RPT_READ_FIFO now return 0xbc and 0x3c or only 0x3c?
-         */
-        s->kbd.start ++;
-        s->kbd.start &= sizeof(s->kbd.fifo) - 1;
-        s->kbd.len --;
-
-        return s->kbd.fifo[s->kbd.start];
-    case LM832x_CMD_RPT_READ_FIFO:
-        if (byte >= s->kbd.len)
-            return 0x00;
-
-        return s->kbd.fifo[(s->kbd.start + byte) & (sizeof(s->kbd.fifo) - 1)];
-
-    case LM832x_CMD_READ_ERROR:
-        return s->error;
-
-    case LM832x_CMD_READ_ROTATOR:
-        return 0;
-
-    case LM832x_CMD_READ_KEY_SIZE:
-        return s->kbd.size;
-
-    case LM832x_CMD_READ_CFG:
-        return s->config & 0xf;
-
-    case LM832x_CMD_READ_CLOCK:
-        return (s->clock & 0xfc) | 2;
-
-    default:
-        lm_kbd_error(s, ERR_CMDUNK);
-        fprintf(stderr, "%s: unknown command %02x\n", __FUNCTION__, reg);
-        return 0x00;
-    }
-
-    return ret >> (byte << 3);
-}
-
-static void lm_kbd_write(LM823KbdState *s, int reg, int byte, uint8_t value)
-{
-    switch (reg) {
-    case LM832x_CMD_WRITE_CFG:
-        s->config = value;
-        /* This must be done whenever s->mux.in is updated (never).  */
-        if ((s->config >> 1) & 1)                      /* MUX1EN */
-            qemu_set_irq(s->mux.out[0], s->mux.in[0][(s->config >> 0) & 1]);
-        if ((s->config >> 3) & 1)                      /* MUX2EN */
-            qemu_set_irq(s->mux.out[0], s->mux.in[0][(s->config >> 2) & 1]);
-        /* TODO: check that this is issued only following the chip reset
-         * and not in the middle of operation and that it is followed by
-         * the GPIO ports re-resablishing through WRITE_PORT_SEL and
-         * WRITE_PORT_STATE (using a timer perhaps) and otherwise output
-         * warnings.  */
-        s->status = 0;
-        lm_kbd_irq_update(s);
-        s->kbd.len = 0;
-        s->kbd.start = 0;
-        s->reg = LM832x_GENERAL_ERROR;
-        break;
-
-    case LM832x_CMD_RESET:
-        if (value == 0xaa)
-            lm_kbd_reset(s);
-        else
-            lm_kbd_error(s, ERR_BADPAR);
-        s->reg = LM832x_GENERAL_ERROR;
-        break;
-
-    case LM823x_CMD_WRITE_PULL_DOWN:
-        if (!byte)
-            s->gpio.pull = value;
-        else {
-            s->gpio.pull |= value << 8;
-            lm_kbd_gpio_update(s);
-            s->reg = LM832x_GENERAL_ERROR;
-        }
-        break;
-    case LM832x_CMD_WRITE_PORT_SEL:
-        if (!byte)
-            s->gpio.dir = value;
-        else {
-            s->gpio.dir |= value << 8;
-            lm_kbd_gpio_update(s);
-            s->reg = LM832x_GENERAL_ERROR;
-        }
-        break;
-    case LM832x_CMD_WRITE_PORT_STATE:
-        if (!byte)
-            s->gpio.mask = value;
-        else {
-            s->gpio.mask |= value << 8;
-            lm_kbd_gpio_update(s);
-            s->reg = LM832x_GENERAL_ERROR;
-        }
-        break;
-
-    case LM832x_CMD_SET_ACTIVE:
-        s->acttime = value;
-        s->reg = LM832x_GENERAL_ERROR;
-        break;
-
-    case LM832x_CMD_SET_DEBOUNCE:
-        s->kbd.dbnctime = value;
-        s->reg = LM832x_GENERAL_ERROR;
-        if (!value)
-            lm_kbd_error(s, ERR_BADPAR);
-        break;
-
-    case LM832x_CMD_SET_KEY_SIZE:
-        s->kbd.size = value;
-        s->reg = LM832x_GENERAL_ERROR;
-        if (
-                        (value & 0xf) < 3 || (value & 0xf) > LM832x_MAX_KPY ||
-                        (value >> 4) < 3 || (value >> 4) > LM832x_MAX_KPX)
-            lm_kbd_error(s, ERR_BADPAR);
-        break;
-
-    case LM832x_CMD_WRITE_CLOCK:
-        s->clock = value;
-        s->reg = LM832x_GENERAL_ERROR;
-        if ((value & 3) && (value & 3) != 3) {
-            lm_kbd_error(s, ERR_BADPAR);
-            fprintf(stderr, "%s: invalid clock setting in RCPWM\n",
-                            __FUNCTION__);
-        }
-        /* TODO: Validate that the command is only issued once */
-        break;
-
-    case LM832x_CMD_PWM_WRITE:
-        if (byte == 0) {
-            if (!(value & 3) || (value >> 2) > 59) {
-                lm_kbd_error(s, ERR_BADPAR);
-                s->reg = LM832x_GENERAL_ERROR;
-                break;
-            }
-
-            s->pwm.faddr = value;
-            s->pwm.file[s->pwm.faddr] = 0;
-        } else if (byte == 1) {
-            s->pwm.file[s->pwm.faddr] |= value << 8;
-        } else if (byte == 2) {
-            s->pwm.file[s->pwm.faddr] |= value << 0;
-            s->reg = LM832x_GENERAL_ERROR;
-        }
-        break;
-    case LM832x_CMD_PWM_START:
-        s->reg = LM832x_GENERAL_ERROR;
-        if (!(value & 3) || (value >> 2) > 59) {
-            lm_kbd_error(s, ERR_BADPAR);
-            break;
-        }
-
-        s->pwm.addr[(value & 3) - 1] = value >> 2;
-        lm_kbd_pwm_start(s, (value & 3) - 1);
-        break;
-    case LM832x_CMD_PWM_STOP:
-        s->reg = LM832x_GENERAL_ERROR;
-        if (!(value & 3)) {
-            lm_kbd_error(s, ERR_BADPAR);
-            break;
-        }
-
-        qemu_del_timer(s->pwm.tm[(value & 3) - 1]);
-        break;
-
-    case LM832x_GENERAL_ERROR:
-        lm_kbd_error(s, ERR_BADPAR);
-        break;
-    default:
-        lm_kbd_error(s, ERR_CMDUNK);
-        fprintf(stderr, "%s: unknown command %02x\n", __FUNCTION__, reg);
-        break;
-    }
-}
-
-static void lm_i2c_event(I2CSlave *i2c, enum i2c_event event)
-{
-    LM823KbdState *s = FROM_I2C_SLAVE(LM823KbdState, i2c);
-
-    switch (event) {
-    case I2C_START_RECV:
-    case I2C_START_SEND:
-        s->i2c_cycle = 0;
-        s->i2c_dir = (event == I2C_START_SEND);
-        break;
-
-    default:
-        break;
-    }
-}
-
-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(I2CSlave *i2c, uint8_t data)
-{
-    LM823KbdState *s = (LM823KbdState *) i2c;
-
-    if (!s->i2c_cycle)
-        s->reg = data;
-    else
-        lm_kbd_write(s, s->reg, s->i2c_cycle - 1, data);
-    s->i2c_cycle ++;
-
-    return 0;
-}
-
-static int lm_kbd_post_load(void *opaque, int version_id)
-{
-    LM823KbdState *s = opaque;
-
-    lm_kbd_irq_update(s);
-    lm_kbd_gpio_update(s);
-
-    return 0;
-}
-
-static const VMStateDescription vmstate_lm_kbd = {
-    .name = "LM8323",
-    .version_id = 0,
-    .minimum_version_id = 0,
-    .minimum_version_id_old = 0,
-    .post_load = lm_kbd_post_load,
-    .fields      = (VMStateField []) {
-        VMSTATE_I2C_SLAVE(i2c, LM823KbdState),
-        VMSTATE_UINT8(i2c_dir, LM823KbdState),
-        VMSTATE_UINT8(i2c_cycle, LM823KbdState),
-        VMSTATE_UINT8(reg, LM823KbdState),
-        VMSTATE_UINT8(config, LM823KbdState),
-        VMSTATE_UINT8(status, LM823KbdState),
-        VMSTATE_UINT8(acttime, LM823KbdState),
-        VMSTATE_UINT8(error, LM823KbdState),
-        VMSTATE_UINT8(clock, LM823KbdState),
-        VMSTATE_UINT16(gpio.pull, LM823KbdState),
-        VMSTATE_UINT16(gpio.mask, LM823KbdState),
-        VMSTATE_UINT16(gpio.dir, LM823KbdState),
-        VMSTATE_UINT16(gpio.level, LM823KbdState),
-        VMSTATE_UINT8(kbd.dbnctime, LM823KbdState),
-        VMSTATE_UINT8(kbd.size, LM823KbdState),
-        VMSTATE_UINT8(kbd.start, LM823KbdState),
-        VMSTATE_UINT8(kbd.len, LM823KbdState),
-        VMSTATE_BUFFER(kbd.fifo, LM823KbdState),
-        VMSTATE_UINT16_ARRAY(pwm.file, LM823KbdState, 256),
-        VMSTATE_UINT8(pwm.faddr, LM823KbdState),
-        VMSTATE_BUFFER(pwm.addr, LM823KbdState),
-        VMSTATE_TIMER_ARRAY(pwm.tm, LM823KbdState, 3),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-
-static int lm8323_init(I2CSlave *i2c)
-{
-    LM823KbdState *s = FROM_I2C_SLAVE(LM823KbdState, i2c);
-
-    s->model = 0x8323;
-    s->pwm.tm[0] = qemu_new_timer_ns(vm_clock, lm_kbd_pwm0_tick, s);
-    s->pwm.tm[1] = qemu_new_timer_ns(vm_clock, lm_kbd_pwm1_tick, s);
-    s->pwm.tm[2] = qemu_new_timer_ns(vm_clock, lm_kbd_pwm2_tick, s);
-    qdev_init_gpio_out(&i2c->qdev, &s->nirq, 1);
-
-    lm_kbd_reset(s);
-
-    qemu_register_reset((void *) lm_kbd_reset, s);
-    return 0;
-}
-
-void lm832x_key_event(DeviceState *dev, int key, int state)
-{
-    LM823KbdState *s = FROM_I2C_SLAVE(LM823KbdState, I2C_SLAVE(dev));
-
-    if ((s->status & INT_ERROR) && (s->error & ERR_FIFOOVR))
-        return;
-
-    if (s->kbd.len >= sizeof(s->kbd.fifo)) {
-        lm_kbd_error(s, ERR_FIFOOVR);
-        return;
-    }
-
-    s->kbd.fifo[(s->kbd.start + s->kbd.len ++) & (sizeof(s->kbd.fifo) - 1)] =
-            key | (state << 7);
-
-    /* We never set ERR_KEYOVR because we support multiple keys fine.  */
-    s->status |= INT_KEYPAD;
-    lm_kbd_irq_update(s);
-}
-
-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 const TypeInfo lm8323_info = {
-    .name          = "lm8323",
-    .parent        = TYPE_I2C_SLAVE,
-    .instance_size = sizeof(LM823KbdState),
-    .class_init    = lm8323_class_init,
-};
-
-static void lm832x_register_types(void)
-{
-    type_register_static(&lm8323_info);
-}
-
-type_init(lm832x_register_types)
diff --git a/hw/loader.c b/hw/loader.c
deleted file mode 100644 (file)
index 6ce66fb..0000000
+++ /dev/null
@@ -1,850 +0,0 @@
-/*
- * QEMU Executable loader
- *
- * Copyright (c) 2006 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.
- *
- * Gunzip functionality in this file is derived from u-boot:
- *
- * (C) Copyright 2008 Semihalf
- *
- * (C) Copyright 2000-2005
- * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
- *
- * 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 "hw/hw.h"
-#include "disas/disas.h"
-#include "monitor/monitor.h"
-#include "sysemu/sysemu.h"
-#include "hw/uboot_image.h"
-#include "hw/loader.h"
-#include "hw/fw_cfg.h"
-#include "exec/memory.h"
-#include "exec/address-spaces.h"
-
-#include <zlib.h>
-
-static int roms_loaded;
-
-/* return the size or -1 if error */
-int get_image_size(const char *filename)
-{
-    int fd, size;
-    fd = open(filename, O_RDONLY | O_BINARY);
-    if (fd < 0)
-        return -1;
-    size = lseek(fd, 0, SEEK_END);
-    close(fd);
-    return size;
-}
-
-/* return the size or -1 if error */
-/* deprecated, because caller does not specify buffer size! */
-int load_image(const char *filename, uint8_t *addr)
-{
-    int fd, size;
-    fd = open(filename, O_RDONLY | O_BINARY);
-    if (fd < 0)
-        return -1;
-    size = lseek(fd, 0, SEEK_END);
-    lseek(fd, 0, SEEK_SET);
-    if (read(fd, addr, size) != size) {
-        close(fd);
-        return -1;
-    }
-    close(fd);
-    return size;
-}
-
-/* read()-like version */
-ssize_t read_targphys(const char *name,
-                      int fd, hwaddr dst_addr, size_t nbytes)
-{
-    uint8_t *buf;
-    ssize_t did;
-
-    buf = g_malloc(nbytes);
-    did = read(fd, buf, nbytes);
-    if (did > 0)
-        rom_add_blob_fixed("read", buf, did, dst_addr);
-    g_free(buf);
-    return did;
-}
-
-/* return the size or -1 if error */
-int load_image_targphys(const char *filename,
-                        hwaddr addr, uint64_t max_sz)
-{
-    int size;
-
-    size = get_image_size(filename);
-    if (size > max_sz) {
-        return -1;
-    }
-    if (size > 0) {
-        rom_add_file_fixed(filename, addr, -1);
-    }
-    return size;
-}
-
-void pstrcpy_targphys(const char *name, hwaddr dest, int buf_size,
-                      const char *source)
-{
-    const char *nulp;
-    char *ptr;
-
-    if (buf_size <= 0) return;
-    nulp = memchr(source, 0, buf_size);
-    if (nulp) {
-        rom_add_blob_fixed(name, source, (nulp - source) + 1, dest);
-    } else {
-        rom_add_blob_fixed(name, source, buf_size, dest);
-        ptr = rom_ptr(dest + buf_size - 1);
-        *ptr = 0;
-    }
-}
-
-/* A.OUT loader */
-
-struct exec
-{
-  uint32_t a_info;   /* Use macros N_MAGIC, etc for access */
-  uint32_t a_text;   /* length of text, in bytes */
-  uint32_t a_data;   /* length of data, in bytes */
-  uint32_t a_bss;    /* length of uninitialized data area, in bytes */
-  uint32_t a_syms;   /* length of symbol table data in file, in bytes */
-  uint32_t a_entry;  /* start address */
-  uint32_t a_trsize; /* length of relocation info for text, in bytes */
-  uint32_t a_drsize; /* length of relocation info for data, in bytes */
-};
-
-static void bswap_ahdr(struct exec *e)
-{
-    bswap32s(&e->a_info);
-    bswap32s(&e->a_text);
-    bswap32s(&e->a_data);
-    bswap32s(&e->a_bss);
-    bswap32s(&e->a_syms);
-    bswap32s(&e->a_entry);
-    bswap32s(&e->a_trsize);
-    bswap32s(&e->a_drsize);
-}
-
-#define N_MAGIC(exec) ((exec).a_info & 0xffff)
-#define OMAGIC 0407
-#define NMAGIC 0410
-#define ZMAGIC 0413
-#define QMAGIC 0314
-#define _N_HDROFF(x) (1024 - sizeof (struct exec))
-#define N_TXTOFF(x)                                                    \
-    (N_MAGIC(x) == ZMAGIC ? _N_HDROFF((x)) + sizeof (struct exec) :    \
-     (N_MAGIC(x) == QMAGIC ? 0 : sizeof (struct exec)))
-#define N_TXTADDR(x, target_page_size) (N_MAGIC(x) == QMAGIC ? target_page_size : 0)
-#define _N_SEGMENT_ROUND(x, target_page_size) (((x) + target_page_size - 1) & ~(target_page_size - 1))
-
-#define _N_TXTENDADDR(x, target_page_size) (N_TXTADDR(x, target_page_size)+(x).a_text)
-
-#define N_DATADDR(x, target_page_size) \
-    (N_MAGIC(x)==OMAGIC? (_N_TXTENDADDR(x, target_page_size)) \
-     : (_N_SEGMENT_ROUND (_N_TXTENDADDR(x, target_page_size), target_page_size)))
-
-
-int load_aout(const char *filename, hwaddr addr, int max_sz,
-              int bswap_needed, hwaddr target_page_size)
-{
-    int fd;
-    ssize_t size, ret;
-    struct exec e;
-    uint32_t magic;
-
-    fd = open(filename, O_RDONLY | O_BINARY);
-    if (fd < 0)
-        return -1;
-
-    size = read(fd, &e, sizeof(e));
-    if (size < 0)
-        goto fail;
-
-    if (bswap_needed) {
-        bswap_ahdr(&e);
-    }
-
-    magic = N_MAGIC(e);
-    switch (magic) {
-    case ZMAGIC:
-    case QMAGIC:
-    case OMAGIC:
-        if (e.a_text + e.a_data > max_sz)
-            goto fail;
-       lseek(fd, N_TXTOFF(e), SEEK_SET);
-       size = read_targphys(filename, fd, addr, e.a_text + e.a_data);
-       if (size < 0)
-           goto fail;
-       break;
-    case NMAGIC:
-        if (N_DATADDR(e, target_page_size) + e.a_data > max_sz)
-            goto fail;
-       lseek(fd, N_TXTOFF(e), SEEK_SET);
-       size = read_targphys(filename, fd, addr, e.a_text);
-       if (size < 0)
-           goto fail;
-        ret = read_targphys(filename, fd, addr + N_DATADDR(e, target_page_size),
-                            e.a_data);
-       if (ret < 0)
-           goto fail;
-       size += ret;
-       break;
-    default:
-       goto fail;
-    }
-    close(fd);
-    return size;
- fail:
-    close(fd);
-    return -1;
-}
-
-/* ELF loader */
-
-static void *load_at(int fd, int offset, int size)
-{
-    void *ptr;
-    if (lseek(fd, offset, SEEK_SET) < 0)
-        return NULL;
-    ptr = g_malloc(size);
-    if (read(fd, ptr, size) != size) {
-        g_free(ptr);
-        return NULL;
-    }
-    return ptr;
-}
-
-#ifdef ELF_CLASS
-#undef ELF_CLASS
-#endif
-
-#define ELF_CLASS   ELFCLASS32
-#include "elf.h"
-
-#define SZ             32
-#define elf_word        uint32_t
-#define elf_sword        int32_t
-#define bswapSZs       bswap32s
-#include "hw/elf_ops.h"
-
-#undef elfhdr
-#undef elf_phdr
-#undef elf_shdr
-#undef elf_sym
-#undef elf_note
-#undef elf_word
-#undef elf_sword
-#undef bswapSZs
-#undef SZ
-#define elfhdr         elf64_hdr
-#define elf_phdr       elf64_phdr
-#define elf_note       elf64_note
-#define elf_shdr       elf64_shdr
-#define elf_sym                elf64_sym
-#define elf_word        uint64_t
-#define elf_sword        int64_t
-#define bswapSZs       bswap64s
-#define SZ             64
-#include "hw/elf_ops.h"
-
-/* return < 0 if error, otherwise the number of bytes loaded in memory */
-int load_elf(const char *filename, uint64_t (*translate_fn)(void *, uint64_t),
-             void *translate_opaque, uint64_t *pentry, uint64_t *lowaddr,
-             uint64_t *highaddr, int big_endian, int elf_machine, int clear_lsb)
-{
-    int fd, data_order, target_data_order, must_swab, ret;
-    uint8_t e_ident[EI_NIDENT];
-
-    fd = open(filename, O_RDONLY | O_BINARY);
-    if (fd < 0) {
-        perror(filename);
-        return -1;
-    }
-    if (read(fd, e_ident, sizeof(e_ident)) != sizeof(e_ident))
-        goto fail;
-    if (e_ident[0] != ELFMAG0 ||
-        e_ident[1] != ELFMAG1 ||
-        e_ident[2] != ELFMAG2 ||
-        e_ident[3] != ELFMAG3)
-        goto fail;
-#ifdef HOST_WORDS_BIGENDIAN
-    data_order = ELFDATA2MSB;
-#else
-    data_order = ELFDATA2LSB;
-#endif
-    must_swab = data_order != e_ident[EI_DATA];
-    if (big_endian) {
-        target_data_order = ELFDATA2MSB;
-    } else {
-        target_data_order = ELFDATA2LSB;
-    }
-
-    if (target_data_order != e_ident[EI_DATA]) {
-        goto fail;
-    }
-
-    lseek(fd, 0, SEEK_SET);
-    if (e_ident[EI_CLASS] == ELFCLASS64) {
-        ret = load_elf64(filename, fd, translate_fn, translate_opaque, must_swab,
-                         pentry, lowaddr, highaddr, elf_machine, clear_lsb);
-    } else {
-        ret = load_elf32(filename, fd, translate_fn, translate_opaque, must_swab,
-                         pentry, lowaddr, highaddr, elf_machine, clear_lsb);
-    }
-
-    close(fd);
-    return ret;
-
- fail:
-    close(fd);
-    return -1;
-}
-
-static void bswap_uboot_header(uboot_image_header_t *hdr)
-{
-#ifndef HOST_WORDS_BIGENDIAN
-    bswap32s(&hdr->ih_magic);
-    bswap32s(&hdr->ih_hcrc);
-    bswap32s(&hdr->ih_time);
-    bswap32s(&hdr->ih_size);
-    bswap32s(&hdr->ih_load);
-    bswap32s(&hdr->ih_ep);
-    bswap32s(&hdr->ih_dcrc);
-#endif
-}
-
-
-#define ZALLOC_ALIGNMENT       16
-
-static void *zalloc(void *x, unsigned items, unsigned size)
-{
-    void *p;
-
-    size *= items;
-    size = (size + ZALLOC_ALIGNMENT - 1) & ~(ZALLOC_ALIGNMENT - 1);
-
-    p = g_malloc(size);
-
-    return (p);
-}
-
-static void zfree(void *x, void *addr)
-{
-    g_free(addr);
-}
-
-
-#define HEAD_CRC       2
-#define EXTRA_FIELD    4
-#define ORIG_NAME      8
-#define COMMENT                0x10
-#define RESERVED       0xe0
-
-#define DEFLATED       8
-
-/* This is the usual maximum in uboot, so if a uImage overflows this, it would
- * overflow on real hardware too. */
-#define UBOOT_MAX_GUNZIP_BYTES (64 << 20)
-
-static ssize_t gunzip(void *dst, size_t dstlen, uint8_t *src,
-                      size_t srclen)
-{
-    z_stream s;
-    ssize_t dstbytes;
-    int r, i, flags;
-
-    /* skip header */
-    i = 10;
-    flags = src[3];
-    if (src[2] != DEFLATED || (flags & RESERVED) != 0) {
-        puts ("Error: Bad gzipped data\n");
-        return -1;
-    }
-    if ((flags & EXTRA_FIELD) != 0)
-        i = 12 + src[10] + (src[11] << 8);
-    if ((flags & ORIG_NAME) != 0)
-        while (src[i++] != 0)
-            ;
-    if ((flags & COMMENT) != 0)
-        while (src[i++] != 0)
-            ;
-    if ((flags & HEAD_CRC) != 0)
-        i += 2;
-    if (i >= srclen) {
-        puts ("Error: gunzip out of data in header\n");
-        return -1;
-    }
-
-    s.zalloc = zalloc;
-    s.zfree = zfree;
-
-    r = inflateInit2(&s, -MAX_WBITS);
-    if (r != Z_OK) {
-        printf ("Error: inflateInit2() returned %d\n", r);
-        return (-1);
-    }
-    s.next_in = src + i;
-    s.avail_in = srclen - i;
-    s.next_out = dst;
-    s.avail_out = dstlen;
-    r = inflate(&s, Z_FINISH);
-    if (r != Z_OK && r != Z_STREAM_END) {
-        printf ("Error: inflate() returned %d\n", r);
-        return -1;
-    }
-    dstbytes = s.next_out - (unsigned char *) dst;
-    inflateEnd(&s);
-
-    return dstbytes;
-}
-
-/* Load a U-Boot image.  */
-int load_uimage(const char *filename, hwaddr *ep,
-                hwaddr *loadaddr, int *is_linux)
-{
-    int fd;
-    int size;
-    uboot_image_header_t h;
-    uboot_image_header_t *hdr = &h;
-    uint8_t *data = NULL;
-    int ret = -1;
-
-    fd = open(filename, O_RDONLY | O_BINARY);
-    if (fd < 0)
-        return -1;
-
-    size = read(fd, hdr, sizeof(uboot_image_header_t));
-    if (size < 0)
-        goto out;
-
-    bswap_uboot_header(hdr);
-
-    if (hdr->ih_magic != IH_MAGIC)
-        goto out;
-
-    /* TODO: Implement other image types.  */
-    if (hdr->ih_type != IH_TYPE_KERNEL) {
-        fprintf(stderr, "Can only load u-boot image type \"kernel\"\n");
-        goto out;
-    }
-
-    switch (hdr->ih_comp) {
-    case IH_COMP_NONE:
-    case IH_COMP_GZIP:
-        break;
-    default:
-        fprintf(stderr,
-                "Unable to load u-boot images with compression type %d\n",
-                hdr->ih_comp);
-        goto out;
-    }
-
-    /* TODO: Check CPU type.  */
-    if (is_linux) {
-        if (hdr->ih_os == IH_OS_LINUX)
-            *is_linux = 1;
-        else
-            *is_linux = 0;
-    }
-
-    *ep = hdr->ih_ep;
-    data = g_malloc(hdr->ih_size);
-
-    if (read(fd, data, hdr->ih_size) != hdr->ih_size) {
-        fprintf(stderr, "Error reading file\n");
-        goto out;
-    }
-
-    if (hdr->ih_comp == IH_COMP_GZIP) {
-        uint8_t *compressed_data;
-        size_t max_bytes;
-        ssize_t bytes;
-
-        compressed_data = data;
-        max_bytes = UBOOT_MAX_GUNZIP_BYTES;
-        data = g_malloc(max_bytes);
-
-        bytes = gunzip(data, max_bytes, compressed_data, hdr->ih_size);
-        g_free(compressed_data);
-        if (bytes < 0) {
-            fprintf(stderr, "Unable to decompress gzipped image!\n");
-            goto out;
-        }
-        hdr->ih_size = bytes;
-    }
-
-    rom_add_blob_fixed(filename, data, hdr->ih_size, hdr->ih_load);
-
-    if (loadaddr)
-        *loadaddr = hdr->ih_load;
-
-    ret = hdr->ih_size;
-
-out:
-    if (data)
-        g_free(data);
-    close(fd);
-    return ret;
-}
-
-/*
- * Functions for reboot-persistent memory regions.
- *  - used for vga bios and option roms.
- *  - also linux kernel (-kernel / -initrd).
- */
-
-typedef struct Rom Rom;
-
-struct Rom {
-    char *name;
-    char *path;
-
-    /* datasize is the amount of memory allocated in "data". If datasize is less
-     * than romsize, it means that the area from datasize to romsize is filled
-     * with zeros.
-     */
-    size_t romsize;
-    size_t datasize;
-
-    uint8_t *data;
-    int isrom;
-    char *fw_dir;
-    char *fw_file;
-
-    hwaddr addr;
-    QTAILQ_ENTRY(Rom) next;
-};
-
-static FWCfgState *fw_cfg;
-static QTAILQ_HEAD(, Rom) roms = QTAILQ_HEAD_INITIALIZER(roms);
-
-static void rom_insert(Rom *rom)
-{
-    Rom *item;
-
-    if (roms_loaded) {
-        hw_error ("ROM images must be loaded at startup\n");
-    }
-
-    /* list is ordered by load address */
-    QTAILQ_FOREACH(item, &roms, next) {
-        if (rom->addr >= item->addr)
-            continue;
-        QTAILQ_INSERT_BEFORE(item, rom, next);
-        return;
-    }
-    QTAILQ_INSERT_TAIL(&roms, rom, next);
-}
-
-int rom_add_file(const char *file, const char *fw_dir,
-                 hwaddr addr, int32_t bootindex)
-{
-    Rom *rom;
-    int rc, fd = -1;
-    char devpath[100];
-
-    rom = g_malloc0(sizeof(*rom));
-    rom->name = g_strdup(file);
-    rom->path = qemu_find_file(QEMU_FILE_TYPE_BIOS, rom->name);
-    if (rom->path == NULL) {
-        rom->path = g_strdup(file);
-    }
-
-    fd = open(rom->path, O_RDONLY | O_BINARY);
-    if (fd == -1) {
-        fprintf(stderr, "Could not open option rom '%s': %s\n",
-                rom->path, strerror(errno));
-        goto err;
-    }
-
-    if (fw_dir) {
-        rom->fw_dir  = g_strdup(fw_dir);
-        rom->fw_file = g_strdup(file);
-    }
-    rom->addr     = addr;
-    rom->romsize  = lseek(fd, 0, SEEK_END);
-    rom->datasize = rom->romsize;
-    rom->data     = g_malloc0(rom->datasize);
-    lseek(fd, 0, SEEK_SET);
-    rc = read(fd, rom->data, rom->datasize);
-    if (rc != rom->datasize) {
-        fprintf(stderr, "rom: file %-20s: read error: rc=%d (expected %zd)\n",
-                rom->name, rc, rom->datasize);
-        goto err;
-    }
-    close(fd);
-    rom_insert(rom);
-    if (rom->fw_file && fw_cfg) {
-        const char *basename;
-        char fw_file_name[56];
-
-        basename = strrchr(rom->fw_file, '/');
-        if (basename) {
-            basename++;
-        } else {
-            basename = rom->fw_file;
-        }
-        snprintf(fw_file_name, sizeof(fw_file_name), "%s/%s", rom->fw_dir,
-                 basename);
-        fw_cfg_add_file(fw_cfg, fw_file_name, rom->data, rom->romsize);
-        snprintf(devpath, sizeof(devpath), "/rom@%s", fw_file_name);
-    } else {
-        snprintf(devpath, sizeof(devpath), "/rom@" TARGET_FMT_plx, addr);
-    }
-
-    add_boot_device_path(bootindex, NULL, devpath);
-    return 0;
-
-err:
-    if (fd != -1)
-        close(fd);
-    g_free(rom->data);
-    g_free(rom->path);
-    g_free(rom->name);
-    g_free(rom);
-    return -1;
-}
-
-int rom_add_blob(const char *name, const void *blob, size_t len,
-                 hwaddr addr)
-{
-    Rom *rom;
-
-    rom           = g_malloc0(sizeof(*rom));
-    rom->name     = g_strdup(name);
-    rom->addr     = addr;
-    rom->romsize  = len;
-    rom->datasize = len;
-    rom->data     = g_malloc0(rom->datasize);
-    memcpy(rom->data, blob, len);
-    rom_insert(rom);
-    return 0;
-}
-
-/* This function is specific for elf program because we don't need to allocate
- * all the rom. We just allocate the first part and the rest is just zeros. This
- * is why romsize and datasize are different. Also, this function seize the
- * memory ownership of "data", so we don't have to allocate and copy the buffer.
- */
-int rom_add_elf_program(const char *name, void *data, size_t datasize,
-                        size_t romsize, hwaddr addr)
-{
-    Rom *rom;
-
-    rom           = g_malloc0(sizeof(*rom));
-    rom->name     = g_strdup(name);
-    rom->addr     = addr;
-    rom->datasize = datasize;
-    rom->romsize  = romsize;
-    rom->data     = data;
-    rom_insert(rom);
-    return 0;
-}
-
-int rom_add_vga(const char *file)
-{
-    return rom_add_file(file, "vgaroms", 0, -1);
-}
-
-int rom_add_option(const char *file, int32_t bootindex)
-{
-    return rom_add_file(file, "genroms", 0, bootindex);
-}
-
-static void rom_reset(void *unused)
-{
-    Rom *rom;
-
-    QTAILQ_FOREACH(rom, &roms, next) {
-        if (rom->fw_file) {
-            continue;
-        }
-        if (rom->data == NULL) {
-            continue;
-        }
-        cpu_physical_memory_write_rom(rom->addr, rom->data, rom->datasize);
-        if (rom->isrom) {
-            /* rom needs to be written only once */
-            g_free(rom->data);
-            rom->data = NULL;
-        }
-    }
-}
-
-int rom_load_all(void)
-{
-    hwaddr addr = 0;
-    MemoryRegionSection section;
-    Rom *rom;
-
-    QTAILQ_FOREACH(rom, &roms, next) {
-        if (rom->fw_file) {
-            continue;
-        }
-        if (addr > rom->addr) {
-            fprintf(stderr, "rom: requested regions overlap "
-                    "(rom %s. free=0x" TARGET_FMT_plx
-                    ", addr=0x" TARGET_FMT_plx ")\n",
-                    rom->name, addr, rom->addr);
-            return -1;
-        }
-        addr  = rom->addr;
-        addr += rom->romsize;
-        section = memory_region_find(get_system_memory(), rom->addr, 1);
-        rom->isrom = section.size && memory_region_is_rom(section.mr);
-    }
-    qemu_register_reset(rom_reset, NULL);
-    roms_loaded = 1;
-    return 0;
-}
-
-void rom_set_fw(void *f)
-{
-    fw_cfg = f;
-}
-
-static Rom *find_rom(hwaddr addr)
-{
-    Rom *rom;
-
-    QTAILQ_FOREACH(rom, &roms, next) {
-        if (rom->fw_file) {
-            continue;
-        }
-        if (rom->addr > addr) {
-            continue;
-        }
-        if (rom->addr + rom->romsize < addr) {
-            continue;
-        }
-        return rom;
-    }
-    return NULL;
-}
-
-/*
- * Copies memory from registered ROMs to dest. Any memory that is contained in
- * a ROM between addr and addr + size is copied. Note that this can involve
- * multiple ROMs, which need not start at addr and need not end at addr + size.
- */
-int rom_copy(uint8_t *dest, hwaddr addr, size_t size)
-{
-    hwaddr end = addr + size;
-    uint8_t *s, *d = dest;
-    size_t l = 0;
-    Rom *rom;
-
-    QTAILQ_FOREACH(rom, &roms, next) {
-        if (rom->fw_file) {
-            continue;
-        }
-        if (rom->addr + rom->romsize < addr) {
-            continue;
-        }
-        if (rom->addr > end) {
-            break;
-        }
-        if (!rom->data) {
-            continue;
-        }
-
-        d = dest + (rom->addr - addr);
-        s = rom->data;
-        l = rom->datasize;
-
-        if ((d + l) > (dest + size)) {
-            l = dest - d;
-        }
-
-        memcpy(d, s, l);
-
-        if (rom->romsize > rom->datasize) {
-            /* If datasize is less than romsize, it means that we didn't
-             * allocate all the ROM because the trailing data are only zeros.
-             */
-
-            d += l;
-            l = rom->romsize - rom->datasize;
-
-            if ((d + l) > (dest + size)) {
-                /* Rom size doesn't fit in the destination area. Adjust to avoid
-                 * overflow.
-                 */
-                l = dest - d;
-            }
-
-            if (l > 0) {
-                memset(d, 0x0, l);
-            }
-        }
-    }
-
-    return (d + l) - dest;
-}
-
-void *rom_ptr(hwaddr addr)
-{
-    Rom *rom;
-
-    rom = find_rom(addr);
-    if (!rom || !rom->data)
-        return NULL;
-    return rom->data + (addr - rom->addr);
-}
-
-void do_info_roms(Monitor *mon, const QDict *qdict)
-{
-    Rom *rom;
-
-    QTAILQ_FOREACH(rom, &roms, next) {
-        if (!rom->fw_file) {
-            monitor_printf(mon, "addr=" TARGET_FMT_plx
-                           " size=0x%06zx mem=%s name=\"%s\"\n",
-                           rom->addr, rom->romsize,
-                           rom->isrom ? "rom" : "ram",
-                           rom->name);
-        } else {
-            monitor_printf(mon, "fw=%s/%s"
-                           " size=0x%06zx name=\"%s\"\n",
-                           rom->fw_dir,
-                           rom->fw_file,
-                           rom->romsize,
-                           rom->name);
-        }
-    }
-}
diff --git a/hw/loader.h b/hw/loader.h
deleted file mode 100644 (file)
index 0958f06..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-#ifndef LOADER_H
-#define LOADER_H
-#include "qapi/qmp/qdict.h"
-
-/* loader.c */
-int get_image_size(const char *filename);
-int load_image(const char *filename, uint8_t *addr); /* deprecated */
-int load_image_targphys(const char *filename, hwaddr,
-                        uint64_t max_sz);
-int load_elf(const char *filename, uint64_t (*translate_fn)(void *, uint64_t),
-             void *translate_opaque, uint64_t *pentry, uint64_t *lowaddr,
-             uint64_t *highaddr, int big_endian, int elf_machine,
-             int clear_lsb);
-int load_aout(const char *filename, hwaddr addr, int max_sz,
-              int bswap_needed, hwaddr target_page_size);
-int load_uimage(const char *filename, hwaddr *ep,
-                hwaddr *loadaddr, int *is_linux);
-
-ssize_t read_targphys(const char *name,
-                      int fd, hwaddr dst_addr, size_t nbytes);
-void pstrcpy_targphys(const char *name,
-                      hwaddr dest, int buf_size,
-                      const char *source);
-
-
-int rom_add_file(const char *file, const char *fw_dir,
-                 hwaddr addr, int32_t bootindex);
-int rom_add_blob(const char *name, const void *blob, size_t len,
-                 hwaddr addr);
-int rom_add_elf_program(const char *name, void *data, size_t datasize,
-                        size_t romsize, hwaddr addr);
-int rom_load_all(void);
-void rom_set_fw(void *f);
-int rom_copy(uint8_t *dest, hwaddr addr, size_t size);
-void *rom_ptr(hwaddr addr);
-void do_info_roms(Monitor *mon, const QDict *qdict);
-
-#define rom_add_file_fixed(_f, _a, _i)          \
-    rom_add_file(_f, NULL, _a, _i)
-#define rom_add_blob_fixed(_f, _b, _l, _a)      \
-    rom_add_blob(_f, _b, _l, _a)
-
-#define PC_ROM_MIN_VGA     0xc0000
-#define PC_ROM_MIN_OPTION  0xc8000
-#define PC_ROM_MAX         0xe0000
-#define PC_ROM_ALIGN       0x800
-#define PC_ROM_SIZE        (PC_ROM_MAX - PC_ROM_MIN_VGA)
-
-int rom_add_vga(const char *file);
-int rom_add_option(const char *file, int32_t bootindex);
-
-#endif
diff --git a/hw/lpc_ich9.c b/hw/lpc_ich9.c
deleted file mode 100644 (file)
index ff0a309..0000000
+++ /dev/null
@@ -1,628 +0,0 @@
-/*
- * QEMU ICH9 Emulation
- *
- * Copyright (c) 2006 Fabrice Bellard
- * Copyright (c) 2009, 2010, 2011
- *               Isaku Yamahata <yamahata at valinux co jp>
- *               VA Linux Systems Japan K.K.
- * Copyright (C) 2012 Jason Baron <jbaron@redhat.com>
- *
- * This is based on piix_pci.c, but heavily modified.
- *
- * 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 "hw/hw.h"
-#include "qemu/range.h"
-#include "hw/isa.h"
-#include "hw/sysbus.h"
-#include "hw/pc.h"
-#include "hw/apm.h"
-#include "hw/ioapic.h"
-#include "hw/pci/pci.h"
-#include "hw/pci/pcie_host.h"
-#include "hw/pci/pci_bridge.h"
-#include "hw/ich9.h"
-#include "hw/acpi.h"
-#include "hw/acpi_ich9.h"
-#include "hw/pam.h"
-#include "hw/pci/pci_bus.h"
-#include "exec/address-spaces.h"
-#include "sysemu/sysemu.h"
-
-static int ich9_lpc_sci_irq(ICH9LPCState *lpc);
-
-/*****************************************************************************/
-/* ICH9 LPC PCI to ISA bridge */
-
-static void ich9_lpc_reset(DeviceState *qdev);
-
-/* chipset configuration register
- * to access chipset configuration registers, pci_[sg]et_{byte, word, long}
- * are used.
- * Although it's not pci configuration space, it's little endian as Intel.
- */
-
-static void ich9_cc_update_ir(uint8_t irr[PCI_NUM_PINS], uint16_t ir)
-{
-    int intx;
-    for (intx = 0; intx < PCI_NUM_PINS; intx++) {
-        irr[intx] = (ir >> (intx * ICH9_CC_DIR_SHIFT)) & ICH9_CC_DIR_MASK;
-    }
-}
-
-static void ich9_cc_update(ICH9LPCState *lpc)
-{
-    int slot;
-    int pci_intx;
-
-    const int reg_offsets[] = {
-        ICH9_CC_D25IR,
-        ICH9_CC_D26IR,
-        ICH9_CC_D27IR,
-        ICH9_CC_D28IR,
-        ICH9_CC_D29IR,
-        ICH9_CC_D30IR,
-        ICH9_CC_D31IR,
-    };
-    const int *offset;
-
-    /* D{25 - 31}IR, but D30IR is read only to 0. */
-    for (slot = 25, offset = reg_offsets; slot < 32; slot++, offset++) {
-        if (slot == 30) {
-            continue;
-        }
-        ich9_cc_update_ir(lpc->irr[slot],
-                          pci_get_word(lpc->chip_config + *offset));
-    }
-
-    /*
-     * D30: DMI2PCI bridge
-     * It is arbitrarily decided how INTx lines of PCI devicesbehind the bridge
-     * are connected to pirq lines. Our choice is PIRQ[E-H].
-     * INT[A-D] are connected to PIRQ[E-H]
-     */
-    for (pci_intx = 0; pci_intx < PCI_NUM_PINS; pci_intx++) {
-        lpc->irr[30][pci_intx] = pci_intx + 4;
-    }
-}
-
-static void ich9_cc_init(ICH9LPCState *lpc)
-{
-    int slot;
-    int intx;
-
-    /* the default irq routing is arbitrary as long as it matches with
-     * acpi irq routing table.
-     * The one that is incompatible with piix_pci(= bochs) one is
-     * intentionally chosen to let the users know that the different
-     * board is used.
-     *
-     * int[A-D] -> pirq[E-F]
-     * avoid pirq A-D because they are used for pci express port
-     */
-    for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
-        for (intx = 0; intx < PCI_NUM_PINS; intx++) {
-            lpc->irr[slot][intx] = (slot + intx) % 4 + 4;
-        }
-    }
-    ich9_cc_update(lpc);
-}
-
-static void ich9_cc_reset(ICH9LPCState *lpc)
-{
-    uint8_t *c = lpc->chip_config;
-
-    memset(lpc->chip_config, 0, sizeof(lpc->chip_config));
-
-    pci_set_long(c + ICH9_CC_D31IR, ICH9_CC_DIR_DEFAULT);
-    pci_set_long(c + ICH9_CC_D30IR, ICH9_CC_D30IR_DEFAULT);
-    pci_set_long(c + ICH9_CC_D29IR, ICH9_CC_DIR_DEFAULT);
-    pci_set_long(c + ICH9_CC_D28IR, ICH9_CC_DIR_DEFAULT);
-    pci_set_long(c + ICH9_CC_D27IR, ICH9_CC_DIR_DEFAULT);
-    pci_set_long(c + ICH9_CC_D26IR, ICH9_CC_DIR_DEFAULT);
-    pci_set_long(c + ICH9_CC_D25IR, ICH9_CC_DIR_DEFAULT);
-
-    ich9_cc_update(lpc);
-}
-
-static void ich9_cc_addr_len(uint64_t *addr, unsigned *len)
-{
-    *addr &= ICH9_CC_ADDR_MASK;
-    if (*addr + *len >= ICH9_CC_SIZE) {
-        *len = ICH9_CC_SIZE - *addr;
-    }
-}
-
-/* val: little endian */
-static void ich9_cc_write(void *opaque, hwaddr addr,
-                          uint64_t val, unsigned len)
-{
-    ICH9LPCState *lpc = (ICH9LPCState *)opaque;
-
-    ich9_cc_addr_len(&addr, &len);
-    memcpy(lpc->chip_config + addr, &val, len);
-    pci_bus_fire_intx_routing_notifier(lpc->d.bus);
-    ich9_cc_update(lpc);
-}
-
-/* return value: little endian */
-static uint64_t ich9_cc_read(void *opaque, hwaddr addr,
-                              unsigned len)
-{
-    ICH9LPCState *lpc = (ICH9LPCState *)opaque;
-
-    uint32_t val = 0;
-    ich9_cc_addr_len(&addr, &len);
-    memcpy(&val, lpc->chip_config + addr, len);
-    return val;
-}
-
-/* IRQ routing */
-/* */
-static void ich9_lpc_rout(uint8_t pirq_rout, int *pic_irq, int *pic_dis)
-{
-    *pic_irq = pirq_rout & ICH9_LPC_PIRQ_ROUT_MASK;
-    *pic_dis = pirq_rout & ICH9_LPC_PIRQ_ROUT_IRQEN;
-}
-
-static void ich9_lpc_pic_irq(ICH9LPCState *lpc, int pirq_num,
-                             int *pic_irq, int *pic_dis)
-{
-    switch (pirq_num) {
-    case 0 ... 3: /* A-D */
-        ich9_lpc_rout(lpc->d.config[ICH9_LPC_PIRQA_ROUT + pirq_num],
-                      pic_irq, pic_dis);
-        return;
-    case 4 ... 7: /* E-H */
-        ich9_lpc_rout(lpc->d.config[ICH9_LPC_PIRQE_ROUT + (pirq_num - 4)],
-                      pic_irq, pic_dis);
-        return;
-    default:
-        break;
-    }
-    abort();
-}
-
-/* pic_irq: i8254 irq 0-15 */
-static void ich9_lpc_update_pic(ICH9LPCState *lpc, int pic_irq)
-{
-    int i, pic_level;
-
-    /* The pic level is the logical OR of all the PCI irqs mapped to it */
-    pic_level = 0;
-    for (i = 0; i < ICH9_LPC_NB_PIRQS; i++) {
-        int tmp_irq;
-        int tmp_dis;
-        ich9_lpc_pic_irq(lpc, i, &tmp_irq, &tmp_dis);
-        if (!tmp_dis && pic_irq == tmp_irq) {
-            pic_level |= pci_bus_get_irq_level(lpc->d.bus, i);
-        }
-    }
-    if (pic_irq == ich9_lpc_sci_irq(lpc)) {
-        pic_level |= lpc->sci_level;
-    }
-
-    qemu_set_irq(lpc->pic[pic_irq], pic_level);
-}
-
-/* pirq: pirq[A-H] 0-7*/
-static void ich9_lpc_update_by_pirq(ICH9LPCState *lpc, int pirq)
-{
-    int pic_irq;
-    int pic_dis;
-
-    ich9_lpc_pic_irq(lpc, pirq, &pic_irq, &pic_dis);
-    assert(pic_irq < ICH9_LPC_PIC_NUM_PINS);
-    if (pic_dis) {
-        return;
-    }
-
-    ich9_lpc_update_pic(lpc, pic_irq);
-}
-
-/* APIC mode: GSIx: PIRQ[A-H] -> GSI 16, ... no pirq shares same APIC pins. */
-static int ich9_pirq_to_gsi(int pirq)
-{
-    return pirq + ICH9_LPC_PIC_NUM_PINS;
-}
-
-static int ich9_gsi_to_pirq(int gsi)
-{
-    return gsi - ICH9_LPC_PIC_NUM_PINS;
-}
-
-static void ich9_lpc_update_apic(ICH9LPCState *lpc, int gsi)
-{
-    int level = 0;
-
-    if (gsi >= ICH9_LPC_PIC_NUM_PINS) {
-        level |= pci_bus_get_irq_level(lpc->d.bus, ich9_gsi_to_pirq(gsi));
-    }
-    if (gsi == ich9_lpc_sci_irq(lpc)) {
-        level |= lpc->sci_level;
-    }
-
-    qemu_set_irq(lpc->ioapic[gsi], level);
-}
-
-void ich9_lpc_set_irq(void *opaque, int pirq, int level)
-{
-    ICH9LPCState *lpc = opaque;
-
-    assert(0 <= pirq);
-    assert(pirq < ICH9_LPC_NB_PIRQS);
-
-    ich9_lpc_update_apic(lpc, ich9_pirq_to_gsi(pirq));
-    ich9_lpc_update_by_pirq(lpc, pirq);
-}
-
-/* return the pirq number (PIRQ[A-H]:0-7) corresponding to
- * a given device irq pin.
- */
-int ich9_lpc_map_irq(PCIDevice *pci_dev, int intx)
-{
-    BusState *bus = qdev_get_parent_bus(&pci_dev->qdev);
-    PCIBus *pci_bus = PCI_BUS(bus);
-    PCIDevice *lpc_pdev =
-            pci_bus->devices[PCI_DEVFN(ICH9_LPC_DEV, ICH9_LPC_FUNC)];
-    ICH9LPCState *lpc = ICH9_LPC_DEVICE(lpc_pdev);
-
-    return lpc->irr[PCI_SLOT(pci_dev->devfn)][intx];
-}
-
-PCIINTxRoute ich9_route_intx_pin_to_irq(void *opaque, int pirq_pin)
-{
-    ICH9LPCState *lpc = opaque;
-    PCIINTxRoute route;
-    int pic_irq;
-    int pic_dis;
-
-    assert(0 <= pirq_pin);
-    assert(pirq_pin < ICH9_LPC_NB_PIRQS);
-
-    route.mode = PCI_INTX_ENABLED;
-    ich9_lpc_pic_irq(lpc, pirq_pin, &pic_irq, &pic_dis);
-    if (!pic_dis) {
-        if (pic_irq < ICH9_LPC_PIC_NUM_PINS) {
-            route.irq = pic_irq;
-        } else {
-            route.mode = PCI_INTX_DISABLED;
-            route.irq = -1;
-        }
-    } else {
-        route.irq = ich9_pirq_to_gsi(pirq_pin);
-    }
-
-    return route;
-}
-
-static int ich9_lpc_sci_irq(ICH9LPCState *lpc)
-{
-    switch (lpc->d.config[ICH9_LPC_ACPI_CTRL] &
-            ICH9_LPC_ACPI_CTRL_SCI_IRQ_SEL_MASK) {
-    case ICH9_LPC_ACPI_CTRL_9:
-        return 9;
-    case ICH9_LPC_ACPI_CTRL_10:
-        return 10;
-    case ICH9_LPC_ACPI_CTRL_11:
-        return 11;
-    case ICH9_LPC_ACPI_CTRL_20:
-        return 20;
-    case ICH9_LPC_ACPI_CTRL_21:
-        return 21;
-    default:
-        /* reserved */
-        break;
-    }
-    return -1;
-}
-
-static void ich9_set_sci(void *opaque, int irq_num, int level)
-{
-    ICH9LPCState *lpc = opaque;
-    int irq;
-
-    assert(irq_num == 0);
-    level = !!level;
-    if (level == lpc->sci_level) {
-        return;
-    }
-    lpc->sci_level = level;
-
-    irq = ich9_lpc_sci_irq(lpc);
-    if (irq < 0) {
-        return;
-    }
-
-    ich9_lpc_update_apic(lpc, irq);
-    if (irq < ICH9_LPC_PIC_NUM_PINS) {
-        ich9_lpc_update_pic(lpc, irq);
-    }
-}
-
-void ich9_lpc_pm_init(PCIDevice *lpc_pci, qemu_irq cmos_s3)
-{
-    ICH9LPCState *lpc = ICH9_LPC_DEVICE(lpc_pci);
-    qemu_irq *sci_irq;
-
-    sci_irq = qemu_allocate_irqs(ich9_set_sci, lpc, 1);
-    ich9_pm_init(lpc_pci, &lpc->pm, sci_irq[0], cmos_s3);
-
-    ich9_lpc_reset(&lpc->d.qdev);
-}
-
-/* APM */
-
-static void ich9_apm_ctrl_changed(uint32_t val, void *arg)
-{
-    ICH9LPCState *lpc = arg;
-
-    /* ACPI specs 3.0, 4.7.2.5 */
-    acpi_pm1_cnt_update(&lpc->pm.acpi_regs,
-                        val == ICH9_APM_ACPI_ENABLE,
-                        val == ICH9_APM_ACPI_DISABLE);
-
-    /* SMI_EN = PMBASE + 30. SMI control and enable register */
-    if (lpc->pm.smi_en & ICH9_PMIO_SMI_EN_APMC_EN) {
-        cpu_interrupt(CPU(x86_env_get_cpu(first_cpu)), CPU_INTERRUPT_SMI);
-    }
-}
-
-/* config:PMBASE */
-static void
-ich9_lpc_pmbase_update(ICH9LPCState *lpc)
-{
-    uint32_t pm_io_base = pci_get_long(lpc->d.config + ICH9_LPC_PMBASE);
-    pm_io_base &= ICH9_LPC_PMBASE_BASE_ADDRESS_MASK;
-
-    ich9_pm_iospace_update(&lpc->pm, pm_io_base);
-}
-
-/* config:RBCA */
-static void ich9_lpc_rcba_update(ICH9LPCState *lpc, uint32_t rbca_old)
-{
-    uint32_t rbca = pci_get_long(lpc->d.config + ICH9_LPC_RCBA);
-
-    if (rbca_old & ICH9_LPC_RCBA_EN) {
-            memory_region_del_subregion(get_system_memory(), &lpc->rbca_mem);
-    }
-    if (rbca & ICH9_LPC_RCBA_EN) {
-            memory_region_add_subregion_overlap(get_system_memory(),
-                                                rbca & ICH9_LPC_RCBA_BA_MASK,
-                                                &lpc->rbca_mem, 1);
-    }
-}
-
-static int ich9_lpc_post_load(void *opaque, int version_id)
-{
-    ICH9LPCState *lpc = opaque;
-
-    ich9_lpc_pmbase_update(lpc);
-    ich9_lpc_rcba_update(lpc, 0 /* disabled ICH9_LPC_RBCA_EN */);
-    return 0;
-}
-
-static void ich9_lpc_config_write(PCIDevice *d,
-                                  uint32_t addr, uint32_t val, int len)
-{
-    ICH9LPCState *lpc = ICH9_LPC_DEVICE(d);
-    uint32_t rbca_old = pci_get_long(d->config + ICH9_LPC_RCBA);
-
-    pci_default_write_config(d, addr, val, len);
-    if (ranges_overlap(addr, len, ICH9_LPC_PMBASE, 4)) {
-        ich9_lpc_pmbase_update(lpc);
-    }
-    if (ranges_overlap(addr, len, ICH9_LPC_RCBA, 4)) {
-        ich9_lpc_rcba_update(lpc, rbca_old);
-    }
-    if (ranges_overlap(addr, len, ICH9_LPC_PIRQA_ROUT, 4)) {
-        pci_bus_fire_intx_routing_notifier(lpc->d.bus);
-    }
-    if (ranges_overlap(addr, len, ICH9_LPC_PIRQE_ROUT, 4)) {
-        pci_bus_fire_intx_routing_notifier(lpc->d.bus);
-    }
-}
-
-static void ich9_lpc_reset(DeviceState *qdev)
-{
-    PCIDevice *d = PCI_DEVICE(qdev);
-    ICH9LPCState *lpc = ICH9_LPC_DEVICE(d);
-    uint32_t rbca_old = pci_get_long(d->config + ICH9_LPC_RCBA);
-    int i;
-
-    for (i = 0; i < 4; i++) {
-        pci_set_byte(d->config + ICH9_LPC_PIRQA_ROUT + i,
-                     ICH9_LPC_PIRQ_ROUT_DEFAULT);
-    }
-    for (i = 0; i < 4; i++) {
-        pci_set_byte(d->config + ICH9_LPC_PIRQE_ROUT + i,
-                     ICH9_LPC_PIRQ_ROUT_DEFAULT);
-    }
-    pci_set_byte(d->config + ICH9_LPC_ACPI_CTRL, ICH9_LPC_ACPI_CTRL_DEFAULT);
-
-    pci_set_long(d->config + ICH9_LPC_PMBASE, ICH9_LPC_PMBASE_DEFAULT);
-    pci_set_long(d->config + ICH9_LPC_RCBA, ICH9_LPC_RCBA_DEFAULT);
-
-    ich9_cc_reset(lpc);
-
-    ich9_lpc_pmbase_update(lpc);
-    ich9_lpc_rcba_update(lpc, rbca_old);
-
-    lpc->sci_level = 0;
-    lpc->rst_cnt = 0;
-}
-
-static const MemoryRegionOps rbca_mmio_ops = {
-    .read = ich9_cc_read,
-    .write = ich9_cc_write,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static void ich9_lpc_machine_ready(Notifier *n, void *opaque)
-{
-    ICH9LPCState *s = container_of(n, ICH9LPCState, machine_ready);
-    uint8_t *pci_conf;
-
-    pci_conf = s->d.config;
-    if (isa_is_ioport_assigned(0x3f8)) {
-        /* com1 */
-        pci_conf[0x82] |= 0x01;
-    }
-    if (isa_is_ioport_assigned(0x2f8)) {
-        /* com2 */
-        pci_conf[0x82] |= 0x02;
-    }
-    if (isa_is_ioport_assigned(0x378)) {
-        /* lpt */
-        pci_conf[0x82] |= 0x04;
-    }
-    if (isa_is_ioport_assigned(0x3f0)) {
-        /* floppy */
-        pci_conf[0x82] |= 0x08;
-    }
-}
-
-/* reset control */
-static void ich9_rst_cnt_write(void *opaque, hwaddr addr, uint64_t val,
-                               unsigned len)
-{
-    ICH9LPCState *lpc = opaque;
-
-    if (val & 4) {
-        qemu_system_reset_request();
-        return;
-    }
-    lpc->rst_cnt = val & 0xA; /* keep FULL_RST (bit 3) and SYS_RST (bit 1) */
-}
-
-static uint64_t ich9_rst_cnt_read(void *opaque, hwaddr addr, unsigned len)
-{
-    ICH9LPCState *lpc = opaque;
-
-    return lpc->rst_cnt;
-}
-
-static const MemoryRegionOps ich9_rst_cnt_ops = {
-    .read = ich9_rst_cnt_read,
-    .write = ich9_rst_cnt_write,
-    .endianness = DEVICE_LITTLE_ENDIAN
-};
-
-static int ich9_lpc_initfn(PCIDevice *d)
-{
-    ICH9LPCState *lpc = ICH9_LPC_DEVICE(d);
-    ISABus *isa_bus;
-
-    isa_bus = isa_bus_new(&d->qdev, get_system_io());
-
-    pci_set_long(d->wmask + ICH9_LPC_PMBASE,
-                 ICH9_LPC_PMBASE_BASE_ADDRESS_MASK);
-
-    memory_region_init_io(&lpc->rbca_mem, &rbca_mmio_ops, lpc,
-                            "lpc-rbca-mmio", ICH9_CC_SIZE);
-
-    lpc->isa_bus = isa_bus;
-
-    ich9_cc_init(lpc);
-    apm_init(d, &lpc->apm, ich9_apm_ctrl_changed, lpc);
-
-    lpc->machine_ready.notify = ich9_lpc_machine_ready;
-    qemu_add_machine_init_done_notifier(&lpc->machine_ready);
-
-    memory_region_init_io(&lpc->rst_cnt_mem, &ich9_rst_cnt_ops, lpc,
-                          "lpc-reset-control", 1);
-    memory_region_add_subregion_overlap(pci_address_space_io(d),
-                                        ICH9_RST_CNT_IOPORT, &lpc->rst_cnt_mem,
-                                        1);
-
-    return 0;
-}
-
-static bool ich9_rst_cnt_needed(void *opaque)
-{
-    ICH9LPCState *lpc = opaque;
-
-    return (lpc->rst_cnt != 0);
-}
-
-static const VMStateDescription vmstate_ich9_rst_cnt = {
-    .name = "ICH9LPC/rst_cnt",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT8(rst_cnt, ICH9LPCState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static const VMStateDescription vmstate_ich9_lpc = {
-    .name = "ICH9LPC",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .post_load = ich9_lpc_post_load,
-    .fields = (VMStateField[]) {
-        VMSTATE_PCI_DEVICE(d, ICH9LPCState),
-        VMSTATE_STRUCT(apm, ICH9LPCState, 0, vmstate_apm, APMState),
-        VMSTATE_STRUCT(pm, ICH9LPCState, 0, vmstate_ich9_pm, ICH9LPCPMRegs),
-        VMSTATE_UINT8_ARRAY(chip_config, ICH9LPCState, ICH9_CC_SIZE),
-        VMSTATE_UINT32(sci_level, ICH9LPCState),
-        VMSTATE_END_OF_LIST()
-    },
-    .subsections = (VMStateSubsection[]) {
-        {
-            .vmsd = &vmstate_ich9_rst_cnt,
-            .needed = ich9_rst_cnt_needed
-        },
-        { 0 }
-    }
-};
-
-static void ich9_lpc_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
-    dc->reset = ich9_lpc_reset;
-    k->init = ich9_lpc_initfn;
-    dc->vmsd = &vmstate_ich9_lpc;
-    dc->no_user = 1;
-    k->config_write = ich9_lpc_config_write;
-    dc->desc = "ICH9 LPC bridge";
-    k->vendor_id = PCI_VENDOR_ID_INTEL;
-    k->device_id = PCI_DEVICE_ID_INTEL_ICH9_8;
-    k->revision = ICH9_A2_LPC_REVISION;
-    k->class_id = PCI_CLASS_BRIDGE_ISA;
-
-}
-
-static const TypeInfo ich9_lpc_info = {
-    .name       = TYPE_ICH9_LPC_DEVICE,
-    .parent     = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(struct ICH9LPCState),
-    .class_init  = ich9_lpc_class_init,
-};
-
-static void ich9_lpc_register(void)
-{
-    type_register_static(&ich9_lpc_info);
-}
-
-type_init(ich9_lpc_register);
diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c
deleted file mode 100644 (file)
index 5a8bf4d..0000000
+++ /dev/null
@@ -1,2136 +0,0 @@
-/*
- * QEMU LSI53C895A SCSI Host Bus Adapter emulation
- *
- * Copyright (c) 2006 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the LGPL.
- */
-
-/* ??? Need to check if the {read,write}[wl] routines work properly on
-   big-endian targets.  */
-
-#include <assert.h>
-
-#include "hw/hw.h"
-#include "hw/pci/pci.h"
-#include "hw/scsi.h"
-#include "sysemu/dma.h"
-
-//#define DEBUG_LSI
-//#define DEBUG_LSI_REG
-
-#ifdef DEBUG_LSI
-#define DPRINTF(fmt, ...) \
-do { printf("lsi_scsi: " fmt , ## __VA_ARGS__); } while (0)
-#define BADF(fmt, ...) \
-do { fprintf(stderr, "lsi_scsi: error: " fmt , ## __VA_ARGS__); exit(1);} while (0)
-#else
-#define DPRINTF(fmt, ...) do {} while(0)
-#define BADF(fmt, ...) \
-do { fprintf(stderr, "lsi_scsi: error: " fmt , ## __VA_ARGS__);} while (0)
-#endif
-
-#define LSI_MAX_DEVS 7
-
-#define LSI_SCNTL0_TRG    0x01
-#define LSI_SCNTL0_AAP    0x02
-#define LSI_SCNTL0_EPC    0x08
-#define LSI_SCNTL0_WATN   0x10
-#define LSI_SCNTL0_START  0x20
-
-#define LSI_SCNTL1_SST    0x01
-#define LSI_SCNTL1_IARB   0x02
-#define LSI_SCNTL1_AESP   0x04
-#define LSI_SCNTL1_RST    0x08
-#define LSI_SCNTL1_CON    0x10
-#define LSI_SCNTL1_DHP    0x20
-#define LSI_SCNTL1_ADB    0x40
-#define LSI_SCNTL1_EXC    0x80
-
-#define LSI_SCNTL2_WSR    0x01
-#define LSI_SCNTL2_VUE0   0x02
-#define LSI_SCNTL2_VUE1   0x04
-#define LSI_SCNTL2_WSS    0x08
-#define LSI_SCNTL2_SLPHBEN 0x10
-#define LSI_SCNTL2_SLPMD  0x20
-#define LSI_SCNTL2_CHM    0x40
-#define LSI_SCNTL2_SDU    0x80
-
-#define LSI_ISTAT0_DIP    0x01
-#define LSI_ISTAT0_SIP    0x02
-#define LSI_ISTAT0_INTF   0x04
-#define LSI_ISTAT0_CON    0x08
-#define LSI_ISTAT0_SEM    0x10
-#define LSI_ISTAT0_SIGP   0x20
-#define LSI_ISTAT0_SRST   0x40
-#define LSI_ISTAT0_ABRT   0x80
-
-#define LSI_ISTAT1_SI     0x01
-#define LSI_ISTAT1_SRUN   0x02
-#define LSI_ISTAT1_FLSH   0x04
-
-#define LSI_SSTAT0_SDP0   0x01
-#define LSI_SSTAT0_RST    0x02
-#define LSI_SSTAT0_WOA    0x04
-#define LSI_SSTAT0_LOA    0x08
-#define LSI_SSTAT0_AIP    0x10
-#define LSI_SSTAT0_OLF    0x20
-#define LSI_SSTAT0_ORF    0x40
-#define LSI_SSTAT0_ILF    0x80
-
-#define LSI_SIST0_PAR     0x01
-#define LSI_SIST0_RST     0x02
-#define LSI_SIST0_UDC     0x04
-#define LSI_SIST0_SGE     0x08
-#define LSI_SIST0_RSL     0x10
-#define LSI_SIST0_SEL     0x20
-#define LSI_SIST0_CMP     0x40
-#define LSI_SIST0_MA      0x80
-
-#define LSI_SIST1_HTH     0x01
-#define LSI_SIST1_GEN     0x02
-#define LSI_SIST1_STO     0x04
-#define LSI_SIST1_SBMC    0x10
-
-#define LSI_SOCL_IO       0x01
-#define LSI_SOCL_CD       0x02
-#define LSI_SOCL_MSG      0x04
-#define LSI_SOCL_ATN      0x08
-#define LSI_SOCL_SEL      0x10
-#define LSI_SOCL_BSY      0x20
-#define LSI_SOCL_ACK      0x40
-#define LSI_SOCL_REQ      0x80
-
-#define LSI_DSTAT_IID     0x01
-#define LSI_DSTAT_SIR     0x04
-#define LSI_DSTAT_SSI     0x08
-#define LSI_DSTAT_ABRT    0x10
-#define LSI_DSTAT_BF      0x20
-#define LSI_DSTAT_MDPE    0x40
-#define LSI_DSTAT_DFE     0x80
-
-#define LSI_DCNTL_COM     0x01
-#define LSI_DCNTL_IRQD    0x02
-#define LSI_DCNTL_STD     0x04
-#define LSI_DCNTL_IRQM    0x08
-#define LSI_DCNTL_SSM     0x10
-#define LSI_DCNTL_PFEN    0x20
-#define LSI_DCNTL_PFF     0x40
-#define LSI_DCNTL_CLSE    0x80
-
-#define LSI_DMODE_MAN     0x01
-#define LSI_DMODE_BOF     0x02
-#define LSI_DMODE_ERMP    0x04
-#define LSI_DMODE_ERL     0x08
-#define LSI_DMODE_DIOM    0x10
-#define LSI_DMODE_SIOM    0x20
-
-#define LSI_CTEST2_DACK   0x01
-#define LSI_CTEST2_DREQ   0x02
-#define LSI_CTEST2_TEOP   0x04
-#define LSI_CTEST2_PCICIE 0x08
-#define LSI_CTEST2_CM     0x10
-#define LSI_CTEST2_CIO    0x20
-#define LSI_CTEST2_SIGP   0x40
-#define LSI_CTEST2_DDIR   0x80
-
-#define LSI_CTEST5_BL2    0x04
-#define LSI_CTEST5_DDIR   0x08
-#define LSI_CTEST5_MASR   0x10
-#define LSI_CTEST5_DFSN   0x20
-#define LSI_CTEST5_BBCK   0x40
-#define LSI_CTEST5_ADCK   0x80
-
-#define LSI_CCNTL0_DILS   0x01
-#define LSI_CCNTL0_DISFC  0x10
-#define LSI_CCNTL0_ENNDJ  0x20
-#define LSI_CCNTL0_PMJCTL 0x40
-#define LSI_CCNTL0_ENPMJ  0x80
-
-#define LSI_CCNTL1_EN64DBMV  0x01
-#define LSI_CCNTL1_EN64TIBMV 0x02
-#define LSI_CCNTL1_64TIMOD   0x04
-#define LSI_CCNTL1_DDAC      0x08
-#define LSI_CCNTL1_ZMOD      0x80
-
-/* Enable Response to Reselection */
-#define LSI_SCID_RRE      0x60
-
-#define LSI_CCNTL1_40BIT (LSI_CCNTL1_EN64TIBMV|LSI_CCNTL1_64TIMOD)
-
-#define PHASE_DO          0
-#define PHASE_DI          1
-#define PHASE_CMD         2
-#define PHASE_ST          3
-#define PHASE_MO          6
-#define PHASE_MI          7
-#define PHASE_MASK        7
-
-/* Maximum length of MSG IN data.  */
-#define LSI_MAX_MSGIN_LEN 8
-
-/* Flag set if this is a tagged command.  */
-#define LSI_TAG_VALID     (1 << 16)
-
-typedef struct lsi_request {
-    SCSIRequest *req;
-    uint32_t tag;
-    uint32_t dma_len;
-    uint8_t *dma_buf;
-    uint32_t pending;
-    int out;
-    QTAILQ_ENTRY(lsi_request) next;
-} lsi_request;
-
-typedef struct {
-    PCIDevice dev;
-    MemoryRegion mmio_io;
-    MemoryRegion ram_io;
-    MemoryRegion io_io;
-
-    int carry; /* ??? Should this be an a visible register somewhere?  */
-    int status;
-    /* Action to take at the end of a MSG IN phase.
-       0 = COMMAND, 1 = disconnect, 2 = DATA OUT, 3 = DATA IN.  */
-    int msg_action;
-    int msg_len;
-    uint8_t msg[LSI_MAX_MSGIN_LEN];
-    /* 0 if SCRIPTS are running or stopped.
-     * 1 if a Wait Reselect instruction has been issued.
-     * 2 if processing DMA from lsi_execute_script.
-     * 3 if a DMA operation is in progress.  */
-    int waiting;
-    SCSIBus bus;
-    int current_lun;
-    /* The tag is a combination of the device ID and the SCSI tag.  */
-    uint32_t select_tag;
-    int command_complete;
-    QTAILQ_HEAD(, lsi_request) queue;
-    lsi_request *current;
-
-    uint32_t dsa;
-    uint32_t temp;
-    uint32_t dnad;
-    uint32_t dbc;
-    uint8_t istat0;
-    uint8_t istat1;
-    uint8_t dcmd;
-    uint8_t dstat;
-    uint8_t dien;
-    uint8_t sist0;
-    uint8_t sist1;
-    uint8_t sien0;
-    uint8_t sien1;
-    uint8_t mbox0;
-    uint8_t mbox1;
-    uint8_t dfifo;
-    uint8_t ctest2;
-    uint8_t ctest3;
-    uint8_t ctest4;
-    uint8_t ctest5;
-    uint8_t ccntl0;
-    uint8_t ccntl1;
-    uint32_t dsp;
-    uint32_t dsps;
-    uint8_t dmode;
-    uint8_t dcntl;
-    uint8_t scntl0;
-    uint8_t scntl1;
-    uint8_t scntl2;
-    uint8_t scntl3;
-    uint8_t sstat0;
-    uint8_t sstat1;
-    uint8_t scid;
-    uint8_t sxfer;
-    uint8_t socl;
-    uint8_t sdid;
-    uint8_t ssid;
-    uint8_t sfbr;
-    uint8_t stest1;
-    uint8_t stest2;
-    uint8_t stest3;
-    uint8_t sidl;
-    uint8_t stime0;
-    uint8_t respid0;
-    uint8_t respid1;
-    uint32_t mmrs;
-    uint32_t mmws;
-    uint32_t sfs;
-    uint32_t drs;
-    uint32_t sbms;
-    uint32_t dbms;
-    uint32_t dnad64;
-    uint32_t pmjad1;
-    uint32_t pmjad2;
-    uint32_t rbc;
-    uint32_t ua;
-    uint32_t ia;
-    uint32_t sbc;
-    uint32_t csbc;
-    uint32_t scratch[18]; /* SCRATCHA-SCRATCHR */
-    uint8_t sbr;
-
-    /* Script ram is stored as 32-bit words in host byteorder.  */
-    uint32_t script_ram[2048];
-} LSIState;
-
-static inline int lsi_irq_on_rsl(LSIState *s)
-{
-    return (s->sien0 & LSI_SIST0_RSL) && (s->scid & LSI_SCID_RRE);
-}
-
-static void lsi_soft_reset(LSIState *s)
-{
-    DPRINTF("Reset\n");
-    s->carry = 0;
-
-    s->msg_action = 0;
-    s->msg_len = 0;
-    s->waiting = 0;
-    s->dsa = 0;
-    s->dnad = 0;
-    s->dbc = 0;
-    s->temp = 0;
-    memset(s->scratch, 0, sizeof(s->scratch));
-    s->istat0 = 0;
-    s->istat1 = 0;
-    s->dcmd = 0x40;
-    s->dstat = LSI_DSTAT_DFE;
-    s->dien = 0;
-    s->sist0 = 0;
-    s->sist1 = 0;
-    s->sien0 = 0;
-    s->sien1 = 0;
-    s->mbox0 = 0;
-    s->mbox1 = 0;
-    s->dfifo = 0;
-    s->ctest2 = LSI_CTEST2_DACK;
-    s->ctest3 = 0;
-    s->ctest4 = 0;
-    s->ctest5 = 0;
-    s->ccntl0 = 0;
-    s->ccntl1 = 0;
-    s->dsp = 0;
-    s->dsps = 0;
-    s->dmode = 0;
-    s->dcntl = 0;
-    s->scntl0 = 0xc0;
-    s->scntl1 = 0;
-    s->scntl2 = 0;
-    s->scntl3 = 0;
-    s->sstat0 = 0;
-    s->sstat1 = 0;
-    s->scid = 7;
-    s->sxfer = 0;
-    s->socl = 0;
-    s->sdid = 0;
-    s->ssid = 0;
-    s->stest1 = 0;
-    s->stest2 = 0;
-    s->stest3 = 0;
-    s->sidl = 0;
-    s->stime0 = 0;
-    s->respid0 = 0x80;
-    s->respid1 = 0;
-    s->mmrs = 0;
-    s->mmws = 0;
-    s->sfs = 0;
-    s->drs = 0;
-    s->sbms = 0;
-    s->dbms = 0;
-    s->dnad64 = 0;
-    s->pmjad1 = 0;
-    s->pmjad2 = 0;
-    s->rbc = 0;
-    s->ua = 0;
-    s->ia = 0;
-    s->sbc = 0;
-    s->csbc = 0;
-    s->sbr = 0;
-    assert(QTAILQ_EMPTY(&s->queue));
-    assert(!s->current);
-}
-
-static int lsi_dma_40bit(LSIState *s)
-{
-    if ((s->ccntl1 & LSI_CCNTL1_40BIT) == LSI_CCNTL1_40BIT)
-        return 1;
-    return 0;
-}
-
-static int lsi_dma_ti64bit(LSIState *s)
-{
-    if ((s->ccntl1 & LSI_CCNTL1_EN64TIBMV) == LSI_CCNTL1_EN64TIBMV)
-        return 1;
-    return 0;
-}
-
-static int lsi_dma_64bit(LSIState *s)
-{
-    if ((s->ccntl1 & LSI_CCNTL1_EN64DBMV) == LSI_CCNTL1_EN64DBMV)
-        return 1;
-    return 0;
-}
-
-static uint8_t lsi_reg_readb(LSIState *s, int offset);
-static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val);
-static void lsi_execute_script(LSIState *s);
-static void lsi_reselect(LSIState *s, lsi_request *p);
-
-static inline uint32_t read_dword(LSIState *s, uint32_t addr)
-{
-    uint32_t buf;
-
-    pci_dma_read(&s->dev, addr, &buf, 4);
-    return cpu_to_le32(buf);
-}
-
-static void lsi_stop_script(LSIState *s)
-{
-    s->istat1 &= ~LSI_ISTAT1_SRUN;
-}
-
-static void lsi_update_irq(LSIState *s)
-{
-    int level;
-    static int last_level;
-    lsi_request *p;
-
-    /* It's unclear whether the DIP/SIP bits should be cleared when the
-       Interrupt Status Registers are cleared or when istat0 is read.
-       We currently do the formwer, which seems to work.  */
-    level = 0;
-    if (s->dstat) {
-        if (s->dstat & s->dien)
-            level = 1;
-        s->istat0 |= LSI_ISTAT0_DIP;
-    } else {
-        s->istat0 &= ~LSI_ISTAT0_DIP;
-    }
-
-    if (s->sist0 || s->sist1) {
-        if ((s->sist0 & s->sien0) || (s->sist1 & s->sien1))
-            level = 1;
-        s->istat0 |= LSI_ISTAT0_SIP;
-    } else {
-        s->istat0 &= ~LSI_ISTAT0_SIP;
-    }
-    if (s->istat0 & LSI_ISTAT0_INTF)
-        level = 1;
-
-    if (level != last_level) {
-        DPRINTF("Update IRQ level %d dstat %02x sist %02x%02x\n",
-                level, s->dstat, s->sist1, s->sist0);
-        last_level = level;
-    }
-    qemu_set_irq(s->dev.irq[0], level);
-
-    if (!level && lsi_irq_on_rsl(s) && !(s->scntl1 & LSI_SCNTL1_CON)) {
-        DPRINTF("Handled IRQs & disconnected, looking for pending "
-                "processes\n");
-        QTAILQ_FOREACH(p, &s->queue, next) {
-            if (p->pending) {
-                lsi_reselect(s, p);
-                break;
-            }
-        }
-    }
-}
-
-/* Stop SCRIPTS execution and raise a SCSI interrupt.  */
-static void lsi_script_scsi_interrupt(LSIState *s, int stat0, int stat1)
-{
-    uint32_t mask0;
-    uint32_t mask1;
-
-    DPRINTF("SCSI Interrupt 0x%02x%02x prev 0x%02x%02x\n",
-            stat1, stat0, s->sist1, s->sist0);
-    s->sist0 |= stat0;
-    s->sist1 |= stat1;
-    /* Stop processor on fatal or unmasked interrupt.  As a special hack
-       we don't stop processing when raising STO.  Instead continue
-       execution and stop at the next insn that accesses the SCSI bus.  */
-    mask0 = s->sien0 | ~(LSI_SIST0_CMP | LSI_SIST0_SEL | LSI_SIST0_RSL);
-    mask1 = s->sien1 | ~(LSI_SIST1_GEN | LSI_SIST1_HTH);
-    mask1 &= ~LSI_SIST1_STO;
-    if (s->sist0 & mask0 || s->sist1 & mask1) {
-        lsi_stop_script(s);
-    }
-    lsi_update_irq(s);
-}
-
-/* Stop SCRIPTS execution and raise a DMA interrupt.  */
-static void lsi_script_dma_interrupt(LSIState *s, int stat)
-{
-    DPRINTF("DMA Interrupt 0x%x prev 0x%x\n", stat, s->dstat);
-    s->dstat |= stat;
-    lsi_update_irq(s);
-    lsi_stop_script(s);
-}
-
-static inline void lsi_set_phase(LSIState *s, int phase)
-{
-    s->sstat1 = (s->sstat1 & ~PHASE_MASK) | phase;
-}
-
-static void lsi_bad_phase(LSIState *s, int out, int new_phase)
-{
-    /* Trigger a phase mismatch.  */
-    if (s->ccntl0 & LSI_CCNTL0_ENPMJ) {
-        if ((s->ccntl0 & LSI_CCNTL0_PMJCTL)) {
-            s->dsp = out ? s->pmjad1 : s->pmjad2;
-        } else {
-            s->dsp = (s->scntl2 & LSI_SCNTL2_WSR ? s->pmjad2 : s->pmjad1);
-        }
-        DPRINTF("Data phase mismatch jump to %08x\n", s->dsp);
-    } else {
-        DPRINTF("Phase mismatch interrupt\n");
-        lsi_script_scsi_interrupt(s, LSI_SIST0_MA, 0);
-        lsi_stop_script(s);
-    }
-    lsi_set_phase(s, new_phase);
-}
-
-
-/* Resume SCRIPTS execution after a DMA operation.  */
-static void lsi_resume_script(LSIState *s)
-{
-    if (s->waiting != 2) {
-        s->waiting = 0;
-        lsi_execute_script(s);
-    } else {
-        s->waiting = 0;
-    }
-}
-
-static void lsi_disconnect(LSIState *s)
-{
-    s->scntl1 &= ~LSI_SCNTL1_CON;
-    s->sstat1 &= ~PHASE_MASK;
-}
-
-static void lsi_bad_selection(LSIState *s, uint32_t id)
-{
-    DPRINTF("Selected absent target %d\n", id);
-    lsi_script_scsi_interrupt(s, 0, LSI_SIST1_STO);
-    lsi_disconnect(s);
-}
-
-/* Initiate a SCSI layer data transfer.  */
-static void lsi_do_dma(LSIState *s, int out)
-{
-    uint32_t count;
-    dma_addr_t addr;
-    SCSIDevice *dev;
-
-    assert(s->current);
-    if (!s->current->dma_len) {
-        /* Wait until data is available.  */
-        DPRINTF("DMA no data available\n");
-        return;
-    }
-
-    dev = s->current->req->dev;
-    assert(dev);
-
-    count = s->dbc;
-    if (count > s->current->dma_len)
-        count = s->current->dma_len;
-
-    addr = s->dnad;
-    /* both 40 and Table Indirect 64-bit DMAs store upper bits in dnad64 */
-    if (lsi_dma_40bit(s) || lsi_dma_ti64bit(s))
-        addr |= ((uint64_t)s->dnad64 << 32);
-    else if (s->dbms)
-        addr |= ((uint64_t)s->dbms << 32);
-    else if (s->sbms)
-        addr |= ((uint64_t)s->sbms << 32);
-
-    DPRINTF("DMA addr=0x" DMA_ADDR_FMT " len=%d\n", addr, count);
-    s->csbc += count;
-    s->dnad += count;
-    s->dbc -= count;
-     if (s->current->dma_buf == NULL) {
-        s->current->dma_buf = scsi_req_get_buf(s->current->req);
-    }
-    /* ??? Set SFBR to first data byte.  */
-    if (out) {
-        pci_dma_read(&s->dev, addr, s->current->dma_buf, count);
-    } else {
-        pci_dma_write(&s->dev, addr, s->current->dma_buf, count);
-    }
-    s->current->dma_len -= count;
-    if (s->current->dma_len == 0) {
-        s->current->dma_buf = NULL;
-        scsi_req_continue(s->current->req);
-    } else {
-        s->current->dma_buf += count;
-        lsi_resume_script(s);
-    }
-}
-
-
-/* Add a command to the queue.  */
-static void lsi_queue_command(LSIState *s)
-{
-    lsi_request *p = s->current;
-
-    DPRINTF("Queueing tag=0x%x\n", p->tag);
-    assert(s->current != NULL);
-    assert(s->current->dma_len == 0);
-    QTAILQ_INSERT_TAIL(&s->queue, s->current, next);
-    s->current = NULL;
-
-    p->pending = 0;
-    p->out = (s->sstat1 & PHASE_MASK) == PHASE_DO;
-}
-
-/* Queue a byte for a MSG IN phase.  */
-static void lsi_add_msg_byte(LSIState *s, uint8_t data)
-{
-    if (s->msg_len >= LSI_MAX_MSGIN_LEN) {
-        BADF("MSG IN data too long\n");
-    } else {
-        DPRINTF("MSG IN 0x%02x\n", data);
-        s->msg[s->msg_len++] = data;
-    }
-}
-
-/* Perform reselection to continue a command.  */
-static void lsi_reselect(LSIState *s, lsi_request *p)
-{
-    int id;
-
-    assert(s->current == NULL);
-    QTAILQ_REMOVE(&s->queue, p, next);
-    s->current = p;
-
-    id = (p->tag >> 8) & 0xf;
-    s->ssid = id | 0x80;
-    /* LSI53C700 Family Compatibility, see LSI53C895A 4-73 */
-    if (!(s->dcntl & LSI_DCNTL_COM)) {
-        s->sfbr = 1 << (id & 0x7);
-    }
-    DPRINTF("Reselected target %d\n", id);
-    s->scntl1 |= LSI_SCNTL1_CON;
-    lsi_set_phase(s, PHASE_MI);
-    s->msg_action = p->out ? 2 : 3;
-    s->current->dma_len = p->pending;
-    lsi_add_msg_byte(s, 0x80);
-    if (s->current->tag & LSI_TAG_VALID) {
-        lsi_add_msg_byte(s, 0x20);
-        lsi_add_msg_byte(s, p->tag & 0xff);
-    }
-
-    if (lsi_irq_on_rsl(s)) {
-        lsi_script_scsi_interrupt(s, LSI_SIST0_RSL, 0);
-    }
-}
-
-static lsi_request *lsi_find_by_tag(LSIState *s, uint32_t tag)
-{
-    lsi_request *p;
-
-    QTAILQ_FOREACH(p, &s->queue, next) {
-        if (p->tag == tag) {
-            return p;
-        }
-    }
-
-    return NULL;
-}
-
-static void lsi_request_free(LSIState *s, lsi_request *p)
-{
-    if (p == s->current) {
-        s->current = NULL;
-    } else {
-        QTAILQ_REMOVE(&s->queue, p, next);
-    }
-    g_free(p);
-}
-
-static void lsi_request_cancelled(SCSIRequest *req)
-{
-    LSIState *s = DO_UPCAST(LSIState, dev.qdev, req->bus->qbus.parent);
-    lsi_request *p = req->hba_private;
-
-    req->hba_private = NULL;
-    lsi_request_free(s, p);
-    scsi_req_unref(req);
-}
-
-/* Record that data is available for a queued command.  Returns zero if
-   the device was reselected, nonzero if the IO is deferred.  */
-static int lsi_queue_req(LSIState *s, SCSIRequest *req, uint32_t len)
-{
-    lsi_request *p = req->hba_private;
-
-    if (p->pending) {
-        BADF("Multiple IO pending for request %p\n", p);
-    }
-    p->pending = len;
-    /* Reselect if waiting for it, or if reselection triggers an IRQ
-       and the bus is free.
-       Since no interrupt stacking is implemented in the emulation, it
-       is also required that there are no pending interrupts waiting
-       for service from the device driver. */
-    if (s->waiting == 1 ||
-        (lsi_irq_on_rsl(s) && !(s->scntl1 & LSI_SCNTL1_CON) &&
-         !(s->istat0 & (LSI_ISTAT0_SIP | LSI_ISTAT0_DIP)))) {
-        /* Reselect device.  */
-        lsi_reselect(s, p);
-        return 0;
-    } else {
-        DPRINTF("Queueing IO tag=0x%x\n", p->tag);
-        p->pending = len;
-        return 1;
-    }
-}
-
- /* Callback to indicate that the SCSI layer has completed a command.  */
-static void lsi_command_complete(SCSIRequest *req, uint32_t status, size_t resid)
-{
-    LSIState *s = DO_UPCAST(LSIState, dev.qdev, req->bus->qbus.parent);
-    int out;
-
-    out = (s->sstat1 & PHASE_MASK) == PHASE_DO;
-    DPRINTF("Command complete status=%d\n", (int)status);
-    s->status = status;
-    s->command_complete = 2;
-    if (s->waiting && s->dbc != 0) {
-        /* Raise phase mismatch for short transfers.  */
-        lsi_bad_phase(s, out, PHASE_ST);
-    } else {
-        lsi_set_phase(s, PHASE_ST);
-    }
-
-    if (req->hba_private == s->current) {
-        req->hba_private = NULL;
-        lsi_request_free(s, s->current);
-        scsi_req_unref(req);
-    }
-    lsi_resume_script(s);
-}
-
- /* Callback to indicate that the SCSI layer has completed a transfer.  */
-static void lsi_transfer_data(SCSIRequest *req, uint32_t len)
-{
-    LSIState *s = DO_UPCAST(LSIState, dev.qdev, req->bus->qbus.parent);
-    int out;
-
-    assert(req->hba_private);
-    if (s->waiting == 1 || req->hba_private != s->current ||
-        (lsi_irq_on_rsl(s) && !(s->scntl1 & LSI_SCNTL1_CON))) {
-        if (lsi_queue_req(s, req, len)) {
-            return;
-        }
-    }
-
-    out = (s->sstat1 & PHASE_MASK) == PHASE_DO;
-
-    /* host adapter (re)connected */
-    DPRINTF("Data ready tag=0x%x len=%d\n", req->tag, len);
-    s->current->dma_len = len;
-    s->command_complete = 1;
-    if (s->waiting) {
-        if (s->waiting == 1 || s->dbc == 0) {
-            lsi_resume_script(s);
-        } else {
-            lsi_do_dma(s, out);
-        }
-    }
-}
-
-static void lsi_do_command(LSIState *s)
-{
-    SCSIDevice *dev;
-    uint8_t buf[16];
-    uint32_t id;
-    int n;
-
-    DPRINTF("Send command len=%d\n", s->dbc);
-    if (s->dbc > 16)
-        s->dbc = 16;
-    pci_dma_read(&s->dev, s->dnad, buf, s->dbc);
-    s->sfbr = buf[0];
-    s->command_complete = 0;
-
-    id = (s->select_tag >> 8) & 0xf;
-    dev = scsi_device_find(&s->bus, 0, id, s->current_lun);
-    if (!dev) {
-        lsi_bad_selection(s, id);
-        return;
-    }
-
-    assert(s->current == NULL);
-    s->current = g_malloc0(sizeof(lsi_request));
-    s->current->tag = s->select_tag;
-    s->current->req = scsi_req_new(dev, s->current->tag, s->current_lun, buf,
-                                   s->current);
-
-    n = scsi_req_enqueue(s->current->req);
-    if (n) {
-        if (n > 0) {
-            lsi_set_phase(s, PHASE_DI);
-        } else if (n < 0) {
-            lsi_set_phase(s, PHASE_DO);
-        }
-        scsi_req_continue(s->current->req);
-    }
-    if (!s->command_complete) {
-        if (n) {
-            /* Command did not complete immediately so disconnect.  */
-            lsi_add_msg_byte(s, 2); /* SAVE DATA POINTER */
-            lsi_add_msg_byte(s, 4); /* DISCONNECT */
-            /* wait data */
-            lsi_set_phase(s, PHASE_MI);
-            s->msg_action = 1;
-            lsi_queue_command(s);
-        } else {
-            /* wait command complete */
-            lsi_set_phase(s, PHASE_DI);
-        }
-    }
-}
-
-static void lsi_do_status(LSIState *s)
-{
-    uint8_t status;
-    DPRINTF("Get status len=%d status=%d\n", s->dbc, s->status);
-    if (s->dbc != 1)
-        BADF("Bad Status move\n");
-    s->dbc = 1;
-    status = s->status;
-    s->sfbr = status;
-    pci_dma_write(&s->dev, s->dnad, &status, 1);
-    lsi_set_phase(s, PHASE_MI);
-    s->msg_action = 1;
-    lsi_add_msg_byte(s, 0); /* COMMAND COMPLETE */
-}
-
-static void lsi_do_msgin(LSIState *s)
-{
-    int len;
-    DPRINTF("Message in len=%d/%d\n", s->dbc, s->msg_len);
-    s->sfbr = s->msg[0];
-    len = s->msg_len;
-    if (len > s->dbc)
-        len = s->dbc;
-    pci_dma_write(&s->dev, s->dnad, s->msg, len);
-    /* Linux drivers rely on the last byte being in the SIDL.  */
-    s->sidl = s->msg[len - 1];
-    s->msg_len -= len;
-    if (s->msg_len) {
-        memmove(s->msg, s->msg + len, s->msg_len);
-    } else {
-        /* ??? Check if ATN (not yet implemented) is asserted and maybe
-           switch to PHASE_MO.  */
-        switch (s->msg_action) {
-        case 0:
-            lsi_set_phase(s, PHASE_CMD);
-            break;
-        case 1:
-            lsi_disconnect(s);
-            break;
-        case 2:
-            lsi_set_phase(s, PHASE_DO);
-            break;
-        case 3:
-            lsi_set_phase(s, PHASE_DI);
-            break;
-        default:
-            abort();
-        }
-    }
-}
-
-/* Read the next byte during a MSGOUT phase.  */
-static uint8_t lsi_get_msgbyte(LSIState *s)
-{
-    uint8_t data;
-    pci_dma_read(&s->dev, s->dnad, &data, 1);
-    s->dnad++;
-    s->dbc--;
-    return data;
-}
-
-/* Skip the next n bytes during a MSGOUT phase. */
-static void lsi_skip_msgbytes(LSIState *s, unsigned int n)
-{
-    s->dnad += n;
-    s->dbc  -= n;
-}
-
-static void lsi_do_msgout(LSIState *s)
-{
-    uint8_t msg;
-    int len;
-    uint32_t current_tag;
-    lsi_request *current_req, *p, *p_next;
-
-    if (s->current) {
-        current_tag = s->current->tag;
-        current_req = s->current;
-    } else {
-        current_tag = s->select_tag;
-        current_req = lsi_find_by_tag(s, current_tag);
-    }
-
-    DPRINTF("MSG out len=%d\n", s->dbc);
-    while (s->dbc) {
-        msg = lsi_get_msgbyte(s);
-        s->sfbr = msg;
-
-        switch (msg) {
-        case 0x04:
-            DPRINTF("MSG: Disconnect\n");
-            lsi_disconnect(s);
-            break;
-        case 0x08:
-            DPRINTF("MSG: No Operation\n");
-            lsi_set_phase(s, PHASE_CMD);
-            break;
-        case 0x01:
-            len = lsi_get_msgbyte(s);
-            msg = lsi_get_msgbyte(s);
-            (void)len; /* avoid a warning about unused variable*/
-            DPRINTF("Extended message 0x%x (len %d)\n", msg, len);
-            switch (msg) {
-            case 1:
-                DPRINTF("SDTR (ignored)\n");
-                lsi_skip_msgbytes(s, 2);
-                break;
-            case 3:
-                DPRINTF("WDTR (ignored)\n");
-                lsi_skip_msgbytes(s, 1);
-                break;
-            default:
-                goto bad;
-            }
-            break;
-        case 0x20: /* SIMPLE queue */
-            s->select_tag |= lsi_get_msgbyte(s) | LSI_TAG_VALID;
-            DPRINTF("SIMPLE queue tag=0x%x\n", s->select_tag & 0xff);
-            break;
-        case 0x21: /* HEAD of queue */
-            BADF("HEAD queue not implemented\n");
-            s->select_tag |= lsi_get_msgbyte(s) | LSI_TAG_VALID;
-            break;
-        case 0x22: /* ORDERED queue */
-            BADF("ORDERED queue not implemented\n");
-            s->select_tag |= lsi_get_msgbyte(s) | LSI_TAG_VALID;
-            break;
-        case 0x0d:
-            /* The ABORT TAG message clears the current I/O process only. */
-            DPRINTF("MSG: ABORT TAG tag=0x%x\n", current_tag);
-            if (current_req) {
-                scsi_req_cancel(current_req->req);
-            }
-            lsi_disconnect(s);
-            break;
-        case 0x06:
-        case 0x0e:
-        case 0x0c:
-            /* The ABORT message clears all I/O processes for the selecting
-               initiator on the specified logical unit of the target. */
-            if (msg == 0x06) {
-                DPRINTF("MSG: ABORT tag=0x%x\n", current_tag);
-            }
-            /* The CLEAR QUEUE message clears all I/O processes for all
-               initiators on the specified logical unit of the target. */
-            if (msg == 0x0e) {
-                DPRINTF("MSG: CLEAR QUEUE tag=0x%x\n", current_tag);
-            }
-            /* The BUS DEVICE RESET message clears all I/O processes for all
-               initiators on all logical units of the target. */
-            if (msg == 0x0c) {
-                DPRINTF("MSG: BUS DEVICE RESET tag=0x%x\n", current_tag);
-            }
-
-            /* clear the current I/O process */
-            if (s->current) {
-                scsi_req_cancel(s->current->req);
-            }
-
-            /* As the current implemented devices scsi_disk and scsi_generic
-               only support one LUN, we don't need to keep track of LUNs.
-               Clearing I/O processes for other initiators could be possible
-               for scsi_generic by sending a SG_SCSI_RESET to the /dev/sgX
-               device, but this is currently not implemented (and seems not
-               to be really necessary). So let's simply clear all queued
-               commands for the current device: */
-            QTAILQ_FOREACH_SAFE(p, &s->queue, next, p_next) {
-                if ((p->tag & 0x0000ff00) == (current_tag & 0x0000ff00)) {
-                    scsi_req_cancel(p->req);
-                }
-            }
-
-            lsi_disconnect(s);
-            break;
-        default:
-            if ((msg & 0x80) == 0) {
-                goto bad;
-            }
-            s->current_lun = msg & 7;
-            DPRINTF("Select LUN %d\n", s->current_lun);
-            lsi_set_phase(s, PHASE_CMD);
-            break;
-        }
-    }
-    return;
-bad:
-    BADF("Unimplemented message 0x%02x\n", msg);
-    lsi_set_phase(s, PHASE_MI);
-    lsi_add_msg_byte(s, 7); /* MESSAGE REJECT */
-    s->msg_action = 0;
-}
-
-/* Sign extend a 24-bit value.  */
-static inline int32_t sxt24(int32_t n)
-{
-    return (n << 8) >> 8;
-}
-
-#define LSI_BUF_SIZE 4096
-static void lsi_memcpy(LSIState *s, uint32_t dest, uint32_t src, int count)
-{
-    int n;
-    uint8_t buf[LSI_BUF_SIZE];
-
-    DPRINTF("memcpy dest 0x%08x src 0x%08x count %d\n", dest, src, count);
-    while (count) {
-        n = (count > LSI_BUF_SIZE) ? LSI_BUF_SIZE : count;
-        pci_dma_read(&s->dev, src, buf, n);
-        pci_dma_write(&s->dev, dest, buf, n);
-        src += n;
-        dest += n;
-        count -= n;
-    }
-}
-
-static void lsi_wait_reselect(LSIState *s)
-{
-    lsi_request *p;
-
-    DPRINTF("Wait Reselect\n");
-
-    QTAILQ_FOREACH(p, &s->queue, next) {
-        if (p->pending) {
-            lsi_reselect(s, p);
-            break;
-        }
-    }
-    if (s->current == NULL) {
-        s->waiting = 1;
-    }
-}
-
-static void lsi_execute_script(LSIState *s)
-{
-    uint32_t insn;
-    uint32_t addr, addr_high;
-    int opcode;
-    int insn_processed = 0;
-
-    s->istat1 |= LSI_ISTAT1_SRUN;
-again:
-    insn_processed++;
-    insn = read_dword(s, s->dsp);
-    if (!insn) {
-        /* If we receive an empty opcode increment the DSP by 4 bytes
-           instead of 8 and execute the next opcode at that location */
-        s->dsp += 4;
-        goto again;
-    }
-    addr = read_dword(s, s->dsp + 4);
-    addr_high = 0;
-    DPRINTF("SCRIPTS dsp=%08x opcode %08x arg %08x\n", s->dsp, insn, addr);
-    s->dsps = addr;
-    s->dcmd = insn >> 24;
-    s->dsp += 8;
-    switch (insn >> 30) {
-    case 0: /* Block move.  */
-        if (s->sist1 & LSI_SIST1_STO) {
-            DPRINTF("Delayed select timeout\n");
-            lsi_stop_script(s);
-            break;
-        }
-        s->dbc = insn & 0xffffff;
-        s->rbc = s->dbc;
-        /* ??? Set ESA.  */
-        s->ia = s->dsp - 8;
-        if (insn & (1 << 29)) {
-            /* Indirect addressing.  */
-            addr = read_dword(s, addr);
-        } else if (insn & (1 << 28)) {
-            uint32_t buf[2];
-            int32_t offset;
-            /* Table indirect addressing.  */
-
-            /* 32-bit Table indirect */
-            offset = sxt24(addr);
-            pci_dma_read(&s->dev, s->dsa + offset, buf, 8);
-            /* byte count is stored in bits 0:23 only */
-            s->dbc = cpu_to_le32(buf[0]) & 0xffffff;
-            s->rbc = s->dbc;
-            addr = cpu_to_le32(buf[1]);
-
-            /* 40-bit DMA, upper addr bits [39:32] stored in first DWORD of
-             * table, bits [31:24] */
-            if (lsi_dma_40bit(s))
-                addr_high = cpu_to_le32(buf[0]) >> 24;
-            else if (lsi_dma_ti64bit(s)) {
-                int selector = (cpu_to_le32(buf[0]) >> 24) & 0x1f;
-                switch (selector) {
-                case 0 ... 0x0f:
-                    /* offset index into scratch registers since
-                     * TI64 mode can use registers C to R */
-                    addr_high = s->scratch[2 + selector];
-                    break;
-                case 0x10:
-                    addr_high = s->mmrs;
-                    break;
-                case 0x11:
-                    addr_high = s->mmws;
-                    break;
-                case 0x12:
-                    addr_high = s->sfs;
-                    break;
-                case 0x13:
-                    addr_high = s->drs;
-                    break;
-                case 0x14:
-                    addr_high = s->sbms;
-                    break;
-                case 0x15:
-                    addr_high = s->dbms;
-                    break;
-                default:
-                    BADF("Illegal selector specified (0x%x > 0x15)"
-                         " for 64-bit DMA block move", selector);
-                    break;
-                }
-            }
-        } else if (lsi_dma_64bit(s)) {
-            /* fetch a 3rd dword if 64-bit direct move is enabled and
-               only if we're not doing table indirect or indirect addressing */
-            s->dbms = read_dword(s, s->dsp);
-            s->dsp += 4;
-            s->ia = s->dsp - 12;
-        }
-        if ((s->sstat1 & PHASE_MASK) != ((insn >> 24) & 7)) {
-            DPRINTF("Wrong phase got %d expected %d\n",
-                    s->sstat1 & PHASE_MASK, (insn >> 24) & 7);
-            lsi_script_scsi_interrupt(s, LSI_SIST0_MA, 0);
-            break;
-        }
-        s->dnad = addr;
-        s->dnad64 = addr_high;
-        switch (s->sstat1 & 0x7) {
-        case PHASE_DO:
-            s->waiting = 2;
-            lsi_do_dma(s, 1);
-            if (s->waiting)
-                s->waiting = 3;
-            break;
-        case PHASE_DI:
-            s->waiting = 2;
-            lsi_do_dma(s, 0);
-            if (s->waiting)
-                s->waiting = 3;
-            break;
-        case PHASE_CMD:
-            lsi_do_command(s);
-            break;
-        case PHASE_ST:
-            lsi_do_status(s);
-            break;
-        case PHASE_MO:
-            lsi_do_msgout(s);
-            break;
-        case PHASE_MI:
-            lsi_do_msgin(s);
-            break;
-        default:
-            BADF("Unimplemented phase %d\n", s->sstat1 & PHASE_MASK);
-            exit(1);
-        }
-        s->dfifo = s->dbc & 0xff;
-        s->ctest5 = (s->ctest5 & 0xfc) | ((s->dbc >> 8) & 3);
-        s->sbc = s->dbc;
-        s->rbc -= s->dbc;
-        s->ua = addr + s->dbc;
-        break;
-
-    case 1: /* IO or Read/Write instruction.  */
-        opcode = (insn >> 27) & 7;
-        if (opcode < 5) {
-            uint32_t id;
-
-            if (insn & (1 << 25)) {
-                id = read_dword(s, s->dsa + sxt24(insn));
-            } else {
-                id = insn;
-            }
-            id = (id >> 16) & 0xf;
-            if (insn & (1 << 26)) {
-                addr = s->dsp + sxt24(addr);
-            }
-            s->dnad = addr;
-            switch (opcode) {
-            case 0: /* Select */
-                s->sdid = id;
-                if (s->scntl1 & LSI_SCNTL1_CON) {
-                    DPRINTF("Already reselected, jumping to alternative address\n");
-                    s->dsp = s->dnad;
-                    break;
-                }
-                s->sstat0 |= LSI_SSTAT0_WOA;
-                s->scntl1 &= ~LSI_SCNTL1_IARB;
-                if (!scsi_device_find(&s->bus, 0, id, 0)) {
-                    lsi_bad_selection(s, id);
-                    break;
-                }
-                DPRINTF("Selected target %d%s\n",
-                        id, insn & (1 << 3) ? " ATN" : "");
-                /* ??? Linux drivers compain when this is set.  Maybe
-                   it only applies in low-level mode (unimplemented).
-                lsi_script_scsi_interrupt(s, LSI_SIST0_CMP, 0); */
-                s->select_tag = id << 8;
-                s->scntl1 |= LSI_SCNTL1_CON;
-                if (insn & (1 << 3)) {
-                    s->socl |= LSI_SOCL_ATN;
-                }
-                lsi_set_phase(s, PHASE_MO);
-                break;
-            case 1: /* Disconnect */
-                DPRINTF("Wait Disconnect\n");
-                s->scntl1 &= ~LSI_SCNTL1_CON;
-                break;
-            case 2: /* Wait Reselect */
-                if (!lsi_irq_on_rsl(s)) {
-                    lsi_wait_reselect(s);
-                }
-                break;
-            case 3: /* Set */
-                DPRINTF("Set%s%s%s%s\n",
-                        insn & (1 << 3) ? " ATN" : "",
-                        insn & (1 << 6) ? " ACK" : "",
-                        insn & (1 << 9) ? " TM" : "",
-                        insn & (1 << 10) ? " CC" : "");
-                if (insn & (1 << 3)) {
-                    s->socl |= LSI_SOCL_ATN;
-                    lsi_set_phase(s, PHASE_MO);
-                }
-                if (insn & (1 << 9)) {
-                    BADF("Target mode not implemented\n");
-                    exit(1);
-                }
-                if (insn & (1 << 10))
-                    s->carry = 1;
-                break;
-            case 4: /* Clear */
-                DPRINTF("Clear%s%s%s%s\n",
-                        insn & (1 << 3) ? " ATN" : "",
-                        insn & (1 << 6) ? " ACK" : "",
-                        insn & (1 << 9) ? " TM" : "",
-                        insn & (1 << 10) ? " CC" : "");
-                if (insn & (1 << 3)) {
-                    s->socl &= ~LSI_SOCL_ATN;
-                }
-                if (insn & (1 << 10))
-                    s->carry = 0;
-                break;
-            }
-        } else {
-            uint8_t op0;
-            uint8_t op1;
-            uint8_t data8;
-            int reg;
-            int operator;
-#ifdef DEBUG_LSI
-            static const char *opcode_names[3] =
-                {"Write", "Read", "Read-Modify-Write"};
-            static const char *operator_names[8] =
-                {"MOV", "SHL", "OR", "XOR", "AND", "SHR", "ADD", "ADC"};
-#endif
-
-            reg = ((insn >> 16) & 0x7f) | (insn & 0x80);
-            data8 = (insn >> 8) & 0xff;
-            opcode = (insn >> 27) & 7;
-            operator = (insn >> 24) & 7;
-            DPRINTF("%s reg 0x%x %s data8=0x%02x sfbr=0x%02x%s\n",
-                    opcode_names[opcode - 5], reg,
-                    operator_names[operator], data8, s->sfbr,
-                    (insn & (1 << 23)) ? " SFBR" : "");
-            op0 = op1 = 0;
-            switch (opcode) {
-            case 5: /* From SFBR */
-                op0 = s->sfbr;
-                op1 = data8;
-                break;
-            case 6: /* To SFBR */
-                if (operator)
-                    op0 = lsi_reg_readb(s, reg);
-                op1 = data8;
-                break;
-            case 7: /* Read-modify-write */
-                if (operator)
-                    op0 = lsi_reg_readb(s, reg);
-                if (insn & (1 << 23)) {
-                    op1 = s->sfbr;
-                } else {
-                    op1 = data8;
-                }
-                break;
-            }
-
-            switch (operator) {
-            case 0: /* move */
-                op0 = op1;
-                break;
-            case 1: /* Shift left */
-                op1 = op0 >> 7;
-                op0 = (op0 << 1) | s->carry;
-                s->carry = op1;
-                break;
-            case 2: /* OR */
-                op0 |= op1;
-                break;
-            case 3: /* XOR */
-                op0 ^= op1;
-                break;
-            case 4: /* AND */
-                op0 &= op1;
-                break;
-            case 5: /* SHR */
-                op1 = op0 & 1;
-                op0 = (op0 >> 1) | (s->carry << 7);
-                s->carry = op1;
-                break;
-            case 6: /* ADD */
-                op0 += op1;
-                s->carry = op0 < op1;
-                break;
-            case 7: /* ADC */
-                op0 += op1 + s->carry;
-                if (s->carry)
-                    s->carry = op0 <= op1;
-                else
-                    s->carry = op0 < op1;
-                break;
-            }
-
-            switch (opcode) {
-            case 5: /* From SFBR */
-            case 7: /* Read-modify-write */
-                lsi_reg_writeb(s, reg, op0);
-                break;
-            case 6: /* To SFBR */
-                s->sfbr = op0;
-                break;
-            }
-        }
-        break;
-
-    case 2: /* Transfer Control.  */
-        {
-            int cond;
-            int jmp;
-
-            if ((insn & 0x002e0000) == 0) {
-                DPRINTF("NOP\n");
-                break;
-            }
-            if (s->sist1 & LSI_SIST1_STO) {
-                DPRINTF("Delayed select timeout\n");
-                lsi_stop_script(s);
-                break;
-            }
-            cond = jmp = (insn & (1 << 19)) != 0;
-            if (cond == jmp && (insn & (1 << 21))) {
-                DPRINTF("Compare carry %d\n", s->carry == jmp);
-                cond = s->carry != 0;
-            }
-            if (cond == jmp && (insn & (1 << 17))) {
-                DPRINTF("Compare phase %d %c= %d\n",
-                        (s->sstat1 & PHASE_MASK),
-                        jmp ? '=' : '!',
-                        ((insn >> 24) & 7));
-                cond = (s->sstat1 & PHASE_MASK) == ((insn >> 24) & 7);
-            }
-            if (cond == jmp && (insn & (1 << 18))) {
-                uint8_t mask;
-
-                mask = (~insn >> 8) & 0xff;
-                DPRINTF("Compare data 0x%x & 0x%x %c= 0x%x\n",
-                        s->sfbr, mask, jmp ? '=' : '!', insn & mask);
-                cond = (s->sfbr & mask) == (insn & mask);
-            }
-            if (cond == jmp) {
-                if (insn & (1 << 23)) {
-                    /* Relative address.  */
-                    addr = s->dsp + sxt24(addr);
-                }
-                switch ((insn >> 27) & 7) {
-                case 0: /* Jump */
-                    DPRINTF("Jump to 0x%08x\n", addr);
-                    s->dsp = addr;
-                    break;
-                case 1: /* Call */
-                    DPRINTF("Call 0x%08x\n", addr);
-                    s->temp = s->dsp;
-                    s->dsp = addr;
-                    break;
-                case 2: /* Return */
-                    DPRINTF("Return to 0x%08x\n", s->temp);
-                    s->dsp = s->temp;
-                    break;
-                case 3: /* Interrupt */
-                    DPRINTF("Interrupt 0x%08x\n", s->dsps);
-                    if ((insn & (1 << 20)) != 0) {
-                        s->istat0 |= LSI_ISTAT0_INTF;
-                        lsi_update_irq(s);
-                    } else {
-                        lsi_script_dma_interrupt(s, LSI_DSTAT_SIR);
-                    }
-                    break;
-                default:
-                    DPRINTF("Illegal transfer control\n");
-                    lsi_script_dma_interrupt(s, LSI_DSTAT_IID);
-                    break;
-                }
-            } else {
-                DPRINTF("Control condition failed\n");
-            }
-        }
-        break;
-
-    case 3:
-        if ((insn & (1 << 29)) == 0) {
-            /* Memory move.  */
-            uint32_t dest;
-            /* ??? The docs imply the destination address is loaded into
-               the TEMP register.  However the Linux drivers rely on
-               the value being presrved.  */
-            dest = read_dword(s, s->dsp);
-            s->dsp += 4;
-            lsi_memcpy(s, dest, addr, insn & 0xffffff);
-        } else {
-            uint8_t data[7];
-            int reg;
-            int n;
-            int i;
-
-            if (insn & (1 << 28)) {
-                addr = s->dsa + sxt24(addr);
-            }
-            n = (insn & 7);
-            reg = (insn >> 16) & 0xff;
-            if (insn & (1 << 24)) {
-                pci_dma_read(&s->dev, addr, data, n);
-                DPRINTF("Load reg 0x%x size %d addr 0x%08x = %08x\n", reg, n,
-                        addr, *(int *)data);
-                for (i = 0; i < n; i++) {
-                    lsi_reg_writeb(s, reg + i, data[i]);
-                }
-            } else {
-                DPRINTF("Store reg 0x%x size %d addr 0x%08x\n", reg, n, addr);
-                for (i = 0; i < n; i++) {
-                    data[i] = lsi_reg_readb(s, reg + i);
-                }
-                pci_dma_write(&s->dev, addr, data, n);
-            }
-        }
-    }
-    if (insn_processed > 10000 && !s->waiting) {
-        /* Some windows drivers make the device spin waiting for a memory
-           location to change.  If we have been executed a lot of code then
-           assume this is the case and force an unexpected device disconnect.
-           This is apparently sufficient to beat the drivers into submission.
-         */
-        if (!(s->sien0 & LSI_SIST0_UDC))
-            fprintf(stderr, "inf. loop with UDC masked\n");
-        lsi_script_scsi_interrupt(s, LSI_SIST0_UDC, 0);
-        lsi_disconnect(s);
-    } else if (s->istat1 & LSI_ISTAT1_SRUN && !s->waiting) {
-        if (s->dcntl & LSI_DCNTL_SSM) {
-            lsi_script_dma_interrupt(s, LSI_DSTAT_SSI);
-        } else {
-            goto again;
-        }
-    }
-    DPRINTF("SCRIPTS execution stopped\n");
-}
-
-static uint8_t lsi_reg_readb(LSIState *s, int offset)
-{
-    uint8_t tmp;
-#define CASE_GET_REG24(name, addr) \
-    case addr: return s->name & 0xff; \
-    case addr + 1: return (s->name >> 8) & 0xff; \
-    case addr + 2: return (s->name >> 16) & 0xff;
-
-#define CASE_GET_REG32(name, addr) \
-    case addr: return s->name & 0xff; \
-    case addr + 1: return (s->name >> 8) & 0xff; \
-    case addr + 2: return (s->name >> 16) & 0xff; \
-    case addr + 3: return (s->name >> 24) & 0xff;
-
-#ifdef DEBUG_LSI_REG
-    DPRINTF("Read reg %x\n", offset);
-#endif
-    switch (offset) {
-    case 0x00: /* SCNTL0 */
-        return s->scntl0;
-    case 0x01: /* SCNTL1 */
-        return s->scntl1;
-    case 0x02: /* SCNTL2 */
-        return s->scntl2;
-    case 0x03: /* SCNTL3 */
-        return s->scntl3;
-    case 0x04: /* SCID */
-        return s->scid;
-    case 0x05: /* SXFER */
-        return s->sxfer;
-    case 0x06: /* SDID */
-        return s->sdid;
-    case 0x07: /* GPREG0 */
-        return 0x7f;
-    case 0x08: /* Revision ID */
-        return 0x00;
-    case 0xa: /* SSID */
-        return s->ssid;
-    case 0xb: /* SBCL */
-        /* ??? This is not correct. However it's (hopefully) only
-           used for diagnostics, so should be ok.  */
-        return 0;
-    case 0xc: /* DSTAT */
-        tmp = s->dstat | 0x80;
-        if ((s->istat0 & LSI_ISTAT0_INTF) == 0)
-            s->dstat = 0;
-        lsi_update_irq(s);
-        return tmp;
-    case 0x0d: /* SSTAT0 */
-        return s->sstat0;
-    case 0x0e: /* SSTAT1 */
-        return s->sstat1;
-    case 0x0f: /* SSTAT2 */
-        return s->scntl1 & LSI_SCNTL1_CON ? 0 : 2;
-    CASE_GET_REG32(dsa, 0x10)
-    case 0x14: /* ISTAT0 */
-        return s->istat0;
-    case 0x15: /* ISTAT1 */
-        return s->istat1;
-    case 0x16: /* MBOX0 */
-        return s->mbox0;
-    case 0x17: /* MBOX1 */
-        return s->mbox1;
-    case 0x18: /* CTEST0 */
-        return 0xff;
-    case 0x19: /* CTEST1 */
-        return 0;
-    case 0x1a: /* CTEST2 */
-        tmp = s->ctest2 | LSI_CTEST2_DACK | LSI_CTEST2_CM;
-        if (s->istat0 & LSI_ISTAT0_SIGP) {
-            s->istat0 &= ~LSI_ISTAT0_SIGP;
-            tmp |= LSI_CTEST2_SIGP;
-        }
-        return tmp;
-    case 0x1b: /* CTEST3 */
-        return s->ctest3;
-    CASE_GET_REG32(temp, 0x1c)
-    case 0x20: /* DFIFO */
-        return 0;
-    case 0x21: /* CTEST4 */
-        return s->ctest4;
-    case 0x22: /* CTEST5 */
-        return s->ctest5;
-    case 0x23: /* CTEST6 */
-         return 0;
-    CASE_GET_REG24(dbc, 0x24)
-    case 0x27: /* DCMD */
-        return s->dcmd;
-    CASE_GET_REG32(dnad, 0x28)
-    CASE_GET_REG32(dsp, 0x2c)
-    CASE_GET_REG32(dsps, 0x30)
-    CASE_GET_REG32(scratch[0], 0x34)
-    case 0x38: /* DMODE */
-        return s->dmode;
-    case 0x39: /* DIEN */
-        return s->dien;
-    case 0x3a: /* SBR */
-        return s->sbr;
-    case 0x3b: /* DCNTL */
-        return s->dcntl;
-    case 0x40: /* SIEN0 */
-        return s->sien0;
-    case 0x41: /* SIEN1 */
-        return s->sien1;
-    case 0x42: /* SIST0 */
-        tmp = s->sist0;
-        s->sist0 = 0;
-        lsi_update_irq(s);
-        return tmp;
-    case 0x43: /* SIST1 */
-        tmp = s->sist1;
-        s->sist1 = 0;
-        lsi_update_irq(s);
-        return tmp;
-    case 0x46: /* MACNTL */
-        return 0x0f;
-    case 0x47: /* GPCNTL0 */
-        return 0x0f;
-    case 0x48: /* STIME0 */
-        return s->stime0;
-    case 0x4a: /* RESPID0 */
-        return s->respid0;
-    case 0x4b: /* RESPID1 */
-        return s->respid1;
-    case 0x4d: /* STEST1 */
-        return s->stest1;
-    case 0x4e: /* STEST2 */
-        return s->stest2;
-    case 0x4f: /* STEST3 */
-        return s->stest3;
-    case 0x50: /* SIDL */
-        /* This is needed by the linux drivers.  We currently only update it
-           during the MSG IN phase.  */
-        return s->sidl;
-    case 0x52: /* STEST4 */
-        return 0xe0;
-    case 0x56: /* CCNTL0 */
-        return s->ccntl0;
-    case 0x57: /* CCNTL1 */
-        return s->ccntl1;
-    case 0x58: /* SBDL */
-        /* Some drivers peek at the data bus during the MSG IN phase.  */
-        if ((s->sstat1 & PHASE_MASK) == PHASE_MI)
-            return s->msg[0];
-        return 0;
-    case 0x59: /* SBDL high */
-        return 0;
-    CASE_GET_REG32(mmrs, 0xa0)
-    CASE_GET_REG32(mmws, 0xa4)
-    CASE_GET_REG32(sfs, 0xa8)
-    CASE_GET_REG32(drs, 0xac)
-    CASE_GET_REG32(sbms, 0xb0)
-    CASE_GET_REG32(dbms, 0xb4)
-    CASE_GET_REG32(dnad64, 0xb8)
-    CASE_GET_REG32(pmjad1, 0xc0)
-    CASE_GET_REG32(pmjad2, 0xc4)
-    CASE_GET_REG32(rbc, 0xc8)
-    CASE_GET_REG32(ua, 0xcc)
-    CASE_GET_REG32(ia, 0xd4)
-    CASE_GET_REG32(sbc, 0xd8)
-    CASE_GET_REG32(csbc, 0xdc)
-    }
-    if (offset >= 0x5c && offset < 0xa0) {
-        int n;
-        int shift;
-        n = (offset - 0x58) >> 2;
-        shift = (offset & 3) * 8;
-        return (s->scratch[n] >> shift) & 0xff;
-    }
-    BADF("readb 0x%x\n", offset);
-    exit(1);
-#undef CASE_GET_REG24
-#undef CASE_GET_REG32
-}
-
-static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val)
-{
-#define CASE_SET_REG24(name, addr) \
-    case addr    : s->name &= 0xffffff00; s->name |= val;       break; \
-    case addr + 1: s->name &= 0xffff00ff; s->name |= val << 8;  break; \
-    case addr + 2: s->name &= 0xff00ffff; s->name |= val << 16; break;
-
-#define CASE_SET_REG32(name, addr) \
-    case addr    : s->name &= 0xffffff00; s->name |= val;       break; \
-    case addr + 1: s->name &= 0xffff00ff; s->name |= val << 8;  break; \
-    case addr + 2: s->name &= 0xff00ffff; s->name |= val << 16; break; \
-    case addr + 3: s->name &= 0x00ffffff; s->name |= val << 24; break;
-
-#ifdef DEBUG_LSI_REG
-    DPRINTF("Write reg %x = %02x\n", offset, val);
-#endif
-    switch (offset) {
-    case 0x00: /* SCNTL0 */
-        s->scntl0 = val;
-        if (val & LSI_SCNTL0_START) {
-            BADF("Start sequence not implemented\n");
-        }
-        break;
-    case 0x01: /* SCNTL1 */
-        s->scntl1 = val & ~LSI_SCNTL1_SST;
-        if (val & LSI_SCNTL1_IARB) {
-            BADF("Immediate Arbritration not implemented\n");
-        }
-        if (val & LSI_SCNTL1_RST) {
-            if (!(s->sstat0 & LSI_SSTAT0_RST)) {
-                qbus_reset_all(&s->bus.qbus);
-                s->sstat0 |= LSI_SSTAT0_RST;
-                lsi_script_scsi_interrupt(s, LSI_SIST0_RST, 0);
-            }
-        } else {
-            s->sstat0 &= ~LSI_SSTAT0_RST;
-        }
-        break;
-    case 0x02: /* SCNTL2 */
-        val &= ~(LSI_SCNTL2_WSR | LSI_SCNTL2_WSS);
-        s->scntl2 = val;
-        break;
-    case 0x03: /* SCNTL3 */
-        s->scntl3 = val;
-        break;
-    case 0x04: /* SCID */
-        s->scid = val;
-        break;
-    case 0x05: /* SXFER */
-        s->sxfer = val;
-        break;
-    case 0x06: /* SDID */
-        if ((val & 0xf) != (s->ssid & 0xf))
-            BADF("Destination ID does not match SSID\n");
-        s->sdid = val & 0xf;
-        break;
-    case 0x07: /* GPREG0 */
-        break;
-    case 0x08: /* SFBR */
-        /* The CPU is not allowed to write to this register.  However the
-           SCRIPTS register move instructions are.  */
-        s->sfbr = val;
-        break;
-    case 0x0a: case 0x0b:
-        /* Openserver writes to these readonly registers on startup */
-       return;
-    case 0x0c: case 0x0d: case 0x0e: case 0x0f:
-        /* Linux writes to these readonly registers on startup.  */
-        return;
-    CASE_SET_REG32(dsa, 0x10)
-    case 0x14: /* ISTAT0 */
-        s->istat0 = (s->istat0 & 0x0f) | (val & 0xf0);
-        if (val & LSI_ISTAT0_ABRT) {
-            lsi_script_dma_interrupt(s, LSI_DSTAT_ABRT);
-        }
-        if (val & LSI_ISTAT0_INTF) {
-            s->istat0 &= ~LSI_ISTAT0_INTF;
-            lsi_update_irq(s);
-        }
-        if (s->waiting == 1 && val & LSI_ISTAT0_SIGP) {
-            DPRINTF("Woken by SIGP\n");
-            s->waiting = 0;
-            s->dsp = s->dnad;
-            lsi_execute_script(s);
-        }
-        if (val & LSI_ISTAT0_SRST) {
-            qdev_reset_all(&s->dev.qdev);
-        }
-        break;
-    case 0x16: /* MBOX0 */
-        s->mbox0 = val;
-        break;
-    case 0x17: /* MBOX1 */
-        s->mbox1 = val;
-        break;
-    case 0x1a: /* CTEST2 */
-       s->ctest2 = val & LSI_CTEST2_PCICIE;
-       break;
-    case 0x1b: /* CTEST3 */
-        s->ctest3 = val & 0x0f;
-        break;
-    CASE_SET_REG32(temp, 0x1c)
-    case 0x21: /* CTEST4 */
-        if (val & 7) {
-           BADF("Unimplemented CTEST4-FBL 0x%x\n", val);
-        }
-        s->ctest4 = val;
-        break;
-    case 0x22: /* CTEST5 */
-        if (val & (LSI_CTEST5_ADCK | LSI_CTEST5_BBCK)) {
-            BADF("CTEST5 DMA increment not implemented\n");
-        }
-        s->ctest5 = val;
-        break;
-    CASE_SET_REG24(dbc, 0x24)
-    CASE_SET_REG32(dnad, 0x28)
-    case 0x2c: /* DSP[0:7] */
-        s->dsp &= 0xffffff00;
-        s->dsp |= val;
-        break;
-    case 0x2d: /* DSP[8:15] */
-        s->dsp &= 0xffff00ff;
-        s->dsp |= val << 8;
-        break;
-    case 0x2e: /* DSP[16:23] */
-        s->dsp &= 0xff00ffff;
-        s->dsp |= val << 16;
-        break;
-    case 0x2f: /* DSP[24:31] */
-        s->dsp &= 0x00ffffff;
-        s->dsp |= val << 24;
-        if ((s->dmode & LSI_DMODE_MAN) == 0
-            && (s->istat1 & LSI_ISTAT1_SRUN) == 0)
-            lsi_execute_script(s);
-        break;
-    CASE_SET_REG32(dsps, 0x30)
-    CASE_SET_REG32(scratch[0], 0x34)
-    case 0x38: /* DMODE */
-        if (val & (LSI_DMODE_SIOM | LSI_DMODE_DIOM)) {
-            BADF("IO mappings not implemented\n");
-        }
-        s->dmode = val;
-        break;
-    case 0x39: /* DIEN */
-        s->dien = val;
-        lsi_update_irq(s);
-        break;
-    case 0x3a: /* SBR */
-        s->sbr = val;
-        break;
-    case 0x3b: /* DCNTL */
-        s->dcntl = val & ~(LSI_DCNTL_PFF | LSI_DCNTL_STD);
-        if ((val & LSI_DCNTL_STD) && (s->istat1 & LSI_ISTAT1_SRUN) == 0)
-            lsi_execute_script(s);
-        break;
-    case 0x40: /* SIEN0 */
-        s->sien0 = val;
-        lsi_update_irq(s);
-        break;
-    case 0x41: /* SIEN1 */
-        s->sien1 = val;
-        lsi_update_irq(s);
-        break;
-    case 0x47: /* GPCNTL0 */
-        break;
-    case 0x48: /* STIME0 */
-        s->stime0 = val;
-        break;
-    case 0x49: /* STIME1 */
-        if (val & 0xf) {
-            DPRINTF("General purpose timer not implemented\n");
-            /* ??? Raising the interrupt immediately seems to be sufficient
-               to keep the FreeBSD driver happy.  */
-            lsi_script_scsi_interrupt(s, 0, LSI_SIST1_GEN);
-        }
-        break;
-    case 0x4a: /* RESPID0 */
-        s->respid0 = val;
-        break;
-    case 0x4b: /* RESPID1 */
-        s->respid1 = val;
-        break;
-    case 0x4d: /* STEST1 */
-        s->stest1 = val;
-        break;
-    case 0x4e: /* STEST2 */
-        if (val & 1) {
-            BADF("Low level mode not implemented\n");
-        }
-        s->stest2 = val;
-        break;
-    case 0x4f: /* STEST3 */
-        if (val & 0x41) {
-            BADF("SCSI FIFO test mode not implemented\n");
-        }
-        s->stest3 = val;
-        break;
-    case 0x56: /* CCNTL0 */
-        s->ccntl0 = val;
-        break;
-    case 0x57: /* CCNTL1 */
-        s->ccntl1 = val;
-        break;
-    CASE_SET_REG32(mmrs, 0xa0)
-    CASE_SET_REG32(mmws, 0xa4)
-    CASE_SET_REG32(sfs, 0xa8)
-    CASE_SET_REG32(drs, 0xac)
-    CASE_SET_REG32(sbms, 0xb0)
-    CASE_SET_REG32(dbms, 0xb4)
-    CASE_SET_REG32(dnad64, 0xb8)
-    CASE_SET_REG32(pmjad1, 0xc0)
-    CASE_SET_REG32(pmjad2, 0xc4)
-    CASE_SET_REG32(rbc, 0xc8)
-    CASE_SET_REG32(ua, 0xcc)
-    CASE_SET_REG32(ia, 0xd4)
-    CASE_SET_REG32(sbc, 0xd8)
-    CASE_SET_REG32(csbc, 0xdc)
-    default:
-        if (offset >= 0x5c && offset < 0xa0) {
-            int n;
-            int shift;
-            n = (offset - 0x58) >> 2;
-            shift = (offset & 3) * 8;
-            s->scratch[n] &= ~(0xff << shift);
-            s->scratch[n] |= (val & 0xff) << shift;
-        } else {
-            BADF("Unhandled writeb 0x%x = 0x%x\n", offset, val);
-        }
-    }
-#undef CASE_SET_REG24
-#undef CASE_SET_REG32
-}
-
-static void lsi_mmio_write(void *opaque, hwaddr addr,
-                           uint64_t val, unsigned size)
-{
-    LSIState *s = opaque;
-
-    lsi_reg_writeb(s, addr & 0xff, val);
-}
-
-static uint64_t lsi_mmio_read(void *opaque, hwaddr addr,
-                              unsigned size)
-{
-    LSIState *s = opaque;
-
-    return lsi_reg_readb(s, addr & 0xff);
-}
-
-static const MemoryRegionOps lsi_mmio_ops = {
-    .read = lsi_mmio_read,
-    .write = lsi_mmio_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .impl = {
-        .min_access_size = 1,
-        .max_access_size = 1,
-    },
-};
-
-static void lsi_ram_write(void *opaque, hwaddr addr,
-                          uint64_t val, unsigned size)
-{
-    LSIState *s = opaque;
-    uint32_t newval;
-    uint32_t mask;
-    int shift;
-
-    newval = s->script_ram[addr >> 2];
-    shift = (addr & 3) * 8;
-    mask = ((uint64_t)1 << (size * 8)) - 1;
-    newval &= ~(mask << shift);
-    newval |= val << shift;
-    s->script_ram[addr >> 2] = newval;
-}
-
-static uint64_t lsi_ram_read(void *opaque, hwaddr addr,
-                             unsigned size)
-{
-    LSIState *s = opaque;
-    uint32_t val;
-    uint32_t mask;
-
-    val = s->script_ram[addr >> 2];
-    mask = ((uint64_t)1 << (size * 8)) - 1;
-    val >>= (addr & 3) * 8;
-    return val & mask;
-}
-
-static const MemoryRegionOps lsi_ram_ops = {
-    .read = lsi_ram_read,
-    .write = lsi_ram_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static uint64_t lsi_io_read(void *opaque, hwaddr addr,
-                            unsigned size)
-{
-    LSIState *s = opaque;
-    return lsi_reg_readb(s, addr & 0xff);
-}
-
-static void lsi_io_write(void *opaque, hwaddr addr,
-                         uint64_t val, unsigned size)
-{
-    LSIState *s = opaque;
-    lsi_reg_writeb(s, addr & 0xff, val);
-}
-
-static const MemoryRegionOps lsi_io_ops = {
-    .read = lsi_io_read,
-    .write = lsi_io_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .impl = {
-        .min_access_size = 1,
-        .max_access_size = 1,
-    },
-};
-
-static void lsi_scsi_reset(DeviceState *dev)
-{
-    LSIState *s = DO_UPCAST(LSIState, dev.qdev, dev);
-
-    lsi_soft_reset(s);
-}
-
-static void lsi_pre_save(void *opaque)
-{
-    LSIState *s = opaque;
-
-    if (s->current) {
-        assert(s->current->dma_buf == NULL);
-        assert(s->current->dma_len == 0);
-    }
-    assert(QTAILQ_EMPTY(&s->queue));
-}
-
-static const VMStateDescription vmstate_lsi_scsi = {
-    .name = "lsiscsi",
-    .version_id = 0,
-    .minimum_version_id = 0,
-    .minimum_version_id_old = 0,
-    .pre_save = lsi_pre_save,
-    .fields      = (VMStateField []) {
-        VMSTATE_PCI_DEVICE(dev, LSIState),
-
-        VMSTATE_INT32(carry, LSIState),
-        VMSTATE_INT32(status, LSIState),
-        VMSTATE_INT32(msg_action, LSIState),
-        VMSTATE_INT32(msg_len, LSIState),
-        VMSTATE_BUFFER(msg, LSIState),
-        VMSTATE_INT32(waiting, LSIState),
-
-        VMSTATE_UINT32(dsa, LSIState),
-        VMSTATE_UINT32(temp, LSIState),
-        VMSTATE_UINT32(dnad, LSIState),
-        VMSTATE_UINT32(dbc, LSIState),
-        VMSTATE_UINT8(istat0, LSIState),
-        VMSTATE_UINT8(istat1, LSIState),
-        VMSTATE_UINT8(dcmd, LSIState),
-        VMSTATE_UINT8(dstat, LSIState),
-        VMSTATE_UINT8(dien, LSIState),
-        VMSTATE_UINT8(sist0, LSIState),
-        VMSTATE_UINT8(sist1, LSIState),
-        VMSTATE_UINT8(sien0, LSIState),
-        VMSTATE_UINT8(sien1, LSIState),
-        VMSTATE_UINT8(mbox0, LSIState),
-        VMSTATE_UINT8(mbox1, LSIState),
-        VMSTATE_UINT8(dfifo, LSIState),
-        VMSTATE_UINT8(ctest2, LSIState),
-        VMSTATE_UINT8(ctest3, LSIState),
-        VMSTATE_UINT8(ctest4, LSIState),
-        VMSTATE_UINT8(ctest5, LSIState),
-        VMSTATE_UINT8(ccntl0, LSIState),
-        VMSTATE_UINT8(ccntl1, LSIState),
-        VMSTATE_UINT32(dsp, LSIState),
-        VMSTATE_UINT32(dsps, LSIState),
-        VMSTATE_UINT8(dmode, LSIState),
-        VMSTATE_UINT8(dcntl, LSIState),
-        VMSTATE_UINT8(scntl0, LSIState),
-        VMSTATE_UINT8(scntl1, LSIState),
-        VMSTATE_UINT8(scntl2, LSIState),
-        VMSTATE_UINT8(scntl3, LSIState),
-        VMSTATE_UINT8(sstat0, LSIState),
-        VMSTATE_UINT8(sstat1, LSIState),
-        VMSTATE_UINT8(scid, LSIState),
-        VMSTATE_UINT8(sxfer, LSIState),
-        VMSTATE_UINT8(socl, LSIState),
-        VMSTATE_UINT8(sdid, LSIState),
-        VMSTATE_UINT8(ssid, LSIState),
-        VMSTATE_UINT8(sfbr, LSIState),
-        VMSTATE_UINT8(stest1, LSIState),
-        VMSTATE_UINT8(stest2, LSIState),
-        VMSTATE_UINT8(stest3, LSIState),
-        VMSTATE_UINT8(sidl, LSIState),
-        VMSTATE_UINT8(stime0, LSIState),
-        VMSTATE_UINT8(respid0, LSIState),
-        VMSTATE_UINT8(respid1, LSIState),
-        VMSTATE_UINT32(mmrs, LSIState),
-        VMSTATE_UINT32(mmws, LSIState),
-        VMSTATE_UINT32(sfs, LSIState),
-        VMSTATE_UINT32(drs, LSIState),
-        VMSTATE_UINT32(sbms, LSIState),
-        VMSTATE_UINT32(dbms, LSIState),
-        VMSTATE_UINT32(dnad64, LSIState),
-        VMSTATE_UINT32(pmjad1, LSIState),
-        VMSTATE_UINT32(pmjad2, LSIState),
-        VMSTATE_UINT32(rbc, LSIState),
-        VMSTATE_UINT32(ua, LSIState),
-        VMSTATE_UINT32(ia, LSIState),
-        VMSTATE_UINT32(sbc, LSIState),
-        VMSTATE_UINT32(csbc, LSIState),
-        VMSTATE_BUFFER_UNSAFE(scratch, LSIState, 0, 18 * sizeof(uint32_t)),
-        VMSTATE_UINT8(sbr, LSIState),
-
-        VMSTATE_BUFFER_UNSAFE(script_ram, LSIState, 0, 2048 * sizeof(uint32_t)),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void lsi_scsi_uninit(PCIDevice *d)
-{
-    LSIState *s = DO_UPCAST(LSIState, dev, d);
-
-    memory_region_destroy(&s->mmio_io);
-    memory_region_destroy(&s->ram_io);
-    memory_region_destroy(&s->io_io);
-}
-
-static const struct SCSIBusInfo lsi_scsi_info = {
-    .tcq = true,
-    .max_target = LSI_MAX_DEVS,
-    .max_lun = 0,  /* LUN support is buggy */
-
-    .transfer_data = lsi_transfer_data,
-    .complete = lsi_command_complete,
-    .cancel = lsi_request_cancelled
-};
-
-static int lsi_scsi_init(PCIDevice *dev)
-{
-    LSIState *s = DO_UPCAST(LSIState, dev, dev);
-    uint8_t *pci_conf;
-
-    pci_conf = s->dev.config;
-
-    /* PCI latency timer = 255 */
-    pci_conf[PCI_LATENCY_TIMER] = 0xff;
-    /* Interrupt pin A */
-    pci_conf[PCI_INTERRUPT_PIN] = 0x01;
-
-    memory_region_init_io(&s->mmio_io, &lsi_mmio_ops, s, "lsi-mmio", 0x400);
-    memory_region_init_io(&s->ram_io, &lsi_ram_ops, s, "lsi-ram", 0x2000);
-    memory_region_init_io(&s->io_io, &lsi_io_ops, s, "lsi-io", 256);
-
-    pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io_io);
-    pci_register_bar(&s->dev, 1, 0, &s->mmio_io);
-    pci_register_bar(&s->dev, 2, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->ram_io);
-    QTAILQ_INIT(&s->queue);
-
-    scsi_bus_new(&s->bus, &dev->qdev, &lsi_scsi_info);
-    if (!dev->qdev.hotplugged) {
-        return scsi_bus_legacy_handle_cmdline(&s->bus);
-    }
-    return 0;
-}
-
-static void lsi_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
-    k->init = lsi_scsi_init;
-    k->exit = lsi_scsi_uninit;
-    k->vendor_id = PCI_VENDOR_ID_LSI_LOGIC;
-    k->device_id = PCI_DEVICE_ID_LSI_53C895A;
-    k->class_id = PCI_CLASS_STORAGE_SCSI;
-    k->subsystem_id = 0x1000;
-    dc->reset = lsi_scsi_reset;
-    dc->vmsd = &vmstate_lsi_scsi;
-}
-
-static const TypeInfo lsi_info = {
-    .name          = "lsi53c895a",
-    .parent        = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(LSIState),
-    .class_init    = lsi_class_init,
-};
-
-static void lsi53c895a_register_types(void)
-{
-    type_register_static(&lsi_info);
-}
-
-type_init(lsi53c895a_register_types)
diff --git a/hw/m25p80.c b/hw/m25p80.c
deleted file mode 100644 (file)
index 55e9d0d..0000000
+++ /dev/null
@@ -1,672 +0,0 @@
-/*
- * ST M25P80 emulator. Emulate all SPI flash devices based on the m25p80 command
- * set. Known devices table current as of Jun/2012 and taken from linux.
- * See drivers/mtd/devices/m25p80.c.
- *
- * Copyright (C) 2011 Edgar E. Iglesias <edgar.iglesias@gmail.com>
- * Copyright (C) 2012 Peter A. G. Crosthwaite <peter.crosthwaite@petalogix.com>
- * Copyright (C) 2012 PetaLogix
- *
- * 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 or
- * (at your option) a later version 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
- * 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 "hw/hw.h"
-#include "sysemu/blockdev.h"
-#include "hw/ssi.h"
-#include "hw/devices.h"
-
-#ifdef M25P80_ERR_DEBUG
-#define DB_PRINT(...) do { \
-    fprintf(stderr,  ": %s: ", __func__); \
-    fprintf(stderr, ## __VA_ARGS__); \
-    } while (0);
-#else
-    #define DB_PRINT(...)
-#endif
-
-/* Fields for FlashPartInfo->flags */
-
-/* erase capabilities */
-#define ER_4K 1
-#define ER_32K 2
-/* set to allow the page program command to write 0s back to 1. Useful for
- * modelling EEPROM with SPI flash command set
- */
-#define WR_1 0x100
-
-typedef struct FlashPartInfo {
-    const char *part_name;
-    /* jedec code. (jedec >> 16) & 0xff is the 1st byte, >> 8 the 2nd etc */
-    uint32_t jedec;
-    /* extended jedec code */
-    uint16_t ext_jedec;
-    /* there is confusion between manufacturers as to what a sector is. In this
-     * device model, a "sector" is the size that is erased by the ERASE_SECTOR
-     * command (opcode 0xd8).
-     */
-    uint32_t sector_size;
-    uint32_t n_sectors;
-    uint32_t page_size;
-    uint8_t flags;
-} FlashPartInfo;
-
-/* adapted from linux */
-
-#define INFO(_part_name, _jedec, _ext_jedec, _sector_size, _n_sectors, _flags)\
-    .part_name = (_part_name),\
-    .jedec = (_jedec),\
-    .ext_jedec = (_ext_jedec),\
-    .sector_size = (_sector_size),\
-    .n_sectors = (_n_sectors),\
-    .page_size = 256,\
-    .flags = (_flags),\
-
-#define JEDEC_NUMONYX 0x20
-#define JEDEC_WINBOND 0xEF
-#define JEDEC_SPANSION 0x01
-
-static const FlashPartInfo known_devices[] = {
-    /* Atmel -- some are (confusingly) marketed as "DataFlash" */
-    { INFO("at25fs010",   0x1f6601,      0,  32 << 10,   4, ER_4K) },
-    { INFO("at25fs040",   0x1f6604,      0,  64 << 10,   8, ER_4K) },
-
-    { INFO("at25df041a",  0x1f4401,      0,  64 << 10,   8, ER_4K) },
-    { INFO("at25df321a",  0x1f4701,      0,  64 << 10,  64, ER_4K) },
-    { INFO("at25df641",   0x1f4800,      0,  64 << 10, 128, ER_4K) },
-
-    { INFO("at26f004",    0x1f0400,      0,  64 << 10,   8, ER_4K) },
-    { INFO("at26df081a",  0x1f4501,      0,  64 << 10,  16, ER_4K) },
-    { INFO("at26df161a",  0x1f4601,      0,  64 << 10,  32, ER_4K) },
-    { INFO("at26df321",   0x1f4700,      0,  64 << 10,  64, ER_4K) },
-
-    /* EON -- en25xxx */
-    { INFO("en25f32",     0x1c3116,      0,  64 << 10,  64, ER_4K) },
-    { INFO("en25p32",     0x1c2016,      0,  64 << 10,  64, 0) },
-    { INFO("en25q32b",    0x1c3016,      0,  64 << 10,  64, 0) },
-    { INFO("en25p64",     0x1c2017,      0,  64 << 10, 128, 0) },
-
-    /* Intel/Numonyx -- xxxs33b */
-    { INFO("160s33b",     0x898911,      0,  64 << 10,  32, 0) },
-    { INFO("320s33b",     0x898912,      0,  64 << 10,  64, 0) },
-    { INFO("640s33b",     0x898913,      0,  64 << 10, 128, 0) },
-
-    /* Macronix */
-    { INFO("mx25l4005a",  0xc22013,      0,  64 << 10,   8, ER_4K) },
-    { INFO("mx25l8005",   0xc22014,      0,  64 << 10,  16, 0) },
-    { INFO("mx25l1606e",  0xc22015,      0,  64 << 10,  32, ER_4K) },
-    { INFO("mx25l3205d",  0xc22016,      0,  64 << 10,  64, 0) },
-    { INFO("mx25l6405d",  0xc22017,      0,  64 << 10, 128, 0) },
-    { INFO("mx25l12805d", 0xc22018,      0,  64 << 10, 256, 0) },
-    { INFO("mx25l12855e", 0xc22618,      0,  64 << 10, 256, 0) },
-    { INFO("mx25l25635e", 0xc22019,      0,  64 << 10, 512, 0) },
-    { INFO("mx25l25655e", 0xc22619,      0,  64 << 10, 512, 0) },
-
-    /* Spansion -- single (large) sector size only, at least
-     * for the chips listed here (without boot sectors).
-     */
-    { INFO("s25sl004a",   0x010212,      0,  64 << 10,   8, 0) },
-    { INFO("s25sl008a",   0x010213,      0,  64 << 10,  16, 0) },
-    { INFO("s25sl016a",   0x010214,      0,  64 << 10,  32, 0) },
-    { INFO("s25sl032a",   0x010215,      0,  64 << 10,  64, 0) },
-    { INFO("s25sl032p",   0x010215, 0x4d00,  64 << 10,  64, ER_4K) },
-    { INFO("s25sl064a",   0x010216,      0,  64 << 10, 128, 0) },
-    { INFO("s25fl256s0",  0x010219, 0x4d00, 256 << 10, 128, 0) },
-    { INFO("s25fl256s1",  0x010219, 0x4d01,  64 << 10, 512, 0) },
-    { INFO("s25fl512s",   0x010220, 0x4d00, 256 << 10, 256, 0) },
-    { INFO("s70fl01gs",   0x010221, 0x4d00, 256 << 10, 256, 0) },
-    { INFO("s25sl12800",  0x012018, 0x0300, 256 << 10,  64, 0) },
-    { INFO("s25sl12801",  0x012018, 0x0301,  64 << 10, 256, 0) },
-    { INFO("s25fl129p0",  0x012018, 0x4d00, 256 << 10,  64, 0) },
-    { INFO("s25fl129p1",  0x012018, 0x4d01,  64 << 10, 256, 0) },
-    { INFO("s25fl016k",   0xef4015,      0,  64 << 10,  32, ER_4K | ER_32K) },
-    { INFO("s25fl064k",   0xef4017,      0,  64 << 10, 128, ER_4K | ER_32K) },
-
-    /* SST -- large erase sizes are "overlays", "sectors" are 4<< 10 */
-    { INFO("sst25vf040b", 0xbf258d,      0,  64 << 10,   8, ER_4K) },
-    { INFO("sst25vf080b", 0xbf258e,      0,  64 << 10,  16, ER_4K) },
-    { INFO("sst25vf016b", 0xbf2541,      0,  64 << 10,  32, ER_4K) },
-    { INFO("sst25vf032b", 0xbf254a,      0,  64 << 10,  64, ER_4K) },
-    { INFO("sst25wf512",  0xbf2501,      0,  64 << 10,   1, ER_4K) },
-    { INFO("sst25wf010",  0xbf2502,      0,  64 << 10,   2, ER_4K) },
-    { INFO("sst25wf020",  0xbf2503,      0,  64 << 10,   4, ER_4K) },
-    { INFO("sst25wf040",  0xbf2504,      0,  64 << 10,   8, ER_4K) },
-
-    /* ST Microelectronics -- newer production may have feature updates */
-    { INFO("m25p05",      0x202010,      0,  32 << 10,   2, 0) },
-    { INFO("m25p10",      0x202011,      0,  32 << 10,   4, 0) },
-    { INFO("m25p20",      0x202012,      0,  64 << 10,   4, 0) },
-    { INFO("m25p40",      0x202013,      0,  64 << 10,   8, 0) },
-    { INFO("m25p80",      0x202014,      0,  64 << 10,  16, 0) },
-    { INFO("m25p16",      0x202015,      0,  64 << 10,  32, 0) },
-    { INFO("m25p32",      0x202016,      0,  64 << 10,  64, 0) },
-    { INFO("m25p64",      0x202017,      0,  64 << 10, 128, 0) },
-    { INFO("m25p128",     0x202018,      0, 256 << 10,  64, 0) },
-
-    { INFO("m45pe10",     0x204011,      0,  64 << 10,   2, 0) },
-    { INFO("m45pe80",     0x204014,      0,  64 << 10,  16, 0) },
-    { INFO("m45pe16",     0x204015,      0,  64 << 10,  32, 0) },
-
-    { INFO("m25pe80",     0x208014,      0,  64 << 10,  16, 0) },
-    { INFO("m25pe16",     0x208015,      0,  64 << 10,  32, ER_4K) },
-
-    { INFO("m25px32",     0x207116,      0,  64 << 10,  64, ER_4K) },
-    { INFO("m25px32-s0",  0x207316,      0,  64 << 10,  64, ER_4K) },
-    { INFO("m25px32-s1",  0x206316,      0,  64 << 10,  64, ER_4K) },
-    { INFO("m25px64",     0x207117,      0,  64 << 10, 128, 0) },
-
-    /* Winbond -- w25x "blocks" are 64k, "sectors" are 4KiB */
-    { INFO("w25x10",      0xef3011,      0,  64 << 10,   2, ER_4K) },
-    { INFO("w25x20",      0xef3012,      0,  64 << 10,   4, ER_4K) },
-    { INFO("w25x40",      0xef3013,      0,  64 << 10,   8, ER_4K) },
-    { INFO("w25x80",      0xef3014,      0,  64 << 10,  16, ER_4K) },
-    { INFO("w25x16",      0xef3015,      0,  64 << 10,  32, ER_4K) },
-    { INFO("w25x32",      0xef3016,      0,  64 << 10,  64, ER_4K) },
-    { INFO("w25q32",      0xef4016,      0,  64 << 10,  64, ER_4K) },
-    { INFO("w25x64",      0xef3017,      0,  64 << 10, 128, ER_4K) },
-    { INFO("w25q64",      0xef4017,      0,  64 << 10, 128, ER_4K) },
-
-    /* Numonyx -- n25q128 */
-    { INFO("n25q128",      0x20ba18,      0,  64 << 10, 256, 0) },
-};
-
-typedef enum {
-    NOP = 0,
-    WRSR = 0x1,
-    WRDI = 0x4,
-    RDSR = 0x5,
-    WREN = 0x6,
-    JEDEC_READ = 0x9f,
-    BULK_ERASE = 0xc7,
-
-    READ = 0x3,
-    FAST_READ = 0xb,
-    DOR = 0x3b,
-    QOR = 0x6b,
-    DIOR = 0xbb,
-    QIOR = 0xeb,
-
-    PP = 0x2,
-    DPP = 0xa2,
-    QPP = 0x32,
-
-    ERASE_4K = 0x20,
-    ERASE_32K = 0x52,
-    ERASE_SECTOR = 0xd8,
-} FlashCMD;
-
-typedef enum {
-    STATE_IDLE,
-    STATE_PAGE_PROGRAM,
-    STATE_READ,
-    STATE_COLLECTING_DATA,
-    STATE_READING_DATA,
-} CMDState;
-
-typedef struct Flash {
-    SSISlave ssidev;
-    uint32_t r;
-
-    BlockDriverState *bdrv;
-
-    uint8_t *storage;
-    uint32_t size;
-    int page_size;
-
-    uint8_t state;
-    uint8_t data[16];
-    uint32_t len;
-    uint32_t pos;
-    uint8_t needed_bytes;
-    uint8_t cmd_in_progress;
-    uint64_t cur_addr;
-    bool write_enable;
-
-    int64_t dirty_page;
-
-    const FlashPartInfo *pi;
-
-} Flash;
-
-typedef struct M25P80Class {
-    SSISlaveClass parent_class;
-    FlashPartInfo *pi;
-} M25P80Class;
-
-#define TYPE_M25P80 "m25p80-generic"
-#define M25P80(obj) \
-     OBJECT_CHECK(Flash, (obj), TYPE_M25P80)
-#define M25P80_CLASS(klass) \
-     OBJECT_CLASS_CHECK(M25P80Class, (klass), TYPE_M25P80)
-#define M25P80_GET_CLASS(obj) \
-     OBJECT_GET_CLASS(M25P80Class, (obj), TYPE_M25P80)
-
-static void bdrv_sync_complete(void *opaque, int ret)
-{
-    /* do nothing. Masters do not directly interact with the backing store,
-     * only the working copy so no mutexing required.
-     */
-}
-
-static void flash_sync_page(Flash *s, int page)
-{
-    if (s->bdrv) {
-        int bdrv_sector, nb_sectors;
-        QEMUIOVector iov;
-
-        bdrv_sector = (page * s->pi->page_size) / BDRV_SECTOR_SIZE;
-        nb_sectors = DIV_ROUND_UP(s->pi->page_size, BDRV_SECTOR_SIZE);
-        qemu_iovec_init(&iov, 1);
-        qemu_iovec_add(&iov, s->storage + bdrv_sector * BDRV_SECTOR_SIZE,
-                                                nb_sectors * BDRV_SECTOR_SIZE);
-        bdrv_aio_writev(s->bdrv, bdrv_sector, &iov, nb_sectors,
-                                                bdrv_sync_complete, NULL);
-    }
-}
-
-static inline void flash_sync_area(Flash *s, int64_t off, int64_t len)
-{
-    int64_t start, end, nb_sectors;
-    QEMUIOVector iov;
-
-    if (!s->bdrv) {
-        return;
-    }
-
-    assert(!(len % BDRV_SECTOR_SIZE));
-    start = off / BDRV_SECTOR_SIZE;
-    end = (off + len) / BDRV_SECTOR_SIZE;
-    nb_sectors = end - start;
-    qemu_iovec_init(&iov, 1);
-    qemu_iovec_add(&iov, s->storage + (start * BDRV_SECTOR_SIZE),
-                                        nb_sectors * BDRV_SECTOR_SIZE);
-    bdrv_aio_writev(s->bdrv, start, &iov, nb_sectors, bdrv_sync_complete, NULL);
-}
-
-static void flash_erase(Flash *s, int offset, FlashCMD cmd)
-{
-    uint32_t len;
-    uint8_t capa_to_assert = 0;
-
-    switch (cmd) {
-    case ERASE_4K:
-        len = 4 << 10;
-        capa_to_assert = ER_4K;
-        break;
-    case ERASE_32K:
-        len = 32 << 10;
-        capa_to_assert = ER_32K;
-        break;
-    case ERASE_SECTOR:
-        len = s->pi->sector_size;
-        break;
-    case BULK_ERASE:
-        len = s->size;
-        break;
-    default:
-        abort();
-    }
-
-    DB_PRINT("offset = %#x, len = %d\n", offset, len);
-    if ((s->pi->flags & capa_to_assert) != capa_to_assert) {
-        hw_error("m25p80: %dk erase size not supported by device\n", len);
-    }
-
-    if (!s->write_enable) {
-        DB_PRINT("erase with write protect!\n");
-        return;
-    }
-    memset(s->storage + offset, 0xff, len);
-    flash_sync_area(s, offset, len);
-}
-
-static inline void flash_sync_dirty(Flash *s, int64_t newpage)
-{
-    if (s->dirty_page >= 0 && s->dirty_page != newpage) {
-        flash_sync_page(s, s->dirty_page);
-        s->dirty_page = newpage;
-    }
-}
-
-static inline
-void flash_write8(Flash *s, uint64_t addr, uint8_t data)
-{
-    int64_t page = addr / s->pi->page_size;
-    uint8_t prev = s->storage[s->cur_addr];
-
-    if (!s->write_enable) {
-        DB_PRINT("write with write protect!\n");
-    }
-
-    if ((prev ^ data) & data) {
-        DB_PRINT("programming zero to one! addr=%lx  %x -> %x\n",
-                  addr, prev, data);
-    }
-
-    if (s->pi->flags & WR_1) {
-        s->storage[s->cur_addr] = data;
-    } else {
-        s->storage[s->cur_addr] &= data;
-    }
-
-    flash_sync_dirty(s, page);
-    s->dirty_page = page;
-}
-
-static void complete_collecting_data(Flash *s)
-{
-    s->cur_addr = s->data[0] << 16;
-    s->cur_addr |= s->data[1] << 8;
-    s->cur_addr |= s->data[2];
-
-    s->state = STATE_IDLE;
-
-    switch (s->cmd_in_progress) {
-    case DPP:
-    case QPP:
-    case PP:
-        s->state = STATE_PAGE_PROGRAM;
-        break;
-    case READ:
-    case FAST_READ:
-    case DOR:
-    case QOR:
-    case DIOR:
-    case QIOR:
-        s->state = STATE_READ;
-        break;
-    case ERASE_4K:
-    case ERASE_32K:
-    case ERASE_SECTOR:
-        flash_erase(s, s->cur_addr, s->cmd_in_progress);
-        break;
-    case WRSR:
-        if (s->write_enable) {
-            s->write_enable = false;
-        }
-        break;
-    default:
-        break;
-    }
-}
-
-static void decode_new_cmd(Flash *s, uint32_t value)
-{
-    s->cmd_in_progress = value;
-    DB_PRINT("decoded new command:%x\n", value);
-
-    switch (value) {
-
-    case ERASE_4K:
-    case ERASE_32K:
-    case ERASE_SECTOR:
-    case READ:
-    case DPP:
-    case QPP:
-    case PP:
-        s->needed_bytes = 3;
-        s->pos = 0;
-        s->len = 0;
-        s->state = STATE_COLLECTING_DATA;
-        break;
-
-    case FAST_READ:
-    case DOR:
-    case QOR:
-        s->needed_bytes = 4;
-        s->pos = 0;
-        s->len = 0;
-        s->state = STATE_COLLECTING_DATA;
-        break;
-
-    case DIOR:
-        switch ((s->pi->jedec >> 16) & 0xFF) {
-        case JEDEC_WINBOND:
-        case JEDEC_SPANSION:
-            s->needed_bytes = 4;
-            break;
-        case JEDEC_NUMONYX:
-        default:
-            s->needed_bytes = 5;
-        }
-        s->pos = 0;
-        s->len = 0;
-        s->state = STATE_COLLECTING_DATA;
-        break;
-
-    case QIOR:
-        switch ((s->pi->jedec >> 16) & 0xFF) {
-        case JEDEC_WINBOND:
-        case JEDEC_SPANSION:
-            s->needed_bytes = 6;
-            break;
-        case JEDEC_NUMONYX:
-        default:
-            s->needed_bytes = 8;
-        }
-        s->pos = 0;
-        s->len = 0;
-        s->state = STATE_COLLECTING_DATA;
-        break;
-
-    case WRSR:
-        if (s->write_enable) {
-            s->needed_bytes = 1;
-            s->pos = 0;
-            s->len = 0;
-            s->state = STATE_COLLECTING_DATA;
-        }
-        break;
-
-    case WRDI:
-        s->write_enable = false;
-        break;
-    case WREN:
-        s->write_enable = true;
-        break;
-
-    case RDSR:
-        s->data[0] = (!!s->write_enable) << 1;
-        s->pos = 0;
-        s->len = 1;
-        s->state = STATE_READING_DATA;
-        break;
-
-    case JEDEC_READ:
-        DB_PRINT("populated jedec code\n");
-        s->data[0] = (s->pi->jedec >> 16) & 0xff;
-        s->data[1] = (s->pi->jedec >> 8) & 0xff;
-        s->data[2] = s->pi->jedec & 0xff;
-        if (s->pi->ext_jedec) {
-            s->data[3] = (s->pi->ext_jedec >> 8) & 0xff;
-            s->data[4] = s->pi->ext_jedec & 0xff;
-            s->len = 5;
-        } else {
-            s->len = 3;
-        }
-        s->pos = 0;
-        s->state = STATE_READING_DATA;
-        break;
-
-    case BULK_ERASE:
-        if (s->write_enable) {
-            DB_PRINT("chip erase\n");
-            flash_erase(s, 0, BULK_ERASE);
-        } else {
-            DB_PRINT("chip erase with write protect!\n");
-        }
-        break;
-    case NOP:
-        break;
-    default:
-        DB_PRINT("Unknown cmd %x\n", value);
-        break;
-    }
-}
-
-static int m25p80_cs(SSISlave *ss, bool select)
-{
-    Flash *s = FROM_SSI_SLAVE(Flash, ss);
-
-    if (select) {
-        s->len = 0;
-        s->pos = 0;
-        s->state = STATE_IDLE;
-        flash_sync_dirty(s, -1);
-    }
-
-    DB_PRINT("%sselect\n", select ? "de" : "");
-
-    return 0;
-}
-
-static uint32_t m25p80_transfer8(SSISlave *ss, uint32_t tx)
-{
-    Flash *s = FROM_SSI_SLAVE(Flash, ss);
-    uint32_t r = 0;
-
-    switch (s->state) {
-
-    case STATE_PAGE_PROGRAM:
-        DB_PRINT("page program cur_addr=%lx data=%x\n", s->cur_addr,
-                 (uint8_t)tx);
-        flash_write8(s, s->cur_addr, (uint8_t)tx);
-        s->cur_addr++;
-        break;
-
-    case STATE_READ:
-        r = s->storage[s->cur_addr];
-        DB_PRINT("READ 0x%lx=%x\n", s->cur_addr, r);
-        s->cur_addr = (s->cur_addr + 1) % s->size;
-        break;
-
-    case STATE_COLLECTING_DATA:
-        s->data[s->len] = (uint8_t)tx;
-        s->len++;
-
-        if (s->len == s->needed_bytes) {
-            complete_collecting_data(s);
-        }
-        break;
-
-    case STATE_READING_DATA:
-        r = s->data[s->pos];
-        s->pos++;
-        if (s->pos == s->len) {
-            s->pos = 0;
-            s->state = STATE_IDLE;
-        }
-        break;
-
-    default:
-    case STATE_IDLE:
-        decode_new_cmd(s, (uint8_t)tx);
-        break;
-    }
-
-    return r;
-}
-
-static int m25p80_init(SSISlave *ss)
-{
-    DriveInfo *dinfo;
-    Flash *s = FROM_SSI_SLAVE(Flash, ss);
-    M25P80Class *mc = M25P80_GET_CLASS(s);
-
-    s->pi = mc->pi;
-
-    s->size = s->pi->sector_size * s->pi->n_sectors;
-    s->dirty_page = -1;
-    s->storage = qemu_blockalign(s->bdrv, s->size);
-
-    dinfo = drive_get_next(IF_MTD);
-
-    if (dinfo && dinfo->bdrv) {
-        DB_PRINT("Binding to IF_MTD drive\n");
-        s->bdrv = dinfo->bdrv;
-        /* FIXME: Move to late init */
-        if (bdrv_read(s->bdrv, 0, s->storage, DIV_ROUND_UP(s->size,
-                                                    BDRV_SECTOR_SIZE))) {
-            fprintf(stderr, "Failed to initialize SPI flash!\n");
-            return 1;
-        }
-    } else {
-        memset(s->storage, 0xFF, s->size);
-    }
-
-    return 0;
-}
-
-static void m25p80_pre_save(void *opaque)
-{
-    flash_sync_dirty((Flash *)opaque, -1);
-}
-
-static const VMStateDescription vmstate_m25p80 = {
-    .name = "xilinx_spi",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .pre_save = m25p80_pre_save,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT8(state, Flash),
-        VMSTATE_UINT8_ARRAY(data, Flash, 16),
-        VMSTATE_UINT32(len, Flash),
-        VMSTATE_UINT32(pos, Flash),
-        VMSTATE_UINT8(needed_bytes, Flash),
-        VMSTATE_UINT8(cmd_in_progress, Flash),
-        VMSTATE_UINT64(cur_addr, Flash),
-        VMSTATE_BOOL(write_enable, Flash),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void m25p80_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
-    M25P80Class *mc = M25P80_CLASS(klass);
-
-    k->init = m25p80_init;
-    k->transfer = m25p80_transfer8;
-    k->set_cs = m25p80_cs;
-    k->cs_polarity = SSI_CS_LOW;
-    dc->vmsd = &vmstate_m25p80;
-    mc->pi = data;
-}
-
-static const TypeInfo m25p80_info = {
-    .name           = TYPE_M25P80,
-    .parent         = TYPE_SSI_SLAVE,
-    .instance_size  = sizeof(Flash),
-    .class_size     = sizeof(M25P80Class),
-    .abstract       = true,
-};
-
-static void m25p80_register_types(void)
-{
-    int i;
-
-    type_register_static(&m25p80_info);
-    for (i = 0; i < ARRAY_SIZE(known_devices); ++i) {
-        TypeInfo ti = {
-            .name       = known_devices[i].part_name,
-            .parent     = TYPE_M25P80,
-            .class_init = m25p80_class_init,
-            .class_data = (void *)&known_devices[i],
-        };
-        type_register(&ti);
-    }
-}
-
-type_init(m25p80_register_types)
diff --git a/hw/m48t59.c b/hw/m48t59.c
deleted file mode 100644 (file)
index 39a9d80..0000000
+++ /dev/null
@@ -1,778 +0,0 @@
-/*
- * QEMU M48T59 and M48T08 NVRAM emulation for PPC PREP and Sparc platforms
- *
- * Copyright (c) 2003-2005, 2007 Jocelyn Mayer
- *
- * 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 "hw/hw.h"
-#include "hw/nvram.h"
-#include "qemu/timer.h"
-#include "sysemu/sysemu.h"
-#include "hw/sysbus.h"
-#include "hw/isa.h"
-#include "exec/address-spaces.h"
-
-//#define DEBUG_NVRAM
-
-#if defined(DEBUG_NVRAM)
-#define NVRAM_PRINTF(fmt, ...) do { printf(fmt , ## __VA_ARGS__); } while (0)
-#else
-#define NVRAM_PRINTF(fmt, ...) do { } while (0)
-#endif
-
-/*
- * The M48T02, M48T08 and M48T59 chips are very similar. The newer '59 has
- * alarm and a watchdog timer and related control registers. In the
- * PPC platform there is also a nvram lock function.
- */
-
-/*
- * Chipset docs:
- * http://www.st.com/stonline/products/literature/ds/2410/m48t02.pdf
- * http://www.st.com/stonline/products/literature/ds/2411/m48t08.pdf
- * http://www.st.com/stonline/products/literature/od/7001/m48t59y.pdf
- */
-
-struct M48t59State {
-    /* Hardware parameters */
-    qemu_irq IRQ;
-    MemoryRegion iomem;
-    uint32_t io_base;
-    uint32_t size;
-    /* RTC management */
-    time_t   time_offset;
-    time_t   stop_time;
-    /* Alarm & watchdog */
-    struct tm alarm;
-    struct QEMUTimer *alrm_timer;
-    struct QEMUTimer *wd_timer;
-    /* NVRAM storage */
-    uint8_t *buffer;
-    /* Model parameters */
-    uint32_t model; /* 2 = m48t02, 8 = m48t08, 59 = m48t59 */
-    /* NVRAM storage */
-    uint16_t addr;
-    uint8_t  lock;
-};
-
-typedef struct M48t59ISAState {
-    ISADevice busdev;
-    M48t59State state;
-    MemoryRegion io;
-} M48t59ISAState;
-
-typedef struct M48t59SysBusState {
-    SysBusDevice busdev;
-    M48t59State state;
-    MemoryRegion io;
-} M48t59SysBusState;
-
-/* Fake timer functions */
-
-/* Alarm management */
-static void alarm_cb (void *opaque)
-{
-    struct tm tm;
-    uint64_t next_time;
-    M48t59State *NVRAM = opaque;
-
-    qemu_set_irq(NVRAM->IRQ, 1);
-    if ((NVRAM->buffer[0x1FF5] & 0x80) == 0 &&
-       (NVRAM->buffer[0x1FF4] & 0x80) == 0 &&
-       (NVRAM->buffer[0x1FF3] & 0x80) == 0 &&
-       (NVRAM->buffer[0x1FF2] & 0x80) == 0) {
-        /* Repeat once a month */
-        qemu_get_timedate(&tm, NVRAM->time_offset);
-        tm.tm_mon++;
-        if (tm.tm_mon == 13) {
-            tm.tm_mon = 1;
-            tm.tm_year++;
-        }
-        next_time = qemu_timedate_diff(&tm) - NVRAM->time_offset;
-    } else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 &&
-              (NVRAM->buffer[0x1FF4] & 0x80) == 0 &&
-              (NVRAM->buffer[0x1FF3] & 0x80) == 0 &&
-              (NVRAM->buffer[0x1FF2] & 0x80) == 0) {
-        /* Repeat once a day */
-        next_time = 24 * 60 * 60;
-    } else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 &&
-              (NVRAM->buffer[0x1FF4] & 0x80) != 0 &&
-              (NVRAM->buffer[0x1FF3] & 0x80) == 0 &&
-              (NVRAM->buffer[0x1FF2] & 0x80) == 0) {
-        /* Repeat once an hour */
-        next_time = 60 * 60;
-    } else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 &&
-              (NVRAM->buffer[0x1FF4] & 0x80) != 0 &&
-              (NVRAM->buffer[0x1FF3] & 0x80) != 0 &&
-              (NVRAM->buffer[0x1FF2] & 0x80) == 0) {
-        /* Repeat once a minute */
-        next_time = 60;
-    } else {
-        /* Repeat once a second */
-        next_time = 1;
-    }
-    qemu_mod_timer(NVRAM->alrm_timer, qemu_get_clock_ns(rtc_clock) +
-                    next_time * 1000);
-    qemu_set_irq(NVRAM->IRQ, 0);
-}
-
-static void set_alarm(M48t59State *NVRAM)
-{
-    int diff;
-    if (NVRAM->alrm_timer != NULL) {
-        qemu_del_timer(NVRAM->alrm_timer);
-        diff = qemu_timedate_diff(&NVRAM->alarm) - NVRAM->time_offset;
-        if (diff > 0)
-            qemu_mod_timer(NVRAM->alrm_timer, diff * 1000);
-    }
-}
-
-/* RTC management helpers */
-static inline void get_time(M48t59State *NVRAM, struct tm *tm)
-{
-    qemu_get_timedate(tm, NVRAM->time_offset);
-}
-
-static void set_time(M48t59State *NVRAM, struct tm *tm)
-{
-    NVRAM->time_offset = qemu_timedate_diff(tm);
-    set_alarm(NVRAM);
-}
-
-/* Watchdog management */
-static void watchdog_cb (void *opaque)
-{
-    M48t59State *NVRAM = opaque;
-
-    NVRAM->buffer[0x1FF0] |= 0x80;
-    if (NVRAM->buffer[0x1FF7] & 0x80) {
-       NVRAM->buffer[0x1FF7] = 0x00;
-       NVRAM->buffer[0x1FFC] &= ~0x40;
-        /* May it be a hw CPU Reset instead ? */
-        qemu_system_reset_request();
-    } else {
-       qemu_set_irq(NVRAM->IRQ, 1);
-       qemu_set_irq(NVRAM->IRQ, 0);
-    }
-}
-
-static void set_up_watchdog(M48t59State *NVRAM, uint8_t value)
-{
-    uint64_t interval; /* in 1/16 seconds */
-
-    NVRAM->buffer[0x1FF0] &= ~0x80;
-    if (NVRAM->wd_timer != NULL) {
-        qemu_del_timer(NVRAM->wd_timer);
-        if (value != 0) {
-            interval = (1 << (2 * (value & 0x03))) * ((value >> 2) & 0x1F);
-            qemu_mod_timer(NVRAM->wd_timer, ((uint64_t)time(NULL) * 1000) +
-                           ((interval * 1000) >> 4));
-        }
-    }
-}
-
-/* Direct access to NVRAM */
-void m48t59_write (void *opaque, uint32_t addr, uint32_t val)
-{
-    M48t59State *NVRAM = opaque;
-    struct tm tm;
-    int tmp;
-
-    if (addr > 0x1FF8 && addr < 0x2000)
-       NVRAM_PRINTF("%s: 0x%08x => 0x%08x\n", __func__, addr, val);
-
-    /* check for NVRAM access */
-    if ((NVRAM->model == 2 && addr < 0x7f8) ||
-        (NVRAM->model == 8 && addr < 0x1ff8) ||
-        (NVRAM->model == 59 && addr < 0x1ff0)) {
-        goto do_write;
-    }
-
-    /* TOD access */
-    switch (addr) {
-    case 0x1FF0:
-        /* flags register : read-only */
-        break;
-    case 0x1FF1:
-        /* unused */
-        break;
-    case 0x1FF2:
-        /* alarm seconds */
-        tmp = from_bcd(val & 0x7F);
-        if (tmp >= 0 && tmp <= 59) {
-            NVRAM->alarm.tm_sec = tmp;
-            NVRAM->buffer[0x1FF2] = val;
-            set_alarm(NVRAM);
-        }
-        break;
-    case 0x1FF3:
-        /* alarm minutes */
-        tmp = from_bcd(val & 0x7F);
-        if (tmp >= 0 && tmp <= 59) {
-            NVRAM->alarm.tm_min = tmp;
-            NVRAM->buffer[0x1FF3] = val;
-            set_alarm(NVRAM);
-        }
-        break;
-    case 0x1FF4:
-        /* alarm hours */
-        tmp = from_bcd(val & 0x3F);
-        if (tmp >= 0 && tmp <= 23) {
-            NVRAM->alarm.tm_hour = tmp;
-            NVRAM->buffer[0x1FF4] = val;
-            set_alarm(NVRAM);
-        }
-        break;
-    case 0x1FF5:
-        /* alarm date */
-        tmp = from_bcd(val & 0x3F);
-        if (tmp != 0) {
-            NVRAM->alarm.tm_mday = tmp;
-            NVRAM->buffer[0x1FF5] = val;
-            set_alarm(NVRAM);
-        }
-        break;
-    case 0x1FF6:
-        /* interrupts */
-        NVRAM->buffer[0x1FF6] = val;
-        break;
-    case 0x1FF7:
-        /* watchdog */
-        NVRAM->buffer[0x1FF7] = val;
-        set_up_watchdog(NVRAM, val);
-        break;
-    case 0x1FF8:
-    case 0x07F8:
-        /* control */
-       NVRAM->buffer[addr] = (val & ~0xA0) | 0x90;
-        break;
-    case 0x1FF9:
-    case 0x07F9:
-        /* seconds (BCD) */
-       tmp = from_bcd(val & 0x7F);
-       if (tmp >= 0 && tmp <= 59) {
-           get_time(NVRAM, &tm);
-           tm.tm_sec = tmp;
-           set_time(NVRAM, &tm);
-       }
-        if ((val & 0x80) ^ (NVRAM->buffer[addr] & 0x80)) {
-           if (val & 0x80) {
-               NVRAM->stop_time = time(NULL);
-           } else {
-               NVRAM->time_offset += NVRAM->stop_time - time(NULL);
-               NVRAM->stop_time = 0;
-           }
-       }
-        NVRAM->buffer[addr] = val & 0x80;
-        break;
-    case 0x1FFA:
-    case 0x07FA:
-        /* minutes (BCD) */
-       tmp = from_bcd(val & 0x7F);
-       if (tmp >= 0 && tmp <= 59) {
-           get_time(NVRAM, &tm);
-           tm.tm_min = tmp;
-           set_time(NVRAM, &tm);
-       }
-        break;
-    case 0x1FFB:
-    case 0x07FB:
-        /* hours (BCD) */
-       tmp = from_bcd(val & 0x3F);
-       if (tmp >= 0 && tmp <= 23) {
-           get_time(NVRAM, &tm);
-           tm.tm_hour = tmp;
-           set_time(NVRAM, &tm);
-       }
-        break;
-    case 0x1FFC:
-    case 0x07FC:
-        /* day of the week / century */
-       tmp = from_bcd(val & 0x07);
-       get_time(NVRAM, &tm);
-       tm.tm_wday = tmp;
-       set_time(NVRAM, &tm);
-        NVRAM->buffer[addr] = val & 0x40;
-        break;
-    case 0x1FFD:
-    case 0x07FD:
-        /* date (BCD) */
-       tmp = from_bcd(val & 0x3F);
-       if (tmp != 0) {
-           get_time(NVRAM, &tm);
-           tm.tm_mday = tmp;
-           set_time(NVRAM, &tm);
-       }
-        break;
-    case 0x1FFE:
-    case 0x07FE:
-        /* month */
-       tmp = from_bcd(val & 0x1F);
-       if (tmp >= 1 && tmp <= 12) {
-           get_time(NVRAM, &tm);
-           tm.tm_mon = tmp - 1;
-           set_time(NVRAM, &tm);
-       }
-        break;
-    case 0x1FFF:
-    case 0x07FF:
-        /* year */
-       tmp = from_bcd(val);
-       if (tmp >= 0 && tmp <= 99) {
-           get_time(NVRAM, &tm);
-            if (NVRAM->model == 8) {
-                tm.tm_year = from_bcd(val) + 68; // Base year is 1968
-            } else {
-                tm.tm_year = from_bcd(val);
-            }
-           set_time(NVRAM, &tm);
-       }
-        break;
-    default:
-        /* Check lock registers state */
-        if (addr >= 0x20 && addr <= 0x2F && (NVRAM->lock & 1))
-            break;
-        if (addr >= 0x30 && addr <= 0x3F && (NVRAM->lock & 2))
-            break;
-    do_write:
-        if (addr < NVRAM->size) {
-            NVRAM->buffer[addr] = val & 0xFF;
-       }
-        break;
-    }
-}
-
-uint32_t m48t59_read (void *opaque, uint32_t addr)
-{
-    M48t59State *NVRAM = opaque;
-    struct tm tm;
-    uint32_t retval = 0xFF;
-
-    /* check for NVRAM access */
-    if ((NVRAM->model == 2 && addr < 0x078f) ||
-        (NVRAM->model == 8 && addr < 0x1ff8) ||
-        (NVRAM->model == 59 && addr < 0x1ff0)) {
-        goto do_read;
-    }
-
-    /* TOD access */
-    switch (addr) {
-    case 0x1FF0:
-        /* flags register */
-       goto do_read;
-    case 0x1FF1:
-        /* unused */
-       retval = 0;
-        break;
-    case 0x1FF2:
-        /* alarm seconds */
-       goto do_read;
-    case 0x1FF3:
-        /* alarm minutes */
-       goto do_read;
-    case 0x1FF4:
-        /* alarm hours */
-       goto do_read;
-    case 0x1FF5:
-        /* alarm date */
-       goto do_read;
-    case 0x1FF6:
-        /* interrupts */
-       goto do_read;
-    case 0x1FF7:
-       /* A read resets the watchdog */
-       set_up_watchdog(NVRAM, NVRAM->buffer[0x1FF7]);
-       goto do_read;
-    case 0x1FF8:
-    case 0x07F8:
-        /* control */
-       goto do_read;
-    case 0x1FF9:
-    case 0x07F9:
-        /* seconds (BCD) */
-        get_time(NVRAM, &tm);
-        retval = (NVRAM->buffer[addr] & 0x80) | to_bcd(tm.tm_sec);
-        break;
-    case 0x1FFA:
-    case 0x07FA:
-        /* minutes (BCD) */
-        get_time(NVRAM, &tm);
-        retval = to_bcd(tm.tm_min);
-        break;
-    case 0x1FFB:
-    case 0x07FB:
-        /* hours (BCD) */
-        get_time(NVRAM, &tm);
-        retval = to_bcd(tm.tm_hour);
-        break;
-    case 0x1FFC:
-    case 0x07FC:
-        /* day of the week / century */
-        get_time(NVRAM, &tm);
-        retval = NVRAM->buffer[addr] | tm.tm_wday;
-        break;
-    case 0x1FFD:
-    case 0x07FD:
-        /* date */
-        get_time(NVRAM, &tm);
-        retval = to_bcd(tm.tm_mday);
-        break;
-    case 0x1FFE:
-    case 0x07FE:
-        /* month */
-        get_time(NVRAM, &tm);
-        retval = to_bcd(tm.tm_mon + 1);
-        break;
-    case 0x1FFF:
-    case 0x07FF:
-        /* year */
-        get_time(NVRAM, &tm);
-        if (NVRAM->model == 8) {
-            retval = to_bcd(tm.tm_year - 68); // Base year is 1968
-        } else {
-            retval = to_bcd(tm.tm_year);
-        }
-        break;
-    default:
-        /* Check lock registers state */
-        if (addr >= 0x20 && addr <= 0x2F && (NVRAM->lock & 1))
-            break;
-        if (addr >= 0x30 && addr <= 0x3F && (NVRAM->lock & 2))
-            break;
-    do_read:
-        if (addr < NVRAM->size) {
-            retval = NVRAM->buffer[addr];
-       }
-        break;
-    }
-    if (addr > 0x1FF9 && addr < 0x2000)
-       NVRAM_PRINTF("%s: 0x%08x <= 0x%08x\n", __func__, addr, retval);
-
-    return retval;
-}
-
-void m48t59_toggle_lock (void *opaque, int lock)
-{
-    M48t59State *NVRAM = opaque;
-
-    NVRAM->lock ^= 1 << lock;
-}
-
-/* IO access to NVRAM */
-static void NVRAM_writeb(void *opaque, hwaddr addr, uint64_t val,
-                         unsigned size)
-{
-    M48t59State *NVRAM = opaque;
-
-    NVRAM_PRINTF("%s: 0x%08x => 0x%08x\n", __func__, addr, val);
-    switch (addr) {
-    case 0:
-        NVRAM->addr &= ~0x00FF;
-        NVRAM->addr |= val;
-        break;
-    case 1:
-        NVRAM->addr &= ~0xFF00;
-        NVRAM->addr |= val << 8;
-        break;
-    case 3:
-        m48t59_write(NVRAM, NVRAM->addr, val);
-        NVRAM->addr = 0x0000;
-        break;
-    default:
-        break;
-    }
-}
-
-static uint64_t NVRAM_readb(void *opaque, hwaddr addr, unsigned size)
-{
-    M48t59State *NVRAM = opaque;
-    uint32_t retval;
-
-    switch (addr) {
-    case 3:
-        retval = m48t59_read(NVRAM, NVRAM->addr);
-        break;
-    default:
-        retval = -1;
-        break;
-    }
-    NVRAM_PRINTF("%s: 0x%08x <= 0x%08x\n", __func__, addr, retval);
-
-    return retval;
-}
-
-static void nvram_writeb (void *opaque, hwaddr addr, uint32_t value)
-{
-    M48t59State *NVRAM = opaque;
-
-    m48t59_write(NVRAM, addr, value & 0xff);
-}
-
-static void nvram_writew (void *opaque, hwaddr addr, uint32_t value)
-{
-    M48t59State *NVRAM = opaque;
-
-    m48t59_write(NVRAM, addr, (value >> 8) & 0xff);
-    m48t59_write(NVRAM, addr + 1, value & 0xff);
-}
-
-static void nvram_writel (void *opaque, hwaddr addr, uint32_t value)
-{
-    M48t59State *NVRAM = opaque;
-
-    m48t59_write(NVRAM, addr, (value >> 24) & 0xff);
-    m48t59_write(NVRAM, addr + 1, (value >> 16) & 0xff);
-    m48t59_write(NVRAM, addr + 2, (value >> 8) & 0xff);
-    m48t59_write(NVRAM, addr + 3, value & 0xff);
-}
-
-static uint32_t nvram_readb (void *opaque, hwaddr addr)
-{
-    M48t59State *NVRAM = opaque;
-    uint32_t retval;
-
-    retval = m48t59_read(NVRAM, addr);
-    return retval;
-}
-
-static uint32_t nvram_readw (void *opaque, hwaddr addr)
-{
-    M48t59State *NVRAM = opaque;
-    uint32_t retval;
-
-    retval = m48t59_read(NVRAM, addr) << 8;
-    retval |= m48t59_read(NVRAM, addr + 1);
-    return retval;
-}
-
-static uint32_t nvram_readl (void *opaque, hwaddr addr)
-{
-    M48t59State *NVRAM = opaque;
-    uint32_t retval;
-
-    retval = m48t59_read(NVRAM, addr) << 24;
-    retval |= m48t59_read(NVRAM, addr + 1) << 16;
-    retval |= m48t59_read(NVRAM, addr + 2) << 8;
-    retval |= m48t59_read(NVRAM, addr + 3);
-    return retval;
-}
-
-static const MemoryRegionOps nvram_ops = {
-    .old_mmio = {
-        .read = { nvram_readb, nvram_readw, nvram_readl, },
-        .write = { nvram_writeb, nvram_writew, nvram_writel, },
-    },
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static const VMStateDescription vmstate_m48t59 = {
-    .name = "m48t59",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField[]) {
-        VMSTATE_UINT8(lock, M48t59State),
-        VMSTATE_UINT16(addr, M48t59State),
-        VMSTATE_VBUFFER_UINT32(buffer, M48t59State, 0, NULL, 0, size),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void m48t59_reset_common(M48t59State *NVRAM)
-{
-    NVRAM->addr = 0;
-    NVRAM->lock = 0;
-    if (NVRAM->alrm_timer != NULL)
-        qemu_del_timer(NVRAM->alrm_timer);
-
-    if (NVRAM->wd_timer != NULL)
-        qemu_del_timer(NVRAM->wd_timer);
-}
-
-static void m48t59_reset_isa(DeviceState *d)
-{
-    M48t59ISAState *isa = container_of(d, M48t59ISAState, busdev.qdev);
-    M48t59State *NVRAM = &isa->state;
-
-    m48t59_reset_common(NVRAM);
-}
-
-static void m48t59_reset_sysbus(DeviceState *d)
-{
-    M48t59SysBusState *sys = container_of(d, M48t59SysBusState, busdev.qdev);
-    M48t59State *NVRAM = &sys->state;
-
-    m48t59_reset_common(NVRAM);
-}
-
-static const MemoryRegionOps m48t59_io_ops = {
-    .read = NVRAM_readb,
-    .write = NVRAM_writeb,
-    .impl = {
-        .min_access_size = 1,
-        .max_access_size = 1,
-    },
-    .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-/* Initialisation routine */
-M48t59State *m48t59_init(qemu_irq IRQ, hwaddr mem_base,
-                         uint32_t io_base, uint16_t size, int model)
-{
-    DeviceState *dev;
-    SysBusDevice *s;
-    M48t59SysBusState *d;
-    M48t59State *state;
-
-    dev = qdev_create(NULL, "m48t59");
-    qdev_prop_set_uint32(dev, "model", model);
-    qdev_prop_set_uint32(dev, "size", size);
-    qdev_prop_set_uint32(dev, "io_base", io_base);
-    qdev_init_nofail(dev);
-    s = SYS_BUS_DEVICE(dev);
-    d = FROM_SYSBUS(M48t59SysBusState, s);
-    state = &d->state;
-    sysbus_connect_irq(s, 0, IRQ);
-    memory_region_init_io(&d->io, &m48t59_io_ops, state, "m48t59", 4);
-    if (io_base != 0) {
-        memory_region_add_subregion(get_system_io(), io_base, &d->io);
-    }
-    if (mem_base != 0) {
-        sysbus_mmio_map(s, 0, mem_base);
-    }
-
-    return state;
-}
-
-M48t59State *m48t59_init_isa(ISABus *bus, uint32_t io_base, uint16_t size,
-                             int model)
-{
-    M48t59ISAState *d;
-    ISADevice *dev;
-    M48t59State *s;
-
-    dev = isa_create(bus, "m48t59_isa");
-    qdev_prop_set_uint32(&dev->qdev, "model", model);
-    qdev_prop_set_uint32(&dev->qdev, "size", size);
-    qdev_prop_set_uint32(&dev->qdev, "io_base", io_base);
-    qdev_init_nofail(&dev->qdev);
-    d = DO_UPCAST(M48t59ISAState, busdev, dev);
-    s = &d->state;
-
-    memory_region_init_io(&d->io, &m48t59_io_ops, s, "m48t59", 4);
-    if (io_base != 0) {
-        isa_register_ioport(dev, &d->io, io_base);
-    }
-
-    return s;
-}
-
-static void m48t59_init_common(M48t59State *s)
-{
-    s->buffer = g_malloc0(s->size);
-    if (s->model == 59) {
-        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);
-
-    vmstate_register(NULL, -1, &vmstate_m48t59, s);
-}
-
-static int m48t59_init_isa1(ISADevice *dev)
-{
-    M48t59ISAState *d = DO_UPCAST(M48t59ISAState, busdev, dev);
-    M48t59State *s = &d->state;
-
-    isa_init_irq(dev, &s->IRQ, 8);
-    m48t59_init_common(s);
-
-    return 0;
-}
-
-static int m48t59_init1(SysBusDevice *dev)
-{
-    M48t59SysBusState *d = FROM_SYSBUS(M48t59SysBusState, dev);
-    M48t59State *s = &d->state;
-
-    sysbus_init_irq(dev, &s->IRQ);
-
-    memory_region_init_io(&s->iomem, &nvram_ops, s, "m48t59.nvram", s->size);
-    sysbus_init_mmio(dev, &s->iomem);
-    m48t59_init_common(s);
-
-    return 0;
-}
-
-static Property m48t59_isa_properties[] = {
-    DEFINE_PROP_UINT32("size",    M48t59ISAState, state.size,    -1),
-    DEFINE_PROP_UINT32("model",   M48t59ISAState, state.model,   -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 const TypeInfo m48t59_isa_info = {
-    .name          = "m48t59_isa",
-    .parent        = TYPE_ISA_DEVICE,
-    .instance_size = sizeof(M48t59ISAState),
-    .class_init    = m48t59_init_class_isa1,
-};
-
-static Property m48t59_properties[] = {
-    DEFINE_PROP_UINT32("size",    M48t59SysBusState, state.size,    -1),
-    DEFINE_PROP_UINT32("model",   M48t59SysBusState, state.model,   -1),
-    DEFINE_PROP_HEX32( "io_base", M48t59SysBusState, state.io_base,  0),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void m48t59_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = m48t59_init1;
-    dc->reset = m48t59_reset_sysbus;
-    dc->props = m48t59_properties;
-}
-
-static const TypeInfo m48t59_info = {
-    .name          = "m48t59",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(M48t59SysBusState),
-    .class_init    = m48t59_class_init,
-};
-
-static void m48t59_register_types(void)
-{
-    type_register_static(&m48t59_info);
-    type_register_static(&m48t59_isa_info);
-}
-
-type_init(m48t59_register_types)
index ede32a7c4ef00bd1a0a0a0ae416f640f25270cf5..c4352e783ad5902d780b5dd06ff074cca7c9e85c 100644 (file)
@@ -1,7 +1,3 @@
-obj-y = mcf_uart.o mcf_fec.o
-
-obj-y := $(addprefix ../,$(obj-y))
-
 obj-y += an5206.o mcf5208.o
 obj-y += dummy_m68k.o
 
index 7c21c66cdecb9789bf93e0115586cb7caaa149b2..c4a5626a53191495de6239ca00b0a851b4897c36 100644 (file)
@@ -7,7 +7,7 @@
  */
 
 #include "hw/hw.h"
-#include "hw/mcf.h"
+#include "hw/m68k/mcf.h"
 #include "hw/boards.h"
 #include "hw/loader.h"
 #include "elf.h"
index 58cd8d46c9a32597f39c2a36a50935712e4a2b91..bcc619d74bc02c7e23a1ae526e0067365a69e8c6 100644 (file)
@@ -6,7 +6,7 @@
  * This code is licensed under the GPL
  */
 #include "hw/hw.h"
-#include "hw/mcf.h"
+#include "hw/m68k/mcf.h"
 #include "qemu/timer.h"
 #include "hw/ptimer.h"
 #include "sysemu/sysemu.h"
index 748bf5698378796ac017a331683aca626ea34d3f..05efde7ceb9a0607ad6931af170ddf8381e36133 100644 (file)
@@ -6,7 +6,7 @@
  * This code is licensed under the GPL
  */
 #include "hw/hw.h"
-#include "hw/mcf.h"
+#include "hw/m68k/mcf.h"
 #include "qemu/timer.h"
 #include "hw/ptimer.h"
 #include "sysemu/sysemu.h"
index fff27b34aa09e0859ae163c7ebec586cce719f59..cfe660d0a497da19cb53c28bafe2dda42df9b9df 100644 (file)
@@ -6,7 +6,7 @@
  * This code is licensed under the GPL
  */
 #include "hw/hw.h"
-#include "hw/mcf.h"
+#include "hw/m68k/mcf.h"
 #include "exec/address-spaces.h"
 
 typedef struct {
diff --git a/hw/mac_dbdma.c b/hw/mac_dbdma.c
deleted file mode 100644 (file)
index 61d2f35..0000000
+++ /dev/null
@@ -1,859 +0,0 @@
-/*
- * PowerMac descriptor-based DMA emulation
- *
- * Copyright (c) 2005-2007 Fabrice Bellard
- * Copyright (c) 2007 Jocelyn Mayer
- * Copyright (c) 2009 Laurent Vivier
- *
- * some parts from linux-2.6.28, arch/powerpc/include/asm/dbdma.h
- *
- *   Definitions for using the Apple Descriptor-Based DMA controller
- *   in Power Macintosh computers.
- *
- *   Copyright (C) 1996 Paul Mackerras.
- *
- * some parts from mol 0.9.71
- *
- *   Descriptor based DMA emulation
- *
- *   Copyright (C) 1998-2004 Samuel Rydh (samuel@ibrium.se)
- *
- * 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 "hw/hw.h"
-#include "hw/isa.h"
-#include "hw/mac_dbdma.h"
-#include "qemu/main-loop.h"
-
-/* debug DBDMA */
-//#define DEBUG_DBDMA
-
-#ifdef DEBUG_DBDMA
-#define DBDMA_DPRINTF(fmt, ...)                                 \
-    do { printf("DBDMA: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DBDMA_DPRINTF(fmt, ...)
-#endif
-
-/*
- */
-
-/*
- * DBDMA control/status registers.  All little-endian.
- */
-
-#define DBDMA_CONTROL         0x00
-#define DBDMA_STATUS          0x01
-#define DBDMA_CMDPTR_HI       0x02
-#define DBDMA_CMDPTR_LO       0x03
-#define DBDMA_INTR_SEL        0x04
-#define DBDMA_BRANCH_SEL      0x05
-#define DBDMA_WAIT_SEL        0x06
-#define DBDMA_XFER_MODE       0x07
-#define DBDMA_DATA2PTR_HI     0x08
-#define DBDMA_DATA2PTR_LO     0x09
-#define DBDMA_RES1            0x0A
-#define DBDMA_ADDRESS_HI      0x0B
-#define DBDMA_BRANCH_ADDR_HI  0x0C
-#define DBDMA_RES2            0x0D
-#define DBDMA_RES3            0x0E
-#define DBDMA_RES4            0x0F
-
-#define DBDMA_REGS            16
-#define DBDMA_SIZE            (DBDMA_REGS * sizeof(uint32_t))
-
-#define DBDMA_CHANNEL_SHIFT   7
-#define DBDMA_CHANNEL_SIZE    (1 << DBDMA_CHANNEL_SHIFT)
-
-#define DBDMA_CHANNELS        (0x1000 >> DBDMA_CHANNEL_SHIFT)
-
-/* Bits in control and status registers */
-
-#define RUN    0x8000
-#define PAUSE  0x4000
-#define FLUSH  0x2000
-#define WAKE   0x1000
-#define DEAD   0x0800
-#define ACTIVE 0x0400
-#define BT     0x0100
-#define DEVSTAT        0x00ff
-
-/*
- * DBDMA command structure.  These fields are all little-endian!
- */
-
-typedef struct dbdma_cmd {
-    uint16_t req_count;          /* requested byte transfer count */
-    uint16_t command;    /* command word (has bit-fields) */
-    uint32_t phy_addr;   /* physical data address */
-    uint32_t cmd_dep;    /* command-dependent field */
-    uint16_t res_count;          /* residual count after completion */
-    uint16_t xfer_status; /* transfer status */
-} dbdma_cmd;
-
-/* DBDMA command values in command field */
-
-#define COMMAND_MASK    0xf000
-#define OUTPUT_MORE    0x0000  /* transfer memory data to stream */
-#define OUTPUT_LAST    0x1000  /* ditto followed by end marker */
-#define INPUT_MORE     0x2000  /* transfer stream data to memory */
-#define INPUT_LAST     0x3000  /* ditto, expect end marker */
-#define STORE_WORD     0x4000  /* write word (4 bytes) to device reg */
-#define LOAD_WORD      0x5000  /* read word (4 bytes) from device reg */
-#define DBDMA_NOP      0x6000  /* do nothing */
-#define DBDMA_STOP     0x7000  /* suspend processing */
-
-/* Key values in command field */
-
-#define KEY_MASK        0x0700
-#define KEY_STREAM0    0x0000  /* usual data stream */
-#define KEY_STREAM1    0x0100  /* control/status stream */
-#define KEY_STREAM2    0x0200  /* device-dependent stream */
-#define KEY_STREAM3    0x0300  /* device-dependent stream */
-#define KEY_STREAM4    0x0400  /* reserved */
-#define KEY_REGS       0x0500  /* device register space */
-#define KEY_SYSTEM     0x0600  /* system memory-mapped space */
-#define KEY_DEVICE     0x0700  /* device memory-mapped space */
-
-/* Interrupt control values in command field */
-
-#define INTR_MASK       0x0030
-#define INTR_NEVER     0x0000  /* don't interrupt */
-#define INTR_IFSET     0x0010  /* intr if condition bit is 1 */
-#define INTR_IFCLR     0x0020  /* intr if condition bit is 0 */
-#define INTR_ALWAYS    0x0030  /* always interrupt */
-
-/* Branch control values in command field */
-
-#define BR_MASK         0x000c
-#define BR_NEVER       0x0000  /* don't branch */
-#define BR_IFSET       0x0004  /* branch if condition bit is 1 */
-#define BR_IFCLR       0x0008  /* branch if condition bit is 0 */
-#define BR_ALWAYS      0x000c  /* always branch */
-
-/* Wait control values in command field */
-
-#define WAIT_MASK       0x0003
-#define WAIT_NEVER     0x0000  /* don't wait */
-#define WAIT_IFSET     0x0001  /* wait if condition bit is 1 */
-#define WAIT_IFCLR     0x0002  /* wait if condition bit is 0 */
-#define WAIT_ALWAYS    0x0003  /* always wait */
-
-typedef struct DBDMA_channel {
-    int channel;
-    uint32_t regs[DBDMA_REGS];
-    qemu_irq irq;
-    DBDMA_io io;
-    DBDMA_rw rw;
-    DBDMA_flush flush;
-    dbdma_cmd current;
-    int processing;
-} DBDMA_channel;
-
-typedef struct {
-    MemoryRegion mem;
-    DBDMA_channel channels[DBDMA_CHANNELS];
-} DBDMAState;
-
-#ifdef DEBUG_DBDMA
-static void dump_dbdma_cmd(dbdma_cmd *cmd)
-{
-    printf("dbdma_cmd %p\n", cmd);
-    printf("    req_count 0x%04x\n", le16_to_cpu(cmd->req_count));
-    printf("    command 0x%04x\n", le16_to_cpu(cmd->command));
-    printf("    phy_addr 0x%08x\n", le32_to_cpu(cmd->phy_addr));
-    printf("    cmd_dep 0x%08x\n", le32_to_cpu(cmd->cmd_dep));
-    printf("    res_count 0x%04x\n", le16_to_cpu(cmd->res_count));
-    printf("    xfer_status 0x%04x\n", le16_to_cpu(cmd->xfer_status));
-}
-#else
-static void dump_dbdma_cmd(dbdma_cmd *cmd)
-{
-}
-#endif
-static void dbdma_cmdptr_load(DBDMA_channel *ch)
-{
-    DBDMA_DPRINTF("dbdma_cmdptr_load 0x%08x\n",
-                  ch->regs[DBDMA_CMDPTR_LO]);
-    cpu_physical_memory_read(ch->regs[DBDMA_CMDPTR_LO],
-                             (uint8_t*)&ch->current, sizeof(dbdma_cmd));
-}
-
-static void dbdma_cmdptr_save(DBDMA_channel *ch)
-{
-    DBDMA_DPRINTF("dbdma_cmdptr_save 0x%08x\n",
-                  ch->regs[DBDMA_CMDPTR_LO]);
-    DBDMA_DPRINTF("xfer_status 0x%08x res_count 0x%04x\n",
-                  le16_to_cpu(ch->current.xfer_status),
-                  le16_to_cpu(ch->current.res_count));
-    cpu_physical_memory_write(ch->regs[DBDMA_CMDPTR_LO],
-                              (uint8_t*)&ch->current, sizeof(dbdma_cmd));
-}
-
-static void kill_channel(DBDMA_channel *ch)
-{
-    DBDMA_DPRINTF("kill_channel\n");
-
-    ch->regs[DBDMA_STATUS] |= DEAD;
-    ch->regs[DBDMA_STATUS] &= ~ACTIVE;
-
-    qemu_irq_raise(ch->irq);
-}
-
-static void conditional_interrupt(DBDMA_channel *ch)
-{
-    dbdma_cmd *current = &ch->current;
-    uint16_t intr;
-    uint16_t sel_mask, sel_value;
-    uint32_t status;
-    int cond;
-
-    DBDMA_DPRINTF("conditional_interrupt\n");
-
-    intr = le16_to_cpu(current->command) & INTR_MASK;
-
-    switch(intr) {
-    case INTR_NEVER:  /* don't interrupt */
-        return;
-    case INTR_ALWAYS: /* always interrupt */
-        qemu_irq_raise(ch->irq);
-        return;
-    }
-
-    status = ch->regs[DBDMA_STATUS] & DEVSTAT;
-
-    sel_mask = (ch->regs[DBDMA_INTR_SEL] >> 16) & 0x0f;
-    sel_value = ch->regs[DBDMA_INTR_SEL] & 0x0f;
-
-    cond = (status & sel_mask) == (sel_value & sel_mask);
-
-    switch(intr) {
-    case INTR_IFSET:  /* intr if condition bit is 1 */
-        if (cond)
-            qemu_irq_raise(ch->irq);
-        return;
-    case INTR_IFCLR:  /* intr if condition bit is 0 */
-        if (!cond)
-            qemu_irq_raise(ch->irq);
-        return;
-    }
-}
-
-static int conditional_wait(DBDMA_channel *ch)
-{
-    dbdma_cmd *current = &ch->current;
-    uint16_t wait;
-    uint16_t sel_mask, sel_value;
-    uint32_t status;
-    int cond;
-
-    DBDMA_DPRINTF("conditional_wait\n");
-
-    wait = le16_to_cpu(current->command) & WAIT_MASK;
-
-    switch(wait) {
-    case WAIT_NEVER:  /* don't wait */
-        return 0;
-    case WAIT_ALWAYS: /* always wait */
-        return 1;
-    }
-
-    status = ch->regs[DBDMA_STATUS] & DEVSTAT;
-
-    sel_mask = (ch->regs[DBDMA_WAIT_SEL] >> 16) & 0x0f;
-    sel_value = ch->regs[DBDMA_WAIT_SEL] & 0x0f;
-
-    cond = (status & sel_mask) == (sel_value & sel_mask);
-
-    switch(wait) {
-    case WAIT_IFSET:  /* wait if condition bit is 1 */
-        if (cond)
-            return 1;
-        return 0;
-    case WAIT_IFCLR:  /* wait if condition bit is 0 */
-        if (!cond)
-            return 1;
-        return 0;
-    }
-    return 0;
-}
-
-static void next(DBDMA_channel *ch)
-{
-    uint32_t cp;
-
-    ch->regs[DBDMA_STATUS] &= ~BT;
-
-    cp = ch->regs[DBDMA_CMDPTR_LO];
-    ch->regs[DBDMA_CMDPTR_LO] = cp + sizeof(dbdma_cmd);
-    dbdma_cmdptr_load(ch);
-}
-
-static void branch(DBDMA_channel *ch)
-{
-    dbdma_cmd *current = &ch->current;
-
-    ch->regs[DBDMA_CMDPTR_LO] = current->cmd_dep;
-    ch->regs[DBDMA_STATUS] |= BT;
-    dbdma_cmdptr_load(ch);
-}
-
-static void conditional_branch(DBDMA_channel *ch)
-{
-    dbdma_cmd *current = &ch->current;
-    uint16_t br;
-    uint16_t sel_mask, sel_value;
-    uint32_t status;
-    int cond;
-
-    DBDMA_DPRINTF("conditional_branch\n");
-
-    /* check if we must branch */
-
-    br = le16_to_cpu(current->command) & BR_MASK;
-
-    switch(br) {
-    case BR_NEVER:  /* don't branch */
-        next(ch);
-        return;
-    case BR_ALWAYS: /* always branch */
-        branch(ch);
-        return;
-    }
-
-    status = ch->regs[DBDMA_STATUS] & DEVSTAT;
-
-    sel_mask = (ch->regs[DBDMA_BRANCH_SEL] >> 16) & 0x0f;
-    sel_value = ch->regs[DBDMA_BRANCH_SEL] & 0x0f;
-
-    cond = (status & sel_mask) == (sel_value & sel_mask);
-
-    switch(br) {
-    case BR_IFSET:  /* branch if condition bit is 1 */
-        if (cond)
-            branch(ch);
-        else
-            next(ch);
-        return;
-    case BR_IFCLR:  /* branch if condition bit is 0 */
-        if (!cond)
-            branch(ch);
-        else
-            next(ch);
-        return;
-    }
-}
-
-static QEMUBH *dbdma_bh;
-static void channel_run(DBDMA_channel *ch);
-
-static void dbdma_end(DBDMA_io *io)
-{
-    DBDMA_channel *ch = io->channel;
-    dbdma_cmd *current = &ch->current;
-
-    if (conditional_wait(ch))
-        goto wait;
-
-    current->xfer_status = cpu_to_le16(ch->regs[DBDMA_STATUS]);
-    current->res_count = cpu_to_le16(io->len);
-    dbdma_cmdptr_save(ch);
-    if (io->is_last)
-        ch->regs[DBDMA_STATUS] &= ~FLUSH;
-
-    conditional_interrupt(ch);
-    conditional_branch(ch);
-
-wait:
-    ch->processing = 0;
-    if ((ch->regs[DBDMA_STATUS] & RUN) &&
-        (ch->regs[DBDMA_STATUS] & ACTIVE))
-        channel_run(ch);
-}
-
-static void start_output(DBDMA_channel *ch, int key, uint32_t addr,
-                        uint16_t req_count, int is_last)
-{
-    DBDMA_DPRINTF("start_output\n");
-
-    /* KEY_REGS, KEY_DEVICE and KEY_STREAM
-     * are not implemented in the mac-io chip
-     */
-
-    DBDMA_DPRINTF("addr 0x%x key 0x%x\n", addr, key);
-    if (!addr || key > KEY_STREAM3) {
-        kill_channel(ch);
-        return;
-    }
-
-    ch->io.addr = addr;
-    ch->io.len = req_count;
-    ch->io.is_last = is_last;
-    ch->io.dma_end = dbdma_end;
-    ch->io.is_dma_out = 1;
-    ch->processing = 1;
-    if (ch->rw) {
-        ch->rw(&ch->io);
-    }
-}
-
-static void start_input(DBDMA_channel *ch, int key, uint32_t addr,
-                       uint16_t req_count, int is_last)
-{
-    DBDMA_DPRINTF("start_input\n");
-
-    /* KEY_REGS, KEY_DEVICE and KEY_STREAM
-     * are not implemented in the mac-io chip
-     */
-
-    if (!addr || key > KEY_STREAM3) {
-        kill_channel(ch);
-        return;
-    }
-
-    ch->io.addr = addr;
-    ch->io.len = req_count;
-    ch->io.is_last = is_last;
-    ch->io.dma_end = dbdma_end;
-    ch->io.is_dma_out = 0;
-    ch->processing = 1;
-    if (ch->rw) {
-        ch->rw(&ch->io);
-    }
-}
-
-static void load_word(DBDMA_channel *ch, int key, uint32_t addr,
-                     uint16_t len)
-{
-    dbdma_cmd *current = &ch->current;
-    uint32_t val;
-
-    DBDMA_DPRINTF("load_word\n");
-
-    /* only implements KEY_SYSTEM */
-
-    if (key != KEY_SYSTEM) {
-        printf("DBDMA: LOAD_WORD, unimplemented key %x\n", key);
-        kill_channel(ch);
-        return;
-    }
-
-    cpu_physical_memory_read(addr, (uint8_t*)&val, len);
-
-    if (len == 2)
-        val = (val << 16) | (current->cmd_dep & 0x0000ffff);
-    else if (len == 1)
-        val = (val << 24) | (current->cmd_dep & 0x00ffffff);
-
-    current->cmd_dep = val;
-
-    if (conditional_wait(ch))
-        goto wait;
-
-    current->xfer_status = cpu_to_le16(ch->regs[DBDMA_STATUS]);
-    dbdma_cmdptr_save(ch);
-    ch->regs[DBDMA_STATUS] &= ~FLUSH;
-
-    conditional_interrupt(ch);
-    next(ch);
-
-wait:
-    qemu_bh_schedule(dbdma_bh);
-}
-
-static void store_word(DBDMA_channel *ch, int key, uint32_t addr,
-                      uint16_t len)
-{
-    dbdma_cmd *current = &ch->current;
-    uint32_t val;
-
-    DBDMA_DPRINTF("store_word\n");
-
-    /* only implements KEY_SYSTEM */
-
-    if (key != KEY_SYSTEM) {
-        printf("DBDMA: STORE_WORD, unimplemented key %x\n", key);
-        kill_channel(ch);
-        return;
-    }
-
-    val = current->cmd_dep;
-    if (len == 2)
-        val >>= 16;
-    else if (len == 1)
-        val >>= 24;
-
-    cpu_physical_memory_write(addr, (uint8_t*)&val, len);
-
-    if (conditional_wait(ch))
-        goto wait;
-
-    current->xfer_status = cpu_to_le16(ch->regs[DBDMA_STATUS]);
-    dbdma_cmdptr_save(ch);
-    ch->regs[DBDMA_STATUS] &= ~FLUSH;
-
-    conditional_interrupt(ch);
-    next(ch);
-
-wait:
-    qemu_bh_schedule(dbdma_bh);
-}
-
-static void nop(DBDMA_channel *ch)
-{
-    dbdma_cmd *current = &ch->current;
-
-    if (conditional_wait(ch))
-        goto wait;
-
-    current->xfer_status = cpu_to_le16(ch->regs[DBDMA_STATUS]);
-    dbdma_cmdptr_save(ch);
-
-    conditional_interrupt(ch);
-    conditional_branch(ch);
-
-wait:
-    qemu_bh_schedule(dbdma_bh);
-}
-
-static void stop(DBDMA_channel *ch)
-{
-    ch->regs[DBDMA_STATUS] &= ~(ACTIVE|DEAD|FLUSH);
-
-    /* the stop command does not increment command pointer */
-}
-
-static void channel_run(DBDMA_channel *ch)
-{
-    dbdma_cmd *current = &ch->current;
-    uint16_t cmd, key;
-    uint16_t req_count;
-    uint32_t phy_addr;
-
-    DBDMA_DPRINTF("channel_run\n");
-    dump_dbdma_cmd(current);
-
-    /* clear WAKE flag at command fetch */
-
-    ch->regs[DBDMA_STATUS] &= ~WAKE;
-
-    cmd = le16_to_cpu(current->command) & COMMAND_MASK;
-
-    switch (cmd) {
-    case DBDMA_NOP:
-        nop(ch);
-       return;
-
-    case DBDMA_STOP:
-        stop(ch);
-       return;
-    }
-
-    key = le16_to_cpu(current->command) & 0x0700;
-    req_count = le16_to_cpu(current->req_count);
-    phy_addr = le32_to_cpu(current->phy_addr);
-
-    if (key == KEY_STREAM4) {
-        printf("command %x, invalid key 4\n", cmd);
-        kill_channel(ch);
-        return;
-    }
-
-    switch (cmd) {
-    case OUTPUT_MORE:
-        start_output(ch, key, phy_addr, req_count, 0);
-       return;
-
-    case OUTPUT_LAST:
-        start_output(ch, key, phy_addr, req_count, 1);
-       return;
-
-    case INPUT_MORE:
-        start_input(ch, key, phy_addr, req_count, 0);
-       return;
-
-    case INPUT_LAST:
-        start_input(ch, key, phy_addr, req_count, 1);
-       return;
-    }
-
-    if (key < KEY_REGS) {
-        printf("command %x, invalid key %x\n", cmd, key);
-        key = KEY_SYSTEM;
-    }
-
-    /* for LOAD_WORD and STORE_WORD, req_count is on 3 bits
-     * and BRANCH is invalid
-     */
-
-    req_count = req_count & 0x0007;
-    if (req_count & 0x4) {
-        req_count = 4;
-        phy_addr &= ~3;
-    } else if (req_count & 0x2) {
-        req_count = 2;
-        phy_addr &= ~1;
-    } else
-        req_count = 1;
-
-    switch (cmd) {
-    case LOAD_WORD:
-        load_word(ch, key, phy_addr, req_count);
-       return;
-
-    case STORE_WORD:
-        store_word(ch, key, phy_addr, req_count);
-       return;
-    }
-}
-
-static void DBDMA_run(DBDMAState *s)
-{
-    int channel;
-
-    for (channel = 0; channel < DBDMA_CHANNELS; channel++) {
-        DBDMA_channel *ch = &s->channels[channel];
-        uint32_t status = ch->regs[DBDMA_STATUS];
-        if (!ch->processing && (status & RUN) && (status & ACTIVE)) {
-            channel_run(ch);
-        }
-    }
-}
-
-static void DBDMA_run_bh(void *opaque)
-{
-    DBDMAState *s = opaque;
-
-    DBDMA_DPRINTF("DBDMA_run_bh\n");
-
-    DBDMA_run(s);
-}
-
-void DBDMA_register_channel(void *dbdma, int nchan, qemu_irq irq,
-                            DBDMA_rw rw, DBDMA_flush flush,
-                            void *opaque)
-{
-    DBDMAState *s = dbdma;
-    DBDMA_channel *ch = &s->channels[nchan];
-
-    DBDMA_DPRINTF("DBDMA_register_channel 0x%x\n", nchan);
-
-    ch->irq = irq;
-    ch->channel = nchan;
-    ch->rw = rw;
-    ch->flush = flush;
-    ch->io.opaque = opaque;
-    ch->io.channel = ch;
-}
-
-static void
-dbdma_control_write(DBDMA_channel *ch)
-{
-    uint16_t mask, value;
-    uint32_t status;
-
-    mask = (ch->regs[DBDMA_CONTROL] >> 16) & 0xffff;
-    value = ch->regs[DBDMA_CONTROL] & 0xffff;
-
-    value &= (RUN | PAUSE | FLUSH | WAKE | DEVSTAT);
-
-    status = ch->regs[DBDMA_STATUS];
-
-    status = (value & mask) | (status & ~mask);
-
-    if (status & WAKE)
-        status |= ACTIVE;
-    if (status & RUN) {
-        status |= ACTIVE;
-        status &= ~DEAD;
-    }
-    if (status & PAUSE)
-        status &= ~ACTIVE;
-    if ((ch->regs[DBDMA_STATUS] & RUN) && !(status & RUN)) {
-        /* RUN is cleared */
-        status &= ~(ACTIVE|DEAD);
-        if ((status & FLUSH) && ch->flush) {
-            ch->flush(&ch->io);
-            status &= ~FLUSH;
-        }
-    }
-
-    DBDMA_DPRINTF("    status 0x%08x\n", status);
-
-    ch->regs[DBDMA_STATUS] = status;
-
-    if (status & ACTIVE)
-        qemu_bh_schedule(dbdma_bh);
-    if ((status & FLUSH) && ch->flush)
-        ch->flush(&ch->io);
-}
-
-static void dbdma_write(void *opaque, hwaddr addr,
-                        uint64_t value, unsigned size)
-{
-    int channel = addr >> DBDMA_CHANNEL_SHIFT;
-    DBDMAState *s = opaque;
-    DBDMA_channel *ch = &s->channels[channel];
-    int reg = (addr - (channel << DBDMA_CHANNEL_SHIFT)) >> 2;
-
-    DBDMA_DPRINTF("writel 0x" TARGET_FMT_plx " <= 0x%08x\n", addr, value);
-    DBDMA_DPRINTF("channel 0x%x reg 0x%x\n",
-                  (uint32_t)addr >> DBDMA_CHANNEL_SHIFT, reg);
-
-    /* cmdptr cannot be modified if channel is RUN or ACTIVE */
-
-    if (reg == DBDMA_CMDPTR_LO &&
-        (ch->regs[DBDMA_STATUS] & (RUN | ACTIVE)))
-       return;
-
-    ch->regs[reg] = value;
-
-    switch(reg) {
-    case DBDMA_CONTROL:
-        dbdma_control_write(ch);
-        break;
-    case DBDMA_CMDPTR_LO:
-        /* 16-byte aligned */
-        ch->regs[DBDMA_CMDPTR_LO] &= ~0xf;
-        dbdma_cmdptr_load(ch);
-        break;
-    case DBDMA_STATUS:
-    case DBDMA_INTR_SEL:
-    case DBDMA_BRANCH_SEL:
-    case DBDMA_WAIT_SEL:
-        /* nothing to do */
-        break;
-    case DBDMA_XFER_MODE:
-    case DBDMA_CMDPTR_HI:
-    case DBDMA_DATA2PTR_HI:
-    case DBDMA_DATA2PTR_LO:
-    case DBDMA_ADDRESS_HI:
-    case DBDMA_BRANCH_ADDR_HI:
-    case DBDMA_RES1:
-    case DBDMA_RES2:
-    case DBDMA_RES3:
-    case DBDMA_RES4:
-        /* unused */
-        break;
-    }
-}
-
-static uint64_t dbdma_read(void *opaque, hwaddr addr,
-                           unsigned size)
-{
-    uint32_t value;
-    int channel = addr >> DBDMA_CHANNEL_SHIFT;
-    DBDMAState *s = opaque;
-    DBDMA_channel *ch = &s->channels[channel];
-    int reg = (addr - (channel << DBDMA_CHANNEL_SHIFT)) >> 2;
-
-    value = ch->regs[reg];
-
-    DBDMA_DPRINTF("readl 0x" TARGET_FMT_plx " => 0x%08x\n", addr, value);
-    DBDMA_DPRINTF("channel 0x%x reg 0x%x\n",
-                  (uint32_t)addr >> DBDMA_CHANNEL_SHIFT, reg);
-
-    switch(reg) {
-    case DBDMA_CONTROL:
-        value = 0;
-        break;
-    case DBDMA_STATUS:
-    case DBDMA_CMDPTR_LO:
-    case DBDMA_INTR_SEL:
-    case DBDMA_BRANCH_SEL:
-    case DBDMA_WAIT_SEL:
-        /* nothing to do */
-        break;
-    case DBDMA_XFER_MODE:
-    case DBDMA_CMDPTR_HI:
-    case DBDMA_DATA2PTR_HI:
-    case DBDMA_DATA2PTR_LO:
-    case DBDMA_ADDRESS_HI:
-    case DBDMA_BRANCH_ADDR_HI:
-        /* unused */
-        value = 0;
-        break;
-    case DBDMA_RES1:
-    case DBDMA_RES2:
-    case DBDMA_RES3:
-    case DBDMA_RES4:
-        /* reserved */
-        break;
-    }
-
-    return value;
-}
-
-static const MemoryRegionOps dbdma_ops = {
-    .read = dbdma_read,
-    .write = dbdma_write,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-};
-
-static const VMStateDescription vmstate_dbdma_channel = {
-    .name = "dbdma_channel",
-    .version_id = 0,
-    .minimum_version_id = 0,
-    .minimum_version_id_old = 0,
-    .fields      = (VMStateField[]) {
-        VMSTATE_UINT32_ARRAY(regs, struct DBDMA_channel, DBDMA_REGS),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static const VMStateDescription vmstate_dbdma = {
-    .name = "dbdma",
-    .version_id = 2,
-    .minimum_version_id = 2,
-    .minimum_version_id_old = 2,
-    .fields      = (VMStateField[]) {
-        VMSTATE_STRUCT_ARRAY(channels, DBDMAState, DBDMA_CHANNELS, 1,
-                             vmstate_dbdma_channel, DBDMA_channel),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void dbdma_reset(void *opaque)
-{
-    DBDMAState *s = opaque;
-    int i;
-
-    for (i = 0; i < DBDMA_CHANNELS; i++)
-        memset(s->channels[i].regs, 0, DBDMA_SIZE);
-}
-
-void* DBDMA_init (MemoryRegion **dbdma_mem)
-{
-    DBDMAState *s;
-
-    s = g_malloc0(sizeof(DBDMAState));
-
-    memory_region_init_io(&s->mem, &dbdma_ops, s, "dbdma", 0x1000);
-    *dbdma_mem = &s->mem;
-    vmstate_register(NULL, -1, &vmstate_dbdma, s);
-    qemu_register_reset(dbdma_reset, s);
-
-    dbdma_bh = qemu_bh_new(DBDMA_run_bh, s);
-
-    return s;
-}
diff --git a/hw/mac_dbdma.h b/hw/mac_dbdma.h
deleted file mode 100644 (file)
index 691263e..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (c) 2009 Laurent Vivier
- *
- * 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_MAC_DBDMA_H
-#define HW_MAC_DBDMA_H 1
-
-#include "exec/memory.h"
-
-typedef struct DBDMA_io DBDMA_io;
-
-typedef void (*DBDMA_flush)(DBDMA_io *io);
-typedef void (*DBDMA_rw)(DBDMA_io *io);
-typedef void (*DBDMA_end)(DBDMA_io *io);
-struct DBDMA_io {
-    void *opaque;
-    void *channel;
-    hwaddr addr;
-    int len;
-    int is_last;
-    int is_dma_out;
-    DBDMA_end dma_end;
-};
-
-
-void DBDMA_register_channel(void *dbdma, int nchan, qemu_irq irq,
-                            DBDMA_rw rw, DBDMA_flush flush,
-                            void *opaque);
-void* DBDMA_init (MemoryRegion **dbdma_mem);
-
-#endif
diff --git a/hw/mac_nvram.c b/hw/mac_nvram.c
deleted file mode 100644 (file)
index ed32bde..0000000
+++ /dev/null
@@ -1,196 +0,0 @@
-/*
- * PowerMac NVRAM emulation
- *
- * Copyright (c) 2005-2007 Fabrice Bellard
- * Copyright (c) 2007 Jocelyn Mayer
- *
- * 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 "hw/hw.h"
-#include "hw/firmware_abi.h"
-#include "sysemu/sysemu.h"
-#include "hw/ppc/mac.h"
-
-/* debug NVR */
-//#define DEBUG_NVR
-
-#ifdef DEBUG_NVR
-#define NVR_DPRINTF(fmt, ...)                                   \
-    do { printf("NVR: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define NVR_DPRINTF(fmt, ...)
-#endif
-
-#define DEF_SYSTEM_SIZE 0xc10
-
-/* Direct access to NVRAM */
-uint8_t macio_nvram_read(MacIONVRAMState *s, uint32_t addr)
-{
-    uint32_t ret;
-
-    if (addr < s->size) {
-        ret = s->data[addr];
-    } else {
-        ret = -1;
-    }
-    NVR_DPRINTF("read addr %04" PRIx32 " val %" PRIx8 "\n", addr, ret);
-
-    return ret;
-}
-
-void macio_nvram_write(MacIONVRAMState *s, uint32_t addr, uint8_t val)
-{
-    NVR_DPRINTF("write addr %04" PRIx32 " val %" PRIx8 "\n", addr, val);
-    if (addr < s->size) {
-        s->data[addr] = val;
-    }
-}
-
-/* macio style NVRAM device */
-static void macio_nvram_writeb(void *opaque, hwaddr addr,
-                               uint64_t value, unsigned size)
-{
-    MacIONVRAMState *s = opaque;
-
-    addr = (addr >> s->it_shift) & (s->size - 1);
-    s->data[addr] = value;
-    NVR_DPRINTF("writeb addr %04" PHYS_PRIx " val %" PRIx64 "\n", addr, value);
-}
-
-static uint64_t macio_nvram_readb(void *opaque, hwaddr addr,
-                                  unsigned size)
-{
-    MacIONVRAMState *s = opaque;
-    uint32_t value;
-
-    addr = (addr >> s->it_shift) & (s->size - 1);
-    value = s->data[addr];
-    NVR_DPRINTF("readb addr %04x val %x\n", (int)addr, value);
-
-    return value;
-}
-
-static const MemoryRegionOps macio_nvram_ops = {
-    .read = macio_nvram_readb,
-    .write = macio_nvram_writeb,
-    .endianness = DEVICE_BIG_ENDIAN,
-};
-
-static const VMStateDescription vmstate_macio_nvram = {
-    .name = "macio_nvram",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField[]) {
-        VMSTATE_VBUFFER_UINT32(data, MacIONVRAMState, 0, NULL, 0, size),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-
-static void macio_nvram_reset(DeviceState *dev)
-{
-}
-
-static void macio_nvram_realizefn(DeviceState *dev, Error **errp)
-{
-    SysBusDevice *d = SYS_BUS_DEVICE(dev);
-    MacIONVRAMState *s = MACIO_NVRAM(dev);
-
-    s->data = g_malloc0(s->size);
-
-    memory_region_init_io(&s->mem, &macio_nvram_ops, s, "macio-nvram",
-                          s->size << s->it_shift);
-    sysbus_init_mmio(d, &s->mem);
-}
-
-static void macio_nvram_unrealizefn(DeviceState *dev, Error **errp)
-{
-    MacIONVRAMState *s = MACIO_NVRAM(dev);
-
-    g_free(s->data);
-}
-
-static Property macio_nvram_properties[] = {
-    DEFINE_PROP_UINT32("size", MacIONVRAMState, size, 0),
-    DEFINE_PROP_UINT32("it_shift", MacIONVRAMState, it_shift, 0),
-    DEFINE_PROP_END_OF_LIST()
-};
-
-static void macio_nvram_class_init(ObjectClass *oc, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(oc);
-
-    dc->realize = macio_nvram_realizefn;
-    dc->unrealize = macio_nvram_unrealizefn;
-    dc->reset = macio_nvram_reset;
-    dc->vmsd = &vmstate_macio_nvram;
-    dc->props = macio_nvram_properties;
-}
-
-static const TypeInfo macio_nvram_type_info = {
-    .name = TYPE_MACIO_NVRAM,
-    .parent = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(MacIONVRAMState),
-    .class_init = macio_nvram_class_init,
-};
-
-static void macio_nvram_register_types(void)
-{
-    type_register_static(&macio_nvram_type_info);
-}
-
-/* Set up a system OpenBIOS NVRAM partition */
-void pmac_format_nvram_partition (MacIONVRAMState *nvr, int len)
-{
-    unsigned int i;
-    uint32_t start = 0, end;
-    struct OpenBIOS_nvpart_v1 *part_header;
-
-    // OpenBIOS nvram variables
-    // Variable partition
-    part_header = (struct OpenBIOS_nvpart_v1 *)nvr->data;
-    part_header->signature = OPENBIOS_PART_SYSTEM;
-    pstrcpy(part_header->name, sizeof(part_header->name), "system");
-
-    end = start + sizeof(struct OpenBIOS_nvpart_v1);
-    for (i = 0; i < nb_prom_envs; i++)
-        end = OpenBIOS_set_var(nvr->data, end, prom_envs[i]);
-
-    // End marker
-    nvr->data[end++] = '\0';
-
-    end = start + ((end - start + 15) & ~15);
-    /* XXX: OpenBIOS is not able to grow up a partition. Leave some space for
-       new variables. */
-    if (end < DEF_SYSTEM_SIZE)
-        end = DEF_SYSTEM_SIZE;
-    OpenBIOS_finish_partition(part_header, end - start);
-
-    // free partition
-    start = end;
-    part_header = (struct OpenBIOS_nvpart_v1 *)&nvr->data[start];
-    part_header->signature = OPENBIOS_PART_FREE;
-    pstrcpy(part_header->name, sizeof(part_header->name), "free");
-
-    end = len;
-    OpenBIOS_finish_partition(part_header, end - start);
-}
-
-type_init(macio_nvram_register_types)
diff --git a/hw/macio.c b/hw/macio.c
deleted file mode 100644 (file)
index e91143e..0000000
+++ /dev/null
@@ -1,305 +0,0 @@
-/*
- * PowerMac MacIO device emulation
- *
- * Copyright (c) 2005-2007 Fabrice Bellard
- * Copyright (c) 2007 Jocelyn Mayer
- *
- * 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 "hw/hw.h"
-#include "hw/ppc/mac.h"
-#include "hw/pci/pci.h"
-#include "hw/mac_dbdma.h"
-#include "hw/escc.h"
-
-#define TYPE_MACIO "macio"
-#define MACIO(obj) OBJECT_CHECK(MacIOState, (obj), TYPE_MACIO)
-
-typedef struct MacIOState
-{
-    /*< private >*/
-    PCIDevice parent;
-    /*< public >*/
-
-    MemoryRegion bar;
-    CUDAState cuda;
-    void *dbdma;
-    MemoryRegion *pic_mem;
-    MemoryRegion *escc_mem;
-} MacIOState;
-
-#define OLDWORLD_MACIO(obj) \
-    OBJECT_CHECK(OldWorldMacIOState, (obj), TYPE_OLDWORLD_MACIO)
-
-typedef struct OldWorldMacIOState {
-    /*< private >*/
-    MacIOState parent_obj;
-    /*< public >*/
-
-    qemu_irq irqs[3];
-
-    MacIONVRAMState nvram;
-    MACIOIDEState ide;
-} OldWorldMacIOState;
-
-#define NEWWORLD_MACIO(obj) \
-    OBJECT_CHECK(NewWorldMacIOState, (obj), TYPE_NEWWORLD_MACIO)
-
-typedef struct NewWorldMacIOState {
-    /*< private >*/
-    MacIOState parent_obj;
-    /*< public >*/
-    qemu_irq irqs[5];
-    MACIOIDEState ide[2];
-} NewWorldMacIOState;
-
-static void macio_bar_setup(MacIOState *macio_state)
-{
-    MemoryRegion *bar = &macio_state->bar;
-
-    if (macio_state->escc_mem) {
-        memory_region_add_subregion(bar, 0x13000, macio_state->escc_mem);
-    }
-}
-
-static int macio_common_initfn(PCIDevice *d)
-{
-    MacIOState *s = MACIO(d);
-    SysBusDevice *sysbus_dev;
-    int ret;
-
-    d->config[0x3d] = 0x01; // interrupt on pin 1
-
-    ret = qdev_init(DEVICE(&s->cuda));
-    if (ret < 0) {
-        return ret;
-    }
-    sysbus_dev = SYS_BUS_DEVICE(&s->cuda);
-    memory_region_add_subregion(&s->bar, 0x16000,
-                                sysbus_mmio_get_region(sysbus_dev, 0));
-
-    macio_bar_setup(s);
-    pci_register_bar(d, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar);
-
-    return 0;
-}
-
-static int macio_oldworld_initfn(PCIDevice *d)
-{
-    MacIOState *s = MACIO(d);
-    OldWorldMacIOState *os = OLDWORLD_MACIO(d);
-    SysBusDevice *sysbus_dev;
-    int ret = macio_common_initfn(d);
-    if (ret < 0) {
-        return ret;
-    }
-
-    sysbus_dev = SYS_BUS_DEVICE(&s->cuda);
-    sysbus_connect_irq(sysbus_dev, 0, os->irqs[0]);
-
-    ret = qdev_init(DEVICE(&os->nvram));
-    if (ret < 0) {
-        return ret;
-    }
-    sysbus_dev = SYS_BUS_DEVICE(&os->nvram);
-    memory_region_add_subregion(&s->bar, 0x60000,
-                                sysbus_mmio_get_region(sysbus_dev, 0));
-    pmac_format_nvram_partition(&os->nvram, os->nvram.size);
-
-    if (s->pic_mem) {
-        /* Heathrow PIC */
-        memory_region_add_subregion(&s->bar, 0x00000, s->pic_mem);
-    }
-
-    sysbus_dev = SYS_BUS_DEVICE(&os->ide);
-    sysbus_connect_irq(sysbus_dev, 0, os->irqs[1]);
-    sysbus_connect_irq(sysbus_dev, 1, os->irqs[2]);
-    macio_ide_register_dma(&os->ide, s->dbdma, 0x16);
-    ret = qdev_init(DEVICE(&os->ide));
-    if (ret < 0) {
-        return ret;
-    }
-
-    return 0;
-}
-
-static void macio_oldworld_init(Object *obj)
-{
-    MacIOState *s = MACIO(obj);
-    OldWorldMacIOState *os = OLDWORLD_MACIO(obj);
-    DeviceState *dev;
-
-    qdev_init_gpio_out(DEVICE(obj), os->irqs, ARRAY_SIZE(os->irqs));
-
-    object_initialize(&os->nvram, TYPE_MACIO_NVRAM);
-    dev = DEVICE(&os->nvram);
-    qdev_prop_set_uint32(dev, "size", 0x2000);
-    qdev_prop_set_uint32(dev, "it_shift", 4);
-
-    object_initialize(&os->ide, TYPE_MACIO_IDE);
-    qdev_set_parent_bus(DEVICE(&os->ide), sysbus_get_default());
-    memory_region_add_subregion(&s->bar, 0x1f000 + (1 * 0x1000), &os->ide.mem);
-    object_property_add_child(obj, "ide", OBJECT(&os->ide), NULL);
-}
-
-static int macio_newworld_initfn(PCIDevice *d)
-{
-    MacIOState *s = MACIO(d);
-    NewWorldMacIOState *ns = NEWWORLD_MACIO(d);
-    SysBusDevice *sysbus_dev;
-    int ret = macio_common_initfn(d);
-    if (ret < 0) {
-        return ret;
-    }
-
-    sysbus_dev = SYS_BUS_DEVICE(&s->cuda);
-    sysbus_connect_irq(sysbus_dev, 0, ns->irqs[0]);
-
-    if (s->pic_mem) {
-        /* OpenPIC */
-        memory_region_add_subregion(&s->bar, 0x40000, s->pic_mem);
-    }
-
-    sysbus_dev = SYS_BUS_DEVICE(&ns->ide[0]);
-    sysbus_connect_irq(sysbus_dev, 0, ns->irqs[1]);
-    sysbus_connect_irq(sysbus_dev, 1, ns->irqs[2]);
-    macio_ide_register_dma(&ns->ide[0], s->dbdma, 0x16);
-    ret = qdev_init(DEVICE(&ns->ide[0]));
-    if (ret < 0) {
-        return ret;
-    }
-
-    sysbus_dev = SYS_BUS_DEVICE(&ns->ide[1]);
-    sysbus_connect_irq(sysbus_dev, 0, ns->irqs[3]);
-    sysbus_connect_irq(sysbus_dev, 1, ns->irqs[4]);
-    macio_ide_register_dma(&ns->ide[1], s->dbdma, 0x1a);
-    ret = qdev_init(DEVICE(&ns->ide[1]));
-    if (ret < 0) {
-        return ret;
-    }
-
-    return 0;
-}
-
-static void macio_newworld_init(Object *obj)
-{
-    MacIOState *s = MACIO(obj);
-    NewWorldMacIOState *ns = NEWWORLD_MACIO(obj);
-    int i;
-    gchar *name;
-
-    qdev_init_gpio_out(DEVICE(obj), ns->irqs, ARRAY_SIZE(ns->irqs));
-
-    for (i = 0; i < 2; i++) {
-        object_initialize(&ns->ide[i], TYPE_MACIO_IDE);
-        qdev_set_parent_bus(DEVICE(&ns->ide[i]), sysbus_get_default());
-        memory_region_add_subregion(&s->bar, 0x1f000 + ((i + 1) * 0x1000),
-                                    &ns->ide[i].mem);
-        name = g_strdup_printf("ide[%i]", i);
-        object_property_add_child(obj, name, OBJECT(&ns->ide[i]), NULL);
-        g_free(name);
-    }
-}
-
-static void macio_instance_init(Object *obj)
-{
-    MacIOState *s = MACIO(obj);
-    MemoryRegion *dbdma_mem;
-
-    memory_region_init(&s->bar, "macio", 0x80000);
-
-    object_initialize(&s->cuda, TYPE_CUDA);
-    qdev_set_parent_bus(DEVICE(&s->cuda), sysbus_get_default());
-    object_property_add_child(obj, "cuda", OBJECT(&s->cuda), NULL);
-
-    s->dbdma = DBDMA_init(&dbdma_mem);
-    memory_region_add_subregion(&s->bar, 0x08000, dbdma_mem);
-}
-
-static void macio_oldworld_class_init(ObjectClass *oc, void *data)
-{
-    PCIDeviceClass *pdc = PCI_DEVICE_CLASS(oc);
-
-    pdc->init = macio_oldworld_initfn;
-    pdc->device_id = PCI_DEVICE_ID_APPLE_343S1201;
-}
-
-static void macio_newworld_class_init(ObjectClass *oc, void *data)
-{
-    PCIDeviceClass *pdc = PCI_DEVICE_CLASS(oc);
-
-    pdc->init = macio_newworld_initfn;
-    pdc->device_id = PCI_DEVICE_ID_APPLE_UNI_N_KEYL;
-}
-
-static void macio_class_init(ObjectClass *klass, void *data)
-{
-    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
-    k->vendor_id = PCI_VENDOR_ID_APPLE;
-    k->class_id = PCI_CLASS_OTHERS << 8;
-}
-
-static const TypeInfo macio_oldworld_type_info = {
-    .name          = TYPE_OLDWORLD_MACIO,
-    .parent        = TYPE_MACIO,
-    .instance_size = sizeof(OldWorldMacIOState),
-    .instance_init = macio_oldworld_init,
-    .class_init    = macio_oldworld_class_init,
-};
-
-static const TypeInfo macio_newworld_type_info = {
-    .name          = TYPE_NEWWORLD_MACIO,
-    .parent        = TYPE_MACIO,
-    .instance_size = sizeof(NewWorldMacIOState),
-    .instance_init = macio_newworld_init,
-    .class_init    = macio_newworld_class_init,
-};
-
-static const TypeInfo macio_type_info = {
-    .name          = TYPE_MACIO,
-    .parent        = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(MacIOState),
-    .instance_init = macio_instance_init,
-    .abstract      = true,
-    .class_init    = macio_class_init,
-};
-
-static void macio_register_types(void)
-{
-    type_register_static(&macio_type_info);
-    type_register_static(&macio_oldworld_type_info);
-    type_register_static(&macio_newworld_type_info);
-}
-
-type_init(macio_register_types)
-
-void macio_init(PCIDevice *d,
-                MemoryRegion *pic_mem,
-                MemoryRegion *escc_mem)
-{
-    MacIOState *macio_state = MACIO(d);
-
-    macio_state->pic_mem = pic_mem;
-    macio_state->escc_mem = escc_mem;
-    /* Note: this code is strongly inspirated from the corresponding code
-       in PearPC */
-
-    qdev_init_nofail(DEVICE(d));
-}
diff --git a/hw/marvell_88w8618_audio.c b/hw/marvell_88w8618_audio.c
deleted file mode 100644 (file)
index e042046..0000000
+++ /dev/null
@@ -1,303 +0,0 @@
-/*
- * Marvell 88w8618 audio emulation extracted from
- * Marvell MV88w8618 / Freecom MusicPal emulation.
- *
- * 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/sysbus.h"
-#include "hw/hw.h"
-#include "hw/i2c.h"
-#include "hw/sysbus.h"
-#include "audio/audio.h"
-
-#define MP_AUDIO_SIZE           0x00001000
-
-/* Audio register offsets */
-#define MP_AUDIO_PLAYBACK_MODE  0x00
-#define MP_AUDIO_CLOCK_DIV      0x18
-#define MP_AUDIO_IRQ_STATUS     0x20
-#define MP_AUDIO_IRQ_ENABLE     0x24
-#define MP_AUDIO_TX_START_LO    0x28
-#define MP_AUDIO_TX_THRESHOLD   0x2C
-#define MP_AUDIO_TX_STATUS      0x38
-#define MP_AUDIO_TX_START_HI    0x40
-
-/* Status register and IRQ enable bits */
-#define MP_AUDIO_TX_HALF        (1 << 6)
-#define MP_AUDIO_TX_FULL        (1 << 7)
-
-/* Playback mode bits */
-#define MP_AUDIO_16BIT_SAMPLE   (1 << 0)
-#define MP_AUDIO_PLAYBACK_EN    (1 << 7)
-#define MP_AUDIO_CLOCK_24MHZ    (1 << 9)
-#define MP_AUDIO_MONO           (1 << 14)
-
-typedef struct mv88w8618_audio_state {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-    qemu_irq irq;
-    uint32_t playback_mode;
-    uint32_t status;
-    uint32_t irq_enable;
-    uint32_t phys_buf;
-    uint32_t target_buffer;
-    uint32_t threshold;
-    uint32_t play_pos;
-    uint32_t last_free;
-    uint32_t clock_div;
-    void *wm;
-} mv88w8618_audio_state;
-
-static void mv88w8618_audio_callback(void *opaque, int free_out, int free_in)
-{
-    mv88w8618_audio_state *s = opaque;
-    int16_t *codec_buffer;
-    int8_t buf[4096];
-    int8_t *mem_buffer;
-    int pos, block_size;
-
-    if (!(s->playback_mode & MP_AUDIO_PLAYBACK_EN)) {
-        return;
-    }
-    if (s->playback_mode & MP_AUDIO_16BIT_SAMPLE) {
-        free_out <<= 1;
-    }
-    if (!(s->playback_mode & MP_AUDIO_MONO)) {
-        free_out <<= 1;
-    }
-    block_size = s->threshold / 2;
-    if (free_out - s->last_free < block_size) {
-        return;
-    }
-    if (block_size > 4096) {
-        return;
-    }
-    cpu_physical_memory_read(s->target_buffer + s->play_pos, (void *)buf,
-                             block_size);
-    mem_buffer = buf;
-    if (s->playback_mode & MP_AUDIO_16BIT_SAMPLE) {
-        if (s->playback_mode & MP_AUDIO_MONO) {
-            codec_buffer = wm8750_dac_buffer(s->wm, block_size >> 1);
-            for (pos = 0; pos < block_size; pos += 2) {
-                *codec_buffer++ = *(int16_t *)mem_buffer;
-                *codec_buffer++ = *(int16_t *)mem_buffer;
-                mem_buffer += 2;
-            }
-        } else {
-            memcpy(wm8750_dac_buffer(s->wm, block_size >> 2),
-                   (uint32_t *)mem_buffer, block_size);
-        }
-    } else {
-        if (s->playback_mode & MP_AUDIO_MONO) {
-            codec_buffer = wm8750_dac_buffer(s->wm, block_size);
-            for (pos = 0; pos < block_size; pos++) {
-                *codec_buffer++ = cpu_to_le16(256 * *mem_buffer);
-                *codec_buffer++ = cpu_to_le16(256 * *mem_buffer++);
-            }
-        } else {
-            codec_buffer = wm8750_dac_buffer(s->wm, block_size >> 1);
-            for (pos = 0; pos < block_size; pos += 2) {
-                *codec_buffer++ = cpu_to_le16(256 * *mem_buffer++);
-                *codec_buffer++ = cpu_to_le16(256 * *mem_buffer++);
-            }
-        }
-    }
-    wm8750_dac_commit(s->wm);
-
-    s->last_free = free_out - block_size;
-
-    if (s->play_pos == 0) {
-        s->status |= MP_AUDIO_TX_HALF;
-        s->play_pos = block_size;
-    } else {
-        s->status |= MP_AUDIO_TX_FULL;
-        s->play_pos = 0;
-    }
-
-    if (s->status & s->irq_enable) {
-        qemu_irq_raise(s->irq);
-    }
-}
-
-static void mv88w8618_audio_clock_update(mv88w8618_audio_state *s)
-{
-    int rate;
-
-    if (s->playback_mode & MP_AUDIO_CLOCK_24MHZ) {
-        rate = 24576000 / 64; /* 24.576MHz */
-    } else {
-        rate = 11289600 / 64; /* 11.2896MHz */
-    }
-    rate /= ((s->clock_div >> 8) & 0xff) + 1;
-
-    wm8750_set_bclk_in(s->wm, rate);
-}
-
-static uint64_t mv88w8618_audio_read(void *opaque, hwaddr offset,
-                                    unsigned size)
-{
-    mv88w8618_audio_state *s = opaque;
-
-    switch (offset) {
-    case MP_AUDIO_PLAYBACK_MODE:
-        return s->playback_mode;
-
-    case MP_AUDIO_CLOCK_DIV:
-        return s->clock_div;
-
-    case MP_AUDIO_IRQ_STATUS:
-        return s->status;
-
-    case MP_AUDIO_IRQ_ENABLE:
-        return s->irq_enable;
-
-    case MP_AUDIO_TX_STATUS:
-        return s->play_pos >> 2;
-
-    default:
-        return 0;
-    }
-}
-
-static void mv88w8618_audio_write(void *opaque, hwaddr offset,
-                                  uint64_t value, unsigned size)
-{
-    mv88w8618_audio_state *s = opaque;
-
-    switch (offset) {
-    case MP_AUDIO_PLAYBACK_MODE:
-        if (value & MP_AUDIO_PLAYBACK_EN &&
-            !(s->playback_mode & MP_AUDIO_PLAYBACK_EN)) {
-            s->status = 0;
-            s->last_free = 0;
-            s->play_pos = 0;
-        }
-        s->playback_mode = value;
-        mv88w8618_audio_clock_update(s);
-        break;
-
-    case MP_AUDIO_CLOCK_DIV:
-        s->clock_div = value;
-        s->last_free = 0;
-        s->play_pos = 0;
-        mv88w8618_audio_clock_update(s);
-        break;
-
-    case MP_AUDIO_IRQ_STATUS:
-        s->status &= ~value;
-        break;
-
-    case MP_AUDIO_IRQ_ENABLE:
-        s->irq_enable = value;
-        if (s->status & s->irq_enable) {
-            qemu_irq_raise(s->irq);
-        }
-        break;
-
-    case MP_AUDIO_TX_START_LO:
-        s->phys_buf = (s->phys_buf & 0xFFFF0000) | (value & 0xFFFF);
-        s->target_buffer = s->phys_buf;
-        s->play_pos = 0;
-        s->last_free = 0;
-        break;
-
-    case MP_AUDIO_TX_THRESHOLD:
-        s->threshold = (value + 1) * 4;
-        break;
-
-    case MP_AUDIO_TX_START_HI:
-        s->phys_buf = (s->phys_buf & 0xFFFF) | (value << 16);
-        s->target_buffer = s->phys_buf;
-        s->play_pos = 0;
-        s->last_free = 0;
-        break;
-    }
-}
-
-static void mv88w8618_audio_reset(DeviceState *d)
-{
-    mv88w8618_audio_state *s = FROM_SYSBUS(mv88w8618_audio_state,
-                                           SYS_BUS_DEVICE(d));
-
-    s->playback_mode = 0;
-    s->status = 0;
-    s->irq_enable = 0;
-    s->clock_div = 0;
-    s->threshold = 0;
-    s->phys_buf = 0;
-}
-
-static const MemoryRegionOps mv88w8618_audio_ops = {
-    .read = mv88w8618_audio_read,
-    .write = mv88w8618_audio_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int mv88w8618_audio_init(SysBusDevice *dev)
-{
-    mv88w8618_audio_state *s = FROM_SYSBUS(mv88w8618_audio_state, dev);
-
-    sysbus_init_irq(dev, &s->irq);
-
-    wm8750_data_req_set(s->wm, mv88w8618_audio_callback, s);
-
-    memory_region_init_io(&s->iomem, &mv88w8618_audio_ops, s,
-                          "audio", MP_AUDIO_SIZE);
-    sysbus_init_mmio(dev, &s->iomem);
-
-    return 0;
-}
-
-static const VMStateDescription mv88w8618_audio_vmsd = {
-    .name = "mv88w8618_audio",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT32(playback_mode, mv88w8618_audio_state),
-        VMSTATE_UINT32(status, mv88w8618_audio_state),
-        VMSTATE_UINT32(irq_enable, mv88w8618_audio_state),
-        VMSTATE_UINT32(phys_buf, mv88w8618_audio_state),
-        VMSTATE_UINT32(target_buffer, mv88w8618_audio_state),
-        VMSTATE_UINT32(threshold, mv88w8618_audio_state),
-        VMSTATE_UINT32(play_pos, mv88w8618_audio_state),
-        VMSTATE_UINT32(last_free, mv88w8618_audio_state),
-        VMSTATE_UINT32(clock_div, mv88w8618_audio_state),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static Property mv88w8618_audio_properties[] = {
-    DEFINE_PROP_PTR("wm8750", mv88w8618_audio_state, wm),
-    {/* end of list */},
-};
-
-static void mv88w8618_audio_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = mv88w8618_audio_init;
-    dc->reset = mv88w8618_audio_reset;
-    dc->vmsd = &mv88w8618_audio_vmsd;
-    dc->props = mv88w8618_audio_properties;
-}
-
-static const 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_types(void)
-{
-    type_register_static(&mv88w8618_audio_info);
-}
-
-type_init(mv88w8618_register_types)
diff --git a/hw/max111x.c b/hw/max111x.c
deleted file mode 100644 (file)
index d477ecd..0000000
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- * Maxim MAX1110/1111 ADC chip emulation.
- *
- * Copyright (c) 2006 Openedhand Ltd.
- * Written by Andrzej Zaborowski <balrog@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 "hw/ssi.h"
-
-typedef struct {
-    SSISlave ssidev;
-    qemu_irq interrupt;
-    uint8_t tb1, rb2, rb3;
-    int cycle;
-
-    uint8_t input[8];
-    int inputs, com;
-} MAX111xState;
-
-/* Control-byte bitfields */
-#define CB_PD0         (1 << 0)
-#define CB_PD1         (1 << 1)
-#define CB_SGL         (1 << 2)
-#define CB_UNI         (1 << 3)
-#define CB_SEL0                (1 << 4)
-#define CB_SEL1                (1 << 5)
-#define CB_SEL2                (1 << 6)
-#define CB_START       (1 << 7)
-
-#define CHANNEL_NUM(v, b0, b1, b2)     \
-                       ((((v) >> (2 + (b0))) & 4) |    \
-                        (((v) >> (3 + (b1))) & 2) |    \
-                        (((v) >> (4 + (b2))) & 1))
-
-static uint32_t max111x_read(MAX111xState *s)
-{
-    if (!s->tb1)
-        return 0;
-
-    switch (s->cycle ++) {
-    case 1:
-        return s->rb2;
-    case 2:
-        return s->rb3;
-    }
-
-    return 0;
-}
-
-/* Interpret a control-byte */
-static void max111x_write(MAX111xState *s, uint32_t value)
-{
-    int measure, chan;
-
-    /* Ignore the value if START bit is zero */
-    if (!(value & CB_START))
-        return;
-
-    s->cycle = 0;
-
-    if (!(value & CB_PD1)) {
-        s->tb1 = 0;
-        return;
-    }
-
-    s->tb1 = value;
-
-    if (s->inputs == 8)
-        chan = CHANNEL_NUM(value, 1, 0, 2);
-    else
-        chan = CHANNEL_NUM(value & ~CB_SEL0, 0, 1, 2);
-
-    if (value & CB_SGL)
-        measure = s->input[chan] - s->com;
-    else
-        measure = s->input[chan] - s->input[chan ^ 1];
-
-    if (!(value & CB_UNI))
-        measure ^= 0x80;
-
-    s->rb2 = (measure >> 2) & 0x3f;
-    s->rb3 = (measure << 6) & 0xc0;
-
-    /* FIXME: When should the IRQ be lowered?  */
-    qemu_irq_raise(s->interrupt);
-}
-
-static uint32_t max111x_transfer(SSISlave *dev, uint32_t value)
-{
-    MAX111xState *s = FROM_SSI_SLAVE(MAX111xState, dev);
-    max111x_write(s, value);
-    return max111x_read(s);
-}
-
-static const VMStateDescription vmstate_max111x = {
-    .name = "max111x",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField[]) {
-        VMSTATE_SSI_SLAVE(ssidev, MAX111xState),
-        VMSTATE_UINT8(tb1, MAX111xState),
-        VMSTATE_UINT8(rb2, MAX111xState),
-        VMSTATE_UINT8(rb3, MAX111xState),
-        VMSTATE_INT32_EQUAL(inputs, MAX111xState),
-        VMSTATE_INT32(com, MAX111xState),
-        VMSTATE_ARRAY_INT32_UNSAFE(input, MAX111xState, inputs,
-                                   vmstate_info_uint8, uint8_t),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static int max111x_init(SSISlave *dev, int inputs)
-{
-    MAX111xState *s = FROM_SSI_SLAVE(MAX111xState, dev);
-
-    qdev_init_gpio_out(&dev->qdev, &s->interrupt, 1);
-
-    s->inputs = inputs;
-    /* TODO: add a user interface for setting these */
-    s->input[0] = 0xf0;
-    s->input[1] = 0xe0;
-    s->input[2] = 0xd0;
-    s->input[3] = 0xc0;
-    s->input[4] = 0xb0;
-    s->input[5] = 0xa0;
-    s->input[6] = 0x90;
-    s->input[7] = 0x80;
-    s->com = 0;
-
-    vmstate_register(&dev->qdev, -1, &vmstate_max111x, s);
-    return 0;
-}
-
-static int max1110_init(SSISlave *dev)
-{
-    return max111x_init(dev, 8);
-}
-
-static int max1111_init(SSISlave *dev)
-{
-    return max111x_init(dev, 4);
-}
-
-void max111x_set_input(DeviceState *dev, int line, uint8_t value)
-{
-    MAX111xState *s = FROM_SSI_SLAVE(MAX111xState, SSI_SLAVE_FROM_QDEV(dev));
-    assert(line >= 0 && line < s->inputs);
-    s->input[line] = value;
-}
-
-static void max1110_class_init(ObjectClass *klass, void *data)
-{
-    SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
-
-    k->init = max1110_init;
-    k->transfer = max111x_transfer;
-}
-
-static const 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)
-{
-    SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
-
-    k->init = max1111_init;
-    k->transfer = max111x_transfer;
-}
-
-static const TypeInfo max1111_info = {
-    .name          = "max1111",
-    .parent        = TYPE_SSI_SLAVE,
-    .instance_size = sizeof(MAX111xState),
-    .class_init    = max1111_class_init,
-};
-
-static void max111x_register_types(void)
-{
-    type_register_static(&max1110_info);
-    type_register_static(&max1111_info);
-}
-
-type_init(max111x_register_types)
diff --git a/hw/max7310.c b/hw/max7310.c
deleted file mode 100644 (file)
index e5cb810..0000000
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
- * MAX7310 8-port GPIO expansion chip.
- *
- * Copyright (c) 2006 Openedhand Ltd.
- * Written by Andrzej Zaborowski <balrog@zabor.org>
- *
- * This file is licensed under GNU GPL.
- */
-
-#include "hw/i2c.h"
-
-typedef struct {
-    I2CSlave i2c;
-    int i2c_command_byte;
-    int len;
-
-    uint8_t level;
-    uint8_t direction;
-    uint8_t polarity;
-    uint8_t status;
-    uint8_t command;
-    qemu_irq handler[8];
-    qemu_irq *gpio_in;
-} MAX7310State;
-
-static void max7310_reset(DeviceState *dev)
-{
-    MAX7310State *s = FROM_I2C_SLAVE(MAX7310State, I2C_SLAVE(dev));
-    s->level &= s->direction;
-    s->direction = 0xff;
-    s->polarity = 0xf0;
-    s->status = 0x01;
-    s->command = 0x00;
-}
-
-static int max7310_rx(I2CSlave *i2c)
-{
-    MAX7310State *s = (MAX7310State *) i2c;
-
-    switch (s->command) {
-    case 0x00: /* Input port */
-        return s->level ^ s->polarity;
-        break;
-
-    case 0x01: /* Output port */
-        return s->level & ~s->direction;
-        break;
-
-    case 0x02: /* Polarity inversion */
-        return s->polarity;
-
-    case 0x03: /* Configuration */
-        return s->direction;
-
-    case 0x04: /* Timeout */
-        return s->status;
-        break;
-
-    case 0xff: /* Reserved */
-        return 0xff;
-
-    default:
-#ifdef VERBOSE
-        printf("%s: unknown register %02x\n", __FUNCTION__, s->command);
-#endif
-        break;
-    }
-    return 0xff;
-}
-
-static int max7310_tx(I2CSlave *i2c, uint8_t data)
-{
-    MAX7310State *s = (MAX7310State *) i2c;
-    uint8_t diff;
-    int line;
-
-    if (s->len ++ > 1) {
-#ifdef VERBOSE
-        printf("%s: message too long (%i bytes)\n", __FUNCTION__, s->len);
-#endif
-        return 1;
-    }
-
-    if (s->i2c_command_byte) {
-        s->command = data;
-        s->i2c_command_byte = 0;
-        return 0;
-    }
-
-    switch (s->command) {
-    case 0x01: /* Output port */
-        for (diff = (data ^ s->level) & ~s->direction; diff;
-                        diff &= ~(1 << line)) {
-            line = ffs(diff) - 1;
-            if (s->handler[line])
-                qemu_set_irq(s->handler[line], (data >> line) & 1);
-        }
-        s->level = (s->level & s->direction) | (data & ~s->direction);
-        break;
-
-    case 0x02: /* Polarity inversion */
-        s->polarity = data;
-        break;
-
-    case 0x03: /* Configuration */
-        s->level &= ~(s->direction ^ data);
-        s->direction = data;
-        break;
-
-    case 0x04: /* Timeout */
-        s->status = data;
-        break;
-
-    case 0x00: /* Input port - ignore writes */
-       break;
-    default:
-#ifdef VERBOSE
-        printf("%s: unknown register %02x\n", __FUNCTION__, s->command);
-#endif
-        return 1;
-    }
-
-    return 0;
-}
-
-static void max7310_event(I2CSlave *i2c, enum i2c_event event)
-{
-    MAX7310State *s = (MAX7310State *) i2c;
-    s->len = 0;
-
-    switch (event) {
-    case I2C_START_SEND:
-        s->i2c_command_byte = 1;
-        break;
-    case I2C_FINISH:
-#ifdef VERBOSE
-        if (s->len == 1)
-            printf("%s: message too short (%i bytes)\n", __FUNCTION__, s->len);
-#endif
-        break;
-    default:
-        break;
-    }
-}
-
-static const VMStateDescription vmstate_max7310 = {
-    .name = "max7310",
-    .version_id = 0,
-    .minimum_version_id = 0,
-    .minimum_version_id_old = 0,
-    .fields      = (VMStateField []) {
-        VMSTATE_INT32(i2c_command_byte, MAX7310State),
-        VMSTATE_INT32(len, MAX7310State),
-        VMSTATE_UINT8(level, MAX7310State),
-        VMSTATE_UINT8(direction, MAX7310State),
-        VMSTATE_UINT8(polarity, MAX7310State),
-        VMSTATE_UINT8(status, MAX7310State),
-        VMSTATE_UINT8(command, MAX7310State),
-        VMSTATE_I2C_SLAVE(i2c, MAX7310State),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void max7310_gpio_set(void *opaque, int line, int level)
-{
-    MAX7310State *s = (MAX7310State *) opaque;
-    if (line >= ARRAY_SIZE(s->handler) || line  < 0)
-        hw_error("bad GPIO line");
-
-    if (level)
-        s->level |= s->direction & (1 << line);
-    else
-        s->level &= ~(s->direction & (1 << line));
-}
-
-/* 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(I2CSlave *i2c)
-{
-    MAX7310State *s = FROM_I2C_SLAVE(MAX7310State, i2c);
-
-    qdev_init_gpio_in(&i2c->qdev, max7310_gpio_set, 8);
-    qdev_init_gpio_out(&i2c->qdev, s->handler, 8);
-
-    return 0;
-}
-
-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 const TypeInfo max7310_info = {
-    .name          = "max7310",
-    .parent        = TYPE_I2C_SLAVE,
-    .instance_size = sizeof(MAX7310State),
-    .class_init    = max7310_class_init,
-};
-
-static void max7310_register_types(void)
-{
-    type_register_static(&max7310_info);
-}
-
-type_init(max7310_register_types)
diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c
deleted file mode 100644 (file)
index a2119ad..0000000
+++ /dev/null
@@ -1,913 +0,0 @@
-/*
- * QEMU MC146818 RTC 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.
- */
-#include "hw/hw.h"
-#include "qemu/timer.h"
-#include "sysemu/sysemu.h"
-#include "hw/mc146818rtc.h"
-#include "qapi/visitor.h"
-
-#ifdef TARGET_I386
-#include "hw/apic.h"
-#endif
-
-//#define DEBUG_CMOS
-//#define DEBUG_COALESCED
-
-#ifdef DEBUG_CMOS
-# define CMOS_DPRINTF(format, ...)      printf(format, ## __VA_ARGS__)
-#else
-# define CMOS_DPRINTF(format, ...)      do { } while (0)
-#endif
-
-#ifdef DEBUG_COALESCED
-# define DPRINTF_C(format, ...)      printf(format, ## __VA_ARGS__)
-#else
-# define DPRINTF_C(format, ...)      do { } while (0)
-#endif
-
-#define NSEC_PER_SEC    1000000000LL
-#define SEC_PER_MIN     60
-#define MIN_PER_HOUR    60
-#define SEC_PER_HOUR    3600
-#define HOUR_PER_DAY    24
-#define SEC_PER_DAY     86400
-
-#define RTC_REINJECT_ON_ACK_COUNT 20
-#define RTC_CLOCK_RATE            32768
-#define UIP_HOLD_LENGTH           (8 * NSEC_PER_SEC / 32768)
-
-typedef struct RTCState {
-    ISADevice dev;
-    MemoryRegion io;
-    uint8_t cmos_data[128];
-    uint8_t cmos_index;
-    int32_t base_year;
-    uint64_t base_rtc;
-    uint64_t last_update;
-    int64_t offset;
-    qemu_irq irq;
-    qemu_irq sqw_irq;
-    int it_shift;
-    /* periodic timer */
-    QEMUTimer *periodic_timer;
-    int64_t next_periodic_time;
-    /* update-ended timer */
-    QEMUTimer *update_timer;
-    uint64_t next_alarm_time;
-    uint16_t irq_reinject_on_ack_count;
-    uint32_t irq_coalesced;
-    uint32_t period;
-    QEMUTimer *coalesced_timer;
-    Notifier clock_reset_notifier;
-    LostTickPolicy lost_tick_policy;
-    Notifier suspend_notifier;
-} RTCState;
-
-static void rtc_set_time(RTCState *s);
-static void rtc_update_time(RTCState *s);
-static void rtc_set_cmos(RTCState *s, const struct tm *tm);
-static inline int rtc_from_bcd(RTCState *s, int a);
-static uint64_t get_next_alarm(RTCState *s);
-
-static inline bool rtc_running(RTCState *s)
-{
-    return (!(s->cmos_data[RTC_REG_B] & REG_B_SET) &&
-            (s->cmos_data[RTC_REG_A] & 0x70) <= 0x20);
-}
-
-static uint64_t get_guest_rtc_ns(RTCState *s)
-{
-    uint64_t guest_rtc;
-    uint64_t guest_clock = qemu_get_clock_ns(rtc_clock);
-
-    guest_rtc = s->base_rtc * NSEC_PER_SEC
-                 + guest_clock - s->last_update + s->offset;
-    return guest_rtc;
-}
-
-#ifdef TARGET_I386
-static void rtc_coalesced_timer_update(RTCState *s)
-{
-    if (s->irq_coalesced == 0) {
-        qemu_del_timer(s->coalesced_timer);
-    } else {
-        /* divide each RTC interval to 2 - 8 smaller intervals */
-        int c = MIN(s->irq_coalesced, 7) + 1; 
-        int64_t next_clock = qemu_get_clock_ns(rtc_clock) +
-            muldiv64(s->period / c, get_ticks_per_sec(), RTC_CLOCK_RATE);
-        qemu_mod_timer(s->coalesced_timer, next_clock);
-    }
-}
-
-static void rtc_coalesced_timer(void *opaque)
-{
-    RTCState *s = opaque;
-
-    if (s->irq_coalesced != 0) {
-        apic_reset_irq_delivered();
-        s->cmos_data[RTC_REG_C] |= 0xc0;
-        DPRINTF_C("cmos: injecting from timer\n");
-        qemu_irq_raise(s->irq);
-        if (apic_get_irq_delivered()) {
-            s->irq_coalesced--;
-            DPRINTF_C("cmos: coalesced irqs decreased to %d\n",
-                      s->irq_coalesced);
-        }
-    }
-
-    rtc_coalesced_timer_update(s);
-}
-#endif
-
-/* handle periodic timer */
-static void periodic_timer_update(RTCState *s, int64_t current_time)
-{
-    int period_code, period;
-    int64_t cur_clock, next_irq_clock;
-
-    period_code = s->cmos_data[RTC_REG_A] & 0x0f;
-    if (period_code != 0
-        && ((s->cmos_data[RTC_REG_B] & REG_B_PIE)
-            || ((s->cmos_data[RTC_REG_B] & REG_B_SQWE) && s->sqw_irq))) {
-        if (period_code <= 2)
-            period_code += 7;
-        /* period in 32 Khz cycles */
-        period = 1 << (period_code - 1);
-#ifdef TARGET_I386
-        if (period != s->period) {
-            s->irq_coalesced = (s->irq_coalesced * s->period) / period;
-            DPRINTF_C("cmos: coalesced irqs scaled to %d\n", s->irq_coalesced);
-        }
-        s->period = period;
-#endif
-        /* compute 32 khz clock */
-        cur_clock = muldiv64(current_time, RTC_CLOCK_RATE, get_ticks_per_sec());
-        next_irq_clock = (cur_clock & ~(period - 1)) + period;
-        s->next_periodic_time =
-            muldiv64(next_irq_clock, get_ticks_per_sec(), RTC_CLOCK_RATE) + 1;
-        qemu_mod_timer(s->periodic_timer, s->next_periodic_time);
-    } else {
-#ifdef TARGET_I386
-        s->irq_coalesced = 0;
-#endif
-        qemu_del_timer(s->periodic_timer);
-    }
-}
-
-static void rtc_periodic_timer(void *opaque)
-{
-    RTCState *s = opaque;
-
-    periodic_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] |= REG_C_IRQF;
-#ifdef TARGET_I386
-        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();
-            qemu_irq_raise(s->irq);
-            if (!apic_get_irq_delivered()) {
-                s->irq_coalesced++;
-                rtc_coalesced_timer_update(s);
-                DPRINTF_C("cmos: coalesced irqs increased to %d\n",
-                          s->irq_coalesced);
-            }
-        } else
-#endif
-        qemu_irq_raise(s->irq);
-    }
-    if (s->cmos_data[RTC_REG_B] & REG_B_SQWE) {
-        /* Not square wave at all but we don't want 2048Hz interrupts!
-           Must be seen as a pulse.  */
-        qemu_irq_raise(s->sqw_irq);
-    }
-}
-
-/* handle update-ended timer */
-static void check_update_timer(RTCState *s)
-{
-    uint64_t next_update_time;
-    uint64_t guest_nsec;
-    int next_alarm_sec;
-
-    /* From the data sheet: "Holding the dividers in reset prevents
-     * interrupts from operating, while setting the SET bit allows"
-     * them to occur.  However, it will prevent an alarm interrupt
-     * from occurring, because the time of day is not updated.
-     */
-    if ((s->cmos_data[RTC_REG_A] & 0x60) == 0x60) {
-        qemu_del_timer(s->update_timer);
-        return;
-    }
-    if ((s->cmos_data[RTC_REG_C] & REG_C_UF) &&
-        (s->cmos_data[RTC_REG_B] & REG_B_SET)) {
-        qemu_del_timer(s->update_timer);
-        return;
-    }
-    if ((s->cmos_data[RTC_REG_C] & REG_C_UF) &&
-        (s->cmos_data[RTC_REG_C] & REG_C_AF)) {
-        qemu_del_timer(s->update_timer);
-        return;
-    }
-
-    guest_nsec = get_guest_rtc_ns(s) % NSEC_PER_SEC;
-    /* if UF is clear, reprogram to next second */
-    next_update_time = qemu_get_clock_ns(rtc_clock)
-        + NSEC_PER_SEC - guest_nsec;
-
-    /* Compute time of next alarm.  One second is already accounted
-     * for in next_update_time.
-     */
-    next_alarm_sec = get_next_alarm(s);
-    s->next_alarm_time = next_update_time + (next_alarm_sec - 1) * NSEC_PER_SEC;
-
-    if (s->cmos_data[RTC_REG_C] & REG_C_UF) {
-        /* UF is set, but AF is clear.  Program the timer to target
-         * the alarm time.  */
-        next_update_time = s->next_alarm_time;
-    }
-    if (next_update_time != qemu_timer_expire_time_ns(s->update_timer)) {
-        qemu_mod_timer(s->update_timer, next_update_time);
-    }
-}
-
-static inline uint8_t convert_hour(RTCState *s, uint8_t hour)
-{
-    if (!(s->cmos_data[RTC_REG_B] & REG_B_24H)) {
-        hour %= 12;
-        if (s->cmos_data[RTC_HOURS] & 0x80) {
-            hour += 12;
-        }
-    }
-    return hour;
-}
-
-static uint64_t get_next_alarm(RTCState *s)
-{
-    int32_t alarm_sec, alarm_min, alarm_hour, cur_hour, cur_min, cur_sec;
-    int32_t hour, min, sec;
-
-    rtc_update_time(s);
-
-    alarm_sec = rtc_from_bcd(s, s->cmos_data[RTC_SECONDS_ALARM]);
-    alarm_min = rtc_from_bcd(s, s->cmos_data[RTC_MINUTES_ALARM]);
-    alarm_hour = rtc_from_bcd(s, s->cmos_data[RTC_HOURS_ALARM]);
-    alarm_hour = alarm_hour == -1 ? -1 : convert_hour(s, alarm_hour);
-
-    cur_sec = rtc_from_bcd(s, s->cmos_data[RTC_SECONDS]);
-    cur_min = rtc_from_bcd(s, s->cmos_data[RTC_MINUTES]);
-    cur_hour = rtc_from_bcd(s, s->cmos_data[RTC_HOURS]);
-    cur_hour = convert_hour(s, cur_hour);
-
-    if (alarm_hour == -1) {
-        alarm_hour = cur_hour;
-        if (alarm_min == -1) {
-            alarm_min = cur_min;
-            if (alarm_sec == -1) {
-                alarm_sec = cur_sec + 1;
-            } else if (cur_sec > alarm_sec) {
-                alarm_min++;
-            }
-        } else if (cur_min == alarm_min) {
-            if (alarm_sec == -1) {
-                alarm_sec = cur_sec + 1;
-            } else {
-                if (cur_sec > alarm_sec) {
-                    alarm_hour++;
-                }
-            }
-            if (alarm_sec == SEC_PER_MIN) {
-                /* wrap to next hour, minutes is not in don't care mode */
-                alarm_sec = 0;
-                alarm_hour++;
-            }
-        } else if (cur_min > alarm_min) {
-            alarm_hour++;
-        }
-    } else if (cur_hour == alarm_hour) {
-        if (alarm_min == -1) {
-            alarm_min = cur_min;
-            if (alarm_sec == -1) {
-                alarm_sec = cur_sec + 1;
-            } else if (cur_sec > alarm_sec) {
-                alarm_min++;
-            }
-
-            if (alarm_sec == SEC_PER_MIN) {
-                alarm_sec = 0;
-                alarm_min++;
-            }
-            /* wrap to next day, hour is not in don't care mode */
-            alarm_min %= MIN_PER_HOUR;
-        } else if (cur_min == alarm_min) {
-            if (alarm_sec == -1) {
-                alarm_sec = cur_sec + 1;
-            }
-            /* wrap to next day, hours+minutes not in don't care mode */
-            alarm_sec %= SEC_PER_MIN;
-        }
-    }
-
-    /* values that are still don't care fire at the next min/sec */
-    if (alarm_min == -1) {
-        alarm_min = 0;
-    }
-    if (alarm_sec == -1) {
-        alarm_sec = 0;
-    }
-
-    /* keep values in range */
-    if (alarm_sec == SEC_PER_MIN) {
-        alarm_sec = 0;
-        alarm_min++;
-    }
-    if (alarm_min == MIN_PER_HOUR) {
-        alarm_min = 0;
-        alarm_hour++;
-    }
-    alarm_hour %= HOUR_PER_DAY;
-
-    hour = alarm_hour - cur_hour;
-    min = hour * MIN_PER_HOUR + alarm_min - cur_min;
-    sec = min * SEC_PER_MIN + alarm_sec - cur_sec;
-    return sec <= 0 ? sec + SEC_PER_DAY : sec;
-}
-
-static void rtc_update_timer(void *opaque)
-{
-    RTCState *s = opaque;
-    int32_t irqs = REG_C_UF;
-    int32_t new_irqs;
-
-    assert((s->cmos_data[RTC_REG_A] & 0x60) != 0x60);
-
-    /* UIP might have been latched, update time and clear it.  */
-    rtc_update_time(s);
-    s->cmos_data[RTC_REG_A] &= ~REG_A_UIP;
-
-    if (qemu_get_clock_ns(rtc_clock) >= s->next_alarm_time) {
-        irqs |= REG_C_AF;
-        if (s->cmos_data[RTC_REG_B] & REG_B_AIE) {
-            qemu_system_wakeup_request(QEMU_WAKEUP_REASON_RTC);
-        }
-    }
-
-    new_irqs = irqs & ~s->cmos_data[RTC_REG_C];
-    s->cmos_data[RTC_REG_C] |= irqs;
-    if ((new_irqs & s->cmos_data[RTC_REG_B]) != 0) {
-        s->cmos_data[RTC_REG_C] |= REG_C_IRQF;
-        qemu_irq_raise(s->irq);
-    }
-    check_update_timer(s);
-}
-
-static void cmos_ioport_write(void *opaque, hwaddr addr,
-                              uint64_t data, unsigned size)
-{
-    RTCState *s = opaque;
-
-    if ((addr & 1) == 0) {
-        s->cmos_index = data & 0x7f;
-    } else {
-        CMOS_DPRINTF("cmos: write index=0x%02x val=0x%02x\n",
-                     s->cmos_index, data);
-        switch(s->cmos_index) {
-        case RTC_SECONDS_ALARM:
-        case RTC_MINUTES_ALARM:
-        case RTC_HOURS_ALARM:
-            s->cmos_data[s->cmos_index] = data;
-            check_update_timer(s);
-            break;
-       case RTC_IBM_PS2_CENTURY_BYTE:
-            s->cmos_index = RTC_CENTURY;
-            /* fall through */
-        case RTC_CENTURY:
-        case RTC_SECONDS:
-        case RTC_MINUTES:
-        case RTC_HOURS:
-        case RTC_DAY_OF_WEEK:
-        case RTC_DAY_OF_MONTH:
-        case RTC_MONTH:
-        case RTC_YEAR:
-            s->cmos_data[s->cmos_index] = data;
-            /* if in set mode, do not update the time */
-            if (rtc_running(s)) {
-                rtc_set_time(s);
-                check_update_timer(s);
-            }
-            break;
-        case RTC_REG_A:
-            if ((data & 0x60) == 0x60) {
-                if (rtc_running(s)) {
-                    rtc_update_time(s);
-                }
-                /* What happens to UIP when divider reset is enabled is
-                 * unclear from the datasheet.  Shouldn't matter much
-                 * though.
-                 */
-                s->cmos_data[RTC_REG_A] &= ~REG_A_UIP;
-            } else if (((s->cmos_data[RTC_REG_A] & 0x60) == 0x60) &&
-                    (data & 0x70)  <= 0x20) {
-                /* when the divider reset is removed, the first update cycle
-                 * begins one-half second later*/
-                if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) {
-                    s->offset = 500000000;
-                    rtc_set_time(s);
-                }
-                s->cmos_data[RTC_REG_A] &= ~REG_A_UIP;
-            }
-            /* UIP bit is read only */
-            s->cmos_data[RTC_REG_A] = (data & ~REG_A_UIP) |
-                (s->cmos_data[RTC_REG_A] & REG_A_UIP);
-            periodic_timer_update(s, qemu_get_clock_ns(rtc_clock));
-            check_update_timer(s);
-            break;
-        case RTC_REG_B:
-            if (data & REG_B_SET) {
-                /* update cmos to when the rtc was stopping */
-                if (rtc_running(s)) {
-                    rtc_update_time(s);
-                }
-                /* set mode: reset UIP mode */
-                s->cmos_data[RTC_REG_A] &= ~REG_A_UIP;
-                data &= ~REG_B_UIE;
-            } else {
-                /* if disabling set mode, update the time */
-                if ((s->cmos_data[RTC_REG_B] & REG_B_SET) &&
-                    (s->cmos_data[RTC_REG_A] & 0x70) <= 0x20) {
-                    s->offset = get_guest_rtc_ns(s) % NSEC_PER_SEC;
-                    rtc_set_time(s);
-                }
-            }
-            /* if an interrupt flag is already set when the interrupt
-             * becomes enabled, raise an interrupt immediately.  */
-            if (data & s->cmos_data[RTC_REG_C] & REG_C_MASK) {
-                s->cmos_data[RTC_REG_C] |= REG_C_IRQF;
-                qemu_irq_raise(s->irq);
-            } else {
-                s->cmos_data[RTC_REG_C] &= ~REG_C_IRQF;
-                qemu_irq_lower(s->irq);
-            }
-            s->cmos_data[RTC_REG_B] = data;
-            periodic_timer_update(s, qemu_get_clock_ns(rtc_clock));
-            check_update_timer(s);
-            break;
-        case RTC_REG_C:
-        case RTC_REG_D:
-            /* cannot write to them */
-            break;
-        default:
-            s->cmos_data[s->cmos_index] = data;
-            break;
-        }
-    }
-}
-
-static inline int rtc_to_bcd(RTCState *s, int a)
-{
-    if (s->cmos_data[RTC_REG_B] & REG_B_DM) {
-        return a;
-    } else {
-        return ((a / 10) << 4) | (a % 10);
-    }
-}
-
-static inline int rtc_from_bcd(RTCState *s, int a)
-{
-    if ((a & 0xc0) == 0xc0) {
-        return -1;
-    }
-    if (s->cmos_data[RTC_REG_B] & REG_B_DM) {
-        return a;
-    } else {
-        return ((a >> 4) * 10) + (a & 0x0f);
-    }
-}
-
-static void rtc_get_time(RTCState *s, struct tm *tm)
-{
-    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)) {
-        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]);
-    tm->tm_mon = rtc_from_bcd(s, s->cmos_data[RTC_MONTH]) - 1;
-    tm->tm_year =
-        rtc_from_bcd(s, s->cmos_data[RTC_YEAR]) + s->base_year +
-        rtc_from_bcd(s, s->cmos_data[RTC_CENTURY]) * 100 - 1900;
-}
-
-static void rtc_set_time(RTCState *s)
-{
-    struct tm tm;
-
-    rtc_get_time(s, &tm);
-    s->base_rtc = mktimegm(&tm);
-    s->last_update = qemu_get_clock_ns(rtc_clock);
-
-    rtc_change_mon_event(&tm);
-}
-
-static void rtc_set_cmos(RTCState *s, const struct tm *tm)
-{
-    int year;
-
-    s->cmos_data[RTC_SECONDS] = rtc_to_bcd(s, tm->tm_sec);
-    s->cmos_data[RTC_MINUTES] = rtc_to_bcd(s, tm->tm_min);
-    if (s->cmos_data[RTC_REG_B] & REG_B_24H) {
-        /* 24 hour format */
-        s->cmos_data[RTC_HOURS] = rtc_to_bcd(s, tm->tm_hour);
-    } else {
-        /* 12 hour format */
-        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;
-    }
-    s->cmos_data[RTC_DAY_OF_WEEK] = rtc_to_bcd(s, tm->tm_wday + 1);
-    s->cmos_data[RTC_DAY_OF_MONTH] = rtc_to_bcd(s, tm->tm_mday);
-    s->cmos_data[RTC_MONTH] = rtc_to_bcd(s, tm->tm_mon + 1);
-    year = tm->tm_year + 1900 - s->base_year;
-    s->cmos_data[RTC_YEAR] = rtc_to_bcd(s, year % 100);
-    s->cmos_data[RTC_CENTURY] = rtc_to_bcd(s, year / 100);
-}
-
-static void rtc_update_time(RTCState *s)
-{
-    struct tm ret;
-    time_t guest_sec;
-    int64_t guest_nsec;
-
-    guest_nsec = get_guest_rtc_ns(s);
-    guest_sec = guest_nsec / NSEC_PER_SEC;
-    gmtime_r(&guest_sec, &ret);
-
-    /* Is SET flag of Register B disabled? */
-    if ((s->cmos_data[RTC_REG_B] & REG_B_SET) == 0) {
-        rtc_set_cmos(s, &ret);
-    }
-}
-
-static int update_in_progress(RTCState *s)
-{
-    int64_t guest_nsec;
-
-    if (!rtc_running(s)) {
-        return 0;
-    }
-    if (qemu_timer_pending(s->update_timer)) {
-        int64_t next_update_time = qemu_timer_expire_time_ns(s->update_timer);
-        /* Latch UIP until the timer expires.  */
-        if (qemu_get_clock_ns(rtc_clock) >= (next_update_time - UIP_HOLD_LENGTH)) {
-            s->cmos_data[RTC_REG_A] |= REG_A_UIP;
-            return 1;
-        }
-    }
-
-    guest_nsec = get_guest_rtc_ns(s);
-    /* UIP bit will be set at last 244us of every second. */
-    if ((guest_nsec % NSEC_PER_SEC) >= (NSEC_PER_SEC - UIP_HOLD_LENGTH)) {
-        return 1;
-    }
-    return 0;
-}
-
-static uint64_t cmos_ioport_read(void *opaque, hwaddr addr,
-                                 unsigned size)
-{
-    RTCState *s = opaque;
-    int ret;
-    if ((addr & 1) == 0) {
-        return 0xff;
-    } else {
-        switch(s->cmos_index) {
-       case RTC_IBM_PS2_CENTURY_BYTE:
-            s->cmos_index = RTC_CENTURY;
-            /* fall through */
-        case RTC_CENTURY:
-        case RTC_SECONDS:
-        case RTC_MINUTES:
-        case RTC_HOURS:
-        case RTC_DAY_OF_WEEK:
-        case RTC_DAY_OF_MONTH:
-        case RTC_MONTH:
-        case RTC_YEAR:
-            /* if not in set mode, calibrate cmos before
-             * reading*/
-            if (rtc_running(s)) {
-                rtc_update_time(s);
-            }
-            ret = s->cmos_data[s->cmos_index];
-            break;
-        case RTC_REG_A:
-            if (update_in_progress(s)) {
-                s->cmos_data[s->cmos_index] |= REG_A_UIP;
-            } else {
-                s->cmos_data[s->cmos_index] &= ~REG_A_UIP;
-            }
-            ret = s->cmos_data[s->cmos_index];
-            break;
-        case RTC_REG_C:
-            ret = s->cmos_data[s->cmos_index];
-            qemu_irq_lower(s->irq);
-            s->cmos_data[RTC_REG_C] = 0x00;
-            if (ret & (REG_C_UF | REG_C_AF)) {
-                check_update_timer(s);
-            }
-#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);
-                if (apic_get_irq_delivered()) {
-                    s->irq_coalesced--;
-                    DPRINTF_C("cmos: coalesced irqs decreased to %d\n",
-                              s->irq_coalesced);
-                }
-            }
-#endif
-            break;
-        default:
-            ret = s->cmos_data[s->cmos_index];
-            break;
-        }
-        CMOS_DPRINTF("cmos: read index=0x%02x val=0x%02x\n",
-                     s->cmos_index, ret);
-        return ret;
-    }
-}
-
-void rtc_set_memory(ISADevice *dev, int addr, int val)
-{
-    RTCState *s = DO_UPCAST(RTCState, dev, dev);
-    if (addr >= 0 && addr <= 127)
-        s->cmos_data[addr] = val;
-}
-
-static void rtc_set_date_from_host(ISADevice *dev)
-{
-    RTCState *s = DO_UPCAST(RTCState, dev, dev);
-    struct tm tm;
-
-    qemu_get_timedate(&tm, 0);
-
-    s->base_rtc = mktimegm(&tm);
-    s->last_update = qemu_get_clock_ns(rtc_clock);
-    s->offset = 0;
-
-    /* set the CMOS date */
-    rtc_set_cmos(s, &tm);
-}
-
-static int rtc_post_load(void *opaque, int version_id)
-{
-    RTCState *s = opaque;
-
-    if (version_id <= 2) {
-        rtc_set_time(s);
-        s->offset = 0;
-        check_update_timer(s);
-    }
-
-#ifdef TARGET_I386
-    if (version_id >= 2) {
-        if (s->lost_tick_policy == LOST_TICK_SLEW) {
-            rtc_coalesced_timer_update(s);
-        }
-    }
-#endif
-    return 0;
-}
-
-static const VMStateDescription vmstate_rtc = {
-    .name = "mc146818rtc",
-    .version_id = 3,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .post_load = rtc_post_load,
-    .fields      = (VMStateField []) {
-        VMSTATE_BUFFER(cmos_data, RTCState),
-        VMSTATE_UINT8(cmos_index, RTCState),
-        VMSTATE_UNUSED(7*4),
-        VMSTATE_TIMER(periodic_timer, RTCState),
-        VMSTATE_INT64(next_periodic_time, RTCState),
-        VMSTATE_UNUSED(3*8),
-        VMSTATE_UINT32_V(irq_coalesced, RTCState, 2),
-        VMSTATE_UINT32_V(period, RTCState, 2),
-        VMSTATE_UINT64_V(base_rtc, RTCState, 3),
-        VMSTATE_UINT64_V(last_update, RTCState, 3),
-        VMSTATE_INT64_V(offset, RTCState, 3),
-        VMSTATE_TIMER_V(update_timer, RTCState, 3),
-        VMSTATE_UINT64_V(next_alarm_time, RTCState, 3),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void rtc_notify_clock_reset(Notifier *notifier, void *data)
-{
-    RTCState *s = container_of(notifier, RTCState, clock_reset_notifier);
-    int64_t now = *(int64_t *)data;
-
-    rtc_set_date_from_host(&s->dev);
-    periodic_timer_update(s, now);
-    check_update_timer(s);
-#ifdef TARGET_I386
-    if (s->lost_tick_policy == LOST_TICK_SLEW) {
-        rtc_coalesced_timer_update(s);
-    }
-#endif
-}
-
-/* set CMOS shutdown status register (index 0xF) as S3_resume(0xFE)
-   BIOS will read it and start S3 resume at POST Entry */
-static void rtc_notify_suspend(Notifier *notifier, void *data)
-{
-    RTCState *s = container_of(notifier, RTCState, suspend_notifier);
-    rtc_set_memory(&s->dev, 0xF, 0xFE);
-}
-
-static void rtc_reset(void *opaque)
-{
-    RTCState *s = opaque;
-
-    s->cmos_data[RTC_REG_B] &= ~(REG_B_PIE | REG_B_AIE | REG_B_SQWE);
-    s->cmos_data[RTC_REG_C] &= ~(REG_C_UF | REG_C_IRQF | REG_C_PF | REG_C_AF);
-    check_update_timer(s);
-
-    qemu_irq_lower(s->irq);
-
-#ifdef TARGET_I386
-    if (s->lost_tick_policy == LOST_TICK_SLEW) {
-        s->irq_coalesced = 0;
-    }
-#endif
-}
-
-static const MemoryRegionOps cmos_ops = {
-    .read = cmos_ioport_read,
-    .write = cmos_ioport_write,
-    .impl = {
-        .min_access_size = 1,
-        .max_access_size = 1,
-    },
-    .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static void rtc_get_date(Object *obj, Visitor *v, void *opaque,
-                         const char *name, Error **errp)
-{
-    ISADevice *isa = ISA_DEVICE(obj);
-    RTCState *s = DO_UPCAST(RTCState, dev, isa);
-    struct tm current_tm;
-
-    rtc_update_time(s);
-    rtc_get_time(s, &current_tm);
-    visit_start_struct(v, NULL, "struct tm", name, 0, errp);
-    visit_type_int32(v, &current_tm.tm_year, "tm_year", errp);
-    visit_type_int32(v, &current_tm.tm_mon, "tm_mon", errp);
-    visit_type_int32(v, &current_tm.tm_mday, "tm_mday", errp);
-    visit_type_int32(v, &current_tm.tm_hour, "tm_hour", errp);
-    visit_type_int32(v, &current_tm.tm_min, "tm_min", errp);
-    visit_type_int32(v, &current_tm.tm_sec, "tm_sec", errp);
-    visit_end_struct(v, errp);
-}
-
-static int rtc_initfn(ISADevice *dev)
-{
-    RTCState *s = DO_UPCAST(RTCState, dev, dev);
-    int base = 0x70;
-
-    s->cmos_data[RTC_REG_A] = 0x26;
-    s->cmos_data[RTC_REG_B] = 0x02;
-    s->cmos_data[RTC_REG_C] = 0x00;
-    s->cmos_data[RTC_REG_D] = 0x80;
-
-    /* This is for historical reasons.  The default base year qdev property
-     * was set to 2000 for most machine types before the century byte was
-     * implemented.
-     *
-     * This if statement means that the century byte will be always 0
-     * (at least until 2079...) for base_year = 1980, but will be set
-     * correctly for base_year = 2000.
-     */
-    if (s->base_year == 2000) {
-        s->base_year = 0;
-    }
-
-    rtc_set_date_from_host(dev);
-
-#ifdef TARGET_I386
-    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->update_timer = qemu_new_timer_ns(rtc_clock, rtc_update_timer, s);
-    check_update_timer(s);
-
-    s->clock_reset_notifier.notify = rtc_notify_clock_reset;
-    qemu_register_clock_reset_notifier(rtc_clock, &s->clock_reset_notifier);
-
-    s->suspend_notifier.notify = rtc_notify_suspend;
-    qemu_register_suspend_notifier(&s->suspend_notifier);
-
-    memory_region_init_io(&s->io, &cmos_ops, s, "rtc", 2);
-    isa_register_ioport(dev, &s->io, base);
-
-    qdev_set_legacy_instance_id(&dev->qdev, base, 3);
-    qemu_register_reset(rtc_reset, s);
-
-    object_property_add(OBJECT(s), "date", "struct tm",
-                        rtc_get_date, NULL, NULL, s, NULL);
-
-    return 0;
-}
-
-ISADevice *rtc_init(ISABus *bus, int base_year, qemu_irq intercept_irq)
-{
-    ISADevice *dev;
-    RTCState *s;
-
-    dev = isa_create(bus, "mc146818rtc");
-    s = DO_UPCAST(RTCState, dev, dev);
-    qdev_prop_set_int32(&dev->qdev, "base_year", base_year);
-    qdev_init_nofail(&dev->qdev);
-    if (intercept_irq) {
-        s->irq = intercept_irq;
-    } else {
-        isa_init_irq(dev, &s->irq, RTC_ISA_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 const TypeInfo mc146818rtc_info = {
-    .name          = "mc146818rtc",
-    .parent        = TYPE_ISA_DEVICE,
-    .instance_size = sizeof(RTCState),
-    .class_init    = rtc_class_initfn,
-};
-
-static void mc146818rtc_register_types(void)
-{
-    type_register_static(&mc146818rtc_info);
-}
-
-type_init(mc146818rtc_register_types)
diff --git a/hw/mc146818rtc.h b/hw/mc146818rtc.h
deleted file mode 100644 (file)
index 967403e..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-#ifndef MC146818RTC_H
-#define MC146818RTC_H
-
-#include "hw/isa.h"
-#include "hw/mc146818rtc_regs.h"
-
-ISADevice *rtc_init(ISABus *bus, int base_year, qemu_irq intercept_irq);
-void rtc_set_memory(ISADevice *dev, int addr, int val);
-void rtc_set_date(ISADevice *dev, const struct tm *tm);
-
-#endif /* !MC146818RTC_H */
diff --git a/hw/mc146818rtc_regs.h b/hw/mc146818rtc_regs.h
deleted file mode 100644 (file)
index ccdee42..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * QEMU MC146818 RTC 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 RTC_REGS_H
-#define RTC_REGS_H
-
-#define RTC_ISA_IRQ 8
-
-#define RTC_SECONDS             0
-#define RTC_SECONDS_ALARM       1
-#define RTC_MINUTES             2
-#define RTC_MINUTES_ALARM       3
-#define RTC_HOURS               4
-#define RTC_HOURS_ALARM         5
-#define RTC_ALARM_DONT_CARE    0xC0
-
-#define RTC_DAY_OF_WEEK         6
-#define RTC_DAY_OF_MONTH        7
-#define RTC_MONTH               8
-#define RTC_YEAR                9
-
-#define RTC_REG_A               10
-#define RTC_REG_B               11
-#define RTC_REG_C               12
-#define RTC_REG_D               13
-
-/* PC cmos mappings */
-#define RTC_CENTURY              0x32
-#define RTC_IBM_PS2_CENTURY_BYTE 0x37
-
-#define REG_A_UIP 0x80
-
-#define REG_B_SET  0x80
-#define REG_B_PIE  0x40
-#define REG_B_AIE  0x20
-#define REG_B_UIE  0x10
-#define REG_B_SQWE 0x08
-#define REG_B_DM   0x04
-#define REG_B_24H  0x02
-
-#define REG_C_UF   0x10
-#define REG_C_IRQF 0x80
-#define REG_C_PF   0x40
-#define REG_C_AF   0x20
-#define REG_C_MASK 0x70
-
-#endif
diff --git a/hw/mcf.h b/hw/mcf.h
deleted file mode 100644 (file)
index fbc8dc2..0000000
--- a/hw/mcf.h
+++ /dev/null
@@ -1,30 +0,0 @@
-#ifndef HW_MCF_H
-#define HW_MCF_H
-/* Motorola ColdFire device prototypes.  */
-
-struct MemoryRegion;
-
-/* mcf_uart.c */
-uint64_t mcf_uart_read(void *opaque, hwaddr addr,
-                       unsigned size);
-void mcf_uart_write(void *opaque, hwaddr addr,
-                    uint64_t val, unsigned size);
-void *mcf_uart_init(qemu_irq irq, CharDriverState *chr);
-void mcf_uart_mm_init(struct MemoryRegion *sysmem,
-                      hwaddr base,
-                      qemu_irq irq, CharDriverState *chr);
-
-/* mcf_intc.c */
-qemu_irq *mcf_intc_init(struct MemoryRegion *sysmem,
-                        hwaddr base,
-                        M68kCPU *cpu);
-
-/* mcf_fec.c */
-void mcf_fec_init(struct MemoryRegion *sysmem, NICInfo *nd,
-                  hwaddr base, qemu_irq *irq);
-
-/* mcf5206.c */
-qemu_irq *mcf5206_init(struct MemoryRegion *sysmem,
-                       uint32_t base, M68kCPU *cpu);
-
-#endif
diff --git a/hw/mcf_fec.c b/hw/mcf_fec.c
deleted file mode 100644 (file)
index 0227bd8..0000000
+++ /dev/null
@@ -1,480 +0,0 @@
-/*
- * ColdFire Fast Ethernet Controller emulation.
- *
- * Copyright (c) 2007 CodeSourcery.
- *
- * This code is licensed under the GPL
- */
-#include "hw/hw.h"
-#include "net/net.h"
-#include "hw/mcf.h"
-/* For crc32 */
-#include <zlib.h>
-#include "exec/address-spaces.h"
-
-//#define DEBUG_FEC 1
-
-#ifdef DEBUG_FEC
-#define DPRINTF(fmt, ...) \
-do { printf("mcf_fec: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...) do {} while(0)
-#endif
-
-#define FEC_MAX_FRAME_SIZE 2032
-
-typedef struct {
-    MemoryRegion *sysmem;
-    MemoryRegion iomem;
-    qemu_irq *irq;
-    NICState *nic;
-    NICConf conf;
-    uint32_t irq_state;
-    uint32_t eir;
-    uint32_t eimr;
-    int rx_enabled;
-    uint32_t rx_descriptor;
-    uint32_t tx_descriptor;
-    uint32_t ecr;
-    uint32_t mmfr;
-    uint32_t mscr;
-    uint32_t rcr;
-    uint32_t tcr;
-    uint32_t tfwr;
-    uint32_t rfsr;
-    uint32_t erdsr;
-    uint32_t etdsr;
-    uint32_t emrbr;
-} mcf_fec_state;
-
-#define FEC_INT_HB   0x80000000
-#define FEC_INT_BABR 0x40000000
-#define FEC_INT_BABT 0x20000000
-#define FEC_INT_GRA  0x10000000
-#define FEC_INT_TXF  0x08000000
-#define FEC_INT_TXB  0x04000000
-#define FEC_INT_RXF  0x02000000
-#define FEC_INT_RXB  0x01000000
-#define FEC_INT_MII  0x00800000
-#define FEC_INT_EB   0x00400000
-#define FEC_INT_LC   0x00200000
-#define FEC_INT_RL   0x00100000
-#define FEC_INT_UN   0x00080000
-
-#define FEC_EN      2
-#define FEC_RESET   1
-
-/* Map interrupt flags onto IRQ lines.  */
-#define FEC_NUM_IRQ 13
-static const uint32_t mcf_fec_irq_map[FEC_NUM_IRQ] = {
-    FEC_INT_TXF,
-    FEC_INT_TXB,
-    FEC_INT_UN,
-    FEC_INT_RL,
-    FEC_INT_RXF,
-    FEC_INT_RXB,
-    FEC_INT_MII,
-    FEC_INT_LC,
-    FEC_INT_HB,
-    FEC_INT_GRA,
-    FEC_INT_EB,
-    FEC_INT_BABT,
-    FEC_INT_BABR
-};
-
-/* Buffer Descriptor.  */
-typedef struct {
-    uint16_t flags;
-    uint16_t length;
-    uint32_t data;
-} mcf_fec_bd;
-
-#define FEC_BD_R    0x8000
-#define FEC_BD_E    0x8000
-#define FEC_BD_O1   0x4000
-#define FEC_BD_W    0x2000
-#define FEC_BD_O2   0x1000
-#define FEC_BD_L    0x0800
-#define FEC_BD_TC   0x0400
-#define FEC_BD_ABC  0x0200
-#define FEC_BD_M    0x0100
-#define FEC_BD_BC   0x0080
-#define FEC_BD_MC   0x0040
-#define FEC_BD_LG   0x0020
-#define FEC_BD_NO   0x0010
-#define FEC_BD_CR   0x0004
-#define FEC_BD_OV   0x0002
-#define FEC_BD_TR   0x0001
-
-static void mcf_fec_read_bd(mcf_fec_bd *bd, uint32_t addr)
-{
-    cpu_physical_memory_read(addr, (uint8_t *)bd, sizeof(*bd));
-    be16_to_cpus(&bd->flags);
-    be16_to_cpus(&bd->length);
-    be32_to_cpus(&bd->data);
-}
-
-static void mcf_fec_write_bd(mcf_fec_bd *bd, uint32_t addr)
-{
-    mcf_fec_bd tmp;
-    tmp.flags = cpu_to_be16(bd->flags);
-    tmp.length = cpu_to_be16(bd->length);
-    tmp.data = cpu_to_be32(bd->data);
-    cpu_physical_memory_write(addr, (uint8_t *)&tmp, sizeof(tmp));
-}
-
-static void mcf_fec_update(mcf_fec_state *s)
-{
-    uint32_t active;
-    uint32_t changed;
-    uint32_t mask;
-    int i;
-
-    active = s->eir & s->eimr;
-    changed = active ^s->irq_state;
-    for (i = 0; i < FEC_NUM_IRQ; i++) {
-        mask = mcf_fec_irq_map[i];
-        if (changed & mask) {
-            DPRINTF("IRQ %d = %d\n", i, (active & mask) != 0);
-            qemu_set_irq(s->irq[i], (active & mask) != 0);
-        }
-    }
-    s->irq_state = active;
-}
-
-static void mcf_fec_do_tx(mcf_fec_state *s)
-{
-    uint32_t addr;
-    mcf_fec_bd bd;
-    int frame_size;
-    int len;
-    uint8_t frame[FEC_MAX_FRAME_SIZE];
-    uint8_t *ptr;
-
-    DPRINTF("do_tx\n");
-    ptr = frame;
-    frame_size = 0;
-    addr = s->tx_descriptor;
-    while (1) {
-        mcf_fec_read_bd(&bd, addr);
-        DPRINTF("tx_bd %x flags %04x len %d data %08x\n",
-                addr, bd.flags, bd.length, bd.data);
-        if ((bd.flags & FEC_BD_R) == 0) {
-            /* Run out of descriptors to transmit.  */
-            break;
-        }
-        len = bd.length;
-        if (frame_size + len > FEC_MAX_FRAME_SIZE) {
-            len = FEC_MAX_FRAME_SIZE - frame_size;
-            s->eir |= FEC_INT_BABT;
-        }
-        cpu_physical_memory_read(bd.data, ptr, len);
-        ptr += len;
-        frame_size += len;
-        if (bd.flags & FEC_BD_L) {
-            /* Last buffer in frame.  */
-            DPRINTF("Sending packet\n");
-            qemu_send_packet(qemu_get_queue(s->nic), frame, len);
-            ptr = frame;
-            frame_size = 0;
-            s->eir |= FEC_INT_TXF;
-        }
-        s->eir |= FEC_INT_TXB;
-        bd.flags &= ~FEC_BD_R;
-        /* Write back the modified descriptor.  */
-        mcf_fec_write_bd(&bd, addr);
-        /* Advance to the next descriptor.  */
-        if ((bd.flags & FEC_BD_W) != 0) {
-            addr = s->etdsr;
-        } else {
-            addr += 8;
-        }
-    }
-    s->tx_descriptor = addr;
-}
-
-static void mcf_fec_enable_rx(mcf_fec_state *s)
-{
-    mcf_fec_bd bd;
-
-    mcf_fec_read_bd(&bd, s->rx_descriptor);
-    s->rx_enabled = ((bd.flags & FEC_BD_E) != 0);
-    if (!s->rx_enabled)
-        DPRINTF("RX buffer full\n");
-}
-
-static void mcf_fec_reset(mcf_fec_state *s)
-{
-    s->eir = 0;
-    s->eimr = 0;
-    s->rx_enabled = 0;
-    s->ecr = 0;
-    s->mscr = 0;
-    s->rcr = 0x05ee0001;
-    s->tcr = 0;
-    s->tfwr = 0;
-    s->rfsr = 0x500;
-}
-
-static uint64_t mcf_fec_read(void *opaque, hwaddr addr,
-                             unsigned size)
-{
-    mcf_fec_state *s = (mcf_fec_state *)opaque;
-    switch (addr & 0x3ff) {
-    case 0x004: return s->eir;
-    case 0x008: return s->eimr;
-    case 0x010: return s->rx_enabled ? (1 << 24) : 0; /* RDAR */
-    case 0x014: return 0; /* TDAR */
-    case 0x024: return s->ecr;
-    case 0x040: return s->mmfr;
-    case 0x044: return s->mscr;
-    case 0x064: return 0; /* MIBC */
-    case 0x084: return s->rcr;
-    case 0x0c4: return s->tcr;
-    case 0x0e4: /* PALR */
-        return (s->conf.macaddr.a[0] << 24) | (s->conf.macaddr.a[1] << 16)
-              | (s->conf.macaddr.a[2] << 8) | s->conf.macaddr.a[3];
-        break;
-    case 0x0e8: /* PAUR */
-        return (s->conf.macaddr.a[4] << 24) | (s->conf.macaddr.a[5] << 16) | 0x8808;
-    case 0x0ec: return 0x10000; /* OPD */
-    case 0x118: return 0;
-    case 0x11c: return 0;
-    case 0x120: return 0;
-    case 0x124: return 0;
-    case 0x144: return s->tfwr;
-    case 0x14c: return 0x600;
-    case 0x150: return s->rfsr;
-    case 0x180: return s->erdsr;
-    case 0x184: return s->etdsr;
-    case 0x188: return s->emrbr;
-    default:
-        hw_error("mcf_fec_read: Bad address 0x%x\n", (int)addr);
-        return 0;
-    }
-}
-
-static void mcf_fec_write(void *opaque, hwaddr addr,
-                          uint64_t value, unsigned size)
-{
-    mcf_fec_state *s = (mcf_fec_state *)opaque;
-    switch (addr & 0x3ff) {
-    case 0x004:
-        s->eir &= ~value;
-        break;
-    case 0x008:
-        s->eimr = value;
-        break;
-    case 0x010: /* RDAR */
-        if ((s->ecr & FEC_EN) && !s->rx_enabled) {
-            DPRINTF("RX enable\n");
-            mcf_fec_enable_rx(s);
-        }
-        break;
-    case 0x014: /* TDAR */
-        if (s->ecr & FEC_EN) {
-            mcf_fec_do_tx(s);
-        }
-        break;
-    case 0x024:
-        s->ecr = value;
-        if (value & FEC_RESET) {
-            DPRINTF("Reset\n");
-            mcf_fec_reset(s);
-        }
-        if ((s->ecr & FEC_EN) == 0) {
-            s->rx_enabled = 0;
-        }
-        break;
-    case 0x040:
-        /* TODO: Implement MII.  */
-        s->mmfr = value;
-        break;
-    case 0x044:
-        s->mscr = value & 0xfe;
-        break;
-    case 0x064:
-        /* TODO: Implement MIB.  */
-        break;
-    case 0x084:
-        s->rcr = value & 0x07ff003f;
-        /* TODO: Implement LOOP mode.  */
-        break;
-    case 0x0c4: /* TCR */
-        /* We transmit immediately, so raise GRA immediately.  */
-        s->tcr = value;
-        if (value & 1)
-            s->eir |= FEC_INT_GRA;
-        break;
-    case 0x0e4: /* PALR */
-        s->conf.macaddr.a[0] = value >> 24;
-        s->conf.macaddr.a[1] = value >> 16;
-        s->conf.macaddr.a[2] = value >> 8;
-        s->conf.macaddr.a[3] = value;
-        break;
-    case 0x0e8: /* PAUR */
-        s->conf.macaddr.a[4] = value >> 24;
-        s->conf.macaddr.a[5] = value >> 16;
-        break;
-    case 0x0ec:
-        /* OPD */
-        break;
-    case 0x118:
-    case 0x11c:
-    case 0x120:
-    case 0x124:
-        /* TODO: implement MAC hash filtering.  */
-        break;
-    case 0x144:
-        s->tfwr = value & 3;
-        break;
-    case 0x14c:
-        /* FRBR writes ignored.  */
-        break;
-    case 0x150:
-        s->rfsr = (value & 0x3fc) | 0x400;
-        break;
-    case 0x180:
-        s->erdsr = value & ~3;
-        s->rx_descriptor = s->erdsr;
-        break;
-    case 0x184:
-        s->etdsr = value & ~3;
-        s->tx_descriptor = s->etdsr;
-        break;
-    case 0x188:
-        s->emrbr = value & 0x7f0;
-        break;
-    default:
-        hw_error("mcf_fec_write Bad address 0x%x\n", (int)addr);
-    }
-    mcf_fec_update(s);
-}
-
-static int mcf_fec_can_receive(NetClientState *nc)
-{
-    mcf_fec_state *s = qemu_get_nic_opaque(nc);
-    return s->rx_enabled;
-}
-
-static ssize_t mcf_fec_receive(NetClientState *nc, const uint8_t *buf, size_t size)
-{
-    mcf_fec_state *s = qemu_get_nic_opaque(nc);
-    mcf_fec_bd bd;
-    uint32_t flags = 0;
-    uint32_t addr;
-    uint32_t crc;
-    uint32_t buf_addr;
-    uint8_t *crc_ptr;
-    unsigned int buf_len;
-
-    DPRINTF("do_rx len %d\n", size);
-    if (!s->rx_enabled) {
-        fprintf(stderr, "mcf_fec_receive: Unexpected packet\n");
-    }
-    /* 4 bytes for the CRC.  */
-    size += 4;
-    crc = cpu_to_be32(crc32(~0, buf, size));
-    crc_ptr = (uint8_t *)&crc;
-    /* Huge frames are truncted.  */
-    if (size > FEC_MAX_FRAME_SIZE) {
-        size = FEC_MAX_FRAME_SIZE;
-        flags |= FEC_BD_TR | FEC_BD_LG;
-    }
-    /* Frames larger than the user limit just set error flags.  */
-    if (size > (s->rcr >> 16)) {
-        flags |= FEC_BD_LG;
-    }
-    addr = s->rx_descriptor;
-    while (size > 0) {
-        mcf_fec_read_bd(&bd, addr);
-        if ((bd.flags & FEC_BD_E) == 0) {
-            /* No descriptors available.  Bail out.  */
-            /* FIXME: This is wrong.  We should probably either save the
-               remainder for when more RX buffers are available, or
-               flag an error.  */
-            fprintf(stderr, "mcf_fec: Lost end of frame\n");
-            break;
-        }
-        buf_len = (size <= s->emrbr) ? size: s->emrbr;
-        bd.length = buf_len;
-        size -= buf_len;
-        DPRINTF("rx_bd %x length %d\n", addr, bd.length);
-        /* The last 4 bytes are the CRC.  */
-        if (size < 4)
-            buf_len += size - 4;
-        buf_addr = bd.data;
-        cpu_physical_memory_write(buf_addr, buf, buf_len);
-        buf += buf_len;
-        if (size < 4) {
-            cpu_physical_memory_write(buf_addr + buf_len, crc_ptr, 4 - size);
-            crc_ptr += 4 - size;
-        }
-        bd.flags &= ~FEC_BD_E;
-        if (size == 0) {
-            /* Last buffer in frame.  */
-            bd.flags |= flags | FEC_BD_L;
-            DPRINTF("rx frame flags %04x\n", bd.flags);
-            s->eir |= FEC_INT_RXF;
-        } else {
-            s->eir |= FEC_INT_RXB;
-        }
-        mcf_fec_write_bd(&bd, addr);
-        /* Advance to the next descriptor.  */
-        if ((bd.flags & FEC_BD_W) != 0) {
-            addr = s->erdsr;
-        } else {
-            addr += 8;
-        }
-    }
-    s->rx_descriptor = addr;
-    mcf_fec_enable_rx(s);
-    mcf_fec_update(s);
-    return size;
-}
-
-static const MemoryRegionOps mcf_fec_ops = {
-    .read = mcf_fec_read,
-    .write = mcf_fec_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void mcf_fec_cleanup(NetClientState *nc)
-{
-    mcf_fec_state *s = qemu_get_nic_opaque(nc);
-
-    memory_region_del_subregion(s->sysmem, &s->iomem);
-    memory_region_destroy(&s->iomem);
-
-    g_free(s);
-}
-
-static NetClientInfo net_mcf_fec_info = {
-    .type = NET_CLIENT_OPTIONS_KIND_NIC,
-    .size = sizeof(NICState),
-    .can_receive = mcf_fec_can_receive,
-    .receive = mcf_fec_receive,
-    .cleanup = mcf_fec_cleanup,
-};
-
-void mcf_fec_init(MemoryRegion *sysmem, NICInfo *nd,
-                  hwaddr base, qemu_irq *irq)
-{
-    mcf_fec_state *s;
-
-    qemu_check_nic_model(nd, "mcf_fec");
-
-    s = (mcf_fec_state *)g_malloc0(sizeof(mcf_fec_state));
-    s->sysmem = sysmem;
-    s->irq = irq;
-
-    memory_region_init_io(&s->iomem, &mcf_fec_ops, s, "fec", 0x400);
-    memory_region_add_subregion(sysmem, base, &s->iomem);
-
-    s->conf.macaddr = nd->macaddr;
-    s->conf.peers.ncs[0] = nd->netdev;
-
-    s->nic = qemu_new_nic(&net_mcf_fec_info, &s->conf, nd->model, nd->name, s);
-
-    qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
-}
diff --git a/hw/mcf_uart.c b/hw/mcf_uart.c
deleted file mode 100644 (file)
index e5de801..0000000
+++ /dev/null
@@ -1,307 +0,0 @@
-/*
- * ColdFire UART emulation.
- *
- * Copyright (c) 2007 CodeSourcery.
- *
- * This code is licensed under the GPL
- */
-#include "hw/hw.h"
-#include "hw/mcf.h"
-#include "char/char.h"
-#include "exec/address-spaces.h"
-
-typedef struct {
-    MemoryRegion iomem;
-    uint8_t mr[2];
-    uint8_t sr;
-    uint8_t isr;
-    uint8_t imr;
-    uint8_t bg1;
-    uint8_t bg2;
-    uint8_t fifo[4];
-    uint8_t tb;
-    int current_mr;
-    int fifo_len;
-    int tx_enabled;
-    int rx_enabled;
-    qemu_irq irq;
-    CharDriverState *chr;
-} mcf_uart_state;
-
-/* UART Status Register bits.  */
-#define MCF_UART_RxRDY  0x01
-#define MCF_UART_FFULL  0x02
-#define MCF_UART_TxRDY  0x04
-#define MCF_UART_TxEMP  0x08
-#define MCF_UART_OE     0x10
-#define MCF_UART_PE     0x20
-#define MCF_UART_FE     0x40
-#define MCF_UART_RB     0x80
-
-/* Interrupt flags.  */
-#define MCF_UART_TxINT  0x01
-#define MCF_UART_RxINT  0x02
-#define MCF_UART_DBINT  0x04
-#define MCF_UART_COSINT 0x80
-
-/* UMR1 flags.  */
-#define MCF_UART_BC0    0x01
-#define MCF_UART_BC1    0x02
-#define MCF_UART_PT     0x04
-#define MCF_UART_PM0    0x08
-#define MCF_UART_PM1    0x10
-#define MCF_UART_ERR    0x20
-#define MCF_UART_RxIRQ  0x40
-#define MCF_UART_RxRTS  0x80
-
-static void mcf_uart_update(mcf_uart_state *s)
-{
-    s->isr &= ~(MCF_UART_TxINT | MCF_UART_RxINT);
-    if (s->sr & MCF_UART_TxRDY)
-        s->isr |= MCF_UART_TxINT;
-    if ((s->sr & ((s->mr[0] & MCF_UART_RxIRQ)
-                  ? MCF_UART_FFULL : MCF_UART_RxRDY)) != 0)
-        s->isr |= MCF_UART_RxINT;
-
-    qemu_set_irq(s->irq, (s->isr & s->imr) != 0);
-}
-
-uint64_t mcf_uart_read(void *opaque, hwaddr addr,
-                       unsigned size)
-{
-    mcf_uart_state *s = (mcf_uart_state *)opaque;
-    switch (addr & 0x3f) {
-    case 0x00:
-        return s->mr[s->current_mr];
-    case 0x04:
-        return s->sr;
-    case 0x0c:
-        {
-            uint8_t val;
-            int i;
-
-            if (s->fifo_len == 0)
-                return 0;
-
-            val = s->fifo[0];
-            s->fifo_len--;
-            for (i = 0; i < s->fifo_len; i++)
-                s->fifo[i] = s->fifo[i + 1];
-            s->sr &= ~MCF_UART_FFULL;
-            if (s->fifo_len == 0)
-                s->sr &= ~MCF_UART_RxRDY;
-            mcf_uart_update(s);
-            qemu_chr_accept_input(s->chr);
-            return val;
-        }
-    case 0x10:
-        /* TODO: Implement IPCR.  */
-        return 0;
-    case 0x14:
-        return s->isr;
-    case 0x18:
-        return s->bg1;
-    case 0x1c:
-        return s->bg2;
-    default:
-        return 0;
-    }
-}
-
-/* Update TxRDY flag and set data if present and enabled.  */
-static void mcf_uart_do_tx(mcf_uart_state *s)
-{
-    if (s->tx_enabled && (s->sr & MCF_UART_TxEMP) == 0) {
-        if (s->chr)
-            qemu_chr_fe_write(s->chr, (unsigned char *)&s->tb, 1);
-        s->sr |= MCF_UART_TxEMP;
-    }
-    if (s->tx_enabled) {
-        s->sr |= MCF_UART_TxRDY;
-    } else {
-        s->sr &= ~MCF_UART_TxRDY;
-    }
-}
-
-static void mcf_do_command(mcf_uart_state *s, uint8_t cmd)
-{
-    /* Misc command.  */
-    switch ((cmd >> 4) & 3) {
-    case 0: /* No-op.  */
-        break;
-    case 1: /* Reset mode register pointer.  */
-        s->current_mr = 0;
-        break;
-    case 2: /* Reset receiver.  */
-        s->rx_enabled = 0;
-        s->fifo_len = 0;
-        s->sr &= ~(MCF_UART_RxRDY | MCF_UART_FFULL);
-        break;
-    case 3: /* Reset transmitter.  */
-        s->tx_enabled = 0;
-        s->sr |= MCF_UART_TxEMP;
-        s->sr &= ~MCF_UART_TxRDY;
-        break;
-    case 4: /* Reset error status.  */
-        break;
-    case 5: /* Reset break-change interrupt.  */
-        s->isr &= ~MCF_UART_DBINT;
-        break;
-    case 6: /* Start break.  */
-    case 7: /* Stop break.  */
-        break;
-    }
-
-    /* Transmitter command.  */
-    switch ((cmd >> 2) & 3) {
-    case 0: /* No-op.  */
-        break;
-    case 1: /* Enable.  */
-        s->tx_enabled = 1;
-        mcf_uart_do_tx(s);
-        break;
-    case 2: /* Disable.  */
-        s->tx_enabled = 0;
-        mcf_uart_do_tx(s);
-        break;
-    case 3: /* Reserved.  */
-        fprintf(stderr, "mcf_uart: Bad TX command\n");
-        break;
-    }
-
-    /* Receiver command.  */
-    switch (cmd & 3) {
-    case 0: /* No-op.  */
-        break;
-    case 1: /* Enable.  */
-        s->rx_enabled = 1;
-        break;
-    case 2:
-        s->rx_enabled = 0;
-        break;
-    case 3: /* Reserved.  */
-        fprintf(stderr, "mcf_uart: Bad RX command\n");
-        break;
-    }
-}
-
-void mcf_uart_write(void *opaque, hwaddr addr,
-                    uint64_t val, unsigned size)
-{
-    mcf_uart_state *s = (mcf_uart_state *)opaque;
-    switch (addr & 0x3f) {
-    case 0x00:
-        s->mr[s->current_mr] = val;
-        s->current_mr = 1;
-        break;
-    case 0x04:
-        /* CSR is ignored.  */
-        break;
-    case 0x08: /* Command Register.  */
-        mcf_do_command(s, val);
-        break;
-    case 0x0c: /* Transmit Buffer.  */
-        s->sr &= ~MCF_UART_TxEMP;
-        s->tb = val;
-        mcf_uart_do_tx(s);
-        break;
-    case 0x10:
-        /* ACR is ignored.  */
-        break;
-    case 0x14:
-        s->imr = val;
-        break;
-    default:
-        break;
-    }
-    mcf_uart_update(s);
-}
-
-static void mcf_uart_reset(mcf_uart_state *s)
-{
-    s->fifo_len = 0;
-    s->mr[0] = 0;
-    s->mr[1] = 0;
-    s->sr = MCF_UART_TxEMP;
-    s->tx_enabled = 0;
-    s->rx_enabled = 0;
-    s->isr = 0;
-    s->imr = 0;
-}
-
-static void mcf_uart_push_byte(mcf_uart_state *s, uint8_t data)
-{
-    /* Break events overwrite the last byte if the fifo is full.  */
-    if (s->fifo_len == 4)
-        s->fifo_len--;
-
-    s->fifo[s->fifo_len] = data;
-    s->fifo_len++;
-    s->sr |= MCF_UART_RxRDY;
-    if (s->fifo_len == 4)
-        s->sr |= MCF_UART_FFULL;
-
-    mcf_uart_update(s);
-}
-
-static void mcf_uart_event(void *opaque, int event)
-{
-    mcf_uart_state *s = (mcf_uart_state *)opaque;
-
-    switch (event) {
-    case CHR_EVENT_BREAK:
-        s->isr |= MCF_UART_DBINT;
-        mcf_uart_push_byte(s, 0);
-        break;
-    default:
-        break;
-    }
-}
-
-static int mcf_uart_can_receive(void *opaque)
-{
-    mcf_uart_state *s = (mcf_uart_state *)opaque;
-
-    return s->rx_enabled && (s->sr & MCF_UART_FFULL) == 0;
-}
-
-static void mcf_uart_receive(void *opaque, const uint8_t *buf, int size)
-{
-    mcf_uart_state *s = (mcf_uart_state *)opaque;
-
-    mcf_uart_push_byte(s, buf[0]);
-}
-
-void *mcf_uart_init(qemu_irq irq, CharDriverState *chr)
-{
-    mcf_uart_state *s;
-
-    s = g_malloc0(sizeof(mcf_uart_state));
-    s->chr = chr;
-    s->irq = irq;
-    if (chr) {
-        qemu_chr_fe_claim_no_fail(chr);
-        qemu_chr_add_handlers(chr, mcf_uart_can_receive, mcf_uart_receive,
-                              mcf_uart_event, s);
-    }
-    mcf_uart_reset(s);
-    return s;
-}
-
-static const MemoryRegionOps mcf_uart_ops = {
-    .read = mcf_uart_read,
-    .write = mcf_uart_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-void mcf_uart_mm_init(MemoryRegion *sysmem,
-                      hwaddr base,
-                      qemu_irq irq,
-                      CharDriverState *chr)
-{
-    mcf_uart_state *s;
-
-    s = mcf_uart_init(irq, chr);
-    memory_region_init_io(&s->iomem, &mcf_uart_ops, s, "uart", 0x40);
-    memory_region_add_subregion(sysmem, base, &s->iomem);
-}
diff --git a/hw/megasas.c b/hw/megasas.c
deleted file mode 100644 (file)
index 9b815d4..0000000
+++ /dev/null
@@ -1,2213 +0,0 @@
-/*
- * QEMU MegaRAID SAS 8708EM2 Host Bus Adapter emulation
- * Based on the linux driver code at drivers/scsi/megaraid
- *
- * Copyright (c) 2009-2012 Hannes Reinecke, SUSE Labs
- *
- * 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/hw.h"
-#include "hw/pci/pci.h"
-#include "sysemu/dma.h"
-#include "hw/pci/msix.h"
-#include "qemu/iov.h"
-#include "hw/scsi.h"
-#include "hw/scsi-defs.h"
-#include "trace.h"
-
-#include "hw/mfi.h"
-
-#define MEGASAS_VERSION "1.70"
-#define MEGASAS_MAX_FRAMES 2048         /* Firmware limit at 65535 */
-#define MEGASAS_DEFAULT_FRAMES 1000     /* Windows requires this */
-#define MEGASAS_MAX_SGE 128             /* Firmware limit */
-#define MEGASAS_DEFAULT_SGE 80
-#define MEGASAS_MAX_SECTORS 0xFFFF      /* No real limit */
-#define MEGASAS_MAX_ARRAYS 128
-
-#define MEGASAS_HBA_SERIAL "QEMU123456"
-#define NAA_LOCALLY_ASSIGNED_ID 0x3ULL
-#define IEEE_COMPANY_LOCALLY_ASSIGNED 0x525400
-
-#define MEGASAS_FLAG_USE_JBOD      0
-#define MEGASAS_MASK_USE_JBOD      (1 << MEGASAS_FLAG_USE_JBOD)
-#define MEGASAS_FLAG_USE_MSIX      1
-#define MEGASAS_MASK_USE_MSIX      (1 << MEGASAS_FLAG_USE_MSIX)
-#define MEGASAS_FLAG_USE_QUEUE64   2
-#define MEGASAS_MASK_USE_QUEUE64   (1 << MEGASAS_FLAG_USE_QUEUE64)
-
-static const char *mfi_frame_desc[] = {
-    "MFI init", "LD Read", "LD Write", "LD SCSI", "PD SCSI",
-    "MFI Doorbell", "MFI Abort", "MFI SMP", "MFI Stop"};
-
-typedef struct MegasasCmd {
-    uint32_t index;
-    uint16_t flags;
-    uint16_t count;
-    uint64_t context;
-
-    hwaddr pa;
-    hwaddr pa_size;
-    union mfi_frame *frame;
-    SCSIRequest *req;
-    QEMUSGList qsg;
-    void *iov_buf;
-    size_t iov_size;
-    size_t iov_offset;
-    struct MegasasState *state;
-} MegasasCmd;
-
-typedef struct MegasasState {
-    PCIDevice dev;
-    MemoryRegion mmio_io;
-    MemoryRegion port_io;
-    MemoryRegion queue_io;
-    uint32_t frame_hi;
-
-    int fw_state;
-    uint32_t fw_sge;
-    uint32_t fw_cmds;
-    uint32_t flags;
-    int fw_luns;
-    int intr_mask;
-    int doorbell;
-    int busy;
-
-    MegasasCmd *event_cmd;
-    int event_locale;
-    int event_class;
-    int event_count;
-    int shutdown_event;
-    int boot_event;
-
-    uint64_t sas_addr;
-    char *hba_serial;
-
-    uint64_t reply_queue_pa;
-    void *reply_queue;
-    int reply_queue_len;
-    int reply_queue_head;
-    int reply_queue_tail;
-    uint64_t consumer_pa;
-    uint64_t producer_pa;
-
-    MegasasCmd frames[MEGASAS_MAX_FRAMES];
-
-    SCSIBus bus;
-} MegasasState;
-
-#define MEGASAS_INTR_DISABLED_MASK 0xFFFFFFFF
-
-static bool megasas_intr_enabled(MegasasState *s)
-{
-    if ((s->intr_mask & MEGASAS_INTR_DISABLED_MASK) !=
-        MEGASAS_INTR_DISABLED_MASK) {
-        return true;
-    }
-    return false;
-}
-
-static bool megasas_use_queue64(MegasasState *s)
-{
-    return s->flags & MEGASAS_MASK_USE_QUEUE64;
-}
-
-static bool megasas_use_msix(MegasasState *s)
-{
-    return s->flags & MEGASAS_MASK_USE_MSIX;
-}
-
-static bool megasas_is_jbod(MegasasState *s)
-{
-    return s->flags & MEGASAS_MASK_USE_JBOD;
-}
-
-static void megasas_frame_set_cmd_status(unsigned long frame, uint8_t v)
-{
-    stb_phys(frame + offsetof(struct mfi_frame_header, cmd_status), v);
-}
-
-static void megasas_frame_set_scsi_status(unsigned long frame, uint8_t v)
-{
-    stb_phys(frame + offsetof(struct mfi_frame_header, scsi_status), v);
-}
-
-/*
- * Context is considered opaque, but the HBA firmware is running
- * in little endian mode. So convert it to little endian, too.
- */
-static uint64_t megasas_frame_get_context(unsigned long frame)
-{
-    return ldq_le_phys(frame + offsetof(struct mfi_frame_header, context));
-}
-
-static bool megasas_frame_is_ieee_sgl(MegasasCmd *cmd)
-{
-    return cmd->flags & MFI_FRAME_IEEE_SGL;
-}
-
-static bool megasas_frame_is_sgl64(MegasasCmd *cmd)
-{
-    return cmd->flags & MFI_FRAME_SGL64;
-}
-
-static bool megasas_frame_is_sense64(MegasasCmd *cmd)
-{
-    return cmd->flags & MFI_FRAME_SENSE64;
-}
-
-static uint64_t megasas_sgl_get_addr(MegasasCmd *cmd,
-                                     union mfi_sgl *sgl)
-{
-    uint64_t addr;
-
-    if (megasas_frame_is_ieee_sgl(cmd)) {
-        addr = le64_to_cpu(sgl->sg_skinny->addr);
-    } else if (megasas_frame_is_sgl64(cmd)) {
-        addr = le64_to_cpu(sgl->sg64->addr);
-    } else {
-        addr = le32_to_cpu(sgl->sg32->addr);
-    }
-    return addr;
-}
-
-static uint32_t megasas_sgl_get_len(MegasasCmd *cmd,
-                                    union mfi_sgl *sgl)
-{
-    uint32_t len;
-
-    if (megasas_frame_is_ieee_sgl(cmd)) {
-        len = le32_to_cpu(sgl->sg_skinny->len);
-    } else if (megasas_frame_is_sgl64(cmd)) {
-        len = le32_to_cpu(sgl->sg64->len);
-    } else {
-        len = le32_to_cpu(sgl->sg32->len);
-    }
-    return len;
-}
-
-static union mfi_sgl *megasas_sgl_next(MegasasCmd *cmd,
-                                       union mfi_sgl *sgl)
-{
-    uint8_t *next = (uint8_t *)sgl;
-
-    if (megasas_frame_is_ieee_sgl(cmd)) {
-        next += sizeof(struct mfi_sg_skinny);
-    } else if (megasas_frame_is_sgl64(cmd)) {
-        next += sizeof(struct mfi_sg64);
-    } else {
-        next += sizeof(struct mfi_sg32);
-    }
-
-    if (next >= (uint8_t *)cmd->frame + cmd->pa_size) {
-        return NULL;
-    }
-    return (union mfi_sgl *)next;
-}
-
-static void megasas_soft_reset(MegasasState *s);
-
-static int megasas_map_sgl(MegasasState *s, MegasasCmd *cmd, union mfi_sgl *sgl)
-{
-    int i;
-    int iov_count = 0;
-    size_t iov_size = 0;
-
-    cmd->flags = le16_to_cpu(cmd->frame->header.flags);
-    iov_count = cmd->frame->header.sge_count;
-    if (iov_count > MEGASAS_MAX_SGE) {
-        trace_megasas_iovec_sgl_overflow(cmd->index, iov_count,
-                                         MEGASAS_MAX_SGE);
-        return iov_count;
-    }
-    qemu_sglist_init(&cmd->qsg, iov_count, pci_dma_context(&s->dev));
-    for (i = 0; i < iov_count; i++) {
-        dma_addr_t iov_pa, iov_size_p;
-
-        if (!sgl) {
-            trace_megasas_iovec_sgl_underflow(cmd->index, i);
-            goto unmap;
-        }
-        iov_pa = megasas_sgl_get_addr(cmd, sgl);
-        iov_size_p = megasas_sgl_get_len(cmd, sgl);
-        if (!iov_pa || !iov_size_p) {
-            trace_megasas_iovec_sgl_invalid(cmd->index, i,
-                                            iov_pa, iov_size_p);
-            goto unmap;
-        }
-        qemu_sglist_add(&cmd->qsg, iov_pa, iov_size_p);
-        sgl = megasas_sgl_next(cmd, sgl);
-        iov_size += (size_t)iov_size_p;
-    }
-    if (cmd->iov_size > iov_size) {
-        trace_megasas_iovec_overflow(cmd->index, iov_size, cmd->iov_size);
-    } else if (cmd->iov_size < iov_size) {
-        trace_megasas_iovec_underflow(cmd->iov_size, iov_size, cmd->iov_size);
-    }
-    cmd->iov_offset = 0;
-    return 0;
-unmap:
-    qemu_sglist_destroy(&cmd->qsg);
-    return iov_count - i;
-}
-
-static void megasas_unmap_sgl(MegasasCmd *cmd)
-{
-    qemu_sglist_destroy(&cmd->qsg);
-    cmd->iov_offset = 0;
-}
-
-/*
- * passthrough sense and io sense are at the same offset
- */
-static int megasas_build_sense(MegasasCmd *cmd, uint8_t *sense_ptr,
-    uint8_t sense_len)
-{
-    uint32_t pa_hi = 0, pa_lo;
-    hwaddr pa;
-
-    if (sense_len > cmd->frame->header.sense_len) {
-        sense_len = cmd->frame->header.sense_len;
-    }
-    if (sense_len) {
-        pa_lo = le32_to_cpu(cmd->frame->pass.sense_addr_lo);
-        if (megasas_frame_is_sense64(cmd)) {
-            pa_hi = le32_to_cpu(cmd->frame->pass.sense_addr_hi);
-        }
-        pa = ((uint64_t) pa_hi << 32) | pa_lo;
-        cpu_physical_memory_write(pa, sense_ptr, sense_len);
-        cmd->frame->header.sense_len = sense_len;
-    }
-    return sense_len;
-}
-
-static void megasas_write_sense(MegasasCmd *cmd, SCSISense sense)
-{
-    uint8_t sense_buf[SCSI_SENSE_BUF_SIZE];
-    uint8_t sense_len = 18;
-
-    memset(sense_buf, 0, sense_len);
-    sense_buf[0] = 0xf0;
-    sense_buf[2] = sense.key;
-    sense_buf[7] = 10;
-    sense_buf[12] = sense.asc;
-    sense_buf[13] = sense.ascq;
-    megasas_build_sense(cmd, sense_buf, sense_len);
-}
-
-static void megasas_copy_sense(MegasasCmd *cmd)
-{
-    uint8_t sense_buf[SCSI_SENSE_BUF_SIZE];
-    uint8_t sense_len;
-
-    sense_len = scsi_req_get_sense(cmd->req, sense_buf,
-                                   SCSI_SENSE_BUF_SIZE);
-    megasas_build_sense(cmd, sense_buf, sense_len);
-}
-
-/*
- * Format an INQUIRY CDB
- */
-static int megasas_setup_inquiry(uint8_t *cdb, int pg, int len)
-{
-    memset(cdb, 0, 6);
-    cdb[0] = INQUIRY;
-    if (pg > 0) {
-        cdb[1] = 0x1;
-        cdb[2] = pg;
-    }
-    cdb[3] = (len >> 8) & 0xff;
-    cdb[4] = (len & 0xff);
-    return len;
-}
-
-/*
- * Encode lba and len into a READ_16/WRITE_16 CDB
- */
-static void megasas_encode_lba(uint8_t *cdb, uint64_t lba,
-                               uint32_t len, bool is_write)
-{
-    memset(cdb, 0x0, 16);
-    if (is_write) {
-        cdb[0] = WRITE_16;
-    } else {
-        cdb[0] = READ_16;
-    }
-    cdb[2] = (lba >> 56) & 0xff;
-    cdb[3] = (lba >> 48) & 0xff;
-    cdb[4] = (lba >> 40) & 0xff;
-    cdb[5] = (lba >> 32) & 0xff;
-    cdb[6] = (lba >> 24) & 0xff;
-    cdb[7] = (lba >> 16) & 0xff;
-    cdb[8] = (lba >> 8) & 0xff;
-    cdb[9] = (lba) & 0xff;
-    cdb[10] = (len >> 24) & 0xff;
-    cdb[11] = (len >> 16) & 0xff;
-    cdb[12] = (len >> 8) & 0xff;
-    cdb[13] = (len) & 0xff;
-}
-
-/*
- * Utility functions
- */
-static uint64_t megasas_fw_time(void)
-{
-    struct tm curtime;
-    uint64_t bcd_time;
-
-    qemu_get_timedate(&curtime, 0);
-    bcd_time = ((uint64_t)curtime.tm_sec & 0xff) << 48 |
-        ((uint64_t)curtime.tm_min & 0xff)  << 40 |
-        ((uint64_t)curtime.tm_hour & 0xff) << 32 |
-        ((uint64_t)curtime.tm_mday & 0xff) << 24 |
-        ((uint64_t)curtime.tm_mon & 0xff)  << 16 |
-        ((uint64_t)(curtime.tm_year + 1900) & 0xffff);
-
-    return bcd_time;
-}
-
-/*
- * Default disk sata address
- * 0x1221 is the magic number as
- * present in real hardware,
- * so use it here, too.
- */
-static uint64_t megasas_get_sata_addr(uint16_t id)
-{
-    uint64_t addr = (0x1221ULL << 48);
-    return addr & (id << 24);
-}
-
-/*
- * Frame handling
- */
-static int megasas_next_index(MegasasState *s, int index, int limit)
-{
-    index++;
-    if (index == limit) {
-        index = 0;
-    }
-    return index;
-}
-
-static MegasasCmd *megasas_lookup_frame(MegasasState *s,
-    hwaddr frame)
-{
-    MegasasCmd *cmd = NULL;
-    int num = 0, index;
-
-    index = s->reply_queue_head;
-
-    while (num < s->fw_cmds) {
-        if (s->frames[index].pa && s->frames[index].pa == frame) {
-            cmd = &s->frames[index];
-            break;
-        }
-        index = megasas_next_index(s, index, s->fw_cmds);
-        num++;
-    }
-
-    return cmd;
-}
-
-static MegasasCmd *megasas_next_frame(MegasasState *s,
-    hwaddr frame)
-{
-    MegasasCmd *cmd = NULL;
-    int num = 0, index;
-
-    cmd = megasas_lookup_frame(s, frame);
-    if (cmd) {
-        trace_megasas_qf_found(cmd->index, cmd->pa);
-        return cmd;
-    }
-    index = s->reply_queue_head;
-    num = 0;
-    while (num < s->fw_cmds) {
-        if (!s->frames[index].pa) {
-            cmd = &s->frames[index];
-            break;
-        }
-        index = megasas_next_index(s, index, s->fw_cmds);
-        num++;
-    }
-    if (!cmd) {
-        trace_megasas_qf_failed(frame);
-    }
-    trace_megasas_qf_new(index, cmd);
-    return cmd;
-}
-
-static MegasasCmd *megasas_enqueue_frame(MegasasState *s,
-    hwaddr frame, uint64_t context, int count)
-{
-    MegasasCmd *cmd = NULL;
-    int frame_size = MFI_FRAME_SIZE * 16;
-    hwaddr frame_size_p = frame_size;
-
-    cmd = megasas_next_frame(s, frame);
-    /* All frames busy */
-    if (!cmd) {
-        return NULL;
-    }
-    if (!cmd->pa) {
-        cmd->pa = frame;
-        /* Map all possible frames */
-        cmd->frame = cpu_physical_memory_map(frame, &frame_size_p, 0);
-        if (frame_size_p != frame_size) {
-            trace_megasas_qf_map_failed(cmd->index, (unsigned long)frame);
-            if (cmd->frame) {
-                cpu_physical_memory_unmap(cmd->frame, frame_size_p, 0, 0);
-                cmd->frame = NULL;
-                cmd->pa = 0;
-            }
-            s->event_count++;
-            return NULL;
-        }
-        cmd->pa_size = frame_size_p;
-        cmd->context = context;
-        if (!megasas_use_queue64(s)) {
-            cmd->context &= (uint64_t)0xFFFFFFFF;
-        }
-    }
-    cmd->count = count;
-    s->busy++;
-
-    trace_megasas_qf_enqueue(cmd->index, cmd->count, cmd->context,
-                             s->reply_queue_head, s->busy);
-
-    return cmd;
-}
-
-static void megasas_complete_frame(MegasasState *s, uint64_t context)
-{
-    int tail, queue_offset;
-
-    /* Decrement busy count */
-    s->busy--;
-
-    if (s->reply_queue_pa) {
-        /*
-         * Put command on the reply queue.
-         * Context is opaque, but emulation is running in
-         * little endian. So convert it.
-         */
-        tail = s->reply_queue_head;
-        if (megasas_use_queue64(s)) {
-            queue_offset = tail * sizeof(uint64_t);
-            stq_le_phys(s->reply_queue_pa + queue_offset, context);
-        } else {
-            queue_offset = tail * sizeof(uint32_t);
-            stl_le_phys(s->reply_queue_pa + queue_offset, context);
-        }
-        s->reply_queue_head = megasas_next_index(s, tail, s->fw_cmds);
-        trace_megasas_qf_complete(context, tail, queue_offset,
-                                  s->busy, s->doorbell);
-    }
-
-    if (megasas_intr_enabled(s)) {
-        /* Notify HBA */
-        s->doorbell++;
-        if (s->doorbell == 1) {
-            if (msix_enabled(&s->dev)) {
-                trace_megasas_msix_raise(0);
-                msix_notify(&s->dev, 0);
-            } else {
-                trace_megasas_irq_raise();
-                qemu_irq_raise(s->dev.irq[0]);
-            }
-        }
-    } else {
-        trace_megasas_qf_complete_noirq(context);
-    }
-}
-
-static void megasas_reset_frames(MegasasState *s)
-{
-    int i;
-    MegasasCmd *cmd;
-
-    for (i = 0; i < s->fw_cmds; i++) {
-        cmd = &s->frames[i];
-        if (cmd->pa) {
-            cpu_physical_memory_unmap(cmd->frame, cmd->pa_size, 0, 0);
-            cmd->frame = NULL;
-            cmd->pa = 0;
-        }
-    }
-}
-
-static void megasas_abort_command(MegasasCmd *cmd)
-{
-    if (cmd->req) {
-        scsi_req_cancel(cmd->req);
-        cmd->req = NULL;
-    }
-}
-
-static int megasas_init_firmware(MegasasState *s, MegasasCmd *cmd)
-{
-    uint32_t pa_hi, pa_lo;
-    hwaddr iq_pa, initq_size;
-    struct mfi_init_qinfo *initq;
-    uint32_t flags;
-    int ret = MFI_STAT_OK;
-
-    pa_lo = le32_to_cpu(cmd->frame->init.qinfo_new_addr_lo);
-    pa_hi = le32_to_cpu(cmd->frame->init.qinfo_new_addr_hi);
-    iq_pa = (((uint64_t) pa_hi << 32) | pa_lo);
-    trace_megasas_init_firmware((uint64_t)iq_pa);
-    initq_size = sizeof(*initq);
-    initq = cpu_physical_memory_map(iq_pa, &initq_size, 0);
-    if (!initq || initq_size != sizeof(*initq)) {
-        trace_megasas_initq_map_failed(cmd->index);
-        s->event_count++;
-        ret = MFI_STAT_MEMORY_NOT_AVAILABLE;
-        goto out;
-    }
-    s->reply_queue_len = le32_to_cpu(initq->rq_entries) & 0xFFFF;
-    if (s->reply_queue_len > s->fw_cmds) {
-        trace_megasas_initq_mismatch(s->reply_queue_len, s->fw_cmds);
-        s->event_count++;
-        ret = MFI_STAT_INVALID_PARAMETER;
-        goto out;
-    }
-    pa_lo = le32_to_cpu(initq->rq_addr_lo);
-    pa_hi = le32_to_cpu(initq->rq_addr_hi);
-    s->reply_queue_pa = ((uint64_t) pa_hi << 32) | pa_lo;
-    pa_lo = le32_to_cpu(initq->ci_addr_lo);
-    pa_hi = le32_to_cpu(initq->ci_addr_hi);
-    s->consumer_pa = ((uint64_t) pa_hi << 32) | pa_lo;
-    pa_lo = le32_to_cpu(initq->pi_addr_lo);
-    pa_hi = le32_to_cpu(initq->pi_addr_hi);
-    s->producer_pa = ((uint64_t) pa_hi << 32) | pa_lo;
-    s->reply_queue_head = ldl_le_phys(s->producer_pa);
-    s->reply_queue_tail = ldl_le_phys(s->consumer_pa);
-    flags = le32_to_cpu(initq->flags);
-    if (flags & MFI_QUEUE_FLAG_CONTEXT64) {
-        s->flags |= MEGASAS_MASK_USE_QUEUE64;
-    }
-    trace_megasas_init_queue((unsigned long)s->reply_queue_pa,
-                             s->reply_queue_len, s->reply_queue_head,
-                             s->reply_queue_tail, flags);
-    megasas_reset_frames(s);
-    s->fw_state = MFI_FWSTATE_OPERATIONAL;
-out:
-    if (initq) {
-        cpu_physical_memory_unmap(initq, initq_size, 0, 0);
-    }
-    return ret;
-}
-
-static int megasas_map_dcmd(MegasasState *s, MegasasCmd *cmd)
-{
-    dma_addr_t iov_pa, iov_size;
-
-    cmd->flags = le16_to_cpu(cmd->frame->header.flags);
-    if (!cmd->frame->header.sge_count) {
-        trace_megasas_dcmd_zero_sge(cmd->index);
-        cmd->iov_size = 0;
-        return 0;
-    } else if (cmd->frame->header.sge_count > 1) {
-        trace_megasas_dcmd_invalid_sge(cmd->index,
-                                       cmd->frame->header.sge_count);
-        cmd->iov_size = 0;
-        return -1;
-    }
-    iov_pa = megasas_sgl_get_addr(cmd, &cmd->frame->dcmd.sgl);
-    iov_size = megasas_sgl_get_len(cmd, &cmd->frame->dcmd.sgl);
-    qemu_sglist_init(&cmd->qsg, 1, pci_dma_context(&s->dev));
-    qemu_sglist_add(&cmd->qsg, iov_pa, iov_size);
-    cmd->iov_size = iov_size;
-    return cmd->iov_size;
-}
-
-static void megasas_finish_dcmd(MegasasCmd *cmd, uint32_t iov_size)
-{
-    trace_megasas_finish_dcmd(cmd->index, iov_size);
-
-    if (cmd->frame->header.sge_count) {
-        qemu_sglist_destroy(&cmd->qsg);
-    }
-    if (iov_size > cmd->iov_size) {
-        if (megasas_frame_is_ieee_sgl(cmd)) {
-            cmd->frame->dcmd.sgl.sg_skinny->len = cpu_to_le32(iov_size);
-        } else if (megasas_frame_is_sgl64(cmd)) {
-            cmd->frame->dcmd.sgl.sg64->len = cpu_to_le32(iov_size);
-        } else {
-            cmd->frame->dcmd.sgl.sg32->len = cpu_to_le32(iov_size);
-        }
-    }
-    cmd->iov_size = 0;
-}
-
-static int megasas_ctrl_get_info(MegasasState *s, MegasasCmd *cmd)
-{
-    struct mfi_ctrl_info info;
-    size_t dcmd_size = sizeof(info);
-    BusChild *kid;
-    int num_ld_disks = 0;
-    uint16_t sdev_id;
-
-    memset(&info, 0x0, cmd->iov_size);
-    if (cmd->iov_size < dcmd_size) {
-        trace_megasas_dcmd_invalid_xfer_len(cmd->index, cmd->iov_size,
-                                            dcmd_size);
-        return MFI_STAT_INVALID_PARAMETER;
-    }
-
-    info.pci.vendor = cpu_to_le16(PCI_VENDOR_ID_LSI_LOGIC);
-    info.pci.device = cpu_to_le16(PCI_DEVICE_ID_LSI_SAS1078);
-    info.pci.subvendor = cpu_to_le16(PCI_VENDOR_ID_LSI_LOGIC);
-    info.pci.subdevice = cpu_to_le16(0x1013);
-
-    /*
-     * For some reason the firmware supports
-     * only up to 8 device ports.
-     * Despite supporting a far larger number
-     * of devices for the physical devices.
-     * So just display the first 8 devices
-     * in the device port list, independent
-     * of how many logical devices are actually
-     * present.
-     */
-    info.host.type = MFI_INFO_HOST_PCIE;
-    info.device.type = MFI_INFO_DEV_SAS3G;
-    info.device.port_count = 8;
-    QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) {
-        SCSIDevice *sdev = DO_UPCAST(SCSIDevice, qdev, kid->child);
-
-        if (num_ld_disks < 8) {
-            sdev_id = ((sdev->id & 0xFF) >> 8) | (sdev->lun & 0xFF);
-            info.device.port_addr[num_ld_disks] =
-                cpu_to_le64(megasas_get_sata_addr(sdev_id));
-        }
-        num_ld_disks++;
-    }
-
-    memcpy(info.product_name, "MegaRAID SAS 8708EM2", 20);
-    snprintf(info.serial_number, 32, "%s", s->hba_serial);
-    snprintf(info.package_version, 0x60, "%s-QEMU", QEMU_VERSION);
-    memcpy(info.image_component[0].name, "APP", 3);
-    memcpy(info.image_component[0].version, MEGASAS_VERSION "-QEMU", 9);
-    memcpy(info.image_component[0].build_date, __DATE__, 11);
-    memcpy(info.image_component[0].build_time, __TIME__, 8);
-    info.image_component_count = 1;
-    if (s->dev.has_rom) {
-        uint8_t biosver[32];
-        uint8_t *ptr;
-
-        ptr = memory_region_get_ram_ptr(&s->dev.rom);
-        memcpy(biosver, ptr + 0x41, 31);
-        qemu_put_ram_ptr(ptr);
-        memcpy(info.image_component[1].name, "BIOS", 4);
-        memcpy(info.image_component[1].version, biosver,
-               strlen((const char *)biosver));
-        info.image_component_count++;
-    }
-    info.current_fw_time = cpu_to_le32(megasas_fw_time());
-    info.max_arms = 32;
-    info.max_spans = 8;
-    info.max_arrays = MEGASAS_MAX_ARRAYS;
-    info.max_lds = s->fw_luns;
-    info.max_cmds = cpu_to_le16(s->fw_cmds);
-    info.max_sg_elements = cpu_to_le16(s->fw_sge);
-    info.max_request_size = cpu_to_le32(MEGASAS_MAX_SECTORS);
-    info.lds_present = cpu_to_le16(num_ld_disks);
-    info.pd_present = cpu_to_le16(num_ld_disks);
-    info.pd_disks_present = cpu_to_le16(num_ld_disks);
-    info.hw_present = cpu_to_le32(MFI_INFO_HW_NVRAM |
-                                   MFI_INFO_HW_MEM |
-                                   MFI_INFO_HW_FLASH);
-    info.memory_size = cpu_to_le16(512);
-    info.nvram_size = cpu_to_le16(32);
-    info.flash_size = cpu_to_le16(16);
-    info.raid_levels = cpu_to_le32(MFI_INFO_RAID_0);
-    info.adapter_ops = cpu_to_le32(MFI_INFO_AOPS_RBLD_RATE |
-                                    MFI_INFO_AOPS_SELF_DIAGNOSTIC |
-                                    MFI_INFO_AOPS_MIXED_ARRAY);
-    info.ld_ops = cpu_to_le32(MFI_INFO_LDOPS_DISK_CACHE_POLICY |
-                               MFI_INFO_LDOPS_ACCESS_POLICY |
-                               MFI_INFO_LDOPS_IO_POLICY |
-                               MFI_INFO_LDOPS_WRITE_POLICY |
-                               MFI_INFO_LDOPS_READ_POLICY);
-    info.max_strips_per_io = cpu_to_le16(s->fw_sge);
-    info.stripe_sz_ops.min = 3;
-    info.stripe_sz_ops.max = ffs(MEGASAS_MAX_SECTORS + 1) - 1;
-    info.properties.pred_fail_poll_interval = cpu_to_le16(300);
-    info.properties.intr_throttle_cnt = cpu_to_le16(16);
-    info.properties.intr_throttle_timeout = cpu_to_le16(50);
-    info.properties.rebuild_rate = 30;
-    info.properties.patrol_read_rate = 30;
-    info.properties.bgi_rate = 30;
-    info.properties.cc_rate = 30;
-    info.properties.recon_rate = 30;
-    info.properties.cache_flush_interval = 4;
-    info.properties.spinup_drv_cnt = 2;
-    info.properties.spinup_delay = 6;
-    info.properties.ecc_bucket_size = 15;
-    info.properties.ecc_bucket_leak_rate = cpu_to_le16(1440);
-    info.properties.expose_encl_devices = 1;
-    info.properties.OnOffProperties = cpu_to_le32(MFI_CTRL_PROP_EnableJBOD);
-    info.pd_ops = cpu_to_le32(MFI_INFO_PDOPS_FORCE_ONLINE |
-                               MFI_INFO_PDOPS_FORCE_OFFLINE);
-    info.pd_mix_support = cpu_to_le32(MFI_INFO_PDMIX_SAS |
-                                       MFI_INFO_PDMIX_SATA |
-                                       MFI_INFO_PDMIX_LD);
-
-    cmd->iov_size -= dma_buf_read((uint8_t *)&info, dcmd_size, &cmd->qsg);
-    return MFI_STAT_OK;
-}
-
-static int megasas_mfc_get_defaults(MegasasState *s, MegasasCmd *cmd)
-{
-    struct mfi_defaults info;
-    size_t dcmd_size = sizeof(struct mfi_defaults);
-
-    memset(&info, 0x0, dcmd_size);
-    if (cmd->iov_size < dcmd_size) {
-        trace_megasas_dcmd_invalid_xfer_len(cmd->index, cmd->iov_size,
-                                            dcmd_size);
-        return MFI_STAT_INVALID_PARAMETER;
-    }
-
-    info.sas_addr = cpu_to_le64(s->sas_addr);
-    info.stripe_size = 3;
-    info.flush_time = 4;
-    info.background_rate = 30;
-    info.allow_mix_in_enclosure = 1;
-    info.allow_mix_in_ld = 1;
-    info.direct_pd_mapping = 1;
-    /* Enable for BIOS support */
-    info.bios_enumerate_lds = 1;
-    info.disable_ctrl_r = 1;
-    info.expose_enclosure_devices = 1;
-    info.disable_preboot_cli = 1;
-    info.cluster_disable = 1;
-
-    cmd->iov_size -= dma_buf_read((uint8_t *)&info, dcmd_size, &cmd->qsg);
-    return MFI_STAT_OK;
-}
-
-static int megasas_dcmd_get_bios_info(MegasasState *s, MegasasCmd *cmd)
-{
-    struct mfi_bios_data info;
-    size_t dcmd_size = sizeof(info);
-
-    memset(&info, 0x0, dcmd_size);
-    if (cmd->iov_size < dcmd_size) {
-        trace_megasas_dcmd_invalid_xfer_len(cmd->index, cmd->iov_size,
-                                            dcmd_size);
-        return MFI_STAT_INVALID_PARAMETER;
-    }
-    info.continue_on_error = 1;
-    info.verbose = 1;
-    if (megasas_is_jbod(s)) {
-        info.expose_all_drives = 1;
-    }
-
-    cmd->iov_size -= dma_buf_read((uint8_t *)&info, dcmd_size, &cmd->qsg);
-    return MFI_STAT_OK;
-}
-
-static int megasas_dcmd_get_fw_time(MegasasState *s, MegasasCmd *cmd)
-{
-    uint64_t fw_time;
-    size_t dcmd_size = sizeof(fw_time);
-
-    fw_time = cpu_to_le64(megasas_fw_time());
-
-    cmd->iov_size -= dma_buf_read((uint8_t *)&fw_time, dcmd_size, &cmd->qsg);
-    return MFI_STAT_OK;
-}
-
-static int megasas_dcmd_set_fw_time(MegasasState *s, MegasasCmd *cmd)
-{
-    uint64_t fw_time;
-
-    /* This is a dummy; setting of firmware time is not allowed */
-    memcpy(&fw_time, cmd->frame->dcmd.mbox, sizeof(fw_time));
-
-    trace_megasas_dcmd_set_fw_time(cmd->index, fw_time);
-    fw_time = cpu_to_le64(megasas_fw_time());
-    return MFI_STAT_OK;
-}
-
-static int megasas_event_info(MegasasState *s, MegasasCmd *cmd)
-{
-    struct mfi_evt_log_state info;
-    size_t dcmd_size = sizeof(info);
-
-    memset(&info, 0, dcmd_size);
-
-    info.newest_seq_num = cpu_to_le32(s->event_count);
-    info.shutdown_seq_num = cpu_to_le32(s->shutdown_event);
-    info.boot_seq_num = cpu_to_le32(s->boot_event);
-
-    cmd->iov_size -= dma_buf_read((uint8_t *)&info, dcmd_size, &cmd->qsg);
-    return MFI_STAT_OK;
-}
-
-static int megasas_event_wait(MegasasState *s, MegasasCmd *cmd)
-{
-    union mfi_evt event;
-
-    if (cmd->iov_size < sizeof(struct mfi_evt_detail)) {
-        trace_megasas_dcmd_invalid_xfer_len(cmd->index, cmd->iov_size,
-                                            sizeof(struct mfi_evt_detail));
-        return MFI_STAT_INVALID_PARAMETER;
-    }
-    s->event_count = cpu_to_le32(cmd->frame->dcmd.mbox[0]);
-    event.word = cpu_to_le32(cmd->frame->dcmd.mbox[4]);
-    s->event_locale = event.members.locale;
-    s->event_class = event.members.class;
-    s->event_cmd = cmd;
-    /* Decrease busy count; event frame doesn't count here */
-    s->busy--;
-    cmd->iov_size = sizeof(struct mfi_evt_detail);
-    return MFI_STAT_INVALID_STATUS;
-}
-
-static int megasas_dcmd_pd_get_list(MegasasState *s, MegasasCmd *cmd)
-{
-    struct mfi_pd_list info;
-    size_t dcmd_size = sizeof(info);
-    BusChild *kid;
-    uint32_t offset, dcmd_limit, num_pd_disks = 0, max_pd_disks;
-    uint16_t sdev_id;
-
-    memset(&info, 0, dcmd_size);
-    offset = 8;
-    dcmd_limit = offset + sizeof(struct mfi_pd_address);
-    if (cmd->iov_size < dcmd_limit) {
-        trace_megasas_dcmd_invalid_xfer_len(cmd->index, cmd->iov_size,
-                                            dcmd_limit);
-        return MFI_STAT_INVALID_PARAMETER;
-    }
-
-    max_pd_disks = (cmd->iov_size - offset) / sizeof(struct mfi_pd_address);
-    if (max_pd_disks > s->fw_luns) {
-        max_pd_disks = s->fw_luns;
-    }
-
-    QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) {
-        SCSIDevice *sdev = DO_UPCAST(SCSIDevice, qdev, kid->child);
-
-        sdev_id = ((sdev->id & 0xFF) >> 8) | (sdev->lun & 0xFF);
-        info.addr[num_pd_disks].device_id = cpu_to_le16(sdev_id);
-        info.addr[num_pd_disks].encl_device_id = 0xFFFF;
-        info.addr[num_pd_disks].encl_index = 0;
-        info.addr[num_pd_disks].slot_number = (sdev->id & 0xFF);
-        info.addr[num_pd_disks].scsi_dev_type = sdev->type;
-        info.addr[num_pd_disks].connect_port_bitmap = 0x1;
-        info.addr[num_pd_disks].sas_addr[0] =
-            cpu_to_le64(megasas_get_sata_addr(sdev_id));
-        num_pd_disks++;
-        offset += sizeof(struct mfi_pd_address);
-    }
-    trace_megasas_dcmd_pd_get_list(cmd->index, num_pd_disks,
-                                   max_pd_disks, offset);
-
-    info.size = cpu_to_le32(offset);
-    info.count = cpu_to_le32(num_pd_disks);
-
-    cmd->iov_size -= dma_buf_read((uint8_t *)&info, offset, &cmd->qsg);
-    return MFI_STAT_OK;
-}
-
-static int megasas_dcmd_pd_list_query(MegasasState *s, MegasasCmd *cmd)
-{
-    uint16_t flags;
-
-    /* mbox0 contains flags */
-    flags = le16_to_cpu(cmd->frame->dcmd.mbox[0]);
-    trace_megasas_dcmd_pd_list_query(cmd->index, flags);
-    if (flags == MR_PD_QUERY_TYPE_ALL ||
-        megasas_is_jbod(s)) {
-        return megasas_dcmd_pd_get_list(s, cmd);
-    }
-
-    return MFI_STAT_OK;
-}
-
-static int megasas_pd_get_info_submit(SCSIDevice *sdev, int lun,
-                                      MegasasCmd *cmd)
-{
-    struct mfi_pd_info *info = cmd->iov_buf;
-    size_t dcmd_size = sizeof(struct mfi_pd_info);
-    BlockConf *conf = &sdev->conf;
-    uint64_t pd_size;
-    uint16_t sdev_id = ((sdev->id & 0xFF) >> 8) | (lun & 0xFF);
-    uint8_t cmdbuf[6];
-    SCSIRequest *req;
-    size_t len, resid;
-
-    if (!cmd->iov_buf) {
-        cmd->iov_buf = g_malloc(dcmd_size);
-        memset(cmd->iov_buf, 0, dcmd_size);
-        info = cmd->iov_buf;
-        info->inquiry_data[0] = 0x7f; /* Force PQual 0x3, PType 0x1f */
-        info->vpd_page83[0] = 0x7f;
-        megasas_setup_inquiry(cmdbuf, 0, sizeof(info->inquiry_data));
-        req = scsi_req_new(sdev, cmd->index, lun, cmdbuf, cmd);
-        if (!req) {
-            trace_megasas_dcmd_req_alloc_failed(cmd->index,
-                                                "PD get info std inquiry");
-            g_free(cmd->iov_buf);
-            cmd->iov_buf = NULL;
-            return MFI_STAT_FLASH_ALLOC_FAIL;
-        }
-        trace_megasas_dcmd_internal_submit(cmd->index,
-                                           "PD get info std inquiry", lun);
-        len = scsi_req_enqueue(req);
-        if (len > 0) {
-            cmd->iov_size = len;
-            scsi_req_continue(req);
-        }
-        return MFI_STAT_INVALID_STATUS;
-    } else if (info->inquiry_data[0] != 0x7f && info->vpd_page83[0] == 0x7f) {
-        megasas_setup_inquiry(cmdbuf, 0x83, sizeof(info->vpd_page83));
-        req = scsi_req_new(sdev, cmd->index, lun, cmdbuf, cmd);
-        if (!req) {
-            trace_megasas_dcmd_req_alloc_failed(cmd->index,
-                                                "PD get info vpd inquiry");
-            return MFI_STAT_FLASH_ALLOC_FAIL;
-        }
-        trace_megasas_dcmd_internal_submit(cmd->index,
-                                           "PD get info vpd inquiry", lun);
-        len = scsi_req_enqueue(req);
-        if (len > 0) {
-            cmd->iov_size = len;
-            scsi_req_continue(req);
-        }
-        return MFI_STAT_INVALID_STATUS;
-    }
-    /* Finished, set FW state */
-    if ((info->inquiry_data[0] >> 5) == 0) {
-        if (megasas_is_jbod(cmd->state)) {
-            info->fw_state = cpu_to_le16(MFI_PD_STATE_SYSTEM);
-        } else {
-            info->fw_state = cpu_to_le16(MFI_PD_STATE_ONLINE);
-        }
-    } else {
-        info->fw_state = cpu_to_le16(MFI_PD_STATE_OFFLINE);
-    }
-
-    info->ref.v.device_id = cpu_to_le16(sdev_id);
-    info->state.ddf.pd_type = cpu_to_le16(MFI_PD_DDF_TYPE_IN_VD|
-                                          MFI_PD_DDF_TYPE_INTF_SAS);
-    bdrv_get_geometry(conf->bs, &pd_size);
-    info->raw_size = cpu_to_le64(pd_size);
-    info->non_coerced_size = cpu_to_le64(pd_size);
-    info->coerced_size = cpu_to_le64(pd_size);
-    info->encl_device_id = 0xFFFF;
-    info->slot_number = (sdev->id & 0xFF);
-    info->path_info.count = 1;
-    info->path_info.sas_addr[0] =
-        cpu_to_le64(megasas_get_sata_addr(sdev_id));
-    info->connected_port_bitmap = 0x1;
-    info->device_speed = 1;
-    info->link_speed = 1;
-    resid = dma_buf_read(cmd->iov_buf, dcmd_size, &cmd->qsg);
-    g_free(cmd->iov_buf);
-    cmd->iov_size = dcmd_size - resid;
-    cmd->iov_buf = NULL;
-    return MFI_STAT_OK;
-}
-
-static int megasas_dcmd_pd_get_info(MegasasState *s, MegasasCmd *cmd)
-{
-    size_t dcmd_size = sizeof(struct mfi_pd_info);
-    uint16_t pd_id;
-    SCSIDevice *sdev = NULL;
-    int retval = MFI_STAT_DEVICE_NOT_FOUND;
-
-    if (cmd->iov_size < dcmd_size) {
-        return MFI_STAT_INVALID_PARAMETER;
-    }
-
-    /* mbox0 has the ID */
-    pd_id = le16_to_cpu(cmd->frame->dcmd.mbox[0]);
-    sdev = scsi_device_find(&s->bus, 0, pd_id, 0);
-    trace_megasas_dcmd_pd_get_info(cmd->index, pd_id);
-
-    if (sdev) {
-        /* Submit inquiry */
-        retval = megasas_pd_get_info_submit(sdev, pd_id, cmd);
-    }
-
-    return retval;
-}
-
-static int megasas_dcmd_ld_get_list(MegasasState *s, MegasasCmd *cmd)
-{
-    struct mfi_ld_list info;
-    size_t dcmd_size = sizeof(info), resid;
-    uint32_t num_ld_disks = 0, max_ld_disks = s->fw_luns;
-    uint64_t ld_size;
-    BusChild *kid;
-
-    memset(&info, 0, dcmd_size);
-    if (cmd->iov_size < dcmd_size) {
-        trace_megasas_dcmd_invalid_xfer_len(cmd->index, cmd->iov_size,
-                                            dcmd_size);
-        return MFI_STAT_INVALID_PARAMETER;
-    }
-
-    if (megasas_is_jbod(s)) {
-        max_ld_disks = 0;
-    }
-    QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) {
-        SCSIDevice *sdev = DO_UPCAST(SCSIDevice, qdev, kid->child);
-        BlockConf *conf = &sdev->conf;
-
-        if (num_ld_disks >= max_ld_disks) {
-            break;
-        }
-        /* Logical device size is in blocks */
-        bdrv_get_geometry(conf->bs, &ld_size);
-        info.ld_list[num_ld_disks].ld.v.target_id = sdev->id;
-        info.ld_list[num_ld_disks].ld.v.lun_id = sdev->lun;
-        info.ld_list[num_ld_disks].state = MFI_LD_STATE_OPTIMAL;
-        info.ld_list[num_ld_disks].size = cpu_to_le64(ld_size);
-        num_ld_disks++;
-    }
-    info.ld_count = cpu_to_le32(num_ld_disks);
-    trace_megasas_dcmd_ld_get_list(cmd->index, num_ld_disks, max_ld_disks);
-
-    resid = dma_buf_read((uint8_t *)&info, dcmd_size, &cmd->qsg);
-    cmd->iov_size = dcmd_size - resid;
-    return MFI_STAT_OK;
-}
-
-static int megasas_ld_get_info_submit(SCSIDevice *sdev, int lun,
-                                      MegasasCmd *cmd)
-{
-    struct mfi_ld_info *info = cmd->iov_buf;
-    size_t dcmd_size = sizeof(struct mfi_ld_info);
-    uint8_t cdb[6];
-    SCSIRequest *req;
-    ssize_t len, resid;
-    BlockConf *conf = &sdev->conf;
-    uint16_t sdev_id = ((sdev->id & 0xFF) >> 8) | (lun & 0xFF);
-    uint64_t ld_size;
-
-    if (!cmd->iov_buf) {
-        cmd->iov_buf = g_malloc(dcmd_size);
-        memset(cmd->iov_buf, 0x0, dcmd_size);
-        info = cmd->iov_buf;
-        megasas_setup_inquiry(cdb, 0x83, sizeof(info->vpd_page83));
-        req = scsi_req_new(sdev, cmd->index, lun, cdb, cmd);
-        if (!req) {
-            trace_megasas_dcmd_req_alloc_failed(cmd->index,
-                                                "LD get info vpd inquiry");
-            g_free(cmd->iov_buf);
-            cmd->iov_buf = NULL;
-            return MFI_STAT_FLASH_ALLOC_FAIL;
-        }
-        trace_megasas_dcmd_internal_submit(cmd->index,
-                                           "LD get info vpd inquiry", lun);
-        len = scsi_req_enqueue(req);
-        if (len > 0) {
-            cmd->iov_size = len;
-            scsi_req_continue(req);
-        }
-        return MFI_STAT_INVALID_STATUS;
-    }
-
-    info->ld_config.params.state = MFI_LD_STATE_OPTIMAL;
-    info->ld_config.properties.ld.v.target_id = lun;
-    info->ld_config.params.stripe_size = 3;
-    info->ld_config.params.num_drives = 1;
-    info->ld_config.params.is_consistent = 1;
-    /* Logical device size is in blocks */
-    bdrv_get_geometry(conf->bs, &ld_size);
-    info->size = cpu_to_le64(ld_size);
-    memset(info->ld_config.span, 0, sizeof(info->ld_config.span));
-    info->ld_config.span[0].start_block = 0;
-    info->ld_config.span[0].num_blocks = info->size;
-    info->ld_config.span[0].array_ref = cpu_to_le16(sdev_id);
-
-    resid = dma_buf_read(cmd->iov_buf, dcmd_size, &cmd->qsg);
-    g_free(cmd->iov_buf);
-    cmd->iov_size = dcmd_size - resid;
-    cmd->iov_buf = NULL;
-    return MFI_STAT_OK;
-}
-
-static int megasas_dcmd_ld_get_info(MegasasState *s, MegasasCmd *cmd)
-{
-    struct mfi_ld_info info;
-    size_t dcmd_size = sizeof(info);
-    uint16_t ld_id;
-    uint32_t max_ld_disks = s->fw_luns;
-    SCSIDevice *sdev = NULL;
-    int retval = MFI_STAT_DEVICE_NOT_FOUND;
-
-    if (cmd->iov_size < dcmd_size) {
-        return MFI_STAT_INVALID_PARAMETER;
-    }
-
-    /* mbox0 has the ID */
-    ld_id = le16_to_cpu(cmd->frame->dcmd.mbox[0]);
-    trace_megasas_dcmd_ld_get_info(cmd->index, ld_id);
-
-    if (megasas_is_jbod(s)) {
-        return MFI_STAT_DEVICE_NOT_FOUND;
-    }
-
-    if (ld_id < max_ld_disks) {
-        sdev = scsi_device_find(&s->bus, 0, ld_id, 0);
-    }
-
-    if (sdev) {
-        retval = megasas_ld_get_info_submit(sdev, ld_id, cmd);
-    }
-
-    return retval;
-}
-
-static int megasas_dcmd_cfg_read(MegasasState *s, MegasasCmd *cmd)
-{
-    uint8_t data[4096];
-    struct mfi_config_data *info;
-    int num_pd_disks = 0, array_offset, ld_offset;
-    BusChild *kid;
-
-    if (cmd->iov_size > 4096) {
-        return MFI_STAT_INVALID_PARAMETER;
-    }
-
-    QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) {
-        num_pd_disks++;
-    }
-    info = (struct mfi_config_data *)&data;
-    /*
-     * Array mapping:
-     * - One array per SCSI device
-     * - One logical drive per SCSI device
-     *   spanning the entire device
-     */
-    info->array_count = num_pd_disks;
-    info->array_size = sizeof(struct mfi_array) * num_pd_disks;
-    info->log_drv_count = num_pd_disks;
-    info->log_drv_size = sizeof(struct mfi_ld_config) * num_pd_disks;
-    info->spares_count = 0;
-    info->spares_size = sizeof(struct mfi_spare);
-    info->size = sizeof(struct mfi_config_data) + info->array_size +
-        info->log_drv_size;
-    if (info->size > 4096) {
-        return MFI_STAT_INVALID_PARAMETER;
-    }
-
-    array_offset = sizeof(struct mfi_config_data);
-    ld_offset = array_offset + sizeof(struct mfi_array) * num_pd_disks;
-
-    QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) {
-        SCSIDevice *sdev = DO_UPCAST(SCSIDevice, qdev, kid->child);
-        BlockConf *conf = &sdev->conf;
-        uint16_t sdev_id = ((sdev->id & 0xFF) >> 8) | (sdev->lun & 0xFF);
-        struct mfi_array *array;
-        struct mfi_ld_config *ld;
-        uint64_t pd_size;
-        int i;
-
-        array = (struct mfi_array *)(data + array_offset);
-        bdrv_get_geometry(conf->bs, &pd_size);
-        array->size = cpu_to_le64(pd_size);
-        array->num_drives = 1;
-        array->array_ref = cpu_to_le16(sdev_id);
-        array->pd[0].ref.v.device_id = cpu_to_le16(sdev_id);
-        array->pd[0].ref.v.seq_num = 0;
-        array->pd[0].fw_state = MFI_PD_STATE_ONLINE;
-        array->pd[0].encl.pd = 0xFF;
-        array->pd[0].encl.slot = (sdev->id & 0xFF);
-        for (i = 1; i < MFI_MAX_ROW_SIZE; i++) {
-            array->pd[i].ref.v.device_id = 0xFFFF;
-            array->pd[i].ref.v.seq_num = 0;
-            array->pd[i].fw_state = MFI_PD_STATE_UNCONFIGURED_GOOD;
-            array->pd[i].encl.pd = 0xFF;
-            array->pd[i].encl.slot = 0xFF;
-        }
-        array_offset += sizeof(struct mfi_array);
-        ld = (struct mfi_ld_config *)(data + ld_offset);
-        memset(ld, 0, sizeof(struct mfi_ld_config));
-        ld->properties.ld.v.target_id = (sdev->id & 0xFF);
-        ld->properties.default_cache_policy = MR_LD_CACHE_READ_AHEAD |
-            MR_LD_CACHE_READ_ADAPTIVE;
-        ld->properties.current_cache_policy = MR_LD_CACHE_READ_AHEAD |
-            MR_LD_CACHE_READ_ADAPTIVE;
-        ld->params.state = MFI_LD_STATE_OPTIMAL;
-        ld->params.stripe_size = 3;
-        ld->params.num_drives = 1;
-        ld->params.span_depth = 1;
-        ld->params.is_consistent = 1;
-        ld->span[0].start_block = 0;
-        ld->span[0].num_blocks = cpu_to_le64(pd_size);
-        ld->span[0].array_ref = cpu_to_le16(sdev_id);
-        ld_offset += sizeof(struct mfi_ld_config);
-    }
-
-    cmd->iov_size -= dma_buf_read((uint8_t *)data, info->size, &cmd->qsg);
-    return MFI_STAT_OK;
-}
-
-static int megasas_dcmd_get_properties(MegasasState *s, MegasasCmd *cmd)
-{
-    struct mfi_ctrl_props info;
-    size_t dcmd_size = sizeof(info);
-
-    memset(&info, 0x0, dcmd_size);
-    if (cmd->iov_size < dcmd_size) {
-        trace_megasas_dcmd_invalid_xfer_len(cmd->index, cmd->iov_size,
-                                            dcmd_size);
-        return MFI_STAT_INVALID_PARAMETER;
-    }
-    info.pred_fail_poll_interval = cpu_to_le16(300);
-    info.intr_throttle_cnt = cpu_to_le16(16);
-    info.intr_throttle_timeout = cpu_to_le16(50);
-    info.rebuild_rate = 30;
-    info.patrol_read_rate = 30;
-    info.bgi_rate = 30;
-    info.cc_rate = 30;
-    info.recon_rate = 30;
-    info.cache_flush_interval = 4;
-    info.spinup_drv_cnt = 2;
-    info.spinup_delay = 6;
-    info.ecc_bucket_size = 15;
-    info.ecc_bucket_leak_rate = cpu_to_le16(1440);
-    info.expose_encl_devices = 1;
-
-    cmd->iov_size -= dma_buf_read((uint8_t *)&info, dcmd_size, &cmd->qsg);
-    return MFI_STAT_OK;
-}
-
-static int megasas_cache_flush(MegasasState *s, MegasasCmd *cmd)
-{
-    bdrv_drain_all();
-    return MFI_STAT_OK;
-}
-
-static int megasas_ctrl_shutdown(MegasasState *s, MegasasCmd *cmd)
-{
-    s->fw_state = MFI_FWSTATE_READY;
-    return MFI_STAT_OK;
-}
-
-static int megasas_cluster_reset_ld(MegasasState *s, MegasasCmd *cmd)
-{
-    return MFI_STAT_INVALID_DCMD;
-}
-
-static int megasas_dcmd_set_properties(MegasasState *s, MegasasCmd *cmd)
-{
-    struct mfi_ctrl_props info;
-    size_t dcmd_size = sizeof(info);
-
-    if (cmd->iov_size < dcmd_size) {
-        trace_megasas_dcmd_invalid_xfer_len(cmd->index, cmd->iov_size,
-                                            dcmd_size);
-        return MFI_STAT_INVALID_PARAMETER;
-    }
-    dma_buf_write((uint8_t *)&info, cmd->iov_size, &cmd->qsg);
-    trace_megasas_dcmd_unsupported(cmd->index, cmd->iov_size);
-    return MFI_STAT_OK;
-}
-
-static int megasas_dcmd_dummy(MegasasState *s, MegasasCmd *cmd)
-{
-    trace_megasas_dcmd_dummy(cmd->index, cmd->iov_size);
-    return MFI_STAT_OK;
-}
-
-static const struct dcmd_cmd_tbl_t {
-    int opcode;
-    const char *desc;
-    int (*func)(MegasasState *s, MegasasCmd *cmd);
-} dcmd_cmd_tbl[] = {
-    { MFI_DCMD_CTRL_MFI_HOST_MEM_ALLOC, "CTRL_HOST_MEM_ALLOC",
-      megasas_dcmd_dummy },
-    { MFI_DCMD_CTRL_GET_INFO, "CTRL_GET_INFO",
-      megasas_ctrl_get_info },
-    { MFI_DCMD_CTRL_GET_PROPERTIES, "CTRL_GET_PROPERTIES",
-      megasas_dcmd_get_properties },
-    { MFI_DCMD_CTRL_SET_PROPERTIES, "CTRL_SET_PROPERTIES",
-      megasas_dcmd_set_properties },
-    { MFI_DCMD_CTRL_ALARM_GET, "CTRL_ALARM_GET",
-      megasas_dcmd_dummy },
-    { MFI_DCMD_CTRL_ALARM_ENABLE, "CTRL_ALARM_ENABLE",
-      megasas_dcmd_dummy },
-    { MFI_DCMD_CTRL_ALARM_DISABLE, "CTRL_ALARM_DISABLE",
-      megasas_dcmd_dummy },
-    { MFI_DCMD_CTRL_ALARM_SILENCE, "CTRL_ALARM_SILENCE",
-      megasas_dcmd_dummy },
-    { MFI_DCMD_CTRL_ALARM_TEST, "CTRL_ALARM_TEST",
-      megasas_dcmd_dummy },
-    { MFI_DCMD_CTRL_EVENT_GETINFO, "CTRL_EVENT_GETINFO",
-      megasas_event_info },
-    { MFI_DCMD_CTRL_EVENT_GET, "CTRL_EVENT_GET",
-      megasas_dcmd_dummy },
-    { MFI_DCMD_CTRL_EVENT_WAIT, "CTRL_EVENT_WAIT",
-      megasas_event_wait },
-    { MFI_DCMD_CTRL_SHUTDOWN, "CTRL_SHUTDOWN",
-      megasas_ctrl_shutdown },
-    { MFI_DCMD_HIBERNATE_STANDBY, "CTRL_STANDBY",
-      megasas_dcmd_dummy },
-    { MFI_DCMD_CTRL_GET_TIME, "CTRL_GET_TIME",
-      megasas_dcmd_get_fw_time },
-    { MFI_DCMD_CTRL_SET_TIME, "CTRL_SET_TIME",
-      megasas_dcmd_set_fw_time },
-    { MFI_DCMD_CTRL_BIOS_DATA_GET, "CTRL_BIOS_DATA_GET",
-      megasas_dcmd_get_bios_info },
-    { MFI_DCMD_CTRL_FACTORY_DEFAULTS, "CTRL_FACTORY_DEFAULTS",
-      megasas_dcmd_dummy },
-    { MFI_DCMD_CTRL_MFC_DEFAULTS_GET, "CTRL_MFC_DEFAULTS_GET",
-      megasas_mfc_get_defaults },
-    { MFI_DCMD_CTRL_MFC_DEFAULTS_SET, "CTRL_MFC_DEFAULTS_SET",
-      megasas_dcmd_dummy },
-    { MFI_DCMD_CTRL_CACHE_FLUSH, "CTRL_CACHE_FLUSH",
-      megasas_cache_flush },
-    { MFI_DCMD_PD_GET_LIST, "PD_GET_LIST",
-      megasas_dcmd_pd_get_list },
-    { MFI_DCMD_PD_LIST_QUERY, "PD_LIST_QUERY",
-      megasas_dcmd_pd_list_query },
-    { MFI_DCMD_PD_GET_INFO, "PD_GET_INFO",
-      megasas_dcmd_pd_get_info },
-    { MFI_DCMD_PD_STATE_SET, "PD_STATE_SET",
-      megasas_dcmd_dummy },
-    { MFI_DCMD_PD_REBUILD, "PD_REBUILD",
-      megasas_dcmd_dummy },
-    { MFI_DCMD_PD_BLINK, "PD_BLINK",
-      megasas_dcmd_dummy },
-    { MFI_DCMD_PD_UNBLINK, "PD_UNBLINK",
-      megasas_dcmd_dummy },
-    { MFI_DCMD_LD_GET_LIST, "LD_GET_LIST",
-      megasas_dcmd_ld_get_list},
-    { MFI_DCMD_LD_GET_INFO, "LD_GET_INFO",
-      megasas_dcmd_ld_get_info },
-    { MFI_DCMD_LD_GET_PROP, "LD_GET_PROP",
-      megasas_dcmd_dummy },
-    { MFI_DCMD_LD_SET_PROP, "LD_SET_PROP",
-      megasas_dcmd_dummy },
-    { MFI_DCMD_LD_DELETE, "LD_DELETE",
-      megasas_dcmd_dummy },
-    { MFI_DCMD_CFG_READ, "CFG_READ",
-      megasas_dcmd_cfg_read },
-    { MFI_DCMD_CFG_ADD, "CFG_ADD",
-      megasas_dcmd_dummy },
-    { MFI_DCMD_CFG_CLEAR, "CFG_CLEAR",
-      megasas_dcmd_dummy },
-    { MFI_DCMD_CFG_FOREIGN_READ, "CFG_FOREIGN_READ",
-      megasas_dcmd_dummy },
-    { MFI_DCMD_CFG_FOREIGN_IMPORT, "CFG_FOREIGN_IMPORT",
-      megasas_dcmd_dummy },
-    { MFI_DCMD_BBU_STATUS, "BBU_STATUS",
-      megasas_dcmd_dummy },
-    { MFI_DCMD_BBU_CAPACITY_INFO, "BBU_CAPACITY_INFO",
-      megasas_dcmd_dummy },
-    { MFI_DCMD_BBU_DESIGN_INFO, "BBU_DESIGN_INFO",
-      megasas_dcmd_dummy },
-    { MFI_DCMD_BBU_PROP_GET, "BBU_PROP_GET",
-      megasas_dcmd_dummy },
-    { MFI_DCMD_CLUSTER, "CLUSTER",
-      megasas_dcmd_dummy },
-    { MFI_DCMD_CLUSTER_RESET_ALL, "CLUSTER_RESET_ALL",
-      megasas_dcmd_dummy },
-    { MFI_DCMD_CLUSTER_RESET_LD, "CLUSTER_RESET_LD",
-      megasas_cluster_reset_ld },
-    { -1, NULL, NULL }
-};
-
-static int megasas_handle_dcmd(MegasasState *s, MegasasCmd *cmd)
-{
-    int opcode, len;
-    int retval = 0;
-    const struct dcmd_cmd_tbl_t *cmdptr = dcmd_cmd_tbl;
-
-    opcode = le32_to_cpu(cmd->frame->dcmd.opcode);
-    trace_megasas_handle_dcmd(cmd->index, opcode);
-    len = megasas_map_dcmd(s, cmd);
-    if (len < 0) {
-        return MFI_STAT_MEMORY_NOT_AVAILABLE;
-    }
-    while (cmdptr->opcode != -1 && cmdptr->opcode != opcode) {
-        cmdptr++;
-    }
-    if (cmdptr->opcode == -1) {
-        trace_megasas_dcmd_unhandled(cmd->index, opcode, len);
-        retval = megasas_dcmd_dummy(s, cmd);
-    } else {
-        trace_megasas_dcmd_enter(cmd->index, cmdptr->desc, len);
-        retval = cmdptr->func(s, cmd);
-    }
-    if (retval != MFI_STAT_INVALID_STATUS) {
-        megasas_finish_dcmd(cmd, len);
-    }
-    return retval;
-}
-
-static int megasas_finish_internal_dcmd(MegasasCmd *cmd,
-                                        SCSIRequest *req)
-{
-    int opcode;
-    int retval = MFI_STAT_OK;
-    int lun = req->lun;
-
-    opcode = le32_to_cpu(cmd->frame->dcmd.opcode);
-    scsi_req_unref(req);
-    trace_megasas_dcmd_internal_finish(cmd->index, opcode, lun);
-    switch (opcode) {
-    case MFI_DCMD_PD_GET_INFO:
-        retval = megasas_pd_get_info_submit(req->dev, lun, cmd);
-        break;
-    case MFI_DCMD_LD_GET_INFO:
-        retval = megasas_ld_get_info_submit(req->dev, lun, cmd);
-        break;
-    default:
-        trace_megasas_dcmd_internal_invalid(cmd->index, opcode);
-        retval = MFI_STAT_INVALID_DCMD;
-        break;
-    }
-    if (retval != MFI_STAT_INVALID_STATUS) {
-        megasas_finish_dcmd(cmd, cmd->iov_size);
-    }
-    return retval;
-}
-
-static int megasas_enqueue_req(MegasasCmd *cmd, bool is_write)
-{
-    int len;
-
-    len = scsi_req_enqueue(cmd->req);
-    if (len < 0) {
-        len = -len;
-    }
-    if (len > 0) {
-        if (len > cmd->iov_size) {
-            if (is_write) {
-                trace_megasas_iov_write_overflow(cmd->index, len,
-                                                 cmd->iov_size);
-            } else {
-                trace_megasas_iov_read_overflow(cmd->index, len,
-                                                cmd->iov_size);
-            }
-        }
-        if (len < cmd->iov_size) {
-            if (is_write) {
-                trace_megasas_iov_write_underflow(cmd->index, len,
-                                                  cmd->iov_size);
-            } else {
-                trace_megasas_iov_read_underflow(cmd->index, len,
-                                                 cmd->iov_size);
-            }
-            cmd->iov_size = len;
-        }
-        scsi_req_continue(cmd->req);
-    }
-    return len;
-}
-
-static int megasas_handle_scsi(MegasasState *s, MegasasCmd *cmd,
-                               bool is_logical)
-{
-    uint8_t *cdb;
-    int len;
-    bool is_write;
-    struct SCSIDevice *sdev = NULL;
-
-    cdb = cmd->frame->pass.cdb;
-
-    if (cmd->frame->header.target_id < s->fw_luns) {
-        sdev = scsi_device_find(&s->bus, 0, cmd->frame->header.target_id,
-                                cmd->frame->header.lun_id);
-    }
-    cmd->iov_size = le32_to_cpu(cmd->frame->header.data_len);
-    trace_megasas_handle_scsi(mfi_frame_desc[cmd->frame->header.frame_cmd],
-                              is_logical, cmd->frame->header.target_id,
-                              cmd->frame->header.lun_id, sdev, cmd->iov_size);
-
-    if (!sdev || (megasas_is_jbod(s) && is_logical)) {
-        trace_megasas_scsi_target_not_present(
-            mfi_frame_desc[cmd->frame->header.frame_cmd], is_logical,
-            cmd->frame->header.target_id, cmd->frame->header.lun_id);
-        return MFI_STAT_DEVICE_NOT_FOUND;
-    }
-
-    if (cmd->frame->header.cdb_len > 16) {
-        trace_megasas_scsi_invalid_cdb_len(
-                mfi_frame_desc[cmd->frame->header.frame_cmd], is_logical,
-                cmd->frame->header.target_id, cmd->frame->header.lun_id,
-                cmd->frame->header.cdb_len);
-        megasas_write_sense(cmd, SENSE_CODE(INVALID_OPCODE));
-        cmd->frame->header.scsi_status = CHECK_CONDITION;
-        s->event_count++;
-        return MFI_STAT_SCSI_DONE_WITH_ERROR;
-    }
-
-    if (megasas_map_sgl(s, cmd, &cmd->frame->pass.sgl)) {
-        megasas_write_sense(cmd, SENSE_CODE(TARGET_FAILURE));
-        cmd->frame->header.scsi_status = CHECK_CONDITION;
-        s->event_count++;
-        return MFI_STAT_SCSI_DONE_WITH_ERROR;
-    }
-
-    cmd->req = scsi_req_new(sdev, cmd->index,
-                            cmd->frame->header.lun_id, cdb, cmd);
-    if (!cmd->req) {
-        trace_megasas_scsi_req_alloc_failed(
-                mfi_frame_desc[cmd->frame->header.frame_cmd],
-                cmd->frame->header.target_id, cmd->frame->header.lun_id);
-        megasas_write_sense(cmd, SENSE_CODE(NO_SENSE));
-        cmd->frame->header.scsi_status = BUSY;
-        s->event_count++;
-        return MFI_STAT_SCSI_DONE_WITH_ERROR;
-    }
-
-    is_write = (cmd->req->cmd.mode == SCSI_XFER_TO_DEV);
-    len = megasas_enqueue_req(cmd, is_write);
-    if (len > 0) {
-        if (is_write) {
-            trace_megasas_scsi_write_start(cmd->index, len);
-        } else {
-            trace_megasas_scsi_read_start(cmd->index, len);
-        }
-    } else {
-        trace_megasas_scsi_nodata(cmd->index);
-    }
-    return MFI_STAT_INVALID_STATUS;
-}
-
-static int megasas_handle_io(MegasasState *s, MegasasCmd *cmd)
-{
-    uint32_t lba_count, lba_start_hi, lba_start_lo;
-    uint64_t lba_start;
-    bool is_write = (cmd->frame->header.frame_cmd == MFI_CMD_LD_WRITE);
-    uint8_t cdb[16];
-    int len;
-    struct SCSIDevice *sdev = NULL;
-
-    lba_count = le32_to_cpu(cmd->frame->io.header.data_len);
-    lba_start_lo = le32_to_cpu(cmd->frame->io.lba_lo);
-    lba_start_hi = le32_to_cpu(cmd->frame->io.lba_hi);
-    lba_start = ((uint64_t)lba_start_hi << 32) | lba_start_lo;
-
-    if (cmd->frame->header.target_id < s->fw_luns) {
-        sdev = scsi_device_find(&s->bus, 0, cmd->frame->header.target_id,
-                                cmd->frame->header.lun_id);
-    }
-
-    trace_megasas_handle_io(cmd->index,
-                            mfi_frame_desc[cmd->frame->header.frame_cmd],
-                            cmd->frame->header.target_id,
-                            cmd->frame->header.lun_id,
-                            (unsigned long)lba_start, (unsigned long)lba_count);
-    if (!sdev) {
-        trace_megasas_io_target_not_present(cmd->index,
-            mfi_frame_desc[cmd->frame->header.frame_cmd],
-            cmd->frame->header.target_id, cmd->frame->header.lun_id);
-        return MFI_STAT_DEVICE_NOT_FOUND;
-    }
-
-    if (cmd->frame->header.cdb_len > 16) {
-        trace_megasas_scsi_invalid_cdb_len(
-            mfi_frame_desc[cmd->frame->header.frame_cmd], 1,
-            cmd->frame->header.target_id, cmd->frame->header.lun_id,
-            cmd->frame->header.cdb_len);
-        megasas_write_sense(cmd, SENSE_CODE(INVALID_OPCODE));
-        cmd->frame->header.scsi_status = CHECK_CONDITION;
-        s->event_count++;
-        return MFI_STAT_SCSI_DONE_WITH_ERROR;
-    }
-
-    cmd->iov_size = lba_count * sdev->blocksize;
-    if (megasas_map_sgl(s, cmd, &cmd->frame->io.sgl)) {
-        megasas_write_sense(cmd, SENSE_CODE(TARGET_FAILURE));
-        cmd->frame->header.scsi_status = CHECK_CONDITION;
-        s->event_count++;
-        return MFI_STAT_SCSI_DONE_WITH_ERROR;
-    }
-
-    megasas_encode_lba(cdb, lba_start, lba_count, is_write);
-    cmd->req = scsi_req_new(sdev, cmd->index,
-                            cmd->frame->header.lun_id, cdb, cmd);
-    if (!cmd->req) {
-        trace_megasas_scsi_req_alloc_failed(
-            mfi_frame_desc[cmd->frame->header.frame_cmd],
-            cmd->frame->header.target_id, cmd->frame->header.lun_id);
-        megasas_write_sense(cmd, SENSE_CODE(NO_SENSE));
-        cmd->frame->header.scsi_status = BUSY;
-        s->event_count++;
-        return MFI_STAT_SCSI_DONE_WITH_ERROR;
-    }
-    len = megasas_enqueue_req(cmd, is_write);
-    if (len > 0) {
-        if (is_write) {
-            trace_megasas_io_write_start(cmd->index, lba_start, lba_count, len);
-        } else {
-            trace_megasas_io_read_start(cmd->index, lba_start, lba_count, len);
-        }
-    }
-    return MFI_STAT_INVALID_STATUS;
-}
-
-static int megasas_finish_internal_command(MegasasCmd *cmd,
-                                           SCSIRequest *req, size_t resid)
-{
-    int retval = MFI_STAT_INVALID_CMD;
-
-    if (cmd->frame->header.frame_cmd == MFI_CMD_DCMD) {
-        cmd->iov_size -= resid;
-        retval = megasas_finish_internal_dcmd(cmd, req);
-    }
-    return retval;
-}
-
-static QEMUSGList *megasas_get_sg_list(SCSIRequest *req)
-{
-    MegasasCmd *cmd = req->hba_private;
-
-    if (cmd->frame->header.frame_cmd == MFI_CMD_DCMD) {
-        return NULL;
-    } else {
-        return &cmd->qsg;
-    }
-}
-
-static void megasas_xfer_complete(SCSIRequest *req, uint32_t len)
-{
-    MegasasCmd *cmd = req->hba_private;
-    uint8_t *buf;
-    uint32_t opcode;
-
-    trace_megasas_io_complete(cmd->index, len);
-
-    if (cmd->frame->header.frame_cmd != MFI_CMD_DCMD) {
-        scsi_req_continue(req);
-        return;
-    }
-
-    buf = scsi_req_get_buf(req);
-    opcode = le32_to_cpu(cmd->frame->dcmd.opcode);
-    if (opcode == MFI_DCMD_PD_GET_INFO && cmd->iov_buf) {
-        struct mfi_pd_info *info = cmd->iov_buf;
-
-        if (info->inquiry_data[0] == 0x7f) {
-            memset(info->inquiry_data, 0, sizeof(info->inquiry_data));
-            memcpy(info->inquiry_data, buf, len);
-        } else if (info->vpd_page83[0] == 0x7f) {
-            memset(info->vpd_page83, 0, sizeof(info->vpd_page83));
-            memcpy(info->vpd_page83, buf, len);
-        }
-        scsi_req_continue(req);
-    } else if (opcode == MFI_DCMD_LD_GET_INFO) {
-        struct mfi_ld_info *info = cmd->iov_buf;
-
-        if (cmd->iov_buf) {
-            memcpy(info->vpd_page83, buf, sizeof(info->vpd_page83));
-            scsi_req_continue(req);
-        }
-    }
-}
-
-static void megasas_command_complete(SCSIRequest *req, uint32_t status,
-                                     size_t resid)
-{
-    MegasasCmd *cmd = req->hba_private;
-    uint8_t cmd_status = MFI_STAT_OK;
-
-    trace_megasas_command_complete(cmd->index, status, resid);
-
-    if (cmd->req != req) {
-        /*
-         * Internal command complete
-         */
-        cmd_status = megasas_finish_internal_command(cmd, req, resid);
-        if (cmd_status == MFI_STAT_INVALID_STATUS) {
-            return;
-        }
-    } else {
-        req->status = status;
-        trace_megasas_scsi_complete(cmd->index, req->status,
-                                    cmd->iov_size, req->cmd.xfer);
-        if (req->status != GOOD) {
-            cmd_status = MFI_STAT_SCSI_DONE_WITH_ERROR;
-        }
-        if (req->status == CHECK_CONDITION) {
-            megasas_copy_sense(cmd);
-        }
-
-        megasas_unmap_sgl(cmd);
-        cmd->frame->header.scsi_status = req->status;
-        scsi_req_unref(cmd->req);
-        cmd->req = NULL;
-    }
-    cmd->frame->header.cmd_status = cmd_status;
-    megasas_complete_frame(cmd->state, cmd->context);
-}
-
-static void megasas_command_cancel(SCSIRequest *req)
-{
-    MegasasCmd *cmd = req->hba_private;
-
-    if (cmd) {
-        megasas_abort_command(cmd);
-    } else {
-        scsi_req_unref(req);
-    }
-}
-
-static int megasas_handle_abort(MegasasState *s, MegasasCmd *cmd)
-{
-    uint64_t abort_ctx = le64_to_cpu(cmd->frame->abort.abort_context);
-    hwaddr abort_addr, addr_hi, addr_lo;
-    MegasasCmd *abort_cmd;
-
-    addr_hi = le32_to_cpu(cmd->frame->abort.abort_mfi_addr_hi);
-    addr_lo = le32_to_cpu(cmd->frame->abort.abort_mfi_addr_lo);
-    abort_addr = ((uint64_t)addr_hi << 32) | addr_lo;
-
-    abort_cmd = megasas_lookup_frame(s, abort_addr);
-    if (!abort_cmd) {
-        trace_megasas_abort_no_cmd(cmd->index, abort_ctx);
-        s->event_count++;
-        return MFI_STAT_OK;
-    }
-    if (!megasas_use_queue64(s)) {
-        abort_ctx &= (uint64_t)0xFFFFFFFF;
-    }
-    if (abort_cmd->context != abort_ctx) {
-        trace_megasas_abort_invalid_context(cmd->index, abort_cmd->index,
-                                            abort_cmd->context);
-        s->event_count++;
-        return MFI_STAT_ABORT_NOT_POSSIBLE;
-    }
-    trace_megasas_abort_frame(cmd->index, abort_cmd->index);
-    megasas_abort_command(abort_cmd);
-    if (!s->event_cmd || abort_cmd != s->event_cmd) {
-        s->event_cmd = NULL;
-    }
-    s->event_count++;
-    return MFI_STAT_OK;
-}
-
-static void megasas_handle_frame(MegasasState *s, uint64_t frame_addr,
-                                 uint32_t frame_count)
-{
-    uint8_t frame_status = MFI_STAT_INVALID_CMD;
-    uint64_t frame_context;
-    MegasasCmd *cmd;
-
-    /*
-     * Always read 64bit context, top bits will be
-     * masked out if required in megasas_enqueue_frame()
-     */
-    frame_context = megasas_frame_get_context(frame_addr);
-
-    cmd = megasas_enqueue_frame(s, frame_addr, frame_context, frame_count);
-    if (!cmd) {
-        /* reply queue full */
-        trace_megasas_frame_busy(frame_addr);
-        megasas_frame_set_scsi_status(frame_addr, BUSY);
-        megasas_frame_set_cmd_status(frame_addr, MFI_STAT_SCSI_DONE_WITH_ERROR);
-        megasas_complete_frame(s, frame_context);
-        s->event_count++;
-        return;
-    }
-    switch (cmd->frame->header.frame_cmd) {
-    case MFI_CMD_INIT:
-        frame_status = megasas_init_firmware(s, cmd);
-        break;
-    case MFI_CMD_DCMD:
-        frame_status = megasas_handle_dcmd(s, cmd);
-        break;
-    case MFI_CMD_ABORT:
-        frame_status = megasas_handle_abort(s, cmd);
-        break;
-    case MFI_CMD_PD_SCSI_IO:
-        frame_status = megasas_handle_scsi(s, cmd, 0);
-        break;
-    case MFI_CMD_LD_SCSI_IO:
-        frame_status = megasas_handle_scsi(s, cmd, 1);
-        break;
-    case MFI_CMD_LD_READ:
-    case MFI_CMD_LD_WRITE:
-        frame_status = megasas_handle_io(s, cmd);
-        break;
-    default:
-        trace_megasas_unhandled_frame_cmd(cmd->index,
-                                          cmd->frame->header.frame_cmd);
-        s->event_count++;
-        break;
-    }
-    if (frame_status != MFI_STAT_INVALID_STATUS) {
-        if (cmd->frame) {
-            cmd->frame->header.cmd_status = frame_status;
-        } else {
-            megasas_frame_set_cmd_status(frame_addr, frame_status);
-        }
-        megasas_complete_frame(s, cmd->context);
-    }
-}
-
-static uint64_t megasas_mmio_read(void *opaque, hwaddr addr,
-                                  unsigned size)
-{
-    MegasasState *s = opaque;
-    uint32_t retval = 0;
-
-    switch (addr) {
-    case MFI_IDB:
-        retval = 0;
-        break;
-    case MFI_OMSG0:
-    case MFI_OSP0:
-        retval = (megasas_use_msix(s) ? MFI_FWSTATE_MSIX_SUPPORTED : 0) |
-            (s->fw_state & MFI_FWSTATE_MASK) |
-            ((s->fw_sge & 0xff) << 16) |
-            (s->fw_cmds & 0xFFFF);
-        break;
-    case MFI_OSTS:
-        if (megasas_intr_enabled(s) && s->doorbell) {
-            retval = MFI_1078_RM | 1;
-        }
-        break;
-    case MFI_OMSK:
-        retval = s->intr_mask;
-        break;
-    case MFI_ODCR0:
-        retval = s->doorbell;
-        break;
-    default:
-        trace_megasas_mmio_invalid_readl(addr);
-        break;
-    }
-    trace_megasas_mmio_readl(addr, retval);
-    return retval;
-}
-
-static void megasas_mmio_write(void *opaque, hwaddr addr,
-                               uint64_t val, unsigned size)
-{
-    MegasasState *s = opaque;
-    uint64_t frame_addr;
-    uint32_t frame_count;
-    int i;
-
-    trace_megasas_mmio_writel(addr, val);
-    switch (addr) {
-    case MFI_IDB:
-        if (val & MFI_FWINIT_ABORT) {
-            /* Abort all pending cmds */
-            for (i = 0; i < s->fw_cmds; i++) {
-                megasas_abort_command(&s->frames[i]);
-            }
-        }
-        if (val & MFI_FWINIT_READY) {
-            /* move to FW READY */
-            megasas_soft_reset(s);
-        }
-        if (val & MFI_FWINIT_MFIMODE) {
-            /* discard MFIs */
-        }
-        break;
-    case MFI_OMSK:
-        s->intr_mask = val;
-        if (!megasas_intr_enabled(s) && !msix_enabled(&s->dev)) {
-            trace_megasas_irq_lower();
-            qemu_irq_lower(s->dev.irq[0]);
-        }
-        if (megasas_intr_enabled(s)) {
-            trace_megasas_intr_enabled();
-        } else {
-            trace_megasas_intr_disabled();
-        }
-        break;
-    case MFI_ODCR0:
-        s->doorbell = 0;
-        if (s->producer_pa && megasas_intr_enabled(s)) {
-            /* Update reply queue pointer */
-            trace_megasas_qf_update(s->reply_queue_head, s->busy);
-            stl_le_phys(s->producer_pa, s->reply_queue_head);
-            if (!msix_enabled(&s->dev)) {
-                trace_megasas_irq_lower();
-                qemu_irq_lower(s->dev.irq[0]);
-            }
-        }
-        break;
-    case MFI_IQPH:
-        /* Received high 32 bits of a 64 bit MFI frame address */
-        s->frame_hi = val;
-        break;
-    case MFI_IQPL:
-        /* Received low 32 bits of a 64 bit MFI frame address */
-    case MFI_IQP:
-        /* Received 32 bit MFI frame address */
-        frame_addr = (val & ~0x1F);
-        /* Add possible 64 bit offset */
-        frame_addr |= ((uint64_t)s->frame_hi << 32);
-        s->frame_hi = 0;
-        frame_count = (val >> 1) & 0xF;
-        megasas_handle_frame(s, frame_addr, frame_count);
-        break;
-    default:
-        trace_megasas_mmio_invalid_writel(addr, val);
-        break;
-    }
-}
-
-static const MemoryRegionOps megasas_mmio_ops = {
-    .read = megasas_mmio_read,
-    .write = megasas_mmio_write,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-    .impl = {
-        .min_access_size = 8,
-        .max_access_size = 8,
-    }
-};
-
-static uint64_t megasas_port_read(void *opaque, hwaddr addr,
-                                  unsigned size)
-{
-    return megasas_mmio_read(opaque, addr & 0xff, size);
-}
-
-static void megasas_port_write(void *opaque, hwaddr addr,
-                               uint64_t val, unsigned size)
-{
-    megasas_mmio_write(opaque, addr & 0xff, val, size);
-}
-
-static const MemoryRegionOps megasas_port_ops = {
-    .read = megasas_port_read,
-    .write = megasas_port_write,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-    .impl = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    }
-};
-
-static uint64_t megasas_queue_read(void *opaque, hwaddr addr,
-                                   unsigned size)
-{
-    return 0;
-}
-
-static const MemoryRegionOps megasas_queue_ops = {
-    .read = megasas_queue_read,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-    .impl = {
-        .min_access_size = 8,
-        .max_access_size = 8,
-    }
-};
-
-static void megasas_soft_reset(MegasasState *s)
-{
-    int i;
-    MegasasCmd *cmd;
-
-    trace_megasas_reset();
-    for (i = 0; i < s->fw_cmds; i++) {
-        cmd = &s->frames[i];
-        megasas_abort_command(cmd);
-    }
-    megasas_reset_frames(s);
-    s->reply_queue_len = s->fw_cmds;
-    s->reply_queue_pa = 0;
-    s->consumer_pa = 0;
-    s->producer_pa = 0;
-    s->fw_state = MFI_FWSTATE_READY;
-    s->doorbell = 0;
-    s->intr_mask = MEGASAS_INTR_DISABLED_MASK;
-    s->frame_hi = 0;
-    s->flags &= ~MEGASAS_MASK_USE_QUEUE64;
-    s->event_count++;
-    s->boot_event = s->event_count;
-}
-
-static void megasas_scsi_reset(DeviceState *dev)
-{
-    MegasasState *s = DO_UPCAST(MegasasState, dev.qdev, dev);
-
-    megasas_soft_reset(s);
-}
-
-static const VMStateDescription vmstate_megasas = {
-    .name = "megasas",
-    .version_id = 0,
-    .minimum_version_id = 0,
-    .minimum_version_id_old = 0,
-    .fields      = (VMStateField[]) {
-        VMSTATE_PCI_DEVICE(dev, MegasasState),
-
-        VMSTATE_INT32(fw_state, MegasasState),
-        VMSTATE_INT32(intr_mask, MegasasState),
-        VMSTATE_INT32(doorbell, MegasasState),
-        VMSTATE_UINT64(reply_queue_pa, MegasasState),
-        VMSTATE_UINT64(consumer_pa, MegasasState),
-        VMSTATE_UINT64(producer_pa, MegasasState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void megasas_scsi_uninit(PCIDevice *d)
-{
-    MegasasState *s = DO_UPCAST(MegasasState, dev, d);
-
-#ifdef USE_MSIX
-    msix_uninit(&s->dev, &s->mmio_io);
-#endif
-    memory_region_destroy(&s->mmio_io);
-    memory_region_destroy(&s->port_io);
-    memory_region_destroy(&s->queue_io);
-}
-
-static const struct SCSIBusInfo megasas_scsi_info = {
-    .tcq = true,
-    .max_target = MFI_MAX_LD,
-    .max_lun = 255,
-
-    .transfer_data = megasas_xfer_complete,
-    .get_sg_list = megasas_get_sg_list,
-    .complete = megasas_command_complete,
-    .cancel = megasas_command_cancel,
-};
-
-static int megasas_scsi_init(PCIDevice *dev)
-{
-    MegasasState *s = DO_UPCAST(MegasasState, dev, dev);
-    uint8_t *pci_conf;
-    int i, bar_type;
-
-    pci_conf = s->dev.config;
-
-    /* PCI latency timer = 0 */
-    pci_conf[PCI_LATENCY_TIMER] = 0;
-    /* Interrupt pin 1 */
-    pci_conf[PCI_INTERRUPT_PIN] = 0x01;
-
-    memory_region_init_io(&s->mmio_io, &megasas_mmio_ops, s,
-                          "megasas-mmio", 0x4000);
-    memory_region_init_io(&s->port_io, &megasas_port_ops, s,
-                          "megasas-io", 256);
-    memory_region_init_io(&s->queue_io, &megasas_queue_ops, s,
-                          "megasas-queue", 0x40000);
-
-#ifdef USE_MSIX
-    /* MSI-X support is currently broken */
-    if (megasas_use_msix(s) &&
-        msix_init(&s->dev, 15, &s->mmio_io, 0, 0x2000)) {
-        s->flags &= ~MEGASAS_MASK_USE_MSIX;
-    }
-#else
-    s->flags &= ~MEGASAS_MASK_USE_MSIX;
-#endif
-
-    bar_type = PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64;
-    pci_register_bar(&s->dev, 0, bar_type, &s->mmio_io);
-    pci_register_bar(&s->dev, 2, PCI_BASE_ADDRESS_SPACE_IO, &s->port_io);
-    pci_register_bar(&s->dev, 3, bar_type, &s->queue_io);
-
-    if (megasas_use_msix(s)) {
-        msix_vector_use(&s->dev, 0);
-    }
-
-    if (!s->sas_addr) {
-        s->sas_addr = ((NAA_LOCALLY_ASSIGNED_ID << 24) |
-                       IEEE_COMPANY_LOCALLY_ASSIGNED) << 36;
-        s->sas_addr |= (pci_bus_num(dev->bus) << 16);
-        s->sas_addr |= (PCI_SLOT(dev->devfn) << 8);
-        s->sas_addr |= PCI_FUNC(dev->devfn);
-    }
-    if (!s->hba_serial) {
-       s->hba_serial = g_strdup(MEGASAS_HBA_SERIAL);
-    }
-    if (s->fw_sge >= MEGASAS_MAX_SGE - MFI_PASS_FRAME_SIZE) {
-        s->fw_sge = MEGASAS_MAX_SGE - MFI_PASS_FRAME_SIZE;
-    } else if (s->fw_sge >= 128 - MFI_PASS_FRAME_SIZE) {
-        s->fw_sge = 128 - MFI_PASS_FRAME_SIZE;
-    } else {
-        s->fw_sge = 64 - MFI_PASS_FRAME_SIZE;
-    }
-    if (s->fw_cmds > MEGASAS_MAX_FRAMES) {
-        s->fw_cmds = MEGASAS_MAX_FRAMES;
-    }
-    trace_megasas_init(s->fw_sge, s->fw_cmds,
-                       megasas_use_msix(s) ? "MSI-X" : "INTx",
-                       megasas_is_jbod(s) ? "jbod" : "raid");
-    s->fw_luns = (MFI_MAX_LD > MAX_SCSI_DEVS) ?
-        MAX_SCSI_DEVS : MFI_MAX_LD;
-    s->producer_pa = 0;
-    s->consumer_pa = 0;
-    for (i = 0; i < s->fw_cmds; i++) {
-        s->frames[i].index = i;
-        s->frames[i].context = -1;
-        s->frames[i].pa = 0;
-        s->frames[i].state = s;
-    }
-
-    scsi_bus_new(&s->bus, &dev->qdev, &megasas_scsi_info);
-    scsi_bus_legacy_handle_cmdline(&s->bus);
-    return 0;
-}
-
-static Property megasas_properties[] = {
-    DEFINE_PROP_UINT32("max_sge", MegasasState, fw_sge,
-                       MEGASAS_DEFAULT_SGE),
-    DEFINE_PROP_UINT32("max_cmds", MegasasState, fw_cmds,
-                       MEGASAS_DEFAULT_FRAMES),
-    DEFINE_PROP_STRING("hba_serial", MegasasState, hba_serial),
-    DEFINE_PROP_HEX64("sas_address", MegasasState, sas_addr, 0),
-#ifdef USE_MSIX
-    DEFINE_PROP_BIT("use_msix", MegasasState, flags,
-                    MEGASAS_FLAG_USE_MSIX, false),
-#endif
-    DEFINE_PROP_BIT("use_jbod", MegasasState, flags,
-                    MEGASAS_FLAG_USE_JBOD, false),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void megasas_class_init(ObjectClass *oc, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(oc);
-    PCIDeviceClass *pc = PCI_DEVICE_CLASS(oc);
-
-    pc->init = megasas_scsi_init;
-    pc->exit = megasas_scsi_uninit;
-    pc->vendor_id = PCI_VENDOR_ID_LSI_LOGIC;
-    pc->device_id = PCI_DEVICE_ID_LSI_SAS1078;
-    pc->subsystem_vendor_id = PCI_VENDOR_ID_LSI_LOGIC;
-    pc->subsystem_id = 0x1013;
-    pc->class_id = PCI_CLASS_STORAGE_RAID;
-    dc->props = megasas_properties;
-    dc->reset = megasas_scsi_reset;
-    dc->vmsd = &vmstate_megasas;
-    dc->desc = "LSI MegaRAID SAS 1078";
-}
-
-static const TypeInfo megasas_info = {
-    .name  = "megasas",
-    .parent = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(MegasasState),
-    .class_init = megasas_class_init,
-};
-
-static void megasas_register_types(void)
-{
-    type_register_static(&megasas_info);
-}
-
-type_init(megasas_register_types)
diff --git a/hw/mfi.h b/hw/mfi.h
deleted file mode 100644 (file)
index cd8355b..0000000
--- a/hw/mfi.h
+++ /dev/null
@@ -1,1249 +0,0 @@
-/*
- * NetBSD header file, copied from
- * http://gitorious.org/freebsd/freebsd/blobs/HEAD/sys/dev/mfi/mfireg.h
- */
-/*-
- * Copyright (c) 2006 IronPort Systems
- * Copyright (c) 2007 LSI Corp.
- * Copyright (c) 2007 Rajesh Prabhakaran.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#ifndef MFI_REG_H
-#define MFI_REG_H
-
-/*
- * MegaRAID SAS MFI firmware definitions
- */
-
-/*
- * Start with the register set.  All registers are 32 bits wide.
- * The usual Intel IOP style setup.
- */
-#define MFI_IMSG0 0x10    /* Inbound message 0 */
-#define MFI_IMSG1 0x14    /* Inbound message 1 */
-#define MFI_OMSG0 0x18    /* Outbound message 0 */
-#define MFI_OMSG1 0x1c    /* Outbound message 1 */
-#define MFI_IDB   0x20    /* Inbound doorbell */
-#define MFI_ISTS  0x24    /* Inbound interrupt status */
-#define MFI_IMSK  0x28    /* Inbound interrupt mask */
-#define MFI_ODB   0x2c    /* Outbound doorbell */
-#define MFI_OSTS  0x30    /* Outbound interrupt status */
-#define MFI_OMSK  0x34    /* Outbound interrupt mask */
-#define MFI_IQP   0x40    /* Inbound queue port */
-#define MFI_OQP   0x44    /* Outbound queue port */
-
-/*
- * 1078 specific related register
- */
-#define MFI_ODR0        0x9c            /* outbound doorbell register0 */
-#define MFI_ODCR0       0xa0            /* outbound doorbell clear register0  */
-#define MFI_OSP0        0xb0            /* outbound scratch pad0  */
-#define MFI_IQPL        0xc0            /* Inbound queue port (low bytes)  */
-#define MFI_IQPH        0xc4            /* Inbound queue port (high bytes)  */
-#define MFI_DIAG        0xf8            /* Host diag */
-#define MFI_SEQ         0xfc            /* Sequencer offset */
-#define MFI_1078_EIM    0x80000004      /* 1078 enable intrrupt mask  */
-#define MFI_RMI         0x2             /* reply message interrupt  */
-#define MFI_1078_RM     0x80000000      /* reply 1078 message interrupt  */
-#define MFI_ODC         0x4             /* outbound doorbell change interrupt */
-
-/*
- * gen2 specific changes
- */
-#define MFI_GEN2_EIM    0x00000005      /* gen2 enable interrupt mask */
-#define MFI_GEN2_RM     0x00000001      /* reply gen2 message interrupt */
-
-/*
- * skinny specific changes
- */
-#define MFI_SKINNY_IDB  0x00    /* Inbound doorbell is at 0x00 for skinny */
-#define MFI_SKINNY_RM   0x00000001      /* reply skinny message interrupt */
-
-/* Bits for MFI_OSTS */
-#define MFI_OSTS_INTR_VALID     0x00000002
-
-/*
- * Firmware state values.  Found in OMSG0 during initialization.
- */
-#define MFI_FWSTATE_MASK                0xf0000000
-#define MFI_FWSTATE_UNDEFINED           0x00000000
-#define MFI_FWSTATE_BB_INIT             0x10000000
-#define MFI_FWSTATE_FW_INIT             0x40000000
-#define MFI_FWSTATE_WAIT_HANDSHAKE      0x60000000
-#define MFI_FWSTATE_FW_INIT_2           0x70000000
-#define MFI_FWSTATE_DEVICE_SCAN         0x80000000
-#define MFI_FWSTATE_BOOT_MSG_PENDING    0x90000000
-#define MFI_FWSTATE_FLUSH_CACHE         0xa0000000
-#define MFI_FWSTATE_READY               0xb0000000
-#define MFI_FWSTATE_OPERATIONAL         0xc0000000
-#define MFI_FWSTATE_FAULT               0xf0000000
-#define MFI_FWSTATE_MAXSGL_MASK         0x00ff0000
-#define MFI_FWSTATE_MAXCMD_MASK         0x0000ffff
-#define MFI_FWSTATE_MSIX_SUPPORTED      0x04000000
-#define MFI_FWSTATE_HOSTMEMREQD_MASK    0x08000000
-
-/*
- * Control bits to drive the card to ready state.  These go into the IDB
- * register.
- */
-#define MFI_FWINIT_ABORT        0x00000001 /* Abort all pending commands */
-#define MFI_FWINIT_READY        0x00000002 /* Move from operational to ready */
-#define MFI_FWINIT_MFIMODE      0x00000004 /* unknown */
-#define MFI_FWINIT_CLEAR_HANDSHAKE 0x00000008 /* Respond to WAIT_HANDSHAKE */
-#define MFI_FWINIT_HOTPLUG      0x00000010
-#define MFI_FWINIT_STOP_ADP     0x00000020 /* Move to operational, stop */
-#define MFI_FWINIT_ADP_RESET    0x00000040 /* Reset ADP */
-
-/* MFI Commands */
-typedef enum {
-    MFI_CMD_INIT = 0x00,
-    MFI_CMD_LD_READ,
-    MFI_CMD_LD_WRITE,
-    MFI_CMD_LD_SCSI_IO,
-    MFI_CMD_PD_SCSI_IO,
-    MFI_CMD_DCMD,
-    MFI_CMD_ABORT,
-    MFI_CMD_SMP,
-    MFI_CMD_STP
-} mfi_cmd_t;
-
-/* Direct commands */
-typedef enum {
-    MFI_DCMD_CTRL_MFI_HOST_MEM_ALLOC =  0x0100e100,
-    MFI_DCMD_CTRL_GET_INFO =            0x01010000,
-    MFI_DCMD_CTRL_GET_PROPERTIES =      0x01020100,
-    MFI_DCMD_CTRL_SET_PROPERTIES =      0x01020200,
-    MFI_DCMD_CTRL_ALARM =               0x01030000,
-    MFI_DCMD_CTRL_ALARM_GET =           0x01030100,
-    MFI_DCMD_CTRL_ALARM_ENABLE =        0x01030200,
-    MFI_DCMD_CTRL_ALARM_DISABLE =       0x01030300,
-    MFI_DCMD_CTRL_ALARM_SILENCE =       0x01030400,
-    MFI_DCMD_CTRL_ALARM_TEST =          0x01030500,
-    MFI_DCMD_CTRL_EVENT_GETINFO =       0x01040100,
-    MFI_DCMD_CTRL_EVENT_CLEAR =         0x01040200,
-    MFI_DCMD_CTRL_EVENT_GET =           0x01040300,
-    MFI_DCMD_CTRL_EVENT_COUNT =         0x01040400,
-    MFI_DCMD_CTRL_EVENT_WAIT =          0x01040500,
-    MFI_DCMD_CTRL_SHUTDOWN =            0x01050000,
-    MFI_DCMD_HIBERNATE_STANDBY =        0x01060000,
-    MFI_DCMD_CTRL_GET_TIME =            0x01080101,
-    MFI_DCMD_CTRL_SET_TIME =            0x01080102,
-    MFI_DCMD_CTRL_BIOS_DATA_GET =       0x010c0100,
-    MFI_DCMD_CTRL_BIOS_DATA_SET =       0x010c0200,
-    MFI_DCMD_CTRL_FACTORY_DEFAULTS =    0x010d0000,
-    MFI_DCMD_CTRL_MFC_DEFAULTS_GET =    0x010e0201,
-    MFI_DCMD_CTRL_MFC_DEFAULTS_SET =    0x010e0202,
-    MFI_DCMD_CTRL_CACHE_FLUSH =         0x01101000,
-    MFI_DCMD_PD_GET_LIST =              0x02010000,
-    MFI_DCMD_PD_LIST_QUERY =            0x02010100,
-    MFI_DCMD_PD_GET_INFO =              0x02020000,
-    MFI_DCMD_PD_STATE_SET =             0x02030100,
-    MFI_DCMD_PD_REBUILD =               0x02040100,
-    MFI_DCMD_PD_BLINK =                 0x02070100,
-    MFI_DCMD_PD_UNBLINK =               0x02070200,
-    MFI_DCMD_LD_GET_LIST =              0x03010000,
-    MFI_DCMD_LD_GET_INFO =              0x03020000,
-    MFI_DCMD_LD_GET_PROP =              0x03030000,
-    MFI_DCMD_LD_SET_PROP =              0x03040000,
-    MFI_DCMD_LD_DELETE =                0x03090000,
-    MFI_DCMD_CFG_READ =                 0x04010000,
-    MFI_DCMD_CFG_ADD =                  0x04020000,
-    MFI_DCMD_CFG_CLEAR =                0x04030000,
-    MFI_DCMD_CFG_FOREIGN_READ =         0x04060100,
-    MFI_DCMD_CFG_FOREIGN_IMPORT =       0x04060400,
-    MFI_DCMD_BBU_STATUS =               0x05010000,
-    MFI_DCMD_BBU_CAPACITY_INFO =        0x05020000,
-    MFI_DCMD_BBU_DESIGN_INFO =          0x05030000,
-    MFI_DCMD_BBU_PROP_GET =             0x05050100,
-    MFI_DCMD_CLUSTER =                  0x08000000,
-    MFI_DCMD_CLUSTER_RESET_ALL =        0x08010100,
-    MFI_DCMD_CLUSTER_RESET_LD =         0x08010200
-} mfi_dcmd_t;
-
-/* Modifiers for MFI_DCMD_CTRL_FLUSHCACHE */
-#define MFI_FLUSHCACHE_CTRL     0x01
-#define MFI_FLUSHCACHE_DISK     0x02
-
-/* Modifiers for MFI_DCMD_CTRL_SHUTDOWN */
-#define MFI_SHUTDOWN_SPINDOWN   0x01
-
-/*
- * MFI Frame flags
- */
-typedef enum {
-    MFI_FRAME_DONT_POST_IN_REPLY_QUEUE =        0x0001,
-    MFI_FRAME_SGL64 =                           0x0002,
-    MFI_FRAME_SENSE64 =                         0x0004,
-    MFI_FRAME_DIR_WRITE =                       0x0008,
-    MFI_FRAME_DIR_READ =                        0x0010,
-    MFI_FRAME_IEEE_SGL =                        0x0020,
-} mfi_frame_flags;
-
-/* MFI Status codes */
-typedef enum {
-    MFI_STAT_OK =                       0x00,
-    MFI_STAT_INVALID_CMD,
-    MFI_STAT_INVALID_DCMD,
-    MFI_STAT_INVALID_PARAMETER,
-    MFI_STAT_INVALID_SEQUENCE_NUMBER,
-    MFI_STAT_ABORT_NOT_POSSIBLE,
-    MFI_STAT_APP_HOST_CODE_NOT_FOUND,
-    MFI_STAT_APP_IN_USE,
-    MFI_STAT_APP_NOT_INITIALIZED,
-    MFI_STAT_ARRAY_INDEX_INVALID,
-    MFI_STAT_ARRAY_ROW_NOT_EMPTY,
-    MFI_STAT_CONFIG_RESOURCE_CONFLICT,
-    MFI_STAT_DEVICE_NOT_FOUND,
-    MFI_STAT_DRIVE_TOO_SMALL,
-    MFI_STAT_FLASH_ALLOC_FAIL,
-    MFI_STAT_FLASH_BUSY,
-    MFI_STAT_FLASH_ERROR =              0x10,
-    MFI_STAT_FLASH_IMAGE_BAD,
-    MFI_STAT_FLASH_IMAGE_INCOMPLETE,
-    MFI_STAT_FLASH_NOT_OPEN,
-    MFI_STAT_FLASH_NOT_STARTED,
-    MFI_STAT_FLUSH_FAILED,
-    MFI_STAT_HOST_CODE_NOT_FOUNT,
-    MFI_STAT_LD_CC_IN_PROGRESS,
-    MFI_STAT_LD_INIT_IN_PROGRESS,
-    MFI_STAT_LD_LBA_OUT_OF_RANGE,
-    MFI_STAT_LD_MAX_CONFIGURED,
-    MFI_STAT_LD_NOT_OPTIMAL,
-    MFI_STAT_LD_RBLD_IN_PROGRESS,
-    MFI_STAT_LD_RECON_IN_PROGRESS,
-    MFI_STAT_LD_WRONG_RAID_LEVEL,
-    MFI_STAT_MAX_SPARES_EXCEEDED,
-    MFI_STAT_MEMORY_NOT_AVAILABLE =     0x20,
-    MFI_STAT_MFC_HW_ERROR,
-    MFI_STAT_NO_HW_PRESENT,
-    MFI_STAT_NOT_FOUND,
-    MFI_STAT_NOT_IN_ENCL,
-    MFI_STAT_PD_CLEAR_IN_PROGRESS,
-    MFI_STAT_PD_TYPE_WRONG,
-    MFI_STAT_PR_DISABLED,
-    MFI_STAT_ROW_INDEX_INVALID,
-    MFI_STAT_SAS_CONFIG_INVALID_ACTION,
-    MFI_STAT_SAS_CONFIG_INVALID_DATA,
-    MFI_STAT_SAS_CONFIG_INVALID_PAGE,
-    MFI_STAT_SAS_CONFIG_INVALID_TYPE,
-    MFI_STAT_SCSI_DONE_WITH_ERROR,
-    MFI_STAT_SCSI_IO_FAILED,
-    MFI_STAT_SCSI_RESERVATION_CONFLICT,
-    MFI_STAT_SHUTDOWN_FAILED =          0x30,
-    MFI_STAT_TIME_NOT_SET,
-    MFI_STAT_WRONG_STATE,
-    MFI_STAT_LD_OFFLINE,
-    MFI_STAT_PEER_NOTIFICATION_REJECTED,
-    MFI_STAT_PEER_NOTIFICATION_FAILED,
-    MFI_STAT_RESERVATION_IN_PROGRESS,
-    MFI_STAT_I2C_ERRORS_DETECTED,
-    MFI_STAT_PCI_ERRORS_DETECTED,
-    MFI_STAT_DIAG_FAILED,
-    MFI_STAT_BOOT_MSG_PENDING,
-    MFI_STAT_FOREIGN_CONFIG_INCOMPLETE,
-    MFI_STAT_INVALID_SGL,
-    MFI_STAT_UNSUPPORTED_HW,
-    MFI_STAT_CC_SCHEDULE_DISABLED,
-    MFI_STAT_PD_COPYBACK_IN_PROGRESS,
-    MFI_STAT_MULTIPLE_PDS_IN_ARRAY =    0x40,
-    MFI_STAT_FW_DOWNLOAD_ERROR,
-    MFI_STAT_FEATURE_SECURITY_NOT_ENABLED,
-    MFI_STAT_LOCK_KEY_ALREADY_EXISTS,
-    MFI_STAT_LOCK_KEY_BACKUP_NOT_ALLOWED,
-    MFI_STAT_LOCK_KEY_VERIFY_NOT_ALLOWED,
-    MFI_STAT_LOCK_KEY_VERIFY_FAILED,
-    MFI_STAT_LOCK_KEY_REKEY_NOT_ALLOWED,
-    MFI_STAT_LOCK_KEY_INVALID,
-    MFI_STAT_LOCK_KEY_ESCROW_INVALID,
-    MFI_STAT_LOCK_KEY_BACKUP_REQUIRED,
-    MFI_STAT_SECURE_LD_EXISTS,
-    MFI_STAT_LD_SECURE_NOT_ALLOWED,
-    MFI_STAT_REPROVISION_NOT_ALLOWED,
-    MFI_STAT_PD_SECURITY_TYPE_WRONG,
-    MFI_STAT_LD_ENCRYPTION_TYPE_INVALID,
-    MFI_STAT_CONFIG_FDE_NON_FDE_MIX_NOT_ALLOWED = 0x50,
-    MFI_STAT_CONFIG_LD_ENCRYPTION_TYPE_MIX_NOT_ALLOWED,
-    MFI_STAT_SECRET_KEY_NOT_ALLOWED,
-    MFI_STAT_PD_HW_ERRORS_DETECTED,
-    MFI_STAT_LD_CACHE_PINNED,
-    MFI_STAT_POWER_STATE_SET_IN_PROGRESS,
-    MFI_STAT_POWER_STATE_SET_BUSY,
-    MFI_STAT_POWER_STATE_WRONG,
-    MFI_STAT_PR_NO_AVAILABLE_PD_FOUND,
-    MFI_STAT_CTRL_RESET_REQUIRED,
-    MFI_STAT_LOCK_KEY_EKM_NO_BOOT_AGENT,
-    MFI_STAT_SNAP_NO_SPACE,
-    MFI_STAT_SNAP_PARTIAL_FAILURE,
-    MFI_STAT_UPGRADE_KEY_INCOMPATIBLE,
-    MFI_STAT_PFK_INCOMPATIBLE,
-    MFI_STAT_PD_MAX_UNCONFIGURED,
-    MFI_STAT_IO_METRICS_DISABLED =      0x60,
-    MFI_STAT_AEC_NOT_STOPPED,
-    MFI_STAT_PI_TYPE_WRONG,
-    MFI_STAT_LD_PD_PI_INCOMPATIBLE,
-    MFI_STAT_PI_NOT_ENABLED,
-    MFI_STAT_LD_BLOCK_SIZE_MISMATCH,
-    MFI_STAT_INVALID_STATUS =           0xFF
-} mfi_status_t;
-
-/* Event classes */
-typedef enum {
-    MFI_EVT_CLASS_DEBUG =      -2,
-    MFI_EVT_CLASS_PROGRESS =   -1,
-    MFI_EVT_CLASS_INFO =        0,
-    MFI_EVT_CLASS_WARNING =     1,
-    MFI_EVT_CLASS_CRITICAL =    2,
-    MFI_EVT_CLASS_FATAL =       3,
-    MFI_EVT_CLASS_DEAD =        4
-} mfi_evt_class_t;
-
-/* Event locales */
-typedef enum {
-    MFI_EVT_LOCALE_LD =         0x0001,
-    MFI_EVT_LOCALE_PD =         0x0002,
-    MFI_EVT_LOCALE_ENCL =       0x0004,
-    MFI_EVT_LOCALE_BBU =        0x0008,
-    MFI_EVT_LOCALE_SAS =        0x0010,
-    MFI_EVT_LOCALE_CTRL =       0x0020,
-    MFI_EVT_LOCALE_CONFIG =     0x0040,
-    MFI_EVT_LOCALE_CLUSTER =    0x0080,
-    MFI_EVT_LOCALE_ALL =        0xffff
-} mfi_evt_locale_t;
-
-/* Event args */
-typedef enum {
-    MR_EVT_ARGS_NONE =          0x00,
-    MR_EVT_ARGS_CDB_SENSE,
-    MR_EVT_ARGS_LD,
-    MR_EVT_ARGS_LD_COUNT,
-    MR_EVT_ARGS_LD_LBA,
-    MR_EVT_ARGS_LD_OWNER,
-    MR_EVT_ARGS_LD_LBA_PD_LBA,
-    MR_EVT_ARGS_LD_PROG,
-    MR_EVT_ARGS_LD_STATE,
-    MR_EVT_ARGS_LD_STRIP,
-    MR_EVT_ARGS_PD,
-    MR_EVT_ARGS_PD_ERR,
-    MR_EVT_ARGS_PD_LBA,
-    MR_EVT_ARGS_PD_LBA_LD,
-    MR_EVT_ARGS_PD_PROG,
-    MR_EVT_ARGS_PD_STATE,
-    MR_EVT_ARGS_PCI,
-    MR_EVT_ARGS_RATE,
-    MR_EVT_ARGS_STR,
-    MR_EVT_ARGS_TIME,
-    MR_EVT_ARGS_ECC,
-    MR_EVT_ARGS_LD_PROP,
-    MR_EVT_ARGS_PD_SPARE,
-    MR_EVT_ARGS_PD_INDEX,
-    MR_EVT_ARGS_DIAG_PASS,
-    MR_EVT_ARGS_DIAG_FAIL,
-    MR_EVT_ARGS_PD_LBA_LBA,
-    MR_EVT_ARGS_PORT_PHY,
-    MR_EVT_ARGS_PD_MISSING,
-    MR_EVT_ARGS_PD_ADDRESS,
-    MR_EVT_ARGS_BITMAP,
-    MR_EVT_ARGS_CONNECTOR,
-    MR_EVT_ARGS_PD_PD,
-    MR_EVT_ARGS_PD_FRU,
-    MR_EVT_ARGS_PD_PATHINFO,
-    MR_EVT_ARGS_PD_POWER_STATE,
-    MR_EVT_ARGS_GENERIC,
-} mfi_evt_args;
-
-/* Event codes */
-#define MR_EVT_CFG_CLEARED                          0x0004
-#define MR_EVT_CTRL_SHUTDOWN                        0x002a
-#define MR_EVT_LD_STATE_CHANGE                      0x0051
-#define MR_EVT_PD_INSERTED                          0x005b
-#define MR_EVT_PD_REMOVED                           0x0070
-#define MR_EVT_PD_STATE_CHANGED                     0x0072
-#define MR_EVT_LD_CREATED                           0x008a
-#define MR_EVT_LD_DELETED                           0x008b
-#define MR_EVT_FOREIGN_CFG_IMPORTED                 0x00db
-#define MR_EVT_LD_OFFLINE                           0x00fc
-#define MR_EVT_CTRL_HOST_BUS_SCAN_REQUESTED         0x0152
-
-typedef enum {
-    MR_LD_CACHE_WRITE_BACK =            0x01,
-    MR_LD_CACHE_WRITE_ADAPTIVE =        0x02,
-    MR_LD_CACHE_READ_AHEAD =            0x04,
-    MR_LD_CACHE_READ_ADAPTIVE =         0x08,
-    MR_LD_CACHE_WRITE_CACHE_BAD_BBU =   0x10,
-    MR_LD_CACHE_ALLOW_WRITE_CACHE =     0x20,
-    MR_LD_CACHE_ALLOW_READ_CACHE =      0x40
-} mfi_ld_cache;
-
-typedef enum {
-    MR_PD_CACHE_UNCHANGED  =    0,
-    MR_PD_CACHE_ENABLE =        1,
-    MR_PD_CACHE_DISABLE =       2
-} mfi_pd_cache;
-
-typedef enum {
-    MR_PD_QUERY_TYPE_ALL =              0,
-    MR_PD_QUERY_TYPE_STATE =            1,
-    MR_PD_QUERY_TYPE_POWER_STATE =      2,
-    MR_PD_QUERY_TYPE_MEDIA_TYPE =       3,
-    MR_PD_QUERY_TYPE_SPEED =            4,
-    MR_PD_QUERY_TYPE_EXPOSED_TO_HOST =  5, /*query for system drives */
-} mfi_pd_query_type;
-
-/*
- * Other propertities and definitions
- */
-#define MFI_MAX_PD_CHANNELS     2
-#define MFI_MAX_LD_CHANNELS     2
-#define MFI_MAX_CHANNELS        (MFI_MAX_PD_CHANNELS + MFI_MAX_LD_CHANNELS)
-#define MFI_MAX_CHANNEL_DEVS  128
-#define MFI_DEFAULT_ID         -1
-#define MFI_MAX_LUN             8
-#define MFI_MAX_LD             64
-
-#define MFI_FRAME_SIZE         64
-#define MFI_MBOX_SIZE          12
-
-/* Firmware flashing can take 40s */
-#define MFI_POLL_TIMEOUT_SECS  50
-
-/* Allow for speedier math calculations */
-#define MFI_SECTOR_LEN        512
-
-/* Scatter Gather elements */
-struct mfi_sg32 {
-    uint32_t addr;
-    uint32_t len;
-} QEMU_PACKED;
-
-struct mfi_sg64 {
-    uint64_t addr;
-    uint32_t len;
-} QEMU_PACKED;
-
-struct mfi_sg_skinny {
-    uint64_t addr;
-    uint32_t len;
-    uint32_t flag;
-} QEMU_PACKED;
-
-union mfi_sgl {
-    struct mfi_sg32 sg32[1];
-    struct mfi_sg64 sg64[1];
-    struct mfi_sg_skinny sg_skinny[1];
-} QEMU_PACKED;
-
-/* Message frames.  All messages have a common header */
-struct mfi_frame_header {
-    uint8_t frame_cmd;
-    uint8_t sense_len;
-    uint8_t cmd_status;
-    uint8_t scsi_status;
-    uint8_t target_id;
-    uint8_t lun_id;
-    uint8_t cdb_len;
-    uint8_t sge_count;
-    uint64_t context;
-    uint16_t flags;
-    uint16_t timeout;
-    uint32_t data_len;
-} QEMU_PACKED;
-
-struct mfi_init_frame {
-    struct mfi_frame_header header;
-    uint32_t qinfo_new_addr_lo;
-    uint32_t qinfo_new_addr_hi;
-    uint32_t qinfo_old_addr_lo;
-    uint32_t qinfo_old_addr_hi;
-    uint32_t reserved[6];
-};
-
-#define MFI_IO_FRAME_SIZE 40
-struct mfi_io_frame {
-    struct mfi_frame_header header;
-    uint32_t sense_addr_lo;
-    uint32_t sense_addr_hi;
-    uint32_t lba_lo;
-    uint32_t lba_hi;
-    union mfi_sgl sgl;
-} QEMU_PACKED;
-
-#define MFI_PASS_FRAME_SIZE 48
-struct mfi_pass_frame {
-    struct mfi_frame_header header;
-    uint32_t sense_addr_lo;
-    uint32_t sense_addr_hi;
-    uint8_t cdb[16];
-    union mfi_sgl sgl;
-} QEMU_PACKED;
-
-#define MFI_DCMD_FRAME_SIZE 40
-struct mfi_dcmd_frame {
-    struct mfi_frame_header header;
-    uint32_t opcode;
-    uint8_t mbox[MFI_MBOX_SIZE];
-    union mfi_sgl sgl;
-} QEMU_PACKED;
-
-struct mfi_abort_frame {
-    struct mfi_frame_header header;
-    uint64_t abort_context;
-    uint32_t abort_mfi_addr_lo;
-    uint32_t abort_mfi_addr_hi;
-    uint32_t reserved1[6];
-} QEMU_PACKED;
-
-struct mfi_smp_frame {
-    struct mfi_frame_header header;
-    uint64_t sas_addr;
-    union {
-        struct mfi_sg32 sg32[2];
-        struct mfi_sg64 sg64[2];
-    } sgl;
-} QEMU_PACKED;
-
-struct mfi_stp_frame {
-    struct mfi_frame_header header;
-    uint16_t fis[10];
-    uint32_t stp_flags;
-    union {
-        struct mfi_sg32 sg32[2];
-        struct mfi_sg64 sg64[2];
-    } sgl;
-} QEMU_PACKED;
-
-union mfi_frame {
-    struct mfi_frame_header header;
-    struct mfi_init_frame init;
-    struct mfi_io_frame io;
-    struct mfi_pass_frame pass;
-    struct mfi_dcmd_frame dcmd;
-    struct mfi_abort_frame abort;
-    struct mfi_smp_frame smp;
-    struct mfi_stp_frame stp;
-    uint64_t raw[8];
-    uint8_t bytes[MFI_FRAME_SIZE];
-};
-
-#define MFI_SENSE_LEN 128
-struct mfi_sense {
-    uint8_t     data[MFI_SENSE_LEN];
-};
-
-#define MFI_QUEUE_FLAG_CONTEXT64 0x00000002
-
-/* The queue init structure that is passed with the init message */
-struct mfi_init_qinfo {
-    uint32_t flags;
-    uint32_t rq_entries;
-    uint32_t rq_addr_lo;
-    uint32_t rq_addr_hi;
-    uint32_t pi_addr_lo;
-    uint32_t pi_addr_hi;
-    uint32_t ci_addr_lo;
-    uint32_t ci_addr_hi;
-} QEMU_PACKED;
-
-/* Controller properties */
-struct mfi_ctrl_props {
-    uint16_t seq_num;
-    uint16_t pred_fail_poll_interval;
-    uint16_t intr_throttle_cnt;
-    uint16_t intr_throttle_timeout;
-    uint8_t rebuild_rate;
-    uint8_t patrol_read_rate;
-    uint8_t bgi_rate;
-    uint8_t cc_rate;
-    uint8_t recon_rate;
-    uint8_t cache_flush_interval;
-    uint8_t spinup_drv_cnt;
-    uint8_t spinup_delay;
-    uint8_t cluster_enable;
-    uint8_t coercion_mode;
-    uint8_t alarm_enable;
-    uint8_t disable_auto_rebuild;
-    uint8_t disable_battery_warn;
-    uint8_t ecc_bucket_size;
-    uint16_t ecc_bucket_leak_rate;
-    uint8_t restore_hotspare_on_insertion;
-    uint8_t expose_encl_devices;
-    uint8_t maintainPdFailHistory;
-    uint8_t disallowHostRequestReordering;
-    uint8_t abortCCOnError;
-    uint8_t loadBalanceMode;
-    uint8_t disableAutoDetectBackplane;
-    uint8_t snapVDSpace;
-    uint32_t OnOffProperties;
-/* set TRUE to disable copyBack (0=copyback enabled) */
-#define MFI_CTRL_PROP_CopyBackDisabled           (1 << 0)
-#define MFI_CTRL_PROP_SMARTerEnabled             (1 << 1)
-#define MFI_CTRL_PROP_PRCorrectUnconfiguredAreas (1 << 2)
-#define MFI_CTRL_PROP_UseFdeOnly                 (1 << 3)
-#define MFI_CTRL_PROP_DisableNCQ                 (1 << 4)
-#define MFI_CTRL_PROP_SSDSMARTerEnabled          (1 << 5)
-#define MFI_CTRL_PROP_SSDPatrolReadEnabled       (1 << 6)
-#define MFI_CTRL_PROP_EnableSpinDownUnconfigured (1 << 7)
-#define MFI_CTRL_PROP_AutoEnhancedImport         (1 << 8)
-#define MFI_CTRL_PROP_EnableSecretKeyControl     (1 << 9)
-#define MFI_CTRL_PROP_DisableOnlineCtrlReset     (1 << 10)
-#define MFI_CTRL_PROP_AllowBootWithPinnedCache   (1 << 11)
-#define MFI_CTRL_PROP_DisableSpinDownHS          (1 << 12)
-#define MFI_CTRL_PROP_EnableJBOD                 (1 << 13)
-
-    uint8_t autoSnapVDSpace; /* % of source LD to be
-                              * reserved for auto snapshot
-                              * in snapshot repository, for
-                              * metadata and user data
-                              * 1=5%, 2=10%, 3=15% and so on
-                              */
-    uint8_t viewSpace;       /* snapshot writeable VIEWs
-                              * capacity as a % of source LD
-                              * capacity. 0=READ only
-                              * 1=5%, 2=10%, 3=15% and so on
-                              */
-    uint16_t spinDownTime;    /* # of idle minutes before device
-                               * is spun down (0=use FW defaults)
-                               */
-    uint8_t reserved[24];
-} QEMU_PACKED;
-
-/* PCI information about the card. */
-struct mfi_info_pci {
-    uint16_t vendor;
-    uint16_t device;
-    uint16_t subvendor;
-    uint16_t subdevice;
-    uint8_t reserved[24];
-} QEMU_PACKED;
-
-/* Host (front end) interface information */
-struct mfi_info_host {
-    uint8_t type;
-#define MFI_INFO_HOST_PCIX      0x01
-#define MFI_INFO_HOST_PCIE      0x02
-#define MFI_INFO_HOST_ISCSI     0x04
-#define MFI_INFO_HOST_SAS3G     0x08
-    uint8_t reserved[6];
-    uint8_t port_count;
-    uint64_t port_addr[8];
-} QEMU_PACKED;
-
-/* Device (back end) interface information */
-struct mfi_info_device {
-    uint8_t type;
-#define MFI_INFO_DEV_SPI        0x01
-#define MFI_INFO_DEV_SAS3G      0x02
-#define MFI_INFO_DEV_SATA1      0x04
-#define MFI_INFO_DEV_SATA3G     0x08
-#define MFI_INFO_DEV_PCIE       0x10
-    uint8_t reserved[6];
-    uint8_t port_count;
-    uint64_t port_addr[8];
-} QEMU_PACKED;
-
-/* Firmware component information */
-struct mfi_info_component {
-    char name[8];
-    char version[32];
-    char build_date[16];
-    char build_time[16];
-} QEMU_PACKED;
-
-/* Controller default settings */
-struct mfi_defaults {
-    uint64_t sas_addr;
-    uint8_t phy_polarity;
-    uint8_t background_rate;
-    uint8_t stripe_size;
-    uint8_t flush_time;
-    uint8_t write_back;
-    uint8_t read_ahead;
-    uint8_t cache_when_bbu_bad;
-    uint8_t cached_io;
-    uint8_t smart_mode;
-    uint8_t alarm_disable;
-    uint8_t coercion;
-    uint8_t zrc_config;
-    uint8_t dirty_led_shows_drive_activity;
-    uint8_t bios_continue_on_error;
-    uint8_t spindown_mode;
-    uint8_t allowed_device_types;
-    uint8_t allow_mix_in_enclosure;
-    uint8_t allow_mix_in_ld;
-    uint8_t allow_sata_in_cluster;
-    uint8_t max_chained_enclosures;
-    uint8_t disable_ctrl_r;
-    uint8_t enable_web_bios;
-    uint8_t phy_polarity_split;
-    uint8_t direct_pd_mapping;
-    uint8_t bios_enumerate_lds;
-    uint8_t restored_hot_spare_on_insertion;
-    uint8_t expose_enclosure_devices;
-    uint8_t maintain_pd_fail_history;
-    uint8_t disable_puncture;
-    uint8_t zero_based_enumeration;
-    uint8_t disable_preboot_cli;
-    uint8_t show_drive_led_on_activity;
-    uint8_t cluster_disable;
-    uint8_t sas_disable;
-    uint8_t auto_detect_backplane;
-    uint8_t fde_only;
-    uint8_t delay_during_post;
-    uint8_t resv[19];
-} QEMU_PACKED;
-
-/* Controller default settings */
-struct mfi_bios_data {
-    uint16_t boot_target_id;
-    uint8_t do_not_int_13;
-    uint8_t continue_on_error;
-    uint8_t verbose;
-    uint8_t geometry;
-    uint8_t expose_all_drives;
-    uint8_t reserved[56];
-    uint8_t check_sum;
-} QEMU_PACKED;
-
-/* SAS (?) controller info, returned from MFI_DCMD_CTRL_GETINFO. */
-struct mfi_ctrl_info {
-    struct mfi_info_pci pci;
-    struct mfi_info_host host;
-    struct mfi_info_device device;
-
-    /* Firmware components that are present and active. */
-    uint32_t image_check_word;
-    uint32_t image_component_count;
-    struct mfi_info_component image_component[8];
-
-    /* Firmware components that have been flashed but are inactive */
-    uint32_t pending_image_component_count;
-    struct mfi_info_component pending_image_component[8];
-
-    uint8_t max_arms;
-    uint8_t max_spans;
-    uint8_t max_arrays;
-    uint8_t max_lds;
-    char product_name[80];
-    char serial_number[32];
-    uint32_t hw_present;
-#define MFI_INFO_HW_BBU         0x01
-#define MFI_INFO_HW_ALARM       0x02
-#define MFI_INFO_HW_NVRAM       0x04
-#define MFI_INFO_HW_UART        0x08
-#define MFI_INFO_HW_MEM         0x10
-#define MFI_INFO_HW_FLASH       0x20
-    uint32_t current_fw_time;
-    uint16_t max_cmds;
-    uint16_t max_sg_elements;
-    uint32_t max_request_size;
-    uint16_t lds_present;
-    uint16_t lds_degraded;
-    uint16_t lds_offline;
-    uint16_t pd_present;
-    uint16_t pd_disks_present;
-    uint16_t pd_disks_pred_failure;
-    uint16_t pd_disks_failed;
-    uint16_t nvram_size;
-    uint16_t memory_size;
-    uint16_t flash_size;
-    uint16_t ram_correctable_errors;
-    uint16_t ram_uncorrectable_errors;
-    uint8_t cluster_allowed;
-    uint8_t cluster_active;
-    uint16_t max_strips_per_io;
-
-    uint32_t raid_levels;
-#define MFI_INFO_RAID_0         0x01
-#define MFI_INFO_RAID_1         0x02
-#define MFI_INFO_RAID_5         0x04
-#define MFI_INFO_RAID_1E        0x08
-#define MFI_INFO_RAID_6         0x10
-
-    uint32_t adapter_ops;
-#define MFI_INFO_AOPS_RBLD_RATE         0x0001
-#define MFI_INFO_AOPS_CC_RATE           0x0002
-#define MFI_INFO_AOPS_BGI_RATE          0x0004
-#define MFI_INFO_AOPS_RECON_RATE        0x0008
-#define MFI_INFO_AOPS_PATROL_RATE       0x0010
-#define MFI_INFO_AOPS_ALARM_CONTROL     0x0020
-#define MFI_INFO_AOPS_CLUSTER_SUPPORTED 0x0040
-#define MFI_INFO_AOPS_BBU               0x0080
-#define MFI_INFO_AOPS_SPANNING_ALLOWED  0x0100
-#define MFI_INFO_AOPS_DEDICATED_SPARES  0x0200
-#define MFI_INFO_AOPS_REVERTIBLE_SPARES 0x0400
-#define MFI_INFO_AOPS_FOREIGN_IMPORT    0x0800
-#define MFI_INFO_AOPS_SELF_DIAGNOSTIC   0x1000
-#define MFI_INFO_AOPS_MIXED_ARRAY       0x2000
-#define MFI_INFO_AOPS_GLOBAL_SPARES     0x4000
-
-    uint32_t ld_ops;
-#define MFI_INFO_LDOPS_READ_POLICY      0x01
-#define MFI_INFO_LDOPS_WRITE_POLICY     0x02
-#define MFI_INFO_LDOPS_IO_POLICY        0x04
-#define MFI_INFO_LDOPS_ACCESS_POLICY    0x08
-#define MFI_INFO_LDOPS_DISK_CACHE_POLICY 0x10
-
-    struct {
-        uint8_t min;
-        uint8_t max;
-        uint8_t reserved[2];
-    } QEMU_PACKED stripe_sz_ops;
-
-    uint32_t pd_ops;
-#define MFI_INFO_PDOPS_FORCE_ONLINE     0x01
-#define MFI_INFO_PDOPS_FORCE_OFFLINE    0x02
-#define MFI_INFO_PDOPS_FORCE_REBUILD    0x04
-
-    uint32_t pd_mix_support;
-#define MFI_INFO_PDMIX_SAS              0x01
-#define MFI_INFO_PDMIX_SATA             0x02
-#define MFI_INFO_PDMIX_ENCL             0x04
-#define MFI_INFO_PDMIX_LD               0x08
-#define MFI_INFO_PDMIX_SATA_CLUSTER     0x10
-
-    uint8_t ecc_bucket_count;
-    uint8_t reserved2[11];
-    struct mfi_ctrl_props properties;
-    char package_version[0x60];
-    uint8_t pad[0x800 - 0x6a0];
-} QEMU_PACKED;
-
-/* keep track of an event. */
-union mfi_evt {
-    struct {
-        uint16_t locale;
-        uint8_t reserved;
-        int8_t class;
-    } members;
-    uint32_t word;
-} QEMU_PACKED;
-
-/* event log state. */
-struct mfi_evt_log_state {
-    uint32_t newest_seq_num;
-    uint32_t oldest_seq_num;
-    uint32_t clear_seq_num;
-    uint32_t shutdown_seq_num;
-    uint32_t boot_seq_num;
-} QEMU_PACKED;
-
-struct mfi_progress {
-    uint16_t progress;
-    uint16_t elapsed_seconds;
-} QEMU_PACKED;
-
-struct mfi_evt_ld {
-    uint16_t target_id;
-    uint8_t ld_index;
-    uint8_t reserved;
-} QEMU_PACKED;
-
-struct mfi_evt_pd {
-    uint16_t device_id;
-    uint8_t enclosure_index;
-    uint8_t slot_number;
-} QEMU_PACKED;
-
-/* event detail, returned from MFI_DCMD_CTRL_EVENT_WAIT. */
-struct mfi_evt_detail {
-    uint32_t seq;
-    uint32_t time;
-    uint32_t code;
-    union mfi_evt class;
-    uint8_t arg_type;
-    uint8_t reserved1[15];
-
-    union {
-        struct {
-            struct mfi_evt_pd pd;
-            uint8_t cdb_len;
-            uint8_t sense_len;
-            uint8_t reserved[2];
-            uint8_t cdb[16];
-            uint8_t sense[64];
-        } cdb_sense;
-
-        struct mfi_evt_ld ld;
-
-        struct {
-            struct mfi_evt_ld ld;
-            uint64_t count;
-        } ld_count;
-
-        struct {
-            uint64_t lba;
-            struct mfi_evt_ld ld;
-        } ld_lba;
-
-        struct {
-            struct mfi_evt_ld ld;
-            uint32_t pre_owner;
-            uint32_t new_owner;
-        } ld_owner;
-
-        struct {
-            uint64_t ld_lba;
-            uint64_t pd_lba;
-            struct mfi_evt_ld ld;
-            struct mfi_evt_pd pd;
-        } ld_lba_pd_lba;
-
-        struct {
-            struct mfi_evt_ld ld;
-            struct mfi_progress prog;
-        } ld_prog;
-
-        struct {
-            struct mfi_evt_ld ld;
-            uint32_t prev_state;
-            uint32_t new_state;
-        } ld_state;
-
-        struct {
-            uint64_t strip;
-            struct mfi_evt_ld ld;
-        } ld_strip;
-
-        struct mfi_evt_pd pd;
-
-        struct {
-            struct mfi_evt_pd pd;
-            uint32_t err;
-        } pd_err;
-
-        struct {
-            uint64_t lba;
-            struct mfi_evt_pd pd;
-        } pd_lba;
-
-        struct {
-            uint64_t lba;
-            struct mfi_evt_pd pd;
-            struct mfi_evt_ld ld;
-        } pd_lba_ld;
-
-        struct {
-            struct mfi_evt_pd pd;
-            struct mfi_progress prog;
-        } pd_prog;
-
-        struct {
-            struct mfi_evt_pd ld;
-            uint32_t prev_state;
-            uint32_t new_state;
-        } pd_state;
-
-        struct {
-            uint16_t venderId;
-            uint16_t deviceId;
-            uint16_t subVenderId;
-            uint16_t subDeviceId;
-        } pci;
-
-        uint32_t rate;
-
-        char str[96];
-
-        struct {
-            uint32_t rtc;
-            uint16_t elapsedSeconds;
-        } time;
-
-        struct {
-            uint32_t ecar;
-            uint32_t elog;
-            char str[64];
-        } ecc;
-
-        uint8_t b[96];
-        uint16_t s[48];
-        uint32_t w[24];
-        uint64_t d[12];
-    } args;
-
-    char description[128];
-} QEMU_PACKED;
-
-struct mfi_evt_list {
-    uint32_t count;
-    uint32_t reserved;
-    struct mfi_evt_detail event[1];
-} QEMU_PACKED;
-
-union mfi_pd_ref {
-    struct {
-        uint16_t device_id;
-        uint16_t seq_num;
-    } v;
-    uint32_t ref;
-} QEMU_PACKED;
-
-union mfi_pd_ddf_type {
-    struct {
-        uint16_t pd_type;
-#define MFI_PD_DDF_TYPE_FORCED_PD_GUID (1 << 0)
-#define MFI_PD_DDF_TYPE_IN_VD          (1 << 1)
-#define MFI_PD_DDF_TYPE_IS_GLOBAL_SPARE (1 << 2)
-#define MFI_PD_DDF_TYPE_IS_SPARE        (1 << 3)
-#define MFI_PD_DDF_TYPE_IS_FOREIGN      (1 << 4)
-#define MFI_PD_DDF_TYPE_INTF_SPI        (1 << 12)
-#define MFI_PD_DDF_TYPE_INTF_SAS        (1 << 13)
-#define MFI_PD_DDF_TYPE_INTF_SATA1      (1 << 14)
-#define MFI_PD_DDF_TYPE_INTF_SATA3G     (1 << 15)
-        uint16_t reserved;
-    } ddf;
-    struct {
-        uint32_t reserved;
-    } non_disk;
-    uint32_t type;
-} QEMU_PACKED;
-
-struct mfi_pd_progress {
-    uint32_t active;
-#define PD_PROGRESS_ACTIVE_REBUILD (1 << 0)
-#define PD_PROGRESS_ACTIVE_PATROL  (1 << 1)
-#define PD_PROGRESS_ACTIVE_CLEAR   (1 << 2)
-    struct mfi_progress rbld;
-    struct mfi_progress patrol;
-    struct mfi_progress clear;
-    struct mfi_progress reserved[4];
-} QEMU_PACKED;
-
-struct mfi_pd_info {
-    union mfi_pd_ref ref;
-    uint8_t inquiry_data[96];
-    uint8_t vpd_page83[64];
-    uint8_t not_supported;
-    uint8_t scsi_dev_type;
-    uint8_t connected_port_bitmap;
-    uint8_t device_speed;
-    uint32_t media_err_count;
-    uint32_t other_err_count;
-    uint32_t pred_fail_count;
-    uint32_t last_pred_fail_event_seq_num;
-    uint16_t fw_state;
-    uint8_t disable_for_removal;
-    uint8_t link_speed;
-    union mfi_pd_ddf_type state;
-    struct {
-        uint8_t count;
-        uint8_t is_path_broken;
-        uint8_t reserved[6];
-        uint64_t sas_addr[4];
-    } path_info;
-    uint64_t raw_size;
-    uint64_t non_coerced_size;
-    uint64_t coerced_size;
-    uint16_t encl_device_id;
-    uint8_t encl_index;
-    uint8_t slot_number;
-    struct mfi_pd_progress prog_info;
-    uint8_t bad_block_table_full;
-    uint8_t unusable_in_current_config;
-    uint8_t vpd_page83_ext[64];
-    uint8_t reserved[512-358];
-} QEMU_PACKED;
-
-struct mfi_pd_address {
-    uint16_t device_id;
-    uint16_t encl_device_id;
-    uint8_t encl_index;
-    uint8_t slot_number;
-    uint8_t scsi_dev_type;
-    uint8_t connect_port_bitmap;
-    uint64_t sas_addr[2];
-} QEMU_PACKED;
-
-#define MFI_MAX_SYS_PDS 240
-struct mfi_pd_list {
-    uint32_t size;
-    uint32_t count;
-    struct mfi_pd_address addr[MFI_MAX_SYS_PDS];
-} QEMU_PACKED;
-
-union mfi_ld_ref {
-    struct {
-        uint8_t target_id;
-        uint8_t lun_id;
-        uint16_t seq;
-    } v;
-    uint32_t ref;
-} QEMU_PACKED;
-
-struct mfi_ld_list {
-    uint32_t ld_count;
-    uint32_t reserved1;
-    struct {
-        union mfi_ld_ref ld;
-        uint8_t state;
-        uint8_t reserved2[3];
-        uint64_t size;
-    } ld_list[MFI_MAX_LD];
-} QEMU_PACKED;
-
-enum mfi_ld_access {
-    MFI_LD_ACCESS_RW =          0,
-    MFI_LD_ACCSSS_RO =          2,
-    MFI_LD_ACCESS_BLOCKED =     3,
-};
-#define MFI_LD_ACCESS_MASK      3
-
-enum mfi_ld_state {
-    MFI_LD_STATE_OFFLINE =              0,
-    MFI_LD_STATE_PARTIALLY_DEGRADED =   1,
-    MFI_LD_STATE_DEGRADED =             2,
-    MFI_LD_STATE_OPTIMAL =              3
-};
-
-enum mfi_syspd_state {
-    MFI_PD_STATE_UNCONFIGURED_GOOD =    0x00,
-    MFI_PD_STATE_UNCONFIGURED_BAD =     0x01,
-    MFI_PD_STATE_HOT_SPARE =            0x02,
-    MFI_PD_STATE_OFFLINE =              0x10,
-    MFI_PD_STATE_FAILED =               0x11,
-    MFI_PD_STATE_REBUILD =              0x14,
-    MFI_PD_STATE_ONLINE =               0x18,
-    MFI_PD_STATE_COPYBACK =             0x20,
-    MFI_PD_STATE_SYSTEM =               0x40
-};
-
-struct mfi_ld_props {
-    union mfi_ld_ref ld;
-    char name[16];
-    uint8_t default_cache_policy;
-    uint8_t access_policy;
-    uint8_t disk_cache_policy;
-    uint8_t current_cache_policy;
-    uint8_t no_bgi;
-    uint8_t reserved[7];
-} QEMU_PACKED;
-
-struct mfi_ld_params {
-    uint8_t primary_raid_level;
-    uint8_t raid_level_qualifier;
-    uint8_t secondary_raid_level;
-    uint8_t stripe_size;
-    uint8_t num_drives;
-    uint8_t span_depth;
-    uint8_t state;
-    uint8_t init_state;
-    uint8_t is_consistent;
-    uint8_t reserved[23];
-} QEMU_PACKED;
-
-struct mfi_ld_progress {
-    uint32_t            active;
-#define MFI_LD_PROGRESS_CC      (1<<0)
-#define MFI_LD_PROGRESS_BGI     (1<<1)
-#define MFI_LD_PROGRESS_FGI     (1<<2)
-#define MFI_LD_PORGRESS_RECON   (1<<3)
-    struct mfi_progress cc;
-    struct mfi_progress bgi;
-    struct mfi_progress fgi;
-    struct mfi_progress recon;
-    struct mfi_progress reserved[4];
-} QEMU_PACKED;
-
-struct mfi_span {
-    uint64_t start_block;
-    uint64_t num_blocks;
-    uint16_t array_ref;
-    uint8_t reserved[6];
-} QEMU_PACKED;
-
-#define MFI_MAX_SPAN_DEPTH      8
-struct mfi_ld_config {
-    struct mfi_ld_props properties;
-    struct mfi_ld_params params;
-    struct mfi_span span[MFI_MAX_SPAN_DEPTH];
-} QEMU_PACKED;
-
-struct mfi_ld_info {
-    struct mfi_ld_config ld_config;
-    uint64_t size;
-    struct mfi_ld_progress progress;
-    uint16_t cluster_owner;
-    uint8_t reconstruct_active;
-    uint8_t reserved1[1];
-    uint8_t vpd_page83[64];
-    uint8_t reserved2[16];
-} QEMU_PACKED;
-
-union mfi_spare_type {
-    uint8_t flags;
-#define MFI_SPARE_IS_DEDICATED (1 << 0)
-#define MFI_SPARE_IS_REVERTABLE (1 << 1)
-#define MFI_SPARE_IS_ENCL_AFFINITY (1 << 2)
-    uint8_t type;
-} QEMU_PACKED;
-
-#define MFI_MAX_ARRAYS 16
-struct mfi_spare {
-    union mfi_pd_ref ref;
-    union mfi_spare_type spare_type;
-    uint8_t reserved[2];
-    uint8_t array_count;
-    uint16_t array_refd[MFI_MAX_ARRAYS];
-} QEMU_PACKED;
-
-#define MFI_MAX_ROW_SIZE 32
-struct mfi_array {
-    uint64_t size;
-    uint8_t num_drives;
-    uint8_t reserved;
-    uint16_t array_ref;
-    uint8_t pad[20];
-    struct {
-        union mfi_pd_ref ref;
-        uint16_t fw_state; /* enum mfi_syspd_state */
-        struct {
-            uint8_t pd;
-            uint8_t slot;
-        } encl;
-    } pd[MFI_MAX_ROW_SIZE];
-} QEMU_PACKED;
-
-struct mfi_config_data {
-    uint32_t size;
-    uint16_t array_count;
-    uint16_t array_size;
-    uint16_t log_drv_count;
-    uint16_t log_drv_size;
-    uint16_t spares_count;
-    uint16_t spares_size;
-    uint8_t reserved[16];
-    /*
-      struct mfi_array  array[];
-      struct mfi_ld_config ld[];
-      struct mfi_spare  spare[];
-    */
-} QEMU_PACKED;
-
-#define MFI_SCSI_MAX_TARGETS  128
-#define MFI_SCSI_MAX_LUNS       8
-#define MFI_SCSI_INITIATOR_ID 255
-#define MFI_SCSI_MAX_CMDS       8
-#define MFI_SCSI_MAX_CDB_LEN   16
-
-#endif /* MFI_REG_H */
index 9e7f249941a7f6b6e003f61c9986851106ab765a..c65e2aabf1916d7fc3c8a571e25ca707d9f301c4 100644 (file)
@@ -1,8 +1,3 @@
-obj-y += xilinx_spi.o
-obj-y += xilinx_ethlite.o
-
-obj-y := $(addprefix ../,$(obj-y))
-
 obj-y += petalogix_s3adsp1800_mmu.o
 obj-y += petalogix_ml605_mmu.o
 obj-y += boot.o
index e13b3e13bbf4838c2417ac872925ad30708cbb55..23cb11d70e69c5a8000997aac7824a1b1c080c42 100644 (file)
@@ -31,7 +31,7 @@
 #include "hw/loader.h"
 #include "elf.h"
 
-#include "hw/microblaze_boot.h"
+#include "boot.h"
 
 static struct
 {
diff --git a/hw/microblaze/boot.h b/hw/microblaze/boot.h
new file mode 100644 (file)
index 0000000..b14ef2b
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef __MICROBLAZE_BOOT__
+#define __MICROBLAZE_BOOT__
+
+#include "hw/hw.h"
+
+void microblaze_load_kernel(MicroBlazeCPU *cpu, hwaddr ddr_base,
+                            uint32_t ramsize, const char *dtb_filename,
+                            void (*machine_cpu_reset)(MicroBlazeCPU *));
+
+#endif /* __MICROBLAZE_BOOT __ */
index cfc02207abe66199bc496a2544c23017b6012703..f61818b42bc77cee2ab9b7a3265b7a8d1ccd9572 100644 (file)
 #include "hw/sysbus.h"
 #include "hw/hw.h"
 #include "net/net.h"
-#include "hw/flash.h"
+#include "hw/block/flash.h"
 #include "sysemu/sysemu.h"
-#include "hw/devices.h"
+#include "hw/arm/devices.h"
 #include "hw/boards.h"
 #include "hw/xilinx.h"
 #include "sysemu/blockdev.h"
-#include "hw/serial.h"
+#include "hw/char/serial.h"
 #include "exec/address-spaces.h"
 #include "hw/ssi.h"
 
-#include "hw/microblaze_boot.h"
-#include "hw/microblaze_pic_cpu.h"
+#include "boot.h"
+#include "pic_cpu.h"
 
 #include "hw/stream.h"
 
@@ -158,8 +158,7 @@ petalogix_ml605_init(QEMUMachineInitArgs *args)
         for (i = 0; i < NUM_SPI_FLASHES; i++) {
             qemu_irq cs_line;
 
-            dev = ssi_create_slave_no_init(spi, "n25q128");
-            qdev_init_nofail(dev);
+            dev = ssi_create_slave(spi, "n25q128");
             cs_line = qdev_get_gpio_in(dev, 0);
             sysbus_connect_irq(busdev, i+1, cs_line);
         }
index 24983621e59fbf0b2c9d59136a863ba98442c14b..eedd60e38c56082bdf050d38bc91368368d7e0e6 100644 (file)
 #include "hw/sysbus.h"
 #include "hw/hw.h"
 #include "net/net.h"
-#include "hw/flash.h"
+#include "hw/block/flash.h"
 #include "sysemu/sysemu.h"
-#include "hw/devices.h"
+#include "hw/arm/devices.h"
 #include "hw/boards.h"
 #include "hw/xilinx.h"
 #include "sysemu/blockdev.h"
 #include "exec/address-spaces.h"
 
-#include "hw/microblaze_boot.h"
-#include "hw/microblaze_pic_cpu.h"
+#include "boot.h"
+#include "pic_cpu.h"
 
 #define LMB_BRAM_SIZE  (128 * 1024)
 #define FLASH_SIZE     (16 * 1024 * 1024)
index 6248de92bbd5ca5a833c5edd9746130f02ec1410..16902f788088db7deaf9f8f5d7c1d55d7b5f01c4 100644 (file)
@@ -23,7 +23,7 @@
  */
 
 #include "hw/hw.h"
-#include "hw/microblaze_pic_cpu.h"
+#include "pic_cpu.h"
 
 #define D(x)
 
diff --git a/hw/microblaze/pic_cpu.h b/hw/microblaze/pic_cpu.h
new file mode 100644 (file)
index 0000000..43090a4
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef MICROBLAZE_PIC_CPU_H
+#define MICROBLAZE_PIC_CPU_H
+
+#include "qemu-common.h"
+
+qemu_irq *microblaze_pic_init_cpu(CPUMBState *env);
+
+#endif /*  MICROBLAZE_PIC_CPU_H */
diff --git a/hw/microblaze_boot.h b/hw/microblaze_boot.h
deleted file mode 100644 (file)
index b14ef2b..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef __MICROBLAZE_BOOT__
-#define __MICROBLAZE_BOOT__
-
-#include "hw/hw.h"
-
-void microblaze_load_kernel(MicroBlazeCPU *cpu, hwaddr ddr_base,
-                            uint32_t ramsize, const char *dtb_filename,
-                            void (*machine_cpu_reset)(MicroBlazeCPU *));
-
-#endif /* __MICROBLAZE_BOOT __ */
diff --git a/hw/microblaze_pic_cpu.h b/hw/microblaze_pic_cpu.h
deleted file mode 100644 (file)
index 43090a4..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef MICROBLAZE_PIC_CPU_H
-#define MICROBLAZE_PIC_CPU_H
-
-#include "qemu-common.h"
-
-qemu_irq *microblaze_pic_init_cpu(CPUMBState *env);
-
-#endif /*  MICROBLAZE_PIC_CPU_H */
diff --git a/hw/milkymist-ac97.c b/hw/milkymist-ac97.c
deleted file mode 100644 (file)
index e08e9dc..0000000
+++ /dev/null
@@ -1,344 +0,0 @@
-/*
- *  QEMU model of the Milkymist System Controller.
- *
- *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
- *
- * 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/>.
- *
- *
- * Specification available at:
- *   http://www.milkymist.org/socdoc/ac97.pdf
- */
-
-#include "hw/hw.h"
-#include "hw/sysbus.h"
-#include "trace.h"
-#include "audio/audio.h"
-#include "qemu/error-report.h"
-
-enum {
-    R_AC97_CTRL = 0,
-    R_AC97_ADDR,
-    R_AC97_DATAOUT,
-    R_AC97_DATAIN,
-    R_D_CTRL,
-    R_D_ADDR,
-    R_D_REMAINING,
-    R_RESERVED,
-    R_U_CTRL,
-    R_U_ADDR,
-    R_U_REMAINING,
-    R_MAX
-};
-
-enum {
-    AC97_CTRL_RQEN  = (1<<0),
-    AC97_CTRL_WRITE = (1<<1),
-};
-
-enum {
-    CTRL_EN = (1<<0),
-};
-
-struct MilkymistAC97State {
-    SysBusDevice busdev;
-    MemoryRegion regs_region;
-
-    QEMUSoundCard card;
-    SWVoiceIn *voice_in;
-    SWVoiceOut *voice_out;
-
-    uint32_t regs[R_MAX];
-
-    qemu_irq crrequest_irq;
-    qemu_irq crreply_irq;
-    qemu_irq dmar_irq;
-    qemu_irq dmaw_irq;
-};
-typedef struct MilkymistAC97State MilkymistAC97State;
-
-static void update_voices(MilkymistAC97State *s)
-{
-    if (s->regs[R_D_CTRL] & CTRL_EN) {
-        AUD_set_active_out(s->voice_out, 1);
-    } else {
-        AUD_set_active_out(s->voice_out, 0);
-    }
-
-    if (s->regs[R_U_CTRL] & CTRL_EN) {
-        AUD_set_active_in(s->voice_in, 1);
-    } else {
-        AUD_set_active_in(s->voice_in, 0);
-    }
-}
-
-static uint64_t ac97_read(void *opaque, hwaddr addr,
-                          unsigned size)
-{
-    MilkymistAC97State *s = opaque;
-    uint32_t r = 0;
-
-    addr >>= 2;
-    switch (addr) {
-    case R_AC97_CTRL:
-    case R_AC97_ADDR:
-    case R_AC97_DATAOUT:
-    case R_AC97_DATAIN:
-    case R_D_CTRL:
-    case R_D_ADDR:
-    case R_D_REMAINING:
-    case R_U_CTRL:
-    case R_U_ADDR:
-    case R_U_REMAINING:
-        r = s->regs[addr];
-        break;
-
-    default:
-        error_report("milkymist_ac97: read access to unknown register 0x"
-                TARGET_FMT_plx, addr << 2);
-        break;
-    }
-
-    trace_milkymist_ac97_memory_read(addr << 2, r);
-
-    return r;
-}
-
-static void ac97_write(void *opaque, hwaddr addr, uint64_t value,
-                       unsigned size)
-{
-    MilkymistAC97State *s = opaque;
-
-    trace_milkymist_ac97_memory_write(addr, value);
-
-    addr >>= 2;
-    switch (addr) {
-    case R_AC97_CTRL:
-        /* always raise an IRQ according to the direction */
-        if (value & AC97_CTRL_RQEN) {
-            if (value & AC97_CTRL_WRITE) {
-                trace_milkymist_ac97_pulse_irq_crrequest();
-                qemu_irq_pulse(s->crrequest_irq);
-            } else {
-                trace_milkymist_ac97_pulse_irq_crreply();
-                qemu_irq_pulse(s->crreply_irq);
-            }
-        }
-
-        /* RQEN is self clearing */
-        s->regs[addr] = value & ~AC97_CTRL_RQEN;
-        break;
-    case R_D_CTRL:
-    case R_U_CTRL:
-        s->regs[addr] = value;
-        update_voices(s);
-        break;
-    case R_AC97_ADDR:
-    case R_AC97_DATAOUT:
-    case R_AC97_DATAIN:
-    case R_D_ADDR:
-    case R_D_REMAINING:
-    case R_U_ADDR:
-    case R_U_REMAINING:
-        s->regs[addr] = value;
-        break;
-
-    default:
-        error_report("milkymist_ac97: write access to unknown register 0x"
-                TARGET_FMT_plx, addr);
-        break;
-    }
-
-}
-
-static const MemoryRegionOps ac97_mmio_ops = {
-    .read = ac97_read,
-    .write = ac97_write,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void ac97_in_cb(void *opaque, int avail_b)
-{
-    MilkymistAC97State *s = opaque;
-    uint8_t buf[4096];
-    uint32_t remaining = s->regs[R_U_REMAINING];
-    int temp = audio_MIN(remaining, avail_b);
-    uint32_t addr = s->regs[R_U_ADDR];
-    int transferred = 0;
-
-    trace_milkymist_ac97_in_cb(avail_b, remaining);
-
-    /* prevent from raising an IRQ */
-    if (temp == 0) {
-        return;
-    }
-
-    while (temp) {
-        int acquired, to_copy;
-
-        to_copy = audio_MIN(temp, sizeof(buf));
-        acquired = AUD_read(s->voice_in, buf, to_copy);
-        if (!acquired) {
-            break;
-        }
-
-        cpu_physical_memory_write(addr, buf, acquired);
-
-        temp -= acquired;
-        addr += acquired;
-        transferred += acquired;
-    }
-
-    trace_milkymist_ac97_in_cb_transferred(transferred);
-
-    s->regs[R_U_ADDR] = addr;
-    s->regs[R_U_REMAINING] -= transferred;
-
-    if ((s->regs[R_U_CTRL] & CTRL_EN) && (s->regs[R_U_REMAINING] == 0)) {
-        trace_milkymist_ac97_pulse_irq_dmaw();
-        qemu_irq_pulse(s->dmaw_irq);
-    }
-}
-
-static void ac97_out_cb(void *opaque, int free_b)
-{
-    MilkymistAC97State *s = opaque;
-    uint8_t buf[4096];
-    uint32_t remaining = s->regs[R_D_REMAINING];
-    int temp = audio_MIN(remaining, free_b);
-    uint32_t addr = s->regs[R_D_ADDR];
-    int transferred = 0;
-
-    trace_milkymist_ac97_out_cb(free_b, remaining);
-
-    /* prevent from raising an IRQ */
-    if (temp == 0) {
-        return;
-    }
-
-    while (temp) {
-        int copied, to_copy;
-
-        to_copy = audio_MIN(temp, sizeof(buf));
-        cpu_physical_memory_read(addr, buf, to_copy);
-        copied = AUD_write(s->voice_out, buf, to_copy);
-        if (!copied) {
-            break;
-        }
-        temp -= copied;
-        addr += copied;
-        transferred += copied;
-    }
-
-    trace_milkymist_ac97_out_cb_transferred(transferred);
-
-    s->regs[R_D_ADDR] = addr;
-    s->regs[R_D_REMAINING] -= transferred;
-
-    if ((s->regs[R_D_CTRL] & CTRL_EN) && (s->regs[R_D_REMAINING] == 0)) {
-        trace_milkymist_ac97_pulse_irq_dmar();
-        qemu_irq_pulse(s->dmar_irq);
-    }
-}
-
-static void milkymist_ac97_reset(DeviceState *d)
-{
-    MilkymistAC97State *s = container_of(d, MilkymistAC97State, busdev.qdev);
-    int i;
-
-    for (i = 0; i < R_MAX; i++) {
-        s->regs[i] = 0;
-    }
-
-    AUD_set_active_in(s->voice_in, 0);
-    AUD_set_active_out(s->voice_out, 0);
-}
-
-static int ac97_post_load(void *opaque, int version_id)
-{
-    MilkymistAC97State *s = opaque;
-
-    update_voices(s);
-
-    return 0;
-}
-
-static int milkymist_ac97_init(SysBusDevice *dev)
-{
-    MilkymistAC97State *s = FROM_SYSBUS(typeof(*s), dev);
-
-    struct audsettings as;
-    sysbus_init_irq(dev, &s->crrequest_irq);
-    sysbus_init_irq(dev, &s->crreply_irq);
-    sysbus_init_irq(dev, &s->dmar_irq);
-    sysbus_init_irq(dev, &s->dmaw_irq);
-
-    AUD_register_card("Milkymist AC'97", &s->card);
-
-    as.freq = 48000;
-    as.nchannels = 2;
-    as.fmt = AUD_FMT_S16;
-    as.endianness = 1;
-
-    s->voice_in = AUD_open_in(&s->card, s->voice_in,
-            "mm_ac97.in", s, ac97_in_cb, &as);
-    s->voice_out = AUD_open_out(&s->card, s->voice_out,
-            "mm_ac97.out", s, ac97_out_cb, &as);
-
-    memory_region_init_io(&s->regs_region, &ac97_mmio_ops, s,
-            "milkymist-ac97", R_MAX * 4);
-    sysbus_init_mmio(dev, &s->regs_region);
-
-    return 0;
-}
-
-static const VMStateDescription vmstate_milkymist_ac97 = {
-    .name = "milkymist-ac97",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .post_load = ac97_post_load,
-    .fields      = (VMStateField[]) {
-        VMSTATE_UINT32_ARRAY(regs, MilkymistAC97State, R_MAX),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-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 const 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_types(void)
-{
-    type_register_static(&milkymist_ac97_info);
-}
-
-type_init(milkymist_ac97_register_types)
diff --git a/hw/milkymist-hpdmc.c b/hw/milkymist-hpdmc.c
deleted file mode 100644 (file)
index d922f6f..0000000
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- *  QEMU model of the Milkymist High Performance Dynamic Memory Controller.
- *
- *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
- *
- * 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/>.
- *
- *
- * Specification available at:
- *   http://www.milkymist.org/socdoc/hpdmc.pdf
- */
-
-#include "hw/hw.h"
-#include "hw/sysbus.h"
-#include "trace.h"
-#include "qemu/error-report.h"
-
-enum {
-    R_SYSTEM = 0,
-    R_BYPASS,
-    R_TIMING,
-    R_IODELAY,
-    R_MAX
-};
-
-enum {
-    IODELAY_DQSDELAY_RDY = (1<<5),
-    IODELAY_PLL1_LOCKED  = (1<<6),
-    IODELAY_PLL2_LOCKED  = (1<<7),
-};
-
-struct MilkymistHpdmcState {
-    SysBusDevice busdev;
-    MemoryRegion regs_region;
-
-    uint32_t regs[R_MAX];
-};
-typedef struct MilkymistHpdmcState MilkymistHpdmcState;
-
-static uint64_t hpdmc_read(void *opaque, hwaddr addr,
-                           unsigned size)
-{
-    MilkymistHpdmcState *s = opaque;
-    uint32_t r = 0;
-
-    addr >>= 2;
-    switch (addr) {
-    case R_SYSTEM:
-    case R_BYPASS:
-    case R_TIMING:
-    case R_IODELAY:
-        r = s->regs[addr];
-        break;
-
-    default:
-        error_report("milkymist_hpdmc: read access to unknown register 0x"
-                TARGET_FMT_plx, addr << 2);
-        break;
-    }
-
-    trace_milkymist_hpdmc_memory_read(addr << 2, r);
-
-    return r;
-}
-
-static void hpdmc_write(void *opaque, hwaddr addr, uint64_t value,
-                        unsigned size)
-{
-    MilkymistHpdmcState *s = opaque;
-
-    trace_milkymist_hpdmc_memory_write(addr, value);
-
-    addr >>= 2;
-    switch (addr) {
-    case R_SYSTEM:
-    case R_BYPASS:
-    case R_TIMING:
-        s->regs[addr] = value;
-        break;
-    case R_IODELAY:
-        /* ignore writes */
-        break;
-
-    default:
-        error_report("milkymist_hpdmc: write access to unknown register 0x"
-                TARGET_FMT_plx, addr << 2);
-        break;
-    }
-}
-
-static const MemoryRegionOps hpdmc_mmio_ops = {
-    .read = hpdmc_read,
-    .write = hpdmc_write,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void milkymist_hpdmc_reset(DeviceState *d)
-{
-    MilkymistHpdmcState *s = container_of(d, MilkymistHpdmcState, busdev.qdev);
-    int i;
-
-    for (i = 0; i < R_MAX; i++) {
-        s->regs[i] = 0;
-    }
-
-    /* defaults */
-    s->regs[R_IODELAY] = IODELAY_DQSDELAY_RDY | IODELAY_PLL1_LOCKED
-                         | IODELAY_PLL2_LOCKED;
-}
-
-static int milkymist_hpdmc_init(SysBusDevice *dev)
-{
-    MilkymistHpdmcState *s = FROM_SYSBUS(typeof(*s), dev);
-
-    memory_region_init_io(&s->regs_region, &hpdmc_mmio_ops, s,
-            "milkymist-hpdmc", R_MAX * 4);
-    sysbus_init_mmio(dev, &s->regs_region);
-
-    return 0;
-}
-
-static const VMStateDescription vmstate_milkymist_hpdmc = {
-    .name = "milkymist-hpdmc",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField[]) {
-        VMSTATE_UINT32_ARRAY(regs, MilkymistHpdmcState, R_MAX),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-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 const 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_types(void)
-{
-    type_register_static(&milkymist_hpdmc_info);
-}
-
-type_init(milkymist_hpdmc_register_types)
diff --git a/hw/milkymist-hw.h b/hw/milkymist-hw.h
deleted file mode 100644 (file)
index 4e86c4e..0000000
+++ /dev/null
@@ -1,208 +0,0 @@
-#ifndef QEMU_HW_MILKYMIST_H
-#define QEMU_HW_MILKYMIST_H
-
-#include "hw/qdev.h"
-#include "hw/qdev-addr.h"
-#include "net/net.h"
-
-static inline DeviceState *milkymist_uart_create(hwaddr base,
-        qemu_irq irq)
-{
-    DeviceState *dev;
-
-    dev = qdev_create(NULL, "milkymist-uart");
-    qdev_init_nofail(dev);
-    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
-    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq);
-
-    return dev;
-}
-
-static inline DeviceState *milkymist_hpdmc_create(hwaddr base)
-{
-    DeviceState *dev;
-
-    dev = qdev_create(NULL, "milkymist-hpdmc");
-    qdev_init_nofail(dev);
-    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
-
-    return dev;
-}
-
-static inline DeviceState *milkymist_memcard_create(hwaddr base)
-{
-    DeviceState *dev;
-
-    dev = qdev_create(NULL, "milkymist-memcard");
-    qdev_init_nofail(dev);
-    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
-
-    return dev;
-}
-
-static inline DeviceState *milkymist_vgafb_create(hwaddr base,
-        uint32_t fb_offset, uint32_t fb_mask)
-{
-    DeviceState *dev;
-
-    dev = qdev_create(NULL, "milkymist-vgafb");
-    qdev_prop_set_uint32(dev, "fb_offset", fb_offset);
-    qdev_prop_set_uint32(dev, "fb_mask", fb_mask);
-    qdev_init_nofail(dev);
-    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
-
-    return dev;
-}
-
-static inline DeviceState *milkymist_sysctl_create(hwaddr base,
-        qemu_irq gpio_irq, qemu_irq timer0_irq, qemu_irq timer1_irq,
-        uint32_t freq_hz, uint32_t system_id, uint32_t capabilities,
-        uint32_t gpio_strappings)
-{
-    DeviceState *dev;
-
-    dev = qdev_create(NULL, "milkymist-sysctl");
-    qdev_prop_set_uint32(dev, "frequency", freq_hz);
-    qdev_prop_set_uint32(dev, "systemid", system_id);
-    qdev_prop_set_uint32(dev, "capabilities", capabilities);
-    qdev_prop_set_uint32(dev, "gpio_strappings", gpio_strappings);
-    qdev_init_nofail(dev);
-    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
-    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, gpio_irq);
-    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, timer0_irq);
-    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 2, timer1_irq);
-
-    return dev;
-}
-
-static inline DeviceState *milkymist_pfpu_create(hwaddr base,
-        qemu_irq irq)
-{
-    DeviceState *dev;
-
-    dev = qdev_create(NULL, "milkymist-pfpu");
-    qdev_init_nofail(dev);
-    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
-    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq);
-    return dev;
-}
-
-#ifdef CONFIG_GLX
-#include <X11/Xlib.h>
-#include <GL/glx.h>
-static const int glx_fbconfig_attr[] = {
-    GLX_GREEN_SIZE, 5,
-    GLX_GREEN_SIZE, 6,
-    GLX_BLUE_SIZE, 5,
-    None
-};
-#endif
-
-static inline DeviceState *milkymist_tmu2_create(hwaddr base,
-        qemu_irq irq)
-{
-#ifdef CONFIG_GLX
-    DeviceState *dev;
-    Display *d;
-    GLXFBConfig *configs;
-    int nelements;
-    int ver_major, ver_minor;
-
-    if (display_type == DT_NOGRAPHIC) {
-        return NULL;
-    }
-
-    /* check that GLX will work */
-    d = XOpenDisplay(NULL);
-    if (d == NULL) {
-        return NULL;
-    }
-
-    if (!glXQueryVersion(d, &ver_major, &ver_minor)) {
-        /* Yeah, sometimes getting the GLX version can fail.
-         * Isn't X beautiful? */
-        XCloseDisplay(d);
-        return NULL;
-    }
-
-    if ((ver_major < 1) || ((ver_major == 1) && (ver_minor < 3))) {
-        printf("Your GLX version is %d.%d,"
-          "but TMU emulation needs at least 1.3. TMU disabled.\n",
-          ver_major, ver_minor);
-        XCloseDisplay(d);
-        return NULL;
-    }
-
-    configs = glXChooseFBConfig(d, 0, glx_fbconfig_attr, &nelements);
-    if (configs == NULL) {
-        XCloseDisplay(d);
-        return NULL;
-    }
-
-    XFree(configs);
-    XCloseDisplay(d);
-
-    dev = qdev_create(NULL, "milkymist-tmu2");
-    qdev_init_nofail(dev);
-    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
-    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq);
-
-    return dev;
-#else
-    return NULL;
-#endif
-}
-
-static inline DeviceState *milkymist_ac97_create(hwaddr base,
-        qemu_irq crrequest_irq, qemu_irq crreply_irq, qemu_irq dmar_irq,
-        qemu_irq dmaw_irq)
-{
-    DeviceState *dev;
-
-    dev = qdev_create(NULL, "milkymist-ac97");
-    qdev_init_nofail(dev);
-    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
-    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, crrequest_irq);
-    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, crreply_irq);
-    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 2, dmar_irq);
-    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 3, dmaw_irq);
-
-    return dev;
-}
-
-static inline DeviceState *milkymist_minimac2_create(hwaddr base,
-        hwaddr buffers_base, qemu_irq rx_irq, qemu_irq tx_irq)
-{
-    DeviceState *dev;
-
-    qemu_check_nic_model(&nd_table[0], "minimac2");
-    dev = qdev_create(NULL, "milkymist-minimac2");
-    qdev_set_nic_properties(dev, &nd_table[0]);
-    qdev_init_nofail(dev);
-    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
-    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 1, buffers_base);
-    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, rx_irq);
-    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, tx_irq);
-
-    return dev;
-}
-
-static inline DeviceState *milkymist_softusb_create(hwaddr base,
-        qemu_irq irq, uint32_t pmem_base, uint32_t pmem_size,
-        uint32_t dmem_base, uint32_t dmem_size)
-{
-    DeviceState *dev;
-
-    dev = qdev_create(NULL, "milkymist-softusb");
-    qdev_prop_set_uint32(dev, "pmem_size", pmem_size);
-    qdev_prop_set_uint32(dev, "dmem_size", dmem_size);
-    qdev_init_nofail(dev);
-    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
-    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 1, pmem_base);
-    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, dmem_base);
-    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq);
-
-    return dev;
-}
-
-#endif /* QEMU_HW_MILKYMIST_H */
diff --git a/hw/milkymist-memcard.c b/hw/milkymist-memcard.c
deleted file mode 100644 (file)
index d5944bc..0000000
+++ /dev/null
@@ -1,303 +0,0 @@
-/*
- *  QEMU model of the Milkymist SD Card Controller.
- *
- *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
- *
- * 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/>.
- *
- *
- * Specification available at:
- *   http://www.milkymist.org/socdoc/memcard.pdf
- */
-
-#include "hw/hw.h"
-#include "hw/sysbus.h"
-#include "sysemu/sysemu.h"
-#include "trace.h"
-#include "qemu/error-report.h"
-#include "sysemu/blockdev.h"
-#include "hw/sd.h"
-
-enum {
-    ENABLE_CMD_TX   = (1<<0),
-    ENABLE_CMD_RX   = (1<<1),
-    ENABLE_DAT_TX   = (1<<2),
-    ENABLE_DAT_RX   = (1<<3),
-};
-
-enum {
-    PENDING_CMD_TX   = (1<<0),
-    PENDING_CMD_RX   = (1<<1),
-    PENDING_DAT_TX   = (1<<2),
-    PENDING_DAT_RX   = (1<<3),
-};
-
-enum {
-    START_CMD_TX    = (1<<0),
-    START_DAT_RX    = (1<<1),
-};
-
-enum {
-    R_CLK2XDIV = 0,
-    R_ENABLE,
-    R_PENDING,
-    R_START,
-    R_CMD,
-    R_DAT,
-    R_MAX
-};
-
-struct MilkymistMemcardState {
-    SysBusDevice busdev;
-    MemoryRegion regs_region;
-    SDState *card;
-
-    int command_write_ptr;
-    int response_read_ptr;
-    int response_len;
-    int ignore_next_cmd;
-    int enabled;
-    uint8_t command[6];
-    uint8_t response[17];
-    uint32_t regs[R_MAX];
-};
-typedef struct MilkymistMemcardState MilkymistMemcardState;
-
-static void update_pending_bits(MilkymistMemcardState *s)
-{
-    /* transmits are instantaneous, thus tx pending bits are never set */
-    s->regs[R_PENDING] = 0;
-    /* if rx is enabled the corresponding pending bits are always set */
-    if (s->regs[R_ENABLE] & ENABLE_CMD_RX) {
-        s->regs[R_PENDING] |= PENDING_CMD_RX;
-    }
-    if (s->regs[R_ENABLE] & ENABLE_DAT_RX) {
-        s->regs[R_PENDING] |= PENDING_DAT_RX;
-    }
-}
-
-static void memcard_sd_command(MilkymistMemcardState *s)
-{
-    SDRequest req;
-
-    req.cmd = s->command[0] & 0x3f;
-    req.arg = (s->command[1] << 24) | (s->command[2] << 16)
-              | (s->command[3] << 8) | s->command[4];
-    req.crc = s->command[5];
-
-    s->response[0] = req.cmd;
-    s->response_len = sd_do_command(s->card, &req, s->response+1);
-    s->response_read_ptr = 0;
-
-    if (s->response_len == 16) {
-        /* R2 response */
-        s->response[0] = 0x3f;
-        s->response_len += 1;
-    } else if (s->response_len == 4) {
-        /* no crc calculation, insert dummy byte */
-        s->response[5] = 0;
-        s->response_len += 2;
-    }
-
-    if (req.cmd == 0) {
-        /* next write is a dummy byte to clock the initialization of the sd
-         * card */
-        s->ignore_next_cmd = 1;
-    }
-}
-
-static uint64_t memcard_read(void *opaque, hwaddr addr,
-                             unsigned size)
-{
-    MilkymistMemcardState *s = opaque;
-    uint32_t r = 0;
-
-    addr >>= 2;
-    switch (addr) {
-    case R_CMD:
-        if (!s->enabled) {
-            r = 0xff;
-        } else {
-            r = s->response[s->response_read_ptr++];
-            if (s->response_read_ptr > s->response_len) {
-                error_report("milkymist_memcard: "
-                        "read more cmd bytes than available. Clipping.");
-                s->response_read_ptr = 0;
-            }
-        }
-        break;
-    case R_DAT:
-        if (!s->enabled) {
-            r = 0xffffffff;
-        } else {
-            r = 0;
-            r |= sd_read_data(s->card) << 24;
-            r |= sd_read_data(s->card) << 16;
-            r |= sd_read_data(s->card) << 8;
-            r |= sd_read_data(s->card);
-        }
-        break;
-    case R_CLK2XDIV:
-    case R_ENABLE:
-    case R_PENDING:
-    case R_START:
-        r = s->regs[addr];
-        break;
-
-    default:
-        error_report("milkymist_memcard: read access to unknown register 0x"
-                TARGET_FMT_plx, addr << 2);
-        break;
-    }
-
-    trace_milkymist_memcard_memory_read(addr << 2, r);
-
-    return r;
-}
-
-static void memcard_write(void *opaque, hwaddr addr, uint64_t value,
-                          unsigned size)
-{
-    MilkymistMemcardState *s = opaque;
-
-    trace_milkymist_memcard_memory_write(addr, value);
-
-    addr >>= 2;
-    switch (addr) {
-    case R_PENDING:
-        /* clear rx pending bits */
-        s->regs[R_PENDING] &= ~(value & (PENDING_CMD_RX | PENDING_DAT_RX));
-        update_pending_bits(s);
-        break;
-    case R_CMD:
-        if (!s->enabled) {
-            break;
-        }
-        if (s->ignore_next_cmd) {
-            s->ignore_next_cmd = 0;
-            break;
-        }
-        s->command[s->command_write_ptr] = value & 0xff;
-        s->command_write_ptr = (s->command_write_ptr + 1) % 6;
-        if (s->command_write_ptr == 0) {
-            memcard_sd_command(s);
-        }
-        break;
-    case R_DAT:
-        if (!s->enabled) {
-            break;
-        }
-        sd_write_data(s->card, (value >> 24) & 0xff);
-        sd_write_data(s->card, (value >> 16) & 0xff);
-        sd_write_data(s->card, (value >> 8) & 0xff);
-        sd_write_data(s->card, value & 0xff);
-        break;
-    case R_ENABLE:
-        s->regs[addr] = value;
-        update_pending_bits(s);
-        break;
-    case R_CLK2XDIV:
-    case R_START:
-        s->regs[addr] = value;
-        break;
-
-    default:
-        error_report("milkymist_memcard: write access to unknown register 0x"
-                TARGET_FMT_plx, addr << 2);
-        break;
-    }
-}
-
-static const MemoryRegionOps memcard_mmio_ops = {
-    .read = memcard_read,
-    .write = memcard_write,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void milkymist_memcard_reset(DeviceState *d)
-{
-    MilkymistMemcardState *s =
-            container_of(d, MilkymistMemcardState, busdev.qdev);
-    int i;
-
-    s->command_write_ptr = 0;
-    s->response_read_ptr = 0;
-    s->response_len = 0;
-
-    for (i = 0; i < R_MAX; i++) {
-        s->regs[i] = 0;
-    }
-}
-
-static int milkymist_memcard_init(SysBusDevice *dev)
-{
-    MilkymistMemcardState *s = FROM_SYSBUS(typeof(*s), dev);
-    DriveInfo *dinfo;
-
-    dinfo = drive_get_next(IF_SD);
-    s->card = sd_init(dinfo ? dinfo->bdrv : NULL, 0);
-    s->enabled = dinfo ? bdrv_is_inserted(dinfo->bdrv) : 0;
-
-    memory_region_init_io(&s->regs_region, &memcard_mmio_ops, s,
-            "milkymist-memcard", R_MAX * 4);
-    sysbus_init_mmio(dev, &s->regs_region);
-
-    return 0;
-}
-
-static const VMStateDescription vmstate_milkymist_memcard = {
-    .name = "milkymist-memcard",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField[]) {
-        VMSTATE_INT32(command_write_ptr, MilkymistMemcardState),
-        VMSTATE_INT32(response_read_ptr, MilkymistMemcardState),
-        VMSTATE_INT32(response_len, MilkymistMemcardState),
-        VMSTATE_INT32(ignore_next_cmd, MilkymistMemcardState),
-        VMSTATE_INT32(enabled, MilkymistMemcardState),
-        VMSTATE_UINT8_ARRAY(command, MilkymistMemcardState, 6),
-        VMSTATE_UINT8_ARRAY(response, MilkymistMemcardState, 17),
-        VMSTATE_UINT32_ARRAY(regs, MilkymistMemcardState, R_MAX),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-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 const 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_types(void)
-{
-    type_register_static(&milkymist_memcard_info);
-}
-
-type_init(milkymist_memcard_register_types)
diff --git a/hw/milkymist-minimac2.c b/hw/milkymist-minimac2.c
deleted file mode 100644 (file)
index 29618e8..0000000
+++ /dev/null
@@ -1,547 +0,0 @@
-/*
- *  QEMU model of the Milkymist minimac2 block.
- *
- *  Copyright (c) 2011 Michael Walle <michael@walle.cc>
- *
- * 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/>.
- *
- *
- * Specification available at:
- *   not available yet
- *
- */
-
-#include "hw/hw.h"
-#include "hw/sysbus.h"
-#include "trace.h"
-#include "net/net.h"
-#include "qemu/error-report.h"
-#include "hw/qdev-addr.h"
-
-#include <zlib.h>
-
-enum {
-    R_SETUP = 0,
-    R_MDIO,
-    R_STATE0,
-    R_COUNT0,
-    R_STATE1,
-    R_COUNT1,
-    R_TXCOUNT,
-    R_MAX
-};
-
-enum {
-    SETUP_PHY_RST = (1<<0),
-};
-
-enum {
-    MDIO_DO  = (1<<0),
-    MDIO_DI  = (1<<1),
-    MDIO_OE  = (1<<2),
-    MDIO_CLK = (1<<3),
-};
-
-enum {
-    STATE_EMPTY   = 0,
-    STATE_LOADED  = 1,
-    STATE_PENDING = 2,
-};
-
-enum {
-    MDIO_OP_WRITE = 1,
-    MDIO_OP_READ  = 2,
-};
-
-enum mdio_state {
-    MDIO_STATE_IDLE,
-    MDIO_STATE_READING,
-    MDIO_STATE_WRITING,
-};
-
-enum {
-    R_PHY_ID1  = 2,
-    R_PHY_ID2  = 3,
-    R_PHY_MAX  = 32
-};
-
-#define MINIMAC2_MTU 1530
-#define MINIMAC2_BUFFER_SIZE 2048
-
-struct MilkymistMinimac2MdioState {
-    int last_clk;
-    int count;
-    uint32_t data;
-    uint16_t data_out;
-    int state;
-
-    uint8_t phy_addr;
-    uint8_t reg_addr;
-};
-typedef struct MilkymistMinimac2MdioState MilkymistMinimac2MdioState;
-
-struct MilkymistMinimac2State {
-    SysBusDevice busdev;
-    NICState *nic;
-    NICConf conf;
-    char *phy_model;
-    MemoryRegion buffers;
-    MemoryRegion regs_region;
-
-    qemu_irq rx_irq;
-    qemu_irq tx_irq;
-
-    uint32_t regs[R_MAX];
-
-    MilkymistMinimac2MdioState mdio;
-
-    uint16_t phy_regs[R_PHY_MAX];
-
-    uint8_t *rx0_buf;
-    uint8_t *rx1_buf;
-    uint8_t *tx_buf;
-};
-typedef struct MilkymistMinimac2State MilkymistMinimac2State;
-
-static const uint8_t preamble_sfd[] = {
-        0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5
-};
-
-static void minimac2_mdio_write_reg(MilkymistMinimac2State *s,
-        uint8_t phy_addr, uint8_t reg_addr, uint16_t value)
-{
-    trace_milkymist_minimac2_mdio_write(phy_addr, reg_addr, value);
-
-    /* nop */
-}
-
-static uint16_t minimac2_mdio_read_reg(MilkymistMinimac2State *s,
-        uint8_t phy_addr, uint8_t reg_addr)
-{
-    uint16_t r = s->phy_regs[reg_addr];
-
-    trace_milkymist_minimac2_mdio_read(phy_addr, reg_addr, r);
-
-    return r;
-}
-
-static void minimac2_update_mdio(MilkymistMinimac2State *s)
-{
-    MilkymistMinimac2MdioState *m = &s->mdio;
-
-    /* detect rising clk edge */
-    if (m->last_clk == 0 && (s->regs[R_MDIO] & MDIO_CLK)) {
-        /* shift data in */
-        int bit = ((s->regs[R_MDIO] & MDIO_DO)
-                   && (s->regs[R_MDIO] & MDIO_OE)) ? 1 : 0;
-        m->data = (m->data << 1) | bit;
-
-        /* check for sync */
-        if (m->data == 0xffffffff) {
-            m->count = 32;
-        }
-
-        if (m->count == 16) {
-            uint8_t start = (m->data >> 14) & 0x3;
-            uint8_t op = (m->data >> 12) & 0x3;
-            uint8_t ta = (m->data) & 0x3;
-
-            if (start == 1 && op == MDIO_OP_WRITE && ta == 2) {
-                m->state = MDIO_STATE_WRITING;
-            } else if (start == 1 && op == MDIO_OP_READ && (ta & 1) == 0) {
-                m->state = MDIO_STATE_READING;
-            } else {
-                m->state = MDIO_STATE_IDLE;
-            }
-
-            if (m->state != MDIO_STATE_IDLE) {
-                m->phy_addr = (m->data >> 7) & 0x1f;
-                m->reg_addr = (m->data >> 2) & 0x1f;
-            }
-
-            if (m->state == MDIO_STATE_READING) {
-                m->data_out = minimac2_mdio_read_reg(s, m->phy_addr,
-                        m->reg_addr);
-            }
-        }
-
-        if (m->count < 16 && m->state == MDIO_STATE_READING) {
-            int bit = (m->data_out & 0x8000) ? 1 : 0;
-            m->data_out <<= 1;
-
-            if (bit) {
-                s->regs[R_MDIO] |= MDIO_DI;
-            } else {
-                s->regs[R_MDIO] &= ~MDIO_DI;
-            }
-        }
-
-        if (m->count == 0 && m->state) {
-            if (m->state == MDIO_STATE_WRITING) {
-                uint16_t data = m->data & 0xffff;
-                minimac2_mdio_write_reg(s, m->phy_addr, m->reg_addr, data);
-            }
-            m->state = MDIO_STATE_IDLE;
-        }
-        m->count--;
-    }
-
-    m->last_clk = (s->regs[R_MDIO] & MDIO_CLK) ? 1 : 0;
-}
-
-static size_t assemble_frame(uint8_t *buf, size_t size,
-        const uint8_t *payload, size_t payload_size)
-{
-    uint32_t crc;
-
-    if (size < payload_size + 12) {
-        error_report("milkymist_minimac2: received too big ethernet frame");
-        return 0;
-    }
-
-    /* prepend preamble and sfd */
-    memcpy(buf, preamble_sfd, 8);
-
-    /* now copy the payload */
-    memcpy(buf + 8, payload, payload_size);
-
-    /* pad frame if needed */
-    if (payload_size < 60) {
-        memset(buf + payload_size + 8, 0, 60 - payload_size);
-        payload_size = 60;
-    }
-
-    /* append fcs */
-    crc = cpu_to_le32(crc32(0, buf + 8, payload_size));
-    memcpy(buf + payload_size + 8, &crc, 4);
-
-    return payload_size + 12;
-}
-
-static void minimac2_tx(MilkymistMinimac2State *s)
-{
-    uint32_t txcount = s->regs[R_TXCOUNT];
-    uint8_t *buf = s->tx_buf;
-
-    if (txcount < 64) {
-        error_report("milkymist_minimac2: ethernet frame too small (%u < %u)",
-                txcount, 64);
-        goto err;
-    }
-
-    if (txcount > MINIMAC2_MTU) {
-        error_report("milkymist_minimac2: MTU exceeded (%u > %u)",
-                txcount, MINIMAC2_MTU);
-        goto err;
-    }
-
-    if (memcmp(buf, preamble_sfd, 8) != 0) {
-        error_report("milkymist_minimac2: frame doesn't contain the preamble "
-                "and/or the SFD (%02x %02x %02x %02x %02x %02x %02x %02x)",
-                buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
-        goto err;
-    }
-
-    trace_milkymist_minimac2_tx_frame(txcount - 12);
-
-    /* send packet, skipping preamble and sfd */
-    qemu_send_packet_raw(qemu_get_queue(s->nic), buf + 8, txcount - 12);
-
-    s->regs[R_TXCOUNT] = 0;
-
-err:
-    trace_milkymist_minimac2_pulse_irq_tx();
-    qemu_irq_pulse(s->tx_irq);
-}
-
-static void update_rx_interrupt(MilkymistMinimac2State *s)
-{
-    if (s->regs[R_STATE0] == STATE_PENDING
-            || s->regs[R_STATE1] == STATE_PENDING) {
-        trace_milkymist_minimac2_raise_irq_rx();
-        qemu_irq_raise(s->rx_irq);
-    } else {
-        trace_milkymist_minimac2_lower_irq_rx();
-        qemu_irq_lower(s->rx_irq);
-    }
-}
-
-static ssize_t minimac2_rx(NetClientState *nc, const uint8_t *buf, size_t size)
-{
-    MilkymistMinimac2State *s = qemu_get_nic_opaque(nc);
-
-    uint32_t r_count;
-    uint32_t r_state;
-    uint8_t *rx_buf;
-
-    size_t frame_size;
-
-    trace_milkymist_minimac2_rx_frame(buf, size);
-
-    /* choose appropriate slot */
-    if (s->regs[R_STATE0] == STATE_LOADED) {
-        r_count = R_COUNT0;
-        r_state = R_STATE0;
-        rx_buf = s->rx0_buf;
-    } else if (s->regs[R_STATE1] == STATE_LOADED) {
-        r_count = R_COUNT1;
-        r_state = R_STATE1;
-        rx_buf = s->rx1_buf;
-    } else {
-        trace_milkymist_minimac2_drop_rx_frame(buf);
-        return size;
-    }
-
-    /* assemble frame */
-    frame_size = assemble_frame(rx_buf, MINIMAC2_BUFFER_SIZE, buf, size);
-
-    if (frame_size == 0) {
-        return size;
-    }
-
-    trace_milkymist_minimac2_rx_transfer(rx_buf, frame_size);
-
-    /* update slot */
-    s->regs[r_count] = frame_size;
-    s->regs[r_state] = STATE_PENDING;
-
-    update_rx_interrupt(s);
-
-    return size;
-}
-
-static uint64_t
-minimac2_read(void *opaque, hwaddr addr, unsigned size)
-{
-    MilkymistMinimac2State *s = opaque;
-    uint32_t r = 0;
-
-    addr >>= 2;
-    switch (addr) {
-    case R_SETUP:
-    case R_MDIO:
-    case R_STATE0:
-    case R_COUNT0:
-    case R_STATE1:
-    case R_COUNT1:
-    case R_TXCOUNT:
-        r = s->regs[addr];
-        break;
-
-    default:
-        error_report("milkymist_minimac2: read access to unknown register 0x"
-                TARGET_FMT_plx, addr << 2);
-        break;
-    }
-
-    trace_milkymist_minimac2_memory_read(addr << 2, r);
-
-    return r;
-}
-
-static void
-minimac2_write(void *opaque, hwaddr addr, uint64_t value,
-               unsigned size)
-{
-    MilkymistMinimac2State *s = opaque;
-
-    trace_milkymist_minimac2_memory_read(addr, value);
-
-    addr >>= 2;
-    switch (addr) {
-    case R_MDIO:
-    {
-        /* MDIO_DI is read only */
-        int mdio_di = (s->regs[R_MDIO] & MDIO_DI);
-        s->regs[R_MDIO] = value;
-        if (mdio_di) {
-            s->regs[R_MDIO] |= mdio_di;
-        } else {
-            s->regs[R_MDIO] &= ~mdio_di;
-        }
-
-        minimac2_update_mdio(s);
-    } break;
-    case R_TXCOUNT:
-        s->regs[addr] = value;
-        if (value > 0) {
-            minimac2_tx(s);
-        }
-        break;
-    case R_STATE0:
-    case R_STATE1:
-        s->regs[addr] = value;
-        update_rx_interrupt(s);
-        break;
-    case R_SETUP:
-    case R_COUNT0:
-    case R_COUNT1:
-        s->regs[addr] = value;
-        break;
-
-    default:
-        error_report("milkymist_minimac2: write access to unknown register 0x"
-                TARGET_FMT_plx, addr << 2);
-        break;
-    }
-}
-
-static const MemoryRegionOps minimac2_ops = {
-    .read = minimac2_read,
-    .write = minimac2_write,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int minimac2_can_rx(NetClientState *nc)
-{
-    MilkymistMinimac2State *s = qemu_get_nic_opaque(nc);
-
-    if (s->regs[R_STATE0] == STATE_LOADED) {
-        return 1;
-    }
-    if (s->regs[R_STATE1] == STATE_LOADED) {
-        return 1;
-    }
-
-    return 0;
-}
-
-static void minimac2_cleanup(NetClientState *nc)
-{
-    MilkymistMinimac2State *s = qemu_get_nic_opaque(nc);
-
-    s->nic = NULL;
-}
-
-static void milkymist_minimac2_reset(DeviceState *d)
-{
-    MilkymistMinimac2State *s =
-            container_of(d, MilkymistMinimac2State, busdev.qdev);
-    int i;
-
-    for (i = 0; i < R_MAX; i++) {
-        s->regs[i] = 0;
-    }
-    for (i = 0; i < R_PHY_MAX; i++) {
-        s->phy_regs[i] = 0;
-    }
-
-    /* defaults */
-    s->phy_regs[R_PHY_ID1] = 0x0022; /* Micrel KSZ8001L */
-    s->phy_regs[R_PHY_ID2] = 0x161a;
-}
-
-static NetClientInfo net_milkymist_minimac2_info = {
-    .type = NET_CLIENT_OPTIONS_KIND_NIC,
-    .size = sizeof(NICState),
-    .can_receive = minimac2_can_rx,
-    .receive = minimac2_rx,
-    .cleanup = minimac2_cleanup,
-};
-
-static int milkymist_minimac2_init(SysBusDevice *dev)
-{
-    MilkymistMinimac2State *s = FROM_SYSBUS(typeof(*s), dev);
-    size_t buffers_size = TARGET_PAGE_ALIGN(3 * MINIMAC2_BUFFER_SIZE);
-
-    sysbus_init_irq(dev, &s->rx_irq);
-    sysbus_init_irq(dev, &s->tx_irq);
-
-    memory_region_init_io(&s->regs_region, &minimac2_ops, s,
-                          "milkymist-minimac2", R_MAX * 4);
-    sysbus_init_mmio(dev, &s->regs_region);
-
-    /* register buffers memory */
-    memory_region_init_ram(&s->buffers, "milkymist-minimac2.buffers",
-                           buffers_size);
-    vmstate_register_ram_global(&s->buffers);
-    s->rx0_buf = memory_region_get_ram_ptr(&s->buffers);
-    s->rx1_buf = s->rx0_buf + MINIMAC2_BUFFER_SIZE;
-    s->tx_buf = s->rx1_buf + MINIMAC2_BUFFER_SIZE;
-
-    sysbus_init_mmio(dev, &s->buffers);
-
-    qemu_macaddr_default_if_unset(&s->conf.macaddr);
-    s->nic = qemu_new_nic(&net_milkymist_minimac2_info, &s->conf,
-                          object_get_typename(OBJECT(dev)), dev->qdev.id, s);
-    qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
-
-    return 0;
-}
-
-static const VMStateDescription vmstate_milkymist_minimac2_mdio = {
-    .name = "milkymist-minimac2-mdio",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField[]) {
-        VMSTATE_INT32(last_clk, MilkymistMinimac2MdioState),
-        VMSTATE_INT32(count, MilkymistMinimac2MdioState),
-        VMSTATE_UINT32(data, MilkymistMinimac2MdioState),
-        VMSTATE_UINT16(data_out, MilkymistMinimac2MdioState),
-        VMSTATE_INT32(state, MilkymistMinimac2MdioState),
-        VMSTATE_UINT8(phy_addr, MilkymistMinimac2MdioState),
-        VMSTATE_UINT8(reg_addr, MilkymistMinimac2MdioState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static const VMStateDescription vmstate_milkymist_minimac2 = {
-    .name = "milkymist-minimac2",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField[]) {
-        VMSTATE_UINT32_ARRAY(regs, MilkymistMinimac2State, R_MAX),
-        VMSTATE_UINT16_ARRAY(phy_regs, MilkymistMinimac2State, R_PHY_MAX),
-        VMSTATE_STRUCT(mdio, MilkymistMinimac2State, 0,
-                vmstate_milkymist_minimac2_mdio, MilkymistMinimac2MdioState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static Property milkymist_minimac2_properties[] = {
-    DEFINE_NIC_PROPERTIES(MilkymistMinimac2State, conf),
-    DEFINE_PROP_STRING("phy_model", MilkymistMinimac2State, phy_model),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void milkymist_minimac2_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = milkymist_minimac2_init;
-    dc->reset = milkymist_minimac2_reset;
-    dc->vmsd = &vmstate_milkymist_minimac2;
-    dc->props = milkymist_minimac2_properties;
-}
-
-static const 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_types(void)
-{
-    type_register_static(&milkymist_minimac2_info);
-}
-
-type_init(milkymist_minimac2_register_types)
diff --git a/hw/milkymist-pfpu.c b/hw/milkymist-pfpu.c
deleted file mode 100644 (file)
index ad44b4d..0000000
+++ /dev/null
@@ -1,544 +0,0 @@
-/*
- *  QEMU model of the Milkymist programmable FPU.
- *
- *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
- *
- * 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/>.
- *
- *
- * Specification available at:
- *   http://www.milkymist.org/socdoc/pfpu.pdf
- *
- */
-
-#include "hw/hw.h"
-#include "hw/sysbus.h"
-#include "trace.h"
-#include "qemu/log.h"
-#include "qemu/error-report.h"
-#include <math.h>
-
-/* #define TRACE_EXEC */
-
-#ifdef TRACE_EXEC
-#    define D_EXEC(x) x
-#else
-#    define D_EXEC(x)
-#endif
-
-enum {
-    R_CTL = 0,
-    R_MESHBASE,
-    R_HMESHLAST,
-    R_VMESHLAST,
-    R_CODEPAGE,
-    R_VERTICES,
-    R_COLLISIONS,
-    R_STRAYWRITES,
-    R_LASTDMA,
-    R_PC,
-    R_DREGBASE,
-    R_CODEBASE,
-    R_MAX
-};
-
-enum {
-    CTL_START_BUSY = (1<<0),
-};
-
-enum {
-    OP_NOP = 0,
-    OP_FADD,
-    OP_FSUB,
-    OP_FMUL,
-    OP_FABS,
-    OP_F2I,
-    OP_I2F,
-    OP_VECTOUT,
-    OP_SIN,
-    OP_COS,
-    OP_ABOVE,
-    OP_EQUAL,
-    OP_COPY,
-    OP_IF,
-    OP_TSIGN,
-    OP_QUAKE,
-};
-
-enum {
-    GPR_X = 0,
-    GPR_Y = 1,
-    GPR_FLAGS = 2,
-};
-
-enum {
-    LATENCY_FADD = 5,
-    LATENCY_FSUB = 5,
-    LATENCY_FMUL = 7,
-    LATENCY_FABS = 2,
-    LATENCY_F2I = 2,
-    LATENCY_I2F = 3,
-    LATENCY_VECTOUT = 0,
-    LATENCY_SIN = 4,
-    LATENCY_COS = 4,
-    LATENCY_ABOVE = 2,
-    LATENCY_EQUAL = 2,
-    LATENCY_COPY = 2,
-    LATENCY_IF = 2,
-    LATENCY_TSIGN = 2,
-    LATENCY_QUAKE = 2,
-    MAX_LATENCY = 7
-};
-
-#define GPR_BEGIN       0x100
-#define GPR_END         0x17f
-#define MICROCODE_BEGIN 0x200
-#define MICROCODE_END   0x3ff
-#define MICROCODE_WORDS 2048
-
-#define REINTERPRET_CAST(type, val) (*((type *)&(val)))
-
-#ifdef TRACE_EXEC
-static const char *opcode_to_str[] = {
-    "NOP", "FADD", "FSUB", "FMUL", "FABS", "F2I", "I2F", "VECTOUT",
-    "SIN", "COS", "ABOVE", "EQUAL", "COPY", "IF", "TSIGN", "QUAKE",
-};
-#endif
-
-struct MilkymistPFPUState {
-    SysBusDevice busdev;
-    MemoryRegion regs_region;
-    CharDriverState *chr;
-    qemu_irq irq;
-
-    uint32_t regs[R_MAX];
-    uint32_t gp_regs[128];
-    uint32_t microcode[MICROCODE_WORDS];
-
-    int output_queue_pos;
-    uint32_t output_queue[MAX_LATENCY];
-};
-typedef struct MilkymistPFPUState MilkymistPFPUState;
-
-static inline hwaddr
-get_dma_address(uint32_t base, uint32_t x, uint32_t y)
-{
-    return base + 8 * (128 * y + x);
-}
-
-static inline void
-output_queue_insert(MilkymistPFPUState *s, uint32_t val, int pos)
-{
-    s->output_queue[(s->output_queue_pos + pos) % MAX_LATENCY] = val;
-}
-
-static inline uint32_t
-output_queue_remove(MilkymistPFPUState *s)
-{
-    return s->output_queue[s->output_queue_pos];
-}
-
-static inline void
-output_queue_advance(MilkymistPFPUState *s)
-{
-    s->output_queue[s->output_queue_pos] = 0;
-    s->output_queue_pos = (s->output_queue_pos + 1) % MAX_LATENCY;
-}
-
-static int pfpu_decode_insn(MilkymistPFPUState *s)
-{
-    uint32_t pc = s->regs[R_PC];
-    uint32_t insn = s->microcode[pc];
-    uint32_t reg_a = (insn >> 18) & 0x7f;
-    uint32_t reg_b = (insn >> 11) & 0x7f;
-    uint32_t op = (insn >> 7) & 0xf;
-    uint32_t reg_d = insn & 0x7f;
-    uint32_t r = 0;
-    int latency = 0;
-
-    switch (op) {
-    case OP_NOP:
-        break;
-    case OP_FADD:
-    {
-        float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]);
-        float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]);
-        float t = a + b;
-        r = REINTERPRET_CAST(uint32_t, t);
-        latency = LATENCY_FADD;
-        D_EXEC(qemu_log("ADD a=%f b=%f t=%f, r=%08x\n", a, b, t, r));
-    } break;
-    case OP_FSUB:
-    {
-        float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]);
-        float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]);
-        float t = a - b;
-        r = REINTERPRET_CAST(uint32_t, t);
-        latency = LATENCY_FSUB;
-        D_EXEC(qemu_log("SUB a=%f b=%f t=%f, r=%08x\n", a, b, t, r));
-    } break;
-    case OP_FMUL:
-    {
-        float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]);
-        float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]);
-        float t = a * b;
-        r = REINTERPRET_CAST(uint32_t, t);
-        latency = LATENCY_FMUL;
-        D_EXEC(qemu_log("MUL a=%f b=%f t=%f, r=%08x\n", a, b, t, r));
-    } break;
-    case OP_FABS:
-    {
-        float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]);
-        float t = fabsf(a);
-        r = REINTERPRET_CAST(uint32_t, t);
-        latency = LATENCY_FABS;
-        D_EXEC(qemu_log("ABS a=%f t=%f, r=%08x\n", a, t, r));
-    } break;
-    case OP_F2I:
-    {
-        float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]);
-        int32_t t = a;
-        r = REINTERPRET_CAST(uint32_t, t);
-        latency = LATENCY_F2I;
-        D_EXEC(qemu_log("F2I a=%f t=%d, r=%08x\n", a, t, r));
-    } break;
-    case OP_I2F:
-    {
-        int32_t a = REINTERPRET_CAST(int32_t, s->gp_regs[reg_a]);
-        float t = a;
-        r = REINTERPRET_CAST(uint32_t, t);
-        latency = LATENCY_I2F;
-        D_EXEC(qemu_log("I2F a=%08x t=%f, r=%08x\n", a, t, r));
-    } break;
-    case OP_VECTOUT:
-    {
-        uint32_t a = cpu_to_be32(s->gp_regs[reg_a]);
-        uint32_t b = cpu_to_be32(s->gp_regs[reg_b]);
-        hwaddr dma_ptr =
-            get_dma_address(s->regs[R_MESHBASE],
-                    s->gp_regs[GPR_X], s->gp_regs[GPR_Y]);
-        cpu_physical_memory_write(dma_ptr, (uint8_t *)&a, 4);
-        cpu_physical_memory_write(dma_ptr + 4, (uint8_t *)&b, 4);
-        s->regs[R_LASTDMA] = dma_ptr + 4;
-        D_EXEC(qemu_log("VECTOUT a=%08x b=%08x dma=%08x\n", a, b, dma_ptr));
-        trace_milkymist_pfpu_vectout(a, b, dma_ptr);
-    } break;
-    case OP_SIN:
-    {
-        int32_t a = REINTERPRET_CAST(int32_t, s->gp_regs[reg_a]);
-        float t = sinf(a * (1.0f / (M_PI * 4096.0f)));
-        r = REINTERPRET_CAST(uint32_t, t);
-        latency = LATENCY_SIN;
-        D_EXEC(qemu_log("SIN a=%d t=%f, r=%08x\n", a, t, r));
-    } break;
-    case OP_COS:
-    {
-        int32_t a = REINTERPRET_CAST(int32_t, s->gp_regs[reg_a]);
-        float t = cosf(a * (1.0f / (M_PI * 4096.0f)));
-        r = REINTERPRET_CAST(uint32_t, t);
-        latency = LATENCY_COS;
-        D_EXEC(qemu_log("COS a=%d t=%f, r=%08x\n", a, t, r));
-    } break;
-    case OP_ABOVE:
-    {
-        float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]);
-        float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]);
-        float t = (a > b) ? 1.0f : 0.0f;
-        r = REINTERPRET_CAST(uint32_t, t);
-        latency = LATENCY_ABOVE;
-        D_EXEC(qemu_log("ABOVE a=%f b=%f t=%f, r=%08x\n", a, b, t, r));
-    } break;
-    case OP_EQUAL:
-    {
-        float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]);
-        float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]);
-        float t = (a == b) ? 1.0f : 0.0f;
-        r = REINTERPRET_CAST(uint32_t, t);
-        latency = LATENCY_EQUAL;
-        D_EXEC(qemu_log("EQUAL a=%f b=%f t=%f, r=%08x\n", a, b, t, r));
-    } break;
-    case OP_COPY:
-    {
-        r = s->gp_regs[reg_a];
-        latency = LATENCY_COPY;
-        D_EXEC(qemu_log("COPY"));
-    } break;
-    case OP_IF:
-    {
-        float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]);
-        float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]);
-        uint32_t f = s->gp_regs[GPR_FLAGS];
-        float t = (f != 0) ? a : b;
-        r = REINTERPRET_CAST(uint32_t, t);
-        latency = LATENCY_IF;
-        D_EXEC(qemu_log("IF f=%u a=%f b=%f t=%f, r=%08x\n", f, a, b, t, r));
-    } break;
-    case OP_TSIGN:
-    {
-        float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]);
-        float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]);
-        float t = (b < 0) ? -a : a;
-        r = REINTERPRET_CAST(uint32_t, t);
-        latency = LATENCY_TSIGN;
-        D_EXEC(qemu_log("TSIGN a=%f b=%f t=%f, r=%08x\n", a, b, t, r));
-    } break;
-    case OP_QUAKE:
-    {
-        uint32_t a = s->gp_regs[reg_a];
-        r = 0x5f3759df - (a >> 1);
-        latency = LATENCY_QUAKE;
-        D_EXEC(qemu_log("QUAKE a=%d r=%08x\n", a, r));
-    } break;
-
-    default:
-        error_report("milkymist_pfpu: unknown opcode %d", op);
-        break;
-    }
-
-    if (!reg_d) {
-        D_EXEC(qemu_log("%04d %8s R%03d, R%03d <L=%d, E=%04d>\n",
-                    s->regs[R_PC], opcode_to_str[op], reg_a, reg_b, latency,
-                    s->regs[R_PC] + latency));
-    } else {
-        D_EXEC(qemu_log("%04d %8s R%03d, R%03d <L=%d, E=%04d> -> R%03d\n",
-                    s->regs[R_PC], opcode_to_str[op], reg_a, reg_b, latency,
-                    s->regs[R_PC] + latency, reg_d));
-    }
-
-    if (op == OP_VECTOUT) {
-        return 0;
-    }
-
-    /* store output for this cycle */
-    if (reg_d) {
-        uint32_t val = output_queue_remove(s);
-        D_EXEC(qemu_log("R%03d <- 0x%08x\n", reg_d, val));
-        s->gp_regs[reg_d] = val;
-    }
-
-    output_queue_advance(s);
-
-    /* store op output */
-    if (op != OP_NOP) {
-        output_queue_insert(s, r, latency-1);
-    }
-
-    /* advance PC */
-    s->regs[R_PC]++;
-
-    return 1;
-};
-
-static void pfpu_start(MilkymistPFPUState *s)
-{
-    int x, y;
-    int i;
-
-    for (y = 0; y <= s->regs[R_VMESHLAST]; y++) {
-        for (x = 0; x <= s->regs[R_HMESHLAST]; x++) {
-            D_EXEC(qemu_log("\nprocessing x=%d y=%d\n", x, y));
-
-            /* set current position */
-            s->gp_regs[GPR_X] = x;
-            s->gp_regs[GPR_Y] = y;
-
-            /* run microcode on this position */
-            i = 0;
-            while (pfpu_decode_insn(s)) {
-                /* decode at most MICROCODE_WORDS instructions */
-                if (i++ >= MICROCODE_WORDS) {
-                    error_report("milkymist_pfpu: too many instructions "
-                            "executed in microcode. No VECTOUT?");
-                    break;
-                }
-            }
-
-            /* reset pc for next run */
-            s->regs[R_PC] = 0;
-        }
-    }
-
-    s->regs[R_VERTICES] = x * y;
-
-    trace_milkymist_pfpu_pulse_irq();
-    qemu_irq_pulse(s->irq);
-}
-
-static inline int get_microcode_address(MilkymistPFPUState *s, uint32_t addr)
-{
-    return (512 * s->regs[R_CODEPAGE]) + addr - MICROCODE_BEGIN;
-}
-
-static uint64_t pfpu_read(void *opaque, hwaddr addr,
-                          unsigned size)
-{
-    MilkymistPFPUState *s = opaque;
-    uint32_t r = 0;
-
-    addr >>= 2;
-    switch (addr) {
-    case R_CTL:
-    case R_MESHBASE:
-    case R_HMESHLAST:
-    case R_VMESHLAST:
-    case R_CODEPAGE:
-    case R_VERTICES:
-    case R_COLLISIONS:
-    case R_STRAYWRITES:
-    case R_LASTDMA:
-    case R_PC:
-    case R_DREGBASE:
-    case R_CODEBASE:
-        r = s->regs[addr];
-        break;
-    case GPR_BEGIN ... GPR_END:
-        r = s->gp_regs[addr - GPR_BEGIN];
-        break;
-    case MICROCODE_BEGIN ...  MICROCODE_END:
-        r = s->microcode[get_microcode_address(s, addr)];
-        break;
-
-    default:
-        error_report("milkymist_pfpu: read access to unknown register 0x"
-                TARGET_FMT_plx, addr << 2);
-        break;
-    }
-
-    trace_milkymist_pfpu_memory_read(addr << 2, r);
-
-    return r;
-}
-
-static void pfpu_write(void *opaque, hwaddr addr, uint64_t value,
-                       unsigned size)
-{
-    MilkymistPFPUState *s = opaque;
-
-    trace_milkymist_pfpu_memory_write(addr, value);
-
-    addr >>= 2;
-    switch (addr) {
-    case R_CTL:
-        if (value & CTL_START_BUSY) {
-            pfpu_start(s);
-        }
-        break;
-    case R_MESHBASE:
-    case R_HMESHLAST:
-    case R_VMESHLAST:
-    case R_CODEPAGE:
-    case R_VERTICES:
-    case R_COLLISIONS:
-    case R_STRAYWRITES:
-    case R_LASTDMA:
-    case R_PC:
-    case R_DREGBASE:
-    case R_CODEBASE:
-        s->regs[addr] = value;
-        break;
-    case GPR_BEGIN ...  GPR_END:
-        s->gp_regs[addr - GPR_BEGIN] = value;
-        break;
-    case MICROCODE_BEGIN ...  MICROCODE_END:
-        s->microcode[get_microcode_address(s, addr)] = value;
-        break;
-
-    default:
-        error_report("milkymist_pfpu: write access to unknown register 0x"
-                TARGET_FMT_plx, addr << 2);
-        break;
-    }
-}
-
-static const MemoryRegionOps pfpu_mmio_ops = {
-    .read = pfpu_read,
-    .write = pfpu_write,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void milkymist_pfpu_reset(DeviceState *d)
-{
-    MilkymistPFPUState *s = container_of(d, MilkymistPFPUState, busdev.qdev);
-    int i;
-
-    for (i = 0; i < R_MAX; i++) {
-        s->regs[i] = 0;
-    }
-    for (i = 0; i < 128; i++) {
-        s->gp_regs[i] = 0;
-    }
-    for (i = 0; i < MICROCODE_WORDS; i++) {
-        s->microcode[i] = 0;
-    }
-    s->output_queue_pos = 0;
-    for (i = 0; i < MAX_LATENCY; i++) {
-        s->output_queue[i] = 0;
-    }
-}
-
-static int milkymist_pfpu_init(SysBusDevice *dev)
-{
-    MilkymistPFPUState *s = FROM_SYSBUS(typeof(*s), dev);
-
-    sysbus_init_irq(dev, &s->irq);
-
-    memory_region_init_io(&s->regs_region, &pfpu_mmio_ops, s,
-            "milkymist-pfpu", MICROCODE_END * 4);
-    sysbus_init_mmio(dev, &s->regs_region);
-
-    return 0;
-}
-
-static const VMStateDescription vmstate_milkymist_pfpu = {
-    .name = "milkymist-pfpu",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField[]) {
-        VMSTATE_UINT32_ARRAY(regs, MilkymistPFPUState, R_MAX),
-        VMSTATE_UINT32_ARRAY(gp_regs, MilkymistPFPUState, 128),
-        VMSTATE_UINT32_ARRAY(microcode, MilkymistPFPUState, MICROCODE_WORDS),
-        VMSTATE_INT32(output_queue_pos, MilkymistPFPUState),
-        VMSTATE_UINT32_ARRAY(output_queue, MilkymistPFPUState, MAX_LATENCY),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-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 const 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_types(void)
-{
-    type_register_static(&milkymist_pfpu_info);
-}
-
-type_init(milkymist_pfpu_register_types)
diff --git a/hw/milkymist-softusb.c b/hw/milkymist-softusb.c
deleted file mode 100644 (file)
index 90a0ae5..0000000
+++ /dev/null
@@ -1,334 +0,0 @@
-/*
- *  QEMU model of the Milkymist SoftUSB block.
- *
- *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
- *
- * 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/>.
- *
- *
- * Specification available at:
- *   not available yet
- */
-
-#include "hw/hw.h"
-#include "hw/sysbus.h"
-#include "trace.h"
-#include "ui/console.h"
-#include "hw/hid.h"
-#include "qemu/error-report.h"
-
-enum {
-    R_CTRL = 0,
-    R_MAX
-};
-
-enum {
-    CTRL_RESET = (1<<0),
-};
-
-#define COMLOC_DEBUG_PRODUCE 0x1000
-#define COMLOC_DEBUG_BASE    0x1001
-#define COMLOC_MEVT_PRODUCE  0x1101
-#define COMLOC_MEVT_BASE     0x1102
-#define COMLOC_KEVT_PRODUCE  0x1142
-#define COMLOC_KEVT_BASE     0x1143
-
-struct MilkymistSoftUsbState {
-    SysBusDevice busdev;
-    HIDState hid_kbd;
-    HIDState hid_mouse;
-
-    MemoryRegion regs_region;
-    MemoryRegion pmem;
-    MemoryRegion dmem;
-    qemu_irq irq;
-
-    void *pmem_ptr;
-    void *dmem_ptr;
-
-    /* device properties */
-    uint32_t pmem_size;
-    uint32_t dmem_size;
-
-    /* device registers */
-    uint32_t regs[R_MAX];
-
-    /* mouse state */
-    uint8_t mouse_hid_buffer[4];
-
-    /* keyboard state */
-    uint8_t kbd_hid_buffer[8];
-};
-typedef struct MilkymistSoftUsbState MilkymistSoftUsbState;
-
-static uint64_t softusb_read(void *opaque, hwaddr addr,
-                             unsigned size)
-{
-    MilkymistSoftUsbState *s = opaque;
-    uint32_t r = 0;
-
-    addr >>= 2;
-    switch (addr) {
-    case R_CTRL:
-        r = s->regs[addr];
-        break;
-
-    default:
-        error_report("milkymist_softusb: read access to unknown register 0x"
-                TARGET_FMT_plx, addr << 2);
-        break;
-    }
-
-    trace_milkymist_softusb_memory_read(addr << 2, r);
-
-    return r;
-}
-
-static void
-softusb_write(void *opaque, hwaddr addr, uint64_t value,
-              unsigned size)
-{
-    MilkymistSoftUsbState *s = opaque;
-
-    trace_milkymist_softusb_memory_write(addr, value);
-
-    addr >>= 2;
-    switch (addr) {
-    case R_CTRL:
-        s->regs[addr] = value;
-        break;
-
-    default:
-        error_report("milkymist_softusb: write access to unknown register 0x"
-                TARGET_FMT_plx, addr << 2);
-        break;
-    }
-}
-
-static const MemoryRegionOps softusb_mmio_ops = {
-    .read = softusb_read,
-    .write = softusb_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-};
-
-static inline void softusb_read_dmem(MilkymistSoftUsbState *s,
-        uint32_t offset, uint8_t *buf, uint32_t len)
-{
-    if (offset + len >= s->dmem_size) {
-        error_report("milkymist_softusb: read dmem out of bounds "
-                "at offset 0x%x, len %d", offset, len);
-        memset(buf, 0, len);
-        return;
-    }
-
-    memcpy(buf, s->dmem_ptr + offset, len);
-}
-
-static inline void softusb_write_dmem(MilkymistSoftUsbState *s,
-        uint32_t offset, uint8_t *buf, uint32_t len)
-{
-    if (offset + len >= s->dmem_size) {
-        error_report("milkymist_softusb: write dmem out of bounds "
-                "at offset 0x%x, len %d", offset, len);
-        return;
-    }
-
-    memcpy(s->dmem_ptr + offset, buf, len);
-}
-
-static inline void softusb_read_pmem(MilkymistSoftUsbState *s,
-        uint32_t offset, uint8_t *buf, uint32_t len)
-{
-    if (offset + len >= s->pmem_size) {
-        error_report("milkymist_softusb: read pmem out of bounds "
-                "at offset 0x%x, len %d", offset, len);
-        memset(buf, 0, len);
-        return;
-    }
-
-    memcpy(buf, s->pmem_ptr + offset, len);
-}
-
-static inline void softusb_write_pmem(MilkymistSoftUsbState *s,
-        uint32_t offset, uint8_t *buf, uint32_t len)
-{
-    if (offset + len >= s->pmem_size) {
-        error_report("milkymist_softusb: write pmem out of bounds "
-                "at offset 0x%x, len %d", offset, len);
-        return;
-    }
-
-    memcpy(s->pmem_ptr + offset, buf, len);
-}
-
-static void softusb_mouse_changed(MilkymistSoftUsbState *s)
-{
-    uint8_t m;
-
-    softusb_read_dmem(s, COMLOC_MEVT_PRODUCE, &m, 1);
-    trace_milkymist_softusb_mevt(m);
-    softusb_write_dmem(s, COMLOC_MEVT_BASE + 4 * m, s->mouse_hid_buffer, 4);
-    m = (m + 1) & 0xf;
-    softusb_write_dmem(s, COMLOC_MEVT_PRODUCE, &m, 1);
-
-    trace_milkymist_softusb_pulse_irq();
-    qemu_irq_pulse(s->irq);
-}
-
-static void softusb_kbd_changed(MilkymistSoftUsbState *s)
-{
-    uint8_t m;
-
-    softusb_read_dmem(s, COMLOC_KEVT_PRODUCE, &m, 1);
-    trace_milkymist_softusb_kevt(m);
-    softusb_write_dmem(s, COMLOC_KEVT_BASE + 8 * m, s->kbd_hid_buffer, 8);
-    m = (m + 1) & 0x7;
-    softusb_write_dmem(s, COMLOC_KEVT_PRODUCE, &m, 1);
-
-    trace_milkymist_softusb_pulse_irq();
-    qemu_irq_pulse(s->irq);
-}
-
-static void softusb_kbd_hid_datain(HIDState *hs)
-{
-    MilkymistSoftUsbState *s = container_of(hs, MilkymistSoftUsbState, hid_kbd);
-    int len;
-
-    /* if device is in reset, do nothing */
-    if (s->regs[R_CTRL] & CTRL_RESET) {
-        return;
-    }
-
-    len = hid_keyboard_poll(hs, s->kbd_hid_buffer, sizeof(s->kbd_hid_buffer));
-
-    if (len == 8) {
-        softusb_kbd_changed(s);
-    }
-}
-
-static void softusb_mouse_hid_datain(HIDState *hs)
-{
-    MilkymistSoftUsbState *s =
-            container_of(hs, MilkymistSoftUsbState, hid_mouse);
-    int len;
-
-    /* if device is in reset, do nothing */
-    if (s->regs[R_CTRL] & CTRL_RESET) {
-        return;
-    }
-
-    len = hid_pointer_poll(hs, s->mouse_hid_buffer,
-            sizeof(s->mouse_hid_buffer));
-
-    if (len == 4) {
-        softusb_mouse_changed(s);
-    }
-}
-
-static void milkymist_softusb_reset(DeviceState *d)
-{
-    MilkymistSoftUsbState *s =
-            container_of(d, MilkymistSoftUsbState, busdev.qdev);
-    int i;
-
-    for (i = 0; i < R_MAX; i++) {
-        s->regs[i] = 0;
-    }
-    memset(s->kbd_hid_buffer, 0, sizeof(s->kbd_hid_buffer));
-    memset(s->mouse_hid_buffer, 0, sizeof(s->mouse_hid_buffer));
-
-    hid_reset(&s->hid_kbd);
-    hid_reset(&s->hid_mouse);
-
-    /* defaults */
-    s->regs[R_CTRL] = CTRL_RESET;
-}
-
-static int milkymist_softusb_init(SysBusDevice *dev)
-{
-    MilkymistSoftUsbState *s = FROM_SYSBUS(typeof(*s), dev);
-
-    sysbus_init_irq(dev, &s->irq);
-
-    memory_region_init_io(&s->regs_region, &softusb_mmio_ops, s,
-                          "milkymist-softusb", R_MAX * 4);
-    sysbus_init_mmio(dev, &s->regs_region);
-
-    /* register pmem and dmem */
-    memory_region_init_ram(&s->pmem, "milkymist-softusb.pmem",
-                           s->pmem_size);
-    vmstate_register_ram_global(&s->pmem);
-    s->pmem_ptr = memory_region_get_ram_ptr(&s->pmem);
-    sysbus_init_mmio(dev, &s->pmem);
-    memory_region_init_ram(&s->dmem, "milkymist-softusb.dmem",
-                           s->dmem_size);
-    vmstate_register_ram_global(&s->dmem);
-    s->dmem_ptr = memory_region_get_ram_ptr(&s->dmem);
-    sysbus_init_mmio(dev, &s->dmem);
-
-    hid_init(&s->hid_kbd, HID_KEYBOARD, softusb_kbd_hid_datain);
-    hid_init(&s->hid_mouse, HID_MOUSE, softusb_mouse_hid_datain);
-
-    return 0;
-}
-
-static const VMStateDescription vmstate_milkymist_softusb = {
-    .name = "milkymist-softusb",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField[]) {
-        VMSTATE_UINT32_ARRAY(regs, MilkymistSoftUsbState, R_MAX),
-        VMSTATE_HID_KEYBOARD_DEVICE(hid_kbd, MilkymistSoftUsbState),
-        VMSTATE_HID_POINTER_DEVICE(hid_mouse, MilkymistSoftUsbState),
-        VMSTATE_BUFFER(kbd_hid_buffer, MilkymistSoftUsbState),
-        VMSTATE_BUFFER(mouse_hid_buffer, MilkymistSoftUsbState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static Property milkymist_softusb_properties[] = {
-    DEFINE_PROP_UINT32("pmem_size", MilkymistSoftUsbState, pmem_size, 0x00001000),
-    DEFINE_PROP_UINT32("dmem_size", MilkymistSoftUsbState, dmem_size, 0x00002000),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void milkymist_softusb_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = milkymist_softusb_init;
-    dc->reset = milkymist_softusb_reset;
-    dc->vmsd = &vmstate_milkymist_softusb;
-    dc->props = milkymist_softusb_properties;
-}
-
-static const 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_types(void)
-{
-    type_register_static(&milkymist_softusb_info);
-}
-
-type_init(milkymist_softusb_register_types)
diff --git a/hw/milkymist-sysctl.c b/hw/milkymist-sysctl.c
deleted file mode 100644 (file)
index e083a28..0000000
+++ /dev/null
@@ -1,338 +0,0 @@
-/*
- *  QEMU model of the Milkymist System Controller.
- *
- *  Copyright (c) 2010-2012 Michael Walle <michael@walle.cc>
- *
- * 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/>.
- *
- *
- * Specification available at:
- *   http://www.milkymist.org/socdoc/sysctl.pdf
- */
-
-#include "hw/hw.h"
-#include "hw/sysbus.h"
-#include "sysemu/sysemu.h"
-#include "trace.h"
-#include "qemu/timer.h"
-#include "hw/ptimer.h"
-#include "qemu/error-report.h"
-
-enum {
-    CTRL_ENABLE      = (1<<0),
-    CTRL_AUTORESTART = (1<<1),
-};
-
-enum {
-    ICAP_READY       = (1<<0),
-};
-
-enum {
-    R_GPIO_IN         = 0,
-    R_GPIO_OUT,
-    R_GPIO_INTEN,
-    R_TIMER0_CONTROL  = 4,
-    R_TIMER0_COMPARE,
-    R_TIMER0_COUNTER,
-    R_TIMER1_CONTROL  = 8,
-    R_TIMER1_COMPARE,
-    R_TIMER1_COUNTER,
-    R_ICAP = 16,
-    R_DBG_SCRATCHPAD  = 20,
-    R_DBG_WRITE_LOCK,
-    R_CLK_FREQUENCY   = 29,
-    R_CAPABILITIES,
-    R_SYSTEM_ID,
-    R_MAX
-};
-
-struct MilkymistSysctlState {
-    SysBusDevice busdev;
-    MemoryRegion regs_region;
-
-    QEMUBH *bh0;
-    QEMUBH *bh1;
-    ptimer_state *ptimer0;
-    ptimer_state *ptimer1;
-
-    uint32_t freq_hz;
-    uint32_t capabilities;
-    uint32_t systemid;
-    uint32_t strappings;
-
-    uint32_t regs[R_MAX];
-
-    qemu_irq gpio_irq;
-    qemu_irq timer0_irq;
-    qemu_irq timer1_irq;
-};
-typedef struct MilkymistSysctlState MilkymistSysctlState;
-
-static void sysctl_icap_write(MilkymistSysctlState *s, uint32_t value)
-{
-    trace_milkymist_sysctl_icap_write(value);
-    switch (value & 0xffff) {
-    case 0x000e:
-        qemu_system_shutdown_request();
-        break;
-    }
-}
-
-static uint64_t sysctl_read(void *opaque, hwaddr addr,
-                            unsigned size)
-{
-    MilkymistSysctlState *s = opaque;
-    uint32_t r = 0;
-
-    addr >>= 2;
-    switch (addr) {
-    case R_TIMER0_COUNTER:
-        r = (uint32_t)ptimer_get_count(s->ptimer0);
-        /* milkymist timer counts up */
-        r = s->regs[R_TIMER0_COMPARE] - r;
-        break;
-    case R_TIMER1_COUNTER:
-        r = (uint32_t)ptimer_get_count(s->ptimer1);
-        /* milkymist timer counts up */
-        r = s->regs[R_TIMER1_COMPARE] - r;
-        break;
-    case R_GPIO_IN:
-    case R_GPIO_OUT:
-    case R_GPIO_INTEN:
-    case R_TIMER0_CONTROL:
-    case R_TIMER0_COMPARE:
-    case R_TIMER1_CONTROL:
-    case R_TIMER1_COMPARE:
-    case R_ICAP:
-    case R_DBG_SCRATCHPAD:
-    case R_DBG_WRITE_LOCK:
-    case R_CLK_FREQUENCY:
-    case R_CAPABILITIES:
-    case R_SYSTEM_ID:
-        r = s->regs[addr];
-        break;
-
-    default:
-        error_report("milkymist_sysctl: read access to unknown register 0x"
-                TARGET_FMT_plx, addr << 2);
-        break;
-    }
-
-    trace_milkymist_sysctl_memory_read(addr << 2, r);
-
-    return r;
-}
-
-static void sysctl_write(void *opaque, hwaddr addr, uint64_t value,
-                         unsigned size)
-{
-    MilkymistSysctlState *s = opaque;
-
-    trace_milkymist_sysctl_memory_write(addr, value);
-
-    addr >>= 2;
-    switch (addr) {
-    case R_GPIO_OUT:
-    case R_GPIO_INTEN:
-    case R_TIMER0_COUNTER:
-    case R_TIMER1_COUNTER:
-    case R_DBG_SCRATCHPAD:
-        s->regs[addr] = value;
-        break;
-    case R_TIMER0_COMPARE:
-        ptimer_set_limit(s->ptimer0, value, 0);
-        s->regs[addr] = value;
-        break;
-    case R_TIMER1_COMPARE:
-        ptimer_set_limit(s->ptimer1, value, 0);
-        s->regs[addr] = value;
-        break;
-    case R_TIMER0_CONTROL:
-        s->regs[addr] = value;
-        if (s->regs[R_TIMER0_CONTROL] & CTRL_ENABLE) {
-            trace_milkymist_sysctl_start_timer0();
-            ptimer_set_count(s->ptimer0,
-                    s->regs[R_TIMER0_COMPARE] - s->regs[R_TIMER0_COUNTER]);
-            ptimer_run(s->ptimer0, 0);
-        } else {
-            trace_milkymist_sysctl_stop_timer0();
-            ptimer_stop(s->ptimer0);
-        }
-        break;
-    case R_TIMER1_CONTROL:
-        s->regs[addr] = value;
-        if (s->regs[R_TIMER1_CONTROL] & CTRL_ENABLE) {
-            trace_milkymist_sysctl_start_timer1();
-            ptimer_set_count(s->ptimer1,
-                    s->regs[R_TIMER1_COMPARE] - s->regs[R_TIMER1_COUNTER]);
-            ptimer_run(s->ptimer1, 0);
-        } else {
-            trace_milkymist_sysctl_stop_timer1();
-            ptimer_stop(s->ptimer1);
-        }
-        break;
-    case R_ICAP:
-        sysctl_icap_write(s, value);
-        break;
-    case R_DBG_WRITE_LOCK:
-        s->regs[addr] = 1;
-        break;
-    case R_SYSTEM_ID:
-        qemu_system_reset_request();
-        break;
-
-    case R_GPIO_IN:
-    case R_CLK_FREQUENCY:
-    case R_CAPABILITIES:
-        error_report("milkymist_sysctl: write to read-only register 0x"
-                TARGET_FMT_plx, addr << 2);
-        break;
-
-    default:
-        error_report("milkymist_sysctl: write access to unknown register 0x"
-                TARGET_FMT_plx, addr << 2);
-        break;
-    }
-}
-
-static const MemoryRegionOps sysctl_mmio_ops = {
-    .read = sysctl_read,
-    .write = sysctl_write,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void timer0_hit(void *opaque)
-{
-    MilkymistSysctlState *s = opaque;
-
-    if (!(s->regs[R_TIMER0_CONTROL] & CTRL_AUTORESTART)) {
-        s->regs[R_TIMER0_CONTROL] &= ~CTRL_ENABLE;
-        trace_milkymist_sysctl_stop_timer0();
-        ptimer_stop(s->ptimer0);
-    }
-
-    trace_milkymist_sysctl_pulse_irq_timer0();
-    qemu_irq_pulse(s->timer0_irq);
-}
-
-static void timer1_hit(void *opaque)
-{
-    MilkymistSysctlState *s = opaque;
-
-    if (!(s->regs[R_TIMER1_CONTROL] & CTRL_AUTORESTART)) {
-        s->regs[R_TIMER1_CONTROL] &= ~CTRL_ENABLE;
-        trace_milkymist_sysctl_stop_timer1();
-        ptimer_stop(s->ptimer1);
-    }
-
-    trace_milkymist_sysctl_pulse_irq_timer1();
-    qemu_irq_pulse(s->timer1_irq);
-}
-
-static void milkymist_sysctl_reset(DeviceState *d)
-{
-    MilkymistSysctlState *s =
-            container_of(d, MilkymistSysctlState, busdev.qdev);
-    int i;
-
-    for (i = 0; i < R_MAX; i++) {
-        s->regs[i] = 0;
-    }
-
-    ptimer_stop(s->ptimer0);
-    ptimer_stop(s->ptimer1);
-
-    /* defaults */
-    s->regs[R_ICAP] = ICAP_READY;
-    s->regs[R_SYSTEM_ID] = s->systemid;
-    s->regs[R_CLK_FREQUENCY] = s->freq_hz;
-    s->regs[R_CAPABILITIES] = s->capabilities;
-    s->regs[R_GPIO_IN] = s->strappings;
-}
-
-static int milkymist_sysctl_init(SysBusDevice *dev)
-{
-    MilkymistSysctlState *s = FROM_SYSBUS(typeof(*s), dev);
-
-    sysbus_init_irq(dev, &s->gpio_irq);
-    sysbus_init_irq(dev, &s->timer0_irq);
-    sysbus_init_irq(dev, &s->timer1_irq);
-
-    s->bh0 = qemu_bh_new(timer0_hit, s);
-    s->bh1 = qemu_bh_new(timer1_hit, s);
-    s->ptimer0 = ptimer_init(s->bh0);
-    s->ptimer1 = ptimer_init(s->bh1);
-    ptimer_set_freq(s->ptimer0, s->freq_hz);
-    ptimer_set_freq(s->ptimer1, s->freq_hz);
-
-    memory_region_init_io(&s->regs_region, &sysctl_mmio_ops, s,
-            "milkymist-sysctl", R_MAX * 4);
-    sysbus_init_mmio(dev, &s->regs_region);
-
-    return 0;
-}
-
-static const VMStateDescription vmstate_milkymist_sysctl = {
-    .name = "milkymist-sysctl",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField[]) {
-        VMSTATE_UINT32_ARRAY(regs, MilkymistSysctlState, R_MAX),
-        VMSTATE_PTIMER(ptimer0, MilkymistSysctlState),
-        VMSTATE_PTIMER(ptimer1, MilkymistSysctlState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static Property milkymist_sysctl_properties[] = {
-    DEFINE_PROP_UINT32("frequency", MilkymistSysctlState,
-    freq_hz, 80000000),
-    DEFINE_PROP_UINT32("capabilities", MilkymistSysctlState,
-    capabilities, 0x00000000),
-    DEFINE_PROP_UINT32("systemid", MilkymistSysctlState,
-    systemid, 0x10014d31),
-    DEFINE_PROP_UINT32("gpio_strappings", MilkymistSysctlState,
-    strappings, 0x00000001),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void milkymist_sysctl_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = milkymist_sysctl_init;
-    dc->reset = milkymist_sysctl_reset;
-    dc->vmsd = &vmstate_milkymist_sysctl;
-    dc->props = milkymist_sysctl_properties;
-}
-
-static const 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_types(void)
-{
-    type_register_static(&milkymist_sysctl_info);
-}
-
-type_init(milkymist_sysctl_register_types)
diff --git a/hw/milkymist-tmu2.c b/hw/milkymist-tmu2.c
deleted file mode 100644 (file)
index b723a04..0000000
+++ /dev/null
@@ -1,490 +0,0 @@
-/*
- *  QEMU model of the Milkymist texture mapping unit.
- *
- *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
- *  Copyright (c) 2010 Sebastien Bourdeauducq
- *                       <sebastien.bourdeauducq@lekernel.net>
- *
- * 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/>.
- *
- *
- * Specification available at:
- *   http://www.milkymist.org/socdoc/tmu2.pdf
- *
- */
-
-#include "hw/hw.h"
-#include "hw/sysbus.h"
-#include "trace.h"
-#include "qemu/error-report.h"
-
-#include <X11/Xlib.h>
-#include <GL/gl.h>
-#include <GL/glx.h>
-
-enum {
-    R_CTL = 0,
-    R_HMESHLAST,
-    R_VMESHLAST,
-    R_BRIGHTNESS,
-    R_CHROMAKEY,
-    R_VERTICESADDR,
-    R_TEXFBUF,
-    R_TEXHRES,
-    R_TEXVRES,
-    R_TEXHMASK,
-    R_TEXVMASK,
-    R_DSTFBUF,
-    R_DSTHRES,
-    R_DSTVRES,
-    R_DSTHOFFSET,
-    R_DSTVOFFSET,
-    R_DSTSQUAREW,
-    R_DSTSQUAREH,
-    R_ALPHA,
-    R_MAX
-};
-
-enum {
-    CTL_START_BUSY  = (1<<0),
-    CTL_CHROMAKEY   = (1<<1),
-};
-
-enum {
-    MAX_BRIGHTNESS = 63,
-    MAX_ALPHA      = 63,
-};
-
-enum {
-    MESH_MAXSIZE = 128,
-};
-
-struct vertex {
-    int x;
-    int y;
-} QEMU_PACKED;
-
-struct MilkymistTMU2State {
-    SysBusDevice busdev;
-    MemoryRegion regs_region;
-    CharDriverState *chr;
-    qemu_irq irq;
-
-    uint32_t regs[R_MAX];
-
-    Display *dpy;
-    GLXFBConfig glx_fb_config;
-    GLXContext glx_context;
-};
-typedef struct MilkymistTMU2State MilkymistTMU2State;
-
-static const int glx_fbconfig_attr[] = {
-    GLX_GREEN_SIZE, 5,
-    GLX_GREEN_SIZE, 6,
-    GLX_BLUE_SIZE, 5,
-    None
-};
-
-static int tmu2_glx_init(MilkymistTMU2State *s)
-{
-    GLXFBConfig *configs;
-    int nelements;
-
-    s->dpy = XOpenDisplay(NULL); /* FIXME: call XCloseDisplay() */
-    if (s->dpy == NULL) {
-        return 1;
-    }
-
-    configs = glXChooseFBConfig(s->dpy, 0, glx_fbconfig_attr, &nelements);
-    if (configs == NULL) {
-        return 1;
-    }
-
-    s->glx_fb_config = *configs;
-    XFree(configs);
-
-    /* FIXME: call glXDestroyContext() */
-    s->glx_context = glXCreateNewContext(s->dpy, s->glx_fb_config,
-            GLX_RGBA_TYPE, NULL, 1);
-    if (s->glx_context == NULL) {
-        return 1;
-    }
-
-    return 0;
-}
-
-static void tmu2_gl_map(struct vertex *mesh, int texhres, int texvres,
-        int hmeshlast, int vmeshlast, int ho, int vo, int sw, int sh)
-{
-    int x, y;
-    int x0, y0, x1, y1;
-    int u0, v0, u1, v1, u2, v2, u3, v3;
-    double xscale = 1.0 / ((double)(64 * texhres));
-    double yscale = 1.0 / ((double)(64 * texvres));
-
-    glLoadIdentity();
-    glTranslatef(ho, vo, 0);
-    glEnable(GL_TEXTURE_2D);
-    glBegin(GL_QUADS);
-
-    for (y = 0; y < vmeshlast; y++) {
-        y0 = y * sh;
-        y1 = y0 + sh;
-        for (x = 0; x < hmeshlast; x++) {
-            x0 = x * sw;
-            x1 = x0 + sw;
-
-            u0 = be32_to_cpu(mesh[MESH_MAXSIZE * y + x].x);
-            v0 = be32_to_cpu(mesh[MESH_MAXSIZE * y + x].y);
-            u1 = be32_to_cpu(mesh[MESH_MAXSIZE * y + x + 1].x);
-            v1 = be32_to_cpu(mesh[MESH_MAXSIZE * y + x + 1].y);
-            u2 = be32_to_cpu(mesh[MESH_MAXSIZE * (y + 1) + x + 1].x);
-            v2 = be32_to_cpu(mesh[MESH_MAXSIZE * (y + 1) + x + 1].y);
-            u3 = be32_to_cpu(mesh[MESH_MAXSIZE * (y + 1) + x].x);
-            v3 = be32_to_cpu(mesh[MESH_MAXSIZE * (y + 1) + x].y);
-
-            glTexCoord2d(((double)u0) * xscale, ((double)v0) * yscale);
-            glVertex3i(x0, y0, 0);
-            glTexCoord2d(((double)u1) * xscale, ((double)v1) * yscale);
-            glVertex3i(x1, y0, 0);
-            glTexCoord2d(((double)u2) * xscale, ((double)v2) * yscale);
-            glVertex3i(x1, y1, 0);
-            glTexCoord2d(((double)u3) * xscale, ((double)v3) * yscale);
-            glVertex3i(x0, y1, 0);
-        }
-    }
-
-    glEnd();
-}
-
-static void tmu2_start(MilkymistTMU2State *s)
-{
-    int pbuffer_attrib[6] = {
-        GLX_PBUFFER_WIDTH,
-        0,
-        GLX_PBUFFER_HEIGHT,
-        0,
-        GLX_PRESERVED_CONTENTS,
-        True
-    };
-
-    GLXPbuffer pbuffer;
-    GLuint texture;
-    void *fb;
-    hwaddr fb_len;
-    void *mesh;
-    hwaddr mesh_len;
-    float m;
-
-    trace_milkymist_tmu2_start();
-
-    /* Create and set up a suitable OpenGL context */
-    pbuffer_attrib[1] = s->regs[R_DSTHRES];
-    pbuffer_attrib[3] = s->regs[R_DSTVRES];
-    pbuffer = glXCreatePbuffer(s->dpy, s->glx_fb_config, pbuffer_attrib);
-    glXMakeContextCurrent(s->dpy, pbuffer, pbuffer, s->glx_context);
-
-    /* Fixup endianness. TODO: would it work on BE hosts? */
-    glPixelStorei(GL_UNPACK_SWAP_BYTES, 1);
-    glPixelStorei(GL_PACK_SWAP_BYTES, 1);
-
-    /* Row alignment */
-    glPixelStorei(GL_UNPACK_ALIGNMENT, 2);
-    glPixelStorei(GL_PACK_ALIGNMENT, 2);
-
-    /* Read the QEMU source framebuffer into an OpenGL texture */
-    glGenTextures(1, &texture);
-    glBindTexture(GL_TEXTURE_2D, texture);
-    fb_len = 2*s->regs[R_TEXHRES]*s->regs[R_TEXVRES];
-    fb = cpu_physical_memory_map(s->regs[R_TEXFBUF], &fb_len, 0);
-    if (fb == NULL) {
-        glDeleteTextures(1, &texture);
-        glXMakeContextCurrent(s->dpy, None, None, NULL);
-        glXDestroyPbuffer(s->dpy, pbuffer);
-        return;
-    }
-    glTexImage2D(GL_TEXTURE_2D, 0, 3, s->regs[R_TEXHRES], s->regs[R_TEXVRES],
-            0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, fb);
-    cpu_physical_memory_unmap(fb, fb_len, 0, fb_len);
-
-    /* Set up texturing options */
-    /* WARNING:
-     * Many cases of TMU2 masking are not supported by OpenGL.
-     * We only implement the most common ones:
-     *  - full bilinear filtering vs. nearest texel
-     *  - texture clamping vs. texture wrapping
-     */
-    if ((s->regs[R_TEXHMASK] & 0x3f) > 0x20) {
-        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-    } else {
-        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-    }
-    if ((s->regs[R_TEXHMASK] >> 6) & s->regs[R_TEXHRES]) {
-        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
-    } else {
-        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
-    }
-    if ((s->regs[R_TEXVMASK] >> 6) & s->regs[R_TEXVRES]) {
-        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
-    } else {
-        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
-    }
-
-    /* Translucency and decay */
-    glEnable(GL_BLEND);
-    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-    m = (float)(s->regs[R_BRIGHTNESS] + 1) / 64.0f;
-    glColor4f(m, m, m, (float)(s->regs[R_ALPHA] + 1) / 64.0f);
-
-    /* Read the QEMU dest. framebuffer into the OpenGL framebuffer */
-    fb_len = 2 * s->regs[R_DSTHRES] * s->regs[R_DSTVRES];
-    fb = cpu_physical_memory_map(s->regs[R_DSTFBUF], &fb_len, 0);
-    if (fb == NULL) {
-        glDeleteTextures(1, &texture);
-        glXMakeContextCurrent(s->dpy, None, None, NULL);
-        glXDestroyPbuffer(s->dpy, pbuffer);
-        return;
-    }
-
-    glDrawPixels(s->regs[R_DSTHRES], s->regs[R_DSTVRES], GL_RGB,
-            GL_UNSIGNED_SHORT_5_6_5, fb);
-    cpu_physical_memory_unmap(fb, fb_len, 0, fb_len);
-    glViewport(0, 0, s->regs[R_DSTHRES], s->regs[R_DSTVRES]);
-    glMatrixMode(GL_PROJECTION);
-    glLoadIdentity();
-    glOrtho(0.0, s->regs[R_DSTHRES], 0.0, s->regs[R_DSTVRES], -1.0, 1.0);
-    glMatrixMode(GL_MODELVIEW);
-
-    /* Map the texture */
-    mesh_len = MESH_MAXSIZE*MESH_MAXSIZE*sizeof(struct vertex);
-    mesh = cpu_physical_memory_map(s->regs[R_VERTICESADDR], &mesh_len, 0);
-    if (mesh == NULL) {
-        glDeleteTextures(1, &texture);
-        glXMakeContextCurrent(s->dpy, None, None, NULL);
-        glXDestroyPbuffer(s->dpy, pbuffer);
-        return;
-    }
-
-    tmu2_gl_map((struct vertex *)mesh,
-        s->regs[R_TEXHRES], s->regs[R_TEXVRES],
-        s->regs[R_HMESHLAST], s->regs[R_VMESHLAST],
-        s->regs[R_DSTHOFFSET], s->regs[R_DSTVOFFSET],
-        s->regs[R_DSTSQUAREW], s->regs[R_DSTSQUAREH]);
-    cpu_physical_memory_unmap(mesh, mesh_len, 0, mesh_len);
-
-    /* Write back the OpenGL framebuffer to the QEMU framebuffer */
-    fb_len = 2 * s->regs[R_DSTHRES] * s->regs[R_DSTVRES];
-    fb = cpu_physical_memory_map(s->regs[R_DSTFBUF], &fb_len, 1);
-    if (fb == NULL) {
-        glDeleteTextures(1, &texture);
-        glXMakeContextCurrent(s->dpy, None, None, NULL);
-        glXDestroyPbuffer(s->dpy, pbuffer);
-        return;
-    }
-
-    glReadPixels(0, 0, s->regs[R_DSTHRES], s->regs[R_DSTVRES], GL_RGB,
-            GL_UNSIGNED_SHORT_5_6_5, fb);
-    cpu_physical_memory_unmap(fb, fb_len, 1, fb_len);
-
-    /* Free OpenGL allocs */
-    glDeleteTextures(1, &texture);
-    glXMakeContextCurrent(s->dpy, None, None, NULL);
-    glXDestroyPbuffer(s->dpy, pbuffer);
-
-    s->regs[R_CTL] &= ~CTL_START_BUSY;
-
-    trace_milkymist_tmu2_pulse_irq();
-    qemu_irq_pulse(s->irq);
-}
-
-static uint64_t tmu2_read(void *opaque, hwaddr addr,
-                          unsigned size)
-{
-    MilkymistTMU2State *s = opaque;
-    uint32_t r = 0;
-
-    addr >>= 2;
-    switch (addr) {
-    case R_CTL:
-    case R_HMESHLAST:
-    case R_VMESHLAST:
-    case R_BRIGHTNESS:
-    case R_CHROMAKEY:
-    case R_VERTICESADDR:
-    case R_TEXFBUF:
-    case R_TEXHRES:
-    case R_TEXVRES:
-    case R_TEXHMASK:
-    case R_TEXVMASK:
-    case R_DSTFBUF:
-    case R_DSTHRES:
-    case R_DSTVRES:
-    case R_DSTHOFFSET:
-    case R_DSTVOFFSET:
-    case R_DSTSQUAREW:
-    case R_DSTSQUAREH:
-    case R_ALPHA:
-        r = s->regs[addr];
-        break;
-
-    default:
-        error_report("milkymist_tmu2: read access to unknown register 0x"
-                TARGET_FMT_plx, addr << 2);
-        break;
-    }
-
-    trace_milkymist_tmu2_memory_read(addr << 2, r);
-
-    return r;
-}
-
-static void tmu2_check_registers(MilkymistTMU2State *s)
-{
-    if (s->regs[R_BRIGHTNESS] > MAX_BRIGHTNESS) {
-        error_report("milkymist_tmu2: max brightness is %d", MAX_BRIGHTNESS);
-    }
-
-    if (s->regs[R_ALPHA] > MAX_ALPHA) {
-        error_report("milkymist_tmu2: max alpha is %d", MAX_ALPHA);
-    }
-
-    if (s->regs[R_VERTICESADDR] & 0x07) {
-        error_report("milkymist_tmu2: vertex mesh address has to be 64-bit "
-                "aligned");
-    }
-
-    if (s->regs[R_TEXFBUF] & 0x01) {
-        error_report("milkymist_tmu2: texture buffer address has to be "
-                "16-bit aligned");
-    }
-}
-
-static void tmu2_write(void *opaque, hwaddr addr, uint64_t value,
-                       unsigned size)
-{
-    MilkymistTMU2State *s = opaque;
-
-    trace_milkymist_tmu2_memory_write(addr, value);
-
-    addr >>= 2;
-    switch (addr) {
-    case R_CTL:
-        s->regs[addr] = value;
-        if (value & CTL_START_BUSY) {
-            tmu2_start(s);
-        }
-        break;
-    case R_BRIGHTNESS:
-    case R_HMESHLAST:
-    case R_VMESHLAST:
-    case R_CHROMAKEY:
-    case R_VERTICESADDR:
-    case R_TEXFBUF:
-    case R_TEXHRES:
-    case R_TEXVRES:
-    case R_TEXHMASK:
-    case R_TEXVMASK:
-    case R_DSTFBUF:
-    case R_DSTHRES:
-    case R_DSTVRES:
-    case R_DSTHOFFSET:
-    case R_DSTVOFFSET:
-    case R_DSTSQUAREW:
-    case R_DSTSQUAREH:
-    case R_ALPHA:
-        s->regs[addr] = value;
-        break;
-
-    default:
-        error_report("milkymist_tmu2: write access to unknown register 0x"
-                TARGET_FMT_plx, addr << 2);
-        break;
-    }
-
-    tmu2_check_registers(s);
-}
-
-static const MemoryRegionOps tmu2_mmio_ops = {
-    .read = tmu2_read,
-    .write = tmu2_write,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void milkymist_tmu2_reset(DeviceState *d)
-{
-    MilkymistTMU2State *s = container_of(d, MilkymistTMU2State, busdev.qdev);
-    int i;
-
-    for (i = 0; i < R_MAX; i++) {
-        s->regs[i] = 0;
-    }
-}
-
-static int milkymist_tmu2_init(SysBusDevice *dev)
-{
-    MilkymistTMU2State *s = FROM_SYSBUS(typeof(*s), dev);
-
-    if (tmu2_glx_init(s)) {
-        return 1;
-    }
-
-    sysbus_init_irq(dev, &s->irq);
-
-    memory_region_init_io(&s->regs_region, &tmu2_mmio_ops, s,
-            "milkymist-tmu2", R_MAX * 4);
-    sysbus_init_mmio(dev, &s->regs_region);
-
-    return 0;
-}
-
-static const VMStateDescription vmstate_milkymist_tmu2 = {
-    .name = "milkymist-tmu2",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField[]) {
-        VMSTATE_UINT32_ARRAY(regs, MilkymistTMU2State, R_MAX),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-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 const 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_types(void)
-{
-    type_register_static(&milkymist_tmu2_info);
-}
-
-type_init(milkymist_tmu2_register_types)
diff --git a/hw/milkymist-uart.c b/hw/milkymist-uart.c
deleted file mode 100644 (file)
index f3bdf69..0000000
+++ /dev/null
@@ -1,244 +0,0 @@
-/*
- *  QEMU model of the Milkymist UART block.
- *
- *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
- *
- * 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/>.
- *
- *
- * Specification available at:
- *   http://www.milkymist.org/socdoc/uart.pdf
- */
-
-#include "hw/hw.h"
-#include "hw/sysbus.h"
-#include "trace.h"
-#include "char/char.h"
-#include "qemu/error-report.h"
-
-enum {
-    R_RXTX = 0,
-    R_DIV,
-    R_STAT,
-    R_CTRL,
-    R_DBG,
-    R_MAX
-};
-
-enum {
-    STAT_THRE   = (1<<0),
-    STAT_RX_EVT = (1<<1),
-    STAT_TX_EVT = (1<<2),
-};
-
-enum {
-    CTRL_RX_IRQ_EN = (1<<0),
-    CTRL_TX_IRQ_EN = (1<<1),
-    CTRL_THRU_EN   = (1<<2),
-};
-
-enum {
-    DBG_BREAK_EN = (1<<0),
-};
-
-struct MilkymistUartState {
-    SysBusDevice busdev;
-    MemoryRegion regs_region;
-    CharDriverState *chr;
-    qemu_irq irq;
-
-    uint32_t regs[R_MAX];
-};
-typedef struct MilkymistUartState MilkymistUartState;
-
-static void uart_update_irq(MilkymistUartState *s)
-{
-    int rx_event = s->regs[R_STAT] & STAT_RX_EVT;
-    int tx_event = s->regs[R_STAT] & STAT_TX_EVT;
-    int rx_irq_en = s->regs[R_CTRL] & CTRL_RX_IRQ_EN;
-    int tx_irq_en = s->regs[R_CTRL] & CTRL_TX_IRQ_EN;
-
-    if ((rx_irq_en && rx_event) || (tx_irq_en && tx_event)) {
-        trace_milkymist_uart_raise_irq();
-        qemu_irq_raise(s->irq);
-    } else {
-        trace_milkymist_uart_lower_irq();
-        qemu_irq_lower(s->irq);
-    }
-}
-
-static uint64_t uart_read(void *opaque, hwaddr addr,
-                          unsigned size)
-{
-    MilkymistUartState *s = opaque;
-    uint32_t r = 0;
-
-    addr >>= 2;
-    switch (addr) {
-    case R_RXTX:
-        r = s->regs[addr];
-        break;
-    case R_DIV:
-    case R_STAT:
-    case R_CTRL:
-    case R_DBG:
-        r = s->regs[addr];
-        break;
-
-    default:
-        error_report("milkymist_uart: read access to unknown register 0x"
-                TARGET_FMT_plx, addr << 2);
-        break;
-    }
-
-    trace_milkymist_uart_memory_read(addr << 2, r);
-
-    return r;
-}
-
-static void uart_write(void *opaque, hwaddr addr, uint64_t value,
-                       unsigned size)
-{
-    MilkymistUartState *s = opaque;
-    unsigned char ch = value;
-
-    trace_milkymist_uart_memory_write(addr, value);
-
-    addr >>= 2;
-    switch (addr) {
-    case R_RXTX:
-        if (s->chr) {
-            qemu_chr_fe_write(s->chr, &ch, 1);
-        }
-        s->regs[R_STAT] |= STAT_TX_EVT;
-        break;
-    case R_DIV:
-    case R_CTRL:
-    case R_DBG:
-        s->regs[addr] = value;
-        break;
-
-    case R_STAT:
-        /* write one to clear bits */
-        s->regs[addr] &= ~(value & (STAT_RX_EVT | STAT_TX_EVT));
-        qemu_chr_accept_input(s->chr);
-        break;
-
-    default:
-        error_report("milkymist_uart: write access to unknown register 0x"
-                TARGET_FMT_plx, addr << 2);
-        break;
-    }
-
-    uart_update_irq(s);
-}
-
-static const MemoryRegionOps uart_mmio_ops = {
-    .read = uart_read,
-    .write = uart_write,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void uart_rx(void *opaque, const uint8_t *buf, int size)
-{
-    MilkymistUartState *s = opaque;
-
-    assert(!(s->regs[R_STAT] & STAT_RX_EVT));
-
-    s->regs[R_STAT] |= STAT_RX_EVT;
-    s->regs[R_RXTX] = *buf;
-
-    uart_update_irq(s);
-}
-
-static int uart_can_rx(void *opaque)
-{
-    MilkymistUartState *s = opaque;
-
-    return !(s->regs[R_STAT] & STAT_RX_EVT);
-}
-
-static void uart_event(void *opaque, int event)
-{
-}
-
-static void milkymist_uart_reset(DeviceState *d)
-{
-    MilkymistUartState *s = container_of(d, MilkymistUartState, busdev.qdev);
-    int i;
-
-    for (i = 0; i < R_MAX; i++) {
-        s->regs[i] = 0;
-    }
-
-    /* THRE is always set */
-    s->regs[R_STAT] = STAT_THRE;
-}
-
-static int milkymist_uart_init(SysBusDevice *dev)
-{
-    MilkymistUartState *s = FROM_SYSBUS(typeof(*s), dev);
-
-    sysbus_init_irq(dev, &s->irq);
-
-    memory_region_init_io(&s->regs_region, &uart_mmio_ops, s,
-            "milkymist-uart", R_MAX * 4);
-    sysbus_init_mmio(dev, &s->regs_region);
-
-    s->chr = qemu_char_get_next_serial();
-    if (s->chr) {
-        qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s);
-    }
-
-    return 0;
-}
-
-static const VMStateDescription vmstate_milkymist_uart = {
-    .name = "milkymist-uart",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField[]) {
-        VMSTATE_UINT32_ARRAY(regs, MilkymistUartState, R_MAX),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-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 const 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_types(void)
-{
-    type_register_static(&milkymist_uart_info);
-}
-
-type_init(milkymist_uart_register_types)
diff --git a/hw/milkymist-vgafb.c b/hw/milkymist-vgafb.c
deleted file mode 100644 (file)
index 98762ec..0000000
+++ /dev/null
@@ -1,335 +0,0 @@
-
-/*
- *  QEMU model of the Milkymist VGA framebuffer.
- *
- *  Copyright (c) 2010-2012 Michael Walle <michael@walle.cc>
- *
- * 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/>.
- *
- *
- * Specification available at:
- *   http://www.milkymist.org/socdoc/vgafb.pdf
- */
-
-#include "hw/hw.h"
-#include "hw/sysbus.h"
-#include "trace.h"
-#include "ui/console.h"
-#include "hw/framebuffer.h"
-#include "ui/pixel_ops.h"
-#include "qemu/error-report.h"
-
-#define BITS 8
-#include "hw/milkymist-vgafb_template.h"
-#define BITS 15
-#include "hw/milkymist-vgafb_template.h"
-#define BITS 16
-#include "hw/milkymist-vgafb_template.h"
-#define BITS 24
-#include "hw/milkymist-vgafb_template.h"
-#define BITS 32
-#include "hw/milkymist-vgafb_template.h"
-
-enum {
-    R_CTRL = 0,
-    R_HRES,
-    R_HSYNC_START,
-    R_HSYNC_END,
-    R_HSCAN,
-    R_VRES,
-    R_VSYNC_START,
-    R_VSYNC_END,
-    R_VSCAN,
-    R_BASEADDRESS,
-    R_BASEADDRESS_ACT,
-    R_BURST_COUNT,
-    R_DDC,
-    R_SOURCE_CLOCK,
-    R_MAX
-};
-
-enum {
-    CTRL_RESET = (1<<0),
-};
-
-struct MilkymistVgafbState {
-    SysBusDevice busdev;
-    MemoryRegion regs_region;
-    QemuConsole *con;
-
-    int invalidate;
-    uint32_t fb_offset;
-    uint32_t fb_mask;
-
-    uint32_t regs[R_MAX];
-};
-typedef struct MilkymistVgafbState MilkymistVgafbState;
-
-static int vgafb_enabled(MilkymistVgafbState *s)
-{
-    return !(s->regs[R_CTRL] & CTRL_RESET);
-}
-
-static void vgafb_update_display(void *opaque)
-{
-    MilkymistVgafbState *s = opaque;
-    DisplaySurface *surface = qemu_console_surface(s->con);
-    int first = 0;
-    int last = 0;
-    drawfn fn;
-
-    if (!vgafb_enabled(s)) {
-        return;
-    }
-
-    int dest_width = s->regs[R_HRES];
-
-    switch (surface_bits_per_pixel(surface)) {
-    case 0:
-        return;
-    case 8:
-        fn = draw_line_8;
-        break;
-    case 15:
-        fn = draw_line_15;
-        dest_width *= 2;
-        break;
-    case 16:
-        fn = draw_line_16;
-        dest_width *= 2;
-        break;
-    case 24:
-        fn = draw_line_24;
-        dest_width *= 3;
-        break;
-    case 32:
-        fn = draw_line_32;
-        dest_width *= 4;
-        break;
-    default:
-        hw_error("milkymist_vgafb: bad color depth\n");
-        break;
-    }
-
-    framebuffer_update_display(surface, sysbus_address_space(&s->busdev),
-                               s->regs[R_BASEADDRESS] + s->fb_offset,
-                               s->regs[R_HRES],
-                               s->regs[R_VRES],
-                               s->regs[R_HRES] * 2,
-                               dest_width,
-                               0,
-                               s->invalidate,
-                               fn,
-                               NULL,
-                               &first, &last);
-
-    if (first >= 0) {
-        dpy_gfx_update(s->con, 0, first, s->regs[R_HRES], last - first + 1);
-    }
-    s->invalidate = 0;
-}
-
-static void vgafb_invalidate_display(void *opaque)
-{
-    MilkymistVgafbState *s = opaque;
-    s->invalidate = 1;
-}
-
-static void vgafb_resize(MilkymistVgafbState *s)
-{
-    if (!vgafb_enabled(s)) {
-        return;
-    }
-
-    qemu_console_resize(s->con, s->regs[R_HRES], s->regs[R_VRES]);
-    s->invalidate = 1;
-}
-
-static uint64_t vgafb_read(void *opaque, hwaddr addr,
-                           unsigned size)
-{
-    MilkymistVgafbState *s = opaque;
-    uint32_t r = 0;
-
-    addr >>= 2;
-    switch (addr) {
-    case R_CTRL:
-    case R_HRES:
-    case R_HSYNC_START:
-    case R_HSYNC_END:
-    case R_HSCAN:
-    case R_VRES:
-    case R_VSYNC_START:
-    case R_VSYNC_END:
-    case R_VSCAN:
-    case R_BASEADDRESS:
-    case R_BURST_COUNT:
-    case R_DDC:
-    case R_SOURCE_CLOCK:
-        r = s->regs[addr];
-    break;
-    case R_BASEADDRESS_ACT:
-        r = s->regs[R_BASEADDRESS];
-    break;
-
-    default:
-        error_report("milkymist_vgafb: read access to unknown register 0x"
-                TARGET_FMT_plx, addr << 2);
-        break;
-    }
-
-    trace_milkymist_vgafb_memory_read(addr << 2, r);
-
-    return r;
-}
-
-static void vgafb_write(void *opaque, hwaddr addr, uint64_t value,
-                        unsigned size)
-{
-    MilkymistVgafbState *s = opaque;
-
-    trace_milkymist_vgafb_memory_write(addr, value);
-
-    addr >>= 2;
-    switch (addr) {
-    case R_CTRL:
-        s->regs[addr] = value;
-        vgafb_resize(s);
-        break;
-    case R_HSYNC_START:
-    case R_HSYNC_END:
-    case R_HSCAN:
-    case R_VSYNC_START:
-    case R_VSYNC_END:
-    case R_VSCAN:
-    case R_BURST_COUNT:
-    case R_DDC:
-    case R_SOURCE_CLOCK:
-        s->regs[addr] = value;
-        break;
-    case R_BASEADDRESS:
-        if (value & 0x1f) {
-            error_report("milkymist_vgafb: framebuffer base address have to "
-                     "be 32 byte aligned");
-            break;
-        }
-        s->regs[addr] = value & s->fb_mask;
-        s->invalidate = 1;
-        break;
-    case R_HRES:
-    case R_VRES:
-        s->regs[addr] = value;
-        vgafb_resize(s);
-        break;
-    case R_BASEADDRESS_ACT:
-        error_report("milkymist_vgafb: write to read-only register 0x"
-                TARGET_FMT_plx, addr << 2);
-        break;
-
-    default:
-        error_report("milkymist_vgafb: write access to unknown register 0x"
-                TARGET_FMT_plx, addr << 2);
-        break;
-    }
-}
-
-static const MemoryRegionOps vgafb_mmio_ops = {
-    .read = vgafb_read,
-    .write = vgafb_write,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void milkymist_vgafb_reset(DeviceState *d)
-{
-    MilkymistVgafbState *s = container_of(d, MilkymistVgafbState, busdev.qdev);
-    int i;
-
-    for (i = 0; i < R_MAX; i++) {
-        s->regs[i] = 0;
-    }
-
-    /* defaults */
-    s->regs[R_CTRL] = CTRL_RESET;
-    s->regs[R_HRES] = 640;
-    s->regs[R_VRES] = 480;
-    s->regs[R_BASEADDRESS] = 0;
-}
-
-static int milkymist_vgafb_init(SysBusDevice *dev)
-{
-    MilkymistVgafbState *s = FROM_SYSBUS(typeof(*s), dev);
-
-    memory_region_init_io(&s->regs_region, &vgafb_mmio_ops, s,
-            "milkymist-vgafb", R_MAX * 4);
-    sysbus_init_mmio(dev, &s->regs_region);
-
-    s->con = graphic_console_init(vgafb_update_display,
-                                  vgafb_invalidate_display,
-                                  NULL, NULL, s);
-
-    return 0;
-}
-
-static int vgafb_post_load(void *opaque, int version_id)
-{
-    vgafb_invalidate_display(opaque);
-    return 0;
-}
-
-static const VMStateDescription vmstate_milkymist_vgafb = {
-    .name = "milkymist-vgafb",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .post_load = vgafb_post_load,
-    .fields      = (VMStateField[]) {
-        VMSTATE_UINT32_ARRAY(regs, MilkymistVgafbState, R_MAX),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static Property milkymist_vgafb_properties[] = {
-    DEFINE_PROP_UINT32("fb_offset", MilkymistVgafbState, fb_offset, 0x0),
-    DEFINE_PROP_UINT32("fb_mask", MilkymistVgafbState, fb_mask, 0xffffffff),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void milkymist_vgafb_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = milkymist_vgafb_init;
-    dc->reset = milkymist_vgafb_reset;
-    dc->vmsd = &vmstate_milkymist_vgafb;
-    dc->props = milkymist_vgafb_properties;
-}
-
-static const 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_types(void)
-{
-    type_register_static(&milkymist_vgafb_info);
-}
-
-type_init(milkymist_vgafb_register_types)
diff --git a/hw/milkymist-vgafb_template.h b/hw/milkymist-vgafb_template.h
deleted file mode 100644 (file)
index 1d33ee8..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- *  QEMU model of the Milkymist VGA framebuffer.
- *
- *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
- *
- * 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/>.
- *
- */
-
-#if BITS == 8
-#define COPY_PIXEL(to, r, g, b)                    \
-    do {                                           \
-        *to = rgb_to_pixel8(r, g, b);              \
-        to += 1;                                   \
-    } while (0)
-#elif BITS == 15
-#define COPY_PIXEL(to, r, g, b)                    \
-    do {                                           \
-        *(uint16_t *)to = rgb_to_pixel15(r, g, b); \
-        to += 2;                                   \
-    } while (0)
-#elif BITS == 16
-#define COPY_PIXEL(to, r, g, b)                    \
-    do {                                           \
-        *(uint16_t *)to = rgb_to_pixel16(r, g, b); \
-        to += 2;                                   \
-    } while (0)
-#elif BITS == 24
-#define COPY_PIXEL(to, r, g, b)                    \
-    do {                                           \
-        uint32_t tmp = rgb_to_pixel24(r, g, b);    \
-        *(to++) =         tmp & 0xff;              \
-        *(to++) =  (tmp >> 8) & 0xff;              \
-        *(to++) = (tmp >> 16) & 0xff;              \
-    } while (0)
-#elif BITS == 32
-#define COPY_PIXEL(to, r, g, b)                    \
-    do {                                           \
-        *(uint32_t *)to = rgb_to_pixel32(r, g, b); \
-        to += 4;                                   \
-    } while (0)
-#else
-#error unknown bit depth
-#endif
-
-static void glue(draw_line_, BITS)(void *opaque, uint8_t *d, const uint8_t *s,
-        int width, int deststep)
-{
-    uint16_t rgb565;
-    uint8_t r, g, b;
-
-    while (width--) {
-        rgb565 = lduw_raw(s);
-        r = ((rgb565 >> 11) & 0x1f) << 3;
-        g = ((rgb565 >>  5) & 0x3f) << 2;
-        b = ((rgb565 >>  0) & 0x1f) << 3;
-        COPY_PIXEL(d, r, g, b);
-        s += 2;
-    }
-}
-
-#undef BITS
-#undef COPY_PIXEL
diff --git a/hw/mips-bios.h b/hw/mips-bios.h
deleted file mode 100644 (file)
index b4b88ac..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#include "cpu.h"
-
-#define BIOS_SIZE (4 * 1024 * 1024)
-#ifdef TARGET_WORDS_BIGENDIAN
-#define BIOS_FILENAME "mips_bios.bin"
-#else
-#define BIOS_FILENAME "mipsel_bios.bin"
-#endif
diff --git a/hw/mips.h b/hw/mips.h
deleted file mode 100644 (file)
index 291e85f..0000000
--- a/hw/mips.h
+++ /dev/null
@@ -1,29 +0,0 @@
-#ifndef HW_MIPS_H
-#define HW_MIPS_H
-/* Definitions for mips board emulation.  */
-
-#include "exec/memory.h"
-
-/* gt64xxx.c */
-PCIBus *gt64120_register(qemu_irq *pic);
-
-/* bonito.c */
-PCIBus *bonito_init(qemu_irq *pic);
-
-/* rc4030.c */
-typedef struct rc4030DMAState *rc4030_dma;
-void rc4030_dma_memory_rw(void *opaque, hwaddr addr, uint8_t *buf, int len, int is_write);
-void rc4030_dma_read(void *dma, uint8_t *buf, int len);
-void rc4030_dma_write(void *dma, uint8_t *buf, int len);
-
-void *rc4030_init(qemu_irq timer, qemu_irq jazz_bus,
-                  qemu_irq **irqs, rc4030_dma **dmas,
-                  MemoryRegion *sysmem);
-
-/* dp8393x.c */
-void dp83932_init(NICInfo *nd, hwaddr base, int it_shift,
-                  MemoryRegion *address_space,
-                  qemu_irq irq, void* mem_opaque,
-                  void (*memory_rw)(void *opaque, hwaddr addr, uint8_t *buf, int len, int is_write));
-
-#endif
index 1e3bca1c373785a3bf5542eb99a2e261e5a87080..0a652f85217d000287ba2216010b4f3b641e347f 100644 (file)
@@ -1,8 +1,4 @@
-obj-y += gt64xxx.o mc146818rtc.o
-obj-$(CONFIG_FULONG) += bonito.o vt82c686.o
-
-obj-y := $(addprefix ../,$(obj-y))
-
 obj-y += mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o
 obj-y += addr.o cputimer.o mips_int.o
 obj-$(CONFIG_FULONG) += mips_fulong2e.o
+obj-y += gt64xxx_pci.o
index cddc25cf3f69f8603e6591d0909e6ee3a5094982..99488f1d2a6f2a8cff217f59013f93355785c9b8 100644 (file)
@@ -21,7 +21,7 @@
  */
 
 #include "hw/hw.h"
-#include "hw/mips_cpudevs.h"
+#include "hw/mips/cpudevs.h"
 
 uint64_t cpu_mips_kseg0_to_phys(void *opaque, uint64_t addr)
 {
index 9ad13f3924a61137b0dc999cbc919a6fe7c6c737..e0266bf15ae68363ea80ce97832b076e834088f9 100644 (file)
@@ -21,7 +21,7 @@
  */
 
 #include "hw/hw.h"
-#include "hw/mips_cpudevs.h"
+#include "hw/mips/cpudevs.h"
 #include "qemu/timer.h"
 
 #define TIMER_FREQ     100 * 1000 * 1000
diff --git a/hw/mips/gt64xxx_pci.c b/hw/mips/gt64xxx_pci.c
new file mode 100644 (file)
index 0000000..189e865
--- /dev/null
@@ -0,0 +1,1188 @@
+/*
+ * QEMU GT64120 PCI host
+ *
+ * Copyright (c) 2006,2007 Aurelien Jarno
+ *
+ * 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 "hw/hw.h"
+#include "hw/mips/mips.h"
+#include "hw/pci/pci.h"
+#include "hw/pci/pci_host.h"
+#include "hw/i386/pc.h"
+#include "exec/address-spaces.h"
+
+//#define DEBUG
+
+#ifdef DEBUG
+#define DPRINTF(fmt, ...) fprintf(stderr, "%s: " fmt, __FUNCTION__, ##__VA_ARGS__)
+#else
+#define DPRINTF(fmt, ...)
+#endif
+
+#define GT_REGS                        (0x1000 >> 2)
+
+/* CPU Configuration */
+#define GT_CPU                 (0x000 >> 2)
+#define GT_MULTI               (0x120 >> 2)
+
+/* CPU Address Decode */
+#define GT_SCS10LD             (0x008 >> 2)
+#define GT_SCS10HD             (0x010 >> 2)
+#define GT_SCS32LD             (0x018 >> 2)
+#define GT_SCS32HD             (0x020 >> 2)
+#define GT_CS20LD              (0x028 >> 2)
+#define GT_CS20HD              (0x030 >> 2)
+#define GT_CS3BOOTLD           (0x038 >> 2)
+#define GT_CS3BOOTHD           (0x040 >> 2)
+#define GT_PCI0IOLD                    (0x048 >> 2)
+#define GT_PCI0IOHD                    (0x050 >> 2)
+#define GT_PCI0M0LD                    (0x058 >> 2)
+#define GT_PCI0M0HD                    (0x060 >> 2)
+#define GT_PCI0M1LD                    (0x080 >> 2)
+#define GT_PCI0M1HD                    (0x088 >> 2)
+#define GT_PCI1IOLD                    (0x090 >> 2)
+#define GT_PCI1IOHD                    (0x098 >> 2)
+#define GT_PCI1M0LD                    (0x0a0 >> 2)
+#define GT_PCI1M0HD                    (0x0a8 >> 2)
+#define GT_PCI1M1LD                    (0x0b0 >> 2)
+#define GT_PCI1M1HD                    (0x0b8 >> 2)
+#define GT_ISD                 (0x068 >> 2)
+
+#define GT_SCS10AR             (0x0d0 >> 2)
+#define GT_SCS32AR             (0x0d8 >> 2)
+#define GT_CS20R               (0x0e0 >> 2)
+#define GT_CS3BOOTR                    (0x0e8 >> 2)
+
+#define GT_PCI0IOREMAP         (0x0f0 >> 2)
+#define GT_PCI0M0REMAP         (0x0f8 >> 2)
+#define GT_PCI0M1REMAP         (0x100 >> 2)
+#define GT_PCI1IOREMAP         (0x108 >> 2)
+#define GT_PCI1M0REMAP         (0x110 >> 2)
+#define GT_PCI1M1REMAP         (0x118 >> 2)
+
+/* CPU Error Report */
+#define GT_CPUERR_ADDRLO       (0x070 >> 2)
+#define GT_CPUERR_ADDRHI       (0x078 >> 2)
+#define GT_CPUERR_DATALO       (0x128 >> 2)            /* GT-64120A only  */
+#define GT_CPUERR_DATAHI       (0x130 >> 2)            /* GT-64120A only  */
+#define GT_CPUERR_PARITY       (0x138 >> 2)            /* GT-64120A only  */
+
+/* CPU Sync Barrier */
+#define GT_PCI0SYNC                    (0x0c0 >> 2)
+#define GT_PCI1SYNC                    (0x0c8 >> 2)
+
+/* SDRAM and Device Address Decode */
+#define GT_SCS0LD              (0x400 >> 2)
+#define GT_SCS0HD              (0x404 >> 2)
+#define GT_SCS1LD              (0x408 >> 2)
+#define GT_SCS1HD              (0x40c >> 2)
+#define GT_SCS2LD              (0x410 >> 2)
+#define GT_SCS2HD              (0x414 >> 2)
+#define GT_SCS3LD              (0x418 >> 2)
+#define GT_SCS3HD              (0x41c >> 2)
+#define GT_CS0LD               (0x420 >> 2)
+#define GT_CS0HD               (0x424 >> 2)
+#define GT_CS1LD               (0x428 >> 2)
+#define GT_CS1HD               (0x42c >> 2)
+#define GT_CS2LD               (0x430 >> 2)
+#define GT_CS2HD               (0x434 >> 2)
+#define GT_CS3LD               (0x438 >> 2)
+#define GT_CS3HD               (0x43c >> 2)
+#define GT_BOOTLD              (0x440 >> 2)
+#define GT_BOOTHD              (0x444 >> 2)
+#define GT_ADERR               (0x470 >> 2)
+
+/* SDRAM Configuration */
+#define GT_SDRAM_CFG           (0x448 >> 2)
+#define GT_SDRAM_OPMODE        (0x474 >> 2)
+#define GT_SDRAM_BM                    (0x478 >> 2)
+#define GT_SDRAM_ADDRDECODE            (0x47c >> 2)
+
+/* SDRAM Parameters */
+#define GT_SDRAM_B0                    (0x44c >> 2)
+#define GT_SDRAM_B1                    (0x450 >> 2)
+#define GT_SDRAM_B2                    (0x454 >> 2)
+#define GT_SDRAM_B3                    (0x458 >> 2)
+
+/* Device Parameters */
+#define GT_DEV_B0              (0x45c >> 2)
+#define GT_DEV_B1              (0x460 >> 2)
+#define GT_DEV_B2              (0x464 >> 2)
+#define GT_DEV_B3              (0x468 >> 2)
+#define GT_DEV_BOOT                    (0x46c >> 2)
+
+/* ECC */
+#define GT_ECC_ERRDATALO       (0x480 >> 2)            /* GT-64120A only  */
+#define GT_ECC_ERRDATAHI       (0x484 >> 2)            /* GT-64120A only  */
+#define GT_ECC_MEM             (0x488 >> 2)            /* GT-64120A only  */
+#define GT_ECC_CALC            (0x48c >> 2)            /* GT-64120A only  */
+#define GT_ECC_ERRADDR         (0x490 >> 2)            /* GT-64120A only  */
+
+/* DMA Record */
+#define GT_DMA0_CNT                    (0x800 >> 2)
+#define GT_DMA1_CNT                    (0x804 >> 2)
+#define GT_DMA2_CNT                    (0x808 >> 2)
+#define GT_DMA3_CNT                    (0x80c >> 2)
+#define GT_DMA0_SA             (0x810 >> 2)
+#define GT_DMA1_SA             (0x814 >> 2)
+#define GT_DMA2_SA             (0x818 >> 2)
+#define GT_DMA3_SA             (0x81c >> 2)
+#define GT_DMA0_DA             (0x820 >> 2)
+#define GT_DMA1_DA             (0x824 >> 2)
+#define GT_DMA2_DA             (0x828 >> 2)
+#define GT_DMA3_DA             (0x82c >> 2)
+#define GT_DMA0_NEXT           (0x830 >> 2)
+#define GT_DMA1_NEXT           (0x834 >> 2)
+#define GT_DMA2_NEXT           (0x838 >> 2)
+#define GT_DMA3_NEXT           (0x83c >> 2)
+#define GT_DMA0_CUR                    (0x870 >> 2)
+#define GT_DMA1_CUR                    (0x874 >> 2)
+#define GT_DMA2_CUR                    (0x878 >> 2)
+#define GT_DMA3_CUR                    (0x87c >> 2)
+
+/* DMA Channel Control */
+#define GT_DMA0_CTRL           (0x840 >> 2)
+#define GT_DMA1_CTRL           (0x844 >> 2)
+#define GT_DMA2_CTRL           (0x848 >> 2)
+#define GT_DMA3_CTRL           (0x84c >> 2)
+
+/* DMA Arbiter */
+#define GT_DMA_ARB             (0x860 >> 2)
+
+/* Timer/Counter */
+#define GT_TC0                 (0x850 >> 2)
+#define GT_TC1                 (0x854 >> 2)
+#define GT_TC2                 (0x858 >> 2)
+#define GT_TC3                 (0x85c >> 2)
+#define GT_TC_CONTROL          (0x864 >> 2)
+
+/* PCI Internal */
+#define GT_PCI0_CMD                    (0xc00 >> 2)
+#define GT_PCI0_TOR                    (0xc04 >> 2)
+#define GT_PCI0_BS_SCS10       (0xc08 >> 2)
+#define GT_PCI0_BS_SCS32       (0xc0c >> 2)
+#define GT_PCI0_BS_CS20        (0xc10 >> 2)
+#define GT_PCI0_BS_CS3BT       (0xc14 >> 2)
+#define GT_PCI1_IACK           (0xc30 >> 2)
+#define GT_PCI0_IACK           (0xc34 >> 2)
+#define GT_PCI0_BARE           (0xc3c >> 2)
+#define GT_PCI0_PREFMBR        (0xc40 >> 2)
+#define GT_PCI0_SCS10_BAR      (0xc48 >> 2)
+#define GT_PCI0_SCS32_BAR      (0xc4c >> 2)
+#define GT_PCI0_CS20_BAR       (0xc50 >> 2)
+#define GT_PCI0_CS3BT_BAR      (0xc54 >> 2)
+#define GT_PCI0_SSCS10_BAR     (0xc58 >> 2)
+#define GT_PCI0_SSCS32_BAR     (0xc5c >> 2)
+#define GT_PCI0_SCS3BT_BAR     (0xc64 >> 2)
+#define GT_PCI1_CMD                    (0xc80 >> 2)
+#define GT_PCI1_TOR                    (0xc84 >> 2)
+#define GT_PCI1_BS_SCS10       (0xc88 >> 2)
+#define GT_PCI1_BS_SCS32       (0xc8c >> 2)
+#define GT_PCI1_BS_CS20        (0xc90 >> 2)
+#define GT_PCI1_BS_CS3BT       (0xc94 >> 2)
+#define GT_PCI1_BARE           (0xcbc >> 2)
+#define GT_PCI1_PREFMBR        (0xcc0 >> 2)
+#define GT_PCI1_SCS10_BAR      (0xcc8 >> 2)
+#define GT_PCI1_SCS32_BAR      (0xccc >> 2)
+#define GT_PCI1_CS20_BAR       (0xcd0 >> 2)
+#define GT_PCI1_CS3BT_BAR      (0xcd4 >> 2)
+#define GT_PCI1_SSCS10_BAR     (0xcd8 >> 2)
+#define GT_PCI1_SSCS32_BAR     (0xcdc >> 2)
+#define GT_PCI1_SCS3BT_BAR     (0xce4 >> 2)
+#define GT_PCI1_CFGADDR        (0xcf0 >> 2)
+#define GT_PCI1_CFGDATA        (0xcf4 >> 2)
+#define GT_PCI0_CFGADDR        (0xcf8 >> 2)
+#define GT_PCI0_CFGDATA        (0xcfc >> 2)
+
+/* Interrupts */
+#define GT_INTRCAUSE           (0xc18 >> 2)
+#define GT_INTRMASK                    (0xc1c >> 2)
+#define GT_PCI0_ICMASK         (0xc24 >> 2)
+#define GT_PCI0_SERR0MASK      (0xc28 >> 2)
+#define GT_CPU_INTSEL          (0xc70 >> 2)
+#define GT_PCI0_INTSEL         (0xc74 >> 2)
+#define GT_HINTRCAUSE          (0xc98 >> 2)
+#define GT_HINTRMASK           (0xc9c >> 2)
+#define GT_PCI0_HICMASK        (0xca4 >> 2)
+#define GT_PCI1_SERR1MASK      (0xca8 >> 2)
+
+#define PCI_MAPPING_ENTRY(regname)            \
+    hwaddr regname ##_start;      \
+    hwaddr regname ##_length;     \
+    MemoryRegion regname ##_mem
+
+#define TYPE_GT64120_PCI_HOST_BRIDGE "gt64120"
+
+#define GT64120_PCI_HOST_BRIDGE(obj) \
+    OBJECT_CHECK(GT64120State, (obj), TYPE_GT64120_PCI_HOST_BRIDGE)
+
+typedef struct GT64120State {
+    PCIHostState parent_obj;
+
+    uint32_t regs[GT_REGS];
+    PCI_MAPPING_ENTRY(PCI0IO);
+    PCI_MAPPING_ENTRY(ISD);
+} GT64120State;
+
+/* Adjust range to avoid touching space which isn't mappable via PCI */
+/* XXX: Hardcoded values for Malta: 0x1e000000 - 0x1f100000
+                                    0x1fc00000 - 0x1fd00000  */
+static void check_reserved_space (hwaddr *start,
+                                  hwaddr *length)
+{
+    hwaddr begin = *start;
+    hwaddr end = *start + *length;
+
+    if (end >= 0x1e000000LL && end < 0x1f100000LL)
+        end = 0x1e000000LL;
+    if (begin >= 0x1e000000LL && begin < 0x1f100000LL)
+        begin = 0x1f100000LL;
+    if (end >= 0x1fc00000LL && end < 0x1fd00000LL)
+        end = 0x1fc00000LL;
+    if (begin >= 0x1fc00000LL && begin < 0x1fd00000LL)
+        begin = 0x1fd00000LL;
+    /* XXX: This is broken when a reserved range splits the requested range */
+    if (end >= 0x1f100000LL && begin < 0x1e000000LL)
+        end = 0x1e000000LL;
+    if (end >= 0x1fd00000LL && begin < 0x1fc00000LL)
+        end = 0x1fc00000LL;
+
+    *start = begin;
+    *length = end - begin;
+}
+
+static void gt64120_isd_mapping(GT64120State *s)
+{
+    hwaddr start = s->regs[GT_ISD] << 21;
+    hwaddr length = 0x1000;
+
+    if (s->ISD_length) {
+        memory_region_del_subregion(get_system_memory(), &s->ISD_mem);
+    }
+    check_reserved_space(&start, &length);
+    length = 0x1000;
+    /* Map new address */
+    DPRINTF("ISD: "TARGET_FMT_plx"@"TARGET_FMT_plx
+        " -> "TARGET_FMT_plx"@"TARGET_FMT_plx"\n",
+        s->ISD_length, s->ISD_start, length, start);
+    s->ISD_start = start;
+    s->ISD_length = length;
+    memory_region_add_subregion(get_system_memory(), s->ISD_start, &s->ISD_mem);
+}
+
+static void gt64120_pci_mapping(GT64120State *s)
+{
+    /* Update IO mapping */
+    if ((s->regs[GT_PCI0IOLD] & 0x7f) <= s->regs[GT_PCI0IOHD])
+    {
+      /* Unmap old IO address */
+      if (s->PCI0IO_length)
+      {
+          memory_region_del_subregion(get_system_memory(), &s->PCI0IO_mem);
+          memory_region_destroy(&s->PCI0IO_mem);
+      }
+      /* Map new IO address */
+      s->PCI0IO_start = s->regs[GT_PCI0IOLD] << 21;
+      s->PCI0IO_length = ((s->regs[GT_PCI0IOHD] + 1) - (s->regs[GT_PCI0IOLD] & 0x7f)) << 21;
+      isa_mem_base = s->PCI0IO_start;
+      if (s->PCI0IO_length) {
+          isa_mmio_setup(&s->PCI0IO_mem, s->PCI0IO_length);
+          memory_region_add_subregion(get_system_memory(), s->PCI0IO_start,
+                                      &s->PCI0IO_mem);
+      }
+    }
+}
+
+static void gt64120_writel (void *opaque, hwaddr addr,
+                            uint64_t val, unsigned size)
+{
+    GT64120State *s = opaque;
+    PCIHostState *phb = PCI_HOST_BRIDGE(s);
+    uint32_t saddr;
+
+    if (!(s->regs[GT_CPU] & 0x00001000))
+        val = bswap32(val);
+
+    saddr = (addr & 0xfff) >> 2;
+    switch (saddr) {
+
+    /* CPU Configuration */
+    case GT_CPU:
+        s->regs[GT_CPU] = val;
+        break;
+    case GT_MULTI:
+       /* Read-only register as only one GT64xxx is present on the CPU bus */
+        break;
+
+    /* CPU Address Decode */
+    case GT_PCI0IOLD:
+        s->regs[GT_PCI0IOLD]    = val & 0x00007fff;
+        s->regs[GT_PCI0IOREMAP] = val & 0x000007ff;
+        gt64120_pci_mapping(s);
+        break;
+    case GT_PCI0M0LD:
+        s->regs[GT_PCI0M0LD]    = val & 0x00007fff;
+        s->regs[GT_PCI0M0REMAP] = val & 0x000007ff;
+        break;
+    case GT_PCI0M1LD:
+        s->regs[GT_PCI0M1LD]    = val & 0x00007fff;
+        s->regs[GT_PCI0M1REMAP] = val & 0x000007ff;
+        break;
+    case GT_PCI1IOLD:
+        s->regs[GT_PCI1IOLD]    = val & 0x00007fff;
+        s->regs[GT_PCI1IOREMAP] = val & 0x000007ff;
+        break;
+    case GT_PCI1M0LD:
+        s->regs[GT_PCI1M0LD]    = val & 0x00007fff;
+        s->regs[GT_PCI1M0REMAP] = val & 0x000007ff;
+        break;
+    case GT_PCI1M1LD:
+        s->regs[GT_PCI1M1LD]    = val & 0x00007fff;
+        s->regs[GT_PCI1M1REMAP] = val & 0x000007ff;
+        break;
+    case GT_PCI0IOHD:
+        s->regs[saddr] = val & 0x0000007f;
+        gt64120_pci_mapping(s);
+        break;
+    case GT_PCI0M0HD:
+    case GT_PCI0M1HD:
+    case GT_PCI1IOHD:
+    case GT_PCI1M0HD:
+    case GT_PCI1M1HD:
+        s->regs[saddr] = val & 0x0000007f;
+        break;
+    case GT_ISD:
+        s->regs[saddr] = val & 0x00007fff;
+        gt64120_isd_mapping(s);
+        break;
+
+    case GT_PCI0IOREMAP:
+    case GT_PCI0M0REMAP:
+    case GT_PCI0M1REMAP:
+    case GT_PCI1IOREMAP:
+    case GT_PCI1M0REMAP:
+    case GT_PCI1M1REMAP:
+        s->regs[saddr] = val & 0x000007ff;
+        break;
+
+    /* CPU Error Report */
+    case GT_CPUERR_ADDRLO:
+    case GT_CPUERR_ADDRHI:
+    case GT_CPUERR_DATALO:
+    case GT_CPUERR_DATAHI:
+    case GT_CPUERR_PARITY:
+       /* Read-only registers, do nothing */
+        break;
+
+    /* CPU Sync Barrier */
+    case GT_PCI0SYNC:
+    case GT_PCI1SYNC:
+       /* Read-only registers, do nothing */
+        break;
+
+    /* SDRAM and Device Address Decode */
+    case GT_SCS0LD:
+    case GT_SCS0HD:
+    case GT_SCS1LD:
+    case GT_SCS1HD:
+    case GT_SCS2LD:
+    case GT_SCS2HD:
+    case GT_SCS3LD:
+    case GT_SCS3HD:
+    case GT_CS0LD:
+    case GT_CS0HD:
+    case GT_CS1LD:
+    case GT_CS1HD:
+    case GT_CS2LD:
+    case GT_CS2HD:
+    case GT_CS3LD:
+    case GT_CS3HD:
+    case GT_BOOTLD:
+    case GT_BOOTHD:
+    case GT_ADERR:
+    /* SDRAM Configuration */
+    case GT_SDRAM_CFG:
+    case GT_SDRAM_OPMODE:
+    case GT_SDRAM_BM:
+    case GT_SDRAM_ADDRDECODE:
+        /* Accept and ignore SDRAM interleave configuration */
+        s->regs[saddr] = val;
+        break;
+
+    /* Device Parameters */
+    case GT_DEV_B0:
+    case GT_DEV_B1:
+    case GT_DEV_B2:
+    case GT_DEV_B3:
+    case GT_DEV_BOOT:
+        /* Not implemented */
+        DPRINTF ("Unimplemented device register offset 0x%x\n", saddr << 2);
+        break;
+
+    /* ECC */
+    case GT_ECC_ERRDATALO:
+    case GT_ECC_ERRDATAHI:
+    case GT_ECC_MEM:
+    case GT_ECC_CALC:
+    case GT_ECC_ERRADDR:
+        /* Read-only registers, do nothing */
+        break;
+
+    /* DMA Record */
+    case GT_DMA0_CNT:
+    case GT_DMA1_CNT:
+    case GT_DMA2_CNT:
+    case GT_DMA3_CNT:
+    case GT_DMA0_SA:
+    case GT_DMA1_SA:
+    case GT_DMA2_SA:
+    case GT_DMA3_SA:
+    case GT_DMA0_DA:
+    case GT_DMA1_DA:
+    case GT_DMA2_DA:
+    case GT_DMA3_DA:
+    case GT_DMA0_NEXT:
+    case GT_DMA1_NEXT:
+    case GT_DMA2_NEXT:
+    case GT_DMA3_NEXT:
+    case GT_DMA0_CUR:
+    case GT_DMA1_CUR:
+    case GT_DMA2_CUR:
+    case GT_DMA3_CUR:
+        /* Not implemented */
+        DPRINTF ("Unimplemented DMA register offset 0x%x\n", saddr << 2);
+        break;
+
+    /* DMA Channel Control */
+    case GT_DMA0_CTRL:
+    case GT_DMA1_CTRL:
+    case GT_DMA2_CTRL:
+    case GT_DMA3_CTRL:
+        /* Not implemented */
+        DPRINTF ("Unimplemented DMA register offset 0x%x\n", saddr << 2);
+        break;
+
+    /* DMA Arbiter */
+    case GT_DMA_ARB:
+        /* Not implemented */
+        DPRINTF ("Unimplemented DMA register offset 0x%x\n", saddr << 2);
+        break;
+
+    /* Timer/Counter */
+    case GT_TC0:
+    case GT_TC1:
+    case GT_TC2:
+    case GT_TC3:
+    case GT_TC_CONTROL:
+        /* Not implemented */
+        DPRINTF ("Unimplemented timer register offset 0x%x\n", saddr << 2);
+        break;
+
+    /* PCI Internal */
+    case GT_PCI0_CMD:
+    case GT_PCI1_CMD:
+        s->regs[saddr] = val & 0x0401fc0f;
+        break;
+    case GT_PCI0_TOR:
+    case GT_PCI0_BS_SCS10:
+    case GT_PCI0_BS_SCS32:
+    case GT_PCI0_BS_CS20:
+    case GT_PCI0_BS_CS3BT:
+    case GT_PCI1_IACK:
+    case GT_PCI0_IACK:
+    case GT_PCI0_BARE:
+    case GT_PCI0_PREFMBR:
+    case GT_PCI0_SCS10_BAR:
+    case GT_PCI0_SCS32_BAR:
+    case GT_PCI0_CS20_BAR:
+    case GT_PCI0_CS3BT_BAR:
+    case GT_PCI0_SSCS10_BAR:
+    case GT_PCI0_SSCS32_BAR:
+    case GT_PCI0_SCS3BT_BAR:
+    case GT_PCI1_TOR:
+    case GT_PCI1_BS_SCS10:
+    case GT_PCI1_BS_SCS32:
+    case GT_PCI1_BS_CS20:
+    case GT_PCI1_BS_CS3BT:
+    case GT_PCI1_BARE:
+    case GT_PCI1_PREFMBR:
+    case GT_PCI1_SCS10_BAR:
+    case GT_PCI1_SCS32_BAR:
+    case GT_PCI1_CS20_BAR:
+    case GT_PCI1_CS3BT_BAR:
+    case GT_PCI1_SSCS10_BAR:
+    case GT_PCI1_SSCS32_BAR:
+    case GT_PCI1_SCS3BT_BAR:
+    case GT_PCI1_CFGADDR:
+    case GT_PCI1_CFGDATA:
+        /* not implemented */
+        break;
+    case GT_PCI0_CFGADDR:
+        phb->config_reg = val & 0x80fffffc;
+        break;
+    case GT_PCI0_CFGDATA:
+        if (!(s->regs[GT_PCI0_CMD] & 1) && (phb->config_reg & 0x00fff800)) {
+            val = bswap32(val);
+        }
+        if (phb->config_reg & (1u << 31)) {
+            pci_data_write(phb->bus, phb->config_reg, val, 4);
+        }
+        break;
+
+    /* Interrupts */
+    case GT_INTRCAUSE:
+        /* not really implemented */
+        s->regs[saddr] = ~(~(s->regs[saddr]) | ~(val & 0xfffffffe));
+        s->regs[saddr] |= !!(s->regs[saddr] & 0xfffffffe);
+        DPRINTF("INTRCAUSE %" PRIx64 "\n", val);
+        break;
+    case GT_INTRMASK:
+        s->regs[saddr] = val & 0x3c3ffffe;
+        DPRINTF("INTRMASK %" PRIx64 "\n", val);
+        break;
+    case GT_PCI0_ICMASK:
+        s->regs[saddr] = val & 0x03fffffe;
+        DPRINTF("ICMASK %" PRIx64 "\n", val);
+        break;
+    case GT_PCI0_SERR0MASK:
+        s->regs[saddr] = val & 0x0000003f;
+        DPRINTF("SERR0MASK %" PRIx64 "\n", val);
+        break;
+
+    /* Reserved when only PCI_0 is configured. */
+    case GT_HINTRCAUSE:
+    case GT_CPU_INTSEL:
+    case GT_PCI0_INTSEL:
+    case GT_HINTRMASK:
+    case GT_PCI0_HICMASK:
+    case GT_PCI1_SERR1MASK:
+        /* not implemented */
+        break;
+
+    /* SDRAM Parameters */
+    case GT_SDRAM_B0:
+    case GT_SDRAM_B1:
+    case GT_SDRAM_B2:
+    case GT_SDRAM_B3:
+        /* We don't simulate electrical parameters of the SDRAM.
+           Accept, but ignore the values. */
+        s->regs[saddr] = val;
+        break;
+
+    default:
+        DPRINTF ("Bad register offset 0x%x\n", (int)addr);
+        break;
+    }
+}
+
+static uint64_t gt64120_readl (void *opaque,
+                               hwaddr addr, unsigned size)
+{
+    GT64120State *s = opaque;
+    PCIHostState *phb = PCI_HOST_BRIDGE(s);
+    uint32_t val;
+    uint32_t saddr;
+
+    saddr = (addr & 0xfff) >> 2;
+    switch (saddr) {
+
+    /* CPU Configuration */
+    case GT_MULTI:
+        /* Only one GT64xxx is present on the CPU bus, return
+           the initial value */
+        val = s->regs[saddr];
+        break;
+
+    /* CPU Error Report */
+    case GT_CPUERR_ADDRLO:
+    case GT_CPUERR_ADDRHI:
+    case GT_CPUERR_DATALO:
+    case GT_CPUERR_DATAHI:
+    case GT_CPUERR_PARITY:
+        /* Emulated memory has no error, always return the initial
+           values */
+        val = s->regs[saddr];
+        break;
+
+    /* CPU Sync Barrier */
+    case GT_PCI0SYNC:
+    case GT_PCI1SYNC:
+        /* Reading those register should empty all FIFO on the PCI
+           bus, which are not emulated. The return value should be
+           a random value that should be ignored. */
+        val = 0xc000ffee;
+        break;
+
+    /* ECC */
+    case GT_ECC_ERRDATALO:
+    case GT_ECC_ERRDATAHI:
+    case GT_ECC_MEM:
+    case GT_ECC_CALC:
+    case GT_ECC_ERRADDR:
+        /* Emulated memory has no error, always return the initial
+           values */
+        val = s->regs[saddr];
+        break;
+
+    case GT_CPU:
+    case GT_SCS10LD:
+    case GT_SCS10HD:
+    case GT_SCS32LD:
+    case GT_SCS32HD:
+    case GT_CS20LD:
+    case GT_CS20HD:
+    case GT_CS3BOOTLD:
+    case GT_CS3BOOTHD:
+    case GT_SCS10AR:
+    case GT_SCS32AR:
+    case GT_CS20R:
+    case GT_CS3BOOTR:
+    case GT_PCI0IOLD:
+    case GT_PCI0M0LD:
+    case GT_PCI0M1LD:
+    case GT_PCI1IOLD:
+    case GT_PCI1M0LD:
+    case GT_PCI1M1LD:
+    case GT_PCI0IOHD:
+    case GT_PCI0M0HD:
+    case GT_PCI0M1HD:
+    case GT_PCI1IOHD:
+    case GT_PCI1M0HD:
+    case GT_PCI1M1HD:
+    case GT_PCI0IOREMAP:
+    case GT_PCI0M0REMAP:
+    case GT_PCI0M1REMAP:
+    case GT_PCI1IOREMAP:
+    case GT_PCI1M0REMAP:
+    case GT_PCI1M1REMAP:
+    case GT_ISD:
+        val = s->regs[saddr];
+        break;
+    case GT_PCI0_IACK:
+        /* Read the IRQ number */
+        val = pic_read_irq(isa_pic);
+        break;
+
+    /* SDRAM and Device Address Decode */
+    case GT_SCS0LD:
+    case GT_SCS0HD:
+    case GT_SCS1LD:
+    case GT_SCS1HD:
+    case GT_SCS2LD:
+    case GT_SCS2HD:
+    case GT_SCS3LD:
+    case GT_SCS3HD:
+    case GT_CS0LD:
+    case GT_CS0HD:
+    case GT_CS1LD:
+    case GT_CS1HD:
+    case GT_CS2LD:
+    case GT_CS2HD:
+    case GT_CS3LD:
+    case GT_CS3HD:
+    case GT_BOOTLD:
+    case GT_BOOTHD:
+    case GT_ADERR:
+        val = s->regs[saddr];
+        break;
+
+    /* SDRAM Configuration */
+    case GT_SDRAM_CFG:
+    case GT_SDRAM_OPMODE:
+    case GT_SDRAM_BM:
+    case GT_SDRAM_ADDRDECODE:
+        val = s->regs[saddr];
+        break;
+
+    /* SDRAM Parameters */
+    case GT_SDRAM_B0:
+    case GT_SDRAM_B1:
+    case GT_SDRAM_B2:
+    case GT_SDRAM_B3:
+        /* We don't simulate electrical parameters of the SDRAM.
+           Just return the last written value. */
+        val = s->regs[saddr];
+        break;
+
+    /* Device Parameters */
+    case GT_DEV_B0:
+    case GT_DEV_B1:
+    case GT_DEV_B2:
+    case GT_DEV_B3:
+    case GT_DEV_BOOT:
+        val = s->regs[saddr];
+        break;
+
+    /* DMA Record */
+    case GT_DMA0_CNT:
+    case GT_DMA1_CNT:
+    case GT_DMA2_CNT:
+    case GT_DMA3_CNT:
+    case GT_DMA0_SA:
+    case GT_DMA1_SA:
+    case GT_DMA2_SA:
+    case GT_DMA3_SA:
+    case GT_DMA0_DA:
+    case GT_DMA1_DA:
+    case GT_DMA2_DA:
+    case GT_DMA3_DA:
+    case GT_DMA0_NEXT:
+    case GT_DMA1_NEXT:
+    case GT_DMA2_NEXT:
+    case GT_DMA3_NEXT:
+    case GT_DMA0_CUR:
+    case GT_DMA1_CUR:
+    case GT_DMA2_CUR:
+    case GT_DMA3_CUR:
+        val = s->regs[saddr];
+        break;
+
+    /* DMA Channel Control */
+    case GT_DMA0_CTRL:
+    case GT_DMA1_CTRL:
+    case GT_DMA2_CTRL:
+    case GT_DMA3_CTRL:
+        val = s->regs[saddr];
+        break;
+
+    /* DMA Arbiter */
+    case GT_DMA_ARB:
+        val = s->regs[saddr];
+        break;
+
+    /* Timer/Counter */
+    case GT_TC0:
+    case GT_TC1:
+    case GT_TC2:
+    case GT_TC3:
+    case GT_TC_CONTROL:
+        val = s->regs[saddr];
+        break;
+
+    /* PCI Internal */
+    case GT_PCI0_CFGADDR:
+        val = phb->config_reg;
+        break;
+    case GT_PCI0_CFGDATA:
+        if (!(phb->config_reg & (1 << 31))) {
+            val = 0xffffffff;
+        } else {
+            val = pci_data_read(phb->bus, phb->config_reg, 4);
+        }
+        if (!(s->regs[GT_PCI0_CMD] & 1) && (phb->config_reg & 0x00fff800)) {
+            val = bswap32(val);
+        }
+        break;
+
+    case GT_PCI0_CMD:
+    case GT_PCI0_TOR:
+    case GT_PCI0_BS_SCS10:
+    case GT_PCI0_BS_SCS32:
+    case GT_PCI0_BS_CS20:
+    case GT_PCI0_BS_CS3BT:
+    case GT_PCI1_IACK:
+    case GT_PCI0_BARE:
+    case GT_PCI0_PREFMBR:
+    case GT_PCI0_SCS10_BAR:
+    case GT_PCI0_SCS32_BAR:
+    case GT_PCI0_CS20_BAR:
+    case GT_PCI0_CS3BT_BAR:
+    case GT_PCI0_SSCS10_BAR:
+    case GT_PCI0_SSCS32_BAR:
+    case GT_PCI0_SCS3BT_BAR:
+    case GT_PCI1_CMD:
+    case GT_PCI1_TOR:
+    case GT_PCI1_BS_SCS10:
+    case GT_PCI1_BS_SCS32:
+    case GT_PCI1_BS_CS20:
+    case GT_PCI1_BS_CS3BT:
+    case GT_PCI1_BARE:
+    case GT_PCI1_PREFMBR:
+    case GT_PCI1_SCS10_BAR:
+    case GT_PCI1_SCS32_BAR:
+    case GT_PCI1_CS20_BAR:
+    case GT_PCI1_CS3BT_BAR:
+    case GT_PCI1_SSCS10_BAR:
+    case GT_PCI1_SSCS32_BAR:
+    case GT_PCI1_SCS3BT_BAR:
+    case GT_PCI1_CFGADDR:
+    case GT_PCI1_CFGDATA:
+        val = s->regs[saddr];
+        break;
+
+    /* Interrupts */
+    case GT_INTRCAUSE:
+        val = s->regs[saddr];
+        DPRINTF("INTRCAUSE %x\n", val);
+        break;
+    case GT_INTRMASK:
+        val = s->regs[saddr];
+        DPRINTF("INTRMASK %x\n", val);
+        break;
+    case GT_PCI0_ICMASK:
+        val = s->regs[saddr];
+        DPRINTF("ICMASK %x\n", val);
+        break;
+    case GT_PCI0_SERR0MASK:
+        val = s->regs[saddr];
+        DPRINTF("SERR0MASK %x\n", val);
+        break;
+
+    /* Reserved when only PCI_0 is configured. */
+    case GT_HINTRCAUSE:
+    case GT_CPU_INTSEL:
+    case GT_PCI0_INTSEL:
+    case GT_HINTRMASK:
+    case GT_PCI0_HICMASK:
+    case GT_PCI1_SERR1MASK:
+        val = s->regs[saddr];
+        break;
+
+    default:
+        val = s->regs[saddr];
+        DPRINTF ("Bad register offset 0x%x\n", (int)addr);
+        break;
+    }
+
+    if (!(s->regs[GT_CPU] & 0x00001000))
+        val = bswap32(val);
+
+    return val;
+}
+
+static const MemoryRegionOps isd_mem_ops = {
+    .read = gt64120_readl,
+    .write = gt64120_writel,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int gt64120_pci_map_irq(PCIDevice *pci_dev, int irq_num)
+{
+    int slot;
+
+    slot = (pci_dev->devfn >> 3);
+
+    switch (slot) {
+      /* PIIX4 USB */
+      case 10:
+        return 3;
+      /* AMD 79C973 Ethernet */
+      case 11:
+        return 1;
+      /* Crystal 4281 Sound */
+      case 12:
+        return 2;
+      /* PCI slot 1 to 4 */
+      case 18 ... 21:
+        return ((slot - 18) + irq_num) & 0x03;
+      /* Unknown device, don't do any translation */
+      default:
+        return irq_num;
+    }
+}
+
+static int pci_irq_levels[4];
+
+static void gt64120_pci_set_irq(void *opaque, int irq_num, int level)
+{
+    int i, pic_irq, pic_level;
+    qemu_irq *pic = opaque;
+
+    pci_irq_levels[irq_num] = level;
+
+    /* now we change the pic irq level according to the piix irq mappings */
+    /* XXX: optimize */
+    pic_irq = piix4_dev->config[0x60 + irq_num];
+    if (pic_irq < 16) {
+        /* The pic level is the logical OR of all the PCI irqs mapped
+           to it */
+        pic_level = 0;
+        for (i = 0; i < 4; i++) {
+            if (pic_irq == piix4_dev->config[0x60 + i])
+                pic_level |= pci_irq_levels[i];
+        }
+        qemu_set_irq(pic[pic_irq], pic_level);
+    }
+}
+
+
+static void gt64120_reset(void *opaque)
+{
+    GT64120State *s = opaque;
+
+    /* FIXME: Malta specific hw assumptions ahead */
+
+    /* CPU Configuration */
+#ifdef TARGET_WORDS_BIGENDIAN
+    s->regs[GT_CPU]           = 0x00000000;
+#else
+    s->regs[GT_CPU]           = 0x00001000;
+#endif
+    s->regs[GT_MULTI]         = 0x00000003;
+
+    /* CPU Address decode */
+    s->regs[GT_SCS10LD]       = 0x00000000;
+    s->regs[GT_SCS10HD]       = 0x00000007;
+    s->regs[GT_SCS32LD]       = 0x00000008;
+    s->regs[GT_SCS32HD]       = 0x0000000f;
+    s->regs[GT_CS20LD]        = 0x000000e0;
+    s->regs[GT_CS20HD]        = 0x00000070;
+    s->regs[GT_CS3BOOTLD]     = 0x000000f8;
+    s->regs[GT_CS3BOOTHD]     = 0x0000007f;
+
+    s->regs[GT_PCI0IOLD]      = 0x00000080;
+    s->regs[GT_PCI0IOHD]      = 0x0000000f;
+    s->regs[GT_PCI0M0LD]      = 0x00000090;
+    s->regs[GT_PCI0M0HD]      = 0x0000001f;
+    s->regs[GT_ISD]           = 0x000000a0;
+    s->regs[GT_PCI0M1LD]      = 0x00000790;
+    s->regs[GT_PCI0M1HD]      = 0x0000001f;
+    s->regs[GT_PCI1IOLD]      = 0x00000100;
+    s->regs[GT_PCI1IOHD]      = 0x0000000f;
+    s->regs[GT_PCI1M0LD]      = 0x00000110;
+    s->regs[GT_PCI1M0HD]      = 0x0000001f;
+    s->regs[GT_PCI1M1LD]      = 0x00000120;
+    s->regs[GT_PCI1M1HD]      = 0x0000002f;
+
+    s->regs[GT_SCS10AR]       = 0x00000000;
+    s->regs[GT_SCS32AR]       = 0x00000008;
+    s->regs[GT_CS20R]         = 0x000000e0;
+    s->regs[GT_CS3BOOTR]      = 0x000000f8;
+
+    s->regs[GT_PCI0IOREMAP]   = 0x00000080;
+    s->regs[GT_PCI0M0REMAP]   = 0x00000090;
+    s->regs[GT_PCI0M1REMAP]   = 0x00000790;
+    s->regs[GT_PCI1IOREMAP]   = 0x00000100;
+    s->regs[GT_PCI1M0REMAP]   = 0x00000110;
+    s->regs[GT_PCI1M1REMAP]   = 0x00000120;
+
+    /* CPU Error Report */
+    s->regs[GT_CPUERR_ADDRLO] = 0x00000000;
+    s->regs[GT_CPUERR_ADDRHI] = 0x00000000;
+    s->regs[GT_CPUERR_DATALO] = 0xffffffff;
+    s->regs[GT_CPUERR_DATAHI] = 0xffffffff;
+    s->regs[GT_CPUERR_PARITY] = 0x000000ff;
+
+    /* CPU Sync Barrier */
+    s->regs[GT_PCI0SYNC]      = 0x00000000;
+    s->regs[GT_PCI1SYNC]      = 0x00000000;
+
+    /* SDRAM and Device Address Decode */
+    s->regs[GT_SCS0LD]        = 0x00000000;
+    s->regs[GT_SCS0HD]        = 0x00000007;
+    s->regs[GT_SCS1LD]        = 0x00000008;
+    s->regs[GT_SCS1HD]        = 0x0000000f;
+    s->regs[GT_SCS2LD]        = 0x00000010;
+    s->regs[GT_SCS2HD]        = 0x00000017;
+    s->regs[GT_SCS3LD]        = 0x00000018;
+    s->regs[GT_SCS3HD]        = 0x0000001f;
+    s->regs[GT_CS0LD]         = 0x000000c0;
+    s->regs[GT_CS0HD]         = 0x000000c7;
+    s->regs[GT_CS1LD]         = 0x000000c8;
+    s->regs[GT_CS1HD]         = 0x000000cf;
+    s->regs[GT_CS2LD]         = 0x000000d0;
+    s->regs[GT_CS2HD]         = 0x000000df;
+    s->regs[GT_CS3LD]         = 0x000000f0;
+    s->regs[GT_CS3HD]         = 0x000000fb;
+    s->regs[GT_BOOTLD]        = 0x000000fc;
+    s->regs[GT_BOOTHD]        = 0x000000ff;
+    s->regs[GT_ADERR]         = 0xffffffff;
+
+    /* SDRAM Configuration */
+    s->regs[GT_SDRAM_CFG]     = 0x00000200;
+    s->regs[GT_SDRAM_OPMODE]  = 0x00000000;
+    s->regs[GT_SDRAM_BM]      = 0x00000007;
+    s->regs[GT_SDRAM_ADDRDECODE] = 0x00000002;
+
+    /* SDRAM Parameters */
+    s->regs[GT_SDRAM_B0]      = 0x00000005;
+    s->regs[GT_SDRAM_B1]      = 0x00000005;
+    s->regs[GT_SDRAM_B2]      = 0x00000005;
+    s->regs[GT_SDRAM_B3]      = 0x00000005;
+
+    /* ECC */
+    s->regs[GT_ECC_ERRDATALO] = 0x00000000;
+    s->regs[GT_ECC_ERRDATAHI] = 0x00000000;
+    s->regs[GT_ECC_MEM]       = 0x00000000;
+    s->regs[GT_ECC_CALC]      = 0x00000000;
+    s->regs[GT_ECC_ERRADDR]   = 0x00000000;
+
+    /* Device Parameters */
+    s->regs[GT_DEV_B0]        = 0x386fffff;
+    s->regs[GT_DEV_B1]        = 0x386fffff;
+    s->regs[GT_DEV_B2]        = 0x386fffff;
+    s->regs[GT_DEV_B3]        = 0x386fffff;
+    s->regs[GT_DEV_BOOT]      = 0x146fffff;
+
+    /* DMA registers are all zeroed at reset */
+
+    /* Timer/Counter */
+    s->regs[GT_TC0]           = 0xffffffff;
+    s->regs[GT_TC1]           = 0x00ffffff;
+    s->regs[GT_TC2]           = 0x00ffffff;
+    s->regs[GT_TC3]           = 0x00ffffff;
+    s->regs[GT_TC_CONTROL]    = 0x00000000;
+
+    /* PCI Internal */
+#ifdef TARGET_WORDS_BIGENDIAN
+    s->regs[GT_PCI0_CMD]      = 0x00000000;
+#else
+    s->regs[GT_PCI0_CMD]      = 0x00010001;
+#endif
+    s->regs[GT_PCI0_TOR]      = 0x0000070f;
+    s->regs[GT_PCI0_BS_SCS10] = 0x00fff000;
+    s->regs[GT_PCI0_BS_SCS32] = 0x00fff000;
+    s->regs[GT_PCI0_BS_CS20]  = 0x01fff000;
+    s->regs[GT_PCI0_BS_CS3BT] = 0x00fff000;
+    s->regs[GT_PCI1_IACK]     = 0x00000000;
+    s->regs[GT_PCI0_IACK]     = 0x00000000;
+    s->regs[GT_PCI0_BARE]     = 0x0000000f;
+    s->regs[GT_PCI0_PREFMBR]  = 0x00000040;
+    s->regs[GT_PCI0_SCS10_BAR] = 0x00000000;
+    s->regs[GT_PCI0_SCS32_BAR] = 0x01000000;
+    s->regs[GT_PCI0_CS20_BAR] = 0x1c000000;
+    s->regs[GT_PCI0_CS3BT_BAR] = 0x1f000000;
+    s->regs[GT_PCI0_SSCS10_BAR] = 0x00000000;
+    s->regs[GT_PCI0_SSCS32_BAR] = 0x01000000;
+    s->regs[GT_PCI0_SCS3BT_BAR] = 0x1f000000;
+#ifdef TARGET_WORDS_BIGENDIAN
+    s->regs[GT_PCI1_CMD]      = 0x00000000;
+#else
+    s->regs[GT_PCI1_CMD]      = 0x00010001;
+#endif
+    s->regs[GT_PCI1_TOR]      = 0x0000070f;
+    s->regs[GT_PCI1_BS_SCS10] = 0x00fff000;
+    s->regs[GT_PCI1_BS_SCS32] = 0x00fff000;
+    s->regs[GT_PCI1_BS_CS20]  = 0x01fff000;
+    s->regs[GT_PCI1_BS_CS3BT] = 0x00fff000;
+    s->regs[GT_PCI1_BARE]     = 0x0000000f;
+    s->regs[GT_PCI1_PREFMBR]  = 0x00000040;
+    s->regs[GT_PCI1_SCS10_BAR] = 0x00000000;
+    s->regs[GT_PCI1_SCS32_BAR] = 0x01000000;
+    s->regs[GT_PCI1_CS20_BAR] = 0x1c000000;
+    s->regs[GT_PCI1_CS3BT_BAR] = 0x1f000000;
+    s->regs[GT_PCI1_SSCS10_BAR] = 0x00000000;
+    s->regs[GT_PCI1_SSCS32_BAR] = 0x01000000;
+    s->regs[GT_PCI1_SCS3BT_BAR] = 0x1f000000;
+    s->regs[GT_PCI1_CFGADDR]  = 0x00000000;
+    s->regs[GT_PCI1_CFGDATA]  = 0x00000000;
+    s->regs[GT_PCI0_CFGADDR]  = 0x00000000;
+
+    /* Interrupt registers are all zeroed at reset */
+
+    gt64120_isd_mapping(s);
+    gt64120_pci_mapping(s);
+}
+
+PCIBus *gt64120_register(qemu_irq *pic)
+{
+    GT64120State *d;
+    PCIHostState *phb;
+    DeviceState *dev;
+
+    dev = qdev_create(NULL, TYPE_GT64120_PCI_HOST_BRIDGE);
+    qdev_init_nofail(dev);
+    d = GT64120_PCI_HOST_BRIDGE(dev);
+    phb = PCI_HOST_BRIDGE(dev);
+    phb->bus = pci_register_bus(dev, "pci",
+                                gt64120_pci_set_irq, gt64120_pci_map_irq,
+                                pic,
+                                get_system_memory(),
+                                get_system_io(),
+                                PCI_DEVFN(18, 0), 4, TYPE_PCI_BUS);
+    memory_region_init_io(&d->ISD_mem, &isd_mem_ops, d, "isd-mem", 0x1000);
+
+    pci_create_simple(phb->bus, PCI_DEVFN(0, 0), "gt64120_pci");
+    return phb->bus;
+}
+
+static int gt64120_init(SysBusDevice *dev)
+{
+    GT64120State *s;
+
+    s = GT64120_PCI_HOST_BRIDGE(dev);
+
+    /* FIXME: This value is computed from registers during reset, but some
+       devices (e.g. VGA card) need to know it when they are registered.
+       This also mean that changing the register to change the mapping
+       does not fully work. */
+    isa_mem_base = 0x10000000;
+    qemu_register_reset(gt64120_reset, s);
+    return 0;
+}
+
+static int gt64120_pci_init(PCIDevice *d)
+{
+    /* FIXME: Malta specific hw assumptions ahead */
+    pci_set_word(d->config + PCI_COMMAND, 0);
+    pci_set_word(d->config + PCI_STATUS,
+                 PCI_STATUS_FAST_BACK | PCI_STATUS_DEVSEL_MEDIUM);
+    pci_config_set_prog_interface(d->config, 0);
+    pci_set_long(d->config + PCI_BASE_ADDRESS_0, 0x00000008);
+    pci_set_long(d->config + PCI_BASE_ADDRESS_1, 0x01000008);
+    pci_set_long(d->config + PCI_BASE_ADDRESS_2, 0x1c000000);
+    pci_set_long(d->config + PCI_BASE_ADDRESS_3, 0x1f000000);
+    pci_set_long(d->config + PCI_BASE_ADDRESS_4, 0x14000000);
+    pci_set_long(d->config + PCI_BASE_ADDRESS_5, 0x14000001);
+    pci_set_byte(d->config + 0x3d, 0x01);
+
+    return 0;
+}
+
+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 const TypeInfo gt64120_pci_info = {
+    .name          = "gt64120_pci",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PCIDevice),
+    .class_init    = gt64120_pci_class_init,
+};
+
+static void gt64120_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sdc->init = gt64120_init;
+}
+
+static const TypeInfo gt64120_info = {
+    .name          = TYPE_GT64120_PCI_HOST_BRIDGE,
+    .parent        = TYPE_PCI_HOST_BRIDGE,
+    .instance_size = sizeof(GT64120State),
+    .class_init    = gt64120_class_init,
+};
+
+static void gt64120_pci_register_types(void)
+{
+    type_register_static(&gt64120_info);
+    type_register_static(&gt64120_pci_info);
+}
+
+type_init(gt64120_pci_register_types)
index 766aa9dfb56b7c061bf3d02fb86a23a0a210a44c..3cf27fa822fb6301309fb6660c5fe6c6544548cb 100644 (file)
  */
 
 #include "hw/hw.h"
-#include "hw/pc.h"
-#include "hw/serial.h"
-#include "hw/fdc.h"
+#include "hw/i386/pc.h"
+#include "hw/char/serial.h"
+#include "hw/block/fdc.h"
 #include "net/net.h"
 #include "hw/boards.h"
-#include "hw/smbus.h"
+#include "hw/i2c/smbus.h"
 #include "block/block.h"
-#include "hw/flash.h"
-#include "hw/mips.h"
-#include "hw/mips_cpudevs.h"
+#include "hw/block/flash.h"
+#include "hw/mips/mips.h"
+#include "hw/mips/cpudevs.h"
 #include "hw/pci/pci.h"
 #include "char/char.h"
 #include "sysemu/sysemu.h"
 #include "audio/audio.h"
 #include "qemu/log.h"
 #include "hw/loader.h"
-#include "hw/mips-bios.h"
+#include "hw/mips/bios.h"
 #include "hw/ide.h"
 #include "elf.h"
-#include "hw/vt82c686.h"
-#include "hw/mc146818rtc.h"
-#include "hw/i8254.h"
+#include "hw/isa/vt82c686.h"
+#include "hw/timer/mc146818rtc.h"
+#include "hw/timer/i8254.h"
 #include "sysemu/blockdev.h"
 #include "exec/address-spaces.h"
 
index 0e5e86699cd55a89e10a78d86f2e4accfc561260..7dbd24d3d6e5d00ff63901d29a3bb1e3f450460c 100644 (file)
@@ -21,7 +21,7 @@
  */
 
 #include "hw/hw.h"
-#include "hw/mips_cpudevs.h"
+#include "hw/mips/cpudevs.h"
 #include "cpu.h"
 
 static void cpu_mips_irq_request(void *opaque, int irq, int level)
index daeb985b1d0368daa249f84c2ccadae4f2f537dc..fd3a5f93f9aa4abc372b16fbd79e19ce1a740be4 100644 (file)
  */
 
 #include "hw/hw.h"
-#include "hw/mips.h"
-#include "hw/mips_cpudevs.h"
-#include "hw/pc.h"
-#include "hw/serial.h"
-#include "hw/isa.h"
-#include "hw/fdc.h"
+#include "hw/mips/mips.h"
+#include "hw/mips/cpudevs.h"
+#include "hw/i386/pc.h"
+#include "hw/char/serial.h"
+#include "hw/isa/isa.h"
+#include "hw/block/fdc.h"
 #include "sysemu/sysemu.h"
 #include "sysemu/arch_init.h"
 #include "hw/boards.h"
 #include "net/net.h"
-#include "hw/esp.h"
-#include "hw/mips-bios.h"
+#include "hw/scsi/esp.h"
+#include "hw/mips/bios.h"
 #include "hw/loader.h"
-#include "hw/mc146818rtc.h"
-#include "hw/i8254.h"
-#include "hw/pcspk.h"
+#include "hw/timer/mc146818rtc.h"
+#include "hw/timer/i8254.h"
+#include "hw/audio/pcspk.h"
 #include "sysemu/blockdev.h"
 #include "hw/sysbus.h"
 #include "exec/address-spaces.h"
index 9a67dce2077227aca2d29fe557c0b981086b5c44..a3e936b77fa3d6517e49f8447c466fda0ad03ad3 100644 (file)
  */
 
 #include "hw/hw.h"
-#include "hw/pc.h"
-#include "hw/serial.h"
-#include "hw/fdc.h"
+#include "hw/i386/pc.h"
+#include "hw/char/serial.h"
+#include "hw/block/fdc.h"
 #include "net/net.h"
 #include "hw/boards.h"
-#include "hw/smbus.h"
+#include "hw/i2c/smbus.h"
 #include "block/block.h"
-#include "hw/flash.h"
-#include "hw/mips.h"
-#include "hw/mips_cpudevs.h"
+#include "hw/block/flash.h"
+#include "hw/mips/mips.h"
+#include "hw/mips/cpudevs.h"
 #include "hw/pci/pci.h"
 #include "char/char.h"
 #include "sysemu/sysemu.h"
 #include "sysemu/arch_init.h"
 #include "hw/boards.h"
 #include "qemu/log.h"
-#include "hw/mips-bios.h"
+#include "hw/mips/bios.h"
 #include "hw/ide.h"
 #include "hw/loader.h"
 #include "elf.h"
-#include "hw/mc146818rtc.h"
-#include "hw/i8254.h"
+#include "hw/timer/mc146818rtc.h"
+#include "hw/timer/i8254.h"
 #include "sysemu/blockdev.h"
 #include "exec/address-spaces.h"
 #include "hw/sysbus.h"             /* SysBusDevice */
index 4935c78c01643e7c56152b4e1ed5adcbd0d8a2d9..d1681ec2fe5b7c102e00df6c8a6cb8b1e2bc9bfd 100644 (file)
  * THE SOFTWARE.
  */
 #include "hw/hw.h"
-#include "hw/mips.h"
-#include "hw/mips_cpudevs.h"
-#include "hw/serial.h"
-#include "hw/isa.h"
+#include "hw/mips/mips.h"
+#include "hw/mips/cpudevs.h"
+#include "hw/char/serial.h"
+#include "hw/isa/isa.h"
 #include "net/net.h"
 #include "sysemu/sysemu.h"
 #include "hw/boards.h"
-#include "hw/mips-bios.h"
+#include "hw/mips/bios.h"
 #include "hw/loader.h"
 #include "elf.h"
 #include "hw/sysbus.h"
index 539a56262078f6d3a88c44c17bef1f95920ab9f4..4646ab6db7f499980fe01043fbc20eb89e17dc92 100644 (file)
@@ -8,22 +8,22 @@
  * the standard PC ISA addresses.
 */
 #include "hw/hw.h"
-#include "hw/mips.h"
-#include "hw/mips_cpudevs.h"
-#include "hw/pc.h"
-#include "hw/serial.h"
-#include "hw/isa.h"
+#include "hw/mips/mips.h"
+#include "hw/mips/cpudevs.h"
+#include "hw/i386/pc.h"
+#include "hw/char/serial.h"
+#include "hw/isa/isa.h"
 #include "net/net.h"
 #include "sysemu/sysemu.h"
 #include "hw/boards.h"
-#include "hw/flash.h"
+#include "hw/block/flash.h"
 #include "qemu/log.h"
-#include "hw/mips-bios.h"
+#include "hw/mips/bios.h"
 #include "hw/ide.h"
 #include "hw/loader.h"
 #include "elf.h"
-#include "hw/mc146818rtc.h"
-#include "hw/i8254.h"
+#include "hw/timer/mc146818rtc.h"
+#include "hw/timer/i8254.h"
 #include "sysemu/blockdev.h"
 #include "exec/address-spaces.h"
 
diff --git a/hw/mips_cpudevs.h b/hw/mips_cpudevs.h
deleted file mode 100644 (file)
index 6bea24b..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-#ifndef HW_MIPS_CPUDEVS_H
-#define HW_MIPS_CPUDEVS_H
-/* Definitions for MIPS CPU internal devices.  */
-
-/* mips_addr.c */
-uint64_t cpu_mips_kseg0_to_phys(void *opaque, uint64_t addr);
-uint64_t cpu_mips_phys_to_kseg0(void *opaque, uint64_t addr);
-
-/* mips_int.c */
-void cpu_mips_irq_init_cpu(CPUMIPSState *env);
-
-/* mips_timer.c */
-void cpu_mips_clock_init(CPUMIPSState *);
-
-#endif
diff --git a/hw/mipsnet.c b/hw/mipsnet.c
deleted file mode 100644 (file)
index ac6193a..0000000
+++ /dev/null
@@ -1,284 +0,0 @@
-#include "hw/hw.h"
-#include "net/net.h"
-#include "trace.h"
-#include "hw/sysbus.h"
-
-/* MIPSnet register offsets */
-
-#define MIPSNET_DEV_ID         0x00
-#define MIPSNET_BUSY           0x08
-#define MIPSNET_RX_DATA_COUNT  0x0c
-#define MIPSNET_TX_DATA_COUNT  0x10
-#define MIPSNET_INT_CTL                0x14
-# define MIPSNET_INTCTL_TXDONE         0x00000001
-# define MIPSNET_INTCTL_RXDONE         0x00000002
-# define MIPSNET_INTCTL_TESTBIT                0x80000000
-#define MIPSNET_INTERRUPT_INFO 0x18
-#define MIPSNET_RX_DATA_BUFFER 0x1c
-#define MIPSNET_TX_DATA_BUFFER 0x20
-
-#define MAX_ETH_FRAME_SIZE     1514
-
-typedef struct MIPSnetState {
-    SysBusDevice busdev;
-
-    uint32_t busy;
-    uint32_t rx_count;
-    uint32_t rx_read;
-    uint32_t tx_count;
-    uint32_t tx_written;
-    uint32_t intctl;
-    uint8_t rx_buffer[MAX_ETH_FRAME_SIZE];
-    uint8_t tx_buffer[MAX_ETH_FRAME_SIZE];
-    MemoryRegion io;
-    qemu_irq irq;
-    NICState *nic;
-    NICConf conf;
-} MIPSnetState;
-
-static void mipsnet_reset(MIPSnetState *s)
-{
-    s->busy = 1;
-    s->rx_count = 0;
-    s->rx_read = 0;
-    s->tx_count = 0;
-    s->tx_written = 0;
-    s->intctl = 0;
-    memset(s->rx_buffer, 0, MAX_ETH_FRAME_SIZE);
-    memset(s->tx_buffer, 0, MAX_ETH_FRAME_SIZE);
-}
-
-static void mipsnet_update_irq(MIPSnetState *s)
-{
-    int isr = !!s->intctl;
-    trace_mipsnet_irq(isr, s->intctl);
-    qemu_set_irq(s->irq, isr);
-}
-
-static int mipsnet_buffer_full(MIPSnetState *s)
-{
-    if (s->rx_count >= MAX_ETH_FRAME_SIZE)
-        return 1;
-    return 0;
-}
-
-static int mipsnet_can_receive(NetClientState *nc)
-{
-    MIPSnetState *s = qemu_get_nic_opaque(nc);
-
-    if (s->busy)
-        return 0;
-    return !mipsnet_buffer_full(s);
-}
-
-static ssize_t mipsnet_receive(NetClientState *nc, const uint8_t *buf, size_t size)
-{
-    MIPSnetState *s = qemu_get_nic_opaque(nc);
-
-    trace_mipsnet_receive(size);
-    if (!mipsnet_can_receive(nc))
-        return -1;
-
-    s->busy = 1;
-
-    /* Just accept everything. */
-
-    /* Write packet data. */
-    memcpy(s->rx_buffer, buf, size);
-
-    s->rx_count = size;
-    s->rx_read = 0;
-
-    /* Now we can signal we have received something. */
-    s->intctl |= MIPSNET_INTCTL_RXDONE;
-    mipsnet_update_irq(s);
-
-    return size;
-}
-
-static uint64_t mipsnet_ioport_read(void *opaque, hwaddr addr,
-                                    unsigned int size)
-{
-    MIPSnetState *s = opaque;
-    int ret = 0;
-
-    addr &= 0x3f;
-    switch (addr) {
-    case MIPSNET_DEV_ID:
-       ret = be32_to_cpu(0x4d495053);          /* MIPS */
-        break;
-    case MIPSNET_DEV_ID + 4:
-       ret = be32_to_cpu(0x4e455430);          /* NET0 */
-        break;
-    case MIPSNET_BUSY:
-       ret = s->busy;
-        break;
-    case MIPSNET_RX_DATA_COUNT:
-       ret = s->rx_count;
-        break;
-    case MIPSNET_TX_DATA_COUNT:
-       ret = s->tx_count;
-        break;
-    case MIPSNET_INT_CTL:
-       ret = s->intctl;
-        s->intctl &= ~MIPSNET_INTCTL_TESTBIT;
-        break;
-    case MIPSNET_INTERRUPT_INFO:
-        /* XXX: This seems to be a per-VPE interrupt number. */
-       ret = 0;
-        break;
-    case MIPSNET_RX_DATA_BUFFER:
-        if (s->rx_count) {
-            s->rx_count--;
-            ret = s->rx_buffer[s->rx_read++];
-        }
-        break;
-    /* Reads as zero. */
-    case MIPSNET_TX_DATA_BUFFER:
-    default:
-        break;
-    }
-    trace_mipsnet_read(addr, ret);
-    return ret;
-}
-
-static void mipsnet_ioport_write(void *opaque, hwaddr addr,
-                                 uint64_t val, unsigned int size)
-{
-    MIPSnetState *s = opaque;
-
-    addr &= 0x3f;
-    trace_mipsnet_write(addr, val);
-    switch (addr) {
-    case MIPSNET_TX_DATA_COUNT:
-       s->tx_count = (val <= MAX_ETH_FRAME_SIZE) ? val : 0;
-        s->tx_written = 0;
-        break;
-    case MIPSNET_INT_CTL:
-        if (val & MIPSNET_INTCTL_TXDONE) {
-            s->intctl &= ~MIPSNET_INTCTL_TXDONE;
-        } else if (val & MIPSNET_INTCTL_RXDONE) {
-            s->intctl &= ~MIPSNET_INTCTL_RXDONE;
-        } else if (val & MIPSNET_INTCTL_TESTBIT) {
-            mipsnet_reset(s);
-            s->intctl |= MIPSNET_INTCTL_TESTBIT;
-        } else if (!val) {
-            /* ACK testbit interrupt, flag was cleared on read. */
-        }
-        s->busy = !!s->intctl;
-        mipsnet_update_irq(s);
-        break;
-    case MIPSNET_TX_DATA_BUFFER:
-        s->tx_buffer[s->tx_written++] = val;
-        if (s->tx_written == s->tx_count) {
-            /* Send buffer. */
-            trace_mipsnet_send(s->tx_count);
-            qemu_send_packet(qemu_get_queue(s->nic), s->tx_buffer, s->tx_count);
-            s->tx_count = s->tx_written = 0;
-            s->intctl |= MIPSNET_INTCTL_TXDONE;
-            s->busy = 1;
-            mipsnet_update_irq(s);
-        }
-        break;
-    /* Read-only registers */
-    case MIPSNET_DEV_ID:
-    case MIPSNET_BUSY:
-    case MIPSNET_RX_DATA_COUNT:
-    case MIPSNET_INTERRUPT_INFO:
-    case MIPSNET_RX_DATA_BUFFER:
-    default:
-        break;
-    }
-}
-
-static const VMStateDescription vmstate_mipsnet = {
-    .name = "mipsnet",
-    .version_id = 0,
-    .minimum_version_id = 0,
-    .minimum_version_id_old = 0,
-    .fields      = (VMStateField[]) {
-        VMSTATE_UINT32(busy, MIPSnetState),
-        VMSTATE_UINT32(rx_count, MIPSnetState),
-        VMSTATE_UINT32(rx_read, MIPSnetState),
-        VMSTATE_UINT32(tx_count, MIPSnetState),
-        VMSTATE_UINT32(tx_written, MIPSnetState),
-        VMSTATE_UINT32(intctl, MIPSnetState),
-        VMSTATE_BUFFER(rx_buffer, MIPSnetState),
-        VMSTATE_BUFFER(tx_buffer, MIPSnetState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void mipsnet_cleanup(NetClientState *nc)
-{
-    MIPSnetState *s = qemu_get_nic_opaque(nc);
-
-    s->nic = NULL;
-}
-
-static NetClientInfo net_mipsnet_info = {
-    .type = NET_CLIENT_OPTIONS_KIND_NIC,
-    .size = sizeof(NICState),
-    .can_receive = mipsnet_can_receive,
-    .receive = mipsnet_receive,
-    .cleanup = mipsnet_cleanup,
-};
-
-static const MemoryRegionOps mipsnet_ioport_ops = {
-    .read = mipsnet_ioport_read,
-    .write = mipsnet_ioport_write,
-    .impl.min_access_size = 1,
-    .impl.max_access_size = 4,
-};
-
-static int mipsnet_sysbus_init(SysBusDevice *dev)
-{
-    MIPSnetState *s = DO_UPCAST(MIPSnetState, busdev, dev);
-
-    memory_region_init_io(&s->io, &mipsnet_ioport_ops, s, "mipsnet-io", 36);
-    sysbus_init_mmio(dev, &s->io);
-    sysbus_init_irq(dev, &s->irq);
-
-    s->nic = qemu_new_nic(&net_mipsnet_info, &s->conf,
-                          object_get_typename(OBJECT(dev)), dev->qdev.id, s);
-    qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
-
-    return 0;
-}
-
-static void mipsnet_sysbus_reset(DeviceState *dev)
-{
-    MIPSnetState *s = DO_UPCAST(MIPSnetState, busdev.qdev, dev);
-    mipsnet_reset(s);
-}
-
-static Property mipsnet_properties[] = {
-    DEFINE_NIC_PROPERTIES(MIPSnetState, conf),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void mipsnet_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = mipsnet_sysbus_init;
-    dc->desc = "MIPS Simulator network device";
-    dc->reset = mipsnet_sysbus_reset;
-    dc->vmsd = &vmstate_mipsnet;
-    dc->props = mipsnet_properties;
-}
-
-static const TypeInfo mipsnet_info = {
-    .name          = "mipsnet",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(MIPSnetState),
-    .class_init    = mipsnet_class_init,
-};
-
-static void mipsnet_register_types(void)
-{
-    type_register_static(&mipsnet_info);
-}
-
-type_init(mipsnet_register_types)
diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
new file mode 100644 (file)
index 0000000..03699c3
--- /dev/null
@@ -0,0 +1,40 @@
+common-obj-$(CONFIG_APPLESMC) += applesmc.o
+common-obj-$(CONFIG_MAX111X) += max111x.o
+common-obj-$(CONFIG_TMP105) += tmp105.o
+common-obj-$(CONFIG_ISA_DEBUG) += debugexit.o
+common-obj-$(CONFIG_SGA) += sga.o
+common-obj-$(CONFIG_ISA_TESTDEV) += pc-testdev.o
+
+obj-$(CONFIG_VMPORT) += vmport.o
+
+# ARM devices
+common-obj-$(CONFIG_PL310) += arm_l2x0.o
+
+# PKUnity SoC devices
+common-obj-$(CONFIG_PUV3) += puv3_pm.o
+
+common-obj-$(CONFIG_MACIO) += macio/
+
+ifeq ($(CONFIG_PCI), y)
+obj-$(CONFIG_KVM) += ivshmem.o
+obj-$(CONFIG_LINUX) += vfio.o
+endif
+
+obj-$(CONFIG_REALVIEW) += arm_sysctl.o
+obj-$(CONFIG_A9SCU) += a9scu.o
+obj-$(CONFIG_NSERIES) += cbus.o
+obj-$(CONFIG_ECCMEMCTL) += eccmemctl.o
+obj-$(CONFIG_EXYNOS4) += exynos4210_pmu.o
+obj-$(CONFIG_IMX) += imx_ccm.o
+obj-$(CONFIG_LM32) += lm32_sys.o
+obj-$(CONFIG_MILKYMIST) += milkymist-hpdmc.o
+obj-$(CONFIG_MILKYMIST) += milkymist-pfpu.o
+obj-$(CONFIG_MAINSTONE) += mst_fpga.o
+obj-$(CONFIG_OMAP) += omap_clk.o
+obj-$(CONFIG_OMAP) += omap_gpmc.o
+obj-$(CONFIG_OMAP) += omap_l4.o
+obj-$(CONFIG_OMAP) += omap_sdrc.o
+obj-$(CONFIG_OMAP) += omap_tap.o
+obj-$(CONFIG_PXA2XX) += pxa2xx_pcmcia.o
+obj-$(CONFIG_SLAVIO) += slavio_misc.o
+obj-$(CONFIG_ZYNQ) += zynq_slcr.o
diff --git a/hw/misc/a9scu.c b/hw/misc/a9scu.c
new file mode 100644 (file)
index 0000000..05897c2
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * Cortex-A9MPCore Snoop Control Unit (SCU) emulation.
+ *
+ * Copyright (c) 2009 CodeSourcery.
+ * Copyright (c) 2011 Linaro Limited.
+ * Written by Paul Brook, Peter Maydell.
+ *
+ * This code is licensed under the GPL.
+ */
+
+#include "hw/sysbus.h"
+
+/* A9MP private memory region.  */
+
+typedef struct A9SCUState {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    uint32_t control;
+    uint32_t status;
+    uint32_t num_cpu;
+} A9SCUState;
+
+#define TYPE_A9_SCU "a9-scu"
+#define A9_SCU(obj) OBJECT_CHECK(A9SCUState, (obj), TYPE_A9_SCU)
+
+static uint64_t a9_scu_read(void *opaque, hwaddr offset,
+                            unsigned size)
+{
+    A9SCUState *s = (A9SCUState *)opaque;
+    switch (offset) {
+    case 0x00: /* Control */
+        return s->control;
+    case 0x04: /* Configuration */
+        return (((1 << s->num_cpu) - 1) << 4) | (s->num_cpu - 1);
+    case 0x08: /* CPU Power Status */
+        return s->status;
+    case 0x09: /* CPU status.  */
+        return s->status >> 8;
+    case 0x0a: /* CPU status.  */
+        return s->status >> 16;
+    case 0x0b: /* CPU status.  */
+        return s->status >> 24;
+    case 0x0c: /* Invalidate All Registers In Secure State */
+        return 0;
+    case 0x40: /* Filtering Start Address Register */
+    case 0x44: /* Filtering End Address Register */
+        /* RAZ/WI, like an implementation with only one AXI master */
+        return 0;
+    case 0x50: /* SCU Access Control Register */
+    case 0x54: /* SCU Non-secure Access Control Register */
+        /* unimplemented, fall through */
+    default:
+        return 0;
+    }
+}
+
+static void a9_scu_write(void *opaque, hwaddr offset,
+                         uint64_t value, unsigned size)
+{
+    A9SCUState *s = (A9SCUState *)opaque;
+    uint32_t mask;
+    uint32_t shift;
+    switch (size) {
+    case 1:
+        mask = 0xff;
+        break;
+    case 2:
+        mask = 0xffff;
+        break;
+    case 4:
+        mask = 0xffffffff;
+        break;
+    default:
+        fprintf(stderr, "Invalid size %u in write to a9 scu register %x\n",
+                size, (unsigned)offset);
+        return;
+    }
+
+    switch (offset) {
+    case 0x00: /* Control */
+        s->control = value & 1;
+        break;
+    case 0x4: /* Configuration: RO */
+        break;
+    case 0x08: case 0x09: case 0x0A: case 0x0B: /* Power Control */
+        shift = (offset - 0x8) * 8;
+        s->status &= ~(mask << shift);
+        s->status |= ((value & mask) << shift);
+        break;
+    case 0x0c: /* Invalidate All Registers In Secure State */
+        /* no-op as we do not implement caches */
+        break;
+    case 0x40: /* Filtering Start Address Register */
+    case 0x44: /* Filtering End Address Register */
+        /* RAZ/WI, like an implementation with only one AXI master */
+        break;
+    case 0x50: /* SCU Access Control Register */
+    case 0x54: /* SCU Non-secure Access Control Register */
+        /* unimplemented, fall through */
+    default:
+        break;
+    }
+}
+
+static const MemoryRegionOps a9_scu_ops = {
+    .read = a9_scu_read,
+    .write = a9_scu_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void a9_scu_reset(DeviceState *dev)
+{
+    A9SCUState *s = A9_SCU(dev);
+    s->control = 0;
+}
+
+static void a9_scu_realize(DeviceState *dev, Error ** errp)
+{
+    A9SCUState *s = A9_SCU(dev);
+    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+
+    memory_region_init_io(&s->iomem, &a9_scu_ops, s, "a9-scu", 0x100);
+    sysbus_init_mmio(sbd, &s->iomem);
+}
+
+static const VMStateDescription vmstate_a9_scu = {
+    .name = "a9-scu",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(control, A9SCUState),
+        VMSTATE_UINT32(status, A9SCUState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static Property a9_scu_properties[] = {
+    DEFINE_PROP_UINT32("num-cpu", A9SCUState, num_cpu, 1),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void a9_scu_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->realize = a9_scu_realize;
+    dc->props = a9_scu_properties;
+    dc->vmsd = &vmstate_a9_scu;
+    dc->reset = a9_scu_reset;
+}
+
+static const TypeInfo a9_scu_info = {
+    .name          = TYPE_A9_SCU,
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(A9SCUState),
+    .class_init    = a9_scu_class_init,
+};
+
+static void a9mp_register_types(void)
+{
+    type_register_static(&a9_scu_info);
+}
+
+type_init(a9mp_register_types)
diff --git a/hw/misc/applesmc.c b/hw/misc/applesmc.c
new file mode 100644 (file)
index 0000000..c29558b
--- /dev/null
@@ -0,0 +1,251 @@
+/*
+ *  Apple SMC controller
+ *
+ *  Copyright (c) 2007 Alexander Graf
+ *
+ *  Authors: Alexander Graf <agraf@suse.de>
+ *           Susanne Graf <suse@csgraf.de>
+ *
+ * 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/>.
+ *
+ * *****************************************************************
+ *
+ * In all Intel-based Apple hardware there is an SMC chip to control the
+ * backlight, fans and several other generic device parameters. It also
+ * contains the magic keys used to dongle Mac OS X to the device.
+ *
+ * This driver was mostly created by looking at the Linux AppleSMC driver
+ * implementation and does not support IRQ.
+ *
+ */
+
+#include "hw/hw.h"
+#include "hw/isa/isa.h"
+#include "ui/console.h"
+#include "qemu/timer.h"
+
+/* #define DEBUG_SMC */
+
+#define APPLESMC_DEFAULT_IOBASE        0x300
+/* data port used by Apple SMC */
+#define APPLESMC_DATA_PORT             0x0
+/* command/status port used by Apple SMC */
+#define APPLESMC_CMD_PORT              0x4
+#define APPLESMC_NR_PORTS              32
+#define APPLESMC_MAX_DATA_LENGTH       32
+
+#define APPLESMC_READ_CMD              0x10
+#define APPLESMC_WRITE_CMD             0x11
+#define APPLESMC_GET_KEY_BY_INDEX_CMD  0x12
+#define APPLESMC_GET_KEY_TYPE_CMD      0x13
+
+#ifdef DEBUG_SMC
+#define smc_debug(...) fprintf(stderr, "AppleSMC: " __VA_ARGS__)
+#else
+#define smc_debug(...) do { } while(0)
+#endif
+
+static char default_osk[64] = "This is a dummy key. Enter the real key "
+                              "using the -osk parameter";
+
+struct AppleSMCData {
+    uint8_t len;
+    const char *key;
+    const char *data;
+    QLIST_ENTRY(AppleSMCData) node;
+};
+
+struct AppleSMCStatus {
+    ISADevice dev;
+    uint32_t iobase;
+    uint8_t cmd;
+    uint8_t status;
+    uint8_t key[4];
+    uint8_t read_pos;
+    uint8_t data_len;
+    uint8_t data_pos;
+    uint8_t data[255];
+    uint8_t charactic[4];
+    char *osk;
+    QLIST_HEAD(, AppleSMCData) data_def;
+};
+
+static void applesmc_io_cmd_writeb(void *opaque, uint32_t addr, uint32_t val)
+{
+    struct AppleSMCStatus *s = opaque;
+
+    smc_debug("CMD Write B: %#x = %#x\n", addr, val);
+    switch(val) {
+        case APPLESMC_READ_CMD:
+            s->status = 0x0c;
+            break;
+    }
+    s->cmd = val;
+    s->read_pos = 0;
+    s->data_pos = 0;
+}
+
+static void applesmc_fill_data(struct AppleSMCStatus *s)
+{
+    struct AppleSMCData *d;
+
+    QLIST_FOREACH(d, &s->data_def, node) {
+        if (!memcmp(d->key, s->key, 4)) {
+            smc_debug("Key matched (%s Len=%d Data=%s)\n", d->key,
+                      d->len, d->data);
+            memcpy(s->data, d->data, d->len);
+            return;
+        }
+    }
+}
+
+static void applesmc_io_data_writeb(void *opaque, uint32_t addr, uint32_t val)
+{
+    struct AppleSMCStatus *s = opaque;
+
+    smc_debug("DATA Write B: %#x = %#x\n", addr, val);
+    switch(s->cmd) {
+        case APPLESMC_READ_CMD:
+            if(s->read_pos < 4) {
+                s->key[s->read_pos] = val;
+                s->status = 0x04;
+            } else if(s->read_pos == 4) {
+                s->data_len = val;
+                s->status = 0x05;
+                s->data_pos = 0;
+                smc_debug("Key = %c%c%c%c Len = %d\n", s->key[0],
+                          s->key[1], s->key[2], s->key[3], val);
+                applesmc_fill_data(s);
+            }
+            s->read_pos++;
+            break;
+    }
+}
+
+static uint32_t applesmc_io_data_readb(void *opaque, uint32_t addr1)
+{
+    struct AppleSMCStatus *s = opaque;
+    uint8_t retval = 0;
+
+    switch(s->cmd) {
+        case APPLESMC_READ_CMD:
+            if(s->data_pos < s->data_len) {
+                retval = s->data[s->data_pos];
+                smc_debug("READ_DATA[%d] = %#hhx\n", s->data_pos,
+                          retval);
+                s->data_pos++;
+                if(s->data_pos == s->data_len) {
+                    s->status = 0x00;
+                    smc_debug("EOF\n");
+                } else
+                    s->status = 0x05;
+            }
+    }
+    smc_debug("DATA Read b: %#x = %#x\n", addr1, retval);
+
+    return retval;
+}
+
+static uint32_t applesmc_io_cmd_readb(void *opaque, uint32_t addr1)
+{
+    struct AppleSMCStatus *s = opaque;
+
+    smc_debug("CMD Read B: %#x\n", addr1);
+    return s->status;
+}
+
+static void applesmc_add_key(struct AppleSMCStatus *s, const char *key,
+                             int len, const char *data)
+{
+    struct AppleSMCData *def;
+
+    def = g_malloc0(sizeof(struct AppleSMCData));
+    def->key = key;
+    def->len = len;
+    def->data = data;
+
+    QLIST_INSERT_HEAD(&s->data_def, def, node);
+}
+
+static void qdev_applesmc_isa_reset(DeviceState *dev)
+{
+    struct AppleSMCStatus *s = DO_UPCAST(struct AppleSMCStatus, dev.qdev, dev);
+    struct AppleSMCData *d, *next;
+
+    /* Remove existing entries */
+    QLIST_FOREACH_SAFE(d, &s->data_def, node, next) {
+        QLIST_REMOVE(d, node);
+    }
+
+    applesmc_add_key(s, "REV ", 6, "\x01\x13\x0f\x00\x00\x03");
+    applesmc_add_key(s, "OSK0", 32, s->osk);
+    applesmc_add_key(s, "OSK1", 32, s->osk + 32);
+    applesmc_add_key(s, "NATJ", 1, "\0");
+    applesmc_add_key(s, "MSSP", 1, "\0");
+    applesmc_add_key(s, "MSSD", 1, "\0x3");
+}
+
+static int applesmc_isa_init(ISADevice *dev)
+{
+    struct AppleSMCStatus *s = DO_UPCAST(struct AppleSMCStatus, dev, dev);
+
+    register_ioport_read(s->iobase + APPLESMC_DATA_PORT, 4, 1,
+                         applesmc_io_data_readb, s);
+    register_ioport_read(s->iobase + APPLESMC_CMD_PORT, 4, 1,
+                         applesmc_io_cmd_readb, s);
+    register_ioport_write(s->iobase + APPLESMC_DATA_PORT, 4, 1,
+                          applesmc_io_data_writeb, s);
+    register_ioport_write(s->iobase + APPLESMC_CMD_PORT, 4, 1,
+                          applesmc_io_cmd_writeb, s);
+
+    if (!s->osk || (strlen(s->osk) != 64)) {
+        fprintf(stderr, "WARNING: Using AppleSMC with invalid key\n");
+        s->osk = default_osk;
+    }
+
+    QLIST_INIT(&s->data_def);
+    qdev_applesmc_isa_reset(&dev->qdev);
+
+    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 const 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_types(void)
+{
+    type_register_static(&applesmc_isa_info);
+}
+
+type_init(applesmc_register_types)
diff --git a/hw/misc/arm_l2x0.c b/hw/misc/arm_l2x0.c
new file mode 100644 (file)
index 0000000..eb4427d
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+ * ARM dummy L210, L220, PL310 cache controller.
+ *
+ * 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 any later version, 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 "hw/sysbus.h"
+
+/* L2C-310 r3p2 */
+#define CACHE_ID 0x410000c8
+
+typedef struct l2x0_state {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    uint32_t cache_type;
+    uint32_t ctrl;
+    uint32_t aux_ctrl;
+    uint32_t data_ctrl;
+    uint32_t tag_ctrl;
+    uint32_t filter_start;
+    uint32_t filter_end;
+} l2x0_state;
+
+static const VMStateDescription vmstate_l2x0 = {
+    .name = "l2x0",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(ctrl, l2x0_state),
+        VMSTATE_UINT32(aux_ctrl, l2x0_state),
+        VMSTATE_UINT32(data_ctrl, l2x0_state),
+        VMSTATE_UINT32(tag_ctrl, l2x0_state),
+        VMSTATE_UINT32(filter_start, l2x0_state),
+        VMSTATE_UINT32(filter_end, l2x0_state),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+
+static uint64_t l2x0_priv_read(void *opaque, hwaddr offset,
+                               unsigned size)
+{
+    uint32_t cache_data;
+    l2x0_state *s = (l2x0_state *)opaque;
+    offset &= 0xfff;
+    if (offset >= 0x730 && offset < 0x800) {
+        return 0; /* cache ops complete */
+    }
+    switch (offset) {
+    case 0:
+        return CACHE_ID;
+    case 0x4:
+        /* aux_ctrl values affect cache_type values */
+        cache_data = (s->aux_ctrl & (7 << 17)) >> 15;
+        cache_data |= (s->aux_ctrl & (1 << 16)) >> 16;
+        return s->cache_type |= (cache_data << 18) | (cache_data << 6);
+    case 0x100:
+        return s->ctrl;
+    case 0x104:
+        return s->aux_ctrl;
+    case 0x108:
+        return s->tag_ctrl;
+    case 0x10C:
+        return s->data_ctrl;
+    case 0xC00:
+        return s->filter_start;
+    case 0xC04:
+        return s->filter_end;
+    case 0xF40:
+        return 0;
+    case 0xF60:
+        return 0;
+    case 0xF80:
+        return 0;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "l2x0_priv_read: Bad offset %x\n", (int)offset);
+        break;
+    }
+    return 0;
+}
+
+static void l2x0_priv_write(void *opaque, hwaddr offset,
+                            uint64_t value, unsigned size)
+{
+    l2x0_state *s = (l2x0_state *)opaque;
+    offset &= 0xfff;
+    if (offset >= 0x730 && offset < 0x800) {
+        /* ignore */
+        return;
+    }
+    switch (offset) {
+    case 0x100:
+        s->ctrl = value & 1;
+        break;
+    case 0x104:
+        s->aux_ctrl = value;
+        break;
+    case 0x108:
+        s->tag_ctrl = value;
+        break;
+    case 0x10C:
+        s->data_ctrl = value;
+        break;
+    case 0xC00:
+        s->filter_start = value;
+        break;
+    case 0xC04:
+        s->filter_end = value;
+        break;
+    case 0xF40:
+        return;
+    case 0xF60:
+        return;
+    case 0xF80:
+        return;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "l2x0_priv_write: Bad offset %x\n", (int)offset);
+        break;
+    }
+}
+
+static void l2x0_priv_reset(DeviceState *dev)
+{
+    l2x0_state *s = DO_UPCAST(l2x0_state, busdev.qdev, dev);
+
+    s->ctrl = 0;
+    s->aux_ctrl = 0x02020000;
+    s->tag_ctrl = 0;
+    s->data_ctrl = 0;
+    s->filter_start = 0;
+    s->filter_end = 0;
+}
+
+static const MemoryRegionOps l2x0_mem_ops = {
+    .read = l2x0_priv_read,
+    .write = l2x0_priv_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+ };
+
+static int l2x0_priv_init(SysBusDevice *dev)
+{
+    l2x0_state *s = FROM_SYSBUS(l2x0_state, dev);
+
+    memory_region_init_io(&s->iomem, &l2x0_mem_ops, s, "l2x0_cc", 0x1000);
+    sysbus_init_mmio(dev, &s->iomem);
+    return 0;
+}
+
+static Property l2x0_properties[] = {
+    DEFINE_PROP_UINT32("cache-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 const TypeInfo l2x0_info = {
+    .name = "l2x0",
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(l2x0_state),
+    .class_init = l2x0_class_init,
+};
+
+static void l2x0_register_types(void)
+{
+    type_register_static(&l2x0_info);
+}
+
+type_init(l2x0_register_types)
diff --git a/hw/misc/arm_sysctl.c b/hw/misc/arm_sysctl.c
new file mode 100644 (file)
index 0000000..c8b55a8
--- /dev/null
@@ -0,0 +1,649 @@
+/*
+ * Status and system control registers for ARM RealView/Versatile boards.
+ *
+ * Copyright (c) 2006-2007 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the GPL.
+ */
+
+#include "hw/hw.h"
+#include "qemu/timer.h"
+#include "qemu/bitops.h"
+#include "hw/sysbus.h"
+#include "hw/arm/primecell.h"
+#include "sysemu/sysemu.h"
+
+#define LOCK_VALUE 0xa05f
+
+typedef struct {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    qemu_irq pl110_mux_ctrl;
+
+    uint32_t sys_id;
+    uint32_t leds;
+    uint16_t lockval;
+    uint32_t cfgdata1;
+    uint32_t cfgdata2;
+    uint32_t flags;
+    uint32_t nvflags;
+    uint32_t resetlevel;
+    uint32_t proc_id;
+    uint32_t sys_mci;
+    uint32_t sys_cfgdata;
+    uint32_t sys_cfgctrl;
+    uint32_t sys_cfgstat;
+    uint32_t sys_clcd;
+    uint32_t mb_clock[6];
+    uint32_t *db_clock;
+    uint32_t db_num_vsensors;
+    uint32_t *db_voltage;
+    uint32_t db_num_clocks;
+    uint32_t *db_clock_reset;
+} arm_sysctl_state;
+
+static const VMStateDescription vmstate_arm_sysctl = {
+    .name = "realview_sysctl",
+    .version_id = 4,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(leds, arm_sysctl_state),
+        VMSTATE_UINT16(lockval, arm_sysctl_state),
+        VMSTATE_UINT32(cfgdata1, arm_sysctl_state),
+        VMSTATE_UINT32(cfgdata2, arm_sysctl_state),
+        VMSTATE_UINT32(flags, arm_sysctl_state),
+        VMSTATE_UINT32(nvflags, arm_sysctl_state),
+        VMSTATE_UINT32(resetlevel, arm_sysctl_state),
+        VMSTATE_UINT32_V(sys_mci, arm_sysctl_state, 2),
+        VMSTATE_UINT32_V(sys_cfgdata, arm_sysctl_state, 2),
+        VMSTATE_UINT32_V(sys_cfgctrl, arm_sysctl_state, 2),
+        VMSTATE_UINT32_V(sys_cfgstat, arm_sysctl_state, 2),
+        VMSTATE_UINT32_V(sys_clcd, arm_sysctl_state, 3),
+        VMSTATE_UINT32_ARRAY_V(mb_clock, arm_sysctl_state, 6, 4),
+        VMSTATE_VARRAY_UINT32(db_clock, arm_sysctl_state, db_num_clocks,
+                              4, vmstate_info_uint32, uint32_t),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+/* The PB926 actually uses a different format for
+ * its SYS_ID register. Fortunately the bits which are
+ * board type on later boards are distinct.
+ */
+#define BOARD_ID_PB926 0x100
+#define BOARD_ID_EB 0x140
+#define BOARD_ID_PBA8 0x178
+#define BOARD_ID_PBX 0x182
+#define BOARD_ID_VEXPRESS 0x190
+
+static int board_id(arm_sysctl_state *s)
+{
+    /* Extract the board ID field from the SYS_ID register value */
+    return (s->sys_id >> 16) & 0xfff;
+}
+
+static void arm_sysctl_reset(DeviceState *d)
+{
+    arm_sysctl_state *s = FROM_SYSBUS(arm_sysctl_state, SYS_BUS_DEVICE(d));
+    int i;
+
+    s->leds = 0;
+    s->lockval = 0;
+    s->cfgdata1 = 0;
+    s->cfgdata2 = 0;
+    s->flags = 0;
+    s->resetlevel = 0;
+    /* Motherboard oscillators (in Hz) */
+    s->mb_clock[0] = 50000000; /* Static memory clock: 50MHz */
+    s->mb_clock[1] = 23750000; /* motherboard CLCD clock: 23.75MHz */
+    s->mb_clock[2] = 24000000; /* IO FPGA peripheral clock: 24MHz */
+    s->mb_clock[3] = 24000000; /* IO FPGA reserved clock: 24MHz */
+    s->mb_clock[4] = 24000000; /* System bus global clock: 24MHz */
+    s->mb_clock[5] = 24000000; /* IO FPGA reserved clock: 24MHz */
+    /* Daughterboard oscillators: reset from property values */
+    for (i = 0; i < s->db_num_clocks; i++) {
+        s->db_clock[i] = s->db_clock_reset[i];
+    }
+    if (board_id(s) == BOARD_ID_VEXPRESS) {
+        /* On VExpress this register will RAZ/WI */
+        s->sys_clcd = 0;
+    } else {
+        /* All others: CLCDID 0x1f, indicating VGA */
+        s->sys_clcd = 0x1f00;
+    }
+}
+
+static uint64_t arm_sysctl_read(void *opaque, hwaddr offset,
+                                unsigned size)
+{
+    arm_sysctl_state *s = (arm_sysctl_state *)opaque;
+
+    switch (offset) {
+    case 0x00: /* ID */
+        return s->sys_id;
+    case 0x04: /* SW */
+        /* General purpose hardware switches.
+           We don't have a useful way of exposing these to the user.  */
+        return 0;
+    case 0x08: /* LED */
+        return s->leds;
+    case 0x20: /* LOCK */
+        return s->lockval;
+    case 0x0c: /* OSC0 */
+    case 0x10: /* OSC1 */
+    case 0x14: /* OSC2 */
+    case 0x18: /* OSC3 */
+    case 0x1c: /* OSC4 */
+    case 0x24: /* 100HZ */
+        /* ??? Implement these.  */
+        return 0;
+    case 0x28: /* CFGDATA1 */
+        return s->cfgdata1;
+    case 0x2c: /* CFGDATA2 */
+        return s->cfgdata2;
+    case 0x30: /* FLAGS */
+        return s->flags;
+    case 0x38: /* NVFLAGS */
+        return s->nvflags;
+    case 0x40: /* RESETCTL */
+        if (board_id(s) == BOARD_ID_VEXPRESS) {
+            /* reserved: RAZ/WI */
+            return 0;
+        }
+        return s->resetlevel;
+    case 0x44: /* PCICTL */
+        return 1;
+    case 0x48: /* MCI */
+        return s->sys_mci;
+    case 0x4c: /* FLASH */
+        return 0;
+    case 0x50: /* CLCD */
+        return s->sys_clcd;
+    case 0x54: /* CLCDSER */
+        return 0;
+    case 0x58: /* BOOTCS */
+        return 0;
+    case 0x5c: /* 24MHz */
+        return muldiv64(qemu_get_clock_ns(vm_clock), 24000000, get_ticks_per_sec());
+    case 0x60: /* MISC */
+        return 0;
+    case 0x84: /* PROCID0 */
+        return s->proc_id;
+    case 0x88: /* PROCID1 */
+        return 0xff000000;
+    case 0x64: /* DMAPSR0 */
+    case 0x68: /* DMAPSR1 */
+    case 0x6c: /* DMAPSR2 */
+    case 0x70: /* IOSEL */
+    case 0x74: /* PLDCTL */
+    case 0x80: /* BUSID */
+    case 0x8c: /* OSCRESET0 */
+    case 0x90: /* OSCRESET1 */
+    case 0x94: /* OSCRESET2 */
+    case 0x98: /* OSCRESET3 */
+    case 0x9c: /* OSCRESET4 */
+    case 0xc0: /* SYS_TEST_OSC0 */
+    case 0xc4: /* SYS_TEST_OSC1 */
+    case 0xc8: /* SYS_TEST_OSC2 */
+    case 0xcc: /* SYS_TEST_OSC3 */
+    case 0xd0: /* SYS_TEST_OSC4 */
+        return 0;
+    case 0xa0: /* SYS_CFGDATA */
+        if (board_id(s) != BOARD_ID_VEXPRESS) {
+            goto bad_reg;
+        }
+        return s->sys_cfgdata;
+    case 0xa4: /* SYS_CFGCTRL */
+        if (board_id(s) != BOARD_ID_VEXPRESS) {
+            goto bad_reg;
+        }
+        return s->sys_cfgctrl;
+    case 0xa8: /* SYS_CFGSTAT */
+        if (board_id(s) != BOARD_ID_VEXPRESS) {
+            goto bad_reg;
+        }
+        return s->sys_cfgstat;
+    default:
+    bad_reg:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "arm_sysctl_read: Bad register offset 0x%x\n",
+                      (int)offset);
+        return 0;
+    }
+}
+
+/* SYS_CFGCTRL functions */
+#define SYS_CFG_OSC 1
+#define SYS_CFG_VOLT 2
+#define SYS_CFG_AMP 3
+#define SYS_CFG_TEMP 4
+#define SYS_CFG_RESET 5
+#define SYS_CFG_SCC 6
+#define SYS_CFG_MUXFPGA 7
+#define SYS_CFG_SHUTDOWN 8
+#define SYS_CFG_REBOOT 9
+#define SYS_CFG_DVIMODE 11
+#define SYS_CFG_POWER 12
+#define SYS_CFG_ENERGY 13
+
+/* SYS_CFGCTRL site field values */
+#define SYS_CFG_SITE_MB 0
+#define SYS_CFG_SITE_DB1 1
+#define SYS_CFG_SITE_DB2 2
+
+/**
+ * vexpress_cfgctrl_read:
+ * @s: arm_sysctl_state pointer
+ * @dcc, @function, @site, @position, @device: split out values from
+ * SYS_CFGCTRL register
+ * @val: pointer to where to put the read data on success
+ *
+ * Handle a VExpress SYS_CFGCTRL register read. On success, return true and
+ * write the read value to *val. On failure, return false (and val may
+ * or may not be written to).
+ */
+static bool vexpress_cfgctrl_read(arm_sysctl_state *s, unsigned int dcc,
+                                  unsigned int function, unsigned int site,
+                                  unsigned int position, unsigned int device,
+                                  uint32_t *val)
+{
+    /* We don't support anything other than DCC 0, board stack position 0
+     * or sites other than motherboard/daughterboard:
+     */
+    if (dcc != 0 || position != 0 ||
+        (site != SYS_CFG_SITE_MB && site != SYS_CFG_SITE_DB1)) {
+        goto cfgctrl_unimp;
+    }
+
+    switch (function) {
+    case SYS_CFG_VOLT:
+        if (site == SYS_CFG_SITE_DB1 && device < s->db_num_vsensors) {
+            *val = s->db_voltage[device];
+            return true;
+        }
+        if (site == SYS_CFG_SITE_MB && device == 0) {
+            /* There is only one motherboard voltage sensor:
+             * VIO : 3.3V : bus voltage between mother and daughterboard
+             */
+            *val = 3300000;
+            return true;
+        }
+        break;
+    case SYS_CFG_OSC:
+        if (site == SYS_CFG_SITE_MB && device < sizeof(s->mb_clock)) {
+            /* motherboard clock */
+            *val = s->mb_clock[device];
+            return true;
+        }
+        if (site == SYS_CFG_SITE_DB1 && device < s->db_num_clocks) {
+            /* daughterboard clock */
+            *val = s->db_clock[device];
+            return true;
+        }
+        break;
+    default:
+        break;
+    }
+
+cfgctrl_unimp:
+    qemu_log_mask(LOG_UNIMP,
+                  "arm_sysctl: Unimplemented SYS_CFGCTRL read of function "
+                  "0x%x DCC 0x%x site 0x%x position 0x%x device 0x%x\n",
+                  function, dcc, site, position, device);
+    return false;
+}
+
+/**
+ * vexpress_cfgctrl_write:
+ * @s: arm_sysctl_state pointer
+ * @dcc, @function, @site, @position, @device: split out values from
+ * SYS_CFGCTRL register
+ * @val: data to write
+ *
+ * Handle a VExpress SYS_CFGCTRL register write. On success, return true.
+ * On failure, return false.
+ */
+static bool vexpress_cfgctrl_write(arm_sysctl_state *s, unsigned int dcc,
+                                   unsigned int function, unsigned int site,
+                                   unsigned int position, unsigned int device,
+                                   uint32_t val)
+{
+    /* We don't support anything other than DCC 0, board stack position 0
+     * or sites other than motherboard/daughterboard:
+     */
+    if (dcc != 0 || position != 0 ||
+        (site != SYS_CFG_SITE_MB && site != SYS_CFG_SITE_DB1)) {
+        goto cfgctrl_unimp;
+    }
+
+    switch (function) {
+    case SYS_CFG_OSC:
+        if (site == SYS_CFG_SITE_MB && device < sizeof(s->mb_clock)) {
+            /* motherboard clock */
+            s->mb_clock[device] = val;
+            return true;
+        }
+        if (site == SYS_CFG_SITE_DB1 && device < s->db_num_clocks) {
+            /* daughterboard clock */
+            s->db_clock[device] = val;
+            return true;
+        }
+        break;
+    case SYS_CFG_MUXFPGA:
+        if (site == SYS_CFG_SITE_MB && device == 0) {
+            /* Select whether video output comes from motherboard
+             * or daughterboard: log and ignore as QEMU doesn't
+             * support this.
+             */
+            qemu_log_mask(LOG_UNIMP, "arm_sysctl: selection of video output "
+                          "not supported, ignoring\n");
+            return true;
+        }
+        break;
+    case SYS_CFG_SHUTDOWN:
+        if (site == SYS_CFG_SITE_MB && device == 0) {
+            qemu_system_shutdown_request();
+            return true;
+        }
+        break;
+    case SYS_CFG_REBOOT:
+        if (site == SYS_CFG_SITE_MB && device == 0) {
+            qemu_system_reset_request();
+            return true;
+        }
+        break;
+    case SYS_CFG_DVIMODE:
+        if (site == SYS_CFG_SITE_MB && device == 0) {
+            /* Selecting DVI mode is meaningless for QEMU: we will
+             * always display the output correctly according to the
+             * pixel height/width programmed into the CLCD controller.
+             */
+            return true;
+        }
+    default:
+        break;
+    }
+
+cfgctrl_unimp:
+    qemu_log_mask(LOG_UNIMP,
+                  "arm_sysctl: Unimplemented SYS_CFGCTRL write of function "
+                  "0x%x DCC 0x%x site 0x%x position 0x%x device 0x%x\n",
+                  function, dcc, site, position, device);
+    return false;
+}
+
+static void arm_sysctl_write(void *opaque, hwaddr offset,
+                             uint64_t val, unsigned size)
+{
+    arm_sysctl_state *s = (arm_sysctl_state *)opaque;
+
+    switch (offset) {
+    case 0x08: /* LED */
+        s->leds = val;
+        break;
+    case 0x0c: /* OSC0 */
+    case 0x10: /* OSC1 */
+    case 0x14: /* OSC2 */
+    case 0x18: /* OSC3 */
+    case 0x1c: /* OSC4 */
+        /* ??? */
+        break;
+    case 0x20: /* LOCK */
+        if (val == LOCK_VALUE)
+            s->lockval = val;
+        else
+            s->lockval = val & 0x7fff;
+        break;
+    case 0x28: /* CFGDATA1 */
+        /* ??? Need to implement this.  */
+        s->cfgdata1 = val;
+        break;
+    case 0x2c: /* CFGDATA2 */
+        /* ??? Need to implement this.  */
+        s->cfgdata2 = val;
+        break;
+    case 0x30: /* FLAGSSET */
+        s->flags |= val;
+        break;
+    case 0x34: /* FLAGSCLR */
+        s->flags &= ~val;
+        break;
+    case 0x38: /* NVFLAGSSET */
+        s->nvflags |= val;
+        break;
+    case 0x3c: /* NVFLAGSCLR */
+        s->nvflags &= ~val;
+        break;
+    case 0x40: /* RESETCTL */
+        switch (board_id(s)) {
+        case BOARD_ID_PB926:
+            if (s->lockval == LOCK_VALUE) {
+                s->resetlevel = val;
+                if (val & 0x100) {
+                    qemu_system_reset_request();
+                }
+            }
+            break;
+        case BOARD_ID_PBX:
+        case BOARD_ID_PBA8:
+            if (s->lockval == LOCK_VALUE) {
+                s->resetlevel = val;
+                if (val & 0x04) {
+                    qemu_system_reset_request();
+                }
+            }
+            break;
+        case BOARD_ID_VEXPRESS:
+        case BOARD_ID_EB:
+        default:
+            /* reserved: RAZ/WI */
+            break;
+        }
+        break;
+    case 0x44: /* PCICTL */
+        /* nothing to do.  */
+        break;
+    case 0x4c: /* FLASH */
+        break;
+    case 0x50: /* CLCD */
+        switch (board_id(s)) {
+        case BOARD_ID_PB926:
+            /* On 926 bits 13:8 are R/O, bits 1:0 control
+             * the mux that defines how to interpret the PL110
+             * graphics format, and other bits are r/w but we
+             * don't implement them to do anything.
+             */
+            s->sys_clcd &= 0x3f00;
+            s->sys_clcd |= val & ~0x3f00;
+            qemu_set_irq(s->pl110_mux_ctrl, val & 3);
+            break;
+        case BOARD_ID_EB:
+            /* The EB is the same except that there is no mux since
+             * the EB has a PL111.
+             */
+            s->sys_clcd &= 0x3f00;
+            s->sys_clcd |= val & ~0x3f00;
+            break;
+        case BOARD_ID_PBA8:
+        case BOARD_ID_PBX:
+            /* On PBA8 and PBX bit 7 is r/w and all other bits
+             * are either r/o or RAZ/WI.
+             */
+            s->sys_clcd &= (1 << 7);
+            s->sys_clcd |= val & ~(1 << 7);
+            break;
+        case BOARD_ID_VEXPRESS:
+        default:
+            /* On VExpress this register is unimplemented and will RAZ/WI */
+            break;
+        }
+        break;
+    case 0x54: /* CLCDSER */
+    case 0x64: /* DMAPSR0 */
+    case 0x68: /* DMAPSR1 */
+    case 0x6c: /* DMAPSR2 */
+    case 0x70: /* IOSEL */
+    case 0x74: /* PLDCTL */
+    case 0x80: /* BUSID */
+    case 0x84: /* PROCID0 */
+    case 0x88: /* PROCID1 */
+    case 0x8c: /* OSCRESET0 */
+    case 0x90: /* OSCRESET1 */
+    case 0x94: /* OSCRESET2 */
+    case 0x98: /* OSCRESET3 */
+    case 0x9c: /* OSCRESET4 */
+        break;
+    case 0xa0: /* SYS_CFGDATA */
+        if (board_id(s) != BOARD_ID_VEXPRESS) {
+            goto bad_reg;
+        }
+        s->sys_cfgdata = val;
+        return;
+    case 0xa4: /* SYS_CFGCTRL */
+        if (board_id(s) != BOARD_ID_VEXPRESS) {
+            goto bad_reg;
+        }
+        /* Undefined bits [19:18] are RAZ/WI, and writing to
+         * the start bit just triggers the action; it always reads
+         * as zero.
+         */
+        s->sys_cfgctrl = val & ~((3 << 18) | (1 << 31));
+        if (val & (1 << 31)) {
+            /* Start bit set -- actually do something */
+            unsigned int dcc = extract32(s->sys_cfgctrl, 26, 4);
+            unsigned int function = extract32(s->sys_cfgctrl, 20, 6);
+            unsigned int site = extract32(s->sys_cfgctrl, 16, 2);
+            unsigned int position = extract32(s->sys_cfgctrl, 12, 4);
+            unsigned int device = extract32(s->sys_cfgctrl, 0, 12);
+            s->sys_cfgstat = 1;            /* complete */
+            if (s->sys_cfgctrl & (1 << 30)) {
+                if (!vexpress_cfgctrl_write(s, dcc, function, site, position,
+                                            device, s->sys_cfgdata)) {
+                    s->sys_cfgstat |= 2;        /* error */
+                }
+            } else {
+                uint32_t val;
+                if (!vexpress_cfgctrl_read(s, dcc, function, site, position,
+                                           device, &val)) {
+                    s->sys_cfgstat |= 2;        /* error */
+                } else {
+                    s->sys_cfgdata = val;
+                }
+            }
+        }
+        s->sys_cfgctrl &= ~(1 << 31);
+        return;
+    case 0xa8: /* SYS_CFGSTAT */
+        if (board_id(s) != BOARD_ID_VEXPRESS) {
+            goto bad_reg;
+        }
+        s->sys_cfgstat = val & 3;
+        return;
+    default:
+    bad_reg:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "arm_sysctl_write: Bad register offset 0x%x\n",
+                      (int)offset);
+        return;
+    }
+}
+
+static const MemoryRegionOps arm_sysctl_ops = {
+    .read = arm_sysctl_read,
+    .write = arm_sysctl_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void arm_sysctl_gpio_set(void *opaque, int line, int level)
+{
+    arm_sysctl_state *s = (arm_sysctl_state *)opaque;
+    switch (line) {
+    case ARM_SYSCTL_GPIO_MMC_WPROT:
+    {
+        /* For PB926 and EB write-protect is bit 2 of SYS_MCI;
+         * for all later boards it is bit 1.
+         */
+        int bit = 2;
+        if ((board_id(s) == BOARD_ID_PB926) || (board_id(s) == BOARD_ID_EB)) {
+            bit = 4;
+        }
+        s->sys_mci &= ~bit;
+        if (level) {
+            s->sys_mci |= bit;
+        }
+        break;
+    }
+    case ARM_SYSCTL_GPIO_MMC_CARDIN:
+        s->sys_mci &= ~1;
+        if (level) {
+            s->sys_mci |= 1;
+        }
+        break;
+    }
+}
+
+static void arm_sysctl_init(Object *obj)
+{
+    DeviceState *dev = DEVICE(obj);
+    SysBusDevice *sd = SYS_BUS_DEVICE(obj);
+    arm_sysctl_state *s = FROM_SYSBUS(arm_sysctl_state, sd);
+
+    memory_region_init_io(&s->iomem, &arm_sysctl_ops, s, "arm-sysctl", 0x1000);
+    sysbus_init_mmio(sd, &s->iomem);
+    qdev_init_gpio_in(dev, arm_sysctl_gpio_set, 2);
+    qdev_init_gpio_out(dev, &s->pl110_mux_ctrl, 1);
+}
+
+static void arm_sysctl_realize(DeviceState *d, Error **errp)
+{
+    arm_sysctl_state *s = FROM_SYSBUS(arm_sysctl_state, SYS_BUS_DEVICE(d));
+    s->db_clock = g_new0(uint32_t, s->db_num_clocks);
+}
+
+static void arm_sysctl_finalize(Object *obj)
+{
+    SysBusDevice *dev = SYS_BUS_DEVICE(obj);
+    arm_sysctl_state *s = FROM_SYSBUS(arm_sysctl_state, dev);
+    g_free(s->db_voltage);
+    g_free(s->db_clock);
+    g_free(s->db_clock_reset);
+}
+
+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),
+    /* Daughterboard power supply voltages (as reported via SYS_CFG) */
+    DEFINE_PROP_ARRAY("db-voltage", arm_sysctl_state, db_num_vsensors,
+                      db_voltage, qdev_prop_uint32, uint32_t),
+    /* Daughterboard clock reset values (as reported via SYS_CFG) */
+    DEFINE_PROP_ARRAY("db-clock", arm_sysctl_state, db_num_clocks,
+                      db_clock_reset, qdev_prop_uint32, uint32_t),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void arm_sysctl_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->realize = arm_sysctl_realize;
+    dc->reset = arm_sysctl_reset;
+    dc->vmsd = &vmstate_arm_sysctl;
+    dc->props = arm_sysctl_properties;
+}
+
+static const TypeInfo arm_sysctl_info = {
+    .name          = "realview_sysctl",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(arm_sysctl_state),
+    .instance_init = arm_sysctl_init,
+    .instance_finalize = arm_sysctl_finalize,
+    .class_init    = arm_sysctl_class_init,
+};
+
+static void arm_sysctl_register_types(void)
+{
+    type_register_static(&arm_sysctl_info);
+}
+
+type_init(arm_sysctl_register_types)
diff --git a/hw/misc/cbus.c b/hw/misc/cbus.c
new file mode 100644 (file)
index 0000000..3d9027f
--- /dev/null
@@ -0,0 +1,618 @@
+/*
+ * CBUS three-pin bus and the Retu / Betty / Tahvo / Vilma / Avilma /
+ * Hinku / Vinku / Ahne / Pihi chips used in various Nokia platforms.
+ * Based on reverse-engineering of a linux driver.
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ * Written by Andrzej Zaborowski <andrew@openedhand.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 or
+ * (at your option) version 3 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
+ * 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 "hw/irq.h"
+#include "hw/arm/devices.h"
+#include "sysemu/sysemu.h"
+
+//#define DEBUG
+
+typedef struct {
+    void *opaque;
+    void (*io)(void *opaque, int rw, int reg, uint16_t *val);
+    int addr;
+} CBusSlave;
+
+typedef struct {
+    CBus cbus;
+
+    int sel;
+    int dat;
+    int clk;
+    int bit;
+    int dir;
+    uint16_t val;
+    qemu_irq dat_out;
+
+    int addr;
+    int reg;
+    int rw;
+    enum {
+        cbus_address,
+        cbus_value,
+    } cycle;
+
+    CBusSlave *slave[8];
+} CBusPriv;
+
+static void cbus_io(CBusPriv *s)
+{
+    if (s->slave[s->addr])
+        s->slave[s->addr]->io(s->slave[s->addr]->opaque,
+                        s->rw, s->reg, &s->val);
+    else
+        hw_error("%s: bad slave address %i\n", __FUNCTION__, s->addr);
+}
+
+static void cbus_cycle(CBusPriv *s)
+{
+    switch (s->cycle) {
+    case cbus_address:
+        s->addr = (s->val >> 6) & 7;
+        s->rw =   (s->val >> 5) & 1;
+        s->reg =  (s->val >> 0) & 0x1f;
+
+        s->cycle = cbus_value;
+        s->bit = 15;
+        s->dir = !s->rw;
+        s->val = 0;
+
+        if (s->rw)
+            cbus_io(s);
+        break;
+
+    case cbus_value:
+        if (!s->rw)
+            cbus_io(s);
+
+        s->cycle = cbus_address;
+        s->bit = 8;
+        s->dir = 1;
+        s->val = 0;
+        break;
+    }
+}
+
+static void cbus_clk(void *opaque, int line, int level)
+{
+    CBusPriv *s = (CBusPriv *) opaque;
+
+    if (!s->sel && level && !s->clk) {
+        if (s->dir)
+            s->val |= s->dat << (s->bit --);
+        else
+            qemu_set_irq(s->dat_out, (s->val >> (s->bit --)) & 1);
+
+        if (s->bit < 0)
+            cbus_cycle(s);
+    }
+
+    s->clk = level;
+}
+
+static void cbus_dat(void *opaque, int line, int level)
+{
+    CBusPriv *s = (CBusPriv *) opaque;
+
+    s->dat = level;
+}
+
+static void cbus_sel(void *opaque, int line, int level)
+{
+    CBusPriv *s = (CBusPriv *) opaque;
+
+    if (!level) {
+        s->dir = 1;
+        s->bit = 8;
+        s->val = 0;
+    }
+
+    s->sel = level;
+}
+
+CBus *cbus_init(qemu_irq dat)
+{
+    CBusPriv *s = (CBusPriv *) g_malloc0(sizeof(*s));
+
+    s->dat_out = dat;
+    s->cbus.clk = qemu_allocate_irqs(cbus_clk, s, 1)[0];
+    s->cbus.dat = qemu_allocate_irqs(cbus_dat, s, 1)[0];
+    s->cbus.sel = qemu_allocate_irqs(cbus_sel, s, 1)[0];
+
+    s->sel = 1;
+    s->clk = 0;
+    s->dat = 0;
+
+    return &s->cbus;
+}
+
+void cbus_attach(CBus *bus, void *slave_opaque)
+{
+    CBusSlave *slave = (CBusSlave *) slave_opaque;
+    CBusPriv *s = (CBusPriv *) bus;
+
+    s->slave[slave->addr] = slave;
+}
+
+/* Retu/Vilma */
+typedef struct {
+    uint16_t irqst;
+    uint16_t irqen;
+    uint16_t cc[2];
+    int channel;
+    uint16_t result[16];
+    uint16_t sample;
+    uint16_t status;
+
+    struct {
+        uint16_t cal;
+    } rtc;
+
+    int is_vilma;
+    qemu_irq irq;
+    CBusSlave cbus;
+} CBusRetu;
+
+static void retu_interrupt_update(CBusRetu *s)
+{
+    qemu_set_irq(s->irq, s->irqst & ~s->irqen);
+}
+
+#define RETU_REG_ASICR         0x00    /* (RO) ASIC ID & revision */
+#define RETU_REG_IDR           0x01    /* (T)  Interrupt ID */
+#define RETU_REG_IMR           0x02    /* (RW) Interrupt mask */
+#define RETU_REG_RTCDSR                0x03    /* (RW) RTC seconds register */
+#define RETU_REG_RTCHMR                0x04    /* (RO) RTC hours and minutes reg */
+#define RETU_REG_RTCHMAR       0x05    /* (RW) RTC hours and minutes set reg */
+#define RETU_REG_RTCCALR       0x06    /* (RW) RTC calibration register */
+#define RETU_REG_ADCR          0x08    /* (RW) ADC result register */
+#define RETU_REG_ADCSCR                0x09    /* (RW) ADC sample control register */
+#define RETU_REG_AFCR          0x0a    /* (RW) AFC register */
+#define RETU_REG_ANTIFR                0x0b    /* (RW) AntiF register */
+#define RETU_REG_CALIBR                0x0c    /* (RW) CalibR register*/
+#define RETU_REG_CCR1          0x0d    /* (RW) Common control register 1 */
+#define RETU_REG_CCR2          0x0e    /* (RW) Common control register 2 */
+#define RETU_REG_RCTRL_CLR     0x0f    /* (T)  Regulator clear register */
+#define RETU_REG_RCTRL_SET     0x10    /* (T)  Regulator set register */
+#define RETU_REG_TXCR          0x11    /* (RW) TxC register */
+#define RETU_REG_STATUS                0x16    /* (RO) Status register */
+#define RETU_REG_WATCHDOG      0x17    /* (RW) Watchdog register */
+#define RETU_REG_AUDTXR                0x18    /* (RW) Audio Codec Tx register */
+#define RETU_REG_AUDPAR                0x19    /* (RW) AudioPA register */
+#define RETU_REG_AUDRXR1       0x1a    /* (RW) Audio receive register 1 */
+#define RETU_REG_AUDRXR2       0x1b    /* (RW) Audio receive register 2 */
+#define RETU_REG_SGR1          0x1c    /* (RW) */
+#define RETU_REG_SCR1          0x1d    /* (RW) */
+#define RETU_REG_SGR2          0x1e    /* (RW) */
+#define RETU_REG_SCR2          0x1f    /* (RW) */
+
+/* Retu Interrupt sources */
+enum {
+    retu_int_pwr       = 0,    /* Power button */
+    retu_int_char      = 1,    /* Charger */
+    retu_int_rtcs      = 2,    /* Seconds */
+    retu_int_rtcm      = 3,    /* Minutes */
+    retu_int_rtcd      = 4,    /* Days */
+    retu_int_rtca      = 5,    /* Alarm */
+    retu_int_hook      = 6,    /* Hook */
+    retu_int_head      = 7,    /* Headset */
+    retu_int_adcs      = 8,    /* ADC sample */
+};
+
+/* Retu ADC channel wiring */
+enum {
+    retu_adc_bsi       = 1,    /* BSI */
+    retu_adc_batt_temp = 2,    /* Battery temperature */
+    retu_adc_chg_volt  = 3,    /* Charger voltage */
+    retu_adc_head_det  = 4,    /* Headset detection */
+    retu_adc_hook_det  = 5,    /* Hook detection */
+    retu_adc_rf_gp     = 6,    /* RF GP */
+    retu_adc_tx_det    = 7,    /* Wideband Tx detection */
+    retu_adc_batt_volt = 8,    /* Battery voltage */
+    retu_adc_sens      = 10,   /* Light sensor */
+    retu_adc_sens_temp = 11,   /* Light sensor temperature */
+    retu_adc_bbatt_volt        = 12,   /* Backup battery voltage */
+    retu_adc_self_temp = 13,   /* RETU temperature */
+};
+
+static inline uint16_t retu_read(CBusRetu *s, int reg)
+{
+#ifdef DEBUG
+    printf("RETU read at %02x\n", reg);
+#endif
+
+    switch (reg) {
+    case RETU_REG_ASICR:
+        return 0x0215 | (s->is_vilma << 7);
+
+    case RETU_REG_IDR: /* TODO: Or is this ffs(s->irqst)?  */
+        return s->irqst;
+
+    case RETU_REG_IMR:
+        return s->irqen;
+
+    case RETU_REG_RTCDSR:
+    case RETU_REG_RTCHMR:
+    case RETU_REG_RTCHMAR:
+        /* TODO */
+        return 0x0000;
+
+    case RETU_REG_RTCCALR:
+        return s->rtc.cal;
+
+    case RETU_REG_ADCR:
+        return (s->channel << 10) | s->result[s->channel];
+    case RETU_REG_ADCSCR:
+        return s->sample;
+
+    case RETU_REG_AFCR:
+    case RETU_REG_ANTIFR:
+    case RETU_REG_CALIBR:
+        /* TODO */
+        return 0x0000;
+
+    case RETU_REG_CCR1:
+        return s->cc[0];
+    case RETU_REG_CCR2:
+        return s->cc[1];
+
+    case RETU_REG_RCTRL_CLR:
+    case RETU_REG_RCTRL_SET:
+    case RETU_REG_TXCR:
+        /* TODO */
+        return 0x0000;
+
+    case RETU_REG_STATUS:
+        return s->status;
+
+    case RETU_REG_WATCHDOG:
+    case RETU_REG_AUDTXR:
+    case RETU_REG_AUDPAR:
+    case RETU_REG_AUDRXR1:
+    case RETU_REG_AUDRXR2:
+    case RETU_REG_SGR1:
+    case RETU_REG_SCR1:
+    case RETU_REG_SGR2:
+    case RETU_REG_SCR2:
+        /* TODO */
+        return 0x0000;
+
+    default:
+        hw_error("%s: bad register %02x\n", __FUNCTION__, reg);
+    }
+}
+
+static inline void retu_write(CBusRetu *s, int reg, uint16_t val)
+{
+#ifdef DEBUG
+    printf("RETU write of %04x at %02x\n", val, reg);
+#endif
+
+    switch (reg) {
+    case RETU_REG_IDR:
+        s->irqst ^= val;
+        retu_interrupt_update(s);
+        break;
+
+    case RETU_REG_IMR:
+        s->irqen = val;
+        retu_interrupt_update(s);
+        break;
+
+    case RETU_REG_RTCDSR:
+    case RETU_REG_RTCHMAR:
+        /* TODO */
+        break;
+
+    case RETU_REG_RTCCALR:
+        s->rtc.cal = val;
+        break;
+
+    case RETU_REG_ADCR:
+        s->channel = (val >> 10) & 0xf;
+        s->irqst |= 1 << retu_int_adcs;
+        retu_interrupt_update(s);
+        break;
+    case RETU_REG_ADCSCR:
+        s->sample &= ~val;
+        break;
+
+    case RETU_REG_AFCR:
+    case RETU_REG_ANTIFR:
+    case RETU_REG_CALIBR:
+
+    case RETU_REG_CCR1:
+        s->cc[0] = val;
+        break;
+    case RETU_REG_CCR2:
+        s->cc[1] = val;
+        break;
+
+    case RETU_REG_RCTRL_CLR:
+    case RETU_REG_RCTRL_SET:
+        /* TODO */
+        break;
+
+    case RETU_REG_WATCHDOG:
+        if (val == 0 && (s->cc[0] & 2))
+            qemu_system_shutdown_request();
+        break;
+
+    case RETU_REG_TXCR:
+    case RETU_REG_AUDTXR:
+    case RETU_REG_AUDPAR:
+    case RETU_REG_AUDRXR1:
+    case RETU_REG_AUDRXR2:
+    case RETU_REG_SGR1:
+    case RETU_REG_SCR1:
+    case RETU_REG_SGR2:
+    case RETU_REG_SCR2:
+        /* TODO */
+        break;
+
+    default:
+        hw_error("%s: bad register %02x\n", __FUNCTION__, reg);
+    }
+}
+
+static void retu_io(void *opaque, int rw, int reg, uint16_t *val)
+{
+    CBusRetu *s = (CBusRetu *) opaque;
+
+    if (rw)
+        *val = retu_read(s, reg);
+    else
+        retu_write(s, reg, *val);
+}
+
+void *retu_init(qemu_irq irq, int vilma)
+{
+    CBusRetu *s = (CBusRetu *) g_malloc0(sizeof(*s));
+
+    s->irq = irq;
+    s->irqen = 0xffff;
+    s->irqst = 0x0000;
+    s->status = 0x0020;
+    s->is_vilma = !!vilma;
+    s->rtc.cal = 0x01;
+    s->result[retu_adc_bsi] = 0x3c2;
+    s->result[retu_adc_batt_temp] = 0x0fc;
+    s->result[retu_adc_chg_volt] = 0x165;
+    s->result[retu_adc_head_det] = 123;
+    s->result[retu_adc_hook_det] = 1023;
+    s->result[retu_adc_rf_gp] = 0x11;
+    s->result[retu_adc_tx_det] = 0x11;
+    s->result[retu_adc_batt_volt] = 0x250;
+    s->result[retu_adc_sens] = 2;
+    s->result[retu_adc_sens_temp] = 0x11;
+    s->result[retu_adc_bbatt_volt] = 0x3d0;
+    s->result[retu_adc_self_temp] = 0x330;
+
+    s->cbus.opaque = s;
+    s->cbus.io = retu_io;
+    s->cbus.addr = 1;
+
+    return &s->cbus;
+}
+
+void retu_key_event(void *retu, int state)
+{
+    CBusSlave *slave = (CBusSlave *) retu;
+    CBusRetu *s = (CBusRetu *) slave->opaque;
+
+    s->irqst |= 1 << retu_int_pwr;
+    retu_interrupt_update(s);
+
+    if (state)
+        s->status &= ~(1 << 5);
+    else
+        s->status |= 1 << 5;
+}
+
+#if 0
+static void retu_head_event(void *retu, int state)
+{
+    CBusSlave *slave = (CBusSlave *) retu;
+    CBusRetu *s = (CBusRetu *) slave->opaque;
+
+    if ((s->cc[0] & 0x500) == 0x500) { /* TODO: Which bits? */
+        /* TODO: reissue the interrupt every 100ms or so.  */
+        s->irqst |= 1 << retu_int_head;
+        retu_interrupt_update(s);
+    }
+
+    if (state)
+        s->result[retu_adc_head_det] = 50;
+    else
+        s->result[retu_adc_head_det] = 123;
+}
+
+static void retu_hook_event(void *retu, int state)
+{
+    CBusSlave *slave = (CBusSlave *) retu;
+    CBusRetu *s = (CBusRetu *) slave->opaque;
+
+    if ((s->cc[0] & 0x500) == 0x500) {
+        /* TODO: reissue the interrupt every 100ms or so.  */
+        s->irqst |= 1 << retu_int_hook;
+        retu_interrupt_update(s);
+    }
+
+    if (state)
+        s->result[retu_adc_hook_det] = 50;
+    else
+        s->result[retu_adc_hook_det] = 123;
+}
+#endif
+
+/* Tahvo/Betty */
+typedef struct {
+    uint16_t irqst;
+    uint16_t irqen;
+    uint8_t charger;
+    uint8_t backlight;
+    uint16_t usbr;
+    uint16_t power;
+
+    int is_betty;
+    qemu_irq irq;
+    CBusSlave cbus;
+} CBusTahvo;
+
+static void tahvo_interrupt_update(CBusTahvo *s)
+{
+    qemu_set_irq(s->irq, s->irqst & ~s->irqen);
+}
+
+#define TAHVO_REG_ASICR                0x00    /* (RO) ASIC ID & revision */
+#define TAHVO_REG_IDR          0x01    /* (T)  Interrupt ID */
+#define TAHVO_REG_IDSR         0x02    /* (RO) Interrupt status */
+#define TAHVO_REG_IMR          0x03    /* (RW) Interrupt mask */
+#define TAHVO_REG_CHAPWMR      0x04    /* (RW) Charger PWM */
+#define TAHVO_REG_LEDPWMR      0x05    /* (RW) LED PWM */
+#define TAHVO_REG_USBR         0x06    /* (RW) USB control */
+#define TAHVO_REG_RCR          0x07    /* (RW) Some kind of power management */
+#define TAHVO_REG_CCR1         0x08    /* (RW) Common control register 1 */
+#define TAHVO_REG_CCR2         0x09    /* (RW) Common control register 2 */
+#define TAHVO_REG_TESTR1       0x0a    /* (RW) Test register 1 */
+#define TAHVO_REG_TESTR2       0x0b    /* (RW) Test register 2 */
+#define TAHVO_REG_NOPR         0x0c    /* (RW) Number of periods */
+#define TAHVO_REG_FRR          0x0d    /* (RO) FR */
+
+static inline uint16_t tahvo_read(CBusTahvo *s, int reg)
+{
+#ifdef DEBUG
+    printf("TAHVO read at %02x\n", reg);
+#endif
+
+    switch (reg) {
+    case TAHVO_REG_ASICR:
+        return 0x0021 | (s->is_betty ? 0x0b00 : 0x0300);       /* 22 in N810 */
+
+    case TAHVO_REG_IDR:
+    case TAHVO_REG_IDSR:       /* XXX: what does this do?  */
+        return s->irqst;
+
+    case TAHVO_REG_IMR:
+        return s->irqen;
+
+    case TAHVO_REG_CHAPWMR:
+        return s->charger;
+
+    case TAHVO_REG_LEDPWMR:
+        return s->backlight;
+
+    case TAHVO_REG_USBR:
+        return s->usbr;
+
+    case TAHVO_REG_RCR:
+        return s->power;
+
+    case TAHVO_REG_CCR1:
+    case TAHVO_REG_CCR2:
+    case TAHVO_REG_TESTR1:
+    case TAHVO_REG_TESTR2:
+    case TAHVO_REG_NOPR:
+    case TAHVO_REG_FRR:
+        return 0x0000;
+
+    default:
+        hw_error("%s: bad register %02x\n", __FUNCTION__, reg);
+    }
+}
+
+static inline void tahvo_write(CBusTahvo *s, int reg, uint16_t val)
+{
+#ifdef DEBUG
+    printf("TAHVO write of %04x at %02x\n", val, reg);
+#endif
+
+    switch (reg) {
+    case TAHVO_REG_IDR:
+        s->irqst ^= val;
+        tahvo_interrupt_update(s);
+        break;
+
+    case TAHVO_REG_IMR:
+        s->irqen = val;
+        tahvo_interrupt_update(s);
+        break;
+
+    case TAHVO_REG_CHAPWMR:
+        s->charger = val;
+        break;
+
+    case TAHVO_REG_LEDPWMR:
+        if (s->backlight != (val & 0x7f)) {
+            s->backlight = val & 0x7f;
+            printf("%s: LCD backlight now at %i / 127\n",
+                            __FUNCTION__, s->backlight);
+        }
+        break;
+
+    case TAHVO_REG_USBR:
+        s->usbr = val;
+        break;
+
+    case TAHVO_REG_RCR:
+        s->power = val;
+        break;
+
+    case TAHVO_REG_CCR1:
+    case TAHVO_REG_CCR2:
+    case TAHVO_REG_TESTR1:
+    case TAHVO_REG_TESTR2:
+    case TAHVO_REG_NOPR:
+    case TAHVO_REG_FRR:
+        break;
+
+    default:
+        hw_error("%s: bad register %02x\n", __FUNCTION__, reg);
+    }
+}
+
+static void tahvo_io(void *opaque, int rw, int reg, uint16_t *val)
+{
+    CBusTahvo *s = (CBusTahvo *) opaque;
+
+    if (rw)
+        *val = tahvo_read(s, reg);
+    else
+        tahvo_write(s, reg, *val);
+}
+
+void *tahvo_init(qemu_irq irq, int betty)
+{
+    CBusTahvo *s = (CBusTahvo *) g_malloc0(sizeof(*s));
+
+    s->irq = irq;
+    s->irqen = 0xffff;
+    s->irqst = 0x0000;
+    s->is_betty = !!betty;
+
+    s->cbus.opaque = s;
+    s->cbus.io = tahvo_io;
+    s->cbus.addr = 2;
+
+    return &s->cbus;
+}
diff --git a/hw/misc/debugexit.c b/hw/misc/debugexit.c
new file mode 100644 (file)
index 0000000..59bed5b
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * debug exit port emulation
+ *
+ * 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 or
+ * (at your option) any later version.
+ */
+
+#include "hw/hw.h"
+#include "hw/isa/isa.h"
+
+#define TYPE_ISA_DEBUG_EXIT_DEVICE "isa-debug-exit"
+#define ISA_DEBUG_EXIT_DEVICE(obj) \
+     OBJECT_CHECK(ISADebugExitState, (obj), TYPE_ISA_DEBUG_EXIT_DEVICE)
+
+typedef struct ISADebugExitState {
+    ISADevice parent_obj;
+
+    uint32_t iobase;
+    uint32_t iosize;
+    MemoryRegion io;
+} ISADebugExitState;
+
+static void debug_exit_write(void *opaque, hwaddr addr, uint64_t val,
+                             unsigned width)
+{
+    exit((val << 1) | 1);
+}
+
+static const MemoryRegionOps debug_exit_ops = {
+    .write = debug_exit_write,
+    .valid.min_access_size = 1,
+    .valid.max_access_size = 4,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static int debug_exit_initfn(ISADevice *dev)
+{
+    ISADebugExitState *isa = ISA_DEBUG_EXIT_DEVICE(dev);
+
+    memory_region_init_io(&isa->io, &debug_exit_ops, isa,
+                          TYPE_ISA_DEBUG_EXIT_DEVICE, isa->iosize);
+    memory_region_add_subregion(isa_address_space_io(dev),
+                                isa->iobase, &isa->io);
+    return 0;
+}
+
+static Property debug_exit_properties[] = {
+    DEFINE_PROP_HEX32("iobase", ISADebugExitState, iobase, 0x501),
+    DEFINE_PROP_HEX32("iosize", ISADebugExitState, iosize, 0x02),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void debug_exit_class_initfn(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+    ic->init = debug_exit_initfn;
+    dc->props = debug_exit_properties;
+}
+
+static const TypeInfo debug_exit_info = {
+    .name          = TYPE_ISA_DEBUG_EXIT_DEVICE,
+    .parent        = TYPE_ISA_DEVICE,
+    .instance_size = sizeof(ISADebugExitState),
+    .class_init    = debug_exit_class_initfn,
+};
+
+static void debug_exit_register_types(void)
+{
+    type_register_static(&debug_exit_info);
+}
+
+type_init(debug_exit_register_types)
diff --git a/hw/misc/eccmemctl.c b/hw/misc/eccmemctl.c
new file mode 100644 (file)
index 0000000..6f4a407
--- /dev/null
@@ -0,0 +1,340 @@
+/*
+ * QEMU Sparc Sun4m ECC memory controller emulation
+ *
+ * Copyright (c) 2007 Robert Reif
+ *
+ * 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 "hw/sysbus.h"
+#include "trace.h"
+
+/* There are 3 versions of this chip used in SMP sun4m systems:
+ * MCC (version 0, implementation 0) SS-600MP
+ * EMC (version 0, implementation 1) SS-10
+ * SMC (version 0, implementation 2) SS-10SX and SS-20
+ *
+ * Chipset docs:
+ * "Sun-4M System Architecture (revision 2.0) by Chuck Narad", 950-1373-01,
+ * http://mediacast.sun.com/users/Barton808/media/Sun4M_SystemArchitecture_edited2.pdf
+ */
+
+#define ECC_MCC        0x00000000
+#define ECC_EMC        0x10000000
+#define ECC_SMC        0x20000000
+
+/* Register indexes */
+#define ECC_MER        0               /* Memory Enable Register */
+#define ECC_MDR        1               /* Memory Delay Register */
+#define ECC_MFSR       2               /* Memory Fault Status Register */
+#define ECC_VCR        3               /* Video Configuration Register */
+#define ECC_MFAR0      4               /* Memory Fault Address Register 0 */
+#define ECC_MFAR1      5               /* Memory Fault Address Register 1 */
+#define ECC_DR         6               /* Diagnostic Register */
+#define ECC_ECR0       7               /* Event Count Register 0 */
+#define ECC_ECR1       8               /* Event Count Register 1 */
+
+/* ECC fault control register */
+#define ECC_MER_EE     0x00000001      /* Enable ECC checking */
+#define ECC_MER_EI     0x00000002      /* Enable Interrupts on
+                                          correctable errors */
+#define ECC_MER_MRR0   0x00000004      /* SIMM 0 */
+#define ECC_MER_MRR1   0x00000008      /* SIMM 1 */
+#define ECC_MER_MRR2   0x00000010      /* SIMM 2 */
+#define ECC_MER_MRR3   0x00000020      /* SIMM 3 */
+#define ECC_MER_MRR4   0x00000040      /* SIMM 4 */
+#define ECC_MER_MRR5   0x00000080      /* SIMM 5 */
+#define ECC_MER_MRR6   0x00000100      /* SIMM 6 */
+#define ECC_MER_MRR7   0x00000200      /* SIMM 7 */
+#define ECC_MER_REU    0x00000100      /* Memory Refresh Enable (600MP) */
+#define ECC_MER_MRR    0x000003fc      /* MRR mask */
+#define ECC_MER_A      0x00000400      /* Memory controller addr map select */
+#define ECC_MER_DCI    0x00000800      /* Disables Coherent Invalidate ACK */
+#define ECC_MER_VER    0x0f000000      /* Version */
+#define ECC_MER_IMPL   0xf0000000      /* Implementation */
+#define ECC_MER_MASK_0 0x00000103      /* Version 0 (MCC) mask */
+#define ECC_MER_MASK_1 0x00000bff      /* Version 1 (EMC) mask */
+#define ECC_MER_MASK_2 0x00000bff      /* Version 2 (SMC) mask */
+
+/* ECC memory delay register */
+#define ECC_MDR_RRI    0x000003ff      /* Refresh Request Interval */
+#define ECC_MDR_MI     0x00001c00      /* MIH Delay */
+#define ECC_MDR_CI     0x0000e000      /* Coherent Invalidate Delay */
+#define ECC_MDR_MDL    0x001f0000      /* MBus Master arbitration delay */
+#define ECC_MDR_MDH    0x03e00000      /* MBus Master arbitration delay */
+#define ECC_MDR_GAD    0x7c000000      /* Graphics Arbitration Delay */
+#define ECC_MDR_RSC    0x80000000      /* Refresh load control */
+#define ECC_MDR_MASK   0x7fffffff
+
+/* ECC fault status register */
+#define ECC_MFSR_CE    0x00000001      /* Correctable error */
+#define ECC_MFSR_BS    0x00000002      /* C2 graphics bad slot access */
+#define ECC_MFSR_TO    0x00000004      /* Timeout on write */
+#define ECC_MFSR_UE    0x00000008      /* Uncorrectable error */
+#define ECC_MFSR_DW    0x000000f0      /* Index of double word in block */
+#define ECC_MFSR_SYND  0x0000ff00      /* Syndrome for correctable error */
+#define ECC_MFSR_ME    0x00010000      /* Multiple errors */
+#define ECC_MFSR_C2ERR 0x00020000      /* C2 graphics error */
+
+/* ECC fault address register 0 */
+#define ECC_MFAR0_PADDR 0x0000000f     /* PA[32-35] */
+#define ECC_MFAR0_TYPE  0x000000f0     /* Transaction type */
+#define ECC_MFAR0_SIZE  0x00000700     /* Transaction size */
+#define ECC_MFAR0_CACHE 0x00000800     /* Mapped cacheable */
+#define ECC_MFAR0_LOCK  0x00001000     /* Error occurred in atomic cycle */
+#define ECC_MFAR0_BMODE 0x00002000     /* Boot mode */
+#define ECC_MFAR0_VADDR 0x003fc000     /* VA[12-19] (superset bits) */
+#define ECC_MFAR0_S     0x08000000     /* Supervisor mode */
+#define ECC_MFARO_MID   0xf0000000     /* Module ID */
+
+/* ECC diagnostic register */
+#define ECC_DR_CBX     0x00000001
+#define ECC_DR_CB0     0x00000002
+#define ECC_DR_CB1     0x00000004
+#define ECC_DR_CB2     0x00000008
+#define ECC_DR_CB4     0x00000010
+#define ECC_DR_CB8     0x00000020
+#define ECC_DR_CB16    0x00000040
+#define ECC_DR_CB32    0x00000080
+#define ECC_DR_DMODE   0x00000c00
+
+#define ECC_NREGS      9
+#define ECC_SIZE       (ECC_NREGS * sizeof(uint32_t))
+
+#define ECC_DIAG_SIZE  4
+#define ECC_DIAG_MASK  (ECC_DIAG_SIZE - 1)
+
+typedef struct ECCState {
+    SysBusDevice busdev;
+    MemoryRegion iomem, iomem_diag;
+    qemu_irq irq;
+    uint32_t regs[ECC_NREGS];
+    uint8_t diag[ECC_DIAG_SIZE];
+    uint32_t version;
+} ECCState;
+
+static void ecc_mem_write(void *opaque, hwaddr addr, uint64_t val,
+                          unsigned size)
+{
+    ECCState *s = opaque;
+
+    switch (addr >> 2) {
+    case ECC_MER:
+        if (s->version == ECC_MCC)
+            s->regs[ECC_MER] = (val & ECC_MER_MASK_0);
+        else if (s->version == ECC_EMC)
+            s->regs[ECC_MER] = s->version | (val & ECC_MER_MASK_1);
+        else if (s->version == ECC_SMC)
+            s->regs[ECC_MER] = s->version | (val & ECC_MER_MASK_2);
+        trace_ecc_mem_writel_mer(val);
+        break;
+    case ECC_MDR:
+        s->regs[ECC_MDR] =  val & ECC_MDR_MASK;
+        trace_ecc_mem_writel_mdr(val);
+        break;
+    case ECC_MFSR:
+        s->regs[ECC_MFSR] =  val;
+        qemu_irq_lower(s->irq);
+        trace_ecc_mem_writel_mfsr(val);
+        break;
+    case ECC_VCR:
+        s->regs[ECC_VCR] =  val;
+        trace_ecc_mem_writel_vcr(val);
+        break;
+    case ECC_DR:
+        s->regs[ECC_DR] =  val;
+        trace_ecc_mem_writel_dr(val);
+        break;
+    case ECC_ECR0:
+        s->regs[ECC_ECR0] =  val;
+        trace_ecc_mem_writel_ecr0(val);
+        break;
+    case ECC_ECR1:
+        s->regs[ECC_ECR0] =  val;
+        trace_ecc_mem_writel_ecr1(val);
+        break;
+    }
+}
+
+static uint64_t ecc_mem_read(void *opaque, hwaddr addr,
+                             unsigned size)
+{
+    ECCState *s = opaque;
+    uint32_t ret = 0;
+
+    switch (addr >> 2) {
+    case ECC_MER:
+        ret = s->regs[ECC_MER];
+        trace_ecc_mem_readl_mer(ret);
+        break;
+    case ECC_MDR:
+        ret = s->regs[ECC_MDR];
+        trace_ecc_mem_readl_mdr(ret);
+        break;
+    case ECC_MFSR:
+        ret = s->regs[ECC_MFSR];
+        trace_ecc_mem_readl_mfsr(ret);
+        break;
+    case ECC_VCR:
+        ret = s->regs[ECC_VCR];
+        trace_ecc_mem_readl_vcr(ret);
+        break;
+    case ECC_MFAR0:
+        ret = s->regs[ECC_MFAR0];
+        trace_ecc_mem_readl_mfar0(ret);
+        break;
+    case ECC_MFAR1:
+        ret = s->regs[ECC_MFAR1];
+        trace_ecc_mem_readl_mfar1(ret);
+        break;
+    case ECC_DR:
+        ret = s->regs[ECC_DR];
+        trace_ecc_mem_readl_dr(ret);
+        break;
+    case ECC_ECR0:
+        ret = s->regs[ECC_ECR0];
+        trace_ecc_mem_readl_ecr0(ret);
+        break;
+    case ECC_ECR1:
+        ret = s->regs[ECC_ECR0];
+        trace_ecc_mem_readl_ecr1(ret);
+        break;
+    }
+    return ret;
+}
+
+static const MemoryRegionOps ecc_mem_ops = {
+    .read = ecc_mem_read,
+    .write = ecc_mem_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static void ecc_diag_mem_write(void *opaque, hwaddr addr,
+                               uint64_t val, unsigned size)
+{
+    ECCState *s = opaque;
+
+    trace_ecc_diag_mem_writeb(addr, val);
+    s->diag[addr & ECC_DIAG_MASK] = val;
+}
+
+static uint64_t ecc_diag_mem_read(void *opaque, hwaddr addr,
+                                  unsigned size)
+{
+    ECCState *s = opaque;
+    uint32_t ret = s->diag[(int)addr];
+
+    trace_ecc_diag_mem_readb(addr, ret);
+    return ret;
+}
+
+static const MemoryRegionOps ecc_diag_mem_ops = {
+    .read = ecc_diag_mem_read,
+    .write = ecc_diag_mem_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+};
+
+static const VMStateDescription vmstate_ecc = {
+    .name ="ECC",
+    .version_id = 3,
+    .minimum_version_id = 3,
+    .minimum_version_id_old = 3,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT32_ARRAY(regs, ECCState, ECC_NREGS),
+        VMSTATE_BUFFER(diag, ECCState),
+        VMSTATE_UINT32(version, ECCState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void ecc_reset(DeviceState *d)
+{
+    ECCState *s = container_of(d, ECCState, busdev.qdev);
+
+    if (s->version == ECC_MCC)
+        s->regs[ECC_MER] &= ECC_MER_REU;
+    else
+        s->regs[ECC_MER] &= (ECC_MER_VER | ECC_MER_IMPL | ECC_MER_MRR |
+                             ECC_MER_DCI);
+    s->regs[ECC_MDR] = 0x20;
+    s->regs[ECC_MFSR] = 0;
+    s->regs[ECC_VCR] = 0;
+    s->regs[ECC_MFAR0] = 0x07c00000;
+    s->regs[ECC_MFAR1] = 0;
+    s->regs[ECC_DR] = 0;
+    s->regs[ECC_ECR0] = 0;
+    s->regs[ECC_ECR1] = 0;
+}
+
+static int ecc_init1(SysBusDevice *dev)
+{
+    ECCState *s = FROM_SYSBUS(ECCState, dev);
+
+    sysbus_init_irq(dev, &s->irq);
+    s->regs[0] = s->version;
+    memory_region_init_io(&s->iomem, &ecc_mem_ops, s, "ecc", ECC_SIZE);
+    sysbus_init_mmio(dev, &s->iomem);
+
+    if (s->version == ECC_MCC) { // SS-600MP only
+        memory_region_init_io(&s->iomem_diag, &ecc_diag_mem_ops, s,
+                              "ecc.diag", ECC_DIAG_SIZE);
+        sysbus_init_mmio(dev, &s->iomem_diag);
+    }
+
+    return 0;
+}
+
+static Property ecc_properties[] = {
+    DEFINE_PROP_HEX32("version", ECCState, version, -1),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void ecc_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = ecc_init1;
+    dc->reset = ecc_reset;
+    dc->vmsd = &vmstate_ecc;
+    dc->props = ecc_properties;
+}
+
+static const TypeInfo ecc_info = {
+    .name          = "eccmemctl",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(ECCState),
+    .class_init    = ecc_class_init,
+};
+
+
+static void ecc_register_types(void)
+{
+    type_register_static(&ecc_info);
+}
+
+type_init(ecc_register_types)
diff --git a/hw/misc/exynos4210_pmu.c b/hw/misc/exynos4210_pmu.c
new file mode 100644 (file)
index 0000000..ba5aa8d
--- /dev/null
@@ -0,0 +1,499 @@
+/*
+ *  Exynos4210 Power Management Unit (PMU) Emulation
+ *
+ *  Copyright (C) 2011 Samsung Electronics Co Ltd.
+ *    Maksim Kozlov <m.kozlov@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 "hw/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, hwaddr 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, hwaddr 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 const 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)
diff --git a/hw/misc/imx_ccm.c b/hw/misc/imx_ccm.c
new file mode 100644 (file)
index 0000000..c153a24
--- /dev/null
@@ -0,0 +1,321 @@
+/*
+ * IMX31 Clock Control Module
+ *
+ * Copyright (C) 2012 NICTA
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ * To get the timer frequencies right, we need to emulate at least part of
+ * the CCM.
+ */
+
+#include "hw/hw.h"
+#include "hw/sysbus.h"
+#include "sysemu/sysemu.h"
+#include "hw/arm/imx.h"
+
+#define CKIH_FREQ 26000000 /* 26MHz crystal input */
+#define CKIL_FREQ    32768 /* nominal 32khz clock */
+
+
+//#define DEBUG_CCM 1
+#ifdef DEBUG_CCM
+#define DPRINTF(fmt, args...) \
+do { printf("imx_ccm: " fmt , ##args); } while (0)
+#else
+#define DPRINTF(fmt, args...) do {} while (0)
+#endif
+
+static int imx_ccm_post_load(void *opaque, int version_id);
+
+typedef struct {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+
+    uint32_t ccmr;
+    uint32_t pdr0;
+    uint32_t pdr1;
+    uint32_t mpctl;
+    uint32_t spctl;
+    uint32_t cgr[3];
+    uint32_t pmcr0;
+    uint32_t pmcr1;
+
+    /* Frequencies precalculated on register changes */
+    uint32_t pll_refclk_freq;
+    uint32_t mcu_clk_freq;
+    uint32_t hsp_clk_freq;
+    uint32_t ipg_clk_freq;
+} IMXCCMState;
+
+static const VMStateDescription vmstate_imx_ccm = {
+    .name = "imx-ccm",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(ccmr, IMXCCMState),
+        VMSTATE_UINT32(pdr0, IMXCCMState),
+        VMSTATE_UINT32(pdr1, IMXCCMState),
+        VMSTATE_UINT32(mpctl, IMXCCMState),
+        VMSTATE_UINT32(spctl, IMXCCMState),
+        VMSTATE_UINT32_ARRAY(cgr, IMXCCMState, 3),
+        VMSTATE_UINT32(pmcr0, IMXCCMState),
+        VMSTATE_UINT32(pmcr1, IMXCCMState),
+        VMSTATE_UINT32(pll_refclk_freq, IMXCCMState),
+    },
+    .post_load = imx_ccm_post_load,
+};
+
+/* CCMR */
+#define CCMR_FPME (1<<0)
+#define CCMR_MPE  (1<<3)
+#define CCMR_MDS  (1<<7)
+#define CCMR_FPMF (1<<26)
+#define CCMR_PRCS (3<<1)
+
+/* PDR0 */
+#define PDR0_MCU_PODF_SHIFT (0)
+#define PDR0_MCU_PODF_MASK (0x7)
+#define PDR0_MAX_PODF_SHIFT (3)
+#define PDR0_MAX_PODF_MASK (0x7)
+#define PDR0_IPG_PODF_SHIFT (6)
+#define PDR0_IPG_PODF_MASK (0x3)
+#define PDR0_NFC_PODF_SHIFT (8)
+#define PDR0_NFC_PODF_MASK (0x7)
+#define PDR0_HSP_PODF_SHIFT (11)
+#define PDR0_HSP_PODF_MASK (0x7)
+#define PDR0_PER_PODF_SHIFT (16)
+#define PDR0_PER_PODF_MASK (0x1f)
+#define PDR0_CSI_PODF_SHIFT (23)
+#define PDR0_CSI_PODF_MASK (0x1ff)
+
+#define EXTRACT(value, name) (((value) >> PDR0_##name##_PODF_SHIFT) \
+                              & PDR0_##name##_PODF_MASK)
+#define INSERT(value, name) (((value) & PDR0_##name##_PODF_MASK) << \
+                             PDR0_##name##_PODF_SHIFT)
+/* PLL control registers */
+#define PD(v) (((v) >> 26) & 0xf)
+#define MFD(v) (((v) >> 16) & 0x3ff)
+#define MFI(v) (((v) >> 10) & 0xf);
+#define MFN(v) ((v) & 0x3ff)
+
+#define PLL_PD(x)               (((x) & 0xf) << 26)
+#define PLL_MFD(x)              (((x) & 0x3ff) << 16)
+#define PLL_MFI(x)              (((x) & 0xf) << 10)
+#define PLL_MFN(x)              (((x) & 0x3ff) << 0)
+
+uint32_t imx_clock_frequency(DeviceState *dev, IMXClk clock)
+{
+    IMXCCMState *s = container_of(dev, IMXCCMState, busdev.qdev);
+
+    switch (clock) {
+    case NOCLK:
+        return 0;
+    case MCU:
+        return s->mcu_clk_freq;
+    case HSP:
+        return s->hsp_clk_freq;
+    case IPG:
+        return s->ipg_clk_freq;
+    case CLK_32k:
+        return CKIL_FREQ;
+    }
+    return 0;
+}
+
+/*
+ * Calculate PLL output frequency
+ */
+static uint32_t calc_pll(uint32_t pllreg, uint32_t base_freq)
+{
+    int32_t mfn = MFN(pllreg);  /* Numerator */
+    uint32_t mfi = MFI(pllreg); /* Integer part */
+    uint32_t mfd = 1 + MFD(pllreg); /* Denominator */
+    uint32_t pd = 1 + PD(pllreg);   /* Pre-divider */
+
+    if (mfi < 5) {
+        mfi = 5;
+    }
+    /* mfn is 10-bit signed twos-complement */
+    mfn <<= 32 - 10;
+    mfn >>= 32 - 10;
+
+    return ((2 * (base_freq >> 10) * (mfi * mfd + mfn)) /
+            (mfd * pd)) << 10;
+}
+
+static void update_clocks(IMXCCMState *s)
+{
+    /*
+     * If we ever emulate more clocks, this should switch to a data-driven
+     * approach
+     */
+
+    if ((s->ccmr & CCMR_PRCS) == 1) {
+        s->pll_refclk_freq = CKIL_FREQ * 1024;
+    } else {
+        s->pll_refclk_freq = CKIH_FREQ;
+    }
+
+    /* ipg_clk_arm aka MCU clock */
+    if ((s->ccmr & CCMR_MDS) || !(s->ccmr & CCMR_MPE)) {
+        s->mcu_clk_freq = s->pll_refclk_freq;
+    } else {
+        s->mcu_clk_freq = calc_pll(s->mpctl, s->pll_refclk_freq);
+    }
+
+    /* High-speed clock */
+    s->hsp_clk_freq = s->mcu_clk_freq / (1 + EXTRACT(s->pdr0, HSP));
+    s->ipg_clk_freq = s->hsp_clk_freq / (1 + EXTRACT(s->pdr0, IPG));
+
+    DPRINTF("Clocks: mcu %uMHz, HSP %uMHz, IPG %uHz\n",
+            s->mcu_clk_freq / 1000000,
+            s->hsp_clk_freq / 1000000,
+            s->ipg_clk_freq);
+}
+
+static void imx_ccm_reset(DeviceState *dev)
+{
+    IMXCCMState *s = container_of(dev, IMXCCMState, busdev.qdev);
+
+    s->ccmr = 0x074b0b7b;
+    s->pdr0 = 0xff870b48;
+    s->pdr1 = 0x49fcfe7f;
+    s->mpctl = PLL_PD(1) | PLL_MFD(0) | PLL_MFI(6) | PLL_MFN(0);
+    s->cgr[0] = s->cgr[1] = s->cgr[2] = 0xffffffff;
+    s->spctl = PLL_PD(1) | PLL_MFD(4) | PLL_MFI(0xc) | PLL_MFN(1);
+    s->pmcr0 = 0x80209828;
+
+    update_clocks(s);
+}
+
+static uint64_t imx_ccm_read(void *opaque, hwaddr offset,
+                                unsigned size)
+{
+    IMXCCMState *s = (IMXCCMState *)opaque;
+
+    DPRINTF("read(offset=%x)", offset >> 2);
+    switch (offset >> 2) {
+    case 0: /* CCMR */
+        DPRINTF(" ccmr = 0x%x\n", s->ccmr);
+        return s->ccmr;
+    case 1:
+        DPRINTF(" pdr0 = 0x%x\n", s->pdr0);
+        return s->pdr0;
+    case 2:
+        DPRINTF(" pdr1 = 0x%x\n", s->pdr1);
+        return s->pdr1;
+    case 4:
+        DPRINTF(" mpctl = 0x%x\n", s->mpctl);
+        return s->mpctl;
+    case 6:
+        DPRINTF(" spctl = 0x%x\n", s->spctl);
+        return s->spctl;
+    case 8:
+        DPRINTF(" cgr0 = 0x%x\n", s->cgr[0]);
+        return s->cgr[0];
+    case 9:
+        DPRINTF(" cgr1 = 0x%x\n", s->cgr[1]);
+        return s->cgr[1];
+    case 10:
+        DPRINTF(" cgr2 = 0x%x\n", s->cgr[2]);
+        return s->cgr[2];
+    case 18: /* LTR1 */
+        return 0x00004040;
+    case 23:
+        DPRINTF(" pcmr0 = 0x%x\n", s->pmcr0);
+        return s->pmcr0;
+    }
+    DPRINTF(" return 0\n");
+    return 0;
+}
+
+static void imx_ccm_write(void *opaque, hwaddr offset,
+                          uint64_t value, unsigned size)
+{
+    IMXCCMState *s = (IMXCCMState *)opaque;
+
+    DPRINTF("write(offset=%x, value = %x)\n",
+            offset >> 2, (unsigned int)value);
+    switch (offset >> 2) {
+    case 0:
+        s->ccmr = CCMR_FPMF | (value & 0x3b6fdfff);
+        break;
+    case 1:
+        s->pdr0 = value & 0xff9f3fff;
+        break;
+    case 2:
+        s->pdr1 = value;
+        break;
+    case 4:
+        s->mpctl = value & 0xbfff3fff;
+        break;
+    case 6:
+        s->spctl = value & 0xbfff3fff;
+        break;
+    case 8:
+        s->cgr[0] = value;
+        return;
+    case 9:
+        s->cgr[1] = value;
+        return;
+    case 10:
+        s->cgr[2] = value;
+        return;
+
+    default:
+        return;
+    }
+    update_clocks(s);
+}
+
+static const struct MemoryRegionOps imx_ccm_ops = {
+    .read = imx_ccm_read,
+    .write = imx_ccm_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int imx_ccm_init(SysBusDevice *dev)
+{
+    IMXCCMState *s = FROM_SYSBUS(typeof(*s), dev);
+
+    memory_region_init_io(&s->iomem, &imx_ccm_ops, s, "imx_ccm", 0x1000);
+    sysbus_init_mmio(dev, &s->iomem);
+
+    return 0;
+}
+
+static int imx_ccm_post_load(void *opaque, int version_id)
+{
+    IMXCCMState *s = (IMXCCMState *)opaque;
+
+    update_clocks(s);
+    return 0;
+}
+
+static void imx_ccm_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sbc->init = imx_ccm_init;
+    dc->reset = imx_ccm_reset;
+    dc->vmsd = &vmstate_imx_ccm;
+    dc->desc = "i.MX Clock Control Module";
+}
+
+static const TypeInfo imx_ccm_info = {
+    .name = "imx_ccm",
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(IMXCCMState),
+    .class_init = imx_ccm_class_init,
+};
+
+static void imx_ccm_register_types(void)
+{
+    type_register_static(&imx_ccm_info);
+}
+
+type_init(imx_ccm_register_types)
diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
new file mode 100644 (file)
index 0000000..f92ce19
--- /dev/null
@@ -0,0 +1,826 @@
+/*
+ * Inter-VM Shared Memory PCI device.
+ *
+ * Author:
+ *      Cam Macdonell <cam@cs.ualberta.ca>
+ *
+ * Based On: cirrus_vga.c
+ *          Copyright (c) 2004 Fabrice Bellard
+ *          Copyright (c) 2004 Makoto Suzuki (suzu)
+ *
+ *      and rtl8139.c
+ *          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/hw.h"
+#include "hw/i386/pc.h"
+#include "hw/pci/pci.h"
+#include "hw/pci/msix.h"
+#include "sysemu/kvm.h"
+#include "migration/migration.h"
+#include "qapi/qmp/qerror.h"
+#include "qemu/event_notifier.h"
+#include "char/char.h"
+
+#include <sys/mman.h>
+#include <sys/types.h>
+
+#define PCI_VENDOR_ID_IVSHMEM   PCI_VENDOR_ID_REDHAT_QUMRANET
+#define PCI_DEVICE_ID_IVSHMEM   0x1110
+
+#define IVSHMEM_IOEVENTFD   0
+#define IVSHMEM_MSI     1
+
+#define IVSHMEM_PEER    0
+#define IVSHMEM_MASTER  1
+
+#define IVSHMEM_REG_BAR_SIZE 0x100
+
+//#define DEBUG_IVSHMEM
+#ifdef DEBUG_IVSHMEM
+#define IVSHMEM_DPRINTF(fmt, ...)        \
+    do {printf("IVSHMEM: " fmt, ## __VA_ARGS__); } while (0)
+#else
+#define IVSHMEM_DPRINTF(fmt, ...)
+#endif
+
+typedef struct Peer {
+    int nb_eventfds;
+    EventNotifier *eventfds;
+} Peer;
+
+typedef struct EventfdEntry {
+    PCIDevice *pdev;
+    int vector;
+} EventfdEntry;
+
+typedef struct IVShmemState {
+    PCIDevice dev;
+    uint32_t intrmask;
+    uint32_t intrstatus;
+    uint32_t doorbell;
+
+    CharDriverState **eventfd_chr;
+    CharDriverState *server_chr;
+    MemoryRegion ivshmem_mmio;
+
+    /* We might need to register the BAR before we actually have the memory.
+     * So prepare a container MemoryRegion for the BAR immediately and
+     * add a subregion when we have the memory.
+     */
+    MemoryRegion bar;
+    MemoryRegion ivshmem;
+    uint64_t ivshmem_size; /* size of shared memory region */
+    uint32_t ivshmem_attr;
+    uint32_t ivshmem_64bit;
+    int shm_fd; /* shared memory file descriptor */
+
+    Peer *peers;
+    int nb_peers; /* how many guests we have space for */
+    int max_peer; /* maximum numbered peer */
+
+    int vm_id;
+    uint32_t vectors;
+    uint32_t features;
+    EventfdEntry *eventfd_table;
+
+    Error *migration_blocker;
+
+    char * shmobj;
+    char * sizearg;
+    char * role;
+    int role_val;   /* scalar to avoid multiple string comparisons */
+} IVShmemState;
+
+/* registers for the Inter-VM shared memory device */
+enum ivshmem_registers {
+    INTRMASK = 0,
+    INTRSTATUS = 4,
+    IVPOSITION = 8,
+    DOORBELL = 12,
+};
+
+static inline uint32_t ivshmem_has_feature(IVShmemState *ivs,
+                                                    unsigned int feature) {
+    return (ivs->features & (1 << feature));
+}
+
+static inline bool is_power_of_two(uint64_t x) {
+    return (x & (x - 1)) == 0;
+}
+
+/* accessing registers - based on rtl8139 */
+static void ivshmem_update_irq(IVShmemState *s, int val)
+{
+    int isr;
+    isr = (s->intrstatus & s->intrmask) & 0xffffffff;
+
+    /* don't print ISR resets */
+    if (isr) {
+        IVSHMEM_DPRINTF("Set IRQ to %d (%04x %04x)\n",
+           isr ? 1 : 0, s->intrstatus, s->intrmask);
+    }
+
+    qemu_set_irq(s->dev.irq[0], (isr != 0));
+}
+
+static void ivshmem_IntrMask_write(IVShmemState *s, uint32_t val)
+{
+    IVSHMEM_DPRINTF("IntrMask write(w) val = 0x%04x\n", val);
+
+    s->intrmask = val;
+
+    ivshmem_update_irq(s, val);
+}
+
+static uint32_t ivshmem_IntrMask_read(IVShmemState *s)
+{
+    uint32_t ret = s->intrmask;
+
+    IVSHMEM_DPRINTF("intrmask read(w) val = 0x%04x\n", ret);
+
+    return ret;
+}
+
+static void ivshmem_IntrStatus_write(IVShmemState *s, uint32_t val)
+{
+    IVSHMEM_DPRINTF("IntrStatus write(w) val = 0x%04x\n", val);
+
+    s->intrstatus = val;
+
+    ivshmem_update_irq(s, val);
+}
+
+static uint32_t ivshmem_IntrStatus_read(IVShmemState *s)
+{
+    uint32_t ret = s->intrstatus;
+
+    /* reading ISR clears all interrupts */
+    s->intrstatus = 0;
+
+    ivshmem_update_irq(s, 0);
+
+    return ret;
+}
+
+static void ivshmem_io_write(void *opaque, hwaddr addr,
+                             uint64_t val, unsigned size)
+{
+    IVShmemState *s = opaque;
+
+    uint16_t dest = val >> 16;
+    uint16_t vector = val & 0xff;
+
+    addr &= 0xfc;
+
+    IVSHMEM_DPRINTF("writing to addr " TARGET_FMT_plx "\n", addr);
+    switch (addr)
+    {
+        case INTRMASK:
+            ivshmem_IntrMask_write(s, val);
+            break;
+
+        case INTRSTATUS:
+            ivshmem_IntrStatus_write(s, val);
+            break;
+
+        case DOORBELL:
+            /* check that dest VM ID is reasonable */
+            if (dest > s->max_peer) {
+                IVSHMEM_DPRINTF("Invalid destination VM ID (%d)\n", dest);
+                break;
+            }
+
+            /* check doorbell range */
+            if (vector < s->peers[dest].nb_eventfds) {
+                IVSHMEM_DPRINTF("Notifying VM %d on vector %d\n", dest, vector);
+                event_notifier_set(&s->peers[dest].eventfds[vector]);
+            }
+            break;
+        default:
+            IVSHMEM_DPRINTF("Invalid VM Doorbell VM %d\n", dest);
+    }
+}
+
+static uint64_t ivshmem_io_read(void *opaque, hwaddr addr,
+                                unsigned size)
+{
+
+    IVShmemState *s = opaque;
+    uint32_t ret;
+
+    switch (addr)
+    {
+        case INTRMASK:
+            ret = ivshmem_IntrMask_read(s);
+            break;
+
+        case INTRSTATUS:
+            ret = ivshmem_IntrStatus_read(s);
+            break;
+
+        case IVPOSITION:
+            /* return my VM ID if the memory is mapped */
+            if (s->shm_fd > 0) {
+                ret = s->vm_id;
+            } else {
+                ret = -1;
+            }
+            break;
+
+        default:
+            IVSHMEM_DPRINTF("why are we reading " TARGET_FMT_plx "\n", addr);
+            ret = 0;
+    }
+
+    return ret;
+}
+
+static const MemoryRegionOps ivshmem_mmio_ops = {
+    .read = ivshmem_io_read,
+    .write = ivshmem_io_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static void ivshmem_receive(void *opaque, const uint8_t *buf, int size)
+{
+    IVShmemState *s = opaque;
+
+    ivshmem_IntrStatus_write(s, *buf);
+
+    IVSHMEM_DPRINTF("ivshmem_receive 0x%02x\n", *buf);
+}
+
+static int ivshmem_can_receive(void * opaque)
+{
+    return 8;
+}
+
+static void ivshmem_event(void *opaque, int event)
+{
+    IVSHMEM_DPRINTF("ivshmem_event %d\n", event);
+}
+
+static void fake_irqfd(void *opaque, const uint8_t *buf, int size) {
+
+    EventfdEntry *entry = opaque;
+    PCIDevice *pdev = entry->pdev;
+
+    IVSHMEM_DPRINTF("interrupt on vector %p %d\n", pdev, entry->vector);
+    msix_notify(pdev, entry->vector);
+}
+
+static CharDriverState* create_eventfd_chr_device(void * opaque, EventNotifier *n,
+                                                  int vector)
+{
+    /* create a event character device based on the passed eventfd */
+    IVShmemState *s = opaque;
+    CharDriverState * chr;
+    int eventfd = event_notifier_get_fd(n);
+
+    chr = qemu_chr_open_eventfd(eventfd);
+
+    if (chr == NULL) {
+        fprintf(stderr, "creating eventfd for eventfd %d failed\n", eventfd);
+        exit(-1);
+    }
+    qemu_chr_fe_claim_no_fail(chr);
+
+    /* if MSI is supported we need multiple interrupts */
+    if (ivshmem_has_feature(s, IVSHMEM_MSI)) {
+        s->eventfd_table[vector].pdev = &s->dev;
+        s->eventfd_table[vector].vector = vector;
+
+        qemu_chr_add_handlers(chr, ivshmem_can_receive, fake_irqfd,
+                      ivshmem_event, &s->eventfd_table[vector]);
+    } else {
+        qemu_chr_add_handlers(chr, ivshmem_can_receive, ivshmem_receive,
+                      ivshmem_event, s);
+    }
+
+    return chr;
+
+}
+
+static int check_shm_size(IVShmemState *s, int fd) {
+    /* check that the guest isn't going to try and map more memory than the
+     * the object has allocated return -1 to indicate error */
+
+    struct stat buf;
+
+    fstat(fd, &buf);
+
+    if (s->ivshmem_size > buf.st_size) {
+        fprintf(stderr,
+                "IVSHMEM ERROR: Requested memory size greater"
+                " than shared object size (%" PRIu64 " > %" PRIu64")\n",
+                s->ivshmem_size, (uint64_t)buf.st_size);
+        return -1;
+    } else {
+        return 0;
+    }
+}
+
+/* create the shared memory BAR when we are not using the server, so we can
+ * create the BAR and map the memory immediately */
+static void create_shared_memory_BAR(IVShmemState *s, int fd) {
+
+    void * ptr;
+
+    s->shm_fd = fd;
+
+    ptr = mmap(0, s->ivshmem_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
+
+    memory_region_init_ram_ptr(&s->ivshmem, "ivshmem.bar2",
+                               s->ivshmem_size, ptr);
+    vmstate_register_ram(&s->ivshmem, &s->dev.qdev);
+    memory_region_add_subregion(&s->bar, 0, &s->ivshmem);
+
+    /* region for shared memory */
+    pci_register_bar(&s->dev, 2, s->ivshmem_attr, &s->bar);
+}
+
+static void ivshmem_add_eventfd(IVShmemState *s, int posn, int i)
+{
+    memory_region_add_eventfd(&s->ivshmem_mmio,
+                              DOORBELL,
+                              4,
+                              true,
+                              (posn << 16) | i,
+                              &s->peers[posn].eventfds[i]);
+}
+
+static void ivshmem_del_eventfd(IVShmemState *s, int posn, int i)
+{
+    memory_region_del_eventfd(&s->ivshmem_mmio,
+                              DOORBELL,
+                              4,
+                              true,
+                              (posn << 16) | i,
+                              &s->peers[posn].eventfds[i]);
+}
+
+static void close_guest_eventfds(IVShmemState *s, int posn)
+{
+    int i, guest_curr_max;
+
+    if (!ivshmem_has_feature(s, IVSHMEM_IOEVENTFD)) {
+        return;
+    }
+
+    guest_curr_max = s->peers[posn].nb_eventfds;
+
+    memory_region_transaction_begin();
+    for (i = 0; i < guest_curr_max; i++) {
+        ivshmem_del_eventfd(s, posn, i);
+    }
+    memory_region_transaction_commit();
+    for (i = 0; i < guest_curr_max; i++) {
+        event_notifier_cleanup(&s->peers[posn].eventfds[i]);
+    }
+
+    g_free(s->peers[posn].eventfds);
+    s->peers[posn].nb_eventfds = 0;
+}
+
+/* this function increase the dynamic storage need to store data about other
+ * guests */
+static void increase_dynamic_storage(IVShmemState *s, int new_min_size) {
+
+    int j, old_nb_alloc;
+
+    old_nb_alloc = s->nb_peers;
+
+    while (new_min_size >= s->nb_peers)
+        s->nb_peers = s->nb_peers * 2;
+
+    IVSHMEM_DPRINTF("bumping storage to %d guests\n", s->nb_peers);
+    s->peers = g_realloc(s->peers, s->nb_peers * sizeof(Peer));
+
+    /* zero out new pointers */
+    for (j = old_nb_alloc; j < s->nb_peers; j++) {
+        s->peers[j].eventfds = NULL;
+        s->peers[j].nb_eventfds = 0;
+    }
+}
+
+static void ivshmem_read(void *opaque, const uint8_t * buf, int flags)
+{
+    IVShmemState *s = opaque;
+    int incoming_fd, tmp_fd;
+    int guest_max_eventfd;
+    long incoming_posn;
+
+    memcpy(&incoming_posn, buf, sizeof(long));
+    /* pick off s->server_chr->msgfd and store it, posn should accompany msg */
+    tmp_fd = qemu_chr_fe_get_msgfd(s->server_chr);
+    IVSHMEM_DPRINTF("posn is %ld, fd is %d\n", incoming_posn, tmp_fd);
+
+    /* make sure we have enough space for this guest */
+    if (incoming_posn >= s->nb_peers) {
+        increase_dynamic_storage(s, incoming_posn);
+    }
+
+    if (tmp_fd == -1) {
+        /* if posn is positive and unseen before then this is our posn*/
+        if ((incoming_posn >= 0) &&
+                            (s->peers[incoming_posn].eventfds == NULL)) {
+            /* receive our posn */
+            s->vm_id = incoming_posn;
+            return;
+        } else {
+            /* otherwise an fd == -1 means an existing guest has gone away */
+            IVSHMEM_DPRINTF("posn %ld has gone away\n", incoming_posn);
+            close_guest_eventfds(s, incoming_posn);
+            return;
+        }
+    }
+
+    /* because of the implementation of get_msgfd, we need a dup */
+    incoming_fd = dup(tmp_fd);
+
+    if (incoming_fd == -1) {
+        fprintf(stderr, "could not allocate file descriptor %s\n",
+                                                            strerror(errno));
+        return;
+    }
+
+    /* if the position is -1, then it's shared memory region fd */
+    if (incoming_posn == -1) {
+
+        void * map_ptr;
+
+        s->max_peer = 0;
+
+        if (check_shm_size(s, incoming_fd) == -1) {
+            exit(-1);
+        }
+
+        /* mmap the region and map into the BAR2 */
+        map_ptr = mmap(0, s->ivshmem_size, PROT_READ|PROT_WRITE, MAP_SHARED,
+                                                            incoming_fd, 0);
+        memory_region_init_ram_ptr(&s->ivshmem,
+                                   "ivshmem.bar2", s->ivshmem_size, map_ptr);
+        vmstate_register_ram(&s->ivshmem, &s->dev.qdev);
+
+        IVSHMEM_DPRINTF("guest h/w addr = %" PRIu64 ", size = %" PRIu64 "\n",
+                         s->ivshmem_offset, s->ivshmem_size);
+
+        memory_region_add_subregion(&s->bar, 0, &s->ivshmem);
+
+        /* only store the fd if it is successfully mapped */
+        s->shm_fd = incoming_fd;
+
+        return;
+    }
+
+    /* each guest has an array of eventfds, and we keep track of how many
+     * guests for each VM */
+    guest_max_eventfd = s->peers[incoming_posn].nb_eventfds;
+
+    if (guest_max_eventfd == 0) {
+        /* one eventfd per MSI vector */
+        s->peers[incoming_posn].eventfds = g_new(EventNotifier, s->vectors);
+    }
+
+    /* this is an eventfd for a particular guest VM */
+    IVSHMEM_DPRINTF("eventfds[%ld][%d] = %d\n", incoming_posn,
+                                            guest_max_eventfd, incoming_fd);
+    event_notifier_init_fd(&s->peers[incoming_posn].eventfds[guest_max_eventfd],
+                           incoming_fd);
+
+    /* increment count for particular guest */
+    s->peers[incoming_posn].nb_eventfds++;
+
+    /* keep track of the maximum VM ID */
+    if (incoming_posn > s->max_peer) {
+        s->max_peer = incoming_posn;
+    }
+
+    if (incoming_posn == s->vm_id) {
+        s->eventfd_chr[guest_max_eventfd] = create_eventfd_chr_device(s,
+                   &s->peers[s->vm_id].eventfds[guest_max_eventfd],
+                   guest_max_eventfd);
+    }
+
+    if (ivshmem_has_feature(s, IVSHMEM_IOEVENTFD)) {
+        ivshmem_add_eventfd(s, incoming_posn, guest_max_eventfd);
+    }
+}
+
+/* Select the MSI-X vectors used by device.
+ * ivshmem maps events to vectors statically, so
+ * we just enable all vectors on init and after reset. */
+static void ivshmem_use_msix(IVShmemState * s)
+{
+    int i;
+
+    if (!msix_present(&s->dev)) {
+        return;
+    }
+
+    for (i = 0; i < s->vectors; i++) {
+        msix_vector_use(&s->dev, i);
+    }
+}
+
+static void ivshmem_reset(DeviceState *d)
+{
+    IVShmemState *s = DO_UPCAST(IVShmemState, dev.qdev, d);
+
+    s->intrstatus = 0;
+    ivshmem_use_msix(s);
+}
+
+static uint64_t ivshmem_get_size(IVShmemState * s) {
+
+    uint64_t value;
+    char *ptr;
+
+    value = strtoull(s->sizearg, &ptr, 10);
+    switch (*ptr) {
+        case 0: case 'M': case 'm':
+            value <<= 20;
+            break;
+        case 'G': case 'g':
+            value <<= 30;
+            break;
+        default:
+            fprintf(stderr, "qemu: invalid ram size: %s\n", s->sizearg);
+            exit(1);
+    }
+
+    /* BARs must be a power of 2 */
+    if (!is_power_of_two(value)) {
+        fprintf(stderr, "ivshmem: size must be power of 2\n");
+        exit(1);
+    }
+
+    return value;
+}
+
+static void ivshmem_setup_msi(IVShmemState * s)
+{
+    if (msix_init_exclusive_bar(&s->dev, s->vectors, 1)) {
+        IVSHMEM_DPRINTF("msix initialization failed\n");
+        exit(1);
+    }
+
+    IVSHMEM_DPRINTF("msix initialized (%d vectors)\n", s->vectors);
+
+    /* allocate QEMU char devices for receiving interrupts */
+    s->eventfd_table = g_malloc0(s->vectors * sizeof(EventfdEntry));
+
+    ivshmem_use_msix(s);
+}
+
+static void ivshmem_save(QEMUFile* f, void *opaque)
+{
+    IVShmemState *proxy = opaque;
+
+    IVSHMEM_DPRINTF("ivshmem_save\n");
+    pci_device_save(&proxy->dev, f);
+
+    if (ivshmem_has_feature(proxy, IVSHMEM_MSI)) {
+        msix_save(&proxy->dev, f);
+    } else {
+        qemu_put_be32(f, proxy->intrstatus);
+        qemu_put_be32(f, proxy->intrmask);
+    }
+
+}
+
+static int ivshmem_load(QEMUFile* f, void *opaque, int version_id)
+{
+    IVSHMEM_DPRINTF("ivshmem_load\n");
+
+    IVShmemState *proxy = opaque;
+    int ret;
+
+    if (version_id > 0) {
+        return -EINVAL;
+    }
+
+    if (proxy->role_val == IVSHMEM_PEER) {
+        fprintf(stderr, "ivshmem: 'peer' devices are not migratable\n");
+        return -EINVAL;
+    }
+
+    ret = pci_device_load(&proxy->dev, f);
+    if (ret) {
+        return ret;
+    }
+
+    if (ivshmem_has_feature(proxy, IVSHMEM_MSI)) {
+        msix_load(&proxy->dev, f);
+       ivshmem_use_msix(proxy);
+    } else {
+        proxy->intrstatus = qemu_get_be32(f);
+        proxy->intrmask = qemu_get_be32(f);
+    }
+
+    return 0;
+}
+
+static void ivshmem_write_config(PCIDevice *pci_dev, uint32_t address,
+                                uint32_t val, int len)
+{
+    pci_default_write_config(pci_dev, address, val, len);
+    msix_write_config(pci_dev, address, val, len);
+}
+
+static int pci_ivshmem_init(PCIDevice *dev)
+{
+    IVShmemState *s = DO_UPCAST(IVShmemState, dev, dev);
+    uint8_t *pci_conf;
+
+    if (s->sizearg == NULL)
+        s->ivshmem_size = 4 << 20; /* 4 MB default */
+    else {
+        s->ivshmem_size = ivshmem_get_size(s);
+    }
+
+    register_savevm(&s->dev.qdev, "ivshmem", 0, 0, ivshmem_save, ivshmem_load,
+                                                                        dev);
+
+    /* IRQFD requires MSI */
+    if (ivshmem_has_feature(s, IVSHMEM_IOEVENTFD) &&
+        !ivshmem_has_feature(s, IVSHMEM_MSI)) {
+        fprintf(stderr, "ivshmem: ioeventfd/irqfd requires MSI\n");
+        exit(1);
+    }
+
+    /* check that role is reasonable */
+    if (s->role) {
+        if (strncmp(s->role, "peer", 5) == 0) {
+            s->role_val = IVSHMEM_PEER;
+        } else if (strncmp(s->role, "master", 7) == 0) {
+            s->role_val = IVSHMEM_MASTER;
+        } else {
+            fprintf(stderr, "ivshmem: 'role' must be 'peer' or 'master'\n");
+            exit(1);
+        }
+    } else {
+        s->role_val = IVSHMEM_MASTER; /* default */
+    }
+
+    if (s->role_val == IVSHMEM_PEER) {
+        error_set(&s->migration_blocker, QERR_DEVICE_FEATURE_BLOCKS_MIGRATION,
+                  "peer mode", "ivshmem");
+        migrate_add_blocker(s->migration_blocker);
+    }
+
+    pci_conf = s->dev.config;
+    pci_conf[PCI_COMMAND] = PCI_COMMAND_IO | PCI_COMMAND_MEMORY;
+
+    pci_config_set_interrupt_pin(pci_conf, 1);
+
+    s->shm_fd = 0;
+
+    memory_region_init_io(&s->ivshmem_mmio, &ivshmem_mmio_ops, s,
+                          "ivshmem-mmio", IVSHMEM_REG_BAR_SIZE);
+
+    /* region for registers*/
+    pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY,
+                     &s->ivshmem_mmio);
+
+    memory_region_init(&s->bar, "ivshmem-bar2-container", s->ivshmem_size);
+    s->ivshmem_attr = PCI_BASE_ADDRESS_SPACE_MEMORY |
+        PCI_BASE_ADDRESS_MEM_PREFETCH;
+    if (s->ivshmem_64bit) {
+        s->ivshmem_attr |= PCI_BASE_ADDRESS_MEM_TYPE_64;
+    }
+
+    if ((s->server_chr != NULL) &&
+                        (strncmp(s->server_chr->filename, "unix:", 5) == 0)) {
+        /* if we get a UNIX socket as the parameter we will talk
+         * to the ivshmem server to receive the memory region */
+
+        if (s->shmobj != NULL) {
+            fprintf(stderr, "WARNING: do not specify both 'chardev' "
+                                                "and 'shm' with ivshmem\n");
+        }
+
+        IVSHMEM_DPRINTF("using shared memory server (socket = %s)\n",
+                                                    s->server_chr->filename);
+
+        if (ivshmem_has_feature(s, IVSHMEM_MSI)) {
+            ivshmem_setup_msi(s);
+        }
+
+        /* we allocate enough space for 16 guests and grow as needed */
+        s->nb_peers = 16;
+        s->vm_id = -1;
+
+        /* allocate/initialize space for interrupt handling */
+        s->peers = g_malloc0(s->nb_peers * sizeof(Peer));
+
+        pci_register_bar(&s->dev, 2, s->ivshmem_attr, &s->bar);
+
+        s->eventfd_chr = g_malloc0(s->vectors * sizeof(CharDriverState *));
+
+        qemu_chr_add_handlers(s->server_chr, ivshmem_can_receive, ivshmem_read,
+                     ivshmem_event, s);
+    } else {
+        /* just map the file immediately, we're not using a server */
+        int fd;
+
+        if (s->shmobj == NULL) {
+            fprintf(stderr, "Must specify 'chardev' or 'shm' to ivshmem\n");
+        }
+
+        IVSHMEM_DPRINTF("using shm_open (shm object = %s)\n", s->shmobj);
+
+        /* try opening with O_EXCL and if it succeeds zero the memory
+         * by truncating to 0 */
+        if ((fd = shm_open(s->shmobj, O_CREAT|O_RDWR|O_EXCL,
+                        S_IRWXU|S_IRWXG|S_IRWXO)) > 0) {
+           /* truncate file to length PCI device's memory */
+            if (ftruncate(fd, s->ivshmem_size) != 0) {
+                fprintf(stderr, "ivshmem: could not truncate shared file\n");
+            }
+
+        } else if ((fd = shm_open(s->shmobj, O_CREAT|O_RDWR,
+                        S_IRWXU|S_IRWXG|S_IRWXO)) < 0) {
+            fprintf(stderr, "ivshmem: could not open shared file\n");
+            exit(-1);
+
+        }
+
+        if (check_shm_size(s, fd) == -1) {
+            exit(-1);
+        }
+
+        create_shared_memory_BAR(s, fd);
+
+    }
+
+    s->dev.config_write = ivshmem_write_config;
+
+    return 0;
+}
+
+static void pci_ivshmem_uninit(PCIDevice *dev)
+{
+    IVShmemState *s = DO_UPCAST(IVShmemState, dev, dev);
+
+    if (s->migration_blocker) {
+        migrate_del_blocker(s->migration_blocker);
+        error_free(s->migration_blocker);
+    }
+
+    memory_region_destroy(&s->ivshmem_mmio);
+    memory_region_del_subregion(&s->bar, &s->ivshmem);
+    vmstate_unregister_ram(&s->ivshmem, &s->dev.qdev);
+    memory_region_destroy(&s->ivshmem);
+    memory_region_destroy(&s->bar);
+    unregister_savevm(&dev->qdev, "ivshmem", s);
+}
+
+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_UINT32("use64", IVShmemState, ivshmem_64bit, 1),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void ivshmem_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = pci_ivshmem_init;
+    k->exit = pci_ivshmem_uninit;
+    k->vendor_id = PCI_VENDOR_ID_IVSHMEM;
+    k->device_id = PCI_DEVICE_ID_IVSHMEM;
+    k->class_id = PCI_CLASS_MEMORY_RAM;
+    dc->reset = ivshmem_reset;
+    dc->props = ivshmem_properties;
+}
+
+static const TypeInfo ivshmem_info = {
+    .name          = "ivshmem",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(IVShmemState),
+    .class_init    = ivshmem_class_init,
+};
+
+static void ivshmem_register_types(void)
+{
+    type_register_static(&ivshmem_info);
+}
+
+type_init(ivshmem_register_types)
diff --git a/hw/misc/lm32_sys.c b/hw/misc/lm32_sys.c
new file mode 100644 (file)
index 0000000..33a3b80
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ *  QEMU model of the LatticeMico32 system control block.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
+ *
+ * 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/>.
+ */
+
+/*
+ * This model is mainly intended for testing purposes and doesn't fit to any
+ * real hardware. On the one hand it provides a control register (R_CTRL) on
+ * the other hand it supports the lm32 tests.
+ *
+ * A write to the control register causes a system shutdown.
+ * Tests first write the pointer to a test name to the test name register
+ * (R_TESTNAME) and then write a zero to the pass/fail register (R_PASSFAIL) if
+ * the test is passed or any non-zero value to it if the test is failed.
+ */
+
+#include "hw/hw.h"
+#include "hw/sysbus.h"
+#include "trace.h"
+#include "qemu/log.h"
+#include "qemu/error-report.h"
+#include "sysemu/sysemu.h"
+#include "qemu/log.h"
+
+enum {
+    R_CTRL = 0,
+    R_PASSFAIL,
+    R_TESTNAME,
+    R_MAX
+};
+
+#define MAX_TESTNAME_LEN 16
+
+struct LM32SysState {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    uint32_t base;
+    uint32_t regs[R_MAX];
+    uint8_t testname[MAX_TESTNAME_LEN];
+};
+typedef struct LM32SysState LM32SysState;
+
+static void copy_testname(LM32SysState *s)
+{
+    cpu_physical_memory_read(s->regs[R_TESTNAME], s->testname,
+            MAX_TESTNAME_LEN);
+    s->testname[MAX_TESTNAME_LEN - 1] = '\0';
+}
+
+static void sys_write(void *opaque, hwaddr addr,
+                      uint64_t value, unsigned size)
+{
+    LM32SysState *s = opaque;
+    char *testname;
+
+    trace_lm32_sys_memory_write(addr, value);
+
+    addr >>= 2;
+    switch (addr) {
+    case R_CTRL:
+        qemu_system_shutdown_request();
+        break;
+    case R_PASSFAIL:
+        s->regs[addr] = value;
+        testname = (char *)s->testname;
+        qemu_log("TC  %-16s %s\n", testname, (value) ? "FAILED" : "OK");
+        break;
+    case R_TESTNAME:
+        s->regs[addr] = value;
+        copy_testname(s);
+        break;
+
+    default:
+        error_report("lm32_sys: write access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+}
+
+static bool sys_ops_accepts(void *opaque, hwaddr addr,
+                            unsigned size, bool is_write)
+{
+    return is_write && size == 4;
+}
+
+static const MemoryRegionOps sys_ops = {
+    .write = sys_write,
+    .valid.accepts = sys_ops_accepts,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void sys_reset(DeviceState *d)
+{
+    LM32SysState *s = container_of(d, LM32SysState, busdev.qdev);
+    int i;
+
+    for (i = 0; i < R_MAX; i++) {
+        s->regs[i] = 0;
+    }
+    memset(s->testname, 0, MAX_TESTNAME_LEN);
+}
+
+static int lm32_sys_init(SysBusDevice *dev)
+{
+    LM32SysState *s = FROM_SYSBUS(typeof(*s), dev);
+
+    memory_region_init_io(&s->iomem, &sys_ops , s, "sys", R_MAX * 4);
+    sysbus_init_mmio(dev, &s->iomem);
+
+    /* Note: This device is not created in the board initialization,
+     * instead it has to be added with the -device parameter. Therefore,
+     * the device maps itself. */
+    sysbus_mmio_map(dev, 0, s->base);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_lm32_sys = {
+    .name = "lm32-sys",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(regs, LM32SysState, R_MAX),
+        VMSTATE_BUFFER(testname, LM32SysState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static Property lm32_sys_properties[] = {
+    DEFINE_PROP_UINT32("base", LM32SysState, base, 0xffff0000),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void lm32_sys_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = lm32_sys_init;
+    dc->reset = sys_reset;
+    dc->vmsd = &vmstate_lm32_sys;
+    dc->props = lm32_sys_properties;
+}
+
+static const 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_types(void)
+{
+    type_register_static(&lm32_sys_info);
+}
+
+type_init(lm32_sys_register_types)
diff --git a/hw/misc/macio/Makefile.objs b/hw/misc/macio/Makefile.objs
new file mode 100644 (file)
index 0000000..ef7ac24
--- /dev/null
@@ -0,0 +1,3 @@
+common-obj-y += macio.o
+common-obj-$(CONFIG_CUDA) += cuda.o
+common-obj-$(CONFIG_MAC_DBDMA) += mac_dbdma.o
diff --git a/hw/misc/macio/cuda.c b/hw/misc/macio/cuda.c
new file mode 100644 (file)
index 0000000..f797796
--- /dev/null
@@ -0,0 +1,740 @@
+/*
+ * QEMU PowerMac CUDA device support
+ *
+ * Copyright (c) 2004-2007 Fabrice Bellard
+ * Copyright (c) 2007 Jocelyn Mayer
+ *
+ * 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 "hw/hw.h"
+#include "hw/ppc/mac.h"
+#include "hw/input/adb.h"
+#include "qemu/timer.h"
+#include "sysemu/sysemu.h"
+
+/* XXX: implement all timer modes */
+
+/* debug CUDA */
+//#define DEBUG_CUDA
+
+/* debug CUDA packets */
+//#define DEBUG_CUDA_PACKET
+
+#ifdef DEBUG_CUDA
+#define CUDA_DPRINTF(fmt, ...)                                  \
+    do { printf("CUDA: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define CUDA_DPRINTF(fmt, ...)
+#endif
+
+/* Bits in B data register: all active low */
+#define TREQ           0x08            /* Transfer request (input) */
+#define TACK           0x10            /* Transfer acknowledge (output) */
+#define TIP            0x20            /* Transfer in progress (output) */
+
+/* Bits in ACR */
+#define SR_CTRL                0x1c            /* Shift register control bits */
+#define SR_EXT         0x0c            /* Shift on external clock */
+#define SR_OUT         0x10            /* Shift out if 1 */
+
+/* Bits in IFR and IER */
+#define IER_SET                0x80            /* set bits in IER */
+#define IER_CLR                0               /* clear bits in IER */
+#define SR_INT         0x04            /* Shift register full/empty */
+#define T1_INT          0x40            /* Timer 1 interrupt */
+#define T2_INT          0x20            /* Timer 2 interrupt */
+
+/* Bits in ACR */
+#define T1MODE          0xc0            /* Timer 1 mode */
+#define T1MODE_CONT     0x40            /*  continuous interrupts */
+
+/* commands (1st byte) */
+#define ADB_PACKET     0
+#define CUDA_PACKET    1
+#define ERROR_PACKET   2
+#define TIMER_PACKET   3
+#define POWER_PACKET   4
+#define MACIIC_PACKET  5
+#define PMU_PACKET     6
+
+
+/* CUDA commands (2nd byte) */
+#define CUDA_WARM_START                        0x0
+#define CUDA_AUTOPOLL                  0x1
+#define CUDA_GET_6805_ADDR             0x2
+#define CUDA_GET_TIME                  0x3
+#define CUDA_GET_PRAM                  0x7
+#define CUDA_SET_6805_ADDR             0x8
+#define CUDA_SET_TIME                  0x9
+#define CUDA_POWERDOWN                 0xa
+#define CUDA_POWERUP_TIME              0xb
+#define CUDA_SET_PRAM                  0xc
+#define CUDA_MS_RESET                  0xd
+#define CUDA_SEND_DFAC                 0xe
+#define CUDA_BATTERY_SWAP_SENSE                0x10
+#define CUDA_RESET_SYSTEM              0x11
+#define CUDA_SET_IPL                   0x12
+#define CUDA_FILE_SERVER_FLAG          0x13
+#define CUDA_SET_AUTO_RATE             0x14
+#define CUDA_GET_AUTO_RATE             0x16
+#define CUDA_SET_DEVICE_LIST           0x19
+#define CUDA_GET_DEVICE_LIST           0x1a
+#define CUDA_SET_ONE_SECOND_MODE       0x1b
+#define CUDA_SET_POWER_MESSAGES                0x21
+#define CUDA_GET_SET_IIC               0x22
+#define CUDA_WAKEUP                    0x23
+#define CUDA_TIMER_TICKLE              0x24
+#define CUDA_COMBINED_FORMAT_IIC       0x25
+
+#define CUDA_TIMER_FREQ (4700000 / 6)
+#define CUDA_ADB_POLL_FREQ 50
+
+/* CUDA returns time_t's offset from Jan 1, 1904, not 1970 */
+#define RTC_OFFSET                      2082844800
+
+static void cuda_update(CUDAState *s);
+static void cuda_receive_packet_from_host(CUDAState *s,
+                                          const uint8_t *data, int len);
+static void cuda_timer_update(CUDAState *s, CUDATimer *ti,
+                              int64_t current_time);
+
+static void cuda_update_irq(CUDAState *s)
+{
+    if (s->ifr & s->ier & (SR_INT | T1_INT)) {
+        qemu_irq_raise(s->irq);
+    } else {
+        qemu_irq_lower(s->irq);
+    }
+}
+
+static unsigned int get_counter(CUDATimer *s)
+{
+    int64_t d;
+    unsigned int counter;
+
+    d = muldiv64(qemu_get_clock_ns(vm_clock) - s->load_time,
+                 CUDA_TIMER_FREQ, get_ticks_per_sec());
+    if (s->index == 0) {
+        /* the timer goes down from latch to -1 (period of latch + 2) */
+        if (d <= (s->counter_value + 1)) {
+            counter = (s->counter_value - d) & 0xffff;
+        } else {
+            counter = (d - (s->counter_value + 1)) % (s->latch + 2);
+            counter = (s->latch - counter) & 0xffff;
+        }
+    } else {
+        counter = (s->counter_value - d) & 0xffff;
+    }
+    return counter;
+}
+
+static void set_counter(CUDAState *s, CUDATimer *ti, unsigned int val)
+{
+    CUDA_DPRINTF("T%d.counter=%d\n", 1 + (ti->timer == NULL), val);
+    ti->load_time = qemu_get_clock_ns(vm_clock);
+    ti->counter_value = val;
+    cuda_timer_update(s, ti, ti->load_time);
+}
+
+static int64_t get_next_irq_time(CUDATimer *s, int64_t current_time)
+{
+    int64_t d, next_time;
+    unsigned int counter;
+
+    /* current counter value */
+    d = muldiv64(current_time - s->load_time,
+                 CUDA_TIMER_FREQ, get_ticks_per_sec());
+    /* the timer goes down from latch to -1 (period of latch + 2) */
+    if (d <= (s->counter_value + 1)) {
+        counter = (s->counter_value - d) & 0xffff;
+    } else {
+        counter = (d - (s->counter_value + 1)) % (s->latch + 2);
+        counter = (s->latch - counter) & 0xffff;
+    }
+
+    /* Note: we consider the irq is raised on 0 */
+    if (counter == 0xffff) {
+        next_time = d + s->latch + 1;
+    } else if (counter == 0) {
+        next_time = d + s->latch + 2;
+    } else {
+        next_time = d + counter;
+    }
+    CUDA_DPRINTF("latch=%d counter=%" PRId64 " delta_next=%" PRId64 "\n",
+                 s->latch, d, next_time - d);
+    next_time = muldiv64(next_time, get_ticks_per_sec(), CUDA_TIMER_FREQ) +
+        s->load_time;
+    if (next_time <= current_time)
+        next_time = current_time + 1;
+    return next_time;
+}
+
+static void cuda_timer_update(CUDAState *s, CUDATimer *ti,
+                              int64_t current_time)
+{
+    if (!ti->timer)
+        return;
+    if ((s->acr & T1MODE) != T1MODE_CONT) {
+        qemu_del_timer(ti->timer);
+    } else {
+        ti->next_irq_time = get_next_irq_time(ti, current_time);
+        qemu_mod_timer(ti->timer, ti->next_irq_time);
+    }
+}
+
+static void cuda_timer1(void *opaque)
+{
+    CUDAState *s = opaque;
+    CUDATimer *ti = &s->timers[0];
+
+    cuda_timer_update(s, ti, ti->next_irq_time);
+    s->ifr |= T1_INT;
+    cuda_update_irq(s);
+}
+
+static uint32_t cuda_readb(void *opaque, hwaddr addr)
+{
+    CUDAState *s = opaque;
+    uint32_t val;
+
+    addr = (addr >> 9) & 0xf;
+    switch(addr) {
+    case 0:
+        val = s->b;
+        break;
+    case 1:
+        val = s->a;
+        break;
+    case 2:
+        val = s->dirb;
+        break;
+    case 3:
+        val = s->dira;
+        break;
+    case 4:
+        val = get_counter(&s->timers[0]) & 0xff;
+        s->ifr &= ~T1_INT;
+        cuda_update_irq(s);
+        break;
+    case 5:
+        val = get_counter(&s->timers[0]) >> 8;
+        cuda_update_irq(s);
+        break;
+    case 6:
+        val = s->timers[0].latch & 0xff;
+        break;
+    case 7:
+        /* XXX: check this */
+        val = (s->timers[0].latch >> 8) & 0xff;
+        break;
+    case 8:
+        val = get_counter(&s->timers[1]) & 0xff;
+        s->ifr &= ~T2_INT;
+        break;
+    case 9:
+        val = get_counter(&s->timers[1]) >> 8;
+        break;
+    case 10:
+        val = s->sr;
+        s->ifr &= ~SR_INT;
+        cuda_update_irq(s);
+        break;
+    case 11:
+        val = s->acr;
+        break;
+    case 12:
+        val = s->pcr;
+        break;
+    case 13:
+        val = s->ifr;
+        if (s->ifr & s->ier)
+            val |= 0x80;
+        break;
+    case 14:
+        val = s->ier | 0x80;
+        break;
+    default:
+    case 15:
+        val = s->anh;
+        break;
+    }
+    if (addr != 13 || val != 0) {
+        CUDA_DPRINTF("read: reg=0x%x val=%02x\n", (int)addr, val);
+    }
+
+    return val;
+}
+
+static void cuda_writeb(void *opaque, hwaddr addr, uint32_t val)
+{
+    CUDAState *s = opaque;
+
+    addr = (addr >> 9) & 0xf;
+    CUDA_DPRINTF("write: reg=0x%x val=%02x\n", (int)addr, val);
+
+    switch(addr) {
+    case 0:
+        s->b = val;
+        cuda_update(s);
+        break;
+    case 1:
+        s->a = val;
+        break;
+    case 2:
+        s->dirb = val;
+        break;
+    case 3:
+        s->dira = val;
+        break;
+    case 4:
+        s->timers[0].latch = (s->timers[0].latch & 0xff00) | val;
+        cuda_timer_update(s, &s->timers[0], qemu_get_clock_ns(vm_clock));
+        break;
+    case 5:
+        s->timers[0].latch = (s->timers[0].latch & 0xff) | (val << 8);
+        s->ifr &= ~T1_INT;
+        set_counter(s, &s->timers[0], s->timers[0].latch);
+        break;
+    case 6:
+        s->timers[0].latch = (s->timers[0].latch & 0xff00) | val;
+        cuda_timer_update(s, &s->timers[0], qemu_get_clock_ns(vm_clock));
+        break;
+    case 7:
+        s->timers[0].latch = (s->timers[0].latch & 0xff) | (val << 8);
+        s->ifr &= ~T1_INT;
+        cuda_timer_update(s, &s->timers[0], qemu_get_clock_ns(vm_clock));
+        break;
+    case 8:
+        s->timers[1].latch = val;
+        set_counter(s, &s->timers[1], val);
+        break;
+    case 9:
+        set_counter(s, &s->timers[1], (val << 8) | s->timers[1].latch);
+        break;
+    case 10:
+        s->sr = val;
+        break;
+    case 11:
+        s->acr = val;
+        cuda_timer_update(s, &s->timers[0], qemu_get_clock_ns(vm_clock));
+        cuda_update(s);
+        break;
+    case 12:
+        s->pcr = val;
+        break;
+    case 13:
+        /* reset bits */
+        s->ifr &= ~val;
+        cuda_update_irq(s);
+        break;
+    case 14:
+        if (val & IER_SET) {
+            /* set bits */
+            s->ier |= val & 0x7f;
+        } else {
+            /* reset bits */
+            s->ier &= ~val;
+        }
+        cuda_update_irq(s);
+        break;
+    default:
+    case 15:
+        s->anh = val;
+        break;
+    }
+}
+
+/* NOTE: TIP and TREQ are negated */
+static void cuda_update(CUDAState *s)
+{
+    int packet_received, len;
+
+    packet_received = 0;
+    if (!(s->b & TIP)) {
+        /* transfer requested from host */
+
+        if (s->acr & SR_OUT) {
+            /* data output */
+            if ((s->b & (TACK | TIP)) != (s->last_b & (TACK | TIP))) {
+                if (s->data_out_index < sizeof(s->data_out)) {
+                    CUDA_DPRINTF("send: %02x\n", s->sr);
+                    s->data_out[s->data_out_index++] = s->sr;
+                    s->ifr |= SR_INT;
+                    cuda_update_irq(s);
+                }
+            }
+        } else {
+            if (s->data_in_index < s->data_in_size) {
+                /* data input */
+                if ((s->b & (TACK | TIP)) != (s->last_b & (TACK | TIP))) {
+                    s->sr = s->data_in[s->data_in_index++];
+                    CUDA_DPRINTF("recv: %02x\n", s->sr);
+                    /* indicate end of transfer */
+                    if (s->data_in_index >= s->data_in_size) {
+                        s->b = (s->b | TREQ);
+                    }
+                    s->ifr |= SR_INT;
+                    cuda_update_irq(s);
+                }
+            }
+        }
+    } else {
+        /* no transfer requested: handle sync case */
+        if ((s->last_b & TIP) && (s->b & TACK) != (s->last_b & TACK)) {
+            /* update TREQ state each time TACK change state */
+            if (s->b & TACK)
+                s->b = (s->b | TREQ);
+            else
+                s->b = (s->b & ~TREQ);
+            s->ifr |= SR_INT;
+            cuda_update_irq(s);
+        } else {
+            if (!(s->last_b & TIP)) {
+                /* handle end of host to cuda transfer */
+                packet_received = (s->data_out_index > 0);
+                /* always an IRQ at the end of transfer */
+                s->ifr |= SR_INT;
+                cuda_update_irq(s);
+            }
+            /* signal if there is data to read */
+            if (s->data_in_index < s->data_in_size) {
+                s->b = (s->b & ~TREQ);
+            }
+        }
+    }
+
+    s->last_acr = s->acr;
+    s->last_b = s->b;
+
+    /* NOTE: cuda_receive_packet_from_host() can call cuda_update()
+       recursively */
+    if (packet_received) {
+        len = s->data_out_index;
+        s->data_out_index = 0;
+        cuda_receive_packet_from_host(s, s->data_out, len);
+    }
+}
+
+static void cuda_send_packet_to_host(CUDAState *s,
+                                     const uint8_t *data, int len)
+{
+#ifdef DEBUG_CUDA_PACKET
+    {
+        int i;
+        printf("cuda_send_packet_to_host:\n");
+        for(i = 0; i < len; i++)
+            printf(" %02x", data[i]);
+        printf("\n");
+    }
+#endif
+    memcpy(s->data_in, data, len);
+    s->data_in_size = len;
+    s->data_in_index = 0;
+    cuda_update(s);
+    s->ifr |= SR_INT;
+    cuda_update_irq(s);
+}
+
+static void cuda_adb_poll(void *opaque)
+{
+    CUDAState *s = opaque;
+    uint8_t obuf[ADB_MAX_OUT_LEN + 2];
+    int olen;
+
+    olen = adb_poll(&s->adb_bus, obuf + 2);
+    if (olen > 0) {
+        obuf[0] = ADB_PACKET;
+        obuf[1] = 0x40; /* polled data */
+        cuda_send_packet_to_host(s, obuf, olen + 2);
+    }
+    qemu_mod_timer(s->adb_poll_timer,
+                   qemu_get_clock_ns(vm_clock) +
+                   (get_ticks_per_sec() / CUDA_ADB_POLL_FREQ));
+}
+
+static void cuda_receive_packet(CUDAState *s,
+                                const uint8_t *data, int len)
+{
+    uint8_t obuf[16];
+    int autopoll;
+    uint32_t ti;
+
+    switch(data[0]) {
+    case CUDA_AUTOPOLL:
+        autopoll = (data[1] != 0);
+        if (autopoll != s->autopoll) {
+            s->autopoll = autopoll;
+            if (autopoll) {
+                qemu_mod_timer(s->adb_poll_timer,
+                               qemu_get_clock_ns(vm_clock) +
+                               (get_ticks_per_sec() / CUDA_ADB_POLL_FREQ));
+            } else {
+                qemu_del_timer(s->adb_poll_timer);
+            }
+        }
+        obuf[0] = CUDA_PACKET;
+        obuf[1] = data[1];
+        cuda_send_packet_to_host(s, obuf, 2);
+        break;
+    case CUDA_SET_TIME:
+        ti = (((uint32_t)data[1]) << 24) + (((uint32_t)data[2]) << 16) + (((uint32_t)data[3]) << 8) + data[4];
+        s->tick_offset = ti - (qemu_get_clock_ns(vm_clock) / get_ticks_per_sec());
+        obuf[0] = CUDA_PACKET;
+        obuf[1] = 0;
+        obuf[2] = 0;
+        cuda_send_packet_to_host(s, obuf, 3);
+        break;
+    case CUDA_GET_TIME:
+        ti = s->tick_offset + (qemu_get_clock_ns(vm_clock) / get_ticks_per_sec());
+        obuf[0] = CUDA_PACKET;
+        obuf[1] = 0;
+        obuf[2] = 0;
+        obuf[3] = ti >> 24;
+        obuf[4] = ti >> 16;
+        obuf[5] = ti >> 8;
+        obuf[6] = ti;
+        cuda_send_packet_to_host(s, obuf, 7);
+        break;
+    case CUDA_FILE_SERVER_FLAG:
+    case CUDA_SET_DEVICE_LIST:
+    case CUDA_SET_AUTO_RATE:
+    case CUDA_SET_POWER_MESSAGES:
+        obuf[0] = CUDA_PACKET;
+        obuf[1] = 0;
+        cuda_send_packet_to_host(s, obuf, 2);
+        break;
+    case CUDA_POWERDOWN:
+        obuf[0] = CUDA_PACKET;
+        obuf[1] = 0;
+        cuda_send_packet_to_host(s, obuf, 2);
+        qemu_system_shutdown_request();
+        break;
+    case CUDA_RESET_SYSTEM:
+        obuf[0] = CUDA_PACKET;
+        obuf[1] = 0;
+        cuda_send_packet_to_host(s, obuf, 2);
+        qemu_system_reset_request();
+        break;
+    default:
+        break;
+    }
+}
+
+static void cuda_receive_packet_from_host(CUDAState *s,
+                                          const uint8_t *data, int len)
+{
+#ifdef DEBUG_CUDA_PACKET
+    {
+        int i;
+        printf("cuda_receive_packet_from_host:\n");
+        for(i = 0; i < len; i++)
+            printf(" %02x", data[i]);
+        printf("\n");
+    }
+#endif
+    switch(data[0]) {
+    case ADB_PACKET:
+        {
+            uint8_t obuf[ADB_MAX_OUT_LEN + 2];
+            int olen;
+            olen = adb_request(&s->adb_bus, obuf + 2, data + 1, len - 1);
+            if (olen > 0) {
+                obuf[0] = ADB_PACKET;
+                obuf[1] = 0x00;
+            } else {
+                /* error */
+                obuf[0] = ADB_PACKET;
+                obuf[1] = -olen;
+                olen = 0;
+            }
+            cuda_send_packet_to_host(s, obuf, olen + 2);
+        }
+        break;
+    case CUDA_PACKET:
+        cuda_receive_packet(s, data + 1, len - 1);
+        break;
+    }
+}
+
+static void cuda_writew (void *opaque, hwaddr addr, uint32_t value)
+{
+}
+
+static void cuda_writel (void *opaque, hwaddr addr, uint32_t value)
+{
+}
+
+static uint32_t cuda_readw (void *opaque, hwaddr addr)
+{
+    return 0;
+}
+
+static uint32_t cuda_readl (void *opaque, hwaddr addr)
+{
+    return 0;
+}
+
+static const MemoryRegionOps cuda_ops = {
+    .old_mmio = {
+        .write = {
+            cuda_writeb,
+            cuda_writew,
+            cuda_writel,
+        },
+        .read = {
+            cuda_readb,
+            cuda_readw,
+            cuda_readl,
+        },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static bool cuda_timer_exist(void *opaque, int version_id)
+{
+    CUDATimer *s = opaque;
+
+    return s->timer != NULL;
+}
+
+static const VMStateDescription vmstate_cuda_timer = {
+    .name = "cuda_timer",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT16(latch, CUDATimer),
+        VMSTATE_UINT16(counter_value, CUDATimer),
+        VMSTATE_INT64(load_time, CUDATimer),
+        VMSTATE_INT64(next_irq_time, CUDATimer),
+        VMSTATE_TIMER_TEST(timer, CUDATimer, cuda_timer_exist),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_cuda = {
+    .name = "cuda",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT8(a, CUDAState),
+        VMSTATE_UINT8(b, CUDAState),
+        VMSTATE_UINT8(dira, CUDAState),
+        VMSTATE_UINT8(dirb, CUDAState),
+        VMSTATE_UINT8(sr, CUDAState),
+        VMSTATE_UINT8(acr, CUDAState),
+        VMSTATE_UINT8(pcr, CUDAState),
+        VMSTATE_UINT8(ifr, CUDAState),
+        VMSTATE_UINT8(ier, CUDAState),
+        VMSTATE_UINT8(anh, CUDAState),
+        VMSTATE_INT32(data_in_size, CUDAState),
+        VMSTATE_INT32(data_in_index, CUDAState),
+        VMSTATE_INT32(data_out_index, CUDAState),
+        VMSTATE_UINT8(autopoll, CUDAState),
+        VMSTATE_BUFFER(data_in, CUDAState),
+        VMSTATE_BUFFER(data_out, CUDAState),
+        VMSTATE_UINT32(tick_offset, CUDAState),
+        VMSTATE_STRUCT_ARRAY(timers, CUDAState, 2, 1,
+                             vmstate_cuda_timer, CUDATimer),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void cuda_reset(DeviceState *dev)
+{
+    CUDAState *s = CUDA(dev);
+
+    s->b = 0;
+    s->a = 0;
+    s->dirb = 0;
+    s->dira = 0;
+    s->sr = 0;
+    s->acr = 0;
+    s->pcr = 0;
+    s->ifr = 0;
+    s->ier = 0;
+    //    s->ier = T1_INT | SR_INT;
+    s->anh = 0;
+    s->data_in_size = 0;
+    s->data_in_index = 0;
+    s->data_out_index = 0;
+    s->autopoll = 0;
+
+    s->timers[0].latch = 0xffff;
+    set_counter(s, &s->timers[0], 0xffff);
+
+    s->timers[1].latch = 0;
+    set_counter(s, &s->timers[1], 0xffff);
+}
+
+static void cuda_realizefn(DeviceState *dev, Error **errp)
+{
+    CUDAState *s = CUDA(dev);
+    struct tm tm;
+
+    s->timers[0].timer = qemu_new_timer_ns(vm_clock, cuda_timer1, s);
+
+    qemu_get_timedate(&tm, 0);
+    s->tick_offset = (uint32_t)mktimegm(&tm) + RTC_OFFSET;
+
+    s->adb_poll_timer = qemu_new_timer_ns(vm_clock, cuda_adb_poll, s);
+}
+
+static void cuda_initfn(Object *obj)
+{
+    SysBusDevice *d = SYS_BUS_DEVICE(obj);
+    CUDAState *s = CUDA(obj);
+    int i;
+
+    memory_region_init_io(&s->mem, &cuda_ops, s, "cuda", 0x2000);
+    sysbus_init_mmio(d, &s->mem);
+    sysbus_init_irq(d, &s->irq);
+
+    for (i = 0; i < ARRAY_SIZE(s->timers); i++) {
+        s->timers[i].index = i;
+    }
+
+    qbus_create_inplace((BusState *)&s->adb_bus, TYPE_ADB_BUS, DEVICE(obj),
+                        "adb.0");
+}
+
+static void cuda_class_init(ObjectClass *oc, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(oc);
+
+    dc->realize = cuda_realizefn;
+    dc->reset = cuda_reset;
+    dc->vmsd = &vmstate_cuda;
+}
+
+static const TypeInfo cuda_type_info = {
+    .name = TYPE_CUDA,
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(CUDAState),
+    .instance_init = cuda_initfn,
+    .class_init = cuda_class_init,
+};
+
+static void cuda_register_types(void)
+{
+    type_register_static(&cuda_type_info);
+}
+
+type_init(cuda_register_types)
diff --git a/hw/misc/macio/mac_dbdma.c b/hw/misc/macio/mac_dbdma.c
new file mode 100644 (file)
index 0000000..a2363bb
--- /dev/null
@@ -0,0 +1,859 @@
+/*
+ * PowerMac descriptor-based DMA emulation
+ *
+ * Copyright (c) 2005-2007 Fabrice Bellard
+ * Copyright (c) 2007 Jocelyn Mayer
+ * Copyright (c) 2009 Laurent Vivier
+ *
+ * some parts from linux-2.6.28, arch/powerpc/include/asm/dbdma.h
+ *
+ *   Definitions for using the Apple Descriptor-Based DMA controller
+ *   in Power Macintosh computers.
+ *
+ *   Copyright (C) 1996 Paul Mackerras.
+ *
+ * some parts from mol 0.9.71
+ *
+ *   Descriptor based DMA emulation
+ *
+ *   Copyright (C) 1998-2004 Samuel Rydh (samuel@ibrium.se)
+ *
+ * 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 "hw/hw.h"
+#include "hw/isa/isa.h"
+#include "hw/ppc/mac_dbdma.h"
+#include "qemu/main-loop.h"
+
+/* debug DBDMA */
+//#define DEBUG_DBDMA
+
+#ifdef DEBUG_DBDMA
+#define DBDMA_DPRINTF(fmt, ...)                                 \
+    do { printf("DBDMA: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DBDMA_DPRINTF(fmt, ...)
+#endif
+
+/*
+ */
+
+/*
+ * DBDMA control/status registers.  All little-endian.
+ */
+
+#define DBDMA_CONTROL         0x00
+#define DBDMA_STATUS          0x01
+#define DBDMA_CMDPTR_HI       0x02
+#define DBDMA_CMDPTR_LO       0x03
+#define DBDMA_INTR_SEL        0x04
+#define DBDMA_BRANCH_SEL      0x05
+#define DBDMA_WAIT_SEL        0x06
+#define DBDMA_XFER_MODE       0x07
+#define DBDMA_DATA2PTR_HI     0x08
+#define DBDMA_DATA2PTR_LO     0x09
+#define DBDMA_RES1            0x0A
+#define DBDMA_ADDRESS_HI      0x0B
+#define DBDMA_BRANCH_ADDR_HI  0x0C
+#define DBDMA_RES2            0x0D
+#define DBDMA_RES3            0x0E
+#define DBDMA_RES4            0x0F
+
+#define DBDMA_REGS            16
+#define DBDMA_SIZE            (DBDMA_REGS * sizeof(uint32_t))
+
+#define DBDMA_CHANNEL_SHIFT   7
+#define DBDMA_CHANNEL_SIZE    (1 << DBDMA_CHANNEL_SHIFT)
+
+#define DBDMA_CHANNELS        (0x1000 >> DBDMA_CHANNEL_SHIFT)
+
+/* Bits in control and status registers */
+
+#define RUN    0x8000
+#define PAUSE  0x4000
+#define FLUSH  0x2000
+#define WAKE   0x1000
+#define DEAD   0x0800
+#define ACTIVE 0x0400
+#define BT     0x0100
+#define DEVSTAT        0x00ff
+
+/*
+ * DBDMA command structure.  These fields are all little-endian!
+ */
+
+typedef struct dbdma_cmd {
+    uint16_t req_count;          /* requested byte transfer count */
+    uint16_t command;    /* command word (has bit-fields) */
+    uint32_t phy_addr;   /* physical data address */
+    uint32_t cmd_dep;    /* command-dependent field */
+    uint16_t res_count;          /* residual count after completion */
+    uint16_t xfer_status; /* transfer status */
+} dbdma_cmd;
+
+/* DBDMA command values in command field */
+
+#define COMMAND_MASK    0xf000
+#define OUTPUT_MORE    0x0000  /* transfer memory data to stream */
+#define OUTPUT_LAST    0x1000  /* ditto followed by end marker */
+#define INPUT_MORE     0x2000  /* transfer stream data to memory */
+#define INPUT_LAST     0x3000  /* ditto, expect end marker */
+#define STORE_WORD     0x4000  /* write word (4 bytes) to device reg */
+#define LOAD_WORD      0x5000  /* read word (4 bytes) from device reg */
+#define DBDMA_NOP      0x6000  /* do nothing */
+#define DBDMA_STOP     0x7000  /* suspend processing */
+
+/* Key values in command field */
+
+#define KEY_MASK        0x0700
+#define KEY_STREAM0    0x0000  /* usual data stream */
+#define KEY_STREAM1    0x0100  /* control/status stream */
+#define KEY_STREAM2    0x0200  /* device-dependent stream */
+#define KEY_STREAM3    0x0300  /* device-dependent stream */
+#define KEY_STREAM4    0x0400  /* reserved */
+#define KEY_REGS       0x0500  /* device register space */
+#define KEY_SYSTEM     0x0600  /* system memory-mapped space */
+#define KEY_DEVICE     0x0700  /* device memory-mapped space */
+
+/* Interrupt control values in command field */
+
+#define INTR_MASK       0x0030
+#define INTR_NEVER     0x0000  /* don't interrupt */
+#define INTR_IFSET     0x0010  /* intr if condition bit is 1 */
+#define INTR_IFCLR     0x0020  /* intr if condition bit is 0 */
+#define INTR_ALWAYS    0x0030  /* always interrupt */
+
+/* Branch control values in command field */
+
+#define BR_MASK         0x000c
+#define BR_NEVER       0x0000  /* don't branch */
+#define BR_IFSET       0x0004  /* branch if condition bit is 1 */
+#define BR_IFCLR       0x0008  /* branch if condition bit is 0 */
+#define BR_ALWAYS      0x000c  /* always branch */
+
+/* Wait control values in command field */
+
+#define WAIT_MASK       0x0003
+#define WAIT_NEVER     0x0000  /* don't wait */
+#define WAIT_IFSET     0x0001  /* wait if condition bit is 1 */
+#define WAIT_IFCLR     0x0002  /* wait if condition bit is 0 */
+#define WAIT_ALWAYS    0x0003  /* always wait */
+
+typedef struct DBDMA_channel {
+    int channel;
+    uint32_t regs[DBDMA_REGS];
+    qemu_irq irq;
+    DBDMA_io io;
+    DBDMA_rw rw;
+    DBDMA_flush flush;
+    dbdma_cmd current;
+    int processing;
+} DBDMA_channel;
+
+typedef struct {
+    MemoryRegion mem;
+    DBDMA_channel channels[DBDMA_CHANNELS];
+} DBDMAState;
+
+#ifdef DEBUG_DBDMA
+static void dump_dbdma_cmd(dbdma_cmd *cmd)
+{
+    printf("dbdma_cmd %p\n", cmd);
+    printf("    req_count 0x%04x\n", le16_to_cpu(cmd->req_count));
+    printf("    command 0x%04x\n", le16_to_cpu(cmd->command));
+    printf("    phy_addr 0x%08x\n", le32_to_cpu(cmd->phy_addr));
+    printf("    cmd_dep 0x%08x\n", le32_to_cpu(cmd->cmd_dep));
+    printf("    res_count 0x%04x\n", le16_to_cpu(cmd->res_count));
+    printf("    xfer_status 0x%04x\n", le16_to_cpu(cmd->xfer_status));
+}
+#else
+static void dump_dbdma_cmd(dbdma_cmd *cmd)
+{
+}
+#endif
+static void dbdma_cmdptr_load(DBDMA_channel *ch)
+{
+    DBDMA_DPRINTF("dbdma_cmdptr_load 0x%08x\n",
+                  ch->regs[DBDMA_CMDPTR_LO]);
+    cpu_physical_memory_read(ch->regs[DBDMA_CMDPTR_LO],
+                             (uint8_t*)&ch->current, sizeof(dbdma_cmd));
+}
+
+static void dbdma_cmdptr_save(DBDMA_channel *ch)
+{
+    DBDMA_DPRINTF("dbdma_cmdptr_save 0x%08x\n",
+                  ch->regs[DBDMA_CMDPTR_LO]);
+    DBDMA_DPRINTF("xfer_status 0x%08x res_count 0x%04x\n",
+                  le16_to_cpu(ch->current.xfer_status),
+                  le16_to_cpu(ch->current.res_count));
+    cpu_physical_memory_write(ch->regs[DBDMA_CMDPTR_LO],
+                              (uint8_t*)&ch->current, sizeof(dbdma_cmd));
+}
+
+static void kill_channel(DBDMA_channel *ch)
+{
+    DBDMA_DPRINTF("kill_channel\n");
+
+    ch->regs[DBDMA_STATUS] |= DEAD;
+    ch->regs[DBDMA_STATUS] &= ~ACTIVE;
+
+    qemu_irq_raise(ch->irq);
+}
+
+static void conditional_interrupt(DBDMA_channel *ch)
+{
+    dbdma_cmd *current = &ch->current;
+    uint16_t intr;
+    uint16_t sel_mask, sel_value;
+    uint32_t status;
+    int cond;
+
+    DBDMA_DPRINTF("conditional_interrupt\n");
+
+    intr = le16_to_cpu(current->command) & INTR_MASK;
+
+    switch(intr) {
+    case INTR_NEVER:  /* don't interrupt */
+        return;
+    case INTR_ALWAYS: /* always interrupt */
+        qemu_irq_raise(ch->irq);
+        return;
+    }
+
+    status = ch->regs[DBDMA_STATUS] & DEVSTAT;
+
+    sel_mask = (ch->regs[DBDMA_INTR_SEL] >> 16) & 0x0f;
+    sel_value = ch->regs[DBDMA_INTR_SEL] & 0x0f;
+
+    cond = (status & sel_mask) == (sel_value & sel_mask);
+
+    switch(intr) {
+    case INTR_IFSET:  /* intr if condition bit is 1 */
+        if (cond)
+            qemu_irq_raise(ch->irq);
+        return;
+    case INTR_IFCLR:  /* intr if condition bit is 0 */
+        if (!cond)
+            qemu_irq_raise(ch->irq);
+        return;
+    }
+}
+
+static int conditional_wait(DBDMA_channel *ch)
+{
+    dbdma_cmd *current = &ch->current;
+    uint16_t wait;
+    uint16_t sel_mask, sel_value;
+    uint32_t status;
+    int cond;
+
+    DBDMA_DPRINTF("conditional_wait\n");
+
+    wait = le16_to_cpu(current->command) & WAIT_MASK;
+
+    switch(wait) {
+    case WAIT_NEVER:  /* don't wait */
+        return 0;
+    case WAIT_ALWAYS: /* always wait */
+        return 1;
+    }
+
+    status = ch->regs[DBDMA_STATUS] & DEVSTAT;
+
+    sel_mask = (ch->regs[DBDMA_WAIT_SEL] >> 16) & 0x0f;
+    sel_value = ch->regs[DBDMA_WAIT_SEL] & 0x0f;
+
+    cond = (status & sel_mask) == (sel_value & sel_mask);
+
+    switch(wait) {
+    case WAIT_IFSET:  /* wait if condition bit is 1 */
+        if (cond)
+            return 1;
+        return 0;
+    case WAIT_IFCLR:  /* wait if condition bit is 0 */
+        if (!cond)
+            return 1;
+        return 0;
+    }
+    return 0;
+}
+
+static void next(DBDMA_channel *ch)
+{
+    uint32_t cp;
+
+    ch->regs[DBDMA_STATUS] &= ~BT;
+
+    cp = ch->regs[DBDMA_CMDPTR_LO];
+    ch->regs[DBDMA_CMDPTR_LO] = cp + sizeof(dbdma_cmd);
+    dbdma_cmdptr_load(ch);
+}
+
+static void branch(DBDMA_channel *ch)
+{
+    dbdma_cmd *current = &ch->current;
+
+    ch->regs[DBDMA_CMDPTR_LO] = current->cmd_dep;
+    ch->regs[DBDMA_STATUS] |= BT;
+    dbdma_cmdptr_load(ch);
+}
+
+static void conditional_branch(DBDMA_channel *ch)
+{
+    dbdma_cmd *current = &ch->current;
+    uint16_t br;
+    uint16_t sel_mask, sel_value;
+    uint32_t status;
+    int cond;
+
+    DBDMA_DPRINTF("conditional_branch\n");
+
+    /* check if we must branch */
+
+    br = le16_to_cpu(current->command) & BR_MASK;
+
+    switch(br) {
+    case BR_NEVER:  /* don't branch */
+        next(ch);
+        return;
+    case BR_ALWAYS: /* always branch */
+        branch(ch);
+        return;
+    }
+
+    status = ch->regs[DBDMA_STATUS] & DEVSTAT;
+
+    sel_mask = (ch->regs[DBDMA_BRANCH_SEL] >> 16) & 0x0f;
+    sel_value = ch->regs[DBDMA_BRANCH_SEL] & 0x0f;
+
+    cond = (status & sel_mask) == (sel_value & sel_mask);
+
+    switch(br) {
+    case BR_IFSET:  /* branch if condition bit is 1 */
+        if (cond)
+            branch(ch);
+        else
+            next(ch);
+        return;
+    case BR_IFCLR:  /* branch if condition bit is 0 */
+        if (!cond)
+            branch(ch);
+        else
+            next(ch);
+        return;
+    }
+}
+
+static QEMUBH *dbdma_bh;
+static void channel_run(DBDMA_channel *ch);
+
+static void dbdma_end(DBDMA_io *io)
+{
+    DBDMA_channel *ch = io->channel;
+    dbdma_cmd *current = &ch->current;
+
+    if (conditional_wait(ch))
+        goto wait;
+
+    current->xfer_status = cpu_to_le16(ch->regs[DBDMA_STATUS]);
+    current->res_count = cpu_to_le16(io->len);
+    dbdma_cmdptr_save(ch);
+    if (io->is_last)
+        ch->regs[DBDMA_STATUS] &= ~FLUSH;
+
+    conditional_interrupt(ch);
+    conditional_branch(ch);
+
+wait:
+    ch->processing = 0;
+    if ((ch->regs[DBDMA_STATUS] & RUN) &&
+        (ch->regs[DBDMA_STATUS] & ACTIVE))
+        channel_run(ch);
+}
+
+static void start_output(DBDMA_channel *ch, int key, uint32_t addr,
+                        uint16_t req_count, int is_last)
+{
+    DBDMA_DPRINTF("start_output\n");
+
+    /* KEY_REGS, KEY_DEVICE and KEY_STREAM
+     * are not implemented in the mac-io chip
+     */
+
+    DBDMA_DPRINTF("addr 0x%x key 0x%x\n", addr, key);
+    if (!addr || key > KEY_STREAM3) {
+        kill_channel(ch);
+        return;
+    }
+
+    ch->io.addr = addr;
+    ch->io.len = req_count;
+    ch->io.is_last = is_last;
+    ch->io.dma_end = dbdma_end;
+    ch->io.is_dma_out = 1;
+    ch->processing = 1;
+    if (ch->rw) {
+        ch->rw(&ch->io);
+    }
+}
+
+static void start_input(DBDMA_channel *ch, int key, uint32_t addr,
+                       uint16_t req_count, int is_last)
+{
+    DBDMA_DPRINTF("start_input\n");
+
+    /* KEY_REGS, KEY_DEVICE and KEY_STREAM
+     * are not implemented in the mac-io chip
+     */
+
+    if (!addr || key > KEY_STREAM3) {
+        kill_channel(ch);
+        return;
+    }
+
+    ch->io.addr = addr;
+    ch->io.len = req_count;
+    ch->io.is_last = is_last;
+    ch->io.dma_end = dbdma_end;
+    ch->io.is_dma_out = 0;
+    ch->processing = 1;
+    if (ch->rw) {
+        ch->rw(&ch->io);
+    }
+}
+
+static void load_word(DBDMA_channel *ch, int key, uint32_t addr,
+                     uint16_t len)
+{
+    dbdma_cmd *current = &ch->current;
+    uint32_t val;
+
+    DBDMA_DPRINTF("load_word\n");
+
+    /* only implements KEY_SYSTEM */
+
+    if (key != KEY_SYSTEM) {
+        printf("DBDMA: LOAD_WORD, unimplemented key %x\n", key);
+        kill_channel(ch);
+        return;
+    }
+
+    cpu_physical_memory_read(addr, (uint8_t*)&val, len);
+
+    if (len == 2)
+        val = (val << 16) | (current->cmd_dep & 0x0000ffff);
+    else if (len == 1)
+        val = (val << 24) | (current->cmd_dep & 0x00ffffff);
+
+    current->cmd_dep = val;
+
+    if (conditional_wait(ch))
+        goto wait;
+
+    current->xfer_status = cpu_to_le16(ch->regs[DBDMA_STATUS]);
+    dbdma_cmdptr_save(ch);
+    ch->regs[DBDMA_STATUS] &= ~FLUSH;
+
+    conditional_interrupt(ch);
+    next(ch);
+
+wait:
+    qemu_bh_schedule(dbdma_bh);
+}
+
+static void store_word(DBDMA_channel *ch, int key, uint32_t addr,
+                      uint16_t len)
+{
+    dbdma_cmd *current = &ch->current;
+    uint32_t val;
+
+    DBDMA_DPRINTF("store_word\n");
+
+    /* only implements KEY_SYSTEM */
+
+    if (key != KEY_SYSTEM) {
+        printf("DBDMA: STORE_WORD, unimplemented key %x\n", key);
+        kill_channel(ch);
+        return;
+    }
+
+    val = current->cmd_dep;
+    if (len == 2)
+        val >>= 16;
+    else if (len == 1)
+        val >>= 24;
+
+    cpu_physical_memory_write(addr, (uint8_t*)&val, len);
+
+    if (conditional_wait(ch))
+        goto wait;
+
+    current->xfer_status = cpu_to_le16(ch->regs[DBDMA_STATUS]);
+    dbdma_cmdptr_save(ch);
+    ch->regs[DBDMA_STATUS] &= ~FLUSH;
+
+    conditional_interrupt(ch);
+    next(ch);
+
+wait:
+    qemu_bh_schedule(dbdma_bh);
+}
+
+static void nop(DBDMA_channel *ch)
+{
+    dbdma_cmd *current = &ch->current;
+
+    if (conditional_wait(ch))
+        goto wait;
+
+    current->xfer_status = cpu_to_le16(ch->regs[DBDMA_STATUS]);
+    dbdma_cmdptr_save(ch);
+
+    conditional_interrupt(ch);
+    conditional_branch(ch);
+
+wait:
+    qemu_bh_schedule(dbdma_bh);
+}
+
+static void stop(DBDMA_channel *ch)
+{
+    ch->regs[DBDMA_STATUS] &= ~(ACTIVE|DEAD|FLUSH);
+
+    /* the stop command does not increment command pointer */
+}
+
+static void channel_run(DBDMA_channel *ch)
+{
+    dbdma_cmd *current = &ch->current;
+    uint16_t cmd, key;
+    uint16_t req_count;
+    uint32_t phy_addr;
+
+    DBDMA_DPRINTF("channel_run\n");
+    dump_dbdma_cmd(current);
+
+    /* clear WAKE flag at command fetch */
+
+    ch->regs[DBDMA_STATUS] &= ~WAKE;
+
+    cmd = le16_to_cpu(current->command) & COMMAND_MASK;
+
+    switch (cmd) {
+    case DBDMA_NOP:
+        nop(ch);
+       return;
+
+    case DBDMA_STOP:
+        stop(ch);
+       return;
+    }
+
+    key = le16_to_cpu(current->command) & 0x0700;
+    req_count = le16_to_cpu(current->req_count);
+    phy_addr = le32_to_cpu(current->phy_addr);
+
+    if (key == KEY_STREAM4) {
+        printf("command %x, invalid key 4\n", cmd);
+        kill_channel(ch);
+        return;
+    }
+
+    switch (cmd) {
+    case OUTPUT_MORE:
+        start_output(ch, key, phy_addr, req_count, 0);
+       return;
+
+    case OUTPUT_LAST:
+        start_output(ch, key, phy_addr, req_count, 1);
+       return;
+
+    case INPUT_MORE:
+        start_input(ch, key, phy_addr, req_count, 0);
+       return;
+
+    case INPUT_LAST:
+        start_input(ch, key, phy_addr, req_count, 1);
+       return;
+    }
+
+    if (key < KEY_REGS) {
+        printf("command %x, invalid key %x\n", cmd, key);
+        key = KEY_SYSTEM;
+    }
+
+    /* for LOAD_WORD and STORE_WORD, req_count is on 3 bits
+     * and BRANCH is invalid
+     */
+
+    req_count = req_count & 0x0007;
+    if (req_count & 0x4) {
+        req_count = 4;
+        phy_addr &= ~3;
+    } else if (req_count & 0x2) {
+        req_count = 2;
+        phy_addr &= ~1;
+    } else
+        req_count = 1;
+
+    switch (cmd) {
+    case LOAD_WORD:
+        load_word(ch, key, phy_addr, req_count);
+       return;
+
+    case STORE_WORD:
+        store_word(ch, key, phy_addr, req_count);
+       return;
+    }
+}
+
+static void DBDMA_run(DBDMAState *s)
+{
+    int channel;
+
+    for (channel = 0; channel < DBDMA_CHANNELS; channel++) {
+        DBDMA_channel *ch = &s->channels[channel];
+        uint32_t status = ch->regs[DBDMA_STATUS];
+        if (!ch->processing && (status & RUN) && (status & ACTIVE)) {
+            channel_run(ch);
+        }
+    }
+}
+
+static void DBDMA_run_bh(void *opaque)
+{
+    DBDMAState *s = opaque;
+
+    DBDMA_DPRINTF("DBDMA_run_bh\n");
+
+    DBDMA_run(s);
+}
+
+void DBDMA_register_channel(void *dbdma, int nchan, qemu_irq irq,
+                            DBDMA_rw rw, DBDMA_flush flush,
+                            void *opaque)
+{
+    DBDMAState *s = dbdma;
+    DBDMA_channel *ch = &s->channels[nchan];
+
+    DBDMA_DPRINTF("DBDMA_register_channel 0x%x\n", nchan);
+
+    ch->irq = irq;
+    ch->channel = nchan;
+    ch->rw = rw;
+    ch->flush = flush;
+    ch->io.opaque = opaque;
+    ch->io.channel = ch;
+}
+
+static void
+dbdma_control_write(DBDMA_channel *ch)
+{
+    uint16_t mask, value;
+    uint32_t status;
+
+    mask = (ch->regs[DBDMA_CONTROL] >> 16) & 0xffff;
+    value = ch->regs[DBDMA_CONTROL] & 0xffff;
+
+    value &= (RUN | PAUSE | FLUSH | WAKE | DEVSTAT);
+
+    status = ch->regs[DBDMA_STATUS];
+
+    status = (value & mask) | (status & ~mask);
+
+    if (status & WAKE)
+        status |= ACTIVE;
+    if (status & RUN) {
+        status |= ACTIVE;
+        status &= ~DEAD;
+    }
+    if (status & PAUSE)
+        status &= ~ACTIVE;
+    if ((ch->regs[DBDMA_STATUS] & RUN) && !(status & RUN)) {
+        /* RUN is cleared */
+        status &= ~(ACTIVE|DEAD);
+        if ((status & FLUSH) && ch->flush) {
+            ch->flush(&ch->io);
+            status &= ~FLUSH;
+        }
+    }
+
+    DBDMA_DPRINTF("    status 0x%08x\n", status);
+
+    ch->regs[DBDMA_STATUS] = status;
+
+    if (status & ACTIVE)
+        qemu_bh_schedule(dbdma_bh);
+    if ((status & FLUSH) && ch->flush)
+        ch->flush(&ch->io);
+}
+
+static void dbdma_write(void *opaque, hwaddr addr,
+                        uint64_t value, unsigned size)
+{
+    int channel = addr >> DBDMA_CHANNEL_SHIFT;
+    DBDMAState *s = opaque;
+    DBDMA_channel *ch = &s->channels[channel];
+    int reg = (addr - (channel << DBDMA_CHANNEL_SHIFT)) >> 2;
+
+    DBDMA_DPRINTF("writel 0x" TARGET_FMT_plx " <= 0x%08x\n", addr, value);
+    DBDMA_DPRINTF("channel 0x%x reg 0x%x\n",
+                  (uint32_t)addr >> DBDMA_CHANNEL_SHIFT, reg);
+
+    /* cmdptr cannot be modified if channel is RUN or ACTIVE */
+
+    if (reg == DBDMA_CMDPTR_LO &&
+        (ch->regs[DBDMA_STATUS] & (RUN | ACTIVE)))
+       return;
+
+    ch->regs[reg] = value;
+
+    switch(reg) {
+    case DBDMA_CONTROL:
+        dbdma_control_write(ch);
+        break;
+    case DBDMA_CMDPTR_LO:
+        /* 16-byte aligned */
+        ch->regs[DBDMA_CMDPTR_LO] &= ~0xf;
+        dbdma_cmdptr_load(ch);
+        break;
+    case DBDMA_STATUS:
+    case DBDMA_INTR_SEL:
+    case DBDMA_BRANCH_SEL:
+    case DBDMA_WAIT_SEL:
+        /* nothing to do */
+        break;
+    case DBDMA_XFER_MODE:
+    case DBDMA_CMDPTR_HI:
+    case DBDMA_DATA2PTR_HI:
+    case DBDMA_DATA2PTR_LO:
+    case DBDMA_ADDRESS_HI:
+    case DBDMA_BRANCH_ADDR_HI:
+    case DBDMA_RES1:
+    case DBDMA_RES2:
+    case DBDMA_RES3:
+    case DBDMA_RES4:
+        /* unused */
+        break;
+    }
+}
+
+static uint64_t dbdma_read(void *opaque, hwaddr addr,
+                           unsigned size)
+{
+    uint32_t value;
+    int channel = addr >> DBDMA_CHANNEL_SHIFT;
+    DBDMAState *s = opaque;
+    DBDMA_channel *ch = &s->channels[channel];
+    int reg = (addr - (channel << DBDMA_CHANNEL_SHIFT)) >> 2;
+
+    value = ch->regs[reg];
+
+    DBDMA_DPRINTF("readl 0x" TARGET_FMT_plx " => 0x%08x\n", addr, value);
+    DBDMA_DPRINTF("channel 0x%x reg 0x%x\n",
+                  (uint32_t)addr >> DBDMA_CHANNEL_SHIFT, reg);
+
+    switch(reg) {
+    case DBDMA_CONTROL:
+        value = 0;
+        break;
+    case DBDMA_STATUS:
+    case DBDMA_CMDPTR_LO:
+    case DBDMA_INTR_SEL:
+    case DBDMA_BRANCH_SEL:
+    case DBDMA_WAIT_SEL:
+        /* nothing to do */
+        break;
+    case DBDMA_XFER_MODE:
+    case DBDMA_CMDPTR_HI:
+    case DBDMA_DATA2PTR_HI:
+    case DBDMA_DATA2PTR_LO:
+    case DBDMA_ADDRESS_HI:
+    case DBDMA_BRANCH_ADDR_HI:
+        /* unused */
+        value = 0;
+        break;
+    case DBDMA_RES1:
+    case DBDMA_RES2:
+    case DBDMA_RES3:
+    case DBDMA_RES4:
+        /* reserved */
+        break;
+    }
+
+    return value;
+}
+
+static const MemoryRegionOps dbdma_ops = {
+    .read = dbdma_read,
+    .write = dbdma_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static const VMStateDescription vmstate_dbdma_channel = {
+    .name = "dbdma_channel",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(regs, struct DBDMA_channel, DBDMA_REGS),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_dbdma = {
+    .name = "dbdma",
+    .version_id = 2,
+    .minimum_version_id = 2,
+    .minimum_version_id_old = 2,
+    .fields      = (VMStateField[]) {
+        VMSTATE_STRUCT_ARRAY(channels, DBDMAState, DBDMA_CHANNELS, 1,
+                             vmstate_dbdma_channel, DBDMA_channel),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void dbdma_reset(void *opaque)
+{
+    DBDMAState *s = opaque;
+    int i;
+
+    for (i = 0; i < DBDMA_CHANNELS; i++)
+        memset(s->channels[i].regs, 0, DBDMA_SIZE);
+}
+
+void* DBDMA_init (MemoryRegion **dbdma_mem)
+{
+    DBDMAState *s;
+
+    s = g_malloc0(sizeof(DBDMAState));
+
+    memory_region_init_io(&s->mem, &dbdma_ops, s, "dbdma", 0x1000);
+    *dbdma_mem = &s->mem;
+    vmstate_register(NULL, -1, &vmstate_dbdma, s);
+    qemu_register_reset(dbdma_reset, s);
+
+    dbdma_bh = qemu_bh_new(DBDMA_run_bh, s);
+
+    return s;
+}
diff --git a/hw/misc/macio/macio.c b/hw/misc/macio/macio.c
new file mode 100644 (file)
index 0000000..2f389dd
--- /dev/null
@@ -0,0 +1,305 @@
+/*
+ * PowerMac MacIO device emulation
+ *
+ * Copyright (c) 2005-2007 Fabrice Bellard
+ * Copyright (c) 2007 Jocelyn Mayer
+ *
+ * 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 "hw/hw.h"
+#include "hw/ppc/mac.h"
+#include "hw/pci/pci.h"
+#include "hw/ppc/mac_dbdma.h"
+#include "hw/char/escc.h"
+
+#define TYPE_MACIO "macio"
+#define MACIO(obj) OBJECT_CHECK(MacIOState, (obj), TYPE_MACIO)
+
+typedef struct MacIOState
+{
+    /*< private >*/
+    PCIDevice parent;
+    /*< public >*/
+
+    MemoryRegion bar;
+    CUDAState cuda;
+    void *dbdma;
+    MemoryRegion *pic_mem;
+    MemoryRegion *escc_mem;
+} MacIOState;
+
+#define OLDWORLD_MACIO(obj) \
+    OBJECT_CHECK(OldWorldMacIOState, (obj), TYPE_OLDWORLD_MACIO)
+
+typedef struct OldWorldMacIOState {
+    /*< private >*/
+    MacIOState parent_obj;
+    /*< public >*/
+
+    qemu_irq irqs[3];
+
+    MacIONVRAMState nvram;
+    MACIOIDEState ide;
+} OldWorldMacIOState;
+
+#define NEWWORLD_MACIO(obj) \
+    OBJECT_CHECK(NewWorldMacIOState, (obj), TYPE_NEWWORLD_MACIO)
+
+typedef struct NewWorldMacIOState {
+    /*< private >*/
+    MacIOState parent_obj;
+    /*< public >*/
+    qemu_irq irqs[5];
+    MACIOIDEState ide[2];
+} NewWorldMacIOState;
+
+static void macio_bar_setup(MacIOState *macio_state)
+{
+    MemoryRegion *bar = &macio_state->bar;
+
+    if (macio_state->escc_mem) {
+        memory_region_add_subregion(bar, 0x13000, macio_state->escc_mem);
+    }
+}
+
+static int macio_common_initfn(PCIDevice *d)
+{
+    MacIOState *s = MACIO(d);
+    SysBusDevice *sysbus_dev;
+    int ret;
+
+    d->config[0x3d] = 0x01; // interrupt on pin 1
+
+    ret = qdev_init(DEVICE(&s->cuda));
+    if (ret < 0) {
+        return ret;
+    }
+    sysbus_dev = SYS_BUS_DEVICE(&s->cuda);
+    memory_region_add_subregion(&s->bar, 0x16000,
+                                sysbus_mmio_get_region(sysbus_dev, 0));
+
+    macio_bar_setup(s);
+    pci_register_bar(d, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar);
+
+    return 0;
+}
+
+static int macio_oldworld_initfn(PCIDevice *d)
+{
+    MacIOState *s = MACIO(d);
+    OldWorldMacIOState *os = OLDWORLD_MACIO(d);
+    SysBusDevice *sysbus_dev;
+    int ret = macio_common_initfn(d);
+    if (ret < 0) {
+        return ret;
+    }
+
+    sysbus_dev = SYS_BUS_DEVICE(&s->cuda);
+    sysbus_connect_irq(sysbus_dev, 0, os->irqs[0]);
+
+    ret = qdev_init(DEVICE(&os->nvram));
+    if (ret < 0) {
+        return ret;
+    }
+    sysbus_dev = SYS_BUS_DEVICE(&os->nvram);
+    memory_region_add_subregion(&s->bar, 0x60000,
+                                sysbus_mmio_get_region(sysbus_dev, 0));
+    pmac_format_nvram_partition(&os->nvram, os->nvram.size);
+
+    if (s->pic_mem) {
+        /* Heathrow PIC */
+        memory_region_add_subregion(&s->bar, 0x00000, s->pic_mem);
+    }
+
+    sysbus_dev = SYS_BUS_DEVICE(&os->ide);
+    sysbus_connect_irq(sysbus_dev, 0, os->irqs[1]);
+    sysbus_connect_irq(sysbus_dev, 1, os->irqs[2]);
+    macio_ide_register_dma(&os->ide, s->dbdma, 0x16);
+    ret = qdev_init(DEVICE(&os->ide));
+    if (ret < 0) {
+        return ret;
+    }
+
+    return 0;
+}
+
+static void macio_oldworld_init(Object *obj)
+{
+    MacIOState *s = MACIO(obj);
+    OldWorldMacIOState *os = OLDWORLD_MACIO(obj);
+    DeviceState *dev;
+
+    qdev_init_gpio_out(DEVICE(obj), os->irqs, ARRAY_SIZE(os->irqs));
+
+    object_initialize(&os->nvram, TYPE_MACIO_NVRAM);
+    dev = DEVICE(&os->nvram);
+    qdev_prop_set_uint32(dev, "size", 0x2000);
+    qdev_prop_set_uint32(dev, "it_shift", 4);
+
+    object_initialize(&os->ide, TYPE_MACIO_IDE);
+    qdev_set_parent_bus(DEVICE(&os->ide), sysbus_get_default());
+    memory_region_add_subregion(&s->bar, 0x1f000 + (1 * 0x1000), &os->ide.mem);
+    object_property_add_child(obj, "ide", OBJECT(&os->ide), NULL);
+}
+
+static int macio_newworld_initfn(PCIDevice *d)
+{
+    MacIOState *s = MACIO(d);
+    NewWorldMacIOState *ns = NEWWORLD_MACIO(d);
+    SysBusDevice *sysbus_dev;
+    int ret = macio_common_initfn(d);
+    if (ret < 0) {
+        return ret;
+    }
+
+    sysbus_dev = SYS_BUS_DEVICE(&s->cuda);
+    sysbus_connect_irq(sysbus_dev, 0, ns->irqs[0]);
+
+    if (s->pic_mem) {
+        /* OpenPIC */
+        memory_region_add_subregion(&s->bar, 0x40000, s->pic_mem);
+    }
+
+    sysbus_dev = SYS_BUS_DEVICE(&ns->ide[0]);
+    sysbus_connect_irq(sysbus_dev, 0, ns->irqs[1]);
+    sysbus_connect_irq(sysbus_dev, 1, ns->irqs[2]);
+    macio_ide_register_dma(&ns->ide[0], s->dbdma, 0x16);
+    ret = qdev_init(DEVICE(&ns->ide[0]));
+    if (ret < 0) {
+        return ret;
+    }
+
+    sysbus_dev = SYS_BUS_DEVICE(&ns->ide[1]);
+    sysbus_connect_irq(sysbus_dev, 0, ns->irqs[3]);
+    sysbus_connect_irq(sysbus_dev, 1, ns->irqs[4]);
+    macio_ide_register_dma(&ns->ide[1], s->dbdma, 0x1a);
+    ret = qdev_init(DEVICE(&ns->ide[1]));
+    if (ret < 0) {
+        return ret;
+    }
+
+    return 0;
+}
+
+static void macio_newworld_init(Object *obj)
+{
+    MacIOState *s = MACIO(obj);
+    NewWorldMacIOState *ns = NEWWORLD_MACIO(obj);
+    int i;
+    gchar *name;
+
+    qdev_init_gpio_out(DEVICE(obj), ns->irqs, ARRAY_SIZE(ns->irqs));
+
+    for (i = 0; i < 2; i++) {
+        object_initialize(&ns->ide[i], TYPE_MACIO_IDE);
+        qdev_set_parent_bus(DEVICE(&ns->ide[i]), sysbus_get_default());
+        memory_region_add_subregion(&s->bar, 0x1f000 + ((i + 1) * 0x1000),
+                                    &ns->ide[i].mem);
+        name = g_strdup_printf("ide[%i]", i);
+        object_property_add_child(obj, name, OBJECT(&ns->ide[i]), NULL);
+        g_free(name);
+    }
+}
+
+static void macio_instance_init(Object *obj)
+{
+    MacIOState *s = MACIO(obj);
+    MemoryRegion *dbdma_mem;
+
+    memory_region_init(&s->bar, "macio", 0x80000);
+
+    object_initialize(&s->cuda, TYPE_CUDA);
+    qdev_set_parent_bus(DEVICE(&s->cuda), sysbus_get_default());
+    object_property_add_child(obj, "cuda", OBJECT(&s->cuda), NULL);
+
+    s->dbdma = DBDMA_init(&dbdma_mem);
+    memory_region_add_subregion(&s->bar, 0x08000, dbdma_mem);
+}
+
+static void macio_oldworld_class_init(ObjectClass *oc, void *data)
+{
+    PCIDeviceClass *pdc = PCI_DEVICE_CLASS(oc);
+
+    pdc->init = macio_oldworld_initfn;
+    pdc->device_id = PCI_DEVICE_ID_APPLE_343S1201;
+}
+
+static void macio_newworld_class_init(ObjectClass *oc, void *data)
+{
+    PCIDeviceClass *pdc = PCI_DEVICE_CLASS(oc);
+
+    pdc->init = macio_newworld_initfn;
+    pdc->device_id = PCI_DEVICE_ID_APPLE_UNI_N_KEYL;
+}
+
+static void macio_class_init(ObjectClass *klass, void *data)
+{
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->vendor_id = PCI_VENDOR_ID_APPLE;
+    k->class_id = PCI_CLASS_OTHERS << 8;
+}
+
+static const TypeInfo macio_oldworld_type_info = {
+    .name          = TYPE_OLDWORLD_MACIO,
+    .parent        = TYPE_MACIO,
+    .instance_size = sizeof(OldWorldMacIOState),
+    .instance_init = macio_oldworld_init,
+    .class_init    = macio_oldworld_class_init,
+};
+
+static const TypeInfo macio_newworld_type_info = {
+    .name          = TYPE_NEWWORLD_MACIO,
+    .parent        = TYPE_MACIO,
+    .instance_size = sizeof(NewWorldMacIOState),
+    .instance_init = macio_newworld_init,
+    .class_init    = macio_newworld_class_init,
+};
+
+static const TypeInfo macio_type_info = {
+    .name          = TYPE_MACIO,
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(MacIOState),
+    .instance_init = macio_instance_init,
+    .abstract      = true,
+    .class_init    = macio_class_init,
+};
+
+static void macio_register_types(void)
+{
+    type_register_static(&macio_type_info);
+    type_register_static(&macio_oldworld_type_info);
+    type_register_static(&macio_newworld_type_info);
+}
+
+type_init(macio_register_types)
+
+void macio_init(PCIDevice *d,
+                MemoryRegion *pic_mem,
+                MemoryRegion *escc_mem)
+{
+    MacIOState *macio_state = MACIO(d);
+
+    macio_state->pic_mem = pic_mem;
+    macio_state->escc_mem = escc_mem;
+    /* Note: this code is strongly inspirated from the corresponding code
+       in PearPC */
+
+    qdev_init_nofail(DEVICE(d));
+}
diff --git a/hw/misc/max111x.c b/hw/misc/max111x.c
new file mode 100644 (file)
index 0000000..d477ecd
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+ * Maxim MAX1110/1111 ADC chip emulation.
+ *
+ * Copyright (c) 2006 Openedhand Ltd.
+ * Written by Andrzej Zaborowski <balrog@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 "hw/ssi.h"
+
+typedef struct {
+    SSISlave ssidev;
+    qemu_irq interrupt;
+    uint8_t tb1, rb2, rb3;
+    int cycle;
+
+    uint8_t input[8];
+    int inputs, com;
+} MAX111xState;
+
+/* Control-byte bitfields */
+#define CB_PD0         (1 << 0)
+#define CB_PD1         (1 << 1)
+#define CB_SGL         (1 << 2)
+#define CB_UNI         (1 << 3)
+#define CB_SEL0                (1 << 4)
+#define CB_SEL1                (1 << 5)
+#define CB_SEL2                (1 << 6)
+#define CB_START       (1 << 7)
+
+#define CHANNEL_NUM(v, b0, b1, b2)     \
+                       ((((v) >> (2 + (b0))) & 4) |    \
+                        (((v) >> (3 + (b1))) & 2) |    \
+                        (((v) >> (4 + (b2))) & 1))
+
+static uint32_t max111x_read(MAX111xState *s)
+{
+    if (!s->tb1)
+        return 0;
+
+    switch (s->cycle ++) {
+    case 1:
+        return s->rb2;
+    case 2:
+        return s->rb3;
+    }
+
+    return 0;
+}
+
+/* Interpret a control-byte */
+static void max111x_write(MAX111xState *s, uint32_t value)
+{
+    int measure, chan;
+
+    /* Ignore the value if START bit is zero */
+    if (!(value & CB_START))
+        return;
+
+    s->cycle = 0;
+
+    if (!(value & CB_PD1)) {
+        s->tb1 = 0;
+        return;
+    }
+
+    s->tb1 = value;
+
+    if (s->inputs == 8)
+        chan = CHANNEL_NUM(value, 1, 0, 2);
+    else
+        chan = CHANNEL_NUM(value & ~CB_SEL0, 0, 1, 2);
+
+    if (value & CB_SGL)
+        measure = s->input[chan] - s->com;
+    else
+        measure = s->input[chan] - s->input[chan ^ 1];
+
+    if (!(value & CB_UNI))
+        measure ^= 0x80;
+
+    s->rb2 = (measure >> 2) & 0x3f;
+    s->rb3 = (measure << 6) & 0xc0;
+
+    /* FIXME: When should the IRQ be lowered?  */
+    qemu_irq_raise(s->interrupt);
+}
+
+static uint32_t max111x_transfer(SSISlave *dev, uint32_t value)
+{
+    MAX111xState *s = FROM_SSI_SLAVE(MAX111xState, dev);
+    max111x_write(s, value);
+    return max111x_read(s);
+}
+
+static const VMStateDescription vmstate_max111x = {
+    .name = "max111x",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_SSI_SLAVE(ssidev, MAX111xState),
+        VMSTATE_UINT8(tb1, MAX111xState),
+        VMSTATE_UINT8(rb2, MAX111xState),
+        VMSTATE_UINT8(rb3, MAX111xState),
+        VMSTATE_INT32_EQUAL(inputs, MAX111xState),
+        VMSTATE_INT32(com, MAX111xState),
+        VMSTATE_ARRAY_INT32_UNSAFE(input, MAX111xState, inputs,
+                                   vmstate_info_uint8, uint8_t),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int max111x_init(SSISlave *dev, int inputs)
+{
+    MAX111xState *s = FROM_SSI_SLAVE(MAX111xState, dev);
+
+    qdev_init_gpio_out(&dev->qdev, &s->interrupt, 1);
+
+    s->inputs = inputs;
+    /* TODO: add a user interface for setting these */
+    s->input[0] = 0xf0;
+    s->input[1] = 0xe0;
+    s->input[2] = 0xd0;
+    s->input[3] = 0xc0;
+    s->input[4] = 0xb0;
+    s->input[5] = 0xa0;
+    s->input[6] = 0x90;
+    s->input[7] = 0x80;
+    s->com = 0;
+
+    vmstate_register(&dev->qdev, -1, &vmstate_max111x, s);
+    return 0;
+}
+
+static int max1110_init(SSISlave *dev)
+{
+    return max111x_init(dev, 8);
+}
+
+static int max1111_init(SSISlave *dev)
+{
+    return max111x_init(dev, 4);
+}
+
+void max111x_set_input(DeviceState *dev, int line, uint8_t value)
+{
+    MAX111xState *s = FROM_SSI_SLAVE(MAX111xState, SSI_SLAVE_FROM_QDEV(dev));
+    assert(line >= 0 && line < s->inputs);
+    s->input[line] = value;
+}
+
+static void max1110_class_init(ObjectClass *klass, void *data)
+{
+    SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
+
+    k->init = max1110_init;
+    k->transfer = max111x_transfer;
+}
+
+static const 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)
+{
+    SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
+
+    k->init = max1111_init;
+    k->transfer = max111x_transfer;
+}
+
+static const TypeInfo max1111_info = {
+    .name          = "max1111",
+    .parent        = TYPE_SSI_SLAVE,
+    .instance_size = sizeof(MAX111xState),
+    .class_init    = max1111_class_init,
+};
+
+static void max111x_register_types(void)
+{
+    type_register_static(&max1110_info);
+    type_register_static(&max1111_info);
+}
+
+type_init(max111x_register_types)
diff --git a/hw/misc/milkymist-hpdmc.c b/hw/misc/milkymist-hpdmc.c
new file mode 100644 (file)
index 0000000..d922f6f
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ *  QEMU model of the Milkymist High Performance Dynamic Memory Controller.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
+ *
+ * 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/>.
+ *
+ *
+ * Specification available at:
+ *   http://www.milkymist.org/socdoc/hpdmc.pdf
+ */
+
+#include "hw/hw.h"
+#include "hw/sysbus.h"
+#include "trace.h"
+#include "qemu/error-report.h"
+
+enum {
+    R_SYSTEM = 0,
+    R_BYPASS,
+    R_TIMING,
+    R_IODELAY,
+    R_MAX
+};
+
+enum {
+    IODELAY_DQSDELAY_RDY = (1<<5),
+    IODELAY_PLL1_LOCKED  = (1<<6),
+    IODELAY_PLL2_LOCKED  = (1<<7),
+};
+
+struct MilkymistHpdmcState {
+    SysBusDevice busdev;
+    MemoryRegion regs_region;
+
+    uint32_t regs[R_MAX];
+};
+typedef struct MilkymistHpdmcState MilkymistHpdmcState;
+
+static uint64_t hpdmc_read(void *opaque, hwaddr addr,
+                           unsigned size)
+{
+    MilkymistHpdmcState *s = opaque;
+    uint32_t r = 0;
+
+    addr >>= 2;
+    switch (addr) {
+    case R_SYSTEM:
+    case R_BYPASS:
+    case R_TIMING:
+    case R_IODELAY:
+        r = s->regs[addr];
+        break;
+
+    default:
+        error_report("milkymist_hpdmc: read access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+
+    trace_milkymist_hpdmc_memory_read(addr << 2, r);
+
+    return r;
+}
+
+static void hpdmc_write(void *opaque, hwaddr addr, uint64_t value,
+                        unsigned size)
+{
+    MilkymistHpdmcState *s = opaque;
+
+    trace_milkymist_hpdmc_memory_write(addr, value);
+
+    addr >>= 2;
+    switch (addr) {
+    case R_SYSTEM:
+    case R_BYPASS:
+    case R_TIMING:
+        s->regs[addr] = value;
+        break;
+    case R_IODELAY:
+        /* ignore writes */
+        break;
+
+    default:
+        error_report("milkymist_hpdmc: write access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+}
+
+static const MemoryRegionOps hpdmc_mmio_ops = {
+    .read = hpdmc_read,
+    .write = hpdmc_write,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void milkymist_hpdmc_reset(DeviceState *d)
+{
+    MilkymistHpdmcState *s = container_of(d, MilkymistHpdmcState, busdev.qdev);
+    int i;
+
+    for (i = 0; i < R_MAX; i++) {
+        s->regs[i] = 0;
+    }
+
+    /* defaults */
+    s->regs[R_IODELAY] = IODELAY_DQSDELAY_RDY | IODELAY_PLL1_LOCKED
+                         | IODELAY_PLL2_LOCKED;
+}
+
+static int milkymist_hpdmc_init(SysBusDevice *dev)
+{
+    MilkymistHpdmcState *s = FROM_SYSBUS(typeof(*s), dev);
+
+    memory_region_init_io(&s->regs_region, &hpdmc_mmio_ops, s,
+            "milkymist-hpdmc", R_MAX * 4);
+    sysbus_init_mmio(dev, &s->regs_region);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_milkymist_hpdmc = {
+    .name = "milkymist-hpdmc",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(regs, MilkymistHpdmcState, R_MAX),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+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 const 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_types(void)
+{
+    type_register_static(&milkymist_hpdmc_info);
+}
+
+type_init(milkymist_hpdmc_register_types)
diff --git a/hw/misc/milkymist-pfpu.c b/hw/misc/milkymist-pfpu.c
new file mode 100644 (file)
index 0000000..ad44b4d
--- /dev/null
@@ -0,0 +1,544 @@
+/*
+ *  QEMU model of the Milkymist programmable FPU.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
+ *
+ * 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/>.
+ *
+ *
+ * Specification available at:
+ *   http://www.milkymist.org/socdoc/pfpu.pdf
+ *
+ */
+
+#include "hw/hw.h"
+#include "hw/sysbus.h"
+#include "trace.h"
+#include "qemu/log.h"
+#include "qemu/error-report.h"
+#include <math.h>
+
+/* #define TRACE_EXEC */
+
+#ifdef TRACE_EXEC
+#    define D_EXEC(x) x
+#else
+#    define D_EXEC(x)
+#endif
+
+enum {
+    R_CTL = 0,
+    R_MESHBASE,
+    R_HMESHLAST,
+    R_VMESHLAST,
+    R_CODEPAGE,
+    R_VERTICES,
+    R_COLLISIONS,
+    R_STRAYWRITES,
+    R_LASTDMA,
+    R_PC,
+    R_DREGBASE,
+    R_CODEBASE,
+    R_MAX
+};
+
+enum {
+    CTL_START_BUSY = (1<<0),
+};
+
+enum {
+    OP_NOP = 0,
+    OP_FADD,
+    OP_FSUB,
+    OP_FMUL,
+    OP_FABS,
+    OP_F2I,
+    OP_I2F,
+    OP_VECTOUT,
+    OP_SIN,
+    OP_COS,
+    OP_ABOVE,
+    OP_EQUAL,
+    OP_COPY,
+    OP_IF,
+    OP_TSIGN,
+    OP_QUAKE,
+};
+
+enum {
+    GPR_X = 0,
+    GPR_Y = 1,
+    GPR_FLAGS = 2,
+};
+
+enum {
+    LATENCY_FADD = 5,
+    LATENCY_FSUB = 5,
+    LATENCY_FMUL = 7,
+    LATENCY_FABS = 2,
+    LATENCY_F2I = 2,
+    LATENCY_I2F = 3,
+    LATENCY_VECTOUT = 0,
+    LATENCY_SIN = 4,
+    LATENCY_COS = 4,
+    LATENCY_ABOVE = 2,
+    LATENCY_EQUAL = 2,
+    LATENCY_COPY = 2,
+    LATENCY_IF = 2,
+    LATENCY_TSIGN = 2,
+    LATENCY_QUAKE = 2,
+    MAX_LATENCY = 7
+};
+
+#define GPR_BEGIN       0x100
+#define GPR_END         0x17f
+#define MICROCODE_BEGIN 0x200
+#define MICROCODE_END   0x3ff
+#define MICROCODE_WORDS 2048
+
+#define REINTERPRET_CAST(type, val) (*((type *)&(val)))
+
+#ifdef TRACE_EXEC
+static const char *opcode_to_str[] = {
+    "NOP", "FADD", "FSUB", "FMUL", "FABS", "F2I", "I2F", "VECTOUT",
+    "SIN", "COS", "ABOVE", "EQUAL", "COPY", "IF", "TSIGN", "QUAKE",
+};
+#endif
+
+struct MilkymistPFPUState {
+    SysBusDevice busdev;
+    MemoryRegion regs_region;
+    CharDriverState *chr;
+    qemu_irq irq;
+
+    uint32_t regs[R_MAX];
+    uint32_t gp_regs[128];
+    uint32_t microcode[MICROCODE_WORDS];
+
+    int output_queue_pos;
+    uint32_t output_queue[MAX_LATENCY];
+};
+typedef struct MilkymistPFPUState MilkymistPFPUState;
+
+static inline hwaddr
+get_dma_address(uint32_t base, uint32_t x, uint32_t y)
+{
+    return base + 8 * (128 * y + x);
+}
+
+static inline void
+output_queue_insert(MilkymistPFPUState *s, uint32_t val, int pos)
+{
+    s->output_queue[(s->output_queue_pos + pos) % MAX_LATENCY] = val;
+}
+
+static inline uint32_t
+output_queue_remove(MilkymistPFPUState *s)
+{
+    return s->output_queue[s->output_queue_pos];
+}
+
+static inline void
+output_queue_advance(MilkymistPFPUState *s)
+{
+    s->output_queue[s->output_queue_pos] = 0;
+    s->output_queue_pos = (s->output_queue_pos + 1) % MAX_LATENCY;
+}
+
+static int pfpu_decode_insn(MilkymistPFPUState *s)
+{
+    uint32_t pc = s->regs[R_PC];
+    uint32_t insn = s->microcode[pc];
+    uint32_t reg_a = (insn >> 18) & 0x7f;
+    uint32_t reg_b = (insn >> 11) & 0x7f;
+    uint32_t op = (insn >> 7) & 0xf;
+    uint32_t reg_d = insn & 0x7f;
+    uint32_t r = 0;
+    int latency = 0;
+
+    switch (op) {
+    case OP_NOP:
+        break;
+    case OP_FADD:
+    {
+        float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]);
+        float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]);
+        float t = a + b;
+        r = REINTERPRET_CAST(uint32_t, t);
+        latency = LATENCY_FADD;
+        D_EXEC(qemu_log("ADD a=%f b=%f t=%f, r=%08x\n", a, b, t, r));
+    } break;
+    case OP_FSUB:
+    {
+        float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]);
+        float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]);
+        float t = a - b;
+        r = REINTERPRET_CAST(uint32_t, t);
+        latency = LATENCY_FSUB;
+        D_EXEC(qemu_log("SUB a=%f b=%f t=%f, r=%08x\n", a, b, t, r));
+    } break;
+    case OP_FMUL:
+    {
+        float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]);
+        float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]);
+        float t = a * b;
+        r = REINTERPRET_CAST(uint32_t, t);
+        latency = LATENCY_FMUL;
+        D_EXEC(qemu_log("MUL a=%f b=%f t=%f, r=%08x\n", a, b, t, r));
+    } break;
+    case OP_FABS:
+    {
+        float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]);
+        float t = fabsf(a);
+        r = REINTERPRET_CAST(uint32_t, t);
+        latency = LATENCY_FABS;
+        D_EXEC(qemu_log("ABS a=%f t=%f, r=%08x\n", a, t, r));
+    } break;
+    case OP_F2I:
+    {
+        float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]);
+        int32_t t = a;
+        r = REINTERPRET_CAST(uint32_t, t);
+        latency = LATENCY_F2I;
+        D_EXEC(qemu_log("F2I a=%f t=%d, r=%08x\n", a, t, r));
+    } break;
+    case OP_I2F:
+    {
+        int32_t a = REINTERPRET_CAST(int32_t, s->gp_regs[reg_a]);
+        float t = a;
+        r = REINTERPRET_CAST(uint32_t, t);
+        latency = LATENCY_I2F;
+        D_EXEC(qemu_log("I2F a=%08x t=%f, r=%08x\n", a, t, r));
+    } break;
+    case OP_VECTOUT:
+    {
+        uint32_t a = cpu_to_be32(s->gp_regs[reg_a]);
+        uint32_t b = cpu_to_be32(s->gp_regs[reg_b]);
+        hwaddr dma_ptr =
+            get_dma_address(s->regs[R_MESHBASE],
+                    s->gp_regs[GPR_X], s->gp_regs[GPR_Y]);
+        cpu_physical_memory_write(dma_ptr, (uint8_t *)&a, 4);
+        cpu_physical_memory_write(dma_ptr + 4, (uint8_t *)&b, 4);
+        s->regs[R_LASTDMA] = dma_ptr + 4;
+        D_EXEC(qemu_log("VECTOUT a=%08x b=%08x dma=%08x\n", a, b, dma_ptr));
+        trace_milkymist_pfpu_vectout(a, b, dma_ptr);
+    } break;
+    case OP_SIN:
+    {
+        int32_t a = REINTERPRET_CAST(int32_t, s->gp_regs[reg_a]);
+        float t = sinf(a * (1.0f / (M_PI * 4096.0f)));
+        r = REINTERPRET_CAST(uint32_t, t);
+        latency = LATENCY_SIN;
+        D_EXEC(qemu_log("SIN a=%d t=%f, r=%08x\n", a, t, r));
+    } break;
+    case OP_COS:
+    {
+        int32_t a = REINTERPRET_CAST(int32_t, s->gp_regs[reg_a]);
+        float t = cosf(a * (1.0f / (M_PI * 4096.0f)));
+        r = REINTERPRET_CAST(uint32_t, t);
+        latency = LATENCY_COS;
+        D_EXEC(qemu_log("COS a=%d t=%f, r=%08x\n", a, t, r));
+    } break;
+    case OP_ABOVE:
+    {
+        float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]);
+        float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]);
+        float t = (a > b) ? 1.0f : 0.0f;
+        r = REINTERPRET_CAST(uint32_t, t);
+        latency = LATENCY_ABOVE;
+        D_EXEC(qemu_log("ABOVE a=%f b=%f t=%f, r=%08x\n", a, b, t, r));
+    } break;
+    case OP_EQUAL:
+    {
+        float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]);
+        float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]);
+        float t = (a == b) ? 1.0f : 0.0f;
+        r = REINTERPRET_CAST(uint32_t, t);
+        latency = LATENCY_EQUAL;
+        D_EXEC(qemu_log("EQUAL a=%f b=%f t=%f, r=%08x\n", a, b, t, r));
+    } break;
+    case OP_COPY:
+    {
+        r = s->gp_regs[reg_a];
+        latency = LATENCY_COPY;
+        D_EXEC(qemu_log("COPY"));
+    } break;
+    case OP_IF:
+    {
+        float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]);
+        float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]);
+        uint32_t f = s->gp_regs[GPR_FLAGS];
+        float t = (f != 0) ? a : b;
+        r = REINTERPRET_CAST(uint32_t, t);
+        latency = LATENCY_IF;
+        D_EXEC(qemu_log("IF f=%u a=%f b=%f t=%f, r=%08x\n", f, a, b, t, r));
+    } break;
+    case OP_TSIGN:
+    {
+        float a = REINTERPRET_CAST(float, s->gp_regs[reg_a]);
+        float b = REINTERPRET_CAST(float, s->gp_regs[reg_b]);
+        float t = (b < 0) ? -a : a;
+        r = REINTERPRET_CAST(uint32_t, t);
+        latency = LATENCY_TSIGN;
+        D_EXEC(qemu_log("TSIGN a=%f b=%f t=%f, r=%08x\n", a, b, t, r));
+    } break;
+    case OP_QUAKE:
+    {
+        uint32_t a = s->gp_regs[reg_a];
+        r = 0x5f3759df - (a >> 1);
+        latency = LATENCY_QUAKE;
+        D_EXEC(qemu_log("QUAKE a=%d r=%08x\n", a, r));
+    } break;
+
+    default:
+        error_report("milkymist_pfpu: unknown opcode %d", op);
+        break;
+    }
+
+    if (!reg_d) {
+        D_EXEC(qemu_log("%04d %8s R%03d, R%03d <L=%d, E=%04d>\n",
+                    s->regs[R_PC], opcode_to_str[op], reg_a, reg_b, latency,
+                    s->regs[R_PC] + latency));
+    } else {
+        D_EXEC(qemu_log("%04d %8s R%03d, R%03d <L=%d, E=%04d> -> R%03d\n",
+                    s->regs[R_PC], opcode_to_str[op], reg_a, reg_b, latency,
+                    s->regs[R_PC] + latency, reg_d));
+    }
+
+    if (op == OP_VECTOUT) {
+        return 0;
+    }
+
+    /* store output for this cycle */
+    if (reg_d) {
+        uint32_t val = output_queue_remove(s);
+        D_EXEC(qemu_log("R%03d <- 0x%08x\n", reg_d, val));
+        s->gp_regs[reg_d] = val;
+    }
+
+    output_queue_advance(s);
+
+    /* store op output */
+    if (op != OP_NOP) {
+        output_queue_insert(s, r, latency-1);
+    }
+
+    /* advance PC */
+    s->regs[R_PC]++;
+
+    return 1;
+};
+
+static void pfpu_start(MilkymistPFPUState *s)
+{
+    int x, y;
+    int i;
+
+    for (y = 0; y <= s->regs[R_VMESHLAST]; y++) {
+        for (x = 0; x <= s->regs[R_HMESHLAST]; x++) {
+            D_EXEC(qemu_log("\nprocessing x=%d y=%d\n", x, y));
+
+            /* set current position */
+            s->gp_regs[GPR_X] = x;
+            s->gp_regs[GPR_Y] = y;
+
+            /* run microcode on this position */
+            i = 0;
+            while (pfpu_decode_insn(s)) {
+                /* decode at most MICROCODE_WORDS instructions */
+                if (i++ >= MICROCODE_WORDS) {
+                    error_report("milkymist_pfpu: too many instructions "
+                            "executed in microcode. No VECTOUT?");
+                    break;
+                }
+            }
+
+            /* reset pc for next run */
+            s->regs[R_PC] = 0;
+        }
+    }
+
+    s->regs[R_VERTICES] = x * y;
+
+    trace_milkymist_pfpu_pulse_irq();
+    qemu_irq_pulse(s->irq);
+}
+
+static inline int get_microcode_address(MilkymistPFPUState *s, uint32_t addr)
+{
+    return (512 * s->regs[R_CODEPAGE]) + addr - MICROCODE_BEGIN;
+}
+
+static uint64_t pfpu_read(void *opaque, hwaddr addr,
+                          unsigned size)
+{
+    MilkymistPFPUState *s = opaque;
+    uint32_t r = 0;
+
+    addr >>= 2;
+    switch (addr) {
+    case R_CTL:
+    case R_MESHBASE:
+    case R_HMESHLAST:
+    case R_VMESHLAST:
+    case R_CODEPAGE:
+    case R_VERTICES:
+    case R_COLLISIONS:
+    case R_STRAYWRITES:
+    case R_LASTDMA:
+    case R_PC:
+    case R_DREGBASE:
+    case R_CODEBASE:
+        r = s->regs[addr];
+        break;
+    case GPR_BEGIN ... GPR_END:
+        r = s->gp_regs[addr - GPR_BEGIN];
+        break;
+    case MICROCODE_BEGIN ...  MICROCODE_END:
+        r = s->microcode[get_microcode_address(s, addr)];
+        break;
+
+    default:
+        error_report("milkymist_pfpu: read access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+
+    trace_milkymist_pfpu_memory_read(addr << 2, r);
+
+    return r;
+}
+
+static void pfpu_write(void *opaque, hwaddr addr, uint64_t value,
+                       unsigned size)
+{
+    MilkymistPFPUState *s = opaque;
+
+    trace_milkymist_pfpu_memory_write(addr, value);
+
+    addr >>= 2;
+    switch (addr) {
+    case R_CTL:
+        if (value & CTL_START_BUSY) {
+            pfpu_start(s);
+        }
+        break;
+    case R_MESHBASE:
+    case R_HMESHLAST:
+    case R_VMESHLAST:
+    case R_CODEPAGE:
+    case R_VERTICES:
+    case R_COLLISIONS:
+    case R_STRAYWRITES:
+    case R_LASTDMA:
+    case R_PC:
+    case R_DREGBASE:
+    case R_CODEBASE:
+        s->regs[addr] = value;
+        break;
+    case GPR_BEGIN ...  GPR_END:
+        s->gp_regs[addr - GPR_BEGIN] = value;
+        break;
+    case MICROCODE_BEGIN ...  MICROCODE_END:
+        s->microcode[get_microcode_address(s, addr)] = value;
+        break;
+
+    default:
+        error_report("milkymist_pfpu: write access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+}
+
+static const MemoryRegionOps pfpu_mmio_ops = {
+    .read = pfpu_read,
+    .write = pfpu_write,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void milkymist_pfpu_reset(DeviceState *d)
+{
+    MilkymistPFPUState *s = container_of(d, MilkymistPFPUState, busdev.qdev);
+    int i;
+
+    for (i = 0; i < R_MAX; i++) {
+        s->regs[i] = 0;
+    }
+    for (i = 0; i < 128; i++) {
+        s->gp_regs[i] = 0;
+    }
+    for (i = 0; i < MICROCODE_WORDS; i++) {
+        s->microcode[i] = 0;
+    }
+    s->output_queue_pos = 0;
+    for (i = 0; i < MAX_LATENCY; i++) {
+        s->output_queue[i] = 0;
+    }
+}
+
+static int milkymist_pfpu_init(SysBusDevice *dev)
+{
+    MilkymistPFPUState *s = FROM_SYSBUS(typeof(*s), dev);
+
+    sysbus_init_irq(dev, &s->irq);
+
+    memory_region_init_io(&s->regs_region, &pfpu_mmio_ops, s,
+            "milkymist-pfpu", MICROCODE_END * 4);
+    sysbus_init_mmio(dev, &s->regs_region);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_milkymist_pfpu = {
+    .name = "milkymist-pfpu",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(regs, MilkymistPFPUState, R_MAX),
+        VMSTATE_UINT32_ARRAY(gp_regs, MilkymistPFPUState, 128),
+        VMSTATE_UINT32_ARRAY(microcode, MilkymistPFPUState, MICROCODE_WORDS),
+        VMSTATE_INT32(output_queue_pos, MilkymistPFPUState),
+        VMSTATE_UINT32_ARRAY(output_queue, MilkymistPFPUState, MAX_LATENCY),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+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 const 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_types(void)
+{
+    type_register_static(&milkymist_pfpu_info);
+}
+
+type_init(milkymist_pfpu_register_types)
diff --git a/hw/misc/mst_fpga.c b/hw/misc/mst_fpga.c
new file mode 100644 (file)
index 0000000..1dd1505
--- /dev/null
@@ -0,0 +1,263 @@
+/*
+ * PXA270-based Intel Mainstone platforms.
+ * FPGA driver
+ *
+ * Copyright (c) 2007 by Armin Kuster <akuster@kama-aina.net> or
+ *                                    <akuster@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/hw.h"
+#include "hw/sysbus.h"
+
+/* Mainstone FPGA for extern irqs */
+#define FPGA_GPIO_PIN  0
+#define MST_NUM_IRQS   16
+#define MST_LEDDAT1            0x10
+#define MST_LEDDAT2            0x14
+#define MST_LEDCTRL            0x40
+#define MST_GPSWR              0x60
+#define MST_MSCWR1             0x80
+#define MST_MSCWR2             0x84
+#define MST_MSCWR3             0x88
+#define MST_MSCRD              0x90
+#define MST_INTMSKENA  0xc0
+#define MST_INTSETCLR  0xd0
+#define MST_PCMCIA0            0xe0
+#define MST_PCMCIA1            0xe4
+
+#define MST_PCMCIAx_READY      (1 << 10)
+#define MST_PCMCIAx_nCD                (1 << 5)
+
+#define MST_PCMCIA_CD0_IRQ     9
+#define MST_PCMCIA_CD1_IRQ     13
+
+typedef struct mst_irq_state{
+       SysBusDevice busdev;
+       MemoryRegion iomem;
+
+       qemu_irq parent;
+
+       uint32_t prev_level;
+       uint32_t leddat1;
+       uint32_t leddat2;
+       uint32_t ledctrl;
+       uint32_t gpswr;
+       uint32_t mscwr1;
+       uint32_t mscwr2;
+       uint32_t mscwr3;
+       uint32_t mscrd;
+       uint32_t intmskena;
+       uint32_t intsetclr;
+       uint32_t pcmcia0;
+       uint32_t pcmcia1;
+}mst_irq_state;
+
+static void
+mst_fpga_set_irq(void *opaque, int irq, int level)
+{
+       mst_irq_state *s = (mst_irq_state *)opaque;
+       uint32_t oldint = s->intsetclr & s->intmskena;
+
+       if (level)
+               s->prev_level |= 1u << irq;
+       else
+               s->prev_level &= ~(1u << irq);
+
+       switch(irq) {
+       case MST_PCMCIA_CD0_IRQ:
+               if (level)
+                       s->pcmcia0 &= ~MST_PCMCIAx_nCD;
+               else
+                       s->pcmcia0 |=  MST_PCMCIAx_nCD;
+               break;
+       case MST_PCMCIA_CD1_IRQ:
+               if (level)
+                       s->pcmcia1 &= ~MST_PCMCIAx_nCD;
+               else
+                       s->pcmcia1 |=  MST_PCMCIAx_nCD;
+               break;
+       }
+
+       if ((s->intmskena & (1u << irq)) && level)
+               s->intsetclr |= 1u << irq;
+
+       if (oldint != (s->intsetclr & s->intmskena))
+               qemu_set_irq(s->parent, s->intsetclr & s->intmskena);
+}
+
+
+static uint64_t
+mst_fpga_readb(void *opaque, hwaddr addr, unsigned size)
+{
+       mst_irq_state *s = (mst_irq_state *) opaque;
+
+       switch (addr) {
+       case MST_LEDDAT1:
+               return s->leddat1;
+       case MST_LEDDAT2:
+               return s->leddat2;
+       case MST_LEDCTRL:
+               return s->ledctrl;
+       case MST_GPSWR:
+               return s->gpswr;
+       case MST_MSCWR1:
+               return s->mscwr1;
+       case MST_MSCWR2:
+               return s->mscwr2;
+       case MST_MSCWR3:
+               return s->mscwr3;
+       case MST_MSCRD:
+               return s->mscrd;
+       case MST_INTMSKENA:
+               return s->intmskena;
+       case MST_INTSETCLR:
+               return s->intsetclr;
+       case MST_PCMCIA0:
+               return s->pcmcia0;
+       case MST_PCMCIA1:
+               return s->pcmcia1;
+       default:
+               printf("Mainstone - mst_fpga_readb: Bad register offset "
+                       "0x" TARGET_FMT_plx "\n", addr);
+       }
+       return 0;
+}
+
+static void
+mst_fpga_writeb(void *opaque, hwaddr addr, uint64_t value,
+               unsigned size)
+{
+       mst_irq_state *s = (mst_irq_state *) opaque;
+       value &= 0xffffffff;
+
+       switch (addr) {
+       case MST_LEDDAT1:
+               s->leddat1 = value;
+               break;
+       case MST_LEDDAT2:
+               s->leddat2 = value;
+               break;
+       case MST_LEDCTRL:
+               s->ledctrl = value;
+               break;
+       case MST_GPSWR:
+               s->gpswr = value;
+               break;
+       case MST_MSCWR1:
+               s->mscwr1 = value;
+               break;
+       case MST_MSCWR2:
+               s->mscwr2 = value;
+               break;
+       case MST_MSCWR3:
+               s->mscwr3 = value;
+               break;
+       case MST_MSCRD:
+               s->mscrd =  value;
+               break;
+       case MST_INTMSKENA:     /* Mask interrupt */
+               s->intmskena = (value & 0xFEEFF);
+               qemu_set_irq(s->parent, s->intsetclr & s->intmskena);
+               break;
+       case MST_INTSETCLR:     /* clear or set interrupt */
+               s->intsetclr = (value & 0xFEEFF);
+               qemu_set_irq(s->parent, s->intsetclr & s->intmskena);
+               break;
+               /* For PCMCIAx allow the to change only power and reset */
+       case MST_PCMCIA0:
+               s->pcmcia0 = (value & 0x1f) | (s->pcmcia0 & ~0x1f);
+               break;
+       case MST_PCMCIA1:
+               s->pcmcia1 = (value & 0x1f) | (s->pcmcia1 & ~0x1f);
+               break;
+       default:
+               printf("Mainstone - mst_fpga_writeb: Bad register offset "
+                       "0x" TARGET_FMT_plx "\n", addr);
+       }
+}
+
+static const MemoryRegionOps mst_fpga_ops = {
+       .read = mst_fpga_readb,
+       .write = mst_fpga_writeb,
+       .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int mst_fpga_post_load(void *opaque, int version_id)
+{
+       mst_irq_state *s = (mst_irq_state *) opaque;
+
+       qemu_set_irq(s->parent, s->intsetclr & s->intmskena);
+       return 0;
+}
+
+static int mst_fpga_init(SysBusDevice *dev)
+{
+       mst_irq_state *s;
+
+       s = FROM_SYSBUS(mst_irq_state, dev);
+
+       s->pcmcia0 = MST_PCMCIAx_READY | MST_PCMCIAx_nCD;
+       s->pcmcia1 = MST_PCMCIAx_READY | MST_PCMCIAx_nCD;
+
+       sysbus_init_irq(dev, &s->parent);
+
+       /* alloc the external 16 irqs */
+       qdev_init_gpio_in(&dev->qdev, mst_fpga_set_irq, MST_NUM_IRQS);
+
+       memory_region_init_io(&s->iomem, &mst_fpga_ops, s,
+                           "fpga", 0x00100000);
+       sysbus_init_mmio(dev, &s->iomem);
+       return 0;
+}
+
+static VMStateDescription vmstate_mst_fpga_regs = {
+       .name = "mainstone_fpga",
+       .version_id = 0,
+       .minimum_version_id = 0,
+       .minimum_version_id_old = 0,
+       .post_load = mst_fpga_post_load,
+       .fields = (VMStateField []) {
+               VMSTATE_UINT32(prev_level, mst_irq_state),
+               VMSTATE_UINT32(leddat1, mst_irq_state),
+               VMSTATE_UINT32(leddat2, mst_irq_state),
+               VMSTATE_UINT32(ledctrl, mst_irq_state),
+               VMSTATE_UINT32(gpswr, mst_irq_state),
+               VMSTATE_UINT32(mscwr1, mst_irq_state),
+               VMSTATE_UINT32(mscwr2, mst_irq_state),
+               VMSTATE_UINT32(mscwr3, mst_irq_state),
+               VMSTATE_UINT32(mscrd, mst_irq_state),
+               VMSTATE_UINT32(intmskena, mst_irq_state),
+               VMSTATE_UINT32(intsetclr, mst_irq_state),
+               VMSTATE_UINT32(pcmcia0, mst_irq_state),
+               VMSTATE_UINT32(pcmcia1, mst_irq_state),
+               VMSTATE_END_OF_LIST(),
+       },
+};
+
+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 const 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_types(void)
+{
+    type_register_static(&mst_fpga_info);
+}
+
+type_init(mst_fpga_register_types)
diff --git a/hw/misc/omap_clk.c b/hw/misc/omap_clk.c
new file mode 100644 (file)
index 0000000..80a3c50
--- /dev/null
@@ -0,0 +1,1264 @@
+/*
+ * OMAP clocks.
+ *
+ * Copyright (C) 2006-2008 Andrzej Zaborowski  <balrog@zabor.org>
+ *
+ * Clocks data comes in part from arch/arm/mach-omap1/clock.h in Linux.
+ *
+ * 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 "hw/hw.h"
+#include "hw/arm/omap.h"
+
+struct clk {
+    const char *name;
+    const char *alias;
+    struct clk *parent;
+    struct clk *child1;
+    struct clk *sibling;
+#define ALWAYS_ENABLED         (1 << 0)
+#define CLOCK_IN_OMAP310       (1 << 10)
+#define CLOCK_IN_OMAP730       (1 << 11)
+#define CLOCK_IN_OMAP1510      (1 << 12)
+#define CLOCK_IN_OMAP16XX      (1 << 13)
+#define CLOCK_IN_OMAP242X      (1 << 14)
+#define CLOCK_IN_OMAP243X      (1 << 15)
+#define CLOCK_IN_OMAP343X      (1 << 16)
+    uint32_t flags;
+    int id;
+
+    int running;               /* Is currently ticking */
+    int enabled;               /* Is enabled, regardless of its input clk */
+    unsigned long rate;                /* Current rate (if .running) */
+    unsigned int divisor;      /* Rate relative to input (if .enabled) */
+    unsigned int multiplier;   /* Rate relative to input (if .enabled) */
+    qemu_irq users[16];                /* Who to notify on change */
+    int usecount;              /* Automatically idle when unused */
+};
+
+static struct clk xtal_osc12m = {
+    .name      = "xtal_osc_12m",
+    .rate      = 12000000,
+    .flags     = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310,
+};
+
+static struct clk xtal_osc32k = {
+    .name      = "xtal_osc_32k",
+    .rate      = 32768,
+    .flags     = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 |
+            CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+};
+
+static struct clk ck_ref = {
+    .name      = "ck_ref",
+    .alias     = "clkin",
+    .parent    = &xtal_osc12m,
+    .flags     = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 |
+            ALWAYS_ENABLED,
+};
+
+/* If a dpll is disabled it becomes a bypass, child clocks don't stop */
+static struct clk dpll1 = {
+    .name      = "dpll1",
+    .parent    = &ck_ref,
+    .flags     = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 |
+            ALWAYS_ENABLED,
+};
+
+static struct clk dpll2 = {
+    .name      = "dpll2",
+    .parent    = &ck_ref,
+    .flags     = CLOCK_IN_OMAP310 | ALWAYS_ENABLED,
+};
+
+static struct clk dpll3 = {
+    .name      = "dpll3",
+    .parent    = &ck_ref,
+    .flags     = CLOCK_IN_OMAP310 | ALWAYS_ENABLED,
+};
+
+static struct clk dpll4 = {
+    .name      = "dpll4",
+    .parent    = &ck_ref,
+    .multiplier        = 4,
+    .flags     = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310,
+};
+
+static struct clk apll = {
+    .name      = "apll",
+    .parent    = &ck_ref,
+    .multiplier        = 48,
+    .divisor   = 12,
+    .flags     = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310,
+};
+
+static struct clk ck_48m = {
+    .name      = "ck_48m",
+    .parent    = &dpll4,       /* either dpll4 or apll */
+    .flags     = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310,
+};
+
+static struct clk ck_dpll1out = {
+    .name      = "ck_dpll1out",
+    .parent    = &dpll1,
+    .flags     = CLOCK_IN_OMAP16XX,
+};
+
+static struct clk sossi_ck = {
+    .name      = "ck_sossi",
+    .parent    = &ck_dpll1out,
+    .flags     = CLOCK_IN_OMAP16XX,
+};
+
+static struct clk clkm1 = {
+    .name      = "clkm1",
+    .alias     = "ck_gen1",
+    .parent    = &dpll1,
+    .flags     = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 |
+            ALWAYS_ENABLED,
+};
+
+static struct clk clkm2 = {
+    .name      = "clkm2",
+    .alias     = "ck_gen2",
+    .parent    = &dpll1,
+    .flags     = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 |
+            ALWAYS_ENABLED,
+};
+
+static struct clk clkm3 = {
+    .name      = "clkm3",
+    .alias     = "ck_gen3",
+    .parent    = &dpll1,       /* either dpll1 or ck_ref */
+    .flags     = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 |
+            ALWAYS_ENABLED,
+};
+
+static struct clk arm_ck = {
+    .name      = "arm_ck",
+    .alias     = "mpu_ck",
+    .parent    = &clkm1,
+    .flags     = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 |
+            ALWAYS_ENABLED,
+};
+
+static struct clk armper_ck = {
+    .name      = "armper_ck",
+    .alias     = "mpuper_ck",
+    .parent    = &clkm1,
+    .flags     = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310,
+};
+
+static struct clk arm_gpio_ck = {
+    .name      = "arm_gpio_ck",
+    .alias     = "mpu_gpio_ck",
+    .parent    = &clkm1,
+    .divisor   = 1,
+    .flags     = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310,
+};
+
+static struct clk armxor_ck = {
+    .name      = "armxor_ck",
+    .alias     = "mpuxor_ck",
+    .parent    = &ck_ref,
+    .flags     = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310,
+};
+
+static struct clk armtim_ck = {
+    .name      = "armtim_ck",
+    .alias     = "mputim_ck",
+    .parent    = &ck_ref,      /* either CLKIN or DPLL1 */
+    .flags     = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310,
+};
+
+static struct clk armwdt_ck = {
+    .name      = "armwdt_ck",
+    .alias     = "mpuwd_ck",
+    .parent    = &clkm1,
+    .divisor   = 14,
+    .flags     = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 |
+            ALWAYS_ENABLED,
+};
+
+static struct clk arminth_ck16xx = {
+    .name      = "arminth_ck",
+    .parent    = &arm_ck,
+    .flags     = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED,
+    /* Note: On 16xx the frequency can be divided by 2 by programming
+     * ARM_CKCTL:ARM_INTHCK_SEL(14) to 1
+     *
+     * 1510 version is in TC clocks.
+     */
+};
+
+static struct clk dsp_ck = {
+    .name      = "dsp_ck",
+    .parent    = &clkm2,
+    .flags     = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
+};
+
+static struct clk dspmmu_ck = {
+    .name      = "dspmmu_ck",
+    .parent    = &clkm2,
+    .flags     = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+            ALWAYS_ENABLED,
+};
+
+static struct clk dspper_ck = {
+    .name      = "dspper_ck",
+    .parent    = &clkm2,
+    .flags     = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
+};
+
+static struct clk dspxor_ck = {
+    .name      = "dspxor_ck",
+    .parent    = &ck_ref,
+    .flags     = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
+};
+
+static struct clk dsptim_ck = {
+    .name      = "dsptim_ck",
+    .parent    = &ck_ref,
+    .flags     = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
+};
+
+static struct clk tc_ck = {
+    .name      = "tc_ck",
+    .parent    = &clkm3,
+    .flags     = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+            CLOCK_IN_OMAP730 | CLOCK_IN_OMAP310 |
+            ALWAYS_ENABLED,
+};
+
+static struct clk arminth_ck15xx = {
+    .name      = "arminth_ck",
+    .parent    = &tc_ck,
+    .flags     = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | ALWAYS_ENABLED,
+    /* Note: On 1510 the frequency follows TC_CK
+     *
+     * 16xx version is in MPU clocks.
+     */
+};
+
+static struct clk tipb_ck = {
+    /* No-idle controlled by "tc_ck" */
+    .name      = "tipb_ck",
+    .parent    = &tc_ck,
+    .flags     = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | ALWAYS_ENABLED,
+};
+
+static struct clk l3_ocpi_ck = {
+    /* No-idle controlled by "tc_ck" */
+    .name      = "l3_ocpi_ck",
+    .parent    = &tc_ck,
+    .flags     = CLOCK_IN_OMAP16XX,
+};
+
+static struct clk tc1_ck = {
+    .name      = "tc1_ck",
+    .parent    = &tc_ck,
+    .flags     = CLOCK_IN_OMAP16XX,
+};
+
+static struct clk tc2_ck = {
+    .name      = "tc2_ck",
+    .parent    = &tc_ck,
+    .flags     = CLOCK_IN_OMAP16XX,
+};
+
+static struct clk dma_ck = {
+    /* No-idle controlled by "tc_ck" */
+    .name      = "dma_ck",
+    .parent    = &tc_ck,
+    .flags     = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 |
+            ALWAYS_ENABLED,
+};
+
+static struct clk dma_lcdfree_ck = {
+    .name      = "dma_lcdfree_ck",
+    .parent    = &tc_ck,
+    .flags     = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED,
+};
+
+static struct clk api_ck = {
+    .name      = "api_ck",
+    .alias     = "mpui_ck",
+    .parent    = &tc_ck,
+    .flags     = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310,
+};
+
+static struct clk lb_ck = {
+    .name      = "lb_ck",
+    .parent    = &tc_ck,
+    .flags     = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310,
+};
+
+static struct clk lbfree_ck = {
+    .name      = "lbfree_ck",
+    .parent    = &tc_ck,
+    .flags     = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310,
+};
+
+static struct clk hsab_ck = {
+    .name      = "hsab_ck",
+    .parent    = &tc_ck,
+    .flags     = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310,
+};
+
+static struct clk rhea1_ck = {
+    .name      = "rhea1_ck",
+    .parent    = &tc_ck,
+    .flags     = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED,
+};
+
+static struct clk rhea2_ck = {
+    .name      = "rhea2_ck",
+    .parent    = &tc_ck,
+    .flags     = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED,
+};
+
+static struct clk lcd_ck_16xx = {
+    .name      = "lcd_ck",
+    .parent    = &clkm3,
+    .flags     = CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP730,
+};
+
+static struct clk lcd_ck_1510 = {
+    .name      = "lcd_ck",
+    .parent    = &clkm3,
+    .flags     = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310,
+};
+
+static struct clk uart1_1510 = {
+    .name      = "uart1_ck",
+    /* Direct from ULPD, no real parent */
+    .parent    = &armper_ck,   /* either armper_ck or dpll4 */
+    .rate      = 12000000,
+    .flags     = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | ALWAYS_ENABLED,
+};
+
+static struct clk uart1_16xx = {
+    .name      = "uart1_ck",
+    /* Direct from ULPD, no real parent */
+    .parent    = &armper_ck,
+    .rate      = 48000000,
+    .flags     = CLOCK_IN_OMAP16XX,
+};
+
+static struct clk uart2_ck = {
+    .name      = "uart2_ck",
+    /* Direct from ULPD, no real parent */
+    .parent    = &armper_ck,   /* either armper_ck or dpll4 */
+    .rate      = 12000000,
+    .flags     = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 |
+            ALWAYS_ENABLED,
+};
+
+static struct clk uart3_1510 = {
+    .name      = "uart3_ck",
+    /* Direct from ULPD, no real parent */
+    .parent    = &armper_ck,   /* either armper_ck or dpll4 */
+    .rate      = 12000000,
+    .flags     = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | ALWAYS_ENABLED,
+};
+
+static struct clk uart3_16xx = {
+    .name      = "uart3_ck",
+    /* Direct from ULPD, no real parent */
+    .parent    = &armper_ck,
+    .rate      = 48000000,
+    .flags     = CLOCK_IN_OMAP16XX,
+};
+
+static struct clk usb_clk0 = { /* 6 MHz output on W4_USB_CLK0 */
+    .name      = "usb_clk0",
+    .alias     = "usb.clko",
+    /* Direct from ULPD, no parent */
+    .rate      = 6000000,
+    .flags     = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310,
+};
+
+static struct clk usb_hhc_ck1510 = {
+    .name      = "usb_hhc_ck",
+    /* Direct from ULPD, no parent */
+    .rate      = 48000000, /* Actually 2 clocks, 12MHz and 48MHz */
+    .flags     = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310,
+};
+
+static struct clk usb_hhc_ck16xx = {
+    .name      = "usb_hhc_ck",
+    /* Direct from ULPD, no parent */
+    .rate      = 48000000,
+    /* OTG_SYSCON_2.OTG_PADEN == 0 (not 1510-compatible) */
+    .flags     = CLOCK_IN_OMAP16XX,
+};
+
+static struct clk usb_w2fc_mclk = {
+    .name      = "usb_w2fc_mclk",
+    .alias     = "usb_w2fc_ck",
+    .parent    = &ck_48m,
+    .rate      = 48000000,
+    .flags     = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
+};
+
+static struct clk mclk_1510 = {
+    .name      = "mclk",
+    /* Direct from ULPD, no parent. May be enabled by ext hardware. */
+    .rate      = 12000000,
+    .flags     = CLOCK_IN_OMAP1510,
+};
+
+static struct clk bclk_310 = {
+    .name      = "bt_mclk_out",        /* Alias midi_mclk_out? */
+    .parent    = &armper_ck,
+    .flags     = CLOCK_IN_OMAP310,
+};
+
+static struct clk mclk_310 = {
+    .name      = "com_mclk_out",
+    .parent    = &armper_ck,
+    .flags     = CLOCK_IN_OMAP310,
+};
+
+static struct clk mclk_16xx = {
+    .name      = "mclk",
+    /* Direct from ULPD, no parent. May be enabled by ext hardware. */
+    .flags     = CLOCK_IN_OMAP16XX,
+};
+
+static struct clk bclk_1510 = {
+    .name      = "bclk",
+    /* Direct from ULPD, no parent. May be enabled by ext hardware. */
+    .rate      = 12000000,
+    .flags     = CLOCK_IN_OMAP1510,
+};
+
+static struct clk bclk_16xx = {
+    .name      = "bclk",
+    /* Direct from ULPD, no parent. May be enabled by ext hardware. */
+    .flags     = CLOCK_IN_OMAP16XX,
+};
+
+static struct clk mmc1_ck = {
+    .name      = "mmc_ck",
+    .id                = 1,
+    /* Functional clock is direct from ULPD, interface clock is ARMPER */
+    .parent    = &armper_ck,   /* either armper_ck or dpll4 */
+    .rate      = 48000000,
+    .flags     = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310,
+};
+
+static struct clk mmc2_ck = {
+    .name      = "mmc_ck",
+    .id                = 2,
+    /* Functional clock is direct from ULPD, interface clock is ARMPER */
+    .parent    = &armper_ck,
+    .rate      = 48000000,
+    .flags     = CLOCK_IN_OMAP16XX,
+};
+
+static struct clk cam_mclk = {
+    .name      = "cam.mclk",
+    .flags     = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
+    .rate      = 12000000,
+};
+
+static struct clk cam_exclk = {
+    .name      = "cam.exclk",
+    .flags     = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
+    /* Either 12M from cam.mclk or 48M from dpll4 */
+    .parent    = &cam_mclk,
+};
+
+static struct clk cam_lclk = {
+    .name      = "cam.lclk",
+    .flags     = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
+};
+
+static struct clk i2c_fck = {
+    .name      = "i2c_fck",
+    .id                = 1,
+    .flags     = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+            ALWAYS_ENABLED,
+    .parent    = &armxor_ck,
+};
+
+static struct clk i2c_ick = {
+    .name      = "i2c_ick",
+    .id                = 1,
+    .flags     = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED,
+    .parent    = &armper_ck,
+};
+
+static struct clk clk32k = {
+    .name      = "clk32-kHz",
+    .flags     = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+            CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
+    .parent    = &xtal_osc32k,
+};
+
+static struct clk ref_clk = {
+    .name      = "ref_clk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
+    .rate      = 12000000,     /* 12 MHz or 13 MHz or 19.2 MHz */
+    /*.parent  = sys.xtalin */
+};
+
+static struct clk apll_96m = {
+    .name      = "apll_96m",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
+    .rate      = 96000000,
+    /*.parent  = ref_clk */
+};
+
+static struct clk apll_54m = {
+    .name      = "apll_54m",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
+    .rate      = 54000000,
+    /*.parent  = ref_clk */
+};
+
+static struct clk sys_clk = {
+    .name      = "sys_clk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
+    .rate      = 32768,
+    /*.parent  = sys.xtalin */
+};
+
+static struct clk sleep_clk = {
+    .name      = "sleep_clk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
+    .rate      = 32768,
+    /*.parent  = sys.xtalin */
+};
+
+static struct clk dpll_ck = {
+    .name      = "dpll",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
+    .parent    = &ref_clk,
+};
+
+static struct clk dpll_x2_ck = {
+    .name      = "dpll_x2",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
+    .parent    = &ref_clk,
+};
+
+static struct clk wdt1_sys_clk = {
+    .name      = "wdt1_sys_clk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
+    .rate      = 32768,
+    /*.parent  = sys.xtalin */
+};
+
+static struct clk func_96m_clk = {
+    .name      = "func_96m_clk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .divisor   = 1,
+    .parent    = &apll_96m,
+};
+
+static struct clk func_48m_clk = {
+    .name      = "func_48m_clk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .divisor   = 2,
+    .parent    = &apll_96m,
+};
+
+static struct clk func_12m_clk = {
+    .name      = "func_12m_clk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .divisor   = 8,
+    .parent    = &apll_96m,
+};
+
+static struct clk func_54m_clk = {
+    .name      = "func_54m_clk",
+    .flags     = CLOCK_IN_OMAP242X,
+    .divisor   = 1,
+    .parent    = &apll_54m,
+};
+
+static struct clk sys_clkout = {
+    .name      = "clkout",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &sys_clk,
+};
+
+static struct clk sys_clkout2 = {
+    .name      = "clkout2",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &sys_clk,
+};
+
+static struct clk core_clk = {
+    .name      = "core_clk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &dpll_x2_ck,  /* Switchable between dpll_ck and clk32k */
+};
+
+static struct clk l3_clk = {
+    .name      = "l3_clk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &core_clk,
+};
+
+static struct clk core_l4_iclk = {
+    .name      = "core_l4_iclk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &l3_clk,
+};
+
+static struct clk wu_l4_iclk = {
+    .name      = "wu_l4_iclk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &l3_clk,
+};
+
+static struct clk core_l3_iclk = {
+    .name      = "core_l3_iclk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &core_clk,
+};
+
+static struct clk core_l4_usb_clk = {
+    .name      = "core_l4_usb_clk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &l3_clk,
+};
+
+static struct clk wu_gpt1_clk = {
+    .name      = "wu_gpt1_clk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &sys_clk,
+};
+
+static struct clk wu_32k_clk = {
+    .name      = "wu_32k_clk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &sys_clk,
+};
+
+static struct clk uart1_fclk = {
+    .name      = "uart1_fclk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &func_48m_clk,
+};
+
+static struct clk uart1_iclk = {
+    .name      = "uart1_iclk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &core_l4_iclk,
+};
+
+static struct clk uart2_fclk = {
+    .name      = "uart2_fclk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &func_48m_clk,
+};
+
+static struct clk uart2_iclk = {
+    .name      = "uart2_iclk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &core_l4_iclk,
+};
+
+static struct clk uart3_fclk = {
+    .name      = "uart3_fclk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &func_48m_clk,
+};
+
+static struct clk uart3_iclk = {
+    .name      = "uart3_iclk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &core_l4_iclk,
+};
+
+static struct clk mpu_fclk = {
+    .name      = "mpu_fclk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &core_clk,
+};
+
+static struct clk mpu_iclk = {
+    .name      = "mpu_iclk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &core_clk,
+};
+
+static struct clk int_m_fclk = {
+    .name      = "int_m_fclk",
+    .alias     = "mpu_intc_fclk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &core_clk,
+};
+
+static struct clk int_m_iclk = {
+    .name      = "int_m_iclk",
+    .alias     = "mpu_intc_iclk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &core_clk,
+};
+
+static struct clk core_gpt2_clk = {
+    .name      = "core_gpt2_clk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &sys_clk,
+};
+
+static struct clk core_gpt3_clk = {
+    .name      = "core_gpt3_clk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &sys_clk,
+};
+
+static struct clk core_gpt4_clk = {
+    .name      = "core_gpt4_clk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &sys_clk,
+};
+
+static struct clk core_gpt5_clk = {
+    .name      = "core_gpt5_clk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &sys_clk,
+};
+
+static struct clk core_gpt6_clk = {
+    .name      = "core_gpt6_clk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &sys_clk,
+};
+
+static struct clk core_gpt7_clk = {
+    .name      = "core_gpt7_clk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &sys_clk,
+};
+
+static struct clk core_gpt8_clk = {
+    .name      = "core_gpt8_clk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &sys_clk,
+};
+
+static struct clk core_gpt9_clk = {
+    .name      = "core_gpt9_clk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &sys_clk,
+};
+
+static struct clk core_gpt10_clk = {
+    .name      = "core_gpt10_clk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &sys_clk,
+};
+
+static struct clk core_gpt11_clk = {
+    .name      = "core_gpt11_clk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &sys_clk,
+};
+
+static struct clk core_gpt12_clk = {
+    .name      = "core_gpt12_clk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &sys_clk,
+};
+
+static struct clk mcbsp1_clk = {
+    .name      = "mcbsp1_cg",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .divisor   = 2,
+    .parent    = &func_96m_clk,
+};
+
+static struct clk mcbsp2_clk = {
+    .name      = "mcbsp2_cg",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .divisor   = 2,
+    .parent    = &func_96m_clk,
+};
+
+static struct clk emul_clk = {
+    .name      = "emul_ck",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &func_54m_clk,
+};
+
+static struct clk sdma_fclk = {
+    .name      = "sdma_fclk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &l3_clk,
+};
+
+static struct clk sdma_iclk = {
+    .name      = "sdma_iclk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &core_l3_iclk, /* core_l4_iclk for the configuration port */
+};
+
+static struct clk i2c1_fclk = {
+    .name      = "i2c1.fclk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &func_12m_clk,
+    .divisor   = 1,
+};
+
+static struct clk i2c1_iclk = {
+    .name      = "i2c1.iclk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &core_l4_iclk,
+};
+
+static struct clk i2c2_fclk = {
+    .name      = "i2c2.fclk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &func_12m_clk,
+    .divisor   = 1,
+};
+
+static struct clk i2c2_iclk = {
+    .name      = "i2c2.iclk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &core_l4_iclk,
+};
+
+static struct clk gpio_dbclk[5] = {
+    {
+        .name  = "gpio1_dbclk",
+        .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+        .parent        = &wu_32k_clk,
+    }, {
+        .name  = "gpio2_dbclk",
+        .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+        .parent        = &wu_32k_clk,
+    }, {
+        .name  = "gpio3_dbclk",
+        .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+        .parent        = &wu_32k_clk,
+    }, {
+        .name  = "gpio4_dbclk",
+        .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+        .parent        = &wu_32k_clk,
+    }, {
+        .name   = "gpio5_dbclk",
+        .flags  = CLOCK_IN_OMAP243X,
+        .parent = &wu_32k_clk,
+    },
+};
+
+static struct clk gpio_iclk = {
+    .name      = "gpio_iclk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &wu_l4_iclk,
+};
+
+static struct clk mmc_fck = {
+    .name      = "mmc_fclk",
+    .flags     = CLOCK_IN_OMAP242X,
+    .parent    = &func_96m_clk,
+};
+
+static struct clk mmc_ick = {
+    .name      = "mmc_iclk",
+    .flags     = CLOCK_IN_OMAP242X,
+    .parent    = &core_l4_iclk,
+};
+
+static struct clk spi_fclk[3] = {
+    {
+        .name  = "spi1_fclk",
+        .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+        .parent        = &func_48m_clk,
+    }, {
+        .name  = "spi2_fclk",
+        .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+        .parent        = &func_48m_clk,
+    }, {
+        .name  = "spi3_fclk",
+        .flags = CLOCK_IN_OMAP243X,
+        .parent        = &func_48m_clk,
+    },
+};
+
+static struct clk dss_clk[2] = {
+    {
+        .name  = "dss_clk1",
+        .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+        .parent        = &core_clk,
+    }, {
+        .name  = "dss_clk2",
+        .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+        .parent        = &sys_clk,
+    },
+};
+
+static struct clk dss_54m_clk = {
+    .name      = "dss_54m_clk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &func_54m_clk,
+};
+
+static struct clk dss_l3_iclk = {
+    .name      = "dss_l3_iclk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &core_l3_iclk,
+};
+
+static struct clk dss_l4_iclk = {
+    .name      = "dss_l4_iclk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    .parent    = &core_l4_iclk,
+};
+
+static struct clk spi_iclk[3] = {
+    {
+        .name  = "spi1_iclk",
+        .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+        .parent        = &core_l4_iclk,
+    }, {
+        .name  = "spi2_iclk",
+        .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+        .parent        = &core_l4_iclk,
+    }, {
+        .name  = "spi3_iclk",
+        .flags = CLOCK_IN_OMAP243X,
+        .parent        = &core_l4_iclk,
+    },
+};
+
+static struct clk omapctrl_clk = {
+    .name      = "omapctrl_iclk",
+    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
+    /* XXX Should be in WKUP domain */
+    .parent    = &core_l4_iclk,
+};
+
+static struct clk *onchip_clks[] = {
+    /* OMAP 1 */
+
+    /* non-ULPD clocks */
+    &xtal_osc12m,
+    &xtal_osc32k,
+    &ck_ref,
+    &dpll1,
+    &dpll2,
+    &dpll3,
+    &dpll4,
+    &apll,
+    &ck_48m,
+    /* CK_GEN1 clocks */
+    &clkm1,
+    &ck_dpll1out,
+    &sossi_ck,
+    &arm_ck,
+    &armper_ck,
+    &arm_gpio_ck,
+    &armxor_ck,
+    &armtim_ck,
+    &armwdt_ck,
+    &arminth_ck15xx,  &arminth_ck16xx,
+    /* CK_GEN2 clocks */
+    &clkm2,
+    &dsp_ck,
+    &dspmmu_ck,
+    &dspper_ck,
+    &dspxor_ck,
+    &dsptim_ck,
+    /* CK_GEN3 clocks */
+    &clkm3,
+    &tc_ck,
+    &tipb_ck,
+    &l3_ocpi_ck,
+    &tc1_ck,
+    &tc2_ck,
+    &dma_ck,
+    &dma_lcdfree_ck,
+    &api_ck,
+    &lb_ck,
+    &lbfree_ck,
+    &hsab_ck,
+    &rhea1_ck,
+    &rhea2_ck,
+    &lcd_ck_16xx,
+    &lcd_ck_1510,
+    /* ULPD clocks */
+    &uart1_1510,
+    &uart1_16xx,
+    &uart2_ck,
+    &uart3_1510,
+    &uart3_16xx,
+    &usb_clk0,
+    &usb_hhc_ck1510, &usb_hhc_ck16xx,
+    &mclk_1510,  &mclk_16xx, &mclk_310,
+    &bclk_1510,  &bclk_16xx, &bclk_310,
+    &mmc1_ck,
+    &mmc2_ck,
+    &cam_mclk,
+    &cam_exclk,
+    &cam_lclk,
+    &clk32k,
+    &usb_w2fc_mclk,
+    /* Virtual clocks */
+    &i2c_fck,
+    &i2c_ick,
+
+    /* OMAP 2 */
+
+    &ref_clk,
+    &apll_96m,
+    &apll_54m,
+    &sys_clk,
+    &sleep_clk,
+    &dpll_ck,
+    &dpll_x2_ck,
+    &wdt1_sys_clk,
+    &func_96m_clk,
+    &func_48m_clk,
+    &func_12m_clk,
+    &func_54m_clk,
+    &sys_clkout,
+    &sys_clkout2,
+    &core_clk,
+    &l3_clk,
+    &core_l4_iclk,
+    &wu_l4_iclk,
+    &core_l3_iclk,
+    &core_l4_usb_clk,
+    &wu_gpt1_clk,
+    &wu_32k_clk,
+    &uart1_fclk,
+    &uart1_iclk,
+    &uart2_fclk,
+    &uart2_iclk,
+    &uart3_fclk,
+    &uart3_iclk,
+    &mpu_fclk,
+    &mpu_iclk,
+    &int_m_fclk,
+    &int_m_iclk,
+    &core_gpt2_clk,
+    &core_gpt3_clk,
+    &core_gpt4_clk,
+    &core_gpt5_clk,
+    &core_gpt6_clk,
+    &core_gpt7_clk,
+    &core_gpt8_clk,
+    &core_gpt9_clk,
+    &core_gpt10_clk,
+    &core_gpt11_clk,
+    &core_gpt12_clk,
+    &mcbsp1_clk,
+    &mcbsp2_clk,
+    &emul_clk,
+    &sdma_fclk,
+    &sdma_iclk,
+    &i2c1_fclk,
+    &i2c1_iclk,
+    &i2c2_fclk,
+    &i2c2_iclk,
+    &gpio_dbclk[0],
+    &gpio_dbclk[1],
+    &gpio_dbclk[2],
+    &gpio_dbclk[3],
+    &gpio_iclk,
+    &mmc_fck,
+    &mmc_ick,
+    &spi_fclk[0],
+    &spi_iclk[0],
+    &spi_fclk[1],
+    &spi_iclk[1],
+    &spi_fclk[2],
+    &spi_iclk[2],
+    &dss_clk[0],
+    &dss_clk[1],
+    &dss_54m_clk,
+    &dss_l3_iclk,
+    &dss_l4_iclk,
+    &omapctrl_clk,
+
+    NULL
+};
+
+void omap_clk_adduser(struct clk *clk, qemu_irq user)
+{
+    qemu_irq *i;
+
+    for (i = clk->users; *i; i ++);
+    *i = user;
+}
+
+struct clk *omap_findclk(struct omap_mpu_state_s *mpu, const char *name)
+{
+    struct clk *i;
+
+    for (i = mpu->clks; i->name; i ++)
+        if (!strcmp(i->name, name) || (i->alias && !strcmp(i->alias, name)))
+            return i;
+    hw_error("%s: %s not found\n", __FUNCTION__, name);
+}
+
+void omap_clk_get(struct clk *clk)
+{
+    clk->usecount ++;
+}
+
+void omap_clk_put(struct clk *clk)
+{
+    if (!(clk->usecount --))
+        hw_error("%s: %s is not in use\n", __FUNCTION__, clk->name);
+}
+
+static void omap_clk_update(struct clk *clk)
+{
+    int parent, running;
+    qemu_irq *user;
+    struct clk *i;
+
+    if (clk->parent)
+        parent = clk->parent->running;
+    else
+        parent = 1;
+
+    running = parent && (clk->enabled ||
+                    ((clk->flags & ALWAYS_ENABLED) && clk->usecount));
+    if (clk->running != running) {
+        clk->running = running;
+        for (user = clk->users; *user; user ++)
+            qemu_set_irq(*user, running);
+        for (i = clk->child1; i; i = i->sibling)
+            omap_clk_update(i);
+    }
+}
+
+static void omap_clk_rate_update_full(struct clk *clk, unsigned long int rate,
+                unsigned long int div, unsigned long int mult)
+{
+    struct clk *i;
+    qemu_irq *user;
+
+    clk->rate = muldiv64(rate, mult, div);
+    if (clk->running)
+        for (user = clk->users; *user; user ++)
+            qemu_irq_raise(*user);
+    for (i = clk->child1; i; i = i->sibling)
+        omap_clk_rate_update_full(i, rate,
+                        div * i->divisor, mult * i->multiplier);
+}
+
+static void omap_clk_rate_update(struct clk *clk)
+{
+    struct clk *i;
+    unsigned long int div, mult = div = 1;
+
+    for (i = clk; i->parent; i = i->parent) {
+        div *= i->divisor;
+        mult *= i->multiplier;
+    }
+
+    omap_clk_rate_update_full(clk, i->rate, div, mult);
+}
+
+void omap_clk_reparent(struct clk *clk, struct clk *parent)
+{
+    struct clk **p;
+
+    if (clk->parent) {
+        for (p = &clk->parent->child1; *p != clk; p = &(*p)->sibling);
+        *p = clk->sibling;
+    }
+
+    clk->parent = parent;
+    if (parent) {
+        clk->sibling = parent->child1;
+        parent->child1 = clk;
+        omap_clk_update(clk);
+        omap_clk_rate_update(clk);
+    } else
+        clk->sibling = NULL;
+}
+
+void omap_clk_onoff(struct clk *clk, int on)
+{
+    clk->enabled = on;
+    omap_clk_update(clk);
+}
+
+void omap_clk_canidle(struct clk *clk, int can)
+{
+    if (can)
+        omap_clk_put(clk);
+    else
+        omap_clk_get(clk);
+}
+
+void omap_clk_setrate(struct clk *clk, int divide, int multiply)
+{
+    clk->divisor = divide;
+    clk->multiplier = multiply;
+    omap_clk_rate_update(clk);
+}
+
+int64_t omap_clk_getrate(omap_clk clk)
+{
+    return clk->rate;
+}
+
+void omap_clk_init(struct omap_mpu_state_s *mpu)
+{
+    struct clk **i, *j, *k;
+    int count;
+    int flag;
+
+    if (cpu_is_omap310(mpu))
+        flag = CLOCK_IN_OMAP310;
+    else if (cpu_is_omap1510(mpu))
+        flag = CLOCK_IN_OMAP1510;
+    else if (cpu_is_omap2410(mpu) || cpu_is_omap2420(mpu))
+        flag = CLOCK_IN_OMAP242X;
+    else if (cpu_is_omap2430(mpu))
+        flag = CLOCK_IN_OMAP243X;
+    else if (cpu_is_omap3430(mpu))
+        flag = CLOCK_IN_OMAP243X;
+    else
+        return;
+
+    for (i = onchip_clks, count = 0; *i; i ++)
+        if ((*i)->flags & flag)
+            count ++;
+    mpu->clks = (struct clk *) g_malloc0(sizeof(struct clk) * (count + 1));
+    for (i = onchip_clks, j = mpu->clks; *i; i ++)
+        if ((*i)->flags & flag) {
+            memcpy(j, *i, sizeof(struct clk));
+            for (k = mpu->clks; k < j; k ++)
+                if (j->parent && !strcmp(j->parent->name, k->name)) {
+                    j->parent = k;
+                    j->sibling = k->child1;
+                    k->child1 = j;
+                } else if (k->parent && !strcmp(k->parent->name, j->name)) {
+                    k->parent = j;
+                    k->sibling = j->child1;
+                    j->child1 = k;
+                }
+            j->divisor = j->divisor ?: 1;
+            j->multiplier = j->multiplier ?: 1;
+            j ++;
+        }
+    for (j = mpu->clks; count --; j ++) {
+        omap_clk_update(j);
+        omap_clk_rate_update(j);
+    }
+}
diff --git a/hw/misc/omap_gpmc.c b/hw/misc/omap_gpmc.c
new file mode 100644 (file)
index 0000000..91adb66
--- /dev/null
@@ -0,0 +1,894 @@
+/*
+ * TI OMAP general purpose memory controller emulation.
+ *
+ * Copyright (C) 2007-2009 Nokia Corporation
+ * Original code written by Andrzej Zaborowski <andrew@openedhand.com>
+ * Enhancements for OMAP3 and NAND support written by Juha Riihimäki
+ *
+ * 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 or
+ * (at your option) any later version 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
+ * 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 "hw/hw.h"
+#include "hw/block/flash.h"
+#include "hw/arm/omap.h"
+#include "exec/memory.h"
+#include "exec/address-spaces.h"
+
+/* General-Purpose Memory Controller */
+struct omap_gpmc_s {
+    qemu_irq irq;
+    qemu_irq drq;
+    MemoryRegion iomem;
+    int accept_256;
+
+    uint8_t revision;
+    uint8_t sysconfig;
+    uint16_t irqst;
+    uint16_t irqen;
+    uint16_t lastirq;
+    uint16_t timeout;
+    uint16_t config;
+    struct omap_gpmc_cs_file_s {
+        uint32_t config[7];
+        MemoryRegion *iomem;
+        MemoryRegion container;
+        MemoryRegion nandiomem;
+        DeviceState *dev;
+    } cs_file[8];
+    int ecc_cs;
+    int ecc_ptr;
+    uint32_t ecc_cfg;
+    ECCState ecc[9];
+    struct prefetch {
+        uint32_t config1; /* GPMC_PREFETCH_CONFIG1 */
+        uint32_t transfercount; /* GPMC_PREFETCH_CONFIG2:TRANSFERCOUNT */
+        int startengine; /* GPMC_PREFETCH_CONTROL:STARTENGINE */
+        int fifopointer; /* GPMC_PREFETCH_STATUS:FIFOPOINTER */
+        int count; /* GPMC_PREFETCH_STATUS:COUNTVALUE */
+        MemoryRegion iomem;
+        uint8_t fifo[64];
+    } prefetch;
+};
+
+#define OMAP_GPMC_8BIT 0
+#define OMAP_GPMC_16BIT 1
+#define OMAP_GPMC_NOR 0
+#define OMAP_GPMC_NAND 2
+
+static int omap_gpmc_devtype(struct omap_gpmc_cs_file_s *f)
+{
+    return (f->config[0] >> 10) & 3;
+}
+
+static int omap_gpmc_devsize(struct omap_gpmc_cs_file_s *f)
+{
+    /* devsize field is really 2 bits but we ignore the high
+     * bit to ensure consistent behaviour if the guest sets
+     * it (values 2 and 3 are reserved in the TRM)
+     */
+    return (f->config[0] >> 12) & 1;
+}
+
+/* Extract the chip-select value from the prefetch config1 register */
+static int prefetch_cs(uint32_t config1)
+{
+    return (config1 >> 24) & 7;
+}
+
+static int prefetch_threshold(uint32_t config1)
+{
+    return (config1 >> 8) & 0x7f;
+}
+
+static void omap_gpmc_int_update(struct omap_gpmc_s *s)
+{
+    /* The TRM is a bit unclear, but it seems to say that
+     * the TERMINALCOUNTSTATUS bit is set only on the
+     * transition when the prefetch engine goes from
+     * active to inactive, whereas the FIFOEVENTSTATUS
+     * bit is held high as long as the fifo has at
+     * least THRESHOLD bytes available.
+     * So we do the latter here, but TERMINALCOUNTSTATUS
+     * is set elsewhere.
+     */
+    if (s->prefetch.fifopointer >= prefetch_threshold(s->prefetch.config1)) {
+        s->irqst |= 1;
+    }
+    if ((s->irqen & s->irqst) != s->lastirq) {
+        s->lastirq = s->irqen & s->irqst;
+        qemu_set_irq(s->irq, s->lastirq);
+    }
+}
+
+static void omap_gpmc_dma_update(struct omap_gpmc_s *s, int value)
+{
+    if (s->prefetch.config1 & 4) {
+        qemu_set_irq(s->drq, value);
+    }
+}
+
+/* Access functions for when a NAND-like device is mapped into memory:
+ * all addresses in the region behave like accesses to the relevant
+ * GPMC_NAND_DATA_i register (which is actually implemented to call these)
+ */
+static uint64_t omap_nand_read(void *opaque, hwaddr addr,
+                               unsigned size)
+{
+    struct omap_gpmc_cs_file_s *f = (struct omap_gpmc_cs_file_s *)opaque;
+    uint64_t v;
+    nand_setpins(f->dev, 0, 0, 0, 1, 0);
+    switch (omap_gpmc_devsize(f)) {
+    case OMAP_GPMC_8BIT:
+        v = nand_getio(f->dev);
+        if (size == 1) {
+            return v;
+        }
+        v |= (nand_getio(f->dev) << 8);
+        if (size == 2) {
+            return v;
+        }
+        v |= (nand_getio(f->dev) << 16);
+        v |= (nand_getio(f->dev) << 24);
+        return v;
+    case OMAP_GPMC_16BIT:
+        v = nand_getio(f->dev);
+        if (size == 1) {
+            /* 8 bit read from 16 bit device : probably a guest bug */
+            return v & 0xff;
+        }
+        if (size == 2) {
+            return v;
+        }
+        v |= (nand_getio(f->dev) << 16);
+        return v;
+    default:
+        abort();
+    }
+}
+
+static void omap_nand_setio(DeviceState *dev, uint64_t value,
+                            int nandsize, int size)
+{
+    /* Write the specified value to the NAND device, respecting
+     * both size of the NAND device and size of the write access.
+     */
+    switch (nandsize) {
+    case OMAP_GPMC_8BIT:
+        switch (size) {
+        case 1:
+            nand_setio(dev, value & 0xff);
+            break;
+        case 2:
+            nand_setio(dev, value & 0xff);
+            nand_setio(dev, (value >> 8) & 0xff);
+            break;
+        case 4:
+        default:
+            nand_setio(dev, value & 0xff);
+            nand_setio(dev, (value >> 8) & 0xff);
+            nand_setio(dev, (value >> 16) & 0xff);
+            nand_setio(dev, (value >> 24) & 0xff);
+            break;
+        }
+        break;
+    case OMAP_GPMC_16BIT:
+        switch (size) {
+        case 1:
+            /* writing to a 16bit device with 8bit access is probably a guest
+             * bug; pass the value through anyway.
+             */
+        case 2:
+            nand_setio(dev, value & 0xffff);
+            break;
+        case 4:
+        default:
+            nand_setio(dev, value & 0xffff);
+            nand_setio(dev, (value >> 16) & 0xffff);
+            break;
+        }
+        break;
+    }
+}
+
+static void omap_nand_write(void *opaque, hwaddr addr,
+                            uint64_t value, unsigned size)
+{
+    struct omap_gpmc_cs_file_s *f = (struct omap_gpmc_cs_file_s *)opaque;
+    nand_setpins(f->dev, 0, 0, 0, 1, 0);
+    omap_nand_setio(f->dev, value, omap_gpmc_devsize(f), size);
+}
+
+static const MemoryRegionOps omap_nand_ops = {
+    .read = omap_nand_read,
+    .write = omap_nand_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void fill_prefetch_fifo(struct omap_gpmc_s *s)
+{
+    /* Fill the prefetch FIFO by reading data from NAND.
+     * We do this synchronously, unlike the hardware which
+     * will do this asynchronously. We refill when the
+     * FIFO has THRESHOLD bytes free, and we always refill
+     * as much data as possible starting at the top end
+     * of the FIFO.
+     * (We have to refill at THRESHOLD rather than waiting
+     * for the FIFO to empty to allow for the case where
+     * the FIFO size isn't an exact multiple of THRESHOLD
+     * and we're doing DMA transfers.)
+     * This means we never need to handle wrap-around in
+     * the fifo-reading code, and the next byte of data
+     * to read is always fifo[63 - fifopointer].
+     */
+    int fptr;
+    int cs = prefetch_cs(s->prefetch.config1);
+    int is16bit = (((s->cs_file[cs].config[0] >> 12) & 3) != 0);
+    int bytes;
+    /* Don't believe the bit of the OMAP TRM that says that COUNTVALUE
+     * and TRANSFERCOUNT are in units of 16 bit words for 16 bit NAND.
+     * Instead believe the bit that says it is always a byte count.
+     */
+    bytes = 64 - s->prefetch.fifopointer;
+    if (bytes > s->prefetch.count) {
+        bytes = s->prefetch.count;
+    }
+    s->prefetch.count -= bytes;
+    s->prefetch.fifopointer += bytes;
+    fptr = 64 - s->prefetch.fifopointer;
+    /* Move the existing data in the FIFO so it sits just
+     * before what we're about to read in
+     */
+    while (fptr < (64 - bytes)) {
+        s->prefetch.fifo[fptr] = s->prefetch.fifo[fptr + bytes];
+        fptr++;
+    }
+    while (fptr < 64) {
+        if (is16bit) {
+            uint32_t v = omap_nand_read(&s->cs_file[cs], 0, 2);
+            s->prefetch.fifo[fptr++] = v & 0xff;
+            s->prefetch.fifo[fptr++] = (v >> 8) & 0xff;
+        } else {
+            s->prefetch.fifo[fptr++] = omap_nand_read(&s->cs_file[cs], 0, 1);
+        }
+    }
+    if (s->prefetch.startengine && (s->prefetch.count == 0)) {
+        /* This was the final transfer: raise TERMINALCOUNTSTATUS */
+        s->irqst |= 2;
+        s->prefetch.startengine = 0;
+    }
+    /* If there are any bytes in the FIFO at this point then
+     * we must raise a DMA request (either this is a final part
+     * transfer, or we filled the FIFO in which case we certainly
+     * have THRESHOLD bytes available)
+     */
+    if (s->prefetch.fifopointer != 0) {
+        omap_gpmc_dma_update(s, 1);
+    }
+    omap_gpmc_int_update(s);
+}
+
+/* Access functions for a NAND-like device when the prefetch/postwrite
+ * engine is enabled -- all addresses in the region behave alike:
+ * data is read or written to the FIFO.
+ */
+static uint64_t omap_gpmc_prefetch_read(void *opaque, hwaddr addr,
+                                        unsigned size)
+{
+    struct omap_gpmc_s *s = (struct omap_gpmc_s *) opaque;
+    uint32_t data;
+    if (s->prefetch.config1 & 1) {
+        /* The TRM doesn't define the behaviour if you read from the
+         * FIFO when the prefetch engine is in write mode. We choose
+         * to always return zero.
+         */
+        return 0;
+    }
+    /* Note that trying to read an empty fifo repeats the last byte */
+    if (s->prefetch.fifopointer) {
+        s->prefetch.fifopointer--;
+    }
+    data = s->prefetch.fifo[63 - s->prefetch.fifopointer];
+    if (s->prefetch.fifopointer ==
+        (64 - prefetch_threshold(s->prefetch.config1))) {
+        /* We've drained THRESHOLD bytes now. So deassert the
+         * DMA request, then refill the FIFO (which will probably
+         * assert it again.)
+         */
+        omap_gpmc_dma_update(s, 0);
+        fill_prefetch_fifo(s);
+    }
+    omap_gpmc_int_update(s);
+    return data;
+}
+
+static void omap_gpmc_prefetch_write(void *opaque, hwaddr addr,
+                                     uint64_t value, unsigned size)
+{
+    struct omap_gpmc_s *s = (struct omap_gpmc_s *) opaque;
+    int cs = prefetch_cs(s->prefetch.config1);
+    if ((s->prefetch.config1 & 1) == 0) {
+        /* The TRM doesn't define the behaviour of writing to the
+         * FIFO when the prefetch engine is in read mode. We
+         * choose to ignore the write.
+         */
+        return;
+    }
+    if (s->prefetch.count == 0) {
+        /* The TRM doesn't define the behaviour of writing to the
+         * FIFO if the transfer is complete. We choose to ignore.
+         */
+        return;
+    }
+    /* The only reason we do any data buffering in postwrite
+     * mode is if we are talking to a 16 bit NAND device, in
+     * which case we need to buffer the first byte of the
+     * 16 bit word until the other byte arrives.
+     */
+    int is16bit = (((s->cs_file[cs].config[0] >> 12) & 3) != 0);
+    if (is16bit) {
+        /* fifopointer alternates between 64 (waiting for first
+         * byte of word) and 63 (waiting for second byte)
+         */
+        if (s->prefetch.fifopointer == 64) {
+            s->prefetch.fifo[0] = value;
+            s->prefetch.fifopointer--;
+        } else {
+            value = (value << 8) | s->prefetch.fifo[0];
+            omap_nand_write(&s->cs_file[cs], 0, value, 2);
+            s->prefetch.count--;
+            s->prefetch.fifopointer = 64;
+        }
+    } else {
+        /* Just write the byte : fifopointer remains 64 at all times */
+        omap_nand_write(&s->cs_file[cs], 0, value, 1);
+        s->prefetch.count--;
+    }
+    if (s->prefetch.count == 0) {
+        /* Final transfer: raise TERMINALCOUNTSTATUS */
+        s->irqst |= 2;
+        s->prefetch.startengine = 0;
+    }
+    omap_gpmc_int_update(s);
+}
+
+static const MemoryRegionOps omap_prefetch_ops = {
+    .read = omap_gpmc_prefetch_read,
+    .write = omap_gpmc_prefetch_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .impl.min_access_size = 1,
+    .impl.max_access_size = 1,
+};
+
+static MemoryRegion *omap_gpmc_cs_memregion(struct omap_gpmc_s *s, int cs)
+{
+    /* Return the MemoryRegion* to map/unmap for this chipselect */
+    struct omap_gpmc_cs_file_s *f = &s->cs_file[cs];
+    if (omap_gpmc_devtype(f) == OMAP_GPMC_NOR) {
+        return f->iomem;
+    }
+    if ((s->prefetch.config1 & 0x80) &&
+        (prefetch_cs(s->prefetch.config1) == cs)) {
+        /* The prefetch engine is enabled for this CS: map the FIFO */
+        return &s->prefetch.iomem;
+    }
+    return &f->nandiomem;
+}
+
+static void omap_gpmc_cs_map(struct omap_gpmc_s *s, int cs)
+{
+    struct omap_gpmc_cs_file_s *f = &s->cs_file[cs];
+    uint32_t mask = (f->config[6] >> 8) & 0xf;
+    uint32_t base = f->config[6] & 0x3f;
+    uint32_t size;
+
+    if (!f->iomem && !f->dev) {
+        return;
+    }
+
+    if (!(f->config[6] & (1 << 6))) {
+        /* Do nothing unless CSVALID */
+        return;
+    }
+
+    /* TODO: check for overlapping regions and report access errors */
+    if (mask != 0x8 && mask != 0xc && mask != 0xe && mask != 0xf
+         && !(s->accept_256 && !mask)) {
+        fprintf(stderr, "%s: invalid chip-select mask address (0x%x)\n",
+                 __func__, mask);
+    }
+
+    base <<= 24;
+    size = (0x0fffffff & ~(mask << 24)) + 1;
+    /* TODO: rather than setting the size of the mapping (which should be
+     * constant), the mask should cause wrapping of the address space, so
+     * that the same memory becomes accessible at every <i>size</i> bytes
+     * starting from <i>base</i>.  */
+    memory_region_init(&f->container, "omap-gpmc-file", size);
+    memory_region_add_subregion(&f->container, 0,
+                                omap_gpmc_cs_memregion(s, cs));
+    memory_region_add_subregion(get_system_memory(), base,
+                                &f->container);
+}
+
+static void omap_gpmc_cs_unmap(struct omap_gpmc_s *s, int cs)
+{
+    struct omap_gpmc_cs_file_s *f = &s->cs_file[cs];
+    if (!(f->config[6] & (1 << 6))) {
+        /* Do nothing unless CSVALID */
+        return;
+    }
+    if (!f->iomem && !f->dev) {
+        return;
+    }
+    memory_region_del_subregion(get_system_memory(), &f->container);
+    memory_region_del_subregion(&f->container, omap_gpmc_cs_memregion(s, cs));
+    memory_region_destroy(&f->container);
+}
+
+void omap_gpmc_reset(struct omap_gpmc_s *s)
+{
+    int i;
+
+    s->sysconfig = 0;
+    s->irqst = 0;
+    s->irqen = 0;
+    omap_gpmc_int_update(s);
+    for (i = 0; i < 8; i++) {
+        /* This has to happen before we change any of the config
+         * used to determine which memory regions are mapped or unmapped.
+         */
+        omap_gpmc_cs_unmap(s, i);
+    }
+    s->timeout = 0;
+    s->config = 0xa00;
+    s->prefetch.config1 = 0x00004000;
+    s->prefetch.transfercount = 0x00000000;
+    s->prefetch.startengine = 0;
+    s->prefetch.fifopointer = 0;
+    s->prefetch.count = 0;
+    for (i = 0; i < 8; i ++) {
+        s->cs_file[i].config[1] = 0x101001;
+        s->cs_file[i].config[2] = 0x020201;
+        s->cs_file[i].config[3] = 0x10031003;
+        s->cs_file[i].config[4] = 0x10f1111;
+        s->cs_file[i].config[5] = 0;
+        s->cs_file[i].config[6] = 0xf00 | (i ? 0 : 1 << 6);
+
+        s->cs_file[i].config[6] = 0xf00;
+        /* In theory we could probe attached devices for some CFG1
+         * bits here, but we just retain them across resets as they
+         * were set initially by omap_gpmc_attach().
+         */
+        if (i == 0) {
+            s->cs_file[i].config[0] &= 0x00433e00;
+            s->cs_file[i].config[6] |= 1 << 6; /* CSVALID */
+            omap_gpmc_cs_map(s, i);
+        } else {
+            s->cs_file[i].config[0] &= 0x00403c00;
+        }
+    }
+    s->ecc_cs = 0;
+    s->ecc_ptr = 0;
+    s->ecc_cfg = 0x3fcff000;
+    for (i = 0; i < 9; i ++)
+        ecc_reset(&s->ecc[i]);
+}
+
+static int gpmc_wordaccess_only(hwaddr addr)
+{
+    /* Return true if the register offset is to a register that
+     * only permits word width accesses.
+     * Non-word accesses are only OK for GPMC_NAND_DATA/ADDRESS/COMMAND
+     * for any chipselect.
+     */
+    if (addr >= 0x60 && addr <= 0x1d4) {
+        int cs = (addr - 0x60) / 0x30;
+        addr -= cs * 0x30;
+        if (addr >= 0x7c && addr < 0x88) {
+            /* GPMC_NAND_COMMAND, GPMC_NAND_ADDRESS, GPMC_NAND_DATA */
+            return 0;
+        }
+    }
+    return 1;
+}
+
+static uint64_t omap_gpmc_read(void *opaque, hwaddr addr,
+                               unsigned size)
+{
+    struct omap_gpmc_s *s = (struct omap_gpmc_s *) opaque;
+    int cs;
+    struct omap_gpmc_cs_file_s *f;
+
+    if (size != 4 && gpmc_wordaccess_only(addr)) {
+        return omap_badwidth_read32(opaque, addr);
+    }
+
+    switch (addr) {
+    case 0x000:        /* GPMC_REVISION */
+        return s->revision;
+
+    case 0x010:        /* GPMC_SYSCONFIG */
+        return s->sysconfig;
+
+    case 0x014:        /* GPMC_SYSSTATUS */
+        return 1;                                              /* RESETDONE */
+
+    case 0x018:        /* GPMC_IRQSTATUS */
+        return s->irqst;
+
+    case 0x01c:        /* GPMC_IRQENABLE */
+        return s->irqen;
+
+    case 0x040:        /* GPMC_TIMEOUT_CONTROL */
+        return s->timeout;
+
+    case 0x044:        /* GPMC_ERR_ADDRESS */
+    case 0x048:        /* GPMC_ERR_TYPE */
+        return 0;
+
+    case 0x050:        /* GPMC_CONFIG */
+        return s->config;
+
+    case 0x054:        /* GPMC_STATUS */
+        return 0x001;
+
+    case 0x060 ... 0x1d4:
+        cs = (addr - 0x060) / 0x30;
+        addr -= cs * 0x30;
+        f = s->cs_file + cs;
+        switch (addr) {
+        case 0x60:      /* GPMC_CONFIG1 */
+            return f->config[0];
+        case 0x64:      /* GPMC_CONFIG2 */
+            return f->config[1];
+        case 0x68:      /* GPMC_CONFIG3 */
+            return f->config[2];
+        case 0x6c:      /* GPMC_CONFIG4 */
+            return f->config[3];
+        case 0x70:      /* GPMC_CONFIG5 */
+            return f->config[4];
+        case 0x74:      /* GPMC_CONFIG6 */
+            return f->config[5];
+        case 0x78:      /* GPMC_CONFIG7 */
+            return f->config[6];
+        case 0x84 ... 0x87: /* GPMC_NAND_DATA */
+            if (omap_gpmc_devtype(f) == OMAP_GPMC_NAND) {
+                return omap_nand_read(f, 0, size);
+            }
+            return 0;
+        }
+        break;
+
+    case 0x1e0:        /* GPMC_PREFETCH_CONFIG1 */
+        return s->prefetch.config1;
+    case 0x1e4:        /* GPMC_PREFETCH_CONFIG2 */
+        return s->prefetch.transfercount;
+    case 0x1ec:        /* GPMC_PREFETCH_CONTROL */
+        return s->prefetch.startengine;
+    case 0x1f0:        /* GPMC_PREFETCH_STATUS */
+        /* NB: The OMAP3 TRM is inconsistent about whether the GPMC
+         * FIFOTHRESHOLDSTATUS bit should be set when
+         * FIFOPOINTER > FIFOTHRESHOLD or when it is >= FIFOTHRESHOLD.
+         * Apparently the underlying functional spec from which the TRM was
+         * created states that the behaviour is ">=", and this also
+         * makes more conceptual sense.
+         */
+        return (s->prefetch.fifopointer << 24) |
+                ((s->prefetch.fifopointer >=
+                  ((s->prefetch.config1 >> 8) & 0x7f) ? 1 : 0) << 16) |
+                s->prefetch.count;
+
+    case 0x1f4:        /* GPMC_ECC_CONFIG */
+        return s->ecc_cs;
+    case 0x1f8:        /* GPMC_ECC_CONTROL */
+        return s->ecc_ptr;
+    case 0x1fc:        /* GPMC_ECC_SIZE_CONFIG */
+        return s->ecc_cfg;
+    case 0x200 ... 0x220:      /* GPMC_ECC_RESULT */
+        cs = (addr & 0x1f) >> 2;
+        /* TODO: check correctness */
+        return
+                ((s->ecc[cs].cp    &  0x07) <<  0) |
+                ((s->ecc[cs].cp    &  0x38) << 13) |
+                ((s->ecc[cs].lp[0] & 0x1ff) <<  3) |
+                ((s->ecc[cs].lp[1] & 0x1ff) << 19);
+
+    case 0x230:        /* GPMC_TESTMODE_CTRL */
+        return 0;
+    case 0x234:        /* GPMC_PSA_LSB */
+    case 0x238:        /* GPMC_PSA_MSB */
+        return 0x00000000;
+    }
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_gpmc_write(void *opaque, hwaddr addr,
+                            uint64_t value, unsigned size)
+{
+    struct omap_gpmc_s *s = (struct omap_gpmc_s *) opaque;
+    int cs;
+    struct omap_gpmc_cs_file_s *f;
+
+    if (size != 4 && gpmc_wordaccess_only(addr)) {
+        return omap_badwidth_write32(opaque, addr, value);
+    }
+
+    switch (addr) {
+    case 0x000:        /* GPMC_REVISION */
+    case 0x014:        /* GPMC_SYSSTATUS */
+    case 0x054:        /* GPMC_STATUS */
+    case 0x1f0:        /* GPMC_PREFETCH_STATUS */
+    case 0x200 ... 0x220:      /* GPMC_ECC_RESULT */
+    case 0x234:        /* GPMC_PSA_LSB */
+    case 0x238:        /* GPMC_PSA_MSB */
+        OMAP_RO_REG(addr);
+        break;
+
+    case 0x010:        /* GPMC_SYSCONFIG */
+        if ((value >> 3) == 0x3)
+            fprintf(stderr, "%s: bad SDRAM idle mode %"PRIi64"\n",
+                            __FUNCTION__, value >> 3);
+        if (value & 2)
+            omap_gpmc_reset(s);
+        s->sysconfig = value & 0x19;
+        break;
+
+    case 0x018:        /* GPMC_IRQSTATUS */
+        s->irqst &= ~value;
+        omap_gpmc_int_update(s);
+        break;
+
+    case 0x01c:        /* GPMC_IRQENABLE */
+        s->irqen = value & 0xf03;
+        omap_gpmc_int_update(s);
+        break;
+
+    case 0x040:        /* GPMC_TIMEOUT_CONTROL */
+        s->timeout = value & 0x1ff1;
+        break;
+
+    case 0x044:        /* GPMC_ERR_ADDRESS */
+    case 0x048:        /* GPMC_ERR_TYPE */
+        break;
+
+    case 0x050:        /* GPMC_CONFIG */
+        s->config = value & 0xf13;
+        break;
+
+    case 0x060 ... 0x1d4:
+        cs = (addr - 0x060) / 0x30;
+        addr -= cs * 0x30;
+        f = s->cs_file + cs;
+        switch (addr) {
+        case 0x60:      /* GPMC_CONFIG1 */
+            f->config[0] = value & 0xffef3e13;
+            break;
+        case 0x64:      /* GPMC_CONFIG2 */
+            f->config[1] = value & 0x001f1f8f;
+            break;
+        case 0x68:      /* GPMC_CONFIG3 */
+            f->config[2] = value & 0x001f1f8f;
+            break;
+        case 0x6c:      /* GPMC_CONFIG4 */
+            f->config[3] = value & 0x1f8f1f8f;
+            break;
+        case 0x70:      /* GPMC_CONFIG5 */
+            f->config[4] = value & 0x0f1f1f1f;
+            break;
+        case 0x74:      /* GPMC_CONFIG6 */
+            f->config[5] = value & 0x00000fcf;
+            break;
+        case 0x78:      /* GPMC_CONFIG7 */
+            if ((f->config[6] ^ value) & 0xf7f) {
+                omap_gpmc_cs_unmap(s, cs);
+                f->config[6] = value & 0x00000f7f;
+                omap_gpmc_cs_map(s, cs);
+            }
+            break;
+        case 0x7c ... 0x7f: /* GPMC_NAND_COMMAND */
+            if (omap_gpmc_devtype(f) == OMAP_GPMC_NAND) {
+                nand_setpins(f->dev, 1, 0, 0, 1, 0); /* CLE */
+                omap_nand_setio(f->dev, value, omap_gpmc_devsize(f), size);
+            }
+            break;
+        case 0x80 ... 0x83: /* GPMC_NAND_ADDRESS */
+            if (omap_gpmc_devtype(f) == OMAP_GPMC_NAND) {
+                nand_setpins(f->dev, 0, 1, 0, 1, 0); /* ALE */
+                omap_nand_setio(f->dev, value, omap_gpmc_devsize(f), size);
+            }
+            break;
+        case 0x84 ... 0x87: /* GPMC_NAND_DATA */
+            if (omap_gpmc_devtype(f) == OMAP_GPMC_NAND) {
+                omap_nand_write(f, 0, value, size);
+            }
+            break;
+        default:
+            goto bad_reg;
+        }
+        break;
+
+    case 0x1e0:        /* GPMC_PREFETCH_CONFIG1 */
+        if (!s->prefetch.startengine) {
+            uint32_t newconfig1 = value & 0x7f8f7fbf;
+            uint32_t changed;
+            changed = newconfig1 ^ s->prefetch.config1;
+            if (changed & (0x80 | 0x7000000)) {
+                /* Turning the engine on or off, or mapping it somewhere else.
+                 * cs_map() and cs_unmap() check the prefetch config and
+                 * overall CSVALID bits, so it is sufficient to unmap-and-map
+                 * both the old cs and the new one. Note that we adhere to
+                 * the "unmap/change config/map" order (and not unmap twice
+                 * if newcs == oldcs), otherwise we'll try to delete the wrong
+                 * memory region.
+                 */
+                int oldcs = prefetch_cs(s->prefetch.config1);
+                int newcs = prefetch_cs(newconfig1);
+                omap_gpmc_cs_unmap(s, oldcs);
+                if (oldcs != newcs) {
+                    omap_gpmc_cs_unmap(s, newcs);
+                }
+                s->prefetch.config1 = newconfig1;
+                omap_gpmc_cs_map(s, oldcs);
+                if (oldcs != newcs) {
+                    omap_gpmc_cs_map(s, newcs);
+                }
+            } else {
+                s->prefetch.config1 = newconfig1;
+            }
+        }
+        break;
+
+    case 0x1e4:        /* GPMC_PREFETCH_CONFIG2 */
+        if (!s->prefetch.startengine) {
+            s->prefetch.transfercount = value & 0x3fff;
+        }
+        break;
+
+    case 0x1ec:        /* GPMC_PREFETCH_CONTROL */
+        if (s->prefetch.startengine != (value & 1)) {
+            s->prefetch.startengine = value & 1;
+            if (s->prefetch.startengine) {
+                /* Prefetch engine start */
+                s->prefetch.count = s->prefetch.transfercount;
+                if (s->prefetch.config1 & 1) {
+                    /* Write */
+                    s->prefetch.fifopointer = 64;
+                } else {
+                    /* Read */
+                    s->prefetch.fifopointer = 0;
+                    fill_prefetch_fifo(s);
+                }
+            } else {
+                /* Prefetch engine forcibly stopped. The TRM
+                 * doesn't define the behaviour if you do this.
+                 * We clear the prefetch count, which means that
+                 * we permit no more writes, and don't read any
+                 * more data from NAND. The CPU can still drain
+                 * the FIFO of unread data.
+                 */
+                s->prefetch.count = 0;
+            }
+            omap_gpmc_int_update(s);
+        }
+        break;
+
+    case 0x1f4:        /* GPMC_ECC_CONFIG */
+        s->ecc_cs = 0x8f;
+        break;
+    case 0x1f8:        /* GPMC_ECC_CONTROL */
+        if (value & (1 << 8))
+            for (cs = 0; cs < 9; cs ++)
+                ecc_reset(&s->ecc[cs]);
+        s->ecc_ptr = value & 0xf;
+        if (s->ecc_ptr == 0 || s->ecc_ptr > 9) {
+            s->ecc_ptr = 0;
+            s->ecc_cs &= ~1;
+        }
+        break;
+    case 0x1fc:        /* GPMC_ECC_SIZE_CONFIG */
+        s->ecc_cfg = value & 0x3fcff1ff;
+        break;
+    case 0x230:        /* GPMC_TESTMODE_CTRL */
+        if (value & 7)
+            fprintf(stderr, "%s: test mode enable attempt\n", __FUNCTION__);
+        break;
+
+    default:
+    bad_reg:
+        OMAP_BAD_REG(addr);
+        return;
+    }
+}
+
+static const MemoryRegionOps omap_gpmc_ops = {
+    .read = omap_gpmc_read,
+    .write = omap_gpmc_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+struct omap_gpmc_s *omap_gpmc_init(struct omap_mpu_state_s *mpu,
+                                   hwaddr base,
+                                   qemu_irq irq, qemu_irq drq)
+{
+    int cs;
+    struct omap_gpmc_s *s = (struct omap_gpmc_s *)
+            g_malloc0(sizeof(struct omap_gpmc_s));
+
+    memory_region_init_io(&s->iomem, &omap_gpmc_ops, s, "omap-gpmc", 0x1000);
+    memory_region_add_subregion(get_system_memory(), base, &s->iomem);
+
+    s->irq = irq;
+    s->drq = drq;
+    s->accept_256 = cpu_is_omap3630(mpu);
+    s->revision = cpu_class_omap3(mpu) ? 0x50 : 0x20;
+    s->lastirq = 0;
+    omap_gpmc_reset(s);
+
+    /* We have to register a different IO memory handler for each
+     * chip select region in case a NAND device is mapped there. We
+     * make the region the worst-case size of 256MB and rely on the
+     * container memory region in cs_map to chop it down to the actual
+     * guest-requested size.
+     */
+    for (cs = 0; cs < 8; cs++) {
+        memory_region_init_io(&s->cs_file[cs].nandiomem,
+                              &omap_nand_ops,
+                              &s->cs_file[cs],
+                              "omap-nand",
+                              256 * 1024 * 1024);
+    }
+
+    memory_region_init_io(&s->prefetch.iomem, &omap_prefetch_ops, s,
+                          "omap-gpmc-prefetch", 256 * 1024 * 1024);
+    return s;
+}
+
+void omap_gpmc_attach(struct omap_gpmc_s *s, int cs, MemoryRegion *iomem)
+{
+    struct omap_gpmc_cs_file_s *f;
+    assert(iomem);
+
+    if (cs < 0 || cs >= 8) {
+        fprintf(stderr, "%s: bad chip-select %i\n", __FUNCTION__, cs);
+        exit(-1);
+    }
+    f = &s->cs_file[cs];
+
+    omap_gpmc_cs_unmap(s, cs);
+    f->config[0] &= ~(0xf << 10);
+    f->iomem = iomem;
+    omap_gpmc_cs_map(s, cs);
+}
+
+void omap_gpmc_attach_nand(struct omap_gpmc_s *s, int cs, DeviceState *nand)
+{
+    struct omap_gpmc_cs_file_s *f;
+    assert(nand);
+
+    if (cs < 0 || cs >= 8) {
+        fprintf(stderr, "%s: bad chip-select %i\n", __func__, cs);
+        exit(-1);
+    }
+    f = &s->cs_file[cs];
+
+    omap_gpmc_cs_unmap(s, cs);
+    f->config[0] &= ~(0xf << 10);
+    f->config[0] |= (OMAP_GPMC_NAND << 10);
+    f->dev = nand;
+    if (nand_getbuswidth(f->dev) == 16) {
+        f->config[0] |= OMAP_GPMC_16BIT << 12;
+    }
+    omap_gpmc_cs_map(s, cs);
+}
diff --git a/hw/misc/omap_l4.c b/hw/misc/omap_l4.c
new file mode 100644 (file)
index 0000000..ac8251f
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * TI OMAP L4 interconnect emulation.
+ *
+ * Copyright (C) 2007-2009 Nokia Corporation
+ * Written by Andrzej Zaborowski <andrew@openedhand.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 or
+ * (at your option) any later version 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
+ * 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 "hw/hw.h"
+#include "hw/arm/omap.h"
+
+struct omap_l4_s {
+    MemoryRegion *address_space;
+    hwaddr base;
+    int ta_num;
+    struct omap_target_agent_s ta[0];
+};
+
+struct omap_l4_s *omap_l4_init(MemoryRegion *address_space,
+                               hwaddr base, int ta_num)
+{
+    struct omap_l4_s *bus = g_malloc0(
+                    sizeof(*bus) + ta_num * sizeof(*bus->ta));
+
+    bus->address_space = address_space;
+    bus->ta_num = ta_num;
+    bus->base = base;
+
+    return bus;
+}
+
+hwaddr omap_l4_region_base(struct omap_target_agent_s *ta,
+                                       int region)
+{
+    return ta->bus->base + ta->start[region].offset;
+}
+
+hwaddr omap_l4_region_size(struct omap_target_agent_s *ta,
+                                       int region)
+{
+    return ta->start[region].size;
+}
+
+static uint64_t omap_l4ta_read(void *opaque, hwaddr addr,
+                               unsigned size)
+{
+    struct omap_target_agent_s *s = (struct omap_target_agent_s *) opaque;
+
+    if (size != 2) {
+        return omap_badwidth_read16(opaque, addr);
+    }
+
+    switch (addr) {
+    case 0x00: /* COMPONENT */
+        return s->component;
+
+    case 0x20: /* AGENT_CONTROL */
+        return s->control;
+
+    case 0x28: /* AGENT_STATUS */
+        return s->status;
+    }
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_l4ta_write(void *opaque, hwaddr addr,
+                            uint64_t value, unsigned size)
+{
+    struct omap_target_agent_s *s = (struct omap_target_agent_s *) opaque;
+
+    if (size != 4) {
+        return omap_badwidth_write32(opaque, addr, value);
+    }
+
+    switch (addr) {
+    case 0x00: /* COMPONENT */
+    case 0x28: /* AGENT_STATUS */
+        OMAP_RO_REG(addr);
+        break;
+
+    case 0x20: /* AGENT_CONTROL */
+        s->control = value & 0x01000700;
+        if (value & 1)                                 /* OCP_RESET */
+            s->status &= ~1;                           /* REQ_TIMEOUT */
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+    }
+}
+
+static const MemoryRegionOps omap_l4ta_ops = {
+    .read = omap_l4ta_read,
+    .write = omap_l4ta_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+struct omap_target_agent_s *omap_l4ta_get(struct omap_l4_s *bus,
+        const struct omap_l4_region_s *regions,
+       const struct omap_l4_agent_info_s *agents,
+       int cs)
+{
+    int i;
+    struct omap_target_agent_s *ta = NULL;
+    const struct omap_l4_agent_info_s *info = NULL;
+
+    for (i = 0; i < bus->ta_num; i ++)
+        if (agents[i].ta == cs) {
+            ta = &bus->ta[i];
+            info = &agents[i];
+            break;
+        }
+    if (!ta) {
+        fprintf(stderr, "%s: bad target agent (%i)\n", __FUNCTION__, cs);
+        exit(-1);
+    }
+
+    ta->bus = bus;
+    ta->start = &regions[info->region];
+    ta->regions = info->regions;
+
+    ta->component = ('Q' << 24) | ('E' << 16) | ('M' << 8) | ('U' << 0);
+    ta->status = 0x00000000;
+    ta->control = 0x00000200;  /* XXX 01000200 for L4TAO */
+
+    memory_region_init_io(&ta->iomem, &omap_l4ta_ops, ta, "omap.l4ta",
+                          omap_l4_region_size(ta, info->ta_region));
+    omap_l4_attach(ta, info->ta_region, &ta->iomem);
+
+    return ta;
+}
+
+hwaddr omap_l4_attach(struct omap_target_agent_s *ta,
+                                         int region, MemoryRegion *mr)
+{
+    hwaddr base;
+
+    if (region < 0 || region >= ta->regions) {
+        fprintf(stderr, "%s: bad io region (%i)\n", __FUNCTION__, region);
+        exit(-1);
+    }
+
+    base = ta->bus->base + ta->start[region].offset;
+    if (mr) {
+        memory_region_add_subregion(ta->bus->address_space, base, mr);
+    }
+
+    return base;
+}
diff --git a/hw/misc/omap_sdrc.c b/hw/misc/omap_sdrc.c
new file mode 100644 (file)
index 0000000..e38b571
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * TI OMAP SDRAM controller emulation.
+ *
+ * Copyright (C) 2007-2008 Nokia Corporation
+ * Written by Andrzej Zaborowski <andrew@openedhand.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 or
+ * (at your option) any later version 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
+ * 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 "hw/hw.h"
+#include "hw/arm/omap.h"
+
+/* SDRAM Controller Subsystem */
+struct omap_sdrc_s {
+    MemoryRegion iomem;
+    uint8_t config;
+};
+
+void omap_sdrc_reset(struct omap_sdrc_s *s)
+{
+    s->config = 0x10;
+}
+
+static uint64_t omap_sdrc_read(void *opaque, hwaddr addr,
+                               unsigned size)
+{
+    struct omap_sdrc_s *s = (struct omap_sdrc_s *) opaque;
+
+    if (size != 4) {
+        return omap_badwidth_read32(opaque, addr);
+    }
+
+    switch (addr) {
+    case 0x00: /* SDRC_REVISION */
+        return 0x20;
+
+    case 0x10: /* SDRC_SYSCONFIG */
+        return s->config;
+
+    case 0x14: /* SDRC_SYSSTATUS */
+        return 1;                                              /* RESETDONE */
+
+    case 0x40: /* SDRC_CS_CFG */
+    case 0x44: /* SDRC_SHARING */
+    case 0x48: /* SDRC_ERR_ADDR */
+    case 0x4c: /* SDRC_ERR_TYPE */
+    case 0x60: /* SDRC_DLLA_SCTRL */
+    case 0x64: /* SDRC_DLLA_STATUS */
+    case 0x68: /* SDRC_DLLB_CTRL */
+    case 0x6c: /* SDRC_DLLB_STATUS */
+    case 0x70: /* SDRC_POWER */
+    case 0x80: /* SDRC_MCFG_0 */
+    case 0x84: /* SDRC_MR_0 */
+    case 0x88: /* SDRC_EMR1_0 */
+    case 0x8c: /* SDRC_EMR2_0 */
+    case 0x90: /* SDRC_EMR3_0 */
+    case 0x94: /* SDRC_DCDL1_CTRL */
+    case 0x98: /* SDRC_DCDL2_CTRL */
+    case 0x9c: /* SDRC_ACTIM_CTRLA_0 */
+    case 0xa0: /* SDRC_ACTIM_CTRLB_0 */
+    case 0xa4: /* SDRC_RFR_CTRL_0 */
+    case 0xa8: /* SDRC_MANUAL_0 */
+    case 0xb0: /* SDRC_MCFG_1 */
+    case 0xb4: /* SDRC_MR_1 */
+    case 0xb8: /* SDRC_EMR1_1 */
+    case 0xbc: /* SDRC_EMR2_1 */
+    case 0xc0: /* SDRC_EMR3_1 */
+    case 0xc4: /* SDRC_ACTIM_CTRLA_1 */
+    case 0xc8: /* SDRC_ACTIM_CTRLB_1 */
+    case 0xd4: /* SDRC_RFR_CTRL_1 */
+    case 0xd8: /* SDRC_MANUAL_1 */
+        return 0x00;
+    }
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_sdrc_write(void *opaque, hwaddr addr,
+                            uint64_t value, unsigned size)
+{
+    struct omap_sdrc_s *s = (struct omap_sdrc_s *) opaque;
+
+    if (size != 4) {
+        return omap_badwidth_write32(opaque, addr, value);
+    }
+
+    switch (addr) {
+    case 0x00: /* SDRC_REVISION */
+    case 0x14: /* SDRC_SYSSTATUS */
+    case 0x48: /* SDRC_ERR_ADDR */
+    case 0x64: /* SDRC_DLLA_STATUS */
+    case 0x6c: /* SDRC_DLLB_STATUS */
+        OMAP_RO_REG(addr);
+        return;
+
+    case 0x10: /* SDRC_SYSCONFIG */
+        if ((value >> 3) != 0x2)
+            fprintf(stderr, "%s: bad SDRAM idle mode %i\n",
+                    __FUNCTION__, (unsigned)value >> 3);
+        if (value & 2)
+            omap_sdrc_reset(s);
+        s->config = value & 0x18;
+        break;
+
+    case 0x40: /* SDRC_CS_CFG */
+    case 0x44: /* SDRC_SHARING */
+    case 0x4c: /* SDRC_ERR_TYPE */
+    case 0x60: /* SDRC_DLLA_SCTRL */
+    case 0x68: /* SDRC_DLLB_CTRL */
+    case 0x70: /* SDRC_POWER */
+    case 0x80: /* SDRC_MCFG_0 */
+    case 0x84: /* SDRC_MR_0 */
+    case 0x88: /* SDRC_EMR1_0 */
+    case 0x8c: /* SDRC_EMR2_0 */
+    case 0x90: /* SDRC_EMR3_0 */
+    case 0x94: /* SDRC_DCDL1_CTRL */
+    case 0x98: /* SDRC_DCDL2_CTRL */
+    case 0x9c: /* SDRC_ACTIM_CTRLA_0 */
+    case 0xa0: /* SDRC_ACTIM_CTRLB_0 */
+    case 0xa4: /* SDRC_RFR_CTRL_0 */
+    case 0xa8: /* SDRC_MANUAL_0 */
+    case 0xb0: /* SDRC_MCFG_1 */
+    case 0xb4: /* SDRC_MR_1 */
+    case 0xb8: /* SDRC_EMR1_1 */
+    case 0xbc: /* SDRC_EMR2_1 */
+    case 0xc0: /* SDRC_EMR3_1 */
+    case 0xc4: /* SDRC_ACTIM_CTRLA_1 */
+    case 0xc8: /* SDRC_ACTIM_CTRLB_1 */
+    case 0xd4: /* SDRC_RFR_CTRL_1 */
+    case 0xd8: /* SDRC_MANUAL_1 */
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+        return;
+    }
+}
+
+static const MemoryRegionOps omap_sdrc_ops = {
+    .read = omap_sdrc_read,
+    .write = omap_sdrc_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+struct omap_sdrc_s *omap_sdrc_init(MemoryRegion *sysmem,
+                                   hwaddr base)
+{
+    struct omap_sdrc_s *s = (struct omap_sdrc_s *)
+            g_malloc0(sizeof(struct omap_sdrc_s));
+
+    omap_sdrc_reset(s);
+
+    memory_region_init_io(&s->iomem, &omap_sdrc_ops, s, "omap.sdrc", 0x1000);
+    memory_region_add_subregion(sysmem, base, &s->iomem);
+
+    return s;
+}
diff --git a/hw/misc/omap_tap.c b/hw/misc/omap_tap.c
new file mode 100644 (file)
index 0000000..99b70d5
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * TI OMAP TEST-Chip-level TAP emulation.
+ *
+ * Copyright (C) 2007-2008 Nokia Corporation
+ * Written by Andrzej Zaborowski <andrew@openedhand.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 or
+ * (at your option) any later version 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
+ * 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 "hw/hw.h"
+#include "hw/arm/omap.h"
+
+/* TEST-Chip-level TAP */
+static uint64_t omap_tap_read(void *opaque, hwaddr addr,
+                              unsigned size)
+{
+    struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
+
+    if (size != 4) {
+        return omap_badwidth_read32(opaque, addr);
+    }
+
+    switch (addr) {
+    case 0x204:        /* IDCODE_reg */
+        switch (s->mpu_model) {
+        case omap2420:
+        case omap2422:
+        case omap2423:
+            return 0x5b5d902f; /* ES 2.2 */
+        case omap2430:
+            return 0x5b68a02f; /* ES 2.2 */
+        case omap3430:
+            return 0x1b7ae02f; /* ES 2 */
+        default:
+            hw_error("%s: Bad mpu model\n", __FUNCTION__);
+        }
+
+    case 0x208:        /* PRODUCTION_ID_reg for OMAP2 */
+    case 0x210:        /* PRODUCTION_ID_reg for OMAP3 */
+        switch (s->mpu_model) {
+        case omap2420:
+            return 0x000254f0; /* POP ESHS2.1.1 in N91/93/95, ES2 in N800 */
+        case omap2422:
+            return 0x000400f0;
+        case omap2423:
+            return 0x000800f0;
+        case omap2430:
+            return 0x000000f0;
+        case omap3430:
+            return 0x000000f0;
+        default:
+            hw_error("%s: Bad mpu model\n", __FUNCTION__);
+        }
+
+    case 0x20c:
+        switch (s->mpu_model) {
+        case omap2420:
+        case omap2422:
+        case omap2423:
+            return 0xcafeb5d9; /* ES 2.2 */
+        case omap2430:
+            return 0xcafeb68a; /* ES 2.2 */
+        case omap3430:
+            return 0xcafeb7ae; /* ES 2 */
+        default:
+            hw_error("%s: Bad mpu model\n", __FUNCTION__);
+        }
+
+    case 0x218:        /* DIE_ID_reg */
+        return ('Q' << 24) | ('E' << 16) | ('M' << 8) | ('U' << 0);
+    case 0x21c:        /* DIE_ID_reg */
+        return 0x54 << 24;
+    case 0x220:        /* DIE_ID_reg */
+        return ('Q' << 24) | ('E' << 16) | ('M' << 8) | ('U' << 0);
+    case 0x224:        /* DIE_ID_reg */
+        return ('Q' << 24) | ('E' << 16) | ('M' << 8) | ('U' << 0);
+    }
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_tap_write(void *opaque, hwaddr addr,
+                           uint64_t value, unsigned size)
+{
+    if (size != 4) {
+        return omap_badwidth_write32(opaque, addr, value);
+    }
+
+    OMAP_BAD_REG(addr);
+}
+
+static const MemoryRegionOps omap_tap_ops = {
+    .read = omap_tap_read,
+    .write = omap_tap_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+void omap_tap_init(struct omap_target_agent_s *ta,
+                struct omap_mpu_state_s *mpu)
+{
+    memory_region_init_io(&mpu->tap_iomem, &omap_tap_ops, mpu, "omap.tap",
+                          omap_l4_region_size(ta, 0));
+    omap_l4_attach(ta, 0, &mpu->tap_iomem);
+}
diff --git a/hw/misc/pc-testdev.c b/hw/misc/pc-testdev.c
new file mode 100644 (file)
index 0000000..32df175
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * QEMU x86 ISA testdev
+ *
+ * Copyright (c) 2012 Avi Kivity, Gerd Hoffmann, Marcelo Tosatti
+ *
+ * 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.
+ */
+
+/*
+ * This device is used to test KVM features specific to the x86 port, such
+ * as emulation, power management, interrupt routing, among others. It's meant
+ * to be used like:
+ *
+ * qemu-system-x86_64 -device pc-testdev -serial stdio \
+ * -device isa-debug-exit,iobase=0xf4,iosize=0x4 \
+ * -kernel /home/lmr/Code/virt-test.git/kvm/unittests/msr.flat
+ *
+ * Where msr.flat is one of the KVM unittests, present on a separate repo,
+ * git://git.kernel.org/pub/scm/virt/kvm/kvm-unit-tests.git
+*/
+
+#include "config-host.h"
+#if defined(CONFIG_POSIX)
+#include <sys/mman.h>
+#endif
+#include "hw/hw.h"
+#include "hw/qdev.h"
+#include "hw/isa/isa.h"
+
+#define IOMEM_LEN    0x10000
+
+typedef struct PCTestdev {
+    ISADevice parent_obj;
+
+    MemoryRegion ioport;
+    MemoryRegion flush;
+    MemoryRegion irq;
+    MemoryRegion iomem;
+    uint32_t ioport_data;
+    char iomem_buf[IOMEM_LEN];
+} PCTestdev;
+
+#define TYPE_TESTDEV "pc-testdev"
+#define TESTDEV(obj) \
+     OBJECT_CHECK(PCTestdev, (obj), TYPE_TESTDEV)
+
+static void test_irq_line(void *opaque, hwaddr addr, uint64_t data,
+                          unsigned len)
+{
+    PCTestdev *dev = opaque;
+    ISADevice *isa = ISA_DEVICE(dev);
+
+    qemu_set_irq(isa_get_irq(isa, addr), !!data);
+}
+
+static const MemoryRegionOps test_irq_ops = {
+    .write = test_irq_line,
+    .valid.min_access_size = 1,
+    .valid.max_access_size = 1,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void test_ioport_write(void *opaque, hwaddr addr, uint64_t data,
+                              unsigned len)
+{
+    PCTestdev *dev = opaque;
+    dev->ioport_data = data;
+}
+
+static uint64_t test_ioport_read(void *opaque, hwaddr addr, unsigned len)
+{
+    PCTestdev *dev = opaque;
+    return dev->ioport_data;
+}
+
+static const MemoryRegionOps test_ioport_ops = {
+    .read = test_ioport_read,
+    .write = test_ioport_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void test_flush_page(void *opaque, hwaddr addr, uint64_t data,
+                            unsigned len)
+{
+    hwaddr page = 4096;
+    void *a = cpu_physical_memory_map(data & ~0xffful, &page, 0);
+
+    /* We might not be able to get the full page, only mprotect what we actually
+       have mapped */
+#if defined(CONFIG_POSIX)
+    mprotect(a, page, PROT_NONE);
+    mprotect(a, page, PROT_READ|PROT_WRITE);
+#endif
+    cpu_physical_memory_unmap(a, page, 0, 0);
+}
+
+static const MemoryRegionOps test_flush_ops = {
+    .write = test_flush_page,
+    .valid.min_access_size = 4,
+    .valid.max_access_size = 4,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static uint64_t test_iomem_read(void *opaque, hwaddr addr, unsigned len)
+{
+    PCTestdev *dev = opaque;
+    uint64_t ret = 0;
+    memcpy(&ret, &dev->iomem_buf[addr], len);
+    ret = le64_to_cpu(ret);
+
+    return ret;
+}
+
+static void test_iomem_write(void *opaque, hwaddr addr, uint64_t val,
+                             unsigned len)
+{
+    PCTestdev *dev = opaque;
+    val = cpu_to_le64(val);
+    memcpy(&dev->iomem_buf[addr], &val, len);
+    dev->iomem_buf[addr] = val;
+}
+
+static const MemoryRegionOps test_iomem_ops = {
+    .read = test_iomem_read,
+    .write = test_iomem_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static int init_test_device(ISADevice *isa)
+{
+    PCTestdev *dev = TESTDEV(isa);
+    MemoryRegion *mem = isa_address_space(isa);
+    MemoryRegion *io = isa_address_space_io(isa);
+
+    memory_region_init_io(&dev->ioport, &test_ioport_ops, dev,
+                          "pc-testdev-ioport", 4);
+    memory_region_init_io(&dev->flush, &test_flush_ops, dev,
+                          "pc-testdev-flush-page", 4);
+    memory_region_init_io(&dev->irq, &test_irq_ops, dev,
+                          "pc-testdev-irq-line", 24);
+    memory_region_init_io(&dev->iomem, &test_iomem_ops, dev,
+                          "pc-testdev-iomem", IOMEM_LEN);
+
+    memory_region_add_subregion(io,  0xe0,       &dev->ioport);
+    memory_region_add_subregion(io,  0xe4,       &dev->flush);
+    memory_region_add_subregion(io,  0x2000,     &dev->irq);
+    memory_region_add_subregion(mem, 0xff000000, &dev->iomem);
+
+    return 0;
+}
+
+static void testdev_class_init(ObjectClass *klass, void *data)
+{
+    ISADeviceClass *k = ISA_DEVICE_CLASS(klass);
+
+    k->init = init_test_device;
+}
+
+static const TypeInfo testdev_info = {
+    .name           = TYPE_TESTDEV,
+    .parent         = TYPE_ISA_DEVICE,
+    .instance_size  = sizeof(PCTestdev),
+    .class_init     = testdev_class_init,
+};
+
+static void testdev_register_types(void)
+{
+    type_register_static(&testdev_info);
+}
+
+type_init(testdev_register_types)
diff --git a/hw/misc/puv3_pm.c b/hw/misc/puv3_pm.c
new file mode 100644 (file)
index 0000000..0aacdc2
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * Power Management device simulation in PKUnity SoC
+ *
+ * Copyright (C) 2010-2012 Guan Xuetao
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation, or any later version.
+ * See the COPYING file in the top-level directory.
+ */
+#include "hw/hw.h"
+#include "hw/sysbus.h"
+
+#undef DEBUG_PUV3
+#include "hw/unicore32/puv3.h"
+
+typedef struct {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+
+    uint32_t reg_PMCR;
+    uint32_t reg_PCGR;
+    uint32_t reg_PLL_SYS_CFG;
+    uint32_t reg_PLL_DDR_CFG;
+    uint32_t reg_PLL_VGA_CFG;
+    uint32_t reg_DIVCFG;
+} PUV3PMState;
+
+static uint64_t puv3_pm_read(void *opaque, hwaddr offset,
+        unsigned size)
+{
+    PUV3PMState *s = opaque;
+    uint32_t ret = 0;
+
+    switch (offset) {
+    case 0x14:
+        ret = s->reg_PCGR;
+        break;
+    case 0x18:
+        ret = s->reg_PLL_SYS_CFG;
+        break;
+    case 0x1c:
+        ret = s->reg_PLL_DDR_CFG;
+        break;
+    case 0x20:
+        ret = s->reg_PLL_VGA_CFG;
+        break;
+    case 0x24:
+        ret = s->reg_DIVCFG;
+        break;
+    case 0x28: /* PLL SYS STATUS */
+        ret = 0x00002401;
+        break;
+    case 0x2c: /* PLL DDR STATUS */
+        ret = 0x00100c00;
+        break;
+    case 0x30: /* PLL VGA STATUS */
+        ret = 0x00003801;
+        break;
+    case 0x34: /* DIV STATUS */
+        ret = 0x22f52015;
+        break;
+    case 0x38: /* SW RESET */
+        ret = 0x0;
+        break;
+    case 0x44: /* PLL DFC DONE */
+        ret = 0x7;
+        break;
+    default:
+        DPRINTF("Bad offset 0x%x\n", offset);
+    }
+    DPRINTF("offset 0x%x, value 0x%x\n", offset, ret);
+
+    return ret;
+}
+
+static void puv3_pm_write(void *opaque, hwaddr offset,
+        uint64_t value, unsigned size)
+{
+    PUV3PMState *s = opaque;
+
+    switch (offset) {
+    case 0x0:
+        s->reg_PMCR = value;
+        break;
+    case 0x14:
+        s->reg_PCGR = value;
+        break;
+    case 0x18:
+        s->reg_PLL_SYS_CFG = value;
+        break;
+    case 0x1c:
+        s->reg_PLL_DDR_CFG = value;
+        break;
+    case 0x20:
+        s->reg_PLL_VGA_CFG = value;
+        break;
+    case 0x24:
+    case 0x38:
+        break;
+    default:
+        DPRINTF("Bad offset 0x%x\n", offset);
+    }
+    DPRINTF("offset 0x%x, value 0x%x\n", offset, value);
+}
+
+static const MemoryRegionOps puv3_pm_ops = {
+    .read = puv3_pm_read,
+    .write = puv3_pm_write,
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int puv3_pm_init(SysBusDevice *dev)
+{
+    PUV3PMState *s = FROM_SYSBUS(PUV3PMState, dev);
+
+    s->reg_PCGR = 0x0;
+
+    memory_region_init_io(&s->iomem, &puv3_pm_ops, s, "puv3_pm",
+            PUV3_REGS_OFFSET);
+    sysbus_init_mmio(dev, &s->iomem);
+
+    return 0;
+}
+
+static void puv3_pm_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sdc->init = puv3_pm_init;
+}
+
+static const TypeInfo puv3_pm_info = {
+    .name = "puv3_pm",
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(PUV3PMState),
+    .class_init = puv3_pm_class_init,
+};
+
+static void puv3_pm_register_type(void)
+{
+    type_register_static(&puv3_pm_info);
+}
+
+type_init(puv3_pm_register_type)
diff --git a/hw/misc/pxa2xx_pcmcia.c b/hw/misc/pxa2xx_pcmcia.c
new file mode 100644 (file)
index 0000000..323d458
--- /dev/null
@@ -0,0 +1,207 @@
+/*
+ * Intel XScale PXA255/270 PC Card and CompactFlash Interface.
+ *
+ * Copyright (c) 2006 Openedhand Ltd.
+ * Written by Andrzej Zaborowski <balrog@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/hw.h"
+#include "hw/pcmcia.h"
+#include "hw/arm/pxa.h"
+
+
+struct PXA2xxPCMCIAState {
+    PCMCIASocket slot;
+    PCMCIACardState *card;
+    MemoryRegion common_iomem;
+    MemoryRegion attr_iomem;
+    MemoryRegion iomem;
+
+    qemu_irq irq;
+    qemu_irq cd_irq;
+};
+
+static uint64_t pxa2xx_pcmcia_common_read(void *opaque,
+                hwaddr offset, unsigned size)
+{
+    PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
+
+    if (s->slot.attached) {
+        return s->card->common_read(s->card->state, offset);
+    }
+
+    return 0;
+}
+
+static void pxa2xx_pcmcia_common_write(void *opaque, hwaddr offset,
+                                       uint64_t value, unsigned size)
+{
+    PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
+
+    if (s->slot.attached) {
+        s->card->common_write(s->card->state, offset, value);
+    }
+}
+
+static uint64_t pxa2xx_pcmcia_attr_read(void *opaque,
+                hwaddr offset, unsigned size)
+{
+    PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
+
+    if (s->slot.attached) {
+        return s->card->attr_read(s->card->state, offset);
+    }
+
+    return 0;
+}
+
+static void pxa2xx_pcmcia_attr_write(void *opaque, hwaddr offset,
+                                     uint64_t value, unsigned size)
+{
+    PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
+
+    if (s->slot.attached) {
+        s->card->attr_write(s->card->state, offset, value);
+    }
+}
+
+static uint64_t pxa2xx_pcmcia_io_read(void *opaque,
+                hwaddr offset, unsigned size)
+{
+    PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
+
+    if (s->slot.attached) {
+        return s->card->io_read(s->card->state, offset);
+    }
+
+    return 0;
+}
+
+static void pxa2xx_pcmcia_io_write(void *opaque, hwaddr offset,
+                                   uint64_t value, unsigned size)
+{
+    PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
+
+    if (s->slot.attached) {
+        s->card->io_write(s->card->state, offset, value);
+    }
+}
+
+static const MemoryRegionOps pxa2xx_pcmcia_common_ops = {
+    .read = pxa2xx_pcmcia_common_read,
+    .write = pxa2xx_pcmcia_common_write,
+    .endianness = DEVICE_NATIVE_ENDIAN
+};
+
+static const MemoryRegionOps pxa2xx_pcmcia_attr_ops = {
+    .read = pxa2xx_pcmcia_attr_read,
+    .write = pxa2xx_pcmcia_attr_write,
+    .endianness = DEVICE_NATIVE_ENDIAN
+};
+
+static const MemoryRegionOps pxa2xx_pcmcia_io_ops = {
+    .read = pxa2xx_pcmcia_io_read,
+    .write = pxa2xx_pcmcia_io_write,
+    .endianness = DEVICE_NATIVE_ENDIAN
+};
+
+static void pxa2xx_pcmcia_set_irq(void *opaque, int line, int level)
+{
+    PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
+    if (!s->irq)
+        return;
+
+    qemu_set_irq(s->irq, level);
+}
+
+PXA2xxPCMCIAState *pxa2xx_pcmcia_init(MemoryRegion *sysmem,
+                                      hwaddr base)
+{
+    PXA2xxPCMCIAState *s;
+
+    s = (PXA2xxPCMCIAState *)
+            g_malloc0(sizeof(PXA2xxPCMCIAState));
+
+    /* Socket I/O Memory Space */
+    memory_region_init_io(&s->iomem, &pxa2xx_pcmcia_io_ops, s,
+                          "pxa2xx-pcmcia-io", 0x04000000);
+    memory_region_add_subregion(sysmem, base | 0x00000000,
+                                &s->iomem);
+
+    /* Then next 64 MB is reserved */
+
+    /* Socket Attribute Memory Space */
+    memory_region_init_io(&s->attr_iomem, &pxa2xx_pcmcia_attr_ops, s,
+                          "pxa2xx-pcmcia-attribute", 0x04000000);
+    memory_region_add_subregion(sysmem, base | 0x08000000,
+                                &s->attr_iomem);
+
+    /* Socket Common Memory Space */
+    memory_region_init_io(&s->common_iomem, &pxa2xx_pcmcia_common_ops, s,
+                          "pxa2xx-pcmcia-common", 0x04000000);
+    memory_region_add_subregion(sysmem, base | 0x0c000000,
+                                &s->common_iomem);
+
+    if (base == 0x30000000)
+        s->slot.slot_string = "PXA PC Card Socket 1";
+    else
+        s->slot.slot_string = "PXA PC Card Socket 0";
+    s->slot.irq = qemu_allocate_irqs(pxa2xx_pcmcia_set_irq, s, 1)[0];
+    pcmcia_socket_register(&s->slot);
+
+    return s;
+}
+
+/* Insert a new card into a slot */
+int pxa2xx_pcmcia_attach(void *opaque, PCMCIACardState *card)
+{
+    PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
+    if (s->slot.attached)
+        return -EEXIST;
+
+    if (s->cd_irq) {
+        qemu_irq_raise(s->cd_irq);
+    }
+
+    s->card = card;
+
+    s->slot.attached = 1;
+    s->card->slot = &s->slot;
+    s->card->attach(s->card->state);
+
+    return 0;
+}
+
+/* Eject card from the slot */
+int pxa2xx_pcmcia_dettach(void *opaque)
+{
+    PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
+    if (!s->slot.attached)
+        return -ENOENT;
+
+    s->card->detach(s->card->state);
+    s->card->slot = NULL;
+    s->card = NULL;
+
+    s->slot.attached = 0;
+
+    if (s->irq)
+        qemu_irq_lower(s->irq);
+    if (s->cd_irq)
+        qemu_irq_lower(s->cd_irq);
+
+    return 0;
+}
+
+/* Who to notify on card events */
+void pxa2xx_pcmcia_set_irq_cb(void *opaque, qemu_irq irq, qemu_irq cd_irq)
+{
+    PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
+    s->irq = irq;
+    s->cd_irq = cd_irq;
+}
diff --git a/hw/misc/sga.c b/hw/misc/sga.c
new file mode 100644 (file)
index 0000000..5cf4b86
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * QEMU dummy ISA device for loading sgabios option rom.
+ *
+ * Copyright (c) 2011 Glauber Costa, Red Hat 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.
+ *
+ * sgabios code originally available at code.google.com/p/sgabios
+ *
+ */
+#include "hw/pci/pci.h"
+#include "hw/i386/pc.h"
+#include "hw/loader.h"
+#include "sysemu/sysemu.h"
+
+#define SGABIOS_FILENAME "sgabios.bin"
+
+typedef struct ISAGAState {
+    ISADevice dev;
+} ISASGAState;
+
+static int sga_initfn(ISADevice *dev)
+{
+    rom_add_vga(SGABIOS_FILENAME);
+    return 0;
+}
+static void sga_class_initfn(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+    ic->init = sga_initfn;
+    dc->desc = "Serial Graphics Adapter";
+}
+
+static const TypeInfo sga_info = {
+    .name          = "sga",
+    .parent        = TYPE_ISA_DEVICE,
+    .instance_size = sizeof(ISASGAState),
+    .class_init    = sga_class_initfn,
+};
+
+static void sga_register_types(void)
+{
+    type_register_static(&sga_info);
+}
+
+type_init(sga_register_types)
diff --git a/hw/misc/slavio_misc.c b/hw/misc/slavio_misc.c
new file mode 100644 (file)
index 0000000..a7a9368
--- /dev/null
@@ -0,0 +1,508 @@
+/*
+ * QEMU Sparc SLAVIO aux io port emulation
+ *
+ * Copyright (c) 2005 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.
+ */
+
+#include "sysemu/sysemu.h"
+#include "hw/sysbus.h"
+#include "trace.h"
+
+/*
+ * This is the auxio port, chip control and system control part of
+ * chip STP2001 (Slave I/O), also produced as NCR89C105. See
+ * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
+ *
+ * This also includes the PMC CPU idle controller.
+ */
+
+typedef struct MiscState {
+    SysBusDevice busdev;
+    MemoryRegion cfg_iomem;
+    MemoryRegion diag_iomem;
+    MemoryRegion mdm_iomem;
+    MemoryRegion led_iomem;
+    MemoryRegion sysctrl_iomem;
+    MemoryRegion aux1_iomem;
+    MemoryRegion aux2_iomem;
+    qemu_irq irq;
+    qemu_irq fdc_tc;
+    uint32_t dummy;
+    uint8_t config;
+    uint8_t aux1, aux2;
+    uint8_t diag, mctrl;
+    uint8_t sysctrl;
+    uint16_t leds;
+} MiscState;
+
+typedef struct APCState {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    qemu_irq cpu_halt;
+} APCState;
+
+#define MISC_SIZE 1
+#define SYSCTRL_SIZE 4
+
+#define AUX1_TC        0x02
+
+#define AUX2_PWROFF    0x01
+#define AUX2_PWRINTCLR 0x02
+#define AUX2_PWRFAIL   0x20
+
+#define CFG_PWRINTEN   0x08
+
+#define SYS_RESET      0x01
+#define SYS_RESETSTAT  0x02
+
+static void slavio_misc_update_irq(void *opaque)
+{
+    MiscState *s = opaque;
+
+    if ((s->aux2 & AUX2_PWRFAIL) && (s->config & CFG_PWRINTEN)) {
+        trace_slavio_misc_update_irq_raise();
+        qemu_irq_raise(s->irq);
+    } else {
+        trace_slavio_misc_update_irq_lower();
+        qemu_irq_lower(s->irq);
+    }
+}
+
+static void slavio_misc_reset(DeviceState *d)
+{
+    MiscState *s = container_of(d, MiscState, busdev.qdev);
+
+    // Diagnostic and system control registers not cleared in reset
+    s->config = s->aux1 = s->aux2 = s->mctrl = 0;
+}
+
+static void slavio_set_power_fail(void *opaque, int irq, int power_failing)
+{
+    MiscState *s = opaque;
+
+    trace_slavio_set_power_fail(power_failing, s->config);
+    if (power_failing && (s->config & CFG_PWRINTEN)) {
+        s->aux2 |= AUX2_PWRFAIL;
+    } else {
+        s->aux2 &= ~AUX2_PWRFAIL;
+    }
+    slavio_misc_update_irq(s);
+}
+
+static void slavio_cfg_mem_writeb(void *opaque, hwaddr addr,
+                                  uint64_t val, unsigned size)
+{
+    MiscState *s = opaque;
+
+    trace_slavio_cfg_mem_writeb(val & 0xff);
+    s->config = val & 0xff;
+    slavio_misc_update_irq(s);
+}
+
+static uint64_t slavio_cfg_mem_readb(void *opaque, hwaddr addr,
+                                     unsigned size)
+{
+    MiscState *s = opaque;
+    uint32_t ret = 0;
+
+    ret = s->config;
+    trace_slavio_cfg_mem_readb(ret);
+    return ret;
+}
+
+static const MemoryRegionOps slavio_cfg_mem_ops = {
+    .read = slavio_cfg_mem_readb,
+    .write = slavio_cfg_mem_writeb,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+};
+
+static void slavio_diag_mem_writeb(void *opaque, hwaddr addr,
+                                   uint64_t val, unsigned size)
+{
+    MiscState *s = opaque;
+
+    trace_slavio_diag_mem_writeb(val & 0xff);
+    s->diag = val & 0xff;
+}
+
+static uint64_t slavio_diag_mem_readb(void *opaque, hwaddr addr,
+                                      unsigned size)
+{
+    MiscState *s = opaque;
+    uint32_t ret = 0;
+
+    ret = s->diag;
+    trace_slavio_diag_mem_readb(ret);
+    return ret;
+}
+
+static const MemoryRegionOps slavio_diag_mem_ops = {
+    .read = slavio_diag_mem_readb,
+    .write = slavio_diag_mem_writeb,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+};
+
+static void slavio_mdm_mem_writeb(void *opaque, hwaddr addr,
+                                  uint64_t val, unsigned size)
+{
+    MiscState *s = opaque;
+
+    trace_slavio_mdm_mem_writeb(val & 0xff);
+    s->mctrl = val & 0xff;
+}
+
+static uint64_t slavio_mdm_mem_readb(void *opaque, hwaddr addr,
+                                     unsigned size)
+{
+    MiscState *s = opaque;
+    uint32_t ret = 0;
+
+    ret = s->mctrl;
+    trace_slavio_mdm_mem_readb(ret);
+    return ret;
+}
+
+static const MemoryRegionOps slavio_mdm_mem_ops = {
+    .read = slavio_mdm_mem_readb,
+    .write = slavio_mdm_mem_writeb,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+};
+
+static void slavio_aux1_mem_writeb(void *opaque, hwaddr addr,
+                                   uint64_t val, unsigned size)
+{
+    MiscState *s = opaque;
+
+    trace_slavio_aux1_mem_writeb(val & 0xff);
+    if (val & AUX1_TC) {
+        // Send a pulse to floppy terminal count line
+        if (s->fdc_tc) {
+            qemu_irq_raise(s->fdc_tc);
+            qemu_irq_lower(s->fdc_tc);
+        }
+        val &= ~AUX1_TC;
+    }
+    s->aux1 = val & 0xff;
+}
+
+static uint64_t slavio_aux1_mem_readb(void *opaque, hwaddr addr,
+                                      unsigned size)
+{
+    MiscState *s = opaque;
+    uint32_t ret = 0;
+
+    ret = s->aux1;
+    trace_slavio_aux1_mem_readb(ret);
+    return ret;
+}
+
+static const MemoryRegionOps slavio_aux1_mem_ops = {
+    .read = slavio_aux1_mem_readb,
+    .write = slavio_aux1_mem_writeb,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+};
+
+static void slavio_aux2_mem_writeb(void *opaque, hwaddr addr,
+                                   uint64_t val, unsigned size)
+{
+    MiscState *s = opaque;
+
+    val &= AUX2_PWRINTCLR | AUX2_PWROFF;
+    trace_slavio_aux2_mem_writeb(val & 0xff);
+    val |= s->aux2 & AUX2_PWRFAIL;
+    if (val & AUX2_PWRINTCLR) // Clear Power Fail int
+        val &= AUX2_PWROFF;
+    s->aux2 = val;
+    if (val & AUX2_PWROFF)
+        qemu_system_shutdown_request();
+    slavio_misc_update_irq(s);
+}
+
+static uint64_t slavio_aux2_mem_readb(void *opaque, hwaddr addr,
+                                      unsigned size)
+{
+    MiscState *s = opaque;
+    uint32_t ret = 0;
+
+    ret = s->aux2;
+    trace_slavio_aux2_mem_readb(ret);
+    return ret;
+}
+
+static const MemoryRegionOps slavio_aux2_mem_ops = {
+    .read = slavio_aux2_mem_readb,
+    .write = slavio_aux2_mem_writeb,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+};
+
+static void apc_mem_writeb(void *opaque, hwaddr addr,
+                           uint64_t val, unsigned size)
+{
+    APCState *s = opaque;
+
+    trace_apc_mem_writeb(val & 0xff);
+    qemu_irq_raise(s->cpu_halt);
+}
+
+static uint64_t apc_mem_readb(void *opaque, hwaddr addr,
+                              unsigned size)
+{
+    uint32_t ret = 0;
+
+    trace_apc_mem_readb(ret);
+    return ret;
+}
+
+static const MemoryRegionOps apc_mem_ops = {
+    .read = apc_mem_readb,
+    .write = apc_mem_writeb,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    }
+};
+
+static uint64_t slavio_sysctrl_mem_readl(void *opaque, hwaddr addr,
+                                         unsigned size)
+{
+    MiscState *s = opaque;
+    uint32_t ret = 0;
+
+    switch (addr) {
+    case 0:
+        ret = s->sysctrl;
+        break;
+    default:
+        break;
+    }
+    trace_slavio_sysctrl_mem_readl(ret);
+    return ret;
+}
+
+static void slavio_sysctrl_mem_writel(void *opaque, hwaddr addr,
+                                      uint64_t val, unsigned size)
+{
+    MiscState *s = opaque;
+
+    trace_slavio_sysctrl_mem_writel(val);
+    switch (addr) {
+    case 0:
+        if (val & SYS_RESET) {
+            s->sysctrl = SYS_RESETSTAT;
+            qemu_system_reset_request();
+        }
+        break;
+    default:
+        break;
+    }
+}
+
+static const MemoryRegionOps slavio_sysctrl_mem_ops = {
+    .read = slavio_sysctrl_mem_readl,
+    .write = slavio_sysctrl_mem_writel,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static uint64_t slavio_led_mem_readw(void *opaque, hwaddr addr,
+                                     unsigned size)
+{
+    MiscState *s = opaque;
+    uint32_t ret = 0;
+
+    switch (addr) {
+    case 0:
+        ret = s->leds;
+        break;
+    default:
+        break;
+    }
+    trace_slavio_led_mem_readw(ret);
+    return ret;
+}
+
+static void slavio_led_mem_writew(void *opaque, hwaddr addr,
+                                  uint64_t val, unsigned size)
+{
+    MiscState *s = opaque;
+
+    trace_slavio_led_mem_readw(val & 0xffff);
+    switch (addr) {
+    case 0:
+        s->leds = val;
+        break;
+    default:
+        break;
+    }
+}
+
+static const MemoryRegionOps slavio_led_mem_ops = {
+    .read = slavio_led_mem_readw,
+    .write = slavio_led_mem_writew,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 2,
+        .max_access_size = 2,
+    },
+};
+
+static const VMStateDescription vmstate_misc = {
+    .name ="slavio_misc",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT32(dummy, MiscState),
+        VMSTATE_UINT8(config, MiscState),
+        VMSTATE_UINT8(aux1, MiscState),
+        VMSTATE_UINT8(aux2, MiscState),
+        VMSTATE_UINT8(diag, MiscState),
+        VMSTATE_UINT8(mctrl, MiscState),
+        VMSTATE_UINT8(sysctrl, MiscState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int apc_init1(SysBusDevice *dev)
+{
+    APCState *s = FROM_SYSBUS(APCState, dev);
+
+    sysbus_init_irq(dev, &s->cpu_halt);
+
+    /* Power management (APC) XXX: not a Slavio device */
+    memory_region_init_io(&s->iomem, &apc_mem_ops, s,
+                          "apc", MISC_SIZE);
+    sysbus_init_mmio(dev, &s->iomem);
+    return 0;
+}
+
+static int slavio_misc_init1(SysBusDevice *dev)
+{
+    MiscState *s = FROM_SYSBUS(MiscState, dev);
+
+    sysbus_init_irq(dev, &s->irq);
+    sysbus_init_irq(dev, &s->fdc_tc);
+
+    /* 8 bit registers */
+    /* Slavio control */
+    memory_region_init_io(&s->cfg_iomem, &slavio_cfg_mem_ops, s,
+                          "configuration", MISC_SIZE);
+    sysbus_init_mmio(dev, &s->cfg_iomem);
+
+    /* Diagnostics */
+    memory_region_init_io(&s->diag_iomem, &slavio_diag_mem_ops, s,
+                          "diagnostic", MISC_SIZE);
+    sysbus_init_mmio(dev, &s->diag_iomem);
+
+    /* Modem control */
+    memory_region_init_io(&s->mdm_iomem, &slavio_mdm_mem_ops, s,
+                          "modem", MISC_SIZE);
+    sysbus_init_mmio(dev, &s->mdm_iomem);
+
+    /* 16 bit registers */
+    /* ss600mp diag LEDs */
+    memory_region_init_io(&s->led_iomem, &slavio_led_mem_ops, s,
+                          "leds", MISC_SIZE);
+    sysbus_init_mmio(dev, &s->led_iomem);
+
+    /* 32 bit registers */
+    /* System control */
+    memory_region_init_io(&s->sysctrl_iomem, &slavio_sysctrl_mem_ops, s,
+                          "system-control", MISC_SIZE);
+    sysbus_init_mmio(dev, &s->sysctrl_iomem);
+
+    /* AUX 1 (Misc System Functions) */
+    memory_region_init_io(&s->aux1_iomem, &slavio_aux1_mem_ops, s,
+                          "misc-system-functions", MISC_SIZE);
+    sysbus_init_mmio(dev, &s->aux1_iomem);
+
+    /* AUX 2 (Software Powerdown Control) */
+    memory_region_init_io(&s->aux2_iomem, &slavio_aux2_mem_ops, s,
+                          "software-powerdown-control", MISC_SIZE);
+    sysbus_init_mmio(dev, &s->aux2_iomem);
+
+    qdev_init_gpio_in(&dev->qdev, slavio_set_power_fail, 1);
+
+    return 0;
+}
+
+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 const 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)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = apc_init1;
+}
+
+static const TypeInfo apc_info = {
+    .name          = "apc",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(MiscState),
+    .class_init    = apc_class_init,
+};
+
+static void slavio_misc_register_types(void)
+{
+    type_register_static(&slavio_misc_info);
+    type_register_static(&apc_info);
+}
+
+type_init(slavio_misc_register_types)
diff --git a/hw/misc/tmp105.c b/hw/misc/tmp105.c
new file mode 100644 (file)
index 0000000..155e03d
--- /dev/null
@@ -0,0 +1,269 @@
+/*
+ * Texas Instruments TMP105 temperature sensor.
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ * Written by Andrzej Zaborowski <andrew@openedhand.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 or
+ * (at your option) version 3 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
+ * 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 "hw/hw.h"
+#include "hw/i2c/i2c.h"
+#include "tmp105.h"
+#include "qapi/visitor.h"
+
+static void tmp105_interrupt_update(TMP105State *s)
+{
+    qemu_set_irq(s->pin, s->alarm ^ ((~s->config >> 2) & 1));  /* POL */
+}
+
+static void tmp105_alarm_update(TMP105State *s)
+{
+    if ((s->config >> 0) & 1) {                                        /* SD */
+        if ((s->config >> 7) & 1)                              /* OS */
+            s->config &= ~(1 << 7);                            /* OS */
+        else
+            return;
+    }
+
+    if ((s->config >> 1) & 1) {                                        /* TM */
+        if (s->temperature >= s->limit[1])
+            s->alarm = 1;
+        else if (s->temperature < s->limit[0])
+            s->alarm = 1;
+    } else {
+        if (s->temperature >= s->limit[1])
+            s->alarm = 1;
+        else if (s->temperature < s->limit[0])
+            s->alarm = 0;
+    }
+
+    tmp105_interrupt_update(s);
+}
+
+static void tmp105_get_temperature(Object *obj, Visitor *v, void *opaque,
+                                   const char *name, Error **errp)
+{
+    TMP105State *s = TMP105(obj);
+    int64_t value = s->temperature;
+
+    visit_type_int(v, &value, name, errp);
+}
+
+/* Units are 0.001 centigrades relative to 0 C.  */
+static void tmp105_set_temperature(Object *obj, Visitor *v, void *opaque,
+                                   const char *name, Error **errp)
+{
+    TMP105State *s = TMP105(obj);
+    int64_t temp;
+
+    visit_type_int(v, &temp, name, errp);
+    if (error_is_set(errp)) {
+        return;
+    }
+    if (temp >= 128000 || temp < -128000) {
+        error_setg(errp, "value %" PRId64 ".%03" PRIu64 " Â°C is out of range",
+                   temp / 1000, temp % 1000);
+        return;
+    }
+
+    s->temperature = ((int16_t) (temp * 0x800 / 128000)) << 4;
+
+    tmp105_alarm_update(s);
+}
+
+static const int tmp105_faultq[4] = { 1, 2, 4, 6 };
+
+static void tmp105_read(TMP105State *s)
+{
+    s->len = 0;
+
+    if ((s->config >> 1) & 1) {                                        /* TM */
+        s->alarm = 0;
+        tmp105_interrupt_update(s);
+    }
+
+    switch (s->pointer & 3) {
+    case TMP105_REG_TEMPERATURE:
+        s->buf[s->len ++] = (((uint16_t) s->temperature) >> 8);
+        s->buf[s->len ++] = (((uint16_t) s->temperature) >> 0) &
+                (0xf0 << ((~s->config >> 5) & 3));             /* R */
+        break;
+
+    case TMP105_REG_CONFIG:
+        s->buf[s->len ++] = s->config;
+        break;
+
+    case TMP105_REG_T_LOW:
+        s->buf[s->len ++] = ((uint16_t) s->limit[0]) >> 8;
+        s->buf[s->len ++] = ((uint16_t) s->limit[0]) >> 0;
+        break;
+
+    case TMP105_REG_T_HIGH:
+        s->buf[s->len ++] = ((uint16_t) s->limit[1]) >> 8;
+        s->buf[s->len ++] = ((uint16_t) s->limit[1]) >> 0;
+        break;
+    }
+}
+
+static void tmp105_write(TMP105State *s)
+{
+    switch (s->pointer & 3) {
+    case TMP105_REG_TEMPERATURE:
+        break;
+
+    case TMP105_REG_CONFIG:
+        if (s->buf[0] & ~s->config & (1 << 0))                 /* SD */
+            printf("%s: TMP105 shutdown\n", __FUNCTION__);
+        s->config = s->buf[0];
+        s->faults = tmp105_faultq[(s->config >> 3) & 3];       /* F */
+        tmp105_alarm_update(s);
+        break;
+
+    case TMP105_REG_T_LOW:
+    case TMP105_REG_T_HIGH:
+        if (s->len >= 3)
+            s->limit[s->pointer & 1] = (int16_t)
+                    ((((uint16_t) s->buf[0]) << 8) | s->buf[1]);
+        tmp105_alarm_update(s);
+        break;
+    }
+}
+
+static int tmp105_rx(I2CSlave *i2c)
+{
+    TMP105State *s = TMP105(i2c);
+
+    if (s->len < 2) {
+        return s->buf[s->len ++];
+    } else {
+        return 0xff;
+    }
+}
+
+static int tmp105_tx(I2CSlave *i2c, uint8_t data)
+{
+    TMP105State *s = TMP105(i2c);
+
+    if (s->len == 0) {
+        s->pointer = data;
+        s->len++;
+    } else {
+        if (s->len <= 2) {
+            s->buf[s->len - 1] = data;
+        }
+        s->len++;
+        tmp105_write(s);
+    }
+
+    return 0;
+}
+
+static void tmp105_event(I2CSlave *i2c, enum i2c_event event)
+{
+    TMP105State *s = TMP105(i2c);
+
+    if (event == I2C_START_RECV) {
+        tmp105_read(s);
+    }
+
+    s->len = 0;
+}
+
+static int tmp105_post_load(void *opaque, int version_id)
+{
+    TMP105State *s = opaque;
+
+    s->faults = tmp105_faultq[(s->config >> 3) & 3];           /* F */
+
+    tmp105_interrupt_update(s);
+    return 0;
+}
+
+static const VMStateDescription vmstate_tmp105 = {
+    .name = "TMP105",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .post_load = tmp105_post_load,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT8(len, TMP105State),
+        VMSTATE_UINT8_ARRAY(buf, TMP105State, 2),
+        VMSTATE_UINT8(pointer, TMP105State),
+        VMSTATE_UINT8(config, TMP105State),
+        VMSTATE_INT16(temperature, TMP105State),
+        VMSTATE_INT16_ARRAY(limit, TMP105State, 2),
+        VMSTATE_UINT8(alarm, TMP105State),
+        VMSTATE_I2C_SLAVE(i2c, TMP105State),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void tmp105_reset(I2CSlave *i2c)
+{
+    TMP105State *s = TMP105(i2c);
+
+    s->temperature = 0;
+    s->pointer = 0;
+    s->config = 0;
+    s->faults = tmp105_faultq[(s->config >> 3) & 3];
+    s->alarm = 0;
+
+    tmp105_interrupt_update(s);
+}
+
+static int tmp105_init(I2CSlave *i2c)
+{
+    TMP105State *s = TMP105(i2c);
+
+    qdev_init_gpio_out(&i2c->qdev, &s->pin, 1);
+
+    tmp105_reset(&s->i2c);
+
+    return 0;
+}
+
+static void tmp105_initfn(Object *obj)
+{
+    object_property_add(obj, "temperature", "int",
+                        tmp105_get_temperature,
+                        tmp105_set_temperature, NULL, NULL, NULL);
+}
+
+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 const TypeInfo tmp105_info = {
+    .name          = TYPE_TMP105,
+    .parent        = TYPE_I2C_SLAVE,
+    .instance_size = sizeof(TMP105State),
+    .instance_init = tmp105_initfn,
+    .class_init    = tmp105_class_init,
+};
+
+static void tmp105_register_types(void)
+{
+    type_register_static(&tmp105_info);
+}
+
+type_init(tmp105_register_types)
diff --git a/hw/misc/tmp105.h b/hw/misc/tmp105.h
new file mode 100644 (file)
index 0000000..9ba05ec
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Texas Instruments TMP105 Temperature Sensor
+ *
+ * Browse the data sheet:
+ *
+ *    http://www.ti.com/lit/gpn/tmp105
+ *
+ * Copyright (C) 2012 Alex Horn <alex.horn@cs.ox.ac.uk>
+ * Copyright (C) 2008-2012 Andrzej Zaborowski <balrogg@gmail.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_TMP105_H
+#define QEMU_TMP105_H
+
+#include "hw/i2c/i2c.h"
+#include "hw/misc/tmp105_regs.h"
+
+#define TYPE_TMP105 "tmp105"
+#define TMP105(obj) OBJECT_CHECK(TMP105State, (obj), TYPE_TMP105)
+
+/**
+ * TMP105State:
+ * @config: Bits 5 and 6 (value 32 and 64) determine the precision of the
+ * temperature. See Table 8 in the data sheet.
+ *
+ * @see_also: http://www.ti.com/lit/gpn/tmp105
+ */
+typedef struct TMP105State {
+    /*< private >*/
+    I2CSlave i2c;
+    /*< public >*/
+
+    uint8_t len;
+    uint8_t buf[2];
+    qemu_irq pin;
+
+    uint8_t pointer;
+    uint8_t config;
+    int16_t temperature;
+    int16_t limit[2];
+    int faults;
+    uint8_t alarm;
+} TMP105State;
+
+#endif
diff --git a/hw/misc/vfio.c b/hw/misc/vfio.c
new file mode 100644 (file)
index 0000000..693a9ff
--- /dev/null
@@ -0,0 +1,3206 @@
+/*
+ * vfio based device assignment support
+ *
+ * Copyright Red Hat, Inc. 2012
+ *
+ * Authors:
+ *  Alex Williamson <alex.williamson@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ * Based on qemu-kvm device-assignment:
+ *  Adapted for KVM by Qumranet.
+ *  Copyright (c) 2007, Neocleus, Alex Novik (alex@neocleus.com)
+ *  Copyright (c) 2007, Neocleus, Guy Zana (guy@neocleus.com)
+ *  Copyright (C) 2008, Qumranet, Amit Shah (amit.shah@qumranet.com)
+ *  Copyright (C) 2008, Red Hat, Amit Shah (amit.shah@redhat.com)
+ *  Copyright (C) 2008, IBM, Muli Ben-Yehuda (muli@il.ibm.com)
+ */
+
+#include <dirent.h>
+#include <linux/vfio.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "config.h"
+#include "exec/address-spaces.h"
+#include "exec/memory.h"
+#include "hw/pci/msi.h"
+#include "hw/pci/msix.h"
+#include "hw/pci/pci.h"
+#include "qemu-common.h"
+#include "qemu/error-report.h"
+#include "qemu/event_notifier.h"
+#include "qemu/queue.h"
+#include "qemu/range.h"
+#include "sysemu/kvm.h"
+#include "sysemu/sysemu.h"
+
+/* #define DEBUG_VFIO */
+#ifdef DEBUG_VFIO
+#define DPRINTF(fmt, ...) \
+    do { fprintf(stderr, "vfio: " fmt, ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) \
+    do { } while (0)
+#endif
+
+/* Extra debugging, trap acceleration paths for more logging */
+#define VFIO_ALLOW_MMAP 1
+#define VFIO_ALLOW_KVM_INTX 1
+
+struct VFIODevice;
+
+typedef struct VFIOQuirk {
+    MemoryRegion mem;
+    struct VFIODevice *vdev;
+    QLIST_ENTRY(VFIOQuirk) next;
+    uint32_t data;
+    uint32_t data2;
+} VFIOQuirk;
+
+typedef struct VFIOBAR {
+    off_t fd_offset; /* offset of BAR within device fd */
+    int fd; /* device fd, allows us to pass VFIOBAR as opaque data */
+    MemoryRegion mem; /* slow, read/write access */
+    MemoryRegion mmap_mem; /* direct mapped access */
+    void *mmap;
+    size_t size;
+    uint32_t flags; /* VFIO region flags (rd/wr/mmap) */
+    uint8_t nr; /* cache the BAR number for debug */
+    QLIST_HEAD(, VFIOQuirk) quirks;
+} VFIOBAR;
+
+typedef struct VFIOVGARegion {
+    MemoryRegion mem;
+    off_t offset;
+    int nr;
+    QLIST_HEAD(, VFIOQuirk) quirks;
+} VFIOVGARegion;
+
+typedef struct VFIOVGA {
+    off_t fd_offset;
+    int fd;
+    VFIOVGARegion region[QEMU_PCI_VGA_NUM_REGIONS];
+} VFIOVGA;
+
+typedef struct VFIOINTx {
+    bool pending; /* interrupt pending */
+    bool kvm_accel; /* set when QEMU bypass through KVM enabled */
+    uint8_t pin; /* which pin to pull for qemu_set_irq */
+    EventNotifier interrupt; /* eventfd triggered on interrupt */
+    EventNotifier unmask; /* eventfd for unmask on QEMU bypass */
+    PCIINTxRoute route; /* routing info for QEMU bypass */
+    uint32_t mmap_timeout; /* delay to re-enable mmaps after interrupt */
+    QEMUTimer *mmap_timer; /* enable mmaps after periods w/o interrupts */
+} VFIOINTx;
+
+typedef struct VFIOMSIVector {
+    EventNotifier interrupt; /* eventfd triggered on interrupt */
+    struct VFIODevice *vdev; /* back pointer to device */
+    int virq; /* KVM irqchip route for QEMU bypass */
+    bool use;
+} VFIOMSIVector;
+
+enum {
+    VFIO_INT_NONE = 0,
+    VFIO_INT_INTx = 1,
+    VFIO_INT_MSI  = 2,
+    VFIO_INT_MSIX = 3,
+};
+
+struct VFIOGroup;
+
+typedef struct VFIOContainer {
+    int fd; /* /dev/vfio/vfio, empowered by the attached groups */
+    struct {
+        /* enable abstraction to support various iommu backends */
+        union {
+            MemoryListener listener; /* Used by type1 iommu */
+        };
+        void (*release)(struct VFIOContainer *);
+    } iommu_data;
+    QLIST_HEAD(, VFIOGroup) group_list;
+    QLIST_ENTRY(VFIOContainer) next;
+} VFIOContainer;
+
+/* Cache of MSI-X setup plus extra mmap and memory region for split BAR map */
+typedef struct VFIOMSIXInfo {
+    uint8_t table_bar;
+    uint8_t pba_bar;
+    uint16_t entries;
+    uint32_t table_offset;
+    uint32_t pba_offset;
+    MemoryRegion mmap_mem;
+    void *mmap;
+} VFIOMSIXInfo;
+
+typedef struct VFIODevice {
+    PCIDevice pdev;
+    int fd;
+    VFIOINTx intx;
+    unsigned int config_size;
+    uint8_t *emulated_config_bits; /* QEMU emulated bits, little-endian */
+    off_t config_offset; /* Offset of config space region within device fd */
+    unsigned int rom_size;
+    off_t rom_offset; /* Offset of ROM region within device fd */
+    int msi_cap_size;
+    VFIOMSIVector *msi_vectors;
+    VFIOMSIXInfo *msix;
+    int nr_vectors; /* Number of MSI/MSIX vectors currently in use */
+    int interrupt; /* Current interrupt type */
+    VFIOBAR bars[PCI_NUM_REGIONS - 1]; /* No ROM */
+    VFIOVGA vga; /* 0xa0000, 0x3b0, 0x3c0 */
+    PCIHostDeviceAddress host;
+    QLIST_ENTRY(VFIODevice) next;
+    struct VFIOGroup *group;
+    uint32_t features;
+#define VFIO_FEATURE_ENABLE_VGA_BIT 0
+#define VFIO_FEATURE_ENABLE_VGA (1 << VFIO_FEATURE_ENABLE_VGA_BIT)
+    int32_t bootindex;
+    uint8_t pm_cap;
+    bool reset_works;
+    bool has_vga;
+} VFIODevice;
+
+typedef struct VFIOGroup {
+    int fd;
+    int groupid;
+    VFIOContainer *container;
+    QLIST_HEAD(, VFIODevice) device_list;
+    QLIST_ENTRY(VFIOGroup) next;
+    QLIST_ENTRY(VFIOGroup) container_next;
+} VFIOGroup;
+
+#define MSIX_CAP_LENGTH 12
+
+static QLIST_HEAD(, VFIOContainer)
+    container_list = QLIST_HEAD_INITIALIZER(container_list);
+
+static QLIST_HEAD(, VFIOGroup)
+    group_list = QLIST_HEAD_INITIALIZER(group_list);
+
+static void vfio_disable_interrupts(VFIODevice *vdev);
+static uint32_t vfio_pci_read_config(PCIDevice *pdev, uint32_t addr, int len);
+static void vfio_pci_write_config(PCIDevice *pdev, uint32_t addr,
+                                  uint32_t val, int len);
+static void vfio_mmap_set_enabled(VFIODevice *vdev, bool enabled);
+
+/*
+ * Common VFIO interrupt disable
+ */
+static void vfio_disable_irqindex(VFIODevice *vdev, int index)
+{
+    struct vfio_irq_set irq_set = {
+        .argsz = sizeof(irq_set),
+        .flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_TRIGGER,
+        .index = index,
+        .start = 0,
+        .count = 0,
+    };
+
+    ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, &irq_set);
+}
+
+/*
+ * INTx
+ */
+static void vfio_unmask_intx(VFIODevice *vdev)
+{
+    struct vfio_irq_set irq_set = {
+        .argsz = sizeof(irq_set),
+        .flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_UNMASK,
+        .index = VFIO_PCI_INTX_IRQ_INDEX,
+        .start = 0,
+        .count = 1,
+    };
+
+    ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, &irq_set);
+}
+
+#ifdef CONFIG_KVM /* Unused outside of CONFIG_KVM code */
+static void vfio_mask_intx(VFIODevice *vdev)
+{
+    struct vfio_irq_set irq_set = {
+        .argsz = sizeof(irq_set),
+        .flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_MASK,
+        .index = VFIO_PCI_INTX_IRQ_INDEX,
+        .start = 0,
+        .count = 1,
+    };
+
+    ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, &irq_set);
+}
+#endif
+
+/*
+ * Disabling BAR mmaping can be slow, but toggling it around INTx can
+ * also be a huge overhead.  We try to get the best of both worlds by
+ * waiting until an interrupt to disable mmaps (subsequent transitions
+ * to the same state are effectively no overhead).  If the interrupt has
+ * been serviced and the time gap is long enough, we re-enable mmaps for
+ * performance.  This works well for things like graphics cards, which
+ * may not use their interrupt at all and are penalized to an unusable
+ * level by read/write BAR traps.  Other devices, like NICs, have more
+ * regular interrupts and see much better latency by staying in non-mmap
+ * mode.  We therefore set the default mmap_timeout such that a ping
+ * is just enough to keep the mmap disabled.  Users can experiment with
+ * other options with the x-intx-mmap-timeout-ms parameter (a value of
+ * zero disables the timer).
+ */
+static void vfio_intx_mmap_enable(void *opaque)
+{
+    VFIODevice *vdev = opaque;
+
+    if (vdev->intx.pending) {
+        qemu_mod_timer(vdev->intx.mmap_timer,
+                       qemu_get_clock_ms(vm_clock) + vdev->intx.mmap_timeout);
+        return;
+    }
+
+    vfio_mmap_set_enabled(vdev, true);
+}
+
+static void vfio_intx_interrupt(void *opaque)
+{
+    VFIODevice *vdev = opaque;
+
+    if (!event_notifier_test_and_clear(&vdev->intx.interrupt)) {
+        return;
+    }
+
+    DPRINTF("%s(%04x:%02x:%02x.%x) Pin %c\n", __func__, vdev->host.domain,
+            vdev->host.bus, vdev->host.slot, vdev->host.function,
+            'A' + vdev->intx.pin);
+
+    vdev->intx.pending = true;
+    qemu_set_irq(vdev->pdev.irq[vdev->intx.pin], 1);
+    vfio_mmap_set_enabled(vdev, false);
+    if (vdev->intx.mmap_timeout) {
+        qemu_mod_timer(vdev->intx.mmap_timer,
+                       qemu_get_clock_ms(vm_clock) + vdev->intx.mmap_timeout);
+    }
+}
+
+static void vfio_eoi(VFIODevice *vdev)
+{
+    if (!vdev->intx.pending) {
+        return;
+    }
+
+    DPRINTF("%s(%04x:%02x:%02x.%x) EOI\n", __func__, vdev->host.domain,
+            vdev->host.bus, vdev->host.slot, vdev->host.function);
+
+    vdev->intx.pending = false;
+    qemu_set_irq(vdev->pdev.irq[vdev->intx.pin], 0);
+    vfio_unmask_intx(vdev);
+}
+
+static void vfio_enable_intx_kvm(VFIODevice *vdev)
+{
+#ifdef CONFIG_KVM
+    struct kvm_irqfd irqfd = {
+        .fd = event_notifier_get_fd(&vdev->intx.interrupt),
+        .gsi = vdev->intx.route.irq,
+        .flags = KVM_IRQFD_FLAG_RESAMPLE,
+    };
+    struct vfio_irq_set *irq_set;
+    int ret, argsz;
+    int32_t *pfd;
+
+    if (!VFIO_ALLOW_KVM_INTX || !kvm_irqfds_enabled() ||
+        vdev->intx.route.mode != PCI_INTX_ENABLED ||
+        !kvm_check_extension(kvm_state, KVM_CAP_IRQFD_RESAMPLE)) {
+        return;
+    }
+
+    /* Get to a known interrupt state */
+    qemu_set_fd_handler(irqfd.fd, NULL, NULL, vdev);
+    vfio_mask_intx(vdev);
+    vdev->intx.pending = false;
+    qemu_set_irq(vdev->pdev.irq[vdev->intx.pin], 0);
+
+    /* Get an eventfd for resample/unmask */
+    if (event_notifier_init(&vdev->intx.unmask, 0)) {
+        error_report("vfio: Error: event_notifier_init failed eoi");
+        goto fail;
+    }
+
+    /* KVM triggers it, VFIO listens for it */
+    irqfd.resamplefd = event_notifier_get_fd(&vdev->intx.unmask);
+
+    if (kvm_vm_ioctl(kvm_state, KVM_IRQFD, &irqfd)) {
+        error_report("vfio: Error: Failed to setup resample irqfd: %m");
+        goto fail_irqfd;
+    }
+
+    argsz = sizeof(*irq_set) + sizeof(*pfd);
+
+    irq_set = g_malloc0(argsz);
+    irq_set->argsz = argsz;
+    irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_UNMASK;
+    irq_set->index = VFIO_PCI_INTX_IRQ_INDEX;
+    irq_set->start = 0;
+    irq_set->count = 1;
+    pfd = (int32_t *)&irq_set->data;
+
+    *pfd = irqfd.resamplefd;
+
+    ret = ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, irq_set);
+    g_free(irq_set);
+    if (ret) {
+        error_report("vfio: Error: Failed to setup INTx unmask fd: %m");
+        goto fail_vfio;
+    }
+
+    /* Let'em rip */
+    vfio_unmask_intx(vdev);
+
+    vdev->intx.kvm_accel = true;
+
+    DPRINTF("%s(%04x:%02x:%02x.%x) KVM INTx accel enabled\n",
+            __func__, vdev->host.domain, vdev->host.bus,
+            vdev->host.slot, vdev->host.function);
+
+    return;
+
+fail_vfio:
+    irqfd.flags = KVM_IRQFD_FLAG_DEASSIGN;
+    kvm_vm_ioctl(kvm_state, KVM_IRQFD, &irqfd);
+fail_irqfd:
+    event_notifier_cleanup(&vdev->intx.unmask);
+fail:
+    qemu_set_fd_handler(irqfd.fd, vfio_intx_interrupt, NULL, vdev);
+    vfio_unmask_intx(vdev);
+#endif
+}
+
+static void vfio_disable_intx_kvm(VFIODevice *vdev)
+{
+#ifdef CONFIG_KVM
+    struct kvm_irqfd irqfd = {
+        .fd = event_notifier_get_fd(&vdev->intx.interrupt),
+        .gsi = vdev->intx.route.irq,
+        .flags = KVM_IRQFD_FLAG_DEASSIGN,
+    };
+
+    if (!vdev->intx.kvm_accel) {
+        return;
+    }
+
+    /*
+     * Get to a known state, hardware masked, QEMU ready to accept new
+     * interrupts, QEMU IRQ de-asserted.
+     */
+    vfio_mask_intx(vdev);
+    vdev->intx.pending = false;
+    qemu_set_irq(vdev->pdev.irq[vdev->intx.pin], 0);
+
+    /* Tell KVM to stop listening for an INTx irqfd */
+    if (kvm_vm_ioctl(kvm_state, KVM_IRQFD, &irqfd)) {
+        error_report("vfio: Error: Failed to disable INTx irqfd: %m");
+    }
+
+    /* We only need to close the eventfd for VFIO to cleanup the kernel side */
+    event_notifier_cleanup(&vdev->intx.unmask);
+
+    /* QEMU starts listening for interrupt events. */
+    qemu_set_fd_handler(irqfd.fd, vfio_intx_interrupt, NULL, vdev);
+
+    vdev->intx.kvm_accel = false;
+
+    /* If we've missed an event, let it re-fire through QEMU */
+    vfio_unmask_intx(vdev);
+
+    DPRINTF("%s(%04x:%02x:%02x.%x) KVM INTx accel disabled\n",
+            __func__, vdev->host.domain, vdev->host.bus,
+            vdev->host.slot, vdev->host.function);
+#endif
+}
+
+static void vfio_update_irq(PCIDevice *pdev)
+{
+    VFIODevice *vdev = DO_UPCAST(VFIODevice, pdev, pdev);
+    PCIINTxRoute route;
+
+    if (vdev->interrupt != VFIO_INT_INTx) {
+        return;
+    }
+
+    route = pci_device_route_intx_to_irq(&vdev->pdev, vdev->intx.pin);
+
+    if (!pci_intx_route_changed(&vdev->intx.route, &route)) {
+        return; /* Nothing changed */
+    }
+
+    DPRINTF("%s(%04x:%02x:%02x.%x) IRQ moved %d -> %d\n", __func__,
+            vdev->host.domain, vdev->host.bus, vdev->host.slot,
+            vdev->host.function, vdev->intx.route.irq, route.irq);
+
+    vfio_disable_intx_kvm(vdev);
+
+    vdev->intx.route = route;
+
+    if (route.mode != PCI_INTX_ENABLED) {
+        return;
+    }
+
+    vfio_enable_intx_kvm(vdev);
+
+    /* Re-enable the interrupt in cased we missed an EOI */
+    vfio_eoi(vdev);
+}
+
+static int vfio_enable_intx(VFIODevice *vdev)
+{
+    uint8_t pin = vfio_pci_read_config(&vdev->pdev, PCI_INTERRUPT_PIN, 1);
+    int ret, argsz;
+    struct vfio_irq_set *irq_set;
+    int32_t *pfd;
+
+    if (!pin) {
+        return 0;
+    }
+
+    vfio_disable_interrupts(vdev);
+
+    vdev->intx.pin = pin - 1; /* Pin A (1) -> irq[0] */
+
+#ifdef CONFIG_KVM
+    /*
+     * Only conditional to avoid generating error messages on platforms
+     * where we won't actually use the result anyway.
+     */
+    if (kvm_irqfds_enabled() &&
+        kvm_check_extension(kvm_state, KVM_CAP_IRQFD_RESAMPLE)) {
+        vdev->intx.route = pci_device_route_intx_to_irq(&vdev->pdev,
+                                                        vdev->intx.pin);
+    }
+#endif
+
+    ret = event_notifier_init(&vdev->intx.interrupt, 0);
+    if (ret) {
+        error_report("vfio: Error: event_notifier_init failed");
+        return ret;
+    }
+
+    argsz = sizeof(*irq_set) + sizeof(*pfd);
+
+    irq_set = g_malloc0(argsz);
+    irq_set->argsz = argsz;
+    irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_TRIGGER;
+    irq_set->index = VFIO_PCI_INTX_IRQ_INDEX;
+    irq_set->start = 0;
+    irq_set->count = 1;
+    pfd = (int32_t *)&irq_set->data;
+
+    *pfd = event_notifier_get_fd(&vdev->intx.interrupt);
+    qemu_set_fd_handler(*pfd, vfio_intx_interrupt, NULL, vdev);
+
+    ret = ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, irq_set);
+    g_free(irq_set);
+    if (ret) {
+        error_report("vfio: Error: Failed to setup INTx fd: %m");
+        qemu_set_fd_handler(*pfd, NULL, NULL, vdev);
+        event_notifier_cleanup(&vdev->intx.interrupt);
+        return -errno;
+    }
+
+    vfio_enable_intx_kvm(vdev);
+
+    vdev->interrupt = VFIO_INT_INTx;
+
+    DPRINTF("%s(%04x:%02x:%02x.%x)\n", __func__, vdev->host.domain,
+            vdev->host.bus, vdev->host.slot, vdev->host.function);
+
+    return 0;
+}
+
+static void vfio_disable_intx(VFIODevice *vdev)
+{
+    int fd;
+
+    qemu_del_timer(vdev->intx.mmap_timer);
+    vfio_disable_intx_kvm(vdev);
+    vfio_disable_irqindex(vdev, VFIO_PCI_INTX_IRQ_INDEX);
+    vdev->intx.pending = false;
+    qemu_set_irq(vdev->pdev.irq[vdev->intx.pin], 0);
+    vfio_mmap_set_enabled(vdev, true);
+
+    fd = event_notifier_get_fd(&vdev->intx.interrupt);
+    qemu_set_fd_handler(fd, NULL, NULL, vdev);
+    event_notifier_cleanup(&vdev->intx.interrupt);
+
+    vdev->interrupt = VFIO_INT_NONE;
+
+    DPRINTF("%s(%04x:%02x:%02x.%x)\n", __func__, vdev->host.domain,
+            vdev->host.bus, vdev->host.slot, vdev->host.function);
+}
+
+/*
+ * MSI/X
+ */
+static void vfio_msi_interrupt(void *opaque)
+{
+    VFIOMSIVector *vector = opaque;
+    VFIODevice *vdev = vector->vdev;
+    int nr = vector - vdev->msi_vectors;
+
+    if (!event_notifier_test_and_clear(&vector->interrupt)) {
+        return;
+    }
+
+    DPRINTF("%s(%04x:%02x:%02x.%x) vector %d\n", __func__,
+            vdev->host.domain, vdev->host.bus, vdev->host.slot,
+            vdev->host.function, nr);
+
+    if (vdev->interrupt == VFIO_INT_MSIX) {
+        msix_notify(&vdev->pdev, nr);
+    } else if (vdev->interrupt == VFIO_INT_MSI) {
+        msi_notify(&vdev->pdev, nr);
+    } else {
+        error_report("vfio: MSI interrupt receieved, but not enabled?");
+    }
+}
+
+static int vfio_enable_vectors(VFIODevice *vdev, bool msix)
+{
+    struct vfio_irq_set *irq_set;
+    int ret = 0, i, argsz;
+    int32_t *fds;
+
+    argsz = sizeof(*irq_set) + (vdev->nr_vectors * sizeof(*fds));
+
+    irq_set = g_malloc0(argsz);
+    irq_set->argsz = argsz;
+    irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_TRIGGER;
+    irq_set->index = msix ? VFIO_PCI_MSIX_IRQ_INDEX : VFIO_PCI_MSI_IRQ_INDEX;
+    irq_set->start = 0;
+    irq_set->count = vdev->nr_vectors;
+    fds = (int32_t *)&irq_set->data;
+
+    for (i = 0; i < vdev->nr_vectors; i++) {
+        if (!vdev->msi_vectors[i].use) {
+            fds[i] = -1;
+            continue;
+        }
+
+        fds[i] = event_notifier_get_fd(&vdev->msi_vectors[i].interrupt);
+    }
+
+    ret = ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, irq_set);
+
+    g_free(irq_set);
+
+    return ret;
+}
+
+static int vfio_msix_vector_do_use(PCIDevice *pdev, unsigned int nr,
+                                   MSIMessage *msg, IOHandler *handler)
+{
+    VFIODevice *vdev = DO_UPCAST(VFIODevice, pdev, pdev);
+    VFIOMSIVector *vector;
+    int ret;
+
+    DPRINTF("%s(%04x:%02x:%02x.%x) vector %d used\n", __func__,
+            vdev->host.domain, vdev->host.bus, vdev->host.slot,
+            vdev->host.function, nr);
+
+    vector = &vdev->msi_vectors[nr];
+    vector->vdev = vdev;
+    vector->use = true;
+
+    msix_vector_use(pdev, nr);
+
+    if (event_notifier_init(&vector->interrupt, 0)) {
+        error_report("vfio: Error: event_notifier_init failed");
+    }
+
+    /*
+     * Attempt to enable route through KVM irqchip,
+     * default to userspace handling if unavailable.
+     */
+    vector->virq = msg ? kvm_irqchip_add_msi_route(kvm_state, *msg) : -1;
+    if (vector->virq < 0 ||
+        kvm_irqchip_add_irqfd_notifier(kvm_state, &vector->interrupt,
+                                       vector->virq) < 0) {
+        if (vector->virq >= 0) {
+            kvm_irqchip_release_virq(kvm_state, vector->virq);
+            vector->virq = -1;
+        }
+        qemu_set_fd_handler(event_notifier_get_fd(&vector->interrupt),
+                            handler, NULL, vector);
+    }
+
+    /*
+     * We don't want to have the host allocate all possible MSI vectors
+     * for a device if they're not in use, so we shutdown and incrementally
+     * increase them as needed.
+     */
+    if (vdev->nr_vectors < nr + 1) {
+        vfio_disable_irqindex(vdev, VFIO_PCI_MSIX_IRQ_INDEX);
+        vdev->nr_vectors = nr + 1;
+        ret = vfio_enable_vectors(vdev, true);
+        if (ret) {
+            error_report("vfio: failed to enable vectors, %d", ret);
+        }
+    } else {
+        int argsz;
+        struct vfio_irq_set *irq_set;
+        int32_t *pfd;
+
+        argsz = sizeof(*irq_set) + sizeof(*pfd);
+
+        irq_set = g_malloc0(argsz);
+        irq_set->argsz = argsz;
+        irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD |
+                         VFIO_IRQ_SET_ACTION_TRIGGER;
+        irq_set->index = VFIO_PCI_MSIX_IRQ_INDEX;
+        irq_set->start = nr;
+        irq_set->count = 1;
+        pfd = (int32_t *)&irq_set->data;
+
+        *pfd = event_notifier_get_fd(&vector->interrupt);
+
+        ret = ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, irq_set);
+        g_free(irq_set);
+        if (ret) {
+            error_report("vfio: failed to modify vector, %d", ret);
+        }
+    }
+
+    return 0;
+}
+
+static int vfio_msix_vector_use(PCIDevice *pdev,
+                                unsigned int nr, MSIMessage msg)
+{
+    return vfio_msix_vector_do_use(pdev, nr, &msg, vfio_msi_interrupt);
+}
+
+static void vfio_msix_vector_release(PCIDevice *pdev, unsigned int nr)
+{
+    VFIODevice *vdev = DO_UPCAST(VFIODevice, pdev, pdev);
+    VFIOMSIVector *vector = &vdev->msi_vectors[nr];
+    int argsz;
+    struct vfio_irq_set *irq_set;
+    int32_t *pfd;
+
+    DPRINTF("%s(%04x:%02x:%02x.%x) vector %d released\n", __func__,
+            vdev->host.domain, vdev->host.bus, vdev->host.slot,
+            vdev->host.function, nr);
+
+    /*
+     * XXX What's the right thing to do here?  This turns off the interrupt
+     * completely, but do we really just want to switch the interrupt to
+     * bouncing through userspace and let msix.c drop it?  Not sure.
+     */
+    msix_vector_unuse(pdev, nr);
+
+    argsz = sizeof(*irq_set) + sizeof(*pfd);
+
+    irq_set = g_malloc0(argsz);
+    irq_set->argsz = argsz;
+    irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD |
+                     VFIO_IRQ_SET_ACTION_TRIGGER;
+    irq_set->index = VFIO_PCI_MSIX_IRQ_INDEX;
+    irq_set->start = nr;
+    irq_set->count = 1;
+    pfd = (int32_t *)&irq_set->data;
+
+    *pfd = -1;
+
+    ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, irq_set);
+
+    g_free(irq_set);
+
+    if (vector->virq < 0) {
+        qemu_set_fd_handler(event_notifier_get_fd(&vector->interrupt),
+                            NULL, NULL, NULL);
+    } else {
+        kvm_irqchip_remove_irqfd_notifier(kvm_state, &vector->interrupt,
+                                          vector->virq);
+        kvm_irqchip_release_virq(kvm_state, vector->virq);
+        vector->virq = -1;
+    }
+
+    event_notifier_cleanup(&vector->interrupt);
+    vector->use = false;
+}
+
+static void vfio_enable_msix(VFIODevice *vdev)
+{
+    vfio_disable_interrupts(vdev);
+
+    vdev->msi_vectors = g_malloc0(vdev->msix->entries * sizeof(VFIOMSIVector));
+
+    vdev->interrupt = VFIO_INT_MSIX;
+
+    /*
+     * Some communication channels between VF & PF or PF & fw rely on the
+     * physical state of the device and expect that enabling MSI-X from the
+     * guest enables the same on the host.  When our guest is Linux, the
+     * guest driver call to pci_enable_msix() sets the enabling bit in the
+     * MSI-X capability, but leaves the vector table masked.  We therefore
+     * can't rely on a vector_use callback (from request_irq() in the guest)
+     * to switch the physical device into MSI-X mode because that may come a
+     * long time after pci_enable_msix().  This code enables vector 0 with
+     * triggering to userspace, then immediately release the vector, leaving
+     * the physical device with no vectors enabled, but MSI-X enabled, just
+     * like the guest view.
+     */
+    vfio_msix_vector_do_use(&vdev->pdev, 0, NULL, NULL);
+    vfio_msix_vector_release(&vdev->pdev, 0);
+
+    if (msix_set_vector_notifiers(&vdev->pdev, vfio_msix_vector_use,
+                                  vfio_msix_vector_release, NULL)) {
+        error_report("vfio: msix_set_vector_notifiers failed");
+    }
+
+    DPRINTF("%s(%04x:%02x:%02x.%x)\n", __func__, vdev->host.domain,
+            vdev->host.bus, vdev->host.slot, vdev->host.function);
+}
+
+static void vfio_enable_msi(VFIODevice *vdev)
+{
+    int ret, i;
+
+    vfio_disable_interrupts(vdev);
+
+    vdev->nr_vectors = msi_nr_vectors_allocated(&vdev->pdev);
+retry:
+    vdev->msi_vectors = g_malloc0(vdev->nr_vectors * sizeof(VFIOMSIVector));
+
+    for (i = 0; i < vdev->nr_vectors; i++) {
+        MSIMessage msg;
+        VFIOMSIVector *vector = &vdev->msi_vectors[i];
+
+        vector->vdev = vdev;
+        vector->use = true;
+
+        if (event_notifier_init(&vector->interrupt, 0)) {
+            error_report("vfio: Error: event_notifier_init failed");
+        }
+
+        msg = msi_get_message(&vdev->pdev, i);
+
+        /*
+         * Attempt to enable route through KVM irqchip,
+         * default to userspace handling if unavailable.
+         */
+        vector->virq = kvm_irqchip_add_msi_route(kvm_state, msg);
+        if (vector->virq < 0 ||
+            kvm_irqchip_add_irqfd_notifier(kvm_state, &vector->interrupt,
+                                           vector->virq) < 0) {
+            qemu_set_fd_handler(event_notifier_get_fd(&vector->interrupt),
+                                vfio_msi_interrupt, NULL, vector);
+        }
+    }
+
+    ret = vfio_enable_vectors(vdev, false);
+    if (ret) {
+        if (ret < 0) {
+            error_report("vfio: Error: Failed to setup MSI fds: %m");
+        } else if (ret != vdev->nr_vectors) {
+            error_report("vfio: Error: Failed to enable %d "
+                         "MSI vectors, retry with %d", vdev->nr_vectors, ret);
+        }
+
+        for (i = 0; i < vdev->nr_vectors; i++) {
+            VFIOMSIVector *vector = &vdev->msi_vectors[i];
+            if (vector->virq >= 0) {
+                kvm_irqchip_remove_irqfd_notifier(kvm_state, &vector->interrupt,
+                                                  vector->virq);
+                kvm_irqchip_release_virq(kvm_state, vector->virq);
+                vector->virq = -1;
+            } else {
+                qemu_set_fd_handler(event_notifier_get_fd(&vector->interrupt),
+                                    NULL, NULL, NULL);
+            }
+            event_notifier_cleanup(&vector->interrupt);
+        }
+
+        g_free(vdev->msi_vectors);
+
+        if (ret > 0 && ret != vdev->nr_vectors) {
+            vdev->nr_vectors = ret;
+            goto retry;
+        }
+        vdev->nr_vectors = 0;
+
+        return;
+    }
+
+    vdev->interrupt = VFIO_INT_MSI;
+
+    DPRINTF("%s(%04x:%02x:%02x.%x) Enabled %d MSI vectors\n", __func__,
+            vdev->host.domain, vdev->host.bus, vdev->host.slot,
+            vdev->host.function, vdev->nr_vectors);
+}
+
+static void vfio_disable_msi_common(VFIODevice *vdev)
+{
+    g_free(vdev->msi_vectors);
+    vdev->msi_vectors = NULL;
+    vdev->nr_vectors = 0;
+    vdev->interrupt = VFIO_INT_NONE;
+
+    vfio_enable_intx(vdev);
+}
+
+static void vfio_disable_msix(VFIODevice *vdev)
+{
+    msix_unset_vector_notifiers(&vdev->pdev);
+
+    if (vdev->nr_vectors) {
+        vfio_disable_irqindex(vdev, VFIO_PCI_MSIX_IRQ_INDEX);
+    }
+
+    vfio_disable_msi_common(vdev);
+
+    DPRINTF("%s(%04x:%02x:%02x.%x)\n", __func__, vdev->host.domain,
+            vdev->host.bus, vdev->host.slot, vdev->host.function);
+}
+
+static void vfio_disable_msi(VFIODevice *vdev)
+{
+    int i;
+
+    vfio_disable_irqindex(vdev, VFIO_PCI_MSI_IRQ_INDEX);
+
+    for (i = 0; i < vdev->nr_vectors; i++) {
+        VFIOMSIVector *vector = &vdev->msi_vectors[i];
+
+        if (!vector->use) {
+            continue;
+        }
+
+        if (vector->virq >= 0) {
+            kvm_irqchip_remove_irqfd_notifier(kvm_state,
+                                              &vector->interrupt, vector->virq);
+            kvm_irqchip_release_virq(kvm_state, vector->virq);
+            vector->virq = -1;
+        } else {
+            qemu_set_fd_handler(event_notifier_get_fd(&vector->interrupt),
+                                NULL, NULL, NULL);
+        }
+
+        event_notifier_cleanup(&vector->interrupt);
+    }
+
+    vfio_disable_msi_common(vdev);
+
+    DPRINTF("%s(%04x:%02x:%02x.%x)\n", __func__, vdev->host.domain,
+            vdev->host.bus, vdev->host.slot, vdev->host.function);
+}
+
+/*
+ * IO Port/MMIO - Beware of the endians, VFIO is always little endian
+ */
+static void vfio_bar_write(void *opaque, hwaddr addr,
+                           uint64_t data, unsigned size)
+{
+    VFIOBAR *bar = opaque;
+    union {
+        uint8_t byte;
+        uint16_t word;
+        uint32_t dword;
+        uint64_t qword;
+    } buf;
+
+    switch (size) {
+    case 1:
+        buf.byte = data;
+        break;
+    case 2:
+        buf.word = cpu_to_le16(data);
+        break;
+    case 4:
+        buf.dword = cpu_to_le32(data);
+        break;
+    default:
+        hw_error("vfio: unsupported write size, %d bytes\n", size);
+        break;
+    }
+
+    if (pwrite(bar->fd, &buf, size, bar->fd_offset + addr) != size) {
+        error_report("%s(,0x%"HWADDR_PRIx", 0x%"PRIx64", %d) failed: %m",
+                     __func__, addr, data, size);
+    }
+
+#ifdef DEBUG_VFIO
+    {
+        VFIODevice *vdev = container_of(bar, VFIODevice, bars[bar->nr]);
+
+        DPRINTF("%s(%04x:%02x:%02x.%x:BAR%d+0x%"HWADDR_PRIx", 0x%"PRIx64
+                ", %d)\n", __func__, vdev->host.domain, vdev->host.bus,
+                vdev->host.slot, vdev->host.function, bar->nr, addr,
+                data, size);
+    }
+#endif
+
+    /*
+     * A read or write to a BAR always signals an INTx EOI.  This will
+     * do nothing if not pending (including not in INTx mode).  We assume
+     * that a BAR access is in response to an interrupt and that BAR
+     * accesses will service the interrupt.  Unfortunately, we don't know
+     * which access will service the interrupt, so we're potentially
+     * getting quite a few host interrupts per guest interrupt.
+     */
+    vfio_eoi(container_of(bar, VFIODevice, bars[bar->nr]));
+}
+
+static uint64_t vfio_bar_read(void *opaque,
+                              hwaddr addr, unsigned size)
+{
+    VFIOBAR *bar = opaque;
+    union {
+        uint8_t byte;
+        uint16_t word;
+        uint32_t dword;
+        uint64_t qword;
+    } buf;
+    uint64_t data = 0;
+
+    if (pread(bar->fd, &buf, size, bar->fd_offset + addr) != size) {
+        error_report("%s(,0x%"HWADDR_PRIx", %d) failed: %m",
+                     __func__, addr, size);
+        return (uint64_t)-1;
+    }
+
+    switch (size) {
+    case 1:
+        data = buf.byte;
+        break;
+    case 2:
+        data = le16_to_cpu(buf.word);
+        break;
+    case 4:
+        data = le32_to_cpu(buf.dword);
+        break;
+    default:
+        hw_error("vfio: unsupported read size, %d bytes\n", size);
+        break;
+    }
+
+#ifdef DEBUG_VFIO
+    {
+        VFIODevice *vdev = container_of(bar, VFIODevice, bars[bar->nr]);
+
+        DPRINTF("%s(%04x:%02x:%02x.%x:BAR%d+0x%"HWADDR_PRIx
+                ", %d) = 0x%"PRIx64"\n", __func__, vdev->host.domain,
+                vdev->host.bus, vdev->host.slot, vdev->host.function,
+                bar->nr, addr, size, data);
+    }
+#endif
+
+    /* Same as write above */
+    vfio_eoi(container_of(bar, VFIODevice, bars[bar->nr]));
+
+    return data;
+}
+
+static const MemoryRegionOps vfio_bar_ops = {
+    .read = vfio_bar_read,
+    .write = vfio_bar_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void vfio_vga_write(void *opaque, hwaddr addr,
+                           uint64_t data, unsigned size)
+{
+    VFIOVGARegion *region = opaque;
+    VFIOVGA *vga = container_of(region, VFIOVGA, region[region->nr]);
+    union {
+        uint8_t byte;
+        uint16_t word;
+        uint32_t dword;
+        uint64_t qword;
+    } buf;
+    off_t offset = vga->fd_offset + region->offset + addr;
+
+    switch (size) {
+    case 1:
+        buf.byte = data;
+        break;
+    case 2:
+        buf.word = cpu_to_le16(data);
+        break;
+    case 4:
+        buf.dword = cpu_to_le32(data);
+        break;
+    default:
+        hw_error("vfio: unsupported write size, %d bytes\n", size);
+        break;
+    }
+
+    if (pwrite(vga->fd, &buf, size, offset) != size) {
+        error_report("%s(,0x%"HWADDR_PRIx", 0x%"PRIx64", %d) failed: %m",
+                     __func__, region->offset + addr, data, size);
+    }
+
+    DPRINTF("%s(0x%"HWADDR_PRIx", 0x%"PRIx64", %d)\n",
+            __func__, region->offset + addr, data, size);
+}
+
+static uint64_t vfio_vga_read(void *opaque, hwaddr addr, unsigned size)
+{
+    VFIOVGARegion *region = opaque;
+    VFIOVGA *vga = container_of(region, VFIOVGA, region[region->nr]);
+    union {
+        uint8_t byte;
+        uint16_t word;
+        uint32_t dword;
+        uint64_t qword;
+    } buf;
+    uint64_t data = 0;
+    off_t offset = vga->fd_offset + region->offset + addr;
+
+    if (pread(vga->fd, &buf, size, offset) != size) {
+        error_report("%s(,0x%"HWADDR_PRIx", %d) failed: %m",
+                     __func__, region->offset + addr, size);
+        return (uint64_t)-1;
+    }
+
+    switch (size) {
+    case 1:
+        data = buf.byte;
+        break;
+    case 2:
+        data = le16_to_cpu(buf.word);
+        break;
+    case 4:
+        data = le32_to_cpu(buf.dword);
+        break;
+    default:
+        hw_error("vfio: unsupported read size, %d bytes\n", size);
+        break;
+    }
+
+    DPRINTF("%s(0x%"HWADDR_PRIx", %d) = 0x%"PRIx64"\n",
+            __func__, region->offset + addr, size, data);
+
+    return data;
+}
+
+static const MemoryRegionOps vfio_vga_ops = {
+    .read = vfio_vga_read,
+    .write = vfio_vga_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+/*
+ * Device specific quirks
+ */
+
+#define PCI_VENDOR_ID_ATI               0x1002
+
+/*
+ * Device 1002:68f9 (Advanced Micro Devices [AMD] nee ATI Cedar PRO [Radeon
+ * HD 5450/6350]) reports the upper byte of the physical address of the
+ * I/O port BAR4 through VGA register 0x3c3.  The BAR is 256 bytes, so the
+ * lower byte is known to be zero.  Probing for this quirk reads 0xff from
+ * port 0x3c3 on some devices so we store the physical address and replace
+ * reads with the virtual address any time it matches.  XXX Research when
+ * to enable quirk.
+ */
+static uint64_t vfio_ati_3c3_quirk_read(void *opaque,
+                                        hwaddr addr, unsigned size)
+{
+    VFIOQuirk *quirk = opaque;
+    VFIODevice *vdev = quirk->vdev;
+    PCIDevice *pdev = &vdev->pdev;
+    uint64_t data = vfio_vga_read(&vdev->vga.region[QEMU_PCI_VGA_IO_HI],
+                                  addr + 0x3, size);
+
+    if (data == quirk->data) {
+        data = pci_get_byte(pdev->config + PCI_BASE_ADDRESS_4 + 1);
+        DPRINTF("%s(0x3c3, 1) = 0x%"PRIx64"\n", __func__, data);
+    }
+
+    return data;
+}
+
+static const MemoryRegionOps vfio_ati_3c3_quirk = {
+    .read = vfio_ati_3c3_quirk_read,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void vfio_vga_probe_ati_3c3_quirk(VFIODevice *vdev)
+{
+    PCIDevice *pdev = &vdev->pdev;
+    off_t physoffset = vdev->config_offset + PCI_BASE_ADDRESS_4;
+    uint32_t physbar;
+    VFIOQuirk *quirk;
+
+    if (pci_get_word(pdev->config + PCI_VENDOR_ID) != PCI_VENDOR_ID_ATI ||
+        vdev->bars[4].size < 256) {
+        return;
+    }
+
+    /* Get I/O port BAR physical address */
+    if (pread(vdev->fd, &physbar, 4, physoffset) != 4) {
+        error_report("vfio: probe failed for ATI/AMD 0x3c3 quirk on device "
+                     "%04x:%02x:%02x.%x", vdev->host.domain,
+                     vdev->host.bus, vdev->host.slot, vdev->host.function);
+        return;
+    }
+
+    quirk = g_malloc0(sizeof(*quirk));
+    quirk->vdev = vdev;
+    quirk->data = (physbar >> 8) & 0xff;
+
+    memory_region_init_io(&quirk->mem, &vfio_ati_3c3_quirk, quirk,
+                          "vfio-ati-3c3-quirk", 1);
+    memory_region_add_subregion(&vdev->vga.region[QEMU_PCI_VGA_IO_HI].mem, 3,
+                                &quirk->mem);
+
+    QLIST_INSERT_HEAD(&vdev->vga.region[QEMU_PCI_VGA_IO_HI].quirks,
+                      quirk, next);
+
+    DPRINTF("Enabled ATI/AMD quirk 0x3c3 for device %04x:%02x:%02x.%x\n",
+            vdev->host.domain, vdev->host.bus, vdev->host.slot,
+            vdev->host.function);
+}
+
+/*
+ * Device 1002:68f9 (Advanced Micro Devices [AMD] nee ATI Cedar PRO [Radeon
+ * HD 5450/6350]) reports the physical address of MMIO BAR0 through a
+ * write/read operation on I/O port BAR4.  When uint32_t 0x4010 is written
+ * to offset 0x0, the subsequent read from offset 0x4 returns the contents
+ * of BAR0.  Test for this quirk on all ATI/AMD devices.  XXX - Note that
+ * 0x10 is the offset of BAR0 in config sapce, is this a window to all of
+ * config space?
+ */
+static uint64_t vfio_ati_4010_quirk_read(void *opaque,
+                                         hwaddr addr, unsigned size)
+{
+    VFIOQuirk *quirk = opaque;
+    VFIODevice *vdev = quirk->vdev;
+    PCIDevice *pdev = &vdev->pdev;
+    uint64_t data = vfio_bar_read(&vdev->bars[4], addr, size);
+
+    if (addr == 4 && size == 4 && quirk->data) {
+        data = pci_get_long(pdev->config + PCI_BASE_ADDRESS_0);
+        DPRINTF("%s(BAR4+0x4) = 0x%"PRIx64"\n", __func__, data);
+    }
+
+    quirk->data = 0;
+
+    return data;
+}
+
+static void vfio_ati_4010_quirk_write(void *opaque, hwaddr addr,
+                                      uint64_t data, unsigned size)
+{
+    VFIOQuirk *quirk = opaque;
+    VFIODevice *vdev = quirk->vdev;
+
+    vfio_bar_write(&vdev->bars[4], addr, data, size);
+
+    quirk->data = (addr == 0 && size == 4 && data == 0x4010) ? 1 : 0;
+}
+
+static const MemoryRegionOps vfio_ati_4010_quirk = {
+    .read = vfio_ati_4010_quirk_read,
+    .write = vfio_ati_4010_quirk_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void vfio_probe_ati_4010_quirk(VFIODevice *vdev, int nr)
+{
+    PCIDevice *pdev = &vdev->pdev;
+    off_t physoffset = vdev->config_offset + PCI_BASE_ADDRESS_0;
+    uint32_t physbar0;
+    uint64_t data;
+    VFIOQuirk *quirk;
+
+    if (!vdev->has_vga || nr != 4 || !vdev->bars[0].size ||
+        pci_get_word(pdev->config + PCI_VENDOR_ID) != PCI_VENDOR_ID_ATI) {
+        return;
+    }
+
+    /* Get I/O port BAR physical address */
+    if (pread(vdev->fd, &physbar0, 4, physoffset) != 4) {
+        error_report("vfio: probe failed for ATI/AMD 0x4010 quirk on device "
+                     "%04x:%02x:%02x.%x", vdev->host.domain,
+                     vdev->host.bus, vdev->host.slot, vdev->host.function);
+        return;
+    }
+
+    /* Write 0x4010 to I/O port BAR offset 0 */
+    vfio_bar_write(&vdev->bars[4], 0, 0x4010, 4);
+    /* Read back result */
+    data = vfio_bar_read(&vdev->bars[4], 4, 4);
+
+    /* If the register matches the physical address of BAR0, we need a quirk */
+    if (data != physbar0) {
+        return;
+    }
+
+    quirk = g_malloc0(sizeof(*quirk));
+    quirk->vdev = vdev;
+
+    memory_region_init_io(&quirk->mem, &vfio_ati_4010_quirk, quirk,
+                          "vfio-ati-4010-quirk", 8);
+    memory_region_add_subregion_overlap(&vdev->bars[nr].mem, 0, &quirk->mem, 1);
+
+    QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next);
+
+    DPRINTF("Enabled ATI/AMD quirk 0x4010 for device %04x:%02x:%02x.%x\n",
+            vdev->host.domain, vdev->host.bus, vdev->host.slot,
+            vdev->host.function);
+}
+
+/*
+ * Device 1002:5b63 (Advanced Micro Devices [AMD] nee ATI RV370 [Radeon X550])
+ * retrieves the upper half of the MMIO BAR0 physical address by writing
+ * 0xf10 to I/O port BAR1 offset 0 and reading the result from offset 6.
+ * XXX - 0x10 is the offset of BAR0 in PCI config space, this could provide
+ * full access to config space.  Config space is little endian, so the data
+ * register probably starts at 0x4.
+ */
+static uint64_t vfio_ati_f10_quirk_read(void *opaque,
+                                        hwaddr addr, unsigned size)
+{
+    VFIOQuirk *quirk = opaque;
+    VFIODevice *vdev = quirk->vdev;
+    PCIDevice *pdev = &vdev->pdev;
+    uint64_t data = vfio_bar_read(&vdev->bars[1], addr, size);
+
+    if (addr == 6 && size == 2 && quirk->data) {
+        data = pci_get_word(pdev->config + PCI_BASE_ADDRESS_0 + 2);
+        DPRINTF("%s(BAR1+0x6) = 0x%"PRIx64"\n", __func__, data);
+    }
+
+    quirk->data = 0;
+
+    return data;
+}
+
+static void vfio_ati_f10_quirk_write(void *opaque, hwaddr addr,
+                                     uint64_t data, unsigned size)
+{
+    VFIOQuirk *quirk = opaque;
+    VFIODevice *vdev = quirk->vdev;
+
+    vfio_bar_write(&vdev->bars[1], addr, data, size);
+
+    quirk->data = (addr == 0 && size == 4 && data == 0xf10) ? 1 : 0;
+}
+
+static const MemoryRegionOps vfio_ati_f10_quirk = {
+    .read = vfio_ati_f10_quirk_read,
+    .write = vfio_ati_f10_quirk_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void vfio_probe_ati_f10_quirk(VFIODevice *vdev, int nr)
+{
+    PCIDevice *pdev = &vdev->pdev;
+    off_t physoffset = vdev->config_offset + PCI_BASE_ADDRESS_0;
+    uint32_t physbar0;
+    uint64_t data;
+    VFIOQuirk *quirk;
+
+    if (!vdev->has_vga || nr != 1 || !vdev->bars[0].size ||
+        pci_get_word(pdev->config + PCI_VENDOR_ID) != PCI_VENDOR_ID_ATI) {
+        return;
+    }
+
+    /* Get I/O port BAR physical address */
+    if (pread(vdev->fd, &physbar0, 4, physoffset) != 4) {
+        error_report("vfio: probe failed for ATI/AMD 0xf10 quirk on device "
+                     "%04x:%02x:%02x.%x", vdev->host.domain,
+                     vdev->host.bus, vdev->host.slot, vdev->host.function);
+        return;
+    }
+
+    vfio_bar_write(&vdev->bars[1], 0, 0xf10, 4);
+    data = vfio_bar_read(&vdev->bars[1], 0x6, 2);
+
+    /* If the register matches the physical address of BAR0, we need a quirk */
+    if (data != (le32_to_cpu(physbar0) >> 16)) {
+        return;
+    }
+
+    quirk = g_malloc0(sizeof(*quirk));
+    quirk->vdev = vdev;
+
+    memory_region_init_io(&quirk->mem, &vfio_ati_f10_quirk, quirk,
+                          "vfio-ati-f10-quirk", 8);
+    memory_region_add_subregion_overlap(&vdev->bars[nr].mem, 0, &quirk->mem, 1);
+
+    QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next);
+
+    DPRINTF("Enabled ATI/AMD quirk 0xf10 for device %04x:%02x:%02x.%x\n",
+            vdev->host.domain, vdev->host.bus, vdev->host.slot,
+            vdev->host.function);
+}
+
+#define PCI_VENDOR_ID_NVIDIA                    0x10de
+
+/*
+ * Nvidia has several different methods to get to config space, the
+ * nouveu project has several of these documented here:
+ * https://github.com/pathscale/envytools/tree/master/hwdocs
+ *
+ * The first quirk is actually not documented in envytools and is found
+ * on 10de:01d1 (NVIDIA Corporation G72 [GeForce 7300 LE]).  This is an
+ * NV46 chipset.  The backdoor uses the legacy VGA I/O ports to access
+ * the mirror of PCI config space found at BAR0 offset 0x1800.  The access
+ * sequence first writes 0x338 to I/O port 0x3d4.  The target offset is
+ * then written to 0x3d0.  Finally 0x538 is written for a read and 0x738
+ * is written for a write to 0x3d4.  The BAR0 offset is then accessible
+ * through 0x3d0.  This quirk doesn't seem to be necessary on newer cards
+ * that use the I/O port BAR5 window but it doesn't hurt to leave it.
+ */
+enum {
+    NV_3D0_NONE,
+    NV_3D0_SELECT,
+    NV_3D0_WINDOW,
+    NV_3D0_READ,
+    NV_3D0_WRITE,
+};
+
+static uint64_t vfio_nvidia_3d0_quirk_read(void *opaque,
+                                           hwaddr addr, unsigned size)
+{
+    VFIOQuirk *quirk = opaque;
+    VFIODevice *vdev = quirk->vdev;
+    PCIDevice *pdev = &vdev->pdev;
+    uint64_t data = vfio_vga_read(&vdev->vga.region[QEMU_PCI_VGA_IO_HI],
+                                  addr + 0x10, size);
+
+    if (quirk->data == NV_3D0_READ && addr == 0) {
+        data = vfio_pci_read_config(pdev, quirk->data2, size);
+        DPRINTF("%s(0x3d0, %d) = 0x%"PRIx64"\n", __func__, size, data);
+    }
+
+    quirk->data = NV_3D0_NONE;
+
+    return data;
+}
+
+static void vfio_nvidia_3d0_quirk_write(void *opaque, hwaddr addr,
+                                        uint64_t data, unsigned size)
+{
+    VFIOQuirk *quirk = opaque;
+    VFIODevice *vdev = quirk->vdev;
+    PCIDevice *pdev = &vdev->pdev;
+
+    switch (quirk->data) {
+    case NV_3D0_NONE:
+        if (addr == 4 && data == 0x338) {
+            quirk->data = NV_3D0_SELECT;
+        }
+        break;
+    case NV_3D0_SELECT:
+        quirk->data = NV_3D0_NONE;
+        if (addr == 0 && (data & ~0xff) == 0x1800) {
+            quirk->data = NV_3D0_WINDOW;
+            quirk->data2 = data & 0xff;
+        }
+        break;
+    case NV_3D0_WINDOW:
+        quirk->data = NV_3D0_NONE;
+        if (addr == 4) {
+            if (data == 0x538) {
+                quirk->data = NV_3D0_READ;
+            } else if (data == 0x738) {
+                quirk->data = NV_3D0_WRITE;
+            }
+        }
+        break;
+    case NV_3D0_WRITE:
+        quirk->data = NV_3D0_NONE;
+        if (addr == 0) {
+            vfio_pci_write_config(pdev, quirk->data2, data, size);
+            DPRINTF("%s(0x3d0, 0x%"PRIx64", %d)\n", __func__, data, size);
+            return;
+        }
+        break;
+    default:
+        quirk->data = NV_3D0_NONE;
+    }
+
+    vfio_vga_write(&vdev->vga.region[QEMU_PCI_VGA_IO_HI],
+                   addr + 0x10, data, size);
+}
+
+static const MemoryRegionOps vfio_nvidia_3d0_quirk = {
+    .read = vfio_nvidia_3d0_quirk_read,
+    .write = vfio_nvidia_3d0_quirk_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void vfio_vga_probe_nvidia_3d0_quirk(VFIODevice *vdev)
+{
+    PCIDevice *pdev = &vdev->pdev;
+    VFIOQuirk *quirk;
+
+    if (pci_get_word(pdev->config + PCI_VENDOR_ID) != PCI_VENDOR_ID_NVIDIA ||
+        !vdev->bars[1].size) {
+        return;
+    }
+
+    quirk = g_malloc0(sizeof(*quirk));
+    quirk->vdev = vdev;
+
+    memory_region_init_io(&quirk->mem, &vfio_nvidia_3d0_quirk, quirk,
+                          "vfio-nvidia-3d0-quirk", 6);
+    memory_region_add_subregion(&vdev->vga.region[QEMU_PCI_VGA_IO_HI].mem,
+                                0x10, &quirk->mem);
+
+    QLIST_INSERT_HEAD(&vdev->vga.region[QEMU_PCI_VGA_IO_HI].quirks,
+                      quirk, next);
+
+    DPRINTF("Enabled NVIDIA VGA 0x3d0 quirk for device %04x:%02x:%02x.%x\n",
+            vdev->host.domain, vdev->host.bus, vdev->host.slot,
+            vdev->host.function);
+}
+
+/*
+ * The second quirk is documented in envytools.  The I/O port BAR5 is just
+ * a set of address/data ports to the MMIO BARs.  The BAR we care about is
+ * again BAR0.  This backdoor is apparently a bit newer than the one above
+ * so we need to not only trap 256 bytes @0x1800, but all of PCI config
+ * space, including extended space is available at the 4k @0x88000.
+ */
+enum {
+    NV_BAR5_ADDRESS = 0x1,
+    NV_BAR5_ENABLE = 0x2,
+    NV_BAR5_MASTER = 0x4,
+    NV_BAR5_VALID = 0x7,
+};
+
+static uint64_t vfio_nvidia_bar5_window_quirk_read(void *opaque,
+                                                   hwaddr addr, unsigned size)
+{
+    VFIOQuirk *quirk = opaque;
+    VFIODevice *vdev = quirk->vdev;
+    uint64_t data = vfio_bar_read(&vdev->bars[5], addr, size);
+
+    if (addr == 0xc && quirk->data == NV_BAR5_VALID) {
+        data = vfio_pci_read_config(&vdev->pdev, quirk->data2, size);
+        DPRINTF("%s(%04x:%02x:%02x.%x:BAR5+0x%"HWADDR_PRIx", %d) = 0x%"
+                PRIx64"\n", __func__, vdev->host.domain, vdev->host.bus,
+                vdev->host.slot, vdev->host.function, addr, size, data);
+    }
+
+    return data;
+}
+
+static void vfio_nvidia_bar5_window_quirk_write(void *opaque, hwaddr addr,
+                                                uint64_t data, unsigned size)
+{
+    VFIOQuirk *quirk = opaque;
+    VFIODevice *vdev = quirk->vdev;
+
+    /*
+     * Use quirk->data to track enables and quirk->data2 for the offset
+     */
+    switch (addr) {
+    case 0x0:
+        if (data & 0x1) {
+            quirk->data |= NV_BAR5_MASTER;
+        } else {
+            quirk->data &= ~NV_BAR5_MASTER;
+        }
+        break;
+    case 0x4:
+        if (data & 0x1) {
+            quirk->data |= NV_BAR5_ENABLE;
+        } else {
+            quirk->data &= ~NV_BAR5_ENABLE;
+        }
+        break;
+    case 0x8:
+        if (quirk->data & NV_BAR5_MASTER) {
+            if ((data & ~0xfff) == 0x88000) {
+                quirk->data |= NV_BAR5_ADDRESS;
+                quirk->data2 = data & 0xfff;
+            } else if ((data & ~0xff) == 0x1800) {
+                quirk->data |= NV_BAR5_ADDRESS;
+                quirk->data2 = data & 0xff;
+            } else {
+                quirk->data &= ~NV_BAR5_ADDRESS;
+            }
+        }
+        break;
+    case 0xc:
+        if (quirk->data == NV_BAR5_VALID) {
+            vfio_pci_write_config(&vdev->pdev, quirk->data2, data, size);
+            DPRINTF("%s(%04x:%02x:%02x.%x:BAR5+0x%"HWADDR_PRIx", 0x%"
+                    PRIx64", %d)\n", __func__, vdev->host.domain,
+                    vdev->host.bus, vdev->host.slot, vdev->host.function,
+                    addr, data, size);
+            return;
+        }
+    }
+
+    vfio_bar_write(&vdev->bars[5], addr, data, size);
+}
+
+static const MemoryRegionOps vfio_nvidia_bar5_window_quirk = {
+    .read = vfio_nvidia_bar5_window_quirk_read,
+    .write = vfio_nvidia_bar5_window_quirk_write,
+    .valid.min_access_size = 4,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void vfio_probe_nvidia_bar5_window_quirk(VFIODevice *vdev, int nr)
+{
+    PCIDevice *pdev = &vdev->pdev;
+    VFIOQuirk *quirk;
+
+    if (!vdev->has_vga || nr != 5 ||
+        pci_get_word(pdev->config + PCI_VENDOR_ID) != PCI_VENDOR_ID_NVIDIA) {
+        return;
+    }
+
+    quirk = g_malloc0(sizeof(*quirk));
+    quirk->vdev = vdev;
+
+    memory_region_init_io(&quirk->mem, &vfio_nvidia_bar5_window_quirk, quirk,
+                          "vfio-nvidia-bar5-window-quirk", 16);
+    memory_region_add_subregion_overlap(&vdev->bars[nr].mem, 0, &quirk->mem, 1);
+
+    QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next);
+
+    DPRINTF("Enabled NVIDIA BAR5 window quirk for device %04x:%02x:%02x.%x\n",
+            vdev->host.domain, vdev->host.bus, vdev->host.slot,
+            vdev->host.function);
+}
+
+/*
+ * Finally, BAR0 itself.  We want to redirect any accesses to either
+ * 0x1800 or 0x88000 through the PCI config space access functions.
+ *
+ * NB - quirk at a page granularity or else they don't seem to work when
+ *      BARs are mmap'd
+ *
+ * Here's offset 0x88000...
+ */
+static uint64_t vfio_nvidia_bar0_88000_quirk_read(void *opaque,
+                                                  hwaddr addr, unsigned size)
+{
+    VFIOQuirk *quirk = opaque;
+    VFIODevice *vdev = quirk->vdev;
+    hwaddr base = 0x88000 & TARGET_PAGE_MASK;
+    hwaddr offset = 0x88000 & ~TARGET_PAGE_MASK;
+    uint64_t data = vfio_bar_read(&vdev->bars[0], addr + base, size);
+
+    if (ranges_overlap(addr, size, offset, PCI_CONFIG_SPACE_SIZE)) {
+        data = vfio_pci_read_config(&vdev->pdev, addr - offset, size);
+
+        DPRINTF("%s(%04x:%02x:%02x.%x:BAR0+0x%"HWADDR_PRIx", %d) = 0x%"
+                PRIx64"\n", __func__, vdev->host.domain, vdev->host.bus,
+                vdev->host.slot, vdev->host.function, addr + base, size, data);
+    }
+
+    return data;
+}
+
+static void vfio_nvidia_bar0_88000_quirk_write(void *opaque, hwaddr addr,
+                                               uint64_t data, unsigned size)
+{
+    VFIOQuirk *quirk = opaque;
+    VFIODevice *vdev = quirk->vdev;
+    hwaddr base = 0x88000 & TARGET_PAGE_MASK;
+    hwaddr offset = 0x88000 & ~TARGET_PAGE_MASK;
+
+    if (ranges_overlap(addr, size, offset, PCI_CONFIG_SPACE_SIZE)) {
+        vfio_pci_write_config(&vdev->pdev, addr - offset, data, size);
+
+        DPRINTF("%s(%04x:%02x:%02x.%x:BAR0+0x%"HWADDR_PRIx", 0x%"
+                PRIx64", %d)\n", __func__, vdev->host.domain, vdev->host.bus,
+                vdev->host.slot, vdev->host.function, addr + base, data, size);
+    } else {
+        vfio_bar_write(&vdev->bars[0], addr + base, data, size);
+    }
+}
+
+static const MemoryRegionOps vfio_nvidia_bar0_88000_quirk = {
+    .read = vfio_nvidia_bar0_88000_quirk_read,
+    .write = vfio_nvidia_bar0_88000_quirk_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void vfio_probe_nvidia_bar0_88000_quirk(VFIODevice *vdev, int nr)
+{
+    PCIDevice *pdev = &vdev->pdev;
+    VFIOQuirk *quirk;
+
+    if (!vdev->has_vga || nr != 0 ||
+        pci_get_word(pdev->config + PCI_VENDOR_ID) != PCI_VENDOR_ID_NVIDIA) {
+        return;
+    }
+
+    quirk = g_malloc0(sizeof(*quirk));
+    quirk->vdev = vdev;
+
+    memory_region_init_io(&quirk->mem, &vfio_nvidia_bar0_88000_quirk, quirk,
+                          "vfio-nvidia-bar0-88000-quirk",
+                          TARGET_PAGE_ALIGN(PCIE_CONFIG_SPACE_SIZE));
+    memory_region_add_subregion_overlap(&vdev->bars[nr].mem,
+                                        0x88000 & TARGET_PAGE_MASK,
+                                        &quirk->mem, 1);
+
+    QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next);
+
+    DPRINTF("Enabled NVIDIA BAR0 0x88000 quirk for device %04x:%02x:%02x.%x\n",
+            vdev->host.domain, vdev->host.bus, vdev->host.slot,
+            vdev->host.function);
+}
+
+/*
+ * And here's the same for BAR0 offset 0x1800...
+ */
+static uint64_t vfio_nvidia_bar0_1800_quirk_read(void *opaque,
+                                                 hwaddr addr, unsigned size)
+{
+    VFIOQuirk *quirk = opaque;
+    VFIODevice *vdev = quirk->vdev;
+    hwaddr base = 0x1800 & TARGET_PAGE_MASK;
+    hwaddr offset = 0x1800 & ~TARGET_PAGE_MASK;
+    uint64_t data = vfio_bar_read(&vdev->bars[0], addr + base, size);
+
+    if (ranges_overlap(addr, size, offset, PCI_CONFIG_SPACE_SIZE)) {
+        data = vfio_pci_read_config(&vdev->pdev, addr - offset, size);
+
+        DPRINTF("%s(%04x:%02x:%02x.%x:BAR0+0x%"HWADDR_PRIx", %d) = 0x%"
+                PRIx64"\n", __func__, vdev->host.domain, vdev->host.bus,
+                vdev->host.slot, vdev->host.function, addr + base, size, data);
+    }
+
+    return data;
+}
+
+static void vfio_nvidia_bar0_1800_quirk_write(void *opaque, hwaddr addr,
+                                              uint64_t data, unsigned size)
+{
+    VFIOQuirk *quirk = opaque;
+    VFIODevice *vdev = quirk->vdev;
+    hwaddr base = 0x1800 & TARGET_PAGE_MASK;
+    hwaddr offset = 0x1800 & ~TARGET_PAGE_MASK;
+
+    if (ranges_overlap(addr, size, offset, PCI_CONFIG_SPACE_SIZE)) {
+        vfio_pci_write_config(&vdev->pdev, addr - offset, data, size);
+
+        DPRINTF("%s(%04x:%02x:%02x.%x:BAR0+0x%"HWADDR_PRIx", 0x%"
+                PRIx64", %d)\n", __func__, vdev->host.domain, vdev->host.bus,
+                vdev->host.slot, vdev->host.function, addr + base, data, size);
+    } else {
+        vfio_bar_write(&vdev->bars[0], addr + base, data, size);
+    }
+}
+
+static const MemoryRegionOps vfio_nvidia_bar0_1800_quirk = {
+    .read = vfio_nvidia_bar0_1800_quirk_read,
+    .write = vfio_nvidia_bar0_1800_quirk_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void vfio_probe_nvidia_bar0_1800_quirk(VFIODevice *vdev, int nr)
+{
+    PCIDevice *pdev = &vdev->pdev;
+    VFIOQuirk *quirk;
+
+    if (!vdev->has_vga || nr != 0 ||
+        pci_get_word(pdev->config + PCI_VENDOR_ID) != PCI_VENDOR_ID_NVIDIA) {
+        return;
+    }
+
+    /* Log the chipset ID */
+    DPRINTF("Nvidia NV%02x\n",
+            (unsigned int)(vfio_bar_read(&vdev->bars[0], 0, 4) >> 20) & 0xff);
+
+    quirk = g_malloc0(sizeof(*quirk));
+    quirk->vdev = vdev;
+
+    memory_region_init_io(&quirk->mem, &vfio_nvidia_bar0_1800_quirk, quirk,
+                          "vfio-nvidia-bar0-1800-quirk",
+                          TARGET_PAGE_ALIGN(PCI_CONFIG_SPACE_SIZE));
+    memory_region_add_subregion_overlap(&vdev->bars[nr].mem,
+                                        0x1800 & TARGET_PAGE_MASK,
+                                        &quirk->mem, 1);
+
+    QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next);
+
+    DPRINTF("Enabled NVIDIA BAR0 0x1800 quirk for device %04x:%02x:%02x.%x\n",
+            vdev->host.domain, vdev->host.bus, vdev->host.slot,
+            vdev->host.function);
+}
+
+/*
+ * TODO - Some Nvidia devices provide config access to their companion HDA
+ * device and even to their parent bridge via these config space mirrors.
+ * Add quirks for those regions.
+ */
+
+/*
+ * Common quirk probe entry points.
+ */
+static void vfio_vga_quirk_setup(VFIODevice *vdev)
+{
+    vfio_vga_probe_ati_3c3_quirk(vdev);
+    vfio_vga_probe_nvidia_3d0_quirk(vdev);
+}
+
+static void vfio_vga_quirk_teardown(VFIODevice *vdev)
+{
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(vdev->vga.region); i++) {
+        while (!QLIST_EMPTY(&vdev->vga.region[i].quirks)) {
+            VFIOQuirk *quirk = QLIST_FIRST(&vdev->vga.region[i].quirks);
+            memory_region_del_subregion(&vdev->vga.region[i].mem, &quirk->mem);
+            QLIST_REMOVE(quirk, next);
+            g_free(quirk);
+        }
+    }
+}
+
+static void vfio_bar_quirk_setup(VFIODevice *vdev, int nr)
+{
+    vfio_probe_ati_4010_quirk(vdev, nr);
+    vfio_probe_ati_f10_quirk(vdev, nr);
+    vfio_probe_nvidia_bar5_window_quirk(vdev, nr);
+    vfio_probe_nvidia_bar0_88000_quirk(vdev, nr);
+    vfio_probe_nvidia_bar0_1800_quirk(vdev, nr);
+}
+
+static void vfio_bar_quirk_teardown(VFIODevice *vdev, int nr)
+{
+    VFIOBAR *bar = &vdev->bars[nr];
+
+    while (!QLIST_EMPTY(&bar->quirks)) {
+        VFIOQuirk *quirk = QLIST_FIRST(&bar->quirks);
+        memory_region_del_subregion(&bar->mem, &quirk->mem);
+        QLIST_REMOVE(quirk, next);
+        g_free(quirk);
+    }
+}
+
+/*
+ * PCI config space
+ */
+static uint32_t vfio_pci_read_config(PCIDevice *pdev, uint32_t addr, int len)
+{
+    VFIODevice *vdev = DO_UPCAST(VFIODevice, pdev, pdev);
+    uint32_t emu_bits = 0, emu_val = 0, phys_val = 0, val;
+
+    memcpy(&emu_bits, vdev->emulated_config_bits + addr, len);
+    emu_bits = le32_to_cpu(emu_bits);
+
+    if (emu_bits) {
+        emu_val = pci_default_read_config(pdev, addr, len);
+    }
+
+    if (~emu_bits & (0xffffffffU >> (32 - len * 8))) {
+        ssize_t ret;
+
+        ret = pread(vdev->fd, &phys_val, len, vdev->config_offset + addr);
+        if (ret != len) {
+            error_report("%s(%04x:%02x:%02x.%x, 0x%x, 0x%x) failed: %m",
+                         __func__, vdev->host.domain, vdev->host.bus,
+                         vdev->host.slot, vdev->host.function, addr, len);
+            return -errno;
+        }
+        phys_val = le32_to_cpu(phys_val);
+    }
+
+    val = (emu_val & emu_bits) | (phys_val & ~emu_bits);
+
+    DPRINTF("%s(%04x:%02x:%02x.%x, @0x%x, len=0x%x) %x\n", __func__,
+            vdev->host.domain, vdev->host.bus, vdev->host.slot,
+            vdev->host.function, addr, len, val);
+
+    return val;
+}
+
+static void vfio_pci_write_config(PCIDevice *pdev, uint32_t addr,
+                                  uint32_t val, int len)
+{
+    VFIODevice *vdev = DO_UPCAST(VFIODevice, pdev, pdev);
+    uint32_t val_le = cpu_to_le32(val);
+
+    DPRINTF("%s(%04x:%02x:%02x.%x, @0x%x, 0x%x, len=0x%x)\n", __func__,
+            vdev->host.domain, vdev->host.bus, vdev->host.slot,
+            vdev->host.function, addr, val, len);
+
+    /* Write everything to VFIO, let it filter out what we can't write */
+    if (pwrite(vdev->fd, &val_le, len, vdev->config_offset + addr) != len) {
+        error_report("%s(%04x:%02x:%02x.%x, 0x%x, 0x%x, 0x%x) failed: %m",
+                     __func__, vdev->host.domain, vdev->host.bus,
+                     vdev->host.slot, vdev->host.function, addr, val, len);
+    }
+
+    /* MSI/MSI-X Enabling/Disabling */
+    if (pdev->cap_present & QEMU_PCI_CAP_MSI &&
+        ranges_overlap(addr, len, pdev->msi_cap, vdev->msi_cap_size)) {
+        int is_enabled, was_enabled = msi_enabled(pdev);
+
+        pci_default_write_config(pdev, addr, val, len);
+
+        is_enabled = msi_enabled(pdev);
+
+        if (!was_enabled && is_enabled) {
+            vfio_enable_msi(vdev);
+        } else if (was_enabled && !is_enabled) {
+            vfio_disable_msi(vdev);
+        }
+    } else if (pdev->cap_present & QEMU_PCI_CAP_MSIX &&
+        ranges_overlap(addr, len, pdev->msix_cap, MSIX_CAP_LENGTH)) {
+        int is_enabled, was_enabled = msix_enabled(pdev);
+
+        pci_default_write_config(pdev, addr, val, len);
+
+        is_enabled = msix_enabled(pdev);
+
+        if (!was_enabled && is_enabled) {
+            vfio_enable_msix(vdev);
+        } else if (was_enabled && !is_enabled) {
+            vfio_disable_msix(vdev);
+        }
+    } else {
+        /* Write everything to QEMU to keep emulated bits correct */
+        pci_default_write_config(pdev, addr, val, len);
+    }
+}
+
+/*
+ * DMA - Mapping and unmapping for the "type1" IOMMU interface used on x86
+ */
+static int vfio_dma_unmap(VFIOContainer *container,
+                          hwaddr iova, ram_addr_t size)
+{
+    struct vfio_iommu_type1_dma_unmap unmap = {
+        .argsz = sizeof(unmap),
+        .flags = 0,
+        .iova = iova,
+        .size = size,
+    };
+
+    if (ioctl(container->fd, VFIO_IOMMU_UNMAP_DMA, &unmap)) {
+        DPRINTF("VFIO_UNMAP_DMA: %d\n", -errno);
+        return -errno;
+    }
+
+    return 0;
+}
+
+static int vfio_dma_map(VFIOContainer *container, hwaddr iova,
+                        ram_addr_t size, void *vaddr, bool readonly)
+{
+    struct vfio_iommu_type1_dma_map map = {
+        .argsz = sizeof(map),
+        .flags = VFIO_DMA_MAP_FLAG_READ,
+        .vaddr = (__u64)(uintptr_t)vaddr,
+        .iova = iova,
+        .size = size,
+    };
+
+    if (!readonly) {
+        map.flags |= VFIO_DMA_MAP_FLAG_WRITE;
+    }
+
+    /*
+     * Try the mapping, if it fails with EBUSY, unmap the region and try
+     * again.  This shouldn't be necessary, but we sometimes see it in
+     * the the VGA ROM space.
+     */
+    if (ioctl(container->fd, VFIO_IOMMU_MAP_DMA, &map) == 0 ||
+        (errno == EBUSY && vfio_dma_unmap(container, iova, size) == 0 &&
+         ioctl(container->fd, VFIO_IOMMU_MAP_DMA, &map) == 0)) {
+        return 0;
+    }
+
+    DPRINTF("VFIO_MAP_DMA: %d\n", -errno);
+    return -errno;
+}
+
+static bool vfio_listener_skipped_section(MemoryRegionSection *section)
+{
+    return !memory_region_is_ram(section->mr);
+}
+
+static void vfio_listener_region_add(MemoryListener *listener,
+                                     MemoryRegionSection *section)
+{
+    VFIOContainer *container = container_of(listener, VFIOContainer,
+                                            iommu_data.listener);
+    hwaddr iova, end;
+    void *vaddr;
+    int ret;
+
+    if (vfio_listener_skipped_section(section)) {
+        DPRINTF("SKIPPING region_add %"HWADDR_PRIx" - %"PRIx64"\n",
+                section->offset_within_address_space,
+                section->offset_within_address_space + section->size - 1);
+        return;
+    }
+
+    if (unlikely((section->offset_within_address_space & ~TARGET_PAGE_MASK) !=
+                 (section->offset_within_region & ~TARGET_PAGE_MASK))) {
+        error_report("%s received unaligned region", __func__);
+        return;
+    }
+
+    iova = TARGET_PAGE_ALIGN(section->offset_within_address_space);
+    end = (section->offset_within_address_space + section->size) &
+          TARGET_PAGE_MASK;
+
+    if (iova >= end) {
+        return;
+    }
+
+    vaddr = memory_region_get_ram_ptr(section->mr) +
+            section->offset_within_region +
+            (iova - section->offset_within_address_space);
+
+    DPRINTF("region_add %"HWADDR_PRIx" - %"HWADDR_PRIx" [%p]\n",
+            iova, end - 1, vaddr);
+
+    ret = vfio_dma_map(container, iova, end - iova, vaddr, section->readonly);
+    if (ret) {
+        error_report("vfio_dma_map(%p, 0x%"HWADDR_PRIx", "
+                     "0x%"HWADDR_PRIx", %p) = %d (%m)",
+                     container, iova, end - iova, vaddr, ret);
+    }
+}
+
+static void vfio_listener_region_del(MemoryListener *listener,
+                                     MemoryRegionSection *section)
+{
+    VFIOContainer *container = container_of(listener, VFIOContainer,
+                                            iommu_data.listener);
+    hwaddr iova, end;
+    int ret;
+
+    if (vfio_listener_skipped_section(section)) {
+        DPRINTF("SKIPPING region_del %"HWADDR_PRIx" - %"PRIx64"\n",
+                section->offset_within_address_space,
+                section->offset_within_address_space + section->size - 1);
+        return;
+    }
+
+    if (unlikely((section->offset_within_address_space & ~TARGET_PAGE_MASK) !=
+                 (section->offset_within_region & ~TARGET_PAGE_MASK))) {
+        error_report("%s received unaligned region", __func__);
+        return;
+    }
+
+    iova = TARGET_PAGE_ALIGN(section->offset_within_address_space);
+    end = (section->offset_within_address_space + section->size) &
+          TARGET_PAGE_MASK;
+
+    if (iova >= end) {
+        return;
+    }
+
+    DPRINTF("region_del %"HWADDR_PRIx" - %"HWADDR_PRIx"\n",
+            iova, end - 1);
+
+    ret = vfio_dma_unmap(container, iova, end - iova);
+    if (ret) {
+        error_report("vfio_dma_unmap(%p, 0x%"HWADDR_PRIx", "
+                     "0x%"HWADDR_PRIx") = %d (%m)",
+                     container, iova, end - iova, ret);
+    }
+}
+
+static MemoryListener vfio_memory_listener = {
+    .region_add = vfio_listener_region_add,
+    .region_del = vfio_listener_region_del,
+};
+
+static void vfio_listener_release(VFIOContainer *container)
+{
+    memory_listener_unregister(&container->iommu_data.listener);
+}
+
+/*
+ * Interrupt setup
+ */
+static void vfio_disable_interrupts(VFIODevice *vdev)
+{
+    switch (vdev->interrupt) {
+    case VFIO_INT_INTx:
+        vfio_disable_intx(vdev);
+        break;
+    case VFIO_INT_MSI:
+        vfio_disable_msi(vdev);
+        break;
+    case VFIO_INT_MSIX:
+        vfio_disable_msix(vdev);
+        break;
+    }
+}
+
+static int vfio_setup_msi(VFIODevice *vdev, int pos)
+{
+    uint16_t ctrl;
+    bool msi_64bit, msi_maskbit;
+    int ret, entries;
+
+    if (pread(vdev->fd, &ctrl, sizeof(ctrl),
+              vdev->config_offset + pos + PCI_CAP_FLAGS) != sizeof(ctrl)) {
+        return -errno;
+    }
+    ctrl = le16_to_cpu(ctrl);
+
+    msi_64bit = !!(ctrl & PCI_MSI_FLAGS_64BIT);
+    msi_maskbit = !!(ctrl & PCI_MSI_FLAGS_MASKBIT);
+    entries = 1 << ((ctrl & PCI_MSI_FLAGS_QMASK) >> 1);
+
+    DPRINTF("%04x:%02x:%02x.%x PCI MSI CAP @0x%x\n", vdev->host.domain,
+            vdev->host.bus, vdev->host.slot, vdev->host.function, pos);
+
+    ret = msi_init(&vdev->pdev, pos, entries, msi_64bit, msi_maskbit);
+    if (ret < 0) {
+        if (ret == -ENOTSUP) {
+            return 0;
+        }
+        error_report("vfio: msi_init failed");
+        return ret;
+    }
+    vdev->msi_cap_size = 0xa + (msi_maskbit ? 0xa : 0) + (msi_64bit ? 0x4 : 0);
+
+    return 0;
+}
+
+/*
+ * We don't have any control over how pci_add_capability() inserts
+ * capabilities into the chain.  In order to setup MSI-X we need a
+ * MemoryRegion for the BAR.  In order to setup the BAR and not
+ * attempt to mmap the MSI-X table area, which VFIO won't allow, we
+ * need to first look for where the MSI-X table lives.  So we
+ * unfortunately split MSI-X setup across two functions.
+ */
+static int vfio_early_setup_msix(VFIODevice *vdev)
+{
+    uint8_t pos;
+    uint16_t ctrl;
+    uint32_t table, pba;
+
+    pos = pci_find_capability(&vdev->pdev, PCI_CAP_ID_MSIX);
+    if (!pos) {
+        return 0;
+    }
+
+    if (pread(vdev->fd, &ctrl, sizeof(ctrl),
+              vdev->config_offset + pos + PCI_CAP_FLAGS) != sizeof(ctrl)) {
+        return -errno;
+    }
+
+    if (pread(vdev->fd, &table, sizeof(table),
+              vdev->config_offset + pos + PCI_MSIX_TABLE) != sizeof(table)) {
+        return -errno;
+    }
+
+    if (pread(vdev->fd, &pba, sizeof(pba),
+              vdev->config_offset + pos + PCI_MSIX_PBA) != sizeof(pba)) {
+        return -errno;
+    }
+
+    ctrl = le16_to_cpu(ctrl);
+    table = le32_to_cpu(table);
+    pba = le32_to_cpu(pba);
+
+    vdev->msix = g_malloc0(sizeof(*(vdev->msix)));
+    vdev->msix->table_bar = table & PCI_MSIX_FLAGS_BIRMASK;
+    vdev->msix->table_offset = table & ~PCI_MSIX_FLAGS_BIRMASK;
+    vdev->msix->pba_bar = pba & PCI_MSIX_FLAGS_BIRMASK;
+    vdev->msix->pba_offset = pba & ~PCI_MSIX_FLAGS_BIRMASK;
+    vdev->msix->entries = (ctrl & PCI_MSIX_FLAGS_QSIZE) + 1;
+
+    DPRINTF("%04x:%02x:%02x.%x "
+            "PCI MSI-X CAP @0x%x, BAR %d, offset 0x%x, entries %d\n",
+            vdev->host.domain, vdev->host.bus, vdev->host.slot,
+            vdev->host.function, pos, vdev->msix->table_bar,
+            vdev->msix->table_offset, vdev->msix->entries);
+
+    return 0;
+}
+
+static int vfio_setup_msix(VFIODevice *vdev, int pos)
+{
+    int ret;
+
+    ret = msix_init(&vdev->pdev, vdev->msix->entries,
+                    &vdev->bars[vdev->msix->table_bar].mem,
+                    vdev->msix->table_bar, vdev->msix->table_offset,
+                    &vdev->bars[vdev->msix->pba_bar].mem,
+                    vdev->msix->pba_bar, vdev->msix->pba_offset, pos);
+    if (ret < 0) {
+        if (ret == -ENOTSUP) {
+            return 0;
+        }
+        error_report("vfio: msix_init failed");
+        return ret;
+    }
+
+    return 0;
+}
+
+static void vfio_teardown_msi(VFIODevice *vdev)
+{
+    msi_uninit(&vdev->pdev);
+
+    if (vdev->msix) {
+        msix_uninit(&vdev->pdev, &vdev->bars[vdev->msix->table_bar].mem,
+                    &vdev->bars[vdev->msix->pba_bar].mem);
+    }
+}
+
+/*
+ * Resource setup
+ */
+static void vfio_mmap_set_enabled(VFIODevice *vdev, bool enabled)
+{
+    int i;
+
+    for (i = 0; i < PCI_ROM_SLOT; i++) {
+        VFIOBAR *bar = &vdev->bars[i];
+
+        if (!bar->size) {
+            continue;
+        }
+
+        memory_region_set_enabled(&bar->mmap_mem, enabled);
+        if (vdev->msix && vdev->msix->table_bar == i) {
+            memory_region_set_enabled(&vdev->msix->mmap_mem, enabled);
+        }
+    }
+}
+
+static void vfio_unmap_bar(VFIODevice *vdev, int nr)
+{
+    VFIOBAR *bar = &vdev->bars[nr];
+
+    if (!bar->size) {
+        return;
+    }
+
+    vfio_bar_quirk_teardown(vdev, nr);
+
+    memory_region_del_subregion(&bar->mem, &bar->mmap_mem);
+    munmap(bar->mmap, memory_region_size(&bar->mmap_mem));
+
+    if (vdev->msix && vdev->msix->table_bar == nr) {
+        memory_region_del_subregion(&bar->mem, &vdev->msix->mmap_mem);
+        munmap(vdev->msix->mmap, memory_region_size(&vdev->msix->mmap_mem));
+    }
+
+    memory_region_destroy(&bar->mem);
+}
+
+static int vfio_mmap_bar(VFIOBAR *bar, MemoryRegion *mem, MemoryRegion *submem,
+                         void **map, size_t size, off_t offset,
+                         const char *name)
+{
+    int ret = 0;
+
+    if (VFIO_ALLOW_MMAP && size && bar->flags & VFIO_REGION_INFO_FLAG_MMAP) {
+        int prot = 0;
+
+        if (bar->flags & VFIO_REGION_INFO_FLAG_READ) {
+            prot |= PROT_READ;
+        }
+
+        if (bar->flags & VFIO_REGION_INFO_FLAG_WRITE) {
+            prot |= PROT_WRITE;
+        }
+
+        *map = mmap(NULL, size, prot, MAP_SHARED,
+                    bar->fd, bar->fd_offset + offset);
+        if (*map == MAP_FAILED) {
+            *map = NULL;
+            ret = -errno;
+            goto empty_region;
+        }
+
+        memory_region_init_ram_ptr(submem, name, size, *map);
+    } else {
+empty_region:
+        /* Create a zero sized sub-region to make cleanup easy. */
+        memory_region_init(submem, name, 0);
+    }
+
+    memory_region_add_subregion(mem, offset, submem);
+
+    return ret;
+}
+
+static void vfio_map_bar(VFIODevice *vdev, int nr)
+{
+    VFIOBAR *bar = &vdev->bars[nr];
+    unsigned size = bar->size;
+    char name[64];
+    uint32_t pci_bar;
+    uint8_t type;
+    int ret;
+
+    /* Skip both unimplemented BARs and the upper half of 64bit BARS. */
+    if (!size) {
+        return;
+    }
+
+    snprintf(name, sizeof(name), "VFIO %04x:%02x:%02x.%x BAR %d",
+             vdev->host.domain, vdev->host.bus, vdev->host.slot,
+             vdev->host.function, nr);
+
+    /* Determine what type of BAR this is for registration */
+    ret = pread(vdev->fd, &pci_bar, sizeof(pci_bar),
+                vdev->config_offset + PCI_BASE_ADDRESS_0 + (4 * nr));
+    if (ret != sizeof(pci_bar)) {
+        error_report("vfio: Failed to read BAR %d (%m)", nr);
+        return;
+    }
+
+    pci_bar = le32_to_cpu(pci_bar);
+    type = pci_bar & (pci_bar & PCI_BASE_ADDRESS_SPACE_IO ?
+           ~PCI_BASE_ADDRESS_IO_MASK : ~PCI_BASE_ADDRESS_MEM_MASK);
+
+    /* A "slow" read/write mapping underlies all BARs */
+    memory_region_init_io(&bar->mem, &vfio_bar_ops, bar, name, size);
+    pci_register_bar(&vdev->pdev, nr, type, &bar->mem);
+
+    /*
+     * We can't mmap areas overlapping the MSIX vector table, so we
+     * potentially insert a direct-mapped subregion before and after it.
+     */
+    if (vdev->msix && vdev->msix->table_bar == nr) {
+        size = vdev->msix->table_offset & TARGET_PAGE_MASK;
+    }
+
+    strncat(name, " mmap", sizeof(name) - strlen(name) - 1);
+    if (vfio_mmap_bar(bar, &bar->mem,
+                      &bar->mmap_mem, &bar->mmap, size, 0, name)) {
+        error_report("%s unsupported. Performance may be slow", name);
+    }
+
+    if (vdev->msix && vdev->msix->table_bar == nr) {
+        unsigned start;
+
+        start = TARGET_PAGE_ALIGN(vdev->msix->table_offset +
+                                  (vdev->msix->entries * PCI_MSIX_ENTRY_SIZE));
+
+        size = start < bar->size ? bar->size - start : 0;
+        strncat(name, " msix-hi", sizeof(name) - strlen(name) - 1);
+        /* VFIOMSIXInfo contains another MemoryRegion for this mapping */
+        if (vfio_mmap_bar(bar, &bar->mem, &vdev->msix->mmap_mem,
+                          &vdev->msix->mmap, size, start, name)) {
+            error_report("%s unsupported. Performance may be slow", name);
+        }
+    }
+
+    vfio_bar_quirk_setup(vdev, nr);
+}
+
+static void vfio_map_bars(VFIODevice *vdev)
+{
+    int i;
+
+    for (i = 0; i < PCI_ROM_SLOT; i++) {
+        vfio_map_bar(vdev, i);
+    }
+
+    if (vdev->has_vga) {
+        memory_region_init_io(&vdev->vga.region[QEMU_PCI_VGA_MEM].mem,
+                              &vfio_vga_ops,
+                              &vdev->vga.region[QEMU_PCI_VGA_MEM],
+                              "vfio-vga-mmio@0xa0000",
+                              QEMU_PCI_VGA_MEM_SIZE);
+        memory_region_init_io(&vdev->vga.region[QEMU_PCI_VGA_IO_LO].mem,
+                              &vfio_vga_ops,
+                              &vdev->vga.region[QEMU_PCI_VGA_IO_LO],
+                              "vfio-vga-io@0x3b0",
+                              QEMU_PCI_VGA_IO_LO_SIZE);
+        memory_region_init_io(&vdev->vga.region[QEMU_PCI_VGA_IO_HI].mem,
+                              &vfio_vga_ops,
+                              &vdev->vga.region[QEMU_PCI_VGA_IO_HI],
+                              "vfio-vga-io@0x3c0",
+                              QEMU_PCI_VGA_IO_HI_SIZE);
+
+        pci_register_vga(&vdev->pdev, &vdev->vga.region[QEMU_PCI_VGA_MEM].mem,
+                         &vdev->vga.region[QEMU_PCI_VGA_IO_LO].mem,
+                         &vdev->vga.region[QEMU_PCI_VGA_IO_HI].mem);
+        vfio_vga_quirk_setup(vdev);
+    }
+}
+
+static void vfio_unmap_bars(VFIODevice *vdev)
+{
+    int i;
+
+    for (i = 0; i < PCI_ROM_SLOT; i++) {
+        vfio_unmap_bar(vdev, i);
+    }
+
+    if (vdev->has_vga) {
+        vfio_vga_quirk_teardown(vdev);
+        pci_unregister_vga(&vdev->pdev);
+        memory_region_destroy(&vdev->vga.region[QEMU_PCI_VGA_MEM].mem);
+        memory_region_destroy(&vdev->vga.region[QEMU_PCI_VGA_IO_LO].mem);
+        memory_region_destroy(&vdev->vga.region[QEMU_PCI_VGA_IO_HI].mem);
+    }
+}
+
+/*
+ * General setup
+ */
+static uint8_t vfio_std_cap_max_size(PCIDevice *pdev, uint8_t pos)
+{
+    uint8_t tmp, next = 0xff;
+
+    for (tmp = pdev->config[PCI_CAPABILITY_LIST]; tmp;
+         tmp = pdev->config[tmp + 1]) {
+        if (tmp > pos && tmp < next) {
+            next = tmp;
+        }
+    }
+
+    return next - pos;
+}
+
+static void vfio_set_word_bits(uint8_t *buf, uint16_t val, uint16_t mask)
+{
+    pci_set_word(buf, (pci_get_word(buf) & ~mask) | val);
+}
+
+static void vfio_add_emulated_word(VFIODevice *vdev, int pos,
+                                   uint16_t val, uint16_t mask)
+{
+    vfio_set_word_bits(vdev->pdev.config + pos, val, mask);
+    vfio_set_word_bits(vdev->pdev.wmask + pos, ~mask, mask);
+    vfio_set_word_bits(vdev->emulated_config_bits + pos, mask, mask);
+}
+
+static void vfio_set_long_bits(uint8_t *buf, uint32_t val, uint32_t mask)
+{
+    pci_set_long(buf, (pci_get_long(buf) & ~mask) | val);
+}
+
+static void vfio_add_emulated_long(VFIODevice *vdev, int pos,
+                                   uint32_t val, uint32_t mask)
+{
+    vfio_set_long_bits(vdev->pdev.config + pos, val, mask);
+    vfio_set_long_bits(vdev->pdev.wmask + pos, ~mask, mask);
+    vfio_set_long_bits(vdev->emulated_config_bits + pos, mask, mask);
+}
+
+static int vfio_setup_pcie_cap(VFIODevice *vdev, int pos, uint8_t size)
+{
+    uint16_t flags;
+    uint8_t type;
+
+    flags = pci_get_word(vdev->pdev.config + pos + PCI_CAP_FLAGS);
+    type = (flags & PCI_EXP_FLAGS_TYPE) >> 4;
+
+    if (type != PCI_EXP_TYPE_ENDPOINT &&
+        type != PCI_EXP_TYPE_LEG_END &&
+        type != PCI_EXP_TYPE_RC_END) {
+
+        error_report("vfio: Assignment of PCIe type 0x%x "
+                     "devices is not currently supported", type);
+        return -EINVAL;
+    }
+
+    if (!pci_bus_is_express(vdev->pdev.bus)) {
+        /*
+         * Use express capability as-is on PCI bus.  It doesn't make much
+         * sense to even expose, but some drivers (ex. tg3) depend on it
+         * and guests don't seem to be particular about it.  We'll need
+         * to revist this or force express devices to express buses if we
+         * ever expose an IOMMU to the guest.
+         */
+    } else if (pci_bus_is_root(vdev->pdev.bus)) {
+        /*
+         * On a Root Complex bus Endpoints become Root Complex Integrated
+         * Endpoints, which changes the type and clears the LNK & LNK2 fields.
+         */
+        if (type == PCI_EXP_TYPE_ENDPOINT) {
+            vfio_add_emulated_word(vdev, pos + PCI_CAP_FLAGS,
+                                   PCI_EXP_TYPE_RC_END << 4,
+                                   PCI_EXP_FLAGS_TYPE);
+
+            /* Link Capabilities, Status, and Control goes away */
+            if (size > PCI_EXP_LNKCTL) {
+                vfio_add_emulated_long(vdev, pos + PCI_EXP_LNKCAP, 0, ~0);
+                vfio_add_emulated_word(vdev, pos + PCI_EXP_LNKCTL, 0, ~0);
+                vfio_add_emulated_word(vdev, pos + PCI_EXP_LNKSTA, 0, ~0);
+
+#ifndef PCI_EXP_LNKCAP2
+#define PCI_EXP_LNKCAP2 44
+#endif
+#ifndef PCI_EXP_LNKSTA2
+#define PCI_EXP_LNKSTA2 50
+#endif
+                /* Link 2 Capabilities, Status, and Control goes away */
+                if (size > PCI_EXP_LNKCAP2) {
+                    vfio_add_emulated_long(vdev, pos + PCI_EXP_LNKCAP2, 0, ~0);
+                    vfio_add_emulated_word(vdev, pos + PCI_EXP_LNKCTL2, 0, ~0);
+                    vfio_add_emulated_word(vdev, pos + PCI_EXP_LNKSTA2, 0, ~0);
+                }
+            }
+
+        } else if (type == PCI_EXP_TYPE_LEG_END) {
+            /*
+             * Legacy endpoints don't belong on the root complex.  Windows
+             * seems to be happier with devices if we skip the capability.
+             */
+            return 0;
+        }
+
+    } else {
+        /*
+         * Convert Root Complex Integrated Endpoints to regular endpoints.
+         * These devices don't support LNK/LNK2 capabilities, so make them up.
+         */
+        if (type == PCI_EXP_TYPE_RC_END) {
+            vfio_add_emulated_word(vdev, pos + PCI_CAP_FLAGS,
+                                   PCI_EXP_TYPE_ENDPOINT << 4,
+                                   PCI_EXP_FLAGS_TYPE);
+            vfio_add_emulated_long(vdev, pos + PCI_EXP_LNKCAP,
+                                   PCI_EXP_LNK_MLW_1 | PCI_EXP_LNK_LS_25, ~0);
+            vfio_add_emulated_word(vdev, pos + PCI_EXP_LNKCTL, 0, ~0);
+        }
+
+        /* Mark the Link Status bits as emulated to allow virtual negotiation */
+        vfio_add_emulated_word(vdev, pos + PCI_EXP_LNKSTA,
+                               pci_get_word(vdev->pdev.config + pos +
+                                            PCI_EXP_LNKSTA),
+                               PCI_EXP_LNKCAP_MLW | PCI_EXP_LNKCAP_SLS);
+    }
+
+    pos = pci_add_capability(&vdev->pdev, PCI_CAP_ID_EXP, pos, size);
+    if (pos >= 0) {
+        vdev->pdev.exp.exp_cap = pos;
+    }
+
+    return pos;
+}
+
+static int vfio_add_std_cap(VFIODevice *vdev, uint8_t pos)
+{
+    PCIDevice *pdev = &vdev->pdev;
+    uint8_t cap_id, next, size;
+    int ret;
+
+    cap_id = pdev->config[pos];
+    next = pdev->config[pos + 1];
+
+    /*
+     * If it becomes important to configure capabilities to their actual
+     * size, use this as the default when it's something we don't recognize.
+     * Since QEMU doesn't actually handle many of the config accesses,
+     * exact size doesn't seem worthwhile.
+     */
+    size = vfio_std_cap_max_size(pdev, pos);
+
+    /*
+     * pci_add_capability always inserts the new capability at the head
+     * of the chain.  Therefore to end up with a chain that matches the
+     * physical device, we insert from the end by making this recursive.
+     * This is also why we pre-caclulate size above as cached config space
+     * will be changed as we unwind the stack.
+     */
+    if (next) {
+        ret = vfio_add_std_cap(vdev, next);
+        if (ret) {
+            return ret;
+        }
+    } else {
+        /* Begin the rebuild, use QEMU emulated list bits */
+        pdev->config[PCI_CAPABILITY_LIST] = 0;
+        vdev->emulated_config_bits[PCI_CAPABILITY_LIST] = 0xff;
+        vdev->emulated_config_bits[PCI_STATUS] |= PCI_STATUS_CAP_LIST;
+    }
+
+    /* Use emulated next pointer to allow dropping caps */
+    pci_set_byte(vdev->emulated_config_bits + pos + 1, 0xff);
+
+    switch (cap_id) {
+    case PCI_CAP_ID_MSI:
+        ret = vfio_setup_msi(vdev, pos);
+        break;
+    case PCI_CAP_ID_EXP:
+        ret = vfio_setup_pcie_cap(vdev, pos, size);
+        break;
+    case PCI_CAP_ID_MSIX:
+        ret = vfio_setup_msix(vdev, pos);
+        break;
+    case PCI_CAP_ID_PM:
+        vdev->pm_cap = pos;
+    default:
+        ret = pci_add_capability(pdev, cap_id, pos, size);
+        break;
+    }
+
+    if (ret < 0) {
+        error_report("vfio: %04x:%02x:%02x.%x Error adding PCI capability "
+                     "0x%x[0x%x]@0x%x: %d", vdev->host.domain,
+                     vdev->host.bus, vdev->host.slot, vdev->host.function,
+                     cap_id, size, pos, ret);
+        return ret;
+    }
+
+    return 0;
+}
+
+static int vfio_add_capabilities(VFIODevice *vdev)
+{
+    PCIDevice *pdev = &vdev->pdev;
+
+    if (!(pdev->config[PCI_STATUS] & PCI_STATUS_CAP_LIST) ||
+        !pdev->config[PCI_CAPABILITY_LIST]) {
+        return 0; /* Nothing to add */
+    }
+
+    return vfio_add_std_cap(vdev, pdev->config[PCI_CAPABILITY_LIST]);
+}
+
+static int vfio_load_rom(VFIODevice *vdev)
+{
+    uint64_t size = vdev->rom_size;
+    char name[32];
+    off_t off = 0, voff = vdev->rom_offset;
+    ssize_t bytes;
+    void *ptr;
+
+    /* If loading ROM from file, pci handles it */
+    if (vdev->pdev.romfile || !vdev->pdev.rom_bar || !size) {
+        return 0;
+    }
+
+    DPRINTF("%s(%04x:%02x:%02x.%x)\n", __func__, vdev->host.domain,
+            vdev->host.bus, vdev->host.slot, vdev->host.function);
+
+    snprintf(name, sizeof(name), "vfio[%04x:%02x:%02x.%x].rom",
+             vdev->host.domain, vdev->host.bus, vdev->host.slot,
+             vdev->host.function);
+    memory_region_init_ram(&vdev->pdev.rom, name, size);
+    ptr = memory_region_get_ram_ptr(&vdev->pdev.rom);
+    memset(ptr, 0xff, size);
+
+    while (size) {
+        bytes = pread(vdev->fd, ptr + off, size, voff + off);
+        if (bytes == 0) {
+            break; /* expect that we could get back less than the ROM BAR */
+        } else if (bytes > 0) {
+            off += bytes;
+            size -= bytes;
+        } else {
+            if (errno == EINTR || errno == EAGAIN) {
+                continue;
+            }
+            error_report("vfio: Error reading device ROM: %m");
+            memory_region_destroy(&vdev->pdev.rom);
+            return -errno;
+        }
+    }
+
+    pci_register_bar(&vdev->pdev, PCI_ROM_SLOT, 0, &vdev->pdev.rom);
+    vdev->pdev.has_rom = true;
+    return 0;
+}
+
+static int vfio_connect_container(VFIOGroup *group)
+{
+    VFIOContainer *container;
+    int ret, fd;
+
+    if (group->container) {
+        return 0;
+    }
+
+    QLIST_FOREACH(container, &container_list, next) {
+        if (!ioctl(group->fd, VFIO_GROUP_SET_CONTAINER, &container->fd)) {
+            group->container = container;
+            QLIST_INSERT_HEAD(&container->group_list, group, container_next);
+            return 0;
+        }
+    }
+
+    fd = qemu_open("/dev/vfio/vfio", O_RDWR);
+    if (fd < 0) {
+        error_report("vfio: failed to open /dev/vfio/vfio: %m");
+        return -errno;
+    }
+
+    ret = ioctl(fd, VFIO_GET_API_VERSION);
+    if (ret != VFIO_API_VERSION) {
+        error_report("vfio: supported vfio version: %d, "
+                     "reported version: %d", VFIO_API_VERSION, ret);
+        close(fd);
+        return -EINVAL;
+    }
+
+    container = g_malloc0(sizeof(*container));
+    container->fd = fd;
+
+    if (ioctl(fd, VFIO_CHECK_EXTENSION, VFIO_TYPE1_IOMMU)) {
+        ret = ioctl(group->fd, VFIO_GROUP_SET_CONTAINER, &fd);
+        if (ret) {
+            error_report("vfio: failed to set group container: %m");
+            g_free(container);
+            close(fd);
+            return -errno;
+        }
+
+        ret = ioctl(fd, VFIO_SET_IOMMU, VFIO_TYPE1_IOMMU);
+        if (ret) {
+            error_report("vfio: failed to set iommu for container: %m");
+            g_free(container);
+            close(fd);
+            return -errno;
+        }
+
+        container->iommu_data.listener = vfio_memory_listener;
+        container->iommu_data.release = vfio_listener_release;
+
+        memory_listener_register(&container->iommu_data.listener, &address_space_memory);
+    } else {
+        error_report("vfio: No available IOMMU models");
+        g_free(container);
+        close(fd);
+        return -EINVAL;
+    }
+
+    QLIST_INIT(&container->group_list);
+    QLIST_INSERT_HEAD(&container_list, container, next);
+
+    group->container = container;
+    QLIST_INSERT_HEAD(&container->group_list, group, container_next);
+
+    return 0;
+}
+
+static void vfio_disconnect_container(VFIOGroup *group)
+{
+    VFIOContainer *container = group->container;
+
+    if (ioctl(group->fd, VFIO_GROUP_UNSET_CONTAINER, &container->fd)) {
+        error_report("vfio: error disconnecting group %d from container",
+                     group->groupid);
+    }
+
+    QLIST_REMOVE(group, container_next);
+    group->container = NULL;
+
+    if (QLIST_EMPTY(&container->group_list)) {
+        if (container->iommu_data.release) {
+            container->iommu_data.release(container);
+        }
+        QLIST_REMOVE(container, next);
+        DPRINTF("vfio_disconnect_container: close container->fd\n");
+        close(container->fd);
+        g_free(container);
+    }
+}
+
+static VFIOGroup *vfio_get_group(int groupid)
+{
+    VFIOGroup *group;
+    char path[32];
+    struct vfio_group_status status = { .argsz = sizeof(status) };
+
+    QLIST_FOREACH(group, &group_list, next) {
+        if (group->groupid == groupid) {
+            return group;
+        }
+    }
+
+    group = g_malloc0(sizeof(*group));
+
+    snprintf(path, sizeof(path), "/dev/vfio/%d", groupid);
+    group->fd = qemu_open(path, O_RDWR);
+    if (group->fd < 0) {
+        error_report("vfio: error opening %s: %m", path);
+        g_free(group);
+        return NULL;
+    }
+
+    if (ioctl(group->fd, VFIO_GROUP_GET_STATUS, &status)) {
+        error_report("vfio: error getting group status: %m");
+        close(group->fd);
+        g_free(group);
+        return NULL;
+    }
+
+    if (!(status.flags & VFIO_GROUP_FLAGS_VIABLE)) {
+        error_report("vfio: error, group %d is not viable, please ensure "
+                     "all devices within the iommu_group are bound to their "
+                     "vfio bus driver.", groupid);
+        close(group->fd);
+        g_free(group);
+        return NULL;
+    }
+
+    group->groupid = groupid;
+    QLIST_INIT(&group->device_list);
+
+    if (vfio_connect_container(group)) {
+        error_report("vfio: failed to setup container for group %d", groupid);
+        close(group->fd);
+        g_free(group);
+        return NULL;
+    }
+
+    QLIST_INSERT_HEAD(&group_list, group, next);
+
+    return group;
+}
+
+static void vfio_put_group(VFIOGroup *group)
+{
+    if (!QLIST_EMPTY(&group->device_list)) {
+        return;
+    }
+
+    vfio_disconnect_container(group);
+    QLIST_REMOVE(group, next);
+    DPRINTF("vfio_put_group: close group->fd\n");
+    close(group->fd);
+    g_free(group);
+}
+
+static int vfio_get_device(VFIOGroup *group, const char *name, VFIODevice *vdev)
+{
+    struct vfio_device_info dev_info = { .argsz = sizeof(dev_info) };
+    struct vfio_region_info reg_info = { .argsz = sizeof(reg_info) };
+    int ret, i;
+
+    ret = ioctl(group->fd, VFIO_GROUP_GET_DEVICE_FD, name);
+    if (ret < 0) {
+        error_report("vfio: error getting device %s from group %d: %m",
+                     name, group->groupid);
+        error_printf("Verify all devices in group %d are bound to vfio-pci "
+                     "or pci-stub and not already in use\n", group->groupid);
+        return ret;
+    }
+
+    vdev->fd = ret;
+    vdev->group = group;
+    QLIST_INSERT_HEAD(&group->device_list, vdev, next);
+
+    /* Sanity check device */
+    ret = ioctl(vdev->fd, VFIO_DEVICE_GET_INFO, &dev_info);
+    if (ret) {
+        error_report("vfio: error getting device info: %m");
+        goto error;
+    }
+
+    DPRINTF("Device %s flags: %u, regions: %u, irgs: %u\n", name,
+            dev_info.flags, dev_info.num_regions, dev_info.num_irqs);
+
+    if (!(dev_info.flags & VFIO_DEVICE_FLAGS_PCI)) {
+        error_report("vfio: Um, this isn't a PCI device");
+        goto error;
+    }
+
+    vdev->reset_works = !!(dev_info.flags & VFIO_DEVICE_FLAGS_RESET);
+    if (!vdev->reset_works) {
+        error_report("Warning, device %s does not support reset", name);
+    }
+
+    if (dev_info.num_regions < VFIO_PCI_CONFIG_REGION_INDEX + 1) {
+        error_report("vfio: unexpected number of io regions %u",
+                     dev_info.num_regions);
+        goto error;
+    }
+
+    if (dev_info.num_irqs < VFIO_PCI_MSIX_IRQ_INDEX + 1) {
+        error_report("vfio: unexpected number of irqs %u", dev_info.num_irqs);
+        goto error;
+    }
+
+    for (i = VFIO_PCI_BAR0_REGION_INDEX; i < VFIO_PCI_ROM_REGION_INDEX; i++) {
+        reg_info.index = i;
+
+        ret = ioctl(vdev->fd, VFIO_DEVICE_GET_REGION_INFO, &reg_info);
+        if (ret) {
+            error_report("vfio: Error getting region %d info: %m", i);
+            goto error;
+        }
+
+        DPRINTF("Device %s region %d:\n", name, i);
+        DPRINTF("  size: 0x%lx, offset: 0x%lx, flags: 0x%lx\n",
+                (unsigned long)reg_info.size, (unsigned long)reg_info.offset,
+                (unsigned long)reg_info.flags);
+
+        vdev->bars[i].flags = reg_info.flags;
+        vdev->bars[i].size = reg_info.size;
+        vdev->bars[i].fd_offset = reg_info.offset;
+        vdev->bars[i].fd = vdev->fd;
+        vdev->bars[i].nr = i;
+        QLIST_INIT(&vdev->bars[i].quirks);
+    }
+
+    reg_info.index = VFIO_PCI_ROM_REGION_INDEX;
+
+    ret = ioctl(vdev->fd, VFIO_DEVICE_GET_REGION_INFO, &reg_info);
+    if (ret) {
+        error_report("vfio: Error getting ROM info: %m");
+        goto error;
+    }
+
+    DPRINTF("Device %s ROM:\n", name);
+    DPRINTF("  size: 0x%lx, offset: 0x%lx, flags: 0x%lx\n",
+            (unsigned long)reg_info.size, (unsigned long)reg_info.offset,
+            (unsigned long)reg_info.flags);
+
+    vdev->rom_size = reg_info.size;
+    vdev->rom_offset = reg_info.offset;
+
+    reg_info.index = VFIO_PCI_CONFIG_REGION_INDEX;
+
+    ret = ioctl(vdev->fd, VFIO_DEVICE_GET_REGION_INFO, &reg_info);
+    if (ret) {
+        error_report("vfio: Error getting config info: %m");
+        goto error;
+    }
+
+    DPRINTF("Device %s config:\n", name);
+    DPRINTF("  size: 0x%lx, offset: 0x%lx, flags: 0x%lx\n",
+            (unsigned long)reg_info.size, (unsigned long)reg_info.offset,
+            (unsigned long)reg_info.flags);
+
+    vdev->config_size = reg_info.size;
+    if (vdev->config_size == PCI_CONFIG_SPACE_SIZE) {
+        vdev->pdev.cap_present &= ~QEMU_PCI_CAP_EXPRESS;
+    }
+    vdev->config_offset = reg_info.offset;
+
+    if ((vdev->features & VFIO_FEATURE_ENABLE_VGA) &&
+        dev_info.num_regions > VFIO_PCI_VGA_REGION_INDEX) {
+        struct vfio_region_info vga_info = {
+            .argsz = sizeof(vga_info),
+            .index = VFIO_PCI_VGA_REGION_INDEX,
+         };
+
+        ret = ioctl(vdev->fd, VFIO_DEVICE_GET_REGION_INFO, &vga_info);
+        if (ret) {
+            error_report(
+                "vfio: Device does not support requested feature x-vga");
+            goto error;
+        }
+
+        if (!(vga_info.flags & VFIO_REGION_INFO_FLAG_READ) ||
+            !(vga_info.flags & VFIO_REGION_INFO_FLAG_WRITE) ||
+            vga_info.size < 0xbffff + 1) {
+            error_report("vfio: Unexpected VGA info, flags 0x%lx, size 0x%lx",
+                         (unsigned long)vga_info.flags,
+                         (unsigned long)vga_info.size);
+            goto error;
+        }
+
+        vdev->vga.fd_offset = vga_info.offset;
+        vdev->vga.fd = vdev->fd;
+
+        vdev->vga.region[QEMU_PCI_VGA_MEM].offset = QEMU_PCI_VGA_MEM_BASE;
+        vdev->vga.region[QEMU_PCI_VGA_MEM].nr = QEMU_PCI_VGA_MEM;
+        QLIST_INIT(&vdev->vga.region[QEMU_PCI_VGA_MEM].quirks);
+
+        vdev->vga.region[QEMU_PCI_VGA_IO_LO].offset = QEMU_PCI_VGA_IO_LO_BASE;
+        vdev->vga.region[QEMU_PCI_VGA_IO_LO].nr = QEMU_PCI_VGA_IO_LO;
+        QLIST_INIT(&vdev->vga.region[QEMU_PCI_VGA_IO_LO].quirks);
+
+        vdev->vga.region[QEMU_PCI_VGA_IO_HI].offset = QEMU_PCI_VGA_IO_HI_BASE;
+        vdev->vga.region[QEMU_PCI_VGA_IO_HI].nr = QEMU_PCI_VGA_IO_HI;
+        QLIST_INIT(&vdev->vga.region[QEMU_PCI_VGA_IO_HI].quirks);
+
+        vdev->has_vga = true;
+    }
+
+error:
+    if (ret) {
+        QLIST_REMOVE(vdev, next);
+        vdev->group = NULL;
+        close(vdev->fd);
+    }
+    return ret;
+}
+
+static void vfio_put_device(VFIODevice *vdev)
+{
+    QLIST_REMOVE(vdev, next);
+    vdev->group = NULL;
+    DPRINTF("vfio_put_device: close vdev->fd\n");
+    close(vdev->fd);
+    if (vdev->msix) {
+        g_free(vdev->msix);
+        vdev->msix = NULL;
+    }
+}
+
+static int vfio_initfn(PCIDevice *pdev)
+{
+    VFIODevice *pvdev, *vdev = DO_UPCAST(VFIODevice, pdev, pdev);
+    VFIOGroup *group;
+    char path[PATH_MAX], iommu_group_path[PATH_MAX], *group_name;
+    ssize_t len;
+    struct stat st;
+    int groupid;
+    int ret;
+
+    /* Check that the host device exists */
+    snprintf(path, sizeof(path),
+             "/sys/bus/pci/devices/%04x:%02x:%02x.%01x/",
+             vdev->host.domain, vdev->host.bus, vdev->host.slot,
+             vdev->host.function);
+    if (stat(path, &st) < 0) {
+        error_report("vfio: error: no such host device: %s", path);
+        return -errno;
+    }
+
+    strncat(path, "iommu_group", sizeof(path) - strlen(path) - 1);
+
+    len = readlink(path, iommu_group_path, PATH_MAX);
+    if (len <= 0) {
+        error_report("vfio: error no iommu_group for device");
+        return -errno;
+    }
+
+    iommu_group_path[len] = 0;
+    group_name = basename(iommu_group_path);
+
+    if (sscanf(group_name, "%d", &groupid) != 1) {
+        error_report("vfio: error reading %s: %m", path);
+        return -errno;
+    }
+
+    DPRINTF("%s(%04x:%02x:%02x.%x) group %d\n", __func__, vdev->host.domain,
+            vdev->host.bus, vdev->host.slot, vdev->host.function, groupid);
+
+    group = vfio_get_group(groupid);
+    if (!group) {
+        error_report("vfio: failed to get group %d", groupid);
+        return -ENOENT;
+    }
+
+    snprintf(path, sizeof(path), "%04x:%02x:%02x.%01x",
+            vdev->host.domain, vdev->host.bus, vdev->host.slot,
+            vdev->host.function);
+
+    QLIST_FOREACH(pvdev, &group->device_list, next) {
+        if (pvdev->host.domain == vdev->host.domain &&
+            pvdev->host.bus == vdev->host.bus &&
+            pvdev->host.slot == vdev->host.slot &&
+            pvdev->host.function == vdev->host.function) {
+
+            error_report("vfio: error: device %s is already attached", path);
+            vfio_put_group(group);
+            return -EBUSY;
+        }
+    }
+
+    ret = vfio_get_device(group, path, vdev);
+    if (ret) {
+        error_report("vfio: failed to get device %s", path);
+        vfio_put_group(group);
+        return ret;
+    }
+
+    /* Get a copy of config space */
+    ret = pread(vdev->fd, vdev->pdev.config,
+                MIN(pci_config_size(&vdev->pdev), vdev->config_size),
+                vdev->config_offset);
+    if (ret < (int)MIN(pci_config_size(&vdev->pdev), vdev->config_size)) {
+        ret = ret < 0 ? -errno : -EFAULT;
+        error_report("vfio: Failed to read device config space");
+        goto out_put;
+    }
+
+    /* vfio emulates a lot for us, but some bits need extra love */
+    vdev->emulated_config_bits = g_malloc0(vdev->config_size);
+
+    /* QEMU can choose to expose the ROM or not */
+    memset(vdev->emulated_config_bits + PCI_ROM_ADDRESS, 0xff, 4);
+
+    /* QEMU can change multi-function devices to single function, or reverse */
+    vdev->emulated_config_bits[PCI_HEADER_TYPE] =
+                                              PCI_HEADER_TYPE_MULTI_FUNCTION;
+
+    /*
+     * Clear host resource mapping info.  If we choose not to register a
+     * BAR, such as might be the case with the option ROM, we can get
+     * confusing, unwritable, residual addresses from the host here.
+     */
+    memset(&vdev->pdev.config[PCI_BASE_ADDRESS_0], 0, 24);
+    memset(&vdev->pdev.config[PCI_ROM_ADDRESS], 0, 4);
+
+    vfio_load_rom(vdev);
+
+    ret = vfio_early_setup_msix(vdev);
+    if (ret) {
+        goto out_put;
+    }
+
+    vfio_map_bars(vdev);
+
+    ret = vfio_add_capabilities(vdev);
+    if (ret) {
+        goto out_teardown;
+    }
+
+    /* QEMU emulates all of MSI & MSIX */
+    if (pdev->cap_present & QEMU_PCI_CAP_MSIX) {
+        memset(vdev->emulated_config_bits + pdev->msix_cap, 0xff,
+               MSIX_CAP_LENGTH);
+    }
+
+    if (pdev->cap_present & QEMU_PCI_CAP_MSI) {
+        memset(vdev->emulated_config_bits + pdev->msi_cap, 0xff,
+               vdev->msi_cap_size);
+    }
+
+    if (vfio_pci_read_config(&vdev->pdev, PCI_INTERRUPT_PIN, 1)) {
+        vdev->intx.mmap_timer = qemu_new_timer_ms(vm_clock,
+                                                  vfio_intx_mmap_enable, vdev);
+        pci_device_set_intx_routing_notifier(&vdev->pdev, vfio_update_irq);
+        ret = vfio_enable_intx(vdev);
+        if (ret) {
+            goto out_teardown;
+        }
+    }
+
+    add_boot_device_path(vdev->bootindex, &pdev->qdev, NULL);
+
+    return 0;
+
+out_teardown:
+    pci_device_set_intx_routing_notifier(&vdev->pdev, NULL);
+    vfio_teardown_msi(vdev);
+    vfio_unmap_bars(vdev);
+out_put:
+    g_free(vdev->emulated_config_bits);
+    vfio_put_device(vdev);
+    vfio_put_group(group);
+    return ret;
+}
+
+static void vfio_exitfn(PCIDevice *pdev)
+{
+    VFIODevice *vdev = DO_UPCAST(VFIODevice, pdev, pdev);
+    VFIOGroup *group = vdev->group;
+
+    pci_device_set_intx_routing_notifier(&vdev->pdev, NULL);
+    vfio_disable_interrupts(vdev);
+    if (vdev->intx.mmap_timer) {
+        qemu_free_timer(vdev->intx.mmap_timer);
+    }
+    vfio_teardown_msi(vdev);
+    vfio_unmap_bars(vdev);
+    g_free(vdev->emulated_config_bits);
+    vfio_put_device(vdev);
+    vfio_put_group(group);
+}
+
+static void vfio_pci_reset(DeviceState *dev)
+{
+    PCIDevice *pdev = DO_UPCAST(PCIDevice, qdev, dev);
+    VFIODevice *vdev = DO_UPCAST(VFIODevice, pdev, pdev);
+    uint16_t cmd;
+
+    DPRINTF("%s(%04x:%02x:%02x.%x)\n", __func__, vdev->host.domain,
+            vdev->host.bus, vdev->host.slot, vdev->host.function);
+
+    vfio_disable_interrupts(vdev);
+
+    /* Make sure the device is in D0 */
+    if (vdev->pm_cap) {
+        uint16_t pmcsr;
+        uint8_t state;
+
+        pmcsr = vfio_pci_read_config(pdev, vdev->pm_cap + PCI_PM_CTRL, 2);
+        state = pmcsr & PCI_PM_CTRL_STATE_MASK;
+        if (state) {
+            pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
+            vfio_pci_write_config(pdev, vdev->pm_cap + PCI_PM_CTRL, pmcsr, 2);
+            /* vfio handles the necessary delay here */
+            pmcsr = vfio_pci_read_config(pdev, vdev->pm_cap + PCI_PM_CTRL, 2);
+            state = pmcsr & PCI_PM_CTRL_STATE_MASK;
+            if (state) {
+                error_report("vfio: Unable to power on device, stuck in D%d\n",
+                             state);
+            }
+        }
+    }
+
+    /*
+     * Stop any ongoing DMA by disconecting I/O, MMIO, and bus master.
+     * Also put INTx Disable in known state.
+     */
+    cmd = vfio_pci_read_config(pdev, PCI_COMMAND, 2);
+    cmd &= ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
+             PCI_COMMAND_INTX_DISABLE);
+    vfio_pci_write_config(pdev, PCI_COMMAND, cmd, 2);
+
+    if (vdev->reset_works) {
+        if (ioctl(vdev->fd, VFIO_DEVICE_RESET)) {
+            error_report("vfio: Error unable to reset physical device "
+                         "(%04x:%02x:%02x.%x): %m", vdev->host.domain,
+                         vdev->host.bus, vdev->host.slot, vdev->host.function);
+        }
+    }
+
+    vfio_enable_intx(vdev);
+}
+
+static Property vfio_pci_dev_properties[] = {
+    DEFINE_PROP_PCI_HOST_DEVADDR("host", VFIODevice, host),
+    DEFINE_PROP_UINT32("x-intx-mmap-timeout-ms", VFIODevice,
+                       intx.mmap_timeout, 1100),
+    DEFINE_PROP_BIT("x-vga", VFIODevice, features,
+                    VFIO_FEATURE_ENABLE_VGA_BIT, false),
+    DEFINE_PROP_INT32("bootindex", VFIODevice, bootindex, -1),
+    /*
+     * TODO - support passed fds... is this necessary?
+     * DEFINE_PROP_STRING("vfiofd", VFIODevice, vfiofd_name),
+     * DEFINE_PROP_STRING("vfiogroupfd, VFIODevice, vfiogroupfd_name),
+     */
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static const VMStateDescription vfio_pci_vmstate = {
+    .name = "vfio-pci",
+    .unmigratable = 1,
+};
+
+static void vfio_pci_dev_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *pdc = PCI_DEVICE_CLASS(klass);
+
+    dc->reset = vfio_pci_reset;
+    dc->props = vfio_pci_dev_properties;
+    dc->vmsd = &vfio_pci_vmstate;
+    dc->desc = "VFIO-based PCI device assignment";
+    pdc->init = vfio_initfn;
+    pdc->exit = vfio_exitfn;
+    pdc->config_read = vfio_pci_read_config;
+    pdc->config_write = vfio_pci_write_config;
+    pdc->is_express = 1; /* We might be */
+}
+
+static const TypeInfo vfio_pci_dev_info = {
+    .name = "vfio-pci",
+    .parent = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(VFIODevice),
+    .class_init = vfio_pci_dev_class_init,
+};
+
+static void register_vfio_pci_dev_type(void)
+{
+    type_register_static(&vfio_pci_dev_info);
+}
+
+type_init(register_vfio_pci_dev_type)
diff --git a/hw/misc/vmport.c b/hw/misc/vmport.c
new file mode 100644 (file)
index 0000000..0d07ea1
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * QEMU VMPort emulation
+ *
+ * Copyright (C) 2007 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 "hw/hw.h"
+#include "hw/isa/isa.h"
+#include "hw/i386/pc.h"
+#include "sysemu/kvm.h"
+#include "hw/qdev.h"
+
+//#define VMPORT_DEBUG
+
+#define VMPORT_CMD_GETVERSION 0x0a
+#define VMPORT_CMD_GETRAMSIZE 0x14
+
+#define VMPORT_ENTRIES 0x2c
+#define VMPORT_MAGIC   0x564D5868
+
+typedef struct _VMPortState
+{
+    ISADevice dev;
+    MemoryRegion io;
+    IOPortReadFunc *func[VMPORT_ENTRIES];
+    void *opaque[VMPORT_ENTRIES];
+} VMPortState;
+
+static VMPortState *port_state;
+
+void vmport_register(unsigned char command, IOPortReadFunc *func, void *opaque)
+{
+    if (command >= VMPORT_ENTRIES)
+        return;
+
+    port_state->func[command] = func;
+    port_state->opaque[command] = opaque;
+}
+
+static uint64_t vmport_ioport_read(void *opaque, hwaddr addr,
+                                   unsigned size)
+{
+    VMPortState *s = opaque;
+    CPUX86State *env = cpu_single_env;
+    unsigned char command;
+    uint32_t eax;
+
+    cpu_synchronize_state(env);
+
+    eax = env->regs[R_EAX];
+    if (eax != VMPORT_MAGIC)
+        return eax;
+
+    command = env->regs[R_ECX];
+    if (command >= VMPORT_ENTRIES)
+        return eax;
+    if (!s->func[command])
+    {
+#ifdef VMPORT_DEBUG
+        fprintf(stderr, "vmport: unknown command %x\n", command);
+#endif
+        return eax;
+    }
+
+    return s->func[command](s->opaque[command], addr);
+}
+
+static void vmport_ioport_write(void *opaque, hwaddr addr,
+                                uint64_t val, unsigned size)
+{
+    CPUX86State *env = cpu_single_env;
+
+    env->regs[R_EAX] = vmport_ioport_read(opaque, addr, 4);
+}
+
+static uint32_t vmport_cmd_get_version(void *opaque, uint32_t addr)
+{
+    CPUX86State *env = cpu_single_env;
+    env->regs[R_EBX] = VMPORT_MAGIC;
+    return 6;
+}
+
+static uint32_t vmport_cmd_ram_size(void *opaque, uint32_t addr)
+{
+    CPUX86State *env = cpu_single_env;
+    env->regs[R_EBX] = 0x1177;
+    return ram_size;
+}
+
+/* vmmouse helpers */
+void vmmouse_get_data(uint32_t *data)
+{
+    CPUX86State *env = cpu_single_env;
+
+    data[0] = env->regs[R_EAX]; data[1] = env->regs[R_EBX];
+    data[2] = env->regs[R_ECX]; data[3] = env->regs[R_EDX];
+    data[4] = env->regs[R_ESI]; data[5] = env->regs[R_EDI];
+}
+
+void vmmouse_set_data(const uint32_t *data)
+{
+    CPUX86State *env = cpu_single_env;
+
+    env->regs[R_EAX] = data[0]; env->regs[R_EBX] = data[1];
+    env->regs[R_ECX] = data[2]; env->regs[R_EDX] = data[3];
+    env->regs[R_ESI] = data[4]; env->regs[R_EDI] = data[5];
+}
+
+static const MemoryRegionOps vmport_ops = {
+    .read = vmport_ioport_read,
+    .write = vmport_ioport_write,
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static int vmport_initfn(ISADevice *dev)
+{
+    VMPortState *s = DO_UPCAST(VMPortState, dev, dev);
+
+    memory_region_init_io(&s->io, &vmport_ops, s, "vmport", 1);
+    isa_register_ioport(dev, &s->io, 0x5658);
+
+    port_state = s;
+    /* Register some generic port commands */
+    vmport_register(VMPORT_CMD_GETVERSION, vmport_cmd_get_version, NULL);
+    vmport_register(VMPORT_CMD_GETRAMSIZE, vmport_cmd_ram_size, NULL);
+    return 0;
+}
+
+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 const TypeInfo vmport_info = {
+    .name          = "vmport",
+    .parent        = TYPE_ISA_DEVICE,
+    .instance_size = sizeof(VMPortState),
+    .class_init    = vmport_class_initfn,
+};
+
+static void vmport_register_types(void)
+{
+    type_register_static(&vmport_info);
+}
+
+type_init(vmport_register_types)
diff --git a/hw/misc/zynq_slcr.c b/hw/misc/zynq_slcr.c
new file mode 100644 (file)
index 0000000..8418327
--- /dev/null
@@ -0,0 +1,536 @@
+/*
+ * Status and system control registers for Xilinx Zynq Platform
+ *
+ * Copyright (c) 2011 Michal Simek <monstr@monstr.eu>
+ * Copyright (c) 2012 PetaLogix Pty Ltd.
+ * Based on hw/arm_sysctl.c, written by Paul Brook
+ *
+ * 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.
+ *
+ * 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 "hw/hw.h"
+#include "qemu/timer.h"
+#include "hw/sysbus.h"
+#include "sysemu/sysemu.h"
+
+#ifdef ZYNQ_ARM_SLCR_ERR_DEBUG
+#define DB_PRINT(...) do { \
+    fprintf(stderr,  ": %s: ", __func__); \
+    fprintf(stderr, ## __VA_ARGS__); \
+    } while (0);
+#else
+    #define DB_PRINT(...)
+#endif
+
+#define XILINX_LOCK_KEY 0x767b
+#define XILINX_UNLOCK_KEY 0xdf0d
+
+typedef enum {
+  ARM_PLL_CTRL,
+  DDR_PLL_CTRL,
+  IO_PLL_CTRL,
+  PLL_STATUS,
+  ARM_PPL_CFG,
+  DDR_PLL_CFG,
+  IO_PLL_CFG,
+  PLL_BG_CTRL,
+  PLL_MAX
+} PLLValues;
+
+typedef enum {
+  ARM_CLK_CTRL,
+  DDR_CLK_CTRL,
+  DCI_CLK_CTRL,
+  APER_CLK_CTRL,
+  USB0_CLK_CTRL,
+  USB1_CLK_CTRL,
+  GEM0_RCLK_CTRL,
+  GEM1_RCLK_CTRL,
+  GEM0_CLK_CTRL,
+  GEM1_CLK_CTRL,
+  SMC_CLK_CTRL,
+  LQSPI_CLK_CTRL,
+  SDIO_CLK_CTRL,
+  UART_CLK_CTRL,
+  SPI_CLK_CTRL,
+  CAN_CLK_CTRL,
+  CAN_MIOCLK_CTRL,
+  DBG_CLK_CTRL,
+  PCAP_CLK_CTRL,
+  TOPSW_CLK_CTRL,
+  CLK_MAX
+} ClkValues;
+
+typedef enum {
+  CLK_CTRL,
+  THR_CTRL,
+  THR_CNT,
+  THR_STA,
+  FPGA_MAX
+} FPGAValues;
+
+typedef enum {
+  SYNC_CTRL,
+  SYNC_STATUS,
+  BANDGAP_TRIP,
+  CC_TEST,
+  PLL_PREDIVISOR,
+  CLK_621_TRUE,
+  PICTURE_DBG,
+  PICTURE_DBG_UCNT,
+  PICTURE_DBG_LCNT,
+  MISC_MAX
+} MiscValues;
+
+typedef enum {
+  PSS,
+  DDDR,
+  DMAC = 3,
+  USB,
+  GEM,
+  SDIO,
+  SPI,
+  CAN,
+  I2C,
+  UART,
+  GPIO,
+  LQSPI,
+  SMC,
+  OCM,
+  DEVCI,
+  FPGA,
+  A9_CPU,
+  RS_AWDT,
+  RST_REASON,
+  RST_REASON_CLR,
+  REBOOT_STATUS,
+  BOOT_MODE,
+  RESET_MAX
+} ResetValues;
+
+typedef struct {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+
+    union {
+        struct {
+            uint16_t scl;
+            uint16_t lockval;
+            uint32_t pll[PLL_MAX]; /* 0x100 - 0x11C */
+            uint32_t clk[CLK_MAX]; /* 0x120 - 0x16C */
+            uint32_t fpga[4][FPGA_MAX]; /* 0x170 - 0x1AC */
+            uint32_t misc[MISC_MAX]; /* 0x1B0 - 0x1D8 */
+            uint32_t reset[RESET_MAX]; /* 0x200 - 0x25C */
+            uint32_t apu_ctrl; /* 0x300 */
+            uint32_t wdt_clk_sel; /* 0x304 */
+            uint32_t tz_ocm[3]; /* 0x400 - 0x408 */
+            uint32_t tz_ddr; /* 0x430 */
+            uint32_t tz_dma[3]; /* 0x440 - 0x448 */
+            uint32_t tz_misc[3]; /* 0x450 - 0x458 */
+            uint32_t tz_fpga[2]; /* 0x484 - 0x488 */
+            uint32_t dbg_ctrl; /* 0x500 */
+            uint32_t pss_idcode; /* 0x530 */
+            uint32_t ddr[8]; /* 0x600 - 0x620 - 0x604-missing */
+            uint32_t mio[54]; /* 0x700 - 0x7D4 */
+            uint32_t mio_func[4]; /* 0x800 - 0x810 */
+            uint32_t sd[2]; /* 0x830 - 0x834 */
+            uint32_t lvl_shftr_en; /* 0x900 */
+            uint32_t ocm_cfg; /* 0x910 */
+            uint32_t cpu_ram[8]; /* 0xA00 - 0xA1C */
+            uint32_t iou[7]; /* 0xA30 - 0xA48 */
+            uint32_t dmac_ram; /* 0xA50 */
+            uint32_t afi[4][3]; /* 0xA60 - 0xA8C */
+            uint32_t ocm[3]; /* 0xA90 - 0xA98 */
+            uint32_t devci_ram; /* 0xAA0 */
+            uint32_t csg_ram; /* 0xAB0 */
+            uint32_t gpiob[12]; /* 0xB00 - 0xB2C */
+            uint32_t ddriob[14]; /* 0xB40 - 0xB74 */
+        };
+        uint8_t data[0x1000];
+    };
+} ZynqSLCRState;
+
+static void zynq_slcr_reset(DeviceState *d)
+{
+    int i;
+    ZynqSLCRState *s =
+            FROM_SYSBUS(ZynqSLCRState, SYS_BUS_DEVICE(d));
+
+    DB_PRINT("RESET\n");
+
+    s->lockval = 1;
+    /* 0x100 - 0x11C */
+    s->pll[ARM_PLL_CTRL] = 0x0001A008;
+    s->pll[DDR_PLL_CTRL] = 0x0001A008;
+    s->pll[IO_PLL_CTRL] = 0x0001A008;
+    s->pll[PLL_STATUS] = 0x0000003F;
+    s->pll[ARM_PPL_CFG] = 0x00014000;
+    s->pll[DDR_PLL_CFG] = 0x00014000;
+    s->pll[IO_PLL_CFG] = 0x00014000;
+
+    /* 0x120 - 0x16C */
+    s->clk[ARM_CLK_CTRL] = 0x1F000400;
+    s->clk[DDR_CLK_CTRL] = 0x18400003;
+    s->clk[DCI_CLK_CTRL] = 0x01E03201;
+    s->clk[APER_CLK_CTRL] = 0x01FFCCCD;
+    s->clk[USB0_CLK_CTRL] = s->clk[USB1_CLK_CTRL] = 0x00101941;
+    s->clk[GEM0_RCLK_CTRL] = s->clk[GEM1_RCLK_CTRL] = 0x00000001;
+    s->clk[GEM0_CLK_CTRL] = s->clk[GEM1_CLK_CTRL] = 0x00003C01;
+    s->clk[SMC_CLK_CTRL] = 0x00003C01;
+    s->clk[LQSPI_CLK_CTRL] = 0x00002821;
+    s->clk[SDIO_CLK_CTRL] = 0x00001E03;
+    s->clk[UART_CLK_CTRL] = 0x00003F03;
+    s->clk[SPI_CLK_CTRL] = 0x00003F03;
+    s->clk[CAN_CLK_CTRL] = 0x00501903;
+    s->clk[DBG_CLK_CTRL] = 0x00000F03;
+    s->clk[PCAP_CLK_CTRL] = 0x00000F01;
+
+    /* 0x170 - 0x1AC */
+    s->fpga[0][CLK_CTRL] = s->fpga[1][CLK_CTRL] = s->fpga[2][CLK_CTRL] =
+            s->fpga[3][CLK_CTRL] = 0x00101800;
+    s->fpga[0][THR_STA] = s->fpga[1][THR_STA] = s->fpga[2][THR_STA] =
+            s->fpga[3][THR_STA] = 0x00010000;
+
+    /* 0x1B0 - 0x1D8 */
+    s->misc[BANDGAP_TRIP] = 0x0000001F;
+    s->misc[PLL_PREDIVISOR] = 0x00000001;
+    s->misc[CLK_621_TRUE] = 0x00000001;
+
+    /* 0x200 - 0x25C */
+    s->reset[FPGA] = 0x01F33F0F;
+    s->reset[RST_REASON] = 0x00000040;
+
+    /* 0x700 - 0x7D4 */
+    for (i = 0; i < 54; i++) {
+        s->mio[i] = 0x00001601;
+    }
+    for (i = 2; i <= 8; i++) {
+        s->mio[i] = 0x00000601;
+    }
+
+    /* MIO_MST_TRI0, MIO_MST_TRI1 */
+    s->mio_func[2] = s->mio_func[3] = 0xFFFFFFFF;
+
+    s->cpu_ram[0] = s->cpu_ram[1] = s->cpu_ram[3] =
+            s->cpu_ram[4] = s->cpu_ram[7] = 0x00010101;
+    s->cpu_ram[2] = s->cpu_ram[5] = 0x01010101;
+    s->cpu_ram[6] = 0x00000001;
+
+    s->iou[0] = s->iou[1] = s->iou[2] = s->iou[3] = 0x09090909;
+    s->iou[4] = s->iou[5] = 0x00090909;
+    s->iou[6] = 0x00000909;
+
+    s->dmac_ram = 0x00000009;
+
+    s->afi[0][0] = s->afi[0][1] = 0x09090909;
+    s->afi[1][0] = s->afi[1][1] = 0x09090909;
+    s->afi[2][0] = s->afi[2][1] = 0x09090909;
+    s->afi[3][0] = s->afi[3][1] = 0x09090909;
+    s->afi[0][2] = s->afi[1][2] = s->afi[2][2] = s->afi[3][2] = 0x00000909;
+
+    s->ocm[0] = 0x01010101;
+    s->ocm[1] = s->ocm[2] = 0x09090909;
+
+    s->devci_ram = 0x00000909;
+    s->csg_ram = 0x00000001;
+
+    s->ddriob[0] = s->ddriob[1] = s->ddriob[2] = s->ddriob[3] = 0x00000e00;
+    s->ddriob[4] = s->ddriob[5] = s->ddriob[6] = 0x00000e00;
+    s->ddriob[12] = 0x00000021;
+}
+
+static inline uint32_t zynq_slcr_read_imp(void *opaque,
+    hwaddr offset)
+{
+    ZynqSLCRState *s = (ZynqSLCRState *)opaque;
+
+    switch (offset) {
+    case 0x0: /* SCL */
+        return s->scl;
+    case 0x4: /* LOCK */
+    case 0x8: /* UNLOCK */
+        DB_PRINT("Reading SCLR_LOCK/UNLOCK is not enabled\n");
+        return 0;
+    case 0x0C: /* LOCKSTA */
+        return s->lockval;
+    case 0x100 ... 0x11C:
+        return s->pll[(offset - 0x100) / 4];
+    case 0x120 ... 0x16C:
+        return s->clk[(offset - 0x120) / 4];
+    case 0x170 ... 0x1AC:
+        return s->fpga[0][(offset - 0x170) / 4];
+    case 0x1B0 ... 0x1D8:
+        return s->misc[(offset - 0x1B0) / 4];
+    case 0x200 ... 0x258:
+        return s->reset[(offset - 0x200) / 4];
+    case 0x25c:
+        return 1;
+    case 0x300:
+        return s->apu_ctrl;
+    case 0x304:
+        return s->wdt_clk_sel;
+    case 0x400 ... 0x408:
+        return s->tz_ocm[(offset - 0x400) / 4];
+    case 0x430:
+        return s->tz_ddr;
+    case 0x440 ... 0x448:
+        return s->tz_dma[(offset - 0x440) / 4];
+    case 0x450 ... 0x458:
+        return s->tz_misc[(offset - 0x450) / 4];
+    case 0x484 ... 0x488:
+        return s->tz_fpga[(offset - 0x484) / 4];
+    case 0x500:
+        return s->dbg_ctrl;
+    case 0x530:
+        return s->pss_idcode;
+    case 0x600 ... 0x620:
+        if (offset == 0x604) {
+            goto bad_reg;
+        }
+        return s->ddr[(offset - 0x600) / 4];
+    case 0x700 ... 0x7D4:
+        return s->mio[(offset - 0x700) / 4];
+    case 0x800 ... 0x810:
+        return s->mio_func[(offset - 0x800) / 4];
+    case 0x830 ... 0x834:
+        return s->sd[(offset - 0x830) / 4];
+    case 0x900:
+        return s->lvl_shftr_en;
+    case 0x910:
+        return s->ocm_cfg;
+    case 0xA00 ... 0xA1C:
+        return s->cpu_ram[(offset - 0xA00) / 4];
+    case 0xA30 ... 0xA48:
+        return s->iou[(offset - 0xA30) / 4];
+    case 0xA50:
+        return s->dmac_ram;
+    case 0xA60 ... 0xA8C:
+        return s->afi[0][(offset - 0xA60) / 4];
+    case 0xA90 ... 0xA98:
+        return s->ocm[(offset - 0xA90) / 4];
+    case 0xAA0:
+        return s->devci_ram;
+    case 0xAB0:
+        return s->csg_ram;
+    case 0xB00 ... 0xB2C:
+        return s->gpiob[(offset - 0xB00) / 4];
+    case 0xB40 ... 0xB74:
+        return s->ddriob[(offset - 0xB40) / 4];
+    default:
+    bad_reg:
+        DB_PRINT("Bad register offset 0x%x\n", (int)offset);
+        return 0;
+    }
+}
+
+static uint64_t zynq_slcr_read(void *opaque, hwaddr offset,
+    unsigned size)
+{
+    uint32_t ret = zynq_slcr_read_imp(opaque, offset);
+
+    DB_PRINT("addr: %08x data: %08x\n", (unsigned)offset, (unsigned)ret);
+    return ret;
+}
+
+static void zynq_slcr_write(void *opaque, hwaddr offset,
+                          uint64_t val, unsigned size)
+{
+    ZynqSLCRState *s = (ZynqSLCRState *)opaque;
+
+    DB_PRINT("offset: %08x data: %08x\n", (unsigned)offset, (unsigned)val);
+
+    switch (offset) {
+    case 0x00: /* SCL */
+        s->scl = val & 0x1;
+    return;
+    case 0x4: /* SLCR_LOCK */
+        if ((val & 0xFFFF) == XILINX_LOCK_KEY) {
+            DB_PRINT("XILINX LOCK 0xF8000000 + 0x%x <= 0x%x\n", (int)offset,
+                (unsigned)val & 0xFFFF);
+            s->lockval = 1;
+        } else {
+            DB_PRINT("WRONG XILINX LOCK KEY 0xF8000000 + 0x%x <= 0x%x\n",
+                (int)offset, (unsigned)val & 0xFFFF);
+        }
+        return;
+    case 0x8: /* SLCR_UNLOCK */
+        if ((val & 0xFFFF) == XILINX_UNLOCK_KEY) {
+            DB_PRINT("XILINX UNLOCK 0xF8000000 + 0x%x <= 0x%x\n", (int)offset,
+                (unsigned)val & 0xFFFF);
+            s->lockval = 0;
+        } else {
+            DB_PRINT("WRONG XILINX UNLOCK KEY 0xF8000000 + 0x%x <= 0x%x\n",
+                (int)offset, (unsigned)val & 0xFFFF);
+        }
+        return;
+    case 0xc: /* LOCKSTA */
+        DB_PRINT("Writing SCLR_LOCKSTA is not enabled\n");
+        return;
+    }
+
+    if (!s->lockval) {
+        switch (offset) {
+        case 0x100 ... 0x11C:
+            if (offset == 0x10C) {
+                goto bad_reg;
+            }
+            s->pll[(offset - 0x100) / 4] = val;
+            break;
+        case 0x120 ... 0x16C:
+            s->clk[(offset - 0x120) / 4] = val;
+            break;
+        case 0x170 ... 0x1AC:
+            s->fpga[0][(offset - 0x170) / 4] = val;
+            break;
+        case 0x1B0 ... 0x1D8:
+            s->misc[(offset - 0x1B0) / 4] = val;
+            break;
+        case 0x200 ... 0x25C:
+            if (offset == 0x250) {
+                goto bad_reg;
+            }
+            s->reset[(offset - 0x200) / 4] = val;
+            break;
+        case 0x300:
+            s->apu_ctrl = val;
+            break;
+        case 0x304:
+            s->wdt_clk_sel = val;
+            break;
+        case 0x400 ... 0x408:
+            s->tz_ocm[(offset - 0x400) / 4] = val;
+            break;
+        case 0x430:
+            s->tz_ddr = val;
+            break;
+        case 0x440 ... 0x448:
+            s->tz_dma[(offset - 0x440) / 4] = val;
+            break;
+        case 0x450 ... 0x458:
+            s->tz_misc[(offset - 0x450) / 4] = val;
+            break;
+        case 0x484 ... 0x488:
+            s->tz_fpga[(offset - 0x484) / 4] = val;
+            break;
+        case 0x500:
+            s->dbg_ctrl = val;
+            break;
+        case 0x530:
+            s->pss_idcode = val;
+            break;
+        case 0x600 ... 0x620:
+            if (offset == 0x604) {
+                goto bad_reg;
+            }
+            s->ddr[(offset - 0x600) / 4] = val;
+            break;
+        case 0x700 ... 0x7D4:
+            s->mio[(offset - 0x700) / 4] = val;
+            break;
+        case 0x800 ... 0x810:
+            s->mio_func[(offset - 0x800) / 4] = val;
+            break;
+        case 0x830 ... 0x834:
+            s->sd[(offset - 0x830) / 4] = val;
+            break;
+        case 0x900:
+            s->lvl_shftr_en = val;
+            break;
+        case 0x910:
+            break;
+        case 0xA00 ... 0xA1C:
+            s->cpu_ram[(offset - 0xA00) / 4] = val;
+            break;
+        case 0xA30 ... 0xA48:
+            s->iou[(offset - 0xA30) / 4] = val;
+            break;
+        case 0xA50:
+            s->dmac_ram = val;
+            break;
+        case 0xA60 ... 0xA8C:
+            s->afi[0][(offset - 0xA60) / 4] = val;
+            break;
+        case 0xA90:
+            s->ocm[0] = val;
+            break;
+        case 0xAA0:
+            s->devci_ram = val;
+            break;
+        case 0xAB0:
+            s->csg_ram = val;
+            break;
+        case 0xB00 ... 0xB2C:
+            if (offset == 0xB20 || offset == 0xB2C) {
+                goto bad_reg;
+            }
+            s->gpiob[(offset - 0xB00) / 4] = val;
+            break;
+        case 0xB40 ... 0xB74:
+            s->ddriob[(offset - 0xB40) / 4] = val;
+            break;
+        default:
+        bad_reg:
+            DB_PRINT("Bad register write %x <= %08x\n", (int)offset,
+                     (unsigned)val);
+        }
+    } else {
+        DB_PRINT("SCLR registers are locked. Unlock them first\n");
+    }
+}
+
+static const MemoryRegionOps slcr_ops = {
+    .read = zynq_slcr_read,
+    .write = zynq_slcr_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int zynq_slcr_init(SysBusDevice *dev)
+{
+    ZynqSLCRState *s = FROM_SYSBUS(ZynqSLCRState, dev);
+
+    memory_region_init_io(&s->iomem, &slcr_ops, s, "slcr", 0x1000);
+    sysbus_init_mmio(dev, &s->iomem);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_zynq_slcr = {
+    .name = "zynq_slcr",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT8_ARRAY(data, ZynqSLCRState, 0x1000),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void zynq_slcr_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sdc->init = zynq_slcr_init;
+    dc->vmsd = &vmstate_zynq_slcr;
+    dc->reset = zynq_slcr_reset;
+}
+
+static const TypeInfo zynq_slcr_info = {
+    .class_init = zynq_slcr_class_init,
+    .name  = "xilinx,zynq_slcr",
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size  = sizeof(ZynqSLCRState),
+};
+
+static void zynq_slcr_register_types(void)
+{
+    type_register_static(&zynq_slcr_info);
+}
+
+type_init(zynq_slcr_register_types)
index a5f1742936323055afd1b587ea4d9b05bbd34f62..bfc90012fd08e20ea3f446585ed00e3a2c2c87eb 100644 (file)
@@ -1,5 +1,2 @@
 # moxie boards
-obj-y = serial.o mc146818rtc.o vga.o
-
-obj-y := $(addprefix ../,$(obj-y))
 obj-y += moxiesim.o
index e1e88a9c30728e7c571a894fa9f2cefdfce31560..70bf28f2fd4d747485938d6d45bf8b429af974ad 100644 (file)
  */
 #include "hw/sysbus.h"
 #include "hw/hw.h"
-#include "hw/pc.h"
-#include "hw/isa.h"
+#include "hw/i386/pc.h"
+#include "hw/isa/isa.h"
 #include "net/net.h"
 #include "sysemu/sysemu.h"
 #include "hw/boards.h"
 #include "hw/loader.h"
-#include "hw/serial.h"
+#include "hw/char/serial.h"
 #include "exec/address-spaces.h"
 
 #define PHYS_MEM_BASE 0x80000000
diff --git a/hw/mst_fpga.c b/hw/mst_fpga.c
deleted file mode 100644 (file)
index 1dd1505..0000000
+++ /dev/null
@@ -1,263 +0,0 @@
-/*
- * PXA270-based Intel Mainstone platforms.
- * FPGA driver
- *
- * Copyright (c) 2007 by Armin Kuster <akuster@kama-aina.net> or
- *                                    <akuster@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/hw.h"
-#include "hw/sysbus.h"
-
-/* Mainstone FPGA for extern irqs */
-#define FPGA_GPIO_PIN  0
-#define MST_NUM_IRQS   16
-#define MST_LEDDAT1            0x10
-#define MST_LEDDAT2            0x14
-#define MST_LEDCTRL            0x40
-#define MST_GPSWR              0x60
-#define MST_MSCWR1             0x80
-#define MST_MSCWR2             0x84
-#define MST_MSCWR3             0x88
-#define MST_MSCRD              0x90
-#define MST_INTMSKENA  0xc0
-#define MST_INTSETCLR  0xd0
-#define MST_PCMCIA0            0xe0
-#define MST_PCMCIA1            0xe4
-
-#define MST_PCMCIAx_READY      (1 << 10)
-#define MST_PCMCIAx_nCD                (1 << 5)
-
-#define MST_PCMCIA_CD0_IRQ     9
-#define MST_PCMCIA_CD1_IRQ     13
-
-typedef struct mst_irq_state{
-       SysBusDevice busdev;
-       MemoryRegion iomem;
-
-       qemu_irq parent;
-
-       uint32_t prev_level;
-       uint32_t leddat1;
-       uint32_t leddat2;
-       uint32_t ledctrl;
-       uint32_t gpswr;
-       uint32_t mscwr1;
-       uint32_t mscwr2;
-       uint32_t mscwr3;
-       uint32_t mscrd;
-       uint32_t intmskena;
-       uint32_t intsetclr;
-       uint32_t pcmcia0;
-       uint32_t pcmcia1;
-}mst_irq_state;
-
-static void
-mst_fpga_set_irq(void *opaque, int irq, int level)
-{
-       mst_irq_state *s = (mst_irq_state *)opaque;
-       uint32_t oldint = s->intsetclr & s->intmskena;
-
-       if (level)
-               s->prev_level |= 1u << irq;
-       else
-               s->prev_level &= ~(1u << irq);
-
-       switch(irq) {
-       case MST_PCMCIA_CD0_IRQ:
-               if (level)
-                       s->pcmcia0 &= ~MST_PCMCIAx_nCD;
-               else
-                       s->pcmcia0 |=  MST_PCMCIAx_nCD;
-               break;
-       case MST_PCMCIA_CD1_IRQ:
-               if (level)
-                       s->pcmcia1 &= ~MST_PCMCIAx_nCD;
-               else
-                       s->pcmcia1 |=  MST_PCMCIAx_nCD;
-               break;
-       }
-
-       if ((s->intmskena & (1u << irq)) && level)
-               s->intsetclr |= 1u << irq;
-
-       if (oldint != (s->intsetclr & s->intmskena))
-               qemu_set_irq(s->parent, s->intsetclr & s->intmskena);
-}
-
-
-static uint64_t
-mst_fpga_readb(void *opaque, hwaddr addr, unsigned size)
-{
-       mst_irq_state *s = (mst_irq_state *) opaque;
-
-       switch (addr) {
-       case MST_LEDDAT1:
-               return s->leddat1;
-       case MST_LEDDAT2:
-               return s->leddat2;
-       case MST_LEDCTRL:
-               return s->ledctrl;
-       case MST_GPSWR:
-               return s->gpswr;
-       case MST_MSCWR1:
-               return s->mscwr1;
-       case MST_MSCWR2:
-               return s->mscwr2;
-       case MST_MSCWR3:
-               return s->mscwr3;
-       case MST_MSCRD:
-               return s->mscrd;
-       case MST_INTMSKENA:
-               return s->intmskena;
-       case MST_INTSETCLR:
-               return s->intsetclr;
-       case MST_PCMCIA0:
-               return s->pcmcia0;
-       case MST_PCMCIA1:
-               return s->pcmcia1;
-       default:
-               printf("Mainstone - mst_fpga_readb: Bad register offset "
-                       "0x" TARGET_FMT_plx "\n", addr);
-       }
-       return 0;
-}
-
-static void
-mst_fpga_writeb(void *opaque, hwaddr addr, uint64_t value,
-               unsigned size)
-{
-       mst_irq_state *s = (mst_irq_state *) opaque;
-       value &= 0xffffffff;
-
-       switch (addr) {
-       case MST_LEDDAT1:
-               s->leddat1 = value;
-               break;
-       case MST_LEDDAT2:
-               s->leddat2 = value;
-               break;
-       case MST_LEDCTRL:
-               s->ledctrl = value;
-               break;
-       case MST_GPSWR:
-               s->gpswr = value;
-               break;
-       case MST_MSCWR1:
-               s->mscwr1 = value;
-               break;
-       case MST_MSCWR2:
-               s->mscwr2 = value;
-               break;
-       case MST_MSCWR3:
-               s->mscwr3 = value;
-               break;
-       case MST_MSCRD:
-               s->mscrd =  value;
-               break;
-       case MST_INTMSKENA:     /* Mask interrupt */
-               s->intmskena = (value & 0xFEEFF);
-               qemu_set_irq(s->parent, s->intsetclr & s->intmskena);
-               break;
-       case MST_INTSETCLR:     /* clear or set interrupt */
-               s->intsetclr = (value & 0xFEEFF);
-               qemu_set_irq(s->parent, s->intsetclr & s->intmskena);
-               break;
-               /* For PCMCIAx allow the to change only power and reset */
-       case MST_PCMCIA0:
-               s->pcmcia0 = (value & 0x1f) | (s->pcmcia0 & ~0x1f);
-               break;
-       case MST_PCMCIA1:
-               s->pcmcia1 = (value & 0x1f) | (s->pcmcia1 & ~0x1f);
-               break;
-       default:
-               printf("Mainstone - mst_fpga_writeb: Bad register offset "
-                       "0x" TARGET_FMT_plx "\n", addr);
-       }
-}
-
-static const MemoryRegionOps mst_fpga_ops = {
-       .read = mst_fpga_readb,
-       .write = mst_fpga_writeb,
-       .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int mst_fpga_post_load(void *opaque, int version_id)
-{
-       mst_irq_state *s = (mst_irq_state *) opaque;
-
-       qemu_set_irq(s->parent, s->intsetclr & s->intmskena);
-       return 0;
-}
-
-static int mst_fpga_init(SysBusDevice *dev)
-{
-       mst_irq_state *s;
-
-       s = FROM_SYSBUS(mst_irq_state, dev);
-
-       s->pcmcia0 = MST_PCMCIAx_READY | MST_PCMCIAx_nCD;
-       s->pcmcia1 = MST_PCMCIAx_READY | MST_PCMCIAx_nCD;
-
-       sysbus_init_irq(dev, &s->parent);
-
-       /* alloc the external 16 irqs */
-       qdev_init_gpio_in(&dev->qdev, mst_fpga_set_irq, MST_NUM_IRQS);
-
-       memory_region_init_io(&s->iomem, &mst_fpga_ops, s,
-                           "fpga", 0x00100000);
-       sysbus_init_mmio(dev, &s->iomem);
-       return 0;
-}
-
-static VMStateDescription vmstate_mst_fpga_regs = {
-       .name = "mainstone_fpga",
-       .version_id = 0,
-       .minimum_version_id = 0,
-       .minimum_version_id_old = 0,
-       .post_load = mst_fpga_post_load,
-       .fields = (VMStateField []) {
-               VMSTATE_UINT32(prev_level, mst_irq_state),
-               VMSTATE_UINT32(leddat1, mst_irq_state),
-               VMSTATE_UINT32(leddat2, mst_irq_state),
-               VMSTATE_UINT32(ledctrl, mst_irq_state),
-               VMSTATE_UINT32(gpswr, mst_irq_state),
-               VMSTATE_UINT32(mscwr1, mst_irq_state),
-               VMSTATE_UINT32(mscwr2, mst_irq_state),
-               VMSTATE_UINT32(mscwr3, mst_irq_state),
-               VMSTATE_UINT32(mscrd, mst_irq_state),
-               VMSTATE_UINT32(intmskena, mst_irq_state),
-               VMSTATE_UINT32(intsetclr, mst_irq_state),
-               VMSTATE_UINT32(pcmcia0, mst_irq_state),
-               VMSTATE_UINT32(pcmcia1, mst_irq_state),
-               VMSTATE_END_OF_LIST(),
-       },
-};
-
-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 const 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_types(void)
-{
-    type_register_static(&mst_fpga_info);
-}
-
-type_init(mst_fpga_register_types)
diff --git a/hw/multiboot.h b/hw/multiboot.h
deleted file mode 100644 (file)
index 98fb1b7..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-#ifndef QEMU_MULTIBOOT_H
-#define QEMU_MULTIBOOT_H
-
-int load_multiboot(void *fw_cfg,
-                   FILE *f,
-                   const char *kernel_filename,
-                   const char *initrd_filename,
-                   const char *kernel_cmdline,
-                   int kernel_file_size,
-                   uint8_t *header);
-
-#endif
diff --git a/hw/nand.c b/hw/nand.c
deleted file mode 100644 (file)
index de3e502..0000000
--- a/hw/nand.c
+++ /dev/null
@@ -1,790 +0,0 @@
-/*
- * Flash NAND memory emulation.  Based on "16M x 8 Bit NAND Flash
- * Memory" datasheet for the KM29U128AT / K9F2808U0A chips from
- * Samsung Electronic.
- *
- * Copyright (c) 2006 Openedhand Ltd.
- * Written by Andrzej Zaborowski <balrog@zabor.org>
- *
- * Support for additional features based on "MT29F2G16ABCWP 2Gx16"
- * datasheet from Micron Technology and "NAND02G-B2C" datasheet
- * 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
-
-# include "hw/hw.h"
-# include "hw/flash.h"
-# include "sysemu/blockdev.h"
-# include "hw/sysbus.h"
-#include "qemu/error-report.h"
-
-# define NAND_CMD_READ0                0x00
-# define NAND_CMD_READ1                0x01
-# define NAND_CMD_READ2                0x50
-# define NAND_CMD_LPREAD2      0x30
-# define NAND_CMD_NOSERIALREAD2        0x35
-# define NAND_CMD_RANDOMREAD1  0x05
-# define NAND_CMD_RANDOMREAD2  0xe0
-# define NAND_CMD_READID       0x90
-# define NAND_CMD_RESET                0xff
-# define NAND_CMD_PAGEPROGRAM1 0x80
-# define NAND_CMD_PAGEPROGRAM2 0x10
-# define NAND_CMD_CACHEPROGRAM2        0x15
-# define NAND_CMD_BLOCKERASE1  0x60
-# define NAND_CMD_BLOCKERASE2  0xd0
-# define NAND_CMD_READSTATUS   0x70
-# define NAND_CMD_COPYBACKPRG1 0x85
-
-# define NAND_IOSTATUS_ERROR   (1 << 0)
-# define NAND_IOSTATUS_PLANE0  (1 << 1)
-# define NAND_IOSTATUS_PLANE1  (1 << 2)
-# define NAND_IOSTATUS_PLANE2  (1 << 3)
-# define NAND_IOSTATUS_PLANE3  (1 << 4)
-# define NAND_IOSTATUS_READY    (1 << 6)
-# define NAND_IOSTATUS_UNPROTCT        (1 << 7)
-
-# define MAX_PAGE              0x800
-# define MAX_OOB               0x40
-
-typedef struct NANDFlashState NANDFlashState;
-struct NANDFlashState {
-    SysBusDevice busdev;
-    uint8_t manf_id, chip_id;
-    uint8_t buswidth; /* in BYTES */
-    int size, pages;
-    int page_shift, oob_shift, erase_shift, addr_shift;
-    uint8_t *storage;
-    BlockDriverState *bdrv;
-    int mem_oob;
-
-    uint8_t cle, ale, ce, wp, gnd;
-
-    uint8_t io[MAX_PAGE + MAX_OOB + 0x400];
-    uint8_t *ioaddr;
-    int iolen;
-
-    uint32_t cmd;
-    uint64_t addr;
-    int addrlen;
-    int status;
-    int offset;
-
-    void (*blk_write)(NANDFlashState *s);
-    void (*blk_erase)(NANDFlashState *s);
-    void (*blk_load)(NANDFlashState *s, uint64_t addr, int offset);
-
-    uint32_t ioaddr_vmstate;
-};
-
-static void mem_and(uint8_t *dest, const uint8_t *src, size_t n)
-{
-    /* Like memcpy() but we logical-AND the data into the destination */
-    int i;
-    for (i = 0; i < n; i++) {
-        dest[i] &= src[i];
-    }
-}
-
-# define NAND_NO_AUTOINCR      0x00000001
-# define NAND_BUSWIDTH_16      0x00000002
-# define NAND_NO_PADDING       0x00000004
-# define NAND_CACHEPRG         0x00000008
-# define NAND_COPYBACK         0x00000010
-# define NAND_IS_AND           0x00000020
-# define NAND_4PAGE_ARRAY      0x00000040
-# define NAND_NO_READRDY       0x00000100
-# define NAND_SAMSUNG_LP       (NAND_NO_PADDING | NAND_COPYBACK)
-
-# define NAND_IO
-
-# define PAGE(addr)            ((addr) >> ADDR_SHIFT)
-# define PAGE_START(page)      (PAGE(page) * (PAGE_SIZE + OOB_SIZE))
-# define PAGE_MASK             ((1 << ADDR_SHIFT) - 1)
-# define OOB_SHIFT             (PAGE_SHIFT - 5)
-# define OOB_SIZE              (1 << OOB_SHIFT)
-# define SECTOR(addr)          ((addr) >> (9 + ADDR_SHIFT - PAGE_SHIFT))
-# define SECTOR_OFFSET(addr)   ((addr) & ((511 >> PAGE_SHIFT) << 8))
-
-# define PAGE_SIZE             256
-# define PAGE_SHIFT            8
-# define PAGE_SECTORS          1
-# define ADDR_SHIFT            8
-# include "nand.c"
-# define PAGE_SIZE             512
-# define PAGE_SHIFT            9
-# define PAGE_SECTORS          1
-# define ADDR_SHIFT            8
-# include "nand.c"
-# define PAGE_SIZE             2048
-# define PAGE_SHIFT            11
-# define PAGE_SECTORS          4
-# define ADDR_SHIFT            16
-# include "nand.c"
-
-/* Information based on Linux drivers/mtd/nand/nand_ids.c */
-static const struct {
-    int size;
-    int width;
-    int page_shift;
-    int erase_shift;
-    uint32_t options;
-} nand_flash_ids[0x100] = {
-    [0 ... 0xff] = { 0 },
-
-    [0x6e] = { 1,      8,      8, 4, 0 },
-    [0x64] = { 2,      8,      8, 4, 0 },
-    [0x6b] = { 4,      8,      9, 4, 0 },
-    [0xe8] = { 1,      8,      8, 4, 0 },
-    [0xec] = { 1,      8,      8, 4, 0 },
-    [0xea] = { 2,      8,      8, 4, 0 },
-    [0xd5] = { 4,      8,      9, 4, 0 },
-    [0xe3] = { 4,      8,      9, 4, 0 },
-    [0xe5] = { 4,      8,      9, 4, 0 },
-    [0xd6] = { 8,      8,      9, 4, 0 },
-
-    [0x39] = { 8,      8,      9, 4, 0 },
-    [0xe6] = { 8,      8,      9, 4, 0 },
-    [0x49] = { 8,      16,     9, 4, NAND_BUSWIDTH_16 },
-    [0x59] = { 8,      16,     9, 4, NAND_BUSWIDTH_16 },
-
-    [0x33] = { 16,     8,      9, 5, 0 },
-    [0x73] = { 16,     8,      9, 5, 0 },
-    [0x43] = { 16,     16,     9, 5, NAND_BUSWIDTH_16 },
-    [0x53] = { 16,     16,     9, 5, NAND_BUSWIDTH_16 },
-
-    [0x35] = { 32,     8,      9, 5, 0 },
-    [0x75] = { 32,     8,      9, 5, 0 },
-    [0x45] = { 32,     16,     9, 5, NAND_BUSWIDTH_16 },
-    [0x55] = { 32,     16,     9, 5, NAND_BUSWIDTH_16 },
-
-    [0x36] = { 64,     8,      9, 5, 0 },
-    [0x76] = { 64,     8,      9, 5, 0 },
-    [0x46] = { 64,     16,     9, 5, NAND_BUSWIDTH_16 },
-    [0x56] = { 64,     16,     9, 5, NAND_BUSWIDTH_16 },
-
-    [0x78] = { 128,    8,      9, 5, 0 },
-    [0x39] = { 128,    8,      9, 5, 0 },
-    [0x79] = { 128,    8,      9, 5, 0 },
-    [0x72] = { 128,    16,     9, 5, NAND_BUSWIDTH_16 },
-    [0x49] = { 128,    16,     9, 5, NAND_BUSWIDTH_16 },
-    [0x74] = { 128,    16,     9, 5, NAND_BUSWIDTH_16 },
-    [0x59] = { 128,    16,     9, 5, NAND_BUSWIDTH_16 },
-
-    [0x71] = { 256,    8,      9, 5, 0 },
-
-    /*
-     * These are the new chips with large page size. The pagesize and the
-     * erasesize is determined from the extended id bytes
-     */
-# define LP_OPTIONS    (NAND_SAMSUNG_LP | NAND_NO_READRDY | NAND_NO_AUTOINCR)
-# define LP_OPTIONS16  (LP_OPTIONS | NAND_BUSWIDTH_16)
-
-    /* 512 Megabit */
-    [0xa2] = { 64,     8,      0, 0, LP_OPTIONS },
-    [0xf2] = { 64,     8,      0, 0, LP_OPTIONS },
-    [0xb2] = { 64,     16,     0, 0, LP_OPTIONS16 },
-    [0xc2] = { 64,     16,     0, 0, LP_OPTIONS16 },
-
-    /* 1 Gigabit */
-    [0xa1] = { 128,    8,      0, 0, LP_OPTIONS },
-    [0xf1] = { 128,    8,      0, 0, LP_OPTIONS },
-    [0xb1] = { 128,    16,     0, 0, LP_OPTIONS16 },
-    [0xc1] = { 128,    16,     0, 0, LP_OPTIONS16 },
-
-    /* 2 Gigabit */
-    [0xaa] = { 256,    8,      0, 0, LP_OPTIONS },
-    [0xda] = { 256,    8,      0, 0, LP_OPTIONS },
-    [0xba] = { 256,    16,     0, 0, LP_OPTIONS16 },
-    [0xca] = { 256,    16,     0, 0, LP_OPTIONS16 },
-
-    /* 4 Gigabit */
-    [0xac] = { 512,    8,      0, 0, LP_OPTIONS },
-    [0xdc] = { 512,    8,      0, 0, LP_OPTIONS },
-    [0xbc] = { 512,    16,     0, 0, LP_OPTIONS16 },
-    [0xcc] = { 512,    16,     0, 0, LP_OPTIONS16 },
-
-    /* 8 Gigabit */
-    [0xa3] = { 1024,   8,      0, 0, LP_OPTIONS },
-    [0xd3] = { 1024,   8,      0, 0, LP_OPTIONS },
-    [0xb3] = { 1024,   16,     0, 0, LP_OPTIONS16 },
-    [0xc3] = { 1024,   16,     0, 0, LP_OPTIONS16 },
-
-    /* 16 Gigabit */
-    [0xa5] = { 2048,   8,      0, 0, LP_OPTIONS },
-    [0xd5] = { 2048,   8,      0, 0, LP_OPTIONS },
-    [0xb5] = { 2048,   16,     0, 0, LP_OPTIONS16 },
-    [0xc5] = { 2048,   16,     0, 0, LP_OPTIONS16 },
-};
-
-static void nand_reset(DeviceState *dev)
-{
-    NANDFlashState *s = FROM_SYSBUS(NANDFlashState, SYS_BUS_DEVICE(dev));
-    s->cmd = NAND_CMD_READ0;
-    s->addr = 0;
-    s->addrlen = 0;
-    s->iolen = 0;
-    s->offset = 0;
-    s->status &= NAND_IOSTATUS_UNPROTCT;
-    s->status |= NAND_IOSTATUS_READY;
-}
-
-static inline void nand_pushio_byte(NANDFlashState *s, uint8_t value)
-{
-    s->ioaddr[s->iolen++] = value;
-    for (value = s->buswidth; --value;) {
-        s->ioaddr[s->iolen++] = 0;
-    }
-}
-
-static void nand_command(NANDFlashState *s)
-{
-    unsigned int offset;
-    switch (s->cmd) {
-    case NAND_CMD_READ0:
-        s->iolen = 0;
-        break;
-
-    case NAND_CMD_READID:
-        s->ioaddr = s->io;
-        s->iolen = 0;
-        nand_pushio_byte(s, s->manf_id);
-        nand_pushio_byte(s, s->chip_id);
-        nand_pushio_byte(s, 'Q'); /* Don't-care byte (often 0xa5) */
-        if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) {
-            /* Page Size, Block Size, Spare Size; bit 6 indicates
-             * 8 vs 16 bit width NAND.
-             */
-            nand_pushio_byte(s, (s->buswidth == 2) ? 0x55 : 0x15);
-        } else {
-            nand_pushio_byte(s, 0xc0); /* Multi-plane */
-        }
-        break;
-
-    case NAND_CMD_RANDOMREAD2:
-    case NAND_CMD_NOSERIALREAD2:
-        if (!(nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP))
-            break;
-        offset = s->addr & ((1 << s->addr_shift) - 1);
-        s->blk_load(s, s->addr, offset);
-        if (s->gnd)
-            s->iolen = (1 << s->page_shift) - offset;
-        else
-            s->iolen = (1 << s->page_shift) + (1 << s->oob_shift) - offset;
-        break;
-
-    case NAND_CMD_RESET:
-        nand_reset(&s->busdev.qdev);
-        break;
-
-    case NAND_CMD_PAGEPROGRAM1:
-        s->ioaddr = s->io;
-        s->iolen = 0;
-        break;
-
-    case NAND_CMD_PAGEPROGRAM2:
-        if (s->wp) {
-            s->blk_write(s);
-        }
-        break;
-
-    case NAND_CMD_BLOCKERASE1:
-        break;
-
-    case NAND_CMD_BLOCKERASE2:
-        if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP)
-            s->addr <<= 16;
-        else
-            s->addr <<= 8;
-
-        if (s->wp) {
-            s->blk_erase(s);
-        }
-        break;
-
-    case NAND_CMD_READSTATUS:
-        s->ioaddr = s->io;
-        s->iolen = 0;
-        nand_pushio_byte(s, s->status);
-        break;
-
-    default:
-        printf("%s: Unknown NAND command 0x%02x\n", __FUNCTION__, s->cmd);
-    }
-}
-
-static void nand_pre_save(void *opaque)
-{
-    NANDFlashState *s = opaque;
-
-    s->ioaddr_vmstate = s->ioaddr - s->io;
-}
-
-static int nand_post_load(void *opaque, int version_id)
-{
-    NANDFlashState *s = opaque;
-
-    if (s->ioaddr_vmstate > sizeof(s->io)) {
-        return -EINVAL;
-    }
-    s->ioaddr = s->io + s->ioaddr_vmstate;
-
-    return 0;
-}
-
-static const VMStateDescription vmstate_nand = {
-    .name = "nand",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .pre_save = nand_pre_save,
-    .post_load = nand_post_load,
-    .fields      = (VMStateField[]) {
-        VMSTATE_UINT8(cle, NANDFlashState),
-        VMSTATE_UINT8(ale, NANDFlashState),
-        VMSTATE_UINT8(ce, NANDFlashState),
-        VMSTATE_UINT8(wp, NANDFlashState),
-        VMSTATE_UINT8(gnd, NANDFlashState),
-        VMSTATE_BUFFER(io, NANDFlashState),
-        VMSTATE_UINT32(ioaddr_vmstate, NANDFlashState),
-        VMSTATE_INT32(iolen, NANDFlashState),
-        VMSTATE_UINT32(cmd, NANDFlashState),
-        VMSTATE_UINT64(addr, NANDFlashState),
-        VMSTATE_INT32(addrlen, NANDFlashState),
-        VMSTATE_INT32(status, NANDFlashState),
-        VMSTATE_INT32(offset, NANDFlashState),
-        /* XXX: do we want to save s->storage too? */
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static int nand_device_init(SysBusDevice *dev)
-{
-    int pagesize;
-    NANDFlashState *s = FROM_SYSBUS(NANDFlashState, dev);
-
-    s->buswidth = nand_flash_ids[s->chip_id].width >> 3;
-    s->size = nand_flash_ids[s->chip_id].size << 20;
-    if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) {
-        s->page_shift = 11;
-        s->erase_shift = 6;
-    } else {
-        s->page_shift = nand_flash_ids[s->chip_id].page_shift;
-        s->erase_shift = nand_flash_ids[s->chip_id].erase_shift;
-    }
-
-    switch (1 << s->page_shift) {
-    case 256:
-        nand_init_256(s);
-        break;
-    case 512:
-        nand_init_512(s);
-        break;
-    case 2048:
-        nand_init_2048(s);
-        break;
-    default:
-        error_report("Unsupported NAND block size");
-        return -1;
-    }
-
-    pagesize = 1 << s->oob_shift;
-    s->mem_oob = 1;
-    if (s->bdrv) {
-        if (bdrv_is_read_only(s->bdrv)) {
-            error_report("Can't use a read-only drive");
-            return -1;
-        }
-        if (bdrv_getlength(s->bdrv) >=
-                (s->pages << s->page_shift) + (s->pages << s->oob_shift)) {
-            pagesize = 0;
-            s->mem_oob = 0;
-        }
-    } else {
-        pagesize += 1 << s->page_shift;
-    }
-    if (pagesize) {
-        s->storage = (uint8_t *) memset(g_malloc(s->pages * pagesize),
-                        0xff, s->pages * pagesize);
-    }
-    /* Give s->ioaddr a sane value in case we save state before it is used. */
-    s->ioaddr = s->io;
-
-    return 0;
-}
-
-static Property nand_properties[] = {
-    DEFINE_PROP_UINT8("manufacturer_id", NANDFlashState, manf_id, 0),
-    DEFINE_PROP_UINT8("chip_id", NANDFlashState, chip_id, 0),
-    DEFINE_PROP_DRIVE("drive", NANDFlashState, bdrv),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void nand_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = nand_device_init;
-    dc->reset = nand_reset;
-    dc->vmsd = &vmstate_nand;
-    dc->props = nand_properties;
-}
-
-static const TypeInfo nand_info = {
-    .name          = "nand",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(NANDFlashState),
-    .class_init    = nand_class_init,
-};
-
-static void nand_register_types(void)
-{
-    type_register_static(&nand_info);
-}
-
-/*
- * Chip inputs are CLE, ALE, CE, WP, GND and eight I/O pins.  Chip
- * outputs are R/B and eight I/O pins.
- *
- * CE, WP and R/B are active low.
- */
-void nand_setpins(DeviceState *dev, uint8_t cle, uint8_t ale,
-                  uint8_t ce, uint8_t wp, uint8_t gnd)
-{
-    NANDFlashState *s = (NANDFlashState *) dev;
-    s->cle = cle;
-    s->ale = ale;
-    s->ce = ce;
-    s->wp = wp;
-    s->gnd = gnd;
-    if (wp)
-        s->status |= NAND_IOSTATUS_UNPROTCT;
-    else
-        s->status &= ~NAND_IOSTATUS_UNPROTCT;
-}
-
-void nand_getpins(DeviceState *dev, int *rb)
-{
-    *rb = 1;
-}
-
-void nand_setio(DeviceState *dev, uint32_t value)
-{
-    int i;
-    NANDFlashState *s = (NANDFlashState *) dev;
-    if (!s->ce && s->cle) {
-        if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) {
-            if (s->cmd == NAND_CMD_READ0 && value == NAND_CMD_LPREAD2)
-                return;
-            if (value == NAND_CMD_RANDOMREAD1) {
-                s->addr &= ~((1 << s->addr_shift) - 1);
-                s->addrlen = 0;
-                return;
-            }
-        }
-        if (value == NAND_CMD_READ0)
-            s->offset = 0;
-       else if (value == NAND_CMD_READ1) {
-            s->offset = 0x100;
-            value = NAND_CMD_READ0;
-        }
-       else if (value == NAND_CMD_READ2) {
-            s->offset = 1 << s->page_shift;
-            value = NAND_CMD_READ0;
-        }
-
-        s->cmd = value;
-
-        if (s->cmd == NAND_CMD_READSTATUS ||
-                s->cmd == NAND_CMD_PAGEPROGRAM2 ||
-                s->cmd == NAND_CMD_BLOCKERASE1 ||
-                s->cmd == NAND_CMD_BLOCKERASE2 ||
-                s->cmd == NAND_CMD_NOSERIALREAD2 ||
-                s->cmd == NAND_CMD_RANDOMREAD2 ||
-                s->cmd == NAND_CMD_RESET)
-            nand_command(s);
-
-        if (s->cmd != NAND_CMD_RANDOMREAD2) {
-            s->addrlen = 0;
-        }
-    }
-
-    if (s->ale) {
-        unsigned int shift = s->addrlen * 8;
-        unsigned int mask = ~(0xff << shift);
-        unsigned int v = value << shift;
-
-        s->addr = (s->addr & mask) | v;
-        s->addrlen ++;
-
-        switch (s->addrlen) {
-        case 1:
-            if (s->cmd == NAND_CMD_READID) {
-                nand_command(s);
-            }
-            break;
-        case 2: /* fix cache address as a byte address */
-            s->addr <<= (s->buswidth - 1);
-            break;
-        case 3:
-            if (!(nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) &&
-                    (s->cmd == NAND_CMD_READ0 ||
-                     s->cmd == NAND_CMD_PAGEPROGRAM1)) {
-                nand_command(s);
-            }
-            break;
-        case 4:
-            if ((nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) &&
-                    nand_flash_ids[s->chip_id].size < 256 && /* 1Gb or less */
-                    (s->cmd == NAND_CMD_READ0 ||
-                     s->cmd == NAND_CMD_PAGEPROGRAM1)) {
-                nand_command(s);
-            }
-            break;
-        case 5:
-            if ((nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) &&
-                    nand_flash_ids[s->chip_id].size >= 256 && /* 2Gb or more */
-                    (s->cmd == NAND_CMD_READ0 ||
-                     s->cmd == NAND_CMD_PAGEPROGRAM1)) {
-                nand_command(s);
-            }
-            break;
-        default:
-            break;
-        }
-    }
-
-    if (!s->cle && !s->ale && s->cmd == NAND_CMD_PAGEPROGRAM1) {
-        if (s->iolen < (1 << s->page_shift) + (1 << s->oob_shift)) {
-            for (i = s->buswidth; i--; value >>= 8) {
-                s->io[s->iolen ++] = (uint8_t) (value & 0xff);
-            }
-        }
-    } else if (!s->cle && !s->ale && s->cmd == NAND_CMD_COPYBACKPRG1) {
-        if ((s->addr & ((1 << s->addr_shift) - 1)) <
-                (1 << s->page_shift) + (1 << s->oob_shift)) {
-            for (i = s->buswidth; i--; s->addr++, value >>= 8) {
-                s->io[s->iolen + (s->addr & ((1 << s->addr_shift) - 1))] =
-                    (uint8_t) (value & 0xff);
-            }
-        }
-    }
-}
-
-uint32_t nand_getio(DeviceState *dev)
-{
-    int offset;
-    uint32_t x = 0;
-    NANDFlashState *s = (NANDFlashState *) dev;
-
-    /* Allow sequential reading */
-    if (!s->iolen && s->cmd == NAND_CMD_READ0) {
-        offset = (int) (s->addr & ((1 << s->addr_shift) - 1)) + s->offset;
-        s->offset = 0;
-
-        s->blk_load(s, s->addr, offset);
-        if (s->gnd)
-            s->iolen = (1 << s->page_shift) - offset;
-        else
-            s->iolen = (1 << s->page_shift) + (1 << s->oob_shift) - offset;
-    }
-
-    if (s->ce || s->iolen <= 0)
-        return 0;
-
-    for (offset = s->buswidth; offset--;) {
-        x |= s->ioaddr[offset] << (offset << 3);
-    }
-    /* after receiving READ STATUS command all subsequent reads will
-     * return the status register value until another command is issued
-     */
-    if (s->cmd != NAND_CMD_READSTATUS) {
-        s->addr   += s->buswidth;
-        s->ioaddr += s->buswidth;
-        s->iolen  -= s->buswidth;
-    }
-    return x;
-}
-
-uint32_t nand_getbuswidth(DeviceState *dev)
-{
-    NANDFlashState *s = (NANDFlashState *) dev;
-    return s->buswidth << 3;
-}
-
-DeviceState *nand_init(BlockDriverState *bdrv, int manf_id, int chip_id)
-{
-    DeviceState *dev;
-
-    if (nand_flash_ids[chip_id].size == 0) {
-        hw_error("%s: Unsupported NAND chip ID.\n", __FUNCTION__);
-    }
-    dev = qdev_create(NULL, "nand");
-    qdev_prop_set_uint8(dev, "manufacturer_id", manf_id);
-    qdev_prop_set_uint8(dev, "chip_id", chip_id);
-    if (bdrv) {
-        qdev_prop_set_drive_nofail(dev, "drive", bdrv);
-    }
-
-    qdev_init_nofail(dev);
-    return dev;
-}
-
-type_init(nand_register_types)
-
-#else
-
-/* Program a single page */
-static void glue(nand_blk_write_, PAGE_SIZE)(NANDFlashState *s)
-{
-    uint64_t off, page, sector, soff;
-    uint8_t iobuf[(PAGE_SECTORS + 2) * 0x200];
-    if (PAGE(s->addr) >= s->pages)
-        return;
-
-    if (!s->bdrv) {
-        mem_and(s->storage + PAGE_START(s->addr) + (s->addr & PAGE_MASK) +
-                        s->offset, s->io, s->iolen);
-    } else if (s->mem_oob) {
-        sector = SECTOR(s->addr);
-        off = (s->addr & PAGE_MASK) + s->offset;
-        soff = SECTOR_OFFSET(s->addr);
-        if (bdrv_read(s->bdrv, sector, iobuf, PAGE_SECTORS) < 0) {
-            printf("%s: read error in sector %" PRIu64 "\n", __func__, sector);
-            return;
-        }
-
-        mem_and(iobuf + (soff | off), s->io, MIN(s->iolen, PAGE_SIZE - off));
-        if (off + s->iolen > PAGE_SIZE) {
-            page = PAGE(s->addr);
-            mem_and(s->storage + (page << OOB_SHIFT), s->io + PAGE_SIZE - off,
-                            MIN(OOB_SIZE, off + s->iolen - PAGE_SIZE));
-        }
-
-        if (bdrv_write(s->bdrv, sector, iobuf, PAGE_SECTORS) < 0) {
-            printf("%s: write error in sector %" PRIu64 "\n", __func__, sector);
-        }
-    } else {
-        off = PAGE_START(s->addr) + (s->addr & PAGE_MASK) + s->offset;
-        sector = off >> 9;
-        soff = off & 0x1ff;
-        if (bdrv_read(s->bdrv, sector, iobuf, PAGE_SECTORS + 2) < 0) {
-            printf("%s: read error in sector %" PRIu64 "\n", __func__, sector);
-            return;
-        }
-
-        mem_and(iobuf + soff, s->io, s->iolen);
-
-        if (bdrv_write(s->bdrv, sector, iobuf, PAGE_SECTORS + 2) < 0) {
-            printf("%s: write error in sector %" PRIu64 "\n", __func__, sector);
-        }
-    }
-    s->offset = 0;
-}
-
-/* Erase a single block */
-static void glue(nand_blk_erase_, PAGE_SIZE)(NANDFlashState *s)
-{
-    uint64_t i, page, addr;
-    uint8_t iobuf[0x200] = { [0 ... 0x1ff] = 0xff, };
-    addr = s->addr & ~((1 << (ADDR_SHIFT + s->erase_shift)) - 1);
-
-    if (PAGE(addr) >= s->pages)
-        return;
-
-    if (!s->bdrv) {
-        memset(s->storage + PAGE_START(addr),
-                        0xff, (PAGE_SIZE + OOB_SIZE) << s->erase_shift);
-    } else if (s->mem_oob) {
-        memset(s->storage + (PAGE(addr) << OOB_SHIFT),
-                        0xff, OOB_SIZE << s->erase_shift);
-        i = SECTOR(addr);
-        page = SECTOR(addr + (ADDR_SHIFT + s->erase_shift));
-        for (; i < page; i ++)
-            if (bdrv_write(s->bdrv, i, iobuf, 1) < 0) {
-                printf("%s: write error in sector %" PRIu64 "\n", __func__, i);
-            }
-    } else {
-        addr = PAGE_START(addr);
-        page = addr >> 9;
-        if (bdrv_read(s->bdrv, page, iobuf, 1) < 0) {
-            printf("%s: read error in sector %" PRIu64 "\n", __func__, page);
-        }
-        memset(iobuf + (addr & 0x1ff), 0xff, (~addr & 0x1ff) + 1);
-        if (bdrv_write(s->bdrv, page, iobuf, 1) < 0) {
-            printf("%s: write error in sector %" PRIu64 "\n", __func__, page);
-        }
-
-        memset(iobuf, 0xff, 0x200);
-        i = (addr & ~0x1ff) + 0x200;
-        for (addr += ((PAGE_SIZE + OOB_SIZE) << s->erase_shift) - 0x200;
-                        i < addr; i += 0x200)
-            if (bdrv_write(s->bdrv, i >> 9, iobuf, 1) < 0) {
-                printf("%s: write error in sector %" PRIu64 "\n",
-                       __func__, i >> 9);
-            }
-
-        page = i >> 9;
-        if (bdrv_read(s->bdrv, page, iobuf, 1) < 0) {
-            printf("%s: read error in sector %" PRIu64 "\n", __func__, page);
-        }
-        memset(iobuf, 0xff, ((addr - 1) & 0x1ff) + 1);
-        if (bdrv_write(s->bdrv, page, iobuf, 1) < 0) {
-            printf("%s: write error in sector %" PRIu64 "\n", __func__, page);
-        }
-    }
-}
-
-static void glue(nand_blk_load_, PAGE_SIZE)(NANDFlashState *s,
-                uint64_t addr, int offset)
-{
-    if (PAGE(addr) >= s->pages)
-        return;
-
-    if (s->bdrv) {
-        if (s->mem_oob) {
-            if (bdrv_read(s->bdrv, SECTOR(addr), s->io, PAGE_SECTORS) < 0) {
-                printf("%s: read error in sector %" PRIu64 "\n",
-                                __func__, SECTOR(addr));
-            }
-            memcpy(s->io + SECTOR_OFFSET(s->addr) + PAGE_SIZE,
-                            s->storage + (PAGE(s->addr) << OOB_SHIFT),
-                            OOB_SIZE);
-            s->ioaddr = s->io + SECTOR_OFFSET(s->addr) + offset;
-        } else {
-            if (bdrv_read(s->bdrv, PAGE_START(addr) >> 9,
-                                    s->io, (PAGE_SECTORS + 2)) < 0) {
-                printf("%s: read error in sector %" PRIu64 "\n",
-                                __func__, PAGE_START(addr) >> 9);
-            }
-            s->ioaddr = s->io + (PAGE_START(addr) & 0x1ff) + offset;
-        }
-    } else {
-        memcpy(s->io, s->storage + PAGE_START(s->addr) +
-                        offset, PAGE_SIZE + OOB_SIZE - offset);
-        s->ioaddr = s->io;
-    }
-}
-
-static void glue(nand_init_, PAGE_SIZE)(NANDFlashState *s)
-{
-    s->oob_shift = PAGE_SHIFT - 5;
-    s->pages = s->size >> PAGE_SHIFT;
-    s->addr_shift = ADDR_SHIFT;
-
-    s->blk_erase = glue(nand_blk_erase_, PAGE_SIZE);
-    s->blk_write = glue(nand_blk_write_, PAGE_SIZE);
-    s->blk_load = glue(nand_blk_load_, PAGE_SIZE);
-}
-
-# undef PAGE_SIZE
-# undef PAGE_SHIFT
-# undef PAGE_SECTORS
-# undef ADDR_SHIFT
-#endif /* NAND_IO */
diff --git a/hw/ne2000-isa.c b/hw/ne2000-isa.c
deleted file mode 100644 (file)
index 47c00c3..0000000
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * QEMU NE2000 emulation -- isa bus windup
- *
- * 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.
- */
-#include "hw/hw.h"
-#include "hw/pc.h"
-#include "hw/isa.h"
-#include "hw/qdev.h"
-#include "net/net.h"
-#include "hw/ne2000.h"
-#include "exec/address-spaces.h"
-
-typedef struct ISANE2000State {
-    ISADevice dev;
-    uint32_t iobase;
-    uint32_t isairq;
-    NE2000State ne2000;
-} ISANE2000State;
-
-static void isa_ne2000_cleanup(NetClientState *nc)
-{
-    NE2000State *s = qemu_get_nic_opaque(nc);
-
-    s->nic = NULL;
-}
-
-static NetClientInfo net_ne2000_isa_info = {
-    .type = NET_CLIENT_OPTIONS_KIND_NIC,
-    .size = sizeof(NICState),
-    .can_receive = ne2000_can_receive,
-    .receive = ne2000_receive,
-    .cleanup = isa_ne2000_cleanup,
-};
-
-static const VMStateDescription vmstate_isa_ne2000 = {
-    .name = "ne2000",
-    .version_id = 2,
-    .minimum_version_id = 0,
-    .minimum_version_id_old = 0,
-    .fields      = (VMStateField []) {
-        VMSTATE_STRUCT(ne2000, ISANE2000State, 0, vmstate_ne2000, NE2000State),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static int isa_ne2000_initfn(ISADevice *dev)
-{
-    ISANE2000State *isa = DO_UPCAST(ISANE2000State, dev, dev);
-    NE2000State *s = &isa->ne2000;
-
-    ne2000_setup_io(s, 0x20);
-    isa_register_ioport(dev, &s->io, isa->iobase);
-
-    isa_init_irq(dev, &s->irq, isa->isairq);
-
-    qemu_macaddr_default_if_unset(&s->c.macaddr);
-    ne2000_reset(s);
-
-    s->nic = qemu_new_nic(&net_ne2000_isa_info, &s->c,
-                          object_get_typename(OBJECT(dev)), dev->qdev.id, s);
-    qemu_format_nic_info_str(qemu_get_queue(s->nic), s->c.macaddr.a);
-
-    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 const 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_types(void)
-{
-    type_register_static(&ne2000_isa_info);
-}
-
-type_init(ne2000_isa_register_types)
diff --git a/hw/ne2000.c b/hw/ne2000.c
deleted file mode 100644 (file)
index 7f45831..0000000
+++ /dev/null
@@ -1,789 +0,0 @@
-/*
- * QEMU NE2000 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.
- */
-#include "hw/hw.h"
-#include "hw/pci/pci.h"
-#include "net/net.h"
-#include "hw/ne2000.h"
-#include "hw/loader.h"
-#include "sysemu/sysemu.h"
-
-/* debug NE2000 card */
-//#define DEBUG_NE2000
-
-#define MAX_ETH_FRAME_SIZE 1514
-
-#define E8390_CMD      0x00  /* The command register (for all pages) */
-/* Page 0 register offsets. */
-#define EN0_CLDALO     0x01    /* Low byte of current local dma addr  RD */
-#define EN0_STARTPG    0x01    /* Starting page of ring bfr WR */
-#define EN0_CLDAHI     0x02    /* High byte of current local dma addr  RD */
-#define EN0_STOPPG     0x02    /* Ending page +1 of ring bfr WR */
-#define EN0_BOUNDARY   0x03    /* Boundary page of ring bfr RD WR */
-#define EN0_TSR                0x04    /* Transmit status reg RD */
-#define EN0_TPSR       0x04    /* Transmit starting page WR */
-#define EN0_NCR                0x05    /* Number of collision reg RD */
-#define EN0_TCNTLO     0x05    /* Low  byte of tx byte count WR */
-#define EN0_FIFO       0x06    /* FIFO RD */
-#define EN0_TCNTHI     0x06    /* High byte of tx byte count WR */
-#define EN0_ISR                0x07    /* Interrupt status reg RD WR */
-#define EN0_CRDALO     0x08    /* low byte of current remote dma address RD */
-#define EN0_RSARLO     0x08    /* Remote start address reg 0 */
-#define EN0_CRDAHI     0x09    /* high byte, current remote dma address RD */
-#define EN0_RSARHI     0x09    /* Remote start address reg 1 */
-#define EN0_RCNTLO     0x0a    /* Remote byte count reg WR */
-#define EN0_RTL8029ID0 0x0a    /* Realtek ID byte #1 RD */
-#define EN0_RCNTHI     0x0b    /* Remote byte count reg WR */
-#define EN0_RTL8029ID1 0x0b    /* Realtek ID byte #2 RD */
-#define EN0_RSR                0x0c    /* rx status reg RD */
-#define EN0_RXCR       0x0c    /* RX configuration reg WR */
-#define EN0_TXCR       0x0d    /* TX configuration reg WR */
-#define EN0_COUNTER0   0x0d    /* Rcv alignment error counter RD */
-#define EN0_DCFG       0x0e    /* Data configuration reg WR */
-#define EN0_COUNTER1   0x0e    /* Rcv CRC error counter RD */
-#define EN0_IMR                0x0f    /* Interrupt mask reg WR */
-#define EN0_COUNTER2   0x0f    /* Rcv missed frame error counter RD */
-
-#define EN1_PHYS        0x11
-#define EN1_CURPAG      0x17
-#define EN1_MULT        0x18
-
-#define EN2_STARTPG    0x21    /* Starting page of ring bfr RD */
-#define EN2_STOPPG     0x22    /* Ending page +1 of ring bfr RD */
-
-#define EN3_CONFIG0    0x33
-#define EN3_CONFIG1    0x34
-#define EN3_CONFIG2    0x35
-#define EN3_CONFIG3    0x36
-
-/*  Register accessed at EN_CMD, the 8390 base addr.  */
-#define E8390_STOP     0x01    /* Stop and reset the chip */
-#define E8390_START    0x02    /* Start the chip, clear reset */
-#define E8390_TRANS    0x04    /* Transmit a frame */
-#define E8390_RREAD    0x08    /* Remote read */
-#define E8390_RWRITE   0x10    /* Remote write  */
-#define E8390_NODMA    0x20    /* Remote DMA */
-#define E8390_PAGE0    0x00    /* Select page chip registers */
-#define E8390_PAGE1    0x40    /* using the two high-order bits */
-#define E8390_PAGE2    0x80    /* Page 3 is invalid. */
-
-/* Bits in EN0_ISR - Interrupt status register */
-#define ENISR_RX       0x01    /* Receiver, no error */
-#define ENISR_TX       0x02    /* Transmitter, no error */
-#define ENISR_RX_ERR   0x04    /* Receiver, with error */
-#define ENISR_TX_ERR   0x08    /* Transmitter, with error */
-#define ENISR_OVER     0x10    /* Receiver overwrote the ring */
-#define ENISR_COUNTERS 0x20    /* Counters need emptying */
-#define ENISR_RDC      0x40    /* remote dma complete */
-#define ENISR_RESET    0x80    /* Reset completed */
-#define ENISR_ALL      0x3f    /* Interrupts we will enable */
-
-/* Bits in received packet status byte and EN0_RSR*/
-#define ENRSR_RXOK     0x01    /* Received a good packet */
-#define ENRSR_CRC      0x02    /* CRC error */
-#define ENRSR_FAE      0x04    /* frame alignment error */
-#define ENRSR_FO       0x08    /* FIFO overrun */
-#define ENRSR_MPA      0x10    /* missed pkt */
-#define ENRSR_PHY      0x20    /* physical/multicast address */
-#define ENRSR_DIS      0x40    /* receiver disable. set in monitor mode */
-#define ENRSR_DEF      0x80    /* deferring */
-
-/* Transmitted packet status, EN0_TSR. */
-#define ENTSR_PTX 0x01 /* Packet transmitted without error */
-#define ENTSR_ND  0x02 /* The transmit wasn't deferred. */
-#define ENTSR_COL 0x04 /* The transmit collided at least once. */
-#define ENTSR_ABT 0x08  /* The transmit collided 16 times, and was deferred. */
-#define ENTSR_CRS 0x10 /* The carrier sense was lost. */
-#define ENTSR_FU  0x20  /* A "FIFO underrun" occurred during transmit. */
-#define ENTSR_CDH 0x40 /* The collision detect "heartbeat" signal was lost. */
-#define ENTSR_OWC 0x80  /* There was an out-of-window collision. */
-
-typedef struct PCINE2000State {
-    PCIDevice dev;
-    NE2000State ne2000;
-} PCINE2000State;
-
-void ne2000_reset(NE2000State *s)
-{
-    int i;
-
-    s->isr = ENISR_RESET;
-    memcpy(s->mem, &s->c.macaddr, 6);
-    s->mem[14] = 0x57;
-    s->mem[15] = 0x57;
-
-    /* duplicate prom data */
-    for(i = 15;i >= 0; i--) {
-        s->mem[2 * i] = s->mem[i];
-        s->mem[2 * i + 1] = s->mem[i];
-    }
-}
-
-static void ne2000_update_irq(NE2000State *s)
-{
-    int isr;
-    isr = (s->isr & s->imr) & 0x7f;
-#if defined(DEBUG_NE2000)
-    printf("NE2000: Set IRQ to %d (%02x %02x)\n",
-          isr ? 1 : 0, s->isr, s->imr);
-#endif
-    qemu_set_irq(s->irq, (isr != 0));
-}
-
-static int ne2000_buffer_full(NE2000State *s)
-{
-    int avail, index, boundary;
-
-    index = s->curpag << 8;
-    boundary = s->boundary << 8;
-    if (index < boundary)
-        avail = boundary - index;
-    else
-        avail = (s->stop - s->start) - (index - boundary);
-    if (avail < (MAX_ETH_FRAME_SIZE + 4))
-        return 1;
-    return 0;
-}
-
-int ne2000_can_receive(NetClientState *nc)
-{
-    NE2000State *s = qemu_get_nic_opaque(nc);
-
-    if (s->cmd & E8390_STOP)
-        return 1;
-    return !ne2000_buffer_full(s);
-}
-
-#define MIN_BUF_SIZE 60
-
-ssize_t ne2000_receive(NetClientState *nc, const uint8_t *buf, size_t size_)
-{
-    NE2000State *s = qemu_get_nic_opaque(nc);
-    int size = size_;
-    uint8_t *p;
-    unsigned int total_len, next, avail, len, index, mcast_idx;
-    uint8_t buf1[60];
-    static const uint8_t broadcast_macaddr[6] =
-        { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
-
-#if defined(DEBUG_NE2000)
-    printf("NE2000: received len=%d\n", size);
-#endif
-
-    if (s->cmd & E8390_STOP || ne2000_buffer_full(s))
-        return -1;
-
-    /* XXX: check this */
-    if (s->rxcr & 0x10) {
-        /* promiscuous: receive all */
-    } else {
-        if (!memcmp(buf,  broadcast_macaddr, 6)) {
-            /* broadcast address */
-            if (!(s->rxcr & 0x04))
-                return size;
-        } else if (buf[0] & 0x01) {
-            /* multicast */
-            if (!(s->rxcr & 0x08))
-                return size;
-            mcast_idx = compute_mcast_idx(buf);
-            if (!(s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7))))
-                return size;
-        } else if (s->mem[0] == buf[0] &&
-                   s->mem[2] == buf[1] &&
-                   s->mem[4] == buf[2] &&
-                   s->mem[6] == buf[3] &&
-                   s->mem[8] == buf[4] &&
-                   s->mem[10] == buf[5]) {
-            /* match */
-        } else {
-            return size;
-        }
-    }
-
-
-    /* if too small buffer, then expand it */
-    if (size < MIN_BUF_SIZE) {
-        memcpy(buf1, buf, size);
-        memset(buf1 + size, 0, MIN_BUF_SIZE - size);
-        buf = buf1;
-        size = MIN_BUF_SIZE;
-    }
-
-    index = s->curpag << 8;
-    /* 4 bytes for header */
-    total_len = size + 4;
-    /* address for next packet (4 bytes for CRC) */
-    next = index + ((total_len + 4 + 255) & ~0xff);
-    if (next >= s->stop)
-        next -= (s->stop - s->start);
-    /* prepare packet header */
-    p = s->mem + index;
-    s->rsr = ENRSR_RXOK; /* receive status */
-    /* XXX: check this */
-    if (buf[0] & 0x01)
-        s->rsr |= ENRSR_PHY;
-    p[0] = s->rsr;
-    p[1] = next >> 8;
-    p[2] = total_len;
-    p[3] = total_len >> 8;
-    index += 4;
-
-    /* write packet data */
-    while (size > 0) {
-        if (index <= s->stop)
-            avail = s->stop - index;
-        else
-            avail = 0;
-        len = size;
-        if (len > avail)
-            len = avail;
-        memcpy(s->mem + index, buf, len);
-        buf += len;
-        index += len;
-        if (index == s->stop)
-            index = s->start;
-        size -= len;
-    }
-    s->curpag = next >> 8;
-
-    /* now we can signal we have received something */
-    s->isr |= ENISR_RX;
-    ne2000_update_irq(s);
-
-    return size_;
-}
-
-static void ne2000_ioport_write(void *opaque, uint32_t addr, uint32_t val)
-{
-    NE2000State *s = opaque;
-    int offset, page, index;
-
-    addr &= 0xf;
-#ifdef DEBUG_NE2000
-    printf("NE2000: write addr=0x%x val=0x%02x\n", addr, val);
-#endif
-    if (addr == E8390_CMD) {
-        /* control register */
-        s->cmd = val;
-        if (!(val & E8390_STOP)) { /* START bit makes no sense on RTL8029... */
-            s->isr &= ~ENISR_RESET;
-            /* test specific case: zero length transfer */
-            if ((val & (E8390_RREAD | E8390_RWRITE)) &&
-                s->rcnt == 0) {
-                s->isr |= ENISR_RDC;
-                ne2000_update_irq(s);
-            }
-            if (val & E8390_TRANS) {
-                index = (s->tpsr << 8);
-                /* XXX: next 2 lines are a hack to make netware 3.11 work */
-                if (index >= NE2000_PMEM_END)
-                    index -= NE2000_PMEM_SIZE;
-                /* fail safe: check range on the transmitted length  */
-                if (index + s->tcnt <= NE2000_PMEM_END) {
-                    qemu_send_packet(qemu_get_queue(s->nic), s->mem + index,
-                                     s->tcnt);
-                }
-                /* signal end of transfer */
-                s->tsr = ENTSR_PTX;
-                s->isr |= ENISR_TX;
-                s->cmd &= ~E8390_TRANS;
-                ne2000_update_irq(s);
-            }
-        }
-    } else {
-        page = s->cmd >> 6;
-        offset = addr | (page << 4);
-        switch(offset) {
-        case EN0_STARTPG:
-            s->start = val << 8;
-            break;
-        case EN0_STOPPG:
-            s->stop = val << 8;
-            break;
-        case EN0_BOUNDARY:
-            s->boundary = val;
-            break;
-        case EN0_IMR:
-            s->imr = val;
-            ne2000_update_irq(s);
-            break;
-        case EN0_TPSR:
-            s->tpsr = val;
-            break;
-        case EN0_TCNTLO:
-            s->tcnt = (s->tcnt & 0xff00) | val;
-            break;
-        case EN0_TCNTHI:
-            s->tcnt = (s->tcnt & 0x00ff) | (val << 8);
-            break;
-        case EN0_RSARLO:
-            s->rsar = (s->rsar & 0xff00) | val;
-            break;
-        case EN0_RSARHI:
-            s->rsar = (s->rsar & 0x00ff) | (val << 8);
-            break;
-        case EN0_RCNTLO:
-            s->rcnt = (s->rcnt & 0xff00) | val;
-            break;
-        case EN0_RCNTHI:
-            s->rcnt = (s->rcnt & 0x00ff) | (val << 8);
-            break;
-        case EN0_RXCR:
-            s->rxcr = val;
-            break;
-        case EN0_DCFG:
-            s->dcfg = val;
-            break;
-        case EN0_ISR:
-            s->isr &= ~(val & 0x7f);
-            ne2000_update_irq(s);
-            break;
-        case EN1_PHYS ... EN1_PHYS + 5:
-            s->phys[offset - EN1_PHYS] = val;
-            break;
-        case EN1_CURPAG:
-            s->curpag = val;
-            break;
-        case EN1_MULT ... EN1_MULT + 7:
-            s->mult[offset - EN1_MULT] = val;
-            break;
-        }
-    }
-}
-
-static uint32_t ne2000_ioport_read(void *opaque, uint32_t addr)
-{
-    NE2000State *s = opaque;
-    int offset, page, ret;
-
-    addr &= 0xf;
-    if (addr == E8390_CMD) {
-        ret = s->cmd;
-    } else {
-        page = s->cmd >> 6;
-        offset = addr | (page << 4);
-        switch(offset) {
-        case EN0_TSR:
-            ret = s->tsr;
-            break;
-        case EN0_BOUNDARY:
-            ret = s->boundary;
-            break;
-        case EN0_ISR:
-            ret = s->isr;
-            break;
-       case EN0_RSARLO:
-           ret = s->rsar & 0x00ff;
-           break;
-       case EN0_RSARHI:
-           ret = s->rsar >> 8;
-           break;
-        case EN1_PHYS ... EN1_PHYS + 5:
-            ret = s->phys[offset - EN1_PHYS];
-            break;
-        case EN1_CURPAG:
-            ret = s->curpag;
-            break;
-        case EN1_MULT ... EN1_MULT + 7:
-            ret = s->mult[offset - EN1_MULT];
-            break;
-        case EN0_RSR:
-            ret = s->rsr;
-            break;
-        case EN2_STARTPG:
-            ret = s->start >> 8;
-            break;
-        case EN2_STOPPG:
-            ret = s->stop >> 8;
-            break;
-       case EN0_RTL8029ID0:
-           ret = 0x50;
-           break;
-       case EN0_RTL8029ID1:
-           ret = 0x43;
-           break;
-       case EN3_CONFIG0:
-           ret = 0;            /* 10baseT media */
-           break;
-       case EN3_CONFIG2:
-           ret = 0x40;         /* 10baseT active */
-           break;
-       case EN3_CONFIG3:
-           ret = 0x40;         /* Full duplex */
-           break;
-        default:
-            ret = 0x00;
-            break;
-        }
-    }
-#ifdef DEBUG_NE2000
-    printf("NE2000: read addr=0x%x val=%02x\n", addr, ret);
-#endif
-    return ret;
-}
-
-static inline void ne2000_mem_writeb(NE2000State *s, uint32_t addr,
-                                     uint32_t val)
-{
-    if (addr < 32 ||
-        (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) {
-        s->mem[addr] = val;
-    }
-}
-
-static inline void ne2000_mem_writew(NE2000State *s, uint32_t addr,
-                                     uint32_t val)
-{
-    addr &= ~1; /* XXX: check exact behaviour if not even */
-    if (addr < 32 ||
-        (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) {
-        *(uint16_t *)(s->mem + addr) = cpu_to_le16(val);
-    }
-}
-
-static inline void ne2000_mem_writel(NE2000State *s, uint32_t addr,
-                                     uint32_t val)
-{
-    addr &= ~1; /* XXX: check exact behaviour if not even */
-    if (addr < 32 ||
-        (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) {
-        cpu_to_le32wu((uint32_t *)(s->mem + addr), val);
-    }
-}
-
-static inline uint32_t ne2000_mem_readb(NE2000State *s, uint32_t addr)
-{
-    if (addr < 32 ||
-        (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) {
-        return s->mem[addr];
-    } else {
-        return 0xff;
-    }
-}
-
-static inline uint32_t ne2000_mem_readw(NE2000State *s, uint32_t addr)
-{
-    addr &= ~1; /* XXX: check exact behaviour if not even */
-    if (addr < 32 ||
-        (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) {
-        return le16_to_cpu(*(uint16_t *)(s->mem + addr));
-    } else {
-        return 0xffff;
-    }
-}
-
-static inline uint32_t ne2000_mem_readl(NE2000State *s, uint32_t addr)
-{
-    addr &= ~1; /* XXX: check exact behaviour if not even */
-    if (addr < 32 ||
-        (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) {
-        return le32_to_cpupu((uint32_t *)(s->mem + addr));
-    } else {
-        return 0xffffffff;
-    }
-}
-
-static inline void ne2000_dma_update(NE2000State *s, int len)
-{
-    s->rsar += len;
-    /* wrap */
-    /* XXX: check what to do if rsar > stop */
-    if (s->rsar == s->stop)
-        s->rsar = s->start;
-
-    if (s->rcnt <= len) {
-        s->rcnt = 0;
-        /* signal end of transfer */
-        s->isr |= ENISR_RDC;
-        ne2000_update_irq(s);
-    } else {
-        s->rcnt -= len;
-    }
-}
-
-static void ne2000_asic_ioport_write(void *opaque, uint32_t addr, uint32_t val)
-{
-    NE2000State *s = opaque;
-
-#ifdef DEBUG_NE2000
-    printf("NE2000: asic write val=0x%04x\n", val);
-#endif
-    if (s->rcnt == 0)
-        return;
-    if (s->dcfg & 0x01) {
-        /* 16 bit access */
-        ne2000_mem_writew(s, s->rsar, val);
-        ne2000_dma_update(s, 2);
-    } else {
-        /* 8 bit access */
-        ne2000_mem_writeb(s, s->rsar, val);
-        ne2000_dma_update(s, 1);
-    }
-}
-
-static uint32_t ne2000_asic_ioport_read(void *opaque, uint32_t addr)
-{
-    NE2000State *s = opaque;
-    int ret;
-
-    if (s->dcfg & 0x01) {
-        /* 16 bit access */
-        ret = ne2000_mem_readw(s, s->rsar);
-        ne2000_dma_update(s, 2);
-    } else {
-        /* 8 bit access */
-        ret = ne2000_mem_readb(s, s->rsar);
-        ne2000_dma_update(s, 1);
-    }
-#ifdef DEBUG_NE2000
-    printf("NE2000: asic read val=0x%04x\n", ret);
-#endif
-    return ret;
-}
-
-static void ne2000_asic_ioport_writel(void *opaque, uint32_t addr, uint32_t val)
-{
-    NE2000State *s = opaque;
-
-#ifdef DEBUG_NE2000
-    printf("NE2000: asic writel val=0x%04x\n", val);
-#endif
-    if (s->rcnt == 0)
-        return;
-    /* 32 bit access */
-    ne2000_mem_writel(s, s->rsar, val);
-    ne2000_dma_update(s, 4);
-}
-
-static uint32_t ne2000_asic_ioport_readl(void *opaque, uint32_t addr)
-{
-    NE2000State *s = opaque;
-    int ret;
-
-    /* 32 bit access */
-    ret = ne2000_mem_readl(s, s->rsar);
-    ne2000_dma_update(s, 4);
-#ifdef DEBUG_NE2000
-    printf("NE2000: asic readl val=0x%04x\n", ret);
-#endif
-    return ret;
-}
-
-static void ne2000_reset_ioport_write(void *opaque, uint32_t addr, uint32_t val)
-{
-    /* nothing to do (end of reset pulse) */
-}
-
-static uint32_t ne2000_reset_ioport_read(void *opaque, uint32_t addr)
-{
-    NE2000State *s = opaque;
-    ne2000_reset(s);
-    return 0;
-}
-
-static int ne2000_post_load(void* opaque, int version_id)
-{
-    NE2000State* s = opaque;
-
-    if (version_id < 2) {
-        s->rxcr = 0x0c;
-    }
-    return 0;
-}
-
-const VMStateDescription vmstate_ne2000 = {
-    .name = "ne2000",
-    .version_id = 2,
-    .minimum_version_id = 0,
-    .minimum_version_id_old = 0,
-    .post_load = ne2000_post_load,
-    .fields      = (VMStateField []) {
-        VMSTATE_UINT8_V(rxcr, NE2000State, 2),
-        VMSTATE_UINT8(cmd, NE2000State),
-        VMSTATE_UINT32(start, NE2000State),
-        VMSTATE_UINT32(stop, NE2000State),
-        VMSTATE_UINT8(boundary, NE2000State),
-        VMSTATE_UINT8(tsr, NE2000State),
-        VMSTATE_UINT8(tpsr, NE2000State),
-        VMSTATE_UINT16(tcnt, NE2000State),
-        VMSTATE_UINT16(rcnt, NE2000State),
-        VMSTATE_UINT32(rsar, NE2000State),
-        VMSTATE_UINT8(rsr, NE2000State),
-        VMSTATE_UINT8(isr, NE2000State),
-        VMSTATE_UINT8(dcfg, NE2000State),
-        VMSTATE_UINT8(imr, NE2000State),
-        VMSTATE_BUFFER(phys, NE2000State),
-        VMSTATE_UINT8(curpag, NE2000State),
-        VMSTATE_BUFFER(mult, NE2000State),
-        VMSTATE_UNUSED(4), /* was irq */
-        VMSTATE_BUFFER(mem, NE2000State),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static const VMStateDescription vmstate_pci_ne2000 = {
-    .name = "ne2000",
-    .version_id = 3,
-    .minimum_version_id = 3,
-    .minimum_version_id_old = 3,
-    .fields      = (VMStateField []) {
-        VMSTATE_PCI_DEVICE(dev, PCINE2000State),
-        VMSTATE_STRUCT(ne2000, PCINE2000State, 0, vmstate_ne2000, NE2000State),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static uint64_t ne2000_read(void *opaque, hwaddr addr,
-                            unsigned size)
-{
-    NE2000State *s = opaque;
-
-    if (addr < 0x10 && size == 1) {
-        return ne2000_ioport_read(s, addr);
-    } else if (addr == 0x10) {
-        if (size <= 2) {
-            return ne2000_asic_ioport_read(s, addr);
-        } else {
-            return ne2000_asic_ioport_readl(s, addr);
-        }
-    } else if (addr == 0x1f && size == 1) {
-        return ne2000_reset_ioport_read(s, addr);
-    }
-    return ((uint64_t)1 << (size * 8)) - 1;
-}
-
-static void ne2000_write(void *opaque, hwaddr addr,
-                         uint64_t data, unsigned size)
-{
-    NE2000State *s = opaque;
-
-    if (addr < 0x10 && size == 1) {
-        ne2000_ioport_write(s, addr, data);
-    } else if (addr == 0x10) {
-        if (size <= 2) {
-            ne2000_asic_ioport_write(s, addr, data);
-        } else {
-            ne2000_asic_ioport_writel(s, addr, data);
-        }
-    } else if (addr == 0x1f && size == 1) {
-        ne2000_reset_ioport_write(s, addr, data);
-    }
-}
-
-static const MemoryRegionOps ne2000_ops = {
-    .read = ne2000_read,
-    .write = ne2000_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-/***********************************************************/
-/* PCI NE2000 definitions */
-
-void ne2000_setup_io(NE2000State *s, unsigned size)
-{
-    memory_region_init_io(&s->io, &ne2000_ops, s, "ne2000", size);
-}
-
-static void ne2000_cleanup(NetClientState *nc)
-{
-    NE2000State *s = qemu_get_nic_opaque(nc);
-
-    s->nic = NULL;
-}
-
-static NetClientInfo net_ne2000_info = {
-    .type = NET_CLIENT_OPTIONS_KIND_NIC,
-    .size = sizeof(NICState),
-    .can_receive = ne2000_can_receive,
-    .receive = ne2000_receive,
-    .cleanup = ne2000_cleanup,
-};
-
-static int pci_ne2000_init(PCIDevice *pci_dev)
-{
-    PCINE2000State *d = DO_UPCAST(PCINE2000State, dev, pci_dev);
-    NE2000State *s;
-    uint8_t *pci_conf;
-
-    pci_conf = d->dev.config;
-    pci_conf[PCI_INTERRUPT_PIN] = 1; /* interrupt pin A */
-
-    s = &d->ne2000;
-    ne2000_setup_io(s, 0x100);
-    pci_register_bar(&d->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io);
-    s->irq = d->dev.irq[0];
-
-    qemu_macaddr_default_if_unset(&s->c.macaddr);
-    ne2000_reset(s);
-
-    s->nic = qemu_new_nic(&net_ne2000_info, &s->c,
-                          object_get_typename(OBJECT(pci_dev)), pci_dev->qdev.id, s);
-    qemu_format_nic_info_str(qemu_get_queue(s->nic), s->c.macaddr.a);
-
-    add_boot_device_path(s->c.bootindex, &pci_dev->qdev, "/ethernet-phy@0");
-
-    return 0;
-}
-
-static void pci_ne2000_exit(PCIDevice *pci_dev)
-{
-    PCINE2000State *d = DO_UPCAST(PCINE2000State, dev, pci_dev);
-    NE2000State *s = &d->ne2000;
-
-    memory_region_destroy(&s->io);
-    qemu_del_nic(s->nic);
-}
-
-static Property ne2000_properties[] = {
-    DEFINE_NIC_PROPERTIES(PCINE2000State, ne2000.c),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void ne2000_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
-    k->init = pci_ne2000_init;
-    k->exit = pci_ne2000_exit;
-    k->romfile = "efi-ne2k_pci.rom",
-    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 const TypeInfo ne2000_info = {
-    .name          = "ne2k_pci",
-    .parent        = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(PCINE2000State),
-    .class_init    = ne2000_class_init,
-};
-
-static void ne2000_register_types(void)
-{
-    type_register_static(&ne2000_info);
-}
-
-type_init(ne2000_register_types)
diff --git a/hw/ne2000.h b/hw/ne2000.h
deleted file mode 100644 (file)
index b31ae03..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-#ifndef HW_NE2000_H
-#define HW_NE2000_H 1
-
-#define NE2000_PMEM_SIZE    (32*1024)
-#define NE2000_PMEM_START   (16*1024)
-#define NE2000_PMEM_END     (NE2000_PMEM_SIZE+NE2000_PMEM_START)
-#define NE2000_MEM_SIZE     NE2000_PMEM_END
-
-typedef struct NE2000State {
-    MemoryRegion io;
-    uint8_t cmd;
-    uint32_t start;
-    uint32_t stop;
-    uint8_t boundary;
-    uint8_t tsr;
-    uint8_t tpsr;
-    uint16_t tcnt;
-    uint16_t rcnt;
-    uint32_t rsar;
-    uint8_t rsr;
-    uint8_t rxcr;
-    uint8_t isr;
-    uint8_t dcfg;
-    uint8_t imr;
-    uint8_t phys[6]; /* mac address */
-    uint8_t curpag;
-    uint8_t mult[8]; /* multicast mask array */
-    qemu_irq irq;
-    NICState *nic;
-    NICConf c;
-    uint8_t mem[NE2000_MEM_SIZE];
-} NE2000State;
-
-void ne2000_setup_io(NE2000State *s, unsigned size);
-extern const VMStateDescription vmstate_ne2000;
-void ne2000_reset(NE2000State *s);
-int ne2000_can_receive(NetClientState *nc);
-ssize_t ne2000_receive(NetClientState *nc, const uint8_t *buf, size_t size_);
-
-#endif
diff --git a/hw/net/Makefile.objs b/hw/net/Makefile.objs
new file mode 100644 (file)
index 0000000..951cca3
--- /dev/null
@@ -0,0 +1,33 @@
+common-obj-$(CONFIG_DP8393X) += dp8393x.o
+common-obj-$(CONFIG_XEN_BACKEND) += xen_nic.o
+
+# PCI network cards
+common-obj-$(CONFIG_NE2000_PCI) += ne2000.o
+common-obj-$(CONFIG_EEPRO100_PCI) += eepro100.o
+common-obj-$(CONFIG_PCNET_PCI) += pcnet-pci.o
+common-obj-$(CONFIG_PCNET_COMMON) += pcnet.o
+common-obj-$(CONFIG_E1000_PCI) += e1000.o
+common-obj-$(CONFIG_RTL8139_PCI) += rtl8139.o
+common-obj-$(CONFIG_VMXNET3_PCI) += vmxnet_tx_pkt.o vmxnet_rx_pkt.o
+common-obj-$(CONFIG_VMXNET3_PCI) += vmxnet3.o
+
+common-obj-$(CONFIG_SMC91C111) += smc91c111.o
+common-obj-$(CONFIG_LAN9118) += lan9118.o
+common-obj-$(CONFIG_NE2000_ISA) += ne2000-isa.o
+common-obj-$(CONFIG_OPENCORES_ETH) += opencores_eth.o
+common-obj-$(CONFIG_XGMAC) += xgmac.o
+common-obj-$(CONFIG_MIPSNET) += mipsnet.o
+common-obj-$(CONFIG_XILINX_AXI) += xilinx_axienet.o
+
+common-obj-$(CONFIG_CADENCE) += cadence_gem.o
+common-obj-$(CONFIG_STELLARIS_ENET) += stellaris_enet.o
+common-obj-$(CONFIG_LANCE) += lance.o
+
+obj-$(CONFIG_ETRAXFS) += etraxfs_eth.o
+obj-$(CONFIG_COLDFIRE) += mcf_fec.o
+obj-$(CONFIG_MILKYMIST) += milkymist-minimac2.o
+obj-$(CONFIG_PSERIES) += spapr_llan.o
+obj-$(CONFIG_XILINX_ETHLITE) += xilinx_ethlite.o
+
+obj-$(CONFIG_VIRTIO) += virtio-net.o
+obj-y += vhost_net.o
diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c
new file mode 100644 (file)
index 0000000..e177057
--- /dev/null
@@ -0,0 +1,1219 @@
+/*
+ * QEMU Xilinx GEM emulation
+ *
+ * Copyright (c) 2011 Xilinx, 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 <zlib.h> /* For crc32 */
+
+#include "hw/sysbus.h"
+#include "net/net.h"
+#include "net/checksum.h"
+
+#ifdef CADENCE_GEM_ERR_DEBUG
+#define DB_PRINT(...) do { \
+    fprintf(stderr,  ": %s: ", __func__); \
+    fprintf(stderr, ## __VA_ARGS__); \
+    } while (0);
+#else
+    #define DB_PRINT(...)
+#endif
+
+#define GEM_NWCTRL        (0x00000000/4) /* Network Control reg */
+#define GEM_NWCFG         (0x00000004/4) /* Network Config reg */
+#define GEM_NWSTATUS      (0x00000008/4) /* Network Status reg */
+#define GEM_USERIO        (0x0000000C/4) /* User IO reg */
+#define GEM_DMACFG        (0x00000010/4) /* DMA Control reg */
+#define GEM_TXSTATUS      (0x00000014/4) /* TX Status reg */
+#define GEM_RXQBASE       (0x00000018/4) /* RX Q Base address reg */
+#define GEM_TXQBASE       (0x0000001C/4) /* TX Q Base address reg */
+#define GEM_RXSTATUS      (0x00000020/4) /* RX Status reg */
+#define GEM_ISR           (0x00000024/4) /* Interrupt Status reg */
+#define GEM_IER           (0x00000028/4) /* Interrupt Enable reg */
+#define GEM_IDR           (0x0000002C/4) /* Interrupt Disable reg */
+#define GEM_IMR           (0x00000030/4) /* Interrupt Mask reg */
+#define GEM_PHYMNTNC      (0x00000034/4) /* Phy Maintaince reg */
+#define GEM_RXPAUSE       (0x00000038/4) /* RX Pause Time reg */
+#define GEM_TXPAUSE       (0x0000003C/4) /* TX Pause Time reg */
+#define GEM_TXPARTIALSF   (0x00000040/4) /* TX Partial Store and Forward */
+#define GEM_RXPARTIALSF   (0x00000044/4) /* RX Partial Store and Forward */
+#define GEM_HASHLO        (0x00000080/4) /* Hash Low address reg */
+#define GEM_HASHHI        (0x00000084/4) /* Hash High address reg */
+#define GEM_SPADDR1LO     (0x00000088/4) /* Specific addr 1 low reg */
+#define GEM_SPADDR1HI     (0x0000008C/4) /* Specific addr 1 high reg */
+#define GEM_SPADDR2LO     (0x00000090/4) /* Specific addr 2 low reg */
+#define GEM_SPADDR2HI     (0x00000094/4) /* Specific addr 2 high reg */
+#define GEM_SPADDR3LO     (0x00000098/4) /* Specific addr 3 low reg */
+#define GEM_SPADDR3HI     (0x0000009C/4) /* Specific addr 3 high reg */
+#define GEM_SPADDR4LO     (0x000000A0/4) /* Specific addr 4 low reg */
+#define GEM_SPADDR4HI     (0x000000A4/4) /* Specific addr 4 high reg */
+#define GEM_TIDMATCH1     (0x000000A8/4) /* Type ID1 Match reg */
+#define GEM_TIDMATCH2     (0x000000AC/4) /* Type ID2 Match reg */
+#define GEM_TIDMATCH3     (0x000000B0/4) /* Type ID3 Match reg */
+#define GEM_TIDMATCH4     (0x000000B4/4) /* Type ID4 Match reg */
+#define GEM_WOLAN         (0x000000B8/4) /* Wake on LAN reg */
+#define GEM_IPGSTRETCH    (0x000000BC/4) /* IPG Stretch reg */
+#define GEM_SVLAN         (0x000000C0/4) /* Stacked VLAN reg */
+#define GEM_MODID         (0x000000FC/4) /* Module ID reg */
+#define GEM_OCTTXLO       (0x00000100/4) /* Octects transmitted Low reg */
+#define GEM_OCTTXHI       (0x00000104/4) /* Octects transmitted High reg */
+#define GEM_TXCNT         (0x00000108/4) /* Error-free Frames transmitted */
+#define GEM_TXBCNT        (0x0000010C/4) /* Error-free Broadcast Frames */
+#define GEM_TXMCNT        (0x00000110/4) /* Error-free Multicast Frame */
+#define GEM_TXPAUSECNT    (0x00000114/4) /* Pause Frames Transmitted */
+#define GEM_TX64CNT       (0x00000118/4) /* Error-free 64 TX */
+#define GEM_TX65CNT       (0x0000011C/4) /* Error-free 65-127 TX */
+#define GEM_TX128CNT      (0x00000120/4) /* Error-free 128-255 TX */
+#define GEM_TX256CNT      (0x00000124/4) /* Error-free 256-511 */
+#define GEM_TX512CNT      (0x00000128/4) /* Error-free 512-1023 TX */
+#define GEM_TX1024CNT     (0x0000012C/4) /* Error-free 1024-1518 TX */
+#define GEM_TX1519CNT     (0x00000130/4) /* Error-free larger than 1519 TX */
+#define GEM_TXURUNCNT     (0x00000134/4) /* TX under run error counter */
+#define GEM_SINGLECOLLCNT (0x00000138/4) /* Single Collision Frames */
+#define GEM_MULTCOLLCNT   (0x0000013C/4) /* Multiple Collision Frames */
+#define GEM_EXCESSCOLLCNT (0x00000140/4) /* Excessive Collision Frames */
+#define GEM_LATECOLLCNT   (0x00000144/4) /* Late Collision Frames */
+#define GEM_DEFERTXCNT    (0x00000148/4) /* Deferred Transmission Frames */
+#define GEM_CSENSECNT     (0x0000014C/4) /* Carrier Sense Error Counter */
+#define GEM_OCTRXLO       (0x00000150/4) /* Octects Received register Low */
+#define GEM_OCTRXHI       (0x00000154/4) /* Octects Received register High */
+#define GEM_RXCNT         (0x00000158/4) /* Error-free Frames Received */
+#define GEM_RXBROADCNT    (0x0000015C/4) /* Error-free Broadcast Frames RX */
+#define GEM_RXMULTICNT    (0x00000160/4) /* Error-free Multicast Frames RX */
+#define GEM_RXPAUSECNT    (0x00000164/4) /* Pause Frames Received Counter */
+#define GEM_RX64CNT       (0x00000168/4) /* Error-free 64 byte Frames RX */
+#define GEM_RX65CNT       (0x0000016C/4) /* Error-free 65-127B Frames RX */
+#define GEM_RX128CNT      (0x00000170/4) /* Error-free 128-255B Frames RX */
+#define GEM_RX256CNT      (0x00000174/4) /* Error-free 256-512B Frames RX */
+#define GEM_RX512CNT      (0x00000178/4) /* Error-free 512-1023B Frames RX */
+#define GEM_RX1024CNT     (0x0000017C/4) /* Error-free 1024-1518B Frames RX */
+#define GEM_RX1519CNT     (0x00000180/4) /* Error-free 1519-max Frames RX */
+#define GEM_RXUNDERCNT    (0x00000184/4) /* Undersize Frames Received */
+#define GEM_RXOVERCNT     (0x00000188/4) /* Oversize Frames Received */
+#define GEM_RXJABCNT      (0x0000018C/4) /* Jabbers Received Counter */
+#define GEM_RXFCSCNT      (0x00000190/4) /* Frame Check seq. Error Counter */
+#define GEM_RXLENERRCNT   (0x00000194/4) /* Length Field Error Counter */
+#define GEM_RXSYMERRCNT   (0x00000198/4) /* Symbol Error Counter */
+#define GEM_RXALIGNERRCNT (0x0000019C/4) /* Alignment Error Counter */
+#define GEM_RXRSCERRCNT   (0x000001A0/4) /* Receive Resource Error Counter */
+#define GEM_RXORUNCNT     (0x000001A4/4) /* Receive Overrun Counter */
+#define GEM_RXIPCSERRCNT  (0x000001A8/4) /* IP header Checksum Error Counter */
+#define GEM_RXTCPCCNT     (0x000001AC/4) /* TCP Checksum Error Counter */
+#define GEM_RXUDPCCNT     (0x000001B0/4) /* UDP Checksum Error Counter */
+
+#define GEM_1588S         (0x000001D0/4) /* 1588 Timer Seconds */
+#define GEM_1588NS        (0x000001D4/4) /* 1588 Timer Nanoseconds */
+#define GEM_1588ADJ       (0x000001D8/4) /* 1588 Timer Adjust */
+#define GEM_1588INC       (0x000001DC/4) /* 1588 Timer Increment */
+#define GEM_PTPETXS       (0x000001E0/4) /* PTP Event Frame Transmitted (s) */
+#define GEM_PTPETXNS      (0x000001E4/4) /* PTP Event Frame Transmitted (ns) */
+#define GEM_PTPERXS       (0x000001E8/4) /* PTP Event Frame Received (s) */
+#define GEM_PTPERXNS      (0x000001EC/4) /* PTP Event Frame Received (ns) */
+#define GEM_PTPPTXS       (0x000001E0/4) /* PTP Peer Frame Transmitted (s) */
+#define GEM_PTPPTXNS      (0x000001E4/4) /* PTP Peer Frame Transmitted (ns) */
+#define GEM_PTPPRXS       (0x000001E8/4) /* PTP Peer Frame Received (s) */
+#define GEM_PTPPRXNS      (0x000001EC/4) /* PTP Peer Frame Received (ns) */
+
+/* Design Configuration Registers */
+#define GEM_DESCONF       (0x00000280/4)
+#define GEM_DESCONF2      (0x00000284/4)
+#define GEM_DESCONF3      (0x00000288/4)
+#define GEM_DESCONF4      (0x0000028C/4)
+#define GEM_DESCONF5      (0x00000290/4)
+#define GEM_DESCONF6      (0x00000294/4)
+#define GEM_DESCONF7      (0x00000298/4)
+
+#define GEM_MAXREG        (0x00000640/4) /* Last valid GEM address */
+
+/*****************************************/
+#define GEM_NWCTRL_TXSTART     0x00000200 /* Transmit Enable */
+#define GEM_NWCTRL_TXENA       0x00000008 /* Transmit Enable */
+#define GEM_NWCTRL_RXENA       0x00000004 /* Receive Enable */
+#define GEM_NWCTRL_LOCALLOOP   0x00000002 /* Local Loopback */
+
+#define GEM_NWCFG_STRIP_FCS    0x00020000 /* Strip FCS field */
+#define GEM_NWCFG_LERR_DISC    0x00010000 /* Discard RX frames with lenth err */
+#define GEM_NWCFG_BUFF_OFST_M  0x0000C000 /* Receive buffer offset mask */
+#define GEM_NWCFG_BUFF_OFST_S  14         /* Receive buffer offset shift */
+#define GEM_NWCFG_UCAST_HASH   0x00000080 /* accept unicast if hash match */
+#define GEM_NWCFG_MCAST_HASH   0x00000040 /* accept multicast if hash match */
+#define GEM_NWCFG_BCAST_REJ    0x00000020 /* Reject broadcast packets */
+#define GEM_NWCFG_PROMISC      0x00000010 /* Accept all packets */
+
+#define GEM_DMACFG_RBUFSZ_M    0x007F0000 /* DMA RX Buffer Size mask */
+#define GEM_DMACFG_RBUFSZ_S    16         /* DMA RX Buffer Size shift */
+#define GEM_DMACFG_RBUFSZ_MUL  64         /* DMA RX Buffer Size multiplier */
+#define GEM_DMACFG_TXCSUM_OFFL 0x00000800 /* Transmit checksum offload */
+
+#define GEM_TXSTATUS_TXCMPL    0x00000020 /* Transmit Complete */
+#define GEM_TXSTATUS_USED      0x00000001 /* sw owned descriptor encountered */
+
+#define GEM_RXSTATUS_FRMRCVD   0x00000002 /* Frame received */
+#define GEM_RXSTATUS_NOBUF     0x00000001 /* Buffer unavailable */
+
+/* GEM_ISR GEM_IER GEM_IDR GEM_IMR */
+#define GEM_INT_TXCMPL        0x00000080 /* Transmit Complete */
+#define GEM_INT_TXUSED         0x00000008
+#define GEM_INT_RXUSED         0x00000004
+#define GEM_INT_RXCMPL        0x00000002
+
+#define GEM_PHYMNTNC_OP_R      0x20000000 /* read operation */
+#define GEM_PHYMNTNC_OP_W      0x10000000 /* write operation */
+#define GEM_PHYMNTNC_ADDR      0x0F800000 /* Address bits */
+#define GEM_PHYMNTNC_ADDR_SHFT 23
+#define GEM_PHYMNTNC_REG       0x007C0000 /* register bits */
+#define GEM_PHYMNTNC_REG_SHIFT 18
+
+/* Marvell PHY definitions */
+#define BOARD_PHY_ADDRESS    23 /* PHY address we will emulate a device at */
+
+#define PHY_REG_CONTROL      0
+#define PHY_REG_STATUS       1
+#define PHY_REG_PHYID1       2
+#define PHY_REG_PHYID2       3
+#define PHY_REG_ANEGADV      4
+#define PHY_REG_LINKPABIL    5
+#define PHY_REG_ANEGEXP      6
+#define PHY_REG_NEXTP        7
+#define PHY_REG_LINKPNEXTP   8
+#define PHY_REG_100BTCTRL    9
+#define PHY_REG_1000BTSTAT   10
+#define PHY_REG_EXTSTAT      15
+#define PHY_REG_PHYSPCFC_CTL 16
+#define PHY_REG_PHYSPCFC_ST  17
+#define PHY_REG_INT_EN       18
+#define PHY_REG_INT_ST       19
+#define PHY_REG_EXT_PHYSPCFC_CTL  20
+#define PHY_REG_RXERR        21
+#define PHY_REG_EACD         22
+#define PHY_REG_LED          24
+#define PHY_REG_LED_OVRD     25
+#define PHY_REG_EXT_PHYSPCFC_CTL2 26
+#define PHY_REG_EXT_PHYSPCFC_ST   27
+#define PHY_REG_CABLE_DIAG   28
+
+#define PHY_REG_CONTROL_RST  0x8000
+#define PHY_REG_CONTROL_LOOP 0x4000
+#define PHY_REG_CONTROL_ANEG 0x1000
+
+#define PHY_REG_STATUS_LINK     0x0004
+#define PHY_REG_STATUS_ANEGCMPL 0x0020
+
+#define PHY_REG_INT_ST_ANEGCMPL 0x0800
+#define PHY_REG_INT_ST_LINKC    0x0400
+#define PHY_REG_INT_ST_ENERGY   0x0010
+
+/***********************************************************************/
+#define GEM_RX_REJECT  1
+#define GEM_RX_ACCEPT  0
+
+/***********************************************************************/
+
+#define DESC_1_USED 0x80000000
+#define DESC_1_LENGTH 0x00001FFF
+
+#define DESC_1_TX_WRAP 0x40000000
+#define DESC_1_TX_LAST 0x00008000
+
+#define DESC_0_RX_WRAP 0x00000002
+#define DESC_0_RX_OWNERSHIP 0x00000001
+
+#define DESC_1_RX_SOF 0x00004000
+#define DESC_1_RX_EOF 0x00008000
+
+static inline unsigned tx_desc_get_buffer(unsigned *desc)
+{
+    return desc[0];
+}
+
+static inline unsigned tx_desc_get_used(unsigned *desc)
+{
+    return (desc[1] & DESC_1_USED) ? 1 : 0;
+}
+
+static inline void tx_desc_set_used(unsigned *desc)
+{
+    desc[1] |= DESC_1_USED;
+}
+
+static inline unsigned tx_desc_get_wrap(unsigned *desc)
+{
+    return (desc[1] & DESC_1_TX_WRAP) ? 1 : 0;
+}
+
+static inline unsigned tx_desc_get_last(unsigned *desc)
+{
+    return (desc[1] & DESC_1_TX_LAST) ? 1 : 0;
+}
+
+static inline unsigned tx_desc_get_length(unsigned *desc)
+{
+    return desc[1] & DESC_1_LENGTH;
+}
+
+static inline void print_gem_tx_desc(unsigned *desc)
+{
+    DB_PRINT("TXDESC:\n");
+    DB_PRINT("bufaddr: 0x%08x\n", *desc);
+    DB_PRINT("used_hw: %d\n", tx_desc_get_used(desc));
+    DB_PRINT("wrap:    %d\n", tx_desc_get_wrap(desc));
+    DB_PRINT("last:    %d\n", tx_desc_get_last(desc));
+    DB_PRINT("length:  %d\n", tx_desc_get_length(desc));
+}
+
+static inline unsigned rx_desc_get_buffer(unsigned *desc)
+{
+    return desc[0] & ~0x3UL;
+}
+
+static inline unsigned rx_desc_get_wrap(unsigned *desc)
+{
+    return desc[0] & DESC_0_RX_WRAP ? 1 : 0;
+}
+
+static inline unsigned rx_desc_get_ownership(unsigned *desc)
+{
+    return desc[0] & DESC_0_RX_OWNERSHIP ? 1 : 0;
+}
+
+static inline void rx_desc_set_ownership(unsigned *desc)
+{
+    desc[0] |= DESC_0_RX_OWNERSHIP;
+}
+
+static inline void rx_desc_set_sof(unsigned *desc)
+{
+    desc[1] |= DESC_1_RX_SOF;
+}
+
+static inline void rx_desc_set_eof(unsigned *desc)
+{
+    desc[1] |= DESC_1_RX_EOF;
+}
+
+static inline void rx_desc_set_length(unsigned *desc, unsigned len)
+{
+    desc[1] &= ~DESC_1_LENGTH;
+    desc[1] |= len;
+}
+
+typedef struct {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    NICState *nic;
+    NICConf conf;
+    qemu_irq irq;
+
+    /* GEM registers backing store */
+    uint32_t regs[GEM_MAXREG];
+    /* Mask of register bits which are write only */
+    uint32_t regs_wo[GEM_MAXREG];
+    /* Mask of register bits which are read only */
+    uint32_t regs_ro[GEM_MAXREG];
+    /* Mask of register bits which are clear on read */
+    uint32_t regs_rtc[GEM_MAXREG];
+    /* Mask of register bits which are write 1 to clear */
+    uint32_t regs_w1c[GEM_MAXREG];
+
+    /* PHY registers backing store */
+    uint16_t phy_regs[32];
+
+    uint8_t phy_loop; /* Are we in phy loopback? */
+
+    /* The current DMA descriptor pointers */
+    uint32_t rx_desc_addr;
+    uint32_t tx_desc_addr;
+
+} GemState;
+
+/* The broadcast MAC address: 0xFFFFFFFFFFFF */
+const uint8_t broadcast_addr[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+
+/*
+ * gem_init_register_masks:
+ * One time initialization.
+ * Set masks to identify which register bits have magical clear properties
+ */
+static void gem_init_register_masks(GemState *s)
+{
+    /* Mask of register bits which are read only*/
+    memset(&s->regs_ro[0], 0, sizeof(s->regs_ro));
+    s->regs_ro[GEM_NWCTRL]   = 0xFFF80000;
+    s->regs_ro[GEM_NWSTATUS] = 0xFFFFFFFF;
+    s->regs_ro[GEM_DMACFG]   = 0xFE00F000;
+    s->regs_ro[GEM_TXSTATUS] = 0xFFFFFE08;
+    s->regs_ro[GEM_RXQBASE]  = 0x00000003;
+    s->regs_ro[GEM_TXQBASE]  = 0x00000003;
+    s->regs_ro[GEM_RXSTATUS] = 0xFFFFFFF0;
+    s->regs_ro[GEM_ISR]      = 0xFFFFFFFF;
+    s->regs_ro[GEM_IMR]      = 0xFFFFFFFF;
+    s->regs_ro[GEM_MODID]    = 0xFFFFFFFF;
+
+    /* Mask of register bits which are clear on read */
+    memset(&s->regs_rtc[0], 0, sizeof(s->regs_rtc));
+    s->regs_rtc[GEM_ISR]      = 0xFFFFFFFF;
+
+    /* Mask of register bits which are write 1 to clear */
+    memset(&s->regs_w1c[0], 0, sizeof(s->regs_w1c));
+    s->regs_w1c[GEM_TXSTATUS] = 0x000001F7;
+    s->regs_w1c[GEM_RXSTATUS] = 0x0000000F;
+
+    /* Mask of register bits which are write only */
+    memset(&s->regs_wo[0], 0, sizeof(s->regs_wo));
+    s->regs_wo[GEM_NWCTRL]   = 0x00073E60;
+    s->regs_wo[GEM_IER]      = 0x07FFFFFF;
+    s->regs_wo[GEM_IDR]      = 0x07FFFFFF;
+}
+
+/*
+ * phy_update_link:
+ * Make the emulated PHY link state match the QEMU "interface" state.
+ */
+static void phy_update_link(GemState *s)
+{
+    DB_PRINT("down %d\n", qemu_get_queue(s->nic)->link_down);
+
+    /* Autonegotiation status mirrors link status.  */
+    if (qemu_get_queue(s->nic)->link_down) {
+        s->phy_regs[PHY_REG_STATUS] &= ~(PHY_REG_STATUS_ANEGCMPL |
+                                         PHY_REG_STATUS_LINK);
+        s->phy_regs[PHY_REG_INT_ST] |= PHY_REG_INT_ST_LINKC;
+    } else {
+        s->phy_regs[PHY_REG_STATUS] |= (PHY_REG_STATUS_ANEGCMPL |
+                                         PHY_REG_STATUS_LINK);
+        s->phy_regs[PHY_REG_INT_ST] |= (PHY_REG_INT_ST_LINKC |
+                                        PHY_REG_INT_ST_ANEGCMPL |
+                                        PHY_REG_INT_ST_ENERGY);
+    }
+}
+
+static int gem_can_receive(NetClientState *nc)
+{
+    GemState *s;
+
+    s = qemu_get_nic_opaque(nc);
+
+    DB_PRINT("\n");
+
+    /* Do nothing if receive is not enabled. */
+    if (!(s->regs[GEM_NWCTRL] & GEM_NWCTRL_RXENA)) {
+        return 0;
+    }
+
+    return 1;
+}
+
+/*
+ * gem_update_int_status:
+ * Raise or lower interrupt based on current status.
+ */
+static void gem_update_int_status(GemState *s)
+{
+    if (s->regs[GEM_ISR]) {
+        DB_PRINT("asserting int. (0x%08x)\n", s->regs[GEM_ISR]);
+        qemu_set_irq(s->irq, 1);
+    }
+}
+
+/*
+ * gem_receive_updatestats:
+ * Increment receive statistics.
+ */
+static void gem_receive_updatestats(GemState *s, const uint8_t *packet,
+                                    unsigned bytes)
+{
+    uint64_t octets;
+
+    /* Total octets (bytes) received */
+    octets = ((uint64_t)(s->regs[GEM_OCTRXLO]) << 32) |
+             s->regs[GEM_OCTRXHI];
+    octets += bytes;
+    s->regs[GEM_OCTRXLO] = octets >> 32;
+    s->regs[GEM_OCTRXHI] = octets;
+
+    /* Error-free Frames received */
+    s->regs[GEM_RXCNT]++;
+
+    /* Error-free Broadcast Frames counter */
+    if (!memcmp(packet, broadcast_addr, 6)) {
+        s->regs[GEM_RXBROADCNT]++;
+    }
+
+    /* Error-free Multicast Frames counter */
+    if (packet[0] == 0x01) {
+        s->regs[GEM_RXMULTICNT]++;
+    }
+
+    if (bytes <= 64) {
+        s->regs[GEM_RX64CNT]++;
+    } else if (bytes <= 127) {
+        s->regs[GEM_RX65CNT]++;
+    } else if (bytes <= 255) {
+        s->regs[GEM_RX128CNT]++;
+    } else if (bytes <= 511) {
+        s->regs[GEM_RX256CNT]++;
+    } else if (bytes <= 1023) {
+        s->regs[GEM_RX512CNT]++;
+    } else if (bytes <= 1518) {
+        s->regs[GEM_RX1024CNT]++;
+    } else {
+        s->regs[GEM_RX1519CNT]++;
+    }
+}
+
+/*
+ * Get the MAC Address bit from the specified position
+ */
+static unsigned get_bit(const uint8_t *mac, unsigned bit)
+{
+    unsigned byte;
+
+    byte = mac[bit / 8];
+    byte >>= (bit & 0x7);
+    byte &= 1;
+
+    return byte;
+}
+
+/*
+ * Calculate a GEM MAC Address hash index
+ */
+static unsigned calc_mac_hash(const uint8_t *mac)
+{
+    int index_bit, mac_bit;
+    unsigned hash_index;
+
+    hash_index = 0;
+    mac_bit = 5;
+    for (index_bit = 5; index_bit >= 0; index_bit--) {
+        hash_index |= (get_bit(mac,  mac_bit) ^
+                               get_bit(mac, mac_bit + 6) ^
+                               get_bit(mac, mac_bit + 12) ^
+                               get_bit(mac, mac_bit + 18) ^
+                               get_bit(mac, mac_bit + 24) ^
+                               get_bit(mac, mac_bit + 30) ^
+                               get_bit(mac, mac_bit + 36) ^
+                               get_bit(mac, mac_bit + 42)) << index_bit;
+        mac_bit--;
+    }
+
+    return hash_index;
+}
+
+/*
+ * gem_mac_address_filter:
+ * Accept or reject this destination address?
+ * Returns:
+ * GEM_RX_REJECT: reject
+ * GEM_RX_ACCEPT: accept
+ */
+static int gem_mac_address_filter(GemState *s, const uint8_t *packet)
+{
+    uint8_t *gem_spaddr;
+    int i;
+
+    /* Promiscuous mode? */
+    if (s->regs[GEM_NWCFG] & GEM_NWCFG_PROMISC) {
+        return GEM_RX_ACCEPT;
+    }
+
+    if (!memcmp(packet, broadcast_addr, 6)) {
+        /* Reject broadcast packets? */
+        if (s->regs[GEM_NWCFG] & GEM_NWCFG_BCAST_REJ) {
+            return GEM_RX_REJECT;
+        }
+        return GEM_RX_ACCEPT;
+    }
+
+    /* Accept packets -w- hash match? */
+    if ((packet[0] == 0x01 && (s->regs[GEM_NWCFG] & GEM_NWCFG_MCAST_HASH)) ||
+        (packet[0] != 0x01 && (s->regs[GEM_NWCFG] & GEM_NWCFG_UCAST_HASH))) {
+        unsigned hash_index;
+
+        hash_index = calc_mac_hash(packet);
+        if (hash_index < 32) {
+            if (s->regs[GEM_HASHLO] & (1<<hash_index)) {
+                return GEM_RX_ACCEPT;
+            }
+        } else {
+            hash_index -= 32;
+            if (s->regs[GEM_HASHHI] & (1<<hash_index)) {
+                return GEM_RX_ACCEPT;
+            }
+        }
+    }
+
+    /* Check all 4 specific addresses */
+    gem_spaddr = (uint8_t *)&(s->regs[GEM_SPADDR1LO]);
+    for (i = 0; i < 4; i++) {
+        if (!memcmp(packet, gem_spaddr, 6)) {
+            return GEM_RX_ACCEPT;
+        }
+
+        gem_spaddr += 8;
+    }
+
+    /* No address match; reject the packet */
+    return GEM_RX_REJECT;
+}
+
+/*
+ * gem_receive:
+ * Fit a packet handed to us by QEMU into the receive descriptor ring.
+ */
+static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size)
+{
+    unsigned    desc[2];
+    hwaddr packet_desc_addr, last_desc_addr;
+    GemState *s;
+    unsigned   rxbufsize, bytes_to_copy;
+    unsigned   rxbuf_offset;
+    uint8_t    rxbuf[2048];
+    uint8_t   *rxbuf_ptr;
+
+    s = qemu_get_nic_opaque(nc);
+
+    /* Do nothing if receive is not enabled. */
+    if (!gem_can_receive(nc)) {
+        return -1;
+    }
+
+    /* Is this destination MAC address "for us" ? */
+    if (gem_mac_address_filter(s, buf) == GEM_RX_REJECT) {
+        return -1;
+    }
+
+    /* Discard packets with receive length error enabled ? */
+    if (s->regs[GEM_NWCFG] & GEM_NWCFG_LERR_DISC) {
+        unsigned type_len;
+
+        /* Fish the ethertype / length field out of the RX packet */
+        type_len = buf[12] << 8 | buf[13];
+        /* It is a length field, not an ethertype */
+        if (type_len < 0x600) {
+            if (size < type_len) {
+                /* discard */
+                return -1;
+            }
+        }
+    }
+
+    /*
+     * Determine configured receive buffer offset (probably 0)
+     */
+    rxbuf_offset = (s->regs[GEM_NWCFG] & GEM_NWCFG_BUFF_OFST_M) >>
+                   GEM_NWCFG_BUFF_OFST_S;
+
+    /* The configure size of each receive buffer.  Determines how many
+     * buffers needed to hold this packet.
+     */
+    rxbufsize = ((s->regs[GEM_DMACFG] & GEM_DMACFG_RBUFSZ_M) >>
+                 GEM_DMACFG_RBUFSZ_S) * GEM_DMACFG_RBUFSZ_MUL;
+    bytes_to_copy = size;
+
+    /* Strip of FCS field ? (usually yes) */
+    if (s->regs[GEM_NWCFG] & GEM_NWCFG_STRIP_FCS) {
+        rxbuf_ptr = (void *)buf;
+    } else {
+        unsigned crc_val;
+        int      crc_offset;
+
+        /* The application wants the FCS field, which QEMU does not provide.
+         * We must try and caclculate one.
+         */
+
+        memcpy(rxbuf, buf, size);
+        memset(rxbuf + size, 0, sizeof(rxbuf) - size);
+        rxbuf_ptr = rxbuf;
+        crc_val = cpu_to_le32(crc32(0, rxbuf, MAX(size, 60)));
+        if (size < 60) {
+            crc_offset = 60;
+        } else {
+            crc_offset = size;
+        }
+        memcpy(rxbuf + crc_offset, &crc_val, sizeof(crc_val));
+
+        bytes_to_copy += 4;
+        size += 4;
+    }
+
+    /* Pad to minimum length */
+    if (size < 64) {
+        size = 64;
+    }
+
+    DB_PRINT("config bufsize: %d packet size: %ld\n", rxbufsize, size);
+
+    packet_desc_addr = s->rx_desc_addr;
+    while (1) {
+        DB_PRINT("read descriptor 0x%x\n", (unsigned)packet_desc_addr);
+        /* read current descriptor */
+        cpu_physical_memory_read(packet_desc_addr,
+                                 (uint8_t *)&desc[0], sizeof(desc));
+
+        /* Descriptor owned by software ? */
+        if (rx_desc_get_ownership(desc) == 1) {
+            DB_PRINT("descriptor 0x%x owned by sw.\n",
+                     (unsigned)packet_desc_addr);
+            s->regs[GEM_RXSTATUS] |= GEM_RXSTATUS_NOBUF;
+            s->regs[GEM_ISR] |= GEM_INT_RXUSED & ~(s->regs[GEM_IMR]);
+            /* Handle interrupt consequences */
+            gem_update_int_status(s);
+            return -1;
+        }
+
+        DB_PRINT("copy %d bytes to 0x%x\n", MIN(bytes_to_copy, rxbufsize),
+                rx_desc_get_buffer(desc));
+
+        /*
+         * Let's have QEMU lend a helping hand.
+         */
+        if (rx_desc_get_buffer(desc) == 0) {
+            DB_PRINT("Invalid RX buffer (NULL) for descriptor 0x%x\n",
+                     (unsigned)packet_desc_addr);
+            break;
+        }
+
+        /* Copy packet data to emulated DMA buffer */
+        cpu_physical_memory_write(rx_desc_get_buffer(desc) + rxbuf_offset,
+                                  rxbuf_ptr, MIN(bytes_to_copy, rxbufsize));
+        bytes_to_copy -= MIN(bytes_to_copy, rxbufsize);
+        rxbuf_ptr += MIN(bytes_to_copy, rxbufsize);
+        if (bytes_to_copy == 0) {
+            break;
+        }
+
+        /* Next descriptor */
+        if (rx_desc_get_wrap(desc)) {
+            packet_desc_addr = s->regs[GEM_RXQBASE];
+        } else {
+            packet_desc_addr += 8;
+        }
+    }
+
+    DB_PRINT("set length: %ld, EOF on descriptor 0x%x\n", size,
+            (unsigned)packet_desc_addr);
+
+    /* Update last descriptor with EOF and total length */
+    rx_desc_set_eof(desc);
+    rx_desc_set_length(desc, size);
+    cpu_physical_memory_write(packet_desc_addr,
+                              (uint8_t *)&desc[0], sizeof(desc));
+
+    /* Advance RX packet descriptor Q */
+    last_desc_addr = packet_desc_addr;
+    packet_desc_addr = s->rx_desc_addr;
+    s->rx_desc_addr = last_desc_addr;
+    if (rx_desc_get_wrap(desc)) {
+        s->rx_desc_addr = s->regs[GEM_RXQBASE];
+        DB_PRINT("wrapping RX descriptor list\n");
+    } else {
+        DB_PRINT("incrementing RX descriptor list\n");
+        s->rx_desc_addr += 8;
+    }
+
+    DB_PRINT("set SOF, OWN on descriptor 0x%08x\n", (unsigned)packet_desc_addr);
+
+    /* Count it */
+    gem_receive_updatestats(s, buf, size);
+
+    /* Update first descriptor (which could also be the last) */
+    /* read descriptor */
+    cpu_physical_memory_read(packet_desc_addr,
+                             (uint8_t *)&desc[0], sizeof(desc));
+    rx_desc_set_sof(desc);
+    rx_desc_set_ownership(desc);
+    cpu_physical_memory_write(packet_desc_addr,
+                              (uint8_t *)&desc[0], sizeof(desc));
+
+    s->regs[GEM_RXSTATUS] |= GEM_RXSTATUS_FRMRCVD;
+    s->regs[GEM_ISR] |= GEM_INT_RXCMPL & ~(s->regs[GEM_IMR]);
+
+    /* Handle interrupt consequences */
+    gem_update_int_status(s);
+
+    return size;
+}
+
+/*
+ * gem_transmit_updatestats:
+ * Increment transmit statistics.
+ */
+static void gem_transmit_updatestats(GemState *s, const uint8_t *packet,
+                                     unsigned bytes)
+{
+    uint64_t octets;
+
+    /* Total octets (bytes) transmitted */
+    octets = ((uint64_t)(s->regs[GEM_OCTTXLO]) << 32) |
+             s->regs[GEM_OCTTXHI];
+    octets += bytes;
+    s->regs[GEM_OCTTXLO] = octets >> 32;
+    s->regs[GEM_OCTTXHI] = octets;
+
+    /* Error-free Frames transmitted */
+    s->regs[GEM_TXCNT]++;
+
+    /* Error-free Broadcast Frames counter */
+    if (!memcmp(packet, broadcast_addr, 6)) {
+        s->regs[GEM_TXBCNT]++;
+    }
+
+    /* Error-free Multicast Frames counter */
+    if (packet[0] == 0x01) {
+        s->regs[GEM_TXMCNT]++;
+    }
+
+    if (bytes <= 64) {
+        s->regs[GEM_TX64CNT]++;
+    } else if (bytes <= 127) {
+        s->regs[GEM_TX65CNT]++;
+    } else if (bytes <= 255) {
+        s->regs[GEM_TX128CNT]++;
+    } else if (bytes <= 511) {
+        s->regs[GEM_TX256CNT]++;
+    } else if (bytes <= 1023) {
+        s->regs[GEM_TX512CNT]++;
+    } else if (bytes <= 1518) {
+        s->regs[GEM_TX1024CNT]++;
+    } else {
+        s->regs[GEM_TX1519CNT]++;
+    }
+}
+
+/*
+ * gem_transmit:
+ * Fish packets out of the descriptor ring and feed them to QEMU
+ */
+static void gem_transmit(GemState *s)
+{
+    unsigned    desc[2];
+    hwaddr packet_desc_addr;
+    uint8_t     tx_packet[2048];
+    uint8_t     *p;
+    unsigned    total_bytes;
+
+    /* Do nothing if transmit is not enabled. */
+    if (!(s->regs[GEM_NWCTRL] & GEM_NWCTRL_TXENA)) {
+        return;
+    }
+
+    DB_PRINT("\n");
+
+    /* The packet we will hand off to qemu.
+     * Packets scattered across multiple descriptors are gathered to this
+     * one contiguous buffer first.
+     */
+    p = tx_packet;
+    total_bytes = 0;
+
+    /* read current descriptor */
+    packet_desc_addr = s->tx_desc_addr;
+    cpu_physical_memory_read(packet_desc_addr,
+                             (uint8_t *)&desc[0], sizeof(desc));
+    /* Handle all descriptors owned by hardware */
+    while (tx_desc_get_used(desc) == 0) {
+
+        /* Do nothing if transmit is not enabled. */
+        if (!(s->regs[GEM_NWCTRL] & GEM_NWCTRL_TXENA)) {
+            return;
+        }
+        print_gem_tx_desc(desc);
+
+        /* The real hardware would eat this (and possibly crash).
+         * For QEMU let's lend a helping hand.
+         */
+        if ((tx_desc_get_buffer(desc) == 0) ||
+            (tx_desc_get_length(desc) == 0)) {
+            DB_PRINT("Invalid TX descriptor @ 0x%x\n",
+                     (unsigned)packet_desc_addr);
+            break;
+        }
+
+        /* Gather this fragment of the packet from "dma memory" to our contig.
+         * buffer.
+         */
+        cpu_physical_memory_read(tx_desc_get_buffer(desc), p,
+                                 tx_desc_get_length(desc));
+        p += tx_desc_get_length(desc);
+        total_bytes += tx_desc_get_length(desc);
+
+        /* Last descriptor for this packet; hand the whole thing off */
+        if (tx_desc_get_last(desc)) {
+            /* Modify the 1st descriptor of this packet to be owned by
+             * the processor.
+             */
+            cpu_physical_memory_read(s->tx_desc_addr,
+                                     (uint8_t *)&desc[0], sizeof(desc));
+            tx_desc_set_used(desc);
+            cpu_physical_memory_write(s->tx_desc_addr,
+                                      (uint8_t *)&desc[0], sizeof(desc));
+            /* Advance the hardare current descriptor past this packet */
+            if (tx_desc_get_wrap(desc)) {
+                s->tx_desc_addr = s->regs[GEM_TXQBASE];
+            } else {
+                s->tx_desc_addr = packet_desc_addr + 8;
+            }
+            DB_PRINT("TX descriptor next: 0x%08x\n", s->tx_desc_addr);
+
+            s->regs[GEM_TXSTATUS] |= GEM_TXSTATUS_TXCMPL;
+            s->regs[GEM_ISR] |= GEM_INT_TXCMPL & ~(s->regs[GEM_IMR]);
+
+            /* Handle interrupt consequences */
+            gem_update_int_status(s);
+
+            /* Is checksum offload enabled? */
+            if (s->regs[GEM_DMACFG] & GEM_DMACFG_TXCSUM_OFFL) {
+                net_checksum_calculate(tx_packet, total_bytes);
+            }
+
+            /* Update MAC statistics */
+            gem_transmit_updatestats(s, tx_packet, total_bytes);
+
+            /* Send the packet somewhere */
+            if (s->phy_loop) {
+                gem_receive(qemu_get_queue(s->nic), tx_packet, total_bytes);
+            } else {
+                qemu_send_packet(qemu_get_queue(s->nic), tx_packet,
+                                 total_bytes);
+            }
+
+            /* Prepare for next packet */
+            p = tx_packet;
+            total_bytes = 0;
+        }
+
+        /* read next descriptor */
+        if (tx_desc_get_wrap(desc)) {
+            packet_desc_addr = s->regs[GEM_TXQBASE];
+        } else {
+            packet_desc_addr += 8;
+        }
+        cpu_physical_memory_read(packet_desc_addr,
+                                 (uint8_t *)&desc[0], sizeof(desc));
+    }
+
+    if (tx_desc_get_used(desc)) {
+        s->regs[GEM_TXSTATUS] |= GEM_TXSTATUS_USED;
+        s->regs[GEM_ISR] |= GEM_INT_TXUSED & ~(s->regs[GEM_IMR]);
+        gem_update_int_status(s);
+    }
+}
+
+static void gem_phy_reset(GemState *s)
+{
+    memset(&s->phy_regs[0], 0, sizeof(s->phy_regs));
+    s->phy_regs[PHY_REG_CONTROL] = 0x1140;
+    s->phy_regs[PHY_REG_STATUS] = 0x7969;
+    s->phy_regs[PHY_REG_PHYID1] = 0x0141;
+    s->phy_regs[PHY_REG_PHYID2] = 0x0CC2;
+    s->phy_regs[PHY_REG_ANEGADV] = 0x01E1;
+    s->phy_regs[PHY_REG_LINKPABIL] = 0xCDE1;
+    s->phy_regs[PHY_REG_ANEGEXP] = 0x000F;
+    s->phy_regs[PHY_REG_NEXTP] = 0x2001;
+    s->phy_regs[PHY_REG_LINKPNEXTP] = 0x40E6;
+    s->phy_regs[PHY_REG_100BTCTRL] = 0x0300;
+    s->phy_regs[PHY_REG_1000BTSTAT] = 0x7C00;
+    s->phy_regs[PHY_REG_EXTSTAT] = 0x3000;
+    s->phy_regs[PHY_REG_PHYSPCFC_CTL] = 0x0078;
+    s->phy_regs[PHY_REG_PHYSPCFC_ST] = 0xBC00;
+    s->phy_regs[PHY_REG_EXT_PHYSPCFC_CTL] = 0x0C60;
+    s->phy_regs[PHY_REG_LED] = 0x4100;
+    s->phy_regs[PHY_REG_EXT_PHYSPCFC_CTL2] = 0x000A;
+    s->phy_regs[PHY_REG_EXT_PHYSPCFC_ST] = 0x848B;
+
+    phy_update_link(s);
+}
+
+static void gem_reset(DeviceState *d)
+{
+    GemState *s = FROM_SYSBUS(GemState, SYS_BUS_DEVICE(d));
+
+    DB_PRINT("\n");
+
+    /* Set post reset register values */
+    memset(&s->regs[0], 0, sizeof(s->regs));
+    s->regs[GEM_NWCFG] = 0x00080000;
+    s->regs[GEM_NWSTATUS] = 0x00000006;
+    s->regs[GEM_DMACFG] = 0x00020784;
+    s->regs[GEM_IMR] = 0x07ffffff;
+    s->regs[GEM_TXPAUSE] = 0x0000ffff;
+    s->regs[GEM_TXPARTIALSF] = 0x000003ff;
+    s->regs[GEM_RXPARTIALSF] = 0x000003ff;
+    s->regs[GEM_MODID] = 0x00020118;
+    s->regs[GEM_DESCONF] = 0x02500111;
+    s->regs[GEM_DESCONF2] = 0x2ab13fff;
+    s->regs[GEM_DESCONF5] = 0x002f2145;
+    s->regs[GEM_DESCONF6] = 0x00000200;
+
+    gem_phy_reset(s);
+
+    gem_update_int_status(s);
+}
+
+static uint16_t gem_phy_read(GemState *s, unsigned reg_num)
+{
+    DB_PRINT("reg: %d value: 0x%04x\n", reg_num, s->phy_regs[reg_num]);
+    return s->phy_regs[reg_num];
+}
+
+static void gem_phy_write(GemState *s, unsigned reg_num, uint16_t val)
+{
+    DB_PRINT("reg: %d value: 0x%04x\n", reg_num, val);
+
+    switch (reg_num) {
+    case PHY_REG_CONTROL:
+        if (val & PHY_REG_CONTROL_RST) {
+            /* Phy reset */
+            gem_phy_reset(s);
+            val &= ~(PHY_REG_CONTROL_RST | PHY_REG_CONTROL_LOOP);
+            s->phy_loop = 0;
+        }
+        if (val & PHY_REG_CONTROL_ANEG) {
+            /* Complete autonegotiation immediately */
+            val &= ~PHY_REG_CONTROL_ANEG;
+            s->phy_regs[PHY_REG_STATUS] |= PHY_REG_STATUS_ANEGCMPL;
+        }
+        if (val & PHY_REG_CONTROL_LOOP) {
+            DB_PRINT("PHY placed in loopback\n");
+            s->phy_loop = 1;
+        } else {
+            s->phy_loop = 0;
+        }
+        break;
+    }
+    s->phy_regs[reg_num] = val;
+}
+
+/*
+ * gem_read32:
+ * Read a GEM register.
+ */
+static uint64_t gem_read(void *opaque, hwaddr offset, unsigned size)
+{
+    GemState *s;
+    uint32_t retval;
+
+    s = (GemState *)opaque;
+
+    offset >>= 2;
+    retval = s->regs[offset];
+
+    DB_PRINT("offset: 0x%04x read: 0x%08x\n", (unsigned)offset*4, retval);
+
+    switch (offset) {
+    case GEM_ISR:
+        DB_PRINT("lowering irq on ISR read\n");
+        qemu_set_irq(s->irq, 0);
+        break;
+    case GEM_PHYMNTNC:
+        if (retval & GEM_PHYMNTNC_OP_R) {
+            uint32_t phy_addr, reg_num;
+
+            phy_addr = (retval & GEM_PHYMNTNC_ADDR) >> GEM_PHYMNTNC_ADDR_SHFT;
+            if (phy_addr == BOARD_PHY_ADDRESS) {
+                reg_num = (retval & GEM_PHYMNTNC_REG) >> GEM_PHYMNTNC_REG_SHIFT;
+                retval &= 0xFFFF0000;
+                retval |= gem_phy_read(s, reg_num);
+            } else {
+                retval |= 0xFFFF; /* No device at this address */
+            }
+        }
+        break;
+    }
+
+    /* Squash read to clear bits */
+    s->regs[offset] &= ~(s->regs_rtc[offset]);
+
+    /* Do not provide write only bits */
+    retval &= ~(s->regs_wo[offset]);
+
+    DB_PRINT("0x%08x\n", retval);
+    return retval;
+}
+
+/*
+ * gem_write32:
+ * Write a GEM register.
+ */
+static void gem_write(void *opaque, hwaddr offset, uint64_t val,
+        unsigned size)
+{
+    GemState *s = (GemState *)opaque;
+    uint32_t readonly;
+
+    DB_PRINT("offset: 0x%04x write: 0x%08x ", (unsigned)offset, (unsigned)val);
+    offset >>= 2;
+
+    /* Squash bits which are read only in write value */
+    val &= ~(s->regs_ro[offset]);
+    /* Preserve (only) bits which are read only in register */
+    readonly = s->regs[offset];
+    readonly &= s->regs_ro[offset];
+
+    /* Squash bits which are write 1 to clear */
+    val &= ~(s->regs_w1c[offset] & val);
+
+    /* Copy register write to backing store */
+    s->regs[offset] = val | readonly;
+
+    /* Handle register write side effects */
+    switch (offset) {
+    case GEM_NWCTRL:
+        if (val & GEM_NWCTRL_TXSTART) {
+            gem_transmit(s);
+        }
+        if (!(val & GEM_NWCTRL_TXENA)) {
+            /* Reset to start of Q when transmit disabled. */
+            s->tx_desc_addr = s->regs[GEM_TXQBASE];
+        }
+        if (val & GEM_NWCTRL_RXENA) {
+            qemu_flush_queued_packets(qemu_get_queue(s->nic));
+        }
+        break;
+
+    case GEM_TXSTATUS:
+        gem_update_int_status(s);
+        break;
+    case GEM_RXQBASE:
+        s->rx_desc_addr = val;
+        break;
+    case GEM_TXQBASE:
+        s->tx_desc_addr = val;
+        break;
+    case GEM_RXSTATUS:
+        gem_update_int_status(s);
+        break;
+    case GEM_IER:
+        s->regs[GEM_IMR] &= ~val;
+        gem_update_int_status(s);
+        break;
+    case GEM_IDR:
+        s->regs[GEM_IMR] |= val;
+        gem_update_int_status(s);
+        break;
+    case GEM_PHYMNTNC:
+        if (val & GEM_PHYMNTNC_OP_W) {
+            uint32_t phy_addr, reg_num;
+
+            phy_addr = (val & GEM_PHYMNTNC_ADDR) >> GEM_PHYMNTNC_ADDR_SHFT;
+            if (phy_addr == BOARD_PHY_ADDRESS) {
+                reg_num = (val & GEM_PHYMNTNC_REG) >> GEM_PHYMNTNC_REG_SHIFT;
+                gem_phy_write(s, reg_num, val);
+            }
+        }
+        break;
+    }
+
+    DB_PRINT("newval: 0x%08x\n", s->regs[offset]);
+}
+
+static const MemoryRegionOps gem_ops = {
+    .read = gem_read,
+    .write = gem_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void gem_cleanup(NetClientState *nc)
+{
+    GemState *s = qemu_get_nic_opaque(nc);
+
+    DB_PRINT("\n");
+    s->nic = NULL;
+}
+
+static void gem_set_link(NetClientState *nc)
+{
+    DB_PRINT("\n");
+    phy_update_link(qemu_get_nic_opaque(nc));
+}
+
+static NetClientInfo net_gem_info = {
+    .type = NET_CLIENT_OPTIONS_KIND_NIC,
+    .size = sizeof(NICState),
+    .can_receive = gem_can_receive,
+    .receive = gem_receive,
+    .cleanup = gem_cleanup,
+    .link_status_changed = gem_set_link,
+};
+
+static int gem_init(SysBusDevice *dev)
+{
+    GemState *s;
+
+    DB_PRINT("\n");
+
+    s = FROM_SYSBUS(GemState, dev);
+    gem_init_register_masks(s);
+    memory_region_init_io(&s->iomem, &gem_ops, s, "enet", sizeof(s->regs));
+    sysbus_init_mmio(dev, &s->iomem);
+    sysbus_init_irq(dev, &s->irq);
+    qemu_macaddr_default_if_unset(&s->conf.macaddr);
+
+    s->nic = qemu_new_nic(&net_gem_info, &s->conf,
+            object_get_typename(OBJECT(dev)), dev->qdev.id, s);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_cadence_gem = {
+    .name = "cadence_gem",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(regs, GemState, GEM_MAXREG),
+        VMSTATE_UINT16_ARRAY(phy_regs, GemState, 32),
+        VMSTATE_UINT8(phy_loop, GemState),
+        VMSTATE_UINT32(rx_desc_addr, GemState),
+        VMSTATE_UINT32(tx_desc_addr, GemState),
+    }
+};
+
+static Property gem_properties[] = {
+    DEFINE_NIC_PROPERTIES(GemState, conf),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void gem_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sdc->init = gem_init;
+    dc->props = gem_properties;
+    dc->vmsd = &vmstate_cadence_gem;
+    dc->reset = gem_reset;
+}
+
+static const TypeInfo gem_info = {
+    .class_init = gem_class_init,
+    .name  = "cadence_gem",
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size  = sizeof(GemState),
+};
+
+static void gem_register_types(void)
+{
+    type_register_static(&gem_info);
+}
+
+type_init(gem_register_types)
diff --git a/hw/net/dp8393x.c b/hw/net/dp8393x.c
new file mode 100644 (file)
index 0000000..2289f08
--- /dev/null
@@ -0,0 +1,914 @@
+/*
+ * QEMU NS SONIC DP8393x netcard
+ *
+ * Copyright (c) 2008-2009 Herve Poussineau
+ *
+ * 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 "hw/hw.h"
+#include "qemu/timer.h"
+#include "net/net.h"
+#include "hw/mips/mips.h"
+
+//#define DEBUG_SONIC
+
+/* Calculate CRCs properly on Rx packets */
+#define SONIC_CALCULATE_RXCRC
+
+#if defined(SONIC_CALCULATE_RXCRC)
+/* For crc32 */
+#include <zlib.h>
+#endif
+
+#ifdef DEBUG_SONIC
+#define DPRINTF(fmt, ...) \
+do { printf("sonic: " fmt , ##  __VA_ARGS__); } while (0)
+static const char* reg_names[] = {
+    "CR", "DCR", "RCR", "TCR", "IMR", "ISR", "UTDA", "CTDA",
+    "TPS", "TFC", "TSA0", "TSA1", "TFS", "URDA", "CRDA", "CRBA0",
+    "CRBA1", "RBWC0", "RBWC1", "EOBC", "URRA", "RSA", "REA", "RRP",
+    "RWP", "TRBA0", "TRBA1", "0x1b", "0x1c", "0x1d", "0x1e", "LLFA",
+    "TTDA", "CEP", "CAP2", "CAP1", "CAP0", "CE", "CDP", "CDC",
+    "SR", "WT0", "WT1", "RSC", "CRCT", "FAET", "MPT", "MDT",
+    "0x30", "0x31", "0x32", "0x33", "0x34", "0x35", "0x36", "0x37",
+    "0x38", "0x39", "0x3a", "0x3b", "0x3c", "0x3d", "0x3e", "DCR2" };
+#else
+#define DPRINTF(fmt, ...) do {} while (0)
+#endif
+
+#define SONIC_ERROR(fmt, ...) \
+do { printf("sonic ERROR: %s: " fmt, __func__ , ## __VA_ARGS__); } while (0)
+
+#define SONIC_CR     0x00
+#define SONIC_DCR    0x01
+#define SONIC_RCR    0x02
+#define SONIC_TCR    0x03
+#define SONIC_IMR    0x04
+#define SONIC_ISR    0x05
+#define SONIC_UTDA   0x06
+#define SONIC_CTDA   0x07
+#define SONIC_TPS    0x08
+#define SONIC_TFC    0x09
+#define SONIC_TSA0   0x0a
+#define SONIC_TSA1   0x0b
+#define SONIC_TFS    0x0c
+#define SONIC_URDA   0x0d
+#define SONIC_CRDA   0x0e
+#define SONIC_CRBA0  0x0f
+#define SONIC_CRBA1  0x10
+#define SONIC_RBWC0  0x11
+#define SONIC_RBWC1  0x12
+#define SONIC_EOBC   0x13
+#define SONIC_URRA   0x14
+#define SONIC_RSA    0x15
+#define SONIC_REA    0x16
+#define SONIC_RRP    0x17
+#define SONIC_RWP    0x18
+#define SONIC_TRBA0  0x19
+#define SONIC_TRBA1  0x1a
+#define SONIC_LLFA   0x1f
+#define SONIC_TTDA   0x20
+#define SONIC_CEP    0x21
+#define SONIC_CAP2   0x22
+#define SONIC_CAP1   0x23
+#define SONIC_CAP0   0x24
+#define SONIC_CE     0x25
+#define SONIC_CDP    0x26
+#define SONIC_CDC    0x27
+#define SONIC_SR     0x28
+#define SONIC_WT0    0x29
+#define SONIC_WT1    0x2a
+#define SONIC_RSC    0x2b
+#define SONIC_CRCT   0x2c
+#define SONIC_FAET   0x2d
+#define SONIC_MPT    0x2e
+#define SONIC_MDT    0x2f
+#define SONIC_DCR2   0x3f
+
+#define SONIC_CR_HTX     0x0001
+#define SONIC_CR_TXP     0x0002
+#define SONIC_CR_RXDIS   0x0004
+#define SONIC_CR_RXEN    0x0008
+#define SONIC_CR_STP     0x0010
+#define SONIC_CR_ST      0x0020
+#define SONIC_CR_RST     0x0080
+#define SONIC_CR_RRRA    0x0100
+#define SONIC_CR_LCAM    0x0200
+#define SONIC_CR_MASK    0x03bf
+
+#define SONIC_DCR_DW     0x0020
+#define SONIC_DCR_LBR    0x2000
+#define SONIC_DCR_EXBUS  0x8000
+
+#define SONIC_RCR_PRX    0x0001
+#define SONIC_RCR_LBK    0x0002
+#define SONIC_RCR_FAER   0x0004
+#define SONIC_RCR_CRCR   0x0008
+#define SONIC_RCR_CRS    0x0020
+#define SONIC_RCR_LPKT   0x0040
+#define SONIC_RCR_BC     0x0080
+#define SONIC_RCR_MC     0x0100
+#define SONIC_RCR_LB0    0x0200
+#define SONIC_RCR_LB1    0x0400
+#define SONIC_RCR_AMC    0x0800
+#define SONIC_RCR_PRO    0x1000
+#define SONIC_RCR_BRD    0x2000
+#define SONIC_RCR_RNT    0x4000
+
+#define SONIC_TCR_PTX    0x0001
+#define SONIC_TCR_BCM    0x0002
+#define SONIC_TCR_FU     0x0004
+#define SONIC_TCR_EXC    0x0040
+#define SONIC_TCR_CRSL   0x0080
+#define SONIC_TCR_NCRS   0x0100
+#define SONIC_TCR_EXD    0x0400
+#define SONIC_TCR_CRCI   0x2000
+#define SONIC_TCR_PINT   0x8000
+
+#define SONIC_ISR_RBE    0x0020
+#define SONIC_ISR_RDE    0x0040
+#define SONIC_ISR_TC     0x0080
+#define SONIC_ISR_TXDN   0x0200
+#define SONIC_ISR_PKTRX  0x0400
+#define SONIC_ISR_PINT   0x0800
+#define SONIC_ISR_LCD    0x1000
+
+typedef struct dp8393xState {
+    /* Hardware */
+    int it_shift;
+    qemu_irq irq;
+#ifdef DEBUG_SONIC
+    int irq_level;
+#endif
+    QEMUTimer *watchdog;
+    int64_t wt_last_update;
+    NICConf conf;
+    NICState *nic;
+    MemoryRegion *address_space;
+    MemoryRegion mmio;
+
+    /* Registers */
+    uint8_t cam[16][6];
+    uint16_t regs[0x40];
+
+    /* Temporaries */
+    uint8_t tx_buffer[0x10000];
+    int loopback_packet;
+
+    /* Memory access */
+    void (*memory_rw)(void *opaque, hwaddr addr, uint8_t *buf, int len, int is_write);
+    void* mem_opaque;
+} dp8393xState;
+
+static void dp8393x_update_irq(dp8393xState *s)
+{
+    int level = (s->regs[SONIC_IMR] & s->regs[SONIC_ISR]) ? 1 : 0;
+
+#ifdef DEBUG_SONIC
+    if (level != s->irq_level) {
+        s->irq_level = level;
+        if (level) {
+            DPRINTF("raise irq, isr is 0x%04x\n", s->regs[SONIC_ISR]);
+        } else {
+            DPRINTF("lower irq\n");
+        }
+    }
+#endif
+
+    qemu_set_irq(s->irq, level);
+}
+
+static void do_load_cam(dp8393xState *s)
+{
+    uint16_t data[8];
+    int width, size;
+    uint16_t index = 0;
+
+    width = (s->regs[SONIC_DCR] & SONIC_DCR_DW) ? 2 : 1;
+    size = sizeof(uint16_t) * 4 * width;
+
+    while (s->regs[SONIC_CDC] & 0x1f) {
+        /* Fill current entry */
+        s->memory_rw(s->mem_opaque,
+            (s->regs[SONIC_URRA] << 16) | s->regs[SONIC_CDP],
+            (uint8_t *)data, size, 0);
+        s->cam[index][0] = data[1 * width] & 0xff;
+        s->cam[index][1] = data[1 * width] >> 8;
+        s->cam[index][2] = data[2 * width] & 0xff;
+        s->cam[index][3] = data[2 * width] >> 8;
+        s->cam[index][4] = data[3 * width] & 0xff;
+        s->cam[index][5] = data[3 * width] >> 8;
+        DPRINTF("load cam[%d] with %02x%02x%02x%02x%02x%02x\n", index,
+            s->cam[index][0], s->cam[index][1], s->cam[index][2],
+            s->cam[index][3], s->cam[index][4], s->cam[index][5]);
+        /* Move to next entry */
+        s->regs[SONIC_CDC]--;
+        s->regs[SONIC_CDP] += size;
+        index++;
+    }
+
+    /* Read CAM enable */
+    s->memory_rw(s->mem_opaque,
+        (s->regs[SONIC_URRA] << 16) | s->regs[SONIC_CDP],
+        (uint8_t *)data, size, 0);
+    s->regs[SONIC_CE] = data[0 * width];
+    DPRINTF("load cam done. cam enable mask 0x%04x\n", s->regs[SONIC_CE]);
+
+    /* Done */
+    s->regs[SONIC_CR] &= ~SONIC_CR_LCAM;
+    s->regs[SONIC_ISR] |= SONIC_ISR_LCD;
+    dp8393x_update_irq(s);
+}
+
+static void do_read_rra(dp8393xState *s)
+{
+    uint16_t data[8];
+    int width, size;
+
+    /* Read memory */
+    width = (s->regs[SONIC_DCR] & SONIC_DCR_DW) ? 2 : 1;
+    size = sizeof(uint16_t) * 4 * width;
+    s->memory_rw(s->mem_opaque,
+        (s->regs[SONIC_URRA] << 16) | s->regs[SONIC_RRP],
+        (uint8_t *)data, size, 0);
+
+    /* Update SONIC registers */
+    s->regs[SONIC_CRBA0] = data[0 * width];
+    s->regs[SONIC_CRBA1] = data[1 * width];
+    s->regs[SONIC_RBWC0] = data[2 * width];
+    s->regs[SONIC_RBWC1] = data[3 * width];
+    DPRINTF("CRBA0/1: 0x%04x/0x%04x, RBWC0/1: 0x%04x/0x%04x\n",
+        s->regs[SONIC_CRBA0], s->regs[SONIC_CRBA1],
+        s->regs[SONIC_RBWC0], s->regs[SONIC_RBWC1]);
+
+    /* Go to next entry */
+    s->regs[SONIC_RRP] += size;
+
+    /* Handle wrap */
+    if (s->regs[SONIC_RRP] == s->regs[SONIC_REA]) {
+        s->regs[SONIC_RRP] = s->regs[SONIC_RSA];
+    }
+
+    /* Check resource exhaustion */
+    if (s->regs[SONIC_RRP] == s->regs[SONIC_RWP])
+    {
+        s->regs[SONIC_ISR] |= SONIC_ISR_RBE;
+        dp8393x_update_irq(s);
+    }
+
+    /* Done */
+    s->regs[SONIC_CR] &= ~SONIC_CR_RRRA;
+}
+
+static void do_software_reset(dp8393xState *s)
+{
+    qemu_del_timer(s->watchdog);
+
+    s->regs[SONIC_CR] &= ~(SONIC_CR_LCAM | SONIC_CR_RRRA | SONIC_CR_TXP | SONIC_CR_HTX);
+    s->regs[SONIC_CR] |= SONIC_CR_RST | SONIC_CR_RXDIS;
+}
+
+static void set_next_tick(dp8393xState *s)
+{
+    uint32_t ticks;
+    int64_t delay;
+
+    if (s->regs[SONIC_CR] & SONIC_CR_STP) {
+        qemu_del_timer(s->watchdog);
+        return;
+    }
+
+    ticks = s->regs[SONIC_WT1] << 16 | s->regs[SONIC_WT0];
+    s->wt_last_update = qemu_get_clock_ns(vm_clock);
+    delay = get_ticks_per_sec() * ticks / 5000000;
+    qemu_mod_timer(s->watchdog, s->wt_last_update + delay);
+}
+
+static void update_wt_regs(dp8393xState *s)
+{
+    int64_t elapsed;
+    uint32_t val;
+
+    if (s->regs[SONIC_CR] & SONIC_CR_STP) {
+        qemu_del_timer(s->watchdog);
+        return;
+    }
+
+    elapsed = s->wt_last_update - qemu_get_clock_ns(vm_clock);
+    val = s->regs[SONIC_WT1] << 16 | s->regs[SONIC_WT0];
+    val -= elapsed / 5000000;
+    s->regs[SONIC_WT1] = (val >> 16) & 0xffff;
+    s->regs[SONIC_WT0] = (val >> 0)  & 0xffff;
+    set_next_tick(s);
+
+}
+
+static void do_start_timer(dp8393xState *s)
+{
+    s->regs[SONIC_CR] &= ~SONIC_CR_STP;
+    set_next_tick(s);
+}
+
+static void do_stop_timer(dp8393xState *s)
+{
+    s->regs[SONIC_CR] &= ~SONIC_CR_ST;
+    update_wt_regs(s);
+}
+
+static void do_receiver_enable(dp8393xState *s)
+{
+    s->regs[SONIC_CR] &= ~SONIC_CR_RXDIS;
+}
+
+static void do_receiver_disable(dp8393xState *s)
+{
+    s->regs[SONIC_CR] &= ~SONIC_CR_RXEN;
+}
+
+static void do_transmit_packets(dp8393xState *s)
+{
+    NetClientState *nc = qemu_get_queue(s->nic);
+    uint16_t data[12];
+    int width, size;
+    int tx_len, len;
+    uint16_t i;
+
+    width = (s->regs[SONIC_DCR] & SONIC_DCR_DW) ? 2 : 1;
+
+    while (1) {
+        /* Read memory */
+        DPRINTF("Transmit packet at %08x\n",
+                (s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_CTDA]);
+        size = sizeof(uint16_t) * 6 * width;
+        s->regs[SONIC_TTDA] = s->regs[SONIC_CTDA];
+        s->memory_rw(s->mem_opaque,
+            ((s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_TTDA]) + sizeof(uint16_t) * width,
+            (uint8_t *)data, size, 0);
+        tx_len = 0;
+
+        /* Update registers */
+        s->regs[SONIC_TCR] = data[0 * width] & 0xf000;
+        s->regs[SONIC_TPS] = data[1 * width];
+        s->regs[SONIC_TFC] = data[2 * width];
+        s->regs[SONIC_TSA0] = data[3 * width];
+        s->regs[SONIC_TSA1] = data[4 * width];
+        s->regs[SONIC_TFS] = data[5 * width];
+
+        /* Handle programmable interrupt */
+        if (s->regs[SONIC_TCR] & SONIC_TCR_PINT) {
+            s->regs[SONIC_ISR] |= SONIC_ISR_PINT;
+        } else {
+            s->regs[SONIC_ISR] &= ~SONIC_ISR_PINT;
+        }
+
+        for (i = 0; i < s->regs[SONIC_TFC]; ) {
+            /* Append fragment */
+            len = s->regs[SONIC_TFS];
+            if (tx_len + len > sizeof(s->tx_buffer)) {
+                len = sizeof(s->tx_buffer) - tx_len;
+            }
+            s->memory_rw(s->mem_opaque,
+                (s->regs[SONIC_TSA1] << 16) | s->regs[SONIC_TSA0],
+                &s->tx_buffer[tx_len], len, 0);
+            tx_len += len;
+
+            i++;
+            if (i != s->regs[SONIC_TFC]) {
+                /* Read next fragment details */
+                size = sizeof(uint16_t) * 3 * width;
+                s->memory_rw(s->mem_opaque,
+                    ((s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_TTDA]) + sizeof(uint16_t) * (4 + 3 * i) * width,
+                    (uint8_t *)data, size, 0);
+                s->regs[SONIC_TSA0] = data[0 * width];
+                s->regs[SONIC_TSA1] = data[1 * width];
+                s->regs[SONIC_TFS] = data[2 * width];
+            }
+        }
+
+        /* Handle Ethernet checksum */
+        if (!(s->regs[SONIC_TCR] & SONIC_TCR_CRCI)) {
+            /* Don't append FCS there, to look like slirp packets
+             * which don't have one */
+        } else {
+            /* Remove existing FCS */
+            tx_len -= 4;
+        }
+
+        if (s->regs[SONIC_RCR] & (SONIC_RCR_LB1 | SONIC_RCR_LB0)) {
+            /* Loopback */
+            s->regs[SONIC_TCR] |= SONIC_TCR_CRSL;
+            if (nc->info->can_receive(nc)) {
+                s->loopback_packet = 1;
+                nc->info->receive(nc, s->tx_buffer, tx_len);
+            }
+        } else {
+            /* Transmit packet */
+            qemu_send_packet(nc, s->tx_buffer, tx_len);
+        }
+        s->regs[SONIC_TCR] |= SONIC_TCR_PTX;
+
+        /* Write status */
+        data[0 * width] = s->regs[SONIC_TCR] & 0x0fff; /* status */
+        size = sizeof(uint16_t) * width;
+        s->memory_rw(s->mem_opaque,
+            (s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_TTDA],
+            (uint8_t *)data, size, 1);
+
+        if (!(s->regs[SONIC_CR] & SONIC_CR_HTX)) {
+            /* Read footer of packet */
+            size = sizeof(uint16_t) * width;
+            s->memory_rw(s->mem_opaque,
+                ((s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_TTDA]) + sizeof(uint16_t) * (4 + 3 * s->regs[SONIC_TFC]) * width,
+                (uint8_t *)data, size, 0);
+            s->regs[SONIC_CTDA] = data[0 * width] & ~0x1;
+            if (data[0 * width] & 0x1) {
+                /* EOL detected */
+                break;
+            }
+        }
+    }
+
+    /* Done */
+    s->regs[SONIC_CR] &= ~SONIC_CR_TXP;
+    s->regs[SONIC_ISR] |= SONIC_ISR_TXDN;
+    dp8393x_update_irq(s);
+}
+
+static void do_halt_transmission(dp8393xState *s)
+{
+    /* Nothing to do */
+}
+
+static void do_command(dp8393xState *s, uint16_t command)
+{
+    if ((s->regs[SONIC_CR] & SONIC_CR_RST) && !(command & SONIC_CR_RST)) {
+        s->regs[SONIC_CR] &= ~SONIC_CR_RST;
+        return;
+    }
+
+    s->regs[SONIC_CR] |= (command & SONIC_CR_MASK);
+
+    if (command & SONIC_CR_HTX)
+        do_halt_transmission(s);
+    if (command & SONIC_CR_TXP)
+        do_transmit_packets(s);
+    if (command & SONIC_CR_RXDIS)
+        do_receiver_disable(s);
+    if (command & SONIC_CR_RXEN)
+        do_receiver_enable(s);
+    if (command & SONIC_CR_STP)
+        do_stop_timer(s);
+    if (command & SONIC_CR_ST)
+        do_start_timer(s);
+    if (command & SONIC_CR_RST)
+        do_software_reset(s);
+    if (command & SONIC_CR_RRRA)
+        do_read_rra(s);
+    if (command & SONIC_CR_LCAM)
+        do_load_cam(s);
+}
+
+static uint16_t read_register(dp8393xState *s, int reg)
+{
+    uint16_t val = 0;
+
+    switch (reg) {
+        /* Update data before reading it */
+        case SONIC_WT0:
+        case SONIC_WT1:
+            update_wt_regs(s);
+            val = s->regs[reg];
+            break;
+        /* Accept read to some registers only when in reset mode */
+        case SONIC_CAP2:
+        case SONIC_CAP1:
+        case SONIC_CAP0:
+            if (s->regs[SONIC_CR] & SONIC_CR_RST) {
+                val = s->cam[s->regs[SONIC_CEP] & 0xf][2* (SONIC_CAP0 - reg) + 1] << 8;
+                val |= s->cam[s->regs[SONIC_CEP] & 0xf][2* (SONIC_CAP0 - reg)];
+            }
+            break;
+        /* All other registers have no special contrainst */
+        default:
+            val = s->regs[reg];
+    }
+
+    DPRINTF("read 0x%04x from reg %s\n", val, reg_names[reg]);
+
+    return val;
+}
+
+static void write_register(dp8393xState *s, int reg, uint16_t val)
+{
+    DPRINTF("write 0x%04x to reg %s\n", val, reg_names[reg]);
+
+    switch (reg) {
+        /* Command register */
+        case SONIC_CR:
+            do_command(s, val);
+            break;
+        /* Prevent write to read-only registers */
+        case SONIC_CAP2:
+        case SONIC_CAP1:
+        case SONIC_CAP0:
+        case SONIC_SR:
+        case SONIC_MDT:
+            DPRINTF("writing to reg %d invalid\n", reg);
+            break;
+        /* Accept write to some registers only when in reset mode */
+        case SONIC_DCR:
+            if (s->regs[SONIC_CR] & SONIC_CR_RST) {
+                s->regs[reg] = val & 0xbfff;
+            } else {
+                DPRINTF("writing to DCR invalid\n");
+            }
+            break;
+        case SONIC_DCR2:
+            if (s->regs[SONIC_CR] & SONIC_CR_RST) {
+                s->regs[reg] = val & 0xf017;
+            } else {
+                DPRINTF("writing to DCR2 invalid\n");
+            }
+            break;
+        /* 12 lower bytes are Read Only */
+        case SONIC_TCR:
+            s->regs[reg] = val & 0xf000;
+            break;
+        /* 9 lower bytes are Read Only */
+        case SONIC_RCR:
+            s->regs[reg] = val & 0xffe0;
+            break;
+        /* Ignore most significant bit */
+        case SONIC_IMR:
+            s->regs[reg] = val & 0x7fff;
+            dp8393x_update_irq(s);
+            break;
+        /* Clear bits by writing 1 to them */
+        case SONIC_ISR:
+            val &= s->regs[reg];
+            s->regs[reg] &= ~val;
+            if (val & SONIC_ISR_RBE) {
+                do_read_rra(s);
+            }
+            dp8393x_update_irq(s);
+            break;
+        /* Ignore least significant bit */
+        case SONIC_RSA:
+        case SONIC_REA:
+        case SONIC_RRP:
+        case SONIC_RWP:
+            s->regs[reg] = val & 0xfffe;
+            break;
+        /* Invert written value for some registers */
+        case SONIC_CRCT:
+        case SONIC_FAET:
+        case SONIC_MPT:
+            s->regs[reg] = val ^ 0xffff;
+            break;
+        /* All other registers have no special contrainst */
+        default:
+            s->regs[reg] = val;
+    }
+
+    if (reg == SONIC_WT0 || reg == SONIC_WT1) {
+        set_next_tick(s);
+    }
+}
+
+static void dp8393x_watchdog(void *opaque)
+{
+    dp8393xState *s = opaque;
+
+    if (s->regs[SONIC_CR] & SONIC_CR_STP) {
+        return;
+    }
+
+    s->regs[SONIC_WT1] = 0xffff;
+    s->regs[SONIC_WT0] = 0xffff;
+    set_next_tick(s);
+
+    /* Signal underflow */
+    s->regs[SONIC_ISR] |= SONIC_ISR_TC;
+    dp8393x_update_irq(s);
+}
+
+static uint32_t dp8393x_readw(void *opaque, hwaddr addr)
+{
+    dp8393xState *s = opaque;
+    int reg;
+
+    if ((addr & ((1 << s->it_shift) - 1)) != 0) {
+        return 0;
+    }
+
+    reg = addr >> s->it_shift;
+    return read_register(s, reg);
+}
+
+static uint32_t dp8393x_readb(void *opaque, hwaddr addr)
+{
+    uint16_t v = dp8393x_readw(opaque, addr & ~0x1);
+    return (v >> (8 * (addr & 0x1))) & 0xff;
+}
+
+static uint32_t dp8393x_readl(void *opaque, hwaddr addr)
+{
+    uint32_t v;
+    v = dp8393x_readw(opaque, addr);
+    v |= dp8393x_readw(opaque, addr + 2) << 16;
+    return v;
+}
+
+static void dp8393x_writew(void *opaque, hwaddr addr, uint32_t val)
+{
+    dp8393xState *s = opaque;
+    int reg;
+
+    if ((addr & ((1 << s->it_shift) - 1)) != 0) {
+        return;
+    }
+
+    reg = addr >> s->it_shift;
+
+    write_register(s, reg, (uint16_t)val);
+}
+
+static void dp8393x_writeb(void *opaque, hwaddr addr, uint32_t val)
+{
+    uint16_t old_val = dp8393x_readw(opaque, addr & ~0x1);
+
+    switch (addr & 3) {
+    case 0:
+        val = val | (old_val & 0xff00);
+        break;
+    case 1:
+        val = (val << 8) | (old_val & 0x00ff);
+        break;
+    }
+    dp8393x_writew(opaque, addr & ~0x1, val);
+}
+
+static void dp8393x_writel(void *opaque, hwaddr addr, uint32_t val)
+{
+    dp8393x_writew(opaque, addr, val & 0xffff);
+    dp8393x_writew(opaque, addr + 2, (val >> 16) & 0xffff);
+}
+
+static const MemoryRegionOps dp8393x_ops = {
+    .old_mmio = {
+        .read = { dp8393x_readb, dp8393x_readw, dp8393x_readl, },
+        .write = { dp8393x_writeb, dp8393x_writew, dp8393x_writel, },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int nic_can_receive(NetClientState *nc)
+{
+    dp8393xState *s = qemu_get_nic_opaque(nc);
+
+    if (!(s->regs[SONIC_CR] & SONIC_CR_RXEN))
+        return 0;
+    if (s->regs[SONIC_ISR] & SONIC_ISR_RBE)
+        return 0;
+    return 1;
+}
+
+static int receive_filter(dp8393xState *s, const uint8_t * buf, int size)
+{
+    static const uint8_t bcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+    int i;
+
+    /* Check for runt packet (remember that checksum is not there) */
+    if (size < 64 - 4) {
+        return (s->regs[SONIC_RCR] & SONIC_RCR_RNT) ? 0 : -1;
+    }
+
+    /* Check promiscuous mode */
+    if ((s->regs[SONIC_RCR] & SONIC_RCR_PRO) && (buf[0] & 1) == 0) {
+        return 0;
+    }
+
+    /* Check multicast packets */
+    if ((s->regs[SONIC_RCR] & SONIC_RCR_AMC) && (buf[0] & 1) == 1) {
+        return SONIC_RCR_MC;
+    }
+
+    /* Check broadcast */
+    if ((s->regs[SONIC_RCR] & SONIC_RCR_BRD) && !memcmp(buf, bcast, sizeof(bcast))) {
+        return SONIC_RCR_BC;
+    }
+
+    /* Check CAM */
+    for (i = 0; i < 16; i++) {
+        if (s->regs[SONIC_CE] & (1 << i)) {
+             /* Entry enabled */
+             if (!memcmp(buf, s->cam[i], sizeof(s->cam[i]))) {
+                 return 0;
+             }
+        }
+    }
+
+    return -1;
+}
+
+static ssize_t nic_receive(NetClientState *nc, const uint8_t * buf, size_t size)
+{
+    dp8393xState *s = qemu_get_nic_opaque(nc);
+    uint16_t data[10];
+    int packet_type;
+    uint32_t available, address;
+    int width, rx_len = size;
+    uint32_t checksum;
+
+    width = (s->regs[SONIC_DCR] & SONIC_DCR_DW) ? 2 : 1;
+
+    s->regs[SONIC_RCR] &= ~(SONIC_RCR_PRX | SONIC_RCR_LBK | SONIC_RCR_FAER |
+        SONIC_RCR_CRCR | SONIC_RCR_LPKT | SONIC_RCR_BC | SONIC_RCR_MC);
+
+    packet_type = receive_filter(s, buf, size);
+    if (packet_type < 0) {
+        DPRINTF("packet not for netcard\n");
+        return -1;
+    }
+
+    /* XXX: Check byte ordering */
+
+    /* Check for EOL */
+    if (s->regs[SONIC_LLFA] & 0x1) {
+        /* Are we still in resource exhaustion? */
+        size = sizeof(uint16_t) * 1 * width;
+        address = ((s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA]) + sizeof(uint16_t) * 5 * width;
+        s->memory_rw(s->mem_opaque, address, (uint8_t*)data, size, 0);
+        if (data[0 * width] & 0x1) {
+            /* Still EOL ; stop reception */
+            return -1;
+        } else {
+            s->regs[SONIC_CRDA] = s->regs[SONIC_LLFA];
+        }
+    }
+
+    /* Save current position */
+    s->regs[SONIC_TRBA1] = s->regs[SONIC_CRBA1];
+    s->regs[SONIC_TRBA0] = s->regs[SONIC_CRBA0];
+
+    /* Calculate the ethernet checksum */
+#ifdef SONIC_CALCULATE_RXCRC
+    checksum = cpu_to_le32(crc32(0, buf, rx_len));
+#else
+    checksum = 0;
+#endif
+
+    /* Put packet into RBA */
+    DPRINTF("Receive packet at %08x\n", (s->regs[SONIC_CRBA1] << 16) | s->regs[SONIC_CRBA0]);
+    address = (s->regs[SONIC_CRBA1] << 16) | s->regs[SONIC_CRBA0];
+    s->memory_rw(s->mem_opaque, address, (uint8_t*)buf, rx_len, 1);
+    address += rx_len;
+    s->memory_rw(s->mem_opaque, address, (uint8_t*)&checksum, 4, 1);
+    rx_len += 4;
+    s->regs[SONIC_CRBA1] = address >> 16;
+    s->regs[SONIC_CRBA0] = address & 0xffff;
+    available = (s->regs[SONIC_RBWC1] << 16) | s->regs[SONIC_RBWC0];
+    available -= rx_len / 2;
+    s->regs[SONIC_RBWC1] = available >> 16;
+    s->regs[SONIC_RBWC0] = available & 0xffff;
+
+    /* Update status */
+    if (((s->regs[SONIC_RBWC1] << 16) | s->regs[SONIC_RBWC0]) < s->regs[SONIC_EOBC]) {
+        s->regs[SONIC_RCR] |= SONIC_RCR_LPKT;
+    }
+    s->regs[SONIC_RCR] |= packet_type;
+    s->regs[SONIC_RCR] |= SONIC_RCR_PRX;
+    if (s->loopback_packet) {
+        s->regs[SONIC_RCR] |= SONIC_RCR_LBK;
+        s->loopback_packet = 0;
+    }
+
+    /* Write status to memory */
+    DPRINTF("Write status at %08x\n", (s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA]);
+    data[0 * width] = s->regs[SONIC_RCR]; /* status */
+    data[1 * width] = rx_len; /* byte count */
+    data[2 * width] = s->regs[SONIC_TRBA0]; /* pkt_ptr0 */
+    data[3 * width] = s->regs[SONIC_TRBA1]; /* pkt_ptr1 */
+    data[4 * width] = s->regs[SONIC_RSC]; /* seq_no */
+    size = sizeof(uint16_t) * 5 * width;
+    s->memory_rw(s->mem_opaque, (s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA], (uint8_t *)data, size, 1);
+
+    /* Move to next descriptor */
+    size = sizeof(uint16_t) * width;
+    s->memory_rw(s->mem_opaque,
+        ((s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA]) + sizeof(uint16_t) * 5 * width,
+        (uint8_t *)data, size, 0);
+    s->regs[SONIC_LLFA] = data[0 * width];
+    if (s->regs[SONIC_LLFA] & 0x1) {
+        /* EOL detected */
+        s->regs[SONIC_ISR] |= SONIC_ISR_RDE;
+    } else {
+        data[0 * width] = 0; /* in_use */
+        s->memory_rw(s->mem_opaque,
+            ((s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA]) + sizeof(uint16_t) * 6 * width,
+            (uint8_t *)data, size, 1);
+        s->regs[SONIC_CRDA] = s->regs[SONIC_LLFA];
+        s->regs[SONIC_ISR] |= SONIC_ISR_PKTRX;
+        s->regs[SONIC_RSC] = (s->regs[SONIC_RSC] & 0xff00) | (((s->regs[SONIC_RSC] & 0x00ff) + 1) & 0x00ff);
+
+        if (s->regs[SONIC_RCR] & SONIC_RCR_LPKT) {
+            /* Read next RRA */
+            do_read_rra(s);
+        }
+    }
+
+    /* Done */
+    dp8393x_update_irq(s);
+
+    return size;
+}
+
+static void nic_reset(void *opaque)
+{
+    dp8393xState *s = opaque;
+    qemu_del_timer(s->watchdog);
+
+    s->regs[SONIC_CR] = SONIC_CR_RST | SONIC_CR_STP | SONIC_CR_RXDIS;
+    s->regs[SONIC_DCR] &= ~(SONIC_DCR_EXBUS | SONIC_DCR_LBR);
+    s->regs[SONIC_RCR] &= ~(SONIC_RCR_LB0 | SONIC_RCR_LB1 | SONIC_RCR_BRD | SONIC_RCR_RNT);
+    s->regs[SONIC_TCR] |= SONIC_TCR_NCRS | SONIC_TCR_PTX;
+    s->regs[SONIC_TCR] &= ~SONIC_TCR_BCM;
+    s->regs[SONIC_IMR] = 0;
+    s->regs[SONIC_ISR] = 0;
+    s->regs[SONIC_DCR2] = 0;
+    s->regs[SONIC_EOBC] = 0x02F8;
+    s->regs[SONIC_RSC] = 0;
+    s->regs[SONIC_CE] = 0;
+    s->regs[SONIC_RSC] = 0;
+
+    /* Network cable is connected */
+    s->regs[SONIC_RCR] |= SONIC_RCR_CRS;
+
+    dp8393x_update_irq(s);
+}
+
+static void nic_cleanup(NetClientState *nc)
+{
+    dp8393xState *s = qemu_get_nic_opaque(nc);
+
+    memory_region_del_subregion(s->address_space, &s->mmio);
+    memory_region_destroy(&s->mmio);
+
+    qemu_del_timer(s->watchdog);
+    qemu_free_timer(s->watchdog);
+
+    g_free(s);
+}
+
+static NetClientInfo net_dp83932_info = {
+    .type = NET_CLIENT_OPTIONS_KIND_NIC,
+    .size = sizeof(NICState),
+    .can_receive = nic_can_receive,
+    .receive = nic_receive,
+    .cleanup = nic_cleanup,
+};
+
+void dp83932_init(NICInfo *nd, hwaddr base, int it_shift,
+                  MemoryRegion *address_space,
+                  qemu_irq irq, void* mem_opaque,
+                  void (*memory_rw)(void *opaque, hwaddr addr, uint8_t *buf, int len, int is_write))
+{
+    dp8393xState *s;
+
+    qemu_check_nic_model(nd, "dp83932");
+
+    s = g_malloc0(sizeof(dp8393xState));
+
+    s->address_space = address_space;
+    s->mem_opaque = mem_opaque;
+    s->memory_rw = memory_rw;
+    s->it_shift = it_shift;
+    s->irq = irq;
+    s->watchdog = qemu_new_timer_ns(vm_clock, dp8393x_watchdog, s);
+    s->regs[SONIC_SR] = 0x0004; /* only revision recognized by Linux */
+
+    s->conf.macaddr = nd->macaddr;
+    s->conf.peers.ncs[0] = nd->netdev;
+
+    s->nic = qemu_new_nic(&net_dp83932_info, &s->conf, nd->model, nd->name, s);
+
+    qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
+    qemu_register_reset(nic_reset, s);
+    nic_reset(s);
+
+    memory_region_init_io(&s->mmio, &dp8393x_ops, s,
+                          "dp8393x", 0x40 << it_shift);
+    memory_region_add_subregion(address_space, base, &s->mmio);
+}
diff --git a/hw/net/e1000.c b/hw/net/e1000.c
new file mode 100644 (file)
index 0000000..e6f46f0
--- /dev/null
@@ -0,0 +1,1404 @@
+/*
+ * QEMU e1000 emulation
+ *
+ * Software developer's manual:
+ * http://download.intel.com/design/network/manuals/8254x_GBe_SDM.pdf
+ *
+ * Nir Peleg, Tutis Systems Ltd. for Qumranet Inc.
+ * Copyright (c) 2008 Qumranet
+ * Based on work done by:
+ * Copyright (c) 2007 Dan Aloni
+ * Copyright (c) 2004 Antony T Curtis
+ *
+ * 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/hw.h"
+#include "hw/pci/pci.h"
+#include "net/net.h"
+#include "net/checksum.h"
+#include "hw/loader.h"
+#include "sysemu/sysemu.h"
+#include "sysemu/dma.h"
+
+#include "e1000_regs.h"
+
+#define E1000_DEBUG
+
+#ifdef E1000_DEBUG
+enum {
+    DEBUG_GENERAL,     DEBUG_IO,       DEBUG_MMIO,     DEBUG_INTERRUPT,
+    DEBUG_RX,          DEBUG_TX,       DEBUG_MDIC,     DEBUG_EEPROM,
+    DEBUG_UNKNOWN,     DEBUG_TXSUM,    DEBUG_TXERR,    DEBUG_RXERR,
+    DEBUG_RXFILTER,     DEBUG_PHY,      DEBUG_NOTYET,
+};
+#define DBGBIT(x)      (1<<DEBUG_##x)
+static int debugflags = DBGBIT(TXERR) | DBGBIT(GENERAL);
+
+#define        DBGOUT(what, fmt, ...) do { \
+    if (debugflags & DBGBIT(what)) \
+        fprintf(stderr, "e1000: " fmt, ## __VA_ARGS__); \
+    } while (0)
+#else
+#define        DBGOUT(what, fmt, ...) do {} while (0)
+#endif
+
+#define IOPORT_SIZE       0x40
+#define PNPMMIO_SIZE      0x20000
+#define MIN_BUF_SIZE      60 /* Min. octets in an ethernet frame sans FCS */
+
+/* this is the size past which hardware will drop packets when setting LPE=0 */
+#define MAXIMUM_ETHERNET_VLAN_SIZE 1522
+/* this is the size past which hardware will drop packets when setting LPE=1 */
+#define MAXIMUM_ETHERNET_LPE_SIZE 16384
+
+/*
+ * HW models:
+ *  E1000_DEV_ID_82540EM works with Windows and Linux
+ *  E1000_DEV_ID_82573L OK with windoze and Linux 2.6.22,
+ *     appears to perform better than 82540EM, but breaks with Linux 2.6.18
+ *  E1000_DEV_ID_82544GC_COPPER appears to work; not well tested
+ *  Others never tested
+ */
+enum { E1000_DEVID = E1000_DEV_ID_82540EM };
+
+/*
+ * May need to specify additional MAC-to-PHY entries --
+ * Intel's Windows driver refuses to initialize unless they match
+ */
+enum {
+    PHY_ID2_INIT = E1000_DEVID == E1000_DEV_ID_82573L ?                0xcc2 :
+                   E1000_DEVID == E1000_DEV_ID_82544GC_COPPER ?        0xc30 :
+                   /* default to E1000_DEV_ID_82540EM */       0xc20
+};
+
+typedef struct E1000State_st {
+    PCIDevice dev;
+    NICState *nic;
+    NICConf conf;
+    MemoryRegion mmio;
+    MemoryRegion io;
+
+    uint32_t mac_reg[0x8000];
+    uint16_t phy_reg[0x20];
+    uint16_t eeprom_data[64];
+
+    uint32_t rxbuf_size;
+    uint32_t rxbuf_min_shift;
+    struct e1000_tx {
+        unsigned char header[256];
+        unsigned char vlan_header[4];
+        /* Fields vlan and data must not be reordered or separated. */
+        unsigned char vlan[4];
+        unsigned char data[0x10000];
+        uint16_t size;
+        unsigned char sum_needed;
+        unsigned char vlan_needed;
+        uint8_t ipcss;
+        uint8_t ipcso;
+        uint16_t ipcse;
+        uint8_t tucss;
+        uint8_t tucso;
+        uint16_t tucse;
+        uint8_t hdr_len;
+        uint16_t mss;
+        uint32_t paylen;
+        uint16_t tso_frames;
+        char tse;
+        int8_t ip;
+        int8_t tcp;
+        char cptse;     // current packet tse bit
+    } tx;
+
+    struct {
+        uint32_t val_in;       // shifted in from guest driver
+        uint16_t bitnum_in;
+        uint16_t bitnum_out;
+        uint16_t reading;
+        uint32_t old_eecd;
+    } eecd_state;
+
+    QEMUTimer *autoneg_timer;
+
+/* Compatibility flags for migration to/from qemu 1.3.0 and older */
+#define E1000_FLAG_AUTONEG_BIT 0
+#define E1000_FLAG_AUTONEG (1 << E1000_FLAG_AUTONEG_BIT)
+    uint32_t compat_flags;
+} E1000State;
+
+#define        defreg(x)       x = (E1000_##x>>2)
+enum {
+    defreg(CTRL),      defreg(EECD),   defreg(EERD),   defreg(GPRC),
+    defreg(GPTC),      defreg(ICR),    defreg(ICS),    defreg(IMC),
+    defreg(IMS),       defreg(LEDCTL), defreg(MANC),   defreg(MDIC),
+    defreg(MPC),       defreg(PBA),    defreg(RCTL),   defreg(RDBAH),
+    defreg(RDBAL),     defreg(RDH),    defreg(RDLEN),  defreg(RDT),
+    defreg(STATUS),    defreg(SWSM),   defreg(TCTL),   defreg(TDBAH),
+    defreg(TDBAL),     defreg(TDH),    defreg(TDLEN),  defreg(TDT),
+    defreg(TORH),      defreg(TORL),   defreg(TOTH),   defreg(TOTL),
+    defreg(TPR),       defreg(TPT),    defreg(TXDCTL), defreg(WUFC),
+    defreg(RA),                defreg(MTA),    defreg(CRCERRS),defreg(VFTA),
+    defreg(VET),
+};
+
+static void
+e1000_link_down(E1000State *s)
+{
+    s->mac_reg[STATUS] &= ~E1000_STATUS_LU;
+    s->phy_reg[PHY_STATUS] &= ~MII_SR_LINK_STATUS;
+}
+
+static void
+e1000_link_up(E1000State *s)
+{
+    s->mac_reg[STATUS] |= E1000_STATUS_LU;
+    s->phy_reg[PHY_STATUS] |= MII_SR_LINK_STATUS;
+}
+
+static void
+set_phy_ctrl(E1000State *s, int index, uint16_t val)
+{
+    /*
+     * QEMU 1.3 does not support link auto-negotiation emulation, so if we
+     * migrate during auto negotiation, after migration the link will be
+     * down.
+     */
+    if (!(s->compat_flags & E1000_FLAG_AUTONEG)) {
+        return;
+    }
+    if ((val & MII_CR_AUTO_NEG_EN) && (val & MII_CR_RESTART_AUTO_NEG)) {
+        e1000_link_down(s);
+        s->phy_reg[PHY_STATUS] &= ~MII_SR_AUTONEG_COMPLETE;
+        DBGOUT(PHY, "Start link auto negotiation\n");
+        qemu_mod_timer(s->autoneg_timer, qemu_get_clock_ms(vm_clock) + 500);
+    }
+}
+
+static void
+e1000_autoneg_timer(void *opaque)
+{
+    E1000State *s = opaque;
+    if (!qemu_get_queue(s->nic)->link_down) {
+        e1000_link_up(s);
+    }
+    s->phy_reg[PHY_STATUS] |= MII_SR_AUTONEG_COMPLETE;
+    DBGOUT(PHY, "Auto negotiation is completed\n");
+}
+
+static void (*phyreg_writeops[])(E1000State *, int, uint16_t) = {
+    [PHY_CTRL] = set_phy_ctrl,
+};
+
+enum { NPHYWRITEOPS = ARRAY_SIZE(phyreg_writeops) };
+
+enum { PHY_R = 1, PHY_W = 2, PHY_RW = PHY_R | PHY_W };
+static const char phy_regcap[0x20] = {
+    [PHY_STATUS] = PHY_R,      [M88E1000_EXT_PHY_SPEC_CTRL] = PHY_RW,
+    [PHY_ID1] = PHY_R,         [M88E1000_PHY_SPEC_CTRL] = PHY_RW,
+    [PHY_CTRL] = PHY_RW,       [PHY_1000T_CTRL] = PHY_RW,
+    [PHY_LP_ABILITY] = PHY_R,  [PHY_1000T_STATUS] = PHY_R,
+    [PHY_AUTONEG_ADV] = PHY_RW,        [M88E1000_RX_ERR_CNTR] = PHY_R,
+    [PHY_ID2] = PHY_R,         [M88E1000_PHY_SPEC_STATUS] = PHY_R
+};
+
+static const uint16_t phy_reg_init[] = {
+    [PHY_CTRL] = 0x1140,
+    [PHY_STATUS] = 0x794d, /* link initially up with not completed autoneg */
+    [PHY_ID1] = 0x141,                         [PHY_ID2] = PHY_ID2_INIT,
+    [PHY_1000T_CTRL] = 0x0e00,                 [M88E1000_PHY_SPEC_CTRL] = 0x360,
+    [M88E1000_EXT_PHY_SPEC_CTRL] = 0x0d60,     [PHY_AUTONEG_ADV] = 0xde1,
+    [PHY_LP_ABILITY] = 0x1e0,                  [PHY_1000T_STATUS] = 0x3c00,
+    [M88E1000_PHY_SPEC_STATUS] = 0xac00,
+};
+
+static const uint32_t mac_reg_init[] = {
+    [PBA] =     0x00100030,
+    [LEDCTL] =  0x602,
+    [CTRL] =    E1000_CTRL_SWDPIN2 | E1000_CTRL_SWDPIN0 |
+                E1000_CTRL_SPD_1000 | E1000_CTRL_SLU,
+    [STATUS] =  0x80000000 | E1000_STATUS_GIO_MASTER_ENABLE |
+                E1000_STATUS_ASDV | E1000_STATUS_MTXCKOK |
+                E1000_STATUS_SPEED_1000 | E1000_STATUS_FD |
+                E1000_STATUS_LU,
+    [MANC] =    E1000_MANC_EN_MNG2HOST | E1000_MANC_RCV_TCO_EN |
+                E1000_MANC_ARP_EN | E1000_MANC_0298_EN |
+                E1000_MANC_RMCP_EN,
+};
+
+static void
+set_interrupt_cause(E1000State *s, int index, uint32_t val)
+{
+    if (val && (E1000_DEVID >= E1000_DEV_ID_82547EI_MOBILE)) {
+        /* Only for 8257x */
+        val |= E1000_ICR_INT_ASSERTED;
+    }
+    s->mac_reg[ICR] = val;
+
+    /*
+     * Make sure ICR and ICS registers have the same value.
+     * The spec says that the ICS register is write-only.  However in practice,
+     * on real hardware ICS is readable, and for reads it has the same value as
+     * ICR (except that ICS does not have the clear on read behaviour of ICR).
+     *
+     * The VxWorks PRO/1000 driver uses this behaviour.
+     */
+    s->mac_reg[ICS] = val;
+
+    qemu_set_irq(s->dev.irq[0], (s->mac_reg[IMS] & s->mac_reg[ICR]) != 0);
+}
+
+static void
+set_ics(E1000State *s, int index, uint32_t val)
+{
+    DBGOUT(INTERRUPT, "set_ics %x, ICR %x, IMR %x\n", val, s->mac_reg[ICR],
+        s->mac_reg[IMS]);
+    set_interrupt_cause(s, 0, val | s->mac_reg[ICR]);
+}
+
+static int
+rxbufsize(uint32_t v)
+{
+    v &= E1000_RCTL_BSEX | E1000_RCTL_SZ_16384 | E1000_RCTL_SZ_8192 |
+         E1000_RCTL_SZ_4096 | E1000_RCTL_SZ_2048 | E1000_RCTL_SZ_1024 |
+         E1000_RCTL_SZ_512 | E1000_RCTL_SZ_256;
+    switch (v) {
+    case E1000_RCTL_BSEX | E1000_RCTL_SZ_16384:
+        return 16384;
+    case E1000_RCTL_BSEX | E1000_RCTL_SZ_8192:
+        return 8192;
+    case E1000_RCTL_BSEX | E1000_RCTL_SZ_4096:
+        return 4096;
+    case E1000_RCTL_SZ_1024:
+        return 1024;
+    case E1000_RCTL_SZ_512:
+        return 512;
+    case E1000_RCTL_SZ_256:
+        return 256;
+    }
+    return 2048;
+}
+
+static void e1000_reset(void *opaque)
+{
+    E1000State *d = opaque;
+    uint8_t *macaddr = d->conf.macaddr.a;
+    int i;
+
+    qemu_del_timer(d->autoneg_timer);
+    memset(d->phy_reg, 0, sizeof d->phy_reg);
+    memmove(d->phy_reg, phy_reg_init, sizeof phy_reg_init);
+    memset(d->mac_reg, 0, sizeof d->mac_reg);
+    memmove(d->mac_reg, mac_reg_init, sizeof mac_reg_init);
+    d->rxbuf_min_shift = 1;
+    memset(&d->tx, 0, sizeof d->tx);
+
+    if (qemu_get_queue(d->nic)->link_down) {
+        e1000_link_down(d);
+    }
+
+    /* Some guests expect pre-initialized RAH/RAL (AddrValid flag + MACaddr) */
+    d->mac_reg[RA] = 0;
+    d->mac_reg[RA + 1] = E1000_RAH_AV;
+    for (i = 0; i < 4; i++) {
+        d->mac_reg[RA] |= macaddr[i] << (8 * i);
+        d->mac_reg[RA + 1] |= (i < 2) ? macaddr[i + 4] << (8 * i) : 0;
+    }
+}
+
+static void
+set_ctrl(E1000State *s, int index, uint32_t val)
+{
+    /* RST is self clearing */
+    s->mac_reg[CTRL] = val & ~E1000_CTRL_RST;
+}
+
+static void
+set_rx_control(E1000State *s, int index, uint32_t val)
+{
+    s->mac_reg[RCTL] = val;
+    s->rxbuf_size = rxbufsize(val);
+    s->rxbuf_min_shift = ((val / E1000_RCTL_RDMTS_QUAT) & 3) + 1;
+    DBGOUT(RX, "RCTL: %d, mac_reg[RCTL] = 0x%x\n", s->mac_reg[RDT],
+           s->mac_reg[RCTL]);
+    qemu_flush_queued_packets(qemu_get_queue(s->nic));
+}
+
+static void
+set_mdic(E1000State *s, int index, uint32_t val)
+{
+    uint32_t data = val & E1000_MDIC_DATA_MASK;
+    uint32_t addr = ((val & E1000_MDIC_REG_MASK) >> E1000_MDIC_REG_SHIFT);
+
+    if ((val & E1000_MDIC_PHY_MASK) >> E1000_MDIC_PHY_SHIFT != 1) // phy #
+        val = s->mac_reg[MDIC] | E1000_MDIC_ERROR;
+    else if (val & E1000_MDIC_OP_READ) {
+        DBGOUT(MDIC, "MDIC read reg 0x%x\n", addr);
+        if (!(phy_regcap[addr] & PHY_R)) {
+            DBGOUT(MDIC, "MDIC read reg %x unhandled\n", addr);
+            val |= E1000_MDIC_ERROR;
+        } else
+            val = (val ^ data) | s->phy_reg[addr];
+    } else if (val & E1000_MDIC_OP_WRITE) {
+        DBGOUT(MDIC, "MDIC write reg 0x%x, value 0x%x\n", addr, data);
+        if (!(phy_regcap[addr] & PHY_W)) {
+            DBGOUT(MDIC, "MDIC write reg %x unhandled\n", addr);
+            val |= E1000_MDIC_ERROR;
+        } else {
+            if (addr < NPHYWRITEOPS && phyreg_writeops[addr]) {
+                phyreg_writeops[addr](s, index, data);
+            }
+            s->phy_reg[addr] = data;
+        }
+    }
+    s->mac_reg[MDIC] = val | E1000_MDIC_READY;
+
+    if (val & E1000_MDIC_INT_EN) {
+        set_ics(s, 0, E1000_ICR_MDAC);
+    }
+}
+
+static uint32_t
+get_eecd(E1000State *s, int index)
+{
+    uint32_t ret = E1000_EECD_PRES|E1000_EECD_GNT | s->eecd_state.old_eecd;
+
+    DBGOUT(EEPROM, "reading eeprom bit %d (reading %d)\n",
+           s->eecd_state.bitnum_out, s->eecd_state.reading);
+    if (!s->eecd_state.reading ||
+        ((s->eeprom_data[(s->eecd_state.bitnum_out >> 4) & 0x3f] >>
+          ((s->eecd_state.bitnum_out & 0xf) ^ 0xf))) & 1)
+        ret |= E1000_EECD_DO;
+    return ret;
+}
+
+static void
+set_eecd(E1000State *s, int index, uint32_t val)
+{
+    uint32_t oldval = s->eecd_state.old_eecd;
+
+    s->eecd_state.old_eecd = val & (E1000_EECD_SK | E1000_EECD_CS |
+            E1000_EECD_DI|E1000_EECD_FWE_MASK|E1000_EECD_REQ);
+    if (!(E1000_EECD_CS & val))                        // CS inactive; nothing to do
+       return;
+    if (E1000_EECD_CS & (val ^ oldval)) {      // CS rise edge; reset state
+       s->eecd_state.val_in = 0;
+       s->eecd_state.bitnum_in = 0;
+       s->eecd_state.bitnum_out = 0;
+       s->eecd_state.reading = 0;
+    }
+    if (!(E1000_EECD_SK & (val ^ oldval)))     // no clock edge
+        return;
+    if (!(E1000_EECD_SK & val)) {              // falling edge
+        s->eecd_state.bitnum_out++;
+        return;
+    }
+    s->eecd_state.val_in <<= 1;
+    if (val & E1000_EECD_DI)
+        s->eecd_state.val_in |= 1;
+    if (++s->eecd_state.bitnum_in == 9 && !s->eecd_state.reading) {
+        s->eecd_state.bitnum_out = ((s->eecd_state.val_in & 0x3f)<<4)-1;
+        s->eecd_state.reading = (((s->eecd_state.val_in >> 6) & 7) ==
+            EEPROM_READ_OPCODE_MICROWIRE);
+    }
+    DBGOUT(EEPROM, "eeprom bitnum in %d out %d, reading %d\n",
+           s->eecd_state.bitnum_in, s->eecd_state.bitnum_out,
+           s->eecd_state.reading);
+}
+
+static uint32_t
+flash_eerd_read(E1000State *s, int x)
+{
+    unsigned int index, r = s->mac_reg[EERD] & ~E1000_EEPROM_RW_REG_START;
+
+    if ((s->mac_reg[EERD] & E1000_EEPROM_RW_REG_START) == 0)
+        return (s->mac_reg[EERD]);
+
+    if ((index = r >> E1000_EEPROM_RW_ADDR_SHIFT) > EEPROM_CHECKSUM_REG)
+        return (E1000_EEPROM_RW_REG_DONE | r);
+
+    return ((s->eeprom_data[index] << E1000_EEPROM_RW_REG_DATA) |
+           E1000_EEPROM_RW_REG_DONE | r);
+}
+
+static void
+putsum(uint8_t *data, uint32_t n, uint32_t sloc, uint32_t css, uint32_t cse)
+{
+    uint32_t sum;
+
+    if (cse && cse < n)
+        n = cse + 1;
+    if (sloc < n-1) {
+        sum = net_checksum_add(n-css, data+css);
+        cpu_to_be16wu((uint16_t *)(data + sloc),
+                      net_checksum_finish(sum));
+    }
+}
+
+static inline int
+vlan_enabled(E1000State *s)
+{
+    return ((s->mac_reg[CTRL] & E1000_CTRL_VME) != 0);
+}
+
+static inline int
+vlan_rx_filter_enabled(E1000State *s)
+{
+    return ((s->mac_reg[RCTL] & E1000_RCTL_VFE) != 0);
+}
+
+static inline int
+is_vlan_packet(E1000State *s, const uint8_t *buf)
+{
+    return (be16_to_cpup((uint16_t *)(buf + 12)) ==
+                le16_to_cpup((uint16_t *)(s->mac_reg + VET)));
+}
+
+static inline int
+is_vlan_txd(uint32_t txd_lower)
+{
+    return ((txd_lower & E1000_TXD_CMD_VLE) != 0);
+}
+
+/* FCS aka Ethernet CRC-32. We don't get it from backends and can't
+ * fill it in, just pad descriptor length by 4 bytes unless guest
+ * told us to strip it off the packet. */
+static inline int
+fcs_len(E1000State *s)
+{
+    return (s->mac_reg[RCTL] & E1000_RCTL_SECRC) ? 0 : 4;
+}
+
+static void
+e1000_send_packet(E1000State *s, const uint8_t *buf, int size)
+{
+    NetClientState *nc = qemu_get_queue(s->nic);
+    if (s->phy_reg[PHY_CTRL] & MII_CR_LOOPBACK) {
+        nc->info->receive(nc, buf, size);
+    } else {
+        qemu_send_packet(nc, buf, size);
+    }
+}
+
+static void
+xmit_seg(E1000State *s)
+{
+    uint16_t len, *sp;
+    unsigned int frames = s->tx.tso_frames, css, sofar, n;
+    struct e1000_tx *tp = &s->tx;
+
+    if (tp->tse && tp->cptse) {
+        css = tp->ipcss;
+        DBGOUT(TXSUM, "frames %d size %d ipcss %d\n",
+               frames, tp->size, css);
+        if (tp->ip) {          // IPv4
+            cpu_to_be16wu((uint16_t *)(tp->data+css+2),
+                          tp->size - css);
+            cpu_to_be16wu((uint16_t *)(tp->data+css+4),
+                          be16_to_cpup((uint16_t *)(tp->data+css+4))+frames);
+        } else                 // IPv6
+            cpu_to_be16wu((uint16_t *)(tp->data+css+4),
+                          tp->size - css);
+        css = tp->tucss;
+        len = tp->size - css;
+        DBGOUT(TXSUM, "tcp %d tucss %d len %d\n", tp->tcp, css, len);
+        if (tp->tcp) {
+            sofar = frames * tp->mss;
+            cpu_to_be32wu((uint32_t *)(tp->data+css+4),        // seq
+                be32_to_cpupu((uint32_t *)(tp->data+css+4))+sofar);
+            if (tp->paylen - sofar > tp->mss)
+                tp->data[css + 13] &= ~9;              // PSH, FIN
+        } else // UDP
+            cpu_to_be16wu((uint16_t *)(tp->data+css+4), len);
+        if (tp->sum_needed & E1000_TXD_POPTS_TXSM) {
+            unsigned int phsum;
+            // add pseudo-header length before checksum calculation
+            sp = (uint16_t *)(tp->data + tp->tucso);
+            phsum = be16_to_cpup(sp) + len;
+            phsum = (phsum >> 16) + (phsum & 0xffff);
+            cpu_to_be16wu(sp, phsum);
+        }
+        tp->tso_frames++;
+    }
+
+    if (tp->sum_needed & E1000_TXD_POPTS_TXSM)
+        putsum(tp->data, tp->size, tp->tucso, tp->tucss, tp->tucse);
+    if (tp->sum_needed & E1000_TXD_POPTS_IXSM)
+        putsum(tp->data, tp->size, tp->ipcso, tp->ipcss, tp->ipcse);
+    if (tp->vlan_needed) {
+        memmove(tp->vlan, tp->data, 4);
+        memmove(tp->data, tp->data + 4, 8);
+        memcpy(tp->data + 8, tp->vlan_header, 4);
+        e1000_send_packet(s, tp->vlan, tp->size + 4);
+    } else
+        e1000_send_packet(s, tp->data, tp->size);
+    s->mac_reg[TPT]++;
+    s->mac_reg[GPTC]++;
+    n = s->mac_reg[TOTL];
+    if ((s->mac_reg[TOTL] += s->tx.size) < n)
+        s->mac_reg[TOTH]++;
+}
+
+static void
+process_tx_desc(E1000State *s, struct e1000_tx_desc *dp)
+{
+    uint32_t txd_lower = le32_to_cpu(dp->lower.data);
+    uint32_t dtype = txd_lower & (E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D);
+    unsigned int split_size = txd_lower & 0xffff, bytes, sz, op;
+    unsigned int msh = 0xfffff, hdr = 0;
+    uint64_t addr;
+    struct e1000_context_desc *xp = (struct e1000_context_desc *)dp;
+    struct e1000_tx *tp = &s->tx;
+
+    if (dtype == E1000_TXD_CMD_DEXT) { // context descriptor
+        op = le32_to_cpu(xp->cmd_and_length);
+        tp->ipcss = xp->lower_setup.ip_fields.ipcss;
+        tp->ipcso = xp->lower_setup.ip_fields.ipcso;
+        tp->ipcse = le16_to_cpu(xp->lower_setup.ip_fields.ipcse);
+        tp->tucss = xp->upper_setup.tcp_fields.tucss;
+        tp->tucso = xp->upper_setup.tcp_fields.tucso;
+        tp->tucse = le16_to_cpu(xp->upper_setup.tcp_fields.tucse);
+        tp->paylen = op & 0xfffff;
+        tp->hdr_len = xp->tcp_seg_setup.fields.hdr_len;
+        tp->mss = le16_to_cpu(xp->tcp_seg_setup.fields.mss);
+        tp->ip = (op & E1000_TXD_CMD_IP) ? 1 : 0;
+        tp->tcp = (op & E1000_TXD_CMD_TCP) ? 1 : 0;
+        tp->tse = (op & E1000_TXD_CMD_TSE) ? 1 : 0;
+        tp->tso_frames = 0;
+        if (tp->tucso == 0) {  // this is probably wrong
+            DBGOUT(TXSUM, "TCP/UDP: cso 0!\n");
+            tp->tucso = tp->tucss + (tp->tcp ? 16 : 6);
+        }
+        return;
+    } else if (dtype == (E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D)) {
+        // data descriptor
+        if (tp->size == 0) {
+            tp->sum_needed = le32_to_cpu(dp->upper.data) >> 8;
+        }
+        tp->cptse = ( txd_lower & E1000_TXD_CMD_TSE ) ? 1 : 0;
+    } else {
+        // legacy descriptor
+        tp->cptse = 0;
+    }
+
+    if (vlan_enabled(s) && is_vlan_txd(txd_lower) &&
+        (tp->cptse || txd_lower & E1000_TXD_CMD_EOP)) {
+        tp->vlan_needed = 1;
+        cpu_to_be16wu((uint16_t *)(tp->vlan_header),
+                      le16_to_cpup((uint16_t *)(s->mac_reg + VET)));
+        cpu_to_be16wu((uint16_t *)(tp->vlan_header + 2),
+                      le16_to_cpu(dp->upper.fields.special));
+    }
+        
+    addr = le64_to_cpu(dp->buffer_addr);
+    if (tp->tse && tp->cptse) {
+        hdr = tp->hdr_len;
+        msh = hdr + tp->mss;
+        do {
+            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);
+            tp->size = sz;
+            addr += bytes;
+            if (sz == msh) {
+                xmit_seg(s);
+                memmove(tp->data, tp->header, hdr);
+                tp->size = hdr;
+            }
+        } while (split_size -= bytes);
+    } else if (!tp->tse && tp->cptse) {
+        // context descriptor TSE is not set, while data descriptor TSE is set
+        DBGOUT(TXERR, "TCP segmentation 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;
+    }
+
+    if (!(txd_lower & E1000_TXD_CMD_EOP))
+        return;
+    if (!(tp->tse && tp->cptse && tp->size < hdr))
+        xmit_seg(s);
+    tp->tso_frames = 0;
+    tp->sum_needed = 0;
+    tp->vlan_needed = 0;
+    tp->size = 0;
+    tp->cptse = 0;
+}
+
+static uint32_t
+txdesc_writeback(E1000State *s, dma_addr_t base, struct e1000_tx_desc *dp)
+{
+    uint32_t txd_upper, txd_lower = le32_to_cpu(dp->lower.data);
+
+    if (!(txd_lower & (E1000_TXD_CMD_RS|E1000_TXD_CMD_RPS)))
+        return 0;
+    txd_upper = (le32_to_cpu(dp->upper.data) | E1000_TXD_STAT_DD) &
+                ~(E1000_TXD_STAT_EC | E1000_TXD_STAT_LC | E1000_TXD_STAT_TU);
+    dp->upper.data = cpu_to_le32(txd_upper);
+    pci_dma_write(&s->dev, base + ((char *)&dp->upper - (char *)dp),
+                  &dp->upper, sizeof(dp->upper));
+    return E1000_ICR_TXDW;
+}
+
+static uint64_t tx_desc_base(E1000State *s)
+{
+    uint64_t bah = s->mac_reg[TDBAH];
+    uint64_t bal = s->mac_reg[TDBAL] & ~0xf;
+
+    return (bah << 32) + bal;
+}
+
+static void
+start_xmit(E1000State *s)
+{
+    dma_addr_t base;
+    struct e1000_tx_desc desc;
+    uint32_t tdh_start = s->mac_reg[TDH], cause = E1000_ICS_TXQE;
+
+    if (!(s->mac_reg[TCTL] & E1000_TCTL_EN)) {
+        DBGOUT(TX, "tx disabled\n");
+        return;
+    }
+
+    while (s->mac_reg[TDH] != s->mac_reg[TDT]) {
+        base = tx_desc_base(s) +
+               sizeof(struct e1000_tx_desc) * s->mac_reg[TDH];
+        pci_dma_read(&s->dev, base, &desc, sizeof(desc));
+
+        DBGOUT(TX, "index %d: %p : %x %x\n", s->mac_reg[TDH],
+               (void *)(intptr_t)desc.buffer_addr, desc.lower.data,
+               desc.upper.data);
+
+        process_tx_desc(s, &desc);
+        cause |= txdesc_writeback(s, base, &desc);
+
+        if (++s->mac_reg[TDH] * sizeof(desc) >= s->mac_reg[TDLEN])
+            s->mac_reg[TDH] = 0;
+        /*
+         * the following could happen only if guest sw assigns
+         * bogus values to TDT/TDLEN.
+         * there's nothing too intelligent we could do about this.
+         */
+        if (s->mac_reg[TDH] == tdh_start) {
+            DBGOUT(TXERR, "TDH wraparound @%x, TDT %x, TDLEN %x\n",
+                   tdh_start, s->mac_reg[TDT], s->mac_reg[TDLEN]);
+            break;
+        }
+    }
+    set_ics(s, 0, cause);
+}
+
+static int
+receive_filter(E1000State *s, const uint8_t *buf, int size)
+{
+    static const uint8_t bcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+    static const int mta_shift[] = {4, 3, 2, 0};
+    uint32_t f, rctl = s->mac_reg[RCTL], ra[2], *rp;
+
+    if (is_vlan_packet(s, buf) && vlan_rx_filter_enabled(s)) {
+        uint16_t vid = be16_to_cpup((uint16_t *)(buf + 14));
+        uint32_t vfta = le32_to_cpup((uint32_t *)(s->mac_reg + VFTA) +
+                                     ((vid >> 5) & 0x7f));
+        if ((vfta & (1 << (vid & 0x1f))) == 0)
+            return 0;
+    }
+
+    if (rctl & E1000_RCTL_UPE)                 // promiscuous
+        return 1;
+
+    if ((buf[0] & 1) && (rctl & E1000_RCTL_MPE))       // promiscuous mcast
+        return 1;
+
+    if ((rctl & E1000_RCTL_BAM) && !memcmp(buf, bcast, sizeof bcast))
+        return 1;
+
+    for (rp = s->mac_reg + RA; rp < s->mac_reg + RA + 32; rp += 2) {
+        if (!(rp[1] & E1000_RAH_AV))
+            continue;
+        ra[0] = cpu_to_le32(rp[0]);
+        ra[1] = cpu_to_le32(rp[1]);
+        if (!memcmp(buf, (uint8_t *)ra, 6)) {
+            DBGOUT(RXFILTER,
+                   "unicast match[%d]: %02x:%02x:%02x:%02x:%02x:%02x\n",
+                   (int)(rp - s->mac_reg - RA)/2,
+                   buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);
+            return 1;
+        }
+    }
+    DBGOUT(RXFILTER, "unicast mismatch: %02x:%02x:%02x:%02x:%02x:%02x\n",
+           buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);
+
+    f = mta_shift[(rctl >> E1000_RCTL_MO_SHIFT) & 3];
+    f = (((buf[5] << 8) | buf[4]) >> f) & 0xfff;
+    if (s->mac_reg[MTA + (f >> 5)] & (1 << (f & 0x1f)))
+        return 1;
+    DBGOUT(RXFILTER,
+           "dropping, inexact filter mismatch: %02x:%02x:%02x:%02x:%02x:%02x MO %d MTA[%d] %x\n",
+           buf[0], buf[1], buf[2], buf[3], buf[4], buf[5],
+           (rctl >> E1000_RCTL_MO_SHIFT) & 3, f >> 5,
+           s->mac_reg[MTA + (f >> 5)]);
+
+    return 0;
+}
+
+static void
+e1000_set_link_status(NetClientState *nc)
+{
+    E1000State *s = qemu_get_nic_opaque(nc);
+    uint32_t old_status = s->mac_reg[STATUS];
+
+    if (nc->link_down) {
+        e1000_link_down(s);
+    } else {
+        e1000_link_up(s);
+    }
+
+    if (s->mac_reg[STATUS] != old_status)
+        set_ics(s, 0, E1000_ICR_LSC);
+}
+
+static bool e1000_has_rxbufs(E1000State *s, size_t total_size)
+{
+    int bufs;
+    /* Fast-path short packets */
+    if (total_size <= s->rxbuf_size) {
+        return s->mac_reg[RDH] != s->mac_reg[RDT];
+    }
+    if (s->mac_reg[RDH] < s->mac_reg[RDT]) {
+        bufs = s->mac_reg[RDT] - s->mac_reg[RDH];
+    } else if (s->mac_reg[RDH] > s->mac_reg[RDT]) {
+        bufs = s->mac_reg[RDLEN] /  sizeof(struct e1000_rx_desc) +
+            s->mac_reg[RDT] - s->mac_reg[RDH];
+    } else {
+        return false;
+    }
+    return total_size <= bufs * s->rxbuf_size;
+}
+
+static int
+e1000_can_receive(NetClientState *nc)
+{
+    E1000State *s = qemu_get_nic_opaque(nc);
+
+    return (s->mac_reg[STATUS] & E1000_STATUS_LU) &&
+        (s->mac_reg[RCTL] & E1000_RCTL_EN) && e1000_has_rxbufs(s, 1);
+}
+
+static uint64_t rx_desc_base(E1000State *s)
+{
+    uint64_t bah = s->mac_reg[RDBAH];
+    uint64_t bal = s->mac_reg[RDBAL] & ~0xf;
+
+    return (bah << 32) + bal;
+}
+
+static ssize_t
+e1000_receive(NetClientState *nc, const uint8_t *buf, size_t size)
+{
+    E1000State *s = qemu_get_nic_opaque(nc);
+    struct e1000_rx_desc desc;
+    dma_addr_t base;
+    unsigned int n, rdt;
+    uint32_t rdh_start;
+    uint16_t vlan_special = 0;
+    uint8_t vlan_status = 0, vlan_offset = 0;
+    uint8_t min_buf[MIN_BUF_SIZE];
+    size_t desc_offset;
+    size_t desc_size;
+    size_t total_size;
+
+    if (!(s->mac_reg[STATUS] & E1000_STATUS_LU)) {
+        return -1;
+    }
+
+    if (!(s->mac_reg[RCTL] & E1000_RCTL_EN)) {
+        return -1;
+    }
+
+    /* Pad to minimum Ethernet frame length */
+    if (size < sizeof(min_buf)) {
+        memcpy(min_buf, buf, size);
+        memset(&min_buf[size], 0, sizeof(min_buf) - size);
+        buf = min_buf;
+        size = sizeof(min_buf);
+    }
+
+    /* Discard oversized packets if !LPE and !SBP. */
+    if ((size > MAXIMUM_ETHERNET_LPE_SIZE ||
+        (size > MAXIMUM_ETHERNET_VLAN_SIZE
+        && !(s->mac_reg[RCTL] & E1000_RCTL_LPE)))
+        && !(s->mac_reg[RCTL] & E1000_RCTL_SBP)) {
+        return size;
+    }
+
+    if (!receive_filter(s, buf, size))
+        return size;
+
+    if (vlan_enabled(s) && is_vlan_packet(s, buf)) {
+        vlan_special = cpu_to_le16(be16_to_cpup((uint16_t *)(buf + 14)));
+        memmove((uint8_t *)buf + 4, buf, 12);
+        vlan_status = E1000_RXD_STAT_VP;
+        vlan_offset = 4;
+        size -= 4;
+    }
+
+    rdh_start = s->mac_reg[RDH];
+    desc_offset = 0;
+    total_size = size + fcs_len(s);
+    if (!e1000_has_rxbufs(s, total_size)) {
+            set_ics(s, 0, E1000_ICS_RXO);
+            return -1;
+    }
+    do {
+        desc_size = total_size - desc_offset;
+        if (desc_size > s->rxbuf_size) {
+            desc_size = s->rxbuf_size;
+        }
+        base = rx_desc_base(s) + sizeof(desc) * s->mac_reg[RDH];
+        pci_dma_read(&s->dev, base, &desc, sizeof(desc));
+        desc.special = vlan_special;
+        desc.status |= (vlan_status | E1000_RXD_STAT_DD);
+        if (desc.buffer_addr) {
+            if (desc_offset < size) {
+                size_t copy_size = size - desc_offset;
+                if (copy_size > s->rxbuf_size) {
+                    copy_size = s->rxbuf_size;
+                }
+                pci_dma_write(&s->dev, le64_to_cpu(desc.buffer_addr),
+                              buf + desc_offset + vlan_offset, copy_size);
+            }
+            desc_offset += desc_size;
+            desc.length = cpu_to_le16(desc_size);
+            if (desc_offset >= total_size) {
+                desc.status |= E1000_RXD_STAT_EOP | E1000_RXD_STAT_IXSM;
+            } else {
+                /* Guest zeroing out status is not a hardware requirement.
+                   Clear EOP in case guest didn't do it. */
+                desc.status &= ~E1000_RXD_STAT_EOP;
+            }
+        } else { // as per intel docs; skip descriptors with null buf addr
+            DBGOUT(RX, "Null RX descriptor!!\n");
+        }
+        pci_dma_write(&s->dev, base, &desc, sizeof(desc));
+
+        if (++s->mac_reg[RDH] * sizeof(desc) >= s->mac_reg[RDLEN])
+            s->mac_reg[RDH] = 0;
+        /* see comment in start_xmit; same here */
+        if (s->mac_reg[RDH] == rdh_start) {
+            DBGOUT(RXERR, "RDH wraparound @%x, RDT %x, RDLEN %x\n",
+                   rdh_start, s->mac_reg[RDT], s->mac_reg[RDLEN]);
+            set_ics(s, 0, E1000_ICS_RXO);
+            return -1;
+        }
+    } while (desc_offset < total_size);
+
+    s->mac_reg[GPRC]++;
+    s->mac_reg[TPR]++;
+    /* TOR - Total Octets Received:
+     * This register includes bytes received in a packet from the <Destination
+     * Address> field through the <CRC> field, inclusively.
+     */
+    n = s->mac_reg[TORL] + size + /* Always include FCS length. */ 4;
+    if (n < s->mac_reg[TORL])
+        s->mac_reg[TORH]++;
+    s->mac_reg[TORL] = n;
+
+    n = E1000_ICS_RXT0;
+    if ((rdt = s->mac_reg[RDT]) < s->mac_reg[RDH])
+        rdt += s->mac_reg[RDLEN] / sizeof(desc);
+    if (((rdt - s->mac_reg[RDH]) * sizeof(desc)) <= s->mac_reg[RDLEN] >>
+        s->rxbuf_min_shift)
+        n |= E1000_ICS_RXDMT0;
+
+    set_ics(s, 0, n);
+
+    return size;
+}
+
+static uint32_t
+mac_readreg(E1000State *s, int index)
+{
+    return s->mac_reg[index];
+}
+
+static uint32_t
+mac_icr_read(E1000State *s, int index)
+{
+    uint32_t ret = s->mac_reg[ICR];
+
+    DBGOUT(INTERRUPT, "ICR read: %x\n", ret);
+    set_interrupt_cause(s, 0, 0);
+    return ret;
+}
+
+static uint32_t
+mac_read_clr4(E1000State *s, int index)
+{
+    uint32_t ret = s->mac_reg[index];
+
+    s->mac_reg[index] = 0;
+    return ret;
+}
+
+static uint32_t
+mac_read_clr8(E1000State *s, int index)
+{
+    uint32_t ret = s->mac_reg[index];
+
+    s->mac_reg[index] = 0;
+    s->mac_reg[index-1] = 0;
+    return ret;
+}
+
+static void
+mac_writereg(E1000State *s, int index, uint32_t val)
+{
+    s->mac_reg[index] = val;
+}
+
+static void
+set_rdt(E1000State *s, int index, uint32_t val)
+{
+    s->mac_reg[index] = val & 0xffff;
+    if (e1000_has_rxbufs(s, 1)) {
+        qemu_flush_queued_packets(qemu_get_queue(s->nic));
+    }
+}
+
+static void
+set_16bit(E1000State *s, int index, uint32_t val)
+{
+    s->mac_reg[index] = val & 0xffff;
+}
+
+static void
+set_dlen(E1000State *s, int index, uint32_t val)
+{
+    s->mac_reg[index] = val & 0xfff80;
+}
+
+static void
+set_tctl(E1000State *s, int index, uint32_t val)
+{
+    s->mac_reg[index] = val;
+    s->mac_reg[TDT] &= 0xffff;
+    start_xmit(s);
+}
+
+static void
+set_icr(E1000State *s, int index, uint32_t val)
+{
+    DBGOUT(INTERRUPT, "set_icr %x\n", val);
+    set_interrupt_cause(s, 0, s->mac_reg[ICR] & ~val);
+}
+
+static void
+set_imc(E1000State *s, int index, uint32_t val)
+{
+    s->mac_reg[IMS] &= ~val;
+    set_ics(s, 0, 0);
+}
+
+static void
+set_ims(E1000State *s, int index, uint32_t val)
+{
+    s->mac_reg[IMS] |= val;
+    set_ics(s, 0, 0);
+}
+
+#define getreg(x)      [x] = mac_readreg
+static uint32_t (*macreg_readops[])(E1000State *, int) = {
+    getreg(PBA),       getreg(RCTL),   getreg(TDH),    getreg(TXDCTL),
+    getreg(WUFC),      getreg(TDT),    getreg(CTRL),   getreg(LEDCTL),
+    getreg(MANC),      getreg(MDIC),   getreg(SWSM),   getreg(STATUS),
+    getreg(TORL),      getreg(TOTL),   getreg(IMS),    getreg(TCTL),
+    getreg(RDH),       getreg(RDT),    getreg(VET),    getreg(ICS),
+    getreg(TDBAL),     getreg(TDBAH),  getreg(RDBAH),  getreg(RDBAL),
+    getreg(TDLEN),     getreg(RDLEN),
+
+    [TOTH] = mac_read_clr8,    [TORH] = mac_read_clr8, [GPRC] = mac_read_clr4,
+    [GPTC] = mac_read_clr4,    [TPR] = mac_read_clr4,  [TPT] = mac_read_clr4,
+    [ICR] = mac_icr_read,      [EECD] = get_eecd,      [EERD] = flash_eerd_read,
+    [CRCERRS ... MPC] = &mac_readreg,
+    [RA ... RA+31] = &mac_readreg,
+    [MTA ... MTA+127] = &mac_readreg,
+    [VFTA ... VFTA+127] = &mac_readreg,
+};
+enum { NREADOPS = ARRAY_SIZE(macreg_readops) };
+
+#define putreg(x)      [x] = mac_writereg
+static void (*macreg_writeops[])(E1000State *, int, uint32_t) = {
+    putreg(PBA),       putreg(EERD),   putreg(SWSM),   putreg(WUFC),
+    putreg(TDBAL),     putreg(TDBAH),  putreg(TXDCTL), putreg(RDBAH),
+    putreg(RDBAL),     putreg(LEDCTL), putreg(VET),
+    [TDLEN] = set_dlen,        [RDLEN] = set_dlen,     [TCTL] = set_tctl,
+    [TDT] = set_tctl,  [MDIC] = set_mdic,      [ICS] = set_ics,
+    [TDH] = set_16bit, [RDH] = set_16bit,      [RDT] = set_rdt,
+    [IMC] = set_imc,   [IMS] = set_ims,        [ICR] = set_icr,
+    [EECD] = set_eecd, [RCTL] = set_rx_control, [CTRL] = set_ctrl,
+    [RA ... RA+31] = &mac_writereg,
+    [MTA ... MTA+127] = &mac_writereg,
+    [VFTA ... VFTA+127] = &mac_writereg,
+};
+
+enum { NWRITEOPS = ARRAY_SIZE(macreg_writeops) };
+
+static void
+e1000_mmio_write(void *opaque, hwaddr addr, uint64_t val,
+                 unsigned size)
+{
+    E1000State *s = opaque;
+    unsigned int index = (addr & 0x1ffff) >> 2;
+
+    if (index < NWRITEOPS && macreg_writeops[index]) {
+        macreg_writeops[index](s, index, val);
+    } else if (index < NREADOPS && macreg_readops[index]) {
+        DBGOUT(MMIO, "e1000_mmio_writel RO %x: 0x%04"PRIx64"\n", index<<2, val);
+    } else {
+        DBGOUT(UNKNOWN, "MMIO unknown write addr=0x%08x,val=0x%08"PRIx64"\n",
+               index<<2, val);
+    }
+}
+
+static uint64_t
+e1000_mmio_read(void *opaque, hwaddr addr, unsigned size)
+{
+    E1000State *s = opaque;
+    unsigned int index = (addr & 0x1ffff) >> 2;
+
+    if (index < NREADOPS && macreg_readops[index])
+    {
+        return macreg_readops[index](s, index);
+    }
+    DBGOUT(UNKNOWN, "MMIO unknown read addr=0x%08x\n", index<<2);
+    return 0;
+}
+
+static const MemoryRegionOps e1000_mmio_ops = {
+    .read = e1000_mmio_read,
+    .write = e1000_mmio_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static uint64_t e1000_io_read(void *opaque, hwaddr addr,
+                              unsigned size)
+{
+    E1000State *s = opaque;
+
+    (void)s;
+    return 0;
+}
+
+static void e1000_io_write(void *opaque, hwaddr addr,
+                           uint64_t val, unsigned size)
+{
+    E1000State *s = opaque;
+
+    (void)s;
+}
+
+static const MemoryRegionOps e1000_io_ops = {
+    .read = e1000_io_read,
+    .write = e1000_io_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static bool is_version_1(void *opaque, int version_id)
+{
+    return version_id == 1;
+}
+
+static void e1000_pre_save(void *opaque)
+{
+    E1000State *s = opaque;
+    NetClientState *nc = qemu_get_queue(s->nic);
+
+    if (!(s->compat_flags & E1000_FLAG_AUTONEG)) {
+        return;
+    }
+
+    /*
+     * If link is down and auto-negotiation is ongoing, complete
+     * auto-negotiation immediately.  This allows is to look at
+     * MII_SR_AUTONEG_COMPLETE to infer link status on load.
+     */
+    if (nc->link_down &&
+        s->phy_reg[PHY_CTRL] & MII_CR_AUTO_NEG_EN &&
+        s->phy_reg[PHY_CTRL] & MII_CR_RESTART_AUTO_NEG) {
+         s->phy_reg[PHY_STATUS] |= MII_SR_AUTONEG_COMPLETE;
+    }
+}
+
+static int e1000_post_load(void *opaque, int version_id)
+{
+    E1000State *s = opaque;
+    NetClientState *nc = qemu_get_queue(s->nic);
+
+    /* nc.link_down can't be migrated, so infer link_down according
+     * to link status bit in mac_reg[STATUS].
+     * Alternatively, restart link negotiation if it was in progress. */
+    nc->link_down = (s->mac_reg[STATUS] & E1000_STATUS_LU) == 0;
+
+    if (!(s->compat_flags & E1000_FLAG_AUTONEG)) {
+        return 0;
+    }
+
+    if (s->phy_reg[PHY_CTRL] & MII_CR_AUTO_NEG_EN &&
+        s->phy_reg[PHY_CTRL] & MII_CR_RESTART_AUTO_NEG &&
+        !(s->phy_reg[PHY_STATUS] & MII_SR_AUTONEG_COMPLETE)) {
+        nc->link_down = false;
+        qemu_mod_timer(s->autoneg_timer, qemu_get_clock_ms(vm_clock) + 500);
+    }
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_e1000 = {
+    .name = "e1000",
+    .version_id = 2,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .pre_save = e1000_pre_save,
+    .post_load = e1000_post_load,
+    .fields      = (VMStateField []) {
+        VMSTATE_PCI_DEVICE(dev, E1000State),
+        VMSTATE_UNUSED_TEST(is_version_1, 4), /* was instance id */
+        VMSTATE_UNUSED(4), /* Was mmio_base.  */
+        VMSTATE_UINT32(rxbuf_size, E1000State),
+        VMSTATE_UINT32(rxbuf_min_shift, E1000State),
+        VMSTATE_UINT32(eecd_state.val_in, E1000State),
+        VMSTATE_UINT16(eecd_state.bitnum_in, E1000State),
+        VMSTATE_UINT16(eecd_state.bitnum_out, E1000State),
+        VMSTATE_UINT16(eecd_state.reading, E1000State),
+        VMSTATE_UINT32(eecd_state.old_eecd, E1000State),
+        VMSTATE_UINT8(tx.ipcss, E1000State),
+        VMSTATE_UINT8(tx.ipcso, E1000State),
+        VMSTATE_UINT16(tx.ipcse, E1000State),
+        VMSTATE_UINT8(tx.tucss, E1000State),
+        VMSTATE_UINT8(tx.tucso, E1000State),
+        VMSTATE_UINT16(tx.tucse, E1000State),
+        VMSTATE_UINT32(tx.paylen, E1000State),
+        VMSTATE_UINT8(tx.hdr_len, E1000State),
+        VMSTATE_UINT16(tx.mss, E1000State),
+        VMSTATE_UINT16(tx.size, E1000State),
+        VMSTATE_UINT16(tx.tso_frames, E1000State),
+        VMSTATE_UINT8(tx.sum_needed, E1000State),
+        VMSTATE_INT8(tx.ip, E1000State),
+        VMSTATE_INT8(tx.tcp, E1000State),
+        VMSTATE_BUFFER(tx.header, E1000State),
+        VMSTATE_BUFFER(tx.data, E1000State),
+        VMSTATE_UINT16_ARRAY(eeprom_data, E1000State, 64),
+        VMSTATE_UINT16_ARRAY(phy_reg, E1000State, 0x20),
+        VMSTATE_UINT32(mac_reg[CTRL], E1000State),
+        VMSTATE_UINT32(mac_reg[EECD], E1000State),
+        VMSTATE_UINT32(mac_reg[EERD], E1000State),
+        VMSTATE_UINT32(mac_reg[GPRC], E1000State),
+        VMSTATE_UINT32(mac_reg[GPTC], E1000State),
+        VMSTATE_UINT32(mac_reg[ICR], E1000State),
+        VMSTATE_UINT32(mac_reg[ICS], E1000State),
+        VMSTATE_UINT32(mac_reg[IMC], E1000State),
+        VMSTATE_UINT32(mac_reg[IMS], E1000State),
+        VMSTATE_UINT32(mac_reg[LEDCTL], E1000State),
+        VMSTATE_UINT32(mac_reg[MANC], E1000State),
+        VMSTATE_UINT32(mac_reg[MDIC], E1000State),
+        VMSTATE_UINT32(mac_reg[MPC], E1000State),
+        VMSTATE_UINT32(mac_reg[PBA], E1000State),
+        VMSTATE_UINT32(mac_reg[RCTL], E1000State),
+        VMSTATE_UINT32(mac_reg[RDBAH], E1000State),
+        VMSTATE_UINT32(mac_reg[RDBAL], E1000State),
+        VMSTATE_UINT32(mac_reg[RDH], E1000State),
+        VMSTATE_UINT32(mac_reg[RDLEN], E1000State),
+        VMSTATE_UINT32(mac_reg[RDT], E1000State),
+        VMSTATE_UINT32(mac_reg[STATUS], E1000State),
+        VMSTATE_UINT32(mac_reg[SWSM], E1000State),
+        VMSTATE_UINT32(mac_reg[TCTL], E1000State),
+        VMSTATE_UINT32(mac_reg[TDBAH], E1000State),
+        VMSTATE_UINT32(mac_reg[TDBAL], E1000State),
+        VMSTATE_UINT32(mac_reg[TDH], E1000State),
+        VMSTATE_UINT32(mac_reg[TDLEN], E1000State),
+        VMSTATE_UINT32(mac_reg[TDT], E1000State),
+        VMSTATE_UINT32(mac_reg[TORH], E1000State),
+        VMSTATE_UINT32(mac_reg[TORL], E1000State),
+        VMSTATE_UINT32(mac_reg[TOTH], E1000State),
+        VMSTATE_UINT32(mac_reg[TOTL], E1000State),
+        VMSTATE_UINT32(mac_reg[TPR], E1000State),
+        VMSTATE_UINT32(mac_reg[TPT], E1000State),
+        VMSTATE_UINT32(mac_reg[TXDCTL], E1000State),
+        VMSTATE_UINT32(mac_reg[WUFC], E1000State),
+        VMSTATE_UINT32(mac_reg[VET], E1000State),
+        VMSTATE_UINT32_SUB_ARRAY(mac_reg, E1000State, RA, 32),
+        VMSTATE_UINT32_SUB_ARRAY(mac_reg, E1000State, MTA, 128),
+        VMSTATE_UINT32_SUB_ARRAY(mac_reg, E1000State, VFTA, 128),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const uint16_t e1000_eeprom_template[64] = {
+    0x0000, 0x0000, 0x0000, 0x0000,      0xffff, 0x0000,      0x0000, 0x0000,
+    0x3000, 0x1000, 0x6403, E1000_DEVID, 0x8086, E1000_DEVID, 0x8086, 0x3040,
+    0x0008, 0x2000, 0x7e14, 0x0048,      0x1000, 0x00d8,      0x0000, 0x2700,
+    0x6cc9, 0x3150, 0x0722, 0x040b,      0x0984, 0x0000,      0xc000, 0x0706,
+    0x1008, 0x0000, 0x0f04, 0x7fff,      0x4d01, 0xffff,      0xffff, 0xffff,
+    0xffff, 0xffff, 0xffff, 0xffff,      0xffff, 0xffff,      0xffff, 0xffff,
+    0x0100, 0x4000, 0x121c, 0xffff,      0xffff, 0xffff,      0xffff, 0xffff,
+    0xffff, 0xffff, 0xffff, 0xffff,      0xffff, 0xffff,      0xffff, 0x0000,
+};
+
+/* PCI interface */
+
+static void
+e1000_mmio_setup(E1000State *d)
+{
+    int i;
+    const uint32_t excluded_regs[] = {
+        E1000_MDIC, E1000_ICR, E1000_ICS, E1000_IMS,
+        E1000_IMC, E1000_TCTL, E1000_TDT, PNPMMIO_SIZE
+    };
+
+    memory_region_init_io(&d->mmio, &e1000_mmio_ops, d, "e1000-mmio",
+                          PNPMMIO_SIZE);
+    memory_region_add_coalescing(&d->mmio, 0, excluded_regs[0]);
+    for (i = 0; excluded_regs[i] != PNPMMIO_SIZE; i++)
+        memory_region_add_coalescing(&d->mmio, excluded_regs[i] + 4,
+                                     excluded_regs[i+1] - excluded_regs[i] - 4);
+    memory_region_init_io(&d->io, &e1000_io_ops, d, "e1000-io", IOPORT_SIZE);
+}
+
+static void
+e1000_cleanup(NetClientState *nc)
+{
+    E1000State *s = qemu_get_nic_opaque(nc);
+
+    s->nic = NULL;
+}
+
+static void
+pci_e1000_uninit(PCIDevice *dev)
+{
+    E1000State *d = DO_UPCAST(E1000State, dev, dev);
+
+    qemu_del_timer(d->autoneg_timer);
+    qemu_free_timer(d->autoneg_timer);
+    memory_region_destroy(&d->mmio);
+    memory_region_destroy(&d->io);
+    qemu_del_nic(d->nic);
+}
+
+static NetClientInfo net_e1000_info = {
+    .type = NET_CLIENT_OPTIONS_KIND_NIC,
+    .size = sizeof(NICState),
+    .can_receive = e1000_can_receive,
+    .receive = e1000_receive,
+    .cleanup = e1000_cleanup,
+    .link_status_changed = e1000_set_link_status,
+};
+
+static int pci_e1000_init(PCIDevice *pci_dev)
+{
+    E1000State *d = DO_UPCAST(E1000State, dev, pci_dev);
+    uint8_t *pci_conf;
+    uint16_t checksum = 0;
+    int i;
+    uint8_t *macaddr;
+
+    pci_conf = d->dev.config;
+
+    /* TODO: RST# value should be 0, PCI spec 6.2.4 */
+    pci_conf[PCI_CACHE_LINE_SIZE] = 0x10;
+
+    pci_conf[PCI_INTERRUPT_PIN] = 1; /* interrupt pin A */
+
+    e1000_mmio_setup(d);
+
+    pci_register_bar(&d->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &d->mmio);
+
+    pci_register_bar(&d->dev, 1, PCI_BASE_ADDRESS_SPACE_IO, &d->io);
+
+    memmove(d->eeprom_data, e1000_eeprom_template,
+        sizeof e1000_eeprom_template);
+    qemu_macaddr_default_if_unset(&d->conf.macaddr);
+    macaddr = d->conf.macaddr.a;
+    for (i = 0; i < 3; i++)
+        d->eeprom_data[i] = (macaddr[2*i+1]<<8) | macaddr[2*i];
+    for (i = 0; i < EEPROM_CHECKSUM_REG; i++)
+        checksum += d->eeprom_data[i];
+    checksum = (uint16_t) EEPROM_SUM - checksum;
+    d->eeprom_data[EEPROM_CHECKSUM_REG] = checksum;
+
+    d->nic = qemu_new_nic(&net_e1000_info, &d->conf,
+                          object_get_typename(OBJECT(d)), d->dev.qdev.id, d);
+
+    qemu_format_nic_info_str(qemu_get_queue(d->nic), macaddr);
+
+    add_boot_device_path(d->conf.bootindex, &pci_dev->qdev, "/ethernet-phy@0");
+
+    d->autoneg_timer = qemu_new_timer_ms(vm_clock, e1000_autoneg_timer, d);
+
+    return 0;
+}
+
+static void qdev_e1000_reset(DeviceState *dev)
+{
+    E1000State *d = DO_UPCAST(E1000State, dev.qdev, dev);
+    e1000_reset(d);
+}
+
+static Property e1000_properties[] = {
+    DEFINE_NIC_PROPERTIES(E1000State, conf),
+    DEFINE_PROP_BIT("autonegotiation", E1000State,
+                    compat_flags, E1000_FLAG_AUTONEG_BIT, true),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void e1000_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = pci_e1000_init;
+    k->exit = pci_e1000_uninit;
+    k->romfile = "efi-e1000.rom";
+    k->vendor_id = PCI_VENDOR_ID_INTEL;
+    k->device_id = E1000_DEVID;
+    k->revision = 0x03;
+    k->class_id = PCI_CLASS_NETWORK_ETHERNET;
+    dc->desc = "Intel Gigabit Ethernet";
+    dc->reset = qdev_e1000_reset;
+    dc->vmsd = &vmstate_e1000;
+    dc->props = e1000_properties;
+}
+
+static const TypeInfo e1000_info = {
+    .name          = "e1000",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(E1000State),
+    .class_init    = e1000_class_init,
+};
+
+static void e1000_register_types(void)
+{
+    type_register_static(&e1000_info);
+}
+
+type_init(e1000_register_types)
diff --git a/hw/net/e1000_regs.h b/hw/net/e1000_regs.h
new file mode 100644 (file)
index 0000000..c9cb79e
--- /dev/null
@@ -0,0 +1,893 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2006 Intel Corporation.
+
+  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, 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/>.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+/* e1000_hw.h
+ * Structures, enums, and macros for the MAC
+ */
+
+#ifndef _E1000_HW_H_
+#define _E1000_HW_H_
+
+
+/* PCI Device IDs */
+#define E1000_DEV_ID_82542               0x1000
+#define E1000_DEV_ID_82543GC_FIBER       0x1001
+#define E1000_DEV_ID_82543GC_COPPER      0x1004
+#define E1000_DEV_ID_82544EI_COPPER      0x1008
+#define E1000_DEV_ID_82544EI_FIBER       0x1009
+#define E1000_DEV_ID_82544GC_COPPER      0x100C
+#define E1000_DEV_ID_82544GC_LOM         0x100D
+#define E1000_DEV_ID_82540EM             0x100E
+#define E1000_DEV_ID_82540EM_LOM         0x1015
+#define E1000_DEV_ID_82540EP_LOM         0x1016
+#define E1000_DEV_ID_82540EP             0x1017
+#define E1000_DEV_ID_82540EP_LP          0x101E
+#define E1000_DEV_ID_82545EM_COPPER      0x100F
+#define E1000_DEV_ID_82545EM_FIBER       0x1011
+#define E1000_DEV_ID_82545GM_COPPER      0x1026
+#define E1000_DEV_ID_82545GM_FIBER       0x1027
+#define E1000_DEV_ID_82545GM_SERDES      0x1028
+#define E1000_DEV_ID_82546EB_COPPER      0x1010
+#define E1000_DEV_ID_82546EB_FIBER       0x1012
+#define E1000_DEV_ID_82546EB_QUAD_COPPER 0x101D
+#define E1000_DEV_ID_82541EI             0x1013
+#define E1000_DEV_ID_82541EI_MOBILE      0x1018
+#define E1000_DEV_ID_82541ER_LOM         0x1014
+#define E1000_DEV_ID_82541ER             0x1078
+#define E1000_DEV_ID_82547GI             0x1075
+#define E1000_DEV_ID_82541GI             0x1076
+#define E1000_DEV_ID_82541GI_MOBILE      0x1077
+#define E1000_DEV_ID_82541GI_LF          0x107C
+#define E1000_DEV_ID_82546GB_COPPER      0x1079
+#define E1000_DEV_ID_82546GB_FIBER       0x107A
+#define E1000_DEV_ID_82546GB_SERDES      0x107B
+#define E1000_DEV_ID_82546GB_PCIE        0x108A
+#define E1000_DEV_ID_82546GB_QUAD_COPPER 0x1099
+#define E1000_DEV_ID_82547EI             0x1019
+#define E1000_DEV_ID_82547EI_MOBILE      0x101A
+#define E1000_DEV_ID_82571EB_COPPER      0x105E
+#define E1000_DEV_ID_82571EB_FIBER       0x105F
+#define E1000_DEV_ID_82571EB_SERDES      0x1060
+#define E1000_DEV_ID_82571EB_QUAD_COPPER 0x10A4
+#define E1000_DEV_ID_82571PT_QUAD_COPPER 0x10D5
+#define E1000_DEV_ID_82571EB_QUAD_FIBER  0x10A5
+#define E1000_DEV_ID_82571EB_QUAD_COPPER_LOWPROFILE  0x10BC
+#define E1000_DEV_ID_82571EB_SERDES_DUAL 0x10D9
+#define E1000_DEV_ID_82571EB_SERDES_QUAD 0x10DA
+#define E1000_DEV_ID_82572EI_COPPER      0x107D
+#define E1000_DEV_ID_82572EI_FIBER       0x107E
+#define E1000_DEV_ID_82572EI_SERDES      0x107F
+#define E1000_DEV_ID_82572EI             0x10B9
+#define E1000_DEV_ID_82573E              0x108B
+#define E1000_DEV_ID_82573E_IAMT         0x108C
+#define E1000_DEV_ID_82573L              0x109A
+#define E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3 0x10B5
+#define E1000_DEV_ID_80003ES2LAN_COPPER_DPT     0x1096
+#define E1000_DEV_ID_80003ES2LAN_SERDES_DPT     0x1098
+#define E1000_DEV_ID_80003ES2LAN_COPPER_SPT     0x10BA
+#define E1000_DEV_ID_80003ES2LAN_SERDES_SPT     0x10BB
+
+#define E1000_DEV_ID_ICH8_IGP_M_AMT      0x1049
+#define E1000_DEV_ID_ICH8_IGP_AMT        0x104A
+#define E1000_DEV_ID_ICH8_IGP_C          0x104B
+#define E1000_DEV_ID_ICH8_IFE            0x104C
+#define E1000_DEV_ID_ICH8_IFE_GT         0x10C4
+#define E1000_DEV_ID_ICH8_IFE_G          0x10C5
+#define E1000_DEV_ID_ICH8_IGP_M          0x104D
+
+/* Register Set. (82543, 82544)
+ *
+ * Registers are defined to be 32 bits and  should be accessed as 32 bit values.
+ * These registers are physically located on the NIC, but are mapped into the
+ * host memory address space.
+ *
+ * RW - register is both readable and writable
+ * RO - register is read only
+ * WO - register is write only
+ * R/clr - register is read only and is cleared when read
+ * A - register array
+ */
+#define E1000_CTRL     0x00000  /* Device Control - RW */
+#define E1000_CTRL_DUP 0x00004  /* Device Control Duplicate (Shadow) - RW */
+#define E1000_STATUS   0x00008  /* Device Status - RO */
+#define E1000_EECD     0x00010  /* EEPROM/Flash Control - RW */
+#define E1000_EERD     0x00014  /* EEPROM Read - RW */
+#define E1000_CTRL_EXT 0x00018  /* Extended Device Control - RW */
+#define E1000_FLA      0x0001C  /* Flash Access - RW */
+#define E1000_MDIC     0x00020  /* MDI Control - RW */
+#define E1000_SCTL     0x00024  /* SerDes Control - RW */
+#define E1000_FEXTNVM  0x00028  /* Future Extended NVM register */
+#define E1000_FCAL     0x00028  /* Flow Control Address Low - RW */
+#define E1000_FCAH     0x0002C  /* Flow Control Address High -RW */
+#define E1000_FCT      0x00030  /* Flow Control Type - RW */
+#define E1000_VET      0x00038  /* VLAN Ether Type - RW */
+#define E1000_ICR      0x000C0  /* Interrupt Cause Read - R/clr */
+#define E1000_ITR      0x000C4  /* Interrupt Throttling Rate - RW */
+#define E1000_ICS      0x000C8  /* Interrupt Cause Set - WO */
+#define E1000_IMS      0x000D0  /* Interrupt Mask Set - RW */
+#define E1000_IMC      0x000D8  /* Interrupt Mask Clear - WO */
+#define E1000_IAM      0x000E0  /* Interrupt Acknowledge Auto Mask */
+#define E1000_RCTL     0x00100  /* RX Control - RW */
+#define E1000_RDTR1    0x02820  /* RX Delay Timer (1) - RW */
+#define E1000_RDBAL1   0x02900  /* RX Descriptor Base Address Low (1) - RW */
+#define E1000_RDBAH1   0x02904  /* RX Descriptor Base Address High (1) - RW */
+#define E1000_RDLEN1   0x02908  /* RX Descriptor Length (1) - RW */
+#define E1000_RDH1     0x02910  /* RX Descriptor Head (1) - RW */
+#define E1000_RDT1     0x02918  /* RX Descriptor Tail (1) - RW */
+#define E1000_FCTTV    0x00170  /* Flow Control Transmit Timer Value - RW */
+#define E1000_TXCW     0x00178  /* TX Configuration Word - RW */
+#define E1000_RXCW     0x00180  /* RX Configuration Word - RO */
+#define E1000_TCTL     0x00400  /* TX Control - RW */
+#define E1000_TCTL_EXT 0x00404  /* Extended TX Control - RW */
+#define E1000_TIPG     0x00410  /* TX Inter-packet gap -RW */
+#define E1000_TBT      0x00448  /* TX Burst Timer - RW */
+#define E1000_AIT      0x00458  /* Adaptive Interframe Spacing Throttle - RW */
+#define E1000_LEDCTL   0x00E00  /* LED Control - RW */
+#define E1000_EXTCNF_CTRL  0x00F00  /* Extended Configuration Control */
+#define E1000_EXTCNF_SIZE  0x00F08  /* Extended Configuration Size */
+#define E1000_PHY_CTRL     0x00F10  /* PHY Control Register in CSR */
+#define FEXTNVM_SW_CONFIG  0x0001
+#define E1000_PBA      0x01000  /* Packet Buffer Allocation - RW */
+#define E1000_PBS      0x01008  /* Packet Buffer Size */
+#define E1000_EEMNGCTL 0x01010  /* MNG EEprom Control */
+#define E1000_FLASH_UPDATES 1000
+#define E1000_EEARBC   0x01024  /* EEPROM Auto Read Bus Control */
+#define E1000_FLASHT   0x01028  /* FLASH Timer Register */
+#define E1000_EEWR     0x0102C  /* EEPROM Write Register - RW */
+#define E1000_FLSWCTL  0x01030  /* FLASH control register */
+#define E1000_FLSWDATA 0x01034  /* FLASH data register */
+#define E1000_FLSWCNT  0x01038  /* FLASH Access Counter */
+#define E1000_FLOP     0x0103C  /* FLASH Opcode Register */
+#define E1000_ERT      0x02008  /* Early Rx Threshold - RW */
+#define E1000_FCRTL    0x02160  /* Flow Control Receive Threshold Low - RW */
+#define E1000_FCRTH    0x02168  /* Flow Control Receive Threshold High - RW */
+#define E1000_PSRCTL   0x02170  /* Packet Split Receive Control - RW */
+#define E1000_RDBAL    0x02800  /* RX Descriptor Base Address Low - RW */
+#define E1000_RDBAH    0x02804  /* RX Descriptor Base Address High - RW */
+#define E1000_RDLEN    0x02808  /* RX Descriptor Length - RW */
+#define E1000_RDH      0x02810  /* RX Descriptor Head - RW */
+#define E1000_RDT      0x02818  /* RX Descriptor Tail - RW */
+#define E1000_RDTR     0x02820  /* RX Delay Timer - RW */
+#define E1000_RDBAL0   E1000_RDBAL /* RX Desc Base Address Low (0) - RW */
+#define E1000_RDBAH0   E1000_RDBAH /* RX Desc Base Address High (0) - RW */
+#define E1000_RDLEN0   E1000_RDLEN /* RX Desc Length (0) - RW */
+#define E1000_RDH0     E1000_RDH   /* RX Desc Head (0) - RW */
+#define E1000_RDT0     E1000_RDT   /* RX Desc Tail (0) - RW */
+#define E1000_RDTR0    E1000_RDTR  /* RX Delay Timer (0) - RW */
+#define E1000_RXDCTL   0x02828  /* RX Descriptor Control queue 0 - RW */
+#define E1000_RXDCTL1  0x02928  /* RX Descriptor Control queue 1 - RW */
+#define E1000_RADV     0x0282C  /* RX Interrupt Absolute Delay Timer - RW */
+#define E1000_RSRPD    0x02C00  /* RX Small Packet Detect - RW */
+#define E1000_RAID     0x02C08  /* Receive Ack Interrupt Delay - RW */
+#define E1000_TXDMAC   0x03000  /* TX DMA Control - RW */
+#define E1000_KABGTXD  0x03004  /* AFE Band Gap Transmit Ref Data */
+#define E1000_TDFH     0x03410  /* TX Data FIFO Head - RW */
+#define E1000_TDFT     0x03418  /* TX Data FIFO Tail - RW */
+#define E1000_TDFHS    0x03420  /* TX Data FIFO Head Saved - RW */
+#define E1000_TDFTS    0x03428  /* TX Data FIFO Tail Saved - RW */
+#define E1000_TDFPC    0x03430  /* TX Data FIFO Packet Count - RW */
+#define E1000_TDBAL    0x03800  /* TX Descriptor Base Address Low - RW */
+#define E1000_TDBAH    0x03804  /* TX Descriptor Base Address High - RW */
+#define E1000_TDLEN    0x03808  /* TX Descriptor Length - RW */
+#define E1000_TDH      0x03810  /* TX Descriptor Head - RW */
+#define E1000_TDT      0x03818  /* TX Descripotr Tail - RW */
+#define E1000_TIDV     0x03820  /* TX Interrupt Delay Value - RW */
+#define E1000_TXDCTL   0x03828  /* TX Descriptor Control - RW */
+#define E1000_TADV     0x0382C  /* TX Interrupt Absolute Delay Val - RW */
+#define E1000_TSPMT    0x03830  /* TCP Segmentation PAD & Min Threshold - RW */
+#define E1000_TARC0    0x03840  /* TX Arbitration Count (0) */
+#define E1000_TDBAL1   0x03900  /* TX Desc Base Address Low (1) - RW */
+#define E1000_TDBAH1   0x03904  /* TX Desc Base Address High (1) - RW */
+#define E1000_TDLEN1   0x03908  /* TX Desc Length (1) - RW */
+#define E1000_TDH1     0x03910  /* TX Desc Head (1) - RW */
+#define E1000_TDT1     0x03918  /* TX Desc Tail (1) - RW */
+#define E1000_TXDCTL1  0x03928  /* TX Descriptor Control (1) - RW */
+#define E1000_TARC1    0x03940  /* TX Arbitration Count (1) */
+#define E1000_CRCERRS  0x04000  /* CRC Error Count - R/clr */
+#define E1000_ALGNERRC 0x04004  /* Alignment Error Count - R/clr */
+#define E1000_SYMERRS  0x04008  /* Symbol Error Count - R/clr */
+#define E1000_RXERRC   0x0400C  /* Receive Error Count - R/clr */
+#define E1000_MPC      0x04010  /* Missed Packet Count - R/clr */
+#define E1000_SCC      0x04014  /* Single Collision Count - R/clr */
+#define E1000_ECOL     0x04018  /* Excessive Collision Count - R/clr */
+#define E1000_MCC      0x0401C  /* Multiple Collision Count - R/clr */
+#define E1000_LATECOL  0x04020  /* Late Collision Count - R/clr */
+#define E1000_COLC     0x04028  /* Collision Count - R/clr */
+#define E1000_DC       0x04030  /* Defer Count - R/clr */
+#define E1000_TNCRS    0x04034  /* TX-No CRS - R/clr */
+#define E1000_SEC      0x04038  /* Sequence Error Count - R/clr */
+#define E1000_CEXTERR  0x0403C  /* Carrier Extension Error Count - R/clr */
+#define E1000_RLEC     0x04040  /* Receive Length Error Count - R/clr */
+#define E1000_XONRXC   0x04048  /* XON RX Count - R/clr */
+#define E1000_XONTXC   0x0404C  /* XON TX Count - R/clr */
+#define E1000_XOFFRXC  0x04050  /* XOFF RX Count - R/clr */
+#define E1000_XOFFTXC  0x04054  /* XOFF TX Count - R/clr */
+#define E1000_FCRUC    0x04058  /* Flow Control RX Unsupported Count- R/clr */
+#define E1000_PRC64    0x0405C  /* Packets RX (64 bytes) - R/clr */
+#define E1000_PRC127   0x04060  /* Packets RX (65-127 bytes) - R/clr */
+#define E1000_PRC255   0x04064  /* Packets RX (128-255 bytes) - R/clr */
+#define E1000_PRC511   0x04068  /* Packets RX (255-511 bytes) - R/clr */
+#define E1000_PRC1023  0x0406C  /* Packets RX (512-1023 bytes) - R/clr */
+#define E1000_PRC1522  0x04070  /* Packets RX (1024-1522 bytes) - R/clr */
+#define E1000_GPRC     0x04074  /* Good Packets RX Count - R/clr */
+#define E1000_BPRC     0x04078  /* Broadcast Packets RX Count - R/clr */
+#define E1000_MPRC     0x0407C  /* Multicast Packets RX Count - R/clr */
+#define E1000_GPTC     0x04080  /* Good Packets TX Count - R/clr */
+#define E1000_GORCL    0x04088  /* Good Octets RX Count Low - R/clr */
+#define E1000_GORCH    0x0408C  /* Good Octets RX Count High - R/clr */
+#define E1000_GOTCL    0x04090  /* Good Octets TX Count Low - R/clr */
+#define E1000_GOTCH    0x04094  /* Good Octets TX Count High - R/clr */
+#define E1000_RNBC     0x040A0  /* RX No Buffers Count - R/clr */
+#define E1000_RUC      0x040A4  /* RX Undersize Count - R/clr */
+#define E1000_RFC      0x040A8  /* RX Fragment Count - R/clr */
+#define E1000_ROC      0x040AC  /* RX Oversize Count - R/clr */
+#define E1000_RJC      0x040B0  /* RX Jabber Count - R/clr */
+#define E1000_MGTPRC   0x040B4  /* Management Packets RX Count - R/clr */
+#define E1000_MGTPDC   0x040B8  /* Management Packets Dropped Count - R/clr */
+#define E1000_MGTPTC   0x040BC  /* Management Packets TX Count - R/clr */
+#define E1000_TORL     0x040C0  /* Total Octets RX Low - R/clr */
+#define E1000_TORH     0x040C4  /* Total Octets RX High - R/clr */
+#define E1000_TOTL     0x040C8  /* Total Octets TX Low - R/clr */
+#define E1000_TOTH     0x040CC  /* Total Octets TX High - R/clr */
+#define E1000_TPR      0x040D0  /* Total Packets RX - R/clr */
+#define E1000_TPT      0x040D4  /* Total Packets TX - R/clr */
+#define E1000_PTC64    0x040D8  /* Packets TX (64 bytes) - R/clr */
+#define E1000_PTC127   0x040DC  /* Packets TX (65-127 bytes) - R/clr */
+#define E1000_PTC255   0x040E0  /* Packets TX (128-255 bytes) - R/clr */
+#define E1000_PTC511   0x040E4  /* Packets TX (256-511 bytes) - R/clr */
+#define E1000_PTC1023  0x040E8  /* Packets TX (512-1023 bytes) - R/clr */
+#define E1000_PTC1522  0x040EC  /* Packets TX (1024-1522 Bytes) - R/clr */
+#define E1000_MPTC     0x040F0  /* Multicast Packets TX Count - R/clr */
+#define E1000_BPTC     0x040F4  /* Broadcast Packets TX Count - R/clr */
+#define E1000_TSCTC    0x040F8  /* TCP Segmentation Context TX - R/clr */
+#define E1000_TSCTFC   0x040FC  /* TCP Segmentation Context TX Fail - R/clr */
+#define E1000_IAC      0x04100  /* Interrupt Assertion Count */
+#define E1000_ICRXPTC  0x04104  /* Interrupt Cause Rx Packet Timer Expire Count */
+#define E1000_ICRXATC  0x04108  /* Interrupt Cause Rx Absolute Timer Expire Count */
+#define E1000_ICTXPTC  0x0410C  /* Interrupt Cause Tx Packet Timer Expire Count */
+#define E1000_ICTXATC  0x04110  /* Interrupt Cause Tx Absolute Timer Expire Count */
+#define E1000_ICTXQEC  0x04118  /* Interrupt Cause Tx Queue Empty Count */
+#define E1000_ICTXQMTC 0x0411C  /* Interrupt Cause Tx Queue Minimum Threshold Count */
+#define E1000_ICRXDMTC 0x04120  /* Interrupt Cause Rx Descriptor Minimum Threshold Count */
+#define E1000_ICRXOC   0x04124  /* Interrupt Cause Receiver Overrun Count */
+#define E1000_RXCSUM   0x05000  /* RX Checksum Control - RW */
+#define E1000_RFCTL    0x05008  /* Receive Filter Control*/
+#define E1000_MTA      0x05200  /* Multicast Table Array - RW Array */
+#define E1000_RA       0x05400  /* Receive Address - RW Array */
+#define E1000_VFTA     0x05600  /* VLAN Filter Table Array - RW Array */
+#define E1000_WUC      0x05800  /* Wakeup Control - RW */
+#define E1000_WUFC     0x05808  /* Wakeup Filter Control - RW */
+#define E1000_WUS      0x05810  /* Wakeup Status - RO */
+#define E1000_MANC     0x05820  /* Management Control - RW */
+#define E1000_IPAV     0x05838  /* IP Address Valid - RW */
+#define E1000_IP4AT    0x05840  /* IPv4 Address Table - RW Array */
+#define E1000_IP6AT    0x05880  /* IPv6 Address Table - RW Array */
+#define E1000_WUPL     0x05900  /* Wakeup Packet Length - RW */
+#define E1000_WUPM     0x05A00  /* Wakeup Packet Memory - RO A */
+#define E1000_FFLT     0x05F00  /* Flexible Filter Length Table - RW Array */
+#define E1000_HOST_IF  0x08800  /* Host Interface */
+#define E1000_FFMT     0x09000  /* Flexible Filter Mask Table - RW Array */
+#define E1000_FFVT     0x09800  /* Flexible Filter Value Table - RW Array */
+
+#define E1000_KUMCTRLSTA 0x00034 /* MAC-PHY interface - RW */
+#define E1000_MDPHYA     0x0003C  /* PHY address - RW */
+#define E1000_MANC2H     0x05860  /* Management Control To Host - RW */
+#define E1000_SW_FW_SYNC 0x05B5C /* Software-Firmware Synchronization - RW */
+
+#define E1000_GCR       0x05B00 /* PCI-Ex Control */
+#define E1000_GSCL_1    0x05B10 /* PCI-Ex Statistic Control #1 */
+#define E1000_GSCL_2    0x05B14 /* PCI-Ex Statistic Control #2 */
+#define E1000_GSCL_3    0x05B18 /* PCI-Ex Statistic Control #3 */
+#define E1000_GSCL_4    0x05B1C /* PCI-Ex Statistic Control #4 */
+#define E1000_FACTPS    0x05B30 /* Function Active and Power State to MNG */
+#define E1000_SWSM      0x05B50 /* SW Semaphore */
+#define E1000_FWSM      0x05B54 /* FW Semaphore */
+#define E1000_FFLT_DBG  0x05F04 /* Debug Register */
+#define E1000_HICR      0x08F00 /* Host Inteface Control */
+
+/* RSS registers */
+#define E1000_CPUVEC    0x02C10 /* CPU Vector Register - RW */
+#define E1000_MRQC      0x05818 /* Multiple Receive Control - RW */
+#define E1000_RETA      0x05C00 /* Redirection Table - RW Array */
+#define E1000_RSSRK     0x05C80 /* RSS Random Key - RW Array */
+#define E1000_RSSIM     0x05864 /* RSS Interrupt Mask */
+#define E1000_RSSIR     0x05868 /* RSS Interrupt Request */
+
+/* PHY 1000 MII Register/Bit Definitions */
+/* PHY Registers defined by IEEE */
+#define PHY_CTRL         0x00 /* Control Register */
+#define PHY_STATUS       0x01 /* Status Regiser */
+#define PHY_ID1          0x02 /* Phy Id Reg (word 1) */
+#define PHY_ID2          0x03 /* Phy Id Reg (word 2) */
+#define PHY_AUTONEG_ADV  0x04 /* Autoneg Advertisement */
+#define PHY_LP_ABILITY   0x05 /* Link Partner Ability (Base Page) */
+#define PHY_AUTONEG_EXP  0x06 /* Autoneg Expansion Reg */
+#define PHY_NEXT_PAGE_TX 0x07 /* Next Page TX */
+#define PHY_LP_NEXT_PAGE 0x08 /* Link Partner Next Page */
+#define PHY_1000T_CTRL   0x09 /* 1000Base-T Control Reg */
+#define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */
+#define PHY_EXT_STATUS   0x0F /* Extended Status Reg */
+
+#define MAX_PHY_REG_ADDRESS        0x1F  /* 5 bit address bus (0-0x1F) */
+#define MAX_PHY_MULTI_PAGE_REG     0xF   /* Registers equal on all pages */
+
+/* M88E1000 Specific Registers */
+#define M88E1000_PHY_SPEC_CTRL     0x10  /* PHY Specific Control Register */
+#define M88E1000_PHY_SPEC_STATUS   0x11  /* PHY Specific Status Register */
+#define M88E1000_INT_ENABLE        0x12  /* Interrupt Enable Register */
+#define M88E1000_INT_STATUS        0x13  /* Interrupt Status Register */
+#define M88E1000_EXT_PHY_SPEC_CTRL 0x14  /* Extended PHY Specific Control */
+#define M88E1000_RX_ERR_CNTR       0x15  /* Receive Error Counter */
+
+#define M88E1000_PHY_EXT_CTRL      0x1A  /* PHY extend control register */
+#define M88E1000_PHY_PAGE_SELECT   0x1D  /* Reg 29 for page number setting */
+#define M88E1000_PHY_GEN_CONTROL   0x1E  /* Its meaning depends on reg 29 */
+#define M88E1000_PHY_VCO_REG_BIT8  0x100 /* Bits 8 & 11 are adjusted for */
+#define M88E1000_PHY_VCO_REG_BIT11 0x800    /* improved BER performance */
+
+/* PHY Control Register */
+#define MII_CR_SPEED_SELECT_MSB 0x0040 /* bits 6,13: 10=1000, 01=100, 00=10 */
+#define MII_CR_COLL_TEST_ENABLE 0x0080 /* Collision test enable */
+#define MII_CR_FULL_DUPLEX      0x0100 /* FDX =1, half duplex =0 */
+#define MII_CR_RESTART_AUTO_NEG 0x0200 /* Restart auto negotiation */
+#define MII_CR_ISOLATE          0x0400 /* Isolate PHY from MII */
+#define MII_CR_POWER_DOWN       0x0800 /* Power down */
+#define MII_CR_AUTO_NEG_EN      0x1000 /* Auto Neg Enable */
+#define MII_CR_SPEED_SELECT_LSB 0x2000 /* bits 6,13: 10=1000, 01=100, 00=10 */
+#define MII_CR_LOOPBACK         0x4000 /* 0 = normal, 1 = loopback */
+#define MII_CR_RESET            0x8000 /* 0 = normal, 1 = PHY reset */
+
+/* PHY Status Register */
+#define MII_SR_EXTENDED_CAPS     0x0001        /* Extended register capabilities */
+#define MII_SR_JABBER_DETECT     0x0002        /* Jabber Detected */
+#define MII_SR_LINK_STATUS       0x0004        /* Link Status 1 = link */
+#define MII_SR_AUTONEG_CAPS      0x0008        /* Auto Neg Capable */
+#define MII_SR_REMOTE_FAULT      0x0010        /* Remote Fault Detect */
+#define MII_SR_AUTONEG_COMPLETE  0x0020        /* Auto Neg Complete */
+#define MII_SR_PREAMBLE_SUPPRESS 0x0040        /* Preamble may be suppressed */
+#define MII_SR_EXTENDED_STATUS   0x0100        /* Ext. status info in Reg 0x0F */
+#define MII_SR_100T2_HD_CAPS     0x0200        /* 100T2 Half Duplex Capable */
+#define MII_SR_100T2_FD_CAPS     0x0400        /* 100T2 Full Duplex Capable */
+#define MII_SR_10T_HD_CAPS       0x0800        /* 10T   Half Duplex Capable */
+#define MII_SR_10T_FD_CAPS       0x1000        /* 10T   Full Duplex Capable */
+#define MII_SR_100X_HD_CAPS      0x2000        /* 100X  Half Duplex Capable */
+#define MII_SR_100X_FD_CAPS      0x4000        /* 100X  Full Duplex Capable */
+#define MII_SR_100T4_CAPS        0x8000        /* 100T4 Capable */
+
+/* Interrupt Cause Read */
+#define E1000_ICR_TXDW          0x00000001 /* Transmit desc written back */
+#define E1000_ICR_TXQE          0x00000002 /* Transmit Queue empty */
+#define E1000_ICR_LSC           0x00000004 /* Link Status Change */
+#define E1000_ICR_RXSEQ         0x00000008 /* rx sequence error */
+#define E1000_ICR_RXDMT0        0x00000010 /* rx desc min. threshold (0) */
+#define E1000_ICR_RXO           0x00000040 /* rx overrun */
+#define E1000_ICR_RXT0          0x00000080 /* rx timer intr (ring 0) */
+#define E1000_ICR_MDAC          0x00000200 /* MDIO access complete */
+#define E1000_ICR_RXCFG         0x00000400 /* RX /c/ ordered set */
+#define E1000_ICR_GPI_EN0       0x00000800 /* GP Int 0 */
+#define E1000_ICR_GPI_EN1       0x00001000 /* GP Int 1 */
+#define E1000_ICR_GPI_EN2       0x00002000 /* GP Int 2 */
+#define E1000_ICR_GPI_EN3       0x00004000 /* GP Int 3 */
+#define E1000_ICR_TXD_LOW       0x00008000
+#define E1000_ICR_SRPD          0x00010000
+#define E1000_ICR_ACK           0x00020000 /* Receive Ack frame */
+#define E1000_ICR_MNG           0x00040000 /* Manageability event */
+#define E1000_ICR_DOCK          0x00080000 /* Dock/Undock */
+#define E1000_ICR_INT_ASSERTED  0x80000000 /* If this bit asserted, the driver should claim the interrupt */
+#define E1000_ICR_RXD_FIFO_PAR0 0x00100000 /* queue 0 Rx descriptor FIFO parity error */
+#define E1000_ICR_TXD_FIFO_PAR0 0x00200000 /* queue 0 Tx descriptor FIFO parity error */
+#define E1000_ICR_HOST_ARB_PAR  0x00400000 /* host arb read buffer parity error */
+#define E1000_ICR_PB_PAR        0x00800000 /* packet buffer parity error */
+#define E1000_ICR_RXD_FIFO_PAR1 0x01000000 /* queue 1 Rx descriptor FIFO parity error */
+#define E1000_ICR_TXD_FIFO_PAR1 0x02000000 /* queue 1 Tx descriptor FIFO parity error */
+#define E1000_ICR_ALL_PARITY    0x03F00000 /* all parity error bits */
+#define E1000_ICR_DSW           0x00000020 /* FW changed the status of DISSW bit in the FWSM */
+#define E1000_ICR_PHYINT        0x00001000 /* LAN connected device generates an interrupt */
+#define E1000_ICR_EPRST         0x00100000 /* ME handware reset occurs */
+
+/* Interrupt Cause Set */
+#define E1000_ICS_TXDW      E1000_ICR_TXDW      /* Transmit desc written back */
+#define E1000_ICS_TXQE      E1000_ICR_TXQE      /* Transmit Queue empty */
+#define E1000_ICS_LSC       E1000_ICR_LSC       /* Link Status Change */
+#define E1000_ICS_RXSEQ     E1000_ICR_RXSEQ     /* rx sequence error */
+#define E1000_ICS_RXDMT0    E1000_ICR_RXDMT0    /* rx desc min. threshold */
+#define E1000_ICS_RXO       E1000_ICR_RXO       /* rx overrun */
+#define E1000_ICS_RXT0      E1000_ICR_RXT0      /* rx timer intr */
+#define E1000_ICS_MDAC      E1000_ICR_MDAC      /* MDIO access complete */
+#define E1000_ICS_RXCFG     E1000_ICR_RXCFG     /* RX /c/ ordered set */
+#define E1000_ICS_GPI_EN0   E1000_ICR_GPI_EN0   /* GP Int 0 */
+#define E1000_ICS_GPI_EN1   E1000_ICR_GPI_EN1   /* GP Int 1 */
+#define E1000_ICS_GPI_EN2   E1000_ICR_GPI_EN2   /* GP Int 2 */
+#define E1000_ICS_GPI_EN3   E1000_ICR_GPI_EN3   /* GP Int 3 */
+#define E1000_ICS_TXD_LOW   E1000_ICR_TXD_LOW
+#define E1000_ICS_SRPD      E1000_ICR_SRPD
+#define E1000_ICS_ACK       E1000_ICR_ACK       /* Receive Ack frame */
+#define E1000_ICS_MNG       E1000_ICR_MNG       /* Manageability event */
+#define E1000_ICS_DOCK      E1000_ICR_DOCK      /* Dock/Undock */
+#define E1000_ICS_RXD_FIFO_PAR0 E1000_ICR_RXD_FIFO_PAR0 /* queue 0 Rx descriptor FIFO parity error */
+#define E1000_ICS_TXD_FIFO_PAR0 E1000_ICR_TXD_FIFO_PAR0 /* queue 0 Tx descriptor FIFO parity error */
+#define E1000_ICS_HOST_ARB_PAR  E1000_ICR_HOST_ARB_PAR  /* host arb read buffer parity error */
+#define E1000_ICS_PB_PAR        E1000_ICR_PB_PAR        /* packet buffer parity error */
+#define E1000_ICS_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* queue 1 Rx descriptor FIFO parity error */
+#define E1000_ICS_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* queue 1 Tx descriptor FIFO parity error */
+#define E1000_ICS_DSW       E1000_ICR_DSW
+#define E1000_ICS_PHYINT    E1000_ICR_PHYINT
+#define E1000_ICS_EPRST     E1000_ICR_EPRST
+
+/* Interrupt Mask Set */
+#define E1000_IMS_TXDW      E1000_ICR_TXDW      /* Transmit desc written back */
+#define E1000_IMS_TXQE      E1000_ICR_TXQE      /* Transmit Queue empty */
+#define E1000_IMS_LSC       E1000_ICR_LSC       /* Link Status Change */
+#define E1000_IMS_RXSEQ     E1000_ICR_RXSEQ     /* rx sequence error */
+#define E1000_IMS_RXDMT0    E1000_ICR_RXDMT0    /* rx desc min. threshold */
+#define E1000_IMS_RXO       E1000_ICR_RXO       /* rx overrun */
+#define E1000_IMS_RXT0      E1000_ICR_RXT0      /* rx timer intr */
+#define E1000_IMS_MDAC      E1000_ICR_MDAC      /* MDIO access complete */
+#define E1000_IMS_RXCFG     E1000_ICR_RXCFG     /* RX /c/ ordered set */
+#define E1000_IMS_GPI_EN0   E1000_ICR_GPI_EN0   /* GP Int 0 */
+#define E1000_IMS_GPI_EN1   E1000_ICR_GPI_EN1   /* GP Int 1 */
+#define E1000_IMS_GPI_EN2   E1000_ICR_GPI_EN2   /* GP Int 2 */
+#define E1000_IMS_GPI_EN3   E1000_ICR_GPI_EN3   /* GP Int 3 */
+#define E1000_IMS_TXD_LOW   E1000_ICR_TXD_LOW
+#define E1000_IMS_SRPD      E1000_ICR_SRPD
+#define E1000_IMS_ACK       E1000_ICR_ACK       /* Receive Ack frame */
+#define E1000_IMS_MNG       E1000_ICR_MNG       /* Manageability event */
+#define E1000_IMS_DOCK      E1000_ICR_DOCK      /* Dock/Undock */
+#define E1000_IMS_RXD_FIFO_PAR0 E1000_ICR_RXD_FIFO_PAR0 /* queue 0 Rx descriptor FIFO parity error */
+#define E1000_IMS_TXD_FIFO_PAR0 E1000_ICR_TXD_FIFO_PAR0 /* queue 0 Tx descriptor FIFO parity error */
+#define E1000_IMS_HOST_ARB_PAR  E1000_ICR_HOST_ARB_PAR  /* host arb read buffer parity error */
+#define E1000_IMS_PB_PAR        E1000_ICR_PB_PAR        /* packet buffer parity error */
+#define E1000_IMS_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* queue 1 Rx descriptor FIFO parity error */
+#define E1000_IMS_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* queue 1 Tx descriptor FIFO parity error */
+#define E1000_IMS_DSW       E1000_ICR_DSW
+#define E1000_IMS_PHYINT    E1000_ICR_PHYINT
+#define E1000_IMS_EPRST     E1000_ICR_EPRST
+
+/* Interrupt Mask Clear */
+#define E1000_IMC_TXDW      E1000_ICR_TXDW      /* Transmit desc written back */
+#define E1000_IMC_TXQE      E1000_ICR_TXQE      /* Transmit Queue empty */
+#define E1000_IMC_LSC       E1000_ICR_LSC       /* Link Status Change */
+#define E1000_IMC_RXSEQ     E1000_ICR_RXSEQ     /* rx sequence error */
+#define E1000_IMC_RXDMT0    E1000_ICR_RXDMT0    /* rx desc min. threshold */
+#define E1000_IMC_RXO       E1000_ICR_RXO       /* rx overrun */
+#define E1000_IMC_RXT0      E1000_ICR_RXT0      /* rx timer intr */
+#define E1000_IMC_MDAC      E1000_ICR_MDAC      /* MDIO access complete */
+#define E1000_IMC_RXCFG     E1000_ICR_RXCFG     /* RX /c/ ordered set */
+#define E1000_IMC_GPI_EN0   E1000_ICR_GPI_EN0   /* GP Int 0 */
+#define E1000_IMC_GPI_EN1   E1000_ICR_GPI_EN1   /* GP Int 1 */
+#define E1000_IMC_GPI_EN2   E1000_ICR_GPI_EN2   /* GP Int 2 */
+#define E1000_IMC_GPI_EN3   E1000_ICR_GPI_EN3   /* GP Int 3 */
+#define E1000_IMC_TXD_LOW   E1000_ICR_TXD_LOW
+#define E1000_IMC_SRPD      E1000_ICR_SRPD
+#define E1000_IMC_ACK       E1000_ICR_ACK       /* Receive Ack frame */
+#define E1000_IMC_MNG       E1000_ICR_MNG       /* Manageability event */
+#define E1000_IMC_DOCK      E1000_ICR_DOCK      /* Dock/Undock */
+#define E1000_IMC_RXD_FIFO_PAR0 E1000_ICR_RXD_FIFO_PAR0 /* queue 0 Rx descriptor FIFO parity error */
+#define E1000_IMC_TXD_FIFO_PAR0 E1000_ICR_TXD_FIFO_PAR0 /* queue 0 Tx descriptor FIFO parity error */
+#define E1000_IMC_HOST_ARB_PAR  E1000_ICR_HOST_ARB_PAR  /* host arb read buffer parity error */
+#define E1000_IMC_PB_PAR        E1000_ICR_PB_PAR        /* packet buffer parity error */
+#define E1000_IMC_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* queue 1 Rx descriptor FIFO parity error */
+#define E1000_IMC_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* queue 1 Tx descriptor FIFO parity error */
+#define E1000_IMC_DSW       E1000_ICR_DSW
+#define E1000_IMC_PHYINT    E1000_ICR_PHYINT
+#define E1000_IMC_EPRST     E1000_ICR_EPRST
+
+/* Receive Control */
+#define E1000_RCTL_RST            0x00000001    /* Software reset */
+#define E1000_RCTL_EN             0x00000002    /* enable */
+#define E1000_RCTL_SBP            0x00000004    /* store bad packet */
+#define E1000_RCTL_UPE            0x00000008    /* unicast promiscuous enable */
+#define E1000_RCTL_MPE            0x00000010    /* multicast promiscuous enab */
+#define E1000_RCTL_LPE            0x00000020    /* long packet enable */
+#define E1000_RCTL_LBM_NO         0x00000000    /* no loopback mode */
+#define E1000_RCTL_LBM_MAC        0x00000040    /* MAC loopback mode */
+#define E1000_RCTL_LBM_SLP        0x00000080    /* serial link loopback mode */
+#define E1000_RCTL_LBM_TCVR       0x000000C0    /* tcvr loopback mode */
+#define E1000_RCTL_DTYP_MASK      0x00000C00    /* Descriptor type mask */
+#define E1000_RCTL_DTYP_PS        0x00000400    /* Packet Split descriptor */
+#define E1000_RCTL_RDMTS_HALF     0x00000000    /* rx desc min threshold size */
+#define E1000_RCTL_RDMTS_QUAT     0x00000100    /* rx desc min threshold size */
+#define E1000_RCTL_RDMTS_EIGTH    0x00000200    /* rx desc min threshold size */
+#define E1000_RCTL_MO_SHIFT       12            /* multicast offset shift */
+#define E1000_RCTL_MO_0           0x00000000    /* multicast offset 11:0 */
+#define E1000_RCTL_MO_1           0x00001000    /* multicast offset 12:1 */
+#define E1000_RCTL_MO_2           0x00002000    /* multicast offset 13:2 */
+#define E1000_RCTL_MO_3           0x00003000    /* multicast offset 15:4 */
+#define E1000_RCTL_MDR            0x00004000    /* multicast desc ring 0 */
+#define E1000_RCTL_BAM            0x00008000    /* broadcast enable */
+/* these buffer sizes are valid if E1000_RCTL_BSEX is 0 */
+#define E1000_RCTL_SZ_2048        0x00000000    /* rx buffer size 2048 */
+#define E1000_RCTL_SZ_1024        0x00010000    /* rx buffer size 1024 */
+#define E1000_RCTL_SZ_512         0x00020000    /* rx buffer size 512 */
+#define E1000_RCTL_SZ_256         0x00030000    /* rx buffer size 256 */
+/* these buffer sizes are valid if E1000_RCTL_BSEX is 1 */
+#define E1000_RCTL_SZ_16384       0x00010000    /* rx buffer size 16384 */
+#define E1000_RCTL_SZ_8192        0x00020000    /* rx buffer size 8192 */
+#define E1000_RCTL_SZ_4096        0x00030000    /* rx buffer size 4096 */
+#define E1000_RCTL_VFE            0x00040000    /* vlan filter enable */
+#define E1000_RCTL_CFIEN          0x00080000    /* canonical form enable */
+#define E1000_RCTL_CFI            0x00100000    /* canonical form indicator */
+#define E1000_RCTL_DPF            0x00400000    /* discard pause frames */
+#define E1000_RCTL_PMCF           0x00800000    /* pass MAC control frames */
+#define E1000_RCTL_BSEX           0x02000000    /* Buffer size extension */
+#define E1000_RCTL_SECRC          0x04000000    /* Strip Ethernet CRC */
+#define E1000_RCTL_FLXBUF_MASK    0x78000000    /* Flexible buffer size */
+#define E1000_RCTL_FLXBUF_SHIFT   27            /* Flexible buffer shift */
+
+
+#define E1000_EEPROM_SWDPIN0   0x0001   /* SWDPIN 0 EEPROM Value */
+#define E1000_EEPROM_LED_LOGIC 0x0020   /* Led Logic Word */
+#define E1000_EEPROM_RW_REG_DATA   16   /* Offset to data in EEPROM read/write registers */
+#define E1000_EEPROM_RW_REG_DONE   0x10 /* Offset to READ/WRITE done bit */
+#define E1000_EEPROM_RW_REG_START  1    /* First bit for telling part to start operation */
+#define E1000_EEPROM_RW_ADDR_SHIFT 8    /* Shift to the address bits */
+#define E1000_EEPROM_POLL_WRITE    1    /* Flag for polling for write complete */
+#define E1000_EEPROM_POLL_READ     0    /* Flag for polling for read complete */
+/* Register Bit Masks */
+/* Device Control */
+#define E1000_CTRL_FD       0x00000001  /* Full duplex.0=half; 1=full */
+#define E1000_CTRL_BEM      0x00000002  /* Endian Mode.0=little,1=big */
+#define E1000_CTRL_PRIOR    0x00000004  /* Priority on PCI. 0=rx,1=fair */
+#define E1000_CTRL_GIO_MASTER_DISABLE 0x00000004 /*Blocks new Master requests */
+#define E1000_CTRL_LRST     0x00000008  /* Link reset. 0=normal,1=reset */
+#define E1000_CTRL_TME      0x00000010  /* Test mode. 0=normal,1=test */
+#define E1000_CTRL_SLE      0x00000020  /* Serial Link on 0=dis,1=en */
+#define E1000_CTRL_ASDE     0x00000020  /* Auto-speed detect enable */
+#define E1000_CTRL_SLU      0x00000040  /* Set link up (Force Link) */
+#define E1000_CTRL_ILOS     0x00000080  /* Invert Loss-Of Signal */
+#define E1000_CTRL_SPD_SEL  0x00000300  /* Speed Select Mask */
+#define E1000_CTRL_SPD_10   0x00000000  /* Force 10Mb */
+#define E1000_CTRL_SPD_100  0x00000100  /* Force 100Mb */
+#define E1000_CTRL_SPD_1000 0x00000200  /* Force 1Gb */
+#define E1000_CTRL_BEM32    0x00000400  /* Big Endian 32 mode */
+#define E1000_CTRL_FRCSPD   0x00000800  /* Force Speed */
+#define E1000_CTRL_FRCDPX   0x00001000  /* Force Duplex */
+#define E1000_CTRL_D_UD_EN  0x00002000  /* Dock/Undock enable */
+#define E1000_CTRL_D_UD_POLARITY 0x00004000 /* Defined polarity of Dock/Undock indication in SDP[0] */
+#define E1000_CTRL_FORCE_PHY_RESET 0x00008000 /* Reset both PHY ports, through PHYRST_N pin */
+#define E1000_CTRL_EXT_LINK_EN 0x00010000 /* enable link status from external LINK_0 and LINK_1 pins */
+#define E1000_CTRL_SWDPIN0  0x00040000  /* SWDPIN 0 value */
+#define E1000_CTRL_SWDPIN1  0x00080000  /* SWDPIN 1 value */
+#define E1000_CTRL_SWDPIN2  0x00100000  /* SWDPIN 2 value */
+#define E1000_CTRL_SWDPIN3  0x00200000  /* SWDPIN 3 value */
+#define E1000_CTRL_SWDPIO0  0x00400000  /* SWDPIN 0 Input or output */
+#define E1000_CTRL_SWDPIO1  0x00800000  /* SWDPIN 1 input or output */
+#define E1000_CTRL_SWDPIO2  0x01000000  /* SWDPIN 2 input or output */
+#define E1000_CTRL_SWDPIO3  0x02000000  /* SWDPIN 3 input or output */
+#define E1000_CTRL_RST      0x04000000  /* Global reset */
+#define E1000_CTRL_RFCE     0x08000000  /* Receive Flow Control enable */
+#define E1000_CTRL_TFCE     0x10000000  /* Transmit flow control enable */
+#define E1000_CTRL_RTE      0x20000000  /* Routing tag enable */
+#define E1000_CTRL_VME      0x40000000  /* IEEE VLAN mode enable */
+#define E1000_CTRL_PHY_RST  0x80000000  /* PHY Reset */
+#define E1000_CTRL_SW2FW_INT 0x02000000  /* Initiate an interrupt to manageability engine */
+
+/* Device Status */
+#define E1000_STATUS_FD         0x00000001      /* Full duplex.0=half,1=full */
+#define E1000_STATUS_LU         0x00000002      /* Link up.0=no,1=link */
+#define E1000_STATUS_FUNC_MASK  0x0000000C      /* PCI Function Mask */
+#define E1000_STATUS_FUNC_SHIFT 2
+#define E1000_STATUS_FUNC_0     0x00000000      /* Function 0 */
+#define E1000_STATUS_FUNC_1     0x00000004      /* Function 1 */
+#define E1000_STATUS_TXOFF      0x00000010      /* transmission paused */
+#define E1000_STATUS_TBIMODE    0x00000020      /* TBI mode */
+#define E1000_STATUS_SPEED_MASK 0x000000C0
+#define E1000_STATUS_SPEED_10   0x00000000      /* Speed 10Mb/s */
+#define E1000_STATUS_SPEED_100  0x00000040      /* Speed 100Mb/s */
+#define E1000_STATUS_SPEED_1000 0x00000080      /* Speed 1000Mb/s */
+#define E1000_STATUS_LAN_INIT_DONE 0x00000200   /* Lan Init Completion
+                                                   by EEPROM/Flash */
+#define E1000_STATUS_ASDV       0x00000300      /* Auto speed detect value */
+#define E1000_STATUS_DOCK_CI    0x00000800      /* Change in Dock/Undock state. Clear on write '0'. */
+#define E1000_STATUS_GIO_MASTER_ENABLE 0x00080000 /* Status of Master requests. */
+#define E1000_STATUS_MTXCKOK    0x00000400      /* MTX clock running OK */
+#define E1000_STATUS_PCI66      0x00000800      /* In 66Mhz slot */
+#define E1000_STATUS_BUS64      0x00001000      /* In 64 bit slot */
+#define E1000_STATUS_PCIX_MODE  0x00002000      /* PCI-X mode */
+#define E1000_STATUS_PCIX_SPEED 0x0000C000      /* PCI-X bus speed */
+#define E1000_STATUS_BMC_SKU_0  0x00100000 /* BMC USB redirect disabled */
+#define E1000_STATUS_BMC_SKU_1  0x00200000 /* BMC SRAM disabled */
+#define E1000_STATUS_BMC_SKU_2  0x00400000 /* BMC SDRAM disabled */
+#define E1000_STATUS_BMC_CRYPTO 0x00800000 /* BMC crypto disabled */
+#define E1000_STATUS_BMC_LITE   0x01000000 /* BMC external code execution disabled */
+#define E1000_STATUS_RGMII_ENABLE 0x02000000 /* RGMII disabled */
+#define E1000_STATUS_FUSE_8       0x04000000
+#define E1000_STATUS_FUSE_9       0x08000000
+#define E1000_STATUS_SERDES0_DIS  0x10000000 /* SERDES disabled on port 0 */
+#define E1000_STATUS_SERDES1_DIS  0x20000000 /* SERDES disabled on port 1 */
+
+/* EEPROM/Flash Control */
+#define E1000_EECD_SK        0x00000001 /* EEPROM Clock */
+#define E1000_EECD_CS        0x00000002 /* EEPROM Chip Select */
+#define E1000_EECD_DI        0x00000004 /* EEPROM Data In */
+#define E1000_EECD_DO        0x00000008 /* EEPROM Data Out */
+#define E1000_EECD_FWE_MASK  0x00000030
+#define E1000_EECD_FWE_DIS   0x00000010 /* Disable FLASH writes */
+#define E1000_EECD_FWE_EN    0x00000020 /* Enable FLASH writes */
+#define E1000_EECD_FWE_SHIFT 4
+#define E1000_EECD_REQ       0x00000040 /* EEPROM Access Request */
+#define E1000_EECD_GNT       0x00000080 /* EEPROM Access Grant */
+#define E1000_EECD_PRES      0x00000100 /* EEPROM Present */
+#define E1000_EECD_SIZE      0x00000200 /* EEPROM Size (0=64 word 1=256 word) */
+#define E1000_EECD_ADDR_BITS 0x00000400 /* EEPROM Addressing bits based on type
+                                         * (0-small, 1-large) */
+#define E1000_EECD_TYPE      0x00002000 /* EEPROM Type (1-SPI, 0-Microwire) */
+#ifndef E1000_EEPROM_GRANT_ATTEMPTS
+#define E1000_EEPROM_GRANT_ATTEMPTS 1000 /* EEPROM # attempts to gain grant */
+#endif
+#define E1000_EECD_AUTO_RD          0x00000200  /* EEPROM Auto Read done */
+#define E1000_EECD_SIZE_EX_MASK     0x00007800  /* EEprom Size */
+#define E1000_EECD_SIZE_EX_SHIFT    11
+#define E1000_EECD_NVADDS    0x00018000 /* NVM Address Size */
+#define E1000_EECD_SELSHAD   0x00020000 /* Select Shadow RAM */
+#define E1000_EECD_INITSRAM  0x00040000 /* Initialize Shadow RAM */
+#define E1000_EECD_FLUPD     0x00080000 /* Update FLASH */
+#define E1000_EECD_AUPDEN    0x00100000 /* Enable Autonomous FLASH update */
+#define E1000_EECD_SHADV     0x00200000 /* Shadow RAM Data Valid */
+#define E1000_EECD_SEC1VAL   0x00400000 /* Sector One Valid */
+#define E1000_EECD_SECVAL_SHIFT      22
+#define E1000_STM_OPCODE     0xDB00
+#define E1000_HICR_FW_RESET  0xC0
+
+#define E1000_SHADOW_RAM_WORDS     2048
+#define E1000_ICH_NVM_SIG_WORD     0x13
+#define E1000_ICH_NVM_SIG_MASK     0xC0
+
+/* MDI Control */
+#define E1000_MDIC_DATA_MASK 0x0000FFFF
+#define E1000_MDIC_REG_MASK  0x001F0000
+#define E1000_MDIC_REG_SHIFT 16
+#define E1000_MDIC_PHY_MASK  0x03E00000
+#define E1000_MDIC_PHY_SHIFT 21
+#define E1000_MDIC_OP_WRITE  0x04000000
+#define E1000_MDIC_OP_READ   0x08000000
+#define E1000_MDIC_READY     0x10000000
+#define E1000_MDIC_INT_EN    0x20000000
+#define E1000_MDIC_ERROR     0x40000000
+
+/* EEPROM Commands - Microwire */
+#define EEPROM_READ_OPCODE_MICROWIRE  0x6  /* EEPROM read opcode */
+#define EEPROM_WRITE_OPCODE_MICROWIRE 0x5  /* EEPROM write opcode */
+#define EEPROM_ERASE_OPCODE_MICROWIRE 0x7  /* EEPROM erase opcode */
+#define EEPROM_EWEN_OPCODE_MICROWIRE  0x13 /* EEPROM erase/write enable */
+#define EEPROM_EWDS_OPCODE_MICROWIRE  0x10 /* EEPROM erast/write disable */
+
+/* EEPROM Word Offsets */
+#define EEPROM_COMPAT                 0x0003
+#define EEPROM_ID_LED_SETTINGS        0x0004
+#define EEPROM_VERSION                0x0005
+#define EEPROM_SERDES_AMPLITUDE       0x0006 /* For SERDES output amplitude adjustment. */
+#define EEPROM_PHY_CLASS_WORD         0x0007
+#define EEPROM_INIT_CONTROL1_REG      0x000A
+#define EEPROM_INIT_CONTROL2_REG      0x000F
+#define EEPROM_SWDEF_PINS_CTRL_PORT_1 0x0010
+#define EEPROM_INIT_CONTROL3_PORT_B   0x0014
+#define EEPROM_INIT_3GIO_3            0x001A
+#define EEPROM_SWDEF_PINS_CTRL_PORT_0 0x0020
+#define EEPROM_INIT_CONTROL3_PORT_A   0x0024
+#define EEPROM_CFG                    0x0012
+#define EEPROM_FLASH_VERSION          0x0032
+#define EEPROM_CHECKSUM_REG           0x003F
+
+#define E1000_EEPROM_CFG_DONE         0x00040000   /* MNG config cycle done */
+#define E1000_EEPROM_CFG_DONE_PORT_1  0x00080000   /* ...for second port */
+
+/* Transmit Descriptor */
+struct e1000_tx_desc {
+    uint64_t buffer_addr;       /* Address of the descriptor's data buffer */
+    union {
+        uint32_t data;
+        struct {
+            uint16_t length;    /* Data buffer length */
+            uint8_t cso;        /* Checksum offset */
+            uint8_t cmd;        /* Descriptor control */
+        } flags;
+    } lower;
+    union {
+        uint32_t data;
+        struct {
+            uint8_t status;     /* Descriptor status */
+            uint8_t css;        /* Checksum start */
+            uint16_t special;
+        } fields;
+    } upper;
+};
+
+/* Transmit Descriptor bit definitions */
+#define E1000_TXD_DTYP_D     0x00100000 /* Data Descriptor */
+#define E1000_TXD_DTYP_C     0x00000000 /* Context Descriptor */
+#define E1000_TXD_POPTS_IXSM 0x01       /* Insert IP checksum */
+#define E1000_TXD_POPTS_TXSM 0x02       /* Insert TCP/UDP checksum */
+#define E1000_TXD_CMD_EOP    0x01000000 /* End of Packet */
+#define E1000_TXD_CMD_IFCS   0x02000000 /* Insert FCS (Ethernet CRC) */
+#define E1000_TXD_CMD_IC     0x04000000 /* Insert Checksum */
+#define E1000_TXD_CMD_RS     0x08000000 /* Report Status */
+#define E1000_TXD_CMD_RPS    0x10000000 /* Report Packet Sent */
+#define E1000_TXD_CMD_DEXT   0x20000000 /* Descriptor extension (0 = legacy) */
+#define E1000_TXD_CMD_VLE    0x40000000 /* Add VLAN tag */
+#define E1000_TXD_CMD_IDE    0x80000000 /* Enable Tidv register */
+#define E1000_TXD_STAT_DD    0x00000001 /* Descriptor Done */
+#define E1000_TXD_STAT_EC    0x00000002 /* Excess Collisions */
+#define E1000_TXD_STAT_LC    0x00000004 /* Late Collisions */
+#define E1000_TXD_STAT_TU    0x00000008 /* Transmit underrun */
+#define E1000_TXD_CMD_TCP    0x01000000 /* TCP packet */
+#define E1000_TXD_CMD_IP     0x02000000 /* IP packet */
+#define E1000_TXD_CMD_TSE    0x04000000 /* TCP Seg enable */
+#define E1000_TXD_STAT_TC    0x00000004 /* Tx Underrun */
+
+/* Transmit Control */
+#define E1000_TCTL_RST    0x00000001    /* software reset */
+#define E1000_TCTL_EN     0x00000002    /* enable tx */
+#define E1000_TCTL_BCE    0x00000004    /* busy check enable */
+#define E1000_TCTL_PSP    0x00000008    /* pad short packets */
+#define E1000_TCTL_CT     0x00000ff0    /* collision threshold */
+#define E1000_TCTL_COLD   0x003ff000    /* collision distance */
+#define E1000_TCTL_SWXOFF 0x00400000    /* SW Xoff transmission */
+#define E1000_TCTL_PBE    0x00800000    /* Packet Burst Enable */
+#define E1000_TCTL_RTLC   0x01000000    /* Re-transmit on late collision */
+#define E1000_TCTL_NRTU   0x02000000    /* No Re-transmit on underrun */
+#define E1000_TCTL_MULR   0x10000000    /* Multiple request support */
+
+/* Receive Descriptor */
+struct e1000_rx_desc {
+    uint64_t buffer_addr; /* Address of the descriptor's data buffer */
+    uint16_t length;     /* Length of data DMAed into data buffer */
+    uint16_t csum;       /* Packet checksum */
+    uint8_t status;      /* Descriptor status */
+    uint8_t errors;      /* Descriptor Errors */
+    uint16_t special;
+};
+
+/* Receive Descriptor bit definitions */
+#define E1000_RXD_STAT_DD       0x01    /* Descriptor Done */
+#define E1000_RXD_STAT_EOP      0x02    /* End of Packet */
+#define E1000_RXD_STAT_IXSM     0x04    /* Ignore checksum */
+#define E1000_RXD_STAT_VP       0x08    /* IEEE VLAN Packet */
+#define E1000_RXD_STAT_UDPCS    0x10    /* UDP xsum caculated */
+#define E1000_RXD_STAT_TCPCS    0x20    /* TCP xsum calculated */
+#define E1000_RXD_STAT_IPCS     0x40    /* IP xsum calculated */
+#define E1000_RXD_STAT_PIF      0x80    /* passed in-exact filter */
+#define E1000_RXD_STAT_IPIDV    0x200   /* IP identification valid */
+#define E1000_RXD_STAT_UDPV     0x400   /* Valid UDP checksum */
+#define E1000_RXD_STAT_ACK      0x8000  /* ACK Packet indication */
+#define E1000_RXD_ERR_CE        0x01    /* CRC Error */
+#define E1000_RXD_ERR_SE        0x02    /* Symbol Error */
+#define E1000_RXD_ERR_SEQ       0x04    /* Sequence Error */
+#define E1000_RXD_ERR_CXE       0x10    /* Carrier Extension Error */
+#define E1000_RXD_ERR_TCPE      0x20    /* TCP/UDP Checksum Error */
+#define E1000_RXD_ERR_IPE       0x40    /* IP Checksum Error */
+#define E1000_RXD_ERR_RXE       0x80    /* Rx Data Error */
+#define E1000_RXD_SPC_VLAN_MASK 0x0FFF  /* VLAN ID is in lower 12 bits */
+#define E1000_RXD_SPC_PRI_MASK  0xE000  /* Priority is in upper 3 bits */
+#define E1000_RXD_SPC_PRI_SHIFT 13
+#define E1000_RXD_SPC_CFI_MASK  0x1000  /* CFI is bit 12 */
+#define E1000_RXD_SPC_CFI_SHIFT 12
+
+#define E1000_RXDEXT_STATERR_CE    0x01000000
+#define E1000_RXDEXT_STATERR_SE    0x02000000
+#define E1000_RXDEXT_STATERR_SEQ   0x04000000
+#define E1000_RXDEXT_STATERR_CXE   0x10000000
+#define E1000_RXDEXT_STATERR_TCPE  0x20000000
+#define E1000_RXDEXT_STATERR_IPE   0x40000000
+#define E1000_RXDEXT_STATERR_RXE   0x80000000
+
+#define E1000_RXDPS_HDRSTAT_HDRSP        0x00008000
+#define E1000_RXDPS_HDRSTAT_HDRLEN_MASK  0x000003FF
+
+/* Receive Address */
+#define E1000_RAH_AV  0x80000000        /* Receive descriptor valid */
+
+/* Offload Context Descriptor */
+struct e1000_context_desc {
+    union {
+        uint32_t ip_config;
+        struct {
+            uint8_t ipcss;      /* IP checksum start */
+            uint8_t ipcso;      /* IP checksum offset */
+            uint16_t ipcse;     /* IP checksum end */
+        } ip_fields;
+    } lower_setup;
+    union {
+        uint32_t tcp_config;
+        struct {
+            uint8_t tucss;      /* TCP checksum start */
+            uint8_t tucso;      /* TCP checksum offset */
+            uint16_t tucse;     /* TCP checksum end */
+        } tcp_fields;
+    } upper_setup;
+    uint32_t cmd_and_length;    /* */
+    union {
+        uint32_t data;
+        struct {
+            uint8_t status;     /* Descriptor status */
+            uint8_t hdr_len;    /* Header length */
+            uint16_t mss;       /* Maximum segment size */
+        } fields;
+    } tcp_seg_setup;
+};
+
+/* Offload data descriptor */
+struct e1000_data_desc {
+    uint64_t buffer_addr;       /* Address of the descriptor's buffer address */
+    union {
+        uint32_t data;
+        struct {
+            uint16_t length;    /* Data buffer length */
+            uint8_t typ_len_ext;        /* */
+            uint8_t cmd;        /* */
+        } flags;
+    } lower;
+    union {
+        uint32_t data;
+        struct {
+            uint8_t status;     /* Descriptor status */
+            uint8_t popts;      /* Packet Options */
+            uint16_t special;   /* */
+        } fields;
+    } upper;
+};
+
+/* Management Control */
+#define E1000_MANC_SMBUS_EN      0x00000001 /* SMBus Enabled - RO */
+#define E1000_MANC_ASF_EN        0x00000002 /* ASF Enabled - RO */
+#define E1000_MANC_R_ON_FORCE    0x00000004 /* Reset on Force TCO - RO */
+#define E1000_MANC_RMCP_EN       0x00000100 /* Enable RCMP 026Fh Filtering */
+#define E1000_MANC_0298_EN       0x00000200 /* Enable RCMP 0298h Filtering */
+#define E1000_MANC_IPV4_EN       0x00000400 /* Enable IPv4 */
+#define E1000_MANC_IPV6_EN       0x00000800 /* Enable IPv6 */
+#define E1000_MANC_SNAP_EN       0x00001000 /* Accept LLC/SNAP */
+#define E1000_MANC_ARP_EN        0x00002000 /* Enable ARP Request Filtering */
+#define E1000_MANC_NEIGHBOR_EN   0x00004000 /* Enable Neighbor Discovery
+                                             * Filtering */
+#define E1000_MANC_ARP_RES_EN    0x00008000 /* Enable ARP response Filtering */
+#define E1000_MANC_TCO_RESET     0x00010000 /* TCO Reset Occurred */
+#define E1000_MANC_RCV_TCO_EN    0x00020000 /* Receive TCO Packets Enabled */
+#define E1000_MANC_REPORT_STATUS 0x00040000 /* Status Reporting Enabled */
+#define E1000_MANC_RCV_ALL       0x00080000 /* Receive All Enabled */
+#define E1000_MANC_BLK_PHY_RST_ON_IDE   0x00040000 /* Block phy resets */
+#define E1000_MANC_EN_MAC_ADDR_FILTER   0x00100000 /* Enable MAC address
+                                                    * filtering */
+#define E1000_MANC_EN_MNG2HOST   0x00200000 /* Enable MNG packets to host
+                                             * memory */
+#define E1000_MANC_EN_IP_ADDR_FILTER    0x00400000 /* Enable IP address
+                                                    * filtering */
+#define E1000_MANC_EN_XSUM_FILTER   0x00800000 /* Enable checksum filtering */
+#define E1000_MANC_BR_EN         0x01000000 /* Enable broadcast filtering */
+#define E1000_MANC_SMB_REQ       0x01000000 /* SMBus Request */
+#define E1000_MANC_SMB_GNT       0x02000000 /* SMBus Grant */
+#define E1000_MANC_SMB_CLK_IN    0x04000000 /* SMBus Clock In */
+#define E1000_MANC_SMB_DATA_IN   0x08000000 /* SMBus Data In */
+#define E1000_MANC_SMB_DATA_OUT  0x10000000 /* SMBus Data Out */
+#define E1000_MANC_SMB_CLK_OUT   0x20000000 /* SMBus Clock Out */
+
+#define E1000_MANC_SMB_DATA_OUT_SHIFT  28 /* SMBus Data Out Shift */
+#define E1000_MANC_SMB_CLK_OUT_SHIFT   29 /* SMBus Clock Out Shift */
+
+/* For checksumming, the sum of all words in the EEPROM should equal 0xBABA. */
+#define EEPROM_SUM 0xBABA
+
+#endif /* _E1000_HW_H_ */
diff --git a/hw/net/eepro100.c b/hw/net/eepro100.c
new file mode 100644 (file)
index 0000000..dc99ea6
--- /dev/null
@@ -0,0 +1,2115 @@
+/*
+ * QEMU i8255x (PRO100) emulation
+ *
+ * Copyright (C) 2006-2011 Stefan Weil
+ *
+ * Portions of the code are copies from grub / etherboot eepro100.c
+ * and linux e100.c.
+ *
+ * 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) version 3 or 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/>.
+ *
+ * Tested features (i82559):
+ *      PXE boot (i386 guest, i386 / mips / mipsel / ppc host) ok
+ *      Linux networking (i386) ok
+ *
+ * Untested:
+ *      Windows networking
+ *
+ * References:
+ *
+ * Intel 8255x 10/100 Mbps Ethernet Controller Family
+ * Open Source Software Developer Manual
+ *
+ * TODO:
+ *      * PHY emulation should be separated from nic emulation.
+ *        Most nic emulations could share the same phy code.
+ *      * i82550 is untested. It is programmed like the i82559.
+ *      * i82562 is untested. It is programmed like the i82559.
+ *      * Power management (i82558 and later) is not implemented.
+ *      * Wake-on-LAN is not implemented.
+ */
+
+#include <stddef.h>             /* offsetof */
+#include "hw/hw.h"
+#include "hw/pci/pci.h"
+#include "net/net.h"
+#include "hw/nvram/eeprom93xx.h"
+#include "sysemu/sysemu.h"
+#include "sysemu/dma.h"
+
+/* QEMU sends frames smaller than 60 bytes to ethernet nics.
+ * Such frames are rejected by real nics and their emulations.
+ * To avoid this behaviour, other nic emulations pad received
+ * frames. The following definition enables this padding for
+ * eepro100, too. We keep the define around in case it might
+ * become useful the future if the core networking is ever
+ * changed to pad short packets itself. */
+#define CONFIG_PAD_RECEIVED_FRAMES
+
+#define KiB 1024
+
+/* Debug EEPRO100 card. */
+#if 0
+# define DEBUG_EEPRO100
+#endif
+
+#ifdef DEBUG_EEPRO100
+#define logout(fmt, ...) fprintf(stderr, "EE100\t%-24s" fmt, __func__, ## __VA_ARGS__)
+#else
+#define logout(fmt, ...) ((void)0)
+#endif
+
+/* Set flags to 0 to disable debug output. */
+#define INT     1       /* interrupt related actions */
+#define MDI     1       /* mdi related actions */
+#define OTHER   1
+#define RXTX    1
+#define EEPROM  1       /* eeprom related actions */
+
+#define TRACE(flag, command) ((flag) ? (command) : (void)0)
+
+#define missing(text) fprintf(stderr, "eepro100: feature is missing in this emulation: " text "\n")
+
+#define MAX_ETH_FRAME_SIZE 1514
+
+/* This driver supports several different devices which are declared here. */
+#define i82550          0x82550
+#define i82551          0x82551
+#define i82557A         0x82557a
+#define i82557B         0x82557b
+#define i82557C         0x82557c
+#define i82558A         0x82558a
+#define i82558B         0x82558b
+#define i82559A         0x82559a
+#define i82559B         0x82559b
+#define i82559C         0x82559c
+#define i82559ER        0x82559e
+#define i82562          0x82562
+#define i82801          0x82801
+
+/* Use 64 word EEPROM. TODO: could be a runtime option. */
+#define EEPROM_SIZE     64
+
+#define PCI_MEM_SIZE            (4 * KiB)
+#define PCI_IO_SIZE             64
+#define PCI_FLASH_SIZE          (128 * KiB)
+
+#define BIT(n) (1 << (n))
+#define BITS(n, m) (((0xffffffffU << (31 - n)) >> (31 - n + m)) << m)
+
+/* The SCB accepts the following controls for the Tx and Rx units: */
+#define  CU_NOP         0x0000  /* No operation. */
+#define  CU_START       0x0010  /* CU start. */
+#define  CU_RESUME      0x0020  /* CU resume. */
+#define  CU_STATSADDR   0x0040  /* Load dump counters address. */
+#define  CU_SHOWSTATS   0x0050  /* Dump statistical counters. */
+#define  CU_CMD_BASE    0x0060  /* Load CU base address. */
+#define  CU_DUMPSTATS   0x0070  /* Dump and reset statistical counters. */
+#define  CU_SRESUME     0x00a0  /* CU static resume. */
+
+#define  RU_NOP         0x0000
+#define  RX_START       0x0001
+#define  RX_RESUME      0x0002
+#define  RU_ABORT       0x0004
+#define  RX_ADDR_LOAD   0x0006
+#define  RX_RESUMENR    0x0007
+#define INT_MASK        0x0100
+#define DRVR_INT        0x0200  /* Driver generated interrupt. */
+
+typedef struct {
+    const char *name;
+    const char *desc;
+    uint16_t device_id;
+    uint8_t revision;
+    uint16_t subsystem_vendor_id;
+    uint16_t subsystem_id;
+
+    uint32_t device;
+    uint8_t stats_size;
+    bool has_extended_tcb_support;
+    bool power_management;
+} E100PCIDeviceInfo;
+
+/* Offsets to the various registers.
+   All accesses need not be longword aligned. */
+typedef enum {
+    SCBStatus = 0,              /* Status Word. */
+    SCBAck = 1,
+    SCBCmd = 2,                 /* Rx/Command Unit command and status. */
+    SCBIntmask = 3,
+    SCBPointer = 4,             /* General purpose pointer. */
+    SCBPort = 8,                /* Misc. commands and operands.  */
+    SCBflash = 12,              /* Flash memory control. */
+    SCBeeprom = 14,             /* EEPROM control. */
+    SCBCtrlMDI = 16,            /* MDI interface control. */
+    SCBEarlyRx = 20,            /* Early receive byte count. */
+    SCBFlow = 24,               /* Flow Control. */
+    SCBpmdr = 27,               /* Power Management Driver. */
+    SCBgctrl = 28,              /* General Control. */
+    SCBgstat = 29,              /* General Status. */
+} E100RegisterOffset;
+
+/* A speedo3 transmit buffer descriptor with two buffers... */
+typedef struct {
+    uint16_t status;
+    uint16_t command;
+    uint32_t link;              /* void * */
+    uint32_t tbd_array_addr;    /* transmit buffer descriptor array address. */
+    uint16_t tcb_bytes;         /* transmit command block byte count (in lower 14 bits */
+    uint8_t tx_threshold;       /* transmit threshold */
+    uint8_t tbd_count;          /* TBD number */
+#if 0
+    /* This constitutes two "TBD" entries: hdr and data */
+    uint32_t tx_buf_addr0;  /* void *, header of frame to be transmitted.  */
+    int32_t  tx_buf_size0;  /* Length of Tx hdr. */
+    uint32_t tx_buf_addr1;  /* void *, data to be transmitted.  */
+    int32_t  tx_buf_size1;  /* Length of Tx data. */
+#endif
+} eepro100_tx_t;
+
+/* Receive frame descriptor. */
+typedef struct {
+    int16_t status;
+    uint16_t command;
+    uint32_t link;              /* struct RxFD * */
+    uint32_t rx_buf_addr;       /* void * */
+    uint16_t count;
+    uint16_t size;
+    /* Ethernet frame data follows. */
+} eepro100_rx_t;
+
+typedef enum {
+    COMMAND_EL = BIT(15),
+    COMMAND_S = BIT(14),
+    COMMAND_I = BIT(13),
+    COMMAND_NC = BIT(4),
+    COMMAND_SF = BIT(3),
+    COMMAND_CMD = BITS(2, 0),
+} scb_command_bit;
+
+typedef enum {
+    STATUS_C = BIT(15),
+    STATUS_OK = BIT(13),
+} scb_status_bit;
+
+typedef struct {
+    uint32_t tx_good_frames, tx_max_collisions, tx_late_collisions,
+             tx_underruns, tx_lost_crs, tx_deferred, tx_single_collisions,
+             tx_multiple_collisions, tx_total_collisions;
+    uint32_t rx_good_frames, rx_crc_errors, rx_alignment_errors,
+             rx_resource_errors, rx_overrun_errors, rx_cdt_errors,
+             rx_short_frame_errors;
+    uint32_t fc_xmt_pause, fc_rcv_pause, fc_rcv_unsupported;
+    uint16_t xmt_tco_frames, rcv_tco_frames;
+    /* TODO: i82559 has six reserved statistics but a total of 24 dwords. */
+    uint32_t reserved[4];
+} eepro100_stats_t;
+
+typedef enum {
+    cu_idle = 0,
+    cu_suspended = 1,
+    cu_active = 2,
+    cu_lpq_active = 2,
+    cu_hqp_active = 3
+} cu_state_t;
+
+typedef enum {
+    ru_idle = 0,
+    ru_suspended = 1,
+    ru_no_resources = 2,
+    ru_ready = 4
+} ru_state_t;
+
+typedef struct {
+    PCIDevice dev;
+    /* Hash register (multicast mask array, multiple individual addresses). */
+    uint8_t mult[8];
+    MemoryRegion mmio_bar;
+    MemoryRegion io_bar;
+    MemoryRegion flash_bar;
+    NICState *nic;
+    NICConf conf;
+    uint8_t scb_stat;           /* SCB stat/ack byte */
+    uint8_t int_stat;           /* PCI interrupt status */
+    /* region must not be saved by nic_save. */
+    uint16_t mdimem[32];
+    eeprom_t *eeprom;
+    uint32_t device;            /* device variant */
+    /* (cu_base + cu_offset) address the next command block in the command block list. */
+    uint32_t cu_base;           /* CU base address */
+    uint32_t cu_offset;         /* CU address offset */
+    /* (ru_base + ru_offset) address the RFD in the Receive Frame Area. */
+    uint32_t ru_base;           /* RU base address */
+    uint32_t ru_offset;         /* RU address offset */
+    uint32_t statsaddr;         /* pointer to eepro100_stats_t */
+
+    /* Temporary status information (no need to save these values),
+     * used while processing CU commands. */
+    eepro100_tx_t tx;           /* transmit buffer descriptor */
+    uint32_t cb_address;        /* = cu_base + cu_offset */
+
+    /* Statistical counters. Also used for wake-up packet (i82559). */
+    eepro100_stats_t statistics;
+
+    /* Data in mem is always in the byte order of the controller (le).
+     * It must be dword aligned to allow direct access to 32 bit values. */
+    uint8_t mem[PCI_MEM_SIZE] __attribute__((aligned(8)));
+
+    /* Configuration bytes. */
+    uint8_t configuration[22];
+
+    /* vmstate for each particular nic */
+    VMStateDescription *vmstate;
+
+    /* Quasi static device properties (no need to save them). */
+    uint16_t stats_size;
+    bool has_extended_tcb_support;
+} EEPRO100State;
+
+/* Word indices in EEPROM. */
+typedef enum {
+    EEPROM_CNFG_MDIX  = 0x03,
+    EEPROM_ID         = 0x05,
+    EEPROM_PHY_ID     = 0x06,
+    EEPROM_VENDOR_ID  = 0x0c,
+    EEPROM_CONFIG_ASF = 0x0d,
+    EEPROM_DEVICE_ID  = 0x23,
+    EEPROM_SMBUS_ADDR = 0x90,
+} EEPROMOffset;
+
+/* Bit values for EEPROM ID word. */
+typedef enum {
+    EEPROM_ID_MDM = BIT(0),     /* Modem */
+    EEPROM_ID_STB = BIT(1),     /* Standby Enable */
+    EEPROM_ID_WMR = BIT(2),     /* ??? */
+    EEPROM_ID_WOL = BIT(5),     /* Wake on LAN */
+    EEPROM_ID_DPD = BIT(6),     /* Deep Power Down */
+    EEPROM_ID_ALT = BIT(7),     /* */
+    /* BITS(10, 8) device revision */
+    EEPROM_ID_BD = BIT(11),     /* boot disable */
+    EEPROM_ID_ID = BIT(13),     /* id bit */
+    /* BITS(15, 14) signature */
+    EEPROM_ID_VALID = BIT(14),  /* signature for valid eeprom */
+} eeprom_id_bit;
+
+/* Default values for MDI (PHY) registers */
+static const uint16_t eepro100_mdi_default[] = {
+    /* MDI Registers 0 - 6, 7 */
+    0x3000, 0x780d, 0x02a8, 0x0154, 0x05e1, 0x0000, 0x0000, 0x0000,
+    /* MDI Registers 8 - 15 */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* MDI Registers 16 - 31 */
+    0x0003, 0x0000, 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+};
+
+/* Readonly mask for MDI (PHY) registers */
+static const uint16_t eepro100_mdi_mask[] = {
+    0x0000, 0xffff, 0xffff, 0xffff, 0xc01f, 0xffff, 0xffff, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0fff, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+    0xffff, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+};
+
+#define POLYNOMIAL 0x04c11db6
+
+static E100PCIDeviceInfo *eepro100_get_class(EEPRO100State *s);
+
+/* From FreeBSD (locally modified). */
+static unsigned e100_compute_mcast_idx(const uint8_t *ep)
+{
+    uint32_t crc;
+    int carry, i, j;
+    uint8_t b;
+
+    crc = 0xffffffff;
+    for (i = 0; i < 6; i++) {
+        b = *ep++;
+        for (j = 0; j < 8; j++) {
+            carry = ((crc & 0x80000000L) ? 1 : 0) ^ (b & 0x01);
+            crc <<= 1;
+            b >>= 1;
+            if (carry) {
+                crc = ((crc ^ POLYNOMIAL) | carry);
+            }
+        }
+    }
+    return (crc & BITS(7, 2)) >> 2;
+}
+
+/* Read a 16 bit control/status (CSR) register. */
+static uint16_t e100_read_reg2(EEPRO100State *s, E100RegisterOffset addr)
+{
+    assert(!((uintptr_t)&s->mem[addr] & 1));
+    return le16_to_cpup((uint16_t *)&s->mem[addr]);
+}
+
+/* Read a 32 bit control/status (CSR) register. */
+static uint32_t e100_read_reg4(EEPRO100State *s, E100RegisterOffset addr)
+{
+    assert(!((uintptr_t)&s->mem[addr] & 3));
+    return le32_to_cpup((uint32_t *)&s->mem[addr]);
+}
+
+/* Write a 16 bit control/status (CSR) register. */
+static void e100_write_reg2(EEPRO100State *s, E100RegisterOffset addr,
+                            uint16_t val)
+{
+    assert(!((uintptr_t)&s->mem[addr] & 1));
+    cpu_to_le16w((uint16_t *)&s->mem[addr], val);
+}
+
+/* Read a 32 bit control/status (CSR) register. */
+static void e100_write_reg4(EEPRO100State *s, E100RegisterOffset addr,
+                            uint32_t val)
+{
+    assert(!((uintptr_t)&s->mem[addr] & 3));
+    cpu_to_le32w((uint32_t *)&s->mem[addr], val);
+}
+
+#if defined(DEBUG_EEPRO100)
+static const char *nic_dump(const uint8_t * buf, unsigned size)
+{
+    static char dump[3 * 16 + 1];
+    char *p = &dump[0];
+    if (size > 16) {
+        size = 16;
+    }
+    while (size-- > 0) {
+        p += sprintf(p, " %02x", *buf++);
+    }
+    return dump;
+}
+#endif                          /* DEBUG_EEPRO100 */
+
+enum scb_stat_ack {
+    stat_ack_not_ours = 0x00,
+    stat_ack_sw_gen = 0x04,
+    stat_ack_rnr = 0x10,
+    stat_ack_cu_idle = 0x20,
+    stat_ack_frame_rx = 0x40,
+    stat_ack_cu_cmd_done = 0x80,
+    stat_ack_not_present = 0xFF,
+    stat_ack_rx = (stat_ack_sw_gen | stat_ack_rnr | stat_ack_frame_rx),
+    stat_ack_tx = (stat_ack_cu_idle | stat_ack_cu_cmd_done),
+};
+
+static void disable_interrupt(EEPRO100State * s)
+{
+    if (s->int_stat) {
+        TRACE(INT, logout("interrupt disabled\n"));
+        qemu_irq_lower(s->dev.irq[0]);
+        s->int_stat = 0;
+    }
+}
+
+static void enable_interrupt(EEPRO100State * s)
+{
+    if (!s->int_stat) {
+        TRACE(INT, logout("interrupt enabled\n"));
+        qemu_irq_raise(s->dev.irq[0]);
+        s->int_stat = 1;
+    }
+}
+
+static void eepro100_acknowledge(EEPRO100State * s)
+{
+    s->scb_stat &= ~s->mem[SCBAck];
+    s->mem[SCBAck] = s->scb_stat;
+    if (s->scb_stat == 0) {
+        disable_interrupt(s);
+    }
+}
+
+static void eepro100_interrupt(EEPRO100State * s, uint8_t status)
+{
+    uint8_t mask = ~s->mem[SCBIntmask];
+    s->mem[SCBAck] |= status;
+    status = s->scb_stat = s->mem[SCBAck];
+    status &= (mask | 0x0f);
+#if 0
+    status &= (~s->mem[SCBIntmask] | 0x0xf);
+#endif
+    if (status && (mask & 0x01)) {
+        /* SCB mask and SCB Bit M do not disable interrupt. */
+        enable_interrupt(s);
+    } else if (s->int_stat) {
+        disable_interrupt(s);
+    }
+}
+
+static void eepro100_cx_interrupt(EEPRO100State * s)
+{
+    /* CU completed action command. */
+    /* Transmit not ok (82557 only, not in emulation). */
+    eepro100_interrupt(s, 0x80);
+}
+
+static void eepro100_cna_interrupt(EEPRO100State * s)
+{
+    /* CU left the active state. */
+    eepro100_interrupt(s, 0x20);
+}
+
+static void eepro100_fr_interrupt(EEPRO100State * s)
+{
+    /* RU received a complete frame. */
+    eepro100_interrupt(s, 0x40);
+}
+
+static void eepro100_rnr_interrupt(EEPRO100State * s)
+{
+    /* RU is not ready. */
+    eepro100_interrupt(s, 0x10);
+}
+
+static void eepro100_mdi_interrupt(EEPRO100State * s)
+{
+    /* MDI completed read or write cycle. */
+    eepro100_interrupt(s, 0x08);
+}
+
+static void eepro100_swi_interrupt(EEPRO100State * s)
+{
+    /* Software has requested an interrupt. */
+    eepro100_interrupt(s, 0x04);
+}
+
+#if 0
+static void eepro100_fcp_interrupt(EEPRO100State * s)
+{
+    /* Flow control pause interrupt (82558 and later). */
+    eepro100_interrupt(s, 0x01);
+}
+#endif
+
+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;
+
+    TRACE(OTHER, logout("%p\n", s));
+
+    /* PCI Status */
+    pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_DEVSEL_MEDIUM |
+                                        PCI_STATUS_FAST_BACK);
+    /* PCI Latency Timer */
+    pci_set_byte(pci_conf + PCI_LATENCY_TIMER, 0x20);   /* latency timer = 32 clocks */
+    /* Capability Pointer is set by PCI framework. */
+    /* Interrupt Line */
+    /* Interrupt Pin */
+    pci_set_byte(pci_conf + PCI_INTERRUPT_PIN, 1);      /* interrupt pin A */
+    /* Minimum Grant */
+    pci_set_byte(pci_conf + PCI_MIN_GNT, 0x08);
+    /* Maximum Latency */
+    pci_set_byte(pci_conf + PCI_MAX_LAT, 0x18);
+
+    s->stats_size = info->stats_size;
+    s->has_extended_tcb_support = info->has_extended_tcb_support;
+
+    switch (device) {
+    case i82550:
+    case i82551:
+    case i82557A:
+    case i82557B:
+    case i82557C:
+    case i82558A:
+    case i82558B:
+    case i82559A:
+    case i82559B:
+    case i82559ER:
+    case i82562:
+    case i82801:
+    case i82559C:
+        break;
+    default:
+        logout("Device %X is undefined!\n", device);
+    }
+
+    /* Standard TxCB. */
+    s->configuration[6] |= BIT(4);
+
+    /* Standard statistical counters. */
+    s->configuration[6] |= BIT(5);
+
+    if (s->stats_size == 80) {
+        /* TODO: check TCO Statistical Counters bit. Documentation not clear. */
+        if (s->configuration[6] & BIT(2)) {
+            /* TCO statistical counters. */
+            assert(s->configuration[6] & BIT(5));
+        } else {
+            if (s->configuration[6] & BIT(5)) {
+                /* No extended statistical counters, i82557 compatible. */
+                s->stats_size = 64;
+            } else {
+                /* i82558 compatible. */
+                s->stats_size = 76;
+            }
+        }
+    } else {
+        if (s->configuration[6] & BIT(5)) {
+            /* No extended statistical counters. */
+            s->stats_size = 64;
+        }
+    }
+    assert(s->stats_size > 0 && s->stats_size <= sizeof(s->statistics));
+
+    if (info->power_management) {
+        /* Power Management Capabilities */
+        int cfg_offset = 0xdc;
+        int r = pci_add_capability(&s->dev, PCI_CAP_ID_PM,
+                                   cfg_offset, PCI_PM_SIZEOF);
+        assert(r >= 0);
+        pci_set_word(pci_conf + cfg_offset + PCI_PM_PMC, 0x7e21);
+#if 0 /* TODO: replace dummy code for power management emulation. */
+        /* TODO: Power Management Control / Status. */
+        pci_set_word(pci_conf + cfg_offset + PCI_PM_CTRL, 0x0000);
+        /* TODO: Ethernet Power Consumption Registers (i82559 and later). */
+        pci_set_byte(pci_conf + cfg_offset + PCI_PM_PPB_EXTENSIONS, 0x0000);
+#endif
+    }
+
+#if EEPROM_SIZE > 0
+    if (device == i82557C || device == i82558B || device == i82559C) {
+        /*
+        TODO: get vendor id from EEPROM for i82557C or later.
+        TODO: get device id from EEPROM for i82557C or later.
+        TODO: status bit 4 can be disabled by EEPROM for i82558, i82559.
+        TODO: header type is determined by EEPROM for i82559.
+        TODO: get subsystem id from EEPROM for i82557C or later.
+        TODO: get subsystem vendor id from EEPROM for i82557C or later.
+        TODO: exp. rom baddr depends on a bit in EEPROM for i82558 or later.
+        TODO: capability pointer depends on EEPROM for i82558.
+        */
+        logout("Get device id and revision from EEPROM!!!\n");
+    }
+#endif /* EEPROM_SIZE > 0 */
+}
+
+static void nic_selective_reset(EEPRO100State * s)
+{
+    size_t i;
+    uint16_t *eeprom_contents = eeprom93xx_data(s->eeprom);
+#if 0
+    eeprom93xx_reset(s->eeprom);
+#endif
+    memcpy(eeprom_contents, s->conf.macaddr.a, 6);
+    eeprom_contents[EEPROM_ID] = EEPROM_ID_VALID;
+    if (s->device == i82557B || s->device == i82557C)
+        eeprom_contents[5] = 0x0100;
+    eeprom_contents[EEPROM_PHY_ID] = 1;
+    uint16_t sum = 0;
+    for (i = 0; i < EEPROM_SIZE - 1; i++) {
+        sum += eeprom_contents[i];
+    }
+    eeprom_contents[EEPROM_SIZE - 1] = 0xbaba - sum;
+    TRACE(EEPROM, logout("checksum=0x%04x\n", eeprom_contents[EEPROM_SIZE - 1]));
+
+    memset(s->mem, 0, sizeof(s->mem));
+    e100_write_reg4(s, SCBCtrlMDI, BIT(21));
+
+    assert(sizeof(s->mdimem) == sizeof(eepro100_mdi_default));
+    memcpy(&s->mdimem[0], &eepro100_mdi_default[0], sizeof(s->mdimem));
+}
+
+static void nic_reset(void *opaque)
+{
+    EEPRO100State *s = opaque;
+    TRACE(OTHER, logout("%p\n", s));
+    /* TODO: Clearing of hash register for selective reset, too? */
+    memset(&s->mult[0], 0, sizeof(s->mult));
+    nic_selective_reset(s);
+}
+
+#if defined(DEBUG_EEPRO100)
+static const char * const e100_reg[PCI_IO_SIZE / 4] = {
+    "Command/Status",
+    "General Pointer",
+    "Port",
+    "EEPROM/Flash Control",
+    "MDI Control",
+    "Receive DMA Byte Count",
+    "Flow Control",
+    "General Status/Control"
+};
+
+static char *regname(uint32_t addr)
+{
+    static char buf[32];
+    if (addr < PCI_IO_SIZE) {
+        const char *r = e100_reg[addr / 4];
+        if (r != 0) {
+            snprintf(buf, sizeof(buf), "%s+%u", r, addr % 4);
+        } else {
+            snprintf(buf, sizeof(buf), "0x%02x", addr);
+        }
+    } else {
+        snprintf(buf, sizeof(buf), "??? 0x%08x", addr);
+    }
+    return buf;
+}
+#endif                          /* DEBUG_EEPRO100 */
+
+/*****************************************************************************
+ *
+ * Command emulation.
+ *
+ ****************************************************************************/
+
+#if 0
+static uint16_t eepro100_read_command(EEPRO100State * s)
+{
+    uint16_t val = 0xffff;
+    TRACE(OTHER, logout("val=0x%04x\n", val));
+    return val;
+}
+#endif
+
+/* Commands that can be put in a command list entry. */
+enum commands {
+    CmdNOp = 0,
+    CmdIASetup = 1,
+    CmdConfigure = 2,
+    CmdMulticastList = 3,
+    CmdTx = 4,
+    CmdTDR = 5,                 /* load microcode */
+    CmdDump = 6,
+    CmdDiagnose = 7,
+
+    /* And some extra flags: */
+    CmdSuspend = 0x4000,        /* Suspend after completion. */
+    CmdIntr = 0x2000,           /* Interrupt after completion. */
+    CmdTxFlex = 0x0008,         /* Use "Flexible mode" for CmdTx command. */
+};
+
+static cu_state_t get_cu_state(EEPRO100State * s)
+{
+    return ((s->mem[SCBStatus] & BITS(7, 6)) >> 6);
+}
+
+static void set_cu_state(EEPRO100State * s, cu_state_t state)
+{
+    s->mem[SCBStatus] = (s->mem[SCBStatus] & ~BITS(7, 6)) + (state << 6);
+}
+
+static ru_state_t get_ru_state(EEPRO100State * s)
+{
+    return ((s->mem[SCBStatus] & BITS(5, 2)) >> 2);
+}
+
+static void set_ru_state(EEPRO100State * s, ru_state_t state)
+{
+    s->mem[SCBStatus] = (s->mem[SCBStatus] & ~BITS(5, 2)) + (state << 2);
+}
+
+static void dump_statistics(EEPRO100State * s)
+{
+    /* Dump statistical data. Most data is never changed by the emulation
+     * and always 0, so we first just copy the whole block and then those
+     * values which really matter.
+     * Number of data should check configuration!!!
+     */
+    pci_dma_write(&s->dev, s->statsaddr, &s->statistics, s->stats_size);
+    stl_le_pci_dma(&s->dev, s->statsaddr + 0,
+                   s->statistics.tx_good_frames);
+    stl_le_pci_dma(&s->dev, s->statsaddr + 36,
+                   s->statistics.rx_good_frames);
+    stl_le_pci_dma(&s->dev, s->statsaddr + 48,
+                   s->statistics.rx_resource_errors);
+    stl_le_pci_dma(&s->dev, s->statsaddr + 60,
+                   s->statistics.rx_short_frame_errors);
+#if 0
+    stw_le_pci_dma(&s->dev, s->statsaddr + 76, s->statistics.xmt_tco_frames);
+    stw_le_pci_dma(&s->dev, s->statsaddr + 78, s->statistics.rcv_tco_frames);
+    missing("CU dump statistical counters");
+#endif
+}
+
+static void read_cb(EEPRO100State *s)
+{
+    pci_dma_read(&s->dev, s->cb_address, &s->tx, sizeof(s->tx));
+    s->tx.status = le16_to_cpu(s->tx.status);
+    s->tx.command = le16_to_cpu(s->tx.command);
+    s->tx.link = le32_to_cpu(s->tx.link);
+    s->tx.tbd_array_addr = le32_to_cpu(s->tx.tbd_array_addr);
+    s->tx.tcb_bytes = le16_to_cpu(s->tx.tcb_bytes);
+}
+
+static void tx_command(EEPRO100State *s)
+{
+    uint32_t tbd_array = le32_to_cpu(s->tx.tbd_array_addr);
+    uint16_t tcb_bytes = (le16_to_cpu(s->tx.tcb_bytes) & 0x3fff);
+    /* Sends larger than MAX_ETH_FRAME_SIZE are allowed, up to 2600 bytes. */
+    uint8_t buf[2600];
+    uint16_t size = 0;
+    uint32_t tbd_address = s->cb_address + 0x10;
+    TRACE(RXTX, logout
+        ("transmit, TBD array address 0x%08x, TCB byte count 0x%04x, TBD count %u\n",
+         tbd_array, tcb_bytes, s->tx.tbd_count));
+
+    if (tcb_bytes > 2600) {
+        logout("TCB byte count too large, using 2600\n");
+        tcb_bytes = 2600;
+    }
+    if (!((tcb_bytes > 0) || (tbd_array != 0xffffffff))) {
+        logout
+            ("illegal values of TBD array address and TCB byte count!\n");
+    }
+    assert(tcb_bytes <= sizeof(buf));
+    while (size < tcb_bytes) {
+        uint32_t tx_buffer_address = ldl_le_pci_dma(&s->dev, tbd_address);
+        uint16_t tx_buffer_size = lduw_le_pci_dma(&s->dev, tbd_address + 4);
+#if 0
+        uint16_t tx_buffer_el = lduw_le_pci_dma(&s->dev, tbd_address + 6);
+#endif
+        tbd_address += 8;
+        TRACE(RXTX, logout
+            ("TBD (simplified mode): buffer address 0x%08x, size 0x%04x\n",
+             tx_buffer_address, tx_buffer_size));
+        tx_buffer_size = MIN(tx_buffer_size, sizeof(buf) - size);
+        pci_dma_read(&s->dev, tx_buffer_address, &buf[size], tx_buffer_size);
+        size += tx_buffer_size;
+    }
+    if (tbd_array == 0xffffffff) {
+        /* Simplified mode. Was already handled by code above. */
+    } else {
+        /* Flexible mode. */
+        uint8_t tbd_count = 0;
+        if (s->has_extended_tcb_support && !(s->configuration[6] & BIT(4))) {
+            /* Extended Flexible TCB. */
+            for (; tbd_count < 2; tbd_count++) {
+                uint32_t tx_buffer_address = ldl_le_pci_dma(&s->dev,
+                                                            tbd_address);
+                uint16_t tx_buffer_size = lduw_le_pci_dma(&s->dev,
+                                                          tbd_address + 4);
+                uint16_t tx_buffer_el = lduw_le_pci_dma(&s->dev,
+                                                        tbd_address + 6);
+                tbd_address += 8;
+                TRACE(RXTX, logout
+                    ("TBD (extended flexible mode): buffer address 0x%08x, size 0x%04x\n",
+                     tx_buffer_address, tx_buffer_size));
+                tx_buffer_size = MIN(tx_buffer_size, sizeof(buf) - size);
+                pci_dma_read(&s->dev, tx_buffer_address,
+                             &buf[size], tx_buffer_size);
+                size += tx_buffer_size;
+                if (tx_buffer_el & 1) {
+                    break;
+                }
+            }
+        }
+        tbd_address = tbd_array;
+        for (; tbd_count < s->tx.tbd_count; tbd_count++) {
+            uint32_t tx_buffer_address = ldl_le_pci_dma(&s->dev, tbd_address);
+            uint16_t tx_buffer_size = lduw_le_pci_dma(&s->dev, tbd_address + 4);
+            uint16_t tx_buffer_el = lduw_le_pci_dma(&s->dev, tbd_address + 6);
+            tbd_address += 8;
+            TRACE(RXTX, logout
+                ("TBD (flexible mode): buffer address 0x%08x, size 0x%04x\n",
+                 tx_buffer_address, tx_buffer_size));
+            tx_buffer_size = MIN(tx_buffer_size, sizeof(buf) - size);
+            pci_dma_read(&s->dev, tx_buffer_address,
+                         &buf[size], tx_buffer_size);
+            size += tx_buffer_size;
+            if (tx_buffer_el & 1) {
+                break;
+            }
+        }
+    }
+    TRACE(RXTX, logout("%p sending frame, len=%d,%s\n", s, size, nic_dump(buf, size)));
+    qemu_send_packet(qemu_get_queue(s->nic), buf, size);
+    s->statistics.tx_good_frames++;
+    /* Transmit with bad status would raise an CX/TNO interrupt.
+     * (82557 only). Emulation never has bad status. */
+#if 0
+    eepro100_cx_interrupt(s);
+#endif
+}
+
+static void set_multicast_list(EEPRO100State *s)
+{
+    uint16_t multicast_count = s->tx.tbd_array_addr & BITS(13, 0);
+    uint16_t i;
+    memset(&s->mult[0], 0, sizeof(s->mult));
+    TRACE(OTHER, logout("multicast list, multicast count = %u\n", multicast_count));
+    for (i = 0; i < multicast_count; i += 6) {
+        uint8_t multicast_addr[6];
+        pci_dma_read(&s->dev, s->cb_address + 10 + i, multicast_addr, 6);
+        TRACE(OTHER, logout("multicast entry %s\n", nic_dump(multicast_addr, 6)));
+        unsigned mcast_idx = e100_compute_mcast_idx(multicast_addr);
+        assert(mcast_idx < 64);
+        s->mult[mcast_idx >> 3] |= (1 << (mcast_idx & 7));
+    }
+}
+
+static void action_command(EEPRO100State *s)
+{
+    for (;;) {
+        bool bit_el;
+        bool bit_s;
+        bool bit_i;
+        bool bit_nc;
+        uint16_t ok_status = STATUS_OK;
+        s->cb_address = s->cu_base + s->cu_offset;
+        read_cb(s);
+        bit_el = ((s->tx.command & COMMAND_EL) != 0);
+        bit_s = ((s->tx.command & COMMAND_S) != 0);
+        bit_i = ((s->tx.command & COMMAND_I) != 0);
+        bit_nc = ((s->tx.command & COMMAND_NC) != 0);
+#if 0
+        bool bit_sf = ((s->tx.command & COMMAND_SF) != 0);
+#endif
+        s->cu_offset = s->tx.link;
+        TRACE(OTHER,
+              logout("val=(cu start), status=0x%04x, command=0x%04x, link=0x%08x\n",
+                     s->tx.status, s->tx.command, s->tx.link));
+        switch (s->tx.command & COMMAND_CMD) {
+        case CmdNOp:
+            /* Do nothing. */
+            break;
+        case CmdIASetup:
+            pci_dma_read(&s->dev, s->cb_address + 8, &s->conf.macaddr.a[0], 6);
+            TRACE(OTHER, logout("macaddr: %s\n", nic_dump(&s->conf.macaddr.a[0], 6)));
+            break;
+        case CmdConfigure:
+            pci_dma_read(&s->dev, s->cb_address + 8,
+                         &s->configuration[0], sizeof(s->configuration));
+            TRACE(OTHER, logout("configuration: %s\n",
+                                nic_dump(&s->configuration[0], 16)));
+            TRACE(OTHER, logout("configuration: %s\n",
+                                nic_dump(&s->configuration[16],
+                                ARRAY_SIZE(s->configuration) - 16)));
+            if (s->configuration[20] & BIT(6)) {
+                TRACE(OTHER, logout("Multiple IA bit\n"));
+            }
+            break;
+        case CmdMulticastList:
+            set_multicast_list(s);
+            break;
+        case CmdTx:
+            if (bit_nc) {
+                missing("CmdTx: NC = 0");
+                ok_status = 0;
+                break;
+            }
+            tx_command(s);
+            break;
+        case CmdTDR:
+            TRACE(OTHER, logout("load microcode\n"));
+            /* Starting with offset 8, the command contains
+             * 64 dwords microcode which we just ignore here. */
+            break;
+        case CmdDiagnose:
+            TRACE(OTHER, logout("diagnose\n"));
+            /* Make sure error flag is not set. */
+            s->tx.status = 0;
+            break;
+        default:
+            missing("undefined command");
+            ok_status = 0;
+            break;
+        }
+        /* Write new status. */
+        stw_le_pci_dma(&s->dev, s->cb_address,
+                       s->tx.status | ok_status | STATUS_C);
+        if (bit_i) {
+            /* CU completed action. */
+            eepro100_cx_interrupt(s);
+        }
+        if (bit_el) {
+            /* CU becomes idle. Terminate command loop. */
+            set_cu_state(s, cu_idle);
+            eepro100_cna_interrupt(s);
+            break;
+        } else if (bit_s) {
+            /* CU becomes suspended. Terminate command loop. */
+            set_cu_state(s, cu_suspended);
+            eepro100_cna_interrupt(s);
+            break;
+        } else {
+            /* More entries in list. */
+            TRACE(OTHER, logout("CU list with at least one more entry\n"));
+        }
+    }
+    TRACE(OTHER, logout("CU list empty\n"));
+    /* List is empty. Now CU is idle or suspended. */
+}
+
+static void eepro100_cu_command(EEPRO100State * s, uint8_t val)
+{
+    cu_state_t cu_state;
+    switch (val) {
+    case CU_NOP:
+        /* No operation. */
+        break;
+    case CU_START:
+        cu_state = get_cu_state(s);
+        if (cu_state != cu_idle && cu_state != cu_suspended) {
+            /* Intel documentation says that CU must be idle or suspended
+             * for the CU start command. */
+            logout("unexpected CU state is %u\n", cu_state);
+        }
+        set_cu_state(s, cu_active);
+        s->cu_offset = e100_read_reg4(s, SCBPointer);
+        action_command(s);
+        break;
+    case CU_RESUME:
+        if (get_cu_state(s) != cu_suspended) {
+            logout("bad CU resume from CU state %u\n", get_cu_state(s));
+            /* Workaround for bad Linux eepro100 driver which resumes
+             * from idle state. */
+#if 0
+            missing("cu resume");
+#endif
+            set_cu_state(s, cu_suspended);
+        }
+        if (get_cu_state(s) == cu_suspended) {
+            TRACE(OTHER, logout("CU resuming\n"));
+            set_cu_state(s, cu_active);
+            action_command(s);
+        }
+        break;
+    case CU_STATSADDR:
+        /* Load dump counters address. */
+        s->statsaddr = e100_read_reg4(s, SCBPointer);
+        TRACE(OTHER, logout("val=0x%02x (dump counters address)\n", val));
+        if (s->statsaddr & 3) {
+            /* Memory must be Dword aligned. */
+            logout("unaligned dump counters address\n");
+            /* Handling of misaligned addresses is undefined.
+             * Here we align the address by ignoring the lower bits. */
+            /* TODO: Test unaligned dump counter address on real hardware. */
+            s->statsaddr &= ~3;
+        }
+        break;
+    case CU_SHOWSTATS:
+        /* Dump statistical counters. */
+        TRACE(OTHER, logout("val=0x%02x (dump stats)\n", val));
+        dump_statistics(s);
+        stl_le_pci_dma(&s->dev, s->statsaddr + s->stats_size, 0xa005);
+        break;
+    case CU_CMD_BASE:
+        /* Load CU base. */
+        TRACE(OTHER, logout("val=0x%02x (CU base address)\n", val));
+        s->cu_base = e100_read_reg4(s, SCBPointer);
+        break;
+    case CU_DUMPSTATS:
+        /* Dump and reset statistical counters. */
+        TRACE(OTHER, logout("val=0x%02x (dump stats and reset)\n", val));
+        dump_statistics(s);
+        stl_le_pci_dma(&s->dev, s->statsaddr + s->stats_size, 0xa007);
+        memset(&s->statistics, 0, sizeof(s->statistics));
+        break;
+    case CU_SRESUME:
+        /* CU static resume. */
+        missing("CU static resume");
+        break;
+    default:
+        missing("Undefined CU command");
+    }
+}
+
+static void eepro100_ru_command(EEPRO100State * s, uint8_t val)
+{
+    switch (val) {
+    case RU_NOP:
+        /* No operation. */
+        break;
+    case RX_START:
+        /* RU start. */
+        if (get_ru_state(s) != ru_idle) {
+            logout("RU state is %u, should be %u\n", get_ru_state(s), ru_idle);
+#if 0
+            assert(!"wrong RU state");
+#endif
+        }
+        set_ru_state(s, ru_ready);
+        s->ru_offset = e100_read_reg4(s, SCBPointer);
+        qemu_flush_queued_packets(qemu_get_queue(s->nic));
+        TRACE(OTHER, logout("val=0x%02x (rx start)\n", val));
+        break;
+    case RX_RESUME:
+        /* Restart RU. */
+        if (get_ru_state(s) != ru_suspended) {
+            logout("RU state is %u, should be %u\n", get_ru_state(s),
+                   ru_suspended);
+#if 0
+            assert(!"wrong RU state");
+#endif
+        }
+        set_ru_state(s, ru_ready);
+        break;
+    case RU_ABORT:
+        /* RU abort. */
+        if (get_ru_state(s) == ru_ready) {
+            eepro100_rnr_interrupt(s);
+        }
+        set_ru_state(s, ru_idle);
+        break;
+    case RX_ADDR_LOAD:
+        /* Load RU base. */
+        TRACE(OTHER, logout("val=0x%02x (RU base address)\n", val));
+        s->ru_base = e100_read_reg4(s, SCBPointer);
+        break;
+    default:
+        logout("val=0x%02x (undefined RU command)\n", val);
+        missing("Undefined SU command");
+    }
+}
+
+static void eepro100_write_command(EEPRO100State * s, uint8_t val)
+{
+    eepro100_ru_command(s, val & 0x0f);
+    eepro100_cu_command(s, val & 0xf0);
+    if ((val) == 0) {
+        TRACE(OTHER, logout("val=0x%02x\n", val));
+    }
+    /* Clear command byte after command was accepted. */
+    s->mem[SCBCmd] = 0;
+}
+
+/*****************************************************************************
+ *
+ * EEPROM emulation.
+ *
+ ****************************************************************************/
+
+#define EEPROM_CS       0x02
+#define EEPROM_SK       0x01
+#define EEPROM_DI       0x04
+#define EEPROM_DO       0x08
+
+static uint16_t eepro100_read_eeprom(EEPRO100State * s)
+{
+    uint16_t val = e100_read_reg2(s, SCBeeprom);
+    if (eeprom93xx_read(s->eeprom)) {
+        val |= EEPROM_DO;
+    } else {
+        val &= ~EEPROM_DO;
+    }
+    TRACE(EEPROM, logout("val=0x%04x\n", val));
+    return val;
+}
+
+static void eepro100_write_eeprom(eeprom_t * eeprom, uint8_t val)
+{
+    TRACE(EEPROM, logout("val=0x%02x\n", val));
+
+    /* mask unwritable bits */
+#if 0
+    val = SET_MASKED(val, 0x31, eeprom->value);
+#endif
+
+    int eecs = ((val & EEPROM_CS) != 0);
+    int eesk = ((val & EEPROM_SK) != 0);
+    int eedi = ((val & EEPROM_DI) != 0);
+    eeprom93xx_write(eeprom, eecs, eesk, eedi);
+}
+
+/*****************************************************************************
+ *
+ * MDI emulation.
+ *
+ ****************************************************************************/
+
+#if defined(DEBUG_EEPRO100)
+static const char * const mdi_op_name[] = {
+    "opcode 0",
+    "write",
+    "read",
+    "opcode 3"
+};
+
+static const char * const mdi_reg_name[] = {
+    "Control",
+    "Status",
+    "PHY Identification (Word 1)",
+    "PHY Identification (Word 2)",
+    "Auto-Negotiation Advertisement",
+    "Auto-Negotiation Link Partner Ability",
+    "Auto-Negotiation Expansion"
+};
+
+static const char *reg2name(uint8_t reg)
+{
+    static char buffer[10];
+    const char *p = buffer;
+    if (reg < ARRAY_SIZE(mdi_reg_name)) {
+        p = mdi_reg_name[reg];
+    } else {
+        snprintf(buffer, sizeof(buffer), "reg=0x%02x", reg);
+    }
+    return p;
+}
+#endif                          /* DEBUG_EEPRO100 */
+
+static uint32_t eepro100_read_mdi(EEPRO100State * s)
+{
+    uint32_t val = e100_read_reg4(s, SCBCtrlMDI);
+
+#ifdef DEBUG_EEPRO100
+    uint8_t raiseint = (val & BIT(29)) >> 29;
+    uint8_t opcode = (val & BITS(27, 26)) >> 26;
+    uint8_t phy = (val & BITS(25, 21)) >> 21;
+    uint8_t reg = (val & BITS(20, 16)) >> 16;
+    uint16_t data = (val & BITS(15, 0));
+#endif
+    /* Emulation takes no time to finish MDI transaction. */
+    val |= BIT(28);
+    TRACE(MDI, logout("val=0x%08x (int=%u, %s, phy=%u, %s, data=0x%04x\n",
+                      val, raiseint, mdi_op_name[opcode], phy,
+                      reg2name(reg), data));
+    return val;
+}
+
+static void eepro100_write_mdi(EEPRO100State *s)
+{
+    uint32_t val = e100_read_reg4(s, SCBCtrlMDI);
+    uint8_t raiseint = (val & BIT(29)) >> 29;
+    uint8_t opcode = (val & BITS(27, 26)) >> 26;
+    uint8_t phy = (val & BITS(25, 21)) >> 21;
+    uint8_t reg = (val & BITS(20, 16)) >> 16;
+    uint16_t data = (val & BITS(15, 0));
+    TRACE(MDI, logout("val=0x%08x (int=%u, %s, phy=%u, %s, data=0x%04x\n",
+          val, raiseint, mdi_op_name[opcode], phy, reg2name(reg), data));
+    if (phy != 1) {
+        /* Unsupported PHY address. */
+#if 0
+        logout("phy must be 1 but is %u\n", phy);
+#endif
+        data = 0;
+    } else if (opcode != 1 && opcode != 2) {
+        /* Unsupported opcode. */
+        logout("opcode must be 1 or 2 but is %u\n", opcode);
+        data = 0;
+    } else if (reg > 6) {
+        /* Unsupported register. */
+        logout("register must be 0...6 but is %u\n", reg);
+        data = 0;
+    } else {
+        TRACE(MDI, logout("val=0x%08x (int=%u, %s, phy=%u, %s, data=0x%04x\n",
+                          val, raiseint, mdi_op_name[opcode], phy,
+                          reg2name(reg), data));
+        if (opcode == 1) {
+            /* MDI write */
+            switch (reg) {
+            case 0:            /* Control Register */
+                if (data & 0x8000) {
+                    /* Reset status and control registers to default. */
+                    s->mdimem[0] = eepro100_mdi_default[0];
+                    s->mdimem[1] = eepro100_mdi_default[1];
+                    data = s->mdimem[reg];
+                } else {
+                    /* Restart Auto Configuration = Normal Operation */
+                    data &= ~0x0200;
+                }
+                break;
+            case 1:            /* Status Register */
+                missing("not writable");
+                data = s->mdimem[reg];
+                break;
+            case 2:            /* PHY Identification Register (Word 1) */
+            case 3:            /* PHY Identification Register (Word 2) */
+                missing("not implemented");
+                break;
+            case 4:            /* Auto-Negotiation Advertisement Register */
+            case 5:            /* Auto-Negotiation Link Partner Ability Register */
+                break;
+            case 6:            /* Auto-Negotiation Expansion Register */
+            default:
+                missing("not implemented");
+            }
+            s->mdimem[reg] = data;
+        } else if (opcode == 2) {
+            /* MDI read */
+            switch (reg) {
+            case 0:            /* Control Register */
+                if (data & 0x8000) {
+                    /* Reset status and control registers to default. */
+                    s->mdimem[0] = eepro100_mdi_default[0];
+                    s->mdimem[1] = eepro100_mdi_default[1];
+                }
+                break;
+            case 1:            /* Status Register */
+                s->mdimem[reg] |= 0x0020;
+                break;
+            case 2:            /* PHY Identification Register (Word 1) */
+            case 3:            /* PHY Identification Register (Word 2) */
+            case 4:            /* Auto-Negotiation Advertisement Register */
+                break;
+            case 5:            /* Auto-Negotiation Link Partner Ability Register */
+                s->mdimem[reg] = 0x41fe;
+                break;
+            case 6:            /* Auto-Negotiation Expansion Register */
+                s->mdimem[reg] = 0x0001;
+                break;
+            }
+            data = s->mdimem[reg];
+        }
+        /* Emulation takes no time to finish MDI transaction.
+         * Set MDI bit in SCB status register. */
+        s->mem[SCBAck] |= 0x08;
+        val |= BIT(28);
+        if (raiseint) {
+            eepro100_mdi_interrupt(s);
+        }
+    }
+    val = (val & 0xffff0000) + data;
+    e100_write_reg4(s, SCBCtrlMDI, val);
+}
+
+/*****************************************************************************
+ *
+ * Port emulation.
+ *
+ ****************************************************************************/
+
+#define PORT_SOFTWARE_RESET     0
+#define PORT_SELFTEST           1
+#define PORT_SELECTIVE_RESET    2
+#define PORT_DUMP               3
+#define PORT_SELECTION_MASK     3
+
+typedef struct {
+    uint32_t st_sign;           /* Self Test Signature */
+    uint32_t st_result;         /* Self Test Results */
+} eepro100_selftest_t;
+
+static uint32_t eepro100_read_port(EEPRO100State * s)
+{
+    return 0;
+}
+
+static void eepro100_write_port(EEPRO100State *s)
+{
+    uint32_t val = e100_read_reg4(s, SCBPort);
+    uint32_t address = (val & ~PORT_SELECTION_MASK);
+    uint8_t selection = (val & PORT_SELECTION_MASK);
+    switch (selection) {
+    case PORT_SOFTWARE_RESET:
+        nic_reset(s);
+        break;
+    case PORT_SELFTEST:
+        TRACE(OTHER, logout("selftest address=0x%08x\n", address));
+        eepro100_selftest_t data;
+        pci_dma_read(&s->dev, address, (uint8_t *) &data, sizeof(data));
+        data.st_sign = 0xffffffff;
+        data.st_result = 0;
+        pci_dma_write(&s->dev, address, (uint8_t *) &data, sizeof(data));
+        break;
+    case PORT_SELECTIVE_RESET:
+        TRACE(OTHER, logout("selective reset, selftest address=0x%08x\n", address));
+        nic_selective_reset(s);
+        break;
+    default:
+        logout("val=0x%08x\n", val);
+        missing("unknown port selection");
+    }
+}
+
+/*****************************************************************************
+ *
+ * General hardware emulation.
+ *
+ ****************************************************************************/
+
+static uint8_t eepro100_read1(EEPRO100State * s, uint32_t addr)
+{
+    uint8_t val = 0;
+    if (addr <= sizeof(s->mem) - sizeof(val)) {
+        val = s->mem[addr];
+    }
+
+    switch (addr) {
+    case SCBStatus:
+    case SCBAck:
+        TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
+        break;
+    case SCBCmd:
+        TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
+#if 0
+        val = eepro100_read_command(s);
+#endif
+        break;
+    case SCBIntmask:
+        TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
+        break;
+    case SCBPort + 3:
+        TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
+        break;
+    case SCBeeprom:
+        val = eepro100_read_eeprom(s);
+        break;
+    case SCBCtrlMDI:
+    case SCBCtrlMDI + 1:
+    case SCBCtrlMDI + 2:
+    case SCBCtrlMDI + 3:
+        val = (uint8_t)(eepro100_read_mdi(s) >> (8 * (addr & 3)));
+        TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
+        break;
+    case SCBpmdr:       /* Power Management Driver Register */
+        val = 0;
+        TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
+        break;
+    case SCBgctrl:      /* General Control Register */
+        TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
+        break;
+    case SCBgstat:      /* General Status Register */
+        /* 100 Mbps full duplex, valid link */
+        val = 0x07;
+        TRACE(OTHER, logout("addr=General Status val=%02x\n", val));
+        break;
+    default:
+        logout("addr=%s val=0x%02x\n", regname(addr), val);
+        missing("unknown byte read");
+    }
+    return val;
+}
+
+static uint16_t eepro100_read2(EEPRO100State * s, uint32_t addr)
+{
+    uint16_t val = 0;
+    if (addr <= sizeof(s->mem) - sizeof(val)) {
+        val = e100_read_reg2(s, addr);
+    }
+
+    switch (addr) {
+    case SCBStatus:
+    case SCBCmd:
+        TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
+        break;
+    case SCBeeprom:
+        val = eepro100_read_eeprom(s);
+        TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
+        break;
+    case SCBCtrlMDI:
+    case SCBCtrlMDI + 2:
+        val = (uint16_t)(eepro100_read_mdi(s) >> (8 * (addr & 3)));
+        TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
+        break;
+    default:
+        logout("addr=%s val=0x%04x\n", regname(addr), val);
+        missing("unknown word read");
+    }
+    return val;
+}
+
+static uint32_t eepro100_read4(EEPRO100State * s, uint32_t addr)
+{
+    uint32_t val = 0;
+    if (addr <= sizeof(s->mem) - sizeof(val)) {
+        val = e100_read_reg4(s, addr);
+    }
+
+    switch (addr) {
+    case SCBStatus:
+        TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val));
+        break;
+    case SCBPointer:
+        TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val));
+        break;
+    case SCBPort:
+        val = eepro100_read_port(s);
+        TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val));
+        break;
+    case SCBflash:
+        val = eepro100_read_eeprom(s);
+        TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val));
+        break;
+    case SCBCtrlMDI:
+        val = eepro100_read_mdi(s);
+        break;
+    default:
+        logout("addr=%s val=0x%08x\n", regname(addr), val);
+        missing("unknown longword read");
+    }
+    return val;
+}
+
+static void eepro100_write1(EEPRO100State * s, uint32_t addr, uint8_t val)
+{
+    /* SCBStatus is readonly. */
+    if (addr > SCBStatus && addr <= sizeof(s->mem) - sizeof(val)) {
+        s->mem[addr] = val;
+    }
+
+    switch (addr) {
+    case SCBStatus:
+        TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
+        break;
+    case SCBAck:
+        TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
+        eepro100_acknowledge(s);
+        break;
+    case SCBCmd:
+        TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
+        eepro100_write_command(s, val);
+        break;
+    case SCBIntmask:
+        TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
+        if (val & BIT(1)) {
+            eepro100_swi_interrupt(s);
+        }
+        eepro100_interrupt(s, 0);
+        break;
+    case SCBPointer:
+    case SCBPointer + 1:
+    case SCBPointer + 2:
+    case SCBPointer + 3:
+        TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
+        break;
+    case SCBPort:
+    case SCBPort + 1:
+    case SCBPort + 2:
+        TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
+        break;
+    case SCBPort + 3:
+        TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
+        eepro100_write_port(s);
+        break;
+    case SCBFlow:       /* does not exist on 82557 */
+    case SCBFlow + 1:
+    case SCBFlow + 2:
+    case SCBpmdr:       /* does not exist on 82557 */
+        TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
+        break;
+    case SCBeeprom:
+        TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
+        eepro100_write_eeprom(s->eeprom, val);
+        break;
+    case SCBCtrlMDI:
+    case SCBCtrlMDI + 1:
+    case SCBCtrlMDI + 2:
+        TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
+        break;
+    case SCBCtrlMDI + 3:
+        TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
+        eepro100_write_mdi(s);
+        break;
+    default:
+        logout("addr=%s val=0x%02x\n", regname(addr), val);
+        missing("unknown byte write");
+    }
+}
+
+static void eepro100_write2(EEPRO100State * s, uint32_t addr, uint16_t val)
+{
+    /* SCBStatus is readonly. */
+    if (addr > SCBStatus && addr <= sizeof(s->mem) - sizeof(val)) {
+        e100_write_reg2(s, addr, val);
+    }
+
+    switch (addr) {
+    case SCBStatus:
+        TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
+        s->mem[SCBAck] = (val >> 8);
+        eepro100_acknowledge(s);
+        break;
+    case SCBCmd:
+        TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
+        eepro100_write_command(s, val);
+        eepro100_write1(s, SCBIntmask, val >> 8);
+        break;
+    case SCBPointer:
+    case SCBPointer + 2:
+        TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
+        break;
+    case SCBPort:
+        TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
+        break;
+    case SCBPort + 2:
+        TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
+        eepro100_write_port(s);
+        break;
+    case SCBeeprom:
+        TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
+        eepro100_write_eeprom(s->eeprom, val);
+        break;
+    case SCBCtrlMDI:
+        TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
+        break;
+    case SCBCtrlMDI + 2:
+        TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
+        eepro100_write_mdi(s);
+        break;
+    default:
+        logout("addr=%s val=0x%04x\n", regname(addr), val);
+        missing("unknown word write");
+    }
+}
+
+static void eepro100_write4(EEPRO100State * s, uint32_t addr, uint32_t val)
+{
+    if (addr <= sizeof(s->mem) - sizeof(val)) {
+        e100_write_reg4(s, addr, val);
+    }
+
+    switch (addr) {
+    case SCBPointer:
+        TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val));
+        break;
+    case SCBPort:
+        TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val));
+        eepro100_write_port(s);
+        break;
+    case SCBflash:
+        TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val));
+        val = val >> 16;
+        eepro100_write_eeprom(s->eeprom, val);
+        break;
+    case SCBCtrlMDI:
+        TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val));
+        eepro100_write_mdi(s);
+        break;
+    default:
+        logout("addr=%s val=0x%08x\n", regname(addr), val);
+        missing("unknown longword write");
+    }
+}
+
+static uint64_t eepro100_read(void *opaque, hwaddr addr,
+                              unsigned size)
+{
+    EEPRO100State *s = opaque;
+
+    switch (size) {
+    case 1: return eepro100_read1(s, addr);
+    case 2: return eepro100_read2(s, addr);
+    case 4: return eepro100_read4(s, addr);
+    default: abort();
+    }
+}
+
+static void eepro100_write(void *opaque, hwaddr addr,
+                           uint64_t data, unsigned size)
+{
+    EEPRO100State *s = opaque;
+
+    switch (size) {
+    case 1:
+        eepro100_write1(s, addr, data);
+        break;
+    case 2:
+        eepro100_write2(s, addr, data);
+        break;
+    case 4:
+        eepro100_write4(s, addr, data);
+        break;
+    default:
+        abort();
+    }
+}
+
+static const MemoryRegionOps eepro100_ops = {
+    .read = eepro100_read,
+    .write = eepro100_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static int nic_can_receive(NetClientState *nc)
+{
+    EEPRO100State *s = qemu_get_nic_opaque(nc);
+    TRACE(RXTX, logout("%p\n", s));
+    return get_ru_state(s) == ru_ready;
+#if 0
+    return !eepro100_buffer_full(s);
+#endif
+}
+
+static ssize_t nic_receive(NetClientState *nc, const uint8_t * buf, size_t size)
+{
+    /* TODO:
+     * - Magic packets should set bit 30 in power management driver register.
+     * - Interesting packets should set bit 29 in power management driver register.
+     */
+    EEPRO100State *s = qemu_get_nic_opaque(nc);
+    uint16_t rfd_status = 0xa000;
+#if defined(CONFIG_PAD_RECEIVED_FRAMES)
+    uint8_t min_buf[60];
+#endif
+    static const uint8_t broadcast_macaddr[6] =
+        { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+#if defined(CONFIG_PAD_RECEIVED_FRAMES)
+    /* Pad to minimum Ethernet frame length */
+    if (size < sizeof(min_buf)) {
+        memcpy(min_buf, buf, size);
+        memset(&min_buf[size], 0, sizeof(min_buf) - size);
+        buf = min_buf;
+        size = sizeof(min_buf);
+    }
+#endif
+
+    if (s->configuration[8] & 0x80) {
+        /* CSMA is disabled. */
+        logout("%p received while CSMA is disabled\n", s);
+        return -1;
+#if !defined(CONFIG_PAD_RECEIVED_FRAMES)
+    } else if (size < 64 && (s->configuration[7] & BIT(0))) {
+        /* Short frame and configuration byte 7/0 (discard short receive) set:
+         * Short frame is discarded */
+        logout("%p received short frame (%zu byte)\n", s, size);
+        s->statistics.rx_short_frame_errors++;
+        return -1;
+#endif
+    } else if ((size > MAX_ETH_FRAME_SIZE + 4) && !(s->configuration[18] & BIT(3))) {
+        /* Long frame and configuration byte 18/3 (long receive ok) not set:
+         * Long frames are discarded. */
+        logout("%p received long frame (%zu byte), ignored\n", s, size);
+        return -1;
+    } else if (memcmp(buf, s->conf.macaddr.a, 6) == 0) {       /* !!! */
+        /* Frame matches individual address. */
+        /* TODO: check configuration byte 15/4 (ignore U/L). */
+        TRACE(RXTX, logout("%p received frame for me, len=%zu\n", s, size));
+    } else if (memcmp(buf, broadcast_macaddr, 6) == 0) {
+        /* Broadcast frame. */
+        TRACE(RXTX, logout("%p received broadcast, len=%zu\n", s, size));
+        rfd_status |= 0x0002;
+    } else if (buf[0] & 0x01) {
+        /* Multicast frame. */
+        TRACE(RXTX, logout("%p received multicast, len=%zu,%s\n", s, size, nic_dump(buf, size)));
+        if (s->configuration[21] & BIT(3)) {
+          /* Multicast all bit is set, receive all multicast frames. */
+        } else {
+          unsigned mcast_idx = e100_compute_mcast_idx(buf);
+          assert(mcast_idx < 64);
+          if (s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7))) {
+            /* Multicast frame is allowed in hash table. */
+          } else if (s->configuration[15] & BIT(0)) {
+              /* Promiscuous: receive all. */
+              rfd_status |= 0x0004;
+          } else {
+              TRACE(RXTX, logout("%p multicast ignored\n", s));
+              return -1;
+          }
+        }
+        /* TODO: Next not for promiscuous mode? */
+        rfd_status |= 0x0002;
+    } else if (s->configuration[15] & BIT(0)) {
+        /* Promiscuous: receive all. */
+        TRACE(RXTX, logout("%p received frame in promiscuous mode, len=%zu\n", s, size));
+        rfd_status |= 0x0004;
+    } else if (s->configuration[20] & BIT(6)) {
+        /* Multiple IA bit set. */
+        unsigned mcast_idx = compute_mcast_idx(buf);
+        assert(mcast_idx < 64);
+        if (s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7))) {
+            TRACE(RXTX, logout("%p accepted, multiple IA bit set\n", s));
+        } else {
+            TRACE(RXTX, logout("%p frame ignored, multiple IA bit set\n", s));
+            return -1;
+        }
+    } else {
+        TRACE(RXTX, logout("%p received frame, ignored, len=%zu,%s\n", s, size,
+              nic_dump(buf, size)));
+        return size;
+    }
+
+    if (get_ru_state(s) != ru_ready) {
+        /* No resources available. */
+        logout("no resources, state=%u\n", get_ru_state(s));
+        /* TODO: RNR interrupt only at first failed frame? */
+        eepro100_rnr_interrupt(s);
+        s->statistics.rx_resource_errors++;
+#if 0
+        assert(!"no resources");
+#endif
+        return -1;
+    }
+    /* !!! */
+    eepro100_rx_t rx;
+    pci_dma_read(&s->dev, s->ru_base + s->ru_offset,
+                 &rx, sizeof(eepro100_rx_t));
+    uint16_t rfd_command = le16_to_cpu(rx.command);
+    uint16_t rfd_size = le16_to_cpu(rx.size);
+
+    if (size > rfd_size) {
+        logout("Receive buffer (%" PRId16 " bytes) too small for data "
+            "(%zu bytes); data truncated\n", rfd_size, size);
+        size = rfd_size;
+    }
+#if !defined(CONFIG_PAD_RECEIVED_FRAMES)
+    if (size < 64) {
+        rfd_status |= 0x0080;
+    }
+#endif
+    TRACE(OTHER, logout("command 0x%04x, link 0x%08x, addr 0x%08x, size %u\n",
+          rfd_command, rx.link, rx.rx_buf_addr, rfd_size));
+    stw_le_pci_dma(&s->dev, s->ru_base + s->ru_offset +
+                offsetof(eepro100_rx_t, status), rfd_status);
+    stw_le_pci_dma(&s->dev, s->ru_base + s->ru_offset +
+                offsetof(eepro100_rx_t, count), size);
+    /* Early receive interrupt not supported. */
+#if 0
+    eepro100_er_interrupt(s);
+#endif
+    /* Receive CRC Transfer not supported. */
+    if (s->configuration[18] & BIT(2)) {
+        missing("Receive CRC Transfer");
+        return -1;
+    }
+    /* TODO: check stripping enable bit. */
+#if 0
+    assert(!(s->configuration[17] & BIT(0)));
+#endif
+    pci_dma_write(&s->dev, s->ru_base + s->ru_offset +
+                  sizeof(eepro100_rx_t), buf, size);
+    s->statistics.rx_good_frames++;
+    eepro100_fr_interrupt(s);
+    s->ru_offset = le32_to_cpu(rx.link);
+    if (rfd_command & COMMAND_EL) {
+        /* EL bit is set, so this was the last frame. */
+        logout("receive: Running out of frames\n");
+        set_ru_state(s, ru_no_resources);
+        eepro100_rnr_interrupt(s);
+    }
+    if (rfd_command & COMMAND_S) {
+        /* S bit is set. */
+        set_ru_state(s, ru_suspended);
+    }
+    return size;
+}
+
+static const VMStateDescription vmstate_eepro100 = {
+    .version_id = 3,
+    .minimum_version_id = 2,
+    .minimum_version_id_old = 2,
+    .fields      = (VMStateField []) {
+        VMSTATE_PCI_DEVICE(dev, EEPRO100State),
+        VMSTATE_UNUSED(32),
+        VMSTATE_BUFFER(mult, EEPRO100State),
+        VMSTATE_BUFFER(mem, EEPRO100State),
+        /* Save all members of struct between scb_stat and mem. */
+        VMSTATE_UINT8(scb_stat, EEPRO100State),
+        VMSTATE_UINT8(int_stat, EEPRO100State),
+        VMSTATE_UNUSED(3*4),
+        VMSTATE_MACADDR(conf.macaddr, EEPRO100State),
+        VMSTATE_UNUSED(19*4),
+        VMSTATE_UINT16_ARRAY(mdimem, EEPRO100State, 32),
+        /* The eeprom should be saved and restored by its own routines. */
+        VMSTATE_UINT32(device, EEPRO100State),
+        /* TODO check device. */
+        VMSTATE_UINT32(cu_base, EEPRO100State),
+        VMSTATE_UINT32(cu_offset, EEPRO100State),
+        VMSTATE_UINT32(ru_base, EEPRO100State),
+        VMSTATE_UINT32(ru_offset, EEPRO100State),
+        VMSTATE_UINT32(statsaddr, EEPRO100State),
+        /* Save eepro100_stats_t statistics. */
+        VMSTATE_UINT32(statistics.tx_good_frames, EEPRO100State),
+        VMSTATE_UINT32(statistics.tx_max_collisions, EEPRO100State),
+        VMSTATE_UINT32(statistics.tx_late_collisions, EEPRO100State),
+        VMSTATE_UINT32(statistics.tx_underruns, EEPRO100State),
+        VMSTATE_UINT32(statistics.tx_lost_crs, EEPRO100State),
+        VMSTATE_UINT32(statistics.tx_deferred, EEPRO100State),
+        VMSTATE_UINT32(statistics.tx_single_collisions, EEPRO100State),
+        VMSTATE_UINT32(statistics.tx_multiple_collisions, EEPRO100State),
+        VMSTATE_UINT32(statistics.tx_total_collisions, EEPRO100State),
+        VMSTATE_UINT32(statistics.rx_good_frames, EEPRO100State),
+        VMSTATE_UINT32(statistics.rx_crc_errors, EEPRO100State),
+        VMSTATE_UINT32(statistics.rx_alignment_errors, EEPRO100State),
+        VMSTATE_UINT32(statistics.rx_resource_errors, EEPRO100State),
+        VMSTATE_UINT32(statistics.rx_overrun_errors, EEPRO100State),
+        VMSTATE_UINT32(statistics.rx_cdt_errors, EEPRO100State),
+        VMSTATE_UINT32(statistics.rx_short_frame_errors, EEPRO100State),
+        VMSTATE_UINT32(statistics.fc_xmt_pause, EEPRO100State),
+        VMSTATE_UINT32(statistics.fc_rcv_pause, EEPRO100State),
+        VMSTATE_UINT32(statistics.fc_rcv_unsupported, EEPRO100State),
+        VMSTATE_UINT16(statistics.xmt_tco_frames, EEPRO100State),
+        VMSTATE_UINT16(statistics.rcv_tco_frames, EEPRO100State),
+        /* Configuration bytes. */
+        VMSTATE_BUFFER(configuration, EEPRO100State),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void nic_cleanup(NetClientState *nc)
+{
+    EEPRO100State *s = qemu_get_nic_opaque(nc);
+
+    s->nic = NULL;
+}
+
+static void pci_nic_uninit(PCIDevice *pci_dev)
+{
+    EEPRO100State *s = DO_UPCAST(EEPRO100State, dev, pci_dev);
+
+    memory_region_destroy(&s->mmio_bar);
+    memory_region_destroy(&s->io_bar);
+    memory_region_destroy(&s->flash_bar);
+    vmstate_unregister(&pci_dev->qdev, s->vmstate, s);
+    eeprom93xx_free(&pci_dev->qdev, s->eeprom);
+    qemu_del_nic(s->nic);
+}
+
+static NetClientInfo net_eepro100_info = {
+    .type = NET_CLIENT_OPTIONS_KIND_NIC,
+    .size = sizeof(NICState),
+    .can_receive = nic_can_receive,
+    .receive = nic_receive,
+    .cleanup = nic_cleanup,
+};
+
+static int e100_nic_init(PCIDevice *pci_dev)
+{
+    EEPRO100State *s = DO_UPCAST(EEPRO100State, dev, pci_dev);
+    E100PCIDeviceInfo *info = eepro100_get_class(s);
+
+    TRACE(OTHER, logout("\n"));
+
+    s->device = info->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. */
+    s->eeprom = eeprom93xx_new(&pci_dev->qdev, EEPROM_SIZE);
+
+    /* Handler for memory-mapped I/O */
+    memory_region_init_io(&s->mmio_bar, &eepro100_ops, s, "eepro100-mmio",
+                          PCI_MEM_SIZE);
+    pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_MEM_PREFETCH, &s->mmio_bar);
+    memory_region_init_io(&s->io_bar, &eepro100_ops, s, "eepro100-io",
+                          PCI_IO_SIZE);
+    pci_register_bar(&s->dev, 1, PCI_BASE_ADDRESS_SPACE_IO, &s->io_bar);
+    /* FIXME: flash aliases to mmio?! */
+    memory_region_init_io(&s->flash_bar, &eepro100_ops, s, "eepro100-flash",
+                          PCI_FLASH_SIZE);
+    pci_register_bar(&s->dev, 2, 0, &s->flash_bar);
+
+    qemu_macaddr_default_if_unset(&s->conf.macaddr);
+    logout("macaddr: %s\n", nic_dump(&s->conf.macaddr.a[0], 6));
+
+    nic_reset(s);
+
+    s->nic = qemu_new_nic(&net_eepro100_info, &s->conf,
+                          object_get_typename(OBJECT(pci_dev)), pci_dev->qdev.id, s);
+
+    qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
+    TRACE(OTHER, logout("%s\n", qemu_get_queue(s->nic)->info_str));
+
+    qemu_register_reset(nic_reset, s);
+
+    s->vmstate = g_malloc(sizeof(vmstate_eepro100));
+    memcpy(s->vmstate, &vmstate_eepro100, sizeof(vmstate_eepro100));
+    s->vmstate->name = qemu_get_queue(s->nic)->model;
+    vmstate_register(&pci_dev->qdev, -1, s->vmstate, s);
+
+    add_boot_device_path(s->conf.bootindex, &pci_dev->qdev, "/ethernet-phy@0");
+
+    return 0;
+}
+
+static E100PCIDeviceInfo e100_devices[] = {
+    {
+        .name = "i82550",
+        .desc = "Intel i82550 Ethernet",
+        .device = i82550,
+        /* TODO: check device id. */
+        .device_id = PCI_DEVICE_ID_INTEL_82551IT,
+        /* Revision ID: 0x0c, 0x0d, 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,
+    },{
+        .name = "i82551",
+        .desc = "Intel i82551 Ethernet",
+        .device = i82551,
+        .device_id = PCI_DEVICE_ID_INTEL_82551IT,
+        /* Revision ID: 0x0f, 0x10. */
+        .revision = 0x0f,
+        /* TODO: check size of statistical counters. */
+        .stats_size = 80,
+        .has_extended_tcb_support = true,
+        .power_management = true,
+    },{
+        .name = "i82557a",
+        .desc = "Intel i82557A Ethernet",
+        .device = i82557A,
+        .device_id = PCI_DEVICE_ID_INTEL_82557,
+        .revision = 0x01,
+        .power_management = false,
+    },{
+        .name = "i82557b",
+        .desc = "Intel i82557B Ethernet",
+        .device = i82557B,
+        .device_id = PCI_DEVICE_ID_INTEL_82557,
+        .revision = 0x02,
+        .power_management = false,
+    },{
+        .name = "i82557c",
+        .desc = "Intel i82557C Ethernet",
+        .device = i82557C,
+        .device_id = PCI_DEVICE_ID_INTEL_82557,
+        .revision = 0x03,
+        .power_management = false,
+    },{
+        .name = "i82558a",
+        .desc = "Intel i82558A Ethernet",
+        .device = i82558A,
+        .device_id = PCI_DEVICE_ID_INTEL_82557,
+        .revision = 0x04,
+        .stats_size = 76,
+        .has_extended_tcb_support = true,
+        .power_management = true,
+    },{
+        .name = "i82558b",
+        .desc = "Intel i82558B Ethernet",
+        .device = i82558B,
+        .device_id = PCI_DEVICE_ID_INTEL_82557,
+        .revision = 0x05,
+        .stats_size = 76,
+        .has_extended_tcb_support = true,
+        .power_management = true,
+    },{
+        .name = "i82559a",
+        .desc = "Intel i82559A Ethernet",
+        .device = i82559A,
+        .device_id = PCI_DEVICE_ID_INTEL_82557,
+        .revision = 0x06,
+        .stats_size = 80,
+        .has_extended_tcb_support = true,
+        .power_management = true,
+    },{
+        .name = "i82559b",
+        .desc = "Intel i82559B Ethernet",
+        .device = i82559B,
+        .device_id = PCI_DEVICE_ID_INTEL_82557,
+        .revision = 0x07,
+        .stats_size = 80,
+        .has_extended_tcb_support = true,
+        .power_management = true,
+    },{
+        .name = "i82559c",
+        .desc = "Intel i82559C Ethernet",
+        .device = i82559C,
+        .device_id = PCI_DEVICE_ID_INTEL_82557,
+#if 0
+        .revision = 0x08,
+#endif
+        /* TODO: Windows wants revision id 0x0c. */
+        .revision = 0x0c,
+#if EEPROM_SIZE > 0
+        .subsystem_vendor_id = PCI_VENDOR_ID_INTEL,
+        .subsystem_id = 0x0040,
+#endif
+        .stats_size = 80,
+        .has_extended_tcb_support = true,
+        .power_management = true,
+    },{
+        .name = "i82559er",
+        .desc = "Intel i82559ER Ethernet",
+        .device = i82559ER,
+        .device_id = PCI_DEVICE_ID_INTEL_82551IT,
+        .revision = 0x09,
+        .stats_size = 80,
+        .has_extended_tcb_support = true,
+        .power_management = true,
+    },{
+        .name = "i82562",
+        .desc = "Intel i82562 Ethernet",
+        .device = i82562,
+        /* TODO: check device id. */
+        .device_id = PCI_DEVICE_ID_INTEL_82551IT,
+        /* TODO: wrong revision id. */
+        .revision = 0x0e,
+        .stats_size = 80,
+        .has_extended_tcb_support = true,
+        .power_management = true,
+    },{
+        /* Toshiba Tecra 8200. */
+        .name = "i82801",
+        .desc = "Intel i82801 Ethernet",
+        .device = i82801,
+        .device_id = 0x2449,
+        .revision = 0x03,
+        .stats_size = 80,
+        .has_extended_tcb_support = true,
+        .power_management = true,
+    }
+};
+
+static E100PCIDeviceInfo *eepro100_get_class_by_name(const char *typename)
+{
+    E100PCIDeviceInfo *info = NULL;
+    int i;
+
+    /* This is admittedly awkward but also temporary.  QOM allows for
+     * parameterized typing and for subclassing both of which would suitable
+     * handle what's going on here.  But class_data is already being used as
+     * a stop-gap hack to allow incremental qdev conversion so we cannot use it
+     * right now.  Once we merge the final QOM series, we can come back here and
+     * do this in a much more elegant fashion.
+     */
+    for (i = 0; i < ARRAY_SIZE(e100_devices); i++) {
+        if (strcmp(e100_devices[i].name, typename) == 0) {
+            info = &e100_devices[i];
+            break;
+        }
+    }
+    assert(info != NULL);
+
+    return info;
+}
+
+static E100PCIDeviceInfo *eepro100_get_class(EEPRO100State *s)
+{
+    return eepro100_get_class_by_name(object_get_typename(OBJECT(s)));
+}
+
+static Property e100_properties[] = {
+    DEFINE_NIC_PROPERTIES(EEPRO100State, conf),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void eepro100_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+    E100PCIDeviceInfo *info;
+
+    info = eepro100_get_class_by_name(object_class_get_name(klass));
+
+    dc->props = e100_properties;
+    dc->desc = info->desc;
+    k->vendor_id = PCI_VENDOR_ID_INTEL;
+    k->class_id = PCI_CLASS_NETWORK_ETHERNET;
+    k->romfile = "pxe-eepro100.rom";
+    k->init = e100_nic_init;
+    k->exit = pci_nic_uninit;
+    k->device_id = info->device_id;
+    k->revision = info->revision;
+    k->subsystem_vendor_id = info->subsystem_vendor_id;
+    k->subsystem_id = info->subsystem_id;
+}
+
+static void eepro100_register_types(void)
+{
+    size_t i;
+    for (i = 0; i < ARRAY_SIZE(e100_devices); i++) {
+        TypeInfo type_info = {};
+        E100PCIDeviceInfo *info = &e100_devices[i];
+
+        type_info.name = info->name;
+        type_info.parent = TYPE_PCI_DEVICE;
+        type_info.class_init = eepro100_class_init;
+        type_info.instance_size = sizeof(EEPRO100State);
+        
+        type_register(&type_info);
+    }
+}
+
+type_init(eepro100_register_types)
diff --git a/hw/net/etraxfs_eth.c b/hw/net/etraxfs_eth.c
new file mode 100644 (file)
index 0000000..1039913
--- /dev/null
@@ -0,0 +1,656 @@
+/*
+ * QEMU ETRAX Ethernet Controller.
+ *
+ * Copyright (c) 2008 Edgar E. Iglesias, Axis Communications AB.
+ *
+ * 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 <stdio.h>
+#include "hw/sysbus.h"
+#include "net/net.h"
+#include "hw/cris/etraxfs.h"
+
+#define D(x)
+
+/* Advertisement control register. */
+#define ADVERTISE_10HALF        0x0020  /* Try for 10mbps half-duplex  */
+#define ADVERTISE_10FULL        0x0040  /* Try for 10mbps full-duplex  */
+#define ADVERTISE_100HALF       0x0080  /* Try for 100mbps half-duplex */
+#define ADVERTISE_100FULL       0x0100  /* Try for 100mbps full-duplex */
+
+/*
+ * The MDIO extensions in the TDK PHY model were reversed engineered from the
+ * linux driver (PHYID and Diagnostics reg).
+ * TODO: Add friendly names for the register nums.
+ */
+struct qemu_phy
+{
+    uint32_t regs[32];
+
+    int link;
+
+    unsigned int (*read)(struct qemu_phy *phy, unsigned int req);
+    void (*write)(struct qemu_phy *phy, unsigned int req, unsigned int data);
+};
+
+static unsigned int tdk_read(struct qemu_phy *phy, unsigned int req)
+{
+    int regnum;
+    unsigned r = 0;
+
+    regnum = req & 0x1f;
+
+    switch (regnum) {
+    case 1:
+        if (!phy->link) {
+            break;
+        }
+        /* MR1.     */
+        /* Speeds and modes.  */
+        r |= (1 << 13) | (1 << 14);
+        r |= (1 << 11) | (1 << 12);
+        r |= (1 << 5); /* Autoneg complete.  */
+        r |= (1 << 3); /* Autoneg able.     */
+        r |= (1 << 2); /* link.     */
+        break;
+    case 5:
+        /* Link partner ability.
+           We are kind; always agree with whatever best mode
+           the guest advertises.  */
+        r = 1 << 14; /* Success.  */
+        /* Copy advertised modes.  */
+        r |= phy->regs[4] & (15 << 5);
+        /* Autoneg support.  */
+        r |= 1;
+        break;
+    case 18:
+    {
+        /* Diagnostics reg.  */
+        int duplex = 0;
+        int speed_100 = 0;
+
+        if (!phy->link) {
+            break;
+        }
+
+        /* Are we advertising 100 half or 100 duplex ? */
+        speed_100 = !!(phy->regs[4] & ADVERTISE_100HALF);
+        speed_100 |= !!(phy->regs[4] & ADVERTISE_100FULL);
+
+        /* Are we advertising 10 duplex or 100 duplex ? */
+        duplex = !!(phy->regs[4] & ADVERTISE_100FULL);
+        duplex |= !!(phy->regs[4] & ADVERTISE_10FULL);
+        r = (speed_100 << 10) | (duplex << 11);
+    }
+    break;
+
+    default:
+        r = phy->regs[regnum];
+        break;
+    }
+    D(printf("\n%s %x = reg[%d]\n", __func__, r, regnum));
+    return r;
+}
+
+static void
+tdk_write(struct qemu_phy *phy, unsigned int req, unsigned int data)
+{
+    int regnum;
+
+    regnum = req & 0x1f;
+    D(printf("%s reg[%d] = %x\n", __func__, regnum, data));
+    switch (regnum) {
+    default:
+        phy->regs[regnum] = data;
+        break;
+    }
+}
+
+static void
+tdk_init(struct qemu_phy *phy)
+{
+    phy->regs[0] = 0x3100;
+    /* PHY Id.  */
+    phy->regs[2] = 0x0300;
+    phy->regs[3] = 0xe400;
+    /* Autonegotiation advertisement reg.  */
+    phy->regs[4] = 0x01E1;
+    phy->link = 1;
+
+    phy->read = tdk_read;
+    phy->write = tdk_write;
+}
+
+struct qemu_mdio
+{
+    /* bus.     */
+    int mdc;
+    int mdio;
+
+    /* decoder.  */
+    enum {
+        PREAMBLE,
+        SOF,
+        OPC,
+        ADDR,
+        REQ,
+        TURNAROUND,
+        DATA
+    } state;
+    unsigned int drive;
+
+    unsigned int cnt;
+    unsigned int addr;
+    unsigned int opc;
+    unsigned int req;
+    unsigned int data;
+
+    struct qemu_phy *devs[32];
+};
+
+static void
+mdio_attach(struct qemu_mdio *bus, struct qemu_phy *phy, unsigned int addr)
+{
+    bus->devs[addr & 0x1f] = phy;
+}
+
+#ifdef USE_THIS_DEAD_CODE
+static void
+mdio_detach(struct qemu_mdio *bus, struct qemu_phy *phy, unsigned int addr)
+{
+    bus->devs[addr & 0x1f] = NULL;
+}
+#endif
+
+static void mdio_read_req(struct qemu_mdio *bus)
+{
+    struct qemu_phy *phy;
+
+    phy = bus->devs[bus->addr];
+    if (phy && phy->read) {
+        bus->data = phy->read(phy, bus->req);
+    } else {
+        bus->data = 0xffff;
+    }
+}
+
+static void mdio_write_req(struct qemu_mdio *bus)
+{
+    struct qemu_phy *phy;
+
+    phy = bus->devs[bus->addr];
+    if (phy && phy->write) {
+        phy->write(phy, bus->req, bus->data);
+    }
+}
+
+static void mdio_cycle(struct qemu_mdio *bus)
+{
+    bus->cnt++;
+
+    D(printf("mdc=%d mdio=%d state=%d cnt=%d drv=%d\n",
+        bus->mdc, bus->mdio, bus->state, bus->cnt, bus->drive));
+#if 0
+    if (bus->mdc) {
+        printf("%d", bus->mdio);
+    }
+#endif
+    switch (bus->state) {
+    case PREAMBLE:
+        if (bus->mdc) {
+            if (bus->cnt >= (32 * 2) && !bus->mdio) {
+                bus->cnt = 0;
+                bus->state = SOF;
+                bus->data = 0;
+            }
+        }
+        break;
+    case SOF:
+        if (bus->mdc) {
+            if (bus->mdio != 1) {
+                printf("WARNING: no SOF\n");
+            }
+            if (bus->cnt == 1*2) {
+                bus->cnt = 0;
+                bus->opc = 0;
+                bus->state = OPC;
+            }
+        }
+        break;
+    case OPC:
+        if (bus->mdc) {
+            bus->opc <<= 1;
+            bus->opc |= bus->mdio & 1;
+            if (bus->cnt == 2*2) {
+                bus->cnt = 0;
+                bus->addr = 0;
+                bus->state = ADDR;
+            }
+        }
+        break;
+    case ADDR:
+        if (bus->mdc) {
+            bus->addr <<= 1;
+            bus->addr |= bus->mdio & 1;
+
+            if (bus->cnt == 5*2) {
+                bus->cnt = 0;
+                bus->req = 0;
+                bus->state = REQ;
+            }
+        }
+        break;
+    case REQ:
+        if (bus->mdc) {
+            bus->req <<= 1;
+            bus->req |= bus->mdio & 1;
+            if (bus->cnt == 5*2) {
+                bus->cnt = 0;
+                bus->state = TURNAROUND;
+            }
+        }
+        break;
+    case TURNAROUND:
+        if (bus->mdc && bus->cnt == 2*2) {
+            bus->mdio = 0;
+            bus->cnt = 0;
+
+            if (bus->opc == 2) {
+                bus->drive = 1;
+                mdio_read_req(bus);
+                bus->mdio = bus->data & 1;
+            }
+            bus->state = DATA;
+        }
+        break;
+    case DATA:
+        if (!bus->mdc) {
+            if (bus->drive) {
+                bus->mdio = !!(bus->data & (1 << 15));
+                bus->data <<= 1;
+            }
+        } else {
+            if (!bus->drive) {
+                bus->data <<= 1;
+                bus->data |= bus->mdio;
+            }
+            if (bus->cnt == 16 * 2) {
+                bus->cnt = 0;
+                bus->state = PREAMBLE;
+                if (!bus->drive) {
+                    mdio_write_req(bus);
+                }
+                bus->drive = 0;
+            }
+        }
+        break;
+    default:
+        break;
+    }
+}
+
+/* ETRAX-FS Ethernet MAC block starts here.  */
+
+#define RW_MA0_LO      0x00
+#define RW_MA0_HI      0x01
+#define RW_MA1_LO      0x02
+#define RW_MA1_HI      0x03
+#define RW_GA_LO      0x04
+#define RW_GA_HI      0x05
+#define RW_GEN_CTRL      0x06
+#define RW_REC_CTRL      0x07
+#define RW_TR_CTRL      0x08
+#define RW_CLR_ERR      0x09
+#define RW_MGM_CTRL      0x0a
+#define R_STAT          0x0b
+#define FS_ETH_MAX_REGS      0x17
+
+struct fs_eth
+{
+    SysBusDevice busdev;
+    MemoryRegion mmio;
+    NICState *nic;
+    NICConf conf;
+
+    /* Two addrs in the filter.  */
+    uint8_t macaddr[2][6];
+    uint32_t regs[FS_ETH_MAX_REGS];
+
+    union {
+        void *vdma_out;
+        struct etraxfs_dma_client *dma_out;
+    };
+    union {
+        void *vdma_in;
+        struct etraxfs_dma_client *dma_in;
+    };
+
+    /* MDIO bus.  */
+    struct qemu_mdio mdio_bus;
+    unsigned int phyaddr;
+    int duplex_mismatch;
+
+    /* PHY.     */
+    struct qemu_phy phy;
+};
+
+static void eth_validate_duplex(struct fs_eth *eth)
+{
+    struct qemu_phy *phy;
+    unsigned int phy_duplex;
+    unsigned int mac_duplex;
+    int new_mm = 0;
+
+    phy = eth->mdio_bus.devs[eth->phyaddr];
+    phy_duplex = !!(phy->read(phy, 18) & (1 << 11));
+    mac_duplex = !!(eth->regs[RW_REC_CTRL] & 128);
+
+    if (mac_duplex != phy_duplex) {
+        new_mm = 1;
+    }
+
+    if (eth->regs[RW_GEN_CTRL] & 1) {
+        if (new_mm != eth->duplex_mismatch) {
+            if (new_mm) {
+                printf("HW: WARNING ETH duplex mismatch MAC=%d PHY=%d\n",
+                       mac_duplex, phy_duplex);
+            } else {
+                printf("HW: ETH duplex ok.\n");
+            }
+        }
+        eth->duplex_mismatch = new_mm;
+    }
+}
+
+static uint64_t
+eth_read(void *opaque, hwaddr addr, unsigned int size)
+{
+    struct fs_eth *eth = opaque;
+    uint32_t r = 0;
+
+    addr >>= 2;
+
+    switch (addr) {
+    case R_STAT:
+        r = eth->mdio_bus.mdio & 1;
+        break;
+    default:
+        r = eth->regs[addr];
+        D(printf("%s %x\n", __func__, addr * 4));
+        break;
+    }
+    return r;
+}
+
+static void eth_update_ma(struct fs_eth *eth, int ma)
+{
+    int reg;
+    int i = 0;
+
+    ma &= 1;
+
+    reg = RW_MA0_LO;
+    if (ma) {
+        reg = RW_MA1_LO;
+    }
+
+    eth->macaddr[ma][i++] = eth->regs[reg];
+    eth->macaddr[ma][i++] = eth->regs[reg] >> 8;
+    eth->macaddr[ma][i++] = eth->regs[reg] >> 16;
+    eth->macaddr[ma][i++] = eth->regs[reg] >> 24;
+    eth->macaddr[ma][i++] = eth->regs[reg + 1];
+    eth->macaddr[ma][i] = eth->regs[reg + 1] >> 8;
+
+    D(printf("set mac%d=%x.%x.%x.%x.%x.%x\n", ma,
+             eth->macaddr[ma][0], eth->macaddr[ma][1],
+             eth->macaddr[ma][2], eth->macaddr[ma][3],
+             eth->macaddr[ma][4], eth->macaddr[ma][5]));
+}
+
+static void
+eth_write(void *opaque, hwaddr addr,
+          uint64_t val64, unsigned int size)
+{
+    struct fs_eth *eth = opaque;
+    uint32_t value = val64;
+
+    addr >>= 2;
+    switch (addr) {
+    case RW_MA0_LO:
+    case RW_MA0_HI:
+        eth->regs[addr] = value;
+        eth_update_ma(eth, 0);
+        break;
+    case RW_MA1_LO:
+    case RW_MA1_HI:
+        eth->regs[addr] = value;
+        eth_update_ma(eth, 1);
+        break;
+
+    case RW_MGM_CTRL:
+        /* Attach an MDIO/PHY abstraction.  */
+        if (value & 2) {
+            eth->mdio_bus.mdio = value & 1;
+        }
+        if (eth->mdio_bus.mdc != (value & 4)) {
+            mdio_cycle(&eth->mdio_bus);
+            eth_validate_duplex(eth);
+        }
+        eth->mdio_bus.mdc = !!(value & 4);
+        eth->regs[addr] = value;
+        break;
+
+    case RW_REC_CTRL:
+        eth->regs[addr] = value;
+        eth_validate_duplex(eth);
+        break;
+
+    default:
+        eth->regs[addr] = value;
+        D(printf("%s %x %x\n", __func__, addr, value));
+        break;
+    }
+}
+
+/* The ETRAX FS has a groupt address table (GAT) which works like a k=1 bloom
+   filter dropping group addresses we have not joined.    The filter has 64
+   bits (m). The has function is a simple nible xor of the group addr.    */
+static int eth_match_groupaddr(struct fs_eth *eth, const unsigned char *sa)
+{
+    unsigned int hsh;
+    int m_individual = eth->regs[RW_REC_CTRL] & 4;
+    int match;
+
+    /* First bit on the wire of a MAC address signals multicast or
+       physical address.  */
+    if (!m_individual && !(sa[0] & 1)) {
+        return 0;
+    }
+
+    /* Calculate the hash index for the GA registers. */
+    hsh = 0;
+    hsh ^= (*sa) & 0x3f;
+    hsh ^= ((*sa) >> 6) & 0x03;
+    ++sa;
+    hsh ^= ((*sa) << 2) & 0x03c;
+    hsh ^= ((*sa) >> 4) & 0xf;
+    ++sa;
+    hsh ^= ((*sa) << 4) & 0x30;
+    hsh ^= ((*sa) >> 2) & 0x3f;
+    ++sa;
+    hsh ^= (*sa) & 0x3f;
+    hsh ^= ((*sa) >> 6) & 0x03;
+    ++sa;
+    hsh ^= ((*sa) << 2) & 0x03c;
+    hsh ^= ((*sa) >> 4) & 0xf;
+    ++sa;
+    hsh ^= ((*sa) << 4) & 0x30;
+    hsh ^= ((*sa) >> 2) & 0x3f;
+
+    hsh &= 63;
+    if (hsh > 31) {
+        match = eth->regs[RW_GA_HI] & (1 << (hsh - 32));
+    } else {
+        match = eth->regs[RW_GA_LO] & (1 << hsh);
+    }
+    D(printf("hsh=%x ga=%x.%x mtch=%d\n", hsh,
+             eth->regs[RW_GA_HI], eth->regs[RW_GA_LO], match));
+    return match;
+}
+
+static int eth_can_receive(NetClientState *nc)
+{
+    return 1;
+}
+
+static ssize_t eth_receive(NetClientState *nc, const uint8_t *buf, size_t size)
+{
+    unsigned char sa_bcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+    struct fs_eth *eth = qemu_get_nic_opaque(nc);
+    int use_ma0 = eth->regs[RW_REC_CTRL] & 1;
+    int use_ma1 = eth->regs[RW_REC_CTRL] & 2;
+    int r_bcast = eth->regs[RW_REC_CTRL] & 8;
+
+    if (size < 12) {
+        return -1;
+    }
+
+    D(printf("%x.%x.%x.%x.%x.%x ma=%d %d bc=%d\n",
+         buf[0], buf[1], buf[2], buf[3], buf[4], buf[5],
+         use_ma0, use_ma1, r_bcast));
+
+    /* Does the frame get through the address filters?  */
+    if ((!use_ma0 || memcmp(buf, eth->macaddr[0], 6))
+        && (!use_ma1 || memcmp(buf, eth->macaddr[1], 6))
+        && (!r_bcast || memcmp(buf, sa_bcast, 6))
+        && !eth_match_groupaddr(eth, buf)) {
+        return size;
+    }
+
+    /* FIXME: Find another way to pass on the fake csum.  */
+    etraxfs_dmac_input(eth->dma_in, (void *)buf, size + 4, 1);
+
+        return size;
+}
+
+static int eth_tx_push(void *opaque, unsigned char *buf, int len, bool eop)
+{
+    struct fs_eth *eth = opaque;
+
+    D(printf("%s buf=%p len=%d\n", __func__, buf, len));
+    qemu_send_packet(qemu_get_queue(eth->nic), buf, len);
+    return len;
+}
+
+static void eth_set_link(NetClientState *nc)
+{
+    struct fs_eth *eth = qemu_get_nic_opaque(nc);
+    D(printf("%s %d\n", __func__, nc->link_down));
+    eth->phy.link = !nc->link_down;
+}
+
+static const MemoryRegionOps eth_ops = {
+    .read = eth_read,
+    .write = eth_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4
+    }
+};
+
+static void eth_cleanup(NetClientState *nc)
+{
+    struct fs_eth *eth = qemu_get_nic_opaque(nc);
+
+    /* Disconnect the client.  */
+    eth->dma_out->client.push = NULL;
+    eth->dma_out->client.opaque = NULL;
+    eth->dma_in->client.opaque = NULL;
+    eth->dma_in->client.pull = NULL;
+        g_free(eth);
+}
+
+static NetClientInfo net_etraxfs_info = {
+    .type = NET_CLIENT_OPTIONS_KIND_NIC,
+    .size = sizeof(NICState),
+    .can_receive = eth_can_receive,
+    .receive = eth_receive,
+    .cleanup = eth_cleanup,
+    .link_status_changed = eth_set_link,
+};
+
+static int fs_eth_init(SysBusDevice *dev)
+{
+    struct fs_eth *s = FROM_SYSBUS(typeof(*s), dev);
+
+    if (!s->dma_out || !s->dma_in) {
+        hw_error("Unconnected ETRAX-FS Ethernet MAC.\n");
+    }
+
+    s->dma_out->client.push = eth_tx_push;
+    s->dma_out->client.opaque = s;
+    s->dma_in->client.opaque = s;
+    s->dma_in->client.pull = NULL;
+
+    memory_region_init_io(&s->mmio, &eth_ops, s, "etraxfs-eth", 0x5c);
+    sysbus_init_mmio(dev, &s->mmio);
+
+    qemu_macaddr_default_if_unset(&s->conf.macaddr);
+    s->nic = qemu_new_nic(&net_etraxfs_info, &s->conf,
+                          object_get_typename(OBJECT(s)), dev->qdev.id, s);
+    qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
+
+
+    tdk_init(&s->phy);
+    mdio_attach(&s->mdio_bus, &s->phy, s->phyaddr);
+    return 0;
+}
+
+static Property etraxfs_eth_properties[] = {
+    DEFINE_PROP_UINT32("phyaddr", struct fs_eth, phyaddr, 1),
+    DEFINE_PROP_PTR("dma_out", struct fs_eth, vdma_out),
+    DEFINE_PROP_PTR("dma_in", struct fs_eth, vdma_in),
+    DEFINE_NIC_PROPERTIES(struct fs_eth, conf),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void etraxfs_eth_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = fs_eth_init;
+    dc->props = etraxfs_eth_properties;
+}
+
+static const 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_types(void)
+{
+    type_register_static(&etraxfs_eth_info);
+}
+
+type_init(etraxfs_eth_register_types)
diff --git a/hw/net/lan9118.c b/hw/net/lan9118.c
new file mode 100644 (file)
index 0000000..04cf267
--- /dev/null
@@ -0,0 +1,1399 @@
+/*
+ * SMSC LAN9118 Ethernet interface emulation
+ *
+ * Copyright (c) 2009 CodeSourcery, LLC.
+ * 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 "hw/sysbus.h"
+#include "net/net.h"
+#include "hw/arm/devices.h"
+#include "sysemu/sysemu.h"
+#include "hw/ptimer.h"
+/* For crc32 */
+#include <zlib.h>
+
+//#define DEBUG_LAN9118
+
+#ifdef DEBUG_LAN9118
+#define DPRINTF(fmt, ...) \
+do { printf("lan9118: " fmt , ## __VA_ARGS__); } while (0)
+#define BADF(fmt, ...) \
+do { hw_error("lan9118: error: " fmt , ## __VA_ARGS__);} while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while(0)
+#define BADF(fmt, ...) \
+do { fprintf(stderr, "lan9118: error: " fmt , ## __VA_ARGS__);} while (0)
+#endif
+
+#define CSR_ID_REV      0x50
+#define CSR_IRQ_CFG     0x54
+#define CSR_INT_STS     0x58
+#define CSR_INT_EN      0x5c
+#define CSR_BYTE_TEST   0x64
+#define CSR_FIFO_INT    0x68
+#define CSR_RX_CFG      0x6c
+#define CSR_TX_CFG      0x70
+#define CSR_HW_CFG      0x74
+#define CSR_RX_DP_CTRL  0x78
+#define CSR_RX_FIFO_INF 0x7c
+#define CSR_TX_FIFO_INF 0x80
+#define CSR_PMT_CTRL    0x84
+#define CSR_GPIO_CFG    0x88
+#define CSR_GPT_CFG     0x8c
+#define CSR_GPT_CNT     0x90
+#define CSR_WORD_SWAP   0x98
+#define CSR_FREE_RUN    0x9c
+#define CSR_RX_DROP     0xa0
+#define CSR_MAC_CSR_CMD 0xa4
+#define CSR_MAC_CSR_DATA 0xa8
+#define CSR_AFC_CFG     0xac
+#define CSR_E2P_CMD     0xb0
+#define CSR_E2P_DATA    0xb4
+
+/* IRQ_CFG */
+#define IRQ_INT         0x00001000
+#define IRQ_EN          0x00000100
+#define IRQ_POL         0x00000010
+#define IRQ_TYPE        0x00000001
+
+/* INT_STS/INT_EN */
+#define SW_INT          0x80000000
+#define TXSTOP_INT      0x02000000
+#define RXSTOP_INT      0x01000000
+#define RXDFH_INT       0x00800000
+#define TX_IOC_INT      0x00200000
+#define RXD_INT         0x00100000
+#define GPT_INT         0x00080000
+#define PHY_INT         0x00040000
+#define PME_INT         0x00020000
+#define TXSO_INT        0x00010000
+#define RWT_INT         0x00008000
+#define RXE_INT         0x00004000
+#define TXE_INT         0x00002000
+#define TDFU_INT        0x00000800
+#define TDFO_INT        0x00000400
+#define TDFA_INT        0x00000200
+#define TSFF_INT        0x00000100
+#define TSFL_INT        0x00000080
+#define RXDF_INT        0x00000040
+#define RDFL_INT        0x00000020
+#define RSFF_INT        0x00000010
+#define RSFL_INT        0x00000008
+#define GPIO2_INT       0x00000004
+#define GPIO1_INT       0x00000002
+#define GPIO0_INT       0x00000001
+#define RESERVED_INT    0x7c001000
+
+#define MAC_CR          1
+#define MAC_ADDRH       2
+#define MAC_ADDRL       3
+#define MAC_HASHH       4
+#define MAC_HASHL       5
+#define MAC_MII_ACC     6
+#define MAC_MII_DATA    7
+#define MAC_FLOW        8
+#define MAC_VLAN1       9 /* TODO */
+#define MAC_VLAN2       10 /* TODO */
+#define MAC_WUFF        11 /* TODO */
+#define MAC_WUCSR       12 /* TODO */
+
+#define MAC_CR_RXALL    0x80000000
+#define MAC_CR_RCVOWN   0x00800000
+#define MAC_CR_LOOPBK   0x00200000
+#define MAC_CR_FDPX     0x00100000
+#define MAC_CR_MCPAS    0x00080000
+#define MAC_CR_PRMS     0x00040000
+#define MAC_CR_INVFILT  0x00020000
+#define MAC_CR_PASSBAD  0x00010000
+#define MAC_CR_HO       0x00008000
+#define MAC_CR_HPFILT   0x00002000
+#define MAC_CR_LCOLL    0x00001000
+#define MAC_CR_BCAST    0x00000800
+#define MAC_CR_DISRTY   0x00000400
+#define MAC_CR_PADSTR   0x00000100
+#define MAC_CR_BOLMT    0x000000c0
+#define MAC_CR_DFCHK    0x00000020
+#define MAC_CR_TXEN     0x00000008
+#define MAC_CR_RXEN     0x00000004
+#define MAC_CR_RESERVED 0x7f404213
+
+#define PHY_INT_ENERGYON            0x80
+#define PHY_INT_AUTONEG_COMPLETE    0x40
+#define PHY_INT_FAULT               0x20
+#define PHY_INT_DOWN                0x10
+#define PHY_INT_AUTONEG_LP          0x08
+#define PHY_INT_PARFAULT            0x04
+#define PHY_INT_AUTONEG_PAGE        0x02
+
+#define GPT_TIMER_EN    0x20000000
+
+enum tx_state {
+    TX_IDLE,
+    TX_B,
+    TX_DATA
+};
+
+typedef struct {
+    /* state is a tx_state but we can't put enums in VMStateDescriptions. */
+    uint32_t state;
+    uint32_t cmd_a;
+    uint32_t cmd_b;
+    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;
+    NICConf conf;
+    qemu_irq irq;
+    MemoryRegion mmio;
+    ptimer_state *timer;
+
+    uint32_t irq_cfg;
+    uint32_t int_sts;
+    uint32_t int_en;
+    uint32_t fifo_int;
+    uint32_t rx_cfg;
+    uint32_t tx_cfg;
+    uint32_t hw_cfg;
+    uint32_t pmt_ctrl;
+    uint32_t gpio_cfg;
+    uint32_t gpt_cfg;
+    uint32_t word_swap;
+    uint32_t free_timer_start;
+    uint32_t mac_cmd;
+    uint32_t mac_data;
+    uint32_t afc_cfg;
+    uint32_t e2p_cmd;
+    uint32_t e2p_data;
+
+    uint32_t mac_cr;
+    uint32_t mac_hashh;
+    uint32_t mac_hashl;
+    uint32_t mac_mii_acc;
+    uint32_t mac_mii_data;
+    uint32_t mac_flow;
+
+    uint32_t phy_status;
+    uint32_t phy_control;
+    uint32_t phy_advertise;
+    uint32_t phy_int;
+    uint32_t phy_int_mask;
+
+    int32_t eeprom_writable;
+    uint8_t eeprom[128];
+
+    int32_t tx_fifo_size;
+    LAN9118Packet *txp;
+    LAN9118Packet tx_packet;
+
+    int32_t tx_status_fifo_used;
+    int32_t tx_status_fifo_head;
+    uint32_t tx_status_fifo[512];
+
+    int32_t rx_status_fifo_size;
+    int32_t rx_status_fifo_used;
+    int32_t rx_status_fifo_head;
+    uint32_t rx_status_fifo[896];
+    int32_t rx_fifo_size;
+    int32_t rx_fifo_used;
+    int32_t rx_fifo_head;
+    uint32_t rx_fifo[3360];
+    int32_t rx_packet_size_head;
+    int32_t rx_packet_size_tail;
+    int32_t rx_packet_size[1024];
+
+    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 = 2,
+    .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_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()
+    }
+};
+
+static void lan9118_update(lan9118_state *s)
+{
+    int level;
+
+    /* TODO: Implement FIFO level IRQs.  */
+    level = (s->int_sts & s->int_en) != 0;
+    if (level) {
+        s->irq_cfg |= IRQ_INT;
+    } else {
+        s->irq_cfg &= ~IRQ_INT;
+    }
+    if ((s->irq_cfg & IRQ_EN) == 0) {
+        level = 0;
+    }
+    if ((s->irq_cfg & (IRQ_TYPE | IRQ_POL)) != (IRQ_TYPE | IRQ_POL)) {
+        /* Interrupt is active low unless we're configured as
+         * active-high polarity, push-pull type.
+         */
+        level = !level;
+    }
+    qemu_set_irq(s->irq, level);
+}
+
+static void lan9118_mac_changed(lan9118_state *s)
+{
+    qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
+}
+
+static void lan9118_reload_eeprom(lan9118_state *s)
+{
+    int i;
+    if (s->eeprom[0] != 0xa5) {
+        s->e2p_cmd &= ~0x10;
+        DPRINTF("MACADDR load failed\n");
+        return;
+    }
+    for (i = 0; i < 6; i++) {
+        s->conf.macaddr.a[i] = s->eeprom[i + 1];
+    }
+    s->e2p_cmd |= 0x10;
+    DPRINTF("MACADDR loaded from eeprom\n");
+    lan9118_mac_changed(s);
+}
+
+static void phy_update_irq(lan9118_state *s)
+{
+    if (s->phy_int & s->phy_int_mask) {
+        s->int_sts |= PHY_INT;
+    } else {
+        s->int_sts &= ~PHY_INT;
+    }
+    lan9118_update(s);
+}
+
+static void phy_update_link(lan9118_state *s)
+{
+    /* Autonegotiation status mirrors link status.  */
+    if (qemu_get_queue(s->nic)->link_down) {
+        s->phy_status &= ~0x0024;
+        s->phy_int |= PHY_INT_DOWN;
+    } else {
+        s->phy_status |= 0x0024;
+        s->phy_int |= PHY_INT_ENERGYON;
+        s->phy_int |= PHY_INT_AUTONEG_COMPLETE;
+    }
+    phy_update_irq(s);
+}
+
+static void lan9118_set_link(NetClientState *nc)
+{
+    phy_update_link(qemu_get_nic_opaque(nc));
+}
+
+static void phy_reset(lan9118_state *s)
+{
+    s->phy_status = 0x7809;
+    s->phy_control = 0x3000;
+    s->phy_advertise = 0x01e1;
+    s->phy_int_mask = 0;
+    s->phy_int = 0;
+    phy_update_link(s);
+}
+
+static void lan9118_reset(DeviceState *d)
+{
+    lan9118_state *s = FROM_SYSBUS(lan9118_state, SYS_BUS_DEVICE(d));
+    s->irq_cfg &= (IRQ_TYPE | IRQ_POL);
+    s->int_sts = 0;
+    s->int_en = 0;
+    s->fifo_int = 0x48000000;
+    s->rx_cfg = 0;
+    s->tx_cfg = 0;
+    s->hw_cfg = s->mode_16bit ? 0x00050000 : 0x00050004;
+    s->pmt_ctrl &= 0x45;
+    s->gpio_cfg = 0;
+    s->txp->fifo_used = 0;
+    s->txp->state = TX_IDLE;
+    s->txp->cmd_a = 0xffffffffu;
+    s->txp->cmd_b = 0xffffffffu;
+    s->txp->len = 0;
+    s->txp->fifo_used = 0;
+    s->tx_fifo_size = 4608;
+    s->tx_status_fifo_used = 0;
+    s->rx_status_fifo_size = 704;
+    s->rx_fifo_size = 2640;
+    s->rx_fifo_used = 0;
+    s->rx_status_fifo_size = 176;
+    s->rx_status_fifo_used = 0;
+    s->rxp_offset = 0;
+    s->rxp_size = 0;
+    s->rxp_pad = 0;
+    s->rx_packet_size_tail = s->rx_packet_size_head;
+    s->rx_packet_size[s->rx_packet_size_head] = 0;
+    s->mac_cmd = 0;
+    s->mac_data = 0;
+    s->afc_cfg = 0;
+    s->e2p_cmd = 0;
+    s->e2p_data = 0;
+    s->free_timer_start = qemu_get_clock_ns(vm_clock) / 40;
+
+    ptimer_stop(s->timer);
+    ptimer_set_count(s->timer, 0xffff);
+    s->gpt_cfg = 0xffff;
+
+    s->mac_cr = MAC_CR_PRMS;
+    s->mac_hashh = 0;
+    s->mac_hashl = 0;
+    s->mac_mii_acc = 0;
+    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;
+    lan9118_reload_eeprom(s);
+}
+
+static int lan9118_can_receive(NetClientState *nc)
+{
+    return 1;
+}
+
+static void rx_fifo_push(lan9118_state *s, uint32_t val)
+{
+    int fifo_pos;
+    fifo_pos = s->rx_fifo_head + s->rx_fifo_used;
+    if (fifo_pos >= s->rx_fifo_size)
+      fifo_pos -= s->rx_fifo_size;
+    s->rx_fifo[fifo_pos] = val;
+    s->rx_fifo_used++;
+}
+
+/* Return nonzero if the packet is accepted by the filter.  */
+static int lan9118_filter(lan9118_state *s, const uint8_t *addr)
+{
+    int multicast;
+    uint32_t hash;
+
+    if (s->mac_cr & MAC_CR_PRMS) {
+        return 1;
+    }
+    if (addr[0] == 0xff && addr[1] == 0xff && addr[2] == 0xff &&
+        addr[3] == 0xff && addr[4] == 0xff && addr[5] == 0xff) {
+        return (s->mac_cr & MAC_CR_BCAST) == 0;
+    }
+
+    multicast = addr[0] & 1;
+    if (multicast &&s->mac_cr & MAC_CR_MCPAS) {
+        return 1;
+    }
+    if (multicast ? (s->mac_cr & MAC_CR_HPFILT) == 0
+                  : (s->mac_cr & MAC_CR_HO) == 0) {
+        /* Exact matching.  */
+        hash = memcmp(addr, s->conf.macaddr.a, 6);
+        if (s->mac_cr & MAC_CR_INVFILT) {
+            return hash != 0;
+        } else {
+            return hash == 0;
+        }
+    } else {
+        /* Hash matching  */
+        hash = compute_mcast_idx(addr);
+        if (hash & 0x20) {
+            return (s->mac_hashh >> (hash & 0x1f)) & 1;
+        } else {
+            return (s->mac_hashl >> (hash & 0x1f)) & 1;
+        }
+    }
+}
+
+static ssize_t lan9118_receive(NetClientState *nc, const uint8_t *buf,
+                               size_t size)
+{
+    lan9118_state *s = qemu_get_nic_opaque(nc);
+    int fifo_len;
+    int offset;
+    int src_pos;
+    int n;
+    int filter;
+    uint32_t val;
+    uint32_t crc;
+    uint32_t status;
+
+    if ((s->mac_cr & MAC_CR_RXEN) == 0) {
+        return -1;
+    }
+
+    if (size >= 2048 || size < 14) {
+        return -1;
+    }
+
+    /* TODO: Implement FIFO overflow notification.  */
+    if (s->rx_status_fifo_used == s->rx_status_fifo_size) {
+        return -1;
+    }
+
+    filter = lan9118_filter(s, buf);
+    if (!filter && (s->mac_cr & MAC_CR_RXALL) == 0) {
+        return size;
+    }
+
+    offset = (s->rx_cfg >> 8) & 0x1f;
+    n = offset & 3;
+    fifo_len = (size + n + 3) >> 2;
+    /* Add a word for the CRC.  */
+    fifo_len++;
+    if (s->rx_fifo_size - s->rx_fifo_used < fifo_len) {
+        return -1;
+    }
+
+    DPRINTF("Got packet len:%d fifo:%d filter:%s\n",
+            (int)size, fifo_len, filter ? "pass" : "fail");
+    val = 0;
+    crc = bswap32(crc32(~0, buf, size));
+    for (src_pos = 0; src_pos < size; src_pos++) {
+        val = (val >> 8) | ((uint32_t)buf[src_pos] << 24);
+        n++;
+        if (n == 4) {
+            n = 0;
+            rx_fifo_push(s, val);
+            val = 0;
+        }
+    }
+    if (n) {
+        val >>= ((4 - n) * 8);
+        val |= crc << (n * 8);
+        rx_fifo_push(s, val);
+        val = crc >> ((4 - n) * 8);
+        rx_fifo_push(s, val);
+    } else {
+        rx_fifo_push(s, crc);
+    }
+    n = s->rx_status_fifo_head + s->rx_status_fifo_used;
+    if (n >= s->rx_status_fifo_size) {
+        n -= s->rx_status_fifo_size;
+    }
+    s->rx_packet_size[s->rx_packet_size_tail] = fifo_len;
+    s->rx_packet_size_tail = (s->rx_packet_size_tail + 1023) & 1023;
+    s->rx_status_fifo_used++;
+
+    status = (size + 4) << 16;
+    if (buf[0] == 0xff && buf[1] == 0xff && buf[2] == 0xff &&
+        buf[3] == 0xff && buf[4] == 0xff && buf[5] == 0xff) {
+        status |= 0x00002000;
+    } else if (buf[0] & 1) {
+        status |= 0x00000400;
+    }
+    if (!filter) {
+        status |= 0x40000000;
+    }
+    s->rx_status_fifo[n] = status;
+
+    if (s->rx_status_fifo_used > (s->fifo_int & 0xff)) {
+        s->int_sts |= RSFL_INT;
+    }
+    lan9118_update(s);
+
+    return size;
+}
+
+static uint32_t rx_fifo_pop(lan9118_state *s)
+{
+    int n;
+    uint32_t val;
+
+    if (s->rxp_size == 0 && s->rxp_pad == 0) {
+        s->rxp_size = s->rx_packet_size[s->rx_packet_size_head];
+        s->rx_packet_size[s->rx_packet_size_head] = 0;
+        if (s->rxp_size != 0) {
+            s->rx_packet_size_head = (s->rx_packet_size_head + 1023) & 1023;
+            s->rxp_offset = (s->rx_cfg >> 10) & 7;
+            n = s->rxp_offset + s->rxp_size;
+            switch (s->rx_cfg >> 30) {
+            case 1:
+                n = (-n) & 3;
+                break;
+            case 2:
+                n = (-n) & 7;
+                break;
+            default:
+                n = 0;
+                break;
+            }
+            s->rxp_pad = n;
+            DPRINTF("Pop packet size:%d offset:%d pad: %d\n",
+                    s->rxp_size, s->rxp_offset, s->rxp_pad);
+        }
+    }
+    if (s->rxp_offset > 0) {
+        s->rxp_offset--;
+        val = 0;
+    } else if (s->rxp_size > 0) {
+        s->rxp_size--;
+        val = s->rx_fifo[s->rx_fifo_head++];
+        if (s->rx_fifo_head >= s->rx_fifo_size) {
+            s->rx_fifo_head -= s->rx_fifo_size;
+        }
+        s->rx_fifo_used--;
+    } else if (s->rxp_pad > 0) {
+        s->rxp_pad--;
+        val =  0;
+    } else {
+        DPRINTF("RX underflow\n");
+        s->int_sts |= RXE_INT;
+        val =  0;
+    }
+    lan9118_update(s);
+    return val;
+}
+
+static void do_tx_packet(lan9118_state *s)
+{
+    int n;
+    uint32_t status;
+
+    /* FIXME: Honor TX disable, and allow queueing of packets.  */
+    if (s->phy_control & 0x4000)  {
+        /* This assumes the receive routine doesn't touch the VLANClient.  */
+        lan9118_receive(qemu_get_queue(s->nic), s->txp->data, s->txp->len);
+    } else {
+        qemu_send_packet(qemu_get_queue(s->nic), s->txp->data, s->txp->len);
+    }
+    s->txp->fifo_used = 0;
+
+    if (s->tx_status_fifo_used == 512) {
+        /* Status FIFO full */
+        return;
+    }
+    /* Add entry to status FIFO.  */
+    status = s->txp->cmd_b & 0xffff0000u;
+    DPRINTF("Sent packet tag:%04x len %d\n", status >> 16, s->txp->len);
+    n = (s->tx_status_fifo_head + s->tx_status_fifo_used) & 511;
+    s->tx_status_fifo[n] = status;
+    s->tx_status_fifo_used++;
+    if (s->tx_status_fifo_used == 512) {
+        s->int_sts |= TSFF_INT;
+        /* TODO: Stop transmission.  */
+    }
+}
+
+static uint32_t rx_status_fifo_pop(lan9118_state *s)
+{
+    uint32_t val;
+
+    val = s->rx_status_fifo[s->rx_status_fifo_head];
+    if (s->rx_status_fifo_used != 0) {
+        s->rx_status_fifo_used--;
+        s->rx_status_fifo_head++;
+        if (s->rx_status_fifo_head >= s->rx_status_fifo_size) {
+            s->rx_status_fifo_head -= s->rx_status_fifo_size;
+        }
+        /* ??? What value should be returned when the FIFO is empty?  */
+        DPRINTF("RX status pop 0x%08x\n", val);
+    }
+    return val;
+}
+
+static uint32_t tx_status_fifo_pop(lan9118_state *s)
+{
+    uint32_t val;
+
+    val = s->tx_status_fifo[s->tx_status_fifo_head];
+    if (s->tx_status_fifo_used != 0) {
+        s->tx_status_fifo_used--;
+        s->tx_status_fifo_head = (s->tx_status_fifo_head + 1) & 511;
+        /* ??? What value should be returned when the FIFO is empty?  */
+    }
+    return val;
+}
+
+static void tx_fifo_push(lan9118_state *s, uint32_t val)
+{
+    int n;
+
+    if (s->txp->fifo_used == s->tx_fifo_size) {
+        s->int_sts |= TDFO_INT;
+        return;
+    }
+    switch (s->txp->state) {
+    case TX_IDLE:
+        s->txp->cmd_a = val & 0x831f37ff;
+        s->txp->fifo_used++;
+        s->txp->state = TX_B;
+        break;
+    case TX_B:
+        if (s->txp->cmd_a & 0x2000) {
+            /* First segment */
+            s->txp->cmd_b = val;
+            s->txp->fifo_used++;
+            s->txp->buffer_size = s->txp->cmd_a & 0x7ff;
+            s->txp->offset = (s->txp->cmd_a >> 16) & 0x1f;
+            /* End alignment does not include command words.  */
+            n = (s->txp->buffer_size + s->txp->offset + 3) >> 2;
+            switch ((n >> 24) & 3) {
+            case 1:
+                n = (-n) & 3;
+                break;
+            case 2:
+                n = (-n) & 7;
+                break;
+            default:
+                n = 0;
+            }
+            s->txp->pad = n;
+            s->txp->len = 0;
+        }
+        DPRINTF("Block len:%d offset:%d pad:%d cmd %08x\n",
+                s->txp->buffer_size, s->txp->offset, s->txp->pad,
+                s->txp->cmd_a);
+        s->txp->state = TX_DATA;
+        break;
+    case TX_DATA:
+        if (s->txp->offset >= 4) {
+            s->txp->offset -= 4;
+            break;
+        }
+        if (s->txp->buffer_size <= 0 && s->txp->pad != 0) {
+            s->txp->pad--;
+        } else {
+            n = 4;
+            while (s->txp->offset) {
+                val >>= 8;
+                n--;
+                s->txp->offset--;
+            }
+            /* Documentation is somewhat unclear on the ordering of bytes
+               in FIFO words.  Empirical results show it to be little-endian.
+               */
+            /* TODO: FIFO overflow checking.  */
+            while (n--) {
+                s->txp->data[s->txp->len] = val & 0xff;
+                s->txp->len++;
+                val >>= 8;
+                s->txp->buffer_size--;
+            }
+            s->txp->fifo_used++;
+        }
+        if (s->txp->buffer_size <= 0 && s->txp->pad == 0) {
+            if (s->txp->cmd_a & 0x1000) {
+                do_tx_packet(s);
+            }
+            if (s->txp->cmd_a & 0x80000000) {
+                s->int_sts |= TX_IOC_INT;
+            }
+            s->txp->state = TX_IDLE;
+        }
+        break;
+    }
+}
+
+static uint32_t do_phy_read(lan9118_state *s, int reg)
+{
+    uint32_t val;
+
+    switch (reg) {
+    case 0: /* Basic Control */
+        return s->phy_control;
+    case 1: /* Basic Status */
+        return s->phy_status;
+    case 2: /* ID1 */
+        return 0x0007;
+    case 3: /* ID2 */
+        return 0xc0d1;
+    case 4: /* Auto-neg advertisement */
+        return s->phy_advertise;
+    case 5: /* Auto-neg Link Partner Ability */
+        return 0x0f71;
+    case 6: /* Auto-neg Expansion */
+        return 1;
+        /* TODO 17, 18, 27, 29, 30, 31 */
+    case 29: /* Interrupt source.  */
+        val = s->phy_int;
+        s->phy_int = 0;
+        phy_update_irq(s);
+        return val;
+    case 30: /* Interrupt mask */
+        return s->phy_int_mask;
+    default:
+        BADF("PHY read reg %d\n", reg);
+        return 0;
+    }
+}
+
+static void do_phy_write(lan9118_state *s, int reg, uint32_t val)
+{
+    switch (reg) {
+    case 0: /* Basic Control */
+        if (val & 0x8000) {
+            phy_reset(s);
+            break;
+        }
+        s->phy_control = val & 0x7980;
+        /* Complete autonegotiation immediately.  */
+        if (val & 0x1000) {
+            s->phy_status |= 0x0020;
+        }
+        break;
+    case 4: /* Auto-neg advertisement */
+        s->phy_advertise = (val & 0x2d7f) | 0x80;
+        break;
+        /* TODO 17, 18, 27, 31 */
+    case 30: /* Interrupt mask */
+        s->phy_int_mask = val & 0xff;
+        phy_update_irq(s);
+        break;
+    default:
+        BADF("PHY write reg %d = 0x%04x\n", reg, val);
+    }
+}
+
+static void do_mac_write(lan9118_state *s, int reg, uint32_t val)
+{
+    switch (reg) {
+    case MAC_CR:
+        if ((s->mac_cr & MAC_CR_RXEN) != 0 && (val & MAC_CR_RXEN) == 0) {
+            s->int_sts |= RXSTOP_INT;
+        }
+        s->mac_cr = val & ~MAC_CR_RESERVED;
+        DPRINTF("MAC_CR: %08x\n", val);
+        break;
+    case MAC_ADDRH:
+        s->conf.macaddr.a[4] = val & 0xff;
+        s->conf.macaddr.a[5] = (val >> 8) & 0xff;
+        lan9118_mac_changed(s);
+        break;
+    case MAC_ADDRL:
+        s->conf.macaddr.a[0] = val & 0xff;
+        s->conf.macaddr.a[1] = (val >> 8) & 0xff;
+        s->conf.macaddr.a[2] = (val >> 16) & 0xff;
+        s->conf.macaddr.a[3] = (val >> 24) & 0xff;
+        lan9118_mac_changed(s);
+        break;
+    case MAC_HASHH:
+        s->mac_hashh = val;
+        break;
+    case MAC_HASHL:
+        s->mac_hashl = val;
+        break;
+    case MAC_MII_ACC:
+        s->mac_mii_acc = val & 0xffc2;
+        if (val & 2) {
+            DPRINTF("PHY write %d = 0x%04x\n",
+                    (val >> 6) & 0x1f, s->mac_mii_data);
+            do_phy_write(s, (val >> 6) & 0x1f, s->mac_mii_data);
+        } else {
+            s->mac_mii_data = do_phy_read(s, (val >> 6) & 0x1f);
+            DPRINTF("PHY read %d = 0x%04x\n",
+                    (val >> 6) & 0x1f, s->mac_mii_data);
+        }
+        break;
+    case MAC_MII_DATA:
+        s->mac_mii_data = val & 0xffff;
+        break;
+    case MAC_FLOW:
+        s->mac_flow = val & 0xffff0000;
+        break;
+    case MAC_VLAN1:
+        /* Writing to this register changes a condition for
+         * FrameTooLong bit in rx_status.  Since we do not set
+         * FrameTooLong anyway, just ignore write to this.
+         */
+        break;
+    default:
+        hw_error("lan9118: Unimplemented MAC register write: %d = 0x%x\n",
+                 s->mac_cmd & 0xf, val);
+    }
+}
+
+static uint32_t do_mac_read(lan9118_state *s, int reg)
+{
+    switch (reg) {
+    case MAC_CR:
+        return s->mac_cr;
+    case MAC_ADDRH:
+        return s->conf.macaddr.a[4] | (s->conf.macaddr.a[5] << 8);
+    case MAC_ADDRL:
+        return s->conf.macaddr.a[0] | (s->conf.macaddr.a[1] << 8)
+               | (s->conf.macaddr.a[2] << 16) | (s->conf.macaddr.a[3] << 24);
+    case MAC_HASHH:
+        return s->mac_hashh;
+        break;
+    case MAC_HASHL:
+        return s->mac_hashl;
+        break;
+    case MAC_MII_ACC:
+        return s->mac_mii_acc;
+    case MAC_MII_DATA:
+        return s->mac_mii_data;
+    case MAC_FLOW:
+        return s->mac_flow;
+    default:
+        hw_error("lan9118: Unimplemented MAC register read: %d\n",
+                 s->mac_cmd & 0xf);
+    }
+}
+
+static void lan9118_eeprom_cmd(lan9118_state *s, int cmd, int addr)
+{
+    s->e2p_cmd = (s->e2p_cmd & 0x10) | (cmd << 28) | addr;
+    switch (cmd) {
+    case 0:
+        s->e2p_data = s->eeprom[addr];
+        DPRINTF("EEPROM Read %d = 0x%02x\n", addr, s->e2p_data);
+        break;
+    case 1:
+        s->eeprom_writable = 0;
+        DPRINTF("EEPROM Write Disable\n");
+        break;
+    case 2: /* EWEN */
+        s->eeprom_writable = 1;
+        DPRINTF("EEPROM Write Enable\n");
+        break;
+    case 3: /* WRITE */
+        if (s->eeprom_writable) {
+            s->eeprom[addr] &= s->e2p_data;
+            DPRINTF("EEPROM Write %d = 0x%02x\n", addr, s->e2p_data);
+        } else {
+            DPRINTF("EEPROM Write %d (ignored)\n", addr);
+        }
+        break;
+    case 4: /* WRAL */
+        if (s->eeprom_writable) {
+            for (addr = 0; addr < 128; addr++) {
+                s->eeprom[addr] &= s->e2p_data;
+            }
+            DPRINTF("EEPROM Write All 0x%02x\n", s->e2p_data);
+        } else {
+            DPRINTF("EEPROM Write All (ignored)\n");
+        }
+        break;
+    case 5: /* ERASE */
+        if (s->eeprom_writable) {
+            s->eeprom[addr] = 0xff;
+            DPRINTF("EEPROM Erase %d\n", addr);
+        } else {
+            DPRINTF("EEPROM Erase %d (ignored)\n", addr);
+        }
+        break;
+    case 6: /* ERAL */
+        if (s->eeprom_writable) {
+            memset(s->eeprom, 0xff, 128);
+            DPRINTF("EEPROM Erase All\n");
+        } else {
+            DPRINTF("EEPROM Erase All (ignored)\n");
+        }
+        break;
+    case 7: /* RELOAD */
+        lan9118_reload_eeprom(s);
+        break;
+    }
+}
+
+static void lan9118_tick(void *opaque)
+{
+    lan9118_state *s = (lan9118_state *)opaque;
+    if (s->int_en & GPT_INT) {
+        s->int_sts |= GPT_INT;
+    }
+    lan9118_update(s);
+}
+
+static void lan9118_writel(void *opaque, hwaddr offset,
+                           uint64_t val, unsigned size)
+{
+    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 */
+        tx_fifo_push(s, val);
+        return;
+    }
+    switch (offset) {
+    case CSR_IRQ_CFG:
+        /* TODO: Implement interrupt deassertion intervals.  */
+        val &= (IRQ_EN | IRQ_POL | IRQ_TYPE);
+        s->irq_cfg = (s->irq_cfg & IRQ_INT) | val;
+        break;
+    case CSR_INT_STS:
+        s->int_sts &= ~val;
+        break;
+    case CSR_INT_EN:
+        s->int_en = val & ~RESERVED_INT;
+        s->int_sts |= val & SW_INT;
+        break;
+    case CSR_FIFO_INT:
+        DPRINTF("FIFO INT levels %08x\n", val);
+        s->fifo_int = val;
+        break;
+    case CSR_RX_CFG:
+        if (val & 0x8000) {
+            /* RX_DUMP */
+            s->rx_fifo_used = 0;
+            s->rx_status_fifo_used = 0;
+            s->rx_packet_size_tail = s->rx_packet_size_head;
+            s->rx_packet_size[s->rx_packet_size_head] = 0;
+        }
+        s->rx_cfg = val & 0xcfff1ff0;
+        break;
+    case CSR_TX_CFG:
+        if (val & 0x8000) {
+            s->tx_status_fifo_used = 0;
+        }
+        if (val & 0x4000) {
+            s->txp->state = TX_IDLE;
+            s->txp->fifo_used = 0;
+            s->txp->cmd_a = 0xffffffff;
+        }
+        s->tx_cfg = val & 6;
+        break;
+    case CSR_HW_CFG:
+        if (val & 1) {
+            /* SRST */
+            lan9118_reset(&s->busdev.qdev);
+        } else {
+            s->hw_cfg = (val & 0x003f300) | (s->hw_cfg & 0x4);
+        }
+        break;
+    case CSR_RX_DP_CTRL:
+        if (val & 0x80000000) {
+            /* Skip forward to next packet.  */
+            s->rxp_pad = 0;
+            s->rxp_offset = 0;
+            if (s->rxp_size == 0) {
+                /* Pop a word to start the next packet.  */
+                rx_fifo_pop(s);
+                s->rxp_pad = 0;
+                s->rxp_offset = 0;
+            }
+            s->rx_fifo_head += s->rxp_size;
+            if (s->rx_fifo_head >= s->rx_fifo_size) {
+                s->rx_fifo_head -= s->rx_fifo_size;
+            }
+        }
+        break;
+    case CSR_PMT_CTRL:
+        if (val & 0x400) {
+            phy_reset(s);
+        }
+        s->pmt_ctrl &= ~0x34e;
+        s->pmt_ctrl |= (val & 0x34e);
+        break;
+    case CSR_GPIO_CFG:
+        /* Probably just enabling LEDs.  */
+        s->gpio_cfg = val & 0x7777071f;
+        break;
+    case CSR_GPT_CFG:
+        if ((s->gpt_cfg ^ val) & GPT_TIMER_EN) {
+            if (val & GPT_TIMER_EN) {
+                ptimer_set_count(s->timer, val & 0xffff);
+                ptimer_run(s->timer, 0);
+            } else {
+                ptimer_stop(s->timer);
+                ptimer_set_count(s->timer, 0xffff);
+            }
+        }
+        s->gpt_cfg = val & (GPT_TIMER_EN | 0xffff);
+        break;
+    case CSR_WORD_SWAP:
+        /* Ignored because we're in 32-bit mode.  */
+        s->word_swap = val;
+        break;
+    case CSR_MAC_CSR_CMD:
+        s->mac_cmd = val & 0x4000000f;
+        if (val & 0x80000000) {
+            if (val & 0x40000000) {
+                s->mac_data = do_mac_read(s, val & 0xf);
+                DPRINTF("MAC read %d = 0x%08x\n", val & 0xf, s->mac_data);
+            } else {
+                DPRINTF("MAC write %d = 0x%08x\n", val & 0xf, s->mac_data);
+                do_mac_write(s, val & 0xf, s->mac_data);
+            }
+        }
+        break;
+    case CSR_MAC_CSR_DATA:
+        s->mac_data = val;
+        break;
+    case CSR_AFC_CFG:
+        s->afc_cfg = val & 0x00ffffff;
+        break;
+    case CSR_E2P_CMD:
+        lan9118_eeprom_cmd(s, (val >> 28) & 7, val & 0x7f);
+        break;
+    case CSR_E2P_DATA:
+        s->e2p_data = val & 0xff;
+        break;
+
+    default:
+        hw_error("lan9118_write: Bad reg 0x%x = %x\n", (int)offset, (int)val);
+        break;
+    }
+    lan9118_update(s);
+}
+
+static void lan9118_writew(void *opaque, hwaddr 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, hwaddr offset,
+                                     uint64_t val, unsigned size)
+{
+    switch (size) {
+    case 2:
+        lan9118_writew(opaque, offset, (uint32_t)val);
+        return;
+    case 4:
+        lan9118_writel(opaque, offset, val, size);
+        return;
+    }
+
+    hw_error("lan9118_write: Bad size 0x%x\n", size);
+}
+
+static uint64_t lan9118_readl(void *opaque, hwaddr offset,
+                              unsigned size)
+{
+    lan9118_state *s = (lan9118_state *)opaque;
+
+    //DPRINTF("Read reg 0x%02x\n", (int)offset);
+    if (offset < 0x20) {
+        /* RX FIFO */
+        return rx_fifo_pop(s);
+    }
+    switch (offset) {
+    case 0x40:
+        return rx_status_fifo_pop(s);
+    case 0x44:
+        return s->rx_status_fifo[s->tx_status_fifo_head];
+    case 0x48:
+        return tx_status_fifo_pop(s);
+    case 0x4c:
+        return s->tx_status_fifo[s->tx_status_fifo_head];
+    case CSR_ID_REV:
+        return 0x01180001;
+    case CSR_IRQ_CFG:
+        return s->irq_cfg;
+    case CSR_INT_STS:
+        return s->int_sts;
+    case CSR_INT_EN:
+        return s->int_en;
+    case CSR_BYTE_TEST:
+        return 0x87654321;
+    case CSR_FIFO_INT:
+        return s->fifo_int;
+    case CSR_RX_CFG:
+        return s->rx_cfg;
+    case CSR_TX_CFG:
+        return s->tx_cfg;
+    case CSR_HW_CFG:
+        return s->hw_cfg;
+    case CSR_RX_DP_CTRL:
+        return 0;
+    case CSR_RX_FIFO_INF:
+        return (s->rx_status_fifo_used << 16) | (s->rx_fifo_used << 2);
+    case CSR_TX_FIFO_INF:
+        return (s->tx_status_fifo_used << 16)
+               | (s->tx_fifo_size - s->txp->fifo_used);
+    case CSR_PMT_CTRL:
+        return s->pmt_ctrl;
+    case CSR_GPIO_CFG:
+        return s->gpio_cfg;
+    case CSR_GPT_CFG:
+        return s->gpt_cfg;
+    case CSR_GPT_CNT:
+        return ptimer_get_count(s->timer);
+    case CSR_WORD_SWAP:
+        return s->word_swap;
+    case CSR_FREE_RUN:
+        return (qemu_get_clock_ns(vm_clock) / 40) - s->free_timer_start;
+    case CSR_RX_DROP:
+        /* TODO: Implement dropped frames counter.  */
+        return 0;
+    case CSR_MAC_CSR_CMD:
+        return s->mac_cmd;
+    case CSR_MAC_CSR_DATA:
+        return s->mac_data;
+    case CSR_AFC_CFG:
+        return s->afc_cfg;
+    case CSR_E2P_CMD:
+        return s->e2p_cmd;
+    case CSR_E2P_DATA:
+        return s->e2p_data;
+    }
+    hw_error("lan9118_read: Bad reg 0x%x\n", (int)offset);
+    return 0;
+}
+
+static uint32_t lan9118_readw(void *opaque, hwaddr 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, hwaddr 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(NetClientState *nc)
+{
+    lan9118_state *s = qemu_get_nic_opaque(nc);
+
+    s->nic = NULL;
+}
+
+static NetClientInfo net_lan9118_info = {
+    .type = NET_CLIENT_OPTIONS_KIND_NIC,
+    .size = sizeof(NICState),
+    .can_receive = lan9118_can_receive,
+    .receive = lan9118_receive,
+    .cleanup = lan9118_cleanup,
+    .link_status_changed = lan9118_set_link,
+};
+
+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, 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);
+
+    s->nic = qemu_new_nic(&net_lan9118_info, &s->conf,
+                          object_get_typename(OBJECT(dev)), dev->qdev.id, s);
+    qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
+    s->eeprom[0] = 0xa5;
+    for (i = 0; i < 6; i++) {
+        s->eeprom[i + 1] = s->conf.macaddr.a[i];
+    }
+    s->pmt_ctrl = 1;
+    s->txp = &s->tx_packet;
+
+    bh = qemu_bh_new(lan9118_tick, s);
+    s->timer = ptimer_init(bh);
+    ptimer_set_freq(s->timer, 10000);
+    ptimer_set_limit(s->timer, 0xffff, 1);
+
+    return 0;
+}
+
+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(),
+};
+
+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 const TypeInfo lan9118_info = {
+    .name          = "lan9118",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(lan9118_state),
+    .class_init    = lan9118_class_init,
+};
+
+static void lan9118_register_types(void)
+{
+    type_register_static(&lan9118_info);
+}
+
+/* Legacy helper function.  Should go away when machine config files are
+   implemented.  */
+void lan9118_init(NICInfo *nd, uint32_t base, qemu_irq irq)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+
+    qemu_check_nic_model(nd, "lan9118");
+    dev = qdev_create(NULL, "lan9118");
+    qdev_set_nic_properties(dev, nd);
+    qdev_init_nofail(dev);
+    s = SYS_BUS_DEVICE(dev);
+    sysbus_mmio_map(s, 0, base);
+    sysbus_connect_irq(s, 0, irq);
+}
+
+type_init(lan9118_register_types)
diff --git a/hw/net/lance.c b/hw/net/lance.c
new file mode 100644 (file)
index 0000000..187497c
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * QEMU AMD PC-Net II (Am79C970A) emulation
+ *
+ * Copyright (c) 2004 Antony T Curtis
+ *
+ * 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.
+ */
+
+/* This software was written to be compatible with the specification:
+ * AMD Am79C970A PCnet-PCI II Ethernet Controller Data-Sheet
+ * AMD Publication# 19436  Rev:E  Amendment/0  Issue Date: June 2000
+ */
+
+/*
+ * On Sparc32, this is the Lance (Am7990) part of chip STP2000 (Master I/O), also
+ * produced as NCR89C100. See
+ * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C100.txt
+ * and
+ * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR92C990.txt
+ */
+
+#include "hw/sysbus.h"
+#include "net/net.h"
+#include "qemu/timer.h"
+#include "qemu/sockets.h"
+#include "hw/sparc/sun4m.h"
+#include "pcnet.h"
+#include "trace.h"
+
+typedef struct {
+    SysBusDevice busdev;
+    PCNetState state;
+} SysBusPCNetState;
+
+static void parent_lance_reset(void *opaque, int irq, int level)
+{
+    SysBusPCNetState *d = opaque;
+    if (level)
+        pcnet_h_reset(&d->state);
+}
+
+static void lance_mem_write(void *opaque, hwaddr addr,
+                            uint64_t val, unsigned size)
+{
+    SysBusPCNetState *d = opaque;
+
+    trace_lance_mem_writew(addr, val & 0xffff);
+    pcnet_ioport_writew(&d->state, addr, val & 0xffff);
+}
+
+static uint64_t lance_mem_read(void *opaque, hwaddr addr,
+                               unsigned size)
+{
+    SysBusPCNetState *d = opaque;
+    uint32_t val;
+
+    val = pcnet_ioport_readw(&d->state, addr);
+    trace_lance_mem_readw(addr, val & 0xffff);
+    return val & 0xffff;
+}
+
+static const MemoryRegionOps lance_mem_ops = {
+    .read = lance_mem_read,
+    .write = lance_mem_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 2,
+        .max_access_size = 2,
+    },
+};
+
+static void lance_cleanup(NetClientState *nc)
+{
+    PCNetState *d = qemu_get_nic_opaque(nc);
+
+    pcnet_common_cleanup(d);
+}
+
+static NetClientInfo net_lance_info = {
+    .type = NET_CLIENT_OPTIONS_KIND_NIC,
+    .size = sizeof(NICState),
+    .can_receive = pcnet_can_receive,
+    .receive = pcnet_receive,
+    .link_status_changed = pcnet_set_link_status,
+    .cleanup = lance_cleanup,
+};
+
+static const VMStateDescription vmstate_lance = {
+    .name = "pcnet",
+    .version_id = 3,
+    .minimum_version_id = 2,
+    .minimum_version_id_old = 2,
+    .fields      = (VMStateField []) {
+        VMSTATE_STRUCT(state, SysBusPCNetState, 0, vmstate_pcnet, PCNetState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int lance_init(SysBusDevice *dev)
+{
+    SysBusPCNetState *d = FROM_SYSBUS(SysBusPCNetState, dev);
+    PCNetState *s = &d->state;
+
+    memory_region_init_io(&s->mmio, &lance_mem_ops, d, "lance-mmio", 4);
+
+    qdev_init_gpio_in(&dev->qdev, parent_lance_reset, 1);
+
+    sysbus_init_mmio(dev, &s->mmio);
+
+    sysbus_init_irq(dev, &s->irq);
+
+    s->phys_mem_read = ledma_memory_read;
+    s->phys_mem_write = ledma_memory_write;
+    return pcnet_common_init(&dev->qdev, s, &net_lance_info);
+}
+
+static void lance_reset(DeviceState *dev)
+{
+    SysBusPCNetState *d = DO_UPCAST(SysBusPCNetState, busdev.qdev, dev);
+
+    pcnet_h_reset(&d->state);
+}
+
+static Property lance_properties[] = {
+    DEFINE_PROP_PTR("dma", SysBusPCNetState, state.dma_opaque),
+    DEFINE_NIC_PROPERTIES(SysBusPCNetState, state.conf),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void lance_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = lance_init;
+    dc->fw_name = "ethernet";
+    dc->reset = lance_reset;
+    dc->vmsd = &vmstate_lance;
+    dc->props = lance_properties;
+}
+
+static const TypeInfo lance_info = {
+    .name          = "lance",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(SysBusPCNetState),
+    .class_init    = lance_class_init,
+};
+
+static void lance_register_types(void)
+{
+    type_register_static(&lance_info);
+}
+
+type_init(lance_register_types)
diff --git a/hw/net/mcf_fec.c b/hw/net/mcf_fec.c
new file mode 100644 (file)
index 0000000..9b68052
--- /dev/null
@@ -0,0 +1,480 @@
+/*
+ * ColdFire Fast Ethernet Controller emulation.
+ *
+ * Copyright (c) 2007 CodeSourcery.
+ *
+ * This code is licensed under the GPL
+ */
+#include "hw/hw.h"
+#include "net/net.h"
+#include "hw/m68k/mcf.h"
+/* For crc32 */
+#include <zlib.h>
+#include "exec/address-spaces.h"
+
+//#define DEBUG_FEC 1
+
+#ifdef DEBUG_FEC
+#define DPRINTF(fmt, ...) \
+do { printf("mcf_fec: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while(0)
+#endif
+
+#define FEC_MAX_FRAME_SIZE 2032
+
+typedef struct {
+    MemoryRegion *sysmem;
+    MemoryRegion iomem;
+    qemu_irq *irq;
+    NICState *nic;
+    NICConf conf;
+    uint32_t irq_state;
+    uint32_t eir;
+    uint32_t eimr;
+    int rx_enabled;
+    uint32_t rx_descriptor;
+    uint32_t tx_descriptor;
+    uint32_t ecr;
+    uint32_t mmfr;
+    uint32_t mscr;
+    uint32_t rcr;
+    uint32_t tcr;
+    uint32_t tfwr;
+    uint32_t rfsr;
+    uint32_t erdsr;
+    uint32_t etdsr;
+    uint32_t emrbr;
+} mcf_fec_state;
+
+#define FEC_INT_HB   0x80000000
+#define FEC_INT_BABR 0x40000000
+#define FEC_INT_BABT 0x20000000
+#define FEC_INT_GRA  0x10000000
+#define FEC_INT_TXF  0x08000000
+#define FEC_INT_TXB  0x04000000
+#define FEC_INT_RXF  0x02000000
+#define FEC_INT_RXB  0x01000000
+#define FEC_INT_MII  0x00800000
+#define FEC_INT_EB   0x00400000
+#define FEC_INT_LC   0x00200000
+#define FEC_INT_RL   0x00100000
+#define FEC_INT_UN   0x00080000
+
+#define FEC_EN      2
+#define FEC_RESET   1
+
+/* Map interrupt flags onto IRQ lines.  */
+#define FEC_NUM_IRQ 13
+static const uint32_t mcf_fec_irq_map[FEC_NUM_IRQ] = {
+    FEC_INT_TXF,
+    FEC_INT_TXB,
+    FEC_INT_UN,
+    FEC_INT_RL,
+    FEC_INT_RXF,
+    FEC_INT_RXB,
+    FEC_INT_MII,
+    FEC_INT_LC,
+    FEC_INT_HB,
+    FEC_INT_GRA,
+    FEC_INT_EB,
+    FEC_INT_BABT,
+    FEC_INT_BABR
+};
+
+/* Buffer Descriptor.  */
+typedef struct {
+    uint16_t flags;
+    uint16_t length;
+    uint32_t data;
+} mcf_fec_bd;
+
+#define FEC_BD_R    0x8000
+#define FEC_BD_E    0x8000
+#define FEC_BD_O1   0x4000
+#define FEC_BD_W    0x2000
+#define FEC_BD_O2   0x1000
+#define FEC_BD_L    0x0800
+#define FEC_BD_TC   0x0400
+#define FEC_BD_ABC  0x0200
+#define FEC_BD_M    0x0100
+#define FEC_BD_BC   0x0080
+#define FEC_BD_MC   0x0040
+#define FEC_BD_LG   0x0020
+#define FEC_BD_NO   0x0010
+#define FEC_BD_CR   0x0004
+#define FEC_BD_OV   0x0002
+#define FEC_BD_TR   0x0001
+
+static void mcf_fec_read_bd(mcf_fec_bd *bd, uint32_t addr)
+{
+    cpu_physical_memory_read(addr, (uint8_t *)bd, sizeof(*bd));
+    be16_to_cpus(&bd->flags);
+    be16_to_cpus(&bd->length);
+    be32_to_cpus(&bd->data);
+}
+
+static void mcf_fec_write_bd(mcf_fec_bd *bd, uint32_t addr)
+{
+    mcf_fec_bd tmp;
+    tmp.flags = cpu_to_be16(bd->flags);
+    tmp.length = cpu_to_be16(bd->length);
+    tmp.data = cpu_to_be32(bd->data);
+    cpu_physical_memory_write(addr, (uint8_t *)&tmp, sizeof(tmp));
+}
+
+static void mcf_fec_update(mcf_fec_state *s)
+{
+    uint32_t active;
+    uint32_t changed;
+    uint32_t mask;
+    int i;
+
+    active = s->eir & s->eimr;
+    changed = active ^s->irq_state;
+    for (i = 0; i < FEC_NUM_IRQ; i++) {
+        mask = mcf_fec_irq_map[i];
+        if (changed & mask) {
+            DPRINTF("IRQ %d = %d\n", i, (active & mask) != 0);
+            qemu_set_irq(s->irq[i], (active & mask) != 0);
+        }
+    }
+    s->irq_state = active;
+}
+
+static void mcf_fec_do_tx(mcf_fec_state *s)
+{
+    uint32_t addr;
+    mcf_fec_bd bd;
+    int frame_size;
+    int len;
+    uint8_t frame[FEC_MAX_FRAME_SIZE];
+    uint8_t *ptr;
+
+    DPRINTF("do_tx\n");
+    ptr = frame;
+    frame_size = 0;
+    addr = s->tx_descriptor;
+    while (1) {
+        mcf_fec_read_bd(&bd, addr);
+        DPRINTF("tx_bd %x flags %04x len %d data %08x\n",
+                addr, bd.flags, bd.length, bd.data);
+        if ((bd.flags & FEC_BD_R) == 0) {
+            /* Run out of descriptors to transmit.  */
+            break;
+        }
+        len = bd.length;
+        if (frame_size + len > FEC_MAX_FRAME_SIZE) {
+            len = FEC_MAX_FRAME_SIZE - frame_size;
+            s->eir |= FEC_INT_BABT;
+        }
+        cpu_physical_memory_read(bd.data, ptr, len);
+        ptr += len;
+        frame_size += len;
+        if (bd.flags & FEC_BD_L) {
+            /* Last buffer in frame.  */
+            DPRINTF("Sending packet\n");
+            qemu_send_packet(qemu_get_queue(s->nic), frame, len);
+            ptr = frame;
+            frame_size = 0;
+            s->eir |= FEC_INT_TXF;
+        }
+        s->eir |= FEC_INT_TXB;
+        bd.flags &= ~FEC_BD_R;
+        /* Write back the modified descriptor.  */
+        mcf_fec_write_bd(&bd, addr);
+        /* Advance to the next descriptor.  */
+        if ((bd.flags & FEC_BD_W) != 0) {
+            addr = s->etdsr;
+        } else {
+            addr += 8;
+        }
+    }
+    s->tx_descriptor = addr;
+}
+
+static void mcf_fec_enable_rx(mcf_fec_state *s)
+{
+    mcf_fec_bd bd;
+
+    mcf_fec_read_bd(&bd, s->rx_descriptor);
+    s->rx_enabled = ((bd.flags & FEC_BD_E) != 0);
+    if (!s->rx_enabled)
+        DPRINTF("RX buffer full\n");
+}
+
+static void mcf_fec_reset(mcf_fec_state *s)
+{
+    s->eir = 0;
+    s->eimr = 0;
+    s->rx_enabled = 0;
+    s->ecr = 0;
+    s->mscr = 0;
+    s->rcr = 0x05ee0001;
+    s->tcr = 0;
+    s->tfwr = 0;
+    s->rfsr = 0x500;
+}
+
+static uint64_t mcf_fec_read(void *opaque, hwaddr addr,
+                             unsigned size)
+{
+    mcf_fec_state *s = (mcf_fec_state *)opaque;
+    switch (addr & 0x3ff) {
+    case 0x004: return s->eir;
+    case 0x008: return s->eimr;
+    case 0x010: return s->rx_enabled ? (1 << 24) : 0; /* RDAR */
+    case 0x014: return 0; /* TDAR */
+    case 0x024: return s->ecr;
+    case 0x040: return s->mmfr;
+    case 0x044: return s->mscr;
+    case 0x064: return 0; /* MIBC */
+    case 0x084: return s->rcr;
+    case 0x0c4: return s->tcr;
+    case 0x0e4: /* PALR */
+        return (s->conf.macaddr.a[0] << 24) | (s->conf.macaddr.a[1] << 16)
+              | (s->conf.macaddr.a[2] << 8) | s->conf.macaddr.a[3];
+        break;
+    case 0x0e8: /* PAUR */
+        return (s->conf.macaddr.a[4] << 24) | (s->conf.macaddr.a[5] << 16) | 0x8808;
+    case 0x0ec: return 0x10000; /* OPD */
+    case 0x118: return 0;
+    case 0x11c: return 0;
+    case 0x120: return 0;
+    case 0x124: return 0;
+    case 0x144: return s->tfwr;
+    case 0x14c: return 0x600;
+    case 0x150: return s->rfsr;
+    case 0x180: return s->erdsr;
+    case 0x184: return s->etdsr;
+    case 0x188: return s->emrbr;
+    default:
+        hw_error("mcf_fec_read: Bad address 0x%x\n", (int)addr);
+        return 0;
+    }
+}
+
+static void mcf_fec_write(void *opaque, hwaddr addr,
+                          uint64_t value, unsigned size)
+{
+    mcf_fec_state *s = (mcf_fec_state *)opaque;
+    switch (addr & 0x3ff) {
+    case 0x004:
+        s->eir &= ~value;
+        break;
+    case 0x008:
+        s->eimr = value;
+        break;
+    case 0x010: /* RDAR */
+        if ((s->ecr & FEC_EN) && !s->rx_enabled) {
+            DPRINTF("RX enable\n");
+            mcf_fec_enable_rx(s);
+        }
+        break;
+    case 0x014: /* TDAR */
+        if (s->ecr & FEC_EN) {
+            mcf_fec_do_tx(s);
+        }
+        break;
+    case 0x024:
+        s->ecr = value;
+        if (value & FEC_RESET) {
+            DPRINTF("Reset\n");
+            mcf_fec_reset(s);
+        }
+        if ((s->ecr & FEC_EN) == 0) {
+            s->rx_enabled = 0;
+        }
+        break;
+    case 0x040:
+        /* TODO: Implement MII.  */
+        s->mmfr = value;
+        break;
+    case 0x044:
+        s->mscr = value & 0xfe;
+        break;
+    case 0x064:
+        /* TODO: Implement MIB.  */
+        break;
+    case 0x084:
+        s->rcr = value & 0x07ff003f;
+        /* TODO: Implement LOOP mode.  */
+        break;
+    case 0x0c4: /* TCR */
+        /* We transmit immediately, so raise GRA immediately.  */
+        s->tcr = value;
+        if (value & 1)
+            s->eir |= FEC_INT_GRA;
+        break;
+    case 0x0e4: /* PALR */
+        s->conf.macaddr.a[0] = value >> 24;
+        s->conf.macaddr.a[1] = value >> 16;
+        s->conf.macaddr.a[2] = value >> 8;
+        s->conf.macaddr.a[3] = value;
+        break;
+    case 0x0e8: /* PAUR */
+        s->conf.macaddr.a[4] = value >> 24;
+        s->conf.macaddr.a[5] = value >> 16;
+        break;
+    case 0x0ec:
+        /* OPD */
+        break;
+    case 0x118:
+    case 0x11c:
+    case 0x120:
+    case 0x124:
+        /* TODO: implement MAC hash filtering.  */
+        break;
+    case 0x144:
+        s->tfwr = value & 3;
+        break;
+    case 0x14c:
+        /* FRBR writes ignored.  */
+        break;
+    case 0x150:
+        s->rfsr = (value & 0x3fc) | 0x400;
+        break;
+    case 0x180:
+        s->erdsr = value & ~3;
+        s->rx_descriptor = s->erdsr;
+        break;
+    case 0x184:
+        s->etdsr = value & ~3;
+        s->tx_descriptor = s->etdsr;
+        break;
+    case 0x188:
+        s->emrbr = value & 0x7f0;
+        break;
+    default:
+        hw_error("mcf_fec_write Bad address 0x%x\n", (int)addr);
+    }
+    mcf_fec_update(s);
+}
+
+static int mcf_fec_can_receive(NetClientState *nc)
+{
+    mcf_fec_state *s = qemu_get_nic_opaque(nc);
+    return s->rx_enabled;
+}
+
+static ssize_t mcf_fec_receive(NetClientState *nc, const uint8_t *buf, size_t size)
+{
+    mcf_fec_state *s = qemu_get_nic_opaque(nc);
+    mcf_fec_bd bd;
+    uint32_t flags = 0;
+    uint32_t addr;
+    uint32_t crc;
+    uint32_t buf_addr;
+    uint8_t *crc_ptr;
+    unsigned int buf_len;
+
+    DPRINTF("do_rx len %d\n", size);
+    if (!s->rx_enabled) {
+        fprintf(stderr, "mcf_fec_receive: Unexpected packet\n");
+    }
+    /* 4 bytes for the CRC.  */
+    size += 4;
+    crc = cpu_to_be32(crc32(~0, buf, size));
+    crc_ptr = (uint8_t *)&crc;
+    /* Huge frames are truncted.  */
+    if (size > FEC_MAX_FRAME_SIZE) {
+        size = FEC_MAX_FRAME_SIZE;
+        flags |= FEC_BD_TR | FEC_BD_LG;
+    }
+    /* Frames larger than the user limit just set error flags.  */
+    if (size > (s->rcr >> 16)) {
+        flags |= FEC_BD_LG;
+    }
+    addr = s->rx_descriptor;
+    while (size > 0) {
+        mcf_fec_read_bd(&bd, addr);
+        if ((bd.flags & FEC_BD_E) == 0) {
+            /* No descriptors available.  Bail out.  */
+            /* FIXME: This is wrong.  We should probably either save the
+               remainder for when more RX buffers are available, or
+               flag an error.  */
+            fprintf(stderr, "mcf_fec: Lost end of frame\n");
+            break;
+        }
+        buf_len = (size <= s->emrbr) ? size: s->emrbr;
+        bd.length = buf_len;
+        size -= buf_len;
+        DPRINTF("rx_bd %x length %d\n", addr, bd.length);
+        /* The last 4 bytes are the CRC.  */
+        if (size < 4)
+            buf_len += size - 4;
+        buf_addr = bd.data;
+        cpu_physical_memory_write(buf_addr, buf, buf_len);
+        buf += buf_len;
+        if (size < 4) {
+            cpu_physical_memory_write(buf_addr + buf_len, crc_ptr, 4 - size);
+            crc_ptr += 4 - size;
+        }
+        bd.flags &= ~FEC_BD_E;
+        if (size == 0) {
+            /* Last buffer in frame.  */
+            bd.flags |= flags | FEC_BD_L;
+            DPRINTF("rx frame flags %04x\n", bd.flags);
+            s->eir |= FEC_INT_RXF;
+        } else {
+            s->eir |= FEC_INT_RXB;
+        }
+        mcf_fec_write_bd(&bd, addr);
+        /* Advance to the next descriptor.  */
+        if ((bd.flags & FEC_BD_W) != 0) {
+            addr = s->erdsr;
+        } else {
+            addr += 8;
+        }
+    }
+    s->rx_descriptor = addr;
+    mcf_fec_enable_rx(s);
+    mcf_fec_update(s);
+    return size;
+}
+
+static const MemoryRegionOps mcf_fec_ops = {
+    .read = mcf_fec_read,
+    .write = mcf_fec_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void mcf_fec_cleanup(NetClientState *nc)
+{
+    mcf_fec_state *s = qemu_get_nic_opaque(nc);
+
+    memory_region_del_subregion(s->sysmem, &s->iomem);
+    memory_region_destroy(&s->iomem);
+
+    g_free(s);
+}
+
+static NetClientInfo net_mcf_fec_info = {
+    .type = NET_CLIENT_OPTIONS_KIND_NIC,
+    .size = sizeof(NICState),
+    .can_receive = mcf_fec_can_receive,
+    .receive = mcf_fec_receive,
+    .cleanup = mcf_fec_cleanup,
+};
+
+void mcf_fec_init(MemoryRegion *sysmem, NICInfo *nd,
+                  hwaddr base, qemu_irq *irq)
+{
+    mcf_fec_state *s;
+
+    qemu_check_nic_model(nd, "mcf_fec");
+
+    s = (mcf_fec_state *)g_malloc0(sizeof(mcf_fec_state));
+    s->sysmem = sysmem;
+    s->irq = irq;
+
+    memory_region_init_io(&s->iomem, &mcf_fec_ops, s, "fec", 0x400);
+    memory_region_add_subregion(sysmem, base, &s->iomem);
+
+    s->conf.macaddr = nd->macaddr;
+    s->conf.peers.ncs[0] = nd->netdev;
+
+    s->nic = qemu_new_nic(&net_mcf_fec_info, &s->conf, nd->model, nd->name, s);
+
+    qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
+}
diff --git a/hw/net/milkymist-minimac2.c b/hw/net/milkymist-minimac2.c
new file mode 100644 (file)
index 0000000..29618e8
--- /dev/null
@@ -0,0 +1,547 @@
+/*
+ *  QEMU model of the Milkymist minimac2 block.
+ *
+ *  Copyright (c) 2011 Michael Walle <michael@walle.cc>
+ *
+ * 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/>.
+ *
+ *
+ * Specification available at:
+ *   not available yet
+ *
+ */
+
+#include "hw/hw.h"
+#include "hw/sysbus.h"
+#include "trace.h"
+#include "net/net.h"
+#include "qemu/error-report.h"
+#include "hw/qdev-addr.h"
+
+#include <zlib.h>
+
+enum {
+    R_SETUP = 0,
+    R_MDIO,
+    R_STATE0,
+    R_COUNT0,
+    R_STATE1,
+    R_COUNT1,
+    R_TXCOUNT,
+    R_MAX
+};
+
+enum {
+    SETUP_PHY_RST = (1<<0),
+};
+
+enum {
+    MDIO_DO  = (1<<0),
+    MDIO_DI  = (1<<1),
+    MDIO_OE  = (1<<2),
+    MDIO_CLK = (1<<3),
+};
+
+enum {
+    STATE_EMPTY   = 0,
+    STATE_LOADED  = 1,
+    STATE_PENDING = 2,
+};
+
+enum {
+    MDIO_OP_WRITE = 1,
+    MDIO_OP_READ  = 2,
+};
+
+enum mdio_state {
+    MDIO_STATE_IDLE,
+    MDIO_STATE_READING,
+    MDIO_STATE_WRITING,
+};
+
+enum {
+    R_PHY_ID1  = 2,
+    R_PHY_ID2  = 3,
+    R_PHY_MAX  = 32
+};
+
+#define MINIMAC2_MTU 1530
+#define MINIMAC2_BUFFER_SIZE 2048
+
+struct MilkymistMinimac2MdioState {
+    int last_clk;
+    int count;
+    uint32_t data;
+    uint16_t data_out;
+    int state;
+
+    uint8_t phy_addr;
+    uint8_t reg_addr;
+};
+typedef struct MilkymistMinimac2MdioState MilkymistMinimac2MdioState;
+
+struct MilkymistMinimac2State {
+    SysBusDevice busdev;
+    NICState *nic;
+    NICConf conf;
+    char *phy_model;
+    MemoryRegion buffers;
+    MemoryRegion regs_region;
+
+    qemu_irq rx_irq;
+    qemu_irq tx_irq;
+
+    uint32_t regs[R_MAX];
+
+    MilkymistMinimac2MdioState mdio;
+
+    uint16_t phy_regs[R_PHY_MAX];
+
+    uint8_t *rx0_buf;
+    uint8_t *rx1_buf;
+    uint8_t *tx_buf;
+};
+typedef struct MilkymistMinimac2State MilkymistMinimac2State;
+
+static const uint8_t preamble_sfd[] = {
+        0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5
+};
+
+static void minimac2_mdio_write_reg(MilkymistMinimac2State *s,
+        uint8_t phy_addr, uint8_t reg_addr, uint16_t value)
+{
+    trace_milkymist_minimac2_mdio_write(phy_addr, reg_addr, value);
+
+    /* nop */
+}
+
+static uint16_t minimac2_mdio_read_reg(MilkymistMinimac2State *s,
+        uint8_t phy_addr, uint8_t reg_addr)
+{
+    uint16_t r = s->phy_regs[reg_addr];
+
+    trace_milkymist_minimac2_mdio_read(phy_addr, reg_addr, r);
+
+    return r;
+}
+
+static void minimac2_update_mdio(MilkymistMinimac2State *s)
+{
+    MilkymistMinimac2MdioState *m = &s->mdio;
+
+    /* detect rising clk edge */
+    if (m->last_clk == 0 && (s->regs[R_MDIO] & MDIO_CLK)) {
+        /* shift data in */
+        int bit = ((s->regs[R_MDIO] & MDIO_DO)
+                   && (s->regs[R_MDIO] & MDIO_OE)) ? 1 : 0;
+        m->data = (m->data << 1) | bit;
+
+        /* check for sync */
+        if (m->data == 0xffffffff) {
+            m->count = 32;
+        }
+
+        if (m->count == 16) {
+            uint8_t start = (m->data >> 14) & 0x3;
+            uint8_t op = (m->data >> 12) & 0x3;
+            uint8_t ta = (m->data) & 0x3;
+
+            if (start == 1 && op == MDIO_OP_WRITE && ta == 2) {
+                m->state = MDIO_STATE_WRITING;
+            } else if (start == 1 && op == MDIO_OP_READ && (ta & 1) == 0) {
+                m->state = MDIO_STATE_READING;
+            } else {
+                m->state = MDIO_STATE_IDLE;
+            }
+
+            if (m->state != MDIO_STATE_IDLE) {
+                m->phy_addr = (m->data >> 7) & 0x1f;
+                m->reg_addr = (m->data >> 2) & 0x1f;
+            }
+
+            if (m->state == MDIO_STATE_READING) {
+                m->data_out = minimac2_mdio_read_reg(s, m->phy_addr,
+                        m->reg_addr);
+            }
+        }
+
+        if (m->count < 16 && m->state == MDIO_STATE_READING) {
+            int bit = (m->data_out & 0x8000) ? 1 : 0;
+            m->data_out <<= 1;
+
+            if (bit) {
+                s->regs[R_MDIO] |= MDIO_DI;
+            } else {
+                s->regs[R_MDIO] &= ~MDIO_DI;
+            }
+        }
+
+        if (m->count == 0 && m->state) {
+            if (m->state == MDIO_STATE_WRITING) {
+                uint16_t data = m->data & 0xffff;
+                minimac2_mdio_write_reg(s, m->phy_addr, m->reg_addr, data);
+            }
+            m->state = MDIO_STATE_IDLE;
+        }
+        m->count--;
+    }
+
+    m->last_clk = (s->regs[R_MDIO] & MDIO_CLK) ? 1 : 0;
+}
+
+static size_t assemble_frame(uint8_t *buf, size_t size,
+        const uint8_t *payload, size_t payload_size)
+{
+    uint32_t crc;
+
+    if (size < payload_size + 12) {
+        error_report("milkymist_minimac2: received too big ethernet frame");
+        return 0;
+    }
+
+    /* prepend preamble and sfd */
+    memcpy(buf, preamble_sfd, 8);
+
+    /* now copy the payload */
+    memcpy(buf + 8, payload, payload_size);
+
+    /* pad frame if needed */
+    if (payload_size < 60) {
+        memset(buf + payload_size + 8, 0, 60 - payload_size);
+        payload_size = 60;
+    }
+
+    /* append fcs */
+    crc = cpu_to_le32(crc32(0, buf + 8, payload_size));
+    memcpy(buf + payload_size + 8, &crc, 4);
+
+    return payload_size + 12;
+}
+
+static void minimac2_tx(MilkymistMinimac2State *s)
+{
+    uint32_t txcount = s->regs[R_TXCOUNT];
+    uint8_t *buf = s->tx_buf;
+
+    if (txcount < 64) {
+        error_report("milkymist_minimac2: ethernet frame too small (%u < %u)",
+                txcount, 64);
+        goto err;
+    }
+
+    if (txcount > MINIMAC2_MTU) {
+        error_report("milkymist_minimac2: MTU exceeded (%u > %u)",
+                txcount, MINIMAC2_MTU);
+        goto err;
+    }
+
+    if (memcmp(buf, preamble_sfd, 8) != 0) {
+        error_report("milkymist_minimac2: frame doesn't contain the preamble "
+                "and/or the SFD (%02x %02x %02x %02x %02x %02x %02x %02x)",
+                buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
+        goto err;
+    }
+
+    trace_milkymist_minimac2_tx_frame(txcount - 12);
+
+    /* send packet, skipping preamble and sfd */
+    qemu_send_packet_raw(qemu_get_queue(s->nic), buf + 8, txcount - 12);
+
+    s->regs[R_TXCOUNT] = 0;
+
+err:
+    trace_milkymist_minimac2_pulse_irq_tx();
+    qemu_irq_pulse(s->tx_irq);
+}
+
+static void update_rx_interrupt(MilkymistMinimac2State *s)
+{
+    if (s->regs[R_STATE0] == STATE_PENDING
+            || s->regs[R_STATE1] == STATE_PENDING) {
+        trace_milkymist_minimac2_raise_irq_rx();
+        qemu_irq_raise(s->rx_irq);
+    } else {
+        trace_milkymist_minimac2_lower_irq_rx();
+        qemu_irq_lower(s->rx_irq);
+    }
+}
+
+static ssize_t minimac2_rx(NetClientState *nc, const uint8_t *buf, size_t size)
+{
+    MilkymistMinimac2State *s = qemu_get_nic_opaque(nc);
+
+    uint32_t r_count;
+    uint32_t r_state;
+    uint8_t *rx_buf;
+
+    size_t frame_size;
+
+    trace_milkymist_minimac2_rx_frame(buf, size);
+
+    /* choose appropriate slot */
+    if (s->regs[R_STATE0] == STATE_LOADED) {
+        r_count = R_COUNT0;
+        r_state = R_STATE0;
+        rx_buf = s->rx0_buf;
+    } else if (s->regs[R_STATE1] == STATE_LOADED) {
+        r_count = R_COUNT1;
+        r_state = R_STATE1;
+        rx_buf = s->rx1_buf;
+    } else {
+        trace_milkymist_minimac2_drop_rx_frame(buf);
+        return size;
+    }
+
+    /* assemble frame */
+    frame_size = assemble_frame(rx_buf, MINIMAC2_BUFFER_SIZE, buf, size);
+
+    if (frame_size == 0) {
+        return size;
+    }
+
+    trace_milkymist_minimac2_rx_transfer(rx_buf, frame_size);
+
+    /* update slot */
+    s->regs[r_count] = frame_size;
+    s->regs[r_state] = STATE_PENDING;
+
+    update_rx_interrupt(s);
+
+    return size;
+}
+
+static uint64_t
+minimac2_read(void *opaque, hwaddr addr, unsigned size)
+{
+    MilkymistMinimac2State *s = opaque;
+    uint32_t r = 0;
+
+    addr >>= 2;
+    switch (addr) {
+    case R_SETUP:
+    case R_MDIO:
+    case R_STATE0:
+    case R_COUNT0:
+    case R_STATE1:
+    case R_COUNT1:
+    case R_TXCOUNT:
+        r = s->regs[addr];
+        break;
+
+    default:
+        error_report("milkymist_minimac2: read access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+
+    trace_milkymist_minimac2_memory_read(addr << 2, r);
+
+    return r;
+}
+
+static void
+minimac2_write(void *opaque, hwaddr addr, uint64_t value,
+               unsigned size)
+{
+    MilkymistMinimac2State *s = opaque;
+
+    trace_milkymist_minimac2_memory_read(addr, value);
+
+    addr >>= 2;
+    switch (addr) {
+    case R_MDIO:
+    {
+        /* MDIO_DI is read only */
+        int mdio_di = (s->regs[R_MDIO] & MDIO_DI);
+        s->regs[R_MDIO] = value;
+        if (mdio_di) {
+            s->regs[R_MDIO] |= mdio_di;
+        } else {
+            s->regs[R_MDIO] &= ~mdio_di;
+        }
+
+        minimac2_update_mdio(s);
+    } break;
+    case R_TXCOUNT:
+        s->regs[addr] = value;
+        if (value > 0) {
+            minimac2_tx(s);
+        }
+        break;
+    case R_STATE0:
+    case R_STATE1:
+        s->regs[addr] = value;
+        update_rx_interrupt(s);
+        break;
+    case R_SETUP:
+    case R_COUNT0:
+    case R_COUNT1:
+        s->regs[addr] = value;
+        break;
+
+    default:
+        error_report("milkymist_minimac2: write access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+}
+
+static const MemoryRegionOps minimac2_ops = {
+    .read = minimac2_read,
+    .write = minimac2_write,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int minimac2_can_rx(NetClientState *nc)
+{
+    MilkymistMinimac2State *s = qemu_get_nic_opaque(nc);
+
+    if (s->regs[R_STATE0] == STATE_LOADED) {
+        return 1;
+    }
+    if (s->regs[R_STATE1] == STATE_LOADED) {
+        return 1;
+    }
+
+    return 0;
+}
+
+static void minimac2_cleanup(NetClientState *nc)
+{
+    MilkymistMinimac2State *s = qemu_get_nic_opaque(nc);
+
+    s->nic = NULL;
+}
+
+static void milkymist_minimac2_reset(DeviceState *d)
+{
+    MilkymistMinimac2State *s =
+            container_of(d, MilkymistMinimac2State, busdev.qdev);
+    int i;
+
+    for (i = 0; i < R_MAX; i++) {
+        s->regs[i] = 0;
+    }
+    for (i = 0; i < R_PHY_MAX; i++) {
+        s->phy_regs[i] = 0;
+    }
+
+    /* defaults */
+    s->phy_regs[R_PHY_ID1] = 0x0022; /* Micrel KSZ8001L */
+    s->phy_regs[R_PHY_ID2] = 0x161a;
+}
+
+static NetClientInfo net_milkymist_minimac2_info = {
+    .type = NET_CLIENT_OPTIONS_KIND_NIC,
+    .size = sizeof(NICState),
+    .can_receive = minimac2_can_rx,
+    .receive = minimac2_rx,
+    .cleanup = minimac2_cleanup,
+};
+
+static int milkymist_minimac2_init(SysBusDevice *dev)
+{
+    MilkymistMinimac2State *s = FROM_SYSBUS(typeof(*s), dev);
+    size_t buffers_size = TARGET_PAGE_ALIGN(3 * MINIMAC2_BUFFER_SIZE);
+
+    sysbus_init_irq(dev, &s->rx_irq);
+    sysbus_init_irq(dev, &s->tx_irq);
+
+    memory_region_init_io(&s->regs_region, &minimac2_ops, s,
+                          "milkymist-minimac2", R_MAX * 4);
+    sysbus_init_mmio(dev, &s->regs_region);
+
+    /* register buffers memory */
+    memory_region_init_ram(&s->buffers, "milkymist-minimac2.buffers",
+                           buffers_size);
+    vmstate_register_ram_global(&s->buffers);
+    s->rx0_buf = memory_region_get_ram_ptr(&s->buffers);
+    s->rx1_buf = s->rx0_buf + MINIMAC2_BUFFER_SIZE;
+    s->tx_buf = s->rx1_buf + MINIMAC2_BUFFER_SIZE;
+
+    sysbus_init_mmio(dev, &s->buffers);
+
+    qemu_macaddr_default_if_unset(&s->conf.macaddr);
+    s->nic = qemu_new_nic(&net_milkymist_minimac2_info, &s->conf,
+                          object_get_typename(OBJECT(dev)), dev->qdev.id, s);
+    qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_milkymist_minimac2_mdio = {
+    .name = "milkymist-minimac2-mdio",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_INT32(last_clk, MilkymistMinimac2MdioState),
+        VMSTATE_INT32(count, MilkymistMinimac2MdioState),
+        VMSTATE_UINT32(data, MilkymistMinimac2MdioState),
+        VMSTATE_UINT16(data_out, MilkymistMinimac2MdioState),
+        VMSTATE_INT32(state, MilkymistMinimac2MdioState),
+        VMSTATE_UINT8(phy_addr, MilkymistMinimac2MdioState),
+        VMSTATE_UINT8(reg_addr, MilkymistMinimac2MdioState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_milkymist_minimac2 = {
+    .name = "milkymist-minimac2",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(regs, MilkymistMinimac2State, R_MAX),
+        VMSTATE_UINT16_ARRAY(phy_regs, MilkymistMinimac2State, R_PHY_MAX),
+        VMSTATE_STRUCT(mdio, MilkymistMinimac2State, 0,
+                vmstate_milkymist_minimac2_mdio, MilkymistMinimac2MdioState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static Property milkymist_minimac2_properties[] = {
+    DEFINE_NIC_PROPERTIES(MilkymistMinimac2State, conf),
+    DEFINE_PROP_STRING("phy_model", MilkymistMinimac2State, phy_model),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void milkymist_minimac2_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = milkymist_minimac2_init;
+    dc->reset = milkymist_minimac2_reset;
+    dc->vmsd = &vmstate_milkymist_minimac2;
+    dc->props = milkymist_minimac2_properties;
+}
+
+static const 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_types(void)
+{
+    type_register_static(&milkymist_minimac2_info);
+}
+
+type_init(milkymist_minimac2_register_types)
diff --git a/hw/net/mipsnet.c b/hw/net/mipsnet.c
new file mode 100644 (file)
index 0000000..ac6193a
--- /dev/null
@@ -0,0 +1,284 @@
+#include "hw/hw.h"
+#include "net/net.h"
+#include "trace.h"
+#include "hw/sysbus.h"
+
+/* MIPSnet register offsets */
+
+#define MIPSNET_DEV_ID         0x00
+#define MIPSNET_BUSY           0x08
+#define MIPSNET_RX_DATA_COUNT  0x0c
+#define MIPSNET_TX_DATA_COUNT  0x10
+#define MIPSNET_INT_CTL                0x14
+# define MIPSNET_INTCTL_TXDONE         0x00000001
+# define MIPSNET_INTCTL_RXDONE         0x00000002
+# define MIPSNET_INTCTL_TESTBIT                0x80000000
+#define MIPSNET_INTERRUPT_INFO 0x18
+#define MIPSNET_RX_DATA_BUFFER 0x1c
+#define MIPSNET_TX_DATA_BUFFER 0x20
+
+#define MAX_ETH_FRAME_SIZE     1514
+
+typedef struct MIPSnetState {
+    SysBusDevice busdev;
+
+    uint32_t busy;
+    uint32_t rx_count;
+    uint32_t rx_read;
+    uint32_t tx_count;
+    uint32_t tx_written;
+    uint32_t intctl;
+    uint8_t rx_buffer[MAX_ETH_FRAME_SIZE];
+    uint8_t tx_buffer[MAX_ETH_FRAME_SIZE];
+    MemoryRegion io;
+    qemu_irq irq;
+    NICState *nic;
+    NICConf conf;
+} MIPSnetState;
+
+static void mipsnet_reset(MIPSnetState *s)
+{
+    s->busy = 1;
+    s->rx_count = 0;
+    s->rx_read = 0;
+    s->tx_count = 0;
+    s->tx_written = 0;
+    s->intctl = 0;
+    memset(s->rx_buffer, 0, MAX_ETH_FRAME_SIZE);
+    memset(s->tx_buffer, 0, MAX_ETH_FRAME_SIZE);
+}
+
+static void mipsnet_update_irq(MIPSnetState *s)
+{
+    int isr = !!s->intctl;
+    trace_mipsnet_irq(isr, s->intctl);
+    qemu_set_irq(s->irq, isr);
+}
+
+static int mipsnet_buffer_full(MIPSnetState *s)
+{
+    if (s->rx_count >= MAX_ETH_FRAME_SIZE)
+        return 1;
+    return 0;
+}
+
+static int mipsnet_can_receive(NetClientState *nc)
+{
+    MIPSnetState *s = qemu_get_nic_opaque(nc);
+
+    if (s->busy)
+        return 0;
+    return !mipsnet_buffer_full(s);
+}
+
+static ssize_t mipsnet_receive(NetClientState *nc, const uint8_t *buf, size_t size)
+{
+    MIPSnetState *s = qemu_get_nic_opaque(nc);
+
+    trace_mipsnet_receive(size);
+    if (!mipsnet_can_receive(nc))
+        return -1;
+
+    s->busy = 1;
+
+    /* Just accept everything. */
+
+    /* Write packet data. */
+    memcpy(s->rx_buffer, buf, size);
+
+    s->rx_count = size;
+    s->rx_read = 0;
+
+    /* Now we can signal we have received something. */
+    s->intctl |= MIPSNET_INTCTL_RXDONE;
+    mipsnet_update_irq(s);
+
+    return size;
+}
+
+static uint64_t mipsnet_ioport_read(void *opaque, hwaddr addr,
+                                    unsigned int size)
+{
+    MIPSnetState *s = opaque;
+    int ret = 0;
+
+    addr &= 0x3f;
+    switch (addr) {
+    case MIPSNET_DEV_ID:
+       ret = be32_to_cpu(0x4d495053);          /* MIPS */
+        break;
+    case MIPSNET_DEV_ID + 4:
+       ret = be32_to_cpu(0x4e455430);          /* NET0 */
+        break;
+    case MIPSNET_BUSY:
+       ret = s->busy;
+        break;
+    case MIPSNET_RX_DATA_COUNT:
+       ret = s->rx_count;
+        break;
+    case MIPSNET_TX_DATA_COUNT:
+       ret = s->tx_count;
+        break;
+    case MIPSNET_INT_CTL:
+       ret = s->intctl;
+        s->intctl &= ~MIPSNET_INTCTL_TESTBIT;
+        break;
+    case MIPSNET_INTERRUPT_INFO:
+        /* XXX: This seems to be a per-VPE interrupt number. */
+       ret = 0;
+        break;
+    case MIPSNET_RX_DATA_BUFFER:
+        if (s->rx_count) {
+            s->rx_count--;
+            ret = s->rx_buffer[s->rx_read++];
+        }
+        break;
+    /* Reads as zero. */
+    case MIPSNET_TX_DATA_BUFFER:
+    default:
+        break;
+    }
+    trace_mipsnet_read(addr, ret);
+    return ret;
+}
+
+static void mipsnet_ioport_write(void *opaque, hwaddr addr,
+                                 uint64_t val, unsigned int size)
+{
+    MIPSnetState *s = opaque;
+
+    addr &= 0x3f;
+    trace_mipsnet_write(addr, val);
+    switch (addr) {
+    case MIPSNET_TX_DATA_COUNT:
+       s->tx_count = (val <= MAX_ETH_FRAME_SIZE) ? val : 0;
+        s->tx_written = 0;
+        break;
+    case MIPSNET_INT_CTL:
+        if (val & MIPSNET_INTCTL_TXDONE) {
+            s->intctl &= ~MIPSNET_INTCTL_TXDONE;
+        } else if (val & MIPSNET_INTCTL_RXDONE) {
+            s->intctl &= ~MIPSNET_INTCTL_RXDONE;
+        } else if (val & MIPSNET_INTCTL_TESTBIT) {
+            mipsnet_reset(s);
+            s->intctl |= MIPSNET_INTCTL_TESTBIT;
+        } else if (!val) {
+            /* ACK testbit interrupt, flag was cleared on read. */
+        }
+        s->busy = !!s->intctl;
+        mipsnet_update_irq(s);
+        break;
+    case MIPSNET_TX_DATA_BUFFER:
+        s->tx_buffer[s->tx_written++] = val;
+        if (s->tx_written == s->tx_count) {
+            /* Send buffer. */
+            trace_mipsnet_send(s->tx_count);
+            qemu_send_packet(qemu_get_queue(s->nic), s->tx_buffer, s->tx_count);
+            s->tx_count = s->tx_written = 0;
+            s->intctl |= MIPSNET_INTCTL_TXDONE;
+            s->busy = 1;
+            mipsnet_update_irq(s);
+        }
+        break;
+    /* Read-only registers */
+    case MIPSNET_DEV_ID:
+    case MIPSNET_BUSY:
+    case MIPSNET_RX_DATA_COUNT:
+    case MIPSNET_INTERRUPT_INFO:
+    case MIPSNET_RX_DATA_BUFFER:
+    default:
+        break;
+    }
+}
+
+static const VMStateDescription vmstate_mipsnet = {
+    .name = "mipsnet",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32(busy, MIPSnetState),
+        VMSTATE_UINT32(rx_count, MIPSnetState),
+        VMSTATE_UINT32(rx_read, MIPSnetState),
+        VMSTATE_UINT32(tx_count, MIPSnetState),
+        VMSTATE_UINT32(tx_written, MIPSnetState),
+        VMSTATE_UINT32(intctl, MIPSnetState),
+        VMSTATE_BUFFER(rx_buffer, MIPSnetState),
+        VMSTATE_BUFFER(tx_buffer, MIPSnetState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void mipsnet_cleanup(NetClientState *nc)
+{
+    MIPSnetState *s = qemu_get_nic_opaque(nc);
+
+    s->nic = NULL;
+}
+
+static NetClientInfo net_mipsnet_info = {
+    .type = NET_CLIENT_OPTIONS_KIND_NIC,
+    .size = sizeof(NICState),
+    .can_receive = mipsnet_can_receive,
+    .receive = mipsnet_receive,
+    .cleanup = mipsnet_cleanup,
+};
+
+static const MemoryRegionOps mipsnet_ioport_ops = {
+    .read = mipsnet_ioport_read,
+    .write = mipsnet_ioport_write,
+    .impl.min_access_size = 1,
+    .impl.max_access_size = 4,
+};
+
+static int mipsnet_sysbus_init(SysBusDevice *dev)
+{
+    MIPSnetState *s = DO_UPCAST(MIPSnetState, busdev, dev);
+
+    memory_region_init_io(&s->io, &mipsnet_ioport_ops, s, "mipsnet-io", 36);
+    sysbus_init_mmio(dev, &s->io);
+    sysbus_init_irq(dev, &s->irq);
+
+    s->nic = qemu_new_nic(&net_mipsnet_info, &s->conf,
+                          object_get_typename(OBJECT(dev)), dev->qdev.id, s);
+    qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
+
+    return 0;
+}
+
+static void mipsnet_sysbus_reset(DeviceState *dev)
+{
+    MIPSnetState *s = DO_UPCAST(MIPSnetState, busdev.qdev, dev);
+    mipsnet_reset(s);
+}
+
+static Property mipsnet_properties[] = {
+    DEFINE_NIC_PROPERTIES(MIPSnetState, conf),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void mipsnet_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = mipsnet_sysbus_init;
+    dc->desc = "MIPS Simulator network device";
+    dc->reset = mipsnet_sysbus_reset;
+    dc->vmsd = &vmstate_mipsnet;
+    dc->props = mipsnet_properties;
+}
+
+static const TypeInfo mipsnet_info = {
+    .name          = "mipsnet",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(MIPSnetState),
+    .class_init    = mipsnet_class_init,
+};
+
+static void mipsnet_register_types(void)
+{
+    type_register_static(&mipsnet_info);
+}
+
+type_init(mipsnet_register_types)
diff --git a/hw/net/ne2000-isa.c b/hw/net/ne2000-isa.c
new file mode 100644 (file)
index 0000000..a093aa8
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * QEMU NE2000 emulation -- isa bus windup
+ *
+ * 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.
+ */
+#include "hw/hw.h"
+#include "hw/i386/pc.h"
+#include "hw/isa/isa.h"
+#include "hw/qdev.h"
+#include "net/net.h"
+#include "ne2000.h"
+#include "exec/address-spaces.h"
+
+typedef struct ISANE2000State {
+    ISADevice dev;
+    uint32_t iobase;
+    uint32_t isairq;
+    NE2000State ne2000;
+} ISANE2000State;
+
+static void isa_ne2000_cleanup(NetClientState *nc)
+{
+    NE2000State *s = qemu_get_nic_opaque(nc);
+
+    s->nic = NULL;
+}
+
+static NetClientInfo net_ne2000_isa_info = {
+    .type = NET_CLIENT_OPTIONS_KIND_NIC,
+    .size = sizeof(NICState),
+    .can_receive = ne2000_can_receive,
+    .receive = ne2000_receive,
+    .cleanup = isa_ne2000_cleanup,
+};
+
+static const VMStateDescription vmstate_isa_ne2000 = {
+    .name = "ne2000",
+    .version_id = 2,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields      = (VMStateField []) {
+        VMSTATE_STRUCT(ne2000, ISANE2000State, 0, vmstate_ne2000, NE2000State),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int isa_ne2000_initfn(ISADevice *dev)
+{
+    ISANE2000State *isa = DO_UPCAST(ISANE2000State, dev, dev);
+    NE2000State *s = &isa->ne2000;
+
+    ne2000_setup_io(s, 0x20);
+    isa_register_ioport(dev, &s->io, isa->iobase);
+
+    isa_init_irq(dev, &s->irq, isa->isairq);
+
+    qemu_macaddr_default_if_unset(&s->c.macaddr);
+    ne2000_reset(s);
+
+    s->nic = qemu_new_nic(&net_ne2000_isa_info, &s->c,
+                          object_get_typename(OBJECT(dev)), dev->qdev.id, s);
+    qemu_format_nic_info_str(qemu_get_queue(s->nic), s->c.macaddr.a);
+
+    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 const 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_types(void)
+{
+    type_register_static(&ne2000_isa_info);
+}
+
+type_init(ne2000_isa_register_types)
diff --git a/hw/net/ne2000.c b/hw/net/ne2000.c
new file mode 100644 (file)
index 0000000..33ee03e
--- /dev/null
@@ -0,0 +1,789 @@
+/*
+ * QEMU NE2000 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.
+ */
+#include "hw/hw.h"
+#include "hw/pci/pci.h"
+#include "net/net.h"
+#include "ne2000.h"
+#include "hw/loader.h"
+#include "sysemu/sysemu.h"
+
+/* debug NE2000 card */
+//#define DEBUG_NE2000
+
+#define MAX_ETH_FRAME_SIZE 1514
+
+#define E8390_CMD      0x00  /* The command register (for all pages) */
+/* Page 0 register offsets. */
+#define EN0_CLDALO     0x01    /* Low byte of current local dma addr  RD */
+#define EN0_STARTPG    0x01    /* Starting page of ring bfr WR */
+#define EN0_CLDAHI     0x02    /* High byte of current local dma addr  RD */
+#define EN0_STOPPG     0x02    /* Ending page +1 of ring bfr WR */
+#define EN0_BOUNDARY   0x03    /* Boundary page of ring bfr RD WR */
+#define EN0_TSR                0x04    /* Transmit status reg RD */
+#define EN0_TPSR       0x04    /* Transmit starting page WR */
+#define EN0_NCR                0x05    /* Number of collision reg RD */
+#define EN0_TCNTLO     0x05    /* Low  byte of tx byte count WR */
+#define EN0_FIFO       0x06    /* FIFO RD */
+#define EN0_TCNTHI     0x06    /* High byte of tx byte count WR */
+#define EN0_ISR                0x07    /* Interrupt status reg RD WR */
+#define EN0_CRDALO     0x08    /* low byte of current remote dma address RD */
+#define EN0_RSARLO     0x08    /* Remote start address reg 0 */
+#define EN0_CRDAHI     0x09    /* high byte, current remote dma address RD */
+#define EN0_RSARHI     0x09    /* Remote start address reg 1 */
+#define EN0_RCNTLO     0x0a    /* Remote byte count reg WR */
+#define EN0_RTL8029ID0 0x0a    /* Realtek ID byte #1 RD */
+#define EN0_RCNTHI     0x0b    /* Remote byte count reg WR */
+#define EN0_RTL8029ID1 0x0b    /* Realtek ID byte #2 RD */
+#define EN0_RSR                0x0c    /* rx status reg RD */
+#define EN0_RXCR       0x0c    /* RX configuration reg WR */
+#define EN0_TXCR       0x0d    /* TX configuration reg WR */
+#define EN0_COUNTER0   0x0d    /* Rcv alignment error counter RD */
+#define EN0_DCFG       0x0e    /* Data configuration reg WR */
+#define EN0_COUNTER1   0x0e    /* Rcv CRC error counter RD */
+#define EN0_IMR                0x0f    /* Interrupt mask reg WR */
+#define EN0_COUNTER2   0x0f    /* Rcv missed frame error counter RD */
+
+#define EN1_PHYS        0x11
+#define EN1_CURPAG      0x17
+#define EN1_MULT        0x18
+
+#define EN2_STARTPG    0x21    /* Starting page of ring bfr RD */
+#define EN2_STOPPG     0x22    /* Ending page +1 of ring bfr RD */
+
+#define EN3_CONFIG0    0x33
+#define EN3_CONFIG1    0x34
+#define EN3_CONFIG2    0x35
+#define EN3_CONFIG3    0x36
+
+/*  Register accessed at EN_CMD, the 8390 base addr.  */
+#define E8390_STOP     0x01    /* Stop and reset the chip */
+#define E8390_START    0x02    /* Start the chip, clear reset */
+#define E8390_TRANS    0x04    /* Transmit a frame */
+#define E8390_RREAD    0x08    /* Remote read */
+#define E8390_RWRITE   0x10    /* Remote write  */
+#define E8390_NODMA    0x20    /* Remote DMA */
+#define E8390_PAGE0    0x00    /* Select page chip registers */
+#define E8390_PAGE1    0x40    /* using the two high-order bits */
+#define E8390_PAGE2    0x80    /* Page 3 is invalid. */
+
+/* Bits in EN0_ISR - Interrupt status register */
+#define ENISR_RX       0x01    /* Receiver, no error */
+#define ENISR_TX       0x02    /* Transmitter, no error */
+#define ENISR_RX_ERR   0x04    /* Receiver, with error */
+#define ENISR_TX_ERR   0x08    /* Transmitter, with error */
+#define ENISR_OVER     0x10    /* Receiver overwrote the ring */
+#define ENISR_COUNTERS 0x20    /* Counters need emptying */
+#define ENISR_RDC      0x40    /* remote dma complete */
+#define ENISR_RESET    0x80    /* Reset completed */
+#define ENISR_ALL      0x3f    /* Interrupts we will enable */
+
+/* Bits in received packet status byte and EN0_RSR*/
+#define ENRSR_RXOK     0x01    /* Received a good packet */
+#define ENRSR_CRC      0x02    /* CRC error */
+#define ENRSR_FAE      0x04    /* frame alignment error */
+#define ENRSR_FO       0x08    /* FIFO overrun */
+#define ENRSR_MPA      0x10    /* missed pkt */
+#define ENRSR_PHY      0x20    /* physical/multicast address */
+#define ENRSR_DIS      0x40    /* receiver disable. set in monitor mode */
+#define ENRSR_DEF      0x80    /* deferring */
+
+/* Transmitted packet status, EN0_TSR. */
+#define ENTSR_PTX 0x01 /* Packet transmitted without error */
+#define ENTSR_ND  0x02 /* The transmit wasn't deferred. */
+#define ENTSR_COL 0x04 /* The transmit collided at least once. */
+#define ENTSR_ABT 0x08  /* The transmit collided 16 times, and was deferred. */
+#define ENTSR_CRS 0x10 /* The carrier sense was lost. */
+#define ENTSR_FU  0x20  /* A "FIFO underrun" occurred during transmit. */
+#define ENTSR_CDH 0x40 /* The collision detect "heartbeat" signal was lost. */
+#define ENTSR_OWC 0x80  /* There was an out-of-window collision. */
+
+typedef struct PCINE2000State {
+    PCIDevice dev;
+    NE2000State ne2000;
+} PCINE2000State;
+
+void ne2000_reset(NE2000State *s)
+{
+    int i;
+
+    s->isr = ENISR_RESET;
+    memcpy(s->mem, &s->c.macaddr, 6);
+    s->mem[14] = 0x57;
+    s->mem[15] = 0x57;
+
+    /* duplicate prom data */
+    for(i = 15;i >= 0; i--) {
+        s->mem[2 * i] = s->mem[i];
+        s->mem[2 * i + 1] = s->mem[i];
+    }
+}
+
+static void ne2000_update_irq(NE2000State *s)
+{
+    int isr;
+    isr = (s->isr & s->imr) & 0x7f;
+#if defined(DEBUG_NE2000)
+    printf("NE2000: Set IRQ to %d (%02x %02x)\n",
+          isr ? 1 : 0, s->isr, s->imr);
+#endif
+    qemu_set_irq(s->irq, (isr != 0));
+}
+
+static int ne2000_buffer_full(NE2000State *s)
+{
+    int avail, index, boundary;
+
+    index = s->curpag << 8;
+    boundary = s->boundary << 8;
+    if (index < boundary)
+        avail = boundary - index;
+    else
+        avail = (s->stop - s->start) - (index - boundary);
+    if (avail < (MAX_ETH_FRAME_SIZE + 4))
+        return 1;
+    return 0;
+}
+
+int ne2000_can_receive(NetClientState *nc)
+{
+    NE2000State *s = qemu_get_nic_opaque(nc);
+
+    if (s->cmd & E8390_STOP)
+        return 1;
+    return !ne2000_buffer_full(s);
+}
+
+#define MIN_BUF_SIZE 60
+
+ssize_t ne2000_receive(NetClientState *nc, const uint8_t *buf, size_t size_)
+{
+    NE2000State *s = qemu_get_nic_opaque(nc);
+    int size = size_;
+    uint8_t *p;
+    unsigned int total_len, next, avail, len, index, mcast_idx;
+    uint8_t buf1[60];
+    static const uint8_t broadcast_macaddr[6] =
+        { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+#if defined(DEBUG_NE2000)
+    printf("NE2000: received len=%d\n", size);
+#endif
+
+    if (s->cmd & E8390_STOP || ne2000_buffer_full(s))
+        return -1;
+
+    /* XXX: check this */
+    if (s->rxcr & 0x10) {
+        /* promiscuous: receive all */
+    } else {
+        if (!memcmp(buf,  broadcast_macaddr, 6)) {
+            /* broadcast address */
+            if (!(s->rxcr & 0x04))
+                return size;
+        } else if (buf[0] & 0x01) {
+            /* multicast */
+            if (!(s->rxcr & 0x08))
+                return size;
+            mcast_idx = compute_mcast_idx(buf);
+            if (!(s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7))))
+                return size;
+        } else if (s->mem[0] == buf[0] &&
+                   s->mem[2] == buf[1] &&
+                   s->mem[4] == buf[2] &&
+                   s->mem[6] == buf[3] &&
+                   s->mem[8] == buf[4] &&
+                   s->mem[10] == buf[5]) {
+            /* match */
+        } else {
+            return size;
+        }
+    }
+
+
+    /* if too small buffer, then expand it */
+    if (size < MIN_BUF_SIZE) {
+        memcpy(buf1, buf, size);
+        memset(buf1 + size, 0, MIN_BUF_SIZE - size);
+        buf = buf1;
+        size = MIN_BUF_SIZE;
+    }
+
+    index = s->curpag << 8;
+    /* 4 bytes for header */
+    total_len = size + 4;
+    /* address for next packet (4 bytes for CRC) */
+    next = index + ((total_len + 4 + 255) & ~0xff);
+    if (next >= s->stop)
+        next -= (s->stop - s->start);
+    /* prepare packet header */
+    p = s->mem + index;
+    s->rsr = ENRSR_RXOK; /* receive status */
+    /* XXX: check this */
+    if (buf[0] & 0x01)
+        s->rsr |= ENRSR_PHY;
+    p[0] = s->rsr;
+    p[1] = next >> 8;
+    p[2] = total_len;
+    p[3] = total_len >> 8;
+    index += 4;
+
+    /* write packet data */
+    while (size > 0) {
+        if (index <= s->stop)
+            avail = s->stop - index;
+        else
+            avail = 0;
+        len = size;
+        if (len > avail)
+            len = avail;
+        memcpy(s->mem + index, buf, len);
+        buf += len;
+        index += len;
+        if (index == s->stop)
+            index = s->start;
+        size -= len;
+    }
+    s->curpag = next >> 8;
+
+    /* now we can signal we have received something */
+    s->isr |= ENISR_RX;
+    ne2000_update_irq(s);
+
+    return size_;
+}
+
+static void ne2000_ioport_write(void *opaque, uint32_t addr, uint32_t val)
+{
+    NE2000State *s = opaque;
+    int offset, page, index;
+
+    addr &= 0xf;
+#ifdef DEBUG_NE2000
+    printf("NE2000: write addr=0x%x val=0x%02x\n", addr, val);
+#endif
+    if (addr == E8390_CMD) {
+        /* control register */
+        s->cmd = val;
+        if (!(val & E8390_STOP)) { /* START bit makes no sense on RTL8029... */
+            s->isr &= ~ENISR_RESET;
+            /* test specific case: zero length transfer */
+            if ((val & (E8390_RREAD | E8390_RWRITE)) &&
+                s->rcnt == 0) {
+                s->isr |= ENISR_RDC;
+                ne2000_update_irq(s);
+            }
+            if (val & E8390_TRANS) {
+                index = (s->tpsr << 8);
+                /* XXX: next 2 lines are a hack to make netware 3.11 work */
+                if (index >= NE2000_PMEM_END)
+                    index -= NE2000_PMEM_SIZE;
+                /* fail safe: check range on the transmitted length  */
+                if (index + s->tcnt <= NE2000_PMEM_END) {
+                    qemu_send_packet(qemu_get_queue(s->nic), s->mem + index,
+                                     s->tcnt);
+                }
+                /* signal end of transfer */
+                s->tsr = ENTSR_PTX;
+                s->isr |= ENISR_TX;
+                s->cmd &= ~E8390_TRANS;
+                ne2000_update_irq(s);
+            }
+        }
+    } else {
+        page = s->cmd >> 6;
+        offset = addr | (page << 4);
+        switch(offset) {
+        case EN0_STARTPG:
+            s->start = val << 8;
+            break;
+        case EN0_STOPPG:
+            s->stop = val << 8;
+            break;
+        case EN0_BOUNDARY:
+            s->boundary = val;
+            break;
+        case EN0_IMR:
+            s->imr = val;
+            ne2000_update_irq(s);
+            break;
+        case EN0_TPSR:
+            s->tpsr = val;
+            break;
+        case EN0_TCNTLO:
+            s->tcnt = (s->tcnt & 0xff00) | val;
+            break;
+        case EN0_TCNTHI:
+            s->tcnt = (s->tcnt & 0x00ff) | (val << 8);
+            break;
+        case EN0_RSARLO:
+            s->rsar = (s->rsar & 0xff00) | val;
+            break;
+        case EN0_RSARHI:
+            s->rsar = (s->rsar & 0x00ff) | (val << 8);
+            break;
+        case EN0_RCNTLO:
+            s->rcnt = (s->rcnt & 0xff00) | val;
+            break;
+        case EN0_RCNTHI:
+            s->rcnt = (s->rcnt & 0x00ff) | (val << 8);
+            break;
+        case EN0_RXCR:
+            s->rxcr = val;
+            break;
+        case EN0_DCFG:
+            s->dcfg = val;
+            break;
+        case EN0_ISR:
+            s->isr &= ~(val & 0x7f);
+            ne2000_update_irq(s);
+            break;
+        case EN1_PHYS ... EN1_PHYS + 5:
+            s->phys[offset - EN1_PHYS] = val;
+            break;
+        case EN1_CURPAG:
+            s->curpag = val;
+            break;
+        case EN1_MULT ... EN1_MULT + 7:
+            s->mult[offset - EN1_MULT] = val;
+            break;
+        }
+    }
+}
+
+static uint32_t ne2000_ioport_read(void *opaque, uint32_t addr)
+{
+    NE2000State *s = opaque;
+    int offset, page, ret;
+
+    addr &= 0xf;
+    if (addr == E8390_CMD) {
+        ret = s->cmd;
+    } else {
+        page = s->cmd >> 6;
+        offset = addr | (page << 4);
+        switch(offset) {
+        case EN0_TSR:
+            ret = s->tsr;
+            break;
+        case EN0_BOUNDARY:
+            ret = s->boundary;
+            break;
+        case EN0_ISR:
+            ret = s->isr;
+            break;
+       case EN0_RSARLO:
+           ret = s->rsar & 0x00ff;
+           break;
+       case EN0_RSARHI:
+           ret = s->rsar >> 8;
+           break;
+        case EN1_PHYS ... EN1_PHYS + 5:
+            ret = s->phys[offset - EN1_PHYS];
+            break;
+        case EN1_CURPAG:
+            ret = s->curpag;
+            break;
+        case EN1_MULT ... EN1_MULT + 7:
+            ret = s->mult[offset - EN1_MULT];
+            break;
+        case EN0_RSR:
+            ret = s->rsr;
+            break;
+        case EN2_STARTPG:
+            ret = s->start >> 8;
+            break;
+        case EN2_STOPPG:
+            ret = s->stop >> 8;
+            break;
+       case EN0_RTL8029ID0:
+           ret = 0x50;
+           break;
+       case EN0_RTL8029ID1:
+           ret = 0x43;
+           break;
+       case EN3_CONFIG0:
+           ret = 0;            /* 10baseT media */
+           break;
+       case EN3_CONFIG2:
+           ret = 0x40;         /* 10baseT active */
+           break;
+       case EN3_CONFIG3:
+           ret = 0x40;         /* Full duplex */
+           break;
+        default:
+            ret = 0x00;
+            break;
+        }
+    }
+#ifdef DEBUG_NE2000
+    printf("NE2000: read addr=0x%x val=%02x\n", addr, ret);
+#endif
+    return ret;
+}
+
+static inline void ne2000_mem_writeb(NE2000State *s, uint32_t addr,
+                                     uint32_t val)
+{
+    if (addr < 32 ||
+        (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) {
+        s->mem[addr] = val;
+    }
+}
+
+static inline void ne2000_mem_writew(NE2000State *s, uint32_t addr,
+                                     uint32_t val)
+{
+    addr &= ~1; /* XXX: check exact behaviour if not even */
+    if (addr < 32 ||
+        (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) {
+        *(uint16_t *)(s->mem + addr) = cpu_to_le16(val);
+    }
+}
+
+static inline void ne2000_mem_writel(NE2000State *s, uint32_t addr,
+                                     uint32_t val)
+{
+    addr &= ~1; /* XXX: check exact behaviour if not even */
+    if (addr < 32 ||
+        (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) {
+        cpu_to_le32wu((uint32_t *)(s->mem + addr), val);
+    }
+}
+
+static inline uint32_t ne2000_mem_readb(NE2000State *s, uint32_t addr)
+{
+    if (addr < 32 ||
+        (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) {
+        return s->mem[addr];
+    } else {
+        return 0xff;
+    }
+}
+
+static inline uint32_t ne2000_mem_readw(NE2000State *s, uint32_t addr)
+{
+    addr &= ~1; /* XXX: check exact behaviour if not even */
+    if (addr < 32 ||
+        (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) {
+        return le16_to_cpu(*(uint16_t *)(s->mem + addr));
+    } else {
+        return 0xffff;
+    }
+}
+
+static inline uint32_t ne2000_mem_readl(NE2000State *s, uint32_t addr)
+{
+    addr &= ~1; /* XXX: check exact behaviour if not even */
+    if (addr < 32 ||
+        (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) {
+        return le32_to_cpupu((uint32_t *)(s->mem + addr));
+    } else {
+        return 0xffffffff;
+    }
+}
+
+static inline void ne2000_dma_update(NE2000State *s, int len)
+{
+    s->rsar += len;
+    /* wrap */
+    /* XXX: check what to do if rsar > stop */
+    if (s->rsar == s->stop)
+        s->rsar = s->start;
+
+    if (s->rcnt <= len) {
+        s->rcnt = 0;
+        /* signal end of transfer */
+        s->isr |= ENISR_RDC;
+        ne2000_update_irq(s);
+    } else {
+        s->rcnt -= len;
+    }
+}
+
+static void ne2000_asic_ioport_write(void *opaque, uint32_t addr, uint32_t val)
+{
+    NE2000State *s = opaque;
+
+#ifdef DEBUG_NE2000
+    printf("NE2000: asic write val=0x%04x\n", val);
+#endif
+    if (s->rcnt == 0)
+        return;
+    if (s->dcfg & 0x01) {
+        /* 16 bit access */
+        ne2000_mem_writew(s, s->rsar, val);
+        ne2000_dma_update(s, 2);
+    } else {
+        /* 8 bit access */
+        ne2000_mem_writeb(s, s->rsar, val);
+        ne2000_dma_update(s, 1);
+    }
+}
+
+static uint32_t ne2000_asic_ioport_read(void *opaque, uint32_t addr)
+{
+    NE2000State *s = opaque;
+    int ret;
+
+    if (s->dcfg & 0x01) {
+        /* 16 bit access */
+        ret = ne2000_mem_readw(s, s->rsar);
+        ne2000_dma_update(s, 2);
+    } else {
+        /* 8 bit access */
+        ret = ne2000_mem_readb(s, s->rsar);
+        ne2000_dma_update(s, 1);
+    }
+#ifdef DEBUG_NE2000
+    printf("NE2000: asic read val=0x%04x\n", ret);
+#endif
+    return ret;
+}
+
+static void ne2000_asic_ioport_writel(void *opaque, uint32_t addr, uint32_t val)
+{
+    NE2000State *s = opaque;
+
+#ifdef DEBUG_NE2000
+    printf("NE2000: asic writel val=0x%04x\n", val);
+#endif
+    if (s->rcnt == 0)
+        return;
+    /* 32 bit access */
+    ne2000_mem_writel(s, s->rsar, val);
+    ne2000_dma_update(s, 4);
+}
+
+static uint32_t ne2000_asic_ioport_readl(void *opaque, uint32_t addr)
+{
+    NE2000State *s = opaque;
+    int ret;
+
+    /* 32 bit access */
+    ret = ne2000_mem_readl(s, s->rsar);
+    ne2000_dma_update(s, 4);
+#ifdef DEBUG_NE2000
+    printf("NE2000: asic readl val=0x%04x\n", ret);
+#endif
+    return ret;
+}
+
+static void ne2000_reset_ioport_write(void *opaque, uint32_t addr, uint32_t val)
+{
+    /* nothing to do (end of reset pulse) */
+}
+
+static uint32_t ne2000_reset_ioport_read(void *opaque, uint32_t addr)
+{
+    NE2000State *s = opaque;
+    ne2000_reset(s);
+    return 0;
+}
+
+static int ne2000_post_load(void* opaque, int version_id)
+{
+    NE2000State* s = opaque;
+
+    if (version_id < 2) {
+        s->rxcr = 0x0c;
+    }
+    return 0;
+}
+
+const VMStateDescription vmstate_ne2000 = {
+    .name = "ne2000",
+    .version_id = 2,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .post_load = ne2000_post_load,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT8_V(rxcr, NE2000State, 2),
+        VMSTATE_UINT8(cmd, NE2000State),
+        VMSTATE_UINT32(start, NE2000State),
+        VMSTATE_UINT32(stop, NE2000State),
+        VMSTATE_UINT8(boundary, NE2000State),
+        VMSTATE_UINT8(tsr, NE2000State),
+        VMSTATE_UINT8(tpsr, NE2000State),
+        VMSTATE_UINT16(tcnt, NE2000State),
+        VMSTATE_UINT16(rcnt, NE2000State),
+        VMSTATE_UINT32(rsar, NE2000State),
+        VMSTATE_UINT8(rsr, NE2000State),
+        VMSTATE_UINT8(isr, NE2000State),
+        VMSTATE_UINT8(dcfg, NE2000State),
+        VMSTATE_UINT8(imr, NE2000State),
+        VMSTATE_BUFFER(phys, NE2000State),
+        VMSTATE_UINT8(curpag, NE2000State),
+        VMSTATE_BUFFER(mult, NE2000State),
+        VMSTATE_UNUSED(4), /* was irq */
+        VMSTATE_BUFFER(mem, NE2000State),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_pci_ne2000 = {
+    .name = "ne2000",
+    .version_id = 3,
+    .minimum_version_id = 3,
+    .minimum_version_id_old = 3,
+    .fields      = (VMStateField []) {
+        VMSTATE_PCI_DEVICE(dev, PCINE2000State),
+        VMSTATE_STRUCT(ne2000, PCINE2000State, 0, vmstate_ne2000, NE2000State),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static uint64_t ne2000_read(void *opaque, hwaddr addr,
+                            unsigned size)
+{
+    NE2000State *s = opaque;
+
+    if (addr < 0x10 && size == 1) {
+        return ne2000_ioport_read(s, addr);
+    } else if (addr == 0x10) {
+        if (size <= 2) {
+            return ne2000_asic_ioport_read(s, addr);
+        } else {
+            return ne2000_asic_ioport_readl(s, addr);
+        }
+    } else if (addr == 0x1f && size == 1) {
+        return ne2000_reset_ioport_read(s, addr);
+    }
+    return ((uint64_t)1 << (size * 8)) - 1;
+}
+
+static void ne2000_write(void *opaque, hwaddr addr,
+                         uint64_t data, unsigned size)
+{
+    NE2000State *s = opaque;
+
+    if (addr < 0x10 && size == 1) {
+        ne2000_ioport_write(s, addr, data);
+    } else if (addr == 0x10) {
+        if (size <= 2) {
+            ne2000_asic_ioport_write(s, addr, data);
+        } else {
+            ne2000_asic_ioport_writel(s, addr, data);
+        }
+    } else if (addr == 0x1f && size == 1) {
+        ne2000_reset_ioport_write(s, addr, data);
+    }
+}
+
+static const MemoryRegionOps ne2000_ops = {
+    .read = ne2000_read,
+    .write = ne2000_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+/***********************************************************/
+/* PCI NE2000 definitions */
+
+void ne2000_setup_io(NE2000State *s, unsigned size)
+{
+    memory_region_init_io(&s->io, &ne2000_ops, s, "ne2000", size);
+}
+
+static void ne2000_cleanup(NetClientState *nc)
+{
+    NE2000State *s = qemu_get_nic_opaque(nc);
+
+    s->nic = NULL;
+}
+
+static NetClientInfo net_ne2000_info = {
+    .type = NET_CLIENT_OPTIONS_KIND_NIC,
+    .size = sizeof(NICState),
+    .can_receive = ne2000_can_receive,
+    .receive = ne2000_receive,
+    .cleanup = ne2000_cleanup,
+};
+
+static int pci_ne2000_init(PCIDevice *pci_dev)
+{
+    PCINE2000State *d = DO_UPCAST(PCINE2000State, dev, pci_dev);
+    NE2000State *s;
+    uint8_t *pci_conf;
+
+    pci_conf = d->dev.config;
+    pci_conf[PCI_INTERRUPT_PIN] = 1; /* interrupt pin A */
+
+    s = &d->ne2000;
+    ne2000_setup_io(s, 0x100);
+    pci_register_bar(&d->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io);
+    s->irq = d->dev.irq[0];
+
+    qemu_macaddr_default_if_unset(&s->c.macaddr);
+    ne2000_reset(s);
+
+    s->nic = qemu_new_nic(&net_ne2000_info, &s->c,
+                          object_get_typename(OBJECT(pci_dev)), pci_dev->qdev.id, s);
+    qemu_format_nic_info_str(qemu_get_queue(s->nic), s->c.macaddr.a);
+
+    add_boot_device_path(s->c.bootindex, &pci_dev->qdev, "/ethernet-phy@0");
+
+    return 0;
+}
+
+static void pci_ne2000_exit(PCIDevice *pci_dev)
+{
+    PCINE2000State *d = DO_UPCAST(PCINE2000State, dev, pci_dev);
+    NE2000State *s = &d->ne2000;
+
+    memory_region_destroy(&s->io);
+    qemu_del_nic(s->nic);
+}
+
+static Property ne2000_properties[] = {
+    DEFINE_NIC_PROPERTIES(PCINE2000State, ne2000.c),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void ne2000_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = pci_ne2000_init;
+    k->exit = pci_ne2000_exit;
+    k->romfile = "efi-ne2k_pci.rom",
+    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 const TypeInfo ne2000_info = {
+    .name          = "ne2k_pci",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PCINE2000State),
+    .class_init    = ne2000_class_init,
+};
+
+static void ne2000_register_types(void)
+{
+    type_register_static(&ne2000_info);
+}
+
+type_init(ne2000_register_types)
diff --git a/hw/net/ne2000.h b/hw/net/ne2000.h
new file mode 100644 (file)
index 0000000..b31ae03
--- /dev/null
@@ -0,0 +1,40 @@
+#ifndef HW_NE2000_H
+#define HW_NE2000_H 1
+
+#define NE2000_PMEM_SIZE    (32*1024)
+#define NE2000_PMEM_START   (16*1024)
+#define NE2000_PMEM_END     (NE2000_PMEM_SIZE+NE2000_PMEM_START)
+#define NE2000_MEM_SIZE     NE2000_PMEM_END
+
+typedef struct NE2000State {
+    MemoryRegion io;
+    uint8_t cmd;
+    uint32_t start;
+    uint32_t stop;
+    uint8_t boundary;
+    uint8_t tsr;
+    uint8_t tpsr;
+    uint16_t tcnt;
+    uint16_t rcnt;
+    uint32_t rsar;
+    uint8_t rsr;
+    uint8_t rxcr;
+    uint8_t isr;
+    uint8_t dcfg;
+    uint8_t imr;
+    uint8_t phys[6]; /* mac address */
+    uint8_t curpag;
+    uint8_t mult[8]; /* multicast mask array */
+    qemu_irq irq;
+    NICState *nic;
+    NICConf c;
+    uint8_t mem[NE2000_MEM_SIZE];
+} NE2000State;
+
+void ne2000_setup_io(NE2000State *s, unsigned size);
+extern const VMStateDescription vmstate_ne2000;
+void ne2000_reset(NE2000State *s);
+int ne2000_can_receive(NetClientState *nc);
+ssize_t ne2000_receive(NetClientState *nc, const uint8_t *buf, size_t size_);
+
+#endif
diff --git a/hw/net/opencores_eth.c b/hw/net/opencores_eth.c
new file mode 100644 (file)
index 0000000..be64bf2
--- /dev/null
@@ -0,0 +1,733 @@
+/*
+ * OpenCores Ethernet MAC 10/100 + subset of
+ * National Semiconductors DP83848C 10/100 PHY
+ *
+ * http://opencores.org/svnget,ethmac?file=%2Ftrunk%2F%2Fdoc%2Feth_speci.pdf
+ * http://cache.national.com/ds/DP/DP83848C.pdf
+ *
+ * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the Open Source and Linux Lab nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "hw/hw.h"
+#include "hw/sysbus.h"
+#include "net/net.h"
+#include "sysemu/sysemu.h"
+#include "trace.h"
+
+/* RECSMALL is not used because it breaks tap networking in linux:
+ * incoming ARP responses are too short
+ */
+#undef USE_RECSMALL
+
+#define GET_FIELD(v, field) (((v) & (field)) >> (field ## _LBN))
+#define GET_REGBIT(s, reg, field) ((s)->regs[reg] & (reg ## _ ## field))
+#define GET_REGFIELD(s, reg, field) \
+    GET_FIELD((s)->regs[reg], reg ## _ ## field)
+
+#define SET_FIELD(v, field, data) \
+    ((v) = (((v) & ~(field)) | (((data) << (field ## _LBN)) & (field))))
+#define SET_REGFIELD(s, reg, field, data) \
+    SET_FIELD((s)->regs[reg], reg ## _ ## field, data)
+
+/* PHY MII registers */
+enum {
+    MII_BMCR,
+    MII_BMSR,
+    MII_PHYIDR1,
+    MII_PHYIDR2,
+    MII_ANAR,
+    MII_ANLPAR,
+    MII_REG_MAX = 16,
+};
+
+typedef struct Mii {
+    uint16_t regs[MII_REG_MAX];
+    bool link_ok;
+} Mii;
+
+static void mii_set_link(Mii *s, bool link_ok)
+{
+    if (link_ok) {
+        s->regs[MII_BMSR] |= 0x4;
+        s->regs[MII_ANLPAR] |= 0x01e1;
+    } else {
+        s->regs[MII_BMSR] &= ~0x4;
+        s->regs[MII_ANLPAR] &= 0x01ff;
+    }
+    s->link_ok = link_ok;
+}
+
+static void mii_reset(Mii *s)
+{
+    memset(s->regs, 0, sizeof(s->regs));
+    s->regs[MII_BMCR] = 0x1000;
+    s->regs[MII_BMSR] = 0x7848; /* no ext regs */
+    s->regs[MII_PHYIDR1] = 0x2000;
+    s->regs[MII_PHYIDR2] = 0x5c90;
+    s->regs[MII_ANAR] = 0x01e1;
+    mii_set_link(s, s->link_ok);
+}
+
+static void mii_ro(Mii *s, uint16_t v)
+{
+}
+
+static void mii_write_bmcr(Mii *s, uint16_t v)
+{
+    if (v & 0x8000) {
+        mii_reset(s);
+    } else {
+        s->regs[MII_BMCR] = v;
+    }
+}
+
+static void mii_write_host(Mii *s, unsigned idx, uint16_t v)
+{
+    static void (*reg_write[MII_REG_MAX])(Mii *s, uint16_t v) = {
+        [MII_BMCR] = mii_write_bmcr,
+        [MII_BMSR] = mii_ro,
+        [MII_PHYIDR1] = mii_ro,
+        [MII_PHYIDR2] = mii_ro,
+    };
+
+    if (idx < MII_REG_MAX) {
+        trace_open_eth_mii_write(idx, v);
+        if (reg_write[idx]) {
+            reg_write[idx](s, v);
+        } else {
+            s->regs[idx] = v;
+        }
+    }
+}
+
+static uint16_t mii_read_host(Mii *s, unsigned idx)
+{
+    trace_open_eth_mii_read(idx, s->regs[idx]);
+    return s->regs[idx];
+}
+
+/* OpenCores Ethernet registers */
+enum {
+    MODER,
+    INT_SOURCE,
+    INT_MASK,
+    IPGT,
+    IPGR1,
+    IPGR2,
+    PACKETLEN,
+    COLLCONF,
+    TX_BD_NUM,
+    CTRLMODER,
+    MIIMODER,
+    MIICOMMAND,
+    MIIADDRESS,
+    MIITX_DATA,
+    MIIRX_DATA,
+    MIISTATUS,
+    MAC_ADDR0,
+    MAC_ADDR1,
+    HASH0,
+    HASH1,
+    TXCTRL,
+    REG_MAX,
+};
+
+enum {
+    MODER_RECSMALL = 0x10000,
+    MODER_PAD = 0x8000,
+    MODER_HUGEN = 0x4000,
+    MODER_RST = 0x800,
+    MODER_LOOPBCK = 0x80,
+    MODER_PRO = 0x20,
+    MODER_IAM = 0x10,
+    MODER_BRO = 0x8,
+    MODER_TXEN = 0x2,
+    MODER_RXEN = 0x1,
+};
+
+enum {
+    INT_SOURCE_RXB = 0x4,
+    INT_SOURCE_TXB = 0x1,
+};
+
+enum {
+    PACKETLEN_MINFL = 0xffff0000,
+    PACKETLEN_MINFL_LBN = 16,
+    PACKETLEN_MAXFL = 0xffff,
+    PACKETLEN_MAXFL_LBN = 0,
+};
+
+enum {
+    MIICOMMAND_WCTRLDATA = 0x4,
+    MIICOMMAND_RSTAT = 0x2,
+    MIICOMMAND_SCANSTAT = 0x1,
+};
+
+enum {
+    MIIADDRESS_RGAD = 0x1f00,
+    MIIADDRESS_RGAD_LBN = 8,
+    MIIADDRESS_FIAD = 0x1f,
+    MIIADDRESS_FIAD_LBN = 0,
+};
+
+enum {
+    MIITX_DATA_CTRLDATA = 0xffff,
+    MIITX_DATA_CTRLDATA_LBN = 0,
+};
+
+enum {
+    MIIRX_DATA_PRSD = 0xffff,
+    MIIRX_DATA_PRSD_LBN = 0,
+};
+
+enum {
+    MIISTATUS_LINKFAIL = 0x1,
+    MIISTATUS_LINKFAIL_LBN = 0,
+};
+
+enum {
+    MAC_ADDR0_BYTE2 = 0xff000000,
+    MAC_ADDR0_BYTE2_LBN = 24,
+    MAC_ADDR0_BYTE3 = 0xff0000,
+    MAC_ADDR0_BYTE3_LBN = 16,
+    MAC_ADDR0_BYTE4 = 0xff00,
+    MAC_ADDR0_BYTE4_LBN = 8,
+    MAC_ADDR0_BYTE5 = 0xff,
+    MAC_ADDR0_BYTE5_LBN = 0,
+};
+
+enum {
+    MAC_ADDR1_BYTE0 = 0xff00,
+    MAC_ADDR1_BYTE0_LBN = 8,
+    MAC_ADDR1_BYTE1 = 0xff,
+    MAC_ADDR1_BYTE1_LBN = 0,
+};
+
+enum {
+    TXD_LEN = 0xffff0000,
+    TXD_LEN_LBN = 16,
+    TXD_RD = 0x8000,
+    TXD_IRQ = 0x4000,
+    TXD_WR = 0x2000,
+    TXD_PAD = 0x1000,
+    TXD_CRC = 0x800,
+    TXD_UR = 0x100,
+    TXD_RTRY = 0xf0,
+    TXD_RTRY_LBN = 4,
+    TXD_RL = 0x8,
+    TXD_LC = 0x4,
+    TXD_DF = 0x2,
+    TXD_CS = 0x1,
+};
+
+enum {
+    RXD_LEN = 0xffff0000,
+    RXD_LEN_LBN = 16,
+    RXD_E = 0x8000,
+    RXD_IRQ = 0x4000,
+    RXD_WRAP = 0x2000,
+    RXD_CF = 0x100,
+    RXD_M = 0x80,
+    RXD_OR = 0x40,
+    RXD_IS = 0x20,
+    RXD_DN = 0x10,
+    RXD_TL = 0x8,
+    RXD_SF = 0x4,
+    RXD_CRC = 0x2,
+    RXD_LC = 0x1,
+};
+
+typedef struct desc {
+    uint32_t len_flags;
+    uint32_t buf_ptr;
+} desc;
+
+#define DEFAULT_PHY 1
+
+typedef struct OpenEthState {
+    SysBusDevice dev;
+    NICState *nic;
+    NICConf conf;
+    MemoryRegion reg_io;
+    MemoryRegion desc_io;
+    qemu_irq irq;
+
+    Mii mii;
+    uint32_t regs[REG_MAX];
+    unsigned tx_desc;
+    unsigned rx_desc;
+    desc desc[128];
+} OpenEthState;
+
+static desc *rx_desc(OpenEthState *s)
+{
+    return s->desc + s->rx_desc;
+}
+
+static desc *tx_desc(OpenEthState *s)
+{
+    return s->desc + s->tx_desc;
+}
+
+static void open_eth_update_irq(OpenEthState *s,
+        uint32_t old, uint32_t new)
+{
+    if (!old != !new) {
+        trace_open_eth_update_irq(new);
+        qemu_set_irq(s->irq, new);
+    }
+}
+
+static void open_eth_int_source_write(OpenEthState *s,
+        uint32_t val)
+{
+    uint32_t old_val = s->regs[INT_SOURCE];
+
+    s->regs[INT_SOURCE] = val;
+    open_eth_update_irq(s, old_val & s->regs[INT_MASK],
+            s->regs[INT_SOURCE] & s->regs[INT_MASK]);
+}
+
+static void open_eth_set_link_status(NetClientState *nc)
+{
+    OpenEthState *s = qemu_get_nic_opaque(nc);
+
+    if (GET_REGBIT(s, MIICOMMAND, SCANSTAT)) {
+        SET_REGFIELD(s, MIISTATUS, LINKFAIL, nc->link_down);
+    }
+    mii_set_link(&s->mii, !nc->link_down);
+}
+
+static void open_eth_reset(void *opaque)
+{
+    OpenEthState *s = opaque;
+
+    memset(s->regs, 0, sizeof(s->regs));
+    s->regs[MODER] = 0xa000;
+    s->regs[IPGT] = 0x12;
+    s->regs[IPGR1] = 0xc;
+    s->regs[IPGR2] = 0x12;
+    s->regs[PACKETLEN] = 0x400600;
+    s->regs[COLLCONF] = 0xf003f;
+    s->regs[TX_BD_NUM] = 0x40;
+    s->regs[MIIMODER] = 0x64;
+
+    s->tx_desc = 0;
+    s->rx_desc = 0x40;
+
+    mii_reset(&s->mii);
+    open_eth_set_link_status(qemu_get_queue(s->nic));
+}
+
+static int open_eth_can_receive(NetClientState *nc)
+{
+    OpenEthState *s = qemu_get_nic_opaque(nc);
+
+    return GET_REGBIT(s, MODER, RXEN) &&
+        (s->regs[TX_BD_NUM] < 0x80) &&
+        (rx_desc(s)->len_flags & RXD_E);
+}
+
+static ssize_t open_eth_receive(NetClientState *nc,
+        const uint8_t *buf, size_t size)
+{
+    OpenEthState *s = qemu_get_nic_opaque(nc);
+    size_t maxfl = GET_REGFIELD(s, PACKETLEN, MAXFL);
+    size_t minfl = GET_REGFIELD(s, PACKETLEN, MINFL);
+    size_t fcsl = 4;
+    bool miss = true;
+
+    trace_open_eth_receive((unsigned)size);
+
+    if (size >= 6) {
+        static const uint8_t bcast_addr[] = {
+            0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+        };
+        if (memcmp(buf, bcast_addr, sizeof(bcast_addr)) == 0) {
+            miss = GET_REGBIT(s, MODER, BRO);
+        } else if ((buf[0] & 0x1) || GET_REGBIT(s, MODER, IAM)) {
+            unsigned mcast_idx = compute_mcast_idx(buf);
+            miss = !(s->regs[HASH0 + mcast_idx / 32] &
+                    (1 << (mcast_idx % 32)));
+            trace_open_eth_receive_mcast(
+                    mcast_idx, s->regs[HASH0], s->regs[HASH1]);
+        } else {
+            miss = GET_REGFIELD(s, MAC_ADDR1, BYTE0) != buf[0] ||
+                GET_REGFIELD(s, MAC_ADDR1, BYTE1) != buf[1] ||
+                GET_REGFIELD(s, MAC_ADDR0, BYTE2) != buf[2] ||
+                GET_REGFIELD(s, MAC_ADDR0, BYTE3) != buf[3] ||
+                GET_REGFIELD(s, MAC_ADDR0, BYTE4) != buf[4] ||
+                GET_REGFIELD(s, MAC_ADDR0, BYTE5) != buf[5];
+        }
+    }
+
+    if (miss && !GET_REGBIT(s, MODER, PRO)) {
+        trace_open_eth_receive_reject();
+        return size;
+    }
+
+#ifdef USE_RECSMALL
+    if (GET_REGBIT(s, MODER, RECSMALL) || size >= minfl) {
+#else
+    {
+#endif
+        static const uint8_t zero[64] = {0};
+        desc *desc = rx_desc(s);
+        size_t copy_size = GET_REGBIT(s, MODER, HUGEN) ? 65536 : maxfl;
+
+        desc->len_flags &= ~(RXD_CF | RXD_M | RXD_OR |
+                RXD_IS | RXD_DN | RXD_TL | RXD_SF | RXD_CRC | RXD_LC);
+
+        if (copy_size > size) {
+            copy_size = size;
+        } else {
+            fcsl = 0;
+        }
+        if (miss) {
+            desc->len_flags |= RXD_M;
+        }
+        if (GET_REGBIT(s, MODER, HUGEN) && size > maxfl) {
+            desc->len_flags |= RXD_TL;
+        }
+#ifdef USE_RECSMALL
+        if (size < minfl) {
+            desc->len_flags |= RXD_SF;
+        }
+#endif
+
+        cpu_physical_memory_write(desc->buf_ptr, buf, copy_size);
+
+        if (GET_REGBIT(s, MODER, PAD) && copy_size < minfl) {
+            if (minfl - copy_size > fcsl) {
+                fcsl = 0;
+            } else {
+                fcsl -= minfl - copy_size;
+            }
+            while (copy_size < minfl) {
+                size_t zero_sz = minfl - copy_size < sizeof(zero) ?
+                    minfl - copy_size : sizeof(zero);
+
+                cpu_physical_memory_write(desc->buf_ptr + copy_size,
+                        zero, zero_sz);
+                copy_size += zero_sz;
+            }
+        }
+
+        /* There's no FCS in the frames handed to us by the QEMU, zero fill it.
+         * Don't do it if the frame is cut at the MAXFL or padded with 4 or
+         * more bytes to the MINFL.
+         */
+        cpu_physical_memory_write(desc->buf_ptr + copy_size, zero, fcsl);
+        copy_size += fcsl;
+
+        SET_FIELD(desc->len_flags, RXD_LEN, copy_size);
+
+        if ((desc->len_flags & RXD_WRAP) || s->rx_desc == 0x7f) {
+            s->rx_desc = s->regs[TX_BD_NUM];
+        } else {
+            ++s->rx_desc;
+        }
+        desc->len_flags &= ~RXD_E;
+
+        trace_open_eth_receive_desc(desc->buf_ptr, desc->len_flags);
+
+        if (desc->len_flags & RXD_IRQ) {
+            open_eth_int_source_write(s,
+                    s->regs[INT_SOURCE] | INT_SOURCE_RXB);
+        }
+    }
+    return size;
+}
+
+static void open_eth_cleanup(NetClientState *nc)
+{
+}
+
+static NetClientInfo net_open_eth_info = {
+    .type = NET_CLIENT_OPTIONS_KIND_NIC,
+    .size = sizeof(NICState),
+    .can_receive = open_eth_can_receive,
+    .receive = open_eth_receive,
+    .cleanup = open_eth_cleanup,
+    .link_status_changed = open_eth_set_link_status,
+};
+
+static void open_eth_start_xmit(OpenEthState *s, desc *tx)
+{
+    uint8_t buf[65536];
+    unsigned len = GET_FIELD(tx->len_flags, TXD_LEN);
+    unsigned tx_len = len;
+
+    if ((tx->len_flags & TXD_PAD) &&
+            tx_len < GET_REGFIELD(s, PACKETLEN, MINFL)) {
+        tx_len = GET_REGFIELD(s, PACKETLEN, MINFL);
+    }
+    if (!GET_REGBIT(s, MODER, HUGEN) &&
+            tx_len > GET_REGFIELD(s, PACKETLEN, MAXFL)) {
+        tx_len = GET_REGFIELD(s, PACKETLEN, MAXFL);
+    }
+
+    trace_open_eth_start_xmit(tx->buf_ptr, len, tx_len);
+
+    if (len > tx_len) {
+        len = tx_len;
+    }
+    cpu_physical_memory_read(tx->buf_ptr, buf, len);
+    if (tx_len > len) {
+        memset(buf + len, 0, tx_len - len);
+    }
+    qemu_send_packet(qemu_get_queue(s->nic), buf, tx_len);
+
+    if (tx->len_flags & TXD_WR) {
+        s->tx_desc = 0;
+    } else {
+        ++s->tx_desc;
+        if (s->tx_desc >= s->regs[TX_BD_NUM]) {
+            s->tx_desc = 0;
+        }
+    }
+    tx->len_flags &= ~(TXD_RD | TXD_UR |
+            TXD_RTRY | TXD_RL | TXD_LC | TXD_DF | TXD_CS);
+    if (tx->len_flags & TXD_IRQ) {
+        open_eth_int_source_write(s, s->regs[INT_SOURCE] | INT_SOURCE_TXB);
+    }
+
+}
+
+static void open_eth_check_start_xmit(OpenEthState *s)
+{
+    desc *tx = tx_desc(s);
+    if (GET_REGBIT(s, MODER, TXEN) && s->regs[TX_BD_NUM] > 0 &&
+            (tx->len_flags & TXD_RD) &&
+            GET_FIELD(tx->len_flags, TXD_LEN) > 4) {
+        open_eth_start_xmit(s, tx);
+    }
+}
+
+static uint64_t open_eth_reg_read(void *opaque,
+        hwaddr addr, unsigned int size)
+{
+    static uint32_t (*reg_read[REG_MAX])(OpenEthState *s) = {
+    };
+    OpenEthState *s = opaque;
+    unsigned idx = addr / 4;
+    uint64_t v = 0;
+
+    if (idx < REG_MAX) {
+        if (reg_read[idx]) {
+            v = reg_read[idx](s);
+        } else {
+            v = s->regs[idx];
+        }
+    }
+    trace_open_eth_reg_read((uint32_t)addr, (uint32_t)v);
+    return v;
+}
+
+static void open_eth_ro(OpenEthState *s, uint32_t val)
+{
+}
+
+static void open_eth_moder_host_write(OpenEthState *s, uint32_t val)
+{
+    uint32_t set = val & ~s->regs[MODER];
+
+    if (set & MODER_RST) {
+        open_eth_reset(s);
+    }
+
+    s->regs[MODER] = val;
+
+    if (set & MODER_RXEN) {
+        s->rx_desc = s->regs[TX_BD_NUM];
+    }
+    if (set & MODER_TXEN) {
+        s->tx_desc = 0;
+        open_eth_check_start_xmit(s);
+    }
+}
+
+static void open_eth_int_source_host_write(OpenEthState *s, uint32_t val)
+{
+    uint32_t old = s->regs[INT_SOURCE];
+
+    s->regs[INT_SOURCE] &= ~val;
+    open_eth_update_irq(s, old & s->regs[INT_MASK],
+            s->regs[INT_SOURCE] & s->regs[INT_MASK]);
+}
+
+static void open_eth_int_mask_host_write(OpenEthState *s, uint32_t val)
+{
+    uint32_t old = s->regs[INT_MASK];
+
+    s->regs[INT_MASK] = val;
+    open_eth_update_irq(s, s->regs[INT_SOURCE] & old,
+            s->regs[INT_SOURCE] & s->regs[INT_MASK]);
+}
+
+static void open_eth_mii_command_host_write(OpenEthState *s, uint32_t val)
+{
+    unsigned fiad = GET_REGFIELD(s, MIIADDRESS, FIAD);
+    unsigned rgad = GET_REGFIELD(s, MIIADDRESS, RGAD);
+
+    if (val & MIICOMMAND_WCTRLDATA) {
+        if (fiad == DEFAULT_PHY) {
+            mii_write_host(&s->mii, rgad,
+                    GET_REGFIELD(s, MIITX_DATA, CTRLDATA));
+        }
+    }
+    if (val & MIICOMMAND_RSTAT) {
+        if (fiad == DEFAULT_PHY) {
+            SET_REGFIELD(s, MIIRX_DATA, PRSD,
+                    mii_read_host(&s->mii, rgad));
+        } else {
+            s->regs[MIIRX_DATA] = 0xffff;
+        }
+        SET_REGFIELD(s, MIISTATUS, LINKFAIL, qemu_get_queue(s->nic)->link_down);
+    }
+}
+
+static void open_eth_mii_tx_host_write(OpenEthState *s, uint32_t val)
+{
+    SET_REGFIELD(s, MIITX_DATA, CTRLDATA, val);
+    if (GET_REGFIELD(s, MIIADDRESS, FIAD) == DEFAULT_PHY) {
+        mii_write_host(&s->mii, GET_REGFIELD(s, MIIADDRESS, RGAD),
+                GET_REGFIELD(s, MIITX_DATA, CTRLDATA));
+    }
+}
+
+static void open_eth_reg_write(void *opaque,
+        hwaddr addr, uint64_t val, unsigned int size)
+{
+    static void (*reg_write[REG_MAX])(OpenEthState *s, uint32_t val) = {
+        [MODER] = open_eth_moder_host_write,
+        [INT_SOURCE] = open_eth_int_source_host_write,
+        [INT_MASK] = open_eth_int_mask_host_write,
+        [MIICOMMAND] = open_eth_mii_command_host_write,
+        [MIITX_DATA] = open_eth_mii_tx_host_write,
+        [MIISTATUS] = open_eth_ro,
+    };
+    OpenEthState *s = opaque;
+    unsigned idx = addr / 4;
+
+    if (idx < REG_MAX) {
+        trace_open_eth_reg_write((uint32_t)addr, (uint32_t)val);
+        if (reg_write[idx]) {
+            reg_write[idx](s, val);
+        } else {
+            s->regs[idx] = val;
+        }
+    }
+}
+
+static uint64_t open_eth_desc_read(void *opaque,
+        hwaddr addr, unsigned int size)
+{
+    OpenEthState *s = opaque;
+    uint64_t v = 0;
+
+    addr &= 0x3ff;
+    memcpy(&v, (uint8_t *)s->desc + addr, size);
+    trace_open_eth_desc_read((uint32_t)addr, (uint32_t)v);
+    return v;
+}
+
+static void open_eth_desc_write(void *opaque,
+        hwaddr addr, uint64_t val, unsigned int size)
+{
+    OpenEthState *s = opaque;
+
+    addr &= 0x3ff;
+    trace_open_eth_desc_write((uint32_t)addr, (uint32_t)val);
+    memcpy((uint8_t *)s->desc + addr, &val, size);
+    open_eth_check_start_xmit(s);
+}
+
+
+static const MemoryRegionOps open_eth_reg_ops = {
+    .read = open_eth_reg_read,
+    .write = open_eth_reg_write,
+};
+
+static const MemoryRegionOps open_eth_desc_ops = {
+    .read = open_eth_desc_read,
+    .write = open_eth_desc_write,
+};
+
+static int sysbus_open_eth_init(SysBusDevice *dev)
+{
+    OpenEthState *s = DO_UPCAST(OpenEthState, dev, dev);
+
+    memory_region_init_io(&s->reg_io, &open_eth_reg_ops, s,
+            "open_eth.regs", 0x54);
+    sysbus_init_mmio(dev, &s->reg_io);
+
+    memory_region_init_io(&s->desc_io, &open_eth_desc_ops, s,
+            "open_eth.desc", 0x400);
+    sysbus_init_mmio(dev, &s->desc_io);
+
+    sysbus_init_irq(dev, &s->irq);
+
+    s->nic = qemu_new_nic(&net_open_eth_info, &s->conf,
+                          object_get_typename(OBJECT(s)), s->dev.qdev.id, s);
+    return 0;
+}
+
+static void qdev_open_eth_reset(DeviceState *dev)
+{
+    OpenEthState *d = DO_UPCAST(OpenEthState, dev.qdev, dev);
+    open_eth_reset(d);
+}
+
+static Property open_eth_properties[] = {
+    DEFINE_NIC_PROPERTIES(OpenEthState, conf),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void open_eth_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = sysbus_open_eth_init;
+    dc->desc = "Opencores 10/100 Mbit Ethernet";
+    dc->reset = qdev_open_eth_reset;
+    dc->props = open_eth_properties;
+}
+
+static const 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_types(void)
+{
+    type_register_static(&open_eth_info);
+}
+
+type_init(open_eth_register_types)
diff --git a/hw/net/pcnet-pci.c b/hw/net/pcnet-pci.c
new file mode 100644 (file)
index 0000000..9df2b87
--- /dev/null
@@ -0,0 +1,376 @@
+/*
+ * QEMU AMD PC-Net II (Am79C970A) PCI emulation
+ *
+ * Copyright (c) 2004 Antony T Curtis
+ *
+ * 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.
+ */
+
+/* This software was written to be compatible with the specification:
+ * AMD Am79C970A PCnet-PCI II Ethernet Controller Data-Sheet
+ * AMD Publication# 19436  Rev:E  Amendment/0  Issue Date: June 2000
+ */
+
+#include "hw/pci/pci.h"
+#include "net/net.h"
+#include "hw/loader.h"
+#include "qemu/timer.h"
+#include "sysemu/dma.h"
+
+#include "pcnet.h"
+
+//#define PCNET_DEBUG
+//#define PCNET_DEBUG_IO
+//#define PCNET_DEBUG_BCR
+//#define PCNET_DEBUG_CSR
+//#define PCNET_DEBUG_RMD
+//#define PCNET_DEBUG_TMD
+//#define PCNET_DEBUG_MATCH
+
+
+typedef struct {
+    PCIDevice pci_dev;
+    PCNetState state;
+    MemoryRegion io_bar;
+} PCIPCNetState;
+
+static void pcnet_aprom_writeb(void *opaque, uint32_t addr, uint32_t val)
+{
+    PCNetState *s = opaque;
+#ifdef PCNET_DEBUG
+    printf("pcnet_aprom_writeb addr=0x%08x val=0x%02x\n", addr, val);
+#endif
+    if (BCR_APROMWE(s)) {
+        s->prom[addr & 15] = val;
+    }
+}
+
+static uint32_t pcnet_aprom_readb(void *opaque, uint32_t addr)
+{
+    PCNetState *s = opaque;
+    uint32_t val = s->prom[addr & 15];
+#ifdef PCNET_DEBUG
+    printf("pcnet_aprom_readb addr=0x%08x val=0x%02x\n", addr, val);
+#endif
+    return val;
+}
+
+static uint64_t pcnet_ioport_read(void *opaque, hwaddr addr,
+                                  unsigned size)
+{
+    PCNetState *d = opaque;
+
+    if (addr < 0x10) {
+        if (!BCR_DWIO(d) && size == 1) {
+            return pcnet_aprom_readb(d, addr);
+        } else if (!BCR_DWIO(d) && (addr & 1) == 0 && size == 2) {
+            return pcnet_aprom_readb(d, addr) |
+                   (pcnet_aprom_readb(d, addr + 1) << 8);
+        } else if (BCR_DWIO(d) && (addr & 3) == 0 && size == 4) {
+            return pcnet_aprom_readb(d, addr) |
+                   (pcnet_aprom_readb(d, addr + 1) << 8) |
+                   (pcnet_aprom_readb(d, addr + 2) << 16) |
+                   (pcnet_aprom_readb(d, addr + 3) << 24);
+        }
+    } else {
+        if (size == 2) {
+            return pcnet_ioport_readw(d, addr);
+        } else if (size == 4) {
+            return pcnet_ioport_readl(d, addr);
+        }
+    }
+    return ((uint64_t)1 << (size * 8)) - 1;
+}
+
+static void pcnet_ioport_write(void *opaque, hwaddr addr,
+                               uint64_t data, unsigned size)
+{
+    PCNetState *d = opaque;
+
+    if (addr < 0x10) {
+        if (!BCR_DWIO(d) && size == 1) {
+            pcnet_aprom_writeb(d, addr, data);
+        } else if (!BCR_DWIO(d) && (addr & 1) == 0 && size == 2) {
+            pcnet_aprom_writeb(d, addr, data & 0xff);
+            pcnet_aprom_writeb(d, addr + 1, data >> 8);
+        } else if (BCR_DWIO(d) && (addr & 3) == 0 && size == 4) {
+            pcnet_aprom_writeb(d, addr, data & 0xff);
+            pcnet_aprom_writeb(d, addr + 1, (data >> 8) & 0xff);
+            pcnet_aprom_writeb(d, addr + 2, (data >> 16) & 0xff);
+            pcnet_aprom_writeb(d, addr + 3, data >> 24);
+        }
+    } else {
+        if (size == 2) {
+            pcnet_ioport_writew(d, addr, data);
+        } else if (size == 4) {
+            pcnet_ioport_writel(d, addr, data);
+        }
+    }
+}
+
+static const MemoryRegionOps pcnet_io_ops = {
+    .read = pcnet_ioport_read,
+    .write = pcnet_ioport_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void pcnet_mmio_writeb(void *opaque, hwaddr addr, uint32_t val)
+{
+    PCNetState *d = opaque;
+#ifdef PCNET_DEBUG_IO
+    printf("pcnet_mmio_writeb addr=0x" TARGET_FMT_plx" val=0x%02x\n", addr,
+           val);
+#endif
+    if (!(addr & 0x10))
+        pcnet_aprom_writeb(d, addr & 0x0f, val);
+}
+
+static uint32_t pcnet_mmio_readb(void *opaque, hwaddr addr)
+{
+    PCNetState *d = opaque;
+    uint32_t val = -1;
+    if (!(addr & 0x10))
+        val = pcnet_aprom_readb(d, addr & 0x0f);
+#ifdef PCNET_DEBUG_IO
+    printf("pcnet_mmio_readb addr=0x" TARGET_FMT_plx " val=0x%02x\n", addr,
+           val & 0xff);
+#endif
+    return val;
+}
+
+static void pcnet_mmio_writew(void *opaque, hwaddr addr, uint32_t val)
+{
+    PCNetState *d = opaque;
+#ifdef PCNET_DEBUG_IO
+    printf("pcnet_mmio_writew addr=0x" TARGET_FMT_plx " val=0x%04x\n", addr,
+           val);
+#endif
+    if (addr & 0x10)
+        pcnet_ioport_writew(d, addr & 0x0f, val);
+    else {
+        addr &= 0x0f;
+        pcnet_aprom_writeb(d, addr, val & 0xff);
+        pcnet_aprom_writeb(d, addr+1, (val & 0xff00) >> 8);
+    }
+}
+
+static uint32_t pcnet_mmio_readw(void *opaque, hwaddr addr)
+{
+    PCNetState *d = opaque;
+    uint32_t val = -1;
+    if (addr & 0x10)
+        val = pcnet_ioport_readw(d, addr & 0x0f);
+    else {
+        addr &= 0x0f;
+        val = pcnet_aprom_readb(d, addr+1);
+        val <<= 8;
+        val |= pcnet_aprom_readb(d, addr);
+    }
+#ifdef PCNET_DEBUG_IO
+    printf("pcnet_mmio_readw addr=0x" TARGET_FMT_plx" val = 0x%04x\n", addr,
+           val & 0xffff);
+#endif
+    return val;
+}
+
+static void pcnet_mmio_writel(void *opaque, hwaddr addr, uint32_t val)
+{
+    PCNetState *d = opaque;
+#ifdef PCNET_DEBUG_IO
+    printf("pcnet_mmio_writel addr=0x" TARGET_FMT_plx" val=0x%08x\n", addr,
+           val);
+#endif
+    if (addr & 0x10)
+        pcnet_ioport_writel(d, addr & 0x0f, val);
+    else {
+        addr &= 0x0f;
+        pcnet_aprom_writeb(d, addr, val & 0xff);
+        pcnet_aprom_writeb(d, addr+1, (val & 0xff00) >> 8);
+        pcnet_aprom_writeb(d, addr+2, (val & 0xff0000) >> 16);
+        pcnet_aprom_writeb(d, addr+3, (val & 0xff000000) >> 24);
+    }
+}
+
+static uint32_t pcnet_mmio_readl(void *opaque, hwaddr addr)
+{
+    PCNetState *d = opaque;
+    uint32_t val;
+    if (addr & 0x10)
+        val = pcnet_ioport_readl(d, addr & 0x0f);
+    else {
+        addr &= 0x0f;
+        val = pcnet_aprom_readb(d, addr+3);
+        val <<= 8;
+        val |= pcnet_aprom_readb(d, addr+2);
+        val <<= 8;
+        val |= pcnet_aprom_readb(d, addr+1);
+        val <<= 8;
+        val |= pcnet_aprom_readb(d, addr);
+    }
+#ifdef PCNET_DEBUG_IO
+    printf("pcnet_mmio_readl addr=0x" TARGET_FMT_plx " val=0x%08x\n", addr,
+           val);
+#endif
+    return val;
+}
+
+static const VMStateDescription vmstate_pci_pcnet = {
+    .name = "pcnet",
+    .version_id = 3,
+    .minimum_version_id = 2,
+    .minimum_version_id_old = 2,
+    .fields      = (VMStateField []) {
+        VMSTATE_PCI_DEVICE(pci_dev, PCIPCNetState),
+        VMSTATE_STRUCT(state, PCIPCNetState, 0, vmstate_pcnet, PCNetState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+/* PCI interface */
+
+static const MemoryRegionOps pcnet_mmio_ops = {
+    .old_mmio = {
+        .read = { pcnet_mmio_readb, pcnet_mmio_readw, pcnet_mmio_readl },
+        .write = { pcnet_mmio_writeb, pcnet_mmio_writew, pcnet_mmio_writel },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void pci_physical_memory_write(void *dma_opaque, hwaddr addr,
+                                      uint8_t *buf, int len, int do_bswap)
+{
+    pci_dma_write(dma_opaque, addr, buf, len);
+}
+
+static void pci_physical_memory_read(void *dma_opaque, hwaddr addr,
+                                     uint8_t *buf, int len, int do_bswap)
+{
+    pci_dma_read(dma_opaque, addr, buf, len);
+}
+
+static void pci_pcnet_cleanup(NetClientState *nc)
+{
+    PCNetState *d = qemu_get_nic_opaque(nc);
+
+    pcnet_common_cleanup(d);
+}
+
+static void pci_pcnet_uninit(PCIDevice *dev)
+{
+    PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev, dev);
+
+    memory_region_destroy(&d->state.mmio);
+    memory_region_destroy(&d->io_bar);
+    qemu_del_timer(d->state.poll_timer);
+    qemu_free_timer(d->state.poll_timer);
+    qemu_del_nic(d->state.nic);
+}
+
+static NetClientInfo net_pci_pcnet_info = {
+    .type = NET_CLIENT_OPTIONS_KIND_NIC,
+    .size = sizeof(NICState),
+    .can_receive = pcnet_can_receive,
+    .receive = pcnet_receive,
+    .link_status_changed = pcnet_set_link_status,
+    .cleanup = pci_pcnet_cleanup,
+};
+
+static int pci_pcnet_init(PCIDevice *pci_dev)
+{
+    PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev, pci_dev);
+    PCNetState *s = &d->state;
+    uint8_t *pci_conf;
+
+#if 0
+    printf("sizeof(RMD)=%d, sizeof(TMD)=%d\n",
+        sizeof(struct pcnet_RMD), sizeof(struct pcnet_TMD));
+#endif
+
+    pci_conf = pci_dev->config;
+
+    pci_set_word(pci_conf + PCI_STATUS,
+                 PCI_STATUS_FAST_BACK | PCI_STATUS_DEVSEL_MEDIUM);
+
+    pci_set_word(pci_conf + PCI_SUBSYSTEM_VENDOR_ID, 0x0);
+    pci_set_word(pci_conf + PCI_SUBSYSTEM_ID, 0x0);
+
+    pci_conf[PCI_INTERRUPT_PIN] = 1; /* interrupt pin A */
+    pci_conf[PCI_MIN_GNT] = 0x06;
+    pci_conf[PCI_MAX_LAT] = 0xff;
+
+    /* Handler for memory-mapped I/O */
+    memory_region_init_io(&d->state.mmio, &pcnet_mmio_ops, s, "pcnet-mmio",
+                          PCNET_PNPMMIO_SIZE);
+
+    memory_region_init_io(&d->io_bar, &pcnet_io_ops, s, "pcnet-io",
+                          PCNET_IOPORT_SIZE);
+    pci_register_bar(pci_dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &d->io_bar);
+
+    pci_register_bar(pci_dev, 1, 0, &s->mmio);
+
+    s->irq = pci_dev->irq[0];
+    s->phys_mem_read = pci_physical_memory_read;
+    s->phys_mem_write = pci_physical_memory_write;
+    s->dma_opaque = pci_dev;
+
+    return pcnet_common_init(&pci_dev->qdev, s, &net_pci_pcnet_info);
+}
+
+static void pci_reset(DeviceState *dev)
+{
+    PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev.qdev, dev);
+
+    pcnet_h_reset(&d->state);
+}
+
+static Property pcnet_properties[] = {
+    DEFINE_NIC_PROPERTIES(PCIPCNetState, state.conf),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void pcnet_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = pci_pcnet_init;
+    k->exit = pci_pcnet_uninit;
+    k->romfile = "efi-pcnet.rom",
+    k->vendor_id = PCI_VENDOR_ID_AMD;
+    k->device_id = PCI_DEVICE_ID_AMD_LANCE;
+    k->revision = 0x10;
+    k->class_id = PCI_CLASS_NETWORK_ETHERNET;
+    dc->reset = pci_reset;
+    dc->vmsd = &vmstate_pci_pcnet;
+    dc->props = pcnet_properties;
+}
+
+static const TypeInfo pcnet_info = {
+    .name          = "pcnet",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PCIPCNetState),
+    .class_init    = pcnet_class_init,
+};
+
+static void pci_pcnet_register_types(void)
+{
+    type_register_static(&pcnet_info);
+}
+
+type_init(pci_pcnet_register_types)
diff --git a/hw/net/pcnet.c b/hw/net/pcnet.c
new file mode 100644 (file)
index 0000000..b606d2b
--- /dev/null
@@ -0,0 +1,1768 @@
+/*
+ * QEMU AMD PC-Net II (Am79C970A) emulation
+ *
+ * Copyright (c) 2004 Antony T Curtis
+ *
+ * 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.
+ */
+
+/* This software was written to be compatible with the specification:
+ * AMD Am79C970A PCnet-PCI II Ethernet Controller Data-Sheet
+ * AMD Publication# 19436  Rev:E  Amendment/0  Issue Date: June 2000
+ */
+
+/*
+ * On Sparc32, this is the Lance (Am7990) part of chip STP2000 (Master I/O), also
+ * produced as NCR89C100. See
+ * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C100.txt
+ * and
+ * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR92C990.txt
+ */
+
+#include "hw/qdev.h"
+#include "net/net.h"
+#include "qemu/timer.h"
+#include "qemu/sockets.h"
+#include "sysemu/sysemu.h"
+
+#include "pcnet.h"
+
+//#define PCNET_DEBUG
+//#define PCNET_DEBUG_IO
+//#define PCNET_DEBUG_BCR
+//#define PCNET_DEBUG_CSR
+//#define PCNET_DEBUG_RMD
+//#define PCNET_DEBUG_TMD
+//#define PCNET_DEBUG_MATCH
+
+
+struct qemu_ether_header {
+    uint8_t ether_dhost[6];
+    uint8_t ether_shost[6];
+    uint16_t ether_type;
+};
+
+#define CSR_INIT(S)      !!(((S)->csr[0])&0x0001)
+#define CSR_STRT(S)      !!(((S)->csr[0])&0x0002)
+#define CSR_STOP(S)      !!(((S)->csr[0])&0x0004)
+#define CSR_TDMD(S)      !!(((S)->csr[0])&0x0008)
+#define CSR_TXON(S)      !!(((S)->csr[0])&0x0010)
+#define CSR_RXON(S)      !!(((S)->csr[0])&0x0020)
+#define CSR_INEA(S)      !!(((S)->csr[0])&0x0040)
+#define CSR_BSWP(S)      !!(((S)->csr[3])&0x0004)
+#define CSR_LAPPEN(S)    !!(((S)->csr[3])&0x0020)
+#define CSR_DXSUFLO(S)   !!(((S)->csr[3])&0x0040)
+#define CSR_ASTRP_RCV(S) !!(((S)->csr[4])&0x0800)
+#define CSR_DPOLL(S)     !!(((S)->csr[4])&0x1000)
+#define CSR_SPND(S)      !!(((S)->csr[5])&0x0001)
+#define CSR_LTINTEN(S)   !!(((S)->csr[5])&0x4000)
+#define CSR_TOKINTD(S)   !!(((S)->csr[5])&0x8000)
+#define CSR_DRX(S)       !!(((S)->csr[15])&0x0001)
+#define CSR_DTX(S)       !!(((S)->csr[15])&0x0002)
+#define CSR_LOOP(S)      !!(((S)->csr[15])&0x0004)
+#define CSR_DXMTFCS(S)   !!(((S)->csr[15])&0x0008)
+#define CSR_INTL(S)      !!(((S)->csr[15])&0x0040)
+#define CSR_DRCVPA(S)    !!(((S)->csr[15])&0x2000)
+#define CSR_DRCVBC(S)    !!(((S)->csr[15])&0x4000)
+#define CSR_PROM(S)      !!(((S)->csr[15])&0x8000)
+
+#define CSR_CRBC(S)      ((S)->csr[40])
+#define CSR_CRST(S)      ((S)->csr[41])
+#define CSR_CXBC(S)      ((S)->csr[42])
+#define CSR_CXST(S)      ((S)->csr[43])
+#define CSR_NRBC(S)      ((S)->csr[44])
+#define CSR_NRST(S)      ((S)->csr[45])
+#define CSR_POLL(S)      ((S)->csr[46])
+#define CSR_PINT(S)      ((S)->csr[47])
+#define CSR_RCVRC(S)     ((S)->csr[72])
+#define CSR_XMTRC(S)     ((S)->csr[74])
+#define CSR_RCVRL(S)     ((S)->csr[76])
+#define CSR_XMTRL(S)     ((S)->csr[78])
+#define CSR_MISSC(S)     ((S)->csr[112])
+
+#define CSR_IADR(S)      ((S)->csr[ 1] | ((uint32_t)(S)->csr[ 2] << 16))
+#define CSR_CRBA(S)      ((S)->csr[18] | ((uint32_t)(S)->csr[19] << 16))
+#define CSR_CXBA(S)      ((S)->csr[20] | ((uint32_t)(S)->csr[21] << 16))
+#define CSR_NRBA(S)      ((S)->csr[22] | ((uint32_t)(S)->csr[23] << 16))
+#define CSR_BADR(S)      ((S)->csr[24] | ((uint32_t)(S)->csr[25] << 16))
+#define CSR_NRDA(S)      ((S)->csr[26] | ((uint32_t)(S)->csr[27] << 16))
+#define CSR_CRDA(S)      ((S)->csr[28] | ((uint32_t)(S)->csr[29] << 16))
+#define CSR_BADX(S)      ((S)->csr[30] | ((uint32_t)(S)->csr[31] << 16))
+#define CSR_NXDA(S)      ((S)->csr[32] | ((uint32_t)(S)->csr[33] << 16))
+#define CSR_CXDA(S)      ((S)->csr[34] | ((uint32_t)(S)->csr[35] << 16))
+#define CSR_NNRD(S)      ((S)->csr[36] | ((uint32_t)(S)->csr[37] << 16))
+#define CSR_NNXD(S)      ((S)->csr[38] | ((uint32_t)(S)->csr[39] << 16))
+#define CSR_PXDA(S)      ((S)->csr[60] | ((uint32_t)(S)->csr[61] << 16))
+#define CSR_NXBA(S)      ((S)->csr[64] | ((uint32_t)(S)->csr[65] << 16))
+
+#define PHYSADDR(S,A) \
+  (BCR_SSIZE32(S) ? (A) : (A) | ((0xff00 & (uint32_t)(S)->csr[2])<<16))
+
+struct pcnet_initblk16 {
+    uint16_t mode;
+    uint16_t padr[3];
+    uint16_t ladrf[4];
+    uint32_t rdra;
+    uint32_t tdra;
+};
+
+struct pcnet_initblk32 {
+    uint16_t mode;
+    uint8_t rlen;
+    uint8_t tlen;
+    uint16_t padr[3];
+    uint16_t _res;
+    uint16_t ladrf[4];
+    uint32_t rdra;
+    uint32_t tdra;
+};
+
+struct pcnet_TMD {
+    uint32_t tbadr;
+    int16_t length;
+    int16_t status;
+    uint32_t misc;
+    uint32_t res;
+};
+
+#define TMDL_BCNT_MASK  0x0fff
+#define TMDL_BCNT_SH    0
+#define TMDL_ONES_MASK  0xf000
+#define TMDL_ONES_SH    12
+
+#define TMDS_BPE_MASK   0x0080
+#define TMDS_BPE_SH     7
+#define TMDS_ENP_MASK   0x0100
+#define TMDS_ENP_SH     8
+#define TMDS_STP_MASK   0x0200
+#define TMDS_STP_SH     9
+#define TMDS_DEF_MASK   0x0400
+#define TMDS_DEF_SH     10
+#define TMDS_ONE_MASK   0x0800
+#define TMDS_ONE_SH     11
+#define TMDS_LTINT_MASK 0x1000
+#define TMDS_LTINT_SH   12
+#define TMDS_NOFCS_MASK 0x2000
+#define TMDS_NOFCS_SH   13
+#define TMDS_ADDFCS_MASK TMDS_NOFCS_MASK
+#define TMDS_ADDFCS_SH  TMDS_NOFCS_SH
+#define TMDS_ERR_MASK   0x4000
+#define TMDS_ERR_SH     14
+#define TMDS_OWN_MASK   0x8000
+#define TMDS_OWN_SH     15
+
+#define TMDM_TRC_MASK   0x0000000f
+#define TMDM_TRC_SH     0
+#define TMDM_TDR_MASK   0x03ff0000
+#define TMDM_TDR_SH     16
+#define TMDM_RTRY_MASK  0x04000000
+#define TMDM_RTRY_SH    26
+#define TMDM_LCAR_MASK  0x08000000
+#define TMDM_LCAR_SH    27
+#define TMDM_LCOL_MASK  0x10000000
+#define TMDM_LCOL_SH    28
+#define TMDM_EXDEF_MASK 0x20000000
+#define TMDM_EXDEF_SH   29
+#define TMDM_UFLO_MASK  0x40000000
+#define TMDM_UFLO_SH    30
+#define TMDM_BUFF_MASK  0x80000000
+#define TMDM_BUFF_SH    31
+
+struct pcnet_RMD {
+    uint32_t rbadr;
+    int16_t buf_length;
+    int16_t status;
+    uint32_t msg_length;
+    uint32_t res;
+};
+
+#define RMDL_BCNT_MASK  0x0fff
+#define RMDL_BCNT_SH    0
+#define RMDL_ONES_MASK  0xf000
+#define RMDL_ONES_SH    12
+
+#define RMDS_BAM_MASK   0x0010
+#define RMDS_BAM_SH     4
+#define RMDS_LFAM_MASK  0x0020
+#define RMDS_LFAM_SH    5
+#define RMDS_PAM_MASK   0x0040
+#define RMDS_PAM_SH     6
+#define RMDS_BPE_MASK   0x0080
+#define RMDS_BPE_SH     7
+#define RMDS_ENP_MASK   0x0100
+#define RMDS_ENP_SH     8
+#define RMDS_STP_MASK   0x0200
+#define RMDS_STP_SH     9
+#define RMDS_BUFF_MASK  0x0400
+#define RMDS_BUFF_SH    10
+#define RMDS_CRC_MASK   0x0800
+#define RMDS_CRC_SH     11
+#define RMDS_OFLO_MASK  0x1000
+#define RMDS_OFLO_SH    12
+#define RMDS_FRAM_MASK  0x2000
+#define RMDS_FRAM_SH    13
+#define RMDS_ERR_MASK   0x4000
+#define RMDS_ERR_SH     14
+#define RMDS_OWN_MASK   0x8000
+#define RMDS_OWN_SH     15
+
+#define RMDM_MCNT_MASK  0x00000fff
+#define RMDM_MCNT_SH    0
+#define RMDM_ZEROS_MASK 0x0000f000
+#define RMDM_ZEROS_SH   12
+#define RMDM_RPC_MASK   0x00ff0000
+#define RMDM_RPC_SH     16
+#define RMDM_RCC_MASK   0xff000000
+#define RMDM_RCC_SH     24
+
+#define SET_FIELD(regp, name, field, value)             \
+  (*(regp) = (*(regp) & ~(name ## _ ## field ## _MASK)) \
+             | ((value) << name ## _ ## field ## _SH))
+
+#define GET_FIELD(reg, name, field)                     \
+  (((reg) & name ## _ ## field ## _MASK) >> name ## _ ## field ## _SH)
+
+#define PRINT_TMD(T) printf(                            \
+        "TMD0 : TBADR=0x%08x\n"                         \
+        "TMD1 : OWN=%d, ERR=%d, FCS=%d, LTI=%d, "       \
+        "ONE=%d, DEF=%d, STP=%d, ENP=%d,\n"             \
+        "       BPE=%d, BCNT=%d\n"                      \
+        "TMD2 : BUF=%d, UFL=%d, EXD=%d, LCO=%d, "       \
+        "LCA=%d, RTR=%d,\n"                             \
+        "       TDR=%d, TRC=%d\n",                      \
+        (T)->tbadr,                                     \
+        GET_FIELD((T)->status, TMDS, OWN),              \
+        GET_FIELD((T)->status, TMDS, ERR),              \
+        GET_FIELD((T)->status, TMDS, NOFCS),            \
+        GET_FIELD((T)->status, TMDS, LTINT),            \
+        GET_FIELD((T)->status, TMDS, ONE),              \
+        GET_FIELD((T)->status, TMDS, DEF),              \
+        GET_FIELD((T)->status, TMDS, STP),              \
+        GET_FIELD((T)->status, TMDS, ENP),              \
+        GET_FIELD((T)->status, TMDS, BPE),              \
+        4096-GET_FIELD((T)->length, TMDL, BCNT),        \
+        GET_FIELD((T)->misc, TMDM, BUFF),               \
+        GET_FIELD((T)->misc, TMDM, UFLO),               \
+        GET_FIELD((T)->misc, TMDM, EXDEF),              \
+        GET_FIELD((T)->misc, TMDM, LCOL),               \
+        GET_FIELD((T)->misc, TMDM, LCAR),               \
+        GET_FIELD((T)->misc, TMDM, RTRY),               \
+        GET_FIELD((T)->misc, TMDM, TDR),                \
+        GET_FIELD((T)->misc, TMDM, TRC))
+
+#define PRINT_RMD(R) printf(                            \
+        "RMD0 : RBADR=0x%08x\n"                         \
+        "RMD1 : OWN=%d, ERR=%d, FRAM=%d, OFLO=%d, "     \
+        "CRC=%d, BUFF=%d, STP=%d, ENP=%d,\n       "     \
+        "BPE=%d, PAM=%d, LAFM=%d, BAM=%d, ONES=%d, BCNT=%d\n" \
+        "RMD2 : RCC=%d, RPC=%d, MCNT=%d, ZEROS=%d\n",   \
+        (R)->rbadr,                                     \
+        GET_FIELD((R)->status, RMDS, OWN),              \
+        GET_FIELD((R)->status, RMDS, ERR),              \
+        GET_FIELD((R)->status, RMDS, FRAM),             \
+        GET_FIELD((R)->status, RMDS, OFLO),             \
+        GET_FIELD((R)->status, RMDS, CRC),              \
+        GET_FIELD((R)->status, RMDS, BUFF),             \
+        GET_FIELD((R)->status, RMDS, STP),              \
+        GET_FIELD((R)->status, RMDS, ENP),              \
+        GET_FIELD((R)->status, RMDS, BPE),              \
+        GET_FIELD((R)->status, RMDS, PAM),              \
+        GET_FIELD((R)->status, RMDS, LFAM),             \
+        GET_FIELD((R)->status, RMDS, BAM),              \
+        GET_FIELD((R)->buf_length, RMDL, ONES),         \
+        4096-GET_FIELD((R)->buf_length, RMDL, BCNT),    \
+        GET_FIELD((R)->msg_length, RMDM, RCC),          \
+        GET_FIELD((R)->msg_length, RMDM, RPC),          \
+        GET_FIELD((R)->msg_length, RMDM, MCNT),         \
+        GET_FIELD((R)->msg_length, RMDM, ZEROS))
+
+static inline void pcnet_tmd_load(PCNetState *s, struct pcnet_TMD *tmd,
+                                  hwaddr addr)
+{
+    if (!BCR_SSIZE32(s)) {
+        struct {
+            uint32_t tbadr;
+            int16_t length;
+            int16_t status;
+       } xda;
+        s->phys_mem_read(s->dma_opaque, addr, (void *)&xda, sizeof(xda), 0);
+        tmd->tbadr = le32_to_cpu(xda.tbadr) & 0xffffff;
+        tmd->length = le16_to_cpu(xda.length);
+        tmd->status = (le32_to_cpu(xda.tbadr) >> 16) & 0xff00;
+        tmd->misc = le16_to_cpu(xda.status) << 16;
+        tmd->res = 0;
+    } else {
+        s->phys_mem_read(s->dma_opaque, addr, (void *)tmd, sizeof(*tmd), 0);
+        le32_to_cpus(&tmd->tbadr);
+        le16_to_cpus((uint16_t *)&tmd->length);
+        le16_to_cpus((uint16_t *)&tmd->status);
+        le32_to_cpus(&tmd->misc);
+        le32_to_cpus(&tmd->res);
+        if (BCR_SWSTYLE(s) == 3) {
+            uint32_t tmp = tmd->tbadr;
+            tmd->tbadr = tmd->misc;
+            tmd->misc = tmp;
+        }
+    }
+}
+
+static inline void pcnet_tmd_store(PCNetState *s, const struct pcnet_TMD *tmd,
+                                   hwaddr addr)
+{
+    if (!BCR_SSIZE32(s)) {
+        struct {
+            uint32_t tbadr;
+            int16_t length;
+            int16_t status;
+        } xda;
+        xda.tbadr = cpu_to_le32((tmd->tbadr & 0xffffff) |
+                                ((tmd->status & 0xff00) << 16));
+        xda.length = cpu_to_le16(tmd->length);
+        xda.status = cpu_to_le16(tmd->misc >> 16);
+        s->phys_mem_write(s->dma_opaque, addr, (void *)&xda, sizeof(xda), 0);
+    } else {
+        struct {
+            uint32_t tbadr;
+            int16_t length;
+            int16_t status;
+            uint32_t misc;
+            uint32_t res;
+        } xda;
+        xda.tbadr = cpu_to_le32(tmd->tbadr);
+        xda.length = cpu_to_le16(tmd->length);
+        xda.status = cpu_to_le16(tmd->status);
+        xda.misc = cpu_to_le32(tmd->misc);
+        xda.res = cpu_to_le32(tmd->res);
+        if (BCR_SWSTYLE(s) == 3) {
+            uint32_t tmp = xda.tbadr;
+            xda.tbadr = xda.misc;
+            xda.misc = tmp;
+        }
+        s->phys_mem_write(s->dma_opaque, addr, (void *)&xda, sizeof(xda), 0);
+    }
+}
+
+static inline void pcnet_rmd_load(PCNetState *s, struct pcnet_RMD *rmd,
+                                  hwaddr addr)
+{
+    if (!BCR_SSIZE32(s)) {
+        struct {
+            uint32_t rbadr;
+            int16_t buf_length;
+            int16_t msg_length;
+       } rda;
+        s->phys_mem_read(s->dma_opaque, addr, (void *)&rda, sizeof(rda), 0);
+        rmd->rbadr = le32_to_cpu(rda.rbadr) & 0xffffff;
+        rmd->buf_length = le16_to_cpu(rda.buf_length);
+        rmd->status = (le32_to_cpu(rda.rbadr) >> 16) & 0xff00;
+        rmd->msg_length = le16_to_cpu(rda.msg_length);
+        rmd->res = 0;
+    } else {
+        s->phys_mem_read(s->dma_opaque, addr, (void *)rmd, sizeof(*rmd), 0);
+        le32_to_cpus(&rmd->rbadr);
+        le16_to_cpus((uint16_t *)&rmd->buf_length);
+        le16_to_cpus((uint16_t *)&rmd->status);
+        le32_to_cpus(&rmd->msg_length);
+        le32_to_cpus(&rmd->res);
+        if (BCR_SWSTYLE(s) == 3) {
+            uint32_t tmp = rmd->rbadr;
+            rmd->rbadr = rmd->msg_length;
+            rmd->msg_length = tmp;
+        }
+    }
+}
+
+static inline void pcnet_rmd_store(PCNetState *s, struct pcnet_RMD *rmd,
+                                   hwaddr addr)
+{
+    if (!BCR_SSIZE32(s)) {
+        struct {
+            uint32_t rbadr;
+            int16_t buf_length;
+            int16_t msg_length;
+        } rda;
+        rda.rbadr = cpu_to_le32((rmd->rbadr & 0xffffff) |
+                                ((rmd->status & 0xff00) << 16));
+        rda.buf_length = cpu_to_le16(rmd->buf_length);
+        rda.msg_length = cpu_to_le16(rmd->msg_length);
+        s->phys_mem_write(s->dma_opaque, addr, (void *)&rda, sizeof(rda), 0);
+    } else {
+        struct {
+            uint32_t rbadr;
+            int16_t buf_length;
+            int16_t status;
+            uint32_t msg_length;
+            uint32_t res;
+        } rda;
+        rda.rbadr = cpu_to_le32(rmd->rbadr);
+        rda.buf_length = cpu_to_le16(rmd->buf_length);
+        rda.status = cpu_to_le16(rmd->status);
+        rda.msg_length = cpu_to_le32(rmd->msg_length);
+        rda.res = cpu_to_le32(rmd->res);
+        if (BCR_SWSTYLE(s) == 3) {
+            uint32_t tmp = rda.rbadr;
+            rda.rbadr = rda.msg_length;
+            rda.msg_length = tmp;
+        }
+        s->phys_mem_write(s->dma_opaque, addr, (void *)&rda, sizeof(rda), 0);
+    }
+}
+
+
+#define TMDLOAD(TMD,ADDR) pcnet_tmd_load(s,TMD,ADDR)
+
+#define TMDSTORE(TMD,ADDR) pcnet_tmd_store(s,TMD,ADDR)
+
+#define RMDLOAD(RMD,ADDR) pcnet_rmd_load(s,RMD,ADDR)
+
+#define RMDSTORE(RMD,ADDR) pcnet_rmd_store(s,RMD,ADDR)
+
+#if 1
+
+#define CHECK_RMD(ADDR,RES) do {                \
+    struct pcnet_RMD rmd;                       \
+    RMDLOAD(&rmd,(ADDR));                       \
+    (RES) |= (GET_FIELD(rmd.buf_length, RMDL, ONES) != 15) \
+          || (GET_FIELD(rmd.msg_length, RMDM, ZEROS) != 0); \
+} while (0)
+
+#define CHECK_TMD(ADDR,RES) do {                \
+    struct pcnet_TMD tmd;                       \
+    TMDLOAD(&tmd,(ADDR));                       \
+    (RES) |= (GET_FIELD(tmd.length, TMDL, ONES) != 15); \
+} while (0)
+
+#else
+
+#define CHECK_RMD(ADDR,RES) do {                \
+    switch (BCR_SWSTYLE(s)) {                   \
+    case 0x00:                                  \
+        do {                                    \
+            uint16_t rda[4];                    \
+            s->phys_mem_read(s->dma_opaque, (ADDR), \
+                (void *)&rda[0], sizeof(rda), 0); \
+            (RES) |= (rda[2] & 0xf000)!=0xf000; \
+            (RES) |= (rda[3] & 0xf000)!=0x0000; \
+        } while (0);                            \
+        break;                                  \
+    case 0x01:                                  \
+    case 0x02:                                  \
+        do {                                    \
+            uint32_t rda[4];                    \
+            s->phys_mem_read(s->dma_opaque, (ADDR), \
+                (void *)&rda[0], sizeof(rda), 0); \
+            (RES) |= (rda[1] & 0x0000f000L)!=0x0000f000L; \
+            (RES) |= (rda[2] & 0x0000f000L)!=0x00000000L; \
+        } while (0);                            \
+        break;                                  \
+    case 0x03:                                  \
+        do {                                    \
+            uint32_t rda[4];                    \
+            s->phys_mem_read(s->dma_opaque, (ADDR), \
+                (void *)&rda[0], sizeof(rda), 0); \
+            (RES) |= (rda[0] & 0x0000f000L)!=0x00000000L; \
+            (RES) |= (rda[1] & 0x0000f000L)!=0x0000f000L; \
+        } while (0);                            \
+        break;                                  \
+    }                                           \
+} while (0)
+
+#define CHECK_TMD(ADDR,RES) do {                \
+    switch (BCR_SWSTYLE(s)) {                   \
+    case 0x00:                                  \
+        do {                                    \
+            uint16_t xda[4];                    \
+            s->phys_mem_read(s->dma_opaque, (ADDR), \
+                (void *)&xda[0], sizeof(xda), 0); \
+            (RES) |= (xda[2] & 0xf000)!=0xf000; \
+        } while (0);                            \
+        break;                                  \
+    case 0x01:                                  \
+    case 0x02:                                  \
+    case 0x03:                                  \
+        do {                                    \
+            uint32_t xda[4];                    \
+            s->phys_mem_read(s->dma_opaque, (ADDR), \
+                (void *)&xda[0], sizeof(xda), 0); \
+            (RES) |= (xda[1] & 0x0000f000L)!=0x0000f000L; \
+        } while (0);                            \
+        break;                                  \
+    }                                           \
+} while (0)
+
+#endif
+
+#define PRINT_PKTHDR(BUF) do {                  \
+    struct qemu_ether_header *hdr = (void *)(BUF); \
+    printf("packet dhost=%02x:%02x:%02x:%02x:%02x:%02x, " \
+           "shost=%02x:%02x:%02x:%02x:%02x:%02x, " \
+           "type=0x%04x\n",                     \
+           hdr->ether_dhost[0],hdr->ether_dhost[1],hdr->ether_dhost[2], \
+           hdr->ether_dhost[3],hdr->ether_dhost[4],hdr->ether_dhost[5], \
+           hdr->ether_shost[0],hdr->ether_shost[1],hdr->ether_shost[2], \
+           hdr->ether_shost[3],hdr->ether_shost[4],hdr->ether_shost[5], \
+           be16_to_cpu(hdr->ether_type));       \
+} while (0)
+
+#define MULTICAST_FILTER_LEN 8
+
+static inline uint32_t lnc_mchash(const uint8_t *ether_addr)
+{
+#define LNC_POLYNOMIAL          0xEDB88320UL
+    uint32_t crc = 0xFFFFFFFF;
+    int idx, bit;
+    uint8_t data;
+
+    for (idx = 0; idx < 6; idx++) {
+        for (data = *ether_addr++, bit = 0; bit < MULTICAST_FILTER_LEN; bit++) {
+            crc = (crc >> 1) ^ (((crc ^ data) & 1) ? LNC_POLYNOMIAL : 0);
+            data >>= 1;
+        }
+    }
+    return crc;
+#undef LNC_POLYNOMIAL
+}
+
+#define CRC(crc, ch)    (crc = (crc >> 8) ^ crctab[(crc ^ (ch)) & 0xff])
+
+/* generated using the AUTODIN II polynomial
+ *     x^32 + x^26 + x^23 + x^22 + x^16 +
+ *     x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x^1 + 1
+ */
+static const uint32_t crctab[256] = {
+       0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
+       0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
+       0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+       0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
+       0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
+       0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+       0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
+       0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
+       0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+       0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
+       0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
+       0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+       0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
+       0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
+       0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+       0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
+       0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
+       0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+       0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
+       0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
+       0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+       0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
+       0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
+       0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+       0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
+       0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
+       0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+       0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
+       0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
+       0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+       0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
+       0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
+       0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+       0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
+       0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
+       0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+       0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
+       0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
+       0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+       0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
+       0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
+       0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+       0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
+       0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
+       0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+       0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
+       0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
+       0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+       0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
+       0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
+       0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+       0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
+       0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
+       0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+       0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
+       0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
+       0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+       0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
+       0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
+       0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+       0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
+       0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
+       0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+       0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
+};
+
+static inline int padr_match(PCNetState *s, const uint8_t *buf, int size)
+{
+    struct qemu_ether_header *hdr = (void *)buf;
+    uint8_t padr[6] = {
+        s->csr[12] & 0xff, s->csr[12] >> 8,
+        s->csr[13] & 0xff, s->csr[13] >> 8,
+        s->csr[14] & 0xff, s->csr[14] >> 8
+    };
+    int result = (!CSR_DRCVPA(s)) && !memcmp(hdr->ether_dhost, padr, 6);
+#ifdef PCNET_DEBUG_MATCH
+    printf("packet dhost=%02x:%02x:%02x:%02x:%02x:%02x, "
+           "padr=%02x:%02x:%02x:%02x:%02x:%02x\n",
+           hdr->ether_dhost[0],hdr->ether_dhost[1],hdr->ether_dhost[2],
+           hdr->ether_dhost[3],hdr->ether_dhost[4],hdr->ether_dhost[5],
+           padr[0],padr[1],padr[2],padr[3],padr[4],padr[5]);
+    printf("padr_match result=%d\n", result);
+#endif
+    return result;
+}
+
+static inline int padr_bcast(PCNetState *s, const uint8_t *buf, int size)
+{
+    static const uint8_t BCAST[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+    struct qemu_ether_header *hdr = (void *)buf;
+    int result = !CSR_DRCVBC(s) && !memcmp(hdr->ether_dhost, BCAST, 6);
+#ifdef PCNET_DEBUG_MATCH
+    printf("padr_bcast result=%d\n", result);
+#endif
+    return result;
+}
+
+static inline int ladr_match(PCNetState *s, const uint8_t *buf, int size)
+{
+    struct qemu_ether_header *hdr = (void *)buf;
+    if ((*(hdr->ether_dhost)&0x01) &&
+        ((uint64_t *)&s->csr[8])[0] != 0LL) {
+        uint8_t ladr[8] = {
+            s->csr[8] & 0xff, s->csr[8] >> 8,
+            s->csr[9] & 0xff, s->csr[9] >> 8,
+            s->csr[10] & 0xff, s->csr[10] >> 8,
+            s->csr[11] & 0xff, s->csr[11] >> 8
+        };
+        int index = lnc_mchash(hdr->ether_dhost) >> 26;
+        return !!(ladr[index >> 3] & (1 << (index & 7)));
+    }
+    return 0;
+}
+
+static inline hwaddr pcnet_rdra_addr(PCNetState *s, int idx)
+{
+    while (idx < 1) idx += CSR_RCVRL(s);
+    return s->rdra + ((CSR_RCVRL(s) - idx) * (BCR_SWSTYLE(s) ? 16 : 8));
+}
+
+static inline int64_t pcnet_get_next_poll_time(PCNetState *s, int64_t current_time)
+{
+    int64_t next_time = current_time +
+        muldiv64(65536 - (CSR_SPND(s) ? 0 : CSR_POLL(s)),
+                 get_ticks_per_sec(), 33000000L);
+    if (next_time <= current_time)
+        next_time = current_time + 1;
+    return next_time;
+}
+
+static void pcnet_poll(PCNetState *s);
+static void pcnet_poll_timer(void *opaque);
+
+static uint32_t pcnet_csr_readw(PCNetState *s, uint32_t rap);
+static void pcnet_csr_writew(PCNetState *s, uint32_t rap, uint32_t new_value);
+static void pcnet_bcr_writew(PCNetState *s, uint32_t rap, uint32_t val);
+
+static void pcnet_s_reset(PCNetState *s)
+{
+#ifdef PCNET_DEBUG
+    printf("pcnet_s_reset\n");
+#endif
+
+    s->rdra = 0;
+    s->tdra = 0;
+    s->rap = 0;
+
+    s->bcr[BCR_BSBC] &= ~0x0080;
+
+    s->csr[0]   = 0x0004;
+    s->csr[3]   = 0x0000;
+    s->csr[4]   = 0x0115;
+    s->csr[5]   = 0x0000;
+    s->csr[6]   = 0x0000;
+    s->csr[8]   = 0;
+    s->csr[9]   = 0;
+    s->csr[10]  = 0;
+    s->csr[11]  = 0;
+    s->csr[12]  = le16_to_cpu(((uint16_t *)&s->prom[0])[0]);
+    s->csr[13]  = le16_to_cpu(((uint16_t *)&s->prom[0])[1]);
+    s->csr[14]  = le16_to_cpu(((uint16_t *)&s->prom[0])[2]);
+    s->csr[15] &= 0x21c4;
+    s->csr[72]  = 1;
+    s->csr[74]  = 1;
+    s->csr[76]  = 1;
+    s->csr[78]  = 1;
+    s->csr[80]  = 0x1410;
+    s->csr[88]  = 0x1003;
+    s->csr[89]  = 0x0262;
+    s->csr[94]  = 0x0000;
+    s->csr[100] = 0x0200;
+    s->csr[103] = 0x0105;
+    s->csr[103] = 0x0105;
+    s->csr[112] = 0x0000;
+    s->csr[114] = 0x0000;
+    s->csr[122] = 0x0000;
+    s->csr[124] = 0x0000;
+
+    s->tx_busy = 0;
+}
+
+static void pcnet_update_irq(PCNetState *s)
+{
+    int isr = 0;
+    s->csr[0] &= ~0x0080;
+
+#if 1
+    if (((s->csr[0] & ~s->csr[3]) & 0x5f00) ||
+        (((s->csr[4]>>1) & ~s->csr[4]) & 0x0115) ||
+        (((s->csr[5]>>1) & s->csr[5]) & 0x0048))
+#else
+    if ((!(s->csr[3] & 0x4000) && !!(s->csr[0] & 0x4000)) /* BABL */ ||
+        (!(s->csr[3] & 0x1000) && !!(s->csr[0] & 0x1000)) /* MISS */ ||
+        (!(s->csr[3] & 0x0100) && !!(s->csr[0] & 0x0100)) /* IDON */ ||
+        (!(s->csr[3] & 0x0200) && !!(s->csr[0] & 0x0200)) /* TINT */ ||
+        (!(s->csr[3] & 0x0400) && !!(s->csr[0] & 0x0400)) /* RINT */ ||
+        (!(s->csr[3] & 0x0800) && !!(s->csr[0] & 0x0800)) /* MERR */ ||
+        (!(s->csr[4] & 0x0001) && !!(s->csr[4] & 0x0002)) /* JAB */ ||
+        (!(s->csr[4] & 0x0004) && !!(s->csr[4] & 0x0008)) /* TXSTRT */ ||
+        (!(s->csr[4] & 0x0010) && !!(s->csr[4] & 0x0020)) /* RCVO */ ||
+        (!(s->csr[4] & 0x0100) && !!(s->csr[4] & 0x0200)) /* MFCO */ ||
+        (!!(s->csr[5] & 0x0040) && !!(s->csr[5] & 0x0080)) /* EXDINT */ ||
+        (!!(s->csr[5] & 0x0008) && !!(s->csr[5] & 0x0010)) /* MPINT */)
+#endif
+    {
+
+        isr = CSR_INEA(s);
+        s->csr[0] |= 0x0080;
+    }
+
+    if (!!(s->csr[4] & 0x0080) && CSR_INEA(s)) { /* UINT */
+        s->csr[4] &= ~0x0080;
+        s->csr[4] |= 0x0040;
+        s->csr[0] |= 0x0080;
+        isr = 1;
+#ifdef PCNET_DEBUG
+        printf("pcnet user int\n");
+#endif
+    }
+
+#if 1
+    if (((s->csr[5]>>1) & s->csr[5]) & 0x0500)
+#else
+    if ((!!(s->csr[5] & 0x0400) && !!(s->csr[5] & 0x0800)) /* SINT */ ||
+        (!!(s->csr[5] & 0x0100) && !!(s->csr[5] & 0x0200)) /* SLPINT */ )
+#endif
+    {
+        isr = 1;
+        s->csr[0] |= 0x0080;
+    }
+
+    if (isr != s->isr) {
+#ifdef PCNET_DEBUG
+        printf("pcnet: INTA=%d\n", isr);
+#endif
+    }
+    qemu_set_irq(s->irq, isr);
+    s->isr = isr;
+}
+
+static void pcnet_init(PCNetState *s)
+{
+    int rlen, tlen;
+    uint16_t padr[3], ladrf[4], mode;
+    uint32_t rdra, tdra;
+
+#ifdef PCNET_DEBUG
+    printf("pcnet_init init_addr=0x%08x\n", PHYSADDR(s,CSR_IADR(s)));
+#endif
+
+    if (BCR_SSIZE32(s)) {
+        struct pcnet_initblk32 initblk;
+        s->phys_mem_read(s->dma_opaque, PHYSADDR(s,CSR_IADR(s)),
+                (uint8_t *)&initblk, sizeof(initblk), 0);
+        mode = le16_to_cpu(initblk.mode);
+        rlen = initblk.rlen >> 4;
+        tlen = initblk.tlen >> 4;
+       ladrf[0] = le16_to_cpu(initblk.ladrf[0]);
+       ladrf[1] = le16_to_cpu(initblk.ladrf[1]);
+       ladrf[2] = le16_to_cpu(initblk.ladrf[2]);
+       ladrf[3] = le16_to_cpu(initblk.ladrf[3]);
+       padr[0] = le16_to_cpu(initblk.padr[0]);
+       padr[1] = le16_to_cpu(initblk.padr[1]);
+       padr[2] = le16_to_cpu(initblk.padr[2]);
+        rdra = le32_to_cpu(initblk.rdra);
+        tdra = le32_to_cpu(initblk.tdra);
+    } else {
+        struct pcnet_initblk16 initblk;
+        s->phys_mem_read(s->dma_opaque, PHYSADDR(s,CSR_IADR(s)),
+                (uint8_t *)&initblk, sizeof(initblk), 0);
+        mode = le16_to_cpu(initblk.mode);
+       ladrf[0] = le16_to_cpu(initblk.ladrf[0]);
+       ladrf[1] = le16_to_cpu(initblk.ladrf[1]);
+       ladrf[2] = le16_to_cpu(initblk.ladrf[2]);
+       ladrf[3] = le16_to_cpu(initblk.ladrf[3]);
+       padr[0] = le16_to_cpu(initblk.padr[0]);
+       padr[1] = le16_to_cpu(initblk.padr[1]);
+       padr[2] = le16_to_cpu(initblk.padr[2]);
+        rdra = le32_to_cpu(initblk.rdra);
+        tdra = le32_to_cpu(initblk.tdra);
+        rlen = rdra >> 29;
+        tlen = tdra >> 29;
+        rdra &= 0x00ffffff;
+        tdra &= 0x00ffffff;
+    }
+
+#if defined(PCNET_DEBUG)
+    printf("rlen=%d tlen=%d\n", rlen, tlen);
+#endif
+
+    CSR_RCVRL(s) = (rlen < 9) ? (1 << rlen) : 512;
+    CSR_XMTRL(s) = (tlen < 9) ? (1 << tlen) : 512;
+    s->csr[ 6] = (tlen << 12) | (rlen << 8);
+    s->csr[15] = mode;
+    s->csr[ 8] = ladrf[0];
+    s->csr[ 9] = ladrf[1];
+    s->csr[10] = ladrf[2];
+    s->csr[11] = ladrf[3];
+    s->csr[12] = padr[0];
+    s->csr[13] = padr[1];
+    s->csr[14] = padr[2];
+    s->rdra = PHYSADDR(s, rdra);
+    s->tdra = PHYSADDR(s, tdra);
+
+    CSR_RCVRC(s) = CSR_RCVRL(s);
+    CSR_XMTRC(s) = CSR_XMTRL(s);
+
+#ifdef PCNET_DEBUG
+    printf("pcnet ss32=%d rdra=0x%08x[%d] tdra=0x%08x[%d]\n",
+        BCR_SSIZE32(s),
+        s->rdra, CSR_RCVRL(s), s->tdra, CSR_XMTRL(s));
+#endif
+
+    s->csr[0] |= 0x0101;
+    s->csr[0] &= ~0x0004;       /* clear STOP bit */
+}
+
+static void pcnet_start(PCNetState *s)
+{
+#ifdef PCNET_DEBUG
+    printf("pcnet_start\n");
+#endif
+
+    if (!CSR_DTX(s))
+        s->csr[0] |= 0x0010;    /* set TXON */
+
+    if (!CSR_DRX(s))
+        s->csr[0] |= 0x0020;    /* set RXON */
+
+    s->csr[0] &= ~0x0004;       /* clear STOP bit */
+    s->csr[0] |= 0x0002;
+    pcnet_poll_timer(s);
+}
+
+static void pcnet_stop(PCNetState *s)
+{
+#ifdef PCNET_DEBUG
+    printf("pcnet_stop\n");
+#endif
+    s->csr[0] &= ~0xffeb;
+    s->csr[0] |= 0x0014;
+    s->csr[4] &= ~0x02c2;
+    s->csr[5] &= ~0x0011;
+    pcnet_poll_timer(s);
+}
+
+static void pcnet_rdte_poll(PCNetState *s)
+{
+    s->csr[28] = s->csr[29] = 0;
+    if (s->rdra) {
+        int bad = 0;
+#if 1
+        hwaddr crda = pcnet_rdra_addr(s, CSR_RCVRC(s));
+        hwaddr nrda = pcnet_rdra_addr(s, -1 + CSR_RCVRC(s));
+        hwaddr nnrd = pcnet_rdra_addr(s, -2 + CSR_RCVRC(s));
+#else
+        hwaddr crda = s->rdra +
+            (CSR_RCVRL(s) - CSR_RCVRC(s)) *
+            (BCR_SWSTYLE(s) ? 16 : 8 );
+        int nrdc = CSR_RCVRC(s)<=1 ? CSR_RCVRL(s) : CSR_RCVRC(s)-1;
+        hwaddr nrda = s->rdra +
+            (CSR_RCVRL(s) - nrdc) *
+            (BCR_SWSTYLE(s) ? 16 : 8 );
+        int nnrc = nrdc<=1 ? CSR_RCVRL(s) : nrdc-1;
+        hwaddr nnrd = s->rdra +
+            (CSR_RCVRL(s) - nnrc) *
+            (BCR_SWSTYLE(s) ? 16 : 8 );
+#endif
+
+        CHECK_RMD(crda, bad);
+        if (!bad) {
+            CHECK_RMD(nrda, bad);
+            if (bad || (nrda == crda)) nrda = 0;
+            CHECK_RMD(nnrd, bad);
+            if (bad || (nnrd == crda)) nnrd = 0;
+
+            s->csr[28] = crda & 0xffff;
+            s->csr[29] = crda >> 16;
+            s->csr[26] = nrda & 0xffff;
+            s->csr[27] = nrda >> 16;
+            s->csr[36] = nnrd & 0xffff;
+            s->csr[37] = nnrd >> 16;
+#ifdef PCNET_DEBUG
+            if (bad) {
+                printf("pcnet: BAD RMD RECORDS AFTER 0x" TARGET_FMT_plx "\n",
+                       crda);
+            }
+        } else {
+            printf("pcnet: BAD RMD RDA=0x" TARGET_FMT_plx "\n",
+                   crda);
+#endif
+        }
+    }
+
+    if (CSR_CRDA(s)) {
+        struct pcnet_RMD rmd;
+        RMDLOAD(&rmd, PHYSADDR(s,CSR_CRDA(s)));
+        CSR_CRBC(s) = GET_FIELD(rmd.buf_length, RMDL, BCNT);
+        CSR_CRST(s) = rmd.status;
+#ifdef PCNET_DEBUG_RMD_X
+        printf("CRDA=0x%08x CRST=0x%04x RCVRC=%d RMDL=0x%04x RMDS=0x%04x RMDM=0x%08x\n",
+                PHYSADDR(s,CSR_CRDA(s)), CSR_CRST(s), CSR_RCVRC(s),
+                rmd.buf_length, rmd.status, rmd.msg_length);
+        PRINT_RMD(&rmd);
+#endif
+    } else {
+        CSR_CRBC(s) = CSR_CRST(s) = 0;
+    }
+
+    if (CSR_NRDA(s)) {
+        struct pcnet_RMD rmd;
+        RMDLOAD(&rmd, PHYSADDR(s,CSR_NRDA(s)));
+        CSR_NRBC(s) = GET_FIELD(rmd.buf_length, RMDL, BCNT);
+        CSR_NRST(s) = rmd.status;
+    } else {
+        CSR_NRBC(s) = CSR_NRST(s) = 0;
+    }
+
+}
+
+static int pcnet_tdte_poll(PCNetState *s)
+{
+    s->csr[34] = s->csr[35] = 0;
+    if (s->tdra) {
+        hwaddr cxda = s->tdra +
+            (CSR_XMTRL(s) - CSR_XMTRC(s)) *
+            (BCR_SWSTYLE(s) ? 16 : 8);
+        int bad = 0;
+        CHECK_TMD(cxda, bad);
+        if (!bad) {
+            if (CSR_CXDA(s) != cxda) {
+                s->csr[60] = s->csr[34];
+                s->csr[61] = s->csr[35];
+                s->csr[62] = CSR_CXBC(s);
+                s->csr[63] = CSR_CXST(s);
+            }
+            s->csr[34] = cxda & 0xffff;
+            s->csr[35] = cxda >> 16;
+#ifdef PCNET_DEBUG_X
+            printf("pcnet: BAD TMD XDA=0x%08x\n", cxda);
+#endif
+        }
+    }
+
+    if (CSR_CXDA(s)) {
+        struct pcnet_TMD tmd;
+
+        TMDLOAD(&tmd, PHYSADDR(s,CSR_CXDA(s)));
+
+        CSR_CXBC(s) = GET_FIELD(tmd.length, TMDL, BCNT);
+        CSR_CXST(s) = tmd.status;
+    } else {
+        CSR_CXBC(s) = CSR_CXST(s) = 0;
+    }
+
+    return !!(CSR_CXST(s) & 0x8000);
+}
+
+int pcnet_can_receive(NetClientState *nc)
+{
+    PCNetState *s = qemu_get_nic_opaque(nc);
+    if (CSR_STOP(s) || CSR_SPND(s))
+        return 0;
+
+    return sizeof(s->buffer)-16;
+}
+
+#define MIN_BUF_SIZE 60
+
+ssize_t pcnet_receive(NetClientState *nc, const uint8_t *buf, size_t size_)
+{
+    PCNetState *s = qemu_get_nic_opaque(nc);
+    int is_padr = 0, is_bcast = 0, is_ladr = 0;
+    uint8_t buf1[60];
+    int remaining;
+    int crc_err = 0;
+    int size = size_;
+
+    if (CSR_DRX(s) || CSR_STOP(s) || CSR_SPND(s) || !size ||
+        (CSR_LOOP(s) && !s->looptest)) {
+        return -1;
+    }
+#ifdef PCNET_DEBUG
+    printf("pcnet_receive size=%d\n", size);
+#endif
+
+    /* if too small buffer, then expand it */
+    if (size < MIN_BUF_SIZE) {
+        memcpy(buf1, buf, size);
+        memset(buf1 + size, 0, MIN_BUF_SIZE - size);
+        buf = buf1;
+        size = MIN_BUF_SIZE;
+    }
+
+    if (CSR_PROM(s)
+        || (is_padr=padr_match(s, buf, size))
+        || (is_bcast=padr_bcast(s, buf, size))
+        || (is_ladr=ladr_match(s, buf, size))) {
+
+        pcnet_rdte_poll(s);
+
+        if (!(CSR_CRST(s) & 0x8000) && s->rdra) {
+            struct pcnet_RMD rmd;
+            int rcvrc = CSR_RCVRC(s)-1,i;
+            hwaddr nrda;
+            for (i = CSR_RCVRL(s)-1; i > 0; i--, rcvrc--) {
+                if (rcvrc <= 1)
+                    rcvrc = CSR_RCVRL(s);
+                nrda = s->rdra +
+                    (CSR_RCVRL(s) - rcvrc) *
+                    (BCR_SWSTYLE(s) ? 16 : 8 );
+                RMDLOAD(&rmd, nrda);
+                if (GET_FIELD(rmd.status, RMDS, OWN)) {
+#ifdef PCNET_DEBUG_RMD
+                    printf("pcnet - scan buffer: RCVRC=%d PREV_RCVRC=%d\n",
+                                rcvrc, CSR_RCVRC(s));
+#endif
+                    CSR_RCVRC(s) = rcvrc;
+                    pcnet_rdte_poll(s);
+                    break;
+                }
+            }
+        }
+
+        if (!(CSR_CRST(s) & 0x8000)) {
+#ifdef PCNET_DEBUG_RMD
+            printf("pcnet - no buffer: RCVRC=%d\n", CSR_RCVRC(s));
+#endif
+            s->csr[0] |= 0x1000; /* Set MISS flag */
+            CSR_MISSC(s)++;
+        } else {
+            uint8_t *src = s->buffer;
+            hwaddr crda = CSR_CRDA(s);
+            struct pcnet_RMD rmd;
+            int pktcount = 0;
+
+            if (!s->looptest) {
+                memcpy(src, buf, size);
+                /* no need to compute the CRC */
+                src[size] = 0;
+                src[size + 1] = 0;
+                src[size + 2] = 0;
+                src[size + 3] = 0;
+                size += 4;
+            } else if (s->looptest == PCNET_LOOPTEST_CRC ||
+                       !CSR_DXMTFCS(s) || size < MIN_BUF_SIZE+4) {
+                uint32_t fcs = ~0;
+                uint8_t *p = src;
+
+                while (p != &src[size])
+                    CRC(fcs, *p++);
+                *(uint32_t *)p = htonl(fcs);
+                size += 4;
+            } else {
+                uint32_t fcs = ~0;
+                uint8_t *p = src;
+
+                while (p != &src[size-4])
+                    CRC(fcs, *p++);
+                crc_err = (*(uint32_t *)p != htonl(fcs));
+            }
+
+#ifdef PCNET_DEBUG_MATCH
+            PRINT_PKTHDR(buf);
+#endif
+
+            RMDLOAD(&rmd, PHYSADDR(s,crda));
+            /*if (!CSR_LAPPEN(s))*/
+                SET_FIELD(&rmd.status, RMDS, STP, 1);
+
+#define PCNET_RECV_STORE() do {                                 \
+    int count = MIN(4096 - GET_FIELD(rmd.buf_length, RMDL, BCNT),remaining); \
+    hwaddr rbadr = PHYSADDR(s, rmd.rbadr);          \
+    s->phys_mem_write(s->dma_opaque, rbadr, src, count, CSR_BSWP(s)); \
+    src += count; remaining -= count;                           \
+    SET_FIELD(&rmd.status, RMDS, OWN, 0);                       \
+    RMDSTORE(&rmd, PHYSADDR(s,crda));                           \
+    pktcount++;                                                 \
+} while (0)
+
+            remaining = size;
+            PCNET_RECV_STORE();
+            if ((remaining > 0) && CSR_NRDA(s)) {
+                hwaddr nrda = CSR_NRDA(s);
+#ifdef PCNET_DEBUG_RMD
+                PRINT_RMD(&rmd);
+#endif
+                RMDLOAD(&rmd, PHYSADDR(s,nrda));
+                if (GET_FIELD(rmd.status, RMDS, OWN)) {
+                    crda = nrda;
+                    PCNET_RECV_STORE();
+#ifdef PCNET_DEBUG_RMD
+                    PRINT_RMD(&rmd);
+#endif
+                    if ((remaining > 0) && (nrda=CSR_NNRD(s))) {
+                        RMDLOAD(&rmd, PHYSADDR(s,nrda));
+                        if (GET_FIELD(rmd.status, RMDS, OWN)) {
+                            crda = nrda;
+                            PCNET_RECV_STORE();
+                        }
+                    }
+                }
+            }
+
+#undef PCNET_RECV_STORE
+
+            RMDLOAD(&rmd, PHYSADDR(s,crda));
+            if (remaining == 0) {
+                SET_FIELD(&rmd.msg_length, RMDM, MCNT, size);
+                SET_FIELD(&rmd.status, RMDS, ENP, 1);
+                SET_FIELD(&rmd.status, RMDS, PAM, !CSR_PROM(s) && is_padr);
+                SET_FIELD(&rmd.status, RMDS, LFAM, !CSR_PROM(s) && is_ladr);
+                SET_FIELD(&rmd.status, RMDS, BAM, !CSR_PROM(s) && is_bcast);
+                if (crc_err) {
+                    SET_FIELD(&rmd.status, RMDS, CRC, 1);
+                    SET_FIELD(&rmd.status, RMDS, ERR, 1);
+                }
+            } else {
+                SET_FIELD(&rmd.status, RMDS, OFLO, 1);
+                SET_FIELD(&rmd.status, RMDS, BUFF, 1);
+                SET_FIELD(&rmd.status, RMDS, ERR, 1);
+            }
+            RMDSTORE(&rmd, PHYSADDR(s,crda));
+            s->csr[0] |= 0x0400;
+
+#ifdef PCNET_DEBUG
+            printf("RCVRC=%d CRDA=0x%08x BLKS=%d\n",
+                CSR_RCVRC(s), PHYSADDR(s,CSR_CRDA(s)), pktcount);
+#endif
+#ifdef PCNET_DEBUG_RMD
+            PRINT_RMD(&rmd);
+#endif
+
+            while (pktcount--) {
+                if (CSR_RCVRC(s) <= 1)
+                    CSR_RCVRC(s) = CSR_RCVRL(s);
+                else
+                    CSR_RCVRC(s)--;
+            }
+
+            pcnet_rdte_poll(s);
+
+        }
+    }
+
+    pcnet_poll(s);
+    pcnet_update_irq(s);
+
+    return size_;
+}
+
+void pcnet_set_link_status(NetClientState *nc)
+{
+    PCNetState *d = qemu_get_nic_opaque(nc);
+
+    d->lnkst = nc->link_down ? 0 : 0x40;
+}
+
+static void pcnet_transmit(PCNetState *s)
+{
+    hwaddr xmit_cxda = 0;
+    int count = CSR_XMTRL(s)-1;
+    int add_crc = 0;
+
+    s->xmit_pos = -1;
+
+    if (!CSR_TXON(s)) {
+        s->csr[0] &= ~0x0008;
+        return;
+    }
+
+    s->tx_busy = 1;
+
+    txagain:
+    if (pcnet_tdte_poll(s)) {
+        struct pcnet_TMD tmd;
+
+        TMDLOAD(&tmd, PHYSADDR(s,CSR_CXDA(s)));
+
+#ifdef PCNET_DEBUG_TMD
+        printf("  TMDLOAD 0x%08x\n", PHYSADDR(s,CSR_CXDA(s)));
+        PRINT_TMD(&tmd);
+#endif
+        if (GET_FIELD(tmd.status, TMDS, STP)) {
+            s->xmit_pos = 0;
+            xmit_cxda = PHYSADDR(s,CSR_CXDA(s));
+            if (BCR_SWSTYLE(s) != 1)
+                add_crc = GET_FIELD(tmd.status, TMDS, ADDFCS);
+        }
+        if (s->lnkst == 0 &&
+            (!CSR_LOOP(s) || (!CSR_INTL(s) && !BCR_TMAULOOP(s)))) {
+            SET_FIELD(&tmd.misc, TMDM, LCAR, 1);
+            SET_FIELD(&tmd.status, TMDS, ERR, 1);
+            SET_FIELD(&tmd.status, TMDS, OWN, 0);
+            s->csr[0] |= 0xa000; /* ERR | CERR */
+            s->xmit_pos = -1;
+            goto txdone;
+        }
+        if (!GET_FIELD(tmd.status, TMDS, ENP)) {
+            int bcnt = 4096 - GET_FIELD(tmd.length, TMDL, BCNT);
+            s->phys_mem_read(s->dma_opaque, PHYSADDR(s, tmd.tbadr),
+                             s->buffer + s->xmit_pos, bcnt, CSR_BSWP(s));
+            s->xmit_pos += bcnt;
+        } else if (s->xmit_pos >= 0) {
+            int bcnt = 4096 - GET_FIELD(tmd.length, TMDL, BCNT);
+            s->phys_mem_read(s->dma_opaque, PHYSADDR(s, tmd.tbadr),
+                             s->buffer + s->xmit_pos, bcnt, CSR_BSWP(s));
+            s->xmit_pos += bcnt;
+#ifdef PCNET_DEBUG
+            printf("pcnet_transmit size=%d\n", s->xmit_pos);
+#endif
+            if (CSR_LOOP(s)) {
+                if (BCR_SWSTYLE(s) == 1)
+                    add_crc = !GET_FIELD(tmd.status, TMDS, NOFCS);
+                s->looptest = add_crc ? PCNET_LOOPTEST_CRC : PCNET_LOOPTEST_NOCRC;
+                pcnet_receive(qemu_get_queue(s->nic), s->buffer, s->xmit_pos);
+                s->looptest = 0;
+            } else
+                if (s->nic)
+                    qemu_send_packet(qemu_get_queue(s->nic), s->buffer,
+                                     s->xmit_pos);
+
+            s->csr[0] &= ~0x0008;   /* clear TDMD */
+            s->csr[4] |= 0x0004;    /* set TXSTRT */
+            s->xmit_pos = -1;
+        }
+
+    txdone:
+        SET_FIELD(&tmd.status, TMDS, OWN, 0);
+        TMDSTORE(&tmd, PHYSADDR(s,CSR_CXDA(s)));
+        if (!CSR_TOKINTD(s) || (CSR_LTINTEN(s) && GET_FIELD(tmd.status, TMDS, LTINT)))
+            s->csr[0] |= 0x0200;    /* set TINT */
+
+        if (CSR_XMTRC(s)<=1)
+            CSR_XMTRC(s) = CSR_XMTRL(s);
+        else
+            CSR_XMTRC(s)--;
+        if (count--)
+            goto txagain;
+
+    } else
+    if (s->xmit_pos >= 0) {
+        struct pcnet_TMD tmd;
+        TMDLOAD(&tmd, xmit_cxda);
+        SET_FIELD(&tmd.misc, TMDM, BUFF, 1);
+        SET_FIELD(&tmd.misc, TMDM, UFLO, 1);
+        SET_FIELD(&tmd.status, TMDS, ERR, 1);
+        SET_FIELD(&tmd.status, TMDS, OWN, 0);
+        TMDSTORE(&tmd, xmit_cxda);
+        s->csr[0] |= 0x0200;    /* set TINT */
+        if (!CSR_DXSUFLO(s)) {
+            s->csr[0] &= ~0x0010;
+        } else
+        if (count--)
+          goto txagain;
+    }
+
+    s->tx_busy = 0;
+}
+
+static void pcnet_poll(PCNetState *s)
+{
+    if (CSR_RXON(s)) {
+        pcnet_rdte_poll(s);
+    }
+
+    if (CSR_TDMD(s) ||
+        (CSR_TXON(s) && !CSR_DPOLL(s) && pcnet_tdte_poll(s)))
+    {
+        /* prevent recursion */
+        if (s->tx_busy)
+            return;
+
+        pcnet_transmit(s);
+    }
+}
+
+static void pcnet_poll_timer(void *opaque)
+{
+    PCNetState *s = opaque;
+
+    qemu_del_timer(s->poll_timer);
+
+    if (CSR_TDMD(s)) {
+        pcnet_transmit(s);
+    }
+
+    pcnet_update_irq(s);
+
+    if (!CSR_STOP(s) && !CSR_SPND(s) && !CSR_DPOLL(s)) {
+        uint64_t now = qemu_get_clock_ns(vm_clock) * 33;
+        if (!s->timer || !now)
+            s->timer = now;
+        else {
+            uint64_t t = now - s->timer + CSR_POLL(s);
+            if (t > 0xffffLL) {
+                pcnet_poll(s);
+                CSR_POLL(s) = CSR_PINT(s);
+            } else
+                CSR_POLL(s) = t;
+        }
+        qemu_mod_timer(s->poll_timer,
+            pcnet_get_next_poll_time(s,qemu_get_clock_ns(vm_clock)));
+    }
+}
+
+
+static void pcnet_csr_writew(PCNetState *s, uint32_t rap, uint32_t new_value)
+{
+    uint16_t val = new_value;
+#ifdef PCNET_DEBUG_CSR
+    printf("pcnet_csr_writew rap=%d val=0x%04x\n", rap, val);
+#endif
+    switch (rap) {
+    case 0:
+        s->csr[0] &= ~(val & 0x7f00); /* Clear any interrupt flags */
+
+        s->csr[0] = (s->csr[0] & ~0x0040) | (val & 0x0048);
+
+        val = (val & 0x007f) | (s->csr[0] & 0x7f00);
+
+        /* IFF STOP, STRT and INIT are set, clear STRT and INIT */
+        if ((val&7) == 7)
+          val &= ~3;
+
+        if (!CSR_STOP(s) && (val & 4))
+            pcnet_stop(s);
+
+        if (!CSR_INIT(s) && (val & 1))
+            pcnet_init(s);
+
+        if (!CSR_STRT(s) && (val & 2))
+            pcnet_start(s);
+
+        if (CSR_TDMD(s))
+            pcnet_transmit(s);
+
+        return;
+    case 1:
+    case 2:
+    case 8:
+    case 9:
+    case 10:
+    case 11:
+    case 12:
+    case 13:
+    case 14:
+    case 15:
+    case 18: /* CRBAL */
+    case 19: /* CRBAU */
+    case 20: /* CXBAL */
+    case 21: /* CXBAU */
+    case 22: /* NRBAU */
+    case 23: /* NRBAU */
+    case 24:
+    case 25:
+    case 26:
+    case 27:
+    case 28:
+    case 29:
+    case 30:
+    case 31:
+    case 32:
+    case 33:
+    case 34:
+    case 35:
+    case 36:
+    case 37:
+    case 38:
+    case 39:
+    case 40: /* CRBC */
+    case 41:
+    case 42: /* CXBC */
+    case 43:
+    case 44:
+    case 45:
+    case 46: /* POLL */
+    case 47: /* POLLINT */
+    case 72:
+    case 74:
+    case 76: /* RCVRL */
+    case 78: /* XMTRL */
+    case 112:
+       if (CSR_STOP(s) || CSR_SPND(s))
+           break;
+       return;
+    case 3:
+        break;
+    case 4:
+        s->csr[4] &= ~(val & 0x026a);
+        val &= ~0x026a; val |= s->csr[4] & 0x026a;
+        break;
+    case 5:
+        s->csr[5] &= ~(val & 0x0a90);
+        val &= ~0x0a90; val |= s->csr[5] & 0x0a90;
+        break;
+    case 16:
+        pcnet_csr_writew(s,1,val);
+        return;
+    case 17:
+        pcnet_csr_writew(s,2,val);
+        return;
+    case 58:
+        pcnet_bcr_writew(s,BCR_SWS,val);
+        break;
+    default:
+        return;
+    }
+    s->csr[rap] = val;
+}
+
+static uint32_t pcnet_csr_readw(PCNetState *s, uint32_t rap)
+{
+    uint32_t val;
+    switch (rap) {
+    case 0:
+        pcnet_update_irq(s);
+        val = s->csr[0];
+        val |= (val & 0x7800) ? 0x8000 : 0;
+        break;
+    case 16:
+        return pcnet_csr_readw(s,1);
+    case 17:
+        return pcnet_csr_readw(s,2);
+    case 58:
+        return pcnet_bcr_readw(s,BCR_SWS);
+    case 88:
+        val = s->csr[89];
+        val <<= 16;
+        val |= s->csr[88];
+        break;
+    default:
+        val = s->csr[rap];
+    }
+#ifdef PCNET_DEBUG_CSR
+    printf("pcnet_csr_readw rap=%d val=0x%04x\n", rap, val);
+#endif
+    return val;
+}
+
+static void pcnet_bcr_writew(PCNetState *s, uint32_t rap, uint32_t val)
+{
+    rap &= 127;
+#ifdef PCNET_DEBUG_BCR
+    printf("pcnet_bcr_writew rap=%d val=0x%04x\n", rap, val);
+#endif
+    switch (rap) {
+    case BCR_SWS:
+        if (!(CSR_STOP(s) || CSR_SPND(s)))
+            return;
+        val &= ~0x0300;
+        switch (val & 0x00ff) {
+        case 0:
+            val |= 0x0200;
+            break;
+        case 1:
+            val |= 0x0100;
+            break;
+        case 2:
+        case 3:
+            val |= 0x0300;
+            break;
+        default:
+            printf("Bad SWSTYLE=0x%02x\n", val & 0xff);
+            val = 0x0200;
+            break;
+        }
+#ifdef PCNET_DEBUG
+       printf("BCR_SWS=0x%04x\n", val);
+#endif
+        /* fall through */
+    case BCR_LNKST:
+    case BCR_LED1:
+    case BCR_LED2:
+    case BCR_LED3:
+    case BCR_MC:
+    case BCR_FDC:
+    case BCR_BSBC:
+    case BCR_EECAS:
+    case BCR_PLAT:
+        s->bcr[rap] = val;
+        break;
+    default:
+        break;
+    }
+}
+
+uint32_t pcnet_bcr_readw(PCNetState *s, uint32_t rap)
+{
+    uint32_t val;
+    rap &= 127;
+    switch (rap) {
+    case BCR_LNKST:
+    case BCR_LED1:
+    case BCR_LED2:
+    case BCR_LED3:
+        val = s->bcr[rap] & ~0x8000;
+        val |= (val & 0x017f & s->lnkst) ? 0x8000 : 0;
+        break;
+    default:
+        val = rap < 32 ? s->bcr[rap] : 0;
+        break;
+    }
+#ifdef PCNET_DEBUG_BCR
+    printf("pcnet_bcr_readw rap=%d val=0x%04x\n", rap, val);
+#endif
+    return val;
+}
+
+void pcnet_h_reset(void *opaque)
+{
+    PCNetState *s = opaque;
+
+    s->bcr[BCR_MSRDA] = 0x0005;
+    s->bcr[BCR_MSWRA] = 0x0005;
+    s->bcr[BCR_MC   ] = 0x0002;
+    s->bcr[BCR_LNKST] = 0x00c0;
+    s->bcr[BCR_LED1 ] = 0x0084;
+    s->bcr[BCR_LED2 ] = 0x0088;
+    s->bcr[BCR_LED3 ] = 0x0090;
+    s->bcr[BCR_FDC  ] = 0x0000;
+    s->bcr[BCR_BSBC ] = 0x9001;
+    s->bcr[BCR_EECAS] = 0x0002;
+    s->bcr[BCR_SWS  ] = 0x0200;
+    s->bcr[BCR_PLAT ] = 0xff06;
+
+    pcnet_s_reset(s);
+    pcnet_update_irq(s);
+    pcnet_poll_timer(s);
+}
+
+void pcnet_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
+{
+    PCNetState *s = opaque;
+    pcnet_poll_timer(s);
+#ifdef PCNET_DEBUG_IO
+    printf("pcnet_ioport_writew addr=0x%08x val=0x%04x\n", addr, val);
+#endif
+    if (!BCR_DWIO(s)) {
+        switch (addr & 0x0f) {
+        case 0x00: /* RDP */
+            pcnet_csr_writew(s, s->rap, val);
+            break;
+        case 0x02:
+            s->rap = val & 0x7f;
+            break;
+        case 0x06:
+            pcnet_bcr_writew(s, s->rap, val);
+            break;
+        }
+    }
+    pcnet_update_irq(s);
+}
+
+uint32_t pcnet_ioport_readw(void *opaque, uint32_t addr)
+{
+    PCNetState *s = opaque;
+    uint32_t val = -1;
+    pcnet_poll_timer(s);
+    if (!BCR_DWIO(s)) {
+        switch (addr & 0x0f) {
+        case 0x00: /* RDP */
+            val = pcnet_csr_readw(s, s->rap);
+            break;
+        case 0x02:
+            val = s->rap;
+            break;
+        case 0x04:
+            pcnet_s_reset(s);
+            val = 0;
+            break;
+        case 0x06:
+            val = pcnet_bcr_readw(s, s->rap);
+            break;
+        }
+    }
+    pcnet_update_irq(s);
+#ifdef PCNET_DEBUG_IO
+    printf("pcnet_ioport_readw addr=0x%08x val=0x%04x\n", addr, val & 0xffff);
+#endif
+    return val;
+}
+
+void pcnet_ioport_writel(void *opaque, uint32_t addr, uint32_t val)
+{
+    PCNetState *s = opaque;
+    pcnet_poll_timer(s);
+#ifdef PCNET_DEBUG_IO
+    printf("pcnet_ioport_writel addr=0x%08x val=0x%08x\n", addr, val);
+#endif
+    if (BCR_DWIO(s)) {
+        switch (addr & 0x0f) {
+        case 0x00: /* RDP */
+            pcnet_csr_writew(s, s->rap, val & 0xffff);
+            break;
+        case 0x04:
+            s->rap = val & 0x7f;
+            break;
+        case 0x0c:
+            pcnet_bcr_writew(s, s->rap, val & 0xffff);
+            break;
+        }
+    } else
+    if ((addr & 0x0f) == 0) {
+        /* switch device to dword i/o mode */
+        pcnet_bcr_writew(s, BCR_BSBC, pcnet_bcr_readw(s, BCR_BSBC) | 0x0080);
+#ifdef PCNET_DEBUG_IO
+        printf("device switched into dword i/o mode\n");
+#endif
+    }
+    pcnet_update_irq(s);
+}
+
+uint32_t pcnet_ioport_readl(void *opaque, uint32_t addr)
+{
+    PCNetState *s = opaque;
+    uint32_t val = -1;
+    pcnet_poll_timer(s);
+    if (BCR_DWIO(s)) {
+        switch (addr & 0x0f) {
+        case 0x00: /* RDP */
+            val = pcnet_csr_readw(s, s->rap);
+            break;
+        case 0x04:
+            val = s->rap;
+            break;
+        case 0x08:
+            pcnet_s_reset(s);
+            val = 0;
+            break;
+        case 0x0c:
+            val = pcnet_bcr_readw(s, s->rap);
+            break;
+        }
+    }
+    pcnet_update_irq(s);
+#ifdef PCNET_DEBUG_IO
+    printf("pcnet_ioport_readl addr=0x%08x val=0x%08x\n", addr, val);
+#endif
+    return val;
+}
+
+static bool is_version_2(void *opaque, int version_id)
+{
+    return version_id == 2;
+}
+
+const VMStateDescription vmstate_pcnet = {
+    .name = "pcnet",
+    .version_id = 3,
+    .minimum_version_id = 2,
+    .minimum_version_id_old = 2,
+    .fields      = (VMStateField []) {
+        VMSTATE_INT32(rap, PCNetState),
+        VMSTATE_INT32(isr, PCNetState),
+        VMSTATE_INT32(lnkst, PCNetState),
+        VMSTATE_UINT32(rdra, PCNetState),
+        VMSTATE_UINT32(tdra, PCNetState),
+        VMSTATE_BUFFER(prom, PCNetState),
+        VMSTATE_UINT16_ARRAY(csr, PCNetState, 128),
+        VMSTATE_UINT16_ARRAY(bcr, PCNetState, 32),
+        VMSTATE_UINT64(timer, PCNetState),
+        VMSTATE_INT32(xmit_pos, PCNetState),
+        VMSTATE_BUFFER(buffer, PCNetState),
+        VMSTATE_UNUSED_TEST(is_version_2, 4),
+        VMSTATE_INT32(tx_busy, PCNetState),
+        VMSTATE_TIMER(poll_timer, PCNetState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+void pcnet_common_cleanup(PCNetState *d)
+{
+    d->nic = NULL;
+}
+
+int pcnet_common_init(DeviceState *dev, PCNetState *s, NetClientInfo *info)
+{
+    int i;
+    uint16_t checksum;
+
+    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, object_get_typename(OBJECT(dev)), dev->id, s);
+    qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
+
+    add_boot_device_path(s->conf.bootindex, dev, "/ethernet-phy@0");
+
+    /* Initialize the PROM */
+
+    /*
+      Datasheet: http://pdfdata.datasheetsite.com/web/24528/AM79C970A.pdf
+      page 95
+    */
+    memcpy(s->prom, s->conf.macaddr.a, 6);
+    /* Reserved Location: must be 00h */
+    s->prom[6] = s->prom[7] = 0x00;
+    /* Reserved Location: must be 00h */
+    s->prom[8] = 0x00;
+    /* Hardware ID: must be 11h if compatibility to AMD drivers is desired */
+    s->prom[9] = 0x11;
+    /* User programmable space, init with 0 */
+    s->prom[10] = s->prom[11] = 0x00;
+    /* LSByte of two-byte checksum, which is the sum of bytes 00h-0Bh
+       and bytes 0Eh and 0Fh, must therefore be initialized with 0! */
+    s->prom[12] = s->prom[13] = 0x00;
+    /* Must be ASCII W (57h) if compatibility to AMD
+       driver software is desired */
+    s->prom[14] = s->prom[15] = 0x57;
+
+    for (i = 0, checksum = 0; i < 16; i++) {
+        checksum += s->prom[i];
+    }
+    *(uint16_t *)&s->prom[12] = cpu_to_le16(checksum);
+
+    s->lnkst = 0x40; /* initial link state: up */
+
+    return 0;
+}
diff --git a/hw/net/pcnet.h b/hw/net/pcnet.h
new file mode 100644 (file)
index 0000000..9dee6f3
--- /dev/null
@@ -0,0 +1,70 @@
+#ifndef HW_PCNET_H
+#define HW_PCNET_H 1
+
+#define PCNET_IOPORT_SIZE       0x20
+#define PCNET_PNPMMIO_SIZE      0x20
+
+#define PCNET_LOOPTEST_CRC     1
+#define PCNET_LOOPTEST_NOCRC   2
+
+#include "exec/memory.h"
+
+/* BUS CONFIGURATION REGISTERS */
+#define BCR_MSRDA    0
+#define BCR_MSWRA    1
+#define BCR_MC       2
+#define BCR_LNKST    4
+#define BCR_LED1     5
+#define BCR_LED2     6
+#define BCR_LED3     7
+#define BCR_FDC      9
+#define BCR_BSBC     18
+#define BCR_EECAS    19
+#define BCR_SWS      20
+#define BCR_PLAT     22
+
+#define BCR_TMAULOOP(S)  !!((S)->bcr[BCR_MC  ] & 0x4000)
+#define BCR_APROMWE(S)   !!((S)->bcr[BCR_MC  ] & 0x0100)
+#define BCR_DWIO(S)      !!((S)->bcr[BCR_BSBC] & 0x0080)
+#define BCR_SSIZE32(S)   !!((S)->bcr[BCR_SWS ] & 0x0100)
+#define BCR_SWSTYLE(S)     ((S)->bcr[BCR_SWS ] & 0x00FF)
+
+typedef struct PCNetState_st PCNetState;
+
+struct PCNetState_st {
+    NICState *nic;
+    NICConf conf;
+    QEMUTimer *poll_timer;
+    int rap, isr, lnkst;
+    uint32_t rdra, tdra;
+    uint8_t prom[16];
+    uint16_t csr[128];
+    uint16_t bcr[32];
+    int xmit_pos;
+    uint64_t timer;
+    MemoryRegion mmio;
+    uint8_t buffer[4096];
+    qemu_irq irq;
+    void (*phys_mem_read)(void *dma_opaque, hwaddr addr,
+                         uint8_t *buf, int len, int do_bswap);
+    void (*phys_mem_write)(void *dma_opaque, hwaddr addr,
+                          uint8_t *buf, int len, int do_bswap);
+    void *dma_opaque;
+    int tx_busy;
+    int looptest;
+};
+
+void pcnet_h_reset(void *opaque);
+void pcnet_ioport_writew(void *opaque, uint32_t addr, uint32_t val);
+uint32_t pcnet_ioport_readw(void *opaque, uint32_t addr);
+void pcnet_ioport_writel(void *opaque, uint32_t addr, uint32_t val);
+uint32_t pcnet_ioport_readl(void *opaque, uint32_t addr);
+uint32_t pcnet_bcr_readw(PCNetState *s, uint32_t rap);
+int pcnet_can_receive(NetClientState *nc);
+ssize_t pcnet_receive(NetClientState *nc, const uint8_t *buf, size_t size_);
+void pcnet_set_link_status(NetClientState *nc);
+void pcnet_common_cleanup(PCNetState *d);
+int pcnet_common_init(DeviceState *dev, PCNetState *s, NetClientInfo *info);
+extern const VMStateDescription vmstate_pcnet;
+
+#endif
diff --git a/hw/net/rtl8139.c b/hw/net/rtl8139.c
new file mode 100644 (file)
index 0000000..9369507
--- /dev/null
@@ -0,0 +1,3555 @@
+/**
+ * QEMU RTL8139 emulation
+ *
+ * Copyright (c) 2006 Igor Kovalenko
+ *
+ * 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.
+
+ * Modifications:
+ *  2006-Jan-28  Mark Malakanov :   TSAD and CSCR implementation (for Windows driver)
+ *
+ *  2006-Apr-28  Juergen Lock   :   EEPROM emulation changes for FreeBSD driver
+ *                                  HW revision ID changes for FreeBSD driver
+ *
+ *  2006-Jul-01  Igor Kovalenko :   Implemented loopback mode for FreeBSD driver
+ *                                  Corrected packet transfer reassembly routine for 8139C+ mode
+ *                                  Rearranged debugging print statements
+ *                                  Implemented PCI timer interrupt (disabled by default)
+ *                                  Implemented Tally Counters, increased VM load/save version
+ *                                  Implemented IP/TCP/UDP checksum task offloading
+ *
+ *  2006-Jul-04  Igor Kovalenko :   Implemented TCP segmentation offloading
+ *                                  Fixed MTU=1500 for produced ethernet frames
+ *
+ *  2006-Jul-09  Igor Kovalenko :   Fixed TCP header length calculation while processing
+ *                                  segmentation offloading
+ *                                  Removed slirp.h dependency
+ *                                  Added rx/tx buffer reset when enabling rx/tx operation
+ *
+ *  2010-Feb-04  Frediano Ziglio:   Rewrote timer support using QEMU timer only
+ *                                  when strictly needed (required for for
+ *                                  Darwin)
+ *  2011-Mar-22  Benjamin Poirier:  Implemented VLAN offloading
+ */
+
+/* For crc32 */
+#include <zlib.h>
+
+#include "hw/hw.h"
+#include "hw/pci/pci.h"
+#include "sysemu/dma.h"
+#include "qemu/timer.h"
+#include "net/net.h"
+#include "hw/loader.h"
+#include "sysemu/sysemu.h"
+#include "qemu/iov.h"
+
+/* debug RTL8139 card */
+//#define DEBUG_RTL8139 1
+
+#define PCI_FREQUENCY 33000000L
+
+#define SET_MASKED(input, mask, curr) \
+    ( ( (input) & ~(mask) ) | ( (curr) & (mask) ) )
+
+/* arg % size for size which is a power of 2 */
+#define MOD2(input, size) \
+    ( ( input ) & ( size - 1 )  )
+
+#define ETHER_ADDR_LEN 6
+#define ETHER_TYPE_LEN 2
+#define ETH_HLEN (ETHER_ADDR_LEN * 2 + ETHER_TYPE_LEN)
+#define ETH_P_IP    0x0800      /* Internet Protocol packet */
+#define ETH_P_8021Q 0x8100      /* 802.1Q VLAN Extended Header  */
+#define ETH_MTU     1500
+
+#define VLAN_TCI_LEN 2
+#define VLAN_HLEN (ETHER_TYPE_LEN + VLAN_TCI_LEN)
+
+#if defined (DEBUG_RTL8139)
+#  define DPRINTF(fmt, ...) \
+    do { fprintf(stderr, "RTL8139: " fmt, ## __VA_ARGS__); } while (0)
+#else
+static inline GCC_FMT_ATTR(1, 2) int DPRINTF(const char *fmt, ...)
+{
+    return 0;
+}
+#endif
+
+/* Symbolic offsets to registers. */
+enum RTL8139_registers {
+    MAC0 = 0,        /* Ethernet hardware address. */
+    MAR0 = 8,        /* Multicast filter. */
+    TxStatus0 = 0x10,/* Transmit status (Four 32bit registers). C mode only */
+                     /* Dump Tally Conter control register(64bit). C+ mode only */
+    TxAddr0 = 0x20,  /* Tx descriptors (also four 32bit). */
+    RxBuf = 0x30,
+    ChipCmd = 0x37,
+    RxBufPtr = 0x38,
+    RxBufAddr = 0x3A,
+    IntrMask = 0x3C,
+    IntrStatus = 0x3E,
+    TxConfig = 0x40,
+    RxConfig = 0x44,
+    Timer = 0x48,        /* A general-purpose counter. */
+    RxMissed = 0x4C,    /* 24 bits valid, write clears. */
+    Cfg9346 = 0x50,
+    Config0 = 0x51,
+    Config1 = 0x52,
+    FlashReg = 0x54,
+    MediaStatus = 0x58,
+    Config3 = 0x59,
+    Config4 = 0x5A,        /* absent on RTL-8139A */
+    HltClk = 0x5B,
+    MultiIntr = 0x5C,
+    PCIRevisionID = 0x5E,
+    TxSummary = 0x60, /* TSAD register. Transmit Status of All Descriptors*/
+    BasicModeCtrl = 0x62,
+    BasicModeStatus = 0x64,
+    NWayAdvert = 0x66,
+    NWayLPAR = 0x68,
+    NWayExpansion = 0x6A,
+    /* Undocumented registers, but required for proper operation. */
+    FIFOTMS = 0x70,        /* FIFO Control and test. */
+    CSCR = 0x74,        /* Chip Status and Configuration Register. */
+    PARA78 = 0x78,
+    PARA7c = 0x7c,        /* Magic transceiver parameter register. */
+    Config5 = 0xD8,        /* absent on RTL-8139A */
+    /* C+ mode */
+    TxPoll        = 0xD9,    /* Tell chip to check Tx descriptors for work */
+    RxMaxSize    = 0xDA, /* Max size of an Rx packet (8169 only) */
+    CpCmd        = 0xE0, /* C+ Command register (C+ mode only) */
+    IntrMitigate    = 0xE2,    /* rx/tx interrupt mitigation control */
+    RxRingAddrLO    = 0xE4, /* 64-bit start addr of Rx ring */
+    RxRingAddrHI    = 0xE8, /* 64-bit start addr of Rx ring */
+    TxThresh    = 0xEC, /* Early Tx threshold */
+};
+
+enum ClearBitMasks {
+    MultiIntrClear = 0xF000,
+    ChipCmdClear = 0xE2,
+    Config1Clear = (1<<7)|(1<<6)|(1<<3)|(1<<2)|(1<<1),
+};
+
+enum ChipCmdBits {
+    CmdReset = 0x10,
+    CmdRxEnb = 0x08,
+    CmdTxEnb = 0x04,
+    RxBufEmpty = 0x01,
+};
+
+/* C+ mode */
+enum CplusCmdBits {
+    CPlusRxVLAN   = 0x0040, /* enable receive VLAN detagging */
+    CPlusRxChkSum = 0x0020, /* enable receive checksum offloading */
+    CPlusRxEnb    = 0x0002,
+    CPlusTxEnb    = 0x0001,
+};
+
+/* Interrupt register bits, using my own meaningful names. */
+enum IntrStatusBits {
+    PCIErr = 0x8000,
+    PCSTimeout = 0x4000,
+    RxFIFOOver = 0x40,
+    RxUnderrun = 0x20, /* Packet Underrun / Link Change */
+    RxOverflow = 0x10,
+    TxErr = 0x08,
+    TxOK = 0x04,
+    RxErr = 0x02,
+    RxOK = 0x01,
+
+    RxAckBits = RxFIFOOver | RxOverflow | RxOK,
+};
+
+enum TxStatusBits {
+    TxHostOwns = 0x2000,
+    TxUnderrun = 0x4000,
+    TxStatOK = 0x8000,
+    TxOutOfWindow = 0x20000000,
+    TxAborted = 0x40000000,
+    TxCarrierLost = 0x80000000,
+};
+enum RxStatusBits {
+    RxMulticast = 0x8000,
+    RxPhysical = 0x4000,
+    RxBroadcast = 0x2000,
+    RxBadSymbol = 0x0020,
+    RxRunt = 0x0010,
+    RxTooLong = 0x0008,
+    RxCRCErr = 0x0004,
+    RxBadAlign = 0x0002,
+    RxStatusOK = 0x0001,
+};
+
+/* Bits in RxConfig. */
+enum rx_mode_bits {
+    AcceptErr = 0x20,
+    AcceptRunt = 0x10,
+    AcceptBroadcast = 0x08,
+    AcceptMulticast = 0x04,
+    AcceptMyPhys = 0x02,
+    AcceptAllPhys = 0x01,
+};
+
+/* Bits in TxConfig. */
+enum tx_config_bits {
+
+        /* Interframe Gap Time. Only TxIFG96 doesn't violate IEEE 802.3 */
+        TxIFGShift = 24,
+        TxIFG84 = (0 << TxIFGShift),    /* 8.4us / 840ns (10 / 100Mbps) */
+        TxIFG88 = (1 << TxIFGShift),    /* 8.8us / 880ns (10 / 100Mbps) */
+        TxIFG92 = (2 << TxIFGShift),    /* 9.2us / 920ns (10 / 100Mbps) */
+        TxIFG96 = (3 << TxIFGShift),    /* 9.6us / 960ns (10 / 100Mbps) */
+
+    TxLoopBack = (1 << 18) | (1 << 17), /* enable loopback test mode */
+    TxCRC = (1 << 16),    /* DISABLE appending CRC to end of Tx packets */
+    TxClearAbt = (1 << 0),    /* Clear abort (WO) */
+    TxDMAShift = 8,        /* DMA burst value (0-7) is shifted this many bits */
+    TxRetryShift = 4,    /* TXRR value (0-15) is shifted this many bits */
+
+    TxVersionMask = 0x7C800000, /* mask out version bits 30-26, 23 */
+};
+
+
+/* Transmit Status of All Descriptors (TSAD) Register */
+enum TSAD_bits {
+ TSAD_TOK3 = 1<<15, // TOK bit of Descriptor 3
+ TSAD_TOK2 = 1<<14, // TOK bit of Descriptor 2
+ TSAD_TOK1 = 1<<13, // TOK bit of Descriptor 1
+ TSAD_TOK0 = 1<<12, // TOK bit of Descriptor 0
+ TSAD_TUN3 = 1<<11, // TUN bit of Descriptor 3
+ TSAD_TUN2 = 1<<10, // TUN bit of Descriptor 2
+ TSAD_TUN1 = 1<<9, // TUN bit of Descriptor 1
+ TSAD_TUN0 = 1<<8, // TUN bit of Descriptor 0
+ TSAD_TABT3 = 1<<07, // TABT bit of Descriptor 3
+ TSAD_TABT2 = 1<<06, // TABT bit of Descriptor 2
+ TSAD_TABT1 = 1<<05, // TABT bit of Descriptor 1
+ TSAD_TABT0 = 1<<04, // TABT bit of Descriptor 0
+ TSAD_OWN3 = 1<<03, // OWN bit of Descriptor 3
+ TSAD_OWN2 = 1<<02, // OWN bit of Descriptor 2
+ TSAD_OWN1 = 1<<01, // OWN bit of Descriptor 1
+ TSAD_OWN0 = 1<<00, // OWN bit of Descriptor 0
+};
+
+
+/* Bits in Config1 */
+enum Config1Bits {
+    Cfg1_PM_Enable = 0x01,
+    Cfg1_VPD_Enable = 0x02,
+    Cfg1_PIO = 0x04,
+    Cfg1_MMIO = 0x08,
+    LWAKE = 0x10,        /* not on 8139, 8139A */
+    Cfg1_Driver_Load = 0x20,
+    Cfg1_LED0 = 0x40,
+    Cfg1_LED1 = 0x80,
+    SLEEP = (1 << 1),    /* only on 8139, 8139A */
+    PWRDN = (1 << 0),    /* only on 8139, 8139A */
+};
+
+/* Bits in Config3 */
+enum Config3Bits {
+    Cfg3_FBtBEn    = (1 << 0), /* 1 = Fast Back to Back */
+    Cfg3_FuncRegEn = (1 << 1), /* 1 = enable CardBus Function registers */
+    Cfg3_CLKRUN_En = (1 << 2), /* 1 = enable CLKRUN */
+    Cfg3_CardB_En  = (1 << 3), /* 1 = enable CardBus registers */
+    Cfg3_LinkUp    = (1 << 4), /* 1 = wake up on link up */
+    Cfg3_Magic     = (1 << 5), /* 1 = wake up on Magic Packet (tm) */
+    Cfg3_PARM_En   = (1 << 6), /* 0 = software can set twister parameters */
+    Cfg3_GNTSel    = (1 << 7), /* 1 = delay 1 clock from PCI GNT signal */
+};
+
+/* Bits in Config4 */
+enum Config4Bits {
+    LWPTN = (1 << 2),    /* not on 8139, 8139A */
+};
+
+/* Bits in Config5 */
+enum Config5Bits {
+    Cfg5_PME_STS     = (1 << 0), /* 1 = PCI reset resets PME_Status */
+    Cfg5_LANWake     = (1 << 1), /* 1 = enable LANWake signal */
+    Cfg5_LDPS        = (1 << 2), /* 0 = save power when link is down */
+    Cfg5_FIFOAddrPtr = (1 << 3), /* Realtek internal SRAM testing */
+    Cfg5_UWF         = (1 << 4), /* 1 = accept unicast wakeup frame */
+    Cfg5_MWF         = (1 << 5), /* 1 = accept multicast wakeup frame */
+    Cfg5_BWF         = (1 << 6), /* 1 = accept broadcast wakeup frame */
+};
+
+enum RxConfigBits {
+    /* rx fifo threshold */
+    RxCfgFIFOShift = 13,
+    RxCfgFIFONone = (7 << RxCfgFIFOShift),
+
+    /* Max DMA burst */
+    RxCfgDMAShift = 8,
+    RxCfgDMAUnlimited = (7 << RxCfgDMAShift),
+
+    /* rx ring buffer length */
+    RxCfgRcv8K = 0,
+    RxCfgRcv16K = (1 << 11),
+    RxCfgRcv32K = (1 << 12),
+    RxCfgRcv64K = (1 << 11) | (1 << 12),
+
+    /* Disable packet wrap at end of Rx buffer. (not possible with 64k) */
+    RxNoWrap = (1 << 7),
+};
+
+/* Twister tuning parameters from RealTek.
+   Completely undocumented, but required to tune bad links on some boards. */
+/*
+enum CSCRBits {
+    CSCR_LinkOKBit = 0x0400,
+    CSCR_LinkChangeBit = 0x0800,
+    CSCR_LinkStatusBits = 0x0f000,
+    CSCR_LinkDownOffCmd = 0x003c0,
+    CSCR_LinkDownCmd = 0x0f3c0,
+*/
+enum CSCRBits {
+    CSCR_Testfun = 1<<15, /* 1 = Auto-neg speeds up internal timer, WO, def 0 */
+    CSCR_LD  = 1<<9,  /* Active low TPI link disable signal. When low, TPI still transmits link pulses and TPI stays in good link state. def 1*/
+    CSCR_HEART_BIT = 1<<8,  /* 1 = HEART BEAT enable, 0 = HEART BEAT disable. HEART BEAT function is only valid in 10Mbps mode. def 1*/
+    CSCR_JBEN = 1<<7,  /* 1 = enable jabber function. 0 = disable jabber function, def 1*/
+    CSCR_F_LINK_100 = 1<<6, /* Used to login force good link in 100Mbps for diagnostic purposes. 1 = DISABLE, 0 = ENABLE. def 1*/
+    CSCR_F_Connect  = 1<<5,  /* Assertion of this bit forces the disconnect function to be bypassed. def 0*/
+    CSCR_Con_status = 1<<3, /* This bit indicates the status of the connection. 1 = valid connected link detected; 0 = disconnected link detected. RO def 0*/
+    CSCR_Con_status_En = 1<<2, /* Assertion of this bit configures LED1 pin to indicate connection status. def 0*/
+    CSCR_PASS_SCR = 1<<0, /* Bypass Scramble, def 0*/
+};
+
+enum Cfg9346Bits {
+    Cfg9346_Normal = 0x00,
+    Cfg9346_Autoload = 0x40,
+    Cfg9346_Programming = 0x80,
+    Cfg9346_ConfigWrite = 0xC0,
+};
+
+typedef enum {
+    CH_8139 = 0,
+    CH_8139_K,
+    CH_8139A,
+    CH_8139A_G,
+    CH_8139B,
+    CH_8130,
+    CH_8139C,
+    CH_8100,
+    CH_8100B_8139D,
+    CH_8101,
+} chip_t;
+
+enum chip_flags {
+    HasHltClk = (1 << 0),
+    HasLWake = (1 << 1),
+};
+
+#define HW_REVID(b30, b29, b28, b27, b26, b23, b22) \
+    (b30<<30 | b29<<29 | b28<<28 | b27<<27 | b26<<26 | b23<<23 | b22<<22)
+#define HW_REVID_MASK    HW_REVID(1, 1, 1, 1, 1, 1, 1)
+
+#define RTL8139_PCI_REVID_8139      0x10
+#define RTL8139_PCI_REVID_8139CPLUS 0x20
+
+#define RTL8139_PCI_REVID           RTL8139_PCI_REVID_8139CPLUS
+
+/* Size is 64 * 16bit words */
+#define EEPROM_9346_ADDR_BITS 6
+#define EEPROM_9346_SIZE  (1 << EEPROM_9346_ADDR_BITS)
+#define EEPROM_9346_ADDR_MASK (EEPROM_9346_SIZE - 1)
+
+enum Chip9346Operation
+{
+    Chip9346_op_mask = 0xc0,          /* 10 zzzzzz */
+    Chip9346_op_read = 0x80,          /* 10 AAAAAA */
+    Chip9346_op_write = 0x40,         /* 01 AAAAAA D(15)..D(0) */
+    Chip9346_op_ext_mask = 0xf0,      /* 11 zzzzzz */
+    Chip9346_op_write_enable = 0x30,  /* 00 11zzzz */
+    Chip9346_op_write_all = 0x10,     /* 00 01zzzz */
+    Chip9346_op_write_disable = 0x00, /* 00 00zzzz */
+};
+
+enum Chip9346Mode
+{
+    Chip9346_none = 0,
+    Chip9346_enter_command_mode,
+    Chip9346_read_command,
+    Chip9346_data_read,      /* from output register */
+    Chip9346_data_write,     /* to input register, then to contents at specified address */
+    Chip9346_data_write_all, /* to input register, then filling contents */
+};
+
+typedef struct EEprom9346
+{
+    uint16_t contents[EEPROM_9346_SIZE];
+    int      mode;
+    uint32_t tick;
+    uint8_t  address;
+    uint16_t input;
+    uint16_t output;
+
+    uint8_t eecs;
+    uint8_t eesk;
+    uint8_t eedi;
+    uint8_t eedo;
+} EEprom9346;
+
+typedef struct RTL8139TallyCounters
+{
+    /* Tally counters */
+    uint64_t   TxOk;
+    uint64_t   RxOk;
+    uint64_t   TxERR;
+    uint32_t   RxERR;
+    uint16_t   MissPkt;
+    uint16_t   FAE;
+    uint32_t   Tx1Col;
+    uint32_t   TxMCol;
+    uint64_t   RxOkPhy;
+    uint64_t   RxOkBrd;
+    uint32_t   RxOkMul;
+    uint16_t   TxAbt;
+    uint16_t   TxUndrn;
+} RTL8139TallyCounters;
+
+/* Clears all tally counters */
+static void RTL8139TallyCounters_clear(RTL8139TallyCounters* counters);
+
+typedef struct RTL8139State {
+    PCIDevice dev;
+    uint8_t phys[8]; /* mac address */
+    uint8_t mult[8]; /* multicast mask array */
+
+    uint32_t TxStatus[4]; /* TxStatus0 in C mode*/ /* also DTCCR[0] and DTCCR[1] in C+ mode */
+    uint32_t TxAddr[4];   /* TxAddr0 */
+    uint32_t RxBuf;       /* Receive buffer */
+    uint32_t RxBufferSize;/* internal variable, receive ring buffer size in C mode */
+    uint32_t RxBufPtr;
+    uint32_t RxBufAddr;
+
+    uint16_t IntrStatus;
+    uint16_t IntrMask;
+
+    uint32_t TxConfig;
+    uint32_t RxConfig;
+    uint32_t RxMissed;
+
+    uint16_t CSCR;
+
+    uint8_t  Cfg9346;
+    uint8_t  Config0;
+    uint8_t  Config1;
+    uint8_t  Config3;
+    uint8_t  Config4;
+    uint8_t  Config5;
+
+    uint8_t  clock_enabled;
+    uint8_t  bChipCmdState;
+
+    uint16_t MultiIntr;
+
+    uint16_t BasicModeCtrl;
+    uint16_t BasicModeStatus;
+    uint16_t NWayAdvert;
+    uint16_t NWayLPAR;
+    uint16_t NWayExpansion;
+
+    uint16_t CpCmd;
+    uint8_t  TxThresh;
+
+    NICState *nic;
+    NICConf conf;
+
+    /* C ring mode */
+    uint32_t   currTxDesc;
+
+    /* C+ mode */
+    uint32_t   cplus_enabled;
+
+    uint32_t   currCPlusRxDesc;
+    uint32_t   currCPlusTxDesc;
+
+    uint32_t   RxRingAddrLO;
+    uint32_t   RxRingAddrHI;
+
+    EEprom9346 eeprom;
+
+    uint32_t   TCTR;
+    uint32_t   TimerInt;
+    int64_t    TCTR_base;
+
+    /* Tally counters */
+    RTL8139TallyCounters tally_counters;
+
+    /* Non-persistent data */
+    uint8_t   *cplus_txbuffer;
+    int        cplus_txbuffer_len;
+    int        cplus_txbuffer_offset;
+
+    /* PCI interrupt timer */
+    QEMUTimer *timer;
+    int64_t TimerExpire;
+
+    MemoryRegion bar_io;
+    MemoryRegion bar_mem;
+
+    /* Support migration to/from old versions */
+    int rtl8139_mmio_io_addr_dummy;
+} RTL8139State;
+
+/* Writes tally counters to memory via DMA */
+static void RTL8139TallyCounters_dma_write(RTL8139State *s, dma_addr_t tc_addr);
+
+static void rtl8139_set_next_tctr_time(RTL8139State *s, int64_t current_time);
+
+static void prom9346_decode_command(EEprom9346 *eeprom, uint8_t command)
+{
+    DPRINTF("eeprom command 0x%02x\n", command);
+
+    switch (command & Chip9346_op_mask)
+    {
+        case Chip9346_op_read:
+        {
+            eeprom->address = command & EEPROM_9346_ADDR_MASK;
+            eeprom->output = eeprom->contents[eeprom->address];
+            eeprom->eedo = 0;
+            eeprom->tick = 0;
+            eeprom->mode = Chip9346_data_read;
+            DPRINTF("eeprom read from address 0x%02x data=0x%04x\n",
+                eeprom->address, eeprom->output);
+        }
+        break;
+
+        case Chip9346_op_write:
+        {
+            eeprom->address = command & EEPROM_9346_ADDR_MASK;
+            eeprom->input = 0;
+            eeprom->tick = 0;
+            eeprom->mode = Chip9346_none; /* Chip9346_data_write */
+            DPRINTF("eeprom begin write to address 0x%02x\n",
+                eeprom->address);
+        }
+        break;
+        default:
+            eeprom->mode = Chip9346_none;
+            switch (command & Chip9346_op_ext_mask)
+            {
+                case Chip9346_op_write_enable:
+                    DPRINTF("eeprom write enabled\n");
+                    break;
+                case Chip9346_op_write_all:
+                    DPRINTF("eeprom begin write all\n");
+                    break;
+                case Chip9346_op_write_disable:
+                    DPRINTF("eeprom write disabled\n");
+                    break;
+            }
+            break;
+    }
+}
+
+static void prom9346_shift_clock(EEprom9346 *eeprom)
+{
+    int bit = eeprom->eedi?1:0;
+
+    ++ eeprom->tick;
+
+    DPRINTF("eeprom: tick %d eedi=%d eedo=%d\n", eeprom->tick, eeprom->eedi,
+        eeprom->eedo);
+
+    switch (eeprom->mode)
+    {
+        case Chip9346_enter_command_mode:
+            if (bit)
+            {
+                eeprom->mode = Chip9346_read_command;
+                eeprom->tick = 0;
+                eeprom->input = 0;
+                DPRINTF("eeprom: +++ synchronized, begin command read\n");
+            }
+            break;
+
+        case Chip9346_read_command:
+            eeprom->input = (eeprom->input << 1) | (bit & 1);
+            if (eeprom->tick == 8)
+            {
+                prom9346_decode_command(eeprom, eeprom->input & 0xff);
+            }
+            break;
+
+        case Chip9346_data_read:
+            eeprom->eedo = (eeprom->output & 0x8000)?1:0;
+            eeprom->output <<= 1;
+            if (eeprom->tick == 16)
+            {
+#if 1
+        // the FreeBSD drivers (rl and re) don't explicitly toggle
+        // CS between reads (or does setting Cfg9346 to 0 count too?),
+        // so we need to enter wait-for-command state here
+                eeprom->mode = Chip9346_enter_command_mode;
+                eeprom->input = 0;
+                eeprom->tick = 0;
+
+                DPRINTF("eeprom: +++ end of read, awaiting next command\n");
+#else
+        // original behaviour
+                ++eeprom->address;
+                eeprom->address &= EEPROM_9346_ADDR_MASK;
+                eeprom->output = eeprom->contents[eeprom->address];
+                eeprom->tick = 0;
+
+                DPRINTF("eeprom: +++ read next address 0x%02x data=0x%04x\n",
+                    eeprom->address, eeprom->output);
+#endif
+            }
+            break;
+
+        case Chip9346_data_write:
+            eeprom->input = (eeprom->input << 1) | (bit & 1);
+            if (eeprom->tick == 16)
+            {
+                DPRINTF("eeprom write to address 0x%02x data=0x%04x\n",
+                    eeprom->address, eeprom->input);
+
+                eeprom->contents[eeprom->address] = eeprom->input;
+                eeprom->mode = Chip9346_none; /* waiting for next command after CS cycle */
+                eeprom->tick = 0;
+                eeprom->input = 0;
+            }
+            break;
+
+        case Chip9346_data_write_all:
+            eeprom->input = (eeprom->input << 1) | (bit & 1);
+            if (eeprom->tick == 16)
+            {
+                int i;
+                for (i = 0; i < EEPROM_9346_SIZE; i++)
+                {
+                    eeprom->contents[i] = eeprom->input;
+                }
+                DPRINTF("eeprom filled with data=0x%04x\n", eeprom->input);
+
+                eeprom->mode = Chip9346_enter_command_mode;
+                eeprom->tick = 0;
+                eeprom->input = 0;
+            }
+            break;
+
+        default:
+            break;
+    }
+}
+
+static int prom9346_get_wire(RTL8139State *s)
+{
+    EEprom9346 *eeprom = &s->eeprom;
+    if (!eeprom->eecs)
+        return 0;
+
+    return eeprom->eedo;
+}
+
+/* FIXME: This should be merged into/replaced by eeprom93xx.c.  */
+static void prom9346_set_wire(RTL8139State *s, int eecs, int eesk, int eedi)
+{
+    EEprom9346 *eeprom = &s->eeprom;
+    uint8_t old_eecs = eeprom->eecs;
+    uint8_t old_eesk = eeprom->eesk;
+
+    eeprom->eecs = eecs;
+    eeprom->eesk = eesk;
+    eeprom->eedi = eedi;
+
+    DPRINTF("eeprom: +++ wires CS=%d SK=%d DI=%d DO=%d\n", eeprom->eecs,
+        eeprom->eesk, eeprom->eedi, eeprom->eedo);
+
+    if (!old_eecs && eecs)
+    {
+        /* Synchronize start */
+        eeprom->tick = 0;
+        eeprom->input = 0;
+        eeprom->output = 0;
+        eeprom->mode = Chip9346_enter_command_mode;
+
+        DPRINTF("=== eeprom: begin access, enter command mode\n");
+    }
+
+    if (!eecs)
+    {
+        DPRINTF("=== eeprom: end access\n");
+        return;
+    }
+
+    if (!old_eesk && eesk)
+    {
+        /* SK front rules */
+        prom9346_shift_clock(eeprom);
+    }
+}
+
+static void rtl8139_update_irq(RTL8139State *s)
+{
+    int isr;
+    isr = (s->IntrStatus & s->IntrMask) & 0xffff;
+
+    DPRINTF("Set IRQ to %d (%04x %04x)\n", isr ? 1 : 0, s->IntrStatus,
+        s->IntrMask);
+
+    qemu_set_irq(s->dev.irq[0], (isr != 0));
+}
+
+static int rtl8139_RxWrap(RTL8139State *s)
+{
+    /* wrapping enabled; assume 1.5k more buffer space if size < 65536 */
+    return (s->RxConfig & (1 << 7));
+}
+
+static int rtl8139_receiver_enabled(RTL8139State *s)
+{
+    return s->bChipCmdState & CmdRxEnb;
+}
+
+static int rtl8139_transmitter_enabled(RTL8139State *s)
+{
+    return s->bChipCmdState & CmdTxEnb;
+}
+
+static int rtl8139_cp_receiver_enabled(RTL8139State *s)
+{
+    return s->CpCmd & CPlusRxEnb;
+}
+
+static int rtl8139_cp_transmitter_enabled(RTL8139State *s)
+{
+    return s->CpCmd & CPlusTxEnb;
+}
+
+static void rtl8139_write_buffer(RTL8139State *s, const void *buf, int size)
+{
+    if (s->RxBufAddr + size > s->RxBufferSize)
+    {
+        int wrapped = MOD2(s->RxBufAddr + size, s->RxBufferSize);
+
+        /* write packet data */
+        if (wrapped && !(s->RxBufferSize < 65536 && rtl8139_RxWrap(s)))
+        {
+            DPRINTF(">>> rx packet wrapped in buffer at %d\n", size - wrapped);
+
+            if (size > wrapped)
+            {
+                pci_dma_write(&s->dev, s->RxBuf + s->RxBufAddr,
+                              buf, size-wrapped);
+            }
+
+            /* reset buffer pointer */
+            s->RxBufAddr = 0;
+
+            pci_dma_write(&s->dev, s->RxBuf + s->RxBufAddr,
+                          buf + (size-wrapped), wrapped);
+
+            s->RxBufAddr = wrapped;
+
+            return;
+        }
+    }
+
+    /* non-wrapping path or overwrapping enabled */
+    pci_dma_write(&s->dev, s->RxBuf + s->RxBufAddr, buf, size);
+
+    s->RxBufAddr += size;
+}
+
+#define MIN_BUF_SIZE 60
+static inline dma_addr_t rtl8139_addr64(uint32_t low, uint32_t high)
+{
+    return low | ((uint64_t)high << 32);
+}
+
+/* Workaround for buggy guest driver such as linux who allocates rx
+ * rings after the receiver were enabled. */
+static bool rtl8139_cp_rx_valid(RTL8139State *s)
+{
+    return !(s->RxRingAddrLO == 0 && s->RxRingAddrHI == 0);
+}
+
+static int rtl8139_can_receive(NetClientState *nc)
+{
+    RTL8139State *s = qemu_get_nic_opaque(nc);
+    int avail;
+
+    /* Receive (drop) packets if card is disabled.  */
+    if (!s->clock_enabled)
+      return 1;
+    if (!rtl8139_receiver_enabled(s))
+      return 1;
+
+    if (rtl8139_cp_receiver_enabled(s) && rtl8139_cp_rx_valid(s)) {
+        /* ??? Flow control not implemented in c+ mode.
+           This is a hack to work around slirp deficiencies anyway.  */
+        return 1;
+    } else {
+        avail = MOD2(s->RxBufferSize + s->RxBufPtr - s->RxBufAddr,
+                     s->RxBufferSize);
+        return (avail == 0 || avail >= 1514 || (s->IntrMask & RxOverflow));
+    }
+}
+
+static ssize_t rtl8139_do_receive(NetClientState *nc, const uint8_t *buf, size_t size_, int do_interrupt)
+{
+    RTL8139State *s = qemu_get_nic_opaque(nc);
+    /* size is the length of the buffer passed to the driver */
+    int size = size_;
+    const uint8_t *dot1q_buf = NULL;
+
+    uint32_t packet_header = 0;
+
+    uint8_t buf1[MIN_BUF_SIZE + VLAN_HLEN];
+    static const uint8_t broadcast_macaddr[6] =
+        { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+    DPRINTF(">>> received len=%d\n", size);
+
+    /* test if board clock is stopped */
+    if (!s->clock_enabled)
+    {
+        DPRINTF("stopped ==========================\n");
+        return -1;
+    }
+
+    /* first check if receiver is enabled */
+
+    if (!rtl8139_receiver_enabled(s))
+    {
+        DPRINTF("receiver disabled ================\n");
+        return -1;
+    }
+
+    /* XXX: check this */
+    if (s->RxConfig & AcceptAllPhys) {
+        /* promiscuous: receive all */
+        DPRINTF(">>> packet received in promiscuous mode\n");
+
+    } else {
+        if (!memcmp(buf,  broadcast_macaddr, 6)) {
+            /* broadcast address */
+            if (!(s->RxConfig & AcceptBroadcast))
+            {
+                DPRINTF(">>> broadcast packet rejected\n");
+
+                /* update tally counter */
+                ++s->tally_counters.RxERR;
+
+                return size;
+            }
+
+            packet_header |= RxBroadcast;
+
+            DPRINTF(">>> broadcast packet received\n");
+
+            /* update tally counter */
+            ++s->tally_counters.RxOkBrd;
+
+        } else if (buf[0] & 0x01) {
+            /* multicast */
+            if (!(s->RxConfig & AcceptMulticast))
+            {
+                DPRINTF(">>> multicast packet rejected\n");
+
+                /* update tally counter */
+                ++s->tally_counters.RxERR;
+
+                return size;
+            }
+
+            int mcast_idx = compute_mcast_idx(buf);
+
+            if (!(s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7))))
+            {
+                DPRINTF(">>> multicast address mismatch\n");
+
+                /* update tally counter */
+                ++s->tally_counters.RxERR;
+
+                return size;
+            }
+
+            packet_header |= RxMulticast;
+
+            DPRINTF(">>> multicast packet received\n");
+
+            /* update tally counter */
+            ++s->tally_counters.RxOkMul;
+
+        } else if (s->phys[0] == buf[0] &&
+                   s->phys[1] == buf[1] &&
+                   s->phys[2] == buf[2] &&
+                   s->phys[3] == buf[3] &&
+                   s->phys[4] == buf[4] &&
+                   s->phys[5] == buf[5]) {
+            /* match */
+            if (!(s->RxConfig & AcceptMyPhys))
+            {
+                DPRINTF(">>> rejecting physical address matching packet\n");
+
+                /* update tally counter */
+                ++s->tally_counters.RxERR;
+
+                return size;
+            }
+
+            packet_header |= RxPhysical;
+
+            DPRINTF(">>> physical address matching packet received\n");
+
+            /* update tally counter */
+            ++s->tally_counters.RxOkPhy;
+
+        } else {
+
+            DPRINTF(">>> unknown packet\n");
+
+            /* update tally counter */
+            ++s->tally_counters.RxERR;
+
+            return size;
+        }
+    }
+
+    /* if too small buffer, then expand it
+     * Include some tailroom in case a vlan tag is later removed. */
+    if (size < MIN_BUF_SIZE + VLAN_HLEN) {
+        memcpy(buf1, buf, size);
+        memset(buf1 + size, 0, MIN_BUF_SIZE + VLAN_HLEN - size);
+        buf = buf1;
+        if (size < MIN_BUF_SIZE) {
+            size = MIN_BUF_SIZE;
+        }
+    }
+
+    if (rtl8139_cp_receiver_enabled(s))
+    {
+        if (!rtl8139_cp_rx_valid(s)) {
+            return size;
+        }
+
+        DPRINTF("in C+ Rx mode ================\n");
+
+        /* begin C+ receiver mode */
+
+/* w0 ownership flag */
+#define CP_RX_OWN (1<<31)
+/* w0 end of ring flag */
+#define CP_RX_EOR (1<<30)
+/* w0 bits 0...12 : buffer size */
+#define CP_RX_BUFFER_SIZE_MASK ((1<<13) - 1)
+/* w1 tag available flag */
+#define CP_RX_TAVA (1<<16)
+/* w1 bits 0...15 : VLAN tag */
+#define CP_RX_VLAN_TAG_MASK ((1<<16) - 1)
+/* w2 low  32bit of Rx buffer ptr */
+/* w3 high 32bit of Rx buffer ptr */
+
+        int descriptor = s->currCPlusRxDesc;
+        dma_addr_t cplus_rx_ring_desc;
+
+        cplus_rx_ring_desc = rtl8139_addr64(s->RxRingAddrLO, s->RxRingAddrHI);
+        cplus_rx_ring_desc += 16 * descriptor;
+
+        DPRINTF("+++ C+ mode reading RX descriptor %d from host memory at "
+            "%08x %08x = "DMA_ADDR_FMT"\n", descriptor, s->RxRingAddrHI,
+            s->RxRingAddrLO, cplus_rx_ring_desc);
+
+        uint32_t val, rxdw0,rxdw1,rxbufLO,rxbufHI;
+
+        pci_dma_read(&s->dev, cplus_rx_ring_desc, &val, 4);
+        rxdw0 = le32_to_cpu(val);
+        pci_dma_read(&s->dev, cplus_rx_ring_desc+4, &val, 4);
+        rxdw1 = le32_to_cpu(val);
+        pci_dma_read(&s->dev, cplus_rx_ring_desc+8, &val, 4);
+        rxbufLO = le32_to_cpu(val);
+        pci_dma_read(&s->dev, cplus_rx_ring_desc+12, &val, 4);
+        rxbufHI = le32_to_cpu(val);
+
+        DPRINTF("+++ C+ mode RX descriptor %d %08x %08x %08x %08x\n",
+            descriptor, rxdw0, rxdw1, rxbufLO, rxbufHI);
+
+        if (!(rxdw0 & CP_RX_OWN))
+        {
+            DPRINTF("C+ Rx mode : descriptor %d is owned by host\n",
+                descriptor);
+
+            s->IntrStatus |= RxOverflow;
+            ++s->RxMissed;
+
+            /* update tally counter */
+            ++s->tally_counters.RxERR;
+            ++s->tally_counters.MissPkt;
+
+            rtl8139_update_irq(s);
+            return size_;
+        }
+
+        uint32_t rx_space = rxdw0 & CP_RX_BUFFER_SIZE_MASK;
+
+        /* write VLAN info to descriptor variables. */
+        if (s->CpCmd & CPlusRxVLAN && be16_to_cpup((uint16_t *)
+                &buf[ETHER_ADDR_LEN * 2]) == ETH_P_8021Q) {
+            dot1q_buf = &buf[ETHER_ADDR_LEN * 2];
+            size -= VLAN_HLEN;
+            /* if too small buffer, use the tailroom added duing expansion */
+            if (size < MIN_BUF_SIZE) {
+                size = MIN_BUF_SIZE;
+            }
+
+            rxdw1 &= ~CP_RX_VLAN_TAG_MASK;
+            /* BE + ~le_to_cpu()~ + cpu_to_le() = BE */
+            rxdw1 |= CP_RX_TAVA | le16_to_cpup((uint16_t *)
+                &dot1q_buf[ETHER_TYPE_LEN]);
+
+            DPRINTF("C+ Rx mode : extracted vlan tag with tci: ""%u\n",
+                be16_to_cpup((uint16_t *)&dot1q_buf[ETHER_TYPE_LEN]));
+        } else {
+            /* reset VLAN tag flag */
+            rxdw1 &= ~CP_RX_TAVA;
+        }
+
+        /* TODO: scatter the packet over available receive ring descriptors space */
+
+        if (size+4 > rx_space)
+        {
+            DPRINTF("C+ Rx mode : descriptor %d size %d received %d + 4\n",
+                descriptor, rx_space, size);
+
+            s->IntrStatus |= RxOverflow;
+            ++s->RxMissed;
+
+            /* update tally counter */
+            ++s->tally_counters.RxERR;
+            ++s->tally_counters.MissPkt;
+
+            rtl8139_update_irq(s);
+            return size_;
+        }
+
+        dma_addr_t rx_addr = rtl8139_addr64(rxbufLO, rxbufHI);
+
+        /* receive/copy to target memory */
+        if (dot1q_buf) {
+            pci_dma_write(&s->dev, rx_addr, buf, 2 * ETHER_ADDR_LEN);
+            pci_dma_write(&s->dev, rx_addr + 2 * ETHER_ADDR_LEN,
+                          buf + 2 * ETHER_ADDR_LEN + VLAN_HLEN,
+                          size - 2 * ETHER_ADDR_LEN);
+        } else {
+            pci_dma_write(&s->dev, rx_addr, buf, size);
+        }
+
+        if (s->CpCmd & CPlusRxChkSum)
+        {
+            /* do some packet checksumming */
+        }
+
+        /* write checksum */
+        val = cpu_to_le32(crc32(0, buf, size_));
+        pci_dma_write(&s->dev, rx_addr+size, (uint8_t *)&val, 4);
+
+/* first segment of received packet flag */
+#define CP_RX_STATUS_FS (1<<29)
+/* last segment of received packet flag */
+#define CP_RX_STATUS_LS (1<<28)
+/* multicast packet flag */
+#define CP_RX_STATUS_MAR (1<<26)
+/* physical-matching packet flag */
+#define CP_RX_STATUS_PAM (1<<25)
+/* broadcast packet flag */
+#define CP_RX_STATUS_BAR (1<<24)
+/* runt packet flag */
+#define CP_RX_STATUS_RUNT (1<<19)
+/* crc error flag */
+#define CP_RX_STATUS_CRC (1<<18)
+/* IP checksum error flag */
+#define CP_RX_STATUS_IPF (1<<15)
+/* UDP checksum error flag */
+#define CP_RX_STATUS_UDPF (1<<14)
+/* TCP checksum error flag */
+#define CP_RX_STATUS_TCPF (1<<13)
+
+        /* transfer ownership to target */
+        rxdw0 &= ~CP_RX_OWN;
+
+        /* set first segment bit */
+        rxdw0 |= CP_RX_STATUS_FS;
+
+        /* set last segment bit */
+        rxdw0 |= CP_RX_STATUS_LS;
+
+        /* set received packet type flags */
+        if (packet_header & RxBroadcast)
+            rxdw0 |= CP_RX_STATUS_BAR;
+        if (packet_header & RxMulticast)
+            rxdw0 |= CP_RX_STATUS_MAR;
+        if (packet_header & RxPhysical)
+            rxdw0 |= CP_RX_STATUS_PAM;
+
+        /* set received size */
+        rxdw0 &= ~CP_RX_BUFFER_SIZE_MASK;
+        rxdw0 |= (size+4);
+
+        /* update ring data */
+        val = cpu_to_le32(rxdw0);
+        pci_dma_write(&s->dev, cplus_rx_ring_desc, (uint8_t *)&val, 4);
+        val = cpu_to_le32(rxdw1);
+        pci_dma_write(&s->dev, cplus_rx_ring_desc+4, (uint8_t *)&val, 4);
+
+        /* update tally counter */
+        ++s->tally_counters.RxOk;
+
+        /* seek to next Rx descriptor */
+        if (rxdw0 & CP_RX_EOR)
+        {
+            s->currCPlusRxDesc = 0;
+        }
+        else
+        {
+            ++s->currCPlusRxDesc;
+        }
+
+        DPRINTF("done C+ Rx mode ----------------\n");
+
+    }
+    else
+    {
+        DPRINTF("in ring Rx mode ================\n");
+
+        /* begin ring receiver mode */
+        int avail = MOD2(s->RxBufferSize + s->RxBufPtr - s->RxBufAddr, s->RxBufferSize);
+
+        /* if receiver buffer is empty then avail == 0 */
+
+        if (avail != 0 && size + 8 >= avail)
+        {
+            DPRINTF("rx overflow: rx buffer length %d head 0x%04x "
+                "read 0x%04x === available 0x%04x need 0x%04x\n",
+                s->RxBufferSize, s->RxBufAddr, s->RxBufPtr, avail, size + 8);
+
+            s->IntrStatus |= RxOverflow;
+            ++s->RxMissed;
+            rtl8139_update_irq(s);
+            return size_;
+        }
+
+        packet_header |= RxStatusOK;
+
+        packet_header |= (((size+4) << 16) & 0xffff0000);
+
+        /* write header */
+        uint32_t val = cpu_to_le32(packet_header);
+
+        rtl8139_write_buffer(s, (uint8_t *)&val, 4);
+
+        rtl8139_write_buffer(s, buf, size);
+
+        /* write checksum */
+        val = cpu_to_le32(crc32(0, buf, size));
+        rtl8139_write_buffer(s, (uint8_t *)&val, 4);
+
+        /* correct buffer write pointer */
+        s->RxBufAddr = MOD2((s->RxBufAddr + 3) & ~0x3, s->RxBufferSize);
+
+        /* now we can signal we have received something */
+
+        DPRINTF("received: rx buffer length %d head 0x%04x read 0x%04x\n",
+            s->RxBufferSize, s->RxBufAddr, s->RxBufPtr);
+    }
+
+    s->IntrStatus |= RxOK;
+
+    if (do_interrupt)
+    {
+        rtl8139_update_irq(s);
+    }
+
+    return size_;
+}
+
+static ssize_t rtl8139_receive(NetClientState *nc, const uint8_t *buf, size_t size)
+{
+    return rtl8139_do_receive(nc, buf, size, 1);
+}
+
+static void rtl8139_reset_rxring(RTL8139State *s, uint32_t bufferSize)
+{
+    s->RxBufferSize = bufferSize;
+    s->RxBufPtr  = 0;
+    s->RxBufAddr = 0;
+}
+
+static void rtl8139_reset(DeviceState *d)
+{
+    RTL8139State *s = container_of(d, RTL8139State, dev.qdev);
+    int i;
+
+    /* restore MAC address */
+    memcpy(s->phys, s->conf.macaddr.a, 6);
+
+    /* reset interrupt mask */
+    s->IntrStatus = 0;
+    s->IntrMask = 0;
+
+    rtl8139_update_irq(s);
+
+    /* mark all status registers as owned by host */
+    for (i = 0; i < 4; ++i)
+    {
+        s->TxStatus[i] = TxHostOwns;
+    }
+
+    s->currTxDesc = 0;
+    s->currCPlusRxDesc = 0;
+    s->currCPlusTxDesc = 0;
+
+    s->RxRingAddrLO = 0;
+    s->RxRingAddrHI = 0;
+
+    s->RxBuf = 0;
+
+    rtl8139_reset_rxring(s, 8192);
+
+    /* ACK the reset */
+    s->TxConfig = 0;
+
+#if 0
+//    s->TxConfig |= HW_REVID(1, 0, 0, 0, 0, 0, 0); // RTL-8139  HasHltClk
+    s->clock_enabled = 0;
+#else
+    s->TxConfig |= HW_REVID(1, 1, 1, 0, 1, 1, 0); // RTL-8139C+ HasLWake
+    s->clock_enabled = 1;
+#endif
+
+    s->bChipCmdState = CmdReset; /* RxBufEmpty bit is calculated on read from ChipCmd */;
+
+    /* set initial state data */
+    s->Config0 = 0x0; /* No boot ROM */
+    s->Config1 = 0xC; /* IO mapped and MEM mapped registers available */
+    s->Config3 = 0x1; /* fast back-to-back compatible */
+    s->Config5 = 0x0;
+
+    s->CSCR = CSCR_F_LINK_100 | CSCR_HEART_BIT | CSCR_LD;
+
+    s->CpCmd   = 0x0; /* reset C+ mode */
+    s->cplus_enabled = 0;
+
+
+//    s->BasicModeCtrl = 0x3100; // 100Mbps, full duplex, autonegotiation
+//    s->BasicModeCtrl = 0x2100; // 100Mbps, full duplex
+    s->BasicModeCtrl = 0x1000; // autonegotiation
+
+    s->BasicModeStatus  = 0x7809;
+    //s->BasicModeStatus |= 0x0040; /* UTP medium */
+    s->BasicModeStatus |= 0x0020; /* autonegotiation completed */
+    /* preserve link state */
+    s->BasicModeStatus |= qemu_get_queue(s->nic)->link_down ? 0 : 0x04;
+
+    s->NWayAdvert    = 0x05e1; /* all modes, full duplex */
+    s->NWayLPAR      = 0x05e1; /* all modes, full duplex */
+    s->NWayExpansion = 0x0001; /* autonegotiation supported */
+
+    /* also reset timer and disable timer interrupt */
+    s->TCTR = 0;
+    s->TimerInt = 0;
+    s->TCTR_base = 0;
+
+    /* reset tally counters */
+    RTL8139TallyCounters_clear(&s->tally_counters);
+}
+
+static void RTL8139TallyCounters_clear(RTL8139TallyCounters* counters)
+{
+    counters->TxOk = 0;
+    counters->RxOk = 0;
+    counters->TxERR = 0;
+    counters->RxERR = 0;
+    counters->MissPkt = 0;
+    counters->FAE = 0;
+    counters->Tx1Col = 0;
+    counters->TxMCol = 0;
+    counters->RxOkPhy = 0;
+    counters->RxOkBrd = 0;
+    counters->RxOkMul = 0;
+    counters->TxAbt = 0;
+    counters->TxUndrn = 0;
+}
+
+static void RTL8139TallyCounters_dma_write(RTL8139State *s, dma_addr_t tc_addr)
+{
+    RTL8139TallyCounters *tally_counters = &s->tally_counters;
+    uint16_t val16;
+    uint32_t val32;
+    uint64_t val64;
+
+    val64 = cpu_to_le64(tally_counters->TxOk);
+    pci_dma_write(&s->dev, tc_addr + 0,     (uint8_t *)&val64, 8);
+
+    val64 = cpu_to_le64(tally_counters->RxOk);
+    pci_dma_write(&s->dev, tc_addr + 8,     (uint8_t *)&val64, 8);
+
+    val64 = cpu_to_le64(tally_counters->TxERR);
+    pci_dma_write(&s->dev, tc_addr + 16,    (uint8_t *)&val64, 8);
+
+    val32 = cpu_to_le32(tally_counters->RxERR);
+    pci_dma_write(&s->dev, tc_addr + 24,    (uint8_t *)&val32, 4);
+
+    val16 = cpu_to_le16(tally_counters->MissPkt);
+    pci_dma_write(&s->dev, tc_addr + 28,    (uint8_t *)&val16, 2);
+
+    val16 = cpu_to_le16(tally_counters->FAE);
+    pci_dma_write(&s->dev, tc_addr + 30,    (uint8_t *)&val16, 2);
+
+    val32 = cpu_to_le32(tally_counters->Tx1Col);
+    pci_dma_write(&s->dev, tc_addr + 32,    (uint8_t *)&val32, 4);
+
+    val32 = cpu_to_le32(tally_counters->TxMCol);
+    pci_dma_write(&s->dev, tc_addr + 36,    (uint8_t *)&val32, 4);
+
+    val64 = cpu_to_le64(tally_counters->RxOkPhy);
+    pci_dma_write(&s->dev, tc_addr + 40,    (uint8_t *)&val64, 8);
+
+    val64 = cpu_to_le64(tally_counters->RxOkBrd);
+    pci_dma_write(&s->dev, tc_addr + 48,    (uint8_t *)&val64, 8);
+
+    val32 = cpu_to_le32(tally_counters->RxOkMul);
+    pci_dma_write(&s->dev, tc_addr + 56,    (uint8_t *)&val32, 4);
+
+    val16 = cpu_to_le16(tally_counters->TxAbt);
+    pci_dma_write(&s->dev, tc_addr + 60,    (uint8_t *)&val16, 2);
+
+    val16 = cpu_to_le16(tally_counters->TxUndrn);
+    pci_dma_write(&s->dev, tc_addr + 62,    (uint8_t *)&val16, 2);
+}
+
+/* Loads values of tally counters from VM state file */
+
+static const VMStateDescription vmstate_tally_counters = {
+    .name = "tally_counters",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT64(TxOk, RTL8139TallyCounters),
+        VMSTATE_UINT64(RxOk, RTL8139TallyCounters),
+        VMSTATE_UINT64(TxERR, RTL8139TallyCounters),
+        VMSTATE_UINT32(RxERR, RTL8139TallyCounters),
+        VMSTATE_UINT16(MissPkt, RTL8139TallyCounters),
+        VMSTATE_UINT16(FAE, RTL8139TallyCounters),
+        VMSTATE_UINT32(Tx1Col, RTL8139TallyCounters),
+        VMSTATE_UINT32(TxMCol, RTL8139TallyCounters),
+        VMSTATE_UINT64(RxOkPhy, RTL8139TallyCounters),
+        VMSTATE_UINT64(RxOkBrd, RTL8139TallyCounters),
+        VMSTATE_UINT16(TxAbt, RTL8139TallyCounters),
+        VMSTATE_UINT16(TxUndrn, RTL8139TallyCounters),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void rtl8139_ChipCmd_write(RTL8139State *s, uint32_t val)
+{
+    val &= 0xff;
+
+    DPRINTF("ChipCmd write val=0x%08x\n", val);
+
+    if (val & CmdReset)
+    {
+        DPRINTF("ChipCmd reset\n");
+        rtl8139_reset(&s->dev.qdev);
+    }
+    if (val & CmdRxEnb)
+    {
+        DPRINTF("ChipCmd enable receiver\n");
+
+        s->currCPlusRxDesc = 0;
+    }
+    if (val & CmdTxEnb)
+    {
+        DPRINTF("ChipCmd enable transmitter\n");
+
+        s->currCPlusTxDesc = 0;
+    }
+
+    /* mask unwritable bits */
+    val = SET_MASKED(val, 0xe3, s->bChipCmdState);
+
+    /* Deassert reset pin before next read */
+    val &= ~CmdReset;
+
+    s->bChipCmdState = val;
+}
+
+static int rtl8139_RxBufferEmpty(RTL8139State *s)
+{
+    int unread = MOD2(s->RxBufferSize + s->RxBufAddr - s->RxBufPtr, s->RxBufferSize);
+
+    if (unread != 0)
+    {
+        DPRINTF("receiver buffer data available 0x%04x\n", unread);
+        return 0;
+    }
+
+    DPRINTF("receiver buffer is empty\n");
+
+    return 1;
+}
+
+static uint32_t rtl8139_ChipCmd_read(RTL8139State *s)
+{
+    uint32_t ret = s->bChipCmdState;
+
+    if (rtl8139_RxBufferEmpty(s))
+        ret |= RxBufEmpty;
+
+    DPRINTF("ChipCmd read val=0x%04x\n", ret);
+
+    return ret;
+}
+
+static void rtl8139_CpCmd_write(RTL8139State *s, uint32_t val)
+{
+    val &= 0xffff;
+
+    DPRINTF("C+ command register write(w) val=0x%04x\n", val);
+
+    s->cplus_enabled = 1;
+
+    /* mask unwritable bits */
+    val = SET_MASKED(val, 0xff84, s->CpCmd);
+
+    s->CpCmd = val;
+}
+
+static uint32_t rtl8139_CpCmd_read(RTL8139State *s)
+{
+    uint32_t ret = s->CpCmd;
+
+    DPRINTF("C+ command register read(w) val=0x%04x\n", ret);
+
+    return ret;
+}
+
+static void rtl8139_IntrMitigate_write(RTL8139State *s, uint32_t val)
+{
+    DPRINTF("C+ IntrMitigate register write(w) val=0x%04x\n", val);
+}
+
+static uint32_t rtl8139_IntrMitigate_read(RTL8139State *s)
+{
+    uint32_t ret = 0;
+
+    DPRINTF("C+ IntrMitigate register read(w) val=0x%04x\n", ret);
+
+    return ret;
+}
+
+static int rtl8139_config_writable(RTL8139State *s)
+{
+    if ((s->Cfg9346 & Chip9346_op_mask) == Cfg9346_ConfigWrite)
+    {
+        return 1;
+    }
+
+    DPRINTF("Configuration registers are write-protected\n");
+
+    return 0;
+}
+
+static void rtl8139_BasicModeCtrl_write(RTL8139State *s, uint32_t val)
+{
+    val &= 0xffff;
+
+    DPRINTF("BasicModeCtrl register write(w) val=0x%04x\n", val);
+
+    /* mask unwritable bits */
+    uint32_t mask = 0x4cff;
+
+    if (1 || !rtl8139_config_writable(s))
+    {
+        /* Speed setting and autonegotiation enable bits are read-only */
+        mask |= 0x3000;
+        /* Duplex mode setting is read-only */
+        mask |= 0x0100;
+    }
+
+    val = SET_MASKED(val, mask, s->BasicModeCtrl);
+
+    s->BasicModeCtrl = val;
+}
+
+static uint32_t rtl8139_BasicModeCtrl_read(RTL8139State *s)
+{
+    uint32_t ret = s->BasicModeCtrl;
+
+    DPRINTF("BasicModeCtrl register read(w) val=0x%04x\n", ret);
+
+    return ret;
+}
+
+static void rtl8139_BasicModeStatus_write(RTL8139State *s, uint32_t val)
+{
+    val &= 0xffff;
+
+    DPRINTF("BasicModeStatus register write(w) val=0x%04x\n", val);
+
+    /* mask unwritable bits */
+    val = SET_MASKED(val, 0xff3f, s->BasicModeStatus);
+
+    s->BasicModeStatus = val;
+}
+
+static uint32_t rtl8139_BasicModeStatus_read(RTL8139State *s)
+{
+    uint32_t ret = s->BasicModeStatus;
+
+    DPRINTF("BasicModeStatus register read(w) val=0x%04x\n", ret);
+
+    return ret;
+}
+
+static void rtl8139_Cfg9346_write(RTL8139State *s, uint32_t val)
+{
+    val &= 0xff;
+
+    DPRINTF("Cfg9346 write val=0x%02x\n", val);
+
+    /* mask unwritable bits */
+    val = SET_MASKED(val, 0x31, s->Cfg9346);
+
+    uint32_t opmode = val & 0xc0;
+    uint32_t eeprom_val = val & 0xf;
+
+    if (opmode == 0x80) {
+        /* eeprom access */
+        int eecs = (eeprom_val & 0x08)?1:0;
+        int eesk = (eeprom_val & 0x04)?1:0;
+        int eedi = (eeprom_val & 0x02)?1:0;
+        prom9346_set_wire(s, eecs, eesk, eedi);
+    } else if (opmode == 0x40) {
+        /* Reset.  */
+        val = 0;
+        rtl8139_reset(&s->dev.qdev);
+    }
+
+    s->Cfg9346 = val;
+}
+
+static uint32_t rtl8139_Cfg9346_read(RTL8139State *s)
+{
+    uint32_t ret = s->Cfg9346;
+
+    uint32_t opmode = ret & 0xc0;
+
+    if (opmode == 0x80)
+    {
+        /* eeprom access */
+        int eedo = prom9346_get_wire(s);
+        if (eedo)
+        {
+            ret |=  0x01;
+        }
+        else
+        {
+            ret &= ~0x01;
+        }
+    }
+
+    DPRINTF("Cfg9346 read val=0x%02x\n", ret);
+
+    return ret;
+}
+
+static void rtl8139_Config0_write(RTL8139State *s, uint32_t val)
+{
+    val &= 0xff;
+
+    DPRINTF("Config0 write val=0x%02x\n", val);
+
+    if (!rtl8139_config_writable(s)) {
+        return;
+    }
+
+    /* mask unwritable bits */
+    val = SET_MASKED(val, 0xf8, s->Config0);
+
+    s->Config0 = val;
+}
+
+static uint32_t rtl8139_Config0_read(RTL8139State *s)
+{
+    uint32_t ret = s->Config0;
+
+    DPRINTF("Config0 read val=0x%02x\n", ret);
+
+    return ret;
+}
+
+static void rtl8139_Config1_write(RTL8139State *s, uint32_t val)
+{
+    val &= 0xff;
+
+    DPRINTF("Config1 write val=0x%02x\n", val);
+
+    if (!rtl8139_config_writable(s)) {
+        return;
+    }
+
+    /* mask unwritable bits */
+    val = SET_MASKED(val, 0xC, s->Config1);
+
+    s->Config1 = val;
+}
+
+static uint32_t rtl8139_Config1_read(RTL8139State *s)
+{
+    uint32_t ret = s->Config1;
+
+    DPRINTF("Config1 read val=0x%02x\n", ret);
+
+    return ret;
+}
+
+static void rtl8139_Config3_write(RTL8139State *s, uint32_t val)
+{
+    val &= 0xff;
+
+    DPRINTF("Config3 write val=0x%02x\n", val);
+
+    if (!rtl8139_config_writable(s)) {
+        return;
+    }
+
+    /* mask unwritable bits */
+    val = SET_MASKED(val, 0x8F, s->Config3);
+
+    s->Config3 = val;
+}
+
+static uint32_t rtl8139_Config3_read(RTL8139State *s)
+{
+    uint32_t ret = s->Config3;
+
+    DPRINTF("Config3 read val=0x%02x\n", ret);
+
+    return ret;
+}
+
+static void rtl8139_Config4_write(RTL8139State *s, uint32_t val)
+{
+    val &= 0xff;
+
+    DPRINTF("Config4 write val=0x%02x\n", val);
+
+    if (!rtl8139_config_writable(s)) {
+        return;
+    }
+
+    /* mask unwritable bits */
+    val = SET_MASKED(val, 0x0a, s->Config4);
+
+    s->Config4 = val;
+}
+
+static uint32_t rtl8139_Config4_read(RTL8139State *s)
+{
+    uint32_t ret = s->Config4;
+
+    DPRINTF("Config4 read val=0x%02x\n", ret);
+
+    return ret;
+}
+
+static void rtl8139_Config5_write(RTL8139State *s, uint32_t val)
+{
+    val &= 0xff;
+
+    DPRINTF("Config5 write val=0x%02x\n", val);
+
+    /* mask unwritable bits */
+    val = SET_MASKED(val, 0x80, s->Config5);
+
+    s->Config5 = val;
+}
+
+static uint32_t rtl8139_Config5_read(RTL8139State *s)
+{
+    uint32_t ret = s->Config5;
+
+    DPRINTF("Config5 read val=0x%02x\n", ret);
+
+    return ret;
+}
+
+static void rtl8139_TxConfig_write(RTL8139State *s, uint32_t val)
+{
+    if (!rtl8139_transmitter_enabled(s))
+    {
+        DPRINTF("transmitter disabled; no TxConfig write val=0x%08x\n", val);
+        return;
+    }
+
+    DPRINTF("TxConfig write val=0x%08x\n", val);
+
+    val = SET_MASKED(val, TxVersionMask | 0x8070f80f, s->TxConfig);
+
+    s->TxConfig = val;
+}
+
+static void rtl8139_TxConfig_writeb(RTL8139State *s, uint32_t val)
+{
+    DPRINTF("RTL8139C TxConfig via write(b) val=0x%02x\n", val);
+
+    uint32_t tc = s->TxConfig;
+    tc &= 0xFFFFFF00;
+    tc |= (val & 0x000000FF);
+    rtl8139_TxConfig_write(s, tc);
+}
+
+static uint32_t rtl8139_TxConfig_read(RTL8139State *s)
+{
+    uint32_t ret = s->TxConfig;
+
+    DPRINTF("TxConfig read val=0x%04x\n", ret);
+
+    return ret;
+}
+
+static void rtl8139_RxConfig_write(RTL8139State *s, uint32_t val)
+{
+    DPRINTF("RxConfig write val=0x%08x\n", val);
+
+    /* mask unwritable bits */
+    val = SET_MASKED(val, 0xf0fc0040, s->RxConfig);
+
+    s->RxConfig = val;
+
+    /* reset buffer size and read/write pointers */
+    rtl8139_reset_rxring(s, 8192 << ((s->RxConfig >> 11) & 0x3));
+
+    DPRINTF("RxConfig write reset buffer size to %d\n", s->RxBufferSize);
+}
+
+static uint32_t rtl8139_RxConfig_read(RTL8139State *s)
+{
+    uint32_t ret = s->RxConfig;
+
+    DPRINTF("RxConfig read val=0x%08x\n", ret);
+
+    return ret;
+}
+
+static void rtl8139_transfer_frame(RTL8139State *s, uint8_t *buf, int size,
+    int do_interrupt, const uint8_t *dot1q_buf)
+{
+    struct iovec *iov = NULL;
+
+    if (!size)
+    {
+        DPRINTF("+++ empty ethernet frame\n");
+        return;
+    }
+
+    if (dot1q_buf && size >= ETHER_ADDR_LEN * 2) {
+        iov = (struct iovec[3]) {
+            { .iov_base = buf, .iov_len = ETHER_ADDR_LEN * 2 },
+            { .iov_base = (void *) dot1q_buf, .iov_len = VLAN_HLEN },
+            { .iov_base = buf + ETHER_ADDR_LEN * 2,
+                .iov_len = size - ETHER_ADDR_LEN * 2 },
+        };
+    }
+
+    if (TxLoopBack == (s->TxConfig & TxLoopBack))
+    {
+        size_t buf2_size;
+        uint8_t *buf2;
+
+        if (iov) {
+            buf2_size = iov_size(iov, 3);
+            buf2 = g_malloc(buf2_size);
+            iov_to_buf(iov, 3, 0, buf2, buf2_size);
+            buf = buf2;
+        }
+
+        DPRINTF("+++ transmit loopback mode\n");
+        rtl8139_do_receive(qemu_get_queue(s->nic), buf, size, do_interrupt);
+
+        if (iov) {
+            g_free(buf2);
+        }
+    }
+    else
+    {
+        if (iov) {
+            qemu_sendv_packet(qemu_get_queue(s->nic), iov, 3);
+        } else {
+            qemu_send_packet(qemu_get_queue(s->nic), buf, size);
+        }
+    }
+}
+
+static int rtl8139_transmit_one(RTL8139State *s, int descriptor)
+{
+    if (!rtl8139_transmitter_enabled(s))
+    {
+        DPRINTF("+++ cannot transmit from descriptor %d: transmitter "
+            "disabled\n", descriptor);
+        return 0;
+    }
+
+    if (s->TxStatus[descriptor] & TxHostOwns)
+    {
+        DPRINTF("+++ cannot transmit from descriptor %d: owned by host "
+            "(%08x)\n", descriptor, s->TxStatus[descriptor]);
+        return 0;
+    }
+
+    DPRINTF("+++ transmitting from descriptor %d\n", descriptor);
+
+    int txsize = s->TxStatus[descriptor] & 0x1fff;
+    uint8_t txbuffer[0x2000];
+
+    DPRINTF("+++ transmit reading %d bytes from host memory at 0x%08x\n",
+        txsize, s->TxAddr[descriptor]);
+
+    pci_dma_read(&s->dev, s->TxAddr[descriptor], txbuffer, txsize);
+
+    /* Mark descriptor as transferred */
+    s->TxStatus[descriptor] |= TxHostOwns;
+    s->TxStatus[descriptor] |= TxStatOK;
+
+    rtl8139_transfer_frame(s, txbuffer, txsize, 0, NULL);
+
+    DPRINTF("+++ transmitted %d bytes from descriptor %d\n", txsize,
+        descriptor);
+
+    /* update interrupt */
+    s->IntrStatus |= TxOK;
+    rtl8139_update_irq(s);
+
+    return 1;
+}
+
+/* structures and macros for task offloading */
+typedef struct ip_header
+{
+    uint8_t  ip_ver_len;    /* version and header length */
+    uint8_t  ip_tos;        /* type of service */
+    uint16_t ip_len;        /* total length */
+    uint16_t ip_id;         /* identification */
+    uint16_t ip_off;        /* fragment offset field */
+    uint8_t  ip_ttl;        /* time to live */
+    uint8_t  ip_p;          /* protocol */
+    uint16_t ip_sum;        /* checksum */
+    uint32_t ip_src,ip_dst; /* source and dest address */
+} ip_header;
+
+#define IP_HEADER_VERSION_4 4
+#define IP_HEADER_VERSION(ip) ((ip->ip_ver_len >> 4)&0xf)
+#define IP_HEADER_LENGTH(ip) (((ip->ip_ver_len)&0xf) << 2)
+
+typedef struct tcp_header
+{
+    uint16_t th_sport;         /* source port */
+    uint16_t th_dport;         /* destination port */
+    uint32_t th_seq;                   /* sequence number */
+    uint32_t th_ack;                   /* acknowledgement number */
+    uint16_t th_offset_flags; /* data offset, reserved 6 bits, TCP protocol flags */
+    uint16_t th_win;                   /* window */
+    uint16_t th_sum;                   /* checksum */
+    uint16_t th_urp;                   /* urgent pointer */
+} tcp_header;
+
+typedef struct udp_header
+{
+    uint16_t uh_sport; /* source port */
+    uint16_t uh_dport; /* destination port */
+    uint16_t uh_ulen;  /* udp length */
+    uint16_t uh_sum;   /* udp checksum */
+} udp_header;
+
+typedef struct ip_pseudo_header
+{
+    uint32_t ip_src;
+    uint32_t ip_dst;
+    uint8_t  zeros;
+    uint8_t  ip_proto;
+    uint16_t ip_payload;
+} ip_pseudo_header;
+
+#define IP_PROTO_TCP 6
+#define IP_PROTO_UDP 17
+
+#define TCP_HEADER_DATA_OFFSET(tcp) (((be16_to_cpu(tcp->th_offset_flags) >> 12)&0xf) << 2)
+#define TCP_FLAGS_ONLY(flags) ((flags)&0x3f)
+#define TCP_HEADER_FLAGS(tcp) TCP_FLAGS_ONLY(be16_to_cpu(tcp->th_offset_flags))
+
+#define TCP_HEADER_CLEAR_FLAGS(tcp, off) ((tcp)->th_offset_flags &= cpu_to_be16(~TCP_FLAGS_ONLY(off)))
+
+#define TCP_FLAG_FIN  0x01
+#define TCP_FLAG_PUSH 0x08
+
+/* produces ones' complement sum of data */
+static uint16_t ones_complement_sum(uint8_t *data, size_t len)
+{
+    uint32_t result = 0;
+
+    for (; len > 1; data+=2, len-=2)
+    {
+        result += *(uint16_t*)data;
+    }
+
+    /* add the remainder byte */
+    if (len)
+    {
+        uint8_t odd[2] = {*data, 0};
+        result += *(uint16_t*)odd;
+    }
+
+    while (result>>16)
+        result = (result & 0xffff) + (result >> 16);
+
+    return result;
+}
+
+static uint16_t ip_checksum(void *data, size_t len)
+{
+    return ~ones_complement_sum((uint8_t*)data, len);
+}
+
+static int rtl8139_cplus_transmit_one(RTL8139State *s)
+{
+    if (!rtl8139_transmitter_enabled(s))
+    {
+        DPRINTF("+++ C+ mode: transmitter disabled\n");
+        return 0;
+    }
+
+    if (!rtl8139_cp_transmitter_enabled(s))
+    {
+        DPRINTF("+++ C+ mode: C+ transmitter disabled\n");
+        return 0 ;
+    }
+
+    int descriptor = s->currCPlusTxDesc;
+
+    dma_addr_t cplus_tx_ring_desc = rtl8139_addr64(s->TxAddr[0], s->TxAddr[1]);
+
+    /* Normal priority ring */
+    cplus_tx_ring_desc += 16 * descriptor;
+
+    DPRINTF("+++ C+ mode reading TX descriptor %d from host memory at "
+        "%08x %08x = 0x"DMA_ADDR_FMT"\n", descriptor, s->TxAddr[1],
+        s->TxAddr[0], cplus_tx_ring_desc);
+
+    uint32_t val, txdw0,txdw1,txbufLO,txbufHI;
+
+    pci_dma_read(&s->dev, cplus_tx_ring_desc,    (uint8_t *)&val, 4);
+    txdw0 = le32_to_cpu(val);
+    pci_dma_read(&s->dev, cplus_tx_ring_desc+4,  (uint8_t *)&val, 4);
+    txdw1 = le32_to_cpu(val);
+    pci_dma_read(&s->dev, cplus_tx_ring_desc+8,  (uint8_t *)&val, 4);
+    txbufLO = le32_to_cpu(val);
+    pci_dma_read(&s->dev, cplus_tx_ring_desc+12, (uint8_t *)&val, 4);
+    txbufHI = le32_to_cpu(val);
+
+    DPRINTF("+++ C+ mode TX descriptor %d %08x %08x %08x %08x\n", descriptor,
+        txdw0, txdw1, txbufLO, txbufHI);
+
+/* w0 ownership flag */
+#define CP_TX_OWN (1<<31)
+/* w0 end of ring flag */
+#define CP_TX_EOR (1<<30)
+/* first segment of received packet flag */
+#define CP_TX_FS (1<<29)
+/* last segment of received packet flag */
+#define CP_TX_LS (1<<28)
+/* large send packet flag */
+#define CP_TX_LGSEN (1<<27)
+/* large send MSS mask, bits 16...25 */
+#define CP_TC_LGSEN_MSS_MASK ((1 << 12) - 1)
+
+/* IP checksum offload flag */
+#define CP_TX_IPCS (1<<18)
+/* UDP checksum offload flag */
+#define CP_TX_UDPCS (1<<17)
+/* TCP checksum offload flag */
+#define CP_TX_TCPCS (1<<16)
+
+/* w0 bits 0...15 : buffer size */
+#define CP_TX_BUFFER_SIZE (1<<16)
+#define CP_TX_BUFFER_SIZE_MASK (CP_TX_BUFFER_SIZE - 1)
+/* w1 add tag flag */
+#define CP_TX_TAGC (1<<17)
+/* w1 bits 0...15 : VLAN tag (big endian) */
+#define CP_TX_VLAN_TAG_MASK ((1<<16) - 1)
+/* w2 low  32bit of Rx buffer ptr */
+/* w3 high 32bit of Rx buffer ptr */
+
+/* set after transmission */
+/* FIFO underrun flag */
+#define CP_TX_STATUS_UNF (1<<25)
+/* transmit error summary flag, valid if set any of three below */
+#define CP_TX_STATUS_TES (1<<23)
+/* out-of-window collision flag */
+#define CP_TX_STATUS_OWC (1<<22)
+/* link failure flag */
+#define CP_TX_STATUS_LNKF (1<<21)
+/* excessive collisions flag */
+#define CP_TX_STATUS_EXC (1<<20)
+
+    if (!(txdw0 & CP_TX_OWN))
+    {
+        DPRINTF("C+ Tx mode : descriptor %d is owned by host\n", descriptor);
+        return 0 ;
+    }
+
+    DPRINTF("+++ C+ Tx mode : transmitting from descriptor %d\n", descriptor);
+
+    if (txdw0 & CP_TX_FS)
+    {
+        DPRINTF("+++ C+ Tx mode : descriptor %d is first segment "
+            "descriptor\n", descriptor);
+
+        /* reset internal buffer offset */
+        s->cplus_txbuffer_offset = 0;
+    }
+
+    int txsize = txdw0 & CP_TX_BUFFER_SIZE_MASK;
+    dma_addr_t tx_addr = rtl8139_addr64(txbufLO, txbufHI);
+
+    /* make sure we have enough space to assemble the packet */
+    if (!s->cplus_txbuffer)
+    {
+        s->cplus_txbuffer_len = CP_TX_BUFFER_SIZE;
+        s->cplus_txbuffer = g_malloc(s->cplus_txbuffer_len);
+        s->cplus_txbuffer_offset = 0;
+
+        DPRINTF("+++ C+ mode transmission buffer allocated space %d\n",
+            s->cplus_txbuffer_len);
+    }
+
+    if (s->cplus_txbuffer_offset + txsize >= s->cplus_txbuffer_len)
+    {
+        /* The spec didn't tell the maximum size, stick to CP_TX_BUFFER_SIZE */
+        txsize = s->cplus_txbuffer_len - s->cplus_txbuffer_offset;
+        DPRINTF("+++ C+ mode transmission buffer overrun, truncated descriptor"
+                "length to %d\n", txsize);
+    }
+
+    if (!s->cplus_txbuffer)
+    {
+        /* out of memory */
+
+        DPRINTF("+++ C+ mode transmiter failed to reallocate %d bytes\n",
+            s->cplus_txbuffer_len);
+
+        /* update tally counter */
+        ++s->tally_counters.TxERR;
+        ++s->tally_counters.TxAbt;
+
+        return 0;
+    }
+
+    /* append more data to the packet */
+
+    DPRINTF("+++ C+ mode transmit reading %d bytes from host memory at "
+            DMA_ADDR_FMT" to offset %d\n", txsize, tx_addr,
+            s->cplus_txbuffer_offset);
+
+    pci_dma_read(&s->dev, tx_addr,
+                 s->cplus_txbuffer + s->cplus_txbuffer_offset, txsize);
+    s->cplus_txbuffer_offset += txsize;
+
+    /* seek to next Rx descriptor */
+    if (txdw0 & CP_TX_EOR)
+    {
+        s->currCPlusTxDesc = 0;
+    }
+    else
+    {
+        ++s->currCPlusTxDesc;
+        if (s->currCPlusTxDesc >= 64)
+            s->currCPlusTxDesc = 0;
+    }
+
+    /* transfer ownership to target */
+    txdw0 &= ~CP_RX_OWN;
+
+    /* reset error indicator bits */
+    txdw0 &= ~CP_TX_STATUS_UNF;
+    txdw0 &= ~CP_TX_STATUS_TES;
+    txdw0 &= ~CP_TX_STATUS_OWC;
+    txdw0 &= ~CP_TX_STATUS_LNKF;
+    txdw0 &= ~CP_TX_STATUS_EXC;
+
+    /* update ring data */
+    val = cpu_to_le32(txdw0);
+    pci_dma_write(&s->dev, cplus_tx_ring_desc, (uint8_t *)&val, 4);
+
+    /* Now decide if descriptor being processed is holding the last segment of packet */
+    if (txdw0 & CP_TX_LS)
+    {
+        uint8_t dot1q_buffer_space[VLAN_HLEN];
+        uint16_t *dot1q_buffer;
+
+        DPRINTF("+++ C+ Tx mode : descriptor %d is last segment descriptor\n",
+            descriptor);
+
+        /* can transfer fully assembled packet */
+
+        uint8_t *saved_buffer  = s->cplus_txbuffer;
+        int      saved_size    = s->cplus_txbuffer_offset;
+        int      saved_buffer_len = s->cplus_txbuffer_len;
+
+        /* create vlan tag */
+        if (txdw1 & CP_TX_TAGC) {
+            /* the vlan tag is in BE byte order in the descriptor
+             * BE + le_to_cpu() + ~swap()~ = cpu */
+            DPRINTF("+++ C+ Tx mode : inserting vlan tag with ""tci: %u\n",
+                bswap16(txdw1 & CP_TX_VLAN_TAG_MASK));
+
+            dot1q_buffer = (uint16_t *) dot1q_buffer_space;
+            dot1q_buffer[0] = cpu_to_be16(ETH_P_8021Q);
+            /* BE + le_to_cpu() + ~cpu_to_le()~ = BE */
+            dot1q_buffer[1] = cpu_to_le16(txdw1 & CP_TX_VLAN_TAG_MASK);
+        } else {
+            dot1q_buffer = NULL;
+        }
+
+        /* reset the card space to protect from recursive call */
+        s->cplus_txbuffer = NULL;
+        s->cplus_txbuffer_offset = 0;
+        s->cplus_txbuffer_len = 0;
+
+        if (txdw0 & (CP_TX_IPCS | CP_TX_UDPCS | CP_TX_TCPCS | CP_TX_LGSEN))
+        {
+            DPRINTF("+++ C+ mode offloaded task checksum\n");
+
+            /* ip packet header */
+            ip_header *ip = NULL;
+            int hlen = 0;
+            uint8_t  ip_protocol = 0;
+            uint16_t ip_data_len = 0;
+
+            uint8_t *eth_payload_data = NULL;
+            size_t   eth_payload_len  = 0;
+
+            int proto = be16_to_cpu(*(uint16_t *)(saved_buffer + 12));
+            if (proto == ETH_P_IP)
+            {
+                DPRINTF("+++ C+ mode has IP packet\n");
+
+                /* not aligned */
+                eth_payload_data = saved_buffer + ETH_HLEN;
+                eth_payload_len  = saved_size   - ETH_HLEN;
+
+                ip = (ip_header*)eth_payload_data;
+
+                if (IP_HEADER_VERSION(ip) != IP_HEADER_VERSION_4) {
+                    DPRINTF("+++ C+ mode packet has bad IP version %d "
+                        "expected %d\n", IP_HEADER_VERSION(ip),
+                        IP_HEADER_VERSION_4);
+                    ip = NULL;
+                } else {
+                    hlen = IP_HEADER_LENGTH(ip);
+                    ip_protocol = ip->ip_p;
+                    ip_data_len = be16_to_cpu(ip->ip_len) - hlen;
+                }
+            }
+
+            if (ip)
+            {
+                if (txdw0 & CP_TX_IPCS)
+                {
+                    DPRINTF("+++ C+ mode need IP checksum\n");
+
+                    if (hlen<sizeof(ip_header) || hlen>eth_payload_len) {/* min header length */
+                        /* bad packet header len */
+                        /* or packet too short */
+                    }
+                    else
+                    {
+                        ip->ip_sum = 0;
+                        ip->ip_sum = ip_checksum(ip, hlen);
+                        DPRINTF("+++ C+ mode IP header len=%d checksum=%04x\n",
+                            hlen, ip->ip_sum);
+                    }
+                }
+
+                if ((txdw0 & CP_TX_LGSEN) && ip_protocol == IP_PROTO_TCP)
+                {
+                    int large_send_mss = (txdw0 >> 16) & CP_TC_LGSEN_MSS_MASK;
+
+                    DPRINTF("+++ C+ mode offloaded task TSO MTU=%d IP data %d "
+                        "frame data %d specified MSS=%d\n", ETH_MTU,
+                        ip_data_len, saved_size - ETH_HLEN, large_send_mss);
+
+                    int tcp_send_offset = 0;
+                    int send_count = 0;
+
+                    /* maximum IP header length is 60 bytes */
+                    uint8_t saved_ip_header[60];
+
+                    /* save IP header template; data area is used in tcp checksum calculation */
+                    memcpy(saved_ip_header, eth_payload_data, hlen);
+
+                    /* a placeholder for checksum calculation routine in tcp case */
+                    uint8_t *data_to_checksum     = eth_payload_data + hlen - 12;
+                    //                    size_t   data_to_checksum_len = eth_payload_len  - hlen + 12;
+
+                    /* pointer to TCP header */
+                    tcp_header *p_tcp_hdr = (tcp_header*)(eth_payload_data + hlen);
+
+                    int tcp_hlen = TCP_HEADER_DATA_OFFSET(p_tcp_hdr);
+
+                    /* ETH_MTU = ip header len + tcp header len + payload */
+                    int tcp_data_len = ip_data_len - tcp_hlen;
+                    int tcp_chunk_size = ETH_MTU - hlen - tcp_hlen;
+
+                    DPRINTF("+++ C+ mode TSO IP data len %d TCP hlen %d TCP "
+                        "data len %d TCP chunk size %d\n", ip_data_len,
+                        tcp_hlen, tcp_data_len, tcp_chunk_size);
+
+                    /* note the cycle below overwrites IP header data,
+                       but restores it from saved_ip_header before sending packet */
+
+                    int is_last_frame = 0;
+
+                    for (tcp_send_offset = 0; tcp_send_offset < tcp_data_len; tcp_send_offset += tcp_chunk_size)
+                    {
+                        uint16_t chunk_size = tcp_chunk_size;
+
+                        /* check if this is the last frame */
+                        if (tcp_send_offset + tcp_chunk_size >= tcp_data_len)
+                        {
+                            is_last_frame = 1;
+                            chunk_size = tcp_data_len - tcp_send_offset;
+                        }
+
+                        DPRINTF("+++ C+ mode TSO TCP seqno %08x\n",
+                            be32_to_cpu(p_tcp_hdr->th_seq));
+
+                        /* add 4 TCP pseudoheader fields */
+                        /* copy IP source and destination fields */
+                        memcpy(data_to_checksum, saved_ip_header + 12, 8);
+
+                        DPRINTF("+++ C+ mode TSO calculating TCP checksum for "
+                            "packet with %d bytes data\n", tcp_hlen +
+                            chunk_size);
+
+                        if (tcp_send_offset)
+                        {
+                            memcpy((uint8_t*)p_tcp_hdr + tcp_hlen, (uint8_t*)p_tcp_hdr + tcp_hlen + tcp_send_offset, chunk_size);
+                        }
+
+                        /* keep PUSH and FIN flags only for the last frame */
+                        if (!is_last_frame)
+                        {
+                            TCP_HEADER_CLEAR_FLAGS(p_tcp_hdr, TCP_FLAG_PUSH|TCP_FLAG_FIN);
+                        }
+
+                        /* recalculate TCP checksum */
+                        ip_pseudo_header *p_tcpip_hdr = (ip_pseudo_header *)data_to_checksum;
+                        p_tcpip_hdr->zeros      = 0;
+                        p_tcpip_hdr->ip_proto   = IP_PROTO_TCP;
+                        p_tcpip_hdr->ip_payload = cpu_to_be16(tcp_hlen + chunk_size);
+
+                        p_tcp_hdr->th_sum = 0;
+
+                        int tcp_checksum = ip_checksum(data_to_checksum, tcp_hlen + chunk_size + 12);
+                        DPRINTF("+++ C+ mode TSO TCP checksum %04x\n",
+                            tcp_checksum);
+
+                        p_tcp_hdr->th_sum = tcp_checksum;
+
+                        /* restore IP header */
+                        memcpy(eth_payload_data, saved_ip_header, hlen);
+
+                        /* set IP data length and recalculate IP checksum */
+                        ip->ip_len = cpu_to_be16(hlen + tcp_hlen + chunk_size);
+
+                        /* increment IP id for subsequent frames */
+                        ip->ip_id = cpu_to_be16(tcp_send_offset/tcp_chunk_size + be16_to_cpu(ip->ip_id));
+
+                        ip->ip_sum = 0;
+                        ip->ip_sum = ip_checksum(eth_payload_data, hlen);
+                        DPRINTF("+++ C+ mode TSO IP header len=%d "
+                            "checksum=%04x\n", hlen, ip->ip_sum);
+
+                        int tso_send_size = ETH_HLEN + hlen + tcp_hlen + chunk_size;
+                        DPRINTF("+++ C+ mode TSO transferring packet size "
+                            "%d\n", tso_send_size);
+                        rtl8139_transfer_frame(s, saved_buffer, tso_send_size,
+                            0, (uint8_t *) dot1q_buffer);
+
+                        /* add transferred count to TCP sequence number */
+                        p_tcp_hdr->th_seq = cpu_to_be32(chunk_size + be32_to_cpu(p_tcp_hdr->th_seq));
+                        ++send_count;
+                    }
+
+                    /* Stop sending this frame */
+                    saved_size = 0;
+                }
+                else if (txdw0 & (CP_TX_TCPCS|CP_TX_UDPCS))
+                {
+                    DPRINTF("+++ C+ mode need TCP or UDP checksum\n");
+
+                    /* maximum IP header length is 60 bytes */
+                    uint8_t saved_ip_header[60];
+                    memcpy(saved_ip_header, eth_payload_data, hlen);
+
+                    uint8_t *data_to_checksum     = eth_payload_data + hlen - 12;
+                    //                    size_t   data_to_checksum_len = eth_payload_len  - hlen + 12;
+
+                    /* add 4 TCP pseudoheader fields */
+                    /* copy IP source and destination fields */
+                    memcpy(data_to_checksum, saved_ip_header + 12, 8);
+
+                    if ((txdw0 & CP_TX_TCPCS) && ip_protocol == IP_PROTO_TCP)
+                    {
+                        DPRINTF("+++ C+ mode calculating TCP checksum for "
+                            "packet with %d bytes data\n", ip_data_len);
+
+                        ip_pseudo_header *p_tcpip_hdr = (ip_pseudo_header *)data_to_checksum;
+                        p_tcpip_hdr->zeros      = 0;
+                        p_tcpip_hdr->ip_proto   = IP_PROTO_TCP;
+                        p_tcpip_hdr->ip_payload = cpu_to_be16(ip_data_len);
+
+                        tcp_header* p_tcp_hdr = (tcp_header *) (data_to_checksum+12);
+
+                        p_tcp_hdr->th_sum = 0;
+
+                        int tcp_checksum = ip_checksum(data_to_checksum, ip_data_len + 12);
+                        DPRINTF("+++ C+ mode TCP checksum %04x\n",
+                            tcp_checksum);
+
+                        p_tcp_hdr->th_sum = tcp_checksum;
+                    }
+                    else if ((txdw0 & CP_TX_UDPCS) && ip_protocol == IP_PROTO_UDP)
+                    {
+                        DPRINTF("+++ C+ mode calculating UDP checksum for "
+                            "packet with %d bytes data\n", ip_data_len);
+
+                        ip_pseudo_header *p_udpip_hdr = (ip_pseudo_header *)data_to_checksum;
+                        p_udpip_hdr->zeros      = 0;
+                        p_udpip_hdr->ip_proto   = IP_PROTO_UDP;
+                        p_udpip_hdr->ip_payload = cpu_to_be16(ip_data_len);
+
+                        udp_header *p_udp_hdr = (udp_header *) (data_to_checksum+12);
+
+                        p_udp_hdr->uh_sum = 0;
+
+                        int udp_checksum = ip_checksum(data_to_checksum, ip_data_len + 12);
+                        DPRINTF("+++ C+ mode UDP checksum %04x\n",
+                            udp_checksum);
+
+                        p_udp_hdr->uh_sum = udp_checksum;
+                    }
+
+                    /* restore IP header */
+                    memcpy(eth_payload_data, saved_ip_header, hlen);
+                }
+            }
+        }
+
+        /* update tally counter */
+        ++s->tally_counters.TxOk;
+
+        DPRINTF("+++ C+ mode transmitting %d bytes packet\n", saved_size);
+
+        rtl8139_transfer_frame(s, saved_buffer, saved_size, 1,
+            (uint8_t *) dot1q_buffer);
+
+        /* restore card space if there was no recursion and reset offset */
+        if (!s->cplus_txbuffer)
+        {
+            s->cplus_txbuffer        = saved_buffer;
+            s->cplus_txbuffer_len    = saved_buffer_len;
+            s->cplus_txbuffer_offset = 0;
+        }
+        else
+        {
+            g_free(saved_buffer);
+        }
+    }
+    else
+    {
+        DPRINTF("+++ C+ mode transmission continue to next descriptor\n");
+    }
+
+    return 1;
+}
+
+static void rtl8139_cplus_transmit(RTL8139State *s)
+{
+    int txcount = 0;
+
+    while (rtl8139_cplus_transmit_one(s))
+    {
+        ++txcount;
+    }
+
+    /* Mark transfer completed */
+    if (!txcount)
+    {
+        DPRINTF("C+ mode : transmitter queue stalled, current TxDesc = %d\n",
+            s->currCPlusTxDesc);
+    }
+    else
+    {
+        /* update interrupt status */
+        s->IntrStatus |= TxOK;
+        rtl8139_update_irq(s);
+    }
+}
+
+static void rtl8139_transmit(RTL8139State *s)
+{
+    int descriptor = s->currTxDesc, txcount = 0;
+
+    /*while*/
+    if (rtl8139_transmit_one(s, descriptor))
+    {
+        ++s->currTxDesc;
+        s->currTxDesc %= 4;
+        ++txcount;
+    }
+
+    /* Mark transfer completed */
+    if (!txcount)
+    {
+        DPRINTF("transmitter queue stalled, current TxDesc = %d\n",
+            s->currTxDesc);
+    }
+}
+
+static void rtl8139_TxStatus_write(RTL8139State *s, uint32_t txRegOffset, uint32_t val)
+{
+
+    int descriptor = txRegOffset/4;
+
+    /* handle C+ transmit mode register configuration */
+
+    if (s->cplus_enabled)
+    {
+        DPRINTF("RTL8139C+ DTCCR write offset=0x%x val=0x%08x "
+            "descriptor=%d\n", txRegOffset, val, descriptor);
+
+        /* handle Dump Tally Counters command */
+        s->TxStatus[descriptor] = val;
+
+        if (descriptor == 0 && (val & 0x8))
+        {
+            hwaddr tc_addr = rtl8139_addr64(s->TxStatus[0] & ~0x3f, s->TxStatus[1]);
+
+            /* dump tally counters to specified memory location */
+            RTL8139TallyCounters_dma_write(s, tc_addr);
+
+            /* mark dump completed */
+            s->TxStatus[0] &= ~0x8;
+        }
+
+        return;
+    }
+
+    DPRINTF("TxStatus write offset=0x%x val=0x%08x descriptor=%d\n",
+        txRegOffset, val, descriptor);
+
+    /* mask only reserved bits */
+    val &= ~0xff00c000; /* these bits are reset on write */
+    val = SET_MASKED(val, 0x00c00000, s->TxStatus[descriptor]);
+
+    s->TxStatus[descriptor] = val;
+
+    /* attempt to start transmission */
+    rtl8139_transmit(s);
+}
+
+static uint32_t rtl8139_TxStatus_TxAddr_read(RTL8139State *s, uint32_t regs[],
+                                             uint32_t base, uint8_t addr,
+                                             int size)
+{
+    uint32_t reg = (addr - base) / 4;
+    uint32_t offset = addr & 0x3;
+    uint32_t ret = 0;
+
+    if (addr & (size - 1)) {
+        DPRINTF("not implemented read for TxStatus/TxAddr "
+                "addr=0x%x size=0x%x\n", addr, size);
+        return ret;
+    }
+
+    switch (size) {
+    case 1: /* fall through */
+    case 2: /* fall through */
+    case 4:
+        ret = (regs[reg] >> offset * 8) & (((uint64_t)1 << (size * 8)) - 1);
+        DPRINTF("TxStatus/TxAddr[%d] read addr=0x%x size=0x%x val=0x%08x\n",
+                reg, addr, size, ret);
+        break;
+    default:
+        DPRINTF("unsupported size 0x%x of TxStatus/TxAddr reading\n", size);
+        break;
+    }
+
+    return ret;
+}
+
+static uint16_t rtl8139_TSAD_read(RTL8139State *s)
+{
+    uint16_t ret = 0;
+
+    /* Simulate TSAD, it is read only anyway */
+
+    ret = ((s->TxStatus[3] & TxStatOK  )?TSAD_TOK3:0)
+         |((s->TxStatus[2] & TxStatOK  )?TSAD_TOK2:0)
+         |((s->TxStatus[1] & TxStatOK  )?TSAD_TOK1:0)
+         |((s->TxStatus[0] & TxStatOK  )?TSAD_TOK0:0)
+
+         |((s->TxStatus[3] & TxUnderrun)?TSAD_TUN3:0)
+         |((s->TxStatus[2] & TxUnderrun)?TSAD_TUN2:0)
+         |((s->TxStatus[1] & TxUnderrun)?TSAD_TUN1:0)
+         |((s->TxStatus[0] & TxUnderrun)?TSAD_TUN0:0)
+
+         |((s->TxStatus[3] & TxAborted )?TSAD_TABT3:0)
+         |((s->TxStatus[2] & TxAborted )?TSAD_TABT2:0)
+         |((s->TxStatus[1] & TxAborted )?TSAD_TABT1:0)
+         |((s->TxStatus[0] & TxAborted )?TSAD_TABT0:0)
+
+         |((s->TxStatus[3] & TxHostOwns )?TSAD_OWN3:0)
+         |((s->TxStatus[2] & TxHostOwns )?TSAD_OWN2:0)
+         |((s->TxStatus[1] & TxHostOwns )?TSAD_OWN1:0)
+         |((s->TxStatus[0] & TxHostOwns )?TSAD_OWN0:0) ;
+
+
+    DPRINTF("TSAD read val=0x%04x\n", ret);
+
+    return ret;
+}
+
+static uint16_t rtl8139_CSCR_read(RTL8139State *s)
+{
+    uint16_t ret = s->CSCR;
+
+    DPRINTF("CSCR read val=0x%04x\n", ret);
+
+    return ret;
+}
+
+static void rtl8139_TxAddr_write(RTL8139State *s, uint32_t txAddrOffset, uint32_t val)
+{
+    DPRINTF("TxAddr write offset=0x%x val=0x%08x\n", txAddrOffset, val);
+
+    s->TxAddr[txAddrOffset/4] = val;
+}
+
+static uint32_t rtl8139_TxAddr_read(RTL8139State *s, uint32_t txAddrOffset)
+{
+    uint32_t ret = s->TxAddr[txAddrOffset/4];
+
+    DPRINTF("TxAddr read offset=0x%x val=0x%08x\n", txAddrOffset, ret);
+
+    return ret;
+}
+
+static void rtl8139_RxBufPtr_write(RTL8139State *s, uint32_t val)
+{
+    DPRINTF("RxBufPtr write val=0x%04x\n", val);
+
+    /* this value is off by 16 */
+    s->RxBufPtr = MOD2(val + 0x10, s->RxBufferSize);
+
+    DPRINTF(" CAPR write: rx buffer length %d head 0x%04x read 0x%04x\n",
+        s->RxBufferSize, s->RxBufAddr, s->RxBufPtr);
+}
+
+static uint32_t rtl8139_RxBufPtr_read(RTL8139State *s)
+{
+    /* this value is off by 16 */
+    uint32_t ret = s->RxBufPtr - 0x10;
+
+    DPRINTF("RxBufPtr read val=0x%04x\n", ret);
+
+    return ret;
+}
+
+static uint32_t rtl8139_RxBufAddr_read(RTL8139State *s)
+{
+    /* this value is NOT off by 16 */
+    uint32_t ret = s->RxBufAddr;
+
+    DPRINTF("RxBufAddr read val=0x%04x\n", ret);
+
+    return ret;
+}
+
+static void rtl8139_RxBuf_write(RTL8139State *s, uint32_t val)
+{
+    DPRINTF("RxBuf write val=0x%08x\n", val);
+
+    s->RxBuf = val;
+
+    /* may need to reset rxring here */
+}
+
+static uint32_t rtl8139_RxBuf_read(RTL8139State *s)
+{
+    uint32_t ret = s->RxBuf;
+
+    DPRINTF("RxBuf read val=0x%08x\n", ret);
+
+    return ret;
+}
+
+static void rtl8139_IntrMask_write(RTL8139State *s, uint32_t val)
+{
+    DPRINTF("IntrMask write(w) val=0x%04x\n", val);
+
+    /* mask unwritable bits */
+    val = SET_MASKED(val, 0x1e00, s->IntrMask);
+
+    s->IntrMask = val;
+
+    rtl8139_set_next_tctr_time(s, qemu_get_clock_ns(vm_clock));
+    rtl8139_update_irq(s);
+
+}
+
+static uint32_t rtl8139_IntrMask_read(RTL8139State *s)
+{
+    uint32_t ret = s->IntrMask;
+
+    DPRINTF("IntrMask read(w) val=0x%04x\n", ret);
+
+    return ret;
+}
+
+static void rtl8139_IntrStatus_write(RTL8139State *s, uint32_t val)
+{
+    DPRINTF("IntrStatus write(w) val=0x%04x\n", val);
+
+#if 0
+
+    /* writing to ISR has no effect */
+
+    return;
+
+#else
+    uint16_t newStatus = s->IntrStatus & ~val;
+
+    /* mask unwritable bits */
+    newStatus = SET_MASKED(newStatus, 0x1e00, s->IntrStatus);
+
+    /* writing 1 to interrupt status register bit clears it */
+    s->IntrStatus = 0;
+    rtl8139_update_irq(s);
+
+    s->IntrStatus = newStatus;
+    /*
+     * Computing if we miss an interrupt here is not that correct but
+     * considered that we should have had already an interrupt
+     * and probably emulated is slower is better to assume this resetting was
+     * done before testing on previous rtl8139_update_irq lead to IRQ losing
+     */
+    rtl8139_set_next_tctr_time(s, qemu_get_clock_ns(vm_clock));
+    rtl8139_update_irq(s);
+
+#endif
+}
+
+static uint32_t rtl8139_IntrStatus_read(RTL8139State *s)
+{
+    rtl8139_set_next_tctr_time(s, qemu_get_clock_ns(vm_clock));
+
+    uint32_t ret = s->IntrStatus;
+
+    DPRINTF("IntrStatus read(w) val=0x%04x\n", ret);
+
+#if 0
+
+    /* reading ISR clears all interrupts */
+    s->IntrStatus = 0;
+
+    rtl8139_update_irq(s);
+
+#endif
+
+    return ret;
+}
+
+static void rtl8139_MultiIntr_write(RTL8139State *s, uint32_t val)
+{
+    DPRINTF("MultiIntr write(w) val=0x%04x\n", val);
+
+    /* mask unwritable bits */
+    val = SET_MASKED(val, 0xf000, s->MultiIntr);
+
+    s->MultiIntr = val;
+}
+
+static uint32_t rtl8139_MultiIntr_read(RTL8139State *s)
+{
+    uint32_t ret = s->MultiIntr;
+
+    DPRINTF("MultiIntr read(w) val=0x%04x\n", ret);
+
+    return ret;
+}
+
+static void rtl8139_io_writeb(void *opaque, uint8_t addr, uint32_t val)
+{
+    RTL8139State *s = opaque;
+
+    switch (addr)
+    {
+        case MAC0 ... MAC0+5:
+            s->phys[addr - MAC0] = val;
+            break;
+        case MAC0+6 ... MAC0+7:
+            /* reserved */
+            break;
+        case MAR0 ... MAR0+7:
+            s->mult[addr - MAR0] = val;
+            break;
+        case ChipCmd:
+            rtl8139_ChipCmd_write(s, val);
+            break;
+        case Cfg9346:
+            rtl8139_Cfg9346_write(s, val);
+            break;
+        case TxConfig: /* windows driver sometimes writes using byte-lenth call */
+            rtl8139_TxConfig_writeb(s, val);
+            break;
+        case Config0:
+            rtl8139_Config0_write(s, val);
+            break;
+        case Config1:
+            rtl8139_Config1_write(s, val);
+            break;
+        case Config3:
+            rtl8139_Config3_write(s, val);
+            break;
+        case Config4:
+            rtl8139_Config4_write(s, val);
+            break;
+        case Config5:
+            rtl8139_Config5_write(s, val);
+            break;
+        case MediaStatus:
+            /* ignore */
+            DPRINTF("not implemented write(b) to MediaStatus val=0x%02x\n",
+                val);
+            break;
+
+        case HltClk:
+            DPRINTF("HltClk write val=0x%08x\n", val);
+            if (val == 'R')
+            {
+                s->clock_enabled = 1;
+            }
+            else if (val == 'H')
+            {
+                s->clock_enabled = 0;
+            }
+            break;
+
+        case TxThresh:
+            DPRINTF("C+ TxThresh write(b) val=0x%02x\n", val);
+            s->TxThresh = val;
+            break;
+
+        case TxPoll:
+            DPRINTF("C+ TxPoll write(b) val=0x%02x\n", val);
+            if (val & (1 << 7))
+            {
+                DPRINTF("C+ TxPoll high priority transmission (not "
+                    "implemented)\n");
+                //rtl8139_cplus_transmit(s);
+            }
+            if (val & (1 << 6))
+            {
+                DPRINTF("C+ TxPoll normal priority transmission\n");
+                rtl8139_cplus_transmit(s);
+            }
+
+            break;
+
+        default:
+            DPRINTF("not implemented write(b) addr=0x%x val=0x%02x\n", addr,
+                val);
+            break;
+    }
+}
+
+static void rtl8139_io_writew(void *opaque, uint8_t addr, uint32_t val)
+{
+    RTL8139State *s = opaque;
+
+    switch (addr)
+    {
+        case IntrMask:
+            rtl8139_IntrMask_write(s, val);
+            break;
+
+        case IntrStatus:
+            rtl8139_IntrStatus_write(s, val);
+            break;
+
+        case MultiIntr:
+            rtl8139_MultiIntr_write(s, val);
+            break;
+
+        case RxBufPtr:
+            rtl8139_RxBufPtr_write(s, val);
+            break;
+
+        case BasicModeCtrl:
+            rtl8139_BasicModeCtrl_write(s, val);
+            break;
+        case BasicModeStatus:
+            rtl8139_BasicModeStatus_write(s, val);
+            break;
+        case NWayAdvert:
+            DPRINTF("NWayAdvert write(w) val=0x%04x\n", val);
+            s->NWayAdvert = val;
+            break;
+        case NWayLPAR:
+            DPRINTF("forbidden NWayLPAR write(w) val=0x%04x\n", val);
+            break;
+        case NWayExpansion:
+            DPRINTF("NWayExpansion write(w) val=0x%04x\n", val);
+            s->NWayExpansion = val;
+            break;
+
+        case CpCmd:
+            rtl8139_CpCmd_write(s, val);
+            break;
+
+        case IntrMitigate:
+            rtl8139_IntrMitigate_write(s, val);
+            break;
+
+        default:
+            DPRINTF("ioport write(w) addr=0x%x val=0x%04x via write(b)\n",
+                addr, val);
+
+            rtl8139_io_writeb(opaque, addr, val & 0xff);
+            rtl8139_io_writeb(opaque, addr + 1, (val >> 8) & 0xff);
+            break;
+    }
+}
+
+static void rtl8139_set_next_tctr_time(RTL8139State *s, int64_t current_time)
+{
+    int64_t pci_time, next_time;
+    uint32_t low_pci;
+
+    DPRINTF("entered rtl8139_set_next_tctr_time\n");
+
+    if (s->TimerExpire && current_time >= s->TimerExpire) {
+        s->IntrStatus |= PCSTimeout;
+        rtl8139_update_irq(s);
+    }
+
+    /* Set QEMU timer only if needed that is
+     * - TimerInt <> 0 (we have a timer)
+     * - mask = 1 (we want an interrupt timer)
+     * - irq = 0  (irq is not already active)
+     * If any of above change we need to compute timer again
+     * Also we must check if timer is passed without QEMU timer
+     */
+    s->TimerExpire = 0;
+    if (!s->TimerInt) {
+        return;
+    }
+
+    pci_time = muldiv64(current_time - s->TCTR_base, PCI_FREQUENCY,
+                                get_ticks_per_sec());
+    low_pci = pci_time & 0xffffffff;
+    pci_time = pci_time - low_pci + s->TimerInt;
+    if (low_pci >= s->TimerInt) {
+        pci_time += 0x100000000LL;
+    }
+    next_time = s->TCTR_base + muldiv64(pci_time, get_ticks_per_sec(),
+                                                PCI_FREQUENCY);
+    s->TimerExpire = next_time;
+
+    if ((s->IntrMask & PCSTimeout) != 0 && (s->IntrStatus & PCSTimeout) == 0) {
+        qemu_mod_timer(s->timer, next_time);
+    }
+}
+
+static void rtl8139_io_writel(void *opaque, uint8_t addr, uint32_t val)
+{
+    RTL8139State *s = opaque;
+
+    switch (addr)
+    {
+        case RxMissed:
+            DPRINTF("RxMissed clearing on write\n");
+            s->RxMissed = 0;
+            break;
+
+        case TxConfig:
+            rtl8139_TxConfig_write(s, val);
+            break;
+
+        case RxConfig:
+            rtl8139_RxConfig_write(s, val);
+            break;
+
+        case TxStatus0 ... TxStatus0+4*4-1:
+            rtl8139_TxStatus_write(s, addr-TxStatus0, val);
+            break;
+
+        case TxAddr0 ... TxAddr0+4*4-1:
+            rtl8139_TxAddr_write(s, addr-TxAddr0, val);
+            break;
+
+        case RxBuf:
+            rtl8139_RxBuf_write(s, val);
+            break;
+
+        case RxRingAddrLO:
+            DPRINTF("C+ RxRing low bits write val=0x%08x\n", val);
+            s->RxRingAddrLO = val;
+            break;
+
+        case RxRingAddrHI:
+            DPRINTF("C+ RxRing high bits write val=0x%08x\n", val);
+            s->RxRingAddrHI = val;
+            break;
+
+        case Timer:
+            DPRINTF("TCTR Timer reset on write\n");
+            s->TCTR_base = qemu_get_clock_ns(vm_clock);
+            rtl8139_set_next_tctr_time(s, s->TCTR_base);
+            break;
+
+        case FlashReg:
+            DPRINTF("FlashReg TimerInt write val=0x%08x\n", val);
+            if (s->TimerInt != val) {
+                s->TimerInt = val;
+                rtl8139_set_next_tctr_time(s, qemu_get_clock_ns(vm_clock));
+            }
+            break;
+
+        default:
+            DPRINTF("ioport write(l) addr=0x%x val=0x%08x via write(b)\n",
+                addr, val);
+            rtl8139_io_writeb(opaque, addr, val & 0xff);
+            rtl8139_io_writeb(opaque, addr + 1, (val >> 8) & 0xff);
+            rtl8139_io_writeb(opaque, addr + 2, (val >> 16) & 0xff);
+            rtl8139_io_writeb(opaque, addr + 3, (val >> 24) & 0xff);
+            break;
+    }
+}
+
+static uint32_t rtl8139_io_readb(void *opaque, uint8_t addr)
+{
+    RTL8139State *s = opaque;
+    int ret;
+
+    switch (addr)
+    {
+        case MAC0 ... MAC0+5:
+            ret = s->phys[addr - MAC0];
+            break;
+        case MAC0+6 ... MAC0+7:
+            ret = 0;
+            break;
+        case MAR0 ... MAR0+7:
+            ret = s->mult[addr - MAR0];
+            break;
+        case TxStatus0 ... TxStatus0+4*4-1:
+            ret = rtl8139_TxStatus_TxAddr_read(s, s->TxStatus, TxStatus0,
+                                               addr, 1);
+            break;
+        case ChipCmd:
+            ret = rtl8139_ChipCmd_read(s);
+            break;
+        case Cfg9346:
+            ret = rtl8139_Cfg9346_read(s);
+            break;
+        case Config0:
+            ret = rtl8139_Config0_read(s);
+            break;
+        case Config1:
+            ret = rtl8139_Config1_read(s);
+            break;
+        case Config3:
+            ret = rtl8139_Config3_read(s);
+            break;
+        case Config4:
+            ret = rtl8139_Config4_read(s);
+            break;
+        case Config5:
+            ret = rtl8139_Config5_read(s);
+            break;
+
+        case MediaStatus:
+            /* The LinkDown bit of MediaStatus is inverse with link status */
+            ret = 0xd0 | (~s->BasicModeStatus & 0x04);
+            DPRINTF("MediaStatus read 0x%x\n", ret);
+            break;
+
+        case HltClk:
+            ret = s->clock_enabled;
+            DPRINTF("HltClk read 0x%x\n", ret);
+            break;
+
+        case PCIRevisionID:
+            ret = RTL8139_PCI_REVID;
+            DPRINTF("PCI Revision ID read 0x%x\n", ret);
+            break;
+
+        case TxThresh:
+            ret = s->TxThresh;
+            DPRINTF("C+ TxThresh read(b) val=0x%02x\n", ret);
+            break;
+
+        case 0x43: /* Part of TxConfig register. Windows driver tries to read it */
+            ret = s->TxConfig >> 24;
+            DPRINTF("RTL8139C TxConfig at 0x43 read(b) val=0x%02x\n", ret);
+            break;
+
+        default:
+            DPRINTF("not implemented read(b) addr=0x%x\n", addr);
+            ret = 0;
+            break;
+    }
+
+    return ret;
+}
+
+static uint32_t rtl8139_io_readw(void *opaque, uint8_t addr)
+{
+    RTL8139State *s = opaque;
+    uint32_t ret;
+
+    switch (addr)
+    {
+        case TxAddr0 ... TxAddr0+4*4-1:
+            ret = rtl8139_TxStatus_TxAddr_read(s, s->TxAddr, TxAddr0, addr, 2);
+            break;
+        case IntrMask:
+            ret = rtl8139_IntrMask_read(s);
+            break;
+
+        case IntrStatus:
+            ret = rtl8139_IntrStatus_read(s);
+            break;
+
+        case MultiIntr:
+            ret = rtl8139_MultiIntr_read(s);
+            break;
+
+        case RxBufPtr:
+            ret = rtl8139_RxBufPtr_read(s);
+            break;
+
+        case RxBufAddr:
+            ret = rtl8139_RxBufAddr_read(s);
+            break;
+
+        case BasicModeCtrl:
+            ret = rtl8139_BasicModeCtrl_read(s);
+            break;
+        case BasicModeStatus:
+            ret = rtl8139_BasicModeStatus_read(s);
+            break;
+        case NWayAdvert:
+            ret = s->NWayAdvert;
+            DPRINTF("NWayAdvert read(w) val=0x%04x\n", ret);
+            break;
+        case NWayLPAR:
+            ret = s->NWayLPAR;
+            DPRINTF("NWayLPAR read(w) val=0x%04x\n", ret);
+            break;
+        case NWayExpansion:
+            ret = s->NWayExpansion;
+            DPRINTF("NWayExpansion read(w) val=0x%04x\n", ret);
+            break;
+
+        case CpCmd:
+            ret = rtl8139_CpCmd_read(s);
+            break;
+
+        case IntrMitigate:
+            ret = rtl8139_IntrMitigate_read(s);
+            break;
+
+        case TxSummary:
+            ret = rtl8139_TSAD_read(s);
+            break;
+
+        case CSCR:
+            ret = rtl8139_CSCR_read(s);
+            break;
+
+        default:
+            DPRINTF("ioport read(w) addr=0x%x via read(b)\n", addr);
+
+            ret  = rtl8139_io_readb(opaque, addr);
+            ret |= rtl8139_io_readb(opaque, addr + 1) << 8;
+
+            DPRINTF("ioport read(w) addr=0x%x val=0x%04x\n", addr, ret);
+            break;
+    }
+
+    return ret;
+}
+
+static uint32_t rtl8139_io_readl(void *opaque, uint8_t addr)
+{
+    RTL8139State *s = opaque;
+    uint32_t ret;
+
+    switch (addr)
+    {
+        case RxMissed:
+            ret = s->RxMissed;
+
+            DPRINTF("RxMissed read val=0x%08x\n", ret);
+            break;
+
+        case TxConfig:
+            ret = rtl8139_TxConfig_read(s);
+            break;
+
+        case RxConfig:
+            ret = rtl8139_RxConfig_read(s);
+            break;
+
+        case TxStatus0 ... TxStatus0+4*4-1:
+            ret = rtl8139_TxStatus_TxAddr_read(s, s->TxStatus, TxStatus0,
+                                               addr, 4);
+            break;
+
+        case TxAddr0 ... TxAddr0+4*4-1:
+            ret = rtl8139_TxAddr_read(s, addr-TxAddr0);
+            break;
+
+        case RxBuf:
+            ret = rtl8139_RxBuf_read(s);
+            break;
+
+        case RxRingAddrLO:
+            ret = s->RxRingAddrLO;
+            DPRINTF("C+ RxRing low bits read val=0x%08x\n", ret);
+            break;
+
+        case RxRingAddrHI:
+            ret = s->RxRingAddrHI;
+            DPRINTF("C+ RxRing high bits read val=0x%08x\n", ret);
+            break;
+
+        case Timer:
+            ret = muldiv64(qemu_get_clock_ns(vm_clock) - s->TCTR_base,
+                           PCI_FREQUENCY, get_ticks_per_sec());
+            DPRINTF("TCTR Timer read val=0x%08x\n", ret);
+            break;
+
+        case FlashReg:
+            ret = s->TimerInt;
+            DPRINTF("FlashReg TimerInt read val=0x%08x\n", ret);
+            break;
+
+        default:
+            DPRINTF("ioport read(l) addr=0x%x via read(b)\n", addr);
+
+            ret  = rtl8139_io_readb(opaque, addr);
+            ret |= rtl8139_io_readb(opaque, addr + 1) << 8;
+            ret |= rtl8139_io_readb(opaque, addr + 2) << 16;
+            ret |= rtl8139_io_readb(opaque, addr + 3) << 24;
+
+            DPRINTF("read(l) addr=0x%x val=%08x\n", addr, ret);
+            break;
+    }
+
+    return ret;
+}
+
+/* */
+
+static void rtl8139_mmio_writeb(void *opaque, hwaddr addr, uint32_t val)
+{
+    rtl8139_io_writeb(opaque, addr & 0xFF, val);
+}
+
+static void rtl8139_mmio_writew(void *opaque, hwaddr addr, uint32_t val)
+{
+    rtl8139_io_writew(opaque, addr & 0xFF, val);
+}
+
+static void rtl8139_mmio_writel(void *opaque, hwaddr addr, uint32_t val)
+{
+    rtl8139_io_writel(opaque, addr & 0xFF, val);
+}
+
+static uint32_t rtl8139_mmio_readb(void *opaque, hwaddr addr)
+{
+    return rtl8139_io_readb(opaque, addr & 0xFF);
+}
+
+static uint32_t rtl8139_mmio_readw(void *opaque, hwaddr addr)
+{
+    uint32_t val = rtl8139_io_readw(opaque, addr & 0xFF);
+    return val;
+}
+
+static uint32_t rtl8139_mmio_readl(void *opaque, hwaddr addr)
+{
+    uint32_t val = rtl8139_io_readl(opaque, addr & 0xFF);
+    return val;
+}
+
+static int rtl8139_post_load(void *opaque, int version_id)
+{
+    RTL8139State* s = opaque;
+    rtl8139_set_next_tctr_time(s, qemu_get_clock_ns(vm_clock));
+    if (version_id < 4) {
+        s->cplus_enabled = s->CpCmd != 0;
+    }
+
+    /* nc.link_down can't be migrated, so infer link_down according
+     * to link status bit in BasicModeStatus */
+    qemu_get_queue(s->nic)->link_down = (s->BasicModeStatus & 0x04) == 0;
+
+    return 0;
+}
+
+static bool rtl8139_hotplug_ready_needed(void *opaque)
+{
+    return qdev_machine_modified();
+}
+
+static const VMStateDescription vmstate_rtl8139_hotplug_ready ={
+    .name = "rtl8139/hotplug_ready",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void rtl8139_pre_save(void *opaque)
+{
+    RTL8139State* s = opaque;
+    int64_t current_time = qemu_get_clock_ns(vm_clock);
+
+    /* set IntrStatus correctly */
+    rtl8139_set_next_tctr_time(s, current_time);
+    s->TCTR = muldiv64(current_time - s->TCTR_base, PCI_FREQUENCY,
+                       get_ticks_per_sec());
+    s->rtl8139_mmio_io_addr_dummy = 0;
+}
+
+static const VMStateDescription vmstate_rtl8139 = {
+    .name = "rtl8139",
+    .version_id = 4,
+    .minimum_version_id = 3,
+    .minimum_version_id_old = 3,
+    .post_load = rtl8139_post_load,
+    .pre_save  = rtl8139_pre_save,
+    .fields      = (VMStateField []) {
+        VMSTATE_PCI_DEVICE(dev, RTL8139State),
+        VMSTATE_PARTIAL_BUFFER(phys, RTL8139State, 6),
+        VMSTATE_BUFFER(mult, RTL8139State),
+        VMSTATE_UINT32_ARRAY(TxStatus, RTL8139State, 4),
+        VMSTATE_UINT32_ARRAY(TxAddr, RTL8139State, 4),
+
+        VMSTATE_UINT32(RxBuf, RTL8139State),
+        VMSTATE_UINT32(RxBufferSize, RTL8139State),
+        VMSTATE_UINT32(RxBufPtr, RTL8139State),
+        VMSTATE_UINT32(RxBufAddr, RTL8139State),
+
+        VMSTATE_UINT16(IntrStatus, RTL8139State),
+        VMSTATE_UINT16(IntrMask, RTL8139State),
+
+        VMSTATE_UINT32(TxConfig, RTL8139State),
+        VMSTATE_UINT32(RxConfig, RTL8139State),
+        VMSTATE_UINT32(RxMissed, RTL8139State),
+        VMSTATE_UINT16(CSCR, RTL8139State),
+
+        VMSTATE_UINT8(Cfg9346, RTL8139State),
+        VMSTATE_UINT8(Config0, RTL8139State),
+        VMSTATE_UINT8(Config1, RTL8139State),
+        VMSTATE_UINT8(Config3, RTL8139State),
+        VMSTATE_UINT8(Config4, RTL8139State),
+        VMSTATE_UINT8(Config5, RTL8139State),
+
+        VMSTATE_UINT8(clock_enabled, RTL8139State),
+        VMSTATE_UINT8(bChipCmdState, RTL8139State),
+
+        VMSTATE_UINT16(MultiIntr, RTL8139State),
+
+        VMSTATE_UINT16(BasicModeCtrl, RTL8139State),
+        VMSTATE_UINT16(BasicModeStatus, RTL8139State),
+        VMSTATE_UINT16(NWayAdvert, RTL8139State),
+        VMSTATE_UINT16(NWayLPAR, RTL8139State),
+        VMSTATE_UINT16(NWayExpansion, RTL8139State),
+
+        VMSTATE_UINT16(CpCmd, RTL8139State),
+        VMSTATE_UINT8(TxThresh, RTL8139State),
+
+        VMSTATE_UNUSED(4),
+        VMSTATE_MACADDR(conf.macaddr, RTL8139State),
+        VMSTATE_INT32(rtl8139_mmio_io_addr_dummy, RTL8139State),
+
+        VMSTATE_UINT32(currTxDesc, RTL8139State),
+        VMSTATE_UINT32(currCPlusRxDesc, RTL8139State),
+        VMSTATE_UINT32(currCPlusTxDesc, RTL8139State),
+        VMSTATE_UINT32(RxRingAddrLO, RTL8139State),
+        VMSTATE_UINT32(RxRingAddrHI, RTL8139State),
+
+        VMSTATE_UINT16_ARRAY(eeprom.contents, RTL8139State, EEPROM_9346_SIZE),
+        VMSTATE_INT32(eeprom.mode, RTL8139State),
+        VMSTATE_UINT32(eeprom.tick, RTL8139State),
+        VMSTATE_UINT8(eeprom.address, RTL8139State),
+        VMSTATE_UINT16(eeprom.input, RTL8139State),
+        VMSTATE_UINT16(eeprom.output, RTL8139State),
+
+        VMSTATE_UINT8(eeprom.eecs, RTL8139State),
+        VMSTATE_UINT8(eeprom.eesk, RTL8139State),
+        VMSTATE_UINT8(eeprom.eedi, RTL8139State),
+        VMSTATE_UINT8(eeprom.eedo, RTL8139State),
+
+        VMSTATE_UINT32(TCTR, RTL8139State),
+        VMSTATE_UINT32(TimerInt, RTL8139State),
+        VMSTATE_INT64(TCTR_base, RTL8139State),
+
+        VMSTATE_STRUCT(tally_counters, RTL8139State, 0,
+                       vmstate_tally_counters, RTL8139TallyCounters),
+
+        VMSTATE_UINT32_V(cplus_enabled, RTL8139State, 4),
+        VMSTATE_END_OF_LIST()
+    },
+    .subsections = (VMStateSubsection []) {
+        {
+            .vmsd = &vmstate_rtl8139_hotplug_ready,
+            .needed = rtl8139_hotplug_ready_needed,
+        }, {
+            /* empty */
+        }
+    }
+};
+
+/***********************************************************/
+/* PCI RTL8139 definitions */
+
+static void rtl8139_ioport_write(void *opaque, hwaddr addr,
+                                 uint64_t val, unsigned size)
+{
+    switch (size) {
+    case 1:
+        rtl8139_io_writeb(opaque, addr, val);
+        break;
+    case 2:
+        rtl8139_io_writew(opaque, addr, val);
+        break;
+    case 4:
+        rtl8139_io_writel(opaque, addr, val);
+        break;
+    }
+}
+
+static uint64_t rtl8139_ioport_read(void *opaque, hwaddr addr,
+                                    unsigned size)
+{
+    switch (size) {
+    case 1:
+        return rtl8139_io_readb(opaque, addr);
+    case 2:
+        return rtl8139_io_readw(opaque, addr);
+    case 4:
+        return rtl8139_io_readl(opaque, addr);
+    }
+
+    return -1;
+}
+
+static const MemoryRegionOps rtl8139_io_ops = {
+    .read = rtl8139_ioport_read,
+    .write = rtl8139_ioport_write,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 4,
+    },
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static const MemoryRegionOps rtl8139_mmio_ops = {
+    .old_mmio = {
+        .read = {
+            rtl8139_mmio_readb,
+            rtl8139_mmio_readw,
+            rtl8139_mmio_readl,
+        },
+        .write = {
+            rtl8139_mmio_writeb,
+            rtl8139_mmio_writew,
+            rtl8139_mmio_writel,
+        },
+    },
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void rtl8139_timer(void *opaque)
+{
+    RTL8139State *s = opaque;
+
+    if (!s->clock_enabled)
+    {
+        DPRINTF(">>> timer: clock is not running\n");
+        return;
+    }
+
+    s->IntrStatus |= PCSTimeout;
+    rtl8139_update_irq(s);
+    rtl8139_set_next_tctr_time(s, qemu_get_clock_ns(vm_clock));
+}
+
+static void rtl8139_cleanup(NetClientState *nc)
+{
+    RTL8139State *s = qemu_get_nic_opaque(nc);
+
+    s->nic = NULL;
+}
+
+static void pci_rtl8139_uninit(PCIDevice *dev)
+{
+    RTL8139State *s = DO_UPCAST(RTL8139State, dev, dev);
+
+    memory_region_destroy(&s->bar_io);
+    memory_region_destroy(&s->bar_mem);
+    if (s->cplus_txbuffer) {
+        g_free(s->cplus_txbuffer);
+        s->cplus_txbuffer = NULL;
+    }
+    qemu_del_timer(s->timer);
+    qemu_free_timer(s->timer);
+    qemu_del_nic(s->nic);
+}
+
+static void rtl8139_set_link_status(NetClientState *nc)
+{
+    RTL8139State *s = qemu_get_nic_opaque(nc);
+
+    if (nc->link_down) {
+        s->BasicModeStatus &= ~0x04;
+    } else {
+        s->BasicModeStatus |= 0x04;
+    }
+
+    s->IntrStatus |= RxUnderrun;
+    rtl8139_update_irq(s);
+}
+
+static NetClientInfo net_rtl8139_info = {
+    .type = NET_CLIENT_OPTIONS_KIND_NIC,
+    .size = sizeof(NICState),
+    .can_receive = rtl8139_can_receive,
+    .receive = rtl8139_receive,
+    .cleanup = rtl8139_cleanup,
+    .link_status_changed = rtl8139_set_link_status,
+};
+
+static int pci_rtl8139_init(PCIDevice *dev)
+{
+    RTL8139State * s = DO_UPCAST(RTL8139State, dev, dev);
+    uint8_t *pci_conf;
+
+    pci_conf = s->dev.config;
+    pci_conf[PCI_INTERRUPT_PIN] = 1;    /* interrupt pin A */
+    /* TODO: start of capability list, but no capability
+     * list bit in status register, and offset 0xdc seems unused. */
+    pci_conf[PCI_CAPABILITY_LIST] = 0xdc;
+
+    memory_region_init_io(&s->bar_io, &rtl8139_io_ops, s, "rtl8139", 0x100);
+    memory_region_init_io(&s->bar_mem, &rtl8139_mmio_ops, s, "rtl8139", 0x100);
+    pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->bar_io);
+    pci_register_bar(&s->dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar_mem);
+
+    qemu_macaddr_default_if_unset(&s->conf.macaddr);
+
+    /* prepare eeprom */
+    s->eeprom.contents[0] = 0x8129;
+#if 1
+    /* PCI vendor and device ID should be mirrored here */
+    s->eeprom.contents[1] = PCI_VENDOR_ID_REALTEK;
+    s->eeprom.contents[2] = PCI_DEVICE_ID_REALTEK_8139;
+#endif
+    s->eeprom.contents[7] = s->conf.macaddr.a[0] | s->conf.macaddr.a[1] << 8;
+    s->eeprom.contents[8] = s->conf.macaddr.a[2] | s->conf.macaddr.a[3] << 8;
+    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,
+                          object_get_typename(OBJECT(dev)), dev->qdev.id, s);
+    qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
+
+    s->cplus_txbuffer = NULL;
+    s->cplus_txbuffer_len = 0;
+    s->cplus_txbuffer_offset = 0;
+
+    s->TimerExpire = 0;
+    s->timer = qemu_new_timer_ns(vm_clock, rtl8139_timer, s);
+    rtl8139_set_next_tctr_time(s, qemu_get_clock_ns(vm_clock));
+
+    add_boot_device_path(s->conf.bootindex, &dev->qdev, "/ethernet-phy@0");
+
+    return 0;
+}
+
+static Property rtl8139_properties[] = {
+    DEFINE_NIC_PROPERTIES(RTL8139State, conf),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void rtl8139_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = pci_rtl8139_init;
+    k->exit = pci_rtl8139_uninit;
+    k->romfile = "efi-rtl8139.rom";
+    k->vendor_id = PCI_VENDOR_ID_REALTEK;
+    k->device_id = PCI_DEVICE_ID_REALTEK_8139;
+    k->revision = RTL8139_PCI_REVID; /* >=0x20 is for 8139C+ */
+    k->class_id = PCI_CLASS_NETWORK_ETHERNET;
+    dc->reset = rtl8139_reset;
+    dc->vmsd = &vmstate_rtl8139;
+    dc->props = rtl8139_properties;
+}
+
+static const TypeInfo rtl8139_info = {
+    .name          = "rtl8139",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(RTL8139State),
+    .class_init    = rtl8139_class_init,
+};
+
+static void rtl8139_register_types(void)
+{
+    type_register_static(&rtl8139_info);
+}
+
+type_init(rtl8139_register_types)
diff --git a/hw/net/smc91c111.c b/hw/net/smc91c111.c
new file mode 100644 (file)
index 0000000..f659256
--- /dev/null
@@ -0,0 +1,806 @@
+/*
+ * SMSC 91C111 Ethernet interface emulation
+ *
+ * Copyright (c) 2005 CodeSourcery, LLC.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the GPL
+ */
+
+#include "hw/sysbus.h"
+#include "net/net.h"
+#include "hw/arm/devices.h"
+/* For crc32 */
+#include <zlib.h>
+
+/* Number of 2k memory pages available.  */
+#define NUM_PACKETS 4
+
+typedef struct {
+    SysBusDevice busdev;
+    NICState *nic;
+    NICConf conf;
+    uint16_t tcr;
+    uint16_t rcr;
+    uint16_t cr;
+    uint16_t ctr;
+    uint16_t gpr;
+    uint16_t ptr;
+    uint16_t ercv;
+    qemu_irq irq;
+    int bank;
+    int packet_num;
+    int tx_alloc;
+    /* Bitmask of allocated packets.  */
+    int allocated;
+    int tx_fifo_len;
+    int tx_fifo[NUM_PACKETS];
+    int rx_fifo_len;
+    int rx_fifo[NUM_PACKETS];
+    int tx_fifo_done_len;
+    int tx_fifo_done[NUM_PACKETS];
+    /* Packet buffer memory.  */
+    uint8_t data[NUM_PACKETS][2048];
+    uint8_t int_level;
+    uint8_t int_mask;
+    MemoryRegion mmio;
+} smc91c111_state;
+
+static const VMStateDescription vmstate_smc91c111 = {
+    .name = "smc91c111",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT16(tcr, smc91c111_state),
+        VMSTATE_UINT16(rcr, smc91c111_state),
+        VMSTATE_UINT16(cr, smc91c111_state),
+        VMSTATE_UINT16(ctr, smc91c111_state),
+        VMSTATE_UINT16(gpr, smc91c111_state),
+        VMSTATE_UINT16(ptr, smc91c111_state),
+        VMSTATE_UINT16(ercv, smc91c111_state),
+        VMSTATE_INT32(bank, smc91c111_state),
+        VMSTATE_INT32(packet_num, smc91c111_state),
+        VMSTATE_INT32(tx_alloc, smc91c111_state),
+        VMSTATE_INT32(allocated, smc91c111_state),
+        VMSTATE_INT32(tx_fifo_len, smc91c111_state),
+        VMSTATE_INT32_ARRAY(tx_fifo, smc91c111_state, NUM_PACKETS),
+        VMSTATE_INT32(rx_fifo_len, smc91c111_state),
+        VMSTATE_INT32_ARRAY(rx_fifo, smc91c111_state, NUM_PACKETS),
+        VMSTATE_INT32(tx_fifo_done_len, smc91c111_state),
+        VMSTATE_INT32_ARRAY(tx_fifo_done, smc91c111_state, NUM_PACKETS),
+        VMSTATE_BUFFER_UNSAFE(data, smc91c111_state, 0, NUM_PACKETS * 2048),
+        VMSTATE_UINT8(int_level, smc91c111_state),
+        VMSTATE_UINT8(int_mask, smc91c111_state),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+#define RCR_SOFT_RST  0x8000
+#define RCR_STRIP_CRC 0x0200
+#define RCR_RXEN      0x0100
+
+#define TCR_EPH_LOOP  0x2000
+#define TCR_NOCRC     0x0100
+#define TCR_PAD_EN    0x0080
+#define TCR_FORCOL    0x0004
+#define TCR_LOOP      0x0002
+#define TCR_TXEN      0x0001
+
+#define INT_MD        0x80
+#define INT_ERCV      0x40
+#define INT_EPH       0x20
+#define INT_RX_OVRN   0x10
+#define INT_ALLOC     0x08
+#define INT_TX_EMPTY  0x04
+#define INT_TX        0x02
+#define INT_RCV       0x01
+
+#define CTR_AUTO_RELEASE  0x0800
+#define CTR_RELOAD        0x0002
+#define CTR_STORE         0x0001
+
+#define RS_ALGNERR      0x8000
+#define RS_BRODCAST     0x4000
+#define RS_BADCRC       0x2000
+#define RS_ODDFRAME     0x1000
+#define RS_TOOLONG      0x0800
+#define RS_TOOSHORT     0x0400
+#define RS_MULTICAST    0x0001
+
+/* Update interrupt status.  */
+static void smc91c111_update(smc91c111_state *s)
+{
+    int level;
+
+    if (s->tx_fifo_len == 0)
+        s->int_level |= INT_TX_EMPTY;
+    if (s->tx_fifo_done_len != 0)
+        s->int_level |= INT_TX;
+    level = (s->int_level & s->int_mask) != 0;
+    qemu_set_irq(s->irq, level);
+}
+
+/* Try to allocate a packet.  Returns 0x80 on failure.  */
+static int smc91c111_allocate_packet(smc91c111_state *s)
+{
+    int i;
+    if (s->allocated == (1 << NUM_PACKETS) - 1) {
+        return 0x80;
+    }
+
+    for (i = 0; i < NUM_PACKETS; i++) {
+        if ((s->allocated & (1 << i)) == 0)
+            break;
+    }
+    s->allocated |= 1 << i;
+    return i;
+}
+
+
+/* Process a pending TX allocate.  */
+static void smc91c111_tx_alloc(smc91c111_state *s)
+{
+    s->tx_alloc = smc91c111_allocate_packet(s);
+    if (s->tx_alloc == 0x80)
+        return;
+    s->int_level |= INT_ALLOC;
+    smc91c111_update(s);
+}
+
+/* Remove and item from the RX FIFO.  */
+static void smc91c111_pop_rx_fifo(smc91c111_state *s)
+{
+    int i;
+
+    s->rx_fifo_len--;
+    if (s->rx_fifo_len) {
+        for (i = 0; i < s->rx_fifo_len; i++)
+            s->rx_fifo[i] = s->rx_fifo[i + 1];
+        s->int_level |= INT_RCV;
+    } else {
+        s->int_level &= ~INT_RCV;
+    }
+    smc91c111_update(s);
+}
+
+/* Remove an item from the TX completion FIFO.  */
+static void smc91c111_pop_tx_fifo_done(smc91c111_state *s)
+{
+    int i;
+
+    if (s->tx_fifo_done_len == 0)
+        return;
+    s->tx_fifo_done_len--;
+    for (i = 0; i < s->tx_fifo_done_len; i++)
+        s->tx_fifo_done[i] = s->tx_fifo_done[i + 1];
+}
+
+/* Release the memory allocated to a packet.  */
+static void smc91c111_release_packet(smc91c111_state *s, int packet)
+{
+    s->allocated &= ~(1 << packet);
+    if (s->tx_alloc == 0x80)
+        smc91c111_tx_alloc(s);
+}
+
+/* Flush the TX FIFO.  */
+static void smc91c111_do_tx(smc91c111_state *s)
+{
+    int i;
+    int len;
+    int control;
+    int packetnum;
+    uint8_t *p;
+
+    if ((s->tcr & TCR_TXEN) == 0)
+        return;
+    if (s->tx_fifo_len == 0)
+        return;
+    for (i = 0; i < s->tx_fifo_len; i++) {
+        packetnum = s->tx_fifo[i];
+        p = &s->data[packetnum][0];
+        /* Set status word.  */
+        *(p++) = 0x01;
+        *(p++) = 0x40;
+        len = *(p++);
+        len |= ((int)*(p++)) << 8;
+        len -= 6;
+        control = p[len + 1];
+        if (control & 0x20)
+            len++;
+        /* ??? This overwrites the data following the buffer.
+           Don't know what real hardware does.  */
+        if (len < 64 && (s->tcr & TCR_PAD_EN)) {
+            memset(p + len, 0, 64 - len);
+            len = 64;
+        }
+#if 0
+        {
+            int add_crc;
+
+            /* The card is supposed to append the CRC to the frame.
+               However none of the other network traffic has the CRC
+               appended.  Suspect this is low level ethernet detail we
+               don't need to worry about.  */
+            add_crc = (control & 0x10) || (s->tcr & TCR_NOCRC) == 0;
+            if (add_crc) {
+                uint32_t crc;
+
+                crc = crc32(~0, p, len);
+                memcpy(p + len, &crc, 4);
+                len += 4;
+            }
+        }
+#endif
+        if (s->ctr & CTR_AUTO_RELEASE)
+            /* Race?  */
+            smc91c111_release_packet(s, packetnum);
+        else if (s->tx_fifo_done_len < NUM_PACKETS)
+            s->tx_fifo_done[s->tx_fifo_done_len++] = packetnum;
+        qemu_send_packet(qemu_get_queue(s->nic), p, len);
+    }
+    s->tx_fifo_len = 0;
+    smc91c111_update(s);
+}
+
+/* Add a packet to the TX FIFO.  */
+static void smc91c111_queue_tx(smc91c111_state *s, int packet)
+{
+    if (s->tx_fifo_len == NUM_PACKETS)
+        return;
+    s->tx_fifo[s->tx_fifo_len++] = packet;
+    smc91c111_do_tx(s);
+}
+
+static void smc91c111_reset(DeviceState *dev)
+{
+    smc91c111_state *s = FROM_SYSBUS(smc91c111_state, SYS_BUS_DEVICE(dev));
+    s->bank = 0;
+    s->tx_fifo_len = 0;
+    s->tx_fifo_done_len = 0;
+    s->rx_fifo_len = 0;
+    s->allocated = 0;
+    s->packet_num = 0;
+    s->tx_alloc = 0;
+    s->tcr = 0;
+    s->rcr = 0;
+    s->cr = 0xa0b1;
+    s->ctr = 0x1210;
+    s->ptr = 0;
+    s->ercv = 0x1f;
+    s->int_level = INT_TX_EMPTY;
+    s->int_mask = 0;
+    smc91c111_update(s);
+}
+
+#define SET_LOW(name, val) s->name = (s->name & 0xff00) | val
+#define SET_HIGH(name, val) s->name = (s->name & 0xff) | (val << 8)
+
+static void smc91c111_writeb(void *opaque, hwaddr offset,
+                             uint32_t value)
+{
+    smc91c111_state *s = (smc91c111_state *)opaque;
+
+    offset = offset & 0xf;
+    if (offset == 14) {
+        s->bank = value;
+        return;
+    }
+    if (offset == 15)
+        return;
+    switch (s->bank) {
+    case 0:
+        switch (offset) {
+        case 0: /* TCR */
+            SET_LOW(tcr, value);
+            return;
+        case 1:
+            SET_HIGH(tcr, value);
+            return;
+        case 4: /* RCR */
+            SET_LOW(rcr, value);
+            return;
+        case 5:
+            SET_HIGH(rcr, value);
+            if (s->rcr & RCR_SOFT_RST)
+                smc91c111_reset(&s->busdev.qdev);
+            return;
+        case 10: case 11: /* RPCR */
+            /* Ignored */
+            return;
+        case 12: case 13: /* Reserved */
+            return;
+        }
+        break;
+
+    case 1:
+        switch (offset) {
+        case 0: /* CONFIG */
+            SET_LOW(cr, value);
+            return;
+        case 1:
+            SET_HIGH(cr,value);
+            return;
+        case 2: case 3: /* BASE */
+        case 4: case 5: case 6: case 7: case 8: case 9: /* IA */
+            /* Not implemented.  */
+            return;
+        case 10: /* Genral Purpose */
+            SET_LOW(gpr, value);
+            return;
+        case 11:
+            SET_HIGH(gpr, value);
+            return;
+        case 12: /* Control */
+            if (value & 1)
+                fprintf(stderr, "smc91c111:EEPROM store not implemented\n");
+            if (value & 2)
+                fprintf(stderr, "smc91c111:EEPROM reload not implemented\n");
+            value &= ~3;
+            SET_LOW(ctr, value);
+            return;
+        case 13:
+            SET_HIGH(ctr, value);
+            return;
+        }
+        break;
+
+    case 2:
+        switch (offset) {
+        case 0: /* MMU Command */
+            switch (value >> 5) {
+            case 0: /* no-op */
+                break;
+            case 1: /* Allocate for TX.  */
+                s->tx_alloc = 0x80;
+                s->int_level &= ~INT_ALLOC;
+                smc91c111_update(s);
+                smc91c111_tx_alloc(s);
+                break;
+            case 2: /* Reset MMU.  */
+                s->allocated = 0;
+                s->tx_fifo_len = 0;
+                s->tx_fifo_done_len = 0;
+                s->rx_fifo_len = 0;
+                s->tx_alloc = 0;
+                break;
+            case 3: /* Remove from RX FIFO.  */
+                smc91c111_pop_rx_fifo(s);
+                break;
+            case 4: /* Remove from RX FIFO and release.  */
+                if (s->rx_fifo_len > 0) {
+                    smc91c111_release_packet(s, s->rx_fifo[0]);
+                }
+                smc91c111_pop_rx_fifo(s);
+                break;
+            case 5: /* Release.  */
+                smc91c111_release_packet(s, s->packet_num);
+                break;
+            case 6: /* Add to TX FIFO.  */
+                smc91c111_queue_tx(s, s->packet_num);
+                break;
+            case 7: /* Reset TX FIFO.  */
+                s->tx_fifo_len = 0;
+                s->tx_fifo_done_len = 0;
+                break;
+            }
+            return;
+        case 1:
+            /* Ignore.  */
+            return;
+        case 2: /* Packet Number Register */
+            s->packet_num = value;
+            return;
+        case 3: case 4: case 5:
+            /* Should be readonly, but linux writes to them anyway. Ignore.  */
+            return;
+        case 6: /* Pointer */
+            SET_LOW(ptr, value);
+            return;
+        case 7:
+            SET_HIGH(ptr, value);
+            return;
+        case 8: case 9: case 10: case 11: /* Data */
+            {
+                int p;
+                int n;
+
+                if (s->ptr & 0x8000)
+                    n = s->rx_fifo[0];
+                else
+                    n = s->packet_num;
+                p = s->ptr & 0x07ff;
+                if (s->ptr & 0x4000) {
+                    s->ptr = (s->ptr & 0xf800) | ((s->ptr + 1) & 0x7ff);
+                } else {
+                    p += (offset & 3);
+                }
+                s->data[n][p] = value;
+            }
+            return;
+        case 12: /* Interrupt ACK.  */
+            s->int_level &= ~(value & 0xd6);
+            if (value & INT_TX)
+                smc91c111_pop_tx_fifo_done(s);
+            smc91c111_update(s);
+            return;
+        case 13: /* Interrupt mask.  */
+            s->int_mask = value;
+            smc91c111_update(s);
+            return;
+        }
+        break;
+
+    case 3:
+        switch (offset) {
+        case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
+            /* Multicast table.  */
+            /* Not implemented.  */
+            return;
+        case 8: case 9: /* Management Interface.  */
+            /* Not implemented.  */
+            return;
+        case 12: /* Early receive.  */
+            s->ercv = value & 0x1f;
+            return;
+        case 13:
+            /* Ignore.  */
+            return;
+        }
+        break;
+    }
+    hw_error("smc91c111_write: Bad reg %d:%x\n", s->bank, (int)offset);
+}
+
+static uint32_t smc91c111_readb(void *opaque, hwaddr offset)
+{
+    smc91c111_state *s = (smc91c111_state *)opaque;
+
+    offset = offset & 0xf;
+    if (offset == 14) {
+        return s->bank;
+    }
+    if (offset == 15)
+        return 0x33;
+    switch (s->bank) {
+    case 0:
+        switch (offset) {
+        case 0: /* TCR */
+            return s->tcr & 0xff;
+        case 1:
+            return s->tcr >> 8;
+        case 2: /* EPH Status */
+            return 0;
+        case 3:
+            return 0x40;
+        case 4: /* RCR */
+            return s->rcr & 0xff;
+        case 5:
+            return s->rcr >> 8;
+        case 6: /* Counter */
+        case 7:
+            /* Not implemented.  */
+            return 0;
+        case 8: /* Memory size.  */
+            return NUM_PACKETS;
+        case 9: /* Free memory available.  */
+            {
+                int i;
+                int n;
+                n = 0;
+                for (i = 0; i < NUM_PACKETS; i++) {
+                    if (s->allocated & (1 << i))
+                        n++;
+                }
+                return n;
+            }
+        case 10: case 11: /* RPCR */
+            /* Not implemented.  */
+            return 0;
+        case 12: case 13: /* Reserved */
+            return 0;
+        }
+        break;
+
+    case 1:
+        switch (offset) {
+        case 0: /* CONFIG */
+            return s->cr & 0xff;
+        case 1:
+            return s->cr >> 8;
+        case 2: case 3: /* BASE */
+            /* Not implemented.  */
+            return 0;
+        case 4: case 5: case 6: case 7: case 8: case 9: /* IA */
+            return s->conf.macaddr.a[offset - 4];
+        case 10: /* General Purpose */
+            return s->gpr & 0xff;
+        case 11:
+            return s->gpr >> 8;
+        case 12: /* Control */
+            return s->ctr & 0xff;
+        case 13:
+            return s->ctr >> 8;
+        }
+        break;
+
+    case 2:
+        switch (offset) {
+        case 0: case 1: /* MMUCR Busy bit.  */
+            return 0;
+        case 2: /* Packet Number.  */
+            return s->packet_num;
+        case 3: /* Allocation Result.  */
+            return s->tx_alloc;
+        case 4: /* TX FIFO */
+            if (s->tx_fifo_done_len == 0)
+                return 0x80;
+            else
+                return s->tx_fifo_done[0];
+        case 5: /* RX FIFO */
+            if (s->rx_fifo_len == 0)
+                return 0x80;
+            else
+                return s->rx_fifo[0];
+        case 6: /* Pointer */
+            return s->ptr & 0xff;
+        case 7:
+            return (s->ptr >> 8) & 0xf7;
+        case 8: case 9: case 10: case 11: /* Data */
+            {
+                int p;
+                int n;
+
+                if (s->ptr & 0x8000)
+                    n = s->rx_fifo[0];
+                else
+                    n = s->packet_num;
+                p = s->ptr & 0x07ff;
+                if (s->ptr & 0x4000) {
+                    s->ptr = (s->ptr & 0xf800) | ((s->ptr + 1) & 0x07ff);
+                } else {
+                    p += (offset & 3);
+                }
+                return s->data[n][p];
+            }
+        case 12: /* Interrupt status.  */
+            return s->int_level;
+        case 13: /* Interrupt mask.  */
+            return s->int_mask;
+        }
+        break;
+
+    case 3:
+        switch (offset) {
+        case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
+            /* Multicast table.  */
+            /* Not implemented.  */
+            return 0;
+        case 8: /* Management Interface.  */
+            /* Not implemented.  */
+            return 0x30;
+        case 9:
+            return 0x33;
+        case 10: /* Revision.  */
+            return 0x91;
+        case 11:
+            return 0x33;
+        case 12:
+            return s->ercv;
+        case 13:
+            return 0;
+        }
+        break;
+    }
+    hw_error("smc91c111_read: Bad reg %d:%x\n", s->bank, (int)offset);
+    return 0;
+}
+
+static void smc91c111_writew(void *opaque, hwaddr offset,
+                             uint32_t value)
+{
+    smc91c111_writeb(opaque, offset, value & 0xff);
+    smc91c111_writeb(opaque, offset + 1, value >> 8);
+}
+
+static void smc91c111_writel(void *opaque, hwaddr offset,
+                             uint32_t value)
+{
+    /* 32-bit writes to offset 0xc only actually write to the bank select
+       register (offset 0xe)  */
+    if (offset != 0xc)
+        smc91c111_writew(opaque, offset, value & 0xffff);
+    smc91c111_writew(opaque, offset + 2, value >> 16);
+}
+
+static uint32_t smc91c111_readw(void *opaque, hwaddr offset)
+{
+    uint32_t val;
+    val = smc91c111_readb(opaque, offset);
+    val |= smc91c111_readb(opaque, offset + 1) << 8;
+    return val;
+}
+
+static uint32_t smc91c111_readl(void *opaque, hwaddr offset)
+{
+    uint32_t val;
+    val = smc91c111_readw(opaque, offset);
+    val |= smc91c111_readw(opaque, offset + 2) << 16;
+    return val;
+}
+
+static int smc91c111_can_receive(NetClientState *nc)
+{
+    smc91c111_state *s = qemu_get_nic_opaque(nc);
+
+    if ((s->rcr & RCR_RXEN) == 0 || (s->rcr & RCR_SOFT_RST))
+        return 1;
+    if (s->allocated == (1 << NUM_PACKETS) - 1)
+        return 0;
+    return 1;
+}
+
+static ssize_t smc91c111_receive(NetClientState *nc, const uint8_t *buf, size_t size)
+{
+    smc91c111_state *s = qemu_get_nic_opaque(nc);
+    int status;
+    int packetsize;
+    uint32_t crc;
+    int packetnum;
+    uint8_t *p;
+
+    if ((s->rcr & RCR_RXEN) == 0 || (s->rcr & RCR_SOFT_RST))
+        return -1;
+    /* Short packets are padded with zeros.  Receiving a packet
+       < 64 bytes long is considered an error condition.  */
+    if (size < 64)
+        packetsize = 64;
+    else
+        packetsize = (size & ~1);
+    packetsize += 6;
+    crc = (s->rcr & RCR_STRIP_CRC) == 0;
+    if (crc)
+        packetsize += 4;
+    /* TODO: Flag overrun and receive errors.  */
+    if (packetsize > 2048)
+        return -1;
+    packetnum = smc91c111_allocate_packet(s);
+    if (packetnum == 0x80)
+        return -1;
+    s->rx_fifo[s->rx_fifo_len++] = packetnum;
+
+    p = &s->data[packetnum][0];
+    /* ??? Multicast packets?  */
+    status = 0;
+    if (size > 1518)
+        status |= RS_TOOLONG;
+    if (size & 1)
+        status |= RS_ODDFRAME;
+    *(p++) = status & 0xff;
+    *(p++) = status >> 8;
+    *(p++) = packetsize & 0xff;
+    *(p++) = packetsize >> 8;
+    memcpy(p, buf, size & ~1);
+    p += (size & ~1);
+    /* Pad short packets.  */
+    if (size < 64) {
+        int pad;
+
+        if (size & 1)
+            *(p++) = buf[size - 1];
+        pad = 64 - size;
+        memset(p, 0, pad);
+        p += pad;
+        size = 64;
+    }
+    /* It's not clear if the CRC should go before or after the last byte in
+       odd sized packets.  Linux disables the CRC, so that's no help.
+       The pictures in the documentation show the CRC aligned on a 16-bit
+       boundary before the last odd byte, so that's what we do.  */
+    if (crc) {
+        crc = crc32(~0, buf, size);
+        *(p++) = crc & 0xff; crc >>= 8;
+        *(p++) = crc & 0xff; crc >>= 8;
+        *(p++) = crc & 0xff; crc >>= 8;
+        *(p++) = crc & 0xff;
+    }
+    if (size & 1) {
+        *(p++) = buf[size - 1];
+        *p = 0x60;
+    } else {
+        *(p++) = 0;
+        *p = 0x40;
+    }
+    /* TODO: Raise early RX interrupt?  */
+    s->int_level |= INT_RCV;
+    smc91c111_update(s);
+
+    return size;
+}
+
+static const MemoryRegionOps smc91c111_mem_ops = {
+    /* The special case for 32 bit writes to 0xc means we can't just
+     * set .impl.min/max_access_size to 1, unfortunately
+     */
+    .old_mmio = {
+        .read = { smc91c111_readb, smc91c111_readw, smc91c111_readl, },
+        .write = { smc91c111_writeb, smc91c111_writew, smc91c111_writel, },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void smc91c111_cleanup(NetClientState *nc)
+{
+    smc91c111_state *s = qemu_get_nic_opaque(nc);
+
+    s->nic = NULL;
+}
+
+static NetClientInfo net_smc91c111_info = {
+    .type = NET_CLIENT_OPTIONS_KIND_NIC,
+    .size = sizeof(NICState),
+    .can_receive = smc91c111_can_receive,
+    .receive = smc91c111_receive,
+    .cleanup = smc91c111_cleanup,
+};
+
+static int smc91c111_init1(SysBusDevice *dev)
+{
+    smc91c111_state *s = FROM_SYSBUS(smc91c111_state, dev);
+    memory_region_init_io(&s->mmio, &smc91c111_mem_ops, s,
+                          "smc91c111-mmio", 16);
+    sysbus_init_mmio(dev, &s->mmio);
+    sysbus_init_irq(dev, &s->irq);
+    qemu_macaddr_default_if_unset(&s->conf.macaddr);
+    s->nic = qemu_new_nic(&net_smc91c111_info, &s->conf,
+                          object_get_typename(OBJECT(dev)), dev->qdev.id, s);
+    qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
+    /* ??? Save/restore.  */
+    return 0;
+}
+
+static Property smc91c111_properties[] = {
+    DEFINE_NIC_PROPERTIES(smc91c111_state, conf),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void smc91c111_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = smc91c111_init1;
+    dc->reset = smc91c111_reset;
+    dc->vmsd = &vmstate_smc91c111;
+    dc->props = smc91c111_properties;
+}
+
+static const TypeInfo smc91c111_info = {
+    .name          = "smc91c111",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(smc91c111_state),
+    .class_init    = smc91c111_class_init,
+};
+
+static void smc91c111_register_types(void)
+{
+    type_register_static(&smc91c111_info);
+}
+
+/* Legacy helper function.  Should go away when machine config files are
+   implemented.  */
+void smc91c111_init(NICInfo *nd, uint32_t base, qemu_irq irq)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+
+    qemu_check_nic_model(nd, "smc91c111");
+    dev = qdev_create(NULL, "smc91c111");
+    qdev_set_nic_properties(dev, nd);
+    qdev_init_nofail(dev);
+    s = SYS_BUS_DEVICE(dev);
+    sysbus_mmio_map(s, 0, base);
+    sysbus_connect_irq(s, 0, irq);
+}
+
+type_init(smc91c111_register_types)
diff --git a/hw/net/spapr_llan.c b/hw/net/spapr_llan.c
new file mode 100644 (file)
index 0000000..34332f2
--- /dev/null
@@ -0,0 +1,531 @@
+/*
+ * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator
+ *
+ * PAPR Inter-VM Logical Lan, aka ibmveth
+ *
+ * Copyright (c) 2010,2011 David Gibson, IBM Corporation.
+ *
+ * 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 "hw/hw.h"
+#include "net/net.h"
+#include "hw/qdev.h"
+#include "hw/ppc/spapr.h"
+#include "hw/ppc/spapr_vio.h"
+
+#include <libfdt.h>
+
+#define ETH_ALEN        6
+#define MAX_PACKET_SIZE 65536
+
+/*#define DEBUG*/
+
+#ifdef DEBUG
+#define dprintf(fmt...) do { fprintf(stderr, fmt); } while (0)
+#else
+#define dprintf(fmt...)
+#endif
+
+/*
+ * Virtual LAN device
+ */
+
+typedef uint64_t vlan_bd_t;
+
+#define VLAN_BD_VALID        0x8000000000000000ULL
+#define VLAN_BD_TOGGLE       0x4000000000000000ULL
+#define VLAN_BD_NO_CSUM      0x0200000000000000ULL
+#define VLAN_BD_CSUM_GOOD    0x0100000000000000ULL
+#define VLAN_BD_LEN_MASK     0x00ffffff00000000ULL
+#define VLAN_BD_LEN(bd)      (((bd) & VLAN_BD_LEN_MASK) >> 32)
+#define VLAN_BD_ADDR_MASK    0x00000000ffffffffULL
+#define VLAN_BD_ADDR(bd)     ((bd) & VLAN_BD_ADDR_MASK)
+
+#define VLAN_VALID_BD(addr, len) (VLAN_BD_VALID | \
+                                  (((len) << 32) & VLAN_BD_LEN_MASK) |  \
+                                  (addr & VLAN_BD_ADDR_MASK))
+
+#define VLAN_RXQC_TOGGLE     0x80
+#define VLAN_RXQC_VALID      0x40
+#define VLAN_RXQC_NO_CSUM    0x02
+#define VLAN_RXQC_CSUM_GOOD  0x01
+
+#define VLAN_RQ_ALIGNMENT    16
+#define VLAN_RXQ_BD_OFF      0
+#define VLAN_FILTER_BD_OFF   8
+#define VLAN_RX_BDS_OFF      16
+#define VLAN_MAX_BUFS        ((SPAPR_TCE_PAGE_SIZE - VLAN_RX_BDS_OFF) / 8)
+
+typedef struct VIOsPAPRVLANDevice {
+    VIOsPAPRDevice sdev;
+    NICConf nicconf;
+    NICState *nic;
+    int isopen;
+    target_ulong buf_list;
+    int add_buf_ptr, use_buf_ptr, rx_bufs;
+    target_ulong rxq_ptr;
+} VIOsPAPRVLANDevice;
+
+static int spapr_vlan_can_receive(NetClientState *nc)
+{
+    VIOsPAPRVLANDevice *dev = qemu_get_nic_opaque(nc);
+
+    return (dev->isopen && dev->rx_bufs > 0);
+}
+
+static ssize_t spapr_vlan_receive(NetClientState *nc, const uint8_t *buf,
+                                  size_t size)
+{
+    VIOsPAPRDevice *sdev = qemu_get_nic_opaque(nc);
+    VIOsPAPRVLANDevice *dev = (VIOsPAPRVLANDevice *)sdev;
+    vlan_bd_t rxq_bd = vio_ldq(sdev, dev->buf_list + VLAN_RXQ_BD_OFF);
+    vlan_bd_t bd;
+    int buf_ptr = dev->use_buf_ptr;
+    uint64_t handle;
+    uint8_t control;
+
+    dprintf("spapr_vlan_receive() [%s] rx_bufs=%d\n", sdev->qdev.id,
+            dev->rx_bufs);
+
+    if (!dev->isopen) {
+        return -1;
+    }
+
+    if (!dev->rx_bufs) {
+        return -1;
+    }
+
+    do {
+        buf_ptr += 8;
+        if (buf_ptr >= SPAPR_TCE_PAGE_SIZE) {
+            buf_ptr = VLAN_RX_BDS_OFF;
+        }
+
+        bd = vio_ldq(sdev, dev->buf_list + buf_ptr);
+        dprintf("use_buf_ptr=%d bd=0x%016llx\n",
+                buf_ptr, (unsigned long long)bd);
+    } while ((!(bd & VLAN_BD_VALID) || (VLAN_BD_LEN(bd) < (size + 8)))
+             && (buf_ptr != dev->use_buf_ptr));
+
+    if (!(bd & VLAN_BD_VALID) || (VLAN_BD_LEN(bd) < (size + 8))) {
+        /* Failed to find a suitable buffer */
+        return -1;
+    }
+
+    /* Remove the buffer from the pool */
+    dev->rx_bufs--;
+    dev->use_buf_ptr = buf_ptr;
+    vio_stq(sdev, dev->buf_list + dev->use_buf_ptr, 0);
+
+    dprintf("Found buffer: ptr=%d num=%d\n", dev->use_buf_ptr, dev->rx_bufs);
+
+    /* Transfer the packet data */
+    if (spapr_vio_dma_write(sdev, VLAN_BD_ADDR(bd) + 8, buf, size) < 0) {
+        return -1;
+    }
+
+    dprintf("spapr_vlan_receive: DMA write completed\n");
+
+    /* Update the receive queue */
+    control = VLAN_RXQC_TOGGLE | VLAN_RXQC_VALID;
+    if (rxq_bd & VLAN_BD_TOGGLE) {
+        control ^= VLAN_RXQC_TOGGLE;
+    }
+
+    handle = vio_ldq(sdev, VLAN_BD_ADDR(bd));
+    vio_stq(sdev, VLAN_BD_ADDR(rxq_bd) + dev->rxq_ptr + 8, handle);
+    vio_stl(sdev, VLAN_BD_ADDR(rxq_bd) + dev->rxq_ptr + 4, size);
+    vio_sth(sdev, VLAN_BD_ADDR(rxq_bd) + dev->rxq_ptr + 2, 8);
+    vio_stb(sdev, VLAN_BD_ADDR(rxq_bd) + dev->rxq_ptr, control);
+
+    dprintf("wrote rxq entry (ptr=0x%llx): 0x%016llx 0x%016llx\n",
+            (unsigned long long)dev->rxq_ptr,
+            (unsigned long long)vio_ldq(sdev, VLAN_BD_ADDR(rxq_bd) +
+                                        dev->rxq_ptr),
+            (unsigned long long)vio_ldq(sdev, VLAN_BD_ADDR(rxq_bd) +
+                                        dev->rxq_ptr + 8));
+
+    dev->rxq_ptr += 16;
+    if (dev->rxq_ptr >= VLAN_BD_LEN(rxq_bd)) {
+        dev->rxq_ptr = 0;
+        vio_stq(sdev, dev->buf_list + VLAN_RXQ_BD_OFF, rxq_bd ^ VLAN_BD_TOGGLE);
+    }
+
+    if (sdev->signal_state & 1) {
+        qemu_irq_pulse(spapr_vio_qirq(sdev));
+    }
+
+    return size;
+}
+
+static void spapr_vlan_cleanup(NetClientState *nc)
+{
+    VIOsPAPRVLANDevice *dev = qemu_get_nic_opaque(nc);
+
+    dev->nic = NULL;
+}
+
+static NetClientInfo net_spapr_vlan_info = {
+    .type = NET_CLIENT_OPTIONS_KIND_NIC,
+    .size = sizeof(NICState),
+    .can_receive = spapr_vlan_can_receive,
+    .receive = spapr_vlan_receive,
+    .cleanup = spapr_vlan_cleanup,
+};
+
+static void spapr_vlan_reset(VIOsPAPRDevice *sdev)
+{
+    VIOsPAPRVLANDevice *dev = DO_UPCAST(VIOsPAPRVLANDevice, sdev, sdev);
+
+    dev->buf_list = 0;
+    dev->rx_bufs = 0;
+    dev->isopen = 0;
+}
+
+static int spapr_vlan_init(VIOsPAPRDevice *sdev)
+{
+    VIOsPAPRVLANDevice *dev = (VIOsPAPRVLANDevice *)sdev;
+
+    qemu_macaddr_default_if_unset(&dev->nicconf.macaddr);
+
+    dev->nic = qemu_new_nic(&net_spapr_vlan_info, &dev->nicconf,
+                            object_get_typename(OBJECT(sdev)), sdev->qdev.id, dev);
+    qemu_format_nic_info_str(qemu_get_queue(dev->nic), dev->nicconf.macaddr.a);
+
+    return 0;
+}
+
+void spapr_vlan_create(VIOsPAPRBus *bus, NICInfo *nd)
+{
+    DeviceState *dev;
+
+    dev = qdev_create(&bus->bus, "spapr-vlan");
+
+    qdev_set_nic_properties(dev, nd);
+
+    qdev_init_nofail(dev);
+}
+
+static int spapr_vlan_devnode(VIOsPAPRDevice *dev, void *fdt, int node_off)
+{
+    VIOsPAPRVLANDevice *vdev = (VIOsPAPRVLANDevice *)dev;
+    uint8_t padded_mac[8] = {0, 0};
+    int ret;
+
+    /* Some old phyp versions give the mac address in an 8-byte
+     * property.  The kernel driver has an insane workaround for this;
+     * rather than doing the obvious thing and checking the property
+     * length, it checks whether the first byte has 0b10 in the low
+     * bits.  If a correct 6-byte property has a different first byte
+     * the kernel will get the wrong mac address, overrunning its
+     * buffer in the process (read only, thank goodness).
+     *
+     * Here we workaround the kernel workaround by always supplying an
+     * 8-byte property, with the mac address in the last six bytes */
+    memcpy(&padded_mac[2], &vdev->nicconf.macaddr, ETH_ALEN);
+    ret = fdt_setprop(fdt, node_off, "local-mac-address",
+                      padded_mac, sizeof(padded_mac));
+    if (ret < 0) {
+        return ret;
+    }
+
+    ret = fdt_setprop_cell(fdt, node_off, "ibm,mac-address-filters", 0);
+    if (ret < 0) {
+        return ret;
+    }
+
+    return 0;
+}
+
+static int check_bd(VIOsPAPRVLANDevice *dev, vlan_bd_t bd,
+                    target_ulong alignment)
+{
+    if ((VLAN_BD_ADDR(bd) % alignment)
+        || (VLAN_BD_LEN(bd) % alignment)) {
+        return -1;
+    }
+
+    if (!spapr_vio_dma_valid(&dev->sdev, VLAN_BD_ADDR(bd),
+                             VLAN_BD_LEN(bd), DMA_DIRECTION_FROM_DEVICE)
+        || !spapr_vio_dma_valid(&dev->sdev, VLAN_BD_ADDR(bd),
+                                VLAN_BD_LEN(bd), DMA_DIRECTION_TO_DEVICE)) {
+        return -1;
+    }
+
+    return 0;
+}
+
+static target_ulong h_register_logical_lan(PowerPCCPU *cpu,
+                                           sPAPREnvironment *spapr,
+                                           target_ulong opcode,
+                                           target_ulong *args)
+{
+    target_ulong reg = args[0];
+    target_ulong buf_list = args[1];
+    target_ulong rec_queue = args[2];
+    target_ulong filter_list = args[3];
+    VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
+    VIOsPAPRVLANDevice *dev = (VIOsPAPRVLANDevice *)sdev;
+    vlan_bd_t filter_list_bd;
+
+    if (!dev) {
+        return H_PARAMETER;
+    }
+
+    if (dev->isopen) {
+        hcall_dprintf("H_REGISTER_LOGICAL_LAN called twice without "
+                      "H_FREE_LOGICAL_LAN\n");
+        return H_RESOURCE;
+    }
+
+    if (check_bd(dev, VLAN_VALID_BD(buf_list, SPAPR_TCE_PAGE_SIZE),
+                 SPAPR_TCE_PAGE_SIZE) < 0) {
+        hcall_dprintf("Bad buf_list 0x" TARGET_FMT_lx "\n", buf_list);
+        return H_PARAMETER;
+    }
+
+    filter_list_bd = VLAN_VALID_BD(filter_list, SPAPR_TCE_PAGE_SIZE);
+    if (check_bd(dev, filter_list_bd, SPAPR_TCE_PAGE_SIZE) < 0) {
+        hcall_dprintf("Bad filter_list 0x" TARGET_FMT_lx "\n", filter_list);
+        return H_PARAMETER;
+    }
+
+    if (!(rec_queue & VLAN_BD_VALID)
+        || (check_bd(dev, rec_queue, VLAN_RQ_ALIGNMENT) < 0)) {
+        hcall_dprintf("Bad receive queue\n");
+        return H_PARAMETER;
+    }
+
+    dev->buf_list = buf_list;
+    sdev->signal_state = 0;
+
+    rec_queue &= ~VLAN_BD_TOGGLE;
+
+    /* Initialize the buffer list */
+    vio_stq(sdev, buf_list, rec_queue);
+    vio_stq(sdev, buf_list + 8, filter_list_bd);
+    spapr_vio_dma_set(sdev, buf_list + VLAN_RX_BDS_OFF, 0,
+                      SPAPR_TCE_PAGE_SIZE - VLAN_RX_BDS_OFF);
+    dev->add_buf_ptr = VLAN_RX_BDS_OFF - 8;
+    dev->use_buf_ptr = VLAN_RX_BDS_OFF - 8;
+    dev->rx_bufs = 0;
+    dev->rxq_ptr = 0;
+
+    /* Initialize the receive queue */
+    spapr_vio_dma_set(sdev, VLAN_BD_ADDR(rec_queue), 0, VLAN_BD_LEN(rec_queue));
+
+    dev->isopen = 1;
+    return H_SUCCESS;
+}
+
+
+static target_ulong h_free_logical_lan(PowerPCCPU *cpu, sPAPREnvironment *spapr,
+                                       target_ulong opcode, target_ulong *args)
+{
+    target_ulong reg = args[0];
+    VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
+    VIOsPAPRVLANDevice *dev = (VIOsPAPRVLANDevice *)sdev;
+
+    if (!dev) {
+        return H_PARAMETER;
+    }
+
+    if (!dev->isopen) {
+        hcall_dprintf("H_FREE_LOGICAL_LAN called without "
+                      "H_REGISTER_LOGICAL_LAN\n");
+        return H_RESOURCE;
+    }
+
+    spapr_vlan_reset(sdev);
+    return H_SUCCESS;
+}
+
+static target_ulong h_add_logical_lan_buffer(PowerPCCPU *cpu,
+                                             sPAPREnvironment *spapr,
+                                             target_ulong opcode,
+                                             target_ulong *args)
+{
+    target_ulong reg = args[0];
+    target_ulong buf = args[1];
+    VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
+    VIOsPAPRVLANDevice *dev = (VIOsPAPRVLANDevice *)sdev;
+    vlan_bd_t bd;
+
+    dprintf("H_ADD_LOGICAL_LAN_BUFFER(0x" TARGET_FMT_lx
+            ", 0x" TARGET_FMT_lx ")\n", reg, buf);
+
+    if (!sdev) {
+        hcall_dprintf("Bad device\n");
+        return H_PARAMETER;
+    }
+
+    if ((check_bd(dev, buf, 4) < 0)
+        || (VLAN_BD_LEN(buf) < 16)) {
+        hcall_dprintf("Bad buffer enqueued\n");
+        return H_PARAMETER;
+    }
+
+    if (!dev->isopen || dev->rx_bufs >= VLAN_MAX_BUFS) {
+        return H_RESOURCE;
+    }
+
+    do {
+        dev->add_buf_ptr += 8;
+        if (dev->add_buf_ptr >= SPAPR_TCE_PAGE_SIZE) {
+            dev->add_buf_ptr = VLAN_RX_BDS_OFF;
+        }
+
+        bd = vio_ldq(sdev, dev->buf_list + dev->add_buf_ptr);
+    } while (bd & VLAN_BD_VALID);
+
+    vio_stq(sdev, dev->buf_list + dev->add_buf_ptr, buf);
+
+    dev->rx_bufs++;
+
+    dprintf("h_add_logical_lan_buffer():  Added buf  ptr=%d  rx_bufs=%d"
+            " bd=0x%016llx\n", dev->add_buf_ptr, dev->rx_bufs,
+            (unsigned long long)buf);
+
+    return H_SUCCESS;
+}
+
+static target_ulong h_send_logical_lan(PowerPCCPU *cpu, sPAPREnvironment *spapr,
+                                       target_ulong opcode, target_ulong *args)
+{
+    target_ulong reg = args[0];
+    target_ulong *bufs = args + 1;
+    target_ulong continue_token = args[7];
+    VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
+    VIOsPAPRVLANDevice *dev = (VIOsPAPRVLANDevice *)sdev;
+    unsigned total_len;
+    uint8_t *lbuf, *p;
+    int i, nbufs;
+    int ret;
+
+    dprintf("H_SEND_LOGICAL_LAN(0x" TARGET_FMT_lx ", <bufs>, 0x"
+            TARGET_FMT_lx ")\n", reg, continue_token);
+
+    if (!sdev) {
+        return H_PARAMETER;
+    }
+
+    dprintf("rxbufs = %d\n", dev->rx_bufs);
+
+    if (!dev->isopen) {
+        return H_DROPPED;
+    }
+
+    if (continue_token) {
+        return H_HARDWARE; /* FIXME actually handle this */
+    }
+
+    total_len = 0;
+    for (i = 0; i < 6; i++) {
+        dprintf("   buf desc: 0x" TARGET_FMT_lx "\n", bufs[i]);
+        if (!(bufs[i] & VLAN_BD_VALID)) {
+            break;
+        }
+        total_len += VLAN_BD_LEN(bufs[i]);
+    }
+
+    nbufs = i;
+    dprintf("h_send_logical_lan() %d buffers, total length 0x%x\n",
+            nbufs, total_len);
+
+    if (total_len == 0) {
+        return H_SUCCESS;
+    }
+
+    if (total_len > MAX_PACKET_SIZE) {
+        /* Don't let the guest force too large an allocation */
+        return H_RESOURCE;
+    }
+
+    lbuf = alloca(total_len);
+    p = lbuf;
+    for (i = 0; i < nbufs; i++) {
+        ret = spapr_vio_dma_read(sdev, VLAN_BD_ADDR(bufs[i]),
+                                 p, VLAN_BD_LEN(bufs[i]));
+        if (ret < 0) {
+            return ret;
+        }
+
+        p += VLAN_BD_LEN(bufs[i]);
+    }
+
+    qemu_send_packet(qemu_get_queue(dev->nic), lbuf, total_len);
+
+    return H_SUCCESS;
+}
+
+static target_ulong h_multicast_ctrl(PowerPCCPU *cpu, sPAPREnvironment *spapr,
+                                     target_ulong opcode, target_ulong *args)
+{
+    target_ulong reg = args[0];
+    VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
+
+    if (!dev) {
+        return H_PARAMETER;
+    }
+
+    return H_SUCCESS;
+}
+
+static Property spapr_vlan_properties[] = {
+    DEFINE_SPAPR_PROPERTIES(VIOsPAPRVLANDevice, sdev),
+    DEFINE_NIC_PROPERTIES(VIOsPAPRVLANDevice, nicconf),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void spapr_vlan_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    VIOsPAPRDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass);
+
+    k->init = spapr_vlan_init;
+    k->reset = spapr_vlan_reset;
+    k->devnode = spapr_vlan_devnode;
+    k->dt_name = "l-lan";
+    k->dt_type = "network";
+    k->dt_compatible = "IBM,l-lan";
+    k->signal_mask = 0x1;
+    dc->props = spapr_vlan_properties;
+    k->rtce_window_size = 0x10000000;
+}
+
+static const 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_types(void)
+{
+    spapr_register_hypercall(H_REGISTER_LOGICAL_LAN, h_register_logical_lan);
+    spapr_register_hypercall(H_FREE_LOGICAL_LAN, h_free_logical_lan);
+    spapr_register_hypercall(H_SEND_LOGICAL_LAN, h_send_logical_lan);
+    spapr_register_hypercall(H_ADD_LOGICAL_LAN_BUFFER,
+                             h_add_logical_lan_buffer);
+    spapr_register_hypercall(H_MULTICAST_CTRL, h_multicast_ctrl);
+    type_register_static(&spapr_vlan_info);
+}
+
+type_init(spapr_vlan_register_types)
diff --git a/hw/net/stellaris_enet.c b/hw/net/stellaris_enet.c
new file mode 100644 (file)
index 0000000..59b8456
--- /dev/null
@@ -0,0 +1,450 @@
+/*
+ * Luminary Micro Stellaris Ethernet Controller
+ *
+ * Copyright (c) 2007 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the GPL.
+ */
+#include "hw/sysbus.h"
+#include "net/net.h"
+#include <zlib.h>
+
+//#define DEBUG_STELLARIS_ENET 1
+
+#ifdef DEBUG_STELLARIS_ENET
+#define DPRINTF(fmt, ...) \
+do { printf("stellaris_enet: " fmt , ## __VA_ARGS__); } while (0)
+#define BADF(fmt, ...) \
+do { fprintf(stderr, "stellaris_enet: error: " fmt , ## __VA_ARGS__); exit(1);} while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while(0)
+#define BADF(fmt, ...) \
+do { fprintf(stderr, "stellaris_enet: error: " fmt , ## __VA_ARGS__);} while (0)
+#endif
+
+#define SE_INT_RX       0x01
+#define SE_INT_TXER     0x02
+#define SE_INT_TXEMP    0x04
+#define SE_INT_FOV      0x08
+#define SE_INT_RXER     0x10
+#define SE_INT_MD       0x20
+#define SE_INT_PHY      0x40
+
+#define SE_RCTL_RXEN    0x01
+#define SE_RCTL_AMUL    0x02
+#define SE_RCTL_PRMS    0x04
+#define SE_RCTL_BADCRC  0x08
+#define SE_RCTL_RSTFIFO 0x10
+
+#define SE_TCTL_TXEN    0x01
+#define SE_TCTL_PADEN   0x02
+#define SE_TCTL_CRC     0x04
+#define SE_TCTL_DUPLEX  0x08
+
+typedef struct {
+    SysBusDevice busdev;
+    uint32_t ris;
+    uint32_t im;
+    uint32_t rctl;
+    uint32_t tctl;
+    uint32_t thr;
+    uint32_t mctl;
+    uint32_t mdv;
+    uint32_t mtxd;
+    uint32_t mrxd;
+    uint32_t np;
+    int tx_frame_len;
+    int tx_fifo_len;
+    uint8_t tx_fifo[2048];
+    /* Real hardware has a 2k fifo, which works out to be at most 31 packets.
+       We implement a full 31 packet fifo.  */
+    struct {
+        uint8_t data[2048];
+        int len;
+    } rx[31];
+    uint8_t *rx_fifo;
+    int rx_fifo_len;
+    int next_packet;
+    NICState *nic;
+    NICConf conf;
+    qemu_irq irq;
+    MemoryRegion mmio;
+} stellaris_enet_state;
+
+static void stellaris_enet_update(stellaris_enet_state *s)
+{
+    qemu_set_irq(s->irq, (s->ris & s->im) != 0);
+}
+
+/* TODO: Implement MAC address filtering.  */
+static ssize_t stellaris_enet_receive(NetClientState *nc, const uint8_t *buf, size_t size)
+{
+    stellaris_enet_state *s = qemu_get_nic_opaque(nc);
+    int n;
+    uint8_t *p;
+    uint32_t crc;
+
+    if ((s->rctl & SE_RCTL_RXEN) == 0)
+        return -1;
+    if (s->np >= 31) {
+        DPRINTF("Packet dropped\n");
+        return -1;
+    }
+
+    DPRINTF("Received packet len=%d\n", size);
+    n = s->next_packet + s->np;
+    if (n >= 31)
+        n -= 31;
+    s->np++;
+
+    s->rx[n].len = size + 6;
+    p = s->rx[n].data;
+    *(p++) = (size + 6);
+    *(p++) = (size + 6) >> 8;
+    memcpy (p, buf, size);
+    p += size;
+    crc = crc32(~0, buf, size);
+    *(p++) = crc;
+    *(p++) = crc >> 8;
+    *(p++) = crc >> 16;
+    *(p++) = crc >> 24;
+    /* Clear the remaining bytes in the last word.  */
+    if ((size & 3) != 2) {
+        memset(p, 0, (6 - size) & 3);
+    }
+
+    s->ris |= SE_INT_RX;
+    stellaris_enet_update(s);
+
+    return size;
+}
+
+static int stellaris_enet_can_receive(NetClientState *nc)
+{
+    stellaris_enet_state *s = qemu_get_nic_opaque(nc);
+
+    if ((s->rctl & SE_RCTL_RXEN) == 0)
+        return 1;
+
+    return (s->np < 31);
+}
+
+static uint64_t stellaris_enet_read(void *opaque, hwaddr offset,
+                                    unsigned size)
+{
+    stellaris_enet_state *s = (stellaris_enet_state *)opaque;
+    uint32_t val;
+
+    switch (offset) {
+    case 0x00: /* RIS */
+        DPRINTF("IRQ status %02x\n", s->ris);
+        return s->ris;
+    case 0x04: /* IM */
+        return s->im;
+    case 0x08: /* RCTL */
+        return s->rctl;
+    case 0x0c: /* TCTL */
+        return s->tctl;
+    case 0x10: /* DATA */
+        if (s->rx_fifo_len == 0) {
+            if (s->np == 0) {
+                BADF("RX underflow\n");
+                return 0;
+            }
+            s->rx_fifo_len = s->rx[s->next_packet].len;
+            s->rx_fifo = s->rx[s->next_packet].data;
+            DPRINTF("RX FIFO start packet len=%d\n", s->rx_fifo_len);
+        }
+        val = s->rx_fifo[0] | (s->rx_fifo[1] << 8) | (s->rx_fifo[2] << 16)
+              | (s->rx_fifo[3] << 24);
+        s->rx_fifo += 4;
+        s->rx_fifo_len -= 4;
+        if (s->rx_fifo_len <= 0) {
+            s->rx_fifo_len = 0;
+            s->next_packet++;
+            if (s->next_packet >= 31)
+                s->next_packet = 0;
+            s->np--;
+            DPRINTF("RX done np=%d\n", s->np);
+        }
+        return val;
+    case 0x14: /* IA0 */
+        return s->conf.macaddr.a[0] | (s->conf.macaddr.a[1] << 8)
+               | (s->conf.macaddr.a[2] << 16) | (s->conf.macaddr.a[3] << 24);
+    case 0x18: /* IA1 */
+        return s->conf.macaddr.a[4] | (s->conf.macaddr.a[5] << 8);
+    case 0x1c: /* THR */
+        return s->thr;
+    case 0x20: /* MCTL */
+        return s->mctl;
+    case 0x24: /* MDV */
+        return s->mdv;
+    case 0x28: /* MADD */
+        return 0;
+    case 0x2c: /* MTXD */
+        return s->mtxd;
+    case 0x30: /* MRXD */
+        return s->mrxd;
+    case 0x34: /* NP */
+        return s->np;
+    case 0x38: /* TR */
+        return 0;
+    case 0x3c: /* Undocuented: Timestamp? */
+        return 0;
+    default:
+        hw_error("stellaris_enet_read: Bad offset %x\n", (int)offset);
+        return 0;
+    }
+}
+
+static void stellaris_enet_write(void *opaque, hwaddr offset,
+                                 uint64_t value, unsigned size)
+{
+    stellaris_enet_state *s = (stellaris_enet_state *)opaque;
+
+    switch (offset) {
+    case 0x00: /* IACK */
+        s->ris &= ~value;
+        DPRINTF("IRQ ack %02x/%02x\n", value, s->ris);
+        stellaris_enet_update(s);
+        /* Clearing TXER also resets the TX fifo.  */
+        if (value & SE_INT_TXER)
+            s->tx_frame_len = -1;
+        break;
+    case 0x04: /* IM */
+        DPRINTF("IRQ mask %02x/%02x\n", value, s->ris);
+        s->im = value;
+        stellaris_enet_update(s);
+        break;
+    case 0x08: /* RCTL */
+        s->rctl = value;
+        if (value & SE_RCTL_RSTFIFO) {
+            s->rx_fifo_len = 0;
+            s->np = 0;
+            stellaris_enet_update(s);
+        }
+        break;
+    case 0x0c: /* TCTL */
+        s->tctl = value;
+        break;
+    case 0x10: /* DATA */
+        if (s->tx_frame_len == -1) {
+            s->tx_frame_len = value & 0xffff;
+            if (s->tx_frame_len > 2032) {
+                DPRINTF("TX frame too long (%d)\n", s->tx_frame_len);
+                s->tx_frame_len = 0;
+                s->ris |= SE_INT_TXER;
+                stellaris_enet_update(s);
+            } else {
+                DPRINTF("Start TX frame len=%d\n", s->tx_frame_len);
+                /* The value written does not include the ethernet header.  */
+                s->tx_frame_len += 14;
+                if ((s->tctl & SE_TCTL_CRC) == 0)
+                    s->tx_frame_len += 4;
+                s->tx_fifo_len = 0;
+                s->tx_fifo[s->tx_fifo_len++] = value >> 16;
+                s->tx_fifo[s->tx_fifo_len++] = value >> 24;
+            }
+        } else {
+            s->tx_fifo[s->tx_fifo_len++] = value;
+            s->tx_fifo[s->tx_fifo_len++] = value >> 8;
+            s->tx_fifo[s->tx_fifo_len++] = value >> 16;
+            s->tx_fifo[s->tx_fifo_len++] = value >> 24;
+            if (s->tx_fifo_len >= s->tx_frame_len) {
+                /* We don't implement explicit CRC, so just chop it off.  */
+                if ((s->tctl & SE_TCTL_CRC) == 0)
+                    s->tx_frame_len -= 4;
+                if ((s->tctl & SE_TCTL_PADEN) && s->tx_frame_len < 60) {
+                    memset(&s->tx_fifo[s->tx_frame_len], 0, 60 - s->tx_frame_len);
+                    s->tx_fifo_len = 60;
+                }
+                qemu_send_packet(qemu_get_queue(s->nic), s->tx_fifo,
+                                 s->tx_frame_len);
+                s->tx_frame_len = -1;
+                s->ris |= SE_INT_TXEMP;
+                stellaris_enet_update(s);
+                DPRINTF("Done TX\n");
+            }
+        }
+        break;
+    case 0x14: /* IA0 */
+        s->conf.macaddr.a[0] = value;
+        s->conf.macaddr.a[1] = value >> 8;
+        s->conf.macaddr.a[2] = value >> 16;
+        s->conf.macaddr.a[3] = value >> 24;
+        break;
+    case 0x18: /* IA1 */
+        s->conf.macaddr.a[4] = value;
+        s->conf.macaddr.a[5] = value >> 8;
+        break;
+    case 0x1c: /* THR */
+        s->thr = value;
+        break;
+    case 0x20: /* MCTL */
+        s->mctl = value;
+        break;
+    case 0x24: /* MDV */
+        s->mdv = value;
+        break;
+    case 0x28: /* MADD */
+        /* ignored.  */
+        break;
+    case 0x2c: /* MTXD */
+        s->mtxd = value & 0xff;
+        break;
+    case 0x30: /* MRXD */
+    case 0x34: /* NP */
+    case 0x38: /* TR */
+        /* Ignored.  */
+    case 0x3c: /* Undocuented: Timestamp? */
+        /* Ignored.  */
+        break;
+    default:
+        hw_error("stellaris_enet_write: Bad offset %x\n", (int)offset);
+    }
+}
+
+static const MemoryRegionOps stellaris_enet_ops = {
+    .read = stellaris_enet_read,
+    .write = stellaris_enet_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void stellaris_enet_reset(stellaris_enet_state *s)
+{
+    s->mdv = 0x80;
+    s->rctl = SE_RCTL_BADCRC;
+    s->im = SE_INT_PHY | SE_INT_MD | SE_INT_RXER | SE_INT_FOV | SE_INT_TXEMP
+            | SE_INT_TXER | SE_INT_RX;
+    s->thr = 0x3f;
+    s->tx_frame_len = -1;
+}
+
+static void stellaris_enet_save(QEMUFile *f, void *opaque)
+{
+    stellaris_enet_state *s = (stellaris_enet_state *)opaque;
+    int i;
+
+    qemu_put_be32(f, s->ris);
+    qemu_put_be32(f, s->im);
+    qemu_put_be32(f, s->rctl);
+    qemu_put_be32(f, s->tctl);
+    qemu_put_be32(f, s->thr);
+    qemu_put_be32(f, s->mctl);
+    qemu_put_be32(f, s->mdv);
+    qemu_put_be32(f, s->mtxd);
+    qemu_put_be32(f, s->mrxd);
+    qemu_put_be32(f, s->np);
+    qemu_put_be32(f, s->tx_frame_len);
+    qemu_put_be32(f, s->tx_fifo_len);
+    qemu_put_buffer(f, s->tx_fifo, sizeof(s->tx_fifo));
+    for (i = 0; i < 31; i++) {
+        qemu_put_be32(f, s->rx[i].len);
+        qemu_put_buffer(f, s->rx[i].data, sizeof(s->rx[i].data));
+
+    }
+    qemu_put_be32(f, s->next_packet);
+    qemu_put_be32(f, s->rx_fifo - s->rx[s->next_packet].data);
+    qemu_put_be32(f, s->rx_fifo_len);
+}
+
+static int stellaris_enet_load(QEMUFile *f, void *opaque, int version_id)
+{
+    stellaris_enet_state *s = (stellaris_enet_state *)opaque;
+    int i;
+
+    if (version_id != 1)
+        return -EINVAL;
+
+    s->ris = qemu_get_be32(f);
+    s->im = qemu_get_be32(f);
+    s->rctl = qemu_get_be32(f);
+    s->tctl = qemu_get_be32(f);
+    s->thr = qemu_get_be32(f);
+    s->mctl = qemu_get_be32(f);
+    s->mdv = qemu_get_be32(f);
+    s->mtxd = qemu_get_be32(f);
+    s->mrxd = qemu_get_be32(f);
+    s->np = qemu_get_be32(f);
+    s->tx_frame_len = qemu_get_be32(f);
+    s->tx_fifo_len = qemu_get_be32(f);
+    qemu_get_buffer(f, s->tx_fifo, sizeof(s->tx_fifo));
+    for (i = 0; i < 31; i++) {
+        s->rx[i].len = qemu_get_be32(f);
+        qemu_get_buffer(f, s->rx[i].data, sizeof(s->rx[i].data));
+
+    }
+    s->next_packet = qemu_get_be32(f);
+    s->rx_fifo = s->rx[s->next_packet].data + qemu_get_be32(f);
+    s->rx_fifo_len = qemu_get_be32(f);
+
+    return 0;
+}
+
+static void stellaris_enet_cleanup(NetClientState *nc)
+{
+    stellaris_enet_state *s = qemu_get_nic_opaque(nc);
+
+    unregister_savevm(&s->busdev.qdev, "stellaris_enet", s);
+
+    memory_region_destroy(&s->mmio);
+
+    g_free(s);
+}
+
+static NetClientInfo net_stellaris_enet_info = {
+    .type = NET_CLIENT_OPTIONS_KIND_NIC,
+    .size = sizeof(NICState),
+    .can_receive = stellaris_enet_can_receive,
+    .receive = stellaris_enet_receive,
+    .cleanup = stellaris_enet_cleanup,
+};
+
+static int stellaris_enet_init(SysBusDevice *dev)
+{
+    stellaris_enet_state *s = FROM_SYSBUS(stellaris_enet_state, dev);
+
+    memory_region_init_io(&s->mmio, &stellaris_enet_ops, s, "stellaris_enet",
+                          0x1000);
+    sysbus_init_mmio(dev, &s->mmio);
+    sysbus_init_irq(dev, &s->irq);
+    qemu_macaddr_default_if_unset(&s->conf.macaddr);
+
+    s->nic = qemu_new_nic(&net_stellaris_enet_info, &s->conf,
+                          object_get_typename(OBJECT(dev)), dev->qdev.id, s);
+    qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
+
+    stellaris_enet_reset(s);
+    register_savevm(&s->busdev.qdev, "stellaris_enet", -1, 1,
+                    stellaris_enet_save, stellaris_enet_load, s);
+    return 0;
+}
+
+static Property stellaris_enet_properties[] = {
+    DEFINE_NIC_PROPERTIES(stellaris_enet_state, conf),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void stellaris_enet_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = stellaris_enet_init;
+    dc->props = stellaris_enet_properties;
+}
+
+static const 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_types(void)
+{
+    type_register_static(&stellaris_enet_info);
+}
+
+type_init(stellaris_enet_register_types)
diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c
new file mode 100644 (file)
index 0000000..8c5384c
--- /dev/null
@@ -0,0 +1,328 @@
+/*
+ * vhost-net support
+ *
+ * Copyright Red Hat, Inc. 2010
+ *
+ * Authors:
+ *  Michael S. Tsirkin <mst@redhat.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 "net/net.h"
+#include "net/tap.h"
+
+#include "hw/virtio/virtio-net.h"
+#include "net/vhost_net.h"
+#include "qemu/error-report.h"
+
+#include "config.h"
+
+#ifdef CONFIG_VHOST_NET
+#include <linux/vhost.h>
+#include <sys/socket.h>
+#include <linux/kvm.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <linux/virtio_ring.h>
+#include <netpacket/packet.h>
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <netinet/in.h>
+
+#include <stdio.h>
+
+#include "hw/virtio/vhost.h"
+
+struct vhost_net {
+    struct vhost_dev dev;
+    struct vhost_virtqueue vqs[2];
+    int backend;
+    NetClientState *nc;
+};
+
+unsigned vhost_net_get_features(struct vhost_net *net, unsigned features)
+{
+    /* Clear features not supported by host kernel. */
+    if (!(net->dev.features & (1 << VIRTIO_F_NOTIFY_ON_EMPTY))) {
+        features &= ~(1 << VIRTIO_F_NOTIFY_ON_EMPTY);
+    }
+    if (!(net->dev.features & (1 << VIRTIO_RING_F_INDIRECT_DESC))) {
+        features &= ~(1 << VIRTIO_RING_F_INDIRECT_DESC);
+    }
+    if (!(net->dev.features & (1 << VIRTIO_RING_F_EVENT_IDX))) {
+        features &= ~(1 << VIRTIO_RING_F_EVENT_IDX);
+    }
+    if (!(net->dev.features & (1 << VIRTIO_NET_F_MRG_RXBUF))) {
+        features &= ~(1 << VIRTIO_NET_F_MRG_RXBUF);
+    }
+    return features;
+}
+
+void vhost_net_ack_features(struct vhost_net *net, unsigned features)
+{
+    net->dev.acked_features = net->dev.backend_features;
+    if (features & (1 << VIRTIO_F_NOTIFY_ON_EMPTY)) {
+        net->dev.acked_features |= (1 << VIRTIO_F_NOTIFY_ON_EMPTY);
+    }
+    if (features & (1 << VIRTIO_RING_F_INDIRECT_DESC)) {
+        net->dev.acked_features |= (1 << VIRTIO_RING_F_INDIRECT_DESC);
+    }
+    if (features & (1 << VIRTIO_RING_F_EVENT_IDX)) {
+        net->dev.acked_features |= (1 << VIRTIO_RING_F_EVENT_IDX);
+    }
+    if (features & (1 << VIRTIO_NET_F_MRG_RXBUF)) {
+        net->dev.acked_features |= (1 << VIRTIO_NET_F_MRG_RXBUF);
+    }
+}
+
+static int vhost_net_get_fd(NetClientState *backend)
+{
+    switch (backend->info->type) {
+    case NET_CLIENT_OPTIONS_KIND_TAP:
+        return tap_get_fd(backend);
+    default:
+        fprintf(stderr, "vhost-net requires tap backend\n");
+        return -EBADFD;
+    }
+}
+
+struct vhost_net *vhost_net_init(NetClientState *backend, int devfd,
+                                 bool force)
+{
+    int r;
+    struct vhost_net *net = g_malloc(sizeof *net);
+    if (!backend) {
+        fprintf(stderr, "vhost-net requires backend to be setup\n");
+        goto fail;
+    }
+    r = vhost_net_get_fd(backend);
+    if (r < 0) {
+        goto fail;
+    }
+    net->nc = backend;
+    net->dev.backend_features = tap_has_vnet_hdr(backend) ? 0 :
+        (1 << VHOST_NET_F_VIRTIO_NET_HDR);
+    net->backend = r;
+
+    net->dev.nvqs = 2;
+    net->dev.vqs = net->vqs;
+
+    r = vhost_dev_init(&net->dev, devfd, "/dev/vhost-net", force);
+    if (r < 0) {
+        goto fail;
+    }
+    if (!tap_has_vnet_hdr_len(backend,
+                              sizeof(struct virtio_net_hdr_mrg_rxbuf))) {
+        net->dev.features &= ~(1 << VIRTIO_NET_F_MRG_RXBUF);
+    }
+    if (~net->dev.features & net->dev.backend_features) {
+        fprintf(stderr, "vhost lacks feature mask %" PRIu64 " for backend\n",
+                (uint64_t)(~net->dev.features & net->dev.backend_features));
+        vhost_dev_cleanup(&net->dev);
+        goto fail;
+    }
+
+    /* Set sane init value. Override when guest acks. */
+    vhost_net_ack_features(net, 0);
+    return net;
+fail:
+    g_free(net);
+    return NULL;
+}
+
+bool vhost_net_query(VHostNetState *net, VirtIODevice *dev)
+{
+    return vhost_dev_query(&net->dev, dev);
+}
+
+static int vhost_net_start_one(struct vhost_net *net,
+                               VirtIODevice *dev,
+                               int vq_index)
+{
+    struct vhost_vring_file file = { };
+    int r;
+
+    if (net->dev.started) {
+        return 0;
+    }
+
+    net->dev.nvqs = 2;
+    net->dev.vqs = net->vqs;
+    net->dev.vq_index = vq_index;
+
+    r = vhost_dev_enable_notifiers(&net->dev, dev);
+    if (r < 0) {
+        goto fail_notifiers;
+    }
+
+    r = vhost_dev_start(&net->dev, dev);
+    if (r < 0) {
+        goto fail_start;
+    }
+
+    net->nc->info->poll(net->nc, false);
+    qemu_set_fd_handler(net->backend, NULL, NULL, NULL);
+    file.fd = net->backend;
+    for (file.index = 0; file.index < net->dev.nvqs; ++file.index) {
+        r = ioctl(net->dev.control, VHOST_NET_SET_BACKEND, &file);
+        if (r < 0) {
+            r = -errno;
+            goto fail;
+        }
+    }
+    return 0;
+fail:
+    file.fd = -1;
+    while (file.index-- > 0) {
+        int r = ioctl(net->dev.control, VHOST_NET_SET_BACKEND, &file);
+        assert(r >= 0);
+    }
+    net->nc->info->poll(net->nc, true);
+    vhost_dev_stop(&net->dev, dev);
+fail_start:
+    vhost_dev_disable_notifiers(&net->dev, dev);
+fail_notifiers:
+    return r;
+}
+
+static void vhost_net_stop_one(struct vhost_net *net,
+                               VirtIODevice *dev)
+{
+    struct vhost_vring_file file = { .fd = -1 };
+
+    if (!net->dev.started) {
+        return;
+    }
+
+    for (file.index = 0; file.index < net->dev.nvqs; ++file.index) {
+        int r = ioctl(net->dev.control, VHOST_NET_SET_BACKEND, &file);
+        assert(r >= 0);
+    }
+    net->nc->info->poll(net->nc, true);
+    vhost_dev_stop(&net->dev, dev);
+    vhost_dev_disable_notifiers(&net->dev, dev);
+}
+
+int vhost_net_start(VirtIODevice *dev, NetClientState *ncs,
+                    int total_queues)
+{
+    int r, i = 0;
+
+    if (!dev->binding->set_guest_notifiers) {
+        error_report("binding does not support guest notifiers");
+        r = -ENOSYS;
+        goto err;
+    }
+
+    for (i = 0; i < total_queues; i++) {
+        r = vhost_net_start_one(tap_get_vhost_net(ncs[i].peer), dev, i * 2);
+
+        if (r < 0) {
+            goto err;
+        }
+    }
+
+    r = dev->binding->set_guest_notifiers(dev->binding_opaque,
+                                          total_queues * 2,
+                                          true);
+    if (r < 0) {
+        error_report("Error binding guest notifier: %d", -r);
+        goto err;
+    }
+
+    return 0;
+
+err:
+    while (--i >= 0) {
+        vhost_net_stop_one(tap_get_vhost_net(ncs[i].peer), dev);
+    }
+    return r;
+}
+
+void vhost_net_stop(VirtIODevice *dev, NetClientState *ncs,
+                    int total_queues)
+{
+    int i, r;
+
+    r = dev->binding->set_guest_notifiers(dev->binding_opaque,
+                                          total_queues * 2,
+                                          false);
+    if (r < 0) {
+        fprintf(stderr, "vhost guest notifier cleanup failed: %d\n", r);
+        fflush(stderr);
+    }
+    assert(r >= 0);
+
+    for (i = 0; i < total_queues; i++) {
+        vhost_net_stop_one(tap_get_vhost_net(ncs[i].peer), dev);
+    }
+}
+
+void vhost_net_cleanup(struct vhost_net *net)
+{
+    vhost_dev_cleanup(&net->dev);
+    g_free(net);
+}
+
+bool vhost_net_virtqueue_pending(VHostNetState *net, int idx)
+{
+    return vhost_virtqueue_pending(&net->dev, idx);
+}
+
+void vhost_net_virtqueue_mask(VHostNetState *net, VirtIODevice *dev,
+                              int idx, bool mask)
+{
+    vhost_virtqueue_mask(&net->dev, dev, idx, mask);
+}
+#else
+struct vhost_net *vhost_net_init(NetClientState *backend, int devfd,
+                                 bool force)
+{
+    error_report("vhost-net support is not compiled in");
+    return NULL;
+}
+
+bool vhost_net_query(VHostNetState *net, VirtIODevice *dev)
+{
+    return false;
+}
+
+int vhost_net_start(VirtIODevice *dev,
+                    NetClientState *ncs,
+                    int total_queues)
+{
+    return -ENOSYS;
+}
+void vhost_net_stop(VirtIODevice *dev,
+                    NetClientState *ncs,
+                    int total_queues)
+{
+}
+
+void vhost_net_cleanup(struct vhost_net *net)
+{
+}
+
+unsigned vhost_net_get_features(struct vhost_net *net, unsigned features)
+{
+    return features;
+}
+void vhost_net_ack_features(struct vhost_net *net, unsigned features)
+{
+}
+
+bool vhost_net_virtqueue_pending(VHostNetState *net, int idx)
+{
+    return -ENOSYS;
+}
+
+void vhost_net_virtqueue_mask(VHostNetState *net, VirtIODevice *dev,
+                              int idx, bool mask)
+{
+}
+#endif
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
new file mode 100644 (file)
index 0000000..bc8fd43
--- /dev/null
@@ -0,0 +1,1370 @@
+/*
+ * Virtio Network Device
+ *
+ * Copyright IBM, Corp. 2007
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.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 "qemu/iov.h"
+#include "hw/virtio/virtio.h"
+#include "net/net.h"
+#include "net/checksum.h"
+#include "net/tap.h"
+#include "qemu/error-report.h"
+#include "qemu/timer.h"
+#include "hw/virtio/virtio-net.h"
+#include "net/vhost_net.h"
+
+#define VIRTIO_NET_VM_VERSION    11
+
+#define MAC_TABLE_ENTRIES    64
+#define MAX_VLAN    (1 << 12)   /* Per 802.1Q definition */
+
+/*
+ * Calculate the number of bytes up to and including the given 'field' of
+ * 'container'.
+ */
+#define endof(container, field) \
+    (offsetof(container, field) + sizeof(((container *)0)->field))
+
+typedef struct VirtIOFeature {
+    uint32_t flags;
+    size_t end;
+} VirtIOFeature;
+
+static VirtIOFeature feature_sizes[] = {
+    {.flags = 1 << VIRTIO_NET_F_MAC,
+     .end = endof(struct virtio_net_config, mac)},
+    {.flags = 1 << VIRTIO_NET_F_STATUS,
+     .end = endof(struct virtio_net_config, status)},
+    {.flags = 1 << VIRTIO_NET_F_MQ,
+     .end = endof(struct virtio_net_config, max_virtqueue_pairs)},
+    {}
+};
+
+static VirtIONetQueue *virtio_net_get_subqueue(NetClientState *nc)
+{
+    VirtIONet *n = qemu_get_nic_opaque(nc);
+
+    return &n->vqs[nc->queue_index];
+}
+
+static int vq2q(int queue_index)
+{
+    return queue_index / 2;
+}
+
+/* TODO
+ * - we could suppress RX interrupt if we were so inclined.
+ */
+
+static VirtIONet *to_virtio_net(VirtIODevice *vdev)
+{
+    return (VirtIONet *)vdev;
+}
+
+static void virtio_net_get_config(VirtIODevice *vdev, uint8_t *config)
+{
+    VirtIONet *n = to_virtio_net(vdev);
+    struct virtio_net_config netcfg;
+
+    stw_p(&netcfg.status, n->status);
+    stw_p(&netcfg.max_virtqueue_pairs, n->max_queues);
+    memcpy(netcfg.mac, n->mac, ETH_ALEN);
+    memcpy(config, &netcfg, n->config_size);
+}
+
+static void virtio_net_set_config(VirtIODevice *vdev, const uint8_t *config)
+{
+    VirtIONet *n = to_virtio_net(vdev);
+    struct virtio_net_config netcfg = {};
+
+    memcpy(&netcfg, config, n->config_size);
+
+    if (!(n->vdev.guest_features >> VIRTIO_NET_F_CTRL_MAC_ADDR & 1) &&
+        memcmp(netcfg.mac, n->mac, ETH_ALEN)) {
+        memcpy(n->mac, netcfg.mac, ETH_ALEN);
+        qemu_format_nic_info_str(qemu_get_queue(n->nic), n->mac);
+    }
+}
+
+static bool virtio_net_started(VirtIONet *n, uint8_t status)
+{
+    return (status & VIRTIO_CONFIG_S_DRIVER_OK) &&
+        (n->status & VIRTIO_NET_S_LINK_UP) && n->vdev.vm_running;
+}
+
+static void virtio_net_vhost_status(VirtIONet *n, uint8_t status)
+{
+    NetClientState *nc = qemu_get_queue(n->nic);
+    int queues = n->multiqueue ? n->max_queues : 1;
+
+    if (!nc->peer) {
+        return;
+    }
+    if (nc->peer->info->type != NET_CLIENT_OPTIONS_KIND_TAP) {
+        return;
+    }
+
+    if (!tap_get_vhost_net(nc->peer)) {
+        return;
+    }
+
+    if (!!n->vhost_started == virtio_net_started(n, status) &&
+                              !nc->peer->link_down) {
+        return;
+    }
+    if (!n->vhost_started) {
+        int r;
+        if (!vhost_net_query(tap_get_vhost_net(nc->peer), &n->vdev)) {
+            return;
+        }
+        n->vhost_started = 1;
+        r = vhost_net_start(&n->vdev, n->nic->ncs, queues);
+        if (r < 0) {
+            error_report("unable to start vhost net: %d: "
+                         "falling back on userspace virtio", -r);
+            n->vhost_started = 0;
+        }
+    } else {
+        vhost_net_stop(&n->vdev, n->nic->ncs, queues);
+        n->vhost_started = 0;
+    }
+}
+
+static void virtio_net_set_status(struct VirtIODevice *vdev, uint8_t status)
+{
+    VirtIONet *n = to_virtio_net(vdev);
+    VirtIONetQueue *q;
+    int i;
+    uint8_t queue_status;
+
+    virtio_net_vhost_status(n, status);
+
+    for (i = 0; i < n->max_queues; i++) {
+        q = &n->vqs[i];
+
+        if ((!n->multiqueue && i != 0) || i >= n->curr_queues) {
+            queue_status = 0;
+        } else {
+            queue_status = status;
+        }
+
+        if (!q->tx_waiting) {
+            continue;
+        }
+
+        if (virtio_net_started(n, queue_status) && !n->vhost_started) {
+            if (q->tx_timer) {
+                qemu_mod_timer(q->tx_timer,
+                               qemu_get_clock_ns(vm_clock) + n->tx_timeout);
+            } else {
+                qemu_bh_schedule(q->tx_bh);
+            }
+        } else {
+            if (q->tx_timer) {
+                qemu_del_timer(q->tx_timer);
+            } else {
+                qemu_bh_cancel(q->tx_bh);
+            }
+        }
+    }
+}
+
+static void virtio_net_set_link_status(NetClientState *nc)
+{
+    VirtIONet *n = qemu_get_nic_opaque(nc);
+    uint16_t old_status = n->status;
+
+    if (nc->link_down)
+        n->status &= ~VIRTIO_NET_S_LINK_UP;
+    else
+        n->status |= VIRTIO_NET_S_LINK_UP;
+
+    if (n->status != old_status)
+        virtio_notify_config(&n->vdev);
+
+    virtio_net_set_status(&n->vdev, n->vdev.status);
+}
+
+static void virtio_net_reset(VirtIODevice *vdev)
+{
+    VirtIONet *n = to_virtio_net(vdev);
+
+    /* Reset back to compatibility mode */
+    n->promisc = 1;
+    n->allmulti = 0;
+    n->alluni = 0;
+    n->nomulti = 0;
+    n->nouni = 0;
+    n->nobcast = 0;
+    /* multiqueue is disabled by default */
+    n->curr_queues = 1;
+
+    /* Flush any MAC and VLAN filter table state */
+    n->mac_table.in_use = 0;
+    n->mac_table.first_multi = 0;
+    n->mac_table.multi_overflow = 0;
+    n->mac_table.uni_overflow = 0;
+    memset(n->mac_table.macs, 0, MAC_TABLE_ENTRIES * ETH_ALEN);
+    memcpy(&n->mac[0], &n->nic->conf->macaddr, sizeof(n->mac));
+    memset(n->vlans, 0, MAX_VLAN >> 3);
+}
+
+static void peer_test_vnet_hdr(VirtIONet *n)
+{
+    NetClientState *nc = qemu_get_queue(n->nic);
+    if (!nc->peer) {
+        return;
+    }
+
+    if (nc->peer->info->type != NET_CLIENT_OPTIONS_KIND_TAP) {
+        return;
+    }
+
+    n->has_vnet_hdr = tap_has_vnet_hdr(nc->peer);
+}
+
+static int peer_has_vnet_hdr(VirtIONet *n)
+{
+    return n->has_vnet_hdr;
+}
+
+static int peer_has_ufo(VirtIONet *n)
+{
+    if (!peer_has_vnet_hdr(n))
+        return 0;
+
+    n->has_ufo = tap_has_ufo(qemu_get_queue(n->nic)->peer);
+
+    return n->has_ufo;
+}
+
+static void virtio_net_set_mrg_rx_bufs(VirtIONet *n, int mergeable_rx_bufs)
+{
+    int i;
+    NetClientState *nc;
+
+    n->mergeable_rx_bufs = mergeable_rx_bufs;
+
+    n->guest_hdr_len = n->mergeable_rx_bufs ?
+        sizeof(struct virtio_net_hdr_mrg_rxbuf) : sizeof(struct virtio_net_hdr);
+
+    for (i = 0; i < n->max_queues; i++) {
+        nc = qemu_get_subqueue(n->nic, i);
+
+        if (peer_has_vnet_hdr(n) &&
+            tap_has_vnet_hdr_len(nc->peer, n->guest_hdr_len)) {
+            tap_set_vnet_hdr_len(nc->peer, n->guest_hdr_len);
+            n->host_hdr_len = n->guest_hdr_len;
+        }
+    }
+}
+
+static int peer_attach(VirtIONet *n, int index)
+{
+    NetClientState *nc = qemu_get_subqueue(n->nic, index);
+
+    if (!nc->peer) {
+        return 0;
+    }
+
+    if (nc->peer->info->type != NET_CLIENT_OPTIONS_KIND_TAP) {
+        return 0;
+    }
+
+    return tap_enable(nc->peer);
+}
+
+static int peer_detach(VirtIONet *n, int index)
+{
+    NetClientState *nc = qemu_get_subqueue(n->nic, index);
+
+    if (!nc->peer) {
+        return 0;
+    }
+
+    if (nc->peer->info->type !=  NET_CLIENT_OPTIONS_KIND_TAP) {
+        return 0;
+    }
+
+    return tap_disable(nc->peer);
+}
+
+static void virtio_net_set_queues(VirtIONet *n)
+{
+    int i;
+
+    for (i = 0; i < n->max_queues; i++) {
+        if (i < n->curr_queues) {
+            assert(!peer_attach(n, i));
+        } else {
+            assert(!peer_detach(n, i));
+        }
+    }
+}
+
+static void virtio_net_set_multiqueue(VirtIONet *n, int multiqueue, int ctrl);
+
+static uint32_t virtio_net_get_features(VirtIODevice *vdev, uint32_t features)
+{
+    VirtIONet *n = to_virtio_net(vdev);
+    NetClientState *nc = qemu_get_queue(n->nic);
+
+    features |= (1 << VIRTIO_NET_F_MAC);
+
+    if (!peer_has_vnet_hdr(n)) {
+        features &= ~(0x1 << VIRTIO_NET_F_CSUM);
+        features &= ~(0x1 << VIRTIO_NET_F_HOST_TSO4);
+        features &= ~(0x1 << VIRTIO_NET_F_HOST_TSO6);
+        features &= ~(0x1 << VIRTIO_NET_F_HOST_ECN);
+
+        features &= ~(0x1 << VIRTIO_NET_F_GUEST_CSUM);
+        features &= ~(0x1 << VIRTIO_NET_F_GUEST_TSO4);
+        features &= ~(0x1 << VIRTIO_NET_F_GUEST_TSO6);
+        features &= ~(0x1 << VIRTIO_NET_F_GUEST_ECN);
+    }
+
+    if (!peer_has_vnet_hdr(n) || !peer_has_ufo(n)) {
+        features &= ~(0x1 << VIRTIO_NET_F_GUEST_UFO);
+        features &= ~(0x1 << VIRTIO_NET_F_HOST_UFO);
+    }
+
+    if (!nc->peer || nc->peer->info->type != NET_CLIENT_OPTIONS_KIND_TAP) {
+        return features;
+    }
+    if (!tap_get_vhost_net(nc->peer)) {
+        return features;
+    }
+    return vhost_net_get_features(tap_get_vhost_net(nc->peer), features);
+}
+
+static uint32_t virtio_net_bad_features(VirtIODevice *vdev)
+{
+    uint32_t features = 0;
+
+    /* Linux kernel 2.6.25.  It understood MAC (as everyone must),
+     * but also these: */
+    features |= (1 << VIRTIO_NET_F_MAC);
+    features |= (1 << VIRTIO_NET_F_CSUM);
+    features |= (1 << VIRTIO_NET_F_HOST_TSO4);
+    features |= (1 << VIRTIO_NET_F_HOST_TSO6);
+    features |= (1 << VIRTIO_NET_F_HOST_ECN);
+
+    return features;
+}
+
+static void virtio_net_set_features(VirtIODevice *vdev, uint32_t features)
+{
+    VirtIONet *n = to_virtio_net(vdev);
+    int i;
+
+    virtio_net_set_multiqueue(n, !!(features & (1 << VIRTIO_NET_F_MQ)),
+                              !!(features & (1 << VIRTIO_NET_F_CTRL_VQ)));
+
+    virtio_net_set_mrg_rx_bufs(n, !!(features & (1 << VIRTIO_NET_F_MRG_RXBUF)));
+
+    if (n->has_vnet_hdr) {
+        tap_set_offload(qemu_get_subqueue(n->nic, 0)->peer,
+                        (features >> VIRTIO_NET_F_GUEST_CSUM) & 1,
+                        (features >> VIRTIO_NET_F_GUEST_TSO4) & 1,
+                        (features >> VIRTIO_NET_F_GUEST_TSO6) & 1,
+                        (features >> VIRTIO_NET_F_GUEST_ECN)  & 1,
+                        (features >> VIRTIO_NET_F_GUEST_UFO)  & 1);
+    }
+
+    for (i = 0;  i < n->max_queues; i++) {
+        NetClientState *nc = qemu_get_subqueue(n->nic, i);
+
+        if (!nc->peer || nc->peer->info->type != NET_CLIENT_OPTIONS_KIND_TAP) {
+            continue;
+        }
+        if (!tap_get_vhost_net(nc->peer)) {
+            continue;
+        }
+        vhost_net_ack_features(tap_get_vhost_net(nc->peer), features);
+    }
+}
+
+static int virtio_net_handle_rx_mode(VirtIONet *n, uint8_t cmd,
+                                     struct iovec *iov, unsigned int iov_cnt)
+{
+    uint8_t on;
+    size_t s;
+
+    s = iov_to_buf(iov, iov_cnt, 0, &on, sizeof(on));
+    if (s != sizeof(on)) {
+        return VIRTIO_NET_ERR;
+    }
+
+    if (cmd == VIRTIO_NET_CTRL_RX_PROMISC) {
+        n->promisc = on;
+    } else if (cmd == VIRTIO_NET_CTRL_RX_ALLMULTI) {
+        n->allmulti = on;
+    } else if (cmd == VIRTIO_NET_CTRL_RX_ALLUNI) {
+        n->alluni = on;
+    } else if (cmd == VIRTIO_NET_CTRL_RX_NOMULTI) {
+        n->nomulti = on;
+    } else if (cmd == VIRTIO_NET_CTRL_RX_NOUNI) {
+        n->nouni = on;
+    } else if (cmd == VIRTIO_NET_CTRL_RX_NOBCAST) {
+        n->nobcast = on;
+    } else {
+        return VIRTIO_NET_ERR;
+    }
+
+    return VIRTIO_NET_OK;
+}
+
+static int virtio_net_handle_mac(VirtIONet *n, uint8_t cmd,
+                                 struct iovec *iov, unsigned int iov_cnt)
+{
+    struct virtio_net_ctrl_mac mac_data;
+    size_t s;
+
+    if (cmd == VIRTIO_NET_CTRL_MAC_ADDR_SET) {
+        if (iov_size(iov, iov_cnt) != sizeof(n->mac)) {
+            return VIRTIO_NET_ERR;
+        }
+        s = iov_to_buf(iov, iov_cnt, 0, &n->mac, sizeof(n->mac));
+        assert(s == sizeof(n->mac));
+        qemu_format_nic_info_str(qemu_get_queue(n->nic), n->mac);
+        return VIRTIO_NET_OK;
+    }
+
+    if (cmd != VIRTIO_NET_CTRL_MAC_TABLE_SET) {
+        return VIRTIO_NET_ERR;
+    }
+
+    n->mac_table.in_use = 0;
+    n->mac_table.first_multi = 0;
+    n->mac_table.uni_overflow = 0;
+    n->mac_table.multi_overflow = 0;
+    memset(n->mac_table.macs, 0, MAC_TABLE_ENTRIES * ETH_ALEN);
+
+    s = iov_to_buf(iov, iov_cnt, 0, &mac_data.entries,
+                   sizeof(mac_data.entries));
+    mac_data.entries = ldl_p(&mac_data.entries);
+    if (s != sizeof(mac_data.entries)) {
+        return VIRTIO_NET_ERR;
+    }
+    iov_discard_front(&iov, &iov_cnt, s);
+
+    if (mac_data.entries * ETH_ALEN > iov_size(iov, iov_cnt)) {
+        return VIRTIO_NET_ERR;
+    }
+
+    if (mac_data.entries <= MAC_TABLE_ENTRIES) {
+        s = iov_to_buf(iov, iov_cnt, 0, n->mac_table.macs,
+                       mac_data.entries * ETH_ALEN);
+        if (s != mac_data.entries * ETH_ALEN) {
+            return VIRTIO_NET_ERR;
+        }
+        n->mac_table.in_use += mac_data.entries;
+    } else {
+        n->mac_table.uni_overflow = 1;
+    }
+
+    iov_discard_front(&iov, &iov_cnt, mac_data.entries * ETH_ALEN);
+
+    n->mac_table.first_multi = n->mac_table.in_use;
+
+    s = iov_to_buf(iov, iov_cnt, 0, &mac_data.entries,
+                   sizeof(mac_data.entries));
+    mac_data.entries = ldl_p(&mac_data.entries);
+    if (s != sizeof(mac_data.entries)) {
+        return VIRTIO_NET_ERR;
+    }
+
+    iov_discard_front(&iov, &iov_cnt, s);
+
+    if (mac_data.entries * ETH_ALEN != iov_size(iov, iov_cnt)) {
+        return VIRTIO_NET_ERR;
+    }
+
+    if (n->mac_table.in_use + mac_data.entries <= MAC_TABLE_ENTRIES) {
+        s = iov_to_buf(iov, iov_cnt, 0, n->mac_table.macs,
+                       mac_data.entries * ETH_ALEN);
+        if (s != mac_data.entries * ETH_ALEN) {
+            return VIRTIO_NET_ERR;
+        }
+        n->mac_table.in_use += mac_data.entries;
+    } else {
+        n->mac_table.multi_overflow = 1;
+    }
+
+    return VIRTIO_NET_OK;
+}
+
+static int virtio_net_handle_vlan_table(VirtIONet *n, uint8_t cmd,
+                                        struct iovec *iov, unsigned int iov_cnt)
+{
+    uint16_t vid;
+    size_t s;
+
+    s = iov_to_buf(iov, iov_cnt, 0, &vid, sizeof(vid));
+    vid = lduw_p(&vid);
+    if (s != sizeof(vid)) {
+        return VIRTIO_NET_ERR;
+    }
+
+    if (vid >= MAX_VLAN)
+        return VIRTIO_NET_ERR;
+
+    if (cmd == VIRTIO_NET_CTRL_VLAN_ADD)
+        n->vlans[vid >> 5] |= (1U << (vid & 0x1f));
+    else if (cmd == VIRTIO_NET_CTRL_VLAN_DEL)
+        n->vlans[vid >> 5] &= ~(1U << (vid & 0x1f));
+    else
+        return VIRTIO_NET_ERR;
+
+    return VIRTIO_NET_OK;
+}
+
+static int virtio_net_handle_mq(VirtIONet *n, uint8_t cmd,
+                                struct iovec *iov, unsigned int iov_cnt)
+{
+    struct virtio_net_ctrl_mq mq;
+    size_t s;
+    uint16_t queues;
+
+    s = iov_to_buf(iov, iov_cnt, 0, &mq, sizeof(mq));
+    if (s != sizeof(mq)) {
+        return VIRTIO_NET_ERR;
+    }
+
+    if (cmd != VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET) {
+        return VIRTIO_NET_ERR;
+    }
+
+    queues = lduw_p(&mq.virtqueue_pairs);
+
+    if (queues < VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN ||
+        queues > VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX ||
+        queues > n->max_queues ||
+        !n->multiqueue) {
+        return VIRTIO_NET_ERR;
+    }
+
+    n->curr_queues = queues;
+    /* stop the backend before changing the number of queues to avoid handling a
+     * disabled queue */
+    virtio_net_set_status(&n->vdev, n->vdev.status);
+    virtio_net_set_queues(n);
+
+    return VIRTIO_NET_OK;
+}
+static void virtio_net_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
+{
+    VirtIONet *n = to_virtio_net(vdev);
+    struct virtio_net_ctrl_hdr ctrl;
+    virtio_net_ctrl_ack status = VIRTIO_NET_ERR;
+    VirtQueueElement elem;
+    size_t s;
+    struct iovec *iov;
+    unsigned int iov_cnt;
+
+    while (virtqueue_pop(vq, &elem)) {
+        if (iov_size(elem.in_sg, elem.in_num) < sizeof(status) ||
+            iov_size(elem.out_sg, elem.out_num) < sizeof(ctrl)) {
+            error_report("virtio-net ctrl missing headers");
+            exit(1);
+        }
+
+        iov = elem.out_sg;
+        iov_cnt = elem.out_num;
+        s = iov_to_buf(iov, iov_cnt, 0, &ctrl, sizeof(ctrl));
+        iov_discard_front(&iov, &iov_cnt, sizeof(ctrl));
+        if (s != sizeof(ctrl)) {
+            status = VIRTIO_NET_ERR;
+        } else if (ctrl.class == VIRTIO_NET_CTRL_RX) {
+            status = virtio_net_handle_rx_mode(n, ctrl.cmd, iov, iov_cnt);
+        } else if (ctrl.class == VIRTIO_NET_CTRL_MAC) {
+            status = virtio_net_handle_mac(n, ctrl.cmd, iov, iov_cnt);
+        } else if (ctrl.class == VIRTIO_NET_CTRL_VLAN) {
+            status = virtio_net_handle_vlan_table(n, ctrl.cmd, iov, iov_cnt);
+        } else if (ctrl.class == VIRTIO_NET_CTRL_MQ) {
+            status = virtio_net_handle_mq(n, ctrl.cmd, iov, iov_cnt);
+        }
+
+        s = iov_from_buf(elem.in_sg, elem.in_num, 0, &status, sizeof(status));
+        assert(s == sizeof(status));
+
+        virtqueue_push(vq, &elem, sizeof(status));
+        virtio_notify(vdev, vq);
+    }
+}
+
+/* RX */
+
+static void virtio_net_handle_rx(VirtIODevice *vdev, VirtQueue *vq)
+{
+    VirtIONet *n = to_virtio_net(vdev);
+    int queue_index = vq2q(virtio_get_queue_index(vq));
+
+    qemu_flush_queued_packets(qemu_get_subqueue(n->nic, queue_index));
+}
+
+static int virtio_net_can_receive(NetClientState *nc)
+{
+    VirtIONet *n = qemu_get_nic_opaque(nc);
+    VirtIONetQueue *q = virtio_net_get_subqueue(nc);
+
+    if (!n->vdev.vm_running) {
+        return 0;
+    }
+
+    if (nc->queue_index >= n->curr_queues) {
+        return 0;
+    }
+
+    if (!virtio_queue_ready(q->rx_vq) ||
+        !(n->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK)) {
+        return 0;
+    }
+
+    return 1;
+}
+
+static int virtio_net_has_buffers(VirtIONetQueue *q, int bufsize)
+{
+    VirtIONet *n = q->n;
+    if (virtio_queue_empty(q->rx_vq) ||
+        (n->mergeable_rx_bufs &&
+         !virtqueue_avail_bytes(q->rx_vq, bufsize, 0))) {
+        virtio_queue_set_notification(q->rx_vq, 1);
+
+        /* To avoid a race condition where the guest has made some buffers
+         * available after the above check but before notification was
+         * enabled, check for available buffers again.
+         */
+        if (virtio_queue_empty(q->rx_vq) ||
+            (n->mergeable_rx_bufs &&
+             !virtqueue_avail_bytes(q->rx_vq, bufsize, 0))) {
+            return 0;
+        }
+    }
+
+    virtio_queue_set_notification(q->rx_vq, 0);
+    return 1;
+}
+
+/* dhclient uses AF_PACKET but doesn't pass auxdata to the kernel so
+ * it never finds out that the packets don't have valid checksums.  This
+ * causes dhclient to get upset.  Fedora's carried a patch for ages to
+ * fix this with Xen but it hasn't appeared in an upstream release of
+ * dhclient yet.
+ *
+ * To avoid breaking existing guests, we catch udp packets and add
+ * checksums.  This is terrible but it's better than hacking the guest
+ * kernels.
+ *
+ * N.B. if we introduce a zero-copy API, this operation is no longer free so
+ * we should provide a mechanism to disable it to avoid polluting the host
+ * cache.
+ */
+static void work_around_broken_dhclient(struct virtio_net_hdr *hdr,
+                                        uint8_t *buf, size_t size)
+{
+    if ((hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) && /* missing csum */
+        (size > 27 && size < 1500) && /* normal sized MTU */
+        (buf[12] == 0x08 && buf[13] == 0x00) && /* ethertype == IPv4 */
+        (buf[23] == 17) && /* ip.protocol == UDP */
+        (buf[34] == 0 && buf[35] == 67)) { /* udp.srcport == bootps */
+        net_checksum_calculate(buf, size);
+        hdr->flags &= ~VIRTIO_NET_HDR_F_NEEDS_CSUM;
+    }
+}
+
+static void receive_header(VirtIONet *n, const struct iovec *iov, int iov_cnt,
+                           const void *buf, size_t size)
+{
+    if (n->has_vnet_hdr) {
+        /* FIXME this cast is evil */
+        void *wbuf = (void *)buf;
+        work_around_broken_dhclient(wbuf, wbuf + n->host_hdr_len,
+                                    size - n->host_hdr_len);
+        iov_from_buf(iov, iov_cnt, 0, buf, sizeof(struct virtio_net_hdr));
+    } else {
+        struct virtio_net_hdr hdr = {
+            .flags = 0,
+            .gso_type = VIRTIO_NET_HDR_GSO_NONE
+        };
+        iov_from_buf(iov, iov_cnt, 0, &hdr, sizeof hdr);
+    }
+}
+
+static int receive_filter(VirtIONet *n, const uint8_t *buf, int size)
+{
+    static const uint8_t bcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+    static const uint8_t vlan[] = {0x81, 0x00};
+    uint8_t *ptr = (uint8_t *)buf;
+    int i;
+
+    if (n->promisc)
+        return 1;
+
+    ptr += n->host_hdr_len;
+
+    if (!memcmp(&ptr[12], vlan, sizeof(vlan))) {
+        int vid = be16_to_cpup((uint16_t *)(ptr + 14)) & 0xfff;
+        if (!(n->vlans[vid >> 5] & (1U << (vid & 0x1f))))
+            return 0;
+    }
+
+    if (ptr[0] & 1) { // multicast
+        if (!memcmp(ptr, bcast, sizeof(bcast))) {
+            return !n->nobcast;
+        } else if (n->nomulti) {
+            return 0;
+        } else if (n->allmulti || n->mac_table.multi_overflow) {
+            return 1;
+        }
+
+        for (i = n->mac_table.first_multi; i < n->mac_table.in_use; i++) {
+            if (!memcmp(ptr, &n->mac_table.macs[i * ETH_ALEN], ETH_ALEN)) {
+                return 1;
+            }
+        }
+    } else { // unicast
+        if (n->nouni) {
+            return 0;
+        } else if (n->alluni || n->mac_table.uni_overflow) {
+            return 1;
+        } else if (!memcmp(ptr, n->mac, ETH_ALEN)) {
+            return 1;
+        }
+
+        for (i = 0; i < n->mac_table.first_multi; i++) {
+            if (!memcmp(ptr, &n->mac_table.macs[i * ETH_ALEN], ETH_ALEN)) {
+                return 1;
+            }
+        }
+    }
+
+    return 0;
+}
+
+static ssize_t virtio_net_receive(NetClientState *nc, const uint8_t *buf, size_t size)
+{
+    VirtIONet *n = qemu_get_nic_opaque(nc);
+    VirtIONetQueue *q = virtio_net_get_subqueue(nc);
+    struct iovec mhdr_sg[VIRTQUEUE_MAX_SIZE];
+    struct virtio_net_hdr_mrg_rxbuf mhdr;
+    unsigned mhdr_cnt = 0;
+    size_t offset, i, guest_offset;
+
+    if (!virtio_net_can_receive(nc)) {
+        return -1;
+    }
+
+    /* hdr_len refers to the header we supply to the guest */
+    if (!virtio_net_has_buffers(q, size + n->guest_hdr_len - n->host_hdr_len)) {
+        return 0;
+    }
+
+    if (!receive_filter(n, buf, size))
+        return size;
+
+    offset = i = 0;
+
+    while (offset < size) {
+        VirtQueueElement elem;
+        int len, total;
+        const struct iovec *sg = elem.in_sg;
+
+        total = 0;
+
+        if (virtqueue_pop(q->rx_vq, &elem) == 0) {
+            if (i == 0)
+                return -1;
+            error_report("virtio-net unexpected empty queue: "
+                    "i %zd mergeable %d offset %zd, size %zd, "
+                    "guest hdr len %zd, host hdr len %zd guest features 0x%x",
+                    i, n->mergeable_rx_bufs, offset, size,
+                    n->guest_hdr_len, n->host_hdr_len, n->vdev.guest_features);
+            exit(1);
+        }
+
+        if (elem.in_num < 1) {
+            error_report("virtio-net receive queue contains no in buffers");
+            exit(1);
+        }
+
+        if (i == 0) {
+            assert(offset == 0);
+            if (n->mergeable_rx_bufs) {
+                mhdr_cnt = iov_copy(mhdr_sg, ARRAY_SIZE(mhdr_sg),
+                                    sg, elem.in_num,
+                                    offsetof(typeof(mhdr), num_buffers),
+                                    sizeof(mhdr.num_buffers));
+            }
+
+            receive_header(n, sg, elem.in_num, buf, size);
+            offset = n->host_hdr_len;
+            total += n->guest_hdr_len;
+            guest_offset = n->guest_hdr_len;
+        } else {
+            guest_offset = 0;
+        }
+
+        /* copy in packet.  ugh */
+        len = iov_from_buf(sg, elem.in_num, guest_offset,
+                           buf + offset, size - offset);
+        total += len;
+        offset += len;
+        /* If buffers can't be merged, at this point we
+         * must have consumed the complete packet.
+         * Otherwise, drop it. */
+        if (!n->mergeable_rx_bufs && offset < size) {
+#if 0
+            error_report("virtio-net truncated non-mergeable packet: "
+                         "i %zd mergeable %d offset %zd, size %zd, "
+                         "guest hdr len %zd, host hdr len %zd",
+                         i, n->mergeable_rx_bufs,
+                         offset, size, n->guest_hdr_len, n->host_hdr_len);
+#endif
+            return size;
+        }
+
+        /* signal other side */
+        virtqueue_fill(q->rx_vq, &elem, total, i++);
+    }
+
+    if (mhdr_cnt) {
+        stw_p(&mhdr.num_buffers, i);
+        iov_from_buf(mhdr_sg, mhdr_cnt,
+                     0,
+                     &mhdr.num_buffers, sizeof mhdr.num_buffers);
+    }
+
+    virtqueue_flush(q->rx_vq, i);
+    virtio_notify(&n->vdev, q->rx_vq);
+
+    return size;
+}
+
+static int32_t virtio_net_flush_tx(VirtIONetQueue *q);
+
+static void virtio_net_tx_complete(NetClientState *nc, ssize_t len)
+{
+    VirtIONet *n = qemu_get_nic_opaque(nc);
+    VirtIONetQueue *q = virtio_net_get_subqueue(nc);
+
+    virtqueue_push(q->tx_vq, &q->async_tx.elem, 0);
+    virtio_notify(&n->vdev, q->tx_vq);
+
+    q->async_tx.elem.out_num = q->async_tx.len = 0;
+
+    virtio_queue_set_notification(q->tx_vq, 1);
+    virtio_net_flush_tx(q);
+}
+
+/* TX */
+static int32_t virtio_net_flush_tx(VirtIONetQueue *q)
+{
+    VirtIONet *n = q->n;
+    VirtQueueElement elem;
+    int32_t num_packets = 0;
+    int queue_index = vq2q(virtio_get_queue_index(q->tx_vq));
+    if (!(n->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK)) {
+        return num_packets;
+    }
+
+    assert(n->vdev.vm_running);
+
+    if (q->async_tx.elem.out_num) {
+        virtio_queue_set_notification(q->tx_vq, 0);
+        return num_packets;
+    }
+
+    while (virtqueue_pop(q->tx_vq, &elem)) {
+        ssize_t ret, len;
+        unsigned int out_num = elem.out_num;
+        struct iovec *out_sg = &elem.out_sg[0];
+        struct iovec sg[VIRTQUEUE_MAX_SIZE];
+
+        if (out_num < 1) {
+            error_report("virtio-net header not in first element");
+            exit(1);
+        }
+
+        /*
+         * If host wants to see the guest header as is, we can
+         * pass it on unchanged. Otherwise, copy just the parts
+         * that host is interested in.
+         */
+        assert(n->host_hdr_len <= n->guest_hdr_len);
+        if (n->host_hdr_len != n->guest_hdr_len) {
+            unsigned sg_num = iov_copy(sg, ARRAY_SIZE(sg),
+                                       out_sg, out_num,
+                                       0, n->host_hdr_len);
+            sg_num += iov_copy(sg + sg_num, ARRAY_SIZE(sg) - sg_num,
+                             out_sg, out_num,
+                             n->guest_hdr_len, -1);
+            out_num = sg_num;
+            out_sg = sg;
+        }
+
+        len = n->guest_hdr_len;
+
+        ret = qemu_sendv_packet_async(qemu_get_subqueue(n->nic, queue_index),
+                                      out_sg, out_num, virtio_net_tx_complete);
+        if (ret == 0) {
+            virtio_queue_set_notification(q->tx_vq, 0);
+            q->async_tx.elem = elem;
+            q->async_tx.len  = len;
+            return -EBUSY;
+        }
+
+        len += ret;
+
+        virtqueue_push(q->tx_vq, &elem, 0);
+        virtio_notify(&n->vdev, q->tx_vq);
+
+        if (++num_packets >= n->tx_burst) {
+            break;
+        }
+    }
+    return num_packets;
+}
+
+static void virtio_net_handle_tx_timer(VirtIODevice *vdev, VirtQueue *vq)
+{
+    VirtIONet *n = to_virtio_net(vdev);
+    VirtIONetQueue *q = &n->vqs[vq2q(virtio_get_queue_index(vq))];
+
+    /* This happens when device was stopped but VCPU wasn't. */
+    if (!n->vdev.vm_running) {
+        q->tx_waiting = 1;
+        return;
+    }
+
+    if (q->tx_waiting) {
+        virtio_queue_set_notification(vq, 1);
+        qemu_del_timer(q->tx_timer);
+        q->tx_waiting = 0;
+        virtio_net_flush_tx(q);
+    } else {
+        qemu_mod_timer(q->tx_timer,
+                       qemu_get_clock_ns(vm_clock) + n->tx_timeout);
+        q->tx_waiting = 1;
+        virtio_queue_set_notification(vq, 0);
+    }
+}
+
+static void virtio_net_handle_tx_bh(VirtIODevice *vdev, VirtQueue *vq)
+{
+    VirtIONet *n = to_virtio_net(vdev);
+    VirtIONetQueue *q = &n->vqs[vq2q(virtio_get_queue_index(vq))];
+
+    if (unlikely(q->tx_waiting)) {
+        return;
+    }
+    q->tx_waiting = 1;
+    /* This happens when device was stopped but VCPU wasn't. */
+    if (!n->vdev.vm_running) {
+        return;
+    }
+    virtio_queue_set_notification(vq, 0);
+    qemu_bh_schedule(q->tx_bh);
+}
+
+static void virtio_net_tx_timer(void *opaque)
+{
+    VirtIONetQueue *q = opaque;
+    VirtIONet *n = q->n;
+    assert(n->vdev.vm_running);
+
+    q->tx_waiting = 0;
+
+    /* Just in case the driver is not ready on more */
+    if (!(n->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK))
+        return;
+
+    virtio_queue_set_notification(q->tx_vq, 1);
+    virtio_net_flush_tx(q);
+}
+
+static void virtio_net_tx_bh(void *opaque)
+{
+    VirtIONetQueue *q = opaque;
+    VirtIONet *n = q->n;
+    int32_t ret;
+
+    assert(n->vdev.vm_running);
+
+    q->tx_waiting = 0;
+
+    /* Just in case the driver is not ready on more */
+    if (unlikely(!(n->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK)))
+        return;
+
+    ret = virtio_net_flush_tx(q);
+    if (ret == -EBUSY) {
+        return; /* Notification re-enable handled by tx_complete */
+    }
+
+    /* If we flush a full burst of packets, assume there are
+     * more coming and immediately reschedule */
+    if (ret >= n->tx_burst) {
+        qemu_bh_schedule(q->tx_bh);
+        q->tx_waiting = 1;
+        return;
+    }
+
+    /* If less than a full burst, re-enable notification and flush
+     * anything that may have come in while we weren't looking.  If
+     * we find something, assume the guest is still active and reschedule */
+    virtio_queue_set_notification(q->tx_vq, 1);
+    if (virtio_net_flush_tx(q) > 0) {
+        virtio_queue_set_notification(q->tx_vq, 0);
+        qemu_bh_schedule(q->tx_bh);
+        q->tx_waiting = 1;
+    }
+}
+
+static void virtio_net_set_multiqueue(VirtIONet *n, int multiqueue, int ctrl)
+{
+    VirtIODevice *vdev = &n->vdev;
+    int i, max = multiqueue ? n->max_queues : 1;
+
+    n->multiqueue = multiqueue;
+
+    for (i = 2; i <= n->max_queues * 2 + 1; i++) {
+        virtio_del_queue(vdev, i);
+    }
+
+    for (i = 1; i < max; i++) {
+        n->vqs[i].rx_vq = virtio_add_queue(vdev, 256, virtio_net_handle_rx);
+        if (n->vqs[i].tx_timer) {
+            n->vqs[i].tx_vq =
+                virtio_add_queue(vdev, 256, virtio_net_handle_tx_timer);
+            n->vqs[i].tx_timer = qemu_new_timer_ns(vm_clock,
+                                                   virtio_net_tx_timer,
+                                                   &n->vqs[i]);
+        } else {
+            n->vqs[i].tx_vq =
+                virtio_add_queue(vdev, 256, virtio_net_handle_tx_bh);
+            n->vqs[i].tx_bh = qemu_bh_new(virtio_net_tx_bh, &n->vqs[i]);
+        }
+
+        n->vqs[i].tx_waiting = 0;
+        n->vqs[i].n = n;
+    }
+
+    if (ctrl) {
+        n->ctrl_vq = virtio_add_queue(vdev, 64, virtio_net_handle_ctrl);
+    }
+
+    virtio_net_set_queues(n);
+}
+
+static void virtio_net_save(QEMUFile *f, void *opaque)
+{
+    int i;
+    VirtIONet *n = opaque;
+
+    /* At this point, backend must be stopped, otherwise
+     * it might keep writing to memory. */
+    assert(!n->vhost_started);
+    virtio_save(&n->vdev, f);
+
+    qemu_put_buffer(f, n->mac, ETH_ALEN);
+    qemu_put_be32(f, n->vqs[0].tx_waiting);
+    qemu_put_be32(f, n->mergeable_rx_bufs);
+    qemu_put_be16(f, n->status);
+    qemu_put_byte(f, n->promisc);
+    qemu_put_byte(f, n->allmulti);
+    qemu_put_be32(f, n->mac_table.in_use);
+    qemu_put_buffer(f, n->mac_table.macs, n->mac_table.in_use * ETH_ALEN);
+    qemu_put_buffer(f, (uint8_t *)n->vlans, MAX_VLAN >> 3);
+    qemu_put_be32(f, n->has_vnet_hdr);
+    qemu_put_byte(f, n->mac_table.multi_overflow);
+    qemu_put_byte(f, n->mac_table.uni_overflow);
+    qemu_put_byte(f, n->alluni);
+    qemu_put_byte(f, n->nomulti);
+    qemu_put_byte(f, n->nouni);
+    qemu_put_byte(f, n->nobcast);
+    qemu_put_byte(f, n->has_ufo);
+    if (n->max_queues > 1) {
+        qemu_put_be16(f, n->max_queues);
+        qemu_put_be16(f, n->curr_queues);
+        for (i = 1; i < n->curr_queues; i++) {
+            qemu_put_be32(f, n->vqs[i].tx_waiting);
+        }
+    }
+}
+
+static int virtio_net_load(QEMUFile *f, void *opaque, int version_id)
+{
+    VirtIONet *n = opaque;
+    int ret, i, link_down;
+
+    if (version_id < 2 || version_id > VIRTIO_NET_VM_VERSION)
+        return -EINVAL;
+
+    ret = virtio_load(&n->vdev, f);
+    if (ret) {
+        return ret;
+    }
+
+    qemu_get_buffer(f, n->mac, ETH_ALEN);
+    n->vqs[0].tx_waiting = qemu_get_be32(f);
+
+    virtio_net_set_mrg_rx_bufs(n, qemu_get_be32(f));
+
+    if (version_id >= 3)
+        n->status = qemu_get_be16(f);
+
+    if (version_id >= 4) {
+        if (version_id < 8) {
+            n->promisc = qemu_get_be32(f);
+            n->allmulti = qemu_get_be32(f);
+        } else {
+            n->promisc = qemu_get_byte(f);
+            n->allmulti = qemu_get_byte(f);
+        }
+    }
+
+    if (version_id >= 5) {
+        n->mac_table.in_use = qemu_get_be32(f);
+        /* MAC_TABLE_ENTRIES may be different from the saved image */
+        if (n->mac_table.in_use <= MAC_TABLE_ENTRIES) {
+            qemu_get_buffer(f, n->mac_table.macs,
+                            n->mac_table.in_use * ETH_ALEN);
+        } else if (n->mac_table.in_use) {
+            uint8_t *buf = g_malloc0(n->mac_table.in_use);
+            qemu_get_buffer(f, buf, n->mac_table.in_use * ETH_ALEN);
+            g_free(buf);
+            n->mac_table.multi_overflow = n->mac_table.uni_overflow = 1;
+            n->mac_table.in_use = 0;
+        }
+    }
+    if (version_id >= 6)
+        qemu_get_buffer(f, (uint8_t *)n->vlans, MAX_VLAN >> 3);
+
+    if (version_id >= 7) {
+        if (qemu_get_be32(f) && !peer_has_vnet_hdr(n)) {
+            error_report("virtio-net: saved image requires vnet_hdr=on");
+            return -1;
+        }
+
+        if (n->has_vnet_hdr) {
+            tap_set_offload(qemu_get_queue(n->nic)->peer,
+                    (n->vdev.guest_features >> VIRTIO_NET_F_GUEST_CSUM) & 1,
+                    (n->vdev.guest_features >> VIRTIO_NET_F_GUEST_TSO4) & 1,
+                    (n->vdev.guest_features >> VIRTIO_NET_F_GUEST_TSO6) & 1,
+                    (n->vdev.guest_features >> VIRTIO_NET_F_GUEST_ECN)  & 1,
+                    (n->vdev.guest_features >> VIRTIO_NET_F_GUEST_UFO)  & 1);
+        }
+    }
+
+    if (version_id >= 9) {
+        n->mac_table.multi_overflow = qemu_get_byte(f);
+        n->mac_table.uni_overflow = qemu_get_byte(f);
+    }
+
+    if (version_id >= 10) {
+        n->alluni = qemu_get_byte(f);
+        n->nomulti = qemu_get_byte(f);
+        n->nouni = qemu_get_byte(f);
+        n->nobcast = qemu_get_byte(f);
+    }
+
+    if (version_id >= 11) {
+        if (qemu_get_byte(f) && !peer_has_ufo(n)) {
+            error_report("virtio-net: saved image requires TUN_F_UFO support");
+            return -1;
+        }
+    }
+
+    if (n->max_queues > 1) {
+        if (n->max_queues != qemu_get_be16(f)) {
+            error_report("virtio-net: different max_queues ");
+            return -1;
+        }
+
+        n->curr_queues = qemu_get_be16(f);
+        for (i = 1; i < n->curr_queues; i++) {
+            n->vqs[i].tx_waiting = qemu_get_be32(f);
+        }
+    }
+
+    virtio_net_set_queues(n);
+
+    /* Find the first multicast entry in the saved MAC filter */
+    for (i = 0; i < n->mac_table.in_use; i++) {
+        if (n->mac_table.macs[i * ETH_ALEN] & 1) {
+            break;
+        }
+    }
+    n->mac_table.first_multi = i;
+
+    /* nc.link_down can't be migrated, so infer link_down according
+     * to link status bit in n->status */
+    link_down = (n->status & VIRTIO_NET_S_LINK_UP) == 0;
+    for (i = 0; i < n->max_queues; i++) {
+        qemu_get_subqueue(n->nic, i)->link_down = link_down;
+    }
+
+    return 0;
+}
+
+static void virtio_net_cleanup(NetClientState *nc)
+{
+    VirtIONet *n = qemu_get_nic_opaque(nc);
+
+    n->nic = NULL;
+}
+
+static NetClientInfo net_virtio_info = {
+    .type = NET_CLIENT_OPTIONS_KIND_NIC,
+    .size = sizeof(NICState),
+    .can_receive = virtio_net_can_receive,
+    .receive = virtio_net_receive,
+        .cleanup = virtio_net_cleanup,
+    .link_status_changed = virtio_net_set_link_status,
+};
+
+static bool virtio_net_guest_notifier_pending(VirtIODevice *vdev, int idx)
+{
+    VirtIONet *n = to_virtio_net(vdev);
+    NetClientState *nc = qemu_get_subqueue(n->nic, vq2q(idx));
+    assert(n->vhost_started);
+    return vhost_net_virtqueue_pending(tap_get_vhost_net(nc->peer), idx);
+}
+
+static void virtio_net_guest_notifier_mask(VirtIODevice *vdev, int idx,
+                                           bool mask)
+{
+    VirtIONet *n = to_virtio_net(vdev);
+    NetClientState *nc = qemu_get_subqueue(n->nic, vq2q(idx));
+    assert(n->vhost_started);
+    vhost_net_virtqueue_mask(tap_get_vhost_net(nc->peer),
+                             vdev, idx, mask);
+}
+
+VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf,
+                              virtio_net_conf *net, uint32_t host_features)
+{
+    VirtIONet *n;
+    int i, config_size = 0;
+
+    for (i = 0; feature_sizes[i].flags != 0; i++) {
+        if (host_features & feature_sizes[i].flags) {
+            config_size = MAX(feature_sizes[i].end, config_size);
+        }
+    }
+
+    n = (VirtIONet *)virtio_common_init("virtio-net", VIRTIO_ID_NET,
+                                        config_size, sizeof(VirtIONet));
+
+    n->config_size = config_size;
+    n->vdev.get_config = virtio_net_get_config;
+    n->vdev.set_config = virtio_net_set_config;
+    n->vdev.get_features = virtio_net_get_features;
+    n->vdev.set_features = virtio_net_set_features;
+    n->vdev.bad_features = virtio_net_bad_features;
+    n->vdev.reset = virtio_net_reset;
+    n->vdev.set_status = virtio_net_set_status;
+    n->vdev.guest_notifier_mask = virtio_net_guest_notifier_mask;
+    n->vdev.guest_notifier_pending = virtio_net_guest_notifier_pending;
+    n->max_queues = MAX(conf->queues, 1);
+    n->vqs = g_malloc0(sizeof(VirtIONetQueue) * n->max_queues);
+    n->vqs[0].rx_vq = virtio_add_queue(&n->vdev, 256, virtio_net_handle_rx);
+    n->curr_queues = 1;
+    n->vqs[0].n = n;
+    n->tx_timeout = net->txtimer;
+
+    if (net->tx && strcmp(net->tx, "timer") && strcmp(net->tx, "bh")) {
+        error_report("virtio-net: "
+                     "Unknown option tx=%s, valid options: \"timer\" \"bh\"",
+                     net->tx);
+        error_report("Defaulting to \"bh\"");
+    }
+
+    if (net->tx && !strcmp(net->tx, "timer")) {
+        n->vqs[0].tx_vq = virtio_add_queue(&n->vdev, 256,
+                                           virtio_net_handle_tx_timer);
+        n->vqs[0].tx_timer = qemu_new_timer_ns(vm_clock, virtio_net_tx_timer,
+                                               &n->vqs[0]);
+    } else {
+        n->vqs[0].tx_vq = virtio_add_queue(&n->vdev, 256,
+                                           virtio_net_handle_tx_bh);
+        n->vqs[0].tx_bh = qemu_bh_new(virtio_net_tx_bh, &n->vqs[0]);
+    }
+    n->ctrl_vq = virtio_add_queue(&n->vdev, 64, virtio_net_handle_ctrl);
+    qemu_macaddr_default_if_unset(&conf->macaddr);
+    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, object_get_typename(OBJECT(dev)), dev->id, n);
+    peer_test_vnet_hdr(n);
+    if (peer_has_vnet_hdr(n)) {
+        for (i = 0; i < n->max_queues; i++) {
+            tap_using_vnet_hdr(qemu_get_subqueue(n->nic, i)->peer, true);
+        }
+        n->host_hdr_len = sizeof(struct virtio_net_hdr);
+    } else {
+        n->host_hdr_len = 0;
+    }
+
+    qemu_format_nic_info_str(qemu_get_queue(n->nic), conf->macaddr.a);
+
+    n->vqs[0].tx_waiting = 0;
+    n->tx_burst = net->txburst;
+    virtio_net_set_mrg_rx_bufs(n, 0);
+    n->promisc = 1; /* for compatibility */
+
+    n->mac_table.macs = g_malloc0(MAC_TABLE_ENTRIES * ETH_ALEN);
+
+    n->vlans = g_malloc0(MAX_VLAN >> 3);
+
+    n->qdev = dev;
+    register_savevm(dev, "virtio-net", -1, VIRTIO_NET_VM_VERSION,
+                    virtio_net_save, virtio_net_load, n);
+
+    add_boot_device_path(conf->bootindex, dev, "/ethernet-phy@0");
+
+    return &n->vdev;
+}
+
+void virtio_net_exit(VirtIODevice *vdev)
+{
+    VirtIONet *n = DO_UPCAST(VirtIONet, vdev, vdev);
+    int i;
+
+    /* This will stop vhost backend if appropriate. */
+    virtio_net_set_status(vdev, 0);
+
+    unregister_savevm(n->qdev, "virtio-net", n);
+
+    g_free(n->mac_table.macs);
+    g_free(n->vlans);
+
+    for (i = 0; i < n->max_queues; i++) {
+        VirtIONetQueue *q = &n->vqs[i];
+        NetClientState *nc = qemu_get_subqueue(n->nic, i);
+
+        qemu_purge_queued_packets(nc);
+
+        if (q->tx_timer) {
+            qemu_del_timer(q->tx_timer);
+            qemu_free_timer(q->tx_timer);
+        } else {
+            qemu_bh_delete(q->tx_bh);
+        }
+    }
+
+    g_free(n->vqs);
+    qemu_del_nic(n->nic);
+    virtio_cleanup(&n->vdev);
+}
diff --git a/hw/net/vmware_utils.h b/hw/net/vmware_utils.h
new file mode 100644 (file)
index 0000000..5307e2c
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * QEMU VMWARE paravirtual devices - auxiliary code
+ *
+ * Copyright (c) 2012 Ravello Systems LTD (http://ravellosystems.com)
+ *
+ * Developed by Daynix Computing LTD (http://www.daynix.com)
+ *
+ * Authors:
+ * Dmitry Fleytman <dmitry@daynix.com>
+ * Yan Vugenfirer <yan@daynix.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 VMWARE_UTILS_H
+#define VMWARE_UTILS_H
+
+#include "qemu/range.h"
+
+#ifndef VMW_SHPRN
+#define VMW_SHPRN(fmt, ...) do {} while (0)
+#endif
+
+/*
+ * Shared memory access functions with byte swap support
+ * Each function contains printout for reverse-engineering needs
+ *
+ */
+static inline void
+vmw_shmem_read(hwaddr addr, void *buf, int len)
+{
+    VMW_SHPRN("SHMEM r: %" PRIx64 ", len: %d to %p", addr, len, buf);
+    cpu_physical_memory_read(addr, buf, len);
+}
+
+static inline void
+vmw_shmem_write(hwaddr addr, void *buf, int len)
+{
+    VMW_SHPRN("SHMEM w: %" PRIx64 ", len: %d to %p", addr, len, buf);
+    cpu_physical_memory_write(addr, buf, len);
+}
+
+static inline void
+vmw_shmem_rw(hwaddr addr, void *buf, int len, int is_write)
+{
+    VMW_SHPRN("SHMEM r/w: %" PRIx64 ", len: %d (to %p), is write: %d",
+              addr, len, buf, is_write);
+
+    cpu_physical_memory_rw(addr, buf, len, is_write);
+}
+
+static inline void
+vmw_shmem_set(hwaddr addr, uint8 val, int len)
+{
+    int i;
+    VMW_SHPRN("SHMEM set: %" PRIx64 ", len: %d (value 0x%X)", addr, len, val);
+
+    for (i = 0; i < len; i++) {
+        cpu_physical_memory_write(addr + i, &val, 1);
+    }
+}
+
+static inline uint32_t
+vmw_shmem_ld8(hwaddr addr)
+{
+    uint8_t res = ldub_phys(addr);
+    VMW_SHPRN("SHMEM load8: %" PRIx64 " (value 0x%X)", addr, res);
+    return res;
+}
+
+static inline void
+vmw_shmem_st8(hwaddr addr, uint8_t value)
+{
+    VMW_SHPRN("SHMEM store8: %" PRIx64 " (value 0x%X)", addr, value);
+    stb_phys(addr, value);
+}
+
+static inline uint32_t
+vmw_shmem_ld16(hwaddr addr)
+{
+    uint16_t res = lduw_le_phys(addr);
+    VMW_SHPRN("SHMEM load16: %" PRIx64 " (value 0x%X)", addr, res);
+    return res;
+}
+
+static inline void
+vmw_shmem_st16(hwaddr addr, uint16_t value)
+{
+    VMW_SHPRN("SHMEM store16: %" PRIx64 " (value 0x%X)", addr, value);
+    stw_le_phys(addr, value);
+}
+
+static inline uint32_t
+vmw_shmem_ld32(hwaddr addr)
+{
+    uint32_t res = ldl_le_phys(addr);
+    VMW_SHPRN("SHMEM load32: %" PRIx64 " (value 0x%X)", addr, res);
+    return res;
+}
+
+static inline void
+vmw_shmem_st32(hwaddr addr, uint32_t value)
+{
+    VMW_SHPRN("SHMEM store32: %" PRIx64 " (value 0x%X)", addr, value);
+    stl_le_phys(addr, value);
+}
+
+static inline uint64_t
+vmw_shmem_ld64(hwaddr addr)
+{
+    uint64_t res = ldq_le_phys(addr);
+    VMW_SHPRN("SHMEM load64: %" PRIx64 " (value %" PRIx64 ")", addr, res);
+    return res;
+}
+
+static inline void
+vmw_shmem_st64(hwaddr addr, uint64_t value)
+{
+    VMW_SHPRN("SHMEM store64: %" PRIx64 " (value %" PRIx64 ")", addr, value);
+    stq_le_phys(addr, value);
+}
+
+/* Macros for simplification of operations on array-style registers */
+
+/*
+ * Whether <addr> lies inside of array-style register defined by <base>,
+ * number of elements (<cnt>) and element size (<regsize>)
+ *
+*/
+#define VMW_IS_MULTIREG_ADDR(addr, base, cnt, regsize)                 \
+    range_covers_byte(base, cnt * regsize, addr)
+
+/*
+ * Returns index of given register (<addr>) in array-style register defined by
+ * <base> and element size (<regsize>)
+ *
+*/
+#define VMW_MULTIREG_IDX_BY_ADDR(addr, base, regsize)                  \
+    (((addr) - (base)) / (regsize))
+
+#endif
diff --git a/hw/net/vmxnet3.c b/hw/net/vmxnet3.c
new file mode 100644 (file)
index 0000000..5f483e7
--- /dev/null
@@ -0,0 +1,2471 @@
+/*
+ * QEMU VMWARE VMXNET3 paravirtual NIC
+ *
+ * Copyright (c) 2012 Ravello Systems LTD (http://ravellosystems.com)
+ *
+ * Developed by Daynix Computing LTD (http://www.daynix.com)
+ *
+ * Authors:
+ * Dmitry Fleytman <dmitry@daynix.com>
+ * Tamir Shomer <tamirs@daynix.com>
+ * Yan Vugenfirer <yan@daynix.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/hw.h"
+#include "hw/pci/pci.h"
+#include "net/net.h"
+#include "net/tap.h"
+#include "net/checksum.h"
+#include "sysemu/sysemu.h"
+#include "qemu-common.h"
+#include "qemu/bswap.h"
+#include "hw/pci/msix.h"
+#include "hw/pci/msi.h"
+
+#include "vmxnet3.h"
+#include "vmxnet_debug.h"
+#include "vmware_utils.h"
+#include "vmxnet_tx_pkt.h"
+#include "vmxnet_rx_pkt.h"
+
+#define PCI_DEVICE_ID_VMWARE_VMXNET3_REVISION 0x1
+#define VMXNET3_MSIX_BAR_SIZE 0x2000
+
+#define VMXNET3_BAR0_IDX      (0)
+#define VMXNET3_BAR1_IDX      (1)
+#define VMXNET3_MSIX_BAR_IDX  (2)
+
+#define VMXNET3_OFF_MSIX_TABLE (0x000)
+#define VMXNET3_OFF_MSIX_PBA   (0x800)
+
+/* Link speed in Mbps should be shifted by 16 */
+#define VMXNET3_LINK_SPEED      (1000 << 16)
+
+/* Link status: 1 - up, 0 - down. */
+#define VMXNET3_LINK_STATUS_UP  0x1
+
+/* Least significant bit should be set for revision and version */
+#define VMXNET3_DEVICE_VERSION    0x1
+#define VMXNET3_DEVICE_REVISION   0x1
+
+/* Macros for rings descriptors access */
+#define VMXNET3_READ_TX_QUEUE_DESCR8(dpa, field) \
+    (vmw_shmem_ld8(dpa + offsetof(struct Vmxnet3_TxQueueDesc, field)))
+
+#define VMXNET3_WRITE_TX_QUEUE_DESCR8(dpa, field, value) \
+    (vmw_shmem_st8(dpa + offsetof(struct Vmxnet3_TxQueueDesc, field, value)))
+
+#define VMXNET3_READ_TX_QUEUE_DESCR32(dpa, field) \
+    (vmw_shmem_ld32(dpa + offsetof(struct Vmxnet3_TxQueueDesc, field)))
+
+#define VMXNET3_WRITE_TX_QUEUE_DESCR32(dpa, field, value) \
+    (vmw_shmem_st32(dpa + offsetof(struct Vmxnet3_TxQueueDesc, field), value))
+
+#define VMXNET3_READ_TX_QUEUE_DESCR64(dpa, field) \
+    (vmw_shmem_ld64(dpa + offsetof(struct Vmxnet3_TxQueueDesc, field)))
+
+#define VMXNET3_WRITE_TX_QUEUE_DESCR64(dpa, field, value) \
+    (vmw_shmem_st64(dpa + offsetof(struct Vmxnet3_TxQueueDesc, field), value))
+
+#define VMXNET3_READ_RX_QUEUE_DESCR64(dpa, field) \
+    (vmw_shmem_ld64(dpa + offsetof(struct Vmxnet3_RxQueueDesc, field)))
+
+#define VMXNET3_READ_RX_QUEUE_DESCR32(dpa, field) \
+    (vmw_shmem_ld32(dpa + offsetof(struct Vmxnet3_RxQueueDesc, field)))
+
+#define VMXNET3_WRITE_RX_QUEUE_DESCR64(dpa, field, value) \
+    (vmw_shmem_st64(dpa + offsetof(struct Vmxnet3_RxQueueDesc, field), value))
+
+#define VMXNET3_WRITE_RX_QUEUE_DESCR8(dpa, field, value) \
+    (vmw_shmem_st8(dpa + offsetof(struct Vmxnet3_RxQueueDesc, field), value))
+
+/* Macros for guest driver shared area access */
+#define VMXNET3_READ_DRV_SHARED64(shpa, field) \
+    (vmw_shmem_ld64(shpa + offsetof(struct Vmxnet3_DriverShared, field)))
+
+#define VMXNET3_READ_DRV_SHARED32(shpa, field) \
+    (vmw_shmem_ld32(shpa + offsetof(struct Vmxnet3_DriverShared, field)))
+
+#define VMXNET3_WRITE_DRV_SHARED32(shpa, field, val) \
+    (vmw_shmem_st32(shpa + offsetof(struct Vmxnet3_DriverShared, field), val))
+
+#define VMXNET3_READ_DRV_SHARED16(shpa, field) \
+    (vmw_shmem_ld16(shpa + offsetof(struct Vmxnet3_DriverShared, field)))
+
+#define VMXNET3_READ_DRV_SHARED8(shpa, field) \
+    (vmw_shmem_ld8(shpa + offsetof(struct Vmxnet3_DriverShared, field)))
+
+#define VMXNET3_READ_DRV_SHARED(shpa, field, b, l) \
+    (vmw_shmem_read(shpa + offsetof(struct Vmxnet3_DriverShared, field), b, l))
+
+#define VMXNET_FLAG_IS_SET(field, flag) (((field) & (flag)) == (flag))
+
+#define TYPE_VMXNET3 "vmxnet3"
+#define VMXNET3(obj) OBJECT_CHECK(VMXNET3State, (obj), TYPE_VMXNET3)
+
+/* Cyclic ring abstraction */
+typedef struct {
+    hwaddr pa;
+    size_t size;
+    size_t cell_size;
+    size_t next;
+    uint8_t gen;
+} Vmxnet3Ring;
+
+static inline void vmxnet3_ring_init(Vmxnet3Ring *ring,
+                                     hwaddr pa,
+                                     size_t size,
+                                     size_t cell_size,
+                                     bool zero_region)
+{
+    ring->pa = pa;
+    ring->size = size;
+    ring->cell_size = cell_size;
+    ring->gen = VMXNET3_INIT_GEN;
+    ring->next = 0;
+
+    if (zero_region) {
+        vmw_shmem_set(pa, 0, size * cell_size);
+    }
+}
+
+#define VMXNET3_RING_DUMP(macro, ring_name, ridx, r)                         \
+    macro("%s#%d: base %" PRIx64 " size %lu cell_size %lu gen %d next %lu",  \
+          (ring_name), (ridx),                                               \
+          (r)->pa, (r)->size, (r)->cell_size, (r)->gen, (r)->next)
+
+static inline void vmxnet3_ring_inc(Vmxnet3Ring *ring)
+{
+    if (++ring->next >= ring->size) {
+        ring->next = 0;
+        ring->gen ^= 1;
+    }
+}
+
+static inline void vmxnet3_ring_dec(Vmxnet3Ring *ring)
+{
+    if (ring->next-- == 0) {
+        ring->next = ring->size - 1;
+        ring->gen ^= 1;
+    }
+}
+
+static inline hwaddr vmxnet3_ring_curr_cell_pa(Vmxnet3Ring *ring)
+{
+    return ring->pa + ring->next * ring->cell_size;
+}
+
+static inline void vmxnet3_ring_read_curr_cell(Vmxnet3Ring *ring, void *buff)
+{
+    vmw_shmem_read(vmxnet3_ring_curr_cell_pa(ring), buff, ring->cell_size);
+}
+
+static inline void vmxnet3_ring_write_curr_cell(Vmxnet3Ring *ring, void *buff)
+{
+    vmw_shmem_write(vmxnet3_ring_curr_cell_pa(ring), buff, ring->cell_size);
+}
+
+static inline size_t vmxnet3_ring_curr_cell_idx(Vmxnet3Ring *ring)
+{
+    return ring->next;
+}
+
+static inline uint8_t vmxnet3_ring_curr_gen(Vmxnet3Ring *ring)
+{
+    return ring->gen;
+}
+
+/* Debug trace-related functions */
+static inline void
+vmxnet3_dump_tx_descr(struct Vmxnet3_TxDesc *descr)
+{
+    VMW_PKPRN("TX DESCR: "
+              "addr %" PRIx64 ", len: %d, gen: %d, rsvd: %d, "
+              "dtype: %d, ext1: %d, msscof: %d, hlen: %d, om: %d, "
+              "eop: %d, cq: %d, ext2: %d, ti: %d, tci: %d",
+              le64_to_cpu(descr->addr), descr->len, descr->gen, descr->rsvd,
+              descr->dtype, descr->ext1, descr->msscof, descr->hlen, descr->om,
+              descr->eop, descr->cq, descr->ext2, descr->ti, descr->tci);
+}
+
+static inline void
+vmxnet3_dump_virt_hdr(struct virtio_net_hdr *vhdr)
+{
+    VMW_PKPRN("VHDR: flags 0x%x, gso_type: 0x%x, hdr_len: %d, gso_size: %d, "
+              "csum_start: %d, csum_offset: %d",
+              vhdr->flags, vhdr->gso_type, vhdr->hdr_len, vhdr->gso_size,
+              vhdr->csum_start, vhdr->csum_offset);
+}
+
+static inline void
+vmxnet3_dump_rx_descr(struct Vmxnet3_RxDesc *descr)
+{
+    VMW_PKPRN("RX DESCR: addr %" PRIx64 ", len: %d, gen: %d, rsvd: %d, "
+              "dtype: %d, ext1: %d, btype: %d",
+              le64_to_cpu(descr->addr), descr->len, descr->gen,
+              descr->rsvd, descr->dtype, descr->ext1, descr->btype);
+}
+
+/* Device state and helper functions */
+#define VMXNET3_RX_RINGS_PER_QUEUE (2)
+
+typedef struct {
+    Vmxnet3Ring tx_ring;
+    Vmxnet3Ring comp_ring;
+
+    uint8_t intr_idx;
+    hwaddr tx_stats_pa;
+    struct UPT1_TxStats txq_stats;
+} Vmxnet3TxqDescr;
+
+typedef struct {
+    Vmxnet3Ring rx_ring[VMXNET3_RX_RINGS_PER_QUEUE];
+    Vmxnet3Ring comp_ring;
+    uint8_t intr_idx;
+    hwaddr rx_stats_pa;
+    struct UPT1_RxStats rxq_stats;
+} Vmxnet3RxqDescr;
+
+typedef struct {
+    bool is_masked;
+    bool is_pending;
+    bool is_asserted;
+} Vmxnet3IntState;
+
+typedef struct {
+        PCIDevice parent_obj;
+        NICState *nic;
+        NICConf conf;
+        MemoryRegion bar0;
+        MemoryRegion bar1;
+        MemoryRegion msix_bar;
+
+        Vmxnet3RxqDescr rxq_descr[VMXNET3_DEVICE_MAX_RX_QUEUES];
+        Vmxnet3TxqDescr txq_descr[VMXNET3_DEVICE_MAX_TX_QUEUES];
+
+        /* Whether MSI-X support was installed successfully */
+        bool msix_used;
+        /* Whether MSI support was installed successfully */
+        bool msi_used;
+        hwaddr drv_shmem;
+        hwaddr temp_shared_guest_driver_memory;
+
+        uint8_t txq_num;
+
+        /* This boolean tells whether RX packet being indicated has to */
+        /* be split into head and body chunks from different RX rings  */
+        bool rx_packets_compound;
+
+        bool rx_vlan_stripping;
+        bool lro_supported;
+
+        uint8_t rxq_num;
+
+        /* Network MTU */
+        uint32_t mtu;
+
+        /* Maximum number of fragments for indicated TX packets */
+        uint32_t max_tx_frags;
+
+        /* Maximum number of fragments for indicated RX packets */
+        uint16_t max_rx_frags;
+
+        /* Index for events interrupt */
+        uint8_t event_int_idx;
+
+        /* Whether automatic interrupts masking enabled */
+        bool auto_int_masking;
+
+        bool peer_has_vhdr;
+
+        /* TX packets to QEMU interface */
+        struct VmxnetTxPkt *tx_pkt;
+        uint32_t offload_mode;
+        uint32_t cso_or_gso_size;
+        uint16_t tci;
+        bool needs_vlan;
+
+        struct VmxnetRxPkt *rx_pkt;
+
+        bool tx_sop;
+        bool skip_current_tx_pkt;
+
+        uint32_t device_active;
+        uint32_t last_command;
+
+        uint32_t link_status_and_speed;
+
+        Vmxnet3IntState interrupt_states[VMXNET3_MAX_INTRS];
+
+        uint32_t temp_mac;   /* To store the low part first */
+
+        MACAddr perm_mac;
+        uint32_t vlan_table[VMXNET3_VFT_SIZE];
+        uint32_t rx_mode;
+        MACAddr *mcast_list;
+        uint32_t mcast_list_len;
+        uint32_t mcast_list_buff_size; /* needed for live migration. */
+} VMXNET3State;
+
+/* Interrupt management */
+
+/*
+ *This function returns sign whether interrupt line is in asserted state
+ * This depends on the type of interrupt used. For INTX interrupt line will
+ * be asserted until explicit deassertion, for MSI(X) interrupt line will
+ * be deasserted automatically due to notification semantics of the MSI(X)
+ * interrupts
+ */
+static bool _vmxnet3_assert_interrupt_line(VMXNET3State *s, uint32_t int_idx)
+{
+    PCIDevice *d = PCI_DEVICE(s);
+
+    if (s->msix_used && msix_enabled(d)) {
+        VMW_IRPRN("Sending MSI-X notification for vector %u", int_idx);
+        msix_notify(d, int_idx);
+        return false;
+    }
+    if (s->msi_used && msi_enabled(d)) {
+        VMW_IRPRN("Sending MSI notification for vector %u", int_idx);
+        msi_notify(d, int_idx);
+        return false;
+    }
+
+    VMW_IRPRN("Asserting line for interrupt %u", int_idx);
+    qemu_set_irq(d->irq[int_idx], 1);
+    return true;
+}
+
+static void _vmxnet3_deassert_interrupt_line(VMXNET3State *s, int lidx)
+{
+    PCIDevice *d = PCI_DEVICE(s);
+
+    /*
+     * This function should never be called for MSI(X) interrupts
+     * because deassertion never required for message interrupts
+     */
+    assert(!s->msix_used || !msix_enabled(d));
+    /*
+     * This function should never be called for MSI(X) interrupts
+     * because deassertion never required for message interrupts
+     */
+    assert(!s->msi_used || !msi_enabled(d));
+
+    VMW_IRPRN("Deasserting line for interrupt %u", lidx);
+    qemu_set_irq(d->irq[lidx], 0);
+}
+
+static void vmxnet3_update_interrupt_line_state(VMXNET3State *s, int lidx)
+{
+    if (!s->interrupt_states[lidx].is_pending &&
+       s->interrupt_states[lidx].is_asserted) {
+        VMW_IRPRN("New interrupt line state for index %d is DOWN", lidx);
+        _vmxnet3_deassert_interrupt_line(s, lidx);
+        s->interrupt_states[lidx].is_asserted = false;
+        return;
+    }
+
+    if (s->interrupt_states[lidx].is_pending &&
+       !s->interrupt_states[lidx].is_masked &&
+       !s->interrupt_states[lidx].is_asserted) {
+        VMW_IRPRN("New interrupt line state for index %d is UP", lidx);
+        s->interrupt_states[lidx].is_asserted =
+            _vmxnet3_assert_interrupt_line(s, lidx);
+        s->interrupt_states[lidx].is_pending = false;
+        return;
+    }
+}
+
+static void vmxnet3_trigger_interrupt(VMXNET3State *s, int lidx)
+{
+    PCIDevice *d = PCI_DEVICE(s);
+    s->interrupt_states[lidx].is_pending = true;
+    vmxnet3_update_interrupt_line_state(s, lidx);
+
+    if (s->msix_used && msix_enabled(d) && s->auto_int_masking) {
+        goto do_automask;
+    }
+
+    if (s->msi_used && msi_enabled(d) && s->auto_int_masking) {
+        goto do_automask;
+    }
+
+    return;
+
+do_automask:
+    s->interrupt_states[lidx].is_masked = true;
+    vmxnet3_update_interrupt_line_state(s, lidx);
+}
+
+static bool vmxnet3_interrupt_asserted(VMXNET3State *s, int lidx)
+{
+    return s->interrupt_states[lidx].is_asserted;
+}
+
+static void vmxnet3_clear_interrupt(VMXNET3State *s, int int_idx)
+{
+    s->interrupt_states[int_idx].is_pending = false;
+    if (s->auto_int_masking) {
+        s->interrupt_states[int_idx].is_masked = true;
+    }
+    vmxnet3_update_interrupt_line_state(s, int_idx);
+}
+
+static void
+vmxnet3_on_interrupt_mask_changed(VMXNET3State *s, int lidx, bool is_masked)
+{
+    s->interrupt_states[lidx].is_masked = is_masked;
+    vmxnet3_update_interrupt_line_state(s, lidx);
+}
+
+static bool vmxnet3_verify_driver_magic(hwaddr dshmem)
+{
+    return (VMXNET3_READ_DRV_SHARED32(dshmem, magic) == VMXNET3_REV1_MAGIC);
+}
+
+#define VMXNET3_GET_BYTE(x, byte_num) (((x) >> (byte_num)*8) & 0xFF)
+#define VMXNET3_MAKE_BYTE(byte_num, val) \
+    (((uint32_t)((val) & 0xFF)) << (byte_num)*8)
+
+static void vmxnet3_set_variable_mac(VMXNET3State *s, uint32_t h, uint32_t l)
+{
+    s->conf.macaddr.a[0] = VMXNET3_GET_BYTE(l,  0);
+    s->conf.macaddr.a[1] = VMXNET3_GET_BYTE(l,  1);
+    s->conf.macaddr.a[2] = VMXNET3_GET_BYTE(l,  2);
+    s->conf.macaddr.a[3] = VMXNET3_GET_BYTE(l,  3);
+    s->conf.macaddr.a[4] = VMXNET3_GET_BYTE(h, 0);
+    s->conf.macaddr.a[5] = VMXNET3_GET_BYTE(h, 1);
+
+    VMW_CFPRN("Variable MAC: " VMXNET_MF, VMXNET_MA(s->conf.macaddr.a));
+
+    qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
+}
+
+static uint64_t vmxnet3_get_mac_low(MACAddr *addr)
+{
+    return VMXNET3_MAKE_BYTE(0, addr->a[0]) |
+           VMXNET3_MAKE_BYTE(1, addr->a[1]) |
+           VMXNET3_MAKE_BYTE(2, addr->a[2]) |
+           VMXNET3_MAKE_BYTE(3, addr->a[3]);
+}
+
+static uint64_t vmxnet3_get_mac_high(MACAddr *addr)
+{
+    return VMXNET3_MAKE_BYTE(0, addr->a[4]) |
+           VMXNET3_MAKE_BYTE(1, addr->a[5]);
+}
+
+static void
+vmxnet3_inc_tx_consumption_counter(VMXNET3State *s, int qidx)
+{
+    vmxnet3_ring_inc(&s->txq_descr[qidx].tx_ring);
+}
+
+static inline void
+vmxnet3_inc_rx_consumption_counter(VMXNET3State *s, int qidx, int ridx)
+{
+    vmxnet3_ring_inc(&s->rxq_descr[qidx].rx_ring[ridx]);
+}
+
+static inline void
+vmxnet3_inc_tx_completion_counter(VMXNET3State *s, int qidx)
+{
+    vmxnet3_ring_inc(&s->txq_descr[qidx].comp_ring);
+}
+
+static void
+vmxnet3_inc_rx_completion_counter(VMXNET3State *s, int qidx)
+{
+    vmxnet3_ring_inc(&s->rxq_descr[qidx].comp_ring);
+}
+
+static void
+vmxnet3_dec_rx_completion_counter(VMXNET3State *s, int qidx)
+{
+    vmxnet3_ring_dec(&s->rxq_descr[qidx].comp_ring);
+}
+
+static void vmxnet3_complete_packet(VMXNET3State *s, int qidx, uint32 tx_ridx)
+{
+    struct Vmxnet3_TxCompDesc txcq_descr;
+
+    VMXNET3_RING_DUMP(VMW_RIPRN, "TXC", qidx, &s->txq_descr[qidx].comp_ring);
+
+    txcq_descr.txdIdx = tx_ridx;
+    txcq_descr.gen = vmxnet3_ring_curr_gen(&s->txq_descr[qidx].comp_ring);
+
+    vmxnet3_ring_write_curr_cell(&s->txq_descr[qidx].comp_ring, &txcq_descr);
+
+    /* Flush changes in TX descriptor before changing the counter value */
+    smp_wmb();
+
+    vmxnet3_inc_tx_completion_counter(s, qidx);
+    vmxnet3_trigger_interrupt(s, s->txq_descr[qidx].intr_idx);
+}
+
+static bool
+vmxnet3_setup_tx_offloads(VMXNET3State *s)
+{
+    switch (s->offload_mode) {
+    case VMXNET3_OM_NONE:
+        vmxnet_tx_pkt_build_vheader(s->tx_pkt, false, false, 0);
+        break;
+
+    case VMXNET3_OM_CSUM:
+        vmxnet_tx_pkt_build_vheader(s->tx_pkt, false, true, 0);
+        VMW_PKPRN("L4 CSO requested\n");
+        break;
+
+    case VMXNET3_OM_TSO:
+        vmxnet_tx_pkt_build_vheader(s->tx_pkt, true, true,
+            s->cso_or_gso_size);
+        vmxnet_tx_pkt_update_ip_checksums(s->tx_pkt);
+        VMW_PKPRN("GSO offload requested.");
+        break;
+
+    default:
+        assert(false);
+        return false;
+    }
+
+    return true;
+}
+
+static void
+vmxnet3_tx_retrieve_metadata(VMXNET3State *s,
+                             const struct Vmxnet3_TxDesc *txd)
+{
+    s->offload_mode = txd->om;
+    s->cso_or_gso_size = txd->msscof;
+    s->tci = txd->tci;
+    s->needs_vlan = txd->ti;
+}
+
+typedef enum {
+    VMXNET3_PKT_STATUS_OK,
+    VMXNET3_PKT_STATUS_ERROR,
+    VMXNET3_PKT_STATUS_DISCARD,/* only for tx */
+    VMXNET3_PKT_STATUS_OUT_OF_BUF /* only for rx */
+} Vmxnet3PktStatus;
+
+static void
+vmxnet3_on_tx_done_update_stats(VMXNET3State *s, int qidx,
+    Vmxnet3PktStatus status)
+{
+    size_t tot_len = vmxnet_tx_pkt_get_total_len(s->tx_pkt);
+    struct UPT1_TxStats *stats = &s->txq_descr[qidx].txq_stats;
+
+    switch (status) {
+    case VMXNET3_PKT_STATUS_OK:
+        switch (vmxnet_tx_pkt_get_packet_type(s->tx_pkt)) {
+        case ETH_PKT_BCAST:
+            stats->bcastPktsTxOK++;
+            stats->bcastBytesTxOK += tot_len;
+            break;
+        case ETH_PKT_MCAST:
+            stats->mcastPktsTxOK++;
+            stats->mcastBytesTxOK += tot_len;
+            break;
+        case ETH_PKT_UCAST:
+            stats->ucastPktsTxOK++;
+            stats->ucastBytesTxOK += tot_len;
+            break;
+        default:
+            assert(false);
+        }
+
+        if (s->offload_mode == VMXNET3_OM_TSO) {
+            /*
+             * According to VMWARE headers this statistic is a number
+             * of packets after segmentation but since we don't have
+             * this information in QEMU model, the best we can do is to
+             * provide number of non-segmented packets
+             */
+            stats->TSOPktsTxOK++;
+            stats->TSOBytesTxOK += tot_len;
+        }
+        break;
+
+    case VMXNET3_PKT_STATUS_DISCARD:
+        stats->pktsTxDiscard++;
+        break;
+
+    case VMXNET3_PKT_STATUS_ERROR:
+        stats->pktsTxError++;
+        break;
+
+    default:
+        assert(false);
+    }
+}
+
+static void
+vmxnet3_on_rx_done_update_stats(VMXNET3State *s,
+                                int qidx,
+                                Vmxnet3PktStatus status)
+{
+    struct UPT1_RxStats *stats = &s->rxq_descr[qidx].rxq_stats;
+    size_t tot_len = vmxnet_rx_pkt_get_total_len(s->rx_pkt);
+
+    switch (status) {
+    case VMXNET3_PKT_STATUS_OUT_OF_BUF:
+        stats->pktsRxOutOfBuf++;
+        break;
+
+    case VMXNET3_PKT_STATUS_ERROR:
+        stats->pktsRxError++;
+        break;
+    case VMXNET3_PKT_STATUS_OK:
+        switch (vmxnet_rx_pkt_get_packet_type(s->rx_pkt)) {
+        case ETH_PKT_BCAST:
+            stats->bcastPktsRxOK++;
+            stats->bcastBytesRxOK += tot_len;
+            break;
+        case ETH_PKT_MCAST:
+            stats->mcastPktsRxOK++;
+            stats->mcastBytesRxOK += tot_len;
+            break;
+        case ETH_PKT_UCAST:
+            stats->ucastPktsRxOK++;
+            stats->ucastBytesRxOK += tot_len;
+            break;
+        default:
+            assert(false);
+        }
+
+        if (tot_len > s->mtu) {
+            stats->LROPktsRxOK++;
+            stats->LROBytesRxOK += tot_len;
+        }
+        break;
+    default:
+        assert(false);
+    }
+}
+
+static inline bool
+vmxnet3_pop_next_tx_descr(VMXNET3State *s,
+                          int qidx,
+                          struct Vmxnet3_TxDesc *txd,
+                          uint32_t *descr_idx)
+{
+    Vmxnet3Ring *ring = &s->txq_descr[qidx].tx_ring;
+
+    vmxnet3_ring_read_curr_cell(ring, txd);
+    if (txd->gen == vmxnet3_ring_curr_gen(ring)) {
+        /* Only read after generation field verification */
+        smp_rmb();
+        /* Re-read to be sure we got the latest version */
+        vmxnet3_ring_read_curr_cell(ring, txd);
+        VMXNET3_RING_DUMP(VMW_RIPRN, "TX", qidx, ring);
+        *descr_idx = vmxnet3_ring_curr_cell_idx(ring);
+        vmxnet3_inc_tx_consumption_counter(s, qidx);
+        return true;
+    }
+
+    return false;
+}
+
+static bool
+vmxnet3_send_packet(VMXNET3State *s, uint32_t qidx)
+{
+    Vmxnet3PktStatus status = VMXNET3_PKT_STATUS_OK;
+
+    if (!vmxnet3_setup_tx_offloads(s)) {
+        status = VMXNET3_PKT_STATUS_ERROR;
+        goto func_exit;
+    }
+
+    /* debug prints */
+    vmxnet3_dump_virt_hdr(vmxnet_tx_pkt_get_vhdr(s->tx_pkt));
+    vmxnet_tx_pkt_dump(s->tx_pkt);
+
+    if (!vmxnet_tx_pkt_send(s->tx_pkt, qemu_get_queue(s->nic))) {
+        status = VMXNET3_PKT_STATUS_DISCARD;
+        goto func_exit;
+    }
+
+func_exit:
+    vmxnet3_on_tx_done_update_stats(s, qidx, status);
+    return (status == VMXNET3_PKT_STATUS_OK);
+}
+
+static void vmxnet3_process_tx_queue(VMXNET3State *s, int qidx)
+{
+    struct Vmxnet3_TxDesc txd;
+    uint32_t txd_idx;
+    uint32_t data_len;
+    hwaddr data_pa;
+
+    for (;;) {
+        if (!vmxnet3_pop_next_tx_descr(s, qidx, &txd, &txd_idx)) {
+            break;
+        }
+
+        vmxnet3_dump_tx_descr(&txd);
+
+        if (!s->skip_current_tx_pkt) {
+            data_len = (txd.len > 0) ? txd.len : VMXNET3_MAX_TX_BUF_SIZE;
+            data_pa = le64_to_cpu(txd.addr);
+
+            if (!vmxnet_tx_pkt_add_raw_fragment(s->tx_pkt,
+                                                data_pa,
+                                                data_len)) {
+                s->skip_current_tx_pkt = true;
+            }
+        }
+
+        if (s->tx_sop) {
+            vmxnet3_tx_retrieve_metadata(s, &txd);
+            s->tx_sop = false;
+        }
+
+        if (txd.eop) {
+            if (!s->skip_current_tx_pkt) {
+                vmxnet_tx_pkt_parse(s->tx_pkt);
+
+                if (s->needs_vlan) {
+                    vmxnet_tx_pkt_setup_vlan_header(s->tx_pkt, s->tci);
+                }
+
+                vmxnet3_send_packet(s, qidx);
+            } else {
+                vmxnet3_on_tx_done_update_stats(s, qidx,
+                                                VMXNET3_PKT_STATUS_ERROR);
+            }
+
+            vmxnet3_complete_packet(s, qidx, txd_idx);
+            s->tx_sop = true;
+            s->skip_current_tx_pkt = false;
+            vmxnet_tx_pkt_reset(s->tx_pkt);
+        }
+    }
+}
+
+static inline void
+vmxnet3_read_next_rx_descr(VMXNET3State *s, int qidx, int ridx,
+                           struct Vmxnet3_RxDesc *dbuf, uint32_t *didx)
+{
+    Vmxnet3Ring *ring = &s->rxq_descr[qidx].rx_ring[ridx];
+    *didx = vmxnet3_ring_curr_cell_idx(ring);
+    vmxnet3_ring_read_curr_cell(ring, dbuf);
+}
+
+static inline uint8_t
+vmxnet3_get_rx_ring_gen(VMXNET3State *s, int qidx, int ridx)
+{
+    return s->rxq_descr[qidx].rx_ring[ridx].gen;
+}
+
+static inline hwaddr
+vmxnet3_pop_rxc_descr(VMXNET3State *s, int qidx, uint32_t *descr_gen)
+{
+    uint8_t ring_gen;
+    struct Vmxnet3_RxCompDesc rxcd;
+
+    hwaddr daddr =
+        vmxnet3_ring_curr_cell_pa(&s->rxq_descr[qidx].comp_ring);
+
+    cpu_physical_memory_read(daddr, &rxcd, sizeof(struct Vmxnet3_RxCompDesc));
+    ring_gen = vmxnet3_ring_curr_gen(&s->rxq_descr[qidx].comp_ring);
+
+    if (rxcd.gen != ring_gen) {
+        *descr_gen = ring_gen;
+        vmxnet3_inc_rx_completion_counter(s, qidx);
+        return daddr;
+    }
+
+    return 0;
+}
+
+static inline void
+vmxnet3_revert_rxc_descr(VMXNET3State *s, int qidx)
+{
+    vmxnet3_dec_rx_completion_counter(s, qidx);
+}
+
+#define RXQ_IDX      (0)
+#define RX_HEAD_BODY_RING (0)
+#define RX_BODY_ONLY_RING (1)
+
+static bool
+vmxnet3_get_next_head_rx_descr(VMXNET3State *s,
+                               struct Vmxnet3_RxDesc *descr_buf,
+                               uint32_t *descr_idx,
+                               uint32_t *ridx)
+{
+    for (;;) {
+        uint32_t ring_gen;
+        vmxnet3_read_next_rx_descr(s, RXQ_IDX, RX_HEAD_BODY_RING,
+                                   descr_buf, descr_idx);
+
+        /* If no more free descriptors - return */
+        ring_gen = vmxnet3_get_rx_ring_gen(s, RXQ_IDX, RX_HEAD_BODY_RING);
+        if (descr_buf->gen != ring_gen) {
+            return false;
+        }
+
+        /* Only read after generation field verification */
+        smp_rmb();
+        /* Re-read to be sure we got the latest version */
+        vmxnet3_read_next_rx_descr(s, RXQ_IDX, RX_HEAD_BODY_RING,
+                                   descr_buf, descr_idx);
+
+        /* Mark current descriptor as used/skipped */
+        vmxnet3_inc_rx_consumption_counter(s, RXQ_IDX, RX_HEAD_BODY_RING);
+
+        /* If this is what we are looking for - return */
+        if (descr_buf->btype == VMXNET3_RXD_BTYPE_HEAD) {
+            *ridx = RX_HEAD_BODY_RING;
+            return true;
+        }
+    }
+}
+
+static bool
+vmxnet3_get_next_body_rx_descr(VMXNET3State *s,
+                               struct Vmxnet3_RxDesc *d,
+                               uint32_t *didx,
+                               uint32_t *ridx)
+{
+    vmxnet3_read_next_rx_descr(s, RXQ_IDX, RX_HEAD_BODY_RING, d, didx);
+
+    /* Try to find corresponding descriptor in head/body ring */
+    if (d->gen == vmxnet3_get_rx_ring_gen(s, RXQ_IDX, RX_HEAD_BODY_RING)) {
+        /* Only read after generation field verification */
+        smp_rmb();
+        /* Re-read to be sure we got the latest version */
+        vmxnet3_read_next_rx_descr(s, RXQ_IDX, RX_HEAD_BODY_RING, d, didx);
+        if (d->btype == VMXNET3_RXD_BTYPE_BODY) {
+            vmxnet3_inc_rx_consumption_counter(s, RXQ_IDX, RX_HEAD_BODY_RING);
+            *ridx = RX_HEAD_BODY_RING;
+            return true;
+        }
+    }
+
+    /*
+     * If there is no free descriptors on head/body ring or next free
+     * descriptor is a head descriptor switch to body only ring
+     */
+    vmxnet3_read_next_rx_descr(s, RXQ_IDX, RX_BODY_ONLY_RING, d, didx);
+
+    /* If no more free descriptors - return */
+    if (d->gen == vmxnet3_get_rx_ring_gen(s, RXQ_IDX, RX_BODY_ONLY_RING)) {
+        /* Only read after generation field verification */
+        smp_rmb();
+        /* Re-read to be sure we got the latest version */
+        vmxnet3_read_next_rx_descr(s, RXQ_IDX, RX_BODY_ONLY_RING, d, didx);
+        assert(d->btype == VMXNET3_RXD_BTYPE_BODY);
+        *ridx = RX_BODY_ONLY_RING;
+        vmxnet3_inc_rx_consumption_counter(s, RXQ_IDX, RX_BODY_ONLY_RING);
+        return true;
+    }
+
+    return false;
+}
+
+static inline bool
+vmxnet3_get_next_rx_descr(VMXNET3State *s, bool is_head,
+                          struct Vmxnet3_RxDesc *descr_buf,
+                          uint32_t *descr_idx,
+                          uint32_t *ridx)
+{
+    if (is_head || !s->rx_packets_compound) {
+        return vmxnet3_get_next_head_rx_descr(s, descr_buf, descr_idx, ridx);
+    } else {
+        return vmxnet3_get_next_body_rx_descr(s, descr_buf, descr_idx, ridx);
+    }
+}
+
+static void vmxnet3_rx_update_descr(struct VmxnetRxPkt *pkt,
+    struct Vmxnet3_RxCompDesc *rxcd)
+{
+    int csum_ok, is_gso;
+    bool isip4, isip6, istcp, isudp;
+    struct virtio_net_hdr *vhdr;
+    uint8_t offload_type;
+
+    if (vmxnet_rx_pkt_is_vlan_stripped(pkt)) {
+        rxcd->ts = 1;
+        rxcd->tci = vmxnet_rx_pkt_get_vlan_tag(pkt);
+    }
+
+    if (!vmxnet_rx_pkt_has_virt_hdr(pkt)) {
+        goto nocsum;
+    }
+
+    vhdr = vmxnet_rx_pkt_get_vhdr(pkt);
+    /*
+     * Checksum is valid when lower level tell so or when lower level
+     * requires checksum offload telling that packet produced/bridged
+     * locally and did travel over network after last checksum calculation
+     * or production
+     */
+    csum_ok = VMXNET_FLAG_IS_SET(vhdr->flags, VIRTIO_NET_HDR_F_DATA_VALID) ||
+              VMXNET_FLAG_IS_SET(vhdr->flags, VIRTIO_NET_HDR_F_NEEDS_CSUM);
+
+    offload_type = vhdr->gso_type & ~VIRTIO_NET_HDR_GSO_ECN;
+    is_gso = (offload_type != VIRTIO_NET_HDR_GSO_NONE) ? 1 : 0;
+
+    if (!csum_ok && !is_gso) {
+        goto nocsum;
+    }
+
+    vmxnet_rx_pkt_get_protocols(pkt, &isip4, &isip6, &isudp, &istcp);
+    if ((!istcp && !isudp) || (!isip4 && !isip6)) {
+        goto nocsum;
+    }
+
+    rxcd->cnc = 0;
+    rxcd->v4 = isip4 ? 1 : 0;
+    rxcd->v6 = isip6 ? 1 : 0;
+    rxcd->tcp = istcp ? 1 : 0;
+    rxcd->udp = isudp ? 1 : 0;
+    rxcd->fcs = rxcd->tuc = rxcd->ipc = 1;
+    return;
+
+nocsum:
+    rxcd->cnc = 1;
+    return;
+}
+
+static void
+vmxnet3_physical_memory_writev(const struct iovec *iov,
+                               size_t start_iov_off,
+                               hwaddr target_addr,
+                               size_t bytes_to_copy)
+{
+    size_t curr_off = 0;
+    size_t copied = 0;
+
+    while (bytes_to_copy) {
+        if (start_iov_off < (curr_off + iov->iov_len)) {
+            size_t chunk_len =
+                MIN((curr_off + iov->iov_len) - start_iov_off, bytes_to_copy);
+
+            cpu_physical_memory_write(target_addr + copied,
+                                      iov->iov_base + start_iov_off - curr_off,
+                                      chunk_len);
+
+            copied += chunk_len;
+            start_iov_off += chunk_len;
+            curr_off = start_iov_off;
+            bytes_to_copy -= chunk_len;
+        } else {
+            curr_off += iov->iov_len;
+        }
+        iov++;
+    }
+}
+
+static bool
+vmxnet3_indicate_packet(VMXNET3State *s)
+{
+    struct Vmxnet3_RxDesc rxd;
+    bool is_head = true;
+    uint32_t rxd_idx;
+    uint32_t rx_ridx = 0;
+
+    struct Vmxnet3_RxCompDesc rxcd;
+    uint32_t new_rxcd_gen = VMXNET3_INIT_GEN;
+    hwaddr new_rxcd_pa = 0;
+    hwaddr ready_rxcd_pa = 0;
+    struct iovec *data = vmxnet_rx_pkt_get_iovec(s->rx_pkt);
+    size_t bytes_copied = 0;
+    size_t bytes_left = vmxnet_rx_pkt_get_total_len(s->rx_pkt);
+    uint16_t num_frags = 0;
+    size_t chunk_size;
+
+    vmxnet_rx_pkt_dump(s->rx_pkt);
+
+    while (bytes_left > 0) {
+
+        /* cannot add more frags to packet */
+        if (num_frags == s->max_rx_frags) {
+            break;
+        }
+
+        new_rxcd_pa = vmxnet3_pop_rxc_descr(s, RXQ_IDX, &new_rxcd_gen);
+        if (!new_rxcd_pa) {
+            break;
+        }
+
+        if (!vmxnet3_get_next_rx_descr(s, is_head, &rxd, &rxd_idx, &rx_ridx)) {
+            break;
+        }
+
+        chunk_size = MIN(bytes_left, rxd.len);
+        vmxnet3_physical_memory_writev(data, bytes_copied,
+                                       le64_to_cpu(rxd.addr), chunk_size);
+        bytes_copied += chunk_size;
+        bytes_left -= chunk_size;
+
+        vmxnet3_dump_rx_descr(&rxd);
+
+        if (0 != ready_rxcd_pa) {
+            cpu_physical_memory_write(ready_rxcd_pa, &rxcd, sizeof(rxcd));
+        }
+
+        memset(&rxcd, 0, sizeof(struct Vmxnet3_RxCompDesc));
+        rxcd.rxdIdx = rxd_idx;
+        rxcd.len = chunk_size;
+        rxcd.sop = is_head;
+        rxcd.gen = new_rxcd_gen;
+        rxcd.rqID = RXQ_IDX + rx_ridx * s->rxq_num;
+
+        if (0 == bytes_left) {
+            vmxnet3_rx_update_descr(s->rx_pkt, &rxcd);
+        }
+
+        VMW_RIPRN("RX Completion descriptor: rxRing: %lu rxIdx %lu len %lu "
+                  "sop %d csum_correct %lu",
+                  (unsigned long) rx_ridx,
+                  (unsigned long) rxcd.rxdIdx,
+                  (unsigned long) rxcd.len,
+                  (int) rxcd.sop,
+                  (unsigned long) rxcd.tuc);
+
+        is_head = false;
+        ready_rxcd_pa = new_rxcd_pa;
+        new_rxcd_pa = 0;
+        num_frags++;
+    }
+
+    if (0 != ready_rxcd_pa) {
+        rxcd.eop = 1;
+        rxcd.err = (0 != bytes_left);
+        cpu_physical_memory_write(ready_rxcd_pa, &rxcd, sizeof(rxcd));
+
+        /* Flush RX descriptor changes */
+        smp_wmb();
+    }
+
+    if (0 != new_rxcd_pa) {
+        vmxnet3_revert_rxc_descr(s, RXQ_IDX);
+    }
+
+    vmxnet3_trigger_interrupt(s, s->rxq_descr[RXQ_IDX].intr_idx);
+
+    if (bytes_left == 0) {
+        vmxnet3_on_rx_done_update_stats(s, RXQ_IDX, VMXNET3_PKT_STATUS_OK);
+        return true;
+    } else if (num_frags == s->max_rx_frags) {
+        vmxnet3_on_rx_done_update_stats(s, RXQ_IDX, VMXNET3_PKT_STATUS_ERROR);
+        return false;
+    } else {
+        vmxnet3_on_rx_done_update_stats(s, RXQ_IDX,
+                                        VMXNET3_PKT_STATUS_OUT_OF_BUF);
+        return false;
+    }
+}
+
+static void
+vmxnet3_io_bar0_write(void *opaque, hwaddr addr,
+                      uint64_t val, unsigned size)
+{
+    VMXNET3State *s = opaque;
+
+    if (VMW_IS_MULTIREG_ADDR(addr, VMXNET3_REG_TXPROD,
+                        VMXNET3_DEVICE_MAX_TX_QUEUES, VMXNET3_REG_ALIGN)) {
+        int tx_queue_idx =
+            VMW_MULTIREG_IDX_BY_ADDR(addr, VMXNET3_REG_TXPROD,
+                                     VMXNET3_REG_ALIGN);
+        assert(tx_queue_idx <= s->txq_num);
+        vmxnet3_process_tx_queue(s, tx_queue_idx);
+        return;
+    }
+
+    if (VMW_IS_MULTIREG_ADDR(addr, VMXNET3_REG_IMR,
+                        VMXNET3_MAX_INTRS, VMXNET3_REG_ALIGN)) {
+        int l = VMW_MULTIREG_IDX_BY_ADDR(addr, VMXNET3_REG_IMR,
+                                         VMXNET3_REG_ALIGN);
+
+        VMW_CBPRN("Interrupt mask for line %d written: 0x%" PRIx64, l, val);
+
+        vmxnet3_on_interrupt_mask_changed(s, l, val);
+        return;
+    }
+
+    if (VMW_IS_MULTIREG_ADDR(addr, VMXNET3_REG_RXPROD,
+                        VMXNET3_DEVICE_MAX_RX_QUEUES, VMXNET3_REG_ALIGN) ||
+       VMW_IS_MULTIREG_ADDR(addr, VMXNET3_REG_RXPROD2,
+                        VMXNET3_DEVICE_MAX_RX_QUEUES, VMXNET3_REG_ALIGN)) {
+        return;
+    }
+
+    VMW_WRPRN("BAR0 unknown write [%" PRIx64 "] = %" PRIx64 ", size %d",
+              (uint64_t) addr, val, size);
+}
+
+static uint64_t
+vmxnet3_io_bar0_read(void *opaque, hwaddr addr, unsigned size)
+{
+    if (VMW_IS_MULTIREG_ADDR(addr, VMXNET3_REG_IMR,
+                        VMXNET3_MAX_INTRS, VMXNET3_REG_ALIGN)) {
+        assert(false);
+    }
+
+    VMW_CBPRN("BAR0 unknown read [%" PRIx64 "], size %d", addr, size);
+    return 0;
+}
+
+static void vmxnet3_reset_interrupt_states(VMXNET3State *s)
+{
+    int i;
+    for (i = 0; i < ARRAY_SIZE(s->interrupt_states); i++) {
+        s->interrupt_states[i].is_asserted = false;
+        s->interrupt_states[i].is_pending = false;
+        s->interrupt_states[i].is_masked = true;
+    }
+}
+
+static void vmxnet3_reset_mac(VMXNET3State *s)
+{
+    memcpy(&s->conf.macaddr.a, &s->perm_mac.a, sizeof(s->perm_mac.a));
+    VMW_CFPRN("MAC address set to: " VMXNET_MF, VMXNET_MA(s->conf.macaddr.a));
+}
+
+static void vmxnet3_deactivate_device(VMXNET3State *s)
+{
+    VMW_CBPRN("Deactivating vmxnet3...");
+    s->device_active = false;
+}
+
+static void vmxnet3_reset(VMXNET3State *s)
+{
+    VMW_CBPRN("Resetting vmxnet3...");
+
+    vmxnet3_deactivate_device(s);
+    vmxnet3_reset_interrupt_states(s);
+    vmxnet_tx_pkt_reset(s->tx_pkt);
+    s->drv_shmem = 0;
+    s->tx_sop = true;
+    s->skip_current_tx_pkt = false;
+}
+
+static void vmxnet3_update_rx_mode(VMXNET3State *s)
+{
+    s->rx_mode = VMXNET3_READ_DRV_SHARED32(s->drv_shmem,
+                                           devRead.rxFilterConf.rxMode);
+    VMW_CFPRN("RX mode: 0x%08X", s->rx_mode);
+}
+
+static void vmxnet3_update_vlan_filters(VMXNET3State *s)
+{
+    int i;
+
+    /* Copy configuration from shared memory */
+    VMXNET3_READ_DRV_SHARED(s->drv_shmem,
+                            devRead.rxFilterConf.vfTable,
+                            s->vlan_table,
+                            sizeof(s->vlan_table));
+
+    /* Invert byte order when needed */
+    for (i = 0; i < ARRAY_SIZE(s->vlan_table); i++) {
+        s->vlan_table[i] = le32_to_cpu(s->vlan_table[i]);
+    }
+
+    /* Dump configuration for debugging purposes */
+    VMW_CFPRN("Configured VLANs:");
+    for (i = 0; i < sizeof(s->vlan_table) * 8; i++) {
+        if (VMXNET3_VFTABLE_ENTRY_IS_SET(s->vlan_table, i)) {
+            VMW_CFPRN("\tVLAN %d is present", i);
+        }
+    }
+}
+
+static void vmxnet3_update_mcast_filters(VMXNET3State *s)
+{
+    uint16_t list_bytes =
+        VMXNET3_READ_DRV_SHARED16(s->drv_shmem,
+                                  devRead.rxFilterConf.mfTableLen);
+
+    s->mcast_list_len = list_bytes / sizeof(s->mcast_list[0]);
+
+    s->mcast_list = g_realloc(s->mcast_list, list_bytes);
+    if (NULL == s->mcast_list) {
+        if (0 == s->mcast_list_len) {
+            VMW_CFPRN("Current multicast list is empty");
+        } else {
+            VMW_ERPRN("Failed to allocate multicast list of %d elements",
+                      s->mcast_list_len);
+        }
+        s->mcast_list_len = 0;
+    } else {
+        int i;
+        hwaddr mcast_list_pa =
+            VMXNET3_READ_DRV_SHARED64(s->drv_shmem,
+                                      devRead.rxFilterConf.mfTablePA);
+
+        cpu_physical_memory_read(mcast_list_pa, s->mcast_list, list_bytes);
+        VMW_CFPRN("Current multicast list len is %d:", s->mcast_list_len);
+        for (i = 0; i < s->mcast_list_len; i++) {
+            VMW_CFPRN("\t" VMXNET_MF, VMXNET_MA(s->mcast_list[i].a));
+        }
+    }
+}
+
+static void vmxnet3_setup_rx_filtering(VMXNET3State *s)
+{
+    vmxnet3_update_rx_mode(s);
+    vmxnet3_update_vlan_filters(s);
+    vmxnet3_update_mcast_filters(s);
+}
+
+static uint32_t vmxnet3_get_interrupt_config(VMXNET3State *s)
+{
+    uint32_t interrupt_mode = VMXNET3_IT_AUTO | (VMXNET3_IMM_AUTO << 2);
+    VMW_CFPRN("Interrupt config is 0x%X", interrupt_mode);
+    return interrupt_mode;
+}
+
+static void vmxnet3_fill_stats(VMXNET3State *s)
+{
+    int i;
+    for (i = 0; i < s->txq_num; i++) {
+        cpu_physical_memory_write(s->txq_descr[i].tx_stats_pa,
+                                  &s->txq_descr[i].txq_stats,
+                                  sizeof(s->txq_descr[i].txq_stats));
+    }
+
+    for (i = 0; i < s->rxq_num; i++) {
+        cpu_physical_memory_write(s->rxq_descr[i].rx_stats_pa,
+                                  &s->rxq_descr[i].rxq_stats,
+                                  sizeof(s->rxq_descr[i].rxq_stats));
+    }
+}
+
+static void vmxnet3_adjust_by_guest_type(VMXNET3State *s)
+{
+    struct Vmxnet3_GOSInfo gos;
+
+    VMXNET3_READ_DRV_SHARED(s->drv_shmem, devRead.misc.driverInfo.gos,
+                            &gos, sizeof(gos));
+    s->rx_packets_compound =
+        (gos.gosType == VMXNET3_GOS_TYPE_WIN) ? false : true;
+
+    VMW_CFPRN("Guest type specifics: RXCOMPOUND: %d", s->rx_packets_compound);
+}
+
+static void
+vmxnet3_dump_conf_descr(const char *name,
+                        struct Vmxnet3_VariableLenConfDesc *pm_descr)
+{
+    VMW_CFPRN("%s descriptor dump: Version %u, Length %u",
+              name, pm_descr->confVer, pm_descr->confLen);
+
+};
+
+static void vmxnet3_update_pm_state(VMXNET3State *s)
+{
+    struct Vmxnet3_VariableLenConfDesc pm_descr;
+
+    pm_descr.confLen =
+        VMXNET3_READ_DRV_SHARED32(s->drv_shmem, devRead.pmConfDesc.confLen);
+    pm_descr.confVer =
+        VMXNET3_READ_DRV_SHARED32(s->drv_shmem, devRead.pmConfDesc.confVer);
+    pm_descr.confPA =
+        VMXNET3_READ_DRV_SHARED64(s->drv_shmem, devRead.pmConfDesc.confPA);
+
+    vmxnet3_dump_conf_descr("PM State", &pm_descr);
+}
+
+static void vmxnet3_update_features(VMXNET3State *s)
+{
+    uint32_t guest_features;
+    int rxcso_supported;
+
+    guest_features = VMXNET3_READ_DRV_SHARED32(s->drv_shmem,
+                                               devRead.misc.uptFeatures);
+
+    rxcso_supported = VMXNET_FLAG_IS_SET(guest_features, UPT1_F_RXCSUM);
+    s->rx_vlan_stripping = VMXNET_FLAG_IS_SET(guest_features, UPT1_F_RXVLAN);
+    s->lro_supported = VMXNET_FLAG_IS_SET(guest_features, UPT1_F_LRO);
+
+    VMW_CFPRN("Features configuration: LRO: %d, RXCSUM: %d, VLANSTRIP: %d",
+              s->lro_supported, rxcso_supported,
+              s->rx_vlan_stripping);
+    if (s->peer_has_vhdr) {
+        tap_set_offload(qemu_get_queue(s->nic)->peer,
+                        rxcso_supported,
+                        s->lro_supported,
+                        s->lro_supported,
+                        0,
+                        0);
+    }
+}
+
+static void vmxnet3_activate_device(VMXNET3State *s)
+{
+    int i;
+    static const uint32_t VMXNET3_DEF_TX_THRESHOLD = 1;
+    hwaddr qdescr_table_pa;
+    uint64_t pa;
+    uint32_t size;
+
+    /* Verify configuration consistency */
+    if (!vmxnet3_verify_driver_magic(s->drv_shmem)) {
+        VMW_ERPRN("Device configuration received from driver is invalid");
+        return;
+    }
+
+    vmxnet3_adjust_by_guest_type(s);
+    vmxnet3_update_features(s);
+    vmxnet3_update_pm_state(s);
+    vmxnet3_setup_rx_filtering(s);
+    /* Cache fields from shared memory */
+    s->mtu = VMXNET3_READ_DRV_SHARED32(s->drv_shmem, devRead.misc.mtu);
+    VMW_CFPRN("MTU is %u", s->mtu);
+
+    s->max_rx_frags =
+        VMXNET3_READ_DRV_SHARED16(s->drv_shmem, devRead.misc.maxNumRxSG);
+
+    if (s->max_rx_frags == 0) {
+        s->max_rx_frags = 1;
+    }
+
+    VMW_CFPRN("Max RX fragments is %u", s->max_rx_frags);
+
+    s->event_int_idx =
+        VMXNET3_READ_DRV_SHARED8(s->drv_shmem, devRead.intrConf.eventIntrIdx);
+    VMW_CFPRN("Events interrupt line is %u", s->event_int_idx);
+
+    s->auto_int_masking =
+        VMXNET3_READ_DRV_SHARED8(s->drv_shmem, devRead.intrConf.autoMask);
+    VMW_CFPRN("Automatic interrupt masking is %d", (int)s->auto_int_masking);
+
+    s->txq_num =
+        VMXNET3_READ_DRV_SHARED8(s->drv_shmem, devRead.misc.numTxQueues);
+    s->rxq_num =
+        VMXNET3_READ_DRV_SHARED8(s->drv_shmem, devRead.misc.numRxQueues);
+
+    VMW_CFPRN("Number of TX/RX queues %u/%u", s->txq_num, s->rxq_num);
+    assert(s->txq_num <= VMXNET3_DEVICE_MAX_TX_QUEUES);
+
+    qdescr_table_pa =
+        VMXNET3_READ_DRV_SHARED64(s->drv_shmem, devRead.misc.queueDescPA);
+    VMW_CFPRN("TX queues descriptors table is at 0x%" PRIx64, qdescr_table_pa);
+
+    /*
+     * Worst-case scenario is a packet that holds all TX rings space so
+     * we calculate total size of all TX rings for max TX fragments number
+     */
+    s->max_tx_frags = 0;
+
+    /* TX queues */
+    for (i = 0; i < s->txq_num; i++) {
+        hwaddr qdescr_pa =
+            qdescr_table_pa + i * sizeof(struct Vmxnet3_TxQueueDesc);
+
+        /* Read interrupt number for this TX queue */
+        s->txq_descr[i].intr_idx =
+            VMXNET3_READ_TX_QUEUE_DESCR8(qdescr_pa, conf.intrIdx);
+
+        VMW_CFPRN("TX Queue %d interrupt: %d", i, s->txq_descr[i].intr_idx);
+
+        /* Read rings memory locations for TX queues */
+        pa = VMXNET3_READ_TX_QUEUE_DESCR64(qdescr_pa, conf.txRingBasePA);
+        size = VMXNET3_READ_TX_QUEUE_DESCR32(qdescr_pa, conf.txRingSize);
+
+        vmxnet3_ring_init(&s->txq_descr[i].tx_ring, pa, size,
+                          sizeof(struct Vmxnet3_TxDesc), false);
+        VMXNET3_RING_DUMP(VMW_CFPRN, "TX", i, &s->txq_descr[i].tx_ring);
+
+        s->max_tx_frags += size;
+
+        /* TXC ring */
+        pa = VMXNET3_READ_TX_QUEUE_DESCR64(qdescr_pa, conf.compRingBasePA);
+        size = VMXNET3_READ_TX_QUEUE_DESCR32(qdescr_pa, conf.compRingSize);
+        vmxnet3_ring_init(&s->txq_descr[i].comp_ring, pa, size,
+                          sizeof(struct Vmxnet3_TxCompDesc), true);
+        VMXNET3_RING_DUMP(VMW_CFPRN, "TXC", i, &s->txq_descr[i].comp_ring);
+
+        s->txq_descr[i].tx_stats_pa =
+            qdescr_pa + offsetof(struct Vmxnet3_TxQueueDesc, stats);
+
+        memset(&s->txq_descr[i].txq_stats, 0,
+               sizeof(s->txq_descr[i].txq_stats));
+
+        /* Fill device-managed parameters for queues */
+        VMXNET3_WRITE_TX_QUEUE_DESCR32(qdescr_pa,
+                                       ctrl.txThreshold,
+                                       VMXNET3_DEF_TX_THRESHOLD);
+    }
+
+    /* Preallocate TX packet wrapper */
+    VMW_CFPRN("Max TX fragments is %u", s->max_tx_frags);
+    vmxnet_tx_pkt_init(&s->tx_pkt, s->max_tx_frags, s->peer_has_vhdr);
+    vmxnet_rx_pkt_init(&s->rx_pkt, s->peer_has_vhdr);
+
+    /* Read rings memory locations for RX queues */
+    for (i = 0; i < s->rxq_num; i++) {
+        int j;
+        hwaddr qd_pa =
+            qdescr_table_pa + s->txq_num * sizeof(struct Vmxnet3_TxQueueDesc) +
+            i * sizeof(struct Vmxnet3_RxQueueDesc);
+
+        /* Read interrupt number for this RX queue */
+        s->rxq_descr[i].intr_idx =
+            VMXNET3_READ_TX_QUEUE_DESCR8(qd_pa, conf.intrIdx);
+
+        VMW_CFPRN("RX Queue %d interrupt: %d", i, s->rxq_descr[i].intr_idx);
+
+        /* Read rings memory locations */
+        for (j = 0; j < VMXNET3_RX_RINGS_PER_QUEUE; j++) {
+            /* RX rings */
+            pa = VMXNET3_READ_RX_QUEUE_DESCR64(qd_pa, conf.rxRingBasePA[j]);
+            size = VMXNET3_READ_RX_QUEUE_DESCR32(qd_pa, conf.rxRingSize[j]);
+            vmxnet3_ring_init(&s->rxq_descr[i].rx_ring[j], pa, size,
+                              sizeof(struct Vmxnet3_RxDesc), false);
+            VMW_CFPRN("RX queue %d:%d: Base: %" PRIx64 ", Size: %d",
+                      i, j, pa, size);
+        }
+
+        /* RXC ring */
+        pa = VMXNET3_READ_RX_QUEUE_DESCR64(qd_pa, conf.compRingBasePA);
+        size = VMXNET3_READ_RX_QUEUE_DESCR32(qd_pa, conf.compRingSize);
+        vmxnet3_ring_init(&s->rxq_descr[i].comp_ring, pa, size,
+                          sizeof(struct Vmxnet3_RxCompDesc), true);
+        VMW_CFPRN("RXC queue %d: Base: %" PRIx64 ", Size: %d", i, pa, size);
+
+        s->rxq_descr[i].rx_stats_pa =
+            qd_pa + offsetof(struct Vmxnet3_RxQueueDesc, stats);
+        memset(&s->rxq_descr[i].rxq_stats, 0,
+               sizeof(s->rxq_descr[i].rxq_stats));
+    }
+
+    /* Make sure everything is in place before device activation */
+    smp_wmb();
+
+    vmxnet3_reset_mac(s);
+
+    s->device_active = true;
+}
+
+static void vmxnet3_handle_command(VMXNET3State *s, uint64_t cmd)
+{
+    s->last_command = cmd;
+
+    switch (cmd) {
+    case VMXNET3_CMD_GET_PERM_MAC_HI:
+        VMW_CBPRN("Set: Get upper part of permanent MAC");
+        break;
+
+    case VMXNET3_CMD_GET_PERM_MAC_LO:
+        VMW_CBPRN("Set: Get lower part of permanent MAC");
+        break;
+
+    case VMXNET3_CMD_GET_STATS:
+        VMW_CBPRN("Set: Get device statistics");
+        vmxnet3_fill_stats(s);
+        break;
+
+    case VMXNET3_CMD_ACTIVATE_DEV:
+        VMW_CBPRN("Set: Activating vmxnet3 device");
+        vmxnet3_activate_device(s);
+        break;
+
+    case VMXNET3_CMD_UPDATE_RX_MODE:
+        VMW_CBPRN("Set: Update rx mode");
+        vmxnet3_update_rx_mode(s);
+        break;
+
+    case VMXNET3_CMD_UPDATE_VLAN_FILTERS:
+        VMW_CBPRN("Set: Update VLAN filters");
+        vmxnet3_update_vlan_filters(s);
+        break;
+
+    case VMXNET3_CMD_UPDATE_MAC_FILTERS:
+        VMW_CBPRN("Set: Update MAC filters");
+        vmxnet3_update_mcast_filters(s);
+        break;
+
+    case VMXNET3_CMD_UPDATE_FEATURE:
+        VMW_CBPRN("Set: Update features");
+        vmxnet3_update_features(s);
+        break;
+
+    case VMXNET3_CMD_UPDATE_PMCFG:
+        VMW_CBPRN("Set: Update power management config");
+        vmxnet3_update_pm_state(s);
+        break;
+
+    case VMXNET3_CMD_GET_LINK:
+        VMW_CBPRN("Set: Get link");
+        break;
+
+    case VMXNET3_CMD_RESET_DEV:
+        VMW_CBPRN("Set: Reset device");
+        vmxnet3_reset(s);
+        break;
+
+    case VMXNET3_CMD_QUIESCE_DEV:
+        VMW_CBPRN("Set: VMXNET3_CMD_QUIESCE_DEV - pause the device");
+        vmxnet3_deactivate_device(s);
+        break;
+
+    case VMXNET3_CMD_GET_CONF_INTR:
+        VMW_CBPRN("Set: VMXNET3_CMD_GET_CONF_INTR - interrupt configuration");
+        break;
+
+    default:
+        VMW_CBPRN("Received unknown command: %" PRIx64, cmd);
+        break;
+    }
+}
+
+static uint64_t vmxnet3_get_command_status(VMXNET3State *s)
+{
+    uint64_t ret;
+
+    switch (s->last_command) {
+    case VMXNET3_CMD_ACTIVATE_DEV:
+        ret = (s->device_active) ? 0 : -1;
+        VMW_CFPRN("Device active: %" PRIx64, ret);
+        break;
+
+    case VMXNET3_CMD_RESET_DEV:
+    case VMXNET3_CMD_QUIESCE_DEV:
+    case VMXNET3_CMD_GET_QUEUE_STATUS:
+        ret = 0;
+        break;
+
+    case VMXNET3_CMD_GET_LINK:
+        ret = s->link_status_and_speed;
+        VMW_CFPRN("Link and speed: %" PRIx64, ret);
+        break;
+
+    case VMXNET3_CMD_GET_PERM_MAC_LO:
+        ret = vmxnet3_get_mac_low(&s->perm_mac);
+        break;
+
+    case VMXNET3_CMD_GET_PERM_MAC_HI:
+        ret = vmxnet3_get_mac_high(&s->perm_mac);
+        break;
+
+    case VMXNET3_CMD_GET_CONF_INTR:
+        ret = vmxnet3_get_interrupt_config(s);
+        break;
+
+    default:
+        VMW_WRPRN("Received request for unknown command: %x", s->last_command);
+        ret = -1;
+        break;
+    }
+
+    return ret;
+}
+
+static void vmxnet3_set_events(VMXNET3State *s, uint32_t val)
+{
+    uint32_t events;
+
+    VMW_CBPRN("Setting events: 0x%x", val);
+    events = VMXNET3_READ_DRV_SHARED32(s->drv_shmem, ecr) | val;
+    VMXNET3_WRITE_DRV_SHARED32(s->drv_shmem, ecr, events);
+}
+
+static void vmxnet3_ack_events(VMXNET3State *s, uint32_t val)
+{
+    uint32_t events;
+
+    VMW_CBPRN("Clearing events: 0x%x", val);
+    events = VMXNET3_READ_DRV_SHARED32(s->drv_shmem, ecr) & ~val;
+    VMXNET3_WRITE_DRV_SHARED32(s->drv_shmem, ecr, events);
+}
+
+static void
+vmxnet3_io_bar1_write(void *opaque,
+                      hwaddr addr,
+                      uint64_t val,
+                      unsigned size)
+{
+    VMXNET3State *s = opaque;
+
+    switch (addr) {
+    /* Vmxnet3 Revision Report Selection */
+    case VMXNET3_REG_VRRS:
+        VMW_CBPRN("Write BAR1 [VMXNET3_REG_VRRS] = %" PRIx64 ", size %d",
+                  val, size);
+        break;
+
+    /* UPT Version Report Selection */
+    case VMXNET3_REG_UVRS:
+        VMW_CBPRN("Write BAR1 [VMXNET3_REG_UVRS] = %" PRIx64 ", size %d",
+                  val, size);
+        break;
+
+    /* Driver Shared Address Low */
+    case VMXNET3_REG_DSAL:
+        VMW_CBPRN("Write BAR1 [VMXNET3_REG_DSAL] = %" PRIx64 ", size %d",
+                  val, size);
+        /*
+         * Guest driver will first write the low part of the shared
+         * memory address. We save it to temp variable and set the
+         * shared address only after we get the high part
+         */
+        if (0 == val) {
+            s->device_active = false;
+        }
+        s->temp_shared_guest_driver_memory = val;
+        s->drv_shmem = 0;
+        break;
+
+    /* Driver Shared Address High */
+    case VMXNET3_REG_DSAH:
+        VMW_CBPRN("Write BAR1 [VMXNET3_REG_DSAH] = %" PRIx64 ", size %d",
+                  val, size);
+        /*
+         * Set the shared memory between guest driver and device.
+         * We already should have low address part.
+         */
+        s->drv_shmem = s->temp_shared_guest_driver_memory | (val << 32);
+        break;
+
+    /* Command */
+    case VMXNET3_REG_CMD:
+        VMW_CBPRN("Write BAR1 [VMXNET3_REG_CMD] = %" PRIx64 ", size %d",
+                  val, size);
+        vmxnet3_handle_command(s, val);
+        break;
+
+    /* MAC Address Low */
+    case VMXNET3_REG_MACL:
+        VMW_CBPRN("Write BAR1 [VMXNET3_REG_MACL] = %" PRIx64 ", size %d",
+                  val, size);
+        s->temp_mac = val;
+        break;
+
+    /* MAC Address High */
+    case VMXNET3_REG_MACH:
+        VMW_CBPRN("Write BAR1 [VMXNET3_REG_MACH] = %" PRIx64 ", size %d",
+                  val, size);
+        vmxnet3_set_variable_mac(s, val, s->temp_mac);
+        break;
+
+    /* Interrupt Cause Register */
+    case VMXNET3_REG_ICR:
+        VMW_CBPRN("Write BAR1 [VMXNET3_REG_ICR] = %" PRIx64 ", size %d",
+                  val, size);
+        assert(false);
+        break;
+
+    /* Event Cause Register */
+    case VMXNET3_REG_ECR:
+        VMW_CBPRN("Write BAR1 [VMXNET3_REG_ECR] = %" PRIx64 ", size %d",
+                  val, size);
+        vmxnet3_ack_events(s, val);
+        break;
+
+    default:
+        VMW_CBPRN("Unknown Write to BAR1 [%" PRIx64 "] = %" PRIx64 ", size %d",
+                  addr, val, size);
+        break;
+    }
+}
+
+static uint64_t
+vmxnet3_io_bar1_read(void *opaque, hwaddr addr, unsigned size)
+{
+        VMXNET3State *s = opaque;
+        uint64_t ret = 0;
+
+        switch (addr) {
+        /* Vmxnet3 Revision Report Selection */
+        case VMXNET3_REG_VRRS:
+            VMW_CBPRN("Read BAR1 [VMXNET3_REG_VRRS], size %d", size);
+            ret = VMXNET3_DEVICE_REVISION;
+            break;
+
+        /* UPT Version Report Selection */
+        case VMXNET3_REG_UVRS:
+            VMW_CBPRN("Read BAR1 [VMXNET3_REG_UVRS], size %d", size);
+            ret = VMXNET3_DEVICE_VERSION;
+            break;
+
+        /* Command */
+        case VMXNET3_REG_CMD:
+            VMW_CBPRN("Read BAR1 [VMXNET3_REG_CMD], size %d", size);
+            ret = vmxnet3_get_command_status(s);
+            break;
+
+        /* MAC Address Low */
+        case VMXNET3_REG_MACL:
+            VMW_CBPRN("Read BAR1 [VMXNET3_REG_MACL], size %d", size);
+            ret = vmxnet3_get_mac_low(&s->conf.macaddr);
+            break;
+
+        /* MAC Address High */
+        case VMXNET3_REG_MACH:
+            VMW_CBPRN("Read BAR1 [VMXNET3_REG_MACH], size %d", size);
+            ret = vmxnet3_get_mac_high(&s->conf.macaddr);
+            break;
+
+        /*
+         * Interrupt Cause Register
+         * Used for legacy interrupts only so interrupt index always 0
+         */
+        case VMXNET3_REG_ICR:
+            VMW_CBPRN("Read BAR1 [VMXNET3_REG_ICR], size %d", size);
+            if (vmxnet3_interrupt_asserted(s, 0)) {
+                vmxnet3_clear_interrupt(s, 0);
+                ret = true;
+            } else {
+                ret = false;
+            }
+            break;
+
+        default:
+            VMW_CBPRN("Unknow read BAR1[%" PRIx64 "], %d bytes", addr, size);
+            break;
+        }
+
+        return ret;
+}
+
+static int
+vmxnet3_can_receive(NetClientState *nc)
+{
+    VMXNET3State *s = qemu_get_nic_opaque(nc);
+    return s->device_active &&
+           VMXNET_FLAG_IS_SET(s->link_status_and_speed, VMXNET3_LINK_STATUS_UP);
+}
+
+static inline bool
+vmxnet3_is_registered_vlan(VMXNET3State *s, const void *data)
+{
+    uint16_t vlan_tag = eth_get_pkt_tci(data) & VLAN_VID_MASK;
+    if (IS_SPECIAL_VLAN_ID(vlan_tag)) {
+        return true;
+    }
+
+    return VMXNET3_VFTABLE_ENTRY_IS_SET(s->vlan_table, vlan_tag);
+}
+
+static bool
+vmxnet3_is_allowed_mcast_group(VMXNET3State *s, const uint8_t *group_mac)
+{
+    int i;
+    for (i = 0; i < s->mcast_list_len; i++) {
+        if (!memcmp(group_mac, s->mcast_list[i].a, sizeof(s->mcast_list[i]))) {
+            return true;
+        }
+    }
+    return false;
+}
+
+static bool
+vmxnet3_rx_filter_may_indicate(VMXNET3State *s, const void *data,
+    size_t size)
+{
+    struct eth_header *ehdr = PKT_GET_ETH_HDR(data);
+
+    if (VMXNET_FLAG_IS_SET(s->rx_mode, VMXNET3_RXM_PROMISC)) {
+        return true;
+    }
+
+    if (!vmxnet3_is_registered_vlan(s, data)) {
+        return false;
+    }
+
+    switch (vmxnet_rx_pkt_get_packet_type(s->rx_pkt)) {
+    case ETH_PKT_UCAST:
+        if (!VMXNET_FLAG_IS_SET(s->rx_mode, VMXNET3_RXM_UCAST)) {
+            return false;
+        }
+        if (memcmp(s->conf.macaddr.a, ehdr->h_dest, ETH_ALEN)) {
+            return false;
+        }
+        break;
+
+    case ETH_PKT_BCAST:
+        if (!VMXNET_FLAG_IS_SET(s->rx_mode, VMXNET3_RXM_BCAST)) {
+            return false;
+        }
+        break;
+
+    case ETH_PKT_MCAST:
+        if (VMXNET_FLAG_IS_SET(s->rx_mode, VMXNET3_RXM_ALL_MULTI)) {
+            return true;
+        }
+        if (!VMXNET_FLAG_IS_SET(s->rx_mode, VMXNET3_RXM_MCAST)) {
+            return false;
+        }
+        if (!vmxnet3_is_allowed_mcast_group(s, ehdr->h_dest)) {
+            return false;
+        }
+        break;
+
+    default:
+        assert(false);
+    }
+
+    return true;
+}
+
+static ssize_t
+vmxnet3_receive(NetClientState *nc, const uint8_t *buf, size_t size)
+{
+    VMXNET3State *s = qemu_get_nic_opaque(nc);
+    size_t bytes_indicated;
+
+    if (!vmxnet3_can_receive(nc)) {
+        VMW_PKPRN("Cannot receive now");
+        return -1;
+    }
+
+    if (s->peer_has_vhdr) {
+        vmxnet_rx_pkt_set_vhdr(s->rx_pkt, (struct virtio_net_hdr *)buf);
+        buf += sizeof(struct virtio_net_hdr);
+        size -= sizeof(struct virtio_net_hdr);
+    }
+
+    vmxnet_rx_pkt_set_packet_type(s->rx_pkt,
+        get_eth_packet_type(PKT_GET_ETH_HDR(buf)));
+
+    if (vmxnet3_rx_filter_may_indicate(s, buf, size)) {
+        vmxnet_rx_pkt_attach_data(s->rx_pkt, buf, size, s->rx_vlan_stripping);
+        bytes_indicated = vmxnet3_indicate_packet(s) ? size : -1;
+        if (bytes_indicated < size) {
+            VMW_PKPRN("RX: %lu of %lu bytes indicated", bytes_indicated, size);
+        }
+    } else {
+        VMW_PKPRN("Packet dropped by RX filter");
+        bytes_indicated = size;
+    }
+
+    assert(size > 0);
+    assert(bytes_indicated != 0);
+    return bytes_indicated;
+}
+
+static void vmxnet3_cleanup(NetClientState *nc)
+{
+    VMXNET3State *s = qemu_get_nic_opaque(nc);
+    s->nic = NULL;
+}
+
+static void vmxnet3_set_link_status(NetClientState *nc)
+{
+    VMXNET3State *s = qemu_get_nic_opaque(nc);
+
+    if (nc->link_down) {
+        s->link_status_and_speed &= ~VMXNET3_LINK_STATUS_UP;
+    } else {
+        s->link_status_and_speed |= VMXNET3_LINK_STATUS_UP;
+    }
+
+    vmxnet3_set_events(s, VMXNET3_ECR_LINK);
+    vmxnet3_trigger_interrupt(s, s->event_int_idx);
+}
+
+static NetClientInfo net_vmxnet3_info = {
+        .type = NET_CLIENT_OPTIONS_KIND_NIC,
+        .size = sizeof(NICState),
+        .can_receive = vmxnet3_can_receive,
+        .receive = vmxnet3_receive,
+        .cleanup = vmxnet3_cleanup,
+        .link_status_changed = vmxnet3_set_link_status,
+};
+
+static bool vmxnet3_peer_has_vnet_hdr(VMXNET3State *s)
+{
+    NetClientState *peer = qemu_get_queue(s->nic)->peer;
+
+    if ((NULL != peer)                              &&
+        (peer->info->type == NET_CLIENT_OPTIONS_KIND_TAP)   &&
+        tap_has_vnet_hdr(peer)) {
+        return true;
+    }
+
+    VMW_WRPRN("Peer has no virtio extension. Task offloads will be emulated.");
+    return false;
+}
+
+static void vmxnet3_net_uninit(VMXNET3State *s)
+{
+    g_free(s->mcast_list);
+    vmxnet_tx_pkt_reset(s->tx_pkt);
+    vmxnet_tx_pkt_uninit(s->tx_pkt);
+    vmxnet_rx_pkt_uninit(s->rx_pkt);
+    qemu_del_net_client(qemu_get_queue(s->nic));
+}
+
+static void vmxnet3_net_init(VMXNET3State *s)
+{
+    DeviceState *d = DEVICE(s);
+
+    VMW_CBPRN("vmxnet3_net_init called...");
+
+    qemu_macaddr_default_if_unset(&s->conf.macaddr);
+
+    /* Windows guest will query the address that was set on init */
+    memcpy(&s->perm_mac.a, &s->conf.macaddr.a, sizeof(s->perm_mac.a));
+
+    s->mcast_list = NULL;
+    s->mcast_list_len = 0;
+
+    s->link_status_and_speed = VMXNET3_LINK_SPEED | VMXNET3_LINK_STATUS_UP;
+
+    VMW_CFPRN("Permanent MAC: " MAC_FMT, MAC_ARG(s->perm_mac.a));
+
+    s->nic = qemu_new_nic(&net_vmxnet3_info, &s->conf,
+                          object_get_typename(OBJECT(s)),
+                          d->id, s);
+
+    s->peer_has_vhdr = vmxnet3_peer_has_vnet_hdr(s);
+    s->tx_sop = true;
+    s->skip_current_tx_pkt = false;
+    s->tx_pkt = NULL;
+    s->rx_pkt = NULL;
+    s->rx_vlan_stripping = false;
+    s->lro_supported = false;
+
+    if (s->peer_has_vhdr) {
+        tap_set_vnet_hdr_len(qemu_get_queue(s->nic)->peer,
+            sizeof(struct virtio_net_hdr));
+
+        tap_using_vnet_hdr(qemu_get_queue(s->nic)->peer, 1);
+    }
+
+    qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
+}
+
+static void
+vmxnet3_unuse_msix_vectors(VMXNET3State *s, int num_vectors)
+{
+    PCIDevice *d = PCI_DEVICE(s);
+    int i;
+    for (i = 0; i < num_vectors; i++) {
+        msix_vector_unuse(d, i);
+    }
+}
+
+static bool
+vmxnet3_use_msix_vectors(VMXNET3State *s, int num_vectors)
+{
+    PCIDevice *d = PCI_DEVICE(s);
+    int i;
+    for (i = 0; i < num_vectors; i++) {
+        int res = msix_vector_use(d, i);
+        if (0 > res) {
+            VMW_WRPRN("Failed to use MSI-X vector %d, error %d", i, res);
+            vmxnet3_unuse_msix_vectors(s, i);
+            return false;
+        }
+    }
+    return true;
+}
+
+static bool
+vmxnet3_init_msix(VMXNET3State *s)
+{
+    PCIDevice *d = PCI_DEVICE(s);
+    int res = msix_init(d, VMXNET3_MAX_INTRS,
+                        &s->msix_bar,
+                        VMXNET3_MSIX_BAR_IDX, VMXNET3_OFF_MSIX_TABLE,
+                        &s->msix_bar,
+                        VMXNET3_MSIX_BAR_IDX, VMXNET3_OFF_MSIX_PBA,
+                        0);
+
+    if (0 > res) {
+        VMW_WRPRN("Failed to initialize MSI-X, error %d", res);
+        s->msix_used = false;
+    } else {
+        if (!vmxnet3_use_msix_vectors(s, VMXNET3_MAX_INTRS)) {
+            VMW_WRPRN("Failed to use MSI-X vectors, error %d", res);
+            msix_uninit(d, &s->msix_bar, &s->msix_bar);
+            s->msix_used = false;
+        } else {
+            s->msix_used = true;
+        }
+    }
+    return s->msix_used;
+}
+
+static void
+vmxnet3_cleanup_msix(VMXNET3State *s)
+{
+    PCIDevice *d = PCI_DEVICE(s);
+
+    if (s->msix_used) {
+        msix_vector_unuse(d, VMXNET3_MAX_INTRS);
+        msix_uninit(d, &s->msix_bar, &s->msix_bar);
+    }
+}
+
+#define VMXNET3_MSI_NUM_VECTORS   (1)
+#define VMXNET3_MSI_OFFSET        (0x50)
+#define VMXNET3_USE_64BIT         (true)
+#define VMXNET3_PER_VECTOR_MASK   (false)
+
+static bool
+vmxnet3_init_msi(VMXNET3State *s)
+{
+    PCIDevice *d = PCI_DEVICE(s);
+    int res;
+
+    res = msi_init(d, VMXNET3_MSI_OFFSET, VMXNET3_MSI_NUM_VECTORS,
+                   VMXNET3_USE_64BIT, VMXNET3_PER_VECTOR_MASK);
+    if (0 > res) {
+        VMW_WRPRN("Failed to initialize MSI, error %d", res);
+        s->msi_used = false;
+    } else {
+        s->msi_used = true;
+    }
+
+    return s->msi_used;
+}
+
+static void
+vmxnet3_cleanup_msi(VMXNET3State *s)
+{
+    PCIDevice *d = PCI_DEVICE(s);
+
+    if (s->msi_used) {
+        msi_uninit(d);
+    }
+}
+
+static void
+vmxnet3_msix_save(QEMUFile *f, void *opaque)
+{
+    PCIDevice *d = PCI_DEVICE(opaque);
+    msix_save(d, f);
+}
+
+static int
+vmxnet3_msix_load(QEMUFile *f, void *opaque, int version_id)
+{
+    PCIDevice *d = PCI_DEVICE(opaque);
+    msix_load(d, f);
+    return 0;
+}
+
+static const MemoryRegionOps b0_ops = {
+    .read = vmxnet3_io_bar0_read,
+    .write = vmxnet3_io_bar0_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+            .min_access_size = 4,
+            .max_access_size = 4,
+    },
+};
+
+static const MemoryRegionOps b1_ops = {
+    .read = vmxnet3_io_bar1_read,
+    .write = vmxnet3_io_bar1_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+            .min_access_size = 4,
+            .max_access_size = 4,
+    },
+};
+
+static int vmxnet3_pci_init(PCIDevice *pci_dev)
+{
+    DeviceState *dev = DEVICE(pci_dev);
+    VMXNET3State *s = VMXNET3(pci_dev);
+
+    VMW_CBPRN("Starting init...");
+
+    memory_region_init_io(&s->bar0, &b0_ops, s,
+                          "vmxnet3-b0", VMXNET3_PT_REG_SIZE);
+    pci_register_bar(pci_dev, VMXNET3_BAR0_IDX,
+                     PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar0);
+
+    memory_region_init_io(&s->bar1, &b1_ops, s,
+                          "vmxnet3-b1", VMXNET3_VD_REG_SIZE);
+    pci_register_bar(pci_dev, VMXNET3_BAR1_IDX,
+                     PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar1);
+
+    memory_region_init(&s->msix_bar, "vmxnet3-msix-bar",
+                       VMXNET3_MSIX_BAR_SIZE);
+    pci_register_bar(pci_dev, VMXNET3_MSIX_BAR_IDX,
+                     PCI_BASE_ADDRESS_SPACE_MEMORY, &s->msix_bar);
+
+    vmxnet3_reset_interrupt_states(s);
+
+    /* Interrupt pin A */
+    pci_dev->config[PCI_INTERRUPT_PIN] = 0x01;
+
+    if (!vmxnet3_init_msix(s)) {
+        VMW_WRPRN("Failed to initialize MSI-X, configuration is inconsistent.");
+    }
+
+    if (!vmxnet3_init_msi(s)) {
+        VMW_WRPRN("Failed to initialize MSI, configuration is inconsistent.");
+    }
+
+    vmxnet3_net_init(s);
+
+    register_savevm(dev, "vmxnet3-msix", -1, 1,
+                    vmxnet3_msix_save, vmxnet3_msix_load, s);
+
+    add_boot_device_path(s->conf.bootindex, dev, "/ethernet-phy@0");
+
+    return 0;
+}
+
+
+static void vmxnet3_pci_uninit(PCIDevice *pci_dev)
+{
+    DeviceState *dev = DEVICE(pci_dev);
+    VMXNET3State *s = VMXNET3(pci_dev);
+
+    VMW_CBPRN("Starting uninit...");
+
+    unregister_savevm(dev, "vmxnet3-msix", s);
+
+    vmxnet3_net_uninit(s);
+
+    vmxnet3_cleanup_msix(s);
+
+    vmxnet3_cleanup_msi(s);
+
+    memory_region_destroy(&s->bar0);
+    memory_region_destroy(&s->bar1);
+    memory_region_destroy(&s->msix_bar);
+}
+
+static void vmxnet3_qdev_reset(DeviceState *dev)
+{
+    PCIDevice *d = PCI_DEVICE(dev);
+    VMXNET3State *s = VMXNET3(d);
+
+    VMW_CBPRN("Starting QDEV reset...");
+    vmxnet3_reset(s);
+}
+
+static bool vmxnet3_mc_list_needed(void *opaque)
+{
+    return true;
+}
+
+static int vmxnet3_mcast_list_pre_load(void *opaque)
+{
+    VMXNET3State *s = opaque;
+
+    s->mcast_list = g_malloc(s->mcast_list_buff_size);
+
+    return 0;
+}
+
+
+static void vmxnet3_pre_save(void *opaque)
+{
+    VMXNET3State *s = opaque;
+
+    s->mcast_list_buff_size = s->mcast_list_len * sizeof(MACAddr);
+}
+
+static const VMStateDescription vmxstate_vmxnet3_mcast_list = {
+    .name = "vmxnet3/mcast_list",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .pre_load = vmxnet3_mcast_list_pre_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_VBUFFER_UINT32(mcast_list, VMXNET3State, 0, NULL, 0,
+            mcast_list_buff_size),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void vmxnet3_get_ring_from_file(QEMUFile *f, Vmxnet3Ring *r)
+{
+    r->pa = qemu_get_be64(f);
+    r->size = qemu_get_be32(f);
+    r->cell_size = qemu_get_be32(f);
+    r->next = qemu_get_be32(f);
+    r->gen = qemu_get_byte(f);
+}
+
+static void vmxnet3_put_ring_to_file(QEMUFile *f, Vmxnet3Ring *r)
+{
+    qemu_put_be64(f, r->pa);
+    qemu_put_be32(f, r->size);
+    qemu_put_be32(f, r->cell_size);
+    qemu_put_be32(f, r->next);
+    qemu_put_byte(f, r->gen);
+}
+
+static void vmxnet3_get_tx_stats_from_file(QEMUFile *f,
+    struct UPT1_TxStats *tx_stat)
+{
+    tx_stat->TSOPktsTxOK = qemu_get_be64(f);
+    tx_stat->TSOBytesTxOK = qemu_get_be64(f);
+    tx_stat->ucastPktsTxOK = qemu_get_be64(f);
+    tx_stat->ucastBytesTxOK = qemu_get_be64(f);
+    tx_stat->mcastPktsTxOK = qemu_get_be64(f);
+    tx_stat->mcastBytesTxOK = qemu_get_be64(f);
+    tx_stat->bcastPktsTxOK = qemu_get_be64(f);
+    tx_stat->bcastBytesTxOK = qemu_get_be64(f);
+    tx_stat->pktsTxError = qemu_get_be64(f);
+    tx_stat->pktsTxDiscard = qemu_get_be64(f);
+}
+
+static void vmxnet3_put_tx_stats_to_file(QEMUFile *f,
+    struct UPT1_TxStats *tx_stat)
+{
+    qemu_put_be64(f, tx_stat->TSOPktsTxOK);
+    qemu_put_be64(f, tx_stat->TSOBytesTxOK);
+    qemu_put_be64(f, tx_stat->ucastPktsTxOK);
+    qemu_put_be64(f, tx_stat->ucastBytesTxOK);
+    qemu_put_be64(f, tx_stat->mcastPktsTxOK);
+    qemu_put_be64(f, tx_stat->mcastBytesTxOK);
+    qemu_put_be64(f, tx_stat->bcastPktsTxOK);
+    qemu_put_be64(f, tx_stat->bcastBytesTxOK);
+    qemu_put_be64(f, tx_stat->pktsTxError);
+    qemu_put_be64(f, tx_stat->pktsTxDiscard);
+}
+
+static int vmxnet3_get_txq_descr(QEMUFile *f, void *pv, size_t size)
+{
+    Vmxnet3TxqDescr *r = pv;
+
+    vmxnet3_get_ring_from_file(f, &r->tx_ring);
+    vmxnet3_get_ring_from_file(f, &r->comp_ring);
+    r->intr_idx = qemu_get_byte(f);
+    r->tx_stats_pa = qemu_get_be64(f);
+
+    vmxnet3_get_tx_stats_from_file(f, &r->txq_stats);
+
+    return 0;
+}
+
+static void vmxnet3_put_txq_descr(QEMUFile *f, void *pv, size_t size)
+{
+    Vmxnet3TxqDescr *r = pv;
+
+    vmxnet3_put_ring_to_file(f, &r->tx_ring);
+    vmxnet3_put_ring_to_file(f, &r->comp_ring);
+    qemu_put_byte(f, r->intr_idx);
+    qemu_put_be64(f, r->tx_stats_pa);
+    vmxnet3_put_tx_stats_to_file(f, &r->txq_stats);
+}
+
+const VMStateInfo txq_descr_info = {
+    .name = "txq_descr",
+    .get = vmxnet3_get_txq_descr,
+    .put = vmxnet3_put_txq_descr
+};
+
+static void vmxnet3_get_rx_stats_from_file(QEMUFile *f,
+    struct UPT1_RxStats *rx_stat)
+{
+    rx_stat->LROPktsRxOK = qemu_get_be64(f);
+    rx_stat->LROBytesRxOK = qemu_get_be64(f);
+    rx_stat->ucastPktsRxOK = qemu_get_be64(f);
+    rx_stat->ucastBytesRxOK = qemu_get_be64(f);
+    rx_stat->mcastPktsRxOK = qemu_get_be64(f);
+    rx_stat->mcastBytesRxOK = qemu_get_be64(f);
+    rx_stat->bcastPktsRxOK = qemu_get_be64(f);
+    rx_stat->bcastBytesRxOK = qemu_get_be64(f);
+    rx_stat->pktsRxOutOfBuf = qemu_get_be64(f);
+    rx_stat->pktsRxError = qemu_get_be64(f);
+}
+
+static void vmxnet3_put_rx_stats_to_file(QEMUFile *f,
+    struct UPT1_RxStats *rx_stat)
+{
+    qemu_put_be64(f, rx_stat->LROPktsRxOK);
+    qemu_put_be64(f, rx_stat->LROBytesRxOK);
+    qemu_put_be64(f, rx_stat->ucastPktsRxOK);
+    qemu_put_be64(f, rx_stat->ucastBytesRxOK);
+    qemu_put_be64(f, rx_stat->mcastPktsRxOK);
+    qemu_put_be64(f, rx_stat->mcastBytesRxOK);
+    qemu_put_be64(f, rx_stat->bcastPktsRxOK);
+    qemu_put_be64(f, rx_stat->bcastBytesRxOK);
+    qemu_put_be64(f, rx_stat->pktsRxOutOfBuf);
+    qemu_put_be64(f, rx_stat->pktsRxError);
+}
+
+static int vmxnet3_get_rxq_descr(QEMUFile *f, void *pv, size_t size)
+{
+    Vmxnet3RxqDescr *r = pv;
+    int i;
+
+    for (i = 0; i < VMXNET3_RX_RINGS_PER_QUEUE; i++) {
+        vmxnet3_get_ring_from_file(f, &r->rx_ring[i]);
+    }
+
+    vmxnet3_get_ring_from_file(f, &r->comp_ring);
+    r->intr_idx = qemu_get_byte(f);
+    r->rx_stats_pa = qemu_get_be64(f);
+
+    vmxnet3_get_rx_stats_from_file(f, &r->rxq_stats);
+
+    return 0;
+}
+
+static void vmxnet3_put_rxq_descr(QEMUFile *f, void *pv, size_t size)
+{
+    Vmxnet3RxqDescr *r = pv;
+    int i;
+
+    for (i = 0; i < VMXNET3_RX_RINGS_PER_QUEUE; i++) {
+        vmxnet3_put_ring_to_file(f, &r->rx_ring[i]);
+    }
+
+    vmxnet3_put_ring_to_file(f, &r->comp_ring);
+    qemu_put_byte(f, r->intr_idx);
+    qemu_put_be64(f, r->rx_stats_pa);
+    vmxnet3_put_rx_stats_to_file(f, &r->rxq_stats);
+}
+
+static int vmxnet3_post_load(void *opaque, int version_id)
+{
+    VMXNET3State *s = opaque;
+    PCIDevice *d = PCI_DEVICE(s);
+
+    vmxnet_tx_pkt_init(&s->tx_pkt, s->max_tx_frags, s->peer_has_vhdr);
+    vmxnet_rx_pkt_init(&s->rx_pkt, s->peer_has_vhdr);
+
+    if (s->msix_used) {
+        if  (!vmxnet3_use_msix_vectors(s, VMXNET3_MAX_INTRS)) {
+            VMW_WRPRN("Failed to re-use MSI-X vectors");
+            msix_uninit(d, &s->msix_bar, &s->msix_bar);
+            s->msix_used = false;
+            return -1;
+        }
+    }
+
+    return 0;
+}
+
+const VMStateInfo rxq_descr_info = {
+    .name = "rxq_descr",
+    .get = vmxnet3_get_rxq_descr,
+    .put = vmxnet3_put_rxq_descr
+};
+
+static int vmxnet3_get_int_state(QEMUFile *f, void *pv, size_t size)
+{
+    Vmxnet3IntState *r = pv;
+
+    r->is_masked = qemu_get_byte(f);
+    r->is_pending = qemu_get_byte(f);
+    r->is_asserted = qemu_get_byte(f);
+
+    return 0;
+}
+
+static void vmxnet3_put_int_state(QEMUFile *f, void *pv, size_t size)
+{
+    Vmxnet3IntState *r = pv;
+
+    qemu_put_byte(f, r->is_masked);
+    qemu_put_byte(f, r->is_pending);
+    qemu_put_byte(f, r->is_asserted);
+}
+
+const VMStateInfo int_state_info = {
+    .name = "int_state",
+    .get = vmxnet3_get_int_state,
+    .put = vmxnet3_put_int_state
+};
+
+static const VMStateDescription vmstate_vmxnet3 = {
+    .name = "vmxnet3",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .pre_save = vmxnet3_pre_save,
+    .post_load = vmxnet3_post_load,
+    .fields      = (VMStateField[]) {
+            VMSTATE_PCI_DEVICE(parent_obj, VMXNET3State),
+            VMSTATE_BOOL(rx_packets_compound, VMXNET3State),
+            VMSTATE_BOOL(rx_vlan_stripping, VMXNET3State),
+            VMSTATE_BOOL(lro_supported, VMXNET3State),
+            VMSTATE_UINT32(rx_mode, VMXNET3State),
+            VMSTATE_UINT32(mcast_list_len, VMXNET3State),
+            VMSTATE_UINT32(mcast_list_buff_size, VMXNET3State),
+            VMSTATE_UINT32_ARRAY(vlan_table, VMXNET3State, VMXNET3_VFT_SIZE),
+            VMSTATE_UINT32(mtu, VMXNET3State),
+            VMSTATE_UINT16(max_rx_frags, VMXNET3State),
+            VMSTATE_UINT32(max_tx_frags, VMXNET3State),
+            VMSTATE_UINT8(event_int_idx, VMXNET3State),
+            VMSTATE_BOOL(auto_int_masking, VMXNET3State),
+            VMSTATE_UINT8(txq_num, VMXNET3State),
+            VMSTATE_UINT8(rxq_num, VMXNET3State),
+            VMSTATE_UINT32(device_active, VMXNET3State),
+            VMSTATE_UINT32(last_command, VMXNET3State),
+            VMSTATE_UINT32(link_status_and_speed, VMXNET3State),
+            VMSTATE_UINT32(temp_mac, VMXNET3State),
+            VMSTATE_UINT64(drv_shmem, VMXNET3State),
+            VMSTATE_UINT64(temp_shared_guest_driver_memory, VMXNET3State),
+
+            VMSTATE_ARRAY(txq_descr, VMXNET3State,
+                VMXNET3_DEVICE_MAX_TX_QUEUES, 0, txq_descr_info,
+                Vmxnet3TxqDescr),
+            VMSTATE_ARRAY(rxq_descr, VMXNET3State,
+                VMXNET3_DEVICE_MAX_RX_QUEUES, 0, rxq_descr_info,
+                Vmxnet3RxqDescr),
+            VMSTATE_ARRAY(interrupt_states, VMXNET3State, VMXNET3_MAX_INTRS,
+                0, int_state_info, Vmxnet3IntState),
+
+            VMSTATE_END_OF_LIST()
+    },
+    .subsections = (VMStateSubsection[]) {
+        {
+            .vmsd = &vmxstate_vmxnet3_mcast_list,
+            .needed = vmxnet3_mc_list_needed
+        },
+        {
+            /* empty element. */
+        }
+    }
+};
+
+static void
+vmxnet3_write_config(PCIDevice *pci_dev, uint32_t addr, uint32_t val, int len)
+{
+    pci_default_write_config(pci_dev, addr, val, len);
+    msix_write_config(pci_dev, addr, val, len);
+    msi_write_config(pci_dev, addr, val, len);
+}
+
+static Property vmxnet3_properties[] = {
+    DEFINE_NIC_PROPERTIES(VMXNET3State, conf),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void vmxnet3_class_init(ObjectClass *class, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(class);
+    PCIDeviceClass *c = PCI_DEVICE_CLASS(class);
+
+    c->init = vmxnet3_pci_init;
+    c->exit = vmxnet3_pci_uninit;
+    c->vendor_id = PCI_VENDOR_ID_VMWARE;
+    c->device_id = PCI_DEVICE_ID_VMWARE_VMXNET3;
+    c->revision = PCI_DEVICE_ID_VMWARE_VMXNET3_REVISION;
+    c->class_id = PCI_CLASS_NETWORK_ETHERNET;
+    c->subsystem_vendor_id = PCI_VENDOR_ID_VMWARE;
+    c->subsystem_id = PCI_DEVICE_ID_VMWARE_VMXNET3;
+    c->config_write = vmxnet3_write_config,
+    dc->desc = "VMWare Paravirtualized Ethernet v3";
+    dc->reset = vmxnet3_qdev_reset;
+    dc->vmsd = &vmstate_vmxnet3;
+    dc->props = vmxnet3_properties;
+}
+
+static const TypeInfo vmxnet3_info = {
+    .name          = TYPE_VMXNET3,
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(VMXNET3State),
+    .class_init    = vmxnet3_class_init,
+};
+
+static void vmxnet3_register_types(void)
+{
+    VMW_CBPRN("vmxnet3_register_types called...");
+    type_register_static(&vmxnet3_info);
+}
+
+type_init(vmxnet3_register_types)
diff --git a/hw/net/vmxnet3.h b/hw/net/vmxnet3.h
new file mode 100644 (file)
index 0000000..4eae7c7
--- /dev/null
@@ -0,0 +1,757 @@
+/*
+ * QEMU VMWARE VMXNET3 paravirtual NIC interface definitions
+ *
+ * Copyright (c) 2012 Ravello Systems LTD (http://ravellosystems.com)
+ *
+ * Developed by Daynix Computing LTD (http://www.daynix.com)
+ *
+ * Authors:
+ * Dmitry Fleytman <dmitry@daynix.com>
+ * Tamir Shomer <tamirs@daynix.com>
+ * Yan Vugenfirer <yan@daynix.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef _QEMU_VMXNET3_H
+#define _QEMU_VMXNET3_H
+
+#define VMXNET3_DEVICE_MAX_TX_QUEUES 8
+#define VMXNET3_DEVICE_MAX_RX_QUEUES 8   /* Keep this value as a power of 2 */
+
+/*
+ * VMWARE headers we got from Linux kernel do not fully comply QEMU coding
+ * standards in sense of types and defines used.
+ * Since we didn't want to change VMWARE code, following set of typedefs
+ * and defines needed to compile these headers with QEMU introduced.
+ */
+#define u64     uint64_t
+#define u32     uint32_t
+#define u16     uint16_t
+#define u8      uint8_t
+#define __le16  uint16_t
+#define __le32  uint32_t
+#define __le64  uint64_t
+#define __packed QEMU_PACKED
+
+#if defined(HOST_WORDS_BIGENDIAN)
+#define __BIG_ENDIAN_BITFIELD
+#else
+#endif
+
+/*
+ * Following is an interface definition for
+ * VMXNET3 device as provided by VMWARE
+ * See original copyright from Linux kernel v3.2.8
+ * header file drivers/net/vmxnet3/vmxnet3_defs.h below.
+ */
+
+/*
+ * Linux driver for VMware's vmxnet3 ethernet NIC.
+ *
+ * Copyright (C) 2008-2009, VMware, Inc. All Rights Reserved.
+ *
+ * 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; version 2 of the License and no 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, GOOD TITLE or
+ * NON INFRINGEMENT.  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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Maintained by: Shreyas Bhatewara <pv-drivers@vmware.com>
+ *
+ */
+
+struct UPT1_TxStats {
+    u64            TSOPktsTxOK;  /* TSO pkts post-segmentation */
+    u64            TSOBytesTxOK;
+    u64            ucastPktsTxOK;
+    u64            ucastBytesTxOK;
+    u64            mcastPktsTxOK;
+    u64            mcastBytesTxOK;
+    u64            bcastPktsTxOK;
+    u64            bcastBytesTxOK;
+    u64            pktsTxError;
+    u64            pktsTxDiscard;
+};
+
+struct UPT1_RxStats {
+    u64            LROPktsRxOK;    /* LRO pkts */
+    u64            LROBytesRxOK;   /* bytes from LRO pkts */
+    /* the following counters are for pkts from the wire, i.e., pre-LRO */
+    u64            ucastPktsRxOK;
+    u64            ucastBytesRxOK;
+    u64            mcastPktsRxOK;
+    u64            mcastBytesRxOK;
+    u64            bcastPktsRxOK;
+    u64            bcastBytesRxOK;
+    u64            pktsRxOutOfBuf;
+    u64            pktsRxError;
+};
+
+/* interrupt moderation level */
+enum {
+    UPT1_IML_NONE        = 0, /* no interrupt moderation */
+    UPT1_IML_HIGHEST    = 7, /* least intr generated */
+    UPT1_IML_ADAPTIVE    = 8, /* adpative intr moderation */
+};
+/* values for UPT1_RSSConf.hashFunc */
+enum {
+    UPT1_RSS_HASH_TYPE_NONE      = 0x0,
+    UPT1_RSS_HASH_TYPE_IPV4      = 0x01,
+    UPT1_RSS_HASH_TYPE_TCP_IPV4  = 0x02,
+    UPT1_RSS_HASH_TYPE_IPV6      = 0x04,
+    UPT1_RSS_HASH_TYPE_TCP_IPV6  = 0x08,
+};
+
+enum {
+    UPT1_RSS_HASH_FUNC_NONE      = 0x0,
+    UPT1_RSS_HASH_FUNC_TOEPLITZ  = 0x01,
+};
+
+#define UPT1_RSS_MAX_KEY_SIZE        40
+#define UPT1_RSS_MAX_IND_TABLE_SIZE  128
+
+struct UPT1_RSSConf {
+    u16            hashType;
+    u16            hashFunc;
+    u16            hashKeySize;
+    u16            indTableSize;
+    u8            hashKey[UPT1_RSS_MAX_KEY_SIZE];
+    u8            indTable[UPT1_RSS_MAX_IND_TABLE_SIZE];
+};
+
+/* features */
+enum {
+    UPT1_F_RXCSUM        = 0x0001, /* rx csum verification */
+    UPT1_F_RSS           = 0x0002,
+    UPT1_F_RXVLAN        = 0x0004, /* VLAN tag stripping */
+    UPT1_F_LRO           = 0x0008,
+};
+
+/* all registers are 32 bit wide */
+/* BAR 1 */
+enum {
+    VMXNET3_REG_VRRS    = 0x0,    /* Vmxnet3 Revision Report Selection */
+    VMXNET3_REG_UVRS    = 0x8,    /* UPT Version Report Selection */
+    VMXNET3_REG_DSAL    = 0x10,    /* Driver Shared Address Low */
+    VMXNET3_REG_DSAH    = 0x18,    /* Driver Shared Address High */
+    VMXNET3_REG_CMD        = 0x20,    /* Command */
+    VMXNET3_REG_MACL    = 0x28,    /* MAC Address Low */
+    VMXNET3_REG_MACH    = 0x30,    /* MAC Address High */
+    VMXNET3_REG_ICR        = 0x38,    /* Interrupt Cause Register */
+    VMXNET3_REG_ECR        = 0x40    /* Event Cause Register */
+};
+
+/* BAR 0 */
+enum {
+    VMXNET3_REG_IMR        = 0x0,     /* Interrupt Mask Register */
+    VMXNET3_REG_TXPROD    = 0x600, /* Tx Producer Index */
+    VMXNET3_REG_RXPROD    = 0x800, /* Rx Producer Index for ring 1 */
+    VMXNET3_REG_RXPROD2    = 0xA00     /* Rx Producer Index for ring 2 */
+};
+
+#define VMXNET3_PT_REG_SIZE     4096    /* BAR 0 */
+#define VMXNET3_VD_REG_SIZE     4096    /* BAR 1 */
+
+#define VMXNET3_REG_ALIGN       8    /* All registers are 8-byte aligned. */
+#define VMXNET3_REG_ALIGN_MASK  0x7
+
+/* I/O Mapped access to registers */
+#define VMXNET3_IO_TYPE_PT              0
+#define VMXNET3_IO_TYPE_VD              1
+#define VMXNET3_IO_ADDR(type, reg)      (((type) << 24) | ((reg) & 0xFFFFFF))
+#define VMXNET3_IO_TYPE(addr)           ((addr) >> 24)
+#define VMXNET3_IO_REG(addr)            ((addr) & 0xFFFFFF)
+
+enum {
+    VMXNET3_CMD_FIRST_SET = 0xCAFE0000,
+    VMXNET3_CMD_ACTIVATE_DEV = VMXNET3_CMD_FIRST_SET, /* 0xCAFE0000 */
+    VMXNET3_CMD_QUIESCE_DEV,                          /* 0xCAFE0001 */
+    VMXNET3_CMD_RESET_DEV,                            /* 0xCAFE0002 */
+    VMXNET3_CMD_UPDATE_RX_MODE,                       /* 0xCAFE0003 */
+    VMXNET3_CMD_UPDATE_MAC_FILTERS,                   /* 0xCAFE0004 */
+    VMXNET3_CMD_UPDATE_VLAN_FILTERS,                  /* 0xCAFE0005 */
+    VMXNET3_CMD_UPDATE_RSSIDT,                        /* 0xCAFE0006 */
+    VMXNET3_CMD_UPDATE_IML,                           /* 0xCAFE0007 */
+    VMXNET3_CMD_UPDATE_PMCFG,                         /* 0xCAFE0008 */
+    VMXNET3_CMD_UPDATE_FEATURE,                       /* 0xCAFE0009 */
+    VMXNET3_CMD_LOAD_PLUGIN,                          /* 0xCAFE000A */
+
+    VMXNET3_CMD_FIRST_GET = 0xF00D0000,
+    VMXNET3_CMD_GET_QUEUE_STATUS = VMXNET3_CMD_FIRST_GET, /* 0xF00D0000 */
+    VMXNET3_CMD_GET_STATS,                                /* 0xF00D0001 */
+    VMXNET3_CMD_GET_LINK,                                 /* 0xF00D0002 */
+    VMXNET3_CMD_GET_PERM_MAC_LO,                          /* 0xF00D0003 */
+    VMXNET3_CMD_GET_PERM_MAC_HI,                          /* 0xF00D0004 */
+    VMXNET3_CMD_GET_DID_LO,                               /* 0xF00D0005 */
+    VMXNET3_CMD_GET_DID_HI,                               /* 0xF00D0006 */
+    VMXNET3_CMD_GET_DEV_EXTRA_INFO,                       /* 0xF00D0007 */
+    VMXNET3_CMD_GET_CONF_INTR                             /* 0xF00D0008 */
+};
+
+/*
+ *    Little Endian layout of bitfields -
+ *    Byte 0 :    7.....len.....0
+ *    Byte 1 :    rsvd gen 13.len.8
+ *    Byte 2 :     5.msscof.0 ext1  dtype
+ *    Byte 3 :     13...msscof...6
+ *
+ *    Big Endian layout of bitfields -
+ *    Byte 0:        13...msscof...6
+ *    Byte 1 :     5.msscof.0 ext1  dtype
+ *    Byte 2 :    rsvd gen 13.len.8
+ *    Byte 3 :    7.....len.....0
+ *
+ *    Thus, le32_to_cpu on the dword will allow the big endian driver to read
+ *    the bit fields correctly. And cpu_to_le32 will convert bitfields
+ *    bit fields written by big endian driver to format required by device.
+ */
+
+struct Vmxnet3_TxDesc {
+    __le64 addr;
+
+#ifdef __BIG_ENDIAN_BITFIELD
+    u32 msscof:14;  /* MSS, checksum offset, flags */
+    u32 ext1:1;
+    u32 dtype:1;    /* descriptor type */
+    u32 rsvd:1;
+    u32 gen:1;      /* generation bit */
+    u32 len:14;
+#else
+    u32 len:14;
+    u32 gen:1;      /* generation bit */
+    u32 rsvd:1;
+    u32 dtype:1;    /* descriptor type */
+    u32 ext1:1;
+    u32 msscof:14;  /* MSS, checksum offset, flags */
+#endif  /* __BIG_ENDIAN_BITFIELD */
+
+#ifdef __BIG_ENDIAN_BITFIELD
+    u32 tci:16;     /* Tag to Insert */
+    u32 ti:1;       /* VLAN Tag Insertion */
+    u32 ext2:1;
+    u32 cq:1;       /* completion request */
+    u32 eop:1;      /* End Of Packet */
+    u32 om:2;       /* offload mode */
+    u32 hlen:10;    /* header len */
+#else
+    u32 hlen:10;    /* header len */
+    u32 om:2;       /* offload mode */
+    u32 eop:1;      /* End Of Packet */
+    u32 cq:1;       /* completion request */
+    u32 ext2:1;
+    u32 ti:1;       /* VLAN Tag Insertion */
+    u32 tci:16;     /* Tag to Insert */
+#endif  /* __BIG_ENDIAN_BITFIELD */
+};
+
+/* TxDesc.OM values */
+#define VMXNET3_OM_NONE        0
+#define VMXNET3_OM_CSUM        2
+#define VMXNET3_OM_TSO        3
+
+/* fields in TxDesc we access w/o using bit fields */
+#define VMXNET3_TXD_EOP_SHIFT    12
+#define VMXNET3_TXD_CQ_SHIFT    13
+#define VMXNET3_TXD_GEN_SHIFT    14
+#define VMXNET3_TXD_EOP_DWORD_SHIFT 3
+#define VMXNET3_TXD_GEN_DWORD_SHIFT 2
+
+#define VMXNET3_TXD_CQ        (1 << VMXNET3_TXD_CQ_SHIFT)
+#define VMXNET3_TXD_EOP        (1 << VMXNET3_TXD_EOP_SHIFT)
+#define VMXNET3_TXD_GEN        (1 << VMXNET3_TXD_GEN_SHIFT)
+
+#define VMXNET3_HDR_COPY_SIZE   128
+
+
+struct Vmxnet3_TxDataDesc {
+    u8        data[VMXNET3_HDR_COPY_SIZE];
+};
+
+#define VMXNET3_TCD_GEN_SHIFT    31
+#define VMXNET3_TCD_GEN_SIZE    1
+#define VMXNET3_TCD_TXIDX_SHIFT    0
+#define VMXNET3_TCD_TXIDX_SIZE    12
+#define VMXNET3_TCD_GEN_DWORD_SHIFT    3
+
+struct Vmxnet3_TxCompDesc {
+    u32        txdIdx:12;    /* Index of the EOP TxDesc */
+    u32        ext1:20;
+
+    __le32        ext2;
+    __le32        ext3;
+
+    u32        rsvd:24;
+    u32        type:7;       /* completion type */
+    u32        gen:1;        /* generation bit */
+};
+
+struct Vmxnet3_RxDesc {
+    __le64        addr;
+
+#ifdef __BIG_ENDIAN_BITFIELD
+    u32        gen:1;        /* Generation bit */
+    u32        rsvd:15;
+    u32        dtype:1;      /* Descriptor type */
+    u32        btype:1;      /* Buffer Type */
+    u32        len:14;
+#else
+    u32        len:14;
+    u32        btype:1;      /* Buffer Type */
+    u32        dtype:1;      /* Descriptor type */
+    u32        rsvd:15;
+    u32        gen:1;        /* Generation bit */
+#endif
+    u32        ext1;
+};
+
+/* values of RXD.BTYPE */
+#define VMXNET3_RXD_BTYPE_HEAD   0    /* head only */
+#define VMXNET3_RXD_BTYPE_BODY   1    /* body only */
+
+/* fields in RxDesc we access w/o using bit fields */
+#define VMXNET3_RXD_BTYPE_SHIFT  14
+#define VMXNET3_RXD_GEN_SHIFT    31
+
+struct Vmxnet3_RxCompDesc {
+#ifdef __BIG_ENDIAN_BITFIELD
+    u32        ext2:1;
+    u32        cnc:1;        /* Checksum Not Calculated */
+    u32        rssType:4;    /* RSS hash type used */
+    u32        rqID:10;      /* rx queue/ring ID */
+    u32        sop:1;        /* Start of Packet */
+    u32        eop:1;        /* End of Packet */
+    u32        ext1:2;
+    u32        rxdIdx:12;    /* Index of the RxDesc */
+#else
+    u32        rxdIdx:12;    /* Index of the RxDesc */
+    u32        ext1:2;
+    u32        eop:1;        /* End of Packet */
+    u32        sop:1;        /* Start of Packet */
+    u32        rqID:10;      /* rx queue/ring ID */
+    u32        rssType:4;    /* RSS hash type used */
+    u32        cnc:1;        /* Checksum Not Calculated */
+    u32        ext2:1;
+#endif  /* __BIG_ENDIAN_BITFIELD */
+
+    __le32        rssHash;      /* RSS hash value */
+
+#ifdef __BIG_ENDIAN_BITFIELD
+    u32        tci:16;       /* Tag stripped */
+    u32        ts:1;         /* Tag is stripped */
+    u32        err:1;        /* Error */
+    u32        len:14;       /* data length */
+#else
+    u32        len:14;       /* data length */
+    u32        err:1;        /* Error */
+    u32        ts:1;         /* Tag is stripped */
+    u32        tci:16;       /* Tag stripped */
+#endif  /* __BIG_ENDIAN_BITFIELD */
+
+
+#ifdef __BIG_ENDIAN_BITFIELD
+    u32        gen:1;        /* generation bit */
+    u32        type:7;       /* completion type */
+    u32        fcs:1;        /* Frame CRC correct */
+    u32        frg:1;        /* IP Fragment */
+    u32        v4:1;         /* IPv4 */
+    u32        v6:1;         /* IPv6 */
+    u32        ipc:1;        /* IP Checksum Correct */
+    u32        tcp:1;        /* TCP packet */
+    u32        udp:1;        /* UDP packet */
+    u32        tuc:1;        /* TCP/UDP Checksum Correct */
+    u32        csum:16;
+#else
+    u32        csum:16;
+    u32        tuc:1;        /* TCP/UDP Checksum Correct */
+    u32        udp:1;        /* UDP packet */
+    u32        tcp:1;        /* TCP packet */
+    u32        ipc:1;        /* IP Checksum Correct */
+    u32        v6:1;         /* IPv6 */
+    u32        v4:1;         /* IPv4 */
+    u32        frg:1;        /* IP Fragment */
+    u32        fcs:1;        /* Frame CRC correct */
+    u32        type:7;       /* completion type */
+    u32        gen:1;        /* generation bit */
+#endif  /* __BIG_ENDIAN_BITFIELD */
+};
+
+/* fields in RxCompDesc we access via Vmxnet3_GenericDesc.dword[3] */
+#define VMXNET3_RCD_TUC_SHIFT    16
+#define VMXNET3_RCD_IPC_SHIFT    19
+
+/* fields in RxCompDesc we access via Vmxnet3_GenericDesc.qword[1] */
+#define VMXNET3_RCD_TYPE_SHIFT    56
+#define VMXNET3_RCD_GEN_SHIFT    63
+
+/* csum OK for TCP/UDP pkts over IP */
+#define VMXNET3_RCD_CSUM_OK (1 << VMXNET3_RCD_TUC_SHIFT | \
+                     1 << VMXNET3_RCD_IPC_SHIFT)
+#define VMXNET3_TXD_GEN_SIZE 1
+#define VMXNET3_TXD_EOP_SIZE 1
+
+/* value of RxCompDesc.rssType */
+enum {
+    VMXNET3_RCD_RSS_TYPE_NONE     = 0,
+    VMXNET3_RCD_RSS_TYPE_IPV4     = 1,
+    VMXNET3_RCD_RSS_TYPE_TCPIPV4  = 2,
+    VMXNET3_RCD_RSS_TYPE_IPV6     = 3,
+    VMXNET3_RCD_RSS_TYPE_TCPIPV6  = 4,
+};
+
+
+/* a union for accessing all cmd/completion descriptors */
+union Vmxnet3_GenericDesc {
+    __le64                qword[2];
+    __le32                dword[4];
+    __le16                word[8];
+    struct Vmxnet3_TxDesc        txd;
+    struct Vmxnet3_RxDesc        rxd;
+    struct Vmxnet3_TxCompDesc    tcd;
+    struct Vmxnet3_RxCompDesc    rcd;
+};
+
+#define VMXNET3_INIT_GEN       1
+
+/* Max size of a single tx buffer */
+#define VMXNET3_MAX_TX_BUF_SIZE  (1 << 14)
+
+/* # of tx desc needed for a tx buffer size */
+#define VMXNET3_TXD_NEEDED(size) (((size) + VMXNET3_MAX_TX_BUF_SIZE - 1) / \
+                    VMXNET3_MAX_TX_BUF_SIZE)
+
+/* max # of tx descs for a non-tso pkt */
+#define VMXNET3_MAX_TXD_PER_PKT 16
+
+/* Max size of a single rx buffer */
+#define VMXNET3_MAX_RX_BUF_SIZE  ((1 << 14) - 1)
+/* Minimum size of a type 0 buffer */
+#define VMXNET3_MIN_T0_BUF_SIZE  128
+#define VMXNET3_MAX_CSUM_OFFSET  1024
+
+/* Ring base address alignment */
+#define VMXNET3_RING_BA_ALIGN   512
+#define VMXNET3_RING_BA_MASK    (VMXNET3_RING_BA_ALIGN - 1)
+
+/* Ring size must be a multiple of 32 */
+#define VMXNET3_RING_SIZE_ALIGN 32
+#define VMXNET3_RING_SIZE_MASK  (VMXNET3_RING_SIZE_ALIGN - 1)
+
+/* Max ring size */
+#define VMXNET3_TX_RING_MAX_SIZE   4096
+#define VMXNET3_TC_RING_MAX_SIZE   4096
+#define VMXNET3_RX_RING_MAX_SIZE   4096
+#define VMXNET3_RC_RING_MAX_SIZE   8192
+
+/* a list of reasons for queue stop */
+
+enum {
+ VMXNET3_ERR_NOEOP        = 0x80000000, /* cannot find the EOP desc of a pkt */
+ VMXNET3_ERR_TXD_REUSE    = 0x80000001, /* reuse TxDesc before tx completion */
+ VMXNET3_ERR_BIG_PKT      = 0x80000002, /* too many TxDesc for a pkt */
+ VMXNET3_ERR_DESC_NOT_SPT = 0x80000003, /* descriptor type not supported */
+ VMXNET3_ERR_SMALL_BUF    = 0x80000004, /* type 0 buffer too small */
+ VMXNET3_ERR_STRESS       = 0x80000005, /* stress option firing in vmkernel */
+ VMXNET3_ERR_SWITCH       = 0x80000006, /* mode switch failure */
+ VMXNET3_ERR_TXD_INVALID  = 0x80000007, /* invalid TxDesc */
+};
+
+/* completion descriptor types */
+#define VMXNET3_CDTYPE_TXCOMP      0    /* Tx Completion Descriptor */
+#define VMXNET3_CDTYPE_RXCOMP      3    /* Rx Completion Descriptor */
+
+enum {
+    VMXNET3_GOS_BITS_UNK    = 0,   /* unknown */
+    VMXNET3_GOS_BITS_32     = 1,
+    VMXNET3_GOS_BITS_64     = 2,
+};
+
+#define VMXNET3_GOS_TYPE_UNK        0 /* unknown */
+#define VMXNET3_GOS_TYPE_LINUX      1
+#define VMXNET3_GOS_TYPE_WIN        2
+#define VMXNET3_GOS_TYPE_SOLARIS    3
+#define VMXNET3_GOS_TYPE_FREEBSD    4
+#define VMXNET3_GOS_TYPE_PXE        5
+
+struct Vmxnet3_GOSInfo {
+#ifdef __BIG_ENDIAN_BITFIELD
+    u32        gosMisc:10;    /* other info about gos */
+    u32        gosVer:16;     /* gos version */
+    u32        gosType:4;     /* which guest */
+    u32        gosBits:2;    /* 32-bit or 64-bit? */
+#else
+    u32        gosBits:2;     /* 32-bit or 64-bit? */
+    u32        gosType:4;     /* which guest */
+    u32        gosVer:16;     /* gos version */
+    u32        gosMisc:10;    /* other info about gos */
+#endif  /* __BIG_ENDIAN_BITFIELD */
+};
+
+struct Vmxnet3_DriverInfo {
+    __le32                version;
+    struct Vmxnet3_GOSInfo        gos;
+    __le32                vmxnet3RevSpt;
+    __le32                uptVerSpt;
+};
+
+
+#define VMXNET3_REV1_MAGIC  0xbabefee1
+
+/*
+ * QueueDescPA must be 128 bytes aligned. It points to an array of
+ * Vmxnet3_TxQueueDesc followed by an array of Vmxnet3_RxQueueDesc.
+ * The number of Vmxnet3_TxQueueDesc/Vmxnet3_RxQueueDesc are specified by
+ * Vmxnet3_MiscConf.numTxQueues/numRxQueues, respectively.
+ */
+#define VMXNET3_QUEUE_DESC_ALIGN  128
+
+
+struct Vmxnet3_MiscConf {
+    struct Vmxnet3_DriverInfo driverInfo;
+    __le64        uptFeatures;
+    __le64        ddPA;         /* driver data PA */
+    __le64        queueDescPA;  /* queue descriptor table PA */
+    __le32        ddLen;        /* driver data len */
+    __le32        queueDescLen; /* queue desc. table len in bytes */
+    __le32        mtu;
+    __le16        maxNumRxSG;
+    u8        numTxQueues;
+    u8        numRxQueues;
+    __le32        reserved[4];
+};
+
+
+struct Vmxnet3_TxQueueConf {
+    __le64        txRingBasePA;
+    __le64        dataRingBasePA;
+    __le64        compRingBasePA;
+    __le64        ddPA;         /* driver data */
+    __le64        reserved;
+    __le32        txRingSize;   /* # of tx desc */
+    __le32        dataRingSize; /* # of data desc */
+    __le32        compRingSize; /* # of comp desc */
+    __le32        ddLen;        /* size of driver data */
+    u8        intrIdx;
+    u8        _pad[7];
+};
+
+
+struct Vmxnet3_RxQueueConf {
+    __le64        rxRingBasePA[2];
+    __le64        compRingBasePA;
+    __le64        ddPA;            /* driver data */
+    __le64        reserved;
+    __le32        rxRingSize[2];   /* # of rx desc */
+    __le32        compRingSize;    /* # of rx comp desc */
+    __le32        ddLen;           /* size of driver data */
+    u8        intrIdx;
+    u8        _pad[7];
+};
+
+
+enum vmxnet3_intr_mask_mode {
+    VMXNET3_IMM_AUTO   = 0,
+    VMXNET3_IMM_ACTIVE = 1,
+    VMXNET3_IMM_LAZY   = 2
+};
+
+enum vmxnet3_intr_type {
+    VMXNET3_IT_AUTO = 0,
+    VMXNET3_IT_INTX = 1,
+    VMXNET3_IT_MSI  = 2,
+    VMXNET3_IT_MSIX = 3
+};
+
+#define VMXNET3_MAX_TX_QUEUES  8
+#define VMXNET3_MAX_RX_QUEUES  16
+/* addition 1 for events */
+#define VMXNET3_MAX_INTRS      25
+
+/* value of intrCtrl */
+#define VMXNET3_IC_DISABLE_ALL  0x1   /* bit 0 */
+
+
+struct Vmxnet3_IntrConf {
+    bool        autoMask;
+    u8        numIntrs;      /* # of interrupts */
+    u8        eventIntrIdx;
+    u8        modLevels[VMXNET3_MAX_INTRS];    /* moderation level for
+                             * each intr */
+    __le32        intrCtrl;
+    __le32        reserved[2];
+};
+
+/* one bit per VLAN ID, the size is in the units of u32 */
+#define VMXNET3_VFT_SIZE  (4096/(sizeof(uint32_t)*8))
+
+
+struct Vmxnet3_QueueStatus {
+    bool        stopped;
+    u8        _pad[3];
+    __le32        error;
+};
+
+
+struct Vmxnet3_TxQueueCtrl {
+    __le32        txNumDeferred;
+    __le32        txThreshold;
+    __le64        reserved;
+};
+
+
+struct Vmxnet3_RxQueueCtrl {
+    bool        updateRxProd;
+    u8        _pad[7];
+    __le64        reserved;
+};
+
+enum {
+    VMXNET3_RXM_UCAST     = 0x01,  /* unicast only */
+    VMXNET3_RXM_MCAST     = 0x02,  /* multicast passing the filters */
+    VMXNET3_RXM_BCAST     = 0x04,  /* broadcast only */
+    VMXNET3_RXM_ALL_MULTI = 0x08,  /* all multicast */
+    VMXNET3_RXM_PROMISC   = 0x10  /* promiscuous */
+};
+
+struct Vmxnet3_RxFilterConf {
+    __le32        rxMode;       /* VMXNET3_RXM_xxx */
+    __le16        mfTableLen;   /* size of the multicast filter table */
+    __le16        _pad1;
+    __le64        mfTablePA;    /* PA of the multicast filters table */
+    __le32        vfTable[VMXNET3_VFT_SIZE]; /* vlan filter */
+};
+
+
+#define VMXNET3_PM_MAX_FILTERS        6
+#define VMXNET3_PM_MAX_PATTERN_SIZE   128
+#define VMXNET3_PM_MAX_MASK_SIZE      (VMXNET3_PM_MAX_PATTERN_SIZE / 8)
+
+#define VMXNET3_PM_WAKEUP_MAGIC  cpu_to_le16(0x01)  /* wake up on magic pkts */
+#define VMXNET3_PM_WAKEUP_FILTER cpu_to_le16(0x02)  /* wake up on pkts matching
+                                                     * filters */
+
+
+struct Vmxnet3_PM_PktFilter {
+    u8        maskSize;
+    u8        patternSize;
+    u8        mask[VMXNET3_PM_MAX_MASK_SIZE];
+    u8        pattern[VMXNET3_PM_MAX_PATTERN_SIZE];
+    u8        pad[6];
+};
+
+
+struct Vmxnet3_PMConf {
+    __le16        wakeUpEvents;  /* VMXNET3_PM_WAKEUP_xxx */
+    u8        numFilters;
+    u8        pad[5];
+    struct Vmxnet3_PM_PktFilter filters[VMXNET3_PM_MAX_FILTERS];
+};
+
+
+struct Vmxnet3_VariableLenConfDesc {
+    __le32        confVer;
+    __le32        confLen;
+    __le64        confPA;
+};
+
+
+struct Vmxnet3_TxQueueDesc {
+    struct Vmxnet3_TxQueueCtrl        ctrl;
+    struct Vmxnet3_TxQueueConf        conf;
+
+    /* Driver read after a GET command */
+    struct Vmxnet3_QueueStatus        status;
+    struct UPT1_TxStats            stats;
+    u8                    _pad[88]; /* 128 aligned */
+};
+
+
+struct Vmxnet3_RxQueueDesc {
+    struct Vmxnet3_RxQueueCtrl        ctrl;
+    struct Vmxnet3_RxQueueConf        conf;
+    /* Driver read after a GET commad */
+    struct Vmxnet3_QueueStatus        status;
+    struct UPT1_RxStats            stats;
+    u8                      __pad[88]; /* 128 aligned */
+};
+
+
+struct Vmxnet3_DSDevRead {
+    /* read-only region for device, read by dev in response to a SET cmd */
+    struct Vmxnet3_MiscConf            misc;
+    struct Vmxnet3_IntrConf            intrConf;
+    struct Vmxnet3_RxFilterConf        rxFilterConf;
+    struct Vmxnet3_VariableLenConfDesc    rssConfDesc;
+    struct Vmxnet3_VariableLenConfDesc    pmConfDesc;
+    struct Vmxnet3_VariableLenConfDesc    pluginConfDesc;
+};
+
+/* All structures in DriverShared are padded to multiples of 8 bytes */
+struct Vmxnet3_DriverShared {
+    __le32              magic;
+    /* make devRead start at 64bit boundaries */
+    __le32              pad;
+    struct Vmxnet3_DSDevRead    devRead;
+    __le32              ecr;
+    __le32              reserved[5];
+};
+
+
+#define VMXNET3_ECR_RQERR       (1 << 0)
+#define VMXNET3_ECR_TQERR       (1 << 1)
+#define VMXNET3_ECR_LINK        (1 << 2)
+#define VMXNET3_ECR_DIC         (1 << 3)
+#define VMXNET3_ECR_DEBUG       (1 << 4)
+
+/* flip the gen bit of a ring */
+#define VMXNET3_FLIP_RING_GEN(gen) ((gen) = (gen) ^ 0x1)
+
+/* only use this if moving the idx won't affect the gen bit */
+#define VMXNET3_INC_RING_IDX_ONLY(idx, ring_size) \
+    do {\
+        (idx)++;\
+        if (unlikely((idx) == (ring_size))) {\
+            (idx) = 0;\
+        } \
+    } while (0)
+
+#define VMXNET3_SET_VFTABLE_ENTRY(vfTable, vid) \
+    (vfTable[vid >> 5] |= (1 << (vid & 31)))
+#define VMXNET3_CLEAR_VFTABLE_ENTRY(vfTable, vid) \
+    (vfTable[vid >> 5] &= ~(1 << (vid & 31)))
+
+#define VMXNET3_VFTABLE_ENTRY_IS_SET(vfTable, vid) \
+    ((vfTable[vid >> 5] & (1 << (vid & 31))) != 0)
+
+#define VMXNET3_MAX_MTU     9000
+#define VMXNET3_MIN_MTU     60
+
+#define VMXNET3_LINK_UP         (10000 << 16 | 1)    /* 10 Gbps, up */
+#define VMXNET3_LINK_DOWN       0
+
+#undef u64
+#undef u32
+#undef u16
+#undef u8
+#undef __le16
+#undef __le32
+#undef __le64
+#undef __packed
+#if defined(HOST_WORDS_BIGENDIAN)
+#undef __BIG_ENDIAN_BITFIELD
+#endif
+
+#endif
diff --git a/hw/net/vmxnet_debug.h b/hw/net/vmxnet_debug.h
new file mode 100644 (file)
index 0000000..96dae0f
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * QEMU VMWARE VMXNET* paravirtual NICs - debugging facilities
+ *
+ * Copyright (c) 2012 Ravello Systems LTD (http://ravellosystems.com)
+ *
+ * Developed by Daynix Computing LTD (http://www.daynix.com)
+ *
+ * Authors:
+ * Dmitry Fleytman <dmitry@daynix.com>
+ * Tamir Shomer <tamirs@daynix.com>
+ * Yan Vugenfirer <yan@daynix.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_VMXNET_DEBUG_H
+#define _QEMU_VMXNET_DEBUG_H
+
+#define VMXNET_DEVICE_NAME "vmxnet3"
+
+/* #define VMXNET_DEBUG_CB */
+#define VMXNET_DEBUG_WARNINGS
+#define VMXNET_DEBUG_ERRORS
+/* #define VMXNET_DEBUG_INTERRUPTS */
+/* #define VMXNET_DEBUG_CONFIG */
+/* #define VMXNET_DEBUG_RINGS */
+/* #define VMXNET_DEBUG_PACKETS */
+/* #define VMXNET_DEBUG_SHMEM_ACCESS */
+
+#ifdef VMXNET_DEBUG_SHMEM_ACCESS
+#define VMW_SHPRN(fmt, ...)                                                   \
+    do {                                                                      \
+        printf("[%s][SH][%s]: " fmt "\n", VMXNET_DEVICE_NAME, __func__,       \
+            ## __VA_ARGS__);                                                  \
+    } while (0)
+#else
+#define VMW_SHPRN(fmt, ...) do {} while (0)
+#endif
+
+#ifdef VMXNET_DEBUG_CB
+#define VMW_CBPRN(fmt, ...)                                                   \
+    do {                                                                      \
+        printf("[%s][CB][%s]: " fmt "\n", VMXNET_DEVICE_NAME, __func__,       \
+            ## __VA_ARGS__);                                                  \
+    } while (0)
+#else
+#define VMW_CBPRN(fmt, ...) do {} while (0)
+#endif
+
+#ifdef VMXNET_DEBUG_PACKETS
+#define VMW_PKPRN(fmt, ...)                                                   \
+    do {                                                                      \
+        printf("[%s][PK][%s]: " fmt "\n", VMXNET_DEVICE_NAME, __func__,       \
+            ## __VA_ARGS__);                                                  \
+    } while (0)
+#else
+#define VMW_PKPRN(fmt, ...) do {} while (0)
+#endif
+
+#ifdef VMXNET_DEBUG_WARNINGS
+#define VMW_WRPRN(fmt, ...)                                                   \
+    do {                                                                      \
+        printf("[%s][WR][%s]: " fmt "\n", VMXNET_DEVICE_NAME, __func__,       \
+            ## __VA_ARGS__);                                                  \
+    } while (0)
+#else
+#define VMW_WRPRN(fmt, ...) do {} while (0)
+#endif
+
+#ifdef VMXNET_DEBUG_ERRORS
+#define VMW_ERPRN(fmt, ...)                                                   \
+    do {                                                                      \
+        printf("[%s][ER][%s]: " fmt "\n", VMXNET_DEVICE_NAME, __func__,       \
+            ## __VA_ARGS__);                                                  \
+    } while (0)
+#else
+#define VMW_ERPRN(fmt, ...) do {} while (0)
+#endif
+
+#ifdef VMXNET_DEBUG_INTERRUPTS
+#define VMW_IRPRN(fmt, ...)                                                   \
+    do {                                                                      \
+        printf("[%s][IR][%s]: " fmt "\n", VMXNET_DEVICE_NAME, __func__,       \
+            ## __VA_ARGS__);                                                  \
+    } while (0)
+#else
+#define VMW_IRPRN(fmt, ...) do {} while (0)
+#endif
+
+#ifdef VMXNET_DEBUG_CONFIG
+#define VMW_CFPRN(fmt, ...)                                                   \
+    do {                                                                      \
+        printf("[%s][CF][%s]: " fmt "\n", VMXNET_DEVICE_NAME, __func__,       \
+            ## __VA_ARGS__);                                                  \
+    } while (0)
+#else
+#define VMW_CFPRN(fmt, ...) do {} while (0)
+#endif
+
+#ifdef VMXNET_DEBUG_RINGS
+#define VMW_RIPRN(fmt, ...)                                                   \
+    do {                                                                      \
+        printf("[%s][RI][%s]: " fmt "\n", VMXNET_DEVICE_NAME, __func__,       \
+            ## __VA_ARGS__);                                                  \
+    } while (0)
+#else
+#define VMW_RIPRN(fmt, ...) do {} while (0)
+#endif
+
+#define VMXNET_MF       "%02X:%02X:%02X:%02X:%02X:%02X"
+#define VMXNET_MA(a)    (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
+
+#endif /* _QEMU_VMXNET3_DEBUG_H  */
diff --git a/hw/net/vmxnet_rx_pkt.c b/hw/net/vmxnet_rx_pkt.c
new file mode 100644 (file)
index 0000000..a40e346
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * QEMU VMWARE VMXNET* paravirtual NICs - RX packets abstractions
+ *
+ * Copyright (c) 2012 Ravello Systems LTD (http://ravellosystems.com)
+ *
+ * Developed by Daynix Computing LTD (http://www.daynix.com)
+ *
+ * Authors:
+ * Dmitry Fleytman <dmitry@daynix.com>
+ * Tamir Shomer <tamirs@daynix.com>
+ * Yan Vugenfirer <yan@daynix.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 "vmxnet_rx_pkt.h"
+#include "net/eth.h"
+#include "qemu-common.h"
+#include "qemu/iov.h"
+#include "net/checksum.h"
+#include "net/tap.h"
+
+/*
+ * RX packet may contain up to 2 fragments - rebuilt eth header
+ * in case of VLAN tag stripping
+ * and payload received from QEMU - in any case
+ */
+#define VMXNET_MAX_RX_PACKET_FRAGMENTS (2)
+
+struct VmxnetRxPkt {
+    struct virtio_net_hdr virt_hdr;
+    uint8_t ehdr_buf[ETH_MAX_L2_HDR_LEN];
+    struct iovec vec[VMXNET_MAX_RX_PACKET_FRAGMENTS];
+    uint16_t vec_len;
+    uint32_t tot_len;
+    uint16_t tci;
+    bool vlan_stripped;
+    bool has_virt_hdr;
+    eth_pkt_types_e packet_type;
+
+    /* Analysis results */
+    bool isip4;
+    bool isip6;
+    bool isudp;
+    bool istcp;
+};
+
+void vmxnet_rx_pkt_init(struct VmxnetRxPkt **pkt, bool has_virt_hdr)
+{
+    struct VmxnetRxPkt *p = g_malloc0(sizeof *p);
+    p->has_virt_hdr = has_virt_hdr;
+    *pkt = p;
+}
+
+void vmxnet_rx_pkt_uninit(struct VmxnetRxPkt *pkt)
+{
+    g_free(pkt);
+}
+
+struct virtio_net_hdr *vmxnet_rx_pkt_get_vhdr(struct VmxnetRxPkt *pkt)
+{
+    assert(pkt);
+    return &pkt->virt_hdr;
+}
+
+void vmxnet_rx_pkt_attach_data(struct VmxnetRxPkt *pkt, const void *data,
+                               size_t len, bool strip_vlan)
+{
+    uint16_t tci = 0;
+    uint16_t ploff;
+    assert(pkt);
+    pkt->vlan_stripped = false;
+
+    if (strip_vlan) {
+        pkt->vlan_stripped = eth_strip_vlan(data, pkt->ehdr_buf, &ploff, &tci);
+    }
+
+    if (pkt->vlan_stripped) {
+        pkt->vec[0].iov_base = pkt->ehdr_buf;
+        pkt->vec[0].iov_len = ploff - sizeof(struct vlan_header);
+        pkt->vec[1].iov_base = (uint8_t *) data + ploff;
+        pkt->vec[1].iov_len = len - ploff;
+        pkt->vec_len = 2;
+        pkt->tot_len = len - ploff + sizeof(struct eth_header);
+    } else {
+        pkt->vec[0].iov_base = (void *)data;
+        pkt->vec[0].iov_len = len;
+        pkt->vec_len = 1;
+        pkt->tot_len = len;
+    }
+
+    pkt->tci = tci;
+
+    eth_get_protocols(data, len, &pkt->isip4, &pkt->isip6,
+        &pkt->isudp, &pkt->istcp);
+}
+
+void vmxnet_rx_pkt_dump(struct VmxnetRxPkt *pkt)
+{
+#ifdef VMXNET_RX_PKT_DEBUG
+    VmxnetRxPkt *pkt = (VmxnetRxPkt *)pkt;
+    assert(pkt);
+
+    printf("RX PKT: tot_len: %d, vlan_stripped: %d, vlan_tag: %d\n",
+              pkt->tot_len, pkt->vlan_stripped, pkt->tci);
+#endif
+}
+
+void vmxnet_rx_pkt_set_packet_type(struct VmxnetRxPkt *pkt,
+    eth_pkt_types_e packet_type)
+{
+    assert(pkt);
+
+    pkt->packet_type = packet_type;
+
+}
+
+eth_pkt_types_e vmxnet_rx_pkt_get_packet_type(struct VmxnetRxPkt *pkt)
+{
+    assert(pkt);
+
+    return pkt->packet_type;
+}
+
+size_t vmxnet_rx_pkt_get_total_len(struct VmxnetRxPkt *pkt)
+{
+    assert(pkt);
+
+    return pkt->tot_len;
+}
+
+void vmxnet_rx_pkt_get_protocols(struct VmxnetRxPkt *pkt,
+                                 bool *isip4, bool *isip6,
+                                 bool *isudp, bool *istcp)
+{
+    assert(pkt);
+
+    *isip4 = pkt->isip4;
+    *isip6 = pkt->isip6;
+    *isudp = pkt->isudp;
+    *istcp = pkt->istcp;
+}
+
+struct iovec *vmxnet_rx_pkt_get_iovec(struct VmxnetRxPkt *pkt)
+{
+    assert(pkt);
+
+    return pkt->vec;
+}
+
+void vmxnet_rx_pkt_set_vhdr(struct VmxnetRxPkt *pkt,
+                            struct virtio_net_hdr *vhdr)
+{
+    assert(pkt);
+
+    memcpy(&pkt->virt_hdr, vhdr, sizeof pkt->virt_hdr);
+}
+
+bool vmxnet_rx_pkt_is_vlan_stripped(struct VmxnetRxPkt *pkt)
+{
+    assert(pkt);
+
+    return pkt->vlan_stripped;
+}
+
+bool vmxnet_rx_pkt_has_virt_hdr(struct VmxnetRxPkt *pkt)
+{
+    assert(pkt);
+
+    return pkt->has_virt_hdr;
+}
+
+uint16_t vmxnet_rx_pkt_get_num_frags(struct VmxnetRxPkt *pkt)
+{
+    assert(pkt);
+
+    return pkt->vec_len;
+}
+
+uint16_t vmxnet_rx_pkt_get_vlan_tag(struct VmxnetRxPkt *pkt)
+{
+    assert(pkt);
+
+    return pkt->tci;
+}
diff --git a/hw/net/vmxnet_rx_pkt.h b/hw/net/vmxnet_rx_pkt.h
new file mode 100644 (file)
index 0000000..6b2c60e
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ * QEMU VMWARE VMXNET* paravirtual NICs - RX packets abstraction
+ *
+ * Copyright (c) 2012 Ravello Systems LTD (http://ravellosystems.com)
+ *
+ * Developed by Daynix Computing LTD (http://www.daynix.com)
+ *
+ * Authors:
+ * Dmitry Fleytman <dmitry@daynix.com>
+ * Tamir Shomer <tamirs@daynix.com>
+ * Yan Vugenfirer <yan@daynix.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 VMXNET_RX_PKT_H
+#define VMXNET_RX_PKT_H
+
+#include "stdint.h"
+#include "stdbool.h"
+#include "net/eth.h"
+
+/* defines to enable packet dump functions */
+/*#define VMXNET_RX_PKT_DEBUG*/
+
+struct VmxnetRxPkt;
+
+/**
+ * Clean all rx packet resources
+ *
+ * @pkt:            packet
+ *
+ */
+void vmxnet_rx_pkt_uninit(struct VmxnetRxPkt *pkt);
+
+/**
+ * Init function for rx packet functionality
+ *
+ * @pkt:            packet pointer
+ * @has_virt_hdr:   device uses virtio header
+ *
+ */
+void vmxnet_rx_pkt_init(struct VmxnetRxPkt **pkt, bool has_virt_hdr);
+
+/**
+ * returns total length of data attached to rx context
+ *
+ * @pkt:            packet
+ *
+ * Return:  nothing
+ *
+ */
+size_t vmxnet_rx_pkt_get_total_len(struct VmxnetRxPkt *pkt);
+
+/**
+ * fetches packet analysis results
+ *
+ * @pkt:            packet
+ * @isip4:          whether the packet given is IPv4
+ * @isip6:          whether the packet given is IPv6
+ * @isudp:          whether the packet given is UDP
+ * @istcp:          whether the packet given is TCP
+ *
+ */
+void vmxnet_rx_pkt_get_protocols(struct VmxnetRxPkt *pkt,
+                                 bool *isip4, bool *isip6,
+                                 bool *isudp, bool *istcp);
+
+/**
+ * returns virtio header stored in rx context
+ *
+ * @pkt:            packet
+ * @ret:            virtio header
+ *
+ */
+struct virtio_net_hdr *vmxnet_rx_pkt_get_vhdr(struct VmxnetRxPkt *pkt);
+
+/**
+ * returns packet type
+ *
+ * @pkt:            packet
+ * @ret:            packet type
+ *
+ */
+eth_pkt_types_e vmxnet_rx_pkt_get_packet_type(struct VmxnetRxPkt *pkt);
+
+/**
+ * returns vlan tag
+ *
+ * @pkt:            packet
+ * @ret:            VLAN tag
+ *
+ */
+uint16_t vmxnet_rx_pkt_get_vlan_tag(struct VmxnetRxPkt *pkt);
+
+/**
+ * tells whether vlan was stripped from the packet
+ *
+ * @pkt:            packet
+ * @ret:            VLAN stripped sign
+ *
+ */
+bool vmxnet_rx_pkt_is_vlan_stripped(struct VmxnetRxPkt *pkt);
+
+/**
+ * notifies caller if the packet has virtio header
+ *
+ * @pkt:            packet
+ * @ret:            true if packet has virtio header, false otherwize
+ *
+ */
+bool vmxnet_rx_pkt_has_virt_hdr(struct VmxnetRxPkt *pkt);
+
+/**
+ * returns number of frags attached to the packet
+ *
+ * @pkt:            packet
+ * @ret:            number of frags
+ *
+ */
+uint16_t vmxnet_rx_pkt_get_num_frags(struct VmxnetRxPkt *pkt);
+
+/**
+ * attach data to rx packet
+ *
+ * @pkt:            packet
+ * @data:           pointer to the data buffer
+ * @len:            data length
+ * @strip_vlan:     should the module strip vlan from data
+ *
+ */
+void vmxnet_rx_pkt_attach_data(struct VmxnetRxPkt *pkt, const void *data,
+    size_t len, bool strip_vlan);
+
+/**
+ * returns io vector that holds the attached data
+ *
+ * @pkt:            packet
+ * @ret:            pointer to IOVec
+ *
+ */
+struct iovec *vmxnet_rx_pkt_get_iovec(struct VmxnetRxPkt *pkt);
+
+/**
+ * prints rx packet data if debug is enabled
+ *
+ * @pkt:            packet
+ *
+ */
+void vmxnet_rx_pkt_dump(struct VmxnetRxPkt *pkt);
+
+/**
+ * copy passed vhdr data to packet context
+ *
+ * @pkt:            packet
+ * @vhdr:           VHDR buffer
+ *
+ */
+void vmxnet_rx_pkt_set_vhdr(struct VmxnetRxPkt *pkt,
+    struct virtio_net_hdr *vhdr);
+
+/**
+ * save packet type in packet context
+ *
+ * @pkt:            packet
+ * @packet_type:    the packet type
+ *
+ */
+void vmxnet_rx_pkt_set_packet_type(struct VmxnetRxPkt *pkt,
+    eth_pkt_types_e packet_type);
+
+#endif
diff --git a/hw/net/vmxnet_tx_pkt.c b/hw/net/vmxnet_tx_pkt.c
new file mode 100644 (file)
index 0000000..b1e795b
--- /dev/null
@@ -0,0 +1,567 @@
+/*
+ * QEMU VMWARE VMXNET* paravirtual NICs - TX packets abstractions
+ *
+ * Copyright (c) 2012 Ravello Systems LTD (http://ravellosystems.com)
+ *
+ * Developed by Daynix Computing LTD (http://www.daynix.com)
+ *
+ * Authors:
+ * Dmitry Fleytman <dmitry@daynix.com>
+ * Tamir Shomer <tamirs@daynix.com>
+ * Yan Vugenfirer <yan@daynix.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 "vmxnet_tx_pkt.h"
+#include "net/eth.h"
+#include "qemu-common.h"
+#include "qemu/iov.h"
+#include "net/checksum.h"
+#include "net/tap.h"
+#include "net/net.h"
+#include "exec/cpu-common.h"
+
+enum {
+    VMXNET_TX_PKT_VHDR_FRAG = 0,
+    VMXNET_TX_PKT_L2HDR_FRAG,
+    VMXNET_TX_PKT_L3HDR_FRAG,
+    VMXNET_TX_PKT_PL_START_FRAG
+};
+
+/* TX packet private context */
+struct VmxnetTxPkt {
+    struct virtio_net_hdr virt_hdr;
+    bool has_virt_hdr;
+
+    struct iovec *raw;
+    uint32_t raw_frags;
+    uint32_t max_raw_frags;
+
+    struct iovec *vec;
+
+    uint8_t l2_hdr[ETH_MAX_L2_HDR_LEN];
+
+    uint32_t payload_len;
+
+    uint32_t payload_frags;
+    uint32_t max_payload_frags;
+
+    uint16_t hdr_len;
+    eth_pkt_types_e packet_type;
+    uint8_t l4proto;
+};
+
+void vmxnet_tx_pkt_init(struct VmxnetTxPkt **pkt, uint32_t max_frags,
+    bool has_virt_hdr)
+{
+    struct VmxnetTxPkt *p = g_malloc0(sizeof *p);
+
+    p->vec = g_malloc((sizeof *p->vec) *
+        (max_frags + VMXNET_TX_PKT_PL_START_FRAG));
+
+    p->raw = g_malloc((sizeof *p->raw) * max_frags);
+
+    p->max_payload_frags = max_frags;
+    p->max_raw_frags = max_frags;
+    p->has_virt_hdr = has_virt_hdr;
+    p->vec[VMXNET_TX_PKT_VHDR_FRAG].iov_base = &p->virt_hdr;
+    p->vec[VMXNET_TX_PKT_VHDR_FRAG].iov_len =
+        p->has_virt_hdr ? sizeof p->virt_hdr : 0;
+    p->vec[VMXNET_TX_PKT_L2HDR_FRAG].iov_base = &p->l2_hdr;
+    p->vec[VMXNET_TX_PKT_L3HDR_FRAG].iov_base = NULL;
+    p->vec[VMXNET_TX_PKT_L3HDR_FRAG].iov_len = 0;
+
+    *pkt = p;
+}
+
+void vmxnet_tx_pkt_uninit(struct VmxnetTxPkt *pkt)
+{
+    if (pkt) {
+        g_free(pkt->vec);
+        g_free(pkt->raw);
+        g_free(pkt);
+    }
+}
+
+void vmxnet_tx_pkt_update_ip_checksums(struct VmxnetTxPkt *pkt)
+{
+    uint16_t csum;
+    uint32_t ph_raw_csum;
+    assert(pkt);
+    uint8_t gso_type = pkt->virt_hdr.gso_type & ~VIRTIO_NET_HDR_GSO_ECN;
+    struct ip_header *ip_hdr;
+
+    if (VIRTIO_NET_HDR_GSO_TCPV4 != gso_type &&
+        VIRTIO_NET_HDR_GSO_UDP != gso_type) {
+        return;
+    }
+
+    ip_hdr = pkt->vec[VMXNET_TX_PKT_L3HDR_FRAG].iov_base;
+
+    if (pkt->payload_len + pkt->vec[VMXNET_TX_PKT_L3HDR_FRAG].iov_len >
+        ETH_MAX_IP_DGRAM_LEN) {
+        return;
+    }
+
+    ip_hdr->ip_len = cpu_to_be16(pkt->payload_len +
+        pkt->vec[VMXNET_TX_PKT_L3HDR_FRAG].iov_len);
+
+    /* Calculate IP header checksum                    */
+    ip_hdr->ip_sum = 0;
+    csum = net_raw_checksum((uint8_t *)ip_hdr,
+        pkt->vec[VMXNET_TX_PKT_L3HDR_FRAG].iov_len);
+    ip_hdr->ip_sum = cpu_to_be16(csum);
+
+    /* Calculate IP pseudo header checksum             */
+    ph_raw_csum = eth_calc_pseudo_hdr_csum(ip_hdr, pkt->payload_len);
+    csum = cpu_to_be16(~net_checksum_finish(ph_raw_csum));
+    iov_from_buf(&pkt->vec[VMXNET_TX_PKT_PL_START_FRAG], pkt->payload_frags,
+                 pkt->virt_hdr.csum_offset, &csum, sizeof(csum));
+}
+
+static void vmxnet_tx_pkt_calculate_hdr_len(struct VmxnetTxPkt *pkt)
+{
+    pkt->hdr_len = pkt->vec[VMXNET_TX_PKT_L2HDR_FRAG].iov_len +
+        pkt->vec[VMXNET_TX_PKT_L3HDR_FRAG].iov_len;
+}
+
+static bool vmxnet_tx_pkt_parse_headers(struct VmxnetTxPkt *pkt)
+{
+    struct iovec *l2_hdr, *l3_hdr;
+    size_t bytes_read;
+    size_t full_ip6hdr_len;
+    uint16_t l3_proto;
+
+    assert(pkt);
+
+    l2_hdr = &pkt->vec[VMXNET_TX_PKT_L2HDR_FRAG];
+    l3_hdr = &pkt->vec[VMXNET_TX_PKT_L3HDR_FRAG];
+
+    bytes_read = iov_to_buf(pkt->raw, pkt->raw_frags, 0, l2_hdr->iov_base,
+                            ETH_MAX_L2_HDR_LEN);
+    if (bytes_read < ETH_MAX_L2_HDR_LEN) {
+        l2_hdr->iov_len = 0;
+        return false;
+    } else {
+        l2_hdr->iov_len = eth_get_l2_hdr_length(l2_hdr->iov_base);
+    }
+
+    l3_proto = eth_get_l3_proto(l2_hdr->iov_base, l2_hdr->iov_len);
+
+    switch (l3_proto) {
+    case ETH_P_IP:
+        l3_hdr->iov_base = g_malloc(ETH_MAX_IP4_HDR_LEN);
+
+        bytes_read = iov_to_buf(pkt->raw, pkt->raw_frags, l2_hdr->iov_len,
+                                l3_hdr->iov_base, sizeof(struct ip_header));
+
+        if (bytes_read < sizeof(struct ip_header)) {
+            l3_hdr->iov_len = 0;
+            return false;
+        }
+
+        l3_hdr->iov_len = IP_HDR_GET_LEN(l3_hdr->iov_base);
+        pkt->l4proto = ((struct ip_header *) l3_hdr->iov_base)->ip_p;
+
+        /* copy optional IPv4 header data */
+        bytes_read = iov_to_buf(pkt->raw, pkt->raw_frags,
+                                l2_hdr->iov_len + sizeof(struct ip_header),
+                                l3_hdr->iov_base + sizeof(struct ip_header),
+                                l3_hdr->iov_len - sizeof(struct ip_header));
+        if (bytes_read < l3_hdr->iov_len - sizeof(struct ip_header)) {
+            l3_hdr->iov_len = 0;
+            return false;
+        }
+        break;
+
+    case ETH_P_IPV6:
+        if (!eth_parse_ipv6_hdr(pkt->raw, pkt->raw_frags, l2_hdr->iov_len,
+                               &pkt->l4proto, &full_ip6hdr_len)) {
+            l3_hdr->iov_len = 0;
+            return false;
+        }
+
+        l3_hdr->iov_base = g_malloc(full_ip6hdr_len);
+
+        bytes_read = iov_to_buf(pkt->raw, pkt->raw_frags, l2_hdr->iov_len,
+                                l3_hdr->iov_base, full_ip6hdr_len);
+
+        if (bytes_read < full_ip6hdr_len) {
+            l3_hdr->iov_len = 0;
+            return false;
+        } else {
+            l3_hdr->iov_len = full_ip6hdr_len;
+        }
+        break;
+
+    default:
+        l3_hdr->iov_len = 0;
+        break;
+    }
+
+    vmxnet_tx_pkt_calculate_hdr_len(pkt);
+    pkt->packet_type = get_eth_packet_type(l2_hdr->iov_base);
+    return true;
+}
+
+static bool vmxnet_tx_pkt_rebuild_payload(struct VmxnetTxPkt *pkt)
+{
+    size_t payload_len = iov_size(pkt->raw, pkt->raw_frags) - pkt->hdr_len;
+
+    pkt->payload_frags = iov_copy(&pkt->vec[VMXNET_TX_PKT_PL_START_FRAG],
+                                pkt->max_payload_frags,
+                                pkt->raw, pkt->raw_frags,
+                                pkt->hdr_len, payload_len);
+
+    if (pkt->payload_frags != (uint32_t) -1) {
+        pkt->payload_len = payload_len;
+        return true;
+    } else {
+        return false;
+    }
+}
+
+bool vmxnet_tx_pkt_parse(struct VmxnetTxPkt *pkt)
+{
+    return vmxnet_tx_pkt_parse_headers(pkt) &&
+           vmxnet_tx_pkt_rebuild_payload(pkt);
+}
+
+struct virtio_net_hdr *vmxnet_tx_pkt_get_vhdr(struct VmxnetTxPkt *pkt)
+{
+    assert(pkt);
+    return &pkt->virt_hdr;
+}
+
+static uint8_t vmxnet_tx_pkt_get_gso_type(struct VmxnetTxPkt *pkt,
+                                          bool tso_enable)
+{
+    uint8_t rc = VIRTIO_NET_HDR_GSO_NONE;
+    uint16_t l3_proto;
+
+    l3_proto = eth_get_l3_proto(pkt->vec[VMXNET_TX_PKT_L2HDR_FRAG].iov_base,
+        pkt->vec[VMXNET_TX_PKT_L2HDR_FRAG].iov_len);
+
+    if (!tso_enable) {
+        goto func_exit;
+    }
+
+    rc = eth_get_gso_type(l3_proto, pkt->vec[VMXNET_TX_PKT_L3HDR_FRAG].iov_base,
+                          pkt->l4proto);
+
+func_exit:
+    return rc;
+}
+
+void vmxnet_tx_pkt_build_vheader(struct VmxnetTxPkt *pkt, bool tso_enable,
+    bool csum_enable, uint32_t gso_size)
+{
+    struct tcp_hdr l4hdr;
+    assert(pkt);
+
+    /* csum has to be enabled if tso is. */
+    assert(csum_enable || !tso_enable);
+
+    pkt->virt_hdr.gso_type = vmxnet_tx_pkt_get_gso_type(pkt, tso_enable);
+
+    switch (pkt->virt_hdr.gso_type & ~VIRTIO_NET_HDR_GSO_ECN) {
+    case VIRTIO_NET_HDR_GSO_NONE:
+        pkt->virt_hdr.hdr_len = 0;
+        pkt->virt_hdr.gso_size = 0;
+        break;
+
+    case VIRTIO_NET_HDR_GSO_UDP:
+        pkt->virt_hdr.gso_size = IP_FRAG_ALIGN_SIZE(gso_size);
+        pkt->virt_hdr.hdr_len = pkt->hdr_len + sizeof(struct udp_header);
+        break;
+
+    case VIRTIO_NET_HDR_GSO_TCPV4:
+    case VIRTIO_NET_HDR_GSO_TCPV6:
+        iov_to_buf(&pkt->vec[VMXNET_TX_PKT_PL_START_FRAG], pkt->payload_frags,
+                   0, &l4hdr, sizeof(l4hdr));
+        pkt->virt_hdr.hdr_len = pkt->hdr_len + l4hdr.th_off * sizeof(uint32_t);
+        pkt->virt_hdr.gso_size = IP_FRAG_ALIGN_SIZE(gso_size);
+        break;
+
+    default:
+        assert(false);
+    }
+
+    if (csum_enable) {
+        switch (pkt->l4proto) {
+        case IP_PROTO_TCP:
+            pkt->virt_hdr.flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
+            pkt->virt_hdr.csum_start = pkt->hdr_len;
+            pkt->virt_hdr.csum_offset = offsetof(struct tcp_hdr, th_sum);
+            break;
+        case IP_PROTO_UDP:
+            pkt->virt_hdr.flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
+            pkt->virt_hdr.csum_start = pkt->hdr_len;
+            pkt->virt_hdr.csum_offset = offsetof(struct udp_hdr, uh_sum);
+            break;
+        default:
+            break;
+        }
+    }
+}
+
+void vmxnet_tx_pkt_setup_vlan_header(struct VmxnetTxPkt *pkt, uint16_t vlan)
+{
+    bool is_new;
+    assert(pkt);
+
+    eth_setup_vlan_headers(pkt->vec[VMXNET_TX_PKT_L2HDR_FRAG].iov_base,
+        vlan, &is_new);
+
+    /* update l2hdrlen */
+    if (is_new) {
+        pkt->hdr_len += sizeof(struct vlan_header);
+        pkt->vec[VMXNET_TX_PKT_L2HDR_FRAG].iov_len +=
+            sizeof(struct vlan_header);
+    }
+}
+
+bool vmxnet_tx_pkt_add_raw_fragment(struct VmxnetTxPkt *pkt, hwaddr pa,
+    size_t len)
+{
+    hwaddr mapped_len = 0;
+    struct iovec *ventry;
+    assert(pkt);
+    assert(pkt->max_raw_frags > pkt->raw_frags);
+
+    if (!len) {
+        return true;
+     }
+
+    ventry = &pkt->raw[pkt->raw_frags];
+    mapped_len = len;
+
+    ventry->iov_base = cpu_physical_memory_map(pa, &mapped_len, false);
+    ventry->iov_len = mapped_len;
+    pkt->raw_frags += !!ventry->iov_base;
+
+    if ((ventry->iov_base == NULL) || (len != mapped_len)) {
+        return false;
+    }
+
+    return true;
+}
+
+eth_pkt_types_e vmxnet_tx_pkt_get_packet_type(struct VmxnetTxPkt *pkt)
+{
+    assert(pkt);
+
+    return pkt->packet_type;
+}
+
+size_t vmxnet_tx_pkt_get_total_len(struct VmxnetTxPkt *pkt)
+{
+    assert(pkt);
+
+    return pkt->hdr_len + pkt->payload_len;
+}
+
+void vmxnet_tx_pkt_dump(struct VmxnetTxPkt *pkt)
+{
+#ifdef VMXNET_TX_PKT_DEBUG
+    assert(pkt);
+
+    printf("TX PKT: hdr_len: %d, pkt_type: 0x%X, l2hdr_len: %lu, "
+        "l3hdr_len: %lu, payload_len: %u\n", pkt->hdr_len, pkt->packet_type,
+        pkt->vec[VMXNET_TX_PKT_L2HDR_FRAG].iov_len,
+        pkt->vec[VMXNET_TX_PKT_L3HDR_FRAG].iov_len, pkt->payload_len);
+#endif
+}
+
+void vmxnet_tx_pkt_reset(struct VmxnetTxPkt *pkt)
+{
+    int i;
+
+    /* no assert, as reset can be called before tx_pkt_init */
+    if (!pkt) {
+        return;
+    }
+
+    memset(&pkt->virt_hdr, 0, sizeof(pkt->virt_hdr));
+
+    g_free(pkt->vec[VMXNET_TX_PKT_L3HDR_FRAG].iov_base);
+    pkt->vec[VMXNET_TX_PKT_L3HDR_FRAG].iov_base = NULL;
+
+    assert(pkt->vec);
+    for (i = VMXNET_TX_PKT_L2HDR_FRAG;
+         i < pkt->payload_frags + VMXNET_TX_PKT_PL_START_FRAG; i++) {
+        pkt->vec[i].iov_len = 0;
+    }
+    pkt->payload_len = 0;
+    pkt->payload_frags = 0;
+
+    assert(pkt->raw);
+    for (i = 0; i < pkt->raw_frags; i++) {
+        assert(pkt->raw[i].iov_base);
+        cpu_physical_memory_unmap(pkt->raw[i].iov_base, pkt->raw[i].iov_len,
+                                  false, pkt->raw[i].iov_len);
+        pkt->raw[i].iov_len = 0;
+    }
+    pkt->raw_frags = 0;
+
+    pkt->hdr_len = 0;
+    pkt->packet_type = 0;
+    pkt->l4proto = 0;
+}
+
+static void vmxnet_tx_pkt_do_sw_csum(struct VmxnetTxPkt *pkt)
+{
+    struct iovec *iov = &pkt->vec[VMXNET_TX_PKT_L2HDR_FRAG];
+    uint32_t csum_cntr;
+    uint16_t csum = 0;
+    /* num of iovec without vhdr */
+    uint32_t iov_len = pkt->payload_frags + VMXNET_TX_PKT_PL_START_FRAG - 1;
+    uint16_t csl;
+    struct ip_header *iphdr;
+    size_t csum_offset = pkt->virt_hdr.csum_start + pkt->virt_hdr.csum_offset;
+
+    /* Put zero to checksum field */
+    iov_from_buf(iov, iov_len, csum_offset, &csum, sizeof csum);
+
+    /* Calculate L4 TCP/UDP checksum */
+    csl = pkt->payload_len;
+
+    /* data checksum */
+    csum_cntr =
+        net_checksum_add_iov(iov, iov_len, pkt->virt_hdr.csum_start, csl);
+    /* add pseudo header to csum */
+    iphdr = pkt->vec[VMXNET_TX_PKT_L3HDR_FRAG].iov_base;
+    csum_cntr += eth_calc_pseudo_hdr_csum(iphdr, csl);
+
+    /* Put the checksum obtained into the packet */
+    csum = cpu_to_be16(net_checksum_finish(csum_cntr));
+    iov_from_buf(iov, iov_len, csum_offset, &csum, sizeof csum);
+}
+
+enum {
+    VMXNET_TX_PKT_FRAGMENT_L2_HDR_POS = 0,
+    VMXNET_TX_PKT_FRAGMENT_L3_HDR_POS,
+    VMXNET_TX_PKT_FRAGMENT_HEADER_NUM
+};
+
+#define VMXNET_MAX_FRAG_SG_LIST (64)
+
+static size_t vmxnet_tx_pkt_fetch_fragment(struct VmxnetTxPkt *pkt,
+    int *src_idx, size_t *src_offset, struct iovec *dst, int *dst_idx)
+{
+    size_t fetched = 0;
+    struct iovec *src = pkt->vec;
+
+    *dst_idx = VMXNET_TX_PKT_FRAGMENT_HEADER_NUM;
+
+    while (fetched < pkt->virt_hdr.gso_size) {
+
+        /* no more place in fragment iov */
+        if (*dst_idx == VMXNET_MAX_FRAG_SG_LIST) {
+            break;
+        }
+
+        /* no more data in iovec */
+        if (*src_idx == (pkt->payload_frags + VMXNET_TX_PKT_PL_START_FRAG)) {
+            break;
+        }
+
+
+        dst[*dst_idx].iov_base = src[*src_idx].iov_base + *src_offset;
+        dst[*dst_idx].iov_len = MIN(src[*src_idx].iov_len - *src_offset,
+            pkt->virt_hdr.gso_size - fetched);
+
+        *src_offset += dst[*dst_idx].iov_len;
+        fetched += dst[*dst_idx].iov_len;
+
+        if (*src_offset == src[*src_idx].iov_len) {
+            *src_offset = 0;
+            (*src_idx)++;
+        }
+
+        (*dst_idx)++;
+    }
+
+    return fetched;
+}
+
+static bool vmxnet_tx_pkt_do_sw_fragmentation(struct VmxnetTxPkt *pkt,
+    NetClientState *nc)
+{
+    struct iovec fragment[VMXNET_MAX_FRAG_SG_LIST];
+    size_t fragment_len = 0;
+    bool more_frags = false;
+
+    /* some pointers for shorter code */
+    void *l2_iov_base, *l3_iov_base;
+    size_t l2_iov_len, l3_iov_len;
+    int src_idx =  VMXNET_TX_PKT_PL_START_FRAG, dst_idx;
+    size_t src_offset = 0;
+    size_t fragment_offset = 0;
+
+    l2_iov_base = pkt->vec[VMXNET_TX_PKT_L2HDR_FRAG].iov_base;
+    l2_iov_len = pkt->vec[VMXNET_TX_PKT_L2HDR_FRAG].iov_len;
+    l3_iov_base = pkt->vec[VMXNET_TX_PKT_L3HDR_FRAG].iov_base;
+    l3_iov_len = pkt->vec[VMXNET_TX_PKT_L3HDR_FRAG].iov_len;
+
+    /* Copy headers */
+    fragment[VMXNET_TX_PKT_FRAGMENT_L2_HDR_POS].iov_base = l2_iov_base;
+    fragment[VMXNET_TX_PKT_FRAGMENT_L2_HDR_POS].iov_len = l2_iov_len;
+    fragment[VMXNET_TX_PKT_FRAGMENT_L3_HDR_POS].iov_base = l3_iov_base;
+    fragment[VMXNET_TX_PKT_FRAGMENT_L3_HDR_POS].iov_len = l3_iov_len;
+
+
+    /* Put as much data as possible and send */
+    do {
+        fragment_len = vmxnet_tx_pkt_fetch_fragment(pkt, &src_idx, &src_offset,
+            fragment, &dst_idx);
+
+        more_frags = (fragment_offset + fragment_len < pkt->payload_len);
+
+        eth_setup_ip4_fragmentation(l2_iov_base, l2_iov_len, l3_iov_base,
+            l3_iov_len, fragment_len, fragment_offset, more_frags);
+
+        eth_fix_ip4_checksum(l3_iov_base, l3_iov_len);
+
+        qemu_sendv_packet(nc, fragment, dst_idx);
+
+        fragment_offset += fragment_len;
+
+    } while (more_frags);
+
+    return true;
+}
+
+bool vmxnet_tx_pkt_send(struct VmxnetTxPkt *pkt, NetClientState *nc)
+{
+    assert(pkt);
+
+    if (!pkt->has_virt_hdr &&
+        pkt->virt_hdr.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) {
+        vmxnet_tx_pkt_do_sw_csum(pkt);
+    }
+
+    /*
+     * Since underlying infrastructure does not support IP datagrams longer
+     * than 64K we should drop such packets and don't even try to send
+     */
+    if (VIRTIO_NET_HDR_GSO_NONE != pkt->virt_hdr.gso_type) {
+        if (pkt->payload_len >
+            ETH_MAX_IP_DGRAM_LEN -
+            pkt->vec[VMXNET_TX_PKT_L3HDR_FRAG].iov_len) {
+            return false;
+        }
+    }
+
+    if (pkt->has_virt_hdr ||
+        pkt->virt_hdr.gso_type == VIRTIO_NET_HDR_GSO_NONE) {
+        qemu_sendv_packet(nc, pkt->vec,
+            pkt->payload_frags + VMXNET_TX_PKT_PL_START_FRAG);
+        return true;
+    }
+
+    return vmxnet_tx_pkt_do_sw_fragmentation(pkt, nc);
+}
diff --git a/hw/net/vmxnet_tx_pkt.h b/hw/net/vmxnet_tx_pkt.h
new file mode 100644 (file)
index 0000000..57121a6
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * QEMU VMWARE VMXNET* paravirtual NICs - TX packets abstraction
+ *
+ * Copyright (c) 2012 Ravello Systems LTD (http://ravellosystems.com)
+ *
+ * Developed by Daynix Computing LTD (http://www.daynix.com)
+ *
+ * Authors:
+ * Dmitry Fleytman <dmitry@daynix.com>
+ * Tamir Shomer <tamirs@daynix.com>
+ * Yan Vugenfirer <yan@daynix.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 VMXNET_TX_PKT_H
+#define VMXNET_TX_PKT_H
+
+#include "stdint.h"
+#include "stdbool.h"
+#include "net/eth.h"
+#include "exec/hwaddr.h"
+
+/* define to enable packet dump functions */
+/*#define VMXNET_TX_PKT_DEBUG*/
+
+struct VmxnetTxPkt;
+
+/**
+ * Init function for tx packet functionality
+ *
+ * @pkt:            packet pointer
+ * @max_frags:      max tx ip fragments
+ * @has_virt_hdr:   device uses virtio header.
+ */
+void vmxnet_tx_pkt_init(struct VmxnetTxPkt **pkt, uint32_t max_frags,
+    bool has_virt_hdr);
+
+/**
+ * Clean all tx packet resources.
+ *
+ * @pkt:            packet.
+ */
+void vmxnet_tx_pkt_uninit(struct VmxnetTxPkt *pkt);
+
+/**
+ * get virtio header
+ *
+ * @pkt:            packet
+ * @ret:            virtio header
+ */
+struct virtio_net_hdr *vmxnet_tx_pkt_get_vhdr(struct VmxnetTxPkt *pkt);
+
+/**
+ * build virtio header (will be stored in module context)
+ *
+ * @pkt:            packet
+ * @tso_enable:     TSO enabled
+ * @csum_enable:    CSO enabled
+ * @gso_size:       MSS size for TSO
+ *
+ */
+void vmxnet_tx_pkt_build_vheader(struct VmxnetTxPkt *pkt, bool tso_enable,
+    bool csum_enable, uint32_t gso_size);
+
+/**
+ * updates vlan tag, and adds vlan header in case it is missing
+ *
+ * @pkt:            packet
+ * @vlan:           VLAN tag
+ *
+ */
+void vmxnet_tx_pkt_setup_vlan_header(struct VmxnetTxPkt *pkt, uint16_t vlan);
+
+/**
+ * populate data fragment into pkt context.
+ *
+ * @pkt:            packet
+ * @pa:             physical address of fragment
+ * @len:            length of fragment
+ *
+ */
+bool vmxnet_tx_pkt_add_raw_fragment(struct VmxnetTxPkt *pkt, hwaddr pa,
+    size_t len);
+
+/**
+ * fix ip header fields and calculate checksums needed.
+ *
+ * @pkt:            packet
+ *
+ */
+void vmxnet_tx_pkt_update_ip_checksums(struct VmxnetTxPkt *pkt);
+
+/**
+ * get length of all populated data.
+ *
+ * @pkt:            packet
+ * @ret:            total data length
+ *
+ */
+size_t vmxnet_tx_pkt_get_total_len(struct VmxnetTxPkt *pkt);
+
+/**
+ * get packet type
+ *
+ * @pkt:            packet
+ * @ret:            packet type
+ *
+ */
+eth_pkt_types_e vmxnet_tx_pkt_get_packet_type(struct VmxnetTxPkt *pkt);
+
+/**
+ * prints packet data if debug is enabled
+ *
+ * @pkt:            packet
+ *
+ */
+void vmxnet_tx_pkt_dump(struct VmxnetTxPkt *pkt);
+
+/**
+ * reset tx packet private context (needed to be called between packets)
+ *
+ * @pkt:            packet
+ *
+ */
+void vmxnet_tx_pkt_reset(struct VmxnetTxPkt *pkt);
+
+/**
+ * Send packet to qemu. handles sw offloads if vhdr is not supported.
+ *
+ * @pkt:            packet
+ * @nc:             NetClientState
+ * @ret:            operation result
+ *
+ */
+bool vmxnet_tx_pkt_send(struct VmxnetTxPkt *pkt, NetClientState *nc);
+
+/**
+ * parse raw packet data and analyze offload requirements.
+ *
+ * @pkt:            packet
+ *
+ */
+bool vmxnet_tx_pkt_parse(struct VmxnetTxPkt *pkt);
+
+#endif
diff --git a/hw/net/xen_nic.c b/hw/net/xen_nic.c
new file mode 100644 (file)
index 0000000..63918ae
--- /dev/null
@@ -0,0 +1,439 @@
+/*
+ *  xen paravirt network card backend
+ *
+ *  (c) Gerd Hoffmann <kraxel@redhat.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; under version 2 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
+ *  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/>.
+ *
+ *  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>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+#include <inttypes.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/wait.h>
+
+#include "hw/hw.h"
+#include "net/net.h"
+#include "net/checksum.h"
+#include "net/util.h"
+#include "hw/xen/xen_backend.h"
+
+#include <xen/io/netif.h>
+
+/* ------------------------------------------------------------- */
+
+struct XenNetDev {
+    struct XenDevice      xendev;  /* must be first */
+    char                  *mac;
+    int                   tx_work;
+    int                   tx_ring_ref;
+    int                   rx_ring_ref;
+    struct netif_tx_sring *txs;
+    struct netif_rx_sring *rxs;
+    netif_tx_back_ring_t  tx_ring;
+    netif_rx_back_ring_t  rx_ring;
+    NICConf               conf;
+    NICState              *nic;
+};
+
+/* ------------------------------------------------------------- */
+
+static void net_tx_response(struct XenNetDev *netdev, netif_tx_request_t *txp, int8_t st)
+{
+    RING_IDX i = netdev->tx_ring.rsp_prod_pvt;
+    netif_tx_response_t *resp;
+    int notify;
+
+    resp = RING_GET_RESPONSE(&netdev->tx_ring, i);
+    resp->id     = txp->id;
+    resp->status = st;
+
+#if 0
+    if (txp->flags & NETTXF_extra_info) {
+        RING_GET_RESPONSE(&netdev->tx_ring, ++i)->status = NETIF_RSP_NULL;
+    }
+#endif
+
+    netdev->tx_ring.rsp_prod_pvt = ++i;
+    RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&netdev->tx_ring, notify);
+    if (notify) {
+        xen_be_send_notify(&netdev->xendev);
+    }
+
+    if (i == netdev->tx_ring.req_cons) {
+        int more_to_do;
+        RING_FINAL_CHECK_FOR_REQUESTS(&netdev->tx_ring, more_to_do);
+        if (more_to_do) {
+            netdev->tx_work++;
+        }
+    }
+}
+
+static void net_tx_error(struct XenNetDev *netdev, netif_tx_request_t *txp, RING_IDX end)
+{
+#if 0
+    /*
+     * Hmm, why netback fails everything in the ring?
+     * Should we do that even when not supporting SG and TSO?
+     */
+    RING_IDX cons = netdev->tx_ring.req_cons;
+
+    do {
+        make_tx_response(netif, txp, NETIF_RSP_ERROR);
+        if (cons >= end) {
+            break;
+        }
+        txp = RING_GET_REQUEST(&netdev->tx_ring, cons++);
+    } while (1);
+    netdev->tx_ring.req_cons = cons;
+    netif_schedule_work(netif);
+    netif_put(netif);
+#else
+    net_tx_response(netdev, txp, NETIF_RSP_ERROR);
+#endif
+}
+
+static void net_tx_packets(struct XenNetDev *netdev)
+{
+    netif_tx_request_t txreq;
+    RING_IDX rc, rp;
+    void *page;
+    void *tmpbuf = NULL;
+
+    for (;;) {
+        rc = netdev->tx_ring.req_cons;
+        rp = netdev->tx_ring.sring->req_prod;
+        xen_rmb(); /* Ensure we see queued requests up to 'rp'. */
+
+        while ((rc != rp)) {
+            if (RING_REQUEST_CONS_OVERFLOW(&netdev->tx_ring, rc)) {
+                break;
+            }
+            memcpy(&txreq, RING_GET_REQUEST(&netdev->tx_ring, rc), sizeof(txreq));
+            netdev->tx_ring.req_cons = ++rc;
+
+#if 1
+            /* should not happen in theory, we don't announce the *
+             * feature-{sg,gso,whatelse} flags in xenstore (yet?) */
+            if (txreq.flags & NETTXF_extra_info) {
+                xen_be_printf(&netdev->xendev, 0, "FIXME: extra info flag\n");
+                net_tx_error(netdev, &txreq, rc);
+                continue;
+            }
+            if (txreq.flags & NETTXF_more_data) {
+                xen_be_printf(&netdev->xendev, 0, "FIXME: more data flag\n");
+                net_tx_error(netdev, &txreq, rc);
+                continue;
+            }
+#endif
+
+            if (txreq.size < 14) {
+                xen_be_printf(&netdev->xendev, 0, "bad packet size: %d\n", txreq.size);
+                net_tx_error(netdev, &txreq, rc);
+                continue;
+            }
+
+            if ((txreq.offset + txreq.size) > XC_PAGE_SIZE) {
+                xen_be_printf(&netdev->xendev, 0, "error: page crossing\n");
+                net_tx_error(netdev, &txreq, rc);
+                continue;
+            }
+
+            xen_be_printf(&netdev->xendev, 3, "tx packet ref %d, off %d, len %d, flags 0x%x%s%s%s%s\n",
+                          txreq.gref, txreq.offset, txreq.size, txreq.flags,
+                          (txreq.flags & NETTXF_csum_blank)     ? " csum_blank"     : "",
+                          (txreq.flags & NETTXF_data_validated) ? " data_validated" : "",
+                          (txreq.flags & NETTXF_more_data)      ? " more_data"      : "",
+                          (txreq.flags & NETTXF_extra_info)     ? " extra_info"     : "");
+
+            page = xc_gnttab_map_grant_ref(netdev->xendev.gnttabdev,
+                                           netdev->xendev.dom,
+                                           txreq.gref, PROT_READ);
+            if (page == NULL) {
+                xen_be_printf(&netdev->xendev, 0, "error: tx gref dereference failed (%d)\n",
+                              txreq.gref);
+                net_tx_error(netdev, &txreq, rc);
+                continue;
+            }
+            if (txreq.flags & NETTXF_csum_blank) {
+                /* have read-only mapping -> can't fill checksum in-place */
+                if (!tmpbuf) {
+                    tmpbuf = g_malloc(XC_PAGE_SIZE);
+                }
+                memcpy(tmpbuf, page + txreq.offset, txreq.size);
+                net_checksum_calculate(tmpbuf, txreq.size);
+                qemu_send_packet(qemu_get_queue(netdev->nic), tmpbuf,
+                                 txreq.size);
+            } else {
+                qemu_send_packet(qemu_get_queue(netdev->nic),
+                                 page + txreq.offset, txreq.size);
+            }
+            xc_gnttab_munmap(netdev->xendev.gnttabdev, page, 1);
+            net_tx_response(netdev, &txreq, NETIF_RSP_OKAY);
+        }
+        if (!netdev->tx_work) {
+            break;
+        }
+        netdev->tx_work = 0;
+    }
+    g_free(tmpbuf);
+}
+
+/* ------------------------------------------------------------- */
+
+static void net_rx_response(struct XenNetDev *netdev,
+                            netif_rx_request_t *req, int8_t st,
+                            uint16_t offset, uint16_t size,
+                            uint16_t flags)
+{
+    RING_IDX i = netdev->rx_ring.rsp_prod_pvt;
+    netif_rx_response_t *resp;
+    int notify;
+
+    resp = RING_GET_RESPONSE(&netdev->rx_ring, i);
+    resp->offset     = offset;
+    resp->flags      = flags;
+    resp->id         = req->id;
+    resp->status     = (int16_t)size;
+    if (st < 0) {
+        resp->status = (int16_t)st;
+    }
+
+    xen_be_printf(&netdev->xendev, 3, "rx response: idx %d, status %d, flags 0x%x\n",
+                  i, resp->status, resp->flags);
+
+    netdev->rx_ring.rsp_prod_pvt = ++i;
+    RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&netdev->rx_ring, notify);
+    if (notify) {
+        xen_be_send_notify(&netdev->xendev);
+    }
+}
+
+#define NET_IP_ALIGN 2
+
+static int net_rx_ok(NetClientState *nc)
+{
+    struct XenNetDev *netdev = qemu_get_nic_opaque(nc);
+    RING_IDX rc, rp;
+
+    if (netdev->xendev.be_state != XenbusStateConnected) {
+        return 0;
+    }
+
+    rc = netdev->rx_ring.req_cons;
+    rp = netdev->rx_ring.sring->req_prod;
+    xen_rmb();
+
+    if (rc == rp || RING_REQUEST_CONS_OVERFLOW(&netdev->rx_ring, rc)) {
+        xen_be_printf(&netdev->xendev, 2, "%s: no rx buffers (%d/%d)\n",
+                      __FUNCTION__, rc, rp);
+        return 0;
+    }
+    return 1;
+}
+
+static ssize_t net_rx_packet(NetClientState *nc, const uint8_t *buf, size_t size)
+{
+    struct XenNetDev *netdev = qemu_get_nic_opaque(nc);
+    netif_rx_request_t rxreq;
+    RING_IDX rc, rp;
+    void *page;
+
+    if (netdev->xendev.be_state != XenbusStateConnected) {
+        return -1;
+    }
+
+    rc = netdev->rx_ring.req_cons;
+    rp = netdev->rx_ring.sring->req_prod;
+    xen_rmb(); /* Ensure we see queued requests up to 'rp'. */
+
+    if (rc == rp || RING_REQUEST_CONS_OVERFLOW(&netdev->rx_ring, rc)) {
+        xen_be_printf(&netdev->xendev, 2, "no buffer, drop packet\n");
+        return -1;
+    }
+    if (size > XC_PAGE_SIZE - NET_IP_ALIGN) {
+        xen_be_printf(&netdev->xendev, 0, "packet too big (%lu > %ld)",
+                      (unsigned long)size, XC_PAGE_SIZE - NET_IP_ALIGN);
+        return -1;
+    }
+
+    memcpy(&rxreq, RING_GET_REQUEST(&netdev->rx_ring, rc), sizeof(rxreq));
+    netdev->rx_ring.req_cons = ++rc;
+
+    page = xc_gnttab_map_grant_ref(netdev->xendev.gnttabdev,
+                                   netdev->xendev.dom,
+                                   rxreq.gref, PROT_WRITE);
+    if (page == NULL) {
+        xen_be_printf(&netdev->xendev, 0, "error: rx gref dereference failed (%d)\n",
+                      rxreq.gref);
+        net_rx_response(netdev, &rxreq, NETIF_RSP_ERROR, 0, 0, 0);
+        return -1;
+    }
+    memcpy(page + NET_IP_ALIGN, buf, size);
+    xc_gnttab_munmap(netdev->xendev.gnttabdev, page, 1);
+    net_rx_response(netdev, &rxreq, NETIF_RSP_OKAY, NET_IP_ALIGN, size, 0);
+
+    return size;
+}
+
+/* ------------------------------------------------------------- */
+
+static NetClientInfo net_xen_info = {
+    .type = NET_CLIENT_OPTIONS_KIND_NIC,
+    .size = sizeof(NICState),
+    .can_receive = net_rx_ok,
+    .receive = net_rx_packet,
+};
+
+static int net_init(struct XenDevice *xendev)
+{
+    struct XenNetDev *netdev = container_of(xendev, struct XenNetDev, xendev);
+
+    /* read xenstore entries */
+    if (netdev->mac == NULL) {
+        netdev->mac = xenstore_read_be_str(&netdev->xendev, "mac");
+    }
+
+    /* do we have all we need? */
+    if (netdev->mac == NULL) {
+        return -1;
+    }
+
+    if (net_parse_macaddr(netdev->conf.macaddr.a, netdev->mac) < 0) {
+        return -1;
+    }
+
+    netdev->nic = qemu_new_nic(&net_xen_info, &netdev->conf,
+                               "xen", NULL, netdev);
+
+    snprintf(qemu_get_queue(netdev->nic)->info_str,
+             sizeof(qemu_get_queue(netdev->nic)->info_str),
+             "nic: xenbus vif macaddr=%s", netdev->mac);
+
+    /* fill info */
+    xenstore_write_be_int(&netdev->xendev, "feature-rx-copy", 1);
+    xenstore_write_be_int(&netdev->xendev, "feature-rx-flip", 0);
+
+    return 0;
+}
+
+static int net_connect(struct XenDevice *xendev)
+{
+    struct XenNetDev *netdev = container_of(xendev, struct XenNetDev, xendev);
+    int rx_copy;
+
+    if (xenstore_read_fe_int(&netdev->xendev, "tx-ring-ref",
+                             &netdev->tx_ring_ref) == -1) {
+        return -1;
+    }
+    if (xenstore_read_fe_int(&netdev->xendev, "rx-ring-ref",
+                             &netdev->rx_ring_ref) == -1) {
+        return 1;
+    }
+    if (xenstore_read_fe_int(&netdev->xendev, "event-channel",
+                             &netdev->xendev.remote_port) == -1) {
+        return -1;
+    }
+
+    if (xenstore_read_fe_int(&netdev->xendev, "request-rx-copy", &rx_copy) == -1) {
+        rx_copy = 0;
+    }
+    if (rx_copy == 0) {
+        xen_be_printf(&netdev->xendev, 0, "frontend doesn't support rx-copy.\n");
+        return -1;
+    }
+
+    netdev->txs = xc_gnttab_map_grant_ref(netdev->xendev.gnttabdev,
+                                          netdev->xendev.dom,
+                                          netdev->tx_ring_ref,
+                                          PROT_READ | PROT_WRITE);
+    netdev->rxs = xc_gnttab_map_grant_ref(netdev->xendev.gnttabdev,
+                                          netdev->xendev.dom,
+                                          netdev->rx_ring_ref,
+                                          PROT_READ | PROT_WRITE);
+    if (!netdev->txs || !netdev->rxs) {
+        return -1;
+    }
+    BACK_RING_INIT(&netdev->tx_ring, netdev->txs, XC_PAGE_SIZE);
+    BACK_RING_INIT(&netdev->rx_ring, netdev->rxs, XC_PAGE_SIZE);
+
+    xen_be_bind_evtchn(&netdev->xendev);
+
+    xen_be_printf(&netdev->xendev, 1, "ok: tx-ring-ref %d, rx-ring-ref %d, "
+                  "remote port %d, local port %d\n",
+                  netdev->tx_ring_ref, netdev->rx_ring_ref,
+                  netdev->xendev.remote_port, netdev->xendev.local_port);
+
+    net_tx_packets(netdev);
+    return 0;
+}
+
+static void net_disconnect(struct XenDevice *xendev)
+{
+    struct XenNetDev *netdev = container_of(xendev, struct XenNetDev, xendev);
+
+    xen_be_unbind_evtchn(&netdev->xendev);
+
+    if (netdev->txs) {
+        xc_gnttab_munmap(netdev->xendev.gnttabdev, netdev->txs, 1);
+        netdev->txs = NULL;
+    }
+    if (netdev->rxs) {
+        xc_gnttab_munmap(netdev->xendev.gnttabdev, netdev->rxs, 1);
+        netdev->rxs = NULL;
+    }
+    if (netdev->nic) {
+        qemu_del_nic(netdev->nic);
+        netdev->nic = NULL;
+    }
+}
+
+static void net_event(struct XenDevice *xendev)
+{
+    struct XenNetDev *netdev = container_of(xendev, struct XenNetDev, xendev);
+    net_tx_packets(netdev);
+    qemu_flush_queued_packets(qemu_get_queue(netdev->nic));
+}
+
+static int net_free(struct XenDevice *xendev)
+{
+    struct XenNetDev *netdev = container_of(xendev, struct XenNetDev, xendev);
+
+    g_free(netdev->mac);
+    return 0;
+}
+
+/* ------------------------------------------------------------- */
+
+struct XenDevOps xen_netdev_ops = {
+    .size       = sizeof(struct XenNetDev),
+    .flags      = DEVOPS_FLAG_NEED_GNTDEV,
+    .init       = net_init,
+    .initialise    = net_connect,
+    .event      = net_event,
+    .disconnect = net_disconnect,
+    .free       = net_free,
+};
diff --git a/hw/net/xgmac.c b/hw/net/xgmac.c
new file mode 100644 (file)
index 0000000..5275f48
--- /dev/null
@@ -0,0 +1,433 @@
+/*
+ * QEMU model of XGMAC Ethernet.
+ *
+ * derived from the Xilinx AXI-Ethernet by Edgar E. Iglesias.
+ *
+ * Copyright (c) 2011 Calxeda, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "hw/sysbus.h"
+#include "char/char.h"
+#include "qemu/log.h"
+#include "net/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(qemu_get_queue(s->nic), 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, hwaddr 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, hwaddr 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(NetClientState *nc)
+{
+    struct XgmacState *s = qemu_get_nic_opaque(nc);
+
+    /* RX enabled?  */
+    return s->regs[DMA_CONTROL] & DMA_CONTROL_SR;
+}
+
+static ssize_t eth_rx(NetClientState *nc, const uint8_t *buf, size_t size)
+{
+    struct XgmacState *s = qemu_get_nic_opaque(nc);
+    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(NetClientState *nc)
+{
+    struct XgmacState *s = qemu_get_nic_opaque(nc);
+    s->nic = NULL;
+}
+
+static NetClientInfo net_xgmac_enet_info = {
+    .type = NET_CLIENT_OPTIONS_KIND_NIC,
+    .size = sizeof(NICState),
+    .can_receive = eth_can_rx,
+    .receive = eth_rx,
+    .cleanup = eth_cleanup,
+};
+
+static int xgmac_enet_init(SysBusDevice *dev)
+{
+    struct XgmacState *s = FROM_SYSBUS(typeof(*s), dev);
+
+    memory_region_init_io(&s->iomem, &enet_mem_ops, s, "xgmac", 0x1000);
+    sysbus_init_mmio(dev, &s->iomem);
+    sysbus_init_irq(dev, &s->sbd_irq);
+    sysbus_init_irq(dev, &s->pmt_irq);
+    sysbus_init_irq(dev, &s->mci_irq);
+
+    qemu_macaddr_default_if_unset(&s->conf.macaddr);
+    s->nic = qemu_new_nic(&net_xgmac_enet_info, &s->conf,
+                          object_get_typename(OBJECT(dev)), dev->qdev.id, s);
+    qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
+
+    s->regs[XGMAC_ADDR_HIGH(0)] = (s->conf.macaddr.a[5] << 8) |
+                                   s->conf.macaddr.a[4];
+    s->regs[XGMAC_ADDR_LOW(0)] = (s->conf.macaddr.a[3] << 24) |
+                                 (s->conf.macaddr.a[2] << 16) |
+                                 (s->conf.macaddr.a[1] << 8) |
+                                  s->conf.macaddr.a[0];
+
+    return 0;
+}
+
+static Property xgmac_properties[] = {
+    DEFINE_NIC_PROPERTIES(struct XgmacState, conf),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void xgmac_enet_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    sbc->init = xgmac_enet_init;
+    dc->vmsd = &vmstate_xgmac;
+    dc->props = xgmac_properties;
+}
+
+static const 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_types(void)
+{
+    type_register_static(&xgmac_enet_info);
+}
+
+type_init(xgmac_enet_register_types)
diff --git a/hw/net/xilinx_axienet.c b/hw/net/xilinx_axienet.c
new file mode 100644 (file)
index 0000000..07c4bad
--- /dev/null
@@ -0,0 +1,918 @@
+/*
+ * QEMU model of Xilinx AXI-Ethernet.
+ *
+ * Copyright (c) 2011 Edgar E. Iglesias.
+ *
+ * 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 "hw/sysbus.h"
+#include "qemu/log.h"
+#include "net/net.h"
+#include "net/checksum.h"
+#include "qapi/qmp/qerror.h"
+
+#include "hw/stream.h"
+
+#define DPHY(x)
+
+/* Advertisement control register. */
+#define ADVERTISE_10HALF        0x0020  /* Try for 10mbps half-duplex  */
+#define ADVERTISE_10FULL        0x0040  /* Try for 10mbps full-duplex  */
+#define ADVERTISE_100HALF       0x0080  /* Try for 100mbps half-duplex */
+#define ADVERTISE_100FULL       0x0100  /* Try for 100mbps full-duplex */
+
+struct PHY {
+    uint32_t regs[32];
+
+    int link;
+
+    unsigned int (*read)(struct PHY *phy, unsigned int req);
+    void (*write)(struct PHY *phy, unsigned int req,
+                  unsigned int data);
+};
+
+static unsigned int tdk_read(struct PHY *phy, unsigned int req)
+{
+    int regnum;
+    unsigned r = 0;
+
+    regnum = req & 0x1f;
+
+    switch (regnum) {
+        case 1:
+            if (!phy->link) {
+                break;
+            }
+            /* MR1.  */
+            /* Speeds and modes.  */
+            r |= (1 << 13) | (1 << 14);
+            r |= (1 << 11) | (1 << 12);
+            r |= (1 << 5); /* Autoneg complete.  */
+            r |= (1 << 3); /* Autoneg able.  */
+            r |= (1 << 2); /* link.  */
+            r |= (1 << 1); /* link.  */
+            break;
+        case 5:
+            /* Link partner ability.
+               We are kind; always agree with whatever best mode
+               the guest advertises.  */
+            r = 1 << 14; /* Success.  */
+            /* Copy advertised modes.  */
+            r |= phy->regs[4] & (15 << 5);
+            /* Autoneg support.  */
+            r |= 1;
+            break;
+        case 17:
+            /* Marvel PHY on many xilinx boards.  */
+            r = 0x8000; /* 1000Mb  */
+            break;
+        case 18:
+            {
+                /* Diagnostics reg.  */
+                int duplex = 0;
+                int speed_100 = 0;
+
+                if (!phy->link) {
+                    break;
+                }
+
+                /* Are we advertising 100 half or 100 duplex ? */
+                speed_100 = !!(phy->regs[4] & ADVERTISE_100HALF);
+                speed_100 |= !!(phy->regs[4] & ADVERTISE_100FULL);
+
+                /* Are we advertising 10 duplex or 100 duplex ? */
+                duplex = !!(phy->regs[4] & ADVERTISE_100FULL);
+                duplex |= !!(phy->regs[4] & ADVERTISE_10FULL);
+                r = (speed_100 << 10) | (duplex << 11);
+            }
+            break;
+
+        default:
+            r = phy->regs[regnum];
+            break;
+    }
+    DPHY(qemu_log("\n%s %x = reg[%d]\n", __func__, r, regnum));
+    return r;
+}
+
+static void
+tdk_write(struct PHY *phy, unsigned int req, unsigned int data)
+{
+    int regnum;
+
+    regnum = req & 0x1f;
+    DPHY(qemu_log("%s reg[%d] = %x\n", __func__, regnum, data));
+    switch (regnum) {
+        default:
+            phy->regs[regnum] = data;
+            break;
+    }
+}
+
+static void
+tdk_init(struct PHY *phy)
+{
+    phy->regs[0] = 0x3100;
+    /* PHY Id.  */
+    phy->regs[2] = 0x0300;
+    phy->regs[3] = 0xe400;
+    /* Autonegotiation advertisement reg.  */
+    phy->regs[4] = 0x01E1;
+    phy->link = 1;
+
+    phy->read = tdk_read;
+    phy->write = tdk_write;
+}
+
+struct MDIOBus {
+    /* bus.  */
+    int mdc;
+    int mdio;
+
+    /* decoder.  */
+    enum {
+        PREAMBLE,
+        SOF,
+        OPC,
+        ADDR,
+        REQ,
+        TURNAROUND,
+        DATA
+    } state;
+    unsigned int drive;
+
+    unsigned int cnt;
+    unsigned int addr;
+    unsigned int opc;
+    unsigned int req;
+    unsigned int data;
+
+    struct PHY *devs[32];
+};
+
+static void
+mdio_attach(struct MDIOBus *bus, struct PHY *phy, unsigned int addr)
+{
+    bus->devs[addr & 0x1f] = phy;
+}
+
+#ifdef USE_THIS_DEAD_CODE
+static void
+mdio_detach(struct MDIOBus *bus, struct PHY *phy, unsigned int addr)
+{
+    bus->devs[addr & 0x1f] = NULL;
+}
+#endif
+
+static uint16_t mdio_read_req(struct MDIOBus *bus, unsigned int addr,
+                  unsigned int reg)
+{
+    struct PHY *phy;
+    uint16_t data;
+
+    phy = bus->devs[addr];
+    if (phy && phy->read) {
+        data = phy->read(phy, reg);
+    } else {
+        data = 0xffff;
+    }
+    DPHY(qemu_log("%s addr=%d reg=%d data=%x\n", __func__, addr, reg, data));
+    return data;
+}
+
+static void mdio_write_req(struct MDIOBus *bus, unsigned int addr,
+               unsigned int reg, uint16_t data)
+{
+    struct PHY *phy;
+
+    DPHY(qemu_log("%s addr=%d reg=%d data=%x\n", __func__, addr, reg, data));
+    phy = bus->devs[addr];
+    if (phy && phy->write) {
+        phy->write(phy, reg, data);
+    }
+}
+
+#define DENET(x)
+
+#define R_RAF      (0x000 / 4)
+enum {
+    RAF_MCAST_REJ = (1 << 1),
+    RAF_BCAST_REJ = (1 << 2),
+    RAF_EMCF_EN = (1 << 12),
+    RAF_NEWFUNC_EN = (1 << 11)
+};
+
+#define R_IS       (0x00C / 4)
+enum {
+    IS_HARD_ACCESS_COMPLETE = 1,
+    IS_AUTONEG = (1 << 1),
+    IS_RX_COMPLETE = (1 << 2),
+    IS_RX_REJECT = (1 << 3),
+    IS_TX_COMPLETE = (1 << 5),
+    IS_RX_DCM_LOCK = (1 << 6),
+    IS_MGM_RDY = (1 << 7),
+    IS_PHY_RST_DONE = (1 << 8),
+};
+
+#define R_IP       (0x010 / 4)
+#define R_IE       (0x014 / 4)
+#define R_UAWL     (0x020 / 4)
+#define R_UAWU     (0x024 / 4)
+#define R_PPST     (0x030 / 4)
+enum {
+    PPST_LINKSTATUS = (1 << 0),
+    PPST_PHY_LINKSTATUS = (1 << 7),
+};
+
+#define R_STATS_RX_BYTESL (0x200 / 4)
+#define R_STATS_RX_BYTESH (0x204 / 4)
+#define R_STATS_TX_BYTESL (0x208 / 4)
+#define R_STATS_TX_BYTESH (0x20C / 4)
+#define R_STATS_RXL       (0x290 / 4)
+#define R_STATS_RXH       (0x294 / 4)
+#define R_STATS_RX_BCASTL (0x2a0 / 4)
+#define R_STATS_RX_BCASTH (0x2a4 / 4)
+#define R_STATS_RX_MCASTL (0x2a8 / 4)
+#define R_STATS_RX_MCASTH (0x2ac / 4)
+
+#define R_RCW0     (0x400 / 4)
+#define R_RCW1     (0x404 / 4)
+enum {
+    RCW1_VLAN = (1 << 27),
+    RCW1_RX   = (1 << 28),
+    RCW1_FCS  = (1 << 29),
+    RCW1_JUM  = (1 << 30),
+    RCW1_RST  = (1 << 31),
+};
+
+#define R_TC       (0x408 / 4)
+enum {
+    TC_VLAN = (1 << 27),
+    TC_TX   = (1 << 28),
+    TC_FCS  = (1 << 29),
+    TC_JUM  = (1 << 30),
+    TC_RST  = (1 << 31),
+};
+
+#define R_EMMC     (0x410 / 4)
+enum {
+    EMMC_LINKSPEED_10MB = (0 << 30),
+    EMMC_LINKSPEED_100MB = (1 << 30),
+    EMMC_LINKSPEED_1000MB = (2 << 30),
+};
+
+#define R_PHYC     (0x414 / 4)
+
+#define R_MC       (0x500 / 4)
+#define MC_EN      (1 << 6)
+
+#define R_MCR      (0x504 / 4)
+#define R_MWD      (0x508 / 4)
+#define R_MRD      (0x50c / 4)
+#define R_MIS      (0x600 / 4)
+#define R_MIP      (0x620 / 4)
+#define R_MIE      (0x640 / 4)
+#define R_MIC      (0x640 / 4)
+
+#define R_UAW0     (0x700 / 4)
+#define R_UAW1     (0x704 / 4)
+#define R_FMI      (0x708 / 4)
+#define R_AF0      (0x710 / 4)
+#define R_AF1      (0x714 / 4)
+#define R_MAX      (0x34 / 4)
+
+/* Indirect registers.  */
+struct TEMAC  {
+    struct MDIOBus mdio_bus;
+    struct PHY phy;
+
+    void *parent;
+};
+
+struct XilinxAXIEnet {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    qemu_irq irq;
+    StreamSlave *tx_dev;
+    NICState *nic;
+    NICConf conf;
+
+
+    uint32_t c_rxmem;
+    uint32_t c_txmem;
+    uint32_t c_phyaddr;
+
+    struct TEMAC TEMAC;
+
+    /* MII regs.  */
+    union {
+        uint32_t regs[4];
+        struct {
+            uint32_t mc;
+            uint32_t mcr;
+            uint32_t mwd;
+            uint32_t mrd;
+        };
+    } mii;
+
+    struct {
+        uint64_t rx_bytes;
+        uint64_t tx_bytes;
+
+        uint64_t rx;
+        uint64_t rx_bcast;
+        uint64_t rx_mcast;
+    } stats;
+
+    /* Receive configuration words.  */
+    uint32_t rcw[2];
+    /* Transmit config.  */
+    uint32_t tc;
+    uint32_t emmc;
+    uint32_t phyc;
+
+    /* Unicast Address Word.  */
+    uint32_t uaw[2];
+    /* Unicast address filter used with extended mcast.  */
+    uint32_t ext_uaw[2];
+    uint32_t fmi;
+
+    uint32_t regs[R_MAX];
+
+    /* Multicast filter addrs.  */
+    uint32_t maddr[4][2];
+    /* 32K x 1 lookup filter.  */
+    uint32_t ext_mtable[1024];
+
+
+    uint8_t *rxmem;
+};
+
+static void axienet_rx_reset(struct XilinxAXIEnet *s)
+{
+    s->rcw[1] = RCW1_JUM | RCW1_FCS | RCW1_RX | RCW1_VLAN;
+}
+
+static void axienet_tx_reset(struct XilinxAXIEnet *s)
+{
+    s->tc = TC_JUM | TC_TX | TC_VLAN;
+}
+
+static inline int axienet_rx_resetting(struct XilinxAXIEnet *s)
+{
+    return s->rcw[1] & RCW1_RST;
+}
+
+static inline int axienet_rx_enabled(struct XilinxAXIEnet *s)
+{
+    return s->rcw[1] & RCW1_RX;
+}
+
+static inline int axienet_extmcf_enabled(struct XilinxAXIEnet *s)
+{
+    return !!(s->regs[R_RAF] & RAF_EMCF_EN);
+}
+
+static inline int axienet_newfunc_enabled(struct XilinxAXIEnet *s)
+{
+    return !!(s->regs[R_RAF] & RAF_NEWFUNC_EN);
+}
+
+static void axienet_reset(struct XilinxAXIEnet *s)
+{
+    axienet_rx_reset(s);
+    axienet_tx_reset(s);
+
+    s->regs[R_PPST] = PPST_LINKSTATUS | PPST_PHY_LINKSTATUS;
+    s->regs[R_IS] = IS_AUTONEG | IS_RX_DCM_LOCK | IS_MGM_RDY | IS_PHY_RST_DONE;
+
+    s->emmc = EMMC_LINKSPEED_100MB;
+}
+
+static void enet_update_irq(struct XilinxAXIEnet *s)
+{
+    s->regs[R_IP] = s->regs[R_IS] & s->regs[R_IE];
+    qemu_set_irq(s->irq, !!s->regs[R_IP]);
+}
+
+static uint64_t enet_read(void *opaque, hwaddr addr, unsigned size)
+{
+    struct XilinxAXIEnet *s = opaque;
+    uint32_t r = 0;
+    addr >>= 2;
+
+    switch (addr) {
+        case R_RCW0:
+        case R_RCW1:
+            r = s->rcw[addr & 1];
+            break;
+
+        case R_TC:
+            r = s->tc;
+            break;
+
+        case R_EMMC:
+            r = s->emmc;
+            break;
+
+        case R_PHYC:
+            r = s->phyc;
+            break;
+
+        case R_MCR:
+            r = s->mii.regs[addr & 3] | (1 << 7); /* Always ready.  */
+            break;
+
+        case R_STATS_RX_BYTESL:
+        case R_STATS_RX_BYTESH:
+            r = s->stats.rx_bytes >> (32 * (addr & 1));
+            break;
+
+        case R_STATS_TX_BYTESL:
+        case R_STATS_TX_BYTESH:
+            r = s->stats.tx_bytes >> (32 * (addr & 1));
+            break;
+
+        case R_STATS_RXL:
+        case R_STATS_RXH:
+            r = s->stats.rx >> (32 * (addr & 1));
+            break;
+        case R_STATS_RX_BCASTL:
+        case R_STATS_RX_BCASTH:
+            r = s->stats.rx_bcast >> (32 * (addr & 1));
+            break;
+        case R_STATS_RX_MCASTL:
+        case R_STATS_RX_MCASTH:
+            r = s->stats.rx_mcast >> (32 * (addr & 1));
+            break;
+
+        case R_MC:
+        case R_MWD:
+        case R_MRD:
+            r = s->mii.regs[addr & 3];
+            break;
+
+        case R_UAW0:
+        case R_UAW1:
+            r = s->uaw[addr & 1];
+            break;
+
+        case R_UAWU:
+        case R_UAWL:
+            r = s->ext_uaw[addr & 1];
+            break;
+
+        case R_FMI:
+            r = s->fmi;
+            break;
+
+        case R_AF0:
+        case R_AF1:
+            r = s->maddr[s->fmi & 3][addr & 1];
+            break;
+
+        case 0x8000 ... 0x83ff:
+            r = s->ext_mtable[addr - 0x8000];
+            break;
+
+        default:
+            if (addr < ARRAY_SIZE(s->regs)) {
+                r = s->regs[addr];
+            }
+            DENET(qemu_log("%s addr=" TARGET_FMT_plx " v=%x\n",
+                            __func__, addr * 4, r));
+            break;
+    }
+    return r;
+}
+
+static void enet_write(void *opaque, hwaddr addr,
+                       uint64_t value, unsigned size)
+{
+    struct XilinxAXIEnet *s = opaque;
+    struct TEMAC *t = &s->TEMAC;
+
+    addr >>= 2;
+    switch (addr) {
+        case R_RCW0:
+        case R_RCW1:
+            s->rcw[addr & 1] = value;
+            if ((addr & 1) && value & RCW1_RST) {
+                axienet_rx_reset(s);
+            } else {
+                qemu_flush_queued_packets(qemu_get_queue(s->nic));
+            }
+            break;
+
+        case R_TC:
+            s->tc = value;
+            if (value & TC_RST) {
+                axienet_tx_reset(s);
+            }
+            break;
+
+        case R_EMMC:
+            s->emmc = value;
+            break;
+
+        case R_PHYC:
+            s->phyc = value;
+            break;
+
+        case R_MC:
+             value &= ((1 < 7) - 1);
+
+             /* Enable the MII.  */
+             if (value & MC_EN) {
+                 unsigned int miiclkdiv = value & ((1 << 6) - 1);
+                 if (!miiclkdiv) {
+                     qemu_log("AXIENET: MDIO enabled but MDIOCLK is zero!\n");
+                 }
+             }
+             s->mii.mc = value;
+             break;
+
+        case R_MCR: {
+             unsigned int phyaddr = (value >> 24) & 0x1f;
+             unsigned int regaddr = (value >> 16) & 0x1f;
+             unsigned int op = (value >> 14) & 3;
+             unsigned int initiate = (value >> 11) & 1;
+
+             if (initiate) {
+                 if (op == 1) {
+                     mdio_write_req(&t->mdio_bus, phyaddr, regaddr, s->mii.mwd);
+                 } else if (op == 2) {
+                     s->mii.mrd = mdio_read_req(&t->mdio_bus, phyaddr, regaddr);
+                 } else {
+                     qemu_log("AXIENET: invalid MDIOBus OP=%d\n", op);
+                 }
+             }
+             s->mii.mcr = value;
+             break;
+        }
+
+        case R_MWD:
+        case R_MRD:
+             s->mii.regs[addr & 3] = value;
+             break;
+
+
+        case R_UAW0:
+        case R_UAW1:
+            s->uaw[addr & 1] = value;
+            break;
+
+        case R_UAWL:
+        case R_UAWU:
+            s->ext_uaw[addr & 1] = value;
+            break;
+
+        case R_FMI:
+            s->fmi = value;
+            break;
+
+        case R_AF0:
+        case R_AF1:
+            s->maddr[s->fmi & 3][addr & 1] = value;
+            break;
+
+        case R_IS:
+            s->regs[addr] &= ~value;
+            break;
+
+        case 0x8000 ... 0x83ff:
+            s->ext_mtable[addr - 0x8000] = value;
+            break;
+
+        default:
+            DENET(qemu_log("%s addr=" TARGET_FMT_plx " v=%x\n",
+                           __func__, addr * 4, (unsigned)value));
+            if (addr < ARRAY_SIZE(s->regs)) {
+                s->regs[addr] = value;
+            }
+            break;
+    }
+    enet_update_irq(s);
+}
+
+static const MemoryRegionOps enet_ops = {
+    .read = enet_read,
+    .write = enet_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static int eth_can_rx(NetClientState *nc)
+{
+    struct XilinxAXIEnet *s = qemu_get_nic_opaque(nc);
+
+    /* RX enabled?  */
+    return !axienet_rx_resetting(s) && axienet_rx_enabled(s);
+}
+
+static int enet_match_addr(const uint8_t *buf, uint32_t f0, uint32_t f1)
+{
+    int match = 1;
+
+    if (memcmp(buf, &f0, 4)) {
+        match = 0;
+    }
+
+    if (buf[4] != (f1 & 0xff) || buf[5] != ((f1 >> 8) & 0xff)) {
+        match = 0;
+    }
+
+    return match;
+}
+
+static ssize_t eth_rx(NetClientState *nc, const uint8_t *buf, size_t size)
+{
+    struct XilinxAXIEnet *s = qemu_get_nic_opaque(nc);
+    static const unsigned char sa_bcast[6] = {0xff, 0xff, 0xff,
+                                              0xff, 0xff, 0xff};
+    static const unsigned char sa_ipmcast[3] = {0x01, 0x00, 0x52};
+    uint32_t app[6] = {0};
+    int promisc = s->fmi & (1 << 31);
+    int unicast, broadcast, multicast, ip_multicast = 0;
+    uint32_t csum32;
+    uint16_t csum16;
+    int i;
+
+    DENET(qemu_log("%s: %zd bytes\n", __func__, size));
+
+    unicast = ~buf[0] & 0x1;
+    broadcast = memcmp(buf, sa_bcast, 6) == 0;
+    multicast = !unicast && !broadcast;
+    if (multicast && (memcmp(sa_ipmcast, buf, sizeof sa_ipmcast) == 0)) {
+        ip_multicast = 1;
+    }
+
+    /* Jumbo or vlan sizes ?  */
+    if (!(s->rcw[1] & RCW1_JUM)) {
+        if (size > 1518 && size <= 1522 && !(s->rcw[1] & RCW1_VLAN)) {
+            return size;
+        }
+    }
+
+    /* Basic Address filters.  If you want to use the extended filters
+       you'll generally have to place the ethernet mac into promiscuous mode
+       to avoid the basic filtering from dropping most frames.  */
+    if (!promisc) {
+        if (unicast) {
+            if (!enet_match_addr(buf, s->uaw[0], s->uaw[1])) {
+                return size;
+            }
+        } else {
+            if (broadcast) {
+                /* Broadcast.  */
+                if (s->regs[R_RAF] & RAF_BCAST_REJ) {
+                    return size;
+                }
+            } else {
+                int drop = 1;
+
+                /* Multicast.  */
+                if (s->regs[R_RAF] & RAF_MCAST_REJ) {
+                    return size;
+                }
+
+                for (i = 0; i < 4; i++) {
+                    if (enet_match_addr(buf, s->maddr[i][0], s->maddr[i][1])) {
+                        drop = 0;
+                        break;
+                    }
+                }
+
+                if (drop) {
+                    return size;
+                }
+            }
+        }
+    }
+
+    /* Extended mcast filtering enabled?  */
+    if (axienet_newfunc_enabled(s) && axienet_extmcf_enabled(s)) {
+        if (unicast) {
+            if (!enet_match_addr(buf, s->ext_uaw[0], s->ext_uaw[1])) {
+                return size;
+            }
+        } else {
+            if (broadcast) {
+                /* Broadcast. ???  */
+                if (s->regs[R_RAF] & RAF_BCAST_REJ) {
+                    return size;
+                }
+            } else {
+                int idx, bit;
+
+                /* Multicast.  */
+                if (!memcmp(buf, sa_ipmcast, 3)) {
+                    return size;
+                }
+
+                idx  = (buf[4] & 0x7f) << 8;
+                idx |= buf[5];
+
+                bit = 1 << (idx & 0x1f);
+                idx >>= 5;
+
+                if (!(s->ext_mtable[idx] & bit)) {
+                    return size;
+                }
+            }
+        }
+    }
+
+    if (size < 12) {
+        s->regs[R_IS] |= IS_RX_REJECT;
+        enet_update_irq(s);
+        return -1;
+    }
+
+    if (size > (s->c_rxmem - 4)) {
+        size = s->c_rxmem - 4;
+    }
+
+    memcpy(s->rxmem, buf, size);
+    memset(s->rxmem + size, 0, 4); /* Clear the FCS.  */
+
+    if (s->rcw[1] & RCW1_FCS) {
+        size += 4; /* fcs is inband.  */
+    }
+
+    app[0] = 5 << 28;
+    csum32 = net_checksum_add(size - 14, (uint8_t *)s->rxmem + 14);
+    /* Fold it once.  */
+    csum32 = (csum32 & 0xffff) + (csum32 >> 16);
+    /* And twice to get rid of possible carries.  */
+    csum16 = (csum32 & 0xffff) + (csum32 >> 16);
+    app[3] = csum16;
+    app[4] = size & 0xffff;
+
+    s->stats.rx_bytes += size;
+    s->stats.rx++;
+    if (multicast) {
+        s->stats.rx_mcast++;
+        app[2] |= 1 | (ip_multicast << 1);
+    } else if (broadcast) {
+        s->stats.rx_bcast++;
+        app[2] |= 1 << 3;
+    }
+
+    /* Good frame.  */
+    app[2] |= 1 << 6;
+
+    stream_push(s->tx_dev, (void *)s->rxmem, size, app);
+
+    s->regs[R_IS] |= IS_RX_COMPLETE;
+    enet_update_irq(s);
+    return size;
+}
+
+static void eth_cleanup(NetClientState *nc)
+{
+    /* FIXME.  */
+    struct XilinxAXIEnet *s = qemu_get_nic_opaque(nc);
+    g_free(s->rxmem);
+    g_free(s);
+}
+
+static void
+axienet_stream_push(StreamSlave *obj, uint8_t *buf, size_t size, uint32_t *hdr)
+{
+    struct XilinxAXIEnet *s = FROM_SYSBUS(typeof(*s), SYS_BUS_DEVICE(obj));
+
+    /* TX enable ?  */
+    if (!(s->tc & TC_TX)) {
+        return;
+    }
+
+    /* Jumbo or vlan sizes ?  */
+    if (!(s->tc & TC_JUM)) {
+        if (size > 1518 && size <= 1522 && !(s->tc & TC_VLAN)) {
+            return;
+        }
+    }
+
+    if (hdr[0] & 1) {
+        unsigned int start_off = hdr[1] >> 16;
+        unsigned int write_off = hdr[1] & 0xffff;
+        uint32_t tmp_csum;
+        uint16_t csum;
+
+        tmp_csum = net_checksum_add(size - start_off,
+                                    (uint8_t *)buf + start_off);
+        /* Accumulate the seed.  */
+        tmp_csum += hdr[2] & 0xffff;
+
+        /* Fold the 32bit partial checksum.  */
+        csum = net_checksum_finish(tmp_csum);
+
+        /* Writeback.  */
+        buf[write_off] = csum >> 8;
+        buf[write_off + 1] = csum & 0xff;
+    }
+
+    qemu_send_packet(qemu_get_queue(s->nic), buf, size);
+
+    s->stats.tx_bytes += size;
+    s->regs[R_IS] |= IS_TX_COMPLETE;
+    enet_update_irq(s);
+}
+
+static NetClientInfo net_xilinx_enet_info = {
+    .type = NET_CLIENT_OPTIONS_KIND_NIC,
+    .size = sizeof(NICState),
+    .can_receive = eth_can_rx,
+    .receive = eth_rx,
+    .cleanup = eth_cleanup,
+};
+
+static int xilinx_enet_init(SysBusDevice *dev)
+{
+    struct XilinxAXIEnet *s = FROM_SYSBUS(typeof(*s), dev);
+
+    sysbus_init_irq(dev, &s->irq);
+
+    memory_region_init_io(&s->iomem, &enet_ops, s, "enet", 0x40000);
+    sysbus_init_mmio(dev, &s->iomem);
+
+    qemu_macaddr_default_if_unset(&s->conf.macaddr);
+    s->nic = qemu_new_nic(&net_xilinx_enet_info, &s->conf,
+                          object_get_typename(OBJECT(dev)), dev->qdev.id, s);
+    qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
+
+    tdk_init(&s->TEMAC.phy);
+    mdio_attach(&s->TEMAC.mdio_bus, &s->TEMAC.phy, s->c_phyaddr);
+
+    s->TEMAC.parent = s;
+
+    s->rxmem = g_malloc(s->c_rxmem);
+    axienet_reset(s);
+
+    return 0;
+}
+
+static void xilinx_enet_initfn(Object *obj)
+{
+    struct XilinxAXIEnet *s = FROM_SYSBUS(typeof(*s), SYS_BUS_DEVICE(obj));
+    Error *errp = NULL;
+
+    object_property_add_link(obj, "axistream-connected", TYPE_STREAM_SLAVE,
+                             (Object **) &s->tx_dev, &errp);
+    assert_no_error(errp);
+}
+
+static Property xilinx_enet_properties[] = {
+    DEFINE_PROP_UINT32("phyaddr", struct XilinxAXIEnet, c_phyaddr, 7),
+    DEFINE_PROP_UINT32("rxmem", struct XilinxAXIEnet, c_rxmem, 0x1000),
+    DEFINE_PROP_UINT32("txmem", struct XilinxAXIEnet, c_txmem, 0x1000),
+    DEFINE_NIC_PROPERTIES(struct XilinxAXIEnet, conf),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void xilinx_enet_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+    StreamSlaveClass *ssc = STREAM_SLAVE_CLASS(klass);
+
+    k->init = xilinx_enet_init;
+    dc->props = xilinx_enet_properties;
+    ssc->push = axienet_stream_push;
+}
+
+static const TypeInfo xilinx_enet_info = {
+    .name          = "xlnx.axi-ethernet",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(struct XilinxAXIEnet),
+    .class_init    = xilinx_enet_class_init,
+    .instance_init = xilinx_enet_initfn,
+    .interfaces = (InterfaceInfo[]) {
+            { TYPE_STREAM_SLAVE },
+            { }
+    }
+};
+
+static void xilinx_enet_register_types(void)
+{
+    type_register_static(&xilinx_enet_info);
+}
+
+type_init(xilinx_enet_register_types)
diff --git a/hw/net/xilinx_ethlite.c b/hw/net/xilinx_ethlite.c
new file mode 100644 (file)
index 0000000..b2e3523
--- /dev/null
@@ -0,0 +1,263 @@
+/*
+ * QEMU model of the Xilinx Ethernet Lite MAC.
+ *
+ * Copyright (c) 2009 Edgar E. Iglesias.
+ *
+ * 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 "hw/sysbus.h"
+#include "hw/hw.h"
+#include "net/net.h"
+
+#define D(x)
+#define R_TX_BUF0     0
+#define R_TX_LEN0     (0x07f4 / 4)
+#define R_TX_GIE0     (0x07f8 / 4)
+#define R_TX_CTRL0    (0x07fc / 4)
+#define R_TX_BUF1     (0x0800 / 4)
+#define R_TX_LEN1     (0x0ff4 / 4)
+#define R_TX_CTRL1    (0x0ffc / 4)
+
+#define R_RX_BUF0     (0x1000 / 4)
+#define R_RX_CTRL0    (0x17fc / 4)
+#define R_RX_BUF1     (0x1800 / 4)
+#define R_RX_CTRL1    (0x1ffc / 4)
+#define R_MAX         (0x2000 / 4)
+
+#define GIE_GIE    0x80000000
+
+#define CTRL_I     0x8
+#define CTRL_P     0x2
+#define CTRL_S     0x1
+
+struct xlx_ethlite
+{
+    SysBusDevice busdev;
+    MemoryRegion mmio;
+    qemu_irq irq;
+    NICState *nic;
+    NICConf conf;
+
+    uint32_t c_tx_pingpong;
+    uint32_t c_rx_pingpong;
+    unsigned int txbuf;
+    unsigned int rxbuf;
+
+    uint32_t regs[R_MAX];
+};
+
+static inline void eth_pulse_irq(struct xlx_ethlite *s)
+{
+    /* Only the first gie reg is active.  */
+    if (s->regs[R_TX_GIE0] & GIE_GIE) {
+        qemu_irq_pulse(s->irq);
+    }
+}
+
+static uint64_t
+eth_read(void *opaque, hwaddr addr, unsigned int size)
+{
+    struct xlx_ethlite *s = opaque;
+    uint32_t r = 0;
+
+    addr >>= 2;
+
+    switch (addr)
+    {
+        case R_TX_GIE0:
+        case R_TX_LEN0:
+        case R_TX_LEN1:
+        case R_TX_CTRL1:
+        case R_TX_CTRL0:
+        case R_RX_CTRL1:
+        case R_RX_CTRL0:
+            r = s->regs[addr];
+            D(qemu_log("%s " TARGET_FMT_plx "=%x\n", __func__, addr * 4, r));
+            break;
+
+        default:
+            r = tswap32(s->regs[addr]);
+            break;
+    }
+    return r;
+}
+
+static void
+eth_write(void *opaque, hwaddr addr,
+          uint64_t val64, unsigned int size)
+{
+    struct xlx_ethlite *s = opaque;
+    unsigned int base = 0;
+    uint32_t value = val64;
+
+    addr >>= 2;
+    switch (addr) 
+    {
+        case R_TX_CTRL0:
+        case R_TX_CTRL1:
+            if (addr == R_TX_CTRL1)
+                base = 0x800 / 4;
+
+            D(qemu_log("%s addr=" TARGET_FMT_plx " val=%x\n",
+                       __func__, addr * 4, value));
+            if ((value & (CTRL_P | CTRL_S)) == CTRL_S) {
+                qemu_send_packet(qemu_get_queue(s->nic),
+                                 (void *) &s->regs[base],
+                                 s->regs[base + R_TX_LEN0]);
+                D(qemu_log("eth_tx %d\n", s->regs[base + R_TX_LEN0]));
+                if (s->regs[base + R_TX_CTRL0] & CTRL_I)
+                    eth_pulse_irq(s);
+            } else if ((value & (CTRL_P | CTRL_S)) == (CTRL_P | CTRL_S)) {
+                memcpy(&s->conf.macaddr.a[0], &s->regs[base], 6);
+                if (s->regs[base + R_TX_CTRL0] & CTRL_I)
+                    eth_pulse_irq(s);
+            }
+
+            /* We are fast and get ready pretty much immediately so
+               we actually never flip the S nor P bits to one.  */
+            s->regs[addr] = value & ~(CTRL_P | CTRL_S);
+            break;
+
+        /* Keep these native.  */
+        case R_RX_CTRL0:
+        case R_RX_CTRL1:
+            if (!(value & CTRL_S)) {
+                qemu_flush_queued_packets(qemu_get_queue(s->nic));
+            }
+        case R_TX_LEN0:
+        case R_TX_LEN1:
+        case R_TX_GIE0:
+            D(qemu_log("%s addr=" TARGET_FMT_plx " val=%x\n",
+                       __func__, addr * 4, value));
+            s->regs[addr] = value;
+            break;
+
+        default:
+            s->regs[addr] = tswap32(value);
+            break;
+    }
+}
+
+static const MemoryRegionOps eth_ops = {
+    .read = eth_read,
+    .write = eth_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4
+    }
+};
+
+static int eth_can_rx(NetClientState *nc)
+{
+    struct xlx_ethlite *s = qemu_get_nic_opaque(nc);
+    unsigned int rxbase = s->rxbuf * (0x800 / 4);
+
+    return !(s->regs[rxbase + R_RX_CTRL0] & CTRL_S);
+}
+
+static ssize_t eth_rx(NetClientState *nc, const uint8_t *buf, size_t size)
+{
+    struct xlx_ethlite *s = qemu_get_nic_opaque(nc);
+    unsigned int rxbase = s->rxbuf * (0x800 / 4);
+
+    /* DA filter.  */
+    if (!(buf[0] & 0x80) && memcmp(&s->conf.macaddr.a[0], buf, 6))
+        return size;
+
+    if (s->regs[rxbase + R_RX_CTRL0] & CTRL_S) {
+        D(qemu_log("ethlite lost packet %x\n", s->regs[R_RX_CTRL0]));
+        return -1;
+    }
+
+    D(qemu_log("%s %zd rxbase=%x\n", __func__, size, rxbase));
+    memcpy(&s->regs[rxbase + R_RX_BUF0], buf, size);
+
+    s->regs[rxbase + R_RX_CTRL0] |= CTRL_S;
+    if (s->regs[rxbase + R_RX_CTRL0] & CTRL_I)
+        eth_pulse_irq(s);
+
+    /* If c_rx_pingpong was set flip buffers.  */
+    s->rxbuf ^= s->c_rx_pingpong;
+    return size;
+}
+
+static void eth_cleanup(NetClientState *nc)
+{
+    struct xlx_ethlite *s = qemu_get_nic_opaque(nc);
+
+    s->nic = NULL;
+}
+
+static NetClientInfo net_xilinx_ethlite_info = {
+    .type = NET_CLIENT_OPTIONS_KIND_NIC,
+    .size = sizeof(NICState),
+    .can_receive = eth_can_rx,
+    .receive = eth_rx,
+    .cleanup = eth_cleanup,
+};
+
+static int xilinx_ethlite_init(SysBusDevice *dev)
+{
+    struct xlx_ethlite *s = FROM_SYSBUS(typeof (*s), dev);
+
+    sysbus_init_irq(dev, &s->irq);
+    s->rxbuf = 0;
+
+    memory_region_init_io(&s->mmio, &eth_ops, s, "xlnx.xps-ethernetlite",
+                                                                    R_MAX * 4);
+    sysbus_init_mmio(dev, &s->mmio);
+
+    qemu_macaddr_default_if_unset(&s->conf.macaddr);
+    s->nic = qemu_new_nic(&net_xilinx_ethlite_info, &s->conf,
+                          object_get_typename(OBJECT(dev)), dev->qdev.id, s);
+    qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
+    return 0;
+}
+
+static Property xilinx_ethlite_properties[] = {
+    DEFINE_PROP_UINT32("tx-ping-pong", struct xlx_ethlite, c_tx_pingpong, 1),
+    DEFINE_PROP_UINT32("rx-ping-pong", struct xlx_ethlite, c_rx_pingpong, 1),
+    DEFINE_NIC_PROPERTIES(struct xlx_ethlite, conf),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void xilinx_ethlite_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = xilinx_ethlite_init;
+    dc->props = xilinx_ethlite_properties;
+}
+
+static const TypeInfo xilinx_ethlite_info = {
+    .name          = "xlnx.xps-ethernetlite",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(struct xlx_ethlite),
+    .class_init    = xilinx_ethlite_class_init,
+};
+
+static void xilinx_ethlite_register_types(void)
+{
+    type_register_static(&xilinx_ethlite_info);
+}
+
+type_init(xilinx_ethlite_register_types)
diff --git a/hw/null-machine.c b/hw/null-machine.c
deleted file mode 100644 (file)
index bdf109f..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Empty machine
- *
- * Copyright IBM, Corp. 2012
- *
- * Authors:
- *  Anthony Liguori   <aliguori@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-common.h"
-#include "hw/hw.h"
-#include "hw/boards.h"
-
-static void machine_none_init(QEMUMachineInitArgs *args)
-{
-}
-
-static QEMUMachine machine_none = {
-    .name = "none",
-    .desc = "empty machine",
-    .init = machine_none_init,
-    .max_cpus = 0,
-    DEFAULT_MACHINE_OPTIONS,
-};
-
-static void register_machines(void)
-{
-    qemu_register_machine(&machine_none);
-}
-
-machine_init(register_machines);
-
diff --git a/hw/nvram.h b/hw/nvram.h
deleted file mode 100644 (file)
index 59337fa..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-#ifndef NVRAM_H
-#define NVRAM_H
-
-/* NVRAM helpers */
-typedef uint32_t (*nvram_read_t)(void *private, uint32_t addr);
-typedef void (*nvram_write_t)(void *private, uint32_t addr, uint32_t val);
-typedef struct nvram_t {
-    void *opaque;
-    nvram_read_t read_fn;
-    nvram_write_t write_fn;
-} nvram_t;
-
-uint32_t NVRAM_get_lword (nvram_t *nvram, uint32_t addr);
-int NVRAM_get_string (nvram_t *nvram, uint8_t *dst, uint16_t addr, int max);
-
-int PPC_NVRAM_set_params (nvram_t *nvram, uint16_t NVRAM_size,
-                          const char *arch,
-                          uint32_t RAM_size, int boot_device,
-                          uint32_t kernel_image, uint32_t kernel_size,
-                          const char *cmdline,
-                          uint32_t initrd_image, uint32_t initrd_size,
-                          uint32_t NVRAM_image,
-                          int width, int height, int depth);
-typedef struct M48t59State M48t59State;
-
-void m48t59_write (void *private, uint32_t addr, uint32_t val);
-uint32_t m48t59_read (void *private, uint32_t addr);
-void m48t59_toggle_lock (void *private, int lock);
-M48t59State *m48t59_init_isa(ISABus *bus, uint32_t io_base, uint16_t size,
-                             int type);
-M48t59State *m48t59_init(qemu_irq IRQ, hwaddr mem_base,
-                         uint32_t io_base, uint16_t size, int type);
-
-#endif /* !NVRAM_H */
diff --git a/hw/nvram/Makefile.objs b/hw/nvram/Makefile.objs
new file mode 100644 (file)
index 0000000..e9a6694
--- /dev/null
@@ -0,0 +1,5 @@
+common-obj-$(CONFIG_DS1225Y) += ds1225y.o
+common-obj-y += eeprom93xx.o
+common-obj-y += fw_cfg.o
+common-obj-$(CONFIG_MAC_NVRAM) += mac_nvram.o
+obj-$(CONFIG_PSERIES) += spapr_nvram.o
diff --git a/hw/nvram/ds1225y.c b/hw/nvram/ds1225y.c
new file mode 100644 (file)
index 0000000..488f1d7
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * QEMU NVRAM emulation for DS1225Y chip
+ *
+ * Copyright (c) 2007-2008 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 "hw/sysbus.h"
+#include "trace.h"
+
+typedef struct {
+    DeviceState qdev;
+    MemoryRegion iomem;
+    uint32_t chip_size;
+    char *filename;
+    FILE *file;
+    uint8_t *contents;
+} NvRamState;
+
+static uint64_t nvram_read(void *opaque, hwaddr addr, unsigned size)
+{
+    NvRamState *s = opaque;
+    uint32_t val;
+
+    val = s->contents[addr];
+    trace_nvram_read(addr, val);
+    return val;
+}
+
+static void nvram_write(void *opaque, hwaddr addr, uint64_t val,
+                        unsigned size)
+{
+    NvRamState *s = opaque;
+
+    val &= 0xff;
+    trace_nvram_write(addr, s->contents[addr], val);
+
+    s->contents[addr] = val;
+    if (s->file) {
+        fseek(s->file, addr, SEEK_SET);
+        fputc(val, s->file);
+        fflush(s->file);
+    }
+}
+
+static const MemoryRegionOps nvram_ops = {
+    .read = nvram_read,
+    .write = nvram_write,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static int nvram_post_load(void *opaque, int version_id)
+{
+    NvRamState *s = opaque;
+
+    /* Close file, as filename may has changed in load/store process */
+    if (s->file) {
+        fclose(s->file);
+    }
+
+    /* Write back nvram contents */
+    s->file = fopen(s->filename, "wb");
+    if (s->file) {
+        /* Write back contents, as 'wb' mode cleaned the file */
+        if (fwrite(s->contents, s->chip_size, 1, s->file) != 1) {
+            printf("nvram_post_load: short write\n");
+        }
+        fflush(s->file);
+    }
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_nvram = {
+    .name = "nvram",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .post_load = nvram_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_VARRAY_UINT32(contents, NvRamState, chip_size, 0,
+                              vmstate_info_uint8, uint8_t),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+typedef struct {
+    SysBusDevice busdev;
+    NvRamState nvram;
+} SysBusNvRamState;
+
+static int nvram_sysbus_initfn(SysBusDevice *dev)
+{
+    NvRamState *s = &FROM_SYSBUS(SysBusNvRamState, dev)->nvram;
+    FILE *file;
+
+    s->contents = g_malloc0(s->chip_size);
+
+    memory_region_init_io(&s->iomem, &nvram_ops, s, "nvram", s->chip_size);
+    sysbus_init_mmio(dev, &s->iomem);
+
+    /* Read current file */
+    file = fopen(s->filename, "rb");
+    if (file) {
+        /* Read nvram contents */
+        if (fread(s->contents, s->chip_size, 1, file) != 1) {
+            printf("nvram_sysbus_initfn: short read\n");
+        }
+        fclose(file);
+    }
+    nvram_post_load(s, 0);
+
+    return 0;
+}
+
+static Property nvram_sysbus_properties[] = {
+    DEFINE_PROP_UINT32("size", SysBusNvRamState, nvram.chip_size, 0x2000),
+    DEFINE_PROP_STRING("filename", SysBusNvRamState, nvram.filename),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void nvram_sysbus_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = nvram_sysbus_initfn;
+    dc->vmsd = &vmstate_nvram;
+    dc->props = nvram_sysbus_properties;
+}
+
+static const 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_types(void)
+{
+    type_register_static(&nvram_sysbus_info);
+}
+
+type_init(nvram_register_types)
diff --git a/hw/nvram/eeprom93xx.c b/hw/nvram/eeprom93xx.c
new file mode 100644 (file)
index 0000000..08f4df5
--- /dev/null
@@ -0,0 +1,337 @@
+/*
+ * QEMU EEPROM 93xx emulation
+ *
+ * Copyright (c) 2006-2007 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
+ * 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/>.
+ */
+
+/* Emulation for serial EEPROMs:
+ * NMC93C06 256-Bit (16 x 16)
+ * NMC93C46 1024-Bit (64 x 16)
+ * NMC93C56 2028 Bit (128 x 16)
+ * NMC93C66 4096 Bit (256 x 16)
+ * Compatible devices include FM93C46 and others.
+ *
+ * Other drivers use these interface functions:
+ * eeprom93xx_new   - add a new EEPROM (with 16, 64 or 256 words)
+ * eeprom93xx_free  - destroy EEPROM
+ * eeprom93xx_read  - read data from the EEPROM
+ * eeprom93xx_write - write data to the EEPROM
+ * eeprom93xx_data  - get EEPROM data array for external manipulation
+ *
+ * Todo list:
+ * - No emulation of EEPROM timings.
+ */
+
+#include "hw/hw.h"
+#include "hw/nvram/eeprom93xx.h"
+
+/* Debug EEPROM emulation. */
+//~ #define DEBUG_EEPROM
+
+#ifdef DEBUG_EEPROM
+#define logout(fmt, ...) fprintf(stderr, "EEPROM\t%-24s" fmt, __func__, ## __VA_ARGS__)
+#else
+#define logout(fmt, ...) ((void)0)
+#endif
+
+#define EEPROM_INSTANCE  0
+#define OLD_EEPROM_VERSION 20061112
+#define EEPROM_VERSION (OLD_EEPROM_VERSION + 1)
+
+#if 0
+typedef enum {
+  eeprom_read  = 0x80,   /* read register xx */
+  eeprom_write = 0x40,   /* write register xx */
+  eeprom_erase = 0xc0,   /* erase register xx */
+  eeprom_ewen  = 0x30,   /* erase / write enable */
+  eeprom_ewds  = 0x00,   /* erase / write disable */
+  eeprom_eral  = 0x20,   /* erase all registers */
+  eeprom_wral  = 0x10,   /* write all registers */
+  eeprom_amask = 0x0f,
+  eeprom_imask = 0xf0
+} eeprom_instruction_t;
+#endif
+
+#ifdef DEBUG_EEPROM
+static const char *opstring[] = {
+  "extended", "write", "read", "erase"
+};
+#endif
+
+struct _eeprom_t {
+    uint8_t  tick;
+    uint8_t  address;
+    uint8_t  command;
+    uint8_t  writable;
+
+    uint8_t eecs;
+    uint8_t eesk;
+    uint8_t eedo;
+
+    uint8_t  addrbits;
+    uint16_t size;
+    uint16_t data;
+    uint16_t contents[0];
+};
+
+/* Code for saving and restoring of EEPROM state. */
+
+/* Restore an uint16_t from an uint8_t
+   This is a Big hack, but it is how the old state did it.
+ */
+
+static int get_uint16_from_uint8(QEMUFile *f, void *pv, size_t size)
+{
+    uint16_t *v = pv;
+    *v = qemu_get_ubyte(f);
+    return 0;
+}
+
+static void put_unused(QEMUFile *f, void *pv, size_t size)
+{
+    fprintf(stderr, "uint16_from_uint8 is used only for backwards compatibility.\n");
+    fprintf(stderr, "Never should be used to write a new state.\n");
+    exit(0);
+}
+
+static const VMStateInfo vmstate_hack_uint16_from_uint8 = {
+    .name = "uint16_from_uint8",
+    .get  = get_uint16_from_uint8,
+    .put  = put_unused,
+};
+
+#define VMSTATE_UINT16_HACK_TEST(_f, _s, _t)                           \
+    VMSTATE_SINGLE_TEST(_f, _s, _t, 0, vmstate_hack_uint16_from_uint8, uint16_t)
+
+static bool is_old_eeprom_version(void *opaque, int version_id)
+{
+    return version_id == OLD_EEPROM_VERSION;
+}
+
+static const VMStateDescription vmstate_eeprom = {
+    .name = "eeprom",
+    .version_id = EEPROM_VERSION,
+    .minimum_version_id = OLD_EEPROM_VERSION,
+    .minimum_version_id_old = OLD_EEPROM_VERSION,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT8(tick, eeprom_t),
+        VMSTATE_UINT8(address, eeprom_t),
+        VMSTATE_UINT8(command, eeprom_t),
+        VMSTATE_UINT8(writable, eeprom_t),
+
+        VMSTATE_UINT8(eecs, eeprom_t),
+        VMSTATE_UINT8(eesk, eeprom_t),
+        VMSTATE_UINT8(eedo, eeprom_t),
+
+        VMSTATE_UINT8(addrbits, eeprom_t),
+        VMSTATE_UINT16_HACK_TEST(size, eeprom_t, is_old_eeprom_version),
+        VMSTATE_UNUSED_TEST(is_old_eeprom_version, 1),
+        VMSTATE_UINT16_EQUAL_V(size, eeprom_t, EEPROM_VERSION),
+        VMSTATE_UINT16(data, eeprom_t),
+        VMSTATE_VARRAY_UINT16_UNSAFE(contents, eeprom_t, size, 0,
+                                     vmstate_info_uint16, uint16_t),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+void eeprom93xx_write(eeprom_t *eeprom, int eecs, int eesk, int eedi)
+{
+    uint8_t tick = eeprom->tick;
+    uint8_t eedo = eeprom->eedo;
+    uint16_t address = eeprom->address;
+    uint8_t command = eeprom->command;
+
+    logout("CS=%u SK=%u DI=%u DO=%u, tick = %u\n",
+           eecs, eesk, eedi, eedo, tick);
+
+    if (! eeprom->eecs && eecs) {
+        /* Start chip select cycle. */
+        logout("Cycle start, waiting for 1st start bit (0)\n");
+        tick = 0;
+        command = 0x0;
+        address = 0x0;
+    } else if (eeprom->eecs && ! eecs) {
+        /* End chip select cycle. This triggers write / erase. */
+        if (eeprom->writable) {
+            uint8_t subcommand = address >> (eeprom->addrbits - 2);
+            if (command == 0 && subcommand == 2) {
+                /* Erase all. */
+                for (address = 0; address < eeprom->size; address++) {
+                    eeprom->contents[address] = 0xffff;
+                }
+            } else if (command == 3) {
+                /* Erase word. */
+                eeprom->contents[address] = 0xffff;
+            } else if (tick >= 2 + 2 + eeprom->addrbits + 16) {
+                if (command == 1) {
+                    /* Write word. */
+                    eeprom->contents[address] &= eeprom->data;
+                } else if (command == 0 && subcommand == 1) {
+                    /* Write all. */
+                    for (address = 0; address < eeprom->size; address++) {
+                        eeprom->contents[address] &= eeprom->data;
+                    }
+                }
+            }
+        }
+        /* Output DO is tristate, read results in 1. */
+        eedo = 1;
+    } else if (eecs && ! eeprom->eesk && eesk) {
+        /* Raising edge of clock shifts data in. */
+        if (tick == 0) {
+            /* Wait for 1st start bit. */
+            if (eedi == 0) {
+                logout("Got correct 1st start bit, waiting for 2nd start bit (1)\n");
+                tick++;
+            } else {
+                logout("wrong 1st start bit (is 1, should be 0)\n");
+                tick = 2;
+                //~ assert(!"wrong start bit");
+            }
+        } else if (tick == 1) {
+            /* Wait for 2nd start bit. */
+            if (eedi != 0) {
+                logout("Got correct 2nd start bit, getting command + address\n");
+                tick++;
+            } else {
+                logout("1st start bit is longer than needed\n");
+            }
+        } else if (tick < 2 + 2) {
+            /* Got 2 start bits, transfer 2 opcode bits. */
+            tick++;
+            command <<= 1;
+            if (eedi) {
+                command += 1;
+            }
+        } else if (tick < 2 + 2 + eeprom->addrbits) {
+            /* Got 2 start bits and 2 opcode bits, transfer all address bits. */
+            tick++;
+            address = ((address << 1) | eedi);
+            if (tick == 2 + 2 + eeprom->addrbits) {
+                logout("%s command, address = 0x%02x (value 0x%04x)\n",
+                       opstring[command], address, eeprom->contents[address]);
+                if (command == 2) {
+                    eedo = 0;
+                }
+                address = address % eeprom->size;
+                if (command == 0) {
+                    /* Command code in upper 2 bits of address. */
+                    switch (address >> (eeprom->addrbits - 2)) {
+                        case 0:
+                            logout("write disable command\n");
+                            eeprom->writable = 0;
+                            break;
+                        case 1:
+                            logout("write all command\n");
+                            break;
+                        case 2:
+                            logout("erase all command\n");
+                            break;
+                        case 3:
+                            logout("write enable command\n");
+                            eeprom->writable = 1;
+                            break;
+                    }
+                } else {
+                    /* Read, write or erase word. */
+                    eeprom->data = eeprom->contents[address];
+                }
+            }
+        } else if (tick < 2 + 2 + eeprom->addrbits + 16) {
+            /* Transfer 16 data bits. */
+            tick++;
+            if (command == 2) {
+                /* Read word. */
+                eedo = ((eeprom->data & 0x8000) != 0);
+            }
+            eeprom->data <<= 1;
+            eeprom->data += eedi;
+        } else {
+            logout("additional unneeded tick, not processed\n");
+        }
+    }
+    /* Save status of EEPROM. */
+    eeprom->tick = tick;
+    eeprom->eecs = eecs;
+    eeprom->eesk = eesk;
+    eeprom->eedo = eedo;
+    eeprom->address = address;
+    eeprom->command = command;
+}
+
+uint16_t eeprom93xx_read(eeprom_t *eeprom)
+{
+    /* Return status of pin DO (0 or 1). */
+    logout("CS=%u DO=%u\n", eeprom->eecs, eeprom->eedo);
+    return (eeprom->eedo);
+}
+
+#if 0
+void eeprom93xx_reset(eeprom_t *eeprom)
+{
+    /* prepare eeprom */
+    logout("eeprom = 0x%p\n", eeprom);
+    eeprom->tick = 0;
+    eeprom->command = 0;
+}
+#endif
+
+eeprom_t *eeprom93xx_new(DeviceState *dev, uint16_t nwords)
+{
+    /* Add a new EEPROM (with 16, 64 or 256 words). */
+    eeprom_t *eeprom;
+    uint8_t addrbits;
+
+    switch (nwords) {
+        case 16:
+        case 64:
+            addrbits = 6;
+            break;
+        case 128:
+        case 256:
+            addrbits = 8;
+            break;
+        default:
+            assert(!"Unsupported EEPROM size, fallback to 64 words!");
+            nwords = 64;
+            addrbits = 6;
+    }
+
+    eeprom = (eeprom_t *)g_malloc0(sizeof(*eeprom) + nwords * 2);
+    eeprom->size = nwords;
+    eeprom->addrbits = addrbits;
+    /* Output DO is tristate, read results in 1. */
+    eeprom->eedo = 1;
+    logout("eeprom = 0x%p, nwords = %u\n", eeprom, nwords);
+    vmstate_register(dev, 0, &vmstate_eeprom, eeprom);
+    return eeprom;
+}
+
+void eeprom93xx_free(DeviceState *dev, eeprom_t *eeprom)
+{
+    /* Destroy EEPROM. */
+    logout("eeprom = 0x%p\n", eeprom);
+    vmstate_unregister(dev, &vmstate_eeprom, eeprom);
+    g_free(eeprom);
+}
+
+uint16_t *eeprom93xx_data(eeprom_t *eeprom)
+{
+    /* Get EEPROM data array. */
+    return &eeprom->contents[0];
+}
+
+/* eof */
diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c
new file mode 100644 (file)
index 0000000..97bba87
--- /dev/null
@@ -0,0 +1,574 @@
+/*
+ * QEMU Firmware configuration device emulation
+ *
+ * Copyright (c) 2008 Gleb Natapov
+ *
+ * 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 "hw/hw.h"
+#include "sysemu/sysemu.h"
+#include "hw/isa/isa.h"
+#include "hw/nvram/fw_cfg.h"
+#include "hw/sysbus.h"
+#include "trace.h"
+#include "qemu/error-report.h"
+#include "qemu/config-file.h"
+
+#define FW_CFG_SIZE 2
+#define FW_CFG_DATA_SIZE 1
+
+typedef struct FWCfgEntry {
+    uint32_t len;
+    uint8_t *data;
+    void *callback_opaque;
+    FWCfgCallback callback;
+} FWCfgEntry;
+
+struct FWCfgState {
+    SysBusDevice busdev;
+    MemoryRegion ctl_iomem, data_iomem, comb_iomem;
+    uint32_t ctl_iobase, data_iobase;
+    FWCfgEntry entries[2][FW_CFG_MAX_ENTRY];
+    FWCfgFiles *files;
+    uint16_t cur_entry;
+    uint32_t cur_offset;
+    Notifier machine_ready;
+};
+
+#define JPG_FILE 0
+#define BMP_FILE 1
+
+static char *read_splashfile(char *filename, size_t *file_sizep,
+                             int *file_typep)
+{
+    GError *err = NULL;
+    gboolean res;
+    gchar *content;
+    int file_type;
+    unsigned int filehead;
+    int bmp_bpp;
+
+    res = g_file_get_contents(filename, &content, file_sizep, &err);
+    if (res == FALSE) {
+        error_report("failed to read splash file '%s'", filename);
+        g_error_free(err);
+        return NULL;
+    }
+
+    /* check file size */
+    if (*file_sizep < 30) {
+        goto error;
+    }
+
+    /* check magic ID */
+    filehead = ((content[0] & 0xff) + (content[1] << 8)) & 0xffff;
+    if (filehead == 0xd8ff) {
+        file_type = JPG_FILE;
+    } else if (filehead == 0x4d42) {
+        file_type = BMP_FILE;
+    } else {
+        goto error;
+    }
+
+    /* check BMP bpp */
+    if (file_type == BMP_FILE) {
+        bmp_bpp = (content[28] + (content[29] << 8)) & 0xffff;
+        if (bmp_bpp != 24) {
+            goto error;
+        }
+    }
+
+    /* return values */
+    *file_typep = file_type;
+
+    return content;
+
+error:
+    error_report("splash file '%s' format not recognized; must be JPEG "
+                 "or 24 bit BMP", filename);
+    g_free(content);
+    return NULL;
+}
+
+static void fw_cfg_bootsplash(FWCfgState *s)
+{
+    int boot_splash_time = -1;
+    const char *boot_splash_filename = NULL;
+    char *p;
+    char *filename, *file_data;
+    size_t file_size;
+    int file_type;
+    const char *temp;
+
+    /* get user configuration */
+    QemuOptsList *plist = qemu_find_opts("boot-opts");
+    QemuOpts *opts = QTAILQ_FIRST(&plist->head);
+    if (opts != NULL) {
+        temp = qemu_opt_get(opts, "splash");
+        if (temp != NULL) {
+            boot_splash_filename = temp;
+        }
+        temp = qemu_opt_get(opts, "splash-time");
+        if (temp != NULL) {
+            p = (char *)temp;
+            boot_splash_time = strtol(p, (char **)&p, 10);
+        }
+    }
+
+    /* insert splash time if user configurated */
+    if (boot_splash_time >= 0) {
+        /* validate the input */
+        if (boot_splash_time > 0xffff) {
+            error_report("splash time is big than 65535, force it to 65535.");
+            boot_splash_time = 0xffff;
+        }
+        /* use little endian format */
+        qemu_extra_params_fw[0] = (uint8_t)(boot_splash_time & 0xff);
+        qemu_extra_params_fw[1] = (uint8_t)((boot_splash_time >> 8) & 0xff);
+        fw_cfg_add_file(s, "etc/boot-menu-wait", qemu_extra_params_fw, 2);
+    }
+
+    /* insert splash file if user configurated */
+    if (boot_splash_filename != NULL) {
+        filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, boot_splash_filename);
+        if (filename == NULL) {
+            error_report("failed to find file '%s'.", boot_splash_filename);
+            return;
+        }
+
+        /* loading file data */
+        file_data = read_splashfile(filename, &file_size, &file_type);
+        if (file_data == NULL) {
+            g_free(filename);
+            return;
+        }
+        if (boot_splash_filedata != NULL) {
+            g_free(boot_splash_filedata);
+        }
+        boot_splash_filedata = (uint8_t *)file_data;
+        boot_splash_filedata_size = file_size;
+
+        /* insert data */
+        if (file_type == JPG_FILE) {
+            fw_cfg_add_file(s, "bootsplash.jpg",
+                    boot_splash_filedata, boot_splash_filedata_size);
+        } else {
+            fw_cfg_add_file(s, "bootsplash.bmp",
+                    boot_splash_filedata, boot_splash_filedata_size);
+        }
+        g_free(filename);
+    }
+}
+
+static void fw_cfg_reboot(FWCfgState *s)
+{
+    int reboot_timeout = -1;
+    char *p;
+    const char *temp;
+
+    /* get user configuration */
+    QemuOptsList *plist = qemu_find_opts("boot-opts");
+    QemuOpts *opts = QTAILQ_FIRST(&plist->head);
+    if (opts != NULL) {
+        temp = qemu_opt_get(opts, "reboot-timeout");
+        if (temp != NULL) {
+            p = (char *)temp;
+            reboot_timeout = strtol(p, (char **)&p, 10);
+        }
+    }
+    /* validate the input */
+    if (reboot_timeout > 0xffff) {
+        error_report("reboot timeout is larger than 65535, force it to 65535.");
+        reboot_timeout = 0xffff;
+    }
+    fw_cfg_add_file(s, "etc/boot-fail-wait", g_memdup(&reboot_timeout, 4), 4);
+}
+
+static void fw_cfg_write(FWCfgState *s, uint8_t value)
+{
+    int arch = !!(s->cur_entry & FW_CFG_ARCH_LOCAL);
+    FWCfgEntry *e = &s->entries[arch][s->cur_entry & FW_CFG_ENTRY_MASK];
+
+    trace_fw_cfg_write(s, value);
+
+    if (s->cur_entry & FW_CFG_WRITE_CHANNEL && e->callback &&
+        s->cur_offset < e->len) {
+        e->data[s->cur_offset++] = value;
+        if (s->cur_offset == e->len) {
+            e->callback(e->callback_opaque, e->data);
+            s->cur_offset = 0;
+        }
+    }
+}
+
+static int fw_cfg_select(FWCfgState *s, uint16_t key)
+{
+    int ret;
+
+    s->cur_offset = 0;
+    if ((key & FW_CFG_ENTRY_MASK) >= FW_CFG_MAX_ENTRY) {
+        s->cur_entry = FW_CFG_INVALID;
+        ret = 0;
+    } else {
+        s->cur_entry = key;
+        ret = 1;
+    }
+
+    trace_fw_cfg_select(s, key, ret);
+    return ret;
+}
+
+static uint8_t fw_cfg_read(FWCfgState *s)
+{
+    int arch = !!(s->cur_entry & FW_CFG_ARCH_LOCAL);
+    FWCfgEntry *e = &s->entries[arch][s->cur_entry & FW_CFG_ENTRY_MASK];
+    uint8_t ret;
+
+    if (s->cur_entry == FW_CFG_INVALID || !e->data || s->cur_offset >= e->len)
+        ret = 0;
+    else
+        ret = e->data[s->cur_offset++];
+
+    trace_fw_cfg_read(s, ret);
+    return ret;
+}
+
+static uint64_t fw_cfg_data_mem_read(void *opaque, hwaddr addr,
+                                     unsigned size)
+{
+    return fw_cfg_read(opaque);
+}
+
+static void fw_cfg_data_mem_write(void *opaque, hwaddr addr,
+                                  uint64_t value, unsigned size)
+{
+    fw_cfg_write(opaque, (uint8_t)value);
+}
+
+static void fw_cfg_ctl_mem_write(void *opaque, hwaddr addr,
+                                 uint64_t value, unsigned size)
+{
+    fw_cfg_select(opaque, (uint16_t)value);
+}
+
+static bool fw_cfg_ctl_mem_valid(void *opaque, hwaddr addr,
+                                 unsigned size, bool is_write)
+{
+    return is_write && size == 2;
+}
+
+static uint64_t fw_cfg_comb_read(void *opaque, hwaddr addr,
+                                 unsigned size)
+{
+    return fw_cfg_read(opaque);
+}
+
+static void fw_cfg_comb_write(void *opaque, hwaddr addr,
+                              uint64_t value, unsigned size)
+{
+    switch (size) {
+    case 1:
+        fw_cfg_write(opaque, (uint8_t)value);
+        break;
+    case 2:
+        fw_cfg_select(opaque, (uint16_t)value);
+        break;
+    }
+}
+
+static bool fw_cfg_comb_valid(void *opaque, hwaddr addr,
+                                  unsigned size, bool is_write)
+{
+    return (size == 1) || (is_write && size == 2);
+}
+
+static const MemoryRegionOps fw_cfg_ctl_mem_ops = {
+    .write = fw_cfg_ctl_mem_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid.accepts = fw_cfg_ctl_mem_valid,
+};
+
+static const MemoryRegionOps fw_cfg_data_mem_ops = {
+    .read = fw_cfg_data_mem_read,
+    .write = fw_cfg_data_mem_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+};
+
+static const MemoryRegionOps fw_cfg_comb_mem_ops = {
+    .read = fw_cfg_comb_read,
+    .write = fw_cfg_comb_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid.accepts = fw_cfg_comb_valid,
+};
+
+static void fw_cfg_reset(DeviceState *d)
+{
+    FWCfgState *s = DO_UPCAST(FWCfgState, busdev.qdev, d);
+
+    fw_cfg_select(s, 0);
+}
+
+/* Save restore 32 bit int as uint16_t
+   This is a Big hack, but it is how the old state did it.
+   Or we broke compatibility in the state, or we can't use struct tm
+ */
+
+static int get_uint32_as_uint16(QEMUFile *f, void *pv, size_t size)
+{
+    uint32_t *v = pv;
+    *v = qemu_get_be16(f);
+    return 0;
+}
+
+static void put_unused(QEMUFile *f, void *pv, size_t size)
+{
+    fprintf(stderr, "uint32_as_uint16 is only used for backward compatibility.\n");
+    fprintf(stderr, "This functions shouldn't be called.\n");
+}
+
+static const VMStateInfo vmstate_hack_uint32_as_uint16 = {
+    .name = "int32_as_uint16",
+    .get  = get_uint32_as_uint16,
+    .put  = put_unused,
+};
+
+#define VMSTATE_UINT16_HACK(_f, _s, _t)                                    \
+    VMSTATE_SINGLE_TEST(_f, _s, _t, 0, vmstate_hack_uint32_as_uint16, uint32_t)
+
+
+static bool is_version_1(void *opaque, int version_id)
+{
+    return version_id == 1;
+}
+
+static const VMStateDescription vmstate_fw_cfg = {
+    .name = "fw_cfg",
+    .version_id = 2,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT16(cur_entry, FWCfgState),
+        VMSTATE_UINT16_HACK(cur_offset, FWCfgState, is_version_1),
+        VMSTATE_UINT32_V(cur_offset, FWCfgState, 2),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+void fw_cfg_add_bytes(FWCfgState *s, uint16_t key, void *data, size_t len)
+{
+    int arch = !!(key & FW_CFG_ARCH_LOCAL);
+
+    key &= FW_CFG_ENTRY_MASK;
+
+    assert(key < FW_CFG_MAX_ENTRY && len < UINT32_MAX);
+
+    s->entries[arch][key].data = data;
+    s->entries[arch][key].len = (uint32_t)len;
+}
+
+void fw_cfg_add_string(FWCfgState *s, uint16_t key, const char *value)
+{
+    size_t sz = strlen(value) + 1;
+
+    return fw_cfg_add_bytes(s, key, g_memdup(value, sz), sz);
+}
+
+void fw_cfg_add_i16(FWCfgState *s, uint16_t key, uint16_t value)
+{
+    uint16_t *copy;
+
+    copy = g_malloc(sizeof(value));
+    *copy = cpu_to_le16(value);
+    fw_cfg_add_bytes(s, key, copy, sizeof(value));
+}
+
+void fw_cfg_add_i32(FWCfgState *s, uint16_t key, uint32_t value)
+{
+    uint32_t *copy;
+
+    copy = g_malloc(sizeof(value));
+    *copy = cpu_to_le32(value);
+    fw_cfg_add_bytes(s, key, copy, sizeof(value));
+}
+
+void fw_cfg_add_i64(FWCfgState *s, uint16_t key, uint64_t value)
+{
+    uint64_t *copy;
+
+    copy = g_malloc(sizeof(value));
+    *copy = cpu_to_le64(value);
+    fw_cfg_add_bytes(s, key, copy, sizeof(value));
+}
+
+void fw_cfg_add_callback(FWCfgState *s, uint16_t key, FWCfgCallback callback,
+                         void *callback_opaque, void *data, size_t len)
+{
+    int arch = !!(key & FW_CFG_ARCH_LOCAL);
+
+    assert(key & FW_CFG_WRITE_CHANNEL);
+
+    key &= FW_CFG_ENTRY_MASK;
+
+    assert(key < FW_CFG_MAX_ENTRY && len <= UINT32_MAX);
+
+    s->entries[arch][key].data = data;
+    s->entries[arch][key].len = (uint32_t)len;
+    s->entries[arch][key].callback_opaque = callback_opaque;
+    s->entries[arch][key].callback = callback;
+}
+
+void fw_cfg_add_file(FWCfgState *s,  const char *filename,
+                     void *data, size_t len)
+{
+    int i, index;
+    size_t dsize;
+
+    if (!s->files) {
+        dsize = sizeof(uint32_t) + sizeof(FWCfgFile) * FW_CFG_FILE_SLOTS;
+        s->files = g_malloc0(dsize);
+        fw_cfg_add_bytes(s, FW_CFG_FILE_DIR, s->files, dsize);
+    }
+
+    index = be32_to_cpu(s->files->count);
+    assert(index < FW_CFG_FILE_SLOTS);
+
+    fw_cfg_add_bytes(s, FW_CFG_FILE_FIRST + index, data, len);
+
+    pstrcpy(s->files->f[index].name, sizeof(s->files->f[index].name),
+            filename);
+    for (i = 0; i < index; i++) {
+        if (strcmp(s->files->f[index].name, s->files->f[i].name) == 0) {
+            trace_fw_cfg_add_file_dupe(s, s->files->f[index].name);
+            return;
+        }
+    }
+
+    s->files->f[index].size   = cpu_to_be32(len);
+    s->files->f[index].select = cpu_to_be16(FW_CFG_FILE_FIRST + index);
+    trace_fw_cfg_add_file(s, index, s->files->f[index].name, len);
+
+    s->files->count = cpu_to_be32(index+1);
+}
+
+static void fw_cfg_machine_ready(struct Notifier *n, void *data)
+{
+    size_t len;
+    FWCfgState *s = container_of(n, FWCfgState, machine_ready);
+    char *bootindex = get_boot_devices_list(&len);
+
+    fw_cfg_add_file(s, "bootorder", (uint8_t*)bootindex, len);
+}
+
+FWCfgState *fw_cfg_init(uint32_t ctl_port, uint32_t data_port,
+                        hwaddr ctl_addr, hwaddr data_addr)
+{
+    DeviceState *dev;
+    SysBusDevice *d;
+    FWCfgState *s;
+
+    dev = qdev_create(NULL, "fw_cfg");
+    qdev_prop_set_uint32(dev, "ctl_iobase", ctl_port);
+    qdev_prop_set_uint32(dev, "data_iobase", data_port);
+    qdev_init_nofail(dev);
+    d = SYS_BUS_DEVICE(dev);
+
+    s = DO_UPCAST(FWCfgState, busdev.qdev, dev);
+
+    if (ctl_addr) {
+        sysbus_mmio_map(d, 0, ctl_addr);
+    }
+    if (data_addr) {
+        sysbus_mmio_map(d, 1, data_addr);
+    }
+    fw_cfg_add_bytes(s, FW_CFG_SIGNATURE, (char *)"QEMU", 4);
+    fw_cfg_add_bytes(s, FW_CFG_UUID, qemu_uuid, 16);
+    fw_cfg_add_i16(s, FW_CFG_NOGRAPHIC, (uint16_t)(display_type == DT_NOGRAPHIC));
+    fw_cfg_add_i16(s, FW_CFG_NB_CPUS, (uint16_t)smp_cpus);
+    fw_cfg_add_i16(s, FW_CFG_BOOT_MENU, (uint16_t)boot_menu);
+    fw_cfg_bootsplash(s);
+    fw_cfg_reboot(s);
+
+    s->machine_ready.notify = fw_cfg_machine_ready;
+    qemu_add_machine_init_done_notifier(&s->machine_ready);
+
+    return s;
+}
+
+static int fw_cfg_init1(SysBusDevice *dev)
+{
+    FWCfgState *s = FROM_SYSBUS(FWCfgState, dev);
+
+    memory_region_init_io(&s->ctl_iomem, &fw_cfg_ctl_mem_ops, s,
+                          "fwcfg.ctl", FW_CFG_SIZE);
+    sysbus_init_mmio(dev, &s->ctl_iomem);
+    memory_region_init_io(&s->data_iomem, &fw_cfg_data_mem_ops, s,
+                          "fwcfg.data", FW_CFG_DATA_SIZE);
+    sysbus_init_mmio(dev, &s->data_iomem);
+    /* In case ctl and data overlap: */
+    memory_region_init_io(&s->comb_iomem, &fw_cfg_comb_mem_ops, s,
+                          "fwcfg", FW_CFG_SIZE);
+
+    if (s->ctl_iobase + 1 == s->data_iobase) {
+        sysbus_add_io(dev, s->ctl_iobase, &s->comb_iomem);
+    } else {
+        if (s->ctl_iobase) {
+            sysbus_add_io(dev, s->ctl_iobase, &s->ctl_iomem);
+        }
+        if (s->data_iobase) {
+            sysbus_add_io(dev, s->data_iobase, &s->data_iomem);
+        }
+    }
+    return 0;
+}
+
+static Property fw_cfg_properties[] = {
+    DEFINE_PROP_HEX32("ctl_iobase", FWCfgState, ctl_iobase, -1),
+    DEFINE_PROP_HEX32("data_iobase", FWCfgState, data_iobase, -1),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void fw_cfg_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = fw_cfg_init1;
+    dc->no_user = 1;
+    dc->reset = fw_cfg_reset;
+    dc->vmsd = &vmstate_fw_cfg;
+    dc->props = fw_cfg_properties;
+}
+
+static const 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_types(void)
+{
+    type_register_static(&fw_cfg_info);
+}
+
+type_init(fw_cfg_register_types)
diff --git a/hw/nvram/mac_nvram.c b/hw/nvram/mac_nvram.c
new file mode 100644 (file)
index 0000000..5223330
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ * PowerMac NVRAM emulation
+ *
+ * Copyright (c) 2005-2007 Fabrice Bellard
+ * Copyright (c) 2007 Jocelyn Mayer
+ *
+ * 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 "hw/hw.h"
+#include "hw/sparc/firmware_abi.h"
+#include "sysemu/sysemu.h"
+#include "hw/ppc/mac.h"
+
+/* debug NVR */
+//#define DEBUG_NVR
+
+#ifdef DEBUG_NVR
+#define NVR_DPRINTF(fmt, ...)                                   \
+    do { printf("NVR: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define NVR_DPRINTF(fmt, ...)
+#endif
+
+#define DEF_SYSTEM_SIZE 0xc10
+
+/* Direct access to NVRAM */
+uint8_t macio_nvram_read(MacIONVRAMState *s, uint32_t addr)
+{
+    uint32_t ret;
+
+    if (addr < s->size) {
+        ret = s->data[addr];
+    } else {
+        ret = -1;
+    }
+    NVR_DPRINTF("read addr %04" PRIx32 " val %" PRIx8 "\n", addr, ret);
+
+    return ret;
+}
+
+void macio_nvram_write(MacIONVRAMState *s, uint32_t addr, uint8_t val)
+{
+    NVR_DPRINTF("write addr %04" PRIx32 " val %" PRIx8 "\n", addr, val);
+    if (addr < s->size) {
+        s->data[addr] = val;
+    }
+}
+
+/* macio style NVRAM device */
+static void macio_nvram_writeb(void *opaque, hwaddr addr,
+                               uint64_t value, unsigned size)
+{
+    MacIONVRAMState *s = opaque;
+
+    addr = (addr >> s->it_shift) & (s->size - 1);
+    s->data[addr] = value;
+    NVR_DPRINTF("writeb addr %04" PHYS_PRIx " val %" PRIx64 "\n", addr, value);
+}
+
+static uint64_t macio_nvram_readb(void *opaque, hwaddr addr,
+                                  unsigned size)
+{
+    MacIONVRAMState *s = opaque;
+    uint32_t value;
+
+    addr = (addr >> s->it_shift) & (s->size - 1);
+    value = s->data[addr];
+    NVR_DPRINTF("readb addr %04x val %x\n", (int)addr, value);
+
+    return value;
+}
+
+static const MemoryRegionOps macio_nvram_ops = {
+    .read = macio_nvram_readb,
+    .write = macio_nvram_writeb,
+    .endianness = DEVICE_BIG_ENDIAN,
+};
+
+static const VMStateDescription vmstate_macio_nvram = {
+    .name = "macio_nvram",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_VBUFFER_UINT32(data, MacIONVRAMState, 0, NULL, 0, size),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+
+static void macio_nvram_reset(DeviceState *dev)
+{
+}
+
+static void macio_nvram_realizefn(DeviceState *dev, Error **errp)
+{
+    SysBusDevice *d = SYS_BUS_DEVICE(dev);
+    MacIONVRAMState *s = MACIO_NVRAM(dev);
+
+    s->data = g_malloc0(s->size);
+
+    memory_region_init_io(&s->mem, &macio_nvram_ops, s, "macio-nvram",
+                          s->size << s->it_shift);
+    sysbus_init_mmio(d, &s->mem);
+}
+
+static void macio_nvram_unrealizefn(DeviceState *dev, Error **errp)
+{
+    MacIONVRAMState *s = MACIO_NVRAM(dev);
+
+    g_free(s->data);
+}
+
+static Property macio_nvram_properties[] = {
+    DEFINE_PROP_UINT32("size", MacIONVRAMState, size, 0),
+    DEFINE_PROP_UINT32("it_shift", MacIONVRAMState, it_shift, 0),
+    DEFINE_PROP_END_OF_LIST()
+};
+
+static void macio_nvram_class_init(ObjectClass *oc, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(oc);
+
+    dc->realize = macio_nvram_realizefn;
+    dc->unrealize = macio_nvram_unrealizefn;
+    dc->reset = macio_nvram_reset;
+    dc->vmsd = &vmstate_macio_nvram;
+    dc->props = macio_nvram_properties;
+}
+
+static const TypeInfo macio_nvram_type_info = {
+    .name = TYPE_MACIO_NVRAM,
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(MacIONVRAMState),
+    .class_init = macio_nvram_class_init,
+};
+
+static void macio_nvram_register_types(void)
+{
+    type_register_static(&macio_nvram_type_info);
+}
+
+/* Set up a system OpenBIOS NVRAM partition */
+void pmac_format_nvram_partition (MacIONVRAMState *nvr, int len)
+{
+    unsigned int i;
+    uint32_t start = 0, end;
+    struct OpenBIOS_nvpart_v1 *part_header;
+
+    // OpenBIOS nvram variables
+    // Variable partition
+    part_header = (struct OpenBIOS_nvpart_v1 *)nvr->data;
+    part_header->signature = OPENBIOS_PART_SYSTEM;
+    pstrcpy(part_header->name, sizeof(part_header->name), "system");
+
+    end = start + sizeof(struct OpenBIOS_nvpart_v1);
+    for (i = 0; i < nb_prom_envs; i++)
+        end = OpenBIOS_set_var(nvr->data, end, prom_envs[i]);
+
+    // End marker
+    nvr->data[end++] = '\0';
+
+    end = start + ((end - start + 15) & ~15);
+    /* XXX: OpenBIOS is not able to grow up a partition. Leave some space for
+       new variables. */
+    if (end < DEF_SYSTEM_SIZE)
+        end = DEF_SYSTEM_SIZE;
+    OpenBIOS_finish_partition(part_header, end - start);
+
+    // free partition
+    start = end;
+    part_header = (struct OpenBIOS_nvpart_v1 *)&nvr->data[start];
+    part_header->signature = OPENBIOS_PART_FREE;
+    pstrcpy(part_header->name, sizeof(part_header->name), "free");
+
+    end = len;
+    OpenBIOS_finish_partition(part_header, end - start);
+}
+
+type_init(macio_nvram_register_types)
diff --git a/hw/nvram/spapr_nvram.c b/hw/nvram/spapr_nvram.c
new file mode 100644 (file)
index 0000000..0cc6cba
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ * QEMU sPAPR NVRAM emulation
+ *
+ * Copyright (C) 2012 David Gibson, IBM Corporation.
+ *
+ * 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 <libfdt.h>
+
+#include "sysemu/device_tree.h"
+#include "hw/sysbus.h"
+#include "hw/ppc/spapr.h"
+#include "hw/ppc/spapr_vio.h"
+
+typedef struct sPAPRNVRAM {
+    VIOsPAPRDevice sdev;
+    uint32_t size;
+    uint8_t *buf;
+    BlockDriverState *drive;
+} sPAPRNVRAM;
+
+#define MIN_NVRAM_SIZE 8192
+#define DEFAULT_NVRAM_SIZE 65536
+#define MAX_NVRAM_SIZE (UINT16_MAX * 16)
+
+static void rtas_nvram_fetch(sPAPREnvironment *spapr,
+                             uint32_t token, uint32_t nargs,
+                             target_ulong args,
+                             uint32_t nret, target_ulong rets)
+{
+    sPAPRNVRAM *nvram = spapr->nvram;
+    hwaddr offset, buffer, len;
+    int alen;
+    void *membuf;
+
+    if ((nargs != 3) || (nret != 2)) {
+        rtas_st(rets, 0, -3);
+        return;
+    }
+
+    if (!nvram) {
+        rtas_st(rets, 0, -1);
+        rtas_st(rets, 1, 0);
+        return;
+    }
+
+    offset = rtas_ld(args, 0);
+    buffer = rtas_ld(args, 1);
+    len = rtas_ld(args, 2);
+
+    if (((offset + len) < offset)
+        || ((offset + len) > nvram->size)) {
+        rtas_st(rets, 0, -3);
+        rtas_st(rets, 1, 0);
+        return;
+    }
+
+    membuf = cpu_physical_memory_map(buffer, &len, 1);
+    if (nvram->drive) {
+        alen = bdrv_pread(nvram->drive, offset, membuf, len);
+    } else {
+        assert(nvram->buf);
+
+        memcpy(membuf, nvram->buf + offset, len);
+        alen = len;
+    }
+    cpu_physical_memory_unmap(membuf, len, 1, len);
+
+    rtas_st(rets, 0, (alen < len) ? -1 : 0);
+    rtas_st(rets, 1, (alen < 0) ? 0 : alen);
+}
+
+static void rtas_nvram_store(sPAPREnvironment *spapr,
+                             uint32_t token, uint32_t nargs,
+                             target_ulong args,
+                             uint32_t nret, target_ulong rets)
+{
+    sPAPRNVRAM *nvram = spapr->nvram;
+    hwaddr offset, buffer, len;
+    int alen;
+    void *membuf;
+
+    if ((nargs != 3) || (nret != 2)) {
+        rtas_st(rets, 0, -3);
+        return;
+    }
+
+    if (!nvram) {
+        rtas_st(rets, 0, -1);
+        return;
+    }
+
+    offset = rtas_ld(args, 0);
+    buffer = rtas_ld(args, 1);
+    len = rtas_ld(args, 2);
+
+    if (((offset + len) < offset)
+        || ((offset + len) > nvram->size)) {
+        rtas_st(rets, 0, -3);
+        return;
+    }
+
+    membuf = cpu_physical_memory_map(buffer, &len, 0);
+    if (nvram->drive) {
+        alen = bdrv_pwrite(nvram->drive, offset, membuf, len);
+    } else {
+        assert(nvram->buf);
+
+        memcpy(nvram->buf + offset, membuf, len);
+        alen = len;
+    }
+    cpu_physical_memory_unmap(membuf, len, 0, len);
+
+    rtas_st(rets, 0, (alen < len) ? -1 : 0);
+    rtas_st(rets, 1, (alen < 0) ? 0 : alen);
+}
+
+static int spapr_nvram_init(VIOsPAPRDevice *dev)
+{
+    sPAPRNVRAM *nvram = (sPAPRNVRAM *)dev;
+
+    if (nvram->drive) {
+        nvram->size = bdrv_getlength(nvram->drive);
+    } else {
+        nvram->size = DEFAULT_NVRAM_SIZE;
+        nvram->buf = g_malloc0(nvram->size);
+    }
+
+    if ((nvram->size < MIN_NVRAM_SIZE) || (nvram->size > MAX_NVRAM_SIZE)) {
+        fprintf(stderr, "spapr-nvram must be between %d and %d bytes in size\n",
+                MIN_NVRAM_SIZE, MAX_NVRAM_SIZE);
+        return -1;
+    }
+
+    spapr_rtas_register("nvram-fetch", rtas_nvram_fetch);
+    spapr_rtas_register("nvram-store", rtas_nvram_store);
+
+    return 0;
+}
+
+static int spapr_nvram_devnode(VIOsPAPRDevice *dev, void *fdt, int node_off)
+{
+    sPAPRNVRAM *nvram = (sPAPRNVRAM *)dev;
+
+    return fdt_setprop_cell(fdt, node_off, "#bytes", nvram->size);
+}
+
+static Property spapr_nvram_properties[] = {
+    DEFINE_SPAPR_PROPERTIES(sPAPRNVRAM, sdev),
+    DEFINE_PROP_DRIVE("drive", sPAPRNVRAM, drive),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void spapr_nvram_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    VIOsPAPRDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass);
+
+    k->init = spapr_nvram_init;
+    k->devnode = spapr_nvram_devnode;
+    k->dt_name = "nvram";
+    k->dt_type = "nvram";
+    k->dt_compatible = "qemu,spapr-nvram";
+    dc->props = spapr_nvram_properties;
+}
+
+static const TypeInfo spapr_nvram_type_info = {
+    .name          = "spapr-nvram",
+    .parent        = TYPE_VIO_SPAPR_DEVICE,
+    .instance_size = sizeof(sPAPRNVRAM),
+    .class_init    = spapr_nvram_class_init,
+};
+
+static void spapr_nvram_register_types(void)
+{
+    type_register_static(&spapr_nvram_type_info);
+}
+
+type_init(spapr_nvram_register_types)
diff --git a/hw/omap.h b/hw/omap.h
deleted file mode 100644 (file)
index 188cda8..0000000
--- a/hw/omap.h
+++ /dev/null
@@ -1,1015 +0,0 @@
-/*
- * Texas Instruments OMAP processors.
- *
- * Copyright (C) 2006-2008 Andrzej Zaborowski  <balrog@zabor.org>
- *
- * 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 or
- * (at your option) version 3 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
- * 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 hw_omap_h
-#include "exec/memory.h"
-# define hw_omap_h             "omap.h"
-#include "hw/irq.h"
-
-# define OMAP_EMIFS_BASE       0x00000000
-# define OMAP2_Q0_BASE         0x00000000
-# define OMAP_CS0_BASE         0x00000000
-# define OMAP_CS1_BASE         0x04000000
-# define OMAP_CS2_BASE         0x08000000
-# define OMAP_CS3_BASE         0x0c000000
-# define OMAP_EMIFF_BASE       0x10000000
-# define OMAP_IMIF_BASE                0x20000000
-# define OMAP_LOCALBUS_BASE    0x30000000
-# define OMAP2_Q1_BASE         0x40000000
-# define OMAP2_L4_BASE         0x48000000
-# define OMAP2_SRAM_BASE       0x40200000
-# define OMAP2_L3_BASE         0x68000000
-# define OMAP2_Q2_BASE         0x80000000
-# define OMAP2_Q3_BASE         0xc0000000
-# define OMAP_MPUI_BASE                0xe1000000
-
-# define OMAP730_SRAM_SIZE     0x00032000
-# define OMAP15XX_SRAM_SIZE    0x00030000
-# define OMAP16XX_SRAM_SIZE    0x00004000
-# define OMAP1611_SRAM_SIZE    0x0003e800
-# define OMAP242X_SRAM_SIZE    0x000a0000
-# define OMAP243X_SRAM_SIZE    0x00010000
-# define OMAP_CS0_SIZE         0x04000000
-# define OMAP_CS1_SIZE         0x04000000
-# define OMAP_CS2_SIZE         0x04000000
-# define OMAP_CS3_SIZE         0x04000000
-
-/* omap_clk.c */
-struct omap_mpu_state_s;
-typedef struct clk *omap_clk;
-omap_clk omap_findclk(struct omap_mpu_state_s *mpu, const char *name);
-void omap_clk_init(struct omap_mpu_state_s *mpu);
-void omap_clk_adduser(struct clk *clk, qemu_irq user);
-void omap_clk_get(omap_clk clk);
-void omap_clk_put(omap_clk clk);
-void omap_clk_onoff(omap_clk clk, int on);
-void omap_clk_canidle(omap_clk clk, int can);
-void omap_clk_setrate(omap_clk clk, int divide, int multiply);
-int64_t omap_clk_getrate(omap_clk clk);
-void omap_clk_reparent(omap_clk clk, omap_clk parent);
-
-/* OMAP2 l4 Interconnect */
-struct omap_l4_s;
-struct omap_l4_region_s {
-    hwaddr offset;
-    size_t size;
-    int access;
-};
-struct omap_l4_agent_info_s {
-    int ta;
-    int region;
-    int regions;
-    int ta_region;
-};
-struct omap_target_agent_s {
-    MemoryRegion iomem;
-    struct omap_l4_s *bus;
-    int regions;
-    const struct omap_l4_region_s *start;
-    hwaddr base;
-    uint32_t component;
-    uint32_t control;
-    uint32_t status;
-};
-struct omap_l4_s *omap_l4_init(MemoryRegion *address_space,
-                               hwaddr base, int ta_num);
-
-struct omap_target_agent_s;
-struct omap_target_agent_s *omap_l4ta_get(
-    struct omap_l4_s *bus,
-    const struct omap_l4_region_s *regions,
-    const struct omap_l4_agent_info_s *agents,
-    int cs);
-hwaddr omap_l4_attach(struct omap_target_agent_s *ta,
-                                         int region, MemoryRegion *mr);
-hwaddr omap_l4_region_base(struct omap_target_agent_s *ta,
-                                       int region);
-hwaddr omap_l4_region_size(struct omap_target_agent_s *ta,
-                                       int region);
-
-/* OMAP2 SDRAM controller */
-struct omap_sdrc_s;
-struct omap_sdrc_s *omap_sdrc_init(MemoryRegion *sysmem,
-                                   hwaddr base);
-void omap_sdrc_reset(struct omap_sdrc_s *s);
-
-/* OMAP2 general purpose memory controller */
-struct omap_gpmc_s;
-struct omap_gpmc_s *omap_gpmc_init(struct omap_mpu_state_s *mpu,
-                                   hwaddr base,
-                                   qemu_irq irq, qemu_irq drq);
-void omap_gpmc_reset(struct omap_gpmc_s *s);
-void omap_gpmc_attach(struct omap_gpmc_s *s, int cs, MemoryRegion *iomem);
-void omap_gpmc_attach_nand(struct omap_gpmc_s *s, int cs, DeviceState *nand);
-
-/*
- * Common IRQ numbers for level 1 interrupt handler
- * See /usr/include/asm-arm/arch-omap/irqs.h in Linux.
- */
-# define OMAP_INT_CAMERA               1
-# define OMAP_INT_FIQ                  3
-# define OMAP_INT_RTDX                 6
-# define OMAP_INT_DSP_MMU_ABORT                7
-# define OMAP_INT_HOST                 8
-# define OMAP_INT_ABORT                        9
-# define OMAP_INT_BRIDGE_PRIV          13
-# define OMAP_INT_GPIO_BANK1           14
-# define OMAP_INT_UART3                        15
-# define OMAP_INT_TIMER3               16
-# define OMAP_INT_DMA_CH0_6            19
-# define OMAP_INT_DMA_CH1_7            20
-# define OMAP_INT_DMA_CH2_8            21
-# define OMAP_INT_DMA_CH3              22
-# define OMAP_INT_DMA_CH4              23
-# define OMAP_INT_DMA_CH5              24
-# define OMAP_INT_DMA_LCD              25
-# define OMAP_INT_TIMER1               26
-# define OMAP_INT_WD_TIMER             27
-# define OMAP_INT_BRIDGE_PUB           28
-# define OMAP_INT_TIMER2               30
-# define OMAP_INT_LCD_CTRL             31
-
-/*
- * Common OMAP-15xx IRQ numbers for level 1 interrupt handler
- */
-# define OMAP_INT_15XX_IH2_IRQ         0
-# define OMAP_INT_15XX_LB_MMU          17
-# define OMAP_INT_15XX_LOCAL_BUS       29
-
-/*
- * OMAP-1510 specific IRQ numbers for level 1 interrupt handler
- */
-# define OMAP_INT_1510_SPI_TX          4
-# define OMAP_INT_1510_SPI_RX          5
-# define OMAP_INT_1510_DSP_MAILBOX1    10
-# define OMAP_INT_1510_DSP_MAILBOX2    11
-
-/*
- * OMAP-310 specific IRQ numbers for level 1 interrupt handler
- */
-# define OMAP_INT_310_McBSP2_TX                4
-# define OMAP_INT_310_McBSP2_RX                5
-# define OMAP_INT_310_HSB_MAILBOX1     12
-# define OMAP_INT_310_HSAB_MMU         18
-
-/*
- * OMAP-1610 specific IRQ numbers for level 1 interrupt handler
- */
-# define OMAP_INT_1610_IH2_IRQ         0
-# define OMAP_INT_1610_IH2_FIQ         2
-# define OMAP_INT_1610_McBSP2_TX       4
-# define OMAP_INT_1610_McBSP2_RX       5
-# define OMAP_INT_1610_DSP_MAILBOX1    10
-# define OMAP_INT_1610_DSP_MAILBOX2    11
-# define OMAP_INT_1610_LCD_LINE                12
-# define OMAP_INT_1610_GPTIMER1                17
-# define OMAP_INT_1610_GPTIMER2                18
-# define OMAP_INT_1610_SSR_FIFO_0      29
-
-/*
- * OMAP-730 specific IRQ numbers for level 1 interrupt handler
- */
-# define OMAP_INT_730_IH2_FIQ          0
-# define OMAP_INT_730_IH2_IRQ          1
-# define OMAP_INT_730_USB_NON_ISO      2
-# define OMAP_INT_730_USB_ISO          3
-# define OMAP_INT_730_ICR              4
-# define OMAP_INT_730_EAC              5
-# define OMAP_INT_730_GPIO_BANK1       6
-# define OMAP_INT_730_GPIO_BANK2       7
-# define OMAP_INT_730_GPIO_BANK3       8
-# define OMAP_INT_730_McBSP2TX         10
-# define OMAP_INT_730_McBSP2RX         11
-# define OMAP_INT_730_McBSP2RX_OVF     12
-# define OMAP_INT_730_LCD_LINE         14
-# define OMAP_INT_730_GSM_PROTECT      15
-# define OMAP_INT_730_TIMER3           16
-# define OMAP_INT_730_GPIO_BANK5       17
-# define OMAP_INT_730_GPIO_BANK6       18
-# define OMAP_INT_730_SPGIO_WR         29
-
-/*
- * Common IRQ numbers for level 2 interrupt handler
- */
-# define OMAP_INT_KEYBOARD             1
-# define OMAP_INT_uWireTX              2
-# define OMAP_INT_uWireRX              3
-# define OMAP_INT_I2C                  4
-# define OMAP_INT_MPUIO                        5
-# define OMAP_INT_USB_HHC_1            6
-# define OMAP_INT_McBSP3TX             10
-# define OMAP_INT_McBSP3RX             11
-# define OMAP_INT_McBSP1TX             12
-# define OMAP_INT_McBSP1RX             13
-# define OMAP_INT_UART1                        14
-# define OMAP_INT_UART2                        15
-# define OMAP_INT_USB_W2FC             20
-# define OMAP_INT_1WIRE                        21
-# define OMAP_INT_OS_TIMER             22
-# define OMAP_INT_OQN                  23
-# define OMAP_INT_GAUGE_32K            24
-# define OMAP_INT_RTC_TIMER            25
-# define OMAP_INT_RTC_ALARM            26
-# define OMAP_INT_DSP_MMU              28
-
-/*
- * OMAP-1510 specific IRQ numbers for level 2 interrupt handler
- */
-# define OMAP_INT_1510_BT_MCSI1TX      16
-# define OMAP_INT_1510_BT_MCSI1RX      17
-# define OMAP_INT_1510_SoSSI_MATCH     19
-# define OMAP_INT_1510_MEM_STICK       27
-# define OMAP_INT_1510_COM_SPI_RO      31
-
-/*
- * OMAP-310 specific IRQ numbers for level 2 interrupt handler
- */
-# define OMAP_INT_310_FAC              0
-# define OMAP_INT_310_USB_HHC_2                7
-# define OMAP_INT_310_MCSI1_FE         16
-# define OMAP_INT_310_MCSI2_FE         17
-# define OMAP_INT_310_USB_W2FC_ISO     29
-# define OMAP_INT_310_USB_W2FC_NON_ISO 30
-# define OMAP_INT_310_McBSP2RX_OF      31
-
-/*
- * OMAP-1610 specific IRQ numbers for level 2 interrupt handler
- */
-# define OMAP_INT_1610_FAC             0
-# define OMAP_INT_1610_USB_HHC_2       7
-# define OMAP_INT_1610_USB_OTG         8
-# define OMAP_INT_1610_SoSSI           9
-# define OMAP_INT_1610_BT_MCSI1TX      16
-# define OMAP_INT_1610_BT_MCSI1RX      17
-# define OMAP_INT_1610_SoSSI_MATCH     19
-# define OMAP_INT_1610_MEM_STICK       27
-# define OMAP_INT_1610_McBSP2RX_OF     31
-# define OMAP_INT_1610_STI             32
-# define OMAP_INT_1610_STI_WAKEUP      33
-# define OMAP_INT_1610_GPTIMER3                34
-# define OMAP_INT_1610_GPTIMER4                35
-# define OMAP_INT_1610_GPTIMER5                36
-# define OMAP_INT_1610_GPTIMER6                37
-# define OMAP_INT_1610_GPTIMER7                38
-# define OMAP_INT_1610_GPTIMER8                39
-# define OMAP_INT_1610_GPIO_BANK2      40
-# define OMAP_INT_1610_GPIO_BANK3      41
-# define OMAP_INT_1610_MMC2            42
-# define OMAP_INT_1610_CF              43
-# define OMAP_INT_1610_WAKE_UP_REQ     46
-# define OMAP_INT_1610_GPIO_BANK4      48
-# define OMAP_INT_1610_SPI             49
-# define OMAP_INT_1610_DMA_CH6         53
-# define OMAP_INT_1610_DMA_CH7         54
-# define OMAP_INT_1610_DMA_CH8         55
-# define OMAP_INT_1610_DMA_CH9         56
-# define OMAP_INT_1610_DMA_CH10                57
-# define OMAP_INT_1610_DMA_CH11                58
-# define OMAP_INT_1610_DMA_CH12                59
-# define OMAP_INT_1610_DMA_CH13                60
-# define OMAP_INT_1610_DMA_CH14                61
-# define OMAP_INT_1610_DMA_CH15                62
-# define OMAP_INT_1610_NAND            63
-
-/*
- * OMAP-730 specific IRQ numbers for level 2 interrupt handler
- */
-# define OMAP_INT_730_HW_ERRORS                0
-# define OMAP_INT_730_NFIQ_PWR_FAIL    1
-# define OMAP_INT_730_CFCD             2
-# define OMAP_INT_730_CFIREQ           3
-# define OMAP_INT_730_I2C              4
-# define OMAP_INT_730_PCC              5
-# define OMAP_INT_730_MPU_EXT_NIRQ     6
-# define OMAP_INT_730_SPI_100K_1       7
-# define OMAP_INT_730_SYREN_SPI                8
-# define OMAP_INT_730_VLYNQ            9
-# define OMAP_INT_730_GPIO_BANK4       10
-# define OMAP_INT_730_McBSP1TX         11
-# define OMAP_INT_730_McBSP1RX         12
-# define OMAP_INT_730_McBSP1RX_OF      13
-# define OMAP_INT_730_UART_MODEM_IRDA_2        14
-# define OMAP_INT_730_UART_MODEM_1     15
-# define OMAP_INT_730_MCSI             16
-# define OMAP_INT_730_uWireTX          17
-# define OMAP_INT_730_uWireRX          18
-# define OMAP_INT_730_SMC_CD           19
-# define OMAP_INT_730_SMC_IREQ         20
-# define OMAP_INT_730_HDQ_1WIRE                21
-# define OMAP_INT_730_TIMER32K         22
-# define OMAP_INT_730_MMC_SDIO         23
-# define OMAP_INT_730_UPLD             24
-# define OMAP_INT_730_USB_HHC_1                27
-# define OMAP_INT_730_USB_HHC_2                28
-# define OMAP_INT_730_USB_GENI         29
-# define OMAP_INT_730_USB_OTG          30
-# define OMAP_INT_730_CAMERA_IF                31
-# define OMAP_INT_730_RNG              32
-# define OMAP_INT_730_DUAL_MODE_TIMER  33
-# define OMAP_INT_730_DBB_RF_EN                34
-# define OMAP_INT_730_MPUIO_KEYPAD     35
-# define OMAP_INT_730_SHA1_MD5         36
-# define OMAP_INT_730_SPI_100K_2       37
-# define OMAP_INT_730_RNG_IDLE         38
-# define OMAP_INT_730_MPUIO            39
-# define OMAP_INT_730_LLPC_LCD_CTRL_OFF        40
-# define OMAP_INT_730_LLPC_OE_FALLING  41
-# define OMAP_INT_730_LLPC_OE_RISING   42
-# define OMAP_INT_730_LLPC_VSYNC       43
-# define OMAP_INT_730_WAKE_UP_REQ      46
-# define OMAP_INT_730_DMA_CH6          53
-# define OMAP_INT_730_DMA_CH7          54
-# define OMAP_INT_730_DMA_CH8          55
-# define OMAP_INT_730_DMA_CH9          56
-# define OMAP_INT_730_DMA_CH10         57
-# define OMAP_INT_730_DMA_CH11         58
-# define OMAP_INT_730_DMA_CH12         59
-# define OMAP_INT_730_DMA_CH13         60
-# define OMAP_INT_730_DMA_CH14         61
-# define OMAP_INT_730_DMA_CH15         62
-# define OMAP_INT_730_NAND             63
-
-/*
- * OMAP-24xx common IRQ numbers
- */
-# define OMAP_INT_24XX_STI             4
-# define OMAP_INT_24XX_SYS_NIRQ                7
-# define OMAP_INT_24XX_L3_IRQ          10
-# define OMAP_INT_24XX_PRCM_MPU_IRQ    11
-# define OMAP_INT_24XX_SDMA_IRQ0       12
-# define OMAP_INT_24XX_SDMA_IRQ1       13
-# define OMAP_INT_24XX_SDMA_IRQ2       14
-# define OMAP_INT_24XX_SDMA_IRQ3       15
-# define OMAP_INT_243X_MCBSP2_IRQ      16
-# define OMAP_INT_243X_MCBSP3_IRQ      17
-# define OMAP_INT_243X_MCBSP4_IRQ      18
-# define OMAP_INT_243X_MCBSP5_IRQ      19
-# define OMAP_INT_24XX_GPMC_IRQ                20
-# define OMAP_INT_24XX_GUFFAW_IRQ      21
-# define OMAP_INT_24XX_IVA_IRQ         22
-# define OMAP_INT_24XX_EAC_IRQ         23
-# define OMAP_INT_24XX_CAM_IRQ         24
-# define OMAP_INT_24XX_DSS_IRQ         25
-# define OMAP_INT_24XX_MAIL_U0_MPU     26
-# define OMAP_INT_24XX_DSP_UMA         27
-# define OMAP_INT_24XX_DSP_MMU         28
-# define OMAP_INT_24XX_GPIO_BANK1      29
-# define OMAP_INT_24XX_GPIO_BANK2      30
-# define OMAP_INT_24XX_GPIO_BANK3      31
-# define OMAP_INT_24XX_GPIO_BANK4      32
-# define OMAP_INT_243X_GPIO_BANK5      33
-# define OMAP_INT_24XX_MAIL_U3_MPU     34
-# define OMAP_INT_24XX_WDT3            35
-# define OMAP_INT_24XX_WDT4            36
-# define OMAP_INT_24XX_GPTIMER1                37
-# define OMAP_INT_24XX_GPTIMER2                38
-# define OMAP_INT_24XX_GPTIMER3                39
-# define OMAP_INT_24XX_GPTIMER4                40
-# define OMAP_INT_24XX_GPTIMER5                41
-# define OMAP_INT_24XX_GPTIMER6                42
-# define OMAP_INT_24XX_GPTIMER7                43
-# define OMAP_INT_24XX_GPTIMER8                44
-# define OMAP_INT_24XX_GPTIMER9                45
-# define OMAP_INT_24XX_GPTIMER10       46
-# define OMAP_INT_24XX_GPTIMER11       47
-# define OMAP_INT_24XX_GPTIMER12       48
-# define OMAP_INT_24XX_PKA_IRQ         50
-# define OMAP_INT_24XX_SHA1MD5_IRQ     51
-# define OMAP_INT_24XX_RNG_IRQ         52
-# define OMAP_INT_24XX_MG_IRQ          53
-# define OMAP_INT_24XX_I2C1_IRQ                56
-# define OMAP_INT_24XX_I2C2_IRQ                57
-# define OMAP_INT_24XX_MCBSP1_IRQ_TX   59
-# define OMAP_INT_24XX_MCBSP1_IRQ_RX   60
-# define OMAP_INT_24XX_MCBSP2_IRQ_TX   62
-# define OMAP_INT_24XX_MCBSP2_IRQ_RX   63
-# define OMAP_INT_243X_MCBSP1_IRQ      64
-# define OMAP_INT_24XX_MCSPI1_IRQ      65
-# define OMAP_INT_24XX_MCSPI2_IRQ      66
-# define OMAP_INT_24XX_SSI1_IRQ0       67
-# define OMAP_INT_24XX_SSI1_IRQ1       68
-# define OMAP_INT_24XX_SSI2_IRQ0       69
-# define OMAP_INT_24XX_SSI2_IRQ1       70
-# define OMAP_INT_24XX_SSI_GDD_IRQ     71
-# define OMAP_INT_24XX_UART1_IRQ       72
-# define OMAP_INT_24XX_UART2_IRQ       73
-# define OMAP_INT_24XX_UART3_IRQ       74
-# define OMAP_INT_24XX_USB_IRQ_GEN     75
-# define OMAP_INT_24XX_USB_IRQ_NISO    76
-# define OMAP_INT_24XX_USB_IRQ_ISO     77
-# define OMAP_INT_24XX_USB_IRQ_HGEN    78
-# define OMAP_INT_24XX_USB_IRQ_HSOF    79
-# define OMAP_INT_24XX_USB_IRQ_OTG     80
-# define OMAP_INT_24XX_VLYNQ_IRQ       81
-# define OMAP_INT_24XX_MMC_IRQ         83
-# define OMAP_INT_24XX_MS_IRQ          84
-# define OMAP_INT_24XX_FAC_IRQ         85
-# define OMAP_INT_24XX_MCSPI3_IRQ      91
-# define OMAP_INT_243X_HS_USB_MC       92
-# define OMAP_INT_243X_HS_USB_DMA      93
-# define OMAP_INT_243X_CARKIT          94
-# define OMAP_INT_34XX_GPTIMER12       95
-
-/* omap_dma.c */
-enum omap_dma_model {
-    omap_dma_3_0,
-    omap_dma_3_1,
-    omap_dma_3_2,
-    omap_dma_4,
-};
-
-struct soc_dma_s;
-struct soc_dma_s *omap_dma_init(hwaddr base, qemu_irq *irqs,
-                MemoryRegion *sysmem,
-                qemu_irq lcd_irq, struct omap_mpu_state_s *mpu, omap_clk clk,
-                enum omap_dma_model model);
-struct soc_dma_s *omap_dma4_init(hwaddr base, qemu_irq *irqs,
-                MemoryRegion *sysmem,
-                struct omap_mpu_state_s *mpu, int fifo,
-                int chans, omap_clk iclk, omap_clk fclk);
-void omap_dma_reset(struct soc_dma_s *s);
-
-struct dma_irq_map {
-    int ih;
-    int intr;
-};
-
-/* Only used in OMAP DMA 3.x gigacells */
-enum omap_dma_port {
-    emiff = 0,
-    emifs,
-    imif,      /* omap16xx: ocp_t1 */
-    tipb,
-    local,     /* omap16xx: ocp_t2 */
-    tipb_mpui,
-    __omap_dma_port_last,
-};
-
-typedef enum {
-    constant = 0,
-    post_incremented,
-    single_index,
-    double_index,
-} omap_dma_addressing_t;
-
-/* Only used in OMAP DMA 3.x gigacells */
-struct omap_dma_lcd_channel_s {
-    enum omap_dma_port src;
-    hwaddr src_f1_top;
-    hwaddr src_f1_bottom;
-    hwaddr src_f2_top;
-    hwaddr src_f2_bottom;
-
-    /* Used in OMAP DMA 3.2 gigacell */
-    unsigned char brust_f1;
-    unsigned char pack_f1;
-    unsigned char data_type_f1;
-    unsigned char brust_f2;
-    unsigned char pack_f2;
-    unsigned char data_type_f2;
-    unsigned char end_prog;
-    unsigned char repeat;
-    unsigned char auto_init;
-    unsigned char priority;
-    unsigned char fs;
-    unsigned char running;
-    unsigned char bs;
-    unsigned char omap_3_1_compatible_disable;
-    unsigned char dst;
-    unsigned char lch_type;
-    int16_t element_index_f1;
-    int16_t element_index_f2;
-    int32_t frame_index_f1;
-    int32_t frame_index_f2;
-    uint16_t elements_f1;
-    uint16_t frames_f1;
-    uint16_t elements_f2;
-    uint16_t frames_f2;
-    omap_dma_addressing_t mode_f1;
-    omap_dma_addressing_t mode_f2;
-
-    /* Destination port is fixed.  */
-    int interrupts;
-    int condition;
-    int dual;
-
-    int current_frame;
-    hwaddr phys_framebuffer[2];
-    qemu_irq irq;
-    struct omap_mpu_state_s *mpu;
-} *omap_dma_get_lcdch(struct soc_dma_s *s);
-
-/*
- * DMA request numbers for OMAP1
- * See /usr/include/asm-arm/arch-omap/dma.h in Linux.
- */
-# define OMAP_DMA_NO_DEVICE            0
-# define OMAP_DMA_MCSI1_TX             1
-# define OMAP_DMA_MCSI1_RX             2
-# define OMAP_DMA_I2C_RX               3
-# define OMAP_DMA_I2C_TX               4
-# define OMAP_DMA_EXT_NDMA_REQ0                5
-# define OMAP_DMA_EXT_NDMA_REQ1                6
-# define OMAP_DMA_UWIRE_TX             7
-# define OMAP_DMA_MCBSP1_TX            8
-# define OMAP_DMA_MCBSP1_RX            9
-# define OMAP_DMA_MCBSP3_TX            10
-# define OMAP_DMA_MCBSP3_RX            11
-# define OMAP_DMA_UART1_TX             12
-# define OMAP_DMA_UART1_RX             13
-# define OMAP_DMA_UART2_TX             14
-# define OMAP_DMA_UART2_RX             15
-# define OMAP_DMA_MCBSP2_TX            16
-# define OMAP_DMA_MCBSP2_RX            17
-# define OMAP_DMA_UART3_TX             18
-# define OMAP_DMA_UART3_RX             19
-# define OMAP_DMA_CAMERA_IF_RX         20
-# define OMAP_DMA_MMC_TX               21
-# define OMAP_DMA_MMC_RX               22
-# define OMAP_DMA_NAND                 23      /* Not in OMAP310 */
-# define OMAP_DMA_IRQ_LCD_LINE         24      /* Not in OMAP310 */
-# define OMAP_DMA_MEMORY_STICK         25      /* Not in OMAP310 */
-# define OMAP_DMA_USB_W2FC_RX0         26
-# define OMAP_DMA_USB_W2FC_RX1         27
-# define OMAP_DMA_USB_W2FC_RX2         28
-# define OMAP_DMA_USB_W2FC_TX0         29
-# define OMAP_DMA_USB_W2FC_TX1         30
-# define OMAP_DMA_USB_W2FC_TX2         31
-
-/* These are only for 1610 */
-# define OMAP_DMA_CRYPTO_DES_IN                32
-# define OMAP_DMA_SPI_TX               33
-# define OMAP_DMA_SPI_RX               34
-# define OMAP_DMA_CRYPTO_HASH          35
-# define OMAP_DMA_CCP_ATTN             36
-# define OMAP_DMA_CCP_FIFO_NOT_EMPTY   37
-# define OMAP_DMA_CMT_APE_TX_CHAN_0    38
-# define OMAP_DMA_CMT_APE_RV_CHAN_0    39
-# define OMAP_DMA_CMT_APE_TX_CHAN_1    40
-# define OMAP_DMA_CMT_APE_RV_CHAN_1    41
-# define OMAP_DMA_CMT_APE_TX_CHAN_2    42
-# define OMAP_DMA_CMT_APE_RV_CHAN_2    43
-# define OMAP_DMA_CMT_APE_TX_CHAN_3    44
-# define OMAP_DMA_CMT_APE_RV_CHAN_3    45
-# define OMAP_DMA_CMT_APE_TX_CHAN_4    46
-# define OMAP_DMA_CMT_APE_RV_CHAN_4    47
-# define OMAP_DMA_CMT_APE_TX_CHAN_5    48
-# define OMAP_DMA_CMT_APE_RV_CHAN_5    49
-# define OMAP_DMA_CMT_APE_TX_CHAN_6    50
-# define OMAP_DMA_CMT_APE_RV_CHAN_6    51
-# define OMAP_DMA_CMT_APE_TX_CHAN_7    52
-# define OMAP_DMA_CMT_APE_RV_CHAN_7    53
-# define OMAP_DMA_MMC2_TX              54
-# define OMAP_DMA_MMC2_RX              55
-# define OMAP_DMA_CRYPTO_DES_OUT       56
-
-/*
- * DMA request numbers for the OMAP2
- */
-# define OMAP24XX_DMA_NO_DEVICE                0
-# define OMAP24XX_DMA_XTI_DMA          1       /* Not in OMAP2420 */
-# define OMAP24XX_DMA_EXT_DMAREQ0      2
-# define OMAP24XX_DMA_EXT_DMAREQ1      3
-# define OMAP24XX_DMA_GPMC             4
-# define OMAP24XX_DMA_GFX              5       /* Not in OMAP2420 */
-# define OMAP24XX_DMA_DSS              6
-# define OMAP24XX_DMA_VLYNQ_TX         7       /* Not in OMAP2420 */
-# define OMAP24XX_DMA_CWT              8       /* Not in OMAP2420 */
-# define OMAP24XX_DMA_AES_TX           9       /* Not in OMAP2420 */
-# define OMAP24XX_DMA_AES_RX           10      /* Not in OMAP2420 */
-# define OMAP24XX_DMA_DES_TX           11      /* Not in OMAP2420 */
-# define OMAP24XX_DMA_DES_RX           12      /* Not in OMAP2420 */
-# define OMAP24XX_DMA_SHA1MD5_RX       13      /* Not in OMAP2420 */
-# define OMAP24XX_DMA_EXT_DMAREQ2      14
-# define OMAP24XX_DMA_EXT_DMAREQ3      15
-# define OMAP24XX_DMA_EXT_DMAREQ4      16
-# define OMAP24XX_DMA_EAC_AC_RD                17
-# define OMAP24XX_DMA_EAC_AC_WR                18
-# define OMAP24XX_DMA_EAC_MD_UL_RD     19
-# define OMAP24XX_DMA_EAC_MD_UL_WR     20
-# define OMAP24XX_DMA_EAC_MD_DL_RD     21
-# define OMAP24XX_DMA_EAC_MD_DL_WR     22
-# define OMAP24XX_DMA_EAC_BT_UL_RD     23
-# define OMAP24XX_DMA_EAC_BT_UL_WR     24
-# define OMAP24XX_DMA_EAC_BT_DL_RD     25
-# define OMAP24XX_DMA_EAC_BT_DL_WR     26
-# define OMAP24XX_DMA_I2C1_TX          27
-# define OMAP24XX_DMA_I2C1_RX          28
-# define OMAP24XX_DMA_I2C2_TX          29
-# define OMAP24XX_DMA_I2C2_RX          30
-# define OMAP24XX_DMA_MCBSP1_TX                31
-# define OMAP24XX_DMA_MCBSP1_RX                32
-# define OMAP24XX_DMA_MCBSP2_TX                33
-# define OMAP24XX_DMA_MCBSP2_RX                34
-# define OMAP24XX_DMA_SPI1_TX0         35
-# define OMAP24XX_DMA_SPI1_RX0         36
-# define OMAP24XX_DMA_SPI1_TX1         37
-# define OMAP24XX_DMA_SPI1_RX1         38
-# define OMAP24XX_DMA_SPI1_TX2         39
-# define OMAP24XX_DMA_SPI1_RX2         40
-# define OMAP24XX_DMA_SPI1_TX3         41
-# define OMAP24XX_DMA_SPI1_RX3         42
-# define OMAP24XX_DMA_SPI2_TX0         43
-# define OMAP24XX_DMA_SPI2_RX0         44
-# define OMAP24XX_DMA_SPI2_TX1         45
-# define OMAP24XX_DMA_SPI2_RX1         46
-
-# define OMAP24XX_DMA_UART1_TX         49
-# define OMAP24XX_DMA_UART1_RX         50
-# define OMAP24XX_DMA_UART2_TX         51
-# define OMAP24XX_DMA_UART2_RX         52
-# define OMAP24XX_DMA_UART3_TX         53
-# define OMAP24XX_DMA_UART3_RX         54
-# define OMAP24XX_DMA_USB_W2FC_TX0     55
-# define OMAP24XX_DMA_USB_W2FC_RX0     56
-# define OMAP24XX_DMA_USB_W2FC_TX1     57
-# define OMAP24XX_DMA_USB_W2FC_RX1     58
-# define OMAP24XX_DMA_USB_W2FC_TX2     59
-# define OMAP24XX_DMA_USB_W2FC_RX2     60
-# define OMAP24XX_DMA_MMC1_TX          61
-# define OMAP24XX_DMA_MMC1_RX          62
-# define OMAP24XX_DMA_MS               63      /* Not in OMAP2420 */
-# define OMAP24XX_DMA_EXT_DMAREQ5      64
-
-/* omap[123].c */
-/* OMAP2 gp timer */
-struct omap_gp_timer_s;
-struct omap_gp_timer_s *omap_gp_timer_init(struct omap_target_agent_s *ta,
-                qemu_irq irq, omap_clk fclk, omap_clk iclk);
-void omap_gp_timer_reset(struct omap_gp_timer_s *s);
-
-/* OMAP2 sysctimer */
-struct omap_synctimer_s;
-struct omap_synctimer_s *omap_synctimer_init(struct omap_target_agent_s *ta,
-                struct omap_mpu_state_s *mpu, omap_clk fclk, omap_clk iclk);
-void omap_synctimer_reset(struct omap_synctimer_s *s);
-
-struct omap_uart_s;
-struct omap_uart_s *omap_uart_init(hwaddr base,
-                qemu_irq irq, omap_clk fclk, omap_clk iclk,
-                qemu_irq txdma, qemu_irq rxdma,
-                const char *label, CharDriverState *chr);
-struct omap_uart_s *omap2_uart_init(MemoryRegion *sysmem,
-                struct omap_target_agent_s *ta,
-                qemu_irq irq, omap_clk fclk, omap_clk iclk,
-                qemu_irq txdma, qemu_irq rxdma,
-                const char *label, CharDriverState *chr);
-void omap_uart_reset(struct omap_uart_s *s);
-void omap_uart_attach(struct omap_uart_s *s, CharDriverState *chr);
-
-struct omap_mpuio_s;
-qemu_irq *omap_mpuio_in_get(struct omap_mpuio_s *s);
-void omap_mpuio_out_set(struct omap_mpuio_s *s, int line, qemu_irq handler);
-void omap_mpuio_key(struct omap_mpuio_s *s, int row, int col, int down);
-
-struct uWireSlave {
-    uint16_t (*receive)(void *opaque);
-    void (*send)(void *opaque, uint16_t data);
-    void *opaque;
-};
-struct omap_uwire_s;
-void omap_uwire_attach(struct omap_uwire_s *s,
-                uWireSlave *slave, int chipselect);
-
-/* OMAP2 spi */
-struct omap_mcspi_s;
-struct omap_mcspi_s *omap_mcspi_init(struct omap_target_agent_s *ta, int chnum,
-                qemu_irq irq, qemu_irq *drq, omap_clk fclk, omap_clk iclk);
-void omap_mcspi_attach(struct omap_mcspi_s *s,
-                uint32_t (*txrx)(void *opaque, uint32_t, int), void *opaque,
-                int chipselect);
-void omap_mcspi_reset(struct omap_mcspi_s *s);
-
-struct I2SCodec {
-    void *opaque;
-
-    /* The CPU can call this if it is generating the clock signal on the
-     * i2s port.  The CODEC can ignore it if it is set up as a clock
-     * master and generates its own clock.  */
-    void (*set_rate)(void *opaque, int in, int out);
-
-    void (*tx_swallow)(void *opaque);
-    qemu_irq rx_swallow;
-    qemu_irq tx_start;
-
-    int tx_rate;
-    int cts;
-    int rx_rate;
-    int rts;
-
-    struct i2s_fifo_s {
-        uint8_t *fifo;
-        int len;
-        int start;
-        int size;
-    } in, out;
-};
-struct omap_mcbsp_s;
-void omap_mcbsp_i2s_attach(struct omap_mcbsp_s *s, I2SCodec *slave);
-
-void omap_tap_init(struct omap_target_agent_s *ta,
-                struct omap_mpu_state_s *mpu);
-
-/* omap_lcdc.c */
-struct omap_lcd_panel_s;
-void omap_lcdc_reset(struct omap_lcd_panel_s *s);
-struct omap_lcd_panel_s *omap_lcdc_init(MemoryRegion *sysmem,
-                                        hwaddr base,
-                                        qemu_irq irq,
-                                        struct omap_dma_lcd_channel_s *dma,
-                                        omap_clk clk);
-
-/* omap_dss.c */
-struct rfbi_chip_s {
-    void *opaque;
-    void (*write)(void *opaque, int dc, uint16_t value);
-    void (*block)(void *opaque, int dc, void *buf, size_t len, int pitch);
-    uint16_t (*read)(void *opaque, int dc);
-};
-struct omap_dss_s;
-void omap_dss_reset(struct omap_dss_s *s);
-struct omap_dss_s *omap_dss_init(struct omap_target_agent_s *ta,
-                MemoryRegion *sysmem,
-                hwaddr l3_base,
-                qemu_irq irq, qemu_irq drq,
-                omap_clk fck1, omap_clk fck2, omap_clk ck54m,
-                omap_clk ick1, omap_clk ick2);
-void omap_rfbi_attach(struct omap_dss_s *s, int cs, struct rfbi_chip_s *chip);
-
-/* omap_mmc.c */
-struct omap_mmc_s;
-struct omap_mmc_s *omap_mmc_init(hwaddr base,
-                MemoryRegion *sysmem,
-                BlockDriverState *bd,
-                qemu_irq irq, qemu_irq dma[], omap_clk clk);
-struct omap_mmc_s *omap2_mmc_init(struct omap_target_agent_s *ta,
-                BlockDriverState *bd, qemu_irq irq, qemu_irq dma[],
-                omap_clk fclk, omap_clk iclk);
-void omap_mmc_reset(struct omap_mmc_s *s);
-void omap_mmc_handlers(struct omap_mmc_s *s, qemu_irq ro, qemu_irq cover);
-void omap_mmc_enable(struct omap_mmc_s *s, int enable);
-
-/* omap_i2c.c */
-i2c_bus *omap_i2c_bus(DeviceState *omap_i2c);
-
-# define cpu_is_omap310(cpu)           (cpu->mpu_model == omap310)
-# define cpu_is_omap1510(cpu)          (cpu->mpu_model == omap1510)
-# define cpu_is_omap1610(cpu)          (cpu->mpu_model == omap1610)
-# define cpu_is_omap1710(cpu)          (cpu->mpu_model == omap1710)
-# define cpu_is_omap2410(cpu)          (cpu->mpu_model == omap2410)
-# define cpu_is_omap2420(cpu)          (cpu->mpu_model == omap2420)
-# define cpu_is_omap2430(cpu)          (cpu->mpu_model == omap2430)
-# define cpu_is_omap3430(cpu)          (cpu->mpu_model == omap3430)
-# define cpu_is_omap3630(cpu)           (cpu->mpu_model == omap3630)
-
-# define cpu_is_omap15xx(cpu)          \
-        (cpu_is_omap310(cpu) || cpu_is_omap1510(cpu))
-# define cpu_is_omap16xx(cpu)          \
-        (cpu_is_omap1610(cpu) || cpu_is_omap1710(cpu))
-# define cpu_is_omap24xx(cpu)          \
-        (cpu_is_omap2410(cpu) || cpu_is_omap2420(cpu) || cpu_is_omap2430(cpu))
-
-# define cpu_class_omap1(cpu)          \
-        (cpu_is_omap15xx(cpu) || cpu_is_omap16xx(cpu))
-# define cpu_class_omap2(cpu)          cpu_is_omap24xx(cpu)
-# define cpu_class_omap3(cpu) \
-        (cpu_is_omap3430(cpu) || cpu_is_omap3630(cpu))
-
-struct omap_mpu_state_s {
-    enum omap_mpu_model {
-        omap310,
-        omap1510,
-        omap1610,
-        omap1710,
-        omap2410,
-        omap2420,
-        omap2422,
-        omap2423,
-        omap2430,
-        omap3430,
-        omap3630,
-    } mpu_model;
-
-    ARMCPU *cpu;
-
-    qemu_irq *drq;
-
-    qemu_irq wakeup;
-
-    MemoryRegion ulpd_pm_iomem;
-    MemoryRegion pin_cfg_iomem;
-    MemoryRegion id_iomem;
-    MemoryRegion id_iomem_e18;
-    MemoryRegion id_iomem_ed4;
-    MemoryRegion id_iomem_e20;
-    MemoryRegion mpui_iomem;
-    MemoryRegion tcmi_iomem;
-    MemoryRegion clkm_iomem;
-    MemoryRegion clkdsp_iomem;
-    MemoryRegion mpui_io_iomem;
-    MemoryRegion tap_iomem;
-    MemoryRegion imif_ram;
-    MemoryRegion emiff_ram;
-    MemoryRegion sdram;
-    MemoryRegion sram;
-
-    struct omap_dma_port_if_s {
-        uint32_t (*read[3])(struct omap_mpu_state_s *s,
-                        hwaddr offset);
-        void (*write[3])(struct omap_mpu_state_s *s,
-                        hwaddr offset, uint32_t value);
-        int (*addr_valid)(struct omap_mpu_state_s *s,
-                        hwaddr addr);
-    } port[__omap_dma_port_last];
-
-    unsigned long sdram_size;
-    unsigned long sram_size;
-
-    /* MPUI-TIPB peripherals */
-    struct omap_uart_s *uart[3];
-
-    DeviceState *gpio;
-
-    struct omap_mcbsp_s *mcbsp1;
-    struct omap_mcbsp_s *mcbsp3;
-
-    /* MPU public TIPB peripherals */
-    struct omap_32khz_timer_s *os_timer;
-
-    struct omap_mmc_s *mmc;
-
-    struct omap_mpuio_s *mpuio;
-
-    struct omap_uwire_s *microwire;
-
-    struct omap_pwl_s *pwl;
-    struct omap_pwt_s *pwt;
-    DeviceState *i2c[2];
-
-    struct omap_rtc_s *rtc;
-
-    struct omap_mcbsp_s *mcbsp2;
-
-    struct omap_lpg_s *led[2];
-
-    /* MPU private TIPB peripherals */
-    DeviceState *ih[2];
-
-    struct soc_dma_s *dma;
-
-    struct omap_mpu_timer_s *timer[3];
-    struct omap_watchdog_timer_s *wdt;
-
-    struct omap_lcd_panel_s *lcd;
-
-    uint32_t ulpd_pm_regs[21];
-    int64_t ulpd_gauge_start;
-
-    uint32_t func_mux_ctrl[14];
-    uint32_t comp_mode_ctrl[1];
-    uint32_t pull_dwn_ctrl[4];
-    uint32_t gate_inh_ctrl[1];
-    uint32_t voltage_ctrl[1];
-    uint32_t test_dbg_ctrl[1];
-    uint32_t mod_conf_ctrl[1];
-    int compat1509;
-
-    uint32_t mpui_ctrl;
-
-    struct omap_tipb_bridge_s *private_tipb;
-    struct omap_tipb_bridge_s *public_tipb;
-
-    uint32_t tcmi_regs[17];
-
-    struct dpll_ctl_s *dpll[3];
-
-    omap_clk clks;
-    struct {
-        int cold_start;
-        int clocking_scheme;
-        uint16_t arm_ckctl;
-        uint16_t arm_idlect1;
-        uint16_t arm_idlect2;
-        uint16_t arm_ewupct;
-        uint16_t arm_rstct1;
-        uint16_t arm_rstct2;
-        uint16_t arm_ckout1;
-        int dpll1_mode;
-        uint16_t dsp_idlect1;
-        uint16_t dsp_idlect2;
-        uint16_t dsp_rstct2;
-    } clkm;
-
-    /* OMAP2-only peripherals */
-    struct omap_l4_s *l4;
-
-    struct omap_gp_timer_s *gptimer[12];
-    struct omap_synctimer_s *synctimer;
-
-    struct omap_prcm_s *prcm;
-    struct omap_sdrc_s *sdrc;
-    struct omap_gpmc_s *gpmc;
-    struct omap_sysctl_s *sysc;
-
-    struct omap_mcspi_s *mcspi[2];
-
-    struct omap_dss_s *dss;
-
-    struct omap_eac_s *eac;
-};
-
-/* omap1.c */
-struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *system_memory,
-                unsigned long sdram_size,
-                const char *core);
-
-/* omap2.c */
-struct omap_mpu_state_s *omap2420_mpu_init(MemoryRegion *sysmem,
-                unsigned long sdram_size,
-                const char *core);
-
-#define OMAP_FMT_plx "%#08" HWADDR_PRIx
-
-uint32_t omap_badwidth_read8(void *opaque, hwaddr addr);
-void omap_badwidth_write8(void *opaque, hwaddr addr,
-                uint32_t value);
-uint32_t omap_badwidth_read16(void *opaque, hwaddr addr);
-void omap_badwidth_write16(void *opaque, hwaddr addr,
-                uint32_t value);
-uint32_t omap_badwidth_read32(void *opaque, hwaddr addr);
-void omap_badwidth_write32(void *opaque, hwaddr addr,
-                uint32_t value);
-
-void omap_mpu_wakeup(void *opaque, int irq, int req);
-
-# define OMAP_BAD_REG(paddr)           \
-        fprintf(stderr, "%s: Bad register " OMAP_FMT_plx "\n", \
-                        __FUNCTION__, paddr)
-# define OMAP_RO_REG(paddr)            \
-        fprintf(stderr, "%s: Read-only register " OMAP_FMT_plx "\n",   \
-                        __FUNCTION__, paddr)
-
-/* OMAP-specific Linux bootloader tags for the ATAG_BOARD area
-   (Board-specifc tags are not here)  */
-#define OMAP_TAG_CLOCK         0x4f01
-#define OMAP_TAG_MMC           0x4f02
-#define OMAP_TAG_SERIAL_CONSOLE        0x4f03
-#define OMAP_TAG_USB           0x4f04
-#define OMAP_TAG_LCD           0x4f05
-#define OMAP_TAG_GPIO_SWITCH   0x4f06
-#define OMAP_TAG_UART          0x4f07
-#define OMAP_TAG_FBMEM         0x4f08
-#define OMAP_TAG_STI_CONSOLE   0x4f09
-#define OMAP_TAG_CAMERA_SENSOR 0x4f0a
-#define OMAP_TAG_PARTITION     0x4f0b
-#define OMAP_TAG_TEA5761       0x4f10
-#define OMAP_TAG_TMP105                0x4f11
-#define OMAP_TAG_BOOT_REASON   0x4f80
-#define OMAP_TAG_FLASH_PART_STR        0x4f81
-#define OMAP_TAG_VERSION_STR   0x4f82
-
-enum {
-    OMAP_GPIOSW_TYPE_COVER     = 0 << 4,
-    OMAP_GPIOSW_TYPE_CONNECTION        = 1 << 4,
-    OMAP_GPIOSW_TYPE_ACTIVITY  = 2 << 4,
-};
-
-#define OMAP_GPIOSW_INVERTED   0x0001
-#define OMAP_GPIOSW_OUTPUT     0x0002
-
-# define TCMI_VERBOSE                  1
-
-# ifdef TCMI_VERBOSE
-#  define OMAP_8B_REG(paddr)           \
-        fprintf(stderr, "%s: 8-bit register " OMAP_FMT_plx "\n",       \
-                        __FUNCTION__, paddr)
-#  define OMAP_16B_REG(paddr)          \
-        fprintf(stderr, "%s: 16-bit register " OMAP_FMT_plx "\n",      \
-                        __FUNCTION__, paddr)
-#  define OMAP_32B_REG(paddr)          \
-        fprintf(stderr, "%s: 32-bit register " OMAP_FMT_plx "\n",      \
-                        __FUNCTION__, paddr)
-# else
-#  define OMAP_8B_REG(paddr)
-#  define OMAP_16B_REG(paddr)
-#  define OMAP_32B_REG(paddr)
-# endif
-
-# define OMAP_MPUI_REG_MASK            0x000007ff
-
-#endif /* hw_omap_h */
diff --git a/hw/omap_clk.c b/hw/omap_clk.c
deleted file mode 100644 (file)
index c7b5c11..0000000
+++ /dev/null
@@ -1,1264 +0,0 @@
-/*
- * OMAP clocks.
- *
- * Copyright (C) 2006-2008 Andrzej Zaborowski  <balrog@zabor.org>
- *
- * Clocks data comes in part from arch/arm/mach-omap1/clock.h in Linux.
- *
- * 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 "hw/hw.h"
-#include "hw/omap.h"
-
-struct clk {
-    const char *name;
-    const char *alias;
-    struct clk *parent;
-    struct clk *child1;
-    struct clk *sibling;
-#define ALWAYS_ENABLED         (1 << 0)
-#define CLOCK_IN_OMAP310       (1 << 10)
-#define CLOCK_IN_OMAP730       (1 << 11)
-#define CLOCK_IN_OMAP1510      (1 << 12)
-#define CLOCK_IN_OMAP16XX      (1 << 13)
-#define CLOCK_IN_OMAP242X      (1 << 14)
-#define CLOCK_IN_OMAP243X      (1 << 15)
-#define CLOCK_IN_OMAP343X      (1 << 16)
-    uint32_t flags;
-    int id;
-
-    int running;               /* Is currently ticking */
-    int enabled;               /* Is enabled, regardless of its input clk */
-    unsigned long rate;                /* Current rate (if .running) */
-    unsigned int divisor;      /* Rate relative to input (if .enabled) */
-    unsigned int multiplier;   /* Rate relative to input (if .enabled) */
-    qemu_irq users[16];                /* Who to notify on change */
-    int usecount;              /* Automatically idle when unused */
-};
-
-static struct clk xtal_osc12m = {
-    .name      = "xtal_osc_12m",
-    .rate      = 12000000,
-    .flags     = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310,
-};
-
-static struct clk xtal_osc32k = {
-    .name      = "xtal_osc_32k",
-    .rate      = 32768,
-    .flags     = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 |
-            CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-};
-
-static struct clk ck_ref = {
-    .name      = "ck_ref",
-    .alias     = "clkin",
-    .parent    = &xtal_osc12m,
-    .flags     = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 |
-            ALWAYS_ENABLED,
-};
-
-/* If a dpll is disabled it becomes a bypass, child clocks don't stop */
-static struct clk dpll1 = {
-    .name      = "dpll1",
-    .parent    = &ck_ref,
-    .flags     = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 |
-            ALWAYS_ENABLED,
-};
-
-static struct clk dpll2 = {
-    .name      = "dpll2",
-    .parent    = &ck_ref,
-    .flags     = CLOCK_IN_OMAP310 | ALWAYS_ENABLED,
-};
-
-static struct clk dpll3 = {
-    .name      = "dpll3",
-    .parent    = &ck_ref,
-    .flags     = CLOCK_IN_OMAP310 | ALWAYS_ENABLED,
-};
-
-static struct clk dpll4 = {
-    .name      = "dpll4",
-    .parent    = &ck_ref,
-    .multiplier        = 4,
-    .flags     = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310,
-};
-
-static struct clk apll = {
-    .name      = "apll",
-    .parent    = &ck_ref,
-    .multiplier        = 48,
-    .divisor   = 12,
-    .flags     = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310,
-};
-
-static struct clk ck_48m = {
-    .name      = "ck_48m",
-    .parent    = &dpll4,       /* either dpll4 or apll */
-    .flags     = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310,
-};
-
-static struct clk ck_dpll1out = {
-    .name      = "ck_dpll1out",
-    .parent    = &dpll1,
-    .flags     = CLOCK_IN_OMAP16XX,
-};
-
-static struct clk sossi_ck = {
-    .name      = "ck_sossi",
-    .parent    = &ck_dpll1out,
-    .flags     = CLOCK_IN_OMAP16XX,
-};
-
-static struct clk clkm1 = {
-    .name      = "clkm1",
-    .alias     = "ck_gen1",
-    .parent    = &dpll1,
-    .flags     = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 |
-            ALWAYS_ENABLED,
-};
-
-static struct clk clkm2 = {
-    .name      = "clkm2",
-    .alias     = "ck_gen2",
-    .parent    = &dpll1,
-    .flags     = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 |
-            ALWAYS_ENABLED,
-};
-
-static struct clk clkm3 = {
-    .name      = "clkm3",
-    .alias     = "ck_gen3",
-    .parent    = &dpll1,       /* either dpll1 or ck_ref */
-    .flags     = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 |
-            ALWAYS_ENABLED,
-};
-
-static struct clk arm_ck = {
-    .name      = "arm_ck",
-    .alias     = "mpu_ck",
-    .parent    = &clkm1,
-    .flags     = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 |
-            ALWAYS_ENABLED,
-};
-
-static struct clk armper_ck = {
-    .name      = "armper_ck",
-    .alias     = "mpuper_ck",
-    .parent    = &clkm1,
-    .flags     = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310,
-};
-
-static struct clk arm_gpio_ck = {
-    .name      = "arm_gpio_ck",
-    .alias     = "mpu_gpio_ck",
-    .parent    = &clkm1,
-    .divisor   = 1,
-    .flags     = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310,
-};
-
-static struct clk armxor_ck = {
-    .name      = "armxor_ck",
-    .alias     = "mpuxor_ck",
-    .parent    = &ck_ref,
-    .flags     = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310,
-};
-
-static struct clk armtim_ck = {
-    .name      = "armtim_ck",
-    .alias     = "mputim_ck",
-    .parent    = &ck_ref,      /* either CLKIN or DPLL1 */
-    .flags     = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310,
-};
-
-static struct clk armwdt_ck = {
-    .name      = "armwdt_ck",
-    .alias     = "mpuwd_ck",
-    .parent    = &clkm1,
-    .divisor   = 14,
-    .flags     = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 |
-            ALWAYS_ENABLED,
-};
-
-static struct clk arminth_ck16xx = {
-    .name      = "arminth_ck",
-    .parent    = &arm_ck,
-    .flags     = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED,
-    /* Note: On 16xx the frequency can be divided by 2 by programming
-     * ARM_CKCTL:ARM_INTHCK_SEL(14) to 1
-     *
-     * 1510 version is in TC clocks.
-     */
-};
-
-static struct clk dsp_ck = {
-    .name      = "dsp_ck",
-    .parent    = &clkm2,
-    .flags     = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
-};
-
-static struct clk dspmmu_ck = {
-    .name      = "dspmmu_ck",
-    .parent    = &clkm2,
-    .flags     = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
-            ALWAYS_ENABLED,
-};
-
-static struct clk dspper_ck = {
-    .name      = "dspper_ck",
-    .parent    = &clkm2,
-    .flags     = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
-};
-
-static struct clk dspxor_ck = {
-    .name      = "dspxor_ck",
-    .parent    = &ck_ref,
-    .flags     = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
-};
-
-static struct clk dsptim_ck = {
-    .name      = "dsptim_ck",
-    .parent    = &ck_ref,
-    .flags     = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
-};
-
-static struct clk tc_ck = {
-    .name      = "tc_ck",
-    .parent    = &clkm3,
-    .flags     = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
-            CLOCK_IN_OMAP730 | CLOCK_IN_OMAP310 |
-            ALWAYS_ENABLED,
-};
-
-static struct clk arminth_ck15xx = {
-    .name      = "arminth_ck",
-    .parent    = &tc_ck,
-    .flags     = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | ALWAYS_ENABLED,
-    /* Note: On 1510 the frequency follows TC_CK
-     *
-     * 16xx version is in MPU clocks.
-     */
-};
-
-static struct clk tipb_ck = {
-    /* No-idle controlled by "tc_ck" */
-    .name      = "tipb_ck",
-    .parent    = &tc_ck,
-    .flags     = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | ALWAYS_ENABLED,
-};
-
-static struct clk l3_ocpi_ck = {
-    /* No-idle controlled by "tc_ck" */
-    .name      = "l3_ocpi_ck",
-    .parent    = &tc_ck,
-    .flags     = CLOCK_IN_OMAP16XX,
-};
-
-static struct clk tc1_ck = {
-    .name      = "tc1_ck",
-    .parent    = &tc_ck,
-    .flags     = CLOCK_IN_OMAP16XX,
-};
-
-static struct clk tc2_ck = {
-    .name      = "tc2_ck",
-    .parent    = &tc_ck,
-    .flags     = CLOCK_IN_OMAP16XX,
-};
-
-static struct clk dma_ck = {
-    /* No-idle controlled by "tc_ck" */
-    .name      = "dma_ck",
-    .parent    = &tc_ck,
-    .flags     = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 |
-            ALWAYS_ENABLED,
-};
-
-static struct clk dma_lcdfree_ck = {
-    .name      = "dma_lcdfree_ck",
-    .parent    = &tc_ck,
-    .flags     = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED,
-};
-
-static struct clk api_ck = {
-    .name      = "api_ck",
-    .alias     = "mpui_ck",
-    .parent    = &tc_ck,
-    .flags     = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310,
-};
-
-static struct clk lb_ck = {
-    .name      = "lb_ck",
-    .parent    = &tc_ck,
-    .flags     = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310,
-};
-
-static struct clk lbfree_ck = {
-    .name      = "lbfree_ck",
-    .parent    = &tc_ck,
-    .flags     = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310,
-};
-
-static struct clk hsab_ck = {
-    .name      = "hsab_ck",
-    .parent    = &tc_ck,
-    .flags     = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310,
-};
-
-static struct clk rhea1_ck = {
-    .name      = "rhea1_ck",
-    .parent    = &tc_ck,
-    .flags     = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED,
-};
-
-static struct clk rhea2_ck = {
-    .name      = "rhea2_ck",
-    .parent    = &tc_ck,
-    .flags     = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED,
-};
-
-static struct clk lcd_ck_16xx = {
-    .name      = "lcd_ck",
-    .parent    = &clkm3,
-    .flags     = CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP730,
-};
-
-static struct clk lcd_ck_1510 = {
-    .name      = "lcd_ck",
-    .parent    = &clkm3,
-    .flags     = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310,
-};
-
-static struct clk uart1_1510 = {
-    .name      = "uart1_ck",
-    /* Direct from ULPD, no real parent */
-    .parent    = &armper_ck,   /* either armper_ck or dpll4 */
-    .rate      = 12000000,
-    .flags     = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | ALWAYS_ENABLED,
-};
-
-static struct clk uart1_16xx = {
-    .name      = "uart1_ck",
-    /* Direct from ULPD, no real parent */
-    .parent    = &armper_ck,
-    .rate      = 48000000,
-    .flags     = CLOCK_IN_OMAP16XX,
-};
-
-static struct clk uart2_ck = {
-    .name      = "uart2_ck",
-    /* Direct from ULPD, no real parent */
-    .parent    = &armper_ck,   /* either armper_ck or dpll4 */
-    .rate      = 12000000,
-    .flags     = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 |
-            ALWAYS_ENABLED,
-};
-
-static struct clk uart3_1510 = {
-    .name      = "uart3_ck",
-    /* Direct from ULPD, no real parent */
-    .parent    = &armper_ck,   /* either armper_ck or dpll4 */
-    .rate      = 12000000,
-    .flags     = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | ALWAYS_ENABLED,
-};
-
-static struct clk uart3_16xx = {
-    .name      = "uart3_ck",
-    /* Direct from ULPD, no real parent */
-    .parent    = &armper_ck,
-    .rate      = 48000000,
-    .flags     = CLOCK_IN_OMAP16XX,
-};
-
-static struct clk usb_clk0 = { /* 6 MHz output on W4_USB_CLK0 */
-    .name      = "usb_clk0",
-    .alias     = "usb.clko",
-    /* Direct from ULPD, no parent */
-    .rate      = 6000000,
-    .flags     = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310,
-};
-
-static struct clk usb_hhc_ck1510 = {
-    .name      = "usb_hhc_ck",
-    /* Direct from ULPD, no parent */
-    .rate      = 48000000, /* Actually 2 clocks, 12MHz and 48MHz */
-    .flags     = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310,
-};
-
-static struct clk usb_hhc_ck16xx = {
-    .name      = "usb_hhc_ck",
-    /* Direct from ULPD, no parent */
-    .rate      = 48000000,
-    /* OTG_SYSCON_2.OTG_PADEN == 0 (not 1510-compatible) */
-    .flags     = CLOCK_IN_OMAP16XX,
-};
-
-static struct clk usb_w2fc_mclk = {
-    .name      = "usb_w2fc_mclk",
-    .alias     = "usb_w2fc_ck",
-    .parent    = &ck_48m,
-    .rate      = 48000000,
-    .flags     = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
-};
-
-static struct clk mclk_1510 = {
-    .name      = "mclk",
-    /* Direct from ULPD, no parent. May be enabled by ext hardware. */
-    .rate      = 12000000,
-    .flags     = CLOCK_IN_OMAP1510,
-};
-
-static struct clk bclk_310 = {
-    .name      = "bt_mclk_out",        /* Alias midi_mclk_out? */
-    .parent    = &armper_ck,
-    .flags     = CLOCK_IN_OMAP310,
-};
-
-static struct clk mclk_310 = {
-    .name      = "com_mclk_out",
-    .parent    = &armper_ck,
-    .flags     = CLOCK_IN_OMAP310,
-};
-
-static struct clk mclk_16xx = {
-    .name      = "mclk",
-    /* Direct from ULPD, no parent. May be enabled by ext hardware. */
-    .flags     = CLOCK_IN_OMAP16XX,
-};
-
-static struct clk bclk_1510 = {
-    .name      = "bclk",
-    /* Direct from ULPD, no parent. May be enabled by ext hardware. */
-    .rate      = 12000000,
-    .flags     = CLOCK_IN_OMAP1510,
-};
-
-static struct clk bclk_16xx = {
-    .name      = "bclk",
-    /* Direct from ULPD, no parent. May be enabled by ext hardware. */
-    .flags     = CLOCK_IN_OMAP16XX,
-};
-
-static struct clk mmc1_ck = {
-    .name      = "mmc_ck",
-    .id                = 1,
-    /* Functional clock is direct from ULPD, interface clock is ARMPER */
-    .parent    = &armper_ck,   /* either armper_ck or dpll4 */
-    .rate      = 48000000,
-    .flags     = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310,
-};
-
-static struct clk mmc2_ck = {
-    .name      = "mmc_ck",
-    .id                = 2,
-    /* Functional clock is direct from ULPD, interface clock is ARMPER */
-    .parent    = &armper_ck,
-    .rate      = 48000000,
-    .flags     = CLOCK_IN_OMAP16XX,
-};
-
-static struct clk cam_mclk = {
-    .name      = "cam.mclk",
-    .flags     = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
-    .rate      = 12000000,
-};
-
-static struct clk cam_exclk = {
-    .name      = "cam.exclk",
-    .flags     = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
-    /* Either 12M from cam.mclk or 48M from dpll4 */
-    .parent    = &cam_mclk,
-};
-
-static struct clk cam_lclk = {
-    .name      = "cam.lclk",
-    .flags     = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
-};
-
-static struct clk i2c_fck = {
-    .name      = "i2c_fck",
-    .id                = 1,
-    .flags     = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
-            ALWAYS_ENABLED,
-    .parent    = &armxor_ck,
-};
-
-static struct clk i2c_ick = {
-    .name      = "i2c_ick",
-    .id                = 1,
-    .flags     = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED,
-    .parent    = &armper_ck,
-};
-
-static struct clk clk32k = {
-    .name      = "clk32-kHz",
-    .flags     = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
-            CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
-    .parent    = &xtal_osc32k,
-};
-
-static struct clk ref_clk = {
-    .name      = "ref_clk",
-    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
-    .rate      = 12000000,     /* 12 MHz or 13 MHz or 19.2 MHz */
-    /*.parent  = sys.xtalin */
-};
-
-static struct clk apll_96m = {
-    .name      = "apll_96m",
-    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
-    .rate      = 96000000,
-    /*.parent  = ref_clk */
-};
-
-static struct clk apll_54m = {
-    .name      = "apll_54m",
-    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
-    .rate      = 54000000,
-    /*.parent  = ref_clk */
-};
-
-static struct clk sys_clk = {
-    .name      = "sys_clk",
-    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
-    .rate      = 32768,
-    /*.parent  = sys.xtalin */
-};
-
-static struct clk sleep_clk = {
-    .name      = "sleep_clk",
-    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
-    .rate      = 32768,
-    /*.parent  = sys.xtalin */
-};
-
-static struct clk dpll_ck = {
-    .name      = "dpll",
-    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
-    .parent    = &ref_clk,
-};
-
-static struct clk dpll_x2_ck = {
-    .name      = "dpll_x2",
-    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
-    .parent    = &ref_clk,
-};
-
-static struct clk wdt1_sys_clk = {
-    .name      = "wdt1_sys_clk",
-    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
-    .rate      = 32768,
-    /*.parent  = sys.xtalin */
-};
-
-static struct clk func_96m_clk = {
-    .name      = "func_96m_clk",
-    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-    .divisor   = 1,
-    .parent    = &apll_96m,
-};
-
-static struct clk func_48m_clk = {
-    .name      = "func_48m_clk",
-    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-    .divisor   = 2,
-    .parent    = &apll_96m,
-};
-
-static struct clk func_12m_clk = {
-    .name      = "func_12m_clk",
-    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-    .divisor   = 8,
-    .parent    = &apll_96m,
-};
-
-static struct clk func_54m_clk = {
-    .name      = "func_54m_clk",
-    .flags     = CLOCK_IN_OMAP242X,
-    .divisor   = 1,
-    .parent    = &apll_54m,
-};
-
-static struct clk sys_clkout = {
-    .name      = "clkout",
-    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-    .parent    = &sys_clk,
-};
-
-static struct clk sys_clkout2 = {
-    .name      = "clkout2",
-    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-    .parent    = &sys_clk,
-};
-
-static struct clk core_clk = {
-    .name      = "core_clk",
-    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-    .parent    = &dpll_x2_ck,  /* Switchable between dpll_ck and clk32k */
-};
-
-static struct clk l3_clk = {
-    .name      = "l3_clk",
-    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-    .parent    = &core_clk,
-};
-
-static struct clk core_l4_iclk = {
-    .name      = "core_l4_iclk",
-    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-    .parent    = &l3_clk,
-};
-
-static struct clk wu_l4_iclk = {
-    .name      = "wu_l4_iclk",
-    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-    .parent    = &l3_clk,
-};
-
-static struct clk core_l3_iclk = {
-    .name      = "core_l3_iclk",
-    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-    .parent    = &core_clk,
-};
-
-static struct clk core_l4_usb_clk = {
-    .name      = "core_l4_usb_clk",
-    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-    .parent    = &l3_clk,
-};
-
-static struct clk wu_gpt1_clk = {
-    .name      = "wu_gpt1_clk",
-    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-    .parent    = &sys_clk,
-};
-
-static struct clk wu_32k_clk = {
-    .name      = "wu_32k_clk",
-    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-    .parent    = &sys_clk,
-};
-
-static struct clk uart1_fclk = {
-    .name      = "uart1_fclk",
-    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-    .parent    = &func_48m_clk,
-};
-
-static struct clk uart1_iclk = {
-    .name      = "uart1_iclk",
-    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-    .parent    = &core_l4_iclk,
-};
-
-static struct clk uart2_fclk = {
-    .name      = "uart2_fclk",
-    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-    .parent    = &func_48m_clk,
-};
-
-static struct clk uart2_iclk = {
-    .name      = "uart2_iclk",
-    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-    .parent    = &core_l4_iclk,
-};
-
-static struct clk uart3_fclk = {
-    .name      = "uart3_fclk",
-    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-    .parent    = &func_48m_clk,
-};
-
-static struct clk uart3_iclk = {
-    .name      = "uart3_iclk",
-    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-    .parent    = &core_l4_iclk,
-};
-
-static struct clk mpu_fclk = {
-    .name      = "mpu_fclk",
-    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-    .parent    = &core_clk,
-};
-
-static struct clk mpu_iclk = {
-    .name      = "mpu_iclk",
-    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-    .parent    = &core_clk,
-};
-
-static struct clk int_m_fclk = {
-    .name      = "int_m_fclk",
-    .alias     = "mpu_intc_fclk",
-    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-    .parent    = &core_clk,
-};
-
-static struct clk int_m_iclk = {
-    .name      = "int_m_iclk",
-    .alias     = "mpu_intc_iclk",
-    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-    .parent    = &core_clk,
-};
-
-static struct clk core_gpt2_clk = {
-    .name      = "core_gpt2_clk",
-    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-    .parent    = &sys_clk,
-};
-
-static struct clk core_gpt3_clk = {
-    .name      = "core_gpt3_clk",
-    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-    .parent    = &sys_clk,
-};
-
-static struct clk core_gpt4_clk = {
-    .name      = "core_gpt4_clk",
-    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-    .parent    = &sys_clk,
-};
-
-static struct clk core_gpt5_clk = {
-    .name      = "core_gpt5_clk",
-    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-    .parent    = &sys_clk,
-};
-
-static struct clk core_gpt6_clk = {
-    .name      = "core_gpt6_clk",
-    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-    .parent    = &sys_clk,
-};
-
-static struct clk core_gpt7_clk = {
-    .name      = "core_gpt7_clk",
-    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-    .parent    = &sys_clk,
-};
-
-static struct clk core_gpt8_clk = {
-    .name      = "core_gpt8_clk",
-    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-    .parent    = &sys_clk,
-};
-
-static struct clk core_gpt9_clk = {
-    .name      = "core_gpt9_clk",
-    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-    .parent    = &sys_clk,
-};
-
-static struct clk core_gpt10_clk = {
-    .name      = "core_gpt10_clk",
-    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-    .parent    = &sys_clk,
-};
-
-static struct clk core_gpt11_clk = {
-    .name      = "core_gpt11_clk",
-    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-    .parent    = &sys_clk,
-};
-
-static struct clk core_gpt12_clk = {
-    .name      = "core_gpt12_clk",
-    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-    .parent    = &sys_clk,
-};
-
-static struct clk mcbsp1_clk = {
-    .name      = "mcbsp1_cg",
-    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-    .divisor   = 2,
-    .parent    = &func_96m_clk,
-};
-
-static struct clk mcbsp2_clk = {
-    .name      = "mcbsp2_cg",
-    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-    .divisor   = 2,
-    .parent    = &func_96m_clk,
-};
-
-static struct clk emul_clk = {
-    .name      = "emul_ck",
-    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-    .parent    = &func_54m_clk,
-};
-
-static struct clk sdma_fclk = {
-    .name      = "sdma_fclk",
-    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-    .parent    = &l3_clk,
-};
-
-static struct clk sdma_iclk = {
-    .name      = "sdma_iclk",
-    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-    .parent    = &core_l3_iclk, /* core_l4_iclk for the configuration port */
-};
-
-static struct clk i2c1_fclk = {
-    .name      = "i2c1.fclk",
-    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-    .parent    = &func_12m_clk,
-    .divisor   = 1,
-};
-
-static struct clk i2c1_iclk = {
-    .name      = "i2c1.iclk",
-    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-    .parent    = &core_l4_iclk,
-};
-
-static struct clk i2c2_fclk = {
-    .name      = "i2c2.fclk",
-    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-    .parent    = &func_12m_clk,
-    .divisor   = 1,
-};
-
-static struct clk i2c2_iclk = {
-    .name      = "i2c2.iclk",
-    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-    .parent    = &core_l4_iclk,
-};
-
-static struct clk gpio_dbclk[5] = {
-    {
-        .name  = "gpio1_dbclk",
-        .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-        .parent        = &wu_32k_clk,
-    }, {
-        .name  = "gpio2_dbclk",
-        .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-        .parent        = &wu_32k_clk,
-    }, {
-        .name  = "gpio3_dbclk",
-        .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-        .parent        = &wu_32k_clk,
-    }, {
-        .name  = "gpio4_dbclk",
-        .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-        .parent        = &wu_32k_clk,
-    }, {
-        .name   = "gpio5_dbclk",
-        .flags  = CLOCK_IN_OMAP243X,
-        .parent = &wu_32k_clk,
-    },
-};
-
-static struct clk gpio_iclk = {
-    .name      = "gpio_iclk",
-    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-    .parent    = &wu_l4_iclk,
-};
-
-static struct clk mmc_fck = {
-    .name      = "mmc_fclk",
-    .flags     = CLOCK_IN_OMAP242X,
-    .parent    = &func_96m_clk,
-};
-
-static struct clk mmc_ick = {
-    .name      = "mmc_iclk",
-    .flags     = CLOCK_IN_OMAP242X,
-    .parent    = &core_l4_iclk,
-};
-
-static struct clk spi_fclk[3] = {
-    {
-        .name  = "spi1_fclk",
-        .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-        .parent        = &func_48m_clk,
-    }, {
-        .name  = "spi2_fclk",
-        .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-        .parent        = &func_48m_clk,
-    }, {
-        .name  = "spi3_fclk",
-        .flags = CLOCK_IN_OMAP243X,
-        .parent        = &func_48m_clk,
-    },
-};
-
-static struct clk dss_clk[2] = {
-    {
-        .name  = "dss_clk1",
-        .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-        .parent        = &core_clk,
-    }, {
-        .name  = "dss_clk2",
-        .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-        .parent        = &sys_clk,
-    },
-};
-
-static struct clk dss_54m_clk = {
-    .name      = "dss_54m_clk",
-    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-    .parent    = &func_54m_clk,
-};
-
-static struct clk dss_l3_iclk = {
-    .name      = "dss_l3_iclk",
-    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-    .parent    = &core_l3_iclk,
-};
-
-static struct clk dss_l4_iclk = {
-    .name      = "dss_l4_iclk",
-    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-    .parent    = &core_l4_iclk,
-};
-
-static struct clk spi_iclk[3] = {
-    {
-        .name  = "spi1_iclk",
-        .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-        .parent        = &core_l4_iclk,
-    }, {
-        .name  = "spi2_iclk",
-        .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-        .parent        = &core_l4_iclk,
-    }, {
-        .name  = "spi3_iclk",
-        .flags = CLOCK_IN_OMAP243X,
-        .parent        = &core_l4_iclk,
-    },
-};
-
-static struct clk omapctrl_clk = {
-    .name      = "omapctrl_iclk",
-    .flags     = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
-    /* XXX Should be in WKUP domain */
-    .parent    = &core_l4_iclk,
-};
-
-static struct clk *onchip_clks[] = {
-    /* OMAP 1 */
-
-    /* non-ULPD clocks */
-    &xtal_osc12m,
-    &xtal_osc32k,
-    &ck_ref,
-    &dpll1,
-    &dpll2,
-    &dpll3,
-    &dpll4,
-    &apll,
-    &ck_48m,
-    /* CK_GEN1 clocks */
-    &clkm1,
-    &ck_dpll1out,
-    &sossi_ck,
-    &arm_ck,
-    &armper_ck,
-    &arm_gpio_ck,
-    &armxor_ck,
-    &armtim_ck,
-    &armwdt_ck,
-    &arminth_ck15xx,  &arminth_ck16xx,
-    /* CK_GEN2 clocks */
-    &clkm2,
-    &dsp_ck,
-    &dspmmu_ck,
-    &dspper_ck,
-    &dspxor_ck,
-    &dsptim_ck,
-    /* CK_GEN3 clocks */
-    &clkm3,
-    &tc_ck,
-    &tipb_ck,
-    &l3_ocpi_ck,
-    &tc1_ck,
-    &tc2_ck,
-    &dma_ck,
-    &dma_lcdfree_ck,
-    &api_ck,
-    &lb_ck,
-    &lbfree_ck,
-    &hsab_ck,
-    &rhea1_ck,
-    &rhea2_ck,
-    &lcd_ck_16xx,
-    &lcd_ck_1510,
-    /* ULPD clocks */
-    &uart1_1510,
-    &uart1_16xx,
-    &uart2_ck,
-    &uart3_1510,
-    &uart3_16xx,
-    &usb_clk0,
-    &usb_hhc_ck1510, &usb_hhc_ck16xx,
-    &mclk_1510,  &mclk_16xx, &mclk_310,
-    &bclk_1510,  &bclk_16xx, &bclk_310,
-    &mmc1_ck,
-    &mmc2_ck,
-    &cam_mclk,
-    &cam_exclk,
-    &cam_lclk,
-    &clk32k,
-    &usb_w2fc_mclk,
-    /* Virtual clocks */
-    &i2c_fck,
-    &i2c_ick,
-
-    /* OMAP 2 */
-
-    &ref_clk,
-    &apll_96m,
-    &apll_54m,
-    &sys_clk,
-    &sleep_clk,
-    &dpll_ck,
-    &dpll_x2_ck,
-    &wdt1_sys_clk,
-    &func_96m_clk,
-    &func_48m_clk,
-    &func_12m_clk,
-    &func_54m_clk,
-    &sys_clkout,
-    &sys_clkout2,
-    &core_clk,
-    &l3_clk,
-    &core_l4_iclk,
-    &wu_l4_iclk,
-    &core_l3_iclk,
-    &core_l4_usb_clk,
-    &wu_gpt1_clk,
-    &wu_32k_clk,
-    &uart1_fclk,
-    &uart1_iclk,
-    &uart2_fclk,
-    &uart2_iclk,
-    &uart3_fclk,
-    &uart3_iclk,
-    &mpu_fclk,
-    &mpu_iclk,
-    &int_m_fclk,
-    &int_m_iclk,
-    &core_gpt2_clk,
-    &core_gpt3_clk,
-    &core_gpt4_clk,
-    &core_gpt5_clk,
-    &core_gpt6_clk,
-    &core_gpt7_clk,
-    &core_gpt8_clk,
-    &core_gpt9_clk,
-    &core_gpt10_clk,
-    &core_gpt11_clk,
-    &core_gpt12_clk,
-    &mcbsp1_clk,
-    &mcbsp2_clk,
-    &emul_clk,
-    &sdma_fclk,
-    &sdma_iclk,
-    &i2c1_fclk,
-    &i2c1_iclk,
-    &i2c2_fclk,
-    &i2c2_iclk,
-    &gpio_dbclk[0],
-    &gpio_dbclk[1],
-    &gpio_dbclk[2],
-    &gpio_dbclk[3],
-    &gpio_iclk,
-    &mmc_fck,
-    &mmc_ick,
-    &spi_fclk[0],
-    &spi_iclk[0],
-    &spi_fclk[1],
-    &spi_iclk[1],
-    &spi_fclk[2],
-    &spi_iclk[2],
-    &dss_clk[0],
-    &dss_clk[1],
-    &dss_54m_clk,
-    &dss_l3_iclk,
-    &dss_l4_iclk,
-    &omapctrl_clk,
-
-    NULL
-};
-
-void omap_clk_adduser(struct clk *clk, qemu_irq user)
-{
-    qemu_irq *i;
-
-    for (i = clk->users; *i; i ++);
-    *i = user;
-}
-
-struct clk *omap_findclk(struct omap_mpu_state_s *mpu, const char *name)
-{
-    struct clk *i;
-
-    for (i = mpu->clks; i->name; i ++)
-        if (!strcmp(i->name, name) || (i->alias && !strcmp(i->alias, name)))
-            return i;
-    hw_error("%s: %s not found\n", __FUNCTION__, name);
-}
-
-void omap_clk_get(struct clk *clk)
-{
-    clk->usecount ++;
-}
-
-void omap_clk_put(struct clk *clk)
-{
-    if (!(clk->usecount --))
-        hw_error("%s: %s is not in use\n", __FUNCTION__, clk->name);
-}
-
-static void omap_clk_update(struct clk *clk)
-{
-    int parent, running;
-    qemu_irq *user;
-    struct clk *i;
-
-    if (clk->parent)
-        parent = clk->parent->running;
-    else
-        parent = 1;
-
-    running = parent && (clk->enabled ||
-                    ((clk->flags & ALWAYS_ENABLED) && clk->usecount));
-    if (clk->running != running) {
-        clk->running = running;
-        for (user = clk->users; *user; user ++)
-            qemu_set_irq(*user, running);
-        for (i = clk->child1; i; i = i->sibling)
-            omap_clk_update(i);
-    }
-}
-
-static void omap_clk_rate_update_full(struct clk *clk, unsigned long int rate,
-                unsigned long int div, unsigned long int mult)
-{
-    struct clk *i;
-    qemu_irq *user;
-
-    clk->rate = muldiv64(rate, mult, div);
-    if (clk->running)
-        for (user = clk->users; *user; user ++)
-            qemu_irq_raise(*user);
-    for (i = clk->child1; i; i = i->sibling)
-        omap_clk_rate_update_full(i, rate,
-                        div * i->divisor, mult * i->multiplier);
-}
-
-static void omap_clk_rate_update(struct clk *clk)
-{
-    struct clk *i;
-    unsigned long int div, mult = div = 1;
-
-    for (i = clk; i->parent; i = i->parent) {
-        div *= i->divisor;
-        mult *= i->multiplier;
-    }
-
-    omap_clk_rate_update_full(clk, i->rate, div, mult);
-}
-
-void omap_clk_reparent(struct clk *clk, struct clk *parent)
-{
-    struct clk **p;
-
-    if (clk->parent) {
-        for (p = &clk->parent->child1; *p != clk; p = &(*p)->sibling);
-        *p = clk->sibling;
-    }
-
-    clk->parent = parent;
-    if (parent) {
-        clk->sibling = parent->child1;
-        parent->child1 = clk;
-        omap_clk_update(clk);
-        omap_clk_rate_update(clk);
-    } else
-        clk->sibling = NULL;
-}
-
-void omap_clk_onoff(struct clk *clk, int on)
-{
-    clk->enabled = on;
-    omap_clk_update(clk);
-}
-
-void omap_clk_canidle(struct clk *clk, int can)
-{
-    if (can)
-        omap_clk_put(clk);
-    else
-        omap_clk_get(clk);
-}
-
-void omap_clk_setrate(struct clk *clk, int divide, int multiply)
-{
-    clk->divisor = divide;
-    clk->multiplier = multiply;
-    omap_clk_rate_update(clk);
-}
-
-int64_t omap_clk_getrate(omap_clk clk)
-{
-    return clk->rate;
-}
-
-void omap_clk_init(struct omap_mpu_state_s *mpu)
-{
-    struct clk **i, *j, *k;
-    int count;
-    int flag;
-
-    if (cpu_is_omap310(mpu))
-        flag = CLOCK_IN_OMAP310;
-    else if (cpu_is_omap1510(mpu))
-        flag = CLOCK_IN_OMAP1510;
-    else if (cpu_is_omap2410(mpu) || cpu_is_omap2420(mpu))
-        flag = CLOCK_IN_OMAP242X;
-    else if (cpu_is_omap2430(mpu))
-        flag = CLOCK_IN_OMAP243X;
-    else if (cpu_is_omap3430(mpu))
-        flag = CLOCK_IN_OMAP243X;
-    else
-        return;
-
-    for (i = onchip_clks, count = 0; *i; i ++)
-        if ((*i)->flags & flag)
-            count ++;
-    mpu->clks = (struct clk *) g_malloc0(sizeof(struct clk) * (count + 1));
-    for (i = onchip_clks, j = mpu->clks; *i; i ++)
-        if ((*i)->flags & flag) {
-            memcpy(j, *i, sizeof(struct clk));
-            for (k = mpu->clks; k < j; k ++)
-                if (j->parent && !strcmp(j->parent->name, k->name)) {
-                    j->parent = k;
-                    j->sibling = k->child1;
-                    k->child1 = j;
-                } else if (k->parent && !strcmp(k->parent->name, j->name)) {
-                    k->parent = j;
-                    k->sibling = j->child1;
-                    j->child1 = k;
-                }
-            j->divisor = j->divisor ?: 1;
-            j->multiplier = j->multiplier ?: 1;
-            j ++;
-        }
-    for (j = mpu->clks; count --; j ++) {
-        omap_clk_update(j);
-        omap_clk_rate_update(j);
-    }
-}
diff --git a/hw/omap_dma.c b/hw/omap_dma.c
deleted file mode 100644 (file)
index 0c5902f..0000000
+++ /dev/null
@@ -1,2101 +0,0 @@
-/*
- * TI OMAP DMA gigacell.
- *
- * Copyright (C) 2006-2008 Andrzej Zaborowski  <balrog@zabor.org>
- * Copyright (C) 2007-2008 Lauro Ramos Venancio  <lauro.venancio@indt.org.br>
- *
- * 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 "qemu/timer.h"
-#include "hw/omap.h"
-#include "hw/irq.h"
-#include "hw/soc_dma.h"
-
-struct omap_dma_channel_s {
-    /* transfer data */
-    int burst[2];
-    int pack[2];
-    int endian[2];
-    int endian_lock[2];
-    int translate[2];
-    enum omap_dma_port port[2];
-    hwaddr addr[2];
-    omap_dma_addressing_t mode[2];
-    uint32_t elements;
-    uint16_t frames;
-    int32_t frame_index[2];
-    int16_t element_index[2];
-    int data_type;
-
-    /* transfer type */
-    int transparent_copy;
-    int constant_fill;
-    uint32_t color;
-    int prefetch;
-
-    /* auto init and linked channel data */
-    int end_prog;
-    int repeat;
-    int auto_init;
-    int link_enabled;
-    int link_next_ch;
-
-    /* interruption data */
-    int interrupts;
-    int status;
-    int cstatus;
-
-    /* state data */
-    int active;
-    int enable;
-    int sync;
-    int src_sync;
-    int pending_request;
-    int waiting_end_prog;
-    uint16_t cpc;
-    int set_update;
-
-    /* sync type */
-    int fs;
-    int bs;
-
-    /* compatibility */
-    int omap_3_1_compatible_disable;
-
-    qemu_irq irq;
-    struct omap_dma_channel_s *sibling;
-
-    struct omap_dma_reg_set_s {
-        hwaddr src, dest;
-        int frame;
-        int element;
-        int pck_element;
-        int frame_delta[2];
-        int elem_delta[2];
-        int frames;
-        int elements;
-        int pck_elements;
-    } active_set;
-
-    struct soc_dma_ch_s *dma;
-
-    /* unused parameters */
-    int write_mode;
-    int priority;
-    int interleave_disabled;
-    int type;
-    int suspend;
-    int buf_disable;
-};
-
-struct omap_dma_s {
-    struct soc_dma_s *dma;
-    MemoryRegion iomem;
-
-    struct omap_mpu_state_s *mpu;
-    omap_clk clk;
-    qemu_irq irq[4];
-    void (*intr_update)(struct omap_dma_s *s);
-    enum omap_dma_model model;
-    int omap_3_1_mapping_disabled;
-
-    uint32_t gcr;
-    uint32_t ocp;
-    uint32_t caps[5];
-    uint32_t irqen[4];
-    uint32_t irqstat[4];
-
-    int chans;
-    struct omap_dma_channel_s ch[32];
-    struct omap_dma_lcd_channel_s lcd_ch;
-};
-
-/* Interrupts */
-#define TIMEOUT_INTR    (1 << 0)
-#define EVENT_DROP_INTR (1 << 1)
-#define HALF_FRAME_INTR (1 << 2)
-#define END_FRAME_INTR  (1 << 3)
-#define LAST_FRAME_INTR (1 << 4)
-#define END_BLOCK_INTR  (1 << 5)
-#define SYNC            (1 << 6)
-#define END_PKT_INTR   (1 << 7)
-#define TRANS_ERR_INTR (1 << 8)
-#define MISALIGN_INTR  (1 << 11)
-
-static inline void omap_dma_interrupts_update(struct omap_dma_s *s)
-{
-    return s->intr_update(s);
-}
-
-static void omap_dma_channel_load(struct omap_dma_channel_s *ch)
-{
-    struct omap_dma_reg_set_s *a = &ch->active_set;
-    int i, normal;
-    int omap_3_1 = !ch->omap_3_1_compatible_disable;
-
-    /*
-     * TODO: verify address ranges and alignment
-     * TODO: port endianness
-     */
-
-    a->src = ch->addr[0];
-    a->dest = ch->addr[1];
-    a->frames = ch->frames;
-    a->elements = ch->elements;
-    a->pck_elements = ch->frame_index[!ch->src_sync];
-    a->frame = 0;
-    a->element = 0;
-    a->pck_element = 0;
-
-    if (unlikely(!ch->elements || !ch->frames)) {
-        printf("%s: bad DMA request\n", __FUNCTION__);
-        return;
-    }
-
-    for (i = 0; i < 2; i ++)
-        switch (ch->mode[i]) {
-        case constant:
-            a->elem_delta[i] = 0;
-            a->frame_delta[i] = 0;
-            break;
-        case post_incremented:
-            a->elem_delta[i] = ch->data_type;
-            a->frame_delta[i] = 0;
-            break;
-        case single_index:
-            a->elem_delta[i] = ch->data_type +
-                    ch->element_index[omap_3_1 ? 0 : i] - 1;
-            a->frame_delta[i] = 0;
-            break;
-        case double_index:
-            a->elem_delta[i] = ch->data_type +
-                    ch->element_index[omap_3_1 ? 0 : i] - 1;
-            a->frame_delta[i] = ch->frame_index[omap_3_1 ? 0 : i] -
-                    ch->element_index[omap_3_1 ? 0 : i];
-            break;
-        default:
-            break;
-        }
-
-    normal = !ch->transparent_copy && !ch->constant_fill &&
-            /* FIFO is big-endian so either (ch->endian[n] == 1) OR
-             * (ch->endian_lock[n] == 1) mean no endianism conversion.  */
-            (ch->endian[0] | ch->endian_lock[0]) ==
-            (ch->endian[1] | ch->endian_lock[1]);
-    for (i = 0; i < 2; i ++) {
-        /* TODO: for a->frame_delta[i] > 0 still use the fast path, just
-         * limit min_elems in omap_dma_transfer_setup to the nearest frame
-         * end.  */
-        if (!a->elem_delta[i] && normal &&
-                        (a->frames == 1 || !a->frame_delta[i]))
-            ch->dma->type[i] = soc_dma_access_const;
-        else if (a->elem_delta[i] == ch->data_type && normal &&
-                        (a->frames == 1 || !a->frame_delta[i]))
-            ch->dma->type[i] = soc_dma_access_linear;
-        else
-            ch->dma->type[i] = soc_dma_access_other;
-
-        ch->dma->vaddr[i] = ch->addr[i];
-    }
-    soc_dma_ch_update(ch->dma);
-}
-
-static void omap_dma_activate_channel(struct omap_dma_s *s,
-                struct omap_dma_channel_s *ch)
-{
-    if (!ch->active) {
-        if (ch->set_update) {
-            /* It's not clear when the active set is supposed to be
-             * loaded from registers.  We're already loading it when the
-             * channel is enabled, and for some guests this is not enough
-             * but that may be also because of a race condition (no
-             * delays in qemu) in the guest code, which we're just
-             * working around here.  */
-            omap_dma_channel_load(ch);
-            ch->set_update = 0;
-        }
-
-        ch->active = 1;
-        soc_dma_set_request(ch->dma, 1);
-        if (ch->sync)
-            ch->status |= SYNC;
-    }
-}
-
-static void omap_dma_deactivate_channel(struct omap_dma_s *s,
-                struct omap_dma_channel_s *ch)
-{
-    /* Update cpc */
-    ch->cpc = ch->active_set.dest & 0xffff;
-
-    if (ch->pending_request && !ch->waiting_end_prog && ch->enable) {
-        /* Don't deactivate the channel */
-        ch->pending_request = 0;
-        return;
-    }
-
-    /* Don't deactive the channel if it is synchronized and the DMA request is
-       active */
-    if (ch->sync && ch->enable && (s->dma->drqbmp & (1 << ch->sync)))
-        return;
-
-    if (ch->active) {
-        ch->active = 0;
-        ch->status &= ~SYNC;
-        soc_dma_set_request(ch->dma, 0);
-    }
-}
-
-static void omap_dma_enable_channel(struct omap_dma_s *s,
-                struct omap_dma_channel_s *ch)
-{
-    if (!ch->enable) {
-        ch->enable = 1;
-        ch->waiting_end_prog = 0;
-        omap_dma_channel_load(ch);
-        /* TODO: theoretically if ch->sync && ch->prefetch &&
-         * !s->dma->drqbmp[ch->sync], we should also activate and fetch
-         * from source and then stall until signalled.  */
-        if ((!ch->sync) || (s->dma->drqbmp & (1 << ch->sync)))
-            omap_dma_activate_channel(s, ch);
-    }
-}
-
-static void omap_dma_disable_channel(struct omap_dma_s *s,
-                struct omap_dma_channel_s *ch)
-{
-    if (ch->enable) {
-        ch->enable = 0;
-        /* Discard any pending request */
-        ch->pending_request = 0;
-        omap_dma_deactivate_channel(s, ch);
-    }
-}
-
-static void omap_dma_channel_end_prog(struct omap_dma_s *s,
-                struct omap_dma_channel_s *ch)
-{
-    if (ch->waiting_end_prog) {
-        ch->waiting_end_prog = 0;
-        if (!ch->sync || ch->pending_request) {
-            ch->pending_request = 0;
-            omap_dma_activate_channel(s, ch);
-        }
-    }
-}
-
-static void omap_dma_interrupts_3_1_update(struct omap_dma_s *s)
-{
-    struct omap_dma_channel_s *ch = s->ch;
-
-    /* First three interrupts are shared between two channels each. */
-    if (ch[0].status | ch[6].status)
-        qemu_irq_raise(ch[0].irq);
-    if (ch[1].status | ch[7].status)
-        qemu_irq_raise(ch[1].irq);
-    if (ch[2].status | ch[8].status)
-        qemu_irq_raise(ch[2].irq);
-    if (ch[3].status)
-        qemu_irq_raise(ch[3].irq);
-    if (ch[4].status)
-        qemu_irq_raise(ch[4].irq);
-    if (ch[5].status)
-        qemu_irq_raise(ch[5].irq);
-}
-
-static void omap_dma_interrupts_3_2_update(struct omap_dma_s *s)
-{
-    struct omap_dma_channel_s *ch = s->ch;
-    int i;
-
-    for (i = s->chans; i; ch ++, i --)
-        if (ch->status)
-            qemu_irq_raise(ch->irq);
-}
-
-static void omap_dma_enable_3_1_mapping(struct omap_dma_s *s)
-{
-    s->omap_3_1_mapping_disabled = 0;
-    s->chans = 9;
-    s->intr_update = omap_dma_interrupts_3_1_update;
-}
-
-static void omap_dma_disable_3_1_mapping(struct omap_dma_s *s)
-{
-    s->omap_3_1_mapping_disabled = 1;
-    s->chans = 16;
-    s->intr_update = omap_dma_interrupts_3_2_update;
-}
-
-static void omap_dma_process_request(struct omap_dma_s *s, int request)
-{
-    int channel;
-    int drop_event = 0;
-    struct omap_dma_channel_s *ch = s->ch;
-
-    for (channel = 0; channel < s->chans; channel ++, ch ++) {
-        if (ch->enable && ch->sync == request) {
-            if (!ch->active)
-                omap_dma_activate_channel(s, ch);
-            else if (!ch->pending_request)
-                ch->pending_request = 1;
-            else {
-                /* Request collision */
-                /* Second request received while processing other request */
-                ch->status |= EVENT_DROP_INTR;
-                drop_event = 1;
-            }
-        }
-    }
-
-    if (drop_event)
-        omap_dma_interrupts_update(s);
-}
-
-static void omap_dma_transfer_generic(struct soc_dma_ch_s *dma)
-{
-    uint8_t value[4];
-    struct omap_dma_channel_s *ch = dma->opaque;
-    struct omap_dma_reg_set_s *a = &ch->active_set;
-    int bytes = dma->bytes;
-#ifdef MULTI_REQ
-    uint16_t status = ch->status;
-#endif
-
-    do {
-        /* Transfer a single element */
-        /* FIXME: check the endianness */
-        if (!ch->constant_fill)
-            cpu_physical_memory_read(a->src, value, ch->data_type);
-        else
-            *(uint32_t *) value = ch->color;
-
-        if (!ch->transparent_copy || *(uint32_t *) value != ch->color)
-            cpu_physical_memory_write(a->dest, value, ch->data_type);
-
-        a->src += a->elem_delta[0];
-        a->dest += a->elem_delta[1];
-        a->element ++;
-
-#ifndef MULTI_REQ
-        if (a->element == a->elements) {
-            /* End of Frame */
-            a->element = 0;
-            a->src += a->frame_delta[0];
-            a->dest += a->frame_delta[1];
-            a->frame ++;
-
-            /* If the channel is async, update cpc */
-            if (!ch->sync)
-                ch->cpc = a->dest & 0xffff;
-        }
-    } while ((bytes -= ch->data_type));
-#else
-        /* If the channel is element synchronized, deactivate it */
-        if (ch->sync && !ch->fs && !ch->bs)
-            omap_dma_deactivate_channel(s, ch);
-
-        /* If it is the last frame, set the LAST_FRAME interrupt */
-        if (a->element == 1 && a->frame == a->frames - 1)
-            if (ch->interrupts & LAST_FRAME_INTR)
-                ch->status |= LAST_FRAME_INTR;
-
-        /* If the half of the frame was reached, set the HALF_FRAME
-           interrupt */
-        if (a->element == (a->elements >> 1))
-            if (ch->interrupts & HALF_FRAME_INTR)
-                ch->status |= HALF_FRAME_INTR;
-
-        if (ch->fs && ch->bs) {
-            a->pck_element ++;
-            /* Check if a full packet has beed transferred.  */
-            if (a->pck_element == a->pck_elements) {
-                a->pck_element = 0;
-
-                /* Set the END_PKT interrupt */
-                if ((ch->interrupts & END_PKT_INTR) && !ch->src_sync)
-                    ch->status |= END_PKT_INTR;
-
-                /* If the channel is packet-synchronized, deactivate it */
-                if (ch->sync)
-                    omap_dma_deactivate_channel(s, ch);
-            }
-        }
-
-        if (a->element == a->elements) {
-            /* End of Frame */
-            a->element = 0;
-            a->src += a->frame_delta[0];
-            a->dest += a->frame_delta[1];
-            a->frame ++;
-
-            /* If the channel is frame synchronized, deactivate it */
-            if (ch->sync && ch->fs && !ch->bs)
-                omap_dma_deactivate_channel(s, ch);
-
-            /* If the channel is async, update cpc */
-            if (!ch->sync)
-                ch->cpc = a->dest & 0xffff;
-
-            /* Set the END_FRAME interrupt */
-            if (ch->interrupts & END_FRAME_INTR)
-                ch->status |= END_FRAME_INTR;
-
-            if (a->frame == a->frames) {
-                /* End of Block */
-                /* Disable the channel */
-
-                if (ch->omap_3_1_compatible_disable) {
-                    omap_dma_disable_channel(s, ch);
-                    if (ch->link_enabled)
-                        omap_dma_enable_channel(s,
-                                        &s->ch[ch->link_next_ch]);
-                } else {
-                    if (!ch->auto_init)
-                        omap_dma_disable_channel(s, ch);
-                    else if (ch->repeat || ch->end_prog)
-                        omap_dma_channel_load(ch);
-                    else {
-                        ch->waiting_end_prog = 1;
-                        omap_dma_deactivate_channel(s, ch);
-                    }
-                }
-
-                if (ch->interrupts & END_BLOCK_INTR)
-                    ch->status |= END_BLOCK_INTR;
-            }
-        }
-    } while (status == ch->status && ch->active);
-
-    omap_dma_interrupts_update(s);
-#endif
-}
-
-enum {
-    omap_dma_intr_element_sync,
-    omap_dma_intr_last_frame,
-    omap_dma_intr_half_frame,
-    omap_dma_intr_frame,
-    omap_dma_intr_frame_sync,
-    omap_dma_intr_packet,
-    omap_dma_intr_packet_sync,
-    omap_dma_intr_block,
-    __omap_dma_intr_last,
-};
-
-static void omap_dma_transfer_setup(struct soc_dma_ch_s *dma)
-{
-    struct omap_dma_port_if_s *src_p, *dest_p;
-    struct omap_dma_reg_set_s *a;
-    struct omap_dma_channel_s *ch = dma->opaque;
-    struct omap_dma_s *s = dma->dma->opaque;
-    int frames, min_elems, elements[__omap_dma_intr_last];
-
-    a = &ch->active_set;
-
-    src_p = &s->mpu->port[ch->port[0]];
-    dest_p = &s->mpu->port[ch->port[1]];
-    if ((!ch->constant_fill && !src_p->addr_valid(s->mpu, a->src)) ||
-                    (!dest_p->addr_valid(s->mpu, a->dest))) {
-#if 0
-        /* Bus time-out */
-        if (ch->interrupts & TIMEOUT_INTR)
-            ch->status |= TIMEOUT_INTR;
-        omap_dma_deactivate_channel(s, ch);
-        continue;
-#endif
-        printf("%s: Bus time-out in DMA%i operation\n",
-                        __FUNCTION__, dma->num);
-    }
-
-    min_elems = INT_MAX;
-
-    /* Check all the conditions that terminate the transfer starting
-     * with those that can occur the soonest.  */
-#define INTR_CHECK(cond, id, nelements)        \
-    if (cond) {                        \
-        elements[id] = nelements;      \
-        if (elements[id] < min_elems)  \
-            min_elems = elements[id];  \
-    } else                             \
-        elements[id] = INT_MAX;
-
-    /* Elements */
-    INTR_CHECK(
-                    ch->sync && !ch->fs && !ch->bs,
-                    omap_dma_intr_element_sync,
-                    1)
-
-    /* Frames */
-    /* TODO: for transfers where entire frames can be read and written
-     * using memcpy() but a->frame_delta is non-zero, try to still do
-     * transfers using soc_dma but limit min_elems to a->elements - ...
-     * See also the TODO in omap_dma_channel_load.  */
-    INTR_CHECK(
-                    (ch->interrupts & LAST_FRAME_INTR) &&
-                    ((a->frame < a->frames - 1) || !a->element),
-                    omap_dma_intr_last_frame,
-                    (a->frames - a->frame - 2) * a->elements +
-                    (a->elements - a->element + 1))
-    INTR_CHECK(
-                    ch->interrupts & HALF_FRAME_INTR,
-                    omap_dma_intr_half_frame,
-                    (a->elements >> 1) +
-                    (a->element >= (a->elements >> 1) ? a->elements : 0) -
-                    a->element)
-    INTR_CHECK(
-                    ch->sync && ch->fs && (ch->interrupts & END_FRAME_INTR),
-                    omap_dma_intr_frame,
-                    a->elements - a->element)
-    INTR_CHECK(
-                    ch->sync && ch->fs && !ch->bs,
-                    omap_dma_intr_frame_sync,
-                    a->elements - a->element)
-
-    /* Packets */
-    INTR_CHECK(
-                    ch->fs && ch->bs &&
-                    (ch->interrupts & END_PKT_INTR) && !ch->src_sync,
-                    omap_dma_intr_packet,
-                    a->pck_elements - a->pck_element)
-    INTR_CHECK(
-                    ch->fs && ch->bs && ch->sync,
-                    omap_dma_intr_packet_sync,
-                    a->pck_elements - a->pck_element)
-
-    /* Blocks */
-    INTR_CHECK(
-                    1,
-                    omap_dma_intr_block,
-                    (a->frames - a->frame - 1) * a->elements +
-                    (a->elements - a->element))
-
-    dma->bytes = min_elems * ch->data_type;
-
-    /* Set appropriate interrupts and/or deactivate channels */
-
-#ifdef MULTI_REQ
-    /* TODO: should all of this only be done if dma->update, and otherwise
-     * inside omap_dma_transfer_generic below - check what's faster.  */
-    if (dma->update) {
-#endif
-
-        /* If the channel is element synchronized, deactivate it */
-        if (min_elems == elements[omap_dma_intr_element_sync])
-            omap_dma_deactivate_channel(s, ch);
-
-        /* If it is the last frame, set the LAST_FRAME interrupt */
-        if (min_elems == elements[omap_dma_intr_last_frame])
-            ch->status |= LAST_FRAME_INTR;
-
-        /* If exactly half of the frame was reached, set the HALF_FRAME
-           interrupt */
-        if (min_elems == elements[omap_dma_intr_half_frame])
-            ch->status |= HALF_FRAME_INTR;
-
-        /* If a full packet has been transferred, set the END_PKT interrupt */
-        if (min_elems == elements[omap_dma_intr_packet])
-            ch->status |= END_PKT_INTR;
-
-        /* If the channel is packet-synchronized, deactivate it */
-        if (min_elems == elements[omap_dma_intr_packet_sync])
-            omap_dma_deactivate_channel(s, ch);
-
-        /* If the channel is frame synchronized, deactivate it */
-        if (min_elems == elements[omap_dma_intr_frame_sync])
-            omap_dma_deactivate_channel(s, ch);
-
-        /* Set the END_FRAME interrupt */
-        if (min_elems == elements[omap_dma_intr_frame])
-            ch->status |= END_FRAME_INTR;
-
-        if (min_elems == elements[omap_dma_intr_block]) {
-            /* End of Block */
-            /* Disable the channel */
-
-            if (ch->omap_3_1_compatible_disable) {
-                omap_dma_disable_channel(s, ch);
-                if (ch->link_enabled)
-                    omap_dma_enable_channel(s, &s->ch[ch->link_next_ch]);
-            } else {
-                if (!ch->auto_init)
-                    omap_dma_disable_channel(s, ch);
-                else if (ch->repeat || ch->end_prog)
-                    omap_dma_channel_load(ch);
-                else {
-                    ch->waiting_end_prog = 1;
-                    omap_dma_deactivate_channel(s, ch);
-                }
-            }
-
-            if (ch->interrupts & END_BLOCK_INTR)
-                ch->status |= END_BLOCK_INTR;
-        }
-
-        /* Update packet number */
-        if (ch->fs && ch->bs) {
-            a->pck_element += min_elems;
-            a->pck_element %= a->pck_elements;
-        }
-
-        /* TODO: check if we really need to update anything here or perhaps we
-         * can skip part of this.  */
-#ifndef MULTI_REQ
-        if (dma->update) {
-#endif
-            a->element += min_elems;
-
-            frames = a->element / a->elements;
-            a->element = a->element % a->elements;
-            a->frame += frames;
-            a->src += min_elems * a->elem_delta[0] + frames * a->frame_delta[0];
-            a->dest += min_elems * a->elem_delta[1] + frames * a->frame_delta[1];
-
-            /* If the channel is async, update cpc */
-            if (!ch->sync && frames)
-                ch->cpc = a->dest & 0xffff;
-
-            /* TODO: if the destination port is IMIF or EMIFF, set the dirty
-             * bits on it.  */
-#ifndef MULTI_REQ
-        }
-#else
-    }
-#endif
-
-    omap_dma_interrupts_update(s);
-}
-
-void omap_dma_reset(struct soc_dma_s *dma)
-{
-    int i;
-    struct omap_dma_s *s = dma->opaque;
-
-    soc_dma_reset(s->dma);
-    if (s->model < omap_dma_4)
-        s->gcr = 0x0004;
-    else
-        s->gcr = 0x00010010;
-    s->ocp = 0x00000000;
-    memset(&s->irqstat, 0, sizeof(s->irqstat));
-    memset(&s->irqen, 0, sizeof(s->irqen));
-    s->lcd_ch.src = emiff;
-    s->lcd_ch.condition = 0;
-    s->lcd_ch.interrupts = 0;
-    s->lcd_ch.dual = 0;
-    if (s->model < omap_dma_4)
-        omap_dma_enable_3_1_mapping(s);
-    for (i = 0; i < s->chans; i ++) {
-        s->ch[i].suspend = 0;
-        s->ch[i].prefetch = 0;
-        s->ch[i].buf_disable = 0;
-        s->ch[i].src_sync = 0;
-        memset(&s->ch[i].burst, 0, sizeof(s->ch[i].burst));
-        memset(&s->ch[i].port, 0, sizeof(s->ch[i].port));
-        memset(&s->ch[i].mode, 0, sizeof(s->ch[i].mode));
-        memset(&s->ch[i].frame_index, 0, sizeof(s->ch[i].frame_index));
-        memset(&s->ch[i].element_index, 0, sizeof(s->ch[i].element_index));
-        memset(&s->ch[i].endian, 0, sizeof(s->ch[i].endian));
-        memset(&s->ch[i].endian_lock, 0, sizeof(s->ch[i].endian_lock));
-        memset(&s->ch[i].translate, 0, sizeof(s->ch[i].translate));
-        s->ch[i].write_mode = 0;
-        s->ch[i].data_type = 0;
-        s->ch[i].transparent_copy = 0;
-        s->ch[i].constant_fill = 0;
-        s->ch[i].color = 0x00000000;
-        s->ch[i].end_prog = 0;
-        s->ch[i].repeat = 0;
-        s->ch[i].auto_init = 0;
-        s->ch[i].link_enabled = 0;
-        if (s->model < omap_dma_4)
-            s->ch[i].interrupts = 0x0003;
-        else
-            s->ch[i].interrupts = 0x0000;
-        s->ch[i].status = 0;
-        s->ch[i].cstatus = 0;
-        s->ch[i].active = 0;
-        s->ch[i].enable = 0;
-        s->ch[i].sync = 0;
-        s->ch[i].pending_request = 0;
-        s->ch[i].waiting_end_prog = 0;
-        s->ch[i].cpc = 0x0000;
-        s->ch[i].fs = 0;
-        s->ch[i].bs = 0;
-        s->ch[i].omap_3_1_compatible_disable = 0;
-        memset(&s->ch[i].active_set, 0, sizeof(s->ch[i].active_set));
-        s->ch[i].priority = 0;
-        s->ch[i].interleave_disabled = 0;
-        s->ch[i].type = 0;
-    }
-}
-
-static int omap_dma_ch_reg_read(struct omap_dma_s *s,
-                struct omap_dma_channel_s *ch, int reg, uint16_t *value)
-{
-    switch (reg) {
-    case 0x00: /* SYS_DMA_CSDP_CH0 */
-        *value = (ch->burst[1] << 14) |
-                (ch->pack[1] << 13) |
-                (ch->port[1] << 9) |
-                (ch->burst[0] << 7) |
-                (ch->pack[0] << 6) |
-                (ch->port[0] << 2) |
-                (ch->data_type >> 1);
-        break;
-
-    case 0x02: /* SYS_DMA_CCR_CH0 */
-        if (s->model <= omap_dma_3_1)
-            *value = 0 << 10;                  /* FIFO_FLUSH reads as 0 */
-        else
-            *value = ch->omap_3_1_compatible_disable << 10;
-        *value |= (ch->mode[1] << 14) |
-                (ch->mode[0] << 12) |
-                (ch->end_prog << 11) |
-                (ch->repeat << 9) |
-                (ch->auto_init << 8) |
-                (ch->enable << 7) |
-                (ch->priority << 6) |
-                (ch->fs << 5) | ch->sync;
-        break;
-
-    case 0x04: /* SYS_DMA_CICR_CH0 */
-        *value = ch->interrupts;
-        break;
-
-    case 0x06: /* SYS_DMA_CSR_CH0 */
-        *value = ch->status;
-        ch->status &= SYNC;
-        if (!ch->omap_3_1_compatible_disable && ch->sibling) {
-            *value |= (ch->sibling->status & 0x3f) << 6;
-            ch->sibling->status &= SYNC;
-        }
-        qemu_irq_lower(ch->irq);
-        break;
-
-    case 0x08: /* SYS_DMA_CSSA_L_CH0 */
-        *value = ch->addr[0] & 0x0000ffff;
-        break;
-
-    case 0x0a: /* SYS_DMA_CSSA_U_CH0 */
-        *value = ch->addr[0] >> 16;
-        break;
-
-    case 0x0c: /* SYS_DMA_CDSA_L_CH0 */
-        *value = ch->addr[1] & 0x0000ffff;
-        break;
-
-    case 0x0e: /* SYS_DMA_CDSA_U_CH0 */
-        *value = ch->addr[1] >> 16;
-        break;
-
-    case 0x10: /* SYS_DMA_CEN_CH0 */
-        *value = ch->elements;
-        break;
-
-    case 0x12: /* SYS_DMA_CFN_CH0 */
-        *value = ch->frames;
-        break;
-
-    case 0x14: /* SYS_DMA_CFI_CH0 */
-        *value = ch->frame_index[0];
-        break;
-
-    case 0x16: /* SYS_DMA_CEI_CH0 */
-        *value = ch->element_index[0];
-        break;
-
-    case 0x18: /* SYS_DMA_CPC_CH0 or DMA_CSAC */
-        if (ch->omap_3_1_compatible_disable)
-            *value = ch->active_set.src & 0xffff;      /* CSAC */
-        else
-            *value = ch->cpc;
-        break;
-
-    case 0x1a: /* DMA_CDAC */
-        *value = ch->active_set.dest & 0xffff; /* CDAC */
-        break;
-
-    case 0x1c: /* DMA_CDEI */
-        *value = ch->element_index[1];
-        break;
-
-    case 0x1e: /* DMA_CDFI */
-        *value = ch->frame_index[1];
-        break;
-
-    case 0x20: /* DMA_COLOR_L */
-        *value = ch->color & 0xffff;
-        break;
-
-    case 0x22: /* DMA_COLOR_U */
-        *value = ch->color >> 16;
-        break;
-
-    case 0x24: /* DMA_CCR2 */
-        *value = (ch->bs << 2) |
-                (ch->transparent_copy << 1) |
-                ch->constant_fill;
-        break;
-
-    case 0x28: /* DMA_CLNK_CTRL */
-        *value = (ch->link_enabled << 15) |
-                (ch->link_next_ch & 0xf);
-        break;
-
-    case 0x2a: /* DMA_LCH_CTRL */
-        *value = (ch->interleave_disabled << 15) |
-                ch->type;
-        break;
-
-    default:
-        return 1;
-    }
-    return 0;
-}
-
-static int omap_dma_ch_reg_write(struct omap_dma_s *s,
-                struct omap_dma_channel_s *ch, int reg, uint16_t value)
-{
-    switch (reg) {
-    case 0x00: /* SYS_DMA_CSDP_CH0 */
-        ch->burst[1] = (value & 0xc000) >> 14;
-        ch->pack[1] = (value & 0x2000) >> 13;
-        ch->port[1] = (enum omap_dma_port) ((value & 0x1e00) >> 9);
-        ch->burst[0] = (value & 0x0180) >> 7;
-        ch->pack[0] = (value & 0x0040) >> 6;
-        ch->port[0] = (enum omap_dma_port) ((value & 0x003c) >> 2);
-        ch->data_type = 1 << (value & 3);
-        if (ch->port[0] >= __omap_dma_port_last)
-            printf("%s: invalid DMA port %i\n", __FUNCTION__,
-                            ch->port[0]);
-        if (ch->port[1] >= __omap_dma_port_last)
-            printf("%s: invalid DMA port %i\n", __FUNCTION__,
-                            ch->port[1]);
-        if ((value & 3) == 3)
-            printf("%s: bad data_type for DMA channel\n", __FUNCTION__);
-        break;
-
-    case 0x02: /* SYS_DMA_CCR_CH0 */
-        ch->mode[1] = (omap_dma_addressing_t) ((value & 0xc000) >> 14);
-        ch->mode[0] = (omap_dma_addressing_t) ((value & 0x3000) >> 12);
-        ch->end_prog = (value & 0x0800) >> 11;
-        if (s->model >= omap_dma_3_2)
-            ch->omap_3_1_compatible_disable  = (value >> 10) & 0x1;
-        ch->repeat = (value & 0x0200) >> 9;
-        ch->auto_init = (value & 0x0100) >> 8;
-        ch->priority = (value & 0x0040) >> 6;
-        ch->fs = (value & 0x0020) >> 5;
-        ch->sync = value & 0x001f;
-
-        if (value & 0x0080)
-            omap_dma_enable_channel(s, ch);
-        else
-            omap_dma_disable_channel(s, ch);
-
-        if (ch->end_prog)
-            omap_dma_channel_end_prog(s, ch);
-
-        break;
-
-    case 0x04: /* SYS_DMA_CICR_CH0 */
-        ch->interrupts = value & 0x3f;
-        break;
-
-    case 0x06: /* SYS_DMA_CSR_CH0 */
-        OMAP_RO_REG((hwaddr) reg);
-        break;
-
-    case 0x08: /* SYS_DMA_CSSA_L_CH0 */
-        ch->addr[0] &= 0xffff0000;
-        ch->addr[0] |= value;
-        break;
-
-    case 0x0a: /* SYS_DMA_CSSA_U_CH0 */
-        ch->addr[0] &= 0x0000ffff;
-        ch->addr[0] |= (uint32_t) value << 16;
-        break;
-
-    case 0x0c: /* SYS_DMA_CDSA_L_CH0 */
-        ch->addr[1] &= 0xffff0000;
-        ch->addr[1] |= value;
-        break;
-
-    case 0x0e: /* SYS_DMA_CDSA_U_CH0 */
-        ch->addr[1] &= 0x0000ffff;
-        ch->addr[1] |= (uint32_t) value << 16;
-        break;
-
-    case 0x10: /* SYS_DMA_CEN_CH0 */
-        ch->elements = value;
-        break;
-
-    case 0x12: /* SYS_DMA_CFN_CH0 */
-        ch->frames = value;
-        break;
-
-    case 0x14: /* SYS_DMA_CFI_CH0 */
-        ch->frame_index[0] = (int16_t) value;
-        break;
-
-    case 0x16: /* SYS_DMA_CEI_CH0 */
-        ch->element_index[0] = (int16_t) value;
-        break;
-
-    case 0x18: /* SYS_DMA_CPC_CH0 or DMA_CSAC */
-        OMAP_RO_REG((hwaddr) reg);
-        break;
-
-    case 0x1c: /* DMA_CDEI */
-        ch->element_index[1] = (int16_t) value;
-        break;
-
-    case 0x1e: /* DMA_CDFI */
-        ch->frame_index[1] = (int16_t) value;
-        break;
-
-    case 0x20: /* DMA_COLOR_L */
-        ch->color &= 0xffff0000;
-        ch->color |= value;
-        break;
-
-    case 0x22: /* DMA_COLOR_U */
-        ch->color &= 0xffff;
-        ch->color |= value << 16;
-        break;
-
-    case 0x24: /* DMA_CCR2 */
-        ch->bs = (value >> 2) & 0x1;
-        ch->transparent_copy = (value >> 1) & 0x1;
-        ch->constant_fill = value & 0x1;
-        break;
-
-    case 0x28: /* DMA_CLNK_CTRL */
-        ch->link_enabled = (value >> 15) & 0x1;
-        if (value & (1 << 14)) {                       /* Stop_Lnk */
-            ch->link_enabled = 0;
-            omap_dma_disable_channel(s, ch);
-        }
-        ch->link_next_ch = value & 0x1f;
-        break;
-
-    case 0x2a: /* DMA_LCH_CTRL */
-        ch->interleave_disabled = (value >> 15) & 0x1;
-        ch->type = value & 0xf;
-        break;
-
-    default:
-        return 1;
-    }
-    return 0;
-}
-
-static int omap_dma_3_2_lcd_write(struct omap_dma_lcd_channel_s *s, int offset,
-                uint16_t value)
-{
-    switch (offset) {
-    case 0xbc0:        /* DMA_LCD_CSDP */
-        s->brust_f2 = (value >> 14) & 0x3;
-        s->pack_f2 = (value >> 13) & 0x1;
-        s->data_type_f2 = (1 << ((value >> 11) & 0x3));
-        s->brust_f1 = (value >> 7) & 0x3;
-        s->pack_f1 = (value >> 6) & 0x1;
-        s->data_type_f1 = (1 << ((value >> 0) & 0x3));
-        break;
-
-    case 0xbc2:        /* DMA_LCD_CCR */
-        s->mode_f2 = (value >> 14) & 0x3;
-        s->mode_f1 = (value >> 12) & 0x3;
-        s->end_prog = (value >> 11) & 0x1;
-        s->omap_3_1_compatible_disable = (value >> 10) & 0x1;
-        s->repeat = (value >> 9) & 0x1;
-        s->auto_init = (value >> 8) & 0x1;
-        s->running = (value >> 7) & 0x1;
-        s->priority = (value >> 6) & 0x1;
-        s->bs = (value >> 4) & 0x1;
-        break;
-
-    case 0xbc4:        /* DMA_LCD_CTRL */
-        s->dst = (value >> 8) & 0x1;
-        s->src = ((value >> 6) & 0x3) << 1;
-        s->condition = 0;
-        /* Assume no bus errors and thus no BUS_ERROR irq bits.  */
-        s->interrupts = (value >> 1) & 1;
-        s->dual = value & 1;
-        break;
-
-    case 0xbc8:        /* TOP_B1_L */
-        s->src_f1_top &= 0xffff0000;
-        s->src_f1_top |= 0x0000ffff & value;
-        break;
-
-    case 0xbca:        /* TOP_B1_U */
-        s->src_f1_top &= 0x0000ffff;
-        s->src_f1_top |= value << 16;
-        break;
-
-    case 0xbcc:        /* BOT_B1_L */
-        s->src_f1_bottom &= 0xffff0000;
-        s->src_f1_bottom |= 0x0000ffff & value;
-        break;
-
-    case 0xbce:        /* BOT_B1_U */
-        s->src_f1_bottom &= 0x0000ffff;
-        s->src_f1_bottom |= (uint32_t) value << 16;
-        break;
-
-    case 0xbd0:        /* TOP_B2_L */
-        s->src_f2_top &= 0xffff0000;
-        s->src_f2_top |= 0x0000ffff & value;
-        break;
-
-    case 0xbd2:        /* TOP_B2_U */
-        s->src_f2_top &= 0x0000ffff;
-        s->src_f2_top |= (uint32_t) value << 16;
-        break;
-
-    case 0xbd4:        /* BOT_B2_L */
-        s->src_f2_bottom &= 0xffff0000;
-        s->src_f2_bottom |= 0x0000ffff & value;
-        break;
-
-    case 0xbd6:        /* BOT_B2_U */
-        s->src_f2_bottom &= 0x0000ffff;
-        s->src_f2_bottom |= (uint32_t) value << 16;
-        break;
-
-    case 0xbd8:        /* DMA_LCD_SRC_EI_B1 */
-        s->element_index_f1 = value;
-        break;
-
-    case 0xbda:        /* DMA_LCD_SRC_FI_B1_L */
-        s->frame_index_f1 &= 0xffff0000;
-        s->frame_index_f1 |= 0x0000ffff & value;
-        break;
-
-    case 0xbf4:        /* DMA_LCD_SRC_FI_B1_U */
-        s->frame_index_f1 &= 0x0000ffff;
-        s->frame_index_f1 |= (uint32_t) value << 16;
-        break;
-
-    case 0xbdc:        /* DMA_LCD_SRC_EI_B2 */
-        s->element_index_f2 = value;
-        break;
-
-    case 0xbde:        /* DMA_LCD_SRC_FI_B2_L */
-        s->frame_index_f2 &= 0xffff0000;
-        s->frame_index_f2 |= 0x0000ffff & value;
-        break;
-
-    case 0xbf6:        /* DMA_LCD_SRC_FI_B2_U */
-        s->frame_index_f2 &= 0x0000ffff;
-        s->frame_index_f2 |= (uint32_t) value << 16;
-        break;
-
-    case 0xbe0:        /* DMA_LCD_SRC_EN_B1 */
-        s->elements_f1 = value;
-        break;
-
-    case 0xbe4:        /* DMA_LCD_SRC_FN_B1 */
-        s->frames_f1 = value;
-        break;
-
-    case 0xbe2:        /* DMA_LCD_SRC_EN_B2 */
-        s->elements_f2 = value;
-        break;
-
-    case 0xbe6:        /* DMA_LCD_SRC_FN_B2 */
-        s->frames_f2 = value;
-        break;
-
-    case 0xbea:        /* DMA_LCD_LCH_CTRL */
-        s->lch_type = value & 0xf;
-        break;
-
-    default:
-        return 1;
-    }
-    return 0;
-}
-
-static int omap_dma_3_2_lcd_read(struct omap_dma_lcd_channel_s *s, int offset,
-                uint16_t *ret)
-{
-    switch (offset) {
-    case 0xbc0:        /* DMA_LCD_CSDP */
-        *ret = (s->brust_f2 << 14) |
-            (s->pack_f2 << 13) |
-            ((s->data_type_f2 >> 1) << 11) |
-            (s->brust_f1 << 7) |
-            (s->pack_f1 << 6) |
-            ((s->data_type_f1 >> 1) << 0);
-        break;
-
-    case 0xbc2:        /* DMA_LCD_CCR */
-        *ret = (s->mode_f2 << 14) |
-            (s->mode_f1 << 12) |
-            (s->end_prog << 11) |
-            (s->omap_3_1_compatible_disable << 10) |
-            (s->repeat << 9) |
-            (s->auto_init << 8) |
-            (s->running << 7) |
-            (s->priority << 6) |
-            (s->bs << 4);
-        break;
-
-    case 0xbc4:        /* DMA_LCD_CTRL */
-        qemu_irq_lower(s->irq);
-        *ret = (s->dst << 8) |
-            ((s->src & 0x6) << 5) |
-            (s->condition << 3) |
-            (s->interrupts << 1) |
-            s->dual;
-        break;
-
-    case 0xbc8:        /* TOP_B1_L */
-        *ret = s->src_f1_top & 0xffff;
-        break;
-
-    case 0xbca:        /* TOP_B1_U */
-        *ret = s->src_f1_top >> 16;
-        break;
-
-    case 0xbcc:        /* BOT_B1_L */
-        *ret = s->src_f1_bottom & 0xffff;
-        break;
-
-    case 0xbce:        /* BOT_B1_U */
-        *ret = s->src_f1_bottom >> 16;
-        break;
-
-    case 0xbd0:        /* TOP_B2_L */
-        *ret = s->src_f2_top & 0xffff;
-        break;
-
-    case 0xbd2:        /* TOP_B2_U */
-        *ret = s->src_f2_top >> 16;
-        break;
-
-    case 0xbd4:        /* BOT_B2_L */
-        *ret = s->src_f2_bottom & 0xffff;
-        break;
-
-    case 0xbd6:        /* BOT_B2_U */
-        *ret = s->src_f2_bottom >> 16;
-        break;
-
-    case 0xbd8:        /* DMA_LCD_SRC_EI_B1 */
-        *ret = s->element_index_f1;
-        break;
-
-    case 0xbda:        /* DMA_LCD_SRC_FI_B1_L */
-        *ret = s->frame_index_f1 & 0xffff;
-        break;
-
-    case 0xbf4:        /* DMA_LCD_SRC_FI_B1_U */
-        *ret = s->frame_index_f1 >> 16;
-        break;
-
-    case 0xbdc:        /* DMA_LCD_SRC_EI_B2 */
-        *ret = s->element_index_f2;
-        break;
-
-    case 0xbde:        /* DMA_LCD_SRC_FI_B2_L */
-        *ret = s->frame_index_f2 & 0xffff;
-        break;
-
-    case 0xbf6:        /* DMA_LCD_SRC_FI_B2_U */
-        *ret = s->frame_index_f2 >> 16;
-        break;
-
-    case 0xbe0:        /* DMA_LCD_SRC_EN_B1 */
-        *ret = s->elements_f1;
-        break;
-
-    case 0xbe4:        /* DMA_LCD_SRC_FN_B1 */
-        *ret = s->frames_f1;
-        break;
-
-    case 0xbe2:        /* DMA_LCD_SRC_EN_B2 */
-        *ret = s->elements_f2;
-        break;
-
-    case 0xbe6:        /* DMA_LCD_SRC_FN_B2 */
-        *ret = s->frames_f2;
-        break;
-
-    case 0xbea:        /* DMA_LCD_LCH_CTRL */
-        *ret = s->lch_type;
-        break;
-
-    default:
-        return 1;
-    }
-    return 0;
-}
-
-static int omap_dma_3_1_lcd_write(struct omap_dma_lcd_channel_s *s, int offset,
-                uint16_t value)
-{
-    switch (offset) {
-    case 0x300:        /* SYS_DMA_LCD_CTRL */
-        s->src = (value & 0x40) ? imif : emiff;
-        s->condition = 0;
-        /* Assume no bus errors and thus no BUS_ERROR irq bits.  */
-        s->interrupts = (value >> 1) & 1;
-        s->dual = value & 1;
-        break;
-
-    case 0x302:        /* SYS_DMA_LCD_TOP_F1_L */
-        s->src_f1_top &= 0xffff0000;
-        s->src_f1_top |= 0x0000ffff & value;
-        break;
-
-    case 0x304:        /* SYS_DMA_LCD_TOP_F1_U */
-        s->src_f1_top &= 0x0000ffff;
-        s->src_f1_top |= value << 16;
-        break;
-
-    case 0x306:        /* SYS_DMA_LCD_BOT_F1_L */
-        s->src_f1_bottom &= 0xffff0000;
-        s->src_f1_bottom |= 0x0000ffff & value;
-        break;
-
-    case 0x308:        /* SYS_DMA_LCD_BOT_F1_U */
-        s->src_f1_bottom &= 0x0000ffff;
-        s->src_f1_bottom |= value << 16;
-        break;
-
-    case 0x30a:        /* SYS_DMA_LCD_TOP_F2_L */
-        s->src_f2_top &= 0xffff0000;
-        s->src_f2_top |= 0x0000ffff & value;
-        break;
-
-    case 0x30c:        /* SYS_DMA_LCD_TOP_F2_U */
-        s->src_f2_top &= 0x0000ffff;
-        s->src_f2_top |= value << 16;
-        break;
-
-    case 0x30e:        /* SYS_DMA_LCD_BOT_F2_L */
-        s->src_f2_bottom &= 0xffff0000;
-        s->src_f2_bottom |= 0x0000ffff & value;
-        break;
-
-    case 0x310:        /* SYS_DMA_LCD_BOT_F2_U */
-        s->src_f2_bottom &= 0x0000ffff;
-        s->src_f2_bottom |= value << 16;
-        break;
-
-    default:
-        return 1;
-    }
-    return 0;
-}
-
-static int omap_dma_3_1_lcd_read(struct omap_dma_lcd_channel_s *s, int offset,
-                uint16_t *ret)
-{
-    int i;
-
-    switch (offset) {
-    case 0x300:        /* SYS_DMA_LCD_CTRL */
-        i = s->condition;
-        s->condition = 0;
-        qemu_irq_lower(s->irq);
-        *ret = ((s->src == imif) << 6) | (i << 3) |
-                (s->interrupts << 1) | s->dual;
-        break;
-
-    case 0x302:        /* SYS_DMA_LCD_TOP_F1_L */
-        *ret = s->src_f1_top & 0xffff;
-        break;
-
-    case 0x304:        /* SYS_DMA_LCD_TOP_F1_U */
-        *ret = s->src_f1_top >> 16;
-        break;
-
-    case 0x306:        /* SYS_DMA_LCD_BOT_F1_L */
-        *ret = s->src_f1_bottom & 0xffff;
-        break;
-
-    case 0x308:        /* SYS_DMA_LCD_BOT_F1_U */
-        *ret = s->src_f1_bottom >> 16;
-        break;
-
-    case 0x30a:        /* SYS_DMA_LCD_TOP_F2_L */
-        *ret = s->src_f2_top & 0xffff;
-        break;
-
-    case 0x30c:        /* SYS_DMA_LCD_TOP_F2_U */
-        *ret = s->src_f2_top >> 16;
-        break;
-
-    case 0x30e:        /* SYS_DMA_LCD_BOT_F2_L */
-        *ret = s->src_f2_bottom & 0xffff;
-        break;
-
-    case 0x310:        /* SYS_DMA_LCD_BOT_F2_U */
-        *ret = s->src_f2_bottom >> 16;
-        break;
-
-    default:
-        return 1;
-    }
-    return 0;
-}
-
-static int omap_dma_sys_write(struct omap_dma_s *s, int offset, uint16_t value)
-{
-    switch (offset) {
-    case 0x400:        /* SYS_DMA_GCR */
-        s->gcr = value;
-        break;
-
-    case 0x404:        /* DMA_GSCR */
-        if (value & 0x8)
-            omap_dma_disable_3_1_mapping(s);
-        else
-            omap_dma_enable_3_1_mapping(s);
-        break;
-
-    case 0x408:        /* DMA_GRST */
-        if (value & 0x1)
-            omap_dma_reset(s->dma);
-        break;
-
-    default:
-        return 1;
-    }
-    return 0;
-}
-
-static int omap_dma_sys_read(struct omap_dma_s *s, int offset,
-                uint16_t *ret)
-{
-    switch (offset) {
-    case 0x400:        /* SYS_DMA_GCR */
-        *ret = s->gcr;
-        break;
-
-    case 0x404:        /* DMA_GSCR */
-        *ret = s->omap_3_1_mapping_disabled << 3;
-        break;
-
-    case 0x408:        /* DMA_GRST */
-        *ret = 0;
-        break;
-
-    case 0x442:        /* DMA_HW_ID */
-    case 0x444:        /* DMA_PCh2_ID */
-    case 0x446:        /* DMA_PCh0_ID */
-    case 0x448:        /* DMA_PCh1_ID */
-    case 0x44a:        /* DMA_PChG_ID */
-    case 0x44c:        /* DMA_PChD_ID */
-        *ret = 1;
-        break;
-
-    case 0x44e:        /* DMA_CAPS_0_U */
-        *ret = (s->caps[0] >> 16) & 0xffff;
-        break;
-    case 0x450:        /* DMA_CAPS_0_L */
-        *ret = (s->caps[0] >>  0) & 0xffff;
-        break;
-
-    case 0x452:        /* DMA_CAPS_1_U */
-        *ret = (s->caps[1] >> 16) & 0xffff;
-        break;
-    case 0x454:        /* DMA_CAPS_1_L */
-        *ret = (s->caps[1] >>  0) & 0xffff;
-        break;
-
-    case 0x456:        /* DMA_CAPS_2 */
-        *ret = s->caps[2];
-        break;
-
-    case 0x458:        /* DMA_CAPS_3 */
-        *ret = s->caps[3];
-        break;
-
-    case 0x45a:        /* DMA_CAPS_4 */
-        *ret = s->caps[4];
-        break;
-
-    case 0x460:        /* DMA_PCh2_SR */
-    case 0x480:        /* DMA_PCh0_SR */
-    case 0x482:        /* DMA_PCh1_SR */
-    case 0x4c0:        /* DMA_PChD_SR_0 */
-        printf("%s: Physical Channel Status Registers not implemented.\n",
-               __FUNCTION__);
-        *ret = 0xff;
-        break;
-
-    default:
-        return 1;
-    }
-    return 0;
-}
-
-static uint64_t omap_dma_read(void *opaque, hwaddr addr,
-                              unsigned size)
-{
-    struct omap_dma_s *s = (struct omap_dma_s *) opaque;
-    int reg, ch;
-    uint16_t ret;
-
-    if (size != 2) {
-        return omap_badwidth_read16(opaque, addr);
-    }
-
-    switch (addr) {
-    case 0x300 ... 0x3fe:
-        if (s->model <= omap_dma_3_1 || !s->omap_3_1_mapping_disabled) {
-            if (omap_dma_3_1_lcd_read(&s->lcd_ch, addr, &ret))
-                break;
-            return ret;
-        }
-        /* Fall through. */
-    case 0x000 ... 0x2fe:
-        reg = addr & 0x3f;
-        ch = (addr >> 6) & 0x0f;
-        if (omap_dma_ch_reg_read(s, &s->ch[ch], reg, &ret))
-            break;
-        return ret;
-
-    case 0x404 ... 0x4fe:
-        if (s->model <= omap_dma_3_1)
-            break;
-        /* Fall through. */
-    case 0x400:
-        if (omap_dma_sys_read(s, addr, &ret))
-            break;
-        return ret;
-
-    case 0xb00 ... 0xbfe:
-        if (s->model == omap_dma_3_2 && s->omap_3_1_mapping_disabled) {
-            if (omap_dma_3_2_lcd_read(&s->lcd_ch, addr, &ret))
-                break;
-            return ret;
-        }
-        break;
-    }
-
-    OMAP_BAD_REG(addr);
-    return 0;
-}
-
-static void omap_dma_write(void *opaque, hwaddr addr,
-                           uint64_t value, unsigned size)
-{
-    struct omap_dma_s *s = (struct omap_dma_s *) opaque;
-    int reg, ch;
-
-    if (size != 2) {
-        return omap_badwidth_write16(opaque, addr, value);
-    }
-
-    switch (addr) {
-    case 0x300 ... 0x3fe:
-        if (s->model <= omap_dma_3_1 || !s->omap_3_1_mapping_disabled) {
-            if (omap_dma_3_1_lcd_write(&s->lcd_ch, addr, value))
-                break;
-            return;
-        }
-        /* Fall through.  */
-    case 0x000 ... 0x2fe:
-        reg = addr & 0x3f;
-        ch = (addr >> 6) & 0x0f;
-        if (omap_dma_ch_reg_write(s, &s->ch[ch], reg, value))
-            break;
-        return;
-
-    case 0x404 ... 0x4fe:
-        if (s->model <= omap_dma_3_1)
-            break;
-    case 0x400:
-        /* Fall through. */
-        if (omap_dma_sys_write(s, addr, value))
-            break;
-        return;
-
-    case 0xb00 ... 0xbfe:
-        if (s->model == omap_dma_3_2 && s->omap_3_1_mapping_disabled) {
-            if (omap_dma_3_2_lcd_write(&s->lcd_ch, addr, value))
-                break;
-            return;
-        }
-        break;
-    }
-
-    OMAP_BAD_REG(addr);
-}
-
-static const MemoryRegionOps omap_dma_ops = {
-    .read = omap_dma_read,
-    .write = omap_dma_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void omap_dma_request(void *opaque, int drq, int req)
-{
-    struct omap_dma_s *s = (struct omap_dma_s *) opaque;
-    /* The request pins are level triggered in QEMU.  */
-    if (req) {
-        if (~s->dma->drqbmp & (1 << drq)) {
-            s->dma->drqbmp |= 1 << drq;
-            omap_dma_process_request(s, drq);
-        }
-    } else
-        s->dma->drqbmp &= ~(1 << drq);
-}
-
-/* XXX: this won't be needed once soc_dma knows about clocks.  */
-static void omap_dma_clk_update(void *opaque, int line, int on)
-{
-    struct omap_dma_s *s = (struct omap_dma_s *) opaque;
-    int i;
-
-    s->dma->freq = omap_clk_getrate(s->clk);
-
-    for (i = 0; i < s->chans; i ++)
-        if (s->ch[i].active)
-            soc_dma_set_request(s->ch[i].dma, on);
-}
-
-static void omap_dma_setcaps(struct omap_dma_s *s)
-{
-    switch (s->model) {
-    default:
-    case omap_dma_3_1:
-        break;
-    case omap_dma_3_2:
-    case omap_dma_4:
-        /* XXX Only available for sDMA */
-        s->caps[0] =
-                (1 << 19) |    /* Constant Fill Capability */
-                (1 << 18);     /* Transparent BLT Capability */
-        s->caps[1] =
-                (1 << 1);      /* 1-bit palettized capability (DMA 3.2 only) */
-        s->caps[2] =
-                (1 << 8) |     /* SEPARATE_SRC_AND_DST_INDEX_CPBLTY */
-                (1 << 7) |     /* DST_DOUBLE_INDEX_ADRS_CPBLTY */
-                (1 << 6) |     /* DST_SINGLE_INDEX_ADRS_CPBLTY */
-                (1 << 5) |     /* DST_POST_INCRMNT_ADRS_CPBLTY */
-                (1 << 4) |     /* DST_CONST_ADRS_CPBLTY */
-                (1 << 3) |     /* SRC_DOUBLE_INDEX_ADRS_CPBLTY */
-                (1 << 2) |     /* SRC_SINGLE_INDEX_ADRS_CPBLTY */
-                (1 << 1) |     /* SRC_POST_INCRMNT_ADRS_CPBLTY */
-                (1 << 0);      /* SRC_CONST_ADRS_CPBLTY */
-        s->caps[3] =
-                (1 << 6) |     /* BLOCK_SYNCHR_CPBLTY (DMA 4 only) */
-                (1 << 7) |     /* PKT_SYNCHR_CPBLTY (DMA 4 only) */
-                (1 << 5) |     /* CHANNEL_CHAINING_CPBLTY */
-                (1 << 4) |     /* LCh_INTERLEAVE_CPBLTY */
-                (1 << 3) |     /* AUTOINIT_REPEAT_CPBLTY (DMA 3.2 only) */
-                (1 << 2) |     /* AUTOINIT_ENDPROG_CPBLTY (DMA 3.2 only) */
-                (1 << 1) |     /* FRAME_SYNCHR_CPBLTY */
-                (1 << 0);      /* ELMNT_SYNCHR_CPBLTY */
-        s->caps[4] =
-                (1 << 7) |     /* PKT_INTERRUPT_CPBLTY (DMA 4 only) */
-                (1 << 6) |     /* SYNC_STATUS_CPBLTY */
-                (1 << 5) |     /* BLOCK_INTERRUPT_CPBLTY */
-                (1 << 4) |     /* LAST_FRAME_INTERRUPT_CPBLTY */
-                (1 << 3) |     /* FRAME_INTERRUPT_CPBLTY */
-                (1 << 2) |     /* HALF_FRAME_INTERRUPT_CPBLTY */
-                (1 << 1) |     /* EVENT_DROP_INTERRUPT_CPBLTY */
-                (1 << 0);      /* TIMEOUT_INTERRUPT_CPBLTY (DMA 3.2 only) */
-        break;
-    }
-}
-
-struct soc_dma_s *omap_dma_init(hwaddr base, qemu_irq *irqs,
-                MemoryRegion *sysmem,
-                qemu_irq lcd_irq, struct omap_mpu_state_s *mpu, omap_clk clk,
-                enum omap_dma_model model)
-{
-    int num_irqs, memsize, i;
-    struct omap_dma_s *s = (struct omap_dma_s *)
-            g_malloc0(sizeof(struct omap_dma_s));
-
-    if (model <= omap_dma_3_1) {
-        num_irqs = 6;
-        memsize = 0x800;
-    } else {
-        num_irqs = 16;
-        memsize = 0xc00;
-    }
-    s->model = model;
-    s->mpu = mpu;
-    s->clk = clk;
-    s->lcd_ch.irq = lcd_irq;
-    s->lcd_ch.mpu = mpu;
-
-    s->dma = soc_dma_init((model <= omap_dma_3_1) ? 9 : 16);
-    s->dma->freq = omap_clk_getrate(clk);
-    s->dma->transfer_fn = omap_dma_transfer_generic;
-    s->dma->setup_fn = omap_dma_transfer_setup;
-    s->dma->drq = qemu_allocate_irqs(omap_dma_request, s, 32);
-    s->dma->opaque = s;
-
-    while (num_irqs --)
-        s->ch[num_irqs].irq = irqs[num_irqs];
-    for (i = 0; i < 3; i ++) {
-        s->ch[i].sibling = &s->ch[i + 6];
-        s->ch[i + 6].sibling = &s->ch[i];
-    }
-    for (i = (model <= omap_dma_3_1) ? 8 : 15; i >= 0; i --) {
-        s->ch[i].dma = &s->dma->ch[i];
-        s->dma->ch[i].opaque = &s->ch[i];
-    }
-
-    omap_dma_setcaps(s);
-    omap_clk_adduser(s->clk, qemu_allocate_irqs(omap_dma_clk_update, s, 1)[0]);
-    omap_dma_reset(s->dma);
-    omap_dma_clk_update(s, 0, 1);
-
-    memory_region_init_io(&s->iomem, &omap_dma_ops, s, "omap.dma", memsize);
-    memory_region_add_subregion(sysmem, base, &s->iomem);
-
-    mpu->drq = s->dma->drq;
-
-    return s->dma;
-}
-
-static void omap_dma_interrupts_4_update(struct omap_dma_s *s)
-{
-    struct omap_dma_channel_s *ch = s->ch;
-    uint32_t bmp, bit;
-
-    for (bmp = 0, bit = 1; bit; ch ++, bit <<= 1)
-        if (ch->status) {
-            bmp |= bit;
-            ch->cstatus |= ch->status;
-            ch->status = 0;
-        }
-    if ((s->irqstat[0] |= s->irqen[0] & bmp))
-        qemu_irq_raise(s->irq[0]);
-    if ((s->irqstat[1] |= s->irqen[1] & bmp))
-        qemu_irq_raise(s->irq[1]);
-    if ((s->irqstat[2] |= s->irqen[2] & bmp))
-        qemu_irq_raise(s->irq[2]);
-    if ((s->irqstat[3] |= s->irqen[3] & bmp))
-        qemu_irq_raise(s->irq[3]);
-}
-
-static uint64_t omap_dma4_read(void *opaque, hwaddr addr,
-                               unsigned size)
-{
-    struct omap_dma_s *s = (struct omap_dma_s *) opaque;
-    int irqn = 0, chnum;
-    struct omap_dma_channel_s *ch;
-
-    if (size == 1) {
-        return omap_badwidth_read16(opaque, addr);
-    }
-
-    switch (addr) {
-    case 0x00: /* DMA4_REVISION */
-        return 0x40;
-
-    case 0x14: /* DMA4_IRQSTATUS_L3 */
-        irqn ++;
-        /* fall through */
-    case 0x10: /* DMA4_IRQSTATUS_L2 */
-        irqn ++;
-        /* fall through */
-    case 0x0c: /* DMA4_IRQSTATUS_L1 */
-        irqn ++;
-        /* fall through */
-    case 0x08: /* DMA4_IRQSTATUS_L0 */
-        return s->irqstat[irqn];
-
-    case 0x24: /* DMA4_IRQENABLE_L3 */
-        irqn ++;
-        /* fall through */
-    case 0x20: /* DMA4_IRQENABLE_L2 */
-        irqn ++;
-        /* fall through */
-    case 0x1c: /* DMA4_IRQENABLE_L1 */
-        irqn ++;
-        /* fall through */
-    case 0x18: /* DMA4_IRQENABLE_L0 */
-        return s->irqen[irqn];
-
-    case 0x28: /* DMA4_SYSSTATUS */
-        return 1;                                              /* RESETDONE */
-
-    case 0x2c: /* DMA4_OCP_SYSCONFIG */
-        return s->ocp;
-
-    case 0x64: /* DMA4_CAPS_0 */
-        return s->caps[0];
-    case 0x6c: /* DMA4_CAPS_2 */
-        return s->caps[2];
-    case 0x70: /* DMA4_CAPS_3 */
-        return s->caps[3];
-    case 0x74: /* DMA4_CAPS_4 */
-        return s->caps[4];
-
-    case 0x78: /* DMA4_GCR */
-        return s->gcr;
-
-    case 0x80 ... 0xfff:
-        addr -= 0x80;
-        chnum = addr / 0x60;
-        ch = s->ch + chnum;
-        addr -= chnum * 0x60;
-        break;
-
-    default:
-        OMAP_BAD_REG(addr);
-        return 0;
-    }
-
-    /* Per-channel registers */
-    switch (addr) {
-    case 0x00: /* DMA4_CCR */
-        return (ch->buf_disable << 25) |
-                (ch->src_sync << 24) |
-                (ch->prefetch << 23) |
-                ((ch->sync & 0x60) << 14) |
-                (ch->bs << 18) |
-                (ch->transparent_copy << 17) |
-                (ch->constant_fill << 16) |
-                (ch->mode[1] << 14) |
-                (ch->mode[0] << 12) |
-                (0 << 10) | (0 << 9) |
-                (ch->suspend << 8) |
-                (ch->enable << 7) |
-                (ch->priority << 6) |
-                (ch->fs << 5) | (ch->sync & 0x1f);
-
-    case 0x04: /* DMA4_CLNK_CTRL */
-        return (ch->link_enabled << 15) | ch->link_next_ch;
-
-    case 0x08: /* DMA4_CICR */
-        return ch->interrupts;
-
-    case 0x0c: /* DMA4_CSR */
-        return ch->cstatus;
-
-    case 0x10: /* DMA4_CSDP */
-        return (ch->endian[0] << 21) |
-                (ch->endian_lock[0] << 20) |
-                (ch->endian[1] << 19) |
-                (ch->endian_lock[1] << 18) |
-                (ch->write_mode << 16) |
-                (ch->burst[1] << 14) |
-                (ch->pack[1] << 13) |
-                (ch->translate[1] << 9) |
-                (ch->burst[0] << 7) |
-                (ch->pack[0] << 6) |
-                (ch->translate[0] << 2) |
-                (ch->data_type >> 1);
-
-    case 0x14: /* DMA4_CEN */
-        return ch->elements;
-
-    case 0x18: /* DMA4_CFN */
-        return ch->frames;
-
-    case 0x1c: /* DMA4_CSSA */
-        return ch->addr[0];
-
-    case 0x20: /* DMA4_CDSA */
-        return ch->addr[1];
-
-    case 0x24: /* DMA4_CSEI */
-        return ch->element_index[0];
-
-    case 0x28: /* DMA4_CSFI */
-        return ch->frame_index[0];
-
-    case 0x2c: /* DMA4_CDEI */
-        return ch->element_index[1];
-
-    case 0x30: /* DMA4_CDFI */
-        return ch->frame_index[1];
-
-    case 0x34: /* DMA4_CSAC */
-        return ch->active_set.src & 0xffff;
-
-    case 0x38: /* DMA4_CDAC */
-        return ch->active_set.dest & 0xffff;
-
-    case 0x3c: /* DMA4_CCEN */
-        return ch->active_set.element;
-
-    case 0x40: /* DMA4_CCFN */
-        return ch->active_set.frame;
-
-    case 0x44: /* DMA4_COLOR */
-        /* XXX only in sDMA */
-        return ch->color;
-
-    default:
-        OMAP_BAD_REG(addr);
-        return 0;
-    }
-}
-
-static void omap_dma4_write(void *opaque, hwaddr addr,
-                            uint64_t value, unsigned size)
-{
-    struct omap_dma_s *s = (struct omap_dma_s *) opaque;
-    int chnum, irqn = 0;
-    struct omap_dma_channel_s *ch;
-
-    if (size == 1) {
-        return omap_badwidth_write16(opaque, addr, value);
-    }
-
-    switch (addr) {
-    case 0x14: /* DMA4_IRQSTATUS_L3 */
-        irqn ++;
-        /* fall through */
-    case 0x10: /* DMA4_IRQSTATUS_L2 */
-        irqn ++;
-        /* fall through */
-    case 0x0c: /* DMA4_IRQSTATUS_L1 */
-        irqn ++;
-        /* fall through */
-    case 0x08: /* DMA4_IRQSTATUS_L0 */
-        s->irqstat[irqn] &= ~value;
-        if (!s->irqstat[irqn])
-            qemu_irq_lower(s->irq[irqn]);
-        return;
-
-    case 0x24: /* DMA4_IRQENABLE_L3 */
-        irqn ++;
-        /* fall through */
-    case 0x20: /* DMA4_IRQENABLE_L2 */
-        irqn ++;
-        /* fall through */
-    case 0x1c: /* DMA4_IRQENABLE_L1 */
-        irqn ++;
-        /* fall through */
-    case 0x18: /* DMA4_IRQENABLE_L0 */
-        s->irqen[irqn] = value;
-        return;
-
-    case 0x2c: /* DMA4_OCP_SYSCONFIG */
-        if (value & 2)                                         /* SOFTRESET */
-            omap_dma_reset(s->dma);
-        s->ocp = value & 0x3321;
-        if (((s->ocp >> 12) & 3) == 3)                         /* MIDLEMODE */
-            fprintf(stderr, "%s: invalid DMA power mode\n", __FUNCTION__);
-        return;
-
-    case 0x78: /* DMA4_GCR */
-        s->gcr = value & 0x00ff00ff;
-       if ((value & 0xff) == 0x00)             /* MAX_CHANNEL_FIFO_DEPTH */
-            fprintf(stderr, "%s: wrong FIFO depth in GCR\n", __FUNCTION__);
-        return;
-
-    case 0x80 ... 0xfff:
-        addr -= 0x80;
-        chnum = addr / 0x60;
-        ch = s->ch + chnum;
-        addr -= chnum * 0x60;
-        break;
-
-    case 0x00: /* DMA4_REVISION */
-    case 0x28: /* DMA4_SYSSTATUS */
-    case 0x64: /* DMA4_CAPS_0 */
-    case 0x6c: /* DMA4_CAPS_2 */
-    case 0x70: /* DMA4_CAPS_3 */
-    case 0x74: /* DMA4_CAPS_4 */
-        OMAP_RO_REG(addr);
-        return;
-
-    default:
-        OMAP_BAD_REG(addr);
-        return;
-    }
-
-    /* Per-channel registers */
-    switch (addr) {
-    case 0x00: /* DMA4_CCR */
-        ch->buf_disable = (value >> 25) & 1;
-        ch->src_sync = (value >> 24) & 1;      /* XXX For CamDMA must be 1 */
-        if (ch->buf_disable && !ch->src_sync)
-            fprintf(stderr, "%s: Buffering disable is not allowed in "
-                            "destination synchronised mode\n", __FUNCTION__);
-        ch->prefetch = (value >> 23) & 1;
-        ch->bs = (value >> 18) & 1;
-        ch->transparent_copy = (value >> 17) & 1;
-        ch->constant_fill = (value >> 16) & 1;
-        ch->mode[1] = (omap_dma_addressing_t) ((value & 0xc000) >> 14);
-        ch->mode[0] = (omap_dma_addressing_t) ((value & 0x3000) >> 12);
-        ch->suspend = (value & 0x0100) >> 8;
-        ch->priority = (value & 0x0040) >> 6;
-        ch->fs = (value & 0x0020) >> 5;
-        if (ch->fs && ch->bs && ch->mode[0] && ch->mode[1])
-            fprintf(stderr, "%s: For a packet transfer at least one port "
-                            "must be constant-addressed\n", __FUNCTION__);
-        ch->sync = (value & 0x001f) | ((value >> 14) & 0x0060);
-        /* XXX must be 0x01 for CamDMA */
-
-        if (value & 0x0080)
-            omap_dma_enable_channel(s, ch);
-        else
-            omap_dma_disable_channel(s, ch);
-
-        break;
-
-    case 0x04: /* DMA4_CLNK_CTRL */
-        ch->link_enabled = (value >> 15) & 0x1;
-        ch->link_next_ch = value & 0x1f;
-        break;
-
-    case 0x08: /* DMA4_CICR */
-        ch->interrupts = value & 0x09be;
-        break;
-
-    case 0x0c: /* DMA4_CSR */
-        ch->cstatus &= ~value;
-        break;
-
-    case 0x10: /* DMA4_CSDP */
-        ch->endian[0] =(value >> 21) & 1;
-        ch->endian_lock[0] =(value >> 20) & 1;
-        ch->endian[1] =(value >> 19) & 1;
-        ch->endian_lock[1] =(value >> 18) & 1;
-        if (ch->endian[0] != ch->endian[1])
-            fprintf(stderr, "%s: DMA endiannes conversion enable attempt\n",
-                            __FUNCTION__);
-        ch->write_mode = (value >> 16) & 3;
-        ch->burst[1] = (value & 0xc000) >> 14;
-        ch->pack[1] = (value & 0x2000) >> 13;
-        ch->translate[1] = (value & 0x1e00) >> 9;
-        ch->burst[0] = (value & 0x0180) >> 7;
-        ch->pack[0] = (value & 0x0040) >> 6;
-        ch->translate[0] = (value & 0x003c) >> 2;
-        if (ch->translate[0] | ch->translate[1])
-            fprintf(stderr, "%s: bad MReqAddressTranslate sideband signal\n",
-                            __FUNCTION__);
-        ch->data_type = 1 << (value & 3);
-        if ((value & 3) == 3)
-            printf("%s: bad data_type for DMA channel\n", __FUNCTION__);
-        break;
-
-    case 0x14: /* DMA4_CEN */
-        ch->set_update = 1;
-        ch->elements = value & 0xffffff;
-        break;
-
-    case 0x18: /* DMA4_CFN */
-        ch->frames = value & 0xffff;
-        ch->set_update = 1;
-        break;
-
-    case 0x1c: /* DMA4_CSSA */
-        ch->addr[0] = (hwaddr) (uint32_t) value;
-        ch->set_update = 1;
-        break;
-
-    case 0x20: /* DMA4_CDSA */
-        ch->addr[1] = (hwaddr) (uint32_t) value;
-        ch->set_update = 1;
-        break;
-
-    case 0x24: /* DMA4_CSEI */
-        ch->element_index[0] = (int16_t) value;
-        ch->set_update = 1;
-        break;
-
-    case 0x28: /* DMA4_CSFI */
-        ch->frame_index[0] = (int32_t) value;
-        ch->set_update = 1;
-        break;
-
-    case 0x2c: /* DMA4_CDEI */
-        ch->element_index[1] = (int16_t) value;
-        ch->set_update = 1;
-        break;
-
-    case 0x30: /* DMA4_CDFI */
-        ch->frame_index[1] = (int32_t) value;
-        ch->set_update = 1;
-        break;
-
-    case 0x44: /* DMA4_COLOR */
-        /* XXX only in sDMA */
-        ch->color = value;
-        break;
-
-    case 0x34: /* DMA4_CSAC */
-    case 0x38: /* DMA4_CDAC */
-    case 0x3c: /* DMA4_CCEN */
-    case 0x40: /* DMA4_CCFN */
-        OMAP_RO_REG(addr);
-        break;
-
-    default:
-        OMAP_BAD_REG(addr);
-    }
-}
-
-static const MemoryRegionOps omap_dma4_ops = {
-    .read = omap_dma4_read,
-    .write = omap_dma4_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-struct soc_dma_s *omap_dma4_init(hwaddr base, qemu_irq *irqs,
-                MemoryRegion *sysmem,
-                struct omap_mpu_state_s *mpu, int fifo,
-                int chans, omap_clk iclk, omap_clk fclk)
-{
-    int i;
-    struct omap_dma_s *s = (struct omap_dma_s *)
-            g_malloc0(sizeof(struct omap_dma_s));
-
-    s->model = omap_dma_4;
-    s->chans = chans;
-    s->mpu = mpu;
-    s->clk = fclk;
-
-    s->dma = soc_dma_init(s->chans);
-    s->dma->freq = omap_clk_getrate(fclk);
-    s->dma->transfer_fn = omap_dma_transfer_generic;
-    s->dma->setup_fn = omap_dma_transfer_setup;
-    s->dma->drq = qemu_allocate_irqs(omap_dma_request, s, 64);
-    s->dma->opaque = s;
-    for (i = 0; i < s->chans; i ++) {
-        s->ch[i].dma = &s->dma->ch[i];
-        s->dma->ch[i].opaque = &s->ch[i];
-    }
-
-    memcpy(&s->irq, irqs, sizeof(s->irq));
-    s->intr_update = omap_dma_interrupts_4_update;
-
-    omap_dma_setcaps(s);
-    omap_clk_adduser(s->clk, qemu_allocate_irqs(omap_dma_clk_update, s, 1)[0]);
-    omap_dma_reset(s->dma);
-    omap_dma_clk_update(s, 0, !!s->dma->freq);
-
-    memory_region_init_io(&s->iomem, &omap_dma4_ops, s, "omap.dma4", 0x1000);
-    memory_region_add_subregion(sysmem, base, &s->iomem);
-
-    mpu->drq = s->dma->drq;
-
-    return s->dma;
-}
-
-struct omap_dma_lcd_channel_s *omap_dma_get_lcdch(struct soc_dma_s *dma)
-{
-    struct omap_dma_s *s = dma->opaque;
-
-    return &s->lcd_ch;
-}
diff --git a/hw/omap_dss.c b/hw/omap_dss.c
deleted file mode 100644 (file)
index 948ad8f..0000000
+++ /dev/null
@@ -1,1086 +0,0 @@
-/*
- * OMAP2 Display Subsystem.
- *
- * Copyright (C) 2008 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.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 or
- * (at your option) version 3 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
- * 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 "hw/hw.h"
-#include "ui/console.h"
-#include "hw/omap.h"
-
-struct omap_dss_s {
-    qemu_irq irq;
-    qemu_irq drq;
-    DisplayState *state;
-    MemoryRegion iomem_diss1, iomem_disc1, iomem_rfbi1, iomem_venc1, iomem_im3;
-
-    int autoidle;
-    int control;
-    int enable;
-
-    struct omap_dss_panel_s {
-        int enable;
-        int nx;
-        int ny;
-
-        int x;
-        int y;
-    } dig, lcd;
-
-    struct {
-        uint32_t idlemode;
-        uint32_t irqst;
-        uint32_t irqen;
-        uint32_t control;
-        uint32_t config;
-        uint32_t capable;
-        uint32_t timing[4];
-        int line;
-        uint32_t bg[2];
-        uint32_t trans[2];
-
-        struct omap_dss_plane_s {
-            int enable;
-            int bpp;
-            int posx;
-            int posy;
-            int nx;
-            int ny;
-
-            hwaddr addr[3];
-
-            uint32_t attr;
-            uint32_t tresh;
-            int rowinc;
-            int colinc;
-            int wininc;
-        } l[3];
-
-        int invalidate;
-        uint16_t palette[256];
-    } dispc;
-
-    struct {
-        int idlemode;
-        uint32_t control;
-        int enable;
-        int pixels;
-        int busy;
-        int skiplines;
-        uint16_t rxbuf;
-        uint32_t config[2];
-        uint32_t time[4];
-        uint32_t data[6];
-        uint16_t vsync;
-        uint16_t hsync;
-        struct rfbi_chip_s *chip[2];
-    } rfbi;
-};
-
-static void omap_dispc_interrupt_update(struct omap_dss_s *s)
-{
-    qemu_set_irq(s->irq, s->dispc.irqst & s->dispc.irqen);
-}
-
-static void omap_rfbi_reset(struct omap_dss_s *s)
-{
-    s->rfbi.idlemode = 0;
-    s->rfbi.control = 2;
-    s->rfbi.enable = 0;
-    s->rfbi.pixels = 0;
-    s->rfbi.skiplines = 0;
-    s->rfbi.busy = 0;
-    s->rfbi.config[0] = 0x00310000;
-    s->rfbi.config[1] = 0x00310000;
-    s->rfbi.time[0] = 0;
-    s->rfbi.time[1] = 0;
-    s->rfbi.time[2] = 0;
-    s->rfbi.time[3] = 0;
-    s->rfbi.data[0] = 0;
-    s->rfbi.data[1] = 0;
-    s->rfbi.data[2] = 0;
-    s->rfbi.data[3] = 0;
-    s->rfbi.data[4] = 0;
-    s->rfbi.data[5] = 0;
-    s->rfbi.vsync = 0;
-    s->rfbi.hsync = 0;
-}
-
-void omap_dss_reset(struct omap_dss_s *s)
-{
-    s->autoidle = 0;
-    s->control = 0;
-    s->enable = 0;
-
-    s->dig.enable = 0;
-    s->dig.nx = 1;
-    s->dig.ny = 1;
-
-    s->lcd.enable = 0;
-    s->lcd.nx = 1;
-    s->lcd.ny = 1;
-
-    s->dispc.idlemode = 0;
-    s->dispc.irqst = 0;
-    s->dispc.irqen = 0;
-    s->dispc.control = 0;
-    s->dispc.config = 0;
-    s->dispc.capable = 0x161;
-    s->dispc.timing[0] = 0;
-    s->dispc.timing[1] = 0;
-    s->dispc.timing[2] = 0;
-    s->dispc.timing[3] = 0;
-    s->dispc.line = 0;
-    s->dispc.bg[0] = 0;
-    s->dispc.bg[1] = 0;
-    s->dispc.trans[0] = 0;
-    s->dispc.trans[1] = 0;
-
-    s->dispc.l[0].enable = 0;
-    s->dispc.l[0].bpp = 0;
-    s->dispc.l[0].addr[0] = 0;
-    s->dispc.l[0].addr[1] = 0;
-    s->dispc.l[0].addr[2] = 0;
-    s->dispc.l[0].posx = 0;
-    s->dispc.l[0].posy = 0;
-    s->dispc.l[0].nx = 1;
-    s->dispc.l[0].ny = 1;
-    s->dispc.l[0].attr = 0;
-    s->dispc.l[0].tresh = 0;
-    s->dispc.l[0].rowinc = 1;
-    s->dispc.l[0].colinc = 1;
-    s->dispc.l[0].wininc = 0;
-
-    omap_rfbi_reset(s);
-    omap_dispc_interrupt_update(s);
-}
-
-static uint64_t omap_diss_read(void *opaque, hwaddr addr,
-                               unsigned size)
-{
-    struct omap_dss_s *s = (struct omap_dss_s *) opaque;
-
-    if (size != 4) {
-        return omap_badwidth_read32(opaque, addr);
-    }
-
-    switch (addr) {
-    case 0x00: /* DSS_REVISIONNUMBER */
-        return 0x20;
-
-    case 0x10: /* DSS_SYSCONFIG */
-        return s->autoidle;
-
-    case 0x14: /* DSS_SYSSTATUS */
-        return 1;                                              /* RESETDONE */
-
-    case 0x40: /* DSS_CONTROL */
-        return s->control;
-
-    case 0x50: /* DSS_PSA_LCD_REG_1 */
-    case 0x54: /* DSS_PSA_LCD_REG_2 */
-    case 0x58: /* DSS_PSA_VIDEO_REG */
-        /* TODO: fake some values when appropriate s->control bits are set */
-        return 0;
-
-    case 0x5c: /* DSS_STATUS */
-        return 1 + (s->control & 1);
-
-    default:
-        break;
-    }
-    OMAP_BAD_REG(addr);
-    return 0;
-}
-
-static void omap_diss_write(void *opaque, hwaddr addr,
-                            uint64_t value, unsigned size)
-{
-    struct omap_dss_s *s = (struct omap_dss_s *) opaque;
-
-    if (size != 4) {
-        return omap_badwidth_write32(opaque, addr, value);
-    }
-
-    switch (addr) {
-    case 0x00: /* DSS_REVISIONNUMBER */
-    case 0x14: /* DSS_SYSSTATUS */
-    case 0x50: /* DSS_PSA_LCD_REG_1 */
-    case 0x54: /* DSS_PSA_LCD_REG_2 */
-    case 0x58: /* DSS_PSA_VIDEO_REG */
-    case 0x5c: /* DSS_STATUS */
-        OMAP_RO_REG(addr);
-        break;
-
-    case 0x10: /* DSS_SYSCONFIG */
-        if (value & 2)                                         /* SOFTRESET */
-            omap_dss_reset(s);
-        s->autoidle = value & 1;
-        break;
-
-    case 0x40: /* DSS_CONTROL */
-        s->control = value & 0x3dd;
-        break;
-
-    default:
-        OMAP_BAD_REG(addr);
-    }
-}
-
-static const MemoryRegionOps omap_diss_ops = {
-    .read = omap_diss_read,
-    .write = omap_diss_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static uint64_t omap_disc_read(void *opaque, hwaddr addr,
-                               unsigned size)
-{
-    struct omap_dss_s *s = (struct omap_dss_s *) opaque;
-
-    if (size != 4) {
-        return omap_badwidth_read32(opaque, addr);
-    }
-
-    switch (addr) {
-    case 0x000:        /* DISPC_REVISION */
-        return 0x20;
-
-    case 0x010:        /* DISPC_SYSCONFIG */
-        return s->dispc.idlemode;
-
-    case 0x014:        /* DISPC_SYSSTATUS */
-        return 1;                                              /* RESETDONE */
-
-    case 0x018:        /* DISPC_IRQSTATUS */
-        return s->dispc.irqst;
-
-    case 0x01c:        /* DISPC_IRQENABLE */
-        return s->dispc.irqen;
-
-    case 0x040:        /* DISPC_CONTROL */
-        return s->dispc.control;
-
-    case 0x044:        /* DISPC_CONFIG */
-        return s->dispc.config;
-
-    case 0x048:        /* DISPC_CAPABLE */
-        return s->dispc.capable;
-
-    case 0x04c:        /* DISPC_DEFAULT_COLOR0 */
-        return s->dispc.bg[0];
-    case 0x050:        /* DISPC_DEFAULT_COLOR1 */
-        return s->dispc.bg[1];
-    case 0x054:        /* DISPC_TRANS_COLOR0 */
-        return s->dispc.trans[0];
-    case 0x058:        /* DISPC_TRANS_COLOR1 */
-        return s->dispc.trans[1];
-
-    case 0x05c:        /* DISPC_LINE_STATUS */
-        return 0x7ff;
-    case 0x060:        /* DISPC_LINE_NUMBER */
-        return s->dispc.line;
-
-    case 0x064:        /* DISPC_TIMING_H */
-        return s->dispc.timing[0];
-    case 0x068:        /* DISPC_TIMING_V */
-        return s->dispc.timing[1];
-    case 0x06c:        /* DISPC_POL_FREQ */
-        return s->dispc.timing[2];
-    case 0x070:        /* DISPC_DIVISOR */
-        return s->dispc.timing[3];
-
-    case 0x078:        /* DISPC_SIZE_DIG */
-        return ((s->dig.ny - 1) << 16) | (s->dig.nx - 1);
-    case 0x07c:        /* DISPC_SIZE_LCD */
-        return ((s->lcd.ny - 1) << 16) | (s->lcd.nx - 1);
-
-    case 0x080:        /* DISPC_GFX_BA0 */
-        return s->dispc.l[0].addr[0];
-    case 0x084:        /* DISPC_GFX_BA1 */
-        return s->dispc.l[0].addr[1];
-    case 0x088:        /* DISPC_GFX_POSITION */
-        return (s->dispc.l[0].posy << 16) | s->dispc.l[0].posx;
-    case 0x08c:        /* DISPC_GFX_SIZE */
-        return ((s->dispc.l[0].ny - 1) << 16) | (s->dispc.l[0].nx - 1);
-    case 0x0a0:        /* DISPC_GFX_ATTRIBUTES */
-        return s->dispc.l[0].attr;
-    case 0x0a4:        /* DISPC_GFX_FIFO_TRESHOLD */
-        return s->dispc.l[0].tresh;
-    case 0x0a8:        /* DISPC_GFX_FIFO_SIZE_STATUS */
-        return 256;
-    case 0x0ac:        /* DISPC_GFX_ROW_INC */
-        return s->dispc.l[0].rowinc;
-    case 0x0b0:        /* DISPC_GFX_PIXEL_INC */
-        return s->dispc.l[0].colinc;
-    case 0x0b4:        /* DISPC_GFX_WINDOW_SKIP */
-        return s->dispc.l[0].wininc;
-    case 0x0b8:        /* DISPC_GFX_TABLE_BA */
-        return s->dispc.l[0].addr[2];
-
-    case 0x0bc:        /* DISPC_VID1_BA0 */
-    case 0x0c0:        /* DISPC_VID1_BA1 */
-    case 0x0c4:        /* DISPC_VID1_POSITION */
-    case 0x0c8:        /* DISPC_VID1_SIZE */
-    case 0x0cc:        /* DISPC_VID1_ATTRIBUTES */
-    case 0x0d0:        /* DISPC_VID1_FIFO_TRESHOLD */
-    case 0x0d4:        /* DISPC_VID1_FIFO_SIZE_STATUS */
-    case 0x0d8:        /* DISPC_VID1_ROW_INC */
-    case 0x0dc:        /* DISPC_VID1_PIXEL_INC */
-    case 0x0e0:        /* DISPC_VID1_FIR */
-    case 0x0e4:        /* DISPC_VID1_PICTURE_SIZE */
-    case 0x0e8:        /* DISPC_VID1_ACCU0 */
-    case 0x0ec:        /* DISPC_VID1_ACCU1 */
-    case 0x0f0 ... 0x140:      /* DISPC_VID1_FIR_COEF, DISPC_VID1_CONV_COEF */
-    case 0x14c:        /* DISPC_VID2_BA0 */
-    case 0x150:        /* DISPC_VID2_BA1 */
-    case 0x154:        /* DISPC_VID2_POSITION */
-    case 0x158:        /* DISPC_VID2_SIZE */
-    case 0x15c:        /* DISPC_VID2_ATTRIBUTES */
-    case 0x160:        /* DISPC_VID2_FIFO_TRESHOLD */
-    case 0x164:        /* DISPC_VID2_FIFO_SIZE_STATUS */
-    case 0x168:        /* DISPC_VID2_ROW_INC */
-    case 0x16c:        /* DISPC_VID2_PIXEL_INC */
-    case 0x170:        /* DISPC_VID2_FIR */
-    case 0x174:        /* DISPC_VID2_PICTURE_SIZE */
-    case 0x178:        /* DISPC_VID2_ACCU0 */
-    case 0x17c:        /* DISPC_VID2_ACCU1 */
-    case 0x180 ... 0x1d0:      /* DISPC_VID2_FIR_COEF, DISPC_VID2_CONV_COEF */
-    case 0x1d4:        /* DISPC_DATA_CYCLE1 */
-    case 0x1d8:        /* DISPC_DATA_CYCLE2 */
-    case 0x1dc:        /* DISPC_DATA_CYCLE3 */
-        return 0;
-
-    default:
-        break;
-    }
-    OMAP_BAD_REG(addr);
-    return 0;
-}
-
-static void omap_disc_write(void *opaque, hwaddr addr,
-                            uint64_t value, unsigned size)
-{
-    struct omap_dss_s *s = (struct omap_dss_s *) opaque;
-
-    if (size != 4) {
-        return omap_badwidth_write32(opaque, addr, value);
-    }
-
-    switch (addr) {
-    case 0x010:        /* DISPC_SYSCONFIG */
-        if (value & 2)                                         /* SOFTRESET */
-            omap_dss_reset(s);
-        s->dispc.idlemode = value & 0x301b;
-        break;
-
-    case 0x018:        /* DISPC_IRQSTATUS */
-        s->dispc.irqst &= ~value;
-        omap_dispc_interrupt_update(s);
-        break;
-
-    case 0x01c:        /* DISPC_IRQENABLE */
-        s->dispc.irqen = value & 0xffff;
-        omap_dispc_interrupt_update(s);
-        break;
-
-    case 0x040:        /* DISPC_CONTROL */
-        s->dispc.control = value & 0x07ff9fff;
-        s->dig.enable = (value >> 1) & 1;
-        s->lcd.enable = (value >> 0) & 1;
-        if (value & (1 << 12))                 /* OVERLAY_OPTIMIZATION */
-            if (!((s->dispc.l[1].attr | s->dispc.l[2].attr) & 1)) {
-                fprintf(stderr, "%s: Overlay Optimization when no overlay "
-                        "region effectively exists leads to "
-                        "unpredictable behaviour!\n", __func__);
-            }
-        if (value & (1 << 6)) {                                /* GODIGITAL */
-            /* XXX: Shadowed fields are:
-             * s->dispc.config
-             * s->dispc.capable
-             * s->dispc.bg[0]
-             * s->dispc.bg[1]
-             * s->dispc.trans[0]
-             * s->dispc.trans[1]
-             * s->dispc.line
-             * s->dispc.timing[0]
-             * s->dispc.timing[1]
-             * s->dispc.timing[2]
-             * s->dispc.timing[3]
-             * s->lcd.nx
-             * s->lcd.ny
-             * s->dig.nx
-             * s->dig.ny
-             * s->dispc.l[0].addr[0]
-             * s->dispc.l[0].addr[1]
-             * s->dispc.l[0].addr[2]
-             * s->dispc.l[0].posx
-             * s->dispc.l[0].posy
-             * s->dispc.l[0].nx
-             * s->dispc.l[0].ny
-             * s->dispc.l[0].tresh
-             * s->dispc.l[0].rowinc
-             * s->dispc.l[0].colinc
-             * s->dispc.l[0].wininc
-             * All they need to be loaded here from their shadow registers.
-             */
-        }
-        if (value & (1 << 5)) {                                /* GOLCD */
-             /* XXX: Likewise for LCD here.  */
-        }
-        s->dispc.invalidate = 1;
-        break;
-
-    case 0x044:        /* DISPC_CONFIG */
-        s->dispc.config = value & 0x3fff;
-        /* XXX:
-         * bits 2:1 (LOADMODE) reset to 0 after set to 1 and palette loaded
-         * bits 2:1 (LOADMODE) reset to 2 after set to 3 and palette loaded
-         */
-        s->dispc.invalidate = 1;
-        break;
-
-    case 0x048:        /* DISPC_CAPABLE */
-        s->dispc.capable = value & 0x3ff;
-        break;
-
-    case 0x04c:        /* DISPC_DEFAULT_COLOR0 */
-        s->dispc.bg[0] = value & 0xffffff;
-        s->dispc.invalidate = 1;
-        break;
-    case 0x050:        /* DISPC_DEFAULT_COLOR1 */
-        s->dispc.bg[1] = value & 0xffffff;
-        s->dispc.invalidate = 1;
-        break;
-    case 0x054:        /* DISPC_TRANS_COLOR0 */
-        s->dispc.trans[0] = value & 0xffffff;
-        s->dispc.invalidate = 1;
-        break;
-    case 0x058:        /* DISPC_TRANS_COLOR1 */
-        s->dispc.trans[1] = value & 0xffffff;
-        s->dispc.invalidate = 1;
-        break;
-
-    case 0x060:        /* DISPC_LINE_NUMBER */
-        s->dispc.line = value & 0x7ff;
-        break;
-
-    case 0x064:        /* DISPC_TIMING_H */
-        s->dispc.timing[0] = value & 0x0ff0ff3f;
-        break;
-    case 0x068:        /* DISPC_TIMING_V */
-        s->dispc.timing[1] = value & 0x0ff0ff3f;
-        break;
-    case 0x06c:        /* DISPC_POL_FREQ */
-        s->dispc.timing[2] = value & 0x0003ffff;
-        break;
-    case 0x070:        /* DISPC_DIVISOR */
-        s->dispc.timing[3] = value & 0x00ff00ff;
-        break;
-
-    case 0x078:        /* DISPC_SIZE_DIG */
-        s->dig.nx = ((value >>  0) & 0x7ff) + 1;               /* PPL */
-        s->dig.ny = ((value >> 16) & 0x7ff) + 1;               /* LPP */
-        s->dispc.invalidate = 1;
-        break;
-    case 0x07c:        /* DISPC_SIZE_LCD */
-        s->lcd.nx = ((value >>  0) & 0x7ff) + 1;               /* PPL */
-        s->lcd.ny = ((value >> 16) & 0x7ff) + 1;               /* LPP */
-        s->dispc.invalidate = 1;
-        break;
-    case 0x080:        /* DISPC_GFX_BA0 */
-        s->dispc.l[0].addr[0] = (hwaddr) value;
-        s->dispc.invalidate = 1;
-        break;
-    case 0x084:        /* DISPC_GFX_BA1 */
-        s->dispc.l[0].addr[1] = (hwaddr) value;
-        s->dispc.invalidate = 1;
-        break;
-    case 0x088:        /* DISPC_GFX_POSITION */
-        s->dispc.l[0].posx = ((value >>  0) & 0x7ff);          /* GFXPOSX */
-        s->dispc.l[0].posy = ((value >> 16) & 0x7ff);          /* GFXPOSY */
-        s->dispc.invalidate = 1;
-        break;
-    case 0x08c:        /* DISPC_GFX_SIZE */
-        s->dispc.l[0].nx = ((value >>  0) & 0x7ff) + 1;                /* GFXSIZEX */
-        s->dispc.l[0].ny = ((value >> 16) & 0x7ff) + 1;                /* GFXSIZEY */
-        s->dispc.invalidate = 1;
-        break;
-    case 0x0a0:        /* DISPC_GFX_ATTRIBUTES */
-        s->dispc.l[0].attr = value & 0x7ff;
-        if (value & (3 << 9))
-            fprintf(stderr, "%s: Big-endian pixel format not supported\n",
-                            __FUNCTION__);
-        s->dispc.l[0].enable = value & 1;
-        s->dispc.l[0].bpp = (value >> 1) & 0xf;
-        s->dispc.invalidate = 1;
-        break;
-    case 0x0a4:        /* DISPC_GFX_FIFO_TRESHOLD */
-        s->dispc.l[0].tresh = value & 0x01ff01ff;
-        break;
-    case 0x0ac:        /* DISPC_GFX_ROW_INC */
-        s->dispc.l[0].rowinc = value;
-        s->dispc.invalidate = 1;
-        break;
-    case 0x0b0:        /* DISPC_GFX_PIXEL_INC */
-        s->dispc.l[0].colinc = value;
-        s->dispc.invalidate = 1;
-        break;
-    case 0x0b4:        /* DISPC_GFX_WINDOW_SKIP */
-        s->dispc.l[0].wininc = value;
-        break;
-    case 0x0b8:        /* DISPC_GFX_TABLE_BA */
-        s->dispc.l[0].addr[2] = (hwaddr) value;
-        s->dispc.invalidate = 1;
-        break;
-
-    case 0x0bc:        /* DISPC_VID1_BA0 */
-    case 0x0c0:        /* DISPC_VID1_BA1 */
-    case 0x0c4:        /* DISPC_VID1_POSITION */
-    case 0x0c8:        /* DISPC_VID1_SIZE */
-    case 0x0cc:        /* DISPC_VID1_ATTRIBUTES */
-    case 0x0d0:        /* DISPC_VID1_FIFO_TRESHOLD */
-    case 0x0d8:        /* DISPC_VID1_ROW_INC */
-    case 0x0dc:        /* DISPC_VID1_PIXEL_INC */
-    case 0x0e0:        /* DISPC_VID1_FIR */
-    case 0x0e4:        /* DISPC_VID1_PICTURE_SIZE */
-    case 0x0e8:        /* DISPC_VID1_ACCU0 */
-    case 0x0ec:        /* DISPC_VID1_ACCU1 */
-    case 0x0f0 ... 0x140:      /* DISPC_VID1_FIR_COEF, DISPC_VID1_CONV_COEF */
-    case 0x14c:        /* DISPC_VID2_BA0 */
-    case 0x150:        /* DISPC_VID2_BA1 */
-    case 0x154:        /* DISPC_VID2_POSITION */
-    case 0x158:        /* DISPC_VID2_SIZE */
-    case 0x15c:        /* DISPC_VID2_ATTRIBUTES */
-    case 0x160:        /* DISPC_VID2_FIFO_TRESHOLD */
-    case 0x168:        /* DISPC_VID2_ROW_INC */
-    case 0x16c:        /* DISPC_VID2_PIXEL_INC */
-    case 0x170:        /* DISPC_VID2_FIR */
-    case 0x174:        /* DISPC_VID2_PICTURE_SIZE */
-    case 0x178:        /* DISPC_VID2_ACCU0 */
-    case 0x17c:        /* DISPC_VID2_ACCU1 */
-    case 0x180 ... 0x1d0:      /* DISPC_VID2_FIR_COEF, DISPC_VID2_CONV_COEF */
-    case 0x1d4:        /* DISPC_DATA_CYCLE1 */
-    case 0x1d8:        /* DISPC_DATA_CYCLE2 */
-    case 0x1dc:        /* DISPC_DATA_CYCLE3 */
-        break;
-
-    default:
-        OMAP_BAD_REG(addr);
-    }
-}
-
-static const MemoryRegionOps omap_disc_ops = {
-    .read = omap_disc_read,
-    .write = omap_disc_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void omap_rfbi_transfer_stop(struct omap_dss_s *s)
-{
-    if (!s->rfbi.busy)
-        return;
-
-    /* TODO: in non-Bypass mode we probably need to just deassert the DRQ.  */
-
-    s->rfbi.busy = 0;
-}
-
-static void omap_rfbi_transfer_start(struct omap_dss_s *s)
-{
-    void *data;
-    hwaddr len;
-    hwaddr data_addr;
-    int pitch;
-    static void *bounce_buffer;
-    static hwaddr bounce_len;
-
-    if (!s->rfbi.enable || s->rfbi.busy)
-        return;
-
-    if (s->rfbi.control & (1 << 1)) {                          /* BYPASS */
-        /* TODO: in non-Bypass mode we probably need to just assert the
-         * DRQ and wait for DMA to write the pixels.  */
-        fprintf(stderr, "%s: Bypass mode unimplemented\n", __FUNCTION__);
-        return;
-    }
-
-    if (!(s->dispc.control & (1 << 11)))                       /* RFBIMODE */
-        return;
-    /* TODO: check that LCD output is enabled in DISPC.  */
-
-    s->rfbi.busy = 1;
-
-    len = s->rfbi.pixels * 2;
-
-    data_addr = s->dispc.l[0].addr[0];
-    data = cpu_physical_memory_map(data_addr, &len, 0);
-    if (data && len != s->rfbi.pixels * 2) {
-        cpu_physical_memory_unmap(data, len, 0, 0);
-        data = NULL;
-        len = s->rfbi.pixels * 2;
-    }
-    if (!data) {
-        if (len > bounce_len) {
-            bounce_buffer = g_realloc(bounce_buffer, len);
-        }
-        data = bounce_buffer;
-        cpu_physical_memory_read(data_addr, data, len);
-    }
-
-    /* TODO bpp */
-    s->rfbi.pixels = 0;
-
-    /* TODO: negative values */
-    pitch = s->dispc.l[0].nx + (s->dispc.l[0].rowinc - 1) / 2;
-
-    if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0])
-        s->rfbi.chip[0]->block(s->rfbi.chip[0]->opaque, 1, data, len, pitch);
-    if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1])
-        s->rfbi.chip[1]->block(s->rfbi.chip[1]->opaque, 1, data, len, pitch);
-
-    if (data != bounce_buffer) {
-        cpu_physical_memory_unmap(data, len, 0, len);
-    }
-
-    omap_rfbi_transfer_stop(s);
-
-    /* TODO */
-    s->dispc.irqst |= 1;                                       /* FRAMEDONE */
-    omap_dispc_interrupt_update(s);
-}
-
-static uint64_t omap_rfbi_read(void *opaque, hwaddr addr,
-                               unsigned size)
-{
-    struct omap_dss_s *s = (struct omap_dss_s *) opaque;
-
-    if (size != 4) {
-        return omap_badwidth_read32(opaque, addr);
-    }
-
-    switch (addr) {
-    case 0x00: /* RFBI_REVISION */
-        return 0x10;
-
-    case 0x10: /* RFBI_SYSCONFIG */
-        return s->rfbi.idlemode;
-
-    case 0x14: /* RFBI_SYSSTATUS */
-        return 1 | (s->rfbi.busy << 8);                                /* RESETDONE */
-
-    case 0x40: /* RFBI_CONTROL */
-        return s->rfbi.control;
-
-    case 0x44: /* RFBI_PIXELCNT */
-        return s->rfbi.pixels;
-
-    case 0x48: /* RFBI_LINE_NUMBER */
-        return s->rfbi.skiplines;
-
-    case 0x58: /* RFBI_READ */
-    case 0x5c: /* RFBI_STATUS */
-        return s->rfbi.rxbuf;
-
-    case 0x60: /* RFBI_CONFIG0 */
-        return s->rfbi.config[0];
-    case 0x64: /* RFBI_ONOFF_TIME0 */
-        return s->rfbi.time[0];
-    case 0x68: /* RFBI_CYCLE_TIME0 */
-        return s->rfbi.time[1];
-    case 0x6c: /* RFBI_DATA_CYCLE1_0 */
-        return s->rfbi.data[0];
-    case 0x70: /* RFBI_DATA_CYCLE2_0 */
-        return s->rfbi.data[1];
-    case 0x74: /* RFBI_DATA_CYCLE3_0 */
-        return s->rfbi.data[2];
-
-    case 0x78: /* RFBI_CONFIG1 */
-        return s->rfbi.config[1];
-    case 0x7c: /* RFBI_ONOFF_TIME1 */
-        return s->rfbi.time[2];
-    case 0x80: /* RFBI_CYCLE_TIME1 */
-        return s->rfbi.time[3];
-    case 0x84: /* RFBI_DATA_CYCLE1_1 */
-        return s->rfbi.data[3];
-    case 0x88: /* RFBI_DATA_CYCLE2_1 */
-        return s->rfbi.data[4];
-    case 0x8c: /* RFBI_DATA_CYCLE3_1 */
-        return s->rfbi.data[5];
-
-    case 0x90: /* RFBI_VSYNC_WIDTH */
-        return s->rfbi.vsync;
-    case 0x94: /* RFBI_HSYNC_WIDTH */
-        return s->rfbi.hsync;
-    }
-    OMAP_BAD_REG(addr);
-    return 0;
-}
-
-static void omap_rfbi_write(void *opaque, hwaddr addr,
-                            uint64_t value, unsigned size)
-{
-    struct omap_dss_s *s = (struct omap_dss_s *) opaque;
-
-    if (size != 4) {
-        return omap_badwidth_write32(opaque, addr, value);
-    }
-
-    switch (addr) {
-    case 0x10: /* RFBI_SYSCONFIG */
-        if (value & 2)                                         /* SOFTRESET */
-            omap_rfbi_reset(s);
-        s->rfbi.idlemode = value & 0x19;
-        break;
-
-    case 0x40: /* RFBI_CONTROL */
-        s->rfbi.control = value & 0xf;
-        s->rfbi.enable = value & 1;
-        if (value & (1 << 4) &&                                        /* ITE */
-                        !(s->rfbi.config[0] & s->rfbi.config[1] & 0xc))
-            omap_rfbi_transfer_start(s);
-        break;
-
-    case 0x44: /* RFBI_PIXELCNT */
-        s->rfbi.pixels = value;
-        break;
-
-    case 0x48: /* RFBI_LINE_NUMBER */
-        s->rfbi.skiplines = value & 0x7ff;
-        break;
-
-    case 0x4c: /* RFBI_CMD */
-        if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0])
-            s->rfbi.chip[0]->write(s->rfbi.chip[0]->opaque, 0, value & 0xffff);
-        if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1])
-            s->rfbi.chip[1]->write(s->rfbi.chip[1]->opaque, 0, value & 0xffff);
-        break;
-    case 0x50: /* RFBI_PARAM */
-        if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0])
-            s->rfbi.chip[0]->write(s->rfbi.chip[0]->opaque, 1, value & 0xffff);
-        if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1])
-            s->rfbi.chip[1]->write(s->rfbi.chip[1]->opaque, 1, value & 0xffff);
-        break;
-    case 0x54: /* RFBI_DATA */
-        /* TODO: take into account the format set up in s->rfbi.config[?] and
-         * s->rfbi.data[?], but special-case the most usual scenario so that
-         * speed doesn't suffer.  */
-        if ((s->rfbi.control & (1 << 2)) && s->rfbi.chip[0]) {
-            s->rfbi.chip[0]->write(s->rfbi.chip[0]->opaque, 1, value & 0xffff);
-            s->rfbi.chip[0]->write(s->rfbi.chip[0]->opaque, 1, value >> 16);
-        }
-        if ((s->rfbi.control & (1 << 3)) && s->rfbi.chip[1]) {
-            s->rfbi.chip[1]->write(s->rfbi.chip[1]->opaque, 1, value & 0xffff);
-            s->rfbi.chip[1]->write(s->rfbi.chip[1]->opaque, 1, value >> 16);
-        }
-        if (!-- s->rfbi.pixels)
-            omap_rfbi_transfer_stop(s);
-        break;
-    case 0x58: /* RFBI_READ */
-        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[1]->read(s->rfbi.chip[1]->opaque, 1);
-        if (!-- s->rfbi.pixels)
-            omap_rfbi_transfer_stop(s);
-        break;
-
-    case 0x5c: /* RFBI_STATUS */
-        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[1]->read(s->rfbi.chip[1]->opaque, 0);
-        if (!-- s->rfbi.pixels)
-            omap_rfbi_transfer_stop(s);
-        break;
-
-    case 0x60: /* RFBI_CONFIG0 */
-        s->rfbi.config[0] = value & 0x003f1fff;
-        break;
-
-    case 0x64: /* RFBI_ONOFF_TIME0 */
-        s->rfbi.time[0] = value & 0x3fffffff;
-        break;
-    case 0x68: /* RFBI_CYCLE_TIME0 */
-        s->rfbi.time[1] = value & 0x0fffffff;
-        break;
-    case 0x6c: /* RFBI_DATA_CYCLE1_0 */
-        s->rfbi.data[0] = value & 0x0f1f0f1f;
-        break;
-    case 0x70: /* RFBI_DATA_CYCLE2_0 */
-        s->rfbi.data[1] = value & 0x0f1f0f1f;
-        break;
-    case 0x74: /* RFBI_DATA_CYCLE3_0 */
-        s->rfbi.data[2] = value & 0x0f1f0f1f;
-        break;
-    case 0x78: /* RFBI_CONFIG1 */
-        s->rfbi.config[1] = value & 0x003f1fff;
-        break;
-
-    case 0x7c: /* RFBI_ONOFF_TIME1 */
-        s->rfbi.time[2] = value & 0x3fffffff;
-        break;
-    case 0x80: /* RFBI_CYCLE_TIME1 */
-        s->rfbi.time[3] = value & 0x0fffffff;
-        break;
-    case 0x84: /* RFBI_DATA_CYCLE1_1 */
-        s->rfbi.data[3] = value & 0x0f1f0f1f;
-        break;
-    case 0x88: /* RFBI_DATA_CYCLE2_1 */
-        s->rfbi.data[4] = value & 0x0f1f0f1f;
-        break;
-    case 0x8c: /* RFBI_DATA_CYCLE3_1 */
-        s->rfbi.data[5] = value & 0x0f1f0f1f;
-        break;
-
-    case 0x90: /* RFBI_VSYNC_WIDTH */
-        s->rfbi.vsync = value & 0xffff;
-        break;
-    case 0x94: /* RFBI_HSYNC_WIDTH */
-        s->rfbi.hsync = value & 0xffff;
-        break;
-
-    default:
-        OMAP_BAD_REG(addr);
-    }
-}
-
-static const MemoryRegionOps omap_rfbi_ops = {
-    .read = omap_rfbi_read,
-    .write = omap_rfbi_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static uint64_t omap_venc_read(void *opaque, hwaddr addr,
-                               unsigned size)
-{
-    if (size != 4) {
-        return omap_badwidth_read32(opaque, addr);
-    }
-
-    switch (addr) {
-    case 0x00: /* REV_ID */
-    case 0x04: /* STATUS */
-    case 0x08: /* F_CONTROL */
-    case 0x10: /* VIDOUT_CTRL */
-    case 0x14: /* SYNC_CTRL */
-    case 0x1c: /* LLEN */
-    case 0x20: /* FLENS */
-    case 0x24: /* HFLTR_CTRL */
-    case 0x28: /* CC_CARR_WSS_CARR */
-    case 0x2c: /* C_PHASE */
-    case 0x30: /* GAIN_U */
-    case 0x34: /* GAIN_V */
-    case 0x38: /* GAIN_Y */
-    case 0x3c: /* BLACK_LEVEL */
-    case 0x40: /* BLANK_LEVEL */
-    case 0x44: /* X_COLOR */
-    case 0x48: /* M_CONTROL */
-    case 0x4c: /* BSTAMP_WSS_DATA */
-    case 0x50: /* S_CARR */
-    case 0x54: /* LINE21 */
-    case 0x58: /* LN_SEL */
-    case 0x5c: /* L21__WC_CTL */
-    case 0x60: /* HTRIGGER_VTRIGGER */
-    case 0x64: /* SAVID__EAVID */
-    case 0x68: /* FLEN__FAL */
-    case 0x6c: /* LAL__PHASE_RESET */
-    case 0x70: /* HS_INT_START_STOP_X */
-    case 0x74: /* HS_EXT_START_STOP_X */
-    case 0x78: /* VS_INT_START_X */
-    case 0x7c: /* VS_INT_STOP_X__VS_INT_START_Y */
-    case 0x80: /* VS_INT_STOP_Y__VS_INT_START_X */
-    case 0x84: /* VS_EXT_STOP_X__VS_EXT_START_Y */
-    case 0x88: /* VS_EXT_STOP_Y */
-    case 0x90: /* AVID_START_STOP_X */
-    case 0x94: /* AVID_START_STOP_Y */
-    case 0xa0: /* FID_INT_START_X__FID_INT_START_Y */
-    case 0xa4: /* FID_INT_OFFSET_Y__FID_EXT_START_X */
-    case 0xa8: /* FID_EXT_START_Y__FID_EXT_OFFSET_Y */
-    case 0xb0: /* TVDETGP_INT_START_STOP_X */
-    case 0xb4: /* TVDETGP_INT_START_STOP_Y */
-    case 0xb8: /* GEN_CTRL */
-    case 0xc4: /* DAC_TST__DAC_A */
-    case 0xc8: /* DAC_B__DAC_C */
-        return 0;
-
-    default:
-        break;
-    }
-    OMAP_BAD_REG(addr);
-    return 0;
-}
-
-static void omap_venc_write(void *opaque, hwaddr addr,
-                            uint64_t value, unsigned size)
-{
-    if (size != 4) {
-        return omap_badwidth_write32(opaque, addr, size);
-    }
-
-    switch (addr) {
-    case 0x08: /* F_CONTROL */
-    case 0x10: /* VIDOUT_CTRL */
-    case 0x14: /* SYNC_CTRL */
-    case 0x1c: /* LLEN */
-    case 0x20: /* FLENS */
-    case 0x24: /* HFLTR_CTRL */
-    case 0x28: /* CC_CARR_WSS_CARR */
-    case 0x2c: /* C_PHASE */
-    case 0x30: /* GAIN_U */
-    case 0x34: /* GAIN_V */
-    case 0x38: /* GAIN_Y */
-    case 0x3c: /* BLACK_LEVEL */
-    case 0x40: /* BLANK_LEVEL */
-    case 0x44: /* X_COLOR */
-    case 0x48: /* M_CONTROL */
-    case 0x4c: /* BSTAMP_WSS_DATA */
-    case 0x50: /* S_CARR */
-    case 0x54: /* LINE21 */
-    case 0x58: /* LN_SEL */
-    case 0x5c: /* L21__WC_CTL */
-    case 0x60: /* HTRIGGER_VTRIGGER */
-    case 0x64: /* SAVID__EAVID */
-    case 0x68: /* FLEN__FAL */
-    case 0x6c: /* LAL__PHASE_RESET */
-    case 0x70: /* HS_INT_START_STOP_X */
-    case 0x74: /* HS_EXT_START_STOP_X */
-    case 0x78: /* VS_INT_START_X */
-    case 0x7c: /* VS_INT_STOP_X__VS_INT_START_Y */
-    case 0x80: /* VS_INT_STOP_Y__VS_INT_START_X */
-    case 0x84: /* VS_EXT_STOP_X__VS_EXT_START_Y */
-    case 0x88: /* VS_EXT_STOP_Y */
-    case 0x90: /* AVID_START_STOP_X */
-    case 0x94: /* AVID_START_STOP_Y */
-    case 0xa0: /* FID_INT_START_X__FID_INT_START_Y */
-    case 0xa4: /* FID_INT_OFFSET_Y__FID_EXT_START_X */
-    case 0xa8: /* FID_EXT_START_Y__FID_EXT_OFFSET_Y */
-    case 0xb0: /* TVDETGP_INT_START_STOP_X */
-    case 0xb4: /* TVDETGP_INT_START_STOP_Y */
-    case 0xb8: /* GEN_CTRL */
-    case 0xc4: /* DAC_TST__DAC_A */
-    case 0xc8: /* DAC_B__DAC_C */
-        break;
-
-    default:
-        OMAP_BAD_REG(addr);
-    }
-}
-
-static const MemoryRegionOps omap_venc_ops = {
-    .read = omap_venc_read,
-    .write = omap_venc_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static uint64_t omap_im3_read(void *opaque, hwaddr addr,
-                              unsigned size)
-{
-    if (size != 4) {
-        return omap_badwidth_read32(opaque, addr);
-    }
-
-    switch (addr) {
-    case 0x0a8:        /* SBIMERRLOGA */
-    case 0x0b0:        /* SBIMERRLOG */
-    case 0x190:        /* SBIMSTATE */
-    case 0x198:        /* SBTMSTATE_L */
-    case 0x19c:        /* SBTMSTATE_H */
-    case 0x1a8:        /* SBIMCONFIG_L */
-    case 0x1ac:        /* SBIMCONFIG_H */
-    case 0x1f8:        /* SBID_L */
-    case 0x1fc:        /* SBID_H */
-        return 0;
-
-    default:
-        break;
-    }
-    OMAP_BAD_REG(addr);
-    return 0;
-}
-
-static void omap_im3_write(void *opaque, hwaddr addr,
-                           uint64_t value, unsigned size)
-{
-    if (size != 4) {
-        return omap_badwidth_write32(opaque, addr, value);
-    }
-
-    switch (addr) {
-    case 0x0b0:        /* SBIMERRLOG */
-    case 0x190:        /* SBIMSTATE */
-    case 0x198:        /* SBTMSTATE_L */
-    case 0x19c:        /* SBTMSTATE_H */
-    case 0x1a8:        /* SBIMCONFIG_L */
-    case 0x1ac:        /* SBIMCONFIG_H */
-        break;
-
-    default:
-        OMAP_BAD_REG(addr);
-    }
-}
-
-static const MemoryRegionOps omap_im3_ops = {
-    .read = omap_im3_read,
-    .write = omap_im3_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-struct omap_dss_s *omap_dss_init(struct omap_target_agent_s *ta,
-                MemoryRegion *sysmem,
-                hwaddr l3_base,
-                qemu_irq irq, qemu_irq drq,
-                omap_clk fck1, omap_clk fck2, omap_clk ck54m,
-                omap_clk ick1, omap_clk ick2)
-{
-    struct omap_dss_s *s = (struct omap_dss_s *)
-            g_malloc0(sizeof(struct omap_dss_s));
-
-    s->irq = irq;
-    s->drq = drq;
-    omap_dss_reset(s);
-
-    memory_region_init_io(&s->iomem_diss1, &omap_diss_ops, s, "omap.diss1",
-                          omap_l4_region_size(ta, 0));
-    memory_region_init_io(&s->iomem_disc1, &omap_disc_ops, s, "omap.disc1",
-                          omap_l4_region_size(ta, 1));
-    memory_region_init_io(&s->iomem_rfbi1, &omap_rfbi_ops, s, "omap.rfbi1",
-                          omap_l4_region_size(ta, 2));
-    memory_region_init_io(&s->iomem_venc1, &omap_venc_ops, s, "omap.venc1",
-                          omap_l4_region_size(ta, 3));
-    memory_region_init_io(&s->iomem_im3, &omap_im3_ops, s,
-                          "omap.im3", 0x1000);
-
-    omap_l4_attach(ta, 0, &s->iomem_diss1);
-    omap_l4_attach(ta, 1, &s->iomem_disc1);
-    omap_l4_attach(ta, 2, &s->iomem_rfbi1);
-    omap_l4_attach(ta, 3, &s->iomem_venc1);
-    memory_region_add_subregion(sysmem, l3_base, &s->iomem_im3);
-
-#if 0
-    s->state = graphic_console_init(omap_update_display,
-                                    omap_invalidate_display, omap_screen_dump, s);
-#endif
-
-    return s;
-}
-
-void omap_rfbi_attach(struct omap_dss_s *s, int cs, struct rfbi_chip_s *chip)
-{
-    if (cs < 0 || cs > 1)
-        hw_error("%s: wrong CS %i\n", __FUNCTION__, cs);
-    s->rfbi.chip[cs] = chip;
-}
diff --git a/hw/omap_gpio.c b/hw/omap_gpio.c
deleted file mode 100644 (file)
index c79f61c..0000000
+++ /dev/null
@@ -1,792 +0,0 @@
-/*
- * TI OMAP processors GPIO emulation.
- *
- * Copyright (C) 2006-2008 Andrzej Zaborowski  <balrog@zabor.org>
- * Copyright (C) 2007-2009 Nokia Corporation
- *
- * 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 or
- * (at your option) version 3 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
- * 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 "hw/hw.h"
-#include "hw/omap.h"
-#include "hw/sysbus.h"
-
-struct omap_gpio_s {
-    qemu_irq irq;
-    qemu_irq handler[16];
-
-    uint16_t inputs;
-    uint16_t outputs;
-    uint16_t dir;
-    uint16_t edge;
-    uint16_t mask;
-    uint16_t ints;
-    uint16_t pins;
-};
-
-struct omap_gpif_s {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-    int mpu_model;
-    void *clk;
-    struct omap_gpio_s omap1;
-};
-
-/* General-Purpose I/O of OMAP1 */
-static void omap_gpio_set(void *opaque, int line, int level)
-{
-    struct omap_gpio_s *s = &((struct omap_gpif_s *) opaque)->omap1;
-    uint16_t prev = s->inputs;
-
-    if (level)
-        s->inputs |= 1 << line;
-    else
-        s->inputs &= ~(1 << line);
-
-    if (((s->edge & s->inputs & ~prev) | (~s->edge & ~s->inputs & prev)) &
-                    (1 << line) & s->dir & ~s->mask) {
-        s->ints |= 1 << line;
-        qemu_irq_raise(s->irq);
-    }
-}
-
-static uint64_t omap_gpio_read(void *opaque, hwaddr addr,
-                               unsigned size)
-{
-    struct omap_gpio_s *s = (struct omap_gpio_s *) opaque;
-    int offset = addr & OMAP_MPUI_REG_MASK;
-
-    if (size != 2) {
-        return omap_badwidth_read16(opaque, addr);
-    }
-
-    switch (offset) {
-    case 0x00: /* DATA_INPUT */
-        return s->inputs & s->pins;
-
-    case 0x04: /* DATA_OUTPUT */
-        return s->outputs;
-
-    case 0x08: /* DIRECTION_CONTROL */
-        return s->dir;
-
-    case 0x0c: /* INTERRUPT_CONTROL */
-        return s->edge;
-
-    case 0x10: /* INTERRUPT_MASK */
-        return s->mask;
-
-    case 0x14: /* INTERRUPT_STATUS */
-        return s->ints;
-
-    case 0x18: /* PIN_CONTROL (not in OMAP310) */
-        OMAP_BAD_REG(addr);
-        return s->pins;
-    }
-
-    OMAP_BAD_REG(addr);
-    return 0;
-}
-
-static void omap_gpio_write(void *opaque, hwaddr addr,
-                            uint64_t value, unsigned size)
-{
-    struct omap_gpio_s *s = (struct omap_gpio_s *) opaque;
-    int offset = addr & OMAP_MPUI_REG_MASK;
-    uint16_t diff;
-    int ln;
-
-    if (size != 2) {
-        return omap_badwidth_write16(opaque, addr, value);
-    }
-
-    switch (offset) {
-    case 0x00: /* DATA_INPUT */
-        OMAP_RO_REG(addr);
-        return;
-
-    case 0x04: /* DATA_OUTPUT */
-        diff = (s->outputs ^ value) & ~s->dir;
-        s->outputs = value;
-        while ((ln = ffs(diff))) {
-            ln --;
-            if (s->handler[ln])
-                qemu_set_irq(s->handler[ln], (value >> ln) & 1);
-            diff &= ~(1 << ln);
-        }
-        break;
-
-    case 0x08: /* DIRECTION_CONTROL */
-        diff = s->outputs & (s->dir ^ value);
-        s->dir = value;
-
-        value = s->outputs & ~s->dir;
-        while ((ln = ffs(diff))) {
-            ln --;
-            if (s->handler[ln])
-                qemu_set_irq(s->handler[ln], (value >> ln) & 1);
-            diff &= ~(1 << ln);
-        }
-        break;
-
-    case 0x0c: /* INTERRUPT_CONTROL */
-        s->edge = value;
-        break;
-
-    case 0x10: /* INTERRUPT_MASK */
-        s->mask = value;
-        break;
-
-    case 0x14: /* INTERRUPT_STATUS */
-        s->ints &= ~value;
-        if (!s->ints)
-            qemu_irq_lower(s->irq);
-        break;
-
-    case 0x18: /* PIN_CONTROL (not in OMAP310 TRM) */
-        OMAP_BAD_REG(addr);
-        s->pins = value;
-        break;
-
-    default:
-        OMAP_BAD_REG(addr);
-        return;
-    }
-}
-
-/* *Some* sources say the memory region is 32-bit.  */
-static const MemoryRegionOps omap_gpio_ops = {
-    .read = omap_gpio_read,
-    .write = omap_gpio_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void omap_gpio_reset(struct omap_gpio_s *s)
-{
-    s->inputs = 0;
-    s->outputs = ~0;
-    s->dir = ~0;
-    s->edge = ~0;
-    s->mask = ~0;
-    s->ints = 0;
-    s->pins = ~0;
-}
-
-struct omap2_gpio_s {
-    qemu_irq irq[2];
-    qemu_irq wkup;
-    qemu_irq *handler;
-    MemoryRegion iomem;
-
-    uint8_t revision;
-    uint8_t config[2];
-    uint32_t inputs;
-    uint32_t outputs;
-    uint32_t dir;
-    uint32_t level[2];
-    uint32_t edge[2];
-    uint32_t mask[2];
-    uint32_t wumask;
-    uint32_t ints[2];
-    uint32_t debounce;
-    uint8_t delay;
-};
-
-struct omap2_gpif_s {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-    int mpu_model;
-    void *iclk;
-    void *fclk[6];
-    int modulecount;
-    struct omap2_gpio_s *modules;
-    qemu_irq *handler;
-    int autoidle;
-    int gpo;
-};
-
-/* General-Purpose Interface of OMAP2/3 */
-static inline void omap2_gpio_module_int_update(struct omap2_gpio_s *s,
-                                                int line)
-{
-    qemu_set_irq(s->irq[line], s->ints[line] & s->mask[line]);
-}
-
-static void omap2_gpio_module_wake(struct omap2_gpio_s *s, int line)
-{
-    if (!(s->config[0] & (1 << 2)))                    /* ENAWAKEUP */
-        return;
-    if (!(s->config[0] & (3 << 3)))                    /* Force Idle */
-        return;
-    if (!(s->wumask & (1 << line)))
-        return;
-
-    qemu_irq_raise(s->wkup);
-}
-
-static inline void omap2_gpio_module_out_update(struct omap2_gpio_s *s,
-                uint32_t diff)
-{
-    int ln;
-
-    s->outputs ^= diff;
-    diff &= ~s->dir;
-    while ((ln = ffs(diff))) {
-        ln --;
-        qemu_set_irq(s->handler[ln], (s->outputs >> ln) & 1);
-        diff &= ~(1 << ln);
-    }
-}
-
-static void omap2_gpio_module_level_update(struct omap2_gpio_s *s, int line)
-{
-    s->ints[line] |= s->dir &
-            ((s->inputs & s->level[1]) | (~s->inputs & s->level[0]));
-    omap2_gpio_module_int_update(s, line);
-}
-
-static inline void omap2_gpio_module_int(struct omap2_gpio_s *s, int line)
-{
-    s->ints[0] |= 1 << line;
-    omap2_gpio_module_int_update(s, 0);
-    s->ints[1] |= 1 << line;
-    omap2_gpio_module_int_update(s, 1);
-    omap2_gpio_module_wake(s, line);
-}
-
-static void omap2_gpio_set(void *opaque, int line, int level)
-{
-    struct omap2_gpif_s *p = opaque;
-    struct omap2_gpio_s *s = &p->modules[line >> 5];
-
-    line &= 31;
-    if (level) {
-        if (s->dir & (1 << line) & ((~s->inputs & s->edge[0]) | s->level[1]))
-            omap2_gpio_module_int(s, line);
-        s->inputs |= 1 << line;
-    } else {
-        if (s->dir & (1 << line) & ((s->inputs & s->edge[1]) | s->level[0]))
-            omap2_gpio_module_int(s, line);
-        s->inputs &= ~(1 << line);
-    }
-}
-
-static void omap2_gpio_module_reset(struct omap2_gpio_s *s)
-{
-    s->config[0] = 0;
-    s->config[1] = 2;
-    s->ints[0] = 0;
-    s->ints[1] = 0;
-    s->mask[0] = 0;
-    s->mask[1] = 0;
-    s->wumask = 0;
-    s->dir = ~0;
-    s->level[0] = 0;
-    s->level[1] = 0;
-    s->edge[0] = 0;
-    s->edge[1] = 0;
-    s->debounce = 0;
-    s->delay = 0;
-}
-
-static uint32_t omap2_gpio_module_read(void *opaque, hwaddr addr)
-{
-    struct omap2_gpio_s *s = (struct omap2_gpio_s *) opaque;
-
-    switch (addr) {
-    case 0x00: /* GPIO_REVISION */
-        return s->revision;
-
-    case 0x10: /* GPIO_SYSCONFIG */
-        return s->config[0];
-
-    case 0x14: /* GPIO_SYSSTATUS */
-        return 0x01;
-
-    case 0x18: /* GPIO_IRQSTATUS1 */
-        return s->ints[0];
-
-    case 0x1c: /* GPIO_IRQENABLE1 */
-    case 0x60: /* GPIO_CLEARIRQENABLE1 */
-    case 0x64: /* GPIO_SETIRQENABLE1 */
-        return s->mask[0];
-
-    case 0x20: /* GPIO_WAKEUPENABLE */
-    case 0x80: /* GPIO_CLEARWKUENA */
-    case 0x84: /* GPIO_SETWKUENA */
-        return s->wumask;
-
-    case 0x28: /* GPIO_IRQSTATUS2 */
-        return s->ints[1];
-
-    case 0x2c: /* GPIO_IRQENABLE2 */
-    case 0x70: /* GPIO_CLEARIRQENABLE2 */
-    case 0x74: /* GPIO_SETIREQNEABLE2 */
-        return s->mask[1];
-
-    case 0x30: /* GPIO_CTRL */
-        return s->config[1];
-
-    case 0x34: /* GPIO_OE */
-        return s->dir;
-
-    case 0x38: /* GPIO_DATAIN */
-        return s->inputs;
-
-    case 0x3c: /* GPIO_DATAOUT */
-    case 0x90: /* GPIO_CLEARDATAOUT */
-    case 0x94: /* GPIO_SETDATAOUT */
-        return s->outputs;
-
-    case 0x40: /* GPIO_LEVELDETECT0 */
-        return s->level[0];
-
-    case 0x44: /* GPIO_LEVELDETECT1 */
-        return s->level[1];
-
-    case 0x48: /* GPIO_RISINGDETECT */
-        return s->edge[0];
-
-    case 0x4c: /* GPIO_FALLINGDETECT */
-        return s->edge[1];
-
-    case 0x50: /* GPIO_DEBOUNCENABLE */
-        return s->debounce;
-
-    case 0x54: /* GPIO_DEBOUNCINGTIME */
-        return s->delay;
-    }
-
-    OMAP_BAD_REG(addr);
-    return 0;
-}
-
-static void omap2_gpio_module_write(void *opaque, hwaddr addr,
-                uint32_t value)
-{
-    struct omap2_gpio_s *s = (struct omap2_gpio_s *) opaque;
-    uint32_t diff;
-    int ln;
-
-    switch (addr) {
-    case 0x00: /* GPIO_REVISION */
-    case 0x14: /* GPIO_SYSSTATUS */
-    case 0x38: /* GPIO_DATAIN */
-        OMAP_RO_REG(addr);
-        break;
-
-    case 0x10: /* GPIO_SYSCONFIG */
-        if (((value >> 3) & 3) == 3)
-            fprintf(stderr, "%s: bad IDLEMODE value\n", __FUNCTION__);
-        if (value & 2)
-            omap2_gpio_module_reset(s);
-        s->config[0] = value & 0x1d;
-        break;
-
-    case 0x18: /* GPIO_IRQSTATUS1 */
-        if (s->ints[0] & value) {
-            s->ints[0] &= ~value;
-            omap2_gpio_module_level_update(s, 0);
-        }
-        break;
-
-    case 0x1c: /* GPIO_IRQENABLE1 */
-        s->mask[0] = value;
-        omap2_gpio_module_int_update(s, 0);
-        break;
-
-    case 0x20: /* GPIO_WAKEUPENABLE */
-        s->wumask = value;
-        break;
-
-    case 0x28: /* GPIO_IRQSTATUS2 */
-        if (s->ints[1] & value) {
-            s->ints[1] &= ~value;
-            omap2_gpio_module_level_update(s, 1);
-        }
-        break;
-
-    case 0x2c: /* GPIO_IRQENABLE2 */
-        s->mask[1] = value;
-        omap2_gpio_module_int_update(s, 1);
-        break;
-
-    case 0x30: /* GPIO_CTRL */
-        s->config[1] = value & 7;
-        break;
-
-    case 0x34: /* GPIO_OE */
-        diff = s->outputs & (s->dir ^ value);
-        s->dir = value;
-
-        value = s->outputs & ~s->dir;
-        while ((ln = ffs(diff))) {
-            diff &= ~(1 <<-- ln);
-            qemu_set_irq(s->handler[ln], (value >> ln) & 1);
-        }
-
-        omap2_gpio_module_level_update(s, 0);
-        omap2_gpio_module_level_update(s, 1);
-        break;
-
-    case 0x3c: /* GPIO_DATAOUT */
-        omap2_gpio_module_out_update(s, s->outputs ^ value);
-        break;
-
-    case 0x40: /* GPIO_LEVELDETECT0 */
-        s->level[0] = value;
-        omap2_gpio_module_level_update(s, 0);
-        omap2_gpio_module_level_update(s, 1);
-        break;
-
-    case 0x44: /* GPIO_LEVELDETECT1 */
-        s->level[1] = value;
-        omap2_gpio_module_level_update(s, 0);
-        omap2_gpio_module_level_update(s, 1);
-        break;
-
-    case 0x48: /* GPIO_RISINGDETECT */
-        s->edge[0] = value;
-        break;
-
-    case 0x4c: /* GPIO_FALLINGDETECT */
-        s->edge[1] = value;
-        break;
-
-    case 0x50: /* GPIO_DEBOUNCENABLE */
-        s->debounce = value;
-        break;
-
-    case 0x54: /* GPIO_DEBOUNCINGTIME */
-        s->delay = value;
-        break;
-
-    case 0x60: /* GPIO_CLEARIRQENABLE1 */
-        s->mask[0] &= ~value;
-        omap2_gpio_module_int_update(s, 0);
-        break;
-
-    case 0x64: /* GPIO_SETIRQENABLE1 */
-        s->mask[0] |= value;
-        omap2_gpio_module_int_update(s, 0);
-        break;
-
-    case 0x70: /* GPIO_CLEARIRQENABLE2 */
-        s->mask[1] &= ~value;
-        omap2_gpio_module_int_update(s, 1);
-        break;
-
-    case 0x74: /* GPIO_SETIREQNEABLE2 */
-        s->mask[1] |= value;
-        omap2_gpio_module_int_update(s, 1);
-        break;
-
-    case 0x80: /* GPIO_CLEARWKUENA */
-        s->wumask &= ~value;
-        break;
-
-    case 0x84: /* GPIO_SETWKUENA */
-        s->wumask |= value;
-        break;
-
-    case 0x90: /* GPIO_CLEARDATAOUT */
-        omap2_gpio_module_out_update(s, s->outputs & value);
-        break;
-
-    case 0x94: /* GPIO_SETDATAOUT */
-        omap2_gpio_module_out_update(s, ~s->outputs & value);
-        break;
-
-    default:
-        OMAP_BAD_REG(addr);
-        return;
-    }
-}
-
-static uint32_t omap2_gpio_module_readp(void *opaque, hwaddr addr)
-{
-    return omap2_gpio_module_read(opaque, addr & ~3) >> ((addr & 3) << 3);
-}
-
-static void omap2_gpio_module_writep(void *opaque, hwaddr addr,
-                uint32_t value)
-{
-    uint32_t cur = 0;
-    uint32_t mask = 0xffff;
-
-    switch (addr & ~3) {
-    case 0x00: /* GPIO_REVISION */
-    case 0x14: /* GPIO_SYSSTATUS */
-    case 0x38: /* GPIO_DATAIN */
-        OMAP_RO_REG(addr);
-        break;
-
-    case 0x10: /* GPIO_SYSCONFIG */
-    case 0x1c: /* GPIO_IRQENABLE1 */
-    case 0x20: /* GPIO_WAKEUPENABLE */
-    case 0x2c: /* GPIO_IRQENABLE2 */
-    case 0x30: /* GPIO_CTRL */
-    case 0x34: /* GPIO_OE */
-    case 0x3c: /* GPIO_DATAOUT */
-    case 0x40: /* GPIO_LEVELDETECT0 */
-    case 0x44: /* GPIO_LEVELDETECT1 */
-    case 0x48: /* GPIO_RISINGDETECT */
-    case 0x4c: /* GPIO_FALLINGDETECT */
-    case 0x50: /* GPIO_DEBOUNCENABLE */
-    case 0x54: /* GPIO_DEBOUNCINGTIME */
-        cur = omap2_gpio_module_read(opaque, addr & ~3) &
-                ~(mask << ((addr & 3) << 3));
-
-        /* Fall through.  */
-    case 0x18: /* GPIO_IRQSTATUS1 */
-    case 0x28: /* GPIO_IRQSTATUS2 */
-    case 0x60: /* GPIO_CLEARIRQENABLE1 */
-    case 0x64: /* GPIO_SETIRQENABLE1 */
-    case 0x70: /* GPIO_CLEARIRQENABLE2 */
-    case 0x74: /* GPIO_SETIREQNEABLE2 */
-    case 0x80: /* GPIO_CLEARWKUENA */
-    case 0x84: /* GPIO_SETWKUENA */
-    case 0x90: /* GPIO_CLEARDATAOUT */
-    case 0x94: /* GPIO_SETDATAOUT */
-        value <<= (addr & 3) << 3;
-        omap2_gpio_module_write(opaque, addr, cur | value);
-        break;
-
-    default:
-        OMAP_BAD_REG(addr);
-        return;
-    }
-}
-
-static const MemoryRegionOps omap2_gpio_module_ops = {
-    .old_mmio = {
-        .read = {
-            omap2_gpio_module_readp,
-            omap2_gpio_module_readp,
-            omap2_gpio_module_read,
-        },
-        .write = {
-            omap2_gpio_module_writep,
-            omap2_gpio_module_writep,
-            omap2_gpio_module_write,
-        },
-    },
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void omap_gpif_reset(DeviceState *dev)
-{
-    struct omap_gpif_s *s = FROM_SYSBUS(struct omap_gpif_s,
-                    SYS_BUS_DEVICE(dev));
-    omap_gpio_reset(&s->omap1);
-}
-
-static void omap2_gpif_reset(DeviceState *dev)
-{
-    int i;
-    struct omap2_gpif_s *s = FROM_SYSBUS(struct omap2_gpif_s,
-                    SYS_BUS_DEVICE(dev));
-    for (i = 0; i < s->modulecount; i++) {
-        omap2_gpio_module_reset(&s->modules[i]);
-    }
-    s->autoidle = 0;
-    s->gpo = 0;
-}
-
-static uint64_t omap2_gpif_top_read(void *opaque, hwaddr addr,
-                                    unsigned size)
-{
-    struct omap2_gpif_s *s = (struct omap2_gpif_s *) opaque;
-
-    switch (addr) {
-    case 0x00: /* IPGENERICOCPSPL_REVISION */
-        return 0x18;
-
-    case 0x10: /* IPGENERICOCPSPL_SYSCONFIG */
-        return s->autoidle;
-
-    case 0x14: /* IPGENERICOCPSPL_SYSSTATUS */
-        return 0x01;
-
-    case 0x18: /* IPGENERICOCPSPL_IRQSTATUS */
-        return 0x00;
-
-    case 0x40: /* IPGENERICOCPSPL_GPO */
-        return s->gpo;
-
-    case 0x50: /* IPGENERICOCPSPL_GPI */
-        return 0x00;
-    }
-
-    OMAP_BAD_REG(addr);
-    return 0;
-}
-
-static void omap2_gpif_top_write(void *opaque, hwaddr addr,
-                                 uint64_t value, unsigned size)
-{
-    struct omap2_gpif_s *s = (struct omap2_gpif_s *) opaque;
-
-    switch (addr) {
-    case 0x00: /* IPGENERICOCPSPL_REVISION */
-    case 0x14: /* IPGENERICOCPSPL_SYSSTATUS */
-    case 0x18: /* IPGENERICOCPSPL_IRQSTATUS */
-    case 0x50: /* IPGENERICOCPSPL_GPI */
-        OMAP_RO_REG(addr);
-        break;
-
-    case 0x10: /* IPGENERICOCPSPL_SYSCONFIG */
-        if (value & (1 << 1))                                  /* SOFTRESET */
-            omap2_gpif_reset(&s->busdev.qdev);
-        s->autoidle = value & 1;
-        break;
-
-    case 0x40: /* IPGENERICOCPSPL_GPO */
-        s->gpo = value & 1;
-        break;
-
-    default:
-        OMAP_BAD_REG(addr);
-        return;
-    }
-}
-
-static const MemoryRegionOps omap2_gpif_top_ops = {
-    .read = omap2_gpif_top_read,
-    .write = omap2_gpif_top_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int omap_gpio_init(SysBusDevice *dev)
-{
-    struct omap_gpif_s *s = FROM_SYSBUS(struct omap_gpif_s, dev);
-    if (!s->clk) {
-        hw_error("omap-gpio: clk not connected\n");
-    }
-    qdev_init_gpio_in(&dev->qdev, omap_gpio_set, 16);
-    qdev_init_gpio_out(&dev->qdev, s->omap1.handler, 16);
-    sysbus_init_irq(dev, &s->omap1.irq);
-    memory_region_init_io(&s->iomem, &omap_gpio_ops, &s->omap1,
-                          "omap.gpio", 0x1000);
-    sysbus_init_mmio(dev, &s->iomem);
-    return 0;
-}
-
-static int omap2_gpio_init(SysBusDevice *dev)
-{
-    int i;
-    struct omap2_gpif_s *s = FROM_SYSBUS(struct omap2_gpif_s, dev);
-    if (!s->iclk) {
-        hw_error("omap2-gpio: iclk not connected\n");
-    }
-    if (s->mpu_model < omap3430) {
-        s->modulecount = (s->mpu_model < omap2430) ? 4 : 5;
-        memory_region_init_io(&s->iomem, &omap2_gpif_top_ops, s,
-                              "omap2.gpio", 0x1000);
-        sysbus_init_mmio(dev, &s->iomem);
-    } else {
-        s->modulecount = 6;
-    }
-    s->modules = g_malloc0(s->modulecount * sizeof(struct omap2_gpio_s));
-    s->handler = g_malloc0(s->modulecount * 32 * sizeof(qemu_irq));
-    qdev_init_gpio_in(&dev->qdev, omap2_gpio_set, s->modulecount * 32);
-    qdev_init_gpio_out(&dev->qdev, s->handler, s->modulecount * 32);
-    for (i = 0; i < s->modulecount; i++) {
-        struct omap2_gpio_s *m = &s->modules[i];
-        if (!s->fclk[i]) {
-            hw_error("omap2-gpio: fclk%d not connected\n", i);
-        }
-        m->revision = (s->mpu_model < omap3430) ? 0x18 : 0x25;
-        m->handler = &s->handler[i * 32];
-        sysbus_init_irq(dev, &m->irq[0]); /* mpu irq */
-        sysbus_init_irq(dev, &m->irq[1]); /* dsp irq */
-        sysbus_init_irq(dev, &m->wkup);
-        memory_region_init_io(&m->iomem, &omap2_gpio_module_ops, m,
-                              "omap.gpio-module", 0x1000);
-        sysbus_init_mmio(dev, &m->iomem);
-    }
-    return 0;
-}
-
-/* Using qdev pointer properties for the clocks is not ideal.
- * qdev should support a generic means of defining a 'port' with
- * an arbitrary interface for connecting two devices. Then we
- * could reframe the omap clock API in terms of clock ports,
- * and get some type safety. For now the best qdev provides is
- * passing an arbitrary pointer.
- * (It's not possible to pass in the string which is the clock
- * name, because this device does not have the necessary information
- * (ie the struct omap_mpu_state_s*) to do the clockname to pointer
- * translation.)
- */
-
-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 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 const TypeInfo omap_gpio_info = {
-    .name          = "omap-gpio",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(struct omap_gpif_s),
-    .class_init    = omap_gpio_class_init,
-};
-
-static Property omap2_gpio_properties[] = {
-    DEFINE_PROP_INT32("mpu_model", struct omap2_gpif_s, mpu_model, 0),
-    DEFINE_PROP_PTR("iclk", struct omap2_gpif_s, iclk),
-    DEFINE_PROP_PTR("fclk0", struct omap2_gpif_s, fclk[0]),
-    DEFINE_PROP_PTR("fclk1", struct omap2_gpif_s, fclk[1]),
-    DEFINE_PROP_PTR("fclk2", struct omap2_gpif_s, fclk[2]),
-    DEFINE_PROP_PTR("fclk3", struct omap2_gpif_s, fclk[3]),
-    DEFINE_PROP_PTR("fclk4", struct omap2_gpif_s, fclk[4]),
-    DEFINE_PROP_PTR("fclk5", struct omap2_gpif_s, fclk[5]),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void omap2_gpio_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = omap2_gpio_init;
-    dc->reset = omap2_gpif_reset;
-    dc->props = omap2_gpio_properties;
-}
-
-static const 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_types(void)
-{
-    type_register_static(&omap_gpio_info);
-    type_register_static(&omap2_gpio_info);
-}
-
-type_init(omap_gpio_register_types)
diff --git a/hw/omap_gpmc.c b/hw/omap_gpmc.c
deleted file mode 100644 (file)
index ebb259c..0000000
+++ /dev/null
@@ -1,894 +0,0 @@
-/*
- * TI OMAP general purpose memory controller emulation.
- *
- * Copyright (C) 2007-2009 Nokia Corporation
- * Original code written by Andrzej Zaborowski <andrew@openedhand.com>
- * Enhancements for OMAP3 and NAND support written by Juha Riihimäki
- *
- * 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 or
- * (at your option) any later version 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
- * 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 "hw/hw.h"
-#include "hw/flash.h"
-#include "hw/omap.h"
-#include "exec/memory.h"
-#include "exec/address-spaces.h"
-
-/* General-Purpose Memory Controller */
-struct omap_gpmc_s {
-    qemu_irq irq;
-    qemu_irq drq;
-    MemoryRegion iomem;
-    int accept_256;
-
-    uint8_t revision;
-    uint8_t sysconfig;
-    uint16_t irqst;
-    uint16_t irqen;
-    uint16_t lastirq;
-    uint16_t timeout;
-    uint16_t config;
-    struct omap_gpmc_cs_file_s {
-        uint32_t config[7];
-        MemoryRegion *iomem;
-        MemoryRegion container;
-        MemoryRegion nandiomem;
-        DeviceState *dev;
-    } cs_file[8];
-    int ecc_cs;
-    int ecc_ptr;
-    uint32_t ecc_cfg;
-    ECCState ecc[9];
-    struct prefetch {
-        uint32_t config1; /* GPMC_PREFETCH_CONFIG1 */
-        uint32_t transfercount; /* GPMC_PREFETCH_CONFIG2:TRANSFERCOUNT */
-        int startengine; /* GPMC_PREFETCH_CONTROL:STARTENGINE */
-        int fifopointer; /* GPMC_PREFETCH_STATUS:FIFOPOINTER */
-        int count; /* GPMC_PREFETCH_STATUS:COUNTVALUE */
-        MemoryRegion iomem;
-        uint8_t fifo[64];
-    } prefetch;
-};
-
-#define OMAP_GPMC_8BIT 0
-#define OMAP_GPMC_16BIT 1
-#define OMAP_GPMC_NOR 0
-#define OMAP_GPMC_NAND 2
-
-static int omap_gpmc_devtype(struct omap_gpmc_cs_file_s *f)
-{
-    return (f->config[0] >> 10) & 3;
-}
-
-static int omap_gpmc_devsize(struct omap_gpmc_cs_file_s *f)
-{
-    /* devsize field is really 2 bits but we ignore the high
-     * bit to ensure consistent behaviour if the guest sets
-     * it (values 2 and 3 are reserved in the TRM)
-     */
-    return (f->config[0] >> 12) & 1;
-}
-
-/* Extract the chip-select value from the prefetch config1 register */
-static int prefetch_cs(uint32_t config1)
-{
-    return (config1 >> 24) & 7;
-}
-
-static int prefetch_threshold(uint32_t config1)
-{
-    return (config1 >> 8) & 0x7f;
-}
-
-static void omap_gpmc_int_update(struct omap_gpmc_s *s)
-{
-    /* The TRM is a bit unclear, but it seems to say that
-     * the TERMINALCOUNTSTATUS bit is set only on the
-     * transition when the prefetch engine goes from
-     * active to inactive, whereas the FIFOEVENTSTATUS
-     * bit is held high as long as the fifo has at
-     * least THRESHOLD bytes available.
-     * So we do the latter here, but TERMINALCOUNTSTATUS
-     * is set elsewhere.
-     */
-    if (s->prefetch.fifopointer >= prefetch_threshold(s->prefetch.config1)) {
-        s->irqst |= 1;
-    }
-    if ((s->irqen & s->irqst) != s->lastirq) {
-        s->lastirq = s->irqen & s->irqst;
-        qemu_set_irq(s->irq, s->lastirq);
-    }
-}
-
-static void omap_gpmc_dma_update(struct omap_gpmc_s *s, int value)
-{
-    if (s->prefetch.config1 & 4) {
-        qemu_set_irq(s->drq, value);
-    }
-}
-
-/* Access functions for when a NAND-like device is mapped into memory:
- * all addresses in the region behave like accesses to the relevant
- * GPMC_NAND_DATA_i register (which is actually implemented to call these)
- */
-static uint64_t omap_nand_read(void *opaque, hwaddr addr,
-                               unsigned size)
-{
-    struct omap_gpmc_cs_file_s *f = (struct omap_gpmc_cs_file_s *)opaque;
-    uint64_t v;
-    nand_setpins(f->dev, 0, 0, 0, 1, 0);
-    switch (omap_gpmc_devsize(f)) {
-    case OMAP_GPMC_8BIT:
-        v = nand_getio(f->dev);
-        if (size == 1) {
-            return v;
-        }
-        v |= (nand_getio(f->dev) << 8);
-        if (size == 2) {
-            return v;
-        }
-        v |= (nand_getio(f->dev) << 16);
-        v |= (nand_getio(f->dev) << 24);
-        return v;
-    case OMAP_GPMC_16BIT:
-        v = nand_getio(f->dev);
-        if (size == 1) {
-            /* 8 bit read from 16 bit device : probably a guest bug */
-            return v & 0xff;
-        }
-        if (size == 2) {
-            return v;
-        }
-        v |= (nand_getio(f->dev) << 16);
-        return v;
-    default:
-        abort();
-    }
-}
-
-static void omap_nand_setio(DeviceState *dev, uint64_t value,
-                            int nandsize, int size)
-{
-    /* Write the specified value to the NAND device, respecting
-     * both size of the NAND device and size of the write access.
-     */
-    switch (nandsize) {
-    case OMAP_GPMC_8BIT:
-        switch (size) {
-        case 1:
-            nand_setio(dev, value & 0xff);
-            break;
-        case 2:
-            nand_setio(dev, value & 0xff);
-            nand_setio(dev, (value >> 8) & 0xff);
-            break;
-        case 4:
-        default:
-            nand_setio(dev, value & 0xff);
-            nand_setio(dev, (value >> 8) & 0xff);
-            nand_setio(dev, (value >> 16) & 0xff);
-            nand_setio(dev, (value >> 24) & 0xff);
-            break;
-        }
-        break;
-    case OMAP_GPMC_16BIT:
-        switch (size) {
-        case 1:
-            /* writing to a 16bit device with 8bit access is probably a guest
-             * bug; pass the value through anyway.
-             */
-        case 2:
-            nand_setio(dev, value & 0xffff);
-            break;
-        case 4:
-        default:
-            nand_setio(dev, value & 0xffff);
-            nand_setio(dev, (value >> 16) & 0xffff);
-            break;
-        }
-        break;
-    }
-}
-
-static void omap_nand_write(void *opaque, hwaddr addr,
-                            uint64_t value, unsigned size)
-{
-    struct omap_gpmc_cs_file_s *f = (struct omap_gpmc_cs_file_s *)opaque;
-    nand_setpins(f->dev, 0, 0, 0, 1, 0);
-    omap_nand_setio(f->dev, value, omap_gpmc_devsize(f), size);
-}
-
-static const MemoryRegionOps omap_nand_ops = {
-    .read = omap_nand_read,
-    .write = omap_nand_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void fill_prefetch_fifo(struct omap_gpmc_s *s)
-{
-    /* Fill the prefetch FIFO by reading data from NAND.
-     * We do this synchronously, unlike the hardware which
-     * will do this asynchronously. We refill when the
-     * FIFO has THRESHOLD bytes free, and we always refill
-     * as much data as possible starting at the top end
-     * of the FIFO.
-     * (We have to refill at THRESHOLD rather than waiting
-     * for the FIFO to empty to allow for the case where
-     * the FIFO size isn't an exact multiple of THRESHOLD
-     * and we're doing DMA transfers.)
-     * This means we never need to handle wrap-around in
-     * the fifo-reading code, and the next byte of data
-     * to read is always fifo[63 - fifopointer].
-     */
-    int fptr;
-    int cs = prefetch_cs(s->prefetch.config1);
-    int is16bit = (((s->cs_file[cs].config[0] >> 12) & 3) != 0);
-    int bytes;
-    /* Don't believe the bit of the OMAP TRM that says that COUNTVALUE
-     * and TRANSFERCOUNT are in units of 16 bit words for 16 bit NAND.
-     * Instead believe the bit that says it is always a byte count.
-     */
-    bytes = 64 - s->prefetch.fifopointer;
-    if (bytes > s->prefetch.count) {
-        bytes = s->prefetch.count;
-    }
-    s->prefetch.count -= bytes;
-    s->prefetch.fifopointer += bytes;
-    fptr = 64 - s->prefetch.fifopointer;
-    /* Move the existing data in the FIFO so it sits just
-     * before what we're about to read in
-     */
-    while (fptr < (64 - bytes)) {
-        s->prefetch.fifo[fptr] = s->prefetch.fifo[fptr + bytes];
-        fptr++;
-    }
-    while (fptr < 64) {
-        if (is16bit) {
-            uint32_t v = omap_nand_read(&s->cs_file[cs], 0, 2);
-            s->prefetch.fifo[fptr++] = v & 0xff;
-            s->prefetch.fifo[fptr++] = (v >> 8) & 0xff;
-        } else {
-            s->prefetch.fifo[fptr++] = omap_nand_read(&s->cs_file[cs], 0, 1);
-        }
-    }
-    if (s->prefetch.startengine && (s->prefetch.count == 0)) {
-        /* This was the final transfer: raise TERMINALCOUNTSTATUS */
-        s->irqst |= 2;
-        s->prefetch.startengine = 0;
-    }
-    /* If there are any bytes in the FIFO at this point then
-     * we must raise a DMA request (either this is a final part
-     * transfer, or we filled the FIFO in which case we certainly
-     * have THRESHOLD bytes available)
-     */
-    if (s->prefetch.fifopointer != 0) {
-        omap_gpmc_dma_update(s, 1);
-    }
-    omap_gpmc_int_update(s);
-}
-
-/* Access functions for a NAND-like device when the prefetch/postwrite
- * engine is enabled -- all addresses in the region behave alike:
- * data is read or written to the FIFO.
- */
-static uint64_t omap_gpmc_prefetch_read(void *opaque, hwaddr addr,
-                                        unsigned size)
-{
-    struct omap_gpmc_s *s = (struct omap_gpmc_s *) opaque;
-    uint32_t data;
-    if (s->prefetch.config1 & 1) {
-        /* The TRM doesn't define the behaviour if you read from the
-         * FIFO when the prefetch engine is in write mode. We choose
-         * to always return zero.
-         */
-        return 0;
-    }
-    /* Note that trying to read an empty fifo repeats the last byte */
-    if (s->prefetch.fifopointer) {
-        s->prefetch.fifopointer--;
-    }
-    data = s->prefetch.fifo[63 - s->prefetch.fifopointer];
-    if (s->prefetch.fifopointer ==
-        (64 - prefetch_threshold(s->prefetch.config1))) {
-        /* We've drained THRESHOLD bytes now. So deassert the
-         * DMA request, then refill the FIFO (which will probably
-         * assert it again.)
-         */
-        omap_gpmc_dma_update(s, 0);
-        fill_prefetch_fifo(s);
-    }
-    omap_gpmc_int_update(s);
-    return data;
-}
-
-static void omap_gpmc_prefetch_write(void *opaque, hwaddr addr,
-                                     uint64_t value, unsigned size)
-{
-    struct omap_gpmc_s *s = (struct omap_gpmc_s *) opaque;
-    int cs = prefetch_cs(s->prefetch.config1);
-    if ((s->prefetch.config1 & 1) == 0) {
-        /* The TRM doesn't define the behaviour of writing to the
-         * FIFO when the prefetch engine is in read mode. We
-         * choose to ignore the write.
-         */
-        return;
-    }
-    if (s->prefetch.count == 0) {
-        /* The TRM doesn't define the behaviour of writing to the
-         * FIFO if the transfer is complete. We choose to ignore.
-         */
-        return;
-    }
-    /* The only reason we do any data buffering in postwrite
-     * mode is if we are talking to a 16 bit NAND device, in
-     * which case we need to buffer the first byte of the
-     * 16 bit word until the other byte arrives.
-     */
-    int is16bit = (((s->cs_file[cs].config[0] >> 12) & 3) != 0);
-    if (is16bit) {
-        /* fifopointer alternates between 64 (waiting for first
-         * byte of word) and 63 (waiting for second byte)
-         */
-        if (s->prefetch.fifopointer == 64) {
-            s->prefetch.fifo[0] = value;
-            s->prefetch.fifopointer--;
-        } else {
-            value = (value << 8) | s->prefetch.fifo[0];
-            omap_nand_write(&s->cs_file[cs], 0, value, 2);
-            s->prefetch.count--;
-            s->prefetch.fifopointer = 64;
-        }
-    } else {
-        /* Just write the byte : fifopointer remains 64 at all times */
-        omap_nand_write(&s->cs_file[cs], 0, value, 1);
-        s->prefetch.count--;
-    }
-    if (s->prefetch.count == 0) {
-        /* Final transfer: raise TERMINALCOUNTSTATUS */
-        s->irqst |= 2;
-        s->prefetch.startengine = 0;
-    }
-    omap_gpmc_int_update(s);
-}
-
-static const MemoryRegionOps omap_prefetch_ops = {
-    .read = omap_gpmc_prefetch_read,
-    .write = omap_gpmc_prefetch_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .impl.min_access_size = 1,
-    .impl.max_access_size = 1,
-};
-
-static MemoryRegion *omap_gpmc_cs_memregion(struct omap_gpmc_s *s, int cs)
-{
-    /* Return the MemoryRegion* to map/unmap for this chipselect */
-    struct omap_gpmc_cs_file_s *f = &s->cs_file[cs];
-    if (omap_gpmc_devtype(f) == OMAP_GPMC_NOR) {
-        return f->iomem;
-    }
-    if ((s->prefetch.config1 & 0x80) &&
-        (prefetch_cs(s->prefetch.config1) == cs)) {
-        /* The prefetch engine is enabled for this CS: map the FIFO */
-        return &s->prefetch.iomem;
-    }
-    return &f->nandiomem;
-}
-
-static void omap_gpmc_cs_map(struct omap_gpmc_s *s, int cs)
-{
-    struct omap_gpmc_cs_file_s *f = &s->cs_file[cs];
-    uint32_t mask = (f->config[6] >> 8) & 0xf;
-    uint32_t base = f->config[6] & 0x3f;
-    uint32_t size;
-
-    if (!f->iomem && !f->dev) {
-        return;
-    }
-
-    if (!(f->config[6] & (1 << 6))) {
-        /* Do nothing unless CSVALID */
-        return;
-    }
-
-    /* TODO: check for overlapping regions and report access errors */
-    if (mask != 0x8 && mask != 0xc && mask != 0xe && mask != 0xf
-         && !(s->accept_256 && !mask)) {
-        fprintf(stderr, "%s: invalid chip-select mask address (0x%x)\n",
-                 __func__, mask);
-    }
-
-    base <<= 24;
-    size = (0x0fffffff & ~(mask << 24)) + 1;
-    /* TODO: rather than setting the size of the mapping (which should be
-     * constant), the mask should cause wrapping of the address space, so
-     * that the same memory becomes accessible at every <i>size</i> bytes
-     * starting from <i>base</i>.  */
-    memory_region_init(&f->container, "omap-gpmc-file", size);
-    memory_region_add_subregion(&f->container, 0,
-                                omap_gpmc_cs_memregion(s, cs));
-    memory_region_add_subregion(get_system_memory(), base,
-                                &f->container);
-}
-
-static void omap_gpmc_cs_unmap(struct omap_gpmc_s *s, int cs)
-{
-    struct omap_gpmc_cs_file_s *f = &s->cs_file[cs];
-    if (!(f->config[6] & (1 << 6))) {
-        /* Do nothing unless CSVALID */
-        return;
-    }
-    if (!f->iomem && !f->dev) {
-        return;
-    }
-    memory_region_del_subregion(get_system_memory(), &f->container);
-    memory_region_del_subregion(&f->container, omap_gpmc_cs_memregion(s, cs));
-    memory_region_destroy(&f->container);
-}
-
-void omap_gpmc_reset(struct omap_gpmc_s *s)
-{
-    int i;
-
-    s->sysconfig = 0;
-    s->irqst = 0;
-    s->irqen = 0;
-    omap_gpmc_int_update(s);
-    for (i = 0; i < 8; i++) {
-        /* This has to happen before we change any of the config
-         * used to determine which memory regions are mapped or unmapped.
-         */
-        omap_gpmc_cs_unmap(s, i);
-    }
-    s->timeout = 0;
-    s->config = 0xa00;
-    s->prefetch.config1 = 0x00004000;
-    s->prefetch.transfercount = 0x00000000;
-    s->prefetch.startengine = 0;
-    s->prefetch.fifopointer = 0;
-    s->prefetch.count = 0;
-    for (i = 0; i < 8; i ++) {
-        s->cs_file[i].config[1] = 0x101001;
-        s->cs_file[i].config[2] = 0x020201;
-        s->cs_file[i].config[3] = 0x10031003;
-        s->cs_file[i].config[4] = 0x10f1111;
-        s->cs_file[i].config[5] = 0;
-        s->cs_file[i].config[6] = 0xf00 | (i ? 0 : 1 << 6);
-
-        s->cs_file[i].config[6] = 0xf00;
-        /* In theory we could probe attached devices for some CFG1
-         * bits here, but we just retain them across resets as they
-         * were set initially by omap_gpmc_attach().
-         */
-        if (i == 0) {
-            s->cs_file[i].config[0] &= 0x00433e00;
-            s->cs_file[i].config[6] |= 1 << 6; /* CSVALID */
-            omap_gpmc_cs_map(s, i);
-        } else {
-            s->cs_file[i].config[0] &= 0x00403c00;
-        }
-    }
-    s->ecc_cs = 0;
-    s->ecc_ptr = 0;
-    s->ecc_cfg = 0x3fcff000;
-    for (i = 0; i < 9; i ++)
-        ecc_reset(&s->ecc[i]);
-}
-
-static int gpmc_wordaccess_only(hwaddr addr)
-{
-    /* Return true if the register offset is to a register that
-     * only permits word width accesses.
-     * Non-word accesses are only OK for GPMC_NAND_DATA/ADDRESS/COMMAND
-     * for any chipselect.
-     */
-    if (addr >= 0x60 && addr <= 0x1d4) {
-        int cs = (addr - 0x60) / 0x30;
-        addr -= cs * 0x30;
-        if (addr >= 0x7c && addr < 0x88) {
-            /* GPMC_NAND_COMMAND, GPMC_NAND_ADDRESS, GPMC_NAND_DATA */
-            return 0;
-        }
-    }
-    return 1;
-}
-
-static uint64_t omap_gpmc_read(void *opaque, hwaddr addr,
-                               unsigned size)
-{
-    struct omap_gpmc_s *s = (struct omap_gpmc_s *) opaque;
-    int cs;
-    struct omap_gpmc_cs_file_s *f;
-
-    if (size != 4 && gpmc_wordaccess_only(addr)) {
-        return omap_badwidth_read32(opaque, addr);
-    }
-
-    switch (addr) {
-    case 0x000:        /* GPMC_REVISION */
-        return s->revision;
-
-    case 0x010:        /* GPMC_SYSCONFIG */
-        return s->sysconfig;
-
-    case 0x014:        /* GPMC_SYSSTATUS */
-        return 1;                                              /* RESETDONE */
-
-    case 0x018:        /* GPMC_IRQSTATUS */
-        return s->irqst;
-
-    case 0x01c:        /* GPMC_IRQENABLE */
-        return s->irqen;
-
-    case 0x040:        /* GPMC_TIMEOUT_CONTROL */
-        return s->timeout;
-
-    case 0x044:        /* GPMC_ERR_ADDRESS */
-    case 0x048:        /* GPMC_ERR_TYPE */
-        return 0;
-
-    case 0x050:        /* GPMC_CONFIG */
-        return s->config;
-
-    case 0x054:        /* GPMC_STATUS */
-        return 0x001;
-
-    case 0x060 ... 0x1d4:
-        cs = (addr - 0x060) / 0x30;
-        addr -= cs * 0x30;
-        f = s->cs_file + cs;
-        switch (addr) {
-        case 0x60:      /* GPMC_CONFIG1 */
-            return f->config[0];
-        case 0x64:      /* GPMC_CONFIG2 */
-            return f->config[1];
-        case 0x68:      /* GPMC_CONFIG3 */
-            return f->config[2];
-        case 0x6c:      /* GPMC_CONFIG4 */
-            return f->config[3];
-        case 0x70:      /* GPMC_CONFIG5 */
-            return f->config[4];
-        case 0x74:      /* GPMC_CONFIG6 */
-            return f->config[5];
-        case 0x78:      /* GPMC_CONFIG7 */
-            return f->config[6];
-        case 0x84 ... 0x87: /* GPMC_NAND_DATA */
-            if (omap_gpmc_devtype(f) == OMAP_GPMC_NAND) {
-                return omap_nand_read(f, 0, size);
-            }
-            return 0;
-        }
-        break;
-
-    case 0x1e0:        /* GPMC_PREFETCH_CONFIG1 */
-        return s->prefetch.config1;
-    case 0x1e4:        /* GPMC_PREFETCH_CONFIG2 */
-        return s->prefetch.transfercount;
-    case 0x1ec:        /* GPMC_PREFETCH_CONTROL */
-        return s->prefetch.startengine;
-    case 0x1f0:        /* GPMC_PREFETCH_STATUS */
-        /* NB: The OMAP3 TRM is inconsistent about whether the GPMC
-         * FIFOTHRESHOLDSTATUS bit should be set when
-         * FIFOPOINTER > FIFOTHRESHOLD or when it is >= FIFOTHRESHOLD.
-         * Apparently the underlying functional spec from which the TRM was
-         * created states that the behaviour is ">=", and this also
-         * makes more conceptual sense.
-         */
-        return (s->prefetch.fifopointer << 24) |
-                ((s->prefetch.fifopointer >=
-                  ((s->prefetch.config1 >> 8) & 0x7f) ? 1 : 0) << 16) |
-                s->prefetch.count;
-
-    case 0x1f4:        /* GPMC_ECC_CONFIG */
-        return s->ecc_cs;
-    case 0x1f8:        /* GPMC_ECC_CONTROL */
-        return s->ecc_ptr;
-    case 0x1fc:        /* GPMC_ECC_SIZE_CONFIG */
-        return s->ecc_cfg;
-    case 0x200 ... 0x220:      /* GPMC_ECC_RESULT */
-        cs = (addr & 0x1f) >> 2;
-        /* TODO: check correctness */
-        return
-                ((s->ecc[cs].cp    &  0x07) <<  0) |
-                ((s->ecc[cs].cp    &  0x38) << 13) |
-                ((s->ecc[cs].lp[0] & 0x1ff) <<  3) |
-                ((s->ecc[cs].lp[1] & 0x1ff) << 19);
-
-    case 0x230:        /* GPMC_TESTMODE_CTRL */
-        return 0;
-    case 0x234:        /* GPMC_PSA_LSB */
-    case 0x238:        /* GPMC_PSA_MSB */
-        return 0x00000000;
-    }
-
-    OMAP_BAD_REG(addr);
-    return 0;
-}
-
-static void omap_gpmc_write(void *opaque, hwaddr addr,
-                            uint64_t value, unsigned size)
-{
-    struct omap_gpmc_s *s = (struct omap_gpmc_s *) opaque;
-    int cs;
-    struct omap_gpmc_cs_file_s *f;
-
-    if (size != 4 && gpmc_wordaccess_only(addr)) {
-        return omap_badwidth_write32(opaque, addr, value);
-    }
-
-    switch (addr) {
-    case 0x000:        /* GPMC_REVISION */
-    case 0x014:        /* GPMC_SYSSTATUS */
-    case 0x054:        /* GPMC_STATUS */
-    case 0x1f0:        /* GPMC_PREFETCH_STATUS */
-    case 0x200 ... 0x220:      /* GPMC_ECC_RESULT */
-    case 0x234:        /* GPMC_PSA_LSB */
-    case 0x238:        /* GPMC_PSA_MSB */
-        OMAP_RO_REG(addr);
-        break;
-
-    case 0x010:        /* GPMC_SYSCONFIG */
-        if ((value >> 3) == 0x3)
-            fprintf(stderr, "%s: bad SDRAM idle mode %"PRIi64"\n",
-                            __FUNCTION__, value >> 3);
-        if (value & 2)
-            omap_gpmc_reset(s);
-        s->sysconfig = value & 0x19;
-        break;
-
-    case 0x018:        /* GPMC_IRQSTATUS */
-        s->irqst &= ~value;
-        omap_gpmc_int_update(s);
-        break;
-
-    case 0x01c:        /* GPMC_IRQENABLE */
-        s->irqen = value & 0xf03;
-        omap_gpmc_int_update(s);
-        break;
-
-    case 0x040:        /* GPMC_TIMEOUT_CONTROL */
-        s->timeout = value & 0x1ff1;
-        break;
-
-    case 0x044:        /* GPMC_ERR_ADDRESS */
-    case 0x048:        /* GPMC_ERR_TYPE */
-        break;
-
-    case 0x050:        /* GPMC_CONFIG */
-        s->config = value & 0xf13;
-        break;
-
-    case 0x060 ... 0x1d4:
-        cs = (addr - 0x060) / 0x30;
-        addr -= cs * 0x30;
-        f = s->cs_file + cs;
-        switch (addr) {
-        case 0x60:      /* GPMC_CONFIG1 */
-            f->config[0] = value & 0xffef3e13;
-            break;
-        case 0x64:      /* GPMC_CONFIG2 */
-            f->config[1] = value & 0x001f1f8f;
-            break;
-        case 0x68:      /* GPMC_CONFIG3 */
-            f->config[2] = value & 0x001f1f8f;
-            break;
-        case 0x6c:      /* GPMC_CONFIG4 */
-            f->config[3] = value & 0x1f8f1f8f;
-            break;
-        case 0x70:      /* GPMC_CONFIG5 */
-            f->config[4] = value & 0x0f1f1f1f;
-            break;
-        case 0x74:      /* GPMC_CONFIG6 */
-            f->config[5] = value & 0x00000fcf;
-            break;
-        case 0x78:      /* GPMC_CONFIG7 */
-            if ((f->config[6] ^ value) & 0xf7f) {
-                omap_gpmc_cs_unmap(s, cs);
-                f->config[6] = value & 0x00000f7f;
-                omap_gpmc_cs_map(s, cs);
-            }
-            break;
-        case 0x7c ... 0x7f: /* GPMC_NAND_COMMAND */
-            if (omap_gpmc_devtype(f) == OMAP_GPMC_NAND) {
-                nand_setpins(f->dev, 1, 0, 0, 1, 0); /* CLE */
-                omap_nand_setio(f->dev, value, omap_gpmc_devsize(f), size);
-            }
-            break;
-        case 0x80 ... 0x83: /* GPMC_NAND_ADDRESS */
-            if (omap_gpmc_devtype(f) == OMAP_GPMC_NAND) {
-                nand_setpins(f->dev, 0, 1, 0, 1, 0); /* ALE */
-                omap_nand_setio(f->dev, value, omap_gpmc_devsize(f), size);
-            }
-            break;
-        case 0x84 ... 0x87: /* GPMC_NAND_DATA */
-            if (omap_gpmc_devtype(f) == OMAP_GPMC_NAND) {
-                omap_nand_write(f, 0, value, size);
-            }
-            break;
-        default:
-            goto bad_reg;
-        }
-        break;
-
-    case 0x1e0:        /* GPMC_PREFETCH_CONFIG1 */
-        if (!s->prefetch.startengine) {
-            uint32_t newconfig1 = value & 0x7f8f7fbf;
-            uint32_t changed;
-            changed = newconfig1 ^ s->prefetch.config1;
-            if (changed & (0x80 | 0x7000000)) {
-                /* Turning the engine on or off, or mapping it somewhere else.
-                 * cs_map() and cs_unmap() check the prefetch config and
-                 * overall CSVALID bits, so it is sufficient to unmap-and-map
-                 * both the old cs and the new one. Note that we adhere to
-                 * the "unmap/change config/map" order (and not unmap twice
-                 * if newcs == oldcs), otherwise we'll try to delete the wrong
-                 * memory region.
-                 */
-                int oldcs = prefetch_cs(s->prefetch.config1);
-                int newcs = prefetch_cs(newconfig1);
-                omap_gpmc_cs_unmap(s, oldcs);
-                if (oldcs != newcs) {
-                    omap_gpmc_cs_unmap(s, newcs);
-                }
-                s->prefetch.config1 = newconfig1;
-                omap_gpmc_cs_map(s, oldcs);
-                if (oldcs != newcs) {
-                    omap_gpmc_cs_map(s, newcs);
-                }
-            } else {
-                s->prefetch.config1 = newconfig1;
-            }
-        }
-        break;
-
-    case 0x1e4:        /* GPMC_PREFETCH_CONFIG2 */
-        if (!s->prefetch.startengine) {
-            s->prefetch.transfercount = value & 0x3fff;
-        }
-        break;
-
-    case 0x1ec:        /* GPMC_PREFETCH_CONTROL */
-        if (s->prefetch.startengine != (value & 1)) {
-            s->prefetch.startengine = value & 1;
-            if (s->prefetch.startengine) {
-                /* Prefetch engine start */
-                s->prefetch.count = s->prefetch.transfercount;
-                if (s->prefetch.config1 & 1) {
-                    /* Write */
-                    s->prefetch.fifopointer = 64;
-                } else {
-                    /* Read */
-                    s->prefetch.fifopointer = 0;
-                    fill_prefetch_fifo(s);
-                }
-            } else {
-                /* Prefetch engine forcibly stopped. The TRM
-                 * doesn't define the behaviour if you do this.
-                 * We clear the prefetch count, which means that
-                 * we permit no more writes, and don't read any
-                 * more data from NAND. The CPU can still drain
-                 * the FIFO of unread data.
-                 */
-                s->prefetch.count = 0;
-            }
-            omap_gpmc_int_update(s);
-        }
-        break;
-
-    case 0x1f4:        /* GPMC_ECC_CONFIG */
-        s->ecc_cs = 0x8f;
-        break;
-    case 0x1f8:        /* GPMC_ECC_CONTROL */
-        if (value & (1 << 8))
-            for (cs = 0; cs < 9; cs ++)
-                ecc_reset(&s->ecc[cs]);
-        s->ecc_ptr = value & 0xf;
-        if (s->ecc_ptr == 0 || s->ecc_ptr > 9) {
-            s->ecc_ptr = 0;
-            s->ecc_cs &= ~1;
-        }
-        break;
-    case 0x1fc:        /* GPMC_ECC_SIZE_CONFIG */
-        s->ecc_cfg = value & 0x3fcff1ff;
-        break;
-    case 0x230:        /* GPMC_TESTMODE_CTRL */
-        if (value & 7)
-            fprintf(stderr, "%s: test mode enable attempt\n", __FUNCTION__);
-        break;
-
-    default:
-    bad_reg:
-        OMAP_BAD_REG(addr);
-        return;
-    }
-}
-
-static const MemoryRegionOps omap_gpmc_ops = {
-    .read = omap_gpmc_read,
-    .write = omap_gpmc_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-struct omap_gpmc_s *omap_gpmc_init(struct omap_mpu_state_s *mpu,
-                                   hwaddr base,
-                                   qemu_irq irq, qemu_irq drq)
-{
-    int cs;
-    struct omap_gpmc_s *s = (struct omap_gpmc_s *)
-            g_malloc0(sizeof(struct omap_gpmc_s));
-
-    memory_region_init_io(&s->iomem, &omap_gpmc_ops, s, "omap-gpmc", 0x1000);
-    memory_region_add_subregion(get_system_memory(), base, &s->iomem);
-
-    s->irq = irq;
-    s->drq = drq;
-    s->accept_256 = cpu_is_omap3630(mpu);
-    s->revision = cpu_class_omap3(mpu) ? 0x50 : 0x20;
-    s->lastirq = 0;
-    omap_gpmc_reset(s);
-
-    /* We have to register a different IO memory handler for each
-     * chip select region in case a NAND device is mapped there. We
-     * make the region the worst-case size of 256MB and rely on the
-     * container memory region in cs_map to chop it down to the actual
-     * guest-requested size.
-     */
-    for (cs = 0; cs < 8; cs++) {
-        memory_region_init_io(&s->cs_file[cs].nandiomem,
-                              &omap_nand_ops,
-                              &s->cs_file[cs],
-                              "omap-nand",
-                              256 * 1024 * 1024);
-    }
-
-    memory_region_init_io(&s->prefetch.iomem, &omap_prefetch_ops, s,
-                          "omap-gpmc-prefetch", 256 * 1024 * 1024);
-    return s;
-}
-
-void omap_gpmc_attach(struct omap_gpmc_s *s, int cs, MemoryRegion *iomem)
-{
-    struct omap_gpmc_cs_file_s *f;
-    assert(iomem);
-
-    if (cs < 0 || cs >= 8) {
-        fprintf(stderr, "%s: bad chip-select %i\n", __FUNCTION__, cs);
-        exit(-1);
-    }
-    f = &s->cs_file[cs];
-
-    omap_gpmc_cs_unmap(s, cs);
-    f->config[0] &= ~(0xf << 10);
-    f->iomem = iomem;
-    omap_gpmc_cs_map(s, cs);
-}
-
-void omap_gpmc_attach_nand(struct omap_gpmc_s *s, int cs, DeviceState *nand)
-{
-    struct omap_gpmc_cs_file_s *f;
-    assert(nand);
-
-    if (cs < 0 || cs >= 8) {
-        fprintf(stderr, "%s: bad chip-select %i\n", __func__, cs);
-        exit(-1);
-    }
-    f = &s->cs_file[cs];
-
-    omap_gpmc_cs_unmap(s, cs);
-    f->config[0] &= ~(0xf << 10);
-    f->config[0] |= (OMAP_GPMC_NAND << 10);
-    f->dev = nand;
-    if (nand_getbuswidth(f->dev) == 16) {
-        f->config[0] |= OMAP_GPMC_16BIT << 12;
-    }
-    omap_gpmc_cs_map(s, cs);
-}
diff --git a/hw/omap_gptimer.c b/hw/omap_gptimer.c
deleted file mode 100644 (file)
index 8485ee8..0000000
+++ /dev/null
@@ -1,488 +0,0 @@
-/*
- * TI OMAP2 general purpose timers emulation.
- *
- * Copyright (C) 2007-2008 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.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 or
- * (at your option) any later version 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
- * 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 "hw/hw.h"
-#include "qemu/timer.h"
-#include "hw/omap.h"
-
-/* GP timers */
-struct omap_gp_timer_s {
-    MemoryRegion iomem;
-    qemu_irq irq;
-    qemu_irq wkup;
-    qemu_irq in;
-    qemu_irq out;
-    omap_clk clk;
-    QEMUTimer *timer;
-    QEMUTimer *match;
-    struct omap_target_agent_s *ta;
-
-    int in_val;
-    int out_val;
-    int64_t time;
-    int64_t rate;
-    int64_t ticks_per_sec;
-
-    int16_t config;
-    int status;
-    int it_ena;
-    int wu_ena;
-    int enable;
-    int inout;
-    int capt2;
-    int pt;
-    enum {
-        gpt_trigger_none, gpt_trigger_overflow, gpt_trigger_both
-    } trigger;
-    enum {
-        gpt_capture_none, gpt_capture_rising,
-        gpt_capture_falling, gpt_capture_both
-    } capture;
-    int scpwm;
-    int ce;
-    int pre;
-    int ptv;
-    int ar;
-    int st;
-    int posted;
-    uint32_t val;
-    uint32_t load_val;
-    uint32_t capture_val[2];
-    uint32_t match_val;
-    int capt_num;
-
-    uint16_t writeh;   /* LSB */
-    uint16_t readh;    /* MSB */
-};
-
-#define GPT_TCAR_IT    (1 << 2)
-#define GPT_OVF_IT     (1 << 1)
-#define GPT_MAT_IT     (1 << 0)
-
-static inline void omap_gp_timer_intr(struct omap_gp_timer_s *timer, int it)
-{
-    if (timer->it_ena & it) {
-        if (!timer->status)
-            qemu_irq_raise(timer->irq);
-
-        timer->status |= it;
-        /* Or are the status bits set even when masked?
-         * i.e. is masking applied before or after the status register?  */
-    }
-
-    if (timer->wu_ena & it)
-        qemu_irq_pulse(timer->wkup);
-}
-
-static inline void omap_gp_timer_out(struct omap_gp_timer_s *timer, int level)
-{
-    if (!timer->inout && timer->out_val != level) {
-        timer->out_val = level;
-        qemu_set_irq(timer->out, level);
-    }
-}
-
-static inline uint32_t omap_gp_timer_read(struct omap_gp_timer_s *timer)
-{
-    uint64_t distance;
-
-    if (timer->st && timer->rate) {
-        distance = qemu_get_clock_ns(vm_clock) - timer->time;
-        distance = muldiv64(distance, timer->rate, timer->ticks_per_sec);
-
-        if (distance >= 0xffffffff - timer->val)
-            return 0xffffffff;
-        else
-            return timer->val + distance;
-    } else
-        return timer->val;
-}
-
-static inline void omap_gp_timer_sync(struct omap_gp_timer_s *timer)
-{
-    if (timer->st) {
-        timer->val = omap_gp_timer_read(timer);
-        timer->time = qemu_get_clock_ns(vm_clock);
-    }
-}
-
-static inline void omap_gp_timer_update(struct omap_gp_timer_s *timer)
-{
-    int64_t expires, matches;
-
-    if (timer->st && timer->rate) {
-        expires = muldiv64(0x100000000ll - timer->val,
-                        timer->ticks_per_sec, timer->rate);
-        qemu_mod_timer(timer->timer, timer->time + expires);
-
-        if (timer->ce && timer->match_val >= timer->val) {
-            matches = muldiv64(timer->match_val - timer->val,
-                            timer->ticks_per_sec, timer->rate);
-            qemu_mod_timer(timer->match, timer->time + matches);
-        } else
-            qemu_del_timer(timer->match);
-    } else {
-        qemu_del_timer(timer->timer);
-        qemu_del_timer(timer->match);
-        omap_gp_timer_out(timer, timer->scpwm);
-    }
-}
-
-static inline void omap_gp_timer_trigger(struct omap_gp_timer_s *timer)
-{
-    if (timer->pt)
-        /* TODO in overflow-and-match mode if the first event to
-         * occur is the match, don't toggle.  */
-        omap_gp_timer_out(timer, !timer->out_val);
-    else
-        /* TODO inverted pulse on timer->out_val == 1?  */
-        qemu_irq_pulse(timer->out);
-}
-
-static void omap_gp_timer_tick(void *opaque)
-{
-    struct omap_gp_timer_s *timer = (struct omap_gp_timer_s *) opaque;
-
-    if (!timer->ar) {
-        timer->st = 0;
-        timer->val = 0;
-    } else {
-        timer->val = timer->load_val;
-        timer->time = qemu_get_clock_ns(vm_clock);
-    }
-
-    if (timer->trigger == gpt_trigger_overflow ||
-                    timer->trigger == gpt_trigger_both)
-        omap_gp_timer_trigger(timer);
-
-    omap_gp_timer_intr(timer, GPT_OVF_IT);
-    omap_gp_timer_update(timer);
-}
-
-static void omap_gp_timer_match(void *opaque)
-{
-    struct omap_gp_timer_s *timer = (struct omap_gp_timer_s *) opaque;
-
-    if (timer->trigger == gpt_trigger_both)
-        omap_gp_timer_trigger(timer);
-
-    omap_gp_timer_intr(timer, GPT_MAT_IT);
-}
-
-static void omap_gp_timer_input(void *opaque, int line, int on)
-{
-    struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque;
-    int trigger;
-
-    switch (s->capture) {
-    default:
-    case gpt_capture_none:
-        trigger = 0;
-        break;
-    case gpt_capture_rising:
-        trigger = !s->in_val && on;
-        break;
-    case gpt_capture_falling:
-        trigger = s->in_val && !on;
-        break;
-    case gpt_capture_both:
-        trigger = (s->in_val == !on);
-        break;
-    }
-    s->in_val = on;
-
-    if (s->inout && trigger && s->capt_num < 2) {
-        s->capture_val[s->capt_num] = omap_gp_timer_read(s);
-
-        if (s->capt2 == s->capt_num ++)
-            omap_gp_timer_intr(s, GPT_TCAR_IT);
-    }
-}
-
-static void omap_gp_timer_clk_update(void *opaque, int line, int on)
-{
-    struct omap_gp_timer_s *timer = (struct omap_gp_timer_s *) opaque;
-
-    omap_gp_timer_sync(timer);
-    timer->rate = on ? omap_clk_getrate(timer->clk) : 0;
-    omap_gp_timer_update(timer);
-}
-
-static void omap_gp_timer_clk_setup(struct omap_gp_timer_s *timer)
-{
-    omap_clk_adduser(timer->clk,
-                    qemu_allocate_irqs(omap_gp_timer_clk_update, timer, 1)[0]);
-    timer->rate = omap_clk_getrate(timer->clk);
-}
-
-void omap_gp_timer_reset(struct omap_gp_timer_s *s)
-{
-    s->config = 0x000;
-    s->status = 0;
-    s->it_ena = 0;
-    s->wu_ena = 0;
-    s->inout = 0;
-    s->capt2 = 0;
-    s->capt_num = 0;
-    s->pt = 0;
-    s->trigger = gpt_trigger_none;
-    s->capture = gpt_capture_none;
-    s->scpwm = 0;
-    s->ce = 0;
-    s->pre = 0;
-    s->ptv = 0;
-    s->ar = 0;
-    s->st = 0;
-    s->posted = 1;
-    s->val = 0x00000000;
-    s->load_val = 0x00000000;
-    s->capture_val[0] = 0x00000000;
-    s->capture_val[1] = 0x00000000;
-    s->match_val = 0x00000000;
-    omap_gp_timer_update(s);
-}
-
-static uint32_t omap_gp_timer_readw(void *opaque, hwaddr addr)
-{
-    struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque;
-
-    switch (addr) {
-    case 0x00: /* TIDR */
-        return 0x21;
-
-    case 0x10: /* TIOCP_CFG */
-        return s->config;
-
-    case 0x14: /* TISTAT */
-        /* ??? When's this bit reset? */
-        return 1;                                              /* RESETDONE */
-
-    case 0x18: /* TISR */
-        return s->status;
-
-    case 0x1c: /* TIER */
-        return s->it_ena;
-
-    case 0x20: /* TWER */
-        return s->wu_ena;
-
-    case 0x24: /* TCLR */
-        return (s->inout << 14) |
-                (s->capt2 << 13) |
-                (s->pt << 12) |
-                (s->trigger << 10) |
-                (s->capture << 8) |
-                (s->scpwm << 7) |
-                (s->ce << 6) |
-                (s->pre << 5) |
-                (s->ptv << 2) |
-                (s->ar << 1) |
-                (s->st << 0);
-
-    case 0x28: /* TCRR */
-        return omap_gp_timer_read(s);
-
-    case 0x2c: /* TLDR */
-        return s->load_val;
-
-    case 0x30: /* TTGR */
-        return 0xffffffff;
-
-    case 0x34: /* TWPS */
-        return 0x00000000;     /* No posted writes pending.  */
-
-    case 0x38: /* TMAR */
-        return s->match_val;
-
-    case 0x3c: /* TCAR1 */
-        return s->capture_val[0];
-
-    case 0x40: /* TSICR */
-        return s->posted << 2;
-
-    case 0x44: /* TCAR2 */
-        return s->capture_val[1];
-    }
-
-    OMAP_BAD_REG(addr);
-    return 0;
-}
-
-static uint32_t omap_gp_timer_readh(void *opaque, hwaddr addr)
-{
-    struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque;
-    uint32_t ret;
-
-    if (addr & 2)
-        return s->readh;
-    else {
-        ret = omap_gp_timer_readw(opaque, addr);
-        s->readh = ret >> 16;
-        return ret & 0xffff;
-    }
-}
-
-static void omap_gp_timer_write(void *opaque, hwaddr addr,
-                uint32_t value)
-{
-    struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque;
-
-    switch (addr) {
-    case 0x00: /* TIDR */
-    case 0x14: /* TISTAT */
-    case 0x34: /* TWPS */
-    case 0x3c: /* TCAR1 */
-    case 0x44: /* TCAR2 */
-        OMAP_RO_REG(addr);
-        break;
-
-    case 0x10: /* TIOCP_CFG */
-        s->config = value & 0x33d;
-        if (((value >> 3) & 3) == 3)                           /* IDLEMODE */
-            fprintf(stderr, "%s: illegal IDLEMODE value in TIOCP_CFG\n",
-                            __FUNCTION__);
-        if (value & 2)                                         /* SOFTRESET */
-            omap_gp_timer_reset(s);
-        break;
-
-    case 0x18: /* TISR */
-        if (value & GPT_TCAR_IT)
-            s->capt_num = 0;
-        if (s->status && !(s->status &= ~value))
-            qemu_irq_lower(s->irq);
-        break;
-
-    case 0x1c: /* TIER */
-        s->it_ena = value & 7;
-        break;
-
-    case 0x20: /* TWER */
-        s->wu_ena = value & 7;
-        break;
-
-    case 0x24: /* TCLR */
-        omap_gp_timer_sync(s);
-        s->inout = (value >> 14) & 1;
-        s->capt2 = (value >> 13) & 1;
-        s->pt = (value >> 12) & 1;
-        s->trigger = (value >> 10) & 3;
-        if (s->capture == gpt_capture_none &&
-                        ((value >> 8) & 3) != gpt_capture_none)
-            s->capt_num = 0;
-        s->capture = (value >> 8) & 3;
-        s->scpwm = (value >> 7) & 1;
-        s->ce = (value >> 6) & 1;
-        s->pre = (value >> 5) & 1;
-        s->ptv = (value >> 2) & 7;
-        s->ar = (value >> 1) & 1;
-        s->st = (value >> 0) & 1;
-        if (s->inout && s->trigger != gpt_trigger_none)
-            fprintf(stderr, "%s: GP timer pin must be an output "
-                            "for this trigger mode\n", __FUNCTION__);
-        if (!s->inout && s->capture != gpt_capture_none)
-            fprintf(stderr, "%s: GP timer pin must be an input "
-                            "for this capture mode\n", __FUNCTION__);
-        if (s->trigger == gpt_trigger_none)
-            omap_gp_timer_out(s, s->scpwm);
-        /* TODO: make sure this doesn't overflow 32-bits */
-        s->ticks_per_sec = get_ticks_per_sec() << (s->pre ? s->ptv + 1 : 0);
-        omap_gp_timer_update(s);
-        break;
-
-    case 0x28: /* TCRR */
-        s->time = qemu_get_clock_ns(vm_clock);
-        s->val = value;
-        omap_gp_timer_update(s);
-        break;
-
-    case 0x2c: /* TLDR */
-        s->load_val = value;
-        break;
-
-    case 0x30: /* TTGR */
-        s->time = qemu_get_clock_ns(vm_clock);
-        s->val = s->load_val;
-        omap_gp_timer_update(s);
-        break;
-
-    case 0x38: /* TMAR */
-        omap_gp_timer_sync(s);
-        s->match_val = value;
-        omap_gp_timer_update(s);
-        break;
-
-    case 0x40: /* TSICR */
-        s->posted = (value >> 2) & 1;
-        if (value & 2) /* How much exactly are we supposed to reset? */
-            omap_gp_timer_reset(s);
-        break;
-
-    default:
-        OMAP_BAD_REG(addr);
-    }
-}
-
-static void omap_gp_timer_writeh(void *opaque, hwaddr addr,
-                uint32_t value)
-{
-    struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque;
-
-    if (addr & 2)
-        return omap_gp_timer_write(opaque, addr, (value << 16) | s->writeh);
-    else
-        s->writeh = (uint16_t) value;
-}
-
-static const MemoryRegionOps omap_gp_timer_ops = {
-    .old_mmio = {
-        .read = {
-            omap_badwidth_read32,
-            omap_gp_timer_readh,
-            omap_gp_timer_readw,
-        },
-        .write = {
-            omap_badwidth_write32,
-            omap_gp_timer_writeh,
-            omap_gp_timer_write,
-        },
-    },
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-struct omap_gp_timer_s *omap_gp_timer_init(struct omap_target_agent_s *ta,
-                qemu_irq irq, omap_clk fclk, omap_clk iclk)
-{
-    struct omap_gp_timer_s *s = (struct omap_gp_timer_s *)
-            g_malloc0(sizeof(struct omap_gp_timer_s));
-
-    s->ta = ta;
-    s->irq = irq;
-    s->clk = fclk;
-    s->timer = qemu_new_timer_ns(vm_clock, omap_gp_timer_tick, s);
-    s->match = qemu_new_timer_ns(vm_clock, omap_gp_timer_match, s);
-    s->in = qemu_allocate_irqs(omap_gp_timer_input, s, 1)[0];
-    omap_gp_timer_reset(s);
-    omap_gp_timer_clk_setup(s);
-
-    memory_region_init_io(&s->iomem, &omap_gp_timer_ops, s, "omap.gptimer",
-                          omap_l4_region_size(ta, 0));
-    omap_l4_attach(ta, 0, &s->iomem);
-
-    return s;
-}
diff --git a/hw/omap_i2c.c b/hw/omap_i2c.c
deleted file mode 100644 (file)
index 92f7b37..0000000
+++ /dev/null
@@ -1,492 +0,0 @@
-/*
- * TI OMAP on-chip I2C controller.  Only "new I2C" mode supported.
- *
- * Copyright (C) 2007 Andrzej Zaborowski  <balrog@zabor.org>
- *
- * 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 "hw/hw.h"
-#include "hw/i2c.h"
-#include "hw/omap.h"
-#include "hw/sysbus.h"
-
-
-typedef struct OMAPI2CState {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-    qemu_irq irq;
-    qemu_irq drq[2];
-    i2c_bus *bus;
-
-    uint8_t revision;
-    void *iclk;
-    void *fclk;
-
-    uint8_t mask;
-    uint16_t stat;
-    uint16_t dma;
-    uint16_t count;
-    int count_cur;
-    uint32_t fifo;
-    int rxlen;
-    int txlen;
-    uint16_t control;
-    uint16_t addr[2];
-    uint8_t divider;
-    uint8_t times[2];
-    uint16_t test;
-} OMAPI2CState;
-
-#define OMAP2_INTR_REV 0x34
-#define OMAP2_GC_REV   0x34
-
-static void omap_i2c_interrupts_update(OMAPI2CState *s)
-{
-    qemu_set_irq(s->irq, s->stat & s->mask);
-    if ((s->dma >> 15) & 1)                                    /* RDMA_EN */
-        qemu_set_irq(s->drq[0], (s->stat >> 3) & 1);           /* RRDY */
-    if ((s->dma >> 7) & 1)                                     /* XDMA_EN */
-        qemu_set_irq(s->drq[1], (s->stat >> 4) & 1);           /* XRDY */
-}
-
-static void omap_i2c_fifo_run(OMAPI2CState *s)
-{
-    int ack = 1;
-
-    if (!i2c_bus_busy(s->bus))
-        return;
-
-    if ((s->control >> 2) & 1) {                               /* RM */
-        if ((s->control >> 1) & 1) {                           /* STP */
-            i2c_end_transfer(s->bus);
-            s->control &= ~(1 << 1);                           /* STP */
-            s->count_cur = s->count;
-            s->txlen = 0;
-        } else if ((s->control >> 9) & 1) {                    /* TRX */
-            while (ack && s->txlen)
-                ack = (i2c_send(s->bus,
-                                        (s->fifo >> ((-- s->txlen) << 3)) &
-                                        0xff) >= 0);
-            s->stat |= 1 << 4;                                 /* XRDY */
-        } else {
-            while (s->rxlen < 4)
-                s->fifo |= i2c_recv(s->bus) << ((s->rxlen ++) << 3);
-            s->stat |= 1 << 3;                                 /* RRDY */
-        }
-    } else {
-        if ((s->control >> 9) & 1) {                           /* TRX */
-            while (ack && s->count_cur && s->txlen) {
-                ack = (i2c_send(s->bus,
-                                        (s->fifo >> ((-- s->txlen) << 3)) &
-                                        0xff) >= 0);
-                s->count_cur --;
-            }
-            if (ack && s->count_cur)
-                s->stat |= 1 << 4;                             /* XRDY */
-            else
-                s->stat &= ~(1 << 4);                          /* XRDY */
-            if (!s->count_cur) {
-                s->stat |= 1 << 2;                             /* ARDY */
-                s->control &= ~(1 << 10);                      /* MST */
-            }
-        } else {
-            while (s->count_cur && s->rxlen < 4) {
-                s->fifo |= i2c_recv(s->bus) << ((s->rxlen ++) << 3);
-                s->count_cur --;
-            }
-            if (s->rxlen)
-                s->stat |= 1 << 3;                             /* RRDY */
-            else
-                s->stat &= ~(1 << 3);                          /* RRDY */
-        }
-        if (!s->count_cur) {
-            if ((s->control >> 1) & 1) {                       /* STP */
-                i2c_end_transfer(s->bus);
-                s->control &= ~(1 << 1);                       /* STP */
-                s->count_cur = s->count;
-                s->txlen = 0;
-            } else {
-                s->stat |= 1 << 2;                             /* ARDY */
-                s->control &= ~(1 << 10);                      /* MST */
-            }
-        }
-    }
-
-    s->stat |= (!ack) << 1;                                    /* NACK */
-    if (!ack)
-        s->control &= ~(1 << 1);                               /* STP */
-}
-
-static void omap_i2c_reset(DeviceState *dev)
-{
-    OMAPI2CState *s = FROM_SYSBUS(OMAPI2CState,
-                                  SYS_BUS_DEVICE(dev));
-    s->mask = 0;
-    s->stat = 0;
-    s->dma = 0;
-    s->count = 0;
-    s->count_cur = 0;
-    s->fifo = 0;
-    s->rxlen = 0;
-    s->txlen = 0;
-    s->control = 0;
-    s->addr[0] = 0;
-    s->addr[1] = 0;
-    s->divider = 0;
-    s->times[0] = 0;
-    s->times[1] = 0;
-    s->test = 0;
-}
-
-static uint32_t omap_i2c_read(void *opaque, hwaddr addr)
-{
-    OMAPI2CState *s = opaque;
-    int offset = addr & OMAP_MPUI_REG_MASK;
-    uint16_t ret;
-
-    switch (offset) {
-    case 0x00: /* I2C_REV */
-        return s->revision;                                    /* REV */
-
-    case 0x04: /* I2C_IE */
-        return s->mask;
-
-    case 0x08: /* I2C_STAT */
-        return s->stat | (i2c_bus_busy(s->bus) << 12);
-
-    case 0x0c: /* I2C_IV */
-        if (s->revision >= OMAP2_INTR_REV)
-            break;
-        ret = ffs(s->stat & s->mask);
-        if (ret)
-            s->stat ^= 1 << (ret - 1);
-        omap_i2c_interrupts_update(s);
-        return ret;
-
-    case 0x10: /* I2C_SYSS */
-        return (s->control >> 15) & 1;                         /* I2C_EN */
-
-    case 0x14: /* I2C_BUF */
-        return s->dma;
-
-    case 0x18: /* I2C_CNT */
-        return s->count_cur;                                   /* DCOUNT */
-
-    case 0x1c: /* I2C_DATA */
-        ret = 0;
-        if (s->control & (1 << 14)) {                          /* BE */
-            ret |= ((s->fifo >> 0) & 0xff) << 8;
-            ret |= ((s->fifo >> 8) & 0xff) << 0;
-        } else {
-            ret |= ((s->fifo >> 8) & 0xff) << 8;
-            ret |= ((s->fifo >> 0) & 0xff) << 0;
-        }
-        if (s->rxlen == 1) {
-            s->stat |= 1 << 15;                                        /* SBD */
-            s->rxlen = 0;
-        } else if (s->rxlen > 1) {
-            if (s->rxlen > 2)
-                s->fifo >>= 16;
-            s->rxlen -= 2;
-        } else {
-            /* XXX: remote access (qualifier) error - what's that?  */
-        }
-        if (!s->rxlen) {
-            s->stat &= ~(1 << 3);                              /* RRDY */
-            if (((s->control >> 10) & 1) &&                    /* MST */
-                            ((~s->control >> 9) & 1)) {                /* TRX */
-                s->stat |= 1 << 2;                             /* ARDY */
-                s->control &= ~(1 << 10);                      /* MST */
-            }
-        }
-        s->stat &= ~(1 << 11);                                 /* ROVR */
-        omap_i2c_fifo_run(s);
-        omap_i2c_interrupts_update(s);
-        return ret;
-
-    case 0x20: /* I2C_SYSC */
-        return 0;
-
-    case 0x24: /* I2C_CON */
-        return s->control;
-
-    case 0x28: /* I2C_OA */
-        return s->addr[0];
-
-    case 0x2c: /* I2C_SA */
-        return s->addr[1];
-
-    case 0x30: /* I2C_PSC */
-        return s->divider;
-
-    case 0x34: /* I2C_SCLL */
-        return s->times[0];
-
-    case 0x38: /* I2C_SCLH */
-        return s->times[1];
-
-    case 0x3c: /* I2C_SYSTEST */
-        if (s->test & (1 << 15)) {                             /* ST_EN */
-            s->test ^= 0xa;
-            return s->test;
-        } else
-            return s->test & ~0x300f;
-    }
-
-    OMAP_BAD_REG(addr);
-    return 0;
-}
-
-static void omap_i2c_write(void *opaque, hwaddr addr,
-                uint32_t value)
-{
-    OMAPI2CState *s = opaque;
-    int offset = addr & OMAP_MPUI_REG_MASK;
-    int nack;
-
-    switch (offset) {
-    case 0x00: /* I2C_REV */
-    case 0x0c: /* I2C_IV */
-    case 0x10: /* I2C_SYSS */
-        OMAP_RO_REG(addr);
-        return;
-
-    case 0x04: /* I2C_IE */
-        s->mask = value & (s->revision < OMAP2_GC_REV ? 0x1f : 0x3f);
-        break;
-
-    case 0x08: /* I2C_STAT */
-        if (s->revision < OMAP2_INTR_REV) {
-            OMAP_RO_REG(addr);
-            return;
-        }
-
-        /* RRDY and XRDY are reset by hardware. (in all versions???) */
-        s->stat &= ~(value & 0x27);
-        omap_i2c_interrupts_update(s);
-        break;
-
-    case 0x14: /* I2C_BUF */
-        s->dma = value & 0x8080;
-        if (value & (1 << 15))                                 /* RDMA_EN */
-            s->mask &= ~(1 << 3);                              /* RRDY_IE */
-        if (value & (1 << 7))                                  /* XDMA_EN */
-            s->mask &= ~(1 << 4);                              /* XRDY_IE */
-        break;
-
-    case 0x18: /* I2C_CNT */
-        s->count = value;                                      /* DCOUNT */
-        break;
-
-    case 0x1c: /* I2C_DATA */
-        if (s->txlen > 2) {
-            /* XXX: remote access (qualifier) error - what's that?  */
-            break;
-        }
-        s->fifo <<= 16;
-        s->txlen += 2;
-        if (s->control & (1 << 14)) {                          /* BE */
-            s->fifo |= ((value >> 8) & 0xff) << 8;
-            s->fifo |= ((value >> 0) & 0xff) << 0;
-        } else {
-            s->fifo |= ((value >> 0) & 0xff) << 8;
-            s->fifo |= ((value >> 8) & 0xff) << 0;
-        }
-        s->stat &= ~(1 << 10);                                 /* XUDF */
-        if (s->txlen > 2)
-            s->stat &= ~(1 << 4);                              /* XRDY */
-        omap_i2c_fifo_run(s);
-        omap_i2c_interrupts_update(s);
-        break;
-
-    case 0x20: /* I2C_SYSC */
-        if (s->revision < OMAP2_INTR_REV) {
-            OMAP_BAD_REG(addr);
-            return;
-        }
-
-        if (value & 2)
-            omap_i2c_reset(&s->busdev.qdev);
-        break;
-
-    case 0x24: /* I2C_CON */
-        s->control = value & 0xcf87;
-        if (~value & (1 << 15)) {                              /* I2C_EN */
-            if (s->revision < OMAP2_INTR_REV)
-                omap_i2c_reset(&s->busdev.qdev);
-            break;
-        }
-        if ((value & (1 << 15)) && !(value & (1 << 10))) {     /* MST */
-            fprintf(stderr, "%s: I^2C slave mode not supported\n",
-                            __FUNCTION__);
-            break;
-        }
-        if ((value & (1 << 15)) && value & (1 << 8)) {         /* XA */
-            fprintf(stderr, "%s: 10-bit addressing mode not supported\n",
-                            __FUNCTION__);
-            break;
-        }
-        if ((value & (1 << 15)) && value & (1 << 0)) {         /* STT */
-            nack = !!i2c_start_transfer(s->bus, s->addr[1],    /* SA */
-                            (~value >> 9) & 1);                        /* TRX */
-            s->stat |= nack << 1;                              /* NACK */
-            s->control &= ~(1 << 0);                           /* STT */
-            s->fifo = 0;
-            if (nack)
-                s->control &= ~(1 << 1);                       /* STP */
-            else {
-                s->count_cur = s->count;
-                omap_i2c_fifo_run(s);
-            }
-            omap_i2c_interrupts_update(s);
-        }
-        break;
-
-    case 0x28: /* I2C_OA */
-        s->addr[0] = value & 0x3ff;
-        break;
-
-    case 0x2c: /* I2C_SA */
-        s->addr[1] = value & 0x3ff;
-        break;
-
-    case 0x30: /* I2C_PSC */
-        s->divider = value;
-        break;
-
-    case 0x34: /* I2C_SCLL */
-        s->times[0] = value;
-        break;
-
-    case 0x38: /* I2C_SCLH */
-        s->times[1] = value;
-        break;
-
-    case 0x3c: /* I2C_SYSTEST */
-        s->test = value & 0xf80f;
-        if (value & (1 << 11))                                 /* SBB */
-            if (s->revision >= OMAP2_INTR_REV) {
-                s->stat |= 0x3f;
-                omap_i2c_interrupts_update(s);
-            }
-        if (value & (1 << 15))                                 /* ST_EN */
-            fprintf(stderr, "%s: System Test not supported\n", __FUNCTION__);
-        break;
-
-    default:
-        OMAP_BAD_REG(addr);
-        return;
-    }
-}
-
-static void omap_i2c_writeb(void *opaque, hwaddr addr,
-                uint32_t value)
-{
-    OMAPI2CState *s = opaque;
-    int offset = addr & OMAP_MPUI_REG_MASK;
-
-    switch (offset) {
-    case 0x1c: /* I2C_DATA */
-        if (s->txlen > 2) {
-            /* XXX: remote access (qualifier) error - what's that?  */
-            break;
-        }
-        s->fifo <<= 8;
-        s->txlen += 1;
-        s->fifo |= value & 0xff;
-        s->stat &= ~(1 << 10);                                 /* XUDF */
-        if (s->txlen > 2)
-            s->stat &= ~(1 << 4);                              /* XRDY */
-        omap_i2c_fifo_run(s);
-        omap_i2c_interrupts_update(s);
-        break;
-
-    default:
-        OMAP_BAD_REG(addr);
-        return;
-    }
-}
-
-static const MemoryRegionOps omap_i2c_ops = {
-    .old_mmio = {
-        .read = {
-            omap_badwidth_read16,
-            omap_i2c_read,
-            omap_badwidth_read16,
-        },
-        .write = {
-            omap_i2c_writeb, /* Only the last fifo write can be 8 bit.  */
-            omap_i2c_write,
-            omap_badwidth_write16,
-        },
-    },
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int omap_i2c_init(SysBusDevice *dev)
-{
-    OMAPI2CState *s = FROM_SYSBUS(OMAPI2CState, dev);
-
-    if (!s->fclk) {
-        hw_error("omap_i2c: fclk not connected\n");
-    }
-    if (s->revision >= OMAP2_INTR_REV && !s->iclk) {
-        /* Note that OMAP1 doesn't have a separate interface clock */
-        hw_error("omap_i2c: iclk not connected\n");
-    }
-    sysbus_init_irq(dev, &s->irq);
-    sysbus_init_irq(dev, &s->drq[0]);
-    sysbus_init_irq(dev, &s->drq[1]);
-    memory_region_init_io(&s->iomem, &omap_i2c_ops, s, "omap.i2c",
-                          (s->revision < OMAP2_INTR_REV) ? 0x800 : 0x1000);
-    sysbus_init_mmio(dev, &s->iomem);
-    s->bus = i2c_init_bus(&dev->qdev, NULL);
-    return 0;
-}
-
-static Property omap_i2c_properties[] = {
-    DEFINE_PROP_UINT8("revision", OMAPI2CState, revision, 0),
-    DEFINE_PROP_PTR("iclk", OMAPI2CState, iclk),
-    DEFINE_PROP_PTR("fclk", OMAPI2CState, fclk),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void omap_i2c_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-    k->init = omap_i2c_init;
-    dc->props = omap_i2c_properties;
-    dc->reset = omap_i2c_reset;
-}
-
-static const TypeInfo omap_i2c_info = {
-    .name = "omap_i2c",
-    .parent = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(OMAPI2CState),
-    .class_init = omap_i2c_class_init,
-};
-
-static void omap_i2c_register_types(void)
-{
-    type_register_static(&omap_i2c_info);
-}
-
-i2c_bus *omap_i2c_bus(DeviceState *omap_i2c)
-{
-    OMAPI2CState *s = FROM_SYSBUS(OMAPI2CState, SYS_BUS_DEVICE(omap_i2c));
-    return s->bus;
-}
-
-type_init(omap_i2c_register_types)
diff --git a/hw/omap_intc.c b/hw/omap_intc.c
deleted file mode 100644 (file)
index 7da9c35..0000000
+++ /dev/null
@@ -1,649 +0,0 @@
-/*
- * TI OMAP interrupt controller emulation.
- *
- * Copyright (C) 2006-2008 Andrzej Zaborowski  <balrog@zabor.org>
- * Copyright (C) 2007-2008 Nokia Corporation
- *
- * 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 or
- * (at your option) version 3 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
- * 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 "hw/hw.h"
-#include "hw/omap.h"
-#include "hw/sysbus.h"
-
-/* Interrupt Handlers */
-struct omap_intr_handler_bank_s {
-    uint32_t irqs;
-    uint32_t inputs;
-    uint32_t mask;
-    uint32_t fiq;
-    uint32_t sens_edge;
-    uint32_t swi;
-    unsigned char priority[32];
-};
-
-struct omap_intr_handler_s {
-    SysBusDevice busdev;
-    qemu_irq *pins;
-    qemu_irq parent_intr[2];
-    MemoryRegion mmio;
-    void *iclk;
-    void *fclk;
-    unsigned char nbanks;
-    int level_only;
-    uint32_t size;
-
-    uint8_t revision;
-
-    /* state */
-    uint32_t new_agr[2];
-    int sir_intr[2];
-    int autoidle;
-    uint32_t mask;
-    struct omap_intr_handler_bank_s bank[3];
-};
-
-static void omap_inth_sir_update(struct omap_intr_handler_s *s, int is_fiq)
-{
-    int i, j, sir_intr, p_intr, p, f;
-    uint32_t level;
-    sir_intr = 0;
-    p_intr = 255;
-
-    /* Find the interrupt line with the highest dynamic priority.
-     * Note: 0 denotes the hightest priority.
-     * If all interrupts have the same priority, the default order is IRQ_N,
-     * IRQ_N-1,...,IRQ_0. */
-    for (j = 0; j < s->nbanks; ++j) {
-        level = s->bank[j].irqs & ~s->bank[j].mask &
-                (is_fiq ? s->bank[j].fiq : ~s->bank[j].fiq);
-        for (f = ffs(level), i = f - 1, level >>= f - 1; f; i += f,
-                        level >>= f) {
-            p = s->bank[j].priority[i];
-            if (p <= p_intr) {
-                p_intr = p;
-                sir_intr = 32 * j + i;
-            }
-            f = ffs(level >> 1);
-        }
-    }
-    s->sir_intr[is_fiq] = sir_intr;
-}
-
-static inline void omap_inth_update(struct omap_intr_handler_s *s, int is_fiq)
-{
-    int i;
-    uint32_t has_intr = 0;
-
-    for (i = 0; i < s->nbanks; ++i)
-        has_intr |= s->bank[i].irqs & ~s->bank[i].mask &
-                (is_fiq ? s->bank[i].fiq : ~s->bank[i].fiq);
-
-    if (s->new_agr[is_fiq] & has_intr & s->mask) {
-        s->new_agr[is_fiq] = 0;
-        omap_inth_sir_update(s, is_fiq);
-        qemu_set_irq(s->parent_intr[is_fiq], 1);
-    }
-}
-
-#define INT_FALLING_EDGE       0
-#define INT_LOW_LEVEL          1
-
-static void omap_set_intr(void *opaque, int irq, int req)
-{
-    struct omap_intr_handler_s *ih = (struct omap_intr_handler_s *) opaque;
-    uint32_t rise;
-
-    struct omap_intr_handler_bank_s *bank = &ih->bank[irq >> 5];
-    int n = irq & 31;
-
-    if (req) {
-        rise = ~bank->irqs & (1 << n);
-        if (~bank->sens_edge & (1 << n))
-            rise &= ~bank->inputs;
-
-        bank->inputs |= (1 << n);
-        if (rise) {
-            bank->irqs |= rise;
-            omap_inth_update(ih, 0);
-            omap_inth_update(ih, 1);
-        }
-    } else {
-        rise = bank->sens_edge & bank->irqs & (1 << n);
-        bank->irqs &= ~rise;
-        bank->inputs &= ~(1 << n);
-    }
-}
-
-/* Simplified version with no edge detection */
-static void omap_set_intr_noedge(void *opaque, int irq, int req)
-{
-    struct omap_intr_handler_s *ih = (struct omap_intr_handler_s *) opaque;
-    uint32_t rise;
-
-    struct omap_intr_handler_bank_s *bank = &ih->bank[irq >> 5];
-    int n = irq & 31;
-
-    if (req) {
-        rise = ~bank->inputs & (1 << n);
-        if (rise) {
-            bank->irqs |= bank->inputs |= rise;
-            omap_inth_update(ih, 0);
-            omap_inth_update(ih, 1);
-        }
-    } else
-        bank->irqs = (bank->inputs &= ~(1 << n)) | bank->swi;
-}
-
-static uint64_t omap_inth_read(void *opaque, hwaddr addr,
-                               unsigned size)
-{
-    struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque;
-    int i, offset = addr;
-    int bank_no = offset >> 8;
-    int line_no;
-    struct omap_intr_handler_bank_s *bank = &s->bank[bank_no];
-    offset &= 0xff;
-
-    switch (offset) {
-    case 0x00: /* ITR */
-        return bank->irqs;
-
-    case 0x04: /* MIR */
-        return bank->mask;
-
-    case 0x10: /* SIR_IRQ_CODE */
-    case 0x14:  /* SIR_FIQ_CODE */
-        if (bank_no != 0)
-            break;
-        line_no = s->sir_intr[(offset - 0x10) >> 2];
-        bank = &s->bank[line_no >> 5];
-        i = line_no & 31;
-        if (((bank->sens_edge >> i) & 1) == INT_FALLING_EDGE)
-            bank->irqs &= ~(1 << i);
-        return line_no;
-
-    case 0x18: /* CONTROL_REG */
-        if (bank_no != 0)
-            break;
-        return 0;
-
-    case 0x1c: /* ILR0 */
-    case 0x20: /* ILR1 */
-    case 0x24: /* ILR2 */
-    case 0x28: /* ILR3 */
-    case 0x2c: /* ILR4 */
-    case 0x30: /* ILR5 */
-    case 0x34: /* ILR6 */
-    case 0x38: /* ILR7 */
-    case 0x3c: /* ILR8 */
-    case 0x40: /* ILR9 */
-    case 0x44: /* ILR10 */
-    case 0x48: /* ILR11 */
-    case 0x4c: /* ILR12 */
-    case 0x50: /* ILR13 */
-    case 0x54: /* ILR14 */
-    case 0x58: /* ILR15 */
-    case 0x5c: /* ILR16 */
-    case 0x60: /* ILR17 */
-    case 0x64: /* ILR18 */
-    case 0x68: /* ILR19 */
-    case 0x6c: /* ILR20 */
-    case 0x70: /* ILR21 */
-    case 0x74: /* ILR22 */
-    case 0x78: /* ILR23 */
-    case 0x7c: /* ILR24 */
-    case 0x80: /* ILR25 */
-    case 0x84: /* ILR26 */
-    case 0x88: /* ILR27 */
-    case 0x8c: /* ILR28 */
-    case 0x90: /* ILR29 */
-    case 0x94: /* ILR30 */
-    case 0x98: /* ILR31 */
-        i = (offset - 0x1c) >> 2;
-        return (bank->priority[i] << 2) |
-                (((bank->sens_edge >> i) & 1) << 1) |
-                ((bank->fiq >> i) & 1);
-
-    case 0x9c: /* ISR */
-        return 0x00000000;
-
-    }
-    OMAP_BAD_REG(addr);
-    return 0;
-}
-
-static void omap_inth_write(void *opaque, hwaddr addr,
-                            uint64_t value, unsigned size)
-{
-    struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque;
-    int i, offset = addr;
-    int bank_no = offset >> 8;
-    struct omap_intr_handler_bank_s *bank = &s->bank[bank_no];
-    offset &= 0xff;
-
-    switch (offset) {
-    case 0x00: /* ITR */
-        /* Important: ignore the clearing if the IRQ is level-triggered and
-           the input bit is 1 */
-        bank->irqs &= value | (bank->inputs & bank->sens_edge);
-        return;
-
-    case 0x04: /* MIR */
-        bank->mask = value;
-        omap_inth_update(s, 0);
-        omap_inth_update(s, 1);
-        return;
-
-    case 0x10: /* SIR_IRQ_CODE */
-    case 0x14: /* SIR_FIQ_CODE */
-        OMAP_RO_REG(addr);
-        break;
-
-    case 0x18: /* CONTROL_REG */
-        if (bank_no != 0)
-            break;
-        if (value & 2) {
-            qemu_set_irq(s->parent_intr[1], 0);
-            s->new_agr[1] = ~0;
-            omap_inth_update(s, 1);
-        }
-        if (value & 1) {
-            qemu_set_irq(s->parent_intr[0], 0);
-            s->new_agr[0] = ~0;
-            omap_inth_update(s, 0);
-        }
-        return;
-
-    case 0x1c: /* ILR0 */
-    case 0x20: /* ILR1 */
-    case 0x24: /* ILR2 */
-    case 0x28: /* ILR3 */
-    case 0x2c: /* ILR4 */
-    case 0x30: /* ILR5 */
-    case 0x34: /* ILR6 */
-    case 0x38: /* ILR7 */
-    case 0x3c: /* ILR8 */
-    case 0x40: /* ILR9 */
-    case 0x44: /* ILR10 */
-    case 0x48: /* ILR11 */
-    case 0x4c: /* ILR12 */
-    case 0x50: /* ILR13 */
-    case 0x54: /* ILR14 */
-    case 0x58: /* ILR15 */
-    case 0x5c: /* ILR16 */
-    case 0x60: /* ILR17 */
-    case 0x64: /* ILR18 */
-    case 0x68: /* ILR19 */
-    case 0x6c: /* ILR20 */
-    case 0x70: /* ILR21 */
-    case 0x74: /* ILR22 */
-    case 0x78: /* ILR23 */
-    case 0x7c: /* ILR24 */
-    case 0x80: /* ILR25 */
-    case 0x84: /* ILR26 */
-    case 0x88: /* ILR27 */
-    case 0x8c: /* ILR28 */
-    case 0x90: /* ILR29 */
-    case 0x94: /* ILR30 */
-    case 0x98: /* ILR31 */
-        i = (offset - 0x1c) >> 2;
-        bank->priority[i] = (value >> 2) & 0x1f;
-        bank->sens_edge &= ~(1 << i);
-        bank->sens_edge |= ((value >> 1) & 1) << i;
-        bank->fiq &= ~(1 << i);
-        bank->fiq |= (value & 1) << i;
-        return;
-
-    case 0x9c: /* ISR */
-        for (i = 0; i < 32; i ++)
-            if (value & (1 << i)) {
-                omap_set_intr(s, 32 * bank_no + i, 1);
-                return;
-            }
-        return;
-    }
-    OMAP_BAD_REG(addr);
-}
-
-static const MemoryRegionOps omap_inth_mem_ops = {
-    .read = omap_inth_read,
-    .write = omap_inth_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-};
-
-static void omap_inth_reset(DeviceState *dev)
-{
-    struct omap_intr_handler_s *s = FROM_SYSBUS(struct omap_intr_handler_s,
-                                                SYS_BUS_DEVICE(dev));
-    int i;
-
-    for (i = 0; i < s->nbanks; ++i){
-        s->bank[i].irqs = 0x00000000;
-        s->bank[i].mask = 0xffffffff;
-        s->bank[i].sens_edge = 0x00000000;
-        s->bank[i].fiq = 0x00000000;
-        s->bank[i].inputs = 0x00000000;
-        s->bank[i].swi = 0x00000000;
-        memset(s->bank[i].priority, 0, sizeof(s->bank[i].priority));
-
-        if (s->level_only)
-            s->bank[i].sens_edge = 0xffffffff;
-    }
-
-    s->new_agr[0] = ~0;
-    s->new_agr[1] = ~0;
-    s->sir_intr[0] = 0;
-    s->sir_intr[1] = 0;
-    s->autoidle = 0;
-    s->mask = ~0;
-
-    qemu_set_irq(s->parent_intr[0], 0);
-    qemu_set_irq(s->parent_intr[1], 0);
-}
-
-static int omap_intc_init(SysBusDevice *dev)
-{
-    struct omap_intr_handler_s *s;
-    s = FROM_SYSBUS(struct omap_intr_handler_s, dev);
-    if (!s->iclk) {
-        hw_error("omap-intc: clk not connected\n");
-    }
-    s->nbanks = 1;
-    sysbus_init_irq(dev, &s->parent_intr[0]);
-    sysbus_init_irq(dev, &s->parent_intr[1]);
-    qdev_init_gpio_in(&dev->qdev, omap_set_intr, s->nbanks * 32);
-    memory_region_init_io(&s->mmio, &omap_inth_mem_ops, s,
-                          "omap-intc", s->size);
-    sysbus_init_mmio(dev, &s->mmio);
-    return 0;
-}
-
-static Property omap_intc_properties[] = {
-    DEFINE_PROP_UINT32("size", struct omap_intr_handler_s, size, 0x100),
-    DEFINE_PROP_PTR("clk", struct omap_intr_handler_s, iclk),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void omap_intc_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = omap_intc_init;
-    dc->reset = omap_inth_reset;
-    dc->props = omap_intc_properties;
-}
-
-static const 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, hwaddr addr,
-                                unsigned size)
-{
-    struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque;
-    int offset = addr;
-    int bank_no, line_no;
-    struct omap_intr_handler_bank_s *bank = NULL;
-
-    if ((offset & 0xf80) == 0x80) {
-        bank_no = (offset & 0x60) >> 5;
-        if (bank_no < s->nbanks) {
-            offset &= ~0x60;
-            bank = &s->bank[bank_no];
-        } else {
-            OMAP_BAD_REG(addr);
-            return 0;
-        }
-    }
-
-    switch (offset) {
-    case 0x00: /* INTC_REVISION */
-        return s->revision;
-
-    case 0x10: /* INTC_SYSCONFIG */
-        return (s->autoidle >> 2) & 1;
-
-    case 0x14: /* INTC_SYSSTATUS */
-        return 1;                                              /* RESETDONE */
-
-    case 0x40: /* INTC_SIR_IRQ */
-        return s->sir_intr[0];
-
-    case 0x44: /* INTC_SIR_FIQ */
-        return s->sir_intr[1];
-
-    case 0x48: /* INTC_CONTROL */
-        return (!s->mask) << 2;                                        /* GLOBALMASK */
-
-    case 0x4c: /* INTC_PROTECTION */
-        return 0;
-
-    case 0x50: /* INTC_IDLE */
-        return s->autoidle & 3;
-
-    /* Per-bank registers */
-    case 0x80: /* INTC_ITR */
-        return bank->inputs;
-
-    case 0x84: /* INTC_MIR */
-        return bank->mask;
-
-    case 0x88: /* INTC_MIR_CLEAR */
-    case 0x8c: /* INTC_MIR_SET */
-        return 0;
-
-    case 0x90: /* INTC_ISR_SET */
-        return bank->swi;
-
-    case 0x94: /* INTC_ISR_CLEAR */
-        return 0;
-
-    case 0x98: /* INTC_PENDING_IRQ */
-        return bank->irqs & ~bank->mask & ~bank->fiq;
-
-    case 0x9c: /* INTC_PENDING_FIQ */
-        return bank->irqs & ~bank->mask & bank->fiq;
-
-    /* Per-line registers */
-    case 0x100 ... 0x300:      /* INTC_ILR */
-        bank_no = (offset - 0x100) >> 7;
-        if (bank_no > s->nbanks)
-            break;
-        bank = &s->bank[bank_no];
-        line_no = (offset & 0x7f) >> 2;
-        return (bank->priority[line_no] << 2) |
-                ((bank->fiq >> line_no) & 1);
-    }
-    OMAP_BAD_REG(addr);
-    return 0;
-}
-
-static void omap2_inth_write(void *opaque, hwaddr addr,
-                             uint64_t value, unsigned size)
-{
-    struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque;
-    int offset = addr;
-    int bank_no, line_no;
-    struct omap_intr_handler_bank_s *bank = NULL;
-
-    if ((offset & 0xf80) == 0x80) {
-        bank_no = (offset & 0x60) >> 5;
-        if (bank_no < s->nbanks) {
-            offset &= ~0x60;
-            bank = &s->bank[bank_no];
-        } else {
-            OMAP_BAD_REG(addr);
-            return;
-        }
-    }
-
-    switch (offset) {
-    case 0x10: /* INTC_SYSCONFIG */
-        s->autoidle &= 4;
-        s->autoidle |= (value & 1) << 2;
-        if (value & 2)                                         /* SOFTRESET */
-            omap_inth_reset(&s->busdev.qdev);
-        return;
-
-    case 0x48: /* INTC_CONTROL */
-        s->mask = (value & 4) ? 0 : ~0;                                /* GLOBALMASK */
-        if (value & 2) {                                       /* NEWFIQAGR */
-            qemu_set_irq(s->parent_intr[1], 0);
-            s->new_agr[1] = ~0;
-            omap_inth_update(s, 1);
-        }
-        if (value & 1) {                                       /* NEWIRQAGR */
-            qemu_set_irq(s->parent_intr[0], 0);
-            s->new_agr[0] = ~0;
-            omap_inth_update(s, 0);
-        }
-        return;
-
-    case 0x4c: /* INTC_PROTECTION */
-        /* TODO: Make a bitmap (or sizeof(char)map) of access privileges
-         * for every register, see Chapter 3 and 4 for privileged mode.  */
-        if (value & 1)
-            fprintf(stderr, "%s: protection mode enable attempt\n",
-                            __FUNCTION__);
-        return;
-
-    case 0x50: /* INTC_IDLE */
-        s->autoidle &= ~3;
-        s->autoidle |= value & 3;
-        return;
-
-    /* Per-bank registers */
-    case 0x84: /* INTC_MIR */
-        bank->mask = value;
-        omap_inth_update(s, 0);
-        omap_inth_update(s, 1);
-        return;
-
-    case 0x88: /* INTC_MIR_CLEAR */
-        bank->mask &= ~value;
-        omap_inth_update(s, 0);
-        omap_inth_update(s, 1);
-        return;
-
-    case 0x8c: /* INTC_MIR_SET */
-        bank->mask |= value;
-        return;
-
-    case 0x90: /* INTC_ISR_SET */
-        bank->irqs |= bank->swi |= value;
-        omap_inth_update(s, 0);
-        omap_inth_update(s, 1);
-        return;
-
-    case 0x94: /* INTC_ISR_CLEAR */
-        bank->swi &= ~value;
-        bank->irqs = bank->swi & bank->inputs;
-        return;
-
-    /* Per-line registers */
-    case 0x100 ... 0x300:      /* INTC_ILR */
-        bank_no = (offset - 0x100) >> 7;
-        if (bank_no > s->nbanks)
-            break;
-        bank = &s->bank[bank_no];
-        line_no = (offset & 0x7f) >> 2;
-        bank->priority[line_no] = (value >> 2) & 0x3f;
-        bank->fiq &= ~(1 << line_no);
-        bank->fiq |= (value & 1) << line_no;
-        return;
-
-    case 0x00: /* INTC_REVISION */
-    case 0x14: /* INTC_SYSSTATUS */
-    case 0x40: /* INTC_SIR_IRQ */
-    case 0x44: /* INTC_SIR_FIQ */
-    case 0x80: /* INTC_ITR */
-    case 0x98: /* INTC_PENDING_IRQ */
-    case 0x9c: /* INTC_PENDING_FIQ */
-        OMAP_RO_REG(addr);
-        return;
-    }
-    OMAP_BAD_REG(addr);
-}
-
-static const MemoryRegionOps omap2_inth_mem_ops = {
-    .read = omap2_inth_read,
-    .write = omap2_inth_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-};
-
-static int omap2_intc_init(SysBusDevice *dev)
-{
-    struct omap_intr_handler_s *s;
-    s = FROM_SYSBUS(struct omap_intr_handler_s, dev);
-    if (!s->iclk) {
-        hw_error("omap2-intc: iclk not connected\n");
-    }
-    if (!s->fclk) {
-        hw_error("omap2-intc: fclk not connected\n");
-    }
-    s->level_only = 1;
-    s->nbanks = 3;
-    sysbus_init_irq(dev, &s->parent_intr[0]);
-    sysbus_init_irq(dev, &s->parent_intr[1]);
-    qdev_init_gpio_in(&dev->qdev, omap_set_intr_noedge, s->nbanks * 32);
-    memory_region_init_io(&s->mmio, &omap2_inth_mem_ops, s,
-                          "omap2-intc", 0x1000);
-    sysbus_init_mmio(dev, &s->mmio);
-    return 0;
-}
-
-static Property omap2_intc_properties[] = {
-    DEFINE_PROP_UINT8("revision", struct omap_intr_handler_s,
-    revision, 0x21),
-    DEFINE_PROP_PTR("iclk", struct omap_intr_handler_s, iclk),
-    DEFINE_PROP_PTR("fclk", struct omap_intr_handler_s, fclk),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void omap2_intc_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = omap2_intc_init;
-    dc->reset = omap_inth_reset;
-    dc->props = omap2_intc_properties;
-}
-
-static const 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_types(void)
-{
-    type_register_static(&omap_intc_info);
-    type_register_static(&omap2_intc_info);
-}
-
-type_init(omap_intc_register_types)
diff --git a/hw/omap_l4.c b/hw/omap_l4.c
deleted file mode 100644 (file)
index cbe8a06..0000000
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * TI OMAP L4 interconnect emulation.
- *
- * Copyright (C) 2007-2009 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.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 or
- * (at your option) any later version 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
- * 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 "hw/hw.h"
-#include "hw/omap.h"
-
-struct omap_l4_s {
-    MemoryRegion *address_space;
-    hwaddr base;
-    int ta_num;
-    struct omap_target_agent_s ta[0];
-};
-
-struct omap_l4_s *omap_l4_init(MemoryRegion *address_space,
-                               hwaddr base, int ta_num)
-{
-    struct omap_l4_s *bus = g_malloc0(
-                    sizeof(*bus) + ta_num * sizeof(*bus->ta));
-
-    bus->address_space = address_space;
-    bus->ta_num = ta_num;
-    bus->base = base;
-
-    return bus;
-}
-
-hwaddr omap_l4_region_base(struct omap_target_agent_s *ta,
-                                       int region)
-{
-    return ta->bus->base + ta->start[region].offset;
-}
-
-hwaddr omap_l4_region_size(struct omap_target_agent_s *ta,
-                                       int region)
-{
-    return ta->start[region].size;
-}
-
-static uint64_t omap_l4ta_read(void *opaque, hwaddr addr,
-                               unsigned size)
-{
-    struct omap_target_agent_s *s = (struct omap_target_agent_s *) opaque;
-
-    if (size != 2) {
-        return omap_badwidth_read16(opaque, addr);
-    }
-
-    switch (addr) {
-    case 0x00: /* COMPONENT */
-        return s->component;
-
-    case 0x20: /* AGENT_CONTROL */
-        return s->control;
-
-    case 0x28: /* AGENT_STATUS */
-        return s->status;
-    }
-
-    OMAP_BAD_REG(addr);
-    return 0;
-}
-
-static void omap_l4ta_write(void *opaque, hwaddr addr,
-                            uint64_t value, unsigned size)
-{
-    struct omap_target_agent_s *s = (struct omap_target_agent_s *) opaque;
-
-    if (size != 4) {
-        return omap_badwidth_write32(opaque, addr, value);
-    }
-
-    switch (addr) {
-    case 0x00: /* COMPONENT */
-    case 0x28: /* AGENT_STATUS */
-        OMAP_RO_REG(addr);
-        break;
-
-    case 0x20: /* AGENT_CONTROL */
-        s->control = value & 0x01000700;
-        if (value & 1)                                 /* OCP_RESET */
-            s->status &= ~1;                           /* REQ_TIMEOUT */
-        break;
-
-    default:
-        OMAP_BAD_REG(addr);
-    }
-}
-
-static const MemoryRegionOps omap_l4ta_ops = {
-    .read = omap_l4ta_read,
-    .write = omap_l4ta_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-struct omap_target_agent_s *omap_l4ta_get(struct omap_l4_s *bus,
-        const struct omap_l4_region_s *regions,
-       const struct omap_l4_agent_info_s *agents,
-       int cs)
-{
-    int i;
-    struct omap_target_agent_s *ta = NULL;
-    const struct omap_l4_agent_info_s *info = NULL;
-
-    for (i = 0; i < bus->ta_num; i ++)
-        if (agents[i].ta == cs) {
-            ta = &bus->ta[i];
-            info = &agents[i];
-            break;
-        }
-    if (!ta) {
-        fprintf(stderr, "%s: bad target agent (%i)\n", __FUNCTION__, cs);
-        exit(-1);
-    }
-
-    ta->bus = bus;
-    ta->start = &regions[info->region];
-    ta->regions = info->regions;
-
-    ta->component = ('Q' << 24) | ('E' << 16) | ('M' << 8) | ('U' << 0);
-    ta->status = 0x00000000;
-    ta->control = 0x00000200;  /* XXX 01000200 for L4TAO */
-
-    memory_region_init_io(&ta->iomem, &omap_l4ta_ops, ta, "omap.l4ta",
-                          omap_l4_region_size(ta, info->ta_region));
-    omap_l4_attach(ta, info->ta_region, &ta->iomem);
-
-    return ta;
-}
-
-hwaddr omap_l4_attach(struct omap_target_agent_s *ta,
-                                         int region, MemoryRegion *mr)
-{
-    hwaddr base;
-
-    if (region < 0 || region >= ta->regions) {
-        fprintf(stderr, "%s: bad io region (%i)\n", __FUNCTION__, region);
-        exit(-1);
-    }
-
-    base = ta->bus->base + ta->start[region].offset;
-    if (mr) {
-        memory_region_add_subregion(ta->bus->address_space, base, mr);
-    }
-
-    return base;
-}
diff --git a/hw/omap_lcd_template.h b/hw/omap_lcd_template.h
deleted file mode 100644 (file)
index 2fb96f8..0000000
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * QEMU OMAP LCD Emulator templates
- *
- * Copyright (c) 2006 Andrzej Zaborowski  <balrog@zabor.org>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS''
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
- * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#if DEPTH == 8
-# define BPP 1
-# define PIXEL_TYPE uint8_t
-#elif DEPTH == 15 || DEPTH == 16
-# define BPP 2
-# define PIXEL_TYPE uint16_t
-#elif DEPTH == 32
-# define BPP 4
-# define PIXEL_TYPE uint32_t
-#else
-# error unsupport depth
-#endif
-
-/*
- * 2-bit colour
- */
-static void glue(draw_line2_, DEPTH)(void *opaque,
-                uint8_t *d, const uint8_t *s, int width, int deststep)
-{
-    uint16_t *pal = opaque;
-    uint8_t v, r, g, b;
-
-    do {
-        v = ldub_raw((void *) s);
-        r = (pal[v & 3] >> 4) & 0xf0;
-        g = pal[v & 3] & 0xf0;
-        b = (pal[v & 3] << 4) & 0xf0;
-        ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
-        d += BPP;
-        v >>= 2;
-        r = (pal[v & 3] >> 4) & 0xf0;
-        g = pal[v & 3] & 0xf0;
-        b = (pal[v & 3] << 4) & 0xf0;
-        ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
-        d += BPP;
-        v >>= 2;
-        r = (pal[v & 3] >> 4) & 0xf0;
-        g = pal[v & 3] & 0xf0;
-        b = (pal[v & 3] << 4) & 0xf0;
-        ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
-        d += BPP;
-        v >>= 2;
-        r = (pal[v & 3] >> 4) & 0xf0;
-        g = pal[v & 3] & 0xf0;
-        b = (pal[v & 3] << 4) & 0xf0;
-        ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
-        d += BPP;
-        s ++;
-        width -= 4;
-    } while (width > 0);
-}
-
-/*
- * 4-bit colour
- */
-static void glue(draw_line4_, DEPTH)(void *opaque,
-                uint8_t *d, const uint8_t *s, int width, int deststep)
-{
-    uint16_t *pal = opaque;
-    uint8_t v, r, g, b;
-
-    do {
-        v = ldub_raw((void *) s);
-        r = (pal[v & 0xf] >> 4) & 0xf0;
-        g = pal[v & 0xf] & 0xf0;
-        b = (pal[v & 0xf] << 4) & 0xf0;
-        ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
-        d += BPP;
-        v >>= 4;
-        r = (pal[v & 0xf] >> 4) & 0xf0;
-        g = pal[v & 0xf] & 0xf0;
-        b = (pal[v & 0xf] << 4) & 0xf0;
-        ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
-        d += BPP;
-        s ++;
-        width -= 2;
-    } while (width > 0);
-}
-
-/*
- * 8-bit colour
- */
-static void glue(draw_line8_, DEPTH)(void *opaque,
-                uint8_t *d, const uint8_t *s, int width, int deststep)
-{
-    uint16_t *pal = opaque;
-    uint8_t v, r, g, b;
-
-    do {
-        v = ldub_raw((void *) s);
-        r = (pal[v] >> 4) & 0xf0;
-        g = pal[v] & 0xf0;
-        b = (pal[v] << 4) & 0xf0;
-        ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
-        s ++;
-        d += BPP;
-    } while (-- width != 0);
-}
-
-/*
- * 12-bit colour
- */
-static void glue(draw_line12_, DEPTH)(void *opaque,
-                uint8_t *d, const uint8_t *s, int width, int deststep)
-{
-    uint16_t v;
-    uint8_t r, g, b;
-
-    do {
-        v = lduw_raw((void *) s);
-        r = (v >> 4) & 0xf0;
-        g = v & 0xf0;
-        b = (v << 4) & 0xf0;
-        ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
-        s += 2;
-        d += BPP;
-    } while (-- width != 0);
-}
-
-/*
- * 16-bit colour
- */
-static void glue(draw_line16_, DEPTH)(void *opaque,
-                uint8_t *d, const uint8_t *s, int width, int deststep)
-{
-#if DEPTH == 16 && defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
-    memcpy(d, s, width * 2);
-#else
-    uint16_t v;
-    uint8_t r, g, b;
-
-    do {
-        v = lduw_raw((void *) s);
-        r = (v >> 8) & 0xf8;
-        g = (v >> 3) & 0xfc;
-        b = (v << 3) & 0xf8;
-        ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
-        s += 2;
-        d += BPP;
-    } while (-- width != 0);
-#endif
-}
-
-#undef DEPTH
-#undef BPP
-#undef PIXEL_TYPE
diff --git a/hw/omap_lcdc.c b/hw/omap_lcdc.c
deleted file mode 100644 (file)
index 4f5b094..0000000
+++ /dev/null
@@ -1,493 +0,0 @@
-/*
- * OMAP LCD controller.
- *
- * Copyright (C) 2006-2007 Andrzej Zaborowski  <balrog@zabor.org>
- *
- * 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 "hw/hw.h"
-#include "ui/console.h"
-#include "hw/omap.h"
-#include "hw/framebuffer.h"
-#include "ui/pixel_ops.h"
-
-struct omap_lcd_panel_s {
-    MemoryRegion *sysmem;
-    MemoryRegion iomem;
-    qemu_irq irq;
-    QemuConsole *con;
-
-    int plm;
-    int tft;
-    int mono;
-    int enable;
-    int width;
-    int height;
-    int interrupts;
-    uint32_t timing[3];
-    uint32_t subpanel;
-    uint32_t ctrl;
-
-    struct omap_dma_lcd_channel_s *dma;
-    uint16_t palette[256];
-    int palette_done;
-    int frame_done;
-    int invalidate;
-    int sync_error;
-};
-
-static void omap_lcd_interrupts(struct omap_lcd_panel_s *s)
-{
-    if (s->frame_done && (s->interrupts & 1)) {
-        qemu_irq_raise(s->irq);
-        return;
-    }
-
-    if (s->palette_done && (s->interrupts & 2)) {
-        qemu_irq_raise(s->irq);
-        return;
-    }
-
-    if (s->sync_error) {
-        qemu_irq_raise(s->irq);
-        return;
-    }
-
-    qemu_irq_lower(s->irq);
-}
-
-#define draw_line_func drawfn
-
-#define DEPTH 8
-#include "hw/omap_lcd_template.h"
-#define DEPTH 15
-#include "hw/omap_lcd_template.h"
-#define DEPTH 16
-#include "hw/omap_lcd_template.h"
-#define DEPTH 32
-#include "hw/omap_lcd_template.h"
-
-static draw_line_func draw_line_table2[33] = {
-    [0 ... 32] = NULL,
-    [8]                = draw_line2_8,
-    [15]       = draw_line2_15,
-    [16]       = draw_line2_16,
-    [32]       = draw_line2_32,
-}, draw_line_table4[33] = {
-    [0 ... 32] = NULL,
-    [8]                = draw_line4_8,
-    [15]       = draw_line4_15,
-    [16]       = draw_line4_16,
-    [32]       = draw_line4_32,
-}, draw_line_table8[33] = {
-    [0 ... 32] = NULL,
-    [8]                = draw_line8_8,
-    [15]       = draw_line8_15,
-    [16]       = draw_line8_16,
-    [32]       = draw_line8_32,
-}, draw_line_table12[33] = {
-    [0 ... 32] = NULL,
-    [8]                = draw_line12_8,
-    [15]       = draw_line12_15,
-    [16]       = draw_line12_16,
-    [32]       = draw_line12_32,
-}, draw_line_table16[33] = {
-    [0 ... 32] = NULL,
-    [8]                = draw_line16_8,
-    [15]       = draw_line16_15,
-    [16]       = draw_line16_16,
-    [32]       = draw_line16_32,
-};
-
-static void omap_update_display(void *opaque)
-{
-    struct omap_lcd_panel_s *omap_lcd = (struct omap_lcd_panel_s *) opaque;
-    DisplaySurface *surface = qemu_console_surface(omap_lcd->con);
-    draw_line_func draw_line;
-    int size, height, first, last;
-    int width, linesize, step, bpp, frame_offset;
-    hwaddr frame_base;
-
-    if (!omap_lcd || omap_lcd->plm == 1 || !omap_lcd->enable ||
-        !surface_bits_per_pixel(surface)) {
-        return;
-    }
-
-    frame_offset = 0;
-    if (omap_lcd->plm != 2) {
-        cpu_physical_memory_read(omap_lcd->dma->phys_framebuffer[
-                                  omap_lcd->dma->current_frame],
-                                 (void *)omap_lcd->palette, 0x200);
-        switch (omap_lcd->palette[0] >> 12 & 7) {
-        case 3 ... 7:
-            frame_offset += 0x200;
-            break;
-        default:
-            frame_offset += 0x20;
-        }
-    }
-
-    /* Colour depth */
-    switch ((omap_lcd->palette[0] >> 12) & 7) {
-    case 1:
-        draw_line = draw_line_table2[surface_bits_per_pixel(surface)];
-        bpp = 2;
-        break;
-
-    case 2:
-        draw_line = draw_line_table4[surface_bits_per_pixel(surface)];
-        bpp = 4;
-        break;
-
-    case 3:
-        draw_line = draw_line_table8[surface_bits_per_pixel(surface)];
-        bpp = 8;
-        break;
-
-    case 4 ... 7:
-        if (!omap_lcd->tft)
-            draw_line = draw_line_table12[surface_bits_per_pixel(surface)];
-        else
-            draw_line = draw_line_table16[surface_bits_per_pixel(surface)];
-        bpp = 16;
-        break;
-
-    default:
-        /* Unsupported at the moment.  */
-        return;
-    }
-
-    /* Resolution */
-    width = omap_lcd->width;
-    if (width != surface_width(surface) ||
-        omap_lcd->height != surface_height(surface)) {
-        qemu_console_resize(omap_lcd->con,
-                            omap_lcd->width, omap_lcd->height);
-        surface = qemu_console_surface(omap_lcd->con);
-        omap_lcd->invalidate = 1;
-    }
-
-    if (omap_lcd->dma->current_frame == 0)
-        size = omap_lcd->dma->src_f1_bottom - omap_lcd->dma->src_f1_top;
-    else
-        size = omap_lcd->dma->src_f2_bottom - omap_lcd->dma->src_f2_top;
-
-    if (frame_offset + ((width * omap_lcd->height * bpp) >> 3) > size + 2) {
-        omap_lcd->sync_error = 1;
-        omap_lcd_interrupts(omap_lcd);
-        omap_lcd->enable = 0;
-        return;
-    }
-
-    /* Content */
-    frame_base = omap_lcd->dma->phys_framebuffer[
-            omap_lcd->dma->current_frame] + frame_offset;
-    omap_lcd->dma->condition |= 1 << omap_lcd->dma->current_frame;
-    if (omap_lcd->dma->interrupts & 1)
-        qemu_irq_raise(omap_lcd->dma->irq);
-    if (omap_lcd->dma->dual)
-        omap_lcd->dma->current_frame ^= 1;
-
-    if (!surface_bits_per_pixel(surface)) {
-        return;
-    }
-
-    first = 0;
-    height = omap_lcd->height;
-    if (omap_lcd->subpanel & (1 << 31)) {
-        if (omap_lcd->subpanel & (1 << 29))
-            first = (omap_lcd->subpanel >> 16) & 0x3ff;
-        else
-            height = (omap_lcd->subpanel >> 16) & 0x3ff;
-        /* TODO: fill the rest of the panel with DPD */
-    }
-
-    step = width * bpp >> 3;
-    linesize = surface_stride(surface);
-    framebuffer_update_display(surface, omap_lcd->sysmem,
-                               frame_base, width, height,
-                               step, linesize, 0,
-                               omap_lcd->invalidate,
-                               draw_line, omap_lcd->palette,
-                               &first, &last);
-    if (first >= 0) {
-        dpy_gfx_update(omap_lcd->con, 0, first, width, last - first + 1);
-    }
-    omap_lcd->invalidate = 0;
-}
-
-static void omap_ppm_save(const char *filename, uint8_t *data,
-                    int w, int h, int linesize, Error **errp)
-{
-    FILE *f;
-    uint8_t *d, *d1;
-    unsigned int v;
-    int ret, y, x, bpp;
-
-    f = fopen(filename, "wb");
-    if (!f) {
-        error_setg(errp, "failed to open file '%s': %s", filename,
-                   strerror(errno));
-        return;
-    }
-    ret = fprintf(f, "P6\n%d %d\n%d\n", w, h, 255);
-    if (ret < 0) {
-        goto write_err;
-    }
-    d1 = data;
-    bpp = linesize / w;
-    for (y = 0; y < h; y ++) {
-        d = d1;
-        for (x = 0; x < w; x ++) {
-            v = *(uint32_t *) d;
-            switch (bpp) {
-            case 2:
-                ret = fputc((v >> 8) & 0xf8, f);
-                if (ret == EOF) {
-                    goto write_err;
-                }
-                ret = fputc((v >> 3) & 0xfc, f);
-                if (ret == EOF) {
-                    goto write_err;
-                }
-                ret = fputc((v << 3) & 0xf8, f);
-                if (ret == EOF) {
-                    goto write_err;
-                }
-                break;
-            case 3:
-            case 4:
-            default:
-                ret = fputc((v >> 16) & 0xff, f);
-                if (ret == EOF) {
-                    goto write_err;
-                }
-                ret = fputc((v >> 8) & 0xff, f);
-                if (ret == EOF) {
-                    goto write_err;
-                }
-                ret = fputc((v) & 0xff, f);
-                if (ret == EOF) {
-                    goto write_err;
-                }
-                break;
-            }
-            d += bpp;
-        }
-        d1 += linesize;
-    }
-out:
-    fclose(f);
-    return;
-
-write_err:
-    error_setg(errp, "failed to write to file '%s': %s", filename,
-               strerror(errno));
-    unlink(filename);
-    goto out;
-}
-
-static void omap_screen_dump(void *opaque, const char *filename, bool cswitch,
-                             Error **errp)
-{
-    struct omap_lcd_panel_s *omap_lcd = opaque;
-    DisplaySurface *surface = qemu_console_surface(omap_lcd->con);
-
-    omap_update_display(opaque);
-    if (omap_lcd && surface_data(surface))
-        omap_ppm_save(filename, surface_data(surface),
-                    omap_lcd->width, omap_lcd->height,
-                    surface_stride(surface), errp);
-}
-
-static void omap_invalidate_display(void *opaque) {
-    struct omap_lcd_panel_s *omap_lcd = opaque;
-    omap_lcd->invalidate = 1;
-}
-
-static void omap_lcd_update(struct omap_lcd_panel_s *s) {
-    if (!s->enable) {
-        s->dma->current_frame = -1;
-        s->sync_error = 0;
-        if (s->plm != 1)
-            s->frame_done = 1;
-        omap_lcd_interrupts(s);
-        return;
-    }
-
-    if (s->dma->current_frame == -1) {
-        s->frame_done = 0;
-        s->palette_done = 0;
-        s->dma->current_frame = 0;
-    }
-
-    if (!s->dma->mpu->port[s->dma->src].addr_valid(s->dma->mpu,
-                            s->dma->src_f1_top) ||
-                    !s->dma->mpu->port[
-                    s->dma->src].addr_valid(s->dma->mpu,
-                            s->dma->src_f1_bottom) ||
-                    (s->dma->dual &&
-                     (!s->dma->mpu->port[
-                      s->dma->src].addr_valid(s->dma->mpu,
-                              s->dma->src_f2_top) ||
-                      !s->dma->mpu->port[
-                      s->dma->src].addr_valid(s->dma->mpu,
-                              s->dma->src_f2_bottom)))) {
-        s->dma->condition |= 1 << 2;
-        if (s->dma->interrupts & (1 << 1))
-            qemu_irq_raise(s->dma->irq);
-        s->enable = 0;
-        return;
-    }
-
-    s->dma->phys_framebuffer[0] = s->dma->src_f1_top;
-    s->dma->phys_framebuffer[1] = s->dma->src_f2_top;
-
-    if (s->plm != 2 && !s->palette_done) {
-        cpu_physical_memory_read(
-            s->dma->phys_framebuffer[s->dma->current_frame],
-            (void *)s->palette, 0x200);
-        s->palette_done = 1;
-        omap_lcd_interrupts(s);
-    }
-}
-
-static uint64_t omap_lcdc_read(void *opaque, hwaddr addr,
-                               unsigned size)
-{
-    struct omap_lcd_panel_s *s = (struct omap_lcd_panel_s *) opaque;
-
-    switch (addr) {
-    case 0x00: /* LCD_CONTROL */
-        return (s->tft << 23) | (s->plm << 20) |
-                (s->tft << 7) | (s->interrupts << 3) |
-                (s->mono << 1) | s->enable | s->ctrl | 0xfe000c34;
-
-    case 0x04: /* LCD_TIMING0 */
-        return (s->timing[0] << 10) | (s->width - 1) | 0x0000000f;
-
-    case 0x08: /* LCD_TIMING1 */
-        return (s->timing[1] << 10) | (s->height - 1);
-
-    case 0x0c: /* LCD_TIMING2 */
-        return s->timing[2] | 0xfc000000;
-
-    case 0x10: /* LCD_STATUS */
-        return (s->palette_done << 6) | (s->sync_error << 2) | s->frame_done;
-
-    case 0x14: /* LCD_SUBPANEL */
-        return s->subpanel;
-
-    default:
-        break;
-    }
-    OMAP_BAD_REG(addr);
-    return 0;
-}
-
-static void omap_lcdc_write(void *opaque, hwaddr addr,
-                            uint64_t value, unsigned size)
-{
-    struct omap_lcd_panel_s *s = (struct omap_lcd_panel_s *) opaque;
-
-    switch (addr) {
-    case 0x00: /* LCD_CONTROL */
-        s->plm = (value >> 20) & 3;
-        s->tft = (value >> 7) & 1;
-        s->interrupts = (value >> 3) & 3;
-        s->mono = (value >> 1) & 1;
-        s->ctrl = value & 0x01cff300;
-        if (s->enable != (value & 1)) {
-            s->enable = value & 1;
-            omap_lcd_update(s);
-        }
-        break;
-
-    case 0x04: /* LCD_TIMING0 */
-        s->timing[0] = value >> 10;
-        s->width = (value & 0x3ff) + 1;
-        break;
-
-    case 0x08: /* LCD_TIMING1 */
-        s->timing[1] = value >> 10;
-        s->height = (value & 0x3ff) + 1;
-        break;
-
-    case 0x0c: /* LCD_TIMING2 */
-        s->timing[2] = value;
-        break;
-
-    case 0x10: /* LCD_STATUS */
-        break;
-
-    case 0x14: /* LCD_SUBPANEL */
-        s->subpanel = value & 0xa1ffffff;
-        break;
-
-    default:
-        OMAP_BAD_REG(addr);
-    }
-}
-
-static const MemoryRegionOps omap_lcdc_ops = {
-    .read = omap_lcdc_read,
-    .write = omap_lcdc_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-void omap_lcdc_reset(struct omap_lcd_panel_s *s)
-{
-    s->dma->current_frame = -1;
-    s->plm = 0;
-    s->tft = 0;
-    s->mono = 0;
-    s->enable = 0;
-    s->width = 0;
-    s->height = 0;
-    s->interrupts = 0;
-    s->timing[0] = 0;
-    s->timing[1] = 0;
-    s->timing[2] = 0;
-    s->subpanel = 0;
-    s->palette_done = 0;
-    s->frame_done = 0;
-    s->sync_error = 0;
-    s->invalidate = 1;
-    s->subpanel = 0;
-    s->ctrl = 0;
-}
-
-struct omap_lcd_panel_s *omap_lcdc_init(MemoryRegion *sysmem,
-                                        hwaddr base,
-                                        qemu_irq irq,
-                                        struct omap_dma_lcd_channel_s *dma,
-                                        omap_clk clk)
-{
-    struct omap_lcd_panel_s *s = (struct omap_lcd_panel_s *)
-            g_malloc0(sizeof(struct omap_lcd_panel_s));
-
-    s->irq = irq;
-    s->dma = dma;
-    s->sysmem = sysmem;
-    omap_lcdc_reset(s);
-
-    memory_region_init_io(&s->iomem, &omap_lcdc_ops, s, "omap.lcdc", 0x100);
-    memory_region_add_subregion(sysmem, base, &s->iomem);
-
-    s->con = graphic_console_init(omap_update_display,
-                                  omap_invalidate_display,
-                                  omap_screen_dump, NULL, s);
-
-    return s;
-}
diff --git a/hw/omap_mmc.c b/hw/omap_mmc.c
deleted file mode 100644 (file)
index 6e48110..0000000
+++ /dev/null
@@ -1,641 +0,0 @@
-/*
- * OMAP on-chip MMC/SD host emulation.
- *
- * Copyright (C) 2006-2007 Andrzej Zaborowski  <balrog@zabor.org>
- *
- * 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 or
- * (at your option) version 3 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
- * 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 "hw/hw.h"
-#include "hw/omap.h"
-#include "hw/sd.h"
-
-struct omap_mmc_s {
-    qemu_irq irq;
-    qemu_irq *dma;
-    qemu_irq coverswitch;
-    MemoryRegion iomem;
-    omap_clk clk;
-    SDState *card;
-    uint16_t last_cmd;
-    uint16_t sdio;
-    uint16_t rsp[8];
-    uint32_t arg;
-    int lines;
-    int dw;
-    int mode;
-    int enable;
-    int be;
-    int rev;
-    uint16_t status;
-    uint16_t mask;
-    uint8_t cto;
-    uint16_t dto;
-    int clkdiv;
-    uint16_t fifo[32];
-    int fifo_start;
-    int fifo_len;
-    uint16_t blen;
-    uint16_t blen_counter;
-    uint16_t nblk;
-    uint16_t nblk_counter;
-    int tx_dma;
-    int rx_dma;
-    int af_level;
-    int ae_level;
-
-    int ddir;
-    int transfer;
-
-    int cdet_wakeup;
-    int cdet_enable;
-    int cdet_state;
-    qemu_irq cdet;
-};
-
-static void omap_mmc_interrupts_update(struct omap_mmc_s *s)
-{
-    qemu_set_irq(s->irq, !!(s->status & s->mask));
-}
-
-static void omap_mmc_fifolevel_update(struct omap_mmc_s *host)
-{
-    if (!host->transfer && !host->fifo_len) {
-        host->status &= 0xf3ff;
-        return;
-    }
-
-    if (host->fifo_len > host->af_level && host->ddir) {
-        if (host->rx_dma) {
-            host->status &= 0xfbff;
-            qemu_irq_raise(host->dma[1]);
-        } else
-            host->status |= 0x0400;
-    } else {
-        host->status &= 0xfbff;
-        qemu_irq_lower(host->dma[1]);
-    }
-
-    if (host->fifo_len < host->ae_level && !host->ddir) {
-        if (host->tx_dma) {
-            host->status &= 0xf7ff;
-            qemu_irq_raise(host->dma[0]);
-        } else
-            host->status |= 0x0800;
-    } else {
-        qemu_irq_lower(host->dma[0]);
-        host->status &= 0xf7ff;
-    }
-}
-
-typedef enum {
-    sd_nore = 0,       /* no response */
-    sd_r1,             /* normal response command */
-    sd_r2,             /* CID, CSD registers */
-    sd_r3,             /* OCR register */
-    sd_r6 = 6,         /* Published RCA response */
-    sd_r1b = -1,
-} sd_rsp_type_t;
-
-static void omap_mmc_command(struct omap_mmc_s *host, int cmd, int dir,
-                sd_cmd_type_t type, int busy, sd_rsp_type_t resptype, int init)
-{
-    uint32_t rspstatus, mask;
-    int rsplen, timeout;
-    SDRequest request;
-    uint8_t response[16];
-
-    if (init && cmd == 0) {
-        host->status |= 0x0001;
-        return;
-    }
-
-    if (resptype == sd_r1 && busy)
-        resptype = sd_r1b;
-
-    if (type == sd_adtc) {
-        host->fifo_start = 0;
-        host->fifo_len = 0;
-        host->transfer = 1;
-        host->ddir = dir;
-    } else
-        host->transfer = 0;
-    timeout = 0;
-    mask = 0;
-    rspstatus = 0;
-
-    request.cmd = cmd;
-    request.arg = host->arg;
-    request.crc = 0; /* FIXME */
-
-    rsplen = sd_do_command(host->card, &request, response);
-
-    /* TODO: validate CRCs */
-    switch (resptype) {
-    case sd_nore:
-        rsplen = 0;
-        break;
-
-    case sd_r1:
-    case sd_r1b:
-        if (rsplen < 4) {
-            timeout = 1;
-            break;
-        }
-        rsplen = 4;
-
-        mask = OUT_OF_RANGE | ADDRESS_ERROR | BLOCK_LEN_ERROR |
-                ERASE_SEQ_ERROR | ERASE_PARAM | WP_VIOLATION |
-                LOCK_UNLOCK_FAILED | COM_CRC_ERROR | ILLEGAL_COMMAND |
-                CARD_ECC_FAILED | CC_ERROR | SD_ERROR |
-                CID_CSD_OVERWRITE;
-        if (host->sdio & (1 << 13))
-            mask |= AKE_SEQ_ERROR;
-        rspstatus = (response[0] << 24) | (response[1] << 16) |
-                (response[2] << 8) | (response[3] << 0);
-        break;
-
-    case sd_r2:
-        if (rsplen < 16) {
-            timeout = 1;
-            break;
-        }
-        rsplen = 16;
-        break;
-
-    case sd_r3:
-        if (rsplen < 4) {
-            timeout = 1;
-            break;
-        }
-        rsplen = 4;
-
-        rspstatus = (response[0] << 24) | (response[1] << 16) |
-                (response[2] << 8) | (response[3] << 0);
-        if (rspstatus & 0x80000000)
-            host->status &= 0xe000;
-        else
-            host->status |= 0x1000;
-        break;
-
-    case sd_r6:
-        if (rsplen < 4) {
-            timeout = 1;
-            break;
-        }
-        rsplen = 4;
-
-        mask = 0xe000 | AKE_SEQ_ERROR;
-        rspstatus = (response[2] << 8) | (response[3] << 0);
-    }
-
-    if (rspstatus & mask)
-        host->status |= 0x4000;
-    else
-        host->status &= 0xb000;
-
-    if (rsplen)
-        for (rsplen = 0; rsplen < 8; rsplen ++)
-            host->rsp[~rsplen & 7] = response[(rsplen << 1) | 1] |
-                    (response[(rsplen << 1) | 0] << 8);
-
-    if (timeout)
-        host->status |= 0x0080;
-    else if (cmd == 12)
-        host->status |= 0x0005;        /* Makes it more real */
-    else
-        host->status |= 0x0001;
-}
-
-static void omap_mmc_transfer(struct omap_mmc_s *host)
-{
-    uint8_t value;
-
-    if (!host->transfer)
-        return;
-
-    while (1) {
-        if (host->ddir) {
-            if (host->fifo_len > host->af_level)
-                break;
-
-            value = sd_read_data(host->card);
-            host->fifo[(host->fifo_start + host->fifo_len) & 31] = value;
-            if (-- host->blen_counter) {
-                value = sd_read_data(host->card);
-                host->fifo[(host->fifo_start + host->fifo_len) & 31] |=
-                        value << 8;
-                host->blen_counter --;
-            }
-
-            host->fifo_len ++;
-        } else {
-            if (!host->fifo_len)
-                break;
-
-            value = host->fifo[host->fifo_start] & 0xff;
-            sd_write_data(host->card, value);
-            if (-- host->blen_counter) {
-                value = host->fifo[host->fifo_start] >> 8;
-                sd_write_data(host->card, value);
-                host->blen_counter --;
-            }
-
-            host->fifo_start ++;
-            host->fifo_len --;
-            host->fifo_start &= 31;
-        }
-
-        if (host->blen_counter == 0) {
-            host->nblk_counter --;
-            host->blen_counter = host->blen;
-
-            if (host->nblk_counter == 0) {
-                host->nblk_counter = host->nblk;
-                host->transfer = 0;
-                host->status |= 0x0008;
-                break;
-            }
-        }
-    }
-}
-
-static void omap_mmc_update(void *opaque)
-{
-    struct omap_mmc_s *s = opaque;
-    omap_mmc_transfer(s);
-    omap_mmc_fifolevel_update(s);
-    omap_mmc_interrupts_update(s);
-}
-
-void omap_mmc_reset(struct omap_mmc_s *host)
-{
-    host->last_cmd = 0;
-    memset(host->rsp, 0, sizeof(host->rsp));
-    host->arg = 0;
-    host->dw = 0;
-    host->mode = 0;
-    host->enable = 0;
-    host->status = 0;
-    host->mask = 0;
-    host->cto = 0;
-    host->dto = 0;
-    host->fifo_len = 0;
-    host->blen = 0;
-    host->blen_counter = 0;
-    host->nblk = 0;
-    host->nblk_counter = 0;
-    host->tx_dma = 0;
-    host->rx_dma = 0;
-    host->ae_level = 0x00;
-    host->af_level = 0x1f;
-    host->transfer = 0;
-    host->cdet_wakeup = 0;
-    host->cdet_enable = 0;
-    qemu_set_irq(host->coverswitch, host->cdet_state);
-    host->clkdiv = 0;
-}
-
-static uint64_t omap_mmc_read(void *opaque, hwaddr offset,
-                              unsigned size)
-{
-    uint16_t i;
-    struct omap_mmc_s *s = (struct omap_mmc_s *) opaque;
-
-    if (size != 2) {
-        return omap_badwidth_read16(opaque, offset);
-    }
-
-    switch (offset) {
-    case 0x00: /* MMC_CMD */
-        return s->last_cmd;
-
-    case 0x04: /* MMC_ARGL */
-        return s->arg & 0x0000ffff;
-
-    case 0x08: /* MMC_ARGH */
-        return s->arg >> 16;
-
-    case 0x0c: /* MMC_CON */
-        return (s->dw << 15) | (s->mode << 12) | (s->enable << 11) | 
-                (s->be << 10) | s->clkdiv;
-
-    case 0x10: /* MMC_STAT */
-        return s->status;
-
-    case 0x14: /* MMC_IE */
-        return s->mask;
-
-    case 0x18: /* MMC_CTO */
-        return s->cto;
-
-    case 0x1c: /* MMC_DTO */
-        return s->dto;
-
-    case 0x20: /* MMC_DATA */
-        /* TODO: support 8-bit access */
-        i = s->fifo[s->fifo_start];
-        if (s->fifo_len == 0) {
-            printf("MMC: FIFO underrun\n");
-            return i;
-        }
-        s->fifo_start ++;
-        s->fifo_len --;
-        s->fifo_start &= 31;
-        omap_mmc_transfer(s);
-        omap_mmc_fifolevel_update(s);
-        omap_mmc_interrupts_update(s);
-        return i;
-
-    case 0x24: /* MMC_BLEN */
-        return s->blen_counter;
-
-    case 0x28: /* MMC_NBLK */
-        return s->nblk_counter;
-
-    case 0x2c: /* MMC_BUF */
-        return (s->rx_dma << 15) | (s->af_level << 8) |
-            (s->tx_dma << 7) | s->ae_level;
-
-    case 0x30: /* MMC_SPI */
-        return 0x0000;
-    case 0x34: /* MMC_SDIO */
-        return (s->cdet_wakeup << 2) | (s->cdet_enable) | s->sdio;
-    case 0x38: /* MMC_SYST */
-        return 0x0000;
-
-    case 0x3c: /* MMC_REV */
-        return s->rev;
-
-    case 0x40: /* MMC_RSP0 */
-    case 0x44: /* MMC_RSP1 */
-    case 0x48: /* MMC_RSP2 */
-    case 0x4c: /* MMC_RSP3 */
-    case 0x50: /* MMC_RSP4 */
-    case 0x54: /* MMC_RSP5 */
-    case 0x58: /* MMC_RSP6 */
-    case 0x5c: /* MMC_RSP7 */
-        return s->rsp[(offset - 0x40) >> 2];
-
-    /* OMAP2-specific */
-    case 0x60: /* MMC_IOSR */
-    case 0x64: /* MMC_SYSC */
-        return 0;
-    case 0x68: /* MMC_SYSS */
-        return 1;                                              /* RSTD */
-    }
-
-    OMAP_BAD_REG(offset);
-    return 0;
-}
-
-static void omap_mmc_write(void *opaque, hwaddr offset,
-                           uint64_t value, unsigned size)
-{
-    int i;
-    struct omap_mmc_s *s = (struct omap_mmc_s *) opaque;
-
-    if (size != 2) {
-        return omap_badwidth_write16(opaque, offset, value);
-    }
-
-    switch (offset) {
-    case 0x00: /* MMC_CMD */
-        if (!s->enable)
-            break;
-
-        s->last_cmd = value;
-        for (i = 0; i < 8; i ++)
-            s->rsp[i] = 0x0000;
-        omap_mmc_command(s, value & 63, (value >> 15) & 1,
-                (sd_cmd_type_t) ((value >> 12) & 3),
-                (value >> 11) & 1,
-                (sd_rsp_type_t) ((value >> 8) & 7),
-                (value >> 7) & 1);
-        omap_mmc_update(s);
-        break;
-
-    case 0x04: /* MMC_ARGL */
-        s->arg &= 0xffff0000;
-        s->arg |= 0x0000ffff & value;
-        break;
-
-    case 0x08: /* MMC_ARGH */
-        s->arg &= 0x0000ffff;
-        s->arg |= value << 16;
-        break;
-
-    case 0x0c: /* MMC_CON */
-        s->dw = (value >> 15) & 1;
-        s->mode = (value >> 12) & 3;
-        s->enable = (value >> 11) & 1;
-        s->be = (value >> 10) & 1;
-        s->clkdiv = (value >> 0) & (s->rev >= 2 ? 0x3ff : 0xff);
-        if (s->mode != 0)
-            printf("SD mode %i unimplemented!\n", s->mode);
-        if (s->be != 0)
-            printf("SD FIFO byte sex unimplemented!\n");
-        if (s->dw != 0 && s->lines < 4)
-            printf("4-bit SD bus enabled\n");
-        if (!s->enable)
-            omap_mmc_reset(s);
-        break;
-
-    case 0x10: /* MMC_STAT */
-        s->status &= ~value;
-        omap_mmc_interrupts_update(s);
-        break;
-
-    case 0x14: /* MMC_IE */
-        s->mask = value & 0x7fff;
-        omap_mmc_interrupts_update(s);
-        break;
-
-    case 0x18: /* MMC_CTO */
-        s->cto = value & 0xff;
-        if (s->cto > 0xfd && s->rev <= 1)
-            printf("MMC: CTO of 0xff and 0xfe cannot be used!\n");
-        break;
-
-    case 0x1c: /* MMC_DTO */
-        s->dto = value & 0xffff;
-        break;
-
-    case 0x20: /* MMC_DATA */
-        /* TODO: support 8-bit access */
-        if (s->fifo_len == 32)
-            break;
-        s->fifo[(s->fifo_start + s->fifo_len) & 31] = value;
-        s->fifo_len ++;
-        omap_mmc_transfer(s);
-        omap_mmc_fifolevel_update(s);
-        omap_mmc_interrupts_update(s);
-        break;
-
-    case 0x24: /* MMC_BLEN */
-        s->blen = (value & 0x07ff) + 1;
-        s->blen_counter = s->blen;
-        break;
-
-    case 0x28: /* MMC_NBLK */
-        s->nblk = (value & 0x07ff) + 1;
-        s->nblk_counter = s->nblk;
-        s->blen_counter = s->blen;
-        break;
-
-    case 0x2c: /* MMC_BUF */
-        s->rx_dma = (value >> 15) & 1;
-        s->af_level = (value >> 8) & 0x1f;
-        s->tx_dma = (value >> 7) & 1;
-        s->ae_level = value & 0x1f;
-
-        if (s->rx_dma)
-            s->status &= 0xfbff;
-        if (s->tx_dma)
-            s->status &= 0xf7ff;
-        omap_mmc_fifolevel_update(s);
-        omap_mmc_interrupts_update(s);
-        break;
-
-    /* SPI, SDIO and TEST modes unimplemented */
-    case 0x30: /* MMC_SPI (OMAP1 only) */
-        break;
-    case 0x34: /* MMC_SDIO */
-        s->sdio = value & (s->rev >= 2 ? 0xfbf3 : 0x2020);
-        s->cdet_wakeup = (value >> 9) & 1;
-        s->cdet_enable = (value >> 2) & 1;
-        break;
-    case 0x38: /* MMC_SYST */
-        break;
-
-    case 0x3c: /* MMC_REV */
-    case 0x40: /* MMC_RSP0 */
-    case 0x44: /* MMC_RSP1 */
-    case 0x48: /* MMC_RSP2 */
-    case 0x4c: /* MMC_RSP3 */
-    case 0x50: /* MMC_RSP4 */
-    case 0x54: /* MMC_RSP5 */
-    case 0x58: /* MMC_RSP6 */
-    case 0x5c: /* MMC_RSP7 */
-        OMAP_RO_REG(offset);
-        break;
-
-    /* OMAP2-specific */
-    case 0x60: /* MMC_IOSR */
-        if (value & 0xf)
-            printf("MMC: SDIO bits used!\n");
-        break;
-    case 0x64: /* MMC_SYSC */
-        if (value & (1 << 2))                                  /* SRTS */
-            omap_mmc_reset(s);
-        break;
-    case 0x68: /* MMC_SYSS */
-        OMAP_RO_REG(offset);
-        break;
-
-    default:
-        OMAP_BAD_REG(offset);
-    }
-}
-
-static const MemoryRegionOps omap_mmc_ops = {
-    .read = omap_mmc_read,
-    .write = omap_mmc_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void omap_mmc_cover_cb(void *opaque, int line, int level)
-{
-    struct omap_mmc_s *host = (struct omap_mmc_s *) opaque;
-
-    if (!host->cdet_state && level) {
-        host->status |= 0x0002;
-        omap_mmc_interrupts_update(host);
-        if (host->cdet_wakeup) {
-            /* TODO: Assert wake-up */
-        }
-    }
-
-    if (host->cdet_state != level) {
-        qemu_set_irq(host->coverswitch, level);
-        host->cdet_state = level;
-    }
-}
-
-struct omap_mmc_s *omap_mmc_init(hwaddr base,
-                MemoryRegion *sysmem,
-                BlockDriverState *bd,
-                qemu_irq irq, qemu_irq dma[], omap_clk clk)
-{
-    struct omap_mmc_s *s = (struct omap_mmc_s *)
-            g_malloc0(sizeof(struct omap_mmc_s));
-
-    s->irq = irq;
-    s->dma = dma;
-    s->clk = clk;
-    s->lines = 1;      /* TODO: needs to be settable per-board */
-    s->rev = 1;
-
-    omap_mmc_reset(s);
-
-    memory_region_init_io(&s->iomem, &omap_mmc_ops, s, "omap.mmc", 0x800);
-    memory_region_add_subregion(sysmem, base, &s->iomem);
-
-    /* Instantiate the storage */
-    s->card = sd_init(bd, 0);
-
-    return s;
-}
-
-struct omap_mmc_s *omap2_mmc_init(struct omap_target_agent_s *ta,
-                BlockDriverState *bd, qemu_irq irq, qemu_irq dma[],
-                omap_clk fclk, omap_clk iclk)
-{
-    struct omap_mmc_s *s = (struct omap_mmc_s *)
-            g_malloc0(sizeof(struct omap_mmc_s));
-
-    s->irq = irq;
-    s->dma = dma;
-    s->clk = fclk;
-    s->lines = 4;
-    s->rev = 2;
-
-    omap_mmc_reset(s);
-
-    memory_region_init_io(&s->iomem, &omap_mmc_ops, s, "omap.mmc",
-                          omap_l4_region_size(ta, 0));
-    omap_l4_attach(ta, 0, &s->iomem);
-
-    /* Instantiate the storage */
-    s->card = sd_init(bd, 0);
-
-    s->cdet = qemu_allocate_irqs(omap_mmc_cover_cb, s, 1)[0];
-    sd_set_cb(s->card, NULL, s->cdet);
-
-    return s;
-}
-
-void omap_mmc_handlers(struct omap_mmc_s *s, qemu_irq ro, qemu_irq cover)
-{
-    if (s->cdet) {
-        sd_set_cb(s->card, ro, s->cdet);
-        s->coverswitch = cover;
-        qemu_set_irq(cover, s->cdet_state);
-    } else
-        sd_set_cb(s->card, ro, cover);
-}
-
-void omap_mmc_enable(struct omap_mmc_s *s, int enable)
-{
-    sd_enable(s->card, enable);
-}
diff --git a/hw/omap_sdrc.c b/hw/omap_sdrc.c
deleted file mode 100644 (file)
index 510e6cc..0000000
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * TI OMAP SDRAM controller emulation.
- *
- * Copyright (C) 2007-2008 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.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 or
- * (at your option) any later version 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
- * 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 "hw/hw.h"
-#include "hw/omap.h"
-
-/* SDRAM Controller Subsystem */
-struct omap_sdrc_s {
-    MemoryRegion iomem;
-    uint8_t config;
-};
-
-void omap_sdrc_reset(struct omap_sdrc_s *s)
-{
-    s->config = 0x10;
-}
-
-static uint64_t omap_sdrc_read(void *opaque, hwaddr addr,
-                               unsigned size)
-{
-    struct omap_sdrc_s *s = (struct omap_sdrc_s *) opaque;
-
-    if (size != 4) {
-        return omap_badwidth_read32(opaque, addr);
-    }
-
-    switch (addr) {
-    case 0x00: /* SDRC_REVISION */
-        return 0x20;
-
-    case 0x10: /* SDRC_SYSCONFIG */
-        return s->config;
-
-    case 0x14: /* SDRC_SYSSTATUS */
-        return 1;                                              /* RESETDONE */
-
-    case 0x40: /* SDRC_CS_CFG */
-    case 0x44: /* SDRC_SHARING */
-    case 0x48: /* SDRC_ERR_ADDR */
-    case 0x4c: /* SDRC_ERR_TYPE */
-    case 0x60: /* SDRC_DLLA_SCTRL */
-    case 0x64: /* SDRC_DLLA_STATUS */
-    case 0x68: /* SDRC_DLLB_CTRL */
-    case 0x6c: /* SDRC_DLLB_STATUS */
-    case 0x70: /* SDRC_POWER */
-    case 0x80: /* SDRC_MCFG_0 */
-    case 0x84: /* SDRC_MR_0 */
-    case 0x88: /* SDRC_EMR1_0 */
-    case 0x8c: /* SDRC_EMR2_0 */
-    case 0x90: /* SDRC_EMR3_0 */
-    case 0x94: /* SDRC_DCDL1_CTRL */
-    case 0x98: /* SDRC_DCDL2_CTRL */
-    case 0x9c: /* SDRC_ACTIM_CTRLA_0 */
-    case 0xa0: /* SDRC_ACTIM_CTRLB_0 */
-    case 0xa4: /* SDRC_RFR_CTRL_0 */
-    case 0xa8: /* SDRC_MANUAL_0 */
-    case 0xb0: /* SDRC_MCFG_1 */
-    case 0xb4: /* SDRC_MR_1 */
-    case 0xb8: /* SDRC_EMR1_1 */
-    case 0xbc: /* SDRC_EMR2_1 */
-    case 0xc0: /* SDRC_EMR3_1 */
-    case 0xc4: /* SDRC_ACTIM_CTRLA_1 */
-    case 0xc8: /* SDRC_ACTIM_CTRLB_1 */
-    case 0xd4: /* SDRC_RFR_CTRL_1 */
-    case 0xd8: /* SDRC_MANUAL_1 */
-        return 0x00;
-    }
-
-    OMAP_BAD_REG(addr);
-    return 0;
-}
-
-static void omap_sdrc_write(void *opaque, hwaddr addr,
-                            uint64_t value, unsigned size)
-{
-    struct omap_sdrc_s *s = (struct omap_sdrc_s *) opaque;
-
-    if (size != 4) {
-        return omap_badwidth_write32(opaque, addr, value);
-    }
-
-    switch (addr) {
-    case 0x00: /* SDRC_REVISION */
-    case 0x14: /* SDRC_SYSSTATUS */
-    case 0x48: /* SDRC_ERR_ADDR */
-    case 0x64: /* SDRC_DLLA_STATUS */
-    case 0x6c: /* SDRC_DLLB_STATUS */
-        OMAP_RO_REG(addr);
-        return;
-
-    case 0x10: /* SDRC_SYSCONFIG */
-        if ((value >> 3) != 0x2)
-            fprintf(stderr, "%s: bad SDRAM idle mode %i\n",
-                    __FUNCTION__, (unsigned)value >> 3);
-        if (value & 2)
-            omap_sdrc_reset(s);
-        s->config = value & 0x18;
-        break;
-
-    case 0x40: /* SDRC_CS_CFG */
-    case 0x44: /* SDRC_SHARING */
-    case 0x4c: /* SDRC_ERR_TYPE */
-    case 0x60: /* SDRC_DLLA_SCTRL */
-    case 0x68: /* SDRC_DLLB_CTRL */
-    case 0x70: /* SDRC_POWER */
-    case 0x80: /* SDRC_MCFG_0 */
-    case 0x84: /* SDRC_MR_0 */
-    case 0x88: /* SDRC_EMR1_0 */
-    case 0x8c: /* SDRC_EMR2_0 */
-    case 0x90: /* SDRC_EMR3_0 */
-    case 0x94: /* SDRC_DCDL1_CTRL */
-    case 0x98: /* SDRC_DCDL2_CTRL */
-    case 0x9c: /* SDRC_ACTIM_CTRLA_0 */
-    case 0xa0: /* SDRC_ACTIM_CTRLB_0 */
-    case 0xa4: /* SDRC_RFR_CTRL_0 */
-    case 0xa8: /* SDRC_MANUAL_0 */
-    case 0xb0: /* SDRC_MCFG_1 */
-    case 0xb4: /* SDRC_MR_1 */
-    case 0xb8: /* SDRC_EMR1_1 */
-    case 0xbc: /* SDRC_EMR2_1 */
-    case 0xc0: /* SDRC_EMR3_1 */
-    case 0xc4: /* SDRC_ACTIM_CTRLA_1 */
-    case 0xc8: /* SDRC_ACTIM_CTRLB_1 */
-    case 0xd4: /* SDRC_RFR_CTRL_1 */
-    case 0xd8: /* SDRC_MANUAL_1 */
-        break;
-
-    default:
-        OMAP_BAD_REG(addr);
-        return;
-    }
-}
-
-static const MemoryRegionOps omap_sdrc_ops = {
-    .read = omap_sdrc_read,
-    .write = omap_sdrc_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-struct omap_sdrc_s *omap_sdrc_init(MemoryRegion *sysmem,
-                                   hwaddr base)
-{
-    struct omap_sdrc_s *s = (struct omap_sdrc_s *)
-            g_malloc0(sizeof(struct omap_sdrc_s));
-
-    omap_sdrc_reset(s);
-
-    memory_region_init_io(&s->iomem, &omap_sdrc_ops, s, "omap.sdrc", 0x1000);
-    memory_region_add_subregion(sysmem, base, &s->iomem);
-
-    return s;
-}
diff --git a/hw/omap_spi.c b/hw/omap_spi.c
deleted file mode 100644 (file)
index 1cbd98d..0000000
+++ /dev/null
@@ -1,373 +0,0 @@
-/*
- * TI OMAP processor's Multichannel SPI emulation.
- *
- * Copyright (C) 2007-2009 Nokia Corporation
- *
- * Original code for OMAP2 by Andrzej Zaborowski <andrew@openedhand.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 or
- * (at your option) any later version 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
- * 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, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-#include "hw/hw.h"
-#include "hw/omap.h"
-
-/* Multichannel SPI */
-struct omap_mcspi_s {
-    MemoryRegion iomem;
-    qemu_irq irq;
-    int chnum;
-
-    uint32_t sysconfig;
-    uint32_t systest;
-    uint32_t irqst;
-    uint32_t irqen;
-    uint32_t wken;
-    uint32_t control;
-
-    struct omap_mcspi_ch_s {
-        qemu_irq txdrq;
-        qemu_irq rxdrq;
-        uint32_t (*txrx)(void *opaque, uint32_t, int);
-        void *opaque;
-
-        uint32_t tx;
-        uint32_t rx;
-
-        uint32_t config;
-        uint32_t status;
-        uint32_t control;
-    } ch[4];
-};
-
-static inline void omap_mcspi_interrupt_update(struct omap_mcspi_s *s)
-{
-    qemu_set_irq(s->irq, s->irqst & s->irqen);
-}
-
-static inline void omap_mcspi_dmarequest_update(struct omap_mcspi_ch_s *ch)
-{
-    qemu_set_irq(ch->txdrq,
-                    (ch->control & 1) &&               /* EN */
-                    (ch->config & (1 << 14)) &&                /* DMAW */
-                    (ch->status & (1 << 1)) &&         /* TXS */
-                    ((ch->config >> 12) & 3) != 1);    /* TRM */
-    qemu_set_irq(ch->rxdrq,
-                    (ch->control & 1) &&               /* EN */
-                    (ch->config & (1 << 15)) &&                /* DMAW */
-                    (ch->status & (1 << 0)) &&         /* RXS */
-                    ((ch->config >> 12) & 3) != 2);    /* TRM */
-}
-
-static void omap_mcspi_transfer_run(struct omap_mcspi_s *s, int chnum)
-{
-    struct omap_mcspi_ch_s *ch = s->ch + chnum;
-
-    if (!(ch->control & 1))                            /* EN */
-        return;
-    if ((ch->status & (1 << 0)) &&                     /* RXS */
-                    ((ch->config >> 12) & 3) != 2 &&   /* TRM */
-                    !(ch->config & (1 << 19)))         /* TURBO */
-        goto intr_update;
-    if ((ch->status & (1 << 1)) &&                     /* TXS */
-                    ((ch->config >> 12) & 3) != 1)     /* TRM */
-        goto intr_update;
-
-    if (!(s->control & 1) ||                           /* SINGLE */
-                    (ch->config & (1 << 20))) {                /* FORCE */
-        if (ch->txrx)
-            ch->rx = ch->txrx(ch->opaque, ch->tx,      /* WL */
-                            1 + (0x1f & (ch->config >> 7)));
-    }
-
-    ch->tx = 0;
-    ch->status |= 1 << 2;                              /* EOT */
-    ch->status |= 1 << 1;                              /* TXS */
-    if (((ch->config >> 12) & 3) != 2)                 /* TRM */
-        ch->status |= 1 << 0;                          /* RXS */
-
-intr_update:
-    if ((ch->status & (1 << 0)) &&                     /* RXS */
-                    ((ch->config >> 12) & 3) != 2 &&   /* TRM */
-                    !(ch->config & (1 << 19)))         /* TURBO */
-        s->irqst |= 1 << (2 + 4 * chnum);              /* RX_FULL */
-    if ((ch->status & (1 << 1)) &&                     /* TXS */
-                    ((ch->config >> 12) & 3) != 1)     /* TRM */
-        s->irqst |= 1 << (0 + 4 * chnum);              /* TX_EMPTY */
-    omap_mcspi_interrupt_update(s);
-    omap_mcspi_dmarequest_update(ch);
-}
-
-void omap_mcspi_reset(struct omap_mcspi_s *s)
-{
-    int ch;
-
-    s->sysconfig = 0;
-    s->systest = 0;
-    s->irqst = 0;
-    s->irqen = 0;
-    s->wken = 0;
-    s->control = 4;
-
-    for (ch = 0; ch < 4; ch ++) {
-        s->ch[ch].config = 0x060000;
-        s->ch[ch].status = 2;                          /* TXS */
-        s->ch[ch].control = 0;
-
-        omap_mcspi_dmarequest_update(s->ch + ch);
-    }
-
-    omap_mcspi_interrupt_update(s);
-}
-
-static uint64_t omap_mcspi_read(void *opaque, hwaddr addr,
-                                unsigned size)
-{
-    struct omap_mcspi_s *s = (struct omap_mcspi_s *) opaque;
-    int ch = 0;
-    uint32_t ret;
-
-    if (size != 4) {
-        return omap_badwidth_read32(opaque, addr);
-    }
-
-    switch (addr) {
-    case 0x00: /* MCSPI_REVISION */
-        return 0x91;
-
-    case 0x10: /* MCSPI_SYSCONFIG */
-        return s->sysconfig;
-
-    case 0x14: /* MCSPI_SYSSTATUS */
-        return 1;                                      /* RESETDONE */
-
-    case 0x18: /* MCSPI_IRQSTATUS */
-        return s->irqst;
-
-    case 0x1c: /* MCSPI_IRQENABLE */
-        return s->irqen;
-
-    case 0x20: /* MCSPI_WAKEUPENABLE */
-        return s->wken;
-
-    case 0x24: /* MCSPI_SYST */
-        return s->systest;
-
-    case 0x28: /* MCSPI_MODULCTRL */
-        return s->control;
-
-    case 0x68: ch ++;
-        /* fall through */
-    case 0x54: ch ++;
-        /* fall through */
-    case 0x40: ch ++;
-        /* fall through */
-    case 0x2c: /* MCSPI_CHCONF */
-        return s->ch[ch].config;
-
-    case 0x6c: ch ++;
-        /* fall through */
-    case 0x58: ch ++;
-        /* fall through */
-    case 0x44: ch ++;
-        /* fall through */
-    case 0x30: /* MCSPI_CHSTAT */
-        return s->ch[ch].status;
-
-    case 0x70: ch ++;
-        /* fall through */
-    case 0x5c: ch ++;
-        /* fall through */
-    case 0x48: ch ++;
-        /* fall through */
-    case 0x34: /* MCSPI_CHCTRL */
-        return s->ch[ch].control;
-
-    case 0x74: ch ++;
-        /* fall through */
-    case 0x60: ch ++;
-        /* fall through */
-    case 0x4c: ch ++;
-        /* fall through */
-    case 0x38: /* MCSPI_TX */
-        return s->ch[ch].tx;
-
-    case 0x78: ch ++;
-        /* fall through */
-    case 0x64: ch ++;
-        /* fall through */
-    case 0x50: ch ++;
-        /* fall through */
-    case 0x3c: /* MCSPI_RX */
-        s->ch[ch].status &= ~(1 << 0);                 /* RXS */
-        ret = s->ch[ch].rx;
-        omap_mcspi_transfer_run(s, ch);
-        return ret;
-    }
-
-    OMAP_BAD_REG(addr);
-    return 0;
-}
-
-static void omap_mcspi_write(void *opaque, hwaddr addr,
-                             uint64_t value, unsigned size)
-{
-    struct omap_mcspi_s *s = (struct omap_mcspi_s *) opaque;
-    int ch = 0;
-
-    if (size != 4) {
-        return omap_badwidth_write32(opaque, addr, value);
-    }
-
-    switch (addr) {
-    case 0x00: /* MCSPI_REVISION */
-    case 0x14: /* MCSPI_SYSSTATUS */
-    case 0x30: /* MCSPI_CHSTAT0 */
-    case 0x3c: /* MCSPI_RX0 */
-    case 0x44: /* MCSPI_CHSTAT1 */
-    case 0x50: /* MCSPI_RX1 */
-    case 0x58: /* MCSPI_CHSTAT2 */
-    case 0x64: /* MCSPI_RX2 */
-    case 0x6c: /* MCSPI_CHSTAT3 */
-    case 0x78: /* MCSPI_RX3 */
-        OMAP_RO_REG(addr);
-        return;
-
-    case 0x10: /* MCSPI_SYSCONFIG */
-        if (value & (1 << 1))                          /* SOFTRESET */
-            omap_mcspi_reset(s);
-        s->sysconfig = value & 0x31d;
-        break;
-
-    case 0x18: /* MCSPI_IRQSTATUS */
-        if (!((s->control & (1 << 3)) && (s->systest & (1 << 11)))) {
-            s->irqst &= ~value;
-            omap_mcspi_interrupt_update(s);
-        }
-        break;
-
-    case 0x1c: /* MCSPI_IRQENABLE */
-        s->irqen = value & 0x1777f;
-        omap_mcspi_interrupt_update(s);
-        break;
-
-    case 0x20: /* MCSPI_WAKEUPENABLE */
-        s->wken = value & 1;
-        break;
-
-    case 0x24: /* MCSPI_SYST */
-        if (s->control & (1 << 3))                     /* SYSTEM_TEST */
-            if (value & (1 << 11)) {                   /* SSB */
-                s->irqst |= 0x1777f;
-                omap_mcspi_interrupt_update(s);
-            }
-        s->systest = value & 0xfff;
-        break;
-
-    case 0x28: /* MCSPI_MODULCTRL */
-        if (value & (1 << 3))                          /* SYSTEM_TEST */
-            if (s->systest & (1 << 11)) {              /* SSB */
-                s->irqst |= 0x1777f;
-                omap_mcspi_interrupt_update(s);
-            }
-        s->control = value & 0xf;
-        break;
-
-    case 0x68: ch ++;
-        /* fall through */
-    case 0x54: ch ++;
-        /* fall through */
-    case 0x40: ch ++;
-        /* fall through */
-    case 0x2c: /* MCSPI_CHCONF */
-        if ((value ^ s->ch[ch].config) & (3 << 14))    /* DMAR | DMAW */
-            omap_mcspi_dmarequest_update(s->ch + ch);
-        if (((value >> 12) & 3) == 3)                  /* TRM */
-            fprintf(stderr, "%s: invalid TRM value (3)\n", __FUNCTION__);
-        if (((value >> 7) & 0x1f) < 3)                 /* WL */
-            fprintf(stderr, "%s: invalid WL value (%" PRIx64 ")\n",
-                            __FUNCTION__, (value >> 7) & 0x1f);
-        s->ch[ch].config = value & 0x7fffff;
-        break;
-
-    case 0x70: ch ++;
-        /* fall through */
-    case 0x5c: ch ++;
-        /* fall through */
-    case 0x48: ch ++;
-        /* fall through */
-    case 0x34: /* MCSPI_CHCTRL */
-        if (value & ~s->ch[ch].control & 1) {          /* EN */
-            s->ch[ch].control |= 1;
-            omap_mcspi_transfer_run(s, ch);
-        } else
-            s->ch[ch].control = value & 1;
-        break;
-
-    case 0x74: ch ++;
-        /* fall through */
-    case 0x60: ch ++;
-        /* fall through */
-    case 0x4c: ch ++;
-        /* fall through */
-    case 0x38: /* MCSPI_TX */
-        s->ch[ch].tx = value;
-        s->ch[ch].status &= ~(1 << 1);                 /* TXS */
-        omap_mcspi_transfer_run(s, ch);
-        break;
-
-    default:
-        OMAP_BAD_REG(addr);
-        return;
-    }
-}
-
-static const MemoryRegionOps omap_mcspi_ops = {
-    .read = omap_mcspi_read,
-    .write = omap_mcspi_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-struct omap_mcspi_s *omap_mcspi_init(struct omap_target_agent_s *ta, int chnum,
-                qemu_irq irq, qemu_irq *drq, omap_clk fclk, omap_clk iclk)
-{
-    struct omap_mcspi_s *s = (struct omap_mcspi_s *)
-            g_malloc0(sizeof(struct omap_mcspi_s));
-    struct omap_mcspi_ch_s *ch = s->ch;
-
-    s->irq = irq;
-    s->chnum = chnum;
-    while (chnum --) {
-        ch->txdrq = *drq ++;
-        ch->rxdrq = *drq ++;
-        ch ++;
-    }
-    omap_mcspi_reset(s);
-
-    memory_region_init_io(&s->iomem, &omap_mcspi_ops, s, "omap.mcspi",
-                          omap_l4_region_size(ta, 0));
-    omap_l4_attach(ta, 0, &s->iomem);
-
-    return s;
-}
-
-void omap_mcspi_attach(struct omap_mcspi_s *s,
-                uint32_t (*txrx)(void *opaque, uint32_t, int), void *opaque,
-                int chipselect)
-{
-    if (chipselect < 0 || chipselect >= s->chnum)
-        hw_error("%s: Bad chipselect %i\n", __FUNCTION__, chipselect);
-
-    s->ch[chipselect].txrx = txrx;
-    s->ch[chipselect].opaque = opaque;
-}
diff --git a/hw/omap_synctimer.c b/hw/omap_synctimer.c
deleted file mode 100644 (file)
index 13e7280..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * TI OMAP2 32kHz sync timer emulation.
- *
- * Copyright (C) 2007-2008 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.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 or
- * (at your option) any later version 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
- * 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 "hw/hw.h"
-#include "qemu/timer.h"
-#include "hw/omap.h"
-struct omap_synctimer_s {
-    MemoryRegion iomem;
-    uint32_t val;
-    uint16_t readh;
-};
-
-/* 32-kHz Sync Timer of the OMAP2 */
-static uint32_t omap_synctimer_read(struct omap_synctimer_s *s) {
-    return muldiv64(qemu_get_clock_ns(vm_clock), 0x8000, get_ticks_per_sec());
-}
-
-void omap_synctimer_reset(struct omap_synctimer_s *s)
-{
-    s->val = omap_synctimer_read(s);
-}
-
-static uint32_t omap_synctimer_readw(void *opaque, hwaddr addr)
-{
-    struct omap_synctimer_s *s = (struct omap_synctimer_s *) opaque;
-
-    switch (addr) {
-    case 0x00: /* 32KSYNCNT_REV */
-        return 0x21;
-
-    case 0x10: /* CR */
-        return omap_synctimer_read(s) - s->val;
-    }
-
-    OMAP_BAD_REG(addr);
-    return 0;
-}
-
-static uint32_t omap_synctimer_readh(void *opaque, hwaddr addr)
-{
-    struct omap_synctimer_s *s = (struct omap_synctimer_s *) opaque;
-    uint32_t ret;
-
-    if (addr & 2)
-        return s->readh;
-    else {
-        ret = omap_synctimer_readw(opaque, addr);
-        s->readh = ret >> 16;
-        return ret & 0xffff;
-    }
-}
-
-static void omap_synctimer_write(void *opaque, hwaddr addr,
-                uint32_t value)
-{
-    OMAP_BAD_REG(addr);
-}
-
-static const MemoryRegionOps omap_synctimer_ops = {
-    .old_mmio = {
-        .read = {
-            omap_badwidth_read32,
-            omap_synctimer_readh,
-            omap_synctimer_readw,
-        },
-        .write = {
-            omap_badwidth_write32,
-            omap_synctimer_write,
-            omap_synctimer_write,
-        },
-    },
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-struct omap_synctimer_s *omap_synctimer_init(struct omap_target_agent_s *ta,
-                struct omap_mpu_state_s *mpu, omap_clk fclk, omap_clk iclk)
-{
-    struct omap_synctimer_s *s = g_malloc0(sizeof(*s));
-
-    omap_synctimer_reset(s);
-    memory_region_init_io(&s->iomem, &omap_synctimer_ops, s, "omap.synctimer",
-                          omap_l4_region_size(ta, 0));
-    omap_l4_attach(ta, 0, &s->iomem);
-
-    return s;
-}
diff --git a/hw/omap_tap.c b/hw/omap_tap.c
deleted file mode 100644 (file)
index 181ecee..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * TI OMAP TEST-Chip-level TAP emulation.
- *
- * Copyright (C) 2007-2008 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.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 or
- * (at your option) any later version 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
- * 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 "hw/hw.h"
-#include "hw/omap.h"
-
-/* TEST-Chip-level TAP */
-static uint64_t omap_tap_read(void *opaque, hwaddr addr,
-                              unsigned size)
-{
-    struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
-
-    if (size != 4) {
-        return omap_badwidth_read32(opaque, addr);
-    }
-
-    switch (addr) {
-    case 0x204:        /* IDCODE_reg */
-        switch (s->mpu_model) {
-        case omap2420:
-        case omap2422:
-        case omap2423:
-            return 0x5b5d902f; /* ES 2.2 */
-        case omap2430:
-            return 0x5b68a02f; /* ES 2.2 */
-        case omap3430:
-            return 0x1b7ae02f; /* ES 2 */
-        default:
-            hw_error("%s: Bad mpu model\n", __FUNCTION__);
-        }
-
-    case 0x208:        /* PRODUCTION_ID_reg for OMAP2 */
-    case 0x210:        /* PRODUCTION_ID_reg for OMAP3 */
-        switch (s->mpu_model) {
-        case omap2420:
-            return 0x000254f0; /* POP ESHS2.1.1 in N91/93/95, ES2 in N800 */
-        case omap2422:
-            return 0x000400f0;
-        case omap2423:
-            return 0x000800f0;
-        case omap2430:
-            return 0x000000f0;
-        case omap3430:
-            return 0x000000f0;
-        default:
-            hw_error("%s: Bad mpu model\n", __FUNCTION__);
-        }
-
-    case 0x20c:
-        switch (s->mpu_model) {
-        case omap2420:
-        case omap2422:
-        case omap2423:
-            return 0xcafeb5d9; /* ES 2.2 */
-        case omap2430:
-            return 0xcafeb68a; /* ES 2.2 */
-        case omap3430:
-            return 0xcafeb7ae; /* ES 2 */
-        default:
-            hw_error("%s: Bad mpu model\n", __FUNCTION__);
-        }
-
-    case 0x218:        /* DIE_ID_reg */
-        return ('Q' << 24) | ('E' << 16) | ('M' << 8) | ('U' << 0);
-    case 0x21c:        /* DIE_ID_reg */
-        return 0x54 << 24;
-    case 0x220:        /* DIE_ID_reg */
-        return ('Q' << 24) | ('E' << 16) | ('M' << 8) | ('U' << 0);
-    case 0x224:        /* DIE_ID_reg */
-        return ('Q' << 24) | ('E' << 16) | ('M' << 8) | ('U' << 0);
-    }
-
-    OMAP_BAD_REG(addr);
-    return 0;
-}
-
-static void omap_tap_write(void *opaque, hwaddr addr,
-                           uint64_t value, unsigned size)
-{
-    if (size != 4) {
-        return omap_badwidth_write32(opaque, addr, value);
-    }
-
-    OMAP_BAD_REG(addr);
-}
-
-static const MemoryRegionOps omap_tap_ops = {
-    .read = omap_tap_read,
-    .write = omap_tap_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-void omap_tap_init(struct omap_target_agent_s *ta,
-                struct omap_mpu_state_s *mpu)
-{
-    memory_region_init_io(&mpu->tap_iomem, &omap_tap_ops, mpu, "omap.tap",
-                          omap_l4_region_size(ta, 0));
-    omap_l4_attach(ta, 0, &mpu->tap_iomem);
-}
diff --git a/hw/omap_uart.c b/hw/omap_uart.c
deleted file mode 100644 (file)
index af51ce7..0000000
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * TI OMAP processors UART emulation.
- *
- * Copyright (C) 2006-2008 Andrzej Zaborowski  <balrog@zabor.org>
- * Copyright (C) 2007-2009 Nokia Corporation
- *
- * 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 or
- * (at your option) version 3 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
- * 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 "char/char.h"
-#include "hw/hw.h"
-#include "hw/omap.h"
-#include "hw/serial.h"
-#include "exec/address-spaces.h"
-
-/* UARTs */
-struct omap_uart_s {
-    MemoryRegion iomem;
-    hwaddr base;
-    SerialState *serial; /* TODO */
-    struct omap_target_agent_s *ta;
-    omap_clk fclk;
-    qemu_irq irq;
-
-    uint8_t eblr;
-    uint8_t syscontrol;
-    uint8_t wkup;
-    uint8_t cfps;
-    uint8_t mdr[2];
-    uint8_t scr;
-    uint8_t clksel;
-};
-
-void omap_uart_reset(struct omap_uart_s *s)
-{
-    s->eblr = 0x00;
-    s->syscontrol = 0;
-    s->wkup = 0x3f;
-    s->cfps = 0x69;
-    s->clksel = 0;
-}
-
-struct omap_uart_s *omap_uart_init(hwaddr base,
-                qemu_irq irq, omap_clk fclk, omap_clk iclk,
-                qemu_irq txdma, qemu_irq rxdma,
-                const char *label, CharDriverState *chr)
-{
-    struct omap_uart_s *s = (struct omap_uart_s *)
-            g_malloc0(sizeof(struct omap_uart_s));
-
-    s->base = base;
-    s->fclk = fclk;
-    s->irq = irq;
-    s->serial = serial_mm_init(get_system_memory(), base, 2, irq,
-                               omap_clk_getrate(fclk)/16,
-                               chr ?: qemu_chr_new(label, "null", NULL),
-                               DEVICE_NATIVE_ENDIAN);
-    return s;
-}
-
-static uint64_t omap_uart_read(void *opaque, hwaddr addr,
-                               unsigned size)
-{
-    struct omap_uart_s *s = (struct omap_uart_s *) opaque;
-
-    if (size == 4) {
-        return omap_badwidth_read8(opaque, addr);
-    }
-
-    switch (addr) {
-    case 0x20: /* MDR1 */
-        return s->mdr[0];
-    case 0x24: /* MDR2 */
-        return s->mdr[1];
-    case 0x40: /* SCR */
-        return s->scr;
-    case 0x44: /* SSR */
-        return 0x0;
-    case 0x48: /* EBLR (OMAP2) */
-        return s->eblr;
-    case 0x4C: /* OSC_12M_SEL (OMAP1) */
-        return s->clksel;
-    case 0x50: /* MVR */
-        return 0x30;
-    case 0x54: /* SYSC (OMAP2) */
-        return s->syscontrol;
-    case 0x58: /* SYSS (OMAP2) */
-        return 1;
-    case 0x5c: /* WER (OMAP2) */
-        return s->wkup;
-    case 0x60: /* CFPS (OMAP2) */
-        return s->cfps;
-    }
-
-    OMAP_BAD_REG(addr);
-    return 0;
-}
-
-static void omap_uart_write(void *opaque, hwaddr addr,
-                            uint64_t value, unsigned size)
-{
-    struct omap_uart_s *s = (struct omap_uart_s *) opaque;
-
-    if (size == 4) {
-        return omap_badwidth_write8(opaque, addr, value);
-    }
-
-    switch (addr) {
-    case 0x20: /* MDR1 */
-        s->mdr[0] = value & 0x7f;
-        break;
-    case 0x24: /* MDR2 */
-        s->mdr[1] = value & 0xff;
-        break;
-    case 0x40: /* SCR */
-        s->scr = value & 0xff;
-        break;
-    case 0x48: /* EBLR (OMAP2) */
-        s->eblr = value & 0xff;
-        break;
-    case 0x4C: /* OSC_12M_SEL (OMAP1) */
-        s->clksel = value & 1;
-        break;
-    case 0x44: /* SSR */
-    case 0x50: /* MVR */
-    case 0x58: /* SYSS (OMAP2) */
-        OMAP_RO_REG(addr);
-        break;
-    case 0x54: /* SYSC (OMAP2) */
-        s->syscontrol = value & 0x1d;
-        if (value & 2)
-            omap_uart_reset(s);
-        break;
-    case 0x5c: /* WER (OMAP2) */
-        s->wkup = value & 0x7f;
-        break;
-    case 0x60: /* CFPS (OMAP2) */
-        s->cfps = value & 0xff;
-        break;
-    default:
-        OMAP_BAD_REG(addr);
-    }
-}
-
-static const MemoryRegionOps omap_uart_ops = {
-    .read = omap_uart_read,
-    .write = omap_uart_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-struct omap_uart_s *omap2_uart_init(MemoryRegion *sysmem,
-                struct omap_target_agent_s *ta,
-                qemu_irq irq, omap_clk fclk, omap_clk iclk,
-                qemu_irq txdma, qemu_irq rxdma,
-                const char *label, CharDriverState *chr)
-{
-    hwaddr base = omap_l4_attach(ta, 0, NULL);
-    struct omap_uart_s *s = omap_uart_init(base, irq,
-                    fclk, iclk, txdma, rxdma, label, chr);
-
-    memory_region_init_io(&s->iomem, &omap_uart_ops, s, "omap.uart", 0x100);
-
-    s->ta = ta;
-
-    memory_region_add_subregion(sysmem, base + 0x20, &s->iomem);
-
-    return s;
-}
-
-void omap_uart_attach(struct omap_uart_s *s, CharDriverState *chr)
-{
-    /* TODO: Should reuse or destroy current s->serial */
-    s->serial = serial_mm_init(get_system_memory(), s->base, 2, s->irq,
-                               omap_clk_getrate(s->fclk) / 16,
-                               chr ?: qemu_chr_new("null", "null", NULL),
-                               DEVICE_NATIVE_ENDIAN);
-}
diff --git a/hw/onenand.c b/hw/onenand.c
deleted file mode 100644 (file)
index ddba366..0000000
+++ /dev/null
@@ -1,841 +0,0 @@
-/*
- * OneNAND flash memories emulation.
- *
- * Copyright (C) 2008 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.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 or
- * (at your option) version 3 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
- * 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 "hw/hw.h"
-#include "hw/flash.h"
-#include "hw/irq.h"
-#include "sysemu/blockdev.h"
-#include "exec/memory.h"
-#include "exec/address-spaces.h"
-#include "hw/sysbus.h"
-#include "qemu/error-report.h"
-
-/* 11 for 2kB-page OneNAND ("2nd generation") and 10 for 1kB-page chips */
-#define PAGE_SHIFT     11
-
-/* Fixed */
-#define BLOCK_SHIFT    (PAGE_SHIFT + 6)
-
-typedef struct {
-    SysBusDevice busdev;
-    struct {
-        uint16_t man;
-        uint16_t dev;
-        uint16_t ver;
-    } id;
-    int shift;
-    hwaddr base;
-    qemu_irq intr;
-    qemu_irq rdy;
-    BlockDriverState *bdrv;
-    BlockDriverState *bdrv_cur;
-    uint8_t *image;
-    uint8_t *otp;
-    uint8_t *current;
-    MemoryRegion ram;
-    MemoryRegion mapped_ram;
-    uint8_t current_direction;
-    uint8_t *boot[2];
-    uint8_t *data[2][2];
-    MemoryRegion iomem;
-    MemoryRegion container;
-    int cycle;
-    int otpmode;
-
-    uint16_t addr[8];
-    uint16_t unladdr[8];
-    int bufaddr;
-    int count;
-    uint16_t command;
-    uint16_t config[2];
-    uint16_t status;
-    uint16_t intstatus;
-    uint16_t wpstatus;
-
-    ECCState ecc;
-
-    int density_mask;
-    int secs;
-    int secs_cur;
-    int blocks;
-    uint8_t *blockwp;
-} OneNANDState;
-
-enum {
-    ONEN_BUF_BLOCK = 0,
-    ONEN_BUF_BLOCK2 = 1,
-    ONEN_BUF_DEST_BLOCK = 2,
-    ONEN_BUF_DEST_PAGE = 3,
-    ONEN_BUF_PAGE = 7,
-};
-
-enum {
-    ONEN_ERR_CMD = 1 << 10,
-    ONEN_ERR_ERASE = 1 << 11,
-    ONEN_ERR_PROG = 1 << 12,
-    ONEN_ERR_LOAD = 1 << 13,
-};
-
-enum {
-    ONEN_INT_RESET = 1 << 4,
-    ONEN_INT_ERASE = 1 << 5,
-    ONEN_INT_PROG = 1 << 6,
-    ONEN_INT_LOAD = 1 << 7,
-    ONEN_INT = 1 << 15,
-};
-
-enum {
-    ONEN_LOCK_LOCKTIGHTEN = 1 << 0,
-    ONEN_LOCK_LOCKED = 1 << 1,
-    ONEN_LOCK_UNLOCKED = 1 << 2,
-};
-
-static void onenand_mem_setup(OneNANDState *s)
-{
-    /* XXX: We should use IO_MEM_ROMD but we broke it earlier...
-     * Both 0x0000 ... 0x01ff and 0x8000 ... 0x800f can be used to
-     * write boot commands.  Also take note of the BWPS bit.  */
-    memory_region_init(&s->container, "onenand", 0x10000 << s->shift);
-    memory_region_add_subregion(&s->container, 0, &s->iomem);
-    memory_region_init_alias(&s->mapped_ram, "onenand-mapped-ram",
-                             &s->ram, 0x0200 << s->shift,
-                             0xbe00 << s->shift);
-    memory_region_add_subregion_overlap(&s->container,
-                                        0x0200 << s->shift,
-                                        &s->mapped_ram,
-                                        1);
-}
-
-static void onenand_intr_update(OneNANDState *s)
-{
-    qemu_set_irq(s->intr, ((s->intstatus >> 15) ^ (~s->config[0] >> 6)) & 1);
-}
-
-static void onenand_pre_save(void *opaque)
-{
-    OneNANDState *s = opaque;
-    if (s->current == s->otp) {
-        s->current_direction = 1;
-    } else if (s->current == s->image) {
-        s->current_direction = 2;
-    } else {
-        s->current_direction = 0;
-    }
-}
-
-static int onenand_post_load(void *opaque, int version_id)
-{
-    OneNANDState *s = opaque;
-    switch (s->current_direction) {
-    case 0:
-        break;
-    case 1:
-        s->current = s->otp;
-        break;
-    case 2:
-        s->current = s->image;
-        break;
-    default:
-        return -1;
-    }
-    onenand_intr_update(s);
-    return 0;
-}
-
-static const VMStateDescription vmstate_onenand = {
-    .name = "onenand",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .pre_save = onenand_pre_save,
-    .post_load = onenand_post_load,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT8(current_direction, OneNANDState),
-        VMSTATE_INT32(cycle, OneNANDState),
-        VMSTATE_INT32(otpmode, OneNANDState),
-        VMSTATE_UINT16_ARRAY(addr, OneNANDState, 8),
-        VMSTATE_UINT16_ARRAY(unladdr, OneNANDState, 8),
-        VMSTATE_INT32(bufaddr, OneNANDState),
-        VMSTATE_INT32(count, OneNANDState),
-        VMSTATE_UINT16(command, OneNANDState),
-        VMSTATE_UINT16_ARRAY(config, OneNANDState, 2),
-        VMSTATE_UINT16(status, OneNANDState),
-        VMSTATE_UINT16(intstatus, OneNANDState),
-        VMSTATE_UINT16(wpstatus, OneNANDState),
-        VMSTATE_INT32(secs_cur, OneNANDState),
-        VMSTATE_PARTIAL_VBUFFER(blockwp, OneNANDState, blocks),
-        VMSTATE_UINT8(ecc.cp, OneNANDState),
-        VMSTATE_UINT16_ARRAY(ecc.lp, OneNANDState, 2),
-        VMSTATE_UINT16(ecc.count, OneNANDState),
-        VMSTATE_BUFFER_UNSAFE(otp, OneNANDState, 0, ((64 + 2) << PAGE_SHIFT)),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-/* Hot reset (Reset OneNAND command) or warm reset (RP pin low) */
-static void onenand_reset(OneNANDState *s, int cold)
-{
-    memset(&s->addr, 0, sizeof(s->addr));
-    s->command = 0;
-    s->count = 1;
-    s->bufaddr = 0;
-    s->config[0] = 0x40c0;
-    s->config[1] = 0x0000;
-    onenand_intr_update(s);
-    qemu_irq_raise(s->rdy);
-    s->status = 0x0000;
-    s->intstatus = cold ? 0x8080 : 0x8010;
-    s->unladdr[0] = 0;
-    s->unladdr[1] = 0;
-    s->wpstatus = 0x0002;
-    s->cycle = 0;
-    s->otpmode = 0;
-    s->bdrv_cur = s->bdrv;
-    s->current = s->image;
-    s->secs_cur = s->secs;
-
-    if (cold) {
-        /* Lock the whole flash */
-        memset(s->blockwp, ONEN_LOCK_LOCKED, s->blocks);
-
-        if (s->bdrv_cur && bdrv_read(s->bdrv_cur, 0, s->boot[0], 8) < 0) {
-            hw_error("%s: Loading the BootRAM failed.\n", __func__);
-        }
-    }
-}
-
-static void onenand_system_reset(DeviceState *dev)
-{
-    onenand_reset(FROM_SYSBUS(OneNANDState, SYS_BUS_DEVICE(dev)), 1);
-}
-
-static inline int onenand_load_main(OneNANDState *s, int sec, int secn,
-                void *dest)
-{
-    if (s->bdrv_cur)
-        return bdrv_read(s->bdrv_cur, sec, dest, secn) < 0;
-    else if (sec + secn > s->secs_cur)
-        return 1;
-
-    memcpy(dest, s->current + (sec << 9), secn << 9);
-
-    return 0;
-}
-
-static inline int onenand_prog_main(OneNANDState *s, int sec, int secn,
-                void *src)
-{
-    int result = 0;
-
-    if (secn > 0) {
-        uint32_t size = (uint32_t)secn * 512;
-        const uint8_t *sp = (const uint8_t *)src;
-        uint8_t *dp = 0;
-        if (s->bdrv_cur) {
-            dp = g_malloc(size);
-            if (!dp || bdrv_read(s->bdrv_cur, sec, dp, secn) < 0) {
-                result = 1;
-            }
-        } else {
-            if (sec + secn > s->secs_cur) {
-                result = 1;
-            } else {
-                dp = (uint8_t *)s->current + (sec << 9);
-            }
-        }
-        if (!result) {
-            uint32_t i;
-            for (i = 0; i < size; i++) {
-                dp[i] &= sp[i];
-            }
-            if (s->bdrv_cur) {
-                result = bdrv_write(s->bdrv_cur, sec, dp, secn) < 0;
-            }
-        }
-        if (dp && s->bdrv_cur) {
-            g_free(dp);
-        }
-    }
-
-    return result;
-}
-
-static inline int onenand_load_spare(OneNANDState *s, int sec, int secn,
-                void *dest)
-{
-    uint8_t buf[512];
-
-    if (s->bdrv_cur) {
-        if (bdrv_read(s->bdrv_cur, s->secs_cur + (sec >> 5), buf, 1) < 0)
-            return 1;
-        memcpy(dest, buf + ((sec & 31) << 4), secn << 4);
-    } else if (sec + secn > s->secs_cur)
-        return 1;
-    else
-        memcpy(dest, s->current + (s->secs_cur << 9) + (sec << 4), secn << 4);
-    return 0;
-}
-
-static inline int onenand_prog_spare(OneNANDState *s, int sec, int secn,
-                void *src)
-{
-    int result = 0;
-    if (secn > 0) {
-        const uint8_t *sp = (const uint8_t *)src;
-        uint8_t *dp = 0, *dpp = 0;
-        if (s->bdrv_cur) {
-            dp = g_malloc(512);
-            if (!dp || bdrv_read(s->bdrv_cur,
-                                 s->secs_cur + (sec >> 5),
-                                 dp, 1) < 0) {
-                result = 1;
-            } else {
-                dpp = dp + ((sec & 31) << 4);
-            }
-        } else {
-            if (sec + secn > s->secs_cur) {
-                result = 1;
-            } else {
-                dpp = s->current + (s->secs_cur << 9) + (sec << 4);
-            }
-        }
-        if (!result) {
-            uint32_t i;
-            for (i = 0; i < (secn << 4); i++) {
-                dpp[i] &= sp[i];
-            }
-            if (s->bdrv_cur) {
-                result = bdrv_write(s->bdrv_cur, s->secs_cur + (sec >> 5),
-                                    dp, 1) < 0;
-            }
-        }
-        if (dp) {
-            g_free(dp);
-        }
-    }
-    return result;
-}
-
-static inline int onenand_erase(OneNANDState *s, int sec, int num)
-{
-    uint8_t *blankbuf, *tmpbuf;
-    blankbuf = g_malloc(512);
-    if (!blankbuf) {
-        return 1;
-    }
-    tmpbuf = g_malloc(512);
-    if (!tmpbuf) {
-        g_free(blankbuf);
-        return 1;
-    }
-    memset(blankbuf, 0xff, 512);
-    for (; num > 0; num--, sec++) {
-        if (s->bdrv_cur) {
-            int erasesec = s->secs_cur + (sec >> 5);
-            if (bdrv_write(s->bdrv_cur, sec, blankbuf, 1) < 0) {
-                goto fail;
-            }
-            if (bdrv_read(s->bdrv_cur, erasesec, tmpbuf, 1) < 0) {
-                goto fail;
-            }
-            memcpy(tmpbuf + ((sec & 31) << 4), blankbuf, 1 << 4);
-            if (bdrv_write(s->bdrv_cur, erasesec, tmpbuf, 1) < 0) {
-                goto fail;
-            }
-        } else {
-            if (sec + 1 > s->secs_cur) {
-                goto fail;
-            }
-            memcpy(s->current + (sec << 9), blankbuf, 512);
-            memcpy(s->current + (s->secs_cur << 9) + (sec << 4),
-                   blankbuf, 1 << 4);
-        }
-    }
-
-    g_free(tmpbuf);
-    g_free(blankbuf);
-    return 0;
-
-fail:
-    g_free(tmpbuf);
-    g_free(blankbuf);
-    return 1;
-}
-
-static void onenand_command(OneNANDState *s)
-{
-    int b;
-    int sec;
-    void *buf;
-#define SETADDR(block, page)                   \
-    sec = (s->addr[page] & 3) +                        \
-            ((((s->addr[page] >> 2) & 0x3f) +  \
-              (((s->addr[block] & 0xfff) |     \
-                (s->addr[block] >> 15 ?                \
-                 s->density_mask : 0)) << 6)) << (PAGE_SHIFT - 9));
-#define SETBUF_M()                             \
-    buf = (s->bufaddr & 8) ?                   \
-            s->data[(s->bufaddr >> 2) & 1][0] : s->boot[0];    \
-    buf += (s->bufaddr & 3) << 9;
-#define SETBUF_S()                             \
-    buf = (s->bufaddr & 8) ?                   \
-            s->data[(s->bufaddr >> 2) & 1][1] : s->boot[1];    \
-    buf += (s->bufaddr & 3) << 4;
-
-    switch (s->command) {
-    case 0x00: /* Load single/multiple sector data unit into buffer */
-        SETADDR(ONEN_BUF_BLOCK, ONEN_BUF_PAGE)
-
-        SETBUF_M()
-        if (onenand_load_main(s, sec, s->count, buf))
-            s->status |= ONEN_ERR_CMD | ONEN_ERR_LOAD;
-
-#if 0
-        SETBUF_S()
-        if (onenand_load_spare(s, sec, s->count, buf))
-            s->status |= ONEN_ERR_CMD | ONEN_ERR_LOAD;
-#endif
-
-        /* TODO: if (s->bufaddr & 3) + s->count was > 4 (2k-pages)
-         * or    if (s->bufaddr & 1) + s->count was > 2 (1k-pages)
-         * then we need two split the read/write into two chunks.
-         */
-        s->intstatus |= ONEN_INT | ONEN_INT_LOAD;
-        break;
-    case 0x13: /* Load single/multiple spare sector into buffer */
-        SETADDR(ONEN_BUF_BLOCK, ONEN_BUF_PAGE)
-
-        SETBUF_S()
-        if (onenand_load_spare(s, sec, s->count, buf))
-            s->status |= ONEN_ERR_CMD | ONEN_ERR_LOAD;
-
-        /* TODO: if (s->bufaddr & 3) + s->count was > 4 (2k-pages)
-         * or    if (s->bufaddr & 1) + s->count was > 2 (1k-pages)
-         * then we need two split the read/write into two chunks.
-         */
-        s->intstatus |= ONEN_INT | ONEN_INT_LOAD;
-        break;
-    case 0x80: /* Program single/multiple sector data unit from buffer */
-        SETADDR(ONEN_BUF_BLOCK, ONEN_BUF_PAGE)
-
-        SETBUF_M()
-        if (onenand_prog_main(s, sec, s->count, buf))
-            s->status |= ONEN_ERR_CMD | ONEN_ERR_PROG;
-
-#if 0
-        SETBUF_S()
-        if (onenand_prog_spare(s, sec, s->count, buf))
-            s->status |= ONEN_ERR_CMD | ONEN_ERR_PROG;
-#endif
-
-        /* TODO: if (s->bufaddr & 3) + s->count was > 4 (2k-pages)
-         * or    if (s->bufaddr & 1) + s->count was > 2 (1k-pages)
-         * then we need two split the read/write into two chunks.
-         */
-        s->intstatus |= ONEN_INT | ONEN_INT_PROG;
-        break;
-    case 0x1a: /* Program single/multiple spare area sector from buffer */
-        SETADDR(ONEN_BUF_BLOCK, ONEN_BUF_PAGE)
-
-        SETBUF_S()
-        if (onenand_prog_spare(s, sec, s->count, buf))
-            s->status |= ONEN_ERR_CMD | ONEN_ERR_PROG;
-
-        /* TODO: if (s->bufaddr & 3) + s->count was > 4 (2k-pages)
-         * or    if (s->bufaddr & 1) + s->count was > 2 (1k-pages)
-         * then we need two split the read/write into two chunks.
-         */
-        s->intstatus |= ONEN_INT | ONEN_INT_PROG;
-        break;
-    case 0x1b: /* Copy-back program */
-        SETBUF_S()
-
-        SETADDR(ONEN_BUF_BLOCK, ONEN_BUF_PAGE)
-        if (onenand_load_main(s, sec, s->count, buf))
-            s->status |= ONEN_ERR_CMD | ONEN_ERR_PROG;
-
-        SETADDR(ONEN_BUF_DEST_BLOCK, ONEN_BUF_DEST_PAGE)
-        if (onenand_prog_main(s, sec, s->count, buf))
-            s->status |= ONEN_ERR_CMD | ONEN_ERR_PROG;
-
-        /* TODO: spare areas */
-
-        s->intstatus |= ONEN_INT | ONEN_INT_PROG;
-        break;
-
-    case 0x23: /* Unlock NAND array block(s) */
-        s->intstatus |= ONEN_INT;
-
-        /* XXX the previous (?) area should be locked automatically */
-        for (b = s->unladdr[0]; b <= s->unladdr[1]; b ++) {
-            if (b >= s->blocks) {
-                s->status |= ONEN_ERR_CMD;
-                break;
-            }
-            if (s->blockwp[b] == ONEN_LOCK_LOCKTIGHTEN)
-                break;
-
-            s->wpstatus = s->blockwp[b] = ONEN_LOCK_UNLOCKED;
-        }
-        break;
-    case 0x27: /* Unlock All NAND array blocks */
-        s->intstatus |= ONEN_INT;
-
-        for (b = 0; b < s->blocks; b ++) {
-            if (b >= s->blocks) {
-                s->status |= ONEN_ERR_CMD;
-                break;
-            }
-            if (s->blockwp[b] == ONEN_LOCK_LOCKTIGHTEN)
-                break;
-
-            s->wpstatus = s->blockwp[b] = ONEN_LOCK_UNLOCKED;
-        }
-        break;
-
-    case 0x2a: /* Lock NAND array block(s) */
-        s->intstatus |= ONEN_INT;
-
-        for (b = s->unladdr[0]; b <= s->unladdr[1]; b ++) {
-            if (b >= s->blocks) {
-                s->status |= ONEN_ERR_CMD;
-                break;
-            }
-            if (s->blockwp[b] == ONEN_LOCK_LOCKTIGHTEN)
-                break;
-
-            s->wpstatus = s->blockwp[b] = ONEN_LOCK_LOCKED;
-        }
-        break;
-    case 0x2c: /* Lock-tight NAND array block(s) */
-        s->intstatus |= ONEN_INT;
-
-        for (b = s->unladdr[0]; b <= s->unladdr[1]; b ++) {
-            if (b >= s->blocks) {
-                s->status |= ONEN_ERR_CMD;
-                break;
-            }
-            if (s->blockwp[b] == ONEN_LOCK_UNLOCKED)
-                continue;
-
-            s->wpstatus = s->blockwp[b] = ONEN_LOCK_LOCKTIGHTEN;
-        }
-        break;
-
-    case 0x71: /* Erase-Verify-Read */
-        s->intstatus |= ONEN_INT;
-        break;
-    case 0x95: /* Multi-block erase */
-        qemu_irq_pulse(s->intr);
-        /* Fall through.  */
-    case 0x94: /* Block erase */
-        sec = ((s->addr[ONEN_BUF_BLOCK] & 0xfff) |
-                        (s->addr[ONEN_BUF_BLOCK] >> 15 ? s->density_mask : 0))
-                << (BLOCK_SHIFT - 9);
-        if (onenand_erase(s, sec, 1 << (BLOCK_SHIFT - 9)))
-            s->status |= ONEN_ERR_CMD | ONEN_ERR_ERASE;
-
-        s->intstatus |= ONEN_INT | ONEN_INT_ERASE;
-        break;
-    case 0xb0: /* Erase suspend */
-        break;
-    case 0x30: /* Erase resume */
-        s->intstatus |= ONEN_INT | ONEN_INT_ERASE;
-        break;
-
-    case 0xf0: /* Reset NAND Flash core */
-        onenand_reset(s, 0);
-        break;
-    case 0xf3: /* Reset OneNAND */
-        onenand_reset(s, 0);
-        break;
-
-    case 0x65: /* OTP Access */
-        s->intstatus |= ONEN_INT;
-        s->bdrv_cur = NULL;
-        s->current = s->otp;
-        s->secs_cur = 1 << (BLOCK_SHIFT - 9);
-        s->addr[ONEN_BUF_BLOCK] = 0;
-        s->otpmode = 1;
-        break;
-
-    default:
-        s->status |= ONEN_ERR_CMD;
-        s->intstatus |= ONEN_INT;
-        fprintf(stderr, "%s: unknown OneNAND command %x\n",
-                        __func__, s->command);
-    }
-
-    onenand_intr_update(s);
-}
-
-static uint64_t onenand_read(void *opaque, hwaddr addr,
-                             unsigned size)
-{
-    OneNANDState *s = (OneNANDState *) opaque;
-    int offset = addr >> s->shift;
-
-    switch (offset) {
-    case 0x0000 ... 0xc000:
-        return lduw_le_p(s->boot[0] + addr);
-
-    case 0xf000:       /* Manufacturer ID */
-        return s->id.man;
-    case 0xf001:       /* Device ID */
-        return s->id.dev;
-    case 0xf002:       /* Version ID */
-        return s->id.ver;
-    /* TODO: get the following values from a real chip!  */
-    case 0xf003:       /* Data Buffer size */
-        return 1 << PAGE_SHIFT;
-    case 0xf004:       /* Boot Buffer size */
-        return 0x200;
-    case 0xf005:       /* Amount of buffers */
-        return 1 | (2 << 8);
-    case 0xf006:       /* Technology */
-        return 0;
-
-    case 0xf100 ... 0xf107:    /* Start addresses */
-        return s->addr[offset - 0xf100];
-
-    case 0xf200:       /* Start buffer */
-        return (s->bufaddr << 8) | ((s->count - 1) & (1 << (PAGE_SHIFT - 10)));
-
-    case 0xf220:       /* Command */
-        return s->command;
-    case 0xf221:       /* System Configuration 1 */
-        return s->config[0] & 0xffe0;
-    case 0xf222:       /* System Configuration 2 */
-        return s->config[1];
-
-    case 0xf240:       /* Controller Status */
-        return s->status;
-    case 0xf241:       /* Interrupt */
-        return s->intstatus;
-    case 0xf24c:       /* Unlock Start Block Address */
-        return s->unladdr[0];
-    case 0xf24d:       /* Unlock End Block Address */
-        return s->unladdr[1];
-    case 0xf24e:       /* Write Protection Status */
-        return s->wpstatus;
-
-    case 0xff00:       /* ECC Status */
-        return 0x00;
-    case 0xff01:       /* ECC Result of main area data */
-    case 0xff02:       /* ECC Result of spare area data */
-    case 0xff03:       /* ECC Result of main area data */
-    case 0xff04:       /* ECC Result of spare area data */
-        hw_error("%s: imeplement ECC\n", __FUNCTION__);
-        return 0x0000;
-    }
-
-    fprintf(stderr, "%s: unknown OneNAND register %x\n",
-                    __FUNCTION__, offset);
-    return 0;
-}
-
-static void onenand_write(void *opaque, hwaddr addr,
-                          uint64_t value, unsigned size)
-{
-    OneNANDState *s = (OneNANDState *) opaque;
-    int offset = addr >> s->shift;
-    int sec;
-
-    switch (offset) {
-    case 0x0000 ... 0x01ff:
-    case 0x8000 ... 0x800f:
-        if (s->cycle) {
-            s->cycle = 0;
-
-            if (value == 0x0000) {
-                SETADDR(ONEN_BUF_BLOCK, ONEN_BUF_PAGE)
-                onenand_load_main(s, sec,
-                                1 << (PAGE_SHIFT - 9), s->data[0][0]);
-                s->addr[ONEN_BUF_PAGE] += 4;
-                s->addr[ONEN_BUF_PAGE] &= 0xff;
-            }
-            break;
-        }
-
-        switch (value) {
-        case 0x00f0:   /* Reset OneNAND */
-            onenand_reset(s, 0);
-            break;
-
-        case 0x00e0:   /* Load Data into Buffer */
-            s->cycle = 1;
-            break;
-
-        case 0x0090:   /* Read Identification Data */
-            memset(s->boot[0], 0, 3 << s->shift);
-            s->boot[0][0 << s->shift] = s->id.man & 0xff;
-            s->boot[0][1 << s->shift] = s->id.dev & 0xff;
-            s->boot[0][2 << s->shift] = s->wpstatus & 0xff;
-            break;
-
-        default:
-            fprintf(stderr, "%s: unknown OneNAND boot command %"PRIx64"\n",
-                            __FUNCTION__, value);
-        }
-        break;
-
-    case 0xf100 ... 0xf107:    /* Start addresses */
-        s->addr[offset - 0xf100] = value;
-        break;
-
-    case 0xf200:       /* Start buffer */
-        s->bufaddr = (value >> 8) & 0xf;
-        if (PAGE_SHIFT == 11)
-            s->count = (value & 3) ?: 4;
-        else if (PAGE_SHIFT == 10)
-            s->count = (value & 1) ?: 2;
-        break;
-
-    case 0xf220:       /* Command */
-        if (s->intstatus & (1 << 15))
-            break;
-        s->command = value;
-        onenand_command(s);
-        break;
-    case 0xf221:       /* System Configuration 1 */
-        s->config[0] = value;
-        onenand_intr_update(s);
-        qemu_set_irq(s->rdy, (s->config[0] >> 7) & 1);
-        break;
-    case 0xf222:       /* System Configuration 2 */
-        s->config[1] = value;
-        break;
-
-    case 0xf241:       /* Interrupt */
-        s->intstatus &= value;
-        if ((1 << 15) & ~s->intstatus)
-            s->status &= ~(ONEN_ERR_CMD | ONEN_ERR_ERASE |
-                            ONEN_ERR_PROG | ONEN_ERR_LOAD);
-        onenand_intr_update(s);
-        break;
-    case 0xf24c:       /* Unlock Start Block Address */
-        s->unladdr[0] = value & (s->blocks - 1);
-        /* For some reason we have to set the end address to by default
-         * be same as start because the software forgets to write anything
-         * in there.  */
-        s->unladdr[1] = value & (s->blocks - 1);
-        break;
-    case 0xf24d:       /* Unlock End Block Address */
-        s->unladdr[1] = value & (s->blocks - 1);
-        break;
-
-    default:
-        fprintf(stderr, "%s: unknown OneNAND register %x\n",
-                        __FUNCTION__, offset);
-    }
-}
-
-static const MemoryRegionOps onenand_ops = {
-    .read = onenand_read,
-    .write = onenand_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int onenand_initfn(SysBusDevice *dev)
-{
-    OneNANDState *s = (OneNANDState *)dev;
-    uint32_t size = 1 << (24 + ((s->id.dev >> 4) & 7));
-    void *ram;
-    s->base = (hwaddr)-1;
-    s->rdy = NULL;
-    s->blocks = size >> BLOCK_SHIFT;
-    s->secs = size >> 9;
-    s->blockwp = g_malloc(s->blocks);
-    s->density_mask = (s->id.dev & 0x08)
-        ? (1 << (6 + ((s->id.dev >> 4) & 7))) : 0;
-    memory_region_init_io(&s->iomem, &onenand_ops, s, "onenand",
-                          0x10000 << s->shift);
-    if (!s->bdrv) {
-        s->image = memset(g_malloc(size + (size >> 5)),
-                          0xff, size + (size >> 5));
-    } else {
-        if (bdrv_is_read_only(s->bdrv)) {
-            error_report("Can't use a read-only drive");
-            return -1;
-        }
-        s->bdrv_cur = s->bdrv;
-    }
-    s->otp = memset(g_malloc((64 + 2) << PAGE_SHIFT),
-                    0xff, (64 + 2) << PAGE_SHIFT);
-    memory_region_init_ram(&s->ram, "onenand.ram", 0xc000 << s->shift);
-    vmstate_register_ram_global(&s->ram);
-    ram = memory_region_get_ram_ptr(&s->ram);
-    s->boot[0] = ram + (0x0000 << s->shift);
-    s->boot[1] = ram + (0x8000 << s->shift);
-    s->data[0][0] = ram + ((0x0200 + (0 << (PAGE_SHIFT - 1))) << s->shift);
-    s->data[0][1] = ram + ((0x8010 + (0 << (PAGE_SHIFT - 6))) << s->shift);
-    s->data[1][0] = ram + ((0x0200 + (1 << (PAGE_SHIFT - 1))) << s->shift);
-    s->data[1][1] = ram + ((0x8010 + (1 << (PAGE_SHIFT - 6))) << s->shift);
-    onenand_mem_setup(s);
-    sysbus_init_irq(dev, &s->intr);
-    sysbus_init_mmio(dev, &s->container);
-    vmstate_register(&dev->qdev,
-                     ((s->shift & 0x7f) << 24)
-                     | ((s->id.man & 0xff) << 16)
-                     | ((s->id.dev & 0xff) << 8)
-                     | (s->id.ver & 0xff),
-                     &vmstate_onenand, s);
-    return 0;
-}
-
-static Property onenand_properties[] = {
-    DEFINE_PROP_UINT16("manufacturer_id", OneNANDState, id.man, 0),
-    DEFINE_PROP_UINT16("device_id", OneNANDState, id.dev, 0),
-    DEFINE_PROP_UINT16("version_id", OneNANDState, id.ver, 0),
-    DEFINE_PROP_INT32("shift", OneNANDState, shift, 0),
-    DEFINE_PROP_DRIVE("drive", OneNANDState, bdrv),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void onenand_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = onenand_initfn;
-    dc->reset = onenand_system_reset;
-    dc->props = onenand_properties;
-}
-
-static const TypeInfo onenand_info = {
-    .name          = "onenand",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(OneNANDState),
-    .class_init    = onenand_class_init,
-};
-
-static void onenand_register_types(void)
-{
-    type_register_static(&onenand_info);
-}
-
-void *onenand_raw_otp(DeviceState *onenand_device)
-{
-    return FROM_SYSBUS(OneNANDState, SYS_BUS_DEVICE(onenand_device))->otp;
-}
-
-type_init(onenand_register_types)
diff --git a/hw/opencores_eth.c b/hw/opencores_eth.c
deleted file mode 100644 (file)
index be64bf2..0000000
+++ /dev/null
@@ -1,733 +0,0 @@
-/*
- * OpenCores Ethernet MAC 10/100 + subset of
- * National Semiconductors DP83848C 10/100 PHY
- *
- * http://opencores.org/svnget,ethmac?file=%2Ftrunk%2F%2Fdoc%2Feth_speci.pdf
- * http://cache.national.com/ds/DP/DP83848C.pdf
- *
- * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in the
- *       documentation and/or other materials provided with the distribution.
- *     * Neither the name of the Open Source and Linux Lab nor the
- *       names of its contributors may be used to endorse or promote products
- *       derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "hw/hw.h"
-#include "hw/sysbus.h"
-#include "net/net.h"
-#include "sysemu/sysemu.h"
-#include "trace.h"
-
-/* RECSMALL is not used because it breaks tap networking in linux:
- * incoming ARP responses are too short
- */
-#undef USE_RECSMALL
-
-#define GET_FIELD(v, field) (((v) & (field)) >> (field ## _LBN))
-#define GET_REGBIT(s, reg, field) ((s)->regs[reg] & (reg ## _ ## field))
-#define GET_REGFIELD(s, reg, field) \
-    GET_FIELD((s)->regs[reg], reg ## _ ## field)
-
-#define SET_FIELD(v, field, data) \
-    ((v) = (((v) & ~(field)) | (((data) << (field ## _LBN)) & (field))))
-#define SET_REGFIELD(s, reg, field, data) \
-    SET_FIELD((s)->regs[reg], reg ## _ ## field, data)
-
-/* PHY MII registers */
-enum {
-    MII_BMCR,
-    MII_BMSR,
-    MII_PHYIDR1,
-    MII_PHYIDR2,
-    MII_ANAR,
-    MII_ANLPAR,
-    MII_REG_MAX = 16,
-};
-
-typedef struct Mii {
-    uint16_t regs[MII_REG_MAX];
-    bool link_ok;
-} Mii;
-
-static void mii_set_link(Mii *s, bool link_ok)
-{
-    if (link_ok) {
-        s->regs[MII_BMSR] |= 0x4;
-        s->regs[MII_ANLPAR] |= 0x01e1;
-    } else {
-        s->regs[MII_BMSR] &= ~0x4;
-        s->regs[MII_ANLPAR] &= 0x01ff;
-    }
-    s->link_ok = link_ok;
-}
-
-static void mii_reset(Mii *s)
-{
-    memset(s->regs, 0, sizeof(s->regs));
-    s->regs[MII_BMCR] = 0x1000;
-    s->regs[MII_BMSR] = 0x7848; /* no ext regs */
-    s->regs[MII_PHYIDR1] = 0x2000;
-    s->regs[MII_PHYIDR2] = 0x5c90;
-    s->regs[MII_ANAR] = 0x01e1;
-    mii_set_link(s, s->link_ok);
-}
-
-static void mii_ro(Mii *s, uint16_t v)
-{
-}
-
-static void mii_write_bmcr(Mii *s, uint16_t v)
-{
-    if (v & 0x8000) {
-        mii_reset(s);
-    } else {
-        s->regs[MII_BMCR] = v;
-    }
-}
-
-static void mii_write_host(Mii *s, unsigned idx, uint16_t v)
-{
-    static void (*reg_write[MII_REG_MAX])(Mii *s, uint16_t v) = {
-        [MII_BMCR] = mii_write_bmcr,
-        [MII_BMSR] = mii_ro,
-        [MII_PHYIDR1] = mii_ro,
-        [MII_PHYIDR2] = mii_ro,
-    };
-
-    if (idx < MII_REG_MAX) {
-        trace_open_eth_mii_write(idx, v);
-        if (reg_write[idx]) {
-            reg_write[idx](s, v);
-        } else {
-            s->regs[idx] = v;
-        }
-    }
-}
-
-static uint16_t mii_read_host(Mii *s, unsigned idx)
-{
-    trace_open_eth_mii_read(idx, s->regs[idx]);
-    return s->regs[idx];
-}
-
-/* OpenCores Ethernet registers */
-enum {
-    MODER,
-    INT_SOURCE,
-    INT_MASK,
-    IPGT,
-    IPGR1,
-    IPGR2,
-    PACKETLEN,
-    COLLCONF,
-    TX_BD_NUM,
-    CTRLMODER,
-    MIIMODER,
-    MIICOMMAND,
-    MIIADDRESS,
-    MIITX_DATA,
-    MIIRX_DATA,
-    MIISTATUS,
-    MAC_ADDR0,
-    MAC_ADDR1,
-    HASH0,
-    HASH1,
-    TXCTRL,
-    REG_MAX,
-};
-
-enum {
-    MODER_RECSMALL = 0x10000,
-    MODER_PAD = 0x8000,
-    MODER_HUGEN = 0x4000,
-    MODER_RST = 0x800,
-    MODER_LOOPBCK = 0x80,
-    MODER_PRO = 0x20,
-    MODER_IAM = 0x10,
-    MODER_BRO = 0x8,
-    MODER_TXEN = 0x2,
-    MODER_RXEN = 0x1,
-};
-
-enum {
-    INT_SOURCE_RXB = 0x4,
-    INT_SOURCE_TXB = 0x1,
-};
-
-enum {
-    PACKETLEN_MINFL = 0xffff0000,
-    PACKETLEN_MINFL_LBN = 16,
-    PACKETLEN_MAXFL = 0xffff,
-    PACKETLEN_MAXFL_LBN = 0,
-};
-
-enum {
-    MIICOMMAND_WCTRLDATA = 0x4,
-    MIICOMMAND_RSTAT = 0x2,
-    MIICOMMAND_SCANSTAT = 0x1,
-};
-
-enum {
-    MIIADDRESS_RGAD = 0x1f00,
-    MIIADDRESS_RGAD_LBN = 8,
-    MIIADDRESS_FIAD = 0x1f,
-    MIIADDRESS_FIAD_LBN = 0,
-};
-
-enum {
-    MIITX_DATA_CTRLDATA = 0xffff,
-    MIITX_DATA_CTRLDATA_LBN = 0,
-};
-
-enum {
-    MIIRX_DATA_PRSD = 0xffff,
-    MIIRX_DATA_PRSD_LBN = 0,
-};
-
-enum {
-    MIISTATUS_LINKFAIL = 0x1,
-    MIISTATUS_LINKFAIL_LBN = 0,
-};
-
-enum {
-    MAC_ADDR0_BYTE2 = 0xff000000,
-    MAC_ADDR0_BYTE2_LBN = 24,
-    MAC_ADDR0_BYTE3 = 0xff0000,
-    MAC_ADDR0_BYTE3_LBN = 16,
-    MAC_ADDR0_BYTE4 = 0xff00,
-    MAC_ADDR0_BYTE4_LBN = 8,
-    MAC_ADDR0_BYTE5 = 0xff,
-    MAC_ADDR0_BYTE5_LBN = 0,
-};
-
-enum {
-    MAC_ADDR1_BYTE0 = 0xff00,
-    MAC_ADDR1_BYTE0_LBN = 8,
-    MAC_ADDR1_BYTE1 = 0xff,
-    MAC_ADDR1_BYTE1_LBN = 0,
-};
-
-enum {
-    TXD_LEN = 0xffff0000,
-    TXD_LEN_LBN = 16,
-    TXD_RD = 0x8000,
-    TXD_IRQ = 0x4000,
-    TXD_WR = 0x2000,
-    TXD_PAD = 0x1000,
-    TXD_CRC = 0x800,
-    TXD_UR = 0x100,
-    TXD_RTRY = 0xf0,
-    TXD_RTRY_LBN = 4,
-    TXD_RL = 0x8,
-    TXD_LC = 0x4,
-    TXD_DF = 0x2,
-    TXD_CS = 0x1,
-};
-
-enum {
-    RXD_LEN = 0xffff0000,
-    RXD_LEN_LBN = 16,
-    RXD_E = 0x8000,
-    RXD_IRQ = 0x4000,
-    RXD_WRAP = 0x2000,
-    RXD_CF = 0x100,
-    RXD_M = 0x80,
-    RXD_OR = 0x40,
-    RXD_IS = 0x20,
-    RXD_DN = 0x10,
-    RXD_TL = 0x8,
-    RXD_SF = 0x4,
-    RXD_CRC = 0x2,
-    RXD_LC = 0x1,
-};
-
-typedef struct desc {
-    uint32_t len_flags;
-    uint32_t buf_ptr;
-} desc;
-
-#define DEFAULT_PHY 1
-
-typedef struct OpenEthState {
-    SysBusDevice dev;
-    NICState *nic;
-    NICConf conf;
-    MemoryRegion reg_io;
-    MemoryRegion desc_io;
-    qemu_irq irq;
-
-    Mii mii;
-    uint32_t regs[REG_MAX];
-    unsigned tx_desc;
-    unsigned rx_desc;
-    desc desc[128];
-} OpenEthState;
-
-static desc *rx_desc(OpenEthState *s)
-{
-    return s->desc + s->rx_desc;
-}
-
-static desc *tx_desc(OpenEthState *s)
-{
-    return s->desc + s->tx_desc;
-}
-
-static void open_eth_update_irq(OpenEthState *s,
-        uint32_t old, uint32_t new)
-{
-    if (!old != !new) {
-        trace_open_eth_update_irq(new);
-        qemu_set_irq(s->irq, new);
-    }
-}
-
-static void open_eth_int_source_write(OpenEthState *s,
-        uint32_t val)
-{
-    uint32_t old_val = s->regs[INT_SOURCE];
-
-    s->regs[INT_SOURCE] = val;
-    open_eth_update_irq(s, old_val & s->regs[INT_MASK],
-            s->regs[INT_SOURCE] & s->regs[INT_MASK]);
-}
-
-static void open_eth_set_link_status(NetClientState *nc)
-{
-    OpenEthState *s = qemu_get_nic_opaque(nc);
-
-    if (GET_REGBIT(s, MIICOMMAND, SCANSTAT)) {
-        SET_REGFIELD(s, MIISTATUS, LINKFAIL, nc->link_down);
-    }
-    mii_set_link(&s->mii, !nc->link_down);
-}
-
-static void open_eth_reset(void *opaque)
-{
-    OpenEthState *s = opaque;
-
-    memset(s->regs, 0, sizeof(s->regs));
-    s->regs[MODER] = 0xa000;
-    s->regs[IPGT] = 0x12;
-    s->regs[IPGR1] = 0xc;
-    s->regs[IPGR2] = 0x12;
-    s->regs[PACKETLEN] = 0x400600;
-    s->regs[COLLCONF] = 0xf003f;
-    s->regs[TX_BD_NUM] = 0x40;
-    s->regs[MIIMODER] = 0x64;
-
-    s->tx_desc = 0;
-    s->rx_desc = 0x40;
-
-    mii_reset(&s->mii);
-    open_eth_set_link_status(qemu_get_queue(s->nic));
-}
-
-static int open_eth_can_receive(NetClientState *nc)
-{
-    OpenEthState *s = qemu_get_nic_opaque(nc);
-
-    return GET_REGBIT(s, MODER, RXEN) &&
-        (s->regs[TX_BD_NUM] < 0x80) &&
-        (rx_desc(s)->len_flags & RXD_E);
-}
-
-static ssize_t open_eth_receive(NetClientState *nc,
-        const uint8_t *buf, size_t size)
-{
-    OpenEthState *s = qemu_get_nic_opaque(nc);
-    size_t maxfl = GET_REGFIELD(s, PACKETLEN, MAXFL);
-    size_t minfl = GET_REGFIELD(s, PACKETLEN, MINFL);
-    size_t fcsl = 4;
-    bool miss = true;
-
-    trace_open_eth_receive((unsigned)size);
-
-    if (size >= 6) {
-        static const uint8_t bcast_addr[] = {
-            0xff, 0xff, 0xff, 0xff, 0xff, 0xff
-        };
-        if (memcmp(buf, bcast_addr, sizeof(bcast_addr)) == 0) {
-            miss = GET_REGBIT(s, MODER, BRO);
-        } else if ((buf[0] & 0x1) || GET_REGBIT(s, MODER, IAM)) {
-            unsigned mcast_idx = compute_mcast_idx(buf);
-            miss = !(s->regs[HASH0 + mcast_idx / 32] &
-                    (1 << (mcast_idx % 32)));
-            trace_open_eth_receive_mcast(
-                    mcast_idx, s->regs[HASH0], s->regs[HASH1]);
-        } else {
-            miss = GET_REGFIELD(s, MAC_ADDR1, BYTE0) != buf[0] ||
-                GET_REGFIELD(s, MAC_ADDR1, BYTE1) != buf[1] ||
-                GET_REGFIELD(s, MAC_ADDR0, BYTE2) != buf[2] ||
-                GET_REGFIELD(s, MAC_ADDR0, BYTE3) != buf[3] ||
-                GET_REGFIELD(s, MAC_ADDR0, BYTE4) != buf[4] ||
-                GET_REGFIELD(s, MAC_ADDR0, BYTE5) != buf[5];
-        }
-    }
-
-    if (miss && !GET_REGBIT(s, MODER, PRO)) {
-        trace_open_eth_receive_reject();
-        return size;
-    }
-
-#ifdef USE_RECSMALL
-    if (GET_REGBIT(s, MODER, RECSMALL) || size >= minfl) {
-#else
-    {
-#endif
-        static const uint8_t zero[64] = {0};
-        desc *desc = rx_desc(s);
-        size_t copy_size = GET_REGBIT(s, MODER, HUGEN) ? 65536 : maxfl;
-
-        desc->len_flags &= ~(RXD_CF | RXD_M | RXD_OR |
-                RXD_IS | RXD_DN | RXD_TL | RXD_SF | RXD_CRC | RXD_LC);
-
-        if (copy_size > size) {
-            copy_size = size;
-        } else {
-            fcsl = 0;
-        }
-        if (miss) {
-            desc->len_flags |= RXD_M;
-        }
-        if (GET_REGBIT(s, MODER, HUGEN) && size > maxfl) {
-            desc->len_flags |= RXD_TL;
-        }
-#ifdef USE_RECSMALL
-        if (size < minfl) {
-            desc->len_flags |= RXD_SF;
-        }
-#endif
-
-        cpu_physical_memory_write(desc->buf_ptr, buf, copy_size);
-
-        if (GET_REGBIT(s, MODER, PAD) && copy_size < minfl) {
-            if (minfl - copy_size > fcsl) {
-                fcsl = 0;
-            } else {
-                fcsl -= minfl - copy_size;
-            }
-            while (copy_size < minfl) {
-                size_t zero_sz = minfl - copy_size < sizeof(zero) ?
-                    minfl - copy_size : sizeof(zero);
-
-                cpu_physical_memory_write(desc->buf_ptr + copy_size,
-                        zero, zero_sz);
-                copy_size += zero_sz;
-            }
-        }
-
-        /* There's no FCS in the frames handed to us by the QEMU, zero fill it.
-         * Don't do it if the frame is cut at the MAXFL or padded with 4 or
-         * more bytes to the MINFL.
-         */
-        cpu_physical_memory_write(desc->buf_ptr + copy_size, zero, fcsl);
-        copy_size += fcsl;
-
-        SET_FIELD(desc->len_flags, RXD_LEN, copy_size);
-
-        if ((desc->len_flags & RXD_WRAP) || s->rx_desc == 0x7f) {
-            s->rx_desc = s->regs[TX_BD_NUM];
-        } else {
-            ++s->rx_desc;
-        }
-        desc->len_flags &= ~RXD_E;
-
-        trace_open_eth_receive_desc(desc->buf_ptr, desc->len_flags);
-
-        if (desc->len_flags & RXD_IRQ) {
-            open_eth_int_source_write(s,
-                    s->regs[INT_SOURCE] | INT_SOURCE_RXB);
-        }
-    }
-    return size;
-}
-
-static void open_eth_cleanup(NetClientState *nc)
-{
-}
-
-static NetClientInfo net_open_eth_info = {
-    .type = NET_CLIENT_OPTIONS_KIND_NIC,
-    .size = sizeof(NICState),
-    .can_receive = open_eth_can_receive,
-    .receive = open_eth_receive,
-    .cleanup = open_eth_cleanup,
-    .link_status_changed = open_eth_set_link_status,
-};
-
-static void open_eth_start_xmit(OpenEthState *s, desc *tx)
-{
-    uint8_t buf[65536];
-    unsigned len = GET_FIELD(tx->len_flags, TXD_LEN);
-    unsigned tx_len = len;
-
-    if ((tx->len_flags & TXD_PAD) &&
-            tx_len < GET_REGFIELD(s, PACKETLEN, MINFL)) {
-        tx_len = GET_REGFIELD(s, PACKETLEN, MINFL);
-    }
-    if (!GET_REGBIT(s, MODER, HUGEN) &&
-            tx_len > GET_REGFIELD(s, PACKETLEN, MAXFL)) {
-        tx_len = GET_REGFIELD(s, PACKETLEN, MAXFL);
-    }
-
-    trace_open_eth_start_xmit(tx->buf_ptr, len, tx_len);
-
-    if (len > tx_len) {
-        len = tx_len;
-    }
-    cpu_physical_memory_read(tx->buf_ptr, buf, len);
-    if (tx_len > len) {
-        memset(buf + len, 0, tx_len - len);
-    }
-    qemu_send_packet(qemu_get_queue(s->nic), buf, tx_len);
-
-    if (tx->len_flags & TXD_WR) {
-        s->tx_desc = 0;
-    } else {
-        ++s->tx_desc;
-        if (s->tx_desc >= s->regs[TX_BD_NUM]) {
-            s->tx_desc = 0;
-        }
-    }
-    tx->len_flags &= ~(TXD_RD | TXD_UR |
-            TXD_RTRY | TXD_RL | TXD_LC | TXD_DF | TXD_CS);
-    if (tx->len_flags & TXD_IRQ) {
-        open_eth_int_source_write(s, s->regs[INT_SOURCE] | INT_SOURCE_TXB);
-    }
-
-}
-
-static void open_eth_check_start_xmit(OpenEthState *s)
-{
-    desc *tx = tx_desc(s);
-    if (GET_REGBIT(s, MODER, TXEN) && s->regs[TX_BD_NUM] > 0 &&
-            (tx->len_flags & TXD_RD) &&
-            GET_FIELD(tx->len_flags, TXD_LEN) > 4) {
-        open_eth_start_xmit(s, tx);
-    }
-}
-
-static uint64_t open_eth_reg_read(void *opaque,
-        hwaddr addr, unsigned int size)
-{
-    static uint32_t (*reg_read[REG_MAX])(OpenEthState *s) = {
-    };
-    OpenEthState *s = opaque;
-    unsigned idx = addr / 4;
-    uint64_t v = 0;
-
-    if (idx < REG_MAX) {
-        if (reg_read[idx]) {
-            v = reg_read[idx](s);
-        } else {
-            v = s->regs[idx];
-        }
-    }
-    trace_open_eth_reg_read((uint32_t)addr, (uint32_t)v);
-    return v;
-}
-
-static void open_eth_ro(OpenEthState *s, uint32_t val)
-{
-}
-
-static void open_eth_moder_host_write(OpenEthState *s, uint32_t val)
-{
-    uint32_t set = val & ~s->regs[MODER];
-
-    if (set & MODER_RST) {
-        open_eth_reset(s);
-    }
-
-    s->regs[MODER] = val;
-
-    if (set & MODER_RXEN) {
-        s->rx_desc = s->regs[TX_BD_NUM];
-    }
-    if (set & MODER_TXEN) {
-        s->tx_desc = 0;
-        open_eth_check_start_xmit(s);
-    }
-}
-
-static void open_eth_int_source_host_write(OpenEthState *s, uint32_t val)
-{
-    uint32_t old = s->regs[INT_SOURCE];
-
-    s->regs[INT_SOURCE] &= ~val;
-    open_eth_update_irq(s, old & s->regs[INT_MASK],
-            s->regs[INT_SOURCE] & s->regs[INT_MASK]);
-}
-
-static void open_eth_int_mask_host_write(OpenEthState *s, uint32_t val)
-{
-    uint32_t old = s->regs[INT_MASK];
-
-    s->regs[INT_MASK] = val;
-    open_eth_update_irq(s, s->regs[INT_SOURCE] & old,
-            s->regs[INT_SOURCE] & s->regs[INT_MASK]);
-}
-
-static void open_eth_mii_command_host_write(OpenEthState *s, uint32_t val)
-{
-    unsigned fiad = GET_REGFIELD(s, MIIADDRESS, FIAD);
-    unsigned rgad = GET_REGFIELD(s, MIIADDRESS, RGAD);
-
-    if (val & MIICOMMAND_WCTRLDATA) {
-        if (fiad == DEFAULT_PHY) {
-            mii_write_host(&s->mii, rgad,
-                    GET_REGFIELD(s, MIITX_DATA, CTRLDATA));
-        }
-    }
-    if (val & MIICOMMAND_RSTAT) {
-        if (fiad == DEFAULT_PHY) {
-            SET_REGFIELD(s, MIIRX_DATA, PRSD,
-                    mii_read_host(&s->mii, rgad));
-        } else {
-            s->regs[MIIRX_DATA] = 0xffff;
-        }
-        SET_REGFIELD(s, MIISTATUS, LINKFAIL, qemu_get_queue(s->nic)->link_down);
-    }
-}
-
-static void open_eth_mii_tx_host_write(OpenEthState *s, uint32_t val)
-{
-    SET_REGFIELD(s, MIITX_DATA, CTRLDATA, val);
-    if (GET_REGFIELD(s, MIIADDRESS, FIAD) == DEFAULT_PHY) {
-        mii_write_host(&s->mii, GET_REGFIELD(s, MIIADDRESS, RGAD),
-                GET_REGFIELD(s, MIITX_DATA, CTRLDATA));
-    }
-}
-
-static void open_eth_reg_write(void *opaque,
-        hwaddr addr, uint64_t val, unsigned int size)
-{
-    static void (*reg_write[REG_MAX])(OpenEthState *s, uint32_t val) = {
-        [MODER] = open_eth_moder_host_write,
-        [INT_SOURCE] = open_eth_int_source_host_write,
-        [INT_MASK] = open_eth_int_mask_host_write,
-        [MIICOMMAND] = open_eth_mii_command_host_write,
-        [MIITX_DATA] = open_eth_mii_tx_host_write,
-        [MIISTATUS] = open_eth_ro,
-    };
-    OpenEthState *s = opaque;
-    unsigned idx = addr / 4;
-
-    if (idx < REG_MAX) {
-        trace_open_eth_reg_write((uint32_t)addr, (uint32_t)val);
-        if (reg_write[idx]) {
-            reg_write[idx](s, val);
-        } else {
-            s->regs[idx] = val;
-        }
-    }
-}
-
-static uint64_t open_eth_desc_read(void *opaque,
-        hwaddr addr, unsigned int size)
-{
-    OpenEthState *s = opaque;
-    uint64_t v = 0;
-
-    addr &= 0x3ff;
-    memcpy(&v, (uint8_t *)s->desc + addr, size);
-    trace_open_eth_desc_read((uint32_t)addr, (uint32_t)v);
-    return v;
-}
-
-static void open_eth_desc_write(void *opaque,
-        hwaddr addr, uint64_t val, unsigned int size)
-{
-    OpenEthState *s = opaque;
-
-    addr &= 0x3ff;
-    trace_open_eth_desc_write((uint32_t)addr, (uint32_t)val);
-    memcpy((uint8_t *)s->desc + addr, &val, size);
-    open_eth_check_start_xmit(s);
-}
-
-
-static const MemoryRegionOps open_eth_reg_ops = {
-    .read = open_eth_reg_read,
-    .write = open_eth_reg_write,
-};
-
-static const MemoryRegionOps open_eth_desc_ops = {
-    .read = open_eth_desc_read,
-    .write = open_eth_desc_write,
-};
-
-static int sysbus_open_eth_init(SysBusDevice *dev)
-{
-    OpenEthState *s = DO_UPCAST(OpenEthState, dev, dev);
-
-    memory_region_init_io(&s->reg_io, &open_eth_reg_ops, s,
-            "open_eth.regs", 0x54);
-    sysbus_init_mmio(dev, &s->reg_io);
-
-    memory_region_init_io(&s->desc_io, &open_eth_desc_ops, s,
-            "open_eth.desc", 0x400);
-    sysbus_init_mmio(dev, &s->desc_io);
-
-    sysbus_init_irq(dev, &s->irq);
-
-    s->nic = qemu_new_nic(&net_open_eth_info, &s->conf,
-                          object_get_typename(OBJECT(s)), s->dev.qdev.id, s);
-    return 0;
-}
-
-static void qdev_open_eth_reset(DeviceState *dev)
-{
-    OpenEthState *d = DO_UPCAST(OpenEthState, dev.qdev, dev);
-    open_eth_reset(d);
-}
-
-static Property open_eth_properties[] = {
-    DEFINE_NIC_PROPERTIES(OpenEthState, conf),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void open_eth_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = sysbus_open_eth_init;
-    dc->desc = "Opencores 10/100 Mbit Ethernet";
-    dc->reset = qdev_open_eth_reset;
-    dc->props = open_eth_properties;
-}
-
-static const 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_types(void)
-{
-    type_register_static(&open_eth_info);
-}
-
-type_init(open_eth_register_types)
diff --git a/hw/openpic.c b/hw/openpic.c
deleted file mode 100644 (file)
index 03a7075..0000000
+++ /dev/null
@@ -1,1661 +0,0 @@
-/*
- * OpenPIC emulation
- *
- * Copyright (c) 2004 Jocelyn Mayer
- *               2011 Alexander Graf
- *
- * 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.
- */
-/*
- *
- * Based on OpenPic implementations:
- * - Intel GW80314 I/O companion chip developer's manual
- * - Motorola MPC8245 & MPC8540 user manuals.
- * - Motorola MCP750 (aka Raven) programmer manual.
- * - Motorola Harrier programmer manuel
- *
- * Serial interrupts, as implemented in Raven chipset are not supported yet.
- *
- */
-#include "hw/hw.h"
-#include "hw/ppc/mac.h"
-#include "hw/pci/pci.h"
-#include "hw/openpic.h"
-#include "hw/sysbus.h"
-#include "hw/pci/msi.h"
-#include "qemu/bitops.h"
-#include "hw/ppc.h"
-
-//#define DEBUG_OPENPIC
-
-#ifdef DEBUG_OPENPIC
-static const int debug_openpic = 1;
-#else
-static const int debug_openpic = 0;
-#endif
-
-#define DPRINTF(fmt, ...) do { \
-        if (debug_openpic) { \
-            printf(fmt , ## __VA_ARGS__); \
-        } \
-    } while (0)
-
-#define MAX_CPU     32
-#define MAX_SRC     256
-#define MAX_TMR     4
-#define MAX_IPI     4
-#define MAX_MSI     8
-#define MAX_IRQ     (MAX_SRC + MAX_IPI + MAX_TMR)
-#define VID         0x03 /* MPIC version ID */
-
-/* OpenPIC capability flags */
-#define OPENPIC_FLAG_IDR_CRIT     (1 << 0)
-#define OPENPIC_FLAG_ILR          (2 << 0)
-
-/* OpenPIC address map */
-#define OPENPIC_GLB_REG_START        0x0
-#define OPENPIC_GLB_REG_SIZE         0x10F0
-#define OPENPIC_TMR_REG_START        0x10F0
-#define OPENPIC_TMR_REG_SIZE         0x220
-#define OPENPIC_MSI_REG_START        0x1600
-#define OPENPIC_MSI_REG_SIZE         0x200
-#define OPENPIC_SUMMARY_REG_START   0x3800
-#define OPENPIC_SUMMARY_REG_SIZE    0x800
-#define OPENPIC_SRC_REG_START        0x10000
-#define OPENPIC_SRC_REG_SIZE         (MAX_SRC * 0x20)
-#define OPENPIC_CPU_REG_START        0x20000
-#define OPENPIC_CPU_REG_SIZE         0x100 + ((MAX_CPU - 1) * 0x1000)
-
-/* Raven */
-#define RAVEN_MAX_CPU      2
-#define RAVEN_MAX_EXT     48
-#define RAVEN_MAX_IRQ     64
-#define RAVEN_MAX_TMR      MAX_TMR
-#define RAVEN_MAX_IPI      MAX_IPI
-
-/* Interrupt definitions */
-#define RAVEN_FE_IRQ     (RAVEN_MAX_EXT)     /* Internal functional IRQ */
-#define RAVEN_ERR_IRQ    (RAVEN_MAX_EXT + 1) /* Error IRQ */
-#define RAVEN_TMR_IRQ    (RAVEN_MAX_EXT + 2) /* First timer IRQ */
-#define RAVEN_IPI_IRQ    (RAVEN_TMR_IRQ + RAVEN_MAX_TMR) /* First IPI IRQ */
-/* First doorbell IRQ */
-#define RAVEN_DBL_IRQ    (RAVEN_IPI_IRQ + (RAVEN_MAX_CPU * RAVEN_MAX_IPI))
-
-typedef struct FslMpicInfo {
-    int max_ext;
-} FslMpicInfo;
-
-static FslMpicInfo fsl_mpic_20 = {
-    .max_ext = 12,
-};
-
-static FslMpicInfo fsl_mpic_42 = {
-    .max_ext = 12,
-};
-
-#define FRR_NIRQ_SHIFT    16
-#define FRR_NCPU_SHIFT     8
-#define FRR_VID_SHIFT      0
-
-#define VID_REVISION_1_2   2
-#define VID_REVISION_1_3   3
-
-#define VIR_GENERIC      0x00000000 /* Generic Vendor ID */
-
-#define GCR_RESET        0x80000000
-#define GCR_MODE_PASS    0x00000000
-#define GCR_MODE_MIXED   0x20000000
-#define GCR_MODE_PROXY   0x60000000
-
-#define TBCR_CI           0x80000000 /* count inhibit */
-#define TCCR_TOG          0x80000000 /* toggles when decrement to zero */
-
-#define IDR_EP_SHIFT      31
-#define IDR_EP_MASK       (1 << IDR_EP_SHIFT)
-#define IDR_CI0_SHIFT     30
-#define IDR_CI1_SHIFT     29
-#define IDR_P1_SHIFT      1
-#define IDR_P0_SHIFT      0
-
-#define ILR_INTTGT_MASK   0x000000ff
-#define ILR_INTTGT_INT    0x00
-#define ILR_INTTGT_CINT   0x01 /* critical */
-#define ILR_INTTGT_MCP    0x02 /* machine check */
-
-/* The currently supported INTTGT values happen to be the same as QEMU's
- * openpic output codes, but don't depend on this.  The output codes
- * could change (unlikely, but...) or support could be added for
- * more INTTGT values.
- */
-static const int inttgt_output[][2] = {
-    { ILR_INTTGT_INT, OPENPIC_OUTPUT_INT },
-    { ILR_INTTGT_CINT, OPENPIC_OUTPUT_CINT },
-    { ILR_INTTGT_MCP, OPENPIC_OUTPUT_MCK },
-};
-
-static int inttgt_to_output(int inttgt)
-{
-    int i;
-
-    for (i = 0; i < ARRAY_SIZE(inttgt_output); i++) {
-        if (inttgt_output[i][0] == inttgt) {
-            return inttgt_output[i][1];
-        }
-    }
-
-    fprintf(stderr, "%s: unsupported inttgt %d\n", __func__, inttgt);
-    return OPENPIC_OUTPUT_INT;
-}
-
-static int output_to_inttgt(int output)
-{
-    int i;
-
-    for (i = 0; i < ARRAY_SIZE(inttgt_output); i++) {
-        if (inttgt_output[i][1] == output) {
-            return inttgt_output[i][0];
-        }
-    }
-
-    abort();
-}
-
-#define MSIIR_OFFSET       0x140
-#define MSIIR_SRS_SHIFT    29
-#define MSIIR_SRS_MASK     (0x7 << MSIIR_SRS_SHIFT)
-#define MSIIR_IBS_SHIFT    24
-#define MSIIR_IBS_MASK     (0x1f << MSIIR_IBS_SHIFT)
-
-static int get_current_cpu(void)
-{
-    CPUState *cpu_single_cpu;
-
-    if (!cpu_single_env) {
-        return -1;
-    }
-
-    cpu_single_cpu = ENV_GET_CPU(cpu_single_env);
-    return cpu_single_cpu->cpu_index;
-}
-
-static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr,
-                                          int idx);
-static void openpic_cpu_write_internal(void *opaque, hwaddr addr,
-                                       uint32_t val, int idx);
-
-typedef enum IRQType {
-    IRQ_TYPE_NORMAL = 0,
-    IRQ_TYPE_FSLINT,        /* FSL internal interrupt -- level only */
-    IRQ_TYPE_FSLSPECIAL,    /* FSL timer/IPI interrupt, edge, no polarity */
-} IRQType;
-
-typedef struct IRQQueue {
-    /* Round up to the nearest 64 IRQs so that the queue length
-     * won't change when moving between 32 and 64 bit hosts.
-     */
-    unsigned long queue[BITS_TO_LONGS((MAX_IRQ + 63) & ~63)];
-    int next;
-    int priority;
-} IRQQueue;
-
-typedef struct IRQSource {
-    uint32_t ivpr;  /* IRQ vector/priority register */
-    uint32_t idr;   /* IRQ destination register */
-    uint32_t destmask; /* bitmap of CPU destinations */
-    int last_cpu;
-    int output;     /* IRQ level, e.g. OPENPIC_OUTPUT_INT */
-    int pending;    /* TRUE if IRQ is pending */
-    IRQType type;
-    bool level:1;   /* level-triggered */
-    bool nomask:1;  /* critical interrupts ignore mask on some FSL MPICs */
-} IRQSource;
-
-#define IVPR_MASK_SHIFT       31
-#define IVPR_MASK_MASK        (1 << IVPR_MASK_SHIFT)
-#define IVPR_ACTIVITY_SHIFT   30
-#define IVPR_ACTIVITY_MASK    (1 << IVPR_ACTIVITY_SHIFT)
-#define IVPR_MODE_SHIFT       29
-#define IVPR_MODE_MASK        (1 << IVPR_MODE_SHIFT)
-#define IVPR_POLARITY_SHIFT   23
-#define IVPR_POLARITY_MASK    (1 << IVPR_POLARITY_SHIFT)
-#define IVPR_SENSE_SHIFT      22
-#define IVPR_SENSE_MASK       (1 << IVPR_SENSE_SHIFT)
-
-#define IVPR_PRIORITY_MASK     (0xF << 16)
-#define IVPR_PRIORITY(_ivprr_) ((int)(((_ivprr_) & IVPR_PRIORITY_MASK) >> 16))
-#define IVPR_VECTOR(opp, _ivprr_) ((_ivprr_) & (opp)->vector_mask)
-
-/* IDR[EP/CI] are only for FSL MPIC prior to v4.0 */
-#define IDR_EP      0x80000000  /* external pin */
-#define IDR_CI      0x40000000  /* critical interrupt */
-
-typedef struct IRQDest {
-    int32_t ctpr; /* CPU current task priority */
-    IRQQueue raised;
-    IRQQueue servicing;
-    qemu_irq *irqs;
-
-    /* Count of IRQ sources asserting on non-INT outputs */
-    uint32_t outputs_active[OPENPIC_OUTPUT_NB];
-} IRQDest;
-
-typedef struct OpenPICState {
-    SysBusDevice busdev;
-    MemoryRegion mem;
-
-    /* Behavior control */
-    FslMpicInfo *fsl;
-    uint32_t model;
-    uint32_t flags;
-    uint32_t nb_irqs;
-    uint32_t vid;
-    uint32_t vir; /* Vendor identification register */
-    uint32_t vector_mask;
-    uint32_t tfrr_reset;
-    uint32_t ivpr_reset;
-    uint32_t idr_reset;
-    uint32_t brr1;
-    uint32_t mpic_mode_mask;
-
-    /* Sub-regions */
-    MemoryRegion sub_io_mem[6];
-
-    /* Global registers */
-    uint32_t frr; /* Feature reporting register */
-    uint32_t gcr; /* Global configuration register  */
-    uint32_t pir; /* Processor initialization register */
-    uint32_t spve; /* Spurious vector register */
-    uint32_t tfrr; /* Timer frequency reporting register */
-    /* Source registers */
-    IRQSource src[MAX_IRQ];
-    /* Local registers per output pin */
-    IRQDest dst[MAX_CPU];
-    uint32_t nb_cpus;
-    /* Timer registers */
-    struct {
-        uint32_t tccr;  /* Global timer current count register */
-        uint32_t tbcr;  /* Global timer base count register */
-    } timers[MAX_TMR];
-    /* Shared MSI registers */
-    struct {
-        uint32_t msir;   /* Shared Message Signaled Interrupt Register */
-    } msi[MAX_MSI];
-    uint32_t max_irq;
-    uint32_t irq_ipi0;
-    uint32_t irq_tim0;
-    uint32_t irq_msi;
-} OpenPICState;
-
-static inline void IRQ_setbit(IRQQueue *q, int n_IRQ)
-{
-    set_bit(n_IRQ, q->queue);
-}
-
-static inline void IRQ_resetbit(IRQQueue *q, int n_IRQ)
-{
-    clear_bit(n_IRQ, q->queue);
-}
-
-static inline int IRQ_testbit(IRQQueue *q, int n_IRQ)
-{
-    return test_bit(n_IRQ, q->queue);
-}
-
-static void IRQ_check(OpenPICState *opp, IRQQueue *q)
-{
-    int irq = -1;
-    int next = -1;
-    int priority = -1;
-
-    for (;;) {
-        irq = find_next_bit(q->queue, opp->max_irq, irq + 1);
-        if (irq == opp->max_irq) {
-            break;
-        }
-
-        DPRINTF("IRQ_check: irq %d set ivpr_pr=%d pr=%d\n",
-                irq, IVPR_PRIORITY(opp->src[irq].ivpr), priority);
-
-        if (IVPR_PRIORITY(opp->src[irq].ivpr) > priority) {
-            next = irq;
-            priority = IVPR_PRIORITY(opp->src[irq].ivpr);
-        }
-    }
-
-    q->next = next;
-    q->priority = priority;
-}
-
-static int IRQ_get_next(OpenPICState *opp, IRQQueue *q)
-{
-    /* XXX: optimize */
-    IRQ_check(opp, q);
-
-    return q->next;
-}
-
-static void IRQ_local_pipe(OpenPICState *opp, int n_CPU, int n_IRQ,
-                           bool active, bool was_active)
-{
-    IRQDest *dst;
-    IRQSource *src;
-    int priority;
-
-    dst = &opp->dst[n_CPU];
-    src = &opp->src[n_IRQ];
-
-    DPRINTF("%s: IRQ %d active %d was %d\n",
-            __func__, n_IRQ, active, was_active);
-
-    if (src->output != OPENPIC_OUTPUT_INT) {
-        DPRINTF("%s: output %d irq %d active %d was %d count %d\n",
-                __func__, src->output, n_IRQ, active, was_active,
-                dst->outputs_active[src->output]);
-
-        /* On Freescale MPIC, critical interrupts ignore priority,
-         * IACK, EOI, etc.  Before MPIC v4.1 they also ignore
-         * masking.
-         */
-        if (active) {
-            if (!was_active && dst->outputs_active[src->output]++ == 0) {
-                DPRINTF("%s: Raise OpenPIC output %d cpu %d irq %d\n",
-                        __func__, src->output, n_CPU, n_IRQ);
-                qemu_irq_raise(dst->irqs[src->output]);
-            }
-        } else {
-            if (was_active && --dst->outputs_active[src->output] == 0) {
-                DPRINTF("%s: Lower OpenPIC output %d cpu %d irq %d\n",
-                        __func__, src->output, n_CPU, n_IRQ);
-                qemu_irq_lower(dst->irqs[src->output]);
-            }
-        }
-
-        return;
-    }
-
-    priority = IVPR_PRIORITY(src->ivpr);
-
-    /* Even if the interrupt doesn't have enough priority,
-     * it is still raised, in case ctpr is lowered later.
-     */
-    if (active) {
-        IRQ_setbit(&dst->raised, n_IRQ);
-    } else {
-        IRQ_resetbit(&dst->raised, n_IRQ);
-    }
-
-    IRQ_check(opp, &dst->raised);
-
-    if (active && priority <= dst->ctpr) {
-        DPRINTF("%s: IRQ %d priority %d too low for ctpr %d on CPU %d\n",
-                __func__, n_IRQ, priority, dst->ctpr, n_CPU);
-        active = 0;
-    }
-
-    if (active) {
-        if (IRQ_get_next(opp, &dst->servicing) >= 0 &&
-                priority <= dst->servicing.priority) {
-            DPRINTF("%s: IRQ %d is hidden by servicing IRQ %d on CPU %d\n",
-                    __func__, n_IRQ, dst->servicing.next, n_CPU);
-        } else {
-            DPRINTF("%s: Raise OpenPIC INT output cpu %d irq %d/%d\n",
-                    __func__, n_CPU, n_IRQ, dst->raised.next);
-            qemu_irq_raise(opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT]);
-        }
-    } else {
-        IRQ_get_next(opp, &dst->servicing);
-        if (dst->raised.priority > dst->ctpr &&
-                dst->raised.priority > dst->servicing.priority) {
-            DPRINTF("%s: IRQ %d inactive, IRQ %d prio %d above %d/%d, CPU %d\n",
-                    __func__, n_IRQ, dst->raised.next, dst->raised.priority,
-                    dst->ctpr, dst->servicing.priority, n_CPU);
-            /* IRQ line stays asserted */
-        } else {
-            DPRINTF("%s: IRQ %d inactive, current prio %d/%d, CPU %d\n",
-                    __func__, n_IRQ, dst->ctpr, dst->servicing.priority, n_CPU);
-            qemu_irq_lower(opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT]);
-        }
-    }
-}
-
-/* update pic state because registers for n_IRQ have changed value */
-static void openpic_update_irq(OpenPICState *opp, int n_IRQ)
-{
-    IRQSource *src;
-    bool active, was_active;
-    int i;
-
-    src = &opp->src[n_IRQ];
-    active = src->pending;
-
-    if ((src->ivpr & IVPR_MASK_MASK) && !src->nomask) {
-        /* Interrupt source is disabled */
-        DPRINTF("%s: IRQ %d is disabled\n", __func__, n_IRQ);
-        active = false;
-    }
-
-    was_active = !!(src->ivpr & IVPR_ACTIVITY_MASK);
-
-    /*
-     * We don't have a similar check for already-active because
-     * ctpr may have changed and we need to withdraw the interrupt.
-     */
-    if (!active && !was_active) {
-        DPRINTF("%s: IRQ %d is already inactive\n", __func__, n_IRQ);
-        return;
-    }
-
-    if (active) {
-        src->ivpr |= IVPR_ACTIVITY_MASK;
-    } else {
-        src->ivpr &= ~IVPR_ACTIVITY_MASK;
-    }
-
-    if (src->destmask == 0) {
-        /* No target */
-        DPRINTF("%s: IRQ %d has no target\n", __func__, n_IRQ);
-        return;
-    }
-
-    if (src->destmask == (1 << src->last_cpu)) {
-        /* Only one CPU is allowed to receive this IRQ */
-        IRQ_local_pipe(opp, src->last_cpu, n_IRQ, active, was_active);
-    } else if (!(src->ivpr & IVPR_MODE_MASK)) {
-        /* Directed delivery mode */
-        for (i = 0; i < opp->nb_cpus; i++) {
-            if (src->destmask & (1 << i)) {
-                IRQ_local_pipe(opp, i, n_IRQ, active, was_active);
-            }
-        }
-    } else {
-        /* Distributed delivery mode */
-        for (i = src->last_cpu + 1; i != src->last_cpu; i++) {
-            if (i == opp->nb_cpus) {
-                i = 0;
-            }
-            if (src->destmask & (1 << i)) {
-                IRQ_local_pipe(opp, i, n_IRQ, active, was_active);
-                src->last_cpu = i;
-                break;
-            }
-        }
-    }
-}
-
-static void openpic_set_irq(void *opaque, int n_IRQ, int level)
-{
-    OpenPICState *opp = opaque;
-    IRQSource *src;
-
-    if (n_IRQ >= MAX_IRQ) {
-        fprintf(stderr, "%s: IRQ %d out of range\n", __func__, n_IRQ);
-        abort();
-    }
-
-    src = &opp->src[n_IRQ];
-    DPRINTF("openpic: set irq %d = %d ivpr=0x%08x\n",
-            n_IRQ, level, src->ivpr);
-    if (src->level) {
-        /* level-sensitive irq */
-        src->pending = level;
-        openpic_update_irq(opp, n_IRQ);
-    } else {
-        /* edge-sensitive irq */
-        if (level) {
-            src->pending = 1;
-            openpic_update_irq(opp, n_IRQ);
-        }
-
-        if (src->output != OPENPIC_OUTPUT_INT) {
-            /* Edge-triggered interrupts shouldn't be used
-             * with non-INT delivery, but just in case,
-             * try to make it do something sane rather than
-             * cause an interrupt storm.  This is close to
-             * what you'd probably see happen in real hardware.
-             */
-            src->pending = 0;
-            openpic_update_irq(opp, n_IRQ);
-        }
-    }
-}
-
-static void openpic_reset(DeviceState *d)
-{
-    OpenPICState *opp = FROM_SYSBUS(typeof(*opp), SYS_BUS_DEVICE(d));
-    int i;
-
-    opp->gcr = GCR_RESET;
-    /* Initialise controller registers */
-    opp->frr = ((opp->nb_irqs - 1) << FRR_NIRQ_SHIFT) |
-               ((opp->nb_cpus - 1) << FRR_NCPU_SHIFT) |
-               (opp->vid << FRR_VID_SHIFT);
-
-    opp->pir = 0;
-    opp->spve = -1 & opp->vector_mask;
-    opp->tfrr = opp->tfrr_reset;
-    /* Initialise IRQ sources */
-    for (i = 0; i < opp->max_irq; i++) {
-        opp->src[i].ivpr = opp->ivpr_reset;
-        opp->src[i].idr  = opp->idr_reset;
-
-        switch (opp->src[i].type) {
-        case IRQ_TYPE_NORMAL:
-            opp->src[i].level = !!(opp->ivpr_reset & IVPR_SENSE_MASK);
-            break;
-
-        case IRQ_TYPE_FSLINT:
-            opp->src[i].ivpr |= IVPR_POLARITY_MASK;
-            break;
-
-        case IRQ_TYPE_FSLSPECIAL:
-            break;
-        }
-    }
-    /* Initialise IRQ destinations */
-    for (i = 0; i < MAX_CPU; i++) {
-        opp->dst[i].ctpr      = 15;
-        memset(&opp->dst[i].raised, 0, sizeof(IRQQueue));
-        opp->dst[i].raised.next = -1;
-        memset(&opp->dst[i].servicing, 0, sizeof(IRQQueue));
-        opp->dst[i].servicing.next = -1;
-    }
-    /* Initialise timers */
-    for (i = 0; i < MAX_TMR; i++) {
-        opp->timers[i].tccr = 0;
-        opp->timers[i].tbcr = TBCR_CI;
-    }
-    /* Go out of RESET state */
-    opp->gcr = 0;
-}
-
-static inline uint32_t read_IRQreg_idr(OpenPICState *opp, int n_IRQ)
-{
-    return opp->src[n_IRQ].idr;
-}
-
-static inline uint32_t read_IRQreg_ilr(OpenPICState *opp, int n_IRQ)
-{
-    if (opp->flags & OPENPIC_FLAG_ILR) {
-        return output_to_inttgt(opp->src[n_IRQ].output);
-    }
-
-    return 0xffffffff;
-}
-
-static inline uint32_t read_IRQreg_ivpr(OpenPICState *opp, int n_IRQ)
-{
-    return opp->src[n_IRQ].ivpr;
-}
-
-static inline void write_IRQreg_idr(OpenPICState *opp, int n_IRQ, uint32_t val)
-{
-    IRQSource *src = &opp->src[n_IRQ];
-    uint32_t normal_mask = (1UL << opp->nb_cpus) - 1;
-    uint32_t crit_mask = 0;
-    uint32_t mask = normal_mask;
-    int crit_shift = IDR_EP_SHIFT - opp->nb_cpus;
-    int i;
-
-    if (opp->flags & OPENPIC_FLAG_IDR_CRIT) {
-        crit_mask = mask << crit_shift;
-        mask |= crit_mask | IDR_EP;
-    }
-
-    src->idr = val & mask;
-    DPRINTF("Set IDR %d to 0x%08x\n", n_IRQ, src->idr);
-
-    if (opp->flags & OPENPIC_FLAG_IDR_CRIT) {
-        if (src->idr & crit_mask) {
-            if (src->idr & normal_mask) {
-                DPRINTF("%s: IRQ configured for multiple output types, using "
-                        "critical\n", __func__);
-            }
-
-            src->output = OPENPIC_OUTPUT_CINT;
-            src->nomask = true;
-            src->destmask = 0;
-
-            for (i = 0; i < opp->nb_cpus; i++) {
-                int n_ci = IDR_CI0_SHIFT - i;
-
-                if (src->idr & (1UL << n_ci)) {
-                    src->destmask |= 1UL << i;
-                }
-            }
-        } else {
-            src->output = OPENPIC_OUTPUT_INT;
-            src->nomask = false;
-            src->destmask = src->idr & normal_mask;
-        }
-    } else {
-        src->destmask = src->idr;
-    }
-}
-
-static inline void write_IRQreg_ilr(OpenPICState *opp, int n_IRQ, uint32_t val)
-{
-    if (opp->flags & OPENPIC_FLAG_ILR) {
-        IRQSource *src = &opp->src[n_IRQ];
-
-        src->output = inttgt_to_output(val & ILR_INTTGT_MASK);
-        DPRINTF("Set ILR %d to 0x%08x, output %d\n", n_IRQ, src->idr,
-                src->output);
-
-        /* TODO: on MPIC v4.0 only, set nomask for non-INT */
-    }
-}
-
-static inline void write_IRQreg_ivpr(OpenPICState *opp, int n_IRQ, uint32_t val)
-{
-    uint32_t mask;
-
-    /* NOTE when implementing newer FSL MPIC models: starting with v4.0,
-     * the polarity bit is read-only on internal interrupts.
-     */
-    mask = IVPR_MASK_MASK | IVPR_PRIORITY_MASK | IVPR_SENSE_MASK |
-           IVPR_POLARITY_MASK | opp->vector_mask;
-
-    /* ACTIVITY bit is read-only */
-    opp->src[n_IRQ].ivpr =
-        (opp->src[n_IRQ].ivpr & IVPR_ACTIVITY_MASK) | (val & mask);
-
-    /* For FSL internal interrupts, The sense bit is reserved and zero,
-     * and the interrupt is always level-triggered.  Timers and IPIs
-     * have no sense or polarity bits, and are edge-triggered.
-     */
-    switch (opp->src[n_IRQ].type) {
-    case IRQ_TYPE_NORMAL:
-        opp->src[n_IRQ].level = !!(opp->src[n_IRQ].ivpr & IVPR_SENSE_MASK);
-        break;
-
-    case IRQ_TYPE_FSLINT:
-        opp->src[n_IRQ].ivpr &= ~IVPR_SENSE_MASK;
-        break;
-
-    case IRQ_TYPE_FSLSPECIAL:
-        opp->src[n_IRQ].ivpr &= ~(IVPR_POLARITY_MASK | IVPR_SENSE_MASK);
-        break;
-    }
-
-    openpic_update_irq(opp, n_IRQ);
-    DPRINTF("Set IVPR %d to 0x%08x -> 0x%08x\n", n_IRQ, val,
-            opp->src[n_IRQ].ivpr);
-}
-
-static void openpic_gcr_write(OpenPICState *opp, uint64_t val)
-{
-    bool mpic_proxy = false;
-
-    if (val & GCR_RESET) {
-        openpic_reset(&opp->busdev.qdev);
-        return;
-    }
-
-    opp->gcr &= ~opp->mpic_mode_mask;
-    opp->gcr |= val & opp->mpic_mode_mask;
-
-    /* Set external proxy mode */
-    if ((val & opp->mpic_mode_mask) == GCR_MODE_PROXY) {
-        mpic_proxy = true;
-    }
-
-    ppce500_set_mpic_proxy(mpic_proxy);
-}
-
-static void openpic_gbl_write(void *opaque, hwaddr addr, uint64_t val,
-                              unsigned len)
-{
-    OpenPICState *opp = opaque;
-    IRQDest *dst;
-    int idx;
-
-    DPRINTF("%s: addr %#" HWADDR_PRIx " <= %08" PRIx64 "\n",
-            __func__, addr, val);
-    if (addr & 0xF) {
-        return;
-    }
-    switch (addr) {
-    case 0x00: /* Block Revision Register1 (BRR1) is Readonly */
-        break;
-    case 0x40:
-    case 0x50:
-    case 0x60:
-    case 0x70:
-    case 0x80:
-    case 0x90:
-    case 0xA0:
-    case 0xB0:
-        openpic_cpu_write_internal(opp, addr, val, get_current_cpu());
-        break;
-    case 0x1000: /* FRR */
-        break;
-    case 0x1020: /* GCR */
-        openpic_gcr_write(opp, val);
-        break;
-    case 0x1080: /* VIR */
-        break;
-    case 0x1090: /* PIR */
-        for (idx = 0; idx < opp->nb_cpus; idx++) {
-            if ((val & (1 << idx)) && !(opp->pir & (1 << idx))) {
-                DPRINTF("Raise OpenPIC RESET output for CPU %d\n", idx);
-                dst = &opp->dst[idx];
-                qemu_irq_raise(dst->irqs[OPENPIC_OUTPUT_RESET]);
-            } else if (!(val & (1 << idx)) && (opp->pir & (1 << idx))) {
-                DPRINTF("Lower OpenPIC RESET output for CPU %d\n", idx);
-                dst = &opp->dst[idx];
-                qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_RESET]);
-            }
-        }
-        opp->pir = val;
-        break;
-    case 0x10A0: /* IPI_IVPR */
-    case 0x10B0:
-    case 0x10C0:
-    case 0x10D0:
-        {
-            int idx;
-            idx = (addr - 0x10A0) >> 4;
-            write_IRQreg_ivpr(opp, opp->irq_ipi0 + idx, val);
-        }
-        break;
-    case 0x10E0: /* SPVE */
-        opp->spve = val & opp->vector_mask;
-        break;
-    default:
-        break;
-    }
-}
-
-static uint64_t openpic_gbl_read(void *opaque, hwaddr addr, unsigned len)
-{
-    OpenPICState *opp = opaque;
-    uint32_t retval;
-
-    DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr);
-    retval = 0xFFFFFFFF;
-    if (addr & 0xF) {
-        return retval;
-    }
-    switch (addr) {
-    case 0x1000: /* FRR */
-        retval = opp->frr;
-        break;
-    case 0x1020: /* GCR */
-        retval = opp->gcr;
-        break;
-    case 0x1080: /* VIR */
-        retval = opp->vir;
-        break;
-    case 0x1090: /* PIR */
-        retval = 0x00000000;
-        break;
-    case 0x00: /* Block Revision Register1 (BRR1) */
-        retval = opp->brr1;
-        break;
-    case 0x40:
-    case 0x50:
-    case 0x60:
-    case 0x70:
-    case 0x80:
-    case 0x90:
-    case 0xA0:
-    case 0xB0:
-        retval = openpic_cpu_read_internal(opp, addr, get_current_cpu());
-        break;
-    case 0x10A0: /* IPI_IVPR */
-    case 0x10B0:
-    case 0x10C0:
-    case 0x10D0:
-        {
-            int idx;
-            idx = (addr - 0x10A0) >> 4;
-            retval = read_IRQreg_ivpr(opp, opp->irq_ipi0 + idx);
-        }
-        break;
-    case 0x10E0: /* SPVE */
-        retval = opp->spve;
-        break;
-    default:
-        break;
-    }
-    DPRINTF("%s: => 0x%08x\n", __func__, retval);
-
-    return retval;
-}
-
-static void openpic_tmr_write(void *opaque, hwaddr addr, uint64_t val,
-                                unsigned len)
-{
-    OpenPICState *opp = opaque;
-    int idx;
-
-    addr += 0x10f0;
-
-    DPRINTF("%s: addr %#" HWADDR_PRIx " <= %08" PRIx64 "\n",
-            __func__, addr, val);
-    if (addr & 0xF) {
-        return;
-    }
-
-    if (addr == 0x10f0) {
-        /* TFRR */
-        opp->tfrr = val;
-        return;
-    }
-
-    idx = (addr >> 6) & 0x3;
-    addr = addr & 0x30;
-
-    switch (addr & 0x30) {
-    case 0x00: /* TCCR */
-        break;
-    case 0x10: /* TBCR */
-        if ((opp->timers[idx].tccr & TCCR_TOG) != 0 &&
-            (val & TBCR_CI) == 0 &&
-            (opp->timers[idx].tbcr & TBCR_CI) != 0) {
-            opp->timers[idx].tccr &= ~TCCR_TOG;
-        }
-        opp->timers[idx].tbcr = val;
-        break;
-    case 0x20: /* TVPR */
-        write_IRQreg_ivpr(opp, opp->irq_tim0 + idx, val);
-        break;
-    case 0x30: /* TDR */
-        write_IRQreg_idr(opp, opp->irq_tim0 + idx, val);
-        break;
-    }
-}
-
-static uint64_t openpic_tmr_read(void *opaque, hwaddr addr, unsigned len)
-{
-    OpenPICState *opp = opaque;
-    uint32_t retval = -1;
-    int idx;
-
-    DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr);
-    if (addr & 0xF) {
-        goto out;
-    }
-    idx = (addr >> 6) & 0x3;
-    if (addr == 0x0) {
-        /* TFRR */
-        retval = opp->tfrr;
-        goto out;
-    }
-    switch (addr & 0x30) {
-    case 0x00: /* TCCR */
-        retval = opp->timers[idx].tccr;
-        break;
-    case 0x10: /* TBCR */
-        retval = opp->timers[idx].tbcr;
-        break;
-    case 0x20: /* TIPV */
-        retval = read_IRQreg_ivpr(opp, opp->irq_tim0 + idx);
-        break;
-    case 0x30: /* TIDE (TIDR) */
-        retval = read_IRQreg_idr(opp, opp->irq_tim0 + idx);
-        break;
-    }
-
-out:
-    DPRINTF("%s: => 0x%08x\n", __func__, retval);
-
-    return retval;
-}
-
-static void openpic_src_write(void *opaque, hwaddr addr, uint64_t val,
-                              unsigned len)
-{
-    OpenPICState *opp = opaque;
-    int idx;
-
-    DPRINTF("%s: addr %#" HWADDR_PRIx " <= %08" PRIx64 "\n",
-            __func__, addr, val);
-
-    addr = addr & 0xffff;
-    idx = addr >> 5;
-
-    switch (addr & 0x1f) {
-    case 0x00:
-        write_IRQreg_ivpr(opp, idx, val);
-        break;
-    case 0x10:
-        write_IRQreg_idr(opp, idx, val);
-        break;
-    case 0x18:
-        write_IRQreg_ilr(opp, idx, val);
-        break;
-    }
-}
-
-static uint64_t openpic_src_read(void *opaque, uint64_t addr, unsigned len)
-{
-    OpenPICState *opp = opaque;
-    uint32_t retval;
-    int idx;
-
-    DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr);
-    retval = 0xFFFFFFFF;
-
-    addr = addr & 0xffff;
-    idx = addr >> 5;
-
-    switch (addr & 0x1f) {
-    case 0x00:
-        retval = read_IRQreg_ivpr(opp, idx);
-        break;
-    case 0x10:
-        retval = read_IRQreg_idr(opp, idx);
-        break;
-    case 0x18:
-        retval = read_IRQreg_ilr(opp, idx);
-        break;
-    }
-
-    DPRINTF("%s: => 0x%08x\n", __func__, retval);
-    return retval;
-}
-
-static void openpic_msi_write(void *opaque, hwaddr addr, uint64_t val,
-                              unsigned size)
-{
-    OpenPICState *opp = opaque;
-    int idx = opp->irq_msi;
-    int srs, ibs;
-
-    DPRINTF("%s: addr %#" HWADDR_PRIx " <= 0x%08" PRIx64 "\n",
-            __func__, addr, val);
-    if (addr & 0xF) {
-        return;
-    }
-
-    switch (addr) {
-    case MSIIR_OFFSET:
-        srs = val >> MSIIR_SRS_SHIFT;
-        idx += srs;
-        ibs = (val & MSIIR_IBS_MASK) >> MSIIR_IBS_SHIFT;
-        opp->msi[srs].msir |= 1 << ibs;
-        openpic_set_irq(opp, idx, 1);
-        break;
-    default:
-        /* most registers are read-only, thus ignored */
-        break;
-    }
-}
-
-static uint64_t openpic_msi_read(void *opaque, hwaddr addr, unsigned size)
-{
-    OpenPICState *opp = opaque;
-    uint64_t r = 0;
-    int i, srs;
-
-    DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr);
-    if (addr & 0xF) {
-        return -1;
-    }
-
-    srs = addr >> 4;
-
-    switch (addr) {
-    case 0x00:
-    case 0x10:
-    case 0x20:
-    case 0x30:
-    case 0x40:
-    case 0x50:
-    case 0x60:
-    case 0x70: /* MSIRs */
-        r = opp->msi[srs].msir;
-        /* Clear on read */
-        opp->msi[srs].msir = 0;
-        openpic_set_irq(opp, opp->irq_msi + srs, 0);
-        break;
-    case 0x120: /* MSISR */
-        for (i = 0; i < MAX_MSI; i++) {
-            r |= (opp->msi[i].msir ? 1 : 0) << i;
-        }
-        break;
-    }
-
-    return r;
-}
-
-static uint64_t openpic_summary_read(void *opaque, hwaddr addr, unsigned size)
-{
-    uint64_t r = 0;
-
-    DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr);
-
-    /* TODO: EISR/EIMR */
-
-    return r;
-}
-
-static void openpic_summary_write(void *opaque, hwaddr addr, uint64_t val,
-                                  unsigned size)
-{
-    DPRINTF("%s: addr %#" HWADDR_PRIx " <= 0x%08" PRIx64 "\n",
-            __func__, addr, val);
-
-    /* TODO: EISR/EIMR */
-}
-
-static void openpic_cpu_write_internal(void *opaque, hwaddr addr,
-                                       uint32_t val, int idx)
-{
-    OpenPICState *opp = opaque;
-    IRQSource *src;
-    IRQDest *dst;
-    int s_IRQ, n_IRQ;
-
-    DPRINTF("%s: cpu %d addr %#" HWADDR_PRIx " <= 0x%08x\n", __func__, idx,
-            addr, val);
-
-    if (idx < 0) {
-        return;
-    }
-
-    if (addr & 0xF) {
-        return;
-    }
-    dst = &opp->dst[idx];
-    addr &= 0xFF0;
-    switch (addr) {
-    case 0x40: /* IPIDR */
-    case 0x50:
-    case 0x60:
-    case 0x70:
-        idx = (addr - 0x40) >> 4;
-        /* we use IDE as mask which CPUs to deliver the IPI to still. */
-        opp->src[opp->irq_ipi0 + idx].destmask |= val;
-        openpic_set_irq(opp, opp->irq_ipi0 + idx, 1);
-        openpic_set_irq(opp, opp->irq_ipi0 + idx, 0);
-        break;
-    case 0x80: /* CTPR */
-        dst->ctpr = val & 0x0000000F;
-
-        DPRINTF("%s: set CPU %d ctpr to %d, raised %d servicing %d\n",
-                __func__, idx, dst->ctpr, dst->raised.priority,
-                dst->servicing.priority);
-
-        if (dst->raised.priority <= dst->ctpr) {
-            DPRINTF("%s: Lower OpenPIC INT output cpu %d due to ctpr\n",
-                    __func__, idx);
-            qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_INT]);
-        } else if (dst->raised.priority > dst->servicing.priority) {
-            DPRINTF("%s: Raise OpenPIC INT output cpu %d irq %d\n",
-                    __func__, idx, dst->raised.next);
-            qemu_irq_raise(dst->irqs[OPENPIC_OUTPUT_INT]);
-        }
-
-        break;
-    case 0x90: /* WHOAMI */
-        /* Read-only register */
-        break;
-    case 0xA0: /* IACK */
-        /* Read-only register */
-        break;
-    case 0xB0: /* EOI */
-        DPRINTF("EOI\n");
-        s_IRQ = IRQ_get_next(opp, &dst->servicing);
-
-        if (s_IRQ < 0) {
-            DPRINTF("%s: EOI with no interrupt in service\n", __func__);
-            break;
-        }
-
-        IRQ_resetbit(&dst->servicing, s_IRQ);
-        /* Set up next servicing IRQ */
-        s_IRQ = IRQ_get_next(opp, &dst->servicing);
-        /* Check queued interrupts. */
-        n_IRQ = IRQ_get_next(opp, &dst->raised);
-        src = &opp->src[n_IRQ];
-        if (n_IRQ != -1 &&
-            (s_IRQ == -1 ||
-             IVPR_PRIORITY(src->ivpr) > dst->servicing.priority)) {
-            DPRINTF("Raise OpenPIC INT output cpu %d irq %d\n",
-                    idx, n_IRQ);
-            qemu_irq_raise(opp->dst[idx].irqs[OPENPIC_OUTPUT_INT]);
-        }
-        break;
-    default:
-        break;
-    }
-}
-
-static void openpic_cpu_write(void *opaque, hwaddr addr, uint64_t val,
-                              unsigned len)
-{
-    openpic_cpu_write_internal(opaque, addr, val, (addr & 0x1f000) >> 12);
-}
-
-
-static uint32_t openpic_iack(OpenPICState *opp, IRQDest *dst, int cpu)
-{
-    IRQSource *src;
-    int retval, irq;
-
-    DPRINTF("Lower OpenPIC INT output\n");
-    qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_INT]);
-
-    irq = IRQ_get_next(opp, &dst->raised);
-    DPRINTF("IACK: irq=%d\n", irq);
-
-    if (irq == -1) {
-        /* No more interrupt pending */
-        return opp->spve;
-    }
-
-    src = &opp->src[irq];
-    if (!(src->ivpr & IVPR_ACTIVITY_MASK) ||
-            !(IVPR_PRIORITY(src->ivpr) > dst->ctpr)) {
-        fprintf(stderr, "%s: bad raised IRQ %d ctpr %d ivpr 0x%08x\n",
-                __func__, irq, dst->ctpr, src->ivpr);
-        openpic_update_irq(opp, irq);
-        retval = opp->spve;
-    } else {
-        /* IRQ enter servicing state */
-        IRQ_setbit(&dst->servicing, irq);
-        retval = IVPR_VECTOR(opp, src->ivpr);
-    }
-
-    if (!src->level) {
-        /* edge-sensitive IRQ */
-        src->ivpr &= ~IVPR_ACTIVITY_MASK;
-        src->pending = 0;
-        IRQ_resetbit(&dst->raised, irq);
-    }
-
-    if ((irq >= opp->irq_ipi0) &&  (irq < (opp->irq_ipi0 + MAX_IPI))) {
-        src->destmask &= ~(1 << cpu);
-        if (src->destmask && !src->level) {
-            /* trigger on CPUs that didn't know about it yet */
-            openpic_set_irq(opp, irq, 1);
-            openpic_set_irq(opp, irq, 0);
-            /* if all CPUs knew about it, set active bit again */
-            src->ivpr |= IVPR_ACTIVITY_MASK;
-        }
-    }
-
-    return retval;
-}
-
-static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr,
-                                          int idx)
-{
-    OpenPICState *opp = opaque;
-    IRQDest *dst;
-    uint32_t retval;
-
-    DPRINTF("%s: cpu %d addr %#" HWADDR_PRIx "\n", __func__, idx, addr);
-    retval = 0xFFFFFFFF;
-
-    if (idx < 0) {
-        return retval;
-    }
-
-    if (addr & 0xF) {
-        return retval;
-    }
-    dst = &opp->dst[idx];
-    addr &= 0xFF0;
-    switch (addr) {
-    case 0x80: /* CTPR */
-        retval = dst->ctpr;
-        break;
-    case 0x90: /* WHOAMI */
-        retval = idx;
-        break;
-    case 0xA0: /* IACK */
-        retval = openpic_iack(opp, dst, idx);
-        break;
-    case 0xB0: /* EOI */
-        retval = 0;
-        break;
-    default:
-        break;
-    }
-    DPRINTF("%s: => 0x%08x\n", __func__, retval);
-
-    return retval;
-}
-
-static uint64_t openpic_cpu_read(void *opaque, hwaddr addr, unsigned len)
-{
-    return openpic_cpu_read_internal(opaque, addr, (addr & 0x1f000) >> 12);
-}
-
-static const MemoryRegionOps openpic_glb_ops_le = {
-    .write = openpic_gbl_write,
-    .read  = openpic_gbl_read,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-    .impl = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-};
-
-static const MemoryRegionOps openpic_glb_ops_be = {
-    .write = openpic_gbl_write,
-    .read  = openpic_gbl_read,
-    .endianness = DEVICE_BIG_ENDIAN,
-    .impl = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-};
-
-static const MemoryRegionOps openpic_tmr_ops_le = {
-    .write = openpic_tmr_write,
-    .read  = openpic_tmr_read,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-    .impl = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-};
-
-static const MemoryRegionOps openpic_tmr_ops_be = {
-    .write = openpic_tmr_write,
-    .read  = openpic_tmr_read,
-    .endianness = DEVICE_BIG_ENDIAN,
-    .impl = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-};
-
-static const MemoryRegionOps openpic_cpu_ops_le = {
-    .write = openpic_cpu_write,
-    .read  = openpic_cpu_read,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-    .impl = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-};
-
-static const MemoryRegionOps openpic_cpu_ops_be = {
-    .write = openpic_cpu_write,
-    .read  = openpic_cpu_read,
-    .endianness = DEVICE_BIG_ENDIAN,
-    .impl = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-};
-
-static const MemoryRegionOps openpic_src_ops_le = {
-    .write = openpic_src_write,
-    .read  = openpic_src_read,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-    .impl = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-};
-
-static const MemoryRegionOps openpic_src_ops_be = {
-    .write = openpic_src_write,
-    .read  = openpic_src_read,
-    .endianness = DEVICE_BIG_ENDIAN,
-    .impl = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-};
-
-static const MemoryRegionOps openpic_msi_ops_be = {
-    .read = openpic_msi_read,
-    .write = openpic_msi_write,
-    .endianness = DEVICE_BIG_ENDIAN,
-    .impl = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-};
-
-static const MemoryRegionOps openpic_summary_ops_be = {
-    .read = openpic_summary_read,
-    .write = openpic_summary_write,
-    .endianness = DEVICE_BIG_ENDIAN,
-    .impl = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-};
-
-static void openpic_save_IRQ_queue(QEMUFile* f, IRQQueue *q)
-{
-    unsigned int i;
-
-    for (i = 0; i < ARRAY_SIZE(q->queue); i++) {
-        /* Always put the lower half of a 64-bit long first, in case we
-         * restore on a 32-bit host.  The least significant bits correspond
-         * to lower IRQ numbers in the bitmap.
-         */
-        qemu_put_be32(f, (uint32_t)q->queue[i]);
-#if LONG_MAX > 0x7FFFFFFF
-        qemu_put_be32(f, (uint32_t)(q->queue[i] >> 32));
-#endif
-    }
-
-    qemu_put_sbe32s(f, &q->next);
-    qemu_put_sbe32s(f, &q->priority);
-}
-
-static void openpic_save(QEMUFile* f, void *opaque)
-{
-    OpenPICState *opp = (OpenPICState *)opaque;
-    unsigned int i;
-
-    qemu_put_be32s(f, &opp->gcr);
-    qemu_put_be32s(f, &opp->vir);
-    qemu_put_be32s(f, &opp->pir);
-    qemu_put_be32s(f, &opp->spve);
-    qemu_put_be32s(f, &opp->tfrr);
-
-    qemu_put_be32s(f, &opp->nb_cpus);
-
-    for (i = 0; i < opp->nb_cpus; i++) {
-        qemu_put_sbe32s(f, &opp->dst[i].ctpr);
-        openpic_save_IRQ_queue(f, &opp->dst[i].raised);
-        openpic_save_IRQ_queue(f, &opp->dst[i].servicing);
-        qemu_put_buffer(f, (uint8_t *)&opp->dst[i].outputs_active,
-                        sizeof(opp->dst[i].outputs_active));
-    }
-
-    for (i = 0; i < MAX_TMR; i++) {
-        qemu_put_be32s(f, &opp->timers[i].tccr);
-        qemu_put_be32s(f, &opp->timers[i].tbcr);
-    }
-
-    for (i = 0; i < opp->max_irq; i++) {
-        qemu_put_be32s(f, &opp->src[i].ivpr);
-        qemu_put_be32s(f, &opp->src[i].idr);
-        qemu_get_be32s(f, &opp->src[i].destmask);
-        qemu_put_sbe32s(f, &opp->src[i].last_cpu);
-        qemu_put_sbe32s(f, &opp->src[i].pending);
-    }
-}
-
-static void openpic_load_IRQ_queue(QEMUFile* f, IRQQueue *q)
-{
-    unsigned int i;
-
-    for (i = 0; i < ARRAY_SIZE(q->queue); i++) {
-        unsigned long val;
-
-        val = qemu_get_be32(f);
-#if LONG_MAX > 0x7FFFFFFF
-        val <<= 32;
-        val |= qemu_get_be32(f);
-#endif
-
-        q->queue[i] = val;
-    }
-
-    qemu_get_sbe32s(f, &q->next);
-    qemu_get_sbe32s(f, &q->priority);
-}
-
-static int openpic_load(QEMUFile* f, void *opaque, int version_id)
-{
-    OpenPICState *opp = (OpenPICState *)opaque;
-    unsigned int i;
-
-    if (version_id != 1) {
-        return -EINVAL;
-    }
-
-    qemu_get_be32s(f, &opp->gcr);
-    qemu_get_be32s(f, &opp->vir);
-    qemu_get_be32s(f, &opp->pir);
-    qemu_get_be32s(f, &opp->spve);
-    qemu_get_be32s(f, &opp->tfrr);
-
-    qemu_get_be32s(f, &opp->nb_cpus);
-
-    for (i = 0; i < opp->nb_cpus; i++) {
-        qemu_get_sbe32s(f, &opp->dst[i].ctpr);
-        openpic_load_IRQ_queue(f, &opp->dst[i].raised);
-        openpic_load_IRQ_queue(f, &opp->dst[i].servicing);
-        qemu_get_buffer(f, (uint8_t *)&opp->dst[i].outputs_active,
-                        sizeof(opp->dst[i].outputs_active));
-    }
-
-    for (i = 0; i < MAX_TMR; i++) {
-        qemu_get_be32s(f, &opp->timers[i].tccr);
-        qemu_get_be32s(f, &opp->timers[i].tbcr);
-    }
-
-    for (i = 0; i < opp->max_irq; i++) {
-        uint32_t val;
-
-        val = qemu_get_be32(f);
-        write_IRQreg_idr(opp, i, val);
-        val = qemu_get_be32(f);
-        write_IRQreg_ivpr(opp, i, val);
-
-        qemu_get_be32s(f, &opp->src[i].ivpr);
-        qemu_get_be32s(f, &opp->src[i].idr);
-        qemu_get_be32s(f, &opp->src[i].destmask);
-        qemu_get_sbe32s(f, &opp->src[i].last_cpu);
-        qemu_get_sbe32s(f, &opp->src[i].pending);
-    }
-
-    return 0;
-}
-
-typedef struct MemReg {
-    const char             *name;
-    MemoryRegionOps const  *ops;
-    hwaddr      start_addr;
-    ram_addr_t              size;
-} MemReg;
-
-static void fsl_common_init(OpenPICState *opp)
-{
-    int i;
-    int virq = MAX_SRC;
-
-    opp->vid = VID_REVISION_1_2;
-    opp->vir = VIR_GENERIC;
-    opp->vector_mask = 0xFFFF;
-    opp->tfrr_reset = 0;
-    opp->ivpr_reset = IVPR_MASK_MASK;
-    opp->idr_reset = 1 << 0;
-    opp->max_irq = MAX_IRQ;
-
-    opp->irq_ipi0 = virq;
-    virq += MAX_IPI;
-    opp->irq_tim0 = virq;
-    virq += MAX_TMR;
-
-    assert(virq <= MAX_IRQ);
-
-    opp->irq_msi = 224;
-
-    msi_supported = true;
-    for (i = 0; i < opp->fsl->max_ext; i++) {
-        opp->src[i].level = false;
-    }
-
-    /* Internal interrupts, including message and MSI */
-    for (i = 16; i < MAX_SRC; i++) {
-        opp->src[i].type = IRQ_TYPE_FSLINT;
-        opp->src[i].level = true;
-    }
-
-    /* timers and IPIs */
-    for (i = MAX_SRC; i < virq; i++) {
-        opp->src[i].type = IRQ_TYPE_FSLSPECIAL;
-        opp->src[i].level = false;
-    }
-}
-
-static void map_list(OpenPICState *opp, const MemReg *list, int *count)
-{
-    while (list->name) {
-        assert(*count < ARRAY_SIZE(opp->sub_io_mem));
-
-        memory_region_init_io(&opp->sub_io_mem[*count], list->ops, opp,
-                              list->name, list->size);
-
-        memory_region_add_subregion(&opp->mem, list->start_addr,
-                                    &opp->sub_io_mem[*count]);
-
-        (*count)++;
-        list++;
-    }
-}
-
-static int openpic_init(SysBusDevice *dev)
-{
-    OpenPICState *opp = FROM_SYSBUS(typeof (*opp), dev);
-    int i, j;
-    int list_count = 0;
-    static const MemReg list_le[] = {
-        {"glb", &openpic_glb_ops_le,
-                OPENPIC_GLB_REG_START, OPENPIC_GLB_REG_SIZE},
-        {"tmr", &openpic_tmr_ops_le,
-                OPENPIC_TMR_REG_START, OPENPIC_TMR_REG_SIZE},
-        {"src", &openpic_src_ops_le,
-                OPENPIC_SRC_REG_START, OPENPIC_SRC_REG_SIZE},
-        {"cpu", &openpic_cpu_ops_le,
-                OPENPIC_CPU_REG_START, OPENPIC_CPU_REG_SIZE},
-        {NULL}
-    };
-    static const MemReg list_be[] = {
-        {"glb", &openpic_glb_ops_be,
-                OPENPIC_GLB_REG_START, OPENPIC_GLB_REG_SIZE},
-        {"tmr", &openpic_tmr_ops_be,
-                OPENPIC_TMR_REG_START, OPENPIC_TMR_REG_SIZE},
-        {"src", &openpic_src_ops_be,
-                OPENPIC_SRC_REG_START, OPENPIC_SRC_REG_SIZE},
-        {"cpu", &openpic_cpu_ops_be,
-                OPENPIC_CPU_REG_START, OPENPIC_CPU_REG_SIZE},
-        {NULL}
-    };
-    static const MemReg list_fsl[] = {
-        {"msi", &openpic_msi_ops_be,
-                OPENPIC_MSI_REG_START, OPENPIC_MSI_REG_SIZE},
-        {"summary", &openpic_summary_ops_be,
-                OPENPIC_SUMMARY_REG_START, OPENPIC_SUMMARY_REG_SIZE},
-        {NULL}
-    };
-
-    memory_region_init(&opp->mem, "openpic", 0x40000);
-
-    switch (opp->model) {
-    case OPENPIC_MODEL_FSL_MPIC_20:
-    default:
-        opp->fsl = &fsl_mpic_20;
-        opp->brr1 = 0x00400200;
-        opp->flags |= OPENPIC_FLAG_IDR_CRIT;
-        opp->nb_irqs = 80;
-        opp->mpic_mode_mask = GCR_MODE_MIXED;
-
-        fsl_common_init(opp);
-        map_list(opp, list_be, &list_count);
-        map_list(opp, list_fsl, &list_count);
-
-        break;
-
-    case OPENPIC_MODEL_FSL_MPIC_42:
-        opp->fsl = &fsl_mpic_42;
-        opp->brr1 = 0x00400402;
-        opp->flags |= OPENPIC_FLAG_ILR;
-        opp->nb_irqs = 196;
-        opp->mpic_mode_mask = GCR_MODE_PROXY;
-
-        fsl_common_init(opp);
-        map_list(opp, list_be, &list_count);
-        map_list(opp, list_fsl, &list_count);
-
-        break;
-
-    case OPENPIC_MODEL_RAVEN:
-        opp->nb_irqs = RAVEN_MAX_EXT;
-        opp->vid = VID_REVISION_1_3;
-        opp->vir = VIR_GENERIC;
-        opp->vector_mask = 0xFF;
-        opp->tfrr_reset = 4160000;
-        opp->ivpr_reset = IVPR_MASK_MASK | IVPR_MODE_MASK;
-        opp->idr_reset = 0;
-        opp->max_irq = RAVEN_MAX_IRQ;
-        opp->irq_ipi0 = RAVEN_IPI_IRQ;
-        opp->irq_tim0 = RAVEN_TMR_IRQ;
-        opp->brr1 = -1;
-        opp->mpic_mode_mask = GCR_MODE_MIXED;
-
-        /* Only UP supported today */
-        if (opp->nb_cpus != 1) {
-            return -EINVAL;
-        }
-
-        map_list(opp, list_le, &list_count);
-        break;
-    }
-
-    for (i = 0; i < opp->nb_cpus; i++) {
-        opp->dst[i].irqs = g_new(qemu_irq, OPENPIC_OUTPUT_NB);
-        for (j = 0; j < OPENPIC_OUTPUT_NB; j++) {
-            sysbus_init_irq(dev, &opp->dst[i].irqs[j]);
-        }
-    }
-
-    register_savevm(&opp->busdev.qdev, "openpic", 0, 2,
-                    openpic_save, openpic_load, opp);
-
-    sysbus_init_mmio(dev, &opp->mem);
-    qdev_init_gpio_in(&dev->qdev, openpic_set_irq, opp->max_irq);
-
-    return 0;
-}
-
-static Property openpic_properties[] = {
-    DEFINE_PROP_UINT32("model", OpenPICState, model, OPENPIC_MODEL_FSL_MPIC_20),
-    DEFINE_PROP_UINT32("nb_cpus", OpenPICState, nb_cpus, 1),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void openpic_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = openpic_init;
-    dc->props = openpic_properties;
-    dc->reset = openpic_reset;
-}
-
-static const TypeInfo openpic_info = {
-    .name          = "openpic",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(OpenPICState),
-    .class_init    = openpic_class_init,
-};
-
-static void openpic_register_types(void)
-{
-    type_register_static(&openpic_info);
-}
-
-type_init(openpic_register_types)
diff --git a/hw/openpic.h b/hw/openpic.h
deleted file mode 100644 (file)
index 9dcaf0e..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-#if !defined(__OPENPIC_H__)
-#define __OPENPIC_H__
-
-/* OpenPIC have 5 outputs per CPU connected and one IRQ out single output */
-enum {
-    OPENPIC_OUTPUT_INT = 0, /* IRQ                       */
-    OPENPIC_OUTPUT_CINT,    /* critical IRQ              */
-    OPENPIC_OUTPUT_MCK,     /* Machine check event       */
-    OPENPIC_OUTPUT_DEBUG,   /* Inconditional debug event */
-    OPENPIC_OUTPUT_RESET,   /* Core reset event          */
-    OPENPIC_OUTPUT_NB,
-};
-
-#define OPENPIC_MODEL_RAVEN       0
-#define OPENPIC_MODEL_FSL_MPIC_20 1
-#define OPENPIC_MODEL_FSL_MPIC_42 2
-
-#endif /* __OPENPIC_H__ */
index db2aac8cf81afe95a31c61efc6157b35682ed82d..49bab1f0f069b4a24c12f2d22ed54cedb6811c09 100644 (file)
@@ -21,7 +21,7 @@
 #include "hw/hw.h"
 #include "hw/boards.h"
 #include "elf.h"
-#include "hw/serial.h"
+#include "hw/char/serial.h"
 #include "net/net.h"
 #include "hw/loader.h"
 #include "exec/address-spaces.h"
diff --git a/hw/pam.c b/hw/pam.c
deleted file mode 100644 (file)
index 6c0061e..0000000
--- a/hw/pam.c
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * QEMU i440FX/PIIX3 PCI Bridge Emulation
- *
- * Copyright (c) 2006 Fabrice Bellard
- * Copyright (c) 2011 Isaku Yamahata <yamahata at valinux co jp>
- *                    VA Linux Systems Japan K.K.
- * Copyright (c) 2012 Jason Baron <jbaron@redhat.com>
- *
- * Split out from piix_pci.c
- *
- * 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 "sysemu/sysemu.h"
-#include "hw/pam.h"
-
-void smram_update(MemoryRegion *smram_region, uint8_t smram,
-                  uint8_t smm_enabled)
-{
-    bool smram_enabled;
-
-    smram_enabled = ((smm_enabled && (smram & SMRAM_G_SMRAME)) ||
-                        (smram & SMRAM_D_OPEN));
-    memory_region_set_enabled(smram_region, !smram_enabled);
-}
-
-void smram_set_smm(uint8_t *host_smm_enabled, int smm, uint8_t smram,
-                   MemoryRegion *smram_region)
-{
-    uint8_t smm_enabled = (smm != 0);
-    if (*host_smm_enabled != smm_enabled) {
-        *host_smm_enabled = smm_enabled;
-        smram_update(smram_region, smram, *host_smm_enabled);
-    }
-}
-
-void init_pam(MemoryRegion *ram_memory, MemoryRegion *system_memory,
-              MemoryRegion *pci_address_space, PAMMemoryRegion *mem,
-              uint32_t start, uint32_t size)
-{
-    int i;
-
-    /* RAM */
-    memory_region_init_alias(&mem->alias[3], "pam-ram", ram_memory,
-                             start, size);
-    /* ROM (XXX: not quite correct) */
-    memory_region_init_alias(&mem->alias[1], "pam-rom", ram_memory,
-                             start, size);
-    memory_region_set_readonly(&mem->alias[1], true);
-
-    /* XXX: should distinguish read/write cases */
-    memory_region_init_alias(&mem->alias[0], "pam-pci", pci_address_space,
-                             start, size);
-    memory_region_init_alias(&mem->alias[2], "pam-pci", pci_address_space,
-                             start, size);
-
-    for (i = 0; i < 4; ++i) {
-        memory_region_set_enabled(&mem->alias[i], false);
-        memory_region_add_subregion_overlap(system_memory, start,
-                                            &mem->alias[i], 1);
-    }
-    mem->current = 0;
-}
-
-void pam_update(PAMMemoryRegion *pam, int idx, uint8_t val)
-{
-    assert(0 <= idx && idx <= 12);
-
-    memory_region_set_enabled(&pam->alias[pam->current], false);
-    pam->current = (val >> ((!(idx & 1)) * 4)) & PAM_ATTR_MASK;
-    memory_region_set_enabled(&pam->alias[pam->current], true);
-}
diff --git a/hw/pam.h b/hw/pam.h
deleted file mode 100644 (file)
index 8e9e349..0000000
--- a/hw/pam.h
+++ /dev/null
@@ -1,97 +0,0 @@
-#ifndef QEMU_PAM_H
-#define QEMU_PAM_H
-
-/*
- * Copyright (c) 2006 Fabrice Bellard
- * Copyright (c) 2011 Isaku Yamahata <yamahata at valinux co jp>
- *               VA Linux Systems Japan K.K.
- * Copyright (c) 2012 Jason Baron <jbaron@redhat.com>
- *
- * Split out from piix_pci.c
- *
- * 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.
- */
-
-/*
- * SMRAM memory area and PAM memory area in Legacy address range for PC.
- * PAM: Programmable Attribute Map registers
- *
- * 0xa0000 - 0xbffff compatible SMRAM
- *
- * 0xc0000 - 0xc3fff Expansion area memory segments
- * 0xc4000 - 0xc7fff
- * 0xc8000 - 0xcbfff
- * 0xcc000 - 0xcffff
- * 0xd0000 - 0xd3fff
- * 0xd4000 - 0xd7fff
- * 0xd8000 - 0xdbfff
- * 0xdc000 - 0xdffff
- * 0xe0000 - 0xe3fff Extended System BIOS Area Memory Segments
- * 0xe4000 - 0xe7fff
- * 0xe8000 - 0xebfff
- * 0xec000 - 0xeffff
- *
- * 0xf0000 - 0xfffff System BIOS Area Memory Segments
- */
-
-#include "qemu-common.h"
-#include "exec/memory.h"
-
-#define SMRAM_C_BASE    0xa0000
-#define SMRAM_C_END     0xc0000
-#define SMRAM_C_SIZE    0x20000
-
-#define PAM_EXPAN_BASE  0xc0000
-#define PAM_EXPAN_SIZE  0x04000
-
-#define PAM_EXBIOS_BASE 0xe0000
-#define PAM_EXBIOS_SIZE 0x04000
-
-#define PAM_BIOS_BASE   0xf0000
-#define PAM_BIOS_END    0xfffff
-/* 64KB: Intel 3 series express chipset family p. 58*/
-#define PAM_BIOS_SIZE   0x10000
-
-/* PAM registers: log nibble and high nibble*/
-#define PAM_ATTR_WE     ((uint8_t)2)
-#define PAM_ATTR_RE     ((uint8_t)1)
-#define PAM_ATTR_MASK   ((uint8_t)3)
-
-/* SMRAM register */
-#define SMRAM_D_OPEN           ((uint8_t)(1 << 6))
-#define SMRAM_D_CLS            ((uint8_t)(1 << 5))
-#define SMRAM_D_LCK            ((uint8_t)(1 << 4))
-#define SMRAM_G_SMRAME         ((uint8_t)(1 << 3))
-#define SMRAM_C_BASE_SEG_MASK  ((uint8_t)0x7)
-#define SMRAM_C_BASE_SEG       ((uint8_t)0x2)  /* hardwired to b010 */
-
-typedef struct PAMMemoryRegion {
-    MemoryRegion alias[4];  /* index = PAM value */
-    unsigned current;
-} PAMMemoryRegion;
-
-void smram_update(MemoryRegion *smram_region, uint8_t smram,
-                  uint8_t smm_enabled);
-void smram_set_smm(uint8_t *host_smm_enabled, int smm, uint8_t smram,
-                   MemoryRegion *smram_region);
-void init_pam(MemoryRegion *ram, MemoryRegion *system, MemoryRegion *pci,
-              PAMMemoryRegion *mem, uint32_t start, uint32_t size);
-void pam_update(PAMMemoryRegion *mem, int idx, uint8_t val);
-
-#endif /* QEMU_PAM_H */
diff --git a/hw/parallel.c b/hw/parallel.c
deleted file mode 100644 (file)
index 0b9af43..0000000
+++ /dev/null
@@ -1,614 +0,0 @@
-/*
- * QEMU Parallel PORT emulation
- *
- * Copyright (c) 2003-2005 Fabrice Bellard
- * Copyright (c) 2007 Marko Kohtala
- *
- * 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 "hw/hw.h"
-#include "char/char.h"
-#include "hw/isa.h"
-#include "hw/pc.h"
-#include "sysemu/sysemu.h"
-
-//#define DEBUG_PARALLEL
-
-#ifdef DEBUG_PARALLEL
-#define pdebug(fmt, ...) printf("pp: " fmt, ## __VA_ARGS__)
-#else
-#define pdebug(fmt, ...) ((void)0)
-#endif
-
-#define PARA_REG_DATA 0
-#define PARA_REG_STS 1
-#define PARA_REG_CTR 2
-#define PARA_REG_EPP_ADDR 3
-#define PARA_REG_EPP_DATA 4
-
-/*
- * These are the definitions for the Printer Status Register
- */
-#define PARA_STS_BUSY  0x80    /* Busy complement */
-#define PARA_STS_ACK   0x40    /* Acknowledge */
-#define PARA_STS_PAPER 0x20    /* Out of paper */
-#define PARA_STS_ONLINE        0x10    /* Online */
-#define PARA_STS_ERROR 0x08    /* Error complement */
-#define PARA_STS_TMOUT 0x01    /* EPP timeout */
-
-/*
- * These are the definitions for the Printer Control Register
- */
-#define PARA_CTR_DIR   0x20    /* Direction (1=read, 0=write) */
-#define PARA_CTR_INTEN 0x10    /* IRQ Enable */
-#define PARA_CTR_SELECT        0x08    /* Select In complement */
-#define PARA_CTR_INIT  0x04    /* Initialize Printer complement */
-#define PARA_CTR_AUTOLF        0x02    /* Auto linefeed complement */
-#define PARA_CTR_STROBE        0x01    /* Strobe complement */
-
-#define PARA_CTR_SIGNAL (PARA_CTR_SELECT|PARA_CTR_INIT|PARA_CTR_AUTOLF|PARA_CTR_STROBE)
-
-typedef struct ParallelState {
-    MemoryRegion iomem;
-    uint8_t dataw;
-    uint8_t datar;
-    uint8_t status;
-    uint8_t control;
-    qemu_irq irq;
-    int irq_pending;
-    CharDriverState *chr;
-    int hw_driver;
-    int epp_timeout;
-    uint32_t last_read_offset; /* For debugging */
-    /* Memory-mapped interface */
-    int it_shift;
-} ParallelState;
-
-typedef struct ISAParallelState {
-    ISADevice dev;
-    uint32_t index;
-    uint32_t iobase;
-    uint32_t isairq;
-    ParallelState state;
-} ISAParallelState;
-
-static void parallel_update_irq(ParallelState *s)
-{
-    if (s->irq_pending)
-        qemu_irq_raise(s->irq);
-    else
-        qemu_irq_lower(s->irq);
-}
-
-static void
-parallel_ioport_write_sw(void *opaque, uint32_t addr, uint32_t val)
-{
-    ParallelState *s = opaque;
-
-    pdebug("write addr=0x%02x val=0x%02x\n", addr, val);
-
-    addr &= 7;
-    switch(addr) {
-    case PARA_REG_DATA:
-        s->dataw = val;
-        parallel_update_irq(s);
-        break;
-    case PARA_REG_CTR:
-        val |= 0xc0;
-        if ((val & PARA_CTR_INIT) == 0 ) {
-            s->status = PARA_STS_BUSY;
-            s->status |= PARA_STS_ACK;
-            s->status |= PARA_STS_ONLINE;
-            s->status |= PARA_STS_ERROR;
-        }
-        else if (val & PARA_CTR_SELECT) {
-            if (val & PARA_CTR_STROBE) {
-                s->status &= ~PARA_STS_BUSY;
-                if ((s->control & PARA_CTR_STROBE) == 0)
-                    qemu_chr_fe_write(s->chr, &s->dataw, 1);
-            } else {
-                if (s->control & PARA_CTR_INTEN) {
-                    s->irq_pending = 1;
-                }
-            }
-        }
-        parallel_update_irq(s);
-        s->control = val;
-        break;
-    }
-}
-
-static void parallel_ioport_write_hw(void *opaque, uint32_t addr, uint32_t val)
-{
-    ParallelState *s = opaque;
-    uint8_t parm = val;
-    int dir;
-
-    /* Sometimes programs do several writes for timing purposes on old
-       HW. Take care not to waste time on writes that do nothing. */
-
-    s->last_read_offset = ~0U;
-
-    addr &= 7;
-    switch(addr) {
-    case PARA_REG_DATA:
-        if (s->dataw == val)
-            return;
-        pdebug("wd%02x\n", val);
-        qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_WRITE_DATA, &parm);
-        s->dataw = val;
-        break;
-    case PARA_REG_STS:
-        pdebug("ws%02x\n", val);
-        if (val & PARA_STS_TMOUT)
-            s->epp_timeout = 0;
-        break;
-    case PARA_REG_CTR:
-        val |= 0xc0;
-        if (s->control == val)
-            return;
-        pdebug("wc%02x\n", val);
-
-        if ((val & PARA_CTR_DIR) != (s->control & PARA_CTR_DIR)) {
-            if (val & PARA_CTR_DIR) {
-                dir = 1;
-            } else {
-                dir = 0;
-            }
-            qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_DATA_DIR, &dir);
-            parm &= ~PARA_CTR_DIR;
-        }
-
-        qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_WRITE_CONTROL, &parm);
-        s->control = val;
-        break;
-    case PARA_REG_EPP_ADDR:
-        if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != PARA_CTR_INIT)
-            /* Controls not correct for EPP address cycle, so do nothing */
-            pdebug("wa%02x s\n", val);
-        else {
-            struct ParallelIOArg ioarg = { .buffer = &parm, .count = 1 };
-            if (qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_EPP_WRITE_ADDR, &ioarg)) {
-                s->epp_timeout = 1;
-                pdebug("wa%02x t\n", val);
-            }
-            else
-                pdebug("wa%02x\n", val);
-        }
-        break;
-    case PARA_REG_EPP_DATA:
-        if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != PARA_CTR_INIT)
-            /* Controls not correct for EPP data cycle, so do nothing */
-            pdebug("we%02x s\n", val);
-        else {
-            struct ParallelIOArg ioarg = { .buffer = &parm, .count = 1 };
-            if (qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_EPP_WRITE, &ioarg)) {
-                s->epp_timeout = 1;
-                pdebug("we%02x t\n", val);
-            }
-            else
-                pdebug("we%02x\n", val);
-        }
-        break;
-    }
-}
-
-static void
-parallel_ioport_eppdata_write_hw2(void *opaque, uint32_t addr, uint32_t val)
-{
-    ParallelState *s = opaque;
-    uint16_t eppdata = cpu_to_le16(val);
-    int err;
-    struct ParallelIOArg ioarg = {
-        .buffer = &eppdata, .count = sizeof(eppdata)
-    };
-    if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != PARA_CTR_INIT) {
-        /* Controls not correct for EPP data cycle, so do nothing */
-        pdebug("we%04x s\n", val);
-        return;
-    }
-    err = qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_EPP_WRITE, &ioarg);
-    if (err) {
-        s->epp_timeout = 1;
-        pdebug("we%04x t\n", val);
-    }
-    else
-        pdebug("we%04x\n", val);
-}
-
-static void
-parallel_ioport_eppdata_write_hw4(void *opaque, uint32_t addr, uint32_t val)
-{
-    ParallelState *s = opaque;
-    uint32_t eppdata = cpu_to_le32(val);
-    int err;
-    struct ParallelIOArg ioarg = {
-        .buffer = &eppdata, .count = sizeof(eppdata)
-    };
-    if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != PARA_CTR_INIT) {
-        /* Controls not correct for EPP data cycle, so do nothing */
-        pdebug("we%08x s\n", val);
-        return;
-    }
-    err = qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_EPP_WRITE, &ioarg);
-    if (err) {
-        s->epp_timeout = 1;
-        pdebug("we%08x t\n", val);
-    }
-    else
-        pdebug("we%08x\n", val);
-}
-
-static uint32_t parallel_ioport_read_sw(void *opaque, uint32_t addr)
-{
-    ParallelState *s = opaque;
-    uint32_t ret = 0xff;
-
-    addr &= 7;
-    switch(addr) {
-    case PARA_REG_DATA:
-        if (s->control & PARA_CTR_DIR)
-            ret = s->datar;
-        else
-            ret = s->dataw;
-        break;
-    case PARA_REG_STS:
-        ret = s->status;
-        s->irq_pending = 0;
-        if ((s->status & PARA_STS_BUSY) == 0 && (s->control & PARA_CTR_STROBE) == 0) {
-            /* XXX Fixme: wait 5 microseconds */
-            if (s->status & PARA_STS_ACK)
-                s->status &= ~PARA_STS_ACK;
-            else {
-                /* XXX Fixme: wait 5 microseconds */
-                s->status |= PARA_STS_ACK;
-                s->status |= PARA_STS_BUSY;
-            }
-        }
-        parallel_update_irq(s);
-        break;
-    case PARA_REG_CTR:
-        ret = s->control;
-        break;
-    }
-    pdebug("read addr=0x%02x val=0x%02x\n", addr, ret);
-    return ret;
-}
-
-static uint32_t parallel_ioport_read_hw(void *opaque, uint32_t addr)
-{
-    ParallelState *s = opaque;
-    uint8_t ret = 0xff;
-    addr &= 7;
-    switch(addr) {
-    case PARA_REG_DATA:
-        qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_READ_DATA, &ret);
-        if (s->last_read_offset != addr || s->datar != ret)
-            pdebug("rd%02x\n", ret);
-        s->datar = ret;
-        break;
-    case PARA_REG_STS:
-        qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_READ_STATUS, &ret);
-        ret &= ~PARA_STS_TMOUT;
-        if (s->epp_timeout)
-            ret |= PARA_STS_TMOUT;
-        if (s->last_read_offset != addr || s->status != ret)
-            pdebug("rs%02x\n", ret);
-        s->status = ret;
-        break;
-    case PARA_REG_CTR:
-        /* s->control has some bits fixed to 1. It is zero only when
-           it has not been yet written to.  */
-        if (s->control == 0) {
-            qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_READ_CONTROL, &ret);
-            if (s->last_read_offset != addr)
-                pdebug("rc%02x\n", ret);
-            s->control = ret;
-        }
-        else {
-            ret = s->control;
-            if (s->last_read_offset != addr)
-                pdebug("rc%02x\n", ret);
-        }
-        break;
-    case PARA_REG_EPP_ADDR:
-        if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != (PARA_CTR_DIR|PARA_CTR_INIT))
-            /* Controls not correct for EPP addr cycle, so do nothing */
-            pdebug("ra%02x s\n", ret);
-        else {
-            struct ParallelIOArg ioarg = { .buffer = &ret, .count = 1 };
-            if (qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_EPP_READ_ADDR, &ioarg)) {
-                s->epp_timeout = 1;
-                pdebug("ra%02x t\n", ret);
-            }
-            else
-                pdebug("ra%02x\n", ret);
-        }
-        break;
-    case PARA_REG_EPP_DATA:
-        if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != (PARA_CTR_DIR|PARA_CTR_INIT))
-            /* Controls not correct for EPP data cycle, so do nothing */
-            pdebug("re%02x s\n", ret);
-        else {
-            struct ParallelIOArg ioarg = { .buffer = &ret, .count = 1 };
-            if (qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_EPP_READ, &ioarg)) {
-                s->epp_timeout = 1;
-                pdebug("re%02x t\n", ret);
-            }
-            else
-                pdebug("re%02x\n", ret);
-        }
-        break;
-    }
-    s->last_read_offset = addr;
-    return ret;
-}
-
-static uint32_t
-parallel_ioport_eppdata_read_hw2(void *opaque, uint32_t addr)
-{
-    ParallelState *s = opaque;
-    uint32_t ret;
-    uint16_t eppdata = ~0;
-    int err;
-    struct ParallelIOArg ioarg = {
-        .buffer = &eppdata, .count = sizeof(eppdata)
-    };
-    if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != (PARA_CTR_DIR|PARA_CTR_INIT)) {
-        /* Controls not correct for EPP data cycle, so do nothing */
-        pdebug("re%04x s\n", eppdata);
-        return eppdata;
-    }
-    err = qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_EPP_READ, &ioarg);
-    ret = le16_to_cpu(eppdata);
-
-    if (err) {
-        s->epp_timeout = 1;
-        pdebug("re%04x t\n", ret);
-    }
-    else
-        pdebug("re%04x\n", ret);
-    return ret;
-}
-
-static uint32_t
-parallel_ioport_eppdata_read_hw4(void *opaque, uint32_t addr)
-{
-    ParallelState *s = opaque;
-    uint32_t ret;
-    uint32_t eppdata = ~0U;
-    int err;
-    struct ParallelIOArg ioarg = {
-        .buffer = &eppdata, .count = sizeof(eppdata)
-    };
-    if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != (PARA_CTR_DIR|PARA_CTR_INIT)) {
-        /* Controls not correct for EPP data cycle, so do nothing */
-        pdebug("re%08x s\n", eppdata);
-        return eppdata;
-    }
-    err = qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_EPP_READ, &ioarg);
-    ret = le32_to_cpu(eppdata);
-
-    if (err) {
-        s->epp_timeout = 1;
-        pdebug("re%08x t\n", ret);
-    }
-    else
-        pdebug("re%08x\n", ret);
-    return ret;
-}
-
-static void parallel_ioport_ecp_write(void *opaque, uint32_t addr, uint32_t val)
-{
-    pdebug("wecp%d=%02x\n", addr & 7, val);
-}
-
-static uint32_t parallel_ioport_ecp_read(void *opaque, uint32_t addr)
-{
-    uint8_t ret = 0xff;
-
-    pdebug("recp%d:%02x\n", addr & 7, ret);
-    return ret;
-}
-
-static void parallel_reset(void *opaque)
-{
-    ParallelState *s = opaque;
-
-    s->datar = ~0;
-    s->dataw = ~0;
-    s->status = PARA_STS_BUSY;
-    s->status |= PARA_STS_ACK;
-    s->status |= PARA_STS_ONLINE;
-    s->status |= PARA_STS_ERROR;
-    s->status |= PARA_STS_TMOUT;
-    s->control = PARA_CTR_SELECT;
-    s->control |= PARA_CTR_INIT;
-    s->control |= 0xc0;
-    s->irq_pending = 0;
-    s->hw_driver = 0;
-    s->epp_timeout = 0;
-    s->last_read_offset = ~0U;
-}
-
-static const int isa_parallel_io[MAX_PARALLEL_PORTS] = { 0x378, 0x278, 0x3bc };
-
-static const MemoryRegionPortio isa_parallel_portio_hw_list[] = {
-    { 0, 8, 1,
-      .read = parallel_ioport_read_hw,
-      .write = parallel_ioport_write_hw },
-    { 4, 1, 2,
-      .read = parallel_ioport_eppdata_read_hw2,
-      .write = parallel_ioport_eppdata_write_hw2 },
-    { 4, 1, 4,
-      .read = parallel_ioport_eppdata_read_hw4,
-      .write = parallel_ioport_eppdata_write_hw4 },
-    { 0x400, 8, 1,
-      .read = parallel_ioport_ecp_read,
-      .write = parallel_ioport_ecp_write },
-    PORTIO_END_OF_LIST(),
-};
-
-static const MemoryRegionPortio isa_parallel_portio_sw_list[] = {
-    { 0, 8, 1,
-      .read = parallel_ioport_read_sw,
-      .write = parallel_ioport_write_sw },
-    PORTIO_END_OF_LIST(),
-};
-
-static int parallel_isa_initfn(ISADevice *dev)
-{
-    static int index;
-    ISAParallelState *isa = DO_UPCAST(ISAParallelState, dev, dev);
-    ParallelState *s = &isa->state;
-    int base;
-    uint8_t dummy;
-
-    if (!s->chr) {
-        fprintf(stderr, "Can't create parallel device, empty char device\n");
-        exit(1);
-    }
-
-    if (isa->index == -1)
-        isa->index = index;
-    if (isa->index >= MAX_PARALLEL_PORTS)
-        return -1;
-    if (isa->iobase == -1)
-        isa->iobase = isa_parallel_io[isa->index];
-    index++;
-
-    base = isa->iobase;
-    isa_init_irq(dev, &s->irq, isa->isairq);
-    qemu_register_reset(parallel_reset, s);
-
-    if (qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_PP_READ_STATUS, &dummy) == 0) {
-        s->hw_driver = 1;
-        s->status = dummy;
-    }
-
-    isa_register_portio_list(dev, base,
-                             (s->hw_driver
-                              ? &isa_parallel_portio_hw_list[0]
-                              : &isa_parallel_portio_sw_list[0]),
-                             s, "parallel");
-    return 0;
-}
-
-/* Memory mapped interface */
-static uint32_t parallel_mm_readb (void *opaque, hwaddr addr)
-{
-    ParallelState *s = opaque;
-
-    return parallel_ioport_read_sw(s, addr >> s->it_shift) & 0xFF;
-}
-
-static void parallel_mm_writeb (void *opaque,
-                                hwaddr addr, uint32_t value)
-{
-    ParallelState *s = opaque;
-
-    parallel_ioport_write_sw(s, addr >> s->it_shift, value & 0xFF);
-}
-
-static uint32_t parallel_mm_readw (void *opaque, hwaddr addr)
-{
-    ParallelState *s = opaque;
-
-    return parallel_ioport_read_sw(s, addr >> s->it_shift) & 0xFFFF;
-}
-
-static void parallel_mm_writew (void *opaque,
-                                hwaddr addr, uint32_t value)
-{
-    ParallelState *s = opaque;
-
-    parallel_ioport_write_sw(s, addr >> s->it_shift, value & 0xFFFF);
-}
-
-static uint32_t parallel_mm_readl (void *opaque, hwaddr addr)
-{
-    ParallelState *s = opaque;
-
-    return parallel_ioport_read_sw(s, addr >> s->it_shift);
-}
-
-static void parallel_mm_writel (void *opaque,
-                                hwaddr addr, uint32_t value)
-{
-    ParallelState *s = opaque;
-
-    parallel_ioport_write_sw(s, addr >> s->it_shift, value);
-}
-
-static const MemoryRegionOps parallel_mm_ops = {
-    .old_mmio = {
-        .read = { parallel_mm_readb, parallel_mm_readw, parallel_mm_readl },
-        .write = { parallel_mm_writeb, parallel_mm_writew, parallel_mm_writel },
-    },
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-/* If fd is zero, it means that the parallel device uses the console */
-bool parallel_mm_init(MemoryRegion *address_space,
-                      hwaddr base, int it_shift, qemu_irq irq,
-                      CharDriverState *chr)
-{
-    ParallelState *s;
-
-    s = g_malloc0(sizeof(ParallelState));
-    s->irq = irq;
-    s->chr = chr;
-    s->it_shift = it_shift;
-    qemu_register_reset(parallel_reset, s);
-
-    memory_region_init_io(&s->iomem, &parallel_mm_ops, s,
-                          "parallel", 8 << it_shift);
-    memory_region_add_subregion(address_space, base, &s->iomem);
-    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 const 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_types(void)
-{
-    type_register_static(&parallel_isa_info);
-}
-
-type_init(parallel_register_types)
diff --git a/hw/pc-testdev.c b/hw/pc-testdev.c
deleted file mode 100644 (file)
index 8236bce..0000000
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * QEMU x86 ISA testdev
- *
- * Copyright (c) 2012 Avi Kivity, Gerd Hoffmann, Marcelo Tosatti
- *
- * 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.
- */
-
-/*
- * This device is used to test KVM features specific to the x86 port, such
- * as emulation, power management, interrupt routing, among others. It's meant
- * to be used like:
- *
- * qemu-system-x86_64 -device pc-testdev -serial stdio \
- * -device isa-debug-exit,iobase=0xf4,iosize=0x4 \
- * -kernel /home/lmr/Code/virt-test.git/kvm/unittests/msr.flat
- *
- * Where msr.flat is one of the KVM unittests, present on a separate repo,
- * git://git.kernel.org/pub/scm/virt/kvm/kvm-unit-tests.git
-*/
-
-#include "config-host.h"
-#if defined(CONFIG_POSIX)
-#include <sys/mman.h>
-#endif
-#include "hw/hw.h"
-#include "hw/qdev.h"
-#include "hw/isa.h"
-
-#define IOMEM_LEN    0x10000
-
-typedef struct PCTestdev {
-    ISADevice parent_obj;
-
-    MemoryRegion ioport;
-    MemoryRegion flush;
-    MemoryRegion irq;
-    MemoryRegion iomem;
-    uint32_t ioport_data;
-    char iomem_buf[IOMEM_LEN];
-} PCTestdev;
-
-#define TYPE_TESTDEV "pc-testdev"
-#define TESTDEV(obj) \
-     OBJECT_CHECK(PCTestdev, (obj), TYPE_TESTDEV)
-
-static void test_irq_line(void *opaque, hwaddr addr, uint64_t data,
-                          unsigned len)
-{
-    PCTestdev *dev = opaque;
-    ISADevice *isa = ISA_DEVICE(dev);
-
-    qemu_set_irq(isa_get_irq(isa, addr), !!data);
-}
-
-static const MemoryRegionOps test_irq_ops = {
-    .write = test_irq_line,
-    .valid.min_access_size = 1,
-    .valid.max_access_size = 1,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static void test_ioport_write(void *opaque, hwaddr addr, uint64_t data,
-                              unsigned len)
-{
-    PCTestdev *dev = opaque;
-    dev->ioport_data = data;
-}
-
-static uint64_t test_ioport_read(void *opaque, hwaddr addr, unsigned len)
-{
-    PCTestdev *dev = opaque;
-    return dev->ioport_data;
-}
-
-static const MemoryRegionOps test_ioport_ops = {
-    .read = test_ioport_read,
-    .write = test_ioport_write,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static void test_flush_page(void *opaque, hwaddr addr, uint64_t data,
-                            unsigned len)
-{
-    hwaddr page = 4096;
-    void *a = cpu_physical_memory_map(data & ~0xffful, &page, 0);
-
-    /* We might not be able to get the full page, only mprotect what we actually
-       have mapped */
-#if defined(CONFIG_POSIX)
-    mprotect(a, page, PROT_NONE);
-    mprotect(a, page, PROT_READ|PROT_WRITE);
-#endif
-    cpu_physical_memory_unmap(a, page, 0, 0);
-}
-
-static const MemoryRegionOps test_flush_ops = {
-    .write = test_flush_page,
-    .valid.min_access_size = 4,
-    .valid.max_access_size = 4,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static uint64_t test_iomem_read(void *opaque, hwaddr addr, unsigned len)
-{
-    PCTestdev *dev = opaque;
-    uint64_t ret = 0;
-    memcpy(&ret, &dev->iomem_buf[addr], len);
-    ret = le64_to_cpu(ret);
-
-    return ret;
-}
-
-static void test_iomem_write(void *opaque, hwaddr addr, uint64_t val,
-                             unsigned len)
-{
-    PCTestdev *dev = opaque;
-    val = cpu_to_le64(val);
-    memcpy(&dev->iomem_buf[addr], &val, len);
-    dev->iomem_buf[addr] = val;
-}
-
-static const MemoryRegionOps test_iomem_ops = {
-    .read = test_iomem_read,
-    .write = test_iomem_write,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static int init_test_device(ISADevice *isa)
-{
-    PCTestdev *dev = TESTDEV(isa);
-    MemoryRegion *mem = isa_address_space(isa);
-    MemoryRegion *io = isa_address_space_io(isa);
-
-    memory_region_init_io(&dev->ioport, &test_ioport_ops, dev,
-                          "pc-testdev-ioport", 4);
-    memory_region_init_io(&dev->flush, &test_flush_ops, dev,
-                          "pc-testdev-flush-page", 4);
-    memory_region_init_io(&dev->irq, &test_irq_ops, dev,
-                          "pc-testdev-irq-line", 24);
-    memory_region_init_io(&dev->iomem, &test_iomem_ops, dev,
-                          "pc-testdev-iomem", IOMEM_LEN);
-
-    memory_region_add_subregion(io,  0xe0,       &dev->ioport);
-    memory_region_add_subregion(io,  0xe4,       &dev->flush);
-    memory_region_add_subregion(io,  0x2000,     &dev->irq);
-    memory_region_add_subregion(mem, 0xff000000, &dev->iomem);
-
-    return 0;
-}
-
-static void testdev_class_init(ObjectClass *klass, void *data)
-{
-    ISADeviceClass *k = ISA_DEVICE_CLASS(klass);
-
-    k->init = init_test_device;
-}
-
-static const TypeInfo testdev_info = {
-    .name           = TYPE_TESTDEV,
-    .parent         = TYPE_ISA_DEVICE,
-    .instance_size  = sizeof(PCTestdev),
-    .class_init     = testdev_class_init,
-};
-
-static void testdev_register_types(void)
-{
-    type_register_static(&testdev_info);
-}
-
-type_init(testdev_register_types)
diff --git a/hw/pc.h b/hw/pc.h
deleted file mode 100644 (file)
index 55964ce..0000000
--- a/hw/pc.h
+++ /dev/null
@@ -1,246 +0,0 @@
-#ifndef HW_PC_H
-#define HW_PC_H
-
-#include "qemu-common.h"
-#include "exec/memory.h"
-#include "exec/ioport.h"
-#include "hw/isa.h"
-#include "hw/fdc.h"
-#include "net/net.h"
-#include "exec/memory.h"
-#include "hw/ioapic.h"
-
-/* PC-style peripherals (also used by other machines).  */
-
-/* parallel.c */
-static inline bool parallel_init(ISABus *bus, int index, CharDriverState *chr)
-{
-    ISADevice *dev;
-
-    dev = isa_try_create(bus, "isa-parallel");
-    if (!dev) {
-        return false;
-    }
-    qdev_prop_set_uint32(&dev->qdev, "index", index);
-    qdev_prop_set_chr(&dev->qdev, "chardev", chr);
-    if (qdev_init(&dev->qdev) < 0) {
-        return false;
-    }
-    return true;
-}
-
-bool parallel_mm_init(MemoryRegion *address_space,
-                      hwaddr base, int it_shift, qemu_irq irq,
-                      CharDriverState *chr);
-
-/* i8259.c */
-
-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, const QDict *qdict);
-void irq_info(Monitor *mon, const QDict *qdict);
-
-/* Global System Interrupts */
-
-#define GSI_NUM_PINS IOAPIC_NUM_PINS
-
-typedef struct GSIState {
-    qemu_irq i8259_irq[ISA_NUM_IRQS];
-    qemu_irq ioapic_irq[IOAPIC_NUM_PINS];
-} GSIState;
-
-void gsi_handler(void *opaque, int n, int level);
-
-/* vmport.c */
-static inline void vmport_init(ISABus *bus)
-{
-    isa_create_simple(bus, "vmport");
-}
-void vmport_register(unsigned char command, IOPortReadFunc *func, void *opaque);
-void vmmouse_get_data(uint32_t *data);
-void vmmouse_set_data(const uint32_t *data);
-
-/* pckbd.c */
-
-void i8042_init(qemu_irq kbd_irq, qemu_irq mouse_irq, uint32_t io_base);
-void i8042_mm_init(qemu_irq kbd_irq, qemu_irq mouse_irq,
-                   MemoryRegion *region, ram_addr_t size,
-                   hwaddr mask);
-void i8042_isa_mouse_fake_event(void *opaque);
-void i8042_setup_a20_line(ISADevice *dev, qemu_irq *a20_out);
-
-/* pc.c */
-extern int fd_bootchk;
-
-void pc_register_ferr_irq(qemu_irq irq);
-void pc_acpi_smi_interrupt(void *opaque, int irq, int level);
-
-void pc_cpus_init(const char *cpu_model);
-void pc_acpi_init(const char *default_dsdt);
-void *pc_memory_init(MemoryRegion *system_memory,
-                    const char *kernel_filename,
-                    const char *kernel_cmdline,
-                    const char *initrd_filename,
-                    ram_addr_t below_4g_mem_size,
-                    ram_addr_t above_4g_mem_size,
-                    MemoryRegion *rom_memory,
-                    MemoryRegion **ram_memory);
-qemu_irq *pc_allocate_cpu_irq(void);
-DeviceState *pc_vga_init(ISABus *isa_bus, PCIBus *pci_bus);
-void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi,
-                          ISADevice **rtc_state,
-                          ISADevice **floppy,
-                          bool no_vmport);
-void pc_init_ne2k_isa(ISABus *bus, NICInfo *nd);
-void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size,
-                  const char *boot_device,
-                  ISADevice *floppy, BusState *ide0, BusState *ide1,
-                  ISADevice *s);
-void pc_nic_init(ISABus *isa_bus, PCIBus *pci_bus);
-void pc_pci_device_init(PCIBus *pci_bus);
-
-typedef void (*cpu_set_smm_t)(int smm, void *arg);
-void cpu_smm_register(cpu_set_smm_t callback, void *arg);
-
-void ioapic_init_gsi(GSIState *gsi_state, const char *parent_name);
-
-/* acpi.c */
-extern int acpi_enabled;
-extern char unsigned *acpi_tables;
-extern size_t acpi_tables_len;
-
-void acpi_bios_init(void);
-void acpi_table_add(const QemuOpts *opts, Error **errp);
-
-/* acpi_piix.c */
-
-i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
-                       qemu_irq sci_irq, qemu_irq smi_irq,
-                       int kvm_enabled, void *fw_cfg);
-void piix4_smbus_register_device(SMBusDevice *dev, uint8_t addr);
-
-/* hpet.c */
-extern int no_hpet;
-
-/* piix_pci.c */
-struct PCII440FXState;
-typedef struct PCII440FXState PCII440FXState;
-
-PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix_devfn,
-                    ISABus **isa_bus, qemu_irq *pic,
-                    MemoryRegion *address_space_mem,
-                    MemoryRegion *address_space_io,
-                    ram_addr_t ram_size,
-                    hwaddr pci_hole_start,
-                    hwaddr pci_hole_size,
-                    hwaddr pci_hole64_start,
-                    hwaddr pci_hole64_size,
-                    MemoryRegion *pci_memory,
-                    MemoryRegion *ram_memory);
-
-/* piix4.c */
-extern PCIDevice *piix4_dev;
-int piix4_init(PCIBus *bus, ISABus **isa_bus, int devfn);
-
-/* vga.c */
-enum vga_retrace_method {
-    VGA_RETRACE_DUMB,
-    VGA_RETRACE_PRECISE
-};
-
-extern enum vga_retrace_method vga_retrace_method;
-
-int isa_vga_mm_init(hwaddr vram_base,
-                    hwaddr ctrl_base, int it_shift,
-                    MemoryRegion *address_space);
-
-/* ne2000.c */
-static inline bool isa_ne2000_init(ISABus *bus, int base, int irq, NICInfo *nd)
-{
-    ISADevice *dev;
-
-    qemu_check_nic_model(nd, "ne2k_isa");
-
-    dev = isa_try_create(bus, "ne2k_isa");
-    if (!dev) {
-        return false;
-    }
-    qdev_prop_set_uint32(&dev->qdev, "iobase", base);
-    qdev_prop_set_uint32(&dev->qdev, "irq",    irq);
-    qdev_set_nic_properties(&dev->qdev, nd);
-    qdev_init_nofail(&dev->qdev);
-    return true;
-}
-
-/* pc_sysfw.c */
-void pc_system_firmware_init(MemoryRegion *rom_memory);
-
-/* e820 types */
-#define E820_RAM        1
-#define E820_RESERVED   2
-#define E820_ACPI       3
-#define E820_NVS        4
-#define E820_UNUSABLE   5
-
-int e820_add_entry(uint64_t, uint64_t, uint32_t);
-
-#define PC_COMPAT_1_4 \
-        {\
-            .driver   = "scsi-hd",\
-            .property = "discard_granularity",\
-            .value    = stringify(0),\
-       },{\
-            .driver   = "scsi-cd",\
-            .property = "discard_granularity",\
-            .value    = stringify(0),\
-       },{\
-            .driver   = "scsi-disk",\
-            .property = "discard_granularity",\
-            .value    = stringify(0),\
-       },{\
-            .driver   = "ide-hd",\
-            .property = "discard_granularity",\
-            .value    = stringify(0),\
-       },{\
-            .driver   = "ide-cd",\
-            .property = "discard_granularity",\
-            .value    = stringify(0),\
-       },{\
-            .driver   = "ide-drive",\
-            .property = "discard_granularity",\
-            .value    = stringify(0),\
-        },{\
-            .driver   = "virtio-blk-pci",\
-            .property = "discard_granularity",\
-            .value    = stringify(0),\
-       },{\
-            .driver   = "virtio-serial-pci",\
-            .property = "vectors",\
-            /* DEV_NVECTORS_UNSPECIFIED as a uint32_t string */\
-            .value    = stringify(0xFFFFFFFF),\
-        },{\
-            .driver   = "e1000",\
-            .property = "romfile",\
-            .value    = "pxe-e1000.rom",\
-        },{\
-            .driver   = "ne2k_pci",\
-            .property = "romfile",\
-            .value    = "pxe-ne2k_pci.rom",\
-        },{\
-            .driver   = "pcnet",\
-            .property = "romfile",\
-            .value    = "pxe-pcnet.rom",\
-        },{\
-            .driver   = "rtl8139",\
-            .property = "romfile",\
-            .value    = "pxe-rtl8139.rom",\
-        },{\
-            .driver   = "virtio-net-pci",\
-            .property = "romfile",\
-            .value    = "pxe-virtio.rom",\
-        }
-
-#endif
diff --git a/hw/pc87312.c b/hw/pc87312.c
deleted file mode 100644 (file)
index c4e4c62..0000000
+++ /dev/null
@@ -1,402 +0,0 @@
-/*
- * QEMU National Semiconductor PC87312 (Super I/O)
- *
- * Copyright (c) 2010-2012 Herve Poussineau
- * Copyright (c) 2011-2012 Andreas Färber
- *
- * 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 "hw/pc87312.h"
-#include "qemu/error-report.h"
-#include "sysemu/blockdev.h"
-#include "sysemu/sysemu.h"
-#include "char/char.h"
-#include "trace.h"
-
-
-#define REG_FER 0
-#define REG_FAR 1
-#define REG_PTR 2
-
-#define FER_PARALLEL_EN   0x01
-#define FER_UART1_EN      0x02
-#define FER_UART2_EN      0x04
-#define FER_FDC_EN        0x08
-#define FER_FDC_4         0x10
-#define FER_FDC_ADDR      0x20
-#define FER_IDE_EN        0x40
-#define FER_IDE_ADDR      0x80
-
-#define FAR_PARALLEL_ADDR 0x03
-#define FAR_UART1_ADDR    0x0C
-#define FAR_UART2_ADDR    0x30
-#define FAR_UART_3_4      0xC0
-
-#define PTR_POWER_DOWN    0x01
-#define PTR_CLOCK_DOWN    0x02
-#define PTR_PWDN          0x04
-#define PTR_IRQ_5_7       0x08
-#define PTR_UART1_TEST    0x10
-#define PTR_UART2_TEST    0x20
-#define PTR_LOCK_CONF     0x40
-#define PTR_EPP_MODE      0x80
-
-
-/* Parallel port */
-
-static inline bool is_parallel_enabled(PC87312State *s)
-{
-    return s->regs[REG_FER] & FER_PARALLEL_EN;
-}
-
-static const uint32_t parallel_base[] = { 0x378, 0x3bc, 0x278, 0x00 };
-
-static inline uint32_t get_parallel_iobase(PC87312State *s)
-{
-    return parallel_base[s->regs[REG_FAR] & FAR_PARALLEL_ADDR];
-}
-
-static const uint32_t parallel_irq[] = { 5, 7, 5, 0 };
-
-static inline uint32_t get_parallel_irq(PC87312State *s)
-{
-    int idx;
-    idx = (s->regs[REG_FAR] & FAR_PARALLEL_ADDR);
-    if (idx == 0) {
-        return (s->regs[REG_PTR] & PTR_IRQ_5_7) ? 7 : 5;
-    } else {
-        return parallel_irq[idx];
-    }
-}
-
-static inline bool is_parallel_epp(PC87312State *s)
-{
-    return s->regs[REG_PTR] & PTR_EPP_MODE;
-}
-
-
-/* UARTs */
-
-static const uint32_t uart_base[2][4] = {
-    { 0x3e8, 0x338, 0x2e8, 0x220 },
-    { 0x2e8, 0x238, 0x2e0, 0x228 }
-};
-
-static inline uint32_t get_uart_iobase(PC87312State *s, int i)
-{
-    int idx;
-    idx = (s->regs[REG_FAR] >> (2 * i + 2)) & 0x3;
-    if (idx == 0) {
-        return 0x3f8;
-    } else if (idx == 1) {
-        return 0x2f8;
-    } else {
-        return uart_base[idx & 1][(s->regs[REG_FAR] & FAR_UART_3_4) >> 6];
-    }
-}
-
-static inline uint32_t get_uart_irq(PC87312State *s, int i)
-{
-    int idx;
-    idx = (s->regs[REG_FAR] >> (2 * i + 2)) & 0x3;
-    return (idx & 1) ? 3 : 4;
-}
-
-static inline bool is_uart_enabled(PC87312State *s, int i)
-{
-    return s->regs[REG_FER] & (FER_UART1_EN << i);
-}
-
-
-/* Floppy controller */
-
-static inline bool is_fdc_enabled(PC87312State *s)
-{
-    return s->regs[REG_FER] & FER_FDC_EN;
-}
-
-static inline uint32_t get_fdc_iobase(PC87312State *s)
-{
-    return (s->regs[REG_FER] & FER_FDC_ADDR) ? 0x370 : 0x3f0;
-}
-
-
-/* IDE controller */
-
-static inline bool is_ide_enabled(PC87312State *s)
-{
-    return s->regs[REG_FER] & FER_IDE_EN;
-}
-
-static inline uint32_t get_ide_iobase(PC87312State *s)
-{
-    return (s->regs[REG_FER] & FER_IDE_ADDR) ? 0x170 : 0x1f0;
-}
-
-
-static void reconfigure_devices(PC87312State *s)
-{
-    error_report("pc87312: unsupported device reconfiguration (%02x %02x %02x)",
-                 s->regs[REG_FER], s->regs[REG_FAR], s->regs[REG_PTR]);
-}
-
-static void pc87312_soft_reset(PC87312State *s)
-{
-    static const uint8_t fer_init[] = {
-        0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4b, 0x4b,
-        0x4b, 0x4b, 0x4b, 0x4b, 0x0f, 0x0f, 0x0f, 0x0f,
-        0x49, 0x49, 0x49, 0x49, 0x07, 0x07, 0x07, 0x07,
-        0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x08, 0x00,
-    };
-    static const uint8_t far_init[] = {
-        0x10, 0x11, 0x11, 0x39, 0x24, 0x38, 0x00, 0x01,
-        0x01, 0x09, 0x08, 0x08, 0x10, 0x11, 0x39, 0x24,
-        0x00, 0x01, 0x01, 0x00, 0x10, 0x11, 0x39, 0x24,
-        0x10, 0x11, 0x11, 0x39, 0x24, 0x38, 0x10, 0x10,
-    };
-    static const uint8_t ptr_init[] = {
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
-    };
-
-    s->read_id_step = 0;
-    s->selected_index = REG_FER;
-
-    s->regs[REG_FER] = fer_init[s->config & 0x1f];
-    s->regs[REG_FAR] = far_init[s->config & 0x1f];
-    s->regs[REG_PTR] = ptr_init[s->config & 0x1f];
-}
-
-static void pc87312_hard_reset(PC87312State *s)
-{
-    pc87312_soft_reset(s);
-}
-
-static void pc87312_io_write(void *opaque, hwaddr addr, uint64_t val,
-                             unsigned int size)
-{
-    PC87312State *s = opaque;
-
-    trace_pc87312_io_write(addr, val);
-
-    if ((addr & 1) == 0) {
-        /* Index register */
-        s->read_id_step = 2;
-        s->selected_index = val;
-    } else {
-        /* Data register */
-        if (s->selected_index < 3) {
-            s->regs[s->selected_index] = val;
-            reconfigure_devices(s);
-        }
-    }
-}
-
-static uint64_t pc87312_io_read(void *opaque, hwaddr addr, unsigned int size)
-{
-    PC87312State *s = opaque;
-    uint32_t val;
-
-    if ((addr & 1) == 0) {
-        /* Index register */
-        if (s->read_id_step++ == 0) {
-            val = 0x88;
-        } else if (s->read_id_step++ == 1) {
-            val = 0;
-        } else {
-            val = s->selected_index;
-        }
-    } else {
-        /* Data register */
-        if (s->selected_index < 3) {
-            val = s->regs[s->selected_index];
-        } else {
-            /* Invalid selected index */
-            val = 0;
-        }
-    }
-
-    trace_pc87312_io_read(addr, val);
-    return val;
-}
-
-static const MemoryRegionOps pc87312_io_ops = {
-    .read  = pc87312_io_read,
-    .write = pc87312_io_write,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-    .valid = {
-        .min_access_size = 1,
-        .max_access_size = 1,
-    },
-};
-
-static int pc87312_post_load(void *opaque, int version_id)
-{
-    PC87312State *s = opaque;
-
-    reconfigure_devices(s);
-    return 0;
-}
-
-static void pc87312_reset(DeviceState *d)
-{
-    PC87312State *s = PC87312(d);
-
-    pc87312_soft_reset(s);
-}
-
-static int pc87312_init(ISADevice *dev)
-{
-    PC87312State *s;
-    DeviceState *d;
-    ISADevice *isa;
-    ISABus *bus;
-    CharDriverState *chr;
-    DriveInfo *drive;
-    char name[5];
-    int i;
-
-    s = PC87312(dev);
-    bus = isa_bus_from_device(dev);
-    pc87312_hard_reset(s);
-    isa_register_ioport(dev, &s->io, s->iobase);
-
-    if (is_parallel_enabled(s)) {
-        chr = parallel_hds[0];
-        if (chr == NULL) {
-            chr = qemu_chr_new("par0", "null", NULL);
-        }
-        isa = isa_create(bus, "isa-parallel");
-        d = DEVICE(isa);
-        qdev_prop_set_uint32(d, "index", 0);
-        qdev_prop_set_uint32(d, "iobase", get_parallel_iobase(s));
-        qdev_prop_set_uint32(d, "irq", get_parallel_irq(s));
-        qdev_prop_set_chr(d, "chardev", chr);
-        qdev_init_nofail(d);
-        s->parallel.dev = isa;
-        trace_pc87312_info_parallel(get_parallel_iobase(s),
-                                    get_parallel_irq(s));
-    }
-
-    for (i = 0; i < 2; i++) {
-        if (is_uart_enabled(s, i)) {
-            chr = serial_hds[i];
-            if (chr == NULL) {
-                snprintf(name, sizeof(name), "ser%d", i);
-                chr = qemu_chr_new(name, "null", NULL);
-            }
-            isa = isa_create(bus, "isa-serial");
-            d = DEVICE(isa);
-            qdev_prop_set_uint32(d, "index", i);
-            qdev_prop_set_uint32(d, "iobase", get_uart_iobase(s, i));
-            qdev_prop_set_uint32(d, "irq", get_uart_irq(s, i));
-            qdev_prop_set_chr(d, "chardev", chr);
-            qdev_init_nofail(d);
-            s->uart[i].dev = isa;
-            trace_pc87312_info_serial(i, get_uart_iobase(s, i),
-                                      get_uart_irq(s, i));
-        }
-    }
-
-    if (is_fdc_enabled(s)) {
-        isa = isa_create(bus, "isa-fdc");
-        d = DEVICE(isa);
-        qdev_prop_set_uint32(d, "iobase", get_fdc_iobase(s));
-        qdev_prop_set_uint32(d, "irq", 6);
-        drive = drive_get(IF_FLOPPY, 0, 0);
-        if (drive != NULL) {
-            qdev_prop_set_drive_nofail(d, "driveA", drive->bdrv);
-        }
-        drive = drive_get(IF_FLOPPY, 0, 1);
-        if (drive != NULL) {
-            qdev_prop_set_drive_nofail(d, "driveB", drive->bdrv);
-        }
-        qdev_init_nofail(d);
-        s->fdc.dev = isa;
-        trace_pc87312_info_floppy(get_fdc_iobase(s));
-    }
-
-    if (is_ide_enabled(s)) {
-        isa = isa_create(bus, "isa-ide");
-        d = DEVICE(isa);
-        qdev_prop_set_uint32(d, "iobase", get_ide_iobase(s));
-        qdev_prop_set_uint32(d, "iobase2", get_ide_iobase(s) + 0x206);
-        qdev_prop_set_uint32(d, "irq", 14);
-        qdev_init_nofail(d);
-        s->ide.dev = isa;
-        trace_pc87312_info_ide(get_ide_iobase(s));
-    }
-
-    return 0;
-}
-
-static void pc87312_initfn(Object *obj)
-{
-    PC87312State *s = PC87312(obj);
-
-    memory_region_init_io(&s->io, &pc87312_io_ops, s, "pc87312", 2);
-}
-
-static const VMStateDescription vmstate_pc87312 = {
-    .name = "pc87312",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .post_load = pc87312_post_load,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT8(read_id_step, PC87312State),
-        VMSTATE_UINT8(selected_index, PC87312State),
-        VMSTATE_UINT8_ARRAY(regs, PC87312State, 3),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static Property pc87312_properties[] = {
-    DEFINE_PROP_HEX32("iobase", PC87312State, iobase, 0x398),
-    DEFINE_PROP_UINT8("config", PC87312State, config, 1),
-    DEFINE_PROP_END_OF_LIST()
-};
-
-static void pc87312_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
-
-    ic->init = pc87312_init;
-    dc->reset = pc87312_reset;
-    dc->vmsd = &vmstate_pc87312;
-    dc->props = pc87312_properties;
-}
-
-static const TypeInfo pc87312_type_info = {
-    .name          = TYPE_PC87312,
-    .parent        = TYPE_ISA_DEVICE,
-    .instance_size = sizeof(PC87312State),
-    .instance_init = pc87312_initfn,
-    .class_init    = pc87312_class_init,
-};
-
-static void pc87312_register_types(void)
-{
-    type_register_static(&pc87312_type_info);
-}
-
-type_init(pc87312_register_types)
diff --git a/hw/pc87312.h b/hw/pc87312.h
deleted file mode 100644 (file)
index ad087c7..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * QEMU National Semiconductor PC87312 (Super I/O)
- *
- * Copyright (c) 2010-2012 Herve Poussineau
- * Copyright (c) 2011-2012 Andreas Färber
- *
- * 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_PC87312_H
-#define QEMU_PC87312_H
-
-#include "hw/isa.h"
-
-
-#define TYPE_PC87312 "pc87312"
-#define PC87312(obj) OBJECT_CHECK(PC87312State, (obj), TYPE_PC87312)
-
-typedef struct PC87312State {
-    ISADevice dev;
-
-    uint32_t iobase;
-    uint8_t config; /* initial configuration */
-
-    struct {
-        ISADevice *dev;
-    } parallel;
-
-    struct {
-        ISADevice *dev;
-    } uart[2];
-
-    struct {
-        ISADevice *dev;
-        BlockDriverState *drive[2];
-        uint32_t base;
-    } fdc;
-
-    struct {
-        ISADevice *dev;
-        uint32_t base;
-    } ide;
-
-    MemoryRegion io;
-
-    uint8_t read_id_step;
-    uint8_t selected_index;
-
-    uint8_t regs[3];
-} PC87312State;
-
-
-#endif
diff --git a/hw/pc_sysfw.c b/hw/pc_sysfw.c
deleted file mode 100644 (file)
index 3e01528..0000000
+++ /dev/null
@@ -1,273 +0,0 @@
-/*
- * QEMU PC System Firmware
- *
- * Copyright (c) 2003-2004 Fabrice Bellard
- * Copyright (c) 2011-2012 Intel Corporation
- *
- * 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 "sysemu/blockdev.h"
-#include "qemu/error-report.h"
-#include "hw/sysbus.h"
-#include "hw/hw.h"
-#include "hw/pc.h"
-#include "hw/boards.h"
-#include "hw/loader.h"
-#include "sysemu/sysemu.h"
-#include "hw/flash.h"
-#include "sysemu/kvm.h"
-
-#define BIOS_FILENAME "bios.bin"
-
-typedef struct PcSysFwDevice {
-    SysBusDevice busdev;
-    uint8_t rom_only;
-} PcSysFwDevice;
-
-static void pc_isa_bios_init(MemoryRegion *rom_memory,
-                             MemoryRegion *flash_mem,
-                             int ram_size)
-{
-    int isa_bios_size;
-    MemoryRegion *isa_bios;
-    uint64_t flash_size;
-    void *flash_ptr, *isa_bios_ptr;
-
-    flash_size = memory_region_size(flash_mem);
-
-    /* map the last 128KB of the BIOS in ISA space */
-    isa_bios_size = flash_size;
-    if (isa_bios_size > (128 * 1024)) {
-        isa_bios_size = 128 * 1024;
-    }
-    isa_bios = g_malloc(sizeof(*isa_bios));
-    memory_region_init_ram(isa_bios, "isa-bios", isa_bios_size);
-    vmstate_register_ram_global(isa_bios);
-    memory_region_add_subregion_overlap(rom_memory,
-                                        0x100000 - isa_bios_size,
-                                        isa_bios,
-                                        1);
-
-    /* copy ISA rom image from top of flash memory */
-    flash_ptr = memory_region_get_ram_ptr(flash_mem);
-    isa_bios_ptr = memory_region_get_ram_ptr(isa_bios);
-    memcpy(isa_bios_ptr,
-           ((uint8_t*)flash_ptr) + (flash_size - isa_bios_size),
-           isa_bios_size);
-
-    memory_region_set_readonly(isa_bios, true);
-}
-
-static void pc_fw_add_pflash_drv(void)
-{
-    QemuOpts *opts;
-    QEMUMachine *machine;
-    char *filename;
-
-    if (bios_name == NULL) {
-        bios_name = BIOS_FILENAME;
-    }
-    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
-    if (!filename) {
-        error_report("Can't open BIOS image %s", bios_name);
-        exit(1);
-    }
-
-    opts = drive_add(IF_PFLASH, -1, filename, "readonly=on");
-
-    g_free(filename);
-
-    if (opts == NULL) {
-      return;
-    }
-
-    machine = find_default_machine();
-    if (machine == NULL) {
-      return;
-    }
-
-    if (!drive_init(opts, machine->block_default_type)) {
-        qemu_opts_del(opts);
-    }
-}
-
-static void pc_system_flash_init(MemoryRegion *rom_memory,
-                                 DriveInfo *pflash_drv)
-{
-    BlockDriverState *bdrv;
-    int64_t size;
-    hwaddr phys_addr;
-    int sector_bits, sector_size;
-    pflash_t *system_flash;
-    MemoryRegion *flash_mem;
-
-    bdrv = pflash_drv->bdrv;
-    size = bdrv_getlength(pflash_drv->bdrv);
-    sector_bits = 12;
-    sector_size = 1 << sector_bits;
-
-    if ((size % sector_size) != 0) {
-        fprintf(stderr,
-                "qemu: PC system firmware (pflash) must be a multiple of 0x%x\n",
-                sector_size);
-        exit(1);
-    }
-
-    phys_addr = 0x100000000ULL - size;
-    system_flash = pflash_cfi01_register(phys_addr, NULL, "system.flash", size,
-                                         bdrv, sector_size, size >> sector_bits,
-                                         1, 0x0000, 0x0000, 0x0000, 0x0000, 0);
-    flash_mem = pflash_cfi01_get_memory(system_flash);
-
-    pc_isa_bios_init(rom_memory, flash_mem, size);
-}
-
-static void old_pc_system_rom_init(MemoryRegion *rom_memory)
-{
-    char *filename;
-    MemoryRegion *bios, *isa_bios;
-    int bios_size, isa_bios_size;
-    int ret;
-
-    /* BIOS load */
-    if (bios_name == NULL) {
-        bios_name = BIOS_FILENAME;
-    }
-    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
-    if (filename) {
-        bios_size = get_image_size(filename);
-    } else {
-        bios_size = -1;
-    }
-    if (bios_size <= 0 ||
-        (bios_size % 65536) != 0) {
-        goto bios_error;
-    }
-    bios = g_malloc(sizeof(*bios));
-    memory_region_init_ram(bios, "pc.bios", bios_size);
-    vmstate_register_ram_global(bios);
-    memory_region_set_readonly(bios, true);
-    ret = rom_add_file_fixed(bios_name, (uint32_t)(-bios_size), -1);
-    if (ret != 0) {
-    bios_error:
-        fprintf(stderr, "qemu: could not load PC BIOS '%s'\n", bios_name);
-        exit(1);
-    }
-    if (filename) {
-        g_free(filename);
-    }
-
-    /* map the last 128KB of the BIOS in ISA space */
-    isa_bios_size = bios_size;
-    if (isa_bios_size > (128 * 1024)) {
-        isa_bios_size = 128 * 1024;
-    }
-    isa_bios = g_malloc(sizeof(*isa_bios));
-    memory_region_init_alias(isa_bios, "isa-bios", bios,
-                             bios_size - isa_bios_size, isa_bios_size);
-    memory_region_add_subregion_overlap(rom_memory,
-                                        0x100000 - isa_bios_size,
-                                        isa_bios,
-                                        1);
-    memory_region_set_readonly(isa_bios, true);
-
-    /* map all the bios at the top of memory */
-    memory_region_add_subregion(rom_memory,
-                                (uint32_t)(-bios_size),
-                                bios);
-}
-
-void pc_system_firmware_init(MemoryRegion *rom_memory)
-{
-    DriveInfo *pflash_drv;
-    PcSysFwDevice *sysfw_dev;
-
-    sysfw_dev = (PcSysFwDevice*) qdev_create(NULL, "pc-sysfw");
-
-    qdev_init_nofail(DEVICE(sysfw_dev));
-
-    if (sysfw_dev->rom_only) {
-        old_pc_system_rom_init(rom_memory);
-        return;
-    }
-
-    pflash_drv = drive_get(IF_PFLASH, 0, 0);
-
-    /* Currently KVM cannot execute from device memory.
-       Use old rom based firmware initialization for KVM. */
-    if (kvm_enabled()) {
-        if (pflash_drv != NULL) {
-            fprintf(stderr, "qemu: pflash cannot be used with kvm enabled\n");
-            exit(1);
-        } else {
-            sysfw_dev->rom_only = 1;
-            old_pc_system_rom_init(rom_memory);
-            return;
-        }
-    }
-
-    /* If a pflash drive is not found, then create one using
-       the bios filename. */
-    if (pflash_drv == NULL) {
-        pc_fw_add_pflash_drv();
-        pflash_drv = drive_get(IF_PFLASH, 0, 0);
-    }
-
-    if (pflash_drv != NULL) {
-        pc_system_flash_init(rom_memory, pflash_drv);
-    } else {
-        fprintf(stderr, "qemu: PC system firmware (pflash) not available\n");
-        exit(1);
-    }
-}
-
-static Property pcsysfw_properties[] = {
-    DEFINE_PROP_UINT8("rom_only", PcSysFwDevice, rom_only, 0),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static int pcsysfw_init(DeviceState *dev)
-{
-    return 0;
-}
-
-static void pcsysfw_class_init (ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS (klass);
-
-    dc->desc = "PC System Firmware";
-    dc->init = pcsysfw_init;
-    dc->props = pcsysfw_properties;
-}
-
-static const TypeInfo pcsysfw_info = {
-    .name          = "pc-sysfw",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof (PcSysFwDevice),
-    .class_init    = pcsysfw_class_init,
-};
-
-static void pcsysfw_register (void)
-{
-    type_register_static (&pcsysfw_info);
-}
-
-type_init (pcsysfw_register);
-
diff --git a/hw/pci-bridge/Makefile.objs b/hw/pci-bridge/Makefile.objs
new file mode 100644 (file)
index 0000000..5dd92d2
--- /dev/null
@@ -0,0 +1,3 @@
+common-obj-y += pci_bridge_dev.o
+common-obj-y += ioh3420.o xio3130_upstream.o xio3130_downstream.o
+common-obj-y += i82801b11.o
diff --git a/hw/pci-bridge/i82801b11.c b/hw/pci-bridge/i82801b11.c
new file mode 100644 (file)
index 0000000..5807a92
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2006 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.
+ */
+/*
+ * QEMU i82801b11 dmi-to-pci Bridge Emulation
+ *
+ *  Copyright (c) 2009, 2010, 2011
+ *                Isaku Yamahata <yamahata at valinux co jp>
+ *                VA Linux Systems Japan K.K.
+ *  Copyright (C) 2012 Jason Baron <jbaron@redhat.com>
+ *
+ * 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/pci/pci.h"
+#include "hw/i386/ich9.h"
+
+
+/*****************************************************************************/
+/* ICH9 DMI-to-PCI bridge */
+#define I82801ba_SSVID_OFFSET   0x50
+#define I82801ba_SSVID_SVID     0
+#define I82801ba_SSVID_SSID     0
+
+typedef struct I82801b11Bridge {
+    PCIBridge br;
+} I82801b11Bridge;
+
+static int i82801b11_bridge_initfn(PCIDevice *d)
+{
+    int rc;
+
+    rc = pci_bridge_initfn(d, TYPE_PCI_BUS);
+    if (rc < 0) {
+        return rc;
+    }
+
+    rc = pci_bridge_ssvid_init(d, I82801ba_SSVID_OFFSET,
+                               I82801ba_SSVID_SVID, I82801ba_SSVID_SSID);
+    if (rc < 0) {
+        goto err_bridge;
+    }
+    pci_config_set_prog_interface(d->config, PCI_CLASS_BRDIGE_PCI_INF_SUB);
+    return 0;
+
+err_bridge:
+    pci_bridge_exitfn(d);
+
+    return rc;
+}
+
+static void i82801b11_bridge_class_init(ObjectClass *klass, void *data)
+{
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->is_bridge = 1;
+    k->vendor_id = PCI_VENDOR_ID_INTEL;
+    k->device_id = PCI_DEVICE_ID_INTEL_82801BA_11;
+    k->revision = ICH9_D2P_A2_REVISION;
+    k->init = i82801b11_bridge_initfn;
+}
+
+static const TypeInfo i82801b11_bridge_info = {
+    .name          = "i82801b11-bridge",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(I82801b11Bridge),
+    .class_init    = i82801b11_bridge_class_init,
+};
+
+PCIBus *ich9_d2pbr_init(PCIBus *bus, int devfn, int sec_bus)
+{
+    PCIDevice *d;
+    PCIBridge *br;
+    char buf[16];
+    DeviceState *qdev;
+
+    d = pci_create_multifunction(bus, devfn, true, "i82801b11-bridge");
+    if (!d) {
+        return NULL;
+    }
+    br = DO_UPCAST(PCIBridge, dev, d);
+    qdev = &br->dev.qdev;
+
+    snprintf(buf, sizeof(buf), "pci.%d", sec_bus);
+    pci_bridge_map_irq(br, buf, pci_swizzle_map_irq_fn);
+    qdev_init_nofail(qdev);
+
+    return pci_bridge_get_sec_bus(br);
+}
+
+static void d2pbr_register(void)
+{
+    type_register_static(&i82801b11_bridge_info);
+}
+
+type_init(d2pbr_register);
diff --git a/hw/pci-bridge/ioh3420.c b/hw/pci-bridge/ioh3420.c
new file mode 100644 (file)
index 0000000..bb541eb
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+ * ioh3420.c
+ * Intel X58 north bridge IOH
+ * PCI Express root port device id 3420
+ *
+ * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
+ *                    VA Linux Systems Japan K.K.
+ *
+ * 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 "hw/pci/pci_ids.h"
+#include "hw/pci/msi.h"
+#include "hw/pci/pcie.h"
+#include "ioh3420.h"
+
+#define PCI_DEVICE_ID_IOH_EPORT         0x3420  /* D0:F0 express mode */
+#define PCI_DEVICE_ID_IOH_REV           0x2
+#define IOH_EP_SSVID_OFFSET             0x40
+#define IOH_EP_SSVID_SVID               PCI_VENDOR_ID_INTEL
+#define IOH_EP_SSVID_SSID               0
+#define IOH_EP_MSI_OFFSET               0x60
+#define IOH_EP_MSI_SUPPORTED_FLAGS      PCI_MSI_FLAGS_MASKBIT
+#define IOH_EP_MSI_NR_VECTOR            2
+#define IOH_EP_EXP_OFFSET               0x90
+#define IOH_EP_AER_OFFSET               0x100
+
+/*
+ * If two MSI vector are allocated, Advanced Error Interrupt Message Number
+ * is 1. otherwise 0.
+ * 17.12.5.10 RPERRSTS,  32:27 bit Advanced Error Interrupt Message Number.
+ */
+static uint8_t ioh3420_aer_vector(const PCIDevice *d)
+{
+    switch (msi_nr_vectors_allocated(d)) {
+    case 1:
+        return 0;
+    case 2:
+        return 1;
+    case 4:
+    case 8:
+    case 16:
+    case 32:
+    default:
+        break;
+    }
+    abort();
+    return 0;
+}
+
+static void ioh3420_aer_vector_update(PCIDevice *d)
+{
+    pcie_aer_root_set_vector(d, ioh3420_aer_vector(d));
+}
+
+static void ioh3420_write_config(PCIDevice *d,
+                                   uint32_t address, uint32_t val, int len)
+{
+    uint32_t root_cmd =
+        pci_get_long(d->config + d->exp.aer_cap + PCI_ERR_ROOT_COMMAND);
+
+    pci_bridge_write_config(d, address, val, len);
+    ioh3420_aer_vector_update(d);
+    pcie_cap_slot_write_config(d, address, val, len);
+    pcie_aer_write_config(d, address, val, len);
+    pcie_aer_root_write_config(d, address, val, len, root_cmd);
+}
+
+static void ioh3420_reset(DeviceState *qdev)
+{
+    PCIDevice *d = PCI_DEVICE(qdev);
+
+    ioh3420_aer_vector_update(d);
+    pcie_cap_root_reset(d);
+    pcie_cap_deverr_reset(d);
+    pcie_cap_slot_reset(d);
+    pcie_aer_root_reset(d);
+    pci_bridge_reset(qdev);
+    pci_bridge_disable_base_limit(d);
+}
+
+static int ioh3420_initfn(PCIDevice *d)
+{
+    PCIBridge* br = DO_UPCAST(PCIBridge, dev, d);
+    PCIEPort *p = DO_UPCAST(PCIEPort, br, br);
+    PCIESlot *s = DO_UPCAST(PCIESlot, port, p);
+    int rc;
+
+    rc = pci_bridge_initfn(d, TYPE_PCIE_BUS);
+    if (rc < 0) {
+        return rc;
+    }
+
+    pcie_port_init_reg(d);
+
+    rc = pci_bridge_ssvid_init(d, IOH_EP_SSVID_OFFSET,
+                               IOH_EP_SSVID_SVID, IOH_EP_SSVID_SSID);
+    if (rc < 0) {
+        goto err_bridge;
+    }
+    rc = msi_init(d, IOH_EP_MSI_OFFSET, IOH_EP_MSI_NR_VECTOR,
+                  IOH_EP_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_64BIT,
+                  IOH_EP_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_MASKBIT);
+    if (rc < 0) {
+        goto err_bridge;
+    }
+    rc = pcie_cap_init(d, IOH_EP_EXP_OFFSET, PCI_EXP_TYPE_ROOT_PORT, p->port);
+    if (rc < 0) {
+        goto err_msi;
+    }
+    pcie_cap_deverr_init(d);
+    pcie_cap_slot_init(d, s->slot);
+    pcie_chassis_create(s->chassis);
+    rc = pcie_chassis_add_slot(s);
+    if (rc < 0) {
+        goto err_pcie_cap;
+    }
+    pcie_cap_root_init(d);
+    rc = pcie_aer_init(d, IOH_EP_AER_OFFSET);
+    if (rc < 0) {
+        goto err;
+    }
+    pcie_aer_root_init(d);
+    ioh3420_aer_vector_update(d);
+    return 0;
+
+err:
+    pcie_chassis_del_slot(s);
+err_pcie_cap:
+    pcie_cap_exit(d);
+err_msi:
+    msi_uninit(d);
+err_bridge:
+    pci_bridge_exitfn(d);
+    return rc;
+}
+
+static void ioh3420_exitfn(PCIDevice *d)
+{
+    PCIBridge* br = DO_UPCAST(PCIBridge, dev, d);
+    PCIEPort *p = DO_UPCAST(PCIEPort, br, br);
+    PCIESlot *s = DO_UPCAST(PCIESlot, port, p);
+
+    pcie_aer_exit(d);
+    pcie_chassis_del_slot(s);
+    pcie_cap_exit(d);
+    msi_uninit(d);
+    pci_bridge_exitfn(d);
+}
+
+PCIESlot *ioh3420_init(PCIBus *bus, int devfn, bool multifunction,
+                         const char *bus_name, pci_map_irq_fn map_irq,
+                         uint8_t port, uint8_t chassis, uint16_t slot)
+{
+    PCIDevice *d;
+    PCIBridge *br;
+    DeviceState *qdev;
+
+    d = pci_create_multifunction(bus, devfn, multifunction, "ioh3420");
+    if (!d) {
+        return NULL;
+    }
+    br = DO_UPCAST(PCIBridge, dev, d);
+
+    qdev = &br->dev.qdev;
+    pci_bridge_map_irq(br, bus_name, map_irq);
+    qdev_prop_set_uint8(qdev, "port", port);
+    qdev_prop_set_uint8(qdev, "chassis", chassis);
+    qdev_prop_set_uint16(qdev, "slot", slot);
+    qdev_init_nofail(qdev);
+
+    return DO_UPCAST(PCIESlot, port, DO_UPCAST(PCIEPort, br, br));
+}
+
+static const VMStateDescription vmstate_ioh3420 = {
+    .name = "ioh-3240-express-root-port",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .post_load = pcie_cap_slot_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_PCIE_DEVICE(port.br.dev, PCIESlot),
+        VMSTATE_STRUCT(port.br.dev.exp.aer_log, PCIESlot, 0,
+                       vmstate_pcie_aer_log, PCIEAERLog),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static Property ioh3420_properties[] = {
+    DEFINE_PROP_UINT8("port", PCIESlot, port.port, 0),
+    DEFINE_PROP_UINT8("chassis", PCIESlot, chassis, 0),
+    DEFINE_PROP_UINT16("slot", PCIESlot, slot, 0),
+    DEFINE_PROP_UINT16("aer_log_max", PCIESlot,
+    port.br.dev.exp.aer_log.log_max,
+    PCIE_AER_LOG_MAX_DEFAULT),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void ioh3420_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->is_express = 1;
+    k->is_bridge = 1;
+    k->config_write = ioh3420_write_config;
+    k->init = ioh3420_initfn;
+    k->exit = ioh3420_exitfn;
+    k->vendor_id = PCI_VENDOR_ID_INTEL;
+    k->device_id = PCI_DEVICE_ID_IOH_EPORT;
+    k->revision = PCI_DEVICE_ID_IOH_REV;
+    dc->desc = "Intel IOH device id 3420 PCIE Root Port";
+    dc->reset = ioh3420_reset;
+    dc->vmsd = &vmstate_ioh3420;
+    dc->props = ioh3420_properties;
+}
+
+static const TypeInfo ioh3420_info = {
+    .name          = "ioh3420",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PCIESlot),
+    .class_init    = ioh3420_class_init,
+};
+
+static void ioh3420_register_types(void)
+{
+    type_register_static(&ioh3420_info);
+}
+
+type_init(ioh3420_register_types)
+
+/*
+ * Local variables:
+ *  c-indent-level: 4
+ *  c-basic-offset: 4
+ *  tab-width: 8
+ *  indent-tab-mode: nil
+ * End:
+ */
diff --git a/hw/pci-bridge/ioh3420.h b/hw/pci-bridge/ioh3420.h
new file mode 100644 (file)
index 0000000..7776e5b
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef QEMU_IOH3420_H
+#define QEMU_IOH3420_H
+
+#include "hw/pci/pcie_port.h"
+
+PCIESlot *ioh3420_init(PCIBus *bus, int devfn, bool multifunction,
+                       const char *bus_name, pci_map_irq_fn map_irq,
+                       uint8_t port, uint8_t chassis, uint16_t slot);
+
+#endif /* QEMU_IOH3420_H */
diff --git a/hw/pci-bridge/pci_bridge_dev.c b/hw/pci-bridge/pci_bridge_dev.c
new file mode 100644 (file)
index 0000000..971b432
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * Standard PCI Bridge Device
+ *
+ * Copyright (c) 2011 Red Hat Inc. Author: Michael S. Tsirkin <mst@redhat.com>
+ *
+ * http://www.pcisig.com/specifications/conventional/pci_to_pci_bridge_architecture/
+ *
+ * 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 "hw/pci/pci_bridge.h"
+#include "hw/pci/pci_ids.h"
+#include "hw/pci/msi.h"
+#include "hw/pci/shpc.h"
+#include "hw/pci/slotid_cap.h"
+#include "exec/memory.h"
+#include "hw/pci/pci_bus.h"
+
+struct PCIBridgeDev {
+    PCIBridge bridge;
+    MemoryRegion bar;
+    uint8_t chassis_nr;
+#define PCI_BRIDGE_DEV_F_MSI_REQ 0
+    uint32_t flags;
+};
+typedef struct PCIBridgeDev PCIBridgeDev;
+
+static int pci_bridge_dev_initfn(PCIDevice *dev)
+{
+    PCIBridge *br = DO_UPCAST(PCIBridge, dev, dev);
+    PCIBridgeDev *bridge_dev = DO_UPCAST(PCIBridgeDev, bridge, br);
+    int err;
+
+    err = pci_bridge_initfn(dev, TYPE_PCI_BUS);
+    if (err) {
+        goto bridge_error;
+    }
+    memory_region_init(&bridge_dev->bar, "shpc-bar", shpc_bar_size(dev));
+    err = shpc_init(dev, &br->sec_bus, &bridge_dev->bar, 0);
+    if (err) {
+        goto shpc_error;
+    }
+    err = slotid_cap_init(dev, 0, bridge_dev->chassis_nr, 0);
+    if (err) {
+        goto slotid_error;
+    }
+    if ((bridge_dev->flags & (1 << PCI_BRIDGE_DEV_F_MSI_REQ)) &&
+        msi_supported) {
+        err = msi_init(dev, 0, 1, true, true);
+        if (err < 0) {
+            goto msi_error;
+        }
+    }
+    /* TODO: spec recommends using 64 bit prefetcheable BAR.
+     * Check whether that works well. */
+    pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY |
+                    PCI_BASE_ADDRESS_MEM_TYPE_64, &bridge_dev->bar);
+    dev->config[PCI_INTERRUPT_PIN] = 0x1;
+    return 0;
+msi_error:
+    slotid_cap_cleanup(dev);
+slotid_error:
+    shpc_cleanup(dev, &bridge_dev->bar);
+shpc_error:
+    memory_region_destroy(&bridge_dev->bar);
+    pci_bridge_exitfn(dev);
+bridge_error:
+    return err;
+}
+
+static void pci_bridge_dev_exitfn(PCIDevice *dev)
+{
+    PCIBridge *br = DO_UPCAST(PCIBridge, dev, dev);
+    PCIBridgeDev *bridge_dev = DO_UPCAST(PCIBridgeDev, bridge, br);
+    if (msi_present(dev)) {
+        msi_uninit(dev);
+    }
+    slotid_cap_cleanup(dev);
+    shpc_cleanup(dev, &bridge_dev->bar);
+    memory_region_destroy(&bridge_dev->bar);
+    pci_bridge_exitfn(dev);
+}
+
+static void pci_bridge_dev_write_config(PCIDevice *d,
+                                        uint32_t address, uint32_t val, int len)
+{
+    pci_bridge_write_config(d, address, val, len);
+    if (msi_present(d)) {
+        msi_write_config(d, address, val, len);
+    }
+    shpc_cap_write_config(d, address, val, len);
+}
+
+static void qdev_pci_bridge_dev_reset(DeviceState *qdev)
+{
+    PCIDevice *dev = DO_UPCAST(PCIDevice, qdev, qdev);
+
+    pci_bridge_reset(qdev);
+    shpc_reset(dev);
+}
+
+static Property pci_bridge_dev_properties[] = {
+                    /* Note: 0 is not a legal chassis number. */
+    DEFINE_PROP_UINT8("chassis_nr", PCIBridgeDev, chassis_nr, 0),
+    DEFINE_PROP_BIT("msi", PCIBridgeDev, flags, PCI_BRIDGE_DEV_F_MSI_REQ, true),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static const VMStateDescription pci_bridge_dev_vmstate = {
+    .name = "pci_bridge",
+    .fields = (VMStateField[]) {
+        VMSTATE_PCI_DEVICE(bridge.dev, PCIBridgeDev),
+        SHPC_VMSTATE(bridge.dev.shpc, PCIBridgeDev),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void pci_bridge_dev_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+    k->init = pci_bridge_dev_initfn;
+    k->exit = pci_bridge_dev_exitfn;
+    k->config_write = pci_bridge_dev_write_config;
+    k->vendor_id = PCI_VENDOR_ID_REDHAT;
+    k->device_id = PCI_DEVICE_ID_REDHAT_BRIDGE;
+    k->class_id = PCI_CLASS_BRIDGE_PCI;
+    k->is_bridge = 1,
+    dc->desc = "Standard PCI Bridge";
+    dc->reset = qdev_pci_bridge_dev_reset;
+    dc->props = pci_bridge_dev_properties;
+    dc->vmsd = &pci_bridge_dev_vmstate;
+}
+
+static const TypeInfo pci_bridge_dev_info = {
+    .name = "pci-bridge",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PCIBridgeDev),
+    .class_init = pci_bridge_dev_class_init,
+};
+
+static void pci_bridge_dev_register(void)
+{
+    type_register_static(&pci_bridge_dev_info);
+}
+
+type_init(pci_bridge_dev_register);
diff --git a/hw/pci-bridge/xio3130_downstream.c b/hw/pci-bridge/xio3130_downstream.c
new file mode 100644 (file)
index 0000000..1810dd2
--- /dev/null
@@ -0,0 +1,217 @@
+/*
+ * x3130_downstream.c
+ * TI X3130 pci express downstream port switch
+ *
+ * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
+ *                    VA Linux Systems Japan K.K.
+ *
+ * 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 "hw/pci/pci_ids.h"
+#include "hw/pci/msi.h"
+#include "hw/pci/pcie.h"
+#include "xio3130_downstream.h"
+
+#define PCI_DEVICE_ID_TI_XIO3130D       0x8233  /* downstream port */
+#define XIO3130_REVISION                0x1
+#define XIO3130_MSI_OFFSET              0x70
+#define XIO3130_MSI_SUPPORTED_FLAGS     PCI_MSI_FLAGS_64BIT
+#define XIO3130_MSI_NR_VECTOR           1
+#define XIO3130_SSVID_OFFSET            0x80
+#define XIO3130_SSVID_SVID              0
+#define XIO3130_SSVID_SSID              0
+#define XIO3130_EXP_OFFSET              0x90
+#define XIO3130_AER_OFFSET              0x100
+
+static void xio3130_downstream_write_config(PCIDevice *d, uint32_t address,
+                                         uint32_t val, int len)
+{
+    pci_bridge_write_config(d, address, val, len);
+    pcie_cap_flr_write_config(d, address, val, len);
+    pcie_cap_slot_write_config(d, address, val, len);
+    pcie_aer_write_config(d, address, val, len);
+}
+
+static void xio3130_downstream_reset(DeviceState *qdev)
+{
+    PCIDevice *d = PCI_DEVICE(qdev);
+
+    pcie_cap_deverr_reset(d);
+    pcie_cap_slot_reset(d);
+    pcie_cap_ari_reset(d);
+    pci_bridge_reset(qdev);
+}
+
+static int xio3130_downstream_initfn(PCIDevice *d)
+{
+    PCIBridge* br = DO_UPCAST(PCIBridge, dev, d);
+    PCIEPort *p = DO_UPCAST(PCIEPort, br, br);
+    PCIESlot *s = DO_UPCAST(PCIESlot, port, p);
+    int rc;
+
+    rc = pci_bridge_initfn(d, TYPE_PCIE_BUS);
+    if (rc < 0) {
+        return rc;
+    }
+
+    pcie_port_init_reg(d);
+
+    rc = msi_init(d, XIO3130_MSI_OFFSET, XIO3130_MSI_NR_VECTOR,
+                  XIO3130_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_64BIT,
+                  XIO3130_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_MASKBIT);
+    if (rc < 0) {
+        goto err_bridge;
+    }
+    rc = pci_bridge_ssvid_init(d, XIO3130_SSVID_OFFSET,
+                               XIO3130_SSVID_SVID, XIO3130_SSVID_SSID);
+    if (rc < 0) {
+        goto err_bridge;
+    }
+    rc = pcie_cap_init(d, XIO3130_EXP_OFFSET, PCI_EXP_TYPE_DOWNSTREAM,
+                       p->port);
+    if (rc < 0) {
+        goto err_msi;
+    }
+    pcie_cap_flr_init(d);
+    pcie_cap_deverr_init(d);
+    pcie_cap_slot_init(d, s->slot);
+    pcie_chassis_create(s->chassis);
+    rc = pcie_chassis_add_slot(s);
+    if (rc < 0) {
+        goto err_pcie_cap;
+    }
+    pcie_cap_ari_init(d);
+    rc = pcie_aer_init(d, XIO3130_AER_OFFSET);
+    if (rc < 0) {
+        goto err;
+    }
+
+    return 0;
+
+err:
+    pcie_chassis_del_slot(s);
+err_pcie_cap:
+    pcie_cap_exit(d);
+err_msi:
+    msi_uninit(d);
+err_bridge:
+    pci_bridge_exitfn(d);
+    return rc;
+}
+
+static void xio3130_downstream_exitfn(PCIDevice *d)
+{
+    PCIBridge* br = DO_UPCAST(PCIBridge, dev, d);
+    PCIEPort *p = DO_UPCAST(PCIEPort, br, br);
+    PCIESlot *s = DO_UPCAST(PCIESlot, port, p);
+
+    pcie_aer_exit(d);
+    pcie_chassis_del_slot(s);
+    pcie_cap_exit(d);
+    msi_uninit(d);
+    pci_bridge_exitfn(d);
+}
+
+PCIESlot *xio3130_downstream_init(PCIBus *bus, int devfn, bool multifunction,
+                                  const char *bus_name, pci_map_irq_fn map_irq,
+                                  uint8_t port, uint8_t chassis,
+                                  uint16_t slot)
+{
+    PCIDevice *d;
+    PCIBridge *br;
+    DeviceState *qdev;
+
+    d = pci_create_multifunction(bus, devfn, multifunction,
+                                 "xio3130-downstream");
+    if (!d) {
+        return NULL;
+    }
+    br = DO_UPCAST(PCIBridge, dev, d);
+
+    qdev = &br->dev.qdev;
+    pci_bridge_map_irq(br, bus_name, map_irq);
+    qdev_prop_set_uint8(qdev, "port", port);
+    qdev_prop_set_uint8(qdev, "chassis", chassis);
+    qdev_prop_set_uint16(qdev, "slot", slot);
+    qdev_init_nofail(qdev);
+
+    return DO_UPCAST(PCIESlot, port, DO_UPCAST(PCIEPort, br, br));
+}
+
+static const VMStateDescription vmstate_xio3130_downstream = {
+    .name = "xio3130-express-downstream-port",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .post_load = pcie_cap_slot_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_PCIE_DEVICE(port.br.dev, PCIESlot),
+        VMSTATE_STRUCT(port.br.dev.exp.aer_log, PCIESlot, 0,
+                       vmstate_pcie_aer_log, PCIEAERLog),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static Property xio3130_downstream_properties[] = {
+    DEFINE_PROP_UINT8("port", PCIESlot, port.port, 0),
+    DEFINE_PROP_UINT8("chassis", PCIESlot, chassis, 0),
+    DEFINE_PROP_UINT16("slot", PCIESlot, slot, 0),
+    DEFINE_PROP_UINT16("aer_log_max", PCIESlot,
+    port.br.dev.exp.aer_log.log_max,
+    PCIE_AER_LOG_MAX_DEFAULT),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void xio3130_downstream_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->is_express = 1;
+    k->is_bridge = 1;
+    k->config_write = xio3130_downstream_write_config;
+    k->init = xio3130_downstream_initfn;
+    k->exit = xio3130_downstream_exitfn;
+    k->vendor_id = PCI_VENDOR_ID_TI;
+    k->device_id = PCI_DEVICE_ID_TI_XIO3130D;
+    k->revision = XIO3130_REVISION;
+    dc->desc = "TI X3130 Downstream Port of PCI Express Switch";
+    dc->reset = xio3130_downstream_reset;
+    dc->vmsd = &vmstate_xio3130_downstream;
+    dc->props = xio3130_downstream_properties;
+}
+
+static const 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_types(void)
+{
+    type_register_static(&xio3130_downstream_info);
+}
+
+type_init(xio3130_downstream_register_types)
+
+/*
+ * Local variables:
+ *  c-indent-level: 4
+ *  c-basic-offset: 4
+ *  tab-width: 8
+ *  indent-tab-mode: nil
+ * End:
+ */
diff --git a/hw/pci-bridge/xio3130_downstream.h b/hw/pci-bridge/xio3130_downstream.h
new file mode 100644 (file)
index 0000000..8426d9f
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef QEMU_XIO3130_DOWNSTREAM_H
+#define QEMU_XIO3130_DOWNSTREAM_H
+
+#include "hw/pci/pcie_port.h"
+
+PCIESlot *xio3130_downstream_init(PCIBus *bus, int devfn, bool multifunction,
+                                  const char *bus_name, pci_map_irq_fn map_irq,
+                                  uint8_t port, uint8_t chassis,
+                                  uint16_t slot);
+
+#endif /* QEMU_XIO3130_DOWNSTREAM_H */
diff --git a/hw/pci-bridge/xio3130_upstream.c b/hw/pci-bridge/xio3130_upstream.c
new file mode 100644 (file)
index 0000000..8e0d97a
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ * xio3130_upstream.c
+ * TI X3130 pci express upstream port switch
+ *
+ * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
+ *                    VA Linux Systems Japan K.K.
+ *
+ * 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 "hw/pci/pci_ids.h"
+#include "hw/pci/msi.h"
+#include "hw/pci/pcie.h"
+#include "xio3130_upstream.h"
+
+#define PCI_DEVICE_ID_TI_XIO3130U       0x8232  /* upstream port */
+#define XIO3130_REVISION                0x2
+#define XIO3130_MSI_OFFSET              0x70
+#define XIO3130_MSI_SUPPORTED_FLAGS     PCI_MSI_FLAGS_64BIT
+#define XIO3130_MSI_NR_VECTOR           1
+#define XIO3130_SSVID_OFFSET            0x80
+#define XIO3130_SSVID_SVID              0
+#define XIO3130_SSVID_SSID              0
+#define XIO3130_EXP_OFFSET              0x90
+#define XIO3130_AER_OFFSET              0x100
+
+static void xio3130_upstream_write_config(PCIDevice *d, uint32_t address,
+                                          uint32_t val, int len)
+{
+    pci_bridge_write_config(d, address, val, len);
+    pcie_cap_flr_write_config(d, address, val, len);
+    pcie_aer_write_config(d, address, val, len);
+}
+
+static void xio3130_upstream_reset(DeviceState *qdev)
+{
+    PCIDevice *d = PCI_DEVICE(qdev);
+
+    pci_bridge_reset(qdev);
+    pcie_cap_deverr_reset(d);
+}
+
+static int xio3130_upstream_initfn(PCIDevice *d)
+{
+    PCIBridge* br = DO_UPCAST(PCIBridge, dev, d);
+    PCIEPort *p = DO_UPCAST(PCIEPort, br, br);
+    int rc;
+
+    rc = pci_bridge_initfn(d, TYPE_PCIE_BUS);
+    if (rc < 0) {
+        return rc;
+    }
+
+    pcie_port_init_reg(d);
+
+    rc = msi_init(d, XIO3130_MSI_OFFSET, XIO3130_MSI_NR_VECTOR,
+                  XIO3130_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_64BIT,
+                  XIO3130_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_MASKBIT);
+    if (rc < 0) {
+        goto err_bridge;
+    }
+    rc = pci_bridge_ssvid_init(d, XIO3130_SSVID_OFFSET,
+                               XIO3130_SSVID_SVID, XIO3130_SSVID_SSID);
+    if (rc < 0) {
+        goto err_bridge;
+    }
+    rc = pcie_cap_init(d, XIO3130_EXP_OFFSET, PCI_EXP_TYPE_UPSTREAM,
+                       p->port);
+    if (rc < 0) {
+        goto err_msi;
+    }
+    pcie_cap_flr_init(d);
+    pcie_cap_deverr_init(d);
+    rc = pcie_aer_init(d, XIO3130_AER_OFFSET);
+    if (rc < 0) {
+        goto err;
+    }
+
+    return 0;
+
+err:
+    pcie_cap_exit(d);
+err_msi:
+    msi_uninit(d);
+err_bridge:
+    pci_bridge_exitfn(d);
+    return rc;
+}
+
+static void xio3130_upstream_exitfn(PCIDevice *d)
+{
+    pcie_aer_exit(d);
+    pcie_cap_exit(d);
+    msi_uninit(d);
+    pci_bridge_exitfn(d);
+}
+
+PCIEPort *xio3130_upstream_init(PCIBus *bus, int devfn, bool multifunction,
+                             const char *bus_name, pci_map_irq_fn map_irq,
+                             uint8_t port)
+{
+    PCIDevice *d;
+    PCIBridge *br;
+    DeviceState *qdev;
+
+    d = pci_create_multifunction(bus, devfn, multifunction, "x3130-upstream");
+    if (!d) {
+        return NULL;
+    }
+    br = DO_UPCAST(PCIBridge, dev, d);
+
+    qdev = &br->dev.qdev;
+    pci_bridge_map_irq(br, bus_name, map_irq);
+    qdev_prop_set_uint8(qdev, "port", port);
+    qdev_init_nofail(qdev);
+
+    return DO_UPCAST(PCIEPort, br, br);
+}
+
+static const VMStateDescription vmstate_xio3130_upstream = {
+    .name = "xio3130-express-upstream-port",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_PCIE_DEVICE(br.dev, PCIEPort),
+        VMSTATE_STRUCT(br.dev.exp.aer_log, PCIEPort, 0, vmstate_pcie_aer_log,
+                       PCIEAERLog),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static Property xio3130_upstream_properties[] = {
+    DEFINE_PROP_UINT8("port", PCIEPort, port, 0),
+    DEFINE_PROP_UINT16("aer_log_max", PCIEPort, br.dev.exp.aer_log.log_max,
+    PCIE_AER_LOG_MAX_DEFAULT),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void xio3130_upstream_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->is_express = 1;
+    k->is_bridge = 1;
+    k->config_write = xio3130_upstream_write_config;
+    k->init = xio3130_upstream_initfn;
+    k->exit = xio3130_upstream_exitfn;
+    k->vendor_id = PCI_VENDOR_ID_TI;
+    k->device_id = PCI_DEVICE_ID_TI_XIO3130U;
+    k->revision = XIO3130_REVISION;
+    dc->desc = "TI X3130 Upstream Port of PCI Express Switch";
+    dc->reset = xio3130_upstream_reset;
+    dc->vmsd = &vmstate_xio3130_upstream;
+    dc->props = xio3130_upstream_properties;
+}
+
+static const 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_types(void)
+{
+    type_register_static(&xio3130_upstream_info);
+}
+
+type_init(xio3130_upstream_register_types)
+
+
+/*
+ * Local variables:
+ *  c-indent-level: 4
+ *  c-basic-offset: 4
+ *  tab-width: 8
+ *  indent-tab-mode: nil
+ * End:
+ */
diff --git a/hw/pci-bridge/xio3130_upstream.h b/hw/pci-bridge/xio3130_upstream.h
new file mode 100644 (file)
index 0000000..08c1d5f
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef QEMU_XIO3130_UPSTREAM_H
+#define QEMU_XIO3130_UPSTREAM_H
+
+#include "hw/pci/pcie_port.h"
+
+PCIEPort *xio3130_upstream_init(PCIBus *bus, int devfn, bool multifunction,
+                                const char *bus_name, pci_map_irq_fn map_irq,
+                                uint8_t port);
+
+#endif /* QEMU_XIO3130_H */
diff --git a/hw/pci-host/Makefile.objs b/hw/pci-host/Makefile.objs
new file mode 100644 (file)
index 0000000..909e702
--- /dev/null
@@ -0,0 +1,18 @@
+common-obj-y += pam.o
+
+# PPC devices
+common-obj-$(CONFIG_PREP_PCI) += prep.o
+common-obj-$(CONFIG_GRACKLE_PCI) += grackle.o
+# NewWorld PowerMac
+common-obj-$(CONFIG_UNIN_PCI) += uninorth.o
+common-obj-$(CONFIG_DEC_PCI) += dec.o
+# PowerPC E500 boards
+common-obj-$(CONFIG_PPCE500_PCI) += ppce500.o
+
+# ARM devices
+common-obj-$(CONFIG_VERSATILE_PCI) += versatile.o
+
+common-obj-$(CONFIG_PCI_APB) += apb.o
+common-obj-$(CONFIG_FULONG) += bonito.o
+common-obj-$(CONFIG_PCI_PIIX) += piix.o
+common-obj-$(CONFIG_PCI_Q35) += q35.o
diff --git a/hw/pci-host/apb.c b/hw/pci-host/apb.c
new file mode 100644 (file)
index 0000000..b4981d7
--- /dev/null
@@ -0,0 +1,542 @@
+/*
+ * QEMU Ultrasparc APB PCI host
+ *
+ * Copyright (c) 2006 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.
+ */
+
+/* XXX This file and most of its contents are somewhat misnamed.  The
+   Ultrasparc PCI host is called the PCI Bus Module (PBM).  The APB is
+   the secondary PCI bridge.  */
+
+#include "hw/sysbus.h"
+#include "hw/pci/pci.h"
+#include "hw/pci/pci_host.h"
+#include "hw/pci/pci_bridge.h"
+#include "hw/pci/pci_bus.h"
+#include "hw/pci-host/apb.h"
+#include "sysemu/sysemu.h"
+#include "exec/address-spaces.h"
+
+/* debug APB */
+//#define DEBUG_APB
+
+#ifdef DEBUG_APB
+#define APB_DPRINTF(fmt, ...) \
+do { printf("APB: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define APB_DPRINTF(fmt, ...)
+#endif
+
+/*
+ * Chipset docs:
+ * PBM: "UltraSPARC IIi User's Manual",
+ * http://www.sun.com/processors/manuals/805-0087.pdf
+ *
+ * APB: "Advanced PCI Bridge (APB) User's Manual",
+ * http://www.sun.com/processors/manuals/805-1251.pdf
+ */
+
+#define PBM_PCI_IMR_MASK    0x7fffffff
+#define PBM_PCI_IMR_ENABLED 0x80000000
+
+#define POR          (1 << 31)
+#define SOFT_POR     (1 << 30)
+#define SOFT_XIR     (1 << 29)
+#define BTN_POR      (1 << 28)
+#define BTN_XIR      (1 << 27)
+#define RESET_MASK   0xf8000000
+#define RESET_WCMASK 0x98000000
+#define RESET_WMASK  0x60000000
+
+#define MAX_IVEC 0x30
+
+typedef struct APBState {
+    SysBusDevice busdev;
+    PCIBus      *bus;
+    MemoryRegion apb_config;
+    MemoryRegion pci_config;
+    MemoryRegion pci_mmio;
+    MemoryRegion pci_ioport;
+    uint32_t iommu[4];
+    uint32_t pci_control[16];
+    uint32_t pci_irq_map[8];
+    uint32_t obio_irq_map[32];
+    qemu_irq *pbm_irqs;
+    qemu_irq *ivec_irqs;
+    uint32_t reset_control;
+    unsigned int nr_resets;
+} APBState;
+
+static void pci_apb_set_irq(void *opaque, int irq_num, int level);
+
+static void apb_config_writel (void *opaque, hwaddr addr,
+                               uint64_t val, unsigned size)
+{
+    APBState *s = opaque;
+
+    APB_DPRINTF("%s: addr " TARGET_FMT_plx " val %" PRIx64 "\n", __func__, addr, val);
+
+    switch (addr & 0xffff) {
+    case 0x30 ... 0x4f: /* DMA error registers */
+        /* XXX: not implemented yet */
+        break;
+    case 0x200 ... 0x20b: /* IOMMU */
+        s->iommu[(addr & 0xf) >> 2] = val;
+        break;
+    case 0x20c ... 0x3ff: /* IOMMU flush */
+        break;
+    case 0xc00 ... 0xc3f: /* PCI interrupt control */
+        if (addr & 4) {
+            s->pci_irq_map[(addr & 0x3f) >> 3] &= PBM_PCI_IMR_MASK;
+            s->pci_irq_map[(addr & 0x3f) >> 3] |= val & ~PBM_PCI_IMR_MASK;
+        }
+        break;
+    case 0x1000 ... 0x1080: /* OBIO interrupt control */
+        if (addr & 4) {
+            s->obio_irq_map[(addr & 0xff) >> 3] &= PBM_PCI_IMR_MASK;
+            s->obio_irq_map[(addr & 0xff) >> 3] |= val & ~PBM_PCI_IMR_MASK;
+        }
+        break;
+    case 0x1400 ... 0x143f: /* PCI interrupt clear */
+        if (addr & 4) {
+            pci_apb_set_irq(s, (addr & 0x3f) >> 3, 0);
+        }
+        break;
+    case 0x1800 ... 0x1860: /* OBIO interrupt clear */
+        if (addr & 4) {
+            pci_apb_set_irq(s, 0x20 | ((addr & 0xff) >> 3), 0);
+        }
+        break;
+    case 0x2000 ... 0x202f: /* PCI control */
+        s->pci_control[(addr & 0x3f) >> 2] = val;
+        break;
+    case 0xf020 ... 0xf027: /* Reset control */
+        if (addr & 4) {
+            val &= RESET_MASK;
+            s->reset_control &= ~(val & RESET_WCMASK);
+            s->reset_control |= val & RESET_WMASK;
+            if (val & SOFT_POR) {
+                s->nr_resets = 0;
+                qemu_system_reset_request();
+            } else if (val & SOFT_XIR) {
+                qemu_system_reset_request();
+            }
+        }
+        break;
+    case 0x5000 ... 0x51cf: /* PIO/DMA diagnostics */
+    case 0xa400 ... 0xa67f: /* IOMMU diagnostics */
+    case 0xa800 ... 0xa80f: /* Interrupt diagnostics */
+    case 0xf000 ... 0xf01f: /* FFB config, memory control */
+        /* we don't care */
+    default:
+        break;
+    }
+}
+
+static uint64_t apb_config_readl (void *opaque,
+                                  hwaddr addr, unsigned size)
+{
+    APBState *s = opaque;
+    uint32_t val;
+
+    switch (addr & 0xffff) {
+    case 0x30 ... 0x4f: /* DMA error registers */
+        val = 0;
+        /* XXX: not implemented yet */
+        break;
+    case 0x200 ... 0x20b: /* IOMMU */
+        val = s->iommu[(addr & 0xf) >> 2];
+        break;
+    case 0x20c ... 0x3ff: /* IOMMU flush */
+        val = 0;
+        break;
+    case 0xc00 ... 0xc3f: /* PCI interrupt control */
+        if (addr & 4) {
+            val = s->pci_irq_map[(addr & 0x3f) >> 3];
+        } else {
+            val = 0;
+        }
+        break;
+    case 0x1000 ... 0x1080: /* OBIO interrupt control */
+        if (addr & 4) {
+            val = s->obio_irq_map[(addr & 0xff) >> 3];
+        } else {
+            val = 0;
+        }
+        break;
+    case 0x2000 ... 0x202f: /* PCI control */
+        val = s->pci_control[(addr & 0x3f) >> 2];
+        break;
+    case 0xf020 ... 0xf027: /* Reset control */
+        if (addr & 4) {
+            val = s->reset_control;
+        } else {
+            val = 0;
+        }
+        break;
+    case 0x5000 ... 0x51cf: /* PIO/DMA diagnostics */
+    case 0xa400 ... 0xa67f: /* IOMMU diagnostics */
+    case 0xa800 ... 0xa80f: /* Interrupt diagnostics */
+    case 0xf000 ... 0xf01f: /* FFB config, memory control */
+        /* we don't care */
+    default:
+        val = 0;
+        break;
+    }
+    APB_DPRINTF("%s: addr " TARGET_FMT_plx " -> %x\n", __func__, addr, val);
+
+    return val;
+}
+
+static const MemoryRegionOps apb_config_ops = {
+    .read = apb_config_readl,
+    .write = apb_config_writel,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void apb_pci_config_write(void *opaque, hwaddr addr,
+                                 uint64_t val, unsigned size)
+{
+    APBState *s = opaque;
+
+    val = qemu_bswap_len(val, size);
+    APB_DPRINTF("%s: addr " TARGET_FMT_plx " val %" PRIx64 "\n", __func__, addr, val);
+    pci_data_write(s->bus, addr, val, size);
+}
+
+static uint64_t apb_pci_config_read(void *opaque, hwaddr addr,
+                                    unsigned size)
+{
+    uint32_t ret;
+    APBState *s = opaque;
+
+    ret = pci_data_read(s->bus, addr, size);
+    ret = qemu_bswap_len(ret, size);
+    APB_DPRINTF("%s: addr " TARGET_FMT_plx " -> %x\n", __func__, addr, ret);
+    return ret;
+}
+
+static void pci_apb_iowriteb (void *opaque, hwaddr addr,
+                                  uint32_t val)
+{
+    cpu_outb(addr & IOPORTS_MASK, val);
+}
+
+static void pci_apb_iowritew (void *opaque, hwaddr addr,
+                                  uint32_t val)
+{
+    cpu_outw(addr & IOPORTS_MASK, bswap16(val));
+}
+
+static void pci_apb_iowritel (void *opaque, hwaddr addr,
+                                uint32_t val)
+{
+    cpu_outl(addr & IOPORTS_MASK, bswap32(val));
+}
+
+static uint32_t pci_apb_ioreadb (void *opaque, hwaddr addr)
+{
+    uint32_t val;
+
+    val = cpu_inb(addr & IOPORTS_MASK);
+    return val;
+}
+
+static uint32_t pci_apb_ioreadw (void *opaque, hwaddr addr)
+{
+    uint32_t val;
+
+    val = bswap16(cpu_inw(addr & IOPORTS_MASK));
+    return val;
+}
+
+static uint32_t pci_apb_ioreadl (void *opaque, hwaddr addr)
+{
+    uint32_t val;
+
+    val = bswap32(cpu_inl(addr & IOPORTS_MASK));
+    return val;
+}
+
+static const MemoryRegionOps pci_ioport_ops = {
+    .old_mmio = {
+        .read = { pci_apb_ioreadb, pci_apb_ioreadw, pci_apb_ioreadl },
+        .write = { pci_apb_iowriteb, pci_apb_iowritew, pci_apb_iowritel, },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+/* The APB host has an IRQ line for each IRQ line of each slot.  */
+static int pci_apb_map_irq(PCIDevice *pci_dev, int irq_num)
+{
+    return ((pci_dev->devfn & 0x18) >> 1) + irq_num;
+}
+
+static int pci_pbm_map_irq(PCIDevice *pci_dev, int irq_num)
+{
+    int bus_offset;
+    if (pci_dev->devfn & 1)
+        bus_offset = 16;
+    else
+        bus_offset = 0;
+    return bus_offset + irq_num;
+}
+
+static void pci_apb_set_irq(void *opaque, int irq_num, int level)
+{
+    APBState *s = opaque;
+
+    /* PCI IRQ map onto the first 32 INO.  */
+    if (irq_num < 32) {
+        if (s->pci_irq_map[irq_num >> 2] & PBM_PCI_IMR_ENABLED) {
+            APB_DPRINTF("%s: set irq %d level %d\n", __func__, irq_num, level);
+            qemu_set_irq(s->ivec_irqs[irq_num], level);
+        } else {
+            APB_DPRINTF("%s: not enabled: lower irq %d\n", __func__, irq_num);
+            qemu_irq_lower(s->ivec_irqs[irq_num]);
+        }
+    } else {
+        /* OBIO IRQ map onto the next 16 INO.  */
+        if (s->obio_irq_map[irq_num - 32] & PBM_PCI_IMR_ENABLED) {
+            APB_DPRINTF("%s: set irq %d level %d\n", __func__, irq_num, level);
+            qemu_set_irq(s->ivec_irqs[irq_num], level);
+        } else {
+            APB_DPRINTF("%s: not enabled: lower irq %d\n", __func__, irq_num);
+            qemu_irq_lower(s->ivec_irqs[irq_num]);
+        }
+    }
+}
+
+static int apb_pci_bridge_initfn(PCIDevice *dev)
+{
+    int rc;
+
+    rc = pci_bridge_initfn(dev, TYPE_PCI_BUS);
+    if (rc < 0) {
+        return rc;
+    }
+
+    /*
+     * command register:
+     * According to PCI bridge spec, after reset
+     *   bus master bit is off
+     *   memory space enable bit is off
+     * According to manual (805-1251.pdf).
+     *   the reset value should be zero unless the boot pin is tied high
+     *   (which is true) and thus it should be PCI_COMMAND_MEMORY.
+     */
+    pci_set_word(dev->config + PCI_COMMAND,
+                 PCI_COMMAND_MEMORY);
+    pci_set_word(dev->config + PCI_STATUS,
+                 PCI_STATUS_FAST_BACK | PCI_STATUS_66MHZ |
+                 PCI_STATUS_DEVSEL_MEDIUM);
+    return 0;
+}
+
+PCIBus *pci_apb_init(hwaddr special_base,
+                     hwaddr mem_base,
+                     qemu_irq *ivec_irqs, PCIBus **bus2, PCIBus **bus3,
+                     qemu_irq **pbm_irqs)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+    APBState *d;
+    PCIDevice *pci_dev;
+    PCIBridge *br;
+
+    /* Ultrasparc PBM main bus */
+    dev = qdev_create(NULL, "pbm");
+    qdev_init_nofail(dev);
+    s = SYS_BUS_DEVICE(dev);
+    /* apb_config */
+    sysbus_mmio_map(s, 0, special_base);
+    /* PCI configuration space */
+    sysbus_mmio_map(s, 1, special_base + 0x1000000ULL);
+    /* pci_ioport */
+    sysbus_mmio_map(s, 2, special_base + 0x2000000ULL);
+    d = FROM_SYSBUS(APBState, s);
+
+    memory_region_init(&d->pci_mmio, "pci-mmio", 0x100000000ULL);
+    memory_region_add_subregion(get_system_memory(), mem_base, &d->pci_mmio);
+
+    d->bus = pci_register_bus(&d->busdev.qdev, "pci",
+                              pci_apb_set_irq, pci_pbm_map_irq, d,
+                              &d->pci_mmio,
+                              get_system_io(),
+                              0, 32, TYPE_PCI_BUS);
+
+    *pbm_irqs = d->pbm_irqs;
+    d->ivec_irqs = ivec_irqs;
+
+    pci_create_simple(d->bus, 0, "pbm-pci");
+
+    /* APB secondary busses */
+    pci_dev = pci_create_multifunction(d->bus, PCI_DEVFN(1, 0), true,
+                                   "pbm-bridge");
+    br = DO_UPCAST(PCIBridge, dev, pci_dev);
+    pci_bridge_map_irq(br, "Advanced PCI Bus secondary bridge 1",
+                       pci_apb_map_irq);
+    qdev_init_nofail(&pci_dev->qdev);
+    *bus2 = pci_bridge_get_sec_bus(br);
+
+    pci_dev = pci_create_multifunction(d->bus, PCI_DEVFN(1, 1), true,
+                                   "pbm-bridge");
+    br = DO_UPCAST(PCIBridge, dev, pci_dev);
+    pci_bridge_map_irq(br, "Advanced PCI Bus secondary bridge 2",
+                       pci_apb_map_irq);
+    qdev_init_nofail(&pci_dev->qdev);
+    *bus3 = pci_bridge_get_sec_bus(br);
+
+    return d->bus;
+}
+
+static void pci_pbm_reset(DeviceState *d)
+{
+    unsigned int i;
+    APBState *s = container_of(d, APBState, busdev.qdev);
+
+    for (i = 0; i < 8; i++) {
+        s->pci_irq_map[i] &= PBM_PCI_IMR_MASK;
+    }
+    for (i = 0; i < 32; i++) {
+        s->obio_irq_map[i] &= PBM_PCI_IMR_MASK;
+    }
+
+    if (s->nr_resets++ == 0) {
+        /* Power on reset */
+        s->reset_control = POR;
+    }
+}
+
+static const MemoryRegionOps pci_config_ops = {
+    .read = apb_pci_config_read,
+    .write = apb_pci_config_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int pci_pbm_init_device(SysBusDevice *dev)
+{
+    APBState *s;
+    unsigned int i;
+
+    s = FROM_SYSBUS(APBState, dev);
+    for (i = 0; i < 8; i++) {
+        s->pci_irq_map[i] = (0x1f << 6) | (i << 2);
+    }
+    for (i = 0; i < 32; i++) {
+        s->obio_irq_map[i] = ((0x1f << 6) | 0x20) + i;
+    }
+    s->pbm_irqs = qemu_allocate_irqs(pci_apb_set_irq, s, MAX_IVEC);
+
+    /* apb_config */
+    memory_region_init_io(&s->apb_config, &apb_config_ops, s, "apb-config",
+                          0x10000);
+    /* at region 0 */
+    sysbus_init_mmio(dev, &s->apb_config);
+
+    memory_region_init_io(&s->pci_config, &pci_config_ops, s, "apb-pci-config",
+                          0x1000000);
+    /* at region 1 */
+    sysbus_init_mmio(dev, &s->pci_config);
+
+    /* pci_ioport */
+    memory_region_init_io(&s->pci_ioport, &pci_ioport_ops, s,
+                          "apb-pci-ioport", 0x10000);
+    /* at region 2 */
+    sysbus_init_mmio(dev, &s->pci_ioport);
+
+    return 0;
+}
+
+static int pbm_pci_host_init(PCIDevice *d)
+{
+    pci_set_word(d->config + PCI_COMMAND,
+                 PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
+    pci_set_word(d->config + PCI_STATUS,
+                 PCI_STATUS_FAST_BACK | PCI_STATUS_66MHZ |
+                 PCI_STATUS_DEVSEL_MEDIUM);
+    return 0;
+}
+
+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;
+}
+
+static const 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 const 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;
+    k->exit = pci_bridge_exitfn;
+    k->vendor_id = PCI_VENDOR_ID_SUN;
+    k->device_id = PCI_DEVICE_ID_SUN_SIMBA;
+    k->revision = 0x11;
+    k->config_write = pci_bridge_write_config;
+    k->is_bridge = 1;
+    dc->reset = pci_bridge_reset;
+    dc->vmsd = &vmstate_pci_device;
+}
+
+static const 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_types(void)
+{
+    type_register_static(&pbm_host_info);
+    type_register_static(&pbm_pci_host_info);
+    type_register_static(&pbm_pci_bridge_info);
+}
+
+type_init(pbm_register_types)
diff --git a/hw/pci-host/bonito.c b/hw/pci-host/bonito.c
new file mode 100644 (file)
index 0000000..974150b
--- /dev/null
@@ -0,0 +1,847 @@
+/*
+ * bonito north bridge support
+ *
+ * Copyright (c) 2008 yajin (yajin@vm-kernel.org)
+ * Copyright (c) 2010 Huacai Chen (zltjiangshi@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.
+ */
+
+/*
+ * fulong 2e mini pc has a bonito north bridge.
+ */
+
+/* what is the meaning of devfn in qemu and IDSEL in bonito northbridge?
+ *
+ * devfn   pci_slot<<3  + funno
+ * one pci bus can have 32 devices and each device can have 8 functions.
+ *
+ * In bonito north bridge, pci slot = IDSEL bit - 12.
+ * For example, PCI_IDSEL_VIA686B = 17,
+ * pci slot = 17-12=5
+ *
+ * so
+ * VT686B_FUN0's devfn = (5<<3)+0
+ * VT686B_FUN1's devfn = (5<<3)+1
+ *
+ * qemu also uses pci address for north bridge to access pci config register.
+ * bus_no   [23:16]
+ * dev_no   [15:11]
+ * fun_no   [10:8]
+ * reg_no   [7:2]
+ *
+ * so function bonito_sbridge_pciaddr for the translation from
+ * north bridge address to pci address.
+ */
+
+#include <assert.h>
+
+#include "hw/hw.h"
+#include "hw/pci/pci.h"
+#include "hw/i386/pc.h"
+#include "hw/mips/mips.h"
+#include "hw/pci/pci_host.h"
+#include "sysemu/sysemu.h"
+#include "exec/address-spaces.h"
+
+//#define DEBUG_BONITO
+
+#ifdef DEBUG_BONITO
+#define DPRINTF(fmt, ...) fprintf(stderr, "%s: " fmt, __FUNCTION__, ##__VA_ARGS__)
+#else
+#define DPRINTF(fmt, ...)
+#endif
+
+/* from linux soure code. include/asm-mips/mips-boards/bonito64.h*/
+#define BONITO_BOOT_BASE        0x1fc00000
+#define BONITO_BOOT_SIZE        0x00100000
+#define BONITO_BOOT_TOP         (BONITO_BOOT_BASE+BONITO_BOOT_SIZE-1)
+#define BONITO_FLASH_BASE       0x1c000000
+#define BONITO_FLASH_SIZE       0x03000000
+#define BONITO_FLASH_TOP        (BONITO_FLASH_BASE+BONITO_FLASH_SIZE-1)
+#define BONITO_SOCKET_BASE      0x1f800000
+#define BONITO_SOCKET_SIZE      0x00400000
+#define BONITO_SOCKET_TOP       (BONITO_SOCKET_BASE+BONITO_SOCKET_SIZE-1)
+#define BONITO_REG_BASE         0x1fe00000
+#define BONITO_REG_SIZE         0x00040000
+#define BONITO_REG_TOP          (BONITO_REG_BASE+BONITO_REG_SIZE-1)
+#define BONITO_DEV_BASE         0x1ff00000
+#define BONITO_DEV_SIZE         0x00100000
+#define BONITO_DEV_TOP          (BONITO_DEV_BASE+BONITO_DEV_SIZE-1)
+#define BONITO_PCILO_BASE       0x10000000
+#define BONITO_PCILO_BASE_VA    0xb0000000
+#define BONITO_PCILO_SIZE       0x0c000000
+#define BONITO_PCILO_TOP        (BONITO_PCILO_BASE+BONITO_PCILO_SIZE-1)
+#define BONITO_PCILO0_BASE      0x10000000
+#define BONITO_PCILO1_BASE      0x14000000
+#define BONITO_PCILO2_BASE      0x18000000
+#define BONITO_PCIHI_BASE       0x20000000
+#define BONITO_PCIHI_SIZE       0x20000000
+#define BONITO_PCIHI_TOP        (BONITO_PCIHI_BASE+BONITO_PCIHI_SIZE-1)
+#define BONITO_PCIIO_BASE       0x1fd00000
+#define BONITO_PCIIO_BASE_VA    0xbfd00000
+#define BONITO_PCIIO_SIZE       0x00010000
+#define BONITO_PCIIO_TOP        (BONITO_PCIIO_BASE+BONITO_PCIIO_SIZE-1)
+#define BONITO_PCICFG_BASE      0x1fe80000
+#define BONITO_PCICFG_SIZE      0x00080000
+#define BONITO_PCICFG_TOP       (BONITO_PCICFG_BASE+BONITO_PCICFG_SIZE-1)
+
+
+#define BONITO_PCICONFIGBASE    0x00
+#define BONITO_REGBASE          0x100
+
+#define BONITO_PCICONFIG_BASE   (BONITO_PCICONFIGBASE+BONITO_REG_BASE)
+#define BONITO_PCICONFIG_SIZE   (0x100)
+
+#define BONITO_INTERNAL_REG_BASE  (BONITO_REGBASE+BONITO_REG_BASE)
+#define BONITO_INTERNAL_REG_SIZE  (0x70)
+
+#define BONITO_SPCICONFIG_BASE  (BONITO_PCICFG_BASE)
+#define BONITO_SPCICONFIG_SIZE  (BONITO_PCICFG_SIZE)
+
+
+
+/* 1. Bonito h/w Configuration */
+/* Power on register */
+
+#define BONITO_BONPONCFG        (0x00 >> 2)      /* 0x100 */
+#define BONITO_BONGENCFG_OFFSET 0x4
+#define BONITO_BONGENCFG        (BONITO_BONGENCFG_OFFSET>>2)   /*0x104 */
+
+/* 2. IO & IDE configuration */
+#define BONITO_IODEVCFG         (0x08 >> 2)      /* 0x108 */
+
+/* 3. IO & IDE configuration */
+#define BONITO_SDCFG            (0x0c >> 2)      /* 0x10c */
+
+/* 4. PCI address map control */
+#define BONITO_PCIMAP           (0x10 >> 2)      /* 0x110 */
+#define BONITO_PCIMEMBASECFG    (0x14 >> 2)      /* 0x114 */
+#define BONITO_PCIMAP_CFG       (0x18 >> 2)      /* 0x118 */
+
+/* 5. ICU & GPIO regs */
+/* GPIO Regs - r/w */
+#define BONITO_GPIODATA_OFFSET  0x1c
+#define BONITO_GPIODATA         (BONITO_GPIODATA_OFFSET >> 2)   /* 0x11c */
+#define BONITO_GPIOIE           (0x20 >> 2)      /* 0x120 */
+
+/* ICU Configuration Regs - r/w */
+#define BONITO_INTEDGE          (0x24 >> 2)      /* 0x124 */
+#define BONITO_INTSTEER         (0x28 >> 2)      /* 0x128 */
+#define BONITO_INTPOL           (0x2c >> 2)      /* 0x12c */
+
+/* ICU Enable Regs - IntEn & IntISR are r/o. */
+#define BONITO_INTENSET         (0x30 >> 2)      /* 0x130 */
+#define BONITO_INTENCLR         (0x34 >> 2)      /* 0x134 */
+#define BONITO_INTEN            (0x38 >> 2)      /* 0x138 */
+#define BONITO_INTISR           (0x3c >> 2)      /* 0x13c */
+
+/* PCI mail boxes */
+#define BONITO_PCIMAIL0_OFFSET    0x40
+#define BONITO_PCIMAIL1_OFFSET    0x44
+#define BONITO_PCIMAIL2_OFFSET    0x48
+#define BONITO_PCIMAIL3_OFFSET    0x4c
+#define BONITO_PCIMAIL0         (0x40 >> 2)      /* 0x140 */
+#define BONITO_PCIMAIL1         (0x44 >> 2)      /* 0x144 */
+#define BONITO_PCIMAIL2         (0x48 >> 2)      /* 0x148 */
+#define BONITO_PCIMAIL3         (0x4c >> 2)      /* 0x14c */
+
+/* 6. PCI cache */
+#define BONITO_PCICACHECTRL     (0x50 >> 2)      /* 0x150 */
+#define BONITO_PCICACHETAG      (0x54 >> 2)      /* 0x154 */
+#define BONITO_PCIBADADDR       (0x58 >> 2)      /* 0x158 */
+#define BONITO_PCIMSTAT         (0x5c >> 2)      /* 0x15c */
+
+/* 7. other*/
+#define BONITO_TIMECFG          (0x60 >> 2)      /* 0x160 */
+#define BONITO_CPUCFG           (0x64 >> 2)      /* 0x164 */
+#define BONITO_DQCFG            (0x68 >> 2)      /* 0x168 */
+#define BONITO_MEMSIZE          (0x6C >> 2)      /* 0x16c */
+
+#define BONITO_REGS             (0x70 >> 2)
+
+/* PCI config for south bridge. type 0 */
+#define BONITO_PCICONF_IDSEL_MASK      0xfffff800     /* [31:11] */
+#define BONITO_PCICONF_IDSEL_OFFSET    11
+#define BONITO_PCICONF_FUN_MASK        0x700    /* [10:8] */
+#define BONITO_PCICONF_FUN_OFFSET      8
+#define BONITO_PCICONF_REG_MASK        0xFC
+#define BONITO_PCICONF_REG_OFFSET      0
+
+
+/* idsel BIT = pci slot number +12 */
+#define PCI_SLOT_BASE              12
+#define PCI_IDSEL_VIA686B_BIT      (17)
+#define PCI_IDSEL_VIA686B          (1<<PCI_IDSEL_VIA686B_BIT)
+
+#define PCI_ADDR(busno,devno,funno,regno)  \
+    ((((busno)<<16)&0xff0000) + (((devno)<<11)&0xf800) + (((funno)<<8)&0x700) + (regno))
+
+#define TYPE_BONITO_PCI_HOST_BRIDGE "Bonito-pcihost"
+
+typedef struct BonitoState BonitoState;
+
+typedef struct PCIBonitoState
+{
+    PCIDevice dev;
+
+    BonitoState *pcihost;
+    uint32_t regs[BONITO_REGS];
+
+    struct bonldma {
+        uint32_t ldmactrl;
+        uint32_t ldmastat;
+        uint32_t ldmaaddr;
+        uint32_t ldmago;
+    } bonldma;
+
+    /* Based at 1fe00300, bonito Copier */
+    struct boncop {
+        uint32_t copctrl;
+        uint32_t copstat;
+        uint32_t coppaddr;
+        uint32_t copgo;
+    } boncop;
+
+    /* Bonito registers */
+    MemoryRegion iomem;
+    MemoryRegion iomem_ldma;
+    MemoryRegion iomem_cop;
+
+    hwaddr bonito_pciio_start;
+    hwaddr bonito_pciio_length;
+    int bonito_pciio_handle;
+
+    hwaddr bonito_localio_start;
+    hwaddr bonito_localio_length;
+    int bonito_localio_handle;
+
+} PCIBonitoState;
+
+#define BONITO_PCI_HOST_BRIDGE(obj) \
+    OBJECT_CHECK(BonitoState, (obj), TYPE_BONITO_PCI_HOST_BRIDGE)
+
+struct BonitoState {
+    PCIHostState parent_obj;
+
+    qemu_irq *pic;
+
+    PCIBonitoState *pci_dev;
+};
+
+static void bonito_writel(void *opaque, hwaddr addr,
+                          uint64_t val, unsigned size)
+{
+    PCIBonitoState *s = opaque;
+    uint32_t saddr;
+    int reset = 0;
+
+    saddr = (addr - BONITO_REGBASE) >> 2;
+
+    DPRINTF("bonito_writel "TARGET_FMT_plx" val %x saddr %x\n", addr, val, saddr);
+    switch (saddr) {
+    case BONITO_BONPONCFG:
+    case BONITO_IODEVCFG:
+    case BONITO_SDCFG:
+    case BONITO_PCIMAP:
+    case BONITO_PCIMEMBASECFG:
+    case BONITO_PCIMAP_CFG:
+    case BONITO_GPIODATA:
+    case BONITO_GPIOIE:
+    case BONITO_INTEDGE:
+    case BONITO_INTSTEER:
+    case BONITO_INTPOL:
+    case BONITO_PCIMAIL0:
+    case BONITO_PCIMAIL1:
+    case BONITO_PCIMAIL2:
+    case BONITO_PCIMAIL3:
+    case BONITO_PCICACHECTRL:
+    case BONITO_PCICACHETAG:
+    case BONITO_PCIBADADDR:
+    case BONITO_PCIMSTAT:
+    case BONITO_TIMECFG:
+    case BONITO_CPUCFG:
+    case BONITO_DQCFG:
+    case BONITO_MEMSIZE:
+        s->regs[saddr] = val;
+        break;
+    case BONITO_BONGENCFG:
+        if (!(s->regs[saddr] & 0x04) && (val & 0x04)) {
+            reset = 1; /* bit 2 jump from 0 to 1 cause reset */
+        }
+        s->regs[saddr] = val;
+        if (reset) {
+            qemu_system_reset_request();
+        }
+        break;
+    case BONITO_INTENSET:
+        s->regs[BONITO_INTENSET] = val;
+        s->regs[BONITO_INTEN] |= val;
+        break;
+    case BONITO_INTENCLR:
+        s->regs[BONITO_INTENCLR] = val;
+        s->regs[BONITO_INTEN] &= ~val;
+        break;
+    case BONITO_INTEN:
+    case BONITO_INTISR:
+        DPRINTF("write to readonly bonito register %x\n", saddr);
+        break;
+    default:
+        DPRINTF("write to unknown bonito register %x\n", saddr);
+        break;
+    }
+}
+
+static uint64_t bonito_readl(void *opaque, hwaddr addr,
+                             unsigned size)
+{
+    PCIBonitoState *s = opaque;
+    uint32_t saddr;
+
+    saddr = (addr - BONITO_REGBASE) >> 2;
+
+    DPRINTF("bonito_readl "TARGET_FMT_plx"\n", addr);
+    switch (saddr) {
+    case BONITO_INTISR:
+        return s->regs[saddr];
+    default:
+        return s->regs[saddr];
+    }
+}
+
+static const MemoryRegionOps bonito_ops = {
+    .read = bonito_readl,
+    .write = bonito_writel,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static void bonito_pciconf_writel(void *opaque, hwaddr addr,
+                                  uint64_t val, unsigned size)
+{
+    PCIBonitoState *s = opaque;
+    PCIDevice *d = PCI_DEVICE(s);
+
+    DPRINTF("bonito_pciconf_writel "TARGET_FMT_plx" val %x\n", addr, val);
+    d->config_write(d, addr, val, 4);
+}
+
+static uint64_t bonito_pciconf_readl(void *opaque, hwaddr addr,
+                                     unsigned size)
+{
+
+    PCIBonitoState *s = opaque;
+    PCIDevice *d = PCI_DEVICE(s);
+
+    DPRINTF("bonito_pciconf_readl "TARGET_FMT_plx"\n", addr);
+    return d->config_read(d, addr, 4);
+}
+
+/* north bridge PCI configure space. 0x1fe0 0000 - 0x1fe0 00ff */
+
+static const MemoryRegionOps bonito_pciconf_ops = {
+    .read = bonito_pciconf_readl,
+    .write = bonito_pciconf_writel,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static uint64_t bonito_ldma_readl(void *opaque, hwaddr addr,
+                                  unsigned size)
+{
+    uint32_t val;
+    PCIBonitoState *s = opaque;
+
+    val = ((uint32_t *)(&s->bonldma))[addr/sizeof(uint32_t)];
+
+    return val;
+}
+
+static void bonito_ldma_writel(void *opaque, hwaddr addr,
+                               uint64_t val, unsigned size)
+{
+    PCIBonitoState *s = opaque;
+
+    ((uint32_t *)(&s->bonldma))[addr/sizeof(uint32_t)] = val & 0xffffffff;
+}
+
+static const MemoryRegionOps bonito_ldma_ops = {
+    .read = bonito_ldma_readl,
+    .write = bonito_ldma_writel,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static uint64_t bonito_cop_readl(void *opaque, hwaddr addr,
+                                 unsigned size)
+{
+    uint32_t val;
+    PCIBonitoState *s = opaque;
+
+    val = ((uint32_t *)(&s->boncop))[addr/sizeof(uint32_t)];
+
+    return val;
+}
+
+static void bonito_cop_writel(void *opaque, hwaddr addr,
+                              uint64_t val, unsigned size)
+{
+    PCIBonitoState *s = opaque;
+
+    ((uint32_t *)(&s->boncop))[addr/sizeof(uint32_t)] = val & 0xffffffff;
+}
+
+static const MemoryRegionOps bonito_cop_ops = {
+    .read = bonito_cop_readl,
+    .write = bonito_cop_writel,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static uint32_t bonito_sbridge_pciaddr(void *opaque, hwaddr addr)
+{
+    PCIBonitoState *s = opaque;
+    PCIHostState *phb = PCI_HOST_BRIDGE(s->pcihost);
+    uint32_t cfgaddr;
+    uint32_t idsel;
+    uint32_t devno;
+    uint32_t funno;
+    uint32_t regno;
+    uint32_t pciaddr;
+
+    /* support type0 pci config */
+    if ((s->regs[BONITO_PCIMAP_CFG] & 0x10000) != 0x0) {
+        return 0xffffffff;
+    }
+
+    cfgaddr = addr & 0xffff;
+    cfgaddr |= (s->regs[BONITO_PCIMAP_CFG] & 0xffff) << 16;
+
+    idsel = (cfgaddr & BONITO_PCICONF_IDSEL_MASK) >> BONITO_PCICONF_IDSEL_OFFSET;
+    devno = ffs(idsel) - 1;
+    funno = (cfgaddr & BONITO_PCICONF_FUN_MASK) >> BONITO_PCICONF_FUN_OFFSET;
+    regno = (cfgaddr & BONITO_PCICONF_REG_MASK) >> BONITO_PCICONF_REG_OFFSET;
+
+    if (idsel == 0) {
+        fprintf(stderr, "error in bonito pci config address " TARGET_FMT_plx
+            ",pcimap_cfg=%x\n", addr, s->regs[BONITO_PCIMAP_CFG]);
+        exit(1);
+    }
+    pciaddr = PCI_ADDR(pci_bus_num(phb->bus), devno, funno, regno);
+    DPRINTF("cfgaddr %x pciaddr %x busno %x devno %d funno %d regno %d\n",
+        cfgaddr, pciaddr, pci_bus_num(phb->bus), devno, funno, regno);
+
+    return pciaddr;
+}
+
+static void bonito_spciconf_writeb(void *opaque, hwaddr addr,
+                                   uint32_t val)
+{
+    PCIBonitoState *s = opaque;
+    PCIDevice *d = PCI_DEVICE(s);
+    PCIHostState *phb = PCI_HOST_BRIDGE(s->pcihost);
+    uint32_t pciaddr;
+    uint16_t status;
+
+    DPRINTF("bonito_spciconf_writeb "TARGET_FMT_plx" val %x\n", addr, val);
+    pciaddr = bonito_sbridge_pciaddr(s, addr);
+
+    if (pciaddr == 0xffffffff) {
+        return;
+    }
+
+    /* set the pci address in s->config_reg */
+    phb->config_reg = (pciaddr) | (1u << 31);
+    pci_data_write(phb->bus, phb->config_reg, val & 0xff, 1);
+
+    /* clear PCI_STATUS_REC_MASTER_ABORT and PCI_STATUS_REC_TARGET_ABORT */
+    status = pci_get_word(d->config + PCI_STATUS);
+    status &= ~(PCI_STATUS_REC_MASTER_ABORT | PCI_STATUS_REC_TARGET_ABORT);
+    pci_set_word(d->config + PCI_STATUS, status);
+}
+
+static void bonito_spciconf_writew(void *opaque, hwaddr addr,
+                                   uint32_t val)
+{
+    PCIBonitoState *s = opaque;
+    PCIDevice *d = PCI_DEVICE(s);
+    PCIHostState *phb = PCI_HOST_BRIDGE(s->pcihost);
+    uint32_t pciaddr;
+    uint16_t status;
+
+    DPRINTF("bonito_spciconf_writew "TARGET_FMT_plx" val %x\n", addr, val);
+    assert((addr & 0x1) == 0);
+
+    pciaddr = bonito_sbridge_pciaddr(s, addr);
+
+    if (pciaddr == 0xffffffff) {
+        return;
+    }
+
+    /* set the pci address in s->config_reg */
+    phb->config_reg = (pciaddr) | (1u << 31);
+    pci_data_write(phb->bus, phb->config_reg, val, 2);
+
+    /* clear PCI_STATUS_REC_MASTER_ABORT and PCI_STATUS_REC_TARGET_ABORT */
+    status = pci_get_word(d->config + PCI_STATUS);
+    status &= ~(PCI_STATUS_REC_MASTER_ABORT | PCI_STATUS_REC_TARGET_ABORT);
+    pci_set_word(d->config + PCI_STATUS, status);
+}
+
+static void bonito_spciconf_writel(void *opaque, hwaddr addr,
+                                   uint32_t val)
+{
+    PCIBonitoState *s = opaque;
+    PCIDevice *d = PCI_DEVICE(s);
+    PCIHostState *phb = PCI_HOST_BRIDGE(s->pcihost);
+    uint32_t pciaddr;
+    uint16_t status;
+
+    DPRINTF("bonito_spciconf_writel "TARGET_FMT_plx" val %x\n", addr, val);
+    assert((addr & 0x3) == 0);
+
+    pciaddr = bonito_sbridge_pciaddr(s, addr);
+
+    if (pciaddr == 0xffffffff) {
+        return;
+    }
+
+    /* set the pci address in s->config_reg */
+    phb->config_reg = (pciaddr) | (1u << 31);
+    pci_data_write(phb->bus, phb->config_reg, val, 4);
+
+    /* clear PCI_STATUS_REC_MASTER_ABORT and PCI_STATUS_REC_TARGET_ABORT */
+    status = pci_get_word(d->config + PCI_STATUS);
+    status &= ~(PCI_STATUS_REC_MASTER_ABORT | PCI_STATUS_REC_TARGET_ABORT);
+    pci_set_word(d->config + PCI_STATUS, status);
+}
+
+static uint32_t bonito_spciconf_readb(void *opaque, hwaddr addr)
+{
+    PCIBonitoState *s = opaque;
+    PCIDevice *d = PCI_DEVICE(s);
+    PCIHostState *phb = PCI_HOST_BRIDGE(s->pcihost);
+    uint32_t pciaddr;
+    uint16_t status;
+
+    DPRINTF("bonito_spciconf_readb "TARGET_FMT_plx"\n", addr);
+    pciaddr = bonito_sbridge_pciaddr(s, addr);
+
+    if (pciaddr == 0xffffffff) {
+        return 0xff;
+    }
+
+    /* set the pci address in s->config_reg */
+    phb->config_reg = (pciaddr) | (1u << 31);
+
+    /* clear PCI_STATUS_REC_MASTER_ABORT and PCI_STATUS_REC_TARGET_ABORT */
+    status = pci_get_word(d->config + PCI_STATUS);
+    status &= ~(PCI_STATUS_REC_MASTER_ABORT | PCI_STATUS_REC_TARGET_ABORT);
+    pci_set_word(d->config + PCI_STATUS, status);
+
+    return pci_data_read(phb->bus, phb->config_reg, 1);
+}
+
+static uint32_t bonito_spciconf_readw(void *opaque, hwaddr addr)
+{
+    PCIBonitoState *s = opaque;
+    PCIDevice *d = PCI_DEVICE(s);
+    PCIHostState *phb = PCI_HOST_BRIDGE(s->pcihost);
+    uint32_t pciaddr;
+    uint16_t status;
+
+    DPRINTF("bonito_spciconf_readw "TARGET_FMT_plx"\n", addr);
+    assert((addr & 0x1) == 0);
+
+    pciaddr = bonito_sbridge_pciaddr(s, addr);
+
+    if (pciaddr == 0xffffffff) {
+        return 0xffff;
+    }
+
+    /* set the pci address in s->config_reg */
+    phb->config_reg = (pciaddr) | (1u << 31);
+
+    /* clear PCI_STATUS_REC_MASTER_ABORT and PCI_STATUS_REC_TARGET_ABORT */
+    status = pci_get_word(d->config + PCI_STATUS);
+    status &= ~(PCI_STATUS_REC_MASTER_ABORT | PCI_STATUS_REC_TARGET_ABORT);
+    pci_set_word(d->config + PCI_STATUS, status);
+
+    return pci_data_read(phb->bus, phb->config_reg, 2);
+}
+
+static uint32_t bonito_spciconf_readl(void *opaque, hwaddr addr)
+{
+    PCIBonitoState *s = opaque;
+    PCIDevice *d = PCI_DEVICE(s);
+    PCIHostState *phb = PCI_HOST_BRIDGE(s->pcihost);
+    uint32_t pciaddr;
+    uint16_t status;
+
+    DPRINTF("bonito_spciconf_readl "TARGET_FMT_plx"\n", addr);
+    assert((addr & 0x3) == 0);
+
+    pciaddr = bonito_sbridge_pciaddr(s, addr);
+
+    if (pciaddr == 0xffffffff) {
+        return 0xffffffff;
+    }
+
+    /* set the pci address in s->config_reg */
+    phb->config_reg = (pciaddr) | (1u << 31);
+
+    /* clear PCI_STATUS_REC_MASTER_ABORT and PCI_STATUS_REC_TARGET_ABORT */
+    status = pci_get_word(d->config + PCI_STATUS);
+    status &= ~(PCI_STATUS_REC_MASTER_ABORT | PCI_STATUS_REC_TARGET_ABORT);
+    pci_set_word(d->config + PCI_STATUS, status);
+
+    return pci_data_read(phb->bus, phb->config_reg, 4);
+}
+
+/* south bridge PCI configure space. 0x1fe8 0000 - 0x1fef ffff */
+static const MemoryRegionOps bonito_spciconf_ops = {
+    .old_mmio = {
+        .read = {
+            bonito_spciconf_readb,
+            bonito_spciconf_readw,
+            bonito_spciconf_readl,
+        },
+        .write = {
+            bonito_spciconf_writeb,
+            bonito_spciconf_writew,
+            bonito_spciconf_writel,
+        },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+#define BONITO_IRQ_BASE 32
+
+static void pci_bonito_set_irq(void *opaque, int irq_num, int level)
+{
+    BonitoState *s = opaque;
+    qemu_irq *pic = s->pic;
+    PCIBonitoState *bonito_state = s->pci_dev;
+    int internal_irq = irq_num - BONITO_IRQ_BASE;
+
+    if (bonito_state->regs[BONITO_INTEDGE] & (1 << internal_irq)) {
+        qemu_irq_pulse(*pic);
+    } else {   /* level triggered */
+        if (bonito_state->regs[BONITO_INTPOL] & (1 << internal_irq)) {
+            qemu_irq_raise(*pic);
+        } else {
+            qemu_irq_lower(*pic);
+        }
+    }
+}
+
+/* map the original irq (0~3) to bonito irq (16~47, but 16~31 are unused) */
+static int pci_bonito_map_irq(PCIDevice * pci_dev, int irq_num)
+{
+    int slot;
+
+    slot = (pci_dev->devfn >> 3);
+
+    switch (slot) {
+    case 5:   /* FULONG2E_VIA_SLOT, SouthBridge, IDE, USB, ACPI, AC97, MC97 */
+        return irq_num % 4 + BONITO_IRQ_BASE;
+    case 6:   /* FULONG2E_ATI_SLOT, VGA */
+        return 4 + BONITO_IRQ_BASE;
+    case 7:   /* FULONG2E_RTL_SLOT, RTL8139 */
+        return 5 + BONITO_IRQ_BASE;
+    case 8 ... 12: /* PCI slot 1 to 4 */
+        return (slot - 8 + irq_num) + 6 + BONITO_IRQ_BASE;
+    default:  /* Unknown device, don't do any translation */
+        return irq_num;
+    }
+}
+
+static void bonito_reset(void *opaque)
+{
+    PCIBonitoState *s = opaque;
+
+    /* set the default value of north bridge registers */
+
+    s->regs[BONITO_BONPONCFG] = 0xc40;
+    s->regs[BONITO_BONGENCFG] = 0x1384;
+    s->regs[BONITO_IODEVCFG] = 0x2bff8010;
+    s->regs[BONITO_SDCFG] = 0x255e0091;
+
+    s->regs[BONITO_GPIODATA] = 0x1ff;
+    s->regs[BONITO_GPIOIE] = 0x1ff;
+    s->regs[BONITO_DQCFG] = 0x8;
+    s->regs[BONITO_MEMSIZE] = 0x10000000;
+    s->regs[BONITO_PCIMAP] = 0x6140;
+}
+
+static const VMStateDescription vmstate_bonito = {
+    .name = "Bonito",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_PCI_DEVICE(dev, PCIBonitoState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int bonito_pcihost_initfn(SysBusDevice *dev)
+{
+    PCIHostState *phb = PCI_HOST_BRIDGE(dev);
+
+    phb->bus = pci_register_bus(DEVICE(dev), "pci",
+                                pci_bonito_set_irq, pci_bonito_map_irq, dev,
+                                get_system_memory(), get_system_io(),
+                                0x28, 32, TYPE_PCI_BUS);
+
+    return 0;
+}
+
+static int bonito_initfn(PCIDevice *dev)
+{
+    PCIBonitoState *s = DO_UPCAST(PCIBonitoState, dev, dev);
+    SysBusDevice *sysbus = SYS_BUS_DEVICE(s->pcihost);
+    PCIHostState *phb = PCI_HOST_BRIDGE(s->pcihost);
+
+    /* Bonito North Bridge, built on FPGA, VENDOR_ID/DEVICE_ID are "undefined" */
+    pci_config_set_prog_interface(dev->config, 0x00);
+
+    /* set the north bridge register mapping */
+    memory_region_init_io(&s->iomem, &bonito_ops, s,
+                          "north-bridge-register", BONITO_INTERNAL_REG_SIZE);
+    sysbus_init_mmio(sysbus, &s->iomem);
+    sysbus_mmio_map(sysbus, 0, BONITO_INTERNAL_REG_BASE);
+
+    /* set the north bridge pci configure  mapping */
+    memory_region_init_io(&phb->conf_mem, &bonito_pciconf_ops, s,
+                          "north-bridge-pci-config", BONITO_PCICONFIG_SIZE);
+    sysbus_init_mmio(sysbus, &phb->conf_mem);
+    sysbus_mmio_map(sysbus, 1, BONITO_PCICONFIG_BASE);
+
+    /* set the south bridge pci configure  mapping */
+    memory_region_init_io(&phb->data_mem, &bonito_spciconf_ops, s,
+                          "south-bridge-pci-config", BONITO_SPCICONFIG_SIZE);
+    sysbus_init_mmio(sysbus, &phb->data_mem);
+    sysbus_mmio_map(sysbus, 2, BONITO_SPCICONFIG_BASE);
+
+    memory_region_init_io(&s->iomem_ldma, &bonito_ldma_ops, s,
+                          "ldma", 0x100);
+    sysbus_init_mmio(sysbus, &s->iomem_ldma);
+    sysbus_mmio_map(sysbus, 3, 0xbfe00200);
+
+    memory_region_init_io(&s->iomem_cop, &bonito_cop_ops, s,
+                          "cop", 0x100);
+    sysbus_init_mmio(sysbus, &s->iomem_cop);
+    sysbus_mmio_map(sysbus, 4, 0xbfe00300);
+
+    /* Map PCI IO Space  0x1fd0 0000 - 0x1fd1 0000 */
+    s->bonito_pciio_start = BONITO_PCIIO_BASE;
+    s->bonito_pciio_length = BONITO_PCIIO_SIZE;
+    isa_mem_base = s->bonito_pciio_start;
+    isa_mmio_init(s->bonito_pciio_start, s->bonito_pciio_length);
+
+    /* add pci local io mapping */
+    s->bonito_localio_start = BONITO_DEV_BASE;
+    s->bonito_localio_length = BONITO_DEV_SIZE;
+    isa_mmio_init(s->bonito_localio_start, s->bonito_localio_length);
+
+    /* set the default value of north bridge pci config */
+    pci_set_word(dev->config + PCI_COMMAND, 0x0000);
+    pci_set_word(dev->config + PCI_STATUS, 0x0000);
+    pci_set_word(dev->config + PCI_SUBSYSTEM_VENDOR_ID, 0x0000);
+    pci_set_word(dev->config + PCI_SUBSYSTEM_ID, 0x0000);
+
+    pci_set_byte(dev->config + PCI_INTERRUPT_LINE, 0x00);
+    pci_set_byte(dev->config + PCI_INTERRUPT_PIN, 0x01);
+    pci_set_byte(dev->config + PCI_MIN_GNT, 0x3c);
+    pci_set_byte(dev->config + PCI_MAX_LAT, 0x00);
+
+    qemu_register_reset(bonito_reset, s);
+
+    return 0;
+}
+
+PCIBus *bonito_init(qemu_irq *pic)
+{
+    DeviceState *dev;
+    BonitoState *pcihost;
+    PCIHostState *phb;
+    PCIBonitoState *s;
+    PCIDevice *d;
+
+    dev = qdev_create(NULL, TYPE_BONITO_PCI_HOST_BRIDGE);
+    phb = PCI_HOST_BRIDGE(dev);
+    pcihost = BONITO_PCI_HOST_BRIDGE(dev);
+    pcihost->pic = pic;
+    qdev_init_nofail(dev);
+
+    /* set the pcihost pointer before bonito_initfn is called */
+    d = pci_create(phb->bus, PCI_DEVFN(0, 0), "Bonito");
+    s = DO_UPCAST(PCIBonitoState, dev, d);
+    s->pcihost = pcihost;
+    pcihost->pci_dev = s;
+    qdev_init_nofail(DEVICE(d));
+
+    return phb->bus;
+}
+
+static void bonito_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = bonito_initfn;
+    k->vendor_id = 0xdf53;
+    k->device_id = 0x00d5;
+    k->revision = 0x01;
+    k->class_id = PCI_CLASS_BRIDGE_HOST;
+    dc->desc = "Host bridge";
+    dc->no_user = 1;
+    dc->vmsd = &vmstate_bonito;
+}
+
+static const 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 const TypeInfo bonito_pcihost_info = {
+    .name          = TYPE_BONITO_PCI_HOST_BRIDGE,
+    .parent        = TYPE_PCI_HOST_BRIDGE,
+    .instance_size = sizeof(BonitoState),
+    .class_init    = bonito_pcihost_class_init,
+};
+
+static void bonito_register_types(void)
+{
+    type_register_static(&bonito_pcihost_info);
+    type_register_static(&bonito_info);
+}
+
+type_init(bonito_register_types)
diff --git a/hw/pci-host/dec.c b/hw/pci-host/dec.c
new file mode 100644 (file)
index 0000000..cff458b
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * QEMU DEC 21154 PCI bridge
+ *
+ * Copyright (c) 2006-2007 Fabrice Bellard
+ * Copyright (c) 2007 Jocelyn Mayer
+ *
+ * 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 "dec.h"
+#include "hw/sysbus.h"
+#include "hw/pci/pci.h"
+#include "hw/pci/pci_host.h"
+#include "hw/pci/pci_bridge.h"
+#include "hw/pci/pci_bus.h"
+
+/* debug DEC */
+//#define DEBUG_DEC
+
+#ifdef DEBUG_DEC
+#define DEC_DPRINTF(fmt, ...)                               \
+    do { printf("DEC: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DEC_DPRINTF(fmt, ...)
+#endif
+
+#define DEC_21154(obj) OBJECT_CHECK(DECState, (obj), TYPE_DEC_21154)
+
+typedef struct DECState {
+    PCIHostState parent_obj;
+} DECState;
+
+static int dec_map_irq(PCIDevice *pci_dev, int irq_num)
+{
+    return irq_num;
+}
+
+static int dec_pci_bridge_initfn(PCIDevice *pci_dev)
+{
+    return pci_bridge_initfn(pci_dev, TYPE_PCI_BUS);
+}
+
+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 = dec_pci_bridge_initfn;
+    k->exit = pci_bridge_exitfn;
+    k->vendor_id = PCI_VENDOR_ID_DEC;
+    k->device_id = PCI_DEVICE_ID_DEC_21154;
+    k->config_write = pci_bridge_write_config;
+    k->is_bridge = 1;
+    dc->desc = "DEC 21154 PCI-PCI bridge";
+    dc->reset = pci_bridge_reset;
+    dc->vmsd = &vmstate_pci_device;
+}
+
+static const 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)
+{
+    PCIDevice *dev;
+    PCIBridge *br;
+
+    dev = pci_create_multifunction(parent_bus, devfn, false,
+                                   "dec-21154-p2p-bridge");
+    br = DO_UPCAST(PCIBridge, dev, dev);
+    pci_bridge_map_irq(br, "DEC 21154 PCI-PCI bridge", dec_map_irq);
+    qdev_init_nofail(&dev->qdev);
+    return pci_bridge_get_sec_bus(br);
+}
+
+static int pci_dec_21154_device_init(SysBusDevice *dev)
+{
+    PCIHostState *phb;
+
+    phb = PCI_HOST_BRIDGE(dev);
+
+    memory_region_init_io(&phb->conf_mem, &pci_host_conf_le_ops,
+                          dev, "pci-conf-idx", 0x1000);
+    memory_region_init_io(&phb->data_mem, &pci_host_data_le_ops,
+                          dev, "pci-data-idx", 0x1000);
+    sysbus_init_mmio(dev, &phb->conf_mem);
+    sysbus_init_mmio(dev, &phb->data_mem);
+    return 0;
+}
+
+static int dec_21154_pci_host_init(PCIDevice *d)
+{
+    /* PCI2PCI bridge same values as PearPC - check this */
+    return 0;
+}
+
+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 const TypeInfo dec_21154_pci_host_info = {
+    .name          = "dec-21154",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PCIDevice),
+    .class_init    = dec_21154_pci_host_class_init,
+};
+
+static void pci_dec_21154_device_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sdc->init = pci_dec_21154_device_init;
+}
+
+static const TypeInfo pci_dec_21154_device_info = {
+    .name          = TYPE_DEC_21154,
+    .parent        = TYPE_PCI_HOST_BRIDGE,
+    .instance_size = sizeof(DECState),
+    .class_init    = pci_dec_21154_device_class_init,
+};
+
+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);
+}
+
+type_init(dec_register_types)
diff --git a/hw/pci-host/dec.h b/hw/pci-host/dec.h
new file mode 100644 (file)
index 0000000..17dc0c2
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef DEC_PCI_H
+#define DEC_PCI_H
+
+#include "qemu-common.h"
+
+#define TYPE_DEC_21154 "dec-21154-sysbus"
+
+PCIBus *pci_dec_21154_init(PCIBus *parent_bus, int devfn);
+
+#endif
diff --git a/hw/pci-host/grackle.c b/hw/pci-host/grackle.c
new file mode 100644 (file)
index 0000000..69344d9
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * QEMU Grackle PCI host (heathrow OldWorld PowerMac)
+ *
+ * Copyright (c) 2006-2007 Fabrice Bellard
+ * Copyright (c) 2007 Jocelyn Mayer
+ *
+ * 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 "hw/pci/pci_host.h"
+#include "hw/ppc/mac.h"
+#include "hw/pci/pci.h"
+
+/* debug Grackle */
+//#define DEBUG_GRACKLE
+
+#ifdef DEBUG_GRACKLE
+#define GRACKLE_DPRINTF(fmt, ...)                               \
+    do { printf("GRACKLE: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define GRACKLE_DPRINTF(fmt, ...)
+#endif
+
+#define GRACKLE_PCI_HOST_BRIDGE(obj) \
+    OBJECT_CHECK(GrackleState, (obj), TYPE_GRACKLE_PCI_HOST_BRIDGE)
+
+typedef struct GrackleState {
+    PCIHostState parent_obj;
+
+    MemoryRegion pci_mmio;
+    MemoryRegion pci_hole;
+} GrackleState;
+
+/* Don't know if this matches real hardware, but it agrees with OHW.  */
+static int pci_grackle_map_irq(PCIDevice *pci_dev, int irq_num)
+{
+    return (irq_num + (pci_dev->devfn >> 3)) & 3;
+}
+
+static void pci_grackle_set_irq(void *opaque, int irq_num, int level)
+{
+    qemu_irq *pic = opaque;
+
+    GRACKLE_DPRINTF("set_irq num %d level %d\n", irq_num, level);
+    qemu_set_irq(pic[irq_num + 0x15], level);
+}
+
+PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic,
+                         MemoryRegion *address_space_mem,
+                         MemoryRegion *address_space_io)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+    PCIHostState *phb;
+    GrackleState *d;
+
+    dev = qdev_create(NULL, TYPE_GRACKLE_PCI_HOST_BRIDGE);
+    qdev_init_nofail(dev);
+    s = SYS_BUS_DEVICE(dev);
+    phb = PCI_HOST_BRIDGE(dev);
+    d = GRACKLE_PCI_HOST_BRIDGE(dev);
+
+    memory_region_init(&d->pci_mmio, "pci-mmio", 0x100000000ULL);
+    memory_region_init_alias(&d->pci_hole, "pci-hole", &d->pci_mmio,
+                             0x80000000ULL, 0x7e000000ULL);
+    memory_region_add_subregion(address_space_mem, 0x80000000ULL,
+                                &d->pci_hole);
+
+    phb->bus = pci_register_bus(dev, "pci",
+                                pci_grackle_set_irq,
+                                pci_grackle_map_irq,
+                                pic,
+                                &d->pci_mmio,
+                                address_space_io,
+                                0, 4, TYPE_PCI_BUS);
+
+    pci_create_simple(phb->bus, 0, "grackle");
+
+    sysbus_mmio_map(s, 0, base);
+    sysbus_mmio_map(s, 1, base + 0x00200000);
+
+    return phb->bus;
+}
+
+static int pci_grackle_init_device(SysBusDevice *dev)
+{
+    PCIHostState *phb;
+
+    phb = PCI_HOST_BRIDGE(dev);
+
+    memory_region_init_io(&phb->conf_mem, &pci_host_conf_le_ops,
+                          dev, "pci-conf-idx", 0x1000);
+    memory_region_init_io(&phb->data_mem, &pci_host_data_le_ops,
+                          dev, "pci-data-idx", 0x1000);
+    sysbus_init_mmio(dev, &phb->conf_mem);
+    sysbus_init_mmio(dev, &phb->data_mem);
+
+    return 0;
+}
+
+static int grackle_pci_host_init(PCIDevice *d)
+{
+    d->config[0x09] = 0x01;
+    return 0;
+}
+
+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 const 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 const TypeInfo grackle_pci_host_info = {
+    .name          = TYPE_GRACKLE_PCI_HOST_BRIDGE,
+    .parent        = TYPE_PCI_HOST_BRIDGE,
+    .instance_size = sizeof(GrackleState),
+    .class_init    = pci_grackle_class_init,
+};
+
+static void grackle_register_types(void)
+{
+    type_register_static(&grackle_pci_info);
+    type_register_static(&grackle_pci_host_info);
+}
+
+type_init(grackle_register_types)
diff --git a/hw/pci-host/pam.c b/hw/pci-host/pam.c
new file mode 100644 (file)
index 0000000..7181bd6
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * QEMU i440FX/PIIX3 PCI Bridge Emulation
+ *
+ * Copyright (c) 2006 Fabrice Bellard
+ * Copyright (c) 2011 Isaku Yamahata <yamahata at valinux co jp>
+ *                    VA Linux Systems Japan K.K.
+ * Copyright (c) 2012 Jason Baron <jbaron@redhat.com>
+ *
+ * Split out from piix_pci.c
+ *
+ * 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 "sysemu/sysemu.h"
+#include "hw/pci-host/pam.h"
+
+void smram_update(MemoryRegion *smram_region, uint8_t smram,
+                  uint8_t smm_enabled)
+{
+    bool smram_enabled;
+
+    smram_enabled = ((smm_enabled && (smram & SMRAM_G_SMRAME)) ||
+                        (smram & SMRAM_D_OPEN));
+    memory_region_set_enabled(smram_region, !smram_enabled);
+}
+
+void smram_set_smm(uint8_t *host_smm_enabled, int smm, uint8_t smram,
+                   MemoryRegion *smram_region)
+{
+    uint8_t smm_enabled = (smm != 0);
+    if (*host_smm_enabled != smm_enabled) {
+        *host_smm_enabled = smm_enabled;
+        smram_update(smram_region, smram, *host_smm_enabled);
+    }
+}
+
+void init_pam(MemoryRegion *ram_memory, MemoryRegion *system_memory,
+              MemoryRegion *pci_address_space, PAMMemoryRegion *mem,
+              uint32_t start, uint32_t size)
+{
+    int i;
+
+    /* RAM */
+    memory_region_init_alias(&mem->alias[3], "pam-ram", ram_memory,
+                             start, size);
+    /* ROM (XXX: not quite correct) */
+    memory_region_init_alias(&mem->alias[1], "pam-rom", ram_memory,
+                             start, size);
+    memory_region_set_readonly(&mem->alias[1], true);
+
+    /* XXX: should distinguish read/write cases */
+    memory_region_init_alias(&mem->alias[0], "pam-pci", pci_address_space,
+                             start, size);
+    memory_region_init_alias(&mem->alias[2], "pam-pci", pci_address_space,
+                             start, size);
+
+    for (i = 0; i < 4; ++i) {
+        memory_region_set_enabled(&mem->alias[i], false);
+        memory_region_add_subregion_overlap(system_memory, start,
+                                            &mem->alias[i], 1);
+    }
+    mem->current = 0;
+}
+
+void pam_update(PAMMemoryRegion *pam, int idx, uint8_t val)
+{
+    assert(0 <= idx && idx <= 12);
+
+    memory_region_set_enabled(&pam->alias[pam->current], false);
+    pam->current = (val >> ((!(idx & 1)) * 4)) & PAM_ATTR_MASK;
+    memory_region_set_enabled(&pam->alias[pam->current], true);
+}
diff --git a/hw/pci-host/piix.c b/hw/pci-host/piix.c
new file mode 100644 (file)
index 0000000..f9e68c3
--- /dev/null
@@ -0,0 +1,657 @@
+/*
+ * QEMU i440FX/PIIX3 PCI Bridge Emulation
+ *
+ * Copyright (c) 2006 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.
+ */
+
+#include "hw/hw.h"
+#include "hw/i386/pc.h"
+#include "hw/pci/pci.h"
+#include "hw/pci/pci_host.h"
+#include "hw/isa/isa.h"
+#include "hw/sysbus.h"
+#include "qemu/range.h"
+#include "hw/xen/xen.h"
+#include "hw/pci-host/pam.h"
+#include "sysemu/sysemu.h"
+
+/*
+ * I440FX chipset data sheet.
+ * http://download.intel.com/design/chipsets/datashts/29054901.pdf
+ */
+
+typedef struct I440FXState {
+    PCIHostState parent_obj;
+} I440FXState;
+
+#define PIIX_NUM_PIC_IRQS       16      /* i8259 * 2 */
+#define PIIX_NUM_PIRQS          4ULL    /* PIRQ[A-D] */
+#define XEN_PIIX_NUM_PIRQS      128ULL
+#define PIIX_PIRQC              0x60
+
+/*
+ * Reset Control Register: PCI-accessible ISA-Compatible Register at address
+ * 0xcf9, provided by the PCI/ISA bridge (PIIX3 PCI function 0, 8086:7000).
+ */
+#define RCR_IOPORT 0xcf9
+
+typedef struct PIIX3State {
+    PCIDevice dev;
+
+    /*
+     * bitmap to track pic levels.
+     * The pic level is the logical OR of all the PCI irqs mapped to it
+     * So one PIC level is tracked by PIIX_NUM_PIRQS bits.
+     *
+     * PIRQ is mapped to PIC pins, we track it by
+     * PIIX_NUM_PIRQS * PIIX_NUM_PIC_IRQS = 64 bits with
+     * pic_irq * PIIX_NUM_PIRQS + pirq
+     */
+#if PIIX_NUM_PIC_IRQS * PIIX_NUM_PIRQS > 64
+#error "unable to encode pic state in 64bit in pic_levels."
+#endif
+    uint64_t pic_levels;
+
+    qemu_irq *pic;
+
+    /* This member isn't used. Just for save/load compatibility */
+    int32_t pci_irq_levels_vmstate[PIIX_NUM_PIRQS];
+
+    /* Reset Control Register contents */
+    uint8_t rcr;
+
+    /* IO memory region for Reset Control Register (RCR_IOPORT) */
+    MemoryRegion rcr_mem;
+} PIIX3State;
+
+#define TYPE_I440FX_PCI_DEVICE "i440FX"
+#define I440FX_PCI_DEVICE(obj) \
+    OBJECT_CHECK(PCII440FXState, (obj), TYPE_I440FX_PCI_DEVICE)
+
+struct PCII440FXState {
+    PCIDevice dev;
+    MemoryRegion *system_memory;
+    MemoryRegion *pci_address_space;
+    MemoryRegion *ram_memory;
+    MemoryRegion pci_hole;
+    MemoryRegion pci_hole_64bit;
+    PAMMemoryRegion pam_regions[13];
+    MemoryRegion smram_region;
+    uint8_t smm_enabled;
+};
+
+
+#define I440FX_PAM      0x59
+#define I440FX_PAM_SIZE 7
+#define I440FX_SMRAM    0x72
+
+static void piix3_set_irq(void *opaque, int pirq, int level);
+static PCIINTxRoute piix3_route_intx_pin_to_irq(void *opaque, int pci_intx);
+static void piix3_write_config_xen(PCIDevice *dev,
+                               uint32_t address, uint32_t val, int len);
+
+/* return the global irq number corresponding to a given device irq
+   pin. We could also use the bus number to have a more precise
+   mapping. */
+static int pci_slot_get_pirq(PCIDevice *pci_dev, int pci_intx)
+{
+    int slot_addend;
+    slot_addend = (pci_dev->devfn >> 3) - 1;
+    return (pci_intx + slot_addend) & 3;
+}
+
+static void i440fx_update_memory_mappings(PCII440FXState *d)
+{
+    int i;
+
+    memory_region_transaction_begin();
+    for (i = 0; i < 13; i++) {
+        pam_update(&d->pam_regions[i], i,
+                   d->dev.config[I440FX_PAM + ((i + 1) / 2)]);
+    }
+    smram_update(&d->smram_region, d->dev.config[I440FX_SMRAM], d->smm_enabled);
+    memory_region_transaction_commit();
+}
+
+static void i440fx_set_smm(int val, void *arg)
+{
+    PCII440FXState *d = arg;
+
+    memory_region_transaction_begin();
+    smram_set_smm(&d->smm_enabled, val, d->dev.config[I440FX_SMRAM],
+                  &d->smram_region);
+    memory_region_transaction_commit();
+}
+
+
+static void i440fx_write_config(PCIDevice *dev,
+                                uint32_t address, uint32_t val, int len)
+{
+    PCII440FXState *d = I440FX_PCI_DEVICE(dev);
+
+    /* XXX: implement SMRAM.D_LOCK */
+    pci_default_write_config(dev, address, val, len);
+    if (ranges_overlap(address, len, I440FX_PAM, I440FX_PAM_SIZE) ||
+        range_covers_byte(address, len, I440FX_SMRAM)) {
+        i440fx_update_memory_mappings(d);
+    }
+}
+
+static int i440fx_load_old(QEMUFile* f, void *opaque, int version_id)
+{
+    PCII440FXState *d = opaque;
+    int ret, i;
+
+    ret = pci_device_load(&d->dev, f);
+    if (ret < 0)
+        return ret;
+    i440fx_update_memory_mappings(d);
+    qemu_get_8s(f, &d->smm_enabled);
+
+    if (version_id == 2) {
+        for (i = 0; i < PIIX_NUM_PIRQS; i++) {
+            qemu_get_be32(f); /* dummy load for compatibility */
+        }
+    }
+
+    return 0;
+}
+
+static int i440fx_post_load(void *opaque, int version_id)
+{
+    PCII440FXState *d = opaque;
+
+    i440fx_update_memory_mappings(d);
+    return 0;
+}
+
+static const VMStateDescription vmstate_i440fx = {
+    .name = "I440FX",
+    .version_id = 3,
+    .minimum_version_id = 3,
+    .minimum_version_id_old = 1,
+    .load_state_old = i440fx_load_old,
+    .post_load = i440fx_post_load,
+    .fields      = (VMStateField []) {
+        VMSTATE_PCI_DEVICE(dev, PCII440FXState),
+        VMSTATE_UINT8(smm_enabled, PCII440FXState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int i440fx_pcihost_initfn(SysBusDevice *dev)
+{
+    PCIHostState *s = PCI_HOST_BRIDGE(dev);
+
+    memory_region_init_io(&s->conf_mem, &pci_host_conf_le_ops, s,
+                          "pci-conf-idx", 4);
+    sysbus_add_io(dev, 0xcf8, &s->conf_mem);
+    sysbus_init_ioports(&s->busdev, 0xcf8, 4);
+
+    memory_region_init_io(&s->data_mem, &pci_host_data_le_ops, s,
+                          "pci-conf-data", 4);
+    sysbus_add_io(dev, 0xcfc, &s->data_mem);
+    sysbus_init_ioports(&s->busdev, 0xcfc, 4);
+
+    return 0;
+}
+
+static int i440fx_initfn(PCIDevice *dev)
+{
+    PCII440FXState *d = I440FX_PCI_DEVICE(dev);
+
+    d->dev.config[I440FX_SMRAM] = 0x02;
+
+    cpu_smm_register(&i440fx_set_smm, d);
+    return 0;
+}
+
+static PCIBus *i440fx_common_init(const char *device_name,
+                                  PCII440FXState **pi440fx_state,
+                                  int *piix3_devfn,
+                                  ISABus **isa_bus, qemu_irq *pic,
+                                  MemoryRegion *address_space_mem,
+                                  MemoryRegion *address_space_io,
+                                  ram_addr_t ram_size,
+                                  hwaddr pci_hole_start,
+                                  hwaddr pci_hole_size,
+                                  hwaddr pci_hole64_start,
+                                  hwaddr pci_hole64_size,
+                                  MemoryRegion *pci_address_space,
+                                  MemoryRegion *ram_memory)
+{
+    DeviceState *dev;
+    PCIBus *b;
+    PCIDevice *d;
+    PCIHostState *s;
+    PIIX3State *piix3;
+    PCII440FXState *f;
+    unsigned i;
+
+    dev = qdev_create(NULL, "i440FX-pcihost");
+    s = PCI_HOST_BRIDGE(dev);
+    b = pci_bus_new(dev, NULL, pci_address_space,
+                    address_space_io, 0, TYPE_PCI_BUS);
+    s->bus = b;
+    object_property_add_child(qdev_get_machine(), "i440fx", OBJECT(dev), NULL);
+    qdev_init_nofail(dev);
+
+    d = pci_create_simple(b, 0, device_name);
+    *pi440fx_state = I440FX_PCI_DEVICE(d);
+    f = *pi440fx_state;
+    f->system_memory = address_space_mem;
+    f->pci_address_space = pci_address_space;
+    f->ram_memory = ram_memory;
+    memory_region_init_alias(&f->pci_hole, "pci-hole", f->pci_address_space,
+                             pci_hole_start, pci_hole_size);
+    memory_region_add_subregion(f->system_memory, pci_hole_start, &f->pci_hole);
+    memory_region_init_alias(&f->pci_hole_64bit, "pci-hole64",
+                             f->pci_address_space,
+                             pci_hole64_start, pci_hole64_size);
+    if (pci_hole64_size) {
+        memory_region_add_subregion(f->system_memory, pci_hole64_start,
+                                    &f->pci_hole_64bit);
+    }
+    memory_region_init_alias(&f->smram_region, "smram-region",
+                             f->pci_address_space, 0xa0000, 0x20000);
+    memory_region_add_subregion_overlap(f->system_memory, 0xa0000,
+                                        &f->smram_region, 1);
+    memory_region_set_enabled(&f->smram_region, false);
+    init_pam(f->ram_memory, f->system_memory, f->pci_address_space,
+             &f->pam_regions[0], PAM_BIOS_BASE, PAM_BIOS_SIZE);
+    for (i = 0; i < 12; ++i) {
+        init_pam(f->ram_memory, f->system_memory, f->pci_address_space,
+                 &f->pam_regions[i+1], PAM_EXPAN_BASE + i * PAM_EXPAN_SIZE,
+                 PAM_EXPAN_SIZE);
+    }
+
+    /* Xen supports additional interrupt routes from the PCI devices to
+     * the IOAPIC: the four pins of each PCI device on the bus are also
+     * connected to the IOAPIC directly.
+     * These additional routes can be discovered through ACPI. */
+    if (xen_enabled()) {
+        piix3 = DO_UPCAST(PIIX3State, dev,
+                pci_create_simple_multifunction(b, -1, true, "PIIX3-xen"));
+        pci_bus_irqs(b, xen_piix3_set_irq, xen_pci_slot_get_pirq,
+                piix3, XEN_PIIX_NUM_PIRQS);
+    } else {
+        piix3 = DO_UPCAST(PIIX3State, dev,
+                pci_create_simple_multifunction(b, -1, true, "PIIX3"));
+        pci_bus_irqs(b, piix3_set_irq, pci_slot_get_pirq, piix3,
+                PIIX_NUM_PIRQS);
+        pci_bus_set_route_irq_fn(b, piix3_route_intx_pin_to_irq);
+    }
+    piix3->pic = pic;
+    *isa_bus = ISA_BUS(qdev_get_child_bus(DEVICE(piix3), "isa.0"));
+
+    *piix3_devfn = piix3->dev.devfn;
+
+    ram_size = ram_size / 8 / 1024 / 1024;
+    if (ram_size > 255)
+        ram_size = 255;
+    (*pi440fx_state)->dev.config[0x57]=ram_size;
+
+    i440fx_update_memory_mappings(f);
+
+    return b;
+}
+
+PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix3_devfn,
+                    ISABus **isa_bus, qemu_irq *pic,
+                    MemoryRegion *address_space_mem,
+                    MemoryRegion *address_space_io,
+                    ram_addr_t ram_size,
+                    hwaddr pci_hole_start,
+                    hwaddr pci_hole_size,
+                    hwaddr pci_hole64_start,
+                    hwaddr pci_hole64_size,
+                    MemoryRegion *pci_memory, MemoryRegion *ram_memory)
+
+{
+    PCIBus *b;
+
+    b = i440fx_common_init(TYPE_I440FX_PCI_DEVICE, pi440fx_state,
+                           piix3_devfn, isa_bus, pic,
+                           address_space_mem, address_space_io, ram_size,
+                           pci_hole_start, pci_hole_size,
+                           pci_hole64_start, pci_hole64_size,
+                           pci_memory, ram_memory);
+    return b;
+}
+
+/* PIIX3 PCI to ISA bridge */
+static void piix3_set_irq_pic(PIIX3State *piix3, int pic_irq)
+{
+    qemu_set_irq(piix3->pic[pic_irq],
+                 !!(piix3->pic_levels &
+                    (((1ULL << PIIX_NUM_PIRQS) - 1) <<
+                     (pic_irq * PIIX_NUM_PIRQS))));
+}
+
+static void piix3_set_irq_level(PIIX3State *piix3, int pirq, int level)
+{
+    int pic_irq;
+    uint64_t mask;
+
+    pic_irq = piix3->dev.config[PIIX_PIRQC + pirq];
+    if (pic_irq >= PIIX_NUM_PIC_IRQS) {
+        return;
+    }
+
+    mask = 1ULL << ((pic_irq * PIIX_NUM_PIRQS) + pirq);
+    piix3->pic_levels &= ~mask;
+    piix3->pic_levels |= mask * !!level;
+
+    piix3_set_irq_pic(piix3, pic_irq);
+}
+
+static void piix3_set_irq(void *opaque, int pirq, int level)
+{
+    PIIX3State *piix3 = opaque;
+    piix3_set_irq_level(piix3, pirq, level);
+}
+
+static PCIINTxRoute piix3_route_intx_pin_to_irq(void *opaque, int pin)
+{
+    PIIX3State *piix3 = opaque;
+    int irq = piix3->dev.config[PIIX_PIRQC + pin];
+    PCIINTxRoute route;
+
+    if (irq < PIIX_NUM_PIC_IRQS) {
+        route.mode = PCI_INTX_ENABLED;
+        route.irq = irq;
+    } else {
+        route.mode = PCI_INTX_DISABLED;
+        route.irq = -1;
+    }
+    return route;
+}
+
+/* irq routing is changed. so rebuild bitmap */
+static void piix3_update_irq_levels(PIIX3State *piix3)
+{
+    int pirq;
+
+    piix3->pic_levels = 0;
+    for (pirq = 0; pirq < PIIX_NUM_PIRQS; pirq++) {
+        piix3_set_irq_level(piix3, pirq,
+                            pci_bus_get_irq_level(piix3->dev.bus, pirq));
+    }
+}
+
+static void piix3_write_config(PCIDevice *dev,
+                               uint32_t address, uint32_t val, int len)
+{
+    pci_default_write_config(dev, address, val, len);
+    if (ranges_overlap(address, len, PIIX_PIRQC, 4)) {
+        PIIX3State *piix3 = DO_UPCAST(PIIX3State, dev, dev);
+        int pic_irq;
+
+        pci_bus_fire_intx_routing_notifier(piix3->dev.bus);
+        piix3_update_irq_levels(piix3);
+        for (pic_irq = 0; pic_irq < PIIX_NUM_PIC_IRQS; pic_irq++) {
+            piix3_set_irq_pic(piix3, pic_irq);
+        }
+    }
+}
+
+static void piix3_write_config_xen(PCIDevice *dev,
+                               uint32_t address, uint32_t val, int len)
+{
+    xen_piix_pci_write_config_client(address, val, len);
+    piix3_write_config(dev, address, val, len);
+}
+
+static void piix3_reset(void *opaque)
+{
+    PIIX3State *d = opaque;
+    uint8_t *pci_conf = d->dev.config;
+
+    pci_conf[0x04] = 0x07; /* master, memory and I/O */
+    pci_conf[0x05] = 0x00;
+    pci_conf[0x06] = 0x00;
+    pci_conf[0x07] = 0x02; /* PCI_status_devsel_medium */
+    pci_conf[0x4c] = 0x4d;
+    pci_conf[0x4e] = 0x03;
+    pci_conf[0x4f] = 0x00;
+    pci_conf[0x60] = 0x80;
+    pci_conf[0x61] = 0x80;
+    pci_conf[0x62] = 0x80;
+    pci_conf[0x63] = 0x80;
+    pci_conf[0x69] = 0x02;
+    pci_conf[0x70] = 0x80;
+    pci_conf[0x76] = 0x0c;
+    pci_conf[0x77] = 0x0c;
+    pci_conf[0x78] = 0x02;
+    pci_conf[0x79] = 0x00;
+    pci_conf[0x80] = 0x00;
+    pci_conf[0x82] = 0x00;
+    pci_conf[0xa0] = 0x08;
+    pci_conf[0xa2] = 0x00;
+    pci_conf[0xa3] = 0x00;
+    pci_conf[0xa4] = 0x00;
+    pci_conf[0xa5] = 0x00;
+    pci_conf[0xa6] = 0x00;
+    pci_conf[0xa7] = 0x00;
+    pci_conf[0xa8] = 0x0f;
+    pci_conf[0xaa] = 0x00;
+    pci_conf[0xab] = 0x00;
+    pci_conf[0xac] = 0x00;
+    pci_conf[0xae] = 0x00;
+
+    d->pic_levels = 0;
+    d->rcr = 0;
+}
+
+static int piix3_post_load(void *opaque, int version_id)
+{
+    PIIX3State *piix3 = opaque;
+    piix3_update_irq_levels(piix3);
+    return 0;
+}
+
+static void piix3_pre_save(void *opaque)
+{
+    int i;
+    PIIX3State *piix3 = opaque;
+
+    for (i = 0; i < ARRAY_SIZE(piix3->pci_irq_levels_vmstate); i++) {
+        piix3->pci_irq_levels_vmstate[i] =
+            pci_bus_get_irq_level(piix3->dev.bus, i);
+    }
+}
+
+static bool piix3_rcr_needed(void *opaque)
+{
+    PIIX3State *piix3 = opaque;
+
+    return (piix3->rcr != 0);
+}
+
+static const VMStateDescription vmstate_piix3_rcr = {
+    .name = "PIIX3/rcr",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField []) {
+        VMSTATE_UINT8(rcr, PIIX3State),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_piix3 = {
+    .name = "PIIX3",
+    .version_id = 3,
+    .minimum_version_id = 2,
+    .minimum_version_id_old = 2,
+    .post_load = piix3_post_load,
+    .pre_save = piix3_pre_save,
+    .fields      = (VMStateField[]) {
+        VMSTATE_PCI_DEVICE(dev, PIIX3State),
+        VMSTATE_INT32_ARRAY_V(pci_irq_levels_vmstate, PIIX3State,
+                              PIIX_NUM_PIRQS, 3),
+        VMSTATE_END_OF_LIST()
+    },
+    .subsections = (VMStateSubsection[]) {
+        {
+            .vmsd = &vmstate_piix3_rcr,
+            .needed = piix3_rcr_needed,
+        },
+        { 0 }
+    }
+};
+
+
+static void rcr_write(void *opaque, hwaddr addr, uint64_t val, unsigned len)
+{
+    PIIX3State *d = opaque;
+
+    if (val & 4) {
+        qemu_system_reset_request();
+        return;
+    }
+    d->rcr = val & 2; /* keep System Reset type only */
+}
+
+static uint64_t rcr_read(void *opaque, hwaddr addr, unsigned len)
+{
+    PIIX3State *d = opaque;
+
+    return d->rcr;
+}
+
+static const MemoryRegionOps rcr_ops = {
+    .read = rcr_read,
+    .write = rcr_write,
+    .endianness = DEVICE_LITTLE_ENDIAN
+};
+
+static int piix3_initfn(PCIDevice *dev)
+{
+    PIIX3State *d = DO_UPCAST(PIIX3State, dev, dev);
+
+    isa_bus_new(DEVICE(d), pci_address_space_io(dev));
+
+    memory_region_init_io(&d->rcr_mem, &rcr_ops, d, "piix3-reset-control", 1);
+    memory_region_add_subregion_overlap(pci_address_space_io(dev), RCR_IOPORT,
+                                        &d->rcr_mem, 1);
+
+    qemu_register_reset(piix3_reset, d);
+    return 0;
+}
+
+static void piix3_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    dc->desc        = "ISA bridge";
+    dc->vmsd        = &vmstate_piix3;
+    dc->no_user     = 1,
+    k->no_hotplug   = 1;
+    k->init         = piix3_initfn;
+    k->config_write = piix3_write_config;
+    k->vendor_id    = PCI_VENDOR_ID_INTEL;
+    /* 82371SB PIIX3 PCI-to-ISA bridge (Step A1) */
+    k->device_id    = PCI_DEVICE_ID_INTEL_82371SB_0;
+    k->class_id     = PCI_CLASS_BRIDGE_ISA;
+}
+
+static const TypeInfo piix3_info = {
+    .name          = "PIIX3",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PIIX3State),
+    .class_init    = piix3_class_init,
+};
+
+static void piix3_xen_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    dc->desc        = "ISA bridge";
+    dc->vmsd        = &vmstate_piix3;
+    dc->no_user     = 1;
+    k->no_hotplug   = 1;
+    k->init         = piix3_initfn;
+    k->config_write = piix3_write_config_xen;
+    k->vendor_id    = PCI_VENDOR_ID_INTEL;
+    /* 82371SB PIIX3 PCI-to-ISA bridge (Step A1) */
+    k->device_id    = PCI_DEVICE_ID_INTEL_82371SB_0;
+    k->class_id     = PCI_CLASS_BRIDGE_ISA;
+};
+
+static const 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;
+    k->init = i440fx_initfn;
+    k->config_write = i440fx_write_config;
+    k->vendor_id = PCI_VENDOR_ID_INTEL;
+    k->device_id = PCI_DEVICE_ID_INTEL_82441;
+    k->revision = 0x02;
+    k->class_id = PCI_CLASS_BRIDGE_HOST;
+    dc->desc = "Host bridge";
+    dc->no_user = 1;
+    dc->vmsd = &vmstate_i440fx;
+}
+
+static const TypeInfo i440fx_info = {
+    .name          = TYPE_I440FX_PCI_DEVICE,
+    .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 const TypeInfo i440fx_pcihost_info = {
+    .name          = "i440FX-pcihost",
+    .parent        = TYPE_PCI_HOST_BRIDGE,
+    .instance_size = sizeof(I440FXState),
+    .class_init    = i440fx_pcihost_class_init,
+};
+
+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);
+}
+
+type_init(i440fx_register_types)
diff --git a/hw/pci-host/ppce500.c b/hw/pci-host/ppce500.c
new file mode 100644 (file)
index 0000000..5e7ad94
--- /dev/null
@@ -0,0 +1,427 @@
+/*
+ * QEMU PowerPC E500 embedded processors pci controller emulation
+ *
+ * Copyright (C) 2009 Freescale Semiconductor, Inc. All rights reserved.
+ *
+ * Author: Yu Liu,     <yu.liu@freescale.com>
+ *
+ * This file is derived from hw/ppc4xx_pci.c,
+ * the copyright for that material belongs to the original owners.
+ *
+ * This 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.
+ */
+
+#include "hw/hw.h"
+#include "hw/ppc/e500-ccsr.h"
+#include "hw/pci/pci.h"
+#include "hw/pci/pci_host.h"
+#include "qemu/bswap.h"
+#include "hw/pci-host/ppce500.h"
+
+#ifdef DEBUG_PCI
+#define pci_debug(fmt, ...) fprintf(stderr, fmt, ## __VA_ARGS__)
+#else
+#define pci_debug(fmt, ...)
+#endif
+
+#define PCIE500_CFGADDR       0x0
+#define PCIE500_CFGDATA       0x4
+#define PCIE500_REG_BASE      0xC00
+#define PCIE500_ALL_SIZE      0x1000
+#define PCIE500_REG_SIZE      (PCIE500_ALL_SIZE - PCIE500_REG_BASE)
+
+#define PCIE500_PCI_IOLEN     0x10000ULL
+
+#define PPCE500_PCI_CONFIG_ADDR         0x0
+#define PPCE500_PCI_CONFIG_DATA         0x4
+#define PPCE500_PCI_INTACK              0x8
+
+#define PPCE500_PCI_OW1                 (0xC20 - PCIE500_REG_BASE)
+#define PPCE500_PCI_OW2                 (0xC40 - PCIE500_REG_BASE)
+#define PPCE500_PCI_OW3                 (0xC60 - PCIE500_REG_BASE)
+#define PPCE500_PCI_OW4                 (0xC80 - PCIE500_REG_BASE)
+#define PPCE500_PCI_IW3                 (0xDA0 - PCIE500_REG_BASE)
+#define PPCE500_PCI_IW2                 (0xDC0 - PCIE500_REG_BASE)
+#define PPCE500_PCI_IW1                 (0xDE0 - PCIE500_REG_BASE)
+
+#define PPCE500_PCI_GASKET_TIMR         (0xE20 - PCIE500_REG_BASE)
+
+#define PCI_POTAR               0x0
+#define PCI_POTEAR              0x4
+#define PCI_POWBAR              0x8
+#define PCI_POWAR               0x10
+
+#define PCI_PITAR               0x0
+#define PCI_PIWBAR              0x8
+#define PCI_PIWBEAR             0xC
+#define PCI_PIWAR               0x10
+
+#define PPCE500_PCI_NR_POBS     5
+#define PPCE500_PCI_NR_PIBS     3
+
+struct  pci_outbound {
+    uint32_t potar;
+    uint32_t potear;
+    uint32_t powbar;
+    uint32_t powar;
+};
+
+struct pci_inbound {
+    uint32_t pitar;
+    uint32_t piwbar;
+    uint32_t piwbear;
+    uint32_t piwar;
+};
+
+#define TYPE_PPC_E500_PCI_HOST_BRIDGE "e500-pcihost"
+
+#define PPC_E500_PCI_HOST_BRIDGE(obj) \
+    OBJECT_CHECK(PPCE500PCIState, (obj), TYPE_PPC_E500_PCI_HOST_BRIDGE)
+
+struct PPCE500PCIState {
+    PCIHostState parent_obj;
+
+    struct pci_outbound pob[PPCE500_PCI_NR_POBS];
+    struct pci_inbound pib[PPCE500_PCI_NR_PIBS];
+    uint32_t gasket_time;
+    qemu_irq irq[4];
+    uint32_t first_slot;
+    /* mmio maps */
+    MemoryRegion container;
+    MemoryRegion iomem;
+    MemoryRegion pio;
+};
+
+#define TYPE_PPC_E500_PCI_BRIDGE "e500-host-bridge"
+#define PPC_E500_PCI_BRIDGE(obj) \
+    OBJECT_CHECK(PPCE500PCIBridgeState, (obj), TYPE_PPC_E500_PCI_BRIDGE)
+
+struct PPCE500PCIBridgeState {
+    /*< private >*/
+    PCIDevice parent;
+    /*< public >*/
+
+    MemoryRegion bar0;
+};
+
+typedef struct PPCE500PCIBridgeState PPCE500PCIBridgeState;
+typedef struct PPCE500PCIState PPCE500PCIState;
+
+static uint64_t pci_reg_read4(void *opaque, hwaddr addr,
+                              unsigned size)
+{
+    PPCE500PCIState *pci = opaque;
+    unsigned long win;
+    uint32_t value = 0;
+    int idx;
+
+    win = addr & 0xfe0;
+
+    switch (win) {
+    case PPCE500_PCI_OW1:
+    case PPCE500_PCI_OW2:
+    case PPCE500_PCI_OW3:
+    case PPCE500_PCI_OW4:
+        idx = (addr >> 5) & 0x7;
+        switch (addr & 0xC) {
+        case PCI_POTAR:
+            value = pci->pob[idx].potar;
+            break;
+        case PCI_POTEAR:
+            value = pci->pob[idx].potear;
+            break;
+        case PCI_POWBAR:
+            value = pci->pob[idx].powbar;
+            break;
+        case PCI_POWAR:
+            value = pci->pob[idx].powar;
+            break;
+        default:
+            break;
+        }
+        break;
+
+    case PPCE500_PCI_IW3:
+    case PPCE500_PCI_IW2:
+    case PPCE500_PCI_IW1:
+        idx = ((addr >> 5) & 0x3) - 1;
+        switch (addr & 0xC) {
+        case PCI_PITAR:
+            value = pci->pib[idx].pitar;
+            break;
+        case PCI_PIWBAR:
+            value = pci->pib[idx].piwbar;
+            break;
+        case PCI_PIWBEAR:
+            value = pci->pib[idx].piwbear;
+            break;
+        case PCI_PIWAR:
+            value = pci->pib[idx].piwar;
+            break;
+        default:
+            break;
+        };
+        break;
+
+    case PPCE500_PCI_GASKET_TIMR:
+        value = pci->gasket_time;
+        break;
+
+    default:
+        break;
+    }
+
+    pci_debug("%s: win:%lx(addr:" TARGET_FMT_plx ") -> value:%x\n", __func__,
+              win, addr, value);
+    return value;
+}
+
+static void pci_reg_write4(void *opaque, hwaddr addr,
+                           uint64_t value, unsigned size)
+{
+    PPCE500PCIState *pci = opaque;
+    unsigned long win;
+    int idx;
+
+    win = addr & 0xfe0;
+
+    pci_debug("%s: value:%x -> win:%lx(addr:" TARGET_FMT_plx ")\n",
+              __func__, (unsigned)value, win, addr);
+
+    switch (win) {
+    case PPCE500_PCI_OW1:
+    case PPCE500_PCI_OW2:
+    case PPCE500_PCI_OW3:
+    case PPCE500_PCI_OW4:
+        idx = (addr >> 5) & 0x7;
+        switch (addr & 0xC) {
+        case PCI_POTAR:
+            pci->pob[idx].potar = value;
+            break;
+        case PCI_POTEAR:
+            pci->pob[idx].potear = value;
+            break;
+        case PCI_POWBAR:
+            pci->pob[idx].powbar = value;
+            break;
+        case PCI_POWAR:
+            pci->pob[idx].powar = value;
+            break;
+        default:
+            break;
+        };
+        break;
+
+    case PPCE500_PCI_IW3:
+    case PPCE500_PCI_IW2:
+    case PPCE500_PCI_IW1:
+        idx = ((addr >> 5) & 0x3) - 1;
+        switch (addr & 0xC) {
+        case PCI_PITAR:
+            pci->pib[idx].pitar = value;
+            break;
+        case PCI_PIWBAR:
+            pci->pib[idx].piwbar = value;
+            break;
+        case PCI_PIWBEAR:
+            pci->pib[idx].piwbear = value;
+            break;
+        case PCI_PIWAR:
+            pci->pib[idx].piwar = value;
+            break;
+        default:
+            break;
+        };
+        break;
+
+    case PPCE500_PCI_GASKET_TIMR:
+        pci->gasket_time = value;
+        break;
+
+    default:
+        break;
+    };
+}
+
+static const MemoryRegionOps e500_pci_reg_ops = {
+    .read = pci_reg_read4,
+    .write = pci_reg_write4,
+    .endianness = DEVICE_BIG_ENDIAN,
+};
+
+static int mpc85xx_pci_map_irq(PCIDevice *pci_dev, int irq_num)
+{
+    int devno = pci_dev->devfn >> 3;
+    int ret;
+
+    ret = ppce500_pci_map_irq_slot(devno, irq_num);
+
+    pci_debug("%s: devfn %x irq %d -> %d  devno:%x\n", __func__,
+           pci_dev->devfn, irq_num, ret, devno);
+
+    return ret;
+}
+
+static void mpc85xx_pci_set_irq(void *opaque, int irq_num, int level)
+{
+    qemu_irq *pic = opaque;
+
+    pci_debug("%s: PCI irq %d, level:%d\n", __func__, irq_num, level);
+
+    qemu_set_irq(pic[irq_num], level);
+}
+
+static const VMStateDescription vmstate_pci_outbound = {
+    .name = "pci_outbound",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32(potar, struct pci_outbound),
+        VMSTATE_UINT32(potear, struct pci_outbound),
+        VMSTATE_UINT32(powbar, struct pci_outbound),
+        VMSTATE_UINT32(powar, struct pci_outbound),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_pci_inbound = {
+    .name = "pci_inbound",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32(pitar, struct pci_inbound),
+        VMSTATE_UINT32(piwbar, struct pci_inbound),
+        VMSTATE_UINT32(piwbear, struct pci_inbound),
+        VMSTATE_UINT32(piwar, struct pci_inbound),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_ppce500_pci = {
+    .name = "ppce500_pci",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_STRUCT_ARRAY(pob, PPCE500PCIState, PPCE500_PCI_NR_POBS, 1,
+                             vmstate_pci_outbound, struct pci_outbound),
+        VMSTATE_STRUCT_ARRAY(pib, PPCE500PCIState, PPCE500_PCI_NR_PIBS, 1,
+                             vmstate_pci_outbound, struct pci_inbound),
+        VMSTATE_UINT32(gasket_time, PPCE500PCIState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+#include "exec/address-spaces.h"
+
+static int e500_pcihost_bridge_initfn(PCIDevice *d)
+{
+    PPCE500PCIBridgeState *b = PPC_E500_PCI_BRIDGE(d);
+    PPCE500CCSRState *ccsr = CCSR(container_get(qdev_get_machine(),
+                                  "/e500-ccsr"));
+
+    pci_config_set_class(d->config, PCI_CLASS_BRIDGE_PCI);
+    d->config[PCI_HEADER_TYPE] =
+        (d->config[PCI_HEADER_TYPE] & PCI_HEADER_TYPE_MULTI_FUNCTION) |
+        PCI_HEADER_TYPE_BRIDGE;
+
+    memory_region_init_alias(&b->bar0, "e500-pci-bar0", &ccsr->ccsr_space,
+                             0, int128_get64(ccsr->ccsr_space.size));
+    pci_register_bar(d, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &b->bar0);
+
+    return 0;
+}
+
+static int e500_pcihost_initfn(SysBusDevice *dev)
+{
+    PCIHostState *h;
+    PPCE500PCIState *s;
+    PCIBus *b;
+    int i;
+    MemoryRegion *address_space_mem = get_system_memory();
+
+    h = PCI_HOST_BRIDGE(dev);
+    s = PPC_E500_PCI_HOST_BRIDGE(dev);
+
+    for (i = 0; i < ARRAY_SIZE(s->irq); i++) {
+        sysbus_init_irq(dev, &s->irq[i]);
+    }
+
+    memory_region_init(&s->pio, "pci-pio", PCIE500_PCI_IOLEN);
+
+    b = pci_register_bus(DEVICE(dev), NULL, mpc85xx_pci_set_irq,
+                         mpc85xx_pci_map_irq, s->irq, address_space_mem,
+                         &s->pio, PCI_DEVFN(s->first_slot, 0), 4, TYPE_PCI_BUS);
+    h->bus = b;
+
+    pci_create_simple(b, 0, "e500-host-bridge");
+
+    memory_region_init(&s->container, "pci-container", PCIE500_ALL_SIZE);
+    memory_region_init_io(&h->conf_mem, &pci_host_conf_be_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, &e500_pci_reg_ops, s,
+                          "pci.reg", PCIE500_REG_SIZE);
+    memory_region_add_subregion(&s->container, PCIE500_CFGADDR, &h->conf_mem);
+    memory_region_add_subregion(&s->container, PCIE500_CFGDATA, &h->data_mem);
+    memory_region_add_subregion(&s->container, PCIE500_REG_BASE, &s->iomem);
+    sysbus_init_mmio(dev, &s->container);
+    sysbus_init_mmio(dev, &s->pio);
+
+    return 0;
+}
+
+static void e500_host_bridge_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = e500_pcihost_bridge_initfn;
+    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 const TypeInfo e500_host_bridge_info = {
+    .name          = "e500-host-bridge",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PPCE500PCIBridgeState),
+    .class_init    = e500_host_bridge_class_init,
+};
+
+static Property pcihost_properties[] = {
+    DEFINE_PROP_UINT32("first_slot", PPCE500PCIState, first_slot, 0x11),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+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->props = pcihost_properties;
+    dc->vmsd = &vmstate_ppce500_pci;
+}
+
+static const TypeInfo e500_pcihost_info = {
+    .name          = TYPE_PPC_E500_PCI_HOST_BRIDGE,
+    .parent        = TYPE_PCI_HOST_BRIDGE,
+    .instance_size = sizeof(PPCE500PCIState),
+    .class_init    = e500_pcihost_class_init,
+};
+
+static void e500_pci_register_types(void)
+{
+    type_register_static(&e500_pcihost_info);
+    type_register_static(&e500_host_bridge_info);
+}
+
+type_init(e500_pci_register_types)
diff --git a/hw/pci-host/prep.c b/hw/pci-host/prep.c
new file mode 100644 (file)
index 0000000..6130253
--- /dev/null
@@ -0,0 +1,232 @@
+/*
+ * QEMU PREP PCI host
+ *
+ * Copyright (c) 2006 Fabrice Bellard
+ * Copyright (c) 2011-2013 Andreas Färber
+ *
+ * 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 "hw/hw.h"
+#include "hw/pci/pci.h"
+#include "hw/pci/pci_bus.h"
+#include "hw/pci/pci_host.h"
+#include "hw/i386/pc.h"
+#include "exec/address-spaces.h"
+
+#define TYPE_RAVEN_PCI_DEVICE "raven"
+#define TYPE_RAVEN_PCI_HOST_BRIDGE "raven-pcihost"
+
+#define RAVEN_PCI_DEVICE(obj) \
+    OBJECT_CHECK(RavenPCIState, (obj), TYPE_RAVEN_PCI_DEVICE)
+
+typedef struct RavenPCIState {
+    PCIDevice dev;
+} RavenPCIState;
+
+#define RAVEN_PCI_HOST_BRIDGE(obj) \
+    OBJECT_CHECK(PREPPCIState, (obj), TYPE_RAVEN_PCI_HOST_BRIDGE)
+
+typedef struct PRePPCIState {
+    PCIHostState parent_obj;
+
+    MemoryRegion intack;
+    qemu_irq irq[4];
+    PCIBus pci_bus;
+    RavenPCIState pci_dev;
+} PREPPCIState;
+
+static inline uint32_t PPC_PCIIO_config(hwaddr addr)
+{
+    int i;
+
+    for (i = 0; i < 11; i++) {
+        if ((addr & (1 << (11 + i))) != 0) {
+            break;
+        }
+    }
+    return (addr & 0x7ff) |  (i << 11);
+}
+
+static void ppc_pci_io_write(void *opaque, hwaddr addr,
+                             uint64_t val, unsigned int size)
+{
+    PREPPCIState *s = opaque;
+    PCIHostState *phb = PCI_HOST_BRIDGE(s);
+    pci_data_write(phb->bus, PPC_PCIIO_config(addr), val, size);
+}
+
+static uint64_t ppc_pci_io_read(void *opaque, hwaddr addr,
+                                unsigned int size)
+{
+    PREPPCIState *s = opaque;
+    PCIHostState *phb = PCI_HOST_BRIDGE(s);
+    return pci_data_read(phb->bus, PPC_PCIIO_config(addr), size);
+}
+
+static const MemoryRegionOps PPC_PCIIO_ops = {
+    .read = ppc_pci_io_read,
+    .write = ppc_pci_io_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static uint64_t ppc_intack_read(void *opaque, hwaddr addr,
+                                unsigned int size)
+{
+    return pic_read_irq(isa_pic);
+}
+
+static const MemoryRegionOps PPC_intack_ops = {
+    .read = ppc_intack_read,
+    .valid = {
+        .max_access_size = 1,
+    },
+};
+
+static int prep_map_irq(PCIDevice *pci_dev, int irq_num)
+{
+    return (irq_num + (pci_dev->devfn >> 3)) & 1;
+}
+
+static void prep_set_irq(void *opaque, int irq_num, int level)
+{
+    qemu_irq *pic = opaque;
+
+    qemu_set_irq(pic[irq_num] , level);
+}
+
+static void raven_pcihost_realizefn(DeviceState *d, Error **errp)
+{
+    SysBusDevice *dev = SYS_BUS_DEVICE(d);
+    PCIHostState *h = PCI_HOST_BRIDGE(dev);
+    PREPPCIState *s = RAVEN_PCI_HOST_BRIDGE(dev);
+    MemoryRegion *address_space_mem = get_system_memory();
+    int i;
+
+    for (i = 0; i < 4; i++) {
+        sysbus_init_irq(dev, &s->irq[i]);
+    }
+
+    pci_bus_irqs(&s->pci_bus, prep_set_irq, prep_map_irq, s->irq, 4);
+
+    memory_region_init_io(&h->conf_mem, &pci_host_conf_be_ops, s,
+                          "pci-conf-idx", 1);
+    sysbus_add_io(dev, 0xcf8, &h->conf_mem);
+    sysbus_init_ioports(&h->busdev, 0xcf8, 1);
+
+    memory_region_init_io(&h->data_mem, &pci_host_data_be_ops, s,
+                          "pci-conf-data", 1);
+    sysbus_add_io(dev, 0xcfc, &h->data_mem);
+    sysbus_init_ioports(&h->busdev, 0xcfc, 1);
+
+    memory_region_init_io(&h->mmcfg, &PPC_PCIIO_ops, s, "pciio", 0x00400000);
+    memory_region_add_subregion(address_space_mem, 0x80800000, &h->mmcfg);
+
+    memory_region_init_io(&s->intack, &PPC_intack_ops, s, "pci-intack", 1);
+    memory_region_add_subregion(address_space_mem, 0xbffffff0, &s->intack);
+
+    /* TODO Remove once realize propagates to child devices. */
+    object_property_set_bool(OBJECT(&s->pci_dev), true, "realized", errp);
+}
+
+static void raven_pcihost_initfn(Object *obj)
+{
+    PCIHostState *h = PCI_HOST_BRIDGE(obj);
+    PREPPCIState *s = RAVEN_PCI_HOST_BRIDGE(obj);
+    MemoryRegion *address_space_mem = get_system_memory();
+    MemoryRegion *address_space_io = get_system_io();
+    DeviceState *pci_dev;
+
+    pci_bus_new_inplace(&s->pci_bus, DEVICE(obj), NULL,
+                        address_space_mem, address_space_io, 0, TYPE_PCI_BUS);
+    h->bus = &s->pci_bus;
+
+    object_initialize(&s->pci_dev, TYPE_RAVEN_PCI_DEVICE);
+    pci_dev = DEVICE(&s->pci_dev);
+    qdev_set_parent_bus(pci_dev, BUS(&s->pci_bus));
+    object_property_set_int(OBJECT(&s->pci_dev), PCI_DEVFN(0, 0), "addr",
+                            NULL);
+    qdev_prop_set_bit(pci_dev, "multifunction", false);
+}
+
+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 0;
+}
+
+static const VMStateDescription vmstate_raven = {
+    .name = "raven",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .fields = (VMStateField[]) {
+        VMSTATE_PCI_DEVICE(dev, RavenPCIState),
+        VMSTATE_END_OF_LIST()
+    },
+};
+
+static void raven_class_init(ObjectClass *klass, void *data)
+{
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    k->init = raven_init;
+    k->vendor_id = PCI_VENDOR_ID_MOTOROLA;
+    k->device_id = PCI_DEVICE_ID_MOTOROLA_RAVEN;
+    k->revision = 0x00;
+    k->class_id = PCI_CLASS_BRIDGE_HOST;
+    dc->desc = "PReP Host Bridge - Motorola Raven";
+    dc->vmsd = &vmstate_raven;
+    dc->no_user = 1;
+}
+
+static const TypeInfo raven_info = {
+    .name = TYPE_RAVEN_PCI_DEVICE,
+    .parent = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(RavenPCIState),
+    .class_init = raven_class_init,
+};
+
+static void raven_pcihost_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->realize = raven_pcihost_realizefn;
+    dc->fw_name = "pci";
+    dc->no_user = 1;
+}
+
+static const TypeInfo raven_pcihost_info = {
+    .name = TYPE_RAVEN_PCI_HOST_BRIDGE,
+    .parent = TYPE_PCI_HOST_BRIDGE,
+    .instance_size = sizeof(PREPPCIState),
+    .instance_init = raven_pcihost_initfn,
+    .class_init = raven_pcihost_class_init,
+};
+
+static void raven_register_types(void)
+{
+    type_register_static(&raven_pcihost_info);
+    type_register_static(&raven_info);
+}
+
+type_init(raven_register_types)
diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c
new file mode 100644 (file)
index 0000000..8467f86
--- /dev/null
@@ -0,0 +1,310 @@
+/*
+ * QEMU MCH/ICH9 PCI Bridge Emulation
+ *
+ * Copyright (c) 2006 Fabrice Bellard
+ * Copyright (c) 2009, 2010, 2011
+ *               Isaku Yamahata <yamahata at valinux co jp>
+ *               VA Linux Systems Japan K.K.
+ * Copyright (C) 2012 Jason Baron <jbaron@redhat.com>
+ *
+ * This is based on piix_pci.c, but heavily modified.
+ *
+ * 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 "hw/hw.h"
+#include "hw/pci-host/q35.h"
+
+/****************************************************************************
+ * Q35 host
+ */
+
+static int q35_host_init(SysBusDevice *dev)
+{
+    PCIBus *b;
+    PCIHostState *pci = FROM_SYSBUS(PCIHostState, dev);
+    Q35PCIHost *s = Q35_HOST_DEVICE(&dev->qdev);
+
+    memory_region_init_io(&pci->conf_mem, &pci_host_conf_le_ops, pci,
+                          "pci-conf-idx", 4);
+    sysbus_add_io(dev, MCH_HOST_BRIDGE_CONFIG_ADDR, &pci->conf_mem);
+    sysbus_init_ioports(&pci->busdev, MCH_HOST_BRIDGE_CONFIG_ADDR, 4);
+
+    memory_region_init_io(&pci->data_mem, &pci_host_data_le_ops, pci,
+                          "pci-conf-data", 4);
+    sysbus_add_io(dev, MCH_HOST_BRIDGE_CONFIG_DATA, &pci->data_mem);
+    sysbus_init_ioports(&pci->busdev, MCH_HOST_BRIDGE_CONFIG_DATA, 4);
+
+    if (pcie_host_init(&s->host) < 0) {
+        return -1;
+    }
+    b = pci_bus_new(&s->host.pci.busdev.qdev, "pcie.0",
+                    s->mch.pci_address_space, s->mch.address_space_io,
+                    0, TYPE_PCIE_BUS);
+    s->host.pci.bus = b;
+    qdev_set_parent_bus(DEVICE(&s->mch), BUS(b));
+    qdev_init_nofail(DEVICE(&s->mch));
+
+    return 0;
+}
+
+static Property mch_props[] = {
+    DEFINE_PROP_UINT64("MCFG", Q35PCIHost, host.base_addr,
+                        MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void q35_host_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = q35_host_init;
+    dc->props = mch_props;
+}
+
+static void q35_host_initfn(Object *obj)
+{
+    Q35PCIHost *s = Q35_HOST_DEVICE(obj);
+
+    object_initialize(&s->mch, TYPE_MCH_PCI_DEVICE);
+    object_property_add_child(OBJECT(s), "mch", OBJECT(&s->mch), NULL);
+    qdev_prop_set_uint32(DEVICE(&s->mch), "addr", PCI_DEVFN(0, 0));
+    qdev_prop_set_bit(DEVICE(&s->mch), "multifunction", false);
+}
+
+static const TypeInfo q35_host_info = {
+    .name       = TYPE_Q35_HOST_DEVICE,
+    .parent     = TYPE_PCIE_HOST_BRIDGE,
+    .instance_size = sizeof(Q35PCIHost),
+    .instance_init = q35_host_initfn,
+    .class_init = q35_host_class_init,
+};
+
+/****************************************************************************
+ * MCH D0:F0
+ */
+
+/* PCIe MMCFG */
+static void mch_update_pciexbar(MCHPCIState *mch)
+{
+    PCIDevice *pci_dev = &mch->d;
+    BusState *bus = qdev_get_parent_bus(&pci_dev->qdev);
+    DeviceState *qdev = bus->parent;
+    Q35PCIHost *s = Q35_HOST_DEVICE(qdev);
+
+    uint64_t pciexbar;
+    int enable;
+    uint64_t addr;
+    uint64_t addr_mask;
+    uint32_t length;
+
+    pciexbar = pci_get_quad(pci_dev->config + MCH_HOST_BRIDGE_PCIEXBAR);
+    enable = pciexbar & MCH_HOST_BRIDGE_PCIEXBAREN;
+    addr_mask = MCH_HOST_BRIDGE_PCIEXBAR_ADMSK;
+    switch (pciexbar & MCH_HOST_BRIDGE_PCIEXBAR_LENGTH_MASK) {
+    case MCH_HOST_BRIDGE_PCIEXBAR_LENGTH_256M:
+        length = 256 * 1024 * 1024;
+        break;
+    case MCH_HOST_BRIDGE_PCIEXBAR_LENGTH_128M:
+        length = 128 * 1024 * 1024;
+        addr_mask |= MCH_HOST_BRIDGE_PCIEXBAR_128ADMSK |
+            MCH_HOST_BRIDGE_PCIEXBAR_64ADMSK;
+        break;
+    case MCH_HOST_BRIDGE_PCIEXBAR_LENGTH_64M:
+        length = 64 * 1024 * 1024;
+        addr_mask |= MCH_HOST_BRIDGE_PCIEXBAR_64ADMSK;
+        break;
+    case MCH_HOST_BRIDGE_PCIEXBAR_LENGTH_RVD:
+    default:
+        enable = 0;
+        length = 0;
+        abort();
+        break;
+    }
+    addr = pciexbar & addr_mask;
+    pcie_host_mmcfg_update(&s->host, enable, addr, length);
+}
+
+/* PAM */
+static void mch_update_pam(MCHPCIState *mch)
+{
+    int i;
+
+    memory_region_transaction_begin();
+    for (i = 0; i < 13; i++) {
+        pam_update(&mch->pam_regions[i], i,
+                   mch->d.config[MCH_HOST_BRIDGE_PAM0 + ((i + 1) / 2)]);
+    }
+    memory_region_transaction_commit();
+}
+
+/* SMRAM */
+static void mch_update_smram(MCHPCIState *mch)
+{
+    memory_region_transaction_begin();
+    smram_update(&mch->smram_region, mch->d.config[MCH_HOST_BRDIGE_SMRAM],
+                    mch->smm_enabled);
+    memory_region_transaction_commit();
+}
+
+static void mch_set_smm(int smm, void *arg)
+{
+    MCHPCIState *mch = arg;
+
+    memory_region_transaction_begin();
+    smram_set_smm(&mch->smm_enabled, smm, mch->d.config[MCH_HOST_BRDIGE_SMRAM],
+                    &mch->smram_region);
+    memory_region_transaction_commit();
+}
+
+static void mch_write_config(PCIDevice *d,
+                              uint32_t address, uint32_t val, int len)
+{
+    MCHPCIState *mch = MCH_PCI_DEVICE(d);
+
+    /* XXX: implement SMRAM.D_LOCK */
+    pci_default_write_config(d, address, val, len);
+
+    if (ranges_overlap(address, len, MCH_HOST_BRIDGE_PAM0,
+                       MCH_HOST_BRIDGE_PAM_SIZE)) {
+        mch_update_pam(mch);
+    }
+
+    if (ranges_overlap(address, len, MCH_HOST_BRIDGE_PCIEXBAR,
+                       MCH_HOST_BRIDGE_PCIEXBAR_SIZE)) {
+        mch_update_pciexbar(mch);
+    }
+
+    if (ranges_overlap(address, len, MCH_HOST_BRDIGE_SMRAM,
+                       MCH_HOST_BRDIGE_SMRAM_SIZE)) {
+        mch_update_smram(mch);
+    }
+}
+
+static void mch_update(MCHPCIState *mch)
+{
+    mch_update_pciexbar(mch);
+    mch_update_pam(mch);
+    mch_update_smram(mch);
+}
+
+static int mch_post_load(void *opaque, int version_id)
+{
+    MCHPCIState *mch = opaque;
+    mch_update(mch);
+    return 0;
+}
+
+static const VMStateDescription vmstate_mch = {
+    .name = "mch",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .post_load = mch_post_load,
+    .fields = (VMStateField []) {
+        VMSTATE_PCI_DEVICE(d, MCHPCIState),
+        VMSTATE_UINT8(smm_enabled, MCHPCIState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void mch_reset(DeviceState *qdev)
+{
+    PCIDevice *d = PCI_DEVICE(qdev);
+    MCHPCIState *mch = MCH_PCI_DEVICE(d);
+
+    pci_set_quad(d->config + MCH_HOST_BRIDGE_PCIEXBAR,
+                 MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT);
+
+    d->config[MCH_HOST_BRDIGE_SMRAM] = MCH_HOST_BRIDGE_SMRAM_DEFAULT;
+
+    mch_update(mch);
+}
+
+static int mch_init(PCIDevice *d)
+{
+    int i;
+    hwaddr pci_hole64_size;
+    MCHPCIState *mch = MCH_PCI_DEVICE(d);
+
+    /* setup pci memory regions */
+    memory_region_init_alias(&mch->pci_hole, "pci-hole",
+                             mch->pci_address_space,
+                             mch->below_4g_mem_size,
+                             0x100000000ULL - mch->below_4g_mem_size);
+    memory_region_add_subregion(mch->system_memory, mch->below_4g_mem_size,
+                                &mch->pci_hole);
+    pci_hole64_size = (sizeof(hwaddr) == 4 ? 0 :
+                       ((uint64_t)1 << 62));
+    memory_region_init_alias(&mch->pci_hole_64bit, "pci-hole64",
+                             mch->pci_address_space,
+                             0x100000000ULL + mch->above_4g_mem_size,
+                             pci_hole64_size);
+    if (pci_hole64_size) {
+        memory_region_add_subregion(mch->system_memory,
+                                    0x100000000ULL + mch->above_4g_mem_size,
+                                    &mch->pci_hole_64bit);
+    }
+    /* smram */
+    cpu_smm_register(&mch_set_smm, mch);
+    memory_region_init_alias(&mch->smram_region, "smram-region",
+                             mch->pci_address_space, 0xa0000, 0x20000);
+    memory_region_add_subregion_overlap(mch->system_memory, 0xa0000,
+                                        &mch->smram_region, 1);
+    memory_region_set_enabled(&mch->smram_region, false);
+    init_pam(mch->ram_memory, mch->system_memory, mch->pci_address_space,
+             &mch->pam_regions[0], PAM_BIOS_BASE, PAM_BIOS_SIZE);
+    for (i = 0; i < 12; ++i) {
+        init_pam(mch->ram_memory, mch->system_memory, mch->pci_address_space,
+                 &mch->pam_regions[i+1], PAM_EXPAN_BASE + i * PAM_EXPAN_SIZE,
+                 PAM_EXPAN_SIZE);
+    }
+    return 0;
+}
+
+static void mch_class_init(ObjectClass *klass, void *data)
+{
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    k->init = mch_init;
+    k->config_write = mch_write_config;
+    dc->reset = mch_reset;
+    dc->desc = "Host bridge";
+    dc->vmsd = &vmstate_mch;
+    k->vendor_id = PCI_VENDOR_ID_INTEL;
+    k->device_id = PCI_DEVICE_ID_INTEL_Q35_MCH;
+    k->revision = MCH_HOST_BRIDGE_REVISION_DEFUALT;
+    k->class_id = PCI_CLASS_BRIDGE_HOST;
+}
+
+static const TypeInfo mch_info = {
+    .name = TYPE_MCH_PCI_DEVICE,
+    .parent = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(MCHPCIState),
+    .class_init = mch_class_init,
+};
+
+static void q35_register(void)
+{
+    type_register_static(&mch_info);
+    type_register_static(&q35_host_info);
+}
+
+type_init(q35_register);
diff --git a/hw/pci-host/uninorth.c b/hw/pci-host/uninorth.c
new file mode 100644 (file)
index 0000000..fff235d
--- /dev/null
@@ -0,0 +1,492 @@
+/*
+ * QEMU Uninorth PCI host (for all Mac99 and newer machines)
+ *
+ * Copyright (c) 2006 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.
+ */
+#include "hw/hw.h"
+#include "hw/ppc/mac.h"
+#include "hw/pci/pci.h"
+#include "hw/pci/pci_host.h"
+
+/* debug UniNorth */
+//#define DEBUG_UNIN
+
+#ifdef DEBUG_UNIN
+#define UNIN_DPRINTF(fmt, ...)                                  \
+    do { printf("UNIN: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define UNIN_DPRINTF(fmt, ...)
+#endif
+
+static const int unin_irq_line[] = { 0x1b, 0x1c, 0x1d, 0x1e };
+
+#define TYPE_UNI_NORTH_PCI_HOST_BRIDGE "uni-north-pci-pcihost"
+#define TYPE_UNI_NORTH_AGP_HOST_BRIDGE "uni-north-agp-pcihost"
+#define TYPE_UNI_NORTH_INTERNAL_PCI_HOST_BRIDGE "uni-north-internal-pci-pcihost"
+#define TYPE_U3_AGP_HOST_BRIDGE "u3-agp-pcihost"
+
+#define UNI_NORTH_PCI_HOST_BRIDGE(obj) \
+    OBJECT_CHECK(UNINState, (obj), TYPE_UNI_NORTH_PCI_HOST_BRIDGE)
+#define UNI_NORTH_AGP_HOST_BRIDGE(obj) \
+    OBJECT_CHECK(UNINState, (obj), TYPE_UNI_NORTH_AGP_HOST_BRIDGE)
+#define UNI_NORTH_INTERNAL_PCI_HOST_BRIDGE(obj) \
+    OBJECT_CHECK(UNINState, (obj), TYPE_UNI_NORTH_INTERNAL_PCI_HOST_BRIDGE)
+#define U3_AGP_HOST_BRIDGE(obj) \
+    OBJECT_CHECK(UNINState, (obj), TYPE_U3_AGP_HOST_BRIDGE)
+
+typedef struct UNINState {
+    PCIHostState parent_obj;
+
+    MemoryRegion pci_mmio;
+    MemoryRegion pci_hole;
+} UNINState;
+
+static int pci_unin_map_irq(PCIDevice *pci_dev, int irq_num)
+{
+    int retval;
+    int devfn = pci_dev->devfn & 0x00FFFFFF;
+
+    retval = (((devfn >> 11) & 0x1F) + irq_num) & 3;
+
+    return retval;
+}
+
+static void pci_unin_set_irq(void *opaque, int irq_num, int level)
+{
+    qemu_irq *pic = opaque;
+
+    UNIN_DPRINTF("%s: setting INT %d = %d\n", __func__,
+                 unin_irq_line[irq_num], level);
+    qemu_set_irq(pic[unin_irq_line[irq_num]], level);
+}
+
+static uint32_t unin_get_config_reg(uint32_t reg, uint32_t addr)
+{
+    uint32_t retval;
+
+    if (reg & (1u << 31)) {
+        /* XXX OpenBIOS compatibility hack */
+        retval = reg | (addr & 3);
+    } else if (reg & 1) {
+        /* CFA1 style */
+        retval = (reg & ~7u) | (addr & 7);
+    } else {
+        uint32_t slot, func;
+
+        /* Grab CFA0 style values */
+        slot = ffs(reg & 0xfffff800) - 1;
+        func = (reg >> 8) & 7;
+
+        /* ... and then convert them to x86 format */
+        /* config pointer */
+        retval = (reg & (0xff - 7)) | (addr & 7);
+        /* slot */
+        retval |= slot << 11;
+        /* fn */
+        retval |= func << 8;
+    }
+
+
+    UNIN_DPRINTF("Converted config space accessor %08x/%08x -> %08x\n",
+                 reg, addr, retval);
+
+    return retval;
+}
+
+static void unin_data_write(void *opaque, hwaddr addr,
+                            uint64_t val, unsigned len)
+{
+    UNINState *s = opaque;
+    PCIHostState *phb = PCI_HOST_BRIDGE(s);
+    UNIN_DPRINTF("write addr %" TARGET_FMT_plx " len %d val %"PRIx64"\n",
+                 addr, len, val);
+    pci_data_write(phb->bus,
+                   unin_get_config_reg(phb->config_reg, addr),
+                   val, len);
+}
+
+static uint64_t unin_data_read(void *opaque, hwaddr addr,
+                               unsigned len)
+{
+    UNINState *s = opaque;
+    PCIHostState *phb = PCI_HOST_BRIDGE(s);
+    uint32_t val;
+
+    val = pci_data_read(phb->bus,
+                        unin_get_config_reg(phb->config_reg, addr),
+                        len);
+    UNIN_DPRINTF("read addr %" TARGET_FMT_plx " len %d val %x\n",
+                 addr, len, val);
+    return val;
+}
+
+static const MemoryRegionOps unin_data_ops = {
+    .read = unin_data_read,
+    .write = unin_data_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static int pci_unin_main_init_device(SysBusDevice *dev)
+{
+    PCIHostState *h;
+
+    /* Use values found on a real PowerMac */
+    /* Uninorth main bus */
+    h = PCI_HOST_BRIDGE(dev);
+
+    memory_region_init_io(&h->conf_mem, &pci_host_conf_le_ops,
+                          dev, "pci-conf-idx", 0x1000);
+    memory_region_init_io(&h->data_mem, &unin_data_ops, dev,
+                          "pci-conf-data", 0x1000);
+    sysbus_init_mmio(dev, &h->conf_mem);
+    sysbus_init_mmio(dev, &h->data_mem);
+
+    return 0;
+}
+
+
+static int pci_u3_agp_init_device(SysBusDevice *dev)
+{
+    PCIHostState *h;
+
+    /* Uninorth U3 AGP bus */
+    h = PCI_HOST_BRIDGE(dev);
+
+    memory_region_init_io(&h->conf_mem, &pci_host_conf_le_ops,
+                          dev, "pci-conf-idx", 0x1000);
+    memory_region_init_io(&h->data_mem, &unin_data_ops, dev,
+                          "pci-conf-data", 0x1000);
+    sysbus_init_mmio(dev, &h->conf_mem);
+    sysbus_init_mmio(dev, &h->data_mem);
+
+    return 0;
+}
+
+static int pci_unin_agp_init_device(SysBusDevice *dev)
+{
+    PCIHostState *h;
+
+    /* Uninorth AGP bus */
+    h = PCI_HOST_BRIDGE(dev);
+
+    memory_region_init_io(&h->conf_mem, &pci_host_conf_le_ops,
+                          dev, "pci-conf-idx", 0x1000);
+    memory_region_init_io(&h->data_mem, &pci_host_data_le_ops,
+                          dev, "pci-conf-data", 0x1000);
+    sysbus_init_mmio(dev, &h->conf_mem);
+    sysbus_init_mmio(dev, &h->data_mem);
+    return 0;
+}
+
+static int pci_unin_internal_init_device(SysBusDevice *dev)
+{
+    PCIHostState *h;
+
+    /* Uninorth internal bus */
+    h = PCI_HOST_BRIDGE(dev);
+
+    memory_region_init_io(&h->conf_mem, &pci_host_conf_le_ops,
+                          dev, "pci-conf-idx", 0x1000);
+    memory_region_init_io(&h->data_mem, &pci_host_data_le_ops,
+                          dev, "pci-conf-data", 0x1000);
+    sysbus_init_mmio(dev, &h->conf_mem);
+    sysbus_init_mmio(dev, &h->data_mem);
+    return 0;
+}
+
+PCIBus *pci_pmac_init(qemu_irq *pic,
+                      MemoryRegion *address_space_mem,
+                      MemoryRegion *address_space_io)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+    PCIHostState *h;
+    UNINState *d;
+
+    /* Use values found on a real PowerMac */
+    /* Uninorth main bus */
+    dev = qdev_create(NULL, TYPE_UNI_NORTH_PCI_HOST_BRIDGE);
+    qdev_init_nofail(dev);
+    s = SYS_BUS_DEVICE(dev);
+    h = PCI_HOST_BRIDGE(s);
+    d = UNI_NORTH_PCI_HOST_BRIDGE(dev);
+    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);
+
+    h->bus = pci_register_bus(dev, "pci",
+                              pci_unin_set_irq, pci_unin_map_irq,
+                              pic,
+                              &d->pci_mmio,
+                              address_space_io,
+                              PCI_DEVFN(11, 0), 4, TYPE_PCI_BUS);
+
+#if 0
+    pci_create_simple(h->bus, PCI_DEVFN(11, 0), "uni-north");
+#endif
+
+    sysbus_mmio_map(s, 0, 0xf2800000);
+    sysbus_mmio_map(s, 1, 0xf2c00000);
+
+    /* DEC 21154 bridge */
+#if 0
+    /* XXX: not activated as PPC BIOS doesn't handle multiple buses properly */
+    pci_create_simple(h->bus, PCI_DEVFN(12, 0), "dec-21154");
+#endif
+
+    /* Uninorth AGP bus */
+    pci_create_simple(h->bus, PCI_DEVFN(11, 0), "uni-north-agp");
+    dev = qdev_create(NULL, TYPE_UNI_NORTH_AGP_HOST_BRIDGE);
+    qdev_init_nofail(dev);
+    s = SYS_BUS_DEVICE(dev);
+    sysbus_mmio_map(s, 0, 0xf0800000);
+    sysbus_mmio_map(s, 1, 0xf0c00000);
+
+    /* Uninorth internal bus */
+#if 0
+    /* XXX: not needed for now */
+    pci_create_simple(h->bus, PCI_DEVFN(14, 0),
+                      "uni-north-internal-pci");
+    dev = qdev_create(NULL, TYPE_UNI_NORTH_INTERNAL_PCI_HOST_BRIDGE);
+    qdev_init_nofail(dev);
+    s = SYS_BUS_DEVICE(dev);
+    sysbus_mmio_map(s, 0, 0xf4800000);
+    sysbus_mmio_map(s, 1, 0xf4c00000);
+#endif
+
+    return h->bus;
+}
+
+PCIBus *pci_pmac_u3_init(qemu_irq *pic,
+                         MemoryRegion *address_space_mem,
+                         MemoryRegion *address_space_io)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+    PCIHostState *h;
+    UNINState *d;
+
+    /* Uninorth AGP bus */
+
+    dev = qdev_create(NULL, TYPE_U3_AGP_HOST_BRIDGE);
+    qdev_init_nofail(dev);
+    s = SYS_BUS_DEVICE(dev);
+    h = PCI_HOST_BRIDGE(dev);
+    d = U3_AGP_HOST_BRIDGE(dev);
+
+    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);
+
+    h->bus = pci_register_bus(dev, "pci",
+                              pci_unin_set_irq, pci_unin_map_irq,
+                              pic,
+                              &d->pci_mmio,
+                              address_space_io,
+                              PCI_DEVFN(11, 0), 4, TYPE_PCI_BUS);
+
+    sysbus_mmio_map(s, 0, 0xf0800000);
+    sysbus_mmio_map(s, 1, 0xf0c00000);
+
+    pci_create_simple(h->bus, 11 << 3, "u3-agp");
+
+    return h->bus;
+}
+
+static int unin_main_pci_host_init(PCIDevice *d)
+{
+    d->config[0x0C] = 0x08; // cache_line_size
+    d->config[0x0D] = 0x10; // latency_timer
+    d->config[0x34] = 0x00; // capabilities_pointer
+    return 0;
+}
+
+static int unin_agp_pci_host_init(PCIDevice *d)
+{
+    d->config[0x0C] = 0x08; // cache_line_size
+    d->config[0x0D] = 0x10; // latency_timer
+    //    d->config[0x34] = 0x80; // capabilities_pointer
+    return 0;
+}
+
+static int u3_agp_pci_host_init(PCIDevice *d)
+{
+    /* cache line size */
+    d->config[0x0C] = 0x08;
+    /* latency timer */
+    d->config[0x0D] = 0x10;
+    return 0;
+}
+
+static int unin_internal_pci_host_init(PCIDevice *d)
+{
+    d->config[0x0C] = 0x08; // cache_line_size
+    d->config[0x0D] = 0x10; // latency_timer
+    d->config[0x34] = 0x00; // capabilities_pointer
+    return 0;
+}
+
+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 const TypeInfo unin_main_pci_host_info = {
+    .name = "uni-north-pci",
+    .parent = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PCIDevice),
+    .class_init = unin_main_pci_host_class_init,
+};
+
+static void u3_agp_pci_host_class_init(ObjectClass *klass, void *data)
+{
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init      = u3_agp_pci_host_init;
+    k->vendor_id = PCI_VENDOR_ID_APPLE;
+    k->device_id = PCI_DEVICE_ID_APPLE_U3_AGP;
+    k->revision  = 0x00;
+    k->class_id  = PCI_CLASS_BRIDGE_HOST;
+}
+
+static const TypeInfo u3_agp_pci_host_info = {
+    .name = "u3-agp",
+    .parent = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PCIDevice),
+    .class_init = u3_agp_pci_host_class_init,
+};
+
+static void unin_agp_pci_host_class_init(ObjectClass *klass, void *data)
+{
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init      = unin_agp_pci_host_init;
+    k->vendor_id = PCI_VENDOR_ID_APPLE;
+    k->device_id = PCI_DEVICE_ID_APPLE_UNI_N_AGP;
+    k->revision  = 0x00;
+    k->class_id  = PCI_CLASS_BRIDGE_HOST;
+}
+
+static const TypeInfo unin_agp_pci_host_info = {
+    .name = "uni-north-agp",
+    .parent = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PCIDevice),
+    .class_init = unin_agp_pci_host_class_init,
+};
+
+static void unin_internal_pci_host_class_init(ObjectClass *klass, void *data)
+{
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init      = unin_internal_pci_host_init;
+    k->vendor_id = PCI_VENDOR_ID_APPLE;
+    k->device_id = PCI_DEVICE_ID_APPLE_UNI_N_I_PCI;
+    k->revision  = 0x00;
+    k->class_id  = PCI_CLASS_BRIDGE_HOST;
+}
+
+static const TypeInfo unin_internal_pci_host_info = {
+    .name = "uni-north-internal-pci",
+    .parent = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PCIDevice),
+    .class_init = unin_internal_pci_host_class_init,
+};
+
+static 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 const TypeInfo pci_unin_main_info = {
+    .name          = TYPE_UNI_NORTH_PCI_HOST_BRIDGE,
+    .parent        = TYPE_PCI_HOST_BRIDGE,
+    .instance_size = sizeof(UNINState),
+    .class_init    = pci_unin_main_class_init,
+};
+
+static void pci_u3_agp_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sbc->init = pci_u3_agp_init_device;
+}
+
+static const TypeInfo pci_u3_agp_info = {
+    .name          = TYPE_U3_AGP_HOST_BRIDGE,
+    .parent        = TYPE_PCI_HOST_BRIDGE,
+    .instance_size = sizeof(UNINState),
+    .class_init    = pci_u3_agp_class_init,
+};
+
+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 const TypeInfo pci_unin_agp_info = {
+    .name          = TYPE_UNI_NORTH_AGP_HOST_BRIDGE,
+    .parent        = TYPE_PCI_HOST_BRIDGE,
+    .instance_size = sizeof(UNINState),
+    .class_init    = pci_unin_agp_class_init,
+};
+
+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 const TypeInfo pci_unin_internal_info = {
+    .name          = TYPE_UNI_NORTH_INTERNAL_PCI_HOST_BRIDGE,
+    .parent        = TYPE_PCI_HOST_BRIDGE,
+    .instance_size = sizeof(UNINState),
+    .class_init    = pci_unin_internal_class_init,
+};
+
+static void unin_register_types(void)
+{
+    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);
+}
+
+type_init(unin_register_types)
diff --git a/hw/pci-host/versatile.c b/hw/pci-host/versatile.c
new file mode 100644 (file)
index 0000000..d67ca79
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * ARM Versatile/PB PCI host controller
+ *
+ * Copyright (c) 2006-2009 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the LGPL.
+ */
+
+#include "hw/sysbus.h"
+#include "hw/pci/pci.h"
+#include "hw/pci/pci_host.h"
+#include "exec/address-spaces.h"
+
+typedef struct {
+    SysBusDevice busdev;
+    qemu_irq irq[4];
+    int realview;
+    MemoryRegion mem_config;
+    MemoryRegion mem_config2;
+    MemoryRegion isa;
+} PCIVPBState;
+
+static inline uint32_t vpb_pci_config_addr(hwaddr addr)
+{
+    return addr & 0xffffff;
+}
+
+static void pci_vpb_config_write(void *opaque, hwaddr addr,
+                                 uint64_t val, unsigned size)
+{
+    pci_data_write(opaque, vpb_pci_config_addr(addr), val, size);
+}
+
+static uint64_t pci_vpb_config_read(void *opaque, hwaddr addr,
+                                    unsigned size)
+{
+    uint32_t val;
+    val = pci_data_read(opaque, vpb_pci_config_addr(addr), size);
+    return val;
+}
+
+static const MemoryRegionOps pci_vpb_config_ops = {
+    .read = pci_vpb_config_read,
+    .write = pci_vpb_config_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int pci_vpb_map_irq(PCIDevice *d, int irq_num)
+{
+    return irq_num;
+}
+
+static void pci_vpb_set_irq(void *opaque, int irq_num, int level)
+{
+    qemu_irq *pic = opaque;
+
+    qemu_set_irq(pic[irq_num], level);
+}
+
+static int pci_vpb_init(SysBusDevice *dev)
+{
+    PCIVPBState *s = FROM_SYSBUS(PCIVPBState, dev);
+    PCIBus *bus;
+    int i;
+
+    for (i = 0; i < 4; i++) {
+        sysbus_init_irq(dev, &s->irq[i]);
+    }
+    bus = pci_register_bus(&dev->qdev, "pci",
+                           pci_vpb_set_irq, pci_vpb_map_irq, s->irq,
+                           get_system_memory(), get_system_io(),
+                           PCI_DEVFN(11, 0), 4, TYPE_PCI_BUS);
+
+    /* ??? Register memory space.  */
+
+    /* Our memory regions are:
+     * 0 : PCI self config window
+     * 1 : PCI config window
+     * 2 : PCI IO window (realview_pci only)
+     */
+    memory_region_init_io(&s->mem_config, &pci_vpb_config_ops, bus,
+                          "pci-vpb-selfconfig", 0x1000000);
+    sysbus_init_mmio(dev, &s->mem_config);
+    memory_region_init_io(&s->mem_config2, &pci_vpb_config_ops, bus,
+                          "pci-vpb-config", 0x1000000);
+    sysbus_init_mmio(dev, &s->mem_config2);
+    if (s->realview) {
+        isa_mmio_setup(&s->isa, 0x0100000);
+        sysbus_init_mmio(dev, &s->isa);
+    }
+
+    pci_create_simple(bus, -1, "versatile_pci_host");
+    return 0;
+}
+
+static int pci_realview_init(SysBusDevice *dev)
+{
+    PCIVPBState *s = FROM_SYSBUS(PCIVPBState, dev);
+    s->realview = 1;
+    return pci_vpb_init(dev);
+}
+
+static int versatile_pci_host_init(PCIDevice *d)
+{
+    pci_set_word(d->config + PCI_STATUS,
+                PCI_STATUS_66MHZ | PCI_STATUS_DEVSEL_MEDIUM);
+    pci_set_byte(d->config + PCI_LATENCY_TIMER, 0x10);
+    return 0;
+}
+
+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 const TypeInfo versatile_pci_host_info = {
+    .name          = "versatile_pci_host",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PCIDevice),
+    .class_init    = versatile_pci_host_class_init,
+};
+
+static void pci_vpb_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sdc->init = pci_vpb_init;
+}
+
+static const TypeInfo pci_vpb_info = {
+    .name          = "versatile_pci",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(PCIVPBState),
+    .class_init    = pci_vpb_class_init,
+};
+
+static void pci_realview_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sdc->init = pci_realview_init;
+}
+
+static const 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_types(void)
+{
+    type_register_static(&pci_vpb_info);
+    type_register_static(&pci_realview_info);
+    type_register_static(&versatile_pci_host_info);
+}
+
+type_init(versatile_pci_register_types)
index 1cd6cde2ee05713e0849e11167acca6bf0b0bb79..a7fb9d0c1199367d046d8a95af0aaa2aa8d95225 100644 (file)
@@ -4,6 +4,8 @@ common-obj-$(CONFIG_PCI) += shpc.o
 common-obj-$(CONFIG_PCI) += slotid_cap.o
 common-obj-$(CONFIG_PCI) += pci_host.o pcie_host.o
 common-obj-$(CONFIG_PCI) += pcie.o pcie_aer.o pcie_port.o
-common-obj-$(CONFIG_NO_PCI) += pci-stub.o
 
+common-obj-$(CONFIG_NO_PCI) += pci-stub.o
 common-obj-$(CONFIG_ALL) += pci-stub.o
+
+obj-$(CONFIG_PCI_HOTPLUG) += pci-hotplug.o
diff --git a/hw/pci/msi.h b/hw/pci/msi.h
deleted file mode 100644 (file)
index 81a3848..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * msi.h
- *
- * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
- *                    VA Linux Systems Japan K.K.
- *
- * 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 QEMU_MSI_H
-#define QEMU_MSI_H
-
-#include "qemu-common.h"
-#include "hw/pci/pci.h"
-
-struct MSIMessage {
-    uint64_t address;
-    uint32_t data;
-};
-
-extern bool msi_supported;
-
-void msi_set_message(PCIDevice *dev, MSIMessage msg);
-MSIMessage msi_get_message(PCIDevice *dev, unsigned int vector);
-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);
-void msi_uninit(struct PCIDevice *dev);
-void msi_reset(PCIDevice *dev);
-void msi_notify(PCIDevice *dev, unsigned int vector);
-void msi_write_config(PCIDevice *dev, uint32_t addr, uint32_t val, int len);
-unsigned int msi_nr_vectors_allocated(const PCIDevice *dev);
-
-static inline bool msi_present(const PCIDevice *dev)
-{
-    return dev->cap_present & QEMU_PCI_CAP_MSI;
-}
-
-#endif /* QEMU_MSI_H */
diff --git a/hw/pci/msix.h b/hw/pci/msix.h
deleted file mode 100644 (file)
index e648410..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-#ifndef QEMU_MSIX_H
-#define QEMU_MSIX_H
-
-#include "qemu-common.h"
-#include "hw/pci/pci.h"
-
-void msix_set_message(PCIDevice *dev, int vector, MSIMessage msg);
-MSIMessage msix_get_message(PCIDevice *dev, unsigned int vector);
-int msix_init(PCIDevice *dev, unsigned short nentries,
-              MemoryRegion *table_bar, uint8_t table_bar_nr,
-              unsigned table_offset, MemoryRegion *pba_bar,
-              uint8_t pba_bar_nr, unsigned pba_offset, uint8_t cap_pos);
-int msix_init_exclusive_bar(PCIDevice *dev, unsigned short nentries,
-                            uint8_t bar_nr);
-
-void msix_write_config(PCIDevice *dev, uint32_t address, uint32_t val, int len);
-
-void msix_uninit(PCIDevice *dev, MemoryRegion *table_bar,
-                 MemoryRegion *pba_bar);
-void msix_uninit_exclusive_bar(PCIDevice *dev);
-
-unsigned int msix_nr_vectors_allocated(const PCIDevice *dev);
-
-void msix_save(PCIDevice *dev, QEMUFile *f);
-void msix_load(PCIDevice *dev, QEMUFile *f);
-
-int msix_enabled(PCIDevice *dev);
-int msix_present(PCIDevice *dev);
-
-bool msix_is_masked(PCIDevice *dev, unsigned vector);
-void msix_set_pending(PCIDevice *dev, unsigned vector);
-
-int msix_vector_use(PCIDevice *dev, unsigned vector);
-void msix_vector_unuse(PCIDevice *dev, unsigned vector);
-void msix_unuse_all_vectors(PCIDevice *dev);
-
-void msix_notify(PCIDevice *dev, unsigned vector);
-
-void msix_reset(PCIDevice *dev);
-
-int msix_set_vector_notifiers(PCIDevice *dev,
-                              MSIVectorUseNotifier use_notifier,
-                              MSIVectorReleaseNotifier release_notifier,
-                              MSIVectorPollNotifier poll_notifier);
-void msix_unset_vector_notifiers(PCIDevice *dev);
-#endif
index f38df30540fa89bbcab982d5b5804c4e2f658961..12287d1efcb78197e784e5697ceb991b29f67cc6 100644 (file)
 #include "hw/boards.h"
 #include "hw/pci/pci.h"
 #include "net/net.h"
-#include "hw/pc.h"
+#include "hw/i386/pc.h"
 #include "monitor/monitor.h"
-#include "hw/scsi.h"
-#include "hw/virtio-blk.h"
+#include "hw/scsi/scsi.h"
+#include "hw/virtio/virtio-blk.h"
 #include "qemu/config-file.h"
 #include "sysemu/blockdev.h"
 #include "qapi/error.h"
@@ -99,7 +99,7 @@ static int scsi_hot_add(Monitor *mon, DeviceState *adapter,
     dinfo->unit = qemu_opt_get_number(dinfo->opts, "unit", -1);
     dinfo->bus = scsibus->busnr;
     scsidev = scsi_bus_legacy_add_drive(scsibus, dinfo->bdrv, dinfo->unit,
-                                        false, -1);
+                                        false, -1, NULL);
     if (!scsidev) {
         return -1;
     }
diff --git a/hw/pci/pci.h b/hw/pci/pci.h
deleted file mode 100644 (file)
index 9ea67a3..0000000
+++ /dev/null
@@ -1,725 +0,0 @@
-#ifndef QEMU_PCI_H
-#define QEMU_PCI_H
-
-#include "qemu-common.h"
-
-#include "hw/qdev.h"
-#include "exec/memory.h"
-#include "sysemu/dma.h"
-
-/* PCI includes legacy ISA access.  */
-#include "hw/isa.h"
-
-#include "hw/pci/pcie.h"
-
-/* PCI bus */
-
-#define PCI_DEVFN(slot, func)   ((((slot) & 0x1f) << 3) | ((func) & 0x07))
-#define PCI_SLOT(devfn)         (((devfn) >> 3) & 0x1f)
-#define PCI_FUNC(devfn)         ((devfn) & 0x07)
-#define PCI_SLOT_MAX            32
-#define PCI_FUNC_MAX            8
-
-/* Class, Vendor and Device IDs from Linux's pci_ids.h */
-#include "hw/pci/pci_ids.h"
-
-/* QEMU-specific Vendor and Device ID definitions */
-
-/* IBM (0x1014) */
-#define PCI_DEVICE_ID_IBM_440GX          0x027f
-#define PCI_DEVICE_ID_IBM_OPENPIC2       0xffff
-
-/* Hitachi (0x1054) */
-#define PCI_VENDOR_ID_HITACHI            0x1054
-#define PCI_DEVICE_ID_HITACHI_SH7751R    0x350e
-
-/* Apple (0x106b) */
-#define PCI_DEVICE_ID_APPLE_343S1201     0x0010
-#define PCI_DEVICE_ID_APPLE_UNI_N_I_PCI  0x001e
-#define PCI_DEVICE_ID_APPLE_UNI_N_PCI    0x001f
-#define PCI_DEVICE_ID_APPLE_UNI_N_KEYL   0x0022
-#define PCI_DEVICE_ID_APPLE_IPID_USB     0x003f
-
-/* Realtek (0x10ec) */
-#define PCI_DEVICE_ID_REALTEK_8029       0x8029
-
-/* Xilinx (0x10ee) */
-#define PCI_DEVICE_ID_XILINX_XC2VP30     0x0300
-
-/* Marvell (0x11ab) */
-#define PCI_DEVICE_ID_MARVELL_GT6412X    0x4620
-
-/* QEMU/Bochs VGA (0x1234) */
-#define PCI_VENDOR_ID_QEMU               0x1234
-#define PCI_DEVICE_ID_QEMU_VGA           0x1111
-
-/* VMWare (0x15ad) */
-#define PCI_VENDOR_ID_VMWARE             0x15ad
-#define PCI_DEVICE_ID_VMWARE_SVGA2       0x0405
-#define PCI_DEVICE_ID_VMWARE_SVGA        0x0710
-#define PCI_DEVICE_ID_VMWARE_NET         0x0720
-#define PCI_DEVICE_ID_VMWARE_SCSI        0x0730
-#define PCI_DEVICE_ID_VMWARE_IDE         0x1729
-#define PCI_DEVICE_ID_VMWARE_VMXNET3     0x07B0
-
-/* Intel (0x8086) */
-#define PCI_DEVICE_ID_INTEL_82551IT      0x1209
-#define PCI_DEVICE_ID_INTEL_82557        0x1229
-#define PCI_DEVICE_ID_INTEL_82801IR      0x2922
-
-/* Red Hat / Qumranet (for QEMU) -- see pci-ids.txt */
-#define PCI_VENDOR_ID_REDHAT_QUMRANET    0x1af4
-#define PCI_SUBVENDOR_ID_REDHAT_QUMRANET 0x1af4
-#define PCI_SUBDEVICE_ID_QEMU            0x1100
-
-#define PCI_DEVICE_ID_VIRTIO_NET         0x1000
-#define PCI_DEVICE_ID_VIRTIO_BLOCK       0x1001
-#define PCI_DEVICE_ID_VIRTIO_BALLOON     0x1002
-#define PCI_DEVICE_ID_VIRTIO_CONSOLE     0x1003
-#define PCI_DEVICE_ID_VIRTIO_SCSI        0x1004
-#define PCI_DEVICE_ID_VIRTIO_RNG         0x1005
-#define PCI_DEVICE_ID_VIRTIO_9P          0x1009
-
-#define PCI_VENDOR_ID_REDHAT             0x1b36
-#define PCI_DEVICE_ID_REDHAT_BRIDGE      0x0001
-#define PCI_DEVICE_ID_REDHAT_SERIAL      0x0002
-#define PCI_DEVICE_ID_REDHAT_SERIAL2     0x0003
-#define PCI_DEVICE_ID_REDHAT_SERIAL4     0x0004
-#define PCI_DEVICE_ID_REDHAT_QXL         0x0100
-
-#define FMT_PCIBUS                      PRIx64
-
-typedef void PCIConfigWriteFunc(PCIDevice *pci_dev,
-                                uint32_t address, uint32_t data, int len);
-typedef uint32_t PCIConfigReadFunc(PCIDevice *pci_dev,
-                                   uint32_t address, int len);
-typedef void PCIMapIORegionFunc(PCIDevice *pci_dev, int region_num,
-                                pcibus_t addr, pcibus_t size, int type);
-typedef void PCIUnregisterFunc(PCIDevice *pci_dev);
-
-typedef struct PCIIORegion {
-    pcibus_t addr; /* current PCI mapping address. -1 means not mapped */
-#define PCI_BAR_UNMAPPED (~(pcibus_t)0)
-    pcibus_t size;
-    uint8_t type;
-    MemoryRegion *memory;
-    MemoryRegion *address_space;
-} PCIIORegion;
-
-#define PCI_ROM_SLOT 6
-#define PCI_NUM_REGIONS 7
-
-enum {
-    QEMU_PCI_VGA_MEM,
-    QEMU_PCI_VGA_IO_LO,
-    QEMU_PCI_VGA_IO_HI,
-    QEMU_PCI_VGA_NUM_REGIONS,
-};
-
-#define QEMU_PCI_VGA_MEM_BASE 0xa0000
-#define QEMU_PCI_VGA_MEM_SIZE 0x20000
-#define QEMU_PCI_VGA_IO_LO_BASE 0x3b0
-#define QEMU_PCI_VGA_IO_LO_SIZE 0xc
-#define QEMU_PCI_VGA_IO_HI_BASE 0x3c0
-#define QEMU_PCI_VGA_IO_HI_SIZE 0x20
-
-#include "hw/pci/pci_regs.h"
-
-/* PCI HEADER_TYPE */
-#define  PCI_HEADER_TYPE_MULTI_FUNCTION 0x80
-
-/* Size of the standard PCI config header */
-#define PCI_CONFIG_HEADER_SIZE 0x40
-/* Size of the standard PCI config space */
-#define PCI_CONFIG_SPACE_SIZE 0x100
-/* Size of the standart PCIe config space: 4KB */
-#define PCIE_CONFIG_SPACE_SIZE  0x1000
-
-#define PCI_NUM_PINS 4 /* A-D */
-
-/* Bits in cap_present field. */
-enum {
-    QEMU_PCI_CAP_MSI = 0x1,
-    QEMU_PCI_CAP_MSIX = 0x2,
-    QEMU_PCI_CAP_EXPRESS = 0x4,
-
-    /* multifunction capable device */
-#define QEMU_PCI_CAP_MULTIFUNCTION_BITNR        3
-    QEMU_PCI_CAP_MULTIFUNCTION = (1 << QEMU_PCI_CAP_MULTIFUNCTION_BITNR),
-
-    /* command register SERR bit enabled */
-#define QEMU_PCI_CAP_SERR_BITNR 4
-    QEMU_PCI_CAP_SERR = (1 << QEMU_PCI_CAP_SERR_BITNR),
-    /* Standard hot plug controller. */
-#define QEMU_PCI_SHPC_BITNR 5
-    QEMU_PCI_CAP_SHPC = (1 << QEMU_PCI_SHPC_BITNR),
-#define QEMU_PCI_SLOTID_BITNR 6
-    QEMU_PCI_CAP_SLOTID = (1 << QEMU_PCI_SLOTID_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 PCIINTxRoute {
-    enum {
-        PCI_INTX_ENABLED,
-        PCI_INTX_INVERTED,
-        PCI_INTX_DISABLED,
-    } mode;
-    int irq;
-} PCIINTxRoute;
-
-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;
-
-typedef void (*PCIINTxRoutingNotifier)(PCIDevice *dev);
-typedef int (*MSIVectorUseNotifier)(PCIDevice *dev, unsigned int vector,
-                                      MSIMessage msg);
-typedef void (*MSIVectorReleaseNotifier)(PCIDevice *dev, unsigned int vector);
-typedef void (*MSIVectorPollNotifier)(PCIDevice *dev,
-                                      unsigned int vector_start,
-                                      unsigned int vector_end);
-
-struct PCIDevice {
-    DeviceState qdev;
-
-    /* PCI config space */
-    uint8_t *config;
-
-    /* Used to enable config checks on load. Note that writable bits are
-     * never checked even if set in cmask. */
-    uint8_t *cmask;
-
-    /* Used to implement R/W bytes */
-    uint8_t *wmask;
-
-    /* Used to implement RW1C(Write 1 to Clear) bytes */
-    uint8_t *w1cmask;
-
-    /* Used to allocate config space for capabilities. */
-    uint8_t *used;
-
-    /* the following fields are read only */
-    PCIBus *bus;
-    int32_t devfn;
-    char name[64];
-    PCIIORegion io_regions[PCI_NUM_REGIONS];
-    AddressSpace bus_master_as;
-    MemoryRegion bus_master_enable_region;
-    DMAContext *dma;
-
-    /* do not access the following fields */
-    PCIConfigReadFunc *config_read;
-    PCIConfigWriteFunc *config_write;
-
-    /* IRQ objects for the INTA-INTD pins.  */
-    qemu_irq *irq;
-
-    /* Legacy PCI VGA regions */
-    MemoryRegion *vga_regions[QEMU_PCI_VGA_NUM_REGIONS];
-    bool has_vga;
-
-    /* Current IRQ levels.  Used internally by the generic PCI code.  */
-    uint8_t irq_state;
-
-    /* Capability bits */
-    uint32_t cap_present;
-
-    /* Offset of MSI-X capability in config space */
-    uint8_t msix_cap;
-
-    /* MSI-X entries */
-    int msix_entries_nr;
-
-    /* Space to store MSIX table & pending bit array */
-    uint8_t *msix_table;
-    uint8_t *msix_pba;
-    /* MemoryRegion container for msix exclusive BAR setup */
-    MemoryRegion msix_exclusive_bar;
-    /* Memory Regions for MSIX table and pending bit entries. */
-    MemoryRegion msix_table_mmio;
-    MemoryRegion msix_pba_mmio;
-    /* Reference-count for entries actually in use by driver. */
-    unsigned *msix_entry_used;
-    /* MSIX function mask set or MSIX disabled */
-    bool msix_function_masked;
-    /* Version id needed for VMState */
-    int32_t version_id;
-
-    /* Offset of MSI capability in config space */
-    uint8_t msi_cap;
-
-    /* PCI Express */
-    PCIExpressDevice exp;
-
-    /* SHPC */
-    SHPCDevice *shpc;
-
-    /* Location of option rom */
-    char *romfile;
-    bool has_rom;
-    MemoryRegion rom;
-    uint32_t rom_bar;
-
-    /* INTx routing notifier */
-    PCIINTxRoutingNotifier intx_routing_notifier;
-
-    /* MSI-X notifiers */
-    MSIVectorUseNotifier msix_vector_use_notifier;
-    MSIVectorReleaseNotifier msix_vector_release_notifier;
-    MSIVectorPollNotifier msix_vector_poll_notifier;
-};
-
-void pci_register_bar(PCIDevice *pci_dev, int region_num,
-                      uint8_t attr, MemoryRegion *memory);
-void pci_register_vga(PCIDevice *pci_dev, MemoryRegion *mem,
-                      MemoryRegion *io_lo, MemoryRegion *io_hi);
-void pci_unregister_vga(PCIDevice *pci_dev);
-pcibus_t pci_get_bar_addr(PCIDevice *pci_dev, int region_num);
-
-int pci_add_capability(PCIDevice *pdev, uint8_t cap_id,
-                       uint8_t offset, uint8_t size);
-
-void pci_del_capability(PCIDevice *pci_dev, uint8_t cap_id, uint8_t cap_size);
-
-uint8_t pci_find_capability(PCIDevice *pci_dev, uint8_t cap_id);
-
-
-uint32_t pci_default_read_config(PCIDevice *d,
-                                 uint32_t address, int len);
-void pci_default_write_config(PCIDevice *d,
-                              uint32_t address, uint32_t val, int len);
-void pci_device_save(PCIDevice *s, QEMUFile *f);
-int pci_device_load(PCIDevice *s, QEMUFile *f);
-MemoryRegion *pci_address_space(PCIDevice *dev);
-MemoryRegion *pci_address_space_io(PCIDevice *dev);
-
-typedef void (*pci_set_irq_fn)(void *opaque, int irq_num, int level);
-typedef int (*pci_map_irq_fn)(PCIDevice *pci_dev, int irq_num);
-typedef PCIINTxRoute (*pci_route_irq_fn)(void *opaque, int pin);
-
-typedef enum {
-    PCI_HOTPLUG_DISABLED,
-    PCI_HOTPLUG_ENABLED,
-    PCI_COLDPLUG_ENABLED,
-} PCIHotplugState;
-
-typedef int (*pci_hotplug_fn)(DeviceState *qdev, PCIDevice *pci_dev,
-                              PCIHotplugState state);
-
-#define TYPE_PCI_BUS "PCI"
-#define PCI_BUS(obj) OBJECT_CHECK(PCIBus, (obj), TYPE_PCI_BUS)
-#define TYPE_PCIE_BUS "PCIE"
-
-bool pci_bus_is_express(PCIBus *bus);
-bool pci_bus_is_root(PCIBus *bus);
-void pci_bus_new_inplace(PCIBus *bus, DeviceState *parent,
-                         const char *name,
-                         MemoryRegion *address_space_mem,
-                         MemoryRegion *address_space_io,
-                         uint8_t devfn_min, const char *typename);
-PCIBus *pci_bus_new(DeviceState *parent, const char *name,
-                    MemoryRegion *address_space_mem,
-                    MemoryRegion *address_space_io,
-                    uint8_t devfn_min, const char *typename);
-void pci_bus_irqs(PCIBus *bus, pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
-                  void *irq_opaque, int nirq);
-int pci_bus_get_irq_level(PCIBus *bus, int irq_num);
-void pci_bus_hotplug(PCIBus *bus, pci_hotplug_fn hotplug, DeviceState *dev);
-/* 0 <= pin <= 3 0 = INTA, 1 = INTB, 2 = INTC, 3 = INTD */
-int pci_swizzle_map_irq_fn(PCIDevice *pci_dev, int pin);
-PCIBus *pci_register_bus(DeviceState *parent, const char *name,
-                         pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
-                         void *irq_opaque,
-                         MemoryRegion *address_space_mem,
-                         MemoryRegion *address_space_io,
-                         uint8_t devfn_min, int nirq, const char *typename);
-void pci_bus_set_route_irq_fn(PCIBus *, pci_route_irq_fn);
-PCIINTxRoute pci_device_route_intx_to_irq(PCIDevice *dev, int pin);
-bool pci_intx_route_changed(PCIINTxRoute *old, PCIINTxRoute *new);
-void pci_bus_fire_intx_routing_notifier(PCIBus *bus);
-void pci_device_set_intx_routing_notifier(PCIDevice *dev,
-                                          PCIINTxRoutingNotifier notifier);
-void pci_device_reset(PCIDevice *dev);
-void pci_bus_reset(PCIBus *bus);
-
-PCIDevice *pci_nic_init(NICInfo *nd, const char *default_model,
-                        const char *default_devaddr);
-PCIDevice *pci_nic_init_nofail(NICInfo *nd, const char *default_model,
-                               const char *default_devaddr);
-
-PCIDevice *pci_vga_init(PCIBus *bus);
-
-int pci_bus_num(PCIBus *s);
-void pci_for_each_device(PCIBus *bus, int bus_num,
-                         void (*fn)(PCIBus *bus, PCIDevice *d, void *opaque),
-                         void *opaque);
-PCIBus *pci_find_root_bus(int domain);
-int pci_find_domain(const PCIBus *bus);
-PCIDevice *pci_find_device(PCIBus *bus, int bus_num, uint8_t devfn);
-int pci_qdev_find_device(const char *id, PCIDevice **pdev);
-PCIBus *pci_get_bus_devfn(int *devfnp, const char *devaddr);
-
-int pci_read_devaddr(Monitor *mon, const char *addr, int *domp, int *busp,
-                     unsigned *slotp);
-
-void pci_device_deassert_intx(PCIDevice *dev);
-
-typedef DMAContext *(*PCIDMAContextFunc)(PCIBus *, void *, int);
-
-void pci_setup_iommu(PCIBus *bus, PCIDMAContextFunc fn, void *opaque);
-
-static inline void
-pci_set_byte(uint8_t *config, uint8_t val)
-{
-    *config = val;
-}
-
-static inline uint8_t
-pci_get_byte(const uint8_t *config)
-{
-    return *config;
-}
-
-static inline void
-pci_set_word(uint8_t *config, uint16_t val)
-{
-    cpu_to_le16wu((uint16_t *)config, val);
-}
-
-static inline uint16_t
-pci_get_word(const uint8_t *config)
-{
-    return le16_to_cpupu((const uint16_t *)config);
-}
-
-static inline void
-pci_set_long(uint8_t *config, uint32_t val)
-{
-    cpu_to_le32wu((uint32_t *)config, val);
-}
-
-static inline uint32_t
-pci_get_long(const uint8_t *config)
-{
-    return le32_to_cpupu((const uint32_t *)config);
-}
-
-static inline void
-pci_set_quad(uint8_t *config, uint64_t val)
-{
-    cpu_to_le64w((uint64_t *)config, val);
-}
-
-static inline uint64_t
-pci_get_quad(const uint8_t *config)
-{
-    return le64_to_cpup((const uint64_t *)config);
-}
-
-static inline void
-pci_config_set_vendor_id(uint8_t *pci_config, uint16_t val)
-{
-    pci_set_word(&pci_config[PCI_VENDOR_ID], val);
-}
-
-static inline void
-pci_config_set_device_id(uint8_t *pci_config, uint16_t val)
-{
-    pci_set_word(&pci_config[PCI_DEVICE_ID], val);
-}
-
-static inline void
-pci_config_set_revision(uint8_t *pci_config, uint8_t val)
-{
-    pci_set_byte(&pci_config[PCI_REVISION_ID], val);
-}
-
-static inline void
-pci_config_set_class(uint8_t *pci_config, uint16_t val)
-{
-    pci_set_word(&pci_config[PCI_CLASS_DEVICE], val);
-}
-
-static inline void
-pci_config_set_prog_interface(uint8_t *pci_config, uint8_t val)
-{
-    pci_set_byte(&pci_config[PCI_CLASS_PROG], val);
-}
-
-static inline void
-pci_config_set_interrupt_pin(uint8_t *pci_config, uint8_t val)
-{
-    pci_set_byte(&pci_config[PCI_INTERRUPT_PIN], val);
-}
-
-/*
- * helper functions to do bit mask operation on configuration space.
- * Just to set bit, use test-and-set and discard returned value.
- * Just to clear bit, use test-and-clear and discard returned value.
- * NOTE: They aren't atomic.
- */
-static inline uint8_t
-pci_byte_test_and_clear_mask(uint8_t *config, uint8_t mask)
-{
-    uint8_t val = pci_get_byte(config);
-    pci_set_byte(config, val & ~mask);
-    return val & mask;
-}
-
-static inline uint8_t
-pci_byte_test_and_set_mask(uint8_t *config, uint8_t mask)
-{
-    uint8_t val = pci_get_byte(config);
-    pci_set_byte(config, val | mask);
-    return val & mask;
-}
-
-static inline uint16_t
-pci_word_test_and_clear_mask(uint8_t *config, uint16_t mask)
-{
-    uint16_t val = pci_get_word(config);
-    pci_set_word(config, val & ~mask);
-    return val & mask;
-}
-
-static inline uint16_t
-pci_word_test_and_set_mask(uint8_t *config, uint16_t mask)
-{
-    uint16_t val = pci_get_word(config);
-    pci_set_word(config, val | mask);
-    return val & mask;
-}
-
-static inline uint32_t
-pci_long_test_and_clear_mask(uint8_t *config, uint32_t mask)
-{
-    uint32_t val = pci_get_long(config);
-    pci_set_long(config, val & ~mask);
-    return val & mask;
-}
-
-static inline uint32_t
-pci_long_test_and_set_mask(uint8_t *config, uint32_t mask)
-{
-    uint32_t val = pci_get_long(config);
-    pci_set_long(config, val | mask);
-    return val & mask;
-}
-
-static inline uint64_t
-pci_quad_test_and_clear_mask(uint8_t *config, uint64_t mask)
-{
-    uint64_t val = pci_get_quad(config);
-    pci_set_quad(config, val & ~mask);
-    return val & mask;
-}
-
-static inline uint64_t
-pci_quad_test_and_set_mask(uint8_t *config, uint64_t mask)
-{
-    uint64_t val = pci_get_quad(config);
-    pci_set_quad(config, val | mask);
-    return val & mask;
-}
-
-/* Access a register specified by a mask */
-static inline void
-pci_set_byte_by_mask(uint8_t *config, uint8_t mask, uint8_t reg)
-{
-    uint8_t val = pci_get_byte(config);
-    uint8_t rval = reg << (ffs(mask) - 1);
-    pci_set_byte(config, (~mask & val) | (mask & rval));
-}
-
-static inline uint8_t
-pci_get_byte_by_mask(uint8_t *config, uint8_t mask)
-{
-    uint8_t val = pci_get_byte(config);
-    return (val & mask) >> (ffs(mask) - 1);
-}
-
-static inline void
-pci_set_word_by_mask(uint8_t *config, uint16_t mask, uint16_t reg)
-{
-    uint16_t val = pci_get_word(config);
-    uint16_t rval = reg << (ffs(mask) - 1);
-    pci_set_word(config, (~mask & val) | (mask & rval));
-}
-
-static inline uint16_t
-pci_get_word_by_mask(uint8_t *config, uint16_t mask)
-{
-    uint16_t val = pci_get_word(config);
-    return (val & mask) >> (ffs(mask) - 1);
-}
-
-static inline void
-pci_set_long_by_mask(uint8_t *config, uint32_t mask, uint32_t reg)
-{
-    uint32_t val = pci_get_long(config);
-    uint32_t rval = reg << (ffs(mask) - 1);
-    pci_set_long(config, (~mask & val) | (mask & rval));
-}
-
-static inline uint32_t
-pci_get_long_by_mask(uint8_t *config, uint32_t mask)
-{
-    uint32_t val = pci_get_long(config);
-    return (val & mask) >> (ffs(mask) - 1);
-}
-
-static inline void
-pci_set_quad_by_mask(uint8_t *config, uint64_t mask, uint64_t reg)
-{
-    uint64_t val = pci_get_quad(config);
-    uint64_t rval = reg << (ffs(mask) - 1);
-    pci_set_quad(config, (~mask & val) | (mask & rval));
-}
-
-static inline uint64_t
-pci_get_quad_by_mask(uint8_t *config, uint64_t mask)
-{
-    uint64_t val = pci_get_quad(config);
-    return (val & mask) >> (ffs(mask) - 1);
-}
-
-PCIDevice *pci_create_multifunction(PCIBus *bus, int devfn, bool multifunction,
-                                    const char *name);
-PCIDevice *pci_create_simple_multifunction(PCIBus *bus, int devfn,
-                                           bool multifunction,
-                                           const char *name);
-PCIDevice *pci_create(PCIBus *bus, int devfn, const char *name);
-PCIDevice *pci_create_simple(PCIBus *bus, int devfn, const char *name);
-
-static inline int pci_is_express(const PCIDevice *d)
-{
-    return d->cap_present & QEMU_PCI_CAP_EXPRESS;
-}
-
-static inline uint32_t pci_config_size(const PCIDevice *d)
-{
-    return pci_is_express(d) ? PCIE_CONFIG_SPACE_SIZE : PCI_CONFIG_SPACE_SIZE;
-}
-
-/* DMA access functions */
-static inline DMAContext *pci_dma_context(PCIDevice *dev)
-{
-    return dev->dma;
-}
-
-static inline int pci_dma_rw(PCIDevice *dev, dma_addr_t addr,
-                             void *buf, dma_addr_t len, DMADirection dir)
-{
-    dma_memory_rw(pci_dma_context(dev), addr, buf, len, dir);
-    return 0;
-}
-
-static inline int pci_dma_read(PCIDevice *dev, dma_addr_t addr,
-                               void *buf, dma_addr_t len)
-{
-    return pci_dma_rw(dev, addr, buf, len, DMA_DIRECTION_TO_DEVICE);
-}
-
-static inline int pci_dma_write(PCIDevice *dev, dma_addr_t addr,
-                                const void *buf, dma_addr_t len)
-{
-    return pci_dma_rw(dev, addr, (void *) buf, len, DMA_DIRECTION_FROM_DEVICE);
-}
-
-#define PCI_DMA_DEFINE_LDST(_l, _s, _bits)                              \
-    static inline uint##_bits##_t ld##_l##_pci_dma(PCIDevice *dev,      \
-                                                   dma_addr_t addr)     \
-    {                                                                   \
-        return ld##_l##_dma(pci_dma_context(dev), addr);                \
-    }                                                                   \
-    static inline void st##_s##_pci_dma(PCIDevice *dev,                 \
-                                        dma_addr_t addr, uint##_bits##_t val) \
-    {                                                                   \
-        st##_s##_dma(pci_dma_context(dev), addr, val);                  \
-    }
-
-PCI_DMA_DEFINE_LDST(ub, b, 8);
-PCI_DMA_DEFINE_LDST(uw_le, w_le, 16)
-PCI_DMA_DEFINE_LDST(l_le, l_le, 32);
-PCI_DMA_DEFINE_LDST(q_le, q_le, 64);
-PCI_DMA_DEFINE_LDST(uw_be, w_be, 16)
-PCI_DMA_DEFINE_LDST(l_be, l_be, 32);
-PCI_DMA_DEFINE_LDST(q_be, q_be, 64);
-
-#undef PCI_DMA_DEFINE_LDST
-
-static inline void *pci_dma_map(PCIDevice *dev, dma_addr_t addr,
-                                dma_addr_t *plen, DMADirection dir)
-{
-    void *buf;
-
-    buf = dma_memory_map(pci_dma_context(dev), addr, plen, dir);
-    return buf;
-}
-
-static inline void pci_dma_unmap(PCIDevice *dev, void *buffer, dma_addr_t len,
-                                 DMADirection dir, dma_addr_t access_len)
-{
-    dma_memory_unmap(pci_dma_context(dev), buffer, len, dir, access_len);
-}
-
-static inline void pci_dma_sglist_init(QEMUSGList *qsg, PCIDevice *dev,
-                                       int alloc_hint)
-{
-    qemu_sglist_init(qsg, alloc_hint, pci_dma_context(dev));
-}
-
-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/pci/pci_bridge.h b/hw/pci/pci_bridge.h
deleted file mode 100644 (file)
index 1868f7a..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * QEMU PCI bridge
- *
- * Copyright (c) 2004 Fabrice Bellard
- *
- * 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, write to the Free Software
- * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- *
- * split out pci bus specific stuff from pci.[hc] to pci_bridge.[hc]
- * Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp>
- *                    VA Linux Systems Japan K.K.
- *
- */
-
-#ifndef QEMU_PCI_BRIDGE_H
-#define QEMU_PCI_BRIDGE_H
-
-#include "hw/pci/pci.h"
-
-int pci_bridge_ssvid_init(PCIDevice *dev, uint8_t offset,
-                          uint16_t svid, uint16_t ssid);
-
-PCIDevice *pci_bridge_get_device(PCIBus *bus);
-PCIBus *pci_bridge_get_sec_bus(PCIBridge *br);
-
-pcibus_t pci_bridge_get_base(const PCIDevice *bridge, uint8_t type);
-pcibus_t pci_bridge_get_limit(const PCIDevice *bridge, uint8_t type);
-
-void pci_bridge_write_config(PCIDevice *d,
-                             uint32_t address, uint32_t val, int len);
-void pci_bridge_disable_base_limit(PCIDevice *dev);
-void pci_bridge_reset_reg(PCIDevice *dev);
-void pci_bridge_reset(DeviceState *qdev);
-
-int pci_bridge_initfn(PCIDevice *pci_dev, const char *typename);
-void pci_bridge_exitfn(PCIDevice *pci_dev);
-
-
-/*
- * before qdev initialization(qdev_init()), this function sets bus_name and
- * map_irq callback which are necessry for pci_bridge_initfn() to
- * initialize bus.
- */
-void pci_bridge_map_irq(PCIBridge *br, const char* bus_name,
-                        pci_map_irq_fn map_irq);
-
-/* TODO: add this define to pci_regs.h in linux and then in qemu. */
-#define  PCI_BRIDGE_CTL_VGA_16BIT      0x10    /* VGA 16-bit decode */
-#define  PCI_BRIDGE_CTL_DISCARD                0x100   /* Primary discard timer */
-#define  PCI_BRIDGE_CTL_SEC_DISCARD    0x200   /* Secondary discard timer */
-#define  PCI_BRIDGE_CTL_DISCARD_STATUS 0x400   /* Discard timer status */
-#define  PCI_BRIDGE_CTL_DISCARD_SERR   0x800   /* Discard timer SERR# enable */
-
-#endif  /* QEMU_PCI_BRIDGE_H */
diff --git a/hw/pci/pci_bus.h b/hw/pci/pci_bus.h
deleted file mode 100644 (file)
index 6ee443c..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-#ifndef QEMU_PCI_BUS_H
-#define QEMU_PCI_BUS_H
-
-/*
- * PCI Bus and Bridge datastructures.
- *
- * Do not access the following members directly;
- * use accessor functions in pci.h, pci_bridge.h
- */
-
-struct PCIBus {
-    BusState qbus;
-    PCIDMAContextFunc dma_context_fn;
-    void *dma_context_opaque;
-    uint8_t devfn_min;
-    pci_set_irq_fn set_irq;
-    pci_map_irq_fn map_irq;
-    pci_route_irq_fn route_intx_to_irq;
-    pci_hotplug_fn hotplug;
-    DeviceState *hotplug_qdev;
-    void *irq_opaque;
-    PCIDevice *devices[PCI_SLOT_MAX * PCI_FUNC_MAX];
-    PCIDevice *parent_dev;
-    MemoryRegion *address_space_mem;
-    MemoryRegion *address_space_io;
-
-    QLIST_HEAD(, PCIBus) child; /* this will be replaced by qdev later */
-    QLIST_ENTRY(PCIBus) sibling;/* this will be replaced by qdev later */
-
-    /* The bus IRQ state is the logical OR of the connected devices.
-       Keep a count of the number of devices with raised IRQs.  */
-    int nirq;
-    int *irq_count;
-};
-
-typedef struct PCIBridgeWindows PCIBridgeWindows;
-
-/*
- * Aliases for each of the address space windows that the bridge
- * can forward. Mapped into the bridge's parent's address space,
- * as subregions.
- */
-struct PCIBridgeWindows {
-    MemoryRegion alias_pref_mem;
-    MemoryRegion alias_mem;
-    MemoryRegion alias_io;
-    /*
-     * When bridge control VGA forwarding is enabled, bridges will
-     * provide positive decode on the PCI VGA defined I/O port and
-     * MMIO ranges.  When enabled forwarding is only qualified on the
-     * I/O and memory enable bits in the bridge command register.
-     */
-    MemoryRegion alias_vga[QEMU_PCI_VGA_NUM_REGIONS];
-};
-
-struct PCIBridge {
-    PCIDevice dev;
-
-    /* private member */
-    PCIBus sec_bus;
-    /*
-     * Memory regions for the bridge's address spaces.  These regions are not
-     * directly added to system_memory/system_io or its descendants.
-     * Bridge's secondary bus points to these, so that devices
-     * under the bridge see these regions as its address spaces.
-     * The regions are as large as the entire address space -
-     * they don't take into account any windows.
-     */
-    MemoryRegion address_space_mem;
-    MemoryRegion address_space_io;
-
-    PCIBridgeWindows *windows;
-
-    pci_map_irq_fn map_irq;
-    const char *bus_name;
-};
-
-#endif /* QEMU_PCI_BUS_H */
diff --git a/hw/pci/pci_host.h b/hw/pci/pci_host.h
deleted file mode 100644 (file)
index 236cd0f..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * QEMU Common PCI Host bridge configuration data space access routines.
- *
- * Copyright (c) 2006 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.
- */
-
-/* Worker routines for a PCI host controller that uses an {address,data}
-   register pair to access PCI configuration space.  */
-
-#ifndef PCI_HOST_H
-#define PCI_HOST_H
-
-#include "hw/sysbus.h"
-
-#define TYPE_PCI_HOST_BRIDGE "pci-host-bridge"
-#define PCI_HOST_BRIDGE(obj) \
-    OBJECT_CHECK(PCIHostState, (obj), TYPE_PCI_HOST_BRIDGE)
-
-struct PCIHostState {
-    SysBusDevice busdev;
-
-    MemoryRegion conf_mem;
-    MemoryRegion data_mem;
-    MemoryRegion mmcfg;
-    uint32_t config_reg;
-    PCIBus *bus;
-};
-
-/* common internal helpers for PCI/PCIe hosts, cut off overflows */
-void pci_host_config_write_common(PCIDevice *pci_dev, uint32_t addr,
-                                  uint32_t limit, uint32_t val, uint32_t len);
-uint32_t pci_host_config_read_common(PCIDevice *pci_dev, uint32_t addr,
-                                     uint32_t limit, uint32_t len);
-
-void pci_data_write(PCIBus *s, uint32_t addr, uint32_t val, int len);
-uint32_t pci_data_read(PCIBus *s, uint32_t addr, int len);
-
-extern const MemoryRegionOps pci_host_conf_le_ops;
-extern const MemoryRegionOps pci_host_conf_be_ops;
-extern const MemoryRegionOps pci_host_data_le_ops;
-extern const MemoryRegionOps pci_host_data_be_ops;
-
-#endif /* PCI_HOST_H */
diff --git a/hw/pci/pci_ids.h b/hw/pci/pci_ids.h
deleted file mode 100644 (file)
index d8dc2f1..0000000
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- *      PCI Class, Vendor and Device IDs
- *
- *      Please keep sorted.
- *
- *      Abbreviated version of linux/pci_ids.h
- *
- *      QEMU-specific definitions belong in pci.h
- */
-#ifndef HW_PCI_IDS_H
-#define HW_PCI_IDS_H 1
-
-/* Device classes and subclasses */
-
-#define PCI_BASE_CLASS_STORAGE           0x01
-#define PCI_BASE_CLASS_NETWORK           0x02
-
-#define PCI_CLASS_STORAGE_SCSI           0x0100
-#define PCI_CLASS_STORAGE_IDE            0x0101
-#define PCI_CLASS_STORAGE_RAID           0x0104
-#define PCI_CLASS_STORAGE_SATA           0x0106
-#define PCI_CLASS_STORAGE_OTHER          0x0180
-
-#define PCI_CLASS_NETWORK_ETHERNET       0x0200
-
-#define PCI_CLASS_DISPLAY_VGA            0x0300
-#define PCI_CLASS_DISPLAY_OTHER          0x0380
-
-#define PCI_CLASS_MULTIMEDIA_AUDIO       0x0401
-
-#define PCI_CLASS_MEMORY_RAM             0x0500
-
-#define PCI_CLASS_SYSTEM_OTHER           0x0880
-
-#define PCI_CLASS_SERIAL_USB             0x0c03
-#define PCI_CLASS_SERIAL_SMBUS           0x0c05
-
-#define PCI_CLASS_BRIDGE_HOST            0x0600
-#define PCI_CLASS_BRIDGE_ISA             0x0601
-#define PCI_CLASS_BRIDGE_PCI             0x0604
-#define PCI_CLASS_BRDIGE_PCI_INF_SUB     0x01
-#define PCI_CLASS_BRIDGE_OTHER           0x0680
-
-#define PCI_CLASS_COMMUNICATION_SERIAL   0x0700
-#define PCI_CLASS_COMMUNICATION_OTHER    0x0780
-
-#define PCI_CLASS_PROCESSOR_CO           0x0b40
-#define PCI_CLASS_PROCESSOR_POWERPC      0x0b20
-
-#define PCI_CLASS_OTHERS                 0xff
-
-/* Vendors and devices.  Sort key: vendor first, device next. */
-
-#define PCI_VENDOR_ID_LSI_LOGIC          0x1000
-#define PCI_DEVICE_ID_LSI_53C895A        0x0012
-#define PCI_DEVICE_ID_LSI_SAS1078        0x0060
-
-#define PCI_VENDOR_ID_DEC                0x1011
-#define PCI_DEVICE_ID_DEC_21154          0x0026
-
-#define PCI_VENDOR_ID_CIRRUS             0x1013
-
-#define PCI_VENDOR_ID_IBM                0x1014
-
-#define PCI_VENDOR_ID_AMD                0x1022
-#define PCI_DEVICE_ID_AMD_LANCE          0x2000
-#define PCI_DEVICE_ID_AMD_SCSI           0x2020
-
-#define PCI_VENDOR_ID_TI                 0x104c
-
-#define PCI_VENDOR_ID_MOTOROLA           0x1057
-#define PCI_DEVICE_ID_MOTOROLA_MPC106    0x0002
-#define PCI_DEVICE_ID_MOTOROLA_RAVEN     0x4801
-
-#define PCI_VENDOR_ID_APPLE              0x106b
-#define PCI_DEVICE_ID_APPLE_UNI_N_AGP    0x0020
-#define PCI_DEVICE_ID_APPLE_U3_AGP       0x004b
-
-#define PCI_VENDOR_ID_SUN                0x108e
-#define PCI_DEVICE_ID_SUN_EBUS           0x1000
-#define PCI_DEVICE_ID_SUN_SIMBA          0x5000
-#define PCI_DEVICE_ID_SUN_SABRE          0xa000
-
-#define PCI_VENDOR_ID_CMD                0x1095
-#define PCI_DEVICE_ID_CMD_646            0x0646
-
-#define PCI_VENDOR_ID_REALTEK            0x10ec
-#define PCI_DEVICE_ID_REALTEK_8139       0x8139
-
-#define PCI_VENDOR_ID_XILINX             0x10ee
-
-#define PCI_VENDOR_ID_VIA                0x1106
-#define PCI_DEVICE_ID_VIA_ISA_BRIDGE     0x0686
-#define PCI_DEVICE_ID_VIA_IDE            0x0571
-#define PCI_DEVICE_ID_VIA_UHCI           0x3038
-#define PCI_DEVICE_ID_VIA_ACPI           0x3057
-#define PCI_DEVICE_ID_VIA_AC97           0x3058
-#define PCI_DEVICE_ID_VIA_MC97           0x3068
-
-#define PCI_VENDOR_ID_MARVELL            0x11ab
-
-#define PCI_VENDOR_ID_ENSONIQ            0x1274
-#define PCI_DEVICE_ID_ENSONIQ_ES1370     0x5000
-
-#define PCI_VENDOR_ID_FREESCALE          0x1957
-#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_82801BA_11   0x244e
-#define PCI_DEVICE_ID_INTEL_82801D       0x24CD
-#define PCI_DEVICE_ID_INTEL_ESB_9        0x25ab
-#define PCI_DEVICE_ID_INTEL_82371SB_0    0x7000
-#define PCI_DEVICE_ID_INTEL_82371SB_1    0x7010
-#define PCI_DEVICE_ID_INTEL_82371SB_2    0x7020
-#define PCI_DEVICE_ID_INTEL_82371AB_0    0x7110
-#define PCI_DEVICE_ID_INTEL_82371AB      0x7111
-#define PCI_DEVICE_ID_INTEL_82371AB_2    0x7112
-#define PCI_DEVICE_ID_INTEL_82371AB_3    0x7113
-
-#define PCI_DEVICE_ID_INTEL_ICH9_0       0x2910
-#define PCI_DEVICE_ID_INTEL_ICH9_1       0x2917
-#define PCI_DEVICE_ID_INTEL_ICH9_2       0x2912
-#define PCI_DEVICE_ID_INTEL_ICH9_3       0x2913
-#define PCI_DEVICE_ID_INTEL_ICH9_4       0x2914
-#define PCI_DEVICE_ID_INTEL_ICH9_5       0x2919
-#define PCI_DEVICE_ID_INTEL_ICH9_6       0x2930
-#define PCI_DEVICE_ID_INTEL_ICH9_7       0x2916
-#define PCI_DEVICE_ID_INTEL_ICH9_8       0x2918
-
-#define PCI_DEVICE_ID_INTEL_82801I_UHCI1 0x2934
-#define PCI_DEVICE_ID_INTEL_82801I_UHCI2 0x2935
-#define PCI_DEVICE_ID_INTEL_82801I_UHCI3 0x2936
-#define PCI_DEVICE_ID_INTEL_82801I_UHCI4 0x2937
-#define PCI_DEVICE_ID_INTEL_82801I_UHCI5 0x2938
-#define PCI_DEVICE_ID_INTEL_82801I_UHCI6 0x2939
-#define PCI_DEVICE_ID_INTEL_82801I_EHCI1 0x293a
-#define PCI_DEVICE_ID_INTEL_82801I_EHCI2 0x293c
-#define PCI_DEVICE_ID_INTEL_82599_SFP_VF 0x10ed
-
-#define PCI_DEVICE_ID_INTEL_Q35_MCH      0x29c0
-
-#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
-
-#define PCI_VENDOR_ID_TEWS               0x1498
-#define PCI_DEVICE_ID_TEWS_TPCI200       0x30C8
-
-#endif
diff --git a/hw/pci/pci_regs.h b/hw/pci/pci_regs.h
deleted file mode 100644 (file)
index 56a404b..0000000
+++ /dev/null
@@ -1,717 +0,0 @@
-/*
- *     pci_regs.h
- *
- *     PCI standard defines
- *     Copyright 1994, Drew Eckhardt
- *     Copyright 1997--1999 Martin Mares <mj@ucw.cz>
- *
- *     For more information, please consult the following manuals (look at
- *     http://www.pcisig.com/ for how to get them):
- *
- *     PCI BIOS Specification
- *     PCI Local Bus Specification
- *     PCI to PCI Bridge Specification
- *     PCI System Design Guide
- *
- *     For hypertransport information, please consult the following manuals
- *     from http://www.hypertransport.org
- *
- *     The Hypertransport I/O Link Specification
- */
-
-#ifndef LINUX_PCI_REGS_H
-#define LINUX_PCI_REGS_H
-
-/*
- * Under PCI, each device has 256 bytes of configuration address space,
- * of which the first 64 bytes are standardized as follows:
- */
-#define PCI_VENDOR_ID          0x00    /* 16 bits */
-#define PCI_DEVICE_ID          0x02    /* 16 bits */
-#define PCI_COMMAND            0x04    /* 16 bits */
-#define  PCI_COMMAND_IO                0x1     /* Enable response in I/O space */
-#define  PCI_COMMAND_MEMORY    0x2     /* Enable response in Memory space */
-#define  PCI_COMMAND_MASTER    0x4     /* Enable bus mastering */
-#define  PCI_COMMAND_SPECIAL   0x8     /* Enable response to special cycles */
-#define  PCI_COMMAND_INVALIDATE        0x10    /* Use memory write and invalidate */
-#define  PCI_COMMAND_VGA_PALETTE 0x20  /* Enable palette snooping */
-#define  PCI_COMMAND_PARITY    0x40    /* Enable parity checking */
-#define  PCI_COMMAND_WAIT      0x80    /* Enable address/data stepping */
-#define  PCI_COMMAND_SERR      0x100   /* Enable SERR */
-#define  PCI_COMMAND_FAST_BACK 0x200   /* Enable back-to-back writes */
-#define  PCI_COMMAND_INTX_DISABLE 0x400 /* INTx Emulation Disable */
-
-#define PCI_STATUS             0x06    /* 16 bits */
-#define  PCI_STATUS_INTERRUPT  0x08    /* Interrupt status */
-#define  PCI_STATUS_CAP_LIST   0x10    /* Support Capability List */
-#define  PCI_STATUS_66MHZ      0x20    /* Support 66 Mhz PCI 2.1 bus */
-#define  PCI_STATUS_UDF                0x40    /* Support User Definable Features [obsolete] */
-#define  PCI_STATUS_FAST_BACK  0x80    /* Accept fast-back to back */
-#define  PCI_STATUS_PARITY     0x100   /* Detected parity error */
-#define  PCI_STATUS_DEVSEL_MASK        0x600   /* DEVSEL timing */
-#define  PCI_STATUS_DEVSEL_FAST                0x000
-#define  PCI_STATUS_DEVSEL_MEDIUM      0x200
-#define  PCI_STATUS_DEVSEL_SLOW                0x400
-#define  PCI_STATUS_SIG_TARGET_ABORT   0x800 /* Set on target abort */
-#define  PCI_STATUS_REC_TARGET_ABORT   0x1000 /* Master ack of " */
-#define  PCI_STATUS_REC_MASTER_ABORT   0x2000 /* Set on master abort */
-#define  PCI_STATUS_SIG_SYSTEM_ERROR   0x4000 /* Set when we drive SERR */
-#define  PCI_STATUS_DETECTED_PARITY    0x8000 /* Set on parity error */
-
-#define PCI_CLASS_REVISION     0x08    /* High 24 bits are class, low 8 revision */
-#define PCI_REVISION_ID                0x08    /* Revision ID */
-#define PCI_CLASS_PROG         0x09    /* Reg. Level Programming Interface */
-#define PCI_CLASS_DEVICE       0x0a    /* Device class */
-
-#define PCI_CACHE_LINE_SIZE    0x0c    /* 8 bits */
-#define PCI_LATENCY_TIMER      0x0d    /* 8 bits */
-#define PCI_HEADER_TYPE                0x0e    /* 8 bits */
-#define  PCI_HEADER_TYPE_NORMAL                0
-#define  PCI_HEADER_TYPE_BRIDGE                1
-#define  PCI_HEADER_TYPE_CARDBUS       2
-
-#define PCI_BIST               0x0f    /* 8 bits */
-#define  PCI_BIST_CODE_MASK    0x0f    /* Return result */
-#define  PCI_BIST_START                0x40    /* 1 to start BIST, 2 secs or less */
-#define  PCI_BIST_CAPABLE      0x80    /* 1 if BIST capable */
-
-/*
- * Base addresses specify locations in memory or I/O space.
- * Decoded size can be determined by writing a value of
- * 0xffffffff to the register, and reading it back.  Only
- * 1 bits are decoded.
- */
-#define PCI_BASE_ADDRESS_0     0x10    /* 32 bits */
-#define PCI_BASE_ADDRESS_1     0x14    /* 32 bits [htype 0,1 only] */
-#define PCI_BASE_ADDRESS_2     0x18    /* 32 bits [htype 0 only] */
-#define PCI_BASE_ADDRESS_3     0x1c    /* 32 bits */
-#define PCI_BASE_ADDRESS_4     0x20    /* 32 bits */
-#define PCI_BASE_ADDRESS_5     0x24    /* 32 bits */
-#define  PCI_BASE_ADDRESS_SPACE                0x01    /* 0 = memory, 1 = I/O */
-#define  PCI_BASE_ADDRESS_SPACE_IO     0x01
-#define  PCI_BASE_ADDRESS_SPACE_MEMORY 0x00
-#define  PCI_BASE_ADDRESS_MEM_TYPE_MASK        0x06
-#define  PCI_BASE_ADDRESS_MEM_TYPE_32  0x00    /* 32 bit address */
-#define  PCI_BASE_ADDRESS_MEM_TYPE_1M  0x02    /* Below 1M [obsolete] */
-#define  PCI_BASE_ADDRESS_MEM_TYPE_64  0x04    /* 64 bit address */
-#define  PCI_BASE_ADDRESS_MEM_PREFETCH 0x08    /* prefetchable? */
-#define  PCI_BASE_ADDRESS_MEM_MASK     (~0x0fUL)
-#define  PCI_BASE_ADDRESS_IO_MASK      (~0x03UL)
-/* bit 1 is reserved if address_space = 1 */
-
-/* Header type 0 (normal devices) */
-#define PCI_CARDBUS_CIS                0x28
-#define PCI_SUBSYSTEM_VENDOR_ID        0x2c
-#define PCI_SUBSYSTEM_ID       0x2e
-#define PCI_ROM_ADDRESS                0x30    /* Bits 31..11 are address, 10..1 reserved */
-#define  PCI_ROM_ADDRESS_ENABLE        0x01
-#define PCI_ROM_ADDRESS_MASK   (~0x7ffUL)
-
-#define PCI_CAPABILITY_LIST    0x34    /* Offset of first capability list entry */
-
-/* 0x35-0x3b are reserved */
-#define PCI_INTERRUPT_LINE     0x3c    /* 8 bits */
-#define PCI_INTERRUPT_PIN      0x3d    /* 8 bits */
-#define PCI_MIN_GNT            0x3e    /* 8 bits */
-#define PCI_MAX_LAT            0x3f    /* 8 bits */
-
-/* Header type 1 (PCI-to-PCI bridges) */
-#define PCI_PRIMARY_BUS                0x18    /* Primary bus number */
-#define PCI_SECONDARY_BUS      0x19    /* Secondary bus number */
-#define PCI_SUBORDINATE_BUS    0x1a    /* Highest bus number behind the bridge */
-#define PCI_SEC_LATENCY_TIMER  0x1b    /* Latency timer for secondary interface */
-#define PCI_IO_BASE            0x1c    /* I/O range behind the bridge */
-#define PCI_IO_LIMIT           0x1d
-#define  PCI_IO_RANGE_TYPE_MASK        0x0fUL  /* I/O bridging type */
-#define  PCI_IO_RANGE_TYPE_16  0x00
-#define  PCI_IO_RANGE_TYPE_32  0x01
-#define  PCI_IO_RANGE_MASK     (~0x0fUL)
-#define PCI_SEC_STATUS         0x1e    /* Secondary status register, only bit 14 used */
-#define PCI_MEMORY_BASE                0x20    /* Memory range behind */
-#define PCI_MEMORY_LIMIT       0x22
-#define  PCI_MEMORY_RANGE_TYPE_MASK 0x0fUL
-#define  PCI_MEMORY_RANGE_MASK (~0x0fUL)
-#define PCI_PREF_MEMORY_BASE   0x24    /* Prefetchable memory range behind */
-#define PCI_PREF_MEMORY_LIMIT  0x26
-#define  PCI_PREF_RANGE_TYPE_MASK 0x0fUL
-#define  PCI_PREF_RANGE_TYPE_32        0x00
-#define  PCI_PREF_RANGE_TYPE_64        0x01
-#define  PCI_PREF_RANGE_MASK   (~0x0fUL)
-#define PCI_PREF_BASE_UPPER32  0x28    /* Upper half of prefetchable memory range */
-#define PCI_PREF_LIMIT_UPPER32 0x2c
-#define PCI_IO_BASE_UPPER16    0x30    /* Upper half of I/O addresses */
-#define PCI_IO_LIMIT_UPPER16   0x32
-/* 0x34 same as for htype 0 */
-/* 0x35-0x3b is reserved */
-#define PCI_ROM_ADDRESS1       0x38    /* Same as PCI_ROM_ADDRESS, but for htype 1 */
-/* 0x3c-0x3d are same as for htype 0 */
-#define PCI_BRIDGE_CONTROL     0x3e
-#define  PCI_BRIDGE_CTL_PARITY 0x01    /* Enable parity detection on secondary interface */
-#define  PCI_BRIDGE_CTL_SERR   0x02    /* The same for SERR forwarding */
-#define  PCI_BRIDGE_CTL_ISA    0x04    /* Enable ISA mode */
-#define  PCI_BRIDGE_CTL_VGA    0x08    /* Forward VGA addresses */
-#define  PCI_BRIDGE_CTL_MASTER_ABORT   0x20  /* Report master aborts */
-#define  PCI_BRIDGE_CTL_BUS_RESET      0x40    /* Secondary bus reset */
-#define  PCI_BRIDGE_CTL_FAST_BACK      0x80    /* Fast Back2Back enabled on secondary interface */
-
-/* Header type 2 (CardBus bridges) */
-#define PCI_CB_CAPABILITY_LIST 0x14
-/* 0x15 reserved */
-#define PCI_CB_SEC_STATUS      0x16    /* Secondary status */
-#define PCI_CB_PRIMARY_BUS     0x18    /* PCI bus number */
-#define PCI_CB_CARD_BUS                0x19    /* CardBus bus number */
-#define PCI_CB_SUBORDINATE_BUS 0x1a    /* Subordinate bus number */
-#define PCI_CB_LATENCY_TIMER   0x1b    /* CardBus latency timer */
-#define PCI_CB_MEMORY_BASE_0   0x1c
-#define PCI_CB_MEMORY_LIMIT_0  0x20
-#define PCI_CB_MEMORY_BASE_1   0x24
-#define PCI_CB_MEMORY_LIMIT_1  0x28
-#define PCI_CB_IO_BASE_0       0x2c
-#define PCI_CB_IO_BASE_0_HI    0x2e
-#define PCI_CB_IO_LIMIT_0      0x30
-#define PCI_CB_IO_LIMIT_0_HI   0x32
-#define PCI_CB_IO_BASE_1       0x34
-#define PCI_CB_IO_BASE_1_HI    0x36
-#define PCI_CB_IO_LIMIT_1      0x38
-#define PCI_CB_IO_LIMIT_1_HI   0x3a
-#define  PCI_CB_IO_RANGE_MASK  (~0x03UL)
-/* 0x3c-0x3d are same as for htype 0 */
-#define PCI_CB_BRIDGE_CONTROL  0x3e
-#define  PCI_CB_BRIDGE_CTL_PARITY      0x01    /* Similar to standard bridge control register */
-#define  PCI_CB_BRIDGE_CTL_SERR                0x02
-#define  PCI_CB_BRIDGE_CTL_ISA         0x04
-#define  PCI_CB_BRIDGE_CTL_VGA         0x08
-#define  PCI_CB_BRIDGE_CTL_MASTER_ABORT        0x20
-#define  PCI_CB_BRIDGE_CTL_CB_RESET    0x40    /* CardBus reset */
-#define  PCI_CB_BRIDGE_CTL_16BIT_INT   0x80    /* Enable interrupt for 16-bit cards */
-#define  PCI_CB_BRIDGE_CTL_PREFETCH_MEM0 0x100 /* Prefetch enable for both memory regions */
-#define  PCI_CB_BRIDGE_CTL_PREFETCH_MEM1 0x200
-#define  PCI_CB_BRIDGE_CTL_POST_WRITES 0x400
-#define PCI_CB_SUBSYSTEM_VENDOR_ID     0x40
-#define PCI_CB_SUBSYSTEM_ID            0x42
-#define PCI_CB_LEGACY_MODE_BASE                0x44    /* 16-bit PC Card legacy mode base address (ExCa) */
-/* 0x48-0x7f reserved */
-
-/* Capability lists */
-
-#define PCI_CAP_LIST_ID                0       /* Capability ID */
-#define  PCI_CAP_ID_PM         0x01    /* Power Management */
-#define  PCI_CAP_ID_AGP                0x02    /* Accelerated Graphics Port */
-#define  PCI_CAP_ID_VPD                0x03    /* Vital Product Data */
-#define  PCI_CAP_ID_SLOTID     0x04    /* Slot Identification */
-#define  PCI_CAP_ID_MSI                0x05    /* Message Signalled Interrupts */
-#define  PCI_CAP_ID_CHSWP      0x06    /* CompactPCI HotSwap */
-#define  PCI_CAP_ID_PCIX       0x07    /* PCI-X */
-#define  PCI_CAP_ID_HT         0x08    /* HyperTransport */
-#define  PCI_CAP_ID_VNDR       0x09    /* Vendor specific */
-#define  PCI_CAP_ID_DBG                0x0A    /* Debug port */
-#define  PCI_CAP_ID_CCRC       0x0B    /* CompactPCI Central Resource Control */
-#define  PCI_CAP_ID_SHPC       0x0C    /* PCI Standard Hot-Plug Controller */
-#define  PCI_CAP_ID_SSVID      0x0D    /* Bridge subsystem vendor/device ID */
-#define  PCI_CAP_ID_AGP3       0x0E    /* AGP Target PCI-PCI bridge */
-#define  PCI_CAP_ID_EXP        0x10    /* PCI Express */
-#define  PCI_CAP_ID_MSIX       0x11    /* MSI-X */
-#define  PCI_CAP_ID_SATA       0x12    /* Serial ATA */
-#define  PCI_CAP_ID_AF         0x13    /* PCI Advanced Features */
-#define PCI_CAP_LIST_NEXT      1       /* Next capability in the list */
-#define PCI_CAP_FLAGS          2       /* Capability defined flags (16 bits) */
-#define PCI_CAP_SIZEOF         4
-
-/* Power Management Registers */
-
-#define PCI_PM_PMC             2       /* PM Capabilities Register */
-#define  PCI_PM_CAP_VER_MASK   0x0007  /* Version */
-#define  PCI_PM_CAP_PME_CLOCK  0x0008  /* PME clock required */
-#define  PCI_PM_CAP_RESERVED    0x0010  /* Reserved field */
-#define  PCI_PM_CAP_DSI                0x0020  /* Device specific initialization */
-#define  PCI_PM_CAP_AUX_POWER  0x01C0  /* Auxiliary power support mask */
-#define  PCI_PM_CAP_D1         0x0200  /* D1 power state support */
-#define  PCI_PM_CAP_D2         0x0400  /* D2 power state support */
-#define  PCI_PM_CAP_PME                0x0800  /* PME pin supported */
-#define  PCI_PM_CAP_PME_MASK   0xF800  /* PME Mask of all supported states */
-#define  PCI_PM_CAP_PME_D0     0x0800  /* PME# from D0 */
-#define  PCI_PM_CAP_PME_D1     0x1000  /* PME# from D1 */
-#define  PCI_PM_CAP_PME_D2     0x2000  /* PME# from D2 */
-#define  PCI_PM_CAP_PME_D3     0x4000  /* PME# from D3 (hot) */
-#define  PCI_PM_CAP_PME_D3cold 0x8000  /* PME# from D3 (cold) */
-#define  PCI_PM_CAP_PME_SHIFT  11      /* Start of the PME Mask in PMC */
-#define PCI_PM_CTRL            4       /* PM control and status register */
-#define  PCI_PM_CTRL_STATE_MASK        0x0003  /* Current power state (D0 to D3) */
-#define  PCI_PM_CTRL_NO_SOFT_RESET     0x0008  /* No reset for D3hot->D0 */
-#define  PCI_PM_CTRL_PME_ENABLE        0x0100  /* PME pin enable */
-#define  PCI_PM_CTRL_DATA_SEL_MASK     0x1e00  /* Data select (??) */
-#define  PCI_PM_CTRL_DATA_SCALE_MASK   0x6000  /* Data scale (??) */
-#define  PCI_PM_CTRL_PME_STATUS        0x8000  /* PME pin status */
-#define PCI_PM_PPB_EXTENSIONS  6       /* PPB support extensions (??) */
-#define  PCI_PM_PPB_B2_B3      0x40    /* Stop clock when in D3hot (??) */
-#define  PCI_PM_BPCC_ENABLE    0x80    /* Bus power/clock control enable (??) */
-#define PCI_PM_DATA_REGISTER   7       /* (??) */
-#define PCI_PM_SIZEOF          8
-
-/* AGP registers */
-
-#define PCI_AGP_VERSION                2       /* BCD version number */
-#define PCI_AGP_RFU            3       /* Rest of capability flags */
-#define PCI_AGP_STATUS         4       /* Status register */
-#define  PCI_AGP_STATUS_RQ_MASK        0xff000000      /* Maximum number of requests - 1 */
-#define  PCI_AGP_STATUS_SBA    0x0200  /* Sideband addressing supported */
-#define  PCI_AGP_STATUS_64BIT  0x0020  /* 64-bit addressing supported */
-#define  PCI_AGP_STATUS_FW     0x0010  /* FW transfers supported */
-#define  PCI_AGP_STATUS_RATE4  0x0004  /* 4x transfer rate supported */
-#define  PCI_AGP_STATUS_RATE2  0x0002  /* 2x transfer rate supported */
-#define  PCI_AGP_STATUS_RATE1  0x0001  /* 1x transfer rate supported */
-#define PCI_AGP_COMMAND                8       /* Control register */
-#define  PCI_AGP_COMMAND_RQ_MASK 0xff000000  /* Master: Maximum number of requests */
-#define  PCI_AGP_COMMAND_SBA   0x0200  /* Sideband addressing enabled */
-#define  PCI_AGP_COMMAND_AGP   0x0100  /* Allow processing of AGP transactions */
-#define  PCI_AGP_COMMAND_64BIT 0x0020  /* Allow processing of 64-bit addresses */
-#define  PCI_AGP_COMMAND_FW    0x0010  /* Force FW transfers */
-#define  PCI_AGP_COMMAND_RATE4 0x0004  /* Use 4x rate */
-#define  PCI_AGP_COMMAND_RATE2 0x0002  /* Use 2x rate */
-#define  PCI_AGP_COMMAND_RATE1 0x0001  /* Use 1x rate */
-#define PCI_AGP_SIZEOF         12
-
-/* Vital Product Data */
-
-#define PCI_VPD_ADDR           2       /* Address to access (15 bits!) */
-#define  PCI_VPD_ADDR_MASK     0x7fff  /* Address mask */
-#define  PCI_VPD_ADDR_F                0x8000  /* Write 0, 1 indicates completion */
-#define PCI_VPD_DATA           4       /* 32-bits of data returned here */
-
-/* Slot Identification */
-
-#define PCI_SID_ESR            2       /* Expansion Slot Register */
-#define  PCI_SID_ESR_NSLOTS    0x1f    /* Number of expansion slots available */
-#define  PCI_SID_ESR_FIC       0x20    /* First In Chassis Flag */
-#define PCI_SID_CHASSIS_NR     3       /* Chassis Number */
-
-/* Message Signalled Interrupts registers */
-
-#define PCI_MSI_FLAGS          2       /* Various flags */
-#define  PCI_MSI_FLAGS_64BIT   0x80    /* 64-bit addresses allowed */
-#define  PCI_MSI_FLAGS_QSIZE   0x70    /* Message queue size configured */
-#define  PCI_MSI_FLAGS_QMASK   0x0e    /* Maximum queue size available */
-#define  PCI_MSI_FLAGS_ENABLE  0x01    /* MSI feature enabled */
-#define  PCI_MSI_FLAGS_MASKBIT 0x100   /* 64-bit mask bits allowed */
-#define PCI_MSI_RFU            3       /* Rest of capability flags */
-#define PCI_MSI_ADDRESS_LO     4       /* Lower 32 bits */
-#define PCI_MSI_ADDRESS_HI     8       /* Upper 32 bits (if PCI_MSI_FLAGS_64BIT set) */
-#define PCI_MSI_DATA_32                8       /* 16 bits of data for 32-bit devices */
-#define PCI_MSI_MASK_32                12      /* Mask bits register for 32-bit devices */
-#define PCI_MSI_DATA_64                12      /* 16 bits of data for 64-bit devices */
-#define PCI_MSI_MASK_64                16      /* Mask bits register for 64-bit devices */
-
-/* MSI-X registers */
-#define PCI_MSIX_FLAGS         2
-#define  PCI_MSIX_FLAGS_QSIZE  0x7FF
-#define  PCI_MSIX_FLAGS_ENABLE (1 << 15)
-#define  PCI_MSIX_FLAGS_MASKALL        (1 << 14)
-#define PCI_MSIX_TABLE         4
-#define PCI_MSIX_PBA           8
-#define  PCI_MSIX_FLAGS_BIRMASK        (7 << 0)
-
-/* MSI-X entry's format */
-#define PCI_MSIX_ENTRY_SIZE            16
-#define  PCI_MSIX_ENTRY_LOWER_ADDR     0
-#define  PCI_MSIX_ENTRY_UPPER_ADDR     4
-#define  PCI_MSIX_ENTRY_DATA           8
-#define  PCI_MSIX_ENTRY_VECTOR_CTRL    12
-#define   PCI_MSIX_ENTRY_CTRL_MASKBIT  1
-
-/* CompactPCI Hotswap Register */
-
-#define PCI_CHSWP_CSR          2       /* Control and Status Register */
-#define  PCI_CHSWP_DHA         0x01    /* Device Hiding Arm */
-#define  PCI_CHSWP_EIM         0x02    /* ENUM# Signal Mask */
-#define  PCI_CHSWP_PIE         0x04    /* Pending Insert or Extract */
-#define  PCI_CHSWP_LOO         0x08    /* LED On / Off */
-#define  PCI_CHSWP_PI          0x30    /* Programming Interface */
-#define  PCI_CHSWP_EXT         0x40    /* ENUM# status - extraction */
-#define  PCI_CHSWP_INS         0x80    /* ENUM# status - insertion */
-
-/* PCI Advanced Feature registers */
-
-#define PCI_AF_LENGTH          2
-#define PCI_AF_CAP             3
-#define  PCI_AF_CAP_TP         0x01
-#define  PCI_AF_CAP_FLR                0x02
-#define PCI_AF_CTRL            4
-#define  PCI_AF_CTRL_FLR       0x01
-#define PCI_AF_STATUS          5
-#define  PCI_AF_STATUS_TP      0x01
-
-/* PCI-X registers */
-
-#define PCI_X_CMD              2       /* Modes & Features */
-#define  PCI_X_CMD_DPERR_E     0x0001  /* Data Parity Error Recovery Enable */
-#define  PCI_X_CMD_ERO         0x0002  /* Enable Relaxed Ordering */
-#define  PCI_X_CMD_READ_512    0x0000  /* 512 byte maximum read byte count */
-#define  PCI_X_CMD_READ_1K     0x0004  /* 1Kbyte maximum read byte count */
-#define  PCI_X_CMD_READ_2K     0x0008  /* 2Kbyte maximum read byte count */
-#define  PCI_X_CMD_READ_4K     0x000c  /* 4Kbyte maximum read byte count */
-#define  PCI_X_CMD_MAX_READ    0x000c  /* Max Memory Read Byte Count */
-                               /* Max # of outstanding split transactions */
-#define  PCI_X_CMD_SPLIT_1     0x0000  /* Max 1 */
-#define  PCI_X_CMD_SPLIT_2     0x0010  /* Max 2 */
-#define  PCI_X_CMD_SPLIT_3     0x0020  /* Max 3 */
-#define  PCI_X_CMD_SPLIT_4     0x0030  /* Max 4 */
-#define  PCI_X_CMD_SPLIT_8     0x0040  /* Max 8 */
-#define  PCI_X_CMD_SPLIT_12    0x0050  /* Max 12 */
-#define  PCI_X_CMD_SPLIT_16    0x0060  /* Max 16 */
-#define  PCI_X_CMD_SPLIT_32    0x0070  /* Max 32 */
-#define  PCI_X_CMD_MAX_SPLIT   0x0070  /* Max Outstanding Split Transactions */
-#define  PCI_X_CMD_VERSION(x)  (((x) >> 12) & 3) /* Version */
-#define PCI_X_STATUS           4       /* PCI-X capabilities */
-#define  PCI_X_STATUS_DEVFN    0x000000ff      /* A copy of devfn */
-#define  PCI_X_STATUS_BUS      0x0000ff00      /* A copy of bus nr */
-#define  PCI_X_STATUS_64BIT    0x00010000      /* 64-bit device */
-#define  PCI_X_STATUS_133MHZ   0x00020000      /* 133 MHz capable */
-#define  PCI_X_STATUS_SPL_DISC 0x00040000      /* Split Completion Discarded */
-#define  PCI_X_STATUS_UNX_SPL  0x00080000      /* Unexpected Split Completion */
-#define  PCI_X_STATUS_COMPLEX  0x00100000      /* Device Complexity */
-#define  PCI_X_STATUS_MAX_READ 0x00600000      /* Designed Max Memory Read Count */
-#define  PCI_X_STATUS_MAX_SPLIT        0x03800000      /* Designed Max Outstanding Split Transactions */
-#define  PCI_X_STATUS_MAX_CUM  0x1c000000      /* Designed Max Cumulative Read Size */
-#define  PCI_X_STATUS_SPL_ERR  0x20000000      /* Rcvd Split Completion Error Msg */
-#define  PCI_X_STATUS_266MHZ   0x40000000      /* 266 MHz capable */
-#define  PCI_X_STATUS_533MHZ   0x80000000      /* 533 MHz capable */
-
-/* PCI Bridge Subsystem ID registers */
-
-#define PCI_SSVID_VENDOR_ID     4      /* PCI-Bridge subsystem vendor id register */
-#define PCI_SSVID_DEVICE_ID     6      /* PCI-Bridge subsystem device id register */
-
-/* PCI Express capability registers */
-
-#define PCI_EXP_FLAGS          2       /* Capabilities register */
-#define PCI_EXP_FLAGS_VERS     0x000f  /* Capability version */
-#define PCI_EXP_FLAGS_TYPE     0x00f0  /* Device/Port type */
-#define  PCI_EXP_TYPE_ENDPOINT 0x0     /* Express Endpoint */
-#define  PCI_EXP_TYPE_LEG_END  0x1     /* Legacy Endpoint */
-#define  PCI_EXP_TYPE_ROOT_PORT 0x4    /* Root Port */
-#define  PCI_EXP_TYPE_UPSTREAM 0x5     /* Upstream Port */
-#define  PCI_EXP_TYPE_DOWNSTREAM 0x6   /* Downstream Port */
-#define  PCI_EXP_TYPE_PCI_BRIDGE 0x7   /* PCI/PCI-X Bridge */
-#define  PCI_EXP_TYPE_PCIE_BRIDGE 0x8   /* PCI/PCI-X to PCIE Bridge */
-#define  PCI_EXP_TYPE_RC_END   0x9     /* Root Complex Integrated Endpoint */
-#define  PCI_EXP_TYPE_RC_EC     0xa     /* Root Complex Event Collector */
-#define PCI_EXP_FLAGS_SLOT     0x0100  /* Slot implemented */
-#define PCI_EXP_FLAGS_IRQ      0x3e00  /* Interrupt message number */
-#define PCI_EXP_DEVCAP         4       /* Device capabilities */
-#define  PCI_EXP_DEVCAP_PAYLOAD        0x07    /* Max_Payload_Size */
-#define  PCI_EXP_DEVCAP_PHANTOM        0x18    /* Phantom functions */
-#define  PCI_EXP_DEVCAP_EXT_TAG        0x20    /* Extended tags */
-#define  PCI_EXP_DEVCAP_L0S    0x1c0   /* L0s Acceptable Latency */
-#define  PCI_EXP_DEVCAP_L1     0xe00   /* L1 Acceptable Latency */
-#define  PCI_EXP_DEVCAP_ATN_BUT        0x1000  /* Attention Button Present */
-#define  PCI_EXP_DEVCAP_ATN_IND        0x2000  /* Attention Indicator Present */
-#define  PCI_EXP_DEVCAP_PWR_IND        0x4000  /* Power Indicator Present */
-#define  PCI_EXP_DEVCAP_RBER   0x8000  /* Role-Based Error Reporting */
-#define  PCI_EXP_DEVCAP_PWR_VAL        0x3fc0000 /* Slot Power Limit Value */
-#define  PCI_EXP_DEVCAP_PWR_SCL        0xc000000 /* Slot Power Limit Scale */
-#define  PCI_EXP_DEVCAP_FLR     0x10000000 /* Function Level Reset */
-#define PCI_EXP_DEVCTL         8       /* Device Control */
-#define  PCI_EXP_DEVCTL_CERE   0x0001  /* Correctable Error Reporting En. */
-#define  PCI_EXP_DEVCTL_NFERE  0x0002  /* Non-Fatal Error Reporting Enable */
-#define  PCI_EXP_DEVCTL_FERE   0x0004  /* Fatal Error Reporting Enable */
-#define  PCI_EXP_DEVCTL_URRE   0x0008  /* Unsupported Request Reporting En. */
-#define  PCI_EXP_DEVCTL_RELAX_EN 0x0010 /* Enable relaxed ordering */
-#define  PCI_EXP_DEVCTL_PAYLOAD        0x00e0  /* Max_Payload_Size */
-#define  PCI_EXP_DEVCTL_EXT_TAG        0x0100  /* Extended Tag Field Enable */
-#define  PCI_EXP_DEVCTL_PHANTOM        0x0200  /* Phantom Functions Enable */
-#define  PCI_EXP_DEVCTL_AUX_PME        0x0400  /* Auxiliary Power PM Enable */
-#define  PCI_EXP_DEVCTL_NOSNOOP_EN 0x0800  /* Enable No Snoop */
-#define  PCI_EXP_DEVCTL_READRQ 0x7000  /* Max_Read_Request_Size */
-#define  PCI_EXP_DEVCTL_BCR_FLR 0x8000  /* Bridge Configuration Retry / FLR */
-#define PCI_EXP_DEVSTA         10      /* Device Status */
-#define  PCI_EXP_DEVSTA_CED    0x01    /* Correctable Error Detected */
-#define  PCI_EXP_DEVSTA_NFED   0x02    /* Non-Fatal Error Detected */
-#define  PCI_EXP_DEVSTA_FED    0x04    /* Fatal Error Detected */
-#define  PCI_EXP_DEVSTA_URD    0x08    /* Unsupported Request Detected */
-#define  PCI_EXP_DEVSTA_AUXPD  0x10    /* AUX Power Detected */
-#define  PCI_EXP_DEVSTA_TRPND  0x20    /* Transactions Pending */
-#define PCI_EXP_LNKCAP         12      /* Link Capabilities */
-#define  PCI_EXP_LNKCAP_SLS    0x0000000f /* Supported Link Speeds */
-#define  PCI_EXP_LNKCAP_MLW    0x000003f0 /* Maximum Link Width */
-#define  PCI_EXP_LNKCAP_ASPMS  0x00000c00 /* ASPM Support */
-#define  PCI_EXP_LNKCAP_L0SEL  0x00007000 /* L0s Exit Latency */
-#define  PCI_EXP_LNKCAP_L1EL   0x00038000 /* L1 Exit Latency */
-#define  PCI_EXP_LNKCAP_CLKPM  0x00040000 /* L1 Clock Power Management */
-#define  PCI_EXP_LNKCAP_SDERC  0x00080000 /* Surprise Down Error Reporting Capable */
-#define  PCI_EXP_LNKCAP_DLLLARC        0x00100000 /* Data Link Layer Link Active Reporting Capable */
-#define  PCI_EXP_LNKCAP_LBNC   0x00200000 /* Link Bandwidth Notification Capability */
-#define  PCI_EXP_LNKCAP_PN     0xff000000 /* Port Number */
-#define PCI_EXP_LNKCTL         16      /* Link Control */
-#define  PCI_EXP_LNKCTL_ASPMC  0x0003  /* ASPM Control */
-#define  PCI_EXP_LNKCTL_RCB    0x0008  /* Read Completion Boundary */
-#define  PCI_EXP_LNKCTL_LD     0x0010  /* Link Disable */
-#define  PCI_EXP_LNKCTL_RL     0x0020  /* Retrain Link */
-#define  PCI_EXP_LNKCTL_CCC    0x0040  /* Common Clock Configuration */
-#define  PCI_EXP_LNKCTL_ES     0x0080  /* Extended Synch */
-#define  PCI_EXP_LNKCTL_CLKREQ_EN 0x100        /* Enable clkreq */
-#define  PCI_EXP_LNKCTL_HAWD   0x0200  /* Hardware Autonomous Width Disable */
-#define  PCI_EXP_LNKCTL_LBMIE  0x0400  /* Link Bandwidth Management Interrupt Enable */
-#define  PCI_EXP_LNKCTL_LABIE  0x0800  /* Lnk Autonomous Bandwidth Interrupt Enable */
-#define PCI_EXP_LNKSTA         18      /* Link Status */
-#define  PCI_EXP_LNKSTA_CLS    0x000f  /* Current Link Speed */
-#define  PCI_EXP_LNKSTA_CLS_2_5GB 0x01 /* Current Link Speed 2.5GT/s */
-#define  PCI_EXP_LNKSTA_CLS_5_0GB 0x02 /* Current Link Speed 5.0GT/s */
-#define  PCI_EXP_LNKSTA_NLW    0x03f0  /* Nogotiated Link Width */
-#define  PCI_EXP_LNKSTA_NLW_SHIFT 4    /* start of NLW mask in link status */
-#define  PCI_EXP_LNKSTA_LT     0x0800  /* Link Training */
-#define  PCI_EXP_LNKSTA_SLC    0x1000  /* Slot Clock Configuration */
-#define  PCI_EXP_LNKSTA_DLLLA  0x2000  /* Data Link Layer Link Active */
-#define  PCI_EXP_LNKSTA_LBMS   0x4000  /* Link Bandwidth Management Status */
-#define  PCI_EXP_LNKSTA_LABS   0x8000  /* Link Autonomous Bandwidth Status */
-#define PCI_EXP_SLTCAP         20      /* Slot Capabilities */
-#define  PCI_EXP_SLTCAP_ABP    0x00000001 /* Attention Button Present */
-#define  PCI_EXP_SLTCAP_PCP    0x00000002 /* Power Controller Present */
-#define  PCI_EXP_SLTCAP_MRLSP  0x00000004 /* MRL Sensor Present */
-#define  PCI_EXP_SLTCAP_AIP    0x00000008 /* Attention Indicator Present */
-#define  PCI_EXP_SLTCAP_PIP    0x00000010 /* Power Indicator Present */
-#define  PCI_EXP_SLTCAP_HPS    0x00000020 /* Hot-Plug Surprise */
-#define  PCI_EXP_SLTCAP_HPC    0x00000040 /* Hot-Plug Capable */
-#define  PCI_EXP_SLTCAP_SPLV   0x00007f80 /* Slot Power Limit Value */
-#define  PCI_EXP_SLTCAP_SPLS   0x00018000 /* Slot Power Limit Scale */
-#define  PCI_EXP_SLTCAP_EIP    0x00020000 /* Electromechanical Interlock Present */
-#define  PCI_EXP_SLTCAP_NCCS   0x00040000 /* No Command Completed Support */
-#define  PCI_EXP_SLTCAP_PSN    0xfff80000 /* Physical Slot Number */
-#define PCI_EXP_SLTCTL         24      /* Slot Control */
-#define  PCI_EXP_SLTCTL_ABPE   0x0001  /* Attention Button Pressed Enable */
-#define  PCI_EXP_SLTCTL_PFDE   0x0002  /* Power Fault Detected Enable */
-#define  PCI_EXP_SLTCTL_MRLSCE 0x0004  /* MRL Sensor Changed Enable */
-#define  PCI_EXP_SLTCTL_PDCE   0x0008  /* Presence Detect Changed Enable */
-#define  PCI_EXP_SLTCTL_CCIE   0x0010  /* Command Completed Interrupt Enable */
-#define  PCI_EXP_SLTCTL_HPIE   0x0020  /* Hot-Plug Interrupt Enable */
-#define  PCI_EXP_SLTCTL_AIC    0x00c0  /* Attention Indicator Control */
-#define  PCI_EXP_SLTCTL_PIC    0x0300  /* Power Indicator Control */
-#define  PCI_EXP_SLTCTL_PCC    0x0400  /* Power Controller Control */
-#define  PCI_EXP_SLTCTL_EIC    0x0800  /* Electromechanical Interlock Control */
-#define  PCI_EXP_SLTCTL_DLLSCE 0x1000  /* Data Link Layer State Changed Enable */
-#define PCI_EXP_SLTSTA         26      /* Slot Status */
-#define  PCI_EXP_SLTSTA_ABP    0x0001  /* Attention Button Pressed */
-#define  PCI_EXP_SLTSTA_PFD    0x0002  /* Power Fault Detected */
-#define  PCI_EXP_SLTSTA_MRLSC  0x0004  /* MRL Sensor Changed */
-#define  PCI_EXP_SLTSTA_PDC    0x0008  /* Presence Detect Changed */
-#define  PCI_EXP_SLTSTA_CC     0x0010  /* Command Completed */
-#define  PCI_EXP_SLTSTA_MRLSS  0x0020  /* MRL Sensor State */
-#define  PCI_EXP_SLTSTA_PDS    0x0040  /* Presence Detect State */
-#define  PCI_EXP_SLTSTA_EIS    0x0080  /* Electromechanical Interlock Status */
-#define  PCI_EXP_SLTSTA_DLLSC  0x0100  /* Data Link Layer State Changed */
-#define PCI_EXP_RTCTL          28      /* Root Control */
-#define  PCI_EXP_RTCTL_SECEE   0x01    /* System Error on Correctable Error */
-#define  PCI_EXP_RTCTL_SENFEE  0x02    /* System Error on Non-Fatal Error */
-#define  PCI_EXP_RTCTL_SEFEE   0x04    /* System Error on Fatal Error */
-#define  PCI_EXP_RTCTL_PMEIE   0x08    /* PME Interrupt Enable */
-#define  PCI_EXP_RTCTL_CRSSVE  0x10    /* CRS Software Visibility Enable */
-#define PCI_EXP_RTCAP          30      /* Root Capabilities */
-#define PCI_EXP_RTSTA          32      /* Root Status */
-#define PCI_EXP_RTSTA_PME      0x10000 /* PME status */
-#define PCI_EXP_RTSTA_PENDING  0x20000 /* PME pending */
-#define PCI_EXP_DEVCAP2                36      /* Device Capabilities 2 */
-#define  PCI_EXP_DEVCAP2_ARI   0x20    /* Alternative Routing-ID */
-#define  PCI_EXP_DEVCAP2_LTR   0x800   /* Latency tolerance reporting */
-#define  PCI_EXP_OBFF_MASK     0xc0000 /* OBFF support mechanism */
-#define  PCI_EXP_OBFF_MSG      0x40000 /* New message signaling */
-#define  PCI_EXP_OBFF_WAKE     0x80000 /* Re-use WAKE# for OBFF */
-#define PCI_EXP_DEVCTL2                40      /* Device Control 2 */
-#define  PCI_EXP_DEVCTL2_ARI   0x20    /* Alternative Routing-ID */
-#define  PCI_EXP_IDO_REQ_EN    0x100   /* ID-based ordering request enable */
-#define  PCI_EXP_IDO_CMP_EN    0x200   /* ID-based ordering completion enable */
-#define  PCI_EXP_LTR_EN                0x400   /* Latency tolerance reporting */
-#define  PCI_EXP_OBFF_MSGA_EN  0x2000  /* OBFF enable with Message type A */
-#define  PCI_EXP_OBFF_MSGB_EN  0x4000  /* OBFF enable with Message type B */
-#define  PCI_EXP_OBFF_WAKE_EN  0x6000  /* OBFF using WAKE# signaling */
-#define PCI_EXP_LNKCTL2                48      /* Link Control 2 */
-#define PCI_EXP_SLTCTL2                56      /* Slot Control 2 */
-
-/* Extended Capabilities (PCI-X 2.0 and Express) */
-#define PCI_EXT_CAP_ID(header)         (header & 0x0000ffff)
-#define PCI_EXT_CAP_VER(header)                ((header >> 16) & 0xf)
-#define PCI_EXT_CAP_NEXT(header)       ((header >> 20) & 0xffc)
-
-#define PCI_EXT_CAP_ID_ERR     1
-#define PCI_EXT_CAP_ID_VC      2
-#define PCI_EXT_CAP_ID_DSN     3
-#define PCI_EXT_CAP_ID_PWR     4
-#define PCI_EXT_CAP_ID_VNDR    11
-#define PCI_EXT_CAP_ID_ACS     13
-#define PCI_EXT_CAP_ID_ARI     14
-#define PCI_EXT_CAP_ID_ATS     15
-#define PCI_EXT_CAP_ID_SRIOV   16
-#define PCI_EXT_CAP_ID_LTR     24
-
-/* Advanced Error Reporting */
-#define PCI_ERR_UNCOR_STATUS   4       /* Uncorrectable Error Status */
-#define  PCI_ERR_UNC_TRAIN     0x00000001      /* Training */
-#define  PCI_ERR_UNC_DLP       0x00000010      /* Data Link Protocol */
-#define  PCI_ERR_UNC_POISON_TLP        0x00001000      /* Poisoned TLP */
-#define  PCI_ERR_UNC_FCP       0x00002000      /* Flow Control Protocol */
-#define  PCI_ERR_UNC_COMP_TIME 0x00004000      /* Completion Timeout */
-#define  PCI_ERR_UNC_COMP_ABORT        0x00008000      /* Completer Abort */
-#define  PCI_ERR_UNC_UNX_COMP  0x00010000      /* Unexpected Completion */
-#define  PCI_ERR_UNC_RX_OVER   0x00020000      /* Receiver Overflow */
-#define  PCI_ERR_UNC_MALF_TLP  0x00040000      /* Malformed TLP */
-#define  PCI_ERR_UNC_ECRC      0x00080000      /* ECRC Error Status */
-#define  PCI_ERR_UNC_UNSUP     0x00100000      /* Unsupported Request */
-#define PCI_ERR_UNCOR_MASK     8       /* Uncorrectable Error Mask */
-       /* Same bits as above */
-#define PCI_ERR_UNCOR_SEVER    12      /* Uncorrectable Error Severity */
-       /* Same bits as above */
-#define PCI_ERR_COR_STATUS     16      /* Correctable Error Status */
-#define  PCI_ERR_COR_RCVR      0x00000001      /* Receiver Error Status */
-#define  PCI_ERR_COR_BAD_TLP   0x00000040      /* Bad TLP Status */
-#define  PCI_ERR_COR_BAD_DLLP  0x00000080      /* Bad DLLP Status */
-#define  PCI_ERR_COR_REP_ROLL  0x00000100      /* REPLAY_NUM Rollover */
-#define  PCI_ERR_COR_REP_TIMER 0x00001000      /* Replay Timer Timeout */
-#define PCI_ERR_COR_MASK       20      /* Correctable Error Mask */
-       /* Same bits as above */
-#define PCI_ERR_CAP            24      /* Advanced Error Capabilities */
-#define  PCI_ERR_CAP_FEP(x)    ((x) & 31)      /* First Error Pointer */
-#define  PCI_ERR_CAP_ECRC_GENC 0x00000020      /* ECRC Generation Capable */
-#define  PCI_ERR_CAP_ECRC_GENE 0x00000040      /* ECRC Generation Enable */
-#define  PCI_ERR_CAP_ECRC_CHKC 0x00000080      /* ECRC Check Capable */
-#define  PCI_ERR_CAP_ECRC_CHKE 0x00000100      /* ECRC Check Enable */
-#define PCI_ERR_HEADER_LOG     28      /* Header Log Register (16 bytes) */
-#define PCI_ERR_ROOT_COMMAND   44      /* Root Error Command */
-/* Correctable Err Reporting Enable */
-#define PCI_ERR_ROOT_CMD_COR_EN                0x00000001
-/* Non-fatal Err Reporting Enable */
-#define PCI_ERR_ROOT_CMD_NONFATAL_EN   0x00000002
-/* Fatal Err Reporting Enable */
-#define PCI_ERR_ROOT_CMD_FATAL_EN      0x00000004
-#define PCI_ERR_ROOT_STATUS    48
-#define PCI_ERR_ROOT_COR_RCV           0x00000001      /* ERR_COR Received */
-/* Multi ERR_COR Received */
-#define PCI_ERR_ROOT_MULTI_COR_RCV     0x00000002
-/* ERR_FATAL/NONFATAL Recevied */
-#define PCI_ERR_ROOT_UNCOR_RCV         0x00000004
-/* Multi ERR_FATAL/NONFATAL Recevied */
-#define PCI_ERR_ROOT_MULTI_UNCOR_RCV   0x00000008
-#define PCI_ERR_ROOT_FIRST_FATAL       0x00000010      /* First Fatal */
-#define PCI_ERR_ROOT_NONFATAL_RCV      0x00000020      /* Non-Fatal Received */
-#define PCI_ERR_ROOT_FATAL_RCV         0x00000040      /* Fatal Received */
-#define PCI_ERR_ROOT_ERR_SRC   52      /* Error Source Identification */
-
-/* Virtual Channel */
-#define PCI_VC_PORT_REG1       4
-#define PCI_VC_PORT_REG2       8
-#define PCI_VC_PORT_CTRL       12
-#define PCI_VC_PORT_STATUS     14
-#define PCI_VC_RES_CAP         16
-#define PCI_VC_RES_CTRL                20
-#define PCI_VC_RES_STATUS      26
-
-/* Power Budgeting */
-#define PCI_PWR_DSR            4       /* Data Select Register */
-#define PCI_PWR_DATA           8       /* Data Register */
-#define  PCI_PWR_DATA_BASE(x)  ((x) & 0xff)        /* Base Power */
-#define  PCI_PWR_DATA_SCALE(x) (((x) >> 8) & 3)    /* Data Scale */
-#define  PCI_PWR_DATA_PM_SUB(x)        (((x) >> 10) & 7)   /* PM Sub State */
-#define  PCI_PWR_DATA_PM_STATE(x) (((x) >> 13) & 3) /* PM State */
-#define  PCI_PWR_DATA_TYPE(x)  (((x) >> 15) & 7)   /* Type */
-#define  PCI_PWR_DATA_RAIL(x)  (((x) >> 18) & 7)   /* Power Rail */
-#define PCI_PWR_CAP            12      /* Capability */
-#define  PCI_PWR_CAP_BUDGET(x) ((x) & 1)       /* Included in system budget */
-
-/*
- * Hypertransport sub capability types
- *
- * Unfortunately there are both 3 bit and 5 bit capability types defined
- * in the HT spec, catering for that is a little messy. You probably don't
- * want to use these directly, just use pci_find_ht_capability() and it
- * will do the right thing for you.
- */
-#define HT_3BIT_CAP_MASK       0xE0
-#define HT_CAPTYPE_SLAVE       0x00    /* Slave/Primary link configuration */
-#define HT_CAPTYPE_HOST                0x20    /* Host/Secondary link configuration */
-
-#define HT_5BIT_CAP_MASK       0xF8
-#define HT_CAPTYPE_IRQ         0x80    /* IRQ Configuration */
-#define HT_CAPTYPE_REMAPPING_40        0xA0    /* 40 bit address remapping */
-#define HT_CAPTYPE_REMAPPING_64 0xA2   /* 64 bit address remapping */
-#define HT_CAPTYPE_UNITID_CLUMP        0x90    /* Unit ID clumping */
-#define HT_CAPTYPE_EXTCONF     0x98    /* Extended Configuration Space Access */
-#define HT_CAPTYPE_MSI_MAPPING 0xA8    /* MSI Mapping Capability */
-#define  HT_MSI_FLAGS          0x02            /* Offset to flags */
-#define  HT_MSI_FLAGS_ENABLE   0x1             /* Mapping enable */
-#define  HT_MSI_FLAGS_FIXED    0x2             /* Fixed mapping only */
-#define  HT_MSI_FIXED_ADDR     0x00000000FEE00000ULL   /* Fixed addr */
-#define  HT_MSI_ADDR_LO                0x04            /* Offset to low addr bits */
-#define  HT_MSI_ADDR_LO_MASK   0xFFF00000      /* Low address bit mask */
-#define  HT_MSI_ADDR_HI                0x08            /* Offset to high addr bits */
-#define HT_CAPTYPE_DIRECT_ROUTE        0xB0    /* Direct routing configuration */
-#define HT_CAPTYPE_VCSET       0xB8    /* Virtual Channel configuration */
-#define HT_CAPTYPE_ERROR_RETRY 0xC0    /* Retry on error configuration */
-#define HT_CAPTYPE_GEN3                0xD0    /* Generation 3 hypertransport configuration */
-#define HT_CAPTYPE_PM          0xE0    /* Hypertransport powermanagement configuration */
-
-/* Alternative Routing-ID Interpretation */
-#define PCI_ARI_CAP            0x04    /* ARI Capability Register */
-#define  PCI_ARI_CAP_MFVC      0x0001  /* MFVC Function Groups Capability */
-#define  PCI_ARI_CAP_ACS       0x0002  /* ACS Function Groups Capability */
-#define  PCI_ARI_CAP_NFN(x)    (((x) >> 8) & 0xff) /* Next Function Number */
-#define PCI_ARI_CTRL           0x06    /* ARI Control Register */
-#define  PCI_ARI_CTRL_MFVC     0x0001  /* MFVC Function Groups Enable */
-#define  PCI_ARI_CTRL_ACS      0x0002  /* ACS Function Groups Enable */
-#define  PCI_ARI_CTRL_FG(x)    (((x) >> 4) & 7) /* Function Group */
-
-/* Address Translation Service */
-#define PCI_ATS_CAP            0x04    /* ATS Capability Register */
-#define  PCI_ATS_CAP_QDEP(x)   ((x) & 0x1f)    /* Invalidate Queue Depth */
-#define  PCI_ATS_MAX_QDEP      32      /* Max Invalidate Queue Depth */
-#define PCI_ATS_CTRL           0x06    /* ATS Control Register */
-#define  PCI_ATS_CTRL_ENABLE   0x8000  /* ATS Enable */
-#define  PCI_ATS_CTRL_STU(x)   ((x) & 0x1f)    /* Smallest Translation Unit */
-#define  PCI_ATS_MIN_STU       12      /* shift of minimum STU block */
-
-/* Single Root I/O Virtualization */
-#define PCI_SRIOV_CAP          0x04    /* SR-IOV Capabilities */
-#define  PCI_SRIOV_CAP_VFM     0x01    /* VF Migration Capable */
-#define  PCI_SRIOV_CAP_INTR(x) ((x) >> 21) /* Interrupt Message Number */
-#define PCI_SRIOV_CTRL         0x08    /* SR-IOV Control */
-#define  PCI_SRIOV_CTRL_VFE    0x01    /* VF Enable */
-#define  PCI_SRIOV_CTRL_VFM    0x02    /* VF Migration Enable */
-#define  PCI_SRIOV_CTRL_INTR   0x04    /* VF Migration Interrupt Enable */
-#define  PCI_SRIOV_CTRL_MSE    0x08    /* VF Memory Space Enable */
-#define  PCI_SRIOV_CTRL_ARI    0x10    /* ARI Capable Hierarchy */
-#define PCI_SRIOV_STATUS       0x0a    /* SR-IOV Status */
-#define  PCI_SRIOV_STATUS_VFM  0x01    /* VF Migration Status */
-#define PCI_SRIOV_INITIAL_VF   0x0c    /* Initial VFs */
-#define PCI_SRIOV_TOTAL_VF     0x0e    /* Total VFs */
-#define PCI_SRIOV_NUM_VF       0x10    /* Number of VFs */
-#define PCI_SRIOV_FUNC_LINK    0x12    /* Function Dependency Link */
-#define PCI_SRIOV_VF_OFFSET    0x14    /* First VF Offset */
-#define PCI_SRIOV_VF_STRIDE    0x16    /* Following VF Stride */
-#define PCI_SRIOV_VF_DID       0x1a    /* VF Device ID */
-#define PCI_SRIOV_SUP_PGSIZE   0x1c    /* Supported Page Sizes */
-#define PCI_SRIOV_SYS_PGSIZE   0x20    /* System Page Size */
-#define PCI_SRIOV_BAR          0x24    /* VF BAR0 */
-#define  PCI_SRIOV_NUM_BARS    6       /* Number of VF BARs */
-#define PCI_SRIOV_VFM          0x3c    /* VF Migration State Array Offset*/
-#define  PCI_SRIOV_VFM_BIR(x)  ((x) & 7)       /* State BIR */
-#define  PCI_SRIOV_VFM_OFFSET(x) ((x) & ~7)    /* State Offset */
-#define  PCI_SRIOV_VFM_UA      0x0     /* Inactive.Unavailable */
-#define  PCI_SRIOV_VFM_MI      0x1     /* Dormant.MigrateIn */
-#define  PCI_SRIOV_VFM_MO      0x2     /* Active.MigrateOut */
-#define  PCI_SRIOV_VFM_AV      0x3     /* Active.Available */
-
-#define PCI_LTR_MAX_SNOOP_LAT  0x4
-#define PCI_LTR_MAX_NOSNOOP_LAT        0x6
-#define  PCI_LTR_VALUE_MASK    0x000003ff
-#define  PCI_LTR_SCALE_MASK    0x00001c00
-#define  PCI_LTR_SCALE_SHIFT   10
-
-/* Access Control Service */
-#define PCI_ACS_CAP            0x04    /* ACS Capability Register */
-#define  PCI_ACS_SV            0x01    /* Source Validation */
-#define  PCI_ACS_TB            0x02    /* Translation Blocking */
-#define  PCI_ACS_RR            0x04    /* P2P Request Redirect */
-#define  PCI_ACS_CR            0x08    /* P2P Completion Redirect */
-#define  PCI_ACS_UF            0x10    /* Upstream Forwarding */
-#define  PCI_ACS_EC            0x20    /* P2P Egress Control */
-#define  PCI_ACS_DT            0x40    /* Direct Translated P2P */
-#define PCI_ACS_CTRL           0x06    /* ACS Control Register */
-#define PCI_ACS_EGRESS_CTL_V   0x08    /* ACS Egress Control Vector */
-
-#endif /* LINUX_PCI_REGS_H */
diff --git a/hw/pci/pcie.h b/hw/pci/pcie.h
deleted file mode 100644 (file)
index c010007..0000000
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * pcie.h
- *
- * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
- *                    VA Linux Systems Japan K.K.
- *
- * 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 QEMU_PCIE_H
-#define QEMU_PCIE_H
-
-#include "hw/hw.h"
-#include "hw/pci/pci_regs.h"
-#include "hw/pci/pcie_regs.h"
-#include "hw/pci/pcie_aer.h"
-
-typedef enum {
-    /* for attention and power indicator */
-    PCI_EXP_HP_IND_RESERVED     = PCI_EXP_SLTCTL_IND_RESERVED,
-    PCI_EXP_HP_IND_ON           = PCI_EXP_SLTCTL_IND_ON,
-    PCI_EXP_HP_IND_BLINK        = PCI_EXP_SLTCTL_IND_BLINK,
-    PCI_EXP_HP_IND_OFF          = PCI_EXP_SLTCTL_IND_OFF,
-} PCIExpressIndicator;
-
-typedef enum {
-    /* these bits must match the bits in Slot Control/Status registers.
-     * PCI_EXP_HP_EV_xxx = PCI_EXP_SLTCTL_xxxE = PCI_EXP_SLTSTA_xxx
-     *
-     * Not all the bits of slot control register match with the ones of
-     * slot status. Not some bits of slot status register is used to
-     * show status, not to report event occurrence.
-     * So such bits must be masked out when checking the software
-     * notification condition.
-     */
-    PCI_EXP_HP_EV_ABP           = PCI_EXP_SLTCTL_ABPE,
-                                        /* attention button pressed */
-    PCI_EXP_HP_EV_PDC           = PCI_EXP_SLTCTL_PDCE,
-                                        /* presence detect changed */
-    PCI_EXP_HP_EV_CCI           = PCI_EXP_SLTCTL_CCIE,
-                                        /* command completed */
-
-    PCI_EXP_HP_EV_SUPPORTED     = PCI_EXP_HP_EV_ABP |
-                                  PCI_EXP_HP_EV_PDC |
-                                  PCI_EXP_HP_EV_CCI,
-                                                /* supported event mask  */
-
-    /* events not listed aren't supported */
-} PCIExpressHotPlugEvent;
-
-struct PCIExpressDevice {
-    /* Offset of express capability in config space */
-    uint8_t exp_cap;
-
-    /* SLOT */
-    unsigned int hpev_intx;     /* INTx for hot plug event (0-3:INT[A-D]#)
-                                 * default is 0 = INTA#
-                                 * If the chip wants to use other interrupt
-                                 * line, initialize this member with the
-                                 * desired number.
-                                 * If the chip dynamically changes this member,
-                                 * also initialize it when loaded as
-                                 * appropreately.
-                                 */
-    bool hpev_notified; /* Logical AND of conditions for hot plug event.
-                         Following 6.7.3.4:
-                         Software Notification of Hot-Plug Events, an interrupt
-                         is sent whenever the logical and of these conditions
-                         transitions from false to true. */
-
-    /* AER */
-    uint16_t aer_cap;
-    PCIEAERLog aer_log;
-    unsigned int aer_intx;      /* INTx for error reporting
-                                 * default is 0 = INTA#
-                                 * If the chip wants to use other interrupt
-                                 * line, initialize this member with the
-                                 * desired number.
-                                 * If the chip dynamically changes this member,
-                                 * also initialize it when loaded as
-                                 * appropreately.
-                                 */
-};
-
-/* PCI express capability helper functions */
-int pcie_cap_init(PCIDevice *dev, uint8_t offset, uint8_t type, uint8_t port);
-int pcie_endpoint_cap_init(PCIDevice *dev, uint8_t offset);
-void pcie_cap_exit(PCIDevice *dev);
-uint8_t pcie_cap_get_type(const PCIDevice *dev);
-void pcie_cap_flags_set_vector(PCIDevice *dev, uint8_t vector);
-uint8_t pcie_cap_flags_get_vector(PCIDevice *dev);
-
-void pcie_cap_deverr_init(PCIDevice *dev);
-void pcie_cap_deverr_reset(PCIDevice *dev);
-
-void pcie_cap_slot_init(PCIDevice *dev, uint16_t slot);
-void pcie_cap_slot_reset(PCIDevice *dev);
-void pcie_cap_slot_write_config(PCIDevice *dev,
-                                uint32_t addr, uint32_t val, int len);
-int pcie_cap_slot_post_load(void *opaque, int version_id);
-void pcie_cap_slot_push_attention_button(PCIDevice *dev);
-
-void pcie_cap_root_init(PCIDevice *dev);
-void pcie_cap_root_reset(PCIDevice *dev);
-
-void pcie_cap_flr_init(PCIDevice *dev);
-void pcie_cap_flr_write_config(PCIDevice *dev,
-                           uint32_t addr, uint32_t val, int len);
-
-void pcie_cap_ari_init(PCIDevice *dev);
-void pcie_cap_ari_reset(PCIDevice *dev);
-bool pcie_cap_is_ari_enabled(const PCIDevice *dev);
-
-/* PCI express extended capability helper functions */
-uint16_t pcie_find_capability(PCIDevice *dev, uint16_t cap_id);
-void pcie_add_capability(PCIDevice *dev,
-                         uint16_t cap_id, uint8_t cap_ver,
-                         uint16_t offset, uint16_t size);
-
-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)),                               \
-    .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/pci/pcie_aer.h b/hw/pci/pcie_aer.h
deleted file mode 100644 (file)
index bcac80a..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * pcie_aer.h
- *
- * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
- *                    VA Linux Systems Japan K.K.
- *
- * 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 QEMU_PCIE_AER_H
-#define QEMU_PCIE_AER_H
-
-#include "hw/hw.h"
-
-/* definitions which PCIExpressDevice uses */
-
-/* AER log */
-struct PCIEAERLog {
-    /* This structure is saved/loaded.
-       So explicitly size them instead of unsigned int */
-
-    /* the number of currently recorded log in log member */
-    uint16_t log_num;
-
-    /*
-     * The maximum number of the log. Errors can be logged up to this.
-     *
-     * This is configurable property.
-     * The specified value will be clipped down to PCIE_AER_LOG_MAX_LIMIT
-     * to avoid unreasonable memory usage.
-     * I bet that 128 log size would be big enough, otherwise too many errors
-     * for system to function normaly. But could consecutive errors occur?
-     */
-#define PCIE_AER_LOG_MAX_DEFAULT        8
-#define PCIE_AER_LOG_MAX_LIMIT          128
-#define PCIE_AER_LOG_MAX_UNSET          0xffff
-    uint16_t log_max;
-
-    /* Error log. log_max-sized array */
-    PCIEAERErr *log;
-};
-
-/* aer error message: error signaling message has only error sevirity and
-   source id. See 2.2.8.3 error signaling messages */
-struct PCIEAERMsg {
-    /*
-     * PCI_ERR_ROOT_CMD_{COR, NONFATAL, FATAL}_EN
-     * = PCI_EXP_DEVCTL_{CERE, NFERE, FERE}
-     */
-    uint32_t severity;
-
-    uint16_t source_id; /* bdf */
-};
-
-static inline bool
-pcie_aer_msg_is_uncor(const PCIEAERMsg *msg)
-{
-    return msg->severity == PCI_ERR_ROOT_CMD_NONFATAL_EN ||
-        msg->severity == PCI_ERR_ROOT_CMD_FATAL_EN;
-}
-
-/* error */
-struct PCIEAERErr {
-    uint32_t status;    /* error status bits */
-    uint16_t source_id; /* bdf */
-
-#define PCIE_AER_ERR_IS_CORRECTABLE     0x1     /* correctable/uncorrectable */
-#define PCIE_AER_ERR_MAYBE_ADVISORY     0x2     /* maybe advisory non-fatal */
-#define PCIE_AER_ERR_HEADER_VALID       0x4     /* TLP header is logged */
-#define PCIE_AER_ERR_TLP_PREFIX_PRESENT 0x8     /* TLP Prefix is logged */
-    uint16_t flags;
-
-    uint32_t header[4]; /* TLP header */
-    uint32_t prefix[4]; /* TLP header prefix */
-};
-
-extern const VMStateDescription vmstate_pcie_aer_log;
-
-int pcie_aer_init(PCIDevice *dev, uint16_t offset);
-void pcie_aer_exit(PCIDevice *dev);
-void pcie_aer_write_config(PCIDevice *dev,
-                           uint32_t addr, uint32_t val, int len);
-
-/* aer root port */
-void pcie_aer_root_set_vector(PCIDevice *dev, unsigned int vector);
-void pcie_aer_root_init(PCIDevice *dev);
-void pcie_aer_root_reset(PCIDevice *dev);
-void pcie_aer_root_write_config(PCIDevice *dev,
-                                uint32_t addr, uint32_t val, int len,
-                                uint32_t root_cmd_prev);
-
-/* error injection */
-int pcie_aer_inject_error(PCIDevice *dev, const PCIEAERErr *err);
-
-#endif /* QEMU_PCIE_AER_H */
diff --git a/hw/pci/pcie_host.h b/hw/pci/pcie_host.h
deleted file mode 100644 (file)
index 1228e36..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * pcie_host.h
- *
- * Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp>
- *                    VA Linux Systems Japan K.K.
- *
- * 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 PCIE_HOST_H
-#define PCIE_HOST_H
-
-#include "hw/pci/pci_host.h"
-#include "exec/memory.h"
-
-#define TYPE_PCIE_HOST_BRIDGE "pcie-host-bridge"
-#define PCIE_HOST_BRIDGE(obj) \
-    OBJECT_CHECK(PCIExpressHost, (obj), TYPE_PCIE_HOST_BRIDGE)
-
-struct PCIExpressHost {
-    PCIHostState pci;
-
-    /* express part */
-
-    /* base address where MMCONFIG area is mapped. */
-    hwaddr  base_addr;
-
-    /* the size of MMCONFIG area. It's host bridge dependent */
-    hwaddr  size;
-
-    /* MMCONFIG mmio area */
-    MemoryRegion mmio;
-};
-
-int pcie_host_init(PCIExpressHost *e);
-void pcie_host_mmcfg_unmap(PCIExpressHost *e);
-void pcie_host_mmcfg_map(PCIExpressHost *e, hwaddr addr, uint32_t size);
-void pcie_host_mmcfg_update(PCIExpressHost *e,
-                            int enable,
-                            hwaddr addr,
-                            uint32_t size);
-
-#endif /* PCIE_HOST_H */
diff --git a/hw/pci/pcie_port.h b/hw/pci/pcie_port.h
deleted file mode 100644 (file)
index d89aa61..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * pcie_port.h
- *
- * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
- *                    VA Linux Systems Japan K.K.
- *
- * 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 QEMU_PCIE_PORT_H
-#define QEMU_PCIE_PORT_H
-
-#include "hw/pci/pci_bridge.h"
-#include "hw/pci/pci_bus.h"
-
-struct PCIEPort {
-    PCIBridge   br;
-
-    /* pci express switch port */
-    uint8_t     port;
-};
-
-void pcie_port_init_reg(PCIDevice *d);
-
-struct PCIESlot {
-    PCIEPort    port;
-
-    /* pci express switch port with slot */
-    uint8_t     chassis;
-    uint16_t    slot;
-    QLIST_ENTRY(PCIESlot) next;
-};
-
-void pcie_chassis_create(uint8_t chassis_number);
-void pcie_main_chassis_create(void);
-PCIESlot *pcie_chassis_find_slot(uint8_t chassis, uint16_t slot);
-int pcie_chassis_add_slot(struct PCIESlot *slot);
-void pcie_chassis_del_slot(PCIESlot *s);
-
-#endif /* QEMU_PCIE_PORT_H */
diff --git a/hw/pci/pcie_regs.h b/hw/pci/pcie_regs.h
deleted file mode 100644 (file)
index 4d123d9..0000000
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * constants for pcie configurations space from pci express spec.
- *
- * TODO:
- * Those constants and macros should go to Linux pci_regs.h
- * Once they're merged, they will go away.
- */
-#ifndef QEMU_PCIE_REGS_H
-#define QEMU_PCIE_REGS_H
-
-
-/* express capability */
-
-#define PCI_EXP_VER2_SIZEOF             0x3c /* express capability of ver. 2 */
-#define PCI_EXT_CAP_VER_SHIFT           16
-#define PCI_EXT_CAP_NEXT_SHIFT          20
-#define PCI_EXT_CAP_NEXT_MASK           (0xffc << PCI_EXT_CAP_NEXT_SHIFT)
-
-#define PCI_EXT_CAP(id, ver, next)                                      \
-    ((id) |                                                             \
-     ((ver) << PCI_EXT_CAP_VER_SHIFT) |                                 \
-     ((next) << PCI_EXT_CAP_NEXT_SHIFT))
-
-#define PCI_EXT_CAP_ALIGN               4
-#define PCI_EXT_CAP_ALIGNUP(x)                                  \
-    (((x) + PCI_EXT_CAP_ALIGN - 1) & ~(PCI_EXT_CAP_ALIGN - 1))
-
-/* PCI_EXP_FLAGS */
-#define PCI_EXP_FLAGS_VER2              2 /* for now, supports only ver. 2 */
-#define PCI_EXP_FLAGS_IRQ_SHIFT         (ffs(PCI_EXP_FLAGS_IRQ) - 1)
-#define PCI_EXP_FLAGS_TYPE_SHIFT        (ffs(PCI_EXP_FLAGS_TYPE) - 1)
-
-
-/* PCI_EXP_LINK{CAP, STA} */
-/* link speed */
-#define PCI_EXP_LNK_LS_25               1
-
-#define PCI_EXP_LNK_MLW_SHIFT           (ffs(PCI_EXP_LNKCAP_MLW) - 1)
-#define PCI_EXP_LNK_MLW_1               (1 << PCI_EXP_LNK_MLW_SHIFT)
-
-/* PCI_EXP_LINKCAP */
-#define PCI_EXP_LNKCAP_ASPMS_SHIFT      (ffs(PCI_EXP_LNKCAP_ASPMS) - 1)
-#define PCI_EXP_LNKCAP_ASPMS_0S         (1 << PCI_EXP_LNKCAP_ASPMS_SHIFT)
-
-#define PCI_EXP_LNKCAP_PN_SHIFT         (ffs(PCI_EXP_LNKCAP_PN) - 1)
-
-#define PCI_EXP_SLTCAP_PSN_SHIFT        (ffs(PCI_EXP_SLTCAP_PSN) - 1)
-
-#define PCI_EXP_SLTCTL_IND_RESERVED     0x0
-#define PCI_EXP_SLTCTL_IND_ON           0x1
-#define PCI_EXP_SLTCTL_IND_BLINK        0x2
-#define PCI_EXP_SLTCTL_IND_OFF          0x3
-#define PCI_EXP_SLTCTL_AIC_SHIFT        (ffs(PCI_EXP_SLTCTL_AIC) - 1)
-#define PCI_EXP_SLTCTL_AIC_OFF                          \
-    (PCI_EXP_SLTCTL_IND_OFF << PCI_EXP_SLTCTL_AIC_SHIFT)
-
-#define PCI_EXP_SLTCTL_PIC_SHIFT        (ffs(PCI_EXP_SLTCTL_PIC) - 1)
-#define PCI_EXP_SLTCTL_PIC_OFF                          \
-    (PCI_EXP_SLTCTL_IND_OFF << PCI_EXP_SLTCTL_PIC_SHIFT)
-
-#define PCI_EXP_SLTCTL_SUPPORTED        \
-            (PCI_EXP_SLTCTL_ABPE |      \
-             PCI_EXP_SLTCTL_PDCE |      \
-             PCI_EXP_SLTCTL_CCIE |      \
-             PCI_EXP_SLTCTL_HPIE |      \
-             PCI_EXP_SLTCTL_AIC |       \
-             PCI_EXP_SLTCTL_PCC |       \
-             PCI_EXP_SLTCTL_EIC)
-
-#define PCI_EXP_DEVCAP2_EFF             0x100000
-#define PCI_EXP_DEVCAP2_EETLPP          0x200000
-
-#define PCI_EXP_DEVCTL2_EETLPPB         0x80
-
-/* ARI */
-#define PCI_ARI_VER                     1
-#define PCI_ARI_SIZEOF                  8
-
-/* AER */
-#define PCI_ERR_VER                     2
-#define PCI_ERR_SIZEOF                  0x48
-
-#define PCI_ERR_UNC_SDN                 0x00000020      /* surprise down */
-#define PCI_ERR_UNC_ACSV                0x00200000      /* ACS Violation */
-#define PCI_ERR_UNC_INTN                0x00400000      /* Internal Error */
-#define PCI_ERR_UNC_MCBTLP              0x00800000      /* MC Blcoked TLP */
-#define PCI_ERR_UNC_ATOP_EBLOCKED       0x01000000      /* atomic op egress blocked */
-#define PCI_ERR_UNC_TLP_PRF_BLOCKED     0x02000000      /* TLP Prefix Blocked */
-#define PCI_ERR_COR_ADV_NONFATAL        0x00002000      /* Advisory Non-Fatal */
-#define PCI_ERR_COR_INTERNAL            0x00004000      /* Corrected Internal */
-#define PCI_ERR_COR_HL_OVERFLOW         0x00008000      /* Header Long Overflow */
-#define PCI_ERR_CAP_FEP_MASK            0x0000001f
-#define PCI_ERR_CAP_MHRC                0x00000200
-#define PCI_ERR_CAP_MHRE                0x00000400
-#define PCI_ERR_CAP_TLP                 0x00000800
-
-#define PCI_ERR_HEADER_LOG_SIZE         16
-#define PCI_ERR_TLP_PREFIX_LOG          0x38
-#define PCI_ERR_TLP_PREFIX_LOG_SIZE     16
-
-#define PCI_SEC_STATUS_RCV_SYSTEM_ERROR         0x4000
-
-/* aer root error command/status */
-#define PCI_ERR_ROOT_CMD_EN_MASK        (PCI_ERR_ROOT_CMD_COR_EN |      \
-                                         PCI_ERR_ROOT_CMD_NONFATAL_EN | \
-                                         PCI_ERR_ROOT_CMD_FATAL_EN)
-
-#define PCI_ERR_ROOT_IRQ_MAX            32
-#define PCI_ERR_ROOT_IRQ                0xf8000000
-#define PCI_ERR_ROOT_IRQ_SHIFT          (ffs(PCI_ERR_ROOT_IRQ) - 1)
-#define PCI_ERR_ROOT_STATUS_REPORT_MASK (PCI_ERR_ROOT_COR_RCV |         \
-                                         PCI_ERR_ROOT_MULTI_COR_RCV |   \
-                                         PCI_ERR_ROOT_UNCOR_RCV |       \
-                                         PCI_ERR_ROOT_MULTI_UNCOR_RCV | \
-                                         PCI_ERR_ROOT_FIRST_FATAL |     \
-                                         PCI_ERR_ROOT_NONFATAL_RCV |    \
-                                         PCI_ERR_ROOT_FATAL_RCV)
-
-#define PCI_ERR_UNC_SUPPORTED           (PCI_ERR_UNC_DLP |              \
-                                         PCI_ERR_UNC_SDN |              \
-                                         PCI_ERR_UNC_POISON_TLP |       \
-                                         PCI_ERR_UNC_FCP |              \
-                                         PCI_ERR_UNC_COMP_TIME |        \
-                                         PCI_ERR_UNC_COMP_ABORT |       \
-                                         PCI_ERR_UNC_UNX_COMP |         \
-                                         PCI_ERR_UNC_RX_OVER |          \
-                                         PCI_ERR_UNC_MALF_TLP |         \
-                                         PCI_ERR_UNC_ECRC |             \
-                                         PCI_ERR_UNC_UNSUP |            \
-                                         PCI_ERR_UNC_ACSV |             \
-                                         PCI_ERR_UNC_INTN |             \
-                                         PCI_ERR_UNC_MCBTLP |           \
-                                         PCI_ERR_UNC_ATOP_EBLOCKED |    \
-                                         PCI_ERR_UNC_TLP_PRF_BLOCKED)
-
-#define PCI_ERR_UNC_SEVERITY_DEFAULT    (PCI_ERR_UNC_DLP |              \
-                                         PCI_ERR_UNC_SDN |              \
-                                         PCI_ERR_UNC_FCP |              \
-                                         PCI_ERR_UNC_RX_OVER |          \
-                                         PCI_ERR_UNC_MALF_TLP |         \
-                                         PCI_ERR_UNC_INTN)
-
-#define PCI_ERR_COR_SUPPORTED           (PCI_ERR_COR_RCVR |             \
-                                         PCI_ERR_COR_BAD_TLP |          \
-                                         PCI_ERR_COR_BAD_DLLP |         \
-                                         PCI_ERR_COR_REP_ROLL |         \
-                                         PCI_ERR_COR_REP_TIMER |        \
-                                         PCI_ERR_COR_ADV_NONFATAL |     \
-                                         PCI_ERR_COR_INTERNAL |         \
-                                         PCI_ERR_COR_HL_OVERFLOW)
-
-#define PCI_ERR_COR_MASK_DEFAULT        (PCI_ERR_COR_ADV_NONFATAL |     \
-                                         PCI_ERR_COR_INTERNAL |         \
-                                         PCI_ERR_COR_HL_OVERFLOW)
-
-#endif /* QEMU_PCIE_REGS_H */
diff --git a/hw/pci/shpc.h b/hw/pci/shpc.h
deleted file mode 100644 (file)
index 467911a..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-#ifndef SHPC_H
-#define SHPC_H
-
-#include "qemu-common.h"
-#include "exec/memory.h"
-#include "migration/vmstate.h"
-
-struct SHPCDevice {
-    /* Capability offset in device's config space */
-    int cap;
-
-    /* # of hot-pluggable slots */
-    int nslots;
-
-    /* SHPC WRS: working register set */
-    uint8_t *config;
-
-    /* Used to enable checks on load. Note that writable bits are
-     * never checked even if set in cmask. */
-    uint8_t *cmask;
-
-    /* Used to implement R/W bytes */
-    uint8_t *wmask;
-
-    /* Used to implement RW1C(Write 1 to Clear) bytes */
-    uint8_t *w1cmask;
-
-    /* MMIO for the SHPC BAR */
-    MemoryRegion mmio;
-
-    /* Bus controlled by this SHPC */
-    PCIBus *sec_bus;
-
-    /* MSI already requested for this event */
-    int msi_requested;
-};
-
-void shpc_reset(PCIDevice *d);
-int shpc_bar_size(PCIDevice *dev);
-int shpc_init(PCIDevice *dev, PCIBus *sec_bus, MemoryRegion *bar, unsigned off);
-void shpc_cleanup(PCIDevice *dev, MemoryRegion *bar);
-void shpc_cap_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int len);
-
-extern VMStateInfo shpc_vmstate_info;
-#define SHPC_VMSTATE(_field, _type) \
-    VMSTATE_BUFFER_UNSAFE_INFO(_field, _type, 0, shpc_vmstate_info, 0)
-
-#endif
diff --git a/hw/pci/slotid_cap.h b/hw/pci/slotid_cap.h
deleted file mode 100644 (file)
index 70db047..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-#ifndef PCI_SLOTID_CAP_H
-#define PCI_SLOTID_CAP_H
-
-#include "qemu-common.h"
-
-int slotid_cap_init(PCIDevice *dev, int nslots,
-                    uint8_t chassis,
-                    unsigned offset);
-void slotid_cap_cleanup(PCIDevice *dev);
-
-#endif
diff --git a/hw/pci_bridge_dev.c b/hw/pci_bridge_dev.c
deleted file mode 100644 (file)
index 971b432..0000000
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * Standard PCI Bridge Device
- *
- * Copyright (c) 2011 Red Hat Inc. Author: Michael S. Tsirkin <mst@redhat.com>
- *
- * http://www.pcisig.com/specifications/conventional/pci_to_pci_bridge_architecture/
- *
- * 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 "hw/pci/pci_bridge.h"
-#include "hw/pci/pci_ids.h"
-#include "hw/pci/msi.h"
-#include "hw/pci/shpc.h"
-#include "hw/pci/slotid_cap.h"
-#include "exec/memory.h"
-#include "hw/pci/pci_bus.h"
-
-struct PCIBridgeDev {
-    PCIBridge bridge;
-    MemoryRegion bar;
-    uint8_t chassis_nr;
-#define PCI_BRIDGE_DEV_F_MSI_REQ 0
-    uint32_t flags;
-};
-typedef struct PCIBridgeDev PCIBridgeDev;
-
-static int pci_bridge_dev_initfn(PCIDevice *dev)
-{
-    PCIBridge *br = DO_UPCAST(PCIBridge, dev, dev);
-    PCIBridgeDev *bridge_dev = DO_UPCAST(PCIBridgeDev, bridge, br);
-    int err;
-
-    err = pci_bridge_initfn(dev, TYPE_PCI_BUS);
-    if (err) {
-        goto bridge_error;
-    }
-    memory_region_init(&bridge_dev->bar, "shpc-bar", shpc_bar_size(dev));
-    err = shpc_init(dev, &br->sec_bus, &bridge_dev->bar, 0);
-    if (err) {
-        goto shpc_error;
-    }
-    err = slotid_cap_init(dev, 0, bridge_dev->chassis_nr, 0);
-    if (err) {
-        goto slotid_error;
-    }
-    if ((bridge_dev->flags & (1 << PCI_BRIDGE_DEV_F_MSI_REQ)) &&
-        msi_supported) {
-        err = msi_init(dev, 0, 1, true, true);
-        if (err < 0) {
-            goto msi_error;
-        }
-    }
-    /* TODO: spec recommends using 64 bit prefetcheable BAR.
-     * Check whether that works well. */
-    pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY |
-                    PCI_BASE_ADDRESS_MEM_TYPE_64, &bridge_dev->bar);
-    dev->config[PCI_INTERRUPT_PIN] = 0x1;
-    return 0;
-msi_error:
-    slotid_cap_cleanup(dev);
-slotid_error:
-    shpc_cleanup(dev, &bridge_dev->bar);
-shpc_error:
-    memory_region_destroy(&bridge_dev->bar);
-    pci_bridge_exitfn(dev);
-bridge_error:
-    return err;
-}
-
-static void pci_bridge_dev_exitfn(PCIDevice *dev)
-{
-    PCIBridge *br = DO_UPCAST(PCIBridge, dev, dev);
-    PCIBridgeDev *bridge_dev = DO_UPCAST(PCIBridgeDev, bridge, br);
-    if (msi_present(dev)) {
-        msi_uninit(dev);
-    }
-    slotid_cap_cleanup(dev);
-    shpc_cleanup(dev, &bridge_dev->bar);
-    memory_region_destroy(&bridge_dev->bar);
-    pci_bridge_exitfn(dev);
-}
-
-static void pci_bridge_dev_write_config(PCIDevice *d,
-                                        uint32_t address, uint32_t val, int len)
-{
-    pci_bridge_write_config(d, address, val, len);
-    if (msi_present(d)) {
-        msi_write_config(d, address, val, len);
-    }
-    shpc_cap_write_config(d, address, val, len);
-}
-
-static void qdev_pci_bridge_dev_reset(DeviceState *qdev)
-{
-    PCIDevice *dev = DO_UPCAST(PCIDevice, qdev, qdev);
-
-    pci_bridge_reset(qdev);
-    shpc_reset(dev);
-}
-
-static Property pci_bridge_dev_properties[] = {
-                    /* Note: 0 is not a legal chassis number. */
-    DEFINE_PROP_UINT8("chassis_nr", PCIBridgeDev, chassis_nr, 0),
-    DEFINE_PROP_BIT("msi", PCIBridgeDev, flags, PCI_BRIDGE_DEV_F_MSI_REQ, true),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static const VMStateDescription pci_bridge_dev_vmstate = {
-    .name = "pci_bridge",
-    .fields = (VMStateField[]) {
-        VMSTATE_PCI_DEVICE(bridge.dev, PCIBridgeDev),
-        SHPC_VMSTATE(bridge.dev.shpc, PCIBridgeDev),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void pci_bridge_dev_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-    k->init = pci_bridge_dev_initfn;
-    k->exit = pci_bridge_dev_exitfn;
-    k->config_write = pci_bridge_dev_write_config;
-    k->vendor_id = PCI_VENDOR_ID_REDHAT;
-    k->device_id = PCI_DEVICE_ID_REDHAT_BRIDGE;
-    k->class_id = PCI_CLASS_BRIDGE_PCI;
-    k->is_bridge = 1,
-    dc->desc = "Standard PCI Bridge";
-    dc->reset = qdev_pci_bridge_dev_reset;
-    dc->props = pci_bridge_dev_properties;
-    dc->vmsd = &pci_bridge_dev_vmstate;
-}
-
-static const TypeInfo pci_bridge_dev_info = {
-    .name = "pci-bridge",
-    .parent        = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(PCIBridgeDev),
-    .class_init = pci_bridge_dev_class_init,
-};
-
-static void pci_bridge_dev_register(void)
-{
-    type_register_static(&pci_bridge_dev_info);
-}
-
-type_init(pci_bridge_dev_register);
diff --git a/hw/pckbd.c b/hw/pckbd.c
deleted file mode 100644 (file)
index cc63df0..0000000
+++ /dev/null
@@ -1,527 +0,0 @@
-/*
- * QEMU PC keyboard emulation
- *
- * 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.
- */
-#include "hw/hw.h"
-#include "hw/isa.h"
-#include "hw/pc.h"
-#include "hw/ps2.h"
-#include "sysemu/sysemu.h"
-
-/* debug PC keyboard */
-//#define DEBUG_KBD
-#ifdef DEBUG_KBD
-#define DPRINTF(fmt, ...)                                       \
-    do { printf("KBD: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...)
-#endif
-
-/*     Keyboard Controller Commands */
-#define KBD_CCMD_READ_MODE     0x20    /* Read mode bits */
-#define KBD_CCMD_WRITE_MODE    0x60    /* Write mode bits */
-#define KBD_CCMD_GET_VERSION   0xA1    /* Get controller version */
-#define KBD_CCMD_MOUSE_DISABLE 0xA7    /* Disable mouse interface */
-#define KBD_CCMD_MOUSE_ENABLE  0xA8    /* Enable mouse interface */
-#define KBD_CCMD_TEST_MOUSE    0xA9    /* Mouse interface test */
-#define KBD_CCMD_SELF_TEST     0xAA    /* Controller self test */
-#define KBD_CCMD_KBD_TEST      0xAB    /* Keyboard interface test */
-#define KBD_CCMD_KBD_DISABLE   0xAD    /* Keyboard interface disable */
-#define KBD_CCMD_KBD_ENABLE    0xAE    /* Keyboard interface enable */
-#define KBD_CCMD_READ_INPORT    0xC0    /* read input port */
-#define KBD_CCMD_READ_OUTPORT  0xD0    /* read output port */
-#define KBD_CCMD_WRITE_OUTPORT 0xD1    /* write output port */
-#define KBD_CCMD_WRITE_OBUF    0xD2
-#define KBD_CCMD_WRITE_AUX_OBUF        0xD3    /* Write to output buffer as if
-                                          initiated by the auxiliary device */
-#define KBD_CCMD_WRITE_MOUSE   0xD4    /* Write the following byte to the mouse */
-#define KBD_CCMD_DISABLE_A20    0xDD    /* HP vectra only ? */
-#define KBD_CCMD_ENABLE_A20     0xDF    /* HP vectra only ? */
-#define KBD_CCMD_PULSE_BITS_3_0 0xF0    /* Pulse bits 3-0 of the output port P2. */
-#define KBD_CCMD_RESET          0xFE    /* Pulse bit 0 of the output port P2 = CPU reset. */
-#define KBD_CCMD_NO_OP          0xFF    /* Pulse no bits of the output port P2. */
-
-/* Keyboard Commands */
-#define KBD_CMD_SET_LEDS       0xED    /* Set keyboard leds */
-#define KBD_CMD_ECHO           0xEE
-#define KBD_CMD_GET_ID                 0xF2    /* get keyboard ID */
-#define KBD_CMD_SET_RATE       0xF3    /* Set typematic rate */
-#define KBD_CMD_ENABLE         0xF4    /* Enable scanning */
-#define KBD_CMD_RESET_DISABLE  0xF5    /* reset and disable scanning */
-#define KBD_CMD_RESET_ENABLE           0xF6    /* reset and enable scanning */
-#define KBD_CMD_RESET          0xFF    /* Reset */
-
-/* Keyboard Replies */
-#define KBD_REPLY_POR          0xAA    /* Power on reset */
-#define KBD_REPLY_ACK          0xFA    /* Command ACK */
-#define KBD_REPLY_RESEND       0xFE    /* Command NACK, send the cmd again */
-
-/* Status Register Bits */
-#define KBD_STAT_OBF           0x01    /* Keyboard output buffer full */
-#define KBD_STAT_IBF           0x02    /* Keyboard input buffer full */
-#define KBD_STAT_SELFTEST      0x04    /* Self test successful */
-#define KBD_STAT_CMD           0x08    /* Last write was a command write (0=data) */
-#define KBD_STAT_UNLOCKED      0x10    /* Zero if keyboard locked */
-#define KBD_STAT_MOUSE_OBF     0x20    /* Mouse output buffer full */
-#define KBD_STAT_GTO           0x40    /* General receive/xmit timeout */
-#define KBD_STAT_PERR          0x80    /* Parity error */
-
-/* Controller Mode Register Bits */
-#define KBD_MODE_KBD_INT       0x01    /* Keyboard data generate IRQ1 */
-#define KBD_MODE_MOUSE_INT     0x02    /* Mouse data generate IRQ12 */
-#define KBD_MODE_SYS           0x04    /* The system flag (?) */
-#define KBD_MODE_NO_KEYLOCK    0x08    /* The keylock doesn't affect the keyboard if set */
-#define KBD_MODE_DISABLE_KBD   0x10    /* Disable keyboard interface */
-#define KBD_MODE_DISABLE_MOUSE 0x20    /* Disable mouse interface */
-#define KBD_MODE_KCC           0x40    /* Scan code conversion to PC format */
-#define KBD_MODE_RFU           0x80
-
-/* Output Port Bits */
-#define KBD_OUT_RESET           0x01    /* 1=normal mode, 0=reset */
-#define KBD_OUT_A20             0x02    /* x86 only */
-#define KBD_OUT_OBF             0x10    /* Keyboard output buffer full */
-#define KBD_OUT_MOUSE_OBF       0x20    /* Mouse output buffer full */
-
-/* Mouse Commands */
-#define AUX_SET_SCALE11                0xE6    /* Set 1:1 scaling */
-#define AUX_SET_SCALE21                0xE7    /* Set 2:1 scaling */
-#define AUX_SET_RES            0xE8    /* Set resolution */
-#define AUX_GET_SCALE          0xE9    /* Get scaling factor */
-#define AUX_SET_STREAM         0xEA    /* Set stream mode */
-#define AUX_POLL               0xEB    /* Poll */
-#define AUX_RESET_WRAP         0xEC    /* Reset wrap mode */
-#define AUX_SET_WRAP           0xEE    /* Set wrap mode */
-#define AUX_SET_REMOTE         0xF0    /* Set remote mode */
-#define AUX_GET_TYPE           0xF2    /* Get type */
-#define AUX_SET_SAMPLE         0xF3    /* Set sample rate */
-#define AUX_ENABLE_DEV         0xF4    /* Enable aux device */
-#define AUX_DISABLE_DEV                0xF5    /* Disable aux device */
-#define AUX_SET_DEFAULT                0xF6
-#define AUX_RESET              0xFF    /* Reset aux device */
-#define AUX_ACK                        0xFA    /* Command byte ACK. */
-
-#define MOUSE_STATUS_REMOTE     0x40
-#define MOUSE_STATUS_ENABLED    0x20
-#define MOUSE_STATUS_SCALE21    0x10
-
-#define KBD_PENDING_KBD         1
-#define KBD_PENDING_AUX         2
-
-typedef struct KBDState {
-    uint8_t write_cmd; /* if non zero, write data to port 60 is expected */
-    uint8_t status;
-    uint8_t mode;
-    uint8_t outport;
-    /* Bitmask of devices with data available.  */
-    uint8_t pending;
-    void *kbd;
-    void *mouse;
-
-    qemu_irq irq_kbd;
-    qemu_irq irq_mouse;
-    qemu_irq *a20_out;
-    hwaddr mask;
-} KBDState;
-
-/* update irq and KBD_STAT_[MOUSE_]OBF */
-/* XXX: not generating the irqs if KBD_MODE_DISABLE_KBD is set may be
-   incorrect, but it avoids having to simulate exact delays */
-static void kbd_update_irq(KBDState *s)
-{
-    int irq_kbd_level, irq_mouse_level;
-
-    irq_kbd_level = 0;
-    irq_mouse_level = 0;
-    s->status &= ~(KBD_STAT_OBF | KBD_STAT_MOUSE_OBF);
-    s->outport &= ~(KBD_OUT_OBF | KBD_OUT_MOUSE_OBF);
-    if (s->pending) {
-        s->status |= KBD_STAT_OBF;
-        s->outport |= KBD_OUT_OBF;
-        /* kbd data takes priority over aux data.  */
-        if (s->pending == KBD_PENDING_AUX) {
-            s->status |= KBD_STAT_MOUSE_OBF;
-            s->outport |= KBD_OUT_MOUSE_OBF;
-            if (s->mode & KBD_MODE_MOUSE_INT)
-                irq_mouse_level = 1;
-        } else {
-            if ((s->mode & KBD_MODE_KBD_INT) &&
-                !(s->mode & KBD_MODE_DISABLE_KBD))
-                irq_kbd_level = 1;
-        }
-    }
-    qemu_set_irq(s->irq_kbd, irq_kbd_level);
-    qemu_set_irq(s->irq_mouse, irq_mouse_level);
-}
-
-static void kbd_update_kbd_irq(void *opaque, int level)
-{
-    KBDState *s = (KBDState *)opaque;
-
-    if (level)
-        s->pending |= KBD_PENDING_KBD;
-    else
-        s->pending &= ~KBD_PENDING_KBD;
-    kbd_update_irq(s);
-}
-
-static void kbd_update_aux_irq(void *opaque, int level)
-{
-    KBDState *s = (KBDState *)opaque;
-
-    if (level)
-        s->pending |= KBD_PENDING_AUX;
-    else
-        s->pending &= ~KBD_PENDING_AUX;
-    kbd_update_irq(s);
-}
-
-static uint64_t kbd_read_status(void *opaque, hwaddr addr,
-                                unsigned size)
-{
-    KBDState *s = opaque;
-    int val;
-    val = s->status;
-    DPRINTF("kbd: read status=0x%02x\n", val);
-    return val;
-}
-
-static void kbd_queue(KBDState *s, int b, int aux)
-{
-    if (aux)
-        ps2_queue(s->mouse, b);
-    else
-        ps2_queue(s->kbd, b);
-}
-
-static void outport_write(KBDState *s, uint32_t val)
-{
-    DPRINTF("kbd: write outport=0x%02x\n", val);
-    s->outport = val;
-    if (s->a20_out) {
-        qemu_set_irq(*s->a20_out, (val >> 1) & 1);
-    }
-    if (!(val & 1)) {
-        qemu_system_reset_request();
-    }
-}
-
-static void kbd_write_command(void *opaque, hwaddr addr,
-                              uint64_t val, unsigned size)
-{
-    KBDState *s = opaque;
-
-    DPRINTF("kbd: write cmd=0x%02x\n", val);
-
-    /* Bits 3-0 of the output port P2 of the keyboard controller may be pulsed
-     * low for approximately 6 micro seconds. Bits 3-0 of the KBD_CCMD_PULSE
-     * command specify the output port bits to be pulsed.
-     * 0: Bit should be pulsed. 1: Bit should not be modified.
-     * The only useful version of this command is pulsing bit 0,
-     * which does a CPU reset.
-     */
-    if((val & KBD_CCMD_PULSE_BITS_3_0) == KBD_CCMD_PULSE_BITS_3_0) {
-        if(!(val & 1))
-            val = KBD_CCMD_RESET;
-        else
-            val = KBD_CCMD_NO_OP;
-    }
-
-    switch(val) {
-    case KBD_CCMD_READ_MODE:
-        kbd_queue(s, s->mode, 0);
-        break;
-    case KBD_CCMD_WRITE_MODE:
-    case KBD_CCMD_WRITE_OBUF:
-    case KBD_CCMD_WRITE_AUX_OBUF:
-    case KBD_CCMD_WRITE_MOUSE:
-    case KBD_CCMD_WRITE_OUTPORT:
-        s->write_cmd = val;
-        break;
-    case KBD_CCMD_MOUSE_DISABLE:
-        s->mode |= KBD_MODE_DISABLE_MOUSE;
-        break;
-    case KBD_CCMD_MOUSE_ENABLE:
-        s->mode &= ~KBD_MODE_DISABLE_MOUSE;
-        break;
-    case KBD_CCMD_TEST_MOUSE:
-        kbd_queue(s, 0x00, 0);
-        break;
-    case KBD_CCMD_SELF_TEST:
-        s->status |= KBD_STAT_SELFTEST;
-        kbd_queue(s, 0x55, 0);
-        break;
-    case KBD_CCMD_KBD_TEST:
-        kbd_queue(s, 0x00, 0);
-        break;
-    case KBD_CCMD_KBD_DISABLE:
-        s->mode |= KBD_MODE_DISABLE_KBD;
-        kbd_update_irq(s);
-        break;
-    case KBD_CCMD_KBD_ENABLE:
-        s->mode &= ~KBD_MODE_DISABLE_KBD;
-        kbd_update_irq(s);
-        break;
-    case KBD_CCMD_READ_INPORT:
-        kbd_queue(s, 0x00, 0);
-        break;
-    case KBD_CCMD_READ_OUTPORT:
-        kbd_queue(s, s->outport, 0);
-        break;
-    case KBD_CCMD_ENABLE_A20:
-        if (s->a20_out) {
-            qemu_irq_raise(*s->a20_out);
-        }
-        s->outport |= KBD_OUT_A20;
-        break;
-    case KBD_CCMD_DISABLE_A20:
-        if (s->a20_out) {
-            qemu_irq_lower(*s->a20_out);
-        }
-        s->outport &= ~KBD_OUT_A20;
-        break;
-    case KBD_CCMD_RESET:
-        qemu_system_reset_request();
-        break;
-    case KBD_CCMD_NO_OP:
-        /* ignore that */
-        break;
-    default:
-        fprintf(stderr, "qemu: unsupported keyboard cmd=0x%02x\n", (int)val);
-        break;
-    }
-}
-
-static uint64_t kbd_read_data(void *opaque, hwaddr addr,
-                              unsigned size)
-{
-    KBDState *s = opaque;
-    uint32_t val;
-
-    if (s->pending == KBD_PENDING_AUX)
-        val = ps2_read_data(s->mouse);
-    else
-        val = ps2_read_data(s->kbd);
-
-    DPRINTF("kbd: read data=0x%02x\n", val);
-    return val;
-}
-
-static void kbd_write_data(void *opaque, hwaddr addr,
-                           uint64_t val, unsigned size)
-{
-    KBDState *s = opaque;
-
-    DPRINTF("kbd: write data=0x%02x\n", val);
-
-    switch(s->write_cmd) {
-    case 0:
-        ps2_write_keyboard(s->kbd, val);
-        break;
-    case KBD_CCMD_WRITE_MODE:
-        s->mode = val;
-        ps2_keyboard_set_translation(s->kbd, (s->mode & KBD_MODE_KCC) != 0);
-        /* ??? */
-        kbd_update_irq(s);
-        break;
-    case KBD_CCMD_WRITE_OBUF:
-        kbd_queue(s, val, 0);
-        break;
-    case KBD_CCMD_WRITE_AUX_OBUF:
-        kbd_queue(s, val, 1);
-        break;
-    case KBD_CCMD_WRITE_OUTPORT:
-        outport_write(s, val);
-        break;
-    case KBD_CCMD_WRITE_MOUSE:
-        ps2_write_mouse(s->mouse, val);
-        break;
-    default:
-        break;
-    }
-    s->write_cmd = 0;
-}
-
-static void kbd_reset(void *opaque)
-{
-    KBDState *s = opaque;
-
-    s->mode = KBD_MODE_KBD_INT | KBD_MODE_MOUSE_INT;
-    s->status = KBD_STAT_CMD | KBD_STAT_UNLOCKED;
-    s->outport = KBD_OUT_RESET | KBD_OUT_A20;
-}
-
-static const VMStateDescription vmstate_kbd = {
-    .name = "pckbd",
-    .version_id = 3,
-    .minimum_version_id = 3,
-    .minimum_version_id_old = 3,
-    .fields      = (VMStateField []) {
-        VMSTATE_UINT8(write_cmd, KBDState),
-        VMSTATE_UINT8(status, KBDState),
-        VMSTATE_UINT8(mode, KBDState),
-        VMSTATE_UINT8(pending, KBDState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-/* Memory mapped interface */
-static uint32_t kbd_mm_readb (void *opaque, hwaddr addr)
-{
-    KBDState *s = opaque;
-
-    if (addr & s->mask)
-        return kbd_read_status(s, 0, 1) & 0xff;
-    else
-        return kbd_read_data(s, 0, 1) & 0xff;
-}
-
-static void kbd_mm_writeb (void *opaque, hwaddr addr, uint32_t value)
-{
-    KBDState *s = opaque;
-
-    if (addr & s->mask)
-        kbd_write_command(s, 0, value & 0xff, 1);
-    else
-        kbd_write_data(s, 0, value & 0xff, 1);
-}
-
-static const MemoryRegionOps i8042_mmio_ops = {
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .old_mmio = {
-        .read = { kbd_mm_readb, kbd_mm_readb, kbd_mm_readb },
-        .write = { kbd_mm_writeb, kbd_mm_writeb, kbd_mm_writeb },
-    },
-};
-
-void i8042_mm_init(qemu_irq kbd_irq, qemu_irq mouse_irq,
-                   MemoryRegion *region, ram_addr_t size,
-                   hwaddr mask)
-{
-    KBDState *s = g_malloc0(sizeof(KBDState));
-
-    s->irq_kbd = kbd_irq;
-    s->irq_mouse = mouse_irq;
-    s->mask = mask;
-
-    vmstate_register(NULL, 0, &vmstate_kbd, s);
-
-    memory_region_init_io(region, &i8042_mmio_ops, s, "i8042", size);
-
-    s->kbd = ps2_kbd_init(kbd_update_kbd_irq, s);
-    s->mouse = ps2_mouse_init(kbd_update_aux_irq, s);
-    qemu_register_reset(kbd_reset, s);
-}
-
-typedef struct ISAKBDState {
-    ISADevice dev;
-    KBDState kbd;
-    MemoryRegion io[2];
-} ISAKBDState;
-
-void i8042_isa_mouse_fake_event(void *opaque)
-{
-    ISADevice *dev = opaque;
-    KBDState *s = &(DO_UPCAST(ISAKBDState, dev, dev)->kbd);
-
-    ps2_mouse_fake_event(s->mouse);
-}
-
-void i8042_setup_a20_line(ISADevice *dev, qemu_irq *a20_out)
-{
-    KBDState *s = &(DO_UPCAST(ISAKBDState, dev, dev)->kbd);
-
-    s->a20_out = a20_out;
-}
-
-static const VMStateDescription vmstate_kbd_isa = {
-    .name = "pckbd",
-    .version_id = 3,
-    .minimum_version_id = 3,
-    .minimum_version_id_old = 3,
-    .fields      = (VMStateField []) {
-        VMSTATE_STRUCT(kbd, ISAKBDState, 0, vmstate_kbd, KBDState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static const MemoryRegionOps i8042_data_ops = {
-    .read = kbd_read_data,
-    .write = kbd_write_data,
-    .impl = {
-        .min_access_size = 1,
-        .max_access_size = 1,
-    },
-    .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static const MemoryRegionOps i8042_cmd_ops = {
-    .read = kbd_read_status,
-    .write = kbd_write_command,
-    .impl = {
-        .min_access_size = 1,
-        .max_access_size = 1,
-    },
-    .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static int i8042_initfn(ISADevice *dev)
-{
-    ISAKBDState *isa_s = DO_UPCAST(ISAKBDState, dev, dev);
-    KBDState *s = &isa_s->kbd;
-
-    isa_init_irq(dev, &s->irq_kbd, 1);
-    isa_init_irq(dev, &s->irq_mouse, 12);
-
-    memory_region_init_io(isa_s->io + 0, &i8042_data_ops, s, "i8042-data", 1);
-    isa_register_ioport(dev, isa_s->io + 0, 0x60);
-
-    memory_region_init_io(isa_s->io + 1, &i8042_cmd_ops, s, "i8042-cmd", 1);
-    isa_register_ioport(dev, isa_s->io + 1, 0x64);
-
-    s->kbd = ps2_kbd_init(kbd_update_kbd_irq, s);
-    s->mouse = ps2_mouse_init(kbd_update_aux_irq, s);
-    qemu_register_reset(kbd_reset, s);
-    return 0;
-}
-
-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 const TypeInfo i8042_info = {
-    .name          = "i8042",
-    .parent        = TYPE_ISA_DEVICE,
-    .instance_size = sizeof(ISAKBDState),
-    .class_init    = i8042_class_initfn,
-};
-
-static void i8042_register_types(void)
-{
-    type_register_static(&i8042_info);
-}
-
-type_init(i8042_register_types)
diff --git a/hw/pcmcia.h b/hw/pcmcia.h
deleted file mode 100644 (file)
index f916693..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-#ifndef HW_PCMCIA_H
-#define HW_PCMCIA_H 1
-
-/* PCMCIA/Cardbus */
-
-#include "qemu-common.h"
-
-typedef struct {
-    qemu_irq irq;
-    int attached;
-    const char *slot_string;
-    const char *card_string;
-} PCMCIASocket;
-
-void pcmcia_socket_register(PCMCIASocket *socket);
-void pcmcia_socket_unregister(PCMCIASocket *socket);
-void pcmcia_info(Monitor *mon, const QDict *qdict);
-
-struct PCMCIACardState {
-    void *state;
-    PCMCIASocket *slot;
-    int (*attach)(void *state);
-    int (*detach)(void *state);
-    const uint8_t *cis;
-    int cis_len;
-
-    /* Only valid if attached */
-    uint8_t (*attr_read)(void *state, uint32_t address);
-    void (*attr_write)(void *state, uint32_t address, uint8_t value);
-    uint16_t (*common_read)(void *state, uint32_t address);
-    void (*common_write)(void *state, uint32_t address, uint16_t value);
-    uint16_t (*io_read)(void *state, uint32_t address);
-    void (*io_write)(void *state, uint32_t address, uint16_t value);
-};
-
-#define CISTPL_DEVICE          0x01    /* 5V Device Information Tuple */
-#define CISTPL_NO_LINK         0x14    /* No Link Tuple */
-#define CISTPL_VERS_1          0x15    /* Level 1 Version Tuple */
-#define CISTPL_JEDEC_C         0x18    /* JEDEC ID Tuple */
-#define CISTPL_JEDEC_A         0x19    /* JEDEC ID Tuple */
-#define CISTPL_CONFIG          0x1a    /* Configuration Tuple */
-#define CISTPL_CFTABLE_ENTRY   0x1b    /* 16-bit PCCard Configuration */
-#define CISTPL_DEVICE_OC       0x1c    /* Additional Device Information */
-#define CISTPL_DEVICE_OA       0x1d    /* Additional Device Information */
-#define CISTPL_DEVICE_GEO      0x1e    /* Additional Device Information */
-#define CISTPL_DEVICE_GEO_A    0x1f    /* Additional Device Information */
-#define CISTPL_MANFID          0x20    /* Manufacture ID Tuple */
-#define CISTPL_FUNCID          0x21    /* Function ID Tuple */
-#define CISTPL_FUNCE           0x22    /* Function Extension Tuple */
-#define CISTPL_END             0xff    /* Tuple End */
-#define CISTPL_ENDMARK         0xff
-
-/* dscm1xxxx.c */
-PCMCIACardState *dscm1xxxx_init(DriveInfo *bdrv);
-
-#endif
diff --git a/hw/pcnet-pci.c b/hw/pcnet-pci.c
deleted file mode 100644 (file)
index 61af57e..0000000
+++ /dev/null
@@ -1,376 +0,0 @@
-/*
- * QEMU AMD PC-Net II (Am79C970A) PCI emulation
- *
- * Copyright (c) 2004 Antony T Curtis
- *
- * 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.
- */
-
-/* This software was written to be compatible with the specification:
- * AMD Am79C970A PCnet-PCI II Ethernet Controller Data-Sheet
- * AMD Publication# 19436  Rev:E  Amendment/0  Issue Date: June 2000
- */
-
-#include "hw/pci/pci.h"
-#include "net/net.h"
-#include "hw/loader.h"
-#include "qemu/timer.h"
-#include "sysemu/dma.h"
-
-#include "hw/pcnet.h"
-
-//#define PCNET_DEBUG
-//#define PCNET_DEBUG_IO
-//#define PCNET_DEBUG_BCR
-//#define PCNET_DEBUG_CSR
-//#define PCNET_DEBUG_RMD
-//#define PCNET_DEBUG_TMD
-//#define PCNET_DEBUG_MATCH
-
-
-typedef struct {
-    PCIDevice pci_dev;
-    PCNetState state;
-    MemoryRegion io_bar;
-} PCIPCNetState;
-
-static void pcnet_aprom_writeb(void *opaque, uint32_t addr, uint32_t val)
-{
-    PCNetState *s = opaque;
-#ifdef PCNET_DEBUG
-    printf("pcnet_aprom_writeb addr=0x%08x val=0x%02x\n", addr, val);
-#endif
-    if (BCR_APROMWE(s)) {
-        s->prom[addr & 15] = val;
-    }
-}
-
-static uint32_t pcnet_aprom_readb(void *opaque, uint32_t addr)
-{
-    PCNetState *s = opaque;
-    uint32_t val = s->prom[addr & 15];
-#ifdef PCNET_DEBUG
-    printf("pcnet_aprom_readb addr=0x%08x val=0x%02x\n", addr, val);
-#endif
-    return val;
-}
-
-static uint64_t pcnet_ioport_read(void *opaque, hwaddr addr,
-                                  unsigned size)
-{
-    PCNetState *d = opaque;
-
-    if (addr < 0x10) {
-        if (!BCR_DWIO(d) && size == 1) {
-            return pcnet_aprom_readb(d, addr);
-        } else if (!BCR_DWIO(d) && (addr & 1) == 0 && size == 2) {
-            return pcnet_aprom_readb(d, addr) |
-                   (pcnet_aprom_readb(d, addr + 1) << 8);
-        } else if (BCR_DWIO(d) && (addr & 3) == 0 && size == 4) {
-            return pcnet_aprom_readb(d, addr) |
-                   (pcnet_aprom_readb(d, addr + 1) << 8) |
-                   (pcnet_aprom_readb(d, addr + 2) << 16) |
-                   (pcnet_aprom_readb(d, addr + 3) << 24);
-        }
-    } else {
-        if (size == 2) {
-            return pcnet_ioport_readw(d, addr);
-        } else if (size == 4) {
-            return pcnet_ioport_readl(d, addr);
-        }
-    }
-    return ((uint64_t)1 << (size * 8)) - 1;
-}
-
-static void pcnet_ioport_write(void *opaque, hwaddr addr,
-                               uint64_t data, unsigned size)
-{
-    PCNetState *d = opaque;
-
-    if (addr < 0x10) {
-        if (!BCR_DWIO(d) && size == 1) {
-            pcnet_aprom_writeb(d, addr, data);
-        } else if (!BCR_DWIO(d) && (addr & 1) == 0 && size == 2) {
-            pcnet_aprom_writeb(d, addr, data & 0xff);
-            pcnet_aprom_writeb(d, addr + 1, data >> 8);
-        } else if (BCR_DWIO(d) && (addr & 3) == 0 && size == 4) {
-            pcnet_aprom_writeb(d, addr, data & 0xff);
-            pcnet_aprom_writeb(d, addr + 1, (data >> 8) & 0xff);
-            pcnet_aprom_writeb(d, addr + 2, (data >> 16) & 0xff);
-            pcnet_aprom_writeb(d, addr + 3, data >> 24);
-        }
-    } else {
-        if (size == 2) {
-            pcnet_ioport_writew(d, addr, data);
-        } else if (size == 4) {
-            pcnet_ioport_writel(d, addr, data);
-        }
-    }
-}
-
-static const MemoryRegionOps pcnet_io_ops = {
-    .read = pcnet_ioport_read,
-    .write = pcnet_ioport_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void pcnet_mmio_writeb(void *opaque, hwaddr addr, uint32_t val)
-{
-    PCNetState *d = opaque;
-#ifdef PCNET_DEBUG_IO
-    printf("pcnet_mmio_writeb addr=0x" TARGET_FMT_plx" val=0x%02x\n", addr,
-           val);
-#endif
-    if (!(addr & 0x10))
-        pcnet_aprom_writeb(d, addr & 0x0f, val);
-}
-
-static uint32_t pcnet_mmio_readb(void *opaque, hwaddr addr)
-{
-    PCNetState *d = opaque;
-    uint32_t val = -1;
-    if (!(addr & 0x10))
-        val = pcnet_aprom_readb(d, addr & 0x0f);
-#ifdef PCNET_DEBUG_IO
-    printf("pcnet_mmio_readb addr=0x" TARGET_FMT_plx " val=0x%02x\n", addr,
-           val & 0xff);
-#endif
-    return val;
-}
-
-static void pcnet_mmio_writew(void *opaque, hwaddr addr, uint32_t val)
-{
-    PCNetState *d = opaque;
-#ifdef PCNET_DEBUG_IO
-    printf("pcnet_mmio_writew addr=0x" TARGET_FMT_plx " val=0x%04x\n", addr,
-           val);
-#endif
-    if (addr & 0x10)
-        pcnet_ioport_writew(d, addr & 0x0f, val);
-    else {
-        addr &= 0x0f;
-        pcnet_aprom_writeb(d, addr, val & 0xff);
-        pcnet_aprom_writeb(d, addr+1, (val & 0xff00) >> 8);
-    }
-}
-
-static uint32_t pcnet_mmio_readw(void *opaque, hwaddr addr)
-{
-    PCNetState *d = opaque;
-    uint32_t val = -1;
-    if (addr & 0x10)
-        val = pcnet_ioport_readw(d, addr & 0x0f);
-    else {
-        addr &= 0x0f;
-        val = pcnet_aprom_readb(d, addr+1);
-        val <<= 8;
-        val |= pcnet_aprom_readb(d, addr);
-    }
-#ifdef PCNET_DEBUG_IO
-    printf("pcnet_mmio_readw addr=0x" TARGET_FMT_plx" val = 0x%04x\n", addr,
-           val & 0xffff);
-#endif
-    return val;
-}
-
-static void pcnet_mmio_writel(void *opaque, hwaddr addr, uint32_t val)
-{
-    PCNetState *d = opaque;
-#ifdef PCNET_DEBUG_IO
-    printf("pcnet_mmio_writel addr=0x" TARGET_FMT_plx" val=0x%08x\n", addr,
-           val);
-#endif
-    if (addr & 0x10)
-        pcnet_ioport_writel(d, addr & 0x0f, val);
-    else {
-        addr &= 0x0f;
-        pcnet_aprom_writeb(d, addr, val & 0xff);
-        pcnet_aprom_writeb(d, addr+1, (val & 0xff00) >> 8);
-        pcnet_aprom_writeb(d, addr+2, (val & 0xff0000) >> 16);
-        pcnet_aprom_writeb(d, addr+3, (val & 0xff000000) >> 24);
-    }
-}
-
-static uint32_t pcnet_mmio_readl(void *opaque, hwaddr addr)
-{
-    PCNetState *d = opaque;
-    uint32_t val;
-    if (addr & 0x10)
-        val = pcnet_ioport_readl(d, addr & 0x0f);
-    else {
-        addr &= 0x0f;
-        val = pcnet_aprom_readb(d, addr+3);
-        val <<= 8;
-        val |= pcnet_aprom_readb(d, addr+2);
-        val <<= 8;
-        val |= pcnet_aprom_readb(d, addr+1);
-        val <<= 8;
-        val |= pcnet_aprom_readb(d, addr);
-    }
-#ifdef PCNET_DEBUG_IO
-    printf("pcnet_mmio_readl addr=0x" TARGET_FMT_plx " val=0x%08x\n", addr,
-           val);
-#endif
-    return val;
-}
-
-static const VMStateDescription vmstate_pci_pcnet = {
-    .name = "pcnet",
-    .version_id = 3,
-    .minimum_version_id = 2,
-    .minimum_version_id_old = 2,
-    .fields      = (VMStateField []) {
-        VMSTATE_PCI_DEVICE(pci_dev, PCIPCNetState),
-        VMSTATE_STRUCT(state, PCIPCNetState, 0, vmstate_pcnet, PCNetState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-/* PCI interface */
-
-static const MemoryRegionOps pcnet_mmio_ops = {
-    .old_mmio = {
-        .read = { pcnet_mmio_readb, pcnet_mmio_readw, pcnet_mmio_readl },
-        .write = { pcnet_mmio_writeb, pcnet_mmio_writew, pcnet_mmio_writel },
-    },
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void pci_physical_memory_write(void *dma_opaque, hwaddr addr,
-                                      uint8_t *buf, int len, int do_bswap)
-{
-    pci_dma_write(dma_opaque, addr, buf, len);
-}
-
-static void pci_physical_memory_read(void *dma_opaque, hwaddr addr,
-                                     uint8_t *buf, int len, int do_bswap)
-{
-    pci_dma_read(dma_opaque, addr, buf, len);
-}
-
-static void pci_pcnet_cleanup(NetClientState *nc)
-{
-    PCNetState *d = qemu_get_nic_opaque(nc);
-
-    pcnet_common_cleanup(d);
-}
-
-static void pci_pcnet_uninit(PCIDevice *dev)
-{
-    PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev, dev);
-
-    memory_region_destroy(&d->state.mmio);
-    memory_region_destroy(&d->io_bar);
-    qemu_del_timer(d->state.poll_timer);
-    qemu_free_timer(d->state.poll_timer);
-    qemu_del_nic(d->state.nic);
-}
-
-static NetClientInfo net_pci_pcnet_info = {
-    .type = NET_CLIENT_OPTIONS_KIND_NIC,
-    .size = sizeof(NICState),
-    .can_receive = pcnet_can_receive,
-    .receive = pcnet_receive,
-    .link_status_changed = pcnet_set_link_status,
-    .cleanup = pci_pcnet_cleanup,
-};
-
-static int pci_pcnet_init(PCIDevice *pci_dev)
-{
-    PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev, pci_dev);
-    PCNetState *s = &d->state;
-    uint8_t *pci_conf;
-
-#if 0
-    printf("sizeof(RMD)=%d, sizeof(TMD)=%d\n",
-        sizeof(struct pcnet_RMD), sizeof(struct pcnet_TMD));
-#endif
-
-    pci_conf = pci_dev->config;
-
-    pci_set_word(pci_conf + PCI_STATUS,
-                 PCI_STATUS_FAST_BACK | PCI_STATUS_DEVSEL_MEDIUM);
-
-    pci_set_word(pci_conf + PCI_SUBSYSTEM_VENDOR_ID, 0x0);
-    pci_set_word(pci_conf + PCI_SUBSYSTEM_ID, 0x0);
-
-    pci_conf[PCI_INTERRUPT_PIN] = 1; /* interrupt pin A */
-    pci_conf[PCI_MIN_GNT] = 0x06;
-    pci_conf[PCI_MAX_LAT] = 0xff;
-
-    /* Handler for memory-mapped I/O */
-    memory_region_init_io(&d->state.mmio, &pcnet_mmio_ops, s, "pcnet-mmio",
-                          PCNET_PNPMMIO_SIZE);
-
-    memory_region_init_io(&d->io_bar, &pcnet_io_ops, s, "pcnet-io",
-                          PCNET_IOPORT_SIZE);
-    pci_register_bar(pci_dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &d->io_bar);
-
-    pci_register_bar(pci_dev, 1, 0, &s->mmio);
-
-    s->irq = pci_dev->irq[0];
-    s->phys_mem_read = pci_physical_memory_read;
-    s->phys_mem_write = pci_physical_memory_write;
-    s->dma_opaque = pci_dev;
-
-    return pcnet_common_init(&pci_dev->qdev, s, &net_pci_pcnet_info);
-}
-
-static void pci_reset(DeviceState *dev)
-{
-    PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev.qdev, dev);
-
-    pcnet_h_reset(&d->state);
-}
-
-static Property pcnet_properties[] = {
-    DEFINE_NIC_PROPERTIES(PCIPCNetState, state.conf),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void pcnet_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
-    k->init = pci_pcnet_init;
-    k->exit = pci_pcnet_uninit;
-    k->romfile = "efi-pcnet.rom",
-    k->vendor_id = PCI_VENDOR_ID_AMD;
-    k->device_id = PCI_DEVICE_ID_AMD_LANCE;
-    k->revision = 0x10;
-    k->class_id = PCI_CLASS_NETWORK_ETHERNET;
-    dc->reset = pci_reset;
-    dc->vmsd = &vmstate_pci_pcnet;
-    dc->props = pcnet_properties;
-}
-
-static const TypeInfo pcnet_info = {
-    .name          = "pcnet",
-    .parent        = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(PCIPCNetState),
-    .class_init    = pcnet_class_init,
-};
-
-static void pci_pcnet_register_types(void)
-{
-    type_register_static(&pcnet_info);
-}
-
-type_init(pci_pcnet_register_types)
diff --git a/hw/pcnet.c b/hw/pcnet.c
deleted file mode 100644 (file)
index b0b462b..0000000
+++ /dev/null
@@ -1,1768 +0,0 @@
-/*
- * QEMU AMD PC-Net II (Am79C970A) emulation
- *
- * Copyright (c) 2004 Antony T Curtis
- *
- * 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.
- */
-
-/* This software was written to be compatible with the specification:
- * AMD Am79C970A PCnet-PCI II Ethernet Controller Data-Sheet
- * AMD Publication# 19436  Rev:E  Amendment/0  Issue Date: June 2000
- */
-
-/*
- * On Sparc32, this is the Lance (Am7990) part of chip STP2000 (Master I/O), also
- * produced as NCR89C100. See
- * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C100.txt
- * and
- * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR92C990.txt
- */
-
-#include "hw/qdev.h"
-#include "net/net.h"
-#include "qemu/timer.h"
-#include "qemu/sockets.h"
-#include "sysemu/sysemu.h"
-
-#include "hw/pcnet.h"
-
-//#define PCNET_DEBUG
-//#define PCNET_DEBUG_IO
-//#define PCNET_DEBUG_BCR
-//#define PCNET_DEBUG_CSR
-//#define PCNET_DEBUG_RMD
-//#define PCNET_DEBUG_TMD
-//#define PCNET_DEBUG_MATCH
-
-
-struct qemu_ether_header {
-    uint8_t ether_dhost[6];
-    uint8_t ether_shost[6];
-    uint16_t ether_type;
-};
-
-#define CSR_INIT(S)      !!(((S)->csr[0])&0x0001)
-#define CSR_STRT(S)      !!(((S)->csr[0])&0x0002)
-#define CSR_STOP(S)      !!(((S)->csr[0])&0x0004)
-#define CSR_TDMD(S)      !!(((S)->csr[0])&0x0008)
-#define CSR_TXON(S)      !!(((S)->csr[0])&0x0010)
-#define CSR_RXON(S)      !!(((S)->csr[0])&0x0020)
-#define CSR_INEA(S)      !!(((S)->csr[0])&0x0040)
-#define CSR_BSWP(S)      !!(((S)->csr[3])&0x0004)
-#define CSR_LAPPEN(S)    !!(((S)->csr[3])&0x0020)
-#define CSR_DXSUFLO(S)   !!(((S)->csr[3])&0x0040)
-#define CSR_ASTRP_RCV(S) !!(((S)->csr[4])&0x0800)
-#define CSR_DPOLL(S)     !!(((S)->csr[4])&0x1000)
-#define CSR_SPND(S)      !!(((S)->csr[5])&0x0001)
-#define CSR_LTINTEN(S)   !!(((S)->csr[5])&0x4000)
-#define CSR_TOKINTD(S)   !!(((S)->csr[5])&0x8000)
-#define CSR_DRX(S)       !!(((S)->csr[15])&0x0001)
-#define CSR_DTX(S)       !!(((S)->csr[15])&0x0002)
-#define CSR_LOOP(S)      !!(((S)->csr[15])&0x0004)
-#define CSR_DXMTFCS(S)   !!(((S)->csr[15])&0x0008)
-#define CSR_INTL(S)      !!(((S)->csr[15])&0x0040)
-#define CSR_DRCVPA(S)    !!(((S)->csr[15])&0x2000)
-#define CSR_DRCVBC(S)    !!(((S)->csr[15])&0x4000)
-#define CSR_PROM(S)      !!(((S)->csr[15])&0x8000)
-
-#define CSR_CRBC(S)      ((S)->csr[40])
-#define CSR_CRST(S)      ((S)->csr[41])
-#define CSR_CXBC(S)      ((S)->csr[42])
-#define CSR_CXST(S)      ((S)->csr[43])
-#define CSR_NRBC(S)      ((S)->csr[44])
-#define CSR_NRST(S)      ((S)->csr[45])
-#define CSR_POLL(S)      ((S)->csr[46])
-#define CSR_PINT(S)      ((S)->csr[47])
-#define CSR_RCVRC(S)     ((S)->csr[72])
-#define CSR_XMTRC(S)     ((S)->csr[74])
-#define CSR_RCVRL(S)     ((S)->csr[76])
-#define CSR_XMTRL(S)     ((S)->csr[78])
-#define CSR_MISSC(S)     ((S)->csr[112])
-
-#define CSR_IADR(S)      ((S)->csr[ 1] | ((uint32_t)(S)->csr[ 2] << 16))
-#define CSR_CRBA(S)      ((S)->csr[18] | ((uint32_t)(S)->csr[19] << 16))
-#define CSR_CXBA(S)      ((S)->csr[20] | ((uint32_t)(S)->csr[21] << 16))
-#define CSR_NRBA(S)      ((S)->csr[22] | ((uint32_t)(S)->csr[23] << 16))
-#define CSR_BADR(S)      ((S)->csr[24] | ((uint32_t)(S)->csr[25] << 16))
-#define CSR_NRDA(S)      ((S)->csr[26] | ((uint32_t)(S)->csr[27] << 16))
-#define CSR_CRDA(S)      ((S)->csr[28] | ((uint32_t)(S)->csr[29] << 16))
-#define CSR_BADX(S)      ((S)->csr[30] | ((uint32_t)(S)->csr[31] << 16))
-#define CSR_NXDA(S)      ((S)->csr[32] | ((uint32_t)(S)->csr[33] << 16))
-#define CSR_CXDA(S)      ((S)->csr[34] | ((uint32_t)(S)->csr[35] << 16))
-#define CSR_NNRD(S)      ((S)->csr[36] | ((uint32_t)(S)->csr[37] << 16))
-#define CSR_NNXD(S)      ((S)->csr[38] | ((uint32_t)(S)->csr[39] << 16))
-#define CSR_PXDA(S)      ((S)->csr[60] | ((uint32_t)(S)->csr[61] << 16))
-#define CSR_NXBA(S)      ((S)->csr[64] | ((uint32_t)(S)->csr[65] << 16))
-
-#define PHYSADDR(S,A) \
-  (BCR_SSIZE32(S) ? (A) : (A) | ((0xff00 & (uint32_t)(S)->csr[2])<<16))
-
-struct pcnet_initblk16 {
-    uint16_t mode;
-    uint16_t padr[3];
-    uint16_t ladrf[4];
-    uint32_t rdra;
-    uint32_t tdra;
-};
-
-struct pcnet_initblk32 {
-    uint16_t mode;
-    uint8_t rlen;
-    uint8_t tlen;
-    uint16_t padr[3];
-    uint16_t _res;
-    uint16_t ladrf[4];
-    uint32_t rdra;
-    uint32_t tdra;
-};
-
-struct pcnet_TMD {
-    uint32_t tbadr;
-    int16_t length;
-    int16_t status;
-    uint32_t misc;
-    uint32_t res;
-};
-
-#define TMDL_BCNT_MASK  0x0fff
-#define TMDL_BCNT_SH    0
-#define TMDL_ONES_MASK  0xf000
-#define TMDL_ONES_SH    12
-
-#define TMDS_BPE_MASK   0x0080
-#define TMDS_BPE_SH     7
-#define TMDS_ENP_MASK   0x0100
-#define TMDS_ENP_SH     8
-#define TMDS_STP_MASK   0x0200
-#define TMDS_STP_SH     9
-#define TMDS_DEF_MASK   0x0400
-#define TMDS_DEF_SH     10
-#define TMDS_ONE_MASK   0x0800
-#define TMDS_ONE_SH     11
-#define TMDS_LTINT_MASK 0x1000
-#define TMDS_LTINT_SH   12
-#define TMDS_NOFCS_MASK 0x2000
-#define TMDS_NOFCS_SH   13
-#define TMDS_ADDFCS_MASK TMDS_NOFCS_MASK
-#define TMDS_ADDFCS_SH  TMDS_NOFCS_SH
-#define TMDS_ERR_MASK   0x4000
-#define TMDS_ERR_SH     14
-#define TMDS_OWN_MASK   0x8000
-#define TMDS_OWN_SH     15
-
-#define TMDM_TRC_MASK   0x0000000f
-#define TMDM_TRC_SH     0
-#define TMDM_TDR_MASK   0x03ff0000
-#define TMDM_TDR_SH     16
-#define TMDM_RTRY_MASK  0x04000000
-#define TMDM_RTRY_SH    26
-#define TMDM_LCAR_MASK  0x08000000
-#define TMDM_LCAR_SH    27
-#define TMDM_LCOL_MASK  0x10000000
-#define TMDM_LCOL_SH    28
-#define TMDM_EXDEF_MASK 0x20000000
-#define TMDM_EXDEF_SH   29
-#define TMDM_UFLO_MASK  0x40000000
-#define TMDM_UFLO_SH    30
-#define TMDM_BUFF_MASK  0x80000000
-#define TMDM_BUFF_SH    31
-
-struct pcnet_RMD {
-    uint32_t rbadr;
-    int16_t buf_length;
-    int16_t status;
-    uint32_t msg_length;
-    uint32_t res;
-};
-
-#define RMDL_BCNT_MASK  0x0fff
-#define RMDL_BCNT_SH    0
-#define RMDL_ONES_MASK  0xf000
-#define RMDL_ONES_SH    12
-
-#define RMDS_BAM_MASK   0x0010
-#define RMDS_BAM_SH     4
-#define RMDS_LFAM_MASK  0x0020
-#define RMDS_LFAM_SH    5
-#define RMDS_PAM_MASK   0x0040
-#define RMDS_PAM_SH     6
-#define RMDS_BPE_MASK   0x0080
-#define RMDS_BPE_SH     7
-#define RMDS_ENP_MASK   0x0100
-#define RMDS_ENP_SH     8
-#define RMDS_STP_MASK   0x0200
-#define RMDS_STP_SH     9
-#define RMDS_BUFF_MASK  0x0400
-#define RMDS_BUFF_SH    10
-#define RMDS_CRC_MASK   0x0800
-#define RMDS_CRC_SH     11
-#define RMDS_OFLO_MASK  0x1000
-#define RMDS_OFLO_SH    12
-#define RMDS_FRAM_MASK  0x2000
-#define RMDS_FRAM_SH    13
-#define RMDS_ERR_MASK   0x4000
-#define RMDS_ERR_SH     14
-#define RMDS_OWN_MASK   0x8000
-#define RMDS_OWN_SH     15
-
-#define RMDM_MCNT_MASK  0x00000fff
-#define RMDM_MCNT_SH    0
-#define RMDM_ZEROS_MASK 0x0000f000
-#define RMDM_ZEROS_SH   12
-#define RMDM_RPC_MASK   0x00ff0000
-#define RMDM_RPC_SH     16
-#define RMDM_RCC_MASK   0xff000000
-#define RMDM_RCC_SH     24
-
-#define SET_FIELD(regp, name, field, value)             \
-  (*(regp) = (*(regp) & ~(name ## _ ## field ## _MASK)) \
-             | ((value) << name ## _ ## field ## _SH))
-
-#define GET_FIELD(reg, name, field)                     \
-  (((reg) & name ## _ ## field ## _MASK) >> name ## _ ## field ## _SH)
-
-#define PRINT_TMD(T) printf(                            \
-        "TMD0 : TBADR=0x%08x\n"                         \
-        "TMD1 : OWN=%d, ERR=%d, FCS=%d, LTI=%d, "       \
-        "ONE=%d, DEF=%d, STP=%d, ENP=%d,\n"             \
-        "       BPE=%d, BCNT=%d\n"                      \
-        "TMD2 : BUF=%d, UFL=%d, EXD=%d, LCO=%d, "       \
-        "LCA=%d, RTR=%d,\n"                             \
-        "       TDR=%d, TRC=%d\n",                      \
-        (T)->tbadr,                                     \
-        GET_FIELD((T)->status, TMDS, OWN),              \
-        GET_FIELD((T)->status, TMDS, ERR),              \
-        GET_FIELD((T)->status, TMDS, NOFCS),            \
-        GET_FIELD((T)->status, TMDS, LTINT),            \
-        GET_FIELD((T)->status, TMDS, ONE),              \
-        GET_FIELD((T)->status, TMDS, DEF),              \
-        GET_FIELD((T)->status, TMDS, STP),              \
-        GET_FIELD((T)->status, TMDS, ENP),              \
-        GET_FIELD((T)->status, TMDS, BPE),              \
-        4096-GET_FIELD((T)->length, TMDL, BCNT),        \
-        GET_FIELD((T)->misc, TMDM, BUFF),               \
-        GET_FIELD((T)->misc, TMDM, UFLO),               \
-        GET_FIELD((T)->misc, TMDM, EXDEF),              \
-        GET_FIELD((T)->misc, TMDM, LCOL),               \
-        GET_FIELD((T)->misc, TMDM, LCAR),               \
-        GET_FIELD((T)->misc, TMDM, RTRY),               \
-        GET_FIELD((T)->misc, TMDM, TDR),                \
-        GET_FIELD((T)->misc, TMDM, TRC))
-
-#define PRINT_RMD(R) printf(                            \
-        "RMD0 : RBADR=0x%08x\n"                         \
-        "RMD1 : OWN=%d, ERR=%d, FRAM=%d, OFLO=%d, "     \
-        "CRC=%d, BUFF=%d, STP=%d, ENP=%d,\n       "     \
-        "BPE=%d, PAM=%d, LAFM=%d, BAM=%d, ONES=%d, BCNT=%d\n" \
-        "RMD2 : RCC=%d, RPC=%d, MCNT=%d, ZEROS=%d\n",   \
-        (R)->rbadr,                                     \
-        GET_FIELD((R)->status, RMDS, OWN),              \
-        GET_FIELD((R)->status, RMDS, ERR),              \
-        GET_FIELD((R)->status, RMDS, FRAM),             \
-        GET_FIELD((R)->status, RMDS, OFLO),             \
-        GET_FIELD((R)->status, RMDS, CRC),              \
-        GET_FIELD((R)->status, RMDS, BUFF),             \
-        GET_FIELD((R)->status, RMDS, STP),              \
-        GET_FIELD((R)->status, RMDS, ENP),              \
-        GET_FIELD((R)->status, RMDS, BPE),              \
-        GET_FIELD((R)->status, RMDS, PAM),              \
-        GET_FIELD((R)->status, RMDS, LFAM),             \
-        GET_FIELD((R)->status, RMDS, BAM),              \
-        GET_FIELD((R)->buf_length, RMDL, ONES),         \
-        4096-GET_FIELD((R)->buf_length, RMDL, BCNT),    \
-        GET_FIELD((R)->msg_length, RMDM, RCC),          \
-        GET_FIELD((R)->msg_length, RMDM, RPC),          \
-        GET_FIELD((R)->msg_length, RMDM, MCNT),         \
-        GET_FIELD((R)->msg_length, RMDM, ZEROS))
-
-static inline void pcnet_tmd_load(PCNetState *s, struct pcnet_TMD *tmd,
-                                  hwaddr addr)
-{
-    if (!BCR_SSIZE32(s)) {
-        struct {
-            uint32_t tbadr;
-            int16_t length;
-            int16_t status;
-       } xda;
-        s->phys_mem_read(s->dma_opaque, addr, (void *)&xda, sizeof(xda), 0);
-        tmd->tbadr = le32_to_cpu(xda.tbadr) & 0xffffff;
-        tmd->length = le16_to_cpu(xda.length);
-        tmd->status = (le32_to_cpu(xda.tbadr) >> 16) & 0xff00;
-        tmd->misc = le16_to_cpu(xda.status) << 16;
-        tmd->res = 0;
-    } else {
-        s->phys_mem_read(s->dma_opaque, addr, (void *)tmd, sizeof(*tmd), 0);
-        le32_to_cpus(&tmd->tbadr);
-        le16_to_cpus((uint16_t *)&tmd->length);
-        le16_to_cpus((uint16_t *)&tmd->status);
-        le32_to_cpus(&tmd->misc);
-        le32_to_cpus(&tmd->res);
-        if (BCR_SWSTYLE(s) == 3) {
-            uint32_t tmp = tmd->tbadr;
-            tmd->tbadr = tmd->misc;
-            tmd->misc = tmp;
-        }
-    }
-}
-
-static inline void pcnet_tmd_store(PCNetState *s, const struct pcnet_TMD *tmd,
-                                   hwaddr addr)
-{
-    if (!BCR_SSIZE32(s)) {
-        struct {
-            uint32_t tbadr;
-            int16_t length;
-            int16_t status;
-        } xda;
-        xda.tbadr = cpu_to_le32((tmd->tbadr & 0xffffff) |
-                                ((tmd->status & 0xff00) << 16));
-        xda.length = cpu_to_le16(tmd->length);
-        xda.status = cpu_to_le16(tmd->misc >> 16);
-        s->phys_mem_write(s->dma_opaque, addr, (void *)&xda, sizeof(xda), 0);
-    } else {
-        struct {
-            uint32_t tbadr;
-            int16_t length;
-            int16_t status;
-            uint32_t misc;
-            uint32_t res;
-        } xda;
-        xda.tbadr = cpu_to_le32(tmd->tbadr);
-        xda.length = cpu_to_le16(tmd->length);
-        xda.status = cpu_to_le16(tmd->status);
-        xda.misc = cpu_to_le32(tmd->misc);
-        xda.res = cpu_to_le32(tmd->res);
-        if (BCR_SWSTYLE(s) == 3) {
-            uint32_t tmp = xda.tbadr;
-            xda.tbadr = xda.misc;
-            xda.misc = tmp;
-        }
-        s->phys_mem_write(s->dma_opaque, addr, (void *)&xda, sizeof(xda), 0);
-    }
-}
-
-static inline void pcnet_rmd_load(PCNetState *s, struct pcnet_RMD *rmd,
-                                  hwaddr addr)
-{
-    if (!BCR_SSIZE32(s)) {
-        struct {
-            uint32_t rbadr;
-            int16_t buf_length;
-            int16_t msg_length;
-       } rda;
-        s->phys_mem_read(s->dma_opaque, addr, (void *)&rda, sizeof(rda), 0);
-        rmd->rbadr = le32_to_cpu(rda.rbadr) & 0xffffff;
-        rmd->buf_length = le16_to_cpu(rda.buf_length);
-        rmd->status = (le32_to_cpu(rda.rbadr) >> 16) & 0xff00;
-        rmd->msg_length = le16_to_cpu(rda.msg_length);
-        rmd->res = 0;
-    } else {
-        s->phys_mem_read(s->dma_opaque, addr, (void *)rmd, sizeof(*rmd), 0);
-        le32_to_cpus(&rmd->rbadr);
-        le16_to_cpus((uint16_t *)&rmd->buf_length);
-        le16_to_cpus((uint16_t *)&rmd->status);
-        le32_to_cpus(&rmd->msg_length);
-        le32_to_cpus(&rmd->res);
-        if (BCR_SWSTYLE(s) == 3) {
-            uint32_t tmp = rmd->rbadr;
-            rmd->rbadr = rmd->msg_length;
-            rmd->msg_length = tmp;
-        }
-    }
-}
-
-static inline void pcnet_rmd_store(PCNetState *s, struct pcnet_RMD *rmd,
-                                   hwaddr addr)
-{
-    if (!BCR_SSIZE32(s)) {
-        struct {
-            uint32_t rbadr;
-            int16_t buf_length;
-            int16_t msg_length;
-        } rda;
-        rda.rbadr = cpu_to_le32((rmd->rbadr & 0xffffff) |
-                                ((rmd->status & 0xff00) << 16));
-        rda.buf_length = cpu_to_le16(rmd->buf_length);
-        rda.msg_length = cpu_to_le16(rmd->msg_length);
-        s->phys_mem_write(s->dma_opaque, addr, (void *)&rda, sizeof(rda), 0);
-    } else {
-        struct {
-            uint32_t rbadr;
-            int16_t buf_length;
-            int16_t status;
-            uint32_t msg_length;
-            uint32_t res;
-        } rda;
-        rda.rbadr = cpu_to_le32(rmd->rbadr);
-        rda.buf_length = cpu_to_le16(rmd->buf_length);
-        rda.status = cpu_to_le16(rmd->status);
-        rda.msg_length = cpu_to_le32(rmd->msg_length);
-        rda.res = cpu_to_le32(rmd->res);
-        if (BCR_SWSTYLE(s) == 3) {
-            uint32_t tmp = rda.rbadr;
-            rda.rbadr = rda.msg_length;
-            rda.msg_length = tmp;
-        }
-        s->phys_mem_write(s->dma_opaque, addr, (void *)&rda, sizeof(rda), 0);
-    }
-}
-
-
-#define TMDLOAD(TMD,ADDR) pcnet_tmd_load(s,TMD,ADDR)
-
-#define TMDSTORE(TMD,ADDR) pcnet_tmd_store(s,TMD,ADDR)
-
-#define RMDLOAD(RMD,ADDR) pcnet_rmd_load(s,RMD,ADDR)
-
-#define RMDSTORE(RMD,ADDR) pcnet_rmd_store(s,RMD,ADDR)
-
-#if 1
-
-#define CHECK_RMD(ADDR,RES) do {                \
-    struct pcnet_RMD rmd;                       \
-    RMDLOAD(&rmd,(ADDR));                       \
-    (RES) |= (GET_FIELD(rmd.buf_length, RMDL, ONES) != 15) \
-          || (GET_FIELD(rmd.msg_length, RMDM, ZEROS) != 0); \
-} while (0)
-
-#define CHECK_TMD(ADDR,RES) do {                \
-    struct pcnet_TMD tmd;                       \
-    TMDLOAD(&tmd,(ADDR));                       \
-    (RES) |= (GET_FIELD(tmd.length, TMDL, ONES) != 15); \
-} while (0)
-
-#else
-
-#define CHECK_RMD(ADDR,RES) do {                \
-    switch (BCR_SWSTYLE(s)) {                   \
-    case 0x00:                                  \
-        do {                                    \
-            uint16_t rda[4];                    \
-            s->phys_mem_read(s->dma_opaque, (ADDR), \
-                (void *)&rda[0], sizeof(rda), 0); \
-            (RES) |= (rda[2] & 0xf000)!=0xf000; \
-            (RES) |= (rda[3] & 0xf000)!=0x0000; \
-        } while (0);                            \
-        break;                                  \
-    case 0x01:                                  \
-    case 0x02:                                  \
-        do {                                    \
-            uint32_t rda[4];                    \
-            s->phys_mem_read(s->dma_opaque, (ADDR), \
-                (void *)&rda[0], sizeof(rda), 0); \
-            (RES) |= (rda[1] & 0x0000f000L)!=0x0000f000L; \
-            (RES) |= (rda[2] & 0x0000f000L)!=0x00000000L; \
-        } while (0);                            \
-        break;                                  \
-    case 0x03:                                  \
-        do {                                    \
-            uint32_t rda[4];                    \
-            s->phys_mem_read(s->dma_opaque, (ADDR), \
-                (void *)&rda[0], sizeof(rda), 0); \
-            (RES) |= (rda[0] & 0x0000f000L)!=0x00000000L; \
-            (RES) |= (rda[1] & 0x0000f000L)!=0x0000f000L; \
-        } while (0);                            \
-        break;                                  \
-    }                                           \
-} while (0)
-
-#define CHECK_TMD(ADDR,RES) do {                \
-    switch (BCR_SWSTYLE(s)) {                   \
-    case 0x00:                                  \
-        do {                                    \
-            uint16_t xda[4];                    \
-            s->phys_mem_read(s->dma_opaque, (ADDR), \
-                (void *)&xda[0], sizeof(xda), 0); \
-            (RES) |= (xda[2] & 0xf000)!=0xf000; \
-        } while (0);                            \
-        break;                                  \
-    case 0x01:                                  \
-    case 0x02:                                  \
-    case 0x03:                                  \
-        do {                                    \
-            uint32_t xda[4];                    \
-            s->phys_mem_read(s->dma_opaque, (ADDR), \
-                (void *)&xda[0], sizeof(xda), 0); \
-            (RES) |= (xda[1] & 0x0000f000L)!=0x0000f000L; \
-        } while (0);                            \
-        break;                                  \
-    }                                           \
-} while (0)
-
-#endif
-
-#define PRINT_PKTHDR(BUF) do {                  \
-    struct qemu_ether_header *hdr = (void *)(BUF); \
-    printf("packet dhost=%02x:%02x:%02x:%02x:%02x:%02x, " \
-           "shost=%02x:%02x:%02x:%02x:%02x:%02x, " \
-           "type=0x%04x\n",                     \
-           hdr->ether_dhost[0],hdr->ether_dhost[1],hdr->ether_dhost[2], \
-           hdr->ether_dhost[3],hdr->ether_dhost[4],hdr->ether_dhost[5], \
-           hdr->ether_shost[0],hdr->ether_shost[1],hdr->ether_shost[2], \
-           hdr->ether_shost[3],hdr->ether_shost[4],hdr->ether_shost[5], \
-           be16_to_cpu(hdr->ether_type));       \
-} while (0)
-
-#define MULTICAST_FILTER_LEN 8
-
-static inline uint32_t lnc_mchash(const uint8_t *ether_addr)
-{
-#define LNC_POLYNOMIAL          0xEDB88320UL
-    uint32_t crc = 0xFFFFFFFF;
-    int idx, bit;
-    uint8_t data;
-
-    for (idx = 0; idx < 6; idx++) {
-        for (data = *ether_addr++, bit = 0; bit < MULTICAST_FILTER_LEN; bit++) {
-            crc = (crc >> 1) ^ (((crc ^ data) & 1) ? LNC_POLYNOMIAL : 0);
-            data >>= 1;
-        }
-    }
-    return crc;
-#undef LNC_POLYNOMIAL
-}
-
-#define CRC(crc, ch)    (crc = (crc >> 8) ^ crctab[(crc ^ (ch)) & 0xff])
-
-/* generated using the AUTODIN II polynomial
- *     x^32 + x^26 + x^23 + x^22 + x^16 +
- *     x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x^1 + 1
- */
-static const uint32_t crctab[256] = {
-       0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
-       0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
-       0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
-       0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
-       0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
-       0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
-       0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
-       0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
-       0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
-       0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
-       0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
-       0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
-       0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
-       0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
-       0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
-       0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
-       0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
-       0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
-       0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
-       0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
-       0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
-       0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
-       0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
-       0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
-       0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
-       0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
-       0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
-       0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
-       0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
-       0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
-       0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
-       0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
-       0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
-       0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
-       0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
-       0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
-       0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
-       0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
-       0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
-       0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
-       0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
-       0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
-       0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
-       0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
-       0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
-       0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
-       0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
-       0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
-       0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
-       0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
-       0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
-       0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
-       0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
-       0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
-       0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
-       0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
-       0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
-       0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
-       0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
-       0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
-       0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
-       0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
-       0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
-       0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
-};
-
-static inline int padr_match(PCNetState *s, const uint8_t *buf, int size)
-{
-    struct qemu_ether_header *hdr = (void *)buf;
-    uint8_t padr[6] = {
-        s->csr[12] & 0xff, s->csr[12] >> 8,
-        s->csr[13] & 0xff, s->csr[13] >> 8,
-        s->csr[14] & 0xff, s->csr[14] >> 8
-    };
-    int result = (!CSR_DRCVPA(s)) && !memcmp(hdr->ether_dhost, padr, 6);
-#ifdef PCNET_DEBUG_MATCH
-    printf("packet dhost=%02x:%02x:%02x:%02x:%02x:%02x, "
-           "padr=%02x:%02x:%02x:%02x:%02x:%02x\n",
-           hdr->ether_dhost[0],hdr->ether_dhost[1],hdr->ether_dhost[2],
-           hdr->ether_dhost[3],hdr->ether_dhost[4],hdr->ether_dhost[5],
-           padr[0],padr[1],padr[2],padr[3],padr[4],padr[5]);
-    printf("padr_match result=%d\n", result);
-#endif
-    return result;
-}
-
-static inline int padr_bcast(PCNetState *s, const uint8_t *buf, int size)
-{
-    static const uint8_t BCAST[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
-    struct qemu_ether_header *hdr = (void *)buf;
-    int result = !CSR_DRCVBC(s) && !memcmp(hdr->ether_dhost, BCAST, 6);
-#ifdef PCNET_DEBUG_MATCH
-    printf("padr_bcast result=%d\n", result);
-#endif
-    return result;
-}
-
-static inline int ladr_match(PCNetState *s, const uint8_t *buf, int size)
-{
-    struct qemu_ether_header *hdr = (void *)buf;
-    if ((*(hdr->ether_dhost)&0x01) &&
-        ((uint64_t *)&s->csr[8])[0] != 0LL) {
-        uint8_t ladr[8] = {
-            s->csr[8] & 0xff, s->csr[8] >> 8,
-            s->csr[9] & 0xff, s->csr[9] >> 8,
-            s->csr[10] & 0xff, s->csr[10] >> 8,
-            s->csr[11] & 0xff, s->csr[11] >> 8
-        };
-        int index = lnc_mchash(hdr->ether_dhost) >> 26;
-        return !!(ladr[index >> 3] & (1 << (index & 7)));
-    }
-    return 0;
-}
-
-static inline hwaddr pcnet_rdra_addr(PCNetState *s, int idx)
-{
-    while (idx < 1) idx += CSR_RCVRL(s);
-    return s->rdra + ((CSR_RCVRL(s) - idx) * (BCR_SWSTYLE(s) ? 16 : 8));
-}
-
-static inline int64_t pcnet_get_next_poll_time(PCNetState *s, int64_t current_time)
-{
-    int64_t next_time = current_time +
-        muldiv64(65536 - (CSR_SPND(s) ? 0 : CSR_POLL(s)),
-                 get_ticks_per_sec(), 33000000L);
-    if (next_time <= current_time)
-        next_time = current_time + 1;
-    return next_time;
-}
-
-static void pcnet_poll(PCNetState *s);
-static void pcnet_poll_timer(void *opaque);
-
-static uint32_t pcnet_csr_readw(PCNetState *s, uint32_t rap);
-static void pcnet_csr_writew(PCNetState *s, uint32_t rap, uint32_t new_value);
-static void pcnet_bcr_writew(PCNetState *s, uint32_t rap, uint32_t val);
-
-static void pcnet_s_reset(PCNetState *s)
-{
-#ifdef PCNET_DEBUG
-    printf("pcnet_s_reset\n");
-#endif
-
-    s->rdra = 0;
-    s->tdra = 0;
-    s->rap = 0;
-
-    s->bcr[BCR_BSBC] &= ~0x0080;
-
-    s->csr[0]   = 0x0004;
-    s->csr[3]   = 0x0000;
-    s->csr[4]   = 0x0115;
-    s->csr[5]   = 0x0000;
-    s->csr[6]   = 0x0000;
-    s->csr[8]   = 0;
-    s->csr[9]   = 0;
-    s->csr[10]  = 0;
-    s->csr[11]  = 0;
-    s->csr[12]  = le16_to_cpu(((uint16_t *)&s->prom[0])[0]);
-    s->csr[13]  = le16_to_cpu(((uint16_t *)&s->prom[0])[1]);
-    s->csr[14]  = le16_to_cpu(((uint16_t *)&s->prom[0])[2]);
-    s->csr[15] &= 0x21c4;
-    s->csr[72]  = 1;
-    s->csr[74]  = 1;
-    s->csr[76]  = 1;
-    s->csr[78]  = 1;
-    s->csr[80]  = 0x1410;
-    s->csr[88]  = 0x1003;
-    s->csr[89]  = 0x0262;
-    s->csr[94]  = 0x0000;
-    s->csr[100] = 0x0200;
-    s->csr[103] = 0x0105;
-    s->csr[103] = 0x0105;
-    s->csr[112] = 0x0000;
-    s->csr[114] = 0x0000;
-    s->csr[122] = 0x0000;
-    s->csr[124] = 0x0000;
-
-    s->tx_busy = 0;
-}
-
-static void pcnet_update_irq(PCNetState *s)
-{
-    int isr = 0;
-    s->csr[0] &= ~0x0080;
-
-#if 1
-    if (((s->csr[0] & ~s->csr[3]) & 0x5f00) ||
-        (((s->csr[4]>>1) & ~s->csr[4]) & 0x0115) ||
-        (((s->csr[5]>>1) & s->csr[5]) & 0x0048))
-#else
-    if ((!(s->csr[3] & 0x4000) && !!(s->csr[0] & 0x4000)) /* BABL */ ||
-        (!(s->csr[3] & 0x1000) && !!(s->csr[0] & 0x1000)) /* MISS */ ||
-        (!(s->csr[3] & 0x0100) && !!(s->csr[0] & 0x0100)) /* IDON */ ||
-        (!(s->csr[3] & 0x0200) && !!(s->csr[0] & 0x0200)) /* TINT */ ||
-        (!(s->csr[3] & 0x0400) && !!(s->csr[0] & 0x0400)) /* RINT */ ||
-        (!(s->csr[3] & 0x0800) && !!(s->csr[0] & 0x0800)) /* MERR */ ||
-        (!(s->csr[4] & 0x0001) && !!(s->csr[4] & 0x0002)) /* JAB */ ||
-        (!(s->csr[4] & 0x0004) && !!(s->csr[4] & 0x0008)) /* TXSTRT */ ||
-        (!(s->csr[4] & 0x0010) && !!(s->csr[4] & 0x0020)) /* RCVO */ ||
-        (!(s->csr[4] & 0x0100) && !!(s->csr[4] & 0x0200)) /* MFCO */ ||
-        (!!(s->csr[5] & 0x0040) && !!(s->csr[5] & 0x0080)) /* EXDINT */ ||
-        (!!(s->csr[5] & 0x0008) && !!(s->csr[5] & 0x0010)) /* MPINT */)
-#endif
-    {
-
-        isr = CSR_INEA(s);
-        s->csr[0] |= 0x0080;
-    }
-
-    if (!!(s->csr[4] & 0x0080) && CSR_INEA(s)) { /* UINT */
-        s->csr[4] &= ~0x0080;
-        s->csr[4] |= 0x0040;
-        s->csr[0] |= 0x0080;
-        isr = 1;
-#ifdef PCNET_DEBUG
-        printf("pcnet user int\n");
-#endif
-    }
-
-#if 1
-    if (((s->csr[5]>>1) & s->csr[5]) & 0x0500)
-#else
-    if ((!!(s->csr[5] & 0x0400) && !!(s->csr[5] & 0x0800)) /* SINT */ ||
-        (!!(s->csr[5] & 0x0100) && !!(s->csr[5] & 0x0200)) /* SLPINT */ )
-#endif
-    {
-        isr = 1;
-        s->csr[0] |= 0x0080;
-    }
-
-    if (isr != s->isr) {
-#ifdef PCNET_DEBUG
-        printf("pcnet: INTA=%d\n", isr);
-#endif
-    }
-    qemu_set_irq(s->irq, isr);
-    s->isr = isr;
-}
-
-static void pcnet_init(PCNetState *s)
-{
-    int rlen, tlen;
-    uint16_t padr[3], ladrf[4], mode;
-    uint32_t rdra, tdra;
-
-#ifdef PCNET_DEBUG
-    printf("pcnet_init init_addr=0x%08x\n", PHYSADDR(s,CSR_IADR(s)));
-#endif
-
-    if (BCR_SSIZE32(s)) {
-        struct pcnet_initblk32 initblk;
-        s->phys_mem_read(s->dma_opaque, PHYSADDR(s,CSR_IADR(s)),
-                (uint8_t *)&initblk, sizeof(initblk), 0);
-        mode = le16_to_cpu(initblk.mode);
-        rlen = initblk.rlen >> 4;
-        tlen = initblk.tlen >> 4;
-       ladrf[0] = le16_to_cpu(initblk.ladrf[0]);
-       ladrf[1] = le16_to_cpu(initblk.ladrf[1]);
-       ladrf[2] = le16_to_cpu(initblk.ladrf[2]);
-       ladrf[3] = le16_to_cpu(initblk.ladrf[3]);
-       padr[0] = le16_to_cpu(initblk.padr[0]);
-       padr[1] = le16_to_cpu(initblk.padr[1]);
-       padr[2] = le16_to_cpu(initblk.padr[2]);
-        rdra = le32_to_cpu(initblk.rdra);
-        tdra = le32_to_cpu(initblk.tdra);
-    } else {
-        struct pcnet_initblk16 initblk;
-        s->phys_mem_read(s->dma_opaque, PHYSADDR(s,CSR_IADR(s)),
-                (uint8_t *)&initblk, sizeof(initblk), 0);
-        mode = le16_to_cpu(initblk.mode);
-       ladrf[0] = le16_to_cpu(initblk.ladrf[0]);
-       ladrf[1] = le16_to_cpu(initblk.ladrf[1]);
-       ladrf[2] = le16_to_cpu(initblk.ladrf[2]);
-       ladrf[3] = le16_to_cpu(initblk.ladrf[3]);
-       padr[0] = le16_to_cpu(initblk.padr[0]);
-       padr[1] = le16_to_cpu(initblk.padr[1]);
-       padr[2] = le16_to_cpu(initblk.padr[2]);
-        rdra = le32_to_cpu(initblk.rdra);
-        tdra = le32_to_cpu(initblk.tdra);
-        rlen = rdra >> 29;
-        tlen = tdra >> 29;
-        rdra &= 0x00ffffff;
-        tdra &= 0x00ffffff;
-    }
-
-#if defined(PCNET_DEBUG)
-    printf("rlen=%d tlen=%d\n", rlen, tlen);
-#endif
-
-    CSR_RCVRL(s) = (rlen < 9) ? (1 << rlen) : 512;
-    CSR_XMTRL(s) = (tlen < 9) ? (1 << tlen) : 512;
-    s->csr[ 6] = (tlen << 12) | (rlen << 8);
-    s->csr[15] = mode;
-    s->csr[ 8] = ladrf[0];
-    s->csr[ 9] = ladrf[1];
-    s->csr[10] = ladrf[2];
-    s->csr[11] = ladrf[3];
-    s->csr[12] = padr[0];
-    s->csr[13] = padr[1];
-    s->csr[14] = padr[2];
-    s->rdra = PHYSADDR(s, rdra);
-    s->tdra = PHYSADDR(s, tdra);
-
-    CSR_RCVRC(s) = CSR_RCVRL(s);
-    CSR_XMTRC(s) = CSR_XMTRL(s);
-
-#ifdef PCNET_DEBUG
-    printf("pcnet ss32=%d rdra=0x%08x[%d] tdra=0x%08x[%d]\n",
-        BCR_SSIZE32(s),
-        s->rdra, CSR_RCVRL(s), s->tdra, CSR_XMTRL(s));
-#endif
-
-    s->csr[0] |= 0x0101;
-    s->csr[0] &= ~0x0004;       /* clear STOP bit */
-}
-
-static void pcnet_start(PCNetState *s)
-{
-#ifdef PCNET_DEBUG
-    printf("pcnet_start\n");
-#endif
-
-    if (!CSR_DTX(s))
-        s->csr[0] |= 0x0010;    /* set TXON */
-
-    if (!CSR_DRX(s))
-        s->csr[0] |= 0x0020;    /* set RXON */
-
-    s->csr[0] &= ~0x0004;       /* clear STOP bit */
-    s->csr[0] |= 0x0002;
-    pcnet_poll_timer(s);
-}
-
-static void pcnet_stop(PCNetState *s)
-{
-#ifdef PCNET_DEBUG
-    printf("pcnet_stop\n");
-#endif
-    s->csr[0] &= ~0xffeb;
-    s->csr[0] |= 0x0014;
-    s->csr[4] &= ~0x02c2;
-    s->csr[5] &= ~0x0011;
-    pcnet_poll_timer(s);
-}
-
-static void pcnet_rdte_poll(PCNetState *s)
-{
-    s->csr[28] = s->csr[29] = 0;
-    if (s->rdra) {
-        int bad = 0;
-#if 1
-        hwaddr crda = pcnet_rdra_addr(s, CSR_RCVRC(s));
-        hwaddr nrda = pcnet_rdra_addr(s, -1 + CSR_RCVRC(s));
-        hwaddr nnrd = pcnet_rdra_addr(s, -2 + CSR_RCVRC(s));
-#else
-        hwaddr crda = s->rdra +
-            (CSR_RCVRL(s) - CSR_RCVRC(s)) *
-            (BCR_SWSTYLE(s) ? 16 : 8 );
-        int nrdc = CSR_RCVRC(s)<=1 ? CSR_RCVRL(s) : CSR_RCVRC(s)-1;
-        hwaddr nrda = s->rdra +
-            (CSR_RCVRL(s) - nrdc) *
-            (BCR_SWSTYLE(s) ? 16 : 8 );
-        int nnrc = nrdc<=1 ? CSR_RCVRL(s) : nrdc-1;
-        hwaddr nnrd = s->rdra +
-            (CSR_RCVRL(s) - nnrc) *
-            (BCR_SWSTYLE(s) ? 16 : 8 );
-#endif
-
-        CHECK_RMD(crda, bad);
-        if (!bad) {
-            CHECK_RMD(nrda, bad);
-            if (bad || (nrda == crda)) nrda = 0;
-            CHECK_RMD(nnrd, bad);
-            if (bad || (nnrd == crda)) nnrd = 0;
-
-            s->csr[28] = crda & 0xffff;
-            s->csr[29] = crda >> 16;
-            s->csr[26] = nrda & 0xffff;
-            s->csr[27] = nrda >> 16;
-            s->csr[36] = nnrd & 0xffff;
-            s->csr[37] = nnrd >> 16;
-#ifdef PCNET_DEBUG
-            if (bad) {
-                printf("pcnet: BAD RMD RECORDS AFTER 0x" TARGET_FMT_plx "\n",
-                       crda);
-            }
-        } else {
-            printf("pcnet: BAD RMD RDA=0x" TARGET_FMT_plx "\n",
-                   crda);
-#endif
-        }
-    }
-
-    if (CSR_CRDA(s)) {
-        struct pcnet_RMD rmd;
-        RMDLOAD(&rmd, PHYSADDR(s,CSR_CRDA(s)));
-        CSR_CRBC(s) = GET_FIELD(rmd.buf_length, RMDL, BCNT);
-        CSR_CRST(s) = rmd.status;
-#ifdef PCNET_DEBUG_RMD_X
-        printf("CRDA=0x%08x CRST=0x%04x RCVRC=%d RMDL=0x%04x RMDS=0x%04x RMDM=0x%08x\n",
-                PHYSADDR(s,CSR_CRDA(s)), CSR_CRST(s), CSR_RCVRC(s),
-                rmd.buf_length, rmd.status, rmd.msg_length);
-        PRINT_RMD(&rmd);
-#endif
-    } else {
-        CSR_CRBC(s) = CSR_CRST(s) = 0;
-    }
-
-    if (CSR_NRDA(s)) {
-        struct pcnet_RMD rmd;
-        RMDLOAD(&rmd, PHYSADDR(s,CSR_NRDA(s)));
-        CSR_NRBC(s) = GET_FIELD(rmd.buf_length, RMDL, BCNT);
-        CSR_NRST(s) = rmd.status;
-    } else {
-        CSR_NRBC(s) = CSR_NRST(s) = 0;
-    }
-
-}
-
-static int pcnet_tdte_poll(PCNetState *s)
-{
-    s->csr[34] = s->csr[35] = 0;
-    if (s->tdra) {
-        hwaddr cxda = s->tdra +
-            (CSR_XMTRL(s) - CSR_XMTRC(s)) *
-            (BCR_SWSTYLE(s) ? 16 : 8);
-        int bad = 0;
-        CHECK_TMD(cxda, bad);
-        if (!bad) {
-            if (CSR_CXDA(s) != cxda) {
-                s->csr[60] = s->csr[34];
-                s->csr[61] = s->csr[35];
-                s->csr[62] = CSR_CXBC(s);
-                s->csr[63] = CSR_CXST(s);
-            }
-            s->csr[34] = cxda & 0xffff;
-            s->csr[35] = cxda >> 16;
-#ifdef PCNET_DEBUG_X
-            printf("pcnet: BAD TMD XDA=0x%08x\n", cxda);
-#endif
-        }
-    }
-
-    if (CSR_CXDA(s)) {
-        struct pcnet_TMD tmd;
-
-        TMDLOAD(&tmd, PHYSADDR(s,CSR_CXDA(s)));
-
-        CSR_CXBC(s) = GET_FIELD(tmd.length, TMDL, BCNT);
-        CSR_CXST(s) = tmd.status;
-    } else {
-        CSR_CXBC(s) = CSR_CXST(s) = 0;
-    }
-
-    return !!(CSR_CXST(s) & 0x8000);
-}
-
-int pcnet_can_receive(NetClientState *nc)
-{
-    PCNetState *s = qemu_get_nic_opaque(nc);
-    if (CSR_STOP(s) || CSR_SPND(s))
-        return 0;
-
-    return sizeof(s->buffer)-16;
-}
-
-#define MIN_BUF_SIZE 60
-
-ssize_t pcnet_receive(NetClientState *nc, const uint8_t *buf, size_t size_)
-{
-    PCNetState *s = qemu_get_nic_opaque(nc);
-    int is_padr = 0, is_bcast = 0, is_ladr = 0;
-    uint8_t buf1[60];
-    int remaining;
-    int crc_err = 0;
-    int size = size_;
-
-    if (CSR_DRX(s) || CSR_STOP(s) || CSR_SPND(s) || !size ||
-        (CSR_LOOP(s) && !s->looptest)) {
-        return -1;
-    }
-#ifdef PCNET_DEBUG
-    printf("pcnet_receive size=%d\n", size);
-#endif
-
-    /* if too small buffer, then expand it */
-    if (size < MIN_BUF_SIZE) {
-        memcpy(buf1, buf, size);
-        memset(buf1 + size, 0, MIN_BUF_SIZE - size);
-        buf = buf1;
-        size = MIN_BUF_SIZE;
-    }
-
-    if (CSR_PROM(s)
-        || (is_padr=padr_match(s, buf, size))
-        || (is_bcast=padr_bcast(s, buf, size))
-        || (is_ladr=ladr_match(s, buf, size))) {
-
-        pcnet_rdte_poll(s);
-
-        if (!(CSR_CRST(s) & 0x8000) && s->rdra) {
-            struct pcnet_RMD rmd;
-            int rcvrc = CSR_RCVRC(s)-1,i;
-            hwaddr nrda;
-            for (i = CSR_RCVRL(s)-1; i > 0; i--, rcvrc--) {
-                if (rcvrc <= 1)
-                    rcvrc = CSR_RCVRL(s);
-                nrda = s->rdra +
-                    (CSR_RCVRL(s) - rcvrc) *
-                    (BCR_SWSTYLE(s) ? 16 : 8 );
-                RMDLOAD(&rmd, nrda);
-                if (GET_FIELD(rmd.status, RMDS, OWN)) {
-#ifdef PCNET_DEBUG_RMD
-                    printf("pcnet - scan buffer: RCVRC=%d PREV_RCVRC=%d\n",
-                                rcvrc, CSR_RCVRC(s));
-#endif
-                    CSR_RCVRC(s) = rcvrc;
-                    pcnet_rdte_poll(s);
-                    break;
-                }
-            }
-        }
-
-        if (!(CSR_CRST(s) & 0x8000)) {
-#ifdef PCNET_DEBUG_RMD
-            printf("pcnet - no buffer: RCVRC=%d\n", CSR_RCVRC(s));
-#endif
-            s->csr[0] |= 0x1000; /* Set MISS flag */
-            CSR_MISSC(s)++;
-        } else {
-            uint8_t *src = s->buffer;
-            hwaddr crda = CSR_CRDA(s);
-            struct pcnet_RMD rmd;
-            int pktcount = 0;
-
-            if (!s->looptest) {
-                memcpy(src, buf, size);
-                /* no need to compute the CRC */
-                src[size] = 0;
-                src[size + 1] = 0;
-                src[size + 2] = 0;
-                src[size + 3] = 0;
-                size += 4;
-            } else if (s->looptest == PCNET_LOOPTEST_CRC ||
-                       !CSR_DXMTFCS(s) || size < MIN_BUF_SIZE+4) {
-                uint32_t fcs = ~0;
-                uint8_t *p = src;
-
-                while (p != &src[size])
-                    CRC(fcs, *p++);
-                *(uint32_t *)p = htonl(fcs);
-                size += 4;
-            } else {
-                uint32_t fcs = ~0;
-                uint8_t *p = src;
-
-                while (p != &src[size-4])
-                    CRC(fcs, *p++);
-                crc_err = (*(uint32_t *)p != htonl(fcs));
-            }
-
-#ifdef PCNET_DEBUG_MATCH
-            PRINT_PKTHDR(buf);
-#endif
-
-            RMDLOAD(&rmd, PHYSADDR(s,crda));
-            /*if (!CSR_LAPPEN(s))*/
-                SET_FIELD(&rmd.status, RMDS, STP, 1);
-
-#define PCNET_RECV_STORE() do {                                 \
-    int count = MIN(4096 - GET_FIELD(rmd.buf_length, RMDL, BCNT),remaining); \
-    hwaddr rbadr = PHYSADDR(s, rmd.rbadr);          \
-    s->phys_mem_write(s->dma_opaque, rbadr, src, count, CSR_BSWP(s)); \
-    src += count; remaining -= count;                           \
-    SET_FIELD(&rmd.status, RMDS, OWN, 0);                       \
-    RMDSTORE(&rmd, PHYSADDR(s,crda));                           \
-    pktcount++;                                                 \
-} while (0)
-
-            remaining = size;
-            PCNET_RECV_STORE();
-            if ((remaining > 0) && CSR_NRDA(s)) {
-                hwaddr nrda = CSR_NRDA(s);
-#ifdef PCNET_DEBUG_RMD
-                PRINT_RMD(&rmd);
-#endif
-                RMDLOAD(&rmd, PHYSADDR(s,nrda));
-                if (GET_FIELD(rmd.status, RMDS, OWN)) {
-                    crda = nrda;
-                    PCNET_RECV_STORE();
-#ifdef PCNET_DEBUG_RMD
-                    PRINT_RMD(&rmd);
-#endif
-                    if ((remaining > 0) && (nrda=CSR_NNRD(s))) {
-                        RMDLOAD(&rmd, PHYSADDR(s,nrda));
-                        if (GET_FIELD(rmd.status, RMDS, OWN)) {
-                            crda = nrda;
-                            PCNET_RECV_STORE();
-                        }
-                    }
-                }
-            }
-
-#undef PCNET_RECV_STORE
-
-            RMDLOAD(&rmd, PHYSADDR(s,crda));
-            if (remaining == 0) {
-                SET_FIELD(&rmd.msg_length, RMDM, MCNT, size);
-                SET_FIELD(&rmd.status, RMDS, ENP, 1);
-                SET_FIELD(&rmd.status, RMDS, PAM, !CSR_PROM(s) && is_padr);
-                SET_FIELD(&rmd.status, RMDS, LFAM, !CSR_PROM(s) && is_ladr);
-                SET_FIELD(&rmd.status, RMDS, BAM, !CSR_PROM(s) && is_bcast);
-                if (crc_err) {
-                    SET_FIELD(&rmd.status, RMDS, CRC, 1);
-                    SET_FIELD(&rmd.status, RMDS, ERR, 1);
-                }
-            } else {
-                SET_FIELD(&rmd.status, RMDS, OFLO, 1);
-                SET_FIELD(&rmd.status, RMDS, BUFF, 1);
-                SET_FIELD(&rmd.status, RMDS, ERR, 1);
-            }
-            RMDSTORE(&rmd, PHYSADDR(s,crda));
-            s->csr[0] |= 0x0400;
-
-#ifdef PCNET_DEBUG
-            printf("RCVRC=%d CRDA=0x%08x BLKS=%d\n",
-                CSR_RCVRC(s), PHYSADDR(s,CSR_CRDA(s)), pktcount);
-#endif
-#ifdef PCNET_DEBUG_RMD
-            PRINT_RMD(&rmd);
-#endif
-
-            while (pktcount--) {
-                if (CSR_RCVRC(s) <= 1)
-                    CSR_RCVRC(s) = CSR_RCVRL(s);
-                else
-                    CSR_RCVRC(s)--;
-            }
-
-            pcnet_rdte_poll(s);
-
-        }
-    }
-
-    pcnet_poll(s);
-    pcnet_update_irq(s);
-
-    return size_;
-}
-
-void pcnet_set_link_status(NetClientState *nc)
-{
-    PCNetState *d = qemu_get_nic_opaque(nc);
-
-    d->lnkst = nc->link_down ? 0 : 0x40;
-}
-
-static void pcnet_transmit(PCNetState *s)
-{
-    hwaddr xmit_cxda = 0;
-    int count = CSR_XMTRL(s)-1;
-    int add_crc = 0;
-
-    s->xmit_pos = -1;
-
-    if (!CSR_TXON(s)) {
-        s->csr[0] &= ~0x0008;
-        return;
-    }
-
-    s->tx_busy = 1;
-
-    txagain:
-    if (pcnet_tdte_poll(s)) {
-        struct pcnet_TMD tmd;
-
-        TMDLOAD(&tmd, PHYSADDR(s,CSR_CXDA(s)));
-
-#ifdef PCNET_DEBUG_TMD
-        printf("  TMDLOAD 0x%08x\n", PHYSADDR(s,CSR_CXDA(s)));
-        PRINT_TMD(&tmd);
-#endif
-        if (GET_FIELD(tmd.status, TMDS, STP)) {
-            s->xmit_pos = 0;
-            xmit_cxda = PHYSADDR(s,CSR_CXDA(s));
-            if (BCR_SWSTYLE(s) != 1)
-                add_crc = GET_FIELD(tmd.status, TMDS, ADDFCS);
-        }
-        if (s->lnkst == 0 &&
-            (!CSR_LOOP(s) || (!CSR_INTL(s) && !BCR_TMAULOOP(s)))) {
-            SET_FIELD(&tmd.misc, TMDM, LCAR, 1);
-            SET_FIELD(&tmd.status, TMDS, ERR, 1);
-            SET_FIELD(&tmd.status, TMDS, OWN, 0);
-            s->csr[0] |= 0xa000; /* ERR | CERR */
-            s->xmit_pos = -1;
-            goto txdone;
-        }
-        if (!GET_FIELD(tmd.status, TMDS, ENP)) {
-            int bcnt = 4096 - GET_FIELD(tmd.length, TMDL, BCNT);
-            s->phys_mem_read(s->dma_opaque, PHYSADDR(s, tmd.tbadr),
-                             s->buffer + s->xmit_pos, bcnt, CSR_BSWP(s));
-            s->xmit_pos += bcnt;
-        } else if (s->xmit_pos >= 0) {
-            int bcnt = 4096 - GET_FIELD(tmd.length, TMDL, BCNT);
-            s->phys_mem_read(s->dma_opaque, PHYSADDR(s, tmd.tbadr),
-                             s->buffer + s->xmit_pos, bcnt, CSR_BSWP(s));
-            s->xmit_pos += bcnt;
-#ifdef PCNET_DEBUG
-            printf("pcnet_transmit size=%d\n", s->xmit_pos);
-#endif
-            if (CSR_LOOP(s)) {
-                if (BCR_SWSTYLE(s) == 1)
-                    add_crc = !GET_FIELD(tmd.status, TMDS, NOFCS);
-                s->looptest = add_crc ? PCNET_LOOPTEST_CRC : PCNET_LOOPTEST_NOCRC;
-                pcnet_receive(qemu_get_queue(s->nic), s->buffer, s->xmit_pos);
-                s->looptest = 0;
-            } else
-                if (s->nic)
-                    qemu_send_packet(qemu_get_queue(s->nic), s->buffer,
-                                     s->xmit_pos);
-
-            s->csr[0] &= ~0x0008;   /* clear TDMD */
-            s->csr[4] |= 0x0004;    /* set TXSTRT */
-            s->xmit_pos = -1;
-        }
-
-    txdone:
-        SET_FIELD(&tmd.status, TMDS, OWN, 0);
-        TMDSTORE(&tmd, PHYSADDR(s,CSR_CXDA(s)));
-        if (!CSR_TOKINTD(s) || (CSR_LTINTEN(s) && GET_FIELD(tmd.status, TMDS, LTINT)))
-            s->csr[0] |= 0x0200;    /* set TINT */
-
-        if (CSR_XMTRC(s)<=1)
-            CSR_XMTRC(s) = CSR_XMTRL(s);
-        else
-            CSR_XMTRC(s)--;
-        if (count--)
-            goto txagain;
-
-    } else
-    if (s->xmit_pos >= 0) {
-        struct pcnet_TMD tmd;
-        TMDLOAD(&tmd, xmit_cxda);
-        SET_FIELD(&tmd.misc, TMDM, BUFF, 1);
-        SET_FIELD(&tmd.misc, TMDM, UFLO, 1);
-        SET_FIELD(&tmd.status, TMDS, ERR, 1);
-        SET_FIELD(&tmd.status, TMDS, OWN, 0);
-        TMDSTORE(&tmd, xmit_cxda);
-        s->csr[0] |= 0x0200;    /* set TINT */
-        if (!CSR_DXSUFLO(s)) {
-            s->csr[0] &= ~0x0010;
-        } else
-        if (count--)
-          goto txagain;
-    }
-
-    s->tx_busy = 0;
-}
-
-static void pcnet_poll(PCNetState *s)
-{
-    if (CSR_RXON(s)) {
-        pcnet_rdte_poll(s);
-    }
-
-    if (CSR_TDMD(s) ||
-        (CSR_TXON(s) && !CSR_DPOLL(s) && pcnet_tdte_poll(s)))
-    {
-        /* prevent recursion */
-        if (s->tx_busy)
-            return;
-
-        pcnet_transmit(s);
-    }
-}
-
-static void pcnet_poll_timer(void *opaque)
-{
-    PCNetState *s = opaque;
-
-    qemu_del_timer(s->poll_timer);
-
-    if (CSR_TDMD(s)) {
-        pcnet_transmit(s);
-    }
-
-    pcnet_update_irq(s);
-
-    if (!CSR_STOP(s) && !CSR_SPND(s) && !CSR_DPOLL(s)) {
-        uint64_t now = qemu_get_clock_ns(vm_clock) * 33;
-        if (!s->timer || !now)
-            s->timer = now;
-        else {
-            uint64_t t = now - s->timer + CSR_POLL(s);
-            if (t > 0xffffLL) {
-                pcnet_poll(s);
-                CSR_POLL(s) = CSR_PINT(s);
-            } else
-                CSR_POLL(s) = t;
-        }
-        qemu_mod_timer(s->poll_timer,
-            pcnet_get_next_poll_time(s,qemu_get_clock_ns(vm_clock)));
-    }
-}
-
-
-static void pcnet_csr_writew(PCNetState *s, uint32_t rap, uint32_t new_value)
-{
-    uint16_t val = new_value;
-#ifdef PCNET_DEBUG_CSR
-    printf("pcnet_csr_writew rap=%d val=0x%04x\n", rap, val);
-#endif
-    switch (rap) {
-    case 0:
-        s->csr[0] &= ~(val & 0x7f00); /* Clear any interrupt flags */
-
-        s->csr[0] = (s->csr[0] & ~0x0040) | (val & 0x0048);
-
-        val = (val & 0x007f) | (s->csr[0] & 0x7f00);
-
-        /* IFF STOP, STRT and INIT are set, clear STRT and INIT */
-        if ((val&7) == 7)
-          val &= ~3;
-
-        if (!CSR_STOP(s) && (val & 4))
-            pcnet_stop(s);
-
-        if (!CSR_INIT(s) && (val & 1))
-            pcnet_init(s);
-
-        if (!CSR_STRT(s) && (val & 2))
-            pcnet_start(s);
-
-        if (CSR_TDMD(s))
-            pcnet_transmit(s);
-
-        return;
-    case 1:
-    case 2:
-    case 8:
-    case 9:
-    case 10:
-    case 11:
-    case 12:
-    case 13:
-    case 14:
-    case 15:
-    case 18: /* CRBAL */
-    case 19: /* CRBAU */
-    case 20: /* CXBAL */
-    case 21: /* CXBAU */
-    case 22: /* NRBAU */
-    case 23: /* NRBAU */
-    case 24:
-    case 25:
-    case 26:
-    case 27:
-    case 28:
-    case 29:
-    case 30:
-    case 31:
-    case 32:
-    case 33:
-    case 34:
-    case 35:
-    case 36:
-    case 37:
-    case 38:
-    case 39:
-    case 40: /* CRBC */
-    case 41:
-    case 42: /* CXBC */
-    case 43:
-    case 44:
-    case 45:
-    case 46: /* POLL */
-    case 47: /* POLLINT */
-    case 72:
-    case 74:
-    case 76: /* RCVRL */
-    case 78: /* XMTRL */
-    case 112:
-       if (CSR_STOP(s) || CSR_SPND(s))
-           break;
-       return;
-    case 3:
-        break;
-    case 4:
-        s->csr[4] &= ~(val & 0x026a);
-        val &= ~0x026a; val |= s->csr[4] & 0x026a;
-        break;
-    case 5:
-        s->csr[5] &= ~(val & 0x0a90);
-        val &= ~0x0a90; val |= s->csr[5] & 0x0a90;
-        break;
-    case 16:
-        pcnet_csr_writew(s,1,val);
-        return;
-    case 17:
-        pcnet_csr_writew(s,2,val);
-        return;
-    case 58:
-        pcnet_bcr_writew(s,BCR_SWS,val);
-        break;
-    default:
-        return;
-    }
-    s->csr[rap] = val;
-}
-
-static uint32_t pcnet_csr_readw(PCNetState *s, uint32_t rap)
-{
-    uint32_t val;
-    switch (rap) {
-    case 0:
-        pcnet_update_irq(s);
-        val = s->csr[0];
-        val |= (val & 0x7800) ? 0x8000 : 0;
-        break;
-    case 16:
-        return pcnet_csr_readw(s,1);
-    case 17:
-        return pcnet_csr_readw(s,2);
-    case 58:
-        return pcnet_bcr_readw(s,BCR_SWS);
-    case 88:
-        val = s->csr[89];
-        val <<= 16;
-        val |= s->csr[88];
-        break;
-    default:
-        val = s->csr[rap];
-    }
-#ifdef PCNET_DEBUG_CSR
-    printf("pcnet_csr_readw rap=%d val=0x%04x\n", rap, val);
-#endif
-    return val;
-}
-
-static void pcnet_bcr_writew(PCNetState *s, uint32_t rap, uint32_t val)
-{
-    rap &= 127;
-#ifdef PCNET_DEBUG_BCR
-    printf("pcnet_bcr_writew rap=%d val=0x%04x\n", rap, val);
-#endif
-    switch (rap) {
-    case BCR_SWS:
-        if (!(CSR_STOP(s) || CSR_SPND(s)))
-            return;
-        val &= ~0x0300;
-        switch (val & 0x00ff) {
-        case 0:
-            val |= 0x0200;
-            break;
-        case 1:
-            val |= 0x0100;
-            break;
-        case 2:
-        case 3:
-            val |= 0x0300;
-            break;
-        default:
-            printf("Bad SWSTYLE=0x%02x\n", val & 0xff);
-            val = 0x0200;
-            break;
-        }
-#ifdef PCNET_DEBUG
-       printf("BCR_SWS=0x%04x\n", val);
-#endif
-        /* fall through */
-    case BCR_LNKST:
-    case BCR_LED1:
-    case BCR_LED2:
-    case BCR_LED3:
-    case BCR_MC:
-    case BCR_FDC:
-    case BCR_BSBC:
-    case BCR_EECAS:
-    case BCR_PLAT:
-        s->bcr[rap] = val;
-        break;
-    default:
-        break;
-    }
-}
-
-uint32_t pcnet_bcr_readw(PCNetState *s, uint32_t rap)
-{
-    uint32_t val;
-    rap &= 127;
-    switch (rap) {
-    case BCR_LNKST:
-    case BCR_LED1:
-    case BCR_LED2:
-    case BCR_LED3:
-        val = s->bcr[rap] & ~0x8000;
-        val |= (val & 0x017f & s->lnkst) ? 0x8000 : 0;
-        break;
-    default:
-        val = rap < 32 ? s->bcr[rap] : 0;
-        break;
-    }
-#ifdef PCNET_DEBUG_BCR
-    printf("pcnet_bcr_readw rap=%d val=0x%04x\n", rap, val);
-#endif
-    return val;
-}
-
-void pcnet_h_reset(void *opaque)
-{
-    PCNetState *s = opaque;
-
-    s->bcr[BCR_MSRDA] = 0x0005;
-    s->bcr[BCR_MSWRA] = 0x0005;
-    s->bcr[BCR_MC   ] = 0x0002;
-    s->bcr[BCR_LNKST] = 0x00c0;
-    s->bcr[BCR_LED1 ] = 0x0084;
-    s->bcr[BCR_LED2 ] = 0x0088;
-    s->bcr[BCR_LED3 ] = 0x0090;
-    s->bcr[BCR_FDC  ] = 0x0000;
-    s->bcr[BCR_BSBC ] = 0x9001;
-    s->bcr[BCR_EECAS] = 0x0002;
-    s->bcr[BCR_SWS  ] = 0x0200;
-    s->bcr[BCR_PLAT ] = 0xff06;
-
-    pcnet_s_reset(s);
-    pcnet_update_irq(s);
-    pcnet_poll_timer(s);
-}
-
-void pcnet_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
-{
-    PCNetState *s = opaque;
-    pcnet_poll_timer(s);
-#ifdef PCNET_DEBUG_IO
-    printf("pcnet_ioport_writew addr=0x%08x val=0x%04x\n", addr, val);
-#endif
-    if (!BCR_DWIO(s)) {
-        switch (addr & 0x0f) {
-        case 0x00: /* RDP */
-            pcnet_csr_writew(s, s->rap, val);
-            break;
-        case 0x02:
-            s->rap = val & 0x7f;
-            break;
-        case 0x06:
-            pcnet_bcr_writew(s, s->rap, val);
-            break;
-        }
-    }
-    pcnet_update_irq(s);
-}
-
-uint32_t pcnet_ioport_readw(void *opaque, uint32_t addr)
-{
-    PCNetState *s = opaque;
-    uint32_t val = -1;
-    pcnet_poll_timer(s);
-    if (!BCR_DWIO(s)) {
-        switch (addr & 0x0f) {
-        case 0x00: /* RDP */
-            val = pcnet_csr_readw(s, s->rap);
-            break;
-        case 0x02:
-            val = s->rap;
-            break;
-        case 0x04:
-            pcnet_s_reset(s);
-            val = 0;
-            break;
-        case 0x06:
-            val = pcnet_bcr_readw(s, s->rap);
-            break;
-        }
-    }
-    pcnet_update_irq(s);
-#ifdef PCNET_DEBUG_IO
-    printf("pcnet_ioport_readw addr=0x%08x val=0x%04x\n", addr, val & 0xffff);
-#endif
-    return val;
-}
-
-void pcnet_ioport_writel(void *opaque, uint32_t addr, uint32_t val)
-{
-    PCNetState *s = opaque;
-    pcnet_poll_timer(s);
-#ifdef PCNET_DEBUG_IO
-    printf("pcnet_ioport_writel addr=0x%08x val=0x%08x\n", addr, val);
-#endif
-    if (BCR_DWIO(s)) {
-        switch (addr & 0x0f) {
-        case 0x00: /* RDP */
-            pcnet_csr_writew(s, s->rap, val & 0xffff);
-            break;
-        case 0x04:
-            s->rap = val & 0x7f;
-            break;
-        case 0x0c:
-            pcnet_bcr_writew(s, s->rap, val & 0xffff);
-            break;
-        }
-    } else
-    if ((addr & 0x0f) == 0) {
-        /* switch device to dword i/o mode */
-        pcnet_bcr_writew(s, BCR_BSBC, pcnet_bcr_readw(s, BCR_BSBC) | 0x0080);
-#ifdef PCNET_DEBUG_IO
-        printf("device switched into dword i/o mode\n");
-#endif
-    }
-    pcnet_update_irq(s);
-}
-
-uint32_t pcnet_ioport_readl(void *opaque, uint32_t addr)
-{
-    PCNetState *s = opaque;
-    uint32_t val = -1;
-    pcnet_poll_timer(s);
-    if (BCR_DWIO(s)) {
-        switch (addr & 0x0f) {
-        case 0x00: /* RDP */
-            val = pcnet_csr_readw(s, s->rap);
-            break;
-        case 0x04:
-            val = s->rap;
-            break;
-        case 0x08:
-            pcnet_s_reset(s);
-            val = 0;
-            break;
-        case 0x0c:
-            val = pcnet_bcr_readw(s, s->rap);
-            break;
-        }
-    }
-    pcnet_update_irq(s);
-#ifdef PCNET_DEBUG_IO
-    printf("pcnet_ioport_readl addr=0x%08x val=0x%08x\n", addr, val);
-#endif
-    return val;
-}
-
-static bool is_version_2(void *opaque, int version_id)
-{
-    return version_id == 2;
-}
-
-const VMStateDescription vmstate_pcnet = {
-    .name = "pcnet",
-    .version_id = 3,
-    .minimum_version_id = 2,
-    .minimum_version_id_old = 2,
-    .fields      = (VMStateField []) {
-        VMSTATE_INT32(rap, PCNetState),
-        VMSTATE_INT32(isr, PCNetState),
-        VMSTATE_INT32(lnkst, PCNetState),
-        VMSTATE_UINT32(rdra, PCNetState),
-        VMSTATE_UINT32(tdra, PCNetState),
-        VMSTATE_BUFFER(prom, PCNetState),
-        VMSTATE_UINT16_ARRAY(csr, PCNetState, 128),
-        VMSTATE_UINT16_ARRAY(bcr, PCNetState, 32),
-        VMSTATE_UINT64(timer, PCNetState),
-        VMSTATE_INT32(xmit_pos, PCNetState),
-        VMSTATE_BUFFER(buffer, PCNetState),
-        VMSTATE_UNUSED_TEST(is_version_2, 4),
-        VMSTATE_INT32(tx_busy, PCNetState),
-        VMSTATE_TIMER(poll_timer, PCNetState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-void pcnet_common_cleanup(PCNetState *d)
-{
-    d->nic = NULL;
-}
-
-int pcnet_common_init(DeviceState *dev, PCNetState *s, NetClientInfo *info)
-{
-    int i;
-    uint16_t checksum;
-
-    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, object_get_typename(OBJECT(dev)), dev->id, s);
-    qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
-
-    add_boot_device_path(s->conf.bootindex, dev, "/ethernet-phy@0");
-
-    /* Initialize the PROM */
-
-    /*
-      Datasheet: http://pdfdata.datasheetsite.com/web/24528/AM79C970A.pdf
-      page 95
-    */
-    memcpy(s->prom, s->conf.macaddr.a, 6);
-    /* Reserved Location: must be 00h */
-    s->prom[6] = s->prom[7] = 0x00;
-    /* Reserved Location: must be 00h */
-    s->prom[8] = 0x00;
-    /* Hardware ID: must be 11h if compatibility to AMD drivers is desired */
-    s->prom[9] = 0x11;
-    /* User programmable space, init with 0 */
-    s->prom[10] = s->prom[11] = 0x00;
-    /* LSByte of two-byte checksum, which is the sum of bytes 00h-0Bh
-       and bytes 0Eh and 0Fh, must therefore be initialized with 0! */
-    s->prom[12] = s->prom[13] = 0x00;
-    /* Must be ASCII W (57h) if compatibility to AMD
-       driver software is desired */
-    s->prom[14] = s->prom[15] = 0x57;
-
-    for (i = 0, checksum = 0; i < 16; i++) {
-        checksum += s->prom[i];
-    }
-    *(uint16_t *)&s->prom[12] = cpu_to_le16(checksum);
-
-    s->lnkst = 0x40; /* initial link state: up */
-
-    return 0;
-}
diff --git a/hw/pcnet.h b/hw/pcnet.h
deleted file mode 100644 (file)
index 9dee6f3..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-#ifndef HW_PCNET_H
-#define HW_PCNET_H 1
-
-#define PCNET_IOPORT_SIZE       0x20
-#define PCNET_PNPMMIO_SIZE      0x20
-
-#define PCNET_LOOPTEST_CRC     1
-#define PCNET_LOOPTEST_NOCRC   2
-
-#include "exec/memory.h"
-
-/* BUS CONFIGURATION REGISTERS */
-#define BCR_MSRDA    0
-#define BCR_MSWRA    1
-#define BCR_MC       2
-#define BCR_LNKST    4
-#define BCR_LED1     5
-#define BCR_LED2     6
-#define BCR_LED3     7
-#define BCR_FDC      9
-#define BCR_BSBC     18
-#define BCR_EECAS    19
-#define BCR_SWS      20
-#define BCR_PLAT     22
-
-#define BCR_TMAULOOP(S)  !!((S)->bcr[BCR_MC  ] & 0x4000)
-#define BCR_APROMWE(S)   !!((S)->bcr[BCR_MC  ] & 0x0100)
-#define BCR_DWIO(S)      !!((S)->bcr[BCR_BSBC] & 0x0080)
-#define BCR_SSIZE32(S)   !!((S)->bcr[BCR_SWS ] & 0x0100)
-#define BCR_SWSTYLE(S)     ((S)->bcr[BCR_SWS ] & 0x00FF)
-
-typedef struct PCNetState_st PCNetState;
-
-struct PCNetState_st {
-    NICState *nic;
-    NICConf conf;
-    QEMUTimer *poll_timer;
-    int rap, isr, lnkst;
-    uint32_t rdra, tdra;
-    uint8_t prom[16];
-    uint16_t csr[128];
-    uint16_t bcr[32];
-    int xmit_pos;
-    uint64_t timer;
-    MemoryRegion mmio;
-    uint8_t buffer[4096];
-    qemu_irq irq;
-    void (*phys_mem_read)(void *dma_opaque, hwaddr addr,
-                         uint8_t *buf, int len, int do_bswap);
-    void (*phys_mem_write)(void *dma_opaque, hwaddr addr,
-                          uint8_t *buf, int len, int do_bswap);
-    void *dma_opaque;
-    int tx_busy;
-    int looptest;
-};
-
-void pcnet_h_reset(void *opaque);
-void pcnet_ioport_writew(void *opaque, uint32_t addr, uint32_t val);
-uint32_t pcnet_ioport_readw(void *opaque, uint32_t addr);
-void pcnet_ioport_writel(void *opaque, uint32_t addr, uint32_t val);
-uint32_t pcnet_ioport_readl(void *opaque, uint32_t addr);
-uint32_t pcnet_bcr_readw(PCNetState *s, uint32_t rap);
-int pcnet_can_receive(NetClientState *nc);
-ssize_t pcnet_receive(NetClientState *nc, const uint8_t *buf, size_t size_);
-void pcnet_set_link_status(NetClientState *nc);
-void pcnet_common_cleanup(PCNetState *d);
-int pcnet_common_init(DeviceState *dev, PCNetState *s, NetClientInfo *info);
-extern const VMStateDescription vmstate_pcnet;
-
-#endif
diff --git a/hw/pcspk.c b/hw/pcspk.c
deleted file mode 100644 (file)
index d533415..0000000
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * 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.
- */
-
-#include "hw/hw.h"
-#include "hw/pc.h"
-#include "hw/isa.h"
-#include "audio/audio.h"
-#include "qemu/timer.h"
-#include "hw/i8254.h"
-#include "hw/pcspk.h"
-
-#define PCSPK_BUF_LEN 1792
-#define PCSPK_SAMPLE_RATE 32000
-#define PCSPK_MAX_FREQ (PCSPK_SAMPLE_RATE >> 1)
-#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;
-    void *pit;
-    unsigned int pit_count;
-    unsigned int samples;
-    unsigned int play_pos;
-    int data_on;
-    int dummy_refresh_clock;
-} PCSpkState;
-
-static const char *s_spk = "pcspk";
-static PCSpkState *pcspk_state;
-
-static inline void generate_samples(PCSpkState *s)
-{
-    unsigned int i;
-
-    if (s->pit_count) {
-        const uint32_t m = PCSPK_SAMPLE_RATE * s->pit_count;
-        const uint32_t n = ((uint64_t)PIT_FREQ << 32) / m;
-
-        /* multiple of wavelength for gapless looping */
-        s->samples = (PCSPK_BUF_LEN * PIT_FREQ / m * m / (PIT_FREQ >> 1) + 1) >> 1;
-        for (i = 0; i < s->samples; ++i)
-            s->sample_buf[i] = (64 & (n * i >> 25)) - 32;
-    } else {
-        s->samples = PCSPK_BUF_LEN;
-        for (i = 0; i < PCSPK_BUF_LEN; ++i)
-            s->sample_buf[i] = 128; /* silence */
-    }
-}
-
-static void pcspk_callback(void *opaque, int free)
-{
-    PCSpkState *s = opaque;
-    PITChannelInfo ch;
-    unsigned int n;
-
-    pit_get_channel_info(s->pit, 2, &ch);
-
-    if (ch.mode != 3) {
-        return;
-    }
-
-    n = ch.initial_count;
-    /* avoid frequencies that are not reproducible with sample rate */
-    if (n < PCSPK_MIN_COUNT)
-        n = 0;
-
-    if (s->pit_count != n) {
-        s->pit_count = n;
-        s->play_pos = 0;
-        generate_samples(s);
-    }
-
-    while (free > 0) {
-        n = audio_MIN(s->samples - s->play_pos, (unsigned int)free);
-        n = AUD_write(s->voice, &s->sample_buf[s->play_pos], n);
-        if (!n)
-            break;
-        s->play_pos = (s->play_pos + n) % s->samples;
-        free -= n;
-    }
-}
-
-int pcspk_audio_init(ISABus *bus)
-{
-    PCSpkState *s = pcspk_state;
-    struct audsettings as = {PCSPK_SAMPLE_RATE, 1, AUD_FMT_U8, 0};
-
-    AUD_register_card(s_spk, &s->card);
-
-    s->voice = AUD_open_out(&s->card, s->voice, s_spk, s, pcspk_callback, &as);
-    if (!s->voice) {
-        AUD_log(s_spk, "Could not open voice\n");
-        return -1;
-    }
-
-    return 0;
-}
-
-static uint64_t pcspk_io_read(void *opaque, hwaddr addr,
-                              unsigned size)
-{
-    PCSpkState *s = opaque;
-    PITChannelInfo ch;
-
-    pit_get_channel_info(s->pit, 2, &ch);
-
-    s->dummy_refresh_clock ^= (1 << 4);
-
-    return ch.gate | (s->data_on << 1) | s->dummy_refresh_clock |
-       (ch.out << 5);
-}
-
-static void pcspk_io_write(void *opaque, hwaddr addr, uint64_t val,
-                           unsigned size)
-{
-    PCSpkState *s = opaque;
-    const int gate = val & 1;
-
-    s->data_on = (val >> 1) & 1;
-    pit_set_gate(s->pit, 2, gate);
-    if (s->voice) {
-        if (gate) /* restart */
-            s->play_pos = 0;
-        AUD_set_active_out(s->voice, gate & s->data_on);
-    }
-}
-
-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 = 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(),
-};
-
-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 const 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
deleted file mode 100644 (file)
index f448d22..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * 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/hw.h"
-#include "hw/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 */
diff --git a/hw/pflash_cfi01.c b/hw/pflash_cfi01.c
deleted file mode 100644 (file)
index 5d57bab..0000000
+++ /dev/null
@@ -1,761 +0,0 @@
-/*
- *  CFI parallel flash with Intel command set emulation
- *
- *  Copyright (c) 2006 Thorsten Zitterell
- *  Copyright (c) 2005 Jocelyn Mayer
- *
- * 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/>.
- */
-
-/*
- * For now, this code can emulate flashes of 1, 2 or 4 bytes width.
- * Supported commands/modes are:
- * - flash read
- * - flash write
- * - flash ID read
- * - sector erase
- * - CFI queries
- *
- * It does not support timings
- * It does not support flash interleaving
- * It does not implement software data protection as found in many real chips
- * It does not implement erase suspend/resume commands
- * It does not implement multiple sectors erase
- *
- * It does not implement much more ...
- */
-
-#include "hw/hw.h"
-#include "hw/flash.h"
-#include "block/block.h"
-#include "qemu/timer.h"
-#include "exec/address-spaces.h"
-#include "qemu/host-utils.h"
-#include "hw/sysbus.h"
-
-#define PFLASH_BUG(fmt, ...) \
-do { \
-    fprintf(stderr, "PFLASH: Possible BUG - " fmt, ## __VA_ARGS__); \
-    exit(1); \
-} while(0)
-
-/* #define PFLASH_DEBUG */
-#ifdef PFLASH_DEBUG
-#define DPRINTF(fmt, ...)                                   \
-do {                                                        \
-    fprintf(stderr, "PFLASH: " fmt , ## __VA_ARGS__);       \
-} while (0)
-#else
-#define DPRINTF(fmt, ...) do { } while (0)
-#endif
-
-struct pflash_t {
-    SysBusDevice busdev;
-    BlockDriverState *bs;
-    uint32_t nb_blocs;
-    uint64_t sector_len;
-    uint8_t width;
-    uint8_t be;
-    int wcycle; /* if 0, the flash is read normally */
-    int bypass;
-    int ro;
-    uint8_t cmd;
-    uint8_t status;
-    uint16_t ident0;
-    uint16_t ident1;
-    uint16_t ident2;
-    uint16_t ident3;
-    uint8_t cfi_len;
-    uint8_t cfi_table[0x52];
-    hwaddr counter;
-    unsigned int writeblock_size;
-    QEMUTimer *timer;
-    MemoryRegion mem;
-    char *name;
-    void *storage;
-};
-
-static void pflash_timer (void *opaque)
-{
-    pflash_t *pfl = opaque;
-
-    DPRINTF("%s: command %02x done\n", __func__, pfl->cmd);
-    /* Reset flash */
-    pfl->status ^= 0x80;
-    if (pfl->bypass) {
-        pfl->wcycle = 2;
-    } else {
-        memory_region_rom_device_set_readable(&pfl->mem, true);
-        pfl->wcycle = 0;
-    }
-    pfl->cmd = 0;
-}
-
-static uint32_t pflash_read (pflash_t *pfl, hwaddr offset,
-                             int width, int be)
-{
-    hwaddr boff;
-    uint32_t ret;
-    uint8_t *p;
-
-    ret = -1;
-    boff = offset & 0xFF; /* why this here ?? */
-
-    if (pfl->width == 2)
-        boff = boff >> 1;
-    else if (pfl->width == 4)
-        boff = boff >> 2;
-
-#if 0
-    DPRINTF("%s: reading offset " TARGET_FMT_plx " under cmd %02x width %d\n",
-            __func__, offset, pfl->cmd, width);
-#endif
-    switch (pfl->cmd) {
-    default:
-        /* This should never happen : reset state & treat it as a read */
-        DPRINTF("%s: unknown command state: %x\n", __func__, pfl->cmd);
-        pfl->wcycle = 0;
-        pfl->cmd = 0;
-        /* fall through to read code */
-    case 0x00:
-        /* Flash area read */
-        p = pfl->storage;
-        switch (width) {
-        case 1:
-            ret = p[offset];
-            DPRINTF("%s: data offset " TARGET_FMT_plx " %02x\n",
-                    __func__, offset, ret);
-            break;
-        case 2:
-            if (be) {
-                ret = p[offset] << 8;
-                ret |= p[offset + 1];
-            } else {
-                ret = p[offset];
-                ret |= p[offset + 1] << 8;
-            }
-            DPRINTF("%s: data offset " TARGET_FMT_plx " %04x\n",
-                    __func__, offset, ret);
-            break;
-        case 4:
-            if (be) {
-                ret = p[offset] << 24;
-                ret |= p[offset + 1] << 16;
-                ret |= p[offset + 2] << 8;
-                ret |= p[offset + 3];
-            } else {
-                ret = p[offset];
-                ret |= p[offset + 1] << 8;
-                ret |= p[offset + 2] << 16;
-                ret |= p[offset + 3] << 24;
-            }
-            DPRINTF("%s: data offset " TARGET_FMT_plx " %08x\n",
-                    __func__, offset, ret);
-            break;
-        default:
-            DPRINTF("BUG in %s\n", __func__);
-        }
-
-        break;
-    case 0x10: /* Single byte program */
-    case 0x20: /* Block erase */
-    case 0x28: /* Block erase */
-    case 0x40: /* single byte program */
-    case 0x50: /* Clear status register */
-    case 0x60: /* Block /un)lock */
-    case 0x70: /* Status Register */
-    case 0xe8: /* Write block */
-        /* Status register read */
-        ret = pfl->status;
-        DPRINTF("%s: status %x\n", __func__, ret);
-        break;
-    case 0x90:
-        switch (boff) {
-        case 0:
-            ret = pfl->ident0 << 8 | pfl->ident1;
-            DPRINTF("%s: Manufacturer Code %04x\n", __func__, ret);
-            break;
-        case 1:
-            ret = pfl->ident2 << 8 | pfl->ident3;
-            DPRINTF("%s: Device ID Code %04x\n", __func__, ret);
-            break;
-        default:
-            DPRINTF("%s: Read Device Information boff=%x\n", __func__,
-                    (unsigned)boff);
-            ret = 0;
-            break;
-        }
-        break;
-    case 0x98: /* Query mode */
-        if (boff > pfl->cfi_len)
-            ret = 0;
-        else
-            ret = pfl->cfi_table[boff];
-        break;
-    }
-    return ret;
-}
-
-/* update flash content on disk */
-static void pflash_update(pflash_t *pfl, int offset,
-                          int size)
-{
-    int offset_end;
-    if (pfl->bs) {
-        offset_end = offset + size;
-        /* round to sectors */
-        offset = offset >> 9;
-        offset_end = (offset_end + 511) >> 9;
-        bdrv_write(pfl->bs, offset, pfl->storage + (offset << 9),
-                   offset_end - offset);
-    }
-}
-
-static inline void pflash_data_write(pflash_t *pfl, hwaddr offset,
-                                     uint32_t value, int width, int be)
-{
-    uint8_t *p = pfl->storage;
-
-    DPRINTF("%s: block write offset " TARGET_FMT_plx
-            " value %x counter " TARGET_FMT_plx "\n",
-            __func__, offset, value, pfl->counter);
-    switch (width) {
-    case 1:
-        p[offset] = value;
-        break;
-    case 2:
-        if (be) {
-            p[offset] = value >> 8;
-            p[offset + 1] = value;
-        } else {
-            p[offset] = value;
-            p[offset + 1] = value >> 8;
-        }
-        break;
-    case 4:
-        if (be) {
-            p[offset] = value >> 24;
-            p[offset + 1] = value >> 16;
-            p[offset + 2] = value >> 8;
-            p[offset + 3] = value;
-        } else {
-            p[offset] = value;
-            p[offset + 1] = value >> 8;
-            p[offset + 2] = value >> 16;
-            p[offset + 3] = value >> 24;
-        }
-        break;
-    }
-
-}
-
-static void pflash_write(pflash_t *pfl, hwaddr offset,
-                         uint32_t value, int width, int be)
-{
-    uint8_t *p;
-    uint8_t cmd;
-
-    cmd = value;
-
-    DPRINTF("%s: writing offset " TARGET_FMT_plx " value %08x width %d wcycle 0x%x\n",
-            __func__, offset, value, width, pfl->wcycle);
-
-    if (!pfl->wcycle) {
-        /* Set the device in I/O access mode */
-        memory_region_rom_device_set_readable(&pfl->mem, false);
-    }
-
-    switch (pfl->wcycle) {
-    case 0:
-        /* read mode */
-        switch (cmd) {
-        case 0x00: /* ??? */
-            goto reset_flash;
-        case 0x10: /* Single Byte Program */
-        case 0x40: /* Single Byte Program */
-            DPRINTF("%s: Single Byte Program\n", __func__);
-            break;
-        case 0x20: /* Block erase */
-            p = pfl->storage;
-            offset &= ~(pfl->sector_len - 1);
-
-            DPRINTF("%s: block erase at " TARGET_FMT_plx " bytes %x\n",
-                    __func__, offset, (unsigned)pfl->sector_len);
-
-            if (!pfl->ro) {
-                memset(p + offset, 0xff, pfl->sector_len);
-                pflash_update(pfl, offset, pfl->sector_len);
-            } else {
-                pfl->status |= 0x20; /* Block erase error */
-            }
-            pfl->status |= 0x80; /* Ready! */
-            break;
-        case 0x50: /* Clear status bits */
-            DPRINTF("%s: Clear status bits\n", __func__);
-            pfl->status = 0x0;
-            goto reset_flash;
-        case 0x60: /* Block (un)lock */
-            DPRINTF("%s: Block unlock\n", __func__);
-            break;
-        case 0x70: /* Status Register */
-            DPRINTF("%s: Read status register\n", __func__);
-            pfl->cmd = cmd;
-            return;
-        case 0x90: /* Read Device ID */
-            DPRINTF("%s: Read Device information\n", __func__);
-            pfl->cmd = cmd;
-            return;
-        case 0x98: /* CFI query */
-            DPRINTF("%s: CFI query\n", __func__);
-            break;
-        case 0xe8: /* Write to buffer */
-            DPRINTF("%s: Write to buffer\n", __func__);
-            pfl->status |= 0x80; /* Ready! */
-            break;
-        case 0xf0: /* Probe for AMD flash */
-            DPRINTF("%s: Probe for AMD flash\n", __func__);
-            goto reset_flash;
-        case 0xff: /* Read array mode */
-            DPRINTF("%s: Read array mode\n", __func__);
-            goto reset_flash;
-        default:
-            goto error_flash;
-        }
-        pfl->wcycle++;
-        pfl->cmd = cmd;
-        break;
-    case 1:
-        switch (pfl->cmd) {
-        case 0x10: /* Single Byte Program */
-        case 0x40: /* Single Byte Program */
-            DPRINTF("%s: Single Byte Program\n", __func__);
-            if (!pfl->ro) {
-                pflash_data_write(pfl, offset, value, width, be);
-                pflash_update(pfl, offset, width);
-            } else {
-                pfl->status |= 0x10; /* Programming error */
-            }
-            pfl->status |= 0x80; /* Ready! */
-            pfl->wcycle = 0;
-        break;
-        case 0x20: /* Block erase */
-        case 0x28:
-            if (cmd == 0xd0) { /* confirm */
-                pfl->wcycle = 0;
-                pfl->status |= 0x80;
-            } else if (cmd == 0xff) { /* read array mode */
-                goto reset_flash;
-            } else
-                goto error_flash;
-
-            break;
-        case 0xe8:
-            DPRINTF("%s: block write of %x bytes\n", __func__, value);
-            pfl->counter = value;
-            pfl->wcycle++;
-            break;
-        case 0x60:
-            if (cmd == 0xd0) {
-                pfl->wcycle = 0;
-                pfl->status |= 0x80;
-            } else if (cmd == 0x01) {
-                pfl->wcycle = 0;
-                pfl->status |= 0x80;
-            } else if (cmd == 0xff) {
-                goto reset_flash;
-            } else {
-                DPRINTF("%s: Unknown (un)locking command\n", __func__);
-                goto reset_flash;
-            }
-            break;
-        case 0x98:
-            if (cmd == 0xff) {
-                goto reset_flash;
-            } else {
-                DPRINTF("%s: leaving query mode\n", __func__);
-            }
-            break;
-        default:
-            goto error_flash;
-        }
-        break;
-    case 2:
-        switch (pfl->cmd) {
-        case 0xe8: /* Block write */
-            if (!pfl->ro) {
-                pflash_data_write(pfl, offset, value, width, be);
-            } else {
-                pfl->status |= 0x10; /* Programming error */
-            }
-
-            pfl->status |= 0x80;
-
-            if (!pfl->counter) {
-                hwaddr mask = pfl->writeblock_size - 1;
-                mask = ~mask;
-
-                DPRINTF("%s: block write finished\n", __func__);
-                pfl->wcycle++;
-                if (!pfl->ro) {
-                    /* Flush the entire write buffer onto backing storage.  */
-                    pflash_update(pfl, offset & mask, pfl->writeblock_size);
-                } else {
-                    pfl->status |= 0x10; /* Programming error */
-                }
-            }
-
-            pfl->counter--;
-            break;
-        default:
-            goto error_flash;
-        }
-        break;
-    case 3: /* Confirm mode */
-        switch (pfl->cmd) {
-        case 0xe8: /* Block write */
-            if (cmd == 0xd0) {
-                pfl->wcycle = 0;
-                pfl->status |= 0x80;
-            } else {
-                DPRINTF("%s: unknown command for \"write block\"\n", __func__);
-                PFLASH_BUG("Write block confirm");
-                goto reset_flash;
-            }
-            break;
-        default:
-            goto error_flash;
-        }
-        break;
-    default:
-        /* Should never happen */
-        DPRINTF("%s: invalid write state\n",  __func__);
-        goto reset_flash;
-    }
-    return;
-
- error_flash:
-    qemu_log_mask(LOG_UNIMP, "%s: Unimplemented flash cmd sequence "
-                  "(offset " TARGET_FMT_plx ", wcycle 0x%x cmd 0x%x value 0x%x)"
-                  "\n", __func__, offset, pfl->wcycle, pfl->cmd, value);
-
- reset_flash:
-    memory_region_rom_device_set_readable(&pfl->mem, true);
-
-    pfl->bypass = 0;
-    pfl->wcycle = 0;
-    pfl->cmd = 0;
-}
-
-
-static uint32_t pflash_readb_be(void *opaque, hwaddr addr)
-{
-    return pflash_read(opaque, addr, 1, 1);
-}
-
-static uint32_t pflash_readb_le(void *opaque, hwaddr addr)
-{
-    return pflash_read(opaque, addr, 1, 0);
-}
-
-static uint32_t pflash_readw_be(void *opaque, hwaddr addr)
-{
-    pflash_t *pfl = opaque;
-
-    return pflash_read(pfl, addr, 2, 1);
-}
-
-static uint32_t pflash_readw_le(void *opaque, hwaddr addr)
-{
-    pflash_t *pfl = opaque;
-
-    return pflash_read(pfl, addr, 2, 0);
-}
-
-static uint32_t pflash_readl_be(void *opaque, hwaddr addr)
-{
-    pflash_t *pfl = opaque;
-
-    return pflash_read(pfl, addr, 4, 1);
-}
-
-static uint32_t pflash_readl_le(void *opaque, hwaddr addr)
-{
-    pflash_t *pfl = opaque;
-
-    return pflash_read(pfl, addr, 4, 0);
-}
-
-static void pflash_writeb_be(void *opaque, hwaddr addr,
-                             uint32_t value)
-{
-    pflash_write(opaque, addr, value, 1, 1);
-}
-
-static void pflash_writeb_le(void *opaque, hwaddr addr,
-                             uint32_t value)
-{
-    pflash_write(opaque, addr, value, 1, 0);
-}
-
-static void pflash_writew_be(void *opaque, hwaddr addr,
-                             uint32_t value)
-{
-    pflash_t *pfl = opaque;
-
-    pflash_write(pfl, addr, value, 2, 1);
-}
-
-static void pflash_writew_le(void *opaque, hwaddr addr,
-                             uint32_t value)
-{
-    pflash_t *pfl = opaque;
-
-    pflash_write(pfl, addr, value, 2, 0);
-}
-
-static void pflash_writel_be(void *opaque, hwaddr addr,
-                             uint32_t value)
-{
-    pflash_t *pfl = opaque;
-
-    pflash_write(pfl, addr, value, 4, 1);
-}
-
-static void pflash_writel_le(void *opaque, hwaddr addr,
-                             uint32_t value)
-{
-    pflash_t *pfl = opaque;
-
-    pflash_write(pfl, addr, value, 4, 0);
-}
-
-static const MemoryRegionOps pflash_cfi01_ops_be = {
-    .old_mmio = {
-        .read = { pflash_readb_be, pflash_readw_be, pflash_readl_be, },
-        .write = { pflash_writeb_be, pflash_writew_be, pflash_writel_be, },
-    },
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static const MemoryRegionOps pflash_cfi01_ops_le = {
-    .old_mmio = {
-        .read = { pflash_readb_le, pflash_readw_le, pflash_readl_le, },
-        .write = { pflash_writeb_le, pflash_writew_le, pflash_writel_le, },
-    },
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int pflash_cfi01_init(SysBusDevice *dev)
-{
-    pflash_t *pfl = FROM_SYSBUS(typeof(*pfl), dev);
-    uint64_t total_len;
-    int ret;
-
-    total_len = pfl->sector_len * pfl->nb_blocs;
-
-    /* XXX: to be fixed */
-#if 0
-    if (total_len != (8 * 1024 * 1024) && total_len != (16 * 1024 * 1024) &&
-        total_len != (32 * 1024 * 1024) && total_len != (64 * 1024 * 1024))
-        return NULL;
-#endif
-
-    memory_region_init_rom_device(
-        &pfl->mem, pfl->be ? &pflash_cfi01_ops_be : &pflash_cfi01_ops_le, pfl,
-        pfl->name, total_len);
-    vmstate_register_ram(&pfl->mem, DEVICE(pfl));
-    pfl->storage = memory_region_get_ram_ptr(&pfl->mem);
-    sysbus_init_mmio(dev, &pfl->mem);
-
-    if (pfl->bs) {
-        /* read the initial flash content */
-        ret = bdrv_read(pfl->bs, 0, pfl->storage, total_len >> 9);
-
-        if (ret < 0) {
-            vmstate_unregister_ram(&pfl->mem, DEVICE(pfl));
-            memory_region_destroy(&pfl->mem);
-            return 1;
-        }
-    }
-
-    if (pfl->bs) {
-        pfl->ro = bdrv_is_read_only(pfl->bs);
-    } else {
-        pfl->ro = 0;
-    }
-
-    pfl->timer = qemu_new_timer_ns(vm_clock, pflash_timer, pfl);
-    pfl->wcycle = 0;
-    pfl->cmd = 0;
-    pfl->status = 0;
-    /* Hardcoded CFI table */
-    pfl->cfi_len = 0x52;
-    /* Standard "QRY" string */
-    pfl->cfi_table[0x10] = 'Q';
-    pfl->cfi_table[0x11] = 'R';
-    pfl->cfi_table[0x12] = 'Y';
-    /* Command set (Intel) */
-    pfl->cfi_table[0x13] = 0x01;
-    pfl->cfi_table[0x14] = 0x00;
-    /* Primary extended table address (none) */
-    pfl->cfi_table[0x15] = 0x31;
-    pfl->cfi_table[0x16] = 0x00;
-    /* Alternate command set (none) */
-    pfl->cfi_table[0x17] = 0x00;
-    pfl->cfi_table[0x18] = 0x00;
-    /* Alternate extended table (none) */
-    pfl->cfi_table[0x19] = 0x00;
-    pfl->cfi_table[0x1A] = 0x00;
-    /* Vcc min */
-    pfl->cfi_table[0x1B] = 0x45;
-    /* Vcc max */
-    pfl->cfi_table[0x1C] = 0x55;
-    /* Vpp min (no Vpp pin) */
-    pfl->cfi_table[0x1D] = 0x00;
-    /* Vpp max (no Vpp pin) */
-    pfl->cfi_table[0x1E] = 0x00;
-    /* Reserved */
-    pfl->cfi_table[0x1F] = 0x07;
-    /* Timeout for min size buffer write */
-    pfl->cfi_table[0x20] = 0x07;
-    /* Typical timeout for block erase */
-    pfl->cfi_table[0x21] = 0x0a;
-    /* Typical timeout for full chip erase (4096 ms) */
-    pfl->cfi_table[0x22] = 0x00;
-    /* Reserved */
-    pfl->cfi_table[0x23] = 0x04;
-    /* Max timeout for buffer write */
-    pfl->cfi_table[0x24] = 0x04;
-    /* Max timeout for block erase */
-    pfl->cfi_table[0x25] = 0x04;
-    /* Max timeout for chip erase */
-    pfl->cfi_table[0x26] = 0x00;
-    /* Device size */
-    pfl->cfi_table[0x27] = ctz32(total_len); // + 1;
-    /* Flash device interface (8 & 16 bits) */
-    pfl->cfi_table[0x28] = 0x02;
-    pfl->cfi_table[0x29] = 0x00;
-    /* Max number of bytes in multi-bytes write */
-    if (pfl->width == 1) {
-        pfl->cfi_table[0x2A] = 0x08;
-    } else {
-        pfl->cfi_table[0x2A] = 0x0B;
-    }
-    pfl->writeblock_size = 1 << pfl->cfi_table[0x2A];
-
-    pfl->cfi_table[0x2B] = 0x00;
-    /* Number of erase block regions (uniform) */
-    pfl->cfi_table[0x2C] = 0x01;
-    /* Erase block region 1 */
-    pfl->cfi_table[0x2D] = pfl->nb_blocs - 1;
-    pfl->cfi_table[0x2E] = (pfl->nb_blocs - 1) >> 8;
-    pfl->cfi_table[0x2F] = pfl->sector_len >> 8;
-    pfl->cfi_table[0x30] = pfl->sector_len >> 16;
-
-    /* Extended */
-    pfl->cfi_table[0x31] = 'P';
-    pfl->cfi_table[0x32] = 'R';
-    pfl->cfi_table[0x33] = 'I';
-
-    pfl->cfi_table[0x34] = '1';
-    pfl->cfi_table[0x35] = '0';
-
-    pfl->cfi_table[0x36] = 0x00;
-    pfl->cfi_table[0x37] = 0x00;
-    pfl->cfi_table[0x38] = 0x00;
-    pfl->cfi_table[0x39] = 0x00;
-
-    pfl->cfi_table[0x3a] = 0x00;
-
-    pfl->cfi_table[0x3b] = 0x00;
-    pfl->cfi_table[0x3c] = 0x00;
-
-    pfl->cfi_table[0x3f] = 0x01; /* Number of protection fields */
-
-    return 0;
-}
-
-static Property pflash_cfi01_properties[] = {
-    DEFINE_PROP_DRIVE("drive", struct pflash_t, bs),
-    DEFINE_PROP_UINT32("num-blocks", struct pflash_t, nb_blocs, 0),
-    DEFINE_PROP_UINT64("sector-length", struct pflash_t, sector_len, 0),
-    DEFINE_PROP_UINT8("width", struct pflash_t, width, 0),
-    DEFINE_PROP_UINT8("big-endian", struct pflash_t, be, 0),
-    DEFINE_PROP_UINT16("id0", struct pflash_t, ident0, 0),
-    DEFINE_PROP_UINT16("id1", struct pflash_t, ident1, 0),
-    DEFINE_PROP_UINT16("id2", struct pflash_t, ident2, 0),
-    DEFINE_PROP_UINT16("id3", struct pflash_t, ident3, 0),
-    DEFINE_PROP_STRING("name", struct pflash_t, name),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void pflash_cfi01_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = pflash_cfi01_init;
-    dc->props = pflash_cfi01_properties;
-}
-
-
-static const TypeInfo pflash_cfi01_info = {
-    .name           = "cfi.pflash01",
-    .parent         = TYPE_SYS_BUS_DEVICE,
-    .instance_size  = sizeof(struct pflash_t),
-    .class_init     = pflash_cfi01_class_init,
-};
-
-static void pflash_cfi01_register_types(void)
-{
-    type_register_static(&pflash_cfi01_info);
-}
-
-type_init(pflash_cfi01_register_types)
-
-pflash_t *pflash_cfi01_register(hwaddr base,
-                                DeviceState *qdev, const char *name,
-                                hwaddr size,
-                                BlockDriverState *bs,
-                                uint32_t sector_len, int nb_blocs, int width,
-                                uint16_t id0, uint16_t id1,
-                                uint16_t id2, uint16_t id3, int be)
-{
-    DeviceState *dev = qdev_create(NULL, "cfi.pflash01");
-    SysBusDevice *busdev = SYS_BUS_DEVICE(dev);
-    pflash_t *pfl = (pflash_t *)object_dynamic_cast(OBJECT(dev),
-                                                    "cfi.pflash01");
-
-    if (bs && qdev_prop_set_drive(dev, "drive", bs)) {
-        abort();
-    }
-    qdev_prop_set_uint32(dev, "num-blocks", nb_blocs);
-    qdev_prop_set_uint64(dev, "sector-length", sector_len);
-    qdev_prop_set_uint8(dev, "width", width);
-    qdev_prop_set_uint8(dev, "big-endian", !!be);
-    qdev_prop_set_uint16(dev, "id0", id0);
-    qdev_prop_set_uint16(dev, "id1", id1);
-    qdev_prop_set_uint16(dev, "id2", id2);
-    qdev_prop_set_uint16(dev, "id3", id3);
-    qdev_prop_set_string(dev, "name", name);
-    qdev_init_nofail(dev);
-
-    sysbus_mmio_map(busdev, 0, base);
-    return pfl;
-}
-
-MemoryRegion *pflash_cfi01_get_memory(pflash_t *fl)
-{
-    return &fl->mem;
-}
diff --git a/hw/pflash_cfi02.c b/hw/pflash_cfi02.c
deleted file mode 100644 (file)
index 37b4fcc..0000000
+++ /dev/null
@@ -1,787 +0,0 @@
-/*
- *  CFI parallel flash with AMD command set emulation
- *
- *  Copyright (c) 2005 Jocelyn Mayer
- *
- * 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/>.
- */
-
-/*
- * For now, this code can emulate flashes of 1, 2 or 4 bytes width.
- * Supported commands/modes are:
- * - flash read
- * - flash write
- * - flash ID read
- * - sector erase
- * - chip erase
- * - unlock bypass command
- * - CFI queries
- *
- * It does not support flash interleaving.
- * It does not implement boot blocs with reduced size
- * It does not implement software data protection as found in many real chips
- * It does not implement erase suspend/resume commands
- * It does not implement multiple sectors erase
- */
-
-#include "hw/hw.h"
-#include "hw/flash.h"
-#include "qemu/timer.h"
-#include "block/block.h"
-#include "exec/address-spaces.h"
-#include "qemu/host-utils.h"
-#include "hw/sysbus.h"
-
-//#define PFLASH_DEBUG
-#ifdef PFLASH_DEBUG
-#define DPRINTF(fmt, ...)                                  \
-do {                                                       \
-    fprintf(stderr "PFLASH: " fmt , ## __VA_ARGS__);       \
-} while (0)
-#else
-#define DPRINTF(fmt, ...) do { } while (0)
-#endif
-
-#define PFLASH_LAZY_ROMD_THRESHOLD 42
-
-struct pflash_t {
-    SysBusDevice busdev;
-    BlockDriverState *bs;
-    uint32_t sector_len;
-    uint32_t nb_blocs;
-    uint32_t chip_len;
-    uint8_t mappings;
-    uint8_t width;
-    uint8_t be;
-    int wcycle; /* if 0, the flash is read normally */
-    int bypass;
-    int ro;
-    uint8_t cmd;
-    uint8_t status;
-    /* FIXME: implement array device properties */
-    uint16_t ident0;
-    uint16_t ident1;
-    uint16_t ident2;
-    uint16_t ident3;
-    uint16_t unlock_addr0;
-    uint16_t unlock_addr1;
-    uint8_t cfi_len;
-    uint8_t cfi_table[0x52];
-    QEMUTimer *timer;
-    /* The device replicates the flash memory across its memory space.  Emulate
-     * that by having a container (.mem) filled with an array of aliases
-     * (.mem_mappings) pointing to the flash memory (.orig_mem).
-     */
-    MemoryRegion mem;
-    MemoryRegion *mem_mappings;    /* array; one per mapping */
-    MemoryRegion orig_mem;
-    int rom_mode;
-    int read_counter; /* used for lazy switch-back to rom mode */
-    char *name;
-    void *storage;
-};
-
-/*
- * Set up replicated mappings of the same region.
- */
-static void pflash_setup_mappings(pflash_t *pfl)
-{
-    unsigned i;
-    hwaddr size = memory_region_size(&pfl->orig_mem);
-
-    memory_region_init(&pfl->mem, "pflash", pfl->mappings * size);
-    pfl->mem_mappings = g_new(MemoryRegion, pfl->mappings);
-    for (i = 0; i < pfl->mappings; ++i) {
-        memory_region_init_alias(&pfl->mem_mappings[i], "pflash-alias",
-                                 &pfl->orig_mem, 0, size);
-        memory_region_add_subregion(&pfl->mem, i * size, &pfl->mem_mappings[i]);
-    }
-}
-
-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)
-{
-    pflash_t *pfl = opaque;
-
-    DPRINTF("%s: command %02x done\n", __func__, pfl->cmd);
-    /* Reset flash */
-    pfl->status ^= 0x80;
-    if (pfl->bypass) {
-        pfl->wcycle = 2;
-    } else {
-        pflash_register_memory(pfl, 1);
-        pfl->wcycle = 0;
-    }
-    pfl->cmd = 0;
-}
-
-static uint32_t pflash_read (pflash_t *pfl, hwaddr offset,
-                             int width, int be)
-{
-    hwaddr boff;
-    uint32_t ret;
-    uint8_t *p;
-
-    DPRINTF("%s: offset " TARGET_FMT_plx "\n", __func__, offset);
-    ret = -1;
-    /* Lazy reset to ROMD mode after a certain amount of read accesses */
-    if (!pfl->rom_mode && pfl->wcycle == 0 &&
-        ++pfl->read_counter > PFLASH_LAZY_ROMD_THRESHOLD) {
-        pflash_register_memory(pfl, 1);
-    }
-    offset &= pfl->chip_len - 1;
-    boff = offset & 0xFF;
-    if (pfl->width == 2)
-        boff = boff >> 1;
-    else if (pfl->width == 4)
-        boff = boff >> 2;
-    switch (pfl->cmd) {
-    default:
-        /* This should never happen : reset state & treat it as a read*/
-        DPRINTF("%s: unknown command state: %x\n", __func__, pfl->cmd);
-        pfl->wcycle = 0;
-        pfl->cmd = 0;
-        /* fall through to the read code */
-    case 0x80:
-        /* We accept reads during second unlock sequence... */
-    case 0x00:
-    flash_read:
-        /* Flash area read */
-        p = pfl->storage;
-        switch (width) {
-        case 1:
-            ret = p[offset];
-//            DPRINTF("%s: data offset %08x %02x\n", __func__, offset, ret);
-            break;
-        case 2:
-            if (be) {
-                ret = p[offset] << 8;
-                ret |= p[offset + 1];
-            } else {
-                ret = p[offset];
-                ret |= p[offset + 1] << 8;
-            }
-//            DPRINTF("%s: data offset %08x %04x\n", __func__, offset, ret);
-            break;
-        case 4:
-            if (be) {
-                ret = p[offset] << 24;
-                ret |= p[offset + 1] << 16;
-                ret |= p[offset + 2] << 8;
-                ret |= p[offset + 3];
-            } else {
-                ret = p[offset];
-                ret |= p[offset + 1] << 8;
-                ret |= p[offset + 2] << 16;
-                ret |= p[offset + 3] << 24;
-            }
-//            DPRINTF("%s: data offset %08x %08x\n", __func__, offset, ret);
-            break;
-        }
-        break;
-    case 0x90:
-        /* flash ID read */
-        switch (boff) {
-        case 0x00:
-        case 0x01:
-            ret = boff & 0x01 ? pfl->ident1 : pfl->ident0;
-            break;
-        case 0x02:
-            ret = 0x00; /* Pretend all sectors are unprotected */
-            break;
-        case 0x0E:
-        case 0x0F:
-            ret = boff & 0x01 ? pfl->ident3 : pfl->ident2;
-            if (ret == (uint8_t)-1) {
-                goto flash_read;
-            }
-            break;
-        default:
-            goto flash_read;
-        }
-        DPRINTF("%s: ID " TARGET_FMT_plx " %x\n", __func__, boff, ret);
-        break;
-    case 0xA0:
-    case 0x10:
-    case 0x30:
-        /* Status register read */
-        ret = pfl->status;
-        DPRINTF("%s: status %x\n", __func__, ret);
-        /* Toggle bit 6 */
-        pfl->status ^= 0x40;
-        break;
-    case 0x98:
-        /* CFI query mode */
-        if (boff > pfl->cfi_len)
-            ret = 0;
-        else
-            ret = pfl->cfi_table[boff];
-        break;
-    }
-
-    return ret;
-}
-
-/* update flash content on disk */
-static void pflash_update(pflash_t *pfl, int offset,
-                          int size)
-{
-    int offset_end;
-    if (pfl->bs) {
-        offset_end = offset + size;
-        /* round to sectors */
-        offset = offset >> 9;
-        offset_end = (offset_end + 511) >> 9;
-        bdrv_write(pfl->bs, offset, pfl->storage + (offset << 9),
-                   offset_end - offset);
-    }
-}
-
-static void pflash_write (pflash_t *pfl, hwaddr offset,
-                          uint32_t value, int width, int be)
-{
-    hwaddr boff;
-    uint8_t *p;
-    uint8_t cmd;
-
-    cmd = value;
-    if (pfl->cmd != 0xA0 && cmd == 0xF0) {
-#if 0
-        DPRINTF("%s: flash reset asked (%02x %02x)\n",
-                __func__, pfl->cmd, cmd);
-#endif
-        goto reset_flash;
-    }
-    DPRINTF("%s: offset " TARGET_FMT_plx " %08x %d %d\n", __func__,
-            offset, value, width, pfl->wcycle);
-    offset &= pfl->chip_len - 1;
-
-    DPRINTF("%s: offset " TARGET_FMT_plx " %08x %d\n", __func__,
-            offset, value, width);
-    boff = offset & (pfl->sector_len - 1);
-    if (pfl->width == 2)
-        boff = boff >> 1;
-    else if (pfl->width == 4)
-        boff = boff >> 2;
-    switch (pfl->wcycle) {
-    case 0:
-        /* Set the device in I/O access mode if required */
-        if (pfl->rom_mode)
-            pflash_register_memory(pfl, 0);
-        pfl->read_counter = 0;
-        /* We're in read mode */
-    check_unlock0:
-        if (boff == 0x55 && cmd == 0x98) {
-        enter_CFI_mode:
-            /* Enter CFI query mode */
-            pfl->wcycle = 7;
-            pfl->cmd = 0x98;
-            return;
-        }
-        if (boff != pfl->unlock_addr0 || cmd != 0xAA) {
-            DPRINTF("%s: unlock0 failed " TARGET_FMT_plx " %02x %04x\n",
-                    __func__, boff, cmd, pfl->unlock_addr0);
-            goto reset_flash;
-        }
-        DPRINTF("%s: unlock sequence started\n", __func__);
-        break;
-    case 1:
-        /* We started an unlock sequence */
-    check_unlock1:
-        if (boff != pfl->unlock_addr1 || cmd != 0x55) {
-            DPRINTF("%s: unlock1 failed " TARGET_FMT_plx " %02x\n", __func__,
-                    boff, cmd);
-            goto reset_flash;
-        }
-        DPRINTF("%s: unlock sequence done\n", __func__);
-        break;
-    case 2:
-        /* We finished an unlock sequence */
-        if (!pfl->bypass && boff != pfl->unlock_addr0) {
-            DPRINTF("%s: command failed " TARGET_FMT_plx " %02x\n", __func__,
-                    boff, cmd);
-            goto reset_flash;
-        }
-        switch (cmd) {
-        case 0x20:
-            pfl->bypass = 1;
-            goto do_bypass;
-        case 0x80:
-        case 0x90:
-        case 0xA0:
-            pfl->cmd = cmd;
-            DPRINTF("%s: starting command %02x\n", __func__, cmd);
-            break;
-        default:
-            DPRINTF("%s: unknown command %02x\n", __func__, cmd);
-            goto reset_flash;
-        }
-        break;
-    case 3:
-        switch (pfl->cmd) {
-        case 0x80:
-            /* We need another unlock sequence */
-            goto check_unlock0;
-        case 0xA0:
-            DPRINTF("%s: write data offset " TARGET_FMT_plx " %08x %d\n",
-                    __func__, offset, value, width);
-            p = pfl->storage;
-            if (!pfl->ro) {
-                switch (width) {
-                case 1:
-                    p[offset] &= value;
-                    pflash_update(pfl, offset, 1);
-                    break;
-                case 2:
-                    if (be) {
-                        p[offset] &= value >> 8;
-                        p[offset + 1] &= value;
-                    } else {
-                        p[offset] &= value;
-                        p[offset + 1] &= value >> 8;
-                    }
-                    pflash_update(pfl, offset, 2);
-                    break;
-                case 4:
-                    if (be) {
-                        p[offset] &= value >> 24;
-                        p[offset + 1] &= value >> 16;
-                        p[offset + 2] &= value >> 8;
-                        p[offset + 3] &= value;
-                    } else {
-                        p[offset] &= value;
-                        p[offset + 1] &= value >> 8;
-                        p[offset + 2] &= value >> 16;
-                        p[offset + 3] &= value >> 24;
-                    }
-                    pflash_update(pfl, offset, 4);
-                    break;
-                }
-            }
-            pfl->status = 0x00 | ~(value & 0x80);
-            /* Let's pretend write is immediate */
-            if (pfl->bypass)
-                goto do_bypass;
-            goto reset_flash;
-        case 0x90:
-            if (pfl->bypass && cmd == 0x00) {
-                /* Unlock bypass reset */
-                goto reset_flash;
-            }
-            /* We can enter CFI query mode from autoselect mode */
-            if (boff == 0x55 && cmd == 0x98)
-                goto enter_CFI_mode;
-            /* No break here */
-        default:
-            DPRINTF("%s: invalid write for command %02x\n",
-                    __func__, pfl->cmd);
-            goto reset_flash;
-        }
-    case 4:
-        switch (pfl->cmd) {
-        case 0xA0:
-            /* Ignore writes while flash data write is occurring */
-            /* As we suppose write is immediate, this should never happen */
-            return;
-        case 0x80:
-            goto check_unlock1;
-        default:
-            /* Should never happen */
-            DPRINTF("%s: invalid command state %02x (wc 4)\n",
-                    __func__, pfl->cmd);
-            goto reset_flash;
-        }
-        break;
-    case 5:
-        switch (cmd) {
-        case 0x10:
-            if (boff != pfl->unlock_addr0) {
-                DPRINTF("%s: chip erase: invalid address " TARGET_FMT_plx "\n",
-                        __func__, offset);
-                goto reset_flash;
-            }
-            /* Chip erase */
-            DPRINTF("%s: start chip erase\n", __func__);
-            if (!pfl->ro) {
-                memset(pfl->storage, 0xFF, pfl->chip_len);
-                pflash_update(pfl, 0, pfl->chip_len);
-            }
-            pfl->status = 0x00;
-            /* Let's wait 5 seconds before chip erase is done */
-            qemu_mod_timer(pfl->timer,
-                           qemu_get_clock_ns(vm_clock) + (get_ticks_per_sec() * 5));
-            break;
-        case 0x30:
-            /* Sector erase */
-            p = pfl->storage;
-            offset &= ~(pfl->sector_len - 1);
-            DPRINTF("%s: start sector erase at " TARGET_FMT_plx "\n", __func__,
-                    offset);
-            if (!pfl->ro) {
-                memset(p + offset, 0xFF, pfl->sector_len);
-                pflash_update(pfl, offset, pfl->sector_len);
-            }
-            pfl->status = 0x00;
-            /* Let's wait 1/2 second before sector erase is done */
-            qemu_mod_timer(pfl->timer,
-                           qemu_get_clock_ns(vm_clock) + (get_ticks_per_sec() / 2));
-            break;
-        default:
-            DPRINTF("%s: invalid command %02x (wc 5)\n", __func__, cmd);
-            goto reset_flash;
-        }
-        pfl->cmd = cmd;
-        break;
-    case 6:
-        switch (pfl->cmd) {
-        case 0x10:
-            /* Ignore writes during chip erase */
-            return;
-        case 0x30:
-            /* Ignore writes during sector erase */
-            return;
-        default:
-            /* Should never happen */
-            DPRINTF("%s: invalid command state %02x (wc 6)\n",
-                    __func__, pfl->cmd);
-            goto reset_flash;
-        }
-        break;
-    case 7: /* Special value for CFI queries */
-        DPRINTF("%s: invalid write in CFI query mode\n", __func__);
-        goto reset_flash;
-    default:
-        /* Should never happen */
-        DPRINTF("%s: invalid write state (wc 7)\n",  __func__);
-        goto reset_flash;
-    }
-    pfl->wcycle++;
-
-    return;
-
-    /* Reset flash */
- reset_flash:
-    pfl->bypass = 0;
-    pfl->wcycle = 0;
-    pfl->cmd = 0;
-    return;
-
- do_bypass:
-    pfl->wcycle = 2;
-    pfl->cmd = 0;
-}
-
-
-static uint32_t pflash_readb_be(void *opaque, hwaddr addr)
-{
-    return pflash_read(opaque, addr, 1, 1);
-}
-
-static uint32_t pflash_readb_le(void *opaque, hwaddr addr)
-{
-    return pflash_read(opaque, addr, 1, 0);
-}
-
-static uint32_t pflash_readw_be(void *opaque, hwaddr addr)
-{
-    pflash_t *pfl = opaque;
-
-    return pflash_read(pfl, addr, 2, 1);
-}
-
-static uint32_t pflash_readw_le(void *opaque, hwaddr addr)
-{
-    pflash_t *pfl = opaque;
-
-    return pflash_read(pfl, addr, 2, 0);
-}
-
-static uint32_t pflash_readl_be(void *opaque, hwaddr addr)
-{
-    pflash_t *pfl = opaque;
-
-    return pflash_read(pfl, addr, 4, 1);
-}
-
-static uint32_t pflash_readl_le(void *opaque, hwaddr addr)
-{
-    pflash_t *pfl = opaque;
-
-    return pflash_read(pfl, addr, 4, 0);
-}
-
-static void pflash_writeb_be(void *opaque, hwaddr addr,
-                             uint32_t value)
-{
-    pflash_write(opaque, addr, value, 1, 1);
-}
-
-static void pflash_writeb_le(void *opaque, hwaddr addr,
-                             uint32_t value)
-{
-    pflash_write(opaque, addr, value, 1, 0);
-}
-
-static void pflash_writew_be(void *opaque, hwaddr addr,
-                             uint32_t value)
-{
-    pflash_t *pfl = opaque;
-
-    pflash_write(pfl, addr, value, 2, 1);
-}
-
-static void pflash_writew_le(void *opaque, hwaddr addr,
-                             uint32_t value)
-{
-    pflash_t *pfl = opaque;
-
-    pflash_write(pfl, addr, value, 2, 0);
-}
-
-static void pflash_writel_be(void *opaque, hwaddr addr,
-                             uint32_t value)
-{
-    pflash_t *pfl = opaque;
-
-    pflash_write(pfl, addr, value, 4, 1);
-}
-
-static void pflash_writel_le(void *opaque, hwaddr addr,
-                             uint32_t value)
-{
-    pflash_t *pfl = opaque;
-
-    pflash_write(pfl, addr, value, 4, 0);
-}
-
-static const MemoryRegionOps pflash_cfi02_ops_be = {
-    .old_mmio = {
-        .read = { pflash_readb_be, pflash_readw_be, pflash_readl_be, },
-        .write = { pflash_writeb_be, pflash_writew_be, pflash_writel_be, },
-    },
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static const MemoryRegionOps pflash_cfi02_ops_le = {
-    .old_mmio = {
-        .read = { pflash_readb_le, pflash_readw_le, pflash_readl_le, },
-        .write = { pflash_writeb_le, pflash_writew_le, pflash_writel_le, },
-    },
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int pflash_cfi02_init(SysBusDevice *dev)
-{
-    pflash_t *pfl = FROM_SYSBUS(typeof(*pfl), dev);
-    uint32_t chip_len;
-    int ret;
-
-    chip_len = pfl->sector_len * pfl->nb_blocs;
-    /* XXX: to be fixed */
-#if 0
-    if (total_len != (8 * 1024 * 1024) && total_len != (16 * 1024 * 1024) &&
-        total_len != (32 * 1024 * 1024) && total_len != (64 * 1024 * 1024))
-        return NULL;
-#endif
-
-    memory_region_init_rom_device(&pfl->orig_mem, pfl->be ?
-                                  &pflash_cfi02_ops_be : &pflash_cfi02_ops_le,
-                                  pfl, pfl->name, chip_len);
-    vmstate_register_ram(&pfl->orig_mem, DEVICE(pfl));
-    pfl->storage = memory_region_get_ram_ptr(&pfl->orig_mem);
-    pfl->chip_len = chip_len;
-    if (pfl->bs) {
-        /* read the initial flash content */
-        ret = bdrv_read(pfl->bs, 0, pfl->storage, chip_len >> 9);
-        if (ret < 0) {
-            g_free(pfl);
-            return 1;
-        }
-    }
-
-    pflash_setup_mappings(pfl);
-    pfl->rom_mode = 1;
-    sysbus_init_mmio(dev, &pfl->mem);
-
-    if (pfl->bs) {
-        pfl->ro = bdrv_is_read_only(pfl->bs);
-    } else {
-        pfl->ro = 0;
-    }
-
-    pfl->timer = qemu_new_timer_ns(vm_clock, pflash_timer, pfl);
-    pfl->wcycle = 0;
-    pfl->cmd = 0;
-    pfl->status = 0;
-    /* Hardcoded CFI table (mostly from SG29 Spansion flash) */
-    pfl->cfi_len = 0x52;
-    /* Standard "QRY" string */
-    pfl->cfi_table[0x10] = 'Q';
-    pfl->cfi_table[0x11] = 'R';
-    pfl->cfi_table[0x12] = 'Y';
-    /* Command set (AMD/Fujitsu) */
-    pfl->cfi_table[0x13] = 0x02;
-    pfl->cfi_table[0x14] = 0x00;
-    /* Primary extended table address */
-    pfl->cfi_table[0x15] = 0x31;
-    pfl->cfi_table[0x16] = 0x00;
-    /* Alternate command set (none) */
-    pfl->cfi_table[0x17] = 0x00;
-    pfl->cfi_table[0x18] = 0x00;
-    /* Alternate extended table (none) */
-    pfl->cfi_table[0x19] = 0x00;
-    pfl->cfi_table[0x1A] = 0x00;
-    /* Vcc min */
-    pfl->cfi_table[0x1B] = 0x27;
-    /* Vcc max */
-    pfl->cfi_table[0x1C] = 0x36;
-    /* Vpp min (no Vpp pin) */
-    pfl->cfi_table[0x1D] = 0x00;
-    /* Vpp max (no Vpp pin) */
-    pfl->cfi_table[0x1E] = 0x00;
-    /* Reserved */
-    pfl->cfi_table[0x1F] = 0x07;
-    /* Timeout for min size buffer write (NA) */
-    pfl->cfi_table[0x20] = 0x00;
-    /* Typical timeout for block erase (512 ms) */
-    pfl->cfi_table[0x21] = 0x09;
-    /* Typical timeout for full chip erase (4096 ms) */
-    pfl->cfi_table[0x22] = 0x0C;
-    /* Reserved */
-    pfl->cfi_table[0x23] = 0x01;
-    /* Max timeout for buffer write (NA) */
-    pfl->cfi_table[0x24] = 0x00;
-    /* Max timeout for block erase */
-    pfl->cfi_table[0x25] = 0x0A;
-    /* Max timeout for chip erase */
-    pfl->cfi_table[0x26] = 0x0D;
-    /* Device size */
-    pfl->cfi_table[0x27] = ctz32(chip_len);
-    /* Flash device interface (8 & 16 bits) */
-    pfl->cfi_table[0x28] = 0x02;
-    pfl->cfi_table[0x29] = 0x00;
-    /* Max number of bytes in multi-bytes write */
-    /* XXX: disable buffered write as it's not supported */
-    //    pfl->cfi_table[0x2A] = 0x05;
-    pfl->cfi_table[0x2A] = 0x00;
-    pfl->cfi_table[0x2B] = 0x00;
-    /* Number of erase block regions (uniform) */
-    pfl->cfi_table[0x2C] = 0x01;
-    /* Erase block region 1 */
-    pfl->cfi_table[0x2D] = pfl->nb_blocs - 1;
-    pfl->cfi_table[0x2E] = (pfl->nb_blocs - 1) >> 8;
-    pfl->cfi_table[0x2F] = pfl->sector_len >> 8;
-    pfl->cfi_table[0x30] = pfl->sector_len >> 16;
-
-    /* Extended */
-    pfl->cfi_table[0x31] = 'P';
-    pfl->cfi_table[0x32] = 'R';
-    pfl->cfi_table[0x33] = 'I';
-
-    pfl->cfi_table[0x34] = '1';
-    pfl->cfi_table[0x35] = '0';
-
-    pfl->cfi_table[0x36] = 0x00;
-    pfl->cfi_table[0x37] = 0x00;
-    pfl->cfi_table[0x38] = 0x00;
-    pfl->cfi_table[0x39] = 0x00;
-
-    pfl->cfi_table[0x3a] = 0x00;
-
-    pfl->cfi_table[0x3b] = 0x00;
-    pfl->cfi_table[0x3c] = 0x00;
-
-    return 0;
-}
-
-static Property pflash_cfi02_properties[] = {
-    DEFINE_PROP_DRIVE("drive", struct pflash_t, bs),
-    DEFINE_PROP_UINT32("num-blocks", struct pflash_t, nb_blocs, 0),
-    DEFINE_PROP_UINT32("sector-length", struct pflash_t, sector_len, 0),
-    DEFINE_PROP_UINT8("width", struct pflash_t, width, 0),
-    DEFINE_PROP_UINT8("mappings", struct pflash_t, mappings, 0),
-    DEFINE_PROP_UINT8("big-endian", struct pflash_t, be, 0),
-    DEFINE_PROP_UINT16("id0", struct pflash_t, ident0, 0),
-    DEFINE_PROP_UINT16("id1", struct pflash_t, ident1, 0),
-    DEFINE_PROP_UINT16("id2", struct pflash_t, ident2, 0),
-    DEFINE_PROP_UINT16("id3", struct pflash_t, ident3, 0),
-    DEFINE_PROP_UINT16("unlock-addr0", struct pflash_t, unlock_addr0, 0),
-    DEFINE_PROP_UINT16("unlock-addr1", struct pflash_t, unlock_addr1, 0),
-    DEFINE_PROP_STRING("name", struct pflash_t, name),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void pflash_cfi02_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = pflash_cfi02_init;
-    dc->props = pflash_cfi02_properties;
-}
-
-static const TypeInfo pflash_cfi02_info = {
-    .name           = "cfi.pflash02",
-    .parent         = TYPE_SYS_BUS_DEVICE,
-    .instance_size  = sizeof(struct pflash_t),
-    .class_init     = pflash_cfi02_class_init,
-};
-
-static void pflash_cfi02_register_types(void)
-{
-    type_register_static(&pflash_cfi02_info);
-}
-
-type_init(pflash_cfi02_register_types)
-
-pflash_t *pflash_cfi02_register(hwaddr base,
-                                DeviceState *qdev, const char *name,
-                                hwaddr size,
-                                BlockDriverState *bs, uint32_t sector_len,
-                                int nb_blocs, int nb_mappings, int width,
-                                uint16_t id0, uint16_t id1,
-                                uint16_t id2, uint16_t id3,
-                                uint16_t unlock_addr0, uint16_t unlock_addr1,
-                                int be)
-{
-    DeviceState *dev = qdev_create(NULL, "cfi.pflash02");
-    SysBusDevice *busdev = SYS_BUS_DEVICE(dev);
-    pflash_t *pfl = (pflash_t *)object_dynamic_cast(OBJECT(dev),
-                                                    "cfi.pflash02");
-
-    if (bs && qdev_prop_set_drive(dev, "drive", bs)) {
-        abort();
-    }
-    qdev_prop_set_uint32(dev, "num-blocks", nb_blocs);
-    qdev_prop_set_uint32(dev, "sector-length", sector_len);
-    qdev_prop_set_uint8(dev, "width", width);
-    qdev_prop_set_uint8(dev, "mappings", nb_mappings);
-    qdev_prop_set_uint8(dev, "big-endian", !!be);
-    qdev_prop_set_uint16(dev, "id0", id0);
-    qdev_prop_set_uint16(dev, "id1", id1);
-    qdev_prop_set_uint16(dev, "id2", id2);
-    qdev_prop_set_uint16(dev, "id3", id3);
-    qdev_prop_set_uint16(dev, "unlock-addr0", unlock_addr0);
-    qdev_prop_set_uint16(dev, "unlock-addr1", unlock_addr1);
-    qdev_prop_set_string(dev, "name", name);
-    qdev_init_nofail(dev);
-
-    sysbus_mmio_map(busdev, 0, base);
-    return pfl;
-}
diff --git a/hw/piix4.c b/hw/piix4.c
deleted file mode 100644 (file)
index 0f5cd01..0000000
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * QEMU PIIX4 PCI Bridge Emulation
- *
- * Copyright (c) 2006 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.
- */
-
-#include "hw/hw.h"
-#include "hw/pc.h"
-#include "hw/pci/pci.h"
-#include "hw/isa.h"
-#include "hw/sysbus.h"
-
-PCIDevice *piix4_dev;
-
-typedef struct PIIX4State {
-    PCIDevice dev;
-} PIIX4State;
-
-static void piix4_reset(void *opaque)
-{
-    PIIX4State *d = opaque;
-    uint8_t *pci_conf = d->dev.config;
-
-    pci_conf[0x04] = 0x07; // master, memory and I/O
-    pci_conf[0x05] = 0x00;
-    pci_conf[0x06] = 0x00;
-    pci_conf[0x07] = 0x02; // PCI_status_devsel_medium
-    pci_conf[0x4c] = 0x4d;
-    pci_conf[0x4e] = 0x03;
-    pci_conf[0x4f] = 0x00;
-    pci_conf[0x60] = 0x0a; // PCI A -> IRQ 10
-    pci_conf[0x61] = 0x0a; // PCI B -> IRQ 10
-    pci_conf[0x62] = 0x0b; // PCI C -> IRQ 11
-    pci_conf[0x63] = 0x0b; // PCI D -> IRQ 11
-    pci_conf[0x69] = 0x02;
-    pci_conf[0x70] = 0x80;
-    pci_conf[0x76] = 0x0c;
-    pci_conf[0x77] = 0x0c;
-    pci_conf[0x78] = 0x02;
-    pci_conf[0x79] = 0x00;
-    pci_conf[0x80] = 0x00;
-    pci_conf[0x82] = 0x00;
-    pci_conf[0xa0] = 0x08;
-    pci_conf[0xa2] = 0x00;
-    pci_conf[0xa3] = 0x00;
-    pci_conf[0xa4] = 0x00;
-    pci_conf[0xa5] = 0x00;
-    pci_conf[0xa6] = 0x00;
-    pci_conf[0xa7] = 0x00;
-    pci_conf[0xa8] = 0x0f;
-    pci_conf[0xaa] = 0x00;
-    pci_conf[0xab] = 0x00;
-    pci_conf[0xac] = 0x00;
-    pci_conf[0xae] = 0x00;
-}
-
-static const VMStateDescription vmstate_piix4 = {
-    .name = "PIIX4",
-    .version_id = 2,
-    .minimum_version_id = 2,
-    .minimum_version_id_old = 2,
-    .fields      = (VMStateField[]) {
-        VMSTATE_PCI_DEVICE(dev, PIIX4State),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static int piix4_initfn(PCIDevice *dev)
-{
-    PIIX4State *d = DO_UPCAST(PIIX4State, dev, dev);
-
-    isa_bus_new(&d->dev.qdev, pci_address_space_io(dev));
-    piix4_dev = &d->dev;
-    qemu_register_reset(piix4_reset, d);
-    return 0;
-}
-
-int piix4_init(PCIBus *bus, ISABus **isa_bus, int devfn)
-{
-    PCIDevice *d;
-
-    d = pci_create_simple_multifunction(bus, devfn, true, "PIIX4");
-    *isa_bus = DO_UPCAST(ISABus, qbus, qdev_get_child_bus(&d->qdev, "isa.0"));
-    return d->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;
-    k->init = piix4_initfn;
-    k->vendor_id = PCI_VENDOR_ID_INTEL;
-    k->device_id = PCI_DEVICE_ID_INTEL_82371AB_0;
-    k->class_id = PCI_CLASS_BRIDGE_ISA;
-    dc->desc = "ISA bridge";
-    dc->no_user = 1;
-    dc->vmsd = &vmstate_piix4;
-}
-
-static const TypeInfo piix4_info = {
-    .name          = "PIIX4",
-    .parent        = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(PIIX4State),
-    .class_init    = piix4_class_init,
-};
-
-static void piix4_register_types(void)
-{
-    type_register_static(&piix4_info);
-}
-
-type_init(piix4_register_types)
diff --git a/hw/piix_pci.c b/hw/piix_pci.c
deleted file mode 100644 (file)
index 83fcfa4..0000000
+++ /dev/null
@@ -1,657 +0,0 @@
-/*
- * QEMU i440FX/PIIX3 PCI Bridge Emulation
- *
- * Copyright (c) 2006 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.
- */
-
-#include "hw/hw.h"
-#include "hw/pc.h"
-#include "hw/pci/pci.h"
-#include "hw/pci/pci_host.h"
-#include "hw/isa.h"
-#include "hw/sysbus.h"
-#include "qemu/range.h"
-#include "hw/xen.h"
-#include "hw/pam.h"
-#include "sysemu/sysemu.h"
-
-/*
- * I440FX chipset data sheet.
- * http://download.intel.com/design/chipsets/datashts/29054901.pdf
- */
-
-typedef struct I440FXState {
-    PCIHostState parent_obj;
-} I440FXState;
-
-#define PIIX_NUM_PIC_IRQS       16      /* i8259 * 2 */
-#define PIIX_NUM_PIRQS          4ULL    /* PIRQ[A-D] */
-#define XEN_PIIX_NUM_PIRQS      128ULL
-#define PIIX_PIRQC              0x60
-
-/*
- * Reset Control Register: PCI-accessible ISA-Compatible Register at address
- * 0xcf9, provided by the PCI/ISA bridge (PIIX3 PCI function 0, 8086:7000).
- */
-#define RCR_IOPORT 0xcf9
-
-typedef struct PIIX3State {
-    PCIDevice dev;
-
-    /*
-     * bitmap to track pic levels.
-     * The pic level is the logical OR of all the PCI irqs mapped to it
-     * So one PIC level is tracked by PIIX_NUM_PIRQS bits.
-     *
-     * PIRQ is mapped to PIC pins, we track it by
-     * PIIX_NUM_PIRQS * PIIX_NUM_PIC_IRQS = 64 bits with
-     * pic_irq * PIIX_NUM_PIRQS + pirq
-     */
-#if PIIX_NUM_PIC_IRQS * PIIX_NUM_PIRQS > 64
-#error "unable to encode pic state in 64bit in pic_levels."
-#endif
-    uint64_t pic_levels;
-
-    qemu_irq *pic;
-
-    /* This member isn't used. Just for save/load compatibility */
-    int32_t pci_irq_levels_vmstate[PIIX_NUM_PIRQS];
-
-    /* Reset Control Register contents */
-    uint8_t rcr;
-
-    /* IO memory region for Reset Control Register (RCR_IOPORT) */
-    MemoryRegion rcr_mem;
-} PIIX3State;
-
-#define TYPE_I440FX_PCI_DEVICE "i440FX"
-#define I440FX_PCI_DEVICE(obj) \
-    OBJECT_CHECK(PCII440FXState, (obj), TYPE_I440FX_PCI_DEVICE)
-
-struct PCII440FXState {
-    PCIDevice dev;
-    MemoryRegion *system_memory;
-    MemoryRegion *pci_address_space;
-    MemoryRegion *ram_memory;
-    MemoryRegion pci_hole;
-    MemoryRegion pci_hole_64bit;
-    PAMMemoryRegion pam_regions[13];
-    MemoryRegion smram_region;
-    uint8_t smm_enabled;
-};
-
-
-#define I440FX_PAM      0x59
-#define I440FX_PAM_SIZE 7
-#define I440FX_SMRAM    0x72
-
-static void piix3_set_irq(void *opaque, int pirq, int level);
-static PCIINTxRoute piix3_route_intx_pin_to_irq(void *opaque, int pci_intx);
-static void piix3_write_config_xen(PCIDevice *dev,
-                               uint32_t address, uint32_t val, int len);
-
-/* return the global irq number corresponding to a given device irq
-   pin. We could also use the bus number to have a more precise
-   mapping. */
-static int pci_slot_get_pirq(PCIDevice *pci_dev, int pci_intx)
-{
-    int slot_addend;
-    slot_addend = (pci_dev->devfn >> 3) - 1;
-    return (pci_intx + slot_addend) & 3;
-}
-
-static void i440fx_update_memory_mappings(PCII440FXState *d)
-{
-    int i;
-
-    memory_region_transaction_begin();
-    for (i = 0; i < 13; i++) {
-        pam_update(&d->pam_regions[i], i,
-                   d->dev.config[I440FX_PAM + ((i + 1) / 2)]);
-    }
-    smram_update(&d->smram_region, d->dev.config[I440FX_SMRAM], d->smm_enabled);
-    memory_region_transaction_commit();
-}
-
-static void i440fx_set_smm(int val, void *arg)
-{
-    PCII440FXState *d = arg;
-
-    memory_region_transaction_begin();
-    smram_set_smm(&d->smm_enabled, val, d->dev.config[I440FX_SMRAM],
-                  &d->smram_region);
-    memory_region_transaction_commit();
-}
-
-
-static void i440fx_write_config(PCIDevice *dev,
-                                uint32_t address, uint32_t val, int len)
-{
-    PCII440FXState *d = I440FX_PCI_DEVICE(dev);
-
-    /* XXX: implement SMRAM.D_LOCK */
-    pci_default_write_config(dev, address, val, len);
-    if (ranges_overlap(address, len, I440FX_PAM, I440FX_PAM_SIZE) ||
-        range_covers_byte(address, len, I440FX_SMRAM)) {
-        i440fx_update_memory_mappings(d);
-    }
-}
-
-static int i440fx_load_old(QEMUFile* f, void *opaque, int version_id)
-{
-    PCII440FXState *d = opaque;
-    int ret, i;
-
-    ret = pci_device_load(&d->dev, f);
-    if (ret < 0)
-        return ret;
-    i440fx_update_memory_mappings(d);
-    qemu_get_8s(f, &d->smm_enabled);
-
-    if (version_id == 2) {
-        for (i = 0; i < PIIX_NUM_PIRQS; i++) {
-            qemu_get_be32(f); /* dummy load for compatibility */
-        }
-    }
-
-    return 0;
-}
-
-static int i440fx_post_load(void *opaque, int version_id)
-{
-    PCII440FXState *d = opaque;
-
-    i440fx_update_memory_mappings(d);
-    return 0;
-}
-
-static const VMStateDescription vmstate_i440fx = {
-    .name = "I440FX",
-    .version_id = 3,
-    .minimum_version_id = 3,
-    .minimum_version_id_old = 1,
-    .load_state_old = i440fx_load_old,
-    .post_load = i440fx_post_load,
-    .fields      = (VMStateField []) {
-        VMSTATE_PCI_DEVICE(dev, PCII440FXState),
-        VMSTATE_UINT8(smm_enabled, PCII440FXState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static int i440fx_pcihost_initfn(SysBusDevice *dev)
-{
-    PCIHostState *s = PCI_HOST_BRIDGE(dev);
-
-    memory_region_init_io(&s->conf_mem, &pci_host_conf_le_ops, s,
-                          "pci-conf-idx", 4);
-    sysbus_add_io(dev, 0xcf8, &s->conf_mem);
-    sysbus_init_ioports(&s->busdev, 0xcf8, 4);
-
-    memory_region_init_io(&s->data_mem, &pci_host_data_le_ops, s,
-                          "pci-conf-data", 4);
-    sysbus_add_io(dev, 0xcfc, &s->data_mem);
-    sysbus_init_ioports(&s->busdev, 0xcfc, 4);
-
-    return 0;
-}
-
-static int i440fx_initfn(PCIDevice *dev)
-{
-    PCII440FXState *d = I440FX_PCI_DEVICE(dev);
-
-    d->dev.config[I440FX_SMRAM] = 0x02;
-
-    cpu_smm_register(&i440fx_set_smm, d);
-    return 0;
-}
-
-static PCIBus *i440fx_common_init(const char *device_name,
-                                  PCII440FXState **pi440fx_state,
-                                  int *piix3_devfn,
-                                  ISABus **isa_bus, qemu_irq *pic,
-                                  MemoryRegion *address_space_mem,
-                                  MemoryRegion *address_space_io,
-                                  ram_addr_t ram_size,
-                                  hwaddr pci_hole_start,
-                                  hwaddr pci_hole_size,
-                                  hwaddr pci_hole64_start,
-                                  hwaddr pci_hole64_size,
-                                  MemoryRegion *pci_address_space,
-                                  MemoryRegion *ram_memory)
-{
-    DeviceState *dev;
-    PCIBus *b;
-    PCIDevice *d;
-    PCIHostState *s;
-    PIIX3State *piix3;
-    PCII440FXState *f;
-    unsigned i;
-
-    dev = qdev_create(NULL, "i440FX-pcihost");
-    s = PCI_HOST_BRIDGE(dev);
-    b = pci_bus_new(dev, NULL, pci_address_space,
-                    address_space_io, 0, TYPE_PCI_BUS);
-    s->bus = b;
-    object_property_add_child(qdev_get_machine(), "i440fx", OBJECT(dev), NULL);
-    qdev_init_nofail(dev);
-
-    d = pci_create_simple(b, 0, device_name);
-    *pi440fx_state = I440FX_PCI_DEVICE(d);
-    f = *pi440fx_state;
-    f->system_memory = address_space_mem;
-    f->pci_address_space = pci_address_space;
-    f->ram_memory = ram_memory;
-    memory_region_init_alias(&f->pci_hole, "pci-hole", f->pci_address_space,
-                             pci_hole_start, pci_hole_size);
-    memory_region_add_subregion(f->system_memory, pci_hole_start, &f->pci_hole);
-    memory_region_init_alias(&f->pci_hole_64bit, "pci-hole64",
-                             f->pci_address_space,
-                             pci_hole64_start, pci_hole64_size);
-    if (pci_hole64_size) {
-        memory_region_add_subregion(f->system_memory, pci_hole64_start,
-                                    &f->pci_hole_64bit);
-    }
-    memory_region_init_alias(&f->smram_region, "smram-region",
-                             f->pci_address_space, 0xa0000, 0x20000);
-    memory_region_add_subregion_overlap(f->system_memory, 0xa0000,
-                                        &f->smram_region, 1);
-    memory_region_set_enabled(&f->smram_region, false);
-    init_pam(f->ram_memory, f->system_memory, f->pci_address_space,
-             &f->pam_regions[0], PAM_BIOS_BASE, PAM_BIOS_SIZE);
-    for (i = 0; i < 12; ++i) {
-        init_pam(f->ram_memory, f->system_memory, f->pci_address_space,
-                 &f->pam_regions[i+1], PAM_EXPAN_BASE + i * PAM_EXPAN_SIZE,
-                 PAM_EXPAN_SIZE);
-    }
-
-    /* Xen supports additional interrupt routes from the PCI devices to
-     * the IOAPIC: the four pins of each PCI device on the bus are also
-     * connected to the IOAPIC directly.
-     * These additional routes can be discovered through ACPI. */
-    if (xen_enabled()) {
-        piix3 = DO_UPCAST(PIIX3State, dev,
-                pci_create_simple_multifunction(b, -1, true, "PIIX3-xen"));
-        pci_bus_irqs(b, xen_piix3_set_irq, xen_pci_slot_get_pirq,
-                piix3, XEN_PIIX_NUM_PIRQS);
-    } else {
-        piix3 = DO_UPCAST(PIIX3State, dev,
-                pci_create_simple_multifunction(b, -1, true, "PIIX3"));
-        pci_bus_irqs(b, piix3_set_irq, pci_slot_get_pirq, piix3,
-                PIIX_NUM_PIRQS);
-        pci_bus_set_route_irq_fn(b, piix3_route_intx_pin_to_irq);
-    }
-    piix3->pic = pic;
-    *isa_bus = ISA_BUS(qdev_get_child_bus(DEVICE(piix3), "isa.0"));
-
-    *piix3_devfn = piix3->dev.devfn;
-
-    ram_size = ram_size / 8 / 1024 / 1024;
-    if (ram_size > 255)
-        ram_size = 255;
-    (*pi440fx_state)->dev.config[0x57]=ram_size;
-
-    i440fx_update_memory_mappings(f);
-
-    return b;
-}
-
-PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix3_devfn,
-                    ISABus **isa_bus, qemu_irq *pic,
-                    MemoryRegion *address_space_mem,
-                    MemoryRegion *address_space_io,
-                    ram_addr_t ram_size,
-                    hwaddr pci_hole_start,
-                    hwaddr pci_hole_size,
-                    hwaddr pci_hole64_start,
-                    hwaddr pci_hole64_size,
-                    MemoryRegion *pci_memory, MemoryRegion *ram_memory)
-
-{
-    PCIBus *b;
-
-    b = i440fx_common_init(TYPE_I440FX_PCI_DEVICE, pi440fx_state,
-                           piix3_devfn, isa_bus, pic,
-                           address_space_mem, address_space_io, ram_size,
-                           pci_hole_start, pci_hole_size,
-                           pci_hole64_start, pci_hole64_size,
-                           pci_memory, ram_memory);
-    return b;
-}
-
-/* PIIX3 PCI to ISA bridge */
-static void piix3_set_irq_pic(PIIX3State *piix3, int pic_irq)
-{
-    qemu_set_irq(piix3->pic[pic_irq],
-                 !!(piix3->pic_levels &
-                    (((1ULL << PIIX_NUM_PIRQS) - 1) <<
-                     (pic_irq * PIIX_NUM_PIRQS))));
-}
-
-static void piix3_set_irq_level(PIIX3State *piix3, int pirq, int level)
-{
-    int pic_irq;
-    uint64_t mask;
-
-    pic_irq = piix3->dev.config[PIIX_PIRQC + pirq];
-    if (pic_irq >= PIIX_NUM_PIC_IRQS) {
-        return;
-    }
-
-    mask = 1ULL << ((pic_irq * PIIX_NUM_PIRQS) + pirq);
-    piix3->pic_levels &= ~mask;
-    piix3->pic_levels |= mask * !!level;
-
-    piix3_set_irq_pic(piix3, pic_irq);
-}
-
-static void piix3_set_irq(void *opaque, int pirq, int level)
-{
-    PIIX3State *piix3 = opaque;
-    piix3_set_irq_level(piix3, pirq, level);
-}
-
-static PCIINTxRoute piix3_route_intx_pin_to_irq(void *opaque, int pin)
-{
-    PIIX3State *piix3 = opaque;
-    int irq = piix3->dev.config[PIIX_PIRQC + pin];
-    PCIINTxRoute route;
-
-    if (irq < PIIX_NUM_PIC_IRQS) {
-        route.mode = PCI_INTX_ENABLED;
-        route.irq = irq;
-    } else {
-        route.mode = PCI_INTX_DISABLED;
-        route.irq = -1;
-    }
-    return route;
-}
-
-/* irq routing is changed. so rebuild bitmap */
-static void piix3_update_irq_levels(PIIX3State *piix3)
-{
-    int pirq;
-
-    piix3->pic_levels = 0;
-    for (pirq = 0; pirq < PIIX_NUM_PIRQS; pirq++) {
-        piix3_set_irq_level(piix3, pirq,
-                            pci_bus_get_irq_level(piix3->dev.bus, pirq));
-    }
-}
-
-static void piix3_write_config(PCIDevice *dev,
-                               uint32_t address, uint32_t val, int len)
-{
-    pci_default_write_config(dev, address, val, len);
-    if (ranges_overlap(address, len, PIIX_PIRQC, 4)) {
-        PIIX3State *piix3 = DO_UPCAST(PIIX3State, dev, dev);
-        int pic_irq;
-
-        pci_bus_fire_intx_routing_notifier(piix3->dev.bus);
-        piix3_update_irq_levels(piix3);
-        for (pic_irq = 0; pic_irq < PIIX_NUM_PIC_IRQS; pic_irq++) {
-            piix3_set_irq_pic(piix3, pic_irq);
-        }
-    }
-}
-
-static void piix3_write_config_xen(PCIDevice *dev,
-                               uint32_t address, uint32_t val, int len)
-{
-    xen_piix_pci_write_config_client(address, val, len);
-    piix3_write_config(dev, address, val, len);
-}
-
-static void piix3_reset(void *opaque)
-{
-    PIIX3State *d = opaque;
-    uint8_t *pci_conf = d->dev.config;
-
-    pci_conf[0x04] = 0x07; /* master, memory and I/O */
-    pci_conf[0x05] = 0x00;
-    pci_conf[0x06] = 0x00;
-    pci_conf[0x07] = 0x02; /* PCI_status_devsel_medium */
-    pci_conf[0x4c] = 0x4d;
-    pci_conf[0x4e] = 0x03;
-    pci_conf[0x4f] = 0x00;
-    pci_conf[0x60] = 0x80;
-    pci_conf[0x61] = 0x80;
-    pci_conf[0x62] = 0x80;
-    pci_conf[0x63] = 0x80;
-    pci_conf[0x69] = 0x02;
-    pci_conf[0x70] = 0x80;
-    pci_conf[0x76] = 0x0c;
-    pci_conf[0x77] = 0x0c;
-    pci_conf[0x78] = 0x02;
-    pci_conf[0x79] = 0x00;
-    pci_conf[0x80] = 0x00;
-    pci_conf[0x82] = 0x00;
-    pci_conf[0xa0] = 0x08;
-    pci_conf[0xa2] = 0x00;
-    pci_conf[0xa3] = 0x00;
-    pci_conf[0xa4] = 0x00;
-    pci_conf[0xa5] = 0x00;
-    pci_conf[0xa6] = 0x00;
-    pci_conf[0xa7] = 0x00;
-    pci_conf[0xa8] = 0x0f;
-    pci_conf[0xaa] = 0x00;
-    pci_conf[0xab] = 0x00;
-    pci_conf[0xac] = 0x00;
-    pci_conf[0xae] = 0x00;
-
-    d->pic_levels = 0;
-    d->rcr = 0;
-}
-
-static int piix3_post_load(void *opaque, int version_id)
-{
-    PIIX3State *piix3 = opaque;
-    piix3_update_irq_levels(piix3);
-    return 0;
-}
-
-static void piix3_pre_save(void *opaque)
-{
-    int i;
-    PIIX3State *piix3 = opaque;
-
-    for (i = 0; i < ARRAY_SIZE(piix3->pci_irq_levels_vmstate); i++) {
-        piix3->pci_irq_levels_vmstate[i] =
-            pci_bus_get_irq_level(piix3->dev.bus, i);
-    }
-}
-
-static bool piix3_rcr_needed(void *opaque)
-{
-    PIIX3State *piix3 = opaque;
-
-    return (piix3->rcr != 0);
-}
-
-static const VMStateDescription vmstate_piix3_rcr = {
-    .name = "PIIX3/rcr",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .fields = (VMStateField []) {
-        VMSTATE_UINT8(rcr, PIIX3State),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static const VMStateDescription vmstate_piix3 = {
-    .name = "PIIX3",
-    .version_id = 3,
-    .minimum_version_id = 2,
-    .minimum_version_id_old = 2,
-    .post_load = piix3_post_load,
-    .pre_save = piix3_pre_save,
-    .fields      = (VMStateField[]) {
-        VMSTATE_PCI_DEVICE(dev, PIIX3State),
-        VMSTATE_INT32_ARRAY_V(pci_irq_levels_vmstate, PIIX3State,
-                              PIIX_NUM_PIRQS, 3),
-        VMSTATE_END_OF_LIST()
-    },
-    .subsections = (VMStateSubsection[]) {
-        {
-            .vmsd = &vmstate_piix3_rcr,
-            .needed = piix3_rcr_needed,
-        },
-        { 0 }
-    }
-};
-
-
-static void rcr_write(void *opaque, hwaddr addr, uint64_t val, unsigned len)
-{
-    PIIX3State *d = opaque;
-
-    if (val & 4) {
-        qemu_system_reset_request();
-        return;
-    }
-    d->rcr = val & 2; /* keep System Reset type only */
-}
-
-static uint64_t rcr_read(void *opaque, hwaddr addr, unsigned len)
-{
-    PIIX3State *d = opaque;
-
-    return d->rcr;
-}
-
-static const MemoryRegionOps rcr_ops = {
-    .read = rcr_read,
-    .write = rcr_write,
-    .endianness = DEVICE_LITTLE_ENDIAN
-};
-
-static int piix3_initfn(PCIDevice *dev)
-{
-    PIIX3State *d = DO_UPCAST(PIIX3State, dev, dev);
-
-    isa_bus_new(DEVICE(d), pci_address_space_io(dev));
-
-    memory_region_init_io(&d->rcr_mem, &rcr_ops, d, "piix3-reset-control", 1);
-    memory_region_add_subregion_overlap(pci_address_space_io(dev), RCR_IOPORT,
-                                        &d->rcr_mem, 1);
-
-    qemu_register_reset(piix3_reset, d);
-    return 0;
-}
-
-static void piix3_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
-    dc->desc        = "ISA bridge";
-    dc->vmsd        = &vmstate_piix3;
-    dc->no_user     = 1,
-    k->no_hotplug   = 1;
-    k->init         = piix3_initfn;
-    k->config_write = piix3_write_config;
-    k->vendor_id    = PCI_VENDOR_ID_INTEL;
-    /* 82371SB PIIX3 PCI-to-ISA bridge (Step A1) */
-    k->device_id    = PCI_DEVICE_ID_INTEL_82371SB_0;
-    k->class_id     = PCI_CLASS_BRIDGE_ISA;
-}
-
-static const TypeInfo piix3_info = {
-    .name          = "PIIX3",
-    .parent        = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(PIIX3State),
-    .class_init    = piix3_class_init,
-};
-
-static void piix3_xen_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
-    dc->desc        = "ISA bridge";
-    dc->vmsd        = &vmstate_piix3;
-    dc->no_user     = 1;
-    k->no_hotplug   = 1;
-    k->init         = piix3_initfn;
-    k->config_write = piix3_write_config_xen;
-    k->vendor_id    = PCI_VENDOR_ID_INTEL;
-    /* 82371SB PIIX3 PCI-to-ISA bridge (Step A1) */
-    k->device_id    = PCI_DEVICE_ID_INTEL_82371SB_0;
-    k->class_id     = PCI_CLASS_BRIDGE_ISA;
-};
-
-static const 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;
-    k->init = i440fx_initfn;
-    k->config_write = i440fx_write_config;
-    k->vendor_id = PCI_VENDOR_ID_INTEL;
-    k->device_id = PCI_DEVICE_ID_INTEL_82441;
-    k->revision = 0x02;
-    k->class_id = PCI_CLASS_BRIDGE_HOST;
-    dc->desc = "Host bridge";
-    dc->no_user = 1;
-    dc->vmsd = &vmstate_i440fx;
-}
-
-static const TypeInfo i440fx_info = {
-    .name          = TYPE_I440FX_PCI_DEVICE,
-    .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 const TypeInfo i440fx_pcihost_info = {
-    .name          = "i440FX-pcihost",
-    .parent        = TYPE_PCI_HOST_BRIDGE,
-    .instance_size = sizeof(I440FXState),
-    .class_init    = i440fx_pcihost_class_init,
-};
-
-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);
-}
-
-type_init(i440fx_register_types)
diff --git a/hw/pl011.c b/hw/pl011.c
deleted file mode 100644 (file)
index 332d5b9..0000000
+++ /dev/null
@@ -1,330 +0,0 @@
-/*
- * Arm PrimeCell PL011 UART
- *
- * Copyright (c) 2006 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the GPL.
- */
-
-#include "hw/sysbus.h"
-#include "char/char.h"
-
-typedef struct {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-    uint32_t readbuff;
-    uint32_t flags;
-    uint32_t lcr;
-    uint32_t cr;
-    uint32_t dmacr;
-    uint32_t int_enabled;
-    uint32_t int_level;
-    uint32_t read_fifo[16];
-    uint32_t ilpr;
-    uint32_t ibrd;
-    uint32_t fbrd;
-    uint32_t ifl;
-    int read_pos;
-    int read_count;
-    int read_trigger;
-    CharDriverState *chr;
-    qemu_irq irq;
-    const unsigned char *id;
-} pl011_state;
-
-#define PL011_INT_TX 0x20
-#define PL011_INT_RX 0x10
-
-#define PL011_FLAG_TXFE 0x80
-#define PL011_FLAG_RXFF 0x40
-#define PL011_FLAG_TXFF 0x20
-#define PL011_FLAG_RXFE 0x10
-
-static const unsigned char pl011_id_arm[8] =
-  { 0x11, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
-static const unsigned char pl011_id_luminary[8] =
-  { 0x11, 0x00, 0x18, 0x01, 0x0d, 0xf0, 0x05, 0xb1 };
-
-static void pl011_update(pl011_state *s)
-{
-    uint32_t flags;
-
-    flags = s->int_level & s->int_enabled;
-    qemu_set_irq(s->irq, flags != 0);
-}
-
-static uint64_t pl011_read(void *opaque, hwaddr offset,
-                           unsigned size)
-{
-    pl011_state *s = (pl011_state *)opaque;
-    uint32_t c;
-
-    if (offset >= 0xfe0 && offset < 0x1000) {
-        return s->id[(offset - 0xfe0) >> 2];
-    }
-    switch (offset >> 2) {
-    case 0: /* UARTDR */
-        s->flags &= ~PL011_FLAG_RXFF;
-        c = s->read_fifo[s->read_pos];
-        if (s->read_count > 0) {
-            s->read_count--;
-            if (++s->read_pos == 16)
-                s->read_pos = 0;
-        }
-        if (s->read_count == 0) {
-            s->flags |= PL011_FLAG_RXFE;
-        }
-        if (s->read_count == s->read_trigger - 1)
-            s->int_level &= ~ PL011_INT_RX;
-        pl011_update(s);
-        if (s->chr) {
-            qemu_chr_accept_input(s->chr);
-        }
-        return c;
-    case 1: /* UARTCR */
-        return 0;
-    case 6: /* UARTFR */
-        return s->flags;
-    case 8: /* UARTILPR */
-        return s->ilpr;
-    case 9: /* UARTIBRD */
-        return s->ibrd;
-    case 10: /* UARTFBRD */
-        return s->fbrd;
-    case 11: /* UARTLCR_H */
-        return s->lcr;
-    case 12: /* UARTCR */
-        return s->cr;
-    case 13: /* UARTIFLS */
-        return s->ifl;
-    case 14: /* UARTIMSC */
-        return s->int_enabled;
-    case 15: /* UARTRIS */
-        return s->int_level;
-    case 16: /* UARTMIS */
-        return s->int_level & s->int_enabled;
-    case 18: /* UARTDMACR */
-        return s->dmacr;
-    default:
-        qemu_log_mask(LOG_GUEST_ERROR,
-                      "pl011_read: Bad offset %x\n", (int)offset);
-        return 0;
-    }
-}
-
-static void pl011_set_read_trigger(pl011_state *s)
-{
-#if 0
-    /* The docs say the RX interrupt is triggered when the FIFO exceeds
-       the threshold.  However linux only reads the FIFO in response to an
-       interrupt.  Triggering the interrupt when the FIFO is non-empty seems
-       to make things work.  */
-    if (s->lcr & 0x10)
-        s->read_trigger = (s->ifl >> 1) & 0x1c;
-    else
-#endif
-        s->read_trigger = 1;
-}
-
-static void pl011_write(void *opaque, hwaddr offset,
-                        uint64_t value, unsigned size)
-{
-    pl011_state *s = (pl011_state *)opaque;
-    unsigned char ch;
-
-    switch (offset >> 2) {
-    case 0: /* UARTDR */
-        /* ??? Check if transmitter is enabled.  */
-        ch = value;
-        if (s->chr)
-            qemu_chr_fe_write(s->chr, &ch, 1);
-        s->int_level |= PL011_INT_TX;
-        pl011_update(s);
-        break;
-    case 1: /* UARTCR */
-        s->cr = value;
-        break;
-    case 6: /* UARTFR */
-        /* Writes to Flag register are ignored.  */
-        break;
-    case 8: /* UARTUARTILPR */
-        s->ilpr = value;
-        break;
-    case 9: /* UARTIBRD */
-        s->ibrd = value;
-        break;
-    case 10: /* UARTFBRD */
-        s->fbrd = value;
-        break;
-    case 11: /* UARTLCR_H */
-        s->lcr = value;
-        pl011_set_read_trigger(s);
-        break;
-    case 12: /* UARTCR */
-        /* ??? Need to implement the enable and loopback bits.  */
-        s->cr = value;
-        break;
-    case 13: /* UARTIFS */
-        s->ifl = value;
-        pl011_set_read_trigger(s);
-        break;
-    case 14: /* UARTIMSC */
-        s->int_enabled = value;
-        pl011_update(s);
-        break;
-    case 17: /* UARTICR */
-        s->int_level &= ~value;
-        pl011_update(s);
-        break;
-    case 18: /* UARTDMACR */
-        s->dmacr = value;
-        if (value & 3) {
-            qemu_log_mask(LOG_UNIMP, "pl011: DMA not implemented\n");
-        }
-        break;
-    default:
-        qemu_log_mask(LOG_GUEST_ERROR,
-                      "pl011_write: Bad offset %x\n", (int)offset);
-    }
-}
-
-static int pl011_can_receive(void *opaque)
-{
-    pl011_state *s = (pl011_state *)opaque;
-
-    if (s->lcr & 0x10)
-        return s->read_count < 16;
-    else
-        return s->read_count < 1;
-}
-
-static void pl011_put_fifo(void *opaque, uint32_t value)
-{
-    pl011_state *s = (pl011_state *)opaque;
-    int slot;
-
-    slot = s->read_pos + s->read_count;
-    if (slot >= 16)
-        slot -= 16;
-    s->read_fifo[slot] = value;
-    s->read_count++;
-    s->flags &= ~PL011_FLAG_RXFE;
-    if (s->cr & 0x10 || s->read_count == 16) {
-        s->flags |= PL011_FLAG_RXFF;
-    }
-    if (s->read_count == s->read_trigger) {
-        s->int_level |= PL011_INT_RX;
-        pl011_update(s);
-    }
-}
-
-static void pl011_receive(void *opaque, const uint8_t *buf, int size)
-{
-    pl011_put_fifo(opaque, *buf);
-}
-
-static void pl011_event(void *opaque, int event)
-{
-    if (event == CHR_EVENT_BREAK)
-        pl011_put_fifo(opaque, 0x400);
-}
-
-static const MemoryRegionOps pl011_ops = {
-    .read = pl011_read,
-    .write = pl011_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static const VMStateDescription vmstate_pl011 = {
-    .name = "pl011",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField[]) {
-        VMSTATE_UINT32(readbuff, pl011_state),
-        VMSTATE_UINT32(flags, pl011_state),
-        VMSTATE_UINT32(lcr, pl011_state),
-        VMSTATE_UINT32(cr, pl011_state),
-        VMSTATE_UINT32(dmacr, pl011_state),
-        VMSTATE_UINT32(int_enabled, pl011_state),
-        VMSTATE_UINT32(int_level, pl011_state),
-        VMSTATE_UINT32_ARRAY(read_fifo, pl011_state, 16),
-        VMSTATE_UINT32(ilpr, pl011_state),
-        VMSTATE_UINT32(ibrd, pl011_state),
-        VMSTATE_UINT32(fbrd, pl011_state),
-        VMSTATE_UINT32(ifl, pl011_state),
-        VMSTATE_INT32(read_pos, pl011_state),
-        VMSTATE_INT32(read_count, pl011_state),
-        VMSTATE_INT32(read_trigger, pl011_state),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static int pl011_init(SysBusDevice *dev, const unsigned char *id)
-{
-    pl011_state *s = FROM_SYSBUS(pl011_state, dev);
-
-    memory_region_init_io(&s->iomem, &pl011_ops, s, "pl011", 0x1000);
-    sysbus_init_mmio(dev, &s->iomem);
-    sysbus_init_irq(dev, &s->irq);
-    s->id = id;
-    s->chr = qemu_char_get_next_serial();
-
-    s->read_trigger = 1;
-    s->ifl = 0x12;
-    s->cr = 0x300;
-    s->flags = 0x90;
-    if (s->chr) {
-        qemu_chr_add_handlers(s->chr, pl011_can_receive, pl011_receive,
-                              pl011_event, s);
-    }
-    vmstate_register(&dev->qdev, -1, &vmstate_pl011, s);
-    return 0;
-}
-
-static int pl011_arm_init(SysBusDevice *dev)
-{
-    return pl011_init(dev, pl011_id_arm);
-}
-
-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 const TypeInfo pl011_arm_info = {
-    .name          = "pl011",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(pl011_state),
-    .class_init    = pl011_arm_class_init,
-};
-
-static void pl011_luminary_class_init(ObjectClass *klass, void *data)
-{
-    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
-
-    sdc->init = pl011_luminary_init;
-}
-
-static const 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_types(void)
-{
-    type_register_static(&pl011_arm_info);
-    type_register_static(&pl011_luminary_info);
-}
-
-type_init(pl011_register_types)
diff --git a/hw/pl022.c b/hw/pl022.c
deleted file mode 100644 (file)
index 536c216..0000000
+++ /dev/null
@@ -1,308 +0,0 @@
-/*
- * Arm PrimeCell PL022 Synchronous Serial Port
- *
- * Copyright (c) 2007 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the GPL.
- */
-
-#include "hw/sysbus.h"
-#include "hw/ssi.h"
-
-//#define DEBUG_PL022 1
-
-#ifdef DEBUG_PL022
-#define DPRINTF(fmt, ...) \
-do { printf("pl022: " fmt , ## __VA_ARGS__); } while (0)
-#define BADF(fmt, ...) \
-do { fprintf(stderr, "pl022: error: " fmt , ## __VA_ARGS__); exit(1);} while (0)
-#else
-#define DPRINTF(fmt, ...) do {} while(0)
-#define BADF(fmt, ...) \
-do { fprintf(stderr, "pl022: error: " fmt , ## __VA_ARGS__);} while (0)
-#endif
-
-#define PL022_CR1_LBM 0x01
-#define PL022_CR1_SSE 0x02
-#define PL022_CR1_MS  0x04
-#define PL022_CR1_SDO 0x08
-
-#define PL022_SR_TFE  0x01
-#define PL022_SR_TNF  0x02
-#define PL022_SR_RNE  0x04
-#define PL022_SR_RFF  0x08
-#define PL022_SR_BSY  0x10
-
-#define PL022_INT_ROR 0x01
-#define PL022_INT_RT  0x04
-#define PL022_INT_RX  0x04
-#define PL022_INT_TX  0x08
-
-typedef struct {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-    uint32_t cr0;
-    uint32_t cr1;
-    uint32_t bitmask;
-    uint32_t sr;
-    uint32_t cpsr;
-    uint32_t is;
-    uint32_t im;
-    /* The FIFO head points to the next empty entry.  */
-    int tx_fifo_head;
-    int rx_fifo_head;
-    int tx_fifo_len;
-    int rx_fifo_len;
-    uint16_t tx_fifo[8];
-    uint16_t rx_fifo[8];
-    qemu_irq irq;
-    SSIBus *ssi;
-} pl022_state;
-
-static const unsigned char pl022_id[8] =
-  { 0x22, 0x10, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
-
-static void pl022_update(pl022_state *s)
-{
-    s->sr = 0;
-    if (s->tx_fifo_len == 0)
-        s->sr |= PL022_SR_TFE;
-    if (s->tx_fifo_len != 8)
-        s->sr |= PL022_SR_TNF;
-    if (s->rx_fifo_len != 0)
-        s->sr |= PL022_SR_RNE;
-    if (s->rx_fifo_len == 8)
-        s->sr |= PL022_SR_RFF;
-    if (s->tx_fifo_len)
-        s->sr |= PL022_SR_BSY;
-    s->is = 0;
-    if (s->rx_fifo_len >= 4)
-        s->is |= PL022_INT_RX;
-    if (s->tx_fifo_len <= 4)
-        s->is |= PL022_INT_TX;
-
-    qemu_set_irq(s->irq, (s->is & s->im) != 0);
-}
-
-static void pl022_xfer(pl022_state *s)
-{
-    int i;
-    int o;
-    int val;
-
-    if ((s->cr1 & PL022_CR1_SSE) == 0) {
-        pl022_update(s);
-        DPRINTF("Disabled\n");
-        return;
-    }
-
-    DPRINTF("Maybe xfer %d/%d\n", s->tx_fifo_len, s->rx_fifo_len);
-    i = (s->tx_fifo_head - s->tx_fifo_len) & 7;
-    o = s->rx_fifo_head;
-    /* ??? We do not emulate the line speed.
-       This may break some applications.  The are two problematic cases:
-        (a) A driver feeds data into the TX FIFO until it is full,
-         and only then drains the RX FIFO.  On real hardware the CPU can
-         feed data fast enough that the RX fifo never gets chance to overflow.
-        (b) A driver transmits data, deliberately allowing the RX FIFO to
-         overflow because it ignores the RX data anyway.
-
-       We choose to support (a) by stalling the transmit engine if it would
-       cause the RX FIFO to overflow.  In practice much transmit-only code
-       falls into (a) because it flushes the RX FIFO to determine when
-       the transfer has completed.  */
-    while (s->tx_fifo_len && s->rx_fifo_len < 8) {
-        DPRINTF("xfer\n");
-        val = s->tx_fifo[i];
-        if (s->cr1 & PL022_CR1_LBM) {
-            /* Loopback mode.  */
-        } else {
-            val = ssi_transfer(s->ssi, val);
-        }
-        s->rx_fifo[o] = val & s->bitmask;
-        i = (i + 1) & 7;
-        o = (o + 1) & 7;
-        s->tx_fifo_len--;
-        s->rx_fifo_len++;
-    }
-    s->rx_fifo_head = o;
-    pl022_update(s);
-}
-
-static uint64_t pl022_read(void *opaque, hwaddr offset,
-                           unsigned size)
-{
-    pl022_state *s = (pl022_state *)opaque;
-    int val;
-
-    if (offset >= 0xfe0 && offset < 0x1000) {
-        return pl022_id[(offset - 0xfe0) >> 2];
-    }
-    switch (offset) {
-    case 0x00: /* CR0 */
-      return s->cr0;
-    case 0x04: /* CR1 */
-      return s->cr1;
-    case 0x08: /* DR */
-        if (s->rx_fifo_len) {
-            val = s->rx_fifo[(s->rx_fifo_head - s->rx_fifo_len) & 7];
-            DPRINTF("RX %02x\n", val);
-            s->rx_fifo_len--;
-            pl022_xfer(s);
-        } else {
-            val = 0;
-        }
-        return val;
-    case 0x0c: /* SR */
-        return s->sr;
-    case 0x10: /* CPSR */
-        return s->cpsr;
-    case 0x14: /* IMSC */
-        return s->im;
-    case 0x18: /* RIS */
-        return s->is;
-    case 0x1c: /* MIS */
-        return s->im & s->is;
-    case 0x20: /* DMACR */
-        /* Not implemented.  */
-        return 0;
-    default:
-        qemu_log_mask(LOG_GUEST_ERROR,
-                      "pl022_read: Bad offset %x\n", (int)offset);
-        return 0;
-    }
-}
-
-static void pl022_write(void *opaque, hwaddr offset,
-                        uint64_t value, unsigned size)
-{
-    pl022_state *s = (pl022_state *)opaque;
-
-    switch (offset) {
-    case 0x00: /* CR0 */
-        s->cr0 = value;
-        /* Clock rate and format are ignored.  */
-        s->bitmask = (1 << ((value & 15) + 1)) - 1;
-        break;
-    case 0x04: /* CR1 */
-        s->cr1 = value;
-        if ((s->cr1 & (PL022_CR1_MS | PL022_CR1_SSE))
-                   == (PL022_CR1_MS | PL022_CR1_SSE)) {
-            BADF("SPI slave mode not implemented\n");
-        }
-        pl022_xfer(s);
-        break;
-    case 0x08: /* DR */
-        if (s->tx_fifo_len < 8) {
-            DPRINTF("TX %02x\n", (unsigned)value);
-            s->tx_fifo[s->tx_fifo_head] = value & s->bitmask;
-            s->tx_fifo_head = (s->tx_fifo_head + 1) & 7;
-            s->tx_fifo_len++;
-            pl022_xfer(s);
-        }
-        break;
-    case 0x10: /* CPSR */
-        /* Prescaler.  Ignored.  */
-        s->cpsr = value & 0xff;
-        break;
-    case 0x14: /* IMSC */
-        s->im = value;
-        pl022_update(s);
-        break;
-    case 0x20: /* DMACR */
-        if (value) {
-            qemu_log_mask(LOG_UNIMP, "pl022: DMA not implemented\n");
-        }
-        break;
-    default:
-        qemu_log_mask(LOG_GUEST_ERROR,
-                      "pl022_write: Bad offset %x\n", (int)offset);
-    }
-}
-
-static void pl022_reset(pl022_state *s)
-{
-    s->rx_fifo_len = 0;
-    s->tx_fifo_len = 0;
-    s->im = 0;
-    s->is = PL022_INT_TX;
-    s->sr = PL022_SR_TFE | PL022_SR_TNF;
-}
-
-static const MemoryRegionOps pl022_ops = {
-    .read = pl022_read,
-    .write = pl022_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static const VMStateDescription vmstate_pl022 = {
-    .name = "pl022_ssp",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField[]) {
-        VMSTATE_UINT32(cr0, pl022_state),
-        VMSTATE_UINT32(cr1, pl022_state),
-        VMSTATE_UINT32(bitmask, pl022_state),
-        VMSTATE_UINT32(sr, pl022_state),
-        VMSTATE_UINT32(cpsr, pl022_state),
-        VMSTATE_UINT32(is, pl022_state),
-        VMSTATE_UINT32(im, pl022_state),
-        VMSTATE_INT32(tx_fifo_head, pl022_state),
-        VMSTATE_INT32(rx_fifo_head, pl022_state),
-        VMSTATE_INT32(tx_fifo_len, pl022_state),
-        VMSTATE_INT32(rx_fifo_len, pl022_state),
-        VMSTATE_UINT16(tx_fifo[0], pl022_state),
-        VMSTATE_UINT16(rx_fifo[0], pl022_state),
-        VMSTATE_UINT16(tx_fifo[1], pl022_state),
-        VMSTATE_UINT16(rx_fifo[1], pl022_state),
-        VMSTATE_UINT16(tx_fifo[2], pl022_state),
-        VMSTATE_UINT16(rx_fifo[2], pl022_state),
-        VMSTATE_UINT16(tx_fifo[3], pl022_state),
-        VMSTATE_UINT16(rx_fifo[3], pl022_state),
-        VMSTATE_UINT16(tx_fifo[4], pl022_state),
-        VMSTATE_UINT16(rx_fifo[4], pl022_state),
-        VMSTATE_UINT16(tx_fifo[5], pl022_state),
-        VMSTATE_UINT16(rx_fifo[5], pl022_state),
-        VMSTATE_UINT16(tx_fifo[6], pl022_state),
-        VMSTATE_UINT16(rx_fifo[6], pl022_state),
-        VMSTATE_UINT16(tx_fifo[7], pl022_state),
-        VMSTATE_UINT16(rx_fifo[7], pl022_state),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static int pl022_init(SysBusDevice *dev)
-{
-    pl022_state *s = FROM_SYSBUS(pl022_state, dev);
-
-    memory_region_init_io(&s->iomem, &pl022_ops, s, "pl022", 0x1000);
-    sysbus_init_mmio(dev, &s->iomem);
-    sysbus_init_irq(dev, &s->irq);
-    s->ssi = ssi_create_bus(&dev->qdev, "ssi");
-    pl022_reset(s);
-    vmstate_register(&dev->qdev, -1, &vmstate_pl022, s);
-    return 0;
-}
-
-static void pl022_class_init(ObjectClass *klass, void *data)
-{
-    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
-
-    sdc->init = pl022_init;
-}
-
-static const TypeInfo pl022_info = {
-    .name          = "pl022",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(pl022_state),
-    .class_init    = pl022_class_init,
-};
-
-static void pl022_register_types(void)
-{
-    type_register_static(&pl022_info);
-}
-
-type_init(pl022_register_types)
diff --git a/hw/pl031.c b/hw/pl031.c
deleted file mode 100644 (file)
index 764940b..0000000
+++ /dev/null
@@ -1,265 +0,0 @@
-/*
- * ARM AMBA PrimeCell PL031 RTC
- *
- * Copyright (c) 2007 CodeSourcery
- *
- * This file is free software; you can redistribute it and/or modify
- * 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 "hw/sysbus.h"
-#include "qemu/timer.h"
-#include "sysemu/sysemu.h"
-
-//#define DEBUG_PL031
-
-#ifdef DEBUG_PL031
-#define DPRINTF(fmt, ...) \
-do { printf("pl031: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...) do {} while(0)
-#endif
-
-#define RTC_DR      0x00    /* Data read register */
-#define RTC_MR      0x04    /* Match register */
-#define RTC_LR      0x08    /* Data load register */
-#define RTC_CR      0x0c    /* Control register */
-#define RTC_IMSC    0x10    /* Interrupt mask and set register */
-#define RTC_RIS     0x14    /* Raw interrupt status register */
-#define RTC_MIS     0x18    /* Masked interrupt status register */
-#define RTC_ICR     0x1c    /* Interrupt clear register */
-
-typedef struct {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-    QEMUTimer *timer;
-    qemu_irq irq;
-
-    /* Needed to preserve the tick_count across migration, even if the
-     * absolute value of the rtc_clock is different on the source and
-     * destination.
-     */
-    uint32_t tick_offset_vmstate;
-    uint32_t tick_offset;
-
-    uint32_t mr;
-    uint32_t lr;
-    uint32_t cr;
-    uint32_t im;
-    uint32_t is;
-} pl031_state;
-
-static const unsigned char pl031_id[] = {
-    0x31, 0x10, 0x14, 0x00,         /* Device ID        */
-    0x0d, 0xf0, 0x05, 0xb1          /* Cell ID      */
-};
-
-static void pl031_update(pl031_state *s)
-{
-    qemu_set_irq(s->irq, s->is & s->im);
-}
-
-static void pl031_interrupt(void * opaque)
-{
-    pl031_state *s = (pl031_state *)opaque;
-
-    s->is = 1;
-    DPRINTF("Alarm raised\n");
-    pl031_update(s);
-}
-
-static uint32_t pl031_get_count(pl031_state *s)
-{
-    int64_t now = qemu_get_clock_ns(rtc_clock);
-    return s->tick_offset + now / get_ticks_per_sec();
-}
-
-static void pl031_set_alarm(pl031_state *s)
-{
-    uint32_t ticks;
-
-    /* The timer wraps around.  This subtraction also wraps in the same way,
-       and gives correct results when alarm < now_ticks.  */
-    ticks = s->mr - pl031_get_count(s);
-    DPRINTF("Alarm set in %ud ticks\n", ticks);
-    if (ticks == 0) {
-        qemu_del_timer(s->timer);
-        pl031_interrupt(s);
-    } else {
-        int64_t now = qemu_get_clock_ns(rtc_clock);
-        qemu_mod_timer(s->timer, now + (int64_t)ticks * get_ticks_per_sec());
-    }
-}
-
-static uint64_t pl031_read(void *opaque, hwaddr offset,
-                           unsigned size)
-{
-    pl031_state *s = (pl031_state *)opaque;
-
-    if (offset >= 0xfe0  &&  offset < 0x1000)
-        return pl031_id[(offset - 0xfe0) >> 2];
-
-    switch (offset) {
-    case RTC_DR:
-        return pl031_get_count(s);
-    case RTC_MR:
-        return s->mr;
-    case RTC_IMSC:
-        return s->im;
-    case RTC_RIS:
-        return s->is;
-    case RTC_LR:
-        return s->lr;
-    case RTC_CR:
-        /* RTC is permanently enabled.  */
-        return 1;
-    case RTC_MIS:
-        return s->is & s->im;
-    case RTC_ICR:
-        qemu_log_mask(LOG_GUEST_ERROR,
-                      "pl031: read of write-only register at offset 0x%x\n",
-                      (int)offset);
-        break;
-    default:
-        qemu_log_mask(LOG_GUEST_ERROR,
-                      "pl031_read: Bad offset 0x%x\n", (int)offset);
-        break;
-    }
-
-    return 0;
-}
-
-static void pl031_write(void * opaque, hwaddr offset,
-                        uint64_t value, unsigned size)
-{
-    pl031_state *s = (pl031_state *)opaque;
-
-
-    switch (offset) {
-    case RTC_LR:
-        s->tick_offset += value - pl031_get_count(s);
-        pl031_set_alarm(s);
-        break;
-    case RTC_MR:
-        s->mr = value;
-        pl031_set_alarm(s);
-        break;
-    case RTC_IMSC:
-        s->im = value & 1;
-        DPRINTF("Interrupt mask %d\n", s->im);
-        pl031_update(s);
-        break;
-    case RTC_ICR:
-        /* The PL031 documentation (DDI0224B) states that the interrupt is
-           cleared when bit 0 of the written value is set.  However the
-           arm926e documentation (DDI0287B) states that the interrupt is
-           cleared when any value is written.  */
-        DPRINTF("Interrupt cleared");
-        s->is = 0;
-        pl031_update(s);
-        break;
-    case RTC_CR:
-        /* Written value is ignored.  */
-        break;
-
-    case RTC_DR:
-    case RTC_MIS:
-    case RTC_RIS:
-        qemu_log_mask(LOG_GUEST_ERROR,
-                      "pl031: write to read-only register at offset 0x%x\n",
-                      (int)offset);
-        break;
-
-    default:
-        qemu_log_mask(LOG_GUEST_ERROR,
-                      "pl031_write: Bad offset 0x%x\n", (int)offset);
-        break;
-    }
-}
-
-static const MemoryRegionOps pl031_ops = {
-    .read = pl031_read,
-    .write = pl031_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int pl031_init(SysBusDevice *dev)
-{
-    pl031_state *s = FROM_SYSBUS(pl031_state, dev);
-    struct tm tm;
-
-    memory_region_init_io(&s->iomem, &pl031_ops, s, "pl031", 0x1000);
-    sysbus_init_mmio(dev, &s->iomem);
-
-    sysbus_init_irq(dev, &s->irq);
-    qemu_get_timedate(&tm, 0);
-    s->tick_offset = mktimegm(&tm) - qemu_get_clock_ns(rtc_clock) / get_ticks_per_sec();
-
-    s->timer = qemu_new_timer_ns(rtc_clock, pl031_interrupt, s);
-    return 0;
-}
-
-static void pl031_pre_save(void *opaque)
-{
-    pl031_state *s = opaque;
-
-    /* tick_offset is base_time - rtc_clock base time.  Instead, we want to
-     * store the base time relative to the vm_clock for backwards-compatibility.  */
-    int64_t delta = qemu_get_clock_ns(rtc_clock) - qemu_get_clock_ns(vm_clock);
-    s->tick_offset_vmstate = s->tick_offset + delta / get_ticks_per_sec();
-}
-
-static int pl031_post_load(void *opaque, int version_id)
-{
-    pl031_state *s = opaque;
-
-    int64_t delta = qemu_get_clock_ns(rtc_clock) - qemu_get_clock_ns(vm_clock);
-    s->tick_offset = s->tick_offset_vmstate - delta / get_ticks_per_sec();
-    pl031_set_alarm(s);
-    return 0;
-}
-
-static const VMStateDescription vmstate_pl031 = {
-    .name = "pl031",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .pre_save = pl031_pre_save,
-    .post_load = pl031_post_load,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT32(tick_offset_vmstate, pl031_state),
-        VMSTATE_UINT32(mr, pl031_state),
-        VMSTATE_UINT32(lr, pl031_state),
-        VMSTATE_UINT32(cr, pl031_state),
-        VMSTATE_UINT32(im, pl031_state),
-        VMSTATE_UINT32(is, pl031_state),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-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 const TypeInfo pl031_info = {
-    .name          = "pl031",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(pl031_state),
-    .class_init    = pl031_class_init,
-};
-
-static void pl031_register_types(void)
-{
-    type_register_static(&pl031_info);
-}
-
-type_init(pl031_register_types)
diff --git a/hw/pl041.c b/hw/pl041.c
deleted file mode 100644 (file)
index 92dddc2..0000000
+++ /dev/null
@@ -1,647 +0,0 @@
-/*
- * Arm PrimeCell PL041 Advanced Audio Codec Interface
- *
- * Copyright (c) 2011
- * Written by Mathieu Sonet - www.elasticsheep.com
- *
- * This code is licensed under the GPL.
- *
- * *****************************************************************
- *
- * This driver emulates the ARM AACI interface
- * connected to a LM4549 codec.
- *
- * Limitations:
- * - Supports only a playback on one channel (Versatile/Vexpress)
- * - Supports only one TX FIFO in compact-mode or non-compact mode.
- * - Supports playback of 12, 16, 18 and 20 bits samples.
- * - Record is not supported.
- * - The PL041 is hardwired to a LM4549 codec.
- *
- */
-
-#include "hw/sysbus.h"
-
-#include "hw/pl041.h"
-#include "hw/lm4549.h"
-
-#if 0
-#define PL041_DEBUG_LEVEL 1
-#endif
-
-#if defined(PL041_DEBUG_LEVEL) && (PL041_DEBUG_LEVEL >= 1)
-#define DBG_L1(fmt, ...) \
-do { printf("pl041: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DBG_L1(fmt, ...) \
-do { } while (0)
-#endif
-
-#if defined(PL041_DEBUG_LEVEL) && (PL041_DEBUG_LEVEL >= 2)
-#define DBG_L2(fmt, ...) \
-do { printf("pl041: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DBG_L2(fmt, ...) \
-do { } while (0)
-#endif
-
-
-#define MAX_FIFO_DEPTH      (1024)
-#define DEFAULT_FIFO_DEPTH  (8)
-
-#define SLOT1_RW    (1 << 19)
-
-/* This FIFO only stores 20-bit samples on 32-bit words.
-   So its level is independent of the selected mode */
-typedef struct {
-    uint32_t level;
-    uint32_t data[MAX_FIFO_DEPTH];
-} pl041_fifo;
-
-typedef struct {
-    pl041_fifo tx_fifo;
-    uint8_t tx_enabled;
-    uint8_t tx_compact_mode;
-    uint8_t tx_sample_size;
-
-    pl041_fifo rx_fifo;
-    uint8_t rx_enabled;
-    uint8_t rx_compact_mode;
-    uint8_t rx_sample_size;
-} pl041_channel;
-
-typedef struct {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-    qemu_irq irq;
-
-    uint32_t fifo_depth; /* FIFO depth in non-compact mode */
-
-    pl041_regfile regs;
-    pl041_channel fifo1;
-    lm4549_state codec;
-} pl041_state;
-
-
-static const unsigned char pl041_default_id[8] = {
-    0x41, 0x10, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1
-};
-
-#if defined(PL041_DEBUG_LEVEL)
-#define REGISTER(name, offset) #name,
-static const char *pl041_regs_name[] = {
-    #include "pl041.hx"
-};
-#undef REGISTER
-#endif
-
-
-#if defined(PL041_DEBUG_LEVEL)
-static const char *get_reg_name(hwaddr offset)
-{
-    if (offset <= PL041_dr1_7) {
-        return pl041_regs_name[offset >> 2];
-    }
-
-    return "unknown";
-}
-#endif
-
-static uint8_t pl041_compute_periphid3(pl041_state *s)
-{
-    uint8_t id3 = 1; /* One channel */
-
-    /* Add the fifo depth information */
-    switch (s->fifo_depth) {
-    case 8:
-        id3 |= 0 << 3;
-        break;
-    case 32:
-        id3 |= 1 << 3;
-        break;
-    case 64:
-        id3 |= 2 << 3;
-        break;
-    case 128:
-        id3 |= 3 << 3;
-        break;
-    case 256:
-        id3 |= 4 << 3;
-        break;
-    case 512:
-        id3 |= 5 << 3;
-        break;
-    case 1024:
-        id3 |= 6 << 3;
-        break;
-    case 2048:
-        id3 |= 7 << 3;
-        break;
-    }
-
-    return id3;
-}
-
-static void pl041_reset(pl041_state *s)
-{
-    DBG_L1("pl041_reset\n");
-
-    memset(&s->regs, 0x00, sizeof(pl041_regfile));
-
-    s->regs.slfr = SL1TXEMPTY | SL2TXEMPTY | SL12TXEMPTY;
-    s->regs.sr1 = TXFE | RXFE | TXHE;
-    s->regs.isr1 = 0;
-
-    memset(&s->fifo1, 0x00, sizeof(s->fifo1));
-}
-
-
-static void pl041_fifo1_write(pl041_state *s, uint32_t value)
-{
-    pl041_channel *channel = &s->fifo1;
-    pl041_fifo *fifo = &s->fifo1.tx_fifo;
-
-    /* Push the value in the FIFO */
-    if (channel->tx_compact_mode == 0) {
-        /* Non-compact mode */
-
-        if (fifo->level < s->fifo_depth) {
-            /* Pad the value with 0 to obtain a 20-bit sample */
-            switch (channel->tx_sample_size) {
-            case 12:
-                value = (value << 8) & 0xFFFFF;
-                break;
-            case 16:
-                value = (value << 4) & 0xFFFFF;
-                break;
-            case 18:
-                value = (value << 2) & 0xFFFFF;
-                break;
-            case 20:
-            default:
-                break;
-            }
-
-            /* Store the sample in the FIFO */
-            fifo->data[fifo->level++] = value;
-        }
-#if defined(PL041_DEBUG_LEVEL)
-        else {
-            DBG_L1("fifo1 write: overrun\n");
-        }
-#endif
-    } else {
-        /* Compact mode */
-
-        if ((fifo->level + 2) < s->fifo_depth) {
-            uint32_t i = 0;
-            uint32_t sample = 0;
-
-            for (i = 0; i < 2; i++) {
-                sample = value & 0xFFFF;
-                value = value >> 16;
-
-                /* Pad each sample with 0 to obtain a 20-bit sample */
-                switch (channel->tx_sample_size) {
-                case 12:
-                    sample = sample << 8;
-                    break;
-                case 16:
-                default:
-                    sample = sample << 4;
-                    break;
-                }
-
-                /* Store the sample in the FIFO */
-                fifo->data[fifo->level++] = sample;
-            }
-        }
-#if defined(PL041_DEBUG_LEVEL)
-        else {
-            DBG_L1("fifo1 write: overrun\n");
-        }
-#endif
-    }
-
-    /* Update the status register */
-    if (fifo->level > 0) {
-        s->regs.sr1 &= ~(TXUNDERRUN | TXFE);
-    }
-
-    if (fifo->level >= (s->fifo_depth / 2)) {
-        s->regs.sr1 &= ~TXHE;
-    }
-
-    if (fifo->level >= s->fifo_depth) {
-        s->regs.sr1 |= TXFF;
-    }
-
-    DBG_L2("fifo1_push sr1 = 0x%08x\n", s->regs.sr1);
-}
-
-static void pl041_fifo1_transmit(pl041_state *s)
-{
-    pl041_channel *channel = &s->fifo1;
-    pl041_fifo *fifo = &s->fifo1.tx_fifo;
-    uint32_t slots = s->regs.txcr1 & TXSLOT_MASK;
-    uint32_t written_samples;
-
-    /* Check if FIFO1 transmit is enabled */
-    if ((channel->tx_enabled) && (slots & (TXSLOT3 | TXSLOT4))) {
-        if (fifo->level >= (s->fifo_depth / 2)) {
-            int i;
-
-            DBG_L1("Transfer FIFO level = %i\n", fifo->level);
-
-            /* Try to transfer the whole FIFO */
-            for (i = 0; i < (fifo->level / 2); i++) {
-                uint32_t left = fifo->data[i * 2];
-                uint32_t right = fifo->data[i * 2 + 1];
-
-                 /* Transmit two 20-bit samples to the codec */
-                if (lm4549_write_samples(&s->codec, left, right) == 0) {
-                    DBG_L1("Codec buffer full\n");
-                    break;
-                }
-            }
-
-            written_samples = i * 2;
-            if (written_samples > 0) {
-                /* Update the FIFO level */
-                fifo->level -= written_samples;
-
-                /* Move back the pending samples to the start of the FIFO */
-                for (i = 0; i < fifo->level; i++) {
-                    fifo->data[i] = fifo->data[written_samples + i];
-                }
-
-                /* Update the status register */
-                s->regs.sr1 &= ~TXFF;
-
-                if (fifo->level <= (s->fifo_depth / 2)) {
-                    s->regs.sr1 |= TXHE;
-                }
-
-                if (fifo->level == 0) {
-                    s->regs.sr1 |= TXFE | TXUNDERRUN;
-                    DBG_L1("Empty FIFO\n");
-                }
-            }
-        }
-    }
-}
-
-static void pl041_isr1_update(pl041_state *s)
-{
-    /* Update ISR1 */
-    if (s->regs.sr1 & TXUNDERRUN) {
-        s->regs.isr1 |= URINTR;
-    } else {
-        s->regs.isr1 &= ~URINTR;
-    }
-
-    if (s->regs.sr1 & TXHE) {
-        s->regs.isr1 |= TXINTR;
-    } else {
-        s->regs.isr1 &= ~TXINTR;
-    }
-
-    if (!(s->regs.sr1 & TXBUSY) && (s->regs.sr1 & TXFE)) {
-        s->regs.isr1 |= TXCINTR;
-    } else {
-        s->regs.isr1 &= ~TXCINTR;
-    }
-
-    /* Update the irq state */
-    qemu_set_irq(s->irq, ((s->regs.isr1 & s->regs.ie1) > 0) ? 1 : 0);
-    DBG_L2("Set interrupt sr1 = 0x%08x isr1 = 0x%08x masked = 0x%08x\n",
-           s->regs.sr1, s->regs.isr1, s->regs.isr1 & s->regs.ie1);
-}
-
-static void pl041_request_data(void *opaque)
-{
-    pl041_state *s = (pl041_state *)opaque;
-
-    /* Trigger pending transfers */
-    pl041_fifo1_transmit(s);
-    pl041_isr1_update(s);
-}
-
-static uint64_t pl041_read(void *opaque, hwaddr offset,
-                                unsigned size)
-{
-    pl041_state *s = (pl041_state *)opaque;
-    int value;
-
-    if ((offset >= PL041_periphid0) && (offset <= PL041_pcellid3)) {
-        if (offset == PL041_periphid3) {
-            value = pl041_compute_periphid3(s);
-        } else {
-            value = pl041_default_id[(offset - PL041_periphid0) >> 2];
-        }
-
-        DBG_L1("pl041_read [0x%08x] => 0x%08x\n", offset, value);
-        return value;
-    } else if (offset <= PL041_dr4_7) {
-        value = *((uint32_t *)&s->regs + (offset >> 2));
-    } else {
-        DBG_L1("pl041_read: Reserved offset %x\n", (int)offset);
-        return 0;
-    }
-
-    switch (offset) {
-    case PL041_allints:
-        value = s->regs.isr1 & 0x7F;
-        break;
-    }
-
-    DBG_L1("pl041_read [0x%08x] %s => 0x%08x\n", offset,
-           get_reg_name(offset), value);
-
-    return value;
-}
-
-static void pl041_write(void *opaque, hwaddr offset,
-                             uint64_t value, unsigned size)
-{
-    pl041_state *s = (pl041_state *)opaque;
-    uint16_t control, data;
-    uint32_t result;
-
-    DBG_L1("pl041_write [0x%08x] %s <= 0x%08x\n", offset,
-           get_reg_name(offset), (unsigned int)value);
-
-    /* Write the register */
-    if (offset <= PL041_dr4_7) {
-        *((uint32_t *)&s->regs + (offset >> 2)) = value;
-    } else {
-        DBG_L1("pl041_write: Reserved offset %x\n", (int)offset);
-        return;
-    }
-
-    /* Execute the actions */
-    switch (offset) {
-    case PL041_txcr1:
-    {
-        pl041_channel *channel = &s->fifo1;
-
-        uint32_t txen = s->regs.txcr1 & TXEN;
-        uint32_t tsize = (s->regs.txcr1 & TSIZE_MASK) >> TSIZE_MASK_BIT;
-        uint32_t compact_mode = (s->regs.txcr1 & TXCOMPACT) ? 1 : 0;
-#if defined(PL041_DEBUG_LEVEL)
-        uint32_t slots = (s->regs.txcr1 & TXSLOT_MASK) >> TXSLOT_MASK_BIT;
-        uint32_t txfen = (s->regs.txcr1 & TXFEN) > 0 ? 1 : 0;
-#endif
-
-        DBG_L1("=> txen = %i slots = 0x%01x tsize = %i compact = %i "
-               "txfen = %i\n", txen, slots,  tsize, compact_mode, txfen);
-
-        channel->tx_enabled = txen;
-        channel->tx_compact_mode = compact_mode;
-
-        switch (tsize) {
-        case 0:
-            channel->tx_sample_size = 16;
-            break;
-        case 1:
-            channel->tx_sample_size = 18;
-            break;
-        case 2:
-            channel->tx_sample_size = 20;
-            break;
-        case 3:
-            channel->tx_sample_size = 12;
-            break;
-        }
-
-        DBG_L1("TX enabled = %i\n", channel->tx_enabled);
-        DBG_L1("TX compact mode = %i\n", channel->tx_compact_mode);
-        DBG_L1("TX sample width = %i\n", channel->tx_sample_size);
-
-        /* Check if compact mode is allowed with selected tsize */
-        if (channel->tx_compact_mode == 1) {
-            if ((channel->tx_sample_size == 18) ||
-                (channel->tx_sample_size == 20)) {
-                channel->tx_compact_mode = 0;
-                DBG_L1("Compact mode not allowed with 18/20-bit sample size\n");
-            }
-        }
-
-        break;
-    }
-    case PL041_sl1tx:
-        s->regs.slfr &= ~SL1TXEMPTY;
-
-        control = (s->regs.sl1tx >> 12) & 0x7F;
-        data = (s->regs.sl2tx >> 4) & 0xFFFF;
-
-        if ((s->regs.sl1tx & SLOT1_RW) == 0) {
-            /* Write operation */
-            lm4549_write(&s->codec, control, data);
-        } else {
-            /* Read operation */
-            result = lm4549_read(&s->codec, control);
-
-            /* Store the returned value */
-            s->regs.sl1rx = s->regs.sl1tx & ~SLOT1_RW;
-            s->regs.sl2rx = result << 4;
-
-            s->regs.slfr &= ~(SL1RXBUSY | SL2RXBUSY);
-            s->regs.slfr |= SL1RXVALID | SL2RXVALID;
-        }
-        break;
-
-    case PL041_sl2tx:
-        s->regs.sl2tx = value;
-        s->regs.slfr &= ~SL2TXEMPTY;
-        break;
-
-    case PL041_intclr:
-        DBG_L1("=> Clear interrupt intclr = 0x%08x isr1 = 0x%08x\n",
-               s->regs.intclr, s->regs.isr1);
-
-        if (s->regs.intclr & TXUEC1) {
-            s->regs.sr1 &= ~TXUNDERRUN;
-        }
-        break;
-
-    case PL041_maincr:
-    {
-#if defined(PL041_DEBUG_LEVEL)
-        char debug[] = " AACIFE  SL1RXEN  SL1TXEN";
-        if (!(value & AACIFE)) {
-            debug[0] = '!';
-        }
-        if (!(value & SL1RXEN)) {
-            debug[8] = '!';
-        }
-        if (!(value & SL1TXEN)) {
-            debug[17] = '!';
-        }
-        DBG_L1("%s\n", debug);
-#endif
-
-        if ((s->regs.maincr & AACIFE) == 0) {
-            pl041_reset(s);
-        }
-        break;
-    }
-
-    case PL041_dr1_0:
-    case PL041_dr1_1:
-    case PL041_dr1_2:
-    case PL041_dr1_3:
-        pl041_fifo1_write(s, value);
-        break;
-    }
-
-    /* Transmit the FIFO content */
-    pl041_fifo1_transmit(s);
-
-    /* Update the ISR1 register */
-    pl041_isr1_update(s);
-}
-
-static void pl041_device_reset(DeviceState *d)
-{
-    pl041_state *s = DO_UPCAST(pl041_state, busdev.qdev, d);
-
-    pl041_reset(s);
-}
-
-static const MemoryRegionOps pl041_ops = {
-    .read = pl041_read,
-    .write = pl041_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int pl041_init(SysBusDevice *dev)
-{
-    pl041_state *s = FROM_SYSBUS(pl041_state, dev);
-
-    DBG_L1("pl041_init 0x%08x\n", (uint32_t)s);
-
-    /* Check the device properties */
-    switch (s->fifo_depth) {
-    case 8:
-    case 32:
-    case 64:
-    case 128:
-    case 256:
-    case 512:
-    case 1024:
-    case 2048:
-        break;
-    case 16:
-    default:
-        /* NC FIFO depth of 16 is not allowed because its id bits in
-           AACIPERIPHID3 overlap with the id for the default NC FIFO depth */
-        qemu_log_mask(LOG_UNIMP,
-                      "pl041: unsupported non-compact fifo depth [%i]\n",
-                      s->fifo_depth);
-        return -1;
-    }
-
-    /* Connect the device to the sysbus */
-    memory_region_init_io(&s->iomem, &pl041_ops, s, "pl041", 0x1000);
-    sysbus_init_mmio(dev, &s->iomem);
-    sysbus_init_irq(dev, &s->irq);
-
-    /* Init the codec */
-    lm4549_init(&s->codec, &pl041_request_data, (void *)s);
-
-    return 0;
-}
-
-static const VMStateDescription vmstate_pl041_regfile = {
-    .name = "pl041_regfile",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField[]) {
-#define REGISTER(name, offset) VMSTATE_UINT32(name, pl041_regfile),
-        #include "pl041.hx"
-#undef REGISTER
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static const VMStateDescription vmstate_pl041_fifo = {
-    .name = "pl041_fifo",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField[]) {
-        VMSTATE_UINT32(level, pl041_fifo),
-        VMSTATE_UINT32_ARRAY(data, pl041_fifo, MAX_FIFO_DEPTH),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static const VMStateDescription vmstate_pl041_channel = {
-    .name = "pl041_channel",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField[]) {
-        VMSTATE_STRUCT(tx_fifo, pl041_channel, 0,
-                       vmstate_pl041_fifo, pl041_fifo),
-        VMSTATE_UINT8(tx_enabled, pl041_channel),
-        VMSTATE_UINT8(tx_compact_mode, pl041_channel),
-        VMSTATE_UINT8(tx_sample_size, pl041_channel),
-        VMSTATE_STRUCT(rx_fifo, pl041_channel, 0,
-                       vmstate_pl041_fifo, pl041_fifo),
-        VMSTATE_UINT8(rx_enabled, pl041_channel),
-        VMSTATE_UINT8(rx_compact_mode, pl041_channel),
-        VMSTATE_UINT8(rx_sample_size, pl041_channel),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static const VMStateDescription vmstate_pl041 = {
-    .name = "pl041",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT32(fifo_depth, pl041_state),
-        VMSTATE_STRUCT(regs, pl041_state, 0,
-                       vmstate_pl041_regfile, pl041_regfile),
-        VMSTATE_STRUCT(fifo1, pl041_state, 0,
-                       vmstate_pl041_channel, pl041_channel),
-        VMSTATE_STRUCT(codec, pl041_state, 0,
-                       vmstate_lm4549_state, lm4549_state),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static Property pl041_device_properties[] = {
-    /* Non-compact FIFO depth property */
-    DEFINE_PROP_UINT32("nc_fifo_depth", pl041_state, fifo_depth, DEFAULT_FIFO_DEPTH),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void pl041_device_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = pl041_init;
-    dc->no_user = 1;
-    dc->reset = pl041_device_reset;
-    dc->vmsd = &vmstate_pl041;
-    dc->props = pl041_device_properties;
-}
-
-static const 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_types(void)
-{
-    type_register_static(&pl041_device_info);
-}
-
-type_init(pl041_register_types)
diff --git a/hw/pl041.h b/hw/pl041.h
deleted file mode 100644 (file)
index 427ab6d..0000000
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Arm PrimeCell PL041 Advanced Audio Codec Interface
- *
- * Copyright (c) 2011
- * Written by Mathieu Sonet - www.elasticsheep.com
- *
- * This code is licensed under the GPL.
- *
- * *****************************************************************
- */
-
-#ifndef HW_PL041_H
-#define HW_PL041_H
-
-/* Register file */
-#define REGISTER(name, offset) uint32_t name;
-typedef struct {
-    #include "pl041.hx"
-} pl041_regfile;
-#undef REGISTER
-
-/* Register addresses */
-#define REGISTER(name, offset) PL041_##name = offset,
-enum {
-    #include "pl041.hx"
-
-    PL041_periphid0 = 0xFE0,
-    PL041_periphid1 = 0xFE4,
-    PL041_periphid2 = 0xFE8,
-    PL041_periphid3 = 0xFEC,
-    PL041_pcellid0  = 0xFF0,
-    PL041_pcellid1  = 0xFF4,
-    PL041_pcellid2  = 0xFF8,
-    PL041_pcellid3  = 0xFFC,
-};
-#undef REGISTER
-
-/* Register bits */
-
-/* IEx */
-#define TXCIE           (1 << 0)
-#define RXTIE           (1 << 1)
-#define TXIE            (1 << 2)
-#define RXIE            (1 << 3)
-#define RXOIE           (1 << 4)
-#define TXUIE           (1 << 5)
-#define RXTOIE          (1 << 6)
-
-/* TXCRx */
-#define TXEN            (1 << 0)
-#define TXSLOT1         (1 << 1)
-#define TXSLOT2         (1 << 2)
-#define TXSLOT3         (1 << 3)
-#define TXSLOT4         (1 << 4)
-#define TXCOMPACT       (1 << 15)
-#define TXFEN           (1 << 16)
-
-#define TXSLOT_MASK_BIT (1)
-#define TXSLOT_MASK     (0xFFF << TXSLOT_MASK_BIT)
-
-#define TSIZE_MASK_BIT  (13)
-#define TSIZE_MASK      (0x3 << TSIZE_MASK_BIT)
-
-#define TSIZE_16BITS    (0x0 << TSIZE_MASK_BIT)
-#define TSIZE_18BITS    (0x1 << TSIZE_MASK_BIT)
-#define TSIZE_20BITS    (0x2 << TSIZE_MASK_BIT)
-#define TSIZE_12BITS    (0x3 << TSIZE_MASK_BIT)
-
-/* SRx */
-#define RXFE         (1 << 0)
-#define TXFE         (1 << 1)
-#define RXHF         (1 << 2)
-#define TXHE         (1 << 3)
-#define RXFF         (1 << 4)
-#define TXFF         (1 << 5)
-#define RXBUSY       (1 << 6)
-#define TXBUSY       (1 << 7)
-#define RXOVERRUN    (1 << 8)
-#define TXUNDERRUN   (1 << 9)
-#define RXTIMEOUT    (1 << 10)
-#define RXTOFE       (1 << 11)
-
-/* ISRx */
-#define TXCINTR      (1 << 0)
-#define RXTOINTR     (1 << 1)
-#define TXINTR       (1 << 2)
-#define RXINTR       (1 << 3)
-#define ORINTR       (1 << 4)
-#define URINTR       (1 << 5)
-#define RXTOFEINTR   (1 << 6)
-
-/* SLFR */
-#define SL1RXBUSY    (1 << 0)
-#define SL1TXBUSY    (1 << 1)
-#define SL2RXBUSY    (1 << 2)
-#define SL2TXBUSY    (1 << 3)
-#define SL12RXBUSY   (1 << 4)
-#define SL12TXBUSY   (1 << 5)
-#define SL1RXVALID   (1 << 6)
-#define SL1TXEMPTY   (1 << 7)
-#define SL2RXVALID   (1 << 8)
-#define SL2TXEMPTY   (1 << 9)
-#define SL12RXVALID  (1 << 10)
-#define SL12TXEMPTY  (1 << 11)
-#define RAWGPIOINT   (1 << 12)
-#define RWIS         (1 << 13)
-
-/* MAINCR */
-#define AACIFE       (1 << 0)
-#define LOOPBACK     (1 << 1)
-#define LOWPOWER     (1 << 2)
-#define SL1RXEN      (1 << 3)
-#define SL1TXEN      (1 << 4)
-#define SL2RXEN      (1 << 5)
-#define SL2TXEN      (1 << 6)
-#define SL12RXEN     (1 << 7)
-#define SL12TXEN     (1 << 8)
-#define DMAENABLE    (1 << 9)
-
-/* INTCLR */
-#define WISC         (1 << 0)
-#define RXOEC1       (1 << 1)
-#define RXOEC2       (1 << 2)
-#define RXOEC3       (1 << 3)
-#define RXOEC4       (1 << 4)
-#define TXUEC1       (1 << 5)
-#define TXUEC2       (1 << 6)
-#define TXUEC3       (1 << 7)
-#define TXUEC4       (1 << 8)
-#define RXTOFEC1     (1 << 9)
-#define RXTOFEC2     (1 << 10)
-#define RXTOFEC3     (1 << 11)
-#define RXTOFEC4     (1 << 12)
-
-#endif /* #ifndef HW_PL041_H */
diff --git a/hw/pl041.hx b/hw/pl041.hx
deleted file mode 100644 (file)
index dd7188c..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Arm PrimeCell PL041 Advanced Audio Codec Interface
- *
- * Copyright (c) 2011
- * Written by Mathieu Sonet - www.elasticsheep.com
- *
- * This code is licensed under the GPL.
- *
- * *****************************************************************
- */
-
-/* PL041 register file description */
-
-REGISTER( rxcr1,   0x00 )
-REGISTER( txcr1,   0x04 )
-REGISTER( sr1,     0x08 )
-REGISTER( isr1,    0x0C )
-REGISTER( ie1,     0x10 )
-REGISTER( rxcr2,   0x14 )
-REGISTER( txcr2,   0x18 )
-REGISTER( sr2,     0x1C )
-REGISTER( isr2,    0x20 )
-REGISTER( ie2,     0x24 )
-REGISTER( rxcr3,   0x28 )
-REGISTER( txcr3,   0x2C )
-REGISTER( sr3,     0x30 )
-REGISTER( isr3,    0x34 )
-REGISTER( ie3,     0x38 )
-REGISTER( rxcr4,   0x3C )
-REGISTER( txcr4,   0x40 )
-REGISTER( sr4,     0x44 )
-REGISTER( isr4,    0x48 )
-REGISTER( ie4,     0x4C )
-REGISTER( sl1rx,   0x50 )
-REGISTER( sl1tx,   0x54 )
-REGISTER( sl2rx,   0x58 )
-REGISTER( sl2tx,   0x5C )
-REGISTER( sl12rx,  0x60 )
-REGISTER( sl12tx,  0x64 )
-REGISTER( slfr,    0x68 )
-REGISTER( slistat, 0x6C )
-REGISTER( slien,   0x70 )
-REGISTER( intclr,  0x74 )
-REGISTER( maincr,  0x78 )
-REGISTER( reset,   0x7C )
-REGISTER( sync,    0x80 )
-REGISTER( allints, 0x84 )
-REGISTER( mainfr,  0x88 )
-REGISTER( unused,  0x8C )
-REGISTER( dr1_0,   0x90 )
-REGISTER( dr1_1,   0x94 )
-REGISTER( dr1_2,   0x98 )
-REGISTER( dr1_3,   0x9C )
-REGISTER( dr1_4,   0xA0 )
-REGISTER( dr1_5,   0xA4 )
-REGISTER( dr1_6,   0xA8 )
-REGISTER( dr1_7,   0xAC )
-REGISTER( dr2_0,   0xB0 )
-REGISTER( dr2_1,   0xB4 )
-REGISTER( dr2_2,   0xB8 )
-REGISTER( dr2_3,   0xBC )
-REGISTER( dr2_4,   0xC0 )
-REGISTER( dr2_5,   0xC4 )
-REGISTER( dr2_6,   0xC8 )
-REGISTER( dr2_7,   0xCC )
-REGISTER( dr3_0,   0xD0 )
-REGISTER( dr3_1,   0xD4 )
-REGISTER( dr3_2,   0xD8 )
-REGISTER( dr3_3,   0xDC )
-REGISTER( dr3_4,   0xE0 )
-REGISTER( dr3_5,   0xE4 )
-REGISTER( dr3_6,   0xE8 )
-REGISTER( dr3_7,   0xEC )
-REGISTER( dr4_0,   0xF0 )
-REGISTER( dr4_1,   0xF4 )
-REGISTER( dr4_2,   0xF8 )
-REGISTER( dr4_3,   0xFC )
-REGISTER( dr4_4,   0x100 )
-REGISTER( dr4_5,   0x104 )
-REGISTER( dr4_6,   0x108 )
-REGISTER( dr4_7,   0x10C )
diff --git a/hw/pl050.c b/hw/pl050.c
deleted file mode 100644 (file)
index bc31ab6..0000000
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * Arm PrimeCell PL050 Keyboard / Mouse Interface
- *
- * Copyright (c) 2006-2007 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the GPL.
- */
-
-#include "hw/sysbus.h"
-#include "hw/ps2.h"
-
-typedef struct {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-    void *dev;
-    uint32_t cr;
-    uint32_t clk;
-    uint32_t last;
-    int pending;
-    qemu_irq irq;
-    int is_mouse;
-} pl050_state;
-
-static const VMStateDescription vmstate_pl050 = {
-    .name = "pl050",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT32(cr, pl050_state),
-        VMSTATE_UINT32(clk, pl050_state),
-        VMSTATE_UINT32(last, pl050_state),
-        VMSTATE_INT32(pending, pl050_state),
-        VMSTATE_INT32(is_mouse, pl050_state),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-#define PL050_TXEMPTY         (1 << 6)
-#define PL050_TXBUSY          (1 << 5)
-#define PL050_RXFULL          (1 << 4)
-#define PL050_RXBUSY          (1 << 3)
-#define PL050_RXPARITY        (1 << 2)
-#define PL050_KMIC            (1 << 1)
-#define PL050_KMID            (1 << 0)
-
-static const unsigned char pl050_id[] =
-{ 0x50, 0x10, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
-
-static void pl050_update(void *opaque, int level)
-{
-    pl050_state *s = (pl050_state *)opaque;
-    int raise;
-
-    s->pending = level;
-    raise = (s->pending && (s->cr & 0x10) != 0)
-            || (s->cr & 0x08) != 0;
-    qemu_set_irq(s->irq, raise);
-}
-
-static uint64_t pl050_read(void *opaque, hwaddr offset,
-                           unsigned size)
-{
-    pl050_state *s = (pl050_state *)opaque;
-    if (offset >= 0xfe0 && offset < 0x1000)
-        return pl050_id[(offset - 0xfe0) >> 2];
-
-    switch (offset >> 2) {
-    case 0: /* KMICR */
-        return s->cr;
-    case 1: /* KMISTAT */
-        {
-            uint8_t val;
-            uint32_t stat;
-
-            val = s->last;
-            val = val ^ (val >> 4);
-            val = val ^ (val >> 2);
-            val = (val ^ (val >> 1)) & 1;
-
-            stat = PL050_TXEMPTY;
-            if (val)
-                stat |= PL050_RXPARITY;
-            if (s->pending)
-                stat |= PL050_RXFULL;
-
-            return stat;
-        }
-    case 2: /* KMIDATA */
-        if (s->pending)
-            s->last = ps2_read_data(s->dev);
-        return s->last;
-    case 3: /* KMICLKDIV */
-        return s->clk;
-    case 4: /* KMIIR */
-        return s->pending | 2;
-    default:
-        qemu_log_mask(LOG_GUEST_ERROR,
-                      "pl050_read: Bad offset %x\n", (int)offset);
-        return 0;
-    }
-}
-
-static void pl050_write(void *opaque, hwaddr offset,
-                        uint64_t value, unsigned size)
-{
-    pl050_state *s = (pl050_state *)opaque;
-    switch (offset >> 2) {
-    case 0: /* KMICR */
-        s->cr = value;
-        pl050_update(s, s->pending);
-        /* ??? Need to implement the enable/disable bit.  */
-        break;
-    case 2: /* KMIDATA */
-        /* ??? This should toggle the TX interrupt line.  */
-        /* ??? This means kbd/mouse can block each other.  */
-        if (s->is_mouse) {
-            ps2_write_mouse(s->dev, value);
-        } else {
-            ps2_write_keyboard(s->dev, value);
-        }
-        break;
-    case 3: /* KMICLKDIV */
-        s->clk = value;
-        return;
-    default:
-        qemu_log_mask(LOG_GUEST_ERROR,
-                      "pl050_write: Bad offset %x\n", (int)offset);
-    }
-}
-static const MemoryRegionOps pl050_ops = {
-    .read = pl050_read,
-    .write = pl050_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int pl050_init(SysBusDevice *dev, int is_mouse)
-{
-    pl050_state *s = FROM_SYSBUS(pl050_state, dev);
-
-    memory_region_init_io(&s->iomem, &pl050_ops, s, "pl050", 0x1000);
-    sysbus_init_mmio(dev, &s->iomem);
-    sysbus_init_irq(dev, &s->irq);
-    s->is_mouse = is_mouse;
-    if (s->is_mouse)
-        s->dev = ps2_mouse_init(pl050_update, s);
-    else
-        s->dev = ps2_kbd_init(pl050_update, s);
-    return 0;
-}
-
-static int pl050_init_keyboard(SysBusDevice *dev)
-{
-    return pl050_init(dev, 0);
-}
-
-static int pl050_init_mouse(SysBusDevice *dev)
-{
-    return pl050_init(dev, 1);
-}
-
-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 const 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 const 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_types(void)
-{
-    type_register_static(&pl050_kbd_info);
-    type_register_static(&pl050_mouse_info);
-}
-
-type_init(pl050_register_types)
diff --git a/hw/pl061.c b/hw/pl061.c
deleted file mode 100644 (file)
index 74bc109..0000000
+++ /dev/null
@@ -1,336 +0,0 @@
-/*
- * Arm PrimeCell PL061 General Purpose IO with additional
- * Luminary Micro Stellaris bits.
- *
- * Copyright (c) 2007 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the GPL.
- */
-
-#include "hw/sysbus.h"
-
-//#define DEBUG_PL061 1
-
-#ifdef DEBUG_PL061
-#define DPRINTF(fmt, ...) \
-do { printf("pl061: " fmt , ## __VA_ARGS__); } while (0)
-#define BADF(fmt, ...) \
-do { fprintf(stderr, "pl061: error: " fmt , ## __VA_ARGS__); exit(1);} while (0)
-#else
-#define DPRINTF(fmt, ...) do {} while(0)
-#define BADF(fmt, ...) \
-do { fprintf(stderr, "pl061: error: " fmt , ## __VA_ARGS__);} while (0)
-#endif
-
-static const uint8_t pl061_id[12] =
-  { 0x00, 0x00, 0x00, 0x00, 0x61, 0x10, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
-static const uint8_t pl061_id_luminary[12] =
-  { 0x00, 0x00, 0x00, 0x00, 0x61, 0x00, 0x18, 0x01, 0x0d, 0xf0, 0x05, 0xb1 };
-
-typedef struct {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-    uint32_t locked;
-    uint32_t data;
-    uint32_t old_data;
-    uint32_t dir;
-    uint32_t isense;
-    uint32_t ibe;
-    uint32_t iev;
-    uint32_t im;
-    uint32_t istate;
-    uint32_t afsel;
-    uint32_t dr2r;
-    uint32_t dr4r;
-    uint32_t dr8r;
-    uint32_t odr;
-    uint32_t pur;
-    uint32_t pdr;
-    uint32_t slr;
-    uint32_t den;
-    uint32_t cr;
-    uint32_t float_high;
-    uint32_t amsel;
-    qemu_irq irq;
-    qemu_irq out[8];
-    const unsigned char *id;
-} pl061_state;
-
-static const VMStateDescription vmstate_pl061 = {
-    .name = "pl061",
-    .version_id = 2,
-    .minimum_version_id = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT32(locked, pl061_state),
-        VMSTATE_UINT32(data, pl061_state),
-        VMSTATE_UINT32(old_data, pl061_state),
-        VMSTATE_UINT32(dir, pl061_state),
-        VMSTATE_UINT32(isense, pl061_state),
-        VMSTATE_UINT32(ibe, pl061_state),
-        VMSTATE_UINT32(iev, pl061_state),
-        VMSTATE_UINT32(im, pl061_state),
-        VMSTATE_UINT32(istate, pl061_state),
-        VMSTATE_UINT32(afsel, pl061_state),
-        VMSTATE_UINT32(dr2r, pl061_state),
-        VMSTATE_UINT32(dr4r, pl061_state),
-        VMSTATE_UINT32(dr8r, pl061_state),
-        VMSTATE_UINT32(odr, pl061_state),
-        VMSTATE_UINT32(pur, pl061_state),
-        VMSTATE_UINT32(pdr, pl061_state),
-        VMSTATE_UINT32(slr, pl061_state),
-        VMSTATE_UINT32(den, pl061_state),
-        VMSTATE_UINT32(cr, pl061_state),
-        VMSTATE_UINT32(float_high, pl061_state),
-        VMSTATE_UINT32_V(amsel, pl061_state, 2),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void pl061_update(pl061_state *s)
-{
-    uint8_t changed;
-    uint8_t mask;
-    uint8_t out;
-    int i;
-
-    /* Outputs float high.  */
-    /* FIXME: This is board dependent.  */
-    out = (s->data & s->dir) | ~s->dir;
-    changed = s->old_data ^ out;
-    if (!changed)
-        return;
-
-    s->old_data = out;
-    for (i = 0; i < 8; i++) {
-        mask = 1 << i;
-        if (changed & mask) {
-            DPRINTF("Set output %d = %d\n", i, (out & mask) != 0);
-            qemu_set_irq(s->out[i], (out & mask) != 0);
-        }
-    }
-
-    /* FIXME: Implement input interrupts.  */
-}
-
-static uint64_t pl061_read(void *opaque, hwaddr offset,
-                           unsigned size)
-{
-    pl061_state *s = (pl061_state *)opaque;
-
-    if (offset >= 0xfd0 && offset < 0x1000) {
-        return s->id[(offset - 0xfd0) >> 2];
-    }
-    if (offset < 0x400) {
-        return s->data & (offset >> 2);
-    }
-    switch (offset) {
-    case 0x400: /* Direction */
-        return s->dir;
-    case 0x404: /* Interrupt sense */
-        return s->isense;
-    case 0x408: /* Interrupt both edges */
-        return s->ibe;
-    case 0x40c: /* Interrupt event */
-        return s->iev;
-    case 0x410: /* Interrupt mask */
-        return s->im;
-    case 0x414: /* Raw interrupt status */
-        return s->istate;
-    case 0x418: /* Masked interrupt status */
-        return s->istate | s->im;
-    case 0x420: /* Alternate function select */
-        return s->afsel;
-    case 0x500: /* 2mA drive */
-        return s->dr2r;
-    case 0x504: /* 4mA drive */
-        return s->dr4r;
-    case 0x508: /* 8mA drive */
-        return s->dr8r;
-    case 0x50c: /* Open drain */
-        return s->odr;
-    case 0x510: /* Pull-up */
-        return s->pur;
-    case 0x514: /* Pull-down */
-        return s->pdr;
-    case 0x518: /* Slew rate control */
-        return s->slr;
-    case 0x51c: /* Digital enable */
-        return s->den;
-    case 0x520: /* Lock */
-        return s->locked;
-    case 0x524: /* Commit */
-        return s->cr;
-    case 0x528: /* Analog mode select */
-        return s->amsel;
-    default:
-        qemu_log_mask(LOG_GUEST_ERROR,
-                      "pl061_read: Bad offset %x\n", (int)offset);
-        return 0;
-    }
-}
-
-static void pl061_write(void *opaque, hwaddr offset,
-                        uint64_t value, unsigned size)
-{
-    pl061_state *s = (pl061_state *)opaque;
-    uint8_t mask;
-
-    if (offset < 0x400) {
-        mask = (offset >> 2) & s->dir;
-        s->data = (s->data & ~mask) | (value & mask);
-        pl061_update(s);
-        return;
-    }
-    switch (offset) {
-    case 0x400: /* Direction */
-        s->dir = value & 0xff;
-        break;
-    case 0x404: /* Interrupt sense */
-        s->isense = value & 0xff;
-        break;
-    case 0x408: /* Interrupt both edges */
-        s->ibe = value & 0xff;
-        break;
-    case 0x40c: /* Interrupt event */
-        s->iev = value & 0xff;
-        break;
-    case 0x410: /* Interrupt mask */
-        s->im = value & 0xff;
-        break;
-    case 0x41c: /* Interrupt clear */
-        s->istate &= ~value;
-        break;
-    case 0x420: /* Alternate function select */
-        mask = s->cr;
-        s->afsel = (s->afsel & ~mask) | (value & mask);
-        break;
-    case 0x500: /* 2mA drive */
-        s->dr2r = value & 0xff;
-        break;
-    case 0x504: /* 4mA drive */
-        s->dr4r = value & 0xff;
-        break;
-    case 0x508: /* 8mA drive */
-        s->dr8r = value & 0xff;
-        break;
-    case 0x50c: /* Open drain */
-        s->odr = value & 0xff;
-        break;
-    case 0x510: /* Pull-up */
-        s->pur = value & 0xff;
-        break;
-    case 0x514: /* Pull-down */
-        s->pdr = value & 0xff;
-        break;
-    case 0x518: /* Slew rate control */
-        s->slr = value & 0xff;
-        break;
-    case 0x51c: /* Digital enable */
-        s->den = value & 0xff;
-        break;
-    case 0x520: /* Lock */
-        s->locked = (value != 0xacce551);
-        break;
-    case 0x524: /* Commit */
-        if (!s->locked)
-            s->cr = value & 0xff;
-        break;
-    case 0x528:
-        s->amsel = value & 0xff;
-        break;
-    default:
-        qemu_log_mask(LOG_GUEST_ERROR,
-                      "pl061_write: Bad offset %x\n", (int)offset);
-    }
-    pl061_update(s);
-}
-
-static void pl061_reset(pl061_state *s)
-{
-  s->locked = 1;
-  s->cr = 0xff;
-}
-
-static void pl061_set_irq(void * opaque, int irq, int level)
-{
-    pl061_state *s = (pl061_state *)opaque;
-    uint8_t mask;
-
-    mask = 1 << irq;
-    if ((s->dir & mask) == 0) {
-        s->data &= ~mask;
-        if (level)
-            s->data |= mask;
-        pl061_update(s);
-    }
-}
-
-static const MemoryRegionOps pl061_ops = {
-    .read = pl061_read,
-    .write = pl061_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int pl061_init(SysBusDevice *dev, const unsigned char *id)
-{
-    pl061_state *s = FROM_SYSBUS(pl061_state, dev);
-    s->id = id;
-    memory_region_init_io(&s->iomem, &pl061_ops, s, "pl061", 0x1000);
-    sysbus_init_mmio(dev, &s->iomem);
-    sysbus_init_irq(dev, &s->irq);
-    qdev_init_gpio_in(&dev->qdev, pl061_set_irq, 8);
-    qdev_init_gpio_out(&dev->qdev, s->out, 8);
-    pl061_reset(s);
-    return 0;
-}
-
-static int pl061_init_luminary(SysBusDevice *dev)
-{
-    return pl061_init(dev, pl061_id_luminary);
-}
-
-static int pl061_init_arm(SysBusDevice *dev)
-{
-    return pl061_init(dev, pl061_id);
-}
-
-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 const 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 const 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_types(void)
-{
-    type_register_static(&pl061_info);
-    type_register_static(&pl061_luminary_info);
-}
-
-type_init(pl061_register_types)
diff --git a/hw/pl080.c b/hw/pl080.c
deleted file mode 100644 (file)
index 00b66b4..0000000
+++ /dev/null
@@ -1,421 +0,0 @@
-/*
- * Arm PrimeCell PL080/PL081 DMA controller
- *
- * Copyright (c) 2006 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the GPL.
- */
-
-#include "hw/sysbus.h"
-
-#define PL080_MAX_CHANNELS 8
-#define PL080_CONF_E    0x1
-#define PL080_CONF_M1   0x2
-#define PL080_CONF_M2   0x4
-
-#define PL080_CCONF_H   0x40000
-#define PL080_CCONF_A   0x20000
-#define PL080_CCONF_L   0x10000
-#define PL080_CCONF_ITC 0x08000
-#define PL080_CCONF_IE  0x04000
-#define PL080_CCONF_E   0x00001
-
-#define PL080_CCTRL_I   0x80000000
-#define PL080_CCTRL_DI  0x08000000
-#define PL080_CCTRL_SI  0x04000000
-#define PL080_CCTRL_D   0x02000000
-#define PL080_CCTRL_S   0x01000000
-
-typedef struct {
-    uint32_t src;
-    uint32_t dest;
-    uint32_t lli;
-    uint32_t ctrl;
-    uint32_t conf;
-} pl080_channel;
-
-typedef struct {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-    uint8_t tc_int;
-    uint8_t tc_mask;
-    uint8_t err_int;
-    uint8_t err_mask;
-    uint32_t conf;
-    uint32_t sync;
-    uint32_t req_single;
-    uint32_t req_burst;
-    pl080_channel chan[PL080_MAX_CHANNELS];
-    int nchannels;
-    /* Flag to avoid recursive DMA invocations.  */
-    int running;
-    qemu_irq irq;
-} pl080_state;
-
-static const VMStateDescription vmstate_pl080_channel = {
-    .name = "pl080_channel",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT32(src, pl080_channel),
-        VMSTATE_UINT32(dest, pl080_channel),
-        VMSTATE_UINT32(lli, pl080_channel),
-        VMSTATE_UINT32(ctrl, pl080_channel),
-        VMSTATE_UINT32(conf, pl080_channel),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static const VMStateDescription vmstate_pl080 = {
-    .name = "pl080",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT8(tc_int, pl080_state),
-        VMSTATE_UINT8(tc_mask, pl080_state),
-        VMSTATE_UINT8(err_int, pl080_state),
-        VMSTATE_UINT8(err_mask, pl080_state),
-        VMSTATE_UINT32(conf, pl080_state),
-        VMSTATE_UINT32(sync, pl080_state),
-        VMSTATE_UINT32(req_single, pl080_state),
-        VMSTATE_UINT32(req_burst, pl080_state),
-        VMSTATE_UINT8(tc_int, pl080_state),
-        VMSTATE_UINT8(tc_int, pl080_state),
-        VMSTATE_UINT8(tc_int, pl080_state),
-        VMSTATE_STRUCT_ARRAY(chan, pl080_state, PL080_MAX_CHANNELS,
-                             1, vmstate_pl080_channel, pl080_channel),
-        VMSTATE_INT32(running, pl080_state),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static const unsigned char pl080_id[] =
-{ 0x80, 0x10, 0x04, 0x0a, 0x0d, 0xf0, 0x05, 0xb1 };
-
-static const unsigned char pl081_id[] =
-{ 0x81, 0x10, 0x04, 0x0a, 0x0d, 0xf0, 0x05, 0xb1 };
-
-static void pl080_update(pl080_state *s)
-{
-    if ((s->tc_int & s->tc_mask)
-            || (s->err_int & s->err_mask))
-        qemu_irq_raise(s->irq);
-    else
-        qemu_irq_lower(s->irq);
-}
-
-static void pl080_run(pl080_state *s)
-{
-    int c;
-    int flow;
-    pl080_channel *ch;
-    int swidth;
-    int dwidth;
-    int xsize;
-    int n;
-    int src_id;
-    int dest_id;
-    int size;
-    uint8_t buff[4];
-    uint32_t req;
-
-    s->tc_mask = 0;
-    for (c = 0; c < s->nchannels; c++) {
-        if (s->chan[c].conf & PL080_CCONF_ITC)
-            s->tc_mask |= 1 << c;
-        if (s->chan[c].conf & PL080_CCONF_IE)
-            s->err_mask |= 1 << c;
-    }
-
-    if ((s->conf & PL080_CONF_E) == 0)
-        return;
-
-hw_error("DMA active\n");
-    /* If we are already in the middle of a DMA operation then indicate that
-       there may be new DMA requests and return immediately.  */
-    if (s->running) {
-        s->running++;
-        return;
-    }
-    s->running = 1;
-    while (s->running) {
-        for (c = 0; c < s->nchannels; c++) {
-            ch = &s->chan[c];
-again:
-            /* Test if thiws channel has any pending DMA requests.  */
-            if ((ch->conf & (PL080_CCONF_H | PL080_CCONF_E))
-                    != PL080_CCONF_E)
-                continue;
-            flow = (ch->conf >> 11) & 7;
-            if (flow >= 4) {
-                hw_error(
-                    "pl080_run: Peripheral flow control not implemented\n");
-            }
-            src_id = (ch->conf >> 1) & 0x1f;
-            dest_id = (ch->conf >> 6) & 0x1f;
-            size = ch->ctrl & 0xfff;
-            req = s->req_single | s->req_burst;
-            switch (flow) {
-            case 0:
-                break;
-            case 1:
-                if ((req & (1u << dest_id)) == 0)
-                    size = 0;
-                break;
-            case 2:
-                if ((req & (1u << src_id)) == 0)
-                    size = 0;
-                break;
-            case 3:
-                if ((req & (1u << src_id)) == 0
-                        || (req & (1u << dest_id)) == 0)
-                    size = 0;
-                break;
-            }
-            if (!size)
-                continue;
-
-            /* Transfer one element.  */
-            /* ??? Should transfer multiple elements for a burst request.  */
-            /* ??? Unclear what the proper behavior is when source and
-               destination widths are different.  */
-            swidth = 1 << ((ch->ctrl >> 18) & 7);
-            dwidth = 1 << ((ch->ctrl >> 21) & 7);
-            for (n = 0; n < dwidth; n+= swidth) {
-                cpu_physical_memory_read(ch->src, buff + n, swidth);
-                if (ch->ctrl & PL080_CCTRL_SI)
-                    ch->src += swidth;
-            }
-            xsize = (dwidth < swidth) ? swidth : dwidth;
-            /* ??? This may pad the value incorrectly for dwidth < 32.  */
-            for (n = 0; n < xsize; n += dwidth) {
-                cpu_physical_memory_write(ch->dest + n, buff + n, dwidth);
-                if (ch->ctrl & PL080_CCTRL_DI)
-                    ch->dest += swidth;
-            }
-
-            size--;
-            ch->ctrl = (ch->ctrl & 0xfffff000) | size;
-            if (size == 0) {
-                /* Transfer complete.  */
-                if (ch->lli) {
-                    ch->src = ldl_le_phys(ch->lli);
-                    ch->dest = ldl_le_phys(ch->lli + 4);
-                    ch->ctrl = ldl_le_phys(ch->lli + 12);
-                    ch->lli = ldl_le_phys(ch->lli + 8);
-                } else {
-                    ch->conf &= ~PL080_CCONF_E;
-                }
-                if (ch->ctrl & PL080_CCTRL_I) {
-                    s->tc_int |= 1 << c;
-                }
-            }
-            goto again;
-        }
-        if (--s->running)
-            s->running = 1;
-    }
-}
-
-static uint64_t pl080_read(void *opaque, hwaddr offset,
-                           unsigned size)
-{
-    pl080_state *s = (pl080_state *)opaque;
-    uint32_t i;
-    uint32_t mask;
-
-    if (offset >= 0xfe0 && offset < 0x1000) {
-        if (s->nchannels == 8) {
-            return pl080_id[(offset - 0xfe0) >> 2];
-        } else {
-            return pl081_id[(offset - 0xfe0) >> 2];
-        }
-    }
-    if (offset >= 0x100 && offset < 0x200) {
-        i = (offset & 0xe0) >> 5;
-        if (i >= s->nchannels)
-            goto bad_offset;
-        switch (offset >> 2) {
-        case 0: /* SrcAddr */
-            return s->chan[i].src;
-        case 1: /* DestAddr */
-            return s->chan[i].dest;
-        case 2: /* LLI */
-            return s->chan[i].lli;
-        case 3: /* Control */
-            return s->chan[i].ctrl;
-        case 4: /* Configuration */
-            return s->chan[i].conf;
-        default:
-            goto bad_offset;
-        }
-    }
-    switch (offset >> 2) {
-    case 0: /* IntStatus */
-        return (s->tc_int & s->tc_mask) | (s->err_int & s->err_mask);
-    case 1: /* IntTCStatus */
-        return (s->tc_int & s->tc_mask);
-    case 3: /* IntErrorStatus */
-        return (s->err_int & s->err_mask);
-    case 5: /* RawIntTCStatus */
-        return s->tc_int;
-    case 6: /* RawIntErrorStatus */
-        return s->err_int;
-    case 7: /* EnbldChns */
-        mask = 0;
-        for (i = 0; i < s->nchannels; i++) {
-            if (s->chan[i].conf & PL080_CCONF_E)
-                mask |= 1 << i;
-        }
-        return mask;
-    case 8: /* SoftBReq */
-    case 9: /* SoftSReq */
-    case 10: /* SoftLBReq */
-    case 11: /* SoftLSReq */
-        /* ??? Implement these. */
-        return 0;
-    case 12: /* Configuration */
-        return s->conf;
-    case 13: /* Sync */
-        return s->sync;
-    default:
-    bad_offset:
-        qemu_log_mask(LOG_GUEST_ERROR,
-                      "pl080_read: Bad offset %x\n", (int)offset);
-        return 0;
-    }
-}
-
-static void pl080_write(void *opaque, hwaddr offset,
-                        uint64_t value, unsigned size)
-{
-    pl080_state *s = (pl080_state *)opaque;
-    int i;
-
-    if (offset >= 0x100 && offset < 0x200) {
-        i = (offset & 0xe0) >> 5;
-        if (i >= s->nchannels)
-            goto bad_offset;
-        switch (offset >> 2) {
-        case 0: /* SrcAddr */
-            s->chan[i].src = value;
-            break;
-        case 1: /* DestAddr */
-            s->chan[i].dest = value;
-            break;
-        case 2: /* LLI */
-            s->chan[i].lli = value;
-            break;
-        case 3: /* Control */
-            s->chan[i].ctrl = value;
-            break;
-        case 4: /* Configuration */
-            s->chan[i].conf = value;
-            pl080_run(s);
-            break;
-        }
-    }
-    switch (offset >> 2) {
-    case 2: /* IntTCClear */
-        s->tc_int &= ~value;
-        break;
-    case 4: /* IntErrorClear */
-        s->err_int &= ~value;
-        break;
-    case 8: /* SoftBReq */
-    case 9: /* SoftSReq */
-    case 10: /* SoftLBReq */
-    case 11: /* SoftLSReq */
-        /* ??? Implement these.  */
-        qemu_log_mask(LOG_UNIMP, "pl080_write: Soft DMA not implemented\n");
-        break;
-    case 12: /* Configuration */
-        s->conf = value;
-        if (s->conf & (PL080_CONF_M1 | PL080_CONF_M1)) {
-            qemu_log_mask(LOG_UNIMP,
-                          "pl080_write: Big-endian DMA not implemented\n");
-        }
-        pl080_run(s);
-        break;
-    case 13: /* Sync */
-        s->sync = value;
-        break;
-    default:
-    bad_offset:
-        qemu_log_mask(LOG_GUEST_ERROR,
-                      "pl080_write: Bad offset %x\n", (int)offset);
-    }
-    pl080_update(s);
-}
-
-static const MemoryRegionOps pl080_ops = {
-    .read = pl080_read,
-    .write = pl080_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int pl08x_init(SysBusDevice *dev, int nchannels)
-{
-    pl080_state *s = FROM_SYSBUS(pl080_state, dev);
-
-    memory_region_init_io(&s->iomem, &pl080_ops, s, "pl080", 0x1000);
-    sysbus_init_mmio(dev, &s->iomem);
-    sysbus_init_irq(dev, &s->irq);
-    s->nchannels = nchannels;
-    return 0;
-}
-
-static int pl080_init(SysBusDevice *dev)
-{
-    return pl08x_init(dev, 8);
-}
-
-static int pl081_init(SysBusDevice *dev)
-{
-    return pl08x_init(dev, 2);
-}
-
-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 const 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 const 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_types(void)
-{
-    type_register_static(&pl080_info);
-    type_register_static(&pl081_info);
-}
-
-type_init(pl080_register_types)
diff --git a/hw/pl110.c b/hw/pl110.c
deleted file mode 100644 (file)
index fbef675..0000000
+++ /dev/null
@@ -1,533 +0,0 @@
-/*
- * Arm PrimeCell PL110 Color LCD Controller
- *
- * Copyright (c) 2005-2009 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the GNU LGPL
- */
-
-#include "hw/sysbus.h"
-#include "ui/console.h"
-#include "hw/framebuffer.h"
-#include "ui/pixel_ops.h"
-
-#define PL110_CR_EN   0x001
-#define PL110_CR_BGR  0x100
-#define PL110_CR_BEBO 0x200
-#define PL110_CR_BEPO 0x400
-#define PL110_CR_PWR  0x800
-
-enum pl110_bppmode
-{
-    BPP_1,
-    BPP_2,
-    BPP_4,
-    BPP_8,
-    BPP_16,
-    BPP_32,
-    BPP_16_565, /* PL111 only */
-    BPP_12      /* PL111 only */
-};
-
-
-/* The Versatile/PB uses a slightly modified PL110 controller.  */
-enum pl110_version
-{
-    PL110,
-    PL110_VERSATILE,
-    PL111
-};
-
-typedef struct {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-    QemuConsole *con;
-
-    int version;
-    uint32_t timing[4];
-    uint32_t cr;
-    uint32_t upbase;
-    uint32_t lpbase;
-    uint32_t int_status;
-    uint32_t int_mask;
-    int cols;
-    int rows;
-    enum pl110_bppmode bpp;
-    int invalidate;
-    uint32_t mux_ctrl;
-    uint32_t palette[256];
-    uint32_t raw_palette[128];
-    qemu_irq irq;
-} pl110_state;
-
-static int vmstate_pl110_post_load(void *opaque, int version_id);
-
-static const VMStateDescription vmstate_pl110 = {
-    .name = "pl110",
-    .version_id = 2,
-    .minimum_version_id = 1,
-    .post_load = vmstate_pl110_post_load,
-    .fields = (VMStateField[]) {
-        VMSTATE_INT32(version, pl110_state),
-        VMSTATE_UINT32_ARRAY(timing, pl110_state, 4),
-        VMSTATE_UINT32(cr, pl110_state),
-        VMSTATE_UINT32(upbase, pl110_state),
-        VMSTATE_UINT32(lpbase, pl110_state),
-        VMSTATE_UINT32(int_status, pl110_state),
-        VMSTATE_UINT32(int_mask, pl110_state),
-        VMSTATE_INT32(cols, pl110_state),
-        VMSTATE_INT32(rows, pl110_state),
-        VMSTATE_UINT32(bpp, pl110_state),
-        VMSTATE_INT32(invalidate, pl110_state),
-        VMSTATE_UINT32_ARRAY(palette, pl110_state, 256),
-        VMSTATE_UINT32_ARRAY(raw_palette, pl110_state, 128),
-        VMSTATE_UINT32_V(mux_ctrl, pl110_state, 2),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static const unsigned char pl110_id[] =
-{ 0x10, 0x11, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
-
-/* The Arm documentation (DDI0224C) says the CLDC on the Versatile board
-   has a different ID.  However Linux only looks for the normal ID.  */
-#if 0
-static const unsigned char pl110_versatile_id[] =
-{ 0x93, 0x10, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
-#else
-#define pl110_versatile_id pl110_id
-#endif
-
-static const unsigned char pl111_id[] = {
-    0x11, 0x11, 0x24, 0x00, 0x0d, 0xf0, 0x05, 0xb1
-};
-
-/* Indexed by pl110_version */
-static const unsigned char *idregs[] = {
-    pl110_id,
-    pl110_versatile_id,
-    pl111_id
-};
-
-#define BITS 8
-#include "hw/pl110_template.h"
-#define BITS 15
-#include "hw/pl110_template.h"
-#define BITS 16
-#include "hw/pl110_template.h"
-#define BITS 24
-#include "hw/pl110_template.h"
-#define BITS 32
-#include "hw/pl110_template.h"
-
-static int pl110_enabled(pl110_state *s)
-{
-  return (s->cr & PL110_CR_EN) && (s->cr & PL110_CR_PWR);
-}
-
-static void pl110_update_display(void *opaque)
-{
-    pl110_state *s = (pl110_state *)opaque;
-    DisplaySurface *surface = qemu_console_surface(s->con);
-    drawfn* fntable;
-    drawfn fn;
-    int dest_width;
-    int src_width;
-    int bpp_offset;
-    int first;
-    int last;
-
-    if (!pl110_enabled(s))
-        return;
-
-    switch (surface_bits_per_pixel(surface)) {
-    case 0:
-        return;
-    case 8:
-        fntable = pl110_draw_fn_8;
-        dest_width = 1;
-        break;
-    case 15:
-        fntable = pl110_draw_fn_15;
-        dest_width = 2;
-        break;
-    case 16:
-        fntable = pl110_draw_fn_16;
-        dest_width = 2;
-        break;
-    case 24:
-        fntable = pl110_draw_fn_24;
-        dest_width = 3;
-        break;
-    case 32:
-        fntable = pl110_draw_fn_32;
-        dest_width = 4;
-        break;
-    default:
-        fprintf(stderr, "pl110: Bad color depth\n");
-        exit(1);
-    }
-    if (s->cr & PL110_CR_BGR)
-        bpp_offset = 0;
-    else
-        bpp_offset = 24;
-
-    if ((s->version != PL111) && (s->bpp == BPP_16)) {
-        /* The PL110's native 16 bit mode is 5551; however
-         * most boards with a PL110 implement an external
-         * mux which allows bits to be reshuffled to give
-         * 565 format. The mux is typically controlled by
-         * an external system register.
-         * This is controlled by a GPIO input pin
-         * so boards can wire it up to their register.
-         *
-         * The PL111 straightforwardly implements both
-         * 5551 and 565 under control of the bpp field
-         * in the LCDControl register.
-         */
-        switch (s->mux_ctrl) {
-        case 3: /* 565 BGR */
-            bpp_offset = (BPP_16_565 - BPP_16);
-            break;
-        case 1: /* 5551 */
-            break;
-        case 0: /* 888; also if we have loaded vmstate from an old version */
-        case 2: /* 565 RGB */
-        default:
-            /* treat as 565 but honour BGR bit */
-            bpp_offset += (BPP_16_565 - BPP_16);
-            break;
-        }
-    }
-
-    if (s->cr & PL110_CR_BEBO)
-        fn = fntable[s->bpp + 8 + bpp_offset];
-    else if (s->cr & PL110_CR_BEPO)
-        fn = fntable[s->bpp + 16 + bpp_offset];
-    else
-        fn = fntable[s->bpp + bpp_offset];
-
-    src_width = s->cols;
-    switch (s->bpp) {
-    case BPP_1:
-        src_width >>= 3;
-        break;
-    case BPP_2:
-        src_width >>= 2;
-        break;
-    case BPP_4:
-        src_width >>= 1;
-        break;
-    case BPP_8:
-        break;
-    case BPP_16:
-    case BPP_16_565:
-    case BPP_12:
-        src_width <<= 1;
-        break;
-    case BPP_32:
-        src_width <<= 2;
-        break;
-    }
-    dest_width *= s->cols;
-    first = 0;
-    framebuffer_update_display(surface, sysbus_address_space(&s->busdev),
-                               s->upbase, s->cols, s->rows,
-                               src_width, dest_width, 0,
-                               s->invalidate,
-                               fn, s->palette,
-                               &first, &last);
-    if (first >= 0) {
-        dpy_gfx_update(s->con, 0, first, s->cols, last - first + 1);
-    }
-    s->invalidate = 0;
-}
-
-static void pl110_invalidate_display(void * opaque)
-{
-    pl110_state *s = (pl110_state *)opaque;
-    s->invalidate = 1;
-    if (pl110_enabled(s)) {
-        qemu_console_resize(s->con, s->cols, s->rows);
-    }
-}
-
-static void pl110_update_palette(pl110_state *s, int n)
-{
-    DisplaySurface *surface = qemu_console_surface(s->con);
-    int i;
-    uint32_t raw;
-    unsigned int r, g, b;
-
-    raw = s->raw_palette[n];
-    n <<= 1;
-    for (i = 0; i < 2; i++) {
-        r = (raw & 0x1f) << 3;
-        raw >>= 5;
-        g = (raw & 0x1f) << 3;
-        raw >>= 5;
-        b = (raw & 0x1f) << 3;
-        /* The I bit is ignored.  */
-        raw >>= 6;
-        switch (surface_bits_per_pixel(surface)) {
-        case 8:
-            s->palette[n] = rgb_to_pixel8(r, g, b);
-            break;
-        case 15:
-            s->palette[n] = rgb_to_pixel15(r, g, b);
-            break;
-        case 16:
-            s->palette[n] = rgb_to_pixel16(r, g, b);
-            break;
-        case 24:
-        case 32:
-            s->palette[n] = rgb_to_pixel32(r, g, b);
-            break;
-        }
-        n++;
-    }
-}
-
-static void pl110_resize(pl110_state *s, int width, int height)
-{
-    if (width != s->cols || height != s->rows) {
-        if (pl110_enabled(s)) {
-            qemu_console_resize(s->con, width, height);
-        }
-    }
-    s->cols = width;
-    s->rows = height;
-}
-
-/* Update interrupts.  */
-static void pl110_update(pl110_state *s)
-{
-  /* TODO: Implement interrupts.  */
-}
-
-static uint64_t pl110_read(void *opaque, hwaddr offset,
-                           unsigned size)
-{
-    pl110_state *s = (pl110_state *)opaque;
-
-    if (offset >= 0xfe0 && offset < 0x1000) {
-        return idregs[s->version][(offset - 0xfe0) >> 2];
-    }
-    if (offset >= 0x200 && offset < 0x400) {
-        return s->raw_palette[(offset - 0x200) >> 2];
-    }
-    switch (offset >> 2) {
-    case 0: /* LCDTiming0 */
-        return s->timing[0];
-    case 1: /* LCDTiming1 */
-        return s->timing[1];
-    case 2: /* LCDTiming2 */
-        return s->timing[2];
-    case 3: /* LCDTiming3 */
-        return s->timing[3];
-    case 4: /* LCDUPBASE */
-        return s->upbase;
-    case 5: /* LCDLPBASE */
-        return s->lpbase;
-    case 6: /* LCDIMSC */
-        if (s->version != PL110) {
-            return s->cr;
-        }
-        return s->int_mask;
-    case 7: /* LCDControl */
-        if (s->version != PL110) {
-            return s->int_mask;
-        }
-        return s->cr;
-    case 8: /* LCDRIS */
-        return s->int_status;
-    case 9: /* LCDMIS */
-        return s->int_status & s->int_mask;
-    case 11: /* LCDUPCURR */
-        /* TODO: Implement vertical refresh.  */
-        return s->upbase;
-    case 12: /* LCDLPCURR */
-        return s->lpbase;
-    default:
-        qemu_log_mask(LOG_GUEST_ERROR,
-                      "pl110_read: Bad offset %x\n", (int)offset);
-        return 0;
-    }
-}
-
-static void pl110_write(void *opaque, hwaddr offset,
-                        uint64_t val, unsigned size)
-{
-    pl110_state *s = (pl110_state *)opaque;
-    int n;
-
-    /* For simplicity invalidate the display whenever a control register
-       is written to.  */
-    s->invalidate = 1;
-    if (offset >= 0x200 && offset < 0x400) {
-        /* Palette.  */
-        n = (offset - 0x200) >> 2;
-        s->raw_palette[(offset - 0x200) >> 2] = val;
-        pl110_update_palette(s, n);
-        return;
-    }
-    switch (offset >> 2) {
-    case 0: /* LCDTiming0 */
-        s->timing[0] = val;
-        n = ((val & 0xfc) + 4) * 4;
-        pl110_resize(s, n, s->rows);
-        break;
-    case 1: /* LCDTiming1 */
-        s->timing[1] = val;
-        n = (val & 0x3ff) + 1;
-        pl110_resize(s, s->cols, n);
-        break;
-    case 2: /* LCDTiming2 */
-        s->timing[2] = val;
-        break;
-    case 3: /* LCDTiming3 */
-        s->timing[3] = val;
-        break;
-    case 4: /* LCDUPBASE */
-        s->upbase = val;
-        break;
-    case 5: /* LCDLPBASE */
-        s->lpbase = val;
-        break;
-    case 6: /* LCDIMSC */
-        if (s->version != PL110) {
-            goto control;
-        }
-    imsc:
-        s->int_mask = val;
-        pl110_update(s);
-        break;
-    case 7: /* LCDControl */
-        if (s->version != PL110) {
-            goto imsc;
-        }
-    control:
-        s->cr = val;
-        s->bpp = (val >> 1) & 7;
-        if (pl110_enabled(s)) {
-            qemu_console_resize(s->con, s->cols, s->rows);
-        }
-        break;
-    case 10: /* LCDICR */
-        s->int_status &= ~val;
-        pl110_update(s);
-        break;
-    default:
-        qemu_log_mask(LOG_GUEST_ERROR,
-                      "pl110_write: Bad offset %x\n", (int)offset);
-    }
-}
-
-static const MemoryRegionOps pl110_ops = {
-    .read = pl110_read,
-    .write = pl110_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void pl110_mux_ctrl_set(void *opaque, int line, int level)
-{
-    pl110_state *s = (pl110_state *)opaque;
-    s->mux_ctrl = level;
-}
-
-static int vmstate_pl110_post_load(void *opaque, int version_id)
-{
-    pl110_state *s = opaque;
-    /* Make sure we redraw, and at the right size */
-    pl110_invalidate_display(s);
-    return 0;
-}
-
-static int pl110_init(SysBusDevice *dev)
-{
-    pl110_state *s = FROM_SYSBUS(pl110_state, dev);
-
-    memory_region_init_io(&s->iomem, &pl110_ops, s, "pl110", 0x1000);
-    sysbus_init_mmio(dev, &s->iomem);
-    sysbus_init_irq(dev, &s->irq);
-    qdev_init_gpio_in(&s->busdev.qdev, pl110_mux_ctrl_set, 1);
-    s->con = graphic_console_init(pl110_update_display,
-                                  pl110_invalidate_display,
-                                  NULL, NULL, s);
-    return 0;
-}
-
-static int pl110_versatile_init(SysBusDevice *dev)
-{
-    pl110_state *s = FROM_SYSBUS(pl110_state, dev);
-    s->version = PL110_VERSATILE;
-    return pl110_init(dev);
-}
-
-static int pl111_init(SysBusDevice *dev)
-{
-    pl110_state *s = FROM_SYSBUS(pl110_state, dev);
-    s->version = PL111;
-    return pl110_init(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 const 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 const 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 const TypeInfo pl111_info = {
-    .name          = "pl111",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(pl110_state),
-    .class_init    = pl111_class_init,
-};
-
-static void pl110_register_types(void)
-{
-    type_register_static(&pl110_info);
-    type_register_static(&pl110_versatile_info);
-    type_register_static(&pl111_info);
-}
-
-type_init(pl110_register_types)
diff --git a/hw/pl110_template.h b/hw/pl110_template.h
deleted file mode 100644 (file)
index ec4bfd6..0000000
+++ /dev/null
@@ -1,395 +0,0 @@
-/*
- * Arm PrimeCell PL110 Color LCD Controller
- *
- * Copyright (c) 2005 CodeSourcery, LLC.
- * Written by Paul Brook
- *
- * This code is licensed under the GNU LGPL
- *
- * Framebuffer format conversion routines.
- */
-
-#ifndef ORDER
-
-#if BITS == 8
-#define COPY_PIXEL(to, from) *(to++) = from
-#elif BITS == 15 || BITS == 16
-#define COPY_PIXEL(to, from) *(uint16_t *)to = from; to += 2;
-#elif BITS == 24
-#define COPY_PIXEL(to, from) \
-  *(to++) = from; *(to++) = (from) >> 8; *(to++) = (from) >> 16
-#elif BITS == 32
-#define COPY_PIXEL(to, from) *(uint32_t *)to = from; to += 4;
-#else
-#error unknown bit depth
-#endif
-
-#undef RGB
-#define BORDER bgr
-#define ORDER 0
-#include "hw/pl110_template.h"
-#define ORDER 1
-#include "hw/pl110_template.h"
-#define ORDER 2
-#include "hw/pl110_template.h"
-#undef BORDER
-#define RGB
-#define BORDER rgb
-#define ORDER 0
-#include "hw/pl110_template.h"
-#define ORDER 1
-#include "hw/pl110_template.h"
-#define ORDER 2
-#include "hw/pl110_template.h"
-#undef BORDER
-
-static drawfn glue(pl110_draw_fn_,BITS)[48] =
-{
-    glue(pl110_draw_line1_lblp_bgr,BITS),
-    glue(pl110_draw_line2_lblp_bgr,BITS),
-    glue(pl110_draw_line4_lblp_bgr,BITS),
-    glue(pl110_draw_line8_lblp_bgr,BITS),
-    glue(pl110_draw_line16_555_lblp_bgr,BITS),
-    glue(pl110_draw_line32_lblp_bgr,BITS),
-    glue(pl110_draw_line16_lblp_bgr,BITS),
-    glue(pl110_draw_line12_lblp_bgr,BITS),
-
-    glue(pl110_draw_line1_bbbp_bgr,BITS),
-    glue(pl110_draw_line2_bbbp_bgr,BITS),
-    glue(pl110_draw_line4_bbbp_bgr,BITS),
-    glue(pl110_draw_line8_bbbp_bgr,BITS),
-    glue(pl110_draw_line16_555_bbbp_bgr,BITS),
-    glue(pl110_draw_line32_bbbp_bgr,BITS),
-    glue(pl110_draw_line16_bbbp_bgr,BITS),
-    glue(pl110_draw_line12_bbbp_bgr,BITS),
-
-    glue(pl110_draw_line1_lbbp_bgr,BITS),
-    glue(pl110_draw_line2_lbbp_bgr,BITS),
-    glue(pl110_draw_line4_lbbp_bgr,BITS),
-    glue(pl110_draw_line8_lbbp_bgr,BITS),
-    glue(pl110_draw_line16_555_lbbp_bgr,BITS),
-    glue(pl110_draw_line32_lbbp_bgr,BITS),
-    glue(pl110_draw_line16_lbbp_bgr,BITS),
-    glue(pl110_draw_line12_lbbp_bgr,BITS),
-
-    glue(pl110_draw_line1_lblp_rgb,BITS),
-    glue(pl110_draw_line2_lblp_rgb,BITS),
-    glue(pl110_draw_line4_lblp_rgb,BITS),
-    glue(pl110_draw_line8_lblp_rgb,BITS),
-    glue(pl110_draw_line16_555_lblp_rgb,BITS),
-    glue(pl110_draw_line32_lblp_rgb,BITS),
-    glue(pl110_draw_line16_lblp_rgb,BITS),
-    glue(pl110_draw_line12_lblp_rgb,BITS),
-
-    glue(pl110_draw_line1_bbbp_rgb,BITS),
-    glue(pl110_draw_line2_bbbp_rgb,BITS),
-    glue(pl110_draw_line4_bbbp_rgb,BITS),
-    glue(pl110_draw_line8_bbbp_rgb,BITS),
-    glue(pl110_draw_line16_555_bbbp_rgb,BITS),
-    glue(pl110_draw_line32_bbbp_rgb,BITS),
-    glue(pl110_draw_line16_bbbp_rgb,BITS),
-    glue(pl110_draw_line12_bbbp_rgb,BITS),
-
-    glue(pl110_draw_line1_lbbp_rgb,BITS),
-    glue(pl110_draw_line2_lbbp_rgb,BITS),
-    glue(pl110_draw_line4_lbbp_rgb,BITS),
-    glue(pl110_draw_line8_lbbp_rgb,BITS),
-    glue(pl110_draw_line16_555_lbbp_rgb,BITS),
-    glue(pl110_draw_line32_lbbp_rgb,BITS),
-    glue(pl110_draw_line16_lbbp_rgb,BITS),
-    glue(pl110_draw_line12_lbbp_rgb,BITS),
-};
-
-#undef BITS
-#undef COPY_PIXEL
-
-#else
-
-#if ORDER == 0
-#define NAME glue(glue(lblp_, BORDER), BITS)
-#ifdef HOST_WORDS_BIGENDIAN
-#define SWAP_WORDS 1
-#endif
-#elif ORDER == 1
-#define NAME glue(glue(bbbp_, BORDER), BITS)
-#ifndef HOST_WORDS_BIGENDIAN
-#define SWAP_WORDS 1
-#endif
-#else
-#define SWAP_PIXELS 1
-#define NAME glue(glue(lbbp_, BORDER), BITS)
-#ifdef HOST_WORDS_BIGENDIAN
-#define SWAP_WORDS 1
-#endif
-#endif
-
-#define FN_2(x, y) FN(x, y) FN(x+1, y)
-#define FN_4(x, y) FN_2(x, y) FN_2(x+2, y)
-#define FN_8(y) FN_4(0, y) FN_4(4, y)
-
-static void glue(pl110_draw_line1_,NAME)(void *opaque, uint8_t *d, const uint8_t *src, int width, int deststep)
-{
-    uint32_t *palette = opaque;
-    uint32_t data;
-    while (width > 0) {
-        data = *(uint32_t *)src;
-#ifdef SWAP_PIXELS
-#define FN(x, y) COPY_PIXEL(d, palette[(data >> (y + 7 - (x))) & 1]);
-#else
-#define FN(x, y) COPY_PIXEL(d, palette[(data >> ((x) + y)) & 1]);
-#endif
-#ifdef SWAP_WORDS
-        FN_8(24)
-        FN_8(16)
-        FN_8(8)
-        FN_8(0)
-#else
-        FN_8(0)
-        FN_8(8)
-        FN_8(16)
-        FN_8(24)
-#endif
-#undef FN
-        width -= 32;
-        src += 4;
-    }
-}
-
-static void glue(pl110_draw_line2_,NAME)(void *opaque, uint8_t *d, const uint8_t *src, int width, int deststep)
-{
-    uint32_t *palette = opaque;
-    uint32_t data;
-    while (width > 0) {
-        data = *(uint32_t *)src;
-#ifdef SWAP_PIXELS
-#define FN(x, y) COPY_PIXEL(d, palette[(data >> (y + 6 - (x)*2)) & 3]);
-#else
-#define FN(x, y) COPY_PIXEL(d, palette[(data >> ((x)*2 + y)) & 3]);
-#endif
-#ifdef SWAP_WORDS
-        FN_4(0, 24)
-        FN_4(0, 16)
-        FN_4(0, 8)
-        FN_4(0, 0)
-#else
-        FN_4(0, 0)
-        FN_4(0, 8)
-        FN_4(0, 16)
-        FN_4(0, 24)
-#endif
-#undef FN
-        width -= 16;
-        src += 4;
-    }
-}
-
-static void glue(pl110_draw_line4_,NAME)(void *opaque, uint8_t *d, const uint8_t *src, int width, int deststep)
-{
-    uint32_t *palette = opaque;
-    uint32_t data;
-    while (width > 0) {
-        data = *(uint32_t *)src;
-#ifdef SWAP_PIXELS
-#define FN(x, y) COPY_PIXEL(d, palette[(data >> (y + 4 - (x)*4)) & 0xf]);
-#else
-#define FN(x, y) COPY_PIXEL(d, palette[(data >> ((x)*4 + y)) & 0xf]);
-#endif
-#ifdef SWAP_WORDS
-        FN_2(0, 24)
-        FN_2(0, 16)
-        FN_2(0, 8)
-        FN_2(0, 0)
-#else
-        FN_2(0, 0)
-        FN_2(0, 8)
-        FN_2(0, 16)
-        FN_2(0, 24)
-#endif
-#undef FN
-        width -= 8;
-        src += 4;
-    }
-}
-
-static void glue(pl110_draw_line8_,NAME)(void *opaque, uint8_t *d, const uint8_t *src, int width, int deststep)
-{
-    uint32_t *palette = opaque;
-    uint32_t data;
-    while (width > 0) {
-        data = *(uint32_t *)src;
-#define FN(x) COPY_PIXEL(d, palette[(data >> (x)) & 0xff]);
-#ifdef SWAP_WORDS
-        FN(24)
-        FN(16)
-        FN(8)
-        FN(0)
-#else
-        FN(0)
-        FN(8)
-        FN(16)
-        FN(24)
-#endif
-#undef FN
-        width -= 4;
-        src += 4;
-    }
-}
-
-static void glue(pl110_draw_line16_,NAME)(void *opaque, uint8_t *d, const uint8_t *src, int width, int deststep)
-{
-    uint32_t data;
-    unsigned int r, g, b;
-    while (width > 0) {
-        data = *(uint32_t *)src;
-#ifdef SWAP_WORDS
-        data = bswap32(data);
-#endif
-#ifdef RGB
-#define LSB r
-#define MSB b
-#else
-#define LSB b
-#define MSB r
-#endif
-#if 0
-        LSB = data & 0x1f;
-        data >>= 5;
-        g = data & 0x3f;
-        data >>= 6;
-        MSB = data & 0x1f;
-        data >>= 5;
-#else
-        LSB = (data & 0x1f) << 3;
-        data >>= 5;
-        g = (data & 0x3f) << 2;
-        data >>= 6;
-        MSB = (data & 0x1f) << 3;
-        data >>= 5;
-#endif
-        COPY_PIXEL(d, glue(rgb_to_pixel,BITS)(r, g, b));
-        LSB = (data & 0x1f) << 3;
-        data >>= 5;
-        g = (data & 0x3f) << 2;
-        data >>= 6;
-        MSB = (data & 0x1f) << 3;
-        data >>= 5;
-        COPY_PIXEL(d, glue(rgb_to_pixel,BITS)(r, g, b));
-#undef MSB
-#undef LSB
-        width -= 2;
-        src += 4;
-    }
-}
-
-static void glue(pl110_draw_line32_,NAME)(void *opaque, uint8_t *d, const uint8_t *src, int width, int deststep)
-{
-    uint32_t data;
-    unsigned int r, g, b;
-    while (width > 0) {
-        data = *(uint32_t *)src;
-#ifdef RGB
-#define LSB r
-#define MSB b
-#else
-#define LSB b
-#define MSB r
-#endif
-#ifndef SWAP_WORDS
-        LSB = data & 0xff;
-        g = (data >> 8) & 0xff;
-        MSB = (data >> 16) & 0xff;
-#else
-        LSB = (data >> 24) & 0xff;
-        g = (data >> 16) & 0xff;
-        MSB = (data >> 8) & 0xff;
-#endif
-        COPY_PIXEL(d, glue(rgb_to_pixel,BITS)(r, g, b));
-#undef MSB
-#undef LSB
-        width--;
-        src += 4;
-    }
-}
-
-static void glue(pl110_draw_line16_555_,NAME)(void *opaque, uint8_t *d, const uint8_t *src, int width, int deststep)
-{
-    /* RGB 555 plus an intensity bit (which we ignore) */
-    uint32_t data;
-    unsigned int r, g, b;
-    while (width > 0) {
-        data = *(uint32_t *)src;
-#ifdef SWAP_WORDS
-        data = bswap32(data);
-#endif
-#ifdef RGB
-#define LSB r
-#define MSB b
-#else
-#define LSB b
-#define MSB r
-#endif
-        LSB = (data & 0x1f) << 3;
-        data >>= 5;
-        g = (data & 0x1f) << 3;
-        data >>= 5;
-        MSB = (data & 0x1f) << 3;
-        data >>= 5;
-        COPY_PIXEL(d, glue(rgb_to_pixel,BITS)(r, g, b));
-        LSB = (data & 0x1f) << 3;
-        data >>= 5;
-        g = (data & 0x1f) << 3;
-        data >>= 5;
-        MSB = (data & 0x1f) << 3;
-        data >>= 6;
-        COPY_PIXEL(d, glue(rgb_to_pixel,BITS)(r, g, b));
-#undef MSB
-#undef LSB
-        width -= 2;
-        src += 4;
-    }
-}
-
-static void glue(pl110_draw_line12_,NAME)(void *opaque, uint8_t *d, const uint8_t *src, int width, int deststep)
-{
-    /* RGB 444 with 4 bits of zeroes at the top of each halfword */
-    uint32_t data;
-    unsigned int r, g, b;
-    while (width > 0) {
-        data = *(uint32_t *)src;
-#ifdef SWAP_WORDS
-        data = bswap32(data);
-#endif
-#ifdef RGB
-#define LSB r
-#define MSB b
-#else
-#define LSB b
-#define MSB r
-#endif
-        LSB = (data & 0xf) << 4;
-        data >>= 4;
-        g = (data & 0xf) << 4;
-        data >>= 4;
-        MSB = (data & 0xf) << 4;
-        data >>= 8;
-        COPY_PIXEL(d, glue(rgb_to_pixel,BITS)(r, g, b));
-        LSB = (data & 0xf) << 4;
-        data >>= 4;
-        g = (data & 0xf) << 4;
-        data >>= 4;
-        MSB = (data & 0xf) << 4;
-        data >>= 8;
-        COPY_PIXEL(d, glue(rgb_to_pixel,BITS)(r, g, b));
-#undef MSB
-#undef LSB
-        width -= 2;
-        src += 4;
-    }
-}
-
-#undef SWAP_PIXELS
-#undef NAME
-#undef SWAP_WORDS
-#undef ORDER
-
-#endif
diff --git a/hw/pl181.c b/hw/pl181.c
deleted file mode 100644 (file)
index 2527296..0000000
+++ /dev/null
@@ -1,515 +0,0 @@
-/*
- * Arm PrimeCell PL181 MultiMedia Card Interface
- *
- * Copyright (c) 2007 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the GPL.
- */
-
-#include "sysemu/blockdev.h"
-#include "hw/sysbus.h"
-#include "hw/sd.h"
-
-//#define DEBUG_PL181 1
-
-#ifdef DEBUG_PL181
-#define DPRINTF(fmt, ...) \
-do { printf("pl181: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...) do {} while(0)
-#endif
-
-#define PL181_FIFO_LEN 16
-
-typedef struct {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-    SDState *card;
-    uint32_t clock;
-    uint32_t power;
-    uint32_t cmdarg;
-    uint32_t cmd;
-    uint32_t datatimer;
-    uint32_t datalength;
-    uint32_t respcmd;
-    uint32_t response[4];
-    uint32_t datactrl;
-    uint32_t datacnt;
-    uint32_t status;
-    uint32_t mask[2];
-    int32_t fifo_pos;
-    int32_t fifo_len;
-    /* The linux 2.6.21 driver is buggy, and misbehaves if new data arrives
-       while it is reading the FIFO.  We hack around this be defering
-       subsequent transfers until after the driver polls the status word.
-       http://www.arm.linux.org.uk/developer/patches/viewpatch.php?id=4446/1
-     */
-    int32_t linux_hack;
-    uint32_t fifo[PL181_FIFO_LEN];
-    qemu_irq irq[2];
-    /* GPIO outputs for 'card is readonly' and 'card inserted' */
-    qemu_irq cardstatus[2];
-} pl181_state;
-
-static const VMStateDescription vmstate_pl181 = {
-    .name = "pl181",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT32(clock, pl181_state),
-        VMSTATE_UINT32(power, pl181_state),
-        VMSTATE_UINT32(cmdarg, pl181_state),
-        VMSTATE_UINT32(cmd, pl181_state),
-        VMSTATE_UINT32(datatimer, pl181_state),
-        VMSTATE_UINT32(datalength, pl181_state),
-        VMSTATE_UINT32(respcmd, pl181_state),
-        VMSTATE_UINT32_ARRAY(response, pl181_state, 4),
-        VMSTATE_UINT32(datactrl, pl181_state),
-        VMSTATE_UINT32(datacnt, pl181_state),
-        VMSTATE_UINT32(status, pl181_state),
-        VMSTATE_UINT32_ARRAY(mask, pl181_state, 2),
-        VMSTATE_INT32(fifo_pos, pl181_state),
-        VMSTATE_INT32(fifo_len, pl181_state),
-        VMSTATE_INT32(linux_hack, pl181_state),
-        VMSTATE_UINT32_ARRAY(fifo, pl181_state, PL181_FIFO_LEN),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-#define PL181_CMD_INDEX     0x3f
-#define PL181_CMD_RESPONSE  (1 << 6)
-#define PL181_CMD_LONGRESP  (1 << 7)
-#define PL181_CMD_INTERRUPT (1 << 8)
-#define PL181_CMD_PENDING   (1 << 9)
-#define PL181_CMD_ENABLE    (1 << 10)
-
-#define PL181_DATA_ENABLE             (1 << 0)
-#define PL181_DATA_DIRECTION          (1 << 1)
-#define PL181_DATA_MODE               (1 << 2)
-#define PL181_DATA_DMAENABLE          (1 << 3)
-
-#define PL181_STATUS_CMDCRCFAIL       (1 << 0)
-#define PL181_STATUS_DATACRCFAIL      (1 << 1)
-#define PL181_STATUS_CMDTIMEOUT       (1 << 2)
-#define PL181_STATUS_DATATIMEOUT      (1 << 3)
-#define PL181_STATUS_TXUNDERRUN       (1 << 4)
-#define PL181_STATUS_RXOVERRUN        (1 << 5)
-#define PL181_STATUS_CMDRESPEND       (1 << 6)
-#define PL181_STATUS_CMDSENT          (1 << 7)
-#define PL181_STATUS_DATAEND          (1 << 8)
-#define PL181_STATUS_DATABLOCKEND     (1 << 10)
-#define PL181_STATUS_CMDACTIVE        (1 << 11)
-#define PL181_STATUS_TXACTIVE         (1 << 12)
-#define PL181_STATUS_RXACTIVE         (1 << 13)
-#define PL181_STATUS_TXFIFOHALFEMPTY  (1 << 14)
-#define PL181_STATUS_RXFIFOHALFFULL   (1 << 15)
-#define PL181_STATUS_TXFIFOFULL       (1 << 16)
-#define PL181_STATUS_RXFIFOFULL       (1 << 17)
-#define PL181_STATUS_TXFIFOEMPTY      (1 << 18)
-#define PL181_STATUS_RXFIFOEMPTY      (1 << 19)
-#define PL181_STATUS_TXDATAAVLBL      (1 << 20)
-#define PL181_STATUS_RXDATAAVLBL      (1 << 21)
-
-#define PL181_STATUS_TX_FIFO (PL181_STATUS_TXACTIVE \
-                             |PL181_STATUS_TXFIFOHALFEMPTY \
-                             |PL181_STATUS_TXFIFOFULL \
-                             |PL181_STATUS_TXFIFOEMPTY \
-                             |PL181_STATUS_TXDATAAVLBL)
-#define PL181_STATUS_RX_FIFO (PL181_STATUS_RXACTIVE \
-                             |PL181_STATUS_RXFIFOHALFFULL \
-                             |PL181_STATUS_RXFIFOFULL \
-                             |PL181_STATUS_RXFIFOEMPTY \
-                             |PL181_STATUS_RXDATAAVLBL)
-
-static const unsigned char pl181_id[] =
-{ 0x81, 0x11, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
-
-static void pl181_update(pl181_state *s)
-{
-    int i;
-    for (i = 0; i < 2; i++) {
-        qemu_set_irq(s->irq[i], (s->status & s->mask[i]) != 0);
-    }
-}
-
-static void pl181_fifo_push(pl181_state *s, uint32_t value)
-{
-    int n;
-
-    if (s->fifo_len == PL181_FIFO_LEN) {
-        fprintf(stderr, "pl181: FIFO overflow\n");
-        return;
-    }
-    n = (s->fifo_pos + s->fifo_len) & (PL181_FIFO_LEN - 1);
-    s->fifo_len++;
-    s->fifo[n] = value;
-    DPRINTF("FIFO push %08x\n", (int)value);
-}
-
-static uint32_t pl181_fifo_pop(pl181_state *s)
-{
-    uint32_t value;
-
-    if (s->fifo_len == 0) {
-        fprintf(stderr, "pl181: FIFO underflow\n");
-        return 0;
-    }
-    value = s->fifo[s->fifo_pos];
-    s->fifo_len--;
-    s->fifo_pos = (s->fifo_pos + 1) & (PL181_FIFO_LEN - 1);
-    DPRINTF("FIFO pop %08x\n", (int)value);
-    return value;
-}
-
-static void pl181_send_command(pl181_state *s)
-{
-    SDRequest request;
-    uint8_t response[16];
-    int rlen;
-
-    request.cmd = s->cmd & PL181_CMD_INDEX;
-    request.arg = s->cmdarg;
-    DPRINTF("Command %d %08x\n", request.cmd, request.arg);
-    rlen = sd_do_command(s->card, &request, response);
-    if (rlen < 0)
-        goto error;
-    if (s->cmd & PL181_CMD_RESPONSE) {
-#define RWORD(n) ((response[n] << 24) | (response[n + 1] << 16) \
-                  | (response[n + 2] << 8) | response[n + 3])
-        if (rlen == 0 || (rlen == 4 && (s->cmd & PL181_CMD_LONGRESP)))
-            goto error;
-        if (rlen != 4 && rlen != 16)
-            goto error;
-        s->response[0] = RWORD(0);
-        if (rlen == 4) {
-            s->response[1] = s->response[2] = s->response[3] = 0;
-        } else {
-            s->response[1] = RWORD(4);
-            s->response[2] = RWORD(8);
-            s->response[3] = RWORD(12) & ~1;
-        }
-        DPRINTF("Response received\n");
-        s->status |= PL181_STATUS_CMDRESPEND;
-#undef RWORD
-    } else {
-        DPRINTF("Command sent\n");
-        s->status |= PL181_STATUS_CMDSENT;
-    }
-    return;
-
-error:
-    DPRINTF("Timeout\n");
-    s->status |= PL181_STATUS_CMDTIMEOUT;
-}
-
-/* Transfer data between the card and the FIFO.  This is complicated by
-   the FIFO holding 32-bit words and the card taking data in single byte
-   chunks.  FIFO bytes are transferred in little-endian order.  */
-
-static void pl181_fifo_run(pl181_state *s)
-{
-    uint32_t bits;
-    uint32_t value = 0;
-    int n;
-    int is_read;
-
-    is_read = (s->datactrl & PL181_DATA_DIRECTION) != 0;
-    if (s->datacnt != 0 && (!is_read || sd_data_ready(s->card))
-            && !s->linux_hack) {
-        if (is_read) {
-            n = 0;
-            while (s->datacnt && s->fifo_len < PL181_FIFO_LEN) {
-                value |= (uint32_t)sd_read_data(s->card) << (n * 8);
-                s->datacnt--;
-                n++;
-                if (n == 4) {
-                    pl181_fifo_push(s, value);
-                    n = 0;
-                    value = 0;
-                }
-            }
-            if (n != 0) {
-                pl181_fifo_push(s, value);
-            }
-        } else { /* write */
-            n = 0;
-            while (s->datacnt > 0 && (s->fifo_len > 0 || n > 0)) {
-                if (n == 0) {
-                    value = pl181_fifo_pop(s);
-                    n = 4;
-                }
-                n--;
-                s->datacnt--;
-                sd_write_data(s->card, value & 0xff);
-                value >>= 8;
-            }
-        }
-    }
-    s->status &= ~(PL181_STATUS_RX_FIFO | PL181_STATUS_TX_FIFO);
-    if (s->datacnt == 0) {
-        s->status |= PL181_STATUS_DATAEND;
-        /* HACK: */
-        s->status |= PL181_STATUS_DATABLOCKEND;
-        DPRINTF("Transfer Complete\n");
-    }
-    if (s->datacnt == 0 && s->fifo_len == 0) {
-        s->datactrl &= ~PL181_DATA_ENABLE;
-        DPRINTF("Data engine idle\n");
-    } else {
-        /* Update FIFO bits.  */
-        bits = PL181_STATUS_TXACTIVE | PL181_STATUS_RXACTIVE;
-        if (s->fifo_len == 0) {
-            bits |= PL181_STATUS_TXFIFOEMPTY;
-            bits |= PL181_STATUS_RXFIFOEMPTY;
-        } else {
-            bits |= PL181_STATUS_TXDATAAVLBL;
-            bits |= PL181_STATUS_RXDATAAVLBL;
-        }
-        if (s->fifo_len == 16) {
-            bits |= PL181_STATUS_TXFIFOFULL;
-            bits |= PL181_STATUS_RXFIFOFULL;
-        }
-        if (s->fifo_len <= 8) {
-            bits |= PL181_STATUS_TXFIFOHALFEMPTY;
-        }
-        if (s->fifo_len >= 8) {
-            bits |= PL181_STATUS_RXFIFOHALFFULL;
-        }
-        if (s->datactrl & PL181_DATA_DIRECTION) {
-            bits &= PL181_STATUS_RX_FIFO;
-        } else {
-            bits &= PL181_STATUS_TX_FIFO;
-        }
-        s->status |= bits;
-    }
-}
-
-static uint64_t pl181_read(void *opaque, hwaddr offset,
-                           unsigned size)
-{
-    pl181_state *s = (pl181_state *)opaque;
-    uint32_t tmp;
-
-    if (offset >= 0xfe0 && offset < 0x1000) {
-        return pl181_id[(offset - 0xfe0) >> 2];
-    }
-    switch (offset) {
-    case 0x00: /* Power */
-        return s->power;
-    case 0x04: /* Clock */
-        return s->clock;
-    case 0x08: /* Argument */
-        return s->cmdarg;
-    case 0x0c: /* Command */
-        return s->cmd;
-    case 0x10: /* RespCmd */
-        return s->respcmd;
-    case 0x14: /* Response0 */
-        return s->response[0];
-    case 0x18: /* Response1 */
-        return s->response[1];
-    case 0x1c: /* Response2 */
-        return s->response[2];
-    case 0x20: /* Response3 */
-        return s->response[3];
-    case 0x24: /* DataTimer */
-        return s->datatimer;
-    case 0x28: /* DataLength */
-        return s->datalength;
-    case 0x2c: /* DataCtrl */
-        return s->datactrl;
-    case 0x30: /* DataCnt */
-        return s->datacnt;
-    case 0x34: /* Status */
-        tmp = s->status;
-        if (s->linux_hack) {
-            s->linux_hack = 0;
-            pl181_fifo_run(s);
-            pl181_update(s);
-        }
-        return tmp;
-    case 0x3c: /* Mask0 */
-        return s->mask[0];
-    case 0x40: /* Mask1 */
-        return s->mask[1];
-    case 0x48: /* FifoCnt */
-        /* The documentation is somewhat vague about exactly what FifoCnt
-           does.  On real hardware it appears to be when decrememnted
-           when a word is transferred between the FIFO and the serial
-           data engine.  DataCnt is decremented after each byte is
-           transferred between the serial engine and the card.
-           We don't emulate this level of detail, so both can be the same.  */
-        tmp = (s->datacnt + 3) >> 2;
-        if (s->linux_hack) {
-            s->linux_hack = 0;
-            pl181_fifo_run(s);
-            pl181_update(s);
-        }
-        return tmp;
-    case 0x80: case 0x84: case 0x88: case 0x8c: /* FifoData */
-    case 0x90: case 0x94: case 0x98: case 0x9c:
-    case 0xa0: case 0xa4: case 0xa8: case 0xac:
-    case 0xb0: case 0xb4: case 0xb8: case 0xbc:
-        if (s->fifo_len == 0) {
-            qemu_log_mask(LOG_GUEST_ERROR, "pl181: Unexpected FIFO read\n");
-            return 0;
-        } else {
-            uint32_t value;
-            value = pl181_fifo_pop(s);
-            s->linux_hack = 1;
-            pl181_fifo_run(s);
-            pl181_update(s);
-            return value;
-        }
-    default:
-        qemu_log_mask(LOG_GUEST_ERROR,
-                      "pl181_read: Bad offset %x\n", (int)offset);
-        return 0;
-    }
-}
-
-static void pl181_write(void *opaque, hwaddr offset,
-                        uint64_t value, unsigned size)
-{
-    pl181_state *s = (pl181_state *)opaque;
-
-    switch (offset) {
-    case 0x00: /* Power */
-        s->power = value & 0xff;
-        break;
-    case 0x04: /* Clock */
-        s->clock = value & 0xff;
-        break;
-    case 0x08: /* Argument */
-        s->cmdarg = value;
-        break;
-    case 0x0c: /* Command */
-        s->cmd = value;
-        if (s->cmd & PL181_CMD_ENABLE) {
-            if (s->cmd & PL181_CMD_INTERRUPT) {
-                qemu_log_mask(LOG_UNIMP,
-                              "pl181: Interrupt mode not implemented\n");
-            } if (s->cmd & PL181_CMD_PENDING) {
-                qemu_log_mask(LOG_UNIMP,
-                              "pl181: Pending commands not implemented\n");
-            } else {
-                pl181_send_command(s);
-                pl181_fifo_run(s);
-            }
-            /* The command has completed one way or the other.  */
-            s->cmd &= ~PL181_CMD_ENABLE;
-        }
-        break;
-    case 0x24: /* DataTimer */
-        s->datatimer = value;
-        break;
-    case 0x28: /* DataLength */
-        s->datalength = value & 0xffff;
-        break;
-    case 0x2c: /* DataCtrl */
-        s->datactrl = value & 0xff;
-        if (value & PL181_DATA_ENABLE) {
-            s->datacnt = s->datalength;
-            pl181_fifo_run(s);
-        }
-        break;
-    case 0x38: /* Clear */
-        s->status &= ~(value & 0x7ff);
-        break;
-    case 0x3c: /* Mask0 */
-        s->mask[0] = value;
-        break;
-    case 0x40: /* Mask1 */
-        s->mask[1] = value;
-        break;
-    case 0x80: case 0x84: case 0x88: case 0x8c: /* FifoData */
-    case 0x90: case 0x94: case 0x98: case 0x9c:
-    case 0xa0: case 0xa4: case 0xa8: case 0xac:
-    case 0xb0: case 0xb4: case 0xb8: case 0xbc:
-        if (s->datacnt == 0) {
-            qemu_log_mask(LOG_GUEST_ERROR, "pl181: Unexpected FIFO write\n");
-        } else {
-            pl181_fifo_push(s, value);
-            pl181_fifo_run(s);
-        }
-        break;
-    default:
-        qemu_log_mask(LOG_GUEST_ERROR,
-                      "pl181_write: Bad offset %x\n", (int)offset);
-    }
-    pl181_update(s);
-}
-
-static const MemoryRegionOps pl181_ops = {
-    .read = pl181_read,
-    .write = pl181_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void pl181_reset(DeviceState *d)
-{
-    pl181_state *s = DO_UPCAST(pl181_state, busdev.qdev, d);
-
-    s->power = 0;
-    s->cmdarg = 0;
-    s->cmd = 0;
-    s->datatimer = 0;
-    s->datalength = 0;
-    s->respcmd = 0;
-    s->response[0] = 0;
-    s->response[1] = 0;
-    s->response[2] = 0;
-    s->response[3] = 0;
-    s->datatimer = 0;
-    s->datalength = 0;
-    s->datactrl = 0;
-    s->datacnt = 0;
-    s->status = 0;
-    s->linux_hack = 0;
-    s->mask[0] = 0;
-    s->mask[1] = 0;
-
-    /* We can assume our GPIO outputs have been wired up now */
-    sd_set_cb(s->card, s->cardstatus[0], s->cardstatus[1]);
-}
-
-static int pl181_init(SysBusDevice *dev)
-{
-    pl181_state *s = FROM_SYSBUS(pl181_state, dev);
-    DriveInfo *dinfo;
-
-    memory_region_init_io(&s->iomem, &pl181_ops, s, "pl181", 0x1000);
-    sysbus_init_mmio(dev, &s->iomem);
-    sysbus_init_irq(dev, &s->irq[0]);
-    sysbus_init_irq(dev, &s->irq[1]);
-    qdev_init_gpio_out(&s->busdev.qdev, s->cardstatus, 2);
-    dinfo = drive_get_next(IF_SD);
-    s->card = sd_init(dinfo ? dinfo->bdrv : NULL, 0);
-    return 0;
-}
-
-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 const TypeInfo pl181_info = {
-    .name          = "pl181",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(pl181_state),
-    .class_init    = pl181_class_init,
-};
-
-static void pl181_register_types(void)
-{
-    type_register_static(&pl181_info);
-}
-
-type_init(pl181_register_types)
diff --git a/hw/pl190.c b/hw/pl190.c
deleted file mode 100644 (file)
index 9610673..0000000
+++ /dev/null
@@ -1,289 +0,0 @@
-/*
- * Arm PrimeCell PL190 Vector Interrupt Controller
- *
- * Copyright (c) 2006 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the GPL.
- */
-
-#include "hw/sysbus.h"
-
-/* The number of virtual priority levels.  16 user vectors plus the
-   unvectored IRQ.  Chained interrupts would require an additional level
-   if implemented.  */
-
-#define PL190_NUM_PRIO 17
-
-typedef struct {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-    uint32_t level;
-    uint32_t soft_level;
-    uint32_t irq_enable;
-    uint32_t fiq_select;
-    uint8_t vect_control[16];
-    uint32_t vect_addr[PL190_NUM_PRIO];
-    /* Mask containing interrupts with higher priority than this one.  */
-    uint32_t prio_mask[PL190_NUM_PRIO + 1];
-    int protected;
-    /* Current priority level.  */
-    int priority;
-    int prev_prio[PL190_NUM_PRIO];
-    qemu_irq irq;
-    qemu_irq fiq;
-} pl190_state;
-
-static const unsigned char pl190_id[] =
-{ 0x90, 0x11, 0x04, 0x00, 0x0D, 0xf0, 0x05, 0xb1 };
-
-static inline uint32_t pl190_irq_level(pl190_state *s)
-{
-    return (s->level | s->soft_level) & s->irq_enable & ~s->fiq_select;
-}
-
-/* Update interrupts.  */
-static void pl190_update(pl190_state *s)
-{
-    uint32_t level = pl190_irq_level(s);
-    int set;
-
-    set = (level & s->prio_mask[s->priority]) != 0;
-    qemu_set_irq(s->irq, set);
-    set = ((s->level | s->soft_level) & s->fiq_select) != 0;
-    qemu_set_irq(s->fiq, set);
-}
-
-static void pl190_set_irq(void *opaque, int irq, int level)
-{
-    pl190_state *s = (pl190_state *)opaque;
-
-    if (level)
-        s->level |= 1u << irq;
-    else
-        s->level &= ~(1u << irq);
-    pl190_update(s);
-}
-
-static void pl190_update_vectors(pl190_state *s)
-{
-    uint32_t mask;
-    int i;
-    int n;
-
-    mask = 0;
-    for (i = 0; i < 16; i++)
-      {
-        s->prio_mask[i] = mask;
-        if (s->vect_control[i] & 0x20)
-          {
-            n = s->vect_control[i] & 0x1f;
-            mask |= 1 << n;
-          }
-      }
-    s->prio_mask[16] = mask;
-    pl190_update(s);
-}
-
-static uint64_t pl190_read(void *opaque, hwaddr offset,
-                           unsigned size)
-{
-    pl190_state *s = (pl190_state *)opaque;
-    int i;
-
-    if (offset >= 0xfe0 && offset < 0x1000) {
-        return pl190_id[(offset - 0xfe0) >> 2];
-    }
-    if (offset >= 0x100 && offset < 0x140) {
-        return s->vect_addr[(offset - 0x100) >> 2];
-    }
-    if (offset >= 0x200 && offset < 0x240) {
-        return s->vect_control[(offset - 0x200) >> 2];
-    }
-    switch (offset >> 2) {
-    case 0: /* IRQSTATUS */
-        return pl190_irq_level(s);
-    case 1: /* FIQSATUS */
-        return (s->level | s->soft_level) & s->fiq_select;
-    case 2: /* RAWINTR */
-        return s->level | s->soft_level;
-    case 3: /* INTSELECT */
-        return s->fiq_select;
-    case 4: /* INTENABLE */
-        return s->irq_enable;
-    case 6: /* SOFTINT */
-        return s->soft_level;
-    case 8: /* PROTECTION */
-        return s->protected;
-    case 12: /* VECTADDR */
-        /* Read vector address at the start of an ISR.  Increases the
-         * current priority level to that of the current interrupt.
-         *
-         * Since an enabled interrupt X at priority P causes prio_mask[Y]
-         * to have bit X set for all Y > P, this loop will stop with
-         * i == the priority of the highest priority set interrupt.
-         */
-        for (i = 0; i < s->priority; i++) {
-            if ((s->level | s->soft_level) & s->prio_mask[i + 1]) {
-                break;
-            }
-        }
-
-        /* Reading this value with no pending interrupts is undefined.
-           We return the default address.  */
-        if (i == PL190_NUM_PRIO)
-          return s->vect_addr[16];
-        if (i < s->priority)
-          {
-            s->prev_prio[i] = s->priority;
-            s->priority = i;
-            pl190_update(s);
-          }
-        return s->vect_addr[s->priority];
-    case 13: /* DEFVECTADDR */
-        return s->vect_addr[16];
-    default:
-        qemu_log_mask(LOG_GUEST_ERROR,
-                      "pl190_read: Bad offset %x\n", (int)offset);
-        return 0;
-    }
-}
-
-static void pl190_write(void *opaque, hwaddr offset,
-                        uint64_t val, unsigned size)
-{
-    pl190_state *s = (pl190_state *)opaque;
-
-    if (offset >= 0x100 && offset < 0x140) {
-        s->vect_addr[(offset - 0x100) >> 2] = val;
-        pl190_update_vectors(s);
-        return;
-    }
-    if (offset >= 0x200 && offset < 0x240) {
-        s->vect_control[(offset - 0x200) >> 2] = val;
-        pl190_update_vectors(s);
-        return;
-    }
-    switch (offset >> 2) {
-    case 0: /* SELECT */
-        /* This is a readonly register, but linux tries to write to it
-           anyway.  Ignore the write.  */
-        break;
-    case 3: /* INTSELECT */
-        s->fiq_select = val;
-        break;
-    case 4: /* INTENABLE */
-        s->irq_enable |= val;
-        break;
-    case 5: /* INTENCLEAR */
-        s->irq_enable &= ~val;
-        break;
-    case 6: /* SOFTINT */
-        s->soft_level |= val;
-        break;
-    case 7: /* SOFTINTCLEAR */
-        s->soft_level &= ~val;
-        break;
-    case 8: /* PROTECTION */
-        /* TODO: Protection (supervisor only access) is not implemented.  */
-        s->protected = val & 1;
-        break;
-    case 12: /* VECTADDR */
-        /* Restore the previous priority level.  The value written is
-           ignored.  */
-        if (s->priority < PL190_NUM_PRIO)
-            s->priority = s->prev_prio[s->priority];
-        break;
-    case 13: /* DEFVECTADDR */
-        s->vect_addr[16] = val;
-        break;
-    case 0xc0: /* ITCR */
-        if (val) {
-            qemu_log_mask(LOG_UNIMP, "pl190: Test mode not implemented\n");
-        }
-        break;
-    default:
-        qemu_log_mask(LOG_GUEST_ERROR,
-                     "pl190_write: Bad offset %x\n", (int)offset);
-        return;
-    }
-    pl190_update(s);
-}
-
-static const MemoryRegionOps pl190_ops = {
-    .read = pl190_read,
-    .write = pl190_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void pl190_reset(DeviceState *d)
-{
-  pl190_state *s = DO_UPCAST(pl190_state, busdev.qdev, d);
-  int i;
-
-  for (i = 0; i < 16; i++)
-    {
-      s->vect_addr[i] = 0;
-      s->vect_control[i] = 0;
-    }
-  s->vect_addr[16] = 0;
-  s->prio_mask[17] = 0xffffffff;
-  s->priority = PL190_NUM_PRIO;
-  pl190_update_vectors(s);
-}
-
-static int pl190_init(SysBusDevice *dev)
-{
-    pl190_state *s = FROM_SYSBUS(pl190_state, dev);
-
-    memory_region_init_io(&s->iomem, &pl190_ops, s, "pl190", 0x1000);
-    sysbus_init_mmio(dev, &s->iomem);
-    qdev_init_gpio_in(&dev->qdev, pl190_set_irq, 32);
-    sysbus_init_irq(dev, &s->irq);
-    sysbus_init_irq(dev, &s->fiq);
-    return 0;
-}
-
-static const VMStateDescription vmstate_pl190 = {
-    .name = "pl190",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT32(level, pl190_state),
-        VMSTATE_UINT32(soft_level, pl190_state),
-        VMSTATE_UINT32(irq_enable, pl190_state),
-        VMSTATE_UINT32(fiq_select, pl190_state),
-        VMSTATE_UINT8_ARRAY(vect_control, pl190_state, 16),
-        VMSTATE_UINT32_ARRAY(vect_addr, pl190_state, PL190_NUM_PRIO),
-        VMSTATE_UINT32_ARRAY(prio_mask, pl190_state, PL190_NUM_PRIO+1),
-        VMSTATE_INT32(protected, pl190_state),
-        VMSTATE_INT32(priority, pl190_state),
-        VMSTATE_INT32_ARRAY(prev_prio, pl190_state, PL190_NUM_PRIO),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-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 const TypeInfo pl190_info = {
-    .name          = "pl190",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(pl190_state),
-    .class_init    = pl190_class_init,
-};
-
-static void pl190_register_types(void)
-{
-    type_register_static(&pl190_info);
-}
-
-type_init(pl190_register_types)
diff --git a/hw/pl330.c b/hw/pl330.c
deleted file mode 100644 (file)
index 1a04773..0000000
+++ /dev/null
@@ -1,1654 +0,0 @@
-/*
- * ARM PrimeCell PL330 DMA Controller
- *
- * Copyright (c) 2009 Samsung Electronics.
- * Contributed by Kirill Batuzov <batuzovk@ispras.ru>
- * Copyright (c) 2012 Peter A.G. Crosthwaite (peter.crosthwaite@petalogix.com)
- * Copyright (c) 2012 PetaLogix Pty Ltd.
- *
- * 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; version 2 or later.
- *
- * 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 "sysemu/dma.h"
-
-#ifndef PL330_ERR_DEBUG
-#define PL330_ERR_DEBUG 0
-#endif
-
-#define DB_PRINT_L(lvl, fmt, args...) do {\
-    if (PL330_ERR_DEBUG >= lvl) {\
-        fprintf(stderr, "PL330: %s:" fmt, __func__, ## args);\
-    } \
-} while (0);
-
-#define DB_PRINT(fmt, args...) DB_PRINT_L(1, fmt, ## args)
-
-#define PL330_PERIPH_NUM            32
-#define PL330_MAX_BURST_LEN         128
-#define PL330_INSN_MAXSIZE          6
-
-#define PL330_FIFO_OK               0
-#define PL330_FIFO_STALL            1
-#define PL330_FIFO_ERR              (-1)
-
-#define PL330_FAULT_UNDEF_INSTR             (1 <<  0)
-#define PL330_FAULT_OPERAND_INVALID         (1 <<  1)
-#define PL330_FAULT_DMAGO_ERR               (1 <<  4)
-#define PL330_FAULT_EVENT_ERR               (1 <<  5)
-#define PL330_FAULT_CH_PERIPH_ERR           (1 <<  6)
-#define PL330_FAULT_CH_RDWR_ERR             (1 <<  7)
-#define PL330_FAULT_ST_DATA_UNAVAILABLE     (1 << 12)
-#define PL330_FAULT_FIFOEMPTY_ERR           (1 << 13)
-#define PL330_FAULT_INSTR_FETCH_ERR         (1 << 16)
-#define PL330_FAULT_DATA_WRITE_ERR          (1 << 17)
-#define PL330_FAULT_DATA_READ_ERR           (1 << 18)
-#define PL330_FAULT_DBG_INSTR               (1 << 30)
-#define PL330_FAULT_LOCKUP_ERR              (1 << 31)
-
-#define PL330_UNTAGGED              0xff
-
-#define PL330_SINGLE                0x0
-#define PL330_BURST                 0x1
-
-#define PL330_WATCHDOG_LIMIT        1024
-
-/* IOMEM mapped registers */
-#define PL330_REG_DSR               0x000
-#define PL330_REG_DPC               0x004
-#define PL330_REG_INTEN             0x020
-#define PL330_REG_INT_EVENT_RIS     0x024
-#define PL330_REG_INTMIS            0x028
-#define PL330_REG_INTCLR            0x02C
-#define PL330_REG_FSRD              0x030
-#define PL330_REG_FSRC              0x034
-#define PL330_REG_FTRD              0x038
-#define PL330_REG_FTR_BASE          0x040
-#define PL330_REG_CSR_BASE          0x100
-#define PL330_REG_CPC_BASE          0x104
-#define PL330_REG_CHANCTRL          0x400
-#define PL330_REG_DBGSTATUS         0xD00
-#define PL330_REG_DBGCMD            0xD04
-#define PL330_REG_DBGINST0          0xD08
-#define PL330_REG_DBGINST1          0xD0C
-#define PL330_REG_CR0_BASE          0xE00
-#define PL330_REG_PERIPH_ID         0xFE0
-
-#define PL330_IOMEM_SIZE    0x1000
-
-#define CFG_BOOT_ADDR 2
-#define CFG_INS 3
-#define CFG_PNS 4
-#define CFG_CRD 5
-
-static const uint32_t pl330_id[] = {
-    0x30, 0x13, 0x24, 0x00, 0x0D, 0xF0, 0x05, 0xB1
-};
-
-/* DMA channel states as they are described in PL330 Technical Reference Manual
- * Most of them will not be used in emulation.
- */
-typedef enum  {
-    pl330_chan_stopped = 0,
-    pl330_chan_executing = 1,
-    pl330_chan_cache_miss = 2,
-    pl330_chan_updating_pc = 3,
-    pl330_chan_waiting_event = 4,
-    pl330_chan_at_barrier = 5,
-    pl330_chan_queue_busy = 6,
-    pl330_chan_waiting_periph = 7,
-    pl330_chan_killing = 8,
-    pl330_chan_completing = 9,
-    pl330_chan_fault_completing = 14,
-    pl330_chan_fault = 15,
-} PL330ChanState;
-
-typedef struct PL330State PL330State;
-
-typedef struct PL330Chan {
-    uint32_t src;
-    uint32_t dst;
-    uint32_t pc;
-    uint32_t control;
-    uint32_t status;
-    uint32_t lc[2];
-    uint32_t fault_type;
-    uint32_t watchdog_timer;
-
-    bool ns;
-    uint8_t request_flag;
-    uint8_t wakeup;
-    uint8_t wfp_sbp;
-
-    uint8_t state;
-    uint8_t stall;
-
-    bool is_manager;
-    PL330State *parent;
-    uint8_t tag;
-} PL330Chan;
-
-static const VMStateDescription vmstate_pl330_chan = {
-    .name = "pl330_chan",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT32(src, PL330Chan),
-        VMSTATE_UINT32(dst, PL330Chan),
-        VMSTATE_UINT32(pc, PL330Chan),
-        VMSTATE_UINT32(control, PL330Chan),
-        VMSTATE_UINT32(status, PL330Chan),
-        VMSTATE_UINT32_ARRAY(lc, PL330Chan, 2),
-        VMSTATE_UINT32(fault_type, PL330Chan),
-        VMSTATE_UINT32(watchdog_timer, PL330Chan),
-        VMSTATE_BOOL(ns, PL330Chan),
-        VMSTATE_UINT8(request_flag, PL330Chan),
-        VMSTATE_UINT8(wakeup, PL330Chan),
-        VMSTATE_UINT8(wfp_sbp, PL330Chan),
-        VMSTATE_UINT8(state, PL330Chan),
-        VMSTATE_UINT8(stall, PL330Chan),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-typedef struct PL330Fifo {
-    uint8_t *buf;
-    uint8_t *tag;
-    uint32_t head;
-    uint32_t num;
-    uint32_t buf_size;
-} PL330Fifo;
-
-static const VMStateDescription vmstate_pl330_fifo = {
-    .name = "pl330_chan",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_VBUFFER_UINT32(buf, PL330Fifo, 1, NULL, 0, buf_size),
-        VMSTATE_VBUFFER_UINT32(tag, PL330Fifo, 1, NULL, 0, buf_size),
-        VMSTATE_UINT32(head, PL330Fifo),
-        VMSTATE_UINT32(num, PL330Fifo),
-        VMSTATE_UINT32(buf_size, PL330Fifo),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-typedef struct PL330QueueEntry {
-    uint32_t addr;
-    uint32_t len;
-    uint8_t n;
-    bool inc;
-    bool z;
-    uint8_t tag;
-    uint8_t seqn;
-} PL330QueueEntry;
-
-static const VMStateDescription vmstate_pl330_queue_entry = {
-    .name = "pl330_queue_entry",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT32(addr, PL330QueueEntry),
-        VMSTATE_UINT32(len, PL330QueueEntry),
-        VMSTATE_UINT8(n, PL330QueueEntry),
-        VMSTATE_BOOL(inc, PL330QueueEntry),
-        VMSTATE_BOOL(z, PL330QueueEntry),
-        VMSTATE_UINT8(tag, PL330QueueEntry),
-        VMSTATE_UINT8(seqn, PL330QueueEntry),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-typedef struct PL330Queue {
-    PL330State *parent;
-    PL330QueueEntry *queue;
-    uint32_t queue_size;
-} PL330Queue;
-
-static const VMStateDescription vmstate_pl330_queue = {
-    .name = "pl330_queue",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_STRUCT_VARRAY_UINT32(queue, PL330Queue, queue_size, 1,
-                                 vmstate_pl330_queue_entry, PL330QueueEntry),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-struct PL330State {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-    qemu_irq irq_abort;
-    qemu_irq *irq;
-
-    /* Config registers. cfg[5] = CfgDn. */
-    uint32_t cfg[6];
-#define EVENT_SEC_STATE 3
-#define PERIPH_SEC_STATE 4
-    /* cfg 0 bits and pieces */
-    uint32_t num_chnls;
-    uint8_t num_periph_req;
-    uint8_t num_events;
-    uint8_t mgr_ns_at_rst;
-    /* cfg 1 bits and pieces */
-    uint8_t i_cache_len;
-    uint8_t num_i_cache_lines;
-    /* CRD bits and pieces */
-    uint8_t data_width;
-    uint8_t wr_cap;
-    uint8_t wr_q_dep;
-    uint8_t rd_cap;
-    uint8_t rd_q_dep;
-    uint16_t data_buffer_dep;
-
-    PL330Chan manager;
-    PL330Chan *chan;
-    PL330Fifo fifo;
-    PL330Queue read_queue;
-    PL330Queue write_queue;
-    uint8_t *lo_seqn;
-    uint8_t *hi_seqn;
-    QEMUTimer *timer; /* is used for restore dma. */
-
-    uint32_t inten;
-    uint32_t int_status;
-    uint32_t ev_status;
-    uint32_t dbg[2];
-    uint8_t debug_status;
-    uint8_t num_faulting;
-    uint8_t periph_busy[PL330_PERIPH_NUM];
-
-};
-
-#define TYPE_PL330 "pl330"
-#define PL330(obj) OBJECT_CHECK(PL330State, (obj), TYPE_PL330)
-
-static const VMStateDescription vmstate_pl330 = {
-    .name = "pl330",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_STRUCT(manager, PL330State, 0, vmstate_pl330_chan, PL330Chan),
-        VMSTATE_STRUCT_VARRAY_UINT32(chan, PL330State, num_chnls, 0,
-                                     vmstate_pl330_chan, PL330Chan),
-        VMSTATE_VBUFFER_UINT32(lo_seqn, PL330State, 1, NULL, 0, num_chnls),
-        VMSTATE_VBUFFER_UINT32(hi_seqn, PL330State, 1, NULL, 0, num_chnls),
-        VMSTATE_STRUCT(fifo, PL330State, 0, vmstate_pl330_fifo, PL330Fifo),
-        VMSTATE_STRUCT(read_queue, PL330State, 0, vmstate_pl330_queue,
-                       PL330Queue),
-        VMSTATE_STRUCT(write_queue, PL330State, 0, vmstate_pl330_queue,
-                       PL330Queue),
-        VMSTATE_TIMER(timer, PL330State),
-        VMSTATE_UINT32(inten, PL330State),
-        VMSTATE_UINT32(int_status, PL330State),
-        VMSTATE_UINT32(ev_status, PL330State),
-        VMSTATE_UINT32_ARRAY(dbg, PL330State, 2),
-        VMSTATE_UINT8(debug_status, PL330State),
-        VMSTATE_UINT8(num_faulting, PL330State),
-        VMSTATE_UINT8_ARRAY(periph_busy, PL330State, PL330_PERIPH_NUM),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-typedef struct PL330InsnDesc {
-    /* OPCODE of the instruction */
-    uint8_t opcode;
-    /* Mask so we can select several sibling instructions, such as
-       DMALD, DMALDS and DMALDB */
-    uint8_t opmask;
-    /* Size of instruction in bytes */
-    uint8_t size;
-    /* Interpreter */
-    void (*exec)(PL330Chan *, uint8_t opcode, uint8_t *args, int len);
-} PL330InsnDesc;
-
-
-/* MFIFO Implementation
- *
- * MFIFO is implemented as a cyclic buffer of BUF_SIZE size. Tagged bytes are
- * stored in this buffer. Data is stored in BUF field, tags - in the
- * corresponding array elements of TAG field.
- */
-
-/* Initialize queue. */
-
-static void pl330_fifo_init(PL330Fifo *s, uint32_t size)
-{
-    s->buf = g_malloc0(size);
-    s->tag = g_malloc0(size);
-    s->buf_size = size;
-}
-
-/* Cyclic increment */
-
-static inline int pl330_fifo_inc(PL330Fifo *s, int x)
-{
-    return (x + 1) % s->buf_size;
-}
-
-/* Number of empty bytes in MFIFO */
-
-static inline int pl330_fifo_num_free(PL330Fifo *s)
-{
-    return s->buf_size - s->num;
-}
-
-/* Push LEN bytes of data stored in BUF to MFIFO and tag it with TAG.
- * Zero returned on success, PL330_FIFO_STALL if there is no enough free
- * space in MFIFO to store requested amount of data. If push was unsuccessful
- * no data is stored to MFIFO.
- */
-
-static int pl330_fifo_push(PL330Fifo *s, uint8_t *buf, int len, uint8_t tag)
-{
-    int i;
-
-    if (s->buf_size - s->num < len) {
-        return PL330_FIFO_STALL;
-    }
-    for (i = 0; i < len; i++) {
-        int push_idx = (s->head + s->num + i) % s->buf_size;
-        s->buf[push_idx] = buf[i];
-        s->tag[push_idx] = tag;
-    }
-    s->num += len;
-    return PL330_FIFO_OK;
-}
-
-/* Get LEN bytes of data from MFIFO and store it to BUF. Tag value of each
- * byte is verified. Zero returned on success, PL330_FIFO_ERR on tag mismatch
- * and PL330_FIFO_STALL if there is no enough data in MFIFO. If get was
- * unsuccessful no data is removed from MFIFO.
- */
-
-static int pl330_fifo_get(PL330Fifo *s, uint8_t *buf, int len, uint8_t tag)
-{
-    int i;
-
-    if (s->num < len) {
-        return PL330_FIFO_STALL;
-    }
-    for (i = 0; i < len; i++) {
-        if (s->tag[s->head] == tag) {
-            int get_idx = (s->head + i) % s->buf_size;
-            buf[i] = s->buf[get_idx];
-        } else { /* Tag mismatch - Rollback transaction */
-            return PL330_FIFO_ERR;
-        }
-    }
-    s->head = (s->head + len) % s->buf_size;
-    s->num -= len;
-    return PL330_FIFO_OK;
-}
-
-/* Reset MFIFO. This completely erases all data in it. */
-
-static inline void pl330_fifo_reset(PL330Fifo *s)
-{
-    s->head = 0;
-    s->num = 0;
-}
-
-/* Return tag of the first byte stored in MFIFO. If MFIFO is empty
- * PL330_UNTAGGED is returned.
- */
-
-static inline uint8_t pl330_fifo_tag(PL330Fifo *s)
-{
-    return (!s->num) ? PL330_UNTAGGED : s->tag[s->head];
-}
-
-/* Returns non-zero if tag TAG is present in fifo or zero otherwise */
-
-static int pl330_fifo_has_tag(PL330Fifo *s, uint8_t tag)
-{
-    int i, n;
-
-    i = s->head;
-    for (n = 0; n < s->num; n++) {
-        if (s->tag[i] == tag) {
-            return 1;
-        }
-        i = pl330_fifo_inc(s, i);
-    }
-    return 0;
-}
-
-/* Remove all entry tagged with TAG from MFIFO */
-
-static void pl330_fifo_tagged_remove(PL330Fifo *s, uint8_t tag)
-{
-    int i, t, n;
-
-    t = i = s->head;
-    for (n = 0; n < s->num; n++) {
-        if (s->tag[i] != tag) {
-            s->buf[t] = s->buf[i];
-            s->tag[t] = s->tag[i];
-            t = pl330_fifo_inc(s, t);
-        } else {
-            s->num = s->num - 1;
-        }
-        i = pl330_fifo_inc(s, i);
-    }
-}
-
-/* Read-Write Queue implementation
- *
- * A Read-Write Queue stores up to QUEUE_SIZE instructions (loads or stores).
- * Each instruction is described by source (for loads) or destination (for
- * stores) address ADDR, width of data to be loaded/stored LEN, number of
- * stores/loads to be performed N, INC bit, Z bit and TAG to identify channel
- * this instruction belongs to. Queue does not store any information about
- * nature of the instruction: is it load or store. PL330 has different queues
- * for loads and stores so this is already known at the top level where it
- * matters.
- *
- * Queue works as FIFO for instructions with equivalent tags, but can issue
- * instructions with different tags in arbitrary order. SEQN field attached to
- * each instruction helps to achieve this. For each TAG queue contains
- * instructions with consecutive SEQN values ranging from LO_SEQN[TAG] to
- * HI_SEQN[TAG]-1 inclusive. SEQN is 8-bit unsigned integer, so SEQN=255 is
- * followed by SEQN=0.
- *
- * Z bit indicates that zeroes should be stored. No MFIFO fetches are performed
- * in this case.
- */
-
-static void pl330_queue_reset(PL330Queue *s)
-{
-    int i;
-
-    for (i = 0; i < s->queue_size; i++) {
-        s->queue[i].tag = PL330_UNTAGGED;
-    }
-}
-
-/* Initialize queue */
-static void pl330_queue_init(PL330Queue *s, int size, PL330State *parent)
-{
-    s->parent = parent;
-    s->queue = g_new0(PL330QueueEntry, size);
-    s->queue_size = size;
-}
-
-/* Returns pointer to an empty slot or NULL if queue is full */
-static PL330QueueEntry *pl330_queue_find_empty(PL330Queue *s)
-{
-    int i;
-
-    for (i = 0; i < s->queue_size; i++) {
-        if (s->queue[i].tag == PL330_UNTAGGED) {
-            return &s->queue[i];
-        }
-    }
-    return NULL;
-}
-
-/* Put instruction in queue.
- * Return value:
- * - zero - OK
- * - non-zero - queue is full
- */
-
-static int pl330_queue_put_insn(PL330Queue *s, uint32_t addr,
-                                int len, int n, bool inc, bool z, uint8_t tag)
-{
-    PL330QueueEntry *entry = pl330_queue_find_empty(s);
-
-    if (!entry) {
-        return 1;
-    }
-    entry->tag = tag;
-    entry->addr = addr;
-    entry->len = len;
-    entry->n = n;
-    entry->z = z;
-    entry->inc = inc;
-    entry->seqn = s->parent->hi_seqn[tag];
-    s->parent->hi_seqn[tag]++;
-    return 0;
-}
-
-/* Returns a pointer to queue slot containing instruction which satisfies
- *  following conditions:
- *   - it has valid tag value (not PL330_UNTAGGED)
- *   - if enforce_seq is set it has to be issuable without violating queue
- *     logic (see above)
- *   - if TAG argument is not PL330_UNTAGGED this instruction has tag value
- *     equivalent to the argument TAG value.
- *  If such instruction cannot be found NULL is returned.
- */
-
-static PL330QueueEntry *pl330_queue_find_insn(PL330Queue *s, uint8_t tag,
-                                              bool enforce_seq)
-{
-    int i;
-
-    for (i = 0; i < s->queue_size; i++) {
-        if (s->queue[i].tag != PL330_UNTAGGED) {
-            if ((!enforce_seq ||
-                    s->queue[i].seqn == s->parent->lo_seqn[s->queue[i].tag]) &&
-                    (s->queue[i].tag == tag || tag == PL330_UNTAGGED ||
-                    s->queue[i].z)) {
-                return &s->queue[i];
-            }
-        }
-    }
-    return NULL;
-}
-
-/* Removes instruction from queue. */
-
-static inline void pl330_queue_remove_insn(PL330Queue *s, PL330QueueEntry *e)
-{
-    s->parent->lo_seqn[e->tag]++;
-    e->tag = PL330_UNTAGGED;
-}
-
-/* Removes all instructions tagged with TAG from queue. */
-
-static inline void pl330_queue_remove_tagged(PL330Queue *s, uint8_t tag)
-{
-    int i;
-
-    for (i = 0; i < s->queue_size; i++) {
-        if (s->queue[i].tag == tag) {
-            s->queue[i].tag = PL330_UNTAGGED;
-        }
-    }
-}
-
-/* DMA instruction execution engine */
-
-/* Moves DMA channel to the FAULT state and updates it's status. */
-
-static inline void pl330_fault(PL330Chan *ch, uint32_t flags)
-{
-    DB_PRINT("ch: %p, flags: %x\n", ch, flags);
-    ch->fault_type |= flags;
-    if (ch->state == pl330_chan_fault) {
-        return;
-    }
-    ch->state = pl330_chan_fault;
-    ch->parent->num_faulting++;
-    if (ch->parent->num_faulting == 1) {
-        DB_PRINT("abort interrupt raised\n");
-        qemu_irq_raise(ch->parent->irq_abort);
-    }
-}
-
-/*
- * For information about instructions see PL330 Technical Reference Manual.
- *
- * Arguments:
- *   CH - channel executing the instruction
- *   OPCODE - opcode
- *   ARGS - array of 8-bit arguments
- *   LEN - number of elements in ARGS array
- */
-
-static void pl330_dmaaddh(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len)
-{
-    uint16_t im = (((uint16_t)args[1]) << 8) | ((uint16_t)args[0]);
-    uint8_t ra = (opcode >> 1) & 1;
-
-    if (ch->is_manager) {
-        pl330_fault(ch, PL330_FAULT_UNDEF_INSTR);
-        return;
-    }
-    if (ra) {
-        ch->dst += im;
-    } else {
-        ch->src += im;
-    }
-}
-
-static void pl330_dmaend(PL330Chan *ch, uint8_t opcode,
-                         uint8_t *args, int len)
-{
-    PL330State *s = ch->parent;
-
-    if (ch->state == pl330_chan_executing && !ch->is_manager) {
-        /* Wait for all transfers to complete */
-        if (pl330_fifo_has_tag(&s->fifo, ch->tag) ||
-            pl330_queue_find_insn(&s->read_queue, ch->tag, false) != NULL ||
-            pl330_queue_find_insn(&s->write_queue, ch->tag, false) != NULL) {
-
-            ch->stall = 1;
-            return;
-        }
-    }
-    DB_PRINT("DMA ending!\n");
-    pl330_fifo_tagged_remove(&s->fifo, ch->tag);
-    pl330_queue_remove_tagged(&s->read_queue, ch->tag);
-    pl330_queue_remove_tagged(&s->write_queue, ch->tag);
-    ch->state = pl330_chan_stopped;
-}
-
-static void pl330_dmaflushp(PL330Chan *ch, uint8_t opcode,
-                                            uint8_t *args, int len)
-{
-    uint8_t periph_id;
-
-    if (args[0] & 7) {
-        pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
-        return;
-    }
-    periph_id = (args[0] >> 3) & 0x1f;
-    if (periph_id >= ch->parent->num_periph_req) {
-        pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
-        return;
-    }
-    if (ch->ns && !(ch->parent->cfg[CFG_PNS] & (1 << periph_id))) {
-        pl330_fault(ch, PL330_FAULT_CH_PERIPH_ERR);
-        return;
-    }
-    /* Do nothing */
-}
-
-static void pl330_dmago(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len)
-{
-    uint8_t chan_id;
-    uint8_t ns;
-    uint32_t pc;
-    PL330Chan *s;
-
-    DB_PRINT("\n");
-
-    if (!ch->is_manager) {
-        pl330_fault(ch, PL330_FAULT_UNDEF_INSTR);
-        return;
-    }
-    ns = !!(opcode & 2);
-    chan_id = args[0] & 7;
-    if ((args[0] >> 3)) {
-        pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
-        return;
-    }
-    if (chan_id >= ch->parent->num_chnls) {
-        pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
-        return;
-    }
-    pc = (((uint32_t)args[4]) << 24) | (((uint32_t)args[3]) << 16) |
-         (((uint32_t)args[2]) << 8)  | (((uint32_t)args[1]));
-    if (ch->parent->chan[chan_id].state != pl330_chan_stopped) {
-        pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
-        return;
-    }
-    if (ch->ns && !ns) {
-        pl330_fault(ch, PL330_FAULT_DMAGO_ERR);
-        return;
-    }
-    s = &ch->parent->chan[chan_id];
-    s->ns = ns;
-    s->pc = pc;
-    s->state = pl330_chan_executing;
-}
-
-static void pl330_dmald(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len)
-{
-    uint8_t bs = opcode & 3;
-    uint32_t size, num;
-    bool inc;
-
-    if (bs == 2) {
-        pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
-        return;
-    }
-    if ((bs == 1 && ch->request_flag == PL330_BURST) ||
-        (bs == 3 && ch->request_flag == PL330_SINGLE)) {
-        /* Perform NOP */
-        return;
-    }
-    if (bs == 1 && ch->request_flag == PL330_SINGLE) {
-        num = 1;
-    } else {
-        num = ((ch->control >> 4) & 0xf) + 1;
-    }
-    size = (uint32_t)1 << ((ch->control >> 1) & 0x7);
-    inc = !!(ch->control & 1);
-    ch->stall = pl330_queue_put_insn(&ch->parent->read_queue, ch->src,
-                                    size, num, inc, 0, ch->tag);
-    if (!ch->stall) {
-        DB_PRINT("channel:%d address:%08x size:%d num:%d %c\n",
-                 ch->tag, ch->src, size, num, inc ? 'Y' : 'N');
-        ch->src += inc ? size * num - (ch->src & (size - 1)) : 0;
-    }
-}
-
-static void pl330_dmaldp(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len)
-{
-    uint8_t periph_id;
-
-    if (args[0] & 7) {
-        pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
-        return;
-    }
-    periph_id = (args[0] >> 3) & 0x1f;
-    if (periph_id >= ch->parent->num_periph_req) {
-        pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
-        return;
-    }
-    if (ch->ns && !(ch->parent->cfg[CFG_PNS] & (1 << periph_id))) {
-        pl330_fault(ch, PL330_FAULT_CH_PERIPH_ERR);
-        return;
-    }
-    pl330_dmald(ch, opcode, args, len);
-}
-
-static void pl330_dmalp(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len)
-{
-    uint8_t lc = (opcode & 2) >> 1;
-
-    ch->lc[lc] = args[0];
-}
-
-static void pl330_dmakill(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len)
-{
-    if (ch->state == pl330_chan_fault ||
-        ch->state == pl330_chan_fault_completing) {
-        /* This is the only way for a channel to leave the faulting state */
-        ch->fault_type = 0;
-        ch->parent->num_faulting--;
-        if (ch->parent->num_faulting == 0) {
-            DB_PRINT("abort interrupt lowered\n");
-            qemu_irq_lower(ch->parent->irq_abort);
-        }
-    }
-    ch->state = pl330_chan_killing;
-    pl330_fifo_tagged_remove(&ch->parent->fifo, ch->tag);
-    pl330_queue_remove_tagged(&ch->parent->read_queue, ch->tag);
-    pl330_queue_remove_tagged(&ch->parent->write_queue, ch->tag);
-    ch->state = pl330_chan_stopped;
-}
-
-static void pl330_dmalpend(PL330Chan *ch, uint8_t opcode,
-                                    uint8_t *args, int len)
-{
-    uint8_t nf = (opcode & 0x10) >> 4;
-    uint8_t bs = opcode & 3;
-    uint8_t lc = (opcode & 4) >> 2;
-
-    if (bs == 2) {
-        pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
-        return;
-    }
-    if ((bs == 1 && ch->request_flag == PL330_BURST) ||
-        (bs == 3 && ch->request_flag == PL330_SINGLE)) {
-        /* Perform NOP */
-        return;
-    }
-    if (!nf || ch->lc[lc]) {
-        if (nf) {
-            ch->lc[lc]--;
-        }
-        DB_PRINT("loop reiteration\n");
-        ch->pc -= args[0];
-        ch->pc -= len + 1;
-        /* "ch->pc -= args[0] + len + 1" is incorrect when args[0] == 256 */
-    } else {
-        DB_PRINT("loop fallthrough\n");
-    }
-}
-
-
-static void pl330_dmamov(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len)
-{
-    uint8_t rd = args[0] & 7;
-    uint32_t im;
-
-    if ((args[0] >> 3)) {
-        pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
-        return;
-    }
-    im = (((uint32_t)args[4]) << 24) | (((uint32_t)args[3]) << 16) |
-         (((uint32_t)args[2]) << 8)  | (((uint32_t)args[1]));
-    switch (rd) {
-    case 0:
-        ch->src = im;
-        break;
-    case 1:
-        ch->control = im;
-        break;
-    case 2:
-        ch->dst = im;
-        break;
-    default:
-        pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
-        return;
-    }
-}
-
-static void pl330_dmanop(PL330Chan *ch, uint8_t opcode,
-                         uint8_t *args, int len)
-{
-    /* NOP is NOP. */
-}
-
-static void pl330_dmarmb(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len)
-{
-   if (pl330_queue_find_insn(&ch->parent->read_queue, ch->tag, false)) {
-        ch->state = pl330_chan_at_barrier;
-        ch->stall = 1;
-        return;
-    } else {
-        ch->state = pl330_chan_executing;
-    }
-}
-
-static void pl330_dmasev(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len)
-{
-    uint8_t ev_id;
-
-    if (args[0] & 7) {
-        pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
-        return;
-    }
-    ev_id = (args[0] >> 3) & 0x1f;
-    if (ev_id >= ch->parent->num_events) {
-        pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
-        return;
-    }
-    if (ch->ns && !(ch->parent->cfg[CFG_INS] & (1 << ev_id))) {
-        pl330_fault(ch, PL330_FAULT_EVENT_ERR);
-        return;
-    }
-    if (ch->parent->inten & (1 << ev_id)) {
-        ch->parent->int_status |= (1 << ev_id);
-        DB_PRINT("event interrupt raised %d\n", ev_id);
-        qemu_irq_raise(ch->parent->irq[ev_id]);
-    } else {
-        ch->parent->ev_status |= (1 << ev_id);
-    }
-}
-
-static void pl330_dmast(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len)
-{
-    uint8_t bs = opcode & 3;
-    uint32_t size, num;
-    bool inc;
-
-    if (bs == 2) {
-        pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
-        return;
-    }
-    if ((bs == 1 && ch->request_flag == PL330_BURST) ||
-        (bs == 3 && ch->request_flag == PL330_SINGLE)) {
-        /* Perform NOP */
-        return;
-    }
-    num = ((ch->control >> 18) & 0xf) + 1;
-    size = (uint32_t)1 << ((ch->control >> 15) & 0x7);
-    inc = !!((ch->control >> 14) & 1);
-    ch->stall = pl330_queue_put_insn(&ch->parent->write_queue, ch->dst,
-                                    size, num, inc, 0, ch->tag);
-    if (!ch->stall) {
-        DB_PRINT("channel:%d address:%08x size:%d num:%d %c\n",
-                 ch->tag, ch->dst, size, num, inc ? 'Y' : 'N');
-        ch->dst += inc ? size * num - (ch->dst & (size - 1)) : 0;
-    }
-}
-
-static void pl330_dmastp(PL330Chan *ch, uint8_t opcode,
-                         uint8_t *args, int len)
-{
-    uint8_t periph_id;
-
-    if (args[0] & 7) {
-        pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
-        return;
-    }
-    periph_id = (args[0] >> 3) & 0x1f;
-    if (periph_id >= ch->parent->num_periph_req) {
-        pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
-        return;
-    }
-    if (ch->ns && !(ch->parent->cfg[CFG_PNS] & (1 << periph_id))) {
-        pl330_fault(ch, PL330_FAULT_CH_PERIPH_ERR);
-        return;
-    }
-    pl330_dmast(ch, opcode, args, len);
-}
-
-static void pl330_dmastz(PL330Chan *ch, uint8_t opcode,
-                         uint8_t *args, int len)
-{
-    uint32_t size, num;
-    bool inc;
-
-    num = ((ch->control >> 18) & 0xf) + 1;
-    size = (uint32_t)1 << ((ch->control >> 15) & 0x7);
-    inc = !!((ch->control >> 14) & 1);
-    ch->stall = pl330_queue_put_insn(&ch->parent->write_queue, ch->dst,
-                                    size, num, inc, 1, ch->tag);
-    if (inc) {
-        ch->dst += size * num;
-    }
-}
-
-static void pl330_dmawfe(PL330Chan *ch, uint8_t opcode,
-                         uint8_t *args, int len)
-{
-    uint8_t ev_id;
-    int i;
-
-    if (args[0] & 5) {
-        pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
-        return;
-    }
-    ev_id = (args[0] >> 3) & 0x1f;
-    if (ev_id >= ch->parent->num_events) {
-        pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
-        return;
-    }
-    if (ch->ns && !(ch->parent->cfg[CFG_INS] & (1 << ev_id))) {
-        pl330_fault(ch, PL330_FAULT_EVENT_ERR);
-        return;
-    }
-    ch->wakeup = ev_id;
-    ch->state = pl330_chan_waiting_event;
-    if (~ch->parent->inten & ch->parent->ev_status & 1 << ev_id) {
-        ch->state = pl330_chan_executing;
-        /* If anyone else is currently waiting on the same event, let them
-         * clear the ev_status so they pick up event as well
-         */
-        for (i = 0; i < ch->parent->num_chnls; ++i) {
-            PL330Chan *peer = &ch->parent->chan[i];
-            if (peer->state == pl330_chan_waiting_event &&
-                    peer->wakeup == ev_id) {
-                return;
-            }
-        }
-        ch->parent->ev_status &= ~(1 << ev_id);
-    } else {
-        ch->stall = 1;
-    }
-}
-
-static void pl330_dmawfp(PL330Chan *ch, uint8_t opcode,
-                         uint8_t *args, int len)
-{
-    uint8_t bs = opcode & 3;
-    uint8_t periph_id;
-
-    if (args[0] & 7) {
-        pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
-        return;
-    }
-    periph_id = (args[0] >> 3) & 0x1f;
-    if (periph_id >= ch->parent->num_periph_req) {
-        pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
-        return;
-    }
-    if (ch->ns && !(ch->parent->cfg[CFG_PNS] & (1 << periph_id))) {
-        pl330_fault(ch, PL330_FAULT_CH_PERIPH_ERR);
-        return;
-    }
-    switch (bs) {
-    case 0: /* S */
-        ch->request_flag = PL330_SINGLE;
-        ch->wfp_sbp = 0;
-        break;
-    case 1: /* P */
-        ch->request_flag = PL330_BURST;
-        ch->wfp_sbp = 2;
-        break;
-    case 2: /* B */
-        ch->request_flag = PL330_BURST;
-        ch->wfp_sbp = 1;
-        break;
-    default:
-        pl330_fault(ch, PL330_FAULT_OPERAND_INVALID);
-        return;
-    }
-
-    if (ch->parent->periph_busy[periph_id]) {
-        ch->state = pl330_chan_waiting_periph;
-        ch->stall = 1;
-    } else if (ch->state == pl330_chan_waiting_periph) {
-        ch->state = pl330_chan_executing;
-    }
-}
-
-static void pl330_dmawmb(PL330Chan *ch, uint8_t opcode,
-                         uint8_t *args, int len)
-{
-    if (pl330_queue_find_insn(&ch->parent->write_queue, ch->tag, false)) {
-        ch->state = pl330_chan_at_barrier;
-        ch->stall = 1;
-        return;
-    } else {
-        ch->state = pl330_chan_executing;
-    }
-}
-
-/* NULL terminated array of the instruction descriptions. */
-static const PL330InsnDesc insn_desc[] = {
-    { .opcode = 0x54, .opmask = 0xFD, .size = 3, .exec = pl330_dmaaddh, },
-    { .opcode = 0x00, .opmask = 0xFF, .size = 1, .exec = pl330_dmaend, },
-    { .opcode = 0x35, .opmask = 0xFF, .size = 2, .exec = pl330_dmaflushp, },
-    { .opcode = 0xA0, .opmask = 0xFD, .size = 6, .exec = pl330_dmago, },
-    { .opcode = 0x04, .opmask = 0xFC, .size = 1, .exec = pl330_dmald, },
-    { .opcode = 0x25, .opmask = 0xFD, .size = 2, .exec = pl330_dmaldp, },
-    { .opcode = 0x20, .opmask = 0xFD, .size = 2, .exec = pl330_dmalp, },
-    /* dmastp  must be before dmalpend in this list, because their maps
-     * are overlapping
-     */
-    { .opcode = 0x29, .opmask = 0xFD, .size = 2, .exec = pl330_dmastp, },
-    { .opcode = 0x28, .opmask = 0xE8, .size = 2, .exec = pl330_dmalpend, },
-    { .opcode = 0x01, .opmask = 0xFF, .size = 1, .exec = pl330_dmakill, },
-    { .opcode = 0xBC, .opmask = 0xFF, .size = 6, .exec = pl330_dmamov, },
-    { .opcode = 0x18, .opmask = 0xFF, .size = 1, .exec = pl330_dmanop, },
-    { .opcode = 0x12, .opmask = 0xFF, .size = 1, .exec = pl330_dmarmb, },
-    { .opcode = 0x34, .opmask = 0xFF, .size = 2, .exec = pl330_dmasev, },
-    { .opcode = 0x08, .opmask = 0xFC, .size = 1, .exec = pl330_dmast, },
-    { .opcode = 0x0C, .opmask = 0xFF, .size = 1, .exec = pl330_dmastz, },
-    { .opcode = 0x36, .opmask = 0xFF, .size = 2, .exec = pl330_dmawfe, },
-    { .opcode = 0x30, .opmask = 0xFC, .size = 2, .exec = pl330_dmawfp, },
-    { .opcode = 0x13, .opmask = 0xFF, .size = 1, .exec = pl330_dmawmb, },
-    { .opcode = 0x00, .opmask = 0x00, .size = 0, .exec = NULL, }
-};
-
-/* Instructions which can be issued via debug registers. */
-static const PL330InsnDesc debug_insn_desc[] = {
-    { .opcode = 0xA0, .opmask = 0xFD, .size = 6, .exec = pl330_dmago, },
-    { .opcode = 0x01, .opmask = 0xFF, .size = 1, .exec = pl330_dmakill, },
-    { .opcode = 0x34, .opmask = 0xFF, .size = 2, .exec = pl330_dmasev, },
-    { .opcode = 0x00, .opmask = 0x00, .size = 0, .exec = NULL, }
-};
-
-static inline const PL330InsnDesc *pl330_fetch_insn(PL330Chan *ch)
-{
-    uint8_t opcode;
-    int i;
-
-    dma_memory_read(&dma_context_memory, ch->pc, &opcode, 1);
-    for (i = 0; insn_desc[i].size; i++) {
-        if ((opcode & insn_desc[i].opmask) == insn_desc[i].opcode) {
-            return &insn_desc[i];
-        }
-    }
-    return NULL;
-}
-
-static inline void pl330_exec_insn(PL330Chan *ch, const PL330InsnDesc *insn)
-{
-    uint8_t buf[PL330_INSN_MAXSIZE];
-
-    assert(insn->size <= PL330_INSN_MAXSIZE);
-    dma_memory_read(&dma_context_memory, ch->pc, buf, insn->size);
-    insn->exec(ch, buf[0], &buf[1], insn->size - 1);
-}
-
-static inline void pl330_update_pc(PL330Chan *ch,
-                                   const PL330InsnDesc *insn)
-{
-    ch->pc += insn->size;
-}
-
-/* Try to execute current instruction in channel CH. Number of executed
-   instructions is returned (0 or 1). */
-static int pl330_chan_exec(PL330Chan *ch)
-{
-    const PL330InsnDesc *insn;
-
-    if (ch->state != pl330_chan_executing &&
-            ch->state != pl330_chan_waiting_periph &&
-            ch->state != pl330_chan_at_barrier &&
-            ch->state != pl330_chan_waiting_event) {
-        DB_PRINT("%d\n", ch->state);
-        return 0;
-    }
-    ch->stall = 0;
-    insn = pl330_fetch_insn(ch);
-    if (!insn) {
-        DB_PRINT("pl330 undefined instruction\n");
-        pl330_fault(ch, PL330_FAULT_UNDEF_INSTR);
-        return 0;
-    }
-    pl330_exec_insn(ch, insn);
-    if (!ch->stall) {
-        pl330_update_pc(ch, insn);
-        ch->watchdog_timer = 0;
-        return 1;
-    /* WDT only active in exec state */
-    } else if (ch->state == pl330_chan_executing) {
-        ch->watchdog_timer++;
-        if (ch->watchdog_timer >= PL330_WATCHDOG_LIMIT) {
-            pl330_fault(ch, PL330_FAULT_LOCKUP_ERR);
-        }
-    }
-    return 0;
-}
-
-/* Try to execute 1 instruction in each channel, one instruction from read
-   queue and one instruction from write queue. Number of successfully executed
-   instructions is returned. */
-static int pl330_exec_cycle(PL330Chan *channel)
-{
-    PL330State *s = channel->parent;
-    PL330QueueEntry *q;
-    int i;
-    int num_exec = 0;
-    int fifo_res = 0;
-    uint8_t buf[PL330_MAX_BURST_LEN];
-
-    /* Execute one instruction in each channel */
-    num_exec += pl330_chan_exec(channel);
-
-    /* Execute one instruction from read queue */
-    q = pl330_queue_find_insn(&s->read_queue, PL330_UNTAGGED, true);
-    if (q != NULL && q->len <= pl330_fifo_num_free(&s->fifo)) {
-        int len = q->len - (q->addr & (q->len - 1));
-
-        dma_memory_read(&dma_context_memory, q->addr, buf, len);
-        if (PL330_ERR_DEBUG > 1) {
-            DB_PRINT("PL330 read from memory @%08x (size = %08x):\n",
-                      q->addr, len);
-            hexdump((char *)buf, stderr, "", len);
-        }
-        fifo_res = pl330_fifo_push(&s->fifo, buf, len, q->tag);
-        if (fifo_res == PL330_FIFO_OK) {
-            if (q->inc) {
-                q->addr += len;
-            }
-            q->n--;
-            if (!q->n) {
-                pl330_queue_remove_insn(&s->read_queue, q);
-            }
-            num_exec++;
-        }
-    }
-
-    /* Execute one instruction from write queue. */
-    q = pl330_queue_find_insn(&s->write_queue, pl330_fifo_tag(&s->fifo), true);
-    if (q != NULL) {
-        int len = q->len - (q->addr & (q->len - 1));
-
-        if (q->z) {
-            for (i = 0; i < len; i++) {
-                buf[i] = 0;
-            }
-        } else {
-            fifo_res = pl330_fifo_get(&s->fifo, buf, len, q->tag);
-        }
-        if (fifo_res == PL330_FIFO_OK || q->z) {
-            dma_memory_write(&dma_context_memory, q->addr, buf, len);
-            if (PL330_ERR_DEBUG > 1) {
-                DB_PRINT("PL330 read from memory @%08x (size = %08x):\n",
-                         q->addr, len);
-                hexdump((char *)buf, stderr, "", len);
-            }
-            if (q->inc) {
-                q->addr += len;
-            }
-            num_exec++;
-        } else if (fifo_res == PL330_FIFO_STALL) {
-            pl330_fault(&channel->parent->chan[q->tag],
-                                PL330_FAULT_FIFOEMPTY_ERR);
-        }
-        q->n--;
-        if (!q->n) {
-            pl330_queue_remove_insn(&s->write_queue, q);
-        }
-    }
-
-    return num_exec;
-}
-
-static int pl330_exec_channel(PL330Chan *channel)
-{
-    int insr_exec = 0;
-
-    /* TODO: Is it all right to execute everything or should we do per-cycle
-       simulation? */
-    while (pl330_exec_cycle(channel)) {
-        insr_exec++;
-    }
-
-    /* Detect deadlock */
-    if (channel->state == pl330_chan_executing) {
-        pl330_fault(channel, PL330_FAULT_LOCKUP_ERR);
-    }
-    /* Situation when one of the queues has deadlocked but all channels
-     * have finished their programs should be impossible.
-     */
-
-    return insr_exec;
-}
-
-static inline void pl330_exec(PL330State *s)
-{
-    DB_PRINT("\n");
-    int i, insr_exec;
-    do {
-        insr_exec = pl330_exec_channel(&s->manager);
-
-        for (i = 0; i < s->num_chnls; i++) {
-            insr_exec += pl330_exec_channel(&s->chan[i]);
-        }
-    } while (insr_exec);
-}
-
-static void pl330_exec_cycle_timer(void *opaque)
-{
-    PL330State *s = (PL330State *)opaque;
-    pl330_exec(s);
-}
-
-/* Stop or restore dma operations */
-
-static void pl330_dma_stop_irq(void *opaque, int irq, int level)
-{
-    PL330State *s = (PL330State *)opaque;
-
-    if (s->periph_busy[irq] != level) {
-        s->periph_busy[irq] = level;
-        qemu_mod_timer(s->timer, qemu_get_clock_ns(vm_clock));
-    }
-}
-
-static void pl330_debug_exec(PL330State *s)
-{
-    uint8_t args[5];
-    uint8_t opcode;
-    uint8_t chan_id;
-    int i;
-    PL330Chan *ch;
-    const PL330InsnDesc *insn;
-
-    s->debug_status = 1;
-    chan_id = (s->dbg[0] >>  8) & 0x07;
-    opcode  = (s->dbg[0] >> 16) & 0xff;
-    args[0] = (s->dbg[0] >> 24) & 0xff;
-    args[1] = (s->dbg[1] >>  0) & 0xff;
-    args[2] = (s->dbg[1] >>  8) & 0xff;
-    args[3] = (s->dbg[1] >> 16) & 0xff;
-    args[4] = (s->dbg[1] >> 24) & 0xff;
-    DB_PRINT("chan id: %d\n", chan_id);
-    if (s->dbg[0] & 1) {
-        ch = &s->chan[chan_id];
-    } else {
-        ch = &s->manager;
-    }
-    insn = NULL;
-    for (i = 0; debug_insn_desc[i].size; i++) {
-        if ((opcode & debug_insn_desc[i].opmask) == debug_insn_desc[i].opcode) {
-            insn = &debug_insn_desc[i];
-        }
-    }
-    if (!insn) {
-        pl330_fault(ch, PL330_FAULT_UNDEF_INSTR | PL330_FAULT_DBG_INSTR);
-        return ;
-    }
-    ch->stall = 0;
-    insn->exec(ch, opcode, args, insn->size - 1);
-    if (ch->fault_type) {
-        ch->fault_type |= PL330_FAULT_DBG_INSTR;
-    }
-    if (ch->stall) {
-        qemu_log_mask(LOG_UNIMP, "pl330: stall of debug instruction not "
-                      "implemented\n");
-    }
-    s->debug_status = 0;
-}
-
-/* IOMEM mapped registers */
-
-static void pl330_iomem_write(void *opaque, hwaddr offset,
-                              uint64_t value, unsigned size)
-{
-    PL330State *s = (PL330State *) opaque;
-    uint32_t i;
-
-    DB_PRINT("addr: %08x data: %08x\n", (unsigned)offset, (unsigned)value);
-
-    switch (offset) {
-    case PL330_REG_INTEN:
-        s->inten = value;
-        break;
-    case PL330_REG_INTCLR:
-        for (i = 0; i < s->num_events; i++) {
-            if (s->int_status & s->inten & value & (1 << i)) {
-                DB_PRINT("event interrupt lowered %d\n", i);
-                qemu_irq_lower(s->irq[i]);
-            }
-        }
-        s->ev_status &= ~(value & s->inten);
-        s->int_status &= ~(value & s->inten);
-        break;
-    case PL330_REG_DBGCMD:
-        if ((value & 3) == 0) {
-            pl330_debug_exec(s);
-            pl330_exec(s);
-        } else {
-            qemu_log_mask(LOG_GUEST_ERROR, "pl330: write of illegal value %u "
-                          "for offset " TARGET_FMT_plx "\n", (unsigned)value,
-                          offset);
-        }
-        break;
-    case PL330_REG_DBGINST0:
-        DB_PRINT("s->dbg[0] = %08x\n", (unsigned)value);
-        s->dbg[0] = value;
-        break;
-    case PL330_REG_DBGINST1:
-        DB_PRINT("s->dbg[1] = %08x\n", (unsigned)value);
-        s->dbg[1] = value;
-        break;
-    default:
-        qemu_log_mask(LOG_GUEST_ERROR, "pl330: bad write offset " TARGET_FMT_plx
-                      "\n", offset);
-        break;
-    }
-}
-
-static inline uint32_t pl330_iomem_read_imp(void *opaque,
-        hwaddr offset)
-{
-    PL330State *s = (PL330State *)opaque;
-    int chan_id;
-    int i;
-    uint32_t res;
-
-    if (offset >= PL330_REG_PERIPH_ID && offset < PL330_REG_PERIPH_ID + 32) {
-        return pl330_id[(offset - PL330_REG_PERIPH_ID) >> 2];
-    }
-    if (offset >= PL330_REG_CR0_BASE && offset < PL330_REG_CR0_BASE + 24) {
-        return s->cfg[(offset - PL330_REG_CR0_BASE) >> 2];
-    }
-    if (offset >= PL330_REG_CHANCTRL && offset < PL330_REG_DBGSTATUS) {
-        offset -= PL330_REG_CHANCTRL;
-        chan_id = offset >> 5;
-        if (chan_id >= s->num_chnls) {
-            qemu_log_mask(LOG_GUEST_ERROR, "pl330: bad read offset "
-                          TARGET_FMT_plx "\n", offset);
-            return 0;
-        }
-        switch (offset & 0x1f) {
-        case 0x00:
-            return s->chan[chan_id].src;
-        case 0x04:
-            return s->chan[chan_id].dst;
-        case 0x08:
-            return s->chan[chan_id].control;
-        case 0x0C:
-            return s->chan[chan_id].lc[0];
-        case 0x10:
-            return s->chan[chan_id].lc[1];
-        default:
-            qemu_log_mask(LOG_GUEST_ERROR, "pl330: bad read offset "
-                          TARGET_FMT_plx "\n", offset);
-            return 0;
-        }
-    }
-    if (offset >= PL330_REG_CSR_BASE && offset < 0x400) {
-        offset -= PL330_REG_CSR_BASE;
-        chan_id = offset >> 3;
-        if (chan_id >= s->num_chnls) {
-            qemu_log_mask(LOG_GUEST_ERROR, "pl330: bad read offset "
-                          TARGET_FMT_plx "\n", offset);
-            return 0;
-        }
-        switch ((offset >> 2) & 1) {
-        case 0x0:
-            res = (s->chan[chan_id].ns << 21) |
-                    (s->chan[chan_id].wakeup << 4) |
-                    (s->chan[chan_id].state) |
-                    (s->chan[chan_id].wfp_sbp << 14);
-            return res;
-        case 0x1:
-            return s->chan[chan_id].pc;
-        default:
-            qemu_log_mask(LOG_GUEST_ERROR, "pl330: read error\n");
-            return 0;
-        }
-    }
-    if (offset >= PL330_REG_FTR_BASE && offset < 0x100) {
-        offset -= PL330_REG_FTR_BASE;
-        chan_id = offset >> 2;
-        if (chan_id >= s->num_chnls) {
-            qemu_log_mask(LOG_GUEST_ERROR, "pl330: bad read offset "
-                          TARGET_FMT_plx "\n", offset);
-            return 0;
-        }
-        return s->chan[chan_id].fault_type;
-    }
-    switch (offset) {
-    case PL330_REG_DSR:
-        return (s->manager.ns << 9) | (s->manager.wakeup << 4) |
-            (s->manager.state & 0xf);
-    case PL330_REG_DPC:
-        return s->manager.pc;
-    case PL330_REG_INTEN:
-        return s->inten;
-    case PL330_REG_INT_EVENT_RIS:
-        return s->ev_status;
-    case PL330_REG_INTMIS:
-        return s->int_status;
-    case PL330_REG_INTCLR:
-        /* Documentation says that we can't read this register
-         * but linux kernel does it
-         */
-        return 0;
-    case PL330_REG_FSRD:
-        return s->manager.state ? 1 : 0;
-    case PL330_REG_FSRC:
-        res = 0;
-        for (i = 0; i < s->num_chnls; i++) {
-            if (s->chan[i].state == pl330_chan_fault ||
-                s->chan[i].state == pl330_chan_fault_completing) {
-                res |= 1 << i;
-            }
-        }
-        return res;
-    case PL330_REG_FTRD:
-        return s->manager.fault_type;
-    case PL330_REG_DBGSTATUS:
-        return s->debug_status;
-    default:
-        qemu_log_mask(LOG_GUEST_ERROR, "pl330: bad read offset "
-                      TARGET_FMT_plx "\n", offset);
-    }
-    return 0;
-}
-
-static uint64_t pl330_iomem_read(void *opaque, hwaddr offset,
-        unsigned size)
-{
-    int ret = pl330_iomem_read_imp(opaque, offset);
-    DB_PRINT("addr: %08x data: %08x\n", (unsigned)offset, ret);
-    return ret;
-}
-
-static const MemoryRegionOps pl330_ops = {
-    .read = pl330_iomem_read,
-    .write = pl330_iomem_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .impl = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    }
-};
-
-/* Controller logic and initialization */
-
-static void pl330_chan_reset(PL330Chan *ch)
-{
-    ch->src = 0;
-    ch->dst = 0;
-    ch->pc = 0;
-    ch->state = pl330_chan_stopped;
-    ch->watchdog_timer = 0;
-    ch->stall = 0;
-    ch->control = 0;
-    ch->status = 0;
-    ch->fault_type = 0;
-}
-
-static void pl330_reset(DeviceState *d)
-{
-    int i;
-    PL330State *s = PL330(d);
-
-    s->inten = 0;
-    s->int_status = 0;
-    s->ev_status = 0;
-    s->debug_status = 0;
-    s->num_faulting = 0;
-    s->manager.ns = s->mgr_ns_at_rst;
-    pl330_fifo_reset(&s->fifo);
-    pl330_queue_reset(&s->read_queue);
-    pl330_queue_reset(&s->write_queue);
-
-    for (i = 0; i < s->num_chnls; i++) {
-        pl330_chan_reset(&s->chan[i]);
-    }
-    for (i = 0; i < s->num_periph_req; i++) {
-        s->periph_busy[i] = 0;
-    }
-
-    qemu_del_timer(s->timer);
-}
-
-static void pl330_realize(DeviceState *dev, Error **errp)
-{
-    int i;
-    PL330State *s = PL330(dev);
-
-    sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq_abort);
-    memory_region_init_io(&s->iomem, &pl330_ops, s, "dma", PL330_IOMEM_SIZE);
-    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
-
-    s->timer = qemu_new_timer_ns(vm_clock, pl330_exec_cycle_timer, s);
-
-    s->cfg[0] = (s->mgr_ns_at_rst ? 0x4 : 0) |
-                (s->num_periph_req > 0 ? 1 : 0) |
-                ((s->num_chnls - 1) & 0x7) << 4 |
-                ((s->num_periph_req - 1) & 0x1f) << 12 |
-                ((s->num_events - 1) & 0x1f) << 17;
-
-    switch (s->i_cache_len) {
-    case (4):
-        s->cfg[1] |= 2;
-        break;
-    case (8):
-        s->cfg[1] |= 3;
-        break;
-    case (16):
-        s->cfg[1] |= 4;
-        break;
-    case (32):
-        s->cfg[1] |= 5;
-        break;
-    default:
-        error_setg(errp, "Bad value for i-cache_len property: %d\n",
-                   s->i_cache_len);
-        return;
-    }
-    s->cfg[1] |= ((s->num_i_cache_lines - 1) & 0xf) << 4;
-
-    s->chan = g_new0(PL330Chan, s->num_chnls);
-    s->hi_seqn = g_new0(uint8_t, s->num_chnls);
-    s->lo_seqn = g_new0(uint8_t, s->num_chnls);
-    for (i = 0; i < s->num_chnls; i++) {
-        s->chan[i].parent = s;
-        s->chan[i].tag = (uint8_t)i;
-    }
-    s->manager.parent = s;
-    s->manager.tag = s->num_chnls;
-    s->manager.is_manager = true;
-
-    s->irq = g_new0(qemu_irq, s->num_events);
-    for (i = 0; i < s->num_events; i++) {
-        sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq[i]);
-    }
-
-    qdev_init_gpio_in(dev, pl330_dma_stop_irq, PL330_PERIPH_NUM);
-
-    switch (s->data_width) {
-    case (32):
-        s->cfg[CFG_CRD] |= 0x2;
-        break;
-    case (64):
-        s->cfg[CFG_CRD] |= 0x3;
-        break;
-    case (128):
-        s->cfg[CFG_CRD] |= 0x4;
-        break;
-    default:
-        error_setg(errp, "Bad value for data_width property: %d\n",
-                   s->data_width);
-        return;
-    }
-
-    s->cfg[CFG_CRD] |= ((s->wr_cap - 1) & 0x7) << 4 |
-                    ((s->wr_q_dep - 1) & 0xf) << 8 |
-                    ((s->rd_cap - 1) & 0x7) << 12 |
-                    ((s->rd_q_dep - 1) & 0xf) << 16 |
-                    ((s->data_buffer_dep - 1) & 0x1ff) << 20;
-
-    pl330_queue_init(&s->read_queue, s->rd_q_dep, s);
-    pl330_queue_init(&s->write_queue, s->wr_q_dep, s);
-    pl330_fifo_init(&s->fifo, s->data_buffer_dep);
-}
-
-static Property pl330_properties[] = {
-    /* CR0 */
-    DEFINE_PROP_UINT32("num_chnls", PL330State, num_chnls, 8),
-    DEFINE_PROP_UINT8("num_periph_req", PL330State, num_periph_req, 4),
-    DEFINE_PROP_UINT8("num_events", PL330State, num_events, 16),
-    DEFINE_PROP_UINT8("mgr_ns_at_rst", PL330State, mgr_ns_at_rst, 0),
-    /* CR1 */
-    DEFINE_PROP_UINT8("i-cache_len", PL330State, i_cache_len, 4),
-    DEFINE_PROP_UINT8("num_i-cache_lines", PL330State, num_i_cache_lines, 8),
-    /* CR2-4 */
-    DEFINE_PROP_UINT32("boot_addr", PL330State, cfg[CFG_BOOT_ADDR], 0),
-    DEFINE_PROP_UINT32("INS", PL330State, cfg[CFG_INS], 0),
-    DEFINE_PROP_UINT32("PNS", PL330State, cfg[CFG_PNS], 0),
-    /* CRD */
-    DEFINE_PROP_UINT8("data_width", PL330State, data_width, 64),
-    DEFINE_PROP_UINT8("wr_cap", PL330State, wr_cap, 8),
-    DEFINE_PROP_UINT8("wr_q_dep", PL330State, wr_q_dep, 16),
-    DEFINE_PROP_UINT8("rd_cap", PL330State, rd_cap, 8),
-    DEFINE_PROP_UINT8("rd_q_dep", PL330State, rd_q_dep, 16),
-    DEFINE_PROP_UINT16("data_buffer_dep", PL330State, data_buffer_dep, 256),
-
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void pl330_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-
-    dc->realize = pl330_realize;
-    dc->reset = pl330_reset;
-    dc->props = pl330_properties;
-    dc->vmsd = &vmstate_pl330;
-}
-
-static const TypeInfo pl330_type_info = {
-    .name           = TYPE_PL330,
-    .parent         = TYPE_SYS_BUS_DEVICE,
-    .instance_size  = sizeof(PL330State),
-    .class_init      = pl330_class_init,
-};
-
-static void pl330_register_types(void)
-{
-    type_register_static(&pl330_type_info);
-}
-
-type_init(pl330_register_types)
diff --git a/hw/pm_smbus.c b/hw/pm_smbus.c
deleted file mode 100644 (file)
index 7900610..0000000
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * PC SMBus implementation
- * splitted from acpi.c
- *
- * Copyright (c) 2006 Fabrice Bellard
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License version 2 as published by the Free Software Foundation.
- *
- * 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/hw.h"
-#include "hw/pc.h"
-#include "hw/pm_smbus.h"
-#include "hw/smbus.h"
-
-/* no save/load? */
-
-#define SMBHSTSTS       0x00
-#define SMBHSTCNT       0x02
-#define SMBHSTCMD       0x03
-#define SMBHSTADD       0x04
-#define SMBHSTDAT0      0x05
-#define SMBHSTDAT1      0x06
-#define SMBBLKDAT       0x07
-
-//#define DEBUG
-
-#ifdef DEBUG
-# define SMBUS_DPRINTF(format, ...)     printf(format, ## __VA_ARGS__)
-#else
-# define SMBUS_DPRINTF(format, ...)     do { } while (0)
-#endif
-
-
-static void smb_transaction(PMSMBus *s)
-{
-    uint8_t prot = (s->smb_ctl >> 2) & 0x07;
-    uint8_t read = s->smb_addr & 0x01;
-    uint8_t cmd = s->smb_cmd;
-    uint8_t addr = s->smb_addr >> 1;
-    i2c_bus *bus = s->smbus;
-
-    SMBUS_DPRINTF("SMBus trans addr=0x%02x prot=0x%02x\n", addr, prot);
-    switch(prot) {
-    case 0x0:
-        smbus_quick_command(bus, addr, read);
-        break;
-    case 0x1:
-        if (read) {
-            s->smb_data0 = smbus_receive_byte(bus, addr);
-        } else {
-            smbus_send_byte(bus, addr, cmd);
-        }
-        break;
-    case 0x2:
-        if (read) {
-            s->smb_data0 = smbus_read_byte(bus, addr, cmd);
-        } else {
-            smbus_write_byte(bus, addr, cmd, s->smb_data0);
-        }
-        break;
-    case 0x3:
-        if (read) {
-            uint16_t val;
-            val = smbus_read_word(bus, addr, cmd);
-            s->smb_data0 = val;
-            s->smb_data1 = val >> 8;
-        } else {
-            smbus_write_word(bus, addr, cmd, (s->smb_data1 << 8) | s->smb_data0);
-        }
-        break;
-    case 0x5:
-        if (read) {
-            s->smb_data0 = smbus_read_block(bus, addr, cmd, s->smb_data);
-        } else {
-            smbus_write_block(bus, addr, cmd, s->smb_data, s->smb_data0);
-        }
-        break;
-    default:
-        goto error;
-    }
-    return;
-
-  error:
-    s->smb_stat |= 0x04;
-}
-
-static void smb_ioport_writeb(void *opaque, hwaddr addr, uint64_t val,
-                              unsigned width)
-{
-    PMSMBus *s = opaque;
-
-    SMBUS_DPRINTF("SMB writeb port=0x%04x val=0x%02x\n", addr, val);
-    switch(addr) {
-    case SMBHSTSTS:
-        s->smb_stat = 0;
-        s->smb_index = 0;
-        break;
-    case SMBHSTCNT:
-        s->smb_ctl = val;
-        if (val & 0x40)
-            smb_transaction(s);
-        break;
-    case SMBHSTCMD:
-        s->smb_cmd = val;
-        break;
-    case SMBHSTADD:
-        s->smb_addr = val;
-        break;
-    case SMBHSTDAT0:
-        s->smb_data0 = val;
-        break;
-    case SMBHSTDAT1:
-        s->smb_data1 = val;
-        break;
-    case SMBBLKDAT:
-        s->smb_data[s->smb_index++] = val;
-        if (s->smb_index > 31)
-            s->smb_index = 0;
-        break;
-    default:
-        break;
-    }
-}
-
-static uint64_t smb_ioport_readb(void *opaque, hwaddr addr, unsigned width)
-{
-    PMSMBus *s = opaque;
-    uint32_t val;
-
-    switch(addr) {
-    case SMBHSTSTS:
-        val = s->smb_stat;
-        break;
-    case SMBHSTCNT:
-        s->smb_index = 0;
-        val = s->smb_ctl & 0x1f;
-        break;
-    case SMBHSTCMD:
-        val = s->smb_cmd;
-        break;
-    case SMBHSTADD:
-        val = s->smb_addr;
-        break;
-    case SMBHSTDAT0:
-        val = s->smb_data0;
-        break;
-    case SMBHSTDAT1:
-        val = s->smb_data1;
-        break;
-    case SMBBLKDAT:
-        val = s->smb_data[s->smb_index++];
-        if (s->smb_index > 31)
-            s->smb_index = 0;
-        break;
-    default:
-        val = 0;
-        break;
-    }
-    SMBUS_DPRINTF("SMB readb port=0x%04x val=0x%02x\n", addr, val);
-    return val;
-}
-
-static const MemoryRegionOps pm_smbus_ops = {
-    .read = smb_ioport_readb,
-    .write = smb_ioport_writeb,
-    .valid.min_access_size = 1,
-    .valid.max_access_size = 1,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-void pm_smbus_init(DeviceState *parent, PMSMBus *smb)
-{
-    smb->smbus = i2c_init_bus(parent, "i2c");
-    memory_region_init_io(&smb->io, &pm_smbus_ops, smb, "pm-smbus", 64);
-}
diff --git a/hw/pm_smbus.h b/hw/pm_smbus.h
deleted file mode 100644 (file)
index e3069bf..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-#ifndef PM_SMBUS_H
-#define PM_SMBUS_H
-
-typedef struct PMSMBus {
-    i2c_bus *smbus;
-    MemoryRegion io;
-
-    uint8_t smb_stat;
-    uint8_t smb_ctl;
-    uint8_t smb_cmd;
-    uint8_t smb_addr;
-    uint8_t smb_data0;
-    uint8_t smb_data1;
-    uint8_t smb_data[32];
-    uint8_t smb_index;
-} PMSMBus;
-
-void pm_smbus_init(DeviceState *parent, PMSMBus *smb);
-
-#endif /* !PM_SMBUS_H */
diff --git a/hw/ppc-viosrp.h b/hw/ppc-viosrp.h
deleted file mode 100644 (file)
index d8e365d..0000000
+++ /dev/null
@@ -1,216 +0,0 @@
-/*****************************************************************************/
-/* srp.h -- SCSI RDMA Protocol definitions                                   */
-/*                                                                           */
-/* Written By: Colin Devilbis, IBM Corporation                               */
-/*                                                                           */
-/* Copyright (C) 2003 IBM Corporation                                        */
-/*                                                                           */
-/* 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, write to the Free Software               */
-/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
-/*                                                                           */
-/*                                                                           */
-/* This file contains structures and definitions for IBM RPA (RS/6000        */
-/* platform architecture) implementation of the SRP (SCSI RDMA Protocol)     */
-/* standard.  SRP is used on IBM iSeries and pSeries platforms to send SCSI  */
-/* commands between logical partitions.                                      */
-/*                                                                           */
-/* SRP Information Units (IUs) are sent on a "Command/Response Queue" (CRQ)  */
-/* between partitions.  The definitions in this file are architected,        */
-/* and cannot be changed without breaking compatibility with other versions  */
-/* of Linux and other operating systems (AIX, OS/400) that talk this protocol*/
-/* between logical partitions                                                */
-/*****************************************************************************/
-#ifndef PPC_VIOSRP_H
-#define PPC_VIOSRP_H
-
-#define SRP_VERSION "16.a"
-#define SRP_MAX_IU_LEN    256
-#define SRP_MAX_LOC_LEN 32
-
-union srp_iu {
-    struct srp_login_req login_req;
-    struct srp_login_rsp login_rsp;
-    struct srp_login_rej login_rej;
-    struct srp_i_logout i_logout;
-    struct srp_t_logout t_logout;
-    struct srp_tsk_mgmt tsk_mgmt;
-    struct srp_cmd cmd;
-    struct srp_rsp rsp;
-    uint8_t reserved[SRP_MAX_IU_LEN];
-};
-
-enum viosrp_crq_formats {
-    VIOSRP_SRP_FORMAT = 0x01,
-    VIOSRP_MAD_FORMAT = 0x02,
-    VIOSRP_OS400_FORMAT = 0x03,
-    VIOSRP_AIX_FORMAT = 0x04,
-    VIOSRP_LINUX_FORMAT = 0x06,
-    VIOSRP_INLINE_FORMAT = 0x07
-};
-
-enum viosrp_crq_status {
-    VIOSRP_OK = 0x0,
-    VIOSRP_NONRECOVERABLE_ERR = 0x1,
-    VIOSRP_VIOLATES_MAX_XFER = 0x2,
-    VIOSRP_PARTNER_PANIC = 0x3,
-    VIOSRP_DEVICE_BUSY = 0x8,
-    VIOSRP_ADAPTER_FAIL = 0x10,
-    VIOSRP_OK2 = 0x99,
-};
-
-struct viosrp_crq {
-    uint8_t valid;        /* used by RPA */
-    uint8_t format;        /* SCSI vs out-of-band */
-    uint8_t reserved;
-    uint8_t status;        /* non-scsi failure? (e.g. DMA failure) */
-    uint16_t timeout;        /* in seconds */
-    uint16_t IU_length;        /* in bytes */
-    uint64_t IU_data_ptr;    /* the TCE for transferring data */
-};
-
-/* MADs are Management requests above and beyond the IUs defined in the SRP
- * standard.
- */
-enum viosrp_mad_types {
-    VIOSRP_EMPTY_IU_TYPE = 0x01,
-    VIOSRP_ERROR_LOG_TYPE = 0x02,
-    VIOSRP_ADAPTER_INFO_TYPE = 0x03,
-    VIOSRP_HOST_CONFIG_TYPE = 0x04,
-    VIOSRP_CAPABILITIES_TYPE = 0x05,
-    VIOSRP_ENABLE_FAST_FAIL = 0x08,
-};
-
-enum viosrp_mad_status {
-    VIOSRP_MAD_SUCCESS = 0x00,
-    VIOSRP_MAD_NOT_SUPPORTED = 0xF1,
-    VIOSRP_MAD_FAILED = 0xF7,
-};
-
-enum viosrp_capability_type {
-    MIGRATION_CAPABILITIES = 0x01,
-    RESERVATION_CAPABILITIES = 0x02,
-};
-
-enum viosrp_capability_support {
-    SERVER_DOES_NOT_SUPPORTS_CAP = 0x0,
-    SERVER_SUPPORTS_CAP = 0x01,
-    SERVER_CAP_DATA = 0x02,
-};
-
-enum viosrp_reserve_type {
-    CLIENT_RESERVE_SCSI_2 = 0x01,
-};
-
-enum viosrp_capability_flag {
-    CLIENT_MIGRATED = 0x01,
-    CLIENT_RECONNECT = 0x02,
-    CAP_LIST_SUPPORTED = 0x04,
-    CAP_LIST_DATA = 0x08,
-};
-
-/*
- * Common MAD header
- */
-struct mad_common {
-    uint32_t type;
-    uint16_t status;
-    uint16_t length;
-    uint64_t tag;
-};
-
-/*
- * All SRP (and MAD) requests normally flow from the
- * client to the server.  There is no way for the server to send
- * an asynchronous message back to the client.  The Empty IU is used
- * to hang out a meaningless request to the server so that it can respond
- * asynchrouously with something like a SCSI AER
- */
-struct viosrp_empty_iu {
-    struct mad_common common;
-    uint64_t buffer;
-    uint32_t port;
-};
-
-struct viosrp_error_log {
-    struct mad_common common;
-    uint64_t buffer;
-};
-
-struct viosrp_adapter_info {
-    struct mad_common common;
-    uint64_t buffer;
-};
-
-struct viosrp_host_config {
-    struct mad_common common;
-    uint64_t buffer;
-};
-
-struct viosrp_fast_fail {
-    struct mad_common common;
-};
-
-struct viosrp_capabilities {
-    struct mad_common common;
-    uint64_t buffer;
-};
-
-struct mad_capability_common {
-    uint32_t cap_type;
-    uint16_t length;
-    uint16_t server_support;
-};
-
-struct mad_reserve_cap {
-    struct mad_capability_common common;
-    uint32_t type;
-};
-
-struct mad_migration_cap {
-    struct mad_capability_common common;
-    uint32_t ecl;
-};
-
-struct capabilities {
-    uint32_t flags;
-    char name[SRP_MAX_LOC_LEN];
-    char loc[SRP_MAX_LOC_LEN];
-    struct mad_migration_cap migration;
-    struct mad_reserve_cap reserve;
-};
-
-union mad_iu {
-    struct viosrp_empty_iu empty_iu;
-    struct viosrp_error_log error_log;
-    struct viosrp_adapter_info adapter_info;
-    struct viosrp_host_config host_config;
-    struct viosrp_fast_fail fast_fail;
-    struct viosrp_capabilities capabilities;
-};
-
-union viosrp_iu {
-    union srp_iu srp;
-    union mad_iu mad;
-};
-
-struct mad_adapter_info_data {
-    char srp_version[8];
-    char partition_name[96];
-    uint32_t partition_number;
-    uint32_t mad_version;
-    uint32_t os_type;
-    uint32_t port_max_txu[8];    /* per-port maximum transfer */
-};
-
-#endif
diff --git a/hw/ppc.h b/hw/ppc.h
deleted file mode 100644 (file)
index acaf0d6..0000000
--- a/hw/ppc.h
+++ /dev/null
@@ -1,99 +0,0 @@
-#ifndef HW_PPC_H
-#define HW_PPC_H 1
-
-void ppc_set_irq(PowerPCCPU *cpu, int n_IRQ, int level);
-
-/* PowerPC hardware exceptions management helpers */
-typedef void (*clk_setup_cb)(void *opaque, uint32_t freq);
-typedef struct clk_setup_t clk_setup_t;
-struct clk_setup_t {
-    clk_setup_cb cb;
-    void *opaque;
-};
-static inline void clk_setup (clk_setup_t *clk, uint32_t freq)
-{
-    if (clk->cb != NULL)
-        (*clk->cb)(clk->opaque, freq);
-}
-
-struct ppc_tb_t {
-    /* Time base management */
-    int64_t  tb_offset;    /* Compensation                    */
-    int64_t  atb_offset;   /* Compensation                    */
-    uint32_t tb_freq;      /* TB frequency                    */
-    /* Decrementer management */
-    uint64_t decr_next;    /* Tick for next decr interrupt    */
-    uint32_t decr_freq;    /* decrementer frequency           */
-    struct QEMUTimer *decr_timer;
-    /* Hypervisor decrementer management */
-    uint64_t hdecr_next;    /* Tick for next hdecr interrupt  */
-    struct QEMUTimer *hdecr_timer;
-    uint64_t purr_load;
-    uint64_t purr_start;
-    void *opaque;
-    uint32_t flags;
-};
-
-/* PPC Timers flags */
-#define PPC_TIMER_BOOKE              (1 << 0) /* Enable Booke support */
-#define PPC_TIMER_E500               (1 << 1) /* Enable e500 support */
-#define PPC_DECR_UNDERFLOW_TRIGGERED (1 << 2) /* Decr interrupt triggered when
-                                               * the most significant bit
-                                               * changes from 0 to 1.
-                                               */
-#define PPC_DECR_ZERO_TRIGGERED      (1 << 3) /* Decr interrupt triggered when
-                                               * the decrementer reaches zero.
-                                               */
-
-uint64_t cpu_ppc_get_tb(ppc_tb_t *tb_env, uint64_t vmclk, int64_t tb_offset);
-clk_setup_cb cpu_ppc_tb_init (CPUPPCState *env, uint32_t freq);
-/* Embedded PowerPC DCR management */
-typedef uint32_t (*dcr_read_cb)(void *opaque, int dcrn);
-typedef void (*dcr_write_cb)(void *opaque, int dcrn, uint32_t val);
-int ppc_dcr_init (CPUPPCState *env, int (*dcr_read_error)(int dcrn),
-                  int (*dcr_write_error)(int dcrn));
-int ppc_dcr_register (CPUPPCState *env, int dcrn, void *opaque,
-                      dcr_read_cb drc_read, dcr_write_cb dcr_write);
-clk_setup_cb ppc_40x_timers_init (CPUPPCState *env, uint32_t freq,
-                                  unsigned int decr_excp);
-
-/* Embedded PowerPC reset */
-void ppc40x_core_reset(PowerPCCPU *cpu);
-void ppc40x_chip_reset(PowerPCCPU *cpu);
-void ppc40x_system_reset(PowerPCCPU *cpu);
-void PREP_debug_write (void *opaque, uint32_t addr, uint32_t val);
-
-extern CPUWriteMemoryFunc * const PPC_io_write[];
-extern CPUReadMemoryFunc * const PPC_io_read[];
-void PPC_debug_write (void *opaque, uint32_t addr, uint32_t val);
-
-void ppc40x_irq_init (CPUPPCState *env);
-void ppce500_irq_init (CPUPPCState *env);
-void ppc6xx_irq_init (CPUPPCState *env);
-void ppc970_irq_init (CPUPPCState *env);
-void ppcPOWER7_irq_init (CPUPPCState *env);
-
-void ppce500_set_mpic_proxy(bool enabled);
-
-/* PPC machines for OpenBIOS */
-enum {
-    ARCH_PREP = 0,
-    ARCH_MAC99,
-    ARCH_HEATHROW,
-    ARCH_MAC99_U3,
-};
-
-#define FW_CFG_PPC_WIDTH       (FW_CFG_ARCH_LOCAL + 0x00)
-#define FW_CFG_PPC_HEIGHT      (FW_CFG_ARCH_LOCAL + 0x01)
-#define FW_CFG_PPC_DEPTH       (FW_CFG_ARCH_LOCAL + 0x02)
-#define FW_CFG_PPC_TBFREQ      (FW_CFG_ARCH_LOCAL + 0x03)
-#define FW_CFG_PPC_IS_KVM       (FW_CFG_ARCH_LOCAL + 0x05)
-#define FW_CFG_PPC_KVM_HC       (FW_CFG_ARCH_LOCAL + 0x06)
-#define FW_CFG_PPC_KVM_PID      (FW_CFG_ARCH_LOCAL + 0x07)
-
-#define PPC_SERIAL_MM_BAUDBASE 399193
-
-/* ppc_booke.c */
-void ppc_booke_timers_init(PowerPCCPU *cpu, uint32_t freq, uint32_t flags);
-
-#endif
index 4de02098e2a85618c32109c3042b86c3263ab6d7..be00d1da3bb2d7763486db955635ce1dc358f259 100644 (file)
@@ -1,26 +1,12 @@
-# PREP target
-obj-y += mc146818rtc.o
-# IBM pSeries (sPAPR)
-obj-$(CONFIG_PSERIES) += spapr_vty.o spapr_llan.o spapr_vscsi.o
-obj-$(CONFIG_PSERIES) += spapr_pci.o pci/pci-hotplug.o
-obj-$(CONFIG_PSERIES) += spapr_nvram.o
-# PowerPC 4xx boards
-obj-y += ppc4xx_pci.o
-# PowerPC OpenPIC
-obj-y += openpic.o
-
-# Xilinx PPC peripherals
-obj-y += xilinx_ethlite.o
-
-obj-y := $(addprefix ../,$(obj-y))
-
 # shared objects
 obj-y += ppc.o ppc_booke.o
 # IBM pSeries (sPAPR)
 obj-$(CONFIG_PSERIES) += spapr.o xics.o spapr_vio.o spapr_events.o
 obj-$(CONFIG_PSERIES) += spapr_hcall.o spapr_iommu.o spapr_rtas.o
+obj-$(CONFIG_PSERIES) += spapr_pci.o
 # PowerPC 4xx boards
 obj-y += ppc405_boards.o ppc4xx_devs.o ppc405_uc.o ppc440_bamboo.o
+obj-y += ppc4xx_pci.o
 # PReP
 obj-y += prep.o
 # OldWorld PowerMac
index fef9c5d842a40cda2097ec69db9696ceb494b681..c1bdb6be981734ea5d83967be8c865e3d5281054 100644 (file)
 #include "net/net.h"
 #include "qemu/config-file.h"
 #include "hw/hw.h"
-#include "hw/serial.h"
+#include "hw/char/serial.h"
 #include "hw/pci/pci.h"
 #include "hw/boards.h"
 #include "sysemu/sysemu.h"
 #include "sysemu/kvm.h"
 #include "kvm_ppc.h"
 #include "sysemu/device_tree.h"
-#include "hw/openpic.h"
-#include "hw/ppc.h"
+#include "hw/ppc/openpic.h"
+#include "hw/ppc/ppc.h"
 #include "hw/loader.h"
 #include "elf.h"
 #include "hw/sysbus.h"
 #include "exec/address-spaces.h"
 #include "qemu/host-utils.h"
-#include "hw/ppce500_pci.h"
+#include "hw/pci-host/ppce500.h"
 
 #define BINARY_DEVICE_TREE_FILE    "mpc8544ds.dtb"
 #define UIMAGE_LOAD_BASE           0
index 4b3057528c69ff80e700d4e13d343e49f5117de1..7292ce12900ef232508687ab90c990b35b538551 100644 (file)
@@ -15,7 +15,7 @@
 #include "hw/boards.h"
 #include "sysemu/device_tree.h"
 #include "hw/pci/pci.h"
-#include "hw/openpic.h"
+#include "hw/ppc/openpic.h"
 
 static void e500plat_fixup_devtree(PPCE500Params *params, void *fdt)
 {
index b17107b7973e4547859eb6770e85eeaea72aed7f..54efaed627b3f321bcc839d48bd45db956467abd 100644 (file)
@@ -28,7 +28,7 @@
 #include "exec/memory.h"
 #include "hw/sysbus.h"
 #include "hw/ide/internal.h"
-#include "hw/adb.h"
+#include "hw/input/adb.h"
 
 /* SMP is not enabled, for now */
 #define MAX_CPUS 1
index a08a6b2086247b2bd7d17dfd9b99cc38a8cd84a4..4a9b8837e3d772ee8e8061977b57b0fc6ea58044 100644 (file)
  *
  */
 #include "hw/hw.h"
-#include "hw/ppc.h"
+#include "hw/ppc/ppc.h"
 #include "hw/ppc/mac.h"
-#include "hw/adb.h"
-#include "hw/mac_dbdma.h"
-#include "hw/nvram.h"
+#include "hw/input/adb.h"
+#include "hw/ppc/mac_dbdma.h"
+#include "hw/timer/m48t59.h"
 #include "hw/pci/pci.h"
 #include "net/net.h"
 #include "sysemu/sysemu.h"
 #include "hw/boards.h"
-#include "hw/fw_cfg.h"
-#include "hw/escc.h"
-#include "hw/openpic.h"
+#include "hw/nvram/fw_cfg.h"
+#include "hw/char/escc.h"
+#include "hw/ppc/openpic.h"
 #include "hw/ide.h"
 #include "hw/loader.h"
 #include "elf.h"
index 2778e45879dc141ad67845e32df94fe4a180be17..3acca94432dfae316c98c9283bf8bfb565c1e071 100644 (file)
  * THE SOFTWARE.
  */
 #include "hw/hw.h"
-#include "hw/ppc.h"
+#include "hw/ppc/ppc.h"
 #include "mac.h"
-#include "hw/adb.h"
-#include "hw/nvram.h"
+#include "hw/input/adb.h"
+#include "hw/timer/m48t59.h"
 #include "sysemu/sysemu.h"
 #include "net/net.h"
-#include "hw/isa.h"
+#include "hw/isa/isa.h"
 #include "hw/pci/pci.h"
 #include "hw/boards.h"
-#include "hw/fw_cfg.h"
-#include "hw/escc.h"
+#include "hw/nvram/fw_cfg.h"
+#include "hw/char/escc.h"
 #include "hw/ide.h"
 #include "hw/loader.h"
 #include "elf.h"
index cf29788c4da8d9dd1b93d800a0af5e6b6cadc11a..444da0246d454f402f8026afddd5645c41607a9e 100644 (file)
@@ -14,7 +14,7 @@
 #include "e500.h"
 #include "hw/boards.h"
 #include "sysemu/device_tree.h"
-#include "hw/openpic.h"
+#include "hw/ppc/openpic.h"
 
 static void mpc8544ds_fixup_devtree(PPCE500Params *params, void *fdt)
 {
index 85bc821d944e2d53e15a97af6451c2ab09ecdaee..fb57b42ea087c58f2852fb634353c13aa4dd2b62 100644 (file)
  * THE SOFTWARE.
  */
 #include "hw/hw.h"
-#include "hw/ppc.h"
+#include "hw/ppc/ppc.h"
 #include "qemu/timer.h"
 #include "sysemu/sysemu.h"
-#include "hw/nvram.h"
+#include "hw/timer/m48t59.h"
 #include "qemu/log.h"
 #include "hw/loader.h"
 #include "sysemu/kvm.h"
diff --git a/hw/ppc/ppc405.h b/hw/ppc/ppc405.h
new file mode 100644 (file)
index 0000000..1c5f04f
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * QEMU PowerPC 405 shared definitions
+ *
+ * Copyright (c) 2007 Jocelyn Mayer
+ *
+ * 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 !defined(PPC_405_H)
+#define PPC_405_H
+
+#include "hw/ppc/ppc4xx.h"
+
+/* Bootinfo as set-up by u-boot */
+typedef struct ppc4xx_bd_info_t ppc4xx_bd_info_t;
+struct ppc4xx_bd_info_t {
+    uint32_t bi_memstart;
+    uint32_t bi_memsize;
+    uint32_t bi_flashstart;
+    uint32_t bi_flashsize;
+    uint32_t bi_flashoffset; /* 0x10 */
+    uint32_t bi_sramstart;
+    uint32_t bi_sramsize;
+    uint32_t bi_bootflags;
+    uint32_t bi_ipaddr; /* 0x20 */
+    uint8_t  bi_enetaddr[6];
+    uint16_t bi_ethspeed;
+    uint32_t bi_intfreq;
+    uint32_t bi_busfreq; /* 0x30 */
+    uint32_t bi_baudrate;
+    uint8_t  bi_s_version[4];
+    uint8_t  bi_r_version[32];
+    uint32_t bi_procfreq;
+    uint32_t bi_plb_busfreq;
+    uint32_t bi_pci_busfreq;
+    uint8_t  bi_pci_enetaddr[6];
+    uint32_t bi_pci_enetaddr2[6];
+    uint32_t bi_opbfreq;
+    uint32_t bi_iic_fast[2];
+};
+
+/* PowerPC 405 core */
+ram_addr_t ppc405_set_bootinfo (CPUPPCState *env, ppc4xx_bd_info_t *bd,
+                                uint32_t flags);
+
+CPUPPCState *ppc405cr_init(MemoryRegion *address_space_mem,
+                        MemoryRegion ram_memories[4],
+                        hwaddr ram_bases[4],
+                        hwaddr ram_sizes[4],
+                        uint32_t sysclk, qemu_irq **picp,
+                        int do_init);
+CPUPPCState *ppc405ep_init(MemoryRegion *address_space_mem,
+                        MemoryRegion ram_memories[2],
+                        hwaddr ram_bases[2],
+                        hwaddr ram_sizes[2],
+                        uint32_t sysclk, qemu_irq **picp,
+                        int do_init);
+/* IBM STBxxx microcontrollers */
+CPUPPCState *ppc_stb025_init (MemoryRegion ram_memories[2],
+                           hwaddr ram_bases[2],
+                           hwaddr ram_sizes[2],
+                           uint32_t sysclk, qemu_irq **picp,
+                           ram_addr_t *offsetp);
+
+#endif /* !defined(PPC_405_H) */
index ba443cf8ef1063af755f783a77599429227b1311..8e56b16648f8085c5d643c14f041454cd072670c 100644 (file)
  * THE SOFTWARE.
  */
 #include "hw/hw.h"
-#include "hw/ppc.h"
-#include "hw/ppc405.h"
-#include "hw/nvram.h"
-#include "hw/flash.h"
+#include "hw/ppc/ppc.h"
+#include "ppc405.h"
+#include "hw/timer/m48t59.h"
+#include "hw/block/flash.h"
 #include "sysemu/sysemu.h"
 #include "block/block.h"
 #include "hw/boards.h"
index 56bae8f6e06e85f4fb13cb3f1459f83fcd3e8835..c6c909e05e325846433824519765351e6c75d39c 100644 (file)
@@ -22,9 +22,9 @@
  * THE SOFTWARE.
  */
 #include "hw/hw.h"
-#include "hw/ppc.h"
-#include "hw/ppc405.h"
-#include "hw/serial.h"
+#include "hw/ppc/ppc.h"
+#include "ppc405.h"
+#include "hw/char/serial.h"
 #include "qemu/timer.h"
 #include "sysemu/sysemu.h"
 #include "qemu/log.h"
index 66911b58c67c1e09bf7ba75b0aa4a706f5cfe8f9..a55e7170cc7c30f587a4b0002a41769b65a331ea 100644 (file)
@@ -23,9 +23,9 @@
 #include "hw/loader.h"
 #include "elf.h"
 #include "exec/address-spaces.h"
-#include "hw/serial.h"
-#include "hw/ppc.h"
-#include "hw/ppc405.h"
+#include "hw/char/serial.h"
+#include "hw/ppc/ppc.h"
+#include "ppc405.h"
 #include "sysemu/sysemu.h"
 #include "hw/sysbus.h"
 
index 49ec728a7b2e9dff3e9a4768f44d356e73d453cd..d8e3dae25cd606ebb05e8180c337766630528a7e 100644 (file)
@@ -22,8 +22,8 @@
  * THE SOFTWARE.
  */
 #include "hw/hw.h"
-#include "hw/ppc.h"
-#include "hw/ppc4xx.h"
+#include "hw/ppc/ppc.h"
+#include "hw/ppc/ppc4xx.h"
 #include "qemu/log.h"
 #include "exec/address-spaces.h"
 
diff --git a/hw/ppc/ppc4xx_pci.c b/hw/ppc/ppc4xx_pci.c
new file mode 100644 (file)
index 0000000..599539b
--- /dev/null
@@ -0,0 +1,414 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * 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/>.
+ *
+ * Copyright IBM Corp. 2008
+ *
+ * Authors: Hollis Blanchard <hollisb@us.ibm.com>
+ */
+
+/* This file implements emulation of the 32-bit PCI controller found in some
+ * 4xx SoCs, such as the 440EP. */
+
+#include "hw/hw.h"
+#include "hw/ppc/ppc.h"
+#include "hw/ppc/ppc4xx.h"
+#include "hw/pci/pci.h"
+#include "hw/pci/pci_host.h"
+#include "exec/address-spaces.h"
+
+#undef DEBUG
+#ifdef DEBUG
+#define DPRINTF(fmt, ...) do { printf(fmt, ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...)
+#endif /* DEBUG */
+
+struct PCIMasterMap {
+    uint32_t la;
+    uint32_t ma;
+    uint32_t pcila;
+    uint32_t pciha;
+};
+
+struct PCITargetMap {
+    uint32_t ms;
+    uint32_t la;
+};
+
+#define PPC4xx_PCI_HOST_BRIDGE(obj) \
+    OBJECT_CHECK(PPC4xxPCIState, (obj), TYPE_PPC4xx_PCI_HOST_BRIDGE)
+
+#define PPC4xx_PCI_NR_PMMS 3
+#define PPC4xx_PCI_NR_PTMS 2
+
+struct PPC4xxPCIState {
+    PCIHostState parent_obj;
+
+    struct PCIMasterMap pmm[PPC4xx_PCI_NR_PMMS];
+    struct PCITargetMap ptm[PPC4xx_PCI_NR_PTMS];
+    qemu_irq irq[4];
+
+    MemoryRegion container;
+    MemoryRegion iomem;
+};
+typedef struct PPC4xxPCIState PPC4xxPCIState;
+
+#define PCIC0_CFGADDR       0x0
+#define PCIC0_CFGDATA       0x4
+
+/* PLB Memory Map (PMM) registers specify which PLB addresses are translated to
+ * PCI accesses. */
+#define PCIL0_PMM0LA        0x0
+#define PCIL0_PMM0MA        0x4
+#define PCIL0_PMM0PCILA     0x8
+#define PCIL0_PMM0PCIHA     0xc
+#define PCIL0_PMM1LA        0x10
+#define PCIL0_PMM1MA        0x14
+#define PCIL0_PMM1PCILA     0x18
+#define PCIL0_PMM1PCIHA     0x1c
+#define PCIL0_PMM2LA        0x20
+#define PCIL0_PMM2MA        0x24
+#define PCIL0_PMM2PCILA     0x28
+#define PCIL0_PMM2PCIHA     0x2c
+
+/* PCI Target Map (PTM) registers specify which PCI addresses are translated to
+ * PLB accesses. */
+#define PCIL0_PTM1MS        0x30
+#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, hwaddr addr,
+                                    unsigned size)
+{
+    PPC4xxPCIState *ppc4xx_pci = opaque;
+    PCIHostState *phb = PCI_HOST_BRIDGE(ppc4xx_pci);
+
+    return phb->config_reg;
+}
+
+static void pci4xx_cfgaddr_write(void *opaque, hwaddr addr,
+                                  uint64_t value, unsigned size)
+{
+    PPC4xxPCIState *ppc4xx_pci = opaque;
+    PCIHostState *phb = PCI_HOST_BRIDGE(ppc4xx_pci);
+
+    phb->config_reg = value & ~0x3;
+}
+
+static const MemoryRegionOps pci4xx_cfgaddr_ops = {
+    .read = pci4xx_cfgaddr_read,
+    .write = pci4xx_cfgaddr_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void ppc4xx_pci_reg_write4(void *opaque, hwaddr offset,
+                                  uint64_t value, unsigned size)
+{
+    struct PPC4xxPCIState *pci = opaque;
+
+    /* We ignore all target attempts at PCI configuration, effectively
+     * assuming a bidirectional 1:1 mapping of PLB and PCI space. */
+
+    switch (offset) {
+    case PCIL0_PMM0LA:
+        pci->pmm[0].la = value;
+        break;
+    case PCIL0_PMM0MA:
+        pci->pmm[0].ma = value;
+        break;
+    case PCIL0_PMM0PCIHA:
+        pci->pmm[0].pciha = value;
+        break;
+    case PCIL0_PMM0PCILA:
+        pci->pmm[0].pcila = value;
+        break;
+
+    case PCIL0_PMM1LA:
+        pci->pmm[1].la = value;
+        break;
+    case PCIL0_PMM1MA:
+        pci->pmm[1].ma = value;
+        break;
+    case PCIL0_PMM1PCIHA:
+        pci->pmm[1].pciha = value;
+        break;
+    case PCIL0_PMM1PCILA:
+        pci->pmm[1].pcila = value;
+        break;
+
+    case PCIL0_PMM2LA:
+        pci->pmm[2].la = value;
+        break;
+    case PCIL0_PMM2MA:
+        pci->pmm[2].ma = value;
+        break;
+    case PCIL0_PMM2PCIHA:
+        pci->pmm[2].pciha = value;
+        break;
+    case PCIL0_PMM2PCILA:
+        pci->pmm[2].pcila = value;
+        break;
+
+    case PCIL0_PTM1MS:
+        pci->ptm[0].ms = value;
+        break;
+    case PCIL0_PTM1LA:
+        pci->ptm[0].la = value;
+        break;
+    case PCIL0_PTM2MS:
+        pci->ptm[1].ms = value;
+        break;
+    case PCIL0_PTM2LA:
+        pci->ptm[1].la = value;
+        break;
+
+    default:
+        printf("%s: unhandled PCI internal register 0x%lx\n", __func__,
+               (unsigned long)offset);
+        break;
+    }
+}
+
+static uint64_t ppc4xx_pci_reg_read4(void *opaque, hwaddr offset,
+                                     unsigned size)
+{
+    struct PPC4xxPCIState *pci = opaque;
+    uint32_t value;
+
+    switch (offset) {
+    case PCIL0_PMM0LA:
+        value = pci->pmm[0].la;
+        break;
+    case PCIL0_PMM0MA:
+        value = pci->pmm[0].ma;
+        break;
+    case PCIL0_PMM0PCIHA:
+        value = pci->pmm[0].pciha;
+        break;
+    case PCIL0_PMM0PCILA:
+        value = pci->pmm[0].pcila;
+        break;
+
+    case PCIL0_PMM1LA:
+        value = pci->pmm[1].la;
+        break;
+    case PCIL0_PMM1MA:
+        value = pci->pmm[1].ma;
+        break;
+    case PCIL0_PMM1PCIHA:
+        value = pci->pmm[1].pciha;
+        break;
+    case PCIL0_PMM1PCILA:
+        value = pci->pmm[1].pcila;
+        break;
+
+    case PCIL0_PMM2LA:
+        value = pci->pmm[2].la;
+        break;
+    case PCIL0_PMM2MA:
+        value = pci->pmm[2].ma;
+        break;
+    case PCIL0_PMM2PCIHA:
+        value = pci->pmm[2].pciha;
+        break;
+    case PCIL0_PMM2PCILA:
+        value = pci->pmm[2].pcila;
+        break;
+
+    case PCIL0_PTM1MS:
+        value = pci->ptm[0].ms;
+        break;
+    case PCIL0_PTM1LA:
+        value = pci->ptm[0].la;
+        break;
+    case PCIL0_PTM2MS:
+        value = pci->ptm[1].ms;
+        break;
+    case PCIL0_PTM2LA:
+        value = pci->ptm[1].la;
+        break;
+
+    default:
+        printf("%s: invalid PCI internal register 0x%lx\n", __func__,
+               (unsigned long)offset);
+        value = 0;
+    }
+
+    return value;
+}
+
+static const MemoryRegionOps pci_reg_ops = {
+    .read = ppc4xx_pci_reg_read4,
+    .write = ppc4xx_pci_reg_write4,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void ppc4xx_pci_reset(void *opaque)
+{
+    struct PPC4xxPCIState *pci = opaque;
+
+    memset(pci->pmm, 0, sizeof(pci->pmm));
+    memset(pci->ptm, 0, sizeof(pci->ptm));
+}
+
+/* On Bamboo, all pins from each slot are tied to a single board IRQ. This
+ * may need further refactoring for other boards. */
+static int ppc4xx_pci_map_irq(PCIDevice *pci_dev, int irq_num)
+{
+    int slot = pci_dev->devfn >> 3;
+
+    DPRINTF("%s: devfn %x irq %d -> %d\n", __func__,
+            pci_dev->devfn, irq_num, slot);
+
+    return slot - 1;
+}
+
+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);
+}
+
+static const VMStateDescription vmstate_pci_master_map = {
+    .name = "pci_master_map",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32(la, struct PCIMasterMap),
+        VMSTATE_UINT32(ma, struct PCIMasterMap),
+        VMSTATE_UINT32(pcila, struct PCIMasterMap),
+        VMSTATE_UINT32(pciha, struct PCIMasterMap),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_pci_target_map = {
+    .name = "pci_target_map",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32(ms, struct PCITargetMap),
+        VMSTATE_UINT32(la, struct PCITargetMap),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_ppc4xx_pci = {
+    .name = "ppc4xx_pci",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_STRUCT_ARRAY(pmm, PPC4xxPCIState, PPC4xx_PCI_NR_PMMS, 1,
+                             vmstate_pci_master_map,
+                             struct PCIMasterMap),
+        VMSTATE_STRUCT_ARRAY(ptm, PPC4xxPCIState, PPC4xx_PCI_NR_PTMS, 1,
+                             vmstate_pci_target_map,
+                             struct PCITargetMap),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+/* XXX Interrupt acknowledge cycles not supported. */
+static int ppc4xx_pcihost_initfn(SysBusDevice *dev)
+{
+    PPC4xxPCIState *s;
+    PCIHostState *h;
+    PCIBus *b;
+    int i;
+
+    h = PCI_HOST_BRIDGE(dev);
+    s = PPC4xx_PCI_HOST_BRIDGE(dev);
+
+    for (i = 0; i < ARRAY_SIZE(s->irq); i++) {
+        sysbus_init_irq(dev, &s->irq[i]);
+    }
+
+    b = pci_register_bus(DEVICE(dev), NULL, ppc4xx_pci_set_irq,
+                         ppc4xx_pci_map_irq, s->irq, get_system_memory(),
+                         get_system_io(), 0, 4, TYPE_PCI_BUS);
+    h->bus = b;
+
+    pci_create_simple(b, 0, "ppc4xx-host-bridge");
+
+    /* XXX split into 2 memory regions, one for config space, one for regs */
+    memory_region_init(&s->container, "pci-container", PCI_ALL_SIZE);
+    memory_region_init_io(&h->conf_mem, &pci_host_conf_le_ops, h,
+                          "pci-conf-idx", 4);
+    memory_region_init_io(&h->data_mem, &pci_host_data_le_ops, h,
+                          "pci-conf-data", 4);
+    memory_region_init_io(&s->iomem, &pci_reg_ops, s,
+                          "pci.reg", PCI_REG_SIZE);
+    memory_region_add_subregion(&s->container, PCIC0_CFGADDR, &h->conf_mem);
+    memory_region_add_subregion(&s->container, PCIC0_CFGDATA, &h->data_mem);
+    memory_region_add_subregion(&s->container, PCI_REG_BASE, &s->iomem);
+    sysbus_init_mmio(dev, &s->container);
+    qemu_register_reset(ppc4xx_pci_reset, s);
+
+    return 0;
+}
+
+static void ppc4xx_host_bridge_class_init(ObjectClass *klass, void *data)
+{
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->desc        = "Host bridge";
+    k->vendor_id    = PCI_VENDOR_ID_IBM;
+    k->device_id    = PCI_DEVICE_ID_IBM_440GX;
+    k->class_id     = PCI_CLASS_BRIDGE_OTHER;
+}
+
+static const 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 const TypeInfo ppc4xx_pcihost_info = {
+    .name          = TYPE_PPC4xx_PCI_HOST_BRIDGE,
+    .parent        = TYPE_PCI_HOST_BRIDGE,
+    .instance_size = sizeof(PPC4xxPCIState),
+    .class_init    = ppc4xx_pcihost_class_init,
+};
+
+static void ppc4xx_pci_register_types(void)
+{
+    type_register_static(&ppc4xx_pcihost_info);
+    type_register_static(&ppc4xx_host_bridge_info);
+}
+
+type_init(ppc4xx_pci_register_types)
index 30375c0c41b4d2518fed96c99577063d9f654d49..585f53b912fc7b0eee7bcc0250cd6e1b235e6497 100644 (file)
  * THE SOFTWARE.
  */
 #include "hw/hw.h"
-#include "hw/ppc.h"
+#include "hw/ppc/ppc.h"
 #include "qemu/timer.h"
 #include "sysemu/sysemu.h"
-#include "hw/nvram.h"
+#include "hw/timer/m48t59.h"
 #include "qemu/log.h"
 #include "hw/loader.h"
 
index 292091180d40a4c16f251f02e37ad6a0ee6f1306..cceab3ead93e852e2b7375940a177e002ff3e5c2 100644 (file)
  * THE SOFTWARE.
  */
 #include "hw/hw.h"
-#include "hw/nvram.h"
-#include "hw/pc.h"
-#include "hw/serial.h"
-#include "hw/fdc.h"
+#include "hw/timer/m48t59.h"
+#include "hw/i386/pc.h"
+#include "hw/char/serial.h"
+#include "hw/block/fdc.h"
 #include "net/net.h"
 #include "sysemu/sysemu.h"
-#include "hw/isa.h"
+#include "hw/isa/isa.h"
 #include "hw/pci/pci.h"
 #include "hw/pci/pci_host.h"
-#include "hw/ppc.h"
+#include "hw/ppc/ppc.h"
 #include "hw/boards.h"
 #include "qemu/log.h"
 #include "hw/ide.h"
 #include "hw/loader.h"
-#include "hw/mc146818rtc.h"
-#include "hw/pc87312.h"
+#include "hw/timer/mc146818rtc.h"
+#include "hw/isa/pc87312.h"
 #include "sysemu/blockdev.h"
 #include "sysemu/arch_init.h"
 #include "exec/address-spaces.h"
index 7b2a11fbe462bd1490298a79fb9f3e491e01ab6d..7a425011da9b7693048807acc6860309f60c1a61 100644 (file)
 #include "kvm_ppc.h"
 
 #include "hw/boards.h"
-#include "hw/ppc.h"
+#include "hw/ppc/ppc.h"
 #include "hw/loader.h"
 
-#include "hw/spapr.h"
-#include "hw/spapr_vio.h"
-#include "hw/spapr_pci.h"
-#include "hw/xics.h"
+#include "hw/ppc/spapr.h"
+#include "hw/ppc/spapr_vio.h"
+#include "hw/pci-host/spapr.h"
+#include "hw/ppc/xics.h"
 #include "hw/pci/msi.h"
 
 #include "sysemu/kvm.h"
index ce78f0922e7f47e7ab5cca323e5c72ca732678f8..ff87ac31d1302226bfd54ae5c62fa9028eedf8b7 100644 (file)
@@ -30,8 +30,8 @@
 #include "hw/qdev.h"
 #include "sysemu/device_tree.h"
 
-#include "hw/spapr.h"
-#include "hw/spapr_vio.h"
+#include "hw/ppc/spapr.h"
+#include "hw/ppc/spapr_vio.h"
 
 #include <libfdt.h>
 
index 22cfb7e6742c7e80b3e60e94bece6c2940a986c5..f518aee21661be914300d86e8e0432f6b1e2ac90 100644 (file)
@@ -2,7 +2,7 @@
 #include "cpu.h"
 #include "sysemu/sysemu.h"
 #include "helper_regs.h"
-#include "hw/spapr.h"
+#include "hw/ppc/spapr.h"
 #include "mmu-hash64.h"
 
 static target_ulong compute_tlbie_rb(target_ulong v, target_ulong r,
index 8d500bf6be01ad80aa9fe0fc59e14ac0f0670b1b..d2782cfb39ac5f91806bb4131a4ab78b7adf1afa 100644 (file)
@@ -23,7 +23,7 @@
 #include "sysemu/dma.h"
 #include "exec/address-spaces.h"
 
-#include "hw/spapr.h"
+#include "hw/ppc/spapr.h"
 
 #include <libfdt.h>
 
diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c
new file mode 100644 (file)
index 0000000..62ff323
--- /dev/null
@@ -0,0 +1,839 @@
+/*
+ * QEMU sPAPR PCI host originated from Uninorth PCI host
+ *
+ * Copyright (c) 2011 Alexey Kardashevskiy, IBM Corporation.
+ * Copyright (C) 2011 David Gibson, IBM Corporation.
+ *
+ * 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 "hw/hw.h"
+#include "hw/pci/pci.h"
+#include "hw/pci/msi.h"
+#include "hw/pci/msix.h"
+#include "hw/pci/pci_host.h"
+#include "hw/ppc/spapr.h"
+#include "hw/pci-host/spapr.h"
+#include "exec/address-spaces.h"
+#include <libfdt.h>
+#include "trace.h"
+
+#include "hw/pci/pci_bus.h"
+
+/* Copied from the kernel arch/powerpc/platforms/pseries/msi.c */
+#define RTAS_QUERY_FN           0
+#define RTAS_CHANGE_FN          1
+#define RTAS_RESET_FN           2
+#define RTAS_CHANGE_MSI_FN      3
+#define RTAS_CHANGE_MSIX_FN     4
+
+/* Interrupt types to return on RTAS_CHANGE_* */
+#define RTAS_TYPE_MSI           1
+#define RTAS_TYPE_MSIX          2
+
+static sPAPRPHBState *find_phb(sPAPREnvironment *spapr, uint64_t buid)
+{
+    sPAPRPHBState *sphb;
+
+    QLIST_FOREACH(sphb, &spapr->phbs, list) {
+        if (sphb->buid != buid) {
+            continue;
+        }
+        return sphb;
+    }
+
+    return NULL;
+}
+
+static PCIDevice *find_dev(sPAPREnvironment *spapr, uint64_t buid,
+                           uint32_t config_addr)
+{
+    sPAPRPHBState *sphb = find_phb(spapr, buid);
+    PCIHostState *phb = PCI_HOST_BRIDGE(sphb);
+    BusState *bus = BUS(phb->bus);
+    BusChild *kid;
+    int devfn = (config_addr >> 8) & 0xFF;
+
+    if (!phb) {
+        return NULL;
+    }
+
+    QTAILQ_FOREACH(kid, &bus->children, sibling) {
+        PCIDevice *dev = (PCIDevice *)kid->child;
+        if (dev->devfn == devfn) {
+            return dev;
+        }
+    }
+
+    return NULL;
+}
+
+static uint32_t rtas_pci_cfgaddr(uint32_t arg)
+{
+    /* This handles the encoding of extended config space addresses */
+    return ((arg >> 20) & 0xf00) | (arg & 0xff);
+}
+
+static void finish_read_pci_config(sPAPREnvironment *spapr, uint64_t buid,
+                                   uint32_t addr, uint32_t size,
+                                   target_ulong rets)
+{
+    PCIDevice *pci_dev;
+    uint32_t val;
+
+    if ((size != 1) && (size != 2) && (size != 4)) {
+        /* access must be 1, 2 or 4 bytes */
+        rtas_st(rets, 0, -1);
+        return;
+    }
+
+    pci_dev = find_dev(spapr, buid, addr);
+    addr = rtas_pci_cfgaddr(addr);
+
+    if (!pci_dev || (addr % size) || (addr >= pci_config_size(pci_dev))) {
+        /* Access must be to a valid device, within bounds and
+         * naturally aligned */
+        rtas_st(rets, 0, -1);
+        return;
+    }
+
+    val = pci_host_config_read_common(pci_dev, addr,
+                                      pci_config_size(pci_dev), size);
+
+    rtas_st(rets, 0, 0);
+    rtas_st(rets, 1, val);
+}
+
+static void rtas_ibm_read_pci_config(sPAPREnvironment *spapr,
+                                     uint32_t token, uint32_t nargs,
+                                     target_ulong args,
+                                     uint32_t nret, target_ulong rets)
+{
+    uint64_t buid;
+    uint32_t size, addr;
+
+    if ((nargs != 4) || (nret != 2)) {
+        rtas_st(rets, 0, -1);
+        return;
+    }
+
+    buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2);
+    size = rtas_ld(args, 3);
+    addr = rtas_ld(args, 0);
+
+    finish_read_pci_config(spapr, buid, addr, size, rets);
+}
+
+static void rtas_read_pci_config(sPAPREnvironment *spapr,
+                                 uint32_t token, uint32_t nargs,
+                                 target_ulong args,
+                                 uint32_t nret, target_ulong rets)
+{
+    uint32_t size, addr;
+
+    if ((nargs != 2) || (nret != 2)) {
+        rtas_st(rets, 0, -1);
+        return;
+    }
+
+    size = rtas_ld(args, 1);
+    addr = rtas_ld(args, 0);
+
+    finish_read_pci_config(spapr, 0, addr, size, rets);
+}
+
+static void finish_write_pci_config(sPAPREnvironment *spapr, uint64_t buid,
+                                    uint32_t addr, uint32_t size,
+                                    uint32_t val, target_ulong rets)
+{
+    PCIDevice *pci_dev;
+
+    if ((size != 1) && (size != 2) && (size != 4)) {
+        /* access must be 1, 2 or 4 bytes */
+        rtas_st(rets, 0, -1);
+        return;
+    }
+
+    pci_dev = find_dev(spapr, buid, addr);
+    addr = rtas_pci_cfgaddr(addr);
+
+    if (!pci_dev || (addr % size) || (addr >= pci_config_size(pci_dev))) {
+        /* Access must be to a valid device, within bounds and
+         * naturally aligned */
+        rtas_st(rets, 0, -1);
+        return;
+    }
+
+    pci_host_config_write_common(pci_dev, addr, pci_config_size(pci_dev),
+                                 val, size);
+
+    rtas_st(rets, 0, 0);
+}
+
+static void rtas_ibm_write_pci_config(sPAPREnvironment *spapr,
+                                      uint32_t token, uint32_t nargs,
+                                      target_ulong args,
+                                      uint32_t nret, target_ulong rets)
+{
+    uint64_t buid;
+    uint32_t val, size, addr;
+
+    if ((nargs != 5) || (nret != 1)) {
+        rtas_st(rets, 0, -1);
+        return;
+    }
+
+    buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2);
+    val = rtas_ld(args, 4);
+    size = rtas_ld(args, 3);
+    addr = rtas_ld(args, 0);
+
+    finish_write_pci_config(spapr, buid, addr, size, val, rets);
+}
+
+static void rtas_write_pci_config(sPAPREnvironment *spapr,
+                                  uint32_t token, uint32_t nargs,
+                                  target_ulong args,
+                                  uint32_t nret, target_ulong rets)
+{
+    uint32_t val, size, addr;
+
+    if ((nargs != 3) || (nret != 1)) {
+        rtas_st(rets, 0, -1);
+        return;
+    }
+
+
+    val = rtas_ld(args, 2);
+    size = rtas_ld(args, 1);
+    addr = rtas_ld(args, 0);
+
+    finish_write_pci_config(spapr, 0, addr, size, val, rets);
+}
+
+/*
+ * Find an entry with config_addr or returns the empty one if not found AND
+ * alloc_new is set.
+ * At the moment the msi_table entries are never released so there is
+ * no point to look till the end of the list if we need to find the free entry.
+ */
+static int spapr_msicfg_find(sPAPRPHBState *phb, uint32_t config_addr,
+                             bool alloc_new)
+{
+    int i;
+
+    for (i = 0; i < SPAPR_MSIX_MAX_DEVS; ++i) {
+        if (!phb->msi_table[i].nvec) {
+            break;
+        }
+        if (phb->msi_table[i].config_addr == config_addr) {
+            return i;
+        }
+    }
+    if ((i < SPAPR_MSIX_MAX_DEVS) && alloc_new) {
+        trace_spapr_pci_msi("Allocating new MSI config", i, config_addr);
+        return i;
+    }
+
+    return -1;
+}
+
+/*
+ * Set MSI/MSIX message data.
+ * This is required for msi_notify()/msix_notify() which
+ * will write at the addresses via spapr_msi_write().
+ */
+static void spapr_msi_setmsg(PCIDevice *pdev, hwaddr addr,
+                             bool msix, unsigned req_num)
+{
+    unsigned i;
+    MSIMessage msg = { .address = addr, .data = 0 };
+
+    if (!msix) {
+        msi_set_message(pdev, msg);
+        trace_spapr_pci_msi_setup(pdev->name, 0, msg.address);
+        return;
+    }
+
+    for (i = 0; i < req_num; ++i) {
+        msg.address = addr | (i << 2);
+        msix_set_message(pdev, i, msg);
+        trace_spapr_pci_msi_setup(pdev->name, i, msg.address);
+    }
+}
+
+static void rtas_ibm_change_msi(sPAPREnvironment *spapr,
+                                uint32_t token, uint32_t nargs,
+                                target_ulong args, uint32_t nret,
+                                target_ulong rets)
+{
+    uint32_t config_addr = rtas_ld(args, 0);
+    uint64_t buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2);
+    unsigned int func = rtas_ld(args, 3);
+    unsigned int req_num = rtas_ld(args, 4); /* 0 == remove all */
+    unsigned int seq_num = rtas_ld(args, 5);
+    unsigned int ret_intr_type;
+    int ndev, irq;
+    sPAPRPHBState *phb = NULL;
+    PCIDevice *pdev = NULL;
+
+    switch (func) {
+    case RTAS_CHANGE_MSI_FN:
+    case RTAS_CHANGE_FN:
+        ret_intr_type = RTAS_TYPE_MSI;
+        break;
+    case RTAS_CHANGE_MSIX_FN:
+        ret_intr_type = RTAS_TYPE_MSIX;
+        break;
+    default:
+        fprintf(stderr, "rtas_ibm_change_msi(%u) is not implemented\n", func);
+        rtas_st(rets, 0, -3); /* Parameter error */
+        return;
+    }
+
+    /* Fins sPAPRPHBState */
+    phb = find_phb(spapr, buid);
+    if (phb) {
+        pdev = find_dev(spapr, buid, config_addr);
+    }
+    if (!phb || !pdev) {
+        rtas_st(rets, 0, -3); /* Parameter error */
+        return;
+    }
+
+    /* Releasing MSIs */
+    if (!req_num) {
+        ndev = spapr_msicfg_find(phb, config_addr, false);
+        if (ndev < 0) {
+            trace_spapr_pci_msi("MSI has not been enabled", -1, config_addr);
+            rtas_st(rets, 0, -1); /* Hardware error */
+            return;
+        }
+        trace_spapr_pci_msi("Released MSIs", ndev, config_addr);
+        rtas_st(rets, 0, 0);
+        rtas_st(rets, 1, 0);
+        return;
+    }
+
+    /* Enabling MSI */
+
+    /* Find a device number in the map to add or reuse the existing one */
+    ndev = spapr_msicfg_find(phb, config_addr, true);
+    if (ndev >= SPAPR_MSIX_MAX_DEVS || ndev < 0) {
+        fprintf(stderr, "No free entry for a new MSI device\n");
+        rtas_st(rets, 0, -1); /* Hardware error */
+        return;
+    }
+    trace_spapr_pci_msi("Configuring MSI", ndev, config_addr);
+
+    /* Check if there is an old config and MSI number has not changed */
+    if (phb->msi_table[ndev].nvec && (req_num != phb->msi_table[ndev].nvec)) {
+        /* Unexpected behaviour */
+        fprintf(stderr, "Cannot reuse MSI config for device#%d", ndev);
+        rtas_st(rets, 0, -1); /* Hardware error */
+        return;
+    }
+
+    /* There is no cached config, allocate MSIs */
+    if (!phb->msi_table[ndev].nvec) {
+        irq = spapr_allocate_irq_block(req_num, false);
+        if (irq < 0) {
+            fprintf(stderr, "Cannot allocate MSIs for device#%d", ndev);
+            rtas_st(rets, 0, -1); /* Hardware error */
+            return;
+        }
+        phb->msi_table[ndev].irq = irq;
+        phb->msi_table[ndev].nvec = req_num;
+        phb->msi_table[ndev].config_addr = config_addr;
+    }
+
+    /* Setup MSI/MSIX vectors in the device (via cfgspace or MSIX BAR) */
+    spapr_msi_setmsg(pdev, phb->msi_win_addr | (ndev << 16),
+                     ret_intr_type == RTAS_TYPE_MSIX, req_num);
+
+    rtas_st(rets, 0, 0);
+    rtas_st(rets, 1, req_num);
+    rtas_st(rets, 2, ++seq_num);
+    rtas_st(rets, 3, ret_intr_type);
+
+    trace_spapr_pci_rtas_ibm_change_msi(func, req_num);
+}
+
+static void rtas_ibm_query_interrupt_source_number(sPAPREnvironment *spapr,
+                                                   uint32_t token,
+                                                   uint32_t nargs,
+                                                   target_ulong args,
+                                                   uint32_t nret,
+                                                   target_ulong rets)
+{
+    uint32_t config_addr = rtas_ld(args, 0);
+    uint64_t buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2);
+    unsigned int intr_src_num = -1, ioa_intr_num = rtas_ld(args, 3);
+    int ndev;
+    sPAPRPHBState *phb = NULL;
+
+    /* Fins sPAPRPHBState */
+    phb = find_phb(spapr, buid);
+    if (!phb) {
+        rtas_st(rets, 0, -3); /* Parameter error */
+        return;
+    }
+
+    /* Find device descriptor and start IRQ */
+    ndev = spapr_msicfg_find(phb, config_addr, false);
+    if (ndev < 0) {
+        trace_spapr_pci_msi("MSI has not been enabled", -1, config_addr);
+        rtas_st(rets, 0, -1); /* Hardware error */
+        return;
+    }
+
+    intr_src_num = phb->msi_table[ndev].irq + ioa_intr_num;
+    trace_spapr_pci_rtas_ibm_query_interrupt_source_number(ioa_intr_num,
+                                                           intr_src_num);
+
+    rtas_st(rets, 0, 0);
+    rtas_st(rets, 1, intr_src_num);
+    rtas_st(rets, 2, 1);/* 0 == level; 1 == edge */
+}
+
+static int pci_spapr_swizzle(int slot, int pin)
+{
+    return (slot + pin) % PCI_NUM_PINS;
+}
+
+static int pci_spapr_map_irq(PCIDevice *pci_dev, int irq_num)
+{
+    /*
+     * Here we need to convert pci_dev + irq_num to some unique value
+     * which is less than number of IRQs on the specific bus (4).  We
+     * use standard PCI swizzling, that is (slot number + pin number)
+     * % 4.
+     */
+    return pci_spapr_swizzle(PCI_SLOT(pci_dev->devfn), irq_num);
+}
+
+static void pci_spapr_set_irq(void *opaque, int irq_num, int level)
+{
+    /*
+     * Here we use the number returned by pci_spapr_map_irq to find a
+     * corresponding qemu_irq.
+     */
+    sPAPRPHBState *phb = opaque;
+
+    trace_spapr_pci_lsi_set(phb->dtbusname, irq_num, phb->lsi_table[irq_num].irq);
+    qemu_set_irq(spapr_phb_lsi_qirq(phb, irq_num), level);
+}
+
+static uint64_t spapr_io_read(void *opaque, hwaddr addr,
+                              unsigned size)
+{
+    switch (size) {
+    case 1:
+        return cpu_inb(addr);
+    case 2:
+        return cpu_inw(addr);
+    case 4:
+        return cpu_inl(addr);
+    }
+    assert(0);
+}
+
+static void spapr_io_write(void *opaque, hwaddr addr,
+                           uint64_t data, unsigned size)
+{
+    switch (size) {
+    case 1:
+        cpu_outb(addr, data);
+        return;
+    case 2:
+        cpu_outw(addr, data);
+        return;
+    case 4:
+        cpu_outl(addr, data);
+        return;
+    }
+    assert(0);
+}
+
+static const MemoryRegionOps spapr_io_ops = {
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .read = spapr_io_read,
+    .write = spapr_io_write
+};
+
+/*
+ * MSI/MSIX memory region implementation.
+ * The handler handles both MSI and MSIX.
+ * For MSI-X, the vector number is encoded as a part of the address,
+ * data is set to 0.
+ * For MSI, the vector number is encoded in least bits in data.
+ */
+static void spapr_msi_write(void *opaque, hwaddr addr,
+                            uint64_t data, unsigned size)
+{
+    sPAPRPHBState *phb = opaque;
+    int ndev = addr >> 16;
+    int vec = ((addr & 0xFFFF) >> 2) | data;
+    uint32_t irq = phb->msi_table[ndev].irq + vec;
+
+    trace_spapr_pci_msi_write(addr, data, irq);
+
+    qemu_irq_pulse(xics_get_qirq(spapr->icp, irq));
+}
+
+static const MemoryRegionOps spapr_msi_ops = {
+    /* There is no .read as the read result is undefined by PCI spec */
+    .read = NULL,
+    .write = spapr_msi_write,
+    .endianness = DEVICE_LITTLE_ENDIAN
+};
+
+/*
+ * PHB PCI device
+ */
+static DMAContext *spapr_pci_dma_context_fn(PCIBus *bus, void *opaque,
+                                            int devfn)
+{
+    sPAPRPHBState *phb = opaque;
+
+    return phb->dma;
+}
+
+static int spapr_phb_init(SysBusDevice *s)
+{
+    sPAPRPHBState *sphb = SPAPR_PCI_HOST_BRIDGE(s);
+    PCIHostState *phb = PCI_HOST_BRIDGE(s);
+    const char *busname;
+    char *namebuf;
+    int i;
+    PCIBus *bus;
+
+    if (sphb->index != -1) {
+        hwaddr windows_base;
+
+        if ((sphb->buid != -1) || (sphb->dma_liobn != -1)
+            || (sphb->mem_win_addr != -1)
+            || (sphb->io_win_addr != -1)
+            || (sphb->msi_win_addr != -1)) {
+            fprintf(stderr, "Either \"index\" or other parameters must"
+                    " be specified for PAPR PHB, not both\n");
+            return -1;
+        }
+
+        sphb->buid = SPAPR_PCI_BASE_BUID + sphb->index;
+        sphb->dma_liobn = SPAPR_PCI_BASE_LIOBN + sphb->index;
+
+        windows_base = SPAPR_PCI_WINDOW_BASE
+            + sphb->index * SPAPR_PCI_WINDOW_SPACING;
+        sphb->mem_win_addr = windows_base + SPAPR_PCI_MMIO_WIN_OFF;
+        sphb->io_win_addr = windows_base + SPAPR_PCI_IO_WIN_OFF;
+        sphb->msi_win_addr = windows_base + SPAPR_PCI_MSI_WIN_OFF;
+    }
+
+    if (sphb->buid == -1) {
+        fprintf(stderr, "BUID not specified for PHB\n");
+        return -1;
+    }
+
+    if (sphb->dma_liobn == -1) {
+        fprintf(stderr, "LIOBN not specified for PHB\n");
+        return -1;
+    }
+
+    if (sphb->mem_win_addr == -1) {
+        fprintf(stderr, "Memory window address not specified for PHB\n");
+        return -1;
+    }
+
+    if (sphb->io_win_addr == -1) {
+        fprintf(stderr, "IO window address not specified for PHB\n");
+        return -1;
+    }
+
+    if (sphb->msi_win_addr == -1) {
+        fprintf(stderr, "MSI window address not specified for PHB\n");
+        return -1;
+    }
+
+    if (find_phb(spapr, sphb->buid)) {
+        fprintf(stderr, "PCI host bridges must have unique BUIDs\n");
+        return -1;
+    }
+
+    sphb->dtbusname = g_strdup_printf("pci@%" PRIx64, sphb->buid);
+
+    namebuf = alloca(strlen(sphb->dtbusname) + 32);
+
+    /* Initialize memory regions */
+    sprintf(namebuf, "%s.mmio", sphb->dtbusname);
+    memory_region_init(&sphb->memspace, namebuf, INT64_MAX);
+
+    sprintf(namebuf, "%s.mmio-alias", sphb->dtbusname);
+    memory_region_init_alias(&sphb->memwindow, namebuf, &sphb->memspace,
+                             SPAPR_PCI_MEM_WIN_BUS_OFFSET, sphb->mem_win_size);
+    memory_region_add_subregion(get_system_memory(), sphb->mem_win_addr,
+                                &sphb->memwindow);
+
+    /* On ppc, we only have MMIO no specific IO space from the CPU
+     * perspective.  In theory we ought to be able to embed the PCI IO
+     * memory region direction in the system memory space.  However,
+     * if any of the IO BAR subregions use the old_portio mechanism,
+     * that won't be processed properly unless accessed from the
+     * system io address space.  This hack to bounce things via
+     * system_io works around the problem until all the users of
+     * old_portion are updated */
+    sprintf(namebuf, "%s.io", sphb->dtbusname);
+    memory_region_init(&sphb->iospace, namebuf, SPAPR_PCI_IO_WIN_SIZE);
+    /* FIXME: fix to support multiple PHBs */
+    memory_region_add_subregion(get_system_io(), 0, &sphb->iospace);
+
+    sprintf(namebuf, "%s.io-alias", sphb->dtbusname);
+    memory_region_init_io(&sphb->iowindow, &spapr_io_ops, sphb,
+                          namebuf, SPAPR_PCI_IO_WIN_SIZE);
+    memory_region_add_subregion(get_system_memory(), sphb->io_win_addr,
+                                &sphb->iowindow);
+
+    /* As MSI/MSIX interrupts trigger by writing at MSI/MSIX vectors,
+     * we need to allocate some memory to catch those writes coming
+     * from msi_notify()/msix_notify() */
+    if (msi_supported) {
+        sprintf(namebuf, "%s.msi", sphb->dtbusname);
+        memory_region_init_io(&sphb->msiwindow, &spapr_msi_ops, sphb,
+                              namebuf, SPAPR_MSIX_MAX_DEVS * 0x10000);
+        memory_region_add_subregion(get_system_memory(), sphb->msi_win_addr,
+                                    &sphb->msiwindow);
+    }
+
+    /*
+     * Selecting a busname is more complex than you'd think, due to
+     * interacting constraints.  If the user has specified an id
+     * explicitly for the phb , then we want to use the qdev default
+     * of naming the bus based on the bridge device (so the user can
+     * then assign devices to it in the way they expect).  For the
+     * first / default PCI bus (index=0) we want to use just "pci"
+     * because libvirt expects there to be a bus called, simply,
+     * "pci".  Otherwise, we use the same name as in the device tree,
+     * since it's unique by construction, and makes the guest visible
+     * BUID clear.
+     */
+    if (s->qdev.id) {
+        busname = NULL;
+    } else if (sphb->index == 0) {
+        busname = "pci";
+    } else {
+        busname = sphb->dtbusname;
+    }
+    bus = pci_register_bus(DEVICE(s), busname,
+                           pci_spapr_set_irq, pci_spapr_map_irq, sphb,
+                           &sphb->memspace, &sphb->iospace,
+                           PCI_DEVFN(0, 0), PCI_NUM_PINS, TYPE_PCI_BUS);
+    phb->bus = bus;
+
+    sphb->dma_window_start = 0;
+    sphb->dma_window_size = 0x40000000;
+    sphb->dma = spapr_tce_new_dma_context(sphb->dma_liobn, sphb->dma_window_size);
+    if (!sphb->dma) {
+        fprintf(stderr, "Unable to create TCE table for %s\n", sphb->dtbusname);
+        return -1;
+    }
+    pci_setup_iommu(bus, spapr_pci_dma_context_fn, sphb);
+
+    QLIST_INSERT_HEAD(&spapr->phbs, sphb, list);
+
+    /* Initialize the LSI table */
+    for (i = 0; i < PCI_NUM_PINS; i++) {
+        uint32_t irq;
+
+        irq = spapr_allocate_lsi(0);
+        if (!irq) {
+            return -1;
+        }
+
+        sphb->lsi_table[i].irq = irq;
+    }
+
+    return 0;
+}
+
+static void spapr_phb_reset(DeviceState *qdev)
+{
+    SysBusDevice *s = SYS_BUS_DEVICE(qdev);
+    sPAPRPHBState *sphb = SPAPR_PCI_HOST_BRIDGE(s);
+
+    /* Reset the IOMMU state */
+    spapr_tce_reset(sphb->dma);
+}
+
+static Property spapr_phb_properties[] = {
+    DEFINE_PROP_INT32("index", sPAPRPHBState, index, -1),
+    DEFINE_PROP_HEX64("buid", sPAPRPHBState, buid, -1),
+    DEFINE_PROP_HEX32("liobn", sPAPRPHBState, dma_liobn, -1),
+    DEFINE_PROP_HEX64("mem_win_addr", sPAPRPHBState, mem_win_addr, -1),
+    DEFINE_PROP_HEX64("mem_win_size", sPAPRPHBState, mem_win_size,
+                      SPAPR_PCI_MMIO_WIN_SIZE),
+    DEFINE_PROP_HEX64("io_win_addr", sPAPRPHBState, io_win_addr, -1),
+    DEFINE_PROP_HEX64("io_win_size", sPAPRPHBState, io_win_size,
+                      SPAPR_PCI_IO_WIN_SIZE),
+    DEFINE_PROP_HEX64("msi_win_addr", sPAPRPHBState, msi_win_addr, -1),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void spapr_phb_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    sdc->init = spapr_phb_init;
+    dc->props = spapr_phb_properties;
+    dc->reset = spapr_phb_reset;
+}
+
+static const TypeInfo spapr_phb_info = {
+    .name          = TYPE_SPAPR_PCI_HOST_BRIDGE,
+    .parent        = TYPE_PCI_HOST_BRIDGE,
+    .instance_size = sizeof(sPAPRPHBState),
+    .class_init    = spapr_phb_class_init,
+};
+
+PCIHostState *spapr_create_phb(sPAPREnvironment *spapr, int index)
+{
+    DeviceState *dev;
+
+    dev = qdev_create(NULL, TYPE_SPAPR_PCI_HOST_BRIDGE);
+    qdev_prop_set_uint32(dev, "index", index);
+    qdev_init_nofail(dev);
+
+    return PCI_HOST_BRIDGE(dev);
+}
+
+/* Macros to operate with address in OF binding to PCI */
+#define b_x(x, p, l)    (((x) & ((1<<(l))-1)) << (p))
+#define b_n(x)          b_x((x), 31, 1) /* 0 if relocatable */
+#define b_p(x)          b_x((x), 30, 1) /* 1 if prefetchable */
+#define b_t(x)          b_x((x), 29, 1) /* 1 if the address is aliased */
+#define b_ss(x)         b_x((x), 24, 2) /* the space code */
+#define b_bbbbbbbb(x)   b_x((x), 16, 8) /* bus number */
+#define b_ddddd(x)      b_x((x), 11, 5) /* device number */
+#define b_fff(x)        b_x((x), 8, 3)  /* function number */
+#define b_rrrrrrrr(x)   b_x((x), 0, 8)  /* register number */
+
+int spapr_populate_pci_dt(sPAPRPHBState *phb,
+                          uint32_t xics_phandle,
+                          void *fdt)
+{
+    int bus_off, i, j;
+    char nodename[256];
+    uint32_t bus_range[] = { cpu_to_be32(0), cpu_to_be32(0xff) };
+    struct {
+        uint32_t hi;
+        uint64_t child;
+        uint64_t parent;
+        uint64_t size;
+    } QEMU_PACKED ranges[] = {
+        {
+            cpu_to_be32(b_ss(1)), cpu_to_be64(0),
+            cpu_to_be64(phb->io_win_addr),
+            cpu_to_be64(memory_region_size(&phb->iospace)),
+        },
+        {
+            cpu_to_be32(b_ss(2)), cpu_to_be64(SPAPR_PCI_MEM_WIN_BUS_OFFSET),
+            cpu_to_be64(phb->mem_win_addr),
+            cpu_to_be64(memory_region_size(&phb->memwindow)),
+        },
+    };
+    uint64_t bus_reg[] = { cpu_to_be64(phb->buid), 0 };
+    uint32_t interrupt_map_mask[] = {
+        cpu_to_be32(b_ddddd(-1)|b_fff(0)), 0x0, 0x0, cpu_to_be32(-1)};
+    uint32_t interrupt_map[PCI_SLOT_MAX * PCI_NUM_PINS][7];
+
+    /* Start populating the FDT */
+    sprintf(nodename, "pci@%" PRIx64, phb->buid);
+    bus_off = fdt_add_subnode(fdt, 0, nodename);
+    if (bus_off < 0) {
+        return bus_off;
+    }
+
+#define _FDT(exp) \
+    do { \
+        int ret = (exp);                                           \
+        if (ret < 0) {                                             \
+            return ret;                                            \
+        }                                                          \
+    } while (0)
+
+    /* Write PHB properties */
+    _FDT(fdt_setprop_string(fdt, bus_off, "device_type", "pci"));
+    _FDT(fdt_setprop_string(fdt, bus_off, "compatible", "IBM,Logical_PHB"));
+    _FDT(fdt_setprop_cell(fdt, bus_off, "#address-cells", 0x3));
+    _FDT(fdt_setprop_cell(fdt, bus_off, "#size-cells", 0x2));
+    _FDT(fdt_setprop_cell(fdt, bus_off, "#interrupt-cells", 0x1));
+    _FDT(fdt_setprop(fdt, bus_off, "used-by-rtas", NULL, 0));
+    _FDT(fdt_setprop(fdt, bus_off, "bus-range", &bus_range, sizeof(bus_range)));
+    _FDT(fdt_setprop(fdt, bus_off, "ranges", &ranges, sizeof(ranges)));
+    _FDT(fdt_setprop(fdt, bus_off, "reg", &bus_reg, sizeof(bus_reg)));
+    _FDT(fdt_setprop_cell(fdt, bus_off, "ibm,pci-config-space-type", 0x1));
+
+    /* Build the interrupt-map, this must matches what is done
+     * in pci_spapr_map_irq
+     */
+    _FDT(fdt_setprop(fdt, bus_off, "interrupt-map-mask",
+                     &interrupt_map_mask, sizeof(interrupt_map_mask)));
+    for (i = 0; i < PCI_SLOT_MAX; i++) {
+        for (j = 0; j < PCI_NUM_PINS; j++) {
+            uint32_t *irqmap = interrupt_map[i*PCI_NUM_PINS + j];
+            int lsi_num = pci_spapr_swizzle(i, j);
+
+            irqmap[0] = cpu_to_be32(b_ddddd(i)|b_fff(0));
+            irqmap[1] = 0;
+            irqmap[2] = 0;
+            irqmap[3] = cpu_to_be32(j+1);
+            irqmap[4] = cpu_to_be32(xics_phandle);
+            irqmap[5] = cpu_to_be32(phb->lsi_table[lsi_num].irq);
+            irqmap[6] = cpu_to_be32(0x8);
+        }
+    }
+    /* Write interrupt map */
+    _FDT(fdt_setprop(fdt, bus_off, "interrupt-map", &interrupt_map,
+                     sizeof(interrupt_map)));
+
+    spapr_dma_dt(fdt, bus_off, "ibm,dma-window",
+                 phb->dma_liobn, phb->dma_window_start,
+                 phb->dma_window_size);
+
+    return 0;
+}
+
+void spapr_pci_rtas_init(void)
+{
+    spapr_rtas_register("read-pci-config", rtas_read_pci_config);
+    spapr_rtas_register("write-pci-config", rtas_write_pci_config);
+    spapr_rtas_register("ibm,read-pci-config", rtas_ibm_read_pci_config);
+    spapr_rtas_register("ibm,write-pci-config", rtas_ibm_write_pci_config);
+    if (msi_supported) {
+        spapr_rtas_register("ibm,query-interrupt-source-number",
+                            rtas_ibm_query_interrupt_source_number);
+        spapr_rtas_register("ibm,change-msi", rtas_ibm_change_msi);
+    }
+}
+
+static void spapr_pci_register_types(void)
+{
+    type_register_static(&spapr_phb_info);
+}
+
+type_init(spapr_pci_register_types)
index a24e853d4defec388cf667324009bc869e146869..b71b59c5cf9163bfdbba417808e4b80f933174ce 100644 (file)
@@ -30,8 +30,8 @@
 #include "hw/qdev.h"
 #include "sysemu/device_tree.h"
 
-#include "hw/spapr.h"
-#include "hw/spapr_vio.h"
+#include "hw/ppc/spapr.h"
+#include "hw/ppc/spapr_vio.h"
 
 #include <libfdt.h>
 
index 6eb3ab54824b3de29d9ec42bb7dfb90f1a8ec4ef..4dbc31541bccb0a365ae350cd16ac50c5695dc7c 100644 (file)
@@ -30,9 +30,9 @@
 #include "sysemu/device_tree.h"
 #include "kvm_ppc.h"
 
-#include "hw/spapr.h"
-#include "hw/spapr_vio.h"
-#include "hw/xics.h"
+#include "hw/ppc/spapr.h"
+#include "hw/ppc/spapr_vio.h"
+#include "hw/ppc/xics.h"
 
 #ifdef CONFIG_FDT
 #include <libfdt.h>
index 41eab1697ce3233fdc8999e335cbe1def05663cc..92b43947f74aaa1d80c3162e6d8d7316b89e604a 100644 (file)
 
 #include "hw/sysbus.h"
 #include "hw/hw.h"
-#include "hw/serial.h"
-#include "hw/flash.h"
+#include "hw/char/serial.h"
+#include "hw/block/flash.h"
 #include "sysemu/sysemu.h"
-#include "hw/devices.h"
+#include "hw/arm/devices.h"
 #include "hw/boards.h"
 #include "sysemu/device_tree.h"
 #include "hw/loader.h"
@@ -35,9 +35,9 @@
 #include "qemu/log.h"
 #include "exec/address-spaces.h"
 
-#include "hw/ppc.h"
-#include "hw/ppc4xx.h"
-#include "hw/ppc405.h"
+#include "hw/ppc/ppc.h"
+#include "hw/ppc/ppc4xx.h"
+#include "ppc405.h"
 
 #include "sysemu/blockdev.h"
 #include "hw/xilinx.h"
index 374da5bbfdbf6059a075d0b0881b83b93bab5d34..8e1e85edfda88dbcca0c858d565ce5405bc63321 100644 (file)
@@ -27,8 +27,8 @@
 
 #include "hw/hw.h"
 #include "trace.h"
-#include "hw/spapr.h"
-#include "hw/xics.h"
+#include "hw/ppc/spapr.h"
+#include "hw/ppc/xics.h"
 
 /*
  * ICP: Presentation layer
diff --git a/hw/ppc405.h b/hw/ppc405.h
deleted file mode 100644 (file)
index 45c2159..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * QEMU PowerPC 405 shared definitions
- *
- * Copyright (c) 2007 Jocelyn Mayer
- *
- * 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 !defined(PPC_405_H)
-#define PPC_405_H
-
-#include "hw/ppc4xx.h"
-
-/* Bootinfo as set-up by u-boot */
-typedef struct ppc4xx_bd_info_t ppc4xx_bd_info_t;
-struct ppc4xx_bd_info_t {
-    uint32_t bi_memstart;
-    uint32_t bi_memsize;
-    uint32_t bi_flashstart;
-    uint32_t bi_flashsize;
-    uint32_t bi_flashoffset; /* 0x10 */
-    uint32_t bi_sramstart;
-    uint32_t bi_sramsize;
-    uint32_t bi_bootflags;
-    uint32_t bi_ipaddr; /* 0x20 */
-    uint8_t  bi_enetaddr[6];
-    uint16_t bi_ethspeed;
-    uint32_t bi_intfreq;
-    uint32_t bi_busfreq; /* 0x30 */
-    uint32_t bi_baudrate;
-    uint8_t  bi_s_version[4];
-    uint8_t  bi_r_version[32];
-    uint32_t bi_procfreq;
-    uint32_t bi_plb_busfreq;
-    uint32_t bi_pci_busfreq;
-    uint8_t  bi_pci_enetaddr[6];
-    uint32_t bi_pci_enetaddr2[6];
-    uint32_t bi_opbfreq;
-    uint32_t bi_iic_fast[2];
-};
-
-/* PowerPC 405 core */
-ram_addr_t ppc405_set_bootinfo (CPUPPCState *env, ppc4xx_bd_info_t *bd,
-                                uint32_t flags);
-
-CPUPPCState *ppc405cr_init(MemoryRegion *address_space_mem,
-                        MemoryRegion ram_memories[4],
-                        hwaddr ram_bases[4],
-                        hwaddr ram_sizes[4],
-                        uint32_t sysclk, qemu_irq **picp,
-                        int do_init);
-CPUPPCState *ppc405ep_init(MemoryRegion *address_space_mem,
-                        MemoryRegion ram_memories[2],
-                        hwaddr ram_bases[2],
-                        hwaddr ram_sizes[2],
-                        uint32_t sysclk, qemu_irq **picp,
-                        int do_init);
-/* IBM STBxxx microcontrollers */
-CPUPPCState *ppc_stb025_init (MemoryRegion ram_memories[2],
-                           hwaddr ram_bases[2],
-                           hwaddr ram_sizes[2],
-                           uint32_t sysclk, qemu_irq **picp,
-                           ram_addr_t *offsetp);
-
-#endif /* !defined(PPC_405_H) */
diff --git a/hw/ppc4xx.h b/hw/ppc4xx.h
deleted file mode 100644 (file)
index 91d84ba..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * QEMU PowerPC 4xx emulation shared definitions
- *
- * Copyright (c) 2007 Jocelyn Mayer
- *
- * 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 !defined(PPC_4XX_H)
-#define PPC_4XX_H
-
-#include "hw/pci/pci.h"
-
-/* PowerPC 4xx core initialization */
-PowerPCCPU *ppc4xx_init(const char *cpu_model,
-                        clk_setup_t *cpu_clk, clk_setup_t *tb_clk,
-                        uint32_t sysclk);
-
-/* PowerPC 4xx universal interrupt controller */
-enum {
-    PPCUIC_OUTPUT_INT = 0,
-    PPCUIC_OUTPUT_CINT = 1,
-    PPCUIC_OUTPUT_NB,
-};
-qemu_irq *ppcuic_init (CPUPPCState *env, qemu_irq *irqs,
-                       uint32_t dcr_base, int has_ssr, int has_vr);
-
-ram_addr_t ppc4xx_sdram_adjust(ram_addr_t ram_size, int nr_banks,
-                               MemoryRegion ram_memories[],
-                               hwaddr ram_bases[],
-                               hwaddr ram_sizes[],
-                               const unsigned int sdram_bank_sizes[]);
-
-void ppc4xx_sdram_init (CPUPPCState *env, qemu_irq irq, int nbanks,
-                        MemoryRegion ram_memories[],
-                        hwaddr *ram_bases,
-                        hwaddr *ram_sizes,
-                        int do_init);
-
-#define TYPE_PPC4xx_PCI_HOST_BRIDGE "ppc4xx-pcihost"
-
-PCIBus *ppc4xx_pci_init(CPUPPCState *env, qemu_irq pci_irqs[4],
-                        hwaddr config_space,
-                        hwaddr int_ack,
-                        hwaddr special_cycle,
-                        hwaddr registers);
-
-#endif /* !defined(PPC_4XX_H) */
diff --git a/hw/ppc4xx_pci.c b/hw/ppc4xx_pci.c
deleted file mode 100644 (file)
index 854e170..0000000
+++ /dev/null
@@ -1,414 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License, version 2, as
- * published by the Free Software Foundation.
- *
- * 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/>.
- *
- * Copyright IBM Corp. 2008
- *
- * Authors: Hollis Blanchard <hollisb@us.ibm.com>
- */
-
-/* This file implements emulation of the 32-bit PCI controller found in some
- * 4xx SoCs, such as the 440EP. */
-
-#include "hw/hw.h"
-#include "hw/ppc.h"
-#include "hw/ppc4xx.h"
-#include "hw/pci/pci.h"
-#include "hw/pci/pci_host.h"
-#include "exec/address-spaces.h"
-
-#undef DEBUG
-#ifdef DEBUG
-#define DPRINTF(fmt, ...) do { printf(fmt, ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...)
-#endif /* DEBUG */
-
-struct PCIMasterMap {
-    uint32_t la;
-    uint32_t ma;
-    uint32_t pcila;
-    uint32_t pciha;
-};
-
-struct PCITargetMap {
-    uint32_t ms;
-    uint32_t la;
-};
-
-#define PPC4xx_PCI_HOST_BRIDGE(obj) \
-    OBJECT_CHECK(PPC4xxPCIState, (obj), TYPE_PPC4xx_PCI_HOST_BRIDGE)
-
-#define PPC4xx_PCI_NR_PMMS 3
-#define PPC4xx_PCI_NR_PTMS 2
-
-struct PPC4xxPCIState {
-    PCIHostState parent_obj;
-
-    struct PCIMasterMap pmm[PPC4xx_PCI_NR_PMMS];
-    struct PCITargetMap ptm[PPC4xx_PCI_NR_PTMS];
-    qemu_irq irq[4];
-
-    MemoryRegion container;
-    MemoryRegion iomem;
-};
-typedef struct PPC4xxPCIState PPC4xxPCIState;
-
-#define PCIC0_CFGADDR       0x0
-#define PCIC0_CFGDATA       0x4
-
-/* PLB Memory Map (PMM) registers specify which PLB addresses are translated to
- * PCI accesses. */
-#define PCIL0_PMM0LA        0x0
-#define PCIL0_PMM0MA        0x4
-#define PCIL0_PMM0PCILA     0x8
-#define PCIL0_PMM0PCIHA     0xc
-#define PCIL0_PMM1LA        0x10
-#define PCIL0_PMM1MA        0x14
-#define PCIL0_PMM1PCILA     0x18
-#define PCIL0_PMM1PCIHA     0x1c
-#define PCIL0_PMM2LA        0x20
-#define PCIL0_PMM2MA        0x24
-#define PCIL0_PMM2PCILA     0x28
-#define PCIL0_PMM2PCIHA     0x2c
-
-/* PCI Target Map (PTM) registers specify which PCI addresses are translated to
- * PLB accesses. */
-#define PCIL0_PTM1MS        0x30
-#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, hwaddr addr,
-                                    unsigned size)
-{
-    PPC4xxPCIState *ppc4xx_pci = opaque;
-    PCIHostState *phb = PCI_HOST_BRIDGE(ppc4xx_pci);
-
-    return phb->config_reg;
-}
-
-static void pci4xx_cfgaddr_write(void *opaque, hwaddr addr,
-                                  uint64_t value, unsigned size)
-{
-    PPC4xxPCIState *ppc4xx_pci = opaque;
-    PCIHostState *phb = PCI_HOST_BRIDGE(ppc4xx_pci);
-
-    phb->config_reg = value & ~0x3;
-}
-
-static const MemoryRegionOps pci4xx_cfgaddr_ops = {
-    .read = pci4xx_cfgaddr_read,
-    .write = pci4xx_cfgaddr_write,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static void ppc4xx_pci_reg_write4(void *opaque, hwaddr offset,
-                                  uint64_t value, unsigned size)
-{
-    struct PPC4xxPCIState *pci = opaque;
-
-    /* We ignore all target attempts at PCI configuration, effectively
-     * assuming a bidirectional 1:1 mapping of PLB and PCI space. */
-
-    switch (offset) {
-    case PCIL0_PMM0LA:
-        pci->pmm[0].la = value;
-        break;
-    case PCIL0_PMM0MA:
-        pci->pmm[0].ma = value;
-        break;
-    case PCIL0_PMM0PCIHA:
-        pci->pmm[0].pciha = value;
-        break;
-    case PCIL0_PMM0PCILA:
-        pci->pmm[0].pcila = value;
-        break;
-
-    case PCIL0_PMM1LA:
-        pci->pmm[1].la = value;
-        break;
-    case PCIL0_PMM1MA:
-        pci->pmm[1].ma = value;
-        break;
-    case PCIL0_PMM1PCIHA:
-        pci->pmm[1].pciha = value;
-        break;
-    case PCIL0_PMM1PCILA:
-        pci->pmm[1].pcila = value;
-        break;
-
-    case PCIL0_PMM2LA:
-        pci->pmm[2].la = value;
-        break;
-    case PCIL0_PMM2MA:
-        pci->pmm[2].ma = value;
-        break;
-    case PCIL0_PMM2PCIHA:
-        pci->pmm[2].pciha = value;
-        break;
-    case PCIL0_PMM2PCILA:
-        pci->pmm[2].pcila = value;
-        break;
-
-    case PCIL0_PTM1MS:
-        pci->ptm[0].ms = value;
-        break;
-    case PCIL0_PTM1LA:
-        pci->ptm[0].la = value;
-        break;
-    case PCIL0_PTM2MS:
-        pci->ptm[1].ms = value;
-        break;
-    case PCIL0_PTM2LA:
-        pci->ptm[1].la = value;
-        break;
-
-    default:
-        printf("%s: unhandled PCI internal register 0x%lx\n", __func__,
-               (unsigned long)offset);
-        break;
-    }
-}
-
-static uint64_t ppc4xx_pci_reg_read4(void *opaque, hwaddr offset,
-                                     unsigned size)
-{
-    struct PPC4xxPCIState *pci = opaque;
-    uint32_t value;
-
-    switch (offset) {
-    case PCIL0_PMM0LA:
-        value = pci->pmm[0].la;
-        break;
-    case PCIL0_PMM0MA:
-        value = pci->pmm[0].ma;
-        break;
-    case PCIL0_PMM0PCIHA:
-        value = pci->pmm[0].pciha;
-        break;
-    case PCIL0_PMM0PCILA:
-        value = pci->pmm[0].pcila;
-        break;
-
-    case PCIL0_PMM1LA:
-        value = pci->pmm[1].la;
-        break;
-    case PCIL0_PMM1MA:
-        value = pci->pmm[1].ma;
-        break;
-    case PCIL0_PMM1PCIHA:
-        value = pci->pmm[1].pciha;
-        break;
-    case PCIL0_PMM1PCILA:
-        value = pci->pmm[1].pcila;
-        break;
-
-    case PCIL0_PMM2LA:
-        value = pci->pmm[2].la;
-        break;
-    case PCIL0_PMM2MA:
-        value = pci->pmm[2].ma;
-        break;
-    case PCIL0_PMM2PCIHA:
-        value = pci->pmm[2].pciha;
-        break;
-    case PCIL0_PMM2PCILA:
-        value = pci->pmm[2].pcila;
-        break;
-
-    case PCIL0_PTM1MS:
-        value = pci->ptm[0].ms;
-        break;
-    case PCIL0_PTM1LA:
-        value = pci->ptm[0].la;
-        break;
-    case PCIL0_PTM2MS:
-        value = pci->ptm[1].ms;
-        break;
-    case PCIL0_PTM2LA:
-        value = pci->ptm[1].la;
-        break;
-
-    default:
-        printf("%s: invalid PCI internal register 0x%lx\n", __func__,
-               (unsigned long)offset);
-        value = 0;
-    }
-
-    return value;
-}
-
-static const MemoryRegionOps pci_reg_ops = {
-    .read = ppc4xx_pci_reg_read4,
-    .write = ppc4xx_pci_reg_write4,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static void ppc4xx_pci_reset(void *opaque)
-{
-    struct PPC4xxPCIState *pci = opaque;
-
-    memset(pci->pmm, 0, sizeof(pci->pmm));
-    memset(pci->ptm, 0, sizeof(pci->ptm));
-}
-
-/* On Bamboo, all pins from each slot are tied to a single board IRQ. This
- * may need further refactoring for other boards. */
-static int ppc4xx_pci_map_irq(PCIDevice *pci_dev, int irq_num)
-{
-    int slot = pci_dev->devfn >> 3;
-
-    DPRINTF("%s: devfn %x irq %d -> %d\n", __func__,
-            pci_dev->devfn, irq_num, slot);
-
-    return slot - 1;
-}
-
-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);
-}
-
-static const VMStateDescription vmstate_pci_master_map = {
-    .name = "pci_master_map",
-    .version_id = 0,
-    .minimum_version_id = 0,
-    .minimum_version_id_old = 0,
-    .fields      = (VMStateField[]) {
-        VMSTATE_UINT32(la, struct PCIMasterMap),
-        VMSTATE_UINT32(ma, struct PCIMasterMap),
-        VMSTATE_UINT32(pcila, struct PCIMasterMap),
-        VMSTATE_UINT32(pciha, struct PCIMasterMap),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static const VMStateDescription vmstate_pci_target_map = {
-    .name = "pci_target_map",
-    .version_id = 0,
-    .minimum_version_id = 0,
-    .minimum_version_id_old = 0,
-    .fields      = (VMStateField[]) {
-        VMSTATE_UINT32(ms, struct PCITargetMap),
-        VMSTATE_UINT32(la, struct PCITargetMap),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static const VMStateDescription vmstate_ppc4xx_pci = {
-    .name = "ppc4xx_pci",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField[]) {
-        VMSTATE_STRUCT_ARRAY(pmm, PPC4xxPCIState, PPC4xx_PCI_NR_PMMS, 1,
-                             vmstate_pci_master_map,
-                             struct PCIMasterMap),
-        VMSTATE_STRUCT_ARRAY(ptm, PPC4xxPCIState, PPC4xx_PCI_NR_PTMS, 1,
-                             vmstate_pci_target_map,
-                             struct PCITargetMap),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-/* XXX Interrupt acknowledge cycles not supported. */
-static int ppc4xx_pcihost_initfn(SysBusDevice *dev)
-{
-    PPC4xxPCIState *s;
-    PCIHostState *h;
-    PCIBus *b;
-    int i;
-
-    h = PCI_HOST_BRIDGE(dev);
-    s = PPC4xx_PCI_HOST_BRIDGE(dev);
-
-    for (i = 0; i < ARRAY_SIZE(s->irq); i++) {
-        sysbus_init_irq(dev, &s->irq[i]);
-    }
-
-    b = pci_register_bus(DEVICE(dev), NULL, ppc4xx_pci_set_irq,
-                         ppc4xx_pci_map_irq, s->irq, get_system_memory(),
-                         get_system_io(), 0, 4, TYPE_PCI_BUS);
-    h->bus = b;
-
-    pci_create_simple(b, 0, "ppc4xx-host-bridge");
-
-    /* XXX split into 2 memory regions, one for config space, one for regs */
-    memory_region_init(&s->container, "pci-container", PCI_ALL_SIZE);
-    memory_region_init_io(&h->conf_mem, &pci_host_conf_le_ops, h,
-                          "pci-conf-idx", 4);
-    memory_region_init_io(&h->data_mem, &pci_host_data_le_ops, h,
-                          "pci-conf-data", 4);
-    memory_region_init_io(&s->iomem, &pci_reg_ops, s,
-                          "pci.reg", PCI_REG_SIZE);
-    memory_region_add_subregion(&s->container, PCIC0_CFGADDR, &h->conf_mem);
-    memory_region_add_subregion(&s->container, PCIC0_CFGDATA, &h->data_mem);
-    memory_region_add_subregion(&s->container, PCI_REG_BASE, &s->iomem);
-    sysbus_init_mmio(dev, &s->container);
-    qemu_register_reset(ppc4xx_pci_reset, s);
-
-    return 0;
-}
-
-static void ppc4xx_host_bridge_class_init(ObjectClass *klass, void *data)
-{
-    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-    DeviceClass *dc = DEVICE_CLASS(klass);
-
-    dc->desc        = "Host bridge";
-    k->vendor_id    = PCI_VENDOR_ID_IBM;
-    k->device_id    = PCI_DEVICE_ID_IBM_440GX;
-    k->class_id     = PCI_CLASS_BRIDGE_OTHER;
-}
-
-static const 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 const TypeInfo ppc4xx_pcihost_info = {
-    .name          = TYPE_PPC4xx_PCI_HOST_BRIDGE,
-    .parent        = TYPE_PCI_HOST_BRIDGE,
-    .instance_size = sizeof(PPC4xxPCIState),
-    .class_init    = ppc4xx_pcihost_class_init,
-};
-
-static void ppc4xx_pci_register_types(void)
-{
-    type_register_static(&ppc4xx_pcihost_info);
-    type_register_static(&ppc4xx_host_bridge_info);
-}
-
-type_init(ppc4xx_pci_register_types)
diff --git a/hw/ppce500_pci.c b/hw/ppce500_pci.c
deleted file mode 100644 (file)
index abc7ebe..0000000
+++ /dev/null
@@ -1,427 +0,0 @@
-/*
- * QEMU PowerPC E500 embedded processors pci controller emulation
- *
- * Copyright (C) 2009 Freescale Semiconductor, Inc. All rights reserved.
- *
- * Author: Yu Liu,     <yu.liu@freescale.com>
- *
- * This file is derived from hw/ppc4xx_pci.c,
- * the copyright for that material belongs to the original owners.
- *
- * This 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.
- */
-
-#include "hw/hw.h"
-#include "hw/ppc/e500-ccsr.h"
-#include "hw/pci/pci.h"
-#include "hw/pci/pci_host.h"
-#include "qemu/bswap.h"
-#include "hw/ppce500_pci.h"
-
-#ifdef DEBUG_PCI
-#define pci_debug(fmt, ...) fprintf(stderr, fmt, ## __VA_ARGS__)
-#else
-#define pci_debug(fmt, ...)
-#endif
-
-#define PCIE500_CFGADDR       0x0
-#define PCIE500_CFGDATA       0x4
-#define PCIE500_REG_BASE      0xC00
-#define PCIE500_ALL_SIZE      0x1000
-#define PCIE500_REG_SIZE      (PCIE500_ALL_SIZE - PCIE500_REG_BASE)
-
-#define PCIE500_PCI_IOLEN     0x10000ULL
-
-#define PPCE500_PCI_CONFIG_ADDR         0x0
-#define PPCE500_PCI_CONFIG_DATA         0x4
-#define PPCE500_PCI_INTACK              0x8
-
-#define PPCE500_PCI_OW1                 (0xC20 - PCIE500_REG_BASE)
-#define PPCE500_PCI_OW2                 (0xC40 - PCIE500_REG_BASE)
-#define PPCE500_PCI_OW3                 (0xC60 - PCIE500_REG_BASE)
-#define PPCE500_PCI_OW4                 (0xC80 - PCIE500_REG_BASE)
-#define PPCE500_PCI_IW3                 (0xDA0 - PCIE500_REG_BASE)
-#define PPCE500_PCI_IW2                 (0xDC0 - PCIE500_REG_BASE)
-#define PPCE500_PCI_IW1                 (0xDE0 - PCIE500_REG_BASE)
-
-#define PPCE500_PCI_GASKET_TIMR         (0xE20 - PCIE500_REG_BASE)
-
-#define PCI_POTAR               0x0
-#define PCI_POTEAR              0x4
-#define PCI_POWBAR              0x8
-#define PCI_POWAR               0x10
-
-#define PCI_PITAR               0x0
-#define PCI_PIWBAR              0x8
-#define PCI_PIWBEAR             0xC
-#define PCI_PIWAR               0x10
-
-#define PPCE500_PCI_NR_POBS     5
-#define PPCE500_PCI_NR_PIBS     3
-
-struct  pci_outbound {
-    uint32_t potar;
-    uint32_t potear;
-    uint32_t powbar;
-    uint32_t powar;
-};
-
-struct pci_inbound {
-    uint32_t pitar;
-    uint32_t piwbar;
-    uint32_t piwbear;
-    uint32_t piwar;
-};
-
-#define TYPE_PPC_E500_PCI_HOST_BRIDGE "e500-pcihost"
-
-#define PPC_E500_PCI_HOST_BRIDGE(obj) \
-    OBJECT_CHECK(PPCE500PCIState, (obj), TYPE_PPC_E500_PCI_HOST_BRIDGE)
-
-struct PPCE500PCIState {
-    PCIHostState parent_obj;
-
-    struct pci_outbound pob[PPCE500_PCI_NR_POBS];
-    struct pci_inbound pib[PPCE500_PCI_NR_PIBS];
-    uint32_t gasket_time;
-    qemu_irq irq[4];
-    uint32_t first_slot;
-    /* mmio maps */
-    MemoryRegion container;
-    MemoryRegion iomem;
-    MemoryRegion pio;
-};
-
-#define TYPE_PPC_E500_PCI_BRIDGE "e500-host-bridge"
-#define PPC_E500_PCI_BRIDGE(obj) \
-    OBJECT_CHECK(PPCE500PCIBridgeState, (obj), TYPE_PPC_E500_PCI_BRIDGE)
-
-struct PPCE500PCIBridgeState {
-    /*< private >*/
-    PCIDevice parent;
-    /*< public >*/
-
-    MemoryRegion bar0;
-};
-
-typedef struct PPCE500PCIBridgeState PPCE500PCIBridgeState;
-typedef struct PPCE500PCIState PPCE500PCIState;
-
-static uint64_t pci_reg_read4(void *opaque, hwaddr addr,
-                              unsigned size)
-{
-    PPCE500PCIState *pci = opaque;
-    unsigned long win;
-    uint32_t value = 0;
-    int idx;
-
-    win = addr & 0xfe0;
-
-    switch (win) {
-    case PPCE500_PCI_OW1:
-    case PPCE500_PCI_OW2:
-    case PPCE500_PCI_OW3:
-    case PPCE500_PCI_OW4:
-        idx = (addr >> 5) & 0x7;
-        switch (addr & 0xC) {
-        case PCI_POTAR:
-            value = pci->pob[idx].potar;
-            break;
-        case PCI_POTEAR:
-            value = pci->pob[idx].potear;
-            break;
-        case PCI_POWBAR:
-            value = pci->pob[idx].powbar;
-            break;
-        case PCI_POWAR:
-            value = pci->pob[idx].powar;
-            break;
-        default:
-            break;
-        }
-        break;
-
-    case PPCE500_PCI_IW3:
-    case PPCE500_PCI_IW2:
-    case PPCE500_PCI_IW1:
-        idx = ((addr >> 5) & 0x3) - 1;
-        switch (addr & 0xC) {
-        case PCI_PITAR:
-            value = pci->pib[idx].pitar;
-            break;
-        case PCI_PIWBAR:
-            value = pci->pib[idx].piwbar;
-            break;
-        case PCI_PIWBEAR:
-            value = pci->pib[idx].piwbear;
-            break;
-        case PCI_PIWAR:
-            value = pci->pib[idx].piwar;
-            break;
-        default:
-            break;
-        };
-        break;
-
-    case PPCE500_PCI_GASKET_TIMR:
-        value = pci->gasket_time;
-        break;
-
-    default:
-        break;
-    }
-
-    pci_debug("%s: win:%lx(addr:" TARGET_FMT_plx ") -> value:%x\n", __func__,
-              win, addr, value);
-    return value;
-}
-
-static void pci_reg_write4(void *opaque, hwaddr addr,
-                           uint64_t value, unsigned size)
-{
-    PPCE500PCIState *pci = opaque;
-    unsigned long win;
-    int idx;
-
-    win = addr & 0xfe0;
-
-    pci_debug("%s: value:%x -> win:%lx(addr:" TARGET_FMT_plx ")\n",
-              __func__, (unsigned)value, win, addr);
-
-    switch (win) {
-    case PPCE500_PCI_OW1:
-    case PPCE500_PCI_OW2:
-    case PPCE500_PCI_OW3:
-    case PPCE500_PCI_OW4:
-        idx = (addr >> 5) & 0x7;
-        switch (addr & 0xC) {
-        case PCI_POTAR:
-            pci->pob[idx].potar = value;
-            break;
-        case PCI_POTEAR:
-            pci->pob[idx].potear = value;
-            break;
-        case PCI_POWBAR:
-            pci->pob[idx].powbar = value;
-            break;
-        case PCI_POWAR:
-            pci->pob[idx].powar = value;
-            break;
-        default:
-            break;
-        };
-        break;
-
-    case PPCE500_PCI_IW3:
-    case PPCE500_PCI_IW2:
-    case PPCE500_PCI_IW1:
-        idx = ((addr >> 5) & 0x3) - 1;
-        switch (addr & 0xC) {
-        case PCI_PITAR:
-            pci->pib[idx].pitar = value;
-            break;
-        case PCI_PIWBAR:
-            pci->pib[idx].piwbar = value;
-            break;
-        case PCI_PIWBEAR:
-            pci->pib[idx].piwbear = value;
-            break;
-        case PCI_PIWAR:
-            pci->pib[idx].piwar = value;
-            break;
-        default:
-            break;
-        };
-        break;
-
-    case PPCE500_PCI_GASKET_TIMR:
-        pci->gasket_time = value;
-        break;
-
-    default:
-        break;
-    };
-}
-
-static const MemoryRegionOps e500_pci_reg_ops = {
-    .read = pci_reg_read4,
-    .write = pci_reg_write4,
-    .endianness = DEVICE_BIG_ENDIAN,
-};
-
-static int mpc85xx_pci_map_irq(PCIDevice *pci_dev, int irq_num)
-{
-    int devno = pci_dev->devfn >> 3;
-    int ret;
-
-    ret = ppce500_pci_map_irq_slot(devno, irq_num);
-
-    pci_debug("%s: devfn %x irq %d -> %d  devno:%x\n", __func__,
-           pci_dev->devfn, irq_num, ret, devno);
-
-    return ret;
-}
-
-static void mpc85xx_pci_set_irq(void *opaque, int irq_num, int level)
-{
-    qemu_irq *pic = opaque;
-
-    pci_debug("%s: PCI irq %d, level:%d\n", __func__, irq_num, level);
-
-    qemu_set_irq(pic[irq_num], level);
-}
-
-static const VMStateDescription vmstate_pci_outbound = {
-    .name = "pci_outbound",
-    .version_id = 0,
-    .minimum_version_id = 0,
-    .minimum_version_id_old = 0,
-    .fields      = (VMStateField[]) {
-        VMSTATE_UINT32(potar, struct pci_outbound),
-        VMSTATE_UINT32(potear, struct pci_outbound),
-        VMSTATE_UINT32(powbar, struct pci_outbound),
-        VMSTATE_UINT32(powar, struct pci_outbound),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static const VMStateDescription vmstate_pci_inbound = {
-    .name = "pci_inbound",
-    .version_id = 0,
-    .minimum_version_id = 0,
-    .minimum_version_id_old = 0,
-    .fields      = (VMStateField[]) {
-        VMSTATE_UINT32(pitar, struct pci_inbound),
-        VMSTATE_UINT32(piwbar, struct pci_inbound),
-        VMSTATE_UINT32(piwbear, struct pci_inbound),
-        VMSTATE_UINT32(piwar, struct pci_inbound),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static const VMStateDescription vmstate_ppce500_pci = {
-    .name = "ppce500_pci",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField[]) {
-        VMSTATE_STRUCT_ARRAY(pob, PPCE500PCIState, PPCE500_PCI_NR_POBS, 1,
-                             vmstate_pci_outbound, struct pci_outbound),
-        VMSTATE_STRUCT_ARRAY(pib, PPCE500PCIState, PPCE500_PCI_NR_PIBS, 1,
-                             vmstate_pci_outbound, struct pci_inbound),
-        VMSTATE_UINT32(gasket_time, PPCE500PCIState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-#include "exec/address-spaces.h"
-
-static int e500_pcihost_bridge_initfn(PCIDevice *d)
-{
-    PPCE500PCIBridgeState *b = PPC_E500_PCI_BRIDGE(d);
-    PPCE500CCSRState *ccsr = CCSR(container_get(qdev_get_machine(),
-                                  "/e500-ccsr"));
-
-    pci_config_set_class(d->config, PCI_CLASS_BRIDGE_PCI);
-    d->config[PCI_HEADER_TYPE] =
-        (d->config[PCI_HEADER_TYPE] & PCI_HEADER_TYPE_MULTI_FUNCTION) |
-        PCI_HEADER_TYPE_BRIDGE;
-
-    memory_region_init_alias(&b->bar0, "e500-pci-bar0", &ccsr->ccsr_space,
-                             0, int128_get64(ccsr->ccsr_space.size));
-    pci_register_bar(d, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &b->bar0);
-
-    return 0;
-}
-
-static int e500_pcihost_initfn(SysBusDevice *dev)
-{
-    PCIHostState *h;
-    PPCE500PCIState *s;
-    PCIBus *b;
-    int i;
-    MemoryRegion *address_space_mem = get_system_memory();
-
-    h = PCI_HOST_BRIDGE(dev);
-    s = PPC_E500_PCI_HOST_BRIDGE(dev);
-
-    for (i = 0; i < ARRAY_SIZE(s->irq); i++) {
-        sysbus_init_irq(dev, &s->irq[i]);
-    }
-
-    memory_region_init(&s->pio, "pci-pio", PCIE500_PCI_IOLEN);
-
-    b = pci_register_bus(DEVICE(dev), NULL, mpc85xx_pci_set_irq,
-                         mpc85xx_pci_map_irq, s->irq, address_space_mem,
-                         &s->pio, PCI_DEVFN(s->first_slot, 0), 4, TYPE_PCI_BUS);
-    h->bus = b;
-
-    pci_create_simple(b, 0, "e500-host-bridge");
-
-    memory_region_init(&s->container, "pci-container", PCIE500_ALL_SIZE);
-    memory_region_init_io(&h->conf_mem, &pci_host_conf_be_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, &e500_pci_reg_ops, s,
-                          "pci.reg", PCIE500_REG_SIZE);
-    memory_region_add_subregion(&s->container, PCIE500_CFGADDR, &h->conf_mem);
-    memory_region_add_subregion(&s->container, PCIE500_CFGDATA, &h->data_mem);
-    memory_region_add_subregion(&s->container, PCIE500_REG_BASE, &s->iomem);
-    sysbus_init_mmio(dev, &s->container);
-    sysbus_init_mmio(dev, &s->pio);
-
-    return 0;
-}
-
-static void e500_host_bridge_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
-    k->init = e500_pcihost_bridge_initfn;
-    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 const TypeInfo e500_host_bridge_info = {
-    .name          = "e500-host-bridge",
-    .parent        = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(PPCE500PCIBridgeState),
-    .class_init    = e500_host_bridge_class_init,
-};
-
-static Property pcihost_properties[] = {
-    DEFINE_PROP_UINT32("first_slot", PPCE500PCIState, first_slot, 0x11),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-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->props = pcihost_properties;
-    dc->vmsd = &vmstate_ppce500_pci;
-}
-
-static const TypeInfo e500_pcihost_info = {
-    .name          = TYPE_PPC_E500_PCI_HOST_BRIDGE,
-    .parent        = TYPE_PCI_HOST_BRIDGE,
-    .instance_size = sizeof(PPCE500PCIState),
-    .class_init    = e500_pcihost_class_init,
-};
-
-static void e500_pci_register_types(void)
-{
-    type_register_static(&e500_pcihost_info);
-    type_register_static(&e500_host_bridge_info);
-}
-
-type_init(e500_pci_register_types)
diff --git a/hw/ppce500_pci.h b/hw/ppce500_pci.h
deleted file mode 100644 (file)
index 61f773e..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef PPCE500_PCI_H
-#define PPCE500_PCI_H
-
-static inline int ppce500_pci_map_irq_slot(int devno, int irq_num)
-{
-    return (devno + irq_num) % 4;
-}
-
-#endif
diff --git a/hw/prep_pci.c b/hw/prep_pci.c
deleted file mode 100644 (file)
index 58df245..0000000
+++ /dev/null
@@ -1,232 +0,0 @@
-/*
- * QEMU PREP PCI host
- *
- * Copyright (c) 2006 Fabrice Bellard
- * Copyright (c) 2011-2013 Andreas Färber
- *
- * 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 "hw/hw.h"
-#include "hw/pci/pci.h"
-#include "hw/pci/pci_bus.h"
-#include "hw/pci/pci_host.h"
-#include "hw/pc.h"
-#include "exec/address-spaces.h"
-
-#define TYPE_RAVEN_PCI_DEVICE "raven"
-#define TYPE_RAVEN_PCI_HOST_BRIDGE "raven-pcihost"
-
-#define RAVEN_PCI_DEVICE(obj) \
-    OBJECT_CHECK(RavenPCIState, (obj), TYPE_RAVEN_PCI_DEVICE)
-
-typedef struct RavenPCIState {
-    PCIDevice dev;
-} RavenPCIState;
-
-#define RAVEN_PCI_HOST_BRIDGE(obj) \
-    OBJECT_CHECK(PREPPCIState, (obj), TYPE_RAVEN_PCI_HOST_BRIDGE)
-
-typedef struct PRePPCIState {
-    PCIHostState parent_obj;
-
-    MemoryRegion intack;
-    qemu_irq irq[4];
-    PCIBus pci_bus;
-    RavenPCIState pci_dev;
-} PREPPCIState;
-
-static inline uint32_t PPC_PCIIO_config(hwaddr addr)
-{
-    int i;
-
-    for (i = 0; i < 11; i++) {
-        if ((addr & (1 << (11 + i))) != 0) {
-            break;
-        }
-    }
-    return (addr & 0x7ff) |  (i << 11);
-}
-
-static void ppc_pci_io_write(void *opaque, hwaddr addr,
-                             uint64_t val, unsigned int size)
-{
-    PREPPCIState *s = opaque;
-    PCIHostState *phb = PCI_HOST_BRIDGE(s);
-    pci_data_write(phb->bus, PPC_PCIIO_config(addr), val, size);
-}
-
-static uint64_t ppc_pci_io_read(void *opaque, hwaddr addr,
-                                unsigned int size)
-{
-    PREPPCIState *s = opaque;
-    PCIHostState *phb = PCI_HOST_BRIDGE(s);
-    return pci_data_read(phb->bus, PPC_PCIIO_config(addr), size);
-}
-
-static const MemoryRegionOps PPC_PCIIO_ops = {
-    .read = ppc_pci_io_read,
-    .write = ppc_pci_io_write,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static uint64_t ppc_intack_read(void *opaque, hwaddr addr,
-                                unsigned int size)
-{
-    return pic_read_irq(isa_pic);
-}
-
-static const MemoryRegionOps PPC_intack_ops = {
-    .read = ppc_intack_read,
-    .valid = {
-        .max_access_size = 1,
-    },
-};
-
-static int prep_map_irq(PCIDevice *pci_dev, int irq_num)
-{
-    return (irq_num + (pci_dev->devfn >> 3)) & 1;
-}
-
-static void prep_set_irq(void *opaque, int irq_num, int level)
-{
-    qemu_irq *pic = opaque;
-
-    qemu_set_irq(pic[irq_num] , level);
-}
-
-static void raven_pcihost_realizefn(DeviceState *d, Error **errp)
-{
-    SysBusDevice *dev = SYS_BUS_DEVICE(d);
-    PCIHostState *h = PCI_HOST_BRIDGE(dev);
-    PREPPCIState *s = RAVEN_PCI_HOST_BRIDGE(dev);
-    MemoryRegion *address_space_mem = get_system_memory();
-    int i;
-
-    for (i = 0; i < 4; i++) {
-        sysbus_init_irq(dev, &s->irq[i]);
-    }
-
-    pci_bus_irqs(&s->pci_bus, prep_set_irq, prep_map_irq, s->irq, 4);
-
-    memory_region_init_io(&h->conf_mem, &pci_host_conf_be_ops, s,
-                          "pci-conf-idx", 1);
-    sysbus_add_io(dev, 0xcf8, &h->conf_mem);
-    sysbus_init_ioports(&h->busdev, 0xcf8, 1);
-
-    memory_region_init_io(&h->data_mem, &pci_host_data_be_ops, s,
-                          "pci-conf-data", 1);
-    sysbus_add_io(dev, 0xcfc, &h->data_mem);
-    sysbus_init_ioports(&h->busdev, 0xcfc, 1);
-
-    memory_region_init_io(&h->mmcfg, &PPC_PCIIO_ops, s, "pciio", 0x00400000);
-    memory_region_add_subregion(address_space_mem, 0x80800000, &h->mmcfg);
-
-    memory_region_init_io(&s->intack, &PPC_intack_ops, s, "pci-intack", 1);
-    memory_region_add_subregion(address_space_mem, 0xbffffff0, &s->intack);
-
-    /* TODO Remove once realize propagates to child devices. */
-    object_property_set_bool(OBJECT(&s->pci_dev), true, "realized", errp);
-}
-
-static void raven_pcihost_initfn(Object *obj)
-{
-    PCIHostState *h = PCI_HOST_BRIDGE(obj);
-    PREPPCIState *s = RAVEN_PCI_HOST_BRIDGE(obj);
-    MemoryRegion *address_space_mem = get_system_memory();
-    MemoryRegion *address_space_io = get_system_io();
-    DeviceState *pci_dev;
-
-    pci_bus_new_inplace(&s->pci_bus, DEVICE(obj), NULL,
-                        address_space_mem, address_space_io, 0, TYPE_PCI_BUS);
-    h->bus = &s->pci_bus;
-
-    object_initialize(&s->pci_dev, TYPE_RAVEN_PCI_DEVICE);
-    pci_dev = DEVICE(&s->pci_dev);
-    qdev_set_parent_bus(pci_dev, BUS(&s->pci_bus));
-    object_property_set_int(OBJECT(&s->pci_dev), PCI_DEVFN(0, 0), "addr",
-                            NULL);
-    qdev_prop_set_bit(pci_dev, "multifunction", false);
-}
-
-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 0;
-}
-
-static const VMStateDescription vmstate_raven = {
-    .name = "raven",
-    .version_id = 0,
-    .minimum_version_id = 0,
-    .fields = (VMStateField[]) {
-        VMSTATE_PCI_DEVICE(dev, RavenPCIState),
-        VMSTATE_END_OF_LIST()
-    },
-};
-
-static void raven_class_init(ObjectClass *klass, void *data)
-{
-    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-    DeviceClass *dc = DEVICE_CLASS(klass);
-
-    k->init = raven_init;
-    k->vendor_id = PCI_VENDOR_ID_MOTOROLA;
-    k->device_id = PCI_DEVICE_ID_MOTOROLA_RAVEN;
-    k->revision = 0x00;
-    k->class_id = PCI_CLASS_BRIDGE_HOST;
-    dc->desc = "PReP Host Bridge - Motorola Raven";
-    dc->vmsd = &vmstate_raven;
-    dc->no_user = 1;
-}
-
-static const TypeInfo raven_info = {
-    .name = TYPE_RAVEN_PCI_DEVICE,
-    .parent = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(RavenPCIState),
-    .class_init = raven_class_init,
-};
-
-static void raven_pcihost_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-
-    dc->realize = raven_pcihost_realizefn;
-    dc->fw_name = "pci";
-    dc->no_user = 1;
-}
-
-static const TypeInfo raven_pcihost_info = {
-    .name = TYPE_RAVEN_PCI_HOST_BRIDGE,
-    .parent = TYPE_PCI_HOST_BRIDGE,
-    .instance_size = sizeof(PREPPCIState),
-    .instance_init = raven_pcihost_initfn,
-    .class_init = raven_pcihost_class_init,
-};
-
-static void raven_register_types(void)
-{
-    type_register_static(&raven_pcihost_info);
-    type_register_static(&raven_info);
-}
-
-type_init(raven_register_types)
diff --git a/hw/primecell.h b/hw/primecell.h
deleted file mode 100644 (file)
index 7337c3b..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-#ifndef PRIMECELL_H
-#define PRIMECELL_H
-
-/* Declarations for ARM PrimeCell based periperals.  */
-/* Also includes some devices that are currently only used by the
-   ARM boards.  */
-
-/* arm_sysctl GPIO lines */
-#define ARM_SYSCTL_GPIO_MMC_WPROT 0
-#define ARM_SYSCTL_GPIO_MMC_CARDIN 1
-
-#endif
diff --git a/hw/ps2.c b/hw/ps2.c
deleted file mode 100644 (file)
index 233a087..0000000
--- a/hw/ps2.c
+++ /dev/null
@@ -1,676 +0,0 @@
-/*
- * QEMU PS/2 keyboard/mouse emulation
- *
- * 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.
- */
-#include "hw/hw.h"
-#include "hw/ps2.h"
-#include "ui/console.h"
-#include "sysemu/sysemu.h"
-
-/* debug PC keyboard */
-//#define DEBUG_KBD
-
-/* debug PC keyboard : only mouse */
-//#define DEBUG_MOUSE
-
-/* Keyboard Commands */
-#define KBD_CMD_SET_LEDS       0xED    /* Set keyboard leds */
-#define KBD_CMD_ECHO           0xEE
-#define KBD_CMD_SCANCODE       0xF0    /* Get/set scancode set */
-#define KBD_CMD_GET_ID                 0xF2    /* get keyboard ID */
-#define KBD_CMD_SET_RATE       0xF3    /* Set typematic rate */
-#define KBD_CMD_ENABLE         0xF4    /* Enable scanning */
-#define KBD_CMD_RESET_DISABLE  0xF5    /* reset and disable scanning */
-#define KBD_CMD_RESET_ENABLE           0xF6    /* reset and enable scanning */
-#define KBD_CMD_RESET          0xFF    /* Reset */
-
-/* Keyboard Replies */
-#define KBD_REPLY_POR          0xAA    /* Power on reset */
-#define KBD_REPLY_ID           0xAB    /* Keyboard ID */
-#define KBD_REPLY_ACK          0xFA    /* Command ACK */
-#define KBD_REPLY_RESEND       0xFE    /* Command NACK, send the cmd again */
-
-/* Mouse Commands */
-#define AUX_SET_SCALE11                0xE6    /* Set 1:1 scaling */
-#define AUX_SET_SCALE21                0xE7    /* Set 2:1 scaling */
-#define AUX_SET_RES            0xE8    /* Set resolution */
-#define AUX_GET_SCALE          0xE9    /* Get scaling factor */
-#define AUX_SET_STREAM         0xEA    /* Set stream mode */
-#define AUX_POLL               0xEB    /* Poll */
-#define AUX_RESET_WRAP         0xEC    /* Reset wrap mode */
-#define AUX_SET_WRAP           0xEE    /* Set wrap mode */
-#define AUX_SET_REMOTE         0xF0    /* Set remote mode */
-#define AUX_GET_TYPE           0xF2    /* Get type */
-#define AUX_SET_SAMPLE         0xF3    /* Set sample rate */
-#define AUX_ENABLE_DEV         0xF4    /* Enable aux device */
-#define AUX_DISABLE_DEV                0xF5    /* Disable aux device */
-#define AUX_SET_DEFAULT                0xF6
-#define AUX_RESET              0xFF    /* Reset aux device */
-#define AUX_ACK                        0xFA    /* Command byte ACK. */
-
-#define MOUSE_STATUS_REMOTE     0x40
-#define MOUSE_STATUS_ENABLED    0x20
-#define MOUSE_STATUS_SCALE21    0x10
-
-#define PS2_QUEUE_SIZE 256
-
-typedef struct {
-    uint8_t data[PS2_QUEUE_SIZE];
-    int rptr, wptr, count;
-} PS2Queue;
-
-typedef struct {
-    PS2Queue queue;
-    int32_t write_cmd;
-    void (*update_irq)(void *, int);
-    void *update_arg;
-} PS2State;
-
-typedef struct {
-    PS2State common;
-    int scan_enabled;
-    /* QEMU uses translated PC scancodes internally.  To avoid multiple
-       conversions we do the translation (if any) in the PS/2 emulation
-       not the keyboard controller.  */
-    int translate;
-    int scancode_set; /* 1=XT, 2=AT, 3=PS/2 */
-    int ledstate;
-} PS2KbdState;
-
-typedef struct {
-    PS2State common;
-    uint8_t mouse_status;
-    uint8_t mouse_resolution;
-    uint8_t mouse_sample_rate;
-    uint8_t mouse_wrap;
-    uint8_t mouse_type; /* 0 = PS2, 3 = IMPS/2, 4 = IMEX */
-    uint8_t mouse_detect_state;
-    int mouse_dx; /* current values, needed for 'poll' mode */
-    int mouse_dy;
-    int mouse_dz;
-    uint8_t mouse_buttons;
-} PS2MouseState;
-
-/* Table to convert from PC scancodes to raw scancodes.  */
-static const unsigned char ps2_raw_keycode[128] = {
-  0, 118,  22,  30,  38,  37,  46,  54,  61,  62,  70,  69,  78,  85, 102,  13,
- 21,  29,  36,  45,  44,  53,  60,  67,  68,  77,  84,  91,  90,  20,  28,  27,
- 35,  43,  52,  51,  59,  66,  75,  76,  82,  14,  18,  93,  26,  34,  33,  42,
- 50,  49,  58,  65,  73,  74,  89, 124,  17,  41,  88,   5,   6,   4,  12,   3,
- 11,   2,  10,   1,   9, 119, 126, 108, 117, 125, 123, 107, 115, 116, 121, 105,
-114, 122, 112, 113, 127,  96,  97, 120,   7,  15,  23,  31,  39,  47,  55,  63,
- 71,  79,  86,  94,   8,  16,  24,  32,  40,  48,  56,  64,  72,  80,  87, 111,
- 19,  25,  57,  81,  83,  92,  95,  98,  99, 100, 101, 103, 104, 106, 109, 110
-};
-static const unsigned char ps2_raw_keycode_set3[128] = {
-  0,   8,  22,  30,  38,  37,  46,  54,  61,  62,  70,  69,  78,  85, 102,  13,
- 21,  29,  36,  45,  44,  53,  60,  67,  68,  77,  84,  91,  90,  17,  28,  27,
- 35,  43,  52,  51,  59,  66,  75,  76,  82,  14,  18,  92,  26,  34,  33,  42,
- 50,  49,  58,  65,  73,  74,  89, 126,  25,  41,  20,   7,  15,  23,  31,  39,
- 47,   2,  63,  71,  79, 118,  95, 108, 117, 125, 132, 107, 115, 116, 124, 105,
-114, 122, 112, 113, 127,  96,  97,  86,  94,  15,  23,  31,  39,  47,  55,  63,
- 71,  79,  86,  94,   8,  16,  24,  32,  40,  48,  56,  64,  72,  80,  87, 111,
- 19,  25,  57,  81,  83,  92,  95,  98,  99, 100, 101, 103, 104, 106, 109, 110
-};
-
-void ps2_queue(void *opaque, int b)
-{
-    PS2State *s = (PS2State *)opaque;
-    PS2Queue *q = &s->queue;
-
-    if (q->count >= PS2_QUEUE_SIZE)
-        return;
-    q->data[q->wptr] = b;
-    if (++q->wptr == PS2_QUEUE_SIZE)
-        q->wptr = 0;
-    q->count++;
-    s->update_irq(s->update_arg, 1);
-}
-
-/*
-   keycode is expressed as follow:
-   bit 7    - 0 key pressed, 1 = key released
-   bits 6-0 - translated scancode set 2
- */
-static void ps2_put_keycode(void *opaque, int keycode)
-{
-    PS2KbdState *s = opaque;
-
-    qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER);
-    /* XXX: add support for scancode set 1 */
-    if (!s->translate && keycode < 0xe0 && s->scancode_set > 1) {
-        if (keycode & 0x80) {
-            ps2_queue(&s->common, 0xf0);
-        }
-        if (s->scancode_set == 2) {
-            keycode = ps2_raw_keycode[keycode & 0x7f];
-        } else if (s->scancode_set == 3) {
-            keycode = ps2_raw_keycode_set3[keycode & 0x7f];
-        }
-      }
-    ps2_queue(&s->common, keycode);
-}
-
-uint32_t ps2_read_data(void *opaque)
-{
-    PS2State *s = (PS2State *)opaque;
-    PS2Queue *q;
-    int val, index;
-
-    q = &s->queue;
-    if (q->count == 0) {
-        /* NOTE: if no data left, we return the last keyboard one
-           (needed for EMM386) */
-        /* XXX: need a timer to do things correctly */
-        index = q->rptr - 1;
-        if (index < 0)
-            index = PS2_QUEUE_SIZE - 1;
-        val = q->data[index];
-    } else {
-        val = q->data[q->rptr];
-        if (++q->rptr == PS2_QUEUE_SIZE)
-            q->rptr = 0;
-        q->count--;
-        /* reading deasserts IRQ */
-        s->update_irq(s->update_arg, 0);
-        /* reassert IRQs if data left */
-        s->update_irq(s->update_arg, q->count != 0);
-    }
-    return val;
-}
-
-static void ps2_set_ledstate(PS2KbdState *s, int ledstate)
-{
-    s->ledstate = ledstate;
-    kbd_put_ledstate(ledstate);
-}
-
-static void ps2_reset_keyboard(PS2KbdState *s)
-{
-    s->scan_enabled = 1;
-    s->scancode_set = 2;
-    ps2_set_ledstate(s, 0);
-}
-
-void ps2_write_keyboard(void *opaque, int val)
-{
-    PS2KbdState *s = (PS2KbdState *)opaque;
-
-    switch(s->common.write_cmd) {
-    default:
-    case -1:
-        switch(val) {
-        case 0x00:
-            ps2_queue(&s->common, KBD_REPLY_ACK);
-            break;
-        case 0x05:
-            ps2_queue(&s->common, KBD_REPLY_RESEND);
-            break;
-        case KBD_CMD_GET_ID:
-            ps2_queue(&s->common, KBD_REPLY_ACK);
-            /* We emulate a MF2 AT keyboard here */
-            ps2_queue(&s->common, KBD_REPLY_ID);
-            if (s->translate)
-                ps2_queue(&s->common, 0x41);
-            else
-                ps2_queue(&s->common, 0x83);
-            break;
-        case KBD_CMD_ECHO:
-            ps2_queue(&s->common, KBD_CMD_ECHO);
-            break;
-        case KBD_CMD_ENABLE:
-            s->scan_enabled = 1;
-            ps2_queue(&s->common, KBD_REPLY_ACK);
-            break;
-        case KBD_CMD_SCANCODE:
-        case KBD_CMD_SET_LEDS:
-        case KBD_CMD_SET_RATE:
-            s->common.write_cmd = val;
-            ps2_queue(&s->common, KBD_REPLY_ACK);
-            break;
-        case KBD_CMD_RESET_DISABLE:
-            ps2_reset_keyboard(s);
-            s->scan_enabled = 0;
-            ps2_queue(&s->common, KBD_REPLY_ACK);
-            break;
-        case KBD_CMD_RESET_ENABLE:
-            ps2_reset_keyboard(s);
-            s->scan_enabled = 1;
-            ps2_queue(&s->common, KBD_REPLY_ACK);
-            break;
-        case KBD_CMD_RESET:
-            ps2_reset_keyboard(s);
-            ps2_queue(&s->common, KBD_REPLY_ACK);
-            ps2_queue(&s->common, KBD_REPLY_POR);
-            break;
-        default:
-            ps2_queue(&s->common, KBD_REPLY_ACK);
-            break;
-        }
-        break;
-    case KBD_CMD_SCANCODE:
-        if (val == 0) {
-            if (s->scancode_set == 1)
-                ps2_put_keycode(s, 0x43);
-            else if (s->scancode_set == 2)
-                ps2_put_keycode(s, 0x41);
-            else if (s->scancode_set == 3)
-                ps2_put_keycode(s, 0x3f);
-        } else {
-            if (val >= 1 && val <= 3)
-                s->scancode_set = val;
-            ps2_queue(&s->common, KBD_REPLY_ACK);
-        }
-        s->common.write_cmd = -1;
-        break;
-    case KBD_CMD_SET_LEDS:
-        ps2_set_ledstate(s, val);
-        ps2_queue(&s->common, KBD_REPLY_ACK);
-        s->common.write_cmd = -1;
-        break;
-    case KBD_CMD_SET_RATE:
-        ps2_queue(&s->common, KBD_REPLY_ACK);
-        s->common.write_cmd = -1;
-        break;
-    }
-}
-
-/* Set the scancode translation mode.
-   0 = raw scancodes.
-   1 = translated scancodes (used by qemu internally).  */
-
-void ps2_keyboard_set_translation(void *opaque, int mode)
-{
-    PS2KbdState *s = (PS2KbdState *)opaque;
-    s->translate = mode;
-}
-
-static void ps2_mouse_send_packet(PS2MouseState *s)
-{
-    unsigned int b;
-    int dx1, dy1, dz1;
-
-    dx1 = s->mouse_dx;
-    dy1 = s->mouse_dy;
-    dz1 = s->mouse_dz;
-    /* XXX: increase range to 8 bits ? */
-    if (dx1 > 127)
-        dx1 = 127;
-    else if (dx1 < -127)
-        dx1 = -127;
-    if (dy1 > 127)
-        dy1 = 127;
-    else if (dy1 < -127)
-        dy1 = -127;
-    b = 0x08 | ((dx1 < 0) << 4) | ((dy1 < 0) << 5) | (s->mouse_buttons & 0x07);
-    ps2_queue(&s->common, b);
-    ps2_queue(&s->common, dx1 & 0xff);
-    ps2_queue(&s->common, dy1 & 0xff);
-    /* extra byte for IMPS/2 or IMEX */
-    switch(s->mouse_type) {
-    default:
-        break;
-    case 3:
-        if (dz1 > 127)
-            dz1 = 127;
-        else if (dz1 < -127)
-                dz1 = -127;
-        ps2_queue(&s->common, dz1 & 0xff);
-        break;
-    case 4:
-        if (dz1 > 7)
-            dz1 = 7;
-        else if (dz1 < -7)
-            dz1 = -7;
-        b = (dz1 & 0x0f) | ((s->mouse_buttons & 0x18) << 1);
-        ps2_queue(&s->common, b);
-        break;
-    }
-
-    /* update deltas */
-    s->mouse_dx -= dx1;
-    s->mouse_dy -= dy1;
-    s->mouse_dz -= dz1;
-}
-
-static void ps2_mouse_event(void *opaque,
-                            int dx, int dy, int dz, int buttons_state)
-{
-    PS2MouseState *s = opaque;
-
-    /* check if deltas are recorded when disabled */
-    if (!(s->mouse_status & MOUSE_STATUS_ENABLED))
-        return;
-
-    s->mouse_dx += dx;
-    s->mouse_dy -= dy;
-    s->mouse_dz += dz;
-    /* XXX: SDL sometimes generates nul events: we delete them */
-    if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0 &&
-        s->mouse_buttons == buttons_state)
-       return;
-    s->mouse_buttons = buttons_state;
-
-    if (buttons_state) {
-        qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER);
-    }
-
-    if (!(s->mouse_status & MOUSE_STATUS_REMOTE) &&
-        (s->common.queue.count < (PS2_QUEUE_SIZE - 16))) {
-        for(;;) {
-            /* if not remote, send event. Multiple events are sent if
-               too big deltas */
-            ps2_mouse_send_packet(s);
-            if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0)
-                break;
-        }
-    }
-}
-
-void ps2_mouse_fake_event(void *opaque)
-{
-    ps2_mouse_event(opaque, 1, 0, 0, 0);
-}
-
-void ps2_write_mouse(void *opaque, int val)
-{
-    PS2MouseState *s = (PS2MouseState *)opaque;
-#ifdef DEBUG_MOUSE
-    printf("kbd: write mouse 0x%02x\n", val);
-#endif
-    switch(s->common.write_cmd) {
-    default:
-    case -1:
-        /* mouse command */
-        if (s->mouse_wrap) {
-            if (val == AUX_RESET_WRAP) {
-                s->mouse_wrap = 0;
-                ps2_queue(&s->common, AUX_ACK);
-                return;
-            } else if (val != AUX_RESET) {
-                ps2_queue(&s->common, val);
-                return;
-            }
-        }
-        switch(val) {
-        case AUX_SET_SCALE11:
-            s->mouse_status &= ~MOUSE_STATUS_SCALE21;
-            ps2_queue(&s->common, AUX_ACK);
-            break;
-        case AUX_SET_SCALE21:
-            s->mouse_status |= MOUSE_STATUS_SCALE21;
-            ps2_queue(&s->common, AUX_ACK);
-            break;
-        case AUX_SET_STREAM:
-            s->mouse_status &= ~MOUSE_STATUS_REMOTE;
-            ps2_queue(&s->common, AUX_ACK);
-            break;
-        case AUX_SET_WRAP:
-            s->mouse_wrap = 1;
-            ps2_queue(&s->common, AUX_ACK);
-            break;
-        case AUX_SET_REMOTE:
-            s->mouse_status |= MOUSE_STATUS_REMOTE;
-            ps2_queue(&s->common, AUX_ACK);
-            break;
-        case AUX_GET_TYPE:
-            ps2_queue(&s->common, AUX_ACK);
-            ps2_queue(&s->common, s->mouse_type);
-            break;
-        case AUX_SET_RES:
-        case AUX_SET_SAMPLE:
-            s->common.write_cmd = val;
-            ps2_queue(&s->common, AUX_ACK);
-            break;
-        case AUX_GET_SCALE:
-            ps2_queue(&s->common, AUX_ACK);
-            ps2_queue(&s->common, s->mouse_status);
-            ps2_queue(&s->common, s->mouse_resolution);
-            ps2_queue(&s->common, s->mouse_sample_rate);
-            break;
-        case AUX_POLL:
-            ps2_queue(&s->common, AUX_ACK);
-            ps2_mouse_send_packet(s);
-            break;
-        case AUX_ENABLE_DEV:
-            s->mouse_status |= MOUSE_STATUS_ENABLED;
-            ps2_queue(&s->common, AUX_ACK);
-            break;
-        case AUX_DISABLE_DEV:
-            s->mouse_status &= ~MOUSE_STATUS_ENABLED;
-            ps2_queue(&s->common, AUX_ACK);
-            break;
-        case AUX_SET_DEFAULT:
-            s->mouse_sample_rate = 100;
-            s->mouse_resolution = 2;
-            s->mouse_status = 0;
-            ps2_queue(&s->common, AUX_ACK);
-            break;
-        case AUX_RESET:
-            s->mouse_sample_rate = 100;
-            s->mouse_resolution = 2;
-            s->mouse_status = 0;
-            s->mouse_type = 0;
-            ps2_queue(&s->common, AUX_ACK);
-            ps2_queue(&s->common, 0xaa);
-            ps2_queue(&s->common, s->mouse_type);
-            break;
-        default:
-            break;
-        }
-        break;
-    case AUX_SET_SAMPLE:
-        s->mouse_sample_rate = val;
-        /* detect IMPS/2 or IMEX */
-        switch(s->mouse_detect_state) {
-        default:
-        case 0:
-            if (val == 200)
-                s->mouse_detect_state = 1;
-            break;
-        case 1:
-            if (val == 100)
-                s->mouse_detect_state = 2;
-            else if (val == 200)
-                s->mouse_detect_state = 3;
-            else
-                s->mouse_detect_state = 0;
-            break;
-        case 2:
-            if (val == 80)
-                s->mouse_type = 3; /* IMPS/2 */
-            s->mouse_detect_state = 0;
-            break;
-        case 3:
-            if (val == 80)
-                s->mouse_type = 4; /* IMEX */
-            s->mouse_detect_state = 0;
-            break;
-        }
-        ps2_queue(&s->common, AUX_ACK);
-        s->common.write_cmd = -1;
-        break;
-    case AUX_SET_RES:
-        s->mouse_resolution = val;
-        ps2_queue(&s->common, AUX_ACK);
-        s->common.write_cmd = -1;
-        break;
-    }
-}
-
-static void ps2_common_reset(PS2State *s)
-{
-    PS2Queue *q;
-    s->write_cmd = -1;
-    q = &s->queue;
-    q->rptr = 0;
-    q->wptr = 0;
-    q->count = 0;
-    s->update_irq(s->update_arg, 0);
-}
-
-static void ps2_kbd_reset(void *opaque)
-{
-    PS2KbdState *s = (PS2KbdState *) opaque;
-
-    ps2_common_reset(&s->common);
-    s->scan_enabled = 0;
-    s->translate = 0;
-    s->scancode_set = 0;
-}
-
-static void ps2_mouse_reset(void *opaque)
-{
-    PS2MouseState *s = (PS2MouseState *) opaque;
-
-    ps2_common_reset(&s->common);
-    s->mouse_status = 0;
-    s->mouse_resolution = 0;
-    s->mouse_sample_rate = 0;
-    s->mouse_wrap = 0;
-    s->mouse_type = 0;
-    s->mouse_detect_state = 0;
-    s->mouse_dx = 0;
-    s->mouse_dy = 0;
-    s->mouse_dz = 0;
-    s->mouse_buttons = 0;
-}
-
-static const VMStateDescription vmstate_ps2_common = {
-    .name = "PS2 Common State",
-    .version_id = 3,
-    .minimum_version_id = 2,
-    .minimum_version_id_old = 2,
-    .fields      = (VMStateField []) {
-        VMSTATE_INT32(write_cmd, PS2State),
-        VMSTATE_INT32(queue.rptr, PS2State),
-        VMSTATE_INT32(queue.wptr, PS2State),
-        VMSTATE_INT32(queue.count, PS2State),
-        VMSTATE_BUFFER(queue.data, PS2State),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static bool ps2_keyboard_ledstate_needed(void *opaque)
-{
-    PS2KbdState *s = opaque;
-
-    return s->ledstate != 0; /* 0 is default state */
-}
-
-static int ps2_kbd_ledstate_post_load(void *opaque, int version_id)
-{
-    PS2KbdState *s = opaque;
-
-    kbd_put_ledstate(s->ledstate);
-    return 0;
-}
-
-static const VMStateDescription vmstate_ps2_keyboard_ledstate = {
-    .name = "ps2kbd/ledstate",
-    .version_id = 3,
-    .minimum_version_id = 2,
-    .minimum_version_id_old = 2,
-    .post_load = ps2_kbd_ledstate_post_load,
-    .fields      = (VMStateField []) {
-        VMSTATE_INT32(ledstate, PS2KbdState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static int ps2_kbd_post_load(void* opaque, int version_id)
-{
-    PS2KbdState *s = (PS2KbdState*)opaque;
-
-    if (version_id == 2)
-        s->scancode_set=2;
-    return 0;
-}
-
-static const VMStateDescription vmstate_ps2_keyboard = {
-    .name = "ps2kbd",
-    .version_id = 3,
-    .minimum_version_id = 2,
-    .minimum_version_id_old = 2,
-    .post_load = ps2_kbd_post_load,
-    .fields      = (VMStateField []) {
-        VMSTATE_STRUCT(common, PS2KbdState, 0, vmstate_ps2_common, PS2State),
-        VMSTATE_INT32(scan_enabled, PS2KbdState),
-        VMSTATE_INT32(translate, PS2KbdState),
-        VMSTATE_INT32_V(scancode_set, PS2KbdState,3),
-        VMSTATE_END_OF_LIST()
-    },
-    .subsections = (VMStateSubsection []) {
-        {
-            .vmsd = &vmstate_ps2_keyboard_ledstate,
-            .needed = ps2_keyboard_ledstate_needed,
-        }, {
-            /* empty */
-        }
-    }
-};
-
-static const VMStateDescription vmstate_ps2_mouse = {
-    .name = "ps2mouse",
-    .version_id = 2,
-    .minimum_version_id = 2,
-    .minimum_version_id_old = 2,
-    .fields      = (VMStateField []) {
-        VMSTATE_STRUCT(common, PS2MouseState, 0, vmstate_ps2_common, PS2State),
-        VMSTATE_UINT8(mouse_status, PS2MouseState),
-        VMSTATE_UINT8(mouse_resolution, PS2MouseState),
-        VMSTATE_UINT8(mouse_sample_rate, PS2MouseState),
-        VMSTATE_UINT8(mouse_wrap, PS2MouseState),
-        VMSTATE_UINT8(mouse_type, PS2MouseState),
-        VMSTATE_UINT8(mouse_detect_state, PS2MouseState),
-        VMSTATE_INT32(mouse_dx, PS2MouseState),
-        VMSTATE_INT32(mouse_dy, PS2MouseState),
-        VMSTATE_INT32(mouse_dz, PS2MouseState),
-        VMSTATE_UINT8(mouse_buttons, PS2MouseState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg)
-{
-    PS2KbdState *s = (PS2KbdState *)g_malloc0(sizeof(PS2KbdState));
-
-    s->common.update_irq = update_irq;
-    s->common.update_arg = update_arg;
-    s->scancode_set = 2;
-    vmstate_register(NULL, 0, &vmstate_ps2_keyboard, s);
-    qemu_add_kbd_event_handler(ps2_put_keycode, s);
-    qemu_register_reset(ps2_kbd_reset, s);
-    return s;
-}
-
-void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg)
-{
-    PS2MouseState *s = (PS2MouseState *)g_malloc0(sizeof(PS2MouseState));
-
-    s->common.update_irq = update_irq;
-    s->common.update_arg = update_arg;
-    vmstate_register(NULL, 0, &vmstate_ps2_mouse, s);
-    qemu_add_mouse_event_handler(ps2_mouse_event, s, 0, "QEMU PS/2 Mouse");
-    qemu_register_reset(ps2_mouse_reset, s);
-    return s;
-}
diff --git a/hw/ps2.h b/hw/ps2.h
deleted file mode 100644 (file)
index 7c45ce7..0000000
--- a/hw/ps2.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * QEMU PS/2 keyboard/mouse emulation
- *
- * 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.
- */
-
-#ifndef HW_PS2_H
-#define HW_PS2_H
-
-/* ps2.c */
-void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg);
-void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg);
-void ps2_write_mouse(void *, int val);
-void ps2_write_keyboard(void *, int val);
-uint32_t ps2_read_data(void *);
-void ps2_queue(void *, int b);
-void ps2_keyboard_set_translation(void *opaque, int mode);
-void ps2_mouse_fake_event(void *opaque);
-
-#endif /* !HW_PS2_H */
diff --git a/hw/ptimer.c b/hw/ptimer.c
deleted file mode 100644 (file)
index 4bc96c9..0000000
+++ /dev/null
@@ -1,231 +0,0 @@
-/*
- * General purpose implementation of a simple periodic countdown timer.
- *
- * Copyright (c) 2007 CodeSourcery.
- *
- * This code is licensed under the GNU LGPL.
- */
-#include "hw/hw.h"
-#include "qemu/timer.h"
-#include "hw/ptimer.h"
-#include "qemu/host-utils.h"
-
-struct ptimer_state
-{
-    uint8_t enabled; /* 0 = disabled, 1 = periodic, 2 = oneshot.  */
-    uint64_t limit;
-    uint64_t delta;
-    uint32_t period_frac;
-    int64_t period;
-    int64_t last_event;
-    int64_t next_event;
-    QEMUBH *bh;
-    QEMUTimer *timer;
-};
-
-/* Use a bottom-half routine to avoid reentrancy issues.  */
-static void ptimer_trigger(ptimer_state *s)
-{
-    if (s->bh) {
-        qemu_bh_schedule(s->bh);
-    }
-}
-
-static void ptimer_reload(ptimer_state *s)
-{
-    if (s->delta == 0) {
-        ptimer_trigger(s);
-        s->delta = s->limit;
-    }
-    if (s->delta == 0 || s->period == 0) {
-        fprintf(stderr, "Timer with period zero, disabling\n");
-        s->enabled = 0;
-        return;
-    }
-
-    s->last_event = s->next_event;
-    s->next_event = s->last_event + s->delta * s->period;
-    if (s->period_frac) {
-        s->next_event += ((int64_t)s->period_frac * s->delta) >> 32;
-    }
-    qemu_mod_timer(s->timer, s->next_event);
-}
-
-static void ptimer_tick(void *opaque)
-{
-    ptimer_state *s = (ptimer_state *)opaque;
-    ptimer_trigger(s);
-    s->delta = 0;
-    if (s->enabled == 2) {
-        s->enabled = 0;
-    } else {
-        ptimer_reload(s);
-    }
-}
-
-uint64_t ptimer_get_count(ptimer_state *s)
-{
-    int64_t now;
-    uint64_t counter;
-
-    if (s->enabled) {
-        now = qemu_get_clock_ns(vm_clock);
-        /* Figure out the current counter value.  */
-        if (now - s->next_event > 0
-            || s->period == 0) {
-            /* Prevent timer underflowing if it should already have
-               triggered.  */
-            counter = 0;
-        } else {
-            uint64_t rem;
-            uint64_t div;
-            int clz1, clz2;
-            int shift;
-
-            /* We need to divide time by period, where time is stored in
-               rem (64-bit integer) and period is stored in period/period_frac
-               (64.32 fixed point).
-              
-               Doing full precision division is hard, so scale values and
-               do a 64-bit division.  The result should be rounded down,
-               so that the rounding error never causes the timer to go
-               backwards.
-            */
-
-            rem = s->next_event - now;
-            div = s->period;
-
-            clz1 = clz64(rem);
-            clz2 = clz64(div);
-            shift = clz1 < clz2 ? clz1 : clz2;
-
-            rem <<= shift;
-            div <<= shift;
-            if (shift >= 32) {
-                div |= ((uint64_t)s->period_frac << (shift - 32));
-            } else {
-                if (shift != 0)
-                    div |= (s->period_frac >> (32 - shift));
-                /* Look at remaining bits of period_frac and round div up if 
-                   necessary.  */
-                if ((uint32_t)(s->period_frac << shift))
-                    div += 1;
-            }
-            counter = rem / div;
-        }
-    } else {
-        counter = s->delta;
-    }
-    return counter;
-}
-
-void ptimer_set_count(ptimer_state *s, uint64_t count)
-{
-    s->delta = count;
-    if (s->enabled) {
-        s->next_event = qemu_get_clock_ns(vm_clock);
-        ptimer_reload(s);
-    }
-}
-
-void ptimer_run(ptimer_state *s, int oneshot)
-{
-    if (s->enabled) {
-        return;
-    }
-    if (s->period == 0) {
-        fprintf(stderr, "Timer with period zero, disabling\n");
-        return;
-    }
-    s->enabled = oneshot ? 2 : 1;
-    s->next_event = qemu_get_clock_ns(vm_clock);
-    ptimer_reload(s);
-}
-
-/* Pause a timer.  Note that this may cause it to "lose" time, even if it
-   is immediately restarted.  */
-void ptimer_stop(ptimer_state *s)
-{
-    if (!s->enabled)
-        return;
-
-    s->delta = ptimer_get_count(s);
-    qemu_del_timer(s->timer);
-    s->enabled = 0;
-}
-
-/* Set counter increment interval in nanoseconds.  */
-void ptimer_set_period(ptimer_state *s, int64_t period)
-{
-    s->period = period;
-    s->period_frac = 0;
-    if (s->enabled) {
-        s->next_event = qemu_get_clock_ns(vm_clock);
-        ptimer_reload(s);
-    }
-}
-
-/* Set counter frequency in Hz.  */
-void ptimer_set_freq(ptimer_state *s, uint32_t freq)
-{
-    s->period = 1000000000ll / freq;
-    s->period_frac = (1000000000ll << 32) / freq;
-    if (s->enabled) {
-        s->next_event = qemu_get_clock_ns(vm_clock);
-        ptimer_reload(s);
-    }
-}
-
-/* Set the initial countdown value.  If reload is nonzero then also set
-   count = limit.  */
-void ptimer_set_limit(ptimer_state *s, uint64_t limit, int reload)
-{
-    /*
-     * Artificially limit timeout rate to something
-     * achievable under QEMU.  Otherwise, QEMU spends all
-     * its time generating timer interrupts, and there
-     * is no forward progress.
-     * About ten microseconds is the fastest that really works
-     * on the current generation of host machines.
-     */
-
-    if (limit * s->period < 10000 && s->period) {
-        limit = 10000 / s->period;
-    }
-
-    s->limit = limit;
-    if (reload)
-        s->delta = limit;
-    if (s->enabled && reload) {
-        s->next_event = qemu_get_clock_ns(vm_clock);
-        ptimer_reload(s);
-    }
-}
-
-const VMStateDescription vmstate_ptimer = {
-    .name = "ptimer",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField[]) {
-        VMSTATE_UINT8(enabled, ptimer_state),
-        VMSTATE_UINT64(limit, ptimer_state),
-        VMSTATE_UINT64(delta, ptimer_state),
-        VMSTATE_UINT32(period_frac, ptimer_state),
-        VMSTATE_INT64(period, ptimer_state),
-        VMSTATE_INT64(last_event, ptimer_state),
-        VMSTATE_INT64(next_event, ptimer_state),
-        VMSTATE_TIMER(timer, ptimer_state),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-ptimer_state *ptimer_init(QEMUBH *bh)
-{
-    ptimer_state *s;
-
-    s = (ptimer_state *)g_malloc0(sizeof(ptimer_state));
-    s->bh = bh;
-    s->timer = qemu_new_timer_ns(vm_clock, ptimer_tick, s);
-    return s;
-}
diff --git a/hw/ptimer.h b/hw/ptimer.h
deleted file mode 100644 (file)
index 28fcaf1..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * 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"
-#include "migration/vmstate.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);
-
-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/puv3.h b/hw/puv3.h
deleted file mode 100644 (file)
index f37adcb..0000000
--- a/hw/puv3.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Misc PKUnity SoC declarations
- *
- * Copyright (C) 2010-2012 Guan Xuetao
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation, or any later version.
- * See the COPYING file in the top-level directory.
- */
-#ifndef QEMU_HW_PUV3_H
-#define QEMU_HW_PUV3_H
-
-#define PUV3_REGS_OFFSET        (0x1000) /* 4K is reasonable */
-
-/* PKUnity System bus (AHB): 0xc0000000 - 0xedffffff (640MB) */
-#define PUV3_DMA_BASE           (0xc0200000) /* AHB-4 */
-
-/* PKUnity Peripheral bus (APB): 0xee000000 - 0xefffffff (128MB) */
-#define PUV3_GPIO_BASE          (0xee500000) /* APB-5 */
-#define PUV3_INTC_BASE          (0xee600000) /* APB-6 */
-#define PUV3_OST_BASE           (0xee800000) /* APB-8 */
-#define PUV3_PM_BASE            (0xeea00000) /* APB-10 */
-#define PUV3_PS2_BASE           (0xeeb00000) /* APB-11 */
-
-/* Hardware interrupts */
-#define PUV3_IRQS_NR            (32)
-
-#define PUV3_IRQS_GPIOLOW0      (0)
-#define PUV3_IRQS_GPIOLOW1      (1)
-#define PUV3_IRQS_GPIOLOW2      (2)
-#define PUV3_IRQS_GPIOLOW3      (3)
-#define PUV3_IRQS_GPIOLOW4      (4)
-#define PUV3_IRQS_GPIOLOW5      (5)
-#define PUV3_IRQS_GPIOLOW6      (6)
-#define PUV3_IRQS_GPIOLOW7      (7)
-#define PUV3_IRQS_GPIOHIGH      (8)
-#define PUV3_IRQS_PS2_KBD       (22)
-#define PUV3_IRQS_PS2_AUX       (23)
-#define PUV3_IRQS_OST0          (26)
-
-/* All puv3_*.c use DPRINTF for debug. */
-#ifdef DEBUG_PUV3
-#define DPRINTF(fmt, ...) printf("%s: " fmt , __func__, ## __VA_ARGS__)
-#else
-#define DPRINTF(fmt, ...) do {} while (0)
-#endif
-
-#endif /* !QEMU_HW_PUV3_H */
diff --git a/hw/puv3_dma.c b/hw/puv3_dma.c
deleted file mode 100644 (file)
index c05a14e..0000000
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * DMA device simulation in PKUnity SoC
- *
- * Copyright (C) 2010-2012 Guan Xuetao
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation, or any later version.
- * See the COPYING file in the top-level directory.
- */
-#include "hw/hw.h"
-#include "hw/sysbus.h"
-
-#undef DEBUG_PUV3
-#include "hw/puv3.h"
-
-#define PUV3_DMA_CH_NR          (6)
-#define PUV3_DMA_CH_MASK        (0xff)
-#define PUV3_DMA_CH(offset)     ((offset) >> 8)
-
-typedef struct {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-    uint32_t reg_CFG[PUV3_DMA_CH_NR];
-} PUV3DMAState;
-
-static uint64_t puv3_dma_read(void *opaque, hwaddr offset,
-        unsigned size)
-{
-    PUV3DMAState *s = opaque;
-    uint32_t ret = 0;
-
-    assert(PUV3_DMA_CH(offset) < PUV3_DMA_CH_NR);
-
-    switch (offset & PUV3_DMA_CH_MASK) {
-    case 0x10:
-        ret = s->reg_CFG[PUV3_DMA_CH(offset)];
-        break;
-    default:
-        DPRINTF("Bad offset 0x%x\n", offset);
-    }
-    DPRINTF("offset 0x%x, value 0x%x\n", offset, ret);
-
-    return ret;
-}
-
-static void puv3_dma_write(void *opaque, hwaddr offset,
-        uint64_t value, unsigned size)
-{
-    PUV3DMAState *s = opaque;
-
-    assert(PUV3_DMA_CH(offset) < PUV3_DMA_CH_NR);
-
-    switch (offset & PUV3_DMA_CH_MASK) {
-    case 0x10:
-        s->reg_CFG[PUV3_DMA_CH(offset)] = value;
-        break;
-    default:
-        DPRINTF("Bad offset 0x%x\n", offset);
-    }
-    DPRINTF("offset 0x%x, value 0x%x\n", offset, value);
-}
-
-static const MemoryRegionOps puv3_dma_ops = {
-    .read = puv3_dma_read,
-    .write = puv3_dma_write,
-    .impl = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int puv3_dma_init(SysBusDevice *dev)
-{
-    PUV3DMAState *s = FROM_SYSBUS(PUV3DMAState, dev);
-    int i;
-
-    for (i = 0; i < PUV3_DMA_CH_NR; i++) {
-        s->reg_CFG[i] = 0x0;
-    }
-
-    memory_region_init_io(&s->iomem, &puv3_dma_ops, s, "puv3_dma",
-            PUV3_REGS_OFFSET);
-    sysbus_init_mmio(dev, &s->iomem);
-
-    return 0;
-}
-
-static void puv3_dma_class_init(ObjectClass *klass, void *data)
-{
-    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
-
-    sdc->init = puv3_dma_init;
-}
-
-static const TypeInfo puv3_dma_info = {
-    .name = "puv3_dma",
-    .parent = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(PUV3DMAState),
-    .class_init = puv3_dma_class_init,
-};
-
-static void puv3_dma_register_type(void)
-{
-    type_register_static(&puv3_dma_info);
-}
-
-type_init(puv3_dma_register_type)
diff --git a/hw/puv3_gpio.c b/hw/puv3_gpio.c
deleted file mode 100644 (file)
index b2a790b..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * GPIO device simulation in PKUnity SoC
- *
- * Copyright (C) 2010-2012 Guan Xuetao
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation, or any later version.
- * See the COPYING file in the top-level directory.
- */
-#include "hw/hw.h"
-#include "hw/sysbus.h"
-
-#undef DEBUG_PUV3
-#include "hw/puv3.h"
-
-typedef struct {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-    qemu_irq irq[9];
-
-    uint32_t reg_GPLR;
-    uint32_t reg_GPDR;
-    uint32_t reg_GPIR;
-} PUV3GPIOState;
-
-static uint64_t puv3_gpio_read(void *opaque, hwaddr offset,
-        unsigned size)
-{
-    PUV3GPIOState *s = opaque;
-    uint32_t ret = 0;
-
-    switch (offset) {
-    case 0x00:
-        ret = s->reg_GPLR;
-        break;
-    case 0x04:
-        ret = s->reg_GPDR;
-        break;
-    case 0x20:
-        ret = s->reg_GPIR;
-        break;
-    default:
-        DPRINTF("Bad offset 0x%x\n", offset);
-    }
-    DPRINTF("offset 0x%x, value 0x%x\n", offset, ret);
-
-    return ret;
-}
-
-static void puv3_gpio_write(void *opaque, hwaddr offset,
-        uint64_t value, unsigned size)
-{
-    PUV3GPIOState *s = opaque;
-
-    DPRINTF("offset 0x%x, value 0x%x\n", offset, value);
-    switch (offset) {
-    case 0x04:
-        s->reg_GPDR = value;
-        break;
-    case 0x08:
-        if (s->reg_GPDR & value) {
-            s->reg_GPLR |= value;
-        } else {
-            DPRINTF("Write gpio input port error!");
-        }
-        break;
-    case 0x0c:
-        if (s->reg_GPDR & value) {
-            s->reg_GPLR &= ~value;
-        } else {
-            DPRINTF("Write gpio input port error!");
-        }
-        break;
-    case 0x10: /* GRER */
-    case 0x14: /* GFER */
-    case 0x18: /* GEDR */
-        break;
-    case 0x20: /* GPIR */
-        s->reg_GPIR = value;
-        break;
-    default:
-        DPRINTF("Bad offset 0x%x\n", offset);
-    }
-}
-
-static const MemoryRegionOps puv3_gpio_ops = {
-    .read = puv3_gpio_read,
-    .write = puv3_gpio_write,
-    .impl = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int puv3_gpio_init(SysBusDevice *dev)
-{
-    PUV3GPIOState *s = FROM_SYSBUS(PUV3GPIOState, dev);
-
-    s->reg_GPLR = 0;
-    s->reg_GPDR = 0;
-
-    /* FIXME: these irqs not handled yet */
-    sysbus_init_irq(dev, &s->irq[PUV3_IRQS_GPIOLOW0]);
-    sysbus_init_irq(dev, &s->irq[PUV3_IRQS_GPIOLOW1]);
-    sysbus_init_irq(dev, &s->irq[PUV3_IRQS_GPIOLOW2]);
-    sysbus_init_irq(dev, &s->irq[PUV3_IRQS_GPIOLOW3]);
-    sysbus_init_irq(dev, &s->irq[PUV3_IRQS_GPIOLOW4]);
-    sysbus_init_irq(dev, &s->irq[PUV3_IRQS_GPIOLOW5]);
-    sysbus_init_irq(dev, &s->irq[PUV3_IRQS_GPIOLOW6]);
-    sysbus_init_irq(dev, &s->irq[PUV3_IRQS_GPIOLOW7]);
-    sysbus_init_irq(dev, &s->irq[PUV3_IRQS_GPIOHIGH]);
-
-    memory_region_init_io(&s->iomem, &puv3_gpio_ops, s, "puv3_gpio",
-            PUV3_REGS_OFFSET);
-    sysbus_init_mmio(dev, &s->iomem);
-
-    return 0;
-}
-
-static void puv3_gpio_class_init(ObjectClass *klass, void *data)
-{
-    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
-
-    sdc->init = puv3_gpio_init;
-}
-
-static const TypeInfo puv3_gpio_info = {
-    .name = "puv3_gpio",
-    .parent = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(PUV3GPIOState),
-    .class_init = puv3_gpio_class_init,
-};
-
-static void puv3_gpio_register_type(void)
-{
-    type_register_static(&puv3_gpio_info);
-}
-
-type_init(puv3_gpio_register_type)
diff --git a/hw/puv3_intc.c b/hw/puv3_intc.c
deleted file mode 100644 (file)
index 6bc9e1a..0000000
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * INTC device simulation in PKUnity SoC
- *
- * Copyright (C) 2010-2012 Guan Xuetao
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation, or any later version.
- * See the COPYING file in the top-level directory.
- */
-#include "hw/sysbus.h"
-
-#undef DEBUG_PUV3
-#include "hw/puv3.h"
-
-typedef struct {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-    qemu_irq parent_irq;
-
-    uint32_t reg_ICMR;
-    uint32_t reg_ICPR;
-} PUV3INTCState;
-
-/* Update interrupt status after enabled or pending bits have been changed.  */
-static void puv3_intc_update(PUV3INTCState *s)
-{
-    if (s->reg_ICMR & s->reg_ICPR) {
-        qemu_irq_raise(s->parent_irq);
-    } else {
-        qemu_irq_lower(s->parent_irq);
-    }
-}
-
-/* Process a change in an external INTC input. */
-static void puv3_intc_handler(void *opaque, int irq, int level)
-{
-    PUV3INTCState *s = opaque;
-
-    DPRINTF("irq 0x%x, level 0x%x\n", irq, level);
-    if (level) {
-        s->reg_ICPR |= (1 << irq);
-    } else {
-        s->reg_ICPR &= ~(1 << irq);
-    }
-    puv3_intc_update(s);
-}
-
-static uint64_t puv3_intc_read(void *opaque, hwaddr offset,
-        unsigned size)
-{
-    PUV3INTCState *s = opaque;
-    uint32_t ret = 0;
-
-    switch (offset) {
-    case 0x04: /* INTC_ICMR */
-        ret = s->reg_ICMR;
-        break;
-    case 0x0c: /* INTC_ICIP */
-        ret = s->reg_ICPR; /* the same value with ICPR */
-        break;
-    default:
-        DPRINTF("Bad offset %x\n", (int)offset);
-    }
-    DPRINTF("offset 0x%x, value 0x%x\n", offset, ret);
-    return ret;
-}
-
-static void puv3_intc_write(void *opaque, hwaddr offset,
-        uint64_t value, unsigned size)
-{
-    PUV3INTCState *s = opaque;
-
-    DPRINTF("offset 0x%x, value 0x%x\n", offset, value);
-    switch (offset) {
-    case 0x00: /* INTC_ICLR */
-    case 0x14: /* INTC_ICCR */
-        break;
-    case 0x04: /* INTC_ICMR */
-        s->reg_ICMR = value;
-        break;
-    default:
-        DPRINTF("Bad offset 0x%x\n", (int)offset);
-        return;
-    }
-    puv3_intc_update(s);
-}
-
-static const MemoryRegionOps puv3_intc_ops = {
-    .read = puv3_intc_read,
-    .write = puv3_intc_write,
-    .impl = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int puv3_intc_init(SysBusDevice *dev)
-{
-    PUV3INTCState *s = FROM_SYSBUS(PUV3INTCState, dev);
-
-    qdev_init_gpio_in(&s->busdev.qdev, puv3_intc_handler, PUV3_IRQS_NR);
-    sysbus_init_irq(&s->busdev, &s->parent_irq);
-
-    s->reg_ICMR = 0;
-    s->reg_ICPR = 0;
-
-    memory_region_init_io(&s->iomem, &puv3_intc_ops, s, "puv3_intc",
-            PUV3_REGS_OFFSET);
-    sysbus_init_mmio(dev, &s->iomem);
-
-    return 0;
-}
-
-static void puv3_intc_class_init(ObjectClass *klass, void *data)
-{
-    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
-
-    sdc->init = puv3_intc_init;
-}
-
-static const TypeInfo puv3_intc_info = {
-    .name = "puv3_intc",
-    .parent = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(PUV3INTCState),
-    .class_init = puv3_intc_class_init,
-};
-
-static void puv3_intc_register_type(void)
-{
-    type_register_static(&puv3_intc_info);
-}
-
-type_init(puv3_intc_register_type)
diff --git a/hw/puv3_ost.c b/hw/puv3_ost.c
deleted file mode 100644 (file)
index 10a522a..0000000
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * OSTimer device simulation in PKUnity SoC
- *
- * Copyright (C) 2010-2012 Guan Xuetao
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation, or any later version.
- * See the COPYING file in the top-level directory.
- */
-#include "hw/sysbus.h"
-#include "hw/ptimer.h"
-
-#undef DEBUG_PUV3
-#include "hw/puv3.h"
-
-/* puv3 ostimer implementation. */
-typedef struct {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-    QEMUBH *bh;
-    qemu_irq irq;
-    ptimer_state *ptimer;
-
-    uint32_t reg_OSMR0;
-    uint32_t reg_OSCR;
-    uint32_t reg_OSSR;
-    uint32_t reg_OIER;
-} PUV3OSTState;
-
-static uint64_t puv3_ost_read(void *opaque, hwaddr offset,
-        unsigned size)
-{
-    PUV3OSTState *s = opaque;
-    uint32_t ret = 0;
-
-    switch (offset) {
-    case 0x10: /* Counter Register */
-        ret = s->reg_OSMR0 - (uint32_t)ptimer_get_count(s->ptimer);
-        break;
-    case 0x14: /* Status Register */
-        ret = s->reg_OSSR;
-        break;
-    case 0x1c: /* Interrupt Enable Register */
-        ret = s->reg_OIER;
-        break;
-    default:
-        DPRINTF("Bad offset %x\n", (int)offset);
-    }
-    DPRINTF("offset 0x%x, value 0x%x\n", offset, ret);
-    return ret;
-}
-
-static void puv3_ost_write(void *opaque, hwaddr offset,
-        uint64_t value, unsigned size)
-{
-    PUV3OSTState *s = opaque;
-
-    DPRINTF("offset 0x%x, value 0x%x\n", offset, value);
-    switch (offset) {
-    case 0x00: /* Match Register 0 */
-        s->reg_OSMR0 = value;
-        if (s->reg_OSMR0 > s->reg_OSCR) {
-            ptimer_set_count(s->ptimer, s->reg_OSMR0 - s->reg_OSCR);
-        } else {
-            ptimer_set_count(s->ptimer, s->reg_OSMR0 +
-                    (0xffffffff - s->reg_OSCR));
-        }
-        ptimer_run(s->ptimer, 2);
-        break;
-    case 0x14: /* Status Register */
-        assert(value == 0);
-        if (s->reg_OSSR) {
-            s->reg_OSSR = value;
-            qemu_irq_lower(s->irq);
-        }
-        break;
-    case 0x1c: /* Interrupt Enable Register */
-        s->reg_OIER = value;
-        break;
-    default:
-        DPRINTF("Bad offset %x\n", (int)offset);
-    }
-}
-
-static const MemoryRegionOps puv3_ost_ops = {
-    .read = puv3_ost_read,
-    .write = puv3_ost_write,
-    .impl = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void puv3_ost_tick(void *opaque)
-{
-    PUV3OSTState *s = opaque;
-
-    DPRINTF("ost hit when ptimer counter from 0x%x to 0x%x!\n",
-            s->reg_OSCR, s->reg_OSMR0);
-
-    s->reg_OSCR = s->reg_OSMR0;
-    if (s->reg_OIER) {
-        s->reg_OSSR = 1;
-        qemu_irq_raise(s->irq);
-    }
-}
-
-static int puv3_ost_init(SysBusDevice *dev)
-{
-    PUV3OSTState *s = FROM_SYSBUS(PUV3OSTState, dev);
-
-    s->reg_OIER = 0;
-    s->reg_OSSR = 0;
-    s->reg_OSMR0 = 0;
-    s->reg_OSCR = 0;
-
-    sysbus_init_irq(dev, &s->irq);
-
-    s->bh = qemu_bh_new(puv3_ost_tick, s);
-    s->ptimer = ptimer_init(s->bh);
-    ptimer_set_freq(s->ptimer, 50 * 1000 * 1000);
-
-    memory_region_init_io(&s->iomem, &puv3_ost_ops, s, "puv3_ost",
-            PUV3_REGS_OFFSET);
-    sysbus_init_mmio(dev, &s->iomem);
-
-    return 0;
-}
-
-static void puv3_ost_class_init(ObjectClass *klass, void *data)
-{
-    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
-
-    sdc->init = puv3_ost_init;
-}
-
-static const TypeInfo puv3_ost_info = {
-    .name = "puv3_ost",
-    .parent = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(PUV3OSTState),
-    .class_init = puv3_ost_class_init,
-};
-
-static void puv3_ost_register_type(void)
-{
-    type_register_static(&puv3_ost_info);
-}
-
-type_init(puv3_ost_register_type)
diff --git a/hw/puv3_pm.c b/hw/puv3_pm.c
deleted file mode 100644 (file)
index 6b8d94d..0000000
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * Power Management device simulation in PKUnity SoC
- *
- * Copyright (C) 2010-2012 Guan Xuetao
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation, or any later version.
- * See the COPYING file in the top-level directory.
- */
-#include "hw/hw.h"
-#include "hw/sysbus.h"
-
-#undef DEBUG_PUV3
-#include "hw/puv3.h"
-
-typedef struct {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-
-    uint32_t reg_PMCR;
-    uint32_t reg_PCGR;
-    uint32_t reg_PLL_SYS_CFG;
-    uint32_t reg_PLL_DDR_CFG;
-    uint32_t reg_PLL_VGA_CFG;
-    uint32_t reg_DIVCFG;
-} PUV3PMState;
-
-static uint64_t puv3_pm_read(void *opaque, hwaddr offset,
-        unsigned size)
-{
-    PUV3PMState *s = opaque;
-    uint32_t ret = 0;
-
-    switch (offset) {
-    case 0x14:
-        ret = s->reg_PCGR;
-        break;
-    case 0x18:
-        ret = s->reg_PLL_SYS_CFG;
-        break;
-    case 0x1c:
-        ret = s->reg_PLL_DDR_CFG;
-        break;
-    case 0x20:
-        ret = s->reg_PLL_VGA_CFG;
-        break;
-    case 0x24:
-        ret = s->reg_DIVCFG;
-        break;
-    case 0x28: /* PLL SYS STATUS */
-        ret = 0x00002401;
-        break;
-    case 0x2c: /* PLL DDR STATUS */
-        ret = 0x00100c00;
-        break;
-    case 0x30: /* PLL VGA STATUS */
-        ret = 0x00003801;
-        break;
-    case 0x34: /* DIV STATUS */
-        ret = 0x22f52015;
-        break;
-    case 0x38: /* SW RESET */
-        ret = 0x0;
-        break;
-    case 0x44: /* PLL DFC DONE */
-        ret = 0x7;
-        break;
-    default:
-        DPRINTF("Bad offset 0x%x\n", offset);
-    }
-    DPRINTF("offset 0x%x, value 0x%x\n", offset, ret);
-
-    return ret;
-}
-
-static void puv3_pm_write(void *opaque, hwaddr offset,
-        uint64_t value, unsigned size)
-{
-    PUV3PMState *s = opaque;
-
-    switch (offset) {
-    case 0x0:
-        s->reg_PMCR = value;
-        break;
-    case 0x14:
-        s->reg_PCGR = value;
-        break;
-    case 0x18:
-        s->reg_PLL_SYS_CFG = value;
-        break;
-    case 0x1c:
-        s->reg_PLL_DDR_CFG = value;
-        break;
-    case 0x20:
-        s->reg_PLL_VGA_CFG = value;
-        break;
-    case 0x24:
-    case 0x38:
-        break;
-    default:
-        DPRINTF("Bad offset 0x%x\n", offset);
-    }
-    DPRINTF("offset 0x%x, value 0x%x\n", offset, value);
-}
-
-static const MemoryRegionOps puv3_pm_ops = {
-    .read = puv3_pm_read,
-    .write = puv3_pm_write,
-    .impl = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int puv3_pm_init(SysBusDevice *dev)
-{
-    PUV3PMState *s = FROM_SYSBUS(PUV3PMState, dev);
-
-    s->reg_PCGR = 0x0;
-
-    memory_region_init_io(&s->iomem, &puv3_pm_ops, s, "puv3_pm",
-            PUV3_REGS_OFFSET);
-    sysbus_init_mmio(dev, &s->iomem);
-
-    return 0;
-}
-
-static void puv3_pm_class_init(ObjectClass *klass, void *data)
-{
-    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
-
-    sdc->init = puv3_pm_init;
-}
-
-static const TypeInfo puv3_pm_info = {
-    .name = "puv3_pm",
-    .parent = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(PUV3PMState),
-    .class_init = puv3_pm_class_init,
-};
-
-static void puv3_pm_register_type(void)
-{
-    type_register_static(&puv3_pm_info);
-}
-
-type_init(puv3_pm_register_type)
diff --git a/hw/pxa.h b/hw/pxa.h
deleted file mode 100644 (file)
index 668232c..0000000
--- a/hw/pxa.h
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
- * Intel XScale PXA255/270 processor support.
- *
- * Copyright (c) 2006 Openedhand Ltd.
- * Written by Andrzej Zaborowski <balrog@zabor.org>
- *
- * This code is licensed under the GNU GPL v2.
- */
-#ifndef PXA_H
-# define PXA_H                 "pxa.h"
-
-#include "exec/memory.h"
-
-/* Interrupt numbers */
-# define PXA2XX_PIC_SSP3       0
-# define PXA2XX_PIC_USBH2      2
-# define PXA2XX_PIC_USBH1      3
-# define PXA2XX_PIC_KEYPAD     4
-# define PXA2XX_PIC_PWRI2C     6
-# define PXA25X_PIC_HWUART     7
-# define PXA27X_PIC_OST_4_11   7
-# define PXA2XX_PIC_GPIO_0     8
-# define PXA2XX_PIC_GPIO_1     9
-# define PXA2XX_PIC_GPIO_X     10
-# define PXA2XX_PIC_I2S        13
-# define PXA26X_PIC_ASSP       15
-# define PXA25X_PIC_NSSP       16
-# define PXA27X_PIC_SSP2       16
-# define PXA2XX_PIC_LCD                17
-# define PXA2XX_PIC_I2C                18
-# define PXA2XX_PIC_ICP                19
-# define PXA2XX_PIC_STUART     20
-# define PXA2XX_PIC_BTUART     21
-# define PXA2XX_PIC_FFUART     22
-# define PXA2XX_PIC_MMC                23
-# define PXA2XX_PIC_SSP                24
-# define PXA2XX_PIC_DMA                25
-# define PXA2XX_PIC_OST_0      26
-# define PXA2XX_PIC_RTC1HZ     30
-# define PXA2XX_PIC_RTCALARM   31
-
-/* DMA requests */
-# define PXA2XX_RX_RQ_I2S      2
-# define PXA2XX_TX_RQ_I2S      3
-# define PXA2XX_RX_RQ_BTUART   4
-# define PXA2XX_TX_RQ_BTUART   5
-# define PXA2XX_RX_RQ_FFUART   6
-# define PXA2XX_TX_RQ_FFUART   7
-# define PXA2XX_RX_RQ_SSP1     13
-# define PXA2XX_TX_RQ_SSP1     14
-# define PXA2XX_RX_RQ_SSP2     15
-# define PXA2XX_TX_RQ_SSP2     16
-# define PXA2XX_RX_RQ_ICP      17
-# define PXA2XX_TX_RQ_ICP      18
-# define PXA2XX_RX_RQ_STUART   19
-# define PXA2XX_TX_RQ_STUART   20
-# define PXA2XX_RX_RQ_MMCI     21
-# define PXA2XX_TX_RQ_MMCI     22
-# define PXA2XX_USB_RQ(x)      ((x) + 24)
-# define PXA2XX_RX_RQ_SSP3     66
-# define PXA2XX_TX_RQ_SSP3     67
-
-# define PXA2XX_SDRAM_BASE     0xa0000000
-# define PXA2XX_INTERNAL_BASE  0x5c000000
-# define PXA2XX_INTERNAL_SIZE  0x40000
-
-/* pxa2xx_pic.c */
-DeviceState *pxa2xx_pic_init(hwaddr base, ARMCPU *cpu);
-
-/* pxa2xx_gpio.c */
-DeviceState *pxa2xx_gpio_init(hwaddr base,
-                              ARMCPU *cpu, DeviceState *pic, int lines);
-void pxa2xx_gpio_read_notifier(DeviceState *dev, qemu_irq handler);
-
-/* pxa2xx_dma.c */
-DeviceState *pxa255_dma_init(hwaddr base, qemu_irq irq);
-DeviceState *pxa27x_dma_init(hwaddr base, qemu_irq irq);
-
-/* pxa2xx_lcd.c */
-typedef struct PXA2xxLCDState PXA2xxLCDState;
-PXA2xxLCDState *pxa2xx_lcdc_init(MemoryRegion *sysmem,
-                hwaddr base, qemu_irq irq);
-void pxa2xx_lcd_vsync_notifier(PXA2xxLCDState *s, qemu_irq handler);
-void pxa2xx_lcdc_oritentation(void *opaque, int angle);
-
-/* pxa2xx_mmci.c */
-typedef struct PXA2xxMMCIState PXA2xxMMCIState;
-PXA2xxMMCIState *pxa2xx_mmci_init(MemoryRegion *sysmem,
-                hwaddr base,
-                BlockDriverState *bd, qemu_irq irq,
-                qemu_irq rx_dma, qemu_irq tx_dma);
-void pxa2xx_mmci_handlers(PXA2xxMMCIState *s, qemu_irq readonly,
-                qemu_irq coverswitch);
-
-/* pxa2xx_pcmcia.c */
-typedef struct PXA2xxPCMCIAState PXA2xxPCMCIAState;
-PXA2xxPCMCIAState *pxa2xx_pcmcia_init(MemoryRegion *sysmem,
-                                      hwaddr base);
-int pxa2xx_pcmcia_attach(void *opaque, PCMCIACardState *card);
-int pxa2xx_pcmcia_dettach(void *opaque);
-void pxa2xx_pcmcia_set_irq_cb(void *opaque, qemu_irq irq, qemu_irq cd_irq);
-
-/* pxa2xx_keypad.c */
-struct  keymap {
-    int column;
-    int row;
-};
-typedef struct PXA2xxKeyPadState PXA2xxKeyPadState;
-PXA2xxKeyPadState *pxa27x_keypad_init(MemoryRegion *sysmem,
-                                      hwaddr base,
-                                      qemu_irq irq);
-void pxa27x_register_keypad(PXA2xxKeyPadState *kp, struct keymap *map,
-                int size);
-
-/* pxa2xx.c */
-typedef struct PXA2xxI2CState PXA2xxI2CState;
-PXA2xxI2CState *pxa2xx_i2c_init(hwaddr base,
-                qemu_irq irq, uint32_t page_size);
-i2c_bus *pxa2xx_i2c_bus(PXA2xxI2CState *s);
-
-typedef struct PXA2xxI2SState PXA2xxI2SState;
-typedef struct PXA2xxFIrState PXA2xxFIrState;
-
-typedef struct {
-    ARMCPU *cpu;
-    DeviceState *pic;
-    qemu_irq reset;
-    MemoryRegion sdram;
-    MemoryRegion internal;
-    MemoryRegion cm_iomem;
-    MemoryRegion mm_iomem;
-    MemoryRegion pm_iomem;
-    DeviceState *dma;
-    DeviceState *gpio;
-    PXA2xxLCDState *lcd;
-    SSIBus **ssp;
-    PXA2xxI2CState *i2c[2];
-    PXA2xxMMCIState *mmc;
-    PXA2xxPCMCIAState *pcmcia[2];
-    PXA2xxI2SState *i2s;
-    PXA2xxFIrState *fir;
-    PXA2xxKeyPadState *kp;
-
-    /* Power management */
-    hwaddr pm_base;
-    uint32_t pm_regs[0x40];
-
-    /* Clock management */
-    hwaddr cm_base;
-    uint32_t cm_regs[4];
-    uint32_t clkcfg;
-
-    /* Memory management */
-    hwaddr mm_base;
-    uint32_t mm_regs[0x1a];
-
-    /* Performance monitoring */
-    uint32_t pmnc;
-} PXA2xxState;
-
-struct PXA2xxI2SState {
-    MemoryRegion iomem;
-    qemu_irq irq;
-    qemu_irq rx_dma;
-    qemu_irq tx_dma;
-    void (*data_req)(void *, int, int);
-
-    uint32_t control[2];
-    uint32_t status;
-    uint32_t mask;
-    uint32_t clk;
-
-    int enable;
-    int rx_len;
-    int tx_len;
-    void (*codec_out)(void *, uint32_t);
-    uint32_t (*codec_in)(void *);
-    void *opaque;
-
-    int fifo_len;
-    uint32_t fifo[16];
-};
-
-# define PA_FMT                        "0x%08lx"
-# define REG_FMT               "0x" TARGET_FMT_plx
-
-PXA2xxState *pxa270_init(MemoryRegion *address_space, unsigned int sdram_size,
-                         const char *revision);
-PXA2xxState *pxa255_init(MemoryRegion *address_space, unsigned int sdram_size);
-
-#endif /* PXA_H */
diff --git a/hw/pxa2xx_dma.c b/hw/pxa2xx_dma.c
deleted file mode 100644 (file)
index 1db21c9..0000000
+++ /dev/null
@@ -1,574 +0,0 @@
-/*
- * Intel XScale PXA255/270 DMA controller.
- *
- * Copyright (c) 2006 Openedhand Ltd.
- * Copyright (c) 2006 Thorsten Zitterell
- * Written by Andrzej Zaborowski <balrog@zabor.org>
- *
- * This code is licensed under the GPL.
- */
-
-#include "hw/hw.h"
-#include "hw/pxa.h"
-#include "hw/sysbus.h"
-
-#define PXA255_DMA_NUM_CHANNELS 16
-#define PXA27X_DMA_NUM_CHANNELS 32
-
-#define PXA2XX_DMA_NUM_REQUESTS 75
-
-typedef struct {
-    uint32_t descr;
-    uint32_t src;
-    uint32_t dest;
-    uint32_t cmd;
-    uint32_t state;
-    int request;
-} PXA2xxDMAChannel;
-
-typedef struct PXA2xxDMAState {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-    qemu_irq irq;
-
-    uint32_t stopintr;
-    uint32_t eorintr;
-    uint32_t rasintr;
-    uint32_t startintr;
-    uint32_t endintr;
-
-    uint32_t align;
-    uint32_t pio;
-
-    int channels;
-    PXA2xxDMAChannel *chan;
-
-    uint8_t req[PXA2XX_DMA_NUM_REQUESTS];
-
-    /* Flag to avoid recursive DMA invocations.  */
-    int running;
-} PXA2xxDMAState;
-
-#define DCSR0  0x0000  /* DMA Control / Status register for Channel 0 */
-#define DCSR31 0x007c  /* DMA Control / Status register for Channel 31 */
-#define DALGN  0x00a0  /* DMA Alignment register */
-#define DPCSR  0x00a4  /* DMA Programmed I/O Control Status register */
-#define DRQSR0 0x00e0  /* DMA DREQ<0> Status register */
-#define DRQSR1 0x00e4  /* DMA DREQ<1> Status register */
-#define DRQSR2 0x00e8  /* DMA DREQ<2> Status register */
-#define DINT   0x00f0  /* DMA Interrupt register */
-#define DRCMR0 0x0100  /* Request to Channel Map register 0 */
-#define DRCMR63        0x01fc  /* Request to Channel Map register 63 */
-#define D_CH0  0x0200  /* Channel 0 Descriptor start */
-#define DRCMR64        0x1100  /* Request to Channel Map register 64 */
-#define DRCMR74        0x1128  /* Request to Channel Map register 74 */
-
-/* Per-channel register */
-#define DDADR  0x00
-#define DSADR  0x01
-#define DTADR  0x02
-#define DCMD   0x03
-
-/* Bit-field masks */
-#define DRCMR_CHLNUM           0x1f
-#define DRCMR_MAPVLD           (1 << 7)
-#define DDADR_STOP             (1 << 0)
-#define DDADR_BREN             (1 << 1)
-#define DCMD_LEN               0x1fff
-#define DCMD_WIDTH(x)          (1 << ((((x) >> 14) & 3) - 1))
-#define DCMD_SIZE(x)           (4 << (((x) >> 16) & 3))
-#define DCMD_FLYBYT            (1 << 19)
-#define DCMD_FLYBYS            (1 << 20)
-#define DCMD_ENDIRQEN          (1 << 21)
-#define DCMD_STARTIRQEN                (1 << 22)
-#define DCMD_CMPEN             (1 << 25)
-#define DCMD_FLOWTRG           (1 << 28)
-#define DCMD_FLOWSRC           (1 << 29)
-#define DCMD_INCTRGADDR                (1 << 30)
-#define DCMD_INCSRCADDR                (1 << 31)
-#define DCSR_BUSERRINTR                (1 << 0)
-#define DCSR_STARTINTR         (1 << 1)
-#define DCSR_ENDINTR           (1 << 2)
-#define DCSR_STOPINTR          (1 << 3)
-#define DCSR_RASINTR           (1 << 4)
-#define DCSR_REQPEND           (1 << 8)
-#define DCSR_EORINT            (1 << 9)
-#define DCSR_CMPST             (1 << 10)
-#define DCSR_MASKRUN           (1 << 22)
-#define DCSR_RASIRQEN          (1 << 23)
-#define DCSR_CLRCMPST          (1 << 24)
-#define DCSR_SETCMPST          (1 << 25)
-#define DCSR_EORSTOPEN         (1 << 26)
-#define DCSR_EORJMPEN          (1 << 27)
-#define DCSR_EORIRQEN          (1 << 28)
-#define DCSR_STOPIRQEN         (1 << 29)
-#define DCSR_NODESCFETCH       (1 << 30)
-#define DCSR_RUN               (1 << 31)
-
-static inline void pxa2xx_dma_update(PXA2xxDMAState *s, int ch)
-{
-    if (ch >= 0) {
-        if ((s->chan[ch].state & DCSR_STOPIRQEN) &&
-                (s->chan[ch].state & DCSR_STOPINTR))
-            s->stopintr |= 1 << ch;
-        else
-            s->stopintr &= ~(1 << ch);
-
-        if ((s->chan[ch].state & DCSR_EORIRQEN) &&
-                (s->chan[ch].state & DCSR_EORINT))
-            s->eorintr |= 1 << ch;
-        else
-            s->eorintr &= ~(1 << ch);
-
-        if ((s->chan[ch].state & DCSR_RASIRQEN) &&
-                (s->chan[ch].state & DCSR_RASINTR))
-            s->rasintr |= 1 << ch;
-        else
-            s->rasintr &= ~(1 << ch);
-
-        if (s->chan[ch].state & DCSR_STARTINTR)
-            s->startintr |= 1 << ch;
-        else
-            s->startintr &= ~(1 << ch);
-
-        if (s->chan[ch].state & DCSR_ENDINTR)
-            s->endintr |= 1 << ch;
-        else
-            s->endintr &= ~(1 << ch);
-    }
-
-    if (s->stopintr | s->eorintr | s->rasintr | s->startintr | s->endintr)
-        qemu_irq_raise(s->irq);
-    else
-        qemu_irq_lower(s->irq);
-}
-
-static inline void pxa2xx_dma_descriptor_fetch(
-                PXA2xxDMAState *s, int ch)
-{
-    uint32_t desc[4];
-    hwaddr daddr = s->chan[ch].descr & ~0xf;
-    if ((s->chan[ch].descr & DDADR_BREN) && (s->chan[ch].state & DCSR_CMPST))
-        daddr += 32;
-
-    cpu_physical_memory_read(daddr, (uint8_t *) desc, 16);
-    s->chan[ch].descr = desc[DDADR];
-    s->chan[ch].src = desc[DSADR];
-    s->chan[ch].dest = desc[DTADR];
-    s->chan[ch].cmd = desc[DCMD];
-
-    if (s->chan[ch].cmd & DCMD_FLOWSRC)
-        s->chan[ch].src &= ~3;
-    if (s->chan[ch].cmd & DCMD_FLOWTRG)
-        s->chan[ch].dest &= ~3;
-
-    if (s->chan[ch].cmd & (DCMD_CMPEN | DCMD_FLYBYS | DCMD_FLYBYT))
-        printf("%s: unsupported mode in channel %i\n", __FUNCTION__, ch);
-
-    if (s->chan[ch].cmd & DCMD_STARTIRQEN)
-        s->chan[ch].state |= DCSR_STARTINTR;
-}
-
-static void pxa2xx_dma_run(PXA2xxDMAState *s)
-{
-    int c, srcinc, destinc;
-    uint32_t n, size;
-    uint32_t width;
-    uint32_t length;
-    uint8_t buffer[32];
-    PXA2xxDMAChannel *ch;
-
-    if (s->running ++)
-        return;
-
-    while (s->running) {
-        s->running = 1;
-        for (c = 0; c < s->channels; c ++) {
-            ch = &s->chan[c];
-
-            while ((ch->state & DCSR_RUN) && !(ch->state & DCSR_STOPINTR)) {
-                /* Test for pending requests */
-                if ((ch->cmd & (DCMD_FLOWSRC | DCMD_FLOWTRG)) && !ch->request)
-                    break;
-
-                length = ch->cmd & DCMD_LEN;
-                size = DCMD_SIZE(ch->cmd);
-                width = DCMD_WIDTH(ch->cmd);
-
-                srcinc = (ch->cmd & DCMD_INCSRCADDR) ? width : 0;
-                destinc = (ch->cmd & DCMD_INCTRGADDR) ? width : 0;
-
-                while (length) {
-                    size = MIN(length, size);
-
-                    for (n = 0; n < size; n += width) {
-                        cpu_physical_memory_read(ch->src, buffer + n, width);
-                        ch->src += srcinc;
-                    }
-
-                    for (n = 0; n < size; n += width) {
-                        cpu_physical_memory_write(ch->dest, buffer + n, width);
-                        ch->dest += destinc;
-                    }
-
-                    length -= size;
-
-                    if ((ch->cmd & (DCMD_FLOWSRC | DCMD_FLOWTRG)) &&
-                            !ch->request) {
-                        ch->state |= DCSR_EORINT;
-                        if (ch->state & DCSR_EORSTOPEN)
-                            ch->state |= DCSR_STOPINTR;
-                        if ((ch->state & DCSR_EORJMPEN) &&
-                                        !(ch->state & DCSR_NODESCFETCH))
-                            pxa2xx_dma_descriptor_fetch(s, c);
-                        break;
-                   }
-                }
-
-                ch->cmd = (ch->cmd & ~DCMD_LEN) | length;
-
-                /* Is the transfer complete now? */
-                if (!length) {
-                    if (ch->cmd & DCMD_ENDIRQEN)
-                        ch->state |= DCSR_ENDINTR;
-
-                    if ((ch->state & DCSR_NODESCFETCH) ||
-                                (ch->descr & DDADR_STOP) ||
-                                (ch->state & DCSR_EORSTOPEN)) {
-                        ch->state |= DCSR_STOPINTR;
-                        ch->state &= ~DCSR_RUN;
-
-                        break;
-                    }
-
-                    ch->state |= DCSR_STOPINTR;
-                    break;
-                }
-            }
-        }
-
-        s->running --;
-    }
-}
-
-static uint64_t pxa2xx_dma_read(void *opaque, hwaddr offset,
-                                unsigned size)
-{
-    PXA2xxDMAState *s = (PXA2xxDMAState *) opaque;
-    unsigned int channel;
-
-    if (size != 4) {
-        hw_error("%s: Bad access width\n", __FUNCTION__);
-        return 5;
-    }
-
-    switch (offset) {
-    case DRCMR64 ... DRCMR74:
-        offset -= DRCMR64 - DRCMR0 - (64 << 2);
-        /* Fall through */
-    case DRCMR0 ... DRCMR63:
-        channel = (offset - DRCMR0) >> 2;
-        return s->req[channel];
-
-    case DRQSR0:
-    case DRQSR1:
-    case DRQSR2:
-        return 0;
-
-    case DCSR0 ... DCSR31:
-        channel = offset >> 2;
-       if (s->chan[channel].request)
-            return s->chan[channel].state | DCSR_REQPEND;
-        return s->chan[channel].state;
-
-    case DINT:
-        return s->stopintr | s->eorintr | s->rasintr |
-                s->startintr | s->endintr;
-
-    case DALGN:
-        return s->align;
-
-    case DPCSR:
-        return s->pio;
-    }
-
-    if (offset >= D_CH0 && offset < D_CH0 + (s->channels << 4)) {
-        channel = (offset - D_CH0) >> 4;
-        switch ((offset & 0x0f) >> 2) {
-        case DDADR:
-            return s->chan[channel].descr;
-        case DSADR:
-            return s->chan[channel].src;
-        case DTADR:
-            return s->chan[channel].dest;
-        case DCMD:
-            return s->chan[channel].cmd;
-        }
-    }
-
-    hw_error("%s: Bad offset 0x" TARGET_FMT_plx "\n", __FUNCTION__, offset);
-    return 7;
-}
-
-static void pxa2xx_dma_write(void *opaque, hwaddr offset,
-                             uint64_t value, unsigned size)
-{
-    PXA2xxDMAState *s = (PXA2xxDMAState *) opaque;
-    unsigned int channel;
-
-    if (size != 4) {
-        hw_error("%s: Bad access width\n", __FUNCTION__);
-        return;
-    }
-
-    switch (offset) {
-    case DRCMR64 ... DRCMR74:
-        offset -= DRCMR64 - DRCMR0 - (64 << 2);
-        /* Fall through */
-    case DRCMR0 ... DRCMR63:
-        channel = (offset - DRCMR0) >> 2;
-
-        if (value & DRCMR_MAPVLD)
-            if ((value & DRCMR_CHLNUM) > s->channels)
-                hw_error("%s: Bad DMA channel %i\n",
-                         __FUNCTION__, (unsigned)value & DRCMR_CHLNUM);
-
-        s->req[channel] = value;
-        break;
-
-    case DRQSR0:
-    case DRQSR1:
-    case DRQSR2:
-        /* Nothing to do */
-        break;
-
-    case DCSR0 ... DCSR31:
-        channel = offset >> 2;
-        s->chan[channel].state &= 0x0000071f & ~(value &
-                        (DCSR_EORINT | DCSR_ENDINTR |
-                         DCSR_STARTINTR | DCSR_BUSERRINTR));
-        s->chan[channel].state |= value & 0xfc800000;
-
-        if (s->chan[channel].state & DCSR_STOPIRQEN)
-            s->chan[channel].state &= ~DCSR_STOPINTR;
-
-        if (value & DCSR_NODESCFETCH) {
-            /* No-descriptor-fetch mode */
-            if (value & DCSR_RUN) {
-                s->chan[channel].state &= ~DCSR_STOPINTR;
-                pxa2xx_dma_run(s);
-            }
-        } else {
-            /* Descriptor-fetch mode */
-            if (value & DCSR_RUN) {
-                s->chan[channel].state &= ~DCSR_STOPINTR;
-                pxa2xx_dma_descriptor_fetch(s, channel);
-                pxa2xx_dma_run(s);
-            }
-        }
-
-        /* Shouldn't matter as our DMA is synchronous.  */
-        if (!(value & (DCSR_RUN | DCSR_MASKRUN)))
-            s->chan[channel].state |= DCSR_STOPINTR;
-
-        if (value & DCSR_CLRCMPST)
-            s->chan[channel].state &= ~DCSR_CMPST;
-        if (value & DCSR_SETCMPST)
-            s->chan[channel].state |= DCSR_CMPST;
-
-        pxa2xx_dma_update(s, channel);
-        break;
-
-    case DALGN:
-        s->align = value;
-        break;
-
-    case DPCSR:
-        s->pio = value & 0x80000001;
-        break;
-
-    default:
-        if (offset >= D_CH0 && offset < D_CH0 + (s->channels << 4)) {
-            channel = (offset - D_CH0) >> 4;
-            switch ((offset & 0x0f) >> 2) {
-            case DDADR:
-                s->chan[channel].descr = value;
-                break;
-            case DSADR:
-                s->chan[channel].src = value;
-                break;
-            case DTADR:
-                s->chan[channel].dest = value;
-                break;
-            case DCMD:
-                s->chan[channel].cmd = value;
-                break;
-            default:
-                goto fail;
-            }
-
-            break;
-        }
-    fail:
-        hw_error("%s: Bad offset " TARGET_FMT_plx "\n", __FUNCTION__, offset);
-    }
-}
-
-static const MemoryRegionOps pxa2xx_dma_ops = {
-    .read = pxa2xx_dma_read,
-    .write = pxa2xx_dma_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void pxa2xx_dma_request(void *opaque, int req_num, int on)
-{
-    PXA2xxDMAState *s = opaque;
-    int ch;
-    if (req_num < 0 || req_num >= PXA2XX_DMA_NUM_REQUESTS)
-        hw_error("%s: Bad DMA request %i\n", __FUNCTION__, req_num);
-
-    if (!(s->req[req_num] & DRCMR_MAPVLD))
-        return;
-    ch = s->req[req_num] & DRCMR_CHLNUM;
-
-    if (!s->chan[ch].request && on)
-        s->chan[ch].state |= DCSR_RASINTR;
-    else
-        s->chan[ch].state &= ~DCSR_RASINTR;
-    if (s->chan[ch].request && !on)
-        s->chan[ch].state |= DCSR_EORINT;
-
-    s->chan[ch].request = on;
-    if (on) {
-        pxa2xx_dma_run(s);
-        pxa2xx_dma_update(s, ch);
-    }
-}
-
-static int pxa2xx_dma_init(SysBusDevice *dev)
-{
-    int i;
-    PXA2xxDMAState *s;
-    s = FROM_SYSBUS(PXA2xxDMAState, dev);
-
-    if (s->channels <= 0) {
-        return -1;
-    }
-
-    s->chan = g_malloc0(sizeof(PXA2xxDMAChannel) * s->channels);
-
-    memset(s->chan, 0, sizeof(PXA2xxDMAChannel) * s->channels);
-    for (i = 0; i < s->channels; i ++)
-        s->chan[i].state = DCSR_STOPINTR;
-
-    memset(s->req, 0, sizeof(uint8_t) * PXA2XX_DMA_NUM_REQUESTS);
-
-    qdev_init_gpio_in(&dev->qdev, pxa2xx_dma_request, PXA2XX_DMA_NUM_REQUESTS);
-
-    memory_region_init_io(&s->iomem, &pxa2xx_dma_ops, s,
-                          "pxa2xx.dma", 0x00010000);
-    sysbus_init_mmio(dev, &s->iomem);
-    sysbus_init_irq(dev, &s->irq);
-
-    return 0;
-}
-
-DeviceState *pxa27x_dma_init(hwaddr base, qemu_irq irq)
-{
-    DeviceState *dev;
-
-    dev = qdev_create(NULL, "pxa2xx-dma");
-    qdev_prop_set_int32(dev, "channels", PXA27X_DMA_NUM_CHANNELS);
-    qdev_init_nofail(dev);
-
-    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
-    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq);
-
-    return dev;
-}
-
-DeviceState *pxa255_dma_init(hwaddr base, qemu_irq irq)
-{
-    DeviceState *dev;
-
-    dev = qdev_create(NULL, "pxa2xx-dma");
-    qdev_prop_set_int32(dev, "channels", PXA27X_DMA_NUM_CHANNELS);
-    qdev_init_nofail(dev);
-
-    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
-    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq);
-
-    return dev;
-}
-
-static bool is_version_0(void *opaque, int version_id)
-{
-    return version_id == 0;
-}
-
-static VMStateDescription vmstate_pxa2xx_dma_chan = {
-    .name = "pxa2xx_dma_chan",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT32(descr, PXA2xxDMAChannel),
-        VMSTATE_UINT32(src, PXA2xxDMAChannel),
-        VMSTATE_UINT32(dest, PXA2xxDMAChannel),
-        VMSTATE_UINT32(cmd, PXA2xxDMAChannel),
-        VMSTATE_UINT32(state, PXA2xxDMAChannel),
-        VMSTATE_INT32(request, PXA2xxDMAChannel),
-        VMSTATE_END_OF_LIST(),
-    },
-};
-
-static VMStateDescription vmstate_pxa2xx_dma = {
-    .name = "pxa2xx_dma",
-    .version_id = 1,
-    .minimum_version_id = 0,
-    .minimum_version_id_old = 0,
-    .fields = (VMStateField[]) {
-        VMSTATE_UNUSED_TEST(is_version_0, 4),
-        VMSTATE_UINT32(stopintr, PXA2xxDMAState),
-        VMSTATE_UINT32(eorintr, PXA2xxDMAState),
-        VMSTATE_UINT32(rasintr, PXA2xxDMAState),
-        VMSTATE_UINT32(startintr, PXA2xxDMAState),
-        VMSTATE_UINT32(endintr, PXA2xxDMAState),
-        VMSTATE_UINT32(align, PXA2xxDMAState),
-        VMSTATE_UINT32(pio, PXA2xxDMAState),
-        VMSTATE_BUFFER(req, PXA2xxDMAState),
-        VMSTATE_STRUCT_VARRAY_POINTER_INT32(chan, PXA2xxDMAState, channels,
-                vmstate_pxa2xx_dma_chan, PXA2xxDMAChannel),
-        VMSTATE_END_OF_LIST(),
-    },
-};
-
-static Property pxa2xx_dma_properties[] = {
-    DEFINE_PROP_INT32("channels", PXA2xxDMAState, channels, -1),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void pxa2xx_dma_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = pxa2xx_dma_init;
-    dc->desc = "PXA2xx DMA controller";
-    dc->vmsd = &vmstate_pxa2xx_dma;
-    dc->props = pxa2xx_dma_properties;
-}
-
-static const 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_types(void)
-{
-    type_register_static(&pxa2xx_dma_info);
-}
-
-type_init(pxa2xx_dma_register_types)
diff --git a/hw/pxa2xx_keypad.c b/hw/pxa2xx_keypad.c
deleted file mode 100644 (file)
index 32ea7a5..0000000
+++ /dev/null
@@ -1,335 +0,0 @@
-/*
- * Intel PXA27X Keypad Controller emulation.
- *
- * Copyright (c) 2007 MontaVista Software, Inc
- * Written by Armin Kuster <akuster@kama-aina.net>
- *              or  <Akuster@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/hw.h"
-#include "hw/pxa.h"
-#include "ui/console.h"
-
-/*
- * Keypad
- */
-#define KPC         0x00    /* Keypad Interface Control register */
-#define KPDK        0x08    /* Keypad Interface Direct Key register */
-#define KPREC       0x10    /* Keypad Interface Rotary Encoder register */
-#define KPMK        0x18    /* Keypad Interface Matrix Key register */
-#define KPAS        0x20    /* Keypad Interface Automatic Scan register */
-#define KPASMKP0    0x28    /* Keypad Interface Automatic Scan Multiple
-                                Key Presser register 0 */
-#define KPASMKP1    0x30    /* Keypad Interface Automatic Scan Multiple
-                                Key Presser register 1 */
-#define KPASMKP2    0x38    /* Keypad Interface Automatic Scan Multiple
-                                Key Presser register 2 */
-#define KPASMKP3    0x40    /* Keypad Interface Automatic Scan Multiple
-                                Key Presser register 3 */
-#define KPKDI       0x48    /* Keypad Interface Key Debounce Interval
-                                register */
-
-/* Keypad defines */
-#define KPC_AS          (0x1 << 30)  /* Automatic Scan bit */
-#define KPC_ASACT       (0x1 << 29)  /* Automatic Scan on Activity */
-#define KPC_MI          (0x1 << 22)  /* Matrix interrupt bit */
-#define KPC_IMKP        (0x1 << 21)  /* Ignore Multiple Key Press */
-#define KPC_MS7         (0x1 << 20)  /* Matrix scan line 7 */
-#define KPC_MS6         (0x1 << 19)  /* Matrix scan line 6 */
-#define KPC_MS5         (0x1 << 18)  /* Matrix scan line 5 */
-#define KPC_MS4         (0x1 << 17)  /* Matrix scan line 4 */
-#define KPC_MS3         (0x1 << 16)  /* Matrix scan line 3 */
-#define KPC_MS2         (0x1 << 15)  /* Matrix scan line 2 */
-#define KPC_MS1         (0x1 << 14)  /* Matrix scan line 1 */
-#define KPC_MS0         (0x1 << 13)  /* Matrix scan line 0 */
-#define KPC_ME          (0x1 << 12)  /* Matrix Keypad Enable */
-#define KPC_MIE         (0x1 << 11)  /* Matrix Interrupt Enable */
-#define KPC_DK_DEB_SEL  (0x1 <<  9)  /* Direct Keypad Debounce Select */
-#define KPC_DI          (0x1 <<  5)  /* Direct key interrupt bit */
-#define KPC_RE_ZERO_DEB (0x1 <<  4)  /* Rotary Encoder Zero Debounce */
-#define KPC_REE1        (0x1 <<  3)  /* Rotary Encoder1 Enable */
-#define KPC_REE0        (0x1 <<  2)  /* Rotary Encoder0 Enable */
-#define KPC_DE          (0x1 <<  1)  /* Direct Keypad Enable */
-#define KPC_DIE         (0x1 <<  0)  /* Direct Keypad interrupt Enable */
-
-#define KPDK_DKP        (0x1 << 31)
-#define KPDK_DK7        (0x1 <<  7)
-#define KPDK_DK6        (0x1 <<  6)
-#define KPDK_DK5        (0x1 <<  5)
-#define KPDK_DK4        (0x1 <<  4)
-#define KPDK_DK3        (0x1 <<  3)
-#define KPDK_DK2        (0x1 <<  2)
-#define KPDK_DK1        (0x1 <<  1)
-#define KPDK_DK0        (0x1 <<  0)
-
-#define KPREC_OF1       (0x1 << 31)
-#define KPREC_UF1       (0x1 << 30)
-#define KPREC_OF0       (0x1 << 15)
-#define KPREC_UF0       (0x1 << 14)
-
-#define KPMK_MKP        (0x1 << 31)
-#define KPAS_SO         (0x1 << 31)
-#define KPASMKPx_SO     (0x1 << 31)
-
-
-#define KPASMKPx_MKC(row, col)  (1 << (row + 16 * (col % 2)))
-
-#define PXAKBD_MAXROW   8
-#define PXAKBD_MAXCOL   8
-
-struct PXA2xxKeyPadState {
-    MemoryRegion iomem;
-    qemu_irq    irq;
-    struct  keymap *map;
-    int         pressed_cnt;
-    int         alt_code;
-
-    uint32_t    kpc;
-    uint32_t    kpdk;
-    uint32_t    kprec;
-    uint32_t    kpmk;
-    uint32_t    kpas;
-    uint32_t    kpasmkp[4];
-    uint32_t    kpkdi;
-};
-
-static void pxa27x_keypad_find_pressed_key(PXA2xxKeyPadState *kp, int *row, int *col)
-{
-    int i;
-    for (i = 0; i < 4; i++)
-    {
-        *col = i * 2;
-        for (*row = 0; *row < 8; (*row)++) {
-            if (kp->kpasmkp[i] & (1 << *row))
-                return;
-        }
-        *col = i * 2 + 1;
-        for (*row = 0; *row < 8; (*row)++) {
-            if (kp->kpasmkp[i] & (1 << (*row + 16)))
-                return;
-        }
-    }
-}
-
-static void pxa27x_keyboard_event (PXA2xxKeyPadState *kp, int keycode)
-{
-    int row, col, rel, assert_irq = 0;
-    uint32_t val;
-
-    if (keycode == 0xe0) {
-        kp->alt_code = 1;
-        return;
-    }
-
-    if(!(kp->kpc & KPC_ME)) /* skip if not enabled */
-        return;
-
-    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;
-    }
-
-    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;
-        }
-    }
-    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;
-
-    if (assert_irq && (kp->kpc & KPC_MIE)) {
-        kp->kpc |= KPC_MI;
-        qemu_irq_raise(kp->irq);
-    }
-}
-
-static uint64_t pxa2xx_keypad_read(void *opaque, hwaddr offset,
-                                   unsigned size)
-{
-    PXA2xxKeyPadState *s = (PXA2xxKeyPadState *) opaque;
-    uint32_t tmp;
-
-    switch (offset) {
-    case KPC:
-        tmp = s->kpc;
-        if(tmp & KPC_MI)
-            s->kpc &= ~(KPC_MI);
-        if(tmp & KPC_DI)
-            s->kpc &= ~(KPC_DI);
-        qemu_irq_lower(s->irq);
-        return tmp;
-        break;
-    case KPDK:
-        return s->kpdk;
-        break;
-    case KPREC:
-        tmp = s->kprec;
-        if(tmp & KPREC_OF1)
-            s->kprec &= ~(KPREC_OF1);
-        if(tmp & KPREC_UF1)
-            s->kprec &= ~(KPREC_UF1);
-        if(tmp & KPREC_OF0)
-            s->kprec &= ~(KPREC_OF0);
-        if(tmp & KPREC_UF0)
-            s->kprec &= ~(KPREC_UF0);
-        return tmp;
-        break;
-    case KPMK:
-        tmp = s->kpmk;
-        if(tmp & KPMK_MKP)
-            s->kpmk &= ~(KPMK_MKP);
-        return tmp;
-        break;
-    case KPAS:
-        return s->kpas;
-        break;
-    case KPASMKP0:
-        return s->kpasmkp[0];
-        break;
-    case KPASMKP1:
-        return s->kpasmkp[1];
-        break;
-    case KPASMKP2:
-        return s->kpasmkp[2];
-        break;
-    case KPASMKP3:
-        return s->kpasmkp[3];
-        break;
-    case KPKDI:
-        return s->kpkdi;
-        break;
-    default:
-        hw_error("%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset);
-    }
-
-    return 0;
-}
-
-static void pxa2xx_keypad_write(void *opaque, hwaddr offset,
-                                uint64_t value, unsigned size)
-{
-    PXA2xxKeyPadState *s = (PXA2xxKeyPadState *) opaque;
-
-    switch (offset) {
-    case KPC:
-        s->kpc = value;
-        if (s->kpc & KPC_AS) {
-            s->kpc &= ~(KPC_AS);
-        }
-        break;
-    case KPDK:
-        s->kpdk = value;
-        break;
-    case KPREC:
-        s->kprec = value;
-        break;
-    case KPMK:
-        s->kpmk = value;
-        break;
-    case KPAS:
-        s->kpas = value;
-        break;
-    case KPASMKP0:
-        s->kpasmkp[0] = value;
-        break;
-    case KPASMKP1:
-        s->kpasmkp[1] = value;
-        break;
-    case KPASMKP2:
-        s->kpasmkp[2] = value;
-        break;
-    case KPASMKP3:
-        s->kpasmkp[3] = value;
-        break;
-    case KPKDI:
-        s->kpkdi = value;
-        break;
-
-    default:
-        hw_error("%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset);
-    }
-}
-
-static const MemoryRegionOps pxa2xx_keypad_ops = {
-    .read = pxa2xx_keypad_read,
-    .write = pxa2xx_keypad_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static const VMStateDescription vmstate_pxa2xx_keypad = {
-    .name = "pxa2xx_keypad",
-    .version_id = 0,
-    .minimum_version_id = 0,
-    .minimum_version_id_old = 0,
-    .fields      = (VMStateField[]) {
-        VMSTATE_UINT32(kpc, PXA2xxKeyPadState),
-        VMSTATE_UINT32(kpdk, PXA2xxKeyPadState),
-        VMSTATE_UINT32(kprec, PXA2xxKeyPadState),
-        VMSTATE_UINT32(kpmk, PXA2xxKeyPadState),
-        VMSTATE_UINT32(kpas, PXA2xxKeyPadState),
-        VMSTATE_UINT32_ARRAY(kpasmkp, PXA2xxKeyPadState, 4),
-        VMSTATE_UINT32(kpkdi, PXA2xxKeyPadState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-PXA2xxKeyPadState *pxa27x_keypad_init(MemoryRegion *sysmem,
-                                      hwaddr base,
-                                      qemu_irq irq)
-{
-    PXA2xxKeyPadState *s;
-
-    s = (PXA2xxKeyPadState *) g_malloc0(sizeof(PXA2xxKeyPadState));
-    s->irq = irq;
-
-    memory_region_init_io(&s->iomem, &pxa2xx_keypad_ops, s,
-                          "pxa2xx-keypad", 0x00100000);
-    memory_region_add_subregion(sysmem, base, &s->iomem);
-
-    vmstate_register(NULL, 0, &vmstate_pxa2xx_keypad, s);
-
-    return s;
-}
-
-void pxa27x_register_keypad(PXA2xxKeyPadState *kp, struct keymap *map,
-        int size)
-{
-    if(!map || size < 0x80) {
-        fprintf(stderr, "%s - No PXA keypad map defined\n", __FUNCTION__);
-        exit(-1);
-    }
-
-    kp->map = map;
-    qemu_add_kbd_event_handler((QEMUPutKBDEvent *) pxa27x_keyboard_event, kp);
-}
diff --git a/hw/pxa2xx_lcd.c b/hw/pxa2xx_lcd.c
deleted file mode 100644 (file)
index f2b0c93..0000000
+++ /dev/null
@@ -1,1058 +0,0 @@
-/*
- * Intel XScale PXA255/270 LCDC emulation.
- *
- * Copyright (c) 2006 Openedhand Ltd.
- * Written by Andrzej Zaborowski <balrog@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/hw.h"
-#include "ui/console.h"
-#include "hw/pxa.h"
-#include "ui/pixel_ops.h"
-/* FIXME: For graphic_rotate. Should probably be done in common code.  */
-#include "sysemu/sysemu.h"
-#include "hw/framebuffer.h"
-
-struct DMAChannel {
-    uint32_t branch;
-    uint8_t up;
-    uint8_t palette[1024];
-    uint8_t pbuffer[1024];
-    void (*redraw)(PXA2xxLCDState *s, hwaddr addr,
-                   int *miny, int *maxy);
-
-    uint32_t descriptor;
-    uint32_t source;
-    uint32_t id;
-    uint32_t command;
-};
-
-struct PXA2xxLCDState {
-    MemoryRegion *sysmem;
-    MemoryRegion iomem;
-    qemu_irq irq;
-    int irqlevel;
-
-    int invalidated;
-    QemuConsole *con;
-    drawfn *line_fn[2];
-    int dest_width;
-    int xres, yres;
-    int pal_for;
-    int transp;
-    enum {
-        pxa_lcdc_2bpp = 1,
-        pxa_lcdc_4bpp = 2,
-        pxa_lcdc_8bpp = 3,
-        pxa_lcdc_16bpp = 4,
-        pxa_lcdc_18bpp = 5,
-        pxa_lcdc_18pbpp = 6,
-        pxa_lcdc_19bpp = 7,
-        pxa_lcdc_19pbpp = 8,
-        pxa_lcdc_24bpp = 9,
-        pxa_lcdc_25bpp = 10,
-    } bpp;
-
-    uint32_t control[6];
-    uint32_t status[2];
-    uint32_t ovl1c[2];
-    uint32_t ovl2c[2];
-    uint32_t ccr;
-    uint32_t cmdcr;
-    uint32_t trgbr;
-    uint32_t tcr;
-    uint32_t liidr;
-    uint8_t bscntr;
-
-    struct DMAChannel dma_ch[7];
-
-    qemu_irq vsync_cb;
-    int orientation;
-};
-
-typedef struct QEMU_PACKED {
-    uint32_t fdaddr;
-    uint32_t fsaddr;
-    uint32_t fidr;
-    uint32_t ldcmd;
-} PXAFrameDescriptor;
-
-#define LCCR0  0x000   /* LCD Controller Control register 0 */
-#define LCCR1  0x004   /* LCD Controller Control register 1 */
-#define LCCR2  0x008   /* LCD Controller Control register 2 */
-#define LCCR3  0x00c   /* LCD Controller Control register 3 */
-#define LCCR4  0x010   /* LCD Controller Control register 4 */
-#define LCCR5  0x014   /* LCD Controller Control register 5 */
-
-#define FBR0   0x020   /* DMA Channel 0 Frame Branch register */
-#define FBR1   0x024   /* DMA Channel 1 Frame Branch register */
-#define FBR2   0x028   /* DMA Channel 2 Frame Branch register */
-#define FBR3   0x02c   /* DMA Channel 3 Frame Branch register */
-#define FBR4   0x030   /* DMA Channel 4 Frame Branch register */
-#define FBR5   0x110   /* DMA Channel 5 Frame Branch register */
-#define FBR6   0x114   /* DMA Channel 6 Frame Branch register */
-
-#define LCSR1  0x034   /* LCD Controller Status register 1 */
-#define LCSR0  0x038   /* LCD Controller Status register 0 */
-#define LIIDR  0x03c   /* LCD Controller Interrupt ID register */
-
-#define TRGBR  0x040   /* TMED RGB Seed register */
-#define TCR    0x044   /* TMED Control register */
-
-#define OVL1C1 0x050   /* Overlay 1 Control register 1 */
-#define OVL1C2 0x060   /* Overlay 1 Control register 2 */
-#define OVL2C1 0x070   /* Overlay 2 Control register 1 */
-#define OVL2C2 0x080   /* Overlay 2 Control register 2 */
-#define CCR    0x090   /* Cursor Control register */
-
-#define CMDCR  0x100   /* Command Control register */
-#define PRSR   0x104   /* Panel Read Status register */
-
-#define PXA_LCDDMA_CHANS       7
-#define DMA_FDADR              0x00    /* Frame Descriptor Address register */
-#define DMA_FSADR              0x04    /* Frame Source Address register */
-#define DMA_FIDR               0x08    /* Frame ID register */
-#define DMA_LDCMD              0x0c    /* Command register */
-
-/* LCD Buffer Strength Control register */
-#define BSCNTR 0x04000054
-
-/* Bitfield masks */
-#define LCCR0_ENB      (1 << 0)
-#define LCCR0_CMS      (1 << 1)
-#define LCCR0_SDS      (1 << 2)
-#define LCCR0_LDM      (1 << 3)
-#define LCCR0_SOFM0    (1 << 4)
-#define LCCR0_IUM      (1 << 5)
-#define LCCR0_EOFM0    (1 << 6)
-#define LCCR0_PAS      (1 << 7)
-#define LCCR0_DPD      (1 << 9)
-#define LCCR0_DIS      (1 << 10)
-#define LCCR0_QDM      (1 << 11)
-#define LCCR0_PDD      (0xff << 12)
-#define LCCR0_BSM0     (1 << 20)
-#define LCCR0_OUM      (1 << 21)
-#define LCCR0_LCDT     (1 << 22)
-#define LCCR0_RDSTM    (1 << 23)
-#define LCCR0_CMDIM    (1 << 24)
-#define LCCR0_OUC      (1 << 25)
-#define LCCR0_LDDALT   (1 << 26)
-#define LCCR1_PPL(x)   ((x) & 0x3ff)
-#define LCCR2_LPP(x)   ((x) & 0x3ff)
-#define LCCR3_API      (15 << 16)
-#define LCCR3_BPP(x)   ((((x) >> 24) & 7) | (((x) >> 26) & 8))
-#define LCCR3_PDFOR(x) (((x) >> 30) & 3)
-#define LCCR4_K1(x)    (((x) >> 0) & 7)
-#define LCCR4_K2(x)    (((x) >> 3) & 7)
-#define LCCR4_K3(x)    (((x) >> 6) & 7)
-#define LCCR4_PALFOR(x)        (((x) >> 15) & 3)
-#define LCCR5_SOFM(ch) (1 << (ch - 1))
-#define LCCR5_EOFM(ch) (1 << (ch + 7))
-#define LCCR5_BSM(ch)  (1 << (ch + 15))
-#define LCCR5_IUM(ch)  (1 << (ch + 23))
-#define OVLC1_EN       (1 << 31)
-#define CCR_CEN                (1 << 31)
-#define FBR_BRA                (1 << 0)
-#define FBR_BINT       (1 << 1)
-#define FBR_SRCADDR    (0xfffffff << 4)
-#define LCSR0_LDD      (1 << 0)
-#define LCSR0_SOF0     (1 << 1)
-#define LCSR0_BER      (1 << 2)
-#define LCSR0_ABC      (1 << 3)
-#define LCSR0_IU0      (1 << 4)
-#define LCSR0_IU1      (1 << 5)
-#define LCSR0_OU       (1 << 6)
-#define LCSR0_QD       (1 << 7)
-#define LCSR0_EOF0     (1 << 8)
-#define LCSR0_BS0      (1 << 9)
-#define LCSR0_SINT     (1 << 10)
-#define LCSR0_RDST     (1 << 11)
-#define LCSR0_CMDINT   (1 << 12)
-#define LCSR0_BERCH(x) (((x) & 7) << 28)
-#define LCSR1_SOF(ch)  (1 << (ch - 1))
-#define LCSR1_EOF(ch)  (1 << (ch + 7))
-#define LCSR1_BS(ch)   (1 << (ch + 15))
-#define LCSR1_IU(ch)   (1 << (ch + 23))
-#define LDCMD_LENGTH(x)        ((x) & 0x001ffffc)
-#define LDCMD_EOFINT   (1 << 21)
-#define LDCMD_SOFINT   (1 << 22)
-#define LDCMD_PAL      (1 << 26)
-
-/* Route internal interrupt lines to the global IC */
-static void pxa2xx_lcdc_int_update(PXA2xxLCDState *s)
-{
-    int level = 0;
-    level |= (s->status[0] & LCSR0_LDD)    && !(s->control[0] & LCCR0_LDM);
-    level |= (s->status[0] & LCSR0_SOF0)   && !(s->control[0] & LCCR0_SOFM0);
-    level |= (s->status[0] & LCSR0_IU0)    && !(s->control[0] & LCCR0_IUM);
-    level |= (s->status[0] & LCSR0_IU1)    && !(s->control[5] & LCCR5_IUM(1));
-    level |= (s->status[0] & LCSR0_OU)     && !(s->control[0] & LCCR0_OUM);
-    level |= (s->status[0] & LCSR0_QD)     && !(s->control[0] & LCCR0_QDM);
-    level |= (s->status[0] & LCSR0_EOF0)   && !(s->control[0] & LCCR0_EOFM0);
-    level |= (s->status[0] & LCSR0_BS0)    && !(s->control[0] & LCCR0_BSM0);
-    level |= (s->status[0] & LCSR0_RDST)   && !(s->control[0] & LCCR0_RDSTM);
-    level |= (s->status[0] & LCSR0_CMDINT) && !(s->control[0] & LCCR0_CMDIM);
-    level |= (s->status[1] & ~s->control[5]);
-
-    qemu_set_irq(s->irq, !!level);
-    s->irqlevel = level;
-}
-
-/* Set Branch Status interrupt high and poke associated registers */
-static inline void pxa2xx_dma_bs_set(PXA2xxLCDState *s, int ch)
-{
-    int unmasked;
-    if (ch == 0) {
-        s->status[0] |= LCSR0_BS0;
-        unmasked = !(s->control[0] & LCCR0_BSM0);
-    } else {
-        s->status[1] |= LCSR1_BS(ch);
-        unmasked = !(s->control[5] & LCCR5_BSM(ch));
-    }
-
-    if (unmasked) {
-        if (s->irqlevel)
-            s->status[0] |= LCSR0_SINT;
-        else
-            s->liidr = s->dma_ch[ch].id;
-    }
-}
-
-/* Set Start Of Frame Status interrupt high and poke associated registers */
-static inline void pxa2xx_dma_sof_set(PXA2xxLCDState *s, int ch)
-{
-    int unmasked;
-    if (!(s->dma_ch[ch].command & LDCMD_SOFINT))
-        return;
-
-    if (ch == 0) {
-        s->status[0] |= LCSR0_SOF0;
-        unmasked = !(s->control[0] & LCCR0_SOFM0);
-    } else {
-        s->status[1] |= LCSR1_SOF(ch);
-        unmasked = !(s->control[5] & LCCR5_SOFM(ch));
-    }
-
-    if (unmasked) {
-        if (s->irqlevel)
-            s->status[0] |= LCSR0_SINT;
-        else
-            s->liidr = s->dma_ch[ch].id;
-    }
-}
-
-/* Set End Of Frame Status interrupt high and poke associated registers */
-static inline void pxa2xx_dma_eof_set(PXA2xxLCDState *s, int ch)
-{
-    int unmasked;
-    if (!(s->dma_ch[ch].command & LDCMD_EOFINT))
-        return;
-
-    if (ch == 0) {
-        s->status[0] |= LCSR0_EOF0;
-        unmasked = !(s->control[0] & LCCR0_EOFM0);
-    } else {
-        s->status[1] |= LCSR1_EOF(ch);
-        unmasked = !(s->control[5] & LCCR5_EOFM(ch));
-    }
-
-    if (unmasked) {
-        if (s->irqlevel)
-            s->status[0] |= LCSR0_SINT;
-        else
-            s->liidr = s->dma_ch[ch].id;
-    }
-}
-
-/* Set Bus Error Status interrupt high and poke associated registers */
-static inline void pxa2xx_dma_ber_set(PXA2xxLCDState *s, int ch)
-{
-    s->status[0] |= LCSR0_BERCH(ch) | LCSR0_BER;
-    if (s->irqlevel)
-        s->status[0] |= LCSR0_SINT;
-    else
-        s->liidr = s->dma_ch[ch].id;
-}
-
-/* Set Read Status interrupt high and poke associated registers */
-static inline void pxa2xx_dma_rdst_set(PXA2xxLCDState *s)
-{
-    s->status[0] |= LCSR0_RDST;
-    if (s->irqlevel && !(s->control[0] & LCCR0_RDSTM))
-        s->status[0] |= LCSR0_SINT;
-}
-
-/* Load new Frame Descriptors from DMA */
-static void pxa2xx_descriptor_load(PXA2xxLCDState *s)
-{
-    PXAFrameDescriptor desc;
-    hwaddr descptr;
-    int i;
-
-    for (i = 0; i < PXA_LCDDMA_CHANS; i ++) {
-        s->dma_ch[i].source = 0;
-
-        if (!s->dma_ch[i].up)
-            continue;
-
-        if (s->dma_ch[i].branch & FBR_BRA) {
-            descptr = s->dma_ch[i].branch & FBR_SRCADDR;
-            if (s->dma_ch[i].branch & FBR_BINT)
-                pxa2xx_dma_bs_set(s, i);
-            s->dma_ch[i].branch &= ~FBR_BRA;
-        } else
-            descptr = s->dma_ch[i].descriptor;
-
-        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);
-        s->dma_ch[i].source = tswap32(desc.fsaddr);
-        s->dma_ch[i].id = tswap32(desc.fidr);
-        s->dma_ch[i].command = tswap32(desc.ldcmd);
-    }
-}
-
-static uint64_t pxa2xx_lcdc_read(void *opaque, hwaddr offset,
-                                 unsigned size)
-{
-    PXA2xxLCDState *s = (PXA2xxLCDState *) opaque;
-    int ch;
-
-    switch (offset) {
-    case LCCR0:
-        return s->control[0];
-    case LCCR1:
-        return s->control[1];
-    case LCCR2:
-        return s->control[2];
-    case LCCR3:
-        return s->control[3];
-    case LCCR4:
-        return s->control[4];
-    case LCCR5:
-        return s->control[5];
-
-    case OVL1C1:
-        return s->ovl1c[0];
-    case OVL1C2:
-        return s->ovl1c[1];
-    case OVL2C1:
-        return s->ovl2c[0];
-    case OVL2C2:
-        return s->ovl2c[1];
-
-    case CCR:
-        return s->ccr;
-
-    case CMDCR:
-        return s->cmdcr;
-
-    case TRGBR:
-        return s->trgbr;
-    case TCR:
-        return s->tcr;
-
-    case 0x200 ... 0x1000:     /* DMA per-channel registers */
-        ch = (offset - 0x200) >> 4;
-        if (!(ch >= 0 && ch < PXA_LCDDMA_CHANS))
-            goto fail;
-
-        switch (offset & 0xf) {
-        case DMA_FDADR:
-            return s->dma_ch[ch].descriptor;
-        case DMA_FSADR:
-            return s->dma_ch[ch].source;
-        case DMA_FIDR:
-            return s->dma_ch[ch].id;
-        case DMA_LDCMD:
-            return s->dma_ch[ch].command;
-        default:
-            goto fail;
-        }
-
-    case FBR0:
-        return s->dma_ch[0].branch;
-    case FBR1:
-        return s->dma_ch[1].branch;
-    case FBR2:
-        return s->dma_ch[2].branch;
-    case FBR3:
-        return s->dma_ch[3].branch;
-    case FBR4:
-        return s->dma_ch[4].branch;
-    case FBR5:
-        return s->dma_ch[5].branch;
-    case FBR6:
-        return s->dma_ch[6].branch;
-
-    case BSCNTR:
-        return s->bscntr;
-
-    case PRSR:
-        return 0;
-
-    case LCSR0:
-        return s->status[0];
-    case LCSR1:
-        return s->status[1];
-    case LIIDR:
-        return s->liidr;
-
-    default:
-    fail:
-        hw_error("%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset);
-    }
-
-    return 0;
-}
-
-static void pxa2xx_lcdc_write(void *opaque, hwaddr offset,
-                              uint64_t value, unsigned size)
-{
-    PXA2xxLCDState *s = (PXA2xxLCDState *) opaque;
-    int ch;
-
-    switch (offset) {
-    case LCCR0:
-        /* ACK Quick Disable done */
-        if ((s->control[0] & LCCR0_ENB) && !(value & LCCR0_ENB))
-            s->status[0] |= LCSR0_QD;
-
-        if (!(s->control[0] & LCCR0_LCDT) && (value & LCCR0_LCDT))
-            printf("%s: internal frame buffer unsupported\n", __FUNCTION__);
-
-        if ((s->control[3] & LCCR3_API) &&
-                (value & LCCR0_ENB) && !(value & LCCR0_LCDT))
-            s->status[0] |= LCSR0_ABC;
-
-        s->control[0] = value & 0x07ffffff;
-        pxa2xx_lcdc_int_update(s);
-
-        s->dma_ch[0].up = !!(value & LCCR0_ENB);
-        s->dma_ch[1].up = (s->ovl1c[0] & OVLC1_EN) || (value & LCCR0_SDS);
-        break;
-
-    case LCCR1:
-        s->control[1] = value;
-        break;
-
-    case LCCR2:
-        s->control[2] = value;
-        break;
-
-    case LCCR3:
-        s->control[3] = value & 0xefffffff;
-        s->bpp = LCCR3_BPP(value);
-        break;
-
-    case LCCR4:
-        s->control[4] = value & 0x83ff81ff;
-        break;
-
-    case LCCR5:
-        s->control[5] = value & 0x3f3f3f3f;
-        break;
-
-    case OVL1C1:
-        if (!(s->ovl1c[0] & OVLC1_EN) && (value & OVLC1_EN))
-            printf("%s: Overlay 1 not supported\n", __FUNCTION__);
-
-        s->ovl1c[0] = value & 0x80ffffff;
-        s->dma_ch[1].up = (value & OVLC1_EN) || (s->control[0] & LCCR0_SDS);
-        break;
-
-    case OVL1C2:
-        s->ovl1c[1] = value & 0x000fffff;
-        break;
-
-    case OVL2C1:
-        if (!(s->ovl2c[0] & OVLC1_EN) && (value & OVLC1_EN))
-            printf("%s: Overlay 2 not supported\n", __FUNCTION__);
-
-        s->ovl2c[0] = value & 0x80ffffff;
-        s->dma_ch[2].up = !!(value & OVLC1_EN);
-        s->dma_ch[3].up = !!(value & OVLC1_EN);
-        s->dma_ch[4].up = !!(value & OVLC1_EN);
-        break;
-
-    case OVL2C2:
-        s->ovl2c[1] = value & 0x007fffff;
-        break;
-
-    case CCR:
-        if (!(s->ccr & CCR_CEN) && (value & CCR_CEN))
-            printf("%s: Hardware cursor unimplemented\n", __FUNCTION__);
-
-        s->ccr = value & 0x81ffffe7;
-        s->dma_ch[5].up = !!(value & CCR_CEN);
-        break;
-
-    case CMDCR:
-        s->cmdcr = value & 0xff;
-        break;
-
-    case TRGBR:
-        s->trgbr = value & 0x00ffffff;
-        break;
-
-    case TCR:
-        s->tcr = value & 0x7fff;
-        break;
-
-    case 0x200 ... 0x1000:     /* DMA per-channel registers */
-        ch = (offset - 0x200) >> 4;
-        if (!(ch >= 0 && ch < PXA_LCDDMA_CHANS))
-            goto fail;
-
-        switch (offset & 0xf) {
-        case DMA_FDADR:
-            s->dma_ch[ch].descriptor = value & 0xfffffff0;
-            break;
-
-        default:
-            goto fail;
-        }
-        break;
-
-    case FBR0:
-        s->dma_ch[0].branch = value & 0xfffffff3;
-        break;
-    case FBR1:
-        s->dma_ch[1].branch = value & 0xfffffff3;
-        break;
-    case FBR2:
-        s->dma_ch[2].branch = value & 0xfffffff3;
-        break;
-    case FBR3:
-        s->dma_ch[3].branch = value & 0xfffffff3;
-        break;
-    case FBR4:
-        s->dma_ch[4].branch = value & 0xfffffff3;
-        break;
-    case FBR5:
-        s->dma_ch[5].branch = value & 0xfffffff3;
-        break;
-    case FBR6:
-        s->dma_ch[6].branch = value & 0xfffffff3;
-        break;
-
-    case BSCNTR:
-        s->bscntr = value & 0xf;
-        break;
-
-    case PRSR:
-        break;
-
-    case LCSR0:
-        s->status[0] &= ~(value & 0xfff);
-        if (value & LCSR0_BER)
-            s->status[0] &= ~LCSR0_BERCH(7);
-        break;
-
-    case LCSR1:
-        s->status[1] &= ~(value & 0x3e3f3f);
-        break;
-
-    default:
-    fail:
-        hw_error("%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset);
-    }
-}
-
-static const MemoryRegionOps pxa2xx_lcdc_ops = {
-    .read = pxa2xx_lcdc_read,
-    .write = pxa2xx_lcdc_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-/* Load new palette for a given DMA channel, convert to internal format */
-static void pxa2xx_palette_parse(PXA2xxLCDState *s, int ch, int bpp)
-{
-    DisplaySurface *surface = qemu_console_surface(s->con);
-    int i, n, format, r, g, b, alpha;
-    uint32_t *dest;
-    uint8_t *src;
-    s->pal_for = LCCR4_PALFOR(s->control[4]);
-    format = s->pal_for;
-
-    switch (bpp) {
-    case pxa_lcdc_2bpp:
-        n = 4;
-        break;
-    case pxa_lcdc_4bpp:
-        n = 16;
-        break;
-    case pxa_lcdc_8bpp:
-        n = 256;
-        break;
-    default:
-        format = 0;
-        return;
-    }
-
-    src = (uint8_t *) s->dma_ch[ch].pbuffer;
-    dest = (uint32_t *) s->dma_ch[ch].palette;
-    alpha = r = g = b = 0;
-
-    for (i = 0; i < n; i ++) {
-        switch (format) {
-        case 0: /* 16 bpp, no transparency */
-            alpha = 0;
-            if (s->control[0] & LCCR0_CMS) {
-                r = g = b = *(uint16_t *) src & 0xff;
-            }
-            else {
-                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 = *(uint16_t *) src & (1 << 24);
-            if (s->control[0] & LCCR0_CMS)
-                r = g = b = *(uint16_t *) src & 0xff;
-            else {
-                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 = *(uint32_t *) src & (1 << 24);
-            if (s->control[0] & LCCR0_CMS)
-                r = g = b = *(uint32_t *) src & 0xff;
-            else {
-                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 = *(uint32_t *) src & (1 << 24);
-            if (s->control[0] & LCCR0_CMS)
-                r = g = b = *(uint32_t *) src & 0xff;
-            else {
-                r = (*(uint32_t *) src & 0xff0000) >> 16;
-                g = (*(uint32_t *) src & 0x00ff00) >> 8;
-                b = (*(uint32_t *) src & 0x0000ff);
-            }
-            src += 4;
-            break;
-        }
-        switch (surface_bits_per_pixel(surface)) {
-        case 8:
-            *dest = rgb_to_pixel8(r, g, b) | alpha;
-            break;
-        case 15:
-            *dest = rgb_to_pixel15(r, g, b) | alpha;
-            break;
-        case 16:
-            *dest = rgb_to_pixel16(r, g, b) | alpha;
-            break;
-        case 24:
-            *dest = rgb_to_pixel24(r, g, b) | alpha;
-            break;
-        case 32:
-            *dest = rgb_to_pixel32(r, g, b) | alpha;
-            break;
-        }
-        dest ++;
-    }
-}
-
-static void pxa2xx_lcdc_dma0_redraw_rot0(PXA2xxLCDState *s,
-                hwaddr addr, int *miny, int *maxy)
-{
-    DisplaySurface *surface = qemu_console_surface(s->con);
-    int src_width, dest_width;
-    drawfn fn = NULL;
-    if (s->dest_width)
-        fn = s->line_fn[s->transp][s->bpp];
-    if (!fn)
-        return;
-
-    src_width = (s->xres + 3) & ~3;     /* Pad to a 4 pixels multiple */
-    if (s->bpp == pxa_lcdc_19pbpp || s->bpp == pxa_lcdc_18pbpp)
-        src_width *= 3;
-    else if (s->bpp > pxa_lcdc_16bpp)
-        src_width *= 4;
-    else if (s->bpp > pxa_lcdc_8bpp)
-        src_width *= 2;
-
-    dest_width = s->xres * s->dest_width;
-    *miny = 0;
-    framebuffer_update_display(surface, s->sysmem,
-                               addr, s->xres, s->yres,
-                               src_width, dest_width, s->dest_width,
-                               s->invalidated,
-                               fn, s->dma_ch[0].palette, miny, maxy);
-}
-
-static void pxa2xx_lcdc_dma0_redraw_rot90(PXA2xxLCDState *s,
-               hwaddr addr, int *miny, int *maxy)
-{
-    DisplaySurface *surface = qemu_console_surface(s->con);
-    int src_width, dest_width;
-    drawfn fn = NULL;
-    if (s->dest_width)
-        fn = s->line_fn[s->transp][s->bpp];
-    if (!fn)
-        return;
-
-    src_width = (s->xres + 3) & ~3;     /* Pad to a 4 pixels multiple */
-    if (s->bpp == pxa_lcdc_19pbpp || s->bpp == pxa_lcdc_18pbpp)
-        src_width *= 3;
-    else if (s->bpp > pxa_lcdc_16bpp)
-        src_width *= 4;
-    else if (s->bpp > pxa_lcdc_8bpp)
-        src_width *= 2;
-
-    dest_width = s->yres * s->dest_width;
-    *miny = 0;
-    framebuffer_update_display(surface, s->sysmem,
-                               addr, s->xres, s->yres,
-                               src_width, s->dest_width, -dest_width,
-                               s->invalidated,
-                               fn, s->dma_ch[0].palette,
-                               miny, maxy);
-}
-
-static void pxa2xx_lcdc_dma0_redraw_rot180(PXA2xxLCDState *s,
-                hwaddr addr, int *miny, int *maxy)
-{
-    DisplaySurface *surface = qemu_console_surface(s->con);
-    int src_width, dest_width;
-    drawfn fn = NULL;
-    if (s->dest_width) {
-        fn = s->line_fn[s->transp][s->bpp];
-    }
-    if (!fn) {
-        return;
-    }
-
-    src_width = (s->xres + 3) & ~3;     /* Pad to a 4 pixels multiple */
-    if (s->bpp == pxa_lcdc_19pbpp || s->bpp == pxa_lcdc_18pbpp) {
-        src_width *= 3;
-    } else if (s->bpp > pxa_lcdc_16bpp) {
-        src_width *= 4;
-    } else if (s->bpp > pxa_lcdc_8bpp) {
-        src_width *= 2;
-    }
-
-    dest_width = s->xres * s->dest_width;
-    *miny = 0;
-    framebuffer_update_display(surface, s->sysmem,
-                               addr, s->xres, s->yres,
-                               src_width, -dest_width, -s->dest_width,
-                               s->invalidated,
-                               fn, s->dma_ch[0].palette, miny, maxy);
-}
-
-static void pxa2xx_lcdc_dma0_redraw_rot270(PXA2xxLCDState *s,
-               hwaddr addr, int *miny, int *maxy)
-{
-    DisplaySurface *surface = qemu_console_surface(s->con);
-    int src_width, dest_width;
-    drawfn fn = NULL;
-    if (s->dest_width) {
-        fn = s->line_fn[s->transp][s->bpp];
-    }
-    if (!fn) {
-        return;
-    }
-
-    src_width = (s->xres + 3) & ~3;     /* Pad to a 4 pixels multiple */
-    if (s->bpp == pxa_lcdc_19pbpp || s->bpp == pxa_lcdc_18pbpp) {
-        src_width *= 3;
-    } else if (s->bpp > pxa_lcdc_16bpp) {
-        src_width *= 4;
-    } else if (s->bpp > pxa_lcdc_8bpp) {
-        src_width *= 2;
-    }
-
-    dest_width = s->yres * s->dest_width;
-    *miny = 0;
-    framebuffer_update_display(surface, s->sysmem,
-                               addr, s->xres, s->yres,
-                               src_width, -s->dest_width, dest_width,
-                               s->invalidated,
-                               fn, s->dma_ch[0].palette,
-                               miny, maxy);
-}
-
-static void pxa2xx_lcdc_resize(PXA2xxLCDState *s)
-{
-    int width, height;
-    if (!(s->control[0] & LCCR0_ENB))
-        return;
-
-    width = LCCR1_PPL(s->control[1]) + 1;
-    height = LCCR2_LPP(s->control[2]) + 1;
-
-    if (width != s->xres || height != s->yres) {
-        if (s->orientation == 90 || s->orientation == 270) {
-            qemu_console_resize(s->con, height, width);
-        } else {
-            qemu_console_resize(s->con, width, height);
-        }
-        s->invalidated = 1;
-        s->xres = width;
-        s->yres = height;
-    }
-}
-
-static void pxa2xx_update_display(void *opaque)
-{
-    PXA2xxLCDState *s = (PXA2xxLCDState *) opaque;
-    hwaddr fbptr;
-    int miny, maxy;
-    int ch;
-    if (!(s->control[0] & LCCR0_ENB))
-        return;
-
-    pxa2xx_descriptor_load(s);
-
-    pxa2xx_lcdc_resize(s);
-    miny = s->yres;
-    maxy = 0;
-    s->transp = s->dma_ch[2].up || s->dma_ch[3].up;
-    /* Note: With overlay planes the order depends on LCCR0 bit 25.  */
-    for (ch = 0; ch < PXA_LCDDMA_CHANS; ch ++)
-        if (s->dma_ch[ch].up) {
-            if (!s->dma_ch[ch].source) {
-                pxa2xx_dma_ber_set(s, ch);
-                continue;
-            }
-            fbptr = s->dma_ch[ch].source;
-            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;
-            }
-
-            if (s->dma_ch[ch].command & LDCMD_PAL) {
-                cpu_physical_memory_read(fbptr, s->dma_ch[ch].pbuffer,
-                    MAX(LDCMD_LENGTH(s->dma_ch[ch].command),
-                        sizeof(s->dma_ch[ch].pbuffer)));
-                pxa2xx_palette_parse(s, ch, s->bpp);
-            } else {
-                /* Do we need to reparse palette */
-                if (LCCR4_PALFOR(s->control[4]) != s->pal_for)
-                    pxa2xx_palette_parse(s, ch, s->bpp);
-
-                /* ACK frame start */
-                pxa2xx_dma_sof_set(s, ch);
-
-                s->dma_ch[ch].redraw(s, fbptr, &miny, &maxy);
-                s->invalidated = 0;
-
-                /* ACK frame completed */
-                pxa2xx_dma_eof_set(s, ch);
-            }
-        }
-
-    if (s->control[0] & LCCR0_DIS) {
-        /* ACK last frame completed */
-        s->control[0] &= ~LCCR0_ENB;
-        s->status[0] |= LCSR0_LDD;
-    }
-
-    if (miny >= 0) {
-        switch (s->orientation) {
-        case 0:
-            dpy_gfx_update(s->con, 0, miny, s->xres, maxy - miny + 1);
-            break;
-        case 90:
-            dpy_gfx_update(s->con, miny, 0, maxy - miny + 1, s->xres);
-            break;
-        case 180:
-            maxy = s->yres - maxy - 1;
-            miny = s->yres - miny - 1;
-            dpy_gfx_update(s->con, 0, maxy, s->xres, miny - maxy + 1);
-            break;
-        case 270:
-            maxy = s->yres - maxy - 1;
-            miny = s->yres - miny - 1;
-            dpy_gfx_update(s->con, maxy, 0, miny - maxy + 1, s->xres);
-            break;
-        }
-    }
-    pxa2xx_lcdc_int_update(s);
-
-    qemu_irq_raise(s->vsync_cb);
-}
-
-static void pxa2xx_invalidate_display(void *opaque)
-{
-    PXA2xxLCDState *s = (PXA2xxLCDState *) opaque;
-    s->invalidated = 1;
-}
-
-static void pxa2xx_lcdc_orientation(void *opaque, int angle)
-{
-    PXA2xxLCDState *s = (PXA2xxLCDState *) opaque;
-
-    switch (angle) {
-    case 0:
-        s->dma_ch[0].redraw = pxa2xx_lcdc_dma0_redraw_rot0;
-        break;
-    case 90:
-        s->dma_ch[0].redraw = pxa2xx_lcdc_dma0_redraw_rot90;
-        break;
-    case 180:
-        s->dma_ch[0].redraw = pxa2xx_lcdc_dma0_redraw_rot180;
-        break;
-    case 270:
-        s->dma_ch[0].redraw = pxa2xx_lcdc_dma0_redraw_rot270;
-        break;
-    }
-
-    s->orientation = angle;
-    s->xres = s->yres = -1;
-    pxa2xx_lcdc_resize(s);
-}
-
-static const VMStateDescription vmstate_dma_channel = {
-    .name = "dma_channel",
-    .version_id = 0,
-    .minimum_version_id = 0,
-    .minimum_version_id_old = 0,
-    .fields      = (VMStateField[]) {
-        VMSTATE_UINT32(branch, struct DMAChannel),
-        VMSTATE_UINT8(up, struct DMAChannel),
-        VMSTATE_BUFFER(pbuffer, struct DMAChannel),
-        VMSTATE_UINT32(descriptor, struct DMAChannel),
-        VMSTATE_UINT32(source, struct DMAChannel),
-        VMSTATE_UINT32(id, struct DMAChannel),
-        VMSTATE_UINT32(command, struct DMAChannel),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static int pxa2xx_lcdc_post_load(void *opaque, int version_id)
-{
-    PXA2xxLCDState *s = opaque;
-
-    s->bpp = LCCR3_BPP(s->control[3]);
-    s->xres = s->yres = s->pal_for = -1;
-
-    return 0;
-}
-
-static const VMStateDescription vmstate_pxa2xx_lcdc = {
-    .name = "pxa2xx_lcdc",
-    .version_id = 0,
-    .minimum_version_id = 0,
-    .minimum_version_id_old = 0,
-    .post_load = pxa2xx_lcdc_post_load,
-    .fields      = (VMStateField[]) {
-        VMSTATE_INT32(irqlevel, PXA2xxLCDState),
-        VMSTATE_INT32(transp, PXA2xxLCDState),
-        VMSTATE_UINT32_ARRAY(control, PXA2xxLCDState, 6),
-        VMSTATE_UINT32_ARRAY(status, PXA2xxLCDState, 2),
-        VMSTATE_UINT32_ARRAY(ovl1c, PXA2xxLCDState, 2),
-        VMSTATE_UINT32_ARRAY(ovl2c, PXA2xxLCDState, 2),
-        VMSTATE_UINT32(ccr, PXA2xxLCDState),
-        VMSTATE_UINT32(cmdcr, PXA2xxLCDState),
-        VMSTATE_UINT32(trgbr, PXA2xxLCDState),
-        VMSTATE_UINT32(tcr, PXA2xxLCDState),
-        VMSTATE_UINT32(liidr, PXA2xxLCDState),
-        VMSTATE_UINT8(bscntr, PXA2xxLCDState),
-        VMSTATE_STRUCT_ARRAY(dma_ch, PXA2xxLCDState, 7, 0,
-                             vmstate_dma_channel, struct DMAChannel),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-#define BITS 8
-#include "hw/pxa2xx_template.h"
-#define BITS 15
-#include "hw/pxa2xx_template.h"
-#define BITS 16
-#include "hw/pxa2xx_template.h"
-#define BITS 24
-#include "hw/pxa2xx_template.h"
-#define BITS 32
-#include "hw/pxa2xx_template.h"
-
-PXA2xxLCDState *pxa2xx_lcdc_init(MemoryRegion *sysmem,
-                                 hwaddr base, qemu_irq irq)
-{
-    PXA2xxLCDState *s;
-    DisplaySurface *surface;
-
-    s = (PXA2xxLCDState *) g_malloc0(sizeof(PXA2xxLCDState));
-    s->invalidated = 1;
-    s->irq = irq;
-    s->sysmem = sysmem;
-
-    pxa2xx_lcdc_orientation(s, graphic_rotate);
-
-    memory_region_init_io(&s->iomem, &pxa2xx_lcdc_ops, s,
-                          "pxa2xx-lcd-controller", 0x00100000);
-    memory_region_add_subregion(sysmem, base, &s->iomem);
-
-    s->con = graphic_console_init(pxa2xx_update_display,
-                                  pxa2xx_invalidate_display,
-                                  NULL, NULL, s);
-    surface = qemu_console_surface(s->con);
-
-    switch (surface_bits_per_pixel(surface)) {
-    case 0:
-        s->dest_width = 0;
-        break;
-    case 8:
-        s->line_fn[0] = pxa2xx_draw_fn_8;
-        s->line_fn[1] = pxa2xx_draw_fn_8t;
-        s->dest_width = 1;
-        break;
-    case 15:
-        s->line_fn[0] = pxa2xx_draw_fn_15;
-        s->line_fn[1] = pxa2xx_draw_fn_15t;
-        s->dest_width = 2;
-        break;
-    case 16:
-        s->line_fn[0] = pxa2xx_draw_fn_16;
-        s->line_fn[1] = pxa2xx_draw_fn_16t;
-        s->dest_width = 2;
-        break;
-    case 24:
-        s->line_fn[0] = pxa2xx_draw_fn_24;
-        s->line_fn[1] = pxa2xx_draw_fn_24t;
-        s->dest_width = 3;
-        break;
-    case 32:
-        s->line_fn[0] = pxa2xx_draw_fn_32;
-        s->line_fn[1] = pxa2xx_draw_fn_32t;
-        s->dest_width = 4;
-        break;
-    default:
-        fprintf(stderr, "%s: Bad color depth\n", __FUNCTION__);
-        exit(1);
-    }
-
-    vmstate_register(NULL, 0, &vmstate_pxa2xx_lcdc, s);
-
-    return s;
-}
-
-void pxa2xx_lcd_vsync_notifier(PXA2xxLCDState *s, qemu_irq handler)
-{
-    s->vsync_cb = handler;
-}
diff --git a/hw/pxa2xx_mmci.c b/hw/pxa2xx_mmci.c
deleted file mode 100644 (file)
index 0df83cc..0000000
+++ /dev/null
@@ -1,553 +0,0 @@
-/*
- * Intel XScale PXA255/270 MultiMediaCard/SD/SDIO Controller emulation.
- *
- * Copyright (c) 2006 Openedhand Ltd.
- * Written by Andrzej Zaborowski <balrog@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/hw.h"
-#include "hw/pxa.h"
-#include "hw/sd.h"
-#include "hw/qdev.h"
-
-struct PXA2xxMMCIState {
-    MemoryRegion iomem;
-    qemu_irq irq;
-    qemu_irq rx_dma;
-    qemu_irq tx_dma;
-
-    SDState *card;
-
-    uint32_t status;
-    uint32_t clkrt;
-    uint32_t spi;
-    uint32_t cmdat;
-    uint32_t resp_tout;
-    uint32_t read_tout;
-    int blklen;
-    int numblk;
-    uint32_t intmask;
-    uint32_t intreq;
-    int cmd;
-    uint32_t arg;
-
-    int active;
-    int bytesleft;
-    uint8_t tx_fifo[64];
-    int tx_start;
-    int tx_len;
-    uint8_t rx_fifo[32];
-    int rx_start;
-    int rx_len;
-    uint16_t resp_fifo[9];
-    int resp_len;
-
-    int cmdreq;
-    int ac_width;
-};
-
-#define MMC_STRPCL     0x00    /* MMC Clock Start/Stop register */
-#define MMC_STAT       0x04    /* MMC Status register */
-#define MMC_CLKRT      0x08    /* MMC Clock Rate register */
-#define MMC_SPI                0x0c    /* MMC SPI Mode register */
-#define MMC_CMDAT      0x10    /* MMC Command/Data register */
-#define MMC_RESTO      0x14    /* MMC Response Time-Out register */
-#define MMC_RDTO       0x18    /* MMC Read Time-Out register */
-#define MMC_BLKLEN     0x1c    /* MMC Block Length register */
-#define MMC_NUMBLK     0x20    /* MMC Number of Blocks register */
-#define MMC_PRTBUF     0x24    /* MMC Buffer Partly Full register */
-#define MMC_I_MASK     0x28    /* MMC Interrupt Mask register */
-#define MMC_I_REG      0x2c    /* MMC Interrupt Request register */
-#define MMC_CMD                0x30    /* MMC Command register */
-#define MMC_ARGH       0x34    /* MMC Argument High register */
-#define MMC_ARGL       0x38    /* MMC Argument Low register */
-#define MMC_RES                0x3c    /* MMC Response FIFO */
-#define MMC_RXFIFO     0x40    /* MMC Receive FIFO */
-#define MMC_TXFIFO     0x44    /* MMC Transmit FIFO */
-#define MMC_RDWAIT     0x48    /* MMC RD_WAIT register */
-#define MMC_BLKS_REM   0x4c    /* MMC Blocks Remaining register */
-
-/* Bitfield masks */
-#define STRPCL_STOP_CLK        (1 << 0)
-#define STRPCL_STRT_CLK        (1 << 1)
-#define STAT_TOUT_RES  (1 << 1)
-#define STAT_CLK_EN    (1 << 8)
-#define STAT_DATA_DONE (1 << 11)
-#define STAT_PRG_DONE  (1 << 12)
-#define STAT_END_CMDRES        (1 << 13)
-#define SPI_SPI_MODE   (1 << 0)
-#define CMDAT_RES_TYPE (3 << 0)
-#define CMDAT_DATA_EN  (1 << 2)
-#define CMDAT_WR_RD    (1 << 3)
-#define CMDAT_DMA_EN   (1 << 7)
-#define CMDAT_STOP_TRAN        (1 << 10)
-#define INT_DATA_DONE  (1 << 0)
-#define INT_PRG_DONE   (1 << 1)
-#define INT_END_CMD    (1 << 2)
-#define INT_STOP_CMD   (1 << 3)
-#define INT_CLK_OFF    (1 << 4)
-#define INT_RXFIFO_REQ (1 << 5)
-#define INT_TXFIFO_REQ (1 << 6)
-#define INT_TINT       (1 << 7)
-#define INT_DAT_ERR    (1 << 8)
-#define INT_RES_ERR    (1 << 9)
-#define INT_RD_STALLED (1 << 10)
-#define INT_SDIO_INT   (1 << 11)
-#define INT_SDIO_SACK  (1 << 12)
-#define PRTBUF_PRT_BUF (1 << 0)
-
-/* Route internal interrupt lines to the global IC and DMA */
-static void pxa2xx_mmci_int_update(PXA2xxMMCIState *s)
-{
-    uint32_t mask = s->intmask;
-    if (s->cmdat & CMDAT_DMA_EN) {
-        mask |= INT_RXFIFO_REQ | INT_TXFIFO_REQ;
-
-        qemu_set_irq(s->rx_dma, !!(s->intreq & INT_RXFIFO_REQ));
-        qemu_set_irq(s->tx_dma, !!(s->intreq & INT_TXFIFO_REQ));
-    }
-
-    qemu_set_irq(s->irq, !!(s->intreq & ~mask));
-}
-
-static void pxa2xx_mmci_fifo_update(PXA2xxMMCIState *s)
-{
-    if (!s->active)
-        return;
-
-    if (s->cmdat & CMDAT_WR_RD) {
-        while (s->bytesleft && s->tx_len) {
-            sd_write_data(s->card, s->tx_fifo[s->tx_start ++]);
-            s->tx_start &= 0x1f;
-            s->tx_len --;
-            s->bytesleft --;
-        }
-        if (s->bytesleft)
-            s->intreq |= INT_TXFIFO_REQ;
-    } else
-        while (s->bytesleft && s->rx_len < 32) {
-            s->rx_fifo[(s->rx_start + (s->rx_len ++)) & 0x1f] =
-                sd_read_data(s->card);
-            s->bytesleft --;
-            s->intreq |= INT_RXFIFO_REQ;
-        }
-
-    if (!s->bytesleft) {
-        s->active = 0;
-        s->intreq |= INT_DATA_DONE;
-        s->status |= STAT_DATA_DONE;
-
-        if (s->cmdat & CMDAT_WR_RD) {
-            s->intreq |= INT_PRG_DONE;
-            s->status |= STAT_PRG_DONE;
-        }
-    }
-
-    pxa2xx_mmci_int_update(s);
-}
-
-static void pxa2xx_mmci_wakequeues(PXA2xxMMCIState *s)
-{
-    int rsplen, i;
-    SDRequest request;
-    uint8_t response[16];
-
-    s->active = 1;
-    s->rx_len = 0;
-    s->tx_len = 0;
-    s->cmdreq = 0;
-
-    request.cmd = s->cmd;
-    request.arg = s->arg;
-    request.crc = 0;   /* FIXME */
-
-    rsplen = sd_do_command(s->card, &request, response);
-    s->intreq |= INT_END_CMD;
-
-    memset(s->resp_fifo, 0, sizeof(s->resp_fifo));
-    switch (s->cmdat & CMDAT_RES_TYPE) {
-#define PXAMMCI_RESP(wd, value0, value1)       \
-        s->resp_fifo[(wd) + 0] |= (value0);    \
-        s->resp_fifo[(wd) + 1] |= (value1) << 8;
-    case 0:    /* No response */
-        goto complete;
-
-    case 1:    /* R1, R4, R5 or R6 */
-        if (rsplen < 4)
-            goto timeout;
-        goto complete;
-
-    case 2:    /* R2 */
-        if (rsplen < 16)
-            goto timeout;
-        goto complete;
-
-    case 3:    /* R3 */
-        if (rsplen < 4)
-            goto timeout;
-        goto complete;
-
-    complete:
-        for (i = 0; rsplen > 0; i ++, rsplen -= 2) {
-            PXAMMCI_RESP(i, response[i * 2], response[i * 2 + 1]);
-        }
-        s->status |= STAT_END_CMDRES;
-
-        if (!(s->cmdat & CMDAT_DATA_EN))
-            s->active = 0;
-        else
-            s->bytesleft = s->numblk * s->blklen;
-
-        s->resp_len = 0;
-        break;
-
-    timeout:
-        s->active = 0;
-        s->status |= STAT_TOUT_RES;
-        break;
-    }
-
-    pxa2xx_mmci_fifo_update(s);
-}
-
-static uint32_t pxa2xx_mmci_read(void *opaque, hwaddr offset)
-{
-    PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque;
-    uint32_t ret;
-
-    switch (offset) {
-    case MMC_STRPCL:
-        return 0;
-    case MMC_STAT:
-        return s->status;
-    case MMC_CLKRT:
-        return s->clkrt;
-    case MMC_SPI:
-        return s->spi;
-    case MMC_CMDAT:
-        return s->cmdat;
-    case MMC_RESTO:
-        return s->resp_tout;
-    case MMC_RDTO:
-        return s->read_tout;
-    case MMC_BLKLEN:
-        return s->blklen;
-    case MMC_NUMBLK:
-        return s->numblk;
-    case MMC_PRTBUF:
-        return 0;
-    case MMC_I_MASK:
-        return s->intmask;
-    case MMC_I_REG:
-        return s->intreq;
-    case MMC_CMD:
-        return s->cmd | 0x40;
-    case MMC_ARGH:
-        return s->arg >> 16;
-    case MMC_ARGL:
-        return s->arg & 0xffff;
-    case MMC_RES:
-        if (s->resp_len < 9)
-            return s->resp_fifo[s->resp_len ++];
-        return 0;
-    case MMC_RXFIFO:
-        ret = 0;
-        while (s->ac_width -- && s->rx_len) {
-            ret |= s->rx_fifo[s->rx_start ++] << (s->ac_width << 3);
-            s->rx_start &= 0x1f;
-            s->rx_len --;
-        }
-        s->intreq &= ~INT_RXFIFO_REQ;
-        pxa2xx_mmci_fifo_update(s);
-        return ret;
-    case MMC_RDWAIT:
-        return 0;
-    case MMC_BLKS_REM:
-        return s->numblk;
-    default:
-        hw_error("%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset);
-    }
-
-    return 0;
-}
-
-static void pxa2xx_mmci_write(void *opaque,
-                hwaddr offset, uint32_t value)
-{
-    PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque;
-
-    switch (offset) {
-    case MMC_STRPCL:
-        if (value & STRPCL_STRT_CLK) {
-            s->status |= STAT_CLK_EN;
-            s->intreq &= ~INT_CLK_OFF;
-
-            if (s->cmdreq && !(s->cmdat & CMDAT_STOP_TRAN)) {
-                s->status &= STAT_CLK_EN;
-                pxa2xx_mmci_wakequeues(s);
-            }
-        }
-
-        if (value & STRPCL_STOP_CLK) {
-            s->status &= ~STAT_CLK_EN;
-            s->intreq |= INT_CLK_OFF;
-            s->active = 0;
-        }
-
-        pxa2xx_mmci_int_update(s);
-        break;
-
-    case MMC_CLKRT:
-        s->clkrt = value & 7;
-        break;
-
-    case MMC_SPI:
-        s->spi = value & 0xf;
-        if (value & SPI_SPI_MODE)
-            printf("%s: attempted to use card in SPI mode\n", __FUNCTION__);
-        break;
-
-    case MMC_CMDAT:
-        s->cmdat = value & 0x3dff;
-        s->active = 0;
-        s->cmdreq = 1;
-        if (!(value & CMDAT_STOP_TRAN)) {
-            s->status &= STAT_CLK_EN;
-
-            if (s->status & STAT_CLK_EN)
-                pxa2xx_mmci_wakequeues(s);
-        }
-
-        pxa2xx_mmci_int_update(s);
-        break;
-
-    case MMC_RESTO:
-        s->resp_tout = value & 0x7f;
-        break;
-
-    case MMC_RDTO:
-        s->read_tout = value & 0xffff;
-        break;
-
-    case MMC_BLKLEN:
-        s->blklen = value & 0xfff;
-        break;
-
-    case MMC_NUMBLK:
-        s->numblk = value & 0xffff;
-        break;
-
-    case MMC_PRTBUF:
-        if (value & PRTBUF_PRT_BUF) {
-            s->tx_start ^= 32;
-            s->tx_len = 0;
-        }
-        pxa2xx_mmci_fifo_update(s);
-        break;
-
-    case MMC_I_MASK:
-        s->intmask = value & 0x1fff;
-        pxa2xx_mmci_int_update(s);
-        break;
-
-    case MMC_CMD:
-        s->cmd = value & 0x3f;
-        break;
-
-    case MMC_ARGH:
-        s->arg &= 0x0000ffff;
-        s->arg |= value << 16;
-        break;
-
-    case MMC_ARGL:
-        s->arg &= 0xffff0000;
-        s->arg |= value & 0x0000ffff;
-        break;
-
-    case MMC_TXFIFO:
-        while (s->ac_width -- && s->tx_len < 0x20)
-            s->tx_fifo[(s->tx_start + (s->tx_len ++)) & 0x1f] =
-                    (value >> (s->ac_width << 3)) & 0xff;
-        s->intreq &= ~INT_TXFIFO_REQ;
-        pxa2xx_mmci_fifo_update(s);
-        break;
-
-    case MMC_RDWAIT:
-    case MMC_BLKS_REM:
-        break;
-
-    default:
-        hw_error("%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset);
-    }
-}
-
-static uint32_t pxa2xx_mmci_readb(void *opaque, hwaddr offset)
-{
-    PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque;
-    s->ac_width = 1;
-    return pxa2xx_mmci_read(opaque, offset);
-}
-
-static uint32_t pxa2xx_mmci_readh(void *opaque, hwaddr offset)
-{
-    PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque;
-    s->ac_width = 2;
-    return pxa2xx_mmci_read(opaque, offset);
-}
-
-static uint32_t pxa2xx_mmci_readw(void *opaque, hwaddr offset)
-{
-    PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque;
-    s->ac_width = 4;
-    return pxa2xx_mmci_read(opaque, offset);
-}
-
-static void pxa2xx_mmci_writeb(void *opaque,
-                hwaddr offset, uint32_t value)
-{
-    PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque;
-    s->ac_width = 1;
-    pxa2xx_mmci_write(opaque, offset, value);
-}
-
-static void pxa2xx_mmci_writeh(void *opaque,
-                hwaddr offset, uint32_t value)
-{
-    PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque;
-    s->ac_width = 2;
-    pxa2xx_mmci_write(opaque, offset, value);
-}
-
-static void pxa2xx_mmci_writew(void *opaque,
-                hwaddr offset, uint32_t value)
-{
-    PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque;
-    s->ac_width = 4;
-    pxa2xx_mmci_write(opaque, offset, value);
-}
-
-static const MemoryRegionOps pxa2xx_mmci_ops = {
-    .old_mmio = {
-        .read = { pxa2xx_mmci_readb,
-                  pxa2xx_mmci_readh,
-                  pxa2xx_mmci_readw, },
-        .write = { pxa2xx_mmci_writeb,
-                   pxa2xx_mmci_writeh,
-                   pxa2xx_mmci_writew, },
-    },
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void pxa2xx_mmci_save(QEMUFile *f, void *opaque)
-{
-    PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque;
-    int i;
-
-    qemu_put_be32s(f, &s->status);
-    qemu_put_be32s(f, &s->clkrt);
-    qemu_put_be32s(f, &s->spi);
-    qemu_put_be32s(f, &s->cmdat);
-    qemu_put_be32s(f, &s->resp_tout);
-    qemu_put_be32s(f, &s->read_tout);
-    qemu_put_be32(f, s->blklen);
-    qemu_put_be32(f, s->numblk);
-    qemu_put_be32s(f, &s->intmask);
-    qemu_put_be32s(f, &s->intreq);
-    qemu_put_be32(f, s->cmd);
-    qemu_put_be32s(f, &s->arg);
-    qemu_put_be32(f, s->cmdreq);
-    qemu_put_be32(f, s->active);
-    qemu_put_be32(f, s->bytesleft);
-
-    qemu_put_byte(f, s->tx_len);
-    for (i = 0; i < s->tx_len; i ++)
-        qemu_put_byte(f, s->tx_fifo[(s->tx_start + i) & 63]);
-
-    qemu_put_byte(f, s->rx_len);
-    for (i = 0; i < s->rx_len; i ++)
-        qemu_put_byte(f, s->rx_fifo[(s->rx_start + i) & 31]);
-
-    qemu_put_byte(f, s->resp_len);
-    for (i = s->resp_len; i < 9; i ++)
-        qemu_put_be16s(f, &s->resp_fifo[i]);
-}
-
-static int pxa2xx_mmci_load(QEMUFile *f, void *opaque, int version_id)
-{
-    PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque;
-    int i;
-
-    qemu_get_be32s(f, &s->status);
-    qemu_get_be32s(f, &s->clkrt);
-    qemu_get_be32s(f, &s->spi);
-    qemu_get_be32s(f, &s->cmdat);
-    qemu_get_be32s(f, &s->resp_tout);
-    qemu_get_be32s(f, &s->read_tout);
-    s->blklen = qemu_get_be32(f);
-    s->numblk = qemu_get_be32(f);
-    qemu_get_be32s(f, &s->intmask);
-    qemu_get_be32s(f, &s->intreq);
-    s->cmd = qemu_get_be32(f);
-    qemu_get_be32s(f, &s->arg);
-    s->cmdreq = qemu_get_be32(f);
-    s->active = qemu_get_be32(f);
-    s->bytesleft = qemu_get_be32(f);
-
-    s->tx_len = qemu_get_byte(f);
-    s->tx_start = 0;
-    if (s->tx_len >= sizeof(s->tx_fifo) || s->tx_len < 0)
-        return -EINVAL;
-    for (i = 0; i < s->tx_len; i ++)
-        s->tx_fifo[i] = qemu_get_byte(f);
-
-    s->rx_len = qemu_get_byte(f);
-    s->rx_start = 0;
-    if (s->rx_len >= sizeof(s->rx_fifo) || s->rx_len < 0)
-        return -EINVAL;
-    for (i = 0; i < s->rx_len; i ++)
-        s->rx_fifo[i] = qemu_get_byte(f);
-
-    s->resp_len = qemu_get_byte(f);
-    if (s->resp_len > 9 || s->resp_len < 0)
-        return -EINVAL;
-    for (i = s->resp_len; i < 9; i ++)
-         qemu_get_be16s(f, &s->resp_fifo[i]);
-
-    return 0;
-}
-
-PXA2xxMMCIState *pxa2xx_mmci_init(MemoryRegion *sysmem,
-                hwaddr base,
-                BlockDriverState *bd, qemu_irq irq,
-                qemu_irq rx_dma, qemu_irq tx_dma)
-{
-    PXA2xxMMCIState *s;
-
-    s = (PXA2xxMMCIState *) g_malloc0(sizeof(PXA2xxMMCIState));
-    s->irq = irq;
-    s->rx_dma = rx_dma;
-    s->tx_dma = tx_dma;
-
-    memory_region_init_io(&s->iomem, &pxa2xx_mmci_ops, s,
-                          "pxa2xx-mmci", 0x00100000);
-    memory_region_add_subregion(sysmem, base, &s->iomem);
-
-    /* Instantiate the actual storage */
-    s->card = sd_init(bd, 0);
-
-    register_savevm(NULL, "pxa2xx_mmci", 0, 0,
-                    pxa2xx_mmci_save, pxa2xx_mmci_load, s);
-
-    return s;
-}
-
-void pxa2xx_mmci_handlers(PXA2xxMMCIState *s, qemu_irq readonly,
-                qemu_irq coverswitch)
-{
-    sd_set_cb(s->card, readonly, coverswitch);
-}
diff --git a/hw/pxa2xx_pcmcia.c b/hw/pxa2xx_pcmcia.c
deleted file mode 100644 (file)
index 66fefba..0000000
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- * Intel XScale PXA255/270 PC Card and CompactFlash Interface.
- *
- * Copyright (c) 2006 Openedhand Ltd.
- * Written by Andrzej Zaborowski <balrog@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/hw.h"
-#include "hw/pcmcia.h"
-#include "hw/pxa.h"
-
-
-struct PXA2xxPCMCIAState {
-    PCMCIASocket slot;
-    PCMCIACardState *card;
-    MemoryRegion common_iomem;
-    MemoryRegion attr_iomem;
-    MemoryRegion iomem;
-
-    qemu_irq irq;
-    qemu_irq cd_irq;
-};
-
-static uint64_t pxa2xx_pcmcia_common_read(void *opaque,
-                hwaddr offset, unsigned size)
-{
-    PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
-
-    if (s->slot.attached) {
-        return s->card->common_read(s->card->state, offset);
-    }
-
-    return 0;
-}
-
-static void pxa2xx_pcmcia_common_write(void *opaque, hwaddr offset,
-                                       uint64_t value, unsigned size)
-{
-    PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
-
-    if (s->slot.attached) {
-        s->card->common_write(s->card->state, offset, value);
-    }
-}
-
-static uint64_t pxa2xx_pcmcia_attr_read(void *opaque,
-                hwaddr offset, unsigned size)
-{
-    PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
-
-    if (s->slot.attached) {
-        return s->card->attr_read(s->card->state, offset);
-    }
-
-    return 0;
-}
-
-static void pxa2xx_pcmcia_attr_write(void *opaque, hwaddr offset,
-                                     uint64_t value, unsigned size)
-{
-    PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
-
-    if (s->slot.attached) {
-        s->card->attr_write(s->card->state, offset, value);
-    }
-}
-
-static uint64_t pxa2xx_pcmcia_io_read(void *opaque,
-                hwaddr offset, unsigned size)
-{
-    PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
-
-    if (s->slot.attached) {
-        return s->card->io_read(s->card->state, offset);
-    }
-
-    return 0;
-}
-
-static void pxa2xx_pcmcia_io_write(void *opaque, hwaddr offset,
-                                   uint64_t value, unsigned size)
-{
-    PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
-
-    if (s->slot.attached) {
-        s->card->io_write(s->card->state, offset, value);
-    }
-}
-
-static const MemoryRegionOps pxa2xx_pcmcia_common_ops = {
-    .read = pxa2xx_pcmcia_common_read,
-    .write = pxa2xx_pcmcia_common_write,
-    .endianness = DEVICE_NATIVE_ENDIAN
-};
-
-static const MemoryRegionOps pxa2xx_pcmcia_attr_ops = {
-    .read = pxa2xx_pcmcia_attr_read,
-    .write = pxa2xx_pcmcia_attr_write,
-    .endianness = DEVICE_NATIVE_ENDIAN
-};
-
-static const MemoryRegionOps pxa2xx_pcmcia_io_ops = {
-    .read = pxa2xx_pcmcia_io_read,
-    .write = pxa2xx_pcmcia_io_write,
-    .endianness = DEVICE_NATIVE_ENDIAN
-};
-
-static void pxa2xx_pcmcia_set_irq(void *opaque, int line, int level)
-{
-    PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
-    if (!s->irq)
-        return;
-
-    qemu_set_irq(s->irq, level);
-}
-
-PXA2xxPCMCIAState *pxa2xx_pcmcia_init(MemoryRegion *sysmem,
-                                      hwaddr base)
-{
-    PXA2xxPCMCIAState *s;
-
-    s = (PXA2xxPCMCIAState *)
-            g_malloc0(sizeof(PXA2xxPCMCIAState));
-
-    /* Socket I/O Memory Space */
-    memory_region_init_io(&s->iomem, &pxa2xx_pcmcia_io_ops, s,
-                          "pxa2xx-pcmcia-io", 0x04000000);
-    memory_region_add_subregion(sysmem, base | 0x00000000,
-                                &s->iomem);
-
-    /* Then next 64 MB is reserved */
-
-    /* Socket Attribute Memory Space */
-    memory_region_init_io(&s->attr_iomem, &pxa2xx_pcmcia_attr_ops, s,
-                          "pxa2xx-pcmcia-attribute", 0x04000000);
-    memory_region_add_subregion(sysmem, base | 0x08000000,
-                                &s->attr_iomem);
-
-    /* Socket Common Memory Space */
-    memory_region_init_io(&s->common_iomem, &pxa2xx_pcmcia_common_ops, s,
-                          "pxa2xx-pcmcia-common", 0x04000000);
-    memory_region_add_subregion(sysmem, base | 0x0c000000,
-                                &s->common_iomem);
-
-    if (base == 0x30000000)
-        s->slot.slot_string = "PXA PC Card Socket 1";
-    else
-        s->slot.slot_string = "PXA PC Card Socket 0";
-    s->slot.irq = qemu_allocate_irqs(pxa2xx_pcmcia_set_irq, s, 1)[0];
-    pcmcia_socket_register(&s->slot);
-
-    return s;
-}
-
-/* Insert a new card into a slot */
-int pxa2xx_pcmcia_attach(void *opaque, PCMCIACardState *card)
-{
-    PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
-    if (s->slot.attached)
-        return -EEXIST;
-
-    if (s->cd_irq) {
-        qemu_irq_raise(s->cd_irq);
-    }
-
-    s->card = card;
-
-    s->slot.attached = 1;
-    s->card->slot = &s->slot;
-    s->card->attach(s->card->state);
-
-    return 0;
-}
-
-/* Eject card from the slot */
-int pxa2xx_pcmcia_dettach(void *opaque)
-{
-    PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
-    if (!s->slot.attached)
-        return -ENOENT;
-
-    s->card->detach(s->card->state);
-    s->card->slot = NULL;
-    s->card = NULL;
-
-    s->slot.attached = 0;
-
-    if (s->irq)
-        qemu_irq_lower(s->irq);
-    if (s->cd_irq)
-        qemu_irq_lower(s->cd_irq);
-
-    return 0;
-}
-
-/* Who to notify on card events */
-void pxa2xx_pcmcia_set_irq_cb(void *opaque, qemu_irq irq, qemu_irq cd_irq)
-{
-    PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
-    s->irq = irq;
-    s->cd_irq = cd_irq;
-}
diff --git a/hw/pxa2xx_template.h b/hw/pxa2xx_template.h
deleted file mode 100644 (file)
index 1cbe36c..0000000
+++ /dev/null
@@ -1,435 +0,0 @@
-/*
- * Intel XScale PXA255/270 LCDC emulation.
- *
- * Copyright (c) 2006 Openedhand Ltd.
- * Written by Andrzej Zaborowski <balrog@zabor.org>
- *
- * This code is licensed under the GPLv2.
- *
- * Framebuffer format conversion routines.
- */
-
-# define SKIP_PIXEL(to)                to += deststep
-#if BITS == 8
-# define COPY_PIXEL(to, from)  *to = from; SKIP_PIXEL(to)
-#elif BITS == 15 || BITS == 16
-# define COPY_PIXEL(to, from)  *(uint16_t *) to = from; SKIP_PIXEL(to)
-#elif BITS == 24
-# define COPY_PIXEL(to, from)  \
-       *(uint16_t *) to = from; *(to + 2) = (from) >> 16; SKIP_PIXEL(to)
-#elif BITS == 32
-# define COPY_PIXEL(to, from)  *(uint32_t *) to = from; SKIP_PIXEL(to)
-#else
-# error unknown bit depth
-#endif
-
-#ifdef HOST_WORDS_BIGENDIAN
-# define SWAP_WORDS    1
-#endif
-
-#define FN_2(x)                FN(x + 1) FN(x)
-#define FN_4(x)                FN_2(x + 2) FN_2(x)
-
-static void glue(pxa2xx_draw_line2_, BITS)(void *opaque,
-                uint8_t *dest, const uint8_t *src, int width, int deststep)
-{
-    uint32_t *palette = opaque;
-    uint32_t data;
-    while (width > 0) {
-        data = *(uint32_t *) src;
-#define FN(x)          COPY_PIXEL(dest, palette[(data >> ((x) * 2)) & 3]);
-#ifdef SWAP_WORDS
-        FN_4(12)
-        FN_4(8)
-        FN_4(4)
-        FN_4(0)
-#else
-        FN_4(0)
-        FN_4(4)
-        FN_4(8)
-        FN_4(12)
-#endif
-#undef FN
-        width -= 16;
-        src += 4;
-    }
-}
-
-static void glue(pxa2xx_draw_line4_, BITS)(void *opaque,
-                uint8_t *dest, const uint8_t *src, int width, int deststep)
-{
-    uint32_t *palette = opaque;
-    uint32_t data;
-    while (width > 0) {
-        data = *(uint32_t *) src;
-#define FN(x)          COPY_PIXEL(dest, palette[(data >> ((x) * 4)) & 0xf]);
-#ifdef SWAP_WORDS
-        FN_2(6)
-        FN_2(4)
-        FN_2(2)
-        FN_2(0)
-#else
-        FN_2(0)
-        FN_2(2)
-        FN_2(4)
-        FN_2(6)
-#endif
-#undef FN
-        width -= 8;
-        src += 4;
-    }
-}
-
-static void glue(pxa2xx_draw_line8_, BITS)(void *opaque,
-                uint8_t *dest, const uint8_t *src, int width, int deststep)
-{
-    uint32_t *palette = opaque;
-    uint32_t data;
-    while (width > 0) {
-        data = *(uint32_t *) src;
-#define FN(x)          COPY_PIXEL(dest, palette[(data >> (x)) & 0xff]);
-#ifdef SWAP_WORDS
-        FN(24)
-        FN(16)
-        FN(8)
-        FN(0)
-#else
-        FN(0)
-        FN(8)
-        FN(16)
-        FN(24)
-#endif
-#undef FN
-        width -= 4;
-        src += 4;
-    }
-}
-
-static void glue(pxa2xx_draw_line16_, BITS)(void *opaque,
-                uint8_t *dest, const uint8_t *src, int width, int deststep)
-{
-    uint32_t data;
-    unsigned int r, g, b;
-    while (width > 0) {
-        data = *(uint32_t *) src;
-#ifdef SWAP_WORDS
-        data = bswap32(data);
-#endif
-        b = (data & 0x1f) << 3;
-        data >>= 5;
-        g = (data & 0x3f) << 2;
-        data >>= 6;
-        r = (data & 0x1f) << 3;
-        data >>= 5;
-        COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
-        b = (data & 0x1f) << 3;
-        data >>= 5;
-        g = (data & 0x3f) << 2;
-        data >>= 6;
-        r = (data & 0x1f) << 3;
-        COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
-        width -= 2;
-        src += 4;
-    }
-}
-
-static void glue(pxa2xx_draw_line16t_, BITS)(void *opaque,
-                uint8_t *dest, const uint8_t *src, int width, int deststep)
-{
-    uint32_t data;
-    unsigned int r, g, b;
-    while (width > 0) {
-        data = *(uint32_t *) src;
-#ifdef SWAP_WORDS
-        data = bswap32(data);
-#endif
-        b = (data & 0x1f) << 3;
-        data >>= 5;
-        g = (data & 0x1f) << 3;
-        data >>= 5;
-        r = (data & 0x1f) << 3;
-        data >>= 5;
-        if (data & 1)
-            SKIP_PIXEL(dest);
-        else
-            COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
-        data >>= 1;
-        b = (data & 0x1f) << 3;
-        data >>= 5;
-        g = (data & 0x1f) << 3;
-        data >>= 5;
-        r = (data & 0x1f) << 3;
-        data >>= 5;
-        if (data & 1)
-            SKIP_PIXEL(dest);
-        else
-            COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
-        width -= 2;
-        src += 4;
-    }
-}
-
-static void glue(pxa2xx_draw_line18_, BITS)(void *opaque,
-                uint8_t *dest, const uint8_t *src, int width, int deststep)
-{
-    uint32_t data;
-    unsigned int r, g, b;
-    while (width > 0) {
-        data = *(uint32_t *) src;
-#ifdef SWAP_WORDS
-        data = bswap32(data);
-#endif
-        b = (data & 0x3f) << 2;
-        data >>= 6;
-        g = (data & 0x3f) << 2;
-        data >>= 6;
-        r = (data & 0x3f) << 2;
-        COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
-        width -= 1;
-        src += 4;
-    }
-}
-
-/* The wicked packed format */
-static void glue(pxa2xx_draw_line18p_, BITS)(void *opaque,
-                uint8_t *dest, const uint8_t *src, int width, int deststep)
-{
-    uint32_t data[3];
-    unsigned int r, g, b;
-    while (width > 0) {
-        data[0] = *(uint32_t *) src;
-        src += 4;
-        data[1] = *(uint32_t *) src;
-        src += 4;
-        data[2] = *(uint32_t *) src;
-        src += 4;
-#ifdef SWAP_WORDS
-        data[0] = bswap32(data[0]);
-        data[1] = bswap32(data[1]);
-        data[2] = bswap32(data[2]);
-#endif
-        b = (data[0] & 0x3f) << 2;
-        data[0] >>= 6;
-        g = (data[0] & 0x3f) << 2;
-        data[0] >>= 6;
-        r = (data[0] & 0x3f) << 2;
-        data[0] >>= 12;
-        COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
-        b = (data[0] & 0x3f) << 2;
-        data[0] >>= 6;
-        g = ((data[1] & 0xf) << 4) | (data[0] << 2);
-        data[1] >>= 4;
-        r = (data[1] & 0x3f) << 2;
-        data[1] >>= 12;
-        COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
-        b = (data[1] & 0x3f) << 2;
-        data[1] >>= 6;
-        g = (data[1] & 0x3f) << 2;
-        data[1] >>= 6;
-        r = ((data[2] & 0x3) << 6) | (data[1] << 2);
-        data[2] >>= 8;
-        COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
-        b = (data[2] & 0x3f) << 2;
-        data[2] >>= 6;
-        g = (data[2] & 0x3f) << 2;
-        data[2] >>= 6;
-        r = data[2] << 2;
-        COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
-        width -= 4;
-    }
-}
-
-static void glue(pxa2xx_draw_line19_, BITS)(void *opaque,
-                uint8_t *dest, const uint8_t *src, int width, int deststep)
-{
-    uint32_t data;
-    unsigned int r, g, b;
-    while (width > 0) {
-        data = *(uint32_t *) src;
-#ifdef SWAP_WORDS
-        data = bswap32(data);
-#endif
-        b = (data & 0x3f) << 2;
-        data >>= 6;
-        g = (data & 0x3f) << 2;
-        data >>= 6;
-        r = (data & 0x3f) << 2;
-        data >>= 6;
-        if (data & 1)
-            SKIP_PIXEL(dest);
-        else
-            COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
-        width -= 1;
-        src += 4;
-    }
-}
-
-/* The wicked packed format */
-static void glue(pxa2xx_draw_line19p_, BITS)(void *opaque,
-                uint8_t *dest, const uint8_t *src, int width, int deststep)
-{
-    uint32_t data[3];
-    unsigned int r, g, b;
-    while (width > 0) {
-        data[0] = *(uint32_t *) src;
-        src += 4;
-        data[1] = *(uint32_t *) src;
-        src += 4;
-        data[2] = *(uint32_t *) src;
-        src += 4;
-# ifdef SWAP_WORDS
-        data[0] = bswap32(data[0]);
-        data[1] = bswap32(data[1]);
-        data[2] = bswap32(data[2]);
-# endif
-        b = (data[0] & 0x3f) << 2;
-        data[0] >>= 6;
-        g = (data[0] & 0x3f) << 2;
-        data[0] >>= 6;
-        r = (data[0] & 0x3f) << 2;
-        data[0] >>= 6;
-        if (data[0] & 1)
-            SKIP_PIXEL(dest);
-        else
-            COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
-        data[0] >>= 6;
-        b = (data[0] & 0x3f) << 2;
-        data[0] >>= 6;
-        g = ((data[1] & 0xf) << 4) | (data[0] << 2);
-        data[1] >>= 4;
-        r = (data[1] & 0x3f) << 2;
-        data[1] >>= 6;
-        if (data[1] & 1)
-            SKIP_PIXEL(dest);
-        else
-            COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
-        data[1] >>= 6;
-        b = (data[1] & 0x3f) << 2;
-        data[1] >>= 6;
-        g = (data[1] & 0x3f) << 2;
-        data[1] >>= 6;
-        r = ((data[2] & 0x3) << 6) | (data[1] << 2);
-        data[2] >>= 2;
-        if (data[2] & 1)
-            SKIP_PIXEL(dest);
-        else
-            COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
-        data[2] >>= 6;
-        b = (data[2] & 0x3f) << 2;
-        data[2] >>= 6;
-        g = (data[2] & 0x3f) << 2;
-        data[2] >>= 6;
-        r = data[2] << 2;
-        data[2] >>= 6;
-        if (data[2] & 1)
-            SKIP_PIXEL(dest);
-        else
-            COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
-        width -= 4;
-    }
-}
-
-static void glue(pxa2xx_draw_line24_, BITS)(void *opaque,
-                uint8_t *dest, const uint8_t *src, int width, int deststep)
-{
-    uint32_t data;
-    unsigned int r, g, b;
-    while (width > 0) {
-        data = *(uint32_t *) src;
-#ifdef SWAP_WORDS
-        data = bswap32(data);
-#endif
-        b = data & 0xff;
-        data >>= 8;
-        g = data & 0xff;
-        data >>= 8;
-        r = data & 0xff;
-        COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
-        width -= 1;
-        src += 4;
-    }
-}
-
-static void glue(pxa2xx_draw_line24t_, BITS)(void *opaque,
-                uint8_t *dest, const uint8_t *src, int width, int deststep)
-{
-    uint32_t data;
-    unsigned int r, g, b;
-    while (width > 0) {
-        data = *(uint32_t *) src;
-#ifdef SWAP_WORDS
-        data = bswap32(data);
-#endif
-        b = (data & 0x7f) << 1;
-        data >>= 7;
-        g = data & 0xff;
-        data >>= 8;
-        r = data & 0xff;
-        data >>= 8;
-        if (data & 1)
-            SKIP_PIXEL(dest);
-        else
-            COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
-        width -= 1;
-        src += 4;
-    }
-}
-
-static void glue(pxa2xx_draw_line25_, BITS)(void *opaque,
-                uint8_t *dest, const uint8_t *src, int width, int deststep)
-{
-    uint32_t data;
-    unsigned int r, g, b;
-    while (width > 0) {
-        data = *(uint32_t *) src;
-#ifdef SWAP_WORDS
-        data = bswap32(data);
-#endif
-        b = data & 0xff;
-        data >>= 8;
-        g = data & 0xff;
-        data >>= 8;
-        r = data & 0xff;
-        data >>= 8;
-        if (data & 1)
-            SKIP_PIXEL(dest);
-        else
-            COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
-        width -= 1;
-        src += 4;
-    }
-}
-
-/* Overlay planes disabled, no transparency */
-static drawfn glue(pxa2xx_draw_fn_, BITS)[16] =
-{
-    [0 ... 0xf]       = NULL,
-    [pxa_lcdc_2bpp]   = glue(pxa2xx_draw_line2_, BITS),
-    [pxa_lcdc_4bpp]   = glue(pxa2xx_draw_line4_, BITS),
-    [pxa_lcdc_8bpp]   = glue(pxa2xx_draw_line8_, BITS),
-    [pxa_lcdc_16bpp]  = glue(pxa2xx_draw_line16_, BITS),
-    [pxa_lcdc_18bpp]  = glue(pxa2xx_draw_line18_, BITS),
-    [pxa_lcdc_18pbpp] = glue(pxa2xx_draw_line18p_, BITS),
-    [pxa_lcdc_24bpp]  = glue(pxa2xx_draw_line24_, BITS),
-};
-
-/* Overlay planes enabled, transparency used */
-static drawfn glue(glue(pxa2xx_draw_fn_, BITS), t)[16] =
-{
-    [0 ... 0xf]       = NULL,
-    [pxa_lcdc_4bpp]   = glue(pxa2xx_draw_line4_, BITS),
-    [pxa_lcdc_8bpp]   = glue(pxa2xx_draw_line8_, BITS),
-    [pxa_lcdc_16bpp]  = glue(pxa2xx_draw_line16t_, BITS),
-    [pxa_lcdc_19bpp]  = glue(pxa2xx_draw_line19_, BITS),
-    [pxa_lcdc_19pbpp] = glue(pxa2xx_draw_line19p_, BITS),
-    [pxa_lcdc_24bpp]  = glue(pxa2xx_draw_line24t_, BITS),
-    [pxa_lcdc_25bpp]  = glue(pxa2xx_draw_line25_, BITS),
-};
-
-#undef BITS
-#undef COPY_PIXEL
-#undef SKIP_PIXEL
-
-#ifdef SWAP_WORDS
-# undef SWAP_WORDS
-#endif
diff --git a/hw/pxa2xx_timer.c b/hw/pxa2xx_timer.c
deleted file mode 100644 (file)
index c173fe4..0000000
+++ /dev/null
@@ -1,583 +0,0 @@
-/*
- * Intel XScale PXA255/270 OS Timers.
- *
- * Copyright (c) 2006 Openedhand Ltd.
- * Copyright (c) 2006 Thorsten Zitterell
- *
- * This code is licensed under the GPL.
- */
-
-#include "hw/hw.h"
-#include "qemu/timer.h"
-#include "sysemu/sysemu.h"
-#include "hw/pxa.h"
-#include "hw/sysbus.h"
-
-#define OSMR0  0x00
-#define OSMR1  0x04
-#define OSMR2  0x08
-#define OSMR3  0x0c
-#define OSMR4  0x80
-#define OSMR5  0x84
-#define OSMR6  0x88
-#define OSMR7  0x8c
-#define OSMR8  0x90
-#define OSMR9  0x94
-#define OSMR10 0x98
-#define OSMR11 0x9c
-#define OSCR   0x10    /* OS Timer Count */
-#define OSCR4  0x40
-#define OSCR5  0x44
-#define OSCR6  0x48
-#define OSCR7  0x4c
-#define OSCR8  0x50
-#define OSCR9  0x54
-#define OSCR10 0x58
-#define OSCR11 0x5c
-#define OSSR   0x14    /* Timer status register */
-#define OWER   0x18
-#define OIER   0x1c    /* Interrupt enable register  3-0 to E3-E0 */
-#define OMCR4  0xc0    /* OS Match Control registers */
-#define OMCR5  0xc4
-#define OMCR6  0xc8
-#define OMCR7  0xcc
-#define OMCR8  0xd0
-#define OMCR9  0xd4
-#define OMCR10 0xd8
-#define OMCR11 0xdc
-#define OSNR   0x20
-
-#define PXA25X_FREQ    3686400 /* 3.6864 MHz */
-#define PXA27X_FREQ    3250000 /* 3.25 MHz */
-
-static int pxa2xx_timer4_freq[8] = {
-    [0] = 0,
-    [1] = 32768,
-    [2] = 1000,
-    [3] = 1,
-    [4] = 1000000,
-    /* [5] is the "Externally supplied clock".  Assign if necessary.  */
-    [5 ... 7] = 0,
-};
-
-typedef struct PXA2xxTimerInfo PXA2xxTimerInfo;
-
-typedef struct {
-    uint32_t value;
-    qemu_irq irq;
-    QEMUTimer *qtimer;
-    int num;
-    PXA2xxTimerInfo *info;
-} PXA2xxTimer0;
-
-typedef struct {
-    PXA2xxTimer0 tm;
-    int32_t oldclock;
-    int32_t clock;
-    uint64_t lastload;
-    uint32_t freq;
-    uint32_t control;
-} PXA2xxTimer4;
-
-struct PXA2xxTimerInfo {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-    uint32_t flags;
-
-    int32_t clock;
-    int32_t oldclock;
-    uint64_t lastload;
-    uint32_t freq;
-    PXA2xxTimer0 timer[4];
-    uint32_t events;
-    uint32_t irq_enabled;
-    uint32_t reset3;
-    uint32_t snapshot;
-
-    qemu_irq irq4;
-    PXA2xxTimer4 tm4[8];
-};
-
-#define PXA2XX_TIMER_HAVE_TM4  0
-
-static inline int pxa2xx_timer_has_tm4(PXA2xxTimerInfo *s)
-{
-    return s->flags & (1 << PXA2XX_TIMER_HAVE_TM4);
-}
-
-static void pxa2xx_timer_update(void *opaque, uint64_t now_qemu)
-{
-    PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque;
-    int i;
-    uint32_t now_vm;
-    uint64_t new_qemu;
-
-    now_vm = s->clock +
-            muldiv64(now_qemu - s->lastload, s->freq, get_ticks_per_sec());
-
-    for (i = 0; i < 4; i ++) {
-        new_qemu = now_qemu + muldiv64((uint32_t) (s->timer[i].value - now_vm),
-                        get_ticks_per_sec(), s->freq);
-        qemu_mod_timer(s->timer[i].qtimer, new_qemu);
-    }
-}
-
-static void pxa2xx_timer_update4(void *opaque, uint64_t now_qemu, int n)
-{
-    PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque;
-    uint32_t now_vm;
-    uint64_t new_qemu;
-    static const int counters[8] = { 0, 0, 0, 0, 4, 4, 6, 6 };
-    int counter;
-
-    if (s->tm4[n].control & (1 << 7))
-        counter = n;
-    else
-        counter = counters[n];
-
-    if (!s->tm4[counter].freq) {
-        qemu_del_timer(s->tm4[n].tm.qtimer);
-        return;
-    }
-
-    now_vm = s->tm4[counter].clock + muldiv64(now_qemu -
-                    s->tm4[counter].lastload,
-                    s->tm4[counter].freq, get_ticks_per_sec());
-
-    new_qemu = now_qemu + muldiv64((uint32_t) (s->tm4[n].tm.value - now_vm),
-                    get_ticks_per_sec(), s->tm4[counter].freq);
-    qemu_mod_timer(s->tm4[n].tm.qtimer, new_qemu);
-}
-
-static uint64_t pxa2xx_timer_read(void *opaque, hwaddr offset,
-                                  unsigned size)
-{
-    PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque;
-    int tm = 0;
-
-    switch (offset) {
-    case OSMR3:  tm ++;
-        /* fall through */
-    case OSMR2:  tm ++;
-        /* fall through */
-    case OSMR1:  tm ++;
-        /* fall through */
-    case OSMR0:
-        return s->timer[tm].value;
-    case OSMR11: tm ++;
-        /* fall through */
-    case OSMR10: tm ++;
-        /* fall through */
-    case OSMR9:  tm ++;
-        /* fall through */
-    case OSMR8:  tm ++;
-        /* fall through */
-    case OSMR7:  tm ++;
-        /* fall through */
-    case OSMR6:  tm ++;
-        /* fall through */
-    case OSMR5:  tm ++;
-        /* fall through */
-    case OSMR4:
-        if (!pxa2xx_timer_has_tm4(s))
-            goto badreg;
-        return s->tm4[tm].tm.value;
-    case OSCR:
-        return s->clock + muldiv64(qemu_get_clock_ns(vm_clock) -
-                        s->lastload, s->freq, get_ticks_per_sec());
-    case OSCR11: tm ++;
-        /* fall through */
-    case OSCR10: tm ++;
-        /* fall through */
-    case OSCR9:  tm ++;
-        /* fall through */
-    case OSCR8:  tm ++;
-        /* fall through */
-    case OSCR7:  tm ++;
-        /* fall through */
-    case OSCR6:  tm ++;
-        /* fall through */
-    case OSCR5:  tm ++;
-        /* fall through */
-    case OSCR4:
-        if (!pxa2xx_timer_has_tm4(s))
-            goto badreg;
-
-        if ((tm == 9 - 4 || tm == 11 - 4) && (s->tm4[tm].control & (1 << 9))) {
-            if (s->tm4[tm - 1].freq)
-                s->snapshot = s->tm4[tm - 1].clock + muldiv64(
-                                qemu_get_clock_ns(vm_clock) -
-                                s->tm4[tm - 1].lastload,
-                                s->tm4[tm - 1].freq, get_ticks_per_sec());
-            else
-                s->snapshot = s->tm4[tm - 1].clock;
-        }
-
-        if (!s->tm4[tm].freq)
-            return s->tm4[tm].clock;
-        return s->tm4[tm].clock + muldiv64(qemu_get_clock_ns(vm_clock) -
-                        s->tm4[tm].lastload, s->tm4[tm].freq, get_ticks_per_sec());
-    case OIER:
-        return s->irq_enabled;
-    case OSSR: /* Status register */
-        return s->events;
-    case OWER:
-        return s->reset3;
-    case OMCR11: tm ++;
-        /* fall through */
-    case OMCR10: tm ++;
-        /* fall through */
-    case OMCR9:  tm ++;
-        /* fall through */
-    case OMCR8:  tm ++;
-        /* fall through */
-    case OMCR7:  tm ++;
-        /* fall through */
-    case OMCR6:  tm ++;
-        /* fall through */
-    case OMCR5:  tm ++;
-        /* fall through */
-    case OMCR4:
-        if (!pxa2xx_timer_has_tm4(s))
-            goto badreg;
-        return s->tm4[tm].control;
-    case OSNR:
-        return s->snapshot;
-    default:
-    badreg:
-        hw_error("pxa2xx_timer_read: Bad offset " REG_FMT "\n", offset);
-    }
-
-    return 0;
-}
-
-static void pxa2xx_timer_write(void *opaque, hwaddr offset,
-                               uint64_t value, unsigned size)
-{
-    int i, tm = 0;
-    PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque;
-
-    switch (offset) {
-    case OSMR3:  tm ++;
-        /* fall through */
-    case OSMR2:  tm ++;
-        /* fall through */
-    case OSMR1:  tm ++;
-        /* fall through */
-    case OSMR0:
-        s->timer[tm].value = value;
-        pxa2xx_timer_update(s, qemu_get_clock_ns(vm_clock));
-        break;
-    case OSMR11: tm ++;
-        /* fall through */
-    case OSMR10: tm ++;
-        /* fall through */
-    case OSMR9:  tm ++;
-        /* fall through */
-    case OSMR8:  tm ++;
-        /* fall through */
-    case OSMR7:  tm ++;
-        /* fall through */
-    case OSMR6:  tm ++;
-        /* fall through */
-    case OSMR5:  tm ++;
-        /* fall through */
-    case OSMR4:
-        if (!pxa2xx_timer_has_tm4(s))
-            goto badreg;
-        s->tm4[tm].tm.value = value;
-        pxa2xx_timer_update4(s, qemu_get_clock_ns(vm_clock), tm);
-        break;
-    case OSCR:
-        s->oldclock = s->clock;
-        s->lastload = qemu_get_clock_ns(vm_clock);
-        s->clock = value;
-        pxa2xx_timer_update(s, s->lastload);
-        break;
-    case OSCR11: tm ++;
-        /* fall through */
-    case OSCR10: tm ++;
-        /* fall through */
-    case OSCR9:  tm ++;
-        /* fall through */
-    case OSCR8:  tm ++;
-        /* fall through */
-    case OSCR7:  tm ++;
-        /* fall through */
-    case OSCR6:  tm ++;
-        /* fall through */
-    case OSCR5:  tm ++;
-        /* fall through */
-    case OSCR4:
-        if (!pxa2xx_timer_has_tm4(s))
-            goto badreg;
-        s->tm4[tm].oldclock = s->tm4[tm].clock;
-        s->tm4[tm].lastload = qemu_get_clock_ns(vm_clock);
-        s->tm4[tm].clock = value;
-        pxa2xx_timer_update4(s, s->tm4[tm].lastload, tm);
-        break;
-    case OIER:
-        s->irq_enabled = value & 0xfff;
-        break;
-    case OSSR: /* Status register */
-        value &= s->events;
-        s->events &= ~value;
-        for (i = 0; i < 4; i ++, value >>= 1)
-            if (value & 1)
-                qemu_irq_lower(s->timer[i].irq);
-        if (pxa2xx_timer_has_tm4(s) && !(s->events & 0xff0) && value)
-            qemu_irq_lower(s->irq4);
-        break;
-    case OWER: /* XXX: Reset on OSMR3 match? */
-        s->reset3 = value;
-        break;
-    case OMCR7:  tm ++;
-        /* fall through */
-    case OMCR6:  tm ++;
-        /* fall through */
-    case OMCR5:  tm ++;
-        /* fall through */
-    case OMCR4:
-        if (!pxa2xx_timer_has_tm4(s))
-            goto badreg;
-        s->tm4[tm].control = value & 0x0ff;
-        /* XXX Stop if running (shouldn't happen) */
-        if ((value & (1 << 7)) || tm == 0)
-            s->tm4[tm].freq = pxa2xx_timer4_freq[value & 7];
-        else {
-            s->tm4[tm].freq = 0;
-            pxa2xx_timer_update4(s, qemu_get_clock_ns(vm_clock), tm);
-        }
-        break;
-    case OMCR11: tm ++;
-        /* fall through */
-    case OMCR10: tm ++;
-        /* fall through */
-    case OMCR9:  tm ++;
-        /* fall through */
-    case OMCR8:  tm += 4;
-        if (!pxa2xx_timer_has_tm4(s))
-            goto badreg;
-        s->tm4[tm].control = value & 0x3ff;
-        /* XXX Stop if running (shouldn't happen) */
-        if ((value & (1 << 7)) || !(tm & 1))
-            s->tm4[tm].freq =
-                    pxa2xx_timer4_freq[(value & (1 << 8)) ?  0 : (value & 7)];
-        else {
-            s->tm4[tm].freq = 0;
-            pxa2xx_timer_update4(s, qemu_get_clock_ns(vm_clock), tm);
-        }
-        break;
-    default:
-    badreg:
-        hw_error("pxa2xx_timer_write: Bad offset " REG_FMT "\n", offset);
-    }
-}
-
-static const MemoryRegionOps pxa2xx_timer_ops = {
-    .read = pxa2xx_timer_read,
-    .write = pxa2xx_timer_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void pxa2xx_timer_tick(void *opaque)
-{
-    PXA2xxTimer0 *t = (PXA2xxTimer0 *) opaque;
-    PXA2xxTimerInfo *i = t->info;
-
-    if (i->irq_enabled & (1 << t->num)) {
-        i->events |= 1 << t->num;
-        qemu_irq_raise(t->irq);
-    }
-
-    if (t->num == 3)
-        if (i->reset3 & 1) {
-            i->reset3 = 0;
-            qemu_system_reset_request();
-        }
-}
-
-static void pxa2xx_timer_tick4(void *opaque)
-{
-    PXA2xxTimer4 *t = (PXA2xxTimer4 *) opaque;
-    PXA2xxTimerInfo *i = (PXA2xxTimerInfo *) t->tm.info;
-
-    pxa2xx_timer_tick(&t->tm);
-    if (t->control & (1 << 3))
-        t->clock = 0;
-    if (t->control & (1 << 6))
-        pxa2xx_timer_update4(i, qemu_get_clock_ns(vm_clock), t->tm.num - 4);
-    if (i->events & 0xff0)
-        qemu_irq_raise(i->irq4);
-}
-
-static int pxa25x_timer_post_load(void *opaque, int version_id)
-{
-    PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque;
-    int64_t now;
-    int i;
-
-    now = qemu_get_clock_ns(vm_clock);
-    pxa2xx_timer_update(s, now);
-
-    if (pxa2xx_timer_has_tm4(s))
-        for (i = 0; i < 8; i ++)
-            pxa2xx_timer_update4(s, now, i);
-
-    return 0;
-}
-
-static int pxa2xx_timer_init(SysBusDevice *dev)
-{
-    int i;
-    PXA2xxTimerInfo *s;
-
-    s = FROM_SYSBUS(PXA2xxTimerInfo, dev);
-    s->irq_enabled = 0;
-    s->oldclock = 0;
-    s->clock = 0;
-    s->lastload = qemu_get_clock_ns(vm_clock);
-    s->reset3 = 0;
-
-    for (i = 0; i < 4; i ++) {
-        s->timer[i].value = 0;
-        sysbus_init_irq(dev, &s->timer[i].irq);
-        s->timer[i].info = s;
-        s->timer[i].num = i;
-        s->timer[i].qtimer = qemu_new_timer_ns(vm_clock,
-                        pxa2xx_timer_tick, &s->timer[i]);
-    }
-    if (s->flags & (1 << PXA2XX_TIMER_HAVE_TM4)) {
-        sysbus_init_irq(dev, &s->irq4);
-
-        for (i = 0; i < 8; i ++) {
-            s->tm4[i].tm.value = 0;
-            s->tm4[i].tm.info = s;
-            s->tm4[i].tm.num = i + 4;
-            s->tm4[i].freq = 0;
-            s->tm4[i].control = 0x0;
-            s->tm4[i].tm.qtimer = qemu_new_timer_ns(vm_clock,
-                        pxa2xx_timer_tick4, &s->tm4[i]);
-        }
-    }
-
-    memory_region_init_io(&s->iomem, &pxa2xx_timer_ops, s,
-                          "pxa2xx-timer", 0x00001000);
-    sysbus_init_mmio(dev, &s->iomem);
-
-    return 0;
-}
-
-static const VMStateDescription vmstate_pxa2xx_timer0_regs = {
-    .name = "pxa2xx_timer0",
-    .version_id = 2,
-    .minimum_version_id = 2,
-    .minimum_version_id_old = 2,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT32(value, PXA2xxTimer0),
-        VMSTATE_END_OF_LIST(),
-    },
-};
-
-static const VMStateDescription vmstate_pxa2xx_timer4_regs = {
-    .name = "pxa2xx_timer4",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_STRUCT(tm, PXA2xxTimer4, 1,
-                        vmstate_pxa2xx_timer0_regs, PXA2xxTimer0),
-        VMSTATE_INT32(oldclock, PXA2xxTimer4),
-        VMSTATE_INT32(clock, PXA2xxTimer4),
-        VMSTATE_UINT64(lastload, PXA2xxTimer4),
-        VMSTATE_UINT32(freq, PXA2xxTimer4),
-        VMSTATE_UINT32(control, PXA2xxTimer4),
-        VMSTATE_END_OF_LIST(),
-    },
-};
-
-static bool pxa2xx_timer_has_tm4_test(void *opaque, int version_id)
-{
-    return pxa2xx_timer_has_tm4(opaque);
-}
-
-static const VMStateDescription vmstate_pxa2xx_timer_regs = {
-    .name = "pxa2xx_timer",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .post_load = pxa25x_timer_post_load,
-    .fields = (VMStateField[]) {
-        VMSTATE_INT32(clock, PXA2xxTimerInfo),
-        VMSTATE_INT32(oldclock, PXA2xxTimerInfo),
-        VMSTATE_UINT64(lastload, PXA2xxTimerInfo),
-        VMSTATE_STRUCT_ARRAY(timer, PXA2xxTimerInfo, 4, 1,
-                        vmstate_pxa2xx_timer0_regs, PXA2xxTimer0),
-        VMSTATE_UINT32(events, PXA2xxTimerInfo),
-        VMSTATE_UINT32(irq_enabled, PXA2xxTimerInfo),
-        VMSTATE_UINT32(reset3, PXA2xxTimerInfo),
-        VMSTATE_UINT32(snapshot, PXA2xxTimerInfo),
-        VMSTATE_STRUCT_ARRAY_TEST(tm4, PXA2xxTimerInfo, 8,
-                        pxa2xx_timer_has_tm4_test, 0,
-                        vmstate_pxa2xx_timer4_regs, PXA2xxTimer4),
-        VMSTATE_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 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 const TypeInfo pxa25x_timer_dev_info = {
-    .name          = "pxa25x-timer",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(PXA2xxTimerInfo),
-    .class_init    = pxa25x_timer_dev_class_init,
-};
-
-static Property pxa27x_timer_dev_properties[] = {
-    DEFINE_PROP_UINT32("freq", PXA2xxTimerInfo, freq, PXA27X_FREQ),
-    DEFINE_PROP_BIT("tm4", PXA2xxTimerInfo, flags,
-    PXA2XX_TIMER_HAVE_TM4, true),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void pxa27x_timer_dev_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = pxa2xx_timer_init;
-    dc->desc = "PXA27x timer";
-    dc->vmsd = &vmstate_pxa2xx_timer_regs;
-    dc->props = pxa27x_timer_dev_properties;
-}
-
-static const 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_types(void)
-{
-    type_register_static(&pxa25x_timer_dev_info);
-    type_register_static(&pxa27x_timer_dev_info);
-}
-
-type_init(pxa2xx_timer_register_types)
diff --git a/hw/q35.c b/hw/q35.c
deleted file mode 100644 (file)
index 6ea081a..0000000
--- a/hw/q35.c
+++ /dev/null
@@ -1,310 +0,0 @@
-/*
- * QEMU MCH/ICH9 PCI Bridge Emulation
- *
- * Copyright (c) 2006 Fabrice Bellard
- * Copyright (c) 2009, 2010, 2011
- *               Isaku Yamahata <yamahata at valinux co jp>
- *               VA Linux Systems Japan K.K.
- * Copyright (C) 2012 Jason Baron <jbaron@redhat.com>
- *
- * This is based on piix_pci.c, but heavily modified.
- *
- * 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 "hw/hw.h"
-#include "hw/q35.h"
-
-/****************************************************************************
- * Q35 host
- */
-
-static int q35_host_init(SysBusDevice *dev)
-{
-    PCIBus *b;
-    PCIHostState *pci = FROM_SYSBUS(PCIHostState, dev);
-    Q35PCIHost *s = Q35_HOST_DEVICE(&dev->qdev);
-
-    memory_region_init_io(&pci->conf_mem, &pci_host_conf_le_ops, pci,
-                          "pci-conf-idx", 4);
-    sysbus_add_io(dev, MCH_HOST_BRIDGE_CONFIG_ADDR, &pci->conf_mem);
-    sysbus_init_ioports(&pci->busdev, MCH_HOST_BRIDGE_CONFIG_ADDR, 4);
-
-    memory_region_init_io(&pci->data_mem, &pci_host_data_le_ops, pci,
-                          "pci-conf-data", 4);
-    sysbus_add_io(dev, MCH_HOST_BRIDGE_CONFIG_DATA, &pci->data_mem);
-    sysbus_init_ioports(&pci->busdev, MCH_HOST_BRIDGE_CONFIG_DATA, 4);
-
-    if (pcie_host_init(&s->host) < 0) {
-        return -1;
-    }
-    b = pci_bus_new(&s->host.pci.busdev.qdev, "pcie.0",
-                    s->mch.pci_address_space, s->mch.address_space_io,
-                    0, TYPE_PCIE_BUS);
-    s->host.pci.bus = b;
-    qdev_set_parent_bus(DEVICE(&s->mch), BUS(b));
-    qdev_init_nofail(DEVICE(&s->mch));
-
-    return 0;
-}
-
-static Property mch_props[] = {
-    DEFINE_PROP_UINT64("MCFG", Q35PCIHost, host.base_addr,
-                        MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void q35_host_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = q35_host_init;
-    dc->props = mch_props;
-}
-
-static void q35_host_initfn(Object *obj)
-{
-    Q35PCIHost *s = Q35_HOST_DEVICE(obj);
-
-    object_initialize(&s->mch, TYPE_MCH_PCI_DEVICE);
-    object_property_add_child(OBJECT(s), "mch", OBJECT(&s->mch), NULL);
-    qdev_prop_set_uint32(DEVICE(&s->mch), "addr", PCI_DEVFN(0, 0));
-    qdev_prop_set_bit(DEVICE(&s->mch), "multifunction", false);
-}
-
-static const TypeInfo q35_host_info = {
-    .name       = TYPE_Q35_HOST_DEVICE,
-    .parent     = TYPE_PCIE_HOST_BRIDGE,
-    .instance_size = sizeof(Q35PCIHost),
-    .instance_init = q35_host_initfn,
-    .class_init = q35_host_class_init,
-};
-
-/****************************************************************************
- * MCH D0:F0
- */
-
-/* PCIe MMCFG */
-static void mch_update_pciexbar(MCHPCIState *mch)
-{
-    PCIDevice *pci_dev = &mch->d;
-    BusState *bus = qdev_get_parent_bus(&pci_dev->qdev);
-    DeviceState *qdev = bus->parent;
-    Q35PCIHost *s = Q35_HOST_DEVICE(qdev);
-
-    uint64_t pciexbar;
-    int enable;
-    uint64_t addr;
-    uint64_t addr_mask;
-    uint32_t length;
-
-    pciexbar = pci_get_quad(pci_dev->config + MCH_HOST_BRIDGE_PCIEXBAR);
-    enable = pciexbar & MCH_HOST_BRIDGE_PCIEXBAREN;
-    addr_mask = MCH_HOST_BRIDGE_PCIEXBAR_ADMSK;
-    switch (pciexbar & MCH_HOST_BRIDGE_PCIEXBAR_LENGTH_MASK) {
-    case MCH_HOST_BRIDGE_PCIEXBAR_LENGTH_256M:
-        length = 256 * 1024 * 1024;
-        break;
-    case MCH_HOST_BRIDGE_PCIEXBAR_LENGTH_128M:
-        length = 128 * 1024 * 1024;
-        addr_mask |= MCH_HOST_BRIDGE_PCIEXBAR_128ADMSK |
-            MCH_HOST_BRIDGE_PCIEXBAR_64ADMSK;
-        break;
-    case MCH_HOST_BRIDGE_PCIEXBAR_LENGTH_64M:
-        length = 64 * 1024 * 1024;
-        addr_mask |= MCH_HOST_BRIDGE_PCIEXBAR_64ADMSK;
-        break;
-    case MCH_HOST_BRIDGE_PCIEXBAR_LENGTH_RVD:
-    default:
-        enable = 0;
-        length = 0;
-        abort();
-        break;
-    }
-    addr = pciexbar & addr_mask;
-    pcie_host_mmcfg_update(&s->host, enable, addr, length);
-}
-
-/* PAM */
-static void mch_update_pam(MCHPCIState *mch)
-{
-    int i;
-
-    memory_region_transaction_begin();
-    for (i = 0; i < 13; i++) {
-        pam_update(&mch->pam_regions[i], i,
-                   mch->d.config[MCH_HOST_BRIDGE_PAM0 + ((i + 1) / 2)]);
-    }
-    memory_region_transaction_commit();
-}
-
-/* SMRAM */
-static void mch_update_smram(MCHPCIState *mch)
-{
-    memory_region_transaction_begin();
-    smram_update(&mch->smram_region, mch->d.config[MCH_HOST_BRDIGE_SMRAM],
-                    mch->smm_enabled);
-    memory_region_transaction_commit();
-}
-
-static void mch_set_smm(int smm, void *arg)
-{
-    MCHPCIState *mch = arg;
-
-    memory_region_transaction_begin();
-    smram_set_smm(&mch->smm_enabled, smm, mch->d.config[MCH_HOST_BRDIGE_SMRAM],
-                    &mch->smram_region);
-    memory_region_transaction_commit();
-}
-
-static void mch_write_config(PCIDevice *d,
-                              uint32_t address, uint32_t val, int len)
-{
-    MCHPCIState *mch = MCH_PCI_DEVICE(d);
-
-    /* XXX: implement SMRAM.D_LOCK */
-    pci_default_write_config(d, address, val, len);
-
-    if (ranges_overlap(address, len, MCH_HOST_BRIDGE_PAM0,
-                       MCH_HOST_BRIDGE_PAM_SIZE)) {
-        mch_update_pam(mch);
-    }
-
-    if (ranges_overlap(address, len, MCH_HOST_BRIDGE_PCIEXBAR,
-                       MCH_HOST_BRIDGE_PCIEXBAR_SIZE)) {
-        mch_update_pciexbar(mch);
-    }
-
-    if (ranges_overlap(address, len, MCH_HOST_BRDIGE_SMRAM,
-                       MCH_HOST_BRDIGE_SMRAM_SIZE)) {
-        mch_update_smram(mch);
-    }
-}
-
-static void mch_update(MCHPCIState *mch)
-{
-    mch_update_pciexbar(mch);
-    mch_update_pam(mch);
-    mch_update_smram(mch);
-}
-
-static int mch_post_load(void *opaque, int version_id)
-{
-    MCHPCIState *mch = opaque;
-    mch_update(mch);
-    return 0;
-}
-
-static const VMStateDescription vmstate_mch = {
-    .name = "mch",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .post_load = mch_post_load,
-    .fields = (VMStateField []) {
-        VMSTATE_PCI_DEVICE(d, MCHPCIState),
-        VMSTATE_UINT8(smm_enabled, MCHPCIState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void mch_reset(DeviceState *qdev)
-{
-    PCIDevice *d = PCI_DEVICE(qdev);
-    MCHPCIState *mch = MCH_PCI_DEVICE(d);
-
-    pci_set_quad(d->config + MCH_HOST_BRIDGE_PCIEXBAR,
-                 MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT);
-
-    d->config[MCH_HOST_BRDIGE_SMRAM] = MCH_HOST_BRIDGE_SMRAM_DEFAULT;
-
-    mch_update(mch);
-}
-
-static int mch_init(PCIDevice *d)
-{
-    int i;
-    hwaddr pci_hole64_size;
-    MCHPCIState *mch = MCH_PCI_DEVICE(d);
-
-    /* setup pci memory regions */
-    memory_region_init_alias(&mch->pci_hole, "pci-hole",
-                             mch->pci_address_space,
-                             mch->below_4g_mem_size,
-                             0x100000000ULL - mch->below_4g_mem_size);
-    memory_region_add_subregion(mch->system_memory, mch->below_4g_mem_size,
-                                &mch->pci_hole);
-    pci_hole64_size = (sizeof(hwaddr) == 4 ? 0 :
-                       ((uint64_t)1 << 62));
-    memory_region_init_alias(&mch->pci_hole_64bit, "pci-hole64",
-                             mch->pci_address_space,
-                             0x100000000ULL + mch->above_4g_mem_size,
-                             pci_hole64_size);
-    if (pci_hole64_size) {
-        memory_region_add_subregion(mch->system_memory,
-                                    0x100000000ULL + mch->above_4g_mem_size,
-                                    &mch->pci_hole_64bit);
-    }
-    /* smram */
-    cpu_smm_register(&mch_set_smm, mch);
-    memory_region_init_alias(&mch->smram_region, "smram-region",
-                             mch->pci_address_space, 0xa0000, 0x20000);
-    memory_region_add_subregion_overlap(mch->system_memory, 0xa0000,
-                                        &mch->smram_region, 1);
-    memory_region_set_enabled(&mch->smram_region, false);
-    init_pam(mch->ram_memory, mch->system_memory, mch->pci_address_space,
-             &mch->pam_regions[0], PAM_BIOS_BASE, PAM_BIOS_SIZE);
-    for (i = 0; i < 12; ++i) {
-        init_pam(mch->ram_memory, mch->system_memory, mch->pci_address_space,
-                 &mch->pam_regions[i+1], PAM_EXPAN_BASE + i * PAM_EXPAN_SIZE,
-                 PAM_EXPAN_SIZE);
-    }
-    return 0;
-}
-
-static void mch_class_init(ObjectClass *klass, void *data)
-{
-    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-    DeviceClass *dc = DEVICE_CLASS(klass);
-
-    k->init = mch_init;
-    k->config_write = mch_write_config;
-    dc->reset = mch_reset;
-    dc->desc = "Host bridge";
-    dc->vmsd = &vmstate_mch;
-    k->vendor_id = PCI_VENDOR_ID_INTEL;
-    k->device_id = PCI_DEVICE_ID_INTEL_Q35_MCH;
-    k->revision = MCH_HOST_BRIDGE_REVISION_DEFUALT;
-    k->class_id = PCI_CLASS_BRIDGE_HOST;
-}
-
-static const TypeInfo mch_info = {
-    .name = TYPE_MCH_PCI_DEVICE,
-    .parent = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(MCHPCIState),
-    .class_init = mch_class_init,
-};
-
-static void q35_register(void)
-{
-    type_register_static(&mch_info);
-    type_register_static(&q35_host_info);
-}
-
-type_init(q35_register);
diff --git a/hw/q35.h b/hw/q35.h
deleted file mode 100644 (file)
index d766bb7..0000000
--- a/hw/q35.h
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * q35.h
- *
- * Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp>
- *                    VA Linux Systems Japan K.K.
- * Copyright (C) 2012 Jason Baron <jbaron@redhat.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 Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>
- */
-
-#ifndef HW_Q35_H
-#define HW_Q35_H
-
-#include "hw/hw.h"
-#include "qemu/range.h"
-#include "hw/isa.h"
-#include "hw/sysbus.h"
-#include "hw/pc.h"
-#include "hw/apm.h"
-#include "hw/apic.h"
-#include "hw/pci/pci.h"
-#include "hw/pci/pcie_host.h"
-#include "hw/acpi.h"
-#include "hw/acpi_ich9.h"
-#include "hw/pam.h"
-
-#define TYPE_Q35_HOST_DEVICE "q35-pcihost"
-#define Q35_HOST_DEVICE(obj) \
-     OBJECT_CHECK(Q35PCIHost, (obj), TYPE_Q35_HOST_DEVICE)
-
-#define TYPE_MCH_PCI_DEVICE "mch"
-#define MCH_PCI_DEVICE(obj) \
-     OBJECT_CHECK(MCHPCIState, (obj), TYPE_MCH_PCI_DEVICE)
-
-typedef struct MCHPCIState {
-    PCIDevice d;
-    MemoryRegion *ram_memory;
-    MemoryRegion *pci_address_space;
-    MemoryRegion *system_memory;
-    MemoryRegion *address_space_io;
-    PAMMemoryRegion pam_regions[13];
-    MemoryRegion smram_region;
-    MemoryRegion pci_hole;
-    MemoryRegion pci_hole_64bit;
-    uint8_t smm_enabled;
-    ram_addr_t below_4g_mem_size;
-    ram_addr_t above_4g_mem_size;
-} MCHPCIState;
-
-typedef struct Q35PCIHost {
-    PCIExpressHost host;
-    MCHPCIState mch;
-} Q35PCIHost;
-
-#define Q35_MASK(bit, ms_bit, ls_bit) \
-((uint##bit##_t)(((1ULL << ((ms_bit) + 1)) - 1) & ~((1ULL << ls_bit) - 1)))
-
-/*
- * gmch part
- */
-
-/* PCI configuration */
-#define MCH_HOST_BRIDGE                        "MCH"
-
-#define MCH_HOST_BRIDGE_CONFIG_ADDR            0xcf8
-#define MCH_HOST_BRIDGE_CONFIG_DATA            0xcfc
-
-/* D0:F0 configuration space */
-#define MCH_HOST_BRIDGE_REVISION_DEFUALT       0x0
-
-#define MCH_HOST_BRIDGE_PCIEXBAR               0x60    /* 64bit register */
-#define MCH_HOST_BRIDGE_PCIEXBAR_SIZE          8       /* 64bit register */
-#define MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT       0xb0000000
-#define MCH_HOST_BRIDGE_PCIEXBAR_ADMSK         Q35_MASK(64, 35, 28)
-#define MCH_HOST_BRIDGE_PCIEXBAR_128ADMSK      ((uint64_t)(1 << 26))
-#define MCH_HOST_BRIDGE_PCIEXBAR_64ADMSK       ((uint64_t)(1 << 25))
-#define MCH_HOST_BRIDGE_PCIEXBAR_LENGTH_MASK   ((uint64_t)(0x3 << 1))
-#define MCH_HOST_BRIDGE_PCIEXBAR_LENGTH_256M   ((uint64_t)(0x0 << 1))
-#define MCH_HOST_BRIDGE_PCIEXBAR_LENGTH_128M   ((uint64_t)(0x1 << 1))
-#define MCH_HOST_BRIDGE_PCIEXBAR_LENGTH_64M    ((uint64_t)(0x2 << 1))
-#define MCH_HOST_BRIDGE_PCIEXBAR_LENGTH_RVD    ((uint64_t)(0x3 << 1))
-#define MCH_HOST_BRIDGE_PCIEXBAREN             ((uint64_t)1)
-
-#define MCH_HOST_BRIDGE_PAM_NB                 7
-#define MCH_HOST_BRIDGE_PAM_SIZE               7
-#define MCH_HOST_BRIDGE_PAM0                   0x90
-#define MCH_HOST_BRIDGE_PAM_BIOS_AREA          0xf0000
-#define MCH_HOST_BRIDGE_PAM_AREA_SIZE          0x10000 /* 16KB */
-#define MCH_HOST_BRIDGE_PAM1                   0x91
-#define MCH_HOST_BRIDGE_PAM_EXPAN_AREA         0xc0000
-#define MCH_HOST_BRIDGE_PAM_EXPAN_SIZE         0x04000
-#define MCH_HOST_BRIDGE_PAM2                   0x92
-#define MCH_HOST_BRIDGE_PAM3                   0x93
-#define MCH_HOST_BRIDGE_PAM4                   0x94
-#define MCH_HOST_BRIDGE_PAM_EXBIOS_AREA        0xe0000
-#define MCH_HOST_BRIDGE_PAM_EXBIOS_SIZE        0x04000
-#define MCH_HOST_BRIDGE_PAM5                   0x95
-#define MCH_HOST_BRIDGE_PAM6                   0x96
-#define MCH_HOST_BRIDGE_PAM_WE_HI              ((uint8_t)(0x2 << 4))
-#define MCH_HOST_BRIDGE_PAM_RE_HI              ((uint8_t)(0x1 << 4))
-#define MCH_HOST_BRIDGE_PAM_HI_MASK            ((uint8_t)(0x3 << 4))
-#define MCH_HOST_BRIDGE_PAM_WE_LO              ((uint8_t)0x2)
-#define MCH_HOST_BRIDGE_PAM_RE_LO              ((uint8_t)0x1)
-#define MCH_HOST_BRIDGE_PAM_LO_MASK            ((uint8_t)0x3)
-#define MCH_HOST_BRIDGE_PAM_WE                 ((uint8_t)0x2)
-#define MCH_HOST_BRIDGE_PAM_RE                 ((uint8_t)0x1)
-#define MCH_HOST_BRIDGE_PAM_MASK               ((uint8_t)0x3)
-
-#define MCH_HOST_BRDIGE_SMRAM                  0x9d
-#define MCH_HOST_BRDIGE_SMRAM_SIZE             1
-#define MCH_HOST_BRIDGE_SMRAM_DEFAULT          ((uint8_t)0x2)
-#define MCH_HOST_BRIDGE_SMRAM_D_OPEN           ((uint8_t)(1 << 6))
-#define MCH_HOST_BRIDGE_SMRAM_D_CLS            ((uint8_t)(1 << 5))
-#define MCH_HOST_BRIDGE_SMRAM_D_LCK            ((uint8_t)(1 << 4))
-#define MCH_HOST_BRIDGE_SMRAM_G_SMRAME         ((uint8_t)(1 << 3))
-#define MCH_HOST_BRIDGE_SMRAM_C_BASE_SEG_MASK  ((uint8_t)0x7)
-#define MCH_HOST_BRIDGE_SMRAM_C_BASE_SEG       ((uint8_t)0x2)  /* hardwired to b010 */
-#define MCH_HOST_BRIDGE_SMRAM_C_BASE           0xa0000
-#define MCH_HOST_BRIDGE_SMRAM_C_END            0xc0000
-#define MCH_HOST_BRIDGE_SMRAM_C_SIZE           0x20000
-#define MCH_HOST_BRIDGE_UPPER_SYSTEM_BIOS_END  0x100000
-
-#define MCH_HOST_BRIDGE_ESMRAMC                0x9e
-#define MCH_HOST_BRDIGE_ESMRAMC_H_SMRAME       ((uint8_t)(1 << 6))
-#define MCH_HOST_BRDIGE_ESMRAMC_E_SMERR        ((uint8_t)(1 << 5))
-#define MCH_HOST_BRDIGE_ESMRAMC_SM_CACHE       ((uint8_t)(1 << 4))
-#define MCH_HOST_BRDIGE_ESMRAMC_SM_L1          ((uint8_t)(1 << 3))
-#define MCH_HOST_BRDIGE_ESMRAMC_SM_L2          ((uint8_t)(1 << 2))
-#define MCH_HOST_BRDIGE_ESMRAMC_TSEG_SZ_MASK   ((uint8_t)(0x3 << 1))
-#define MCH_HOST_BRDIGE_ESMRAMC_TSEG_SZ_1MB    ((uint8_t)(0x0 << 1))
-#define MCH_HOST_BRDIGE_ESMRAMC_TSEG_SZ_2MB    ((uint8_t)(0x1 << 1))
-#define MCH_HOST_BRDIGE_ESMRAMC_TSEG_SZ_8MB    ((uint8_t)(0x2 << 1))
-#define MCH_HOST_BRDIGE_ESMRAMC_T_EN           ((uint8_t)1)
-
-/* D1:F0 PCIE* port*/
-#define MCH_PCIE_DEV                           1
-#define MCH_PCIE_FUNC                          0
-
-#endif /* HW_Q35_H */
diff --git a/hw/qdev-addr.c b/hw/qdev-addr.c
deleted file mode 100644 (file)
index 80a38bb..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-#include "hw/qdev.h"
-#include "hw/qdev-addr.h"
-#include "exec/hwaddr.h"
-#include "qapi/qmp/qerror.h"
-#include "qapi/visitor.h"
-
-/* --- target physical address --- */
-
-static int parse_taddr(DeviceState *dev, Property *prop, const char *str)
-{
-    hwaddr *ptr = qdev_get_prop_ptr(dev, prop);
-
-    *ptr = strtoull(str, NULL, 16);
-    return 0;
-}
-
-static int print_taddr(DeviceState *dev, Property *prop, char *dest, size_t len)
-{
-    hwaddr *ptr = qdev_get_prop_ptr(dev, prop);
-    return snprintf(dest, len, "0x" TARGET_FMT_plx, *ptr);
-}
-
-static void get_taddr(Object *obj, Visitor *v, void *opaque,
-                      const char *name, Error **errp)
-{
-    DeviceState *dev = DEVICE(obj);
-    Property *prop = opaque;
-    hwaddr *ptr = qdev_get_prop_ptr(dev, prop);
-    int64_t value;
-
-    value = *ptr;
-    visit_type_int64(v, &value, name, errp);
-}
-
-static void set_taddr(Object *obj, Visitor *v, void *opaque,
-                      const char *name, Error **errp)
-{
-    DeviceState *dev = DEVICE(obj);
-    Property *prop = opaque;
-    hwaddr *ptr = qdev_get_prop_ptr(dev, prop);
-    Error *local_err = NULL;
-    int64_t value;
-
-    if (dev->realized) {
-        qdev_prop_set_after_realize(dev, name, errp);
-        return;
-    }
-
-    visit_type_int64(v, &value, name, &local_err);
-    if (local_err) {
-        error_propagate(errp, local_err);
-        return;
-    }
-    if ((uint64_t)value <= (uint64_t) ~(hwaddr)0) {
-        *ptr = value;
-    } else {
-        error_set(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE,
-                  dev->id?:"", name, value, (uint64_t) 0,
-                  (uint64_t) ~(hwaddr)0);
-    }
-}
-
-
-PropertyInfo qdev_prop_taddr = {
-    .name  = "taddr",
-    .parse = parse_taddr,
-    .print = print_taddr,
-    .get   = get_taddr,
-    .set   = set_taddr,
-};
-
-void qdev_prop_set_taddr(DeviceState *dev, const char *name, hwaddr value)
-{
-    Error *errp = NULL;
-    object_property_set_int(OBJECT(dev), value, name, &errp);
-    assert(!errp);
-
-}
diff --git a/hw/qdev-addr.h b/hw/qdev-addr.h
deleted file mode 100644 (file)
index 79708e6..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef HW_QDEV_ADDR_H
-#define HW_QDEV_ADDR_H 1
-
-#define DEFINE_PROP_TADDR(_n, _s, _f, _d)                               \
-    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_taddr, hwaddr)
-
-extern PropertyInfo qdev_prop_taddr;
-void qdev_prop_set_taddr(DeviceState *dev, const char *name, hwaddr value);
-
-#endif
diff --git a/hw/qdev-core.h b/hw/qdev-core.h
deleted file mode 100644 (file)
index 547fbc7..0000000
+++ /dev/null
@@ -1,299 +0,0 @@
-#ifndef QDEV_CORE_H
-#define QDEV_CORE_H
-
-#include "qemu/queue.h"
-#include "qemu/option.h"
-#include "qemu/typedefs.h"
-#include "qom/object.h"
-#include "hw/irq.h"
-#include "qapi/error.h"
-
-enum {
-    DEV_NVECTORS_UNSPECIFIED = -1,
-};
-
-#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 int (*qdev_initfn)(DeviceState *dev);
-typedef int (*qdev_event)(DeviceState *dev);
-typedef void (*qdev_resetfn)(DeviceState *dev);
-typedef void (*DeviceRealize)(DeviceState *dev, Error **errp);
-typedef void (*DeviceUnrealize)(DeviceState *dev, Error **errp);
-
-struct VMStateDescription;
-
-/**
- * DeviceClass:
- * @props: Properties accessing state fields.
- * @realize: Callback function invoked when the #DeviceState:realized
- * property is changed to %true. The default invokes @init if not %NULL.
- * @unrealize: Callback function invoked when the #DeviceState:realized
- * property is changed to %false.
- * @init: Callback function invoked when the #DeviceState::realized property
- * is changed to %true. Deprecated, new types inheriting directly from
- * TYPE_DEVICE should use @realize instead, new leaf types should consult
- * their respective parent type.
- *
- * # Realization #
- * Devices are constructed in two stages,
- * 1) object instantiation via object_initialize() and
- * 2) device realization via #DeviceState:realized property.
- * The former may not fail (it might assert or exit), the latter may return
- * error information to the caller and must be re-entrant.
- * Trivial field initializations should go into #TypeInfo.instance_init.
- * Operations depending on @props static properties should go into @realize.
- * After successful realization, setting static properties will fail.
- *
- * As an interim step, the #DeviceState:realized property is set by deprecated
- * functions qdev_init() and qdev_init_nofail().
- * In the future, devices will propagate this state change to their children
- * and along busses they expose.
- * The point in time will be deferred to machine creation, so that values
- * set in @realize will not be introspectable beforehand. Therefore devices
- * must not create children during @realize; they should initialize them via
- * object_initialize() in their own #TypeInfo.instance_init and forward the
- * realization events appropriately.
- *
- * The @init callback is considered private to a particular bus implementation
- * (immediate abstract child types of TYPE_DEVICE). Derived leaf types set an
- * "init" callback on their parent class instead.
- *
- * Any type may override the @realize and/or @unrealize callbacks but needs
- * to call the parent type's implementation if keeping their functionality
- * is desired. Refer to QOM documentation for further discussion and examples.
- *
- * <note>
- *   <para>
- * If a type derived directly from TYPE_DEVICE implements @realize, it does
- * not need to implement @init and therefore does not need to store and call
- * #DeviceClass' default @realize callback.
- * For other types consult the documentation and implementation of the
- * respective parent types.
- *   </para>
- * </note>
- */
-typedef struct DeviceClass {
-    /*< private >*/
-    ObjectClass parent_class;
-    /*< public >*/
-
-    const char *fw_name;
-    const char *desc;
-    Property *props;
-    int no_user;
-
-    /* callbacks */
-    void (*reset)(DeviceState *dev);
-    DeviceRealize realize;
-    DeviceUnrealize unrealize;
-
-    /* device state */
-    const struct VMStateDescription *vmsd;
-
-    /* Private to qdev / bus.  */
-    qdev_initfn init; /* TODO remove, once users are converted to realize */
-    qdev_event unplug;
-    qdev_event exit;
-    const char *bus_type;
-} DeviceClass;
-
-/**
- * DeviceState:
- * @realized: Indicates whether the device has been fully constructed.
- *
- * This structure should not be accessed directly.  We declare it here
- * so that it can be embedded in individual device state structures.
- */
-struct DeviceState {
-    /*< private >*/
-    Object parent_obj;
-    /*< public >*/
-
-    const char *id;
-    bool realized;
-    QemuOpts *opts;
-    int hotplugged;
-    BusState *parent_bus;
-    int num_gpio_out;
-    qemu_irq *gpio_out;
-    int num_gpio_in;
-    qemu_irq *gpio_in;
-    QLIST_HEAD(, BusState) child_bus;
-    int num_child_bus;
-    int instance_id_alias;
-    int alias_required_for_version;
-};
-
-#define TYPE_BUS "bus"
-#define BUS(obj) OBJECT_CHECK(BusState, (obj), TYPE_BUS)
-#define BUS_CLASS(klass) OBJECT_CLASS_CHECK(BusClass, (klass), TYPE_BUS)
-#define BUS_GET_CLASS(obj) OBJECT_GET_CLASS(BusClass, (obj), TYPE_BUS)
-
-struct BusClass {
-    ObjectClass parent_class;
-
-    /* FIXME first arg should be BusState */
-    void (*print_dev)(Monitor *mon, DeviceState *dev, int indent);
-    char *(*get_dev_path)(DeviceState *dev);
-    /*
-     * This callback is used to create Open Firmware device path in accordance
-     * with OF spec http://forthworks.com/standards/of1275.pdf. Individual bus
-     * bindings can be found at http://playground.sun.com/1275/bindings/.
-     */
-    char *(*get_fw_dev_path)(DeviceState *dev);
-    int (*reset)(BusState *bus);
-    /* maximum devices allowed on the bus, 0: no limit. */
-    int max_dev;
-};
-
-typedef struct BusChild {
-    DeviceState *child;
-    int index;
-    QTAILQ_ENTRY(BusChild) sibling;
-} BusChild;
-
-/**
- * BusState:
- */
-struct BusState {
-    Object obj;
-    DeviceState *parent;
-    const char *name;
-    int allow_hotplug;
-    int max_index;
-    QTAILQ_HEAD(ChildrenHead, BusChild) children;
-    QLIST_ENTRY(BusState) sibling;
-};
-
-struct Property {
-    const char   *name;
-    PropertyInfo *info;
-    int          offset;
-    uint8_t      bitnr;
-    uint8_t      qtype;
-    int64_t      defval;
-    int          arrayoffset;
-    PropertyInfo *arrayinfo;
-    int          arrayfieldsize;
-};
-
-struct PropertyInfo {
-    const char *name;
-    const char *legacy_name;
-    const char **enum_table;
-    int (*parse)(DeviceState *dev, Property *prop, const char *str);
-    int (*print)(DeviceState *dev, Property *prop, char *dest, size_t len);
-    ObjectPropertyAccessor *get;
-    ObjectPropertyAccessor *set;
-    ObjectPropertyRelease *release;
-};
-
-typedef struct GlobalProperty {
-    const char *driver;
-    const char *property;
-    const char *value;
-    QTAILQ_ENTRY(GlobalProperty) next;
-} GlobalProperty;
-
-/*** Board API.  This should go away once we have a machine config file.  ***/
-
-DeviceState *qdev_create(BusState *bus, const char *name);
-DeviceState *qdev_try_create(BusState *bus, const char *name);
-int qdev_init(DeviceState *dev) QEMU_WARN_UNUSED_RESULT;
-void qdev_init_nofail(DeviceState *dev);
-void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id,
-                                 int required_for_version);
-void qdev_unplug(DeviceState *dev, Error **errp);
-void qdev_free(DeviceState *dev);
-int qdev_simple_unplug_cb(DeviceState *dev);
-void qdev_machine_creation_done(void);
-bool qdev_machine_modified(void);
-
-qemu_irq qdev_get_gpio_in(DeviceState *dev, int n);
-void qdev_connect_gpio_out(DeviceState *dev, int n, qemu_irq pin);
-
-BusState *qdev_get_child_bus(DeviceState *dev, const char *name);
-
-/*** Device API.  ***/
-
-/* Register device properties.  */
-/* GPIO inputs also double as IRQ sinks.  */
-void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n);
-void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n);
-
-BusState *qdev_get_parent_bus(DeviceState *dev);
-
-/*** BUS API. ***/
-
-DeviceState *qdev_find_recursive(BusState *bus, const char *id);
-
-/* Returns 0 to walk children, > 0 to skip walk, < 0 to terminate walk. */
-typedef int (qbus_walkerfn)(BusState *bus, void *opaque);
-typedef int (qdev_walkerfn)(DeviceState *dev, void *opaque);
-
-void qbus_create_inplace(void *bus, const char *typename,
-                         DeviceState *parent, const char *name);
-BusState *qbus_create(const char *typename, DeviceState *parent, const char *name);
-/* Returns > 0 if either devfn or busfn skip walk somewhere in cursion,
- *         < 0 if either devfn or busfn terminate walk somewhere in cursion,
- *           0 otherwise. */
-int qbus_walk_children(BusState *bus, qdev_walkerfn *devfn,
-                       qbus_walkerfn *busfn, void *opaque);
-int qdev_walk_children(DeviceState *dev, qdev_walkerfn *devfn,
-                       qbus_walkerfn *busfn, void *opaque);
-void qdev_reset_all(DeviceState *dev);
-
-/**
- * @qbus_reset_all:
- * @bus: Bus to be reset.
- *
- * Reset @bus and perform a bus-level ("hard") reset of all devices connected
- * to it, including recursive processing of all buses below @bus itself.  A
- * hard reset means that qbus_reset_all will reset all state of the device.
- * For PCI devices, for example, this will include the base address registers
- * or configuration space.
- */
-void qbus_reset_all(BusState *bus);
-void qbus_reset_all_fn(void *opaque);
-
-void qbus_free(BusState *bus);
-
-#define FROM_QBUS(type, dev) DO_UPCAST(type, qbus, dev)
-
-/* This should go away once we get rid of the NULL bus hack */
-BusState *sysbus_get_default(void);
-
-char *qdev_get_fw_dev_path(DeviceState *dev);
-
-/**
- * @qdev_machine_init
- *
- * Initialize platform devices before machine init.  This is a hack until full
- * support for composition is added.
- */
-void qdev_machine_init(void);
-
-/**
- * @device_reset
- *
- * Reset a single device (by calling the reset method).
- */
-void device_reset(DeviceState *dev);
-
-const struct VMStateDescription *qdev_get_vmsd(DeviceState *dev);
-
-const char *qdev_fw_name(DeviceState *dev);
-
-Object *qdev_get_machine(void);
-
-/* FIXME: make this a link<> */
-void qdev_set_parent_bus(DeviceState *dev, BusState *bus);
-
-extern int qdev_hotplug;
-
-char *qdev_get_dev_path(DeviceState *dev);
-
-#endif
diff --git a/hw/qdev-dma.h b/hw/qdev-dma.h
deleted file mode 100644 (file)
index 6812735..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-/*
- * Support for dma_addr_t typed properties
- *
- * Copyright (C) 2012 David Gibson, IBM Corporation.
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
-#define DEFINE_PROP_DMAADDR(_n, _s, _f, _d)                               \
-    DEFINE_PROP_HEX64(_n, _s, _f, _d)
diff --git a/hw/qdev-properties-system.c b/hw/qdev-properties-system.c
deleted file mode 100644 (file)
index a22b155..0000000
+++ /dev/null
@@ -1,391 +0,0 @@
-/*
- * qdev property parsing and global properties
- * (parts specific for qemu-system-*)
- *
- * This file is based on code from hw/qdev-properties.c from
- * commit 074a86fccd185616469dfcdc0e157f438aebba18,
- * Copyright (c) Gerd Hoffmann <kraxel@redhat.com> and other contributors.
- *
- * 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 "net/net.h"
-#include "hw/qdev.h"
-#include "qapi/qmp/qerror.h"
-#include "sysemu/blockdev.h"
-#include "hw/block-common.h"
-#include "net/hub.h"
-#include "qapi/visitor.h"
-#include "char/char.h"
-
-static void get_pointer(Object *obj, Visitor *v, Property *prop,
-                        const char *(*print)(void *ptr),
-                        const char *name, Error **errp)
-{
-    DeviceState *dev = DEVICE(obj);
-    void **ptr = qdev_get_prop_ptr(dev, prop);
-    char *p;
-
-    p = (char *) (*ptr ? print(*ptr) : "");
-    visit_type_str(v, &p, name, errp);
-}
-
-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);
-    Error *local_err = NULL;
-    void **ptr = qdev_get_prop_ptr(dev, prop);
-    char *str;
-    int ret;
-
-    if (dev->realized) {
-        qdev_prop_set_after_realize(dev, name, errp);
-        return;
-    }
-
-    visit_type_str(v, &str, name, &local_err);
-    if (local_err) {
-        error_propagate(errp, local_err);
-        return;
-    }
-    if (!*str) {
-        g_free(str);
-        *ptr = NULL;
-        return;
-    }
-    ret = parse(dev, str, ptr);
-    error_set_from_qdev_prop_error(errp, ret, dev, prop, str);
-    g_free(str);
-}
-
-/* --- drive --- */
-
-static int parse_drive(DeviceState *dev, const char *str, void **ptr)
-{
-    BlockDriverState *bs;
-
-    bs = bdrv_find(str);
-    if (bs == NULL) {
-        return -ENOENT;
-    }
-    if (bdrv_attach_dev(bs, dev) < 0) {
-        return -EEXIST;
-    }
-    *ptr = bs;
-    return 0;
-}
-
-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) {
-        bdrv_detach_dev(*ptr, dev);
-        blockdev_auto_del(*ptr);
-    }
-}
-
-static const char *print_drive(void *ptr)
-{
-    return bdrv_get_device_name(ptr);
-}
-
-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",
-    .get   = get_drive,
-    .set   = set_drive,
-    .release = release_drive,
-};
-
-/* --- character device --- */
-
-static int parse_chr(DeviceState *dev, const char *str, void **ptr)
-{
-    CharDriverState *chr = qemu_chr_find(str);
-    if (chr == NULL) {
-        return -ENOENT;
-    }
-    if (qemu_chr_fe_claim(chr) != 0) {
-        return -EEXIST;
-    }
-    *ptr = chr;
-    return 0;
-}
-
-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);
-    CharDriverState *chr = *ptr;
-
-    if (chr) {
-        qemu_chr_add_handlers(chr, NULL, NULL, NULL, NULL);
-        qemu_chr_fe_release(chr);
-    }
-}
-
-
-static const char *print_chr(void *ptr)
-{
-    CharDriverState *chr = ptr;
-
-    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",
-    .get   = get_chr,
-    .set   = set_chr,
-    .release = release_chr,
-};
-
-/* --- netdev device --- */
-
-static int parse_netdev(DeviceState *dev, const char *str, void **ptr)
-{
-    NICPeers *peers_ptr = (NICPeers *)ptr;
-    NICConf *conf = container_of(peers_ptr, NICConf, peers);
-    NetClientState **ncs = peers_ptr->ncs;
-    NetClientState *peers[MAX_QUEUE_NUM];
-    int queues, i = 0;
-    int ret;
-
-    queues = qemu_find_net_clients_except(str, peers,
-                                          NET_CLIENT_OPTIONS_KIND_NIC,
-                                          MAX_QUEUE_NUM);
-    if (queues == 0) {
-        ret = -ENOENT;
-        goto err;
-    }
-
-    if (queues > MAX_QUEUE_NUM) {
-        ret = -E2BIG;
-        goto err;
-    }
-
-    for (i = 0; i < queues; i++) {
-        if (peers[i] == NULL) {
-            ret = -ENOENT;
-            goto err;
-        }
-
-        if (peers[i]->peer) {
-            ret = -EEXIST;
-            goto err;
-        }
-
-        ncs[i] = peers[i];
-        ncs[i]->queue_index = i;
-    }
-
-    conf->queues = queues;
-
-    return 0;
-
-err:
-    return ret;
-}
-
-static const char *print_netdev(void *ptr)
-{
-    NetClientState *netdev = ptr;
-
-    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",
-    .get   = get_netdev,
-    .set   = set_netdev,
-};
-
-/* --- vlan --- */
-
-static int print_vlan(DeviceState *dev, Property *prop, char *dest, size_t len)
-{
-    NetClientState **ptr = qdev_get_prop_ptr(dev, prop);
-
-    if (*ptr) {
-        int id;
-        if (!net_hub_id_for_client(*ptr, &id)) {
-            return snprintf(dest, len, "%d", id);
-        }
-    }
-
-    return snprintf(dest, len, "<null>");
-}
-
-static void get_vlan(Object *obj, Visitor *v, void *opaque,
-                     const char *name, Error **errp)
-{
-    DeviceState *dev = DEVICE(obj);
-    Property *prop = opaque;
-    NetClientState **ptr = qdev_get_prop_ptr(dev, prop);
-    int32_t id = -1;
-
-    if (*ptr) {
-        int hub_id;
-        if (!net_hub_id_for_client(*ptr, &hub_id)) {
-            id = hub_id;
-        }
-    }
-
-    visit_type_int32(v, &id, name, errp);
-}
-
-static void set_vlan(Object *obj, Visitor *v, void *opaque,
-                     const char *name, Error **errp)
-{
-    DeviceState *dev = DEVICE(obj);
-    Property *prop = opaque;
-    NICPeers *peers_ptr = qdev_get_prop_ptr(dev, prop);
-    NetClientState **ptr = &peers_ptr->ncs[0];
-    Error *local_err = NULL;
-    int32_t id;
-    NetClientState *hubport;
-
-    if (dev->realized) {
-        qdev_prop_set_after_realize(dev, name, errp);
-        return;
-    }
-
-    visit_type_int32(v, &id, name, &local_err);
-    if (local_err) {
-        error_propagate(errp, local_err);
-        return;
-    }
-    if (id == -1) {
-        *ptr = NULL;
-        return;
-    }
-
-    hubport = net_hub_port_find(id);
-    if (!hubport) {
-        error_set(errp, QERR_INVALID_PARAMETER_VALUE,
-                  name, prop->info->name);
-        return;
-    }
-    *ptr = hubport;
-}
-
-PropertyInfo qdev_prop_vlan = {
-    .name  = "vlan",
-    .print = print_vlan,
-    .get   = get_vlan,
-    .set   = set_vlan,
-};
-
-int qdev_prop_set_drive(DeviceState *dev, const char *name,
-                        BlockDriverState *value)
-{
-    Error *errp = NULL;
-    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);
-        error_free(errp);
-        return -1;
-    }
-    return 0;
-}
-
-void qdev_prop_set_drive_nofail(DeviceState *dev, const char *name,
-                                BlockDriverState *value)
-{
-    if (qdev_prop_set_drive(dev, name, value) < 0) {
-        exit(1);
-    }
-}
-void qdev_prop_set_chr(DeviceState *dev, const char *name,
-                       CharDriverState *value)
-{
-    Error *errp = NULL;
-    assert(!value || value->label);
-    object_property_set_str(OBJECT(dev),
-                            value ? value->label : "", name, &errp);
-    assert_no_error(errp);
-}
-
-void qdev_prop_set_netdev(DeviceState *dev, const char *name,
-                          NetClientState *value)
-{
-    Error *errp = NULL;
-    assert(!value || value->name);
-    object_property_set_str(OBJECT(dev),
-                            value ? value->name : "", name, &errp);
-    assert_no_error(errp);
-}
-
-void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd)
-{
-    qdev_prop_set_macaddr(dev, "mac", nd->macaddr.a);
-    if (nd->netdev) {
-        qdev_prop_set_netdev(dev, "netdev", nd->netdev);
-    }
-    if (nd->nvectors != DEV_NVECTORS_UNSPECIFIED &&
-        object_property_find(OBJECT(dev), "vectors", NULL)) {
-        qdev_prop_set_uint32(dev, "vectors", nd->nvectors);
-    }
-    nd->instantiated = 1;
-}
-
-static int qdev_add_one_global(QemuOpts *opts, void *opaque)
-{
-    GlobalProperty *g;
-
-    g = g_malloc0(sizeof(*g));
-    g->driver   = qemu_opt_get(opts, "driver");
-    g->property = qemu_opt_get(opts, "property");
-    g->value    = qemu_opt_get(opts, "value");
-    qdev_prop_register_global(g);
-    return 0;
-}
-
-void qemu_add_globals(void)
-{
-    qemu_opts_foreach(qemu_find_opts("global"), qdev_add_one_global, NULL, 0);
-}
diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c
deleted file mode 100644 (file)
index 168c466..0000000
+++ /dev/null
@@ -1,1092 +0,0 @@
-#include "net/net.h"
-#include "hw/qdev.h"
-#include "qapi/qmp/qerror.h"
-#include "sysemu/blockdev.h"
-#include "hw/block-common.h"
-#include "net/hub.h"
-#include "qapi/visitor.h"
-#include "char/char.h"
-
-void qdev_prop_set_after_realize(DeviceState *dev, const char *name,
-                                  Error **errp)
-{
-    if (dev->id) {
-        error_setg(errp, "Attempt to set property '%s' on device '%s' "
-                   "(type '%s') after it was realized", name, dev->id,
-                   object_get_typename(OBJECT(dev)));
-    } else {
-        error_setg(errp, "Attempt to set property '%s' on anonymous device "
-                   "(type '%s') after it was realized", name,
-                   object_get_typename(OBJECT(dev)));
-    }
-}
-
-void *qdev_get_prop_ptr(DeviceState *dev, Property *prop)
-{
-    void *ptr = dev;
-    ptr += prop->offset;
-    return ptr;
-}
-
-static void get_enum(Object *obj, Visitor *v, void *opaque,
-                     const char *name, Error **errp)
-{
-    DeviceState *dev = DEVICE(obj);
-    Property *prop = opaque;
-    int *ptr = qdev_get_prop_ptr(dev, prop);
-
-    visit_type_enum(v, ptr, prop->info->enum_table,
-                    prop->info->name, prop->name, errp);
-}
-
-static void set_enum(Object *obj, Visitor *v, void *opaque,
-                     const char *name, Error **errp)
-{
-    DeviceState *dev = DEVICE(obj);
-    Property *prop = opaque;
-    int *ptr = qdev_get_prop_ptr(dev, prop);
-
-    if (dev->realized) {
-        qdev_prop_set_after_realize(dev, name, errp);
-        return;
-    }
-
-    visit_type_enum(v, ptr, prop->info->enum_table,
-                    prop->info->name, prop->name, errp);
-}
-
-/* Bit */
-
-static uint32_t qdev_get_prop_mask(Property *prop)
-{
-    assert(prop->info == &qdev_prop_bit);
-    return 0x1 << prop->bitnr;
-}
-
-static void bit_prop_set(DeviceState *dev, Property *props, bool val)
-{
-    uint32_t *p = qdev_get_prop_ptr(dev, props);
-    uint32_t mask = qdev_get_prop_mask(props);
-    if (val) {
-        *p |= mask;
-    } else {
-        *p &= ~mask;
-    }
-}
-
-static int print_bit(DeviceState *dev, Property *prop, char *dest, size_t len)
-{
-    uint32_t *p = qdev_get_prop_ptr(dev, prop);
-    return snprintf(dest, len, (*p & qdev_get_prop_mask(prop)) ? "on" : "off");
-}
-
-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;
-
-    visit_type_bool(v, &value, name, errp);
-}
-
-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;
-
-    if (dev->realized) {
-        qdev_prop_set_after_realize(dev, name, errp);
-        return;
-    }
-
-    visit_type_bool(v, &value, name, &local_err);
-    if (local_err) {
-        error_propagate(errp, local_err);
-        return;
-    }
-    bit_prop_set(dev, prop, value);
-}
-
-PropertyInfo qdev_prop_bit = {
-    .name  = "boolean",
-    .legacy_name  = "on/off",
-    .print = print_bit,
-    .get   = get_bit,
-    .set   = set_bit,
-};
-
-/* --- 8bit integer --- */
-
-static void get_uint8(Object *obj, Visitor *v, void *opaque,
-                      const char *name, Error **errp)
-{
-    DeviceState *dev = DEVICE(obj);
-    Property *prop = opaque;
-    uint8_t *ptr = qdev_get_prop_ptr(dev, prop);
-
-    visit_type_uint8(v, ptr, name, errp);
-}
-
-static void set_uint8(Object *obj, Visitor *v, void *opaque,
-                      const char *name, Error **errp)
-{
-    DeviceState *dev = DEVICE(obj);
-    Property *prop = opaque;
-    uint8_t *ptr = qdev_get_prop_ptr(dev, prop);
-
-    if (dev->realized) {
-        qdev_prop_set_after_realize(dev, name, errp);
-        return;
-    }
-
-    visit_type_uint8(v, ptr, name, errp);
-}
-
-PropertyInfo qdev_prop_uint8 = {
-    .name  = "uint8",
-    .get   = get_uint8,
-    .set   = set_uint8,
-};
-
-/* --- 8bit hex value --- */
-
-static int parse_hex8(DeviceState *dev, Property *prop, const char *str)
-{
-    uint8_t *ptr = qdev_get_prop_ptr(dev, prop);
-    char *end;
-
-    if (str[0] != '0' || str[1] != 'x') {
-        return -EINVAL;
-    }
-
-    *ptr = strtoul(str, &end, 16);
-    if ((*end != '\0') || (end == str)) {
-        return -EINVAL;
-    }
-
-    return 0;
-}
-
-static int print_hex8(DeviceState *dev, Property *prop, char *dest, size_t len)
-{
-    uint8_t *ptr = qdev_get_prop_ptr(dev, prop);
-    return snprintf(dest, len, "0x%" PRIx8, *ptr);
-}
-
-PropertyInfo qdev_prop_hex8 = {
-    .name  = "uint8",
-    .legacy_name  = "hex8",
-    .parse = parse_hex8,
-    .print = print_hex8,
-    .get   = get_uint8,
-    .set   = set_uint8,
-};
-
-/* --- 16bit integer --- */
-
-static void get_uint16(Object *obj, Visitor *v, void *opaque,
-                       const char *name, Error **errp)
-{
-    DeviceState *dev = DEVICE(obj);
-    Property *prop = opaque;
-    uint16_t *ptr = qdev_get_prop_ptr(dev, prop);
-
-    visit_type_uint16(v, ptr, name, errp);
-}
-
-static void set_uint16(Object *obj, Visitor *v, void *opaque,
-                       const char *name, Error **errp)
-{
-    DeviceState *dev = DEVICE(obj);
-    Property *prop = opaque;
-    uint16_t *ptr = qdev_get_prop_ptr(dev, prop);
-
-    if (dev->realized) {
-        qdev_prop_set_after_realize(dev, name, errp);
-        return;
-    }
-
-    visit_type_uint16(v, ptr, name, errp);
-}
-
-PropertyInfo qdev_prop_uint16 = {
-    .name  = "uint16",
-    .get   = get_uint16,
-    .set   = set_uint16,
-};
-
-/* --- 32bit integer --- */
-
-static void get_uint32(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);
-
-    visit_type_uint32(v, ptr, name, errp);
-}
-
-static void set_uint32(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);
-
-    if (dev->realized) {
-        qdev_prop_set_after_realize(dev, name, errp);
-        return;
-    }
-
-    visit_type_uint32(v, ptr, name, errp);
-}
-
-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);
-
-    visit_type_int32(v, ptr, name, errp);
-}
-
-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);
-
-    if (dev->realized) {
-        qdev_prop_set_after_realize(dev, name, errp);
-        return;
-    }
-
-    visit_type_int32(v, ptr, name, errp);
-}
-
-PropertyInfo qdev_prop_uint32 = {
-    .name  = "uint32",
-    .get   = get_uint32,
-    .set   = set_uint32,
-};
-
-PropertyInfo qdev_prop_int32 = {
-    .name  = "int32",
-    .get   = get_int32,
-    .set   = set_int32,
-};
-
-/* --- 32bit hex value --- */
-
-static int parse_hex32(DeviceState *dev, Property *prop, const char *str)
-{
-    uint32_t *ptr = qdev_get_prop_ptr(dev, prop);
-    char *end;
-
-    if (str[0] != '0' || str[1] != 'x') {
-        return -EINVAL;
-    }
-
-    *ptr = strtoul(str, &end, 16);
-    if ((*end != '\0') || (end == str)) {
-        return -EINVAL;
-    }
-
-    return 0;
-}
-
-static int print_hex32(DeviceState *dev, Property *prop, char *dest, size_t len)
-{
-    uint32_t *ptr = qdev_get_prop_ptr(dev, prop);
-    return snprintf(dest, len, "0x%" PRIx32, *ptr);
-}
-
-PropertyInfo qdev_prop_hex32 = {
-    .name  = "uint32",
-    .legacy_name  = "hex32",
-    .parse = parse_hex32,
-    .print = print_hex32,
-    .get   = get_uint32,
-    .set   = set_uint32,
-};
-
-/* --- 64bit integer --- */
-
-static void get_uint64(Object *obj, Visitor *v, void *opaque,
-                       const char *name, Error **errp)
-{
-    DeviceState *dev = DEVICE(obj);
-    Property *prop = opaque;
-    uint64_t *ptr = qdev_get_prop_ptr(dev, prop);
-
-    visit_type_uint64(v, ptr, name, errp);
-}
-
-static void set_uint64(Object *obj, Visitor *v, void *opaque,
-                       const char *name, Error **errp)
-{
-    DeviceState *dev = DEVICE(obj);
-    Property *prop = opaque;
-    uint64_t *ptr = qdev_get_prop_ptr(dev, prop);
-
-    if (dev->realized) {
-        qdev_prop_set_after_realize(dev, name, errp);
-        return;
-    }
-
-    visit_type_uint64(v, ptr, name, errp);
-}
-
-PropertyInfo qdev_prop_uint64 = {
-    .name  = "uint64",
-    .get   = get_uint64,
-    .set   = set_uint64,
-};
-
-/* --- 64bit hex value --- */
-
-static int parse_hex64(DeviceState *dev, Property *prop, const char *str)
-{
-    uint64_t *ptr = qdev_get_prop_ptr(dev, prop);
-    char *end;
-
-    if (str[0] != '0' || str[1] != 'x') {
-        return -EINVAL;
-    }
-
-    *ptr = strtoull(str, &end, 16);
-    if ((*end != '\0') || (end == str)) {
-        return -EINVAL;
-    }
-
-    return 0;
-}
-
-static int print_hex64(DeviceState *dev, Property *prop, char *dest, size_t len)
-{
-    uint64_t *ptr = qdev_get_prop_ptr(dev, prop);
-    return snprintf(dest, len, "0x%" PRIx64, *ptr);
-}
-
-PropertyInfo qdev_prop_hex64 = {
-    .name  = "uint64",
-    .legacy_name  = "hex64",
-    .parse = parse_hex64,
-    .print = print_hex64,
-    .get   = get_uint64,
-    .set   = set_uint64,
-};
-
-/* --- string --- */
-
-static void release_string(Object *obj, const char *name, void *opaque)
-{
-    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)
-{
-    char **ptr = qdev_get_prop_ptr(dev, prop);
-    if (!*ptr) {
-        return snprintf(dest, len, "<null>");
-    }
-    return snprintf(dest, len, "\"%s\"", *ptr);
-}
-
-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);
-
-    if (!*ptr) {
-        char *str = (char *)"";
-        visit_type_str(v, &str, name, errp);
-    } else {
-        visit_type_str(v, ptr, name, errp);
-    }
-}
-
-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;
-    char *str;
-
-    if (dev->realized) {
-        qdev_prop_set_after_realize(dev, name, errp);
-        return;
-    }
-
-    visit_type_str(v, &str, name, &local_err);
-    if (local_err) {
-        error_propagate(errp, local_err);
-        return;
-    }
-    if (*ptr) {
-        g_free(*ptr);
-    }
-    *ptr = str;
-}
-
-PropertyInfo qdev_prop_string = {
-    .name  = "string",
-    .print = print_string,
-    .release = release_string,
-    .get   = get_string,
-    .set   = set_string,
-};
-
-/* --- pointer --- */
-
-/* Not a proper property, just for dirty hacks.  TODO Remove it!  */
-PropertyInfo qdev_prop_ptr = {
-    .name  = "ptr",
-};
-
-/* --- mac address --- */
-
-/*
- * accepted syntax versions:
- *   01:02:03:04:05:06
- *   01-02-03-04-05-06
- */
-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 *str, *p;
-
-    if (dev->realized) {
-        qdev_prop_set_after_realize(dev, name, errp);
-        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])) {
-            goto inval;
-        }
-        if (!qemu_isxdigit(str[pos+1])) {
-            goto inval;
-        }
-        if (i == 5) {
-            if (str[pos+2] != '\0') {
-                goto inval;
-            }
-        } else {
-            if (str[pos+2] != ':' && str[pos+2] != '-') {
-                goto inval;
-            }
-        }
-        mac->a[i] = strtol(str+pos, &p, 16);
-    }
-    g_free(str);
-    return;
-
-inval:
-    error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str);
-    g_free(str);
-}
-
-PropertyInfo qdev_prop_macaddr = {
-    .name  = "macaddr",
-    .get   = get_mac,
-    .set   = set_mac,
-};
-
-/* --- lost tick policy --- */
-
-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,
-};
-
-QEMU_BUILD_BUG_ON(sizeof(LostTickPolicy) != sizeof(int));
-
-PropertyInfo qdev_prop_losttickpolicy = {
-    .name  = "LostTickPolicy",
-    .enum_table  = lost_tick_policy_table,
-    .get   = get_enum,
-    .set   = set_enum,
-};
-
-/* --- BIOS CHS translation */
-
-static const char *bios_chs_trans_table[] = {
-    [BIOS_ATA_TRANSLATION_AUTO] = "auto",
-    [BIOS_ATA_TRANSLATION_NONE] = "none",
-    [BIOS_ATA_TRANSLATION_LBA]  = "lba",
-};
-
-PropertyInfo qdev_prop_bios_chs_trans = {
-    .name = "bios-chs-trans",
-    .enum_table = bios_chs_trans_table,
-    .get = get_enum,
-    .set = set_enum,
-};
-
-/* --- pci address --- */
-
-/*
- * bus-local address, i.e. "$slot" or "$slot.$fn"
- */
-static void set_pci_devfn(Object *obj, Visitor *v, void *opaque,
-                          const char *name, Error **errp)
-{
-    DeviceState *dev = DEVICE(obj);
-    Property *prop = opaque;
-    int32_t value, *ptr = qdev_get_prop_ptr(dev, prop);
-    unsigned int slot, fn, n;
-    Error *local_err = NULL;
-    char *str;
-
-    if (dev->realized) {
-        qdev_prop_set_after_realize(dev, name, errp);
-        return;
-    }
-
-    visit_type_str(v, &str, name, &local_err);
-    if (local_err) {
-        error_free(local_err);
-        local_err = NULL;
-        visit_type_int32(v, &value, name, &local_err);
-        if (local_err) {
-            error_propagate(errp, local_err);
-        } else if (value < -1 || value > 255) {
-            error_set(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null",
-                      "pci_devfn");
-        } else {
-            *ptr = value;
-        }
-        return;
-    }
-
-    if (sscanf(str, "%x.%x%n", &slot, &fn, &n) != 2) {
-        fn = 0;
-        if (sscanf(str, "%x%n", &slot, &n) != 1) {
-            goto invalid;
-        }
-    }
-    if (str[n] != '\0' || fn > 7 || slot > 31) {
-        goto invalid;
-    }
-    *ptr = slot << 3 | fn;
-    g_free(str);
-    return;
-
-invalid:
-    error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str);
-    g_free(str);
-}
-
-static int print_pci_devfn(DeviceState *dev, Property *prop, char *dest,
-                           size_t len)
-{
-    int32_t *ptr = qdev_get_prop_ptr(dev, prop);
-
-    if (*ptr == -1) {
-        return snprintf(dest, len, "<unset>");
-    } else {
-        return snprintf(dest, len, "%02x.%x", *ptr >> 3, *ptr & 7);
-    }
-}
-
-PropertyInfo qdev_prop_pci_devfn = {
-    .name  = "int32",
-    .legacy_name  = "pci-devfn",
-    .print = print_pci_devfn,
-    .get   = get_int32,
-    .set   = set_pci_devfn,
-};
-
-/* --- blocksize --- */
-
-static void set_blocksize(Object *obj, Visitor *v, void *opaque,
-                          const char *name, Error **errp)
-{
-    DeviceState *dev = DEVICE(obj);
-    Property *prop = opaque;
-    uint16_t value, *ptr = qdev_get_prop_ptr(dev, prop);
-    Error *local_err = NULL;
-    const int64_t min = 512;
-    const int64_t max = 32768;
-
-    if (dev->realized) {
-        qdev_prop_set_after_realize(dev, name, errp);
-        return;
-    }
-
-    visit_type_uint16(v, &value, name, &local_err);
-    if (local_err) {
-        error_propagate(errp, local_err);
-        return;
-    }
-    if (value < min || value > max) {
-        error_set(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE,
-                  dev->id?:"", name, (int64_t)value, min, max);
-        return;
-    }
-
-    /* We rely on power-of-2 blocksizes for bitmasks */
-    if ((value & (value - 1)) != 0) {
-        error_set(errp, QERR_PROPERTY_VALUE_NOT_POWER_OF_2,
-                  dev->id?:"", name, (int64_t)value);
-        return;
-    }
-
-    *ptr = value;
-}
-
-PropertyInfo qdev_prop_blocksize = {
-    .name  = "blocksize",
-    .get   = get_uint16,
-    .set   = set_blocksize,
-};
-
-/* --- pci host address --- */
-
-static void get_pci_host_devaddr(Object *obj, Visitor *v, void *opaque,
-                                 const char *name, Error **errp)
-{
-    DeviceState *dev = DEVICE(obj);
-    Property *prop = opaque;
-    PCIHostDeviceAddress *addr = qdev_get_prop_ptr(dev, prop);
-    char buffer[] = "xxxx:xx:xx.x";
-    char *p = buffer;
-    int rc = 0;
-
-    rc = snprintf(buffer, sizeof(buffer), "%04x:%02x:%02x.%d",
-                  addr->domain, addr->bus, addr->slot, addr->function);
-    assert(rc == sizeof(buffer) - 1);
-
-    visit_type_str(v, &p, name, errp);
-}
-
-/*
- * Parse [<domain>:]<bus>:<slot>.<func>
- *   if <domain> is not supplied, it's assumed to be 0.
- */
-static void set_pci_host_devaddr(Object *obj, Visitor *v, void *opaque,
-                                 const char *name, Error **errp)
-{
-    DeviceState *dev = DEVICE(obj);
-    Property *prop = opaque;
-    PCIHostDeviceAddress *addr = qdev_get_prop_ptr(dev, prop);
-    Error *local_err = NULL;
-    char *str, *p;
-    char *e;
-    unsigned long val;
-    unsigned long dom = 0, bus = 0;
-    unsigned int slot = 0, func = 0;
-
-    if (dev->realized) {
-        qdev_prop_set_after_realize(dev, name, errp);
-        return;
-    }
-
-    visit_type_str(v, &str, name, &local_err);
-    if (local_err) {
-        error_propagate(errp, local_err);
-        return;
-    }
-
-    p = str;
-    val = strtoul(p, &e, 16);
-    if (e == p || *e != ':') {
-        goto inval;
-    }
-    bus = val;
-
-    p = e + 1;
-    val = strtoul(p, &e, 16);
-    if (e == p) {
-        goto inval;
-    }
-    if (*e == ':') {
-        dom = bus;
-        bus = val;
-        p = e + 1;
-        val = strtoul(p, &e, 16);
-        if (e == p) {
-            goto inval;
-        }
-    }
-    slot = val;
-
-    if (*e != '.') {
-        goto inval;
-    }
-    p = e + 1;
-    val = strtoul(p, &e, 10);
-    if (e == p) {
-        goto inval;
-    }
-    func = val;
-
-    if (dom > 0xffff || bus > 0xff || slot > 0x1f || func > 7) {
-        goto inval;
-    }
-
-    if (*e) {
-        goto inval;
-    }
-
-    addr->domain = dom;
-    addr->bus = bus;
-    addr->slot = slot;
-    addr->function = func;
-
-    g_free(str);
-    return;
-
-inval:
-    error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str);
-    g_free(str);
-}
-
-PropertyInfo qdev_prop_pci_host_devaddr = {
-    .name = "pci-host-devaddr",
-    .get = get_pci_host_devaddr,
-    .set = set_pci_host_devaddr,
-};
-
-/* --- support for array properties --- */
-
-/* Used as an opaque for the object properties we add for each
- * array element. Note that the struct Property must be first
- * in the struct so that a pointer to this works as the opaque
- * for the underlying element's property hooks as well as for
- * our own release callback.
- */
-typedef struct {
-    struct Property prop;
-    char *propname;
-    ObjectPropertyRelease *release;
-} ArrayElementProperty;
-
-/* object property release callback for array element properties:
- * we call the underlying element's property release hook, and
- * then free the memory we allocated when we added the property.
- */
-static void array_element_release(Object *obj, const char *name, void *opaque)
-{
-    ArrayElementProperty *p = opaque;
-    if (p->release) {
-        p->release(obj, name, opaque);
-    }
-    g_free(p->propname);
-    g_free(p);
-}
-
-static void set_prop_arraylen(Object *obj, Visitor *v, void *opaque,
-                              const char *name, Error **errp)
-{
-    /* Setter for the property which defines the length of a
-     * variable-sized property array. As well as actually setting the
-     * array-length field in the device struct, we have to create the
-     * array itself and dynamically add the corresponding properties.
-     */
-    DeviceState *dev = DEVICE(obj);
-    Property *prop = opaque;
-    uint32_t *alenptr = qdev_get_prop_ptr(dev, prop);
-    void **arrayptr = (void *)dev + prop->arrayoffset;
-    void *eltptr;
-    const char *arrayname;
-    int i;
-
-    if (dev->realized) {
-        qdev_prop_set_after_realize(dev, name, errp);
-        return;
-    }
-    if (*alenptr) {
-        error_setg(errp, "array size property %s may not be set more than once",
-                   name);
-        return;
-    }
-    visit_type_uint32(v, alenptr, name, errp);
-    if (error_is_set(errp)) {
-        return;
-    }
-    if (!*alenptr) {
-        return;
-    }
-
-    /* DEFINE_PROP_ARRAY guarantees that name should start with this prefix;
-     * strip it off so we can get the name of the array itself.
-     */
-    assert(strncmp(name, PROP_ARRAY_LEN_PREFIX,
-                   strlen(PROP_ARRAY_LEN_PREFIX)) == 0);
-    arrayname = name + strlen(PROP_ARRAY_LEN_PREFIX);
-
-    /* Note that it is the responsibility of the individual device's deinit
-     * to free the array proper.
-     */
-    *arrayptr = eltptr = g_malloc0(*alenptr * prop->arrayfieldsize);
-    for (i = 0; i < *alenptr; i++, eltptr += prop->arrayfieldsize) {
-        char *propname = g_strdup_printf("%s[%d]", arrayname, i);
-        ArrayElementProperty *arrayprop = g_new0(ArrayElementProperty, 1);
-        arrayprop->release = prop->arrayinfo->release;
-        arrayprop->propname = propname;
-        arrayprop->prop.info = prop->arrayinfo;
-        arrayprop->prop.name = propname;
-        /* This ugly piece of pointer arithmetic sets up the offset so
-         * that when the underlying get/set hooks call qdev_get_prop_ptr
-         * they get the right answer despite the array element not actually
-         * being inside the device struct.
-         */
-        arrayprop->prop.offset = eltptr - (void *)dev;
-        assert(qdev_get_prop_ptr(dev, &arrayprop->prop) == eltptr);
-        object_property_add(obj, propname,
-                            arrayprop->prop.info->name,
-                            arrayprop->prop.info->get,
-                            arrayprop->prop.info->set,
-                            array_element_release,
-                            arrayprop, errp);
-        if (error_is_set(errp)) {
-            return;
-        }
-    }
-}
-
-PropertyInfo qdev_prop_arraylen = {
-    .name = "uint32",
-    .get = get_uint32,
-    .set = set_prop_arraylen,
-};
-
-/* --- public helpers --- */
-
-static Property *qdev_prop_walk(Property *props, const char *name)
-{
-    if (!props) {
-        return NULL;
-    }
-    while (props->name) {
-        if (strcmp(props->name, name) == 0) {
-            return props;
-        }
-        props++;
-    }
-    return NULL;
-}
-
-static Property *qdev_prop_find(DeviceState *dev, const char *name)
-{
-    ObjectClass *class;
-    Property *prop;
-
-    /* device properties */
-    class = object_get_class(OBJECT(dev));
-    do {
-        prop = qdev_prop_walk(DEVICE_CLASS(class)->props, name);
-        if (prop) {
-            return prop;
-        }
-        class = object_class_get_parent(class);
-    } while (class != object_class_by_name(TYPE_DEVICE));
-
-    return NULL;
-}
-
-void error_set_from_qdev_prop_error(Error **errp, int ret, DeviceState *dev,
-                                    Property *prop, const char *value)
-{
-    switch (ret) {
-    case -EEXIST:
-        error_set(errp, QERR_PROPERTY_VALUE_IN_USE,
-                  object_get_typename(OBJECT(dev)), prop->name, value);
-        break;
-    default:
-    case -EINVAL:
-        error_set(errp, QERR_PROPERTY_VALUE_BAD,
-                  object_get_typename(OBJECT(dev)), prop->name, value);
-        break;
-    case -ENOENT:
-        error_set(errp, QERR_PROPERTY_VALUE_NOT_FOUND,
-                  object_get_typename(OBJECT(dev)), prop->name, value);
-        break;
-    case 0:
-        break;
-    }
-}
-
-int qdev_prop_parse(DeviceState *dev, const char *name, const char *value)
-{
-    char *legacy_name;
-    Error *err = NULL;
-
-    legacy_name = g_strdup_printf("legacy-%s", name);
-    if (object_property_get_type(OBJECT(dev), legacy_name, NULL)) {
-        object_property_parse(OBJECT(dev), value, legacy_name, &err);
-    } else {
-        object_property_parse(OBJECT(dev), value, name, &err);
-    }
-    g_free(legacy_name);
-
-    if (err) {
-        qerror_report_err(err);
-        error_free(err);
-        return -1;
-    }
-    return 0;
-}
-
-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_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_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_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_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_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_no_error(errp);
-}
-
-void qdev_prop_set_string(DeviceState *dev, const char *name, const char *value)
-{
-    Error *errp = NULL;
-    object_property_set_str(OBJECT(dev), value, name, &errp);
-    assert_no_error(errp);
-}
-
-void qdev_prop_set_macaddr(DeviceState *dev, const char *name, uint8_t *value)
-{
-    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_no_error(errp);
-}
-
-void qdev_prop_set_enum(DeviceState *dev, const char *name, int value)
-{
-    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_no_error(errp);
-}
-
-void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value)
-{
-    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;
-}
-
-static QTAILQ_HEAD(, GlobalProperty) global_props =
-        QTAILQ_HEAD_INITIALIZER(global_props);
-
-void qdev_prop_register_global(GlobalProperty *prop)
-{
-    QTAILQ_INSERT_TAIL(&global_props, prop, next);
-}
-
-void qdev_prop_register_global_list(GlobalProperty *props)
-{
-    int i;
-
-    for (i = 0; props[i].driver != NULL; i++) {
-        qdev_prop_register_global(props+i);
-    }
-}
-
-void qdev_prop_set_globals(DeviceState *dev)
-{
-    ObjectClass *class = object_get_class(OBJECT(dev));
-
-    do {
-        GlobalProperty *prop;
-        QTAILQ_FOREACH(prop, &global_props, next) {
-            if (strcmp(object_class_get_name(class), prop->driver) != 0) {
-                continue;
-            }
-            if (qdev_prop_parse(dev, prop->property, prop->value) != 0) {
-                exit(1);
-            }
-        }
-        class = object_class_get_parent(class);
-    } while (class);
-}
diff --git a/hw/qdev-properties.h b/hw/qdev-properties.h
deleted file mode 100644 (file)
index a379339..0000000
+++ /dev/null
@@ -1,182 +0,0 @@
-#ifndef QEMU_QDEV_PROPERTIES_H
-#define QEMU_QDEV_PROPERTIES_H
-
-#include "hw/qdev-core.h"
-
-/*** qdev-properties.c ***/
-
-extern PropertyInfo qdev_prop_bit;
-extern PropertyInfo qdev_prop_uint8;
-extern PropertyInfo qdev_prop_uint16;
-extern PropertyInfo qdev_prop_uint32;
-extern PropertyInfo qdev_prop_int32;
-extern PropertyInfo qdev_prop_uint64;
-extern PropertyInfo qdev_prop_hex8;
-extern PropertyInfo qdev_prop_hex32;
-extern PropertyInfo qdev_prop_hex64;
-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_bios_chs_trans;
-extern PropertyInfo qdev_prop_drive;
-extern PropertyInfo qdev_prop_netdev;
-extern PropertyInfo qdev_prop_vlan;
-extern PropertyInfo qdev_prop_pci_devfn;
-extern PropertyInfo qdev_prop_blocksize;
-extern PropertyInfo qdev_prop_pci_host_devaddr;
-extern PropertyInfo qdev_prop_arraylen;
-
-#define DEFINE_PROP(_name, _state, _field, _prop, _type) { \
-        .name      = (_name),                                    \
-        .info      = &(_prop),                                   \
-        .offset    = offsetof(_state, _field)                    \
-            + type_check(_type, typeof_field(_state, _field)),   \
-        }
-#define DEFINE_PROP_DEFAULT(_name, _state, _field, _defval, _prop, _type) { \
-        .name      = (_name),                                           \
-        .info      = &(_prop),                                          \
-        .offset    = offsetof(_state, _field)                           \
-            + type_check(_type,typeof_field(_state, _field)),           \
-        .qtype     = QTYPE_QINT,                                        \
-        .defval    = (_type)_defval,                                    \
-        }
-#define DEFINE_PROP_BIT(_name, _state, _field, _bit, _defval) {  \
-        .name      = (_name),                                    \
-        .info      = &(qdev_prop_bit),                           \
-        .bitnr    = (_bit),                                      \
-        .offset    = offsetof(_state, _field)                    \
-            + type_check(uint32_t,typeof_field(_state, _field)), \
-        .qtype     = QTYPE_QBOOL,                                \
-        .defval    = (bool)_defval,                              \
-        }
-
-#define PROP_ARRAY_LEN_PREFIX "len-"
-
-/**
- * DEFINE_PROP_ARRAY:
- * @_name: name of the array
- * @_state: name of the device state structure type
- * @_field: uint32_t field in @_state to hold the array length
- * @_arrayfield: field in @_state (of type '@_arraytype *') which
- *               will point to the array
- * @_arrayprop: PropertyInfo defining what property the array elements have
- * @_arraytype: C type of the array elements
- *
- * Define device properties for a variable-length array _name.  A
- * static property "len-arrayname" is defined. When the device creator
- * sets this property to the desired length of array, further dynamic
- * properties "arrayname[0]", "arrayname[1]", ...  are defined so the
- * device creator can set the array element values. Setting the
- * "len-arrayname" property more than once is an error.
- *
- * When the array length is set, the @_field member of the device
- * struct is set to the array length, and @_arrayfield is set to point
- * to (zero-initialised) memory allocated for the array.  For a zero
- * length array, @_field will be set to 0 and @_arrayfield to NULL.
- * It is the responsibility of the device deinit code to free the
- * @_arrayfield memory.
- */
-#define DEFINE_PROP_ARRAY(_name, _state, _field,                        \
-                          _arrayfield, _arrayprop, _arraytype) {        \
-        .name = (PROP_ARRAY_LEN_PREFIX _name),                          \
-        .info = &(qdev_prop_arraylen),                                  \
-        .offset = offsetof(_state, _field)                              \
-            + type_check(uint32_t, typeof_field(_state, _field)),       \
-        .qtype = QTYPE_QINT,                                            \
-        .arrayinfo = &(_arrayprop),                                     \
-        .arrayfieldsize = sizeof(_arraytype),                           \
-        .arrayoffset = offsetof(_state, _arrayfield),                   \
-        }
-
-#define DEFINE_PROP_UINT8(_n, _s, _f, _d)                       \
-    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_uint8, uint8_t)
-#define DEFINE_PROP_UINT16(_n, _s, _f, _d)                      \
-    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_uint16, uint16_t)
-#define DEFINE_PROP_UINT32(_n, _s, _f, _d)                      \
-    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_uint32, uint32_t)
-#define DEFINE_PROP_INT32(_n, _s, _f, _d)                      \
-    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_int32, int32_t)
-#define DEFINE_PROP_UINT64(_n, _s, _f, _d)                      \
-    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_uint64, uint64_t)
-#define DEFINE_PROP_HEX8(_n, _s, _f, _d)                       \
-    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_hex8, uint8_t)
-#define DEFINE_PROP_HEX32(_n, _s, _f, _d)                       \
-    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_hex32, uint32_t)
-#define DEFINE_PROP_HEX64(_n, _s, _f, _d)                       \
-    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_hex64, uint64_t)
-#define DEFINE_PROP_PCI_DEVFN(_n, _s, _f, _d)                   \
-    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_pci_devfn, int32_t)
-
-#define DEFINE_PROP_PTR(_n, _s, _f)             \
-    DEFINE_PROP(_n, _s, _f, qdev_prop_ptr, void*)
-#define DEFINE_PROP_CHR(_n, _s, _f)             \
-    DEFINE_PROP(_n, _s, _f, qdev_prop_chr, CharDriverState*)
-#define DEFINE_PROP_STRING(_n, _s, _f)             \
-    DEFINE_PROP(_n, _s, _f, qdev_prop_string, char*)
-#define DEFINE_PROP_NETDEV(_n, _s, _f)             \
-    DEFINE_PROP(_n, _s, _f, qdev_prop_netdev, NICPeers)
-#define DEFINE_PROP_VLAN(_n, _s, _f)             \
-    DEFINE_PROP(_n, _s, _f, qdev_prop_vlan, NICPeers)
-#define DEFINE_PROP_DRIVE(_n, _s, _f) \
-    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_BIOS_CHS_TRANS(_n, _s, _f, _d) \
-    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_bios_chs_trans, int)
-#define DEFINE_PROP_BLOCKSIZE(_n, _s, _f, _d) \
-    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_blocksize, uint16_t)
-#define DEFINE_PROP_PCI_HOST_DEVADDR(_n, _s, _f) \
-    DEFINE_PROP(_n, _s, _f, qdev_prop_pci_host_devaddr, PCIHostDeviceAddress)
-
-#define DEFINE_PROP_END_OF_LIST()               \
-    {}
-
-/* Set properties between creation and init.  */
-void *qdev_get_prop_ptr(DeviceState *dev, Property *prop);
-int qdev_prop_parse(DeviceState *dev, const char *name, const char *value);
-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);
-void qdev_prop_set_uint32(DeviceState *dev, const char *name, uint32_t value);
-void qdev_prop_set_int32(DeviceState *dev, const char *name, int32_t value);
-void qdev_prop_set_uint64(DeviceState *dev, const char *name, uint64_t value);
-void qdev_prop_set_string(DeviceState *dev, const char *name, const char *value);
-void qdev_prop_set_chr(DeviceState *dev, const char *name, CharDriverState *value);
-void qdev_prop_set_netdev(DeviceState *dev, const char *name, NetClientState *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_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_register_global(GlobalProperty *prop);
-void qdev_prop_register_global_list(GlobalProperty *props);
-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);
-
-/**
- * @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_prop_set_after_realize:
- * @dev: device
- * @name: name of property
- * @errp: indirect pointer to Error to be set
- * Set the Error object to report that an attempt was made to set a property
- * on a device after it has already been realized. This is a utility function
- * which allows property-setter functions to easily report the error in
- * a friendly format identifying both the device and the property.
- */
-void qdev_prop_set_after_realize(DeviceState *dev, const char *name,
-                                 Error **errp);
-#endif
diff --git a/hw/qdev.c b/hw/qdev.c
deleted file mode 100644 (file)
index e2bb37d..0000000
--- a/hw/qdev.c
+++ /dev/null
@@ -1,882 +0,0 @@
-/*
- *  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/>.
- */
-
-/* The theory here is that it should be possible to create a machine without
-   knowledge of specific devices.  Historically board init routines have
-   passed a bunch of arguments to each device, requiring the board know
-   exactly which device it is dealing with.  This file provides an abstract
-   API for device configuration and initialization.  Devices will generally
-   inherit from a particular bus (e.g. PCI or I2C) rather than
-   this API directly.  */
-
-#include "hw/qdev.h"
-#include "sysemu/sysemu.h"
-#include "qapi/error.h"
-#include "qapi/qmp/qerror.h"
-#include "qapi/visitor.h"
-#include "qapi/qmp/qjson.h"
-#include "monitor/monitor.h"
-
-int qdev_hotplug = 0;
-static bool qdev_hot_added = false;
-static bool qdev_hot_removed = false;
-
-const VMStateDescription *qdev_get_vmsd(DeviceState *dev)
-{
-    DeviceClass *dc = DEVICE_GET_CLASS(dev);
-    return dc->vmsd;
-}
-
-const char *qdev_fw_name(DeviceState *dev)
-{
-    DeviceClass *dc = DEVICE_GET_CLASS(dev);
-
-    if (dc->fw_name) {
-        return dc->fw_name;
-    }
-
-    return object_get_typename(OBJECT(dev));
-}
-
-static void qdev_property_add_legacy(DeviceState *dev, Property *prop,
-                                     Error **errp);
-
-static void bus_remove_child(BusState *bus, DeviceState *child)
-{
-    BusChild *kid;
-
-    QTAILQ_FOREACH(kid, &bus->children, sibling) {
-        if (kid->child == child) {
-            char name[32];
-
-            snprintf(name, sizeof(name), "child[%d]", kid->index);
-            QTAILQ_REMOVE(&bus->children, kid, sibling);
-
-            /* This gives back ownership of kid->child back to us.  */
-            object_property_del(OBJECT(bus), name, NULL);
-            object_unref(OBJECT(kid->child));
-            g_free(kid);
-            return;
-        }
-    }
-}
-
-static void bus_add_child(BusState *bus, DeviceState *child)
-{
-    char name[32];
-    BusChild *kid = g_malloc0(sizeof(*kid));
-
-    if (qdev_hotplug) {
-        assert(bus->allow_hotplug);
-    }
-
-    kid->index = bus->max_index++;
-    kid->child = child;
-    object_ref(OBJECT(kid->child));
-
-    QTAILQ_INSERT_HEAD(&bus->children, kid, sibling);
-
-    /* This transfers ownership of kid->child to the property.  */
-    snprintf(name, sizeof(name), "child[%d]", kid->index);
-    object_property_add_link(OBJECT(bus), name,
-                             object_get_typename(OBJECT(child)),
-                             (Object **)&kid->child,
-                             NULL);
-}
-
-void qdev_set_parent_bus(DeviceState *dev, BusState *bus)
-{
-    dev->parent_bus = bus;
-    object_ref(OBJECT(bus));
-    bus_add_child(bus, dev);
-}
-
-/* Create a new device.  This only initializes the device state structure
-   and allows properties to be set.  qdev_init should be called to
-   initialize the actual device emulation.  */
-DeviceState *qdev_create(BusState *bus, const char *name)
-{
-    DeviceState *dev;
-
-    dev = qdev_try_create(bus, name);
-    if (!dev) {
-        if (bus) {
-            error_report("Unknown device '%s' for bus '%s'", name,
-                         object_get_typename(OBJECT(bus)));
-        } else {
-            error_report("Unknown device '%s' for default sysbus", name);
-        }
-        abort();
-    }
-
-    return dev;
-}
-
-DeviceState *qdev_try_create(BusState *bus, const char *type)
-{
-    DeviceState *dev;
-
-    if (object_class_by_name(type) == NULL) {
-        return NULL;
-    }
-    dev = DEVICE(object_new(type));
-    if (!dev) {
-        return NULL;
-    }
-
-    if (!bus) {
-        bus = sysbus_get_default();
-    }
-
-    qdev_set_parent_bus(dev, bus);
-    object_unref(OBJECT(dev));
-    return dev;
-}
-
-/* Initialize a device.  Device properties should be set before calling
-   this function.  IRQs and MMIO regions should be connected/mapped after
-   calling this function.
-   On failure, destroy the device and return negative value.
-   Return 0 on success.  */
-int qdev_init(DeviceState *dev)
-{
-    Error *local_err = NULL;
-
-    assert(!dev->realized);
-
-    object_property_set_bool(OBJECT(dev), true, "realized", &local_err);
-    if (local_err != NULL) {
-        error_free(local_err);
-        qdev_free(dev);
-        return -1;
-    }
-    return 0;
-}
-
-static void device_realize(DeviceState *dev, Error **err)
-{
-    DeviceClass *dc = DEVICE_GET_CLASS(dev);
-
-    if (dc->init) {
-        int rc = dc->init(dev);
-        if (rc < 0) {
-            error_setg(err, "Device initialization failed.");
-            return;
-        }
-    }
-}
-
-void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id,
-                                 int required_for_version)
-{
-    assert(!dev->realized);
-    dev->instance_id_alias = alias_id;
-    dev->alias_required_for_version = required_for_version;
-}
-
-void qdev_unplug(DeviceState *dev, Error **errp)
-{
-    DeviceClass *dc = DEVICE_GET_CLASS(dev);
-
-    if (!dev->parent_bus->allow_hotplug) {
-        error_set(errp, QERR_BUS_NO_HOTPLUG, dev->parent_bus->name);
-        return;
-    }
-    assert(dc->unplug != NULL);
-
-    qdev_hot_removed = true;
-
-    if (dc->unplug(dev) < 0) {
-        error_set(errp, QERR_UNDEFINED_ERROR);
-        return;
-    }
-}
-
-static int qdev_reset_one(DeviceState *dev, void *opaque)
-{
-    device_reset(dev);
-
-    return 0;
-}
-
-static int qbus_reset_one(BusState *bus, void *opaque)
-{
-    BusClass *bc = BUS_GET_CLASS(bus);
-    if (bc->reset) {
-        return bc->reset(bus);
-    }
-    return 0;
-}
-
-void qdev_reset_all(DeviceState *dev)
-{
-    qdev_walk_children(dev, qdev_reset_one, qbus_reset_one, NULL);
-}
-
-void qbus_reset_all(BusState *bus)
-{
-    qbus_walk_children(bus, qdev_reset_one, qbus_reset_one, NULL);
-}
-
-void qbus_reset_all_fn(void *opaque)
-{
-    BusState *bus = opaque;
-    qbus_reset_all(bus);
-}
-
-/* can be used as ->unplug() callback for the simple cases */
-int qdev_simple_unplug_cb(DeviceState *dev)
-{
-    /* just zap it */
-    qdev_free(dev);
-    return 0;
-}
-
-
-/* Like qdev_init(), but terminate program via error_report() instead of
-   returning an error value.  This is okay during machine creation.
-   Don't use for hotplug, because there callers need to recover from
-   failure.  Exception: if you know the device's init() callback can't
-   fail, then qdev_init_nofail() can't fail either, and is therefore
-   usable even then.  But relying on the device implementation that
-   way is somewhat unclean, and best avoided.  */
-void qdev_init_nofail(DeviceState *dev)
-{
-    const char *typename = object_get_typename(OBJECT(dev));
-
-    if (qdev_init(dev) < 0) {
-        error_report("Initialization of device %s failed", typename);
-        exit(1);
-    }
-}
-
-/* Unlink device from bus and free the structure.  */
-void qdev_free(DeviceState *dev)
-{
-    object_unparent(OBJECT(dev));
-}
-
-void qdev_machine_creation_done(void)
-{
-    /*
-     * ok, initial machine setup is done, starting from now we can
-     * only create hotpluggable devices
-     */
-    qdev_hotplug = 1;
-}
-
-bool qdev_machine_modified(void)
-{
-    return qdev_hot_added || qdev_hot_removed;
-}
-
-BusState *qdev_get_parent_bus(DeviceState *dev)
-{
-    return dev->parent_bus;
-}
-
-void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n)
-{
-    dev->gpio_in = qemu_extend_irqs(dev->gpio_in, dev->num_gpio_in, handler,
-                                        dev, n);
-    dev->num_gpio_in += n;
-}
-
-void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n)
-{
-    assert(dev->num_gpio_out == 0);
-    dev->num_gpio_out = n;
-    dev->gpio_out = pins;
-}
-
-qemu_irq qdev_get_gpio_in(DeviceState *dev, int n)
-{
-    assert(n >= 0 && n < dev->num_gpio_in);
-    return dev->gpio_in[n];
-}
-
-void qdev_connect_gpio_out(DeviceState * dev, int n, qemu_irq pin)
-{
-    assert(n >= 0 && n < dev->num_gpio_out);
-    dev->gpio_out[n] = pin;
-}
-
-BusState *qdev_get_child_bus(DeviceState *dev, const char *name)
-{
-    BusState *bus;
-
-    QLIST_FOREACH(bus, &dev->child_bus, sibling) {
-        if (strcmp(name, bus->name) == 0) {
-            return bus;
-        }
-    }
-    return NULL;
-}
-
-int qbus_walk_children(BusState *bus, qdev_walkerfn *devfn,
-                       qbus_walkerfn *busfn, void *opaque)
-{
-    BusChild *kid;
-    int err;
-
-    if (busfn) {
-        err = busfn(bus, opaque);
-        if (err) {
-            return err;
-        }
-    }
-
-    QTAILQ_FOREACH(kid, &bus->children, sibling) {
-        err = qdev_walk_children(kid->child, devfn, busfn, opaque);
-        if (err < 0) {
-            return err;
-        }
-    }
-
-    return 0;
-}
-
-int qdev_walk_children(DeviceState *dev, qdev_walkerfn *devfn,
-                       qbus_walkerfn *busfn, void *opaque)
-{
-    BusState *bus;
-    int err;
-
-    if (devfn) {
-        err = devfn(dev, opaque);
-        if (err) {
-            return err;
-        }
-    }
-
-    QLIST_FOREACH(bus, &dev->child_bus, sibling) {
-        err = qbus_walk_children(bus, devfn, busfn, opaque);
-        if (err < 0) {
-            return err;
-        }
-    }
-
-    return 0;
-}
-
-DeviceState *qdev_find_recursive(BusState *bus, const char *id)
-{
-    BusChild *kid;
-    DeviceState *ret;
-    BusState *child;
-
-    QTAILQ_FOREACH(kid, &bus->children, sibling) {
-        DeviceState *dev = kid->child;
-
-        if (dev->id && strcmp(dev->id, id) == 0) {
-            return dev;
-        }
-
-        QLIST_FOREACH(child, &dev->child_bus, sibling) {
-            ret = qdev_find_recursive(child, id);
-            if (ret) {
-                return ret;
-            }
-        }
-    }
-    return NULL;
-}
-
-static void qbus_realize(BusState *bus, DeviceState *parent, const char *name)
-{
-    const char *typename = object_get_typename(OBJECT(bus));
-    char *buf;
-    int i,len;
-
-    bus->parent = parent;
-
-    if (name) {
-        bus->name = g_strdup(name);
-    } else if (bus->parent && bus->parent->id) {
-        /* parent device has id -> use it for bus name */
-        len = strlen(bus->parent->id) + 16;
-        buf = g_malloc(len);
-        snprintf(buf, len, "%s.%d", bus->parent->id, bus->parent->num_child_bus);
-        bus->name = buf;
-    } else {
-        /* no id -> use lowercase bus type for bus name */
-        len = strlen(typename) + 16;
-        buf = g_malloc(len);
-        len = snprintf(buf, len, "%s.%d", typename,
-                       bus->parent ? bus->parent->num_child_bus : 0);
-        for (i = 0; i < len; i++)
-            buf[i] = qemu_tolower(buf[i]);
-        bus->name = buf;
-    }
-
-    if (bus->parent) {
-        QLIST_INSERT_HEAD(&bus->parent->child_bus, bus, sibling);
-        bus->parent->num_child_bus++;
-        object_property_add_child(OBJECT(bus->parent), bus->name, OBJECT(bus), NULL);
-        object_unref(OBJECT(bus));
-    } else if (bus != sysbus_get_default()) {
-        /* TODO: once all bus devices are qdevified,
-           only reset handler for main_system_bus should be registered here. */
-        qemu_register_reset(qbus_reset_all_fn, bus);
-    }
-}
-
-static void bus_unparent(Object *obj)
-{
-    BusState *bus = BUS(obj);
-    BusChild *kid;
-
-    while ((kid = QTAILQ_FIRST(&bus->children)) != NULL) {
-        DeviceState *dev = kid->child;
-        qdev_free(dev);
-    }
-    if (bus->parent) {
-        QLIST_REMOVE(bus, sibling);
-        bus->parent->num_child_bus--;
-        bus->parent = NULL;
-    } else {
-        assert(bus != sysbus_get_default()); /* main_system_bus is never freed */
-        qemu_unregister_reset(qbus_reset_all_fn, bus);
-    }
-}
-
-void qbus_create_inplace(void *bus, const char *typename,
-                         DeviceState *parent, const char *name)
-{
-    object_initialize(bus, typename);
-    qbus_realize(bus, parent, name);
-}
-
-BusState *qbus_create(const char *typename, DeviceState *parent, const char *name)
-{
-    BusState *bus;
-
-    bus = BUS(object_new(typename));
-    qbus_realize(bus, parent, name);
-
-    return bus;
-}
-
-void qbus_free(BusState *bus)
-{
-    object_unparent(OBJECT(bus));
-}
-
-static char *bus_get_fw_dev_path(BusState *bus, DeviceState *dev)
-{
-    BusClass *bc = BUS_GET_CLASS(bus);
-
-    if (bc->get_fw_dev_path) {
-        return bc->get_fw_dev_path(dev);
-    }
-
-    return NULL;
-}
-
-static int qdev_get_fw_dev_path_helper(DeviceState *dev, char *p, int size)
-{
-    int l = 0;
-
-    if (dev && dev->parent_bus) {
-        char *d;
-        l = qdev_get_fw_dev_path_helper(dev->parent_bus->parent, p, size);
-        d = bus_get_fw_dev_path(dev->parent_bus, dev);
-        if (d) {
-            l += snprintf(p + l, size - l, "%s", d);
-            g_free(d);
-        } else {
-            l += snprintf(p + l, size - l, "%s", object_get_typename(OBJECT(dev)));
-        }
-    }
-    l += snprintf(p + l , size - l, "/");
-
-    return l;
-}
-
-char* qdev_get_fw_dev_path(DeviceState *dev)
-{
-    char path[128];
-    int l;
-
-    l = qdev_get_fw_dev_path_helper(dev, path, 128);
-
-    path[l-1] = '\0';
-
-    return g_strdup(path);
-}
-
-char *qdev_get_dev_path(DeviceState *dev)
-{
-    BusClass *bc;
-
-    if (!dev || !dev->parent_bus) {
-        return NULL;
-    }
-
-    bc = BUS_GET_CLASS(dev->parent_bus);
-    if (bc->get_dev_path) {
-        return bc->get_dev_path(dev);
-    }
-
-    return NULL;
-}
-
-/**
- * Legacy property handling
- */
-
-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];
-    char *ptr = buffer;
-
-    prop->info->print(dev, prop, buffer, sizeof(buffer));
-    visit_type_str(v, &ptr, name, errp);
-}
-
-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;
-    int ret;
-
-    if (dev->realized) {
-        qdev_prop_set_after_realize(dev, name, errp);
-        return;
-    }
-
-    visit_type_str(v, &ptr, name, &local_err);
-    if (local_err) {
-        error_propagate(errp, local_err);
-        return;
-    }
-
-    ret = prop->info->parse(dev, prop, ptr);
-    error_set_from_qdev_prop_error(errp, ret, dev, prop, ptr);
-    g_free(ptr);
-}
-
-/**
- * @qdev_add_legacy_property - adds a legacy property
- *
- * 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 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;
-
-    /* Register pointer properties as legacy properties */
-    if (!prop->info->print && !prop->info->parse &&
-        (prop->info->set || prop->info->get)) {
-        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 : prop->info->get,
-                        prop->info->parse ? qdev_set_legacy_property : prop->info->set,
-                        NULL,
-                        prop, errp);
-
-    g_free(type);
-    g_free(name);
-}
-
-/**
- * @qdev_property_add_static - add a @Property to a device.
- *
- * Static properties access data in a struct.  The actual type of the
- * property and the field depends on the property type.
- */
-void qdev_property_add_static(DeviceState *dev, Property *prop,
-                              Error **errp)
-{
-    Error *local_err = NULL;
-    Object *obj = OBJECT(dev);
-
-    /*
-     * TODO qdev_prop_ptr does not have getters or setters.  It must
-     * go now that it can be replaced with links.  The test should be
-     * removed along with it: all static properties are read/write.
-     */
-    if (!prop->info->get && !prop->info->set) {
-        return;
-    }
-
-    object_property_add(obj, prop->name, prop->info->name,
-                        prop->info->get, prop->info->set,
-                        prop->info->release,
-                        prop, &local_err);
-
-    if (local_err) {
-        error_propagate(errp, local_err);
-        return;
-    }
-    if (prop->qtype == QTYPE_NONE) {
-        return;
-    }
-
-    if (prop->qtype == QTYPE_QBOOL) {
-        object_property_set_bool(obj, prop->defval, prop->name, &local_err);
-    } else if (prop->info->enum_table) {
-        object_property_set_str(obj, prop->info->enum_table[prop->defval],
-                                prop->name, &local_err);
-    } else if (prop->qtype == QTYPE_QINT) {
-        object_property_set_int(obj, prop->defval, prop->name, &local_err);
-    }
-    assert_no_error(local_err);
-}
-
-static bool device_get_realized(Object *obj, Error **err)
-{
-    DeviceState *dev = DEVICE(obj);
-    return dev->realized;
-}
-
-static void device_set_realized(Object *obj, bool value, Error **err)
-{
-    DeviceState *dev = DEVICE(obj);
-    DeviceClass *dc = DEVICE_GET_CLASS(dev);
-    Error *local_err = NULL;
-
-    if (value && !dev->realized) {
-        if (dc->realize) {
-            dc->realize(dev, &local_err);
-        }
-
-        if (!obj->parent && local_err == NULL) {
-            static int unattached_count;
-            gchar *name = g_strdup_printf("device[%d]", unattached_count++);
-
-            object_property_add_child(container_get(qdev_get_machine(),
-                                                    "/unattached"),
-                                      name, obj, &local_err);
-            g_free(name);
-        }
-
-        if (qdev_get_vmsd(dev) && local_err == NULL) {
-            vmstate_register_with_alias_id(dev, -1, qdev_get_vmsd(dev), dev,
-                                           dev->instance_id_alias,
-                                           dev->alias_required_for_version);
-        }
-        if (dev->hotplugged && local_err == NULL) {
-            device_reset(dev);
-        }
-    } else if (!value && dev->realized) {
-        if (dc->unrealize) {
-            dc->unrealize(dev, &local_err);
-        }
-    }
-
-    if (local_err != NULL) {
-        error_propagate(err, local_err);
-        return;
-    }
-
-    dev->realized = value;
-}
-
-static void device_initfn(Object *obj)
-{
-    DeviceState *dev = DEVICE(obj);
-    ObjectClass *class;
-    Property *prop;
-    Error *err = NULL;
-
-    if (qdev_hotplug) {
-        dev->hotplugged = 1;
-        qdev_hot_added = true;
-    }
-
-    dev->instance_id_alias = -1;
-    dev->realized = false;
-
-    object_property_add_bool(obj, "realized",
-                             device_get_realized, device_set_realized, NULL);
-
-    class = object_get_class(OBJECT(dev));
-    do {
-        for (prop = DEVICE_CLASS(class)->props; prop && prop->name; prop++) {
-            qdev_property_add_legacy(dev, prop, &err);
-            assert_no_error(err);
-            qdev_property_add_static(dev, prop, &err);
-            assert_no_error(err);
-        }
-        class = object_class_get_parent(class);
-    } while (class != object_class_by_name(TYPE_DEVICE));
-    qdev_prop_set_globals(dev);
-
-    object_property_add_link(OBJECT(dev), "parent_bus", TYPE_BUS,
-                             (Object **)&dev->parent_bus, &err);
-    assert_no_error(err);
-}
-
-/* Unlink device from bus and free the structure.  */
-static void device_finalize(Object *obj)
-{
-    DeviceState *dev = DEVICE(obj);
-    if (dev->opts) {
-        qemu_opts_del(dev->opts);
-    }
-}
-
-static void device_class_base_init(ObjectClass *class, void *data)
-{
-    DeviceClass *klass = DEVICE_CLASS(class);
-
-    /* We explicitly look up properties in the superclasses,
-     * so do not propagate them to the subclasses.
-     */
-    klass->props = NULL;
-}
-
-static void device_unparent(Object *obj)
-{
-    DeviceState *dev = DEVICE(obj);
-    DeviceClass *dc = DEVICE_GET_CLASS(dev);
-    BusState *bus;
-    QObject *event_data;
-    bool have_realized = dev->realized;
-
-    while (dev->num_child_bus) {
-        bus = QLIST_FIRST(&dev->child_bus);
-        qbus_free(bus);
-    }
-    if (dev->realized) {
-        if (qdev_get_vmsd(dev)) {
-            vmstate_unregister(dev, qdev_get_vmsd(dev), dev);
-        }
-        if (dc->exit) {
-            dc->exit(dev);
-        }
-    }
-    if (dev->parent_bus) {
-        bus_remove_child(dev->parent_bus, dev);
-        object_unref(OBJECT(dev->parent_bus));
-        dev->parent_bus = NULL;
-    }
-
-    /* Only send event if the device had been completely realized */
-    if (have_realized) {
-        gchar *path = object_get_canonical_path(OBJECT(dev));
-
-        if (dev->id) {
-            event_data = qobject_from_jsonf("{ 'device': %s, 'path': %s }",
-                                            dev->id, path);
-        } else {
-            event_data = qobject_from_jsonf("{ 'path': %s }", path);
-        }
-        monitor_protocol_event(QEVENT_DEVICE_DELETED, event_data);
-        qobject_decref(event_data);
-        g_free(path);
-    }
-}
-
-static void device_class_init(ObjectClass *class, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(class);
-
-    class->unparent = device_unparent;
-    dc->realize = device_realize;
-}
-
-void device_reset(DeviceState *dev)
-{
-    DeviceClass *klass = DEVICE_GET_CLASS(dev);
-
-    if (klass->reset) {
-        klass->reset(dev);
-    }
-}
-
-Object *qdev_get_machine(void)
-{
-    static Object *dev;
-
-    if (dev == NULL) {
-        dev = container_get(object_get_root(), "/machine");
-    }
-
-    return dev;
-}
-
-static const TypeInfo device_type_info = {
-    .name = TYPE_DEVICE,
-    .parent = TYPE_OBJECT,
-    .instance_size = sizeof(DeviceState),
-    .instance_init = device_initfn,
-    .instance_finalize = device_finalize,
-    .class_base_init = device_class_base_init,
-    .class_init = device_class_init,
-    .abstract = true,
-    .class_size = sizeof(DeviceClass),
-};
-
-static void qbus_initfn(Object *obj)
-{
-    BusState *bus = BUS(obj);
-
-    QTAILQ_INIT(&bus->children);
-}
-
-static void bus_class_init(ObjectClass *class, void *data)
-{
-    class->unparent = bus_unparent;
-}
-
-static void qbus_finalize(Object *obj)
-{
-    BusState *bus = BUS(obj);
-
-    g_free((char *)bus->name);
-}
-
-static const TypeInfo bus_info = {
-    .name = TYPE_BUS,
-    .parent = TYPE_OBJECT,
-    .instance_size = sizeof(BusState),
-    .abstract = true,
-    .class_size = sizeof(BusClass),
-    .instance_init = qbus_initfn,
-    .instance_finalize = qbus_finalize,
-    .class_init = bus_class_init,
-};
-
-static void qdev_register_types(void)
-{
-    type_register_static(&bus_info);
-    type_register_static(&device_type_info);
-}
-
-type_init(qdev_register_types)
diff --git a/hw/qdev.h b/hw/qdev.h
deleted file mode 100644 (file)
index 5cb8b08..0000000
--- a/hw/qdev.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef QDEV_H
-#define QDEV_H
-
-#include "hw/hw.h"
-#include "hw/qdev-core.h"
-#include "hw/qdev-properties.h"
-
-#endif
diff --git a/hw/qxl-logger.c b/hw/qxl-logger.c
deleted file mode 100644 (file)
index 84f9aa1..0000000
+++ /dev/null
@@ -1,275 +0,0 @@
-/*
- * qxl command logging -- for debug purposes
- *
- * Copyright (C) 2010 Red Hat, Inc.
- *
- * maintained by Gerd Hoffmann <kraxel@redhat.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 or
- * (at your option) version 3 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
- * 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/timer.h"
-#include "hw/qxl.h"
-
-static const char *qxl_type[] = {
-    [ QXL_CMD_NOP ]     = "nop",
-    [ QXL_CMD_DRAW ]    = "draw",
-    [ QXL_CMD_UPDATE ]  = "update",
-    [ QXL_CMD_CURSOR ]  = "cursor",
-    [ QXL_CMD_MESSAGE ] = "message",
-    [ QXL_CMD_SURFACE ] = "surface",
-};
-
-static const char *qxl_draw_type[] = {
-    [ QXL_DRAW_NOP         ] = "nop",
-    [ QXL_DRAW_FILL        ] = "fill",
-    [ QXL_DRAW_OPAQUE      ] = "opaque",
-    [ QXL_DRAW_COPY        ] = "copy",
-    [ QXL_COPY_BITS        ] = "copy-bits",
-    [ QXL_DRAW_BLEND       ] = "blend",
-    [ QXL_DRAW_BLACKNESS   ] = "blackness",
-    [ QXL_DRAW_WHITENESS   ] = "whitemess",
-    [ QXL_DRAW_INVERS      ] = "invers",
-    [ QXL_DRAW_ROP3        ] = "rop3",
-    [ QXL_DRAW_STROKE      ] = "stroke",
-    [ QXL_DRAW_TEXT        ] = "text",
-    [ QXL_DRAW_TRANSPARENT ] = "transparent",
-    [ QXL_DRAW_ALPHA_BLEND ] = "alpha-blend",
-};
-
-static const char *qxl_draw_effect[] = {
-    [ QXL_EFFECT_BLEND            ] = "blend",
-    [ QXL_EFFECT_OPAQUE           ] = "opaque",
-    [ QXL_EFFECT_REVERT_ON_DUP    ] = "revert-on-dup",
-    [ QXL_EFFECT_BLACKNESS_ON_DUP ] = "blackness-on-dup",
-    [ QXL_EFFECT_WHITENESS_ON_DUP ] = "whiteness-on-dup",
-    [ QXL_EFFECT_NOP_ON_DUP       ] = "nop-on-dup",
-    [ QXL_EFFECT_NOP              ] = "nop",
-    [ QXL_EFFECT_OPAQUE_BRUSH     ] = "opaque-brush",
-};
-
-static const char *qxl_surface_cmd[] = {
-   [ QXL_SURFACE_CMD_CREATE  ] = "create",
-   [ QXL_SURFACE_CMD_DESTROY ] = "destroy",
-};
-
-static const char *spice_surface_fmt[] = {
-   [ SPICE_SURFACE_FMT_INVALID  ] = "invalid",
-   [ SPICE_SURFACE_FMT_1_A      ] = "alpha/1",
-   [ SPICE_SURFACE_FMT_8_A      ] = "alpha/8",
-   [ SPICE_SURFACE_FMT_16_555   ] = "555/16",
-   [ SPICE_SURFACE_FMT_16_565   ] = "565/16",
-   [ SPICE_SURFACE_FMT_32_xRGB  ] = "xRGB/32",
-   [ SPICE_SURFACE_FMT_32_ARGB  ] = "ARGB/32",
-};
-
-static const char *qxl_cursor_cmd[] = {
-   [ QXL_CURSOR_SET   ] = "set",
-   [ QXL_CURSOR_MOVE  ] = "move",
-   [ QXL_CURSOR_HIDE  ] = "hide",
-   [ QXL_CURSOR_TRAIL ] = "trail",
-};
-
-static const char *spice_cursor_type[] = {
-   [ SPICE_CURSOR_TYPE_ALPHA   ] = "alpha",
-   [ SPICE_CURSOR_TYPE_MONO    ] = "mono",
-   [ SPICE_CURSOR_TYPE_COLOR4  ] = "color4",
-   [ SPICE_CURSOR_TYPE_COLOR8  ] = "color8",
-   [ SPICE_CURSOR_TYPE_COLOR16 ] = "color16",
-   [ SPICE_CURSOR_TYPE_COLOR24 ] = "color24",
-   [ SPICE_CURSOR_TYPE_COLOR32 ] = "color32",
-};
-
-static const char *qxl_v2n(const char *n[], size_t l, int v)
-{
-    if (v >= l || !n[v]) {
-        return "???";
-    }
-    return n[v];
-}
-#define qxl_name(_list, _value) qxl_v2n(_list, ARRAY_SIZE(_list), _value)
-
-static int qxl_log_image(PCIQXLDevice *qxl, QXLPHYSICAL addr, int group_id)
-{
-    QXLImage *image;
-    QXLImageDescriptor *desc;
-
-    image = qxl_phys2virt(qxl, addr, group_id);
-    if (!image) {
-        return 1;
-    }
-    desc = &image->descriptor;
-    fprintf(stderr, " (id %" PRIx64 " type %d flags %d width %d height %d",
-            desc->id, desc->type, desc->flags, desc->width, desc->height);
-    switch (desc->type) {
-    case SPICE_IMAGE_TYPE_BITMAP:
-        fprintf(stderr, ", fmt %d flags %d x %d y %d stride %d"
-                " palette %" PRIx64 " data %" PRIx64,
-                image->bitmap.format, image->bitmap.flags,
-                image->bitmap.x, image->bitmap.y,
-                image->bitmap.stride,
-                image->bitmap.palette, image->bitmap.data);
-        break;
-    }
-    fprintf(stderr, ")");
-    return 0;
-}
-
-static void qxl_log_rect(QXLRect *rect)
-{
-    fprintf(stderr, " %dx%d+%d+%d",
-            rect->right - rect->left,
-            rect->bottom - rect->top,
-            rect->left, rect->top);
-}
-
-static int qxl_log_cmd_draw_copy(PCIQXLDevice *qxl, QXLCopy *copy,
-                                 int group_id)
-{
-    int ret;
-
-    fprintf(stderr, " src %" PRIx64,
-            copy->src_bitmap);
-    ret = qxl_log_image(qxl, copy->src_bitmap, group_id);
-    if (ret != 0) {
-        return ret;
-    }
-    fprintf(stderr, " area");
-    qxl_log_rect(&copy->src_area);
-    fprintf(stderr, " rop %d", copy->rop_descriptor);
-    return 0;
-}
-
-static int qxl_log_cmd_draw(PCIQXLDevice *qxl, QXLDrawable *draw, int group_id)
-{
-    fprintf(stderr, ": surface_id %d type %s effect %s",
-            draw->surface_id,
-            qxl_name(qxl_draw_type, draw->type),
-            qxl_name(qxl_draw_effect, draw->effect));
-    switch (draw->type) {
-    case QXL_DRAW_COPY:
-        return qxl_log_cmd_draw_copy(qxl, &draw->u.copy, group_id);
-        break;
-    }
-    return 0;
-}
-
-static int qxl_log_cmd_draw_compat(PCIQXLDevice *qxl, QXLCompatDrawable *draw,
-                                   int group_id)
-{
-    fprintf(stderr, ": type %s effect %s",
-            qxl_name(qxl_draw_type, draw->type),
-            qxl_name(qxl_draw_effect, draw->effect));
-    if (draw->bitmap_offset) {
-        fprintf(stderr, ": bitmap %d",
-                draw->bitmap_offset);
-        qxl_log_rect(&draw->bitmap_area);
-    }
-    switch (draw->type) {
-    case QXL_DRAW_COPY:
-        return qxl_log_cmd_draw_copy(qxl, &draw->u.copy, group_id);
-        break;
-    }
-    return 0;
-}
-
-static void qxl_log_cmd_surface(PCIQXLDevice *qxl, QXLSurfaceCmd *cmd)
-{
-    fprintf(stderr, ": %s id %d",
-            qxl_name(qxl_surface_cmd, cmd->type),
-            cmd->surface_id);
-    if (cmd->type == QXL_SURFACE_CMD_CREATE) {
-        fprintf(stderr, " size %dx%d stride %d format %s (count %d, max %d)",
-                cmd->u.surface_create.width,
-                cmd->u.surface_create.height,
-                cmd->u.surface_create.stride,
-                qxl_name(spice_surface_fmt, cmd->u.surface_create.format),
-                qxl->guest_surfaces.count, qxl->guest_surfaces.max);
-    }
-    if (cmd->type == QXL_SURFACE_CMD_DESTROY) {
-        fprintf(stderr, " (count %d)", qxl->guest_surfaces.count);
-    }
-}
-
-int qxl_log_cmd_cursor(PCIQXLDevice *qxl, QXLCursorCmd *cmd, int group_id)
-{
-    QXLCursor *cursor;
-
-    fprintf(stderr, ": %s",
-            qxl_name(qxl_cursor_cmd, cmd->type));
-    switch (cmd->type) {
-    case QXL_CURSOR_SET:
-        fprintf(stderr, " +%d+%d visible %s, shape @ 0x%" PRIx64,
-                cmd->u.set.position.x,
-                cmd->u.set.position.y,
-                cmd->u.set.visible ? "yes" : "no",
-                cmd->u.set.shape);
-        cursor = qxl_phys2virt(qxl, cmd->u.set.shape, group_id);
-        if (!cursor) {
-            return 1;
-        }
-        fprintf(stderr, " type %s size %dx%d hot-spot +%d+%d"
-                " unique 0x%" PRIx64 " data-size %d",
-                qxl_name(spice_cursor_type, cursor->header.type),
-                cursor->header.width, cursor->header.height,
-                cursor->header.hot_spot_x, cursor->header.hot_spot_y,
-                cursor->header.unique, cursor->data_size);
-        break;
-    case QXL_CURSOR_MOVE:
-        fprintf(stderr, " +%d+%d", cmd->u.position.x, cmd->u.position.y);
-        break;
-    }
-    return 0;
-}
-
-int qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext)
-{
-    bool compat = ext->flags & QXL_COMMAND_FLAG_COMPAT;
-    void *data;
-    int ret;
-
-    if (!qxl->cmdlog) {
-        return 0;
-    }
-    fprintf(stderr, "%" PRId64 " qxl-%d/%s:", qemu_get_clock_ns(vm_clock),
-            qxl->id, ring);
-    fprintf(stderr, " cmd @ 0x%" PRIx64 " %s%s", ext->cmd.data,
-            qxl_name(qxl_type, ext->cmd.type),
-            compat ? "(compat)" : "");
-
-    data = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id);
-    if (!data) {
-        return 1;
-    }
-    switch (ext->cmd.type) {
-    case QXL_CMD_DRAW:
-        if (!compat) {
-            ret = qxl_log_cmd_draw(qxl, data, ext->group_id);
-        } else {
-            ret = qxl_log_cmd_draw_compat(qxl, data, ext->group_id);
-        }
-        if (ret) {
-            return ret;
-        }
-        break;
-    case QXL_CMD_SURFACE:
-        qxl_log_cmd_surface(qxl, data);
-        break;
-    case QXL_CMD_CURSOR:
-        qxl_log_cmd_cursor(qxl, data, ext->group_id);
-        break;
-    }
-    fprintf(stderr, "\n");
-    return 0;
-}
diff --git a/hw/qxl-render.c b/hw/qxl-render.c
deleted file mode 100644 (file)
index 8cd9be4..0000000
+++ /dev/null
@@ -1,280 +0,0 @@
-/*
- * qxl local rendering (aka display on sdl/vnc)
- *
- * Copyright (C) 2010 Red Hat, Inc.
- *
- * maintained by Gerd Hoffmann <kraxel@redhat.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 or
- * (at your option) version 3 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
- * 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 "hw/qxl.h"
-
-static void qxl_blit(PCIQXLDevice *qxl, QXLRect *rect)
-{
-    DisplaySurface *surface = qemu_console_surface(qxl->vga.con);
-    uint8_t *dst = surface_data(surface);
-    uint8_t *src;
-    int len, i;
-
-    if (is_buffer_shared(surface)) {
-        return;
-    }
-    if (!qxl->guest_primary.data) {
-        trace_qxl_render_blit_guest_primary_initialized();
-        qxl->guest_primary.data = memory_region_get_ram_ptr(&qxl->vga.vram);
-    }
-    trace_qxl_render_blit(qxl->guest_primary.qxl_stride,
-            rect->left, rect->right, rect->top, rect->bottom);
-    src = qxl->guest_primary.data;
-    if (qxl->guest_primary.qxl_stride < 0) {
-        /* qxl surface is upside down, walk src scanlines
-         * in reverse order to flip it */
-        src += (qxl->guest_primary.surface.height - rect->top - 1) *
-            qxl->guest_primary.abs_stride;
-    } else {
-        src += rect->top * qxl->guest_primary.abs_stride;
-    }
-    dst += rect->top  * qxl->guest_primary.abs_stride;
-    src += rect->left * qxl->guest_primary.bytes_pp;
-    dst += rect->left * qxl->guest_primary.bytes_pp;
-    len  = (rect->right - rect->left) * qxl->guest_primary.bytes_pp;
-
-    for (i = rect->top; i < rect->bottom; i++) {
-        memcpy(dst, src, len);
-        dst += qxl->guest_primary.abs_stride;
-        src += qxl->guest_primary.qxl_stride;
-    }
-}
-
-void qxl_render_resize(PCIQXLDevice *qxl)
-{
-    QXLSurfaceCreate *sc = &qxl->guest_primary.surface;
-
-    qxl->guest_primary.qxl_stride = sc->stride;
-    qxl->guest_primary.abs_stride = abs(sc->stride);
-    qxl->guest_primary.resized++;
-    switch (sc->format) {
-    case SPICE_SURFACE_FMT_16_555:
-        qxl->guest_primary.bytes_pp = 2;
-        qxl->guest_primary.bits_pp = 15;
-        break;
-    case SPICE_SURFACE_FMT_16_565:
-        qxl->guest_primary.bytes_pp = 2;
-        qxl->guest_primary.bits_pp = 16;
-        break;
-    case SPICE_SURFACE_FMT_32_xRGB:
-    case SPICE_SURFACE_FMT_32_ARGB:
-        qxl->guest_primary.bytes_pp = 4;
-        qxl->guest_primary.bits_pp = 32;
-        break;
-    default:
-        fprintf(stderr, "%s: unhandled format: %x\n", __FUNCTION__,
-                qxl->guest_primary.surface.format);
-        qxl->guest_primary.bytes_pp = 4;
-        qxl->guest_primary.bits_pp = 32;
-        break;
-    }
-}
-
-static void qxl_set_rect_to_surface(PCIQXLDevice *qxl, QXLRect *area)
-{
-    area->left   = 0;
-    area->right  = qxl->guest_primary.surface.width;
-    area->top    = 0;
-    area->bottom = qxl->guest_primary.surface.height;
-}
-
-static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl)
-{
-    VGACommonState *vga = &qxl->vga;
-    DisplaySurface *surface;
-    int i;
-
-    if (qxl->guest_primary.resized) {
-        qxl->guest_primary.resized = 0;
-        qxl->guest_primary.data = memory_region_get_ram_ptr(&qxl->vga.vram);
-        qxl_set_rect_to_surface(qxl, &qxl->dirty[0]);
-        qxl->num_dirty_rects = 1;
-        trace_qxl_render_guest_primary_resized(
-               qxl->guest_primary.surface.width,
-               qxl->guest_primary.surface.height,
-               qxl->guest_primary.qxl_stride,
-               qxl->guest_primary.bytes_pp,
-               qxl->guest_primary.bits_pp);
-        if (qxl->guest_primary.qxl_stride > 0) {
-            surface = qemu_create_displaysurface_from
-                (qxl->guest_primary.surface.width,
-                 qxl->guest_primary.surface.height,
-                 qxl->guest_primary.bits_pp,
-                 qxl->guest_primary.abs_stride,
-                 qxl->guest_primary.data,
-                 false);
-        } else {
-            surface = qemu_create_displaysurface
-                (qxl->guest_primary.surface.width,
-                 qxl->guest_primary.surface.height);
-        }
-        dpy_gfx_replace_surface(vga->con, surface);
-    }
-    for (i = 0; i < qxl->num_dirty_rects; i++) {
-        if (qemu_spice_rect_is_empty(qxl->dirty+i)) {
-            break;
-        }
-        qxl_blit(qxl, qxl->dirty+i);
-        dpy_gfx_update(vga->con,
-                       qxl->dirty[i].left, qxl->dirty[i].top,
-                       qxl->dirty[i].right - qxl->dirty[i].left,
-                       qxl->dirty[i].bottom - qxl->dirty[i].top);
-    }
-    qxl->num_dirty_rects = 0;
-}
-
-/*
- * use ssd.lock to protect render_update_cookie_num.
- * qxl_render_update is called by io thread or vcpu thread, and the completion
- * callbacks are called by spice_server thread, defering to bh called from the
- * io thread.
- */
-void qxl_render_update(PCIQXLDevice *qxl)
-{
-    QXLCookie *cookie;
-
-    qemu_mutex_lock(&qxl->ssd.lock);
-
-    if (!runstate_is_running() || !qxl->guest_primary.commands) {
-        qxl_render_update_area_unlocked(qxl);
-        qemu_mutex_unlock(&qxl->ssd.lock);
-        return;
-    }
-
-    qxl->guest_primary.commands = 0;
-    qxl->render_update_cookie_num++;
-    qemu_mutex_unlock(&qxl->ssd.lock);
-    cookie = qxl_cookie_new(QXL_COOKIE_TYPE_RENDER_UPDATE_AREA,
-                            0);
-    qxl_set_rect_to_surface(qxl, &cookie->u.render.area);
-    qxl_spice_update_area(qxl, 0, &cookie->u.render.area, NULL,
-                          0, 1 /* clear_dirty_region */, QXL_ASYNC, cookie);
-}
-
-void qxl_render_update_area_bh(void *opaque)
-{
-    PCIQXLDevice *qxl = opaque;
-
-    qemu_mutex_lock(&qxl->ssd.lock);
-    qxl_render_update_area_unlocked(qxl);
-    qemu_mutex_unlock(&qxl->ssd.lock);
-}
-
-void qxl_render_update_area_done(PCIQXLDevice *qxl, QXLCookie *cookie)
-{
-    qemu_mutex_lock(&qxl->ssd.lock);
-    trace_qxl_render_update_area_done(cookie);
-    qemu_bh_schedule(qxl->update_area_bh);
-    qxl->render_update_cookie_num--;
-    qemu_mutex_unlock(&qxl->ssd.lock);
-    g_free(cookie);
-}
-
-static QEMUCursor *qxl_cursor(PCIQXLDevice *qxl, QXLCursor *cursor)
-{
-    QEMUCursor *c;
-    uint8_t *image, *mask;
-    size_t size;
-
-    c = cursor_alloc(cursor->header.width, cursor->header.height);
-    c->hot_x = cursor->header.hot_spot_x;
-    c->hot_y = cursor->header.hot_spot_y;
-    switch (cursor->header.type) {
-    case SPICE_CURSOR_TYPE_ALPHA:
-        size = cursor->header.width * cursor->header.height * sizeof(uint32_t);
-        memcpy(c->data, cursor->chunk.data, size);
-        if (qxl->debug > 2) {
-            cursor_print_ascii_art(c, "qxl/alpha");
-        }
-        break;
-    case SPICE_CURSOR_TYPE_MONO:
-        mask  = cursor->chunk.data;
-        image = mask + cursor_get_mono_bpl(c) * c->width;
-        cursor_set_mono(c, 0xffffff, 0x000000, image, 1, mask);
-        if (qxl->debug > 2) {
-            cursor_print_ascii_art(c, "qxl/mono");
-        }
-        break;
-    default:
-        fprintf(stderr, "%s: not implemented: type %d\n",
-                __FUNCTION__, cursor->header.type);
-        goto fail;
-    }
-    return c;
-
-fail:
-    cursor_put(c);
-    return NULL;
-}
-
-
-/* called from spice server thread context only */
-int qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext)
-{
-    QXLCursorCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id);
-    QXLCursor *cursor;
-    QEMUCursor *c;
-
-    if (!cmd) {
-        return 1;
-    }
-
-    if (!dpy_cursor_define_supported(qxl->vga.con)) {
-        return 0;
-    }
-
-    if (qxl->debug > 1 && cmd->type != QXL_CURSOR_MOVE) {
-        fprintf(stderr, "%s", __FUNCTION__);
-        qxl_log_cmd_cursor(qxl, cmd, ext->group_id);
-        fprintf(stderr, "\n");
-    }
-    switch (cmd->type) {
-    case QXL_CURSOR_SET:
-        cursor = qxl_phys2virt(qxl, cmd->u.set.shape, ext->group_id);
-        if (!cursor) {
-            return 1;
-        }
-        if (cursor->chunk.data_size != cursor->data_size) {
-            fprintf(stderr, "%s: multiple chunks\n", __FUNCTION__);
-            return 1;
-        }
-        c = qxl_cursor(qxl, cursor);
-        if (c == NULL) {
-            c = cursor_builtin_left_ptr();
-        }
-        qemu_mutex_lock(&qxl->ssd.lock);
-        if (qxl->ssd.cursor) {
-            cursor_put(qxl->ssd.cursor);
-        }
-        qxl->ssd.cursor = c;
-        qxl->ssd.mouse_x = cmd->u.set.position.x;
-        qxl->ssd.mouse_y = cmd->u.set.position.y;
-        qemu_mutex_unlock(&qxl->ssd.lock);
-        break;
-    case QXL_CURSOR_MOVE:
-        qemu_mutex_lock(&qxl->ssd.lock);
-        qxl->ssd.mouse_x = cmd->u.position.x;
-        qxl->ssd.mouse_y = cmd->u.position.y;
-        qemu_mutex_unlock(&qxl->ssd.lock);
-        break;
-    }
-    return 0;
-}
diff --git a/hw/qxl.c b/hw/qxl.c
deleted file mode 100644 (file)
index b66b414..0000000
--- a/hw/qxl.c
+++ /dev/null
@@ -1,2365 +0,0 @@
-/*
- * Copyright (C) 2010 Red Hat, Inc.
- *
- * written by Yaniv Kamay, Izik Eidus, Gerd Hoffmann
- * maintained by Gerd Hoffmann <kraxel@redhat.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 or
- * (at your option) version 3 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
- * 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 <zlib.h>
-
-#include "qemu-common.h"
-#include "qemu/timer.h"
-#include "qemu/queue.h"
-#include "monitor/monitor.h"
-#include "sysemu/sysemu.h"
-#include "trace.h"
-
-#include "hw/qxl.h"
-
-/*
- * NOTE: SPICE_RING_PROD_ITEM accesses memory on the pci bar and as
- * such can be changed by the guest, so to avoid a guest trigerrable
- * abort we just qxl_set_guest_bug and set the return to NULL. Still
- * it may happen as a result of emulator bug as well.
- */
-#undef SPICE_RING_PROD_ITEM
-#define SPICE_RING_PROD_ITEM(qxl, r, ret) {                             \
-        uint32_t prod = (r)->prod & SPICE_RING_INDEX_MASK(r);           \
-        if (prod >= ARRAY_SIZE((r)->items)) {                           \
-            qxl_set_guest_bug(qxl, "SPICE_RING_PROD_ITEM indices mismatch " \
-                          "%u >= %zu", prod, ARRAY_SIZE((r)->items));   \
-            ret = NULL;                                                 \
-        } else {                                                        \
-            ret = &(r)->items[prod].el;                                 \
-        }                                                               \
-    }
-
-#undef SPICE_RING_CONS_ITEM
-#define SPICE_RING_CONS_ITEM(qxl, r, ret) {                             \
-        uint32_t cons = (r)->cons & SPICE_RING_INDEX_MASK(r);           \
-        if (cons >= ARRAY_SIZE((r)->items)) {                           \
-            qxl_set_guest_bug(qxl, "SPICE_RING_CONS_ITEM indices mismatch " \
-                          "%u >= %zu", cons, ARRAY_SIZE((r)->items));   \
-            ret = NULL;                                                 \
-        } else {                                                        \
-            ret = &(r)->items[cons].el;                                 \
-        }                                                               \
-    }
-
-#undef ALIGN
-#define ALIGN(a, b) (((a) + ((b) - 1)) & ~((b) - 1))
-
-#define PIXEL_SIZE 0.2936875 //1280x1024 is 14.8" x 11.9" 
-
-#define QXL_MODE(_x, _y, _b, _o)                  \
-    {   .x_res = _x,                              \
-        .y_res = _y,                              \
-        .bits  = _b,                              \
-        .stride = (_x) * (_b) / 8,                \
-        .x_mili = PIXEL_SIZE * (_x),              \
-        .y_mili = PIXEL_SIZE * (_y),              \
-        .orientation = _o,                        \
-    }
-
-#define QXL_MODE_16_32(x_res, y_res, orientation) \
-    QXL_MODE(x_res, y_res, 16, orientation),      \
-    QXL_MODE(x_res, y_res, 32, orientation)
-
-#define QXL_MODE_EX(x_res, y_res)                 \
-    QXL_MODE_16_32(x_res, y_res, 0),              \
-    QXL_MODE_16_32(x_res, y_res, 1)
-
-static QXLMode qxl_modes[] = {
-    QXL_MODE_EX(640, 480),
-    QXL_MODE_EX(800, 480),
-    QXL_MODE_EX(800, 600),
-    QXL_MODE_EX(832, 624),
-    QXL_MODE_EX(960, 640),
-    QXL_MODE_EX(1024, 600),
-    QXL_MODE_EX(1024, 768),
-    QXL_MODE_EX(1152, 864),
-    QXL_MODE_EX(1152, 870),
-    QXL_MODE_EX(1280, 720),
-    QXL_MODE_EX(1280, 760),
-    QXL_MODE_EX(1280, 768),
-    QXL_MODE_EX(1280, 800),
-    QXL_MODE_EX(1280, 960),
-    QXL_MODE_EX(1280, 1024),
-    QXL_MODE_EX(1360, 768),
-    QXL_MODE_EX(1366, 768),
-    QXL_MODE_EX(1400, 1050),
-    QXL_MODE_EX(1440, 900),
-    QXL_MODE_EX(1600, 900),
-    QXL_MODE_EX(1600, 1200),
-    QXL_MODE_EX(1680, 1050),
-    QXL_MODE_EX(1920, 1080),
-    /* these modes need more than 8 MB video memory */
-    QXL_MODE_EX(1920, 1200),
-    QXL_MODE_EX(1920, 1440),
-    QXL_MODE_EX(2048, 1536),
-    QXL_MODE_EX(2560, 1440),
-    QXL_MODE_EX(2560, 1600),
-    /* these modes need more than 16 MB video memory */
-    QXL_MODE_EX(2560, 2048),
-    QXL_MODE_EX(2800, 2100),
-    QXL_MODE_EX(3200, 2400),
-};
-
-static void qxl_send_events(PCIQXLDevice *d, uint32_t events);
-static int qxl_destroy_primary(PCIQXLDevice *d, qxl_async_io async);
-static void qxl_reset_memslots(PCIQXLDevice *d);
-static void qxl_reset_surfaces(PCIQXLDevice *d);
-static void qxl_ring_set_dirty(PCIQXLDevice *qxl);
-
-void qxl_set_guest_bug(PCIQXLDevice *qxl, const char *msg, ...)
-{
-    trace_qxl_set_guest_bug(qxl->id);
-    qxl_send_events(qxl, QXL_INTERRUPT_ERROR);
-    qxl->guest_bug = 1;
-    if (qxl->guestdebug) {
-        va_list ap;
-        va_start(ap, msg);
-        fprintf(stderr, "qxl-%d: guest bug: ", qxl->id);
-        vfprintf(stderr, msg, ap);
-        fprintf(stderr, "\n");
-        va_end(ap);
-    }
-}
-
-static void qxl_clear_guest_bug(PCIQXLDevice *qxl)
-{
-    qxl->guest_bug = 0;
-}
-
-void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id,
-                           struct QXLRect *area, struct QXLRect *dirty_rects,
-                           uint32_t num_dirty_rects,
-                           uint32_t clear_dirty_region,
-                           qxl_async_io async, struct QXLCookie *cookie)
-{
-    trace_qxl_spice_update_area(qxl->id, surface_id, area->left, area->right,
-                                area->top, area->bottom);
-    trace_qxl_spice_update_area_rest(qxl->id, num_dirty_rects,
-                                     clear_dirty_region);
-    if (async == QXL_SYNC) {
-        qxl->ssd.worker->update_area(qxl->ssd.worker, surface_id, area,
-                        dirty_rects, num_dirty_rects, clear_dirty_region);
-    } else {
-        assert(cookie != NULL);
-        spice_qxl_update_area_async(&qxl->ssd.qxl, surface_id, area,
-                                    clear_dirty_region, (uintptr_t)cookie);
-    }
-}
-
-static void qxl_spice_destroy_surface_wait_complete(PCIQXLDevice *qxl,
-                                                    uint32_t id)
-{
-    trace_qxl_spice_destroy_surface_wait_complete(qxl->id, id);
-    qemu_mutex_lock(&qxl->track_lock);
-    qxl->guest_surfaces.cmds[id] = 0;
-    qxl->guest_surfaces.count--;
-    qemu_mutex_unlock(&qxl->track_lock);
-}
-
-static void qxl_spice_destroy_surface_wait(PCIQXLDevice *qxl, uint32_t id,
-                                           qxl_async_io async)
-{
-    QXLCookie *cookie;
-
-    trace_qxl_spice_destroy_surface_wait(qxl->id, id, async);
-    if (async) {
-        cookie = qxl_cookie_new(QXL_COOKIE_TYPE_IO,
-                                QXL_IO_DESTROY_SURFACE_ASYNC);
-        cookie->u.surface_id = id;
-        spice_qxl_destroy_surface_async(&qxl->ssd.qxl, id, (uintptr_t)cookie);
-    } else {
-        qxl->ssd.worker->destroy_surface_wait(qxl->ssd.worker, id);
-        qxl_spice_destroy_surface_wait_complete(qxl, id);
-    }
-}
-
-static void qxl_spice_flush_surfaces_async(PCIQXLDevice *qxl)
-{
-    trace_qxl_spice_flush_surfaces_async(qxl->id, qxl->guest_surfaces.count,
-                                         qxl->num_free_res);
-    spice_qxl_flush_surfaces_async(&qxl->ssd.qxl,
-        (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO,
-                                  QXL_IO_FLUSH_SURFACES_ASYNC));
-}
-
-void qxl_spice_loadvm_commands(PCIQXLDevice *qxl, struct QXLCommandExt *ext,
-                               uint32_t count)
-{
-    trace_qxl_spice_loadvm_commands(qxl->id, ext, count);
-    qxl->ssd.worker->loadvm_commands(qxl->ssd.worker, ext, count);
-}
-
-void qxl_spice_oom(PCIQXLDevice *qxl)
-{
-    trace_qxl_spice_oom(qxl->id);
-    qxl->ssd.worker->oom(qxl->ssd.worker);
-}
-
-void qxl_spice_reset_memslots(PCIQXLDevice *qxl)
-{
-    trace_qxl_spice_reset_memslots(qxl->id);
-    qxl->ssd.worker->reset_memslots(qxl->ssd.worker);
-}
-
-static void qxl_spice_destroy_surfaces_complete(PCIQXLDevice *qxl)
-{
-    trace_qxl_spice_destroy_surfaces_complete(qxl->id);
-    qemu_mutex_lock(&qxl->track_lock);
-    memset(qxl->guest_surfaces.cmds, 0,
-           sizeof(qxl->guest_surfaces.cmds) * qxl->ssd.num_surfaces);
-    qxl->guest_surfaces.count = 0;
-    qemu_mutex_unlock(&qxl->track_lock);
-}
-
-static void qxl_spice_destroy_surfaces(PCIQXLDevice *qxl, qxl_async_io async)
-{
-    trace_qxl_spice_destroy_surfaces(qxl->id, async);
-    if (async) {
-        spice_qxl_destroy_surfaces_async(&qxl->ssd.qxl,
-                (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO,
-                                          QXL_IO_DESTROY_ALL_SURFACES_ASYNC));
-    } else {
-        qxl->ssd.worker->destroy_surfaces(qxl->ssd.worker);
-        qxl_spice_destroy_surfaces_complete(qxl);
-    }
-}
-
-static void qxl_spice_monitors_config_async(PCIQXLDevice *qxl, int replay)
-{
-    trace_qxl_spice_monitors_config(qxl->id);
-    if (replay) {
-        /*
-         * don't use QXL_COOKIE_TYPE_IO:
-         *  - we are not running yet (post_load), we will assert
-         *    in send_events
-         *  - this is not a guest io, but a reply, so async_io isn't set.
-         */
-        spice_qxl_monitors_config_async(&qxl->ssd.qxl,
-                qxl->guest_monitors_config,
-                MEMSLOT_GROUP_GUEST,
-                (uintptr_t)qxl_cookie_new(
-                    QXL_COOKIE_TYPE_POST_LOAD_MONITORS_CONFIG,
-                    0));
-    } else {
-        qxl->guest_monitors_config = qxl->ram->monitors_config;
-        spice_qxl_monitors_config_async(&qxl->ssd.qxl,
-                qxl->ram->monitors_config,
-                MEMSLOT_GROUP_GUEST,
-                (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO,
-                                          QXL_IO_MONITORS_CONFIG_ASYNC));
-    }
-}
-
-void qxl_spice_reset_image_cache(PCIQXLDevice *qxl)
-{
-    trace_qxl_spice_reset_image_cache(qxl->id);
-    qxl->ssd.worker->reset_image_cache(qxl->ssd.worker);
-}
-
-void qxl_spice_reset_cursor(PCIQXLDevice *qxl)
-{
-    trace_qxl_spice_reset_cursor(qxl->id);
-    qxl->ssd.worker->reset_cursor(qxl->ssd.worker);
-    qemu_mutex_lock(&qxl->track_lock);
-    qxl->guest_cursor = 0;
-    qemu_mutex_unlock(&qxl->track_lock);
-    if (qxl->ssd.cursor) {
-        cursor_put(qxl->ssd.cursor);
-    }
-    qxl->ssd.cursor = cursor_builtin_hidden();
-}
-
-
-static inline uint32_t msb_mask(uint32_t val)
-{
-    uint32_t mask;
-
-    do {
-        mask = ~(val - 1) & val;
-        val &= ~mask;
-    } while (mask < val);
-
-    return mask;
-}
-
-static ram_addr_t qxl_rom_size(void)
-{
-    uint32_t required_rom_size = sizeof(QXLRom) + sizeof(QXLModes) +
-                                 sizeof(qxl_modes);
-    uint32_t rom_size = 8192; /* two pages */
-
-    required_rom_size = MAX(required_rom_size, TARGET_PAGE_SIZE);
-    required_rom_size = msb_mask(required_rom_size * 2 - 1);
-    assert(required_rom_size <= rom_size);
-    return rom_size;
-}
-
-static void init_qxl_rom(PCIQXLDevice *d)
-{
-    QXLRom *rom = memory_region_get_ram_ptr(&d->rom_bar);
-    QXLModes *modes = (QXLModes *)(rom + 1);
-    uint32_t ram_header_size;
-    uint32_t surface0_area_size;
-    uint32_t num_pages;
-    uint32_t fb;
-    int i, n;
-
-    memset(rom, 0, d->rom_size);
-
-    rom->magic         = cpu_to_le32(QXL_ROM_MAGIC);
-    rom->id            = cpu_to_le32(d->id);
-    rom->log_level     = cpu_to_le32(d->guestdebug);
-    rom->modes_offset  = cpu_to_le32(sizeof(QXLRom));
-
-    rom->slot_gen_bits = MEMSLOT_GENERATION_BITS;
-    rom->slot_id_bits  = MEMSLOT_SLOT_BITS;
-    rom->slots_start   = 1;
-    rom->slots_end     = NUM_MEMSLOTS - 1;
-    rom->n_surfaces    = cpu_to_le32(d->ssd.num_surfaces);
-
-    for (i = 0, n = 0; i < ARRAY_SIZE(qxl_modes); i++) {
-        fb = qxl_modes[i].y_res * qxl_modes[i].stride;
-        if (fb > d->vgamem_size) {
-            continue;
-        }
-        modes->modes[n].id          = cpu_to_le32(i);
-        modes->modes[n].x_res       = cpu_to_le32(qxl_modes[i].x_res);
-        modes->modes[n].y_res       = cpu_to_le32(qxl_modes[i].y_res);
-        modes->modes[n].bits        = cpu_to_le32(qxl_modes[i].bits);
-        modes->modes[n].stride      = cpu_to_le32(qxl_modes[i].stride);
-        modes->modes[n].x_mili      = cpu_to_le32(qxl_modes[i].x_mili);
-        modes->modes[n].y_mili      = cpu_to_le32(qxl_modes[i].y_mili);
-        modes->modes[n].orientation = cpu_to_le32(qxl_modes[i].orientation);
-        n++;
-    }
-    modes->n_modes     = cpu_to_le32(n);
-
-    ram_header_size    = ALIGN(sizeof(QXLRam), 4096);
-    surface0_area_size = ALIGN(d->vgamem_size, 4096);
-    num_pages          = d->vga.vram_size;
-    num_pages         -= ram_header_size;
-    num_pages         -= surface0_area_size;
-    num_pages          = num_pages / TARGET_PAGE_SIZE;
-
-    rom->draw_area_offset   = cpu_to_le32(0);
-    rom->surface0_area_size = cpu_to_le32(surface0_area_size);
-    rom->pages_offset       = cpu_to_le32(surface0_area_size);
-    rom->num_pages          = cpu_to_le32(num_pages);
-    rom->ram_header_offset  = cpu_to_le32(d->vga.vram_size - ram_header_size);
-
-    d->shadow_rom = *rom;
-    d->rom        = rom;
-    d->modes      = modes;
-}
-
-static void init_qxl_ram(PCIQXLDevice *d)
-{
-    uint8_t *buf;
-    uint64_t *item;
-
-    buf = d->vga.vram_ptr;
-    d->ram = (QXLRam *)(buf + le32_to_cpu(d->shadow_rom.ram_header_offset));
-    d->ram->magic       = cpu_to_le32(QXL_RAM_MAGIC);
-    d->ram->int_pending = cpu_to_le32(0);
-    d->ram->int_mask    = cpu_to_le32(0);
-    d->ram->update_surface = 0;
-    SPICE_RING_INIT(&d->ram->cmd_ring);
-    SPICE_RING_INIT(&d->ram->cursor_ring);
-    SPICE_RING_INIT(&d->ram->release_ring);
-    SPICE_RING_PROD_ITEM(d, &d->ram->release_ring, item);
-    assert(item);
-    *item = 0;
-    qxl_ring_set_dirty(d);
-}
-
-/* can be called from spice server thread context */
-static void qxl_set_dirty(MemoryRegion *mr, ram_addr_t addr, ram_addr_t end)
-{
-    memory_region_set_dirty(mr, addr, end - addr);
-}
-
-static void qxl_rom_set_dirty(PCIQXLDevice *qxl)
-{
-    qxl_set_dirty(&qxl->rom_bar, 0, qxl->rom_size);
-}
-
-/* called from spice server thread context only */
-static void qxl_ram_set_dirty(PCIQXLDevice *qxl, void *ptr)
-{
-    void *base = qxl->vga.vram_ptr;
-    intptr_t offset;
-
-    offset = ptr - base;
-    offset &= ~(TARGET_PAGE_SIZE-1);
-    assert(offset < qxl->vga.vram_size);
-    qxl_set_dirty(&qxl->vga.vram, offset, offset + TARGET_PAGE_SIZE);
-}
-
-/* can be called from spice server thread context */
-static void qxl_ring_set_dirty(PCIQXLDevice *qxl)
-{
-    ram_addr_t addr = qxl->shadow_rom.ram_header_offset;
-    ram_addr_t end  = qxl->vga.vram_size;
-    qxl_set_dirty(&qxl->vga.vram, addr, end);
-}
-
-/*
- * keep track of some command state, for savevm/loadvm.
- * called from spice server thread context only
- */
-static int qxl_track_command(PCIQXLDevice *qxl, struct QXLCommandExt *ext)
-{
-    switch (le32_to_cpu(ext->cmd.type)) {
-    case QXL_CMD_SURFACE:
-    {
-        QXLSurfaceCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id);
-
-        if (!cmd) {
-            return 1;
-        }
-        uint32_t id = le32_to_cpu(cmd->surface_id);
-
-        if (id >= qxl->ssd.num_surfaces) {
-            qxl_set_guest_bug(qxl, "QXL_CMD_SURFACE id %d >= %d", id,
-                              qxl->ssd.num_surfaces);
-            return 1;
-        }
-        if (cmd->type == QXL_SURFACE_CMD_CREATE &&
-            (cmd->u.surface_create.stride & 0x03) != 0) {
-            qxl_set_guest_bug(qxl, "QXL_CMD_SURFACE stride = %d %% 4 != 0\n",
-                              cmd->u.surface_create.stride);
-            return 1;
-        }
-        qemu_mutex_lock(&qxl->track_lock);
-        if (cmd->type == QXL_SURFACE_CMD_CREATE) {
-            qxl->guest_surfaces.cmds[id] = ext->cmd.data;
-            qxl->guest_surfaces.count++;
-            if (qxl->guest_surfaces.max < qxl->guest_surfaces.count)
-                qxl->guest_surfaces.max = qxl->guest_surfaces.count;
-        }
-        if (cmd->type == QXL_SURFACE_CMD_DESTROY) {
-            qxl->guest_surfaces.cmds[id] = 0;
-            qxl->guest_surfaces.count--;
-        }
-        qemu_mutex_unlock(&qxl->track_lock);
-        break;
-    }
-    case QXL_CMD_CURSOR:
-    {
-        QXLCursorCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id);
-
-        if (!cmd) {
-            return 1;
-        }
-        if (cmd->type == QXL_CURSOR_SET) {
-            qemu_mutex_lock(&qxl->track_lock);
-            qxl->guest_cursor = ext->cmd.data;
-            qemu_mutex_unlock(&qxl->track_lock);
-        }
-        break;
-    }
-    }
-    return 0;
-}
-
-/* spice display interface callbacks */
-
-static void interface_attach_worker(QXLInstance *sin, QXLWorker *qxl_worker)
-{
-    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
-
-    trace_qxl_interface_attach_worker(qxl->id);
-    qxl->ssd.worker = qxl_worker;
-}
-
-static void interface_set_compression_level(QXLInstance *sin, int level)
-{
-    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
-
-    trace_qxl_interface_set_compression_level(qxl->id, level);
-    qxl->shadow_rom.compression_level = cpu_to_le32(level);
-    qxl->rom->compression_level = cpu_to_le32(level);
-    qxl_rom_set_dirty(qxl);
-}
-
-static void interface_set_mm_time(QXLInstance *sin, uint32_t mm_time)
-{
-    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
-
-    trace_qxl_interface_set_mm_time(qxl->id, mm_time);
-    qxl->shadow_rom.mm_clock = cpu_to_le32(mm_time);
-    qxl->rom->mm_clock = cpu_to_le32(mm_time);
-    qxl_rom_set_dirty(qxl);
-}
-
-static void interface_get_init_info(QXLInstance *sin, QXLDevInitInfo *info)
-{
-    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
-
-    trace_qxl_interface_get_init_info(qxl->id);
-    info->memslot_gen_bits = MEMSLOT_GENERATION_BITS;
-    info->memslot_id_bits = MEMSLOT_SLOT_BITS;
-    info->num_memslots = NUM_MEMSLOTS;
-    info->num_memslots_groups = NUM_MEMSLOTS_GROUPS;
-    info->internal_groupslot_id = 0;
-    info->qxl_ram_size = le32_to_cpu(qxl->shadow_rom.num_pages) << TARGET_PAGE_BITS;
-    info->n_surfaces = qxl->ssd.num_surfaces;
-}
-
-static const char *qxl_mode_to_string(int mode)
-{
-    switch (mode) {
-    case QXL_MODE_COMPAT:
-        return "compat";
-    case QXL_MODE_NATIVE:
-        return "native";
-    case QXL_MODE_UNDEFINED:
-        return "undefined";
-    case QXL_MODE_VGA:
-        return "vga";
-    }
-    return "INVALID";
-}
-
-static const char *io_port_to_string(uint32_t io_port)
-{
-    if (io_port >= QXL_IO_RANGE_SIZE) {
-        return "out of range";
-    }
-    static const char *io_port_to_string[QXL_IO_RANGE_SIZE + 1] = {
-        [QXL_IO_NOTIFY_CMD]             = "QXL_IO_NOTIFY_CMD",
-        [QXL_IO_NOTIFY_CURSOR]          = "QXL_IO_NOTIFY_CURSOR",
-        [QXL_IO_UPDATE_AREA]            = "QXL_IO_UPDATE_AREA",
-        [QXL_IO_UPDATE_IRQ]             = "QXL_IO_UPDATE_IRQ",
-        [QXL_IO_NOTIFY_OOM]             = "QXL_IO_NOTIFY_OOM",
-        [QXL_IO_RESET]                  = "QXL_IO_RESET",
-        [QXL_IO_SET_MODE]               = "QXL_IO_SET_MODE",
-        [QXL_IO_LOG]                    = "QXL_IO_LOG",
-        [QXL_IO_MEMSLOT_ADD]            = "QXL_IO_MEMSLOT_ADD",
-        [QXL_IO_MEMSLOT_DEL]            = "QXL_IO_MEMSLOT_DEL",
-        [QXL_IO_DETACH_PRIMARY]         = "QXL_IO_DETACH_PRIMARY",
-        [QXL_IO_ATTACH_PRIMARY]         = "QXL_IO_ATTACH_PRIMARY",
-        [QXL_IO_CREATE_PRIMARY]         = "QXL_IO_CREATE_PRIMARY",
-        [QXL_IO_DESTROY_PRIMARY]        = "QXL_IO_DESTROY_PRIMARY",
-        [QXL_IO_DESTROY_SURFACE_WAIT]   = "QXL_IO_DESTROY_SURFACE_WAIT",
-        [QXL_IO_DESTROY_ALL_SURFACES]   = "QXL_IO_DESTROY_ALL_SURFACES",
-        [QXL_IO_UPDATE_AREA_ASYNC]      = "QXL_IO_UPDATE_AREA_ASYNC",
-        [QXL_IO_MEMSLOT_ADD_ASYNC]      = "QXL_IO_MEMSLOT_ADD_ASYNC",
-        [QXL_IO_CREATE_PRIMARY_ASYNC]   = "QXL_IO_CREATE_PRIMARY_ASYNC",
-        [QXL_IO_DESTROY_PRIMARY_ASYNC]  = "QXL_IO_DESTROY_PRIMARY_ASYNC",
-        [QXL_IO_DESTROY_SURFACE_ASYNC]  = "QXL_IO_DESTROY_SURFACE_ASYNC",
-        [QXL_IO_DESTROY_ALL_SURFACES_ASYNC]
-                                        = "QXL_IO_DESTROY_ALL_SURFACES_ASYNC",
-        [QXL_IO_FLUSH_SURFACES_ASYNC]   = "QXL_IO_FLUSH_SURFACES_ASYNC",
-        [QXL_IO_FLUSH_RELEASE]          = "QXL_IO_FLUSH_RELEASE",
-        [QXL_IO_MONITORS_CONFIG_ASYNC]  = "QXL_IO_MONITORS_CONFIG_ASYNC",
-    };
-    return io_port_to_string[io_port];
-}
-
-/* called from spice server thread context only */
-static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext)
-{
-    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
-    SimpleSpiceUpdate *update;
-    QXLCommandRing *ring;
-    QXLCommand *cmd;
-    int notify, ret;
-
-    trace_qxl_ring_command_check(qxl->id, qxl_mode_to_string(qxl->mode));
-
-    switch (qxl->mode) {
-    case QXL_MODE_VGA:
-        ret = false;
-        qemu_mutex_lock(&qxl->ssd.lock);
-        update = QTAILQ_FIRST(&qxl->ssd.updates);
-        if (update != NULL) {
-            QTAILQ_REMOVE(&qxl->ssd.updates, update, next);
-            *ext = update->ext;
-            ret = true;
-        }
-        qemu_mutex_unlock(&qxl->ssd.lock);
-        if (ret) {
-            trace_qxl_ring_command_get(qxl->id, qxl_mode_to_string(qxl->mode));
-            qxl_log_command(qxl, "vga", ext);
-        }
-        return ret;
-    case QXL_MODE_COMPAT:
-    case QXL_MODE_NATIVE:
-    case QXL_MODE_UNDEFINED:
-        ring = &qxl->ram->cmd_ring;
-        if (qxl->guest_bug || SPICE_RING_IS_EMPTY(ring)) {
-            return false;
-        }
-        SPICE_RING_CONS_ITEM(qxl, ring, cmd);
-        if (!cmd) {
-            return false;
-        }
-        ext->cmd      = *cmd;
-        ext->group_id = MEMSLOT_GROUP_GUEST;
-        ext->flags    = qxl->cmdflags;
-        SPICE_RING_POP(ring, notify);
-        qxl_ring_set_dirty(qxl);
-        if (notify) {
-            qxl_send_events(qxl, QXL_INTERRUPT_DISPLAY);
-        }
-        qxl->guest_primary.commands++;
-        qxl_track_command(qxl, ext);
-        qxl_log_command(qxl, "cmd", ext);
-        trace_qxl_ring_command_get(qxl->id, qxl_mode_to_string(qxl->mode));
-        return true;
-    default:
-        return false;
-    }
-}
-
-/* called from spice server thread context only */
-static int interface_req_cmd_notification(QXLInstance *sin)
-{
-    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
-    int wait = 1;
-
-    trace_qxl_ring_command_req_notification(qxl->id);
-    switch (qxl->mode) {
-    case QXL_MODE_COMPAT:
-    case QXL_MODE_NATIVE:
-    case QXL_MODE_UNDEFINED:
-        SPICE_RING_CONS_WAIT(&qxl->ram->cmd_ring, wait);
-        qxl_ring_set_dirty(qxl);
-        break;
-    default:
-        /* nothing */
-        break;
-    }
-    return wait;
-}
-
-/* called from spice server thread context only */
-static inline void qxl_push_free_res(PCIQXLDevice *d, int flush)
-{
-    QXLReleaseRing *ring = &d->ram->release_ring;
-    uint64_t *item;
-    int notify;
-
-#define QXL_FREE_BUNCH_SIZE 32
-
-    if (ring->prod - ring->cons + 1 == ring->num_items) {
-        /* ring full -- can't push */
-        return;
-    }
-    if (!flush && d->oom_running) {
-        /* collect everything from oom handler before pushing */
-        return;
-    }
-    if (!flush && d->num_free_res < QXL_FREE_BUNCH_SIZE) {
-        /* collect a bit more before pushing */
-        return;
-    }
-
-    SPICE_RING_PUSH(ring, notify);
-    trace_qxl_ring_res_push(d->id, qxl_mode_to_string(d->mode),
-           d->guest_surfaces.count, d->num_free_res,
-           d->last_release, notify ? "yes" : "no");
-    trace_qxl_ring_res_push_rest(d->id, ring->prod - ring->cons,
-           ring->num_items, ring->prod, ring->cons);
-    if (notify) {
-        qxl_send_events(d, QXL_INTERRUPT_DISPLAY);
-    }
-    SPICE_RING_PROD_ITEM(d, ring, item);
-    if (!item) {
-        return;
-    }
-    *item = 0;
-    d->num_free_res = 0;
-    d->last_release = NULL;
-    qxl_ring_set_dirty(d);
-}
-
-/* called from spice server thread context only */
-static void interface_release_resource(QXLInstance *sin,
-                                       struct QXLReleaseInfoExt ext)
-{
-    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
-    QXLReleaseRing *ring;
-    uint64_t *item, id;
-
-    if (ext.group_id == MEMSLOT_GROUP_HOST) {
-        /* host group -> vga mode update request */
-        qemu_spice_destroy_update(&qxl->ssd, (void *)(intptr_t)ext.info->id);
-        return;
-    }
-
-    /*
-     * ext->info points into guest-visible memory
-     * pci bar 0, $command.release_info
-     */
-    ring = &qxl->ram->release_ring;
-    SPICE_RING_PROD_ITEM(qxl, ring, item);
-    if (!item) {
-        return;
-    }
-    if (*item == 0) {
-        /* stick head into the ring */
-        id = ext.info->id;
-        ext.info->next = 0;
-        qxl_ram_set_dirty(qxl, &ext.info->next);
-        *item = id;
-        qxl_ring_set_dirty(qxl);
-    } else {
-        /* append item to the list */
-        qxl->last_release->next = ext.info->id;
-        qxl_ram_set_dirty(qxl, &qxl->last_release->next);
-        ext.info->next = 0;
-        qxl_ram_set_dirty(qxl, &ext.info->next);
-    }
-    qxl->last_release = ext.info;
-    qxl->num_free_res++;
-    trace_qxl_ring_res_put(qxl->id, qxl->num_free_res);
-    qxl_push_free_res(qxl, 0);
-}
-
-/* called from spice server thread context only */
-static int interface_get_cursor_command(QXLInstance *sin, struct QXLCommandExt *ext)
-{
-    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
-    QXLCursorRing *ring;
-    QXLCommand *cmd;
-    int notify;
-
-    trace_qxl_ring_cursor_check(qxl->id, qxl_mode_to_string(qxl->mode));
-
-    switch (qxl->mode) {
-    case QXL_MODE_COMPAT:
-    case QXL_MODE_NATIVE:
-    case QXL_MODE_UNDEFINED:
-        ring = &qxl->ram->cursor_ring;
-        if (SPICE_RING_IS_EMPTY(ring)) {
-            return false;
-        }
-        SPICE_RING_CONS_ITEM(qxl, ring, cmd);
-        if (!cmd) {
-            return false;
-        }
-        ext->cmd      = *cmd;
-        ext->group_id = MEMSLOT_GROUP_GUEST;
-        ext->flags    = qxl->cmdflags;
-        SPICE_RING_POP(ring, notify);
-        qxl_ring_set_dirty(qxl);
-        if (notify) {
-            qxl_send_events(qxl, QXL_INTERRUPT_CURSOR);
-        }
-        qxl->guest_primary.commands++;
-        qxl_track_command(qxl, ext);
-        qxl_log_command(qxl, "csr", ext);
-        if (qxl->id == 0) {
-            qxl_render_cursor(qxl, ext);
-        }
-        trace_qxl_ring_cursor_get(qxl->id, qxl_mode_to_string(qxl->mode));
-        return true;
-    default:
-        return false;
-    }
-}
-
-/* called from spice server thread context only */
-static int interface_req_cursor_notification(QXLInstance *sin)
-{
-    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
-    int wait = 1;
-
-    trace_qxl_ring_cursor_req_notification(qxl->id);
-    switch (qxl->mode) {
-    case QXL_MODE_COMPAT:
-    case QXL_MODE_NATIVE:
-    case QXL_MODE_UNDEFINED:
-        SPICE_RING_CONS_WAIT(&qxl->ram->cursor_ring, wait);
-        qxl_ring_set_dirty(qxl);
-        break;
-    default:
-        /* nothing */
-        break;
-    }
-    return wait;
-}
-
-/* called from spice server thread context */
-static void interface_notify_update(QXLInstance *sin, uint32_t update_id)
-{
-    /*
-     * Called by spice-server as a result of a QXL_CMD_UPDATE which is not in
-     * use by xf86-video-qxl and is defined out in the qxl windows driver.
-     * Probably was at some earlier version that is prior to git start (2009),
-     * and is still guest trigerrable.
-     */
-    fprintf(stderr, "%s: deprecated\n", __func__);
-}
-
-/* called from spice server thread context only */
-static int interface_flush_resources(QXLInstance *sin)
-{
-    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
-    int ret;
-
-    ret = qxl->num_free_res;
-    if (ret) {
-        qxl_push_free_res(qxl, 1);
-    }
-    return ret;
-}
-
-static void qxl_create_guest_primary_complete(PCIQXLDevice *d);
-
-/* called from spice server thread context only */
-static void interface_async_complete_io(PCIQXLDevice *qxl, QXLCookie *cookie)
-{
-    uint32_t current_async;
-
-    qemu_mutex_lock(&qxl->async_lock);
-    current_async = qxl->current_async;
-    qxl->current_async = QXL_UNDEFINED_IO;
-    qemu_mutex_unlock(&qxl->async_lock);
-
-    trace_qxl_interface_async_complete_io(qxl->id, current_async, cookie);
-    if (!cookie) {
-        fprintf(stderr, "qxl: %s: error, cookie is NULL\n", __func__);
-        return;
-    }
-    if (cookie && current_async != cookie->io) {
-        fprintf(stderr,
-                "qxl: %s: error: current_async = %d != %"
-                PRId64 " = cookie->io\n", __func__, current_async, cookie->io);
-    }
-    switch (current_async) {
-    case QXL_IO_MEMSLOT_ADD_ASYNC:
-    case QXL_IO_DESTROY_PRIMARY_ASYNC:
-    case QXL_IO_UPDATE_AREA_ASYNC:
-    case QXL_IO_FLUSH_SURFACES_ASYNC:
-    case QXL_IO_MONITORS_CONFIG_ASYNC:
-        break;
-    case QXL_IO_CREATE_PRIMARY_ASYNC:
-        qxl_create_guest_primary_complete(qxl);
-        break;
-    case QXL_IO_DESTROY_ALL_SURFACES_ASYNC:
-        qxl_spice_destroy_surfaces_complete(qxl);
-        break;
-    case QXL_IO_DESTROY_SURFACE_ASYNC:
-        qxl_spice_destroy_surface_wait_complete(qxl, cookie->u.surface_id);
-        break;
-    default:
-        fprintf(stderr, "qxl: %s: unexpected current_async %d\n", __func__,
-                current_async);
-    }
-    qxl_send_events(qxl, QXL_INTERRUPT_IO_CMD);
-}
-
-/* called from spice server thread context only */
-static void interface_update_area_complete(QXLInstance *sin,
-        uint32_t surface_id,
-        QXLRect *dirty, uint32_t num_updated_rects)
-{
-    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
-    int i;
-    int qxl_i;
-
-    qemu_mutex_lock(&qxl->ssd.lock);
-    if (surface_id != 0 || !qxl->render_update_cookie_num) {
-        qemu_mutex_unlock(&qxl->ssd.lock);
-        return;
-    }
-    trace_qxl_interface_update_area_complete(qxl->id, surface_id, dirty->left,
-            dirty->right, dirty->top, dirty->bottom);
-    trace_qxl_interface_update_area_complete_rest(qxl->id, num_updated_rects);
-    if (qxl->num_dirty_rects + num_updated_rects > QXL_NUM_DIRTY_RECTS) {
-        /*
-         * overflow - treat this as a full update. Not expected to be common.
-         */
-        trace_qxl_interface_update_area_complete_overflow(qxl->id,
-                                                          QXL_NUM_DIRTY_RECTS);
-        qxl->guest_primary.resized = 1;
-    }
-    if (qxl->guest_primary.resized) {
-        /*
-         * Don't bother copying or scheduling the bh since we will flip
-         * the whole area anyway on completion of the update_area async call
-         */
-        qemu_mutex_unlock(&qxl->ssd.lock);
-        return;
-    }
-    qxl_i = qxl->num_dirty_rects;
-    for (i = 0; i < num_updated_rects; i++) {
-        qxl->dirty[qxl_i++] = dirty[i];
-    }
-    qxl->num_dirty_rects += num_updated_rects;
-    trace_qxl_interface_update_area_complete_schedule_bh(qxl->id,
-                                                         qxl->num_dirty_rects);
-    qemu_bh_schedule(qxl->update_area_bh);
-    qemu_mutex_unlock(&qxl->ssd.lock);
-}
-
-/* called from spice server thread context only */
-static void interface_async_complete(QXLInstance *sin, uint64_t cookie_token)
-{
-    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
-    QXLCookie *cookie = (QXLCookie *)(uintptr_t)cookie_token;
-
-    switch (cookie->type) {
-    case QXL_COOKIE_TYPE_IO:
-        interface_async_complete_io(qxl, cookie);
-        g_free(cookie);
-        break;
-    case QXL_COOKIE_TYPE_RENDER_UPDATE_AREA:
-        qxl_render_update_area_done(qxl, cookie);
-        break;
-    case QXL_COOKIE_TYPE_POST_LOAD_MONITORS_CONFIG:
-        break;
-    default:
-        fprintf(stderr, "qxl: %s: unexpected cookie type %d\n",
-                __func__, cookie->type);
-        g_free(cookie);
-    }
-}
-
-/* called from spice server thread context only */
-static void interface_set_client_capabilities(QXLInstance *sin,
-                                              uint8_t client_present,
-                                              uint8_t caps[58])
-{
-    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
-
-    if (qxl->revision < 4) {
-        trace_qxl_set_client_capabilities_unsupported_by_revision(qxl->id,
-                                                              qxl->revision);
-        return;
-    }
-
-    if (runstate_check(RUN_STATE_INMIGRATE) ||
-        runstate_check(RUN_STATE_POSTMIGRATE)) {
-        return;
-    }
-
-    qxl->shadow_rom.client_present = client_present;
-    memcpy(qxl->shadow_rom.client_capabilities, caps,
-           sizeof(qxl->shadow_rom.client_capabilities));
-    qxl->rom->client_present = client_present;
-    memcpy(qxl->rom->client_capabilities, caps,
-           sizeof(qxl->rom->client_capabilities));
-    qxl_rom_set_dirty(qxl);
-
-    qxl_send_events(qxl, QXL_INTERRUPT_CLIENT);
-}
-
-static uint32_t qxl_crc32(const uint8_t *p, unsigned len)
-{
-    /*
-     * zlib xors the seed with 0xffffffff, and xors the result
-     * again with 0xffffffff; Both are not done with linux's crc32,
-     * which we want to be compatible with, so undo that.
-     */
-    return crc32(0xffffffff, p, len) ^ 0xffffffff;
-}
-
-/* called from main context only */
-static int interface_client_monitors_config(QXLInstance *sin,
-                                        VDAgentMonitorsConfig *monitors_config)
-{
-    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
-    QXLRom *rom = memory_region_get_ram_ptr(&qxl->rom_bar);
-    int i;
-
-    if (qxl->revision < 4) {
-        trace_qxl_client_monitors_config_unsupported_by_device(qxl->id,
-                                                               qxl->revision);
-        return 0;
-    }
-    /*
-     * Older windows drivers set int_mask to 0 when their ISR is called,
-     * then later set it to ~0. So it doesn't relate to the actual interrupts
-     * handled. However, they are old, so clearly they don't support this
-     * interrupt
-     */
-    if (qxl->ram->int_mask == 0 || qxl->ram->int_mask == ~0 ||
-        !(qxl->ram->int_mask & QXL_INTERRUPT_CLIENT_MONITORS_CONFIG)) {
-        trace_qxl_client_monitors_config_unsupported_by_guest(qxl->id,
-                                                            qxl->ram->int_mask,
-                                                            monitors_config);
-        return 0;
-    }
-    if (!monitors_config) {
-        return 1;
-    }
-    memset(&rom->client_monitors_config, 0,
-           sizeof(rom->client_monitors_config));
-    rom->client_monitors_config.count = monitors_config->num_of_monitors;
-    /* monitors_config->flags ignored */
-    if (rom->client_monitors_config.count >=
-            ARRAY_SIZE(rom->client_monitors_config.heads)) {
-        trace_qxl_client_monitors_config_capped(qxl->id,
-                                monitors_config->num_of_monitors,
-                                ARRAY_SIZE(rom->client_monitors_config.heads));
-        rom->client_monitors_config.count =
-            ARRAY_SIZE(rom->client_monitors_config.heads);
-    }
-    for (i = 0 ; i < rom->client_monitors_config.count ; ++i) {
-        VDAgentMonConfig *monitor = &monitors_config->monitors[i];
-        QXLURect *rect = &rom->client_monitors_config.heads[i];
-        /* monitor->depth ignored */
-        rect->left = monitor->x;
-        rect->top = monitor->y;
-        rect->right = monitor->x + monitor->width;
-        rect->bottom = monitor->y + monitor->height;
-    }
-    rom->client_monitors_config_crc = qxl_crc32(
-            (const uint8_t *)&rom->client_monitors_config,
-            sizeof(rom->client_monitors_config));
-    trace_qxl_client_monitors_config_crc(qxl->id,
-            sizeof(rom->client_monitors_config),
-            rom->client_monitors_config_crc);
-
-    trace_qxl_interrupt_client_monitors_config(qxl->id,
-                        rom->client_monitors_config.count,
-                        rom->client_monitors_config.heads);
-    qxl_send_events(qxl, QXL_INTERRUPT_CLIENT_MONITORS_CONFIG);
-    return 1;
-}
-
-static const QXLInterface qxl_interface = {
-    .base.type               = SPICE_INTERFACE_QXL,
-    .base.description        = "qxl gpu",
-    .base.major_version      = SPICE_INTERFACE_QXL_MAJOR,
-    .base.minor_version      = SPICE_INTERFACE_QXL_MINOR,
-
-    .attache_worker          = interface_attach_worker,
-    .set_compression_level   = interface_set_compression_level,
-    .set_mm_time             = interface_set_mm_time,
-    .get_init_info           = interface_get_init_info,
-
-    /* the callbacks below are called from spice server thread context */
-    .get_command             = interface_get_command,
-    .req_cmd_notification    = interface_req_cmd_notification,
-    .release_resource        = interface_release_resource,
-    .get_cursor_command      = interface_get_cursor_command,
-    .req_cursor_notification = interface_req_cursor_notification,
-    .notify_update           = interface_notify_update,
-    .flush_resources         = interface_flush_resources,
-    .async_complete          = interface_async_complete,
-    .update_area_complete    = interface_update_area_complete,
-    .set_client_capabilities = interface_set_client_capabilities,
-    .client_monitors_config = interface_client_monitors_config,
-};
-
-static void qxl_enter_vga_mode(PCIQXLDevice *d)
-{
-    if (d->mode == QXL_MODE_VGA) {
-        return;
-    }
-    trace_qxl_enter_vga_mode(d->id);
-    qemu_spice_create_host_primary(&d->ssd);
-    d->mode = QXL_MODE_VGA;
-    vga_dirty_log_start(&d->vga);
-    vga_hw_update();
-}
-
-static void qxl_exit_vga_mode(PCIQXLDevice *d)
-{
-    if (d->mode != QXL_MODE_VGA) {
-        return;
-    }
-    trace_qxl_exit_vga_mode(d->id);
-    vga_dirty_log_stop(&d->vga);
-    qxl_destroy_primary(d, QXL_SYNC);
-}
-
-static void qxl_update_irq(PCIQXLDevice *d)
-{
-    uint32_t pending = le32_to_cpu(d->ram->int_pending);
-    uint32_t mask    = le32_to_cpu(d->ram->int_mask);
-    int level = !!(pending & mask);
-    qemu_set_irq(d->pci.irq[0], level);
-    qxl_ring_set_dirty(d);
-}
-
-static void qxl_check_state(PCIQXLDevice *d)
-{
-    QXLRam *ram = d->ram;
-    int spice_display_running = qemu_spice_display_is_running(&d->ssd);
-
-    assert(!spice_display_running || SPICE_RING_IS_EMPTY(&ram->cmd_ring));
-    assert(!spice_display_running || SPICE_RING_IS_EMPTY(&ram->cursor_ring));
-}
-
-static void qxl_reset_state(PCIQXLDevice *d)
-{
-    QXLRom *rom = d->rom;
-
-    qxl_check_state(d);
-    d->shadow_rom.update_id = cpu_to_le32(0);
-    *rom = d->shadow_rom;
-    qxl_rom_set_dirty(d);
-    init_qxl_ram(d);
-    d->num_free_res = 0;
-    d->last_release = NULL;
-    memset(&d->ssd.dirty, 0, sizeof(d->ssd.dirty));
-}
-
-static void qxl_soft_reset(PCIQXLDevice *d)
-{
-    trace_qxl_soft_reset(d->id);
-    qxl_check_state(d);
-    qxl_clear_guest_bug(d);
-    d->current_async = QXL_UNDEFINED_IO;
-
-    if (d->id == 0) {
-        qxl_enter_vga_mode(d);
-    } else {
-        d->mode = QXL_MODE_UNDEFINED;
-    }
-}
-
-static void qxl_hard_reset(PCIQXLDevice *d, int loadvm)
-{
-    trace_qxl_hard_reset(d->id, loadvm);
-
-    qxl_spice_reset_cursor(d);
-    qxl_spice_reset_image_cache(d);
-    qxl_reset_surfaces(d);
-    qxl_reset_memslots(d);
-
-    /* pre loadvm reset must not touch QXLRam.  This lives in
-     * device memory, is migrated together with RAM and thus
-     * already loaded at this point */
-    if (!loadvm) {
-        qxl_reset_state(d);
-    }
-    qemu_spice_create_host_memslot(&d->ssd);
-    qxl_soft_reset(d);
-}
-
-static void qxl_reset_handler(DeviceState *dev)
-{
-    PCIQXLDevice *d = DO_UPCAST(PCIQXLDevice, pci.qdev, dev);
-
-    qxl_hard_reset(d, 0);
-}
-
-static void qxl_vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
-{
-    VGACommonState *vga = opaque;
-    PCIQXLDevice *qxl = container_of(vga, PCIQXLDevice, vga);
-
-    trace_qxl_io_write_vga(qxl->id, qxl_mode_to_string(qxl->mode), addr, val);
-    if (qxl->mode != QXL_MODE_VGA) {
-        qxl_destroy_primary(qxl, QXL_SYNC);
-        qxl_soft_reset(qxl);
-    }
-    vga_ioport_write(opaque, addr, val);
-}
-
-static const MemoryRegionPortio qxl_vga_portio_list[] = {
-    { 0x04,  2, 1, .read  = vga_ioport_read,
-                   .write = qxl_vga_ioport_write }, /* 3b4 */
-    { 0x0a,  1, 1, .read  = vga_ioport_read,
-                   .write = qxl_vga_ioport_write }, /* 3ba */
-    { 0x10, 16, 1, .read  = vga_ioport_read,
-                   .write = qxl_vga_ioport_write }, /* 3c0 */
-    { 0x24,  2, 1, .read  = vga_ioport_read,
-                   .write = qxl_vga_ioport_write }, /* 3d4 */
-    { 0x2a,  1, 1, .read  = vga_ioport_read,
-                   .write = qxl_vga_ioport_write }, /* 3da */
-    PORTIO_END_OF_LIST(),
-};
-
-static int qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta,
-                           qxl_async_io async)
-{
-    static const int regions[] = {
-        QXL_RAM_RANGE_INDEX,
-        QXL_VRAM_RANGE_INDEX,
-        QXL_VRAM64_RANGE_INDEX,
-    };
-    uint64_t guest_start;
-    uint64_t guest_end;
-    int pci_region;
-    pcibus_t pci_start;
-    pcibus_t pci_end;
-    intptr_t virt_start;
-    QXLDevMemSlot memslot;
-    int i;
-
-    guest_start = le64_to_cpu(d->guest_slots[slot_id].slot.mem_start);
-    guest_end   = le64_to_cpu(d->guest_slots[slot_id].slot.mem_end);
-
-    trace_qxl_memslot_add_guest(d->id, slot_id, guest_start, guest_end);
-
-    if (slot_id >= NUM_MEMSLOTS) {
-        qxl_set_guest_bug(d, "%s: slot_id >= NUM_MEMSLOTS %d >= %d", __func__,
-                      slot_id, NUM_MEMSLOTS);
-        return 1;
-    }
-    if (guest_start > guest_end) {
-        qxl_set_guest_bug(d, "%s: guest_start > guest_end 0x%" PRIx64
-                         " > 0x%" PRIx64, __func__, guest_start, guest_end);
-        return 1;
-    }
-
-    for (i = 0; i < ARRAY_SIZE(regions); i++) {
-        pci_region = regions[i];
-        pci_start = d->pci.io_regions[pci_region].addr;
-        pci_end = pci_start + d->pci.io_regions[pci_region].size;
-        /* mapped? */
-        if (pci_start == -1) {
-            continue;
-        }
-        /* start address in range ? */
-        if (guest_start < pci_start || guest_start > pci_end) {
-            continue;
-        }
-        /* end address in range ? */
-        if (guest_end > pci_end) {
-            continue;
-        }
-        /* passed */
-        break;
-    }
-    if (i == ARRAY_SIZE(regions)) {
-        qxl_set_guest_bug(d, "%s: finished loop without match", __func__);
-        return 1;
-    }
-
-    switch (pci_region) {
-    case QXL_RAM_RANGE_INDEX:
-        virt_start = (intptr_t)memory_region_get_ram_ptr(&d->vga.vram);
-        break;
-    case QXL_VRAM_RANGE_INDEX:
-    case 4 /* vram 64bit */:
-        virt_start = (intptr_t)memory_region_get_ram_ptr(&d->vram_bar);
-        break;
-    default:
-        /* should not happen */
-        qxl_set_guest_bug(d, "%s: pci_region = %d", __func__, pci_region);
-        return 1;
-    }
-
-    memslot.slot_id = slot_id;
-    memslot.slot_group_id = MEMSLOT_GROUP_GUEST; /* guest group */
-    memslot.virt_start = virt_start + (guest_start - pci_start);
-    memslot.virt_end   = virt_start + (guest_end   - pci_start);
-    memslot.addr_delta = memslot.virt_start - delta;
-    memslot.generation = d->rom->slot_generation = 0;
-    qxl_rom_set_dirty(d);
-
-    qemu_spice_add_memslot(&d->ssd, &memslot, async);
-    d->guest_slots[slot_id].ptr = (void*)memslot.virt_start;
-    d->guest_slots[slot_id].size = memslot.virt_end - memslot.virt_start;
-    d->guest_slots[slot_id].delta = delta;
-    d->guest_slots[slot_id].active = 1;
-    return 0;
-}
-
-static void qxl_del_memslot(PCIQXLDevice *d, uint32_t slot_id)
-{
-    qemu_spice_del_memslot(&d->ssd, MEMSLOT_GROUP_HOST, slot_id);
-    d->guest_slots[slot_id].active = 0;
-}
-
-static void qxl_reset_memslots(PCIQXLDevice *d)
-{
-    qxl_spice_reset_memslots(d);
-    memset(&d->guest_slots, 0, sizeof(d->guest_slots));
-}
-
-static void qxl_reset_surfaces(PCIQXLDevice *d)
-{
-    trace_qxl_reset_surfaces(d->id);
-    d->mode = QXL_MODE_UNDEFINED;
-    qxl_spice_destroy_surfaces(d, QXL_SYNC);
-}
-
-/* can be also called from spice server thread context */
-void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, int group_id)
-{
-    uint64_t phys   = le64_to_cpu(pqxl);
-    uint32_t slot   = (phys >> (64 -  8)) & 0xff;
-    uint64_t offset = phys & 0xffffffffffff;
-
-    switch (group_id) {
-    case MEMSLOT_GROUP_HOST:
-        return (void *)(intptr_t)offset;
-    case MEMSLOT_GROUP_GUEST:
-        if (slot >= NUM_MEMSLOTS) {
-            qxl_set_guest_bug(qxl, "slot too large %d >= %d", slot,
-                              NUM_MEMSLOTS);
-            return NULL;
-        }
-        if (!qxl->guest_slots[slot].active) {
-            qxl_set_guest_bug(qxl, "inactive slot %d\n", slot);
-            return NULL;
-        }
-        if (offset < qxl->guest_slots[slot].delta) {
-            qxl_set_guest_bug(qxl,
-                          "slot %d offset %"PRIu64" < delta %"PRIu64"\n",
-                          slot, offset, qxl->guest_slots[slot].delta);
-            return NULL;
-        }
-        offset -= qxl->guest_slots[slot].delta;
-        if (offset > qxl->guest_slots[slot].size) {
-            qxl_set_guest_bug(qxl,
-                          "slot %d offset %"PRIu64" > size %"PRIu64"\n",
-                          slot, offset, qxl->guest_slots[slot].size);
-            return NULL;
-        }
-        return qxl->guest_slots[slot].ptr + offset;
-    }
-    return NULL;
-}
-
-static void qxl_create_guest_primary_complete(PCIQXLDevice *qxl)
-{
-    /* for local rendering */
-    qxl_render_resize(qxl);
-}
-
-static void qxl_create_guest_primary(PCIQXLDevice *qxl, int loadvm,
-                                     qxl_async_io async)
-{
-    QXLDevSurfaceCreate surface;
-    QXLSurfaceCreate *sc = &qxl->guest_primary.surface;
-    int size;
-    int requested_height = le32_to_cpu(sc->height);
-    int requested_stride = le32_to_cpu(sc->stride);
-
-    size = abs(requested_stride) * requested_height;
-    if (size > qxl->vgamem_size) {
-        qxl_set_guest_bug(qxl, "%s: requested primary larger then framebuffer"
-                               " size", __func__);
-        return;
-    }
-
-    if (qxl->mode == QXL_MODE_NATIVE) {
-        qxl_set_guest_bug(qxl, "%s: nop since already in QXL_MODE_NATIVE",
-                      __func__);
-    }
-    qxl_exit_vga_mode(qxl);
-
-    surface.format     = le32_to_cpu(sc->format);
-    surface.height     = le32_to_cpu(sc->height);
-    surface.mem        = le64_to_cpu(sc->mem);
-    surface.position   = le32_to_cpu(sc->position);
-    surface.stride     = le32_to_cpu(sc->stride);
-    surface.width      = le32_to_cpu(sc->width);
-    surface.type       = le32_to_cpu(sc->type);
-    surface.flags      = le32_to_cpu(sc->flags);
-    trace_qxl_create_guest_primary(qxl->id, sc->width, sc->height, sc->mem,
-                                   sc->format, sc->position);
-    trace_qxl_create_guest_primary_rest(qxl->id, sc->stride, sc->type,
-                                        sc->flags);
-
-    if ((surface.stride & 0x3) != 0) {
-        qxl_set_guest_bug(qxl, "primary surface stride = %d %% 4 != 0",
-                          surface.stride);
-        return;
-    }
-
-    surface.mouse_mode = true;
-    surface.group_id   = MEMSLOT_GROUP_GUEST;
-    if (loadvm) {
-        surface.flags |= QXL_SURF_FLAG_KEEP_DATA;
-    }
-
-    qxl->mode = QXL_MODE_NATIVE;
-    qxl->cmdflags = 0;
-    qemu_spice_create_primary_surface(&qxl->ssd, 0, &surface, async);
-
-    if (async == QXL_SYNC) {
-        qxl_create_guest_primary_complete(qxl);
-    }
-}
-
-/* return 1 if surface destoy was initiated (in QXL_ASYNC case) or
- * done (in QXL_SYNC case), 0 otherwise. */
-static int qxl_destroy_primary(PCIQXLDevice *d, qxl_async_io async)
-{
-    if (d->mode == QXL_MODE_UNDEFINED) {
-        return 0;
-    }
-    trace_qxl_destroy_primary(d->id);
-    d->mode = QXL_MODE_UNDEFINED;
-    qemu_spice_destroy_primary_surface(&d->ssd, 0, async);
-    qxl_spice_reset_cursor(d);
-    return 1;
-}
-
-static void qxl_set_mode(PCIQXLDevice *d, int modenr, int loadvm)
-{
-    pcibus_t start = d->pci.io_regions[QXL_RAM_RANGE_INDEX].addr;
-    pcibus_t end   = d->pci.io_regions[QXL_RAM_RANGE_INDEX].size + start;
-    QXLMode *mode = d->modes->modes + modenr;
-    uint64_t devmem = d->pci.io_regions[QXL_RAM_RANGE_INDEX].addr;
-    QXLMemSlot slot = {
-        .mem_start = start,
-        .mem_end = end
-    };
-    QXLSurfaceCreate surface = {
-        .width      = mode->x_res,
-        .height     = mode->y_res,
-        .stride     = -mode->x_res * 4,
-        .format     = SPICE_SURFACE_FMT_32_xRGB,
-        .flags      = loadvm ? QXL_SURF_FLAG_KEEP_DATA : 0,
-        .mouse_mode = true,
-        .mem        = devmem + d->shadow_rom.draw_area_offset,
-    };
-
-    trace_qxl_set_mode(d->id, modenr, mode->x_res, mode->y_res, mode->bits,
-                       devmem);
-    if (!loadvm) {
-        qxl_hard_reset(d, 0);
-    }
-
-    d->guest_slots[0].slot = slot;
-    assert(qxl_add_memslot(d, 0, devmem, QXL_SYNC) == 0);
-
-    d->guest_primary.surface = surface;
-    qxl_create_guest_primary(d, 0, QXL_SYNC);
-
-    d->mode = QXL_MODE_COMPAT;
-    d->cmdflags = QXL_COMMAND_FLAG_COMPAT;
-    if (mode->bits == 16) {
-        d->cmdflags |= QXL_COMMAND_FLAG_COMPAT_16BPP;
-    }
-    d->shadow_rom.mode = cpu_to_le32(modenr);
-    d->rom->mode = cpu_to_le32(modenr);
-    qxl_rom_set_dirty(d);
-}
-
-static void ioport_write(void *opaque, hwaddr addr,
-                         uint64_t val, unsigned size)
-{
-    PCIQXLDevice *d = opaque;
-    uint32_t io_port = addr;
-    qxl_async_io async = QXL_SYNC;
-    uint32_t orig_io_port = io_port;
-
-    if (d->guest_bug && io_port != QXL_IO_RESET) {
-        return;
-    }
-
-    if (d->revision <= QXL_REVISION_STABLE_V10 &&
-        io_port > QXL_IO_FLUSH_RELEASE) {
-        qxl_set_guest_bug(d, "unsupported io %d for revision %d\n",
-            io_port, d->revision);
-        return;
-    }
-
-    switch (io_port) {
-    case QXL_IO_RESET:
-    case QXL_IO_SET_MODE:
-    case QXL_IO_MEMSLOT_ADD:
-    case QXL_IO_MEMSLOT_DEL:
-    case QXL_IO_CREATE_PRIMARY:
-    case QXL_IO_UPDATE_IRQ:
-    case QXL_IO_LOG:
-    case QXL_IO_MEMSLOT_ADD_ASYNC:
-    case QXL_IO_CREATE_PRIMARY_ASYNC:
-        break;
-    default:
-        if (d->mode != QXL_MODE_VGA) {
-            break;
-        }
-        trace_qxl_io_unexpected_vga_mode(d->id,
-            addr, val, io_port_to_string(io_port));
-        /* be nice to buggy guest drivers */
-        if (io_port >= QXL_IO_UPDATE_AREA_ASYNC &&
-            io_port < QXL_IO_RANGE_SIZE) {
-            qxl_send_events(d, QXL_INTERRUPT_IO_CMD);
-        }
-        return;
-    }
-
-    /* we change the io_port to avoid ifdeffery in the main switch */
-    orig_io_port = io_port;
-    switch (io_port) {
-    case QXL_IO_UPDATE_AREA_ASYNC:
-        io_port = QXL_IO_UPDATE_AREA;
-        goto async_common;
-    case QXL_IO_MEMSLOT_ADD_ASYNC:
-        io_port = QXL_IO_MEMSLOT_ADD;
-        goto async_common;
-    case QXL_IO_CREATE_PRIMARY_ASYNC:
-        io_port = QXL_IO_CREATE_PRIMARY;
-        goto async_common;
-    case QXL_IO_DESTROY_PRIMARY_ASYNC:
-        io_port = QXL_IO_DESTROY_PRIMARY;
-        goto async_common;
-    case QXL_IO_DESTROY_SURFACE_ASYNC:
-        io_port = QXL_IO_DESTROY_SURFACE_WAIT;
-        goto async_common;
-    case QXL_IO_DESTROY_ALL_SURFACES_ASYNC:
-        io_port = QXL_IO_DESTROY_ALL_SURFACES;
-        goto async_common;
-    case QXL_IO_FLUSH_SURFACES_ASYNC:
-    case QXL_IO_MONITORS_CONFIG_ASYNC:
-async_common:
-        async = QXL_ASYNC;
-        qemu_mutex_lock(&d->async_lock);
-        if (d->current_async != QXL_UNDEFINED_IO) {
-            qxl_set_guest_bug(d, "%d async started before last (%d) complete",
-                io_port, d->current_async);
-            qemu_mutex_unlock(&d->async_lock);
-            return;
-        }
-        d->current_async = orig_io_port;
-        qemu_mutex_unlock(&d->async_lock);
-        break;
-    default:
-        break;
-    }
-    trace_qxl_io_write(d->id, qxl_mode_to_string(d->mode), addr, val, size,
-                       async);
-
-    switch (io_port) {
-    case QXL_IO_UPDATE_AREA:
-    {
-        QXLCookie *cookie = NULL;
-        QXLRect update = d->ram->update_area;
-
-        if (d->ram->update_surface > d->ssd.num_surfaces) {
-            qxl_set_guest_bug(d, "QXL_IO_UPDATE_AREA: invalid surface id %d\n",
-                              d->ram->update_surface);
-            break;
-        }
-        if (update.left >= update.right || update.top >= update.bottom ||
-            update.left < 0 || update.top < 0) {
-            qxl_set_guest_bug(d,
-                    "QXL_IO_UPDATE_AREA: invalid area (%ux%u)x(%ux%u)\n",
-                    update.left, update.top, update.right, update.bottom);
-            break;
-        }
-        if (async == QXL_ASYNC) {
-            cookie = qxl_cookie_new(QXL_COOKIE_TYPE_IO,
-                                    QXL_IO_UPDATE_AREA_ASYNC);
-            cookie->u.area = update;
-        }
-        qxl_spice_update_area(d, d->ram->update_surface,
-                              cookie ? &cookie->u.area : &update,
-                              NULL, 0, 0, async, cookie);
-        break;
-    }
-    case QXL_IO_NOTIFY_CMD:
-        qemu_spice_wakeup(&d->ssd);
-        break;
-    case QXL_IO_NOTIFY_CURSOR:
-        qemu_spice_wakeup(&d->ssd);
-        break;
-    case QXL_IO_UPDATE_IRQ:
-        qxl_update_irq(d);
-        break;
-    case QXL_IO_NOTIFY_OOM:
-        if (!SPICE_RING_IS_EMPTY(&d->ram->release_ring)) {
-            break;
-        }
-        d->oom_running = 1;
-        qxl_spice_oom(d);
-        d->oom_running = 0;
-        break;
-    case QXL_IO_SET_MODE:
-        qxl_set_mode(d, val, 0);
-        break;
-    case QXL_IO_LOG:
-        trace_qxl_io_log(d->id, d->ram->log_buf);
-        if (d->guestdebug) {
-            fprintf(stderr, "qxl/guest-%d: %" PRId64 ": %s", d->id,
-                    qemu_get_clock_ns(vm_clock), d->ram->log_buf);
-        }
-        break;
-    case QXL_IO_RESET:
-        qxl_hard_reset(d, 0);
-        break;
-    case QXL_IO_MEMSLOT_ADD:
-        if (val >= NUM_MEMSLOTS) {
-            qxl_set_guest_bug(d, "QXL_IO_MEMSLOT_ADD: val out of range");
-            break;
-        }
-        if (d->guest_slots[val].active) {
-            qxl_set_guest_bug(d,
-                        "QXL_IO_MEMSLOT_ADD: memory slot already active");
-            break;
-        }
-        d->guest_slots[val].slot = d->ram->mem_slot;
-        qxl_add_memslot(d, val, 0, async);
-        break;
-    case QXL_IO_MEMSLOT_DEL:
-        if (val >= NUM_MEMSLOTS) {
-            qxl_set_guest_bug(d, "QXL_IO_MEMSLOT_DEL: val out of range");
-            break;
-        }
-        qxl_del_memslot(d, val);
-        break;
-    case QXL_IO_CREATE_PRIMARY:
-        if (val != 0) {
-            qxl_set_guest_bug(d, "QXL_IO_CREATE_PRIMARY (async=%d): val != 0",
-                          async);
-            goto cancel_async;
-        }
-        d->guest_primary.surface = d->ram->create_surface;
-        qxl_create_guest_primary(d, 0, async);
-        break;
-    case QXL_IO_DESTROY_PRIMARY:
-        if (val != 0) {
-            qxl_set_guest_bug(d, "QXL_IO_DESTROY_PRIMARY (async=%d): val != 0",
-                          async);
-            goto cancel_async;
-        }
-        if (!qxl_destroy_primary(d, async)) {
-            trace_qxl_io_destroy_primary_ignored(d->id,
-                                                 qxl_mode_to_string(d->mode));
-            goto cancel_async;
-        }
-        break;
-    case QXL_IO_DESTROY_SURFACE_WAIT:
-        if (val >= d->ssd.num_surfaces) {
-            qxl_set_guest_bug(d, "QXL_IO_DESTROY_SURFACE (async=%d):"
-                             "%" PRIu64 " >= NUM_SURFACES", async, val);
-            goto cancel_async;
-        }
-        qxl_spice_destroy_surface_wait(d, val, async);
-        break;
-    case QXL_IO_FLUSH_RELEASE: {
-        QXLReleaseRing *ring = &d->ram->release_ring;
-        if (ring->prod - ring->cons + 1 == ring->num_items) {
-            fprintf(stderr,
-                "ERROR: no flush, full release ring [p%d,%dc]\n",
-                ring->prod, ring->cons);
-        }
-        qxl_push_free_res(d, 1 /* flush */);
-        break;
-    }
-    case QXL_IO_FLUSH_SURFACES_ASYNC:
-        qxl_spice_flush_surfaces_async(d);
-        break;
-    case QXL_IO_DESTROY_ALL_SURFACES:
-        d->mode = QXL_MODE_UNDEFINED;
-        qxl_spice_destroy_surfaces(d, async);
-        break;
-    case QXL_IO_MONITORS_CONFIG_ASYNC:
-        qxl_spice_monitors_config_async(d, 0);
-        break;
-    default:
-        qxl_set_guest_bug(d, "%s: unexpected ioport=0x%x\n", __func__, io_port);
-    }
-    return;
-cancel_async:
-    if (async) {
-        qxl_send_events(d, QXL_INTERRUPT_IO_CMD);
-        qemu_mutex_lock(&d->async_lock);
-        d->current_async = QXL_UNDEFINED_IO;
-        qemu_mutex_unlock(&d->async_lock);
-    }
-}
-
-static uint64_t ioport_read(void *opaque, hwaddr addr,
-                            unsigned size)
-{
-    PCIQXLDevice *qxl = opaque;
-
-    trace_qxl_io_read_unexpected(qxl->id);
-    return 0xff;
-}
-
-static const MemoryRegionOps qxl_io_ops = {
-    .read = ioport_read,
-    .write = ioport_write,
-    .valid = {
-        .min_access_size = 1,
-        .max_access_size = 1,
-    },
-};
-
-static void pipe_read(void *opaque)
-{
-    PCIQXLDevice *d = opaque;
-    char dummy;
-    int len;
-
-    do {
-        len = read(d->pipe[0], &dummy, sizeof(dummy));
-    } while (len == sizeof(dummy));
-    qxl_update_irq(d);
-}
-
-static void qxl_send_events(PCIQXLDevice *d, uint32_t events)
-{
-    uint32_t old_pending;
-    uint32_t le_events = cpu_to_le32(events);
-
-    trace_qxl_send_events(d->id, events);
-    if (!qemu_spice_display_is_running(&d->ssd)) {
-        /* spice-server tracks guest running state and should not do this */
-        fprintf(stderr, "%s: spice-server bug: guest stopped, ignoring\n",
-                __func__);
-        trace_qxl_send_events_vm_stopped(d->id, events);
-        return;
-    }
-    old_pending = __sync_fetch_and_or(&d->ram->int_pending, le_events);
-    if ((old_pending & le_events) == le_events) {
-        return;
-    }
-    if (qemu_thread_is_self(&d->main)) {
-        qxl_update_irq(d);
-    } else {
-        if (write(d->pipe[1], d, 1) != 1) {
-            dprint(d, 1, "%s: write to pipe failed\n", __func__);
-        }
-    }
-}
-
-static void init_pipe_signaling(PCIQXLDevice *d)
-{
-    if (pipe(d->pipe) < 0) {
-        fprintf(stderr, "%s:%s: qxl pipe creation failed\n",
-                __FILE__, __func__);
-        exit(1);
-    }
-    fcntl(d->pipe[0], F_SETFL, O_NONBLOCK);
-    fcntl(d->pipe[1], F_SETFL, O_NONBLOCK);
-    fcntl(d->pipe[0], F_SETOWN, getpid());
-
-    qemu_thread_get_self(&d->main);
-    qemu_set_fd_handler(d->pipe[0], pipe_read, NULL, d);
-}
-
-/* graphics console */
-
-static void qxl_hw_update(void *opaque)
-{
-    PCIQXLDevice *qxl = opaque;
-    VGACommonState *vga = &qxl->vga;
-
-    switch (qxl->mode) {
-    case QXL_MODE_VGA:
-        vga->update(vga);
-        break;
-    case QXL_MODE_COMPAT:
-    case QXL_MODE_NATIVE:
-        qxl_render_update(qxl);
-        break;
-    default:
-        break;
-    }
-}
-
-static void qxl_hw_invalidate(void *opaque)
-{
-    PCIQXLDevice *qxl = opaque;
-    VGACommonState *vga = &qxl->vga;
-
-    vga->invalidate(vga);
-}
-
-static void qxl_hw_screen_dump(void *opaque, const char *filename, bool cswitch,
-                               Error **errp)
-{
-    PCIQXLDevice *qxl = opaque;
-    VGACommonState *vga = &qxl->vga;
-
-    switch (qxl->mode) {
-    case QXL_MODE_COMPAT:
-    case QXL_MODE_NATIVE:
-        qxl_render_update(qxl);
-        ppm_save(filename, qxl->ssd.ds, errp);
-        break;
-    case QXL_MODE_VGA:
-        vga->screen_dump(vga, filename, cswitch, errp);
-        break;
-    default:
-        break;
-    }
-}
-
-static void qxl_hw_text_update(void *opaque, console_ch_t *chardata)
-{
-    PCIQXLDevice *qxl = opaque;
-    VGACommonState *vga = &qxl->vga;
-
-    if (qxl->mode == QXL_MODE_VGA) {
-        vga->text_update(vga, chardata);
-        return;
-    }
-}
-
-static void qxl_dirty_surfaces(PCIQXLDevice *qxl)
-{
-    uintptr_t vram_start;
-    int i;
-
-    if (qxl->mode != QXL_MODE_NATIVE && qxl->mode != QXL_MODE_COMPAT) {
-        return;
-    }
-
-    /* dirty the primary surface */
-    qxl_set_dirty(&qxl->vga.vram, qxl->shadow_rom.draw_area_offset,
-                  qxl->shadow_rom.surface0_area_size);
-
-    vram_start = (uintptr_t)memory_region_get_ram_ptr(&qxl->vram_bar);
-
-    /* dirty the off-screen surfaces */
-    for (i = 0; i < qxl->ssd.num_surfaces; i++) {
-        QXLSurfaceCmd *cmd;
-        intptr_t surface_offset;
-        int surface_size;
-
-        if (qxl->guest_surfaces.cmds[i] == 0) {
-            continue;
-        }
-
-        cmd = qxl_phys2virt(qxl, qxl->guest_surfaces.cmds[i],
-                            MEMSLOT_GROUP_GUEST);
-        assert(cmd);
-        assert(cmd->type == QXL_SURFACE_CMD_CREATE);
-        surface_offset = (intptr_t)qxl_phys2virt(qxl,
-                                                 cmd->u.surface_create.data,
-                                                 MEMSLOT_GROUP_GUEST);
-        assert(surface_offset);
-        surface_offset -= vram_start;
-        surface_size = cmd->u.surface_create.height *
-                       abs(cmd->u.surface_create.stride);
-        trace_qxl_surfaces_dirty(qxl->id, i, (int)surface_offset, surface_size);
-        qxl_set_dirty(&qxl->vram_bar, surface_offset, surface_size);
-    }
-}
-
-static void qxl_vm_change_state_handler(void *opaque, int running,
-                                        RunState state)
-{
-    PCIQXLDevice *qxl = opaque;
-
-    if (running) {
-        /*
-         * if qxl_send_events was called from spice server context before
-         * migration ended, qxl_update_irq for these events might not have been
-         * called
-         */
-         qxl_update_irq(qxl);
-    } else {
-        /* make sure surfaces are saved before migration */
-        qxl_dirty_surfaces(qxl);
-    }
-}
-
-/* display change listener */
-
-static void display_update(DisplayChangeListener *dcl,
-                           int x, int y, int w, int h)
-{
-    PCIQXLDevice *qxl = container_of(dcl, PCIQXLDevice, ssd.dcl);
-
-    if (qxl->mode == QXL_MODE_VGA) {
-        qemu_spice_display_update(&qxl->ssd, x, y, w, h);
-    }
-}
-
-static void display_switch(DisplayChangeListener *dcl,
-                           struct DisplaySurface *surface)
-{
-    PCIQXLDevice *qxl = container_of(dcl, PCIQXLDevice, ssd.dcl);
-
-    qxl->ssd.ds = surface;
-    if (qxl->mode == QXL_MODE_VGA) {
-        qemu_spice_display_switch(&qxl->ssd, surface);
-    }
-}
-
-static void display_refresh(DisplayChangeListener *dcl)
-{
-    PCIQXLDevice *qxl = container_of(dcl, PCIQXLDevice, ssd.dcl);
-
-    if (qxl->mode == QXL_MODE_VGA) {
-        qemu_spice_display_refresh(&qxl->ssd);
-    } else {
-        qemu_mutex_lock(&qxl->ssd.lock);
-        qemu_spice_cursor_refresh_unlocked(&qxl->ssd);
-        qemu_mutex_unlock(&qxl->ssd.lock);
-    }
-}
-
-static DisplayChangeListenerOps display_listener_ops = {
-    .dpy_name        = "spice/qxl",
-    .dpy_gfx_update  = display_update,
-    .dpy_gfx_switch  = display_switch,
-    .dpy_refresh     = display_refresh,
-};
-
-static void qxl_init_ramsize(PCIQXLDevice *qxl)
-{
-    /* vga mode framebuffer / primary surface (bar 0, first part) */
-    if (qxl->vgamem_size_mb < 8) {
-        qxl->vgamem_size_mb = 8;
-    }
-    qxl->vgamem_size = qxl->vgamem_size_mb * 1024 * 1024;
-
-    /* vga ram (bar 0, total) */
-    if (qxl->ram_size_mb != -1) {
-        qxl->vga.vram_size = qxl->ram_size_mb * 1024 * 1024;
-    }
-    if (qxl->vga.vram_size < qxl->vgamem_size * 2) {
-        qxl->vga.vram_size = qxl->vgamem_size * 2;
-    }
-
-    /* vram32 (surfaces, 32bit, bar 1) */
-    if (qxl->vram32_size_mb != -1) {
-        qxl->vram32_size = qxl->vram32_size_mb * 1024 * 1024;
-    }
-    if (qxl->vram32_size < 4096) {
-        qxl->vram32_size = 4096;
-    }
-
-    /* vram (surfaces, 64bit, bar 4+5) */
-    if (qxl->vram_size_mb != -1) {
-        qxl->vram_size = qxl->vram_size_mb * 1024 * 1024;
-    }
-    if (qxl->vram_size < qxl->vram32_size) {
-        qxl->vram_size = qxl->vram32_size;
-    }
-
-    if (qxl->revision == 1) {
-        qxl->vram32_size = 4096;
-        qxl->vram_size = 4096;
-    }
-    qxl->vgamem_size = msb_mask(qxl->vgamem_size * 2 - 1);
-    qxl->vga.vram_size = msb_mask(qxl->vga.vram_size * 2 - 1);
-    qxl->vram32_size = msb_mask(qxl->vram32_size * 2 - 1);
-    qxl->vram_size = msb_mask(qxl->vram_size * 2 - 1);
-}
-
-static int qxl_init_common(PCIQXLDevice *qxl)
-{
-    uint8_t* config = qxl->pci.config;
-    uint32_t pci_device_rev;
-    uint32_t io_size;
-
-    qxl->mode = QXL_MODE_UNDEFINED;
-    qxl->generation = 1;
-    qxl->num_memslots = NUM_MEMSLOTS;
-    qemu_mutex_init(&qxl->track_lock);
-    qemu_mutex_init(&qxl->async_lock);
-    qxl->current_async = QXL_UNDEFINED_IO;
-    qxl->guest_bug = 0;
-
-    switch (qxl->revision) {
-    case 1: /* spice 0.4 -- qxl-1 */
-        pci_device_rev = QXL_REVISION_STABLE_V04;
-        io_size = 8;
-        break;
-    case 2: /* spice 0.6 -- qxl-2 */
-        pci_device_rev = QXL_REVISION_STABLE_V06;
-        io_size = 16;
-        break;
-    case 3: /* qxl-3 */
-        pci_device_rev = QXL_REVISION_STABLE_V10;
-        io_size = 32; /* PCI region size must be pow2 */
-        break;
-    case 4: /* qxl-4 */
-        pci_device_rev = QXL_REVISION_STABLE_V12;
-        io_size = msb_mask(QXL_IO_RANGE_SIZE * 2 - 1);
-        break;
-    default:
-        error_report("Invalid revision %d for qxl device (max %d)",
-                     qxl->revision, QXL_DEFAULT_REVISION);
-        return -1;
-    }
-
-    pci_set_byte(&config[PCI_REVISION_ID], pci_device_rev);
-    pci_set_byte(&config[PCI_INTERRUPT_PIN], 1);
-
-    qxl->rom_size = qxl_rom_size();
-    memory_region_init_ram(&qxl->rom_bar, "qxl.vrom", qxl->rom_size);
-    vmstate_register_ram(&qxl->rom_bar, &qxl->pci.qdev);
-    init_qxl_rom(qxl);
-    init_qxl_ram(qxl);
-
-    qxl->guest_surfaces.cmds = g_new0(QXLPHYSICAL, qxl->ssd.num_surfaces);
-    memory_region_init_ram(&qxl->vram_bar, "qxl.vram", qxl->vram_size);
-    vmstate_register_ram(&qxl->vram_bar, &qxl->pci.qdev);
-    memory_region_init_alias(&qxl->vram32_bar, "qxl.vram32", &qxl->vram_bar,
-                             0, qxl->vram32_size);
-
-    memory_region_init_io(&qxl->io_bar, &qxl_io_ops, qxl,
-                          "qxl-ioports", io_size);
-    if (qxl->id == 0) {
-        vga_dirty_log_start(&qxl->vga);
-    }
-    memory_region_set_flush_coalesced(&qxl->io_bar);
-
-
-    pci_register_bar(&qxl->pci, QXL_IO_RANGE_INDEX,
-                     PCI_BASE_ADDRESS_SPACE_IO, &qxl->io_bar);
-
-    pci_register_bar(&qxl->pci, QXL_ROM_RANGE_INDEX,
-                     PCI_BASE_ADDRESS_SPACE_MEMORY, &qxl->rom_bar);
-
-    pci_register_bar(&qxl->pci, QXL_RAM_RANGE_INDEX,
-                     PCI_BASE_ADDRESS_SPACE_MEMORY, &qxl->vga.vram);
-
-    pci_register_bar(&qxl->pci, QXL_VRAM_RANGE_INDEX,
-                     PCI_BASE_ADDRESS_SPACE_MEMORY, &qxl->vram32_bar);
-
-    if (qxl->vram32_size < qxl->vram_size) {
-        /*
-         * Make the 64bit vram bar show up only in case it is
-         * configured to be larger than the 32bit vram bar.
-         */
-        pci_register_bar(&qxl->pci, QXL_VRAM64_RANGE_INDEX,
-                         PCI_BASE_ADDRESS_SPACE_MEMORY |
-                         PCI_BASE_ADDRESS_MEM_TYPE_64 |
-                         PCI_BASE_ADDRESS_MEM_PREFETCH,
-                         &qxl->vram_bar);
-    }
-
-    /* print pci bar details */
-    dprint(qxl, 1, "ram/%s: %d MB [region 0]\n",
-           qxl->id == 0 ? "pri" : "sec",
-           qxl->vga.vram_size / (1024*1024));
-    dprint(qxl, 1, "vram/32: %d MB [region 1]\n",
-           qxl->vram32_size / (1024*1024));
-    dprint(qxl, 1, "vram/64: %d MB %s\n",
-           qxl->vram_size / (1024*1024),
-           qxl->vram32_size < qxl->vram_size ? "[region 4]" : "[unmapped]");
-
-    qxl->ssd.qxl.base.sif = &qxl_interface.base;
-    qxl->ssd.qxl.id = qxl->id;
-    if (qemu_spice_add_interface(&qxl->ssd.qxl.base) != 0) {
-        error_report("qxl interface %d.%d not supported by spice-server",
-                     SPICE_INTERFACE_QXL_MAJOR, SPICE_INTERFACE_QXL_MINOR);
-        return -1;
-    }
-    qemu_add_vm_change_state_handler(qxl_vm_change_state_handler, qxl);
-
-    init_pipe_signaling(qxl);
-    qxl_reset_state(qxl);
-
-    qxl->update_area_bh = qemu_bh_new(qxl_render_update_area_bh, qxl);
-
-    return 0;
-}
-
-static int qxl_init_primary(PCIDevice *dev)
-{
-    PCIQXLDevice *qxl = DO_UPCAST(PCIQXLDevice, pci, dev);
-    VGACommonState *vga = &qxl->vga;
-    PortioList *qxl_vga_port_list = g_new(PortioList, 1);
-    DisplayState *ds;
-    int rc;
-
-    qxl->id = 0;
-    qxl_init_ramsize(qxl);
-    vga->vram_size_mb = qxl->vga.vram_size >> 20;
-    vga_common_init(vga);
-    vga_init(vga, pci_address_space(dev), pci_address_space_io(dev), false);
-    portio_list_init(qxl_vga_port_list, qxl_vga_portio_list, vga, "vga");
-    portio_list_add(qxl_vga_port_list, pci_address_space_io(dev), 0x3b0);
-
-    vga->con = graphic_console_init(qxl_hw_update, qxl_hw_invalidate,
-                                    qxl_hw_screen_dump, qxl_hw_text_update,
-                                    qxl);
-    qxl->ssd.con = vga->con,
-    qemu_spice_display_init_common(&qxl->ssd);
-
-    rc = qxl_init_common(qxl);
-    if (rc != 0) {
-        return rc;
-    }
-
-    qxl->ssd.dcl.ops = &display_listener_ops;
-    ds = qemu_console_displaystate(vga->con);
-    register_displaychangelistener(ds, &qxl->ssd.dcl);
-    return rc;
-}
-
-static int qxl_init_secondary(PCIDevice *dev)
-{
-    static int device_id = 1;
-    PCIQXLDevice *qxl = DO_UPCAST(PCIQXLDevice, pci, dev);
-
-    qxl->id = device_id++;
-    qxl_init_ramsize(qxl);
-    memory_region_init_ram(&qxl->vga.vram, "qxl.vgavram", qxl->vga.vram_size);
-    vmstate_register_ram(&qxl->vga.vram, &qxl->pci.qdev);
-    qxl->vga.vram_ptr = memory_region_get_ram_ptr(&qxl->vga.vram);
-
-    return qxl_init_common(qxl);
-}
-
-static void qxl_pre_save(void *opaque)
-{
-    PCIQXLDevice* d = opaque;
-    uint8_t *ram_start = d->vga.vram_ptr;
-
-    trace_qxl_pre_save(d->id);
-    if (d->last_release == NULL) {
-        d->last_release_offset = 0;
-    } else {
-        d->last_release_offset = (uint8_t *)d->last_release - ram_start;
-    }
-    assert(d->last_release_offset < d->vga.vram_size);
-}
-
-static int qxl_pre_load(void *opaque)
-{
-    PCIQXLDevice* d = opaque;
-
-    trace_qxl_pre_load(d->id);
-    qxl_hard_reset(d, 1);
-    qxl_exit_vga_mode(d);
-    return 0;
-}
-
-static void qxl_create_memslots(PCIQXLDevice *d)
-{
-    int i;
-
-    for (i = 0; i < NUM_MEMSLOTS; i++) {
-        if (!d->guest_slots[i].active) {
-            continue;
-        }
-        qxl_add_memslot(d, i, 0, QXL_SYNC);
-    }
-}
-
-static int qxl_post_load(void *opaque, int version)
-{
-    PCIQXLDevice* d = opaque;
-    uint8_t *ram_start = d->vga.vram_ptr;
-    QXLCommandExt *cmds;
-    int in, out, newmode;
-
-    assert(d->last_release_offset < d->vga.vram_size);
-    if (d->last_release_offset == 0) {
-        d->last_release = NULL;
-    } else {
-        d->last_release = (QXLReleaseInfo *)(ram_start + d->last_release_offset);
-    }
-
-    d->modes = (QXLModes*)((uint8_t*)d->rom + d->rom->modes_offset);
-
-    trace_qxl_post_load(d->id, qxl_mode_to_string(d->mode));
-    newmode = d->mode;
-    d->mode = QXL_MODE_UNDEFINED;
-
-    switch (newmode) {
-    case QXL_MODE_UNDEFINED:
-        qxl_create_memslots(d);
-        break;
-    case QXL_MODE_VGA:
-        qxl_create_memslots(d);
-        qxl_enter_vga_mode(d);
-        break;
-    case QXL_MODE_NATIVE:
-        qxl_create_memslots(d);
-        qxl_create_guest_primary(d, 1, QXL_SYNC);
-
-        /* replay surface-create and cursor-set commands */
-        cmds = g_malloc0(sizeof(QXLCommandExt) * (d->ssd.num_surfaces + 1));
-        for (in = 0, out = 0; in < d->ssd.num_surfaces; in++) {
-            if (d->guest_surfaces.cmds[in] == 0) {
-                continue;
-            }
-            cmds[out].cmd.data = d->guest_surfaces.cmds[in];
-            cmds[out].cmd.type = QXL_CMD_SURFACE;
-            cmds[out].group_id = MEMSLOT_GROUP_GUEST;
-            out++;
-        }
-        if (d->guest_cursor) {
-            cmds[out].cmd.data = d->guest_cursor;
-            cmds[out].cmd.type = QXL_CMD_CURSOR;
-            cmds[out].group_id = MEMSLOT_GROUP_GUEST;
-            out++;
-        }
-        qxl_spice_loadvm_commands(d, cmds, out);
-        g_free(cmds);
-        if (d->guest_monitors_config) {
-            qxl_spice_monitors_config_async(d, 1);
-        }
-        break;
-    case QXL_MODE_COMPAT:
-        /* note: no need to call qxl_create_memslots, qxl_set_mode
-         * creates the mem slot. */
-        qxl_set_mode(d, d->shadow_rom.mode, 1);
-        break;
-    }
-    return 0;
-}
-
-#define QXL_SAVE_VERSION 21
-
-static bool qxl_monitors_config_needed(void *opaque)
-{
-    PCIQXLDevice *qxl = opaque;
-
-    return qxl->guest_monitors_config != 0;
-}
-
-
-static VMStateDescription qxl_memslot = {
-    .name               = "qxl-memslot",
-    .version_id         = QXL_SAVE_VERSION,
-    .minimum_version_id = QXL_SAVE_VERSION,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT64(slot.mem_start, struct guest_slots),
-        VMSTATE_UINT64(slot.mem_end,   struct guest_slots),
-        VMSTATE_UINT32(active,         struct guest_slots),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static VMStateDescription qxl_surface = {
-    .name               = "qxl-surface",
-    .version_id         = QXL_SAVE_VERSION,
-    .minimum_version_id = QXL_SAVE_VERSION,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT32(width,      QXLSurfaceCreate),
-        VMSTATE_UINT32(height,     QXLSurfaceCreate),
-        VMSTATE_INT32(stride,      QXLSurfaceCreate),
-        VMSTATE_UINT32(format,     QXLSurfaceCreate),
-        VMSTATE_UINT32(position,   QXLSurfaceCreate),
-        VMSTATE_UINT32(mouse_mode, QXLSurfaceCreate),
-        VMSTATE_UINT32(flags,      QXLSurfaceCreate),
-        VMSTATE_UINT32(type,       QXLSurfaceCreate),
-        VMSTATE_UINT64(mem,        QXLSurfaceCreate),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static VMStateDescription qxl_vmstate_monitors_config = {
-    .name               = "qxl/monitors-config",
-    .version_id         = 1,
-    .minimum_version_id = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT64(guest_monitors_config, PCIQXLDevice),
-        VMSTATE_END_OF_LIST()
-    },
-};
-
-static VMStateDescription qxl_vmstate = {
-    .name               = "qxl",
-    .version_id         = QXL_SAVE_VERSION,
-    .minimum_version_id = QXL_SAVE_VERSION,
-    .pre_save           = qxl_pre_save,
-    .pre_load           = qxl_pre_load,
-    .post_load          = qxl_post_load,
-    .fields = (VMStateField[]) {
-        VMSTATE_PCI_DEVICE(pci, PCIQXLDevice),
-        VMSTATE_STRUCT(vga, PCIQXLDevice, 0, vmstate_vga_common, VGACommonState),
-        VMSTATE_UINT32(shadow_rom.mode, PCIQXLDevice),
-        VMSTATE_UINT32(num_free_res, PCIQXLDevice),
-        VMSTATE_UINT32(last_release_offset, PCIQXLDevice),
-        VMSTATE_UINT32(mode, PCIQXLDevice),
-        VMSTATE_UINT32(ssd.unique, PCIQXLDevice),
-        VMSTATE_INT32_EQUAL(num_memslots, PCIQXLDevice),
-        VMSTATE_STRUCT_ARRAY(guest_slots, PCIQXLDevice, NUM_MEMSLOTS, 0,
-                             qxl_memslot, struct guest_slots),
-        VMSTATE_STRUCT(guest_primary.surface, PCIQXLDevice, 0,
-                       qxl_surface, QXLSurfaceCreate),
-        VMSTATE_INT32_EQUAL(ssd.num_surfaces, PCIQXLDevice),
-        VMSTATE_VARRAY_INT32(guest_surfaces.cmds, PCIQXLDevice,
-                             ssd.num_surfaces, 0,
-                             vmstate_info_uint64, uint64_t),
-        VMSTATE_UINT64(guest_cursor, PCIQXLDevice),
-        VMSTATE_END_OF_LIST()
-    },
-    .subsections = (VMStateSubsection[]) {
-        {
-            .vmsd = &qxl_vmstate_monitors_config,
-            .needed = qxl_monitors_config_needed,
-        }, {
-            /* empty */
-        }
-    }
-};
-
-static Property qxl_properties[] = {
-        DEFINE_PROP_UINT32("ram_size", PCIQXLDevice, vga.vram_size,
-                           64 * 1024 * 1024),
-        DEFINE_PROP_UINT32("vram_size", PCIQXLDevice, vram32_size,
-                           64 * 1024 * 1024),
-        DEFINE_PROP_UINT32("revision", PCIQXLDevice, revision,
-                           QXL_DEFAULT_REVISION),
-        DEFINE_PROP_UINT32("debug", PCIQXLDevice, debug, 0),
-        DEFINE_PROP_UINT32("guestdebug", PCIQXLDevice, guestdebug, 0),
-        DEFINE_PROP_UINT32("cmdlog", PCIQXLDevice, cmdlog, 0),
-        DEFINE_PROP_UINT32("ram_size_mb",  PCIQXLDevice, ram_size_mb, -1),
-        DEFINE_PROP_UINT32("vram_size_mb", PCIQXLDevice, vram32_size_mb, -1),
-        DEFINE_PROP_UINT32("vram64_size_mb", PCIQXLDevice, vram_size_mb, -1),
-        DEFINE_PROP_UINT32("vgamem_mb", PCIQXLDevice, vgamem_size_mb, 16),
-        DEFINE_PROP_INT32("surfaces", PCIQXLDevice, ssd.num_surfaces, 1024),
-        DEFINE_PROP_END_OF_LIST(),
-};
-
-static void qxl_primary_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
-    k->no_hotplug = 1;
-    k->init = qxl_init_primary;
-    k->romfile = "vgabios-qxl.bin";
-    k->vendor_id = REDHAT_PCI_VENDOR_ID;
-    k->device_id = QXL_DEVICE_ID_STABLE;
-    k->class_id = PCI_CLASS_DISPLAY_VGA;
-    dc->desc = "Spice QXL GPU (primary, vga compatible)";
-    dc->reset = qxl_reset_handler;
-    dc->vmsd = &qxl_vmstate;
-    dc->props = qxl_properties;
-}
-
-static const 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 const TypeInfo qxl_secondary_info = {
-    .name          = "qxl",
-    .parent        = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(PCIQXLDevice),
-    .class_init    = qxl_secondary_class_init,
-};
-
-static void qxl_register_types(void)
-{
-    type_register_static(&qxl_primary_info);
-    type_register_static(&qxl_secondary_info);
-}
-
-type_init(qxl_register_types)
diff --git a/hw/qxl.h b/hw/qxl.h
deleted file mode 100644 (file)
index 36f1a25..0000000
--- a/hw/qxl.h
+++ /dev/null
@@ -1,165 +0,0 @@
-#ifndef HW_QXL_H
-#define HW_QXL_H 1
-
-#include "qemu-common.h"
-
-#include "ui/console.h"
-#include "hw/hw.h"
-#include "hw/pci/pci.h"
-#include "hw/vga_int.h"
-#include "qemu/thread.h"
-
-#include "ui/qemu-spice.h"
-#include "ui/spice-display.h"
-
-enum qxl_mode {
-    QXL_MODE_UNDEFINED,
-    QXL_MODE_VGA,
-    QXL_MODE_COMPAT, /* spice 0.4.x */
-    QXL_MODE_NATIVE,
-};
-
-#ifndef QXL_VRAM64_RANGE_INDEX
-#define QXL_VRAM64_RANGE_INDEX 4
-#endif
-
-#define QXL_UNDEFINED_IO UINT32_MAX
-
-#define QXL_NUM_DIRTY_RECTS 64
-
-typedef struct PCIQXLDevice {
-    PCIDevice          pci;
-    SimpleSpiceDisplay ssd;
-    int                id;
-    uint32_t           debug;
-    uint32_t           guestdebug;
-    uint32_t           cmdlog;
-
-    uint32_t           guest_bug;
-
-    enum qxl_mode      mode;
-    uint32_t           cmdflags;
-    int                generation;
-    uint32_t           revision;
-
-    int32_t            num_memslots;
-
-    uint32_t           current_async;
-    QemuMutex          async_lock;
-
-    struct guest_slots {
-        QXLMemSlot     slot;
-        void           *ptr;
-        uint64_t       size;
-        uint64_t       delta;
-        uint32_t       active;
-    } guest_slots[NUM_MEMSLOTS];
-
-    struct guest_primary {
-        QXLSurfaceCreate surface;
-        uint32_t       commands;
-        uint32_t       resized;
-        int32_t        qxl_stride;
-        uint32_t       abs_stride;
-        uint32_t       bits_pp;
-        uint32_t       bytes_pp;
-        uint8_t        *data;
-    } guest_primary;
-
-    struct surfaces {
-        QXLPHYSICAL    *cmds;
-        uint32_t       count;
-        uint32_t       max;
-    } guest_surfaces;
-    QXLPHYSICAL        guest_cursor;
-
-    QXLPHYSICAL        guest_monitors_config;
-
-    QemuMutex          track_lock;
-
-    /* thread signaling */
-    QemuThread         main;
-    int                pipe[2];
-
-    /* ram pci bar */
-    QXLRam             *ram;
-    VGACommonState     vga;
-    uint32_t           num_free_res;
-    QXLReleaseInfo     *last_release;
-    uint32_t           last_release_offset;
-    uint32_t           oom_running;
-    uint32_t           vgamem_size;
-
-    /* rom pci bar */
-    QXLRom             shadow_rom;
-    QXLRom             *rom;
-    QXLModes           *modes;
-    uint32_t           rom_size;
-    MemoryRegion       rom_bar;
-
-    /* vram pci bar */
-    uint32_t           vram_size;
-    MemoryRegion       vram_bar;
-    uint32_t           vram32_size;
-    MemoryRegion       vram32_bar;
-
-    /* io bar */
-    MemoryRegion       io_bar;
-
-    /* user-friendly properties (in megabytes) */
-    uint32_t          ram_size_mb;
-    uint32_t          vram_size_mb;
-    uint32_t          vram32_size_mb;
-    uint32_t          vgamem_size_mb;
-
-    /* qxl_render_update state */
-    int                render_update_cookie_num;
-    int                num_dirty_rects;
-    QXLRect            dirty[QXL_NUM_DIRTY_RECTS];
-    QEMUBH            *update_area_bh;
-} PCIQXLDevice;
-
-#define PANIC_ON(x) if ((x)) {                         \
-    printf("%s: PANIC %s failed\n", __FUNCTION__, #x); \
-    abort();                                           \
-}
-
-#define dprint(_qxl, _level, _fmt, ...)                                 \
-    do {                                                                \
-        if (_qxl->debug >= _level) {                                    \
-            fprintf(stderr, "qxl-%d: ", _qxl->id);                      \
-            fprintf(stderr, _fmt, ## __VA_ARGS__);                      \
-        }                                                               \
-    } while (0)
-
-#define QXL_DEFAULT_REVISION QXL_REVISION_STABLE_V12
-
-/* qxl.c */
-void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL phys, int group_id);
-void qxl_set_guest_bug(PCIQXLDevice *qxl, const char *msg, ...)
-    GCC_FMT_ATTR(2, 3);
-
-void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id,
-                           struct QXLRect *area, struct QXLRect *dirty_rects,
-                           uint32_t num_dirty_rects,
-                           uint32_t clear_dirty_region,
-                           qxl_async_io async, QXLCookie *cookie);
-void qxl_spice_loadvm_commands(PCIQXLDevice *qxl, struct QXLCommandExt *ext,
-                               uint32_t count);
-void qxl_spice_oom(PCIQXLDevice *qxl);
-void qxl_spice_reset_memslots(PCIQXLDevice *qxl);
-void qxl_spice_reset_image_cache(PCIQXLDevice *qxl);
-void qxl_spice_reset_cursor(PCIQXLDevice *qxl);
-
-/* qxl-logger.c */
-int qxl_log_cmd_cursor(PCIQXLDevice *qxl, QXLCursorCmd *cmd, int group_id);
-int qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext);
-
-/* qxl-render.c */
-void qxl_render_resize(PCIQXLDevice *qxl);
-void qxl_render_update(PCIQXLDevice *qxl);
-int qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext);
-void qxl_render_update_area_done(PCIQXLDevice *qxl, QXLCookie *cookie);
-void qxl_render_update_area_bh(void *opaque);
-
-#endif
diff --git a/hw/rc4030.c b/hw/rc4030.c
deleted file mode 100644 (file)
index b065515..0000000
+++ /dev/null
@@ -1,825 +0,0 @@
-/*
- * QEMU JAZZ RC4030 chipset
- *
- * Copyright (c) 2007-2009 Herve 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 "hw/hw.h"
-#include "hw/mips.h"
-#include "qemu/timer.h"
-
-/********************************************************/
-/* debug rc4030 */
-
-//#define DEBUG_RC4030
-//#define DEBUG_RC4030_DMA
-
-#ifdef DEBUG_RC4030
-#define DPRINTF(fmt, ...) \
-do { printf("rc4030: " fmt , ## __VA_ARGS__); } while (0)
-static const char* irq_names[] = { "parallel", "floppy", "sound", "video",
-            "network", "scsi", "keyboard", "mouse", "serial0", "serial1" };
-#else
-#define DPRINTF(fmt, ...)
-#endif
-
-#define RC4030_ERROR(fmt, ...) \
-do { fprintf(stderr, "rc4030 ERROR: %s: " fmt, __func__ , ## __VA_ARGS__); } while (0)
-
-/********************************************************/
-/* rc4030 emulation                                     */
-
-typedef struct dma_pagetable_entry {
-    int32_t frame;
-    int32_t owner;
-} QEMU_PACKED dma_pagetable_entry;
-
-#define DMA_PAGESIZE    4096
-#define DMA_REG_ENABLE  1
-#define DMA_REG_COUNT   2
-#define DMA_REG_ADDRESS 3
-
-#define DMA_FLAG_ENABLE     0x0001
-#define DMA_FLAG_MEM_TO_DEV 0x0002
-#define DMA_FLAG_TC_INTR    0x0100
-#define DMA_FLAG_MEM_INTR   0x0200
-#define DMA_FLAG_ADDR_INTR  0x0400
-
-typedef struct rc4030State
-{
-    uint32_t config; /* 0x0000: RC4030 config register */
-    uint32_t revision; /* 0x0008: RC4030 Revision register */
-    uint32_t invalid_address_register; /* 0x0010: Invalid Address register */
-
-    /* DMA */
-    uint32_t dma_regs[8][4];
-    uint32_t dma_tl_base; /* 0x0018: DMA transl. table base */
-    uint32_t dma_tl_limit; /* 0x0020: DMA transl. table limit */
-
-    /* cache */
-    uint32_t cache_maint; /* 0x0030: Cache Maintenance */
-    uint32_t remote_failed_address; /* 0x0038: Remote Failed Address */
-    uint32_t memory_failed_address; /* 0x0040: Memory Failed Address */
-    uint32_t cache_ptag; /* 0x0048: I/O Cache Physical Tag */
-    uint32_t cache_ltag; /* 0x0050: I/O Cache Logical Tag */
-    uint32_t cache_bmask; /* 0x0058: I/O Cache Byte Mask */
-
-    uint32_t nmi_interrupt; /* 0x0200: interrupt source */
-    uint32_t offset210;
-    uint32_t nvram_protect; /* 0x0220: NV ram protect register */
-    uint32_t rem_speed[16];
-    uint32_t imr_jazz; /* Local bus int enable mask */
-    uint32_t isr_jazz; /* Local bus int source */
-
-    /* timer */
-    QEMUTimer *periodic_timer;
-    uint32_t itr; /* Interval timer reload */
-
-    qemu_irq timer_irq;
-    qemu_irq jazz_bus_irq;
-
-    MemoryRegion iomem_chipset;
-    MemoryRegion iomem_jazzio;
-} rc4030State;
-
-static void set_next_tick(rc4030State *s)
-{
-    qemu_irq_lower(s->timer_irq);
-    uint32_t tm_hz;
-
-    tm_hz = 1000 / (s->itr + 1);
-
-    qemu_mod_timer(s->periodic_timer, qemu_get_clock_ns(vm_clock) +
-                   get_ticks_per_sec() / tm_hz);
-}
-
-/* called for accesses to rc4030 */
-static uint32_t rc4030_readl(void *opaque, hwaddr addr)
-{
-    rc4030State *s = opaque;
-    uint32_t val;
-
-    addr &= 0x3fff;
-    switch (addr & ~0x3) {
-    /* Global config register */
-    case 0x0000:
-        val = s->config;
-        break;
-    /* Revision register */
-    case 0x0008:
-        val = s->revision;
-        break;
-    /* Invalid Address register */
-    case 0x0010:
-        val = s->invalid_address_register;
-        break;
-    /* DMA transl. table base */
-    case 0x0018:
-        val = s->dma_tl_base;
-        break;
-    /* DMA transl. table limit */
-    case 0x0020:
-        val = s->dma_tl_limit;
-        break;
-    /* Remote Failed Address */
-    case 0x0038:
-        val = s->remote_failed_address;
-        break;
-    /* Memory Failed Address */
-    case 0x0040:
-        val = s->memory_failed_address;
-        break;
-    /* I/O Cache Byte Mask */
-    case 0x0058:
-        val = s->cache_bmask;
-        /* HACK */
-        if (s->cache_bmask == (uint32_t)-1)
-            s->cache_bmask = 0;
-        break;
-    /* Remote Speed Registers */
-    case 0x0070:
-    case 0x0078:
-    case 0x0080:
-    case 0x0088:
-    case 0x0090:
-    case 0x0098:
-    case 0x00a0:
-    case 0x00a8:
-    case 0x00b0:
-    case 0x00b8:
-    case 0x00c0:
-    case 0x00c8:
-    case 0x00d0:
-    case 0x00d8:
-    case 0x00e0:
-    case 0x00e8:
-        val = s->rem_speed[(addr - 0x0070) >> 3];
-        break;
-    /* DMA channel base address */
-    case 0x0100:
-    case 0x0108:
-    case 0x0110:
-    case 0x0118:
-    case 0x0120:
-    case 0x0128:
-    case 0x0130:
-    case 0x0138:
-    case 0x0140:
-    case 0x0148:
-    case 0x0150:
-    case 0x0158:
-    case 0x0160:
-    case 0x0168:
-    case 0x0170:
-    case 0x0178:
-    case 0x0180:
-    case 0x0188:
-    case 0x0190:
-    case 0x0198:
-    case 0x01a0:
-    case 0x01a8:
-    case 0x01b0:
-    case 0x01b8:
-    case 0x01c0:
-    case 0x01c8:
-    case 0x01d0:
-    case 0x01d8:
-    case 0x01e0:
-    case 0x01e8:
-    case 0x01f0:
-    case 0x01f8:
-        {
-            int entry = (addr - 0x0100) >> 5;
-            int idx = (addr & 0x1f) >> 3;
-            val = s->dma_regs[entry][idx];
-        }
-        break;
-    /* Interrupt source */
-    case 0x0200:
-        val = s->nmi_interrupt;
-        break;
-    /* Error type */
-    case 0x0208:
-        val = 0;
-        break;
-    /* Offset 0x0210 */
-    case 0x0210:
-        val = s->offset210;
-        break;
-    /* NV ram protect register */
-    case 0x0220:
-        val = s->nvram_protect;
-        break;
-    /* Interval timer count */
-    case 0x0230:
-        val = 0;
-        qemu_irq_lower(s->timer_irq);
-        break;
-    /* EISA interrupt */
-    case 0x0238:
-        val = 7; /* FIXME: should be read from EISA controller */
-        break;
-    default:
-        RC4030_ERROR("invalid read [" TARGET_FMT_plx "]\n", addr);
-        val = 0;
-        break;
-    }
-
-    if ((addr & ~3) != 0x230) {
-        DPRINTF("read 0x%02x at " TARGET_FMT_plx "\n", val, addr);
-    }
-
-    return val;
-}
-
-static uint32_t rc4030_readw(void *opaque, hwaddr addr)
-{
-    uint32_t v = rc4030_readl(opaque, addr & ~0x3);
-    if (addr & 0x2)
-        return v >> 16;
-    else
-        return v & 0xffff;
-}
-
-static uint32_t rc4030_readb(void *opaque, hwaddr addr)
-{
-    uint32_t v = rc4030_readl(opaque, addr & ~0x3);
-    return (v >> (8 * (addr & 0x3))) & 0xff;
-}
-
-static void rc4030_writel(void *opaque, hwaddr addr, uint32_t val)
-{
-    rc4030State *s = opaque;
-    addr &= 0x3fff;
-
-    DPRINTF("write 0x%02x at " TARGET_FMT_plx "\n", val, addr);
-
-    switch (addr & ~0x3) {
-    /* Global config register */
-    case 0x0000:
-        s->config = val;
-        break;
-    /* DMA transl. table base */
-    case 0x0018:
-        s->dma_tl_base = val;
-        break;
-    /* DMA transl. table limit */
-    case 0x0020:
-        s->dma_tl_limit = val;
-        break;
-    /* DMA transl. table invalidated */
-    case 0x0028:
-        break;
-    /* Cache Maintenance */
-    case 0x0030:
-        s->cache_maint = val;
-        break;
-    /* I/O Cache Physical Tag */
-    case 0x0048:
-        s->cache_ptag = val;
-        break;
-    /* I/O Cache Logical Tag */
-    case 0x0050:
-        s->cache_ltag = val;
-        break;
-    /* I/O Cache Byte Mask */
-    case 0x0058:
-        s->cache_bmask |= val; /* HACK */
-        break;
-    /* I/O Cache Buffer Window */
-    case 0x0060:
-        /* HACK */
-        if (s->cache_ltag == 0x80000001 && s->cache_bmask == 0xf0f0f0f) {
-            hwaddr dest = s->cache_ptag & ~0x1;
-            dest += (s->cache_maint & 0x3) << 3;
-            cpu_physical_memory_write(dest, &val, 4);
-        }
-        break;
-    /* Remote Speed Registers */
-    case 0x0070:
-    case 0x0078:
-    case 0x0080:
-    case 0x0088:
-    case 0x0090:
-    case 0x0098:
-    case 0x00a0:
-    case 0x00a8:
-    case 0x00b0:
-    case 0x00b8:
-    case 0x00c0:
-    case 0x00c8:
-    case 0x00d0:
-    case 0x00d8:
-    case 0x00e0:
-    case 0x00e8:
-        s->rem_speed[(addr - 0x0070) >> 3] = val;
-        break;
-    /* DMA channel base address */
-    case 0x0100:
-    case 0x0108:
-    case 0x0110:
-    case 0x0118:
-    case 0x0120:
-    case 0x0128:
-    case 0x0130:
-    case 0x0138:
-    case 0x0140:
-    case 0x0148:
-    case 0x0150:
-    case 0x0158:
-    case 0x0160:
-    case 0x0168:
-    case 0x0170:
-    case 0x0178:
-    case 0x0180:
-    case 0x0188:
-    case 0x0190:
-    case 0x0198:
-    case 0x01a0:
-    case 0x01a8:
-    case 0x01b0:
-    case 0x01b8:
-    case 0x01c0:
-    case 0x01c8:
-    case 0x01d0:
-    case 0x01d8:
-    case 0x01e0:
-    case 0x01e8:
-    case 0x01f0:
-    case 0x01f8:
-        {
-            int entry = (addr - 0x0100) >> 5;
-            int idx = (addr & 0x1f) >> 3;
-            s->dma_regs[entry][idx] = val;
-        }
-        break;
-    /* Offset 0x0210 */
-    case 0x0210:
-        s->offset210 = val;
-        break;
-    /* Interval timer reload */
-    case 0x0228:
-        s->itr = val;
-        qemu_irq_lower(s->timer_irq);
-        set_next_tick(s);
-        break;
-    /* EISA interrupt */
-    case 0x0238:
-        break;
-    default:
-        RC4030_ERROR("invalid write of 0x%02x at [" TARGET_FMT_plx "]\n", val, addr);
-        break;
-    }
-}
-
-static void rc4030_writew(void *opaque, hwaddr addr, uint32_t val)
-{
-    uint32_t old_val = rc4030_readl(opaque, addr & ~0x3);
-
-    if (addr & 0x2)
-        val = (val << 16) | (old_val & 0x0000ffff);
-    else
-        val = val | (old_val & 0xffff0000);
-    rc4030_writel(opaque, addr & ~0x3, val);
-}
-
-static void rc4030_writeb(void *opaque, hwaddr addr, uint32_t val)
-{
-    uint32_t old_val = rc4030_readl(opaque, addr & ~0x3);
-
-    switch (addr & 3) {
-    case 0:
-        val = val | (old_val & 0xffffff00);
-        break;
-    case 1:
-        val = (val << 8) | (old_val & 0xffff00ff);
-        break;
-    case 2:
-        val = (val << 16) | (old_val & 0xff00ffff);
-        break;
-    case 3:
-        val = (val << 24) | (old_val & 0x00ffffff);
-        break;
-    }
-    rc4030_writel(opaque, addr & ~0x3, val);
-}
-
-static const MemoryRegionOps rc4030_ops = {
-    .old_mmio = {
-        .read = { rc4030_readb, rc4030_readw, rc4030_readl, },
-        .write = { rc4030_writeb, rc4030_writew, rc4030_writel, },
-    },
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void update_jazz_irq(rc4030State *s)
-{
-    uint16_t pending;
-
-    pending = s->isr_jazz & s->imr_jazz;
-
-#ifdef DEBUG_RC4030
-    if (s->isr_jazz != 0) {
-        uint32_t irq = 0;
-        DPRINTF("pending irqs:");
-        for (irq = 0; irq < ARRAY_SIZE(irq_names); irq++) {
-            if (s->isr_jazz & (1 << irq)) {
-                printf(" %s", irq_names[irq]);
-                if (!(s->imr_jazz & (1 << irq))) {
-                    printf("(ignored)");
-                }
-            }
-        }
-        printf("\n");
-    }
-#endif
-
-    if (pending != 0)
-        qemu_irq_raise(s->jazz_bus_irq);
-    else
-        qemu_irq_lower(s->jazz_bus_irq);
-}
-
-static void rc4030_irq_jazz_request(void *opaque, int irq, int level)
-{
-    rc4030State *s = opaque;
-
-    if (level) {
-        s->isr_jazz |= 1 << irq;
-    } else {
-        s->isr_jazz &= ~(1 << irq);
-    }
-
-    update_jazz_irq(s);
-}
-
-static void rc4030_periodic_timer(void *opaque)
-{
-    rc4030State *s = opaque;
-
-    set_next_tick(s);
-    qemu_irq_raise(s->timer_irq);
-}
-
-static uint32_t jazzio_readw(void *opaque, hwaddr addr)
-{
-    rc4030State *s = opaque;
-    uint32_t val;
-    uint32_t irq;
-    addr &= 0xfff;
-
-    switch (addr) {
-    /* Local bus int source */
-    case 0x00: {
-        uint32_t pending = s->isr_jazz & s->imr_jazz;
-        val = 0;
-        irq = 0;
-        while (pending) {
-            if (pending & 1) {
-                DPRINTF("returning irq %s\n", irq_names[irq]);
-                val = (irq + 1) << 2;
-                break;
-            }
-            irq++;
-            pending >>= 1;
-        }
-        break;
-    }
-    /* Local bus int enable mask */
-    case 0x02:
-        val = s->imr_jazz;
-        break;
-    default:
-        RC4030_ERROR("(jazz io controller) invalid read [" TARGET_FMT_plx "]\n", addr);
-        val = 0;
-    }
-
-    DPRINTF("(jazz io controller) read 0x%04x at " TARGET_FMT_plx "\n", val, addr);
-
-    return val;
-}
-
-static uint32_t jazzio_readb(void *opaque, hwaddr addr)
-{
-    uint32_t v;
-    v = jazzio_readw(opaque, addr & ~0x1);
-    return (v >> (8 * (addr & 0x1))) & 0xff;
-}
-
-static uint32_t jazzio_readl(void *opaque, hwaddr addr)
-{
-    uint32_t v;
-    v = jazzio_readw(opaque, addr);
-    v |= jazzio_readw(opaque, addr + 2) << 16;
-    return v;
-}
-
-static void jazzio_writew(void *opaque, hwaddr addr, uint32_t val)
-{
-    rc4030State *s = opaque;
-    addr &= 0xfff;
-
-    DPRINTF("(jazz io controller) write 0x%04x at " TARGET_FMT_plx "\n", val, addr);
-
-    switch (addr) {
-    /* Local bus int enable mask */
-    case 0x02:
-        s->imr_jazz = val;
-        update_jazz_irq(s);
-        break;
-    default:
-        RC4030_ERROR("(jazz io controller) invalid write of 0x%04x at [" TARGET_FMT_plx "]\n", val, addr);
-        break;
-    }
-}
-
-static void jazzio_writeb(void *opaque, hwaddr addr, uint32_t val)
-{
-    uint32_t old_val = jazzio_readw(opaque, addr & ~0x1);
-
-    switch (addr & 1) {
-    case 0:
-        val = val | (old_val & 0xff00);
-        break;
-    case 1:
-        val = (val << 8) | (old_val & 0x00ff);
-        break;
-    }
-    jazzio_writew(opaque, addr & ~0x1, val);
-}
-
-static void jazzio_writel(void *opaque, hwaddr addr, uint32_t val)
-{
-    jazzio_writew(opaque, addr, val & 0xffff);
-    jazzio_writew(opaque, addr + 2, (val >> 16) & 0xffff);
-}
-
-static const MemoryRegionOps jazzio_ops = {
-    .old_mmio = {
-        .read = { jazzio_readb, jazzio_readw, jazzio_readl, },
-        .write = { jazzio_writeb, jazzio_writew, jazzio_writel, },
-    },
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void rc4030_reset(void *opaque)
-{
-    rc4030State *s = opaque;
-    int i;
-
-    s->config = 0x410; /* some boards seem to accept 0x104 too */
-    s->revision = 1;
-    s->invalid_address_register = 0;
-
-    memset(s->dma_regs, 0, sizeof(s->dma_regs));
-    s->dma_tl_base = s->dma_tl_limit = 0;
-
-    s->remote_failed_address = s->memory_failed_address = 0;
-    s->cache_maint = 0;
-    s->cache_ptag = s->cache_ltag = 0;
-    s->cache_bmask = 0;
-
-    s->offset210 = 0x18186;
-    s->nvram_protect = 7;
-    for (i = 0; i < 15; i++)
-        s->rem_speed[i] = 7;
-    s->imr_jazz = 0x10; /* XXX: required by firmware, but why? */
-    s->isr_jazz = 0;
-
-    s->itr = 0;
-
-    qemu_irq_lower(s->timer_irq);
-    qemu_irq_lower(s->jazz_bus_irq);
-}
-
-static int rc4030_load(QEMUFile *f, void *opaque, int version_id)
-{
-    rc4030State* s = opaque;
-    int i, j;
-
-    if (version_id != 2)
-        return -EINVAL;
-
-    s->config = qemu_get_be32(f);
-    s->invalid_address_register = qemu_get_be32(f);
-    for (i = 0; i < 8; i++)
-        for (j = 0; j < 4; j++)
-            s->dma_regs[i][j] = qemu_get_be32(f);
-    s->dma_tl_base = qemu_get_be32(f);
-    s->dma_tl_limit = qemu_get_be32(f);
-    s->cache_maint = qemu_get_be32(f);
-    s->remote_failed_address = qemu_get_be32(f);
-    s->memory_failed_address = qemu_get_be32(f);
-    s->cache_ptag = qemu_get_be32(f);
-    s->cache_ltag = qemu_get_be32(f);
-    s->cache_bmask = qemu_get_be32(f);
-    s->offset210 = qemu_get_be32(f);
-    s->nvram_protect = qemu_get_be32(f);
-    for (i = 0; i < 15; i++)
-        s->rem_speed[i] = qemu_get_be32(f);
-    s->imr_jazz = qemu_get_be32(f);
-    s->isr_jazz = qemu_get_be32(f);
-    s->itr = qemu_get_be32(f);
-
-    set_next_tick(s);
-    update_jazz_irq(s);
-
-    return 0;
-}
-
-static void rc4030_save(QEMUFile *f, void *opaque)
-{
-    rc4030State* s = opaque;
-    int i, j;
-
-    qemu_put_be32(f, s->config);
-    qemu_put_be32(f, s->invalid_address_register);
-    for (i = 0; i < 8; i++)
-        for (j = 0; j < 4; j++)
-            qemu_put_be32(f, s->dma_regs[i][j]);
-    qemu_put_be32(f, s->dma_tl_base);
-    qemu_put_be32(f, s->dma_tl_limit);
-    qemu_put_be32(f, s->cache_maint);
-    qemu_put_be32(f, s->remote_failed_address);
-    qemu_put_be32(f, s->memory_failed_address);
-    qemu_put_be32(f, s->cache_ptag);
-    qemu_put_be32(f, s->cache_ltag);
-    qemu_put_be32(f, s->cache_bmask);
-    qemu_put_be32(f, s->offset210);
-    qemu_put_be32(f, s->nvram_protect);
-    for (i = 0; i < 15; i++)
-        qemu_put_be32(f, s->rem_speed[i]);
-    qemu_put_be32(f, s->imr_jazz);
-    qemu_put_be32(f, s->isr_jazz);
-    qemu_put_be32(f, s->itr);
-}
-
-void rc4030_dma_memory_rw(void *opaque, hwaddr addr, uint8_t *buf, int len, int is_write)
-{
-    rc4030State *s = opaque;
-    hwaddr entry_addr;
-    hwaddr phys_addr;
-    dma_pagetable_entry entry;
-    int index;
-    int ncpy, i;
-
-    i = 0;
-    for (;;) {
-        if (i == len) {
-            break;
-        }
-
-        ncpy = DMA_PAGESIZE - (addr & (DMA_PAGESIZE - 1));
-        if (ncpy > len - i)
-            ncpy = len - i;
-
-        /* Get DMA translation table entry */
-        index = addr / DMA_PAGESIZE;
-        if (index >= s->dma_tl_limit / sizeof(dma_pagetable_entry)) {
-            break;
-        }
-        entry_addr = s->dma_tl_base + index * sizeof(dma_pagetable_entry);
-        /* XXX: not sure. should we really use only lowest bits? */
-        entry_addr &= 0x7fffffff;
-        cpu_physical_memory_read(entry_addr, &entry, sizeof(entry));
-
-        /* Read/write data at right place */
-        phys_addr = entry.frame + (addr & (DMA_PAGESIZE - 1));
-        cpu_physical_memory_rw(phys_addr, &buf[i], ncpy, is_write);
-
-        i += ncpy;
-        addr += ncpy;
-    }
-}
-
-static void rc4030_do_dma(void *opaque, int n, uint8_t *buf, int len, int is_write)
-{
-    rc4030State *s = opaque;
-    hwaddr dma_addr;
-    int dev_to_mem;
-
-    s->dma_regs[n][DMA_REG_ENABLE] &= ~(DMA_FLAG_TC_INTR | DMA_FLAG_MEM_INTR | DMA_FLAG_ADDR_INTR);
-
-    /* Check DMA channel consistency */
-    dev_to_mem = (s->dma_regs[n][DMA_REG_ENABLE] & DMA_FLAG_MEM_TO_DEV) ? 0 : 1;
-    if (!(s->dma_regs[n][DMA_REG_ENABLE] & DMA_FLAG_ENABLE) ||
-        (is_write != dev_to_mem)) {
-        s->dma_regs[n][DMA_REG_ENABLE] |= DMA_FLAG_MEM_INTR;
-        s->nmi_interrupt |= 1 << n;
-        return;
-    }
-
-    /* Get start address and len */
-    if (len > s->dma_regs[n][DMA_REG_COUNT])
-        len = s->dma_regs[n][DMA_REG_COUNT];
-    dma_addr = s->dma_regs[n][DMA_REG_ADDRESS];
-
-    /* Read/write data at right place */
-    rc4030_dma_memory_rw(opaque, dma_addr, buf, len, is_write);
-
-    s->dma_regs[n][DMA_REG_ENABLE] |= DMA_FLAG_TC_INTR;
-    s->dma_regs[n][DMA_REG_COUNT] -= len;
-
-#ifdef DEBUG_RC4030_DMA
-    {
-        int i, j;
-        printf("rc4030 dma: Copying %d bytes %s host %p\n",
-            len, is_write ? "from" : "to", buf);
-        for (i = 0; i < len; i += 16) {
-            int n = 16;
-            if (n > len - i) {
-                n = len - i;
-            }
-            for (j = 0; j < n; j++)
-                printf("%02x ", buf[i + j]);
-            while (j++ < 16)
-                printf("   ");
-            printf("| ");
-            for (j = 0; j < n; j++)
-                printf("%c", isprint(buf[i + j]) ? buf[i + j] : '.');
-            printf("\n");
-        }
-    }
-#endif
-}
-
-struct rc4030DMAState {
-    void *opaque;
-    int n;
-};
-
-void rc4030_dma_read(void *dma, uint8_t *buf, int len)
-{
-    rc4030_dma s = dma;
-    rc4030_do_dma(s->opaque, s->n, buf, len, 0);
-}
-
-void rc4030_dma_write(void *dma, uint8_t *buf, int len)
-{
-    rc4030_dma s = dma;
-    rc4030_do_dma(s->opaque, s->n, buf, len, 1);
-}
-
-static rc4030_dma *rc4030_allocate_dmas(void *opaque, int n)
-{
-    rc4030_dma *s;
-    struct rc4030DMAState *p;
-    int i;
-
-    s = (rc4030_dma *)g_malloc0(sizeof(rc4030_dma) * n);
-    p = (struct rc4030DMAState *)g_malloc0(sizeof(struct rc4030DMAState) * n);
-    for (i = 0; i < n; i++) {
-        p->opaque = opaque;
-        p->n = i;
-        s[i] = p;
-        p++;
-    }
-    return s;
-}
-
-void *rc4030_init(qemu_irq timer, qemu_irq jazz_bus,
-                  qemu_irq **irqs, rc4030_dma **dmas,
-                  MemoryRegion *sysmem)
-{
-    rc4030State *s;
-
-    s = g_malloc0(sizeof(rc4030State));
-
-    *irqs = qemu_allocate_irqs(rc4030_irq_jazz_request, s, 16);
-    *dmas = rc4030_allocate_dmas(s, 4);
-
-    s->periodic_timer = qemu_new_timer_ns(vm_clock, rc4030_periodic_timer, s);
-    s->timer_irq = timer;
-    s->jazz_bus_irq = jazz_bus;
-
-    qemu_register_reset(rc4030_reset, s);
-    register_savevm(NULL, "rc4030", 0, 2, rc4030_save, rc4030_load, s);
-    rc4030_reset(s);
-
-    memory_region_init_io(&s->iomem_chipset, &rc4030_ops, s,
-                          "rc4030.chipset", 0x300);
-    memory_region_add_subregion(sysmem, 0x80000000, &s->iomem_chipset);
-    memory_region_init_io(&s->iomem_jazzio, &jazzio_ops, s,
-                          "rc4030.jazzio", 0x00001000);
-    memory_region_add_subregion(sysmem, 0xf0000000, &s->iomem_jazzio);
-
-    return s;
-}
diff --git a/hw/realview_gic.c b/hw/realview_gic.c
deleted file mode 100644 (file)
index 0ec30ca..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * ARM RealView Emulation Baseboard Interrupt Controller
- *
- * Copyright (c) 2006-2007 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the GPL.
- */
-
-#include "hw/sysbus.h"
-
-typedef struct {
-    SysBusDevice busdev;
-    DeviceState *gic;
-    MemoryRegion container;
-} RealViewGICState;
-
-static void realview_gic_set_irq(void *opaque, int irq, int level)
-{
-    RealViewGICState *s = (RealViewGICState *)opaque;
-    qemu_set_irq(qdev_get_gpio_in(s->gic, irq), level);
-}
-
-static int realview_gic_init(SysBusDevice *dev)
-{
-    RealViewGICState *s = FROM_SYSBUS(RealViewGICState, dev);
-    SysBusDevice *busdev;
-    /* 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.
-     */
-    int numirq = 96;
-
-    s->gic = qdev_create(NULL, "arm_gic");
-    qdev_prop_set_uint32(s->gic, "num-cpu", 1);
-    qdev_prop_set_uint32(s->gic, "num-irq", numirq);
-    qdev_init_nofail(s->gic);
-    busdev = SYS_BUS_DEVICE(s->gic);
-
-    /* Pass through outbound IRQ lines from the GIC */
-    sysbus_pass_irq(dev, busdev);
-
-    /* Pass through inbound GPIO lines to the GIC */
-    qdev_init_gpio_in(&s->busdev.qdev, realview_gic_set_irq, numirq - 32);
-
-    memory_region_init(&s->container, "realview-gic-container", 0x2000);
-    memory_region_add_subregion(&s->container, 0,
-                                sysbus_mmio_get_region(busdev, 1));
-    memory_region_add_subregion(&s->container, 0x1000,
-                                sysbus_mmio_get_region(busdev, 0));
-    sysbus_init_mmio(dev, &s->container);
-    return 0;
-}
-
-static void realview_gic_class_init(ObjectClass *klass, void *data)
-{
-    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
-
-    sdc->init = realview_gic_init;
-}
-
-static const 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_types(void)
-{
-    type_register_static(&realview_gic_info);
-}
-
-type_init(realview_gic_register_types)
diff --git a/hw/rtl8139.c b/hw/rtl8139.c
deleted file mode 100644 (file)
index 9369507..0000000
+++ /dev/null
@@ -1,3555 +0,0 @@
-/**
- * QEMU RTL8139 emulation
- *
- * Copyright (c) 2006 Igor Kovalenko
- *
- * 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.
-
- * Modifications:
- *  2006-Jan-28  Mark Malakanov :   TSAD and CSCR implementation (for Windows driver)
- *
- *  2006-Apr-28  Juergen Lock   :   EEPROM emulation changes for FreeBSD driver
- *                                  HW revision ID changes for FreeBSD driver
- *
- *  2006-Jul-01  Igor Kovalenko :   Implemented loopback mode for FreeBSD driver
- *                                  Corrected packet transfer reassembly routine for 8139C+ mode
- *                                  Rearranged debugging print statements
- *                                  Implemented PCI timer interrupt (disabled by default)
- *                                  Implemented Tally Counters, increased VM load/save version
- *                                  Implemented IP/TCP/UDP checksum task offloading
- *
- *  2006-Jul-04  Igor Kovalenko :   Implemented TCP segmentation offloading
- *                                  Fixed MTU=1500 for produced ethernet frames
- *
- *  2006-Jul-09  Igor Kovalenko :   Fixed TCP header length calculation while processing
- *                                  segmentation offloading
- *                                  Removed slirp.h dependency
- *                                  Added rx/tx buffer reset when enabling rx/tx operation
- *
- *  2010-Feb-04  Frediano Ziglio:   Rewrote timer support using QEMU timer only
- *                                  when strictly needed (required for for
- *                                  Darwin)
- *  2011-Mar-22  Benjamin Poirier:  Implemented VLAN offloading
- */
-
-/* For crc32 */
-#include <zlib.h>
-
-#include "hw/hw.h"
-#include "hw/pci/pci.h"
-#include "sysemu/dma.h"
-#include "qemu/timer.h"
-#include "net/net.h"
-#include "hw/loader.h"
-#include "sysemu/sysemu.h"
-#include "qemu/iov.h"
-
-/* debug RTL8139 card */
-//#define DEBUG_RTL8139 1
-
-#define PCI_FREQUENCY 33000000L
-
-#define SET_MASKED(input, mask, curr) \
-    ( ( (input) & ~(mask) ) | ( (curr) & (mask) ) )
-
-/* arg % size for size which is a power of 2 */
-#define MOD2(input, size) \
-    ( ( input ) & ( size - 1 )  )
-
-#define ETHER_ADDR_LEN 6
-#define ETHER_TYPE_LEN 2
-#define ETH_HLEN (ETHER_ADDR_LEN * 2 + ETHER_TYPE_LEN)
-#define ETH_P_IP    0x0800      /* Internet Protocol packet */
-#define ETH_P_8021Q 0x8100      /* 802.1Q VLAN Extended Header  */
-#define ETH_MTU     1500
-
-#define VLAN_TCI_LEN 2
-#define VLAN_HLEN (ETHER_TYPE_LEN + VLAN_TCI_LEN)
-
-#if defined (DEBUG_RTL8139)
-#  define DPRINTF(fmt, ...) \
-    do { fprintf(stderr, "RTL8139: " fmt, ## __VA_ARGS__); } while (0)
-#else
-static inline GCC_FMT_ATTR(1, 2) int DPRINTF(const char *fmt, ...)
-{
-    return 0;
-}
-#endif
-
-/* Symbolic offsets to registers. */
-enum RTL8139_registers {
-    MAC0 = 0,        /* Ethernet hardware address. */
-    MAR0 = 8,        /* Multicast filter. */
-    TxStatus0 = 0x10,/* Transmit status (Four 32bit registers). C mode only */
-                     /* Dump Tally Conter control register(64bit). C+ mode only */
-    TxAddr0 = 0x20,  /* Tx descriptors (also four 32bit). */
-    RxBuf = 0x30,
-    ChipCmd = 0x37,
-    RxBufPtr = 0x38,
-    RxBufAddr = 0x3A,
-    IntrMask = 0x3C,
-    IntrStatus = 0x3E,
-    TxConfig = 0x40,
-    RxConfig = 0x44,
-    Timer = 0x48,        /* A general-purpose counter. */
-    RxMissed = 0x4C,    /* 24 bits valid, write clears. */
-    Cfg9346 = 0x50,
-    Config0 = 0x51,
-    Config1 = 0x52,
-    FlashReg = 0x54,
-    MediaStatus = 0x58,
-    Config3 = 0x59,
-    Config4 = 0x5A,        /* absent on RTL-8139A */
-    HltClk = 0x5B,
-    MultiIntr = 0x5C,
-    PCIRevisionID = 0x5E,
-    TxSummary = 0x60, /* TSAD register. Transmit Status of All Descriptors*/
-    BasicModeCtrl = 0x62,
-    BasicModeStatus = 0x64,
-    NWayAdvert = 0x66,
-    NWayLPAR = 0x68,
-    NWayExpansion = 0x6A,
-    /* Undocumented registers, but required for proper operation. */
-    FIFOTMS = 0x70,        /* FIFO Control and test. */
-    CSCR = 0x74,        /* Chip Status and Configuration Register. */
-    PARA78 = 0x78,
-    PARA7c = 0x7c,        /* Magic transceiver parameter register. */
-    Config5 = 0xD8,        /* absent on RTL-8139A */
-    /* C+ mode */
-    TxPoll        = 0xD9,    /* Tell chip to check Tx descriptors for work */
-    RxMaxSize    = 0xDA, /* Max size of an Rx packet (8169 only) */
-    CpCmd        = 0xE0, /* C+ Command register (C+ mode only) */
-    IntrMitigate    = 0xE2,    /* rx/tx interrupt mitigation control */
-    RxRingAddrLO    = 0xE4, /* 64-bit start addr of Rx ring */
-    RxRingAddrHI    = 0xE8, /* 64-bit start addr of Rx ring */
-    TxThresh    = 0xEC, /* Early Tx threshold */
-};
-
-enum ClearBitMasks {
-    MultiIntrClear = 0xF000,
-    ChipCmdClear = 0xE2,
-    Config1Clear = (1<<7)|(1<<6)|(1<<3)|(1<<2)|(1<<1),
-};
-
-enum ChipCmdBits {
-    CmdReset = 0x10,
-    CmdRxEnb = 0x08,
-    CmdTxEnb = 0x04,
-    RxBufEmpty = 0x01,
-};
-
-/* C+ mode */
-enum CplusCmdBits {
-    CPlusRxVLAN   = 0x0040, /* enable receive VLAN detagging */
-    CPlusRxChkSum = 0x0020, /* enable receive checksum offloading */
-    CPlusRxEnb    = 0x0002,
-    CPlusTxEnb    = 0x0001,
-};
-
-/* Interrupt register bits, using my own meaningful names. */
-enum IntrStatusBits {
-    PCIErr = 0x8000,
-    PCSTimeout = 0x4000,
-    RxFIFOOver = 0x40,
-    RxUnderrun = 0x20, /* Packet Underrun / Link Change */
-    RxOverflow = 0x10,
-    TxErr = 0x08,
-    TxOK = 0x04,
-    RxErr = 0x02,
-    RxOK = 0x01,
-
-    RxAckBits = RxFIFOOver | RxOverflow | RxOK,
-};
-
-enum TxStatusBits {
-    TxHostOwns = 0x2000,
-    TxUnderrun = 0x4000,
-    TxStatOK = 0x8000,
-    TxOutOfWindow = 0x20000000,
-    TxAborted = 0x40000000,
-    TxCarrierLost = 0x80000000,
-};
-enum RxStatusBits {
-    RxMulticast = 0x8000,
-    RxPhysical = 0x4000,
-    RxBroadcast = 0x2000,
-    RxBadSymbol = 0x0020,
-    RxRunt = 0x0010,
-    RxTooLong = 0x0008,
-    RxCRCErr = 0x0004,
-    RxBadAlign = 0x0002,
-    RxStatusOK = 0x0001,
-};
-
-/* Bits in RxConfig. */
-enum rx_mode_bits {
-    AcceptErr = 0x20,
-    AcceptRunt = 0x10,
-    AcceptBroadcast = 0x08,
-    AcceptMulticast = 0x04,
-    AcceptMyPhys = 0x02,
-    AcceptAllPhys = 0x01,
-};
-
-/* Bits in TxConfig. */
-enum tx_config_bits {
-
-        /* Interframe Gap Time. Only TxIFG96 doesn't violate IEEE 802.3 */
-        TxIFGShift = 24,
-        TxIFG84 = (0 << TxIFGShift),    /* 8.4us / 840ns (10 / 100Mbps) */
-        TxIFG88 = (1 << TxIFGShift),    /* 8.8us / 880ns (10 / 100Mbps) */
-        TxIFG92 = (2 << TxIFGShift),    /* 9.2us / 920ns (10 / 100Mbps) */
-        TxIFG96 = (3 << TxIFGShift),    /* 9.6us / 960ns (10 / 100Mbps) */
-
-    TxLoopBack = (1 << 18) | (1 << 17), /* enable loopback test mode */
-    TxCRC = (1 << 16),    /* DISABLE appending CRC to end of Tx packets */
-    TxClearAbt = (1 << 0),    /* Clear abort (WO) */
-    TxDMAShift = 8,        /* DMA burst value (0-7) is shifted this many bits */
-    TxRetryShift = 4,    /* TXRR value (0-15) is shifted this many bits */
-
-    TxVersionMask = 0x7C800000, /* mask out version bits 30-26, 23 */
-};
-
-
-/* Transmit Status of All Descriptors (TSAD) Register */
-enum TSAD_bits {
- TSAD_TOK3 = 1<<15, // TOK bit of Descriptor 3
- TSAD_TOK2 = 1<<14, // TOK bit of Descriptor 2
- TSAD_TOK1 = 1<<13, // TOK bit of Descriptor 1
- TSAD_TOK0 = 1<<12, // TOK bit of Descriptor 0
- TSAD_TUN3 = 1<<11, // TUN bit of Descriptor 3
- TSAD_TUN2 = 1<<10, // TUN bit of Descriptor 2
- TSAD_TUN1 = 1<<9, // TUN bit of Descriptor 1
- TSAD_TUN0 = 1<<8, // TUN bit of Descriptor 0
- TSAD_TABT3 = 1<<07, // TABT bit of Descriptor 3
- TSAD_TABT2 = 1<<06, // TABT bit of Descriptor 2
- TSAD_TABT1 = 1<<05, // TABT bit of Descriptor 1
- TSAD_TABT0 = 1<<04, // TABT bit of Descriptor 0
- TSAD_OWN3 = 1<<03, // OWN bit of Descriptor 3
- TSAD_OWN2 = 1<<02, // OWN bit of Descriptor 2
- TSAD_OWN1 = 1<<01, // OWN bit of Descriptor 1
- TSAD_OWN0 = 1<<00, // OWN bit of Descriptor 0
-};
-
-
-/* Bits in Config1 */
-enum Config1Bits {
-    Cfg1_PM_Enable = 0x01,
-    Cfg1_VPD_Enable = 0x02,
-    Cfg1_PIO = 0x04,
-    Cfg1_MMIO = 0x08,
-    LWAKE = 0x10,        /* not on 8139, 8139A */
-    Cfg1_Driver_Load = 0x20,
-    Cfg1_LED0 = 0x40,
-    Cfg1_LED1 = 0x80,
-    SLEEP = (1 << 1),    /* only on 8139, 8139A */
-    PWRDN = (1 << 0),    /* only on 8139, 8139A */
-};
-
-/* Bits in Config3 */
-enum Config3Bits {
-    Cfg3_FBtBEn    = (1 << 0), /* 1 = Fast Back to Back */
-    Cfg3_FuncRegEn = (1 << 1), /* 1 = enable CardBus Function registers */
-    Cfg3_CLKRUN_En = (1 << 2), /* 1 = enable CLKRUN */
-    Cfg3_CardB_En  = (1 << 3), /* 1 = enable CardBus registers */
-    Cfg3_LinkUp    = (1 << 4), /* 1 = wake up on link up */
-    Cfg3_Magic     = (1 << 5), /* 1 = wake up on Magic Packet (tm) */
-    Cfg3_PARM_En   = (1 << 6), /* 0 = software can set twister parameters */
-    Cfg3_GNTSel    = (1 << 7), /* 1 = delay 1 clock from PCI GNT signal */
-};
-
-/* Bits in Config4 */
-enum Config4Bits {
-    LWPTN = (1 << 2),    /* not on 8139, 8139A */
-};
-
-/* Bits in Config5 */
-enum Config5Bits {
-    Cfg5_PME_STS     = (1 << 0), /* 1 = PCI reset resets PME_Status */
-    Cfg5_LANWake     = (1 << 1), /* 1 = enable LANWake signal */
-    Cfg5_LDPS        = (1 << 2), /* 0 = save power when link is down */
-    Cfg5_FIFOAddrPtr = (1 << 3), /* Realtek internal SRAM testing */
-    Cfg5_UWF         = (1 << 4), /* 1 = accept unicast wakeup frame */
-    Cfg5_MWF         = (1 << 5), /* 1 = accept multicast wakeup frame */
-    Cfg5_BWF         = (1 << 6), /* 1 = accept broadcast wakeup frame */
-};
-
-enum RxConfigBits {
-    /* rx fifo threshold */
-    RxCfgFIFOShift = 13,
-    RxCfgFIFONone = (7 << RxCfgFIFOShift),
-
-    /* Max DMA burst */
-    RxCfgDMAShift = 8,
-    RxCfgDMAUnlimited = (7 << RxCfgDMAShift),
-
-    /* rx ring buffer length */
-    RxCfgRcv8K = 0,
-    RxCfgRcv16K = (1 << 11),
-    RxCfgRcv32K = (1 << 12),
-    RxCfgRcv64K = (1 << 11) | (1 << 12),
-
-    /* Disable packet wrap at end of Rx buffer. (not possible with 64k) */
-    RxNoWrap = (1 << 7),
-};
-
-/* Twister tuning parameters from RealTek.
-   Completely undocumented, but required to tune bad links on some boards. */
-/*
-enum CSCRBits {
-    CSCR_LinkOKBit = 0x0400,
-    CSCR_LinkChangeBit = 0x0800,
-    CSCR_LinkStatusBits = 0x0f000,
-    CSCR_LinkDownOffCmd = 0x003c0,
-    CSCR_LinkDownCmd = 0x0f3c0,
-*/
-enum CSCRBits {
-    CSCR_Testfun = 1<<15, /* 1 = Auto-neg speeds up internal timer, WO, def 0 */
-    CSCR_LD  = 1<<9,  /* Active low TPI link disable signal. When low, TPI still transmits link pulses and TPI stays in good link state. def 1*/
-    CSCR_HEART_BIT = 1<<8,  /* 1 = HEART BEAT enable, 0 = HEART BEAT disable. HEART BEAT function is only valid in 10Mbps mode. def 1*/
-    CSCR_JBEN = 1<<7,  /* 1 = enable jabber function. 0 = disable jabber function, def 1*/
-    CSCR_F_LINK_100 = 1<<6, /* Used to login force good link in 100Mbps for diagnostic purposes. 1 = DISABLE, 0 = ENABLE. def 1*/
-    CSCR_F_Connect  = 1<<5,  /* Assertion of this bit forces the disconnect function to be bypassed. def 0*/
-    CSCR_Con_status = 1<<3, /* This bit indicates the status of the connection. 1 = valid connected link detected; 0 = disconnected link detected. RO def 0*/
-    CSCR_Con_status_En = 1<<2, /* Assertion of this bit configures LED1 pin to indicate connection status. def 0*/
-    CSCR_PASS_SCR = 1<<0, /* Bypass Scramble, def 0*/
-};
-
-enum Cfg9346Bits {
-    Cfg9346_Normal = 0x00,
-    Cfg9346_Autoload = 0x40,
-    Cfg9346_Programming = 0x80,
-    Cfg9346_ConfigWrite = 0xC0,
-};
-
-typedef enum {
-    CH_8139 = 0,
-    CH_8139_K,
-    CH_8139A,
-    CH_8139A_G,
-    CH_8139B,
-    CH_8130,
-    CH_8139C,
-    CH_8100,
-    CH_8100B_8139D,
-    CH_8101,
-} chip_t;
-
-enum chip_flags {
-    HasHltClk = (1 << 0),
-    HasLWake = (1 << 1),
-};
-
-#define HW_REVID(b30, b29, b28, b27, b26, b23, b22) \
-    (b30<<30 | b29<<29 | b28<<28 | b27<<27 | b26<<26 | b23<<23 | b22<<22)
-#define HW_REVID_MASK    HW_REVID(1, 1, 1, 1, 1, 1, 1)
-
-#define RTL8139_PCI_REVID_8139      0x10
-#define RTL8139_PCI_REVID_8139CPLUS 0x20
-
-#define RTL8139_PCI_REVID           RTL8139_PCI_REVID_8139CPLUS
-
-/* Size is 64 * 16bit words */
-#define EEPROM_9346_ADDR_BITS 6
-#define EEPROM_9346_SIZE  (1 << EEPROM_9346_ADDR_BITS)
-#define EEPROM_9346_ADDR_MASK (EEPROM_9346_SIZE - 1)
-
-enum Chip9346Operation
-{
-    Chip9346_op_mask = 0xc0,          /* 10 zzzzzz */
-    Chip9346_op_read = 0x80,          /* 10 AAAAAA */
-    Chip9346_op_write = 0x40,         /* 01 AAAAAA D(15)..D(0) */
-    Chip9346_op_ext_mask = 0xf0,      /* 11 zzzzzz */
-    Chip9346_op_write_enable = 0x30,  /* 00 11zzzz */
-    Chip9346_op_write_all = 0x10,     /* 00 01zzzz */
-    Chip9346_op_write_disable = 0x00, /* 00 00zzzz */
-};
-
-enum Chip9346Mode
-{
-    Chip9346_none = 0,
-    Chip9346_enter_command_mode,
-    Chip9346_read_command,
-    Chip9346_data_read,      /* from output register */
-    Chip9346_data_write,     /* to input register, then to contents at specified address */
-    Chip9346_data_write_all, /* to input register, then filling contents */
-};
-
-typedef struct EEprom9346
-{
-    uint16_t contents[EEPROM_9346_SIZE];
-    int      mode;
-    uint32_t tick;
-    uint8_t  address;
-    uint16_t input;
-    uint16_t output;
-
-    uint8_t eecs;
-    uint8_t eesk;
-    uint8_t eedi;
-    uint8_t eedo;
-} EEprom9346;
-
-typedef struct RTL8139TallyCounters
-{
-    /* Tally counters */
-    uint64_t   TxOk;
-    uint64_t   RxOk;
-    uint64_t   TxERR;
-    uint32_t   RxERR;
-    uint16_t   MissPkt;
-    uint16_t   FAE;
-    uint32_t   Tx1Col;
-    uint32_t   TxMCol;
-    uint64_t   RxOkPhy;
-    uint64_t   RxOkBrd;
-    uint32_t   RxOkMul;
-    uint16_t   TxAbt;
-    uint16_t   TxUndrn;
-} RTL8139TallyCounters;
-
-/* Clears all tally counters */
-static void RTL8139TallyCounters_clear(RTL8139TallyCounters* counters);
-
-typedef struct RTL8139State {
-    PCIDevice dev;
-    uint8_t phys[8]; /* mac address */
-    uint8_t mult[8]; /* multicast mask array */
-
-    uint32_t TxStatus[4]; /* TxStatus0 in C mode*/ /* also DTCCR[0] and DTCCR[1] in C+ mode */
-    uint32_t TxAddr[4];   /* TxAddr0 */
-    uint32_t RxBuf;       /* Receive buffer */
-    uint32_t RxBufferSize;/* internal variable, receive ring buffer size in C mode */
-    uint32_t RxBufPtr;
-    uint32_t RxBufAddr;
-
-    uint16_t IntrStatus;
-    uint16_t IntrMask;
-
-    uint32_t TxConfig;
-    uint32_t RxConfig;
-    uint32_t RxMissed;
-
-    uint16_t CSCR;
-
-    uint8_t  Cfg9346;
-    uint8_t  Config0;
-    uint8_t  Config1;
-    uint8_t  Config3;
-    uint8_t  Config4;
-    uint8_t  Config5;
-
-    uint8_t  clock_enabled;
-    uint8_t  bChipCmdState;
-
-    uint16_t MultiIntr;
-
-    uint16_t BasicModeCtrl;
-    uint16_t BasicModeStatus;
-    uint16_t NWayAdvert;
-    uint16_t NWayLPAR;
-    uint16_t NWayExpansion;
-
-    uint16_t CpCmd;
-    uint8_t  TxThresh;
-
-    NICState *nic;
-    NICConf conf;
-
-    /* C ring mode */
-    uint32_t   currTxDesc;
-
-    /* C+ mode */
-    uint32_t   cplus_enabled;
-
-    uint32_t   currCPlusRxDesc;
-    uint32_t   currCPlusTxDesc;
-
-    uint32_t   RxRingAddrLO;
-    uint32_t   RxRingAddrHI;
-
-    EEprom9346 eeprom;
-
-    uint32_t   TCTR;
-    uint32_t   TimerInt;
-    int64_t    TCTR_base;
-
-    /* Tally counters */
-    RTL8139TallyCounters tally_counters;
-
-    /* Non-persistent data */
-    uint8_t   *cplus_txbuffer;
-    int        cplus_txbuffer_len;
-    int        cplus_txbuffer_offset;
-
-    /* PCI interrupt timer */
-    QEMUTimer *timer;
-    int64_t TimerExpire;
-
-    MemoryRegion bar_io;
-    MemoryRegion bar_mem;
-
-    /* Support migration to/from old versions */
-    int rtl8139_mmio_io_addr_dummy;
-} RTL8139State;
-
-/* Writes tally counters to memory via DMA */
-static void RTL8139TallyCounters_dma_write(RTL8139State *s, dma_addr_t tc_addr);
-
-static void rtl8139_set_next_tctr_time(RTL8139State *s, int64_t current_time);
-
-static void prom9346_decode_command(EEprom9346 *eeprom, uint8_t command)
-{
-    DPRINTF("eeprom command 0x%02x\n", command);
-
-    switch (command & Chip9346_op_mask)
-    {
-        case Chip9346_op_read:
-        {
-            eeprom->address = command & EEPROM_9346_ADDR_MASK;
-            eeprom->output = eeprom->contents[eeprom->address];
-            eeprom->eedo = 0;
-            eeprom->tick = 0;
-            eeprom->mode = Chip9346_data_read;
-            DPRINTF("eeprom read from address 0x%02x data=0x%04x\n",
-                eeprom->address, eeprom->output);
-        }
-        break;
-
-        case Chip9346_op_write:
-        {
-            eeprom->address = command & EEPROM_9346_ADDR_MASK;
-            eeprom->input = 0;
-            eeprom->tick = 0;
-            eeprom->mode = Chip9346_none; /* Chip9346_data_write */
-            DPRINTF("eeprom begin write to address 0x%02x\n",
-                eeprom->address);
-        }
-        break;
-        default:
-            eeprom->mode = Chip9346_none;
-            switch (command & Chip9346_op_ext_mask)
-            {
-                case Chip9346_op_write_enable:
-                    DPRINTF("eeprom write enabled\n");
-                    break;
-                case Chip9346_op_write_all:
-                    DPRINTF("eeprom begin write all\n");
-                    break;
-                case Chip9346_op_write_disable:
-                    DPRINTF("eeprom write disabled\n");
-                    break;
-            }
-            break;
-    }
-}
-
-static void prom9346_shift_clock(EEprom9346 *eeprom)
-{
-    int bit = eeprom->eedi?1:0;
-
-    ++ eeprom->tick;
-
-    DPRINTF("eeprom: tick %d eedi=%d eedo=%d\n", eeprom->tick, eeprom->eedi,
-        eeprom->eedo);
-
-    switch (eeprom->mode)
-    {
-        case Chip9346_enter_command_mode:
-            if (bit)
-            {
-                eeprom->mode = Chip9346_read_command;
-                eeprom->tick = 0;
-                eeprom->input = 0;
-                DPRINTF("eeprom: +++ synchronized, begin command read\n");
-            }
-            break;
-
-        case Chip9346_read_command:
-            eeprom->input = (eeprom->input << 1) | (bit & 1);
-            if (eeprom->tick == 8)
-            {
-                prom9346_decode_command(eeprom, eeprom->input & 0xff);
-            }
-            break;
-
-        case Chip9346_data_read:
-            eeprom->eedo = (eeprom->output & 0x8000)?1:0;
-            eeprom->output <<= 1;
-            if (eeprom->tick == 16)
-            {
-#if 1
-        // the FreeBSD drivers (rl and re) don't explicitly toggle
-        // CS between reads (or does setting Cfg9346 to 0 count too?),
-        // so we need to enter wait-for-command state here
-                eeprom->mode = Chip9346_enter_command_mode;
-                eeprom->input = 0;
-                eeprom->tick = 0;
-
-                DPRINTF("eeprom: +++ end of read, awaiting next command\n");
-#else
-        // original behaviour
-                ++eeprom->address;
-                eeprom->address &= EEPROM_9346_ADDR_MASK;
-                eeprom->output = eeprom->contents[eeprom->address];
-                eeprom->tick = 0;
-
-                DPRINTF("eeprom: +++ read next address 0x%02x data=0x%04x\n",
-                    eeprom->address, eeprom->output);
-#endif
-            }
-            break;
-
-        case Chip9346_data_write:
-            eeprom->input = (eeprom->input << 1) | (bit & 1);
-            if (eeprom->tick == 16)
-            {
-                DPRINTF("eeprom write to address 0x%02x data=0x%04x\n",
-                    eeprom->address, eeprom->input);
-
-                eeprom->contents[eeprom->address] = eeprom->input;
-                eeprom->mode = Chip9346_none; /* waiting for next command after CS cycle */
-                eeprom->tick = 0;
-                eeprom->input = 0;
-            }
-            break;
-
-        case Chip9346_data_write_all:
-            eeprom->input = (eeprom->input << 1) | (bit & 1);
-            if (eeprom->tick == 16)
-            {
-                int i;
-                for (i = 0; i < EEPROM_9346_SIZE; i++)
-                {
-                    eeprom->contents[i] = eeprom->input;
-                }
-                DPRINTF("eeprom filled with data=0x%04x\n", eeprom->input);
-
-                eeprom->mode = Chip9346_enter_command_mode;
-                eeprom->tick = 0;
-                eeprom->input = 0;
-            }
-            break;
-
-        default:
-            break;
-    }
-}
-
-static int prom9346_get_wire(RTL8139State *s)
-{
-    EEprom9346 *eeprom = &s->eeprom;
-    if (!eeprom->eecs)
-        return 0;
-
-    return eeprom->eedo;
-}
-
-/* FIXME: This should be merged into/replaced by eeprom93xx.c.  */
-static void prom9346_set_wire(RTL8139State *s, int eecs, int eesk, int eedi)
-{
-    EEprom9346 *eeprom = &s->eeprom;
-    uint8_t old_eecs = eeprom->eecs;
-    uint8_t old_eesk = eeprom->eesk;
-
-    eeprom->eecs = eecs;
-    eeprom->eesk = eesk;
-    eeprom->eedi = eedi;
-
-    DPRINTF("eeprom: +++ wires CS=%d SK=%d DI=%d DO=%d\n", eeprom->eecs,
-        eeprom->eesk, eeprom->eedi, eeprom->eedo);
-
-    if (!old_eecs && eecs)
-    {
-        /* Synchronize start */
-        eeprom->tick = 0;
-        eeprom->input = 0;
-        eeprom->output = 0;
-        eeprom->mode = Chip9346_enter_command_mode;
-
-        DPRINTF("=== eeprom: begin access, enter command mode\n");
-    }
-
-    if (!eecs)
-    {
-        DPRINTF("=== eeprom: end access\n");
-        return;
-    }
-
-    if (!old_eesk && eesk)
-    {
-        /* SK front rules */
-        prom9346_shift_clock(eeprom);
-    }
-}
-
-static void rtl8139_update_irq(RTL8139State *s)
-{
-    int isr;
-    isr = (s->IntrStatus & s->IntrMask) & 0xffff;
-
-    DPRINTF("Set IRQ to %d (%04x %04x)\n", isr ? 1 : 0, s->IntrStatus,
-        s->IntrMask);
-
-    qemu_set_irq(s->dev.irq[0], (isr != 0));
-}
-
-static int rtl8139_RxWrap(RTL8139State *s)
-{
-    /* wrapping enabled; assume 1.5k more buffer space if size < 65536 */
-    return (s->RxConfig & (1 << 7));
-}
-
-static int rtl8139_receiver_enabled(RTL8139State *s)
-{
-    return s->bChipCmdState & CmdRxEnb;
-}
-
-static int rtl8139_transmitter_enabled(RTL8139State *s)
-{
-    return s->bChipCmdState & CmdTxEnb;
-}
-
-static int rtl8139_cp_receiver_enabled(RTL8139State *s)
-{
-    return s->CpCmd & CPlusRxEnb;
-}
-
-static int rtl8139_cp_transmitter_enabled(RTL8139State *s)
-{
-    return s->CpCmd & CPlusTxEnb;
-}
-
-static void rtl8139_write_buffer(RTL8139State *s, const void *buf, int size)
-{
-    if (s->RxBufAddr + size > s->RxBufferSize)
-    {
-        int wrapped = MOD2(s->RxBufAddr + size, s->RxBufferSize);
-
-        /* write packet data */
-        if (wrapped && !(s->RxBufferSize < 65536 && rtl8139_RxWrap(s)))
-        {
-            DPRINTF(">>> rx packet wrapped in buffer at %d\n", size - wrapped);
-
-            if (size > wrapped)
-            {
-                pci_dma_write(&s->dev, s->RxBuf + s->RxBufAddr,
-                              buf, size-wrapped);
-            }
-
-            /* reset buffer pointer */
-            s->RxBufAddr = 0;
-
-            pci_dma_write(&s->dev, s->RxBuf + s->RxBufAddr,
-                          buf + (size-wrapped), wrapped);
-
-            s->RxBufAddr = wrapped;
-
-            return;
-        }
-    }
-
-    /* non-wrapping path or overwrapping enabled */
-    pci_dma_write(&s->dev, s->RxBuf + s->RxBufAddr, buf, size);
-
-    s->RxBufAddr += size;
-}
-
-#define MIN_BUF_SIZE 60
-static inline dma_addr_t rtl8139_addr64(uint32_t low, uint32_t high)
-{
-    return low | ((uint64_t)high << 32);
-}
-
-/* Workaround for buggy guest driver such as linux who allocates rx
- * rings after the receiver were enabled. */
-static bool rtl8139_cp_rx_valid(RTL8139State *s)
-{
-    return !(s->RxRingAddrLO == 0 && s->RxRingAddrHI == 0);
-}
-
-static int rtl8139_can_receive(NetClientState *nc)
-{
-    RTL8139State *s = qemu_get_nic_opaque(nc);
-    int avail;
-
-    /* Receive (drop) packets if card is disabled.  */
-    if (!s->clock_enabled)
-      return 1;
-    if (!rtl8139_receiver_enabled(s))
-      return 1;
-
-    if (rtl8139_cp_receiver_enabled(s) && rtl8139_cp_rx_valid(s)) {
-        /* ??? Flow control not implemented in c+ mode.
-           This is a hack to work around slirp deficiencies anyway.  */
-        return 1;
-    } else {
-        avail = MOD2(s->RxBufferSize + s->RxBufPtr - s->RxBufAddr,
-                     s->RxBufferSize);
-        return (avail == 0 || avail >= 1514 || (s->IntrMask & RxOverflow));
-    }
-}
-
-static ssize_t rtl8139_do_receive(NetClientState *nc, const uint8_t *buf, size_t size_, int do_interrupt)
-{
-    RTL8139State *s = qemu_get_nic_opaque(nc);
-    /* size is the length of the buffer passed to the driver */
-    int size = size_;
-    const uint8_t *dot1q_buf = NULL;
-
-    uint32_t packet_header = 0;
-
-    uint8_t buf1[MIN_BUF_SIZE + VLAN_HLEN];
-    static const uint8_t broadcast_macaddr[6] =
-        { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
-
-    DPRINTF(">>> received len=%d\n", size);
-
-    /* test if board clock is stopped */
-    if (!s->clock_enabled)
-    {
-        DPRINTF("stopped ==========================\n");
-        return -1;
-    }
-
-    /* first check if receiver is enabled */
-
-    if (!rtl8139_receiver_enabled(s))
-    {
-        DPRINTF("receiver disabled ================\n");
-        return -1;
-    }
-
-    /* XXX: check this */
-    if (s->RxConfig & AcceptAllPhys) {
-        /* promiscuous: receive all */
-        DPRINTF(">>> packet received in promiscuous mode\n");
-
-    } else {
-        if (!memcmp(buf,  broadcast_macaddr, 6)) {
-            /* broadcast address */
-            if (!(s->RxConfig & AcceptBroadcast))
-            {
-                DPRINTF(">>> broadcast packet rejected\n");
-
-                /* update tally counter */
-                ++s->tally_counters.RxERR;
-
-                return size;
-            }
-
-            packet_header |= RxBroadcast;
-
-            DPRINTF(">>> broadcast packet received\n");
-
-            /* update tally counter */
-            ++s->tally_counters.RxOkBrd;
-
-        } else if (buf[0] & 0x01) {
-            /* multicast */
-            if (!(s->RxConfig & AcceptMulticast))
-            {
-                DPRINTF(">>> multicast packet rejected\n");
-
-                /* update tally counter */
-                ++s->tally_counters.RxERR;
-
-                return size;
-            }
-
-            int mcast_idx = compute_mcast_idx(buf);
-
-            if (!(s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7))))
-            {
-                DPRINTF(">>> multicast address mismatch\n");
-
-                /* update tally counter */
-                ++s->tally_counters.RxERR;
-
-                return size;
-            }
-
-            packet_header |= RxMulticast;
-
-            DPRINTF(">>> multicast packet received\n");
-
-            /* update tally counter */
-            ++s->tally_counters.RxOkMul;
-
-        } else if (s->phys[0] == buf[0] &&
-                   s->phys[1] == buf[1] &&
-                   s->phys[2] == buf[2] &&
-                   s->phys[3] == buf[3] &&
-                   s->phys[4] == buf[4] &&
-                   s->phys[5] == buf[5]) {
-            /* match */
-            if (!(s->RxConfig & AcceptMyPhys))
-            {
-                DPRINTF(">>> rejecting physical address matching packet\n");
-
-                /* update tally counter */
-                ++s->tally_counters.RxERR;
-
-                return size;
-            }
-
-            packet_header |= RxPhysical;
-
-            DPRINTF(">>> physical address matching packet received\n");
-
-            /* update tally counter */
-            ++s->tally_counters.RxOkPhy;
-
-        } else {
-
-            DPRINTF(">>> unknown packet\n");
-
-            /* update tally counter */
-            ++s->tally_counters.RxERR;
-
-            return size;
-        }
-    }
-
-    /* if too small buffer, then expand it
-     * Include some tailroom in case a vlan tag is later removed. */
-    if (size < MIN_BUF_SIZE + VLAN_HLEN) {
-        memcpy(buf1, buf, size);
-        memset(buf1 + size, 0, MIN_BUF_SIZE + VLAN_HLEN - size);
-        buf = buf1;
-        if (size < MIN_BUF_SIZE) {
-            size = MIN_BUF_SIZE;
-        }
-    }
-
-    if (rtl8139_cp_receiver_enabled(s))
-    {
-        if (!rtl8139_cp_rx_valid(s)) {
-            return size;
-        }
-
-        DPRINTF("in C+ Rx mode ================\n");
-
-        /* begin C+ receiver mode */
-
-/* w0 ownership flag */
-#define CP_RX_OWN (1<<31)
-/* w0 end of ring flag */
-#define CP_RX_EOR (1<<30)
-/* w0 bits 0...12 : buffer size */
-#define CP_RX_BUFFER_SIZE_MASK ((1<<13) - 1)
-/* w1 tag available flag */
-#define CP_RX_TAVA (1<<16)
-/* w1 bits 0...15 : VLAN tag */
-#define CP_RX_VLAN_TAG_MASK ((1<<16) - 1)
-/* w2 low  32bit of Rx buffer ptr */
-/* w3 high 32bit of Rx buffer ptr */
-
-        int descriptor = s->currCPlusRxDesc;
-        dma_addr_t cplus_rx_ring_desc;
-
-        cplus_rx_ring_desc = rtl8139_addr64(s->RxRingAddrLO, s->RxRingAddrHI);
-        cplus_rx_ring_desc += 16 * descriptor;
-
-        DPRINTF("+++ C+ mode reading RX descriptor %d from host memory at "
-            "%08x %08x = "DMA_ADDR_FMT"\n", descriptor, s->RxRingAddrHI,
-            s->RxRingAddrLO, cplus_rx_ring_desc);
-
-        uint32_t val, rxdw0,rxdw1,rxbufLO,rxbufHI;
-
-        pci_dma_read(&s->dev, cplus_rx_ring_desc, &val, 4);
-        rxdw0 = le32_to_cpu(val);
-        pci_dma_read(&s->dev, cplus_rx_ring_desc+4, &val, 4);
-        rxdw1 = le32_to_cpu(val);
-        pci_dma_read(&s->dev, cplus_rx_ring_desc+8, &val, 4);
-        rxbufLO = le32_to_cpu(val);
-        pci_dma_read(&s->dev, cplus_rx_ring_desc+12, &val, 4);
-        rxbufHI = le32_to_cpu(val);
-
-        DPRINTF("+++ C+ mode RX descriptor %d %08x %08x %08x %08x\n",
-            descriptor, rxdw0, rxdw1, rxbufLO, rxbufHI);
-
-        if (!(rxdw0 & CP_RX_OWN))
-        {
-            DPRINTF("C+ Rx mode : descriptor %d is owned by host\n",
-                descriptor);
-
-            s->IntrStatus |= RxOverflow;
-            ++s->RxMissed;
-
-            /* update tally counter */
-            ++s->tally_counters.RxERR;
-            ++s->tally_counters.MissPkt;
-
-            rtl8139_update_irq(s);
-            return size_;
-        }
-
-        uint32_t rx_space = rxdw0 & CP_RX_BUFFER_SIZE_MASK;
-
-        /* write VLAN info to descriptor variables. */
-        if (s->CpCmd & CPlusRxVLAN && be16_to_cpup((uint16_t *)
-                &buf[ETHER_ADDR_LEN * 2]) == ETH_P_8021Q) {
-            dot1q_buf = &buf[ETHER_ADDR_LEN * 2];
-            size -= VLAN_HLEN;
-            /* if too small buffer, use the tailroom added duing expansion */
-            if (size < MIN_BUF_SIZE) {
-                size = MIN_BUF_SIZE;
-            }
-
-            rxdw1 &= ~CP_RX_VLAN_TAG_MASK;
-            /* BE + ~le_to_cpu()~ + cpu_to_le() = BE */
-            rxdw1 |= CP_RX_TAVA | le16_to_cpup((uint16_t *)
-                &dot1q_buf[ETHER_TYPE_LEN]);
-
-            DPRINTF("C+ Rx mode : extracted vlan tag with tci: ""%u\n",
-                be16_to_cpup((uint16_t *)&dot1q_buf[ETHER_TYPE_LEN]));
-        } else {
-            /* reset VLAN tag flag */
-            rxdw1 &= ~CP_RX_TAVA;
-        }
-
-        /* TODO: scatter the packet over available receive ring descriptors space */
-
-        if (size+4 > rx_space)
-        {
-            DPRINTF("C+ Rx mode : descriptor %d size %d received %d + 4\n",
-                descriptor, rx_space, size);
-
-            s->IntrStatus |= RxOverflow;
-            ++s->RxMissed;
-
-            /* update tally counter */
-            ++s->tally_counters.RxERR;
-            ++s->tally_counters.MissPkt;
-
-            rtl8139_update_irq(s);
-            return size_;
-        }
-
-        dma_addr_t rx_addr = rtl8139_addr64(rxbufLO, rxbufHI);
-
-        /* receive/copy to target memory */
-        if (dot1q_buf) {
-            pci_dma_write(&s->dev, rx_addr, buf, 2 * ETHER_ADDR_LEN);
-            pci_dma_write(&s->dev, rx_addr + 2 * ETHER_ADDR_LEN,
-                          buf + 2 * ETHER_ADDR_LEN + VLAN_HLEN,
-                          size - 2 * ETHER_ADDR_LEN);
-        } else {
-            pci_dma_write(&s->dev, rx_addr, buf, size);
-        }
-
-        if (s->CpCmd & CPlusRxChkSum)
-        {
-            /* do some packet checksumming */
-        }
-
-        /* write checksum */
-        val = cpu_to_le32(crc32(0, buf, size_));
-        pci_dma_write(&s->dev, rx_addr+size, (uint8_t *)&val, 4);
-
-/* first segment of received packet flag */
-#define CP_RX_STATUS_FS (1<<29)
-/* last segment of received packet flag */
-#define CP_RX_STATUS_LS (1<<28)
-/* multicast packet flag */
-#define CP_RX_STATUS_MAR (1<<26)
-/* physical-matching packet flag */
-#define CP_RX_STATUS_PAM (1<<25)
-/* broadcast packet flag */
-#define CP_RX_STATUS_BAR (1<<24)
-/* runt packet flag */
-#define CP_RX_STATUS_RUNT (1<<19)
-/* crc error flag */
-#define CP_RX_STATUS_CRC (1<<18)
-/* IP checksum error flag */
-#define CP_RX_STATUS_IPF (1<<15)
-/* UDP checksum error flag */
-#define CP_RX_STATUS_UDPF (1<<14)
-/* TCP checksum error flag */
-#define CP_RX_STATUS_TCPF (1<<13)
-
-        /* transfer ownership to target */
-        rxdw0 &= ~CP_RX_OWN;
-
-        /* set first segment bit */
-        rxdw0 |= CP_RX_STATUS_FS;
-
-        /* set last segment bit */
-        rxdw0 |= CP_RX_STATUS_LS;
-
-        /* set received packet type flags */
-        if (packet_header & RxBroadcast)
-            rxdw0 |= CP_RX_STATUS_BAR;
-        if (packet_header & RxMulticast)
-            rxdw0 |= CP_RX_STATUS_MAR;
-        if (packet_header & RxPhysical)
-            rxdw0 |= CP_RX_STATUS_PAM;
-
-        /* set received size */
-        rxdw0 &= ~CP_RX_BUFFER_SIZE_MASK;
-        rxdw0 |= (size+4);
-
-        /* update ring data */
-        val = cpu_to_le32(rxdw0);
-        pci_dma_write(&s->dev, cplus_rx_ring_desc, (uint8_t *)&val, 4);
-        val = cpu_to_le32(rxdw1);
-        pci_dma_write(&s->dev, cplus_rx_ring_desc+4, (uint8_t *)&val, 4);
-
-        /* update tally counter */
-        ++s->tally_counters.RxOk;
-
-        /* seek to next Rx descriptor */
-        if (rxdw0 & CP_RX_EOR)
-        {
-            s->currCPlusRxDesc = 0;
-        }
-        else
-        {
-            ++s->currCPlusRxDesc;
-        }
-
-        DPRINTF("done C+ Rx mode ----------------\n");
-
-    }
-    else
-    {
-        DPRINTF("in ring Rx mode ================\n");
-
-        /* begin ring receiver mode */
-        int avail = MOD2(s->RxBufferSize + s->RxBufPtr - s->RxBufAddr, s->RxBufferSize);
-
-        /* if receiver buffer is empty then avail == 0 */
-
-        if (avail != 0 && size + 8 >= avail)
-        {
-            DPRINTF("rx overflow: rx buffer length %d head 0x%04x "
-                "read 0x%04x === available 0x%04x need 0x%04x\n",
-                s->RxBufferSize, s->RxBufAddr, s->RxBufPtr, avail, size + 8);
-
-            s->IntrStatus |= RxOverflow;
-            ++s->RxMissed;
-            rtl8139_update_irq(s);
-            return size_;
-        }
-
-        packet_header |= RxStatusOK;
-
-        packet_header |= (((size+4) << 16) & 0xffff0000);
-
-        /* write header */
-        uint32_t val = cpu_to_le32(packet_header);
-
-        rtl8139_write_buffer(s, (uint8_t *)&val, 4);
-
-        rtl8139_write_buffer(s, buf, size);
-
-        /* write checksum */
-        val = cpu_to_le32(crc32(0, buf, size));
-        rtl8139_write_buffer(s, (uint8_t *)&val, 4);
-
-        /* correct buffer write pointer */
-        s->RxBufAddr = MOD2((s->RxBufAddr + 3) & ~0x3, s->RxBufferSize);
-
-        /* now we can signal we have received something */
-
-        DPRINTF("received: rx buffer length %d head 0x%04x read 0x%04x\n",
-            s->RxBufferSize, s->RxBufAddr, s->RxBufPtr);
-    }
-
-    s->IntrStatus |= RxOK;
-
-    if (do_interrupt)
-    {
-        rtl8139_update_irq(s);
-    }
-
-    return size_;
-}
-
-static ssize_t rtl8139_receive(NetClientState *nc, const uint8_t *buf, size_t size)
-{
-    return rtl8139_do_receive(nc, buf, size, 1);
-}
-
-static void rtl8139_reset_rxring(RTL8139State *s, uint32_t bufferSize)
-{
-    s->RxBufferSize = bufferSize;
-    s->RxBufPtr  = 0;
-    s->RxBufAddr = 0;
-}
-
-static void rtl8139_reset(DeviceState *d)
-{
-    RTL8139State *s = container_of(d, RTL8139State, dev.qdev);
-    int i;
-
-    /* restore MAC address */
-    memcpy(s->phys, s->conf.macaddr.a, 6);
-
-    /* reset interrupt mask */
-    s->IntrStatus = 0;
-    s->IntrMask = 0;
-
-    rtl8139_update_irq(s);
-
-    /* mark all status registers as owned by host */
-    for (i = 0; i < 4; ++i)
-    {
-        s->TxStatus[i] = TxHostOwns;
-    }
-
-    s->currTxDesc = 0;
-    s->currCPlusRxDesc = 0;
-    s->currCPlusTxDesc = 0;
-
-    s->RxRingAddrLO = 0;
-    s->RxRingAddrHI = 0;
-
-    s->RxBuf = 0;
-
-    rtl8139_reset_rxring(s, 8192);
-
-    /* ACK the reset */
-    s->TxConfig = 0;
-
-#if 0
-//    s->TxConfig |= HW_REVID(1, 0, 0, 0, 0, 0, 0); // RTL-8139  HasHltClk
-    s->clock_enabled = 0;
-#else
-    s->TxConfig |= HW_REVID(1, 1, 1, 0, 1, 1, 0); // RTL-8139C+ HasLWake
-    s->clock_enabled = 1;
-#endif
-
-    s->bChipCmdState = CmdReset; /* RxBufEmpty bit is calculated on read from ChipCmd */;
-
-    /* set initial state data */
-    s->Config0 = 0x0; /* No boot ROM */
-    s->Config1 = 0xC; /* IO mapped and MEM mapped registers available */
-    s->Config3 = 0x1; /* fast back-to-back compatible */
-    s->Config5 = 0x0;
-
-    s->CSCR = CSCR_F_LINK_100 | CSCR_HEART_BIT | CSCR_LD;
-
-    s->CpCmd   = 0x0; /* reset C+ mode */
-    s->cplus_enabled = 0;
-
-
-//    s->BasicModeCtrl = 0x3100; // 100Mbps, full duplex, autonegotiation
-//    s->BasicModeCtrl = 0x2100; // 100Mbps, full duplex
-    s->BasicModeCtrl = 0x1000; // autonegotiation
-
-    s->BasicModeStatus  = 0x7809;
-    //s->BasicModeStatus |= 0x0040; /* UTP medium */
-    s->BasicModeStatus |= 0x0020; /* autonegotiation completed */
-    /* preserve link state */
-    s->BasicModeStatus |= qemu_get_queue(s->nic)->link_down ? 0 : 0x04;
-
-    s->NWayAdvert    = 0x05e1; /* all modes, full duplex */
-    s->NWayLPAR      = 0x05e1; /* all modes, full duplex */
-    s->NWayExpansion = 0x0001; /* autonegotiation supported */
-
-    /* also reset timer and disable timer interrupt */
-    s->TCTR = 0;
-    s->TimerInt = 0;
-    s->TCTR_base = 0;
-
-    /* reset tally counters */
-    RTL8139TallyCounters_clear(&s->tally_counters);
-}
-
-static void RTL8139TallyCounters_clear(RTL8139TallyCounters* counters)
-{
-    counters->TxOk = 0;
-    counters->RxOk = 0;
-    counters->TxERR = 0;
-    counters->RxERR = 0;
-    counters->MissPkt = 0;
-    counters->FAE = 0;
-    counters->Tx1Col = 0;
-    counters->TxMCol = 0;
-    counters->RxOkPhy = 0;
-    counters->RxOkBrd = 0;
-    counters->RxOkMul = 0;
-    counters->TxAbt = 0;
-    counters->TxUndrn = 0;
-}
-
-static void RTL8139TallyCounters_dma_write(RTL8139State *s, dma_addr_t tc_addr)
-{
-    RTL8139TallyCounters *tally_counters = &s->tally_counters;
-    uint16_t val16;
-    uint32_t val32;
-    uint64_t val64;
-
-    val64 = cpu_to_le64(tally_counters->TxOk);
-    pci_dma_write(&s->dev, tc_addr + 0,     (uint8_t *)&val64, 8);
-
-    val64 = cpu_to_le64(tally_counters->RxOk);
-    pci_dma_write(&s->dev, tc_addr + 8,     (uint8_t *)&val64, 8);
-
-    val64 = cpu_to_le64(tally_counters->TxERR);
-    pci_dma_write(&s->dev, tc_addr + 16,    (uint8_t *)&val64, 8);
-
-    val32 = cpu_to_le32(tally_counters->RxERR);
-    pci_dma_write(&s->dev, tc_addr + 24,    (uint8_t *)&val32, 4);
-
-    val16 = cpu_to_le16(tally_counters->MissPkt);
-    pci_dma_write(&s->dev, tc_addr + 28,    (uint8_t *)&val16, 2);
-
-    val16 = cpu_to_le16(tally_counters->FAE);
-    pci_dma_write(&s->dev, tc_addr + 30,    (uint8_t *)&val16, 2);
-
-    val32 = cpu_to_le32(tally_counters->Tx1Col);
-    pci_dma_write(&s->dev, tc_addr + 32,    (uint8_t *)&val32, 4);
-
-    val32 = cpu_to_le32(tally_counters->TxMCol);
-    pci_dma_write(&s->dev, tc_addr + 36,    (uint8_t *)&val32, 4);
-
-    val64 = cpu_to_le64(tally_counters->RxOkPhy);
-    pci_dma_write(&s->dev, tc_addr + 40,    (uint8_t *)&val64, 8);
-
-    val64 = cpu_to_le64(tally_counters->RxOkBrd);
-    pci_dma_write(&s->dev, tc_addr + 48,    (uint8_t *)&val64, 8);
-
-    val32 = cpu_to_le32(tally_counters->RxOkMul);
-    pci_dma_write(&s->dev, tc_addr + 56,    (uint8_t *)&val32, 4);
-
-    val16 = cpu_to_le16(tally_counters->TxAbt);
-    pci_dma_write(&s->dev, tc_addr + 60,    (uint8_t *)&val16, 2);
-
-    val16 = cpu_to_le16(tally_counters->TxUndrn);
-    pci_dma_write(&s->dev, tc_addr + 62,    (uint8_t *)&val16, 2);
-}
-
-/* Loads values of tally counters from VM state file */
-
-static const VMStateDescription vmstate_tally_counters = {
-    .name = "tally_counters",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField []) {
-        VMSTATE_UINT64(TxOk, RTL8139TallyCounters),
-        VMSTATE_UINT64(RxOk, RTL8139TallyCounters),
-        VMSTATE_UINT64(TxERR, RTL8139TallyCounters),
-        VMSTATE_UINT32(RxERR, RTL8139TallyCounters),
-        VMSTATE_UINT16(MissPkt, RTL8139TallyCounters),
-        VMSTATE_UINT16(FAE, RTL8139TallyCounters),
-        VMSTATE_UINT32(Tx1Col, RTL8139TallyCounters),
-        VMSTATE_UINT32(TxMCol, RTL8139TallyCounters),
-        VMSTATE_UINT64(RxOkPhy, RTL8139TallyCounters),
-        VMSTATE_UINT64(RxOkBrd, RTL8139TallyCounters),
-        VMSTATE_UINT16(TxAbt, RTL8139TallyCounters),
-        VMSTATE_UINT16(TxUndrn, RTL8139TallyCounters),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void rtl8139_ChipCmd_write(RTL8139State *s, uint32_t val)
-{
-    val &= 0xff;
-
-    DPRINTF("ChipCmd write val=0x%08x\n", val);
-
-    if (val & CmdReset)
-    {
-        DPRINTF("ChipCmd reset\n");
-        rtl8139_reset(&s->dev.qdev);
-    }
-    if (val & CmdRxEnb)
-    {
-        DPRINTF("ChipCmd enable receiver\n");
-
-        s->currCPlusRxDesc = 0;
-    }
-    if (val & CmdTxEnb)
-    {
-        DPRINTF("ChipCmd enable transmitter\n");
-
-        s->currCPlusTxDesc = 0;
-    }
-
-    /* mask unwritable bits */
-    val = SET_MASKED(val, 0xe3, s->bChipCmdState);
-
-    /* Deassert reset pin before next read */
-    val &= ~CmdReset;
-
-    s->bChipCmdState = val;
-}
-
-static int rtl8139_RxBufferEmpty(RTL8139State *s)
-{
-    int unread = MOD2(s->RxBufferSize + s->RxBufAddr - s->RxBufPtr, s->RxBufferSize);
-
-    if (unread != 0)
-    {
-        DPRINTF("receiver buffer data available 0x%04x\n", unread);
-        return 0;
-    }
-
-    DPRINTF("receiver buffer is empty\n");
-
-    return 1;
-}
-
-static uint32_t rtl8139_ChipCmd_read(RTL8139State *s)
-{
-    uint32_t ret = s->bChipCmdState;
-
-    if (rtl8139_RxBufferEmpty(s))
-        ret |= RxBufEmpty;
-
-    DPRINTF("ChipCmd read val=0x%04x\n", ret);
-
-    return ret;
-}
-
-static void rtl8139_CpCmd_write(RTL8139State *s, uint32_t val)
-{
-    val &= 0xffff;
-
-    DPRINTF("C+ command register write(w) val=0x%04x\n", val);
-
-    s->cplus_enabled = 1;
-
-    /* mask unwritable bits */
-    val = SET_MASKED(val, 0xff84, s->CpCmd);
-
-    s->CpCmd = val;
-}
-
-static uint32_t rtl8139_CpCmd_read(RTL8139State *s)
-{
-    uint32_t ret = s->CpCmd;
-
-    DPRINTF("C+ command register read(w) val=0x%04x\n", ret);
-
-    return ret;
-}
-
-static void rtl8139_IntrMitigate_write(RTL8139State *s, uint32_t val)
-{
-    DPRINTF("C+ IntrMitigate register write(w) val=0x%04x\n", val);
-}
-
-static uint32_t rtl8139_IntrMitigate_read(RTL8139State *s)
-{
-    uint32_t ret = 0;
-
-    DPRINTF("C+ IntrMitigate register read(w) val=0x%04x\n", ret);
-
-    return ret;
-}
-
-static int rtl8139_config_writable(RTL8139State *s)
-{
-    if ((s->Cfg9346 & Chip9346_op_mask) == Cfg9346_ConfigWrite)
-    {
-        return 1;
-    }
-
-    DPRINTF("Configuration registers are write-protected\n");
-
-    return 0;
-}
-
-static void rtl8139_BasicModeCtrl_write(RTL8139State *s, uint32_t val)
-{
-    val &= 0xffff;
-
-    DPRINTF("BasicModeCtrl register write(w) val=0x%04x\n", val);
-
-    /* mask unwritable bits */
-    uint32_t mask = 0x4cff;
-
-    if (1 || !rtl8139_config_writable(s))
-    {
-        /* Speed setting and autonegotiation enable bits are read-only */
-        mask |= 0x3000;
-        /* Duplex mode setting is read-only */
-        mask |= 0x0100;
-    }
-
-    val = SET_MASKED(val, mask, s->BasicModeCtrl);
-
-    s->BasicModeCtrl = val;
-}
-
-static uint32_t rtl8139_BasicModeCtrl_read(RTL8139State *s)
-{
-    uint32_t ret = s->BasicModeCtrl;
-
-    DPRINTF("BasicModeCtrl register read(w) val=0x%04x\n", ret);
-
-    return ret;
-}
-
-static void rtl8139_BasicModeStatus_write(RTL8139State *s, uint32_t val)
-{
-    val &= 0xffff;
-
-    DPRINTF("BasicModeStatus register write(w) val=0x%04x\n", val);
-
-    /* mask unwritable bits */
-    val = SET_MASKED(val, 0xff3f, s->BasicModeStatus);
-
-    s->BasicModeStatus = val;
-}
-
-static uint32_t rtl8139_BasicModeStatus_read(RTL8139State *s)
-{
-    uint32_t ret = s->BasicModeStatus;
-
-    DPRINTF("BasicModeStatus register read(w) val=0x%04x\n", ret);
-
-    return ret;
-}
-
-static void rtl8139_Cfg9346_write(RTL8139State *s, uint32_t val)
-{
-    val &= 0xff;
-
-    DPRINTF("Cfg9346 write val=0x%02x\n", val);
-
-    /* mask unwritable bits */
-    val = SET_MASKED(val, 0x31, s->Cfg9346);
-
-    uint32_t opmode = val & 0xc0;
-    uint32_t eeprom_val = val & 0xf;
-
-    if (opmode == 0x80) {
-        /* eeprom access */
-        int eecs = (eeprom_val & 0x08)?1:0;
-        int eesk = (eeprom_val & 0x04)?1:0;
-        int eedi = (eeprom_val & 0x02)?1:0;
-        prom9346_set_wire(s, eecs, eesk, eedi);
-    } else if (opmode == 0x40) {
-        /* Reset.  */
-        val = 0;
-        rtl8139_reset(&s->dev.qdev);
-    }
-
-    s->Cfg9346 = val;
-}
-
-static uint32_t rtl8139_Cfg9346_read(RTL8139State *s)
-{
-    uint32_t ret = s->Cfg9346;
-
-    uint32_t opmode = ret & 0xc0;
-
-    if (opmode == 0x80)
-    {
-        /* eeprom access */
-        int eedo = prom9346_get_wire(s);
-        if (eedo)
-        {
-            ret |=  0x01;
-        }
-        else
-        {
-            ret &= ~0x01;
-        }
-    }
-
-    DPRINTF("Cfg9346 read val=0x%02x\n", ret);
-
-    return ret;
-}
-
-static void rtl8139_Config0_write(RTL8139State *s, uint32_t val)
-{
-    val &= 0xff;
-
-    DPRINTF("Config0 write val=0x%02x\n", val);
-
-    if (!rtl8139_config_writable(s)) {
-        return;
-    }
-
-    /* mask unwritable bits */
-    val = SET_MASKED(val, 0xf8, s->Config0);
-
-    s->Config0 = val;
-}
-
-static uint32_t rtl8139_Config0_read(RTL8139State *s)
-{
-    uint32_t ret = s->Config0;
-
-    DPRINTF("Config0 read val=0x%02x\n", ret);
-
-    return ret;
-}
-
-static void rtl8139_Config1_write(RTL8139State *s, uint32_t val)
-{
-    val &= 0xff;
-
-    DPRINTF("Config1 write val=0x%02x\n", val);
-
-    if (!rtl8139_config_writable(s)) {
-        return;
-    }
-
-    /* mask unwritable bits */
-    val = SET_MASKED(val, 0xC, s->Config1);
-
-    s->Config1 = val;
-}
-
-static uint32_t rtl8139_Config1_read(RTL8139State *s)
-{
-    uint32_t ret = s->Config1;
-
-    DPRINTF("Config1 read val=0x%02x\n", ret);
-
-    return ret;
-}
-
-static void rtl8139_Config3_write(RTL8139State *s, uint32_t val)
-{
-    val &= 0xff;
-
-    DPRINTF("Config3 write val=0x%02x\n", val);
-
-    if (!rtl8139_config_writable(s)) {
-        return;
-    }
-
-    /* mask unwritable bits */
-    val = SET_MASKED(val, 0x8F, s->Config3);
-
-    s->Config3 = val;
-}
-
-static uint32_t rtl8139_Config3_read(RTL8139State *s)
-{
-    uint32_t ret = s->Config3;
-
-    DPRINTF("Config3 read val=0x%02x\n", ret);
-
-    return ret;
-}
-
-static void rtl8139_Config4_write(RTL8139State *s, uint32_t val)
-{
-    val &= 0xff;
-
-    DPRINTF("Config4 write val=0x%02x\n", val);
-
-    if (!rtl8139_config_writable(s)) {
-        return;
-    }
-
-    /* mask unwritable bits */
-    val = SET_MASKED(val, 0x0a, s->Config4);
-
-    s->Config4 = val;
-}
-
-static uint32_t rtl8139_Config4_read(RTL8139State *s)
-{
-    uint32_t ret = s->Config4;
-
-    DPRINTF("Config4 read val=0x%02x\n", ret);
-
-    return ret;
-}
-
-static void rtl8139_Config5_write(RTL8139State *s, uint32_t val)
-{
-    val &= 0xff;
-
-    DPRINTF("Config5 write val=0x%02x\n", val);
-
-    /* mask unwritable bits */
-    val = SET_MASKED(val, 0x80, s->Config5);
-
-    s->Config5 = val;
-}
-
-static uint32_t rtl8139_Config5_read(RTL8139State *s)
-{
-    uint32_t ret = s->Config5;
-
-    DPRINTF("Config5 read val=0x%02x\n", ret);
-
-    return ret;
-}
-
-static void rtl8139_TxConfig_write(RTL8139State *s, uint32_t val)
-{
-    if (!rtl8139_transmitter_enabled(s))
-    {
-        DPRINTF("transmitter disabled; no TxConfig write val=0x%08x\n", val);
-        return;
-    }
-
-    DPRINTF("TxConfig write val=0x%08x\n", val);
-
-    val = SET_MASKED(val, TxVersionMask | 0x8070f80f, s->TxConfig);
-
-    s->TxConfig = val;
-}
-
-static void rtl8139_TxConfig_writeb(RTL8139State *s, uint32_t val)
-{
-    DPRINTF("RTL8139C TxConfig via write(b) val=0x%02x\n", val);
-
-    uint32_t tc = s->TxConfig;
-    tc &= 0xFFFFFF00;
-    tc |= (val & 0x000000FF);
-    rtl8139_TxConfig_write(s, tc);
-}
-
-static uint32_t rtl8139_TxConfig_read(RTL8139State *s)
-{
-    uint32_t ret = s->TxConfig;
-
-    DPRINTF("TxConfig read val=0x%04x\n", ret);
-
-    return ret;
-}
-
-static void rtl8139_RxConfig_write(RTL8139State *s, uint32_t val)
-{
-    DPRINTF("RxConfig write val=0x%08x\n", val);
-
-    /* mask unwritable bits */
-    val = SET_MASKED(val, 0xf0fc0040, s->RxConfig);
-
-    s->RxConfig = val;
-
-    /* reset buffer size and read/write pointers */
-    rtl8139_reset_rxring(s, 8192 << ((s->RxConfig >> 11) & 0x3));
-
-    DPRINTF("RxConfig write reset buffer size to %d\n", s->RxBufferSize);
-}
-
-static uint32_t rtl8139_RxConfig_read(RTL8139State *s)
-{
-    uint32_t ret = s->RxConfig;
-
-    DPRINTF("RxConfig read val=0x%08x\n", ret);
-
-    return ret;
-}
-
-static void rtl8139_transfer_frame(RTL8139State *s, uint8_t *buf, int size,
-    int do_interrupt, const uint8_t *dot1q_buf)
-{
-    struct iovec *iov = NULL;
-
-    if (!size)
-    {
-        DPRINTF("+++ empty ethernet frame\n");
-        return;
-    }
-
-    if (dot1q_buf && size >= ETHER_ADDR_LEN * 2) {
-        iov = (struct iovec[3]) {
-            { .iov_base = buf, .iov_len = ETHER_ADDR_LEN * 2 },
-            { .iov_base = (void *) dot1q_buf, .iov_len = VLAN_HLEN },
-            { .iov_base = buf + ETHER_ADDR_LEN * 2,
-                .iov_len = size - ETHER_ADDR_LEN * 2 },
-        };
-    }
-
-    if (TxLoopBack == (s->TxConfig & TxLoopBack))
-    {
-        size_t buf2_size;
-        uint8_t *buf2;
-
-        if (iov) {
-            buf2_size = iov_size(iov, 3);
-            buf2 = g_malloc(buf2_size);
-            iov_to_buf(iov, 3, 0, buf2, buf2_size);
-            buf = buf2;
-        }
-
-        DPRINTF("+++ transmit loopback mode\n");
-        rtl8139_do_receive(qemu_get_queue(s->nic), buf, size, do_interrupt);
-
-        if (iov) {
-            g_free(buf2);
-        }
-    }
-    else
-    {
-        if (iov) {
-            qemu_sendv_packet(qemu_get_queue(s->nic), iov, 3);
-        } else {
-            qemu_send_packet(qemu_get_queue(s->nic), buf, size);
-        }
-    }
-}
-
-static int rtl8139_transmit_one(RTL8139State *s, int descriptor)
-{
-    if (!rtl8139_transmitter_enabled(s))
-    {
-        DPRINTF("+++ cannot transmit from descriptor %d: transmitter "
-            "disabled\n", descriptor);
-        return 0;
-    }
-
-    if (s->TxStatus[descriptor] & TxHostOwns)
-    {
-        DPRINTF("+++ cannot transmit from descriptor %d: owned by host "
-            "(%08x)\n", descriptor, s->TxStatus[descriptor]);
-        return 0;
-    }
-
-    DPRINTF("+++ transmitting from descriptor %d\n", descriptor);
-
-    int txsize = s->TxStatus[descriptor] & 0x1fff;
-    uint8_t txbuffer[0x2000];
-
-    DPRINTF("+++ transmit reading %d bytes from host memory at 0x%08x\n",
-        txsize, s->TxAddr[descriptor]);
-
-    pci_dma_read(&s->dev, s->TxAddr[descriptor], txbuffer, txsize);
-
-    /* Mark descriptor as transferred */
-    s->TxStatus[descriptor] |= TxHostOwns;
-    s->TxStatus[descriptor] |= TxStatOK;
-
-    rtl8139_transfer_frame(s, txbuffer, txsize, 0, NULL);
-
-    DPRINTF("+++ transmitted %d bytes from descriptor %d\n", txsize,
-        descriptor);
-
-    /* update interrupt */
-    s->IntrStatus |= TxOK;
-    rtl8139_update_irq(s);
-
-    return 1;
-}
-
-/* structures and macros for task offloading */
-typedef struct ip_header
-{
-    uint8_t  ip_ver_len;    /* version and header length */
-    uint8_t  ip_tos;        /* type of service */
-    uint16_t ip_len;        /* total length */
-    uint16_t ip_id;         /* identification */
-    uint16_t ip_off;        /* fragment offset field */
-    uint8_t  ip_ttl;        /* time to live */
-    uint8_t  ip_p;          /* protocol */
-    uint16_t ip_sum;        /* checksum */
-    uint32_t ip_src,ip_dst; /* source and dest address */
-} ip_header;
-
-#define IP_HEADER_VERSION_4 4
-#define IP_HEADER_VERSION(ip) ((ip->ip_ver_len >> 4)&0xf)
-#define IP_HEADER_LENGTH(ip) (((ip->ip_ver_len)&0xf) << 2)
-
-typedef struct tcp_header
-{
-    uint16_t th_sport;         /* source port */
-    uint16_t th_dport;         /* destination port */
-    uint32_t th_seq;                   /* sequence number */
-    uint32_t th_ack;                   /* acknowledgement number */
-    uint16_t th_offset_flags; /* data offset, reserved 6 bits, TCP protocol flags */
-    uint16_t th_win;                   /* window */
-    uint16_t th_sum;                   /* checksum */
-    uint16_t th_urp;                   /* urgent pointer */
-} tcp_header;
-
-typedef struct udp_header
-{
-    uint16_t uh_sport; /* source port */
-    uint16_t uh_dport; /* destination port */
-    uint16_t uh_ulen;  /* udp length */
-    uint16_t uh_sum;   /* udp checksum */
-} udp_header;
-
-typedef struct ip_pseudo_header
-{
-    uint32_t ip_src;
-    uint32_t ip_dst;
-    uint8_t  zeros;
-    uint8_t  ip_proto;
-    uint16_t ip_payload;
-} ip_pseudo_header;
-
-#define IP_PROTO_TCP 6
-#define IP_PROTO_UDP 17
-
-#define TCP_HEADER_DATA_OFFSET(tcp) (((be16_to_cpu(tcp->th_offset_flags) >> 12)&0xf) << 2)
-#define TCP_FLAGS_ONLY(flags) ((flags)&0x3f)
-#define TCP_HEADER_FLAGS(tcp) TCP_FLAGS_ONLY(be16_to_cpu(tcp->th_offset_flags))
-
-#define TCP_HEADER_CLEAR_FLAGS(tcp, off) ((tcp)->th_offset_flags &= cpu_to_be16(~TCP_FLAGS_ONLY(off)))
-
-#define TCP_FLAG_FIN  0x01
-#define TCP_FLAG_PUSH 0x08
-
-/* produces ones' complement sum of data */
-static uint16_t ones_complement_sum(uint8_t *data, size_t len)
-{
-    uint32_t result = 0;
-
-    for (; len > 1; data+=2, len-=2)
-    {
-        result += *(uint16_t*)data;
-    }
-
-    /* add the remainder byte */
-    if (len)
-    {
-        uint8_t odd[2] = {*data, 0};
-        result += *(uint16_t*)odd;
-    }
-
-    while (result>>16)
-        result = (result & 0xffff) + (result >> 16);
-
-    return result;
-}
-
-static uint16_t ip_checksum(void *data, size_t len)
-{
-    return ~ones_complement_sum((uint8_t*)data, len);
-}
-
-static int rtl8139_cplus_transmit_one(RTL8139State *s)
-{
-    if (!rtl8139_transmitter_enabled(s))
-    {
-        DPRINTF("+++ C+ mode: transmitter disabled\n");
-        return 0;
-    }
-
-    if (!rtl8139_cp_transmitter_enabled(s))
-    {
-        DPRINTF("+++ C+ mode: C+ transmitter disabled\n");
-        return 0 ;
-    }
-
-    int descriptor = s->currCPlusTxDesc;
-
-    dma_addr_t cplus_tx_ring_desc = rtl8139_addr64(s->TxAddr[0], s->TxAddr[1]);
-
-    /* Normal priority ring */
-    cplus_tx_ring_desc += 16 * descriptor;
-
-    DPRINTF("+++ C+ mode reading TX descriptor %d from host memory at "
-        "%08x %08x = 0x"DMA_ADDR_FMT"\n", descriptor, s->TxAddr[1],
-        s->TxAddr[0], cplus_tx_ring_desc);
-
-    uint32_t val, txdw0,txdw1,txbufLO,txbufHI;
-
-    pci_dma_read(&s->dev, cplus_tx_ring_desc,    (uint8_t *)&val, 4);
-    txdw0 = le32_to_cpu(val);
-    pci_dma_read(&s->dev, cplus_tx_ring_desc+4,  (uint8_t *)&val, 4);
-    txdw1 = le32_to_cpu(val);
-    pci_dma_read(&s->dev, cplus_tx_ring_desc+8,  (uint8_t *)&val, 4);
-    txbufLO = le32_to_cpu(val);
-    pci_dma_read(&s->dev, cplus_tx_ring_desc+12, (uint8_t *)&val, 4);
-    txbufHI = le32_to_cpu(val);
-
-    DPRINTF("+++ C+ mode TX descriptor %d %08x %08x %08x %08x\n", descriptor,
-        txdw0, txdw1, txbufLO, txbufHI);
-
-/* w0 ownership flag */
-#define CP_TX_OWN (1<<31)
-/* w0 end of ring flag */
-#define CP_TX_EOR (1<<30)
-/* first segment of received packet flag */
-#define CP_TX_FS (1<<29)
-/* last segment of received packet flag */
-#define CP_TX_LS (1<<28)
-/* large send packet flag */
-#define CP_TX_LGSEN (1<<27)
-/* large send MSS mask, bits 16...25 */
-#define CP_TC_LGSEN_MSS_MASK ((1 << 12) - 1)
-
-/* IP checksum offload flag */
-#define CP_TX_IPCS (1<<18)
-/* UDP checksum offload flag */
-#define CP_TX_UDPCS (1<<17)
-/* TCP checksum offload flag */
-#define CP_TX_TCPCS (1<<16)
-
-/* w0 bits 0...15 : buffer size */
-#define CP_TX_BUFFER_SIZE (1<<16)
-#define CP_TX_BUFFER_SIZE_MASK (CP_TX_BUFFER_SIZE - 1)
-/* w1 add tag flag */
-#define CP_TX_TAGC (1<<17)
-/* w1 bits 0...15 : VLAN tag (big endian) */
-#define CP_TX_VLAN_TAG_MASK ((1<<16) - 1)
-/* w2 low  32bit of Rx buffer ptr */
-/* w3 high 32bit of Rx buffer ptr */
-
-/* set after transmission */
-/* FIFO underrun flag */
-#define CP_TX_STATUS_UNF (1<<25)
-/* transmit error summary flag, valid if set any of three below */
-#define CP_TX_STATUS_TES (1<<23)
-/* out-of-window collision flag */
-#define CP_TX_STATUS_OWC (1<<22)
-/* link failure flag */
-#define CP_TX_STATUS_LNKF (1<<21)
-/* excessive collisions flag */
-#define CP_TX_STATUS_EXC (1<<20)
-
-    if (!(txdw0 & CP_TX_OWN))
-    {
-        DPRINTF("C+ Tx mode : descriptor %d is owned by host\n", descriptor);
-        return 0 ;
-    }
-
-    DPRINTF("+++ C+ Tx mode : transmitting from descriptor %d\n", descriptor);
-
-    if (txdw0 & CP_TX_FS)
-    {
-        DPRINTF("+++ C+ Tx mode : descriptor %d is first segment "
-            "descriptor\n", descriptor);
-
-        /* reset internal buffer offset */
-        s->cplus_txbuffer_offset = 0;
-    }
-
-    int txsize = txdw0 & CP_TX_BUFFER_SIZE_MASK;
-    dma_addr_t tx_addr = rtl8139_addr64(txbufLO, txbufHI);
-
-    /* make sure we have enough space to assemble the packet */
-    if (!s->cplus_txbuffer)
-    {
-        s->cplus_txbuffer_len = CP_TX_BUFFER_SIZE;
-        s->cplus_txbuffer = g_malloc(s->cplus_txbuffer_len);
-        s->cplus_txbuffer_offset = 0;
-
-        DPRINTF("+++ C+ mode transmission buffer allocated space %d\n",
-            s->cplus_txbuffer_len);
-    }
-
-    if (s->cplus_txbuffer_offset + txsize >= s->cplus_txbuffer_len)
-    {
-        /* The spec didn't tell the maximum size, stick to CP_TX_BUFFER_SIZE */
-        txsize = s->cplus_txbuffer_len - s->cplus_txbuffer_offset;
-        DPRINTF("+++ C+ mode transmission buffer overrun, truncated descriptor"
-                "length to %d\n", txsize);
-    }
-
-    if (!s->cplus_txbuffer)
-    {
-        /* out of memory */
-
-        DPRINTF("+++ C+ mode transmiter failed to reallocate %d bytes\n",
-            s->cplus_txbuffer_len);
-
-        /* update tally counter */
-        ++s->tally_counters.TxERR;
-        ++s->tally_counters.TxAbt;
-
-        return 0;
-    }
-
-    /* append more data to the packet */
-
-    DPRINTF("+++ C+ mode transmit reading %d bytes from host memory at "
-            DMA_ADDR_FMT" to offset %d\n", txsize, tx_addr,
-            s->cplus_txbuffer_offset);
-
-    pci_dma_read(&s->dev, tx_addr,
-                 s->cplus_txbuffer + s->cplus_txbuffer_offset, txsize);
-    s->cplus_txbuffer_offset += txsize;
-
-    /* seek to next Rx descriptor */
-    if (txdw0 & CP_TX_EOR)
-    {
-        s->currCPlusTxDesc = 0;
-    }
-    else
-    {
-        ++s->currCPlusTxDesc;
-        if (s->currCPlusTxDesc >= 64)
-            s->currCPlusTxDesc = 0;
-    }
-
-    /* transfer ownership to target */
-    txdw0 &= ~CP_RX_OWN;
-
-    /* reset error indicator bits */
-    txdw0 &= ~CP_TX_STATUS_UNF;
-    txdw0 &= ~CP_TX_STATUS_TES;
-    txdw0 &= ~CP_TX_STATUS_OWC;
-    txdw0 &= ~CP_TX_STATUS_LNKF;
-    txdw0 &= ~CP_TX_STATUS_EXC;
-
-    /* update ring data */
-    val = cpu_to_le32(txdw0);
-    pci_dma_write(&s->dev, cplus_tx_ring_desc, (uint8_t *)&val, 4);
-
-    /* Now decide if descriptor being processed is holding the last segment of packet */
-    if (txdw0 & CP_TX_LS)
-    {
-        uint8_t dot1q_buffer_space[VLAN_HLEN];
-        uint16_t *dot1q_buffer;
-
-        DPRINTF("+++ C+ Tx mode : descriptor %d is last segment descriptor\n",
-            descriptor);
-
-        /* can transfer fully assembled packet */
-
-        uint8_t *saved_buffer  = s->cplus_txbuffer;
-        int      saved_size    = s->cplus_txbuffer_offset;
-        int      saved_buffer_len = s->cplus_txbuffer_len;
-
-        /* create vlan tag */
-        if (txdw1 & CP_TX_TAGC) {
-            /* the vlan tag is in BE byte order in the descriptor
-             * BE + le_to_cpu() + ~swap()~ = cpu */
-            DPRINTF("+++ C+ Tx mode : inserting vlan tag with ""tci: %u\n",
-                bswap16(txdw1 & CP_TX_VLAN_TAG_MASK));
-
-            dot1q_buffer = (uint16_t *) dot1q_buffer_space;
-            dot1q_buffer[0] = cpu_to_be16(ETH_P_8021Q);
-            /* BE + le_to_cpu() + ~cpu_to_le()~ = BE */
-            dot1q_buffer[1] = cpu_to_le16(txdw1 & CP_TX_VLAN_TAG_MASK);
-        } else {
-            dot1q_buffer = NULL;
-        }
-
-        /* reset the card space to protect from recursive call */
-        s->cplus_txbuffer = NULL;
-        s->cplus_txbuffer_offset = 0;
-        s->cplus_txbuffer_len = 0;
-
-        if (txdw0 & (CP_TX_IPCS | CP_TX_UDPCS | CP_TX_TCPCS | CP_TX_LGSEN))
-        {
-            DPRINTF("+++ C+ mode offloaded task checksum\n");
-
-            /* ip packet header */
-            ip_header *ip = NULL;
-            int hlen = 0;
-            uint8_t  ip_protocol = 0;
-            uint16_t ip_data_len = 0;
-
-            uint8_t *eth_payload_data = NULL;
-            size_t   eth_payload_len  = 0;
-
-            int proto = be16_to_cpu(*(uint16_t *)(saved_buffer + 12));
-            if (proto == ETH_P_IP)
-            {
-                DPRINTF("+++ C+ mode has IP packet\n");
-
-                /* not aligned */
-                eth_payload_data = saved_buffer + ETH_HLEN;
-                eth_payload_len  = saved_size   - ETH_HLEN;
-
-                ip = (ip_header*)eth_payload_data;
-
-                if (IP_HEADER_VERSION(ip) != IP_HEADER_VERSION_4) {
-                    DPRINTF("+++ C+ mode packet has bad IP version %d "
-                        "expected %d\n", IP_HEADER_VERSION(ip),
-                        IP_HEADER_VERSION_4);
-                    ip = NULL;
-                } else {
-                    hlen = IP_HEADER_LENGTH(ip);
-                    ip_protocol = ip->ip_p;
-                    ip_data_len = be16_to_cpu(ip->ip_len) - hlen;
-                }
-            }
-
-            if (ip)
-            {
-                if (txdw0 & CP_TX_IPCS)
-                {
-                    DPRINTF("+++ C+ mode need IP checksum\n");
-
-                    if (hlen<sizeof(ip_header) || hlen>eth_payload_len) {/* min header length */
-                        /* bad packet header len */
-                        /* or packet too short */
-                    }
-                    else
-                    {
-                        ip->ip_sum = 0;
-                        ip->ip_sum = ip_checksum(ip, hlen);
-                        DPRINTF("+++ C+ mode IP header len=%d checksum=%04x\n",
-                            hlen, ip->ip_sum);
-                    }
-                }
-
-                if ((txdw0 & CP_TX_LGSEN) && ip_protocol == IP_PROTO_TCP)
-                {
-                    int large_send_mss = (txdw0 >> 16) & CP_TC_LGSEN_MSS_MASK;
-
-                    DPRINTF("+++ C+ mode offloaded task TSO MTU=%d IP data %d "
-                        "frame data %d specified MSS=%d\n", ETH_MTU,
-                        ip_data_len, saved_size - ETH_HLEN, large_send_mss);
-
-                    int tcp_send_offset = 0;
-                    int send_count = 0;
-
-                    /* maximum IP header length is 60 bytes */
-                    uint8_t saved_ip_header[60];
-
-                    /* save IP header template; data area is used in tcp checksum calculation */
-                    memcpy(saved_ip_header, eth_payload_data, hlen);
-
-                    /* a placeholder for checksum calculation routine in tcp case */
-                    uint8_t *data_to_checksum     = eth_payload_data + hlen - 12;
-                    //                    size_t   data_to_checksum_len = eth_payload_len  - hlen + 12;
-
-                    /* pointer to TCP header */
-                    tcp_header *p_tcp_hdr = (tcp_header*)(eth_payload_data + hlen);
-
-                    int tcp_hlen = TCP_HEADER_DATA_OFFSET(p_tcp_hdr);
-
-                    /* ETH_MTU = ip header len + tcp header len + payload */
-                    int tcp_data_len = ip_data_len - tcp_hlen;
-                    int tcp_chunk_size = ETH_MTU - hlen - tcp_hlen;
-
-                    DPRINTF("+++ C+ mode TSO IP data len %d TCP hlen %d TCP "
-                        "data len %d TCP chunk size %d\n", ip_data_len,
-                        tcp_hlen, tcp_data_len, tcp_chunk_size);
-
-                    /* note the cycle below overwrites IP header data,
-                       but restores it from saved_ip_header before sending packet */
-
-                    int is_last_frame = 0;
-
-                    for (tcp_send_offset = 0; tcp_send_offset < tcp_data_len; tcp_send_offset += tcp_chunk_size)
-                    {
-                        uint16_t chunk_size = tcp_chunk_size;
-
-                        /* check if this is the last frame */
-                        if (tcp_send_offset + tcp_chunk_size >= tcp_data_len)
-                        {
-                            is_last_frame = 1;
-                            chunk_size = tcp_data_len - tcp_send_offset;
-                        }
-
-                        DPRINTF("+++ C+ mode TSO TCP seqno %08x\n",
-                            be32_to_cpu(p_tcp_hdr->th_seq));
-
-                        /* add 4 TCP pseudoheader fields */
-                        /* copy IP source and destination fields */
-                        memcpy(data_to_checksum, saved_ip_header + 12, 8);
-
-                        DPRINTF("+++ C+ mode TSO calculating TCP checksum for "
-                            "packet with %d bytes data\n", tcp_hlen +
-                            chunk_size);
-
-                        if (tcp_send_offset)
-                        {
-                            memcpy((uint8_t*)p_tcp_hdr + tcp_hlen, (uint8_t*)p_tcp_hdr + tcp_hlen + tcp_send_offset, chunk_size);
-                        }
-
-                        /* keep PUSH and FIN flags only for the last frame */
-                        if (!is_last_frame)
-                        {
-                            TCP_HEADER_CLEAR_FLAGS(p_tcp_hdr, TCP_FLAG_PUSH|TCP_FLAG_FIN);
-                        }
-
-                        /* recalculate TCP checksum */
-                        ip_pseudo_header *p_tcpip_hdr = (ip_pseudo_header *)data_to_checksum;
-                        p_tcpip_hdr->zeros      = 0;
-                        p_tcpip_hdr->ip_proto   = IP_PROTO_TCP;
-                        p_tcpip_hdr->ip_payload = cpu_to_be16(tcp_hlen + chunk_size);
-
-                        p_tcp_hdr->th_sum = 0;
-
-                        int tcp_checksum = ip_checksum(data_to_checksum, tcp_hlen + chunk_size + 12);
-                        DPRINTF("+++ C+ mode TSO TCP checksum %04x\n",
-                            tcp_checksum);
-
-                        p_tcp_hdr->th_sum = tcp_checksum;
-
-                        /* restore IP header */
-                        memcpy(eth_payload_data, saved_ip_header, hlen);
-
-                        /* set IP data length and recalculate IP checksum */
-                        ip->ip_len = cpu_to_be16(hlen + tcp_hlen + chunk_size);
-
-                        /* increment IP id for subsequent frames */
-                        ip->ip_id = cpu_to_be16(tcp_send_offset/tcp_chunk_size + be16_to_cpu(ip->ip_id));
-
-                        ip->ip_sum = 0;
-                        ip->ip_sum = ip_checksum(eth_payload_data, hlen);
-                        DPRINTF("+++ C+ mode TSO IP header len=%d "
-                            "checksum=%04x\n", hlen, ip->ip_sum);
-
-                        int tso_send_size = ETH_HLEN + hlen + tcp_hlen + chunk_size;
-                        DPRINTF("+++ C+ mode TSO transferring packet size "
-                            "%d\n", tso_send_size);
-                        rtl8139_transfer_frame(s, saved_buffer, tso_send_size,
-                            0, (uint8_t *) dot1q_buffer);
-
-                        /* add transferred count to TCP sequence number */
-                        p_tcp_hdr->th_seq = cpu_to_be32(chunk_size + be32_to_cpu(p_tcp_hdr->th_seq));
-                        ++send_count;
-                    }
-
-                    /* Stop sending this frame */
-                    saved_size = 0;
-                }
-                else if (txdw0 & (CP_TX_TCPCS|CP_TX_UDPCS))
-                {
-                    DPRINTF("+++ C+ mode need TCP or UDP checksum\n");
-
-                    /* maximum IP header length is 60 bytes */
-                    uint8_t saved_ip_header[60];
-                    memcpy(saved_ip_header, eth_payload_data, hlen);
-
-                    uint8_t *data_to_checksum     = eth_payload_data + hlen - 12;
-                    //                    size_t   data_to_checksum_len = eth_payload_len  - hlen + 12;
-
-                    /* add 4 TCP pseudoheader fields */
-                    /* copy IP source and destination fields */
-                    memcpy(data_to_checksum, saved_ip_header + 12, 8);
-
-                    if ((txdw0 & CP_TX_TCPCS) && ip_protocol == IP_PROTO_TCP)
-                    {
-                        DPRINTF("+++ C+ mode calculating TCP checksum for "
-                            "packet with %d bytes data\n", ip_data_len);
-
-                        ip_pseudo_header *p_tcpip_hdr = (ip_pseudo_header *)data_to_checksum;
-                        p_tcpip_hdr->zeros      = 0;
-                        p_tcpip_hdr->ip_proto   = IP_PROTO_TCP;
-                        p_tcpip_hdr->ip_payload = cpu_to_be16(ip_data_len);
-
-                        tcp_header* p_tcp_hdr = (tcp_header *) (data_to_checksum+12);
-
-                        p_tcp_hdr->th_sum = 0;
-
-                        int tcp_checksum = ip_checksum(data_to_checksum, ip_data_len + 12);
-                        DPRINTF("+++ C+ mode TCP checksum %04x\n",
-                            tcp_checksum);
-
-                        p_tcp_hdr->th_sum = tcp_checksum;
-                    }
-                    else if ((txdw0 & CP_TX_UDPCS) && ip_protocol == IP_PROTO_UDP)
-                    {
-                        DPRINTF("+++ C+ mode calculating UDP checksum for "
-                            "packet with %d bytes data\n", ip_data_len);
-
-                        ip_pseudo_header *p_udpip_hdr = (ip_pseudo_header *)data_to_checksum;
-                        p_udpip_hdr->zeros      = 0;
-                        p_udpip_hdr->ip_proto   = IP_PROTO_UDP;
-                        p_udpip_hdr->ip_payload = cpu_to_be16(ip_data_len);
-
-                        udp_header *p_udp_hdr = (udp_header *) (data_to_checksum+12);
-
-                        p_udp_hdr->uh_sum = 0;
-
-                        int udp_checksum = ip_checksum(data_to_checksum, ip_data_len + 12);
-                        DPRINTF("+++ C+ mode UDP checksum %04x\n",
-                            udp_checksum);
-
-                        p_udp_hdr->uh_sum = udp_checksum;
-                    }
-
-                    /* restore IP header */
-                    memcpy(eth_payload_data, saved_ip_header, hlen);
-                }
-            }
-        }
-
-        /* update tally counter */
-        ++s->tally_counters.TxOk;
-
-        DPRINTF("+++ C+ mode transmitting %d bytes packet\n", saved_size);
-
-        rtl8139_transfer_frame(s, saved_buffer, saved_size, 1,
-            (uint8_t *) dot1q_buffer);
-
-        /* restore card space if there was no recursion and reset offset */
-        if (!s->cplus_txbuffer)
-        {
-            s->cplus_txbuffer        = saved_buffer;
-            s->cplus_txbuffer_len    = saved_buffer_len;
-            s->cplus_txbuffer_offset = 0;
-        }
-        else
-        {
-            g_free(saved_buffer);
-        }
-    }
-    else
-    {
-        DPRINTF("+++ C+ mode transmission continue to next descriptor\n");
-    }
-
-    return 1;
-}
-
-static void rtl8139_cplus_transmit(RTL8139State *s)
-{
-    int txcount = 0;
-
-    while (rtl8139_cplus_transmit_one(s))
-    {
-        ++txcount;
-    }
-
-    /* Mark transfer completed */
-    if (!txcount)
-    {
-        DPRINTF("C+ mode : transmitter queue stalled, current TxDesc = %d\n",
-            s->currCPlusTxDesc);
-    }
-    else
-    {
-        /* update interrupt status */
-        s->IntrStatus |= TxOK;
-        rtl8139_update_irq(s);
-    }
-}
-
-static void rtl8139_transmit(RTL8139State *s)
-{
-    int descriptor = s->currTxDesc, txcount = 0;
-
-    /*while*/
-    if (rtl8139_transmit_one(s, descriptor))
-    {
-        ++s->currTxDesc;
-        s->currTxDesc %= 4;
-        ++txcount;
-    }
-
-    /* Mark transfer completed */
-    if (!txcount)
-    {
-        DPRINTF("transmitter queue stalled, current TxDesc = %d\n",
-            s->currTxDesc);
-    }
-}
-
-static void rtl8139_TxStatus_write(RTL8139State *s, uint32_t txRegOffset, uint32_t val)
-{
-
-    int descriptor = txRegOffset/4;
-
-    /* handle C+ transmit mode register configuration */
-
-    if (s->cplus_enabled)
-    {
-        DPRINTF("RTL8139C+ DTCCR write offset=0x%x val=0x%08x "
-            "descriptor=%d\n", txRegOffset, val, descriptor);
-
-        /* handle Dump Tally Counters command */
-        s->TxStatus[descriptor] = val;
-
-        if (descriptor == 0 && (val & 0x8))
-        {
-            hwaddr tc_addr = rtl8139_addr64(s->TxStatus[0] & ~0x3f, s->TxStatus[1]);
-
-            /* dump tally counters to specified memory location */
-            RTL8139TallyCounters_dma_write(s, tc_addr);
-
-            /* mark dump completed */
-            s->TxStatus[0] &= ~0x8;
-        }
-
-        return;
-    }
-
-    DPRINTF("TxStatus write offset=0x%x val=0x%08x descriptor=%d\n",
-        txRegOffset, val, descriptor);
-
-    /* mask only reserved bits */
-    val &= ~0xff00c000; /* these bits are reset on write */
-    val = SET_MASKED(val, 0x00c00000, s->TxStatus[descriptor]);
-
-    s->TxStatus[descriptor] = val;
-
-    /* attempt to start transmission */
-    rtl8139_transmit(s);
-}
-
-static uint32_t rtl8139_TxStatus_TxAddr_read(RTL8139State *s, uint32_t regs[],
-                                             uint32_t base, uint8_t addr,
-                                             int size)
-{
-    uint32_t reg = (addr - base) / 4;
-    uint32_t offset = addr & 0x3;
-    uint32_t ret = 0;
-
-    if (addr & (size - 1)) {
-        DPRINTF("not implemented read for TxStatus/TxAddr "
-                "addr=0x%x size=0x%x\n", addr, size);
-        return ret;
-    }
-
-    switch (size) {
-    case 1: /* fall through */
-    case 2: /* fall through */
-    case 4:
-        ret = (regs[reg] >> offset * 8) & (((uint64_t)1 << (size * 8)) - 1);
-        DPRINTF("TxStatus/TxAddr[%d] read addr=0x%x size=0x%x val=0x%08x\n",
-                reg, addr, size, ret);
-        break;
-    default:
-        DPRINTF("unsupported size 0x%x of TxStatus/TxAddr reading\n", size);
-        break;
-    }
-
-    return ret;
-}
-
-static uint16_t rtl8139_TSAD_read(RTL8139State *s)
-{
-    uint16_t ret = 0;
-
-    /* Simulate TSAD, it is read only anyway */
-
-    ret = ((s->TxStatus[3] & TxStatOK  )?TSAD_TOK3:0)
-         |((s->TxStatus[2] & TxStatOK  )?TSAD_TOK2:0)
-         |((s->TxStatus[1] & TxStatOK  )?TSAD_TOK1:0)
-         |((s->TxStatus[0] & TxStatOK  )?TSAD_TOK0:0)
-
-         |((s->TxStatus[3] & TxUnderrun)?TSAD_TUN3:0)
-         |((s->TxStatus[2] & TxUnderrun)?TSAD_TUN2:0)
-         |((s->TxStatus[1] & TxUnderrun)?TSAD_TUN1:0)
-         |((s->TxStatus[0] & TxUnderrun)?TSAD_TUN0:0)
-
-         |((s->TxStatus[3] & TxAborted )?TSAD_TABT3:0)
-         |((s->TxStatus[2] & TxAborted )?TSAD_TABT2:0)
-         |((s->TxStatus[1] & TxAborted )?TSAD_TABT1:0)
-         |((s->TxStatus[0] & TxAborted )?TSAD_TABT0:0)
-
-         |((s->TxStatus[3] & TxHostOwns )?TSAD_OWN3:0)
-         |((s->TxStatus[2] & TxHostOwns )?TSAD_OWN2:0)
-         |((s->TxStatus[1] & TxHostOwns )?TSAD_OWN1:0)
-         |((s->TxStatus[0] & TxHostOwns )?TSAD_OWN0:0) ;
-
-
-    DPRINTF("TSAD read val=0x%04x\n", ret);
-
-    return ret;
-}
-
-static uint16_t rtl8139_CSCR_read(RTL8139State *s)
-{
-    uint16_t ret = s->CSCR;
-
-    DPRINTF("CSCR read val=0x%04x\n", ret);
-
-    return ret;
-}
-
-static void rtl8139_TxAddr_write(RTL8139State *s, uint32_t txAddrOffset, uint32_t val)
-{
-    DPRINTF("TxAddr write offset=0x%x val=0x%08x\n", txAddrOffset, val);
-
-    s->TxAddr[txAddrOffset/4] = val;
-}
-
-static uint32_t rtl8139_TxAddr_read(RTL8139State *s, uint32_t txAddrOffset)
-{
-    uint32_t ret = s->TxAddr[txAddrOffset/4];
-
-    DPRINTF("TxAddr read offset=0x%x val=0x%08x\n", txAddrOffset, ret);
-
-    return ret;
-}
-
-static void rtl8139_RxBufPtr_write(RTL8139State *s, uint32_t val)
-{
-    DPRINTF("RxBufPtr write val=0x%04x\n", val);
-
-    /* this value is off by 16 */
-    s->RxBufPtr = MOD2(val + 0x10, s->RxBufferSize);
-
-    DPRINTF(" CAPR write: rx buffer length %d head 0x%04x read 0x%04x\n",
-        s->RxBufferSize, s->RxBufAddr, s->RxBufPtr);
-}
-
-static uint32_t rtl8139_RxBufPtr_read(RTL8139State *s)
-{
-    /* this value is off by 16 */
-    uint32_t ret = s->RxBufPtr - 0x10;
-
-    DPRINTF("RxBufPtr read val=0x%04x\n", ret);
-
-    return ret;
-}
-
-static uint32_t rtl8139_RxBufAddr_read(RTL8139State *s)
-{
-    /* this value is NOT off by 16 */
-    uint32_t ret = s->RxBufAddr;
-
-    DPRINTF("RxBufAddr read val=0x%04x\n", ret);
-
-    return ret;
-}
-
-static void rtl8139_RxBuf_write(RTL8139State *s, uint32_t val)
-{
-    DPRINTF("RxBuf write val=0x%08x\n", val);
-
-    s->RxBuf = val;
-
-    /* may need to reset rxring here */
-}
-
-static uint32_t rtl8139_RxBuf_read(RTL8139State *s)
-{
-    uint32_t ret = s->RxBuf;
-
-    DPRINTF("RxBuf read val=0x%08x\n", ret);
-
-    return ret;
-}
-
-static void rtl8139_IntrMask_write(RTL8139State *s, uint32_t val)
-{
-    DPRINTF("IntrMask write(w) val=0x%04x\n", val);
-
-    /* mask unwritable bits */
-    val = SET_MASKED(val, 0x1e00, s->IntrMask);
-
-    s->IntrMask = val;
-
-    rtl8139_set_next_tctr_time(s, qemu_get_clock_ns(vm_clock));
-    rtl8139_update_irq(s);
-
-}
-
-static uint32_t rtl8139_IntrMask_read(RTL8139State *s)
-{
-    uint32_t ret = s->IntrMask;
-
-    DPRINTF("IntrMask read(w) val=0x%04x\n", ret);
-
-    return ret;
-}
-
-static void rtl8139_IntrStatus_write(RTL8139State *s, uint32_t val)
-{
-    DPRINTF("IntrStatus write(w) val=0x%04x\n", val);
-
-#if 0
-
-    /* writing to ISR has no effect */
-
-    return;
-
-#else
-    uint16_t newStatus = s->IntrStatus & ~val;
-
-    /* mask unwritable bits */
-    newStatus = SET_MASKED(newStatus, 0x1e00, s->IntrStatus);
-
-    /* writing 1 to interrupt status register bit clears it */
-    s->IntrStatus = 0;
-    rtl8139_update_irq(s);
-
-    s->IntrStatus = newStatus;
-    /*
-     * Computing if we miss an interrupt here is not that correct but
-     * considered that we should have had already an interrupt
-     * and probably emulated is slower is better to assume this resetting was
-     * done before testing on previous rtl8139_update_irq lead to IRQ losing
-     */
-    rtl8139_set_next_tctr_time(s, qemu_get_clock_ns(vm_clock));
-    rtl8139_update_irq(s);
-
-#endif
-}
-
-static uint32_t rtl8139_IntrStatus_read(RTL8139State *s)
-{
-    rtl8139_set_next_tctr_time(s, qemu_get_clock_ns(vm_clock));
-
-    uint32_t ret = s->IntrStatus;
-
-    DPRINTF("IntrStatus read(w) val=0x%04x\n", ret);
-
-#if 0
-
-    /* reading ISR clears all interrupts */
-    s->IntrStatus = 0;
-
-    rtl8139_update_irq(s);
-
-#endif
-
-    return ret;
-}
-
-static void rtl8139_MultiIntr_write(RTL8139State *s, uint32_t val)
-{
-    DPRINTF("MultiIntr write(w) val=0x%04x\n", val);
-
-    /* mask unwritable bits */
-    val = SET_MASKED(val, 0xf000, s->MultiIntr);
-
-    s->MultiIntr = val;
-}
-
-static uint32_t rtl8139_MultiIntr_read(RTL8139State *s)
-{
-    uint32_t ret = s->MultiIntr;
-
-    DPRINTF("MultiIntr read(w) val=0x%04x\n", ret);
-
-    return ret;
-}
-
-static void rtl8139_io_writeb(void *opaque, uint8_t addr, uint32_t val)
-{
-    RTL8139State *s = opaque;
-
-    switch (addr)
-    {
-        case MAC0 ... MAC0+5:
-            s->phys[addr - MAC0] = val;
-            break;
-        case MAC0+6 ... MAC0+7:
-            /* reserved */
-            break;
-        case MAR0 ... MAR0+7:
-            s->mult[addr - MAR0] = val;
-            break;
-        case ChipCmd:
-            rtl8139_ChipCmd_write(s, val);
-            break;
-        case Cfg9346:
-            rtl8139_Cfg9346_write(s, val);
-            break;
-        case TxConfig: /* windows driver sometimes writes using byte-lenth call */
-            rtl8139_TxConfig_writeb(s, val);
-            break;
-        case Config0:
-            rtl8139_Config0_write(s, val);
-            break;
-        case Config1:
-            rtl8139_Config1_write(s, val);
-            break;
-        case Config3:
-            rtl8139_Config3_write(s, val);
-            break;
-        case Config4:
-            rtl8139_Config4_write(s, val);
-            break;
-        case Config5:
-            rtl8139_Config5_write(s, val);
-            break;
-        case MediaStatus:
-            /* ignore */
-            DPRINTF("not implemented write(b) to MediaStatus val=0x%02x\n",
-                val);
-            break;
-
-        case HltClk:
-            DPRINTF("HltClk write val=0x%08x\n", val);
-            if (val == 'R')
-            {
-                s->clock_enabled = 1;
-            }
-            else if (val == 'H')
-            {
-                s->clock_enabled = 0;
-            }
-            break;
-
-        case TxThresh:
-            DPRINTF("C+ TxThresh write(b) val=0x%02x\n", val);
-            s->TxThresh = val;
-            break;
-
-        case TxPoll:
-            DPRINTF("C+ TxPoll write(b) val=0x%02x\n", val);
-            if (val & (1 << 7))
-            {
-                DPRINTF("C+ TxPoll high priority transmission (not "
-                    "implemented)\n");
-                //rtl8139_cplus_transmit(s);
-            }
-            if (val & (1 << 6))
-            {
-                DPRINTF("C+ TxPoll normal priority transmission\n");
-                rtl8139_cplus_transmit(s);
-            }
-
-            break;
-
-        default:
-            DPRINTF("not implemented write(b) addr=0x%x val=0x%02x\n", addr,
-                val);
-            break;
-    }
-}
-
-static void rtl8139_io_writew(void *opaque, uint8_t addr, uint32_t val)
-{
-    RTL8139State *s = opaque;
-
-    switch (addr)
-    {
-        case IntrMask:
-            rtl8139_IntrMask_write(s, val);
-            break;
-
-        case IntrStatus:
-            rtl8139_IntrStatus_write(s, val);
-            break;
-
-        case MultiIntr:
-            rtl8139_MultiIntr_write(s, val);
-            break;
-
-        case RxBufPtr:
-            rtl8139_RxBufPtr_write(s, val);
-            break;
-
-        case BasicModeCtrl:
-            rtl8139_BasicModeCtrl_write(s, val);
-            break;
-        case BasicModeStatus:
-            rtl8139_BasicModeStatus_write(s, val);
-            break;
-        case NWayAdvert:
-            DPRINTF("NWayAdvert write(w) val=0x%04x\n", val);
-            s->NWayAdvert = val;
-            break;
-        case NWayLPAR:
-            DPRINTF("forbidden NWayLPAR write(w) val=0x%04x\n", val);
-            break;
-        case NWayExpansion:
-            DPRINTF("NWayExpansion write(w) val=0x%04x\n", val);
-            s->NWayExpansion = val;
-            break;
-
-        case CpCmd:
-            rtl8139_CpCmd_write(s, val);
-            break;
-
-        case IntrMitigate:
-            rtl8139_IntrMitigate_write(s, val);
-            break;
-
-        default:
-            DPRINTF("ioport write(w) addr=0x%x val=0x%04x via write(b)\n",
-                addr, val);
-
-            rtl8139_io_writeb(opaque, addr, val & 0xff);
-            rtl8139_io_writeb(opaque, addr + 1, (val >> 8) & 0xff);
-            break;
-    }
-}
-
-static void rtl8139_set_next_tctr_time(RTL8139State *s, int64_t current_time)
-{
-    int64_t pci_time, next_time;
-    uint32_t low_pci;
-
-    DPRINTF("entered rtl8139_set_next_tctr_time\n");
-
-    if (s->TimerExpire && current_time >= s->TimerExpire) {
-        s->IntrStatus |= PCSTimeout;
-        rtl8139_update_irq(s);
-    }
-
-    /* Set QEMU timer only if needed that is
-     * - TimerInt <> 0 (we have a timer)
-     * - mask = 1 (we want an interrupt timer)
-     * - irq = 0  (irq is not already active)
-     * If any of above change we need to compute timer again
-     * Also we must check if timer is passed without QEMU timer
-     */
-    s->TimerExpire = 0;
-    if (!s->TimerInt) {
-        return;
-    }
-
-    pci_time = muldiv64(current_time - s->TCTR_base, PCI_FREQUENCY,
-                                get_ticks_per_sec());
-    low_pci = pci_time & 0xffffffff;
-    pci_time = pci_time - low_pci + s->TimerInt;
-    if (low_pci >= s->TimerInt) {
-        pci_time += 0x100000000LL;
-    }
-    next_time = s->TCTR_base + muldiv64(pci_time, get_ticks_per_sec(),
-                                                PCI_FREQUENCY);
-    s->TimerExpire = next_time;
-
-    if ((s->IntrMask & PCSTimeout) != 0 && (s->IntrStatus & PCSTimeout) == 0) {
-        qemu_mod_timer(s->timer, next_time);
-    }
-}
-
-static void rtl8139_io_writel(void *opaque, uint8_t addr, uint32_t val)
-{
-    RTL8139State *s = opaque;
-
-    switch (addr)
-    {
-        case RxMissed:
-            DPRINTF("RxMissed clearing on write\n");
-            s->RxMissed = 0;
-            break;
-
-        case TxConfig:
-            rtl8139_TxConfig_write(s, val);
-            break;
-
-        case RxConfig:
-            rtl8139_RxConfig_write(s, val);
-            break;
-
-        case TxStatus0 ... TxStatus0+4*4-1:
-            rtl8139_TxStatus_write(s, addr-TxStatus0, val);
-            break;
-
-        case TxAddr0 ... TxAddr0+4*4-1:
-            rtl8139_TxAddr_write(s, addr-TxAddr0, val);
-            break;
-
-        case RxBuf:
-            rtl8139_RxBuf_write(s, val);
-            break;
-
-        case RxRingAddrLO:
-            DPRINTF("C+ RxRing low bits write val=0x%08x\n", val);
-            s->RxRingAddrLO = val;
-            break;
-
-        case RxRingAddrHI:
-            DPRINTF("C+ RxRing high bits write val=0x%08x\n", val);
-            s->RxRingAddrHI = val;
-            break;
-
-        case Timer:
-            DPRINTF("TCTR Timer reset on write\n");
-            s->TCTR_base = qemu_get_clock_ns(vm_clock);
-            rtl8139_set_next_tctr_time(s, s->TCTR_base);
-            break;
-
-        case FlashReg:
-            DPRINTF("FlashReg TimerInt write val=0x%08x\n", val);
-            if (s->TimerInt != val) {
-                s->TimerInt = val;
-                rtl8139_set_next_tctr_time(s, qemu_get_clock_ns(vm_clock));
-            }
-            break;
-
-        default:
-            DPRINTF("ioport write(l) addr=0x%x val=0x%08x via write(b)\n",
-                addr, val);
-            rtl8139_io_writeb(opaque, addr, val & 0xff);
-            rtl8139_io_writeb(opaque, addr + 1, (val >> 8) & 0xff);
-            rtl8139_io_writeb(opaque, addr + 2, (val >> 16) & 0xff);
-            rtl8139_io_writeb(opaque, addr + 3, (val >> 24) & 0xff);
-            break;
-    }
-}
-
-static uint32_t rtl8139_io_readb(void *opaque, uint8_t addr)
-{
-    RTL8139State *s = opaque;
-    int ret;
-
-    switch (addr)
-    {
-        case MAC0 ... MAC0+5:
-            ret = s->phys[addr - MAC0];
-            break;
-        case MAC0+6 ... MAC0+7:
-            ret = 0;
-            break;
-        case MAR0 ... MAR0+7:
-            ret = s->mult[addr - MAR0];
-            break;
-        case TxStatus0 ... TxStatus0+4*4-1:
-            ret = rtl8139_TxStatus_TxAddr_read(s, s->TxStatus, TxStatus0,
-                                               addr, 1);
-            break;
-        case ChipCmd:
-            ret = rtl8139_ChipCmd_read(s);
-            break;
-        case Cfg9346:
-            ret = rtl8139_Cfg9346_read(s);
-            break;
-        case Config0:
-            ret = rtl8139_Config0_read(s);
-            break;
-        case Config1:
-            ret = rtl8139_Config1_read(s);
-            break;
-        case Config3:
-            ret = rtl8139_Config3_read(s);
-            break;
-        case Config4:
-            ret = rtl8139_Config4_read(s);
-            break;
-        case Config5:
-            ret = rtl8139_Config5_read(s);
-            break;
-
-        case MediaStatus:
-            /* The LinkDown bit of MediaStatus is inverse with link status */
-            ret = 0xd0 | (~s->BasicModeStatus & 0x04);
-            DPRINTF("MediaStatus read 0x%x\n", ret);
-            break;
-
-        case HltClk:
-            ret = s->clock_enabled;
-            DPRINTF("HltClk read 0x%x\n", ret);
-            break;
-
-        case PCIRevisionID:
-            ret = RTL8139_PCI_REVID;
-            DPRINTF("PCI Revision ID read 0x%x\n", ret);
-            break;
-
-        case TxThresh:
-            ret = s->TxThresh;
-            DPRINTF("C+ TxThresh read(b) val=0x%02x\n", ret);
-            break;
-
-        case 0x43: /* Part of TxConfig register. Windows driver tries to read it */
-            ret = s->TxConfig >> 24;
-            DPRINTF("RTL8139C TxConfig at 0x43 read(b) val=0x%02x\n", ret);
-            break;
-
-        default:
-            DPRINTF("not implemented read(b) addr=0x%x\n", addr);
-            ret = 0;
-            break;
-    }
-
-    return ret;
-}
-
-static uint32_t rtl8139_io_readw(void *opaque, uint8_t addr)
-{
-    RTL8139State *s = opaque;
-    uint32_t ret;
-
-    switch (addr)
-    {
-        case TxAddr0 ... TxAddr0+4*4-1:
-            ret = rtl8139_TxStatus_TxAddr_read(s, s->TxAddr, TxAddr0, addr, 2);
-            break;
-        case IntrMask:
-            ret = rtl8139_IntrMask_read(s);
-            break;
-
-        case IntrStatus:
-            ret = rtl8139_IntrStatus_read(s);
-            break;
-
-        case MultiIntr:
-            ret = rtl8139_MultiIntr_read(s);
-            break;
-
-        case RxBufPtr:
-            ret = rtl8139_RxBufPtr_read(s);
-            break;
-
-        case RxBufAddr:
-            ret = rtl8139_RxBufAddr_read(s);
-            break;
-
-        case BasicModeCtrl:
-            ret = rtl8139_BasicModeCtrl_read(s);
-            break;
-        case BasicModeStatus:
-            ret = rtl8139_BasicModeStatus_read(s);
-            break;
-        case NWayAdvert:
-            ret = s->NWayAdvert;
-            DPRINTF("NWayAdvert read(w) val=0x%04x\n", ret);
-            break;
-        case NWayLPAR:
-            ret = s->NWayLPAR;
-            DPRINTF("NWayLPAR read(w) val=0x%04x\n", ret);
-            break;
-        case NWayExpansion:
-            ret = s->NWayExpansion;
-            DPRINTF("NWayExpansion read(w) val=0x%04x\n", ret);
-            break;
-
-        case CpCmd:
-            ret = rtl8139_CpCmd_read(s);
-            break;
-
-        case IntrMitigate:
-            ret = rtl8139_IntrMitigate_read(s);
-            break;
-
-        case TxSummary:
-            ret = rtl8139_TSAD_read(s);
-            break;
-
-        case CSCR:
-            ret = rtl8139_CSCR_read(s);
-            break;
-
-        default:
-            DPRINTF("ioport read(w) addr=0x%x via read(b)\n", addr);
-
-            ret  = rtl8139_io_readb(opaque, addr);
-            ret |= rtl8139_io_readb(opaque, addr + 1) << 8;
-
-            DPRINTF("ioport read(w) addr=0x%x val=0x%04x\n", addr, ret);
-            break;
-    }
-
-    return ret;
-}
-
-static uint32_t rtl8139_io_readl(void *opaque, uint8_t addr)
-{
-    RTL8139State *s = opaque;
-    uint32_t ret;
-
-    switch (addr)
-    {
-        case RxMissed:
-            ret = s->RxMissed;
-
-            DPRINTF("RxMissed read val=0x%08x\n", ret);
-            break;
-
-        case TxConfig:
-            ret = rtl8139_TxConfig_read(s);
-            break;
-
-        case RxConfig:
-            ret = rtl8139_RxConfig_read(s);
-            break;
-
-        case TxStatus0 ... TxStatus0+4*4-1:
-            ret = rtl8139_TxStatus_TxAddr_read(s, s->TxStatus, TxStatus0,
-                                               addr, 4);
-            break;
-
-        case TxAddr0 ... TxAddr0+4*4-1:
-            ret = rtl8139_TxAddr_read(s, addr-TxAddr0);
-            break;
-
-        case RxBuf:
-            ret = rtl8139_RxBuf_read(s);
-            break;
-
-        case RxRingAddrLO:
-            ret = s->RxRingAddrLO;
-            DPRINTF("C+ RxRing low bits read val=0x%08x\n", ret);
-            break;
-
-        case RxRingAddrHI:
-            ret = s->RxRingAddrHI;
-            DPRINTF("C+ RxRing high bits read val=0x%08x\n", ret);
-            break;
-
-        case Timer:
-            ret = muldiv64(qemu_get_clock_ns(vm_clock) - s->TCTR_base,
-                           PCI_FREQUENCY, get_ticks_per_sec());
-            DPRINTF("TCTR Timer read val=0x%08x\n", ret);
-            break;
-
-        case FlashReg:
-            ret = s->TimerInt;
-            DPRINTF("FlashReg TimerInt read val=0x%08x\n", ret);
-            break;
-
-        default:
-            DPRINTF("ioport read(l) addr=0x%x via read(b)\n", addr);
-
-            ret  = rtl8139_io_readb(opaque, addr);
-            ret |= rtl8139_io_readb(opaque, addr + 1) << 8;
-            ret |= rtl8139_io_readb(opaque, addr + 2) << 16;
-            ret |= rtl8139_io_readb(opaque, addr + 3) << 24;
-
-            DPRINTF("read(l) addr=0x%x val=%08x\n", addr, ret);
-            break;
-    }
-
-    return ret;
-}
-
-/* */
-
-static void rtl8139_mmio_writeb(void *opaque, hwaddr addr, uint32_t val)
-{
-    rtl8139_io_writeb(opaque, addr & 0xFF, val);
-}
-
-static void rtl8139_mmio_writew(void *opaque, hwaddr addr, uint32_t val)
-{
-    rtl8139_io_writew(opaque, addr & 0xFF, val);
-}
-
-static void rtl8139_mmio_writel(void *opaque, hwaddr addr, uint32_t val)
-{
-    rtl8139_io_writel(opaque, addr & 0xFF, val);
-}
-
-static uint32_t rtl8139_mmio_readb(void *opaque, hwaddr addr)
-{
-    return rtl8139_io_readb(opaque, addr & 0xFF);
-}
-
-static uint32_t rtl8139_mmio_readw(void *opaque, hwaddr addr)
-{
-    uint32_t val = rtl8139_io_readw(opaque, addr & 0xFF);
-    return val;
-}
-
-static uint32_t rtl8139_mmio_readl(void *opaque, hwaddr addr)
-{
-    uint32_t val = rtl8139_io_readl(opaque, addr & 0xFF);
-    return val;
-}
-
-static int rtl8139_post_load(void *opaque, int version_id)
-{
-    RTL8139State* s = opaque;
-    rtl8139_set_next_tctr_time(s, qemu_get_clock_ns(vm_clock));
-    if (version_id < 4) {
-        s->cplus_enabled = s->CpCmd != 0;
-    }
-
-    /* nc.link_down can't be migrated, so infer link_down according
-     * to link status bit in BasicModeStatus */
-    qemu_get_queue(s->nic)->link_down = (s->BasicModeStatus & 0x04) == 0;
-
-    return 0;
-}
-
-static bool rtl8139_hotplug_ready_needed(void *opaque)
-{
-    return qdev_machine_modified();
-}
-
-static const VMStateDescription vmstate_rtl8139_hotplug_ready ={
-    .name = "rtl8139/hotplug_ready",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField []) {
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void rtl8139_pre_save(void *opaque)
-{
-    RTL8139State* s = opaque;
-    int64_t current_time = qemu_get_clock_ns(vm_clock);
-
-    /* set IntrStatus correctly */
-    rtl8139_set_next_tctr_time(s, current_time);
-    s->TCTR = muldiv64(current_time - s->TCTR_base, PCI_FREQUENCY,
-                       get_ticks_per_sec());
-    s->rtl8139_mmio_io_addr_dummy = 0;
-}
-
-static const VMStateDescription vmstate_rtl8139 = {
-    .name = "rtl8139",
-    .version_id = 4,
-    .minimum_version_id = 3,
-    .minimum_version_id_old = 3,
-    .post_load = rtl8139_post_load,
-    .pre_save  = rtl8139_pre_save,
-    .fields      = (VMStateField []) {
-        VMSTATE_PCI_DEVICE(dev, RTL8139State),
-        VMSTATE_PARTIAL_BUFFER(phys, RTL8139State, 6),
-        VMSTATE_BUFFER(mult, RTL8139State),
-        VMSTATE_UINT32_ARRAY(TxStatus, RTL8139State, 4),
-        VMSTATE_UINT32_ARRAY(TxAddr, RTL8139State, 4),
-
-        VMSTATE_UINT32(RxBuf, RTL8139State),
-        VMSTATE_UINT32(RxBufferSize, RTL8139State),
-        VMSTATE_UINT32(RxBufPtr, RTL8139State),
-        VMSTATE_UINT32(RxBufAddr, RTL8139State),
-
-        VMSTATE_UINT16(IntrStatus, RTL8139State),
-        VMSTATE_UINT16(IntrMask, RTL8139State),
-
-        VMSTATE_UINT32(TxConfig, RTL8139State),
-        VMSTATE_UINT32(RxConfig, RTL8139State),
-        VMSTATE_UINT32(RxMissed, RTL8139State),
-        VMSTATE_UINT16(CSCR, RTL8139State),
-
-        VMSTATE_UINT8(Cfg9346, RTL8139State),
-        VMSTATE_UINT8(Config0, RTL8139State),
-        VMSTATE_UINT8(Config1, RTL8139State),
-        VMSTATE_UINT8(Config3, RTL8139State),
-        VMSTATE_UINT8(Config4, RTL8139State),
-        VMSTATE_UINT8(Config5, RTL8139State),
-
-        VMSTATE_UINT8(clock_enabled, RTL8139State),
-        VMSTATE_UINT8(bChipCmdState, RTL8139State),
-
-        VMSTATE_UINT16(MultiIntr, RTL8139State),
-
-        VMSTATE_UINT16(BasicModeCtrl, RTL8139State),
-        VMSTATE_UINT16(BasicModeStatus, RTL8139State),
-        VMSTATE_UINT16(NWayAdvert, RTL8139State),
-        VMSTATE_UINT16(NWayLPAR, RTL8139State),
-        VMSTATE_UINT16(NWayExpansion, RTL8139State),
-
-        VMSTATE_UINT16(CpCmd, RTL8139State),
-        VMSTATE_UINT8(TxThresh, RTL8139State),
-
-        VMSTATE_UNUSED(4),
-        VMSTATE_MACADDR(conf.macaddr, RTL8139State),
-        VMSTATE_INT32(rtl8139_mmio_io_addr_dummy, RTL8139State),
-
-        VMSTATE_UINT32(currTxDesc, RTL8139State),
-        VMSTATE_UINT32(currCPlusRxDesc, RTL8139State),
-        VMSTATE_UINT32(currCPlusTxDesc, RTL8139State),
-        VMSTATE_UINT32(RxRingAddrLO, RTL8139State),
-        VMSTATE_UINT32(RxRingAddrHI, RTL8139State),
-
-        VMSTATE_UINT16_ARRAY(eeprom.contents, RTL8139State, EEPROM_9346_SIZE),
-        VMSTATE_INT32(eeprom.mode, RTL8139State),
-        VMSTATE_UINT32(eeprom.tick, RTL8139State),
-        VMSTATE_UINT8(eeprom.address, RTL8139State),
-        VMSTATE_UINT16(eeprom.input, RTL8139State),
-        VMSTATE_UINT16(eeprom.output, RTL8139State),
-
-        VMSTATE_UINT8(eeprom.eecs, RTL8139State),
-        VMSTATE_UINT8(eeprom.eesk, RTL8139State),
-        VMSTATE_UINT8(eeprom.eedi, RTL8139State),
-        VMSTATE_UINT8(eeprom.eedo, RTL8139State),
-
-        VMSTATE_UINT32(TCTR, RTL8139State),
-        VMSTATE_UINT32(TimerInt, RTL8139State),
-        VMSTATE_INT64(TCTR_base, RTL8139State),
-
-        VMSTATE_STRUCT(tally_counters, RTL8139State, 0,
-                       vmstate_tally_counters, RTL8139TallyCounters),
-
-        VMSTATE_UINT32_V(cplus_enabled, RTL8139State, 4),
-        VMSTATE_END_OF_LIST()
-    },
-    .subsections = (VMStateSubsection []) {
-        {
-            .vmsd = &vmstate_rtl8139_hotplug_ready,
-            .needed = rtl8139_hotplug_ready_needed,
-        }, {
-            /* empty */
-        }
-    }
-};
-
-/***********************************************************/
-/* PCI RTL8139 definitions */
-
-static void rtl8139_ioport_write(void *opaque, hwaddr addr,
-                                 uint64_t val, unsigned size)
-{
-    switch (size) {
-    case 1:
-        rtl8139_io_writeb(opaque, addr, val);
-        break;
-    case 2:
-        rtl8139_io_writew(opaque, addr, val);
-        break;
-    case 4:
-        rtl8139_io_writel(opaque, addr, val);
-        break;
-    }
-}
-
-static uint64_t rtl8139_ioport_read(void *opaque, hwaddr addr,
-                                    unsigned size)
-{
-    switch (size) {
-    case 1:
-        return rtl8139_io_readb(opaque, addr);
-    case 2:
-        return rtl8139_io_readw(opaque, addr);
-    case 4:
-        return rtl8139_io_readl(opaque, addr);
-    }
-
-    return -1;
-}
-
-static const MemoryRegionOps rtl8139_io_ops = {
-    .read = rtl8139_ioport_read,
-    .write = rtl8139_ioport_write,
-    .impl = {
-        .min_access_size = 1,
-        .max_access_size = 4,
-    },
-    .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static const MemoryRegionOps rtl8139_mmio_ops = {
-    .old_mmio = {
-        .read = {
-            rtl8139_mmio_readb,
-            rtl8139_mmio_readw,
-            rtl8139_mmio_readl,
-        },
-        .write = {
-            rtl8139_mmio_writeb,
-            rtl8139_mmio_writew,
-            rtl8139_mmio_writel,
-        },
-    },
-    .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static void rtl8139_timer(void *opaque)
-{
-    RTL8139State *s = opaque;
-
-    if (!s->clock_enabled)
-    {
-        DPRINTF(">>> timer: clock is not running\n");
-        return;
-    }
-
-    s->IntrStatus |= PCSTimeout;
-    rtl8139_update_irq(s);
-    rtl8139_set_next_tctr_time(s, qemu_get_clock_ns(vm_clock));
-}
-
-static void rtl8139_cleanup(NetClientState *nc)
-{
-    RTL8139State *s = qemu_get_nic_opaque(nc);
-
-    s->nic = NULL;
-}
-
-static void pci_rtl8139_uninit(PCIDevice *dev)
-{
-    RTL8139State *s = DO_UPCAST(RTL8139State, dev, dev);
-
-    memory_region_destroy(&s->bar_io);
-    memory_region_destroy(&s->bar_mem);
-    if (s->cplus_txbuffer) {
-        g_free(s->cplus_txbuffer);
-        s->cplus_txbuffer = NULL;
-    }
-    qemu_del_timer(s->timer);
-    qemu_free_timer(s->timer);
-    qemu_del_nic(s->nic);
-}
-
-static void rtl8139_set_link_status(NetClientState *nc)
-{
-    RTL8139State *s = qemu_get_nic_opaque(nc);
-
-    if (nc->link_down) {
-        s->BasicModeStatus &= ~0x04;
-    } else {
-        s->BasicModeStatus |= 0x04;
-    }
-
-    s->IntrStatus |= RxUnderrun;
-    rtl8139_update_irq(s);
-}
-
-static NetClientInfo net_rtl8139_info = {
-    .type = NET_CLIENT_OPTIONS_KIND_NIC,
-    .size = sizeof(NICState),
-    .can_receive = rtl8139_can_receive,
-    .receive = rtl8139_receive,
-    .cleanup = rtl8139_cleanup,
-    .link_status_changed = rtl8139_set_link_status,
-};
-
-static int pci_rtl8139_init(PCIDevice *dev)
-{
-    RTL8139State * s = DO_UPCAST(RTL8139State, dev, dev);
-    uint8_t *pci_conf;
-
-    pci_conf = s->dev.config;
-    pci_conf[PCI_INTERRUPT_PIN] = 1;    /* interrupt pin A */
-    /* TODO: start of capability list, but no capability
-     * list bit in status register, and offset 0xdc seems unused. */
-    pci_conf[PCI_CAPABILITY_LIST] = 0xdc;
-
-    memory_region_init_io(&s->bar_io, &rtl8139_io_ops, s, "rtl8139", 0x100);
-    memory_region_init_io(&s->bar_mem, &rtl8139_mmio_ops, s, "rtl8139", 0x100);
-    pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->bar_io);
-    pci_register_bar(&s->dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar_mem);
-
-    qemu_macaddr_default_if_unset(&s->conf.macaddr);
-
-    /* prepare eeprom */
-    s->eeprom.contents[0] = 0x8129;
-#if 1
-    /* PCI vendor and device ID should be mirrored here */
-    s->eeprom.contents[1] = PCI_VENDOR_ID_REALTEK;
-    s->eeprom.contents[2] = PCI_DEVICE_ID_REALTEK_8139;
-#endif
-    s->eeprom.contents[7] = s->conf.macaddr.a[0] | s->conf.macaddr.a[1] << 8;
-    s->eeprom.contents[8] = s->conf.macaddr.a[2] | s->conf.macaddr.a[3] << 8;
-    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,
-                          object_get_typename(OBJECT(dev)), dev->qdev.id, s);
-    qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
-
-    s->cplus_txbuffer = NULL;
-    s->cplus_txbuffer_len = 0;
-    s->cplus_txbuffer_offset = 0;
-
-    s->TimerExpire = 0;
-    s->timer = qemu_new_timer_ns(vm_clock, rtl8139_timer, s);
-    rtl8139_set_next_tctr_time(s, qemu_get_clock_ns(vm_clock));
-
-    add_boot_device_path(s->conf.bootindex, &dev->qdev, "/ethernet-phy@0");
-
-    return 0;
-}
-
-static Property rtl8139_properties[] = {
-    DEFINE_NIC_PROPERTIES(RTL8139State, conf),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void rtl8139_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
-    k->init = pci_rtl8139_init;
-    k->exit = pci_rtl8139_uninit;
-    k->romfile = "efi-rtl8139.rom";
-    k->vendor_id = PCI_VENDOR_ID_REALTEK;
-    k->device_id = PCI_DEVICE_ID_REALTEK_8139;
-    k->revision = RTL8139_PCI_REVID; /* >=0x20 is for 8139C+ */
-    k->class_id = PCI_CLASS_NETWORK_ETHERNET;
-    dc->reset = rtl8139_reset;
-    dc->vmsd = &vmstate_rtl8139;
-    dc->props = rtl8139_properties;
-}
-
-static const TypeInfo rtl8139_info = {
-    .name          = "rtl8139",
-    .parent        = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(RTL8139State),
-    .class_init    = rtl8139_class_init,
-};
-
-static void rtl8139_register_types(void)
-{
-    type_register_static(&rtl8139_info);
-}
-
-type_init(rtl8139_register_types)
index 9f2f41989c50ef17775642dcd865645ee6f7b43f..77e1218447a641930263d20517a2948dc89fdba9 100644 (file)
@@ -2,7 +2,7 @@ obj-y = s390-virtio-bus.o s390-virtio.o
 obj-y += s390-virtio-hcall.o
 obj-y += sclp.o
 obj-y += event-facility.o
-obj-y += sclpquiesce.o sclpconsole.o
+obj-y += sclpquiesce.o
 obj-y += ipl.o
 obj-y += css.o
 obj-y += s390-virtio-ccw.o
diff --git a/hw/s390x/event-facility.h b/hw/s390x/event-facility.h
deleted file mode 100644 (file)
index 791ab2a..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * SCLP
- *    Event Facility definitions
- *
- * Copyright IBM, Corp. 2012
- *
- * Authors:
- *  Heinz Graalfs <graalfs@de.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or (at your
- * option) any later version.  See the COPYING file in the top-level directory.
- *
- */
-
-#ifndef HW_S390_SCLP_EVENT_FACILITY_H
-#define HW_S390_SCLP_EVENT_FACILITY_H
-
-#include <hw/qdev.h>
-#include "qemu/thread.h"
-
-/* SCLP event types */
-#define SCLP_EVENT_ASCII_CONSOLE_DATA           0x1a
-#define SCLP_EVENT_SIGNAL_QUIESCE               0x1d
-
-/* SCLP event masks */
-#define SCLP_EVENT_MASK_SIGNAL_QUIESCE          0x00000008
-#define SCLP_EVENT_MASK_MSG_ASCII               0x00000040
-
-#define SCLP_UNCONDITIONAL_READ                 0x00
-#define SCLP_SELECTIVE_READ                     0x01
-
-#define TYPE_SCLP_EVENT "s390-sclp-event-type"
-#define SCLP_EVENT(obj) \
-     OBJECT_CHECK(SCLPEvent, (obj), TYPE_SCLP_EVENT)
-#define SCLP_EVENT_CLASS(klass) \
-     OBJECT_CLASS_CHECK(SCLPEventClass, (klass), TYPE_SCLP_EVENT)
-#define SCLP_EVENT_GET_CLASS(obj) \
-     OBJECT_GET_CLASS(SCLPEventClass, (obj), TYPE_SCLP_EVENT)
-
-typedef struct WriteEventMask {
-    SCCBHeader h;
-    uint16_t _reserved;
-    uint16_t mask_length;
-    uint32_t cp_receive_mask;
-    uint32_t cp_send_mask;
-    uint32_t send_mask;
-    uint32_t receive_mask;
-} QEMU_PACKED WriteEventMask;
-
-typedef struct EventBufferHeader {
-    uint16_t length;
-    uint8_t  type;
-    uint8_t  flags;
-    uint16_t _reserved;
-} QEMU_PACKED EventBufferHeader;
-
-typedef struct WriteEventData {
-    SCCBHeader h;
-    EventBufferHeader ebh;
-} QEMU_PACKED WriteEventData;
-
-typedef struct ReadEventData {
-    SCCBHeader h;
-    EventBufferHeader ebh;
-    uint32_t mask;
-} QEMU_PACKED ReadEventData;
-
-typedef struct SCLPEvent {
-    DeviceState qdev;
-    bool event_pending;
-    uint32_t event_type;
-    char *name;
-} SCLPEvent;
-
-typedef struct SCLPEventClass {
-    DeviceClass parent_class;
-    int (*init)(SCLPEvent *event);
-    int (*exit)(SCLPEvent *event);
-
-    /* get SCLP's send mask */
-    unsigned int (*get_send_mask)(void);
-
-    /* get SCLP's receive mask */
-    unsigned int (*get_receive_mask)(void);
-
-    int (*read_event_data)(SCLPEvent *event, EventBufferHeader *evt_buf_hdr,
-                           int *slen);
-
-    int (*write_event_data)(SCLPEvent *event, EventBufferHeader *evt_buf_hdr);
-
-    /* returns the supported event type */
-    int (*event_type)(void);
-
-} SCLPEventClass;
-
-#endif
index 8c529c14d0f2dbb66e463cacda7a3eb25d3e3480..ddf15a21d39ebdbbc4170ba261a1227505285b9c 100644 (file)
 #include "monitor/monitor.h"
 #include "hw/loader.h"
 #include "elf.h"
-#include "hw/virtio.h"
-#include "hw/virtio-rng.h"
-#include "hw/virtio-serial.h"
-#include "hw/virtio-net.h"
+#include "hw/virtio/virtio.h"
+#include "hw/virtio/virtio-rng.h"
+#include "hw/virtio/virtio-serial.h"
+#include "hw/virtio/virtio-net.h"
 #include "hw/sysbus.h"
 #include "sysemu/kvm.h"
 
 #include "hw/s390x/s390-virtio-bus.h"
-#include "hw/virtio-bus.h"
+#include "hw/virtio/virtio-bus.h"
 
 /* #define DEBUG_S390 */
 
index ebe8794204091f164af04dd8cdc220e7e74e4c9c..c557132166c28d946dce7a2655f3ed3cc6162cbd 100644 (file)
 #ifndef HW_S390_VIRTIO_BUS_H
 #define HW_S390_VIRTIO_BUS_H 1
 
-#include "hw/virtio-blk.h"
-#include "hw/virtio-net.h"
-#include "hw/virtio-rng.h"
-#include "hw/virtio-serial.h"
-#include "hw/virtio-scsi.h"
-#include "hw/virtio-bus.h"
+#include "hw/virtio/virtio-blk.h"
+#include "hw/virtio/virtio-net.h"
+#include "hw/virtio/virtio-rng.h"
+#include "hw/virtio/virtio-serial.h"
+#include "hw/virtio/virtio-scsi.h"
+#include "hw/virtio/virtio-bus.h"
 
 #define VIRTIO_DEV_OFFS_TYPE           0       /* 8 bits */
 #define VIRTIO_DEV_OFFS_NUM_VQ         1       /* 8 bits */
index ca275bd9d7412324711bb1f6b1ce37de80f07584..f82c0e19640bd170091d43f40b98b6de9cc729a8 100644 (file)
@@ -29,7 +29,7 @@
 #include "hw/boards.h"
 #include "monitor/monitor.h"
 #include "hw/loader.h"
-#include "hw/virtio.h"
+#include "hw/virtio/virtio.h"
 #include "hw/sysbus.h"
 #include "sysemu/kvm.h"
 #include "exec/address-spaces.h"
diff --git a/hw/s390x/sclp.h b/hw/s390x/sclp.h
deleted file mode 100644 (file)
index 231a38a..0000000
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * SCLP Support
- *
- * Copyright IBM, Corp. 2012
- *
- * Authors:
- *  Christian Borntraeger <borntraeger@de.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or (at your
- * option) any later version.  See the COPYING file in the top-level directory.
- *
- */
-
-#ifndef HW_S390_SCLP_H
-#define HW_S390_SCLP_H
-
-#include <hw/sysbus.h>
-#include <hw/qdev.h>
-
-/* SCLP command codes */
-#define SCLP_CMDW_READ_SCP_INFO                 0x00020001
-#define SCLP_CMDW_READ_SCP_INFO_FORCED          0x00120001
-#define SCLP_CMD_READ_EVENT_DATA                0x00770005
-#define SCLP_CMD_WRITE_EVENT_DATA               0x00760005
-#define SCLP_CMD_READ_EVENT_DATA                0x00770005
-#define SCLP_CMD_WRITE_EVENT_DATA               0x00760005
-#define SCLP_CMD_WRITE_EVENT_MASK               0x00780005
-
-/* SCLP response codes */
-#define SCLP_RC_NORMAL_READ_COMPLETION          0x0010
-#define SCLP_RC_NORMAL_COMPLETION               0x0020
-#define SCLP_RC_INVALID_SCLP_COMMAND            0x01f0
-#define SCLP_RC_CONTAINED_EQUIPMENT_CHECK       0x0340
-#define SCLP_RC_INSUFFICIENT_SCCB_LENGTH        0x0300
-#define SCLP_RC_INVALID_FUNCTION                0x40f0
-#define SCLP_RC_NO_EVENT_BUFFERS_STORED         0x60f0
-#define SCLP_RC_INVALID_SELECTION_MASK          0x70f0
-#define SCLP_RC_INCONSISTENT_LENGTHS            0x72f0
-#define SCLP_RC_EVENT_BUFFER_SYNTAX_ERROR       0x73f0
-#define SCLP_RC_INVALID_MASK_LENGTH             0x74f0
-
-
-/* Service Call Control Block (SCCB) and its elements */
-
-#define SCCB_SIZE 4096
-
-#define SCLP_VARIABLE_LENGTH_RESPONSE           0x80
-#define SCLP_EVENT_BUFFER_ACCEPTED              0x80
-
-#define SCLP_FC_NORMAL_WRITE                    0
-
-/*
- * Normally packed structures are not the right thing to do, since all code
- * must take care of endianness. We cannot use ldl_phys and friends for two
- * reasons, though:
- * - some of the embedded structures below the SCCB can appear multiple times
- *   at different locations, so there is no fixed offset
- * - we work on a private copy of the SCCB, since there are several length
- *   fields, that would cause a security nightmare if we allow the guest to
- *   alter the structure while we parse it. We cannot use ldl_p and friends
- *   either without doing pointer arithmetics
- * So we have to double check that all users of sclp data structures use the
- * right endianness wrappers.
- */
-typedef struct SCCBHeader {
-    uint16_t length;
-    uint8_t function_code;
-    uint8_t control_mask[3];
-    uint16_t response_code;
-} QEMU_PACKED SCCBHeader;
-
-#define SCCB_DATA_LEN (SCCB_SIZE - sizeof(SCCBHeader))
-
-typedef struct ReadInfo {
-    SCCBHeader h;
-    uint16_t rnmax;
-    uint8_t rnsize;
-} QEMU_PACKED ReadInfo;
-
-typedef struct SCCB {
-    SCCBHeader h;
-    char data[SCCB_DATA_LEN];
- } QEMU_PACKED SCCB;
-
-static inline int sccb_data_len(SCCB *sccb)
-{
-    return be16_to_cpu(sccb->h.length) - sizeof(sccb->h);
-}
-
-#define TYPE_DEVICE_S390_SCLP "s390-sclp-device"
-#define SCLP_S390_DEVICE(obj) \
-     OBJECT_CHECK(S390SCLPDevice, (obj), TYPE_DEVICE_S390_SCLP)
-#define SCLP_S390_DEVICE_CLASS(klass) \
-     OBJECT_CLASS_CHECK(S390SCLPDeviceClass, (klass), \
-             TYPE_DEVICE_S390_SCLP)
-#define SCLP_S390_DEVICE_GET_CLASS(obj) \
-     OBJECT_GET_CLASS(S390SCLPDeviceClass, (obj), \
-             TYPE_DEVICE_S390_SCLP)
-
-typedef struct SCLPEventFacility SCLPEventFacility;
-
-typedef struct S390SCLPDevice {
-    SysBusDevice busdev;
-    SCLPEventFacility *ef;
-    void (*sclp_command_handler)(SCLPEventFacility *ef, SCCB *sccb,
-                                 uint64_t code);
-    bool (*event_pending)(SCLPEventFacility *ef);
-} S390SCLPDevice;
-
-typedef struct S390SCLPDeviceClass {
-    DeviceClass qdev;
-    int (*init)(S390SCLPDevice *sdev);
-} S390SCLPDeviceClass;
-
-void s390_sclp_init(void);
-void sclp_service_interrupt(uint32_t sccb);
-
-#endif
diff --git a/hw/s390x/sclpconsole.c b/hw/s390x/sclpconsole.c
deleted file mode 100644 (file)
index 5c881e5..0000000
+++ /dev/null
@@ -1,305 +0,0 @@
-/*
- * SCLP event type
- *    Ascii Console Data (VT220 Console)
- *
- * Copyright IBM, Corp. 2012
- *
- * Authors:
- *  Heinz Graalfs <graalfs@de.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or (at your
- * option) any later version.  See the COPYING file in the top-level directory.
- *
- */
-
-#include <hw/qdev.h>
-#include "qemu/thread.h"
-#include "qemu/error-report.h"
-
-#include "hw/s390x/sclp.h"
-#include "hw/s390x/event-facility.h"
-#include "char/char.h"
-
-typedef struct ASCIIConsoleData {
-    EventBufferHeader ebh;
-    char data[0];
-} QEMU_PACKED ASCIIConsoleData;
-
-/* max size for ASCII data in 4K SCCB page */
-#define SIZE_BUFFER_VT220 4080
-
-typedef struct SCLPConsole {
-    SCLPEvent event;
-    CharDriverState *chr;
-    /* io vector                                                       */
-    uint8_t *iov;           /* iov buffer pointer                      */
-    uint8_t *iov_sclp;      /* pointer to SCLP read offset             */
-    uint8_t *iov_bs;        /* pointer byte stream read offset         */
-    uint32_t iov_data_len;  /* length of byte stream in buffer         */
-    uint32_t iov_sclp_rest; /* length of byte stream not read via SCLP */
-    qemu_irq irq_read_vt220;
-} SCLPConsole;
-
-/* character layer call-back functions */
-
-/* Return number of bytes that fit into iov buffer */
-static int chr_can_read(void *opaque)
-{
-    SCLPConsole *scon = opaque;
-
-    return scon->iov ? SIZE_BUFFER_VT220 - scon->iov_data_len : 0;
-}
-
-/* Receive n bytes from character layer, save in iov buffer,
- * and set event pending */
-static void receive_from_chr_layer(SCLPConsole *scon, const uint8_t *buf,
-                                   int size)
-{
-    assert(scon->iov);
-
-    /* read data must fit into current buffer */
-    assert(size <= SIZE_BUFFER_VT220 - scon->iov_data_len);
-
-    /* put byte-stream from character layer into buffer */
-    memcpy(scon->iov_bs, buf, size);
-    scon->iov_data_len += size;
-    scon->iov_sclp_rest += size;
-    scon->iov_bs += size;
-    scon->event.event_pending = true;
-}
-
-/* Send data from a char device over to the guest */
-static void chr_read(void *opaque, const uint8_t *buf, int size)
-{
-    SCLPConsole *scon = opaque;
-
-    assert(scon);
-
-    receive_from_chr_layer(scon, buf, size);
-    /* trigger SCLP read operation */
-    qemu_irq_raise(scon->irq_read_vt220);
-}
-
-static void chr_event(void *opaque, int event)
-{
-    SCLPConsole *scon = opaque;
-
-    switch (event) {
-    case CHR_EVENT_OPENED:
-        if (!scon->iov) {
-            scon->iov = g_malloc0(SIZE_BUFFER_VT220);
-            scon->iov_sclp = scon->iov;
-            scon->iov_bs = scon->iov;
-            scon->iov_data_len = 0;
-            scon->iov_sclp_rest = 0;
-        }
-        break;
-    case CHR_EVENT_CLOSED:
-        if (scon->iov) {
-            g_free(scon->iov);
-            scon->iov = NULL;
-        }
-        break;
-    }
-}
-
-/* functions to be called by event facility */
-
-static int event_type(void)
-{
-    return SCLP_EVENT_ASCII_CONSOLE_DATA;
-}
-
-static unsigned int send_mask(void)
-{
-    return SCLP_EVENT_MASK_MSG_ASCII;
-}
-
-static unsigned int receive_mask(void)
-{
-    return SCLP_EVENT_MASK_MSG_ASCII;
-}
-
-/* triggered by SCLP's read_event_data -
- * copy console data byte-stream into provided (SCLP) buffer
- */
-static void get_console_data(SCLPEvent *event, uint8_t *buf, size_t *size,
-                             int avail)
-{
-    SCLPConsole *cons = DO_UPCAST(SCLPConsole, event, event);
-
-    /* first byte is hex 0 saying an ascii string follows */
-    *buf++ = '\0';
-    avail--;
-    /* if all data fit into provided SCLP buffer */
-    if (avail >= cons->iov_sclp_rest) {
-        /* copy character byte-stream to SCLP buffer */
-        memcpy(buf, cons->iov_sclp, cons->iov_sclp_rest);
-        *size = cons->iov_sclp_rest + 1;
-        cons->iov_sclp = cons->iov;
-        cons->iov_bs = cons->iov;
-        cons->iov_data_len = 0;
-        cons->iov_sclp_rest = 0;
-        event->event_pending = false;
-        /* data provided and no more data pending */
-    } else {
-        /* if provided buffer is too small, just copy part */
-        memcpy(buf, cons->iov_sclp, avail);
-        *size = avail + 1;
-        cons->iov_sclp_rest -= avail;
-        cons->iov_sclp += avail;
-        /* more data pending */
-    }
-}
-
-static int read_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr,
-                           int *slen)
-{
-    int avail;
-    size_t src_len;
-    uint8_t *to;
-    ASCIIConsoleData *acd = (ASCIIConsoleData *) evt_buf_hdr;
-
-    if (!event->event_pending) {
-        /* no data pending */
-        return 0;
-    }
-
-    to = (uint8_t *)&acd->data;
-    avail = *slen - sizeof(ASCIIConsoleData);
-    get_console_data(event, to, &src_len, avail);
-
-    acd->ebh.length = cpu_to_be16(sizeof(ASCIIConsoleData) + src_len);
-    acd->ebh.type = SCLP_EVENT_ASCII_CONSOLE_DATA;
-    acd->ebh.flags |= SCLP_EVENT_BUFFER_ACCEPTED;
-    *slen = avail - src_len;
-
-    return 1;
-}
-
-/* triggered by SCLP's write_event_data
- *  - write console data to character layer
- *  returns < 0 if an error occurred
- */
-static ssize_t write_console_data(SCLPEvent *event, const uint8_t *buf,
-                                  size_t len)
-{
-    ssize_t ret = 0;
-    const uint8_t *iov_offset;
-    SCLPConsole *scon = DO_UPCAST(SCLPConsole, event, event);
-
-    if (!scon->chr) {
-        /* If there's no backend, we can just say we consumed all data. */
-        return len;
-    }
-
-    iov_offset = buf;
-    while (len > 0) {
-        ret = qemu_chr_fe_write(scon->chr, buf, len);
-        if (ret == 0) {
-            /* a pty doesn't seem to be connected - no error */
-            len = 0;
-        } else if (ret == -EAGAIN || (ret > 0 && ret < len)) {
-            len -= ret;
-            iov_offset += ret;
-        } else {
-            len = 0;
-        }
-    }
-
-    return ret;
-}
-
-static int write_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr)
-{
-    int rc;
-    int length;
-    ssize_t written;
-    ASCIIConsoleData *acd = (ASCIIConsoleData *) evt_buf_hdr;
-
-    length = be16_to_cpu(evt_buf_hdr->length) - sizeof(EventBufferHeader);
-    written = write_console_data(event, (uint8_t *)acd->data, length);
-
-    rc = SCLP_RC_NORMAL_COMPLETION;
-    /* set event buffer accepted flag */
-    evt_buf_hdr->flags |= SCLP_EVENT_BUFFER_ACCEPTED;
-
-    /* written will be zero if a pty is not connected - don't treat as error */
-    if (written < 0) {
-        /* event buffer not accepted due to error in character layer */
-        evt_buf_hdr->flags &= ~(SCLP_EVENT_BUFFER_ACCEPTED);
-        rc = SCLP_RC_CONTAINED_EQUIPMENT_CHECK;
-    }
-
-    return rc;
-}
-
-static void trigger_ascii_console_data(void *env, int n, int level)
-{
-    sclp_service_interrupt(0);
-}
-
-/* qemu object creation and initialization functions */
-
-/* tell character layer our call-back functions */
-static int console_init(SCLPEvent *event)
-{
-    static bool console_available;
-
-    SCLPConsole *scon = DO_UPCAST(SCLPConsole, event, event);
-
-    if (console_available) {
-        error_report("Multiple VT220 operator consoles are not supported");
-        return -1;
-    }
-    console_available = true;
-    event->event_type = SCLP_EVENT_ASCII_CONSOLE_DATA;
-    if (scon->chr) {
-        qemu_chr_add_handlers(scon->chr, chr_can_read,
-                              chr_read, chr_event, scon);
-    }
-    scon->irq_read_vt220 = *qemu_allocate_irqs(trigger_ascii_console_data,
-                                               NULL, 1);
-
-    return 0;
-}
-
-static int console_exit(SCLPEvent *event)
-{
-    return 0;
-}
-
-static Property console_properties[] = {
-    DEFINE_PROP_CHR("chardev", SCLPConsole, chr),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void console_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SCLPEventClass *ec = SCLP_EVENT_CLASS(klass);
-
-    dc->props = console_properties;
-    ec->init = console_init;
-    ec->exit = console_exit;
-    ec->get_send_mask = send_mask;
-    ec->get_receive_mask = receive_mask;
-    ec->event_type = event_type;
-    ec->read_event_data = read_event_data;
-    ec->write_event_data = write_event_data;
-}
-
-static const TypeInfo sclp_console_info = {
-    .name          = "sclpconsole",
-    .parent        = TYPE_SCLP_EVENT,
-    .instance_size = sizeof(SCLPConsole),
-    .class_init    = console_class_init,
-    .class_size    = sizeof(SCLPEventClass),
-};
-
-static void register_types(void)
-{
-    type_register_static(&sclp_console_info);
-}
-
-type_init(register_types)
index 5dce791406ee65e4cbc7b0628866fae5d3645477..4dec0cd8617fc3f6c1f02432e5afa2fba7756e86 100644 (file)
 #include "sysemu/sysemu.h"
 #include "net/net.h"
 #include "monitor/monitor.h"
-#include "hw/virtio.h"
-#include "hw/virtio-serial.h"
-#include "hw/virtio-net.h"
+#include "hw/virtio/virtio.h"
+#include "hw/virtio/virtio-serial.h"
+#include "hw/virtio/virtio-net.h"
 #include "hw/sysbus.h"
 #include "qemu/bitops.h"
-#include "hw/virtio-bus.h"
+#include "hw/virtio/virtio-bus.h"
 
 #include "ioinst.h"
 #include "css.h"
index d58051028350a9138bae592558ec948ac0d54db1..46e9a558af24253417ada0b4b40f62d0545a85a6 100644 (file)
 #ifndef HW_S390X_VIRTIO_CCW_H
 #define HW_S390X_VIRTIO_CCW_H
 
-#include <hw/virtio-blk.h>
-#include <hw/virtio-net.h>
-#include <hw/virtio-serial.h>
-#include <hw/virtio-scsi.h>
-#include "hw/virtio-balloon.h"
-#include <hw/virtio-rng.h>
-#include <hw/virtio-bus.h>
+#include <hw/virtio/virtio-blk.h>
+#include <hw/virtio/virtio-net.h>
+#include <hw/virtio/virtio-serial.h>
+#include <hw/virtio/virtio-scsi.h>
+#include <hw/virtio/virtio-balloon.h>
+#include <hw/virtio/virtio-rng.h>
+#include <hw/virtio/virtio-bus.h>
 
 #define VIRTUAL_CSSID 0xfe
 
diff --git a/hw/sb16.c b/hw/sb16.c
deleted file mode 100644 (file)
index bd51ceb..0000000
--- a/hw/sb16.c
+++ /dev/null
@@ -1,1424 +0,0 @@
-/*
- * QEMU Soundblaster 16 emulation
- *
- * Copyright (c) 2003-2005 Vassili Karpov (malc)
- *
- * 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 "hw/hw.h"
-#include "hw/audiodev.h"
-#include "audio/audio.h"
-#include "hw/isa.h"
-#include "hw/qdev.h"
-#include "qemu/timer.h"
-#include "qemu/host-utils.h"
-
-#define dolog(...) AUD_log ("sb16", __VA_ARGS__)
-
-/* #define DEBUG */
-/* #define DEBUG_SB16_MOST */
-
-#ifdef DEBUG
-#define ldebug(...) dolog (__VA_ARGS__)
-#else
-#define ldebug(...)
-#endif
-
-#define IO_READ_PROTO(name)                             \
-    uint32_t name (void *opaque, uint32_t nport)
-#define IO_WRITE_PROTO(name)                                    \
-    void name (void *opaque, uint32_t nport, uint32_t val)
-
-static const char e3[] = "COPYRIGHT (C) CREATIVE TECHNOLOGY LTD, 1992.";
-
-typedef struct SB16State {
-    ISADevice dev;
-    QEMUSoundCard card;
-    qemu_irq pic;
-    uint32_t irq;
-    uint32_t dma;
-    uint32_t hdma;
-    uint32_t port;
-    uint32_t ver;
-
-    int in_index;
-    int out_data_len;
-    int fmt_stereo;
-    int fmt_signed;
-    int fmt_bits;
-    audfmt_e fmt;
-    int dma_auto;
-    int block_size;
-    int fifo;
-    int freq;
-    int time_const;
-    int speaker;
-    int needed_bytes;
-    int cmd;
-    int use_hdma;
-    int highspeed;
-    int can_write;
-
-    int v2x6;
-
-    uint8_t csp_param;
-    uint8_t csp_value;
-    uint8_t csp_mode;
-    uint8_t csp_regs[256];
-    uint8_t csp_index;
-    uint8_t csp_reg83[4];
-    int csp_reg83r;
-    int csp_reg83w;
-
-    uint8_t in2_data[10];
-    uint8_t out_data[50];
-    uint8_t test_reg;
-    uint8_t last_read_byte;
-    int nzero;
-
-    int left_till_irq;
-
-    int dma_running;
-    int bytes_per_second;
-    int align;
-    int audio_free;
-    SWVoiceOut *voice;
-
-    QEMUTimer *aux_ts;
-    /* mixer state */
-    int mixer_nreg;
-    uint8_t mixer_regs[256];
-} SB16State;
-
-static void SB_audio_callback (void *opaque, int free);
-
-static int magic_of_irq (int irq)
-{
-    switch (irq) {
-    case 5:
-        return 2;
-    case 7:
-        return 4;
-    case 9:
-        return 1;
-    case 10:
-        return 8;
-    default:
-        dolog ("bad irq %d\n", irq);
-        return 2;
-    }
-}
-
-static int irq_of_magic (int magic)
-{
-    switch (magic) {
-    case 1:
-        return 9;
-    case 2:
-        return 5;
-    case 4:
-        return 7;
-    case 8:
-        return 10;
-    default:
-        dolog ("bad irq magic %d\n", magic);
-        return -1;
-    }
-}
-
-#if 0
-static void log_dsp (SB16State *dsp)
-{
-    ldebug ("%s:%s:%d:%s:dmasize=%d:freq=%d:const=%d:speaker=%d\n",
-            dsp->fmt_stereo ? "Stereo" : "Mono",
-            dsp->fmt_signed ? "Signed" : "Unsigned",
-            dsp->fmt_bits,
-            dsp->dma_auto ? "Auto" : "Single",
-            dsp->block_size,
-            dsp->freq,
-            dsp->time_const,
-            dsp->speaker);
-}
-#endif
-
-static void speaker (SB16State *s, int on)
-{
-    s->speaker = on;
-    /* AUD_enable (s->voice, on); */
-}
-
-static void control (SB16State *s, int hold)
-{
-    int dma = s->use_hdma ? s->hdma : s->dma;
-    s->dma_running = hold;
-
-    ldebug ("hold %d high %d dma %d\n", hold, s->use_hdma, dma);
-
-    if (hold) {
-        DMA_hold_DREQ (dma);
-        AUD_set_active_out (s->voice, 1);
-    }
-    else {
-        DMA_release_DREQ (dma);
-        AUD_set_active_out (s->voice, 0);
-    }
-}
-
-static void aux_timer (void *opaque)
-{
-    SB16State *s = opaque;
-    s->can_write = 1;
-    qemu_irq_raise (s->pic);
-}
-
-#define DMA8_AUTO 1
-#define DMA8_HIGH 2
-
-static void continue_dma8 (SB16State *s)
-{
-    if (s->freq > 0) {
-        struct audsettings as;
-
-        s->audio_free = 0;
-
-        as.freq = s->freq;
-        as.nchannels = 1 << s->fmt_stereo;
-        as.fmt = s->fmt;
-        as.endianness = 0;
-
-        s->voice = AUD_open_out (
-            &s->card,
-            s->voice,
-            "sb16",
-            s,
-            SB_audio_callback,
-            &as
-            );
-    }
-
-    control (s, 1);
-}
-
-static void dma_cmd8 (SB16State *s, int mask, int dma_len)
-{
-    s->fmt = AUD_FMT_U8;
-    s->use_hdma = 0;
-    s->fmt_bits = 8;
-    s->fmt_signed = 0;
-    s->fmt_stereo = (s->mixer_regs[0x0e] & 2) != 0;
-    if (-1 == s->time_const) {
-        if (s->freq <= 0)
-            s->freq = 11025;
-    }
-    else {
-        int tmp = (256 - s->time_const);
-        s->freq = (1000000 + (tmp / 2)) / tmp;
-    }
-
-    if (dma_len != -1) {
-        s->block_size = dma_len << s->fmt_stereo;
-    }
-    else {
-        /* This is apparently the only way to make both Act1/PL
-           and SecondReality/FC work
-
-           Act1 sets block size via command 0x48 and it's an odd number
-           SR does the same with even number
-           Both use stereo, and Creatives own documentation states that
-           0x48 sets block size in bytes less one.. go figure */
-        s->block_size &= ~s->fmt_stereo;
-    }
-
-    s->freq >>= s->fmt_stereo;
-    s->left_till_irq = s->block_size;
-    s->bytes_per_second = (s->freq << s->fmt_stereo);
-    /* s->highspeed = (mask & DMA8_HIGH) != 0; */
-    s->dma_auto = (mask & DMA8_AUTO) != 0;
-    s->align = (1 << s->fmt_stereo) - 1;
-
-    if (s->block_size & s->align) {
-        dolog ("warning: misaligned block size %d, alignment %d\n",
-               s->block_size, s->align + 1);
-    }
-
-    ldebug ("freq %d, stereo %d, sign %d, bits %d, "
-            "dma %d, auto %d, fifo %d, high %d\n",
-            s->freq, s->fmt_stereo, s->fmt_signed, s->fmt_bits,
-            s->block_size, s->dma_auto, s->fifo, s->highspeed);
-
-    continue_dma8 (s);
-    speaker (s, 1);
-}
-
-static void dma_cmd (SB16State *s, uint8_t cmd, uint8_t d0, int dma_len)
-{
-    s->use_hdma = cmd < 0xc0;
-    s->fifo = (cmd >> 1) & 1;
-    s->dma_auto = (cmd >> 2) & 1;
-    s->fmt_signed = (d0 >> 4) & 1;
-    s->fmt_stereo = (d0 >> 5) & 1;
-
-    switch (cmd >> 4) {
-    case 11:
-        s->fmt_bits = 16;
-        break;
-
-    case 12:
-        s->fmt_bits = 8;
-        break;
-    }
-
-    if (-1 != s->time_const) {
-#if 1
-        int tmp = 256 - s->time_const;
-        s->freq = (1000000 + (tmp / 2)) / tmp;
-#else
-        /* s->freq = 1000000 / ((255 - s->time_const) << s->fmt_stereo); */
-        s->freq = 1000000 / ((255 - s->time_const));
-#endif
-        s->time_const = -1;
-    }
-
-    s->block_size = dma_len + 1;
-    s->block_size <<= (s->fmt_bits == 16);
-    if (!s->dma_auto) {
-        /* It is clear that for DOOM and auto-init this value
-           shouldn't take stereo into account, while Miles Sound Systems
-           setsound.exe with single transfer mode wouldn't work without it
-           wonders of SB16 yet again */
-        s->block_size <<= s->fmt_stereo;
-    }
-
-    ldebug ("freq %d, stereo %d, sign %d, bits %d, "
-            "dma %d, auto %d, fifo %d, high %d\n",
-            s->freq, s->fmt_stereo, s->fmt_signed, s->fmt_bits,
-            s->block_size, s->dma_auto, s->fifo, s->highspeed);
-
-    if (16 == s->fmt_bits) {
-        if (s->fmt_signed) {
-            s->fmt = AUD_FMT_S16;
-        }
-        else {
-            s->fmt = AUD_FMT_U16;
-        }
-    }
-    else {
-        if (s->fmt_signed) {
-            s->fmt = AUD_FMT_S8;
-        }
-        else {
-            s->fmt = AUD_FMT_U8;
-        }
-    }
-
-    s->left_till_irq = s->block_size;
-
-    s->bytes_per_second = (s->freq << s->fmt_stereo) << (s->fmt_bits == 16);
-    s->highspeed = 0;
-    s->align = (1 << (s->fmt_stereo + (s->fmt_bits == 16))) - 1;
-    if (s->block_size & s->align) {
-        dolog ("warning: misaligned block size %d, alignment %d\n",
-               s->block_size, s->align + 1);
-    }
-
-    if (s->freq) {
-        struct audsettings as;
-
-        s->audio_free = 0;
-
-        as.freq = s->freq;
-        as.nchannels = 1 << s->fmt_stereo;
-        as.fmt = s->fmt;
-        as.endianness = 0;
-
-        s->voice = AUD_open_out (
-            &s->card,
-            s->voice,
-            "sb16",
-            s,
-            SB_audio_callback,
-            &as
-            );
-    }
-
-    control (s, 1);
-    speaker (s, 1);
-}
-
-static inline void dsp_out_data (SB16State *s, uint8_t val)
-{
-    ldebug ("outdata %#x\n", val);
-    if ((size_t) s->out_data_len < sizeof (s->out_data)) {
-        s->out_data[s->out_data_len++] = val;
-    }
-}
-
-static inline uint8_t dsp_get_data (SB16State *s)
-{
-    if (s->in_index) {
-        return s->in2_data[--s->in_index];
-    }
-    else {
-        dolog ("buffer underflow\n");
-        return 0;
-    }
-}
-
-static void command (SB16State *s, uint8_t cmd)
-{
-    ldebug ("command %#x\n", cmd);
-
-    if (cmd > 0xaf && cmd < 0xd0) {
-        if (cmd & 8) {
-            dolog ("ADC not yet supported (command %#x)\n", cmd);
-        }
-
-        switch (cmd >> 4) {
-        case 11:
-        case 12:
-            break;
-        default:
-            dolog ("%#x wrong bits\n", cmd);
-        }
-        s->needed_bytes = 3;
-    }
-    else {
-        s->needed_bytes = 0;
-
-        switch (cmd) {
-        case 0x03:
-            dsp_out_data (s, 0x10); /* s->csp_param); */
-            goto warn;
-
-        case 0x04:
-            s->needed_bytes = 1;
-            goto warn;
-
-        case 0x05:
-            s->needed_bytes = 2;
-            goto warn;
-
-        case 0x08:
-            /* __asm__ ("int3"); */
-            goto warn;
-
-        case 0x0e:
-            s->needed_bytes = 2;
-            goto warn;
-
-        case 0x09:
-            dsp_out_data (s, 0xf8);
-            goto warn;
-
-        case 0x0f:
-            s->needed_bytes = 1;
-            goto warn;
-
-        case 0x10:
-            s->needed_bytes = 1;
-            goto warn;
-
-        case 0x14:
-            s->needed_bytes = 2;
-            s->block_size = 0;
-            break;
-
-        case 0x1c:              /* Auto-Initialize DMA DAC, 8-bit */
-            dma_cmd8 (s, DMA8_AUTO, -1);
-            break;
-
-        case 0x20:              /* Direct ADC, Juice/PL */
-            dsp_out_data (s, 0xff);
-            goto warn;
-
-        case 0x35:
-            dolog ("0x35 - MIDI command not implemented\n");
-            break;
-
-        case 0x40:
-            s->freq = -1;
-            s->time_const = -1;
-            s->needed_bytes = 1;
-            break;
-
-        case 0x41:
-            s->freq = -1;
-            s->time_const = -1;
-            s->needed_bytes = 2;
-            break;
-
-        case 0x42:
-            s->freq = -1;
-            s->time_const = -1;
-            s->needed_bytes = 2;
-            goto warn;
-
-        case 0x45:
-            dsp_out_data (s, 0xaa);
-            goto warn;
-
-        case 0x47:                /* Continue Auto-Initialize DMA 16bit */
-            break;
-
-        case 0x48:
-            s->needed_bytes = 2;
-            break;
-
-        case 0x74:
-            s->needed_bytes = 2; /* DMA DAC, 4-bit ADPCM */
-            dolog ("0x75 - DMA DAC, 4-bit ADPCM not implemented\n");
-            break;
-
-        case 0x75:              /* DMA DAC, 4-bit ADPCM Reference */
-            s->needed_bytes = 2;
-            dolog ("0x74 - DMA DAC, 4-bit ADPCM Reference not implemented\n");
-            break;
-
-        case 0x76:              /* DMA DAC, 2.6-bit ADPCM */
-            s->needed_bytes = 2;
-            dolog ("0x74 - DMA DAC, 2.6-bit ADPCM not implemented\n");
-            break;
-
-        case 0x77:              /* DMA DAC, 2.6-bit ADPCM Reference */
-            s->needed_bytes = 2;
-            dolog ("0x74 - DMA DAC, 2.6-bit ADPCM Reference not implemented\n");
-            break;
-
-        case 0x7d:
-            dolog ("0x7d - Autio-Initialize DMA DAC, 4-bit ADPCM Reference\n");
-            dolog ("not implemented\n");
-            break;
-
-        case 0x7f:
-            dolog (
-                "0x7d - Autio-Initialize DMA DAC, 2.6-bit ADPCM Reference\n"
-                );
-            dolog ("not implemented\n");
-            break;
-
-        case 0x80:
-            s->needed_bytes = 2;
-            break;
-
-        case 0x90:
-        case 0x91:
-            dma_cmd8 (s, ((cmd & 1) == 0) | DMA8_HIGH, -1);
-            break;
-
-        case 0xd0:              /* halt DMA operation. 8bit */
-            control (s, 0);
-            break;
-
-        case 0xd1:              /* speaker on */
-            speaker (s, 1);
-            break;
-
-        case 0xd3:              /* speaker off */
-            speaker (s, 0);
-            break;
-
-        case 0xd4:              /* continue DMA operation. 8bit */
-            /* KQ6 (or maybe Sierras audblst.drv in general) resets
-               the frequency between halt/continue */
-            continue_dma8 (s);
-            break;
-
-        case 0xd5:              /* halt DMA operation. 16bit */
-            control (s, 0);
-            break;
-
-        case 0xd6:              /* continue DMA operation. 16bit */
-            control (s, 1);
-            break;
-
-        case 0xd9:              /* exit auto-init DMA after this block. 16bit */
-            s->dma_auto = 0;
-            break;
-
-        case 0xda:              /* exit auto-init DMA after this block. 8bit */
-            s->dma_auto = 0;
-            break;
-
-        case 0xe0:              /* DSP identification */
-            s->needed_bytes = 1;
-            break;
-
-        case 0xe1:
-            dsp_out_data (s, s->ver & 0xff);
-            dsp_out_data (s, s->ver >> 8);
-            break;
-
-        case 0xe2:
-            s->needed_bytes = 1;
-            goto warn;
-
-        case 0xe3:
-            {
-                int i;
-                for (i = sizeof (e3) - 1; i >= 0; --i)
-                    dsp_out_data (s, e3[i]);
-            }
-            break;
-
-        case 0xe4:              /* write test reg */
-            s->needed_bytes = 1;
-            break;
-
-        case 0xe7:
-            dolog ("Attempt to probe for ESS (0xe7)?\n");
-            break;
-
-        case 0xe8:              /* read test reg */
-            dsp_out_data (s, s->test_reg);
-            break;
-
-        case 0xf2:
-        case 0xf3:
-            dsp_out_data (s, 0xaa);
-            s->mixer_regs[0x82] |= (cmd == 0xf2) ? 1 : 2;
-            qemu_irq_raise (s->pic);
-            break;
-
-        case 0xf9:
-            s->needed_bytes = 1;
-            goto warn;
-
-        case 0xfa:
-            dsp_out_data (s, 0);
-            goto warn;
-
-        case 0xfc:              /* FIXME */
-            dsp_out_data (s, 0);
-            goto warn;
-
-        default:
-            dolog ("Unrecognized command %#x\n", cmd);
-            break;
-        }
-    }
-
-    if (!s->needed_bytes) {
-        ldebug ("\n");
-    }
-
- exit:
-    if (!s->needed_bytes) {
-        s->cmd = -1;
-    }
-    else {
-        s->cmd = cmd;
-    }
-    return;
-
- warn:
-    dolog ("warning: command %#x,%d is not truly understood yet\n",
-           cmd, s->needed_bytes);
-    goto exit;
-
-}
-
-static uint16_t dsp_get_lohi (SB16State *s)
-{
-    uint8_t hi = dsp_get_data (s);
-    uint8_t lo = dsp_get_data (s);
-    return (hi << 8) | lo;
-}
-
-static uint16_t dsp_get_hilo (SB16State *s)
-{
-    uint8_t lo = dsp_get_data (s);
-    uint8_t hi = dsp_get_data (s);
-    return (hi << 8) | lo;
-}
-
-static void complete (SB16State *s)
-{
-    int d0, d1, d2;
-    ldebug ("complete command %#x, in_index %d, needed_bytes %d\n",
-            s->cmd, s->in_index, s->needed_bytes);
-
-    if (s->cmd > 0xaf && s->cmd < 0xd0) {
-        d2 = dsp_get_data (s);
-        d1 = dsp_get_data (s);
-        d0 = dsp_get_data (s);
-
-        if (s->cmd & 8) {
-            dolog ("ADC params cmd = %#x d0 = %d, d1 = %d, d2 = %d\n",
-                   s->cmd, d0, d1, d2);
-        }
-        else {
-            ldebug ("cmd = %#x d0 = %d, d1 = %d, d2 = %d\n",
-                    s->cmd, d0, d1, d2);
-            dma_cmd (s, s->cmd, d0, d1 + (d2 << 8));
-        }
-    }
-    else {
-        switch (s->cmd) {
-        case 0x04:
-            s->csp_mode = dsp_get_data (s);
-            s->csp_reg83r = 0;
-            s->csp_reg83w = 0;
-            ldebug ("CSP command 0x04: mode=%#x\n", s->csp_mode);
-            break;
-
-        case 0x05:
-            s->csp_param = dsp_get_data (s);
-            s->csp_value = dsp_get_data (s);
-            ldebug ("CSP command 0x05: param=%#x value=%#x\n",
-                    s->csp_param,
-                    s->csp_value);
-            break;
-
-        case 0x0e:
-            d0 = dsp_get_data (s);
-            d1 = dsp_get_data (s);
-            ldebug ("write CSP register %d <- %#x\n", d1, d0);
-            if (d1 == 0x83) {
-                ldebug ("0x83[%d] <- %#x\n", s->csp_reg83r, d0);
-                s->csp_reg83[s->csp_reg83r % 4] = d0;
-                s->csp_reg83r += 1;
-            }
-            else {
-                s->csp_regs[d1] = d0;
-            }
-            break;
-
-        case 0x0f:
-            d0 = dsp_get_data (s);
-            ldebug ("read CSP register %#x -> %#x, mode=%#x\n",
-                    d0, s->csp_regs[d0], s->csp_mode);
-            if (d0 == 0x83) {
-                ldebug ("0x83[%d] -> %#x\n",
-                        s->csp_reg83w,
-                        s->csp_reg83[s->csp_reg83w % 4]);
-                dsp_out_data (s, s->csp_reg83[s->csp_reg83w % 4]);
-                s->csp_reg83w += 1;
-            }
-            else {
-                dsp_out_data (s, s->csp_regs[d0]);
-            }
-            break;
-
-        case 0x10:
-            d0 = dsp_get_data (s);
-            dolog ("cmd 0x10 d0=%#x\n", d0);
-            break;
-
-        case 0x14:
-            dma_cmd8 (s, 0, dsp_get_lohi (s) + 1);
-            break;
-
-        case 0x40:
-            s->time_const = dsp_get_data (s);
-            ldebug ("set time const %d\n", s->time_const);
-            break;
-
-        case 0x42:              /* FT2 sets output freq with this, go figure */
-#if 0
-            dolog ("cmd 0x42 might not do what it think it should\n");
-#endif
-        case 0x41:
-            s->freq = dsp_get_hilo (s);
-            ldebug ("set freq %d\n", s->freq);
-            break;
-
-        case 0x48:
-            s->block_size = dsp_get_lohi (s) + 1;
-            ldebug ("set dma block len %d\n", s->block_size);
-            break;
-
-        case 0x74:
-        case 0x75:
-        case 0x76:
-        case 0x77:
-            /* ADPCM stuff, ignore */
-            break;
-
-        case 0x80:
-            {
-                int freq, samples, bytes;
-                int64_t ticks;
-
-                freq = s->freq > 0 ? s->freq : 11025;
-                samples = dsp_get_lohi (s) + 1;
-                bytes = samples << s->fmt_stereo << (s->fmt_bits == 16);
-                ticks = muldiv64 (bytes, get_ticks_per_sec (), freq);
-                if (ticks < get_ticks_per_sec () / 1024) {
-                    qemu_irq_raise (s->pic);
-                }
-                else {
-                    if (s->aux_ts) {
-                        qemu_mod_timer (
-                            s->aux_ts,
-                            qemu_get_clock_ns (vm_clock) + ticks
-                            );
-                    }
-                }
-                ldebug ("mix silence %d %d %" PRId64 "\n", samples, bytes, ticks);
-            }
-            break;
-
-        case 0xe0:
-            d0 = dsp_get_data (s);
-            s->out_data_len = 0;
-            ldebug ("E0 data = %#x\n", d0);
-            dsp_out_data (s, ~d0);
-            break;
-
-        case 0xe2:
-#ifdef DEBUG
-            d0 = dsp_get_data (s);
-            dolog ("E2 = %#x\n", d0);
-#endif
-            break;
-
-        case 0xe4:
-            s->test_reg = dsp_get_data (s);
-            break;
-
-        case 0xf9:
-            d0 = dsp_get_data (s);
-            ldebug ("command 0xf9 with %#x\n", d0);
-            switch (d0) {
-            case 0x0e:
-                dsp_out_data (s, 0xff);
-                break;
-
-            case 0x0f:
-                dsp_out_data (s, 0x07);
-                break;
-
-            case 0x37:
-                dsp_out_data (s, 0x38);
-                break;
-
-            default:
-                dsp_out_data (s, 0x00);
-                break;
-            }
-            break;
-
-        default:
-            dolog ("complete: unrecognized command %#x\n", s->cmd);
-            return;
-        }
-    }
-
-    ldebug ("\n");
-    s->cmd = -1;
-}
-
-static void legacy_reset (SB16State *s)
-{
-    struct audsettings as;
-
-    s->freq = 11025;
-    s->fmt_signed = 0;
-    s->fmt_bits = 8;
-    s->fmt_stereo = 0;
-
-    as.freq = s->freq;
-    as.nchannels = 1;
-    as.fmt = AUD_FMT_U8;
-    as.endianness = 0;
-
-    s->voice = AUD_open_out (
-        &s->card,
-        s->voice,
-        "sb16",
-        s,
-        SB_audio_callback,
-        &as
-        );
-
-    /* Not sure about that... */
-    /* AUD_set_active_out (s->voice, 1); */
-}
-
-static void reset (SB16State *s)
-{
-    qemu_irq_lower (s->pic);
-    if (s->dma_auto) {
-        qemu_irq_raise (s->pic);
-        qemu_irq_lower (s->pic);
-    }
-
-    s->mixer_regs[0x82] = 0;
-    s->dma_auto = 0;
-    s->in_index = 0;
-    s->out_data_len = 0;
-    s->left_till_irq = 0;
-    s->needed_bytes = 0;
-    s->block_size = -1;
-    s->nzero = 0;
-    s->highspeed = 0;
-    s->v2x6 = 0;
-    s->cmd = -1;
-
-    dsp_out_data (s, 0xaa);
-    speaker (s, 0);
-    control (s, 0);
-    legacy_reset (s);
-}
-
-static IO_WRITE_PROTO (dsp_write)
-{
-    SB16State *s = opaque;
-    int iport;
-
-    iport = nport - s->port;
-
-    ldebug ("write %#x <- %#x\n", nport, val);
-    switch (iport) {
-    case 0x06:
-        switch (val) {
-        case 0x00:
-            if (s->v2x6 == 1) {
-                reset (s);
-            }
-            s->v2x6 = 0;
-            break;
-
-        case 0x01:
-        case 0x03:              /* FreeBSD kludge */
-            s->v2x6 = 1;
-            break;
-
-        case 0xc6:
-            s->v2x6 = 0;        /* Prince of Persia, csp.sys, diagnose.exe */
-            break;
-
-        case 0xb8:              /* Panic */
-            reset (s);
-            break;
-
-        case 0x39:
-            dsp_out_data (s, 0x38);
-            reset (s);
-            s->v2x6 = 0x39;
-            break;
-
-        default:
-            s->v2x6 = val;
-            break;
-        }
-        break;
-
-    case 0x0c:                  /* write data or command | write status */
-/*         if (s->highspeed) */
-/*             break; */
-
-        if (0 == s->needed_bytes) {
-            command (s, val);
-#if 0
-            if (0 == s->needed_bytes) {
-                log_dsp (s);
-            }
-#endif
-        }
-        else {
-            if (s->in_index == sizeof (s->in2_data)) {
-                dolog ("in data overrun\n");
-            }
-            else {
-                s->in2_data[s->in_index++] = val;
-                if (s->in_index == s->needed_bytes) {
-                    s->needed_bytes = 0;
-                    complete (s);
-#if 0
-                    log_dsp (s);
-#endif
-                }
-            }
-        }
-        break;
-
-    default:
-        ldebug ("(nport=%#x, val=%#x)\n", nport, val);
-        break;
-    }
-}
-
-static IO_READ_PROTO (dsp_read)
-{
-    SB16State *s = opaque;
-    int iport, retval, ack = 0;
-
-    iport = nport - s->port;
-
-    switch (iport) {
-    case 0x06:                  /* reset */
-        retval = 0xff;
-        break;
-
-    case 0x0a:                  /* read data */
-        if (s->out_data_len) {
-            retval = s->out_data[--s->out_data_len];
-            s->last_read_byte = retval;
-        }
-        else {
-            if (s->cmd != -1) {
-                dolog ("empty output buffer for command %#x\n",
-                       s->cmd);
-            }
-            retval = s->last_read_byte;
-            /* goto error; */
-        }
-        break;
-
-    case 0x0c:                  /* 0 can write */
-        retval = s->can_write ? 0 : 0x80;
-        break;
-
-    case 0x0d:                  /* timer interrupt clear */
-        /* dolog ("timer interrupt clear\n"); */
-        retval = 0;
-        break;
-
-    case 0x0e:                  /* data available status | irq 8 ack */
-        retval = (!s->out_data_len || s->highspeed) ? 0 : 0x80;
-        if (s->mixer_regs[0x82] & 1) {
-            ack = 1;
-            s->mixer_regs[0x82] &= 1;
-            qemu_irq_lower (s->pic);
-        }
-        break;
-
-    case 0x0f:                  /* irq 16 ack */
-        retval = 0xff;
-        if (s->mixer_regs[0x82] & 2) {
-            ack = 1;
-            s->mixer_regs[0x82] &= 2;
-            qemu_irq_lower (s->pic);
-        }
-        break;
-
-    default:
-        goto error;
-    }
-
-    if (!ack) {
-        ldebug ("read %#x -> %#x\n", nport, retval);
-    }
-
-    return retval;
-
- error:
-    dolog ("warning: dsp_read %#x error\n", nport);
-    return 0xff;
-}
-
-static void reset_mixer (SB16State *s)
-{
-    int i;
-
-    memset (s->mixer_regs, 0xff, 0x7f);
-    memset (s->mixer_regs + 0x83, 0xff, sizeof (s->mixer_regs) - 0x83);
-
-    s->mixer_regs[0x02] = 4;    /* master volume 3bits */
-    s->mixer_regs[0x06] = 4;    /* MIDI volume 3bits */
-    s->mixer_regs[0x08] = 0;    /* CD volume 3bits */
-    s->mixer_regs[0x0a] = 0;    /* voice volume 2bits */
-
-    /* d5=input filt, d3=lowpass filt, d1,d2=input source */
-    s->mixer_regs[0x0c] = 0;
-
-    /* d5=output filt, d1=stereo switch */
-    s->mixer_regs[0x0e] = 0;
-
-    /* voice volume L d5,d7, R d1,d3 */
-    s->mixer_regs[0x04] = (4 << 5) | (4 << 1);
-    /* master ... */
-    s->mixer_regs[0x22] = (4 << 5) | (4 << 1);
-    /* MIDI ... */
-    s->mixer_regs[0x26] = (4 << 5) | (4 << 1);
-
-    for (i = 0x30; i < 0x48; i++) {
-        s->mixer_regs[i] = 0x20;
-    }
-}
-
-static IO_WRITE_PROTO (mixer_write_indexb)
-{
-    SB16State *s = opaque;
-    (void) nport;
-    s->mixer_nreg = val;
-}
-
-static IO_WRITE_PROTO (mixer_write_datab)
-{
-    SB16State *s = opaque;
-
-    (void) nport;
-    ldebug ("mixer_write [%#x] <- %#x\n", s->mixer_nreg, val);
-
-    switch (s->mixer_nreg) {
-    case 0x00:
-        reset_mixer (s);
-        break;
-
-    case 0x80:
-        {
-            int irq = irq_of_magic (val);
-            ldebug ("setting irq to %d (val=%#x)\n", irq, val);
-            if (irq > 0) {
-                s->irq = irq;
-            }
-        }
-        break;
-
-    case 0x81:
-        {
-            int dma, hdma;
-
-            dma = ctz32 (val & 0xf);
-            hdma = ctz32 (val & 0xf0);
-            if (dma != s->dma || hdma != s->hdma) {
-                dolog (
-                    "attempt to change DMA "
-                    "8bit %d(%d), 16bit %d(%d) (val=%#x)\n",
-                    dma, s->dma, hdma, s->hdma, val);
-            }
-#if 0
-            s->dma = dma;
-            s->hdma = hdma;
-#endif
-        }
-        break;
-
-    case 0x82:
-        dolog ("attempt to write into IRQ status register (val=%#x)\n",
-               val);
-        return;
-
-    default:
-        if (s->mixer_nreg >= 0x80) {
-            ldebug ("attempt to write mixer[%#x] <- %#x\n", s->mixer_nreg, val);
-        }
-        break;
-    }
-
-    s->mixer_regs[s->mixer_nreg] = val;
-}
-
-static IO_WRITE_PROTO (mixer_write_indexw)
-{
-    mixer_write_indexb (opaque, nport, val & 0xff);
-    mixer_write_datab (opaque, nport, (val >> 8) & 0xff);
-}
-
-static IO_READ_PROTO (mixer_read)
-{
-    SB16State *s = opaque;
-
-    (void) nport;
-#ifndef DEBUG_SB16_MOST
-    if (s->mixer_nreg != 0x82) {
-        ldebug ("mixer_read[%#x] -> %#x\n",
-                s->mixer_nreg, s->mixer_regs[s->mixer_nreg]);
-    }
-#else
-    ldebug ("mixer_read[%#x] -> %#x\n",
-            s->mixer_nreg, s->mixer_regs[s->mixer_nreg]);
-#endif
-    return s->mixer_regs[s->mixer_nreg];
-}
-
-static int write_audio (SB16State *s, int nchan, int dma_pos,
-                        int dma_len, int len)
-{
-    int temp, net;
-    uint8_t tmpbuf[4096];
-
-    temp = len;
-    net = 0;
-
-    while (temp) {
-        int left = dma_len - dma_pos;
-        int copied;
-        size_t to_copy;
-
-        to_copy = audio_MIN (temp, left);
-        if (to_copy > sizeof (tmpbuf)) {
-            to_copy = sizeof (tmpbuf);
-        }
-
-        copied = DMA_read_memory (nchan, tmpbuf, dma_pos, to_copy);
-        copied = AUD_write (s->voice, tmpbuf, copied);
-
-        temp -= copied;
-        dma_pos = (dma_pos + copied) % dma_len;
-        net += copied;
-
-        if (!copied) {
-            break;
-        }
-    }
-
-    return net;
-}
-
-static int SB_read_DMA (void *opaque, int nchan, int dma_pos, int dma_len)
-{
-    SB16State *s = opaque;
-    int till, copy, written, free;
-
-    if (s->block_size <= 0) {
-        dolog ("invalid block size=%d nchan=%d dma_pos=%d dma_len=%d\n",
-               s->block_size, nchan, dma_pos, dma_len);
-        return dma_pos;
-    }
-
-    if (s->left_till_irq < 0) {
-        s->left_till_irq = s->block_size;
-    }
-
-    if (s->voice) {
-        free = s->audio_free & ~s->align;
-        if ((free <= 0) || !dma_len) {
-            return dma_pos;
-        }
-    }
-    else {
-        free = dma_len;
-    }
-
-    copy = free;
-    till = s->left_till_irq;
-
-#ifdef DEBUG_SB16_MOST
-    dolog ("pos:%06d %d till:%d len:%d\n",
-           dma_pos, free, till, dma_len);
-#endif
-
-    if (till <= copy) {
-        if (0 == s->dma_auto) {
-            copy = till;
-        }
-    }
-
-    written = write_audio (s, nchan, dma_pos, dma_len, copy);
-    dma_pos = (dma_pos + written) % dma_len;
-    s->left_till_irq -= written;
-
-    if (s->left_till_irq <= 0) {
-        s->mixer_regs[0x82] |= (nchan & 4) ? 2 : 1;
-        qemu_irq_raise (s->pic);
-        if (0 == s->dma_auto) {
-            control (s, 0);
-            speaker (s, 0);
-        }
-    }
-
-#ifdef DEBUG_SB16_MOST
-    ldebug ("pos %5d free %5d size %5d till % 5d copy %5d written %5d size %5d\n",
-            dma_pos, free, dma_len, s->left_till_irq, copy, written,
-            s->block_size);
-#endif
-
-    while (s->left_till_irq <= 0) {
-        s->left_till_irq = s->block_size + s->left_till_irq;
-    }
-
-    return dma_pos;
-}
-
-static void SB_audio_callback (void *opaque, int free)
-{
-    SB16State *s = opaque;
-    s->audio_free = free;
-}
-
-static int sb16_post_load (void *opaque, int version_id)
-{
-    SB16State *s = opaque;
-
-    if (s->voice) {
-        AUD_close_out (&s->card, s->voice);
-        s->voice = NULL;
-    }
-
-    if (s->dma_running) {
-        if (s->freq) {
-            struct audsettings as;
-
-            s->audio_free = 0;
-
-            as.freq = s->freq;
-            as.nchannels = 1 << s->fmt_stereo;
-            as.fmt = s->fmt;
-            as.endianness = 0;
-
-            s->voice = AUD_open_out (
-                &s->card,
-                s->voice,
-                "sb16",
-                s,
-                SB_audio_callback,
-                &as
-                );
-        }
-
-        control (s, 1);
-        speaker (s, s->speaker);
-    }
-    return 0;
-}
-
-static const VMStateDescription vmstate_sb16 = {
-    .name = "sb16",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .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 ()
-    }
-};
-
-static const MemoryRegionPortio sb16_ioport_list[] = {
-    {  4, 1, 1, .write = mixer_write_indexb },
-    {  4, 1, 2, .write = mixer_write_indexw },
-    {  5, 1, 1, .read = mixer_read, .write = mixer_write_datab },
-    {  6, 1, 1, .read = dsp_read, .write = dsp_write },
-    { 10, 1, 1, .read = dsp_read },
-    { 12, 1, 1, .write = dsp_write },
-    { 12, 4, 1, .read = dsp_read },
-    PORTIO_END_OF_LIST (),
-};
-
-
-static int sb16_initfn (ISADevice *dev)
-{
-    SB16State *s;
-
-    s = DO_UPCAST (SB16State, dev, dev);
-
-    s->cmd = -1;
-    isa_init_irq (dev, &s->pic, s->irq);
-
-    s->mixer_regs[0x80] = magic_of_irq (s->irq);
-    s->mixer_regs[0x81] = (1 << s->dma) | (1 << s->hdma);
-    s->mixer_regs[0x82] = 2 << 5;
-
-    s->csp_regs[5] = 1;
-    s->csp_regs[9] = 0xf8;
-
-    reset_mixer (s);
-    s->aux_ts = qemu_new_timer_ns (vm_clock, aux_timer, s);
-    if (!s->aux_ts) {
-        dolog ("warning: Could not create auxiliary timer\n");
-    }
-
-    isa_register_portio_list (dev, s->port, sb16_ioport_list, s, "sb16");
-
-    DMA_register_channel (s->hdma, SB_read_DMA, s);
-    DMA_register_channel (s->dma, SB_read_DMA, s);
-    s->can_write = 1;
-
-    AUD_register_card ("sb16", &s->card);
-    return 0;
-}
-
-int SB16_init (ISABus *bus)
-{
-    isa_create_simple (bus, "sb16");
-    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 const TypeInfo sb16_info = {
-    .name          = "sb16",
-    .parent        = TYPE_ISA_DEVICE,
-    .instance_size = sizeof (SB16State),
-    .class_init    = sb16_class_initfn,
-};
-
-static void sb16_register_types (void)
-{
-    type_register_static (&sb16_info);
-}
-
-type_init (sb16_register_types)
diff --git a/hw/sbi.c b/hw/sbi.c
deleted file mode 100644 (file)
index 8795749..0000000
--- a/hw/sbi.c
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * QEMU Sparc SBI interrupt controller emulation
- *
- * Based on slavio_intctl, copyright (c) 2003-2005 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.
- */
-
-#include "hw/sysbus.h"
-
-//#define DEBUG_IRQ
-
-#ifdef DEBUG_IRQ
-#define DPRINTF(fmt, ...)                                       \
-    do { printf("IRQ: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...)
-#endif
-
-#define MAX_CPUS 16
-
-#define SBI_NREGS 16
-
-typedef struct SBIState {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-    uint32_t regs[SBI_NREGS];
-    uint32_t intreg_pending[MAX_CPUS];
-    qemu_irq cpu_irqs[MAX_CPUS];
-    uint32_t pil_out[MAX_CPUS];
-} SBIState;
-
-#define SBI_SIZE (SBI_NREGS * 4)
-
-static void sbi_set_irq(void *opaque, int irq, int level)
-{
-}
-
-static uint64_t sbi_mem_read(void *opaque, hwaddr addr,
-                             unsigned size)
-{
-    SBIState *s = opaque;
-    uint32_t saddr, ret;
-
-    saddr = addr >> 2;
-    switch (saddr) {
-    default:
-        ret = s->regs[saddr];
-        break;
-    }
-    DPRINTF("read system reg 0x" TARGET_FMT_plx " = %x\n", addr, ret);
-
-    return ret;
-}
-
-static void sbi_mem_write(void *opaque, hwaddr addr,
-                          uint64_t val, unsigned dize)
-{
-    SBIState *s = opaque;
-    uint32_t saddr;
-
-    saddr = addr >> 2;
-    DPRINTF("write system reg 0x" TARGET_FMT_plx " = %x\n", addr, (int)val);
-    switch (saddr) {
-    default:
-        s->regs[saddr] = val;
-        break;
-    }
-}
-
-static const MemoryRegionOps sbi_mem_ops = {
-    .read = sbi_mem_read,
-    .write = sbi_mem_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-};
-
-static const VMStateDescription vmstate_sbi = {
-    .name ="sbi",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField []) {
-        VMSTATE_UINT32_ARRAY(intreg_pending, SBIState, MAX_CPUS),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void sbi_reset(DeviceState *d)
-{
-    SBIState *s = container_of(d, SBIState, busdev.qdev);
-    unsigned int i;
-
-    for (i = 0; i < MAX_CPUS; i++) {
-        s->intreg_pending[i] = 0;
-    }
-}
-
-static int sbi_init1(SysBusDevice *dev)
-{
-    SBIState *s = FROM_SYSBUS(SBIState, dev);
-    unsigned int i;
-
-    qdev_init_gpio_in(&dev->qdev, sbi_set_irq, 32 + MAX_CPUS);
-    for (i = 0; i < MAX_CPUS; i++) {
-        sysbus_init_irq(dev, &s->cpu_irqs[i]);
-    }
-
-    memory_region_init_io(&s->iomem, &sbi_mem_ops, s, "sbi", SBI_SIZE);
-    sysbus_init_mmio(dev, &s->iomem);
-
-    return 0;
-}
-
-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 const TypeInfo sbi_info = {
-    .name          = "sbi",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(SBIState),
-    .class_init    = sbi_class_init,
-};
-
-static void sbi_register_types(void)
-{
-    type_register_static(&sbi_info);
-}
-
-type_init(sbi_register_types)
diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
deleted file mode 100644 (file)
index 08787c2..0000000
+++ /dev/null
@@ -1,1885 +0,0 @@
-#include "hw/hw.h"
-#include "qemu/error-report.h"
-#include "hw/scsi.h"
-#include "hw/scsi-defs.h"
-#include "hw/qdev.h"
-#include "sysemu/blockdev.h"
-#include "trace.h"
-#include "sysemu/dma.h"
-
-static char *scsibus_get_dev_path(DeviceState *dev);
-static char *scsibus_get_fw_dev_path(DeviceState *dev);
-static int scsi_req_parse(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf);
-static void scsi_req_dequeue(SCSIRequest *req);
-
-static Property scsi_props[] = {
-    DEFINE_PROP_UINT32("channel", SCSIDevice, channel, 0),
-    DEFINE_PROP_UINT32("scsi-id", SCSIDevice, id, -1),
-    DEFINE_PROP_UINT32("lun", SCSIDevice, lun, -1),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void scsi_bus_class_init(ObjectClass *klass, void *data)
-{
-    BusClass *k = BUS_CLASS(klass);
-
-    k->get_dev_path = scsibus_get_dev_path;
-    k->get_fw_dev_path = scsibus_get_fw_dev_path;
-}
-
-static const TypeInfo scsi_bus_info = {
-    .name = TYPE_SCSI_BUS,
-    .parent = TYPE_BUS,
-    .instance_size = sizeof(SCSIBus),
-    .class_init = scsi_bus_class_init,
-};
-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)
-{
-    qbus_create_inplace(&bus->qbus, TYPE_SCSI_BUS, host, NULL);
-    bus->busnr = next_scsi_bus++;
-    bus->info = info;
-    bus->qbus.allow_hotplug = 1;
-}
-
-static void scsi_dma_restart_bh(void *opaque)
-{
-    SCSIDevice *s = opaque;
-    SCSIRequest *req, *next;
-
-    qemu_bh_delete(s->bh);
-    s->bh = NULL;
-
-    QTAILQ_FOREACH_SAFE(req, &s->requests, next, next) {
-        scsi_req_ref(req);
-        if (req->retry) {
-            req->retry = false;
-            switch (req->cmd.mode) {
-            case SCSI_XFER_FROM_DEV:
-            case SCSI_XFER_TO_DEV:
-                scsi_req_continue(req);
-                break;
-            case SCSI_XFER_NONE:
-                assert(!req->sg);
-                scsi_req_dequeue(req);
-                scsi_req_enqueue(req);
-                break;
-            }
-        }
-        scsi_req_unref(req);
-    }
-}
-
-void scsi_req_retry(SCSIRequest *req)
-{
-    /* No need to save a reference, because scsi_dma_restart_bh just
-     * looks at the request list.  */
-    req->retry = true;
-}
-
-static void scsi_dma_restart_cb(void *opaque, int running, RunState state)
-{
-    SCSIDevice *s = opaque;
-
-    if (!running) {
-        return;
-    }
-    if (!s->bh) {
-        s->bh = qemu_bh_new(scsi_dma_restart_bh, s);
-        qemu_bh_schedule(s->bh);
-    }
-}
-
-static int scsi_qdev_init(DeviceState *qdev)
-{
-    SCSIDevice *dev = SCSI_DEVICE(qdev);
-    SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, dev->qdev.parent_bus);
-    SCSIDevice *d;
-    int rc = -1;
-
-    if (dev->channel > bus->info->max_channel) {
-        error_report("bad scsi channel id: %d", dev->channel);
-        goto err;
-    }
-    if (dev->id != -1 && dev->id > bus->info->max_target) {
-        error_report("bad scsi device id: %d", dev->id);
-        goto err;
-    }
-    if (dev->lun != -1 && dev->lun > bus->info->max_lun) {
-        error_report("bad scsi device lun: %d", dev->lun);
-        goto err;
-    }
-
-    if (dev->id == -1) {
-        int id = -1;
-        if (dev->lun == -1) {
-            dev->lun = 0;
-        }
-        do {
-            d = scsi_device_find(bus, dev->channel, ++id, dev->lun);
-        } while (d && d->lun == dev->lun && id < bus->info->max_target);
-        if (d && d->lun == dev->lun) {
-            error_report("no free target");
-            goto err;
-        }
-        dev->id = id;
-    } else if (dev->lun == -1) {
-        int lun = -1;
-        do {
-            d = scsi_device_find(bus, dev->channel, dev->id, ++lun);
-        } while (d && d->lun == lun && lun < bus->info->max_lun);
-        if (d && d->lun == lun) {
-            error_report("no free lun");
-            goto err;
-        }
-        dev->lun = lun;
-    } else {
-        d = scsi_device_find(bus, dev->channel, dev->id, dev->lun);
-        assert(d);
-        if (d->lun == dev->lun && dev != d) {
-            qdev_free(&d->qdev);
-        }
-    }
-
-    QTAILQ_INIT(&dev->requests);
-    rc = scsi_device_init(dev);
-    if (rc == 0) {
-        dev->vmsentry = qemu_add_vm_change_state_handler(scsi_dma_restart_cb,
-                                                         dev);
-    }
-
-    if (bus->info->hotplug) {
-        bus->info->hotplug(bus, dev);
-    }
-
-err:
-    return rc;
-}
-
-static int scsi_qdev_exit(DeviceState *qdev)
-{
-    SCSIDevice *dev = SCSI_DEVICE(qdev);
-
-    if (dev->vmsentry) {
-        qemu_del_vm_change_state_handler(dev->vmsentry);
-    }
-    scsi_device_destroy(dev);
-    return 0;
-}
-
-/* handle legacy '-drive if=scsi,...' cmd line args */
-SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockDriverState *bdrv,
-                                      int unit, bool removable, int bootindex)
-{
-    const char *driver;
-    DeviceState *dev;
-
-    driver = bdrv_is_sg(bdrv) ? "scsi-generic" : "scsi-disk";
-    dev = qdev_create(&bus->qbus, driver);
-    qdev_prop_set_uint32(dev, "scsi-id", unit);
-    if (bootindex >= 0) {
-        qdev_prop_set_int32(dev, "bootindex", bootindex);
-    }
-    if (object_property_find(OBJECT(dev), "removable", NULL)) {
-        qdev_prop_set_bit(dev, "removable", removable);
-    }
-    if (qdev_prop_set_drive(dev, "drive", bdrv) < 0) {
-        qdev_free(dev);
-        return NULL;
-    }
-    if (qdev_init(dev) < 0)
-        return NULL;
-    return SCSI_DEVICE(dev);
-}
-
-int scsi_bus_legacy_handle_cmdline(SCSIBus *bus)
-{
-    Location loc;
-    DriveInfo *dinfo;
-    int res = 0, unit;
-
-    loc_push_none(&loc);
-    for (unit = 0; unit <= bus->info->max_target; unit++) {
-        dinfo = drive_get(IF_SCSI, bus->busnr, unit);
-        if (dinfo == NULL) {
-            continue;
-        }
-        qemu_opts_loc_restore(dinfo->opts);
-        if (!scsi_bus_legacy_add_drive(bus, dinfo->bdrv, unit, false, -1)) {
-            res = -1;
-            break;
-        }
-    }
-    loc_pop(&loc);
-    return res;
-}
-
-static int32_t scsi_invalid_field(SCSIRequest *req, uint8_t *buf)
-{
-    scsi_req_build_sense(req, SENSE_CODE(INVALID_FIELD));
-    scsi_req_complete(req, CHECK_CONDITION);
-    return 0;
-}
-
-static const struct SCSIReqOps reqops_invalid_field = {
-    .size         = sizeof(SCSIRequest),
-    .send_command = scsi_invalid_field
-};
-
-/* SCSIReqOps implementation for invalid commands.  */
-
-static int32_t scsi_invalid_command(SCSIRequest *req, uint8_t *buf)
-{
-    scsi_req_build_sense(req, SENSE_CODE(INVALID_OPCODE));
-    scsi_req_complete(req, CHECK_CONDITION);
-    return 0;
-}
-
-static const struct SCSIReqOps reqops_invalid_opcode = {
-    .size         = sizeof(SCSIRequest),
-    .send_command = scsi_invalid_command
-};
-
-/* SCSIReqOps implementation for unit attention conditions.  */
-
-static int32_t scsi_unit_attention(SCSIRequest *req, uint8_t *buf)
-{
-    if (req->dev->unit_attention.key == UNIT_ATTENTION) {
-        scsi_req_build_sense(req, req->dev->unit_attention);
-    } else if (req->bus->unit_attention.key == UNIT_ATTENTION) {
-        scsi_req_build_sense(req, req->bus->unit_attention);
-    }
-    scsi_req_complete(req, CHECK_CONDITION);
-    return 0;
-}
-
-static const struct SCSIReqOps reqops_unit_attention = {
-    .size         = sizeof(SCSIRequest),
-    .send_command = scsi_unit_attention
-};
-
-/* SCSIReqOps implementation for REPORT LUNS and for commands sent to
-   an invalid LUN.  */
-
-typedef struct SCSITargetReq SCSITargetReq;
-
-struct SCSITargetReq {
-    SCSIRequest req;
-    int len;
-    uint8_t buf[2056];
-};
-
-static void store_lun(uint8_t *outbuf, int lun)
-{
-    if (lun < 256) {
-        outbuf[1] = lun;
-        return;
-    }
-    outbuf[1] = (lun & 255);
-    outbuf[0] = (lun >> 8) | 0x40;
-}
-
-static bool scsi_target_emulate_report_luns(SCSITargetReq *r)
-{
-    BusChild *kid;
-    int i, len, n;
-    int channel, id;
-    bool found_lun0;
-
-    if (r->req.cmd.xfer < 16) {
-        return false;
-    }
-    if (r->req.cmd.buf[2] > 2) {
-        return false;
-    }
-    channel = r->req.dev->channel;
-    id = r->req.dev->id;
-    found_lun0 = false;
-    n = 0;
-    QTAILQ_FOREACH(kid, &r->req.bus->qbus.children, sibling) {
-        DeviceState *qdev = kid->child;
-        SCSIDevice *dev = SCSI_DEVICE(qdev);
-
-        if (dev->channel == channel && dev->id == id) {
-            if (dev->lun == 0) {
-                found_lun0 = true;
-            }
-            n += 8;
-        }
-    }
-    if (!found_lun0) {
-        n += 8;
-    }
-    len = MIN(n + 8, r->req.cmd.xfer & ~7);
-    if (len > sizeof(r->buf)) {
-        /* TODO: > 256 LUNs? */
-        return false;
-    }
-
-    memset(r->buf, 0, len);
-    stl_be_p(&r->buf, n);
-    i = found_lun0 ? 8 : 16;
-    QTAILQ_FOREACH(kid, &r->req.bus->qbus.children, sibling) {
-        DeviceState *qdev = kid->child;
-        SCSIDevice *dev = SCSI_DEVICE(qdev);
-
-        if (dev->channel == channel && dev->id == id) {
-            store_lun(&r->buf[i], dev->lun);
-            i += 8;
-        }
-    }
-    assert(i == n + 8);
-    r->len = len;
-    return true;
-}
-
-static bool scsi_target_emulate_inquiry(SCSITargetReq *r)
-{
-    assert(r->req.dev->lun != r->req.lun);
-    if (r->req.cmd.buf[1] & 0x2) {
-        /* Command support data - optional, not implemented */
-        return false;
-    }
-
-    if (r->req.cmd.buf[1] & 0x1) {
-        /* Vital product data */
-        uint8_t page_code = r->req.cmd.buf[2];
-        r->buf[r->len++] = page_code ; /* this page */
-        r->buf[r->len++] = 0x00;
-
-        switch (page_code) {
-        case 0x00: /* Supported page codes, mandatory */
-        {
-            int pages;
-            pages = r->len++;
-            r->buf[r->len++] = 0x00; /* list of supported pages (this page) */
-            r->buf[pages] = r->len - pages - 1; /* number of pages */
-            break;
-        }
-        default:
-            return false;
-        }
-        /* done with EVPD */
-        assert(r->len < sizeof(r->buf));
-        r->len = MIN(r->req.cmd.xfer, r->len);
-        return true;
-    }
-
-    /* Standard INQUIRY data */
-    if (r->req.cmd.buf[2] != 0) {
-        return false;
-    }
-
-    /* PAGE CODE == 0 */
-    r->len = MIN(r->req.cmd.xfer, 36);
-    memset(r->buf, 0, r->len);
-    if (r->req.lun != 0) {
-        r->buf[0] = TYPE_NO_LUN;
-    } else {
-        r->buf[0] = TYPE_NOT_PRESENT | TYPE_INACTIVE;
-        r->buf[2] = 5; /* Version */
-        r->buf[3] = 2 | 0x10; /* HiSup, response data format */
-        r->buf[4] = r->len - 5; /* Additional Length = (Len - 1) - 4 */
-        r->buf[7] = 0x10 | (r->req.bus->info->tcq ? 0x02 : 0); /* Sync, TCQ.  */
-        memcpy(&r->buf[8], "QEMU    ", 8);
-        memcpy(&r->buf[16], "QEMU TARGET     ", 16);
-        pstrcpy((char *) &r->buf[32], 4, qemu_get_version());
-    }
-    return true;
-}
-
-static int32_t scsi_target_send_command(SCSIRequest *req, uint8_t *buf)
-{
-    SCSITargetReq *r = DO_UPCAST(SCSITargetReq, req, req);
-
-    switch (buf[0]) {
-    case REPORT_LUNS:
-        if (!scsi_target_emulate_report_luns(r)) {
-            goto illegal_request;
-        }
-        break;
-    case INQUIRY:
-        if (!scsi_target_emulate_inquiry(r)) {
-            goto illegal_request;
-        }
-        break;
-    case REQUEST_SENSE:
-        r->len = scsi_device_get_sense(r->req.dev, r->buf,
-                                       MIN(req->cmd.xfer, sizeof r->buf),
-                                       (req->cmd.buf[1] & 1) == 0);
-        if (r->req.dev->sense_is_ua) {
-            scsi_device_unit_attention_reported(req->dev);
-            r->req.dev->sense_len = 0;
-            r->req.dev->sense_is_ua = false;
-        }
-        break;
-    default:
-        scsi_req_build_sense(req, SENSE_CODE(LUN_NOT_SUPPORTED));
-        scsi_req_complete(req, CHECK_CONDITION);
-        return 0;
-    illegal_request:
-        scsi_req_build_sense(req, SENSE_CODE(INVALID_FIELD));
-        scsi_req_complete(req, CHECK_CONDITION);
-        return 0;
-    }
-
-    if (!r->len) {
-        scsi_req_complete(req, GOOD);
-    }
-    return r->len;
-}
-
-static void scsi_target_read_data(SCSIRequest *req)
-{
-    SCSITargetReq *r = DO_UPCAST(SCSITargetReq, req, req);
-    uint32_t n;
-
-    n = r->len;
-    if (n > 0) {
-        r->len = 0;
-        scsi_req_data(&r->req, n);
-    } else {
-        scsi_req_complete(&r->req, GOOD);
-    }
-}
-
-static uint8_t *scsi_target_get_buf(SCSIRequest *req)
-{
-    SCSITargetReq *r = DO_UPCAST(SCSITargetReq, req, req);
-
-    return r->buf;
-}
-
-static const struct SCSIReqOps reqops_target_command = {
-    .size         = sizeof(SCSITargetReq),
-    .send_command = scsi_target_send_command,
-    .read_data    = scsi_target_read_data,
-    .get_buf      = scsi_target_get_buf,
-};
-
-
-SCSIRequest *scsi_req_alloc(const SCSIReqOps *reqops, SCSIDevice *d,
-                            uint32_t tag, uint32_t lun, void *hba_private)
-{
-    SCSIRequest *req;
-
-    req = g_malloc0(reqops->size);
-    req->refcount = 1;
-    req->bus = scsi_bus_from_device(d);
-    req->dev = d;
-    req->tag = tag;
-    req->lun = lun;
-    req->hba_private = hba_private;
-    req->status = -1;
-    req->sense_len = 0;
-    req->ops = reqops;
-    trace_scsi_req_alloc(req->dev->id, req->lun, req->tag);
-    return req;
-}
-
-SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun,
-                          uint8_t *buf, void *hba_private)
-{
-    SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, d->qdev.parent_bus);
-    SCSIRequest *req;
-    SCSICommand cmd;
-
-    if (scsi_req_parse(&cmd, d, buf) != 0) {
-        trace_scsi_req_parse_bad(d->id, lun, tag, buf[0]);
-        req = scsi_req_alloc(&reqops_invalid_opcode, d, tag, lun, hba_private);
-    } else {
-        trace_scsi_req_parsed(d->id, lun, tag, buf[0],
-                              cmd.mode, cmd.xfer);
-        if (cmd.lba != -1) {
-            trace_scsi_req_parsed_lba(d->id, lun, tag, buf[0],
-                                      cmd.lba);
-        }
-
-        if (cmd.xfer > INT32_MAX) {
-            req = scsi_req_alloc(&reqops_invalid_field, d, tag, lun, hba_private);
-        } else if ((d->unit_attention.key == UNIT_ATTENTION ||
-                   bus->unit_attention.key == UNIT_ATTENTION) &&
-                  (buf[0] != INQUIRY &&
-                   buf[0] != REPORT_LUNS &&
-                   buf[0] != GET_CONFIGURATION &&
-                   buf[0] != GET_EVENT_STATUS_NOTIFICATION &&
-
-                   /*
-                    * If we already have a pending unit attention condition,
-                    * report this one before triggering another one.
-                    */
-                   !(buf[0] == REQUEST_SENSE && d->sense_is_ua))) {
-            req = scsi_req_alloc(&reqops_unit_attention, d, tag, lun,
-                                 hba_private);
-        } else if (lun != d->lun ||
-                   buf[0] == REPORT_LUNS ||
-                   (buf[0] == REQUEST_SENSE && d->sense_len)) {
-            req = scsi_req_alloc(&reqops_target_command, d, tag, lun,
-                                 hba_private);
-        } else {
-            req = scsi_device_alloc_req(d, tag, lun, buf, hba_private);
-        }
-    }
-
-    req->cmd = cmd;
-    req->resid = req->cmd.xfer;
-
-    switch (buf[0]) {
-    case INQUIRY:
-        trace_scsi_inquiry(d->id, lun, tag, cmd.buf[1], cmd.buf[2]);
-        break;
-    case TEST_UNIT_READY:
-        trace_scsi_test_unit_ready(d->id, lun, tag);
-        break;
-    case REPORT_LUNS:
-        trace_scsi_report_luns(d->id, lun, tag);
-        break;
-    case REQUEST_SENSE:
-        trace_scsi_request_sense(d->id, lun, tag);
-        break;
-    default:
-        break;
-    }
-
-    return req;
-}
-
-uint8_t *scsi_req_get_buf(SCSIRequest *req)
-{
-    return req->ops->get_buf(req);
-}
-
-static void scsi_clear_unit_attention(SCSIRequest *req)
-{
-    SCSISense *ua;
-    if (req->dev->unit_attention.key != UNIT_ATTENTION &&
-        req->bus->unit_attention.key != UNIT_ATTENTION) {
-        return;
-    }
-
-    /*
-     * If an INQUIRY command enters the enabled command state,
-     * the device server shall [not] clear any unit attention condition;
-     * See also MMC-6, paragraphs 6.5 and 6.6.2.
-     */
-    if (req->cmd.buf[0] == INQUIRY ||
-        req->cmd.buf[0] == GET_CONFIGURATION ||
-        req->cmd.buf[0] == GET_EVENT_STATUS_NOTIFICATION) {
-        return;
-    }
-
-    if (req->dev->unit_attention.key == UNIT_ATTENTION) {
-        ua = &req->dev->unit_attention;
-    } else {
-        ua = &req->bus->unit_attention;
-    }
-
-    /*
-     * If a REPORT LUNS command enters the enabled command state, [...]
-     * the device server shall clear any pending unit attention condition
-     * with an additional sense code of REPORTED LUNS DATA HAS CHANGED.
-     */
-    if (req->cmd.buf[0] == REPORT_LUNS &&
-        !(ua->asc == SENSE_CODE(REPORTED_LUNS_CHANGED).asc &&
-          ua->ascq == SENSE_CODE(REPORTED_LUNS_CHANGED).ascq)) {
-        return;
-    }
-
-    *ua = SENSE_CODE(NO_SENSE);
-}
-
-int scsi_req_get_sense(SCSIRequest *req, uint8_t *buf, int len)
-{
-    int ret;
-
-    assert(len >= 14);
-    if (!req->sense_len) {
-        return 0;
-    }
-
-    ret = scsi_build_sense(req->sense, req->sense_len, buf, len, true);
-
-    /*
-     * FIXME: clearing unit attention conditions upon autosense should be done
-     * only if the UA_INTLCK_CTRL field in the Control mode page is set to 00b
-     * (SAM-5, 5.14).
-     *
-     * We assume UA_INTLCK_CTRL to be 00b for HBAs that support autosense, and
-     * 10b for HBAs that do not support it (do not call scsi_req_get_sense).
-     * Here we handle unit attention clearing for UA_INTLCK_CTRL == 00b.
-     */
-    if (req->dev->sense_is_ua) {
-        scsi_device_unit_attention_reported(req->dev);
-        req->dev->sense_len = 0;
-        req->dev->sense_is_ua = false;
-    }
-    return ret;
-}
-
-int scsi_device_get_sense(SCSIDevice *dev, uint8_t *buf, int len, bool fixed)
-{
-    return scsi_build_sense(dev->sense, dev->sense_len, buf, len, fixed);
-}
-
-void scsi_req_build_sense(SCSIRequest *req, SCSISense sense)
-{
-    trace_scsi_req_build_sense(req->dev->id, req->lun, req->tag,
-                               sense.key, sense.asc, sense.ascq);
-    memset(req->sense, 0, 18);
-    req->sense[0] = 0x70;
-    req->sense[2] = sense.key;
-    req->sense[7] = 10;
-    req->sense[12] = sense.asc;
-    req->sense[13] = sense.ascq;
-    req->sense_len = 18;
-}
-
-static void scsi_req_enqueue_internal(SCSIRequest *req)
-{
-    assert(!req->enqueued);
-    scsi_req_ref(req);
-    if (req->bus->info->get_sg_list) {
-        req->sg = req->bus->info->get_sg_list(req);
-    } else {
-        req->sg = NULL;
-    }
-    req->enqueued = true;
-    QTAILQ_INSERT_TAIL(&req->dev->requests, req, next);
-}
-
-int32_t scsi_req_enqueue(SCSIRequest *req)
-{
-    int32_t rc;
-
-    assert(!req->retry);
-    scsi_req_enqueue_internal(req);
-    scsi_req_ref(req);
-    rc = req->ops->send_command(req, req->cmd.buf);
-    scsi_req_unref(req);
-    return rc;
-}
-
-static void scsi_req_dequeue(SCSIRequest *req)
-{
-    trace_scsi_req_dequeue(req->dev->id, req->lun, req->tag);
-    req->retry = false;
-    if (req->enqueued) {
-        QTAILQ_REMOVE(&req->dev->requests, req, next);
-        req->enqueued = false;
-        scsi_req_unref(req);
-    }
-}
-
-static int scsi_get_performance_length(int num_desc, int type, int data_type)
-{
-    /* MMC-6, paragraph 6.7.  */
-    switch (type) {
-    case 0:
-        if ((data_type & 3) == 0) {
-            /* Each descriptor is as in Table 295 - Nominal performance.  */
-            return 16 * num_desc + 8;
-        } else {
-            /* Each descriptor is as in Table 296 - Exceptions.  */
-            return 6 * num_desc + 8;
-        }
-    case 1:
-    case 4:
-    case 5:
-        return 8 * num_desc + 8;
-    case 2:
-        return 2048 * num_desc + 8;
-    case 3:
-        return 16 * num_desc + 8;
-    default:
-        return 8;
-    }
-}
-
-static int ata_passthrough_xfer_unit(SCSIDevice *dev, uint8_t *buf)
-{
-    int byte_block = (buf[2] >> 2) & 0x1;
-    int type = (buf[2] >> 4) & 0x1;
-    int xfer_unit;
-
-    if (byte_block) {
-        if (type) {
-            xfer_unit = dev->blocksize;
-        } else {
-            xfer_unit = 512;
-        }
-    } else {
-        xfer_unit = 1;
-    }
-
-    return xfer_unit;
-}
-
-static int ata_passthrough_12_xfer_size(SCSIDevice *dev, uint8_t *buf)
-{
-    int length = buf[2] & 0x3;
-    int xfer;
-    int unit = ata_passthrough_xfer_unit(dev, buf);
-
-    switch (length) {
-    case 0:
-    case 3: /* USB-specific.  */
-    default:
-        xfer = 0;
-        break;
-    case 1:
-        xfer = buf[3];
-        break;
-    case 2:
-        xfer = buf[4];
-        break;
-    }
-
-    return xfer * unit;
-}
-
-static int ata_passthrough_16_xfer_size(SCSIDevice *dev, uint8_t *buf)
-{
-    int extend = buf[1] & 0x1;
-    int length = buf[2] & 0x3;
-    int xfer;
-    int unit = ata_passthrough_xfer_unit(dev, buf);
-
-    switch (length) {
-    case 0:
-    case 3: /* USB-specific.  */
-    default:
-        xfer = 0;
-        break;
-    case 1:
-        xfer = buf[4];
-        xfer |= (extend ? buf[3] << 8 : 0);
-        break;
-    case 2:
-        xfer = buf[6];
-        xfer |= (extend ? buf[5] << 8 : 0);
-        break;
-    }
-
-    return xfer * unit;
-}
-
-uint32_t scsi_data_cdb_length(uint8_t *buf)
-{
-    if ((buf[0] >> 5) == 0 && buf[4] == 0) {
-        return 256;
-    } else {
-        return scsi_cdb_length(buf);
-    }
-}
-
-uint32_t scsi_cdb_length(uint8_t *buf)
-{
-    switch (buf[0] >> 5) {
-    case 0:
-        return buf[4];
-        break;
-    case 1:
-    case 2:
-        return lduw_be_p(&buf[7]);
-        break;
-    case 4:
-        return ldl_be_p(&buf[10]) & 0xffffffffULL;
-        break;
-    case 5:
-        return ldl_be_p(&buf[6]) & 0xffffffffULL;
-        break;
-    default:
-        return -1;
-    }
-}
-
-static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
-{
-    cmd->xfer = scsi_cdb_length(buf);
-    switch (buf[0]) {
-    case TEST_UNIT_READY:
-    case REWIND:
-    case START_STOP:
-    case SET_CAPACITY:
-    case WRITE_FILEMARKS:
-    case WRITE_FILEMARKS_16:
-    case SPACE:
-    case RESERVE:
-    case RELEASE:
-    case ERASE:
-    case ALLOW_MEDIUM_REMOVAL:
-    case VERIFY_10:
-    case SEEK_10:
-    case SYNCHRONIZE_CACHE:
-    case SYNCHRONIZE_CACHE_16:
-    case LOCATE_16:
-    case LOCK_UNLOCK_CACHE:
-    case SET_CD_SPEED:
-    case SET_LIMITS:
-    case WRITE_LONG_10:
-    case UPDATE_BLOCK:
-    case RESERVE_TRACK:
-    case SET_READ_AHEAD:
-    case PRE_FETCH:
-    case PRE_FETCH_16:
-    case ALLOW_OVERWRITE:
-        cmd->xfer = 0;
-        break;
-    case MODE_SENSE:
-        break;
-    case WRITE_SAME_10:
-    case WRITE_SAME_16:
-        cmd->xfer = dev->blocksize;
-        break;
-    case READ_CAPACITY_10:
-        cmd->xfer = 8;
-        break;
-    case READ_BLOCK_LIMITS:
-        cmd->xfer = 6;
-        break;
-    case SEND_VOLUME_TAG:
-        /* GPCMD_SET_STREAMING from multimedia commands.  */
-        if (dev->type == TYPE_ROM) {
-            cmd->xfer = buf[10] | (buf[9] << 8);
-        } else {
-            cmd->xfer = buf[9] | (buf[8] << 8);
-        }
-        break;
-    case WRITE_6:
-        /* length 0 means 256 blocks */
-        if (cmd->xfer == 0) {
-            cmd->xfer = 256;
-        }
-    case WRITE_10:
-    case WRITE_VERIFY_10:
-    case WRITE_12:
-    case WRITE_VERIFY_12:
-    case WRITE_16:
-    case WRITE_VERIFY_16:
-        cmd->xfer *= dev->blocksize;
-        break;
-    case READ_6:
-    case READ_REVERSE:
-        /* length 0 means 256 blocks */
-        if (cmd->xfer == 0) {
-            cmd->xfer = 256;
-        }
-    case READ_10:
-    case RECOVER_BUFFERED_DATA:
-    case READ_12:
-    case READ_16:
-        cmd->xfer *= dev->blocksize;
-        break;
-    case FORMAT_UNIT:
-        /* MMC mandates the parameter list to be 12-bytes long.  Parameters
-         * for block devices are restricted to the header right now.  */
-        if (dev->type == TYPE_ROM && (buf[1] & 16)) {
-            cmd->xfer = 12;
-        } else {
-            cmd->xfer = (buf[1] & 16) == 0 ? 0 : (buf[1] & 32 ? 8 : 4);
-        }
-        break;
-    case INQUIRY:
-    case RECEIVE_DIAGNOSTIC:
-    case SEND_DIAGNOSTIC:
-        cmd->xfer = buf[4] | (buf[3] << 8);
-        break;
-    case READ_CD:
-    case READ_BUFFER:
-    case WRITE_BUFFER:
-    case SEND_CUE_SHEET:
-        cmd->xfer = buf[8] | (buf[7] << 8) | (buf[6] << 16);
-        break;
-    case PERSISTENT_RESERVE_OUT:
-        cmd->xfer = ldl_be_p(&buf[5]) & 0xffffffffULL;
-        break;
-    case ERASE_12:
-        if (dev->type == TYPE_ROM) {
-            /* MMC command GET PERFORMANCE.  */
-            cmd->xfer = scsi_get_performance_length(buf[9] | (buf[8] << 8),
-                                                    buf[10], buf[1] & 0x1f);
-        }
-        break;
-    case MECHANISM_STATUS:
-    case READ_DVD_STRUCTURE:
-    case SEND_DVD_STRUCTURE:
-    case MAINTENANCE_OUT:
-    case MAINTENANCE_IN:
-        if (dev->type == TYPE_ROM) {
-            /* GPCMD_REPORT_KEY and GPCMD_SEND_KEY from multi media commands */
-            cmd->xfer = buf[9] | (buf[8] << 8);
-        }
-        break;
-    case ATA_PASSTHROUGH_12:
-        if (dev->type == TYPE_ROM) {
-            /* BLANK command of MMC */
-            cmd->xfer = 0;
-        } else {
-            cmd->xfer = ata_passthrough_12_xfer_size(dev, buf);
-        }
-        break;
-    case ATA_PASSTHROUGH_16:
-        cmd->xfer = ata_passthrough_16_xfer_size(dev, buf);
-        break;
-    }
-    return 0;
-}
-
-static int scsi_req_stream_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
-{
-    switch (buf[0]) {
-    /* stream commands */
-    case ERASE_12:
-    case ERASE_16:
-        cmd->xfer = 0;
-        break;
-    case READ_6:
-    case READ_REVERSE:
-    case RECOVER_BUFFERED_DATA:
-    case WRITE_6:
-        cmd->xfer = buf[4] | (buf[3] << 8) | (buf[2] << 16);
-        if (buf[1] & 0x01) { /* fixed */
-            cmd->xfer *= dev->blocksize;
-        }
-        break;
-    case READ_16:
-    case READ_REVERSE_16:
-    case VERIFY_16:
-    case WRITE_16:
-        cmd->xfer = buf[14] | (buf[13] << 8) | (buf[12] << 16);
-        if (buf[1] & 0x01) { /* fixed */
-            cmd->xfer *= dev->blocksize;
-        }
-        break;
-    case REWIND:
-    case LOAD_UNLOAD:
-        cmd->xfer = 0;
-        break;
-    case SPACE_16:
-        cmd->xfer = buf[13] | (buf[12] << 8);
-        break;
-    case READ_POSITION:
-        switch (buf[1] & 0x1f) /* operation code */ {
-        case SHORT_FORM_BLOCK_ID:
-        case SHORT_FORM_VENDOR_SPECIFIC:
-            cmd->xfer = 20;
-            break;
-        case LONG_FORM:
-            cmd->xfer = 32;
-            break;
-        case EXTENDED_FORM:
-            cmd->xfer = buf[8] | (buf[7] << 8);
-            break;
-        default:
-            return -1;
-        }
-
-        break;
-    case FORMAT_UNIT:
-        cmd->xfer = buf[4] | (buf[3] << 8);
-        break;
-    /* generic commands */
-    default:
-        return scsi_req_length(cmd, dev, buf);
-    }
-    return 0;
-}
-
-static int scsi_req_medium_changer_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
-{
-    switch (buf[0]) {
-    /* medium changer commands */
-    case EXCHANGE_MEDIUM:
-    case INITIALIZE_ELEMENT_STATUS:
-    case INITIALIZE_ELEMENT_STATUS_WITH_RANGE:
-    case MOVE_MEDIUM:
-    case POSITION_TO_ELEMENT:
-        cmd->xfer = 0;
-        break;
-    case READ_ELEMENT_STATUS:
-        cmd->xfer = buf[9] | (buf[8] << 8) | (buf[7] << 16);
-        break;
-
-    /* generic commands */
-    default:
-        return scsi_req_length(cmd, dev, buf);
-    }
-    return 0;
-}
-
-
-static void scsi_cmd_xfer_mode(SCSICommand *cmd)
-{
-    if (!cmd->xfer) {
-        cmd->mode = SCSI_XFER_NONE;
-        return;
-    }
-    switch (cmd->buf[0]) {
-    case WRITE_6:
-    case WRITE_10:
-    case WRITE_VERIFY_10:
-    case WRITE_12:
-    case WRITE_VERIFY_12:
-    case WRITE_16:
-    case WRITE_VERIFY_16:
-    case COPY:
-    case COPY_VERIFY:
-    case COMPARE:
-    case CHANGE_DEFINITION:
-    case LOG_SELECT:
-    case MODE_SELECT:
-    case MODE_SELECT_10:
-    case SEND_DIAGNOSTIC:
-    case WRITE_BUFFER:
-    case FORMAT_UNIT:
-    case REASSIGN_BLOCKS:
-    case SEARCH_EQUAL:
-    case SEARCH_HIGH:
-    case SEARCH_LOW:
-    case UPDATE_BLOCK:
-    case WRITE_LONG_10:
-    case WRITE_SAME_10:
-    case WRITE_SAME_16:
-    case UNMAP:
-    case SEARCH_HIGH_12:
-    case SEARCH_EQUAL_12:
-    case SEARCH_LOW_12:
-    case MEDIUM_SCAN:
-    case SEND_VOLUME_TAG:
-    case SEND_CUE_SHEET:
-    case SEND_DVD_STRUCTURE:
-    case PERSISTENT_RESERVE_OUT:
-    case MAINTENANCE_OUT:
-        cmd->mode = SCSI_XFER_TO_DEV;
-        break;
-    case ATA_PASSTHROUGH_12:
-    case ATA_PASSTHROUGH_16:
-        /* T_DIR */
-        cmd->mode = (cmd->buf[2] & 0x8) ?
-                   SCSI_XFER_FROM_DEV : SCSI_XFER_TO_DEV;
-        break;
-    default:
-        cmd->mode = SCSI_XFER_FROM_DEV;
-        break;
-    }
-}
-
-static uint64_t scsi_cmd_lba(SCSICommand *cmd)
-{
-    uint8_t *buf = cmd->buf;
-    uint64_t lba;
-
-    switch (buf[0] >> 5) {
-    case 0:
-        lba = ldl_be_p(&buf[0]) & 0x1fffff;
-        break;
-    case 1:
-    case 2:
-    case 5:
-        lba = ldl_be_p(&buf[2]) & 0xffffffffULL;
-        break;
-    case 4:
-        lba = ldq_be_p(&buf[2]);
-        break;
-    default:
-        lba = -1;
-
-    }
-    return lba;
-}
-
-int scsi_req_parse(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
-{
-    int rc;
-
-    switch (buf[0] >> 5) {
-    case 0:
-        cmd->len = 6;
-        break;
-    case 1:
-    case 2:
-        cmd->len = 10;
-        break;
-    case 4:
-        cmd->len = 16;
-        break;
-    case 5:
-        cmd->len = 12;
-        break;
-    default:
-        return -1;
-    }
-
-    switch (dev->type) {
-    case TYPE_TAPE:
-        rc = scsi_req_stream_length(cmd, dev, buf);
-        break;
-    case TYPE_MEDIUM_CHANGER:
-        rc = scsi_req_medium_changer_length(cmd, dev, buf);
-        break;
-    default:
-        rc = scsi_req_length(cmd, dev, buf);
-        break;
-    }
-
-    if (rc != 0)
-        return rc;
-
-    memcpy(cmd->buf, buf, cmd->len);
-    scsi_cmd_xfer_mode(cmd);
-    cmd->lba = scsi_cmd_lba(cmd);
-    return 0;
-}
-
-void scsi_device_report_change(SCSIDevice *dev, SCSISense sense)
-{
-    SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, dev->qdev.parent_bus);
-
-    scsi_device_set_ua(dev, sense);
-    if (bus->info->change) {
-        bus->info->change(bus, dev, sense);
-    }
-}
-
-/*
- * Predefined sense codes
- */
-
-/* No sense data available */
-const struct SCSISense sense_code_NO_SENSE = {
-    .key = NO_SENSE , .asc = 0x00 , .ascq = 0x00
-};
-
-/* LUN not ready, Manual intervention required */
-const struct SCSISense sense_code_LUN_NOT_READY = {
-    .key = NOT_READY, .asc = 0x04, .ascq = 0x03
-};
-
-/* LUN not ready, Medium not present */
-const struct SCSISense sense_code_NO_MEDIUM = {
-    .key = NOT_READY, .asc = 0x3a, .ascq = 0x00
-};
-
-/* LUN not ready, medium removal prevented */
-const struct SCSISense sense_code_NOT_READY_REMOVAL_PREVENTED = {
-    .key = NOT_READY, .asc = 0x53, .ascq = 0x02
-};
-
-/* Hardware error, internal target failure */
-const struct SCSISense sense_code_TARGET_FAILURE = {
-    .key = HARDWARE_ERROR, .asc = 0x44, .ascq = 0x00
-};
-
-/* Illegal request, invalid command operation code */
-const struct SCSISense sense_code_INVALID_OPCODE = {
-    .key = ILLEGAL_REQUEST, .asc = 0x20, .ascq = 0x00
-};
-
-/* Illegal request, LBA out of range */
-const struct SCSISense sense_code_LBA_OUT_OF_RANGE = {
-    .key = ILLEGAL_REQUEST, .asc = 0x21, .ascq = 0x00
-};
-
-/* Illegal request, Invalid field in CDB */
-const struct SCSISense sense_code_INVALID_FIELD = {
-    .key = ILLEGAL_REQUEST, .asc = 0x24, .ascq = 0x00
-};
-
-/* Illegal request, Invalid field in parameter list */
-const struct SCSISense sense_code_INVALID_PARAM = {
-    .key = ILLEGAL_REQUEST, .asc = 0x26, .ascq = 0x00
-};
-
-/* Illegal request, Parameter list length error */
-const struct SCSISense sense_code_INVALID_PARAM_LEN = {
-    .key = ILLEGAL_REQUEST, .asc = 0x1a, .ascq = 0x00
-};
-
-/* Illegal request, LUN not supported */
-const struct SCSISense sense_code_LUN_NOT_SUPPORTED = {
-    .key = ILLEGAL_REQUEST, .asc = 0x25, .ascq = 0x00
-};
-
-/* Illegal request, Saving parameters not supported */
-const struct SCSISense sense_code_SAVING_PARAMS_NOT_SUPPORTED = {
-    .key = ILLEGAL_REQUEST, .asc = 0x39, .ascq = 0x00
-};
-
-/* Illegal request, Incompatible medium installed */
-const struct SCSISense sense_code_INCOMPATIBLE_FORMAT = {
-    .key = ILLEGAL_REQUEST, .asc = 0x30, .ascq = 0x00
-};
-
-/* Illegal request, medium removal prevented */
-const struct SCSISense sense_code_ILLEGAL_REQ_REMOVAL_PREVENTED = {
-    .key = ILLEGAL_REQUEST, .asc = 0x53, .ascq = 0x02
-};
-
-/* Command aborted, I/O process terminated */
-const struct SCSISense sense_code_IO_ERROR = {
-    .key = ABORTED_COMMAND, .asc = 0x00, .ascq = 0x06
-};
-
-/* Command aborted, I_T Nexus loss occurred */
-const struct SCSISense sense_code_I_T_NEXUS_LOSS = {
-    .key = ABORTED_COMMAND, .asc = 0x29, .ascq = 0x07
-};
-
-/* Command aborted, Logical Unit failure */
-const struct SCSISense sense_code_LUN_FAILURE = {
-    .key = ABORTED_COMMAND, .asc = 0x3e, .ascq = 0x01
-};
-
-/* Unit attention, Capacity data has changed */
-const struct SCSISense sense_code_CAPACITY_CHANGED = {
-    .key = UNIT_ATTENTION, .asc = 0x2a, .ascq = 0x09
-};
-
-/* Unit attention, Power on, reset or bus device reset occurred */
-const struct SCSISense sense_code_RESET = {
-    .key = UNIT_ATTENTION, .asc = 0x29, .ascq = 0x00
-};
-
-/* Unit attention, No medium */
-const struct SCSISense sense_code_UNIT_ATTENTION_NO_MEDIUM = {
-    .key = UNIT_ATTENTION, .asc = 0x3a, .ascq = 0x00
-};
-
-/* Unit attention, Medium may have changed */
-const struct SCSISense sense_code_MEDIUM_CHANGED = {
-    .key = UNIT_ATTENTION, .asc = 0x28, .ascq = 0x00
-};
-
-/* Unit attention, Reported LUNs data has changed */
-const struct SCSISense sense_code_REPORTED_LUNS_CHANGED = {
-    .key = UNIT_ATTENTION, .asc = 0x3f, .ascq = 0x0e
-};
-
-/* Unit attention, Device internal reset */
-const struct SCSISense sense_code_DEVICE_INTERNAL_RESET = {
-    .key = UNIT_ATTENTION, .asc = 0x29, .ascq = 0x04
-};
-
-/* Data Protection, Write Protected */
-const struct SCSISense sense_code_WRITE_PROTECTED = {
-    .key = DATA_PROTECT, .asc = 0x27, .ascq = 0x00
-};
-
-/*
- * scsi_build_sense
- *
- * Convert between fixed and descriptor sense buffers
- */
-int scsi_build_sense(uint8_t *in_buf, int in_len,
-                     uint8_t *buf, int len, bool fixed)
-{
-    bool fixed_in;
-    SCSISense sense;
-    if (!fixed && len < 8) {
-        return 0;
-    }
-
-    if (in_len == 0) {
-        sense.key = NO_SENSE;
-        sense.asc = 0;
-        sense.ascq = 0;
-    } else {
-        fixed_in = (in_buf[0] & 2) == 0;
-
-        if (fixed == fixed_in) {
-            memcpy(buf, in_buf, MIN(len, in_len));
-            return MIN(len, in_len);
-        }
-
-        if (fixed_in) {
-            sense.key = in_buf[2];
-            sense.asc = in_buf[12];
-            sense.ascq = in_buf[13];
-        } else {
-            sense.key = in_buf[1];
-            sense.asc = in_buf[2];
-            sense.ascq = in_buf[3];
-        }
-    }
-
-    memset(buf, 0, len);
-    if (fixed) {
-        /* Return fixed format sense buffer */
-        buf[0] = 0x70;
-        buf[2] = sense.key;
-        buf[7] = 10;
-        buf[12] = sense.asc;
-        buf[13] = sense.ascq;
-        return MIN(len, 18);
-    } else {
-        /* Return descriptor format sense buffer */
-        buf[0] = 0x72;
-        buf[1] = sense.key;
-        buf[2] = sense.asc;
-        buf[3] = sense.ascq;
-        return 8;
-    }
-}
-
-static const char *scsi_command_name(uint8_t cmd)
-{
-    static const char *names[] = {
-        [ TEST_UNIT_READY          ] = "TEST_UNIT_READY",
-        [ REWIND                   ] = "REWIND",
-        [ REQUEST_SENSE            ] = "REQUEST_SENSE",
-        [ FORMAT_UNIT              ] = "FORMAT_UNIT",
-        [ READ_BLOCK_LIMITS        ] = "READ_BLOCK_LIMITS",
-        [ REASSIGN_BLOCKS          ] = "REASSIGN_BLOCKS/INITIALIZE ELEMENT STATUS",
-        /* LOAD_UNLOAD and INITIALIZE_ELEMENT_STATUS use the same operation code */
-        [ READ_6                   ] = "READ_6",
-        [ WRITE_6                  ] = "WRITE_6",
-        [ SET_CAPACITY             ] = "SET_CAPACITY",
-        [ READ_REVERSE             ] = "READ_REVERSE",
-        [ WRITE_FILEMARKS          ] = "WRITE_FILEMARKS",
-        [ SPACE                    ] = "SPACE",
-        [ INQUIRY                  ] = "INQUIRY",
-        [ RECOVER_BUFFERED_DATA    ] = "RECOVER_BUFFERED_DATA",
-        [ MAINTENANCE_IN           ] = "MAINTENANCE_IN",
-        [ MAINTENANCE_OUT          ] = "MAINTENANCE_OUT",
-        [ MODE_SELECT              ] = "MODE_SELECT",
-        [ RESERVE                  ] = "RESERVE",
-        [ RELEASE                  ] = "RELEASE",
-        [ COPY                     ] = "COPY",
-        [ ERASE                    ] = "ERASE",
-        [ MODE_SENSE               ] = "MODE_SENSE",
-        [ START_STOP               ] = "START_STOP/LOAD_UNLOAD",
-        /* LOAD_UNLOAD and START_STOP use the same operation code */
-        [ RECEIVE_DIAGNOSTIC       ] = "RECEIVE_DIAGNOSTIC",
-        [ SEND_DIAGNOSTIC          ] = "SEND_DIAGNOSTIC",
-        [ ALLOW_MEDIUM_REMOVAL     ] = "ALLOW_MEDIUM_REMOVAL",
-        [ READ_CAPACITY_10         ] = "READ_CAPACITY_10",
-        [ READ_10                  ] = "READ_10",
-        [ WRITE_10                 ] = "WRITE_10",
-        [ SEEK_10                  ] = "SEEK_10/POSITION_TO_ELEMENT",
-        /* SEEK_10 and POSITION_TO_ELEMENT use the same operation code */
-        [ WRITE_VERIFY_10          ] = "WRITE_VERIFY_10",
-        [ VERIFY_10                ] = "VERIFY_10",
-        [ SEARCH_HIGH              ] = "SEARCH_HIGH",
-        [ SEARCH_EQUAL             ] = "SEARCH_EQUAL",
-        [ SEARCH_LOW               ] = "SEARCH_LOW",
-        [ SET_LIMITS               ] = "SET_LIMITS",
-        [ PRE_FETCH                ] = "PRE_FETCH/READ_POSITION",
-        /* READ_POSITION and PRE_FETCH use the same operation code */
-        [ SYNCHRONIZE_CACHE        ] = "SYNCHRONIZE_CACHE",
-        [ LOCK_UNLOCK_CACHE        ] = "LOCK_UNLOCK_CACHE",
-        [ READ_DEFECT_DATA         ] = "READ_DEFECT_DATA/INITIALIZE_ELEMENT_STATUS_WITH_RANGE",
-        /* READ_DEFECT_DATA and INITIALIZE_ELEMENT_STATUS_WITH_RANGE use the same operation code */
-        [ MEDIUM_SCAN              ] = "MEDIUM_SCAN",
-        [ COMPARE                  ] = "COMPARE",
-        [ COPY_VERIFY              ] = "COPY_VERIFY",
-        [ WRITE_BUFFER             ] = "WRITE_BUFFER",
-        [ READ_BUFFER              ] = "READ_BUFFER",
-        [ UPDATE_BLOCK             ] = "UPDATE_BLOCK",
-        [ READ_LONG_10             ] = "READ_LONG_10",
-        [ WRITE_LONG_10            ] = "WRITE_LONG_10",
-        [ CHANGE_DEFINITION        ] = "CHANGE_DEFINITION",
-        [ WRITE_SAME_10            ] = "WRITE_SAME_10",
-        [ UNMAP                    ] = "UNMAP",
-        [ READ_TOC                 ] = "READ_TOC",
-        [ REPORT_DENSITY_SUPPORT   ] = "REPORT_DENSITY_SUPPORT",
-        [ SANITIZE                 ] = "SANITIZE",
-        [ GET_CONFIGURATION        ] = "GET_CONFIGURATION",
-        [ LOG_SELECT               ] = "LOG_SELECT",
-        [ LOG_SENSE                ] = "LOG_SENSE",
-        [ MODE_SELECT_10           ] = "MODE_SELECT_10",
-        [ RESERVE_10               ] = "RESERVE_10",
-        [ RELEASE_10               ] = "RELEASE_10",
-        [ MODE_SENSE_10            ] = "MODE_SENSE_10",
-        [ PERSISTENT_RESERVE_IN    ] = "PERSISTENT_RESERVE_IN",
-        [ PERSISTENT_RESERVE_OUT   ] = "PERSISTENT_RESERVE_OUT",
-        [ WRITE_FILEMARKS_16       ] = "WRITE_FILEMARKS_16",
-        [ EXTENDED_COPY            ] = "EXTENDED_COPY",
-        [ ATA_PASSTHROUGH_16       ] = "ATA_PASSTHROUGH_16",
-        [ ACCESS_CONTROL_IN        ] = "ACCESS_CONTROL_IN",
-        [ ACCESS_CONTROL_OUT       ] = "ACCESS_CONTROL_OUT",
-        [ READ_16                  ] = "READ_16",
-        [ COMPARE_AND_WRITE        ] = "COMPARE_AND_WRITE",
-        [ WRITE_16                 ] = "WRITE_16",
-        [ WRITE_VERIFY_16          ] = "WRITE_VERIFY_16",
-        [ VERIFY_16                ] = "VERIFY_16",
-        [ PRE_FETCH_16             ] = "PRE_FETCH_16",
-        [ SYNCHRONIZE_CACHE_16     ] = "SPACE_16/SYNCHRONIZE_CACHE_16",
-        /* SPACE_16 and SYNCHRONIZE_CACHE_16 use the same operation code */
-        [ LOCATE_16                ] = "LOCATE_16",
-        [ WRITE_SAME_16            ] = "ERASE_16/WRITE_SAME_16",
-        /* ERASE_16 and WRITE_SAME_16 use the same operation code */
-        [ SERVICE_ACTION_IN_16     ] = "SERVICE_ACTION_IN_16",
-        [ WRITE_LONG_16            ] = "WRITE_LONG_16",
-        [ REPORT_LUNS              ] = "REPORT_LUNS",
-        [ ATA_PASSTHROUGH_12       ] = "BLANK/ATA_PASSTHROUGH_12",
-        [ MOVE_MEDIUM              ] = "MOVE_MEDIUM",
-        [ EXCHANGE_MEDIUM          ] = "EXCHANGE MEDIUM",
-        [ READ_12                  ] = "READ_12",
-        [ WRITE_12                 ] = "WRITE_12",
-        [ ERASE_12                 ] = "ERASE_12/GET_PERFORMANCE",
-        /* ERASE_12 and GET_PERFORMANCE use the same operation code */
-        [ SERVICE_ACTION_IN_12     ] = "SERVICE_ACTION_IN_12",
-        [ WRITE_VERIFY_12          ] = "WRITE_VERIFY_12",
-        [ VERIFY_12                ] = "VERIFY_12",
-        [ SEARCH_HIGH_12           ] = "SEARCH_HIGH_12",
-        [ SEARCH_EQUAL_12          ] = "SEARCH_EQUAL_12",
-        [ SEARCH_LOW_12            ] = "SEARCH_LOW_12",
-        [ READ_ELEMENT_STATUS      ] = "READ_ELEMENT_STATUS",
-        [ SEND_VOLUME_TAG          ] = "SEND_VOLUME_TAG/SET_STREAMING",
-        /* SEND_VOLUME_TAG and SET_STREAMING use the same operation code */
-        [ READ_CD                  ] = "READ_CD",
-        [ READ_DEFECT_DATA_12      ] = "READ_DEFECT_DATA_12",
-        [ READ_DVD_STRUCTURE       ] = "READ_DVD_STRUCTURE",
-        [ RESERVE_TRACK            ] = "RESERVE_TRACK",
-        [ SEND_CUE_SHEET           ] = "SEND_CUE_SHEET",
-        [ SEND_DVD_STRUCTURE       ] = "SEND_DVD_STRUCTURE",
-        [ SET_CD_SPEED             ] = "SET_CD_SPEED",
-        [ SET_READ_AHEAD           ] = "SET_READ_AHEAD",
-        [ ALLOW_OVERWRITE          ] = "ALLOW_OVERWRITE",
-        [ MECHANISM_STATUS         ] = "MECHANISM_STATUS",
-    };
-
-    if (cmd >= ARRAY_SIZE(names) || names[cmd] == NULL)
-        return "*UNKNOWN*";
-    return names[cmd];
-}
-
-SCSIRequest *scsi_req_ref(SCSIRequest *req)
-{
-    assert(req->refcount > 0);
-    req->refcount++;
-    return req;
-}
-
-void scsi_req_unref(SCSIRequest *req)
-{
-    assert(req->refcount > 0);
-    if (--req->refcount == 0) {
-        SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, req->dev->qdev.parent_bus);
-        if (bus->info->free_request && req->hba_private) {
-            bus->info->free_request(bus, req->hba_private);
-        }
-        if (req->ops->free_req) {
-            req->ops->free_req(req);
-        }
-        g_free(req);
-    }
-}
-
-/* Tell the device that we finished processing this chunk of I/O.  It
-   will start the next chunk or complete the command.  */
-void scsi_req_continue(SCSIRequest *req)
-{
-    if (req->io_canceled) {
-        trace_scsi_req_continue_canceled(req->dev->id, req->lun, req->tag);
-        return;
-    }
-    trace_scsi_req_continue(req->dev->id, req->lun, req->tag);
-    if (req->cmd.mode == SCSI_XFER_TO_DEV) {
-        req->ops->write_data(req);
-    } else {
-        req->ops->read_data(req);
-    }
-}
-
-/* Called by the devices when data is ready for the HBA.  The HBA should
-   start a DMA operation to read or fill the device's data buffer.
-   Once it completes, calling scsi_req_continue will restart I/O.  */
-void scsi_req_data(SCSIRequest *req, int len)
-{
-    uint8_t *buf;
-    if (req->io_canceled) {
-        trace_scsi_req_data_canceled(req->dev->id, req->lun, req->tag, len);
-        return;
-    }
-    trace_scsi_req_data(req->dev->id, req->lun, req->tag, len);
-    assert(req->cmd.mode != SCSI_XFER_NONE);
-    if (!req->sg) {
-        req->resid -= len;
-        req->bus->info->transfer_data(req, len);
-        return;
-    }
-
-    /* If the device calls scsi_req_data and the HBA specified a
-     * scatter/gather list, the transfer has to happen in a single
-     * step.  */
-    assert(!req->dma_started);
-    req->dma_started = true;
-
-    buf = scsi_req_get_buf(req);
-    if (req->cmd.mode == SCSI_XFER_FROM_DEV) {
-        req->resid = dma_buf_read(buf, len, req->sg);
-    } else {
-        req->resid = dma_buf_write(buf, len, req->sg);
-    }
-    scsi_req_continue(req);
-}
-
-void scsi_req_print(SCSIRequest *req)
-{
-    FILE *fp = stderr;
-    int i;
-
-    fprintf(fp, "[%s id=%d] %s",
-            req->dev->qdev.parent_bus->name,
-            req->dev->id,
-            scsi_command_name(req->cmd.buf[0]));
-    for (i = 1; i < req->cmd.len; i++) {
-        fprintf(fp, " 0x%02x", req->cmd.buf[i]);
-    }
-    switch (req->cmd.mode) {
-    case SCSI_XFER_NONE:
-        fprintf(fp, " - none\n");
-        break;
-    case SCSI_XFER_FROM_DEV:
-        fprintf(fp, " - from-dev len=%zd\n", req->cmd.xfer);
-        break;
-    case SCSI_XFER_TO_DEV:
-        fprintf(fp, " - to-dev len=%zd\n", req->cmd.xfer);
-        break;
-    default:
-        fprintf(fp, " - Oops\n");
-        break;
-    }
-}
-
-void scsi_req_complete(SCSIRequest *req, int status)
-{
-    assert(req->status == -1);
-    req->status = status;
-
-    assert(req->sense_len <= sizeof(req->sense));
-    if (status == GOOD) {
-        req->sense_len = 0;
-    }
-
-    if (req->sense_len) {
-        memcpy(req->dev->sense, req->sense, req->sense_len);
-        req->dev->sense_len = req->sense_len;
-        req->dev->sense_is_ua = (req->ops == &reqops_unit_attention);
-    } else {
-        req->dev->sense_len = 0;
-        req->dev->sense_is_ua = false;
-    }
-
-    /*
-     * Unit attention state is now stored in the device's sense buffer
-     * if the HBA didn't do autosense.  Clear the pending unit attention
-     * flags.
-     */
-    scsi_clear_unit_attention(req);
-
-    scsi_req_ref(req);
-    scsi_req_dequeue(req);
-    req->bus->info->complete(req, req->status, req->resid);
-    scsi_req_unref(req);
-}
-
-void scsi_req_cancel(SCSIRequest *req)
-{
-    trace_scsi_req_cancel(req->dev->id, req->lun, req->tag);
-    if (!req->enqueued) {
-        return;
-    }
-    scsi_req_ref(req);
-    scsi_req_dequeue(req);
-    req->io_canceled = true;
-    if (req->ops->cancel_io) {
-        req->ops->cancel_io(req);
-    }
-    if (req->bus->info->cancel) {
-        req->bus->info->cancel(req);
-    }
-    scsi_req_unref(req);
-}
-
-void scsi_req_abort(SCSIRequest *req, int status)
-{
-    if (!req->enqueued) {
-        return;
-    }
-    scsi_req_ref(req);
-    scsi_req_dequeue(req);
-    req->io_canceled = true;
-    if (req->ops->cancel_io) {
-        req->ops->cancel_io(req);
-    }
-    scsi_req_complete(req, status);
-    scsi_req_unref(req);
-}
-
-static int scsi_ua_precedence(SCSISense sense)
-{
-    if (sense.key != UNIT_ATTENTION) {
-        return INT_MAX;
-    }
-    if (sense.asc == 0x29 && sense.ascq == 0x04) {
-        /* DEVICE INTERNAL RESET goes with POWER ON OCCURRED */
-        return 1;
-    } else if (sense.asc == 0x3F && sense.ascq == 0x01) {
-        /* MICROCODE HAS BEEN CHANGED goes with SCSI BUS RESET OCCURRED */
-        return 2;
-    } else if (sense.asc == 0x29 && (sense.ascq == 0x05 || sense.ascq == 0x06)) {
-        /* These two go with "all others". */
-        ;
-    } else if (sense.asc == 0x29 && sense.ascq <= 0x07) {
-        /* POWER ON, RESET OR BUS DEVICE RESET OCCURRED = 0
-         * POWER ON OCCURRED = 1
-         * SCSI BUS RESET OCCURRED = 2
-         * BUS DEVICE RESET FUNCTION OCCURRED = 3
-         * I_T NEXUS LOSS OCCURRED = 7
-         */
-        return sense.ascq;
-    } else if (sense.asc == 0x2F && sense.ascq == 0x01) {
-        /* COMMANDS CLEARED BY POWER LOSS NOTIFICATION  */
-        return 8;
-    }
-    return (sense.asc << 8) | sense.ascq;
-}
-
-void scsi_device_set_ua(SCSIDevice *sdev, SCSISense sense)
-{
-    int prec1, prec2;
-    if (sense.key != UNIT_ATTENTION) {
-        return;
-    }
-    trace_scsi_device_set_ua(sdev->id, sdev->lun, sense.key,
-                             sense.asc, sense.ascq);
-
-    /*
-     * Override a pre-existing unit attention condition, except for a more
-     * important reset condition.
-    */
-    prec1 = scsi_ua_precedence(sdev->unit_attention);
-    prec2 = scsi_ua_precedence(sense);
-    if (prec2 < prec1) {
-        sdev->unit_attention = sense;
-    }
-}
-
-void scsi_device_purge_requests(SCSIDevice *sdev, SCSISense sense)
-{
-    SCSIRequest *req;
-
-    while (!QTAILQ_EMPTY(&sdev->requests)) {
-        req = QTAILQ_FIRST(&sdev->requests);
-        scsi_req_cancel(req);
-    }
-
-    scsi_device_set_ua(sdev, sense);
-}
-
-static char *scsibus_get_dev_path(DeviceState *dev)
-{
-    SCSIDevice *d = DO_UPCAST(SCSIDevice, qdev, dev);
-    DeviceState *hba = dev->parent_bus->parent;
-    char *id;
-    char *path;
-
-    id = qdev_get_dev_path(hba);
-    if (id) {
-        path = g_strdup_printf("%s/%d:%d:%d", id, d->channel, d->id, d->lun);
-    } else {
-        path = g_strdup_printf("%d:%d:%d", d->channel, d->id, d->lun);
-    }
-    g_free(id);
-    return path;
-}
-
-static char *scsibus_get_fw_dev_path(DeviceState *dev)
-{
-    SCSIDevice *d = SCSI_DEVICE(dev);
-    return g_strdup_printf("channel@%x/%s@%x,%x", d->channel,
-                           qdev_fw_name(dev), d->id, d->lun);
-}
-
-SCSIDevice *scsi_device_find(SCSIBus *bus, int channel, int id, int lun)
-{
-    BusChild *kid;
-    SCSIDevice *target_dev = NULL;
-
-    QTAILQ_FOREACH_REVERSE(kid, &bus->qbus.children, ChildrenHead, sibling) {
-        DeviceState *qdev = kid->child;
-        SCSIDevice *dev = SCSI_DEVICE(qdev);
-
-        if (dev->channel == channel && dev->id == id) {
-            if (dev->lun == lun) {
-                return dev;
-            }
-            target_dev = dev;
-        }
-    }
-    return target_dev;
-}
-
-/* SCSI request list.  For simplicity, pv points to the whole device */
-
-static void put_scsi_requests(QEMUFile *f, void *pv, size_t size)
-{
-    SCSIDevice *s = pv;
-    SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, s->qdev.parent_bus);
-    SCSIRequest *req;
-
-    QTAILQ_FOREACH(req, &s->requests, next) {
-        assert(!req->io_canceled);
-        assert(req->status == -1);
-        assert(req->enqueued);
-
-        qemu_put_sbyte(f, req->retry ? 1 : 2);
-        qemu_put_buffer(f, req->cmd.buf, sizeof(req->cmd.buf));
-        qemu_put_be32s(f, &req->tag);
-        qemu_put_be32s(f, &req->lun);
-        if (bus->info->save_request) {
-            bus->info->save_request(f, req);
-        }
-        if (req->ops->save_request) {
-            req->ops->save_request(f, req);
-        }
-    }
-    qemu_put_sbyte(f, 0);
-}
-
-static int get_scsi_requests(QEMUFile *f, void *pv, size_t size)
-{
-    SCSIDevice *s = pv;
-    SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, s->qdev.parent_bus);
-    int8_t sbyte;
-
-    while ((sbyte = qemu_get_sbyte(f)) > 0) {
-        uint8_t buf[SCSI_CMD_BUF_SIZE];
-        uint32_t tag;
-        uint32_t lun;
-        SCSIRequest *req;
-
-        qemu_get_buffer(f, buf, sizeof(buf));
-        qemu_get_be32s(f, &tag);
-        qemu_get_be32s(f, &lun);
-        req = scsi_req_new(s, tag, lun, buf, NULL);
-        req->retry = (sbyte == 1);
-        if (bus->info->load_request) {
-            req->hba_private = bus->info->load_request(f, req);
-        }
-        if (req->ops->load_request) {
-            req->ops->load_request(f, req);
-        }
-
-        /* Just restart it later.  */
-        scsi_req_enqueue_internal(req);
-
-        /* At this point, the request will be kept alive by the reference
-         * added by scsi_req_enqueue_internal, so we can release our reference.
-         * The HBA of course will add its own reference in the load_request
-         * callback if it needs to hold on the SCSIRequest.
-         */
-        scsi_req_unref(req);
-    }
-
-    return 0;
-}
-
-static int scsi_qdev_unplug(DeviceState *qdev)
-{
-    SCSIDevice *dev = SCSI_DEVICE(qdev);
-    SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, dev->qdev.parent_bus);
-
-    if (bus->info->hot_unplug) {
-        bus->info->hot_unplug(bus, dev);
-    }
-    return qdev_simple_unplug_cb(qdev);
-}
-
-static const VMStateInfo vmstate_info_scsi_requests = {
-    .name = "scsi-requests",
-    .get  = get_scsi_requests,
-    .put  = put_scsi_requests,
-};
-
-const VMStateDescription vmstate_scsi_device = {
-    .name = "SCSIDevice",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT8(unit_attention.key, SCSIDevice),
-        VMSTATE_UINT8(unit_attention.asc, SCSIDevice),
-        VMSTATE_UINT8(unit_attention.ascq, SCSIDevice),
-        VMSTATE_BOOL(sense_is_ua, SCSIDevice),
-        VMSTATE_UINT8_ARRAY(sense, SCSIDevice, SCSI_SENSE_BUF_SIZE),
-        VMSTATE_UINT32(sense_len, SCSIDevice),
-        {
-            .name         = "requests",
-            .version_id   = 0,
-            .field_exists = NULL,
-            .size         = 0,   /* ouch */
-            .info         = &vmstate_info_scsi_requests,
-            .flags        = VMS_SINGLE,
-            .offset       = 0,
-        },
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void scsi_device_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *k = DEVICE_CLASS(klass);
-    k->bus_type = TYPE_SCSI_BUS;
-    k->init     = scsi_qdev_init;
-    k->unplug   = scsi_qdev_unplug;
-    k->exit     = scsi_qdev_exit;
-    k->props    = scsi_props;
-}
-
-static const 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_types(void)
-{
-    type_register_static(&scsi_bus_info);
-    type_register_static(&scsi_device_type_info);
-}
-
-type_init(scsi_register_types)
diff --git a/hw/scsi-defs.h b/hw/scsi-defs.h
deleted file mode 100644 (file)
index 9ab045b..0000000
+++ /dev/null
@@ -1,307 +0,0 @@
-/* Copyright (C) 1998, 1999 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-
-   The GNU C 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.1 of the License, or (at your option) any later version.
-
-   The GNU C 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/>.
-*/
-
-/*
- * This header file contains public constants and structures used by
- * the scsi code for linux.
- */
-#ifndef HW_SCSI_DEFS_H
-#define HW_SCSI_DEFS_H 1
-
-/*
- *      SCSI opcodes
- */
-
-#define TEST_UNIT_READY       0x00
-#define REWIND                0x01
-#define REQUEST_SENSE         0x03
-#define FORMAT_UNIT           0x04
-#define READ_BLOCK_LIMITS     0x05
-#define INITIALIZE_ELEMENT_STATUS 0x07
-#define REASSIGN_BLOCKS       0x07
-#define READ_6                0x08
-#define WRITE_6               0x0a
-#define SET_CAPACITY          0x0b
-#define READ_REVERSE          0x0f
-#define WRITE_FILEMARKS       0x10
-#define SPACE                 0x11
-#define INQUIRY               0x12
-#define RECOVER_BUFFERED_DATA 0x14
-#define MODE_SELECT           0x15
-#define RESERVE               0x16
-#define RELEASE               0x17
-#define COPY                  0x18
-#define ERASE                 0x19
-#define MODE_SENSE            0x1a
-#define LOAD_UNLOAD           0x1b
-#define START_STOP            0x1b
-#define RECEIVE_DIAGNOSTIC    0x1c
-#define SEND_DIAGNOSTIC       0x1d
-#define ALLOW_MEDIUM_REMOVAL  0x1e
-#define READ_CAPACITY_10      0x25
-#define READ_10               0x28
-#define WRITE_10              0x2a
-#define SEEK_10               0x2b
-#define LOCATE_10             0x2b
-#define POSITION_TO_ELEMENT   0x2b
-#define WRITE_VERIFY_10       0x2e
-#define VERIFY_10             0x2f
-#define SEARCH_HIGH           0x30
-#define SEARCH_EQUAL          0x31
-#define SEARCH_LOW            0x32
-#define SET_LIMITS            0x33
-#define PRE_FETCH             0x34
-#define READ_POSITION         0x34
-#define SYNCHRONIZE_CACHE     0x35
-#define LOCK_UNLOCK_CACHE     0x36
-#define INITIALIZE_ELEMENT_STATUS_WITH_RANGE 0x37
-#define READ_DEFECT_DATA      0x37
-#define MEDIUM_SCAN           0x38
-#define COMPARE               0x39
-#define COPY_VERIFY           0x3a
-#define WRITE_BUFFER          0x3b
-#define READ_BUFFER           0x3c
-#define UPDATE_BLOCK          0x3d
-#define READ_LONG_10          0x3e
-#define WRITE_LONG_10         0x3f
-#define CHANGE_DEFINITION     0x40
-#define WRITE_SAME_10         0x41
-#define UNMAP                 0x42
-#define READ_TOC              0x43
-#define REPORT_DENSITY_SUPPORT 0x44
-#define GET_CONFIGURATION     0x46
-#define SANITIZE              0x48
-#define GET_EVENT_STATUS_NOTIFICATION 0x4a
-#define LOG_SELECT            0x4c
-#define LOG_SENSE             0x4d
-#define READ_DISC_INFORMATION 0x51
-#define RESERVE_TRACK         0x53
-#define MODE_SELECT_10        0x55
-#define RESERVE_10            0x56
-#define RELEASE_10            0x57
-#define MODE_SENSE_10         0x5a
-#define SEND_CUE_SHEET        0x5d
-#define PERSISTENT_RESERVE_IN 0x5e
-#define PERSISTENT_RESERVE_OUT 0x5f
-#define VARLENGTH_CDB         0x7f
-#define WRITE_FILEMARKS_16    0x80
-#define READ_REVERSE_16       0x81
-#define ALLOW_OVERWRITE       0x82
-#define EXTENDED_COPY         0x83
-#define ATA_PASSTHROUGH_16    0x85
-#define ACCESS_CONTROL_IN     0x86
-#define ACCESS_CONTROL_OUT    0x87
-#define READ_16               0x88
-#define COMPARE_AND_WRITE     0x89
-#define WRITE_16              0x8a
-#define WRITE_VERIFY_16       0x8e
-#define VERIFY_16             0x8f
-#define PRE_FETCH_16          0x90
-#define SPACE_16              0x91
-#define SYNCHRONIZE_CACHE_16  0x91
-#define LOCATE_16             0x92
-#define WRITE_SAME_16         0x93
-#define ERASE_16              0x93
-#define SERVICE_ACTION_IN_16  0x9e
-#define WRITE_LONG_16         0x9f
-#define REPORT_LUNS           0xa0
-#define ATA_PASSTHROUGH_12    0xa1
-#define MAINTENANCE_IN        0xa3
-#define MAINTENANCE_OUT       0xa4
-#define MOVE_MEDIUM           0xa5
-#define EXCHANGE_MEDIUM       0xa6
-#define SET_READ_AHEAD        0xa7
-#define READ_12               0xa8
-#define WRITE_12              0xaa
-#define SERVICE_ACTION_IN_12  0xab
-#define ERASE_12              0xac
-#define READ_DVD_STRUCTURE    0xad
-#define WRITE_VERIFY_12       0xae
-#define VERIFY_12             0xaf
-#define SEARCH_HIGH_12        0xb0
-#define SEARCH_EQUAL_12       0xb1
-#define SEARCH_LOW_12         0xb2
-#define READ_ELEMENT_STATUS   0xb8
-#define SEND_VOLUME_TAG       0xb6
-#define READ_DEFECT_DATA_12   0xb7
-#define SET_CD_SPEED          0xbb
-#define MECHANISM_STATUS      0xbd
-#define READ_CD               0xbe
-#define SEND_DVD_STRUCTURE    0xbf
-
-/*
- * SERVICE ACTION IN subcodes
- */
-#define SAI_READ_CAPACITY_16  0x10
-
-/*
- * READ POSITION service action codes
- */
-#define SHORT_FORM_BLOCK_ID  0x00
-#define SHORT_FORM_VENDOR_SPECIFIC 0x01
-#define LONG_FORM            0x06
-#define EXTENDED_FORM        0x08
-
-/*
- *  SAM Status codes
- */
-
-#define GOOD                 0x00
-#define CHECK_CONDITION      0x02
-#define CONDITION_GOOD       0x04
-#define BUSY                 0x08
-#define INTERMEDIATE_GOOD    0x10
-#define INTERMEDIATE_C_GOOD  0x14
-#define RESERVATION_CONFLICT 0x18
-#define COMMAND_TERMINATED   0x22
-#define TASK_SET_FULL        0x28
-#define ACA_ACTIVE           0x30
-#define TASK_ABORTED         0x40
-
-#define STATUS_MASK          0x3e
-
-/*
- *  SENSE KEYS
- */
-
-#define NO_SENSE            0x00
-#define RECOVERED_ERROR     0x01
-#define NOT_READY           0x02
-#define MEDIUM_ERROR        0x03
-#define HARDWARE_ERROR      0x04
-#define ILLEGAL_REQUEST     0x05
-#define UNIT_ATTENTION      0x06
-#define DATA_PROTECT        0x07
-#define BLANK_CHECK         0x08
-#define COPY_ABORTED        0x0a
-#define ABORTED_COMMAND     0x0b
-#define VOLUME_OVERFLOW     0x0d
-#define MISCOMPARE          0x0e
-
-
-/*
- *  DEVICE TYPES
- */
-
-#define TYPE_DISK           0x00
-#define TYPE_TAPE           0x01
-#define TYPE_PRINTER        0x02
-#define TYPE_PROCESSOR      0x03    /* HP scanners use this */
-#define TYPE_WORM           0x04    /* Treated as ROM by our system */
-#define TYPE_ROM            0x05
-#define TYPE_SCANNER        0x06
-#define TYPE_MOD            0x07    /* Magneto-optical disk -
-                                    * - treated as TYPE_DISK */
-#define TYPE_MEDIUM_CHANGER 0x08
-#define TYPE_STORAGE_ARRAY  0x0c    /* Storage array device */
-#define TYPE_ENCLOSURE      0x0d    /* Enclosure Services Device */
-#define TYPE_RBC            0x0e    /* Simplified Direct-Access Device */
-#define TYPE_OSD            0x11    /* Object-storage Device */
-#define TYPE_WLUN           0x1e    /* Well known LUN */
-#define TYPE_NOT_PRESENT    0x1f
-#define TYPE_INACTIVE       0x20
-#define TYPE_NO_LUN         0x7f
-
-/* Mode page codes for mode sense/set */
-#define MODE_PAGE_R_W_ERROR                   0x01
-#define MODE_PAGE_HD_GEOMETRY                 0x04
-#define MODE_PAGE_FLEXIBLE_DISK_GEOMETRY      0x05
-#define MODE_PAGE_CACHING                     0x08
-#define MODE_PAGE_AUDIO_CTL                   0x0e
-#define MODE_PAGE_POWER                       0x1a
-#define MODE_PAGE_FAULT_FAIL                  0x1c
-#define MODE_PAGE_TO_PROTECT                  0x1d
-#define MODE_PAGE_CAPABILITIES                0x2a
-#define MODE_PAGE_ALLS                        0x3f
-/* Not in Mt. Fuji, but in ATAPI 2.6 -- depricated now in favor
- * of MODE_PAGE_SENSE_POWER */
-#define MODE_PAGE_CDROM                       0x0d
-
-/* Event notification classes for GET EVENT STATUS NOTIFICATION */
-#define GESN_NO_EVENTS                0
-#define GESN_OPERATIONAL_CHANGE       1
-#define GESN_POWER_MANAGEMENT         2
-#define GESN_EXTERNAL_REQUEST         3
-#define GESN_MEDIA                    4
-#define GESN_MULTIPLE_HOSTS           5
-#define GESN_DEVICE_BUSY              6
-
-/* Event codes for MEDIA event status notification */
-#define MEC_NO_CHANGE                 0
-#define MEC_EJECT_REQUESTED           1
-#define MEC_NEW_MEDIA                 2
-#define MEC_MEDIA_REMOVAL             3 /* only for media changers */
-#define MEC_MEDIA_CHANGED             4 /* only for media changers */
-#define MEC_BG_FORMAT_COMPLETED       5 /* MRW or DVD+RW b/g format completed */
-#define MEC_BG_FORMAT_RESTARTED       6 /* MRW or DVD+RW b/g format restarted */
-
-#define MS_TRAY_OPEN                  1
-#define MS_MEDIA_PRESENT              2
-
-/*
- * Based on values from <linux/cdrom.h> but extending CD_MINS
- * to the maximum common size allowed by the Orange's Book ATIP
- *
- * 90 and 99 min CDs are also available but using them as the
- * upper limit reduces the effectiveness of the heuristic to
- * detect DVDs burned to less than 25% of their maximum capacity
- */
-
-/* Some generally useful CD-ROM information */
-#define CD_MINS                       80 /* max. minutes per CD */
-#define CD_SECS                       60 /* seconds per minute */
-#define CD_FRAMES                     75 /* frames per second */
-#define CD_FRAMESIZE                2048 /* bytes per frame, "cooked" mode */
-#define CD_MAX_BYTES       (CD_MINS * CD_SECS * CD_FRAMES * CD_FRAMESIZE)
-#define CD_MAX_SECTORS     (CD_MAX_BYTES / 512)
-
-/*
- * The MMC values are not IDE specific and might need to be moved
- * to a common header if they are also needed for the SCSI emulation
- */
-
-/* Profile list from MMC-6 revision 1 table 91 */
-#define MMC_PROFILE_NONE                0x0000
-#define MMC_PROFILE_CD_ROM              0x0008
-#define MMC_PROFILE_CD_R                0x0009
-#define MMC_PROFILE_CD_RW               0x000A
-#define MMC_PROFILE_DVD_ROM             0x0010
-#define MMC_PROFILE_DVD_R_SR            0x0011
-#define MMC_PROFILE_DVD_RAM             0x0012
-#define MMC_PROFILE_DVD_RW_RO           0x0013
-#define MMC_PROFILE_DVD_RW_SR           0x0014
-#define MMC_PROFILE_DVD_R_DL_SR         0x0015
-#define MMC_PROFILE_DVD_R_DL_JR         0x0016
-#define MMC_PROFILE_DVD_RW_DL           0x0017
-#define MMC_PROFILE_DVD_DDR             0x0018
-#define MMC_PROFILE_DVD_PLUS_RW         0x001A
-#define MMC_PROFILE_DVD_PLUS_R          0x001B
-#define MMC_PROFILE_DVD_PLUS_RW_DL      0x002A
-#define MMC_PROFILE_DVD_PLUS_R_DL       0x002B
-#define MMC_PROFILE_BD_ROM              0x0040
-#define MMC_PROFILE_BD_R_SRM            0x0041
-#define MMC_PROFILE_BD_R_RRM            0x0042
-#define MMC_PROFILE_BD_RE               0x0043
-#define MMC_PROFILE_HDDVD_ROM           0x0050
-#define MMC_PROFILE_HDDVD_R             0x0051
-#define MMC_PROFILE_HDDVD_RAM           0x0052
-#define MMC_PROFILE_HDDVD_RW            0x0053
-#define MMC_PROFILE_HDDVD_R_DL          0x0058
-#define MMC_PROFILE_HDDVD_RW_DL         0x005A
-#define MMC_PROFILE_INVALID             0xFFFF
-
-#endif
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
deleted file mode 100644 (file)
index c5c7bf3..0000000
+++ /dev/null
@@ -1,2526 +0,0 @@
-/*
- * SCSI Device emulation
- *
- * Copyright (c) 2006 CodeSourcery.
- * Based on code by Fabrice Bellard
- *
- * Written by Paul Brook
- * Modifications:
- *  2009-Dec-12 Artyom Tarasenko : implemented stamdard inquiry for the case
- *                                 when the allocation length of CDB is smaller
- *                                 than 36.
- *  2009-Oct-13 Artyom Tarasenko : implemented the block descriptor in the
- *                                 MODE SENSE response.
- *
- * This code is licensed under the LGPL.
- *
- * Note that this file only handles the SCSI architecture model and device
- * commands.  Emulation of interface/link layer protocols is handled by
- * the host adapter emulator.
- */
-
-//#define DEBUG_SCSI
-
-#ifdef DEBUG_SCSI
-#define DPRINTF(fmt, ...) \
-do { printf("scsi-disk: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...) do {} while(0)
-#endif
-
-#include "qemu-common.h"
-#include "qemu/error-report.h"
-#include "hw/scsi.h"
-#include "hw/scsi-defs.h"
-#include "sysemu/sysemu.h"
-#include "sysemu/blockdev.h"
-#include "hw/block-common.h"
-#include "sysemu/dma.h"
-
-#ifdef __linux
-#include <scsi/sg.h>
-#endif
-
-#define SCSI_DMA_BUF_SIZE           131072
-#define SCSI_MAX_INQUIRY_LEN        256
-#define SCSI_MAX_MODE_LEN           256
-
-#define DEFAULT_DISCARD_GRANULARITY 4096
-
-typedef struct SCSIDiskState SCSIDiskState;
-
-typedef struct SCSIDiskReq {
-    SCSIRequest req;
-    /* Both sector and sector_count are in terms of qemu 512 byte blocks.  */
-    uint64_t sector;
-    uint32_t sector_count;
-    uint32_t buflen;
-    bool started;
-    struct iovec iov;
-    QEMUIOVector qiov;
-    BlockAcctCookie acct;
-} SCSIDiskReq;
-
-#define SCSI_DISK_F_REMOVABLE   0
-#define SCSI_DISK_F_DPOFUA      1
-
-struct SCSIDiskState
-{
-    SCSIDevice qdev;
-    uint32_t features;
-    bool media_changed;
-    bool media_event;
-    bool eject_request;
-    uint64_t wwn;
-    QEMUBH *bh;
-    char *version;
-    char *serial;
-    char *vendor;
-    char *product;
-    bool tray_open;
-    bool tray_locked;
-};
-
-static int scsi_handle_rw_error(SCSIDiskReq *r, int error);
-
-static void scsi_free_request(SCSIRequest *req)
-{
-    SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
-
-    qemu_vfree(r->iov.iov_base);
-}
-
-/* Helper function for command completion with sense.  */
-static void scsi_check_condition(SCSIDiskReq *r, SCSISense sense)
-{
-    DPRINTF("Command complete tag=0x%x sense=%d/%d/%d\n",
-            r->req.tag, sense.key, sense.asc, sense.ascq);
-    scsi_req_build_sense(&r->req, sense);
-    scsi_req_complete(&r->req, CHECK_CONDITION);
-}
-
-/* Cancel a pending data transfer.  */
-static void scsi_cancel_io(SCSIRequest *req)
-{
-    SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
-
-    DPRINTF("Cancel tag=0x%x\n", req->tag);
-    if (r->req.aiocb) {
-        bdrv_aio_cancel(r->req.aiocb);
-
-        /* This reference was left in by scsi_*_data.  We take ownership of
-         * it the moment scsi_req_cancel is called, independent of whether
-         * bdrv_aio_cancel completes the request or not.  */
-        scsi_req_unref(&r->req);
-    }
-    r->req.aiocb = NULL;
-}
-
-static uint32_t scsi_init_iovec(SCSIDiskReq *r, size_t size)
-{
-    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
-
-    if (!r->iov.iov_base) {
-        r->buflen = size;
-        r->iov.iov_base = qemu_blockalign(s->qdev.conf.bs, r->buflen);
-    }
-    r->iov.iov_len = MIN(r->sector_count * 512, r->buflen);
-    qemu_iovec_init_external(&r->qiov, &r->iov, 1);
-    return r->qiov.size / 512;
-}
-
-static void scsi_disk_save_request(QEMUFile *f, SCSIRequest *req)
-{
-    SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
-
-    qemu_put_be64s(f, &r->sector);
-    qemu_put_be32s(f, &r->sector_count);
-    qemu_put_be32s(f, &r->buflen);
-    if (r->buflen) {
-        if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
-            qemu_put_buffer(f, r->iov.iov_base, r->iov.iov_len);
-        } else if (!req->retry) {
-            uint32_t len = r->iov.iov_len;
-            qemu_put_be32s(f, &len);
-            qemu_put_buffer(f, r->iov.iov_base, r->iov.iov_len);
-        }
-    }
-}
-
-static void scsi_disk_load_request(QEMUFile *f, SCSIRequest *req)
-{
-    SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
-
-    qemu_get_be64s(f, &r->sector);
-    qemu_get_be32s(f, &r->sector_count);
-    qemu_get_be32s(f, &r->buflen);
-    if (r->buflen) {
-        scsi_init_iovec(r, r->buflen);
-        if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
-            qemu_get_buffer(f, r->iov.iov_base, r->iov.iov_len);
-        } else if (!r->req.retry) {
-            uint32_t len;
-            qemu_get_be32s(f, &len);
-            r->iov.iov_len = len;
-            assert(r->iov.iov_len <= r->buflen);
-            qemu_get_buffer(f, r->iov.iov_base, r->iov.iov_len);
-        }
-    }
-
-    qemu_iovec_init_external(&r->qiov, &r->iov, 1);
-}
-
-static void scsi_aio_complete(void *opaque, int ret)
-{
-    SCSIDiskReq *r = (SCSIDiskReq *)opaque;
-    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
-
-    assert(r->req.aiocb != NULL);
-    r->req.aiocb = NULL;
-    bdrv_acct_done(s->qdev.conf.bs, &r->acct);
-    if (r->req.io_canceled) {
-        goto done;
-    }
-
-    if (ret < 0) {
-        if (scsi_handle_rw_error(r, -ret)) {
-            goto done;
-        }
-    }
-
-    scsi_req_complete(&r->req, GOOD);
-
-done:
-    if (!r->req.io_canceled) {
-        scsi_req_unref(&r->req);
-    }
-}
-
-static bool scsi_is_cmd_fua(SCSICommand *cmd)
-{
-    switch (cmd->buf[0]) {
-    case READ_10:
-    case READ_12:
-    case READ_16:
-    case WRITE_10:
-    case WRITE_12:
-    case WRITE_16:
-        return (cmd->buf[1] & 8) != 0;
-
-    case VERIFY_10:
-    case VERIFY_12:
-    case VERIFY_16:
-    case WRITE_VERIFY_10:
-    case WRITE_VERIFY_12:
-    case WRITE_VERIFY_16:
-        return true;
-
-    case READ_6:
-    case WRITE_6:
-    default:
-        return false;
-    }
-}
-
-static void scsi_write_do_fua(SCSIDiskReq *r)
-{
-    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
-
-    if (r->req.io_canceled) {
-        goto done;
-    }
-
-    if (scsi_is_cmd_fua(&r->req.cmd)) {
-        bdrv_acct_start(s->qdev.conf.bs, &r->acct, 0, BDRV_ACCT_FLUSH);
-        r->req.aiocb = bdrv_aio_flush(s->qdev.conf.bs, scsi_aio_complete, r);
-        return;
-    }
-
-    scsi_req_complete(&r->req, GOOD);
-
-done:
-    if (!r->req.io_canceled) {
-        scsi_req_unref(&r->req);
-    }
-}
-
-static void scsi_dma_complete(void *opaque, int ret)
-{
-    SCSIDiskReq *r = (SCSIDiskReq *)opaque;
-    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
-
-    assert(r->req.aiocb != NULL);
-    r->req.aiocb = NULL;
-    bdrv_acct_done(s->qdev.conf.bs, &r->acct);
-    if (r->req.io_canceled) {
-        goto done;
-    }
-
-    if (ret < 0) {
-        if (scsi_handle_rw_error(r, -ret)) {
-            goto done;
-        }
-    }
-
-    r->sector += r->sector_count;
-    r->sector_count = 0;
-    if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
-        scsi_write_do_fua(r);
-        return;
-    } else {
-        scsi_req_complete(&r->req, GOOD);
-    }
-
-done:
-    if (!r->req.io_canceled) {
-        scsi_req_unref(&r->req);
-    }
-}
-
-static void scsi_read_complete(void * opaque, int ret)
-{
-    SCSIDiskReq *r = (SCSIDiskReq *)opaque;
-    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
-    int n;
-
-    assert(r->req.aiocb != NULL);
-    r->req.aiocb = NULL;
-    bdrv_acct_done(s->qdev.conf.bs, &r->acct);
-    if (r->req.io_canceled) {
-        goto done;
-    }
-
-    if (ret < 0) {
-        if (scsi_handle_rw_error(r, -ret)) {
-            goto done;
-        }
-    }
-
-    DPRINTF("Data ready tag=0x%x len=%zd\n", r->req.tag, r->qiov.size);
-
-    n = r->qiov.size / 512;
-    r->sector += n;
-    r->sector_count -= n;
-    scsi_req_data(&r->req, r->qiov.size);
-
-done:
-    if (!r->req.io_canceled) {
-        scsi_req_unref(&r->req);
-    }
-}
-
-/* Actually issue a read to the block device.  */
-static void scsi_do_read(void *opaque, int ret)
-{
-    SCSIDiskReq *r = opaque;
-    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
-    uint32_t n;
-
-    if (r->req.aiocb != NULL) {
-        r->req.aiocb = NULL;
-        bdrv_acct_done(s->qdev.conf.bs, &r->acct);
-    }
-    if (r->req.io_canceled) {
-        goto done;
-    }
-
-    if (ret < 0) {
-        if (scsi_handle_rw_error(r, -ret)) {
-            goto done;
-        }
-    }
-
-    /* The request is used as the AIO opaque value, so add a ref.  */
-    scsi_req_ref(&r->req);
-
-    if (r->req.sg) {
-        dma_acct_start(s->qdev.conf.bs, &r->acct, r->req.sg, BDRV_ACCT_READ);
-        r->req.resid -= r->req.sg->size;
-        r->req.aiocb = dma_bdrv_read(s->qdev.conf.bs, r->req.sg, r->sector,
-                                     scsi_dma_complete, r);
-    } else {
-        n = scsi_init_iovec(r, SCSI_DMA_BUF_SIZE);
-        bdrv_acct_start(s->qdev.conf.bs, &r->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_READ);
-        r->req.aiocb = bdrv_aio_readv(s->qdev.conf.bs, r->sector, &r->qiov, n,
-                                      scsi_read_complete, r);
-    }
-
-done:
-    if (!r->req.io_canceled) {
-        scsi_req_unref(&r->req);
-    }
-}
-
-/* Read more data from scsi device into buffer.  */
-static void scsi_read_data(SCSIRequest *req)
-{
-    SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
-    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
-    bool first;
-
-    DPRINTF("Read sector_count=%d\n", r->sector_count);
-    if (r->sector_count == 0) {
-        /* This also clears the sense buffer for REQUEST SENSE.  */
-        scsi_req_complete(&r->req, GOOD);
-        return;
-    }
-
-    /* No data transfer may already be in progress */
-    assert(r->req.aiocb == NULL);
-
-    /* The request is used as the AIO opaque value, so add a ref.  */
-    scsi_req_ref(&r->req);
-    if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
-        DPRINTF("Data transfer direction invalid\n");
-        scsi_read_complete(r, -EINVAL);
-        return;
-    }
-
-    if (s->tray_open) {
-        scsi_read_complete(r, -ENOMEDIUM);
-        return;
-    }
-
-    first = !r->started;
-    r->started = true;
-    if (first && scsi_is_cmd_fua(&r->req.cmd)) {
-        bdrv_acct_start(s->qdev.conf.bs, &r->acct, 0, BDRV_ACCT_FLUSH);
-        r->req.aiocb = bdrv_aio_flush(s->qdev.conf.bs, scsi_do_read, r);
-    } else {
-        scsi_do_read(r, 0);
-    }
-}
-
-/*
- * scsi_handle_rw_error has two return values.  0 means that the error
- * must be ignored, 1 means that the error has been processed and the
- * caller should not do anything else for this request.  Note that
- * scsi_handle_rw_error always manages its reference counts, independent
- * of the return value.
- */
-static int scsi_handle_rw_error(SCSIDiskReq *r, int error)
-{
-    bool is_read = (r->req.cmd.xfer == SCSI_XFER_FROM_DEV);
-    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
-    BlockErrorAction action = bdrv_get_error_action(s->qdev.conf.bs, is_read, error);
-
-    if (action == BDRV_ACTION_REPORT) {
-        switch (error) {
-        case ENOMEDIUM:
-            scsi_check_condition(r, SENSE_CODE(NO_MEDIUM));
-            break;
-        case ENOMEM:
-            scsi_check_condition(r, SENSE_CODE(TARGET_FAILURE));
-            break;
-        case EINVAL:
-            scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
-            break;
-        default:
-            scsi_check_condition(r, SENSE_CODE(IO_ERROR));
-            break;
-        }
-    }
-    bdrv_error_action(s->qdev.conf.bs, action, is_read, error);
-    if (action == BDRV_ACTION_STOP) {
-        scsi_req_retry(&r->req);
-    }
-    return action != BDRV_ACTION_IGNORE;
-}
-
-static void scsi_write_complete(void * opaque, int ret)
-{
-    SCSIDiskReq *r = (SCSIDiskReq *)opaque;
-    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
-    uint32_t n;
-
-    if (r->req.aiocb != NULL) {
-        r->req.aiocb = NULL;
-        bdrv_acct_done(s->qdev.conf.bs, &r->acct);
-    }
-    if (r->req.io_canceled) {
-        goto done;
-    }
-
-    if (ret < 0) {
-        if (scsi_handle_rw_error(r, -ret)) {
-            goto done;
-        }
-    }
-
-    n = r->qiov.size / 512;
-    r->sector += n;
-    r->sector_count -= n;
-    if (r->sector_count == 0) {
-        scsi_write_do_fua(r);
-        return;
-    } else {
-        scsi_init_iovec(r, SCSI_DMA_BUF_SIZE);
-        DPRINTF("Write complete tag=0x%x more=%zd\n", r->req.tag, r->qiov.size);
-        scsi_req_data(&r->req, r->qiov.size);
-    }
-
-done:
-    if (!r->req.io_canceled) {
-        scsi_req_unref(&r->req);
-    }
-}
-
-static void scsi_write_data(SCSIRequest *req)
-{
-    SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
-    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
-    uint32_t n;
-
-    /* No data transfer may already be in progress */
-    assert(r->req.aiocb == NULL);
-
-    /* The request is used as the AIO opaque value, so add a ref.  */
-    scsi_req_ref(&r->req);
-    if (r->req.cmd.mode != SCSI_XFER_TO_DEV) {
-        DPRINTF("Data transfer direction invalid\n");
-        scsi_write_complete(r, -EINVAL);
-        return;
-    }
-
-    if (!r->req.sg && !r->qiov.size) {
-        /* Called for the first time.  Ask the driver to send us more data.  */
-        r->started = true;
-        scsi_write_complete(r, 0);
-        return;
-    }
-    if (s->tray_open) {
-        scsi_write_complete(r, -ENOMEDIUM);
-        return;
-    }
-
-    if (r->req.cmd.buf[0] == VERIFY_10 || r->req.cmd.buf[0] == VERIFY_12 ||
-        r->req.cmd.buf[0] == VERIFY_16) {
-        if (r->req.sg) {
-            scsi_dma_complete(r, 0);
-        } else {
-            scsi_write_complete(r, 0);
-        }
-        return;
-    }
-
-    if (r->req.sg) {
-        dma_acct_start(s->qdev.conf.bs, &r->acct, r->req.sg, BDRV_ACCT_WRITE);
-        r->req.resid -= r->req.sg->size;
-        r->req.aiocb = dma_bdrv_write(s->qdev.conf.bs, r->req.sg, r->sector,
-                                      scsi_dma_complete, r);
-    } else {
-        n = r->qiov.size / 512;
-        bdrv_acct_start(s->qdev.conf.bs, &r->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_WRITE);
-        r->req.aiocb = bdrv_aio_writev(s->qdev.conf.bs, r->sector, &r->qiov, n,
-                                       scsi_write_complete, r);
-    }
-}
-
-/* Return a pointer to the data buffer.  */
-static uint8_t *scsi_get_buf(SCSIRequest *req)
-{
-    SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
-
-    return (uint8_t *)r->iov.iov_base;
-}
-
-static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
-{
-    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
-    int buflen = 0;
-    int start;
-
-    if (req->cmd.buf[1] & 0x1) {
-        /* Vital product data */
-        uint8_t page_code = req->cmd.buf[2];
-
-        outbuf[buflen++] = s->qdev.type & 0x1f;
-        outbuf[buflen++] = page_code ; // this page
-        outbuf[buflen++] = 0x00;
-        outbuf[buflen++] = 0x00;
-        start = buflen;
-
-        switch (page_code) {
-        case 0x00: /* Supported page codes, mandatory */
-        {
-            DPRINTF("Inquiry EVPD[Supported pages] "
-                    "buffer size %zd\n", req->cmd.xfer);
-            outbuf[buflen++] = 0x00; // list of supported pages (this page)
-            if (s->serial) {
-                outbuf[buflen++] = 0x80; // unit serial number
-            }
-            outbuf[buflen++] = 0x83; // device identification
-            if (s->qdev.type == TYPE_DISK) {
-                outbuf[buflen++] = 0xb0; // block limits
-                outbuf[buflen++] = 0xb2; // thin provisioning
-            }
-            break;
-        }
-        case 0x80: /* Device serial number, optional */
-        {
-            int l;
-
-            if (!s->serial) {
-                DPRINTF("Inquiry (EVPD[Serial number] not supported\n");
-                return -1;
-            }
-
-            l = strlen(s->serial);
-            if (l > 20) {
-                l = 20;
-            }
-
-            DPRINTF("Inquiry EVPD[Serial number] "
-                    "buffer size %zd\n", req->cmd.xfer);
-            memcpy(outbuf+buflen, s->serial, l);
-            buflen += l;
-            break;
-        }
-
-        case 0x83: /* Device identification page, mandatory */
-        {
-            const char *str = s->serial ?: bdrv_get_device_name(s->qdev.conf.bs);
-            int max_len = s->serial ? 20 : 255 - 8;
-            int id_len = strlen(str);
-
-            if (id_len > max_len) {
-                id_len = max_len;
-            }
-            DPRINTF("Inquiry EVPD[Device identification] "
-                    "buffer size %zd\n", req->cmd.xfer);
-
-            outbuf[buflen++] = 0x2; // ASCII
-            outbuf[buflen++] = 0;   // not officially assigned
-            outbuf[buflen++] = 0;   // reserved
-            outbuf[buflen++] = id_len; // length of data following
-            memcpy(outbuf+buflen, str, id_len);
-            buflen += id_len;
-
-            if (s->wwn) {
-                outbuf[buflen++] = 0x1; // Binary
-                outbuf[buflen++] = 0x3; // NAA
-                outbuf[buflen++] = 0;   // reserved
-                outbuf[buflen++] = 8;
-                stq_be_p(&outbuf[buflen], s->wwn);
-                buflen += 8;
-            }
-            break;
-        }
-        case 0xb0: /* block limits */
-        {
-            unsigned int unmap_sectors =
-                    s->qdev.conf.discard_granularity / s->qdev.blocksize;
-            unsigned int min_io_size =
-                    s->qdev.conf.min_io_size / s->qdev.blocksize;
-            unsigned int opt_io_size =
-                    s->qdev.conf.opt_io_size / s->qdev.blocksize;
-
-            if (s->qdev.type == TYPE_ROM) {
-                DPRINTF("Inquiry (EVPD[%02X] not supported for CDROM\n",
-                        page_code);
-                return -1;
-            }
-            /* required VPD size with unmap support */
-            buflen = 0x40;
-            memset(outbuf + 4, 0, buflen - 4);
-
-            /* optimal transfer length granularity */
-            outbuf[6] = (min_io_size >> 8) & 0xff;
-            outbuf[7] = min_io_size & 0xff;
-
-            /* optimal transfer length */
-            outbuf[12] = (opt_io_size >> 24) & 0xff;
-            outbuf[13] = (opt_io_size >> 16) & 0xff;
-            outbuf[14] = (opt_io_size >> 8) & 0xff;
-            outbuf[15] = opt_io_size & 0xff;
-
-            /* optimal unmap granularity */
-            outbuf[28] = (unmap_sectors >> 24) & 0xff;
-            outbuf[29] = (unmap_sectors >> 16) & 0xff;
-            outbuf[30] = (unmap_sectors >> 8) & 0xff;
-            outbuf[31] = unmap_sectors & 0xff;
-            break;
-        }
-        case 0xb2: /* thin provisioning */
-        {
-            buflen = 8;
-            outbuf[4] = 0;
-            outbuf[5] = 0xe0; /* unmap & write_same 10/16 all supported */
-            outbuf[6] = s->qdev.conf.discard_granularity ? 2 : 1;
-            outbuf[7] = 0;
-            break;
-        }
-        default:
-            return -1;
-        }
-        /* done with EVPD */
-        assert(buflen - start <= 255);
-        outbuf[start - 1] = buflen - start;
-        return buflen;
-    }
-
-    /* Standard INQUIRY data */
-    if (req->cmd.buf[2] != 0) {
-        return -1;
-    }
-
-    /* PAGE CODE == 0 */
-    buflen = req->cmd.xfer;
-    if (buflen > SCSI_MAX_INQUIRY_LEN) {
-        buflen = SCSI_MAX_INQUIRY_LEN;
-    }
-
-    outbuf[0] = s->qdev.type & 0x1f;
-    outbuf[1] = (s->features & (1 << SCSI_DISK_F_REMOVABLE)) ? 0x80 : 0;
-
-    strpadcpy((char *) &outbuf[16], 16, s->product, ' ');
-    strpadcpy((char *) &outbuf[8], 8, s->vendor, ' ');
-
-    memset(&outbuf[32], 0, 4);
-    memcpy(&outbuf[32], s->version, MIN(4, strlen(s->version)));
-    /*
-     * We claim conformance to SPC-3, which is required for guests
-     * to ask for modern features like READ CAPACITY(16) or the
-     * block characteristics VPD page by default.  Not all of SPC-3
-     * is actually implemented, but we're good enough.
-     */
-    outbuf[2] = 5;
-    outbuf[3] = 2 | 0x10; /* Format 2, HiSup */
-
-    if (buflen > 36) {
-        outbuf[4] = buflen - 5; /* Additional Length = (Len - 1) - 4 */
-    } else {
-        /* If the allocation length of CDB is too small,
-               the additional length is not adjusted */
-        outbuf[4] = 36 - 5;
-    }
-
-    /* Sync data transfer and TCQ.  */
-    outbuf[7] = 0x10 | (req->bus->info->tcq ? 0x02 : 0);
-    return buflen;
-}
-
-static inline bool media_is_dvd(SCSIDiskState *s)
-{
-    uint64_t nb_sectors;
-    if (s->qdev.type != TYPE_ROM) {
-        return false;
-    }
-    if (!bdrv_is_inserted(s->qdev.conf.bs)) {
-        return false;
-    }
-    bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors);
-    return nb_sectors > CD_MAX_SECTORS;
-}
-
-static inline bool media_is_cd(SCSIDiskState *s)
-{
-    uint64_t nb_sectors;
-    if (s->qdev.type != TYPE_ROM) {
-        return false;
-    }
-    if (!bdrv_is_inserted(s->qdev.conf.bs)) {
-        return false;
-    }
-    bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors);
-    return nb_sectors <= CD_MAX_SECTORS;
-}
-
-static int scsi_read_disc_information(SCSIDiskState *s, SCSIDiskReq *r,
-                                      uint8_t *outbuf)
-{
-    uint8_t type = r->req.cmd.buf[1] & 7;
-
-    if (s->qdev.type != TYPE_ROM) {
-        return -1;
-    }
-
-    /* Types 1/2 are only defined for Blu-Ray.  */
-    if (type != 0) {
-        scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
-        return -1;
-    }
-
-    memset(outbuf, 0, 34);
-    outbuf[1] = 32;
-    outbuf[2] = 0xe; /* last session complete, disc finalized */
-    outbuf[3] = 1;   /* first track on disc */
-    outbuf[4] = 1;   /* # of sessions */
-    outbuf[5] = 1;   /* first track of last session */
-    outbuf[6] = 1;   /* last track of last session */
-    outbuf[7] = 0x20; /* unrestricted use */
-    outbuf[8] = 0x00; /* CD-ROM or DVD-ROM */
-    /* 9-10-11: most significant byte corresponding bytes 4-5-6 */
-    /* 12-23: not meaningful for CD-ROM or DVD-ROM */
-    /* 24-31: disc bar code */
-    /* 32: disc application code */
-    /* 33: number of OPC tables */
-
-    return 34;
-}
-
-static int scsi_read_dvd_structure(SCSIDiskState *s, SCSIDiskReq *r,
-                                   uint8_t *outbuf)
-{
-    static const int rds_caps_size[5] = {
-        [0] = 2048 + 4,
-        [1] = 4 + 4,
-        [3] = 188 + 4,
-        [4] = 2048 + 4,
-    };
-
-    uint8_t media = r->req.cmd.buf[1];
-    uint8_t layer = r->req.cmd.buf[6];
-    uint8_t format = r->req.cmd.buf[7];
-    int size = -1;
-
-    if (s->qdev.type != TYPE_ROM) {
-        return -1;
-    }
-    if (media != 0) {
-        scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
-        return -1;
-    }
-
-    if (format != 0xff) {
-        if (s->tray_open || !bdrv_is_inserted(s->qdev.conf.bs)) {
-            scsi_check_condition(r, SENSE_CODE(NO_MEDIUM));
-            return -1;
-        }
-        if (media_is_cd(s)) {
-            scsi_check_condition(r, SENSE_CODE(INCOMPATIBLE_FORMAT));
-            return -1;
-        }
-        if (format >= ARRAY_SIZE(rds_caps_size)) {
-            return -1;
-        }
-        size = rds_caps_size[format];
-        memset(outbuf, 0, size);
-    }
-
-    switch (format) {
-    case 0x00: {
-        /* Physical format information */
-        uint64_t nb_sectors;
-        if (layer != 0) {
-            goto fail;
-        }
-        bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors);
-
-        outbuf[4] = 1;   /* DVD-ROM, part version 1 */
-        outbuf[5] = 0xf; /* 120mm disc, minimum rate unspecified */
-        outbuf[6] = 1;   /* one layer, read-only (per MMC-2 spec) */
-        outbuf[7] = 0;   /* default densities */
-
-        stl_be_p(&outbuf[12], (nb_sectors >> 2) - 1); /* end sector */
-        stl_be_p(&outbuf[16], (nb_sectors >> 2) - 1); /* l0 end sector */
-        break;
-    }
-
-    case 0x01: /* DVD copyright information, all zeros */
-        break;
-
-    case 0x03: /* BCA information - invalid field for no BCA info */
-        return -1;
-
-    case 0x04: /* DVD disc manufacturing information, all zeros */
-        break;
-
-    case 0xff: { /* List capabilities */
-        int i;
-        size = 4;
-        for (i = 0; i < ARRAY_SIZE(rds_caps_size); i++) {
-            if (!rds_caps_size[i]) {
-                continue;
-            }
-            outbuf[size] = i;
-            outbuf[size + 1] = 0x40; /* Not writable, readable */
-            stw_be_p(&outbuf[size + 2], rds_caps_size[i]);
-            size += 4;
-        }
-        break;
-     }
-
-    default:
-        return -1;
-    }
-
-    /* Size of buffer, not including 2 byte size field */
-    stw_be_p(outbuf, size - 2);
-    return size;
-
-fail:
-    return -1;
-}
-
-static int scsi_event_status_media(SCSIDiskState *s, uint8_t *outbuf)
-{
-    uint8_t event_code, media_status;
-
-    media_status = 0;
-    if (s->tray_open) {
-        media_status = MS_TRAY_OPEN;
-    } else if (bdrv_is_inserted(s->qdev.conf.bs)) {
-        media_status = MS_MEDIA_PRESENT;
-    }
-
-    /* Event notification descriptor */
-    event_code = MEC_NO_CHANGE;
-    if (media_status != MS_TRAY_OPEN) {
-        if (s->media_event) {
-            event_code = MEC_NEW_MEDIA;
-            s->media_event = false;
-        } else if (s->eject_request) {
-            event_code = MEC_EJECT_REQUESTED;
-            s->eject_request = false;
-        }
-    }
-
-    outbuf[0] = event_code;
-    outbuf[1] = media_status;
-
-    /* These fields are reserved, just clear them. */
-    outbuf[2] = 0;
-    outbuf[3] = 0;
-    return 4;
-}
-
-static int scsi_get_event_status_notification(SCSIDiskState *s, SCSIDiskReq *r,
-                                              uint8_t *outbuf)
-{
-    int size;
-    uint8_t *buf = r->req.cmd.buf;
-    uint8_t notification_class_request = buf[4];
-    if (s->qdev.type != TYPE_ROM) {
-        return -1;
-    }
-    if ((buf[1] & 1) == 0) {
-        /* asynchronous */
-        return -1;
-    }
-
-    size = 4;
-    outbuf[0] = outbuf[1] = 0;
-    outbuf[3] = 1 << GESN_MEDIA; /* supported events */
-    if (notification_class_request & (1 << GESN_MEDIA)) {
-        outbuf[2] = GESN_MEDIA;
-        size += scsi_event_status_media(s, &outbuf[size]);
-    } else {
-        outbuf[2] = 0x80;
-    }
-    stw_be_p(outbuf, size - 4);
-    return size;
-}
-
-static int scsi_get_configuration(SCSIDiskState *s, uint8_t *outbuf)
-{
-    int current;
-
-    if (s->qdev.type != TYPE_ROM) {
-        return -1;
-    }
-    current = media_is_dvd(s) ? MMC_PROFILE_DVD_ROM : MMC_PROFILE_CD_ROM;
-    memset(outbuf, 0, 40);
-    stl_be_p(&outbuf[0], 36); /* Bytes after the data length field */
-    stw_be_p(&outbuf[6], current);
-    /* outbuf[8] - outbuf[19]: Feature 0 - Profile list */
-    outbuf[10] = 0x03; /* persistent, current */
-    outbuf[11] = 8; /* two profiles */
-    stw_be_p(&outbuf[12], MMC_PROFILE_DVD_ROM);
-    outbuf[14] = (current == MMC_PROFILE_DVD_ROM);
-    stw_be_p(&outbuf[16], MMC_PROFILE_CD_ROM);
-    outbuf[18] = (current == MMC_PROFILE_CD_ROM);
-    /* outbuf[20] - outbuf[31]: Feature 1 - Core feature */
-    stw_be_p(&outbuf[20], 1);
-    outbuf[22] = 0x08 | 0x03; /* version 2, persistent, current */
-    outbuf[23] = 8;
-    stl_be_p(&outbuf[24], 1); /* SCSI */
-    outbuf[28] = 1; /* DBE = 1, mandatory */
-    /* outbuf[32] - outbuf[39]: Feature 3 - Removable media feature */
-    stw_be_p(&outbuf[32], 3);
-    outbuf[34] = 0x08 | 0x03; /* version 2, persistent, current */
-    outbuf[35] = 4;
-    outbuf[36] = 0x39; /* tray, load=1, eject=1, unlocked at powerup, lock=1 */
-    /* TODO: Random readable, CD read, DVD read, drive serial number,
-       power management */
-    return 40;
-}
-
-static int scsi_emulate_mechanism_status(SCSIDiskState *s, uint8_t *outbuf)
-{
-    if (s->qdev.type != TYPE_ROM) {
-        return -1;
-    }
-    memset(outbuf, 0, 8);
-    outbuf[5] = 1; /* CD-ROM */
-    return 8;
-}
-
-static int mode_sense_page(SCSIDiskState *s, int page, uint8_t **p_outbuf,
-                           int page_control)
-{
-    static const int mode_sense_valid[0x3f] = {
-        [MODE_PAGE_HD_GEOMETRY]            = (1 << TYPE_DISK),
-        [MODE_PAGE_FLEXIBLE_DISK_GEOMETRY] = (1 << TYPE_DISK),
-        [MODE_PAGE_CACHING]                = (1 << TYPE_DISK) | (1 << TYPE_ROM),
-        [MODE_PAGE_R_W_ERROR]              = (1 << TYPE_DISK) | (1 << TYPE_ROM),
-        [MODE_PAGE_AUDIO_CTL]              = (1 << TYPE_ROM),
-        [MODE_PAGE_CAPABILITIES]           = (1 << TYPE_ROM),
-    };
-
-    uint8_t *p = *p_outbuf + 2;
-    int length;
-
-    if ((mode_sense_valid[page] & (1 << s->qdev.type)) == 0) {
-        return -1;
-    }
-
-    /*
-     * If Changeable Values are requested, a mask denoting those mode parameters
-     * that are changeable shall be returned. As we currently don't support
-     * parameter changes via MODE_SELECT all bits are returned set to zero.
-     * The buffer was already menset to zero by the caller of this function.
-     *
-     * The offsets here are off by two compared to the descriptions in the
-     * SCSI specs, because those include a 2-byte header.  This is unfortunate,
-     * but it is done so that offsets are consistent within our implementation
-     * of MODE SENSE and MODE SELECT.  MODE SELECT has to deal with both
-     * 2-byte and 4-byte headers.
-     */
-    switch (page) {
-    case MODE_PAGE_HD_GEOMETRY:
-        length = 0x16;
-        if (page_control == 1) { /* Changeable Values */
-            break;
-        }
-        /* if a geometry hint is available, use it */
-        p[0] = (s->qdev.conf.cyls >> 16) & 0xff;
-        p[1] = (s->qdev.conf.cyls >> 8) & 0xff;
-        p[2] = s->qdev.conf.cyls & 0xff;
-        p[3] = s->qdev.conf.heads & 0xff;
-        /* Write precomp start cylinder, disabled */
-        p[4] = (s->qdev.conf.cyls >> 16) & 0xff;
-        p[5] = (s->qdev.conf.cyls >> 8) & 0xff;
-        p[6] = s->qdev.conf.cyls & 0xff;
-        /* Reduced current start cylinder, disabled */
-        p[7] = (s->qdev.conf.cyls >> 16) & 0xff;
-        p[8] = (s->qdev.conf.cyls >> 8) & 0xff;
-        p[9] = s->qdev.conf.cyls & 0xff;
-        /* Device step rate [ns], 200ns */
-        p[10] = 0;
-        p[11] = 200;
-        /* Landing zone cylinder */
-        p[12] = 0xff;
-        p[13] =  0xff;
-        p[14] = 0xff;
-        /* Medium rotation rate [rpm], 5400 rpm */
-        p[18] = (5400 >> 8) & 0xff;
-        p[19] = 5400 & 0xff;
-        break;
-
-    case MODE_PAGE_FLEXIBLE_DISK_GEOMETRY:
-        length = 0x1e;
-        if (page_control == 1) { /* Changeable Values */
-            break;
-        }
-        /* Transfer rate [kbit/s], 5Mbit/s */
-        p[0] = 5000 >> 8;
-        p[1] = 5000 & 0xff;
-        /* if a geometry hint is available, use it */
-        p[2] = s->qdev.conf.heads & 0xff;
-        p[3] = s->qdev.conf.secs & 0xff;
-        p[4] = s->qdev.blocksize >> 8;
-        p[6] = (s->qdev.conf.cyls >> 8) & 0xff;
-        p[7] = s->qdev.conf.cyls & 0xff;
-        /* Write precomp start cylinder, disabled */
-        p[8] = (s->qdev.conf.cyls >> 8) & 0xff;
-        p[9] = s->qdev.conf.cyls & 0xff;
-        /* Reduced current start cylinder, disabled */
-        p[10] = (s->qdev.conf.cyls >> 8) & 0xff;
-        p[11] = s->qdev.conf.cyls & 0xff;
-        /* Device step rate [100us], 100us */
-        p[12] = 0;
-        p[13] = 1;
-        /* Device step pulse width [us], 1us */
-        p[14] = 1;
-        /* Device head settle delay [100us], 100us */
-        p[15] = 0;
-        p[16] = 1;
-        /* Motor on delay [0.1s], 0.1s */
-        p[17] = 1;
-        /* Motor off delay [0.1s], 0.1s */
-        p[18] = 1;
-        /* Medium rotation rate [rpm], 5400 rpm */
-        p[26] = (5400 >> 8) & 0xff;
-        p[27] = 5400 & 0xff;
-        break;
-
-    case MODE_PAGE_CACHING:
-        length = 0x12;
-        if (page_control == 1 || /* Changeable Values */
-            bdrv_enable_write_cache(s->qdev.conf.bs)) {
-            p[0] = 4; /* WCE */
-        }
-        break;
-
-    case MODE_PAGE_R_W_ERROR:
-        length = 10;
-        if (page_control == 1) { /* Changeable Values */
-            break;
-        }
-        p[0] = 0x80; /* Automatic Write Reallocation Enabled */
-        if (s->qdev.type == TYPE_ROM) {
-            p[1] = 0x20; /* Read Retry Count */
-        }
-        break;
-
-    case MODE_PAGE_AUDIO_CTL:
-        length = 14;
-        break;
-
-    case MODE_PAGE_CAPABILITIES:
-        length = 0x14;
-        if (page_control == 1) { /* Changeable Values */
-            break;
-        }
-
-        p[0] = 0x3b; /* CD-R & CD-RW read */
-        p[1] = 0; /* Writing not supported */
-        p[2] = 0x7f; /* Audio, composite, digital out,
-                        mode 2 form 1&2, multi session */
-        p[3] = 0xff; /* CD DA, DA accurate, RW supported,
-                        RW corrected, C2 errors, ISRC,
-                        UPC, Bar code */
-        p[4] = 0x2d | (s->tray_locked ? 2 : 0);
-        /* Locking supported, jumper present, eject, tray */
-        p[5] = 0; /* no volume & mute control, no
-                     changer */
-        p[6] = (50 * 176) >> 8; /* 50x read speed */
-        p[7] = (50 * 176) & 0xff;
-        p[8] = 2 >> 8; /* Two volume levels */
-        p[9] = 2 & 0xff;
-        p[10] = 2048 >> 8; /* 2M buffer */
-        p[11] = 2048 & 0xff;
-        p[12] = (16 * 176) >> 8; /* 16x read speed current */
-        p[13] = (16 * 176) & 0xff;
-        p[16] = (16 * 176) >> 8; /* 16x write speed */
-        p[17] = (16 * 176) & 0xff;
-        p[18] = (16 * 176) >> 8; /* 16x write speed current */
-        p[19] = (16 * 176) & 0xff;
-        break;
-
-    default:
-        return -1;
-    }
-
-    assert(length < 256);
-    (*p_outbuf)[0] = page;
-    (*p_outbuf)[1] = length;
-    *p_outbuf += length + 2;
-    return length + 2;
-}
-
-static int scsi_disk_emulate_mode_sense(SCSIDiskReq *r, uint8_t *outbuf)
-{
-    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
-    uint64_t nb_sectors;
-    bool dbd;
-    int page, buflen, ret, page_control;
-    uint8_t *p;
-    uint8_t dev_specific_param;
-
-    dbd = (r->req.cmd.buf[1] & 0x8) != 0;
-    page = r->req.cmd.buf[2] & 0x3f;
-    page_control = (r->req.cmd.buf[2] & 0xc0) >> 6;
-    DPRINTF("Mode Sense(%d) (page %d, xfer %zd, page_control %d)\n",
-        (r->req.cmd.buf[0] == MODE_SENSE) ? 6 : 10, page, r->req.cmd.xfer, page_control);
-    memset(outbuf, 0, r->req.cmd.xfer);
-    p = outbuf;
-
-    if (s->qdev.type == TYPE_DISK) {
-        dev_specific_param = s->features & (1 << SCSI_DISK_F_DPOFUA) ? 0x10 : 0;
-        if (bdrv_is_read_only(s->qdev.conf.bs)) {
-            dev_specific_param |= 0x80; /* Readonly.  */
-        }
-    } else {
-        /* MMC prescribes that CD/DVD drives have no block descriptors,
-         * and defines no device-specific parameter.  */
-        dev_specific_param = 0x00;
-        dbd = true;
-    }
-
-    if (r->req.cmd.buf[0] == MODE_SENSE) {
-        p[1] = 0; /* Default media type.  */
-        p[2] = dev_specific_param;
-        p[3] = 0; /* Block descriptor length.  */
-        p += 4;
-    } else { /* MODE_SENSE_10 */
-        p[2] = 0; /* Default media type.  */
-        p[3] = dev_specific_param;
-        p[6] = p[7] = 0; /* Block descriptor length.  */
-        p += 8;
-    }
-
-    bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors);
-    if (!dbd && nb_sectors) {
-        if (r->req.cmd.buf[0] == MODE_SENSE) {
-            outbuf[3] = 8; /* Block descriptor length  */
-        } else { /* MODE_SENSE_10 */
-            outbuf[7] = 8; /* Block descriptor length  */
-        }
-        nb_sectors /= (s->qdev.blocksize / 512);
-        if (nb_sectors > 0xffffff) {
-            nb_sectors = 0;
-        }
-        p[0] = 0; /* media density code */
-        p[1] = (nb_sectors >> 16) & 0xff;
-        p[2] = (nb_sectors >> 8) & 0xff;
-        p[3] = nb_sectors & 0xff;
-        p[4] = 0; /* reserved */
-        p[5] = 0; /* bytes 5-7 are the sector size in bytes */
-        p[6] = s->qdev.blocksize >> 8;
-        p[7] = 0;
-        p += 8;
-    }
-
-    if (page_control == 3) {
-        /* Saved Values */
-        scsi_check_condition(r, SENSE_CODE(SAVING_PARAMS_NOT_SUPPORTED));
-        return -1;
-    }
-
-    if (page == 0x3f) {
-        for (page = 0; page <= 0x3e; page++) {
-            mode_sense_page(s, page, &p, page_control);
-        }
-    } else {
-        ret = mode_sense_page(s, page, &p, page_control);
-        if (ret == -1) {
-            return -1;
-        }
-    }
-
-    buflen = p - outbuf;
-    /*
-     * The mode data length field specifies the length in bytes of the
-     * following data that is available to be transferred. The mode data
-     * length does not include itself.
-     */
-    if (r->req.cmd.buf[0] == MODE_SENSE) {
-        outbuf[0] = buflen - 1;
-    } else { /* MODE_SENSE_10 */
-        outbuf[0] = ((buflen - 2) >> 8) & 0xff;
-        outbuf[1] = (buflen - 2) & 0xff;
-    }
-    return buflen;
-}
-
-static int scsi_disk_emulate_read_toc(SCSIRequest *req, uint8_t *outbuf)
-{
-    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
-    int start_track, format, msf, toclen;
-    uint64_t nb_sectors;
-
-    msf = req->cmd.buf[1] & 2;
-    format = req->cmd.buf[2] & 0xf;
-    start_track = req->cmd.buf[6];
-    bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors);
-    DPRINTF("Read TOC (track %d format %d msf %d)\n", start_track, format, msf >> 1);
-    nb_sectors /= s->qdev.blocksize / 512;
-    switch (format) {
-    case 0:
-        toclen = cdrom_read_toc(nb_sectors, outbuf, msf, start_track);
-        break;
-    case 1:
-        /* multi session : only a single session defined */
-        toclen = 12;
-        memset(outbuf, 0, 12);
-        outbuf[1] = 0x0a;
-        outbuf[2] = 0x01;
-        outbuf[3] = 0x01;
-        break;
-    case 2:
-        toclen = cdrom_read_toc_raw(nb_sectors, outbuf, msf, start_track);
-        break;
-    default:
-        return -1;
-    }
-    return toclen;
-}
-
-static int scsi_disk_emulate_start_stop(SCSIDiskReq *r)
-{
-    SCSIRequest *req = &r->req;
-    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
-    bool start = req->cmd.buf[4] & 1;
-    bool loej = req->cmd.buf[4] & 2; /* load on start, eject on !start */
-    int pwrcnd = req->cmd.buf[4] & 0xf0;
-
-    if (pwrcnd) {
-        /* eject/load only happens for power condition == 0 */
-        return 0;
-    }
-
-    if ((s->features & (1 << SCSI_DISK_F_REMOVABLE)) && loej) {
-        if (!start && !s->tray_open && s->tray_locked) {
-            scsi_check_condition(r,
-                                 bdrv_is_inserted(s->qdev.conf.bs)
-                                 ? SENSE_CODE(ILLEGAL_REQ_REMOVAL_PREVENTED)
-                                 : SENSE_CODE(NOT_READY_REMOVAL_PREVENTED));
-            return -1;
-        }
-
-        if (s->tray_open != !start) {
-            bdrv_eject(s->qdev.conf.bs, !start);
-            s->tray_open = !start;
-        }
-    }
-    return 0;
-}
-
-static void scsi_disk_emulate_read_data(SCSIRequest *req)
-{
-    SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
-    int buflen = r->iov.iov_len;
-
-    if (buflen) {
-        DPRINTF("Read buf_len=%d\n", buflen);
-        r->iov.iov_len = 0;
-        r->started = true;
-        scsi_req_data(&r->req, buflen);
-        return;
-    }
-
-    /* This also clears the sense buffer for REQUEST SENSE.  */
-    scsi_req_complete(&r->req, GOOD);
-}
-
-static int scsi_disk_check_mode_select(SCSIDiskState *s, int page,
-                                       uint8_t *inbuf, int inlen)
-{
-    uint8_t mode_current[SCSI_MAX_MODE_LEN];
-    uint8_t mode_changeable[SCSI_MAX_MODE_LEN];
-    uint8_t *p;
-    int len, expected_len, changeable_len, i;
-
-    /* The input buffer does not include the page header, so it is
-     * off by 2 bytes.
-     */
-    expected_len = inlen + 2;
-    if (expected_len > SCSI_MAX_MODE_LEN) {
-        return -1;
-    }
-
-    p = mode_current;
-    memset(mode_current, 0, inlen + 2);
-    len = mode_sense_page(s, page, &p, 0);
-    if (len < 0 || len != expected_len) {
-        return -1;
-    }
-
-    p = mode_changeable;
-    memset(mode_changeable, 0, inlen + 2);
-    changeable_len = mode_sense_page(s, page, &p, 1);
-    assert(changeable_len == len);
-
-    /* Check that unchangeable bits are the same as what MODE SENSE
-     * would return.
-     */
-    for (i = 2; i < len; i++) {
-        if (((mode_current[i] ^ inbuf[i - 2]) & ~mode_changeable[i]) != 0) {
-            return -1;
-        }
-    }
-    return 0;
-}
-
-static void scsi_disk_apply_mode_select(SCSIDiskState *s, int page, uint8_t *p)
-{
-    switch (page) {
-    case MODE_PAGE_CACHING:
-        bdrv_set_enable_write_cache(s->qdev.conf.bs, (p[0] & 4) != 0);
-        break;
-
-    default:
-        break;
-    }
-}
-
-static int mode_select_pages(SCSIDiskReq *r, uint8_t *p, int len, bool change)
-{
-    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
-
-    while (len > 0) {
-        int page, subpage, page_len;
-
-        /* Parse both possible formats for the mode page headers.  */
-        page = p[0] & 0x3f;
-        if (p[0] & 0x40) {
-            if (len < 4) {
-                goto invalid_param_len;
-            }
-            subpage = p[1];
-            page_len = lduw_be_p(&p[2]);
-            p += 4;
-            len -= 4;
-        } else {
-            if (len < 2) {
-                goto invalid_param_len;
-            }
-            subpage = 0;
-            page_len = p[1];
-            p += 2;
-            len -= 2;
-        }
-
-        if (subpage) {
-            goto invalid_param;
-        }
-        if (page_len > len) {
-            goto invalid_param_len;
-        }
-
-        if (!change) {
-            if (scsi_disk_check_mode_select(s, page, p, page_len) < 0) {
-                goto invalid_param;
-            }
-        } else {
-            scsi_disk_apply_mode_select(s, page, p);
-        }
-
-        p += page_len;
-        len -= page_len;
-    }
-    return 0;
-
-invalid_param:
-    scsi_check_condition(r, SENSE_CODE(INVALID_PARAM));
-    return -1;
-
-invalid_param_len:
-    scsi_check_condition(r, SENSE_CODE(INVALID_PARAM_LEN));
-    return -1;
-}
-
-static void scsi_disk_emulate_mode_select(SCSIDiskReq *r, uint8_t *inbuf)
-{
-    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
-    uint8_t *p = inbuf;
-    int cmd = r->req.cmd.buf[0];
-    int len = r->req.cmd.xfer;
-    int hdr_len = (cmd == MODE_SELECT ? 4 : 8);
-    int bd_len;
-    int pass;
-
-    /* We only support PF=1, SP=0.  */
-    if ((r->req.cmd.buf[1] & 0x11) != 0x10) {
-        goto invalid_field;
-    }
-
-    if (len < hdr_len) {
-        goto invalid_param_len;
-    }
-
-    bd_len = (cmd == MODE_SELECT ? p[3] : lduw_be_p(&p[6]));
-    len -= hdr_len;
-    p += hdr_len;
-    if (len < bd_len) {
-        goto invalid_param_len;
-    }
-    if (bd_len != 0 && bd_len != 8) {
-        goto invalid_param;
-    }
-
-    len -= bd_len;
-    p += bd_len;
-
-    /* Ensure no change is made if there is an error!  */
-    for (pass = 0; pass < 2; pass++) {
-        if (mode_select_pages(r, p, len, pass == 1) < 0) {
-            assert(pass == 0);
-            return;
-        }
-    }
-    if (!bdrv_enable_write_cache(s->qdev.conf.bs)) {
-        /* The request is used as the AIO opaque value, so add a ref.  */
-        scsi_req_ref(&r->req);
-        bdrv_acct_start(s->qdev.conf.bs, &r->acct, 0, BDRV_ACCT_FLUSH);
-        r->req.aiocb = bdrv_aio_flush(s->qdev.conf.bs, scsi_aio_complete, r);
-        return;
-    }
-
-    scsi_req_complete(&r->req, GOOD);
-    return;
-
-invalid_param:
-    scsi_check_condition(r, SENSE_CODE(INVALID_PARAM));
-    return;
-
-invalid_param_len:
-    scsi_check_condition(r, SENSE_CODE(INVALID_PARAM_LEN));
-    return;
-
-invalid_field:
-    scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
-}
-
-static inline bool check_lba_range(SCSIDiskState *s,
-                                   uint64_t sector_num, uint32_t nb_sectors)
-{
-    /*
-     * The first line tests that no overflow happens when computing the last
-     * sector.  The second line tests that the last accessed sector is in
-     * range.
-     *
-     * Careful, the computations should not underflow for nb_sectors == 0,
-     * and a 0-block read to the first LBA beyond the end of device is
-     * valid.
-     */
-    return (sector_num <= sector_num + nb_sectors &&
-            sector_num + nb_sectors <= s->qdev.max_lba + 1);
-}
-
-typedef struct UnmapCBData {
-    SCSIDiskReq *r;
-    uint8_t *inbuf;
-    int count;
-} UnmapCBData;
-
-static void scsi_unmap_complete(void *opaque, int ret)
-{
-    UnmapCBData *data = opaque;
-    SCSIDiskReq *r = data->r;
-    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
-    uint64_t sector_num;
-    uint32_t nb_sectors;
-
-    r->req.aiocb = NULL;
-    if (r->req.io_canceled) {
-        goto done;
-    }
-
-    if (ret < 0) {
-        if (scsi_handle_rw_error(r, -ret)) {
-            goto done;
-        }
-    }
-
-    if (data->count > 0) {
-        sector_num = ldq_be_p(&data->inbuf[0]);
-        nb_sectors = ldl_be_p(&data->inbuf[8]) & 0xffffffffULL;
-        if (!check_lba_range(s, sector_num, nb_sectors)) {
-            scsi_check_condition(r, SENSE_CODE(LBA_OUT_OF_RANGE));
-            goto done;
-        }
-
-        r->req.aiocb = bdrv_aio_discard(s->qdev.conf.bs,
-                                        sector_num * (s->qdev.blocksize / 512),
-                                        nb_sectors * (s->qdev.blocksize / 512),
-                                        scsi_unmap_complete, data);
-        data->count--;
-        data->inbuf += 16;
-        return;
-    }
-
-    scsi_req_complete(&r->req, GOOD);
-
-done:
-    if (!r->req.io_canceled) {
-        scsi_req_unref(&r->req);
-    }
-    g_free(data);
-}
-
-static void scsi_disk_emulate_unmap(SCSIDiskReq *r, uint8_t *inbuf)
-{
-    uint8_t *p = inbuf;
-    int len = r->req.cmd.xfer;
-    UnmapCBData *data;
-
-    if (len < 8) {
-        goto invalid_param_len;
-    }
-    if (len < lduw_be_p(&p[0]) + 2) {
-        goto invalid_param_len;
-    }
-    if (len < lduw_be_p(&p[2]) + 8) {
-        goto invalid_param_len;
-    }
-    if (lduw_be_p(&p[2]) & 15) {
-        goto invalid_param_len;
-    }
-
-    data = g_new0(UnmapCBData, 1);
-    data->r = r;
-    data->inbuf = &p[8];
-    data->count = lduw_be_p(&p[2]) >> 4;
-
-    /* The matching unref is in scsi_unmap_complete, before data is freed.  */
-    scsi_req_ref(&r->req);
-    scsi_unmap_complete(data, 0);
-    return;
-
-invalid_param_len:
-    scsi_check_condition(r, SENSE_CODE(INVALID_PARAM_LEN));
-}
-
-static void scsi_disk_emulate_write_data(SCSIRequest *req)
-{
-    SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
-
-    if (r->iov.iov_len) {
-        int buflen = r->iov.iov_len;
-        DPRINTF("Write buf_len=%d\n", buflen);
-        r->iov.iov_len = 0;
-        scsi_req_data(&r->req, buflen);
-        return;
-    }
-
-    switch (req->cmd.buf[0]) {
-    case MODE_SELECT:
-    case MODE_SELECT_10:
-        /* This also clears the sense buffer for REQUEST SENSE.  */
-        scsi_disk_emulate_mode_select(r, r->iov.iov_base);
-        break;
-
-    case UNMAP:
-        scsi_disk_emulate_unmap(r, r->iov.iov_base);
-        break;
-
-    default:
-        abort();
-    }
-}
-
-static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf)
-{
-    SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
-    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
-    uint64_t nb_sectors;
-    uint8_t *outbuf;
-    int buflen;
-
-    switch (req->cmd.buf[0]) {
-    case INQUIRY:
-    case MODE_SENSE:
-    case MODE_SENSE_10:
-    case RESERVE:
-    case RESERVE_10:
-    case RELEASE:
-    case RELEASE_10:
-    case START_STOP:
-    case ALLOW_MEDIUM_REMOVAL:
-    case GET_CONFIGURATION:
-    case GET_EVENT_STATUS_NOTIFICATION:
-    case MECHANISM_STATUS:
-    case REQUEST_SENSE:
-        break;
-
-    default:
-        if (s->tray_open || !bdrv_is_inserted(s->qdev.conf.bs)) {
-            scsi_check_condition(r, SENSE_CODE(NO_MEDIUM));
-            return 0;
-        }
-        break;
-    }
-
-    /*
-     * FIXME: we shouldn't return anything bigger than 4k, but the code
-     * requires the buffer to be as big as req->cmd.xfer in several
-     * places.  So, do not allow CDBs with a very large ALLOCATION
-     * LENGTH.  The real fix would be to modify scsi_read_data and
-     * dma_buf_read, so that they return data beyond the buflen
-     * as all zeros.
-     */
-    if (req->cmd.xfer > 65536) {
-        goto illegal_request;
-    }
-    r->buflen = MAX(4096, req->cmd.xfer);
-
-    if (!r->iov.iov_base) {
-        r->iov.iov_base = qemu_blockalign(s->qdev.conf.bs, r->buflen);
-    }
-
-    buflen = req->cmd.xfer;
-    outbuf = r->iov.iov_base;
-    memset(outbuf, 0, r->buflen);
-    switch (req->cmd.buf[0]) {
-    case TEST_UNIT_READY:
-        assert(!s->tray_open && bdrv_is_inserted(s->qdev.conf.bs));
-        break;
-    case INQUIRY:
-        buflen = scsi_disk_emulate_inquiry(req, outbuf);
-        if (buflen < 0) {
-            goto illegal_request;
-        }
-        break;
-    case MODE_SENSE:
-    case MODE_SENSE_10:
-        buflen = scsi_disk_emulate_mode_sense(r, outbuf);
-        if (buflen < 0) {
-            goto illegal_request;
-        }
-        break;
-    case READ_TOC:
-        buflen = scsi_disk_emulate_read_toc(req, outbuf);
-        if (buflen < 0) {
-            goto illegal_request;
-        }
-        break;
-    case RESERVE:
-        if (req->cmd.buf[1] & 1) {
-            goto illegal_request;
-        }
-        break;
-    case RESERVE_10:
-        if (req->cmd.buf[1] & 3) {
-            goto illegal_request;
-        }
-        break;
-    case RELEASE:
-        if (req->cmd.buf[1] & 1) {
-            goto illegal_request;
-        }
-        break;
-    case RELEASE_10:
-        if (req->cmd.buf[1] & 3) {
-            goto illegal_request;
-        }
-        break;
-    case START_STOP:
-        if (scsi_disk_emulate_start_stop(r) < 0) {
-            return 0;
-        }
-        break;
-    case ALLOW_MEDIUM_REMOVAL:
-        s->tray_locked = req->cmd.buf[4] & 1;
-        bdrv_lock_medium(s->qdev.conf.bs, req->cmd.buf[4] & 1);
-        break;
-    case READ_CAPACITY_10:
-        /* The normal LEN field for this command is zero.  */
-        memset(outbuf, 0, 8);
-        bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors);
-        if (!nb_sectors) {
-            scsi_check_condition(r, SENSE_CODE(LUN_NOT_READY));
-            return 0;
-        }
-        if ((req->cmd.buf[8] & 1) == 0 && req->cmd.lba) {
-            goto illegal_request;
-        }
-        nb_sectors /= s->qdev.blocksize / 512;
-        /* Returned value is the address of the last sector.  */
-        nb_sectors--;
-        /* Remember the new size for read/write sanity checking. */
-        s->qdev.max_lba = nb_sectors;
-        /* Clip to 2TB, instead of returning capacity modulo 2TB. */
-        if (nb_sectors > UINT32_MAX) {
-            nb_sectors = UINT32_MAX;
-        }
-        outbuf[0] = (nb_sectors >> 24) & 0xff;
-        outbuf[1] = (nb_sectors >> 16) & 0xff;
-        outbuf[2] = (nb_sectors >> 8) & 0xff;
-        outbuf[3] = nb_sectors & 0xff;
-        outbuf[4] = 0;
-        outbuf[5] = 0;
-        outbuf[6] = s->qdev.blocksize >> 8;
-        outbuf[7] = 0;
-        break;
-    case REQUEST_SENSE:
-        /* Just return "NO SENSE".  */
-        buflen = scsi_build_sense(NULL, 0, outbuf, r->buflen,
-                                  (req->cmd.buf[1] & 1) == 0);
-        if (buflen < 0) {
-            goto illegal_request;
-        }
-        break;
-    case MECHANISM_STATUS:
-        buflen = scsi_emulate_mechanism_status(s, outbuf);
-        if (buflen < 0) {
-            goto illegal_request;
-        }
-        break;
-    case GET_CONFIGURATION:
-        buflen = scsi_get_configuration(s, outbuf);
-        if (buflen < 0) {
-            goto illegal_request;
-        }
-        break;
-    case GET_EVENT_STATUS_NOTIFICATION:
-        buflen = scsi_get_event_status_notification(s, r, outbuf);
-        if (buflen < 0) {
-            goto illegal_request;
-        }
-        break;
-    case READ_DISC_INFORMATION:
-        buflen = scsi_read_disc_information(s, r, outbuf);
-        if (buflen < 0) {
-            goto illegal_request;
-        }
-        break;
-    case READ_DVD_STRUCTURE:
-        buflen = scsi_read_dvd_structure(s, r, outbuf);
-        if (buflen < 0) {
-            goto illegal_request;
-        }
-        break;
-    case SERVICE_ACTION_IN_16:
-        /* Service Action In subcommands. */
-        if ((req->cmd.buf[1] & 31) == SAI_READ_CAPACITY_16) {
-            DPRINTF("SAI READ CAPACITY(16)\n");
-            memset(outbuf, 0, req->cmd.xfer);
-            bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors);
-            if (!nb_sectors) {
-                scsi_check_condition(r, SENSE_CODE(LUN_NOT_READY));
-                return 0;
-            }
-            if ((req->cmd.buf[14] & 1) == 0 && req->cmd.lba) {
-                goto illegal_request;
-            }
-            nb_sectors /= s->qdev.blocksize / 512;
-            /* Returned value is the address of the last sector.  */
-            nb_sectors--;
-            /* Remember the new size for read/write sanity checking. */
-            s->qdev.max_lba = nb_sectors;
-            outbuf[0] = (nb_sectors >> 56) & 0xff;
-            outbuf[1] = (nb_sectors >> 48) & 0xff;
-            outbuf[2] = (nb_sectors >> 40) & 0xff;
-            outbuf[3] = (nb_sectors >> 32) & 0xff;
-            outbuf[4] = (nb_sectors >> 24) & 0xff;
-            outbuf[5] = (nb_sectors >> 16) & 0xff;
-            outbuf[6] = (nb_sectors >> 8) & 0xff;
-            outbuf[7] = nb_sectors & 0xff;
-            outbuf[8] = 0;
-            outbuf[9] = 0;
-            outbuf[10] = s->qdev.blocksize >> 8;
-            outbuf[11] = 0;
-            outbuf[12] = 0;
-            outbuf[13] = get_physical_block_exp(&s->qdev.conf);
-
-            /* set TPE bit if the format supports discard */
-            if (s->qdev.conf.discard_granularity) {
-                outbuf[14] = 0x80;
-            }
-
-            /* Protection, exponent and lowest lba field left blank. */
-            break;
-        }
-        DPRINTF("Unsupported Service Action In\n");
-        goto illegal_request;
-    case SYNCHRONIZE_CACHE:
-        /* The request is used as the AIO opaque value, so add a ref.  */
-        scsi_req_ref(&r->req);
-        bdrv_acct_start(s->qdev.conf.bs, &r->acct, 0, BDRV_ACCT_FLUSH);
-        r->req.aiocb = bdrv_aio_flush(s->qdev.conf.bs, scsi_aio_complete, r);
-        return 0;
-    case SEEK_10:
-        DPRINTF("Seek(10) (sector %" PRId64 ")\n", r->req.cmd.lba);
-        if (r->req.cmd.lba > s->qdev.max_lba) {
-            goto illegal_lba;
-        }
-        break;
-    case MODE_SELECT:
-        DPRINTF("Mode Select(6) (len %lu)\n", (long)r->req.cmd.xfer);
-        break;
-    case MODE_SELECT_10:
-        DPRINTF("Mode Select(10) (len %lu)\n", (long)r->req.cmd.xfer);
-        break;
-    case UNMAP:
-        DPRINTF("Unmap (len %lu)\n", (long)r->req.cmd.xfer);
-        break;
-    case WRITE_SAME_10:
-    case WRITE_SAME_16:
-        nb_sectors = scsi_data_cdb_length(r->req.cmd.buf);
-        if (bdrv_is_read_only(s->qdev.conf.bs)) {
-            scsi_check_condition(r, SENSE_CODE(WRITE_PROTECTED));
-            return 0;
-        }
-        if (!check_lba_range(s, r->req.cmd.lba, nb_sectors)) {
-            goto illegal_lba;
-        }
-
-        /*
-         * We only support WRITE SAME with the unmap bit set for now.
-         */
-        if (!(req->cmd.buf[1] & 0x8)) {
-            goto illegal_request;
-        }
-
-        /* The request is used as the AIO opaque value, so add a ref.  */
-        scsi_req_ref(&r->req);
-        r->req.aiocb = bdrv_aio_discard(s->qdev.conf.bs,
-                                        r->req.cmd.lba * (s->qdev.blocksize / 512),
-                                        nb_sectors * (s->qdev.blocksize / 512),
-                                        scsi_aio_complete, r);
-        return 0;
-    default:
-        DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]);
-        scsi_check_condition(r, SENSE_CODE(INVALID_OPCODE));
-        return 0;
-    }
-    assert(!r->req.aiocb);
-    r->iov.iov_len = MIN(r->buflen, req->cmd.xfer);
-    if (r->iov.iov_len == 0) {
-        scsi_req_complete(&r->req, GOOD);
-    }
-    if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
-        assert(r->iov.iov_len == req->cmd.xfer);
-        return -r->iov.iov_len;
-    } else {
-        return r->iov.iov_len;
-    }
-
-illegal_request:
-    if (r->req.status == -1) {
-        scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
-    }
-    return 0;
-
-illegal_lba:
-    scsi_check_condition(r, SENSE_CODE(LBA_OUT_OF_RANGE));
-    return 0;
-}
-
-/* Execute a scsi command.  Returns the length of the data expected by the
-   command.  This will be Positive for data transfers from the device
-   (eg. disk reads), negative for transfers to the device (eg. disk writes),
-   and zero if the command does not transfer any data.  */
-
-static int32_t scsi_disk_dma_command(SCSIRequest *req, uint8_t *buf)
-{
-    SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
-    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
-    uint32_t len;
-    uint8_t command;
-
-    command = buf[0];
-
-    if (s->tray_open || !bdrv_is_inserted(s->qdev.conf.bs)) {
-        scsi_check_condition(r, SENSE_CODE(NO_MEDIUM));
-        return 0;
-    }
-
-    len = scsi_data_cdb_length(r->req.cmd.buf);
-    switch (command) {
-    case READ_6:
-    case READ_10:
-    case READ_12:
-    case READ_16:
-        DPRINTF("Read (sector %" PRId64 ", count %u)\n", r->req.cmd.lba, len);
-        if (r->req.cmd.buf[1] & 0xe0) {
-            goto illegal_request;
-        }
-        if (!check_lba_range(s, r->req.cmd.lba, len)) {
-            goto illegal_lba;
-        }
-        r->sector = r->req.cmd.lba * (s->qdev.blocksize / 512);
-        r->sector_count = len * (s->qdev.blocksize / 512);
-        break;
-    case WRITE_6:
-    case WRITE_10:
-    case WRITE_12:
-    case WRITE_16:
-    case WRITE_VERIFY_10:
-    case WRITE_VERIFY_12:
-    case WRITE_VERIFY_16:
-        if (bdrv_is_read_only(s->qdev.conf.bs)) {
-            scsi_check_condition(r, SENSE_CODE(WRITE_PROTECTED));
-            return 0;
-        }
-        /* fallthrough */
-    case VERIFY_10:
-    case VERIFY_12:
-    case VERIFY_16:
-        DPRINTF("Write %s(sector %" PRId64 ", count %u)\n",
-                (command & 0xe) == 0xe ? "And Verify " : "",
-                r->req.cmd.lba, len);
-        if (r->req.cmd.buf[1] & 0xe0) {
-            goto illegal_request;
-        }
-        if (!check_lba_range(s, r->req.cmd.lba, len)) {
-            goto illegal_lba;
-        }
-        r->sector = r->req.cmd.lba * (s->qdev.blocksize / 512);
-        r->sector_count = len * (s->qdev.blocksize / 512);
-        break;
-    default:
-        abort();
-    illegal_request:
-        scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
-        return 0;
-    illegal_lba:
-        scsi_check_condition(r, SENSE_CODE(LBA_OUT_OF_RANGE));
-        return 0;
-    }
-    if (r->sector_count == 0) {
-        scsi_req_complete(&r->req, GOOD);
-    }
-    assert(r->iov.iov_len == 0);
-    if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
-        return -r->sector_count * 512;
-    } else {
-        return r->sector_count * 512;
-    }
-}
-
-static void scsi_disk_reset(DeviceState *dev)
-{
-    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev.qdev, dev);
-    uint64_t nb_sectors;
-
-    scsi_device_purge_requests(&s->qdev, SENSE_CODE(RESET));
-
-    bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors);
-    nb_sectors /= s->qdev.blocksize / 512;
-    if (nb_sectors) {
-        nb_sectors--;
-    }
-    s->qdev.max_lba = nb_sectors;
-}
-
-static void scsi_destroy(SCSIDevice *dev)
-{
-    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
-
-    scsi_device_purge_requests(&s->qdev, SENSE_CODE(NO_SENSE));
-    blockdev_mark_auto_del(s->qdev.conf.bs);
-}
-
-static void scsi_disk_resize_cb(void *opaque)
-{
-    SCSIDiskState *s = opaque;
-
-    /* SPC lists this sense code as available only for
-     * direct-access devices.
-     */
-    if (s->qdev.type == TYPE_DISK) {
-        scsi_device_report_change(&s->qdev, SENSE_CODE(CAPACITY_CHANGED));
-    }
-}
-
-static void scsi_cd_change_media_cb(void *opaque, bool load)
-{
-    SCSIDiskState *s = opaque;
-
-    /*
-     * When a CD gets changed, we have to report an ejected state and
-     * then a loaded state to guests so that they detect tray
-     * open/close and media change events.  Guests that do not use
-     * GET_EVENT_STATUS_NOTIFICATION to detect such tray open/close
-     * states rely on this behavior.
-     *
-     * media_changed governs the state machine used for unit attention
-     * report.  media_event is used by GET EVENT STATUS NOTIFICATION.
-     */
-    s->media_changed = load;
-    s->tray_open = !load;
-    scsi_device_set_ua(&s->qdev, SENSE_CODE(UNIT_ATTENTION_NO_MEDIUM));
-    s->media_event = true;
-    s->eject_request = false;
-}
-
-static void scsi_cd_eject_request_cb(void *opaque, bool force)
-{
-    SCSIDiskState *s = opaque;
-
-    s->eject_request = true;
-    if (force) {
-        s->tray_locked = false;
-    }
-}
-
-static bool scsi_cd_is_tray_open(void *opaque)
-{
-    return ((SCSIDiskState *)opaque)->tray_open;
-}
-
-static bool scsi_cd_is_medium_locked(void *opaque)
-{
-    return ((SCSIDiskState *)opaque)->tray_locked;
-}
-
-static const BlockDevOps scsi_disk_removable_block_ops = {
-    .change_media_cb = scsi_cd_change_media_cb,
-    .eject_request_cb = scsi_cd_eject_request_cb,
-    .is_tray_open = scsi_cd_is_tray_open,
-    .is_medium_locked = scsi_cd_is_medium_locked,
-
-    .resize_cb = scsi_disk_resize_cb,
-};
-
-static const BlockDevOps scsi_disk_block_ops = {
-    .resize_cb = scsi_disk_resize_cb,
-};
-
-static void scsi_disk_unit_attention_reported(SCSIDevice *dev)
-{
-    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
-    if (s->media_changed) {
-        s->media_changed = false;
-        scsi_device_set_ua(&s->qdev, SENSE_CODE(MEDIUM_CHANGED));
-    }
-}
-
-static int scsi_initfn(SCSIDevice *dev)
-{
-    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
-
-    if (!s->qdev.conf.bs) {
-        error_report("drive property not set");
-        return -1;
-    }
-
-    if (!(s->features & (1 << SCSI_DISK_F_REMOVABLE)) &&
-        !bdrv_is_inserted(s->qdev.conf.bs)) {
-        error_report("Device needs media, but drive is empty");
-        return -1;
-    }
-
-    blkconf_serial(&s->qdev.conf, &s->serial);
-    if (dev->type == TYPE_DISK
-        && blkconf_geometry(&dev->conf, NULL, 65535, 255, 255) < 0) {
-        return -1;
-    }
-
-    if (s->qdev.conf.discard_granularity == -1) {
-        s->qdev.conf.discard_granularity =
-            MAX(s->qdev.conf.logical_block_size, DEFAULT_DISCARD_GRANULARITY);
-    }
-
-    if (!s->version) {
-        s->version = g_strdup(qemu_get_version());
-    }
-    if (!s->vendor) {
-        s->vendor = g_strdup("QEMU");
-    }
-
-    if (bdrv_is_sg(s->qdev.conf.bs)) {
-        error_report("unwanted /dev/sg*");
-        return -1;
-    }
-
-    if (s->features & (1 << SCSI_DISK_F_REMOVABLE)) {
-        bdrv_set_dev_ops(s->qdev.conf.bs, &scsi_disk_removable_block_ops, s);
-    } else {
-        bdrv_set_dev_ops(s->qdev.conf.bs, &scsi_disk_block_ops, s);
-    }
-    bdrv_set_buffer_alignment(s->qdev.conf.bs, s->qdev.blocksize);
-
-    bdrv_iostatus_enable(s->qdev.conf.bs);
-    add_boot_device_path(s->qdev.conf.bootindex, &dev->qdev, NULL);
-    return 0;
-}
-
-static int scsi_hd_initfn(SCSIDevice *dev)
-{
-    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
-    s->qdev.blocksize = s->qdev.conf.logical_block_size;
-    s->qdev.type = TYPE_DISK;
-    if (!s->product) {
-        s->product = g_strdup("QEMU HARDDISK");
-    }
-    return scsi_initfn(&s->qdev);
-}
-
-static int scsi_cd_initfn(SCSIDevice *dev)
-{
-    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
-    s->qdev.blocksize = 2048;
-    s->qdev.type = TYPE_ROM;
-    s->features |= 1 << SCSI_DISK_F_REMOVABLE;
-    if (!s->product) {
-        s->product = g_strdup("QEMU CD-ROM");
-    }
-    return scsi_initfn(&s->qdev);
-}
-
-static int scsi_disk_initfn(SCSIDevice *dev)
-{
-    DriveInfo *dinfo;
-
-    if (!dev->conf.bs) {
-        return scsi_initfn(dev);  /* ... and die there */
-    }
-
-    dinfo = drive_get_by_blockdev(dev->conf.bs);
-    if (dinfo->media_cd) {
-        return scsi_cd_initfn(dev);
-    } else {
-        return scsi_hd_initfn(dev);
-    }
-}
-
-static const SCSIReqOps scsi_disk_emulate_reqops = {
-    .size         = sizeof(SCSIDiskReq),
-    .free_req     = scsi_free_request,
-    .send_command = scsi_disk_emulate_command,
-    .read_data    = scsi_disk_emulate_read_data,
-    .write_data   = scsi_disk_emulate_write_data,
-    .get_buf      = scsi_get_buf,
-};
-
-static const SCSIReqOps scsi_disk_dma_reqops = {
-    .size         = sizeof(SCSIDiskReq),
-    .free_req     = scsi_free_request,
-    .send_command = scsi_disk_dma_command,
-    .read_data    = scsi_read_data,
-    .write_data   = scsi_write_data,
-    .cancel_io    = scsi_cancel_io,
-    .get_buf      = scsi_get_buf,
-    .load_request = scsi_disk_load_request,
-    .save_request = scsi_disk_save_request,
-};
-
-static const SCSIReqOps *const scsi_disk_reqops_dispatch[256] = {
-    [TEST_UNIT_READY]                 = &scsi_disk_emulate_reqops,
-    [INQUIRY]                         = &scsi_disk_emulate_reqops,
-    [MODE_SENSE]                      = &scsi_disk_emulate_reqops,
-    [MODE_SENSE_10]                   = &scsi_disk_emulate_reqops,
-    [START_STOP]                      = &scsi_disk_emulate_reqops,
-    [ALLOW_MEDIUM_REMOVAL]            = &scsi_disk_emulate_reqops,
-    [READ_CAPACITY_10]                = &scsi_disk_emulate_reqops,
-    [READ_TOC]                        = &scsi_disk_emulate_reqops,
-    [READ_DVD_STRUCTURE]              = &scsi_disk_emulate_reqops,
-    [READ_DISC_INFORMATION]           = &scsi_disk_emulate_reqops,
-    [GET_CONFIGURATION]               = &scsi_disk_emulate_reqops,
-    [GET_EVENT_STATUS_NOTIFICATION]   = &scsi_disk_emulate_reqops,
-    [MECHANISM_STATUS]                = &scsi_disk_emulate_reqops,
-    [SERVICE_ACTION_IN_16]            = &scsi_disk_emulate_reqops,
-    [REQUEST_SENSE]                   = &scsi_disk_emulate_reqops,
-    [SYNCHRONIZE_CACHE]               = &scsi_disk_emulate_reqops,
-    [SEEK_10]                         = &scsi_disk_emulate_reqops,
-    [MODE_SELECT]                     = &scsi_disk_emulate_reqops,
-    [MODE_SELECT_10]                  = &scsi_disk_emulate_reqops,
-    [UNMAP]                           = &scsi_disk_emulate_reqops,
-    [WRITE_SAME_10]                   = &scsi_disk_emulate_reqops,
-    [WRITE_SAME_16]                   = &scsi_disk_emulate_reqops,
-
-    [READ_6]                          = &scsi_disk_dma_reqops,
-    [READ_10]                         = &scsi_disk_dma_reqops,
-    [READ_12]                         = &scsi_disk_dma_reqops,
-    [READ_16]                         = &scsi_disk_dma_reqops,
-    [VERIFY_10]                       = &scsi_disk_dma_reqops,
-    [VERIFY_12]                       = &scsi_disk_dma_reqops,
-    [VERIFY_16]                       = &scsi_disk_dma_reqops,
-    [WRITE_6]                         = &scsi_disk_dma_reqops,
-    [WRITE_10]                        = &scsi_disk_dma_reqops,
-    [WRITE_12]                        = &scsi_disk_dma_reqops,
-    [WRITE_16]                        = &scsi_disk_dma_reqops,
-    [WRITE_VERIFY_10]                 = &scsi_disk_dma_reqops,
-    [WRITE_VERIFY_12]                 = &scsi_disk_dma_reqops,
-    [WRITE_VERIFY_16]                 = &scsi_disk_dma_reqops,
-};
-
-static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun,
-                                     uint8_t *buf, void *hba_private)
-{
-    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
-    SCSIRequest *req;
-    const SCSIReqOps *ops;
-    uint8_t command;
-
-    command = buf[0];
-    ops = scsi_disk_reqops_dispatch[command];
-    if (!ops) {
-        ops = &scsi_disk_emulate_reqops;
-    }
-    req = scsi_req_alloc(ops, &s->qdev, tag, lun, hba_private);
-
-#ifdef DEBUG_SCSI
-    DPRINTF("Command: lun=%d tag=0x%x data=0x%02x", lun, tag, buf[0]);
-    {
-        int i;
-        for (i = 1; i < req->cmd.len; i++) {
-            printf(" 0x%02x", buf[i]);
-        }
-        printf("\n");
-    }
-#endif
-
-    return req;
-}
-
-#ifdef __linux__
-static int get_device_type(SCSIDiskState *s)
-{
-    BlockDriverState *bdrv = s->qdev.conf.bs;
-    uint8_t cmd[16];
-    uint8_t buf[36];
-    uint8_t sensebuf[8];
-    sg_io_hdr_t io_header;
-    int ret;
-
-    memset(cmd, 0, sizeof(cmd));
-    memset(buf, 0, sizeof(buf));
-    cmd[0] = INQUIRY;
-    cmd[4] = sizeof(buf);
-
-    memset(&io_header, 0, sizeof(io_header));
-    io_header.interface_id = 'S';
-    io_header.dxfer_direction = SG_DXFER_FROM_DEV;
-    io_header.dxfer_len = sizeof(buf);
-    io_header.dxferp = buf;
-    io_header.cmdp = cmd;
-    io_header.cmd_len = sizeof(cmd);
-    io_header.mx_sb_len = sizeof(sensebuf);
-    io_header.sbp = sensebuf;
-    io_header.timeout = 6000; /* XXX */
-
-    ret = bdrv_ioctl(bdrv, SG_IO, &io_header);
-    if (ret < 0 || io_header.driver_status || io_header.host_status) {
-        return -1;
-    }
-    s->qdev.type = buf[0];
-    if (buf[1] & 0x80) {
-        s->features |= 1 << SCSI_DISK_F_REMOVABLE;
-    }
-    return 0;
-}
-
-static int scsi_block_initfn(SCSIDevice *dev)
-{
-    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
-    int sg_version;
-    int rc;
-
-    if (!s->qdev.conf.bs) {
-        error_report("scsi-block: drive property not set");
-        return -1;
-    }
-
-    /* check we are using a driver managing SG_IO (version 3 and after) */
-    if (bdrv_ioctl(s->qdev.conf.bs, SG_GET_VERSION_NUM, &sg_version) < 0 ||
-        sg_version < 30000) {
-        error_report("scsi-block: scsi generic interface too old");
-        return -1;
-    }
-
-    /* get device type from INQUIRY data */
-    rc = get_device_type(s);
-    if (rc < 0) {
-        error_report("scsi-block: INQUIRY failed");
-        return -1;
-    }
-
-    /* Make a guess for the block size, we'll fix it when the guest sends.
-     * READ CAPACITY.  If they don't, they likely would assume these sizes
-     * anyway. (TODO: check in /sys).
-     */
-    if (s->qdev.type == TYPE_ROM || s->qdev.type == TYPE_WORM) {
-        s->qdev.blocksize = 2048;
-    } else {
-        s->qdev.blocksize = 512;
-    }
-    return scsi_initfn(&s->qdev);
-}
-
-static SCSIRequest *scsi_block_new_request(SCSIDevice *d, uint32_t tag,
-                                           uint32_t lun, uint8_t *buf,
-                                           void *hba_private)
-{
-    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
-
-    switch (buf[0]) {
-    case READ_6:
-    case READ_10:
-    case READ_12:
-    case READ_16:
-    case VERIFY_10:
-    case VERIFY_12:
-    case VERIFY_16:
-    case WRITE_6:
-    case WRITE_10:
-    case WRITE_12:
-    case WRITE_16:
-    case WRITE_VERIFY_10:
-    case WRITE_VERIFY_12:
-    case WRITE_VERIFY_16:
-        /* If we are not using O_DIRECT, we might read stale data from the
-        * host cache if writes were made using other commands than these
-        * ones (such as WRITE SAME or EXTENDED COPY, etc.).  So, without
-        * O_DIRECT everything must go through SG_IO.
-         */
-        if (bdrv_get_flags(s->qdev.conf.bs) & BDRV_O_NOCACHE) {
-            break;
-        }
-
-        /* MMC writing cannot be done via pread/pwrite, because it sometimes
-         * involves writing beyond the maximum LBA or to negative LBA (lead-in).
-         * And once you do these writes, reading from the block device is
-         * unreliable, too.  It is even possible that reads deliver random data
-         * from the host page cache (this is probably a Linux bug).
-         *
-         * We might use scsi_disk_dma_reqops as long as no writing commands are
-         * seen, but performance usually isn't paramount on optical media.  So,
-         * just make scsi-block operate the same as scsi-generic for them.
-         */
-        if (s->qdev.type != TYPE_ROM) {
-            return scsi_req_alloc(&scsi_disk_dma_reqops, &s->qdev, tag, lun,
-                                  hba_private);
-        }
-    }
-
-    return scsi_req_alloc(&scsi_generic_req_ops, &s->qdev, tag, lun,
-                          hba_private);
-}
-#endif
-
-#define DEFINE_SCSI_DISK_PROPERTIES()                                \
-    DEFINE_BLOCK_PROPERTIES(SCSIDiskState, qdev.conf),               \
-    DEFINE_PROP_STRING("ver", SCSIDiskState, version),               \
-    DEFINE_PROP_STRING("serial", SCSIDiskState, serial),             \
-    DEFINE_PROP_STRING("vendor", SCSIDiskState, vendor),             \
-    DEFINE_PROP_STRING("product", SCSIDiskState, product)
-
-static Property scsi_hd_properties[] = {
-    DEFINE_SCSI_DISK_PROPERTIES(),
-    DEFINE_PROP_BIT("removable", SCSIDiskState, features,
-                    SCSI_DISK_F_REMOVABLE, false),
-    DEFINE_PROP_BIT("dpofua", SCSIDiskState, features,
-                    SCSI_DISK_F_DPOFUA, false),
-    DEFINE_PROP_HEX64("wwn", SCSIDiskState, wwn, 0),
-    DEFINE_BLOCK_CHS_PROPERTIES(SCSIDiskState, qdev.conf),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static const VMStateDescription vmstate_scsi_disk_state = {
-    .name = "scsi-disk",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_SCSI_DEVICE(qdev, SCSIDiskState),
-        VMSTATE_BOOL(media_changed, SCSIDiskState),
-        VMSTATE_BOOL(media_event, SCSIDiskState),
-        VMSTATE_BOOL(eject_request, SCSIDiskState),
-        VMSTATE_BOOL(tray_open, SCSIDiskState),
-        VMSTATE_BOOL(tray_locked, SCSIDiskState),
-        VMSTATE_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;
-    dc->vmsd  = &vmstate_scsi_disk_state;
-}
-
-static const 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_HEX64("wwn", SCSIDiskState, wwn, 0),
-    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;
-    dc->vmsd  = &vmstate_scsi_disk_state;
-}
-
-static const 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_PROP_DRIVE("drive", SCSIDiskState, qdev.conf.bs),
-    DEFINE_PROP_INT32("bootindex", SCSIDiskState, qdev.conf.bootindex, -1),
-    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;
-    dc->vmsd  = &vmstate_scsi_disk_state;
-}
-
-static const 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, features,
-                    SCSI_DISK_F_REMOVABLE, false),
-    DEFINE_PROP_BIT("dpofua", SCSIDiskState, features,
-                    SCSI_DISK_F_DPOFUA, false),
-    DEFINE_PROP_HEX64("wwn", SCSIDiskState, wwn, 0),
-    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;
-    dc->vmsd  = &vmstate_scsi_disk_state;
-}
-
-static const 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_types(void)
-{
-    type_register_static(&scsi_hd_info);
-    type_register_static(&scsi_cd_info);
-#ifdef __linux__
-    type_register_static(&scsi_block_info);
-#endif
-    type_register_static(&scsi_disk_info);
-}
-
-type_init(scsi_disk_register_types)
diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c
deleted file mode 100644 (file)
index 4d04cac..0000000
+++ /dev/null
@@ -1,516 +0,0 @@
-/*
- * Generic SCSI Device support
- *
- * Copyright (c) 2007 Bull S.A.S.
- * Based on code by Paul Brook
- * Based on code by Fabrice Bellard
- *
- * Written by Laurent Vivier <Laurent.Vivier@bull.net>
- *
- * This code is licensed under the LGPL.
- *
- */
-
-#include "qemu-common.h"
-#include "qemu/error-report.h"
-#include "hw/scsi.h"
-#include "sysemu/blockdev.h"
-
-#ifdef __linux__
-
-//#define DEBUG_SCSI
-
-#ifdef DEBUG_SCSI
-#define DPRINTF(fmt, ...) \
-do { printf("scsi-generic: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...) do {} while(0)
-#endif
-
-#define BADF(fmt, ...) \
-do { fprintf(stderr, "scsi-generic: " fmt , ## __VA_ARGS__); } while (0)
-
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <scsi/sg.h>
-#include "hw/scsi-defs.h"
-
-#define SCSI_SENSE_BUF_SIZE 96
-
-#define SG_ERR_DRIVER_TIMEOUT  0x06
-#define SG_ERR_DRIVER_SENSE    0x08
-
-#define SG_ERR_DID_OK          0x00
-#define SG_ERR_DID_NO_CONNECT  0x01
-#define SG_ERR_DID_BUS_BUSY    0x02
-#define SG_ERR_DID_TIME_OUT    0x03
-
-#ifndef MAX_UINT
-#define MAX_UINT ((unsigned int)-1)
-#endif
-
-typedef struct SCSIGenericReq {
-    SCSIRequest req;
-    uint8_t *buf;
-    int buflen;
-    int len;
-    sg_io_hdr_t io_header;
-} SCSIGenericReq;
-
-static void scsi_generic_save_request(QEMUFile *f, SCSIRequest *req)
-{
-    SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
-
-    qemu_put_sbe32s(f, &r->buflen);
-    if (r->buflen && r->req.cmd.mode == SCSI_XFER_TO_DEV) {
-        assert(!r->req.sg);
-        qemu_put_buffer(f, r->buf, r->req.cmd.xfer);
-    }
-}
-
-static void scsi_generic_load_request(QEMUFile *f, SCSIRequest *req)
-{
-    SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
-
-    qemu_get_sbe32s(f, &r->buflen);
-    if (r->buflen && r->req.cmd.mode == SCSI_XFER_TO_DEV) {
-        assert(!r->req.sg);
-        qemu_get_buffer(f, r->buf, r->req.cmd.xfer);
-    }
-}
-
-static void scsi_free_request(SCSIRequest *req)
-{
-    SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
-
-    g_free(r->buf);
-}
-
-/* Helper function for command completion.  */
-static void scsi_command_complete(void *opaque, int ret)
-{
-    int status;
-    SCSIGenericReq *r = (SCSIGenericReq *)opaque;
-
-    r->req.aiocb = NULL;
-    if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) {
-        r->req.sense_len = r->io_header.sb_len_wr;
-    }
-
-    if (ret != 0) {
-        switch (ret) {
-        case -EDOM:
-            status = TASK_SET_FULL;
-            break;
-        case -ENOMEM:
-            status = CHECK_CONDITION;
-            scsi_req_build_sense(&r->req, SENSE_CODE(TARGET_FAILURE));
-            break;
-        default:
-            status = CHECK_CONDITION;
-            scsi_req_build_sense(&r->req, SENSE_CODE(IO_ERROR));
-            break;
-        }
-    } else {
-        if (r->io_header.host_status == SG_ERR_DID_NO_CONNECT ||
-            r->io_header.host_status == SG_ERR_DID_BUS_BUSY ||
-            r->io_header.host_status == SG_ERR_DID_TIME_OUT ||
-            (r->io_header.driver_status & SG_ERR_DRIVER_TIMEOUT)) {
-            status = BUSY;
-            BADF("Driver Timeout\n");
-        } else if (r->io_header.host_status) {
-            status = CHECK_CONDITION;
-            scsi_req_build_sense(&r->req, SENSE_CODE(I_T_NEXUS_LOSS));
-        } else if (r->io_header.status) {
-            status = r->io_header.status;
-        } else if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) {
-            status = CHECK_CONDITION;
-        } else {
-            status = GOOD;
-        }
-    }
-    DPRINTF("Command complete 0x%p tag=0x%x status=%d\n",
-            r, r->req.tag, status);
-
-    scsi_req_complete(&r->req, status);
-    if (!r->req.io_canceled) {
-        scsi_req_unref(&r->req);
-    }
-}
-
-/* Cancel a pending data transfer.  */
-static void scsi_cancel_io(SCSIRequest *req)
-{
-    SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
-
-    DPRINTF("Cancel tag=0x%x\n", req->tag);
-    if (r->req.aiocb) {
-        bdrv_aio_cancel(r->req.aiocb);
-
-        /* This reference was left in by scsi_*_data.  We take ownership of
-         * it independent of whether bdrv_aio_cancel completes the request
-         * or not.  */
-        scsi_req_unref(&r->req);
-    }
-    r->req.aiocb = NULL;
-}
-
-static int execute_command(BlockDriverState *bdrv,
-                           SCSIGenericReq *r, int direction,
-                          BlockDriverCompletionFunc *complete)
-{
-    r->io_header.interface_id = 'S';
-    r->io_header.dxfer_direction = direction;
-    r->io_header.dxferp = r->buf;
-    r->io_header.dxfer_len = r->buflen;
-    r->io_header.cmdp = r->req.cmd.buf;
-    r->io_header.cmd_len = r->req.cmd.len;
-    r->io_header.mx_sb_len = sizeof(r->req.sense);
-    r->io_header.sbp = r->req.sense;
-    r->io_header.timeout = MAX_UINT;
-    r->io_header.usr_ptr = r;
-    r->io_header.flags |= SG_FLAG_DIRECT_IO;
-
-    r->req.aiocb = bdrv_aio_ioctl(bdrv, SG_IO, &r->io_header, complete, r);
-
-    return 0;
-}
-
-static void scsi_read_complete(void * opaque, int ret)
-{
-    SCSIGenericReq *r = (SCSIGenericReq *)opaque;
-    SCSIDevice *s = r->req.dev;
-    int len;
-
-    r->req.aiocb = NULL;
-    if (ret) {
-        DPRINTF("IO error ret %d\n", ret);
-        scsi_command_complete(r, ret);
-        return;
-    }
-    len = r->io_header.dxfer_len - r->io_header.resid;
-    DPRINTF("Data ready tag=0x%x len=%d\n", r->req.tag, len);
-
-    r->len = -1;
-    if (len == 0) {
-        scsi_command_complete(r, 0);
-    } else {
-        /* Snoop READ CAPACITY output to set the blocksize.  */
-        if (r->req.cmd.buf[0] == READ_CAPACITY_10) {
-            s->blocksize = ldl_be_p(&r->buf[4]);
-            s->max_lba = ldl_be_p(&r->buf[0]);
-        } else if (r->req.cmd.buf[0] == SERVICE_ACTION_IN_16 &&
-                   (r->req.cmd.buf[1] & 31) == SAI_READ_CAPACITY_16) {
-            s->blocksize = ldl_be_p(&r->buf[8]);
-            s->max_lba = ldq_be_p(&r->buf[0]);
-        }
-        bdrv_set_buffer_alignment(s->conf.bs, s->blocksize);
-
-        scsi_req_data(&r->req, len);
-        if (!r->req.io_canceled) {
-            scsi_req_unref(&r->req);
-        }
-    }
-}
-
-/* Read more data from scsi device into buffer.  */
-static void scsi_read_data(SCSIRequest *req)
-{
-    SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
-    SCSIDevice *s = r->req.dev;
-    int ret;
-
-    DPRINTF("scsi_read_data 0x%x\n", req->tag);
-
-    /* The request is used as the AIO opaque value, so add a ref.  */
-    scsi_req_ref(&r->req);
-    if (r->len == -1) {
-        scsi_command_complete(r, 0);
-        return;
-    }
-
-    ret = execute_command(s->conf.bs, r, SG_DXFER_FROM_DEV, scsi_read_complete);
-    if (ret < 0) {
-        scsi_command_complete(r, ret);
-    }
-}
-
-static void scsi_write_complete(void * opaque, int ret)
-{
-    SCSIGenericReq *r = (SCSIGenericReq *)opaque;
-    SCSIDevice *s = r->req.dev;
-
-    DPRINTF("scsi_write_complete() ret = %d\n", ret);
-    r->req.aiocb = NULL;
-    if (ret) {
-        DPRINTF("IO error\n");
-        scsi_command_complete(r, ret);
-        return;
-    }
-
-    if (r->req.cmd.buf[0] == MODE_SELECT && r->req.cmd.buf[4] == 12 &&
-        s->type == TYPE_TAPE) {
-        s->blocksize = (r->buf[9] << 16) | (r->buf[10] << 8) | r->buf[11];
-        DPRINTF("block size %d\n", s->blocksize);
-    }
-
-    scsi_command_complete(r, ret);
-}
-
-/* Write data to a scsi device.  Returns nonzero on failure.
-   The transfer may complete asynchronously.  */
-static void scsi_write_data(SCSIRequest *req)
-{
-    SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
-    SCSIDevice *s = r->req.dev;
-    int ret;
-
-    DPRINTF("scsi_write_data 0x%x\n", req->tag);
-    if (r->len == 0) {
-        r->len = r->buflen;
-        scsi_req_data(&r->req, r->len);
-        return;
-    }
-
-    /* The request is used as the AIO opaque value, so add a ref.  */
-    scsi_req_ref(&r->req);
-    ret = execute_command(s->conf.bs, r, SG_DXFER_TO_DEV, scsi_write_complete);
-    if (ret < 0) {
-        scsi_command_complete(r, ret);
-    }
-}
-
-/* Return a pointer to the data buffer.  */
-static uint8_t *scsi_get_buf(SCSIRequest *req)
-{
-    SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
-
-    return r->buf;
-}
-
-/* Execute a scsi command.  Returns the length of the data expected by the
-   command.  This will be Positive for data transfers from the device
-   (eg. disk reads), negative for transfers to the device (eg. disk writes),
-   and zero if the command does not transfer any data.  */
-
-static int32_t scsi_send_command(SCSIRequest *req, uint8_t *cmd)
-{
-    SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
-    SCSIDevice *s = r->req.dev;
-    int ret;
-
-    DPRINTF("Command: lun=%d tag=0x%x len %zd data=0x%02x", lun, tag,
-            r->req.cmd.xfer, cmd[0]);
-
-#ifdef DEBUG_SCSI
-    {
-        int i;
-        for (i = 1; i < r->req.cmd.len; i++) {
-            printf(" 0x%02x", cmd[i]);
-        }
-        printf("\n");
-    }
-#endif
-
-    if (r->req.cmd.xfer == 0) {
-        if (r->buf != NULL)
-            g_free(r->buf);
-        r->buflen = 0;
-        r->buf = NULL;
-        /* The request is used as the AIO opaque value, so add a ref.  */
-        scsi_req_ref(&r->req);
-        ret = execute_command(s->conf.bs, r, SG_DXFER_NONE, scsi_command_complete);
-        if (ret < 0) {
-            scsi_command_complete(r, ret);
-            return 0;
-        }
-        return 0;
-    }
-
-    if (r->buflen != r->req.cmd.xfer) {
-        if (r->buf != NULL)
-            g_free(r->buf);
-        r->buf = g_malloc(r->req.cmd.xfer);
-        r->buflen = r->req.cmd.xfer;
-    }
-
-    memset(r->buf, 0, r->buflen);
-    r->len = r->req.cmd.xfer;
-    if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
-        r->len = 0;
-        return -r->req.cmd.xfer;
-    } else {
-        return r->req.cmd.xfer;
-    }
-}
-
-static int get_stream_blocksize(BlockDriverState *bdrv)
-{
-    uint8_t cmd[6];
-    uint8_t buf[12];
-    uint8_t sensebuf[8];
-    sg_io_hdr_t io_header;
-    int ret;
-
-    memset(cmd, 0, sizeof(cmd));
-    memset(buf, 0, sizeof(buf));
-    cmd[0] = MODE_SENSE;
-    cmd[4] = sizeof(buf);
-
-    memset(&io_header, 0, sizeof(io_header));
-    io_header.interface_id = 'S';
-    io_header.dxfer_direction = SG_DXFER_FROM_DEV;
-    io_header.dxfer_len = sizeof(buf);
-    io_header.dxferp = buf;
-    io_header.cmdp = cmd;
-    io_header.cmd_len = sizeof(cmd);
-    io_header.mx_sb_len = sizeof(sensebuf);
-    io_header.sbp = sensebuf;
-    io_header.timeout = 6000; /* XXX */
-
-    ret = bdrv_ioctl(bdrv, SG_IO, &io_header);
-    if (ret < 0 || io_header.driver_status || io_header.host_status) {
-        return -1;
-    }
-    return (buf[9] << 16) | (buf[10] << 8) | buf[11];
-}
-
-static void scsi_generic_reset(DeviceState *dev)
-{
-    SCSIDevice *s = SCSI_DEVICE(dev);
-
-    scsi_device_purge_requests(s, SENSE_CODE(RESET));
-}
-
-static void scsi_destroy(SCSIDevice *s)
-{
-    scsi_device_purge_requests(s, SENSE_CODE(NO_SENSE));
-    blockdev_mark_auto_del(s->conf.bs);
-}
-
-static int scsi_generic_initfn(SCSIDevice *s)
-{
-    int sg_version;
-    struct sg_scsi_id scsiid;
-
-    if (!s->conf.bs) {
-        error_report("drive property not set");
-        return -1;
-    }
-
-    if (bdrv_get_on_error(s->conf.bs, 0) != BLOCKDEV_ON_ERROR_ENOSPC) {
-        error_report("Device doesn't support drive option werror");
-        return -1;
-    }
-    if (bdrv_get_on_error(s->conf.bs, 1) != BLOCKDEV_ON_ERROR_REPORT) {
-        error_report("Device doesn't support drive option rerror");
-        return -1;
-    }
-
-    /* check we are using a driver managing SG_IO (version 3 and after */
-    if (bdrv_ioctl(s->conf.bs, SG_GET_VERSION_NUM, &sg_version) < 0) {
-        error_report("scsi generic interface not supported");
-        return -1;
-    }
-    if (sg_version < 30000) {
-        error_report("scsi generic interface too old");
-        return -1;
-    }
-
-    /* get LUN of the /dev/sg? */
-    if (bdrv_ioctl(s->conf.bs, SG_GET_SCSI_ID, &scsiid)) {
-        error_report("SG_GET_SCSI_ID ioctl failed");
-        return -1;
-    }
-
-    /* define device state */
-    s->type = scsiid.scsi_type;
-    DPRINTF("device type %d\n", s->type);
-    if (s->type == TYPE_DISK || s->type == TYPE_ROM) {
-        add_boot_device_path(s->conf.bootindex, &s->qdev, NULL);
-    }
-
-    switch (s->type) {
-    case TYPE_TAPE:
-        s->blocksize = get_stream_blocksize(s->conf.bs);
-        if (s->blocksize == -1) {
-            s->blocksize = 0;
-        }
-        break;
-
-        /* Make a guess for block devices, we'll fix it when the guest sends.
-         * READ CAPACITY.  If they don't, they likely would assume these sizes
-         * anyway. (TODO: they could also send MODE SENSE).
-         */
-    case TYPE_ROM:
-    case TYPE_WORM:
-        s->blocksize = 2048;
-        break;
-    default:
-        s->blocksize = 512;
-        break;
-    }
-
-    DPRINTF("block size %d\n", s->blocksize);
-    return 0;
-}
-
-const SCSIReqOps scsi_generic_req_ops = {
-    .size         = sizeof(SCSIGenericReq),
-    .free_req     = scsi_free_request,
-    .send_command = scsi_send_command,
-    .read_data    = scsi_read_data,
-    .write_data   = scsi_write_data,
-    .cancel_io    = scsi_cancel_io,
-    .get_buf      = scsi_get_buf,
-    .load_request = scsi_generic_load_request,
-    .save_request = scsi_generic_save_request,
-};
-
-static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun,
-                                     uint8_t *buf, void *hba_private)
-{
-    SCSIRequest *req;
-
-    req = scsi_req_alloc(&scsi_generic_req_ops, d, tag, lun, hba_private);
-    return req;
-}
-
-static Property scsi_generic_properties[] = {
-    DEFINE_PROP_DRIVE("drive", SCSIDevice, conf.bs),
-    DEFINE_PROP_INT32("bootindex", SCSIDevice, conf.bootindex, -1),
-    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;
-    dc->vmsd  = &vmstate_scsi_device;
-}
-
-static const 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_types(void)
-{
-    type_register_static(&scsi_generic_info);
-}
-
-type_init(scsi_generic_register_types)
-
-#endif /* __linux__ */
diff --git a/hw/scsi.h b/hw/scsi.h
deleted file mode 100644 (file)
index 33e2e0b..0000000
--- a/hw/scsi.h
+++ /dev/null
@@ -1,255 +0,0 @@
-#ifndef QEMU_HW_SCSI_H
-#define QEMU_HW_SCSI_H
-
-#include "hw/qdev.h"
-#include "block/block.h"
-#include "hw/block-common.h"
-#include "sysemu/sysemu.h"
-
-#define MAX_SCSI_DEVS  255
-
-#define SCSI_CMD_BUF_SIZE     16
-
-typedef struct SCSIBus SCSIBus;
-typedef struct SCSIBusInfo SCSIBusInfo;
-typedef struct SCSICommand SCSICommand;
-typedef struct SCSIDevice SCSIDevice;
-typedef struct SCSIRequest SCSIRequest;
-typedef struct SCSIReqOps SCSIReqOps;
-
-enum SCSIXferMode {
-    SCSI_XFER_NONE,      /*  TEST_UNIT_READY, ...            */
-    SCSI_XFER_FROM_DEV,  /*  READ, INQUIRY, MODE_SENSE, ...  */
-    SCSI_XFER_TO_DEV,    /*  WRITE, MODE_SELECT, ...         */
-};
-
-typedef struct SCSISense {
-    uint8_t key;
-    uint8_t asc;
-    uint8_t ascq;
-} SCSISense;
-
-#define SCSI_SENSE_BUF_SIZE 96
-
-struct SCSICommand {
-    uint8_t buf[SCSI_CMD_BUF_SIZE];
-    int len;
-    size_t xfer;
-    uint64_t lba;
-    enum SCSIXferMode mode;
-};
-
-struct SCSIRequest {
-    SCSIBus           *bus;
-    SCSIDevice        *dev;
-    const SCSIReqOps  *ops;
-    uint32_t          refcount;
-    uint32_t          tag;
-    uint32_t          lun;
-    uint32_t          status;
-    size_t            resid;
-    SCSICommand       cmd;
-    BlockDriverAIOCB  *aiocb;
-    QEMUSGList        *sg;
-    bool              dma_started;
-    uint8_t sense[SCSI_SENSE_BUF_SIZE];
-    uint32_t sense_len;
-    bool enqueued;
-    bool io_canceled;
-    bool retry;
-    void *hba_private;
-    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;
-    VMChangeStateEntry *vmsentry;
-    QEMUBH *bh;
-    uint32_t id;
-    BlockConf conf;
-    SCSISense unit_attention;
-    bool sense_is_ua;
-    uint8_t sense[SCSI_SENSE_BUF_SIZE];
-    uint32_t sense_len;
-    QTAILQ_HEAD(, SCSIRequest) requests;
-    uint32_t channel;
-    uint32_t lun;
-    int blocksize;
-    int type;
-    uint64_t max_lba;
-};
-
-extern const VMStateDescription vmstate_scsi_device;
-
-#define VMSTATE_SCSI_DEVICE(_field, _state) {                        \
-    .name       = (stringify(_field)),                               \
-    .size       = sizeof(SCSIDevice),                                \
-    .vmsd       = &vmstate_scsi_device,                              \
-    .flags      = VMS_STRUCT,                                        \
-    .offset     = vmstate_offset_value(_state, _field, SCSIDevice),  \
-}
-
-/* cdrom.c */
-int cdrom_read_toc(int nb_sectors, uint8_t *buf, int msf, int start_track);
-int cdrom_read_toc_raw(int nb_sectors, uint8_t *buf, int msf, int session_num);
-
-/* scsi-bus.c */
-struct SCSIReqOps {
-    size_t size;
-    void (*free_req)(SCSIRequest *req);
-    int32_t (*send_command)(SCSIRequest *req, uint8_t *buf);
-    void (*read_data)(SCSIRequest *req);
-    void (*write_data)(SCSIRequest *req);
-    void (*cancel_io)(SCSIRequest *req);
-    uint8_t *(*get_buf)(SCSIRequest *req);
-
-    void (*save_request)(QEMUFile *f, SCSIRequest *req);
-    void (*load_request)(QEMUFile *f, SCSIRequest *req);
-};
-
-struct SCSIBusInfo {
-    int tcq;
-    int max_channel, max_target, max_lun;
-    void (*transfer_data)(SCSIRequest *req, uint32_t arg);
-    void (*complete)(SCSIRequest *req, uint32_t arg, size_t resid);
-    void (*cancel)(SCSIRequest *req);
-    void (*hotplug)(SCSIBus *bus, SCSIDevice *dev);
-    void (*hot_unplug)(SCSIBus *bus, SCSIDevice *dev);
-    void (*change)(SCSIBus *bus, SCSIDevice *dev, SCSISense sense);
-    QEMUSGList *(*get_sg_list)(SCSIRequest *req);
-
-    void (*save_request)(QEMUFile *f, SCSIRequest *req);
-    void *(*load_request)(QEMUFile *f, SCSIRequest *req);
-    void (*free_request)(SCSIBus *bus, void *priv);
-};
-
-#define TYPE_SCSI_BUS "SCSI"
-#define SCSI_BUS(obj) OBJECT_CHECK(SCSIBus, (obj), TYPE_SCSI_BUS)
-
-struct SCSIBus {
-    BusState qbus;
-    int busnr;
-
-    SCSISense unit_attention;
-    const SCSIBusInfo *info;
-};
-
-void scsi_bus_new(SCSIBus *bus, DeviceState *host, const SCSIBusInfo *info);
-
-static inline SCSIBus *scsi_bus_from_device(SCSIDevice *d)
-{
-    return DO_UPCAST(SCSIBus, qbus, d->qdev.parent_bus);
-}
-
-SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockDriverState *bdrv,
-                                      int unit, bool removable, int bootindex);
-int scsi_bus_legacy_handle_cmdline(SCSIBus *bus);
-
-/*
- * Predefined sense codes
- */
-
-/* No sense data available */
-extern const struct SCSISense sense_code_NO_SENSE;
-/* LUN not ready, Manual intervention required */
-extern const struct SCSISense sense_code_LUN_NOT_READY;
-/* LUN not ready, Medium not present */
-extern const struct SCSISense sense_code_NO_MEDIUM;
-/* LUN not ready, medium removal prevented */
-extern const struct SCSISense sense_code_NOT_READY_REMOVAL_PREVENTED;
-/* Hardware error, internal target failure */
-extern const struct SCSISense sense_code_TARGET_FAILURE;
-/* Illegal request, invalid command operation code */
-extern const struct SCSISense sense_code_INVALID_OPCODE;
-/* Illegal request, LBA out of range */
-extern const struct SCSISense sense_code_LBA_OUT_OF_RANGE;
-/* Illegal request, Invalid field in CDB */
-extern const struct SCSISense sense_code_INVALID_FIELD;
-/* Illegal request, Invalid field in parameter list */
-extern const struct SCSISense sense_code_INVALID_PARAM;
-/* Illegal request, Parameter list length error */
-extern const struct SCSISense sense_code_INVALID_PARAM_LEN;
-/* Illegal request, LUN not supported */
-extern const struct SCSISense sense_code_LUN_NOT_SUPPORTED;
-/* Illegal request, Saving parameters not supported */
-extern const struct SCSISense sense_code_SAVING_PARAMS_NOT_SUPPORTED;
-/* Illegal request, Incompatible format */
-extern const struct SCSISense sense_code_INCOMPATIBLE_FORMAT;
-/* Illegal request, medium removal prevented */
-extern const struct SCSISense sense_code_ILLEGAL_REQ_REMOVAL_PREVENTED;
-/* Command aborted, I/O process terminated */
-extern const struct SCSISense sense_code_IO_ERROR;
-/* Command aborted, I_T Nexus loss occurred */
-extern const struct SCSISense sense_code_I_T_NEXUS_LOSS;
-/* Command aborted, Logical Unit failure */
-extern const struct SCSISense sense_code_LUN_FAILURE;
-/* LUN not ready, Capacity data has changed */
-extern const struct SCSISense sense_code_CAPACITY_CHANGED;
-/* LUN not ready, Medium not present */
-extern const struct SCSISense sense_code_UNIT_ATTENTION_NO_MEDIUM;
-/* Unit attention, Power on, reset or bus device reset occurred */
-extern const struct SCSISense sense_code_RESET;
-/* Unit attention, Medium may have changed*/
-extern const struct SCSISense sense_code_MEDIUM_CHANGED;
-/* Unit attention, Reported LUNs data has changed */
-extern const struct SCSISense sense_code_REPORTED_LUNS_CHANGED;
-/* Unit attention, Device internal reset */
-extern const struct SCSISense sense_code_DEVICE_INTERNAL_RESET;
-/* Data Protection, Write Protected */
-extern const struct SCSISense sense_code_WRITE_PROTECTED;
-
-#define SENSE_CODE(x) sense_code_ ## x
-
-uint32_t scsi_data_cdb_length(uint8_t *buf);
-uint32_t scsi_cdb_length(uint8_t *buf);
-int scsi_sense_valid(SCSISense sense);
-int scsi_build_sense(uint8_t *in_buf, int in_len,
-                     uint8_t *buf, int len, bool fixed);
-
-SCSIRequest *scsi_req_alloc(const SCSIReqOps *reqops, SCSIDevice *d,
-                            uint32_t tag, uint32_t lun, void *hba_private);
-SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun,
-                          uint8_t *buf, void *hba_private);
-int32_t scsi_req_enqueue(SCSIRequest *req);
-void scsi_req_free(SCSIRequest *req);
-SCSIRequest *scsi_req_ref(SCSIRequest *req);
-void scsi_req_unref(SCSIRequest *req);
-
-void scsi_req_build_sense(SCSIRequest *req, SCSISense sense);
-void scsi_req_print(SCSIRequest *req);
-void scsi_req_continue(SCSIRequest *req);
-void scsi_req_data(SCSIRequest *req, int len);
-void scsi_req_complete(SCSIRequest *req, int status);
-uint8_t *scsi_req_get_buf(SCSIRequest *req);
-int scsi_req_get_sense(SCSIRequest *req, uint8_t *buf, int len);
-void scsi_req_abort(SCSIRequest *req, int status);
-void scsi_req_cancel(SCSIRequest *req);
-void scsi_req_retry(SCSIRequest *req);
-void scsi_device_purge_requests(SCSIDevice *sdev, SCSISense sense);
-void scsi_device_set_ua(SCSIDevice *sdev, SCSISense sense);
-void scsi_device_report_change(SCSIDevice *dev, SCSISense sense);
-int scsi_device_get_sense(SCSIDevice *dev, uint8_t *buf, int len, bool fixed);
-SCSIDevice *scsi_device_find(SCSIBus *bus, int channel, int target, int lun);
-
-/* scsi-generic.c. */
-extern const SCSIReqOps scsi_generic_req_ops;
-
-#endif
diff --git a/hw/scsi/Makefile.objs b/hw/scsi/Makefile.objs
new file mode 100644 (file)
index 0000000..aab0e9b
--- /dev/null
@@ -0,0 +1,8 @@
+common-obj-y += scsi-disk.o
+common-obj-y += scsi-generic.o scsi-bus.o
+common-obj-$(CONFIG_LSI_SCSI_PCI) += lsi53c895a.o
+common-obj-$(CONFIG_MEGASAS_SCSI_PCI) += megasas.o
+common-obj-$(CONFIG_ESP) += esp.o
+common-obj-$(CONFIG_ESP_PCI) += esp-pci.o
+obj-$(CONFIG_PSERIES) += spapr_vscsi.o
+obj-$(CONFIG_VIRTIO) += virtio-scsi.o
diff --git a/hw/scsi/esp-pci.c b/hw/scsi/esp-pci.c
new file mode 100644 (file)
index 0000000..3ca5c8c
--- /dev/null
@@ -0,0 +1,518 @@
+/*
+ * QEMU ESP/NCR53C9x emulation
+ *
+ * Copyright (c) 2005-2006 Fabrice Bellard
+ * Copyright (c) 2012 Herve 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 "hw/pci/pci.h"
+#include "hw/nvram/eeprom93xx.h"
+#include "hw/scsi/esp.h"
+#include "trace.h"
+#include "qemu/log.h"
+
+#define TYPE_AM53C974_DEVICE "am53c974"
+
+#define DMA_CMD   0x0
+#define DMA_STC   0x1
+#define DMA_SPA   0x2
+#define DMA_WBC   0x3
+#define DMA_WAC   0x4
+#define DMA_STAT  0x5
+#define DMA_SMDLA 0x6
+#define DMA_WMAC  0x7
+
+#define DMA_CMD_MASK   0x03
+#define DMA_CMD_DIAG   0x04
+#define DMA_CMD_MDL    0x10
+#define DMA_CMD_INTE_P 0x20
+#define DMA_CMD_INTE_D 0x40
+#define DMA_CMD_DIR    0x80
+
+#define DMA_STAT_PWDN    0x01
+#define DMA_STAT_ERROR   0x02
+#define DMA_STAT_ABORT   0x04
+#define DMA_STAT_DONE    0x08
+#define DMA_STAT_SCSIINT 0x10
+#define DMA_STAT_BCMBLT  0x20
+
+#define SBAC_STATUS 0x1000
+
+typedef struct PCIESPState {
+    PCIDevice dev;
+    MemoryRegion io;
+    uint32_t dma_regs[8];
+    uint32_t sbac;
+    ESPState esp;
+} PCIESPState;
+
+static void esp_pci_handle_idle(PCIESPState *pci, uint32_t val)
+{
+    trace_esp_pci_dma_idle(val);
+    esp_dma_enable(&pci->esp, 0, 0);
+}
+
+static void esp_pci_handle_blast(PCIESPState *pci, uint32_t val)
+{
+    trace_esp_pci_dma_blast(val);
+    qemu_log_mask(LOG_UNIMP, "am53c974: cmd BLAST not implemented\n");
+}
+
+static void esp_pci_handle_abort(PCIESPState *pci, uint32_t val)
+{
+    trace_esp_pci_dma_abort(val);
+    if (pci->esp.current_req) {
+        scsi_req_cancel(pci->esp.current_req);
+    }
+}
+
+static void esp_pci_handle_start(PCIESPState *pci, uint32_t val)
+{
+    trace_esp_pci_dma_start(val);
+
+    pci->dma_regs[DMA_WBC] = pci->dma_regs[DMA_STC];
+    pci->dma_regs[DMA_WAC] = pci->dma_regs[DMA_SPA];
+    pci->dma_regs[DMA_WMAC] = pci->dma_regs[DMA_SMDLA];
+
+    pci->dma_regs[DMA_STAT] &= ~(DMA_STAT_BCMBLT | DMA_STAT_SCSIINT
+                               | DMA_STAT_DONE | DMA_STAT_ABORT
+                               | DMA_STAT_ERROR | DMA_STAT_PWDN);
+
+    esp_dma_enable(&pci->esp, 0, 1);
+}
+
+static void esp_pci_dma_write(PCIESPState *pci, uint32_t saddr, uint32_t val)
+{
+    trace_esp_pci_dma_write(saddr, pci->dma_regs[saddr], val);
+    switch (saddr) {
+    case DMA_CMD:
+        pci->dma_regs[saddr] = val;
+        switch (val & DMA_CMD_MASK) {
+        case 0x0: /* IDLE */
+            esp_pci_handle_idle(pci, val);
+            break;
+        case 0x1: /* BLAST */
+            esp_pci_handle_blast(pci, val);
+            break;
+        case 0x2: /* ABORT */
+            esp_pci_handle_abort(pci, val);
+            break;
+        case 0x3: /* START */
+            esp_pci_handle_start(pci, val);
+            break;
+        default: /* can't happen */
+            abort();
+        }
+        break;
+    case DMA_STC:
+    case DMA_SPA:
+    case DMA_SMDLA:
+        pci->dma_regs[saddr] = val;
+        break;
+    case DMA_STAT:
+        if (!(pci->sbac & SBAC_STATUS)) {
+            /* clear some bits on write */
+            uint32_t mask = DMA_STAT_ERROR | DMA_STAT_ABORT | DMA_STAT_DONE;
+            pci->dma_regs[DMA_STAT] &= ~(val & mask);
+        }
+        break;
+    default:
+        trace_esp_pci_error_invalid_write_dma(val, saddr);
+        return;
+    }
+}
+
+static uint32_t esp_pci_dma_read(PCIESPState *pci, uint32_t saddr)
+{
+    uint32_t val;
+
+    val = pci->dma_regs[saddr];
+    if (saddr == DMA_STAT) {
+        if (pci->esp.rregs[ESP_RSTAT] & STAT_INT) {
+            val |= DMA_STAT_SCSIINT;
+        }
+        if (pci->sbac & SBAC_STATUS) {
+            pci->dma_regs[DMA_STAT] &= ~(DMA_STAT_ERROR | DMA_STAT_ABORT |
+                                         DMA_STAT_DONE);
+        }
+    }
+
+    trace_esp_pci_dma_read(saddr, val);
+    return val;
+}
+
+static void esp_pci_io_write(void *opaque, hwaddr addr,
+                             uint64_t val, unsigned int size)
+{
+    PCIESPState *pci = opaque;
+
+    if (size < 4 || addr & 3) {
+        /* need to upgrade request: we only support 4-bytes accesses */
+        uint32_t current = 0, mask;
+        int shift;
+
+        if (addr < 0x40) {
+            current = pci->esp.wregs[addr >> 2];
+        } else if (addr < 0x60) {
+            current = pci->dma_regs[(addr - 0x40) >> 2];
+        } else if (addr < 0x74) {
+            current = pci->sbac;
+        }
+
+        shift = (4 - size) * 8;
+        mask = (~(uint32_t)0 << shift) >> shift;
+
+        shift = ((4 - (addr & 3)) & 3) * 8;
+        val <<= shift;
+        val |= current & ~(mask << shift);
+        addr &= ~3;
+        size = 4;
+    }
+
+    if (addr < 0x40) {
+        /* SCSI core reg */
+        esp_reg_write(&pci->esp, addr >> 2, val);
+    } else if (addr < 0x60) {
+        /* PCI DMA CCB */
+        esp_pci_dma_write(pci, (addr - 0x40) >> 2, val);
+    } else if (addr == 0x70) {
+        /* DMA SCSI Bus and control */
+        trace_esp_pci_sbac_write(pci->sbac, val);
+        pci->sbac = val;
+    } else {
+        trace_esp_pci_error_invalid_write((int)addr);
+    }
+}
+
+static uint64_t esp_pci_io_read(void *opaque, hwaddr addr,
+                                unsigned int size)
+{
+    PCIESPState *pci = opaque;
+    uint32_t ret;
+
+    if (addr < 0x40) {
+        /* SCSI core reg */
+        ret = esp_reg_read(&pci->esp, addr >> 2);
+    } else if (addr < 0x60) {
+        /* PCI DMA CCB */
+        ret = esp_pci_dma_read(pci, (addr - 0x40) >> 2);
+    } else if (addr == 0x70) {
+        /* DMA SCSI Bus and control */
+        trace_esp_pci_sbac_read(pci->sbac);
+        ret = pci->sbac;
+    } else {
+        /* Invalid region */
+        trace_esp_pci_error_invalid_read((int)addr);
+        ret = 0;
+    }
+
+    /* give only requested data */
+    ret >>= (addr & 3) * 8;
+    ret &= ~(~(uint64_t)0 << (8 * size));
+
+    return ret;
+}
+
+static void esp_pci_dma_memory_rw(PCIESPState *pci, uint8_t *buf, int len,
+                                  DMADirection dir)
+{
+    dma_addr_t addr;
+    DMADirection expected_dir;
+
+    if (pci->dma_regs[DMA_CMD] & DMA_CMD_DIR) {
+        expected_dir = DMA_DIRECTION_FROM_DEVICE;
+    } else {
+        expected_dir = DMA_DIRECTION_TO_DEVICE;
+    }
+
+    if (dir != expected_dir) {
+        trace_esp_pci_error_invalid_dma_direction();
+        return;
+    }
+
+    if (pci->dma_regs[DMA_STAT] & DMA_CMD_MDL) {
+        qemu_log_mask(LOG_UNIMP, "am53c974: MDL transfer not implemented\n");
+    }
+
+    addr = pci->dma_regs[DMA_SPA];
+    if (pci->dma_regs[DMA_WBC] < len) {
+        len = pci->dma_regs[DMA_WBC];
+    }
+
+    pci_dma_rw(&pci->dev, addr, buf, len, dir);
+
+    /* update status registers */
+    pci->dma_regs[DMA_WBC] -= len;
+    pci->dma_regs[DMA_WAC] += len;
+}
+
+static void esp_pci_dma_memory_read(void *opaque, uint8_t *buf, int len)
+{
+    PCIESPState *pci = opaque;
+    esp_pci_dma_memory_rw(pci, buf, len, DMA_DIRECTION_TO_DEVICE);
+}
+
+static void esp_pci_dma_memory_write(void *opaque, uint8_t *buf, int len)
+{
+    PCIESPState *pci = opaque;
+    esp_pci_dma_memory_rw(pci, buf, len, DMA_DIRECTION_FROM_DEVICE);
+}
+
+static const MemoryRegionOps esp_pci_io_ops = {
+    .read = esp_pci_io_read,
+    .write = esp_pci_io_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 4,
+    },
+};
+
+static void esp_pci_hard_reset(DeviceState *dev)
+{
+    PCIESPState *pci = DO_UPCAST(PCIESPState, dev.qdev, dev);
+    esp_hard_reset(&pci->esp);
+    pci->dma_regs[DMA_CMD] &= ~(DMA_CMD_DIR | DMA_CMD_INTE_D | DMA_CMD_INTE_P
+                              | DMA_CMD_MDL | DMA_CMD_DIAG | DMA_CMD_MASK);
+    pci->dma_regs[DMA_WBC] &= ~0xffff;
+    pci->dma_regs[DMA_WAC] = 0xffffffff;
+    pci->dma_regs[DMA_STAT] &= ~(DMA_STAT_BCMBLT | DMA_STAT_SCSIINT
+                               | DMA_STAT_DONE | DMA_STAT_ABORT
+                               | DMA_STAT_ERROR);
+    pci->dma_regs[DMA_WMAC] = 0xfffffffd;
+}
+
+static const VMStateDescription vmstate_esp_pci_scsi = {
+    .name = "pciespscsi",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields = (VMStateField[]) {
+        VMSTATE_PCI_DEVICE(dev, PCIESPState),
+        VMSTATE_BUFFER_UNSAFE(dma_regs, PCIESPState, 0, 8 * sizeof(uint32_t)),
+        VMSTATE_STRUCT(esp, PCIESPState, 0, vmstate_esp, ESPState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void esp_pci_command_complete(SCSIRequest *req, uint32_t status,
+                                     size_t resid)
+{
+    ESPState *s = req->hba_private;
+    PCIESPState *pci = container_of(s, PCIESPState, esp);
+
+    esp_command_complete(req, status, resid);
+    pci->dma_regs[DMA_WBC] = 0;
+    pci->dma_regs[DMA_STAT] |= DMA_STAT_DONE;
+}
+
+static const struct SCSIBusInfo esp_pci_scsi_info = {
+    .tcq = false,
+    .max_target = ESP_MAX_DEVS,
+    .max_lun = 7,
+
+    .transfer_data = esp_transfer_data,
+    .complete = esp_pci_command_complete,
+    .cancel = esp_request_cancelled,
+};
+
+static int esp_pci_scsi_init(PCIDevice *dev)
+{
+    PCIESPState *pci = DO_UPCAST(PCIESPState, dev, dev);
+    ESPState *s = &pci->esp;
+    uint8_t *pci_conf;
+
+    pci_conf = pci->dev.config;
+
+    /* Interrupt pin A */
+    pci_conf[PCI_INTERRUPT_PIN] = 0x01;
+
+    s->dma_memory_read = esp_pci_dma_memory_read;
+    s->dma_memory_write = esp_pci_dma_memory_write;
+    s->dma_opaque = pci;
+    s->chip_id = TCHI_AM53C974;
+    memory_region_init_io(&pci->io, &esp_pci_io_ops, pci, "esp-io", 0x80);
+
+    pci_register_bar(&pci->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &pci->io);
+    s->irq = pci->dev.irq[0];
+
+    scsi_bus_new(&s->bus, &dev->qdev, &esp_pci_scsi_info);
+    if (!dev->qdev.hotplugged) {
+        return scsi_bus_legacy_handle_cmdline(&s->bus);
+    }
+    return 0;
+}
+
+static void esp_pci_scsi_uninit(PCIDevice *d)
+{
+    PCIESPState *pci = DO_UPCAST(PCIESPState, dev, d);
+
+    memory_region_destroy(&pci->io);
+}
+
+static void esp_pci_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = esp_pci_scsi_init;
+    k->exit = esp_pci_scsi_uninit;
+    k->vendor_id = PCI_VENDOR_ID_AMD;
+    k->device_id = PCI_DEVICE_ID_AMD_SCSI;
+    k->revision = 0x10;
+    k->class_id = PCI_CLASS_STORAGE_SCSI;
+    dc->desc = "AMD Am53c974 PCscsi-PCI SCSI adapter";
+    dc->reset = esp_pci_hard_reset;
+    dc->vmsd = &vmstate_esp_pci_scsi;
+}
+
+static const TypeInfo esp_pci_info = {
+    .name = TYPE_AM53C974_DEVICE,
+    .parent = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PCIESPState),
+    .class_init = esp_pci_class_init,
+};
+
+typedef struct {
+    PCIESPState pci;
+    eeprom_t *eeprom;
+} DC390State;
+
+#define TYPE_DC390_DEVICE "dc390"
+#define DC390(obj) \
+    OBJECT_CHECK(DC390State, obj, TYPE_DC390_DEVICE)
+
+#define EE_ADAPT_SCSI_ID 64
+#define EE_MODE2         65
+#define EE_DELAY         66
+#define EE_TAG_CMD_NUM   67
+#define EE_ADAPT_OPTIONS 68
+#define EE_BOOT_SCSI_ID  69
+#define EE_BOOT_SCSI_LUN 70
+#define EE_CHKSUM1       126
+#define EE_CHKSUM2       127
+
+#define EE_ADAPT_OPTION_F6_F8_AT_BOOT   0x01
+#define EE_ADAPT_OPTION_BOOT_FROM_CDROM 0x02
+#define EE_ADAPT_OPTION_INT13           0x04
+#define EE_ADAPT_OPTION_SCAM_SUPPORT    0x08
+
+
+static uint32_t dc390_read_config(PCIDevice *dev, uint32_t addr, int l)
+{
+    DC390State *pci = DC390(dev);
+    uint32_t val;
+
+    val = pci_default_read_config(dev, addr, l);
+
+    if (addr == 0x00 && l == 1) {
+        /* First byte of address space is AND-ed with EEPROM DO line */
+        if (!eeprom93xx_read(pci->eeprom)) {
+            val &= ~0xff;
+        }
+    }
+
+    return val;
+}
+
+static void dc390_write_config(PCIDevice *dev,
+                               uint32_t addr, uint32_t val, int l)
+{
+    DC390State *pci = DC390(dev);
+    if (addr == 0x80) {
+        /* EEPROM write */
+        int eesk = val & 0x80 ? 1 : 0;
+        int eedi = val & 0x40 ? 1 : 0;
+        eeprom93xx_write(pci->eeprom, 1, eesk, eedi);
+    } else if (addr == 0xc0) {
+        /* EEPROM CS low */
+        eeprom93xx_write(pci->eeprom, 0, 0, 0);
+    } else {
+        pci_default_write_config(dev, addr, val, l);
+    }
+}
+
+static int dc390_scsi_init(PCIDevice *dev)
+{
+    DC390State *pci = DC390(dev);
+    uint8_t *contents;
+    uint16_t chksum = 0;
+    int i, ret;
+
+    /* init base class */
+    ret = esp_pci_scsi_init(dev);
+    if (ret < 0) {
+        return ret;
+    }
+
+    /* EEPROM */
+    pci->eeprom = eeprom93xx_new(DEVICE(dev), 64);
+
+    /* set default eeprom values */
+    contents = (uint8_t *)eeprom93xx_data(pci->eeprom);
+
+    for (i = 0; i < 16; i++) {
+        contents[i * 2] = 0x57;
+        contents[i * 2 + 1] = 0x00;
+    }
+    contents[EE_ADAPT_SCSI_ID] = 7;
+    contents[EE_MODE2] = 0x0f;
+    contents[EE_TAG_CMD_NUM] = 0x04;
+    contents[EE_ADAPT_OPTIONS] = EE_ADAPT_OPTION_F6_F8_AT_BOOT
+                               | EE_ADAPT_OPTION_BOOT_FROM_CDROM
+                               | EE_ADAPT_OPTION_INT13;
+
+    /* update eeprom checksum */
+    for (i = 0; i < EE_CHKSUM1; i += 2) {
+        chksum += contents[i] + (((uint16_t)contents[i + 1]) << 8);
+    }
+    chksum = 0x1234 - chksum;
+    contents[EE_CHKSUM1] = chksum & 0xff;
+    contents[EE_CHKSUM2] = chksum >> 8;
+
+    return 0;
+}
+
+static void dc390_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = dc390_scsi_init;
+    k->config_read = dc390_read_config;
+    k->config_write = dc390_write_config;
+    dc->desc = "Tekram DC-390 SCSI adapter";
+}
+
+static const TypeInfo dc390_info = {
+    .name = "dc390",
+    .parent = TYPE_AM53C974_DEVICE,
+    .instance_size = sizeof(DC390State),
+    .class_init = dc390_class_init,
+};
+
+static void esp_pci_register_types(void)
+{
+    type_register_static(&esp_pci_info);
+    type_register_static(&dc390_info);
+}
+
+type_init(esp_pci_register_types)
diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
new file mode 100644 (file)
index 0000000..17adbec
--- /dev/null
@@ -0,0 +1,727 @@
+/*
+ * QEMU ESP/NCR53C9x emulation
+ *
+ * Copyright (c) 2005-2006 Fabrice Bellard
+ * Copyright (c) 2012 Herve 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 "hw/sysbus.h"
+#include "hw/scsi/esp.h"
+#include "trace.h"
+#include "qemu/log.h"
+
+/*
+ * On Sparc32, this is the ESP (NCR53C90) part of chip STP2000 (Master I/O),
+ * also produced as NCR89C100. See
+ * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C100.txt
+ * and
+ * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR53C9X.txt
+ */
+
+static void esp_raise_irq(ESPState *s)
+{
+    if (!(s->rregs[ESP_RSTAT] & STAT_INT)) {
+        s->rregs[ESP_RSTAT] |= STAT_INT;
+        qemu_irq_raise(s->irq);
+        trace_esp_raise_irq();
+    }
+}
+
+static void esp_lower_irq(ESPState *s)
+{
+    if (s->rregs[ESP_RSTAT] & STAT_INT) {
+        s->rregs[ESP_RSTAT] &= ~STAT_INT;
+        qemu_irq_lower(s->irq);
+        trace_esp_lower_irq();
+    }
+}
+
+void esp_dma_enable(ESPState *s, int irq, int level)
+{
+    if (level) {
+        s->dma_enabled = 1;
+        trace_esp_dma_enable();
+        if (s->dma_cb) {
+            s->dma_cb(s);
+            s->dma_cb = NULL;
+        }
+    } else {
+        trace_esp_dma_disable();
+        s->dma_enabled = 0;
+    }
+}
+
+void esp_request_cancelled(SCSIRequest *req)
+{
+    ESPState *s = req->hba_private;
+
+    if (req == s->current_req) {
+        scsi_req_unref(s->current_req);
+        s->current_req = NULL;
+        s->current_dev = NULL;
+    }
+}
+
+static uint32_t get_cmd(ESPState *s, uint8_t *buf)
+{
+    uint32_t dmalen;
+    int target;
+
+    target = s->wregs[ESP_WBUSID] & BUSID_DID;
+    if (s->dma) {
+        dmalen = s->rregs[ESP_TCLO];
+        dmalen |= s->rregs[ESP_TCMID] << 8;
+        dmalen |= s->rregs[ESP_TCHI] << 16;
+        s->dma_memory_read(s->dma_opaque, buf, dmalen);
+    } else {
+        dmalen = s->ti_size;
+        memcpy(buf, s->ti_buf, dmalen);
+        buf[0] = buf[2] >> 5;
+    }
+    trace_esp_get_cmd(dmalen, target);
+
+    s->ti_size = 0;
+    s->ti_rptr = 0;
+    s->ti_wptr = 0;
+
+    if (s->current_req) {
+        /* Started a new command before the old one finished.  Cancel it.  */
+        scsi_req_cancel(s->current_req);
+        s->async_len = 0;
+    }
+
+    s->current_dev = scsi_device_find(&s->bus, 0, target, 0);
+    if (!s->current_dev) {
+        // No such drive
+        s->rregs[ESP_RSTAT] = 0;
+        s->rregs[ESP_RINTR] = INTR_DC;
+        s->rregs[ESP_RSEQ] = SEQ_0;
+        esp_raise_irq(s);
+        return 0;
+    }
+    return dmalen;
+}
+
+static void do_busid_cmd(ESPState *s, uint8_t *buf, uint8_t busid)
+{
+    int32_t datalen;
+    int lun;
+    SCSIDevice *current_lun;
+
+    trace_esp_do_busid_cmd(busid);
+    lun = busid & 7;
+    current_lun = scsi_device_find(&s->bus, 0, s->current_dev->id, lun);
+    s->current_req = scsi_req_new(current_lun, 0, lun, buf, s);
+    datalen = scsi_req_enqueue(s->current_req);
+    s->ti_size = datalen;
+    if (datalen != 0) {
+        s->rregs[ESP_RSTAT] = STAT_TC;
+        s->dma_left = 0;
+        s->dma_counter = 0;
+        if (datalen > 0) {
+            s->rregs[ESP_RSTAT] |= STAT_DI;
+        } else {
+            s->rregs[ESP_RSTAT] |= STAT_DO;
+        }
+        scsi_req_continue(s->current_req);
+    }
+    s->rregs[ESP_RINTR] = INTR_BS | INTR_FC;
+    s->rregs[ESP_RSEQ] = SEQ_CD;
+    esp_raise_irq(s);
+}
+
+static void do_cmd(ESPState *s, uint8_t *buf)
+{
+    uint8_t busid = buf[0];
+
+    do_busid_cmd(s, &buf[1], busid);
+}
+
+static void handle_satn(ESPState *s)
+{
+    uint8_t buf[32];
+    int len;
+
+    if (s->dma && !s->dma_enabled) {
+        s->dma_cb = handle_satn;
+        return;
+    }
+    len = get_cmd(s, buf);
+    if (len)
+        do_cmd(s, buf);
+}
+
+static void handle_s_without_atn(ESPState *s)
+{
+    uint8_t buf[32];
+    int len;
+
+    if (s->dma && !s->dma_enabled) {
+        s->dma_cb = handle_s_without_atn;
+        return;
+    }
+    len = get_cmd(s, buf);
+    if (len) {
+        do_busid_cmd(s, buf, 0);
+    }
+}
+
+static void handle_satn_stop(ESPState *s)
+{
+    if (s->dma && !s->dma_enabled) {
+        s->dma_cb = handle_satn_stop;
+        return;
+    }
+    s->cmdlen = get_cmd(s, s->cmdbuf);
+    if (s->cmdlen) {
+        trace_esp_handle_satn_stop(s->cmdlen);
+        s->do_cmd = 1;
+        s->rregs[ESP_RSTAT] = STAT_TC | STAT_CD;
+        s->rregs[ESP_RINTR] = INTR_BS | INTR_FC;
+        s->rregs[ESP_RSEQ] = SEQ_CD;
+        esp_raise_irq(s);
+    }
+}
+
+static void write_response(ESPState *s)
+{
+    trace_esp_write_response(s->status);
+    s->ti_buf[0] = s->status;
+    s->ti_buf[1] = 0;
+    if (s->dma) {
+        s->dma_memory_write(s->dma_opaque, s->ti_buf, 2);
+        s->rregs[ESP_RSTAT] = STAT_TC | STAT_ST;
+        s->rregs[ESP_RINTR] = INTR_BS | INTR_FC;
+        s->rregs[ESP_RSEQ] = SEQ_CD;
+    } else {
+        s->ti_size = 2;
+        s->ti_rptr = 0;
+        s->ti_wptr = 0;
+        s->rregs[ESP_RFLAGS] = 2;
+    }
+    esp_raise_irq(s);
+}
+
+static void esp_dma_done(ESPState *s)
+{
+    s->rregs[ESP_RSTAT] |= STAT_TC;
+    s->rregs[ESP_RINTR] = INTR_BS;
+    s->rregs[ESP_RSEQ] = 0;
+    s->rregs[ESP_RFLAGS] = 0;
+    s->rregs[ESP_TCLO] = 0;
+    s->rregs[ESP_TCMID] = 0;
+    s->rregs[ESP_TCHI] = 0;
+    esp_raise_irq(s);
+}
+
+static void esp_do_dma(ESPState *s)
+{
+    uint32_t len;
+    int to_device;
+
+    to_device = (s->ti_size < 0);
+    len = s->dma_left;
+    if (s->do_cmd) {
+        trace_esp_do_dma(s->cmdlen, len);
+        s->dma_memory_read(s->dma_opaque, &s->cmdbuf[s->cmdlen], len);
+        s->ti_size = 0;
+        s->cmdlen = 0;
+        s->do_cmd = 0;
+        do_cmd(s, s->cmdbuf);
+        return;
+    }
+    if (s->async_len == 0) {
+        /* Defer until data is available.  */
+        return;
+    }
+    if (len > s->async_len) {
+        len = s->async_len;
+    }
+    if (to_device) {
+        s->dma_memory_read(s->dma_opaque, s->async_buf, len);
+    } else {
+        s->dma_memory_write(s->dma_opaque, s->async_buf, len);
+    }
+    s->dma_left -= len;
+    s->async_buf += len;
+    s->async_len -= len;
+    if (to_device)
+        s->ti_size += len;
+    else
+        s->ti_size -= len;
+    if (s->async_len == 0) {
+        scsi_req_continue(s->current_req);
+        /* If there is still data to be read from the device then
+           complete the DMA operation immediately.  Otherwise defer
+           until the scsi layer has completed.  */
+        if (to_device || s->dma_left != 0 || s->ti_size == 0) {
+            return;
+        }
+    }
+
+    /* Partially filled a scsi buffer. Complete immediately.  */
+    esp_dma_done(s);
+}
+
+void esp_command_complete(SCSIRequest *req, uint32_t status,
+                                 size_t resid)
+{
+    ESPState *s = req->hba_private;
+
+    trace_esp_command_complete();
+    if (s->ti_size != 0) {
+        trace_esp_command_complete_unexpected();
+    }
+    s->ti_size = 0;
+    s->dma_left = 0;
+    s->async_len = 0;
+    if (status) {
+        trace_esp_command_complete_fail();
+    }
+    s->status = status;
+    s->rregs[ESP_RSTAT] = STAT_ST;
+    esp_dma_done(s);
+    if (s->current_req) {
+        scsi_req_unref(s->current_req);
+        s->current_req = NULL;
+        s->current_dev = NULL;
+    }
+}
+
+void esp_transfer_data(SCSIRequest *req, uint32_t len)
+{
+    ESPState *s = req->hba_private;
+
+    trace_esp_transfer_data(s->dma_left, s->ti_size);
+    s->async_len = len;
+    s->async_buf = scsi_req_get_buf(req);
+    if (s->dma_left) {
+        esp_do_dma(s);
+    } else if (s->dma_counter != 0 && s->ti_size <= 0) {
+        /* If this was the last part of a DMA transfer then the
+           completion interrupt is deferred to here.  */
+        esp_dma_done(s);
+    }
+}
+
+static void handle_ti(ESPState *s)
+{
+    uint32_t dmalen, minlen;
+
+    if (s->dma && !s->dma_enabled) {
+        s->dma_cb = handle_ti;
+        return;
+    }
+
+    dmalen = s->rregs[ESP_TCLO];
+    dmalen |= s->rregs[ESP_TCMID] << 8;
+    dmalen |= s->rregs[ESP_TCHI] << 16;
+    if (dmalen==0) {
+      dmalen=0x10000;
+    }
+    s->dma_counter = dmalen;
+
+    if (s->do_cmd)
+        minlen = (dmalen < 32) ? dmalen : 32;
+    else if (s->ti_size < 0)
+        minlen = (dmalen < -s->ti_size) ? dmalen : -s->ti_size;
+    else
+        minlen = (dmalen < s->ti_size) ? dmalen : s->ti_size;
+    trace_esp_handle_ti(minlen);
+    if (s->dma) {
+        s->dma_left = minlen;
+        s->rregs[ESP_RSTAT] &= ~STAT_TC;
+        esp_do_dma(s);
+    } else if (s->do_cmd) {
+        trace_esp_handle_ti_cmd(s->cmdlen);
+        s->ti_size = 0;
+        s->cmdlen = 0;
+        s->do_cmd = 0;
+        do_cmd(s, s->cmdbuf);
+        return;
+    }
+}
+
+void esp_hard_reset(ESPState *s)
+{
+    memset(s->rregs, 0, ESP_REGS);
+    memset(s->wregs, 0, ESP_REGS);
+    s->rregs[ESP_TCHI] = s->chip_id;
+    s->ti_size = 0;
+    s->ti_rptr = 0;
+    s->ti_wptr = 0;
+    s->dma = 0;
+    s->do_cmd = 0;
+    s->dma_cb = NULL;
+
+    s->rregs[ESP_CFG1] = 7;
+}
+
+static void esp_soft_reset(ESPState *s)
+{
+    qemu_irq_lower(s->irq);
+    esp_hard_reset(s);
+}
+
+static void parent_esp_reset(ESPState *s, int irq, int level)
+{
+    if (level) {
+        esp_soft_reset(s);
+    }
+}
+
+uint64_t esp_reg_read(ESPState *s, uint32_t saddr)
+{
+    uint32_t old_val;
+
+    trace_esp_mem_readb(saddr, s->rregs[saddr]);
+    switch (saddr) {
+    case ESP_FIFO:
+        if (s->ti_size > 0) {
+            s->ti_size--;
+            if ((s->rregs[ESP_RSTAT] & STAT_PIO_MASK) == 0) {
+                /* Data out.  */
+                qemu_log_mask(LOG_UNIMP,
+                              "esp: PIO data read not implemented\n");
+                s->rregs[ESP_FIFO] = 0;
+            } else {
+                s->rregs[ESP_FIFO] = s->ti_buf[s->ti_rptr++];
+            }
+            esp_raise_irq(s);
+        }
+        if (s->ti_size == 0) {
+            s->ti_rptr = 0;
+            s->ti_wptr = 0;
+        }
+        break;
+    case ESP_RINTR:
+        /* Clear sequence step, interrupt register and all status bits
+           except TC */
+        old_val = s->rregs[ESP_RINTR];
+        s->rregs[ESP_RINTR] = 0;
+        s->rregs[ESP_RSTAT] &= ~STAT_TC;
+        s->rregs[ESP_RSEQ] = SEQ_CD;
+        esp_lower_irq(s);
+
+        return old_val;
+    default:
+        break;
+    }
+    return s->rregs[saddr];
+}
+
+void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val)
+{
+    trace_esp_mem_writeb(saddr, s->wregs[saddr], val);
+    switch (saddr) {
+    case ESP_TCLO:
+    case ESP_TCMID:
+    case ESP_TCHI:
+        s->rregs[ESP_RSTAT] &= ~STAT_TC;
+        break;
+    case ESP_FIFO:
+        if (s->do_cmd) {
+            s->cmdbuf[s->cmdlen++] = val & 0xff;
+        } else if (s->ti_size == TI_BUFSZ - 1) {
+            trace_esp_error_fifo_overrun();
+        } else {
+            s->ti_size++;
+            s->ti_buf[s->ti_wptr++] = val & 0xff;
+        }
+        break;
+    case ESP_CMD:
+        s->rregs[saddr] = val;
+        if (val & CMD_DMA) {
+            s->dma = 1;
+            /* Reload DMA counter.  */
+            s->rregs[ESP_TCLO] = s->wregs[ESP_TCLO];
+            s->rregs[ESP_TCMID] = s->wregs[ESP_TCMID];
+            s->rregs[ESP_TCHI] = s->wregs[ESP_TCHI];
+        } else {
+            s->dma = 0;
+        }
+        switch(val & CMD_CMD) {
+        case CMD_NOP:
+            trace_esp_mem_writeb_cmd_nop(val);
+            break;
+        case CMD_FLUSH:
+            trace_esp_mem_writeb_cmd_flush(val);
+            //s->ti_size = 0;
+            s->rregs[ESP_RINTR] = INTR_FC;
+            s->rregs[ESP_RSEQ] = 0;
+            s->rregs[ESP_RFLAGS] = 0;
+            break;
+        case CMD_RESET:
+            trace_esp_mem_writeb_cmd_reset(val);
+            esp_soft_reset(s);
+            break;
+        case CMD_BUSRESET:
+            trace_esp_mem_writeb_cmd_bus_reset(val);
+            s->rregs[ESP_RINTR] = INTR_RST;
+            if (!(s->wregs[ESP_CFG1] & CFG1_RESREPT)) {
+                esp_raise_irq(s);
+            }
+            break;
+        case CMD_TI:
+            handle_ti(s);
+            break;
+        case CMD_ICCS:
+            trace_esp_mem_writeb_cmd_iccs(val);
+            write_response(s);
+            s->rregs[ESP_RINTR] = INTR_FC;
+            s->rregs[ESP_RSTAT] |= STAT_MI;
+            break;
+        case CMD_MSGACC:
+            trace_esp_mem_writeb_cmd_msgacc(val);
+            s->rregs[ESP_RINTR] = INTR_DC;
+            s->rregs[ESP_RSEQ] = 0;
+            s->rregs[ESP_RFLAGS] = 0;
+            esp_raise_irq(s);
+            break;
+        case CMD_PAD:
+            trace_esp_mem_writeb_cmd_pad(val);
+            s->rregs[ESP_RSTAT] = STAT_TC;
+            s->rregs[ESP_RINTR] = INTR_FC;
+            s->rregs[ESP_RSEQ] = 0;
+            break;
+        case CMD_SATN:
+            trace_esp_mem_writeb_cmd_satn(val);
+            break;
+        case CMD_RSTATN:
+            trace_esp_mem_writeb_cmd_rstatn(val);
+            break;
+        case CMD_SEL:
+            trace_esp_mem_writeb_cmd_sel(val);
+            handle_s_without_atn(s);
+            break;
+        case CMD_SELATN:
+            trace_esp_mem_writeb_cmd_selatn(val);
+            handle_satn(s);
+            break;
+        case CMD_SELATNS:
+            trace_esp_mem_writeb_cmd_selatns(val);
+            handle_satn_stop(s);
+            break;
+        case CMD_ENSEL:
+            trace_esp_mem_writeb_cmd_ensel(val);
+            s->rregs[ESP_RINTR] = 0;
+            break;
+        case CMD_DISSEL:
+            trace_esp_mem_writeb_cmd_dissel(val);
+            s->rregs[ESP_RINTR] = 0;
+            esp_raise_irq(s);
+            break;
+        default:
+            trace_esp_error_unhandled_command(val);
+            break;
+        }
+        break;
+    case ESP_WBUSID ... ESP_WSYNO:
+        break;
+    case ESP_CFG1:
+    case ESP_CFG2: case ESP_CFG3:
+    case ESP_RES3: case ESP_RES4:
+        s->rregs[saddr] = val;
+        break;
+    case ESP_WCCF ... ESP_WTEST:
+        break;
+    default:
+        trace_esp_error_invalid_write(val, saddr);
+        return;
+    }
+    s->wregs[saddr] = val;
+}
+
+static bool esp_mem_accepts(void *opaque, hwaddr addr,
+                            unsigned size, bool is_write)
+{
+    return (size == 1) || (is_write && size == 4);
+}
+
+const VMStateDescription vmstate_esp = {
+    .name ="esp",
+    .version_id = 3,
+    .minimum_version_id = 3,
+    .minimum_version_id_old = 3,
+    .fields      = (VMStateField []) {
+        VMSTATE_BUFFER(rregs, ESPState),
+        VMSTATE_BUFFER(wregs, ESPState),
+        VMSTATE_INT32(ti_size, ESPState),
+        VMSTATE_UINT32(ti_rptr, ESPState),
+        VMSTATE_UINT32(ti_wptr, ESPState),
+        VMSTATE_BUFFER(ti_buf, ESPState),
+        VMSTATE_UINT32(status, ESPState),
+        VMSTATE_UINT32(dma, ESPState),
+        VMSTATE_BUFFER(cmdbuf, ESPState),
+        VMSTATE_UINT32(cmdlen, ESPState),
+        VMSTATE_UINT32(do_cmd, ESPState),
+        VMSTATE_UINT32(dma_left, ESPState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+typedef struct {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    uint32_t it_shift;
+    ESPState esp;
+} SysBusESPState;
+
+static void sysbus_esp_mem_write(void *opaque, hwaddr addr,
+                                 uint64_t val, unsigned int size)
+{
+    SysBusESPState *sysbus = opaque;
+    uint32_t saddr;
+
+    saddr = addr >> sysbus->it_shift;
+    esp_reg_write(&sysbus->esp, saddr, val);
+}
+
+static uint64_t sysbus_esp_mem_read(void *opaque, hwaddr addr,
+                                    unsigned int size)
+{
+    SysBusESPState *sysbus = opaque;
+    uint32_t saddr;
+
+    saddr = addr >> sysbus->it_shift;
+    return esp_reg_read(&sysbus->esp, saddr);
+}
+
+static const MemoryRegionOps sysbus_esp_mem_ops = {
+    .read = sysbus_esp_mem_read,
+    .write = sysbus_esp_mem_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid.accepts = esp_mem_accepts,
+};
+
+void esp_init(hwaddr espaddr, int it_shift,
+              ESPDMAMemoryReadWriteFunc dma_memory_read,
+              ESPDMAMemoryReadWriteFunc dma_memory_write,
+              void *dma_opaque, qemu_irq irq, qemu_irq *reset,
+              qemu_irq *dma_enable)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+    SysBusESPState *sysbus;
+    ESPState *esp;
+
+    dev = qdev_create(NULL, "esp");
+    sysbus = DO_UPCAST(SysBusESPState, busdev.qdev, dev);
+    esp = &sysbus->esp;
+    esp->dma_memory_read = dma_memory_read;
+    esp->dma_memory_write = dma_memory_write;
+    esp->dma_opaque = dma_opaque;
+    sysbus->it_shift = it_shift;
+    /* XXX for now until rc4030 has been changed to use DMA enable signal */
+    esp->dma_enabled = 1;
+    qdev_init_nofail(dev);
+    s = SYS_BUS_DEVICE(dev);
+    sysbus_connect_irq(s, 0, irq);
+    sysbus_mmio_map(s, 0, espaddr);
+    *reset = qdev_get_gpio_in(dev, 0);
+    *dma_enable = qdev_get_gpio_in(dev, 1);
+}
+
+static const struct SCSIBusInfo esp_scsi_info = {
+    .tcq = false,
+    .max_target = ESP_MAX_DEVS,
+    .max_lun = 7,
+
+    .transfer_data = esp_transfer_data,
+    .complete = esp_command_complete,
+    .cancel = esp_request_cancelled
+};
+
+static void sysbus_esp_gpio_demux(void *opaque, int irq, int level)
+{
+    DeviceState *d = opaque;
+    SysBusESPState *sysbus = container_of(d, SysBusESPState, busdev.qdev);
+    ESPState *s = &sysbus->esp;
+
+    switch (irq) {
+    case 0:
+        parent_esp_reset(s, irq, level);
+        break;
+    case 1:
+        esp_dma_enable(opaque, irq, level);
+        break;
+    }
+}
+
+static int sysbus_esp_init(SysBusDevice *dev)
+{
+    SysBusESPState *sysbus = FROM_SYSBUS(SysBusESPState, dev);
+    ESPState *s = &sysbus->esp;
+
+    sysbus_init_irq(dev, &s->irq);
+    assert(sysbus->it_shift != -1);
+
+    s->chip_id = TCHI_FAS100A;
+    memory_region_init_io(&sysbus->iomem, &sysbus_esp_mem_ops, sysbus,
+                          "esp", ESP_REGS << sysbus->it_shift);
+    sysbus_init_mmio(dev, &sysbus->iomem);
+
+    qdev_init_gpio_in(&dev->qdev, sysbus_esp_gpio_demux, 2);
+
+    scsi_bus_new(&s->bus, &dev->qdev, &esp_scsi_info);
+    return scsi_bus_legacy_handle_cmdline(&s->bus);
+}
+
+static void sysbus_esp_hard_reset(DeviceState *dev)
+{
+    SysBusESPState *sysbus = DO_UPCAST(SysBusESPState, busdev.qdev, dev);
+    esp_hard_reset(&sysbus->esp);
+}
+
+static const VMStateDescription vmstate_sysbus_esp_scsi = {
+    .name = "sysbusespscsi",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields = (VMStateField[]) {
+        VMSTATE_STRUCT(esp, SysBusESPState, 0, vmstate_esp, ESPState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void sysbus_esp_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = sysbus_esp_init;
+    dc->reset = sysbus_esp_hard_reset;
+    dc->vmsd = &vmstate_sysbus_esp_scsi;
+}
+
+static const TypeInfo sysbus_esp_info = {
+    .name          = "esp",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(SysBusESPState),
+    .class_init    = sysbus_esp_class_init,
+};
+
+static void esp_register_types(void)
+{
+    type_register_static(&sysbus_esp_info);
+}
+
+type_init(esp_register_types)
diff --git a/hw/scsi/lsi53c895a.c b/hw/scsi/lsi53c895a.c
new file mode 100644 (file)
index 0000000..c601b29
--- /dev/null
@@ -0,0 +1,2136 @@
+/*
+ * QEMU LSI53C895A SCSI Host Bus Adapter emulation
+ *
+ * Copyright (c) 2006 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the LGPL.
+ */
+
+/* ??? Need to check if the {read,write}[wl] routines work properly on
+   big-endian targets.  */
+
+#include <assert.h>
+
+#include "hw/hw.h"
+#include "hw/pci/pci.h"
+#include "hw/scsi/scsi.h"
+#include "sysemu/dma.h"
+
+//#define DEBUG_LSI
+//#define DEBUG_LSI_REG
+
+#ifdef DEBUG_LSI
+#define DPRINTF(fmt, ...) \
+do { printf("lsi_scsi: " fmt , ## __VA_ARGS__); } while (0)
+#define BADF(fmt, ...) \
+do { fprintf(stderr, "lsi_scsi: error: " fmt , ## __VA_ARGS__); exit(1);} while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while(0)
+#define BADF(fmt, ...) \
+do { fprintf(stderr, "lsi_scsi: error: " fmt , ## __VA_ARGS__);} while (0)
+#endif
+
+#define LSI_MAX_DEVS 7
+
+#define LSI_SCNTL0_TRG    0x01
+#define LSI_SCNTL0_AAP    0x02
+#define LSI_SCNTL0_EPC    0x08
+#define LSI_SCNTL0_WATN   0x10
+#define LSI_SCNTL0_START  0x20
+
+#define LSI_SCNTL1_SST    0x01
+#define LSI_SCNTL1_IARB   0x02
+#define LSI_SCNTL1_AESP   0x04
+#define LSI_SCNTL1_RST    0x08
+#define LSI_SCNTL1_CON    0x10
+#define LSI_SCNTL1_DHP    0x20
+#define LSI_SCNTL1_ADB    0x40
+#define LSI_SCNTL1_EXC    0x80
+
+#define LSI_SCNTL2_WSR    0x01
+#define LSI_SCNTL2_VUE0   0x02
+#define LSI_SCNTL2_VUE1   0x04
+#define LSI_SCNTL2_WSS    0x08
+#define LSI_SCNTL2_SLPHBEN 0x10
+#define LSI_SCNTL2_SLPMD  0x20
+#define LSI_SCNTL2_CHM    0x40
+#define LSI_SCNTL2_SDU    0x80
+
+#define LSI_ISTAT0_DIP    0x01
+#define LSI_ISTAT0_SIP    0x02
+#define LSI_ISTAT0_INTF   0x04
+#define LSI_ISTAT0_CON    0x08
+#define LSI_ISTAT0_SEM    0x10
+#define LSI_ISTAT0_SIGP   0x20
+#define LSI_ISTAT0_SRST   0x40
+#define LSI_ISTAT0_ABRT   0x80
+
+#define LSI_ISTAT1_SI     0x01
+#define LSI_ISTAT1_SRUN   0x02
+#define LSI_ISTAT1_FLSH   0x04
+
+#define LSI_SSTAT0_SDP0   0x01
+#define LSI_SSTAT0_RST    0x02
+#define LSI_SSTAT0_WOA    0x04
+#define LSI_SSTAT0_LOA    0x08
+#define LSI_SSTAT0_AIP    0x10
+#define LSI_SSTAT0_OLF    0x20
+#define LSI_SSTAT0_ORF    0x40
+#define LSI_SSTAT0_ILF    0x80
+
+#define LSI_SIST0_PAR     0x01
+#define LSI_SIST0_RST     0x02
+#define LSI_SIST0_UDC     0x04
+#define LSI_SIST0_SGE     0x08
+#define LSI_SIST0_RSL     0x10
+#define LSI_SIST0_SEL     0x20
+#define LSI_SIST0_CMP     0x40
+#define LSI_SIST0_MA      0x80
+
+#define LSI_SIST1_HTH     0x01
+#define LSI_SIST1_GEN     0x02
+#define LSI_SIST1_STO     0x04
+#define LSI_SIST1_SBMC    0x10
+
+#define LSI_SOCL_IO       0x01
+#define LSI_SOCL_CD       0x02
+#define LSI_SOCL_MSG      0x04
+#define LSI_SOCL_ATN      0x08
+#define LSI_SOCL_SEL      0x10
+#define LSI_SOCL_BSY      0x20
+#define LSI_SOCL_ACK      0x40
+#define LSI_SOCL_REQ      0x80
+
+#define LSI_DSTAT_IID     0x01
+#define LSI_DSTAT_SIR     0x04
+#define LSI_DSTAT_SSI     0x08
+#define LSI_DSTAT_ABRT    0x10
+#define LSI_DSTAT_BF      0x20
+#define LSI_DSTAT_MDPE    0x40
+#define LSI_DSTAT_DFE     0x80
+
+#define LSI_DCNTL_COM     0x01
+#define LSI_DCNTL_IRQD    0x02
+#define LSI_DCNTL_STD     0x04
+#define LSI_DCNTL_IRQM    0x08
+#define LSI_DCNTL_SSM     0x10
+#define LSI_DCNTL_PFEN    0x20
+#define LSI_DCNTL_PFF     0x40
+#define LSI_DCNTL_CLSE    0x80
+
+#define LSI_DMODE_MAN     0x01
+#define LSI_DMODE_BOF     0x02
+#define LSI_DMODE_ERMP    0x04
+#define LSI_DMODE_ERL     0x08
+#define LSI_DMODE_DIOM    0x10
+#define LSI_DMODE_SIOM    0x20
+
+#define LSI_CTEST2_DACK   0x01
+#define LSI_CTEST2_DREQ   0x02
+#define LSI_CTEST2_TEOP   0x04
+#define LSI_CTEST2_PCICIE 0x08
+#define LSI_CTEST2_CM     0x10
+#define LSI_CTEST2_CIO    0x20
+#define LSI_CTEST2_SIGP   0x40
+#define LSI_CTEST2_DDIR   0x80
+
+#define LSI_CTEST5_BL2    0x04
+#define LSI_CTEST5_DDIR   0x08
+#define LSI_CTEST5_MASR   0x10
+#define LSI_CTEST5_DFSN   0x20
+#define LSI_CTEST5_BBCK   0x40
+#define LSI_CTEST5_ADCK   0x80
+
+#define LSI_CCNTL0_DILS   0x01
+#define LSI_CCNTL0_DISFC  0x10
+#define LSI_CCNTL0_ENNDJ  0x20
+#define LSI_CCNTL0_PMJCTL 0x40
+#define LSI_CCNTL0_ENPMJ  0x80
+
+#define LSI_CCNTL1_EN64DBMV  0x01
+#define LSI_CCNTL1_EN64TIBMV 0x02
+#define LSI_CCNTL1_64TIMOD   0x04
+#define LSI_CCNTL1_DDAC      0x08
+#define LSI_CCNTL1_ZMOD      0x80
+
+/* Enable Response to Reselection */
+#define LSI_SCID_RRE      0x60
+
+#define LSI_CCNTL1_40BIT (LSI_CCNTL1_EN64TIBMV|LSI_CCNTL1_64TIMOD)
+
+#define PHASE_DO          0
+#define PHASE_DI          1
+#define PHASE_CMD         2
+#define PHASE_ST          3
+#define PHASE_MO          6
+#define PHASE_MI          7
+#define PHASE_MASK        7
+
+/* Maximum length of MSG IN data.  */
+#define LSI_MAX_MSGIN_LEN 8
+
+/* Flag set if this is a tagged command.  */
+#define LSI_TAG_VALID     (1 << 16)
+
+typedef struct lsi_request {
+    SCSIRequest *req;
+    uint32_t tag;
+    uint32_t dma_len;
+    uint8_t *dma_buf;
+    uint32_t pending;
+    int out;
+    QTAILQ_ENTRY(lsi_request) next;
+} lsi_request;
+
+typedef struct {
+    PCIDevice dev;
+    MemoryRegion mmio_io;
+    MemoryRegion ram_io;
+    MemoryRegion io_io;
+
+    int carry; /* ??? Should this be an a visible register somewhere?  */
+    int status;
+    /* Action to take at the end of a MSG IN phase.
+       0 = COMMAND, 1 = disconnect, 2 = DATA OUT, 3 = DATA IN.  */
+    int msg_action;
+    int msg_len;
+    uint8_t msg[LSI_MAX_MSGIN_LEN];
+    /* 0 if SCRIPTS are running or stopped.
+     * 1 if a Wait Reselect instruction has been issued.
+     * 2 if processing DMA from lsi_execute_script.
+     * 3 if a DMA operation is in progress.  */
+    int waiting;
+    SCSIBus bus;
+    int current_lun;
+    /* The tag is a combination of the device ID and the SCSI tag.  */
+    uint32_t select_tag;
+    int command_complete;
+    QTAILQ_HEAD(, lsi_request) queue;
+    lsi_request *current;
+
+    uint32_t dsa;
+    uint32_t temp;
+    uint32_t dnad;
+    uint32_t dbc;
+    uint8_t istat0;
+    uint8_t istat1;
+    uint8_t dcmd;
+    uint8_t dstat;
+    uint8_t dien;
+    uint8_t sist0;
+    uint8_t sist1;
+    uint8_t sien0;
+    uint8_t sien1;
+    uint8_t mbox0;
+    uint8_t mbox1;
+    uint8_t dfifo;
+    uint8_t ctest2;
+    uint8_t ctest3;
+    uint8_t ctest4;
+    uint8_t ctest5;
+    uint8_t ccntl0;
+    uint8_t ccntl1;
+    uint32_t dsp;
+    uint32_t dsps;
+    uint8_t dmode;
+    uint8_t dcntl;
+    uint8_t scntl0;
+    uint8_t scntl1;
+    uint8_t scntl2;
+    uint8_t scntl3;
+    uint8_t sstat0;
+    uint8_t sstat1;
+    uint8_t scid;
+    uint8_t sxfer;
+    uint8_t socl;
+    uint8_t sdid;
+    uint8_t ssid;
+    uint8_t sfbr;
+    uint8_t stest1;
+    uint8_t stest2;
+    uint8_t stest3;
+    uint8_t sidl;
+    uint8_t stime0;
+    uint8_t respid0;
+    uint8_t respid1;
+    uint32_t mmrs;
+    uint32_t mmws;
+    uint32_t sfs;
+    uint32_t drs;
+    uint32_t sbms;
+    uint32_t dbms;
+    uint32_t dnad64;
+    uint32_t pmjad1;
+    uint32_t pmjad2;
+    uint32_t rbc;
+    uint32_t ua;
+    uint32_t ia;
+    uint32_t sbc;
+    uint32_t csbc;
+    uint32_t scratch[18]; /* SCRATCHA-SCRATCHR */
+    uint8_t sbr;
+
+    /* Script ram is stored as 32-bit words in host byteorder.  */
+    uint32_t script_ram[2048];
+} LSIState;
+
+static inline int lsi_irq_on_rsl(LSIState *s)
+{
+    return (s->sien0 & LSI_SIST0_RSL) && (s->scid & LSI_SCID_RRE);
+}
+
+static void lsi_soft_reset(LSIState *s)
+{
+    DPRINTF("Reset\n");
+    s->carry = 0;
+
+    s->msg_action = 0;
+    s->msg_len = 0;
+    s->waiting = 0;
+    s->dsa = 0;
+    s->dnad = 0;
+    s->dbc = 0;
+    s->temp = 0;
+    memset(s->scratch, 0, sizeof(s->scratch));
+    s->istat0 = 0;
+    s->istat1 = 0;
+    s->dcmd = 0x40;
+    s->dstat = LSI_DSTAT_DFE;
+    s->dien = 0;
+    s->sist0 = 0;
+    s->sist1 = 0;
+    s->sien0 = 0;
+    s->sien1 = 0;
+    s->mbox0 = 0;
+    s->mbox1 = 0;
+    s->dfifo = 0;
+    s->ctest2 = LSI_CTEST2_DACK;
+    s->ctest3 = 0;
+    s->ctest4 = 0;
+    s->ctest5 = 0;
+    s->ccntl0 = 0;
+    s->ccntl1 = 0;
+    s->dsp = 0;
+    s->dsps = 0;
+    s->dmode = 0;
+    s->dcntl = 0;
+    s->scntl0 = 0xc0;
+    s->scntl1 = 0;
+    s->scntl2 = 0;
+    s->scntl3 = 0;
+    s->sstat0 = 0;
+    s->sstat1 = 0;
+    s->scid = 7;
+    s->sxfer = 0;
+    s->socl = 0;
+    s->sdid = 0;
+    s->ssid = 0;
+    s->stest1 = 0;
+    s->stest2 = 0;
+    s->stest3 = 0;
+    s->sidl = 0;
+    s->stime0 = 0;
+    s->respid0 = 0x80;
+    s->respid1 = 0;
+    s->mmrs = 0;
+    s->mmws = 0;
+    s->sfs = 0;
+    s->drs = 0;
+    s->sbms = 0;
+    s->dbms = 0;
+    s->dnad64 = 0;
+    s->pmjad1 = 0;
+    s->pmjad2 = 0;
+    s->rbc = 0;
+    s->ua = 0;
+    s->ia = 0;
+    s->sbc = 0;
+    s->csbc = 0;
+    s->sbr = 0;
+    assert(QTAILQ_EMPTY(&s->queue));
+    assert(!s->current);
+}
+
+static int lsi_dma_40bit(LSIState *s)
+{
+    if ((s->ccntl1 & LSI_CCNTL1_40BIT) == LSI_CCNTL1_40BIT)
+        return 1;
+    return 0;
+}
+
+static int lsi_dma_ti64bit(LSIState *s)
+{
+    if ((s->ccntl1 & LSI_CCNTL1_EN64TIBMV) == LSI_CCNTL1_EN64TIBMV)
+        return 1;
+    return 0;
+}
+
+static int lsi_dma_64bit(LSIState *s)
+{
+    if ((s->ccntl1 & LSI_CCNTL1_EN64DBMV) == LSI_CCNTL1_EN64DBMV)
+        return 1;
+    return 0;
+}
+
+static uint8_t lsi_reg_readb(LSIState *s, int offset);
+static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val);
+static void lsi_execute_script(LSIState *s);
+static void lsi_reselect(LSIState *s, lsi_request *p);
+
+static inline uint32_t read_dword(LSIState *s, uint32_t addr)
+{
+    uint32_t buf;
+
+    pci_dma_read(&s->dev, addr, &buf, 4);
+    return cpu_to_le32(buf);
+}
+
+static void lsi_stop_script(LSIState *s)
+{
+    s->istat1 &= ~LSI_ISTAT1_SRUN;
+}
+
+static void lsi_update_irq(LSIState *s)
+{
+    int level;
+    static int last_level;
+    lsi_request *p;
+
+    /* It's unclear whether the DIP/SIP bits should be cleared when the
+       Interrupt Status Registers are cleared or when istat0 is read.
+       We currently do the formwer, which seems to work.  */
+    level = 0;
+    if (s->dstat) {
+        if (s->dstat & s->dien)
+            level = 1;
+        s->istat0 |= LSI_ISTAT0_DIP;
+    } else {
+        s->istat0 &= ~LSI_ISTAT0_DIP;
+    }
+
+    if (s->sist0 || s->sist1) {
+        if ((s->sist0 & s->sien0) || (s->sist1 & s->sien1))
+            level = 1;
+        s->istat0 |= LSI_ISTAT0_SIP;
+    } else {
+        s->istat0 &= ~LSI_ISTAT0_SIP;
+    }
+    if (s->istat0 & LSI_ISTAT0_INTF)
+        level = 1;
+
+    if (level != last_level) {
+        DPRINTF("Update IRQ level %d dstat %02x sist %02x%02x\n",
+                level, s->dstat, s->sist1, s->sist0);
+        last_level = level;
+    }
+    qemu_set_irq(s->dev.irq[0], level);
+
+    if (!level && lsi_irq_on_rsl(s) && !(s->scntl1 & LSI_SCNTL1_CON)) {
+        DPRINTF("Handled IRQs & disconnected, looking for pending "
+                "processes\n");
+        QTAILQ_FOREACH(p, &s->queue, next) {
+            if (p->pending) {
+                lsi_reselect(s, p);
+                break;
+            }
+        }
+    }
+}
+
+/* Stop SCRIPTS execution and raise a SCSI interrupt.  */
+static void lsi_script_scsi_interrupt(LSIState *s, int stat0, int stat1)
+{
+    uint32_t mask0;
+    uint32_t mask1;
+
+    DPRINTF("SCSI Interrupt 0x%02x%02x prev 0x%02x%02x\n",
+            stat1, stat0, s->sist1, s->sist0);
+    s->sist0 |= stat0;
+    s->sist1 |= stat1;
+    /* Stop processor on fatal or unmasked interrupt.  As a special hack
+       we don't stop processing when raising STO.  Instead continue
+       execution and stop at the next insn that accesses the SCSI bus.  */
+    mask0 = s->sien0 | ~(LSI_SIST0_CMP | LSI_SIST0_SEL | LSI_SIST0_RSL);
+    mask1 = s->sien1 | ~(LSI_SIST1_GEN | LSI_SIST1_HTH);
+    mask1 &= ~LSI_SIST1_STO;
+    if (s->sist0 & mask0 || s->sist1 & mask1) {
+        lsi_stop_script(s);
+    }
+    lsi_update_irq(s);
+}
+
+/* Stop SCRIPTS execution and raise a DMA interrupt.  */
+static void lsi_script_dma_interrupt(LSIState *s, int stat)
+{
+    DPRINTF("DMA Interrupt 0x%x prev 0x%x\n", stat, s->dstat);
+    s->dstat |= stat;
+    lsi_update_irq(s);
+    lsi_stop_script(s);
+}
+
+static inline void lsi_set_phase(LSIState *s, int phase)
+{
+    s->sstat1 = (s->sstat1 & ~PHASE_MASK) | phase;
+}
+
+static void lsi_bad_phase(LSIState *s, int out, int new_phase)
+{
+    /* Trigger a phase mismatch.  */
+    if (s->ccntl0 & LSI_CCNTL0_ENPMJ) {
+        if ((s->ccntl0 & LSI_CCNTL0_PMJCTL)) {
+            s->dsp = out ? s->pmjad1 : s->pmjad2;
+        } else {
+            s->dsp = (s->scntl2 & LSI_SCNTL2_WSR ? s->pmjad2 : s->pmjad1);
+        }
+        DPRINTF("Data phase mismatch jump to %08x\n", s->dsp);
+    } else {
+        DPRINTF("Phase mismatch interrupt\n");
+        lsi_script_scsi_interrupt(s, LSI_SIST0_MA, 0);
+        lsi_stop_script(s);
+    }
+    lsi_set_phase(s, new_phase);
+}
+
+
+/* Resume SCRIPTS execution after a DMA operation.  */
+static void lsi_resume_script(LSIState *s)
+{
+    if (s->waiting != 2) {
+        s->waiting = 0;
+        lsi_execute_script(s);
+    } else {
+        s->waiting = 0;
+    }
+}
+
+static void lsi_disconnect(LSIState *s)
+{
+    s->scntl1 &= ~LSI_SCNTL1_CON;
+    s->sstat1 &= ~PHASE_MASK;
+}
+
+static void lsi_bad_selection(LSIState *s, uint32_t id)
+{
+    DPRINTF("Selected absent target %d\n", id);
+    lsi_script_scsi_interrupt(s, 0, LSI_SIST1_STO);
+    lsi_disconnect(s);
+}
+
+/* Initiate a SCSI layer data transfer.  */
+static void lsi_do_dma(LSIState *s, int out)
+{
+    uint32_t count;
+    dma_addr_t addr;
+    SCSIDevice *dev;
+
+    assert(s->current);
+    if (!s->current->dma_len) {
+        /* Wait until data is available.  */
+        DPRINTF("DMA no data available\n");
+        return;
+    }
+
+    dev = s->current->req->dev;
+    assert(dev);
+
+    count = s->dbc;
+    if (count > s->current->dma_len)
+        count = s->current->dma_len;
+
+    addr = s->dnad;
+    /* both 40 and Table Indirect 64-bit DMAs store upper bits in dnad64 */
+    if (lsi_dma_40bit(s) || lsi_dma_ti64bit(s))
+        addr |= ((uint64_t)s->dnad64 << 32);
+    else if (s->dbms)
+        addr |= ((uint64_t)s->dbms << 32);
+    else if (s->sbms)
+        addr |= ((uint64_t)s->sbms << 32);
+
+    DPRINTF("DMA addr=0x" DMA_ADDR_FMT " len=%d\n", addr, count);
+    s->csbc += count;
+    s->dnad += count;
+    s->dbc -= count;
+     if (s->current->dma_buf == NULL) {
+        s->current->dma_buf = scsi_req_get_buf(s->current->req);
+    }
+    /* ??? Set SFBR to first data byte.  */
+    if (out) {
+        pci_dma_read(&s->dev, addr, s->current->dma_buf, count);
+    } else {
+        pci_dma_write(&s->dev, addr, s->current->dma_buf, count);
+    }
+    s->current->dma_len -= count;
+    if (s->current->dma_len == 0) {
+        s->current->dma_buf = NULL;
+        scsi_req_continue(s->current->req);
+    } else {
+        s->current->dma_buf += count;
+        lsi_resume_script(s);
+    }
+}
+
+
+/* Add a command to the queue.  */
+static void lsi_queue_command(LSIState *s)
+{
+    lsi_request *p = s->current;
+
+    DPRINTF("Queueing tag=0x%x\n", p->tag);
+    assert(s->current != NULL);
+    assert(s->current->dma_len == 0);
+    QTAILQ_INSERT_TAIL(&s->queue, s->current, next);
+    s->current = NULL;
+
+    p->pending = 0;
+    p->out = (s->sstat1 & PHASE_MASK) == PHASE_DO;
+}
+
+/* Queue a byte for a MSG IN phase.  */
+static void lsi_add_msg_byte(LSIState *s, uint8_t data)
+{
+    if (s->msg_len >= LSI_MAX_MSGIN_LEN) {
+        BADF("MSG IN data too long\n");
+    } else {
+        DPRINTF("MSG IN 0x%02x\n", data);
+        s->msg[s->msg_len++] = data;
+    }
+}
+
+/* Perform reselection to continue a command.  */
+static void lsi_reselect(LSIState *s, lsi_request *p)
+{
+    int id;
+
+    assert(s->current == NULL);
+    QTAILQ_REMOVE(&s->queue, p, next);
+    s->current = p;
+
+    id = (p->tag >> 8) & 0xf;
+    s->ssid = id | 0x80;
+    /* LSI53C700 Family Compatibility, see LSI53C895A 4-73 */
+    if (!(s->dcntl & LSI_DCNTL_COM)) {
+        s->sfbr = 1 << (id & 0x7);
+    }
+    DPRINTF("Reselected target %d\n", id);
+    s->scntl1 |= LSI_SCNTL1_CON;
+    lsi_set_phase(s, PHASE_MI);
+    s->msg_action = p->out ? 2 : 3;
+    s->current->dma_len = p->pending;
+    lsi_add_msg_byte(s, 0x80);
+    if (s->current->tag & LSI_TAG_VALID) {
+        lsi_add_msg_byte(s, 0x20);
+        lsi_add_msg_byte(s, p->tag & 0xff);
+    }
+
+    if (lsi_irq_on_rsl(s)) {
+        lsi_script_scsi_interrupt(s, LSI_SIST0_RSL, 0);
+    }
+}
+
+static lsi_request *lsi_find_by_tag(LSIState *s, uint32_t tag)
+{
+    lsi_request *p;
+
+    QTAILQ_FOREACH(p, &s->queue, next) {
+        if (p->tag == tag) {
+            return p;
+        }
+    }
+
+    return NULL;
+}
+
+static void lsi_request_free(LSIState *s, lsi_request *p)
+{
+    if (p == s->current) {
+        s->current = NULL;
+    } else {
+        QTAILQ_REMOVE(&s->queue, p, next);
+    }
+    g_free(p);
+}
+
+static void lsi_request_cancelled(SCSIRequest *req)
+{
+    LSIState *s = DO_UPCAST(LSIState, dev.qdev, req->bus->qbus.parent);
+    lsi_request *p = req->hba_private;
+
+    req->hba_private = NULL;
+    lsi_request_free(s, p);
+    scsi_req_unref(req);
+}
+
+/* Record that data is available for a queued command.  Returns zero if
+   the device was reselected, nonzero if the IO is deferred.  */
+static int lsi_queue_req(LSIState *s, SCSIRequest *req, uint32_t len)
+{
+    lsi_request *p = req->hba_private;
+
+    if (p->pending) {
+        BADF("Multiple IO pending for request %p\n", p);
+    }
+    p->pending = len;
+    /* Reselect if waiting for it, or if reselection triggers an IRQ
+       and the bus is free.
+       Since no interrupt stacking is implemented in the emulation, it
+       is also required that there are no pending interrupts waiting
+       for service from the device driver. */
+    if (s->waiting == 1 ||
+        (lsi_irq_on_rsl(s) && !(s->scntl1 & LSI_SCNTL1_CON) &&
+         !(s->istat0 & (LSI_ISTAT0_SIP | LSI_ISTAT0_DIP)))) {
+        /* Reselect device.  */
+        lsi_reselect(s, p);
+        return 0;
+    } else {
+        DPRINTF("Queueing IO tag=0x%x\n", p->tag);
+        p->pending = len;
+        return 1;
+    }
+}
+
+ /* Callback to indicate that the SCSI layer has completed a command.  */
+static void lsi_command_complete(SCSIRequest *req, uint32_t status, size_t resid)
+{
+    LSIState *s = DO_UPCAST(LSIState, dev.qdev, req->bus->qbus.parent);
+    int out;
+
+    out = (s->sstat1 & PHASE_MASK) == PHASE_DO;
+    DPRINTF("Command complete status=%d\n", (int)status);
+    s->status = status;
+    s->command_complete = 2;
+    if (s->waiting && s->dbc != 0) {
+        /* Raise phase mismatch for short transfers.  */
+        lsi_bad_phase(s, out, PHASE_ST);
+    } else {
+        lsi_set_phase(s, PHASE_ST);
+    }
+
+    if (req->hba_private == s->current) {
+        req->hba_private = NULL;
+        lsi_request_free(s, s->current);
+        scsi_req_unref(req);
+    }
+    lsi_resume_script(s);
+}
+
+ /* Callback to indicate that the SCSI layer has completed a transfer.  */
+static void lsi_transfer_data(SCSIRequest *req, uint32_t len)
+{
+    LSIState *s = DO_UPCAST(LSIState, dev.qdev, req->bus->qbus.parent);
+    int out;
+
+    assert(req->hba_private);
+    if (s->waiting == 1 || req->hba_private != s->current ||
+        (lsi_irq_on_rsl(s) && !(s->scntl1 & LSI_SCNTL1_CON))) {
+        if (lsi_queue_req(s, req, len)) {
+            return;
+        }
+    }
+
+    out = (s->sstat1 & PHASE_MASK) == PHASE_DO;
+
+    /* host adapter (re)connected */
+    DPRINTF("Data ready tag=0x%x len=%d\n", req->tag, len);
+    s->current->dma_len = len;
+    s->command_complete = 1;
+    if (s->waiting) {
+        if (s->waiting == 1 || s->dbc == 0) {
+            lsi_resume_script(s);
+        } else {
+            lsi_do_dma(s, out);
+        }
+    }
+}
+
+static void lsi_do_command(LSIState *s)
+{
+    SCSIDevice *dev;
+    uint8_t buf[16];
+    uint32_t id;
+    int n;
+
+    DPRINTF("Send command len=%d\n", s->dbc);
+    if (s->dbc > 16)
+        s->dbc = 16;
+    pci_dma_read(&s->dev, s->dnad, buf, s->dbc);
+    s->sfbr = buf[0];
+    s->command_complete = 0;
+
+    id = (s->select_tag >> 8) & 0xf;
+    dev = scsi_device_find(&s->bus, 0, id, s->current_lun);
+    if (!dev) {
+        lsi_bad_selection(s, id);
+        return;
+    }
+
+    assert(s->current == NULL);
+    s->current = g_malloc0(sizeof(lsi_request));
+    s->current->tag = s->select_tag;
+    s->current->req = scsi_req_new(dev, s->current->tag, s->current_lun, buf,
+                                   s->current);
+
+    n = scsi_req_enqueue(s->current->req);
+    if (n) {
+        if (n > 0) {
+            lsi_set_phase(s, PHASE_DI);
+        } else if (n < 0) {
+            lsi_set_phase(s, PHASE_DO);
+        }
+        scsi_req_continue(s->current->req);
+    }
+    if (!s->command_complete) {
+        if (n) {
+            /* Command did not complete immediately so disconnect.  */
+            lsi_add_msg_byte(s, 2); /* SAVE DATA POINTER */
+            lsi_add_msg_byte(s, 4); /* DISCONNECT */
+            /* wait data */
+            lsi_set_phase(s, PHASE_MI);
+            s->msg_action = 1;
+            lsi_queue_command(s);
+        } else {
+            /* wait command complete */
+            lsi_set_phase(s, PHASE_DI);
+        }
+    }
+}
+
+static void lsi_do_status(LSIState *s)
+{
+    uint8_t status;
+    DPRINTF("Get status len=%d status=%d\n", s->dbc, s->status);
+    if (s->dbc != 1)
+        BADF("Bad Status move\n");
+    s->dbc = 1;
+    status = s->status;
+    s->sfbr = status;
+    pci_dma_write(&s->dev, s->dnad, &status, 1);
+    lsi_set_phase(s, PHASE_MI);
+    s->msg_action = 1;
+    lsi_add_msg_byte(s, 0); /* COMMAND COMPLETE */
+}
+
+static void lsi_do_msgin(LSIState *s)
+{
+    int len;
+    DPRINTF("Message in len=%d/%d\n", s->dbc, s->msg_len);
+    s->sfbr = s->msg[0];
+    len = s->msg_len;
+    if (len > s->dbc)
+        len = s->dbc;
+    pci_dma_write(&s->dev, s->dnad, s->msg, len);
+    /* Linux drivers rely on the last byte being in the SIDL.  */
+    s->sidl = s->msg[len - 1];
+    s->msg_len -= len;
+    if (s->msg_len) {
+        memmove(s->msg, s->msg + len, s->msg_len);
+    } else {
+        /* ??? Check if ATN (not yet implemented) is asserted and maybe
+           switch to PHASE_MO.  */
+        switch (s->msg_action) {
+        case 0:
+            lsi_set_phase(s, PHASE_CMD);
+            break;
+        case 1:
+            lsi_disconnect(s);
+            break;
+        case 2:
+            lsi_set_phase(s, PHASE_DO);
+            break;
+        case 3:
+            lsi_set_phase(s, PHASE_DI);
+            break;
+        default:
+            abort();
+        }
+    }
+}
+
+/* Read the next byte during a MSGOUT phase.  */
+static uint8_t lsi_get_msgbyte(LSIState *s)
+{
+    uint8_t data;
+    pci_dma_read(&s->dev, s->dnad, &data, 1);
+    s->dnad++;
+    s->dbc--;
+    return data;
+}
+
+/* Skip the next n bytes during a MSGOUT phase. */
+static void lsi_skip_msgbytes(LSIState *s, unsigned int n)
+{
+    s->dnad += n;
+    s->dbc  -= n;
+}
+
+static void lsi_do_msgout(LSIState *s)
+{
+    uint8_t msg;
+    int len;
+    uint32_t current_tag;
+    lsi_request *current_req, *p, *p_next;
+
+    if (s->current) {
+        current_tag = s->current->tag;
+        current_req = s->current;
+    } else {
+        current_tag = s->select_tag;
+        current_req = lsi_find_by_tag(s, current_tag);
+    }
+
+    DPRINTF("MSG out len=%d\n", s->dbc);
+    while (s->dbc) {
+        msg = lsi_get_msgbyte(s);
+        s->sfbr = msg;
+
+        switch (msg) {
+        case 0x04:
+            DPRINTF("MSG: Disconnect\n");
+            lsi_disconnect(s);
+            break;
+        case 0x08:
+            DPRINTF("MSG: No Operation\n");
+            lsi_set_phase(s, PHASE_CMD);
+            break;
+        case 0x01:
+            len = lsi_get_msgbyte(s);
+            msg = lsi_get_msgbyte(s);
+            (void)len; /* avoid a warning about unused variable*/
+            DPRINTF("Extended message 0x%x (len %d)\n", msg, len);
+            switch (msg) {
+            case 1:
+                DPRINTF("SDTR (ignored)\n");
+                lsi_skip_msgbytes(s, 2);
+                break;
+            case 3:
+                DPRINTF("WDTR (ignored)\n");
+                lsi_skip_msgbytes(s, 1);
+                break;
+            default:
+                goto bad;
+            }
+            break;
+        case 0x20: /* SIMPLE queue */
+            s->select_tag |= lsi_get_msgbyte(s) | LSI_TAG_VALID;
+            DPRINTF("SIMPLE queue tag=0x%x\n", s->select_tag & 0xff);
+            break;
+        case 0x21: /* HEAD of queue */
+            BADF("HEAD queue not implemented\n");
+            s->select_tag |= lsi_get_msgbyte(s) | LSI_TAG_VALID;
+            break;
+        case 0x22: /* ORDERED queue */
+            BADF("ORDERED queue not implemented\n");
+            s->select_tag |= lsi_get_msgbyte(s) | LSI_TAG_VALID;
+            break;
+        case 0x0d:
+            /* The ABORT TAG message clears the current I/O process only. */
+            DPRINTF("MSG: ABORT TAG tag=0x%x\n", current_tag);
+            if (current_req) {
+                scsi_req_cancel(current_req->req);
+            }
+            lsi_disconnect(s);
+            break;
+        case 0x06:
+        case 0x0e:
+        case 0x0c:
+            /* The ABORT message clears all I/O processes for the selecting
+               initiator on the specified logical unit of the target. */
+            if (msg == 0x06) {
+                DPRINTF("MSG: ABORT tag=0x%x\n", current_tag);
+            }
+            /* The CLEAR QUEUE message clears all I/O processes for all
+               initiators on the specified logical unit of the target. */
+            if (msg == 0x0e) {
+                DPRINTF("MSG: CLEAR QUEUE tag=0x%x\n", current_tag);
+            }
+            /* The BUS DEVICE RESET message clears all I/O processes for all
+               initiators on all logical units of the target. */
+            if (msg == 0x0c) {
+                DPRINTF("MSG: BUS DEVICE RESET tag=0x%x\n", current_tag);
+            }
+
+            /* clear the current I/O process */
+            if (s->current) {
+                scsi_req_cancel(s->current->req);
+            }
+
+            /* As the current implemented devices scsi_disk and scsi_generic
+               only support one LUN, we don't need to keep track of LUNs.
+               Clearing I/O processes for other initiators could be possible
+               for scsi_generic by sending a SG_SCSI_RESET to the /dev/sgX
+               device, but this is currently not implemented (and seems not
+               to be really necessary). So let's simply clear all queued
+               commands for the current device: */
+            QTAILQ_FOREACH_SAFE(p, &s->queue, next, p_next) {
+                if ((p->tag & 0x0000ff00) == (current_tag & 0x0000ff00)) {
+                    scsi_req_cancel(p->req);
+                }
+            }
+
+            lsi_disconnect(s);
+            break;
+        default:
+            if ((msg & 0x80) == 0) {
+                goto bad;
+            }
+            s->current_lun = msg & 7;
+            DPRINTF("Select LUN %d\n", s->current_lun);
+            lsi_set_phase(s, PHASE_CMD);
+            break;
+        }
+    }
+    return;
+bad:
+    BADF("Unimplemented message 0x%02x\n", msg);
+    lsi_set_phase(s, PHASE_MI);
+    lsi_add_msg_byte(s, 7); /* MESSAGE REJECT */
+    s->msg_action = 0;
+}
+
+/* Sign extend a 24-bit value.  */
+static inline int32_t sxt24(int32_t n)
+{
+    return (n << 8) >> 8;
+}
+
+#define LSI_BUF_SIZE 4096
+static void lsi_memcpy(LSIState *s, uint32_t dest, uint32_t src, int count)
+{
+    int n;
+    uint8_t buf[LSI_BUF_SIZE];
+
+    DPRINTF("memcpy dest 0x%08x src 0x%08x count %d\n", dest, src, count);
+    while (count) {
+        n = (count > LSI_BUF_SIZE) ? LSI_BUF_SIZE : count;
+        pci_dma_read(&s->dev, src, buf, n);
+        pci_dma_write(&s->dev, dest, buf, n);
+        src += n;
+        dest += n;
+        count -= n;
+    }
+}
+
+static void lsi_wait_reselect(LSIState *s)
+{
+    lsi_request *p;
+
+    DPRINTF("Wait Reselect\n");
+
+    QTAILQ_FOREACH(p, &s->queue, next) {
+        if (p->pending) {
+            lsi_reselect(s, p);
+            break;
+        }
+    }
+    if (s->current == NULL) {
+        s->waiting = 1;
+    }
+}
+
+static void lsi_execute_script(LSIState *s)
+{
+    uint32_t insn;
+    uint32_t addr, addr_high;
+    int opcode;
+    int insn_processed = 0;
+
+    s->istat1 |= LSI_ISTAT1_SRUN;
+again:
+    insn_processed++;
+    insn = read_dword(s, s->dsp);
+    if (!insn) {
+        /* If we receive an empty opcode increment the DSP by 4 bytes
+           instead of 8 and execute the next opcode at that location */
+        s->dsp += 4;
+        goto again;
+    }
+    addr = read_dword(s, s->dsp + 4);
+    addr_high = 0;
+    DPRINTF("SCRIPTS dsp=%08x opcode %08x arg %08x\n", s->dsp, insn, addr);
+    s->dsps = addr;
+    s->dcmd = insn >> 24;
+    s->dsp += 8;
+    switch (insn >> 30) {
+    case 0: /* Block move.  */
+        if (s->sist1 & LSI_SIST1_STO) {
+            DPRINTF("Delayed select timeout\n");
+            lsi_stop_script(s);
+            break;
+        }
+        s->dbc = insn & 0xffffff;
+        s->rbc = s->dbc;
+        /* ??? Set ESA.  */
+        s->ia = s->dsp - 8;
+        if (insn & (1 << 29)) {
+            /* Indirect addressing.  */
+            addr = read_dword(s, addr);
+        } else if (insn & (1 << 28)) {
+            uint32_t buf[2];
+            int32_t offset;
+            /* Table indirect addressing.  */
+
+            /* 32-bit Table indirect */
+            offset = sxt24(addr);
+            pci_dma_read(&s->dev, s->dsa + offset, buf, 8);
+            /* byte count is stored in bits 0:23 only */
+            s->dbc = cpu_to_le32(buf[0]) & 0xffffff;
+            s->rbc = s->dbc;
+            addr = cpu_to_le32(buf[1]);
+
+            /* 40-bit DMA, upper addr bits [39:32] stored in first DWORD of
+             * table, bits [31:24] */
+            if (lsi_dma_40bit(s))
+                addr_high = cpu_to_le32(buf[0]) >> 24;
+            else if (lsi_dma_ti64bit(s)) {
+                int selector = (cpu_to_le32(buf[0]) >> 24) & 0x1f;
+                switch (selector) {
+                case 0 ... 0x0f:
+                    /* offset index into scratch registers since
+                     * TI64 mode can use registers C to R */
+                    addr_high = s->scratch[2 + selector];
+                    break;
+                case 0x10:
+                    addr_high = s->mmrs;
+                    break;
+                case 0x11:
+                    addr_high = s->mmws;
+                    break;
+                case 0x12:
+                    addr_high = s->sfs;
+                    break;
+                case 0x13:
+                    addr_high = s->drs;
+                    break;
+                case 0x14:
+                    addr_high = s->sbms;
+                    break;
+                case 0x15:
+                    addr_high = s->dbms;
+                    break;
+                default:
+                    BADF("Illegal selector specified (0x%x > 0x15)"
+                         " for 64-bit DMA block move", selector);
+                    break;
+                }
+            }
+        } else if (lsi_dma_64bit(s)) {
+            /* fetch a 3rd dword if 64-bit direct move is enabled and
+               only if we're not doing table indirect or indirect addressing */
+            s->dbms = read_dword(s, s->dsp);
+            s->dsp += 4;
+            s->ia = s->dsp - 12;
+        }
+        if ((s->sstat1 & PHASE_MASK) != ((insn >> 24) & 7)) {
+            DPRINTF("Wrong phase got %d expected %d\n",
+                    s->sstat1 & PHASE_MASK, (insn >> 24) & 7);
+            lsi_script_scsi_interrupt(s, LSI_SIST0_MA, 0);
+            break;
+        }
+        s->dnad = addr;
+        s->dnad64 = addr_high;
+        switch (s->sstat1 & 0x7) {
+        case PHASE_DO:
+            s->waiting = 2;
+            lsi_do_dma(s, 1);
+            if (s->waiting)
+                s->waiting = 3;
+            break;
+        case PHASE_DI:
+            s->waiting = 2;
+            lsi_do_dma(s, 0);
+            if (s->waiting)
+                s->waiting = 3;
+            break;
+        case PHASE_CMD:
+            lsi_do_command(s);
+            break;
+        case PHASE_ST:
+            lsi_do_status(s);
+            break;
+        case PHASE_MO:
+            lsi_do_msgout(s);
+            break;
+        case PHASE_MI:
+            lsi_do_msgin(s);
+            break;
+        default:
+            BADF("Unimplemented phase %d\n", s->sstat1 & PHASE_MASK);
+            exit(1);
+        }
+        s->dfifo = s->dbc & 0xff;
+        s->ctest5 = (s->ctest5 & 0xfc) | ((s->dbc >> 8) & 3);
+        s->sbc = s->dbc;
+        s->rbc -= s->dbc;
+        s->ua = addr + s->dbc;
+        break;
+
+    case 1: /* IO or Read/Write instruction.  */
+        opcode = (insn >> 27) & 7;
+        if (opcode < 5) {
+            uint32_t id;
+
+            if (insn & (1 << 25)) {
+                id = read_dword(s, s->dsa + sxt24(insn));
+            } else {
+                id = insn;
+            }
+            id = (id >> 16) & 0xf;
+            if (insn & (1 << 26)) {
+                addr = s->dsp + sxt24(addr);
+            }
+            s->dnad = addr;
+            switch (opcode) {
+            case 0: /* Select */
+                s->sdid = id;
+                if (s->scntl1 & LSI_SCNTL1_CON) {
+                    DPRINTF("Already reselected, jumping to alternative address\n");
+                    s->dsp = s->dnad;
+                    break;
+                }
+                s->sstat0 |= LSI_SSTAT0_WOA;
+                s->scntl1 &= ~LSI_SCNTL1_IARB;
+                if (!scsi_device_find(&s->bus, 0, id, 0)) {
+                    lsi_bad_selection(s, id);
+                    break;
+                }
+                DPRINTF("Selected target %d%s\n",
+                        id, insn & (1 << 3) ? " ATN" : "");
+                /* ??? Linux drivers compain when this is set.  Maybe
+                   it only applies in low-level mode (unimplemented).
+                lsi_script_scsi_interrupt(s, LSI_SIST0_CMP, 0); */
+                s->select_tag = id << 8;
+                s->scntl1 |= LSI_SCNTL1_CON;
+                if (insn & (1 << 3)) {
+                    s->socl |= LSI_SOCL_ATN;
+                }
+                lsi_set_phase(s, PHASE_MO);
+                break;
+            case 1: /* Disconnect */
+                DPRINTF("Wait Disconnect\n");
+                s->scntl1 &= ~LSI_SCNTL1_CON;
+                break;
+            case 2: /* Wait Reselect */
+                if (!lsi_irq_on_rsl(s)) {
+                    lsi_wait_reselect(s);
+                }
+                break;
+            case 3: /* Set */
+                DPRINTF("Set%s%s%s%s\n",
+                        insn & (1 << 3) ? " ATN" : "",
+                        insn & (1 << 6) ? " ACK" : "",
+                        insn & (1 << 9) ? " TM" : "",
+                        insn & (1 << 10) ? " CC" : "");
+                if (insn & (1 << 3)) {
+                    s->socl |= LSI_SOCL_ATN;
+                    lsi_set_phase(s, PHASE_MO);
+                }
+                if (insn & (1 << 9)) {
+                    BADF("Target mode not implemented\n");
+                    exit(1);
+                }
+                if (insn & (1 << 10))
+                    s->carry = 1;
+                break;
+            case 4: /* Clear */
+                DPRINTF("Clear%s%s%s%s\n",
+                        insn & (1 << 3) ? " ATN" : "",
+                        insn & (1 << 6) ? " ACK" : "",
+                        insn & (1 << 9) ? " TM" : "",
+                        insn & (1 << 10) ? " CC" : "");
+                if (insn & (1 << 3)) {
+                    s->socl &= ~LSI_SOCL_ATN;
+                }
+                if (insn & (1 << 10))
+                    s->carry = 0;
+                break;
+            }
+        } else {
+            uint8_t op0;
+            uint8_t op1;
+            uint8_t data8;
+            int reg;
+            int operator;
+#ifdef DEBUG_LSI
+            static const char *opcode_names[3] =
+                {"Write", "Read", "Read-Modify-Write"};
+            static const char *operator_names[8] =
+                {"MOV", "SHL", "OR", "XOR", "AND", "SHR", "ADD", "ADC"};
+#endif
+
+            reg = ((insn >> 16) & 0x7f) | (insn & 0x80);
+            data8 = (insn >> 8) & 0xff;
+            opcode = (insn >> 27) & 7;
+            operator = (insn >> 24) & 7;
+            DPRINTF("%s reg 0x%x %s data8=0x%02x sfbr=0x%02x%s\n",
+                    opcode_names[opcode - 5], reg,
+                    operator_names[operator], data8, s->sfbr,
+                    (insn & (1 << 23)) ? " SFBR" : "");
+            op0 = op1 = 0;
+            switch (opcode) {
+            case 5: /* From SFBR */
+                op0 = s->sfbr;
+                op1 = data8;
+                break;
+            case 6: /* To SFBR */
+                if (operator)
+                    op0 = lsi_reg_readb(s, reg);
+                op1 = data8;
+                break;
+            case 7: /* Read-modify-write */
+                if (operator)
+                    op0 = lsi_reg_readb(s, reg);
+                if (insn & (1 << 23)) {
+                    op1 = s->sfbr;
+                } else {
+                    op1 = data8;
+                }
+                break;
+            }
+
+            switch (operator) {
+            case 0: /* move */
+                op0 = op1;
+                break;
+            case 1: /* Shift left */
+                op1 = op0 >> 7;
+                op0 = (op0 << 1) | s->carry;
+                s->carry = op1;
+                break;
+            case 2: /* OR */
+                op0 |= op1;
+                break;
+            case 3: /* XOR */
+                op0 ^= op1;
+                break;
+            case 4: /* AND */
+                op0 &= op1;
+                break;
+            case 5: /* SHR */
+                op1 = op0 & 1;
+                op0 = (op0 >> 1) | (s->carry << 7);
+                s->carry = op1;
+                break;
+            case 6: /* ADD */
+                op0 += op1;
+                s->carry = op0 < op1;
+                break;
+            case 7: /* ADC */
+                op0 += op1 + s->carry;
+                if (s->carry)
+                    s->carry = op0 <= op1;
+                else
+                    s->carry = op0 < op1;
+                break;
+            }
+
+            switch (opcode) {
+            case 5: /* From SFBR */
+            case 7: /* Read-modify-write */
+                lsi_reg_writeb(s, reg, op0);
+                break;
+            case 6: /* To SFBR */
+                s->sfbr = op0;
+                break;
+            }
+        }
+        break;
+
+    case 2: /* Transfer Control.  */
+        {
+            int cond;
+            int jmp;
+
+            if ((insn & 0x002e0000) == 0) {
+                DPRINTF("NOP\n");
+                break;
+            }
+            if (s->sist1 & LSI_SIST1_STO) {
+                DPRINTF("Delayed select timeout\n");
+                lsi_stop_script(s);
+                break;
+            }
+            cond = jmp = (insn & (1 << 19)) != 0;
+            if (cond == jmp && (insn & (1 << 21))) {
+                DPRINTF("Compare carry %d\n", s->carry == jmp);
+                cond = s->carry != 0;
+            }
+            if (cond == jmp && (insn & (1 << 17))) {
+                DPRINTF("Compare phase %d %c= %d\n",
+                        (s->sstat1 & PHASE_MASK),
+                        jmp ? '=' : '!',
+                        ((insn >> 24) & 7));
+                cond = (s->sstat1 & PHASE_MASK) == ((insn >> 24) & 7);
+            }
+            if (cond == jmp && (insn & (1 << 18))) {
+                uint8_t mask;
+
+                mask = (~insn >> 8) & 0xff;
+                DPRINTF("Compare data 0x%x & 0x%x %c= 0x%x\n",
+                        s->sfbr, mask, jmp ? '=' : '!', insn & mask);
+                cond = (s->sfbr & mask) == (insn & mask);
+            }
+            if (cond == jmp) {
+                if (insn & (1 << 23)) {
+                    /* Relative address.  */
+                    addr = s->dsp + sxt24(addr);
+                }
+                switch ((insn >> 27) & 7) {
+                case 0: /* Jump */
+                    DPRINTF("Jump to 0x%08x\n", addr);
+                    s->dsp = addr;
+                    break;
+                case 1: /* Call */
+                    DPRINTF("Call 0x%08x\n", addr);
+                    s->temp = s->dsp;
+                    s->dsp = addr;
+                    break;
+                case 2: /* Return */
+                    DPRINTF("Return to 0x%08x\n", s->temp);
+                    s->dsp = s->temp;
+                    break;
+                case 3: /* Interrupt */
+                    DPRINTF("Interrupt 0x%08x\n", s->dsps);
+                    if ((insn & (1 << 20)) != 0) {
+                        s->istat0 |= LSI_ISTAT0_INTF;
+                        lsi_update_irq(s);
+                    } else {
+                        lsi_script_dma_interrupt(s, LSI_DSTAT_SIR);
+                    }
+                    break;
+                default:
+                    DPRINTF("Illegal transfer control\n");
+                    lsi_script_dma_interrupt(s, LSI_DSTAT_IID);
+                    break;
+                }
+            } else {
+                DPRINTF("Control condition failed\n");
+            }
+        }
+        break;
+
+    case 3:
+        if ((insn & (1 << 29)) == 0) {
+            /* Memory move.  */
+            uint32_t dest;
+            /* ??? The docs imply the destination address is loaded into
+               the TEMP register.  However the Linux drivers rely on
+               the value being presrved.  */
+            dest = read_dword(s, s->dsp);
+            s->dsp += 4;
+            lsi_memcpy(s, dest, addr, insn & 0xffffff);
+        } else {
+            uint8_t data[7];
+            int reg;
+            int n;
+            int i;
+
+            if (insn & (1 << 28)) {
+                addr = s->dsa + sxt24(addr);
+            }
+            n = (insn & 7);
+            reg = (insn >> 16) & 0xff;
+            if (insn & (1 << 24)) {
+                pci_dma_read(&s->dev, addr, data, n);
+                DPRINTF("Load reg 0x%x size %d addr 0x%08x = %08x\n", reg, n,
+                        addr, *(int *)data);
+                for (i = 0; i < n; i++) {
+                    lsi_reg_writeb(s, reg + i, data[i]);
+                }
+            } else {
+                DPRINTF("Store reg 0x%x size %d addr 0x%08x\n", reg, n, addr);
+                for (i = 0; i < n; i++) {
+                    data[i] = lsi_reg_readb(s, reg + i);
+                }
+                pci_dma_write(&s->dev, addr, data, n);
+            }
+        }
+    }
+    if (insn_processed > 10000 && !s->waiting) {
+        /* Some windows drivers make the device spin waiting for a memory
+           location to change.  If we have been executed a lot of code then
+           assume this is the case and force an unexpected device disconnect.
+           This is apparently sufficient to beat the drivers into submission.
+         */
+        if (!(s->sien0 & LSI_SIST0_UDC))
+            fprintf(stderr, "inf. loop with UDC masked\n");
+        lsi_script_scsi_interrupt(s, LSI_SIST0_UDC, 0);
+        lsi_disconnect(s);
+    } else if (s->istat1 & LSI_ISTAT1_SRUN && !s->waiting) {
+        if (s->dcntl & LSI_DCNTL_SSM) {
+            lsi_script_dma_interrupt(s, LSI_DSTAT_SSI);
+        } else {
+            goto again;
+        }
+    }
+    DPRINTF("SCRIPTS execution stopped\n");
+}
+
+static uint8_t lsi_reg_readb(LSIState *s, int offset)
+{
+    uint8_t tmp;
+#define CASE_GET_REG24(name, addr) \
+    case addr: return s->name & 0xff; \
+    case addr + 1: return (s->name >> 8) & 0xff; \
+    case addr + 2: return (s->name >> 16) & 0xff;
+
+#define CASE_GET_REG32(name, addr) \
+    case addr: return s->name & 0xff; \
+    case addr + 1: return (s->name >> 8) & 0xff; \
+    case addr + 2: return (s->name >> 16) & 0xff; \
+    case addr + 3: return (s->name >> 24) & 0xff;
+
+#ifdef DEBUG_LSI_REG
+    DPRINTF("Read reg %x\n", offset);
+#endif
+    switch (offset) {
+    case 0x00: /* SCNTL0 */
+        return s->scntl0;
+    case 0x01: /* SCNTL1 */
+        return s->scntl1;
+    case 0x02: /* SCNTL2 */
+        return s->scntl2;
+    case 0x03: /* SCNTL3 */
+        return s->scntl3;
+    case 0x04: /* SCID */
+        return s->scid;
+    case 0x05: /* SXFER */
+        return s->sxfer;
+    case 0x06: /* SDID */
+        return s->sdid;
+    case 0x07: /* GPREG0 */
+        return 0x7f;
+    case 0x08: /* Revision ID */
+        return 0x00;
+    case 0xa: /* SSID */
+        return s->ssid;
+    case 0xb: /* SBCL */
+        /* ??? This is not correct. However it's (hopefully) only
+           used for diagnostics, so should be ok.  */
+        return 0;
+    case 0xc: /* DSTAT */
+        tmp = s->dstat | 0x80;
+        if ((s->istat0 & LSI_ISTAT0_INTF) == 0)
+            s->dstat = 0;
+        lsi_update_irq(s);
+        return tmp;
+    case 0x0d: /* SSTAT0 */
+        return s->sstat0;
+    case 0x0e: /* SSTAT1 */
+        return s->sstat1;
+    case 0x0f: /* SSTAT2 */
+        return s->scntl1 & LSI_SCNTL1_CON ? 0 : 2;
+    CASE_GET_REG32(dsa, 0x10)
+    case 0x14: /* ISTAT0 */
+        return s->istat0;
+    case 0x15: /* ISTAT1 */
+        return s->istat1;
+    case 0x16: /* MBOX0 */
+        return s->mbox0;
+    case 0x17: /* MBOX1 */
+        return s->mbox1;
+    case 0x18: /* CTEST0 */
+        return 0xff;
+    case 0x19: /* CTEST1 */
+        return 0;
+    case 0x1a: /* CTEST2 */
+        tmp = s->ctest2 | LSI_CTEST2_DACK | LSI_CTEST2_CM;
+        if (s->istat0 & LSI_ISTAT0_SIGP) {
+            s->istat0 &= ~LSI_ISTAT0_SIGP;
+            tmp |= LSI_CTEST2_SIGP;
+        }
+        return tmp;
+    case 0x1b: /* CTEST3 */
+        return s->ctest3;
+    CASE_GET_REG32(temp, 0x1c)
+    case 0x20: /* DFIFO */
+        return 0;
+    case 0x21: /* CTEST4 */
+        return s->ctest4;
+    case 0x22: /* CTEST5 */
+        return s->ctest5;
+    case 0x23: /* CTEST6 */
+         return 0;
+    CASE_GET_REG24(dbc, 0x24)
+    case 0x27: /* DCMD */
+        return s->dcmd;
+    CASE_GET_REG32(dnad, 0x28)
+    CASE_GET_REG32(dsp, 0x2c)
+    CASE_GET_REG32(dsps, 0x30)
+    CASE_GET_REG32(scratch[0], 0x34)
+    case 0x38: /* DMODE */
+        return s->dmode;
+    case 0x39: /* DIEN */
+        return s->dien;
+    case 0x3a: /* SBR */
+        return s->sbr;
+    case 0x3b: /* DCNTL */
+        return s->dcntl;
+    case 0x40: /* SIEN0 */
+        return s->sien0;
+    case 0x41: /* SIEN1 */
+        return s->sien1;
+    case 0x42: /* SIST0 */
+        tmp = s->sist0;
+        s->sist0 = 0;
+        lsi_update_irq(s);
+        return tmp;
+    case 0x43: /* SIST1 */
+        tmp = s->sist1;
+        s->sist1 = 0;
+        lsi_update_irq(s);
+        return tmp;
+    case 0x46: /* MACNTL */
+        return 0x0f;
+    case 0x47: /* GPCNTL0 */
+        return 0x0f;
+    case 0x48: /* STIME0 */
+        return s->stime0;
+    case 0x4a: /* RESPID0 */
+        return s->respid0;
+    case 0x4b: /* RESPID1 */
+        return s->respid1;
+    case 0x4d: /* STEST1 */
+        return s->stest1;
+    case 0x4e: /* STEST2 */
+        return s->stest2;
+    case 0x4f: /* STEST3 */
+        return s->stest3;
+    case 0x50: /* SIDL */
+        /* This is needed by the linux drivers.  We currently only update it
+           during the MSG IN phase.  */
+        return s->sidl;
+    case 0x52: /* STEST4 */
+        return 0xe0;
+    case 0x56: /* CCNTL0 */
+        return s->ccntl0;
+    case 0x57: /* CCNTL1 */
+        return s->ccntl1;
+    case 0x58: /* SBDL */
+        /* Some drivers peek at the data bus during the MSG IN phase.  */
+        if ((s->sstat1 & PHASE_MASK) == PHASE_MI)
+            return s->msg[0];
+        return 0;
+    case 0x59: /* SBDL high */
+        return 0;
+    CASE_GET_REG32(mmrs, 0xa0)
+    CASE_GET_REG32(mmws, 0xa4)
+    CASE_GET_REG32(sfs, 0xa8)
+    CASE_GET_REG32(drs, 0xac)
+    CASE_GET_REG32(sbms, 0xb0)
+    CASE_GET_REG32(dbms, 0xb4)
+    CASE_GET_REG32(dnad64, 0xb8)
+    CASE_GET_REG32(pmjad1, 0xc0)
+    CASE_GET_REG32(pmjad2, 0xc4)
+    CASE_GET_REG32(rbc, 0xc8)
+    CASE_GET_REG32(ua, 0xcc)
+    CASE_GET_REG32(ia, 0xd4)
+    CASE_GET_REG32(sbc, 0xd8)
+    CASE_GET_REG32(csbc, 0xdc)
+    }
+    if (offset >= 0x5c && offset < 0xa0) {
+        int n;
+        int shift;
+        n = (offset - 0x58) >> 2;
+        shift = (offset & 3) * 8;
+        return (s->scratch[n] >> shift) & 0xff;
+    }
+    BADF("readb 0x%x\n", offset);
+    exit(1);
+#undef CASE_GET_REG24
+#undef CASE_GET_REG32
+}
+
+static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val)
+{
+#define CASE_SET_REG24(name, addr) \
+    case addr    : s->name &= 0xffffff00; s->name |= val;       break; \
+    case addr + 1: s->name &= 0xffff00ff; s->name |= val << 8;  break; \
+    case addr + 2: s->name &= 0xff00ffff; s->name |= val << 16; break;
+
+#define CASE_SET_REG32(name, addr) \
+    case addr    : s->name &= 0xffffff00; s->name |= val;       break; \
+    case addr + 1: s->name &= 0xffff00ff; s->name |= val << 8;  break; \
+    case addr + 2: s->name &= 0xff00ffff; s->name |= val << 16; break; \
+    case addr + 3: s->name &= 0x00ffffff; s->name |= val << 24; break;
+
+#ifdef DEBUG_LSI_REG
+    DPRINTF("Write reg %x = %02x\n", offset, val);
+#endif
+    switch (offset) {
+    case 0x00: /* SCNTL0 */
+        s->scntl0 = val;
+        if (val & LSI_SCNTL0_START) {
+            BADF("Start sequence not implemented\n");
+        }
+        break;
+    case 0x01: /* SCNTL1 */
+        s->scntl1 = val & ~LSI_SCNTL1_SST;
+        if (val & LSI_SCNTL1_IARB) {
+            BADF("Immediate Arbritration not implemented\n");
+        }
+        if (val & LSI_SCNTL1_RST) {
+            if (!(s->sstat0 & LSI_SSTAT0_RST)) {
+                qbus_reset_all(&s->bus.qbus);
+                s->sstat0 |= LSI_SSTAT0_RST;
+                lsi_script_scsi_interrupt(s, LSI_SIST0_RST, 0);
+            }
+        } else {
+            s->sstat0 &= ~LSI_SSTAT0_RST;
+        }
+        break;
+    case 0x02: /* SCNTL2 */
+        val &= ~(LSI_SCNTL2_WSR | LSI_SCNTL2_WSS);
+        s->scntl2 = val;
+        break;
+    case 0x03: /* SCNTL3 */
+        s->scntl3 = val;
+        break;
+    case 0x04: /* SCID */
+        s->scid = val;
+        break;
+    case 0x05: /* SXFER */
+        s->sxfer = val;
+        break;
+    case 0x06: /* SDID */
+        if ((val & 0xf) != (s->ssid & 0xf))
+            BADF("Destination ID does not match SSID\n");
+        s->sdid = val & 0xf;
+        break;
+    case 0x07: /* GPREG0 */
+        break;
+    case 0x08: /* SFBR */
+        /* The CPU is not allowed to write to this register.  However the
+           SCRIPTS register move instructions are.  */
+        s->sfbr = val;
+        break;
+    case 0x0a: case 0x0b:
+        /* Openserver writes to these readonly registers on startup */
+       return;
+    case 0x0c: case 0x0d: case 0x0e: case 0x0f:
+        /* Linux writes to these readonly registers on startup.  */
+        return;
+    CASE_SET_REG32(dsa, 0x10)
+    case 0x14: /* ISTAT0 */
+        s->istat0 = (s->istat0 & 0x0f) | (val & 0xf0);
+        if (val & LSI_ISTAT0_ABRT) {
+            lsi_script_dma_interrupt(s, LSI_DSTAT_ABRT);
+        }
+        if (val & LSI_ISTAT0_INTF) {
+            s->istat0 &= ~LSI_ISTAT0_INTF;
+            lsi_update_irq(s);
+        }
+        if (s->waiting == 1 && val & LSI_ISTAT0_SIGP) {
+            DPRINTF("Woken by SIGP\n");
+            s->waiting = 0;
+            s->dsp = s->dnad;
+            lsi_execute_script(s);
+        }
+        if (val & LSI_ISTAT0_SRST) {
+            qdev_reset_all(&s->dev.qdev);
+        }
+        break;
+    case 0x16: /* MBOX0 */
+        s->mbox0 = val;
+        break;
+    case 0x17: /* MBOX1 */
+        s->mbox1 = val;
+        break;
+    case 0x1a: /* CTEST2 */
+       s->ctest2 = val & LSI_CTEST2_PCICIE;
+       break;
+    case 0x1b: /* CTEST3 */
+        s->ctest3 = val & 0x0f;
+        break;
+    CASE_SET_REG32(temp, 0x1c)
+    case 0x21: /* CTEST4 */
+        if (val & 7) {
+           BADF("Unimplemented CTEST4-FBL 0x%x\n", val);
+        }
+        s->ctest4 = val;
+        break;
+    case 0x22: /* CTEST5 */
+        if (val & (LSI_CTEST5_ADCK | LSI_CTEST5_BBCK)) {
+            BADF("CTEST5 DMA increment not implemented\n");
+        }
+        s->ctest5 = val;
+        break;
+    CASE_SET_REG24(dbc, 0x24)
+    CASE_SET_REG32(dnad, 0x28)
+    case 0x2c: /* DSP[0:7] */
+        s->dsp &= 0xffffff00;
+        s->dsp |= val;
+        break;
+    case 0x2d: /* DSP[8:15] */
+        s->dsp &= 0xffff00ff;
+        s->dsp |= val << 8;
+        break;
+    case 0x2e: /* DSP[16:23] */
+        s->dsp &= 0xff00ffff;
+        s->dsp |= val << 16;
+        break;
+    case 0x2f: /* DSP[24:31] */
+        s->dsp &= 0x00ffffff;
+        s->dsp |= val << 24;
+        if ((s->dmode & LSI_DMODE_MAN) == 0
+            && (s->istat1 & LSI_ISTAT1_SRUN) == 0)
+            lsi_execute_script(s);
+        break;
+    CASE_SET_REG32(dsps, 0x30)
+    CASE_SET_REG32(scratch[0], 0x34)
+    case 0x38: /* DMODE */
+        if (val & (LSI_DMODE_SIOM | LSI_DMODE_DIOM)) {
+            BADF("IO mappings not implemented\n");
+        }
+        s->dmode = val;
+        break;
+    case 0x39: /* DIEN */
+        s->dien = val;
+        lsi_update_irq(s);
+        break;
+    case 0x3a: /* SBR */
+        s->sbr = val;
+        break;
+    case 0x3b: /* DCNTL */
+        s->dcntl = val & ~(LSI_DCNTL_PFF | LSI_DCNTL_STD);
+        if ((val & LSI_DCNTL_STD) && (s->istat1 & LSI_ISTAT1_SRUN) == 0)
+            lsi_execute_script(s);
+        break;
+    case 0x40: /* SIEN0 */
+        s->sien0 = val;
+        lsi_update_irq(s);
+        break;
+    case 0x41: /* SIEN1 */
+        s->sien1 = val;
+        lsi_update_irq(s);
+        break;
+    case 0x47: /* GPCNTL0 */
+        break;
+    case 0x48: /* STIME0 */
+        s->stime0 = val;
+        break;
+    case 0x49: /* STIME1 */
+        if (val & 0xf) {
+            DPRINTF("General purpose timer not implemented\n");
+            /* ??? Raising the interrupt immediately seems to be sufficient
+               to keep the FreeBSD driver happy.  */
+            lsi_script_scsi_interrupt(s, 0, LSI_SIST1_GEN);
+        }
+        break;
+    case 0x4a: /* RESPID0 */
+        s->respid0 = val;
+        break;
+    case 0x4b: /* RESPID1 */
+        s->respid1 = val;
+        break;
+    case 0x4d: /* STEST1 */
+        s->stest1 = val;
+        break;
+    case 0x4e: /* STEST2 */
+        if (val & 1) {
+            BADF("Low level mode not implemented\n");
+        }
+        s->stest2 = val;
+        break;
+    case 0x4f: /* STEST3 */
+        if (val & 0x41) {
+            BADF("SCSI FIFO test mode not implemented\n");
+        }
+        s->stest3 = val;
+        break;
+    case 0x56: /* CCNTL0 */
+        s->ccntl0 = val;
+        break;
+    case 0x57: /* CCNTL1 */
+        s->ccntl1 = val;
+        break;
+    CASE_SET_REG32(mmrs, 0xa0)
+    CASE_SET_REG32(mmws, 0xa4)
+    CASE_SET_REG32(sfs, 0xa8)
+    CASE_SET_REG32(drs, 0xac)
+    CASE_SET_REG32(sbms, 0xb0)
+    CASE_SET_REG32(dbms, 0xb4)
+    CASE_SET_REG32(dnad64, 0xb8)
+    CASE_SET_REG32(pmjad1, 0xc0)
+    CASE_SET_REG32(pmjad2, 0xc4)
+    CASE_SET_REG32(rbc, 0xc8)
+    CASE_SET_REG32(ua, 0xcc)
+    CASE_SET_REG32(ia, 0xd4)
+    CASE_SET_REG32(sbc, 0xd8)
+    CASE_SET_REG32(csbc, 0xdc)
+    default:
+        if (offset >= 0x5c && offset < 0xa0) {
+            int n;
+            int shift;
+            n = (offset - 0x58) >> 2;
+            shift = (offset & 3) * 8;
+            s->scratch[n] &= ~(0xff << shift);
+            s->scratch[n] |= (val & 0xff) << shift;
+        } else {
+            BADF("Unhandled writeb 0x%x = 0x%x\n", offset, val);
+        }
+    }
+#undef CASE_SET_REG24
+#undef CASE_SET_REG32
+}
+
+static void lsi_mmio_write(void *opaque, hwaddr addr,
+                           uint64_t val, unsigned size)
+{
+    LSIState *s = opaque;
+
+    lsi_reg_writeb(s, addr & 0xff, val);
+}
+
+static uint64_t lsi_mmio_read(void *opaque, hwaddr addr,
+                              unsigned size)
+{
+    LSIState *s = opaque;
+
+    return lsi_reg_readb(s, addr & 0xff);
+}
+
+static const MemoryRegionOps lsi_mmio_ops = {
+    .read = lsi_mmio_read,
+    .write = lsi_mmio_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+};
+
+static void lsi_ram_write(void *opaque, hwaddr addr,
+                          uint64_t val, unsigned size)
+{
+    LSIState *s = opaque;
+    uint32_t newval;
+    uint32_t mask;
+    int shift;
+
+    newval = s->script_ram[addr >> 2];
+    shift = (addr & 3) * 8;
+    mask = ((uint64_t)1 << (size * 8)) - 1;
+    newval &= ~(mask << shift);
+    newval |= val << shift;
+    s->script_ram[addr >> 2] = newval;
+}
+
+static uint64_t lsi_ram_read(void *opaque, hwaddr addr,
+                             unsigned size)
+{
+    LSIState *s = opaque;
+    uint32_t val;
+    uint32_t mask;
+
+    val = s->script_ram[addr >> 2];
+    mask = ((uint64_t)1 << (size * 8)) - 1;
+    val >>= (addr & 3) * 8;
+    return val & mask;
+}
+
+static const MemoryRegionOps lsi_ram_ops = {
+    .read = lsi_ram_read,
+    .write = lsi_ram_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static uint64_t lsi_io_read(void *opaque, hwaddr addr,
+                            unsigned size)
+{
+    LSIState *s = opaque;
+    return lsi_reg_readb(s, addr & 0xff);
+}
+
+static void lsi_io_write(void *opaque, hwaddr addr,
+                         uint64_t val, unsigned size)
+{
+    LSIState *s = opaque;
+    lsi_reg_writeb(s, addr & 0xff, val);
+}
+
+static const MemoryRegionOps lsi_io_ops = {
+    .read = lsi_io_read,
+    .write = lsi_io_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+};
+
+static void lsi_scsi_reset(DeviceState *dev)
+{
+    LSIState *s = DO_UPCAST(LSIState, dev.qdev, dev);
+
+    lsi_soft_reset(s);
+}
+
+static void lsi_pre_save(void *opaque)
+{
+    LSIState *s = opaque;
+
+    if (s->current) {
+        assert(s->current->dma_buf == NULL);
+        assert(s->current->dma_len == 0);
+    }
+    assert(QTAILQ_EMPTY(&s->queue));
+}
+
+static const VMStateDescription vmstate_lsi_scsi = {
+    .name = "lsiscsi",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .pre_save = lsi_pre_save,
+    .fields      = (VMStateField []) {
+        VMSTATE_PCI_DEVICE(dev, LSIState),
+
+        VMSTATE_INT32(carry, LSIState),
+        VMSTATE_INT32(status, LSIState),
+        VMSTATE_INT32(msg_action, LSIState),
+        VMSTATE_INT32(msg_len, LSIState),
+        VMSTATE_BUFFER(msg, LSIState),
+        VMSTATE_INT32(waiting, LSIState),
+
+        VMSTATE_UINT32(dsa, LSIState),
+        VMSTATE_UINT32(temp, LSIState),
+        VMSTATE_UINT32(dnad, LSIState),
+        VMSTATE_UINT32(dbc, LSIState),
+        VMSTATE_UINT8(istat0, LSIState),
+        VMSTATE_UINT8(istat1, LSIState),
+        VMSTATE_UINT8(dcmd, LSIState),
+        VMSTATE_UINT8(dstat, LSIState),
+        VMSTATE_UINT8(dien, LSIState),
+        VMSTATE_UINT8(sist0, LSIState),
+        VMSTATE_UINT8(sist1, LSIState),
+        VMSTATE_UINT8(sien0, LSIState),
+        VMSTATE_UINT8(sien1, LSIState),
+        VMSTATE_UINT8(mbox0, LSIState),
+        VMSTATE_UINT8(mbox1, LSIState),
+        VMSTATE_UINT8(dfifo, LSIState),
+        VMSTATE_UINT8(ctest2, LSIState),
+        VMSTATE_UINT8(ctest3, LSIState),
+        VMSTATE_UINT8(ctest4, LSIState),
+        VMSTATE_UINT8(ctest5, LSIState),
+        VMSTATE_UINT8(ccntl0, LSIState),
+        VMSTATE_UINT8(ccntl1, LSIState),
+        VMSTATE_UINT32(dsp, LSIState),
+        VMSTATE_UINT32(dsps, LSIState),
+        VMSTATE_UINT8(dmode, LSIState),
+        VMSTATE_UINT8(dcntl, LSIState),
+        VMSTATE_UINT8(scntl0, LSIState),
+        VMSTATE_UINT8(scntl1, LSIState),
+        VMSTATE_UINT8(scntl2, LSIState),
+        VMSTATE_UINT8(scntl3, LSIState),
+        VMSTATE_UINT8(sstat0, LSIState),
+        VMSTATE_UINT8(sstat1, LSIState),
+        VMSTATE_UINT8(scid, LSIState),
+        VMSTATE_UINT8(sxfer, LSIState),
+        VMSTATE_UINT8(socl, LSIState),
+        VMSTATE_UINT8(sdid, LSIState),
+        VMSTATE_UINT8(ssid, LSIState),
+        VMSTATE_UINT8(sfbr, LSIState),
+        VMSTATE_UINT8(stest1, LSIState),
+        VMSTATE_UINT8(stest2, LSIState),
+        VMSTATE_UINT8(stest3, LSIState),
+        VMSTATE_UINT8(sidl, LSIState),
+        VMSTATE_UINT8(stime0, LSIState),
+        VMSTATE_UINT8(respid0, LSIState),
+        VMSTATE_UINT8(respid1, LSIState),
+        VMSTATE_UINT32(mmrs, LSIState),
+        VMSTATE_UINT32(mmws, LSIState),
+        VMSTATE_UINT32(sfs, LSIState),
+        VMSTATE_UINT32(drs, LSIState),
+        VMSTATE_UINT32(sbms, LSIState),
+        VMSTATE_UINT32(dbms, LSIState),
+        VMSTATE_UINT32(dnad64, LSIState),
+        VMSTATE_UINT32(pmjad1, LSIState),
+        VMSTATE_UINT32(pmjad2, LSIState),
+        VMSTATE_UINT32(rbc, LSIState),
+        VMSTATE_UINT32(ua, LSIState),
+        VMSTATE_UINT32(ia, LSIState),
+        VMSTATE_UINT32(sbc, LSIState),
+        VMSTATE_UINT32(csbc, LSIState),
+        VMSTATE_BUFFER_UNSAFE(scratch, LSIState, 0, 18 * sizeof(uint32_t)),
+        VMSTATE_UINT8(sbr, LSIState),
+
+        VMSTATE_BUFFER_UNSAFE(script_ram, LSIState, 0, 2048 * sizeof(uint32_t)),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void lsi_scsi_uninit(PCIDevice *d)
+{
+    LSIState *s = DO_UPCAST(LSIState, dev, d);
+
+    memory_region_destroy(&s->mmio_io);
+    memory_region_destroy(&s->ram_io);
+    memory_region_destroy(&s->io_io);
+}
+
+static const struct SCSIBusInfo lsi_scsi_info = {
+    .tcq = true,
+    .max_target = LSI_MAX_DEVS,
+    .max_lun = 0,  /* LUN support is buggy */
+
+    .transfer_data = lsi_transfer_data,
+    .complete = lsi_command_complete,
+    .cancel = lsi_request_cancelled
+};
+
+static int lsi_scsi_init(PCIDevice *dev)
+{
+    LSIState *s = DO_UPCAST(LSIState, dev, dev);
+    uint8_t *pci_conf;
+
+    pci_conf = s->dev.config;
+
+    /* PCI latency timer = 255 */
+    pci_conf[PCI_LATENCY_TIMER] = 0xff;
+    /* Interrupt pin A */
+    pci_conf[PCI_INTERRUPT_PIN] = 0x01;
+
+    memory_region_init_io(&s->mmio_io, &lsi_mmio_ops, s, "lsi-mmio", 0x400);
+    memory_region_init_io(&s->ram_io, &lsi_ram_ops, s, "lsi-ram", 0x2000);
+    memory_region_init_io(&s->io_io, &lsi_io_ops, s, "lsi-io", 256);
+
+    pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io_io);
+    pci_register_bar(&s->dev, 1, 0, &s->mmio_io);
+    pci_register_bar(&s->dev, 2, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->ram_io);
+    QTAILQ_INIT(&s->queue);
+
+    scsi_bus_new(&s->bus, &dev->qdev, &lsi_scsi_info);
+    if (!dev->qdev.hotplugged) {
+        return scsi_bus_legacy_handle_cmdline(&s->bus);
+    }
+    return 0;
+}
+
+static void lsi_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = lsi_scsi_init;
+    k->exit = lsi_scsi_uninit;
+    k->vendor_id = PCI_VENDOR_ID_LSI_LOGIC;
+    k->device_id = PCI_DEVICE_ID_LSI_53C895A;
+    k->class_id = PCI_CLASS_STORAGE_SCSI;
+    k->subsystem_id = 0x1000;
+    dc->reset = lsi_scsi_reset;
+    dc->vmsd = &vmstate_lsi_scsi;
+}
+
+static const TypeInfo lsi_info = {
+    .name          = "lsi53c895a",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(LSIState),
+    .class_init    = lsi_class_init,
+};
+
+static void lsi53c895a_register_types(void)
+{
+    type_register_static(&lsi_info);
+}
+
+type_init(lsi53c895a_register_types)
diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c
new file mode 100644 (file)
index 0000000..14b0552
--- /dev/null
@@ -0,0 +1,2213 @@
+/*
+ * QEMU MegaRAID SAS 8708EM2 Host Bus Adapter emulation
+ * Based on the linux driver code at drivers/scsi/megaraid
+ *
+ * Copyright (c) 2009-2012 Hannes Reinecke, SUSE Labs
+ *
+ * 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/hw.h"
+#include "hw/pci/pci.h"
+#include "sysemu/dma.h"
+#include "hw/pci/msix.h"
+#include "qemu/iov.h"
+#include "hw/scsi/scsi.h"
+#include "block/scsi.h"
+#include "trace.h"
+
+#include "mfi.h"
+
+#define MEGASAS_VERSION "1.70"
+#define MEGASAS_MAX_FRAMES 2048         /* Firmware limit at 65535 */
+#define MEGASAS_DEFAULT_FRAMES 1000     /* Windows requires this */
+#define MEGASAS_MAX_SGE 128             /* Firmware limit */
+#define MEGASAS_DEFAULT_SGE 80
+#define MEGASAS_MAX_SECTORS 0xFFFF      /* No real limit */
+#define MEGASAS_MAX_ARRAYS 128
+
+#define MEGASAS_HBA_SERIAL "QEMU123456"
+#define NAA_LOCALLY_ASSIGNED_ID 0x3ULL
+#define IEEE_COMPANY_LOCALLY_ASSIGNED 0x525400
+
+#define MEGASAS_FLAG_USE_JBOD      0
+#define MEGASAS_MASK_USE_JBOD      (1 << MEGASAS_FLAG_USE_JBOD)
+#define MEGASAS_FLAG_USE_MSIX      1
+#define MEGASAS_MASK_USE_MSIX      (1 << MEGASAS_FLAG_USE_MSIX)
+#define MEGASAS_FLAG_USE_QUEUE64   2
+#define MEGASAS_MASK_USE_QUEUE64   (1 << MEGASAS_FLAG_USE_QUEUE64)
+
+static const char *mfi_frame_desc[] = {
+    "MFI init", "LD Read", "LD Write", "LD SCSI", "PD SCSI",
+    "MFI Doorbell", "MFI Abort", "MFI SMP", "MFI Stop"};
+
+typedef struct MegasasCmd {
+    uint32_t index;
+    uint16_t flags;
+    uint16_t count;
+    uint64_t context;
+
+    hwaddr pa;
+    hwaddr pa_size;
+    union mfi_frame *frame;
+    SCSIRequest *req;
+    QEMUSGList qsg;
+    void *iov_buf;
+    size_t iov_size;
+    size_t iov_offset;
+    struct MegasasState *state;
+} MegasasCmd;
+
+typedef struct MegasasState {
+    PCIDevice dev;
+    MemoryRegion mmio_io;
+    MemoryRegion port_io;
+    MemoryRegion queue_io;
+    uint32_t frame_hi;
+
+    int fw_state;
+    uint32_t fw_sge;
+    uint32_t fw_cmds;
+    uint32_t flags;
+    int fw_luns;
+    int intr_mask;
+    int doorbell;
+    int busy;
+
+    MegasasCmd *event_cmd;
+    int event_locale;
+    int event_class;
+    int event_count;
+    int shutdown_event;
+    int boot_event;
+
+    uint64_t sas_addr;
+    char *hba_serial;
+
+    uint64_t reply_queue_pa;
+    void *reply_queue;
+    int reply_queue_len;
+    int reply_queue_head;
+    int reply_queue_tail;
+    uint64_t consumer_pa;
+    uint64_t producer_pa;
+
+    MegasasCmd frames[MEGASAS_MAX_FRAMES];
+
+    SCSIBus bus;
+} MegasasState;
+
+#define MEGASAS_INTR_DISABLED_MASK 0xFFFFFFFF
+
+static bool megasas_intr_enabled(MegasasState *s)
+{
+    if ((s->intr_mask & MEGASAS_INTR_DISABLED_MASK) !=
+        MEGASAS_INTR_DISABLED_MASK) {
+        return true;
+    }
+    return false;
+}
+
+static bool megasas_use_queue64(MegasasState *s)
+{
+    return s->flags & MEGASAS_MASK_USE_QUEUE64;
+}
+
+static bool megasas_use_msix(MegasasState *s)
+{
+    return s->flags & MEGASAS_MASK_USE_MSIX;
+}
+
+static bool megasas_is_jbod(MegasasState *s)
+{
+    return s->flags & MEGASAS_MASK_USE_JBOD;
+}
+
+static void megasas_frame_set_cmd_status(unsigned long frame, uint8_t v)
+{
+    stb_phys(frame + offsetof(struct mfi_frame_header, cmd_status), v);
+}
+
+static void megasas_frame_set_scsi_status(unsigned long frame, uint8_t v)
+{
+    stb_phys(frame + offsetof(struct mfi_frame_header, scsi_status), v);
+}
+
+/*
+ * Context is considered opaque, but the HBA firmware is running
+ * in little endian mode. So convert it to little endian, too.
+ */
+static uint64_t megasas_frame_get_context(unsigned long frame)
+{
+    return ldq_le_phys(frame + offsetof(struct mfi_frame_header, context));
+}
+
+static bool megasas_frame_is_ieee_sgl(MegasasCmd *cmd)
+{
+    return cmd->flags & MFI_FRAME_IEEE_SGL;
+}
+
+static bool megasas_frame_is_sgl64(MegasasCmd *cmd)
+{
+    return cmd->flags & MFI_FRAME_SGL64;
+}
+
+static bool megasas_frame_is_sense64(MegasasCmd *cmd)
+{
+    return cmd->flags & MFI_FRAME_SENSE64;
+}
+
+static uint64_t megasas_sgl_get_addr(MegasasCmd *cmd,
+                                     union mfi_sgl *sgl)
+{
+    uint64_t addr;
+
+    if (megasas_frame_is_ieee_sgl(cmd)) {
+        addr = le64_to_cpu(sgl->sg_skinny->addr);
+    } else if (megasas_frame_is_sgl64(cmd)) {
+        addr = le64_to_cpu(sgl->sg64->addr);
+    } else {
+        addr = le32_to_cpu(sgl->sg32->addr);
+    }
+    return addr;
+}
+
+static uint32_t megasas_sgl_get_len(MegasasCmd *cmd,
+                                    union mfi_sgl *sgl)
+{
+    uint32_t len;
+
+    if (megasas_frame_is_ieee_sgl(cmd)) {
+        len = le32_to_cpu(sgl->sg_skinny->len);
+    } else if (megasas_frame_is_sgl64(cmd)) {
+        len = le32_to_cpu(sgl->sg64->len);
+    } else {
+        len = le32_to_cpu(sgl->sg32->len);
+    }
+    return len;
+}
+
+static union mfi_sgl *megasas_sgl_next(MegasasCmd *cmd,
+                                       union mfi_sgl *sgl)
+{
+    uint8_t *next = (uint8_t *)sgl;
+
+    if (megasas_frame_is_ieee_sgl(cmd)) {
+        next += sizeof(struct mfi_sg_skinny);
+    } else if (megasas_frame_is_sgl64(cmd)) {
+        next += sizeof(struct mfi_sg64);
+    } else {
+        next += sizeof(struct mfi_sg32);
+    }
+
+    if (next >= (uint8_t *)cmd->frame + cmd->pa_size) {
+        return NULL;
+    }
+    return (union mfi_sgl *)next;
+}
+
+static void megasas_soft_reset(MegasasState *s);
+
+static int megasas_map_sgl(MegasasState *s, MegasasCmd *cmd, union mfi_sgl *sgl)
+{
+    int i;
+    int iov_count = 0;
+    size_t iov_size = 0;
+
+    cmd->flags = le16_to_cpu(cmd->frame->header.flags);
+    iov_count = cmd->frame->header.sge_count;
+    if (iov_count > MEGASAS_MAX_SGE) {
+        trace_megasas_iovec_sgl_overflow(cmd->index, iov_count,
+                                         MEGASAS_MAX_SGE);
+        return iov_count;
+    }
+    qemu_sglist_init(&cmd->qsg, iov_count, pci_dma_context(&s->dev));
+    for (i = 0; i < iov_count; i++) {
+        dma_addr_t iov_pa, iov_size_p;
+
+        if (!sgl) {
+            trace_megasas_iovec_sgl_underflow(cmd->index, i);
+            goto unmap;
+        }
+        iov_pa = megasas_sgl_get_addr(cmd, sgl);
+        iov_size_p = megasas_sgl_get_len(cmd, sgl);
+        if (!iov_pa || !iov_size_p) {
+            trace_megasas_iovec_sgl_invalid(cmd->index, i,
+                                            iov_pa, iov_size_p);
+            goto unmap;
+        }
+        qemu_sglist_add(&cmd->qsg, iov_pa, iov_size_p);
+        sgl = megasas_sgl_next(cmd, sgl);
+        iov_size += (size_t)iov_size_p;
+    }
+    if (cmd->iov_size > iov_size) {
+        trace_megasas_iovec_overflow(cmd->index, iov_size, cmd->iov_size);
+    } else if (cmd->iov_size < iov_size) {
+        trace_megasas_iovec_underflow(cmd->iov_size, iov_size, cmd->iov_size);
+    }
+    cmd->iov_offset = 0;
+    return 0;
+unmap:
+    qemu_sglist_destroy(&cmd->qsg);
+    return iov_count - i;
+}
+
+static void megasas_unmap_sgl(MegasasCmd *cmd)
+{
+    qemu_sglist_destroy(&cmd->qsg);
+    cmd->iov_offset = 0;
+}
+
+/*
+ * passthrough sense and io sense are at the same offset
+ */
+static int megasas_build_sense(MegasasCmd *cmd, uint8_t *sense_ptr,
+    uint8_t sense_len)
+{
+    uint32_t pa_hi = 0, pa_lo;
+    hwaddr pa;
+
+    if (sense_len > cmd->frame->header.sense_len) {
+        sense_len = cmd->frame->header.sense_len;
+    }
+    if (sense_len) {
+        pa_lo = le32_to_cpu(cmd->frame->pass.sense_addr_lo);
+        if (megasas_frame_is_sense64(cmd)) {
+            pa_hi = le32_to_cpu(cmd->frame->pass.sense_addr_hi);
+        }
+        pa = ((uint64_t) pa_hi << 32) | pa_lo;
+        cpu_physical_memory_write(pa, sense_ptr, sense_len);
+        cmd->frame->header.sense_len = sense_len;
+    }
+    return sense_len;
+}
+
+static void megasas_write_sense(MegasasCmd *cmd, SCSISense sense)
+{
+    uint8_t sense_buf[SCSI_SENSE_BUF_SIZE];
+    uint8_t sense_len = 18;
+
+    memset(sense_buf, 0, sense_len);
+    sense_buf[0] = 0xf0;
+    sense_buf[2] = sense.key;
+    sense_buf[7] = 10;
+    sense_buf[12] = sense.asc;
+    sense_buf[13] = sense.ascq;
+    megasas_build_sense(cmd, sense_buf, sense_len);
+}
+
+static void megasas_copy_sense(MegasasCmd *cmd)
+{
+    uint8_t sense_buf[SCSI_SENSE_BUF_SIZE];
+    uint8_t sense_len;
+
+    sense_len = scsi_req_get_sense(cmd->req, sense_buf,
+                                   SCSI_SENSE_BUF_SIZE);
+    megasas_build_sense(cmd, sense_buf, sense_len);
+}
+
+/*
+ * Format an INQUIRY CDB
+ */
+static int megasas_setup_inquiry(uint8_t *cdb, int pg, int len)
+{
+    memset(cdb, 0, 6);
+    cdb[0] = INQUIRY;
+    if (pg > 0) {
+        cdb[1] = 0x1;
+        cdb[2] = pg;
+    }
+    cdb[3] = (len >> 8) & 0xff;
+    cdb[4] = (len & 0xff);
+    return len;
+}
+
+/*
+ * Encode lba and len into a READ_16/WRITE_16 CDB
+ */
+static void megasas_encode_lba(uint8_t *cdb, uint64_t lba,
+                               uint32_t len, bool is_write)
+{
+    memset(cdb, 0x0, 16);
+    if (is_write) {
+        cdb[0] = WRITE_16;
+    } else {
+        cdb[0] = READ_16;
+    }
+    cdb[2] = (lba >> 56) & 0xff;
+    cdb[3] = (lba >> 48) & 0xff;
+    cdb[4] = (lba >> 40) & 0xff;
+    cdb[5] = (lba >> 32) & 0xff;
+    cdb[6] = (lba >> 24) & 0xff;
+    cdb[7] = (lba >> 16) & 0xff;
+    cdb[8] = (lba >> 8) & 0xff;
+    cdb[9] = (lba) & 0xff;
+    cdb[10] = (len >> 24) & 0xff;
+    cdb[11] = (len >> 16) & 0xff;
+    cdb[12] = (len >> 8) & 0xff;
+    cdb[13] = (len) & 0xff;
+}
+
+/*
+ * Utility functions
+ */
+static uint64_t megasas_fw_time(void)
+{
+    struct tm curtime;
+    uint64_t bcd_time;
+
+    qemu_get_timedate(&curtime, 0);
+    bcd_time = ((uint64_t)curtime.tm_sec & 0xff) << 48 |
+        ((uint64_t)curtime.tm_min & 0xff)  << 40 |
+        ((uint64_t)curtime.tm_hour & 0xff) << 32 |
+        ((uint64_t)curtime.tm_mday & 0xff) << 24 |
+        ((uint64_t)curtime.tm_mon & 0xff)  << 16 |
+        ((uint64_t)(curtime.tm_year + 1900) & 0xffff);
+
+    return bcd_time;
+}
+
+/*
+ * Default disk sata address
+ * 0x1221 is the magic number as
+ * present in real hardware,
+ * so use it here, too.
+ */
+static uint64_t megasas_get_sata_addr(uint16_t id)
+{
+    uint64_t addr = (0x1221ULL << 48);
+    return addr & (id << 24);
+}
+
+/*
+ * Frame handling
+ */
+static int megasas_next_index(MegasasState *s, int index, int limit)
+{
+    index++;
+    if (index == limit) {
+        index = 0;
+    }
+    return index;
+}
+
+static MegasasCmd *megasas_lookup_frame(MegasasState *s,
+    hwaddr frame)
+{
+    MegasasCmd *cmd = NULL;
+    int num = 0, index;
+
+    index = s->reply_queue_head;
+
+    while (num < s->fw_cmds) {
+        if (s->frames[index].pa && s->frames[index].pa == frame) {
+            cmd = &s->frames[index];
+            break;
+        }
+        index = megasas_next_index(s, index, s->fw_cmds);
+        num++;
+    }
+
+    return cmd;
+}
+
+static MegasasCmd *megasas_next_frame(MegasasState *s,
+    hwaddr frame)
+{
+    MegasasCmd *cmd = NULL;
+    int num = 0, index;
+
+    cmd = megasas_lookup_frame(s, frame);
+    if (cmd) {
+        trace_megasas_qf_found(cmd->index, cmd->pa);
+        return cmd;
+    }
+    index = s->reply_queue_head;
+    num = 0;
+    while (num < s->fw_cmds) {
+        if (!s->frames[index].pa) {
+            cmd = &s->frames[index];
+            break;
+        }
+        index = megasas_next_index(s, index, s->fw_cmds);
+        num++;
+    }
+    if (!cmd) {
+        trace_megasas_qf_failed(frame);
+    }
+    trace_megasas_qf_new(index, cmd);
+    return cmd;
+}
+
+static MegasasCmd *megasas_enqueue_frame(MegasasState *s,
+    hwaddr frame, uint64_t context, int count)
+{
+    MegasasCmd *cmd = NULL;
+    int frame_size = MFI_FRAME_SIZE * 16;
+    hwaddr frame_size_p = frame_size;
+
+    cmd = megasas_next_frame(s, frame);
+    /* All frames busy */
+    if (!cmd) {
+        return NULL;
+    }
+    if (!cmd->pa) {
+        cmd->pa = frame;
+        /* Map all possible frames */
+        cmd->frame = cpu_physical_memory_map(frame, &frame_size_p, 0);
+        if (frame_size_p != frame_size) {
+            trace_megasas_qf_map_failed(cmd->index, (unsigned long)frame);
+            if (cmd->frame) {
+                cpu_physical_memory_unmap(cmd->frame, frame_size_p, 0, 0);
+                cmd->frame = NULL;
+                cmd->pa = 0;
+            }
+            s->event_count++;
+            return NULL;
+        }
+        cmd->pa_size = frame_size_p;
+        cmd->context = context;
+        if (!megasas_use_queue64(s)) {
+            cmd->context &= (uint64_t)0xFFFFFFFF;
+        }
+    }
+    cmd->count = count;
+    s->busy++;
+
+    trace_megasas_qf_enqueue(cmd->index, cmd->count, cmd->context,
+                             s->reply_queue_head, s->busy);
+
+    return cmd;
+}
+
+static void megasas_complete_frame(MegasasState *s, uint64_t context)
+{
+    int tail, queue_offset;
+
+    /* Decrement busy count */
+    s->busy--;
+
+    if (s->reply_queue_pa) {
+        /*
+         * Put command on the reply queue.
+         * Context is opaque, but emulation is running in
+         * little endian. So convert it.
+         */
+        tail = s->reply_queue_head;
+        if (megasas_use_queue64(s)) {
+            queue_offset = tail * sizeof(uint64_t);
+            stq_le_phys(s->reply_queue_pa + queue_offset, context);
+        } else {
+            queue_offset = tail * sizeof(uint32_t);
+            stl_le_phys(s->reply_queue_pa + queue_offset, context);
+        }
+        s->reply_queue_head = megasas_next_index(s, tail, s->fw_cmds);
+        trace_megasas_qf_complete(context, tail, queue_offset,
+                                  s->busy, s->doorbell);
+    }
+
+    if (megasas_intr_enabled(s)) {
+        /* Notify HBA */
+        s->doorbell++;
+        if (s->doorbell == 1) {
+            if (msix_enabled(&s->dev)) {
+                trace_megasas_msix_raise(0);
+                msix_notify(&s->dev, 0);
+            } else {
+                trace_megasas_irq_raise();
+                qemu_irq_raise(s->dev.irq[0]);
+            }
+        }
+    } else {
+        trace_megasas_qf_complete_noirq(context);
+    }
+}
+
+static void megasas_reset_frames(MegasasState *s)
+{
+    int i;
+    MegasasCmd *cmd;
+
+    for (i = 0; i < s->fw_cmds; i++) {
+        cmd = &s->frames[i];
+        if (cmd->pa) {
+            cpu_physical_memory_unmap(cmd->frame, cmd->pa_size, 0, 0);
+            cmd->frame = NULL;
+            cmd->pa = 0;
+        }
+    }
+}
+
+static void megasas_abort_command(MegasasCmd *cmd)
+{
+    if (cmd->req) {
+        scsi_req_cancel(cmd->req);
+        cmd->req = NULL;
+    }
+}
+
+static int megasas_init_firmware(MegasasState *s, MegasasCmd *cmd)
+{
+    uint32_t pa_hi, pa_lo;
+    hwaddr iq_pa, initq_size;
+    struct mfi_init_qinfo *initq;
+    uint32_t flags;
+    int ret = MFI_STAT_OK;
+
+    pa_lo = le32_to_cpu(cmd->frame->init.qinfo_new_addr_lo);
+    pa_hi = le32_to_cpu(cmd->frame->init.qinfo_new_addr_hi);
+    iq_pa = (((uint64_t) pa_hi << 32) | pa_lo);
+    trace_megasas_init_firmware((uint64_t)iq_pa);
+    initq_size = sizeof(*initq);
+    initq = cpu_physical_memory_map(iq_pa, &initq_size, 0);
+    if (!initq || initq_size != sizeof(*initq)) {
+        trace_megasas_initq_map_failed(cmd->index);
+        s->event_count++;
+        ret = MFI_STAT_MEMORY_NOT_AVAILABLE;
+        goto out;
+    }
+    s->reply_queue_len = le32_to_cpu(initq->rq_entries) & 0xFFFF;
+    if (s->reply_queue_len > s->fw_cmds) {
+        trace_megasas_initq_mismatch(s->reply_queue_len, s->fw_cmds);
+        s->event_count++;
+        ret = MFI_STAT_INVALID_PARAMETER;
+        goto out;
+    }
+    pa_lo = le32_to_cpu(initq->rq_addr_lo);
+    pa_hi = le32_to_cpu(initq->rq_addr_hi);
+    s->reply_queue_pa = ((uint64_t) pa_hi << 32) | pa_lo;
+    pa_lo = le32_to_cpu(initq->ci_addr_lo);
+    pa_hi = le32_to_cpu(initq->ci_addr_hi);
+    s->consumer_pa = ((uint64_t) pa_hi << 32) | pa_lo;
+    pa_lo = le32_to_cpu(initq->pi_addr_lo);
+    pa_hi = le32_to_cpu(initq->pi_addr_hi);
+    s->producer_pa = ((uint64_t) pa_hi << 32) | pa_lo;
+    s->reply_queue_head = ldl_le_phys(s->producer_pa);
+    s->reply_queue_tail = ldl_le_phys(s->consumer_pa);
+    flags = le32_to_cpu(initq->flags);
+    if (flags & MFI_QUEUE_FLAG_CONTEXT64) {
+        s->flags |= MEGASAS_MASK_USE_QUEUE64;
+    }
+    trace_megasas_init_queue((unsigned long)s->reply_queue_pa,
+                             s->reply_queue_len, s->reply_queue_head,
+                             s->reply_queue_tail, flags);
+    megasas_reset_frames(s);
+    s->fw_state = MFI_FWSTATE_OPERATIONAL;
+out:
+    if (initq) {
+        cpu_physical_memory_unmap(initq, initq_size, 0, 0);
+    }
+    return ret;
+}
+
+static int megasas_map_dcmd(MegasasState *s, MegasasCmd *cmd)
+{
+    dma_addr_t iov_pa, iov_size;
+
+    cmd->flags = le16_to_cpu(cmd->frame->header.flags);
+    if (!cmd->frame->header.sge_count) {
+        trace_megasas_dcmd_zero_sge(cmd->index);
+        cmd->iov_size = 0;
+        return 0;
+    } else if (cmd->frame->header.sge_count > 1) {
+        trace_megasas_dcmd_invalid_sge(cmd->index,
+                                       cmd->frame->header.sge_count);
+        cmd->iov_size = 0;
+        return -1;
+    }
+    iov_pa = megasas_sgl_get_addr(cmd, &cmd->frame->dcmd.sgl);
+    iov_size = megasas_sgl_get_len(cmd, &cmd->frame->dcmd.sgl);
+    qemu_sglist_init(&cmd->qsg, 1, pci_dma_context(&s->dev));
+    qemu_sglist_add(&cmd->qsg, iov_pa, iov_size);
+    cmd->iov_size = iov_size;
+    return cmd->iov_size;
+}
+
+static void megasas_finish_dcmd(MegasasCmd *cmd, uint32_t iov_size)
+{
+    trace_megasas_finish_dcmd(cmd->index, iov_size);
+
+    if (cmd->frame->header.sge_count) {
+        qemu_sglist_destroy(&cmd->qsg);
+    }
+    if (iov_size > cmd->iov_size) {
+        if (megasas_frame_is_ieee_sgl(cmd)) {
+            cmd->frame->dcmd.sgl.sg_skinny->len = cpu_to_le32(iov_size);
+        } else if (megasas_frame_is_sgl64(cmd)) {
+            cmd->frame->dcmd.sgl.sg64->len = cpu_to_le32(iov_size);
+        } else {
+            cmd->frame->dcmd.sgl.sg32->len = cpu_to_le32(iov_size);
+        }
+    }
+    cmd->iov_size = 0;
+}
+
+static int megasas_ctrl_get_info(MegasasState *s, MegasasCmd *cmd)
+{
+    struct mfi_ctrl_info info;
+    size_t dcmd_size = sizeof(info);
+    BusChild *kid;
+    int num_ld_disks = 0;
+    uint16_t sdev_id;
+
+    memset(&info, 0x0, cmd->iov_size);
+    if (cmd->iov_size < dcmd_size) {
+        trace_megasas_dcmd_invalid_xfer_len(cmd->index, cmd->iov_size,
+                                            dcmd_size);
+        return MFI_STAT_INVALID_PARAMETER;
+    }
+
+    info.pci.vendor = cpu_to_le16(PCI_VENDOR_ID_LSI_LOGIC);
+    info.pci.device = cpu_to_le16(PCI_DEVICE_ID_LSI_SAS1078);
+    info.pci.subvendor = cpu_to_le16(PCI_VENDOR_ID_LSI_LOGIC);
+    info.pci.subdevice = cpu_to_le16(0x1013);
+
+    /*
+     * For some reason the firmware supports
+     * only up to 8 device ports.
+     * Despite supporting a far larger number
+     * of devices for the physical devices.
+     * So just display the first 8 devices
+     * in the device port list, independent
+     * of how many logical devices are actually
+     * present.
+     */
+    info.host.type = MFI_INFO_HOST_PCIE;
+    info.device.type = MFI_INFO_DEV_SAS3G;
+    info.device.port_count = 8;
+    QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) {
+        SCSIDevice *sdev = DO_UPCAST(SCSIDevice, qdev, kid->child);
+
+        if (num_ld_disks < 8) {
+            sdev_id = ((sdev->id & 0xFF) >> 8) | (sdev->lun & 0xFF);
+            info.device.port_addr[num_ld_disks] =
+                cpu_to_le64(megasas_get_sata_addr(sdev_id));
+        }
+        num_ld_disks++;
+    }
+
+    memcpy(info.product_name, "MegaRAID SAS 8708EM2", 20);
+    snprintf(info.serial_number, 32, "%s", s->hba_serial);
+    snprintf(info.package_version, 0x60, "%s-QEMU", QEMU_VERSION);
+    memcpy(info.image_component[0].name, "APP", 3);
+    memcpy(info.image_component[0].version, MEGASAS_VERSION "-QEMU", 9);
+    memcpy(info.image_component[0].build_date, __DATE__, 11);
+    memcpy(info.image_component[0].build_time, __TIME__, 8);
+    info.image_component_count = 1;
+    if (s->dev.has_rom) {
+        uint8_t biosver[32];
+        uint8_t *ptr;
+
+        ptr = memory_region_get_ram_ptr(&s->dev.rom);
+        memcpy(biosver, ptr + 0x41, 31);
+        qemu_put_ram_ptr(ptr);
+        memcpy(info.image_component[1].name, "BIOS", 4);
+        memcpy(info.image_component[1].version, biosver,
+               strlen((const char *)biosver));
+        info.image_component_count++;
+    }
+    info.current_fw_time = cpu_to_le32(megasas_fw_time());
+    info.max_arms = 32;
+    info.max_spans = 8;
+    info.max_arrays = MEGASAS_MAX_ARRAYS;
+    info.max_lds = s->fw_luns;
+    info.max_cmds = cpu_to_le16(s->fw_cmds);
+    info.max_sg_elements = cpu_to_le16(s->fw_sge);
+    info.max_request_size = cpu_to_le32(MEGASAS_MAX_SECTORS);
+    info.lds_present = cpu_to_le16(num_ld_disks);
+    info.pd_present = cpu_to_le16(num_ld_disks);
+    info.pd_disks_present = cpu_to_le16(num_ld_disks);
+    info.hw_present = cpu_to_le32(MFI_INFO_HW_NVRAM |
+                                   MFI_INFO_HW_MEM |
+                                   MFI_INFO_HW_FLASH);
+    info.memory_size = cpu_to_le16(512);
+    info.nvram_size = cpu_to_le16(32);
+    info.flash_size = cpu_to_le16(16);
+    info.raid_levels = cpu_to_le32(MFI_INFO_RAID_0);
+    info.adapter_ops = cpu_to_le32(MFI_INFO_AOPS_RBLD_RATE |
+                                    MFI_INFO_AOPS_SELF_DIAGNOSTIC |
+                                    MFI_INFO_AOPS_MIXED_ARRAY);
+    info.ld_ops = cpu_to_le32(MFI_INFO_LDOPS_DISK_CACHE_POLICY |
+                               MFI_INFO_LDOPS_ACCESS_POLICY |
+                               MFI_INFO_LDOPS_IO_POLICY |
+                               MFI_INFO_LDOPS_WRITE_POLICY |
+                               MFI_INFO_LDOPS_READ_POLICY);
+    info.max_strips_per_io = cpu_to_le16(s->fw_sge);
+    info.stripe_sz_ops.min = 3;
+    info.stripe_sz_ops.max = ffs(MEGASAS_MAX_SECTORS + 1) - 1;
+    info.properties.pred_fail_poll_interval = cpu_to_le16(300);
+    info.properties.intr_throttle_cnt = cpu_to_le16(16);
+    info.properties.intr_throttle_timeout = cpu_to_le16(50);
+    info.properties.rebuild_rate = 30;
+    info.properties.patrol_read_rate = 30;
+    info.properties.bgi_rate = 30;
+    info.properties.cc_rate = 30;
+    info.properties.recon_rate = 30;
+    info.properties.cache_flush_interval = 4;
+    info.properties.spinup_drv_cnt = 2;
+    info.properties.spinup_delay = 6;
+    info.properties.ecc_bucket_size = 15;
+    info.properties.ecc_bucket_leak_rate = cpu_to_le16(1440);
+    info.properties.expose_encl_devices = 1;
+    info.properties.OnOffProperties = cpu_to_le32(MFI_CTRL_PROP_EnableJBOD);
+    info.pd_ops = cpu_to_le32(MFI_INFO_PDOPS_FORCE_ONLINE |
+                               MFI_INFO_PDOPS_FORCE_OFFLINE);
+    info.pd_mix_support = cpu_to_le32(MFI_INFO_PDMIX_SAS |
+                                       MFI_INFO_PDMIX_SATA |
+                                       MFI_INFO_PDMIX_LD);
+
+    cmd->iov_size -= dma_buf_read((uint8_t *)&info, dcmd_size, &cmd->qsg);
+    return MFI_STAT_OK;
+}
+
+static int megasas_mfc_get_defaults(MegasasState *s, MegasasCmd *cmd)
+{
+    struct mfi_defaults info;
+    size_t dcmd_size = sizeof(struct mfi_defaults);
+
+    memset(&info, 0x0, dcmd_size);
+    if (cmd->iov_size < dcmd_size) {
+        trace_megasas_dcmd_invalid_xfer_len(cmd->index, cmd->iov_size,
+                                            dcmd_size);
+        return MFI_STAT_INVALID_PARAMETER;
+    }
+
+    info.sas_addr = cpu_to_le64(s->sas_addr);
+    info.stripe_size = 3;
+    info.flush_time = 4;
+    info.background_rate = 30;
+    info.allow_mix_in_enclosure = 1;
+    info.allow_mix_in_ld = 1;
+    info.direct_pd_mapping = 1;
+    /* Enable for BIOS support */
+    info.bios_enumerate_lds = 1;
+    info.disable_ctrl_r = 1;
+    info.expose_enclosure_devices = 1;
+    info.disable_preboot_cli = 1;
+    info.cluster_disable = 1;
+
+    cmd->iov_size -= dma_buf_read((uint8_t *)&info, dcmd_size, &cmd->qsg);
+    return MFI_STAT_OK;
+}
+
+static int megasas_dcmd_get_bios_info(MegasasState *s, MegasasCmd *cmd)
+{
+    struct mfi_bios_data info;
+    size_t dcmd_size = sizeof(info);
+
+    memset(&info, 0x0, dcmd_size);
+    if (cmd->iov_size < dcmd_size) {
+        trace_megasas_dcmd_invalid_xfer_len(cmd->index, cmd->iov_size,
+                                            dcmd_size);
+        return MFI_STAT_INVALID_PARAMETER;
+    }
+    info.continue_on_error = 1;
+    info.verbose = 1;
+    if (megasas_is_jbod(s)) {
+        info.expose_all_drives = 1;
+    }
+
+    cmd->iov_size -= dma_buf_read((uint8_t *)&info, dcmd_size, &cmd->qsg);
+    return MFI_STAT_OK;
+}
+
+static int megasas_dcmd_get_fw_time(MegasasState *s, MegasasCmd *cmd)
+{
+    uint64_t fw_time;
+    size_t dcmd_size = sizeof(fw_time);
+
+    fw_time = cpu_to_le64(megasas_fw_time());
+
+    cmd->iov_size -= dma_buf_read((uint8_t *)&fw_time, dcmd_size, &cmd->qsg);
+    return MFI_STAT_OK;
+}
+
+static int megasas_dcmd_set_fw_time(MegasasState *s, MegasasCmd *cmd)
+{
+    uint64_t fw_time;
+
+    /* This is a dummy; setting of firmware time is not allowed */
+    memcpy(&fw_time, cmd->frame->dcmd.mbox, sizeof(fw_time));
+
+    trace_megasas_dcmd_set_fw_time(cmd->index, fw_time);
+    fw_time = cpu_to_le64(megasas_fw_time());
+    return MFI_STAT_OK;
+}
+
+static int megasas_event_info(MegasasState *s, MegasasCmd *cmd)
+{
+    struct mfi_evt_log_state info;
+    size_t dcmd_size = sizeof(info);
+
+    memset(&info, 0, dcmd_size);
+
+    info.newest_seq_num = cpu_to_le32(s->event_count);
+    info.shutdown_seq_num = cpu_to_le32(s->shutdown_event);
+    info.boot_seq_num = cpu_to_le32(s->boot_event);
+
+    cmd->iov_size -= dma_buf_read((uint8_t *)&info, dcmd_size, &cmd->qsg);
+    return MFI_STAT_OK;
+}
+
+static int megasas_event_wait(MegasasState *s, MegasasCmd *cmd)
+{
+    union mfi_evt event;
+
+    if (cmd->iov_size < sizeof(struct mfi_evt_detail)) {
+        trace_megasas_dcmd_invalid_xfer_len(cmd->index, cmd->iov_size,
+                                            sizeof(struct mfi_evt_detail));
+        return MFI_STAT_INVALID_PARAMETER;
+    }
+    s->event_count = cpu_to_le32(cmd->frame->dcmd.mbox[0]);
+    event.word = cpu_to_le32(cmd->frame->dcmd.mbox[4]);
+    s->event_locale = event.members.locale;
+    s->event_class = event.members.class;
+    s->event_cmd = cmd;
+    /* Decrease busy count; event frame doesn't count here */
+    s->busy--;
+    cmd->iov_size = sizeof(struct mfi_evt_detail);
+    return MFI_STAT_INVALID_STATUS;
+}
+
+static int megasas_dcmd_pd_get_list(MegasasState *s, MegasasCmd *cmd)
+{
+    struct mfi_pd_list info;
+    size_t dcmd_size = sizeof(info);
+    BusChild *kid;
+    uint32_t offset, dcmd_limit, num_pd_disks = 0, max_pd_disks;
+    uint16_t sdev_id;
+
+    memset(&info, 0, dcmd_size);
+    offset = 8;
+    dcmd_limit = offset + sizeof(struct mfi_pd_address);
+    if (cmd->iov_size < dcmd_limit) {
+        trace_megasas_dcmd_invalid_xfer_len(cmd->index, cmd->iov_size,
+                                            dcmd_limit);
+        return MFI_STAT_INVALID_PARAMETER;
+    }
+
+    max_pd_disks = (cmd->iov_size - offset) / sizeof(struct mfi_pd_address);
+    if (max_pd_disks > s->fw_luns) {
+        max_pd_disks = s->fw_luns;
+    }
+
+    QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) {
+        SCSIDevice *sdev = DO_UPCAST(SCSIDevice, qdev, kid->child);
+
+        sdev_id = ((sdev->id & 0xFF) >> 8) | (sdev->lun & 0xFF);
+        info.addr[num_pd_disks].device_id = cpu_to_le16(sdev_id);
+        info.addr[num_pd_disks].encl_device_id = 0xFFFF;
+        info.addr[num_pd_disks].encl_index = 0;
+        info.addr[num_pd_disks].slot_number = (sdev->id & 0xFF);
+        info.addr[num_pd_disks].scsi_dev_type = sdev->type;
+        info.addr[num_pd_disks].connect_port_bitmap = 0x1;
+        info.addr[num_pd_disks].sas_addr[0] =
+            cpu_to_le64(megasas_get_sata_addr(sdev_id));
+        num_pd_disks++;
+        offset += sizeof(struct mfi_pd_address);
+    }
+    trace_megasas_dcmd_pd_get_list(cmd->index, num_pd_disks,
+                                   max_pd_disks, offset);
+
+    info.size = cpu_to_le32(offset);
+    info.count = cpu_to_le32(num_pd_disks);
+
+    cmd->iov_size -= dma_buf_read((uint8_t *)&info, offset, &cmd->qsg);
+    return MFI_STAT_OK;
+}
+
+static int megasas_dcmd_pd_list_query(MegasasState *s, MegasasCmd *cmd)
+{
+    uint16_t flags;
+
+    /* mbox0 contains flags */
+    flags = le16_to_cpu(cmd->frame->dcmd.mbox[0]);
+    trace_megasas_dcmd_pd_list_query(cmd->index, flags);
+    if (flags == MR_PD_QUERY_TYPE_ALL ||
+        megasas_is_jbod(s)) {
+        return megasas_dcmd_pd_get_list(s, cmd);
+    }
+
+    return MFI_STAT_OK;
+}
+
+static int megasas_pd_get_info_submit(SCSIDevice *sdev, int lun,
+                                      MegasasCmd *cmd)
+{
+    struct mfi_pd_info *info = cmd->iov_buf;
+    size_t dcmd_size = sizeof(struct mfi_pd_info);
+    BlockConf *conf = &sdev->conf;
+    uint64_t pd_size;
+    uint16_t sdev_id = ((sdev->id & 0xFF) >> 8) | (lun & 0xFF);
+    uint8_t cmdbuf[6];
+    SCSIRequest *req;
+    size_t len, resid;
+
+    if (!cmd->iov_buf) {
+        cmd->iov_buf = g_malloc(dcmd_size);
+        memset(cmd->iov_buf, 0, dcmd_size);
+        info = cmd->iov_buf;
+        info->inquiry_data[0] = 0x7f; /* Force PQual 0x3, PType 0x1f */
+        info->vpd_page83[0] = 0x7f;
+        megasas_setup_inquiry(cmdbuf, 0, sizeof(info->inquiry_data));
+        req = scsi_req_new(sdev, cmd->index, lun, cmdbuf, cmd);
+        if (!req) {
+            trace_megasas_dcmd_req_alloc_failed(cmd->index,
+                                                "PD get info std inquiry");
+            g_free(cmd->iov_buf);
+            cmd->iov_buf = NULL;
+            return MFI_STAT_FLASH_ALLOC_FAIL;
+        }
+        trace_megasas_dcmd_internal_submit(cmd->index,
+                                           "PD get info std inquiry", lun);
+        len = scsi_req_enqueue(req);
+        if (len > 0) {
+            cmd->iov_size = len;
+            scsi_req_continue(req);
+        }
+        return MFI_STAT_INVALID_STATUS;
+    } else if (info->inquiry_data[0] != 0x7f && info->vpd_page83[0] == 0x7f) {
+        megasas_setup_inquiry(cmdbuf, 0x83, sizeof(info->vpd_page83));
+        req = scsi_req_new(sdev, cmd->index, lun, cmdbuf, cmd);
+        if (!req) {
+            trace_megasas_dcmd_req_alloc_failed(cmd->index,
+                                                "PD get info vpd inquiry");
+            return MFI_STAT_FLASH_ALLOC_FAIL;
+        }
+        trace_megasas_dcmd_internal_submit(cmd->index,
+                                           "PD get info vpd inquiry", lun);
+        len = scsi_req_enqueue(req);
+        if (len > 0) {
+            cmd->iov_size = len;
+            scsi_req_continue(req);
+        }
+        return MFI_STAT_INVALID_STATUS;
+    }
+    /* Finished, set FW state */
+    if ((info->inquiry_data[0] >> 5) == 0) {
+        if (megasas_is_jbod(cmd->state)) {
+            info->fw_state = cpu_to_le16(MFI_PD_STATE_SYSTEM);
+        } else {
+            info->fw_state = cpu_to_le16(MFI_PD_STATE_ONLINE);
+        }
+    } else {
+        info->fw_state = cpu_to_le16(MFI_PD_STATE_OFFLINE);
+    }
+
+    info->ref.v.device_id = cpu_to_le16(sdev_id);
+    info->state.ddf.pd_type = cpu_to_le16(MFI_PD_DDF_TYPE_IN_VD|
+                                          MFI_PD_DDF_TYPE_INTF_SAS);
+    bdrv_get_geometry(conf->bs, &pd_size);
+    info->raw_size = cpu_to_le64(pd_size);
+    info->non_coerced_size = cpu_to_le64(pd_size);
+    info->coerced_size = cpu_to_le64(pd_size);
+    info->encl_device_id = 0xFFFF;
+    info->slot_number = (sdev->id & 0xFF);
+    info->path_info.count = 1;
+    info->path_info.sas_addr[0] =
+        cpu_to_le64(megasas_get_sata_addr(sdev_id));
+    info->connected_port_bitmap = 0x1;
+    info->device_speed = 1;
+    info->link_speed = 1;
+    resid = dma_buf_read(cmd->iov_buf, dcmd_size, &cmd->qsg);
+    g_free(cmd->iov_buf);
+    cmd->iov_size = dcmd_size - resid;
+    cmd->iov_buf = NULL;
+    return MFI_STAT_OK;
+}
+
+static int megasas_dcmd_pd_get_info(MegasasState *s, MegasasCmd *cmd)
+{
+    size_t dcmd_size = sizeof(struct mfi_pd_info);
+    uint16_t pd_id;
+    SCSIDevice *sdev = NULL;
+    int retval = MFI_STAT_DEVICE_NOT_FOUND;
+
+    if (cmd->iov_size < dcmd_size) {
+        return MFI_STAT_INVALID_PARAMETER;
+    }
+
+    /* mbox0 has the ID */
+    pd_id = le16_to_cpu(cmd->frame->dcmd.mbox[0]);
+    sdev = scsi_device_find(&s->bus, 0, pd_id, 0);
+    trace_megasas_dcmd_pd_get_info(cmd->index, pd_id);
+
+    if (sdev) {
+        /* Submit inquiry */
+        retval = megasas_pd_get_info_submit(sdev, pd_id, cmd);
+    }
+
+    return retval;
+}
+
+static int megasas_dcmd_ld_get_list(MegasasState *s, MegasasCmd *cmd)
+{
+    struct mfi_ld_list info;
+    size_t dcmd_size = sizeof(info), resid;
+    uint32_t num_ld_disks = 0, max_ld_disks = s->fw_luns;
+    uint64_t ld_size;
+    BusChild *kid;
+
+    memset(&info, 0, dcmd_size);
+    if (cmd->iov_size < dcmd_size) {
+        trace_megasas_dcmd_invalid_xfer_len(cmd->index, cmd->iov_size,
+                                            dcmd_size);
+        return MFI_STAT_INVALID_PARAMETER;
+    }
+
+    if (megasas_is_jbod(s)) {
+        max_ld_disks = 0;
+    }
+    QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) {
+        SCSIDevice *sdev = DO_UPCAST(SCSIDevice, qdev, kid->child);
+        BlockConf *conf = &sdev->conf;
+
+        if (num_ld_disks >= max_ld_disks) {
+            break;
+        }
+        /* Logical device size is in blocks */
+        bdrv_get_geometry(conf->bs, &ld_size);
+        info.ld_list[num_ld_disks].ld.v.target_id = sdev->id;
+        info.ld_list[num_ld_disks].ld.v.lun_id = sdev->lun;
+        info.ld_list[num_ld_disks].state = MFI_LD_STATE_OPTIMAL;
+        info.ld_list[num_ld_disks].size = cpu_to_le64(ld_size);
+        num_ld_disks++;
+    }
+    info.ld_count = cpu_to_le32(num_ld_disks);
+    trace_megasas_dcmd_ld_get_list(cmd->index, num_ld_disks, max_ld_disks);
+
+    resid = dma_buf_read((uint8_t *)&info, dcmd_size, &cmd->qsg);
+    cmd->iov_size = dcmd_size - resid;
+    return MFI_STAT_OK;
+}
+
+static int megasas_ld_get_info_submit(SCSIDevice *sdev, int lun,
+                                      MegasasCmd *cmd)
+{
+    struct mfi_ld_info *info = cmd->iov_buf;
+    size_t dcmd_size = sizeof(struct mfi_ld_info);
+    uint8_t cdb[6];
+    SCSIRequest *req;
+    ssize_t len, resid;
+    BlockConf *conf = &sdev->conf;
+    uint16_t sdev_id = ((sdev->id & 0xFF) >> 8) | (lun & 0xFF);
+    uint64_t ld_size;
+
+    if (!cmd->iov_buf) {
+        cmd->iov_buf = g_malloc(dcmd_size);
+        memset(cmd->iov_buf, 0x0, dcmd_size);
+        info = cmd->iov_buf;
+        megasas_setup_inquiry(cdb, 0x83, sizeof(info->vpd_page83));
+        req = scsi_req_new(sdev, cmd->index, lun, cdb, cmd);
+        if (!req) {
+            trace_megasas_dcmd_req_alloc_failed(cmd->index,
+                                                "LD get info vpd inquiry");
+            g_free(cmd->iov_buf);
+            cmd->iov_buf = NULL;
+            return MFI_STAT_FLASH_ALLOC_FAIL;
+        }
+        trace_megasas_dcmd_internal_submit(cmd->index,
+                                           "LD get info vpd inquiry", lun);
+        len = scsi_req_enqueue(req);
+        if (len > 0) {
+            cmd->iov_size = len;
+            scsi_req_continue(req);
+        }
+        return MFI_STAT_INVALID_STATUS;
+    }
+
+    info->ld_config.params.state = MFI_LD_STATE_OPTIMAL;
+    info->ld_config.properties.ld.v.target_id = lun;
+    info->ld_config.params.stripe_size = 3;
+    info->ld_config.params.num_drives = 1;
+    info->ld_config.params.is_consistent = 1;
+    /* Logical device size is in blocks */
+    bdrv_get_geometry(conf->bs, &ld_size);
+    info->size = cpu_to_le64(ld_size);
+    memset(info->ld_config.span, 0, sizeof(info->ld_config.span));
+    info->ld_config.span[0].start_block = 0;
+    info->ld_config.span[0].num_blocks = info->size;
+    info->ld_config.span[0].array_ref = cpu_to_le16(sdev_id);
+
+    resid = dma_buf_read(cmd->iov_buf, dcmd_size, &cmd->qsg);
+    g_free(cmd->iov_buf);
+    cmd->iov_size = dcmd_size - resid;
+    cmd->iov_buf = NULL;
+    return MFI_STAT_OK;
+}
+
+static int megasas_dcmd_ld_get_info(MegasasState *s, MegasasCmd *cmd)
+{
+    struct mfi_ld_info info;
+    size_t dcmd_size = sizeof(info);
+    uint16_t ld_id;
+    uint32_t max_ld_disks = s->fw_luns;
+    SCSIDevice *sdev = NULL;
+    int retval = MFI_STAT_DEVICE_NOT_FOUND;
+
+    if (cmd->iov_size < dcmd_size) {
+        return MFI_STAT_INVALID_PARAMETER;
+    }
+
+    /* mbox0 has the ID */
+    ld_id = le16_to_cpu(cmd->frame->dcmd.mbox[0]);
+    trace_megasas_dcmd_ld_get_info(cmd->index, ld_id);
+
+    if (megasas_is_jbod(s)) {
+        return MFI_STAT_DEVICE_NOT_FOUND;
+    }
+
+    if (ld_id < max_ld_disks) {
+        sdev = scsi_device_find(&s->bus, 0, ld_id, 0);
+    }
+
+    if (sdev) {
+        retval = megasas_ld_get_info_submit(sdev, ld_id, cmd);
+    }
+
+    return retval;
+}
+
+static int megasas_dcmd_cfg_read(MegasasState *s, MegasasCmd *cmd)
+{
+    uint8_t data[4096];
+    struct mfi_config_data *info;
+    int num_pd_disks = 0, array_offset, ld_offset;
+    BusChild *kid;
+
+    if (cmd->iov_size > 4096) {
+        return MFI_STAT_INVALID_PARAMETER;
+    }
+
+    QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) {
+        num_pd_disks++;
+    }
+    info = (struct mfi_config_data *)&data;
+    /*
+     * Array mapping:
+     * - One array per SCSI device
+     * - One logical drive per SCSI device
+     *   spanning the entire device
+     */
+    info->array_count = num_pd_disks;
+    info->array_size = sizeof(struct mfi_array) * num_pd_disks;
+    info->log_drv_count = num_pd_disks;
+    info->log_drv_size = sizeof(struct mfi_ld_config) * num_pd_disks;
+    info->spares_count = 0;
+    info->spares_size = sizeof(struct mfi_spare);
+    info->size = sizeof(struct mfi_config_data) + info->array_size +
+        info->log_drv_size;
+    if (info->size > 4096) {
+        return MFI_STAT_INVALID_PARAMETER;
+    }
+
+    array_offset = sizeof(struct mfi_config_data);
+    ld_offset = array_offset + sizeof(struct mfi_array) * num_pd_disks;
+
+    QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) {
+        SCSIDevice *sdev = DO_UPCAST(SCSIDevice, qdev, kid->child);
+        BlockConf *conf = &sdev->conf;
+        uint16_t sdev_id = ((sdev->id & 0xFF) >> 8) | (sdev->lun & 0xFF);
+        struct mfi_array *array;
+        struct mfi_ld_config *ld;
+        uint64_t pd_size;
+        int i;
+
+        array = (struct mfi_array *)(data + array_offset);
+        bdrv_get_geometry(conf->bs, &pd_size);
+        array->size = cpu_to_le64(pd_size);
+        array->num_drives = 1;
+        array->array_ref = cpu_to_le16(sdev_id);
+        array->pd[0].ref.v.device_id = cpu_to_le16(sdev_id);
+        array->pd[0].ref.v.seq_num = 0;
+        array->pd[0].fw_state = MFI_PD_STATE_ONLINE;
+        array->pd[0].encl.pd = 0xFF;
+        array->pd[0].encl.slot = (sdev->id & 0xFF);
+        for (i = 1; i < MFI_MAX_ROW_SIZE; i++) {
+            array->pd[i].ref.v.device_id = 0xFFFF;
+            array->pd[i].ref.v.seq_num = 0;
+            array->pd[i].fw_state = MFI_PD_STATE_UNCONFIGURED_GOOD;
+            array->pd[i].encl.pd = 0xFF;
+            array->pd[i].encl.slot = 0xFF;
+        }
+        array_offset += sizeof(struct mfi_array);
+        ld = (struct mfi_ld_config *)(data + ld_offset);
+        memset(ld, 0, sizeof(struct mfi_ld_config));
+        ld->properties.ld.v.target_id = (sdev->id & 0xFF);
+        ld->properties.default_cache_policy = MR_LD_CACHE_READ_AHEAD |
+            MR_LD_CACHE_READ_ADAPTIVE;
+        ld->properties.current_cache_policy = MR_LD_CACHE_READ_AHEAD |
+            MR_LD_CACHE_READ_ADAPTIVE;
+        ld->params.state = MFI_LD_STATE_OPTIMAL;
+        ld->params.stripe_size = 3;
+        ld->params.num_drives = 1;
+        ld->params.span_depth = 1;
+        ld->params.is_consistent = 1;
+        ld->span[0].start_block = 0;
+        ld->span[0].num_blocks = cpu_to_le64(pd_size);
+        ld->span[0].array_ref = cpu_to_le16(sdev_id);
+        ld_offset += sizeof(struct mfi_ld_config);
+    }
+
+    cmd->iov_size -= dma_buf_read((uint8_t *)data, info->size, &cmd->qsg);
+    return MFI_STAT_OK;
+}
+
+static int megasas_dcmd_get_properties(MegasasState *s, MegasasCmd *cmd)
+{
+    struct mfi_ctrl_props info;
+    size_t dcmd_size = sizeof(info);
+
+    memset(&info, 0x0, dcmd_size);
+    if (cmd->iov_size < dcmd_size) {
+        trace_megasas_dcmd_invalid_xfer_len(cmd->index, cmd->iov_size,
+                                            dcmd_size);
+        return MFI_STAT_INVALID_PARAMETER;
+    }
+    info.pred_fail_poll_interval = cpu_to_le16(300);
+    info.intr_throttle_cnt = cpu_to_le16(16);
+    info.intr_throttle_timeout = cpu_to_le16(50);
+    info.rebuild_rate = 30;
+    info.patrol_read_rate = 30;
+    info.bgi_rate = 30;
+    info.cc_rate = 30;
+    info.recon_rate = 30;
+    info.cache_flush_interval = 4;
+    info.spinup_drv_cnt = 2;
+    info.spinup_delay = 6;
+    info.ecc_bucket_size = 15;
+    info.ecc_bucket_leak_rate = cpu_to_le16(1440);
+    info.expose_encl_devices = 1;
+
+    cmd->iov_size -= dma_buf_read((uint8_t *)&info, dcmd_size, &cmd->qsg);
+    return MFI_STAT_OK;
+}
+
+static int megasas_cache_flush(MegasasState *s, MegasasCmd *cmd)
+{
+    bdrv_drain_all();
+    return MFI_STAT_OK;
+}
+
+static int megasas_ctrl_shutdown(MegasasState *s, MegasasCmd *cmd)
+{
+    s->fw_state = MFI_FWSTATE_READY;
+    return MFI_STAT_OK;
+}
+
+static int megasas_cluster_reset_ld(MegasasState *s, MegasasCmd *cmd)
+{
+    return MFI_STAT_INVALID_DCMD;
+}
+
+static int megasas_dcmd_set_properties(MegasasState *s, MegasasCmd *cmd)
+{
+    struct mfi_ctrl_props info;
+    size_t dcmd_size = sizeof(info);
+
+    if (cmd->iov_size < dcmd_size) {
+        trace_megasas_dcmd_invalid_xfer_len(cmd->index, cmd->iov_size,
+                                            dcmd_size);
+        return MFI_STAT_INVALID_PARAMETER;
+    }
+    dma_buf_write((uint8_t *)&info, cmd->iov_size, &cmd->qsg);
+    trace_megasas_dcmd_unsupported(cmd->index, cmd->iov_size);
+    return MFI_STAT_OK;
+}
+
+static int megasas_dcmd_dummy(MegasasState *s, MegasasCmd *cmd)
+{
+    trace_megasas_dcmd_dummy(cmd->index, cmd->iov_size);
+    return MFI_STAT_OK;
+}
+
+static const struct dcmd_cmd_tbl_t {
+    int opcode;
+    const char *desc;
+    int (*func)(MegasasState *s, MegasasCmd *cmd);
+} dcmd_cmd_tbl[] = {
+    { MFI_DCMD_CTRL_MFI_HOST_MEM_ALLOC, "CTRL_HOST_MEM_ALLOC",
+      megasas_dcmd_dummy },
+    { MFI_DCMD_CTRL_GET_INFO, "CTRL_GET_INFO",
+      megasas_ctrl_get_info },
+    { MFI_DCMD_CTRL_GET_PROPERTIES, "CTRL_GET_PROPERTIES",
+      megasas_dcmd_get_properties },
+    { MFI_DCMD_CTRL_SET_PROPERTIES, "CTRL_SET_PROPERTIES",
+      megasas_dcmd_set_properties },
+    { MFI_DCMD_CTRL_ALARM_GET, "CTRL_ALARM_GET",
+      megasas_dcmd_dummy },
+    { MFI_DCMD_CTRL_ALARM_ENABLE, "CTRL_ALARM_ENABLE",
+      megasas_dcmd_dummy },
+    { MFI_DCMD_CTRL_ALARM_DISABLE, "CTRL_ALARM_DISABLE",
+      megasas_dcmd_dummy },
+    { MFI_DCMD_CTRL_ALARM_SILENCE, "CTRL_ALARM_SILENCE",
+      megasas_dcmd_dummy },
+    { MFI_DCMD_CTRL_ALARM_TEST, "CTRL_ALARM_TEST",
+      megasas_dcmd_dummy },
+    { MFI_DCMD_CTRL_EVENT_GETINFO, "CTRL_EVENT_GETINFO",
+      megasas_event_info },
+    { MFI_DCMD_CTRL_EVENT_GET, "CTRL_EVENT_GET",
+      megasas_dcmd_dummy },
+    { MFI_DCMD_CTRL_EVENT_WAIT, "CTRL_EVENT_WAIT",
+      megasas_event_wait },
+    { MFI_DCMD_CTRL_SHUTDOWN, "CTRL_SHUTDOWN",
+      megasas_ctrl_shutdown },
+    { MFI_DCMD_HIBERNATE_STANDBY, "CTRL_STANDBY",
+      megasas_dcmd_dummy },
+    { MFI_DCMD_CTRL_GET_TIME, "CTRL_GET_TIME",
+      megasas_dcmd_get_fw_time },
+    { MFI_DCMD_CTRL_SET_TIME, "CTRL_SET_TIME",
+      megasas_dcmd_set_fw_time },
+    { MFI_DCMD_CTRL_BIOS_DATA_GET, "CTRL_BIOS_DATA_GET",
+      megasas_dcmd_get_bios_info },
+    { MFI_DCMD_CTRL_FACTORY_DEFAULTS, "CTRL_FACTORY_DEFAULTS",
+      megasas_dcmd_dummy },
+    { MFI_DCMD_CTRL_MFC_DEFAULTS_GET, "CTRL_MFC_DEFAULTS_GET",
+      megasas_mfc_get_defaults },
+    { MFI_DCMD_CTRL_MFC_DEFAULTS_SET, "CTRL_MFC_DEFAULTS_SET",
+      megasas_dcmd_dummy },
+    { MFI_DCMD_CTRL_CACHE_FLUSH, "CTRL_CACHE_FLUSH",
+      megasas_cache_flush },
+    { MFI_DCMD_PD_GET_LIST, "PD_GET_LIST",
+      megasas_dcmd_pd_get_list },
+    { MFI_DCMD_PD_LIST_QUERY, "PD_LIST_QUERY",
+      megasas_dcmd_pd_list_query },
+    { MFI_DCMD_PD_GET_INFO, "PD_GET_INFO",
+      megasas_dcmd_pd_get_info },
+    { MFI_DCMD_PD_STATE_SET, "PD_STATE_SET",
+      megasas_dcmd_dummy },
+    { MFI_DCMD_PD_REBUILD, "PD_REBUILD",
+      megasas_dcmd_dummy },
+    { MFI_DCMD_PD_BLINK, "PD_BLINK",
+      megasas_dcmd_dummy },
+    { MFI_DCMD_PD_UNBLINK, "PD_UNBLINK",
+      megasas_dcmd_dummy },
+    { MFI_DCMD_LD_GET_LIST, "LD_GET_LIST",
+      megasas_dcmd_ld_get_list},
+    { MFI_DCMD_LD_GET_INFO, "LD_GET_INFO",
+      megasas_dcmd_ld_get_info },
+    { MFI_DCMD_LD_GET_PROP, "LD_GET_PROP",
+      megasas_dcmd_dummy },
+    { MFI_DCMD_LD_SET_PROP, "LD_SET_PROP",
+      megasas_dcmd_dummy },
+    { MFI_DCMD_LD_DELETE, "LD_DELETE",
+      megasas_dcmd_dummy },
+    { MFI_DCMD_CFG_READ, "CFG_READ",
+      megasas_dcmd_cfg_read },
+    { MFI_DCMD_CFG_ADD, "CFG_ADD",
+      megasas_dcmd_dummy },
+    { MFI_DCMD_CFG_CLEAR, "CFG_CLEAR",
+      megasas_dcmd_dummy },
+    { MFI_DCMD_CFG_FOREIGN_READ, "CFG_FOREIGN_READ",
+      megasas_dcmd_dummy },
+    { MFI_DCMD_CFG_FOREIGN_IMPORT, "CFG_FOREIGN_IMPORT",
+      megasas_dcmd_dummy },
+    { MFI_DCMD_BBU_STATUS, "BBU_STATUS",
+      megasas_dcmd_dummy },
+    { MFI_DCMD_BBU_CAPACITY_INFO, "BBU_CAPACITY_INFO",
+      megasas_dcmd_dummy },
+    { MFI_DCMD_BBU_DESIGN_INFO, "BBU_DESIGN_INFO",
+      megasas_dcmd_dummy },
+    { MFI_DCMD_BBU_PROP_GET, "BBU_PROP_GET",
+      megasas_dcmd_dummy },
+    { MFI_DCMD_CLUSTER, "CLUSTER",
+      megasas_dcmd_dummy },
+    { MFI_DCMD_CLUSTER_RESET_ALL, "CLUSTER_RESET_ALL",
+      megasas_dcmd_dummy },
+    { MFI_DCMD_CLUSTER_RESET_LD, "CLUSTER_RESET_LD",
+      megasas_cluster_reset_ld },
+    { -1, NULL, NULL }
+};
+
+static int megasas_handle_dcmd(MegasasState *s, MegasasCmd *cmd)
+{
+    int opcode, len;
+    int retval = 0;
+    const struct dcmd_cmd_tbl_t *cmdptr = dcmd_cmd_tbl;
+
+    opcode = le32_to_cpu(cmd->frame->dcmd.opcode);
+    trace_megasas_handle_dcmd(cmd->index, opcode);
+    len = megasas_map_dcmd(s, cmd);
+    if (len < 0) {
+        return MFI_STAT_MEMORY_NOT_AVAILABLE;
+    }
+    while (cmdptr->opcode != -1 && cmdptr->opcode != opcode) {
+        cmdptr++;
+    }
+    if (cmdptr->opcode == -1) {
+        trace_megasas_dcmd_unhandled(cmd->index, opcode, len);
+        retval = megasas_dcmd_dummy(s, cmd);
+    } else {
+        trace_megasas_dcmd_enter(cmd->index, cmdptr->desc, len);
+        retval = cmdptr->func(s, cmd);
+    }
+    if (retval != MFI_STAT_INVALID_STATUS) {
+        megasas_finish_dcmd(cmd, len);
+    }
+    return retval;
+}
+
+static int megasas_finish_internal_dcmd(MegasasCmd *cmd,
+                                        SCSIRequest *req)
+{
+    int opcode;
+    int retval = MFI_STAT_OK;
+    int lun = req->lun;
+
+    opcode = le32_to_cpu(cmd->frame->dcmd.opcode);
+    scsi_req_unref(req);
+    trace_megasas_dcmd_internal_finish(cmd->index, opcode, lun);
+    switch (opcode) {
+    case MFI_DCMD_PD_GET_INFO:
+        retval = megasas_pd_get_info_submit(req->dev, lun, cmd);
+        break;
+    case MFI_DCMD_LD_GET_INFO:
+        retval = megasas_ld_get_info_submit(req->dev, lun, cmd);
+        break;
+    default:
+        trace_megasas_dcmd_internal_invalid(cmd->index, opcode);
+        retval = MFI_STAT_INVALID_DCMD;
+        break;
+    }
+    if (retval != MFI_STAT_INVALID_STATUS) {
+        megasas_finish_dcmd(cmd, cmd->iov_size);
+    }
+    return retval;
+}
+
+static int megasas_enqueue_req(MegasasCmd *cmd, bool is_write)
+{
+    int len;
+
+    len = scsi_req_enqueue(cmd->req);
+    if (len < 0) {
+        len = -len;
+    }
+    if (len > 0) {
+        if (len > cmd->iov_size) {
+            if (is_write) {
+                trace_megasas_iov_write_overflow(cmd->index, len,
+                                                 cmd->iov_size);
+            } else {
+                trace_megasas_iov_read_overflow(cmd->index, len,
+                                                cmd->iov_size);
+            }
+        }
+        if (len < cmd->iov_size) {
+            if (is_write) {
+                trace_megasas_iov_write_underflow(cmd->index, len,
+                                                  cmd->iov_size);
+            } else {
+                trace_megasas_iov_read_underflow(cmd->index, len,
+                                                 cmd->iov_size);
+            }
+            cmd->iov_size = len;
+        }
+        scsi_req_continue(cmd->req);
+    }
+    return len;
+}
+
+static int megasas_handle_scsi(MegasasState *s, MegasasCmd *cmd,
+                               bool is_logical)
+{
+    uint8_t *cdb;
+    int len;
+    bool is_write;
+    struct SCSIDevice *sdev = NULL;
+
+    cdb = cmd->frame->pass.cdb;
+
+    if (cmd->frame->header.target_id < s->fw_luns) {
+        sdev = scsi_device_find(&s->bus, 0, cmd->frame->header.target_id,
+                                cmd->frame->header.lun_id);
+    }
+    cmd->iov_size = le32_to_cpu(cmd->frame->header.data_len);
+    trace_megasas_handle_scsi(mfi_frame_desc[cmd->frame->header.frame_cmd],
+                              is_logical, cmd->frame->header.target_id,
+                              cmd->frame->header.lun_id, sdev, cmd->iov_size);
+
+    if (!sdev || (megasas_is_jbod(s) && is_logical)) {
+        trace_megasas_scsi_target_not_present(
+            mfi_frame_desc[cmd->frame->header.frame_cmd], is_logical,
+            cmd->frame->header.target_id, cmd->frame->header.lun_id);
+        return MFI_STAT_DEVICE_NOT_FOUND;
+    }
+
+    if (cmd->frame->header.cdb_len > 16) {
+        trace_megasas_scsi_invalid_cdb_len(
+                mfi_frame_desc[cmd->frame->header.frame_cmd], is_logical,
+                cmd->frame->header.target_id, cmd->frame->header.lun_id,
+                cmd->frame->header.cdb_len);
+        megasas_write_sense(cmd, SENSE_CODE(INVALID_OPCODE));
+        cmd->frame->header.scsi_status = CHECK_CONDITION;
+        s->event_count++;
+        return MFI_STAT_SCSI_DONE_WITH_ERROR;
+    }
+
+    if (megasas_map_sgl(s, cmd, &cmd->frame->pass.sgl)) {
+        megasas_write_sense(cmd, SENSE_CODE(TARGET_FAILURE));
+        cmd->frame->header.scsi_status = CHECK_CONDITION;
+        s->event_count++;
+        return MFI_STAT_SCSI_DONE_WITH_ERROR;
+    }
+
+    cmd->req = scsi_req_new(sdev, cmd->index,
+                            cmd->frame->header.lun_id, cdb, cmd);
+    if (!cmd->req) {
+        trace_megasas_scsi_req_alloc_failed(
+                mfi_frame_desc[cmd->frame->header.frame_cmd],
+                cmd->frame->header.target_id, cmd->frame->header.lun_id);
+        megasas_write_sense(cmd, SENSE_CODE(NO_SENSE));
+        cmd->frame->header.scsi_status = BUSY;
+        s->event_count++;
+        return MFI_STAT_SCSI_DONE_WITH_ERROR;
+    }
+
+    is_write = (cmd->req->cmd.mode == SCSI_XFER_TO_DEV);
+    len = megasas_enqueue_req(cmd, is_write);
+    if (len > 0) {
+        if (is_write) {
+            trace_megasas_scsi_write_start(cmd->index, len);
+        } else {
+            trace_megasas_scsi_read_start(cmd->index, len);
+        }
+    } else {
+        trace_megasas_scsi_nodata(cmd->index);
+    }
+    return MFI_STAT_INVALID_STATUS;
+}
+
+static int megasas_handle_io(MegasasState *s, MegasasCmd *cmd)
+{
+    uint32_t lba_count, lba_start_hi, lba_start_lo;
+    uint64_t lba_start;
+    bool is_write = (cmd->frame->header.frame_cmd == MFI_CMD_LD_WRITE);
+    uint8_t cdb[16];
+    int len;
+    struct SCSIDevice *sdev = NULL;
+
+    lba_count = le32_to_cpu(cmd->frame->io.header.data_len);
+    lba_start_lo = le32_to_cpu(cmd->frame->io.lba_lo);
+    lba_start_hi = le32_to_cpu(cmd->frame->io.lba_hi);
+    lba_start = ((uint64_t)lba_start_hi << 32) | lba_start_lo;
+
+    if (cmd->frame->header.target_id < s->fw_luns) {
+        sdev = scsi_device_find(&s->bus, 0, cmd->frame->header.target_id,
+                                cmd->frame->header.lun_id);
+    }
+
+    trace_megasas_handle_io(cmd->index,
+                            mfi_frame_desc[cmd->frame->header.frame_cmd],
+                            cmd->frame->header.target_id,
+                            cmd->frame->header.lun_id,
+                            (unsigned long)lba_start, (unsigned long)lba_count);
+    if (!sdev) {
+        trace_megasas_io_target_not_present(cmd->index,
+            mfi_frame_desc[cmd->frame->header.frame_cmd],
+            cmd->frame->header.target_id, cmd->frame->header.lun_id);
+        return MFI_STAT_DEVICE_NOT_FOUND;
+    }
+
+    if (cmd->frame->header.cdb_len > 16) {
+        trace_megasas_scsi_invalid_cdb_len(
+            mfi_frame_desc[cmd->frame->header.frame_cmd], 1,
+            cmd->frame->header.target_id, cmd->frame->header.lun_id,
+            cmd->frame->header.cdb_len);
+        megasas_write_sense(cmd, SENSE_CODE(INVALID_OPCODE));
+        cmd->frame->header.scsi_status = CHECK_CONDITION;
+        s->event_count++;
+        return MFI_STAT_SCSI_DONE_WITH_ERROR;
+    }
+
+    cmd->iov_size = lba_count * sdev->blocksize;
+    if (megasas_map_sgl(s, cmd, &cmd->frame->io.sgl)) {
+        megasas_write_sense(cmd, SENSE_CODE(TARGET_FAILURE));
+        cmd->frame->header.scsi_status = CHECK_CONDITION;
+        s->event_count++;
+        return MFI_STAT_SCSI_DONE_WITH_ERROR;
+    }
+
+    megasas_encode_lba(cdb, lba_start, lba_count, is_write);
+    cmd->req = scsi_req_new(sdev, cmd->index,
+                            cmd->frame->header.lun_id, cdb, cmd);
+    if (!cmd->req) {
+        trace_megasas_scsi_req_alloc_failed(
+            mfi_frame_desc[cmd->frame->header.frame_cmd],
+            cmd->frame->header.target_id, cmd->frame->header.lun_id);
+        megasas_write_sense(cmd, SENSE_CODE(NO_SENSE));
+        cmd->frame->header.scsi_status = BUSY;
+        s->event_count++;
+        return MFI_STAT_SCSI_DONE_WITH_ERROR;
+    }
+    len = megasas_enqueue_req(cmd, is_write);
+    if (len > 0) {
+        if (is_write) {
+            trace_megasas_io_write_start(cmd->index, lba_start, lba_count, len);
+        } else {
+            trace_megasas_io_read_start(cmd->index, lba_start, lba_count, len);
+        }
+    }
+    return MFI_STAT_INVALID_STATUS;
+}
+
+static int megasas_finish_internal_command(MegasasCmd *cmd,
+                                           SCSIRequest *req, size_t resid)
+{
+    int retval = MFI_STAT_INVALID_CMD;
+
+    if (cmd->frame->header.frame_cmd == MFI_CMD_DCMD) {
+        cmd->iov_size -= resid;
+        retval = megasas_finish_internal_dcmd(cmd, req);
+    }
+    return retval;
+}
+
+static QEMUSGList *megasas_get_sg_list(SCSIRequest *req)
+{
+    MegasasCmd *cmd = req->hba_private;
+
+    if (cmd->frame->header.frame_cmd == MFI_CMD_DCMD) {
+        return NULL;
+    } else {
+        return &cmd->qsg;
+    }
+}
+
+static void megasas_xfer_complete(SCSIRequest *req, uint32_t len)
+{
+    MegasasCmd *cmd = req->hba_private;
+    uint8_t *buf;
+    uint32_t opcode;
+
+    trace_megasas_io_complete(cmd->index, len);
+
+    if (cmd->frame->header.frame_cmd != MFI_CMD_DCMD) {
+        scsi_req_continue(req);
+        return;
+    }
+
+    buf = scsi_req_get_buf(req);
+    opcode = le32_to_cpu(cmd->frame->dcmd.opcode);
+    if (opcode == MFI_DCMD_PD_GET_INFO && cmd->iov_buf) {
+        struct mfi_pd_info *info = cmd->iov_buf;
+
+        if (info->inquiry_data[0] == 0x7f) {
+            memset(info->inquiry_data, 0, sizeof(info->inquiry_data));
+            memcpy(info->inquiry_data, buf, len);
+        } else if (info->vpd_page83[0] == 0x7f) {
+            memset(info->vpd_page83, 0, sizeof(info->vpd_page83));
+            memcpy(info->vpd_page83, buf, len);
+        }
+        scsi_req_continue(req);
+    } else if (opcode == MFI_DCMD_LD_GET_INFO) {
+        struct mfi_ld_info *info = cmd->iov_buf;
+
+        if (cmd->iov_buf) {
+            memcpy(info->vpd_page83, buf, sizeof(info->vpd_page83));
+            scsi_req_continue(req);
+        }
+    }
+}
+
+static void megasas_command_complete(SCSIRequest *req, uint32_t status,
+                                     size_t resid)
+{
+    MegasasCmd *cmd = req->hba_private;
+    uint8_t cmd_status = MFI_STAT_OK;
+
+    trace_megasas_command_complete(cmd->index, status, resid);
+
+    if (cmd->req != req) {
+        /*
+         * Internal command complete
+         */
+        cmd_status = megasas_finish_internal_command(cmd, req, resid);
+        if (cmd_status == MFI_STAT_INVALID_STATUS) {
+            return;
+        }
+    } else {
+        req->status = status;
+        trace_megasas_scsi_complete(cmd->index, req->status,
+                                    cmd->iov_size, req->cmd.xfer);
+        if (req->status != GOOD) {
+            cmd_status = MFI_STAT_SCSI_DONE_WITH_ERROR;
+        }
+        if (req->status == CHECK_CONDITION) {
+            megasas_copy_sense(cmd);
+        }
+
+        megasas_unmap_sgl(cmd);
+        cmd->frame->header.scsi_status = req->status;
+        scsi_req_unref(cmd->req);
+        cmd->req = NULL;
+    }
+    cmd->frame->header.cmd_status = cmd_status;
+    megasas_complete_frame(cmd->state, cmd->context);
+}
+
+static void megasas_command_cancel(SCSIRequest *req)
+{
+    MegasasCmd *cmd = req->hba_private;
+
+    if (cmd) {
+        megasas_abort_command(cmd);
+    } else {
+        scsi_req_unref(req);
+    }
+}
+
+static int megasas_handle_abort(MegasasState *s, MegasasCmd *cmd)
+{
+    uint64_t abort_ctx = le64_to_cpu(cmd->frame->abort.abort_context);
+    hwaddr abort_addr, addr_hi, addr_lo;
+    MegasasCmd *abort_cmd;
+
+    addr_hi = le32_to_cpu(cmd->frame->abort.abort_mfi_addr_hi);
+    addr_lo = le32_to_cpu(cmd->frame->abort.abort_mfi_addr_lo);
+    abort_addr = ((uint64_t)addr_hi << 32) | addr_lo;
+
+    abort_cmd = megasas_lookup_frame(s, abort_addr);
+    if (!abort_cmd) {
+        trace_megasas_abort_no_cmd(cmd->index, abort_ctx);
+        s->event_count++;
+        return MFI_STAT_OK;
+    }
+    if (!megasas_use_queue64(s)) {
+        abort_ctx &= (uint64_t)0xFFFFFFFF;
+    }
+    if (abort_cmd->context != abort_ctx) {
+        trace_megasas_abort_invalid_context(cmd->index, abort_cmd->index,
+                                            abort_cmd->context);
+        s->event_count++;
+        return MFI_STAT_ABORT_NOT_POSSIBLE;
+    }
+    trace_megasas_abort_frame(cmd->index, abort_cmd->index);
+    megasas_abort_command(abort_cmd);
+    if (!s->event_cmd || abort_cmd != s->event_cmd) {
+        s->event_cmd = NULL;
+    }
+    s->event_count++;
+    return MFI_STAT_OK;
+}
+
+static void megasas_handle_frame(MegasasState *s, uint64_t frame_addr,
+                                 uint32_t frame_count)
+{
+    uint8_t frame_status = MFI_STAT_INVALID_CMD;
+    uint64_t frame_context;
+    MegasasCmd *cmd;
+
+    /*
+     * Always read 64bit context, top bits will be
+     * masked out if required in megasas_enqueue_frame()
+     */
+    frame_context = megasas_frame_get_context(frame_addr);
+
+    cmd = megasas_enqueue_frame(s, frame_addr, frame_context, frame_count);
+    if (!cmd) {
+        /* reply queue full */
+        trace_megasas_frame_busy(frame_addr);
+        megasas_frame_set_scsi_status(frame_addr, BUSY);
+        megasas_frame_set_cmd_status(frame_addr, MFI_STAT_SCSI_DONE_WITH_ERROR);
+        megasas_complete_frame(s, frame_context);
+        s->event_count++;
+        return;
+    }
+    switch (cmd->frame->header.frame_cmd) {
+    case MFI_CMD_INIT:
+        frame_status = megasas_init_firmware(s, cmd);
+        break;
+    case MFI_CMD_DCMD:
+        frame_status = megasas_handle_dcmd(s, cmd);
+        break;
+    case MFI_CMD_ABORT:
+        frame_status = megasas_handle_abort(s, cmd);
+        break;
+    case MFI_CMD_PD_SCSI_IO:
+        frame_status = megasas_handle_scsi(s, cmd, 0);
+        break;
+    case MFI_CMD_LD_SCSI_IO:
+        frame_status = megasas_handle_scsi(s, cmd, 1);
+        break;
+    case MFI_CMD_LD_READ:
+    case MFI_CMD_LD_WRITE:
+        frame_status = megasas_handle_io(s, cmd);
+        break;
+    default:
+        trace_megasas_unhandled_frame_cmd(cmd->index,
+                                          cmd->frame->header.frame_cmd);
+        s->event_count++;
+        break;
+    }
+    if (frame_status != MFI_STAT_INVALID_STATUS) {
+        if (cmd->frame) {
+            cmd->frame->header.cmd_status = frame_status;
+        } else {
+            megasas_frame_set_cmd_status(frame_addr, frame_status);
+        }
+        megasas_complete_frame(s, cmd->context);
+    }
+}
+
+static uint64_t megasas_mmio_read(void *opaque, hwaddr addr,
+                                  unsigned size)
+{
+    MegasasState *s = opaque;
+    uint32_t retval = 0;
+
+    switch (addr) {
+    case MFI_IDB:
+        retval = 0;
+        break;
+    case MFI_OMSG0:
+    case MFI_OSP0:
+        retval = (megasas_use_msix(s) ? MFI_FWSTATE_MSIX_SUPPORTED : 0) |
+            (s->fw_state & MFI_FWSTATE_MASK) |
+            ((s->fw_sge & 0xff) << 16) |
+            (s->fw_cmds & 0xFFFF);
+        break;
+    case MFI_OSTS:
+        if (megasas_intr_enabled(s) && s->doorbell) {
+            retval = MFI_1078_RM | 1;
+        }
+        break;
+    case MFI_OMSK:
+        retval = s->intr_mask;
+        break;
+    case MFI_ODCR0:
+        retval = s->doorbell;
+        break;
+    default:
+        trace_megasas_mmio_invalid_readl(addr);
+        break;
+    }
+    trace_megasas_mmio_readl(addr, retval);
+    return retval;
+}
+
+static void megasas_mmio_write(void *opaque, hwaddr addr,
+                               uint64_t val, unsigned size)
+{
+    MegasasState *s = opaque;
+    uint64_t frame_addr;
+    uint32_t frame_count;
+    int i;
+
+    trace_megasas_mmio_writel(addr, val);
+    switch (addr) {
+    case MFI_IDB:
+        if (val & MFI_FWINIT_ABORT) {
+            /* Abort all pending cmds */
+            for (i = 0; i < s->fw_cmds; i++) {
+                megasas_abort_command(&s->frames[i]);
+            }
+        }
+        if (val & MFI_FWINIT_READY) {
+            /* move to FW READY */
+            megasas_soft_reset(s);
+        }
+        if (val & MFI_FWINIT_MFIMODE) {
+            /* discard MFIs */
+        }
+        break;
+    case MFI_OMSK:
+        s->intr_mask = val;
+        if (!megasas_intr_enabled(s) && !msix_enabled(&s->dev)) {
+            trace_megasas_irq_lower();
+            qemu_irq_lower(s->dev.irq[0]);
+        }
+        if (megasas_intr_enabled(s)) {
+            trace_megasas_intr_enabled();
+        } else {
+            trace_megasas_intr_disabled();
+        }
+        break;
+    case MFI_ODCR0:
+        s->doorbell = 0;
+        if (s->producer_pa && megasas_intr_enabled(s)) {
+            /* Update reply queue pointer */
+            trace_megasas_qf_update(s->reply_queue_head, s->busy);
+            stl_le_phys(s->producer_pa, s->reply_queue_head);
+            if (!msix_enabled(&s->dev)) {
+                trace_megasas_irq_lower();
+                qemu_irq_lower(s->dev.irq[0]);
+            }
+        }
+        break;
+    case MFI_IQPH:
+        /* Received high 32 bits of a 64 bit MFI frame address */
+        s->frame_hi = val;
+        break;
+    case MFI_IQPL:
+        /* Received low 32 bits of a 64 bit MFI frame address */
+    case MFI_IQP:
+        /* Received 32 bit MFI frame address */
+        frame_addr = (val & ~0x1F);
+        /* Add possible 64 bit offset */
+        frame_addr |= ((uint64_t)s->frame_hi << 32);
+        s->frame_hi = 0;
+        frame_count = (val >> 1) & 0xF;
+        megasas_handle_frame(s, frame_addr, frame_count);
+        break;
+    default:
+        trace_megasas_mmio_invalid_writel(addr, val);
+        break;
+    }
+}
+
+static const MemoryRegionOps megasas_mmio_ops = {
+    .read = megasas_mmio_read,
+    .write = megasas_mmio_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+        .min_access_size = 8,
+        .max_access_size = 8,
+    }
+};
+
+static uint64_t megasas_port_read(void *opaque, hwaddr addr,
+                                  unsigned size)
+{
+    return megasas_mmio_read(opaque, addr & 0xff, size);
+}
+
+static void megasas_port_write(void *opaque, hwaddr addr,
+                               uint64_t val, unsigned size)
+{
+    megasas_mmio_write(opaque, addr & 0xff, val, size);
+}
+
+static const MemoryRegionOps megasas_port_ops = {
+    .read = megasas_port_read,
+    .write = megasas_port_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    }
+};
+
+static uint64_t megasas_queue_read(void *opaque, hwaddr addr,
+                                   unsigned size)
+{
+    return 0;
+}
+
+static const MemoryRegionOps megasas_queue_ops = {
+    .read = megasas_queue_read,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .impl = {
+        .min_access_size = 8,
+        .max_access_size = 8,
+    }
+};
+
+static void megasas_soft_reset(MegasasState *s)
+{
+    int i;
+    MegasasCmd *cmd;
+
+    trace_megasas_reset();
+    for (i = 0; i < s->fw_cmds; i++) {
+        cmd = &s->frames[i];
+        megasas_abort_command(cmd);
+    }
+    megasas_reset_frames(s);
+    s->reply_queue_len = s->fw_cmds;
+    s->reply_queue_pa = 0;
+    s->consumer_pa = 0;
+    s->producer_pa = 0;
+    s->fw_state = MFI_FWSTATE_READY;
+    s->doorbell = 0;
+    s->intr_mask = MEGASAS_INTR_DISABLED_MASK;
+    s->frame_hi = 0;
+    s->flags &= ~MEGASAS_MASK_USE_QUEUE64;
+    s->event_count++;
+    s->boot_event = s->event_count;
+}
+
+static void megasas_scsi_reset(DeviceState *dev)
+{
+    MegasasState *s = DO_UPCAST(MegasasState, dev.qdev, dev);
+
+    megasas_soft_reset(s);
+}
+
+static const VMStateDescription vmstate_megasas = {
+    .name = "megasas",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields      = (VMStateField[]) {
+        VMSTATE_PCI_DEVICE(dev, MegasasState),
+
+        VMSTATE_INT32(fw_state, MegasasState),
+        VMSTATE_INT32(intr_mask, MegasasState),
+        VMSTATE_INT32(doorbell, MegasasState),
+        VMSTATE_UINT64(reply_queue_pa, MegasasState),
+        VMSTATE_UINT64(consumer_pa, MegasasState),
+        VMSTATE_UINT64(producer_pa, MegasasState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void megasas_scsi_uninit(PCIDevice *d)
+{
+    MegasasState *s = DO_UPCAST(MegasasState, dev, d);
+
+#ifdef USE_MSIX
+    msix_uninit(&s->dev, &s->mmio_io);
+#endif
+    memory_region_destroy(&s->mmio_io);
+    memory_region_destroy(&s->port_io);
+    memory_region_destroy(&s->queue_io);
+}
+
+static const struct SCSIBusInfo megasas_scsi_info = {
+    .tcq = true,
+    .max_target = MFI_MAX_LD,
+    .max_lun = 255,
+
+    .transfer_data = megasas_xfer_complete,
+    .get_sg_list = megasas_get_sg_list,
+    .complete = megasas_command_complete,
+    .cancel = megasas_command_cancel,
+};
+
+static int megasas_scsi_init(PCIDevice *dev)
+{
+    MegasasState *s = DO_UPCAST(MegasasState, dev, dev);
+    uint8_t *pci_conf;
+    int i, bar_type;
+
+    pci_conf = s->dev.config;
+
+    /* PCI latency timer = 0 */
+    pci_conf[PCI_LATENCY_TIMER] = 0;
+    /* Interrupt pin 1 */
+    pci_conf[PCI_INTERRUPT_PIN] = 0x01;
+
+    memory_region_init_io(&s->mmio_io, &megasas_mmio_ops, s,
+                          "megasas-mmio", 0x4000);
+    memory_region_init_io(&s->port_io, &megasas_port_ops, s,
+                          "megasas-io", 256);
+    memory_region_init_io(&s->queue_io, &megasas_queue_ops, s,
+                          "megasas-queue", 0x40000);
+
+#ifdef USE_MSIX
+    /* MSI-X support is currently broken */
+    if (megasas_use_msix(s) &&
+        msix_init(&s->dev, 15, &s->mmio_io, 0, 0x2000)) {
+        s->flags &= ~MEGASAS_MASK_USE_MSIX;
+    }
+#else
+    s->flags &= ~MEGASAS_MASK_USE_MSIX;
+#endif
+
+    bar_type = PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64;
+    pci_register_bar(&s->dev, 0, bar_type, &s->mmio_io);
+    pci_register_bar(&s->dev, 2, PCI_BASE_ADDRESS_SPACE_IO, &s->port_io);
+    pci_register_bar(&s->dev, 3, bar_type, &s->queue_io);
+
+    if (megasas_use_msix(s)) {
+        msix_vector_use(&s->dev, 0);
+    }
+
+    if (!s->sas_addr) {
+        s->sas_addr = ((NAA_LOCALLY_ASSIGNED_ID << 24) |
+                       IEEE_COMPANY_LOCALLY_ASSIGNED) << 36;
+        s->sas_addr |= (pci_bus_num(dev->bus) << 16);
+        s->sas_addr |= (PCI_SLOT(dev->devfn) << 8);
+        s->sas_addr |= PCI_FUNC(dev->devfn);
+    }
+    if (!s->hba_serial) {
+       s->hba_serial = g_strdup(MEGASAS_HBA_SERIAL);
+    }
+    if (s->fw_sge >= MEGASAS_MAX_SGE - MFI_PASS_FRAME_SIZE) {
+        s->fw_sge = MEGASAS_MAX_SGE - MFI_PASS_FRAME_SIZE;
+    } else if (s->fw_sge >= 128 - MFI_PASS_FRAME_SIZE) {
+        s->fw_sge = 128 - MFI_PASS_FRAME_SIZE;
+    } else {
+        s->fw_sge = 64 - MFI_PASS_FRAME_SIZE;
+    }
+    if (s->fw_cmds > MEGASAS_MAX_FRAMES) {
+        s->fw_cmds = MEGASAS_MAX_FRAMES;
+    }
+    trace_megasas_init(s->fw_sge, s->fw_cmds,
+                       megasas_use_msix(s) ? "MSI-X" : "INTx",
+                       megasas_is_jbod(s) ? "jbod" : "raid");
+    s->fw_luns = (MFI_MAX_LD > MAX_SCSI_DEVS) ?
+        MAX_SCSI_DEVS : MFI_MAX_LD;
+    s->producer_pa = 0;
+    s->consumer_pa = 0;
+    for (i = 0; i < s->fw_cmds; i++) {
+        s->frames[i].index = i;
+        s->frames[i].context = -1;
+        s->frames[i].pa = 0;
+        s->frames[i].state = s;
+    }
+
+    scsi_bus_new(&s->bus, &dev->qdev, &megasas_scsi_info);
+    scsi_bus_legacy_handle_cmdline(&s->bus);
+    return 0;
+}
+
+static Property megasas_properties[] = {
+    DEFINE_PROP_UINT32("max_sge", MegasasState, fw_sge,
+                       MEGASAS_DEFAULT_SGE),
+    DEFINE_PROP_UINT32("max_cmds", MegasasState, fw_cmds,
+                       MEGASAS_DEFAULT_FRAMES),
+    DEFINE_PROP_STRING("hba_serial", MegasasState, hba_serial),
+    DEFINE_PROP_HEX64("sas_address", MegasasState, sas_addr, 0),
+#ifdef USE_MSIX
+    DEFINE_PROP_BIT("use_msix", MegasasState, flags,
+                    MEGASAS_FLAG_USE_MSIX, false),
+#endif
+    DEFINE_PROP_BIT("use_jbod", MegasasState, flags,
+                    MEGASAS_FLAG_USE_JBOD, false),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void megasas_class_init(ObjectClass *oc, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(oc);
+    PCIDeviceClass *pc = PCI_DEVICE_CLASS(oc);
+
+    pc->init = megasas_scsi_init;
+    pc->exit = megasas_scsi_uninit;
+    pc->vendor_id = PCI_VENDOR_ID_LSI_LOGIC;
+    pc->device_id = PCI_DEVICE_ID_LSI_SAS1078;
+    pc->subsystem_vendor_id = PCI_VENDOR_ID_LSI_LOGIC;
+    pc->subsystem_id = 0x1013;
+    pc->class_id = PCI_CLASS_STORAGE_RAID;
+    dc->props = megasas_properties;
+    dc->reset = megasas_scsi_reset;
+    dc->vmsd = &vmstate_megasas;
+    dc->desc = "LSI MegaRAID SAS 1078";
+}
+
+static const TypeInfo megasas_info = {
+    .name  = "megasas",
+    .parent = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(MegasasState),
+    .class_init = megasas_class_init,
+};
+
+static void megasas_register_types(void)
+{
+    type_register_static(&megasas_info);
+}
+
+type_init(megasas_register_types)
diff --git a/hw/scsi/mfi.h b/hw/scsi/mfi.h
new file mode 100644 (file)
index 0000000..cd8355b
--- /dev/null
@@ -0,0 +1,1249 @@
+/*
+ * NetBSD header file, copied from
+ * http://gitorious.org/freebsd/freebsd/blobs/HEAD/sys/dev/mfi/mfireg.h
+ */
+/*-
+ * Copyright (c) 2006 IronPort Systems
+ * Copyright (c) 2007 LSI Corp.
+ * Copyright (c) 2007 Rajesh Prabhakaran.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef MFI_REG_H
+#define MFI_REG_H
+
+/*
+ * MegaRAID SAS MFI firmware definitions
+ */
+
+/*
+ * Start with the register set.  All registers are 32 bits wide.
+ * The usual Intel IOP style setup.
+ */
+#define MFI_IMSG0 0x10    /* Inbound message 0 */
+#define MFI_IMSG1 0x14    /* Inbound message 1 */
+#define MFI_OMSG0 0x18    /* Outbound message 0 */
+#define MFI_OMSG1 0x1c    /* Outbound message 1 */
+#define MFI_IDB   0x20    /* Inbound doorbell */
+#define MFI_ISTS  0x24    /* Inbound interrupt status */
+#define MFI_IMSK  0x28    /* Inbound interrupt mask */
+#define MFI_ODB   0x2c    /* Outbound doorbell */
+#define MFI_OSTS  0x30    /* Outbound interrupt status */
+#define MFI_OMSK  0x34    /* Outbound interrupt mask */
+#define MFI_IQP   0x40    /* Inbound queue port */
+#define MFI_OQP   0x44    /* Outbound queue port */
+
+/*
+ * 1078 specific related register
+ */
+#define MFI_ODR0        0x9c            /* outbound doorbell register0 */
+#define MFI_ODCR0       0xa0            /* outbound doorbell clear register0  */
+#define MFI_OSP0        0xb0            /* outbound scratch pad0  */
+#define MFI_IQPL        0xc0            /* Inbound queue port (low bytes)  */
+#define MFI_IQPH        0xc4            /* Inbound queue port (high bytes)  */
+#define MFI_DIAG        0xf8            /* Host diag */
+#define MFI_SEQ         0xfc            /* Sequencer offset */
+#define MFI_1078_EIM    0x80000004      /* 1078 enable intrrupt mask  */
+#define MFI_RMI         0x2             /* reply message interrupt  */
+#define MFI_1078_RM     0x80000000      /* reply 1078 message interrupt  */
+#define MFI_ODC         0x4             /* outbound doorbell change interrupt */
+
+/*
+ * gen2 specific changes
+ */
+#define MFI_GEN2_EIM    0x00000005      /* gen2 enable interrupt mask */
+#define MFI_GEN2_RM     0x00000001      /* reply gen2 message interrupt */
+
+/*
+ * skinny specific changes
+ */
+#define MFI_SKINNY_IDB  0x00    /* Inbound doorbell is at 0x00 for skinny */
+#define MFI_SKINNY_RM   0x00000001      /* reply skinny message interrupt */
+
+/* Bits for MFI_OSTS */
+#define MFI_OSTS_INTR_VALID     0x00000002
+
+/*
+ * Firmware state values.  Found in OMSG0 during initialization.
+ */
+#define MFI_FWSTATE_MASK                0xf0000000
+#define MFI_FWSTATE_UNDEFINED           0x00000000
+#define MFI_FWSTATE_BB_INIT             0x10000000
+#define MFI_FWSTATE_FW_INIT             0x40000000
+#define MFI_FWSTATE_WAIT_HANDSHAKE      0x60000000
+#define MFI_FWSTATE_FW_INIT_2           0x70000000
+#define MFI_FWSTATE_DEVICE_SCAN         0x80000000
+#define MFI_FWSTATE_BOOT_MSG_PENDING    0x90000000
+#define MFI_FWSTATE_FLUSH_CACHE         0xa0000000
+#define MFI_FWSTATE_READY               0xb0000000
+#define MFI_FWSTATE_OPERATIONAL         0xc0000000
+#define MFI_FWSTATE_FAULT               0xf0000000
+#define MFI_FWSTATE_MAXSGL_MASK         0x00ff0000
+#define MFI_FWSTATE_MAXCMD_MASK         0x0000ffff
+#define MFI_FWSTATE_MSIX_SUPPORTED      0x04000000
+#define MFI_FWSTATE_HOSTMEMREQD_MASK    0x08000000
+
+/*
+ * Control bits to drive the card to ready state.  These go into the IDB
+ * register.
+ */
+#define MFI_FWINIT_ABORT        0x00000001 /* Abort all pending commands */
+#define MFI_FWINIT_READY        0x00000002 /* Move from operational to ready */
+#define MFI_FWINIT_MFIMODE      0x00000004 /* unknown */
+#define MFI_FWINIT_CLEAR_HANDSHAKE 0x00000008 /* Respond to WAIT_HANDSHAKE */
+#define MFI_FWINIT_HOTPLUG      0x00000010
+#define MFI_FWINIT_STOP_ADP     0x00000020 /* Move to operational, stop */
+#define MFI_FWINIT_ADP_RESET    0x00000040 /* Reset ADP */
+
+/* MFI Commands */
+typedef enum {
+    MFI_CMD_INIT = 0x00,
+    MFI_CMD_LD_READ,
+    MFI_CMD_LD_WRITE,
+    MFI_CMD_LD_SCSI_IO,
+    MFI_CMD_PD_SCSI_IO,
+    MFI_CMD_DCMD,
+    MFI_CMD_ABORT,
+    MFI_CMD_SMP,
+    MFI_CMD_STP
+} mfi_cmd_t;
+
+/* Direct commands */
+typedef enum {
+    MFI_DCMD_CTRL_MFI_HOST_MEM_ALLOC =  0x0100e100,
+    MFI_DCMD_CTRL_GET_INFO =            0x01010000,
+    MFI_DCMD_CTRL_GET_PROPERTIES =      0x01020100,
+    MFI_DCMD_CTRL_SET_PROPERTIES =      0x01020200,
+    MFI_DCMD_CTRL_ALARM =               0x01030000,
+    MFI_DCMD_CTRL_ALARM_GET =           0x01030100,
+    MFI_DCMD_CTRL_ALARM_ENABLE =        0x01030200,
+    MFI_DCMD_CTRL_ALARM_DISABLE =       0x01030300,
+    MFI_DCMD_CTRL_ALARM_SILENCE =       0x01030400,
+    MFI_DCMD_CTRL_ALARM_TEST =          0x01030500,
+    MFI_DCMD_CTRL_EVENT_GETINFO =       0x01040100,
+    MFI_DCMD_CTRL_EVENT_CLEAR =         0x01040200,
+    MFI_DCMD_CTRL_EVENT_GET =           0x01040300,
+    MFI_DCMD_CTRL_EVENT_COUNT =         0x01040400,
+    MFI_DCMD_CTRL_EVENT_WAIT =          0x01040500,
+    MFI_DCMD_CTRL_SHUTDOWN =            0x01050000,
+    MFI_DCMD_HIBERNATE_STANDBY =        0x01060000,
+    MFI_DCMD_CTRL_GET_TIME =            0x01080101,
+    MFI_DCMD_CTRL_SET_TIME =            0x01080102,
+    MFI_DCMD_CTRL_BIOS_DATA_GET =       0x010c0100,
+    MFI_DCMD_CTRL_BIOS_DATA_SET =       0x010c0200,
+    MFI_DCMD_CTRL_FACTORY_DEFAULTS =    0x010d0000,
+    MFI_DCMD_CTRL_MFC_DEFAULTS_GET =    0x010e0201,
+    MFI_DCMD_CTRL_MFC_DEFAULTS_SET =    0x010e0202,
+    MFI_DCMD_CTRL_CACHE_FLUSH =         0x01101000,
+    MFI_DCMD_PD_GET_LIST =              0x02010000,
+    MFI_DCMD_PD_LIST_QUERY =            0x02010100,
+    MFI_DCMD_PD_GET_INFO =              0x02020000,
+    MFI_DCMD_PD_STATE_SET =             0x02030100,
+    MFI_DCMD_PD_REBUILD =               0x02040100,
+    MFI_DCMD_PD_BLINK =                 0x02070100,
+    MFI_DCMD_PD_UNBLINK =               0x02070200,
+    MFI_DCMD_LD_GET_LIST =              0x03010000,
+    MFI_DCMD_LD_GET_INFO =              0x03020000,
+    MFI_DCMD_LD_GET_PROP =              0x03030000,
+    MFI_DCMD_LD_SET_PROP =              0x03040000,
+    MFI_DCMD_LD_DELETE =                0x03090000,
+    MFI_DCMD_CFG_READ =                 0x04010000,
+    MFI_DCMD_CFG_ADD =                  0x04020000,
+    MFI_DCMD_CFG_CLEAR =                0x04030000,
+    MFI_DCMD_CFG_FOREIGN_READ =         0x04060100,
+    MFI_DCMD_CFG_FOREIGN_IMPORT =       0x04060400,
+    MFI_DCMD_BBU_STATUS =               0x05010000,
+    MFI_DCMD_BBU_CAPACITY_INFO =        0x05020000,
+    MFI_DCMD_BBU_DESIGN_INFO =          0x05030000,
+    MFI_DCMD_BBU_PROP_GET =             0x05050100,
+    MFI_DCMD_CLUSTER =                  0x08000000,
+    MFI_DCMD_CLUSTER_RESET_ALL =        0x08010100,
+    MFI_DCMD_CLUSTER_RESET_LD =         0x08010200
+} mfi_dcmd_t;
+
+/* Modifiers for MFI_DCMD_CTRL_FLUSHCACHE */
+#define MFI_FLUSHCACHE_CTRL     0x01
+#define MFI_FLUSHCACHE_DISK     0x02
+
+/* Modifiers for MFI_DCMD_CTRL_SHUTDOWN */
+#define MFI_SHUTDOWN_SPINDOWN   0x01
+
+/*
+ * MFI Frame flags
+ */
+typedef enum {
+    MFI_FRAME_DONT_POST_IN_REPLY_QUEUE =        0x0001,
+    MFI_FRAME_SGL64 =                           0x0002,
+    MFI_FRAME_SENSE64 =                         0x0004,
+    MFI_FRAME_DIR_WRITE =                       0x0008,
+    MFI_FRAME_DIR_READ =                        0x0010,
+    MFI_FRAME_IEEE_SGL =                        0x0020,
+} mfi_frame_flags;
+
+/* MFI Status codes */
+typedef enum {
+    MFI_STAT_OK =                       0x00,
+    MFI_STAT_INVALID_CMD,
+    MFI_STAT_INVALID_DCMD,
+    MFI_STAT_INVALID_PARAMETER,
+    MFI_STAT_INVALID_SEQUENCE_NUMBER,
+    MFI_STAT_ABORT_NOT_POSSIBLE,
+    MFI_STAT_APP_HOST_CODE_NOT_FOUND,
+    MFI_STAT_APP_IN_USE,
+    MFI_STAT_APP_NOT_INITIALIZED,
+    MFI_STAT_ARRAY_INDEX_INVALID,
+    MFI_STAT_ARRAY_ROW_NOT_EMPTY,
+    MFI_STAT_CONFIG_RESOURCE_CONFLICT,
+    MFI_STAT_DEVICE_NOT_FOUND,
+    MFI_STAT_DRIVE_TOO_SMALL,
+    MFI_STAT_FLASH_ALLOC_FAIL,
+    MFI_STAT_FLASH_BUSY,
+    MFI_STAT_FLASH_ERROR =              0x10,
+    MFI_STAT_FLASH_IMAGE_BAD,
+    MFI_STAT_FLASH_IMAGE_INCOMPLETE,
+    MFI_STAT_FLASH_NOT_OPEN,
+    MFI_STAT_FLASH_NOT_STARTED,
+    MFI_STAT_FLUSH_FAILED,
+    MFI_STAT_HOST_CODE_NOT_FOUNT,
+    MFI_STAT_LD_CC_IN_PROGRESS,
+    MFI_STAT_LD_INIT_IN_PROGRESS,
+    MFI_STAT_LD_LBA_OUT_OF_RANGE,
+    MFI_STAT_LD_MAX_CONFIGURED,
+    MFI_STAT_LD_NOT_OPTIMAL,
+    MFI_STAT_LD_RBLD_IN_PROGRESS,
+    MFI_STAT_LD_RECON_IN_PROGRESS,
+    MFI_STAT_LD_WRONG_RAID_LEVEL,
+    MFI_STAT_MAX_SPARES_EXCEEDED,
+    MFI_STAT_MEMORY_NOT_AVAILABLE =     0x20,
+    MFI_STAT_MFC_HW_ERROR,
+    MFI_STAT_NO_HW_PRESENT,
+    MFI_STAT_NOT_FOUND,
+    MFI_STAT_NOT_IN_ENCL,
+    MFI_STAT_PD_CLEAR_IN_PROGRESS,
+    MFI_STAT_PD_TYPE_WRONG,
+    MFI_STAT_PR_DISABLED,
+    MFI_STAT_ROW_INDEX_INVALID,
+    MFI_STAT_SAS_CONFIG_INVALID_ACTION,
+    MFI_STAT_SAS_CONFIG_INVALID_DATA,
+    MFI_STAT_SAS_CONFIG_INVALID_PAGE,
+    MFI_STAT_SAS_CONFIG_INVALID_TYPE,
+    MFI_STAT_SCSI_DONE_WITH_ERROR,
+    MFI_STAT_SCSI_IO_FAILED,
+    MFI_STAT_SCSI_RESERVATION_CONFLICT,
+    MFI_STAT_SHUTDOWN_FAILED =          0x30,
+    MFI_STAT_TIME_NOT_SET,
+    MFI_STAT_WRONG_STATE,
+    MFI_STAT_LD_OFFLINE,
+    MFI_STAT_PEER_NOTIFICATION_REJECTED,
+    MFI_STAT_PEER_NOTIFICATION_FAILED,
+    MFI_STAT_RESERVATION_IN_PROGRESS,
+    MFI_STAT_I2C_ERRORS_DETECTED,
+    MFI_STAT_PCI_ERRORS_DETECTED,
+    MFI_STAT_DIAG_FAILED,
+    MFI_STAT_BOOT_MSG_PENDING,
+    MFI_STAT_FOREIGN_CONFIG_INCOMPLETE,
+    MFI_STAT_INVALID_SGL,
+    MFI_STAT_UNSUPPORTED_HW,
+    MFI_STAT_CC_SCHEDULE_DISABLED,
+    MFI_STAT_PD_COPYBACK_IN_PROGRESS,
+    MFI_STAT_MULTIPLE_PDS_IN_ARRAY =    0x40,
+    MFI_STAT_FW_DOWNLOAD_ERROR,
+    MFI_STAT_FEATURE_SECURITY_NOT_ENABLED,
+    MFI_STAT_LOCK_KEY_ALREADY_EXISTS,
+    MFI_STAT_LOCK_KEY_BACKUP_NOT_ALLOWED,
+    MFI_STAT_LOCK_KEY_VERIFY_NOT_ALLOWED,
+    MFI_STAT_LOCK_KEY_VERIFY_FAILED,
+    MFI_STAT_LOCK_KEY_REKEY_NOT_ALLOWED,
+    MFI_STAT_LOCK_KEY_INVALID,
+    MFI_STAT_LOCK_KEY_ESCROW_INVALID,
+    MFI_STAT_LOCK_KEY_BACKUP_REQUIRED,
+    MFI_STAT_SECURE_LD_EXISTS,
+    MFI_STAT_LD_SECURE_NOT_ALLOWED,
+    MFI_STAT_REPROVISION_NOT_ALLOWED,
+    MFI_STAT_PD_SECURITY_TYPE_WRONG,
+    MFI_STAT_LD_ENCRYPTION_TYPE_INVALID,
+    MFI_STAT_CONFIG_FDE_NON_FDE_MIX_NOT_ALLOWED = 0x50,
+    MFI_STAT_CONFIG_LD_ENCRYPTION_TYPE_MIX_NOT_ALLOWED,
+    MFI_STAT_SECRET_KEY_NOT_ALLOWED,
+    MFI_STAT_PD_HW_ERRORS_DETECTED,
+    MFI_STAT_LD_CACHE_PINNED,
+    MFI_STAT_POWER_STATE_SET_IN_PROGRESS,
+    MFI_STAT_POWER_STATE_SET_BUSY,
+    MFI_STAT_POWER_STATE_WRONG,
+    MFI_STAT_PR_NO_AVAILABLE_PD_FOUND,
+    MFI_STAT_CTRL_RESET_REQUIRED,
+    MFI_STAT_LOCK_KEY_EKM_NO_BOOT_AGENT,
+    MFI_STAT_SNAP_NO_SPACE,
+    MFI_STAT_SNAP_PARTIAL_FAILURE,
+    MFI_STAT_UPGRADE_KEY_INCOMPATIBLE,
+    MFI_STAT_PFK_INCOMPATIBLE,
+    MFI_STAT_PD_MAX_UNCONFIGURED,
+    MFI_STAT_IO_METRICS_DISABLED =      0x60,
+    MFI_STAT_AEC_NOT_STOPPED,
+    MFI_STAT_PI_TYPE_WRONG,
+    MFI_STAT_LD_PD_PI_INCOMPATIBLE,
+    MFI_STAT_PI_NOT_ENABLED,
+    MFI_STAT_LD_BLOCK_SIZE_MISMATCH,
+    MFI_STAT_INVALID_STATUS =           0xFF
+} mfi_status_t;
+
+/* Event classes */
+typedef enum {
+    MFI_EVT_CLASS_DEBUG =      -2,
+    MFI_EVT_CLASS_PROGRESS =   -1,
+    MFI_EVT_CLASS_INFO =        0,
+    MFI_EVT_CLASS_WARNING =     1,
+    MFI_EVT_CLASS_CRITICAL =    2,
+    MFI_EVT_CLASS_FATAL =       3,
+    MFI_EVT_CLASS_DEAD =        4
+} mfi_evt_class_t;
+
+/* Event locales */
+typedef enum {
+    MFI_EVT_LOCALE_LD =         0x0001,
+    MFI_EVT_LOCALE_PD =         0x0002,
+    MFI_EVT_LOCALE_ENCL =       0x0004,
+    MFI_EVT_LOCALE_BBU =        0x0008,
+    MFI_EVT_LOCALE_SAS =        0x0010,
+    MFI_EVT_LOCALE_CTRL =       0x0020,
+    MFI_EVT_LOCALE_CONFIG =     0x0040,
+    MFI_EVT_LOCALE_CLUSTER =    0x0080,
+    MFI_EVT_LOCALE_ALL =        0xffff
+} mfi_evt_locale_t;
+
+/* Event args */
+typedef enum {
+    MR_EVT_ARGS_NONE =          0x00,
+    MR_EVT_ARGS_CDB_SENSE,
+    MR_EVT_ARGS_LD,
+    MR_EVT_ARGS_LD_COUNT,
+    MR_EVT_ARGS_LD_LBA,
+    MR_EVT_ARGS_LD_OWNER,
+    MR_EVT_ARGS_LD_LBA_PD_LBA,
+    MR_EVT_ARGS_LD_PROG,
+    MR_EVT_ARGS_LD_STATE,
+    MR_EVT_ARGS_LD_STRIP,
+    MR_EVT_ARGS_PD,
+    MR_EVT_ARGS_PD_ERR,
+    MR_EVT_ARGS_PD_LBA,
+    MR_EVT_ARGS_PD_LBA_LD,
+    MR_EVT_ARGS_PD_PROG,
+    MR_EVT_ARGS_PD_STATE,
+    MR_EVT_ARGS_PCI,
+    MR_EVT_ARGS_RATE,
+    MR_EVT_ARGS_STR,
+    MR_EVT_ARGS_TIME,
+    MR_EVT_ARGS_ECC,
+    MR_EVT_ARGS_LD_PROP,
+    MR_EVT_ARGS_PD_SPARE,
+    MR_EVT_ARGS_PD_INDEX,
+    MR_EVT_ARGS_DIAG_PASS,
+    MR_EVT_ARGS_DIAG_FAIL,
+    MR_EVT_ARGS_PD_LBA_LBA,
+    MR_EVT_ARGS_PORT_PHY,
+    MR_EVT_ARGS_PD_MISSING,
+    MR_EVT_ARGS_PD_ADDRESS,
+    MR_EVT_ARGS_BITMAP,
+    MR_EVT_ARGS_CONNECTOR,
+    MR_EVT_ARGS_PD_PD,
+    MR_EVT_ARGS_PD_FRU,
+    MR_EVT_ARGS_PD_PATHINFO,
+    MR_EVT_ARGS_PD_POWER_STATE,
+    MR_EVT_ARGS_GENERIC,
+} mfi_evt_args;
+
+/* Event codes */
+#define MR_EVT_CFG_CLEARED                          0x0004
+#define MR_EVT_CTRL_SHUTDOWN                        0x002a
+#define MR_EVT_LD_STATE_CHANGE                      0x0051
+#define MR_EVT_PD_INSERTED                          0x005b
+#define MR_EVT_PD_REMOVED                           0x0070
+#define MR_EVT_PD_STATE_CHANGED                     0x0072
+#define MR_EVT_LD_CREATED                           0x008a
+#define MR_EVT_LD_DELETED                           0x008b
+#define MR_EVT_FOREIGN_CFG_IMPORTED                 0x00db
+#define MR_EVT_LD_OFFLINE                           0x00fc
+#define MR_EVT_CTRL_HOST_BUS_SCAN_REQUESTED         0x0152
+
+typedef enum {
+    MR_LD_CACHE_WRITE_BACK =            0x01,
+    MR_LD_CACHE_WRITE_ADAPTIVE =        0x02,
+    MR_LD_CACHE_READ_AHEAD =            0x04,
+    MR_LD_CACHE_READ_ADAPTIVE =         0x08,
+    MR_LD_CACHE_WRITE_CACHE_BAD_BBU =   0x10,
+    MR_LD_CACHE_ALLOW_WRITE_CACHE =     0x20,
+    MR_LD_CACHE_ALLOW_READ_CACHE =      0x40
+} mfi_ld_cache;
+
+typedef enum {
+    MR_PD_CACHE_UNCHANGED  =    0,
+    MR_PD_CACHE_ENABLE =        1,
+    MR_PD_CACHE_DISABLE =       2
+} mfi_pd_cache;
+
+typedef enum {
+    MR_PD_QUERY_TYPE_ALL =              0,
+    MR_PD_QUERY_TYPE_STATE =            1,
+    MR_PD_QUERY_TYPE_POWER_STATE =      2,
+    MR_PD_QUERY_TYPE_MEDIA_TYPE =       3,
+    MR_PD_QUERY_TYPE_SPEED =            4,
+    MR_PD_QUERY_TYPE_EXPOSED_TO_HOST =  5, /*query for system drives */
+} mfi_pd_query_type;
+
+/*
+ * Other propertities and definitions
+ */
+#define MFI_MAX_PD_CHANNELS     2
+#define MFI_MAX_LD_CHANNELS     2
+#define MFI_MAX_CHANNELS        (MFI_MAX_PD_CHANNELS + MFI_MAX_LD_CHANNELS)
+#define MFI_MAX_CHANNEL_DEVS  128
+#define MFI_DEFAULT_ID         -1
+#define MFI_MAX_LUN             8
+#define MFI_MAX_LD             64
+
+#define MFI_FRAME_SIZE         64
+#define MFI_MBOX_SIZE          12
+
+/* Firmware flashing can take 40s */
+#define MFI_POLL_TIMEOUT_SECS  50
+
+/* Allow for speedier math calculations */
+#define MFI_SECTOR_LEN        512
+
+/* Scatter Gather elements */
+struct mfi_sg32 {
+    uint32_t addr;
+    uint32_t len;
+} QEMU_PACKED;
+
+struct mfi_sg64 {
+    uint64_t addr;
+    uint32_t len;
+} QEMU_PACKED;
+
+struct mfi_sg_skinny {
+    uint64_t addr;
+    uint32_t len;
+    uint32_t flag;
+} QEMU_PACKED;
+
+union mfi_sgl {
+    struct mfi_sg32 sg32[1];
+    struct mfi_sg64 sg64[1];
+    struct mfi_sg_skinny sg_skinny[1];
+} QEMU_PACKED;
+
+/* Message frames.  All messages have a common header */
+struct mfi_frame_header {
+    uint8_t frame_cmd;
+    uint8_t sense_len;
+    uint8_t cmd_status;
+    uint8_t scsi_status;
+    uint8_t target_id;
+    uint8_t lun_id;
+    uint8_t cdb_len;
+    uint8_t sge_count;
+    uint64_t context;
+    uint16_t flags;
+    uint16_t timeout;
+    uint32_t data_len;
+} QEMU_PACKED;
+
+struct mfi_init_frame {
+    struct mfi_frame_header header;
+    uint32_t qinfo_new_addr_lo;
+    uint32_t qinfo_new_addr_hi;
+    uint32_t qinfo_old_addr_lo;
+    uint32_t qinfo_old_addr_hi;
+    uint32_t reserved[6];
+};
+
+#define MFI_IO_FRAME_SIZE 40
+struct mfi_io_frame {
+    struct mfi_frame_header header;
+    uint32_t sense_addr_lo;
+    uint32_t sense_addr_hi;
+    uint32_t lba_lo;
+    uint32_t lba_hi;
+    union mfi_sgl sgl;
+} QEMU_PACKED;
+
+#define MFI_PASS_FRAME_SIZE 48
+struct mfi_pass_frame {
+    struct mfi_frame_header header;
+    uint32_t sense_addr_lo;
+    uint32_t sense_addr_hi;
+    uint8_t cdb[16];
+    union mfi_sgl sgl;
+} QEMU_PACKED;
+
+#define MFI_DCMD_FRAME_SIZE 40
+struct mfi_dcmd_frame {
+    struct mfi_frame_header header;
+    uint32_t opcode;
+    uint8_t mbox[MFI_MBOX_SIZE];
+    union mfi_sgl sgl;
+} QEMU_PACKED;
+
+struct mfi_abort_frame {
+    struct mfi_frame_header header;
+    uint64_t abort_context;
+    uint32_t abort_mfi_addr_lo;
+    uint32_t abort_mfi_addr_hi;
+    uint32_t reserved1[6];
+} QEMU_PACKED;
+
+struct mfi_smp_frame {
+    struct mfi_frame_header header;
+    uint64_t sas_addr;
+    union {
+        struct mfi_sg32 sg32[2];
+        struct mfi_sg64 sg64[2];
+    } sgl;
+} QEMU_PACKED;
+
+struct mfi_stp_frame {
+    struct mfi_frame_header header;
+    uint16_t fis[10];
+    uint32_t stp_flags;
+    union {
+        struct mfi_sg32 sg32[2];
+        struct mfi_sg64 sg64[2];
+    } sgl;
+} QEMU_PACKED;
+
+union mfi_frame {
+    struct mfi_frame_header header;
+    struct mfi_init_frame init;
+    struct mfi_io_frame io;
+    struct mfi_pass_frame pass;
+    struct mfi_dcmd_frame dcmd;
+    struct mfi_abort_frame abort;
+    struct mfi_smp_frame smp;
+    struct mfi_stp_frame stp;
+    uint64_t raw[8];
+    uint8_t bytes[MFI_FRAME_SIZE];
+};
+
+#define MFI_SENSE_LEN 128
+struct mfi_sense {
+    uint8_t     data[MFI_SENSE_LEN];
+};
+
+#define MFI_QUEUE_FLAG_CONTEXT64 0x00000002
+
+/* The queue init structure that is passed with the init message */
+struct mfi_init_qinfo {
+    uint32_t flags;
+    uint32_t rq_entries;
+    uint32_t rq_addr_lo;
+    uint32_t rq_addr_hi;
+    uint32_t pi_addr_lo;
+    uint32_t pi_addr_hi;
+    uint32_t ci_addr_lo;
+    uint32_t ci_addr_hi;
+} QEMU_PACKED;
+
+/* Controller properties */
+struct mfi_ctrl_props {
+    uint16_t seq_num;
+    uint16_t pred_fail_poll_interval;
+    uint16_t intr_throttle_cnt;
+    uint16_t intr_throttle_timeout;
+    uint8_t rebuild_rate;
+    uint8_t patrol_read_rate;
+    uint8_t bgi_rate;
+    uint8_t cc_rate;
+    uint8_t recon_rate;
+    uint8_t cache_flush_interval;
+    uint8_t spinup_drv_cnt;
+    uint8_t spinup_delay;
+    uint8_t cluster_enable;
+    uint8_t coercion_mode;
+    uint8_t alarm_enable;
+    uint8_t disable_auto_rebuild;
+    uint8_t disable_battery_warn;
+    uint8_t ecc_bucket_size;
+    uint16_t ecc_bucket_leak_rate;
+    uint8_t restore_hotspare_on_insertion;
+    uint8_t expose_encl_devices;
+    uint8_t maintainPdFailHistory;
+    uint8_t disallowHostRequestReordering;
+    uint8_t abortCCOnError;
+    uint8_t loadBalanceMode;
+    uint8_t disableAutoDetectBackplane;
+    uint8_t snapVDSpace;
+    uint32_t OnOffProperties;
+/* set TRUE to disable copyBack (0=copyback enabled) */
+#define MFI_CTRL_PROP_CopyBackDisabled           (1 << 0)
+#define MFI_CTRL_PROP_SMARTerEnabled             (1 << 1)
+#define MFI_CTRL_PROP_PRCorrectUnconfiguredAreas (1 << 2)
+#define MFI_CTRL_PROP_UseFdeOnly                 (1 << 3)
+#define MFI_CTRL_PROP_DisableNCQ                 (1 << 4)
+#define MFI_CTRL_PROP_SSDSMARTerEnabled          (1 << 5)
+#define MFI_CTRL_PROP_SSDPatrolReadEnabled       (1 << 6)
+#define MFI_CTRL_PROP_EnableSpinDownUnconfigured (1 << 7)
+#define MFI_CTRL_PROP_AutoEnhancedImport         (1 << 8)
+#define MFI_CTRL_PROP_EnableSecretKeyControl     (1 << 9)
+#define MFI_CTRL_PROP_DisableOnlineCtrlReset     (1 << 10)
+#define MFI_CTRL_PROP_AllowBootWithPinnedCache   (1 << 11)
+#define MFI_CTRL_PROP_DisableSpinDownHS          (1 << 12)
+#define MFI_CTRL_PROP_EnableJBOD                 (1 << 13)
+
+    uint8_t autoSnapVDSpace; /* % of source LD to be
+                              * reserved for auto snapshot
+                              * in snapshot repository, for
+                              * metadata and user data
+                              * 1=5%, 2=10%, 3=15% and so on
+                              */
+    uint8_t viewSpace;       /* snapshot writeable VIEWs
+                              * capacity as a % of source LD
+                              * capacity. 0=READ only
+                              * 1=5%, 2=10%, 3=15% and so on
+                              */
+    uint16_t spinDownTime;    /* # of idle minutes before device
+                               * is spun down (0=use FW defaults)
+                               */
+    uint8_t reserved[24];
+} QEMU_PACKED;
+
+/* PCI information about the card. */
+struct mfi_info_pci {
+    uint16_t vendor;
+    uint16_t device;
+    uint16_t subvendor;
+    uint16_t subdevice;
+    uint8_t reserved[24];
+} QEMU_PACKED;
+
+/* Host (front end) interface information */
+struct mfi_info_host {
+    uint8_t type;
+#define MFI_INFO_HOST_PCIX      0x01
+#define MFI_INFO_HOST_PCIE      0x02
+#define MFI_INFO_HOST_ISCSI     0x04
+#define MFI_INFO_HOST_SAS3G     0x08
+    uint8_t reserved[6];
+    uint8_t port_count;
+    uint64_t port_addr[8];
+} QEMU_PACKED;
+
+/* Device (back end) interface information */
+struct mfi_info_device {
+    uint8_t type;
+#define MFI_INFO_DEV_SPI        0x01
+#define MFI_INFO_DEV_SAS3G      0x02
+#define MFI_INFO_DEV_SATA1      0x04
+#define MFI_INFO_DEV_SATA3G     0x08
+#define MFI_INFO_DEV_PCIE       0x10
+    uint8_t reserved[6];
+    uint8_t port_count;
+    uint64_t port_addr[8];
+} QEMU_PACKED;
+
+/* Firmware component information */
+struct mfi_info_component {
+    char name[8];
+    char version[32];
+    char build_date[16];
+    char build_time[16];
+} QEMU_PACKED;
+
+/* Controller default settings */
+struct mfi_defaults {
+    uint64_t sas_addr;
+    uint8_t phy_polarity;
+    uint8_t background_rate;
+    uint8_t stripe_size;
+    uint8_t flush_time;
+    uint8_t write_back;
+    uint8_t read_ahead;
+    uint8_t cache_when_bbu_bad;
+    uint8_t cached_io;
+    uint8_t smart_mode;
+    uint8_t alarm_disable;
+    uint8_t coercion;
+    uint8_t zrc_config;
+    uint8_t dirty_led_shows_drive_activity;
+    uint8_t bios_continue_on_error;
+    uint8_t spindown_mode;
+    uint8_t allowed_device_types;
+    uint8_t allow_mix_in_enclosure;
+    uint8_t allow_mix_in_ld;
+    uint8_t allow_sata_in_cluster;
+    uint8_t max_chained_enclosures;
+    uint8_t disable_ctrl_r;
+    uint8_t enable_web_bios;
+    uint8_t phy_polarity_split;
+    uint8_t direct_pd_mapping;
+    uint8_t bios_enumerate_lds;
+    uint8_t restored_hot_spare_on_insertion;
+    uint8_t expose_enclosure_devices;
+    uint8_t maintain_pd_fail_history;
+    uint8_t disable_puncture;
+    uint8_t zero_based_enumeration;
+    uint8_t disable_preboot_cli;
+    uint8_t show_drive_led_on_activity;
+    uint8_t cluster_disable;
+    uint8_t sas_disable;
+    uint8_t auto_detect_backplane;
+    uint8_t fde_only;
+    uint8_t delay_during_post;
+    uint8_t resv[19];
+} QEMU_PACKED;
+
+/* Controller default settings */
+struct mfi_bios_data {
+    uint16_t boot_target_id;
+    uint8_t do_not_int_13;
+    uint8_t continue_on_error;
+    uint8_t verbose;
+    uint8_t geometry;
+    uint8_t expose_all_drives;
+    uint8_t reserved[56];
+    uint8_t check_sum;
+} QEMU_PACKED;
+
+/* SAS (?) controller info, returned from MFI_DCMD_CTRL_GETINFO. */
+struct mfi_ctrl_info {
+    struct mfi_info_pci pci;
+    struct mfi_info_host host;
+    struct mfi_info_device device;
+
+    /* Firmware components that are present and active. */
+    uint32_t image_check_word;
+    uint32_t image_component_count;
+    struct mfi_info_component image_component[8];
+
+    /* Firmware components that have been flashed but are inactive */
+    uint32_t pending_image_component_count;
+    struct mfi_info_component pending_image_component[8];
+
+    uint8_t max_arms;
+    uint8_t max_spans;
+    uint8_t max_arrays;
+    uint8_t max_lds;
+    char product_name[80];
+    char serial_number[32];
+    uint32_t hw_present;
+#define MFI_INFO_HW_BBU         0x01
+#define MFI_INFO_HW_ALARM       0x02
+#define MFI_INFO_HW_NVRAM       0x04
+#define MFI_INFO_HW_UART        0x08
+#define MFI_INFO_HW_MEM         0x10
+#define MFI_INFO_HW_FLASH       0x20
+    uint32_t current_fw_time;
+    uint16_t max_cmds;
+    uint16_t max_sg_elements;
+    uint32_t max_request_size;
+    uint16_t lds_present;
+    uint16_t lds_degraded;
+    uint16_t lds_offline;
+    uint16_t pd_present;
+    uint16_t pd_disks_present;
+    uint16_t pd_disks_pred_failure;
+    uint16_t pd_disks_failed;
+    uint16_t nvram_size;
+    uint16_t memory_size;
+    uint16_t flash_size;
+    uint16_t ram_correctable_errors;
+    uint16_t ram_uncorrectable_errors;
+    uint8_t cluster_allowed;
+    uint8_t cluster_active;
+    uint16_t max_strips_per_io;
+
+    uint32_t raid_levels;
+#define MFI_INFO_RAID_0         0x01
+#define MFI_INFO_RAID_1         0x02
+#define MFI_INFO_RAID_5         0x04
+#define MFI_INFO_RAID_1E        0x08
+#define MFI_INFO_RAID_6         0x10
+
+    uint32_t adapter_ops;
+#define MFI_INFO_AOPS_RBLD_RATE         0x0001
+#define MFI_INFO_AOPS_CC_RATE           0x0002
+#define MFI_INFO_AOPS_BGI_RATE          0x0004
+#define MFI_INFO_AOPS_RECON_RATE        0x0008
+#define MFI_INFO_AOPS_PATROL_RATE       0x0010
+#define MFI_INFO_AOPS_ALARM_CONTROL     0x0020
+#define MFI_INFO_AOPS_CLUSTER_SUPPORTED 0x0040
+#define MFI_INFO_AOPS_BBU               0x0080
+#define MFI_INFO_AOPS_SPANNING_ALLOWED  0x0100
+#define MFI_INFO_AOPS_DEDICATED_SPARES  0x0200
+#define MFI_INFO_AOPS_REVERTIBLE_SPARES 0x0400
+#define MFI_INFO_AOPS_FOREIGN_IMPORT    0x0800
+#define MFI_INFO_AOPS_SELF_DIAGNOSTIC   0x1000
+#define MFI_INFO_AOPS_MIXED_ARRAY       0x2000
+#define MFI_INFO_AOPS_GLOBAL_SPARES     0x4000
+
+    uint32_t ld_ops;
+#define MFI_INFO_LDOPS_READ_POLICY      0x01
+#define MFI_INFO_LDOPS_WRITE_POLICY     0x02
+#define MFI_INFO_LDOPS_IO_POLICY        0x04
+#define MFI_INFO_LDOPS_ACCESS_POLICY    0x08
+#define MFI_INFO_LDOPS_DISK_CACHE_POLICY 0x10
+
+    struct {
+        uint8_t min;
+        uint8_t max;
+        uint8_t reserved[2];
+    } QEMU_PACKED stripe_sz_ops;
+
+    uint32_t pd_ops;
+#define MFI_INFO_PDOPS_FORCE_ONLINE     0x01
+#define MFI_INFO_PDOPS_FORCE_OFFLINE    0x02
+#define MFI_INFO_PDOPS_FORCE_REBUILD    0x04
+
+    uint32_t pd_mix_support;
+#define MFI_INFO_PDMIX_SAS              0x01
+#define MFI_INFO_PDMIX_SATA             0x02
+#define MFI_INFO_PDMIX_ENCL             0x04
+#define MFI_INFO_PDMIX_LD               0x08
+#define MFI_INFO_PDMIX_SATA_CLUSTER     0x10
+
+    uint8_t ecc_bucket_count;
+    uint8_t reserved2[11];
+    struct mfi_ctrl_props properties;
+    char package_version[0x60];
+    uint8_t pad[0x800 - 0x6a0];
+} QEMU_PACKED;
+
+/* keep track of an event. */
+union mfi_evt {
+    struct {
+        uint16_t locale;
+        uint8_t reserved;
+        int8_t class;
+    } members;
+    uint32_t word;
+} QEMU_PACKED;
+
+/* event log state. */
+struct mfi_evt_log_state {
+    uint32_t newest_seq_num;
+    uint32_t oldest_seq_num;
+    uint32_t clear_seq_num;
+    uint32_t shutdown_seq_num;
+    uint32_t boot_seq_num;
+} QEMU_PACKED;
+
+struct mfi_progress {
+    uint16_t progress;
+    uint16_t elapsed_seconds;
+} QEMU_PACKED;
+
+struct mfi_evt_ld {
+    uint16_t target_id;
+    uint8_t ld_index;
+    uint8_t reserved;
+} QEMU_PACKED;
+
+struct mfi_evt_pd {
+    uint16_t device_id;
+    uint8_t enclosure_index;
+    uint8_t slot_number;
+} QEMU_PACKED;
+
+/* event detail, returned from MFI_DCMD_CTRL_EVENT_WAIT. */
+struct mfi_evt_detail {
+    uint32_t seq;
+    uint32_t time;
+    uint32_t code;
+    union mfi_evt class;
+    uint8_t arg_type;
+    uint8_t reserved1[15];
+
+    union {
+        struct {
+            struct mfi_evt_pd pd;
+            uint8_t cdb_len;
+            uint8_t sense_len;
+            uint8_t reserved[2];
+            uint8_t cdb[16];
+            uint8_t sense[64];
+        } cdb_sense;
+
+        struct mfi_evt_ld ld;
+
+        struct {
+            struct mfi_evt_ld ld;
+            uint64_t count;
+        } ld_count;
+
+        struct {
+            uint64_t lba;
+            struct mfi_evt_ld ld;
+        } ld_lba;
+
+        struct {
+            struct mfi_evt_ld ld;
+            uint32_t pre_owner;
+            uint32_t new_owner;
+        } ld_owner;
+
+        struct {
+            uint64_t ld_lba;
+            uint64_t pd_lba;
+            struct mfi_evt_ld ld;
+            struct mfi_evt_pd pd;
+        } ld_lba_pd_lba;
+
+        struct {
+            struct mfi_evt_ld ld;
+            struct mfi_progress prog;
+        } ld_prog;
+
+        struct {
+            struct mfi_evt_ld ld;
+            uint32_t prev_state;
+            uint32_t new_state;
+        } ld_state;
+
+        struct {
+            uint64_t strip;
+            struct mfi_evt_ld ld;
+        } ld_strip;
+
+        struct mfi_evt_pd pd;
+
+        struct {
+            struct mfi_evt_pd pd;
+            uint32_t err;
+        } pd_err;
+
+        struct {
+            uint64_t lba;
+            struct mfi_evt_pd pd;
+        } pd_lba;
+
+        struct {
+            uint64_t lba;
+            struct mfi_evt_pd pd;
+            struct mfi_evt_ld ld;
+        } pd_lba_ld;
+
+        struct {
+            struct mfi_evt_pd pd;
+            struct mfi_progress prog;
+        } pd_prog;
+
+        struct {
+            struct mfi_evt_pd ld;
+            uint32_t prev_state;
+            uint32_t new_state;
+        } pd_state;
+
+        struct {
+            uint16_t venderId;
+            uint16_t deviceId;
+            uint16_t subVenderId;
+            uint16_t subDeviceId;
+        } pci;
+
+        uint32_t rate;
+
+        char str[96];
+
+        struct {
+            uint32_t rtc;
+            uint16_t elapsedSeconds;
+        } time;
+
+        struct {
+            uint32_t ecar;
+            uint32_t elog;
+            char str[64];
+        } ecc;
+
+        uint8_t b[96];
+        uint16_t s[48];
+        uint32_t w[24];
+        uint64_t d[12];
+    } args;
+
+    char description[128];
+} QEMU_PACKED;
+
+struct mfi_evt_list {
+    uint32_t count;
+    uint32_t reserved;
+    struct mfi_evt_detail event[1];
+} QEMU_PACKED;
+
+union mfi_pd_ref {
+    struct {
+        uint16_t device_id;
+        uint16_t seq_num;
+    } v;
+    uint32_t ref;
+} QEMU_PACKED;
+
+union mfi_pd_ddf_type {
+    struct {
+        uint16_t pd_type;
+#define MFI_PD_DDF_TYPE_FORCED_PD_GUID (1 << 0)
+#define MFI_PD_DDF_TYPE_IN_VD          (1 << 1)
+#define MFI_PD_DDF_TYPE_IS_GLOBAL_SPARE (1 << 2)
+#define MFI_PD_DDF_TYPE_IS_SPARE        (1 << 3)
+#define MFI_PD_DDF_TYPE_IS_FOREIGN      (1 << 4)
+#define MFI_PD_DDF_TYPE_INTF_SPI        (1 << 12)
+#define MFI_PD_DDF_TYPE_INTF_SAS        (1 << 13)
+#define MFI_PD_DDF_TYPE_INTF_SATA1      (1 << 14)
+#define MFI_PD_DDF_TYPE_INTF_SATA3G     (1 << 15)
+        uint16_t reserved;
+    } ddf;
+    struct {
+        uint32_t reserved;
+    } non_disk;
+    uint32_t type;
+} QEMU_PACKED;
+
+struct mfi_pd_progress {
+    uint32_t active;
+#define PD_PROGRESS_ACTIVE_REBUILD (1 << 0)
+#define PD_PROGRESS_ACTIVE_PATROL  (1 << 1)
+#define PD_PROGRESS_ACTIVE_CLEAR   (1 << 2)
+    struct mfi_progress rbld;
+    struct mfi_progress patrol;
+    struct mfi_progress clear;
+    struct mfi_progress reserved[4];
+} QEMU_PACKED;
+
+struct mfi_pd_info {
+    union mfi_pd_ref ref;
+    uint8_t inquiry_data[96];
+    uint8_t vpd_page83[64];
+    uint8_t not_supported;
+    uint8_t scsi_dev_type;
+    uint8_t connected_port_bitmap;
+    uint8_t device_speed;
+    uint32_t media_err_count;
+    uint32_t other_err_count;
+    uint32_t pred_fail_count;
+    uint32_t last_pred_fail_event_seq_num;
+    uint16_t fw_state;
+    uint8_t disable_for_removal;
+    uint8_t link_speed;
+    union mfi_pd_ddf_type state;
+    struct {
+        uint8_t count;
+        uint8_t is_path_broken;
+        uint8_t reserved[6];
+        uint64_t sas_addr[4];
+    } path_info;
+    uint64_t raw_size;
+    uint64_t non_coerced_size;
+    uint64_t coerced_size;
+    uint16_t encl_device_id;
+    uint8_t encl_index;
+    uint8_t slot_number;
+    struct mfi_pd_progress prog_info;
+    uint8_t bad_block_table_full;
+    uint8_t unusable_in_current_config;
+    uint8_t vpd_page83_ext[64];
+    uint8_t reserved[512-358];
+} QEMU_PACKED;
+
+struct mfi_pd_address {
+    uint16_t device_id;
+    uint16_t encl_device_id;
+    uint8_t encl_index;
+    uint8_t slot_number;
+    uint8_t scsi_dev_type;
+    uint8_t connect_port_bitmap;
+    uint64_t sas_addr[2];
+} QEMU_PACKED;
+
+#define MFI_MAX_SYS_PDS 240
+struct mfi_pd_list {
+    uint32_t size;
+    uint32_t count;
+    struct mfi_pd_address addr[MFI_MAX_SYS_PDS];
+} QEMU_PACKED;
+
+union mfi_ld_ref {
+    struct {
+        uint8_t target_id;
+        uint8_t lun_id;
+        uint16_t seq;
+    } v;
+    uint32_t ref;
+} QEMU_PACKED;
+
+struct mfi_ld_list {
+    uint32_t ld_count;
+    uint32_t reserved1;
+    struct {
+        union mfi_ld_ref ld;
+        uint8_t state;
+        uint8_t reserved2[3];
+        uint64_t size;
+    } ld_list[MFI_MAX_LD];
+} QEMU_PACKED;
+
+enum mfi_ld_access {
+    MFI_LD_ACCESS_RW =          0,
+    MFI_LD_ACCSSS_RO =          2,
+    MFI_LD_ACCESS_BLOCKED =     3,
+};
+#define MFI_LD_ACCESS_MASK      3
+
+enum mfi_ld_state {
+    MFI_LD_STATE_OFFLINE =              0,
+    MFI_LD_STATE_PARTIALLY_DEGRADED =   1,
+    MFI_LD_STATE_DEGRADED =             2,
+    MFI_LD_STATE_OPTIMAL =              3
+};
+
+enum mfi_syspd_state {
+    MFI_PD_STATE_UNCONFIGURED_GOOD =    0x00,
+    MFI_PD_STATE_UNCONFIGURED_BAD =     0x01,
+    MFI_PD_STATE_HOT_SPARE =            0x02,
+    MFI_PD_STATE_OFFLINE =              0x10,
+    MFI_PD_STATE_FAILED =               0x11,
+    MFI_PD_STATE_REBUILD =              0x14,
+    MFI_PD_STATE_ONLINE =               0x18,
+    MFI_PD_STATE_COPYBACK =             0x20,
+    MFI_PD_STATE_SYSTEM =               0x40
+};
+
+struct mfi_ld_props {
+    union mfi_ld_ref ld;
+    char name[16];
+    uint8_t default_cache_policy;
+    uint8_t access_policy;
+    uint8_t disk_cache_policy;
+    uint8_t current_cache_policy;
+    uint8_t no_bgi;
+    uint8_t reserved[7];
+} QEMU_PACKED;
+
+struct mfi_ld_params {
+    uint8_t primary_raid_level;
+    uint8_t raid_level_qualifier;
+    uint8_t secondary_raid_level;
+    uint8_t stripe_size;
+    uint8_t num_drives;
+    uint8_t span_depth;
+    uint8_t state;
+    uint8_t init_state;
+    uint8_t is_consistent;
+    uint8_t reserved[23];
+} QEMU_PACKED;
+
+struct mfi_ld_progress {
+    uint32_t            active;
+#define MFI_LD_PROGRESS_CC      (1<<0)
+#define MFI_LD_PROGRESS_BGI     (1<<1)
+#define MFI_LD_PROGRESS_FGI     (1<<2)
+#define MFI_LD_PORGRESS_RECON   (1<<3)
+    struct mfi_progress cc;
+    struct mfi_progress bgi;
+    struct mfi_progress fgi;
+    struct mfi_progress recon;
+    struct mfi_progress reserved[4];
+} QEMU_PACKED;
+
+struct mfi_span {
+    uint64_t start_block;
+    uint64_t num_blocks;
+    uint16_t array_ref;
+    uint8_t reserved[6];
+} QEMU_PACKED;
+
+#define MFI_MAX_SPAN_DEPTH      8
+struct mfi_ld_config {
+    struct mfi_ld_props properties;
+    struct mfi_ld_params params;
+    struct mfi_span span[MFI_MAX_SPAN_DEPTH];
+} QEMU_PACKED;
+
+struct mfi_ld_info {
+    struct mfi_ld_config ld_config;
+    uint64_t size;
+    struct mfi_ld_progress progress;
+    uint16_t cluster_owner;
+    uint8_t reconstruct_active;
+    uint8_t reserved1[1];
+    uint8_t vpd_page83[64];
+    uint8_t reserved2[16];
+} QEMU_PACKED;
+
+union mfi_spare_type {
+    uint8_t flags;
+#define MFI_SPARE_IS_DEDICATED (1 << 0)
+#define MFI_SPARE_IS_REVERTABLE (1 << 1)
+#define MFI_SPARE_IS_ENCL_AFFINITY (1 << 2)
+    uint8_t type;
+} QEMU_PACKED;
+
+#define MFI_MAX_ARRAYS 16
+struct mfi_spare {
+    union mfi_pd_ref ref;
+    union mfi_spare_type spare_type;
+    uint8_t reserved[2];
+    uint8_t array_count;
+    uint16_t array_refd[MFI_MAX_ARRAYS];
+} QEMU_PACKED;
+
+#define MFI_MAX_ROW_SIZE 32
+struct mfi_array {
+    uint64_t size;
+    uint8_t num_drives;
+    uint8_t reserved;
+    uint16_t array_ref;
+    uint8_t pad[20];
+    struct {
+        union mfi_pd_ref ref;
+        uint16_t fw_state; /* enum mfi_syspd_state */
+        struct {
+            uint8_t pd;
+            uint8_t slot;
+        } encl;
+    } pd[MFI_MAX_ROW_SIZE];
+} QEMU_PACKED;
+
+struct mfi_config_data {
+    uint32_t size;
+    uint16_t array_count;
+    uint16_t array_size;
+    uint16_t log_drv_count;
+    uint16_t log_drv_size;
+    uint16_t spares_count;
+    uint16_t spares_size;
+    uint8_t reserved[16];
+    /*
+      struct mfi_array  array[];
+      struct mfi_ld_config ld[];
+      struct mfi_spare  spare[];
+    */
+} QEMU_PACKED;
+
+#define MFI_SCSI_MAX_TARGETS  128
+#define MFI_SCSI_MAX_LUNS       8
+#define MFI_SCSI_INITIATOR_ID 255
+#define MFI_SCSI_MAX_CMDS       8
+#define MFI_SCSI_MAX_CDB_LEN   16
+
+#endif /* MFI_REG_H */
diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c
new file mode 100644 (file)
index 0000000..6239ee1
--- /dev/null
@@ -0,0 +1,1889 @@
+#include "hw/hw.h"
+#include "qemu/error-report.h"
+#include "hw/scsi/scsi.h"
+#include "block/scsi.h"
+#include "hw/qdev.h"
+#include "sysemu/blockdev.h"
+#include "trace.h"
+#include "sysemu/dma.h"
+
+static char *scsibus_get_dev_path(DeviceState *dev);
+static char *scsibus_get_fw_dev_path(DeviceState *dev);
+static int scsi_req_parse(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf);
+static void scsi_req_dequeue(SCSIRequest *req);
+
+static Property scsi_props[] = {
+    DEFINE_PROP_UINT32("channel", SCSIDevice, channel, 0),
+    DEFINE_PROP_UINT32("scsi-id", SCSIDevice, id, -1),
+    DEFINE_PROP_UINT32("lun", SCSIDevice, lun, -1),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void scsi_bus_class_init(ObjectClass *klass, void *data)
+{
+    BusClass *k = BUS_CLASS(klass);
+
+    k->get_dev_path = scsibus_get_dev_path;
+    k->get_fw_dev_path = scsibus_get_fw_dev_path;
+}
+
+static const TypeInfo scsi_bus_info = {
+    .name = TYPE_SCSI_BUS,
+    .parent = TYPE_BUS,
+    .instance_size = sizeof(SCSIBus),
+    .class_init = scsi_bus_class_init,
+};
+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)
+{
+    qbus_create_inplace(&bus->qbus, TYPE_SCSI_BUS, host, NULL);
+    bus->busnr = next_scsi_bus++;
+    bus->info = info;
+    bus->qbus.allow_hotplug = 1;
+}
+
+static void scsi_dma_restart_bh(void *opaque)
+{
+    SCSIDevice *s = opaque;
+    SCSIRequest *req, *next;
+
+    qemu_bh_delete(s->bh);
+    s->bh = NULL;
+
+    QTAILQ_FOREACH_SAFE(req, &s->requests, next, next) {
+        scsi_req_ref(req);
+        if (req->retry) {
+            req->retry = false;
+            switch (req->cmd.mode) {
+            case SCSI_XFER_FROM_DEV:
+            case SCSI_XFER_TO_DEV:
+                scsi_req_continue(req);
+                break;
+            case SCSI_XFER_NONE:
+                assert(!req->sg);
+                scsi_req_dequeue(req);
+                scsi_req_enqueue(req);
+                break;
+            }
+        }
+        scsi_req_unref(req);
+    }
+}
+
+void scsi_req_retry(SCSIRequest *req)
+{
+    /* No need to save a reference, because scsi_dma_restart_bh just
+     * looks at the request list.  */
+    req->retry = true;
+}
+
+static void scsi_dma_restart_cb(void *opaque, int running, RunState state)
+{
+    SCSIDevice *s = opaque;
+
+    if (!running) {
+        return;
+    }
+    if (!s->bh) {
+        s->bh = qemu_bh_new(scsi_dma_restart_bh, s);
+        qemu_bh_schedule(s->bh);
+    }
+}
+
+static int scsi_qdev_init(DeviceState *qdev)
+{
+    SCSIDevice *dev = SCSI_DEVICE(qdev);
+    SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, dev->qdev.parent_bus);
+    SCSIDevice *d;
+    int rc = -1;
+
+    if (dev->channel > bus->info->max_channel) {
+        error_report("bad scsi channel id: %d", dev->channel);
+        goto err;
+    }
+    if (dev->id != -1 && dev->id > bus->info->max_target) {
+        error_report("bad scsi device id: %d", dev->id);
+        goto err;
+    }
+    if (dev->lun != -1 && dev->lun > bus->info->max_lun) {
+        error_report("bad scsi device lun: %d", dev->lun);
+        goto err;
+    }
+
+    if (dev->id == -1) {
+        int id = -1;
+        if (dev->lun == -1) {
+            dev->lun = 0;
+        }
+        do {
+            d = scsi_device_find(bus, dev->channel, ++id, dev->lun);
+        } while (d && d->lun == dev->lun && id < bus->info->max_target);
+        if (d && d->lun == dev->lun) {
+            error_report("no free target");
+            goto err;
+        }
+        dev->id = id;
+    } else if (dev->lun == -1) {
+        int lun = -1;
+        do {
+            d = scsi_device_find(bus, dev->channel, dev->id, ++lun);
+        } while (d && d->lun == lun && lun < bus->info->max_lun);
+        if (d && d->lun == lun) {
+            error_report("no free lun");
+            goto err;
+        }
+        dev->lun = lun;
+    } else {
+        d = scsi_device_find(bus, dev->channel, dev->id, dev->lun);
+        assert(d);
+        if (d->lun == dev->lun && dev != d) {
+            qdev_free(&d->qdev);
+        }
+    }
+
+    QTAILQ_INIT(&dev->requests);
+    rc = scsi_device_init(dev);
+    if (rc == 0) {
+        dev->vmsentry = qemu_add_vm_change_state_handler(scsi_dma_restart_cb,
+                                                         dev);
+    }
+
+    if (bus->info->hotplug) {
+        bus->info->hotplug(bus, dev);
+    }
+
+err:
+    return rc;
+}
+
+static int scsi_qdev_exit(DeviceState *qdev)
+{
+    SCSIDevice *dev = SCSI_DEVICE(qdev);
+
+    if (dev->vmsentry) {
+        qemu_del_vm_change_state_handler(dev->vmsentry);
+    }
+    scsi_device_destroy(dev);
+    return 0;
+}
+
+/* handle legacy '-drive if=scsi,...' cmd line args */
+SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockDriverState *bdrv,
+                                      int unit, bool removable, int bootindex,
+                                      const char *serial)
+{
+    const char *driver;
+    DeviceState *dev;
+
+    driver = bdrv_is_sg(bdrv) ? "scsi-generic" : "scsi-disk";
+    dev = qdev_create(&bus->qbus, driver);
+    qdev_prop_set_uint32(dev, "scsi-id", unit);
+    if (bootindex >= 0) {
+        qdev_prop_set_int32(dev, "bootindex", bootindex);
+    }
+    if (object_property_find(OBJECT(dev), "removable", NULL)) {
+        qdev_prop_set_bit(dev, "removable", removable);
+    }
+    if (serial) {
+        qdev_prop_set_string(dev, "serial", serial);
+    }
+    if (qdev_prop_set_drive(dev, "drive", bdrv) < 0) {
+        qdev_free(dev);
+        return NULL;
+    }
+    if (qdev_init(dev) < 0)
+        return NULL;
+    return SCSI_DEVICE(dev);
+}
+
+int scsi_bus_legacy_handle_cmdline(SCSIBus *bus)
+{
+    Location loc;
+    DriveInfo *dinfo;
+    int res = 0, unit;
+
+    loc_push_none(&loc);
+    for (unit = 0; unit <= bus->info->max_target; unit++) {
+        dinfo = drive_get(IF_SCSI, bus->busnr, unit);
+        if (dinfo == NULL) {
+            continue;
+        }
+        qemu_opts_loc_restore(dinfo->opts);
+        if (!scsi_bus_legacy_add_drive(bus, dinfo->bdrv, unit, false, -1, NULL)) {
+            res = -1;
+            break;
+        }
+    }
+    loc_pop(&loc);
+    return res;
+}
+
+static int32_t scsi_invalid_field(SCSIRequest *req, uint8_t *buf)
+{
+    scsi_req_build_sense(req, SENSE_CODE(INVALID_FIELD));
+    scsi_req_complete(req, CHECK_CONDITION);
+    return 0;
+}
+
+static const struct SCSIReqOps reqops_invalid_field = {
+    .size         = sizeof(SCSIRequest),
+    .send_command = scsi_invalid_field
+};
+
+/* SCSIReqOps implementation for invalid commands.  */
+
+static int32_t scsi_invalid_command(SCSIRequest *req, uint8_t *buf)
+{
+    scsi_req_build_sense(req, SENSE_CODE(INVALID_OPCODE));
+    scsi_req_complete(req, CHECK_CONDITION);
+    return 0;
+}
+
+static const struct SCSIReqOps reqops_invalid_opcode = {
+    .size         = sizeof(SCSIRequest),
+    .send_command = scsi_invalid_command
+};
+
+/* SCSIReqOps implementation for unit attention conditions.  */
+
+static int32_t scsi_unit_attention(SCSIRequest *req, uint8_t *buf)
+{
+    if (req->dev->unit_attention.key == UNIT_ATTENTION) {
+        scsi_req_build_sense(req, req->dev->unit_attention);
+    } else if (req->bus->unit_attention.key == UNIT_ATTENTION) {
+        scsi_req_build_sense(req, req->bus->unit_attention);
+    }
+    scsi_req_complete(req, CHECK_CONDITION);
+    return 0;
+}
+
+static const struct SCSIReqOps reqops_unit_attention = {
+    .size         = sizeof(SCSIRequest),
+    .send_command = scsi_unit_attention
+};
+
+/* SCSIReqOps implementation for REPORT LUNS and for commands sent to
+   an invalid LUN.  */
+
+typedef struct SCSITargetReq SCSITargetReq;
+
+struct SCSITargetReq {
+    SCSIRequest req;
+    int len;
+    uint8_t buf[2056];
+};
+
+static void store_lun(uint8_t *outbuf, int lun)
+{
+    if (lun < 256) {
+        outbuf[1] = lun;
+        return;
+    }
+    outbuf[1] = (lun & 255);
+    outbuf[0] = (lun >> 8) | 0x40;
+}
+
+static bool scsi_target_emulate_report_luns(SCSITargetReq *r)
+{
+    BusChild *kid;
+    int i, len, n;
+    int channel, id;
+    bool found_lun0;
+
+    if (r->req.cmd.xfer < 16) {
+        return false;
+    }
+    if (r->req.cmd.buf[2] > 2) {
+        return false;
+    }
+    channel = r->req.dev->channel;
+    id = r->req.dev->id;
+    found_lun0 = false;
+    n = 0;
+    QTAILQ_FOREACH(kid, &r->req.bus->qbus.children, sibling) {
+        DeviceState *qdev = kid->child;
+        SCSIDevice *dev = SCSI_DEVICE(qdev);
+
+        if (dev->channel == channel && dev->id == id) {
+            if (dev->lun == 0) {
+                found_lun0 = true;
+            }
+            n += 8;
+        }
+    }
+    if (!found_lun0) {
+        n += 8;
+    }
+    len = MIN(n + 8, r->req.cmd.xfer & ~7);
+    if (len > sizeof(r->buf)) {
+        /* TODO: > 256 LUNs? */
+        return false;
+    }
+
+    memset(r->buf, 0, len);
+    stl_be_p(&r->buf, n);
+    i = found_lun0 ? 8 : 16;
+    QTAILQ_FOREACH(kid, &r->req.bus->qbus.children, sibling) {
+        DeviceState *qdev = kid->child;
+        SCSIDevice *dev = SCSI_DEVICE(qdev);
+
+        if (dev->channel == channel && dev->id == id) {
+            store_lun(&r->buf[i], dev->lun);
+            i += 8;
+        }
+    }
+    assert(i == n + 8);
+    r->len = len;
+    return true;
+}
+
+static bool scsi_target_emulate_inquiry(SCSITargetReq *r)
+{
+    assert(r->req.dev->lun != r->req.lun);
+    if (r->req.cmd.buf[1] & 0x2) {
+        /* Command support data - optional, not implemented */
+        return false;
+    }
+
+    if (r->req.cmd.buf[1] & 0x1) {
+        /* Vital product data */
+        uint8_t page_code = r->req.cmd.buf[2];
+        r->buf[r->len++] = page_code ; /* this page */
+        r->buf[r->len++] = 0x00;
+
+        switch (page_code) {
+        case 0x00: /* Supported page codes, mandatory */
+        {
+            int pages;
+            pages = r->len++;
+            r->buf[r->len++] = 0x00; /* list of supported pages (this page) */
+            r->buf[pages] = r->len - pages - 1; /* number of pages */
+            break;
+        }
+        default:
+            return false;
+        }
+        /* done with EVPD */
+        assert(r->len < sizeof(r->buf));
+        r->len = MIN(r->req.cmd.xfer, r->len);
+        return true;
+    }
+
+    /* Standard INQUIRY data */
+    if (r->req.cmd.buf[2] != 0) {
+        return false;
+    }
+
+    /* PAGE CODE == 0 */
+    r->len = MIN(r->req.cmd.xfer, 36);
+    memset(r->buf, 0, r->len);
+    if (r->req.lun != 0) {
+        r->buf[0] = TYPE_NO_LUN;
+    } else {
+        r->buf[0] = TYPE_NOT_PRESENT | TYPE_INACTIVE;
+        r->buf[2] = 5; /* Version */
+        r->buf[3] = 2 | 0x10; /* HiSup, response data format */
+        r->buf[4] = r->len - 5; /* Additional Length = (Len - 1) - 4 */
+        r->buf[7] = 0x10 | (r->req.bus->info->tcq ? 0x02 : 0); /* Sync, TCQ.  */
+        memcpy(&r->buf[8], "QEMU    ", 8);
+        memcpy(&r->buf[16], "QEMU TARGET     ", 16);
+        pstrcpy((char *) &r->buf[32], 4, qemu_get_version());
+    }
+    return true;
+}
+
+static int32_t scsi_target_send_command(SCSIRequest *req, uint8_t *buf)
+{
+    SCSITargetReq *r = DO_UPCAST(SCSITargetReq, req, req);
+
+    switch (buf[0]) {
+    case REPORT_LUNS:
+        if (!scsi_target_emulate_report_luns(r)) {
+            goto illegal_request;
+        }
+        break;
+    case INQUIRY:
+        if (!scsi_target_emulate_inquiry(r)) {
+            goto illegal_request;
+        }
+        break;
+    case REQUEST_SENSE:
+        r->len = scsi_device_get_sense(r->req.dev, r->buf,
+                                       MIN(req->cmd.xfer, sizeof r->buf),
+                                       (req->cmd.buf[1] & 1) == 0);
+        if (r->req.dev->sense_is_ua) {
+            scsi_device_unit_attention_reported(req->dev);
+            r->req.dev->sense_len = 0;
+            r->req.dev->sense_is_ua = false;
+        }
+        break;
+    default:
+        scsi_req_build_sense(req, SENSE_CODE(LUN_NOT_SUPPORTED));
+        scsi_req_complete(req, CHECK_CONDITION);
+        return 0;
+    illegal_request:
+        scsi_req_build_sense(req, SENSE_CODE(INVALID_FIELD));
+        scsi_req_complete(req, CHECK_CONDITION);
+        return 0;
+    }
+
+    if (!r->len) {
+        scsi_req_complete(req, GOOD);
+    }
+    return r->len;
+}
+
+static void scsi_target_read_data(SCSIRequest *req)
+{
+    SCSITargetReq *r = DO_UPCAST(SCSITargetReq, req, req);
+    uint32_t n;
+
+    n = r->len;
+    if (n > 0) {
+        r->len = 0;
+        scsi_req_data(&r->req, n);
+    } else {
+        scsi_req_complete(&r->req, GOOD);
+    }
+}
+
+static uint8_t *scsi_target_get_buf(SCSIRequest *req)
+{
+    SCSITargetReq *r = DO_UPCAST(SCSITargetReq, req, req);
+
+    return r->buf;
+}
+
+static const struct SCSIReqOps reqops_target_command = {
+    .size         = sizeof(SCSITargetReq),
+    .send_command = scsi_target_send_command,
+    .read_data    = scsi_target_read_data,
+    .get_buf      = scsi_target_get_buf,
+};
+
+
+SCSIRequest *scsi_req_alloc(const SCSIReqOps *reqops, SCSIDevice *d,
+                            uint32_t tag, uint32_t lun, void *hba_private)
+{
+    SCSIRequest *req;
+
+    req = g_malloc0(reqops->size);
+    req->refcount = 1;
+    req->bus = scsi_bus_from_device(d);
+    req->dev = d;
+    req->tag = tag;
+    req->lun = lun;
+    req->hba_private = hba_private;
+    req->status = -1;
+    req->sense_len = 0;
+    req->ops = reqops;
+    trace_scsi_req_alloc(req->dev->id, req->lun, req->tag);
+    return req;
+}
+
+SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun,
+                          uint8_t *buf, void *hba_private)
+{
+    SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, d->qdev.parent_bus);
+    SCSIRequest *req;
+    SCSICommand cmd;
+
+    if (scsi_req_parse(&cmd, d, buf) != 0) {
+        trace_scsi_req_parse_bad(d->id, lun, tag, buf[0]);
+        req = scsi_req_alloc(&reqops_invalid_opcode, d, tag, lun, hba_private);
+    } else {
+        trace_scsi_req_parsed(d->id, lun, tag, buf[0],
+                              cmd.mode, cmd.xfer);
+        if (cmd.lba != -1) {
+            trace_scsi_req_parsed_lba(d->id, lun, tag, buf[0],
+                                      cmd.lba);
+        }
+
+        if (cmd.xfer > INT32_MAX) {
+            req = scsi_req_alloc(&reqops_invalid_field, d, tag, lun, hba_private);
+        } else if ((d->unit_attention.key == UNIT_ATTENTION ||
+                   bus->unit_attention.key == UNIT_ATTENTION) &&
+                  (buf[0] != INQUIRY &&
+                   buf[0] != REPORT_LUNS &&
+                   buf[0] != GET_CONFIGURATION &&
+                   buf[0] != GET_EVENT_STATUS_NOTIFICATION &&
+
+                   /*
+                    * If we already have a pending unit attention condition,
+                    * report this one before triggering another one.
+                    */
+                   !(buf[0] == REQUEST_SENSE && d->sense_is_ua))) {
+            req = scsi_req_alloc(&reqops_unit_attention, d, tag, lun,
+                                 hba_private);
+        } else if (lun != d->lun ||
+                   buf[0] == REPORT_LUNS ||
+                   (buf[0] == REQUEST_SENSE && d->sense_len)) {
+            req = scsi_req_alloc(&reqops_target_command, d, tag, lun,
+                                 hba_private);
+        } else {
+            req = scsi_device_alloc_req(d, tag, lun, buf, hba_private);
+        }
+    }
+
+    req->cmd = cmd;
+    req->resid = req->cmd.xfer;
+
+    switch (buf[0]) {
+    case INQUIRY:
+        trace_scsi_inquiry(d->id, lun, tag, cmd.buf[1], cmd.buf[2]);
+        break;
+    case TEST_UNIT_READY:
+        trace_scsi_test_unit_ready(d->id, lun, tag);
+        break;
+    case REPORT_LUNS:
+        trace_scsi_report_luns(d->id, lun, tag);
+        break;
+    case REQUEST_SENSE:
+        trace_scsi_request_sense(d->id, lun, tag);
+        break;
+    default:
+        break;
+    }
+
+    return req;
+}
+
+uint8_t *scsi_req_get_buf(SCSIRequest *req)
+{
+    return req->ops->get_buf(req);
+}
+
+static void scsi_clear_unit_attention(SCSIRequest *req)
+{
+    SCSISense *ua;
+    if (req->dev->unit_attention.key != UNIT_ATTENTION &&
+        req->bus->unit_attention.key != UNIT_ATTENTION) {
+        return;
+    }
+
+    /*
+     * If an INQUIRY command enters the enabled command state,
+     * the device server shall [not] clear any unit attention condition;
+     * See also MMC-6, paragraphs 6.5 and 6.6.2.
+     */
+    if (req->cmd.buf[0] == INQUIRY ||
+        req->cmd.buf[0] == GET_CONFIGURATION ||
+        req->cmd.buf[0] == GET_EVENT_STATUS_NOTIFICATION) {
+        return;
+    }
+
+    if (req->dev->unit_attention.key == UNIT_ATTENTION) {
+        ua = &req->dev->unit_attention;
+    } else {
+        ua = &req->bus->unit_attention;
+    }
+
+    /*
+     * If a REPORT LUNS command enters the enabled command state, [...]
+     * the device server shall clear any pending unit attention condition
+     * with an additional sense code of REPORTED LUNS DATA HAS CHANGED.
+     */
+    if (req->cmd.buf[0] == REPORT_LUNS &&
+        !(ua->asc == SENSE_CODE(REPORTED_LUNS_CHANGED).asc &&
+          ua->ascq == SENSE_CODE(REPORTED_LUNS_CHANGED).ascq)) {
+        return;
+    }
+
+    *ua = SENSE_CODE(NO_SENSE);
+}
+
+int scsi_req_get_sense(SCSIRequest *req, uint8_t *buf, int len)
+{
+    int ret;
+
+    assert(len >= 14);
+    if (!req->sense_len) {
+        return 0;
+    }
+
+    ret = scsi_build_sense(req->sense, req->sense_len, buf, len, true);
+
+    /*
+     * FIXME: clearing unit attention conditions upon autosense should be done
+     * only if the UA_INTLCK_CTRL field in the Control mode page is set to 00b
+     * (SAM-5, 5.14).
+     *
+     * We assume UA_INTLCK_CTRL to be 00b for HBAs that support autosense, and
+     * 10b for HBAs that do not support it (do not call scsi_req_get_sense).
+     * Here we handle unit attention clearing for UA_INTLCK_CTRL == 00b.
+     */
+    if (req->dev->sense_is_ua) {
+        scsi_device_unit_attention_reported(req->dev);
+        req->dev->sense_len = 0;
+        req->dev->sense_is_ua = false;
+    }
+    return ret;
+}
+
+int scsi_device_get_sense(SCSIDevice *dev, uint8_t *buf, int len, bool fixed)
+{
+    return scsi_build_sense(dev->sense, dev->sense_len, buf, len, fixed);
+}
+
+void scsi_req_build_sense(SCSIRequest *req, SCSISense sense)
+{
+    trace_scsi_req_build_sense(req->dev->id, req->lun, req->tag,
+                               sense.key, sense.asc, sense.ascq);
+    memset(req->sense, 0, 18);
+    req->sense[0] = 0x70;
+    req->sense[2] = sense.key;
+    req->sense[7] = 10;
+    req->sense[12] = sense.asc;
+    req->sense[13] = sense.ascq;
+    req->sense_len = 18;
+}
+
+static void scsi_req_enqueue_internal(SCSIRequest *req)
+{
+    assert(!req->enqueued);
+    scsi_req_ref(req);
+    if (req->bus->info->get_sg_list) {
+        req->sg = req->bus->info->get_sg_list(req);
+    } else {
+        req->sg = NULL;
+    }
+    req->enqueued = true;
+    QTAILQ_INSERT_TAIL(&req->dev->requests, req, next);
+}
+
+int32_t scsi_req_enqueue(SCSIRequest *req)
+{
+    int32_t rc;
+
+    assert(!req->retry);
+    scsi_req_enqueue_internal(req);
+    scsi_req_ref(req);
+    rc = req->ops->send_command(req, req->cmd.buf);
+    scsi_req_unref(req);
+    return rc;
+}
+
+static void scsi_req_dequeue(SCSIRequest *req)
+{
+    trace_scsi_req_dequeue(req->dev->id, req->lun, req->tag);
+    req->retry = false;
+    if (req->enqueued) {
+        QTAILQ_REMOVE(&req->dev->requests, req, next);
+        req->enqueued = false;
+        scsi_req_unref(req);
+    }
+}
+
+static int scsi_get_performance_length(int num_desc, int type, int data_type)
+{
+    /* MMC-6, paragraph 6.7.  */
+    switch (type) {
+    case 0:
+        if ((data_type & 3) == 0) {
+            /* Each descriptor is as in Table 295 - Nominal performance.  */
+            return 16 * num_desc + 8;
+        } else {
+            /* Each descriptor is as in Table 296 - Exceptions.  */
+            return 6 * num_desc + 8;
+        }
+    case 1:
+    case 4:
+    case 5:
+        return 8 * num_desc + 8;
+    case 2:
+        return 2048 * num_desc + 8;
+    case 3:
+        return 16 * num_desc + 8;
+    default:
+        return 8;
+    }
+}
+
+static int ata_passthrough_xfer_unit(SCSIDevice *dev, uint8_t *buf)
+{
+    int byte_block = (buf[2] >> 2) & 0x1;
+    int type = (buf[2] >> 4) & 0x1;
+    int xfer_unit;
+
+    if (byte_block) {
+        if (type) {
+            xfer_unit = dev->blocksize;
+        } else {
+            xfer_unit = 512;
+        }
+    } else {
+        xfer_unit = 1;
+    }
+
+    return xfer_unit;
+}
+
+static int ata_passthrough_12_xfer_size(SCSIDevice *dev, uint8_t *buf)
+{
+    int length = buf[2] & 0x3;
+    int xfer;
+    int unit = ata_passthrough_xfer_unit(dev, buf);
+
+    switch (length) {
+    case 0:
+    case 3: /* USB-specific.  */
+    default:
+        xfer = 0;
+        break;
+    case 1:
+        xfer = buf[3];
+        break;
+    case 2:
+        xfer = buf[4];
+        break;
+    }
+
+    return xfer * unit;
+}
+
+static int ata_passthrough_16_xfer_size(SCSIDevice *dev, uint8_t *buf)
+{
+    int extend = buf[1] & 0x1;
+    int length = buf[2] & 0x3;
+    int xfer;
+    int unit = ata_passthrough_xfer_unit(dev, buf);
+
+    switch (length) {
+    case 0:
+    case 3: /* USB-specific.  */
+    default:
+        xfer = 0;
+        break;
+    case 1:
+        xfer = buf[4];
+        xfer |= (extend ? buf[3] << 8 : 0);
+        break;
+    case 2:
+        xfer = buf[6];
+        xfer |= (extend ? buf[5] << 8 : 0);
+        break;
+    }
+
+    return xfer * unit;
+}
+
+uint32_t scsi_data_cdb_length(uint8_t *buf)
+{
+    if ((buf[0] >> 5) == 0 && buf[4] == 0) {
+        return 256;
+    } else {
+        return scsi_cdb_length(buf);
+    }
+}
+
+uint32_t scsi_cdb_length(uint8_t *buf)
+{
+    switch (buf[0] >> 5) {
+    case 0:
+        return buf[4];
+        break;
+    case 1:
+    case 2:
+        return lduw_be_p(&buf[7]);
+        break;
+    case 4:
+        return ldl_be_p(&buf[10]) & 0xffffffffULL;
+        break;
+    case 5:
+        return ldl_be_p(&buf[6]) & 0xffffffffULL;
+        break;
+    default:
+        return -1;
+    }
+}
+
+static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
+{
+    cmd->xfer = scsi_cdb_length(buf);
+    switch (buf[0]) {
+    case TEST_UNIT_READY:
+    case REWIND:
+    case START_STOP:
+    case SET_CAPACITY:
+    case WRITE_FILEMARKS:
+    case WRITE_FILEMARKS_16:
+    case SPACE:
+    case RESERVE:
+    case RELEASE:
+    case ERASE:
+    case ALLOW_MEDIUM_REMOVAL:
+    case VERIFY_10:
+    case SEEK_10:
+    case SYNCHRONIZE_CACHE:
+    case SYNCHRONIZE_CACHE_16:
+    case LOCATE_16:
+    case LOCK_UNLOCK_CACHE:
+    case SET_CD_SPEED:
+    case SET_LIMITS:
+    case WRITE_LONG_10:
+    case UPDATE_BLOCK:
+    case RESERVE_TRACK:
+    case SET_READ_AHEAD:
+    case PRE_FETCH:
+    case PRE_FETCH_16:
+    case ALLOW_OVERWRITE:
+        cmd->xfer = 0;
+        break;
+    case MODE_SENSE:
+        break;
+    case WRITE_SAME_10:
+    case WRITE_SAME_16:
+        cmd->xfer = dev->blocksize;
+        break;
+    case READ_CAPACITY_10:
+        cmd->xfer = 8;
+        break;
+    case READ_BLOCK_LIMITS:
+        cmd->xfer = 6;
+        break;
+    case SEND_VOLUME_TAG:
+        /* GPCMD_SET_STREAMING from multimedia commands.  */
+        if (dev->type == TYPE_ROM) {
+            cmd->xfer = buf[10] | (buf[9] << 8);
+        } else {
+            cmd->xfer = buf[9] | (buf[8] << 8);
+        }
+        break;
+    case WRITE_6:
+        /* length 0 means 256 blocks */
+        if (cmd->xfer == 0) {
+            cmd->xfer = 256;
+        }
+    case WRITE_10:
+    case WRITE_VERIFY_10:
+    case WRITE_12:
+    case WRITE_VERIFY_12:
+    case WRITE_16:
+    case WRITE_VERIFY_16:
+        cmd->xfer *= dev->blocksize;
+        break;
+    case READ_6:
+    case READ_REVERSE:
+        /* length 0 means 256 blocks */
+        if (cmd->xfer == 0) {
+            cmd->xfer = 256;
+        }
+    case READ_10:
+    case RECOVER_BUFFERED_DATA:
+    case READ_12:
+    case READ_16:
+        cmd->xfer *= dev->blocksize;
+        break;
+    case FORMAT_UNIT:
+        /* MMC mandates the parameter list to be 12-bytes long.  Parameters
+         * for block devices are restricted to the header right now.  */
+        if (dev->type == TYPE_ROM && (buf[1] & 16)) {
+            cmd->xfer = 12;
+        } else {
+            cmd->xfer = (buf[1] & 16) == 0 ? 0 : (buf[1] & 32 ? 8 : 4);
+        }
+        break;
+    case INQUIRY:
+    case RECEIVE_DIAGNOSTIC:
+    case SEND_DIAGNOSTIC:
+        cmd->xfer = buf[4] | (buf[3] << 8);
+        break;
+    case READ_CD:
+    case READ_BUFFER:
+    case WRITE_BUFFER:
+    case SEND_CUE_SHEET:
+        cmd->xfer = buf[8] | (buf[7] << 8) | (buf[6] << 16);
+        break;
+    case PERSISTENT_RESERVE_OUT:
+        cmd->xfer = ldl_be_p(&buf[5]) & 0xffffffffULL;
+        break;
+    case ERASE_12:
+        if (dev->type == TYPE_ROM) {
+            /* MMC command GET PERFORMANCE.  */
+            cmd->xfer = scsi_get_performance_length(buf[9] | (buf[8] << 8),
+                                                    buf[10], buf[1] & 0x1f);
+        }
+        break;
+    case MECHANISM_STATUS:
+    case READ_DVD_STRUCTURE:
+    case SEND_DVD_STRUCTURE:
+    case MAINTENANCE_OUT:
+    case MAINTENANCE_IN:
+        if (dev->type == TYPE_ROM) {
+            /* GPCMD_REPORT_KEY and GPCMD_SEND_KEY from multi media commands */
+            cmd->xfer = buf[9] | (buf[8] << 8);
+        }
+        break;
+    case ATA_PASSTHROUGH_12:
+        if (dev->type == TYPE_ROM) {
+            /* BLANK command of MMC */
+            cmd->xfer = 0;
+        } else {
+            cmd->xfer = ata_passthrough_12_xfer_size(dev, buf);
+        }
+        break;
+    case ATA_PASSTHROUGH_16:
+        cmd->xfer = ata_passthrough_16_xfer_size(dev, buf);
+        break;
+    }
+    return 0;
+}
+
+static int scsi_req_stream_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
+{
+    switch (buf[0]) {
+    /* stream commands */
+    case ERASE_12:
+    case ERASE_16:
+        cmd->xfer = 0;
+        break;
+    case READ_6:
+    case READ_REVERSE:
+    case RECOVER_BUFFERED_DATA:
+    case WRITE_6:
+        cmd->xfer = buf[4] | (buf[3] << 8) | (buf[2] << 16);
+        if (buf[1] & 0x01) { /* fixed */
+            cmd->xfer *= dev->blocksize;
+        }
+        break;
+    case READ_16:
+    case READ_REVERSE_16:
+    case VERIFY_16:
+    case WRITE_16:
+        cmd->xfer = buf[14] | (buf[13] << 8) | (buf[12] << 16);
+        if (buf[1] & 0x01) { /* fixed */
+            cmd->xfer *= dev->blocksize;
+        }
+        break;
+    case REWIND:
+    case LOAD_UNLOAD:
+        cmd->xfer = 0;
+        break;
+    case SPACE_16:
+        cmd->xfer = buf[13] | (buf[12] << 8);
+        break;
+    case READ_POSITION:
+        switch (buf[1] & 0x1f) /* operation code */ {
+        case SHORT_FORM_BLOCK_ID:
+        case SHORT_FORM_VENDOR_SPECIFIC:
+            cmd->xfer = 20;
+            break;
+        case LONG_FORM:
+            cmd->xfer = 32;
+            break;
+        case EXTENDED_FORM:
+            cmd->xfer = buf[8] | (buf[7] << 8);
+            break;
+        default:
+            return -1;
+        }
+
+        break;
+    case FORMAT_UNIT:
+        cmd->xfer = buf[4] | (buf[3] << 8);
+        break;
+    /* generic commands */
+    default:
+        return scsi_req_length(cmd, dev, buf);
+    }
+    return 0;
+}
+
+static int scsi_req_medium_changer_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
+{
+    switch (buf[0]) {
+    /* medium changer commands */
+    case EXCHANGE_MEDIUM:
+    case INITIALIZE_ELEMENT_STATUS:
+    case INITIALIZE_ELEMENT_STATUS_WITH_RANGE:
+    case MOVE_MEDIUM:
+    case POSITION_TO_ELEMENT:
+        cmd->xfer = 0;
+        break;
+    case READ_ELEMENT_STATUS:
+        cmd->xfer = buf[9] | (buf[8] << 8) | (buf[7] << 16);
+        break;
+
+    /* generic commands */
+    default:
+        return scsi_req_length(cmd, dev, buf);
+    }
+    return 0;
+}
+
+
+static void scsi_cmd_xfer_mode(SCSICommand *cmd)
+{
+    if (!cmd->xfer) {
+        cmd->mode = SCSI_XFER_NONE;
+        return;
+    }
+    switch (cmd->buf[0]) {
+    case WRITE_6:
+    case WRITE_10:
+    case WRITE_VERIFY_10:
+    case WRITE_12:
+    case WRITE_VERIFY_12:
+    case WRITE_16:
+    case WRITE_VERIFY_16:
+    case COPY:
+    case COPY_VERIFY:
+    case COMPARE:
+    case CHANGE_DEFINITION:
+    case LOG_SELECT:
+    case MODE_SELECT:
+    case MODE_SELECT_10:
+    case SEND_DIAGNOSTIC:
+    case WRITE_BUFFER:
+    case FORMAT_UNIT:
+    case REASSIGN_BLOCKS:
+    case SEARCH_EQUAL:
+    case SEARCH_HIGH:
+    case SEARCH_LOW:
+    case UPDATE_BLOCK:
+    case WRITE_LONG_10:
+    case WRITE_SAME_10:
+    case WRITE_SAME_16:
+    case UNMAP:
+    case SEARCH_HIGH_12:
+    case SEARCH_EQUAL_12:
+    case SEARCH_LOW_12:
+    case MEDIUM_SCAN:
+    case SEND_VOLUME_TAG:
+    case SEND_CUE_SHEET:
+    case SEND_DVD_STRUCTURE:
+    case PERSISTENT_RESERVE_OUT:
+    case MAINTENANCE_OUT:
+        cmd->mode = SCSI_XFER_TO_DEV;
+        break;
+    case ATA_PASSTHROUGH_12:
+    case ATA_PASSTHROUGH_16:
+        /* T_DIR */
+        cmd->mode = (cmd->buf[2] & 0x8) ?
+                   SCSI_XFER_FROM_DEV : SCSI_XFER_TO_DEV;
+        break;
+    default:
+        cmd->mode = SCSI_XFER_FROM_DEV;
+        break;
+    }
+}
+
+static uint64_t scsi_cmd_lba(SCSICommand *cmd)
+{
+    uint8_t *buf = cmd->buf;
+    uint64_t lba;
+
+    switch (buf[0] >> 5) {
+    case 0:
+        lba = ldl_be_p(&buf[0]) & 0x1fffff;
+        break;
+    case 1:
+    case 2:
+    case 5:
+        lba = ldl_be_p(&buf[2]) & 0xffffffffULL;
+        break;
+    case 4:
+        lba = ldq_be_p(&buf[2]);
+        break;
+    default:
+        lba = -1;
+
+    }
+    return lba;
+}
+
+int scsi_req_parse(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
+{
+    int rc;
+
+    switch (buf[0] >> 5) {
+    case 0:
+        cmd->len = 6;
+        break;
+    case 1:
+    case 2:
+        cmd->len = 10;
+        break;
+    case 4:
+        cmd->len = 16;
+        break;
+    case 5:
+        cmd->len = 12;
+        break;
+    default:
+        return -1;
+    }
+
+    switch (dev->type) {
+    case TYPE_TAPE:
+        rc = scsi_req_stream_length(cmd, dev, buf);
+        break;
+    case TYPE_MEDIUM_CHANGER:
+        rc = scsi_req_medium_changer_length(cmd, dev, buf);
+        break;
+    default:
+        rc = scsi_req_length(cmd, dev, buf);
+        break;
+    }
+
+    if (rc != 0)
+        return rc;
+
+    memcpy(cmd->buf, buf, cmd->len);
+    scsi_cmd_xfer_mode(cmd);
+    cmd->lba = scsi_cmd_lba(cmd);
+    return 0;
+}
+
+void scsi_device_report_change(SCSIDevice *dev, SCSISense sense)
+{
+    SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, dev->qdev.parent_bus);
+
+    scsi_device_set_ua(dev, sense);
+    if (bus->info->change) {
+        bus->info->change(bus, dev, sense);
+    }
+}
+
+/*
+ * Predefined sense codes
+ */
+
+/* No sense data available */
+const struct SCSISense sense_code_NO_SENSE = {
+    .key = NO_SENSE , .asc = 0x00 , .ascq = 0x00
+};
+
+/* LUN not ready, Manual intervention required */
+const struct SCSISense sense_code_LUN_NOT_READY = {
+    .key = NOT_READY, .asc = 0x04, .ascq = 0x03
+};
+
+/* LUN not ready, Medium not present */
+const struct SCSISense sense_code_NO_MEDIUM = {
+    .key = NOT_READY, .asc = 0x3a, .ascq = 0x00
+};
+
+/* LUN not ready, medium removal prevented */
+const struct SCSISense sense_code_NOT_READY_REMOVAL_PREVENTED = {
+    .key = NOT_READY, .asc = 0x53, .ascq = 0x02
+};
+
+/* Hardware error, internal target failure */
+const struct SCSISense sense_code_TARGET_FAILURE = {
+    .key = HARDWARE_ERROR, .asc = 0x44, .ascq = 0x00
+};
+
+/* Illegal request, invalid command operation code */
+const struct SCSISense sense_code_INVALID_OPCODE = {
+    .key = ILLEGAL_REQUEST, .asc = 0x20, .ascq = 0x00
+};
+
+/* Illegal request, LBA out of range */
+const struct SCSISense sense_code_LBA_OUT_OF_RANGE = {
+    .key = ILLEGAL_REQUEST, .asc = 0x21, .ascq = 0x00
+};
+
+/* Illegal request, Invalid field in CDB */
+const struct SCSISense sense_code_INVALID_FIELD = {
+    .key = ILLEGAL_REQUEST, .asc = 0x24, .ascq = 0x00
+};
+
+/* Illegal request, Invalid field in parameter list */
+const struct SCSISense sense_code_INVALID_PARAM = {
+    .key = ILLEGAL_REQUEST, .asc = 0x26, .ascq = 0x00
+};
+
+/* Illegal request, Parameter list length error */
+const struct SCSISense sense_code_INVALID_PARAM_LEN = {
+    .key = ILLEGAL_REQUEST, .asc = 0x1a, .ascq = 0x00
+};
+
+/* Illegal request, LUN not supported */
+const struct SCSISense sense_code_LUN_NOT_SUPPORTED = {
+    .key = ILLEGAL_REQUEST, .asc = 0x25, .ascq = 0x00
+};
+
+/* Illegal request, Saving parameters not supported */
+const struct SCSISense sense_code_SAVING_PARAMS_NOT_SUPPORTED = {
+    .key = ILLEGAL_REQUEST, .asc = 0x39, .ascq = 0x00
+};
+
+/* Illegal request, Incompatible medium installed */
+const struct SCSISense sense_code_INCOMPATIBLE_FORMAT = {
+    .key = ILLEGAL_REQUEST, .asc = 0x30, .ascq = 0x00
+};
+
+/* Illegal request, medium removal prevented */
+const struct SCSISense sense_code_ILLEGAL_REQ_REMOVAL_PREVENTED = {
+    .key = ILLEGAL_REQUEST, .asc = 0x53, .ascq = 0x02
+};
+
+/* Command aborted, I/O process terminated */
+const struct SCSISense sense_code_IO_ERROR = {
+    .key = ABORTED_COMMAND, .asc = 0x00, .ascq = 0x06
+};
+
+/* Command aborted, I_T Nexus loss occurred */
+const struct SCSISense sense_code_I_T_NEXUS_LOSS = {
+    .key = ABORTED_COMMAND, .asc = 0x29, .ascq = 0x07
+};
+
+/* Command aborted, Logical Unit failure */
+const struct SCSISense sense_code_LUN_FAILURE = {
+    .key = ABORTED_COMMAND, .asc = 0x3e, .ascq = 0x01
+};
+
+/* Unit attention, Capacity data has changed */
+const struct SCSISense sense_code_CAPACITY_CHANGED = {
+    .key = UNIT_ATTENTION, .asc = 0x2a, .ascq = 0x09
+};
+
+/* Unit attention, Power on, reset or bus device reset occurred */
+const struct SCSISense sense_code_RESET = {
+    .key = UNIT_ATTENTION, .asc = 0x29, .ascq = 0x00
+};
+
+/* Unit attention, No medium */
+const struct SCSISense sense_code_UNIT_ATTENTION_NO_MEDIUM = {
+    .key = UNIT_ATTENTION, .asc = 0x3a, .ascq = 0x00
+};
+
+/* Unit attention, Medium may have changed */
+const struct SCSISense sense_code_MEDIUM_CHANGED = {
+    .key = UNIT_ATTENTION, .asc = 0x28, .ascq = 0x00
+};
+
+/* Unit attention, Reported LUNs data has changed */
+const struct SCSISense sense_code_REPORTED_LUNS_CHANGED = {
+    .key = UNIT_ATTENTION, .asc = 0x3f, .ascq = 0x0e
+};
+
+/* Unit attention, Device internal reset */
+const struct SCSISense sense_code_DEVICE_INTERNAL_RESET = {
+    .key = UNIT_ATTENTION, .asc = 0x29, .ascq = 0x04
+};
+
+/* Data Protection, Write Protected */
+const struct SCSISense sense_code_WRITE_PROTECTED = {
+    .key = DATA_PROTECT, .asc = 0x27, .ascq = 0x00
+};
+
+/*
+ * scsi_build_sense
+ *
+ * Convert between fixed and descriptor sense buffers
+ */
+int scsi_build_sense(uint8_t *in_buf, int in_len,
+                     uint8_t *buf, int len, bool fixed)
+{
+    bool fixed_in;
+    SCSISense sense;
+    if (!fixed && len < 8) {
+        return 0;
+    }
+
+    if (in_len == 0) {
+        sense.key = NO_SENSE;
+        sense.asc = 0;
+        sense.ascq = 0;
+    } else {
+        fixed_in = (in_buf[0] & 2) == 0;
+
+        if (fixed == fixed_in) {
+            memcpy(buf, in_buf, MIN(len, in_len));
+            return MIN(len, in_len);
+        }
+
+        if (fixed_in) {
+            sense.key = in_buf[2];
+            sense.asc = in_buf[12];
+            sense.ascq = in_buf[13];
+        } else {
+            sense.key = in_buf[1];
+            sense.asc = in_buf[2];
+            sense.ascq = in_buf[3];
+        }
+    }
+
+    memset(buf, 0, len);
+    if (fixed) {
+        /* Return fixed format sense buffer */
+        buf[0] = 0x70;
+        buf[2] = sense.key;
+        buf[7] = 10;
+        buf[12] = sense.asc;
+        buf[13] = sense.ascq;
+        return MIN(len, 18);
+    } else {
+        /* Return descriptor format sense buffer */
+        buf[0] = 0x72;
+        buf[1] = sense.key;
+        buf[2] = sense.asc;
+        buf[3] = sense.ascq;
+        return 8;
+    }
+}
+
+static const char *scsi_command_name(uint8_t cmd)
+{
+    static const char *names[] = {
+        [ TEST_UNIT_READY          ] = "TEST_UNIT_READY",
+        [ REWIND                   ] = "REWIND",
+        [ REQUEST_SENSE            ] = "REQUEST_SENSE",
+        [ FORMAT_UNIT              ] = "FORMAT_UNIT",
+        [ READ_BLOCK_LIMITS        ] = "READ_BLOCK_LIMITS",
+        [ REASSIGN_BLOCKS          ] = "REASSIGN_BLOCKS/INITIALIZE ELEMENT STATUS",
+        /* LOAD_UNLOAD and INITIALIZE_ELEMENT_STATUS use the same operation code */
+        [ READ_6                   ] = "READ_6",
+        [ WRITE_6                  ] = "WRITE_6",
+        [ SET_CAPACITY             ] = "SET_CAPACITY",
+        [ READ_REVERSE             ] = "READ_REVERSE",
+        [ WRITE_FILEMARKS          ] = "WRITE_FILEMARKS",
+        [ SPACE                    ] = "SPACE",
+        [ INQUIRY                  ] = "INQUIRY",
+        [ RECOVER_BUFFERED_DATA    ] = "RECOVER_BUFFERED_DATA",
+        [ MAINTENANCE_IN           ] = "MAINTENANCE_IN",
+        [ MAINTENANCE_OUT          ] = "MAINTENANCE_OUT",
+        [ MODE_SELECT              ] = "MODE_SELECT",
+        [ RESERVE                  ] = "RESERVE",
+        [ RELEASE                  ] = "RELEASE",
+        [ COPY                     ] = "COPY",
+        [ ERASE                    ] = "ERASE",
+        [ MODE_SENSE               ] = "MODE_SENSE",
+        [ START_STOP               ] = "START_STOP/LOAD_UNLOAD",
+        /* LOAD_UNLOAD and START_STOP use the same operation code */
+        [ RECEIVE_DIAGNOSTIC       ] = "RECEIVE_DIAGNOSTIC",
+        [ SEND_DIAGNOSTIC          ] = "SEND_DIAGNOSTIC",
+        [ ALLOW_MEDIUM_REMOVAL     ] = "ALLOW_MEDIUM_REMOVAL",
+        [ READ_CAPACITY_10         ] = "READ_CAPACITY_10",
+        [ READ_10                  ] = "READ_10",
+        [ WRITE_10                 ] = "WRITE_10",
+        [ SEEK_10                  ] = "SEEK_10/POSITION_TO_ELEMENT",
+        /* SEEK_10 and POSITION_TO_ELEMENT use the same operation code */
+        [ WRITE_VERIFY_10          ] = "WRITE_VERIFY_10",
+        [ VERIFY_10                ] = "VERIFY_10",
+        [ SEARCH_HIGH              ] = "SEARCH_HIGH",
+        [ SEARCH_EQUAL             ] = "SEARCH_EQUAL",
+        [ SEARCH_LOW               ] = "SEARCH_LOW",
+        [ SET_LIMITS               ] = "SET_LIMITS",
+        [ PRE_FETCH                ] = "PRE_FETCH/READ_POSITION",
+        /* READ_POSITION and PRE_FETCH use the same operation code */
+        [ SYNCHRONIZE_CACHE        ] = "SYNCHRONIZE_CACHE",
+        [ LOCK_UNLOCK_CACHE        ] = "LOCK_UNLOCK_CACHE",
+        [ READ_DEFECT_DATA         ] = "READ_DEFECT_DATA/INITIALIZE_ELEMENT_STATUS_WITH_RANGE",
+        /* READ_DEFECT_DATA and INITIALIZE_ELEMENT_STATUS_WITH_RANGE use the same operation code */
+        [ MEDIUM_SCAN              ] = "MEDIUM_SCAN",
+        [ COMPARE                  ] = "COMPARE",
+        [ COPY_VERIFY              ] = "COPY_VERIFY",
+        [ WRITE_BUFFER             ] = "WRITE_BUFFER",
+        [ READ_BUFFER              ] = "READ_BUFFER",
+        [ UPDATE_BLOCK             ] = "UPDATE_BLOCK",
+        [ READ_LONG_10             ] = "READ_LONG_10",
+        [ WRITE_LONG_10            ] = "WRITE_LONG_10",
+        [ CHANGE_DEFINITION        ] = "CHANGE_DEFINITION",
+        [ WRITE_SAME_10            ] = "WRITE_SAME_10",
+        [ UNMAP                    ] = "UNMAP",
+        [ READ_TOC                 ] = "READ_TOC",
+        [ REPORT_DENSITY_SUPPORT   ] = "REPORT_DENSITY_SUPPORT",
+        [ SANITIZE                 ] = "SANITIZE",
+        [ GET_CONFIGURATION        ] = "GET_CONFIGURATION",
+        [ LOG_SELECT               ] = "LOG_SELECT",
+        [ LOG_SENSE                ] = "LOG_SENSE",
+        [ MODE_SELECT_10           ] = "MODE_SELECT_10",
+        [ RESERVE_10               ] = "RESERVE_10",
+        [ RELEASE_10               ] = "RELEASE_10",
+        [ MODE_SENSE_10            ] = "MODE_SENSE_10",
+        [ PERSISTENT_RESERVE_IN    ] = "PERSISTENT_RESERVE_IN",
+        [ PERSISTENT_RESERVE_OUT   ] = "PERSISTENT_RESERVE_OUT",
+        [ WRITE_FILEMARKS_16       ] = "WRITE_FILEMARKS_16",
+        [ EXTENDED_COPY            ] = "EXTENDED_COPY",
+        [ ATA_PASSTHROUGH_16       ] = "ATA_PASSTHROUGH_16",
+        [ ACCESS_CONTROL_IN        ] = "ACCESS_CONTROL_IN",
+        [ ACCESS_CONTROL_OUT       ] = "ACCESS_CONTROL_OUT",
+        [ READ_16                  ] = "READ_16",
+        [ COMPARE_AND_WRITE        ] = "COMPARE_AND_WRITE",
+        [ WRITE_16                 ] = "WRITE_16",
+        [ WRITE_VERIFY_16          ] = "WRITE_VERIFY_16",
+        [ VERIFY_16                ] = "VERIFY_16",
+        [ PRE_FETCH_16             ] = "PRE_FETCH_16",
+        [ SYNCHRONIZE_CACHE_16     ] = "SPACE_16/SYNCHRONIZE_CACHE_16",
+        /* SPACE_16 and SYNCHRONIZE_CACHE_16 use the same operation code */
+        [ LOCATE_16                ] = "LOCATE_16",
+        [ WRITE_SAME_16            ] = "ERASE_16/WRITE_SAME_16",
+        /* ERASE_16 and WRITE_SAME_16 use the same operation code */
+        [ SERVICE_ACTION_IN_16     ] = "SERVICE_ACTION_IN_16",
+        [ WRITE_LONG_16            ] = "WRITE_LONG_16",
+        [ REPORT_LUNS              ] = "REPORT_LUNS",
+        [ ATA_PASSTHROUGH_12       ] = "BLANK/ATA_PASSTHROUGH_12",
+        [ MOVE_MEDIUM              ] = "MOVE_MEDIUM",
+        [ EXCHANGE_MEDIUM          ] = "EXCHANGE MEDIUM",
+        [ READ_12                  ] = "READ_12",
+        [ WRITE_12                 ] = "WRITE_12",
+        [ ERASE_12                 ] = "ERASE_12/GET_PERFORMANCE",
+        /* ERASE_12 and GET_PERFORMANCE use the same operation code */
+        [ SERVICE_ACTION_IN_12     ] = "SERVICE_ACTION_IN_12",
+        [ WRITE_VERIFY_12          ] = "WRITE_VERIFY_12",
+        [ VERIFY_12                ] = "VERIFY_12",
+        [ SEARCH_HIGH_12           ] = "SEARCH_HIGH_12",
+        [ SEARCH_EQUAL_12          ] = "SEARCH_EQUAL_12",
+        [ SEARCH_LOW_12            ] = "SEARCH_LOW_12",
+        [ READ_ELEMENT_STATUS      ] = "READ_ELEMENT_STATUS",
+        [ SEND_VOLUME_TAG          ] = "SEND_VOLUME_TAG/SET_STREAMING",
+        /* SEND_VOLUME_TAG and SET_STREAMING use the same operation code */
+        [ READ_CD                  ] = "READ_CD",
+        [ READ_DEFECT_DATA_12      ] = "READ_DEFECT_DATA_12",
+        [ READ_DVD_STRUCTURE       ] = "READ_DVD_STRUCTURE",
+        [ RESERVE_TRACK            ] = "RESERVE_TRACK",
+        [ SEND_CUE_SHEET           ] = "SEND_CUE_SHEET",
+        [ SEND_DVD_STRUCTURE       ] = "SEND_DVD_STRUCTURE",
+        [ SET_CD_SPEED             ] = "SET_CD_SPEED",
+        [ SET_READ_AHEAD           ] = "SET_READ_AHEAD",
+        [ ALLOW_OVERWRITE          ] = "ALLOW_OVERWRITE",
+        [ MECHANISM_STATUS         ] = "MECHANISM_STATUS",
+    };
+
+    if (cmd >= ARRAY_SIZE(names) || names[cmd] == NULL)
+        return "*UNKNOWN*";
+    return names[cmd];
+}
+
+SCSIRequest *scsi_req_ref(SCSIRequest *req)
+{
+    assert(req->refcount > 0);
+    req->refcount++;
+    return req;
+}
+
+void scsi_req_unref(SCSIRequest *req)
+{
+    assert(req->refcount > 0);
+    if (--req->refcount == 0) {
+        SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, req->dev->qdev.parent_bus);
+        if (bus->info->free_request && req->hba_private) {
+            bus->info->free_request(bus, req->hba_private);
+        }
+        if (req->ops->free_req) {
+            req->ops->free_req(req);
+        }
+        g_free(req);
+    }
+}
+
+/* Tell the device that we finished processing this chunk of I/O.  It
+   will start the next chunk or complete the command.  */
+void scsi_req_continue(SCSIRequest *req)
+{
+    if (req->io_canceled) {
+        trace_scsi_req_continue_canceled(req->dev->id, req->lun, req->tag);
+        return;
+    }
+    trace_scsi_req_continue(req->dev->id, req->lun, req->tag);
+    if (req->cmd.mode == SCSI_XFER_TO_DEV) {
+        req->ops->write_data(req);
+    } else {
+        req->ops->read_data(req);
+    }
+}
+
+/* Called by the devices when data is ready for the HBA.  The HBA should
+   start a DMA operation to read or fill the device's data buffer.
+   Once it completes, calling scsi_req_continue will restart I/O.  */
+void scsi_req_data(SCSIRequest *req, int len)
+{
+    uint8_t *buf;
+    if (req->io_canceled) {
+        trace_scsi_req_data_canceled(req->dev->id, req->lun, req->tag, len);
+        return;
+    }
+    trace_scsi_req_data(req->dev->id, req->lun, req->tag, len);
+    assert(req->cmd.mode != SCSI_XFER_NONE);
+    if (!req->sg) {
+        req->resid -= len;
+        req->bus->info->transfer_data(req, len);
+        return;
+    }
+
+    /* If the device calls scsi_req_data and the HBA specified a
+     * scatter/gather list, the transfer has to happen in a single
+     * step.  */
+    assert(!req->dma_started);
+    req->dma_started = true;
+
+    buf = scsi_req_get_buf(req);
+    if (req->cmd.mode == SCSI_XFER_FROM_DEV) {
+        req->resid = dma_buf_read(buf, len, req->sg);
+    } else {
+        req->resid = dma_buf_write(buf, len, req->sg);
+    }
+    scsi_req_continue(req);
+}
+
+void scsi_req_print(SCSIRequest *req)
+{
+    FILE *fp = stderr;
+    int i;
+
+    fprintf(fp, "[%s id=%d] %s",
+            req->dev->qdev.parent_bus->name,
+            req->dev->id,
+            scsi_command_name(req->cmd.buf[0]));
+    for (i = 1; i < req->cmd.len; i++) {
+        fprintf(fp, " 0x%02x", req->cmd.buf[i]);
+    }
+    switch (req->cmd.mode) {
+    case SCSI_XFER_NONE:
+        fprintf(fp, " - none\n");
+        break;
+    case SCSI_XFER_FROM_DEV:
+        fprintf(fp, " - from-dev len=%zd\n", req->cmd.xfer);
+        break;
+    case SCSI_XFER_TO_DEV:
+        fprintf(fp, " - to-dev len=%zd\n", req->cmd.xfer);
+        break;
+    default:
+        fprintf(fp, " - Oops\n");
+        break;
+    }
+}
+
+void scsi_req_complete(SCSIRequest *req, int status)
+{
+    assert(req->status == -1);
+    req->status = status;
+
+    assert(req->sense_len <= sizeof(req->sense));
+    if (status == GOOD) {
+        req->sense_len = 0;
+    }
+
+    if (req->sense_len) {
+        memcpy(req->dev->sense, req->sense, req->sense_len);
+        req->dev->sense_len = req->sense_len;
+        req->dev->sense_is_ua = (req->ops == &reqops_unit_attention);
+    } else {
+        req->dev->sense_len = 0;
+        req->dev->sense_is_ua = false;
+    }
+
+    /*
+     * Unit attention state is now stored in the device's sense buffer
+     * if the HBA didn't do autosense.  Clear the pending unit attention
+     * flags.
+     */
+    scsi_clear_unit_attention(req);
+
+    scsi_req_ref(req);
+    scsi_req_dequeue(req);
+    req->bus->info->complete(req, req->status, req->resid);
+    scsi_req_unref(req);
+}
+
+void scsi_req_cancel(SCSIRequest *req)
+{
+    trace_scsi_req_cancel(req->dev->id, req->lun, req->tag);
+    if (!req->enqueued) {
+        return;
+    }
+    scsi_req_ref(req);
+    scsi_req_dequeue(req);
+    req->io_canceled = true;
+    if (req->ops->cancel_io) {
+        req->ops->cancel_io(req);
+    }
+    if (req->bus->info->cancel) {
+        req->bus->info->cancel(req);
+    }
+    scsi_req_unref(req);
+}
+
+void scsi_req_abort(SCSIRequest *req, int status)
+{
+    if (!req->enqueued) {
+        return;
+    }
+    scsi_req_ref(req);
+    scsi_req_dequeue(req);
+    req->io_canceled = true;
+    if (req->ops->cancel_io) {
+        req->ops->cancel_io(req);
+    }
+    scsi_req_complete(req, status);
+    scsi_req_unref(req);
+}
+
+static int scsi_ua_precedence(SCSISense sense)
+{
+    if (sense.key != UNIT_ATTENTION) {
+        return INT_MAX;
+    }
+    if (sense.asc == 0x29 && sense.ascq == 0x04) {
+        /* DEVICE INTERNAL RESET goes with POWER ON OCCURRED */
+        return 1;
+    } else if (sense.asc == 0x3F && sense.ascq == 0x01) {
+        /* MICROCODE HAS BEEN CHANGED goes with SCSI BUS RESET OCCURRED */
+        return 2;
+    } else if (sense.asc == 0x29 && (sense.ascq == 0x05 || sense.ascq == 0x06)) {
+        /* These two go with "all others". */
+        ;
+    } else if (sense.asc == 0x29 && sense.ascq <= 0x07) {
+        /* POWER ON, RESET OR BUS DEVICE RESET OCCURRED = 0
+         * POWER ON OCCURRED = 1
+         * SCSI BUS RESET OCCURRED = 2
+         * BUS DEVICE RESET FUNCTION OCCURRED = 3
+         * I_T NEXUS LOSS OCCURRED = 7
+         */
+        return sense.ascq;
+    } else if (sense.asc == 0x2F && sense.ascq == 0x01) {
+        /* COMMANDS CLEARED BY POWER LOSS NOTIFICATION  */
+        return 8;
+    }
+    return (sense.asc << 8) | sense.ascq;
+}
+
+void scsi_device_set_ua(SCSIDevice *sdev, SCSISense sense)
+{
+    int prec1, prec2;
+    if (sense.key != UNIT_ATTENTION) {
+        return;
+    }
+    trace_scsi_device_set_ua(sdev->id, sdev->lun, sense.key,
+                             sense.asc, sense.ascq);
+
+    /*
+     * Override a pre-existing unit attention condition, except for a more
+     * important reset condition.
+    */
+    prec1 = scsi_ua_precedence(sdev->unit_attention);
+    prec2 = scsi_ua_precedence(sense);
+    if (prec2 < prec1) {
+        sdev->unit_attention = sense;
+    }
+}
+
+void scsi_device_purge_requests(SCSIDevice *sdev, SCSISense sense)
+{
+    SCSIRequest *req;
+
+    while (!QTAILQ_EMPTY(&sdev->requests)) {
+        req = QTAILQ_FIRST(&sdev->requests);
+        scsi_req_cancel(req);
+    }
+
+    scsi_device_set_ua(sdev, sense);
+}
+
+static char *scsibus_get_dev_path(DeviceState *dev)
+{
+    SCSIDevice *d = DO_UPCAST(SCSIDevice, qdev, dev);
+    DeviceState *hba = dev->parent_bus->parent;
+    char *id;
+    char *path;
+
+    id = qdev_get_dev_path(hba);
+    if (id) {
+        path = g_strdup_printf("%s/%d:%d:%d", id, d->channel, d->id, d->lun);
+    } else {
+        path = g_strdup_printf("%d:%d:%d", d->channel, d->id, d->lun);
+    }
+    g_free(id);
+    return path;
+}
+
+static char *scsibus_get_fw_dev_path(DeviceState *dev)
+{
+    SCSIDevice *d = SCSI_DEVICE(dev);
+    return g_strdup_printf("channel@%x/%s@%x,%x", d->channel,
+                           qdev_fw_name(dev), d->id, d->lun);
+}
+
+SCSIDevice *scsi_device_find(SCSIBus *bus, int channel, int id, int lun)
+{
+    BusChild *kid;
+    SCSIDevice *target_dev = NULL;
+
+    QTAILQ_FOREACH_REVERSE(kid, &bus->qbus.children, ChildrenHead, sibling) {
+        DeviceState *qdev = kid->child;
+        SCSIDevice *dev = SCSI_DEVICE(qdev);
+
+        if (dev->channel == channel && dev->id == id) {
+            if (dev->lun == lun) {
+                return dev;
+            }
+            target_dev = dev;
+        }
+    }
+    return target_dev;
+}
+
+/* SCSI request list.  For simplicity, pv points to the whole device */
+
+static void put_scsi_requests(QEMUFile *f, void *pv, size_t size)
+{
+    SCSIDevice *s = pv;
+    SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, s->qdev.parent_bus);
+    SCSIRequest *req;
+
+    QTAILQ_FOREACH(req, &s->requests, next) {
+        assert(!req->io_canceled);
+        assert(req->status == -1);
+        assert(req->enqueued);
+
+        qemu_put_sbyte(f, req->retry ? 1 : 2);
+        qemu_put_buffer(f, req->cmd.buf, sizeof(req->cmd.buf));
+        qemu_put_be32s(f, &req->tag);
+        qemu_put_be32s(f, &req->lun);
+        if (bus->info->save_request) {
+            bus->info->save_request(f, req);
+        }
+        if (req->ops->save_request) {
+            req->ops->save_request(f, req);
+        }
+    }
+    qemu_put_sbyte(f, 0);
+}
+
+static int get_scsi_requests(QEMUFile *f, void *pv, size_t size)
+{
+    SCSIDevice *s = pv;
+    SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, s->qdev.parent_bus);
+    int8_t sbyte;
+
+    while ((sbyte = qemu_get_sbyte(f)) > 0) {
+        uint8_t buf[SCSI_CMD_BUF_SIZE];
+        uint32_t tag;
+        uint32_t lun;
+        SCSIRequest *req;
+
+        qemu_get_buffer(f, buf, sizeof(buf));
+        qemu_get_be32s(f, &tag);
+        qemu_get_be32s(f, &lun);
+        req = scsi_req_new(s, tag, lun, buf, NULL);
+        req->retry = (sbyte == 1);
+        if (bus->info->load_request) {
+            req->hba_private = bus->info->load_request(f, req);
+        }
+        if (req->ops->load_request) {
+            req->ops->load_request(f, req);
+        }
+
+        /* Just restart it later.  */
+        scsi_req_enqueue_internal(req);
+
+        /* At this point, the request will be kept alive by the reference
+         * added by scsi_req_enqueue_internal, so we can release our reference.
+         * The HBA of course will add its own reference in the load_request
+         * callback if it needs to hold on the SCSIRequest.
+         */
+        scsi_req_unref(req);
+    }
+
+    return 0;
+}
+
+static int scsi_qdev_unplug(DeviceState *qdev)
+{
+    SCSIDevice *dev = SCSI_DEVICE(qdev);
+    SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, dev->qdev.parent_bus);
+
+    if (bus->info->hot_unplug) {
+        bus->info->hot_unplug(bus, dev);
+    }
+    return qdev_simple_unplug_cb(qdev);
+}
+
+static const VMStateInfo vmstate_info_scsi_requests = {
+    .name = "scsi-requests",
+    .get  = get_scsi_requests,
+    .put  = put_scsi_requests,
+};
+
+const VMStateDescription vmstate_scsi_device = {
+    .name = "SCSIDevice",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT8(unit_attention.key, SCSIDevice),
+        VMSTATE_UINT8(unit_attention.asc, SCSIDevice),
+        VMSTATE_UINT8(unit_attention.ascq, SCSIDevice),
+        VMSTATE_BOOL(sense_is_ua, SCSIDevice),
+        VMSTATE_UINT8_ARRAY(sense, SCSIDevice, SCSI_SENSE_BUF_SIZE),
+        VMSTATE_UINT32(sense_len, SCSIDevice),
+        {
+            .name         = "requests",
+            .version_id   = 0,
+            .field_exists = NULL,
+            .size         = 0,   /* ouch */
+            .info         = &vmstate_info_scsi_requests,
+            .flags        = VMS_SINGLE,
+            .offset       = 0,
+        },
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void scsi_device_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *k = DEVICE_CLASS(klass);
+    k->bus_type = TYPE_SCSI_BUS;
+    k->init     = scsi_qdev_init;
+    k->unplug   = scsi_qdev_unplug;
+    k->exit     = scsi_qdev_exit;
+    k->props    = scsi_props;
+}
+
+static const 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_types(void)
+{
+    type_register_static(&scsi_bus_info);
+    type_register_static(&scsi_device_type_info);
+}
+
+type_init(scsi_register_types)
diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c
new file mode 100644 (file)
index 0000000..f52bd11
--- /dev/null
@@ -0,0 +1,2526 @@
+/*
+ * SCSI Device emulation
+ *
+ * Copyright (c) 2006 CodeSourcery.
+ * Based on code by Fabrice Bellard
+ *
+ * Written by Paul Brook
+ * Modifications:
+ *  2009-Dec-12 Artyom Tarasenko : implemented stamdard inquiry for the case
+ *                                 when the allocation length of CDB is smaller
+ *                                 than 36.
+ *  2009-Oct-13 Artyom Tarasenko : implemented the block descriptor in the
+ *                                 MODE SENSE response.
+ *
+ * This code is licensed under the LGPL.
+ *
+ * Note that this file only handles the SCSI architecture model and device
+ * commands.  Emulation of interface/link layer protocols is handled by
+ * the host adapter emulator.
+ */
+
+//#define DEBUG_SCSI
+
+#ifdef DEBUG_SCSI
+#define DPRINTF(fmt, ...) \
+do { printf("scsi-disk: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while(0)
+#endif
+
+#include "qemu-common.h"
+#include "qemu/error-report.h"
+#include "hw/scsi/scsi.h"
+#include "block/scsi.h"
+#include "sysemu/sysemu.h"
+#include "sysemu/blockdev.h"
+#include "hw/block/block.h"
+#include "sysemu/dma.h"
+
+#ifdef __linux
+#include <scsi/sg.h>
+#endif
+
+#define SCSI_DMA_BUF_SIZE           131072
+#define SCSI_MAX_INQUIRY_LEN        256
+#define SCSI_MAX_MODE_LEN           256
+
+#define DEFAULT_DISCARD_GRANULARITY 4096
+
+typedef struct SCSIDiskState SCSIDiskState;
+
+typedef struct SCSIDiskReq {
+    SCSIRequest req;
+    /* Both sector and sector_count are in terms of qemu 512 byte blocks.  */
+    uint64_t sector;
+    uint32_t sector_count;
+    uint32_t buflen;
+    bool started;
+    struct iovec iov;
+    QEMUIOVector qiov;
+    BlockAcctCookie acct;
+} SCSIDiskReq;
+
+#define SCSI_DISK_F_REMOVABLE   0
+#define SCSI_DISK_F_DPOFUA      1
+
+struct SCSIDiskState
+{
+    SCSIDevice qdev;
+    uint32_t features;
+    bool media_changed;
+    bool media_event;
+    bool eject_request;
+    uint64_t wwn;
+    QEMUBH *bh;
+    char *version;
+    char *serial;
+    char *vendor;
+    char *product;
+    bool tray_open;
+    bool tray_locked;
+};
+
+static int scsi_handle_rw_error(SCSIDiskReq *r, int error);
+
+static void scsi_free_request(SCSIRequest *req)
+{
+    SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
+
+    qemu_vfree(r->iov.iov_base);
+}
+
+/* Helper function for command completion with sense.  */
+static void scsi_check_condition(SCSIDiskReq *r, SCSISense sense)
+{
+    DPRINTF("Command complete tag=0x%x sense=%d/%d/%d\n",
+            r->req.tag, sense.key, sense.asc, sense.ascq);
+    scsi_req_build_sense(&r->req, sense);
+    scsi_req_complete(&r->req, CHECK_CONDITION);
+}
+
+/* Cancel a pending data transfer.  */
+static void scsi_cancel_io(SCSIRequest *req)
+{
+    SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
+
+    DPRINTF("Cancel tag=0x%x\n", req->tag);
+    if (r->req.aiocb) {
+        bdrv_aio_cancel(r->req.aiocb);
+
+        /* This reference was left in by scsi_*_data.  We take ownership of
+         * it the moment scsi_req_cancel is called, independent of whether
+         * bdrv_aio_cancel completes the request or not.  */
+        scsi_req_unref(&r->req);
+    }
+    r->req.aiocb = NULL;
+}
+
+static uint32_t scsi_init_iovec(SCSIDiskReq *r, size_t size)
+{
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
+
+    if (!r->iov.iov_base) {
+        r->buflen = size;
+        r->iov.iov_base = qemu_blockalign(s->qdev.conf.bs, r->buflen);
+    }
+    r->iov.iov_len = MIN(r->sector_count * 512, r->buflen);
+    qemu_iovec_init_external(&r->qiov, &r->iov, 1);
+    return r->qiov.size / 512;
+}
+
+static void scsi_disk_save_request(QEMUFile *f, SCSIRequest *req)
+{
+    SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
+
+    qemu_put_be64s(f, &r->sector);
+    qemu_put_be32s(f, &r->sector_count);
+    qemu_put_be32s(f, &r->buflen);
+    if (r->buflen) {
+        if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
+            qemu_put_buffer(f, r->iov.iov_base, r->iov.iov_len);
+        } else if (!req->retry) {
+            uint32_t len = r->iov.iov_len;
+            qemu_put_be32s(f, &len);
+            qemu_put_buffer(f, r->iov.iov_base, r->iov.iov_len);
+        }
+    }
+}
+
+static void scsi_disk_load_request(QEMUFile *f, SCSIRequest *req)
+{
+    SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
+
+    qemu_get_be64s(f, &r->sector);
+    qemu_get_be32s(f, &r->sector_count);
+    qemu_get_be32s(f, &r->buflen);
+    if (r->buflen) {
+        scsi_init_iovec(r, r->buflen);
+        if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
+            qemu_get_buffer(f, r->iov.iov_base, r->iov.iov_len);
+        } else if (!r->req.retry) {
+            uint32_t len;
+            qemu_get_be32s(f, &len);
+            r->iov.iov_len = len;
+            assert(r->iov.iov_len <= r->buflen);
+            qemu_get_buffer(f, r->iov.iov_base, r->iov.iov_len);
+        }
+    }
+
+    qemu_iovec_init_external(&r->qiov, &r->iov, 1);
+}
+
+static void scsi_aio_complete(void *opaque, int ret)
+{
+    SCSIDiskReq *r = (SCSIDiskReq *)opaque;
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
+
+    assert(r->req.aiocb != NULL);
+    r->req.aiocb = NULL;
+    bdrv_acct_done(s->qdev.conf.bs, &r->acct);
+    if (r->req.io_canceled) {
+        goto done;
+    }
+
+    if (ret < 0) {
+        if (scsi_handle_rw_error(r, -ret)) {
+            goto done;
+        }
+    }
+
+    scsi_req_complete(&r->req, GOOD);
+
+done:
+    if (!r->req.io_canceled) {
+        scsi_req_unref(&r->req);
+    }
+}
+
+static bool scsi_is_cmd_fua(SCSICommand *cmd)
+{
+    switch (cmd->buf[0]) {
+    case READ_10:
+    case READ_12:
+    case READ_16:
+    case WRITE_10:
+    case WRITE_12:
+    case WRITE_16:
+        return (cmd->buf[1] & 8) != 0;
+
+    case VERIFY_10:
+    case VERIFY_12:
+    case VERIFY_16:
+    case WRITE_VERIFY_10:
+    case WRITE_VERIFY_12:
+    case WRITE_VERIFY_16:
+        return true;
+
+    case READ_6:
+    case WRITE_6:
+    default:
+        return false;
+    }
+}
+
+static void scsi_write_do_fua(SCSIDiskReq *r)
+{
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
+
+    if (r->req.io_canceled) {
+        goto done;
+    }
+
+    if (scsi_is_cmd_fua(&r->req.cmd)) {
+        bdrv_acct_start(s->qdev.conf.bs, &r->acct, 0, BDRV_ACCT_FLUSH);
+        r->req.aiocb = bdrv_aio_flush(s->qdev.conf.bs, scsi_aio_complete, r);
+        return;
+    }
+
+    scsi_req_complete(&r->req, GOOD);
+
+done:
+    if (!r->req.io_canceled) {
+        scsi_req_unref(&r->req);
+    }
+}
+
+static void scsi_dma_complete(void *opaque, int ret)
+{
+    SCSIDiskReq *r = (SCSIDiskReq *)opaque;
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
+
+    assert(r->req.aiocb != NULL);
+    r->req.aiocb = NULL;
+    bdrv_acct_done(s->qdev.conf.bs, &r->acct);
+    if (r->req.io_canceled) {
+        goto done;
+    }
+
+    if (ret < 0) {
+        if (scsi_handle_rw_error(r, -ret)) {
+            goto done;
+        }
+    }
+
+    r->sector += r->sector_count;
+    r->sector_count = 0;
+    if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
+        scsi_write_do_fua(r);
+        return;
+    } else {
+        scsi_req_complete(&r->req, GOOD);
+    }
+
+done:
+    if (!r->req.io_canceled) {
+        scsi_req_unref(&r->req);
+    }
+}
+
+static void scsi_read_complete(void * opaque, int ret)
+{
+    SCSIDiskReq *r = (SCSIDiskReq *)opaque;
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
+    int n;
+
+    assert(r->req.aiocb != NULL);
+    r->req.aiocb = NULL;
+    bdrv_acct_done(s->qdev.conf.bs, &r->acct);
+    if (r->req.io_canceled) {
+        goto done;
+    }
+
+    if (ret < 0) {
+        if (scsi_handle_rw_error(r, -ret)) {
+            goto done;
+        }
+    }
+
+    DPRINTF("Data ready tag=0x%x len=%zd\n", r->req.tag, r->qiov.size);
+
+    n = r->qiov.size / 512;
+    r->sector += n;
+    r->sector_count -= n;
+    scsi_req_data(&r->req, r->qiov.size);
+
+done:
+    if (!r->req.io_canceled) {
+        scsi_req_unref(&r->req);
+    }
+}
+
+/* Actually issue a read to the block device.  */
+static void scsi_do_read(void *opaque, int ret)
+{
+    SCSIDiskReq *r = opaque;
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
+    uint32_t n;
+
+    if (r->req.aiocb != NULL) {
+        r->req.aiocb = NULL;
+        bdrv_acct_done(s->qdev.conf.bs, &r->acct);
+    }
+    if (r->req.io_canceled) {
+        goto done;
+    }
+
+    if (ret < 0) {
+        if (scsi_handle_rw_error(r, -ret)) {
+            goto done;
+        }
+    }
+
+    /* The request is used as the AIO opaque value, so add a ref.  */
+    scsi_req_ref(&r->req);
+
+    if (r->req.sg) {
+        dma_acct_start(s->qdev.conf.bs, &r->acct, r->req.sg, BDRV_ACCT_READ);
+        r->req.resid -= r->req.sg->size;
+        r->req.aiocb = dma_bdrv_read(s->qdev.conf.bs, r->req.sg, r->sector,
+                                     scsi_dma_complete, r);
+    } else {
+        n = scsi_init_iovec(r, SCSI_DMA_BUF_SIZE);
+        bdrv_acct_start(s->qdev.conf.bs, &r->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_READ);
+        r->req.aiocb = bdrv_aio_readv(s->qdev.conf.bs, r->sector, &r->qiov, n,
+                                      scsi_read_complete, r);
+    }
+
+done:
+    if (!r->req.io_canceled) {
+        scsi_req_unref(&r->req);
+    }
+}
+
+/* Read more data from scsi device into buffer.  */
+static void scsi_read_data(SCSIRequest *req)
+{
+    SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
+    bool first;
+
+    DPRINTF("Read sector_count=%d\n", r->sector_count);
+    if (r->sector_count == 0) {
+        /* This also clears the sense buffer for REQUEST SENSE.  */
+        scsi_req_complete(&r->req, GOOD);
+        return;
+    }
+
+    /* No data transfer may already be in progress */
+    assert(r->req.aiocb == NULL);
+
+    /* The request is used as the AIO opaque value, so add a ref.  */
+    scsi_req_ref(&r->req);
+    if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
+        DPRINTF("Data transfer direction invalid\n");
+        scsi_read_complete(r, -EINVAL);
+        return;
+    }
+
+    if (s->tray_open) {
+        scsi_read_complete(r, -ENOMEDIUM);
+        return;
+    }
+
+    first = !r->started;
+    r->started = true;
+    if (first && scsi_is_cmd_fua(&r->req.cmd)) {
+        bdrv_acct_start(s->qdev.conf.bs, &r->acct, 0, BDRV_ACCT_FLUSH);
+        r->req.aiocb = bdrv_aio_flush(s->qdev.conf.bs, scsi_do_read, r);
+    } else {
+        scsi_do_read(r, 0);
+    }
+}
+
+/*
+ * scsi_handle_rw_error has two return values.  0 means that the error
+ * must be ignored, 1 means that the error has been processed and the
+ * caller should not do anything else for this request.  Note that
+ * scsi_handle_rw_error always manages its reference counts, independent
+ * of the return value.
+ */
+static int scsi_handle_rw_error(SCSIDiskReq *r, int error)
+{
+    bool is_read = (r->req.cmd.xfer == SCSI_XFER_FROM_DEV);
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
+    BlockErrorAction action = bdrv_get_error_action(s->qdev.conf.bs, is_read, error);
+
+    if (action == BDRV_ACTION_REPORT) {
+        switch (error) {
+        case ENOMEDIUM:
+            scsi_check_condition(r, SENSE_CODE(NO_MEDIUM));
+            break;
+        case ENOMEM:
+            scsi_check_condition(r, SENSE_CODE(TARGET_FAILURE));
+            break;
+        case EINVAL:
+            scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
+            break;
+        default:
+            scsi_check_condition(r, SENSE_CODE(IO_ERROR));
+            break;
+        }
+    }
+    bdrv_error_action(s->qdev.conf.bs, action, is_read, error);
+    if (action == BDRV_ACTION_STOP) {
+        scsi_req_retry(&r->req);
+    }
+    return action != BDRV_ACTION_IGNORE;
+}
+
+static void scsi_write_complete(void * opaque, int ret)
+{
+    SCSIDiskReq *r = (SCSIDiskReq *)opaque;
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
+    uint32_t n;
+
+    if (r->req.aiocb != NULL) {
+        r->req.aiocb = NULL;
+        bdrv_acct_done(s->qdev.conf.bs, &r->acct);
+    }
+    if (r->req.io_canceled) {
+        goto done;
+    }
+
+    if (ret < 0) {
+        if (scsi_handle_rw_error(r, -ret)) {
+            goto done;
+        }
+    }
+
+    n = r->qiov.size / 512;
+    r->sector += n;
+    r->sector_count -= n;
+    if (r->sector_count == 0) {
+        scsi_write_do_fua(r);
+        return;
+    } else {
+        scsi_init_iovec(r, SCSI_DMA_BUF_SIZE);
+        DPRINTF("Write complete tag=0x%x more=%zd\n", r->req.tag, r->qiov.size);
+        scsi_req_data(&r->req, r->qiov.size);
+    }
+
+done:
+    if (!r->req.io_canceled) {
+        scsi_req_unref(&r->req);
+    }
+}
+
+static void scsi_write_data(SCSIRequest *req)
+{
+    SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
+    uint32_t n;
+
+    /* No data transfer may already be in progress */
+    assert(r->req.aiocb == NULL);
+
+    /* The request is used as the AIO opaque value, so add a ref.  */
+    scsi_req_ref(&r->req);
+    if (r->req.cmd.mode != SCSI_XFER_TO_DEV) {
+        DPRINTF("Data transfer direction invalid\n");
+        scsi_write_complete(r, -EINVAL);
+        return;
+    }
+
+    if (!r->req.sg && !r->qiov.size) {
+        /* Called for the first time.  Ask the driver to send us more data.  */
+        r->started = true;
+        scsi_write_complete(r, 0);
+        return;
+    }
+    if (s->tray_open) {
+        scsi_write_complete(r, -ENOMEDIUM);
+        return;
+    }
+
+    if (r->req.cmd.buf[0] == VERIFY_10 || r->req.cmd.buf[0] == VERIFY_12 ||
+        r->req.cmd.buf[0] == VERIFY_16) {
+        if (r->req.sg) {
+            scsi_dma_complete(r, 0);
+        } else {
+            scsi_write_complete(r, 0);
+        }
+        return;
+    }
+
+    if (r->req.sg) {
+        dma_acct_start(s->qdev.conf.bs, &r->acct, r->req.sg, BDRV_ACCT_WRITE);
+        r->req.resid -= r->req.sg->size;
+        r->req.aiocb = dma_bdrv_write(s->qdev.conf.bs, r->req.sg, r->sector,
+                                      scsi_dma_complete, r);
+    } else {
+        n = r->qiov.size / 512;
+        bdrv_acct_start(s->qdev.conf.bs, &r->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_WRITE);
+        r->req.aiocb = bdrv_aio_writev(s->qdev.conf.bs, r->sector, &r->qiov, n,
+                                       scsi_write_complete, r);
+    }
+}
+
+/* Return a pointer to the data buffer.  */
+static uint8_t *scsi_get_buf(SCSIRequest *req)
+{
+    SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
+
+    return (uint8_t *)r->iov.iov_base;
+}
+
+static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
+{
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
+    int buflen = 0;
+    int start;
+
+    if (req->cmd.buf[1] & 0x1) {
+        /* Vital product data */
+        uint8_t page_code = req->cmd.buf[2];
+
+        outbuf[buflen++] = s->qdev.type & 0x1f;
+        outbuf[buflen++] = page_code ; // this page
+        outbuf[buflen++] = 0x00;
+        outbuf[buflen++] = 0x00;
+        start = buflen;
+
+        switch (page_code) {
+        case 0x00: /* Supported page codes, mandatory */
+        {
+            DPRINTF("Inquiry EVPD[Supported pages] "
+                    "buffer size %zd\n", req->cmd.xfer);
+            outbuf[buflen++] = 0x00; // list of supported pages (this page)
+            if (s->serial) {
+                outbuf[buflen++] = 0x80; // unit serial number
+            }
+            outbuf[buflen++] = 0x83; // device identification
+            if (s->qdev.type == TYPE_DISK) {
+                outbuf[buflen++] = 0xb0; // block limits
+                outbuf[buflen++] = 0xb2; // thin provisioning
+            }
+            break;
+        }
+        case 0x80: /* Device serial number, optional */
+        {
+            int l;
+
+            if (!s->serial) {
+                DPRINTF("Inquiry (EVPD[Serial number] not supported\n");
+                return -1;
+            }
+
+            l = strlen(s->serial);
+            if (l > 20) {
+                l = 20;
+            }
+
+            DPRINTF("Inquiry EVPD[Serial number] "
+                    "buffer size %zd\n", req->cmd.xfer);
+            memcpy(outbuf+buflen, s->serial, l);
+            buflen += l;
+            break;
+        }
+
+        case 0x83: /* Device identification page, mandatory */
+        {
+            const char *str = s->serial ?: bdrv_get_device_name(s->qdev.conf.bs);
+            int max_len = s->serial ? 20 : 255 - 8;
+            int id_len = strlen(str);
+
+            if (id_len > max_len) {
+                id_len = max_len;
+            }
+            DPRINTF("Inquiry EVPD[Device identification] "
+                    "buffer size %zd\n", req->cmd.xfer);
+
+            outbuf[buflen++] = 0x2; // ASCII
+            outbuf[buflen++] = 0;   // not officially assigned
+            outbuf[buflen++] = 0;   // reserved
+            outbuf[buflen++] = id_len; // length of data following
+            memcpy(outbuf+buflen, str, id_len);
+            buflen += id_len;
+
+            if (s->wwn) {
+                outbuf[buflen++] = 0x1; // Binary
+                outbuf[buflen++] = 0x3; // NAA
+                outbuf[buflen++] = 0;   // reserved
+                outbuf[buflen++] = 8;
+                stq_be_p(&outbuf[buflen], s->wwn);
+                buflen += 8;
+            }
+            break;
+        }
+        case 0xb0: /* block limits */
+        {
+            unsigned int unmap_sectors =
+                    s->qdev.conf.discard_granularity / s->qdev.blocksize;
+            unsigned int min_io_size =
+                    s->qdev.conf.min_io_size / s->qdev.blocksize;
+            unsigned int opt_io_size =
+                    s->qdev.conf.opt_io_size / s->qdev.blocksize;
+
+            if (s->qdev.type == TYPE_ROM) {
+                DPRINTF("Inquiry (EVPD[%02X] not supported for CDROM\n",
+                        page_code);
+                return -1;
+            }
+            /* required VPD size with unmap support */
+            buflen = 0x40;
+            memset(outbuf + 4, 0, buflen - 4);
+
+            /* optimal transfer length granularity */
+            outbuf[6] = (min_io_size >> 8) & 0xff;
+            outbuf[7] = min_io_size & 0xff;
+
+            /* optimal transfer length */
+            outbuf[12] = (opt_io_size >> 24) & 0xff;
+            outbuf[13] = (opt_io_size >> 16) & 0xff;
+            outbuf[14] = (opt_io_size >> 8) & 0xff;
+            outbuf[15] = opt_io_size & 0xff;
+
+            /* optimal unmap granularity */
+            outbuf[28] = (unmap_sectors >> 24) & 0xff;
+            outbuf[29] = (unmap_sectors >> 16) & 0xff;
+            outbuf[30] = (unmap_sectors >> 8) & 0xff;
+            outbuf[31] = unmap_sectors & 0xff;
+            break;
+        }
+        case 0xb2: /* thin provisioning */
+        {
+            buflen = 8;
+            outbuf[4] = 0;
+            outbuf[5] = 0xe0; /* unmap & write_same 10/16 all supported */
+            outbuf[6] = s->qdev.conf.discard_granularity ? 2 : 1;
+            outbuf[7] = 0;
+            break;
+        }
+        default:
+            return -1;
+        }
+        /* done with EVPD */
+        assert(buflen - start <= 255);
+        outbuf[start - 1] = buflen - start;
+        return buflen;
+    }
+
+    /* Standard INQUIRY data */
+    if (req->cmd.buf[2] != 0) {
+        return -1;
+    }
+
+    /* PAGE CODE == 0 */
+    buflen = req->cmd.xfer;
+    if (buflen > SCSI_MAX_INQUIRY_LEN) {
+        buflen = SCSI_MAX_INQUIRY_LEN;
+    }
+
+    outbuf[0] = s->qdev.type & 0x1f;
+    outbuf[1] = (s->features & (1 << SCSI_DISK_F_REMOVABLE)) ? 0x80 : 0;
+
+    strpadcpy((char *) &outbuf[16], 16, s->product, ' ');
+    strpadcpy((char *) &outbuf[8], 8, s->vendor, ' ');
+
+    memset(&outbuf[32], 0, 4);
+    memcpy(&outbuf[32], s->version, MIN(4, strlen(s->version)));
+    /*
+     * We claim conformance to SPC-3, which is required for guests
+     * to ask for modern features like READ CAPACITY(16) or the
+     * block characteristics VPD page by default.  Not all of SPC-3
+     * is actually implemented, but we're good enough.
+     */
+    outbuf[2] = 5;
+    outbuf[3] = 2 | 0x10; /* Format 2, HiSup */
+
+    if (buflen > 36) {
+        outbuf[4] = buflen - 5; /* Additional Length = (Len - 1) - 4 */
+    } else {
+        /* If the allocation length of CDB is too small,
+               the additional length is not adjusted */
+        outbuf[4] = 36 - 5;
+    }
+
+    /* Sync data transfer and TCQ.  */
+    outbuf[7] = 0x10 | (req->bus->info->tcq ? 0x02 : 0);
+    return buflen;
+}
+
+static inline bool media_is_dvd(SCSIDiskState *s)
+{
+    uint64_t nb_sectors;
+    if (s->qdev.type != TYPE_ROM) {
+        return false;
+    }
+    if (!bdrv_is_inserted(s->qdev.conf.bs)) {
+        return false;
+    }
+    bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors);
+    return nb_sectors > CD_MAX_SECTORS;
+}
+
+static inline bool media_is_cd(SCSIDiskState *s)
+{
+    uint64_t nb_sectors;
+    if (s->qdev.type != TYPE_ROM) {
+        return false;
+    }
+    if (!bdrv_is_inserted(s->qdev.conf.bs)) {
+        return false;
+    }
+    bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors);
+    return nb_sectors <= CD_MAX_SECTORS;
+}
+
+static int scsi_read_disc_information(SCSIDiskState *s, SCSIDiskReq *r,
+                                      uint8_t *outbuf)
+{
+    uint8_t type = r->req.cmd.buf[1] & 7;
+
+    if (s->qdev.type != TYPE_ROM) {
+        return -1;
+    }
+
+    /* Types 1/2 are only defined for Blu-Ray.  */
+    if (type != 0) {
+        scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
+        return -1;
+    }
+
+    memset(outbuf, 0, 34);
+    outbuf[1] = 32;
+    outbuf[2] = 0xe; /* last session complete, disc finalized */
+    outbuf[3] = 1;   /* first track on disc */
+    outbuf[4] = 1;   /* # of sessions */
+    outbuf[5] = 1;   /* first track of last session */
+    outbuf[6] = 1;   /* last track of last session */
+    outbuf[7] = 0x20; /* unrestricted use */
+    outbuf[8] = 0x00; /* CD-ROM or DVD-ROM */
+    /* 9-10-11: most significant byte corresponding bytes 4-5-6 */
+    /* 12-23: not meaningful for CD-ROM or DVD-ROM */
+    /* 24-31: disc bar code */
+    /* 32: disc application code */
+    /* 33: number of OPC tables */
+
+    return 34;
+}
+
+static int scsi_read_dvd_structure(SCSIDiskState *s, SCSIDiskReq *r,
+                                   uint8_t *outbuf)
+{
+    static const int rds_caps_size[5] = {
+        [0] = 2048 + 4,
+        [1] = 4 + 4,
+        [3] = 188 + 4,
+        [4] = 2048 + 4,
+    };
+
+    uint8_t media = r->req.cmd.buf[1];
+    uint8_t layer = r->req.cmd.buf[6];
+    uint8_t format = r->req.cmd.buf[7];
+    int size = -1;
+
+    if (s->qdev.type != TYPE_ROM) {
+        return -1;
+    }
+    if (media != 0) {
+        scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
+        return -1;
+    }
+
+    if (format != 0xff) {
+        if (s->tray_open || !bdrv_is_inserted(s->qdev.conf.bs)) {
+            scsi_check_condition(r, SENSE_CODE(NO_MEDIUM));
+            return -1;
+        }
+        if (media_is_cd(s)) {
+            scsi_check_condition(r, SENSE_CODE(INCOMPATIBLE_FORMAT));
+            return -1;
+        }
+        if (format >= ARRAY_SIZE(rds_caps_size)) {
+            return -1;
+        }
+        size = rds_caps_size[format];
+        memset(outbuf, 0, size);
+    }
+
+    switch (format) {
+    case 0x00: {
+        /* Physical format information */
+        uint64_t nb_sectors;
+        if (layer != 0) {
+            goto fail;
+        }
+        bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors);
+
+        outbuf[4] = 1;   /* DVD-ROM, part version 1 */
+        outbuf[5] = 0xf; /* 120mm disc, minimum rate unspecified */
+        outbuf[6] = 1;   /* one layer, read-only (per MMC-2 spec) */
+        outbuf[7] = 0;   /* default densities */
+
+        stl_be_p(&outbuf[12], (nb_sectors >> 2) - 1); /* end sector */
+        stl_be_p(&outbuf[16], (nb_sectors >> 2) - 1); /* l0 end sector */
+        break;
+    }
+
+    case 0x01: /* DVD copyright information, all zeros */
+        break;
+
+    case 0x03: /* BCA information - invalid field for no BCA info */
+        return -1;
+
+    case 0x04: /* DVD disc manufacturing information, all zeros */
+        break;
+
+    case 0xff: { /* List capabilities */
+        int i;
+        size = 4;
+        for (i = 0; i < ARRAY_SIZE(rds_caps_size); i++) {
+            if (!rds_caps_size[i]) {
+                continue;
+            }
+            outbuf[size] = i;
+            outbuf[size + 1] = 0x40; /* Not writable, readable */
+            stw_be_p(&outbuf[size + 2], rds_caps_size[i]);
+            size += 4;
+        }
+        break;
+     }
+
+    default:
+        return -1;
+    }
+
+    /* Size of buffer, not including 2 byte size field */
+    stw_be_p(outbuf, size - 2);
+    return size;
+
+fail:
+    return -1;
+}
+
+static int scsi_event_status_media(SCSIDiskState *s, uint8_t *outbuf)
+{
+    uint8_t event_code, media_status;
+
+    media_status = 0;
+    if (s->tray_open) {
+        media_status = MS_TRAY_OPEN;
+    } else if (bdrv_is_inserted(s->qdev.conf.bs)) {
+        media_status = MS_MEDIA_PRESENT;
+    }
+
+    /* Event notification descriptor */
+    event_code = MEC_NO_CHANGE;
+    if (media_status != MS_TRAY_OPEN) {
+        if (s->media_event) {
+            event_code = MEC_NEW_MEDIA;
+            s->media_event = false;
+        } else if (s->eject_request) {
+            event_code = MEC_EJECT_REQUESTED;
+            s->eject_request = false;
+        }
+    }
+
+    outbuf[0] = event_code;
+    outbuf[1] = media_status;
+
+    /* These fields are reserved, just clear them. */
+    outbuf[2] = 0;
+    outbuf[3] = 0;
+    return 4;
+}
+
+static int scsi_get_event_status_notification(SCSIDiskState *s, SCSIDiskReq *r,
+                                              uint8_t *outbuf)
+{
+    int size;
+    uint8_t *buf = r->req.cmd.buf;
+    uint8_t notification_class_request = buf[4];
+    if (s->qdev.type != TYPE_ROM) {
+        return -1;
+    }
+    if ((buf[1] & 1) == 0) {
+        /* asynchronous */
+        return -1;
+    }
+
+    size = 4;
+    outbuf[0] = outbuf[1] = 0;
+    outbuf[3] = 1 << GESN_MEDIA; /* supported events */
+    if (notification_class_request & (1 << GESN_MEDIA)) {
+        outbuf[2] = GESN_MEDIA;
+        size += scsi_event_status_media(s, &outbuf[size]);
+    } else {
+        outbuf[2] = 0x80;
+    }
+    stw_be_p(outbuf, size - 4);
+    return size;
+}
+
+static int scsi_get_configuration(SCSIDiskState *s, uint8_t *outbuf)
+{
+    int current;
+
+    if (s->qdev.type != TYPE_ROM) {
+        return -1;
+    }
+    current = media_is_dvd(s) ? MMC_PROFILE_DVD_ROM : MMC_PROFILE_CD_ROM;
+    memset(outbuf, 0, 40);
+    stl_be_p(&outbuf[0], 36); /* Bytes after the data length field */
+    stw_be_p(&outbuf[6], current);
+    /* outbuf[8] - outbuf[19]: Feature 0 - Profile list */
+    outbuf[10] = 0x03; /* persistent, current */
+    outbuf[11] = 8; /* two profiles */
+    stw_be_p(&outbuf[12], MMC_PROFILE_DVD_ROM);
+    outbuf[14] = (current == MMC_PROFILE_DVD_ROM);
+    stw_be_p(&outbuf[16], MMC_PROFILE_CD_ROM);
+    outbuf[18] = (current == MMC_PROFILE_CD_ROM);
+    /* outbuf[20] - outbuf[31]: Feature 1 - Core feature */
+    stw_be_p(&outbuf[20], 1);
+    outbuf[22] = 0x08 | 0x03; /* version 2, persistent, current */
+    outbuf[23] = 8;
+    stl_be_p(&outbuf[24], 1); /* SCSI */
+    outbuf[28] = 1; /* DBE = 1, mandatory */
+    /* outbuf[32] - outbuf[39]: Feature 3 - Removable media feature */
+    stw_be_p(&outbuf[32], 3);
+    outbuf[34] = 0x08 | 0x03; /* version 2, persistent, current */
+    outbuf[35] = 4;
+    outbuf[36] = 0x39; /* tray, load=1, eject=1, unlocked at powerup, lock=1 */
+    /* TODO: Random readable, CD read, DVD read, drive serial number,
+       power management */
+    return 40;
+}
+
+static int scsi_emulate_mechanism_status(SCSIDiskState *s, uint8_t *outbuf)
+{
+    if (s->qdev.type != TYPE_ROM) {
+        return -1;
+    }
+    memset(outbuf, 0, 8);
+    outbuf[5] = 1; /* CD-ROM */
+    return 8;
+}
+
+static int mode_sense_page(SCSIDiskState *s, int page, uint8_t **p_outbuf,
+                           int page_control)
+{
+    static const int mode_sense_valid[0x3f] = {
+        [MODE_PAGE_HD_GEOMETRY]            = (1 << TYPE_DISK),
+        [MODE_PAGE_FLEXIBLE_DISK_GEOMETRY] = (1 << TYPE_DISK),
+        [MODE_PAGE_CACHING]                = (1 << TYPE_DISK) | (1 << TYPE_ROM),
+        [MODE_PAGE_R_W_ERROR]              = (1 << TYPE_DISK) | (1 << TYPE_ROM),
+        [MODE_PAGE_AUDIO_CTL]              = (1 << TYPE_ROM),
+        [MODE_PAGE_CAPABILITIES]           = (1 << TYPE_ROM),
+    };
+
+    uint8_t *p = *p_outbuf + 2;
+    int length;
+
+    if ((mode_sense_valid[page] & (1 << s->qdev.type)) == 0) {
+        return -1;
+    }
+
+    /*
+     * If Changeable Values are requested, a mask denoting those mode parameters
+     * that are changeable shall be returned. As we currently don't support
+     * parameter changes via MODE_SELECT all bits are returned set to zero.
+     * The buffer was already menset to zero by the caller of this function.
+     *
+     * The offsets here are off by two compared to the descriptions in the
+     * SCSI specs, because those include a 2-byte header.  This is unfortunate,
+     * but it is done so that offsets are consistent within our implementation
+     * of MODE SENSE and MODE SELECT.  MODE SELECT has to deal with both
+     * 2-byte and 4-byte headers.
+     */
+    switch (page) {
+    case MODE_PAGE_HD_GEOMETRY:
+        length = 0x16;
+        if (page_control == 1) { /* Changeable Values */
+            break;
+        }
+        /* if a geometry hint is available, use it */
+        p[0] = (s->qdev.conf.cyls >> 16) & 0xff;
+        p[1] = (s->qdev.conf.cyls >> 8) & 0xff;
+        p[2] = s->qdev.conf.cyls & 0xff;
+        p[3] = s->qdev.conf.heads & 0xff;
+        /* Write precomp start cylinder, disabled */
+        p[4] = (s->qdev.conf.cyls >> 16) & 0xff;
+        p[5] = (s->qdev.conf.cyls >> 8) & 0xff;
+        p[6] = s->qdev.conf.cyls & 0xff;
+        /* Reduced current start cylinder, disabled */
+        p[7] = (s->qdev.conf.cyls >> 16) & 0xff;
+        p[8] = (s->qdev.conf.cyls >> 8) & 0xff;
+        p[9] = s->qdev.conf.cyls & 0xff;
+        /* Device step rate [ns], 200ns */
+        p[10] = 0;
+        p[11] = 200;
+        /* Landing zone cylinder */
+        p[12] = 0xff;
+        p[13] =  0xff;
+        p[14] = 0xff;
+        /* Medium rotation rate [rpm], 5400 rpm */
+        p[18] = (5400 >> 8) & 0xff;
+        p[19] = 5400 & 0xff;
+        break;
+
+    case MODE_PAGE_FLEXIBLE_DISK_GEOMETRY:
+        length = 0x1e;
+        if (page_control == 1) { /* Changeable Values */
+            break;
+        }
+        /* Transfer rate [kbit/s], 5Mbit/s */
+        p[0] = 5000 >> 8;
+        p[1] = 5000 & 0xff;
+        /* if a geometry hint is available, use it */
+        p[2] = s->qdev.conf.heads & 0xff;
+        p[3] = s->qdev.conf.secs & 0xff;
+        p[4] = s->qdev.blocksize >> 8;
+        p[6] = (s->qdev.conf.cyls >> 8) & 0xff;
+        p[7] = s->qdev.conf.cyls & 0xff;
+        /* Write precomp start cylinder, disabled */
+        p[8] = (s->qdev.conf.cyls >> 8) & 0xff;
+        p[9] = s->qdev.conf.cyls & 0xff;
+        /* Reduced current start cylinder, disabled */
+        p[10] = (s->qdev.conf.cyls >> 8) & 0xff;
+        p[11] = s->qdev.conf.cyls & 0xff;
+        /* Device step rate [100us], 100us */
+        p[12] = 0;
+        p[13] = 1;
+        /* Device step pulse width [us], 1us */
+        p[14] = 1;
+        /* Device head settle delay [100us], 100us */
+        p[15] = 0;
+        p[16] = 1;
+        /* Motor on delay [0.1s], 0.1s */
+        p[17] = 1;
+        /* Motor off delay [0.1s], 0.1s */
+        p[18] = 1;
+        /* Medium rotation rate [rpm], 5400 rpm */
+        p[26] = (5400 >> 8) & 0xff;
+        p[27] = 5400 & 0xff;
+        break;
+
+    case MODE_PAGE_CACHING:
+        length = 0x12;
+        if (page_control == 1 || /* Changeable Values */
+            bdrv_enable_write_cache(s->qdev.conf.bs)) {
+            p[0] = 4; /* WCE */
+        }
+        break;
+
+    case MODE_PAGE_R_W_ERROR:
+        length = 10;
+        if (page_control == 1) { /* Changeable Values */
+            break;
+        }
+        p[0] = 0x80; /* Automatic Write Reallocation Enabled */
+        if (s->qdev.type == TYPE_ROM) {
+            p[1] = 0x20; /* Read Retry Count */
+        }
+        break;
+
+    case MODE_PAGE_AUDIO_CTL:
+        length = 14;
+        break;
+
+    case MODE_PAGE_CAPABILITIES:
+        length = 0x14;
+        if (page_control == 1) { /* Changeable Values */
+            break;
+        }
+
+        p[0] = 0x3b; /* CD-R & CD-RW read */
+        p[1] = 0; /* Writing not supported */
+        p[2] = 0x7f; /* Audio, composite, digital out,
+                        mode 2 form 1&2, multi session */
+        p[3] = 0xff; /* CD DA, DA accurate, RW supported,
+                        RW corrected, C2 errors, ISRC,
+                        UPC, Bar code */
+        p[4] = 0x2d | (s->tray_locked ? 2 : 0);
+        /* Locking supported, jumper present, eject, tray */
+        p[5] = 0; /* no volume & mute control, no
+                     changer */
+        p[6] = (50 * 176) >> 8; /* 50x read speed */
+        p[7] = (50 * 176) & 0xff;
+        p[8] = 2 >> 8; /* Two volume levels */
+        p[9] = 2 & 0xff;
+        p[10] = 2048 >> 8; /* 2M buffer */
+        p[11] = 2048 & 0xff;
+        p[12] = (16 * 176) >> 8; /* 16x read speed current */
+        p[13] = (16 * 176) & 0xff;
+        p[16] = (16 * 176) >> 8; /* 16x write speed */
+        p[17] = (16 * 176) & 0xff;
+        p[18] = (16 * 176) >> 8; /* 16x write speed current */
+        p[19] = (16 * 176) & 0xff;
+        break;
+
+    default:
+        return -1;
+    }
+
+    assert(length < 256);
+    (*p_outbuf)[0] = page;
+    (*p_outbuf)[1] = length;
+    *p_outbuf += length + 2;
+    return length + 2;
+}
+
+static int scsi_disk_emulate_mode_sense(SCSIDiskReq *r, uint8_t *outbuf)
+{
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
+    uint64_t nb_sectors;
+    bool dbd;
+    int page, buflen, ret, page_control;
+    uint8_t *p;
+    uint8_t dev_specific_param;
+
+    dbd = (r->req.cmd.buf[1] & 0x8) != 0;
+    page = r->req.cmd.buf[2] & 0x3f;
+    page_control = (r->req.cmd.buf[2] & 0xc0) >> 6;
+    DPRINTF("Mode Sense(%d) (page %d, xfer %zd, page_control %d)\n",
+        (r->req.cmd.buf[0] == MODE_SENSE) ? 6 : 10, page, r->req.cmd.xfer, page_control);
+    memset(outbuf, 0, r->req.cmd.xfer);
+    p = outbuf;
+
+    if (s->qdev.type == TYPE_DISK) {
+        dev_specific_param = s->features & (1 << SCSI_DISK_F_DPOFUA) ? 0x10 : 0;
+        if (bdrv_is_read_only(s->qdev.conf.bs)) {
+            dev_specific_param |= 0x80; /* Readonly.  */
+        }
+    } else {
+        /* MMC prescribes that CD/DVD drives have no block descriptors,
+         * and defines no device-specific parameter.  */
+        dev_specific_param = 0x00;
+        dbd = true;
+    }
+
+    if (r->req.cmd.buf[0] == MODE_SENSE) {
+        p[1] = 0; /* Default media type.  */
+        p[2] = dev_specific_param;
+        p[3] = 0; /* Block descriptor length.  */
+        p += 4;
+    } else { /* MODE_SENSE_10 */
+        p[2] = 0; /* Default media type.  */
+        p[3] = dev_specific_param;
+        p[6] = p[7] = 0; /* Block descriptor length.  */
+        p += 8;
+    }
+
+    bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors);
+    if (!dbd && nb_sectors) {
+        if (r->req.cmd.buf[0] == MODE_SENSE) {
+            outbuf[3] = 8; /* Block descriptor length  */
+        } else { /* MODE_SENSE_10 */
+            outbuf[7] = 8; /* Block descriptor length  */
+        }
+        nb_sectors /= (s->qdev.blocksize / 512);
+        if (nb_sectors > 0xffffff) {
+            nb_sectors = 0;
+        }
+        p[0] = 0; /* media density code */
+        p[1] = (nb_sectors >> 16) & 0xff;
+        p[2] = (nb_sectors >> 8) & 0xff;
+        p[3] = nb_sectors & 0xff;
+        p[4] = 0; /* reserved */
+        p[5] = 0; /* bytes 5-7 are the sector size in bytes */
+        p[6] = s->qdev.blocksize >> 8;
+        p[7] = 0;
+        p += 8;
+    }
+
+    if (page_control == 3) {
+        /* Saved Values */
+        scsi_check_condition(r, SENSE_CODE(SAVING_PARAMS_NOT_SUPPORTED));
+        return -1;
+    }
+
+    if (page == 0x3f) {
+        for (page = 0; page <= 0x3e; page++) {
+            mode_sense_page(s, page, &p, page_control);
+        }
+    } else {
+        ret = mode_sense_page(s, page, &p, page_control);
+        if (ret == -1) {
+            return -1;
+        }
+    }
+
+    buflen = p - outbuf;
+    /*
+     * The mode data length field specifies the length in bytes of the
+     * following data that is available to be transferred. The mode data
+     * length does not include itself.
+     */
+    if (r->req.cmd.buf[0] == MODE_SENSE) {
+        outbuf[0] = buflen - 1;
+    } else { /* MODE_SENSE_10 */
+        outbuf[0] = ((buflen - 2) >> 8) & 0xff;
+        outbuf[1] = (buflen - 2) & 0xff;
+    }
+    return buflen;
+}
+
+static int scsi_disk_emulate_read_toc(SCSIRequest *req, uint8_t *outbuf)
+{
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
+    int start_track, format, msf, toclen;
+    uint64_t nb_sectors;
+
+    msf = req->cmd.buf[1] & 2;
+    format = req->cmd.buf[2] & 0xf;
+    start_track = req->cmd.buf[6];
+    bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors);
+    DPRINTF("Read TOC (track %d format %d msf %d)\n", start_track, format, msf >> 1);
+    nb_sectors /= s->qdev.blocksize / 512;
+    switch (format) {
+    case 0:
+        toclen = cdrom_read_toc(nb_sectors, outbuf, msf, start_track);
+        break;
+    case 1:
+        /* multi session : only a single session defined */
+        toclen = 12;
+        memset(outbuf, 0, 12);
+        outbuf[1] = 0x0a;
+        outbuf[2] = 0x01;
+        outbuf[3] = 0x01;
+        break;
+    case 2:
+        toclen = cdrom_read_toc_raw(nb_sectors, outbuf, msf, start_track);
+        break;
+    default:
+        return -1;
+    }
+    return toclen;
+}
+
+static int scsi_disk_emulate_start_stop(SCSIDiskReq *r)
+{
+    SCSIRequest *req = &r->req;
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
+    bool start = req->cmd.buf[4] & 1;
+    bool loej = req->cmd.buf[4] & 2; /* load on start, eject on !start */
+    int pwrcnd = req->cmd.buf[4] & 0xf0;
+
+    if (pwrcnd) {
+        /* eject/load only happens for power condition == 0 */
+        return 0;
+    }
+
+    if ((s->features & (1 << SCSI_DISK_F_REMOVABLE)) && loej) {
+        if (!start && !s->tray_open && s->tray_locked) {
+            scsi_check_condition(r,
+                                 bdrv_is_inserted(s->qdev.conf.bs)
+                                 ? SENSE_CODE(ILLEGAL_REQ_REMOVAL_PREVENTED)
+                                 : SENSE_CODE(NOT_READY_REMOVAL_PREVENTED));
+            return -1;
+        }
+
+        if (s->tray_open != !start) {
+            bdrv_eject(s->qdev.conf.bs, !start);
+            s->tray_open = !start;
+        }
+    }
+    return 0;
+}
+
+static void scsi_disk_emulate_read_data(SCSIRequest *req)
+{
+    SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
+    int buflen = r->iov.iov_len;
+
+    if (buflen) {
+        DPRINTF("Read buf_len=%d\n", buflen);
+        r->iov.iov_len = 0;
+        r->started = true;
+        scsi_req_data(&r->req, buflen);
+        return;
+    }
+
+    /* This also clears the sense buffer for REQUEST SENSE.  */
+    scsi_req_complete(&r->req, GOOD);
+}
+
+static int scsi_disk_check_mode_select(SCSIDiskState *s, int page,
+                                       uint8_t *inbuf, int inlen)
+{
+    uint8_t mode_current[SCSI_MAX_MODE_LEN];
+    uint8_t mode_changeable[SCSI_MAX_MODE_LEN];
+    uint8_t *p;
+    int len, expected_len, changeable_len, i;
+
+    /* The input buffer does not include the page header, so it is
+     * off by 2 bytes.
+     */
+    expected_len = inlen + 2;
+    if (expected_len > SCSI_MAX_MODE_LEN) {
+        return -1;
+    }
+
+    p = mode_current;
+    memset(mode_current, 0, inlen + 2);
+    len = mode_sense_page(s, page, &p, 0);
+    if (len < 0 || len != expected_len) {
+        return -1;
+    }
+
+    p = mode_changeable;
+    memset(mode_changeable, 0, inlen + 2);
+    changeable_len = mode_sense_page(s, page, &p, 1);
+    assert(changeable_len == len);
+
+    /* Check that unchangeable bits are the same as what MODE SENSE
+     * would return.
+     */
+    for (i = 2; i < len; i++) {
+        if (((mode_current[i] ^ inbuf[i - 2]) & ~mode_changeable[i]) != 0) {
+            return -1;
+        }
+    }
+    return 0;
+}
+
+static void scsi_disk_apply_mode_select(SCSIDiskState *s, int page, uint8_t *p)
+{
+    switch (page) {
+    case MODE_PAGE_CACHING:
+        bdrv_set_enable_write_cache(s->qdev.conf.bs, (p[0] & 4) != 0);
+        break;
+
+    default:
+        break;
+    }
+}
+
+static int mode_select_pages(SCSIDiskReq *r, uint8_t *p, int len, bool change)
+{
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
+
+    while (len > 0) {
+        int page, subpage, page_len;
+
+        /* Parse both possible formats for the mode page headers.  */
+        page = p[0] & 0x3f;
+        if (p[0] & 0x40) {
+            if (len < 4) {
+                goto invalid_param_len;
+            }
+            subpage = p[1];
+            page_len = lduw_be_p(&p[2]);
+            p += 4;
+            len -= 4;
+        } else {
+            if (len < 2) {
+                goto invalid_param_len;
+            }
+            subpage = 0;
+            page_len = p[1];
+            p += 2;
+            len -= 2;
+        }
+
+        if (subpage) {
+            goto invalid_param;
+        }
+        if (page_len > len) {
+            goto invalid_param_len;
+        }
+
+        if (!change) {
+            if (scsi_disk_check_mode_select(s, page, p, page_len) < 0) {
+                goto invalid_param;
+            }
+        } else {
+            scsi_disk_apply_mode_select(s, page, p);
+        }
+
+        p += page_len;
+        len -= page_len;
+    }
+    return 0;
+
+invalid_param:
+    scsi_check_condition(r, SENSE_CODE(INVALID_PARAM));
+    return -1;
+
+invalid_param_len:
+    scsi_check_condition(r, SENSE_CODE(INVALID_PARAM_LEN));
+    return -1;
+}
+
+static void scsi_disk_emulate_mode_select(SCSIDiskReq *r, uint8_t *inbuf)
+{
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
+    uint8_t *p = inbuf;
+    int cmd = r->req.cmd.buf[0];
+    int len = r->req.cmd.xfer;
+    int hdr_len = (cmd == MODE_SELECT ? 4 : 8);
+    int bd_len;
+    int pass;
+
+    /* We only support PF=1, SP=0.  */
+    if ((r->req.cmd.buf[1] & 0x11) != 0x10) {
+        goto invalid_field;
+    }
+
+    if (len < hdr_len) {
+        goto invalid_param_len;
+    }
+
+    bd_len = (cmd == MODE_SELECT ? p[3] : lduw_be_p(&p[6]));
+    len -= hdr_len;
+    p += hdr_len;
+    if (len < bd_len) {
+        goto invalid_param_len;
+    }
+    if (bd_len != 0 && bd_len != 8) {
+        goto invalid_param;
+    }
+
+    len -= bd_len;
+    p += bd_len;
+
+    /* Ensure no change is made if there is an error!  */
+    for (pass = 0; pass < 2; pass++) {
+        if (mode_select_pages(r, p, len, pass == 1) < 0) {
+            assert(pass == 0);
+            return;
+        }
+    }
+    if (!bdrv_enable_write_cache(s->qdev.conf.bs)) {
+        /* The request is used as the AIO opaque value, so add a ref.  */
+        scsi_req_ref(&r->req);
+        bdrv_acct_start(s->qdev.conf.bs, &r->acct, 0, BDRV_ACCT_FLUSH);
+        r->req.aiocb = bdrv_aio_flush(s->qdev.conf.bs, scsi_aio_complete, r);
+        return;
+    }
+
+    scsi_req_complete(&r->req, GOOD);
+    return;
+
+invalid_param:
+    scsi_check_condition(r, SENSE_CODE(INVALID_PARAM));
+    return;
+
+invalid_param_len:
+    scsi_check_condition(r, SENSE_CODE(INVALID_PARAM_LEN));
+    return;
+
+invalid_field:
+    scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
+}
+
+static inline bool check_lba_range(SCSIDiskState *s,
+                                   uint64_t sector_num, uint32_t nb_sectors)
+{
+    /*
+     * The first line tests that no overflow happens when computing the last
+     * sector.  The second line tests that the last accessed sector is in
+     * range.
+     *
+     * Careful, the computations should not underflow for nb_sectors == 0,
+     * and a 0-block read to the first LBA beyond the end of device is
+     * valid.
+     */
+    return (sector_num <= sector_num + nb_sectors &&
+            sector_num + nb_sectors <= s->qdev.max_lba + 1);
+}
+
+typedef struct UnmapCBData {
+    SCSIDiskReq *r;
+    uint8_t *inbuf;
+    int count;
+} UnmapCBData;
+
+static void scsi_unmap_complete(void *opaque, int ret)
+{
+    UnmapCBData *data = opaque;
+    SCSIDiskReq *r = data->r;
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
+    uint64_t sector_num;
+    uint32_t nb_sectors;
+
+    r->req.aiocb = NULL;
+    if (r->req.io_canceled) {
+        goto done;
+    }
+
+    if (ret < 0) {
+        if (scsi_handle_rw_error(r, -ret)) {
+            goto done;
+        }
+    }
+
+    if (data->count > 0) {
+        sector_num = ldq_be_p(&data->inbuf[0]);
+        nb_sectors = ldl_be_p(&data->inbuf[8]) & 0xffffffffULL;
+        if (!check_lba_range(s, sector_num, nb_sectors)) {
+            scsi_check_condition(r, SENSE_CODE(LBA_OUT_OF_RANGE));
+            goto done;
+        }
+
+        r->req.aiocb = bdrv_aio_discard(s->qdev.conf.bs,
+                                        sector_num * (s->qdev.blocksize / 512),
+                                        nb_sectors * (s->qdev.blocksize / 512),
+                                        scsi_unmap_complete, data);
+        data->count--;
+        data->inbuf += 16;
+        return;
+    }
+
+    scsi_req_complete(&r->req, GOOD);
+
+done:
+    if (!r->req.io_canceled) {
+        scsi_req_unref(&r->req);
+    }
+    g_free(data);
+}
+
+static void scsi_disk_emulate_unmap(SCSIDiskReq *r, uint8_t *inbuf)
+{
+    uint8_t *p = inbuf;
+    int len = r->req.cmd.xfer;
+    UnmapCBData *data;
+
+    if (len < 8) {
+        goto invalid_param_len;
+    }
+    if (len < lduw_be_p(&p[0]) + 2) {
+        goto invalid_param_len;
+    }
+    if (len < lduw_be_p(&p[2]) + 8) {
+        goto invalid_param_len;
+    }
+    if (lduw_be_p(&p[2]) & 15) {
+        goto invalid_param_len;
+    }
+
+    data = g_new0(UnmapCBData, 1);
+    data->r = r;
+    data->inbuf = &p[8];
+    data->count = lduw_be_p(&p[2]) >> 4;
+
+    /* The matching unref is in scsi_unmap_complete, before data is freed.  */
+    scsi_req_ref(&r->req);
+    scsi_unmap_complete(data, 0);
+    return;
+
+invalid_param_len:
+    scsi_check_condition(r, SENSE_CODE(INVALID_PARAM_LEN));
+}
+
+static void scsi_disk_emulate_write_data(SCSIRequest *req)
+{
+    SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
+
+    if (r->iov.iov_len) {
+        int buflen = r->iov.iov_len;
+        DPRINTF("Write buf_len=%d\n", buflen);
+        r->iov.iov_len = 0;
+        scsi_req_data(&r->req, buflen);
+        return;
+    }
+
+    switch (req->cmd.buf[0]) {
+    case MODE_SELECT:
+    case MODE_SELECT_10:
+        /* This also clears the sense buffer for REQUEST SENSE.  */
+        scsi_disk_emulate_mode_select(r, r->iov.iov_base);
+        break;
+
+    case UNMAP:
+        scsi_disk_emulate_unmap(r, r->iov.iov_base);
+        break;
+
+    default:
+        abort();
+    }
+}
+
+static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf)
+{
+    SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
+    uint64_t nb_sectors;
+    uint8_t *outbuf;
+    int buflen;
+
+    switch (req->cmd.buf[0]) {
+    case INQUIRY:
+    case MODE_SENSE:
+    case MODE_SENSE_10:
+    case RESERVE:
+    case RESERVE_10:
+    case RELEASE:
+    case RELEASE_10:
+    case START_STOP:
+    case ALLOW_MEDIUM_REMOVAL:
+    case GET_CONFIGURATION:
+    case GET_EVENT_STATUS_NOTIFICATION:
+    case MECHANISM_STATUS:
+    case REQUEST_SENSE:
+        break;
+
+    default:
+        if (s->tray_open || !bdrv_is_inserted(s->qdev.conf.bs)) {
+            scsi_check_condition(r, SENSE_CODE(NO_MEDIUM));
+            return 0;
+        }
+        break;
+    }
+
+    /*
+     * FIXME: we shouldn't return anything bigger than 4k, but the code
+     * requires the buffer to be as big as req->cmd.xfer in several
+     * places.  So, do not allow CDBs with a very large ALLOCATION
+     * LENGTH.  The real fix would be to modify scsi_read_data and
+     * dma_buf_read, so that they return data beyond the buflen
+     * as all zeros.
+     */
+    if (req->cmd.xfer > 65536) {
+        goto illegal_request;
+    }
+    r->buflen = MAX(4096, req->cmd.xfer);
+
+    if (!r->iov.iov_base) {
+        r->iov.iov_base = qemu_blockalign(s->qdev.conf.bs, r->buflen);
+    }
+
+    buflen = req->cmd.xfer;
+    outbuf = r->iov.iov_base;
+    memset(outbuf, 0, r->buflen);
+    switch (req->cmd.buf[0]) {
+    case TEST_UNIT_READY:
+        assert(!s->tray_open && bdrv_is_inserted(s->qdev.conf.bs));
+        break;
+    case INQUIRY:
+        buflen = scsi_disk_emulate_inquiry(req, outbuf);
+        if (buflen < 0) {
+            goto illegal_request;
+        }
+        break;
+    case MODE_SENSE:
+    case MODE_SENSE_10:
+        buflen = scsi_disk_emulate_mode_sense(r, outbuf);
+        if (buflen < 0) {
+            goto illegal_request;
+        }
+        break;
+    case READ_TOC:
+        buflen = scsi_disk_emulate_read_toc(req, outbuf);
+        if (buflen < 0) {
+            goto illegal_request;
+        }
+        break;
+    case RESERVE:
+        if (req->cmd.buf[1] & 1) {
+            goto illegal_request;
+        }
+        break;
+    case RESERVE_10:
+        if (req->cmd.buf[1] & 3) {
+            goto illegal_request;
+        }
+        break;
+    case RELEASE:
+        if (req->cmd.buf[1] & 1) {
+            goto illegal_request;
+        }
+        break;
+    case RELEASE_10:
+        if (req->cmd.buf[1] & 3) {
+            goto illegal_request;
+        }
+        break;
+    case START_STOP:
+        if (scsi_disk_emulate_start_stop(r) < 0) {
+            return 0;
+        }
+        break;
+    case ALLOW_MEDIUM_REMOVAL:
+        s->tray_locked = req->cmd.buf[4] & 1;
+        bdrv_lock_medium(s->qdev.conf.bs, req->cmd.buf[4] & 1);
+        break;
+    case READ_CAPACITY_10:
+        /* The normal LEN field for this command is zero.  */
+        memset(outbuf, 0, 8);
+        bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors);
+        if (!nb_sectors) {
+            scsi_check_condition(r, SENSE_CODE(LUN_NOT_READY));
+            return 0;
+        }
+        if ((req->cmd.buf[8] & 1) == 0 && req->cmd.lba) {
+            goto illegal_request;
+        }
+        nb_sectors /= s->qdev.blocksize / 512;
+        /* Returned value is the address of the last sector.  */
+        nb_sectors--;
+        /* Remember the new size for read/write sanity checking. */
+        s->qdev.max_lba = nb_sectors;
+        /* Clip to 2TB, instead of returning capacity modulo 2TB. */
+        if (nb_sectors > UINT32_MAX) {
+            nb_sectors = UINT32_MAX;
+        }
+        outbuf[0] = (nb_sectors >> 24) & 0xff;
+        outbuf[1] = (nb_sectors >> 16) & 0xff;
+        outbuf[2] = (nb_sectors >> 8) & 0xff;
+        outbuf[3] = nb_sectors & 0xff;
+        outbuf[4] = 0;
+        outbuf[5] = 0;
+        outbuf[6] = s->qdev.blocksize >> 8;
+        outbuf[7] = 0;
+        break;
+    case REQUEST_SENSE:
+        /* Just return "NO SENSE".  */
+        buflen = scsi_build_sense(NULL, 0, outbuf, r->buflen,
+                                  (req->cmd.buf[1] & 1) == 0);
+        if (buflen < 0) {
+            goto illegal_request;
+        }
+        break;
+    case MECHANISM_STATUS:
+        buflen = scsi_emulate_mechanism_status(s, outbuf);
+        if (buflen < 0) {
+            goto illegal_request;
+        }
+        break;
+    case GET_CONFIGURATION:
+        buflen = scsi_get_configuration(s, outbuf);
+        if (buflen < 0) {
+            goto illegal_request;
+        }
+        break;
+    case GET_EVENT_STATUS_NOTIFICATION:
+        buflen = scsi_get_event_status_notification(s, r, outbuf);
+        if (buflen < 0) {
+            goto illegal_request;
+        }
+        break;
+    case READ_DISC_INFORMATION:
+        buflen = scsi_read_disc_information(s, r, outbuf);
+        if (buflen < 0) {
+            goto illegal_request;
+        }
+        break;
+    case READ_DVD_STRUCTURE:
+        buflen = scsi_read_dvd_structure(s, r, outbuf);
+        if (buflen < 0) {
+            goto illegal_request;
+        }
+        break;
+    case SERVICE_ACTION_IN_16:
+        /* Service Action In subcommands. */
+        if ((req->cmd.buf[1] & 31) == SAI_READ_CAPACITY_16) {
+            DPRINTF("SAI READ CAPACITY(16)\n");
+            memset(outbuf, 0, req->cmd.xfer);
+            bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors);
+            if (!nb_sectors) {
+                scsi_check_condition(r, SENSE_CODE(LUN_NOT_READY));
+                return 0;
+            }
+            if ((req->cmd.buf[14] & 1) == 0 && req->cmd.lba) {
+                goto illegal_request;
+            }
+            nb_sectors /= s->qdev.blocksize / 512;
+            /* Returned value is the address of the last sector.  */
+            nb_sectors--;
+            /* Remember the new size for read/write sanity checking. */
+            s->qdev.max_lba = nb_sectors;
+            outbuf[0] = (nb_sectors >> 56) & 0xff;
+            outbuf[1] = (nb_sectors >> 48) & 0xff;
+            outbuf[2] = (nb_sectors >> 40) & 0xff;
+            outbuf[3] = (nb_sectors >> 32) & 0xff;
+            outbuf[4] = (nb_sectors >> 24) & 0xff;
+            outbuf[5] = (nb_sectors >> 16) & 0xff;
+            outbuf[6] = (nb_sectors >> 8) & 0xff;
+            outbuf[7] = nb_sectors & 0xff;
+            outbuf[8] = 0;
+            outbuf[9] = 0;
+            outbuf[10] = s->qdev.blocksize >> 8;
+            outbuf[11] = 0;
+            outbuf[12] = 0;
+            outbuf[13] = get_physical_block_exp(&s->qdev.conf);
+
+            /* set TPE bit if the format supports discard */
+            if (s->qdev.conf.discard_granularity) {
+                outbuf[14] = 0x80;
+            }
+
+            /* Protection, exponent and lowest lba field left blank. */
+            break;
+        }
+        DPRINTF("Unsupported Service Action In\n");
+        goto illegal_request;
+    case SYNCHRONIZE_CACHE:
+        /* The request is used as the AIO opaque value, so add a ref.  */
+        scsi_req_ref(&r->req);
+        bdrv_acct_start(s->qdev.conf.bs, &r->acct, 0, BDRV_ACCT_FLUSH);
+        r->req.aiocb = bdrv_aio_flush(s->qdev.conf.bs, scsi_aio_complete, r);
+        return 0;
+    case SEEK_10:
+        DPRINTF("Seek(10) (sector %" PRId64 ")\n", r->req.cmd.lba);
+        if (r->req.cmd.lba > s->qdev.max_lba) {
+            goto illegal_lba;
+        }
+        break;
+    case MODE_SELECT:
+        DPRINTF("Mode Select(6) (len %lu)\n", (long)r->req.cmd.xfer);
+        break;
+    case MODE_SELECT_10:
+        DPRINTF("Mode Select(10) (len %lu)\n", (long)r->req.cmd.xfer);
+        break;
+    case UNMAP:
+        DPRINTF("Unmap (len %lu)\n", (long)r->req.cmd.xfer);
+        break;
+    case WRITE_SAME_10:
+    case WRITE_SAME_16:
+        nb_sectors = scsi_data_cdb_length(r->req.cmd.buf);
+        if (bdrv_is_read_only(s->qdev.conf.bs)) {
+            scsi_check_condition(r, SENSE_CODE(WRITE_PROTECTED));
+            return 0;
+        }
+        if (!check_lba_range(s, r->req.cmd.lba, nb_sectors)) {
+            goto illegal_lba;
+        }
+
+        /*
+         * We only support WRITE SAME with the unmap bit set for now.
+         */
+        if (!(req->cmd.buf[1] & 0x8)) {
+            goto illegal_request;
+        }
+
+        /* The request is used as the AIO opaque value, so add a ref.  */
+        scsi_req_ref(&r->req);
+        r->req.aiocb = bdrv_aio_discard(s->qdev.conf.bs,
+                                        r->req.cmd.lba * (s->qdev.blocksize / 512),
+                                        nb_sectors * (s->qdev.blocksize / 512),
+                                        scsi_aio_complete, r);
+        return 0;
+    default:
+        DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]);
+        scsi_check_condition(r, SENSE_CODE(INVALID_OPCODE));
+        return 0;
+    }
+    assert(!r->req.aiocb);
+    r->iov.iov_len = MIN(r->buflen, req->cmd.xfer);
+    if (r->iov.iov_len == 0) {
+        scsi_req_complete(&r->req, GOOD);
+    }
+    if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
+        assert(r->iov.iov_len == req->cmd.xfer);
+        return -r->iov.iov_len;
+    } else {
+        return r->iov.iov_len;
+    }
+
+illegal_request:
+    if (r->req.status == -1) {
+        scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
+    }
+    return 0;
+
+illegal_lba:
+    scsi_check_condition(r, SENSE_CODE(LBA_OUT_OF_RANGE));
+    return 0;
+}
+
+/* Execute a scsi command.  Returns the length of the data expected by the
+   command.  This will be Positive for data transfers from the device
+   (eg. disk reads), negative for transfers to the device (eg. disk writes),
+   and zero if the command does not transfer any data.  */
+
+static int32_t scsi_disk_dma_command(SCSIRequest *req, uint8_t *buf)
+{
+    SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
+    uint32_t len;
+    uint8_t command;
+
+    command = buf[0];
+
+    if (s->tray_open || !bdrv_is_inserted(s->qdev.conf.bs)) {
+        scsi_check_condition(r, SENSE_CODE(NO_MEDIUM));
+        return 0;
+    }
+
+    len = scsi_data_cdb_length(r->req.cmd.buf);
+    switch (command) {
+    case READ_6:
+    case READ_10:
+    case READ_12:
+    case READ_16:
+        DPRINTF("Read (sector %" PRId64 ", count %u)\n", r->req.cmd.lba, len);
+        if (r->req.cmd.buf[1] & 0xe0) {
+            goto illegal_request;
+        }
+        if (!check_lba_range(s, r->req.cmd.lba, len)) {
+            goto illegal_lba;
+        }
+        r->sector = r->req.cmd.lba * (s->qdev.blocksize / 512);
+        r->sector_count = len * (s->qdev.blocksize / 512);
+        break;
+    case WRITE_6:
+    case WRITE_10:
+    case WRITE_12:
+    case WRITE_16:
+    case WRITE_VERIFY_10:
+    case WRITE_VERIFY_12:
+    case WRITE_VERIFY_16:
+        if (bdrv_is_read_only(s->qdev.conf.bs)) {
+            scsi_check_condition(r, SENSE_CODE(WRITE_PROTECTED));
+            return 0;
+        }
+        /* fallthrough */
+    case VERIFY_10:
+    case VERIFY_12:
+    case VERIFY_16:
+        DPRINTF("Write %s(sector %" PRId64 ", count %u)\n",
+                (command & 0xe) == 0xe ? "And Verify " : "",
+                r->req.cmd.lba, len);
+        if (r->req.cmd.buf[1] & 0xe0) {
+            goto illegal_request;
+        }
+        if (!check_lba_range(s, r->req.cmd.lba, len)) {
+            goto illegal_lba;
+        }
+        r->sector = r->req.cmd.lba * (s->qdev.blocksize / 512);
+        r->sector_count = len * (s->qdev.blocksize / 512);
+        break;
+    default:
+        abort();
+    illegal_request:
+        scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
+        return 0;
+    illegal_lba:
+        scsi_check_condition(r, SENSE_CODE(LBA_OUT_OF_RANGE));
+        return 0;
+    }
+    if (r->sector_count == 0) {
+        scsi_req_complete(&r->req, GOOD);
+    }
+    assert(r->iov.iov_len == 0);
+    if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
+        return -r->sector_count * 512;
+    } else {
+        return r->sector_count * 512;
+    }
+}
+
+static void scsi_disk_reset(DeviceState *dev)
+{
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev.qdev, dev);
+    uint64_t nb_sectors;
+
+    scsi_device_purge_requests(&s->qdev, SENSE_CODE(RESET));
+
+    bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors);
+    nb_sectors /= s->qdev.blocksize / 512;
+    if (nb_sectors) {
+        nb_sectors--;
+    }
+    s->qdev.max_lba = nb_sectors;
+}
+
+static void scsi_destroy(SCSIDevice *dev)
+{
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
+
+    scsi_device_purge_requests(&s->qdev, SENSE_CODE(NO_SENSE));
+    blockdev_mark_auto_del(s->qdev.conf.bs);
+}
+
+static void scsi_disk_resize_cb(void *opaque)
+{
+    SCSIDiskState *s = opaque;
+
+    /* SPC lists this sense code as available only for
+     * direct-access devices.
+     */
+    if (s->qdev.type == TYPE_DISK) {
+        scsi_device_report_change(&s->qdev, SENSE_CODE(CAPACITY_CHANGED));
+    }
+}
+
+static void scsi_cd_change_media_cb(void *opaque, bool load)
+{
+    SCSIDiskState *s = opaque;
+
+    /*
+     * When a CD gets changed, we have to report an ejected state and
+     * then a loaded state to guests so that they detect tray
+     * open/close and media change events.  Guests that do not use
+     * GET_EVENT_STATUS_NOTIFICATION to detect such tray open/close
+     * states rely on this behavior.
+     *
+     * media_changed governs the state machine used for unit attention
+     * report.  media_event is used by GET EVENT STATUS NOTIFICATION.
+     */
+    s->media_changed = load;
+    s->tray_open = !load;
+    scsi_device_set_ua(&s->qdev, SENSE_CODE(UNIT_ATTENTION_NO_MEDIUM));
+    s->media_event = true;
+    s->eject_request = false;
+}
+
+static void scsi_cd_eject_request_cb(void *opaque, bool force)
+{
+    SCSIDiskState *s = opaque;
+
+    s->eject_request = true;
+    if (force) {
+        s->tray_locked = false;
+    }
+}
+
+static bool scsi_cd_is_tray_open(void *opaque)
+{
+    return ((SCSIDiskState *)opaque)->tray_open;
+}
+
+static bool scsi_cd_is_medium_locked(void *opaque)
+{
+    return ((SCSIDiskState *)opaque)->tray_locked;
+}
+
+static const BlockDevOps scsi_disk_removable_block_ops = {
+    .change_media_cb = scsi_cd_change_media_cb,
+    .eject_request_cb = scsi_cd_eject_request_cb,
+    .is_tray_open = scsi_cd_is_tray_open,
+    .is_medium_locked = scsi_cd_is_medium_locked,
+
+    .resize_cb = scsi_disk_resize_cb,
+};
+
+static const BlockDevOps scsi_disk_block_ops = {
+    .resize_cb = scsi_disk_resize_cb,
+};
+
+static void scsi_disk_unit_attention_reported(SCSIDevice *dev)
+{
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
+    if (s->media_changed) {
+        s->media_changed = false;
+        scsi_device_set_ua(&s->qdev, SENSE_CODE(MEDIUM_CHANGED));
+    }
+}
+
+static int scsi_initfn(SCSIDevice *dev)
+{
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
+
+    if (!s->qdev.conf.bs) {
+        error_report("drive property not set");
+        return -1;
+    }
+
+    if (!(s->features & (1 << SCSI_DISK_F_REMOVABLE)) &&
+        !bdrv_is_inserted(s->qdev.conf.bs)) {
+        error_report("Device needs media, but drive is empty");
+        return -1;
+    }
+
+    blkconf_serial(&s->qdev.conf, &s->serial);
+    if (dev->type == TYPE_DISK
+        && blkconf_geometry(&dev->conf, NULL, 65535, 255, 255) < 0) {
+        return -1;
+    }
+
+    if (s->qdev.conf.discard_granularity == -1) {
+        s->qdev.conf.discard_granularity =
+            MAX(s->qdev.conf.logical_block_size, DEFAULT_DISCARD_GRANULARITY);
+    }
+
+    if (!s->version) {
+        s->version = g_strdup(qemu_get_version());
+    }
+    if (!s->vendor) {
+        s->vendor = g_strdup("QEMU");
+    }
+
+    if (bdrv_is_sg(s->qdev.conf.bs)) {
+        error_report("unwanted /dev/sg*");
+        return -1;
+    }
+
+    if (s->features & (1 << SCSI_DISK_F_REMOVABLE)) {
+        bdrv_set_dev_ops(s->qdev.conf.bs, &scsi_disk_removable_block_ops, s);
+    } else {
+        bdrv_set_dev_ops(s->qdev.conf.bs, &scsi_disk_block_ops, s);
+    }
+    bdrv_set_buffer_alignment(s->qdev.conf.bs, s->qdev.blocksize);
+
+    bdrv_iostatus_enable(s->qdev.conf.bs);
+    add_boot_device_path(s->qdev.conf.bootindex, &dev->qdev, NULL);
+    return 0;
+}
+
+static int scsi_hd_initfn(SCSIDevice *dev)
+{
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
+    s->qdev.blocksize = s->qdev.conf.logical_block_size;
+    s->qdev.type = TYPE_DISK;
+    if (!s->product) {
+        s->product = g_strdup("QEMU HARDDISK");
+    }
+    return scsi_initfn(&s->qdev);
+}
+
+static int scsi_cd_initfn(SCSIDevice *dev)
+{
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
+    s->qdev.blocksize = 2048;
+    s->qdev.type = TYPE_ROM;
+    s->features |= 1 << SCSI_DISK_F_REMOVABLE;
+    if (!s->product) {
+        s->product = g_strdup("QEMU CD-ROM");
+    }
+    return scsi_initfn(&s->qdev);
+}
+
+static int scsi_disk_initfn(SCSIDevice *dev)
+{
+    DriveInfo *dinfo;
+
+    if (!dev->conf.bs) {
+        return scsi_initfn(dev);  /* ... and die there */
+    }
+
+    dinfo = drive_get_by_blockdev(dev->conf.bs);
+    if (dinfo->media_cd) {
+        return scsi_cd_initfn(dev);
+    } else {
+        return scsi_hd_initfn(dev);
+    }
+}
+
+static const SCSIReqOps scsi_disk_emulate_reqops = {
+    .size         = sizeof(SCSIDiskReq),
+    .free_req     = scsi_free_request,
+    .send_command = scsi_disk_emulate_command,
+    .read_data    = scsi_disk_emulate_read_data,
+    .write_data   = scsi_disk_emulate_write_data,
+    .get_buf      = scsi_get_buf,
+};
+
+static const SCSIReqOps scsi_disk_dma_reqops = {
+    .size         = sizeof(SCSIDiskReq),
+    .free_req     = scsi_free_request,
+    .send_command = scsi_disk_dma_command,
+    .read_data    = scsi_read_data,
+    .write_data   = scsi_write_data,
+    .cancel_io    = scsi_cancel_io,
+    .get_buf      = scsi_get_buf,
+    .load_request = scsi_disk_load_request,
+    .save_request = scsi_disk_save_request,
+};
+
+static const SCSIReqOps *const scsi_disk_reqops_dispatch[256] = {
+    [TEST_UNIT_READY]                 = &scsi_disk_emulate_reqops,
+    [INQUIRY]                         = &scsi_disk_emulate_reqops,
+    [MODE_SENSE]                      = &scsi_disk_emulate_reqops,
+    [MODE_SENSE_10]                   = &scsi_disk_emulate_reqops,
+    [START_STOP]                      = &scsi_disk_emulate_reqops,
+    [ALLOW_MEDIUM_REMOVAL]            = &scsi_disk_emulate_reqops,
+    [READ_CAPACITY_10]                = &scsi_disk_emulate_reqops,
+    [READ_TOC]                        = &scsi_disk_emulate_reqops,
+    [READ_DVD_STRUCTURE]              = &scsi_disk_emulate_reqops,
+    [READ_DISC_INFORMATION]           = &scsi_disk_emulate_reqops,
+    [GET_CONFIGURATION]               = &scsi_disk_emulate_reqops,
+    [GET_EVENT_STATUS_NOTIFICATION]   = &scsi_disk_emulate_reqops,
+    [MECHANISM_STATUS]                = &scsi_disk_emulate_reqops,
+    [SERVICE_ACTION_IN_16]            = &scsi_disk_emulate_reqops,
+    [REQUEST_SENSE]                   = &scsi_disk_emulate_reqops,
+    [SYNCHRONIZE_CACHE]               = &scsi_disk_emulate_reqops,
+    [SEEK_10]                         = &scsi_disk_emulate_reqops,
+    [MODE_SELECT]                     = &scsi_disk_emulate_reqops,
+    [MODE_SELECT_10]                  = &scsi_disk_emulate_reqops,
+    [UNMAP]                           = &scsi_disk_emulate_reqops,
+    [WRITE_SAME_10]                   = &scsi_disk_emulate_reqops,
+    [WRITE_SAME_16]                   = &scsi_disk_emulate_reqops,
+
+    [READ_6]                          = &scsi_disk_dma_reqops,
+    [READ_10]                         = &scsi_disk_dma_reqops,
+    [READ_12]                         = &scsi_disk_dma_reqops,
+    [READ_16]                         = &scsi_disk_dma_reqops,
+    [VERIFY_10]                       = &scsi_disk_dma_reqops,
+    [VERIFY_12]                       = &scsi_disk_dma_reqops,
+    [VERIFY_16]                       = &scsi_disk_dma_reqops,
+    [WRITE_6]                         = &scsi_disk_dma_reqops,
+    [WRITE_10]                        = &scsi_disk_dma_reqops,
+    [WRITE_12]                        = &scsi_disk_dma_reqops,
+    [WRITE_16]                        = &scsi_disk_dma_reqops,
+    [WRITE_VERIFY_10]                 = &scsi_disk_dma_reqops,
+    [WRITE_VERIFY_12]                 = &scsi_disk_dma_reqops,
+    [WRITE_VERIFY_16]                 = &scsi_disk_dma_reqops,
+};
+
+static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun,
+                                     uint8_t *buf, void *hba_private)
+{
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
+    SCSIRequest *req;
+    const SCSIReqOps *ops;
+    uint8_t command;
+
+    command = buf[0];
+    ops = scsi_disk_reqops_dispatch[command];
+    if (!ops) {
+        ops = &scsi_disk_emulate_reqops;
+    }
+    req = scsi_req_alloc(ops, &s->qdev, tag, lun, hba_private);
+
+#ifdef DEBUG_SCSI
+    DPRINTF("Command: lun=%d tag=0x%x data=0x%02x", lun, tag, buf[0]);
+    {
+        int i;
+        for (i = 1; i < req->cmd.len; i++) {
+            printf(" 0x%02x", buf[i]);
+        }
+        printf("\n");
+    }
+#endif
+
+    return req;
+}
+
+#ifdef __linux__
+static int get_device_type(SCSIDiskState *s)
+{
+    BlockDriverState *bdrv = s->qdev.conf.bs;
+    uint8_t cmd[16];
+    uint8_t buf[36];
+    uint8_t sensebuf[8];
+    sg_io_hdr_t io_header;
+    int ret;
+
+    memset(cmd, 0, sizeof(cmd));
+    memset(buf, 0, sizeof(buf));
+    cmd[0] = INQUIRY;
+    cmd[4] = sizeof(buf);
+
+    memset(&io_header, 0, sizeof(io_header));
+    io_header.interface_id = 'S';
+    io_header.dxfer_direction = SG_DXFER_FROM_DEV;
+    io_header.dxfer_len = sizeof(buf);
+    io_header.dxferp = buf;
+    io_header.cmdp = cmd;
+    io_header.cmd_len = sizeof(cmd);
+    io_header.mx_sb_len = sizeof(sensebuf);
+    io_header.sbp = sensebuf;
+    io_header.timeout = 6000; /* XXX */
+
+    ret = bdrv_ioctl(bdrv, SG_IO, &io_header);
+    if (ret < 0 || io_header.driver_status || io_header.host_status) {
+        return -1;
+    }
+    s->qdev.type = buf[0];
+    if (buf[1] & 0x80) {
+        s->features |= 1 << SCSI_DISK_F_REMOVABLE;
+    }
+    return 0;
+}
+
+static int scsi_block_initfn(SCSIDevice *dev)
+{
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
+    int sg_version;
+    int rc;
+
+    if (!s->qdev.conf.bs) {
+        error_report("scsi-block: drive property not set");
+        return -1;
+    }
+
+    /* check we are using a driver managing SG_IO (version 3 and after) */
+    if (bdrv_ioctl(s->qdev.conf.bs, SG_GET_VERSION_NUM, &sg_version) < 0 ||
+        sg_version < 30000) {
+        error_report("scsi-block: scsi generic interface too old");
+        return -1;
+    }
+
+    /* get device type from INQUIRY data */
+    rc = get_device_type(s);
+    if (rc < 0) {
+        error_report("scsi-block: INQUIRY failed");
+        return -1;
+    }
+
+    /* Make a guess for the block size, we'll fix it when the guest sends.
+     * READ CAPACITY.  If they don't, they likely would assume these sizes
+     * anyway. (TODO: check in /sys).
+     */
+    if (s->qdev.type == TYPE_ROM || s->qdev.type == TYPE_WORM) {
+        s->qdev.blocksize = 2048;
+    } else {
+        s->qdev.blocksize = 512;
+    }
+    return scsi_initfn(&s->qdev);
+}
+
+static SCSIRequest *scsi_block_new_request(SCSIDevice *d, uint32_t tag,
+                                           uint32_t lun, uint8_t *buf,
+                                           void *hba_private)
+{
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
+
+    switch (buf[0]) {
+    case READ_6:
+    case READ_10:
+    case READ_12:
+    case READ_16:
+    case VERIFY_10:
+    case VERIFY_12:
+    case VERIFY_16:
+    case WRITE_6:
+    case WRITE_10:
+    case WRITE_12:
+    case WRITE_16:
+    case WRITE_VERIFY_10:
+    case WRITE_VERIFY_12:
+    case WRITE_VERIFY_16:
+        /* If we are not using O_DIRECT, we might read stale data from the
+        * host cache if writes were made using other commands than these
+        * ones (such as WRITE SAME or EXTENDED COPY, etc.).  So, without
+        * O_DIRECT everything must go through SG_IO.
+         */
+        if (bdrv_get_flags(s->qdev.conf.bs) & BDRV_O_NOCACHE) {
+            break;
+        }
+
+        /* MMC writing cannot be done via pread/pwrite, because it sometimes
+         * involves writing beyond the maximum LBA or to negative LBA (lead-in).
+         * And once you do these writes, reading from the block device is
+         * unreliable, too.  It is even possible that reads deliver random data
+         * from the host page cache (this is probably a Linux bug).
+         *
+         * We might use scsi_disk_dma_reqops as long as no writing commands are
+         * seen, but performance usually isn't paramount on optical media.  So,
+         * just make scsi-block operate the same as scsi-generic for them.
+         */
+        if (s->qdev.type != TYPE_ROM) {
+            return scsi_req_alloc(&scsi_disk_dma_reqops, &s->qdev, tag, lun,
+                                  hba_private);
+        }
+    }
+
+    return scsi_req_alloc(&scsi_generic_req_ops, &s->qdev, tag, lun,
+                          hba_private);
+}
+#endif
+
+#define DEFINE_SCSI_DISK_PROPERTIES()                                \
+    DEFINE_BLOCK_PROPERTIES(SCSIDiskState, qdev.conf),               \
+    DEFINE_PROP_STRING("ver", SCSIDiskState, version),               \
+    DEFINE_PROP_STRING("serial", SCSIDiskState, serial),             \
+    DEFINE_PROP_STRING("vendor", SCSIDiskState, vendor),             \
+    DEFINE_PROP_STRING("product", SCSIDiskState, product)
+
+static Property scsi_hd_properties[] = {
+    DEFINE_SCSI_DISK_PROPERTIES(),
+    DEFINE_PROP_BIT("removable", SCSIDiskState, features,
+                    SCSI_DISK_F_REMOVABLE, false),
+    DEFINE_PROP_BIT("dpofua", SCSIDiskState, features,
+                    SCSI_DISK_F_DPOFUA, false),
+    DEFINE_PROP_HEX64("wwn", SCSIDiskState, wwn, 0),
+    DEFINE_BLOCK_CHS_PROPERTIES(SCSIDiskState, qdev.conf),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static const VMStateDescription vmstate_scsi_disk_state = {
+    .name = "scsi-disk",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_SCSI_DEVICE(qdev, SCSIDiskState),
+        VMSTATE_BOOL(media_changed, SCSIDiskState),
+        VMSTATE_BOOL(media_event, SCSIDiskState),
+        VMSTATE_BOOL(eject_request, SCSIDiskState),
+        VMSTATE_BOOL(tray_open, SCSIDiskState),
+        VMSTATE_BOOL(tray_locked, SCSIDiskState),
+        VMSTATE_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;
+    dc->vmsd  = &vmstate_scsi_disk_state;
+}
+
+static const 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_HEX64("wwn", SCSIDiskState, wwn, 0),
+    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;
+    dc->vmsd  = &vmstate_scsi_disk_state;
+}
+
+static const 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_PROP_DRIVE("drive", SCSIDiskState, qdev.conf.bs),
+    DEFINE_PROP_INT32("bootindex", SCSIDiskState, qdev.conf.bootindex, -1),
+    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;
+    dc->vmsd  = &vmstate_scsi_disk_state;
+}
+
+static const 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, features,
+                    SCSI_DISK_F_REMOVABLE, false),
+    DEFINE_PROP_BIT("dpofua", SCSIDiskState, features,
+                    SCSI_DISK_F_DPOFUA, false),
+    DEFINE_PROP_HEX64("wwn", SCSIDiskState, wwn, 0),
+    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;
+    dc->vmsd  = &vmstate_scsi_disk_state;
+}
+
+static const 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_types(void)
+{
+    type_register_static(&scsi_hd_info);
+    type_register_static(&scsi_cd_info);
+#ifdef __linux__
+    type_register_static(&scsi_block_info);
+#endif
+    type_register_static(&scsi_disk_info);
+}
+
+type_init(scsi_disk_register_types)
diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c
new file mode 100644 (file)
index 0000000..2a9a561
--- /dev/null
@@ -0,0 +1,516 @@
+/*
+ * Generic SCSI Device support
+ *
+ * Copyright (c) 2007 Bull S.A.S.
+ * Based on code by Paul Brook
+ * Based on code by Fabrice Bellard
+ *
+ * Written by Laurent Vivier <Laurent.Vivier@bull.net>
+ *
+ * This code is licensed under the LGPL.
+ *
+ */
+
+#include "qemu-common.h"
+#include "qemu/error-report.h"
+#include "hw/scsi/scsi.h"
+#include "sysemu/blockdev.h"
+
+#ifdef __linux__
+
+//#define DEBUG_SCSI
+
+#ifdef DEBUG_SCSI
+#define DPRINTF(fmt, ...) \
+do { printf("scsi-generic: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while(0)
+#endif
+
+#define BADF(fmt, ...) \
+do { fprintf(stderr, "scsi-generic: " fmt , ## __VA_ARGS__); } while (0)
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <scsi/sg.h>
+#include "block/scsi.h"
+
+#define SCSI_SENSE_BUF_SIZE 96
+
+#define SG_ERR_DRIVER_TIMEOUT  0x06
+#define SG_ERR_DRIVER_SENSE    0x08
+
+#define SG_ERR_DID_OK          0x00
+#define SG_ERR_DID_NO_CONNECT  0x01
+#define SG_ERR_DID_BUS_BUSY    0x02
+#define SG_ERR_DID_TIME_OUT    0x03
+
+#ifndef MAX_UINT
+#define MAX_UINT ((unsigned int)-1)
+#endif
+
+typedef struct SCSIGenericReq {
+    SCSIRequest req;
+    uint8_t *buf;
+    int buflen;
+    int len;
+    sg_io_hdr_t io_header;
+} SCSIGenericReq;
+
+static void scsi_generic_save_request(QEMUFile *f, SCSIRequest *req)
+{
+    SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
+
+    qemu_put_sbe32s(f, &r->buflen);
+    if (r->buflen && r->req.cmd.mode == SCSI_XFER_TO_DEV) {
+        assert(!r->req.sg);
+        qemu_put_buffer(f, r->buf, r->req.cmd.xfer);
+    }
+}
+
+static void scsi_generic_load_request(QEMUFile *f, SCSIRequest *req)
+{
+    SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
+
+    qemu_get_sbe32s(f, &r->buflen);
+    if (r->buflen && r->req.cmd.mode == SCSI_XFER_TO_DEV) {
+        assert(!r->req.sg);
+        qemu_get_buffer(f, r->buf, r->req.cmd.xfer);
+    }
+}
+
+static void scsi_free_request(SCSIRequest *req)
+{
+    SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
+
+    g_free(r->buf);
+}
+
+/* Helper function for command completion.  */
+static void scsi_command_complete(void *opaque, int ret)
+{
+    int status;
+    SCSIGenericReq *r = (SCSIGenericReq *)opaque;
+
+    r->req.aiocb = NULL;
+    if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) {
+        r->req.sense_len = r->io_header.sb_len_wr;
+    }
+
+    if (ret != 0) {
+        switch (ret) {
+        case -EDOM:
+            status = TASK_SET_FULL;
+            break;
+        case -ENOMEM:
+            status = CHECK_CONDITION;
+            scsi_req_build_sense(&r->req, SENSE_CODE(TARGET_FAILURE));
+            break;
+        default:
+            status = CHECK_CONDITION;
+            scsi_req_build_sense(&r->req, SENSE_CODE(IO_ERROR));
+            break;
+        }
+    } else {
+        if (r->io_header.host_status == SG_ERR_DID_NO_CONNECT ||
+            r->io_header.host_status == SG_ERR_DID_BUS_BUSY ||
+            r->io_header.host_status == SG_ERR_DID_TIME_OUT ||
+            (r->io_header.driver_status & SG_ERR_DRIVER_TIMEOUT)) {
+            status = BUSY;
+            BADF("Driver Timeout\n");
+        } else if (r->io_header.host_status) {
+            status = CHECK_CONDITION;
+            scsi_req_build_sense(&r->req, SENSE_CODE(I_T_NEXUS_LOSS));
+        } else if (r->io_header.status) {
+            status = r->io_header.status;
+        } else if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) {
+            status = CHECK_CONDITION;
+        } else {
+            status = GOOD;
+        }
+    }
+    DPRINTF("Command complete 0x%p tag=0x%x status=%d\n",
+            r, r->req.tag, status);
+
+    scsi_req_complete(&r->req, status);
+    if (!r->req.io_canceled) {
+        scsi_req_unref(&r->req);
+    }
+}
+
+/* Cancel a pending data transfer.  */
+static void scsi_cancel_io(SCSIRequest *req)
+{
+    SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
+
+    DPRINTF("Cancel tag=0x%x\n", req->tag);
+    if (r->req.aiocb) {
+        bdrv_aio_cancel(r->req.aiocb);
+
+        /* This reference was left in by scsi_*_data.  We take ownership of
+         * it independent of whether bdrv_aio_cancel completes the request
+         * or not.  */
+        scsi_req_unref(&r->req);
+    }
+    r->req.aiocb = NULL;
+}
+
+static int execute_command(BlockDriverState *bdrv,
+                           SCSIGenericReq *r, int direction,
+                          BlockDriverCompletionFunc *complete)
+{
+    r->io_header.interface_id = 'S';
+    r->io_header.dxfer_direction = direction;
+    r->io_header.dxferp = r->buf;
+    r->io_header.dxfer_len = r->buflen;
+    r->io_header.cmdp = r->req.cmd.buf;
+    r->io_header.cmd_len = r->req.cmd.len;
+    r->io_header.mx_sb_len = sizeof(r->req.sense);
+    r->io_header.sbp = r->req.sense;
+    r->io_header.timeout = MAX_UINT;
+    r->io_header.usr_ptr = r;
+    r->io_header.flags |= SG_FLAG_DIRECT_IO;
+
+    r->req.aiocb = bdrv_aio_ioctl(bdrv, SG_IO, &r->io_header, complete, r);
+
+    return 0;
+}
+
+static void scsi_read_complete(void * opaque, int ret)
+{
+    SCSIGenericReq *r = (SCSIGenericReq *)opaque;
+    SCSIDevice *s = r->req.dev;
+    int len;
+
+    r->req.aiocb = NULL;
+    if (ret) {
+        DPRINTF("IO error ret %d\n", ret);
+        scsi_command_complete(r, ret);
+        return;
+    }
+    len = r->io_header.dxfer_len - r->io_header.resid;
+    DPRINTF("Data ready tag=0x%x len=%d\n", r->req.tag, len);
+
+    r->len = -1;
+    if (len == 0) {
+        scsi_command_complete(r, 0);
+    } else {
+        /* Snoop READ CAPACITY output to set the blocksize.  */
+        if (r->req.cmd.buf[0] == READ_CAPACITY_10) {
+            s->blocksize = ldl_be_p(&r->buf[4]);
+            s->max_lba = ldl_be_p(&r->buf[0]);
+        } else if (r->req.cmd.buf[0] == SERVICE_ACTION_IN_16 &&
+                   (r->req.cmd.buf[1] & 31) == SAI_READ_CAPACITY_16) {
+            s->blocksize = ldl_be_p(&r->buf[8]);
+            s->max_lba = ldq_be_p(&r->buf[0]);
+        }
+        bdrv_set_buffer_alignment(s->conf.bs, s->blocksize);
+
+        scsi_req_data(&r->req, len);
+        if (!r->req.io_canceled) {
+            scsi_req_unref(&r->req);
+        }
+    }
+}
+
+/* Read more data from scsi device into buffer.  */
+static void scsi_read_data(SCSIRequest *req)
+{
+    SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
+    SCSIDevice *s = r->req.dev;
+    int ret;
+
+    DPRINTF("scsi_read_data 0x%x\n", req->tag);
+
+    /* The request is used as the AIO opaque value, so add a ref.  */
+    scsi_req_ref(&r->req);
+    if (r->len == -1) {
+        scsi_command_complete(r, 0);
+        return;
+    }
+
+    ret = execute_command(s->conf.bs, r, SG_DXFER_FROM_DEV, scsi_read_complete);
+    if (ret < 0) {
+        scsi_command_complete(r, ret);
+    }
+}
+
+static void scsi_write_complete(void * opaque, int ret)
+{
+    SCSIGenericReq *r = (SCSIGenericReq *)opaque;
+    SCSIDevice *s = r->req.dev;
+
+    DPRINTF("scsi_write_complete() ret = %d\n", ret);
+    r->req.aiocb = NULL;
+    if (ret) {
+        DPRINTF("IO error\n");
+        scsi_command_complete(r, ret);
+        return;
+    }
+
+    if (r->req.cmd.buf[0] == MODE_SELECT && r->req.cmd.buf[4] == 12 &&
+        s->type == TYPE_TAPE) {
+        s->blocksize = (r->buf[9] << 16) | (r->buf[10] << 8) | r->buf[11];
+        DPRINTF("block size %d\n", s->blocksize);
+    }
+
+    scsi_command_complete(r, ret);
+}
+
+/* Write data to a scsi device.  Returns nonzero on failure.
+   The transfer may complete asynchronously.  */
+static void scsi_write_data(SCSIRequest *req)
+{
+    SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
+    SCSIDevice *s = r->req.dev;
+    int ret;
+
+    DPRINTF("scsi_write_data 0x%x\n", req->tag);
+    if (r->len == 0) {
+        r->len = r->buflen;
+        scsi_req_data(&r->req, r->len);
+        return;
+    }
+
+    /* The request is used as the AIO opaque value, so add a ref.  */
+    scsi_req_ref(&r->req);
+    ret = execute_command(s->conf.bs, r, SG_DXFER_TO_DEV, scsi_write_complete);
+    if (ret < 0) {
+        scsi_command_complete(r, ret);
+    }
+}
+
+/* Return a pointer to the data buffer.  */
+static uint8_t *scsi_get_buf(SCSIRequest *req)
+{
+    SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
+
+    return r->buf;
+}
+
+/* Execute a scsi command.  Returns the length of the data expected by the
+   command.  This will be Positive for data transfers from the device
+   (eg. disk reads), negative for transfers to the device (eg. disk writes),
+   and zero if the command does not transfer any data.  */
+
+static int32_t scsi_send_command(SCSIRequest *req, uint8_t *cmd)
+{
+    SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
+    SCSIDevice *s = r->req.dev;
+    int ret;
+
+    DPRINTF("Command: lun=%d tag=0x%x len %zd data=0x%02x", lun, tag,
+            r->req.cmd.xfer, cmd[0]);
+
+#ifdef DEBUG_SCSI
+    {
+        int i;
+        for (i = 1; i < r->req.cmd.len; i++) {
+            printf(" 0x%02x", cmd[i]);
+        }
+        printf("\n");
+    }
+#endif
+
+    if (r->req.cmd.xfer == 0) {
+        if (r->buf != NULL)
+            g_free(r->buf);
+        r->buflen = 0;
+        r->buf = NULL;
+        /* The request is used as the AIO opaque value, so add a ref.  */
+        scsi_req_ref(&r->req);
+        ret = execute_command(s->conf.bs, r, SG_DXFER_NONE, scsi_command_complete);
+        if (ret < 0) {
+            scsi_command_complete(r, ret);
+            return 0;
+        }
+        return 0;
+    }
+
+    if (r->buflen != r->req.cmd.xfer) {
+        if (r->buf != NULL)
+            g_free(r->buf);
+        r->buf = g_malloc(r->req.cmd.xfer);
+        r->buflen = r->req.cmd.xfer;
+    }
+
+    memset(r->buf, 0, r->buflen);
+    r->len = r->req.cmd.xfer;
+    if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
+        r->len = 0;
+        return -r->req.cmd.xfer;
+    } else {
+        return r->req.cmd.xfer;
+    }
+}
+
+static int get_stream_blocksize(BlockDriverState *bdrv)
+{
+    uint8_t cmd[6];
+    uint8_t buf[12];
+    uint8_t sensebuf[8];
+    sg_io_hdr_t io_header;
+    int ret;
+
+    memset(cmd, 0, sizeof(cmd));
+    memset(buf, 0, sizeof(buf));
+    cmd[0] = MODE_SENSE;
+    cmd[4] = sizeof(buf);
+
+    memset(&io_header, 0, sizeof(io_header));
+    io_header.interface_id = 'S';
+    io_header.dxfer_direction = SG_DXFER_FROM_DEV;
+    io_header.dxfer_len = sizeof(buf);
+    io_header.dxferp = buf;
+    io_header.cmdp = cmd;
+    io_header.cmd_len = sizeof(cmd);
+    io_header.mx_sb_len = sizeof(sensebuf);
+    io_header.sbp = sensebuf;
+    io_header.timeout = 6000; /* XXX */
+
+    ret = bdrv_ioctl(bdrv, SG_IO, &io_header);
+    if (ret < 0 || io_header.driver_status || io_header.host_status) {
+        return -1;
+    }
+    return (buf[9] << 16) | (buf[10] << 8) | buf[11];
+}
+
+static void scsi_generic_reset(DeviceState *dev)
+{
+    SCSIDevice *s = SCSI_DEVICE(dev);
+
+    scsi_device_purge_requests(s, SENSE_CODE(RESET));
+}
+
+static void scsi_destroy(SCSIDevice *s)
+{
+    scsi_device_purge_requests(s, SENSE_CODE(NO_SENSE));
+    blockdev_mark_auto_del(s->conf.bs);
+}
+
+static int scsi_generic_initfn(SCSIDevice *s)
+{
+    int sg_version;
+    struct sg_scsi_id scsiid;
+
+    if (!s->conf.bs) {
+        error_report("drive property not set");
+        return -1;
+    }
+
+    if (bdrv_get_on_error(s->conf.bs, 0) != BLOCKDEV_ON_ERROR_ENOSPC) {
+        error_report("Device doesn't support drive option werror");
+        return -1;
+    }
+    if (bdrv_get_on_error(s->conf.bs, 1) != BLOCKDEV_ON_ERROR_REPORT) {
+        error_report("Device doesn't support drive option rerror");
+        return -1;
+    }
+
+    /* check we are using a driver managing SG_IO (version 3 and after */
+    if (bdrv_ioctl(s->conf.bs, SG_GET_VERSION_NUM, &sg_version) < 0) {
+        error_report("scsi generic interface not supported");
+        return -1;
+    }
+    if (sg_version < 30000) {
+        error_report("scsi generic interface too old");
+        return -1;
+    }
+
+    /* get LUN of the /dev/sg? */
+    if (bdrv_ioctl(s->conf.bs, SG_GET_SCSI_ID, &scsiid)) {
+        error_report("SG_GET_SCSI_ID ioctl failed");
+        return -1;
+    }
+
+    /* define device state */
+    s->type = scsiid.scsi_type;
+    DPRINTF("device type %d\n", s->type);
+    if (s->type == TYPE_DISK || s->type == TYPE_ROM) {
+        add_boot_device_path(s->conf.bootindex, &s->qdev, NULL);
+    }
+
+    switch (s->type) {
+    case TYPE_TAPE:
+        s->blocksize = get_stream_blocksize(s->conf.bs);
+        if (s->blocksize == -1) {
+            s->blocksize = 0;
+        }
+        break;
+
+        /* Make a guess for block devices, we'll fix it when the guest sends.
+         * READ CAPACITY.  If they don't, they likely would assume these sizes
+         * anyway. (TODO: they could also send MODE SENSE).
+         */
+    case TYPE_ROM:
+    case TYPE_WORM:
+        s->blocksize = 2048;
+        break;
+    default:
+        s->blocksize = 512;
+        break;
+    }
+
+    DPRINTF("block size %d\n", s->blocksize);
+    return 0;
+}
+
+const SCSIReqOps scsi_generic_req_ops = {
+    .size         = sizeof(SCSIGenericReq),
+    .free_req     = scsi_free_request,
+    .send_command = scsi_send_command,
+    .read_data    = scsi_read_data,
+    .write_data   = scsi_write_data,
+    .cancel_io    = scsi_cancel_io,
+    .get_buf      = scsi_get_buf,
+    .load_request = scsi_generic_load_request,
+    .save_request = scsi_generic_save_request,
+};
+
+static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun,
+                                     uint8_t *buf, void *hba_private)
+{
+    SCSIRequest *req;
+
+    req = scsi_req_alloc(&scsi_generic_req_ops, d, tag, lun, hba_private);
+    return req;
+}
+
+static Property scsi_generic_properties[] = {
+    DEFINE_PROP_DRIVE("drive", SCSIDevice, conf.bs),
+    DEFINE_PROP_INT32("bootindex", SCSIDevice, conf.bootindex, -1),
+    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;
+    dc->vmsd  = &vmstate_scsi_device;
+}
+
+static const 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_types(void)
+{
+    type_register_static(&scsi_generic_info);
+}
+
+type_init(scsi_generic_register_types)
+
+#endif /* __linux__ */
diff --git a/hw/scsi/spapr_vscsi.c b/hw/scsi/spapr_vscsi.c
new file mode 100644 (file)
index 0000000..999a463
--- /dev/null
@@ -0,0 +1,982 @@
+/*
+ * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator
+ *
+ * PAPR Virtual SCSI, aka ibmvscsi
+ *
+ * Copyright (c) 2010,2011 Benjamin Herrenschmidt, IBM Corporation.
+ *
+ * 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.
+ *
+ * TODO:
+ *
+ *  - Cleanups :-)
+ *  - Sort out better how to assign devices to VSCSI instances
+ *  - Fix residual counts
+ *  - Add indirect descriptors support
+ *  - Maybe do autosense (PAPR seems to mandate it, linux doesn't care)
+ */
+#include "hw/hw.h"
+#include "hw/scsi/scsi.h"
+#include "block/scsi.h"
+#include "srp.h"
+#include "hw/qdev.h"
+#include "hw/ppc/spapr.h"
+#include "hw/ppc/spapr_vio.h"
+#include "viosrp.h"
+
+#include <libfdt.h>
+
+/*#define DEBUG_VSCSI*/
+
+#ifdef DEBUG_VSCSI
+#define dprintf(fmt, ...) \
+    do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
+#else
+#define dprintf(fmt, ...) \
+    do { } while (0)
+#endif
+
+/*
+ * Virtual SCSI device
+ */
+
+/* Random numbers */
+#define VSCSI_MAX_SECTORS       4096
+#define VSCSI_REQ_LIMIT         24
+
+#define SCSI_SENSE_BUF_SIZE     96
+#define SRP_RSP_SENSE_DATA_LEN  18
+
+typedef union vscsi_crq {
+    struct viosrp_crq s;
+    uint8_t raw[16];
+} vscsi_crq;
+
+typedef struct vscsi_req {
+    vscsi_crq               crq;
+    union viosrp_iu         iu;
+
+    /* SCSI request tracking */
+    SCSIRequest             *sreq;
+    uint32_t                qtag; /* qemu tag != srp tag */
+    int                     lun;
+    int                     active;
+    long                    data_len;
+    int                     writing;
+    int                     senselen;
+    uint8_t                 sense[SCSI_SENSE_BUF_SIZE];
+
+    /* RDMA related bits */
+    uint8_t                 dma_fmt;
+    struct srp_direct_buf   ext_desc;
+    struct srp_direct_buf   *cur_desc;
+    struct srp_indirect_buf *ind_desc;
+    int                     local_desc;
+    int                     total_desc;
+} vscsi_req;
+
+
+typedef struct {
+    VIOsPAPRDevice vdev;
+    SCSIBus bus;
+    vscsi_req reqs[VSCSI_REQ_LIMIT];
+} VSCSIState;
+
+static struct vscsi_req *vscsi_get_req(VSCSIState *s)
+{
+    vscsi_req *req;
+    int i;
+
+    for (i = 0; i < VSCSI_REQ_LIMIT; i++) {
+        req = &s->reqs[i];
+        if (!req->active) {
+            memset(req, 0, sizeof(*req));
+            req->qtag = i;
+            req->active = 1;
+            return req;
+        }
+    }
+    return NULL;
+}
+
+static void vscsi_put_req(vscsi_req *req)
+{
+    if (req->sreq != NULL) {
+        scsi_req_unref(req->sreq);
+    }
+    req->sreq = NULL;
+    req->active = 0;
+}
+
+static SCSIDevice *vscsi_device_find(SCSIBus *bus, uint64_t srp_lun, int *lun)
+{
+    int channel = 0, id = 0;
+
+retry:
+    switch (srp_lun >> 62) {
+    case 0:
+        if ((srp_lun >> 56) != 0) {
+            channel = (srp_lun >> 56) & 0x3f;
+            id = (srp_lun >> 48) & 0xff;
+            srp_lun <<= 16;
+            goto retry;
+        }
+        *lun = (srp_lun >> 48) & 0xff;
+        break;
+
+    case 1:
+        *lun = (srp_lun >> 48) & 0x3fff;
+        break;
+    case 2:
+        channel = (srp_lun >> 53) & 0x7;
+        id = (srp_lun >> 56) & 0x3f;
+        *lun = (srp_lun >> 48) & 0x1f;
+        break;
+    case 3:
+        *lun = -1;
+        return NULL;
+    default:
+        abort();
+    }
+
+    return scsi_device_find(bus, channel, id, *lun);
+}
+
+static int vscsi_send_iu(VSCSIState *s, vscsi_req *req,
+                         uint64_t length, uint8_t format)
+{
+    long rc, rc1;
+
+    /* First copy the SRP */
+    rc = spapr_vio_dma_write(&s->vdev, req->crq.s.IU_data_ptr,
+                             &req->iu, length);
+    if (rc) {
+        fprintf(stderr, "vscsi_send_iu: DMA write failure !\n");
+    }
+
+    req->crq.s.valid = 0x80;
+    req->crq.s.format = format;
+    req->crq.s.reserved = 0x00;
+    req->crq.s.timeout = cpu_to_be16(0x0000);
+    req->crq.s.IU_length = cpu_to_be16(length);
+    req->crq.s.IU_data_ptr = req->iu.srp.rsp.tag; /* right byte order */
+
+    if (rc == 0) {
+        req->crq.s.status = 0x99; /* Just needs to be non-zero */
+    } else {
+        req->crq.s.status = 0x00;
+    }
+
+    rc1 = spapr_vio_send_crq(&s->vdev, req->crq.raw);
+    if (rc1) {
+        fprintf(stderr, "vscsi_send_iu: Error sending response\n");
+        return rc1;
+    }
+
+    return rc;
+}
+
+static void vscsi_makeup_sense(VSCSIState *s, vscsi_req *req,
+                               uint8_t key, uint8_t asc, uint8_t ascq)
+{
+    req->senselen = SRP_RSP_SENSE_DATA_LEN;
+
+    /* Valid bit and 'current errors' */
+    req->sense[0] = (0x1 << 7 | 0x70);
+    /* Sense key */
+    req->sense[2] = key;
+    /* Additional sense length */
+    req->sense[7] = 0xa; /* 10 bytes */
+    /* Additional sense code */
+    req->sense[12] = asc;
+    req->sense[13] = ascq;
+}
+
+static int vscsi_send_rsp(VSCSIState *s, vscsi_req *req,
+                          uint8_t status, int32_t res_in, int32_t res_out)
+{
+    union viosrp_iu *iu = &req->iu;
+    uint64_t tag = iu->srp.rsp.tag;
+    int total_len = sizeof(iu->srp.rsp);
+
+    dprintf("VSCSI: Sending resp status: 0x%x, "
+            "res_in: %d, res_out: %d\n", status, res_in, res_out);
+
+    memset(iu, 0, sizeof(struct srp_rsp));
+    iu->srp.rsp.opcode = SRP_RSP;
+    iu->srp.rsp.req_lim_delta = cpu_to_be32(1);
+    iu->srp.rsp.tag = tag;
+
+    /* Handle residuals */
+    if (res_in < 0) {
+        iu->srp.rsp.flags |= SRP_RSP_FLAG_DIUNDER;
+        res_in = -res_in;
+    } else if (res_in) {
+        iu->srp.rsp.flags |= SRP_RSP_FLAG_DIOVER;
+    }
+    if (res_out < 0) {
+        iu->srp.rsp.flags |= SRP_RSP_FLAG_DOUNDER;
+        res_out = -res_out;
+    } else if (res_out) {
+        iu->srp.rsp.flags |= SRP_RSP_FLAG_DOOVER;
+    }
+    iu->srp.rsp.data_in_res_cnt = cpu_to_be32(res_in);
+    iu->srp.rsp.data_out_res_cnt = cpu_to_be32(res_out);
+
+    /* We don't do response data */
+    /* iu->srp.rsp.flags &= ~SRP_RSP_FLAG_RSPVALID; */
+    iu->srp.rsp.resp_data_len = cpu_to_be32(0);
+
+    /* Handle success vs. failure */
+    iu->srp.rsp.status = status;
+    if (status) {
+        iu->srp.rsp.sol_not = (iu->srp.cmd.sol_not & 0x04) >> 2;
+        if (req->senselen) {
+            req->iu.srp.rsp.flags |= SRP_RSP_FLAG_SNSVALID;
+            req->iu.srp.rsp.sense_data_len = cpu_to_be32(req->senselen);
+            memcpy(req->iu.srp.rsp.data, req->sense, req->senselen);
+            total_len += req->senselen;
+        }
+    } else {
+        iu->srp.rsp.sol_not = (iu->srp.cmd.sol_not & 0x02) >> 1;
+    }
+
+    vscsi_send_iu(s, req, total_len, VIOSRP_SRP_FORMAT);
+    return 0;
+}
+
+static inline void vscsi_swap_desc(struct srp_direct_buf *desc)
+{
+    desc->va = be64_to_cpu(desc->va);
+    desc->len = be32_to_cpu(desc->len);
+}
+
+static int vscsi_srp_direct_data(VSCSIState *s, vscsi_req *req,
+                                 uint8_t *buf, uint32_t len)
+{
+    struct srp_direct_buf *md = req->cur_desc;
+    uint32_t llen;
+    int rc = 0;
+
+    dprintf("VSCSI: direct segment 0x%x bytes, va=0x%llx desc len=0x%x\n",
+            len, (unsigned long long)md->va, md->len);
+
+    llen = MIN(len, md->len);
+    if (llen) {
+        if (req->writing) { /* writing = to device = reading from memory */
+            rc = spapr_vio_dma_read(&s->vdev, md->va, buf, llen);
+        } else {
+            rc = spapr_vio_dma_write(&s->vdev, md->va, buf, llen);
+        }
+    }
+    md->len -= llen;
+    md->va += llen;
+
+    if (rc) {
+        return -1;
+    }
+    return llen;
+}
+
+static int vscsi_srp_indirect_data(VSCSIState *s, vscsi_req *req,
+                                   uint8_t *buf, uint32_t len)
+{
+    struct srp_direct_buf *td = &req->ind_desc->table_desc;
+    struct srp_direct_buf *md = req->cur_desc;
+    int rc = 0;
+    uint32_t llen, total = 0;
+
+    dprintf("VSCSI: indirect segment 0x%x bytes, td va=0x%llx len=0x%x\n",
+            len, (unsigned long long)td->va, td->len);
+
+    /* While we have data ... */
+    while (len) {
+        /* If we have a descriptor but it's empty, go fetch a new one */
+        if (md && md->len == 0) {
+            /* More local available, use one */
+            if (req->local_desc) {
+                md = ++req->cur_desc;
+                --req->local_desc;
+                --req->total_desc;
+                td->va += sizeof(struct srp_direct_buf);
+            } else {
+                md = req->cur_desc = NULL;
+            }
+        }
+        /* No descriptor at hand, fetch one */
+        if (!md) {
+            if (!req->total_desc) {
+                dprintf("VSCSI:   Out of descriptors !\n");
+                break;
+            }
+            md = req->cur_desc = &req->ext_desc;
+            dprintf("VSCSI:   Reading desc from 0x%llx\n",
+                    (unsigned long long)td->va);
+            rc = spapr_vio_dma_read(&s->vdev, td->va, md,
+                                    sizeof(struct srp_direct_buf));
+            if (rc) {
+                dprintf("VSCSI: spapr_vio_dma_read -> %d reading ext_desc\n",
+                        rc);
+                break;
+            }
+            vscsi_swap_desc(md);
+            td->va += sizeof(struct srp_direct_buf);
+            --req->total_desc;
+        }
+        dprintf("VSCSI:   [desc va=0x%llx,len=0x%x] remaining=0x%x\n",
+                (unsigned long long)md->va, md->len, len);
+
+        /* Perform transfer */
+        llen = MIN(len, md->len);
+        if (req->writing) { /* writing = to device = reading from memory */
+            rc = spapr_vio_dma_read(&s->vdev, md->va, buf, llen);
+        } else {
+            rc = spapr_vio_dma_write(&s->vdev, md->va, buf, llen);
+        }
+        if (rc) {
+            dprintf("VSCSI: spapr_vio_dma_r/w(%d) -> %d\n", req->writing, rc);
+            break;
+        }
+        dprintf("VSCSI:     data: %02x %02x %02x %02x...\n",
+                buf[0], buf[1], buf[2], buf[3]);
+
+        len -= llen;
+        buf += llen;
+        total += llen;
+        md->va += llen;
+        md->len -= llen;
+    }
+    return rc ? -1 : total;
+}
+
+static int vscsi_srp_transfer_data(VSCSIState *s, vscsi_req *req,
+                                   int writing, uint8_t *buf, uint32_t len)
+{
+    int err = 0;
+
+    switch (req->dma_fmt) {
+    case SRP_NO_DATA_DESC:
+        dprintf("VSCSI: no data desc transfer, skipping 0x%x bytes\n", len);
+        break;
+    case SRP_DATA_DESC_DIRECT:
+        err = vscsi_srp_direct_data(s, req, buf, len);
+        break;
+    case SRP_DATA_DESC_INDIRECT:
+        err = vscsi_srp_indirect_data(s, req, buf, len);
+        break;
+    }
+    return err;
+}
+
+/* Bits from linux srp */
+static int data_out_desc_size(struct srp_cmd *cmd)
+{
+    int size = 0;
+    uint8_t fmt = cmd->buf_fmt >> 4;
+
+    switch (fmt) {
+    case SRP_NO_DATA_DESC:
+        break;
+    case SRP_DATA_DESC_DIRECT:
+        size = sizeof(struct srp_direct_buf);
+        break;
+    case SRP_DATA_DESC_INDIRECT:
+        size = sizeof(struct srp_indirect_buf) +
+            sizeof(struct srp_direct_buf)*cmd->data_out_desc_cnt;
+        break;
+    default:
+        break;
+    }
+    return size;
+}
+
+static int vscsi_preprocess_desc(vscsi_req *req)
+{
+    struct srp_cmd *cmd = &req->iu.srp.cmd;
+    int offset, i;
+
+    offset = cmd->add_cdb_len & ~3;
+
+    if (req->writing) {
+        req->dma_fmt = cmd->buf_fmt >> 4;
+    } else {
+        offset += data_out_desc_size(cmd);
+        req->dma_fmt = cmd->buf_fmt & ((1U << 4) - 1);
+    }
+
+    switch (req->dma_fmt) {
+    case SRP_NO_DATA_DESC:
+        break;
+    case SRP_DATA_DESC_DIRECT:
+        req->cur_desc = (struct srp_direct_buf *)(cmd->add_data + offset);
+        req->total_desc = req->local_desc = 1;
+        vscsi_swap_desc(req->cur_desc);
+        dprintf("VSCSI: using direct RDMA %s, 0x%x bytes MD: 0x%llx\n",
+                req->writing ? "write" : "read",
+                req->cur_desc->len, (unsigned long long)req->cur_desc->va);
+        break;
+    case SRP_DATA_DESC_INDIRECT:
+        req->ind_desc = (struct srp_indirect_buf *)(cmd->add_data + offset);
+        vscsi_swap_desc(&req->ind_desc->table_desc);
+        req->total_desc = req->ind_desc->table_desc.len /
+            sizeof(struct srp_direct_buf);
+        req->local_desc = req->writing ? cmd->data_out_desc_cnt :
+            cmd->data_in_desc_cnt;
+        for (i = 0; i < req->local_desc; i++) {
+            vscsi_swap_desc(&req->ind_desc->desc_list[i]);
+        }
+        req->cur_desc = req->local_desc ? &req->ind_desc->desc_list[0] : NULL;
+        dprintf("VSCSI: using indirect RDMA %s, 0x%x bytes %d descs "
+                "(%d local) VA: 0x%llx\n",
+                req->writing ? "read" : "write",
+                be32_to_cpu(req->ind_desc->len),
+                req->total_desc, req->local_desc,
+                (unsigned long long)req->ind_desc->table_desc.va);
+        break;
+    default:
+        fprintf(stderr,
+                "vscsi_preprocess_desc: Unknown format %x\n", req->dma_fmt);
+        return -1;
+    }
+
+    return 0;
+}
+
+/* Callback to indicate that the SCSI layer has completed a transfer.  */
+static void vscsi_transfer_data(SCSIRequest *sreq, uint32_t len)
+{
+    VSCSIState *s = DO_UPCAST(VSCSIState, vdev.qdev, sreq->bus->qbus.parent);
+    vscsi_req *req = sreq->hba_private;
+    uint8_t *buf;
+    int rc = 0;
+
+    dprintf("VSCSI: SCSI xfer complete tag=0x%x len=0x%x, req=%p\n",
+            sreq->tag, len, req);
+    if (req == NULL) {
+        fprintf(stderr, "VSCSI: Can't find request for tag 0x%x\n", sreq->tag);
+        return;
+    }
+
+    if (len) {
+        buf = scsi_req_get_buf(sreq);
+        rc = vscsi_srp_transfer_data(s, req, req->writing, buf, len);
+    }
+    if (rc < 0) {
+        fprintf(stderr, "VSCSI: RDMA error rc=%d!\n", rc);
+        vscsi_makeup_sense(s, req, HARDWARE_ERROR, 0, 0);
+        scsi_req_abort(req->sreq, CHECK_CONDITION);
+        return;
+    }
+
+    /* Start next chunk */
+    req->data_len -= rc;
+    scsi_req_continue(sreq);
+}
+
+/* Callback to indicate that the SCSI layer has completed a transfer.  */
+static void vscsi_command_complete(SCSIRequest *sreq, uint32_t status, size_t resid)
+{
+    VSCSIState *s = DO_UPCAST(VSCSIState, vdev.qdev, sreq->bus->qbus.parent);
+    vscsi_req *req = sreq->hba_private;
+    int32_t res_in = 0, res_out = 0;
+
+    dprintf("VSCSI: SCSI cmd complete, r=0x%x tag=0x%x status=0x%x, req=%p\n",
+            reason, sreq->tag, status, req);
+    if (req == NULL) {
+        fprintf(stderr, "VSCSI: Can't find request for tag 0x%x\n", sreq->tag);
+        return;
+    }
+
+    if (status == CHECK_CONDITION) {
+        req->senselen = scsi_req_get_sense(req->sreq, req->sense,
+                                           sizeof(req->sense));
+        dprintf("VSCSI: Sense data, %d bytes:\n", len);
+        dprintf("       %02x  %02x  %02x  %02x  %02x  %02x  %02x  %02x\n",
+                req->sense[0], req->sense[1], req->sense[2], req->sense[3],
+                req->sense[4], req->sense[5], req->sense[6], req->sense[7]);
+        dprintf("       %02x  %02x  %02x  %02x  %02x  %02x  %02x  %02x\n",
+                req->sense[8], req->sense[9], req->sense[10], req->sense[11],
+                req->sense[12], req->sense[13], req->sense[14], req->sense[15]);
+    }
+
+    dprintf("VSCSI: Command complete err=%d\n", status);
+    if (status == 0) {
+        /* We handle overflows, not underflows for normal commands,
+         * but hopefully nobody cares
+         */
+        if (req->writing) {
+            res_out = req->data_len;
+        } else {
+            res_in = req->data_len;
+        }
+    }
+    vscsi_send_rsp(s, req, status, res_in, res_out);
+    vscsi_put_req(req);
+}
+
+static void vscsi_request_cancelled(SCSIRequest *sreq)
+{
+    vscsi_req *req = sreq->hba_private;
+
+    vscsi_put_req(req);
+}
+
+static void vscsi_process_login(VSCSIState *s, vscsi_req *req)
+{
+    union viosrp_iu *iu = &req->iu;
+    struct srp_login_rsp *rsp = &iu->srp.login_rsp;
+    uint64_t tag = iu->srp.rsp.tag;
+
+    dprintf("VSCSI: Got login, sendin response !\n");
+
+    /* TODO handle case that requested size is wrong and
+     * buffer format is wrong
+     */
+    memset(iu, 0, sizeof(struct srp_login_rsp));
+    rsp->opcode = SRP_LOGIN_RSP;
+    /* Don't advertise quite as many request as we support to
+     * keep room for management stuff etc...
+     */
+    rsp->req_lim_delta = cpu_to_be32(VSCSI_REQ_LIMIT-2);
+    rsp->tag = tag;
+    rsp->max_it_iu_len = cpu_to_be32(sizeof(union srp_iu));
+    rsp->max_ti_iu_len = cpu_to_be32(sizeof(union srp_iu));
+    /* direct and indirect */
+    rsp->buf_fmt = cpu_to_be16(SRP_BUF_FORMAT_DIRECT | SRP_BUF_FORMAT_INDIRECT);
+
+    vscsi_send_iu(s, req, sizeof(*rsp), VIOSRP_SRP_FORMAT);
+}
+
+static void vscsi_inquiry_no_target(VSCSIState *s, vscsi_req *req)
+{
+    uint8_t *cdb = req->iu.srp.cmd.cdb;
+    uint8_t resp_data[36];
+    int rc, len, alen;
+
+    /* We dont do EVPD. Also check that page_code is 0 */
+    if ((cdb[1] & 0x01) || (cdb[1] & 0x01) || cdb[2] != 0) {
+        /* Send INVALID FIELD IN CDB */
+        vscsi_makeup_sense(s, req, ILLEGAL_REQUEST, 0x24, 0);
+        vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0);
+        return;
+    }
+    alen = cdb[3];
+    alen = (alen << 8) | cdb[4];
+    len = MIN(alen, 36);
+
+    /* Fake up inquiry using PQ=3 */
+    memset(resp_data, 0, 36);
+    resp_data[0] = 0x7f;   /* Not capable of supporting a device here */
+    resp_data[2] = 0x06;   /* SPS-4 */
+    resp_data[3] = 0x02;   /* Resp data format */
+    resp_data[4] = 36 - 5; /* Additional length */
+    resp_data[7] = 0x10;   /* Sync transfers */
+    memcpy(&resp_data[16], "QEMU EMPTY      ", 16);
+    memcpy(&resp_data[8], "QEMU    ", 8);
+
+    req->writing = 0;
+    vscsi_preprocess_desc(req);
+    rc = vscsi_srp_transfer_data(s, req, 0, resp_data, len);
+    if (rc < 0) {
+        vscsi_makeup_sense(s, req, HARDWARE_ERROR, 0, 0);
+        vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0);
+    } else {
+        vscsi_send_rsp(s, req, 0, 36 - rc, 0);
+    }
+}
+
+static int vscsi_queue_cmd(VSCSIState *s, vscsi_req *req)
+{
+    union srp_iu *srp = &req->iu.srp;
+    SCSIDevice *sdev;
+    int n, lun;
+
+    sdev = vscsi_device_find(&s->bus, be64_to_cpu(srp->cmd.lun), &lun);
+    if (!sdev) {
+        dprintf("VSCSI: Command for lun %08" PRIx64 " with no drive\n", be64_to_cpu(srp->cmd.lun));
+        if (srp->cmd.cdb[0] == INQUIRY) {
+            vscsi_inquiry_no_target(s, req);
+        } else {
+            vscsi_makeup_sense(s, req, ILLEGAL_REQUEST, 0x24, 0x00);
+            vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0);
+        } return 1;
+    }
+
+    req->lun = lun;
+    req->sreq = scsi_req_new(sdev, req->qtag, lun, srp->cmd.cdb, req);
+    n = scsi_req_enqueue(req->sreq);
+
+    dprintf("VSCSI: Queued command tag 0x%x CMD 0x%x ID %d LUN %d ret: %d\n",
+            req->qtag, srp->cmd.cdb[0], id, lun, n);
+
+    if (n) {
+        /* Transfer direction must be set before preprocessing the
+         * descriptors
+         */
+        req->writing = (n < 1);
+
+        /* Preprocess RDMA descriptors */
+        vscsi_preprocess_desc(req);
+
+        /* Get transfer direction and initiate transfer */
+        if (n > 0) {
+            req->data_len = n;
+        } else if (n < 0) {
+            req->data_len = -n;
+        }
+        scsi_req_continue(req->sreq);
+    }
+    /* Don't touch req here, it may have been recycled already */
+
+    return 0;
+}
+
+static int vscsi_process_tsk_mgmt(VSCSIState *s, vscsi_req *req)
+{
+    union viosrp_iu *iu = &req->iu;
+    int fn;
+
+    fprintf(stderr, "vscsi_process_tsk_mgmt %02x\n",
+            iu->srp.tsk_mgmt.tsk_mgmt_func);
+
+    switch (iu->srp.tsk_mgmt.tsk_mgmt_func) {
+#if 0 /* We really don't deal with these for now */
+    case SRP_TSK_ABORT_TASK:
+        fn = ABORT_TASK;
+        break;
+    case SRP_TSK_ABORT_TASK_SET:
+        fn = ABORT_TASK_SET;
+        break;
+    case SRP_TSK_CLEAR_TASK_SET:
+        fn = CLEAR_TASK_SET;
+        break;
+    case SRP_TSK_LUN_RESET:
+        fn = LOGICAL_UNIT_RESET;
+        break;
+    case SRP_TSK_CLEAR_ACA:
+        fn = CLEAR_ACA;
+        break;
+#endif
+    default:
+        fn = 0;
+    }
+    if (fn) {
+        /* XXX Send/Handle target task management */
+        ;
+    } else {
+        vscsi_makeup_sense(s, req, ILLEGAL_REQUEST, 0x20, 0);
+        vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0);
+    }
+    return !fn;
+}
+
+static int vscsi_handle_srp_req(VSCSIState *s, vscsi_req *req)
+{
+    union srp_iu *srp = &req->iu.srp;
+    int done = 1;
+    uint8_t opcode = srp->rsp.opcode;
+
+    switch (opcode) {
+    case SRP_LOGIN_REQ:
+        vscsi_process_login(s, req);
+        break;
+    case SRP_TSK_MGMT:
+        done = vscsi_process_tsk_mgmt(s, req);
+        break;
+    case SRP_CMD:
+        done = vscsi_queue_cmd(s, req);
+        break;
+    case SRP_LOGIN_RSP:
+    case SRP_I_LOGOUT:
+    case SRP_T_LOGOUT:
+    case SRP_RSP:
+    case SRP_CRED_REQ:
+    case SRP_CRED_RSP:
+    case SRP_AER_REQ:
+    case SRP_AER_RSP:
+        fprintf(stderr, "VSCSI: Unsupported opcode %02x\n", opcode);
+        break;
+    default:
+        fprintf(stderr, "VSCSI: Unknown type %02x\n", opcode);
+    }
+
+    return done;
+}
+
+static int vscsi_send_adapter_info(VSCSIState *s, vscsi_req *req)
+{
+    struct viosrp_adapter_info *sinfo;
+    struct mad_adapter_info_data info;
+    int rc;
+
+    sinfo = &req->iu.mad.adapter_info;
+
+#if 0 /* What for ? */
+    rc = spapr_vio_dma_read(&s->vdev, be64_to_cpu(sinfo->buffer),
+                            &info, be16_to_cpu(sinfo->common.length));
+    if (rc) {
+        fprintf(stderr, "vscsi_send_adapter_info: DMA read failure !\n");
+    }
+#endif
+    memset(&info, 0, sizeof(info));
+    strcpy(info.srp_version, SRP_VERSION);
+    memcpy(info.partition_name, "qemu", sizeof("qemu"));
+    info.partition_number = cpu_to_be32(0);
+    info.mad_version = cpu_to_be32(1);
+    info.os_type = cpu_to_be32(2);
+    info.port_max_txu[0] = cpu_to_be32(VSCSI_MAX_SECTORS << 9);
+
+    rc = spapr_vio_dma_write(&s->vdev, be64_to_cpu(sinfo->buffer),
+                             &info, be16_to_cpu(sinfo->common.length));
+    if (rc)  {
+        fprintf(stderr, "vscsi_send_adapter_info: DMA write failure !\n");
+    }
+
+    sinfo->common.status = rc ? cpu_to_be32(1) : 0;
+
+    return vscsi_send_iu(s, req, sizeof(*sinfo), VIOSRP_MAD_FORMAT);
+}
+
+static int vscsi_handle_mad_req(VSCSIState *s, vscsi_req *req)
+{
+    union mad_iu *mad = &req->iu.mad;
+
+    switch (be32_to_cpu(mad->empty_iu.common.type)) {
+    case VIOSRP_EMPTY_IU_TYPE:
+        fprintf(stderr, "Unsupported EMPTY MAD IU\n");
+        break;
+    case VIOSRP_ERROR_LOG_TYPE:
+        fprintf(stderr, "Unsupported ERROR LOG MAD IU\n");
+        mad->error_log.common.status = cpu_to_be16(1);
+        vscsi_send_iu(s, req, sizeof(mad->error_log), VIOSRP_MAD_FORMAT);
+        break;
+    case VIOSRP_ADAPTER_INFO_TYPE:
+        vscsi_send_adapter_info(s, req);
+        break;
+    case VIOSRP_HOST_CONFIG_TYPE:
+        mad->host_config.common.status = cpu_to_be16(1);
+        vscsi_send_iu(s, req, sizeof(mad->host_config), VIOSRP_MAD_FORMAT);
+        break;
+    default:
+        fprintf(stderr, "VSCSI: Unknown MAD type %02x\n",
+                be32_to_cpu(mad->empty_iu.common.type));
+    }
+
+    return 1;
+}
+
+static void vscsi_got_payload(VSCSIState *s, vscsi_crq *crq)
+{
+    vscsi_req *req;
+    int done;
+
+    req = vscsi_get_req(s);
+    if (req == NULL) {
+        fprintf(stderr, "VSCSI: Failed to get a request !\n");
+        return;
+    }
+
+    /* We only support a limited number of descriptors, we know
+     * the ibmvscsi driver uses up to 10 max, so it should fit
+     * in our 256 bytes IUs. If not we'll have to increase the size
+     * of the structure.
+     */
+    if (crq->s.IU_length > sizeof(union viosrp_iu)) {
+        fprintf(stderr, "VSCSI: SRP IU too long (%d bytes) !\n",
+                crq->s.IU_length);
+        vscsi_put_req(req);
+        return;
+    }
+
+    /* XXX Handle failure differently ? */
+    if (spapr_vio_dma_read(&s->vdev, crq->s.IU_data_ptr, &req->iu,
+                           crq->s.IU_length)) {
+        fprintf(stderr, "vscsi_got_payload: DMA read failure !\n");
+        vscsi_put_req(req);
+        return;
+    }
+    memcpy(&req->crq, crq, sizeof(vscsi_crq));
+
+    if (crq->s.format == VIOSRP_MAD_FORMAT) {
+        done = vscsi_handle_mad_req(s, req);
+    } else {
+        done = vscsi_handle_srp_req(s, req);
+    }
+
+    if (done) {
+        vscsi_put_req(req);
+    }
+}
+
+
+static int vscsi_do_crq(struct VIOsPAPRDevice *dev, uint8_t *crq_data)
+{
+    VSCSIState *s = DO_UPCAST(VSCSIState, vdev, dev);
+    vscsi_crq crq;
+
+    memcpy(crq.raw, crq_data, 16);
+    crq.s.timeout = be16_to_cpu(crq.s.timeout);
+    crq.s.IU_length = be16_to_cpu(crq.s.IU_length);
+    crq.s.IU_data_ptr = be64_to_cpu(crq.s.IU_data_ptr);
+
+    dprintf("VSCSI: do_crq %02x %02x ...\n", crq.raw[0], crq.raw[1]);
+
+    switch (crq.s.valid) {
+    case 0xc0: /* Init command/response */
+
+        /* Respond to initialization request */
+        if (crq.s.format == 0x01) {
+            memset(crq.raw, 0, 16);
+            crq.s.valid = 0xc0;
+            crq.s.format = 0x02;
+            spapr_vio_send_crq(dev, crq.raw);
+        }
+
+        /* Note that in hotplug cases, we might get a 0x02
+         * as a result of us emitting the init request
+         */
+
+        break;
+    case 0xff: /* Link event */
+
+        /* Not handled for now */
+
+        break;
+    case 0x80: /* Payloads */
+        switch (crq.s.format) {
+        case VIOSRP_SRP_FORMAT: /* AKA VSCSI request */
+        case VIOSRP_MAD_FORMAT: /* AKA VSCSI response */
+            vscsi_got_payload(s, &crq);
+            break;
+        case VIOSRP_OS400_FORMAT:
+        case VIOSRP_AIX_FORMAT:
+        case VIOSRP_LINUX_FORMAT:
+        case VIOSRP_INLINE_FORMAT:
+            fprintf(stderr, "vscsi_do_srq: Unsupported payload format %02x\n",
+                    crq.s.format);
+            break;
+        default:
+            fprintf(stderr, "vscsi_do_srq: Unknown payload format %02x\n",
+                    crq.s.format);
+        }
+        break;
+    default:
+        fprintf(stderr, "vscsi_do_crq: unknown CRQ %02x %02x ...\n",
+                crq.raw[0], crq.raw[1]);
+    };
+
+    return 0;
+}
+
+static const struct SCSIBusInfo vscsi_scsi_info = {
+    .tcq = true,
+    .max_channel = 7, /* logical unit addressing format */
+    .max_target = 63,
+    .max_lun = 31,
+
+    .transfer_data = vscsi_transfer_data,
+    .complete = vscsi_command_complete,
+    .cancel = vscsi_request_cancelled
+};
+
+static void spapr_vscsi_reset(VIOsPAPRDevice *dev)
+{
+    VSCSIState *s = DO_UPCAST(VSCSIState, vdev, dev);
+    int i;
+
+    memset(s->reqs, 0, sizeof(s->reqs));
+    for (i = 0; i < VSCSI_REQ_LIMIT; i++) {
+        s->reqs[i].qtag = i;
+    }
+}
+
+static int spapr_vscsi_init(VIOsPAPRDevice *dev)
+{
+    VSCSIState *s = DO_UPCAST(VSCSIState, vdev, dev);
+
+    dev->crq.SendFunc = vscsi_do_crq;
+
+    scsi_bus_new(&s->bus, &dev->qdev, &vscsi_scsi_info);
+    if (!dev->qdev.hotplugged) {
+        scsi_bus_legacy_handle_cmdline(&s->bus);
+    }
+
+    return 0;
+}
+
+void spapr_vscsi_create(VIOsPAPRBus *bus)
+{
+    DeviceState *dev;
+
+    dev = qdev_create(&bus->bus, "spapr-vscsi");
+
+    qdev_init_nofail(dev);
+}
+
+static int spapr_vscsi_devnode(VIOsPAPRDevice *dev, void *fdt, int node_off)
+{
+    int ret;
+
+    ret = fdt_setprop_cell(fdt, node_off, "#address-cells", 2);
+    if (ret < 0) {
+        return ret;
+    }
+
+    ret = fdt_setprop_cell(fdt, node_off, "#size-cells", 0);
+    if (ret < 0) {
+        return ret;
+    }
+
+    return 0;
+}
+
+static Property spapr_vscsi_properties[] = {
+    DEFINE_SPAPR_PROPERTIES(VSCSIState, vdev),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void spapr_vscsi_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    VIOsPAPRDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass);
+
+    k->init = spapr_vscsi_init;
+    k->reset = spapr_vscsi_reset;
+    k->devnode = spapr_vscsi_devnode;
+    k->dt_name = "v-scsi";
+    k->dt_type = "vscsi";
+    k->dt_compatible = "IBM,v-scsi";
+    k->signal_mask = 0x00000001;
+    dc->props = spapr_vscsi_properties;
+    k->rtce_window_size = 0x10000000;
+}
+
+static const 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_types(void)
+{
+    type_register_static(&spapr_vscsi_info);
+}
+
+type_init(spapr_vscsi_register_types)
diff --git a/hw/scsi/srp.h b/hw/scsi/srp.h
new file mode 100644 (file)
index 0000000..5e0cad5
--- /dev/null
@@ -0,0 +1,240 @@
+/*
+ * Copyright (c) 2005 Cisco Systems.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * 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 SCSI_SRP_H
+#define SCSI_SRP_H
+
+/*
+ * Structures and constants for the SCSI RDMA Protocol (SRP) as
+ * defined by the INCITS T10 committee.  This file was written using
+ * draft Revision 16a of the SRP standard.
+ */
+
+enum {
+
+    SRP_LOGIN_REQ = 0x00,
+    SRP_TSK_MGMT  = 0x01,
+    SRP_CMD       = 0x02,
+    SRP_I_LOGOUT  = 0x03,
+    SRP_LOGIN_RSP = 0xc0,
+    SRP_RSP       = 0xc1,
+    SRP_LOGIN_REJ = 0xc2,
+    SRP_T_LOGOUT  = 0x80,
+    SRP_CRED_REQ  = 0x81,
+    SRP_AER_REQ   = 0x82,
+    SRP_CRED_RSP  = 0x41,
+    SRP_AER_RSP   = 0x42
+};
+
+enum {
+    SRP_BUF_FORMAT_DIRECT   = 1 << 1,
+    SRP_BUF_FORMAT_INDIRECT = 1 << 2
+};
+
+enum {
+    SRP_NO_DATA_DESC       = 0,
+    SRP_DATA_DESC_DIRECT   = 1,
+    SRP_DATA_DESC_INDIRECT = 2
+};
+
+enum {
+    SRP_TSK_ABORT_TASK     = 0x01,
+    SRP_TSK_ABORT_TASK_SET = 0x02,
+    SRP_TSK_CLEAR_TASK_SET = 0x04,
+    SRP_TSK_LUN_RESET      = 0x08,
+    SRP_TSK_CLEAR_ACA      = 0x40
+};
+
+enum srp_login_rej_reason {
+    SRP_LOGIN_REJ_UNABLE_ESTABLISH_CHANNEL   = 0x00010000,
+    SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES     = 0x00010001,
+    SRP_LOGIN_REJ_REQ_IT_IU_LENGTH_TOO_LARGE = 0x00010002,
+    SRP_LOGIN_REJ_UNABLE_ASSOCIATE_CHANNEL   = 0x00010003,
+    SRP_LOGIN_REJ_UNSUPPORTED_DESCRIPTOR_FMT = 0x00010004,
+    SRP_LOGIN_REJ_MULTI_CHANNEL_UNSUPPORTED  = 0x00010005,
+    SRP_LOGIN_REJ_CHANNEL_LIMIT_REACHED      = 0x00010006
+};
+
+enum {
+    SRP_REV10_IB_IO_CLASS  = 0xff00,
+    SRP_REV16A_IB_IO_CLASS = 0x0100
+};
+
+struct srp_direct_buf {
+    uint64_t    va;
+    uint32_t    key;
+    uint32_t    len;
+};
+
+/*
+ * We need the packed attribute because the SRP spec puts the list of
+ * descriptors at an offset of 20, which is not aligned to the size of
+ * struct srp_direct_buf.  The whole structure must be packed to avoid
+ * having the 20-byte structure padded to 24 bytes on 64-bit architectures.
+ */
+struct srp_indirect_buf {
+    struct srp_direct_buf    table_desc;
+    uint32_t                 len;
+    struct srp_direct_buf    desc_list[0];
+} QEMU_PACKED;
+
+enum {
+    SRP_MULTICHAN_SINGLE = 0,
+    SRP_MULTICHAN_MULTI  = 1
+};
+
+struct srp_login_req {
+    uint8_t    opcode;
+    uint8_t    reserved1[7];
+    uint64_t   tag;
+    uint32_t   req_it_iu_len;
+    uint8_t    reserved2[4];
+    uint16_t   req_buf_fmt;
+    uint8_t    req_flags;
+    uint8_t    reserved3[5];
+    uint8_t    initiator_port_id[16];
+    uint8_t    target_port_id[16];
+};
+
+/*
+ * The SRP spec defines the size of the LOGIN_RSP structure to be 52
+ * bytes, so it needs to be packed to avoid having it padded to 56
+ * bytes on 64-bit architectures.
+ */
+struct srp_login_rsp {
+    uint8_t    opcode;
+    uint8_t    reserved1[3];
+    uint32_t   req_lim_delta;
+    uint64_t   tag;
+    uint32_t   max_it_iu_len;
+    uint32_t   max_ti_iu_len;
+    uint16_t   buf_fmt;
+    uint8_t    rsp_flags;
+    uint8_t    reserved2[25];
+} QEMU_PACKED;
+
+struct srp_login_rej {
+    uint8_t    opcode;
+    uint8_t    reserved1[3];
+    uint32_t   reason;
+    uint64_t   tag;
+    uint8_t    reserved2[8];
+    uint16_t   buf_fmt;
+    uint8_t    reserved3[6];
+};
+
+struct srp_i_logout {
+    uint8_t    opcode;
+    uint8_t    reserved[7];
+    uint64_t   tag;
+};
+
+struct srp_t_logout {
+    uint8_t    opcode;
+    uint8_t    sol_not;
+    uint8_t    reserved[2];
+    uint32_t   reason;
+    uint64_t   tag;
+};
+
+/*
+ * We need the packed attribute because the SRP spec only aligns the
+ * 8-byte LUN field to 4 bytes.
+ */
+struct srp_tsk_mgmt {
+    uint8_t    opcode;
+    uint8_t    sol_not;
+    uint8_t    reserved1[6];
+    uint64_t   tag;
+    uint8_t    reserved2[4];
+    uint64_t   lun;
+    uint8_t    reserved3[2];
+    uint8_t    tsk_mgmt_func;
+    uint8_t    reserved4;
+    uint64_t   task_tag;
+    uint8_t    reserved5[8];
+} QEMU_PACKED;
+
+/*
+ * We need the packed attribute because the SRP spec only aligns the
+ * 8-byte LUN field to 4 bytes.
+ */
+struct srp_cmd {
+    uint8_t    opcode;
+    uint8_t    sol_not;
+    uint8_t    reserved1[3];
+    uint8_t    buf_fmt;
+    uint8_t    data_out_desc_cnt;
+    uint8_t    data_in_desc_cnt;
+    uint64_t   tag;
+    uint8_t    reserved2[4];
+    uint64_t   lun;
+    uint8_t    reserved3;
+    uint8_t    task_attr;
+    uint8_t    reserved4;
+    uint8_t    add_cdb_len;
+    uint8_t    cdb[16];
+    uint8_t    add_data[0];
+} QEMU_PACKED;
+
+enum {
+    SRP_RSP_FLAG_RSPVALID = 1 << 0,
+    SRP_RSP_FLAG_SNSVALID = 1 << 1,
+    SRP_RSP_FLAG_DOOVER   = 1 << 2,
+    SRP_RSP_FLAG_DOUNDER  = 1 << 3,
+    SRP_RSP_FLAG_DIOVER   = 1 << 4,
+    SRP_RSP_FLAG_DIUNDER  = 1 << 5
+};
+
+/*
+ * The SRP spec defines the size of the RSP structure to be 36 bytes,
+ * so it needs to be packed to avoid having it padded to 40 bytes on
+ * 64-bit architectures.
+ */
+struct srp_rsp {
+    uint8_t    opcode;
+    uint8_t    sol_not;
+    uint8_t    reserved1[2];
+    uint32_t   req_lim_delta;
+    uint64_t   tag;
+    uint8_t    reserved2[2];
+    uint8_t    flags;
+    uint8_t    status;
+    uint32_t   data_out_res_cnt;
+    uint32_t   data_in_res_cnt;
+    uint32_t   sense_data_len;
+    uint32_t   resp_data_len;
+    uint8_t    data[0];
+} QEMU_PACKED;
+
+#endif /* SCSI_SRP_H */
diff --git a/hw/scsi/viosrp.h b/hw/scsi/viosrp.h
new file mode 100644 (file)
index 0000000..d8e365d
--- /dev/null
@@ -0,0 +1,216 @@
+/*****************************************************************************/
+/* srp.h -- SCSI RDMA Protocol definitions                                   */
+/*                                                                           */
+/* Written By: Colin Devilbis, IBM Corporation                               */
+/*                                                                           */
+/* Copyright (C) 2003 IBM Corporation                                        */
+/*                                                                           */
+/* 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, write to the Free Software               */
+/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+/*                                                                           */
+/*                                                                           */
+/* This file contains structures and definitions for IBM RPA (RS/6000        */
+/* platform architecture) implementation of the SRP (SCSI RDMA Protocol)     */
+/* standard.  SRP is used on IBM iSeries and pSeries platforms to send SCSI  */
+/* commands between logical partitions.                                      */
+/*                                                                           */
+/* SRP Information Units (IUs) are sent on a "Command/Response Queue" (CRQ)  */
+/* between partitions.  The definitions in this file are architected,        */
+/* and cannot be changed without breaking compatibility with other versions  */
+/* of Linux and other operating systems (AIX, OS/400) that talk this protocol*/
+/* between logical partitions                                                */
+/*****************************************************************************/
+#ifndef PPC_VIOSRP_H
+#define PPC_VIOSRP_H
+
+#define SRP_VERSION "16.a"
+#define SRP_MAX_IU_LEN    256
+#define SRP_MAX_LOC_LEN 32
+
+union srp_iu {
+    struct srp_login_req login_req;
+    struct srp_login_rsp login_rsp;
+    struct srp_login_rej login_rej;
+    struct srp_i_logout i_logout;
+    struct srp_t_logout t_logout;
+    struct srp_tsk_mgmt tsk_mgmt;
+    struct srp_cmd cmd;
+    struct srp_rsp rsp;
+    uint8_t reserved[SRP_MAX_IU_LEN];
+};
+
+enum viosrp_crq_formats {
+    VIOSRP_SRP_FORMAT = 0x01,
+    VIOSRP_MAD_FORMAT = 0x02,
+    VIOSRP_OS400_FORMAT = 0x03,
+    VIOSRP_AIX_FORMAT = 0x04,
+    VIOSRP_LINUX_FORMAT = 0x06,
+    VIOSRP_INLINE_FORMAT = 0x07
+};
+
+enum viosrp_crq_status {
+    VIOSRP_OK = 0x0,
+    VIOSRP_NONRECOVERABLE_ERR = 0x1,
+    VIOSRP_VIOLATES_MAX_XFER = 0x2,
+    VIOSRP_PARTNER_PANIC = 0x3,
+    VIOSRP_DEVICE_BUSY = 0x8,
+    VIOSRP_ADAPTER_FAIL = 0x10,
+    VIOSRP_OK2 = 0x99,
+};
+
+struct viosrp_crq {
+    uint8_t valid;        /* used by RPA */
+    uint8_t format;        /* SCSI vs out-of-band */
+    uint8_t reserved;
+    uint8_t status;        /* non-scsi failure? (e.g. DMA failure) */
+    uint16_t timeout;        /* in seconds */
+    uint16_t IU_length;        /* in bytes */
+    uint64_t IU_data_ptr;    /* the TCE for transferring data */
+};
+
+/* MADs are Management requests above and beyond the IUs defined in the SRP
+ * standard.
+ */
+enum viosrp_mad_types {
+    VIOSRP_EMPTY_IU_TYPE = 0x01,
+    VIOSRP_ERROR_LOG_TYPE = 0x02,
+    VIOSRP_ADAPTER_INFO_TYPE = 0x03,
+    VIOSRP_HOST_CONFIG_TYPE = 0x04,
+    VIOSRP_CAPABILITIES_TYPE = 0x05,
+    VIOSRP_ENABLE_FAST_FAIL = 0x08,
+};
+
+enum viosrp_mad_status {
+    VIOSRP_MAD_SUCCESS = 0x00,
+    VIOSRP_MAD_NOT_SUPPORTED = 0xF1,
+    VIOSRP_MAD_FAILED = 0xF7,
+};
+
+enum viosrp_capability_type {
+    MIGRATION_CAPABILITIES = 0x01,
+    RESERVATION_CAPABILITIES = 0x02,
+};
+
+enum viosrp_capability_support {
+    SERVER_DOES_NOT_SUPPORTS_CAP = 0x0,
+    SERVER_SUPPORTS_CAP = 0x01,
+    SERVER_CAP_DATA = 0x02,
+};
+
+enum viosrp_reserve_type {
+    CLIENT_RESERVE_SCSI_2 = 0x01,
+};
+
+enum viosrp_capability_flag {
+    CLIENT_MIGRATED = 0x01,
+    CLIENT_RECONNECT = 0x02,
+    CAP_LIST_SUPPORTED = 0x04,
+    CAP_LIST_DATA = 0x08,
+};
+
+/*
+ * Common MAD header
+ */
+struct mad_common {
+    uint32_t type;
+    uint16_t status;
+    uint16_t length;
+    uint64_t tag;
+};
+
+/*
+ * All SRP (and MAD) requests normally flow from the
+ * client to the server.  There is no way for the server to send
+ * an asynchronous message back to the client.  The Empty IU is used
+ * to hang out a meaningless request to the server so that it can respond
+ * asynchrouously with something like a SCSI AER
+ */
+struct viosrp_empty_iu {
+    struct mad_common common;
+    uint64_t buffer;
+    uint32_t port;
+};
+
+struct viosrp_error_log {
+    struct mad_common common;
+    uint64_t buffer;
+};
+
+struct viosrp_adapter_info {
+    struct mad_common common;
+    uint64_t buffer;
+};
+
+struct viosrp_host_config {
+    struct mad_common common;
+    uint64_t buffer;
+};
+
+struct viosrp_fast_fail {
+    struct mad_common common;
+};
+
+struct viosrp_capabilities {
+    struct mad_common common;
+    uint64_t buffer;
+};
+
+struct mad_capability_common {
+    uint32_t cap_type;
+    uint16_t length;
+    uint16_t server_support;
+};
+
+struct mad_reserve_cap {
+    struct mad_capability_common common;
+    uint32_t type;
+};
+
+struct mad_migration_cap {
+    struct mad_capability_common common;
+    uint32_t ecl;
+};
+
+struct capabilities {
+    uint32_t flags;
+    char name[SRP_MAX_LOC_LEN];
+    char loc[SRP_MAX_LOC_LEN];
+    struct mad_migration_cap migration;
+    struct mad_reserve_cap reserve;
+};
+
+union mad_iu {
+    struct viosrp_empty_iu empty_iu;
+    struct viosrp_error_log error_log;
+    struct viosrp_adapter_info adapter_info;
+    struct viosrp_host_config host_config;
+    struct viosrp_fast_fail fast_fail;
+    struct viosrp_capabilities capabilities;
+};
+
+union viosrp_iu {
+    union srp_iu srp;
+    union mad_iu mad;
+};
+
+struct mad_adapter_info_data {
+    char srp_version[8];
+    char partition_name[96];
+    uint32_t partition_number;
+    uint32_t mad_version;
+    uint32_t os_type;
+    uint32_t port_max_txu[8];    /* per-port maximum transfer */
+};
+
+#endif
diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
new file mode 100644 (file)
index 0000000..ead7cda
--- /dev/null
@@ -0,0 +1,774 @@
+/*
+ * Virtio SCSI HBA
+ *
+ * Copyright IBM, Corp. 2010
+ * Copyright Red Hat, Inc. 2011
+ *
+ * Authors:
+ *   Stefan Hajnoczi    <stefanha@linux.vnet.ibm.com>
+ *   Paolo Bonzini      <pbonzini@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 "hw/virtio/virtio-scsi.h"
+#include "qemu/error-report.h"
+#include <hw/scsi/scsi.h>
+#include <block/scsi.h>
+#include <hw/virtio/virtio-bus.h>
+
+#define VIRTIO_SCSI_VQ_SIZE     128
+#define VIRTIO_SCSI_CDB_SIZE    32
+#define VIRTIO_SCSI_SENSE_SIZE  96
+#define VIRTIO_SCSI_MAX_CHANNEL 0
+#define VIRTIO_SCSI_MAX_TARGET  255
+#define VIRTIO_SCSI_MAX_LUN     16383
+
+/* Response codes */
+#define VIRTIO_SCSI_S_OK                       0
+#define VIRTIO_SCSI_S_OVERRUN                  1
+#define VIRTIO_SCSI_S_ABORTED                  2
+#define VIRTIO_SCSI_S_BAD_TARGET               3
+#define VIRTIO_SCSI_S_RESET                    4
+#define VIRTIO_SCSI_S_BUSY                     5
+#define VIRTIO_SCSI_S_TRANSPORT_FAILURE        6
+#define VIRTIO_SCSI_S_TARGET_FAILURE           7
+#define VIRTIO_SCSI_S_NEXUS_FAILURE            8
+#define VIRTIO_SCSI_S_FAILURE                  9
+#define VIRTIO_SCSI_S_FUNCTION_SUCCEEDED       10
+#define VIRTIO_SCSI_S_FUNCTION_REJECTED        11
+#define VIRTIO_SCSI_S_INCORRECT_LUN            12
+
+/* Controlq type codes.  */
+#define VIRTIO_SCSI_T_TMF                      0
+#define VIRTIO_SCSI_T_AN_QUERY                 1
+#define VIRTIO_SCSI_T_AN_SUBSCRIBE             2
+
+/* Valid TMF subtypes.  */
+#define VIRTIO_SCSI_T_TMF_ABORT_TASK           0
+#define VIRTIO_SCSI_T_TMF_ABORT_TASK_SET       1
+#define VIRTIO_SCSI_T_TMF_CLEAR_ACA            2
+#define VIRTIO_SCSI_T_TMF_CLEAR_TASK_SET       3
+#define VIRTIO_SCSI_T_TMF_I_T_NEXUS_RESET      4
+#define VIRTIO_SCSI_T_TMF_LOGICAL_UNIT_RESET   5
+#define VIRTIO_SCSI_T_TMF_QUERY_TASK           6
+#define VIRTIO_SCSI_T_TMF_QUERY_TASK_SET       7
+
+/* Events.  */
+#define VIRTIO_SCSI_T_EVENTS_MISSED            0x80000000
+#define VIRTIO_SCSI_T_NO_EVENT                 0
+#define VIRTIO_SCSI_T_TRANSPORT_RESET          1
+#define VIRTIO_SCSI_T_ASYNC_NOTIFY             2
+#define VIRTIO_SCSI_T_PARAM_CHANGE             3
+
+/* Reasons for transport reset event */
+#define VIRTIO_SCSI_EVT_RESET_HARD             0
+#define VIRTIO_SCSI_EVT_RESET_RESCAN           1
+#define VIRTIO_SCSI_EVT_RESET_REMOVED          2
+
+/* SCSI command request, followed by data-out */
+typedef struct {
+    uint8_t lun[8];              /* Logical Unit Number */
+    uint64_t tag;                /* Command identifier */
+    uint8_t task_attr;           /* Task attribute */
+    uint8_t prio;
+    uint8_t crn;
+    uint8_t cdb[];
+} QEMU_PACKED VirtIOSCSICmdReq;
+
+/* Response, followed by sense data and data-in */
+typedef struct {
+    uint32_t sense_len;          /* Sense data length */
+    uint32_t resid;              /* Residual bytes in data buffer */
+    uint16_t status_qualifier;   /* Status qualifier */
+    uint8_t status;              /* Command completion status */
+    uint8_t response;            /* Response values */
+    uint8_t sense[];
+} QEMU_PACKED VirtIOSCSICmdResp;
+
+/* Task Management Request */
+typedef struct {
+    uint32_t type;
+    uint32_t subtype;
+    uint8_t lun[8];
+    uint64_t tag;
+} QEMU_PACKED VirtIOSCSICtrlTMFReq;
+
+typedef struct {
+    uint8_t response;
+} QEMU_PACKED VirtIOSCSICtrlTMFResp;
+
+/* Asynchronous notification query/subscription */
+typedef struct {
+    uint32_t type;
+    uint8_t lun[8];
+    uint32_t event_requested;
+} QEMU_PACKED VirtIOSCSICtrlANReq;
+
+typedef struct {
+    uint32_t event_actual;
+    uint8_t response;
+} QEMU_PACKED VirtIOSCSICtrlANResp;
+
+typedef struct {
+    uint32_t event;
+    uint8_t lun[8];
+    uint32_t reason;
+} QEMU_PACKED VirtIOSCSIEvent;
+
+typedef struct {
+    uint32_t num_queues;
+    uint32_t seg_max;
+    uint32_t max_sectors;
+    uint32_t cmd_per_lun;
+    uint32_t event_info_size;
+    uint32_t sense_size;
+    uint32_t cdb_size;
+    uint16_t max_channel;
+    uint16_t max_target;
+    uint32_t max_lun;
+} QEMU_PACKED VirtIOSCSIConfig;
+
+typedef struct VirtIOSCSIReq {
+    VirtIOSCSI *dev;
+    VirtQueue *vq;
+    VirtQueueElement elem;
+    QEMUSGList qsgl;
+    SCSIRequest *sreq;
+    union {
+        char                  *buf;
+        VirtIOSCSICmdReq      *cmd;
+        VirtIOSCSICtrlTMFReq  *tmf;
+        VirtIOSCSICtrlANReq   *an;
+    } req;
+    union {
+        char                  *buf;
+        VirtIOSCSICmdResp     *cmd;
+        VirtIOSCSICtrlTMFResp *tmf;
+        VirtIOSCSICtrlANResp  *an;
+        VirtIOSCSIEvent       *event;
+    } resp;
+} VirtIOSCSIReq;
+
+static inline int virtio_scsi_get_lun(uint8_t *lun)
+{
+    return ((lun[2] << 8) | lun[3]) & 0x3FFF;
+}
+
+static inline SCSIDevice *virtio_scsi_device_find(VirtIOSCSI *s, uint8_t *lun)
+{
+    if (lun[0] != 1) {
+        return NULL;
+    }
+    if (lun[2] != 0 && !(lun[2] >= 0x40 && lun[2] < 0x80)) {
+        return NULL;
+    }
+    return scsi_device_find(&s->bus, 0, lun[1], virtio_scsi_get_lun(lun));
+}
+
+static void virtio_scsi_complete_req(VirtIOSCSIReq *req)
+{
+    VirtIOSCSI *s = req->dev;
+    VirtQueue *vq = req->vq;
+    VirtIODevice *vdev = VIRTIO_DEVICE(s);
+    virtqueue_push(vq, &req->elem, req->qsgl.size + req->elem.in_sg[0].iov_len);
+    qemu_sglist_destroy(&req->qsgl);
+    if (req->sreq) {
+        req->sreq->hba_private = NULL;
+        scsi_req_unref(req->sreq);
+    }
+    g_free(req);
+    virtio_notify(vdev, vq);
+}
+
+static void virtio_scsi_bad_req(void)
+{
+    error_report("wrong size for virtio-scsi headers");
+    exit(1);
+}
+
+static void qemu_sgl_init_external(QEMUSGList *qsgl, struct iovec *sg,
+                                   hwaddr *addr, int num)
+{
+    qemu_sglist_init(qsgl, num, &dma_context_memory);
+    while (num--) {
+        qemu_sglist_add(qsgl, *(addr++), (sg++)->iov_len);
+    }
+}
+
+static void virtio_scsi_parse_req(VirtIOSCSI *s, VirtQueue *vq,
+                                  VirtIOSCSIReq *req)
+{
+    assert(req->elem.in_num);
+    req->vq = vq;
+    req->dev = s;
+    req->sreq = NULL;
+    if (req->elem.out_num) {
+        req->req.buf = req->elem.out_sg[0].iov_base;
+    }
+    req->resp.buf = req->elem.in_sg[0].iov_base;
+
+    if (req->elem.out_num > 1) {
+        qemu_sgl_init_external(&req->qsgl, &req->elem.out_sg[1],
+                               &req->elem.out_addr[1],
+                               req->elem.out_num - 1);
+    } else {
+        qemu_sgl_init_external(&req->qsgl, &req->elem.in_sg[1],
+                               &req->elem.in_addr[1],
+                               req->elem.in_num - 1);
+    }
+}
+
+static VirtIOSCSIReq *virtio_scsi_pop_req(VirtIOSCSI *s, VirtQueue *vq)
+{
+    VirtIOSCSIReq *req;
+    req = g_malloc(sizeof(*req));
+    if (!virtqueue_pop(vq, &req->elem)) {
+        g_free(req);
+        return NULL;
+    }
+
+    virtio_scsi_parse_req(s, vq, req);
+    return req;
+}
+
+static void virtio_scsi_save_request(QEMUFile *f, SCSIRequest *sreq)
+{
+    VirtIOSCSIReq *req = sreq->hba_private;
+    uint32_t n = virtio_queue_get_id(req->vq) - 2;
+
+    assert(n < req->dev->conf.num_queues);
+    qemu_put_be32s(f, &n);
+    qemu_put_buffer(f, (unsigned char *)&req->elem, sizeof(req->elem));
+}
+
+static void *virtio_scsi_load_request(QEMUFile *f, SCSIRequest *sreq)
+{
+    SCSIBus *bus = sreq->bus;
+    VirtIOSCSI *s = container_of(bus, VirtIOSCSI, bus);
+    VirtIOSCSIReq *req;
+    uint32_t n;
+
+    req = g_malloc(sizeof(*req));
+    qemu_get_be32s(f, &n);
+    assert(n < s->conf.num_queues);
+    qemu_get_buffer(f, (unsigned char *)&req->elem, sizeof(req->elem));
+    virtio_scsi_parse_req(s, s->cmd_vqs[n], req);
+
+    scsi_req_ref(sreq);
+    req->sreq = sreq;
+    if (req->sreq->cmd.mode != SCSI_XFER_NONE) {
+        int req_mode =
+            (req->elem.in_num > 1 ? SCSI_XFER_FROM_DEV : SCSI_XFER_TO_DEV);
+
+        assert(req->sreq->cmd.mode == req_mode);
+    }
+    return req;
+}
+
+static void virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req)
+{
+    SCSIDevice *d = virtio_scsi_device_find(s, req->req.tmf->lun);
+    SCSIRequest *r, *next;
+    BusChild *kid;
+    int target;
+
+    /* Here VIRTIO_SCSI_S_OK means "FUNCTION COMPLETE".  */
+    req->resp.tmf->response = VIRTIO_SCSI_S_OK;
+
+    switch (req->req.tmf->subtype) {
+    case VIRTIO_SCSI_T_TMF_ABORT_TASK:
+    case VIRTIO_SCSI_T_TMF_QUERY_TASK:
+        if (!d) {
+            goto fail;
+        }
+        if (d->lun != virtio_scsi_get_lun(req->req.tmf->lun)) {
+            goto incorrect_lun;
+        }
+        QTAILQ_FOREACH_SAFE(r, &d->requests, next, next) {
+            VirtIOSCSIReq *cmd_req = r->hba_private;
+            if (cmd_req && cmd_req->req.cmd->tag == req->req.tmf->tag) {
+                break;
+            }
+        }
+        if (r) {
+            /*
+             * Assert that the request has not been completed yet, we
+             * check for it in the loop above.
+             */
+            assert(r->hba_private);
+            if (req->req.tmf->subtype == VIRTIO_SCSI_T_TMF_QUERY_TASK) {
+                /* "If the specified command is present in the task set, then
+                 * return a service response set to FUNCTION SUCCEEDED".
+                 */
+                req->resp.tmf->response = VIRTIO_SCSI_S_FUNCTION_SUCCEEDED;
+            } else {
+                scsi_req_cancel(r);
+            }
+        }
+        break;
+
+    case VIRTIO_SCSI_T_TMF_LOGICAL_UNIT_RESET:
+        if (!d) {
+            goto fail;
+        }
+        if (d->lun != virtio_scsi_get_lun(req->req.tmf->lun)) {
+            goto incorrect_lun;
+        }
+        s->resetting++;
+        qdev_reset_all(&d->qdev);
+        s->resetting--;
+        break;
+
+    case VIRTIO_SCSI_T_TMF_ABORT_TASK_SET:
+    case VIRTIO_SCSI_T_TMF_CLEAR_TASK_SET:
+    case VIRTIO_SCSI_T_TMF_QUERY_TASK_SET:
+        if (!d) {
+            goto fail;
+        }
+        if (d->lun != virtio_scsi_get_lun(req->req.tmf->lun)) {
+            goto incorrect_lun;
+        }
+        QTAILQ_FOREACH_SAFE(r, &d->requests, next, next) {
+            if (r->hba_private) {
+                if (req->req.tmf->subtype == VIRTIO_SCSI_T_TMF_QUERY_TASK_SET) {
+                    /* "If there is any command present in the task set, then
+                     * return a service response set to FUNCTION SUCCEEDED".
+                     */
+                    req->resp.tmf->response = VIRTIO_SCSI_S_FUNCTION_SUCCEEDED;
+                    break;
+                } else {
+                    scsi_req_cancel(r);
+                }
+            }
+        }
+        break;
+
+    case VIRTIO_SCSI_T_TMF_I_T_NEXUS_RESET:
+        target = req->req.tmf->lun[1];
+        s->resetting++;
+        QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) {
+             d = DO_UPCAST(SCSIDevice, qdev, kid->child);
+             if (d->channel == 0 && d->id == target) {
+                qdev_reset_all(&d->qdev);
+             }
+        }
+        s->resetting--;
+        break;
+
+    case VIRTIO_SCSI_T_TMF_CLEAR_ACA:
+    default:
+        req->resp.tmf->response = VIRTIO_SCSI_S_FUNCTION_REJECTED;
+        break;
+    }
+
+    return;
+
+incorrect_lun:
+    req->resp.tmf->response = VIRTIO_SCSI_S_INCORRECT_LUN;
+    return;
+
+fail:
+    req->resp.tmf->response = VIRTIO_SCSI_S_BAD_TARGET;
+}
+
+static void virtio_scsi_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
+{
+    VirtIOSCSI *s = (VirtIOSCSI *)vdev;
+    VirtIOSCSIReq *req;
+
+    while ((req = virtio_scsi_pop_req(s, vq))) {
+        int out_size, in_size;
+        if (req->elem.out_num < 1 || req->elem.in_num < 1) {
+            virtio_scsi_bad_req();
+            continue;
+        }
+
+        out_size = req->elem.out_sg[0].iov_len;
+        in_size = req->elem.in_sg[0].iov_len;
+        if (req->req.tmf->type == VIRTIO_SCSI_T_TMF) {
+            if (out_size < sizeof(VirtIOSCSICtrlTMFReq) ||
+                in_size < sizeof(VirtIOSCSICtrlTMFResp)) {
+                virtio_scsi_bad_req();
+            }
+            virtio_scsi_do_tmf(s, req);
+
+        } else if (req->req.tmf->type == VIRTIO_SCSI_T_AN_QUERY ||
+                   req->req.tmf->type == VIRTIO_SCSI_T_AN_SUBSCRIBE) {
+            if (out_size < sizeof(VirtIOSCSICtrlANReq) ||
+                in_size < sizeof(VirtIOSCSICtrlANResp)) {
+                virtio_scsi_bad_req();
+            }
+            req->resp.an->event_actual = 0;
+            req->resp.an->response = VIRTIO_SCSI_S_OK;
+        }
+        virtio_scsi_complete_req(req);
+    }
+}
+
+static void virtio_scsi_command_complete(SCSIRequest *r, uint32_t status,
+                                         size_t resid)
+{
+    VirtIOSCSIReq *req = r->hba_private;
+    uint32_t sense_len;
+
+    req->resp.cmd->response = VIRTIO_SCSI_S_OK;
+    req->resp.cmd->status = status;
+    if (req->resp.cmd->status == GOOD) {
+        req->resp.cmd->resid = tswap32(resid);
+    } else {
+        req->resp.cmd->resid = 0;
+        sense_len = scsi_req_get_sense(r, req->resp.cmd->sense,
+                                       VIRTIO_SCSI_SENSE_SIZE);
+        req->resp.cmd->sense_len = tswap32(sense_len);
+    }
+    virtio_scsi_complete_req(req);
+}
+
+static QEMUSGList *virtio_scsi_get_sg_list(SCSIRequest *r)
+{
+    VirtIOSCSIReq *req = r->hba_private;
+
+    return &req->qsgl;
+}
+
+static void virtio_scsi_request_cancelled(SCSIRequest *r)
+{
+    VirtIOSCSIReq *req = r->hba_private;
+
+    if (!req) {
+        return;
+    }
+    if (req->dev->resetting) {
+        req->resp.cmd->response = VIRTIO_SCSI_S_RESET;
+    } else {
+        req->resp.cmd->response = VIRTIO_SCSI_S_ABORTED;
+    }
+    virtio_scsi_complete_req(req);
+}
+
+static void virtio_scsi_fail_cmd_req(VirtIOSCSIReq *req)
+{
+    req->resp.cmd->response = VIRTIO_SCSI_S_FAILURE;
+    virtio_scsi_complete_req(req);
+}
+
+static void virtio_scsi_handle_cmd(VirtIODevice *vdev, VirtQueue *vq)
+{
+    VirtIOSCSI *s = (VirtIOSCSI *)vdev;
+    VirtIOSCSIReq *req;
+    int n;
+
+    while ((req = virtio_scsi_pop_req(s, vq))) {
+        SCSIDevice *d;
+        int out_size, in_size;
+        if (req->elem.out_num < 1 || req->elem.in_num < 1) {
+            virtio_scsi_bad_req();
+        }
+
+        out_size = req->elem.out_sg[0].iov_len;
+        in_size = req->elem.in_sg[0].iov_len;
+        if (out_size < sizeof(VirtIOSCSICmdReq) + s->cdb_size ||
+            in_size < sizeof(VirtIOSCSICmdResp) + s->sense_size) {
+            virtio_scsi_bad_req();
+        }
+
+        if (req->elem.out_num > 1 && req->elem.in_num > 1) {
+            virtio_scsi_fail_cmd_req(req);
+            continue;
+        }
+
+        d = virtio_scsi_device_find(s, req->req.cmd->lun);
+        if (!d) {
+            req->resp.cmd->response = VIRTIO_SCSI_S_BAD_TARGET;
+            virtio_scsi_complete_req(req);
+            continue;
+        }
+        req->sreq = scsi_req_new(d, req->req.cmd->tag,
+                                 virtio_scsi_get_lun(req->req.cmd->lun),
+                                 req->req.cmd->cdb, req);
+
+        if (req->sreq->cmd.mode != SCSI_XFER_NONE) {
+            int req_mode =
+                (req->elem.in_num > 1 ? SCSI_XFER_FROM_DEV : SCSI_XFER_TO_DEV);
+
+            if (req->sreq->cmd.mode != req_mode ||
+                req->sreq->cmd.xfer > req->qsgl.size) {
+                req->resp.cmd->response = VIRTIO_SCSI_S_OVERRUN;
+                virtio_scsi_complete_req(req);
+                continue;
+            }
+        }
+
+        n = scsi_req_enqueue(req->sreq);
+        if (n) {
+            scsi_req_continue(req->sreq);
+        }
+    }
+}
+
+static void virtio_scsi_get_config(VirtIODevice *vdev,
+                                   uint8_t *config)
+{
+    VirtIOSCSIConfig *scsiconf = (VirtIOSCSIConfig *)config;
+    VirtIOSCSI *s = (VirtIOSCSI *)vdev;
+
+    stl_raw(&scsiconf->num_queues, s->conf.num_queues);
+    stl_raw(&scsiconf->seg_max, 128 - 2);
+    stl_raw(&scsiconf->max_sectors, s->conf.max_sectors);
+    stl_raw(&scsiconf->cmd_per_lun, s->conf.cmd_per_lun);
+    stl_raw(&scsiconf->event_info_size, sizeof(VirtIOSCSIEvent));
+    stl_raw(&scsiconf->sense_size, s->sense_size);
+    stl_raw(&scsiconf->cdb_size, s->cdb_size);
+    stw_raw(&scsiconf->max_channel, VIRTIO_SCSI_MAX_CHANNEL);
+    stw_raw(&scsiconf->max_target, VIRTIO_SCSI_MAX_TARGET);
+    stl_raw(&scsiconf->max_lun, VIRTIO_SCSI_MAX_LUN);
+}
+
+static void virtio_scsi_set_config(VirtIODevice *vdev,
+                                   const uint8_t *config)
+{
+    VirtIOSCSIConfig *scsiconf = (VirtIOSCSIConfig *)config;
+    VirtIOSCSI *s = (VirtIOSCSI *)vdev;
+
+    if ((uint32_t) ldl_raw(&scsiconf->sense_size) >= 65536 ||
+        (uint32_t) ldl_raw(&scsiconf->cdb_size) >= 256) {
+        error_report("bad data written to virtio-scsi configuration space");
+        exit(1);
+    }
+
+    s->sense_size = ldl_raw(&scsiconf->sense_size);
+    s->cdb_size = ldl_raw(&scsiconf->cdb_size);
+}
+
+static uint32_t virtio_scsi_get_features(VirtIODevice *vdev,
+                                         uint32_t requested_features)
+{
+    return requested_features;
+}
+
+static void virtio_scsi_reset(VirtIODevice *vdev)
+{
+    VirtIOSCSI *s = (VirtIOSCSI *)vdev;
+
+    s->resetting++;
+    qbus_reset_all(&s->bus.qbus);
+    s->resetting--;
+
+    s->sense_size = VIRTIO_SCSI_SENSE_SIZE;
+    s->cdb_size = VIRTIO_SCSI_CDB_SIZE;
+    s->events_dropped = false;
+}
+
+/* The device does not have anything to save beyond the virtio data.
+ * Request data is saved with callbacks from SCSI devices.
+ */
+static void virtio_scsi_save(QEMUFile *f, void *opaque)
+{
+    VirtIODevice *vdev = VIRTIO_DEVICE(opaque);
+    virtio_save(vdev, f);
+}
+
+static int virtio_scsi_load(QEMUFile *f, void *opaque, int version_id)
+{
+    VirtIODevice *vdev = VIRTIO_DEVICE(opaque);
+    int ret;
+
+    ret = virtio_load(vdev, f);
+    if (ret) {
+        return ret;
+    }
+    return 0;
+}
+
+static void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev,
+                                   uint32_t event, uint32_t reason)
+{
+    VirtIOSCSIReq *req = virtio_scsi_pop_req(s, s->event_vq);
+    VirtIOSCSIEvent *evt;
+    VirtIODevice *vdev = VIRTIO_DEVICE(s);
+    int in_size;
+
+    if (!(vdev->status & VIRTIO_CONFIG_S_DRIVER_OK)) {
+        return;
+    }
+
+    if (!req) {
+        s->events_dropped = true;
+        return;
+    }
+
+    if (req->elem.out_num || req->elem.in_num != 1) {
+        virtio_scsi_bad_req();
+    }
+
+    if (s->events_dropped) {
+        event |= VIRTIO_SCSI_T_EVENTS_MISSED;
+        s->events_dropped = false;
+    }
+
+    in_size = req->elem.in_sg[0].iov_len;
+    if (in_size < sizeof(VirtIOSCSIEvent)) {
+        virtio_scsi_bad_req();
+    }
+
+    evt = req->resp.event;
+    memset(evt, 0, sizeof(VirtIOSCSIEvent));
+    evt->event = event;
+    evt->reason = reason;
+    if (!dev) {
+        assert(event == VIRTIO_SCSI_T_NO_EVENT);
+    } else {
+        evt->lun[0] = 1;
+        evt->lun[1] = dev->id;
+
+        /* Linux wants us to keep the same encoding we use for REPORT LUNS.  */
+        if (dev->lun >= 256) {
+            evt->lun[2] = (dev->lun >> 8) | 0x40;
+        }
+        evt->lun[3] = dev->lun & 0xFF;
+    }
+    virtio_scsi_complete_req(req);
+}
+
+static void virtio_scsi_handle_event(VirtIODevice *vdev, VirtQueue *vq)
+{
+    VirtIOSCSI *s = VIRTIO_SCSI(vdev);
+
+    if (s->events_dropped) {
+        virtio_scsi_push_event(s, NULL, VIRTIO_SCSI_T_NO_EVENT, 0);
+    }
+}
+
+static void virtio_scsi_change(SCSIBus *bus, SCSIDevice *dev, SCSISense sense)
+{
+    VirtIOSCSI *s = container_of(bus, VirtIOSCSI, bus);
+    VirtIODevice *vdev = VIRTIO_DEVICE(s);
+
+    if (((vdev->guest_features >> VIRTIO_SCSI_F_CHANGE) & 1) &&
+        dev->type != TYPE_ROM) {
+        virtio_scsi_push_event(s, dev, VIRTIO_SCSI_T_PARAM_CHANGE,
+                               sense.asc | (sense.ascq << 8));
+    }
+}
+
+static void virtio_scsi_hotplug(SCSIBus *bus, SCSIDevice *dev)
+{
+    VirtIOSCSI *s = container_of(bus, VirtIOSCSI, bus);
+    VirtIODevice *vdev = VIRTIO_DEVICE(s);
+
+    if ((vdev->guest_features >> VIRTIO_SCSI_F_HOTPLUG) & 1) {
+        virtio_scsi_push_event(s, dev, VIRTIO_SCSI_T_TRANSPORT_RESET,
+                               VIRTIO_SCSI_EVT_RESET_RESCAN);
+    }
+}
+
+static void virtio_scsi_hot_unplug(SCSIBus *bus, SCSIDevice *dev)
+{
+    VirtIOSCSI *s = container_of(bus, VirtIOSCSI, bus);
+    VirtIODevice *vdev = VIRTIO_DEVICE(s);
+
+    if ((vdev->guest_features >> VIRTIO_SCSI_F_HOTPLUG) & 1) {
+        virtio_scsi_push_event(s, dev, VIRTIO_SCSI_T_TRANSPORT_RESET,
+                               VIRTIO_SCSI_EVT_RESET_REMOVED);
+    }
+}
+
+static struct SCSIBusInfo virtio_scsi_scsi_info = {
+    .tcq = true,
+    .max_channel = VIRTIO_SCSI_MAX_CHANNEL,
+    .max_target = VIRTIO_SCSI_MAX_TARGET,
+    .max_lun = VIRTIO_SCSI_MAX_LUN,
+
+    .complete = virtio_scsi_command_complete,
+    .cancel = virtio_scsi_request_cancelled,
+    .change = virtio_scsi_change,
+    .hotplug = virtio_scsi_hotplug,
+    .hot_unplug = virtio_scsi_hot_unplug,
+    .get_sg_list = virtio_scsi_get_sg_list,
+    .save_request = virtio_scsi_save_request,
+    .load_request = virtio_scsi_load_request,
+};
+
+static int virtio_scsi_device_init(VirtIODevice *vdev)
+{
+    DeviceState *qdev = DEVICE(vdev);
+    VirtIOSCSI *s = VIRTIO_SCSI(vdev);
+    static int virtio_scsi_id;
+    int i;
+
+    virtio_init(VIRTIO_DEVICE(s), "virtio-scsi", VIRTIO_ID_SCSI,
+                sizeof(VirtIOSCSIConfig));
+
+    s->cmd_vqs = g_malloc0(s->conf.num_queues * sizeof(VirtQueue *));
+
+    /* TODO set up vdev function pointers */
+    vdev->get_config = virtio_scsi_get_config;
+    vdev->set_config = virtio_scsi_set_config;
+    vdev->get_features = virtio_scsi_get_features;
+    vdev->reset = virtio_scsi_reset;
+
+    s->ctrl_vq = virtio_add_queue(vdev, VIRTIO_SCSI_VQ_SIZE,
+                                  virtio_scsi_handle_ctrl);
+    s->event_vq = virtio_add_queue(vdev, VIRTIO_SCSI_VQ_SIZE,
+                                   virtio_scsi_handle_event);
+    for (i = 0; i < s->conf.num_queues; i++) {
+        s->cmd_vqs[i] = virtio_add_queue(vdev, VIRTIO_SCSI_VQ_SIZE,
+                                         virtio_scsi_handle_cmd);
+    }
+
+    scsi_bus_new(&s->bus, qdev, &virtio_scsi_scsi_info);
+    if (!qdev->hotplugged) {
+        scsi_bus_legacy_handle_cmdline(&s->bus);
+    }
+
+    register_savevm(qdev, "virtio-scsi", virtio_scsi_id++, 1,
+                    virtio_scsi_save, virtio_scsi_load, s);
+
+    return 0;
+}
+
+static int virtio_scsi_device_exit(DeviceState *qdev)
+{
+    VirtIOSCSI *s = VIRTIO_SCSI(qdev);
+    VirtIODevice *vdev = VIRTIO_DEVICE(qdev);
+
+    unregister_savevm(qdev, "virtio-scsi", s);
+    g_free(s->cmd_vqs);
+    virtio_common_cleanup(vdev);
+    return 0;
+}
+
+static Property virtio_scsi_properties[] = {
+    DEFINE_VIRTIO_SCSI_PROPERTIES(VirtIOSCSI, conf),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void virtio_scsi_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
+    dc->exit = virtio_scsi_device_exit;
+    dc->props = virtio_scsi_properties;
+    vdc->init = virtio_scsi_device_init;
+    vdc->get_config = virtio_scsi_get_config;
+    vdc->set_config = virtio_scsi_set_config;
+    vdc->get_features = virtio_scsi_get_features;
+    vdc->reset = virtio_scsi_reset;
+}
+
+static const TypeInfo virtio_scsi_info = {
+    .name = TYPE_VIRTIO_SCSI,
+    .parent = TYPE_VIRTIO_DEVICE,
+    .instance_size = sizeof(VirtIOSCSI),
+    .class_init = virtio_scsi_class_init,
+};
+
+static void virtio_register_types(void)
+{
+    type_register_static(&virtio_scsi_info);
+}
+
+type_init(virtio_register_types)
diff --git a/hw/sd.c b/hw/sd.c
deleted file mode 100644 (file)
index a895123..0000000
--- a/hw/sd.c
+++ /dev/null
@@ -1,1764 +0,0 @@
-/*
- * SD Memory Card emulation as defined in the "SD Memory Card Physical
- * layer specification, Version 1.10."
- *
- * Copyright (c) 2006 Andrzej Zaborowski  <balrog@zabor.org>
- * Copyright (c) 2007 CodeSourcery
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS''
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
- * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "hw/hw.h"
-#include "block/block.h"
-#include "hw/sd.h"
-#include "qemu/bitmap.h"
-
-//#define DEBUG_SD 1
-
-#ifdef DEBUG_SD
-#define DPRINTF(fmt, ...) \
-do { fprintf(stderr, "SD: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...) do {} while(0)
-#endif
-
-typedef enum {
-    sd_r0 = 0,    /* no response */
-    sd_r1,        /* normal response command */
-    sd_r2_i,      /* CID register */
-    sd_r2_s,      /* CSD register */
-    sd_r3,        /* OCR register */
-    sd_r6 = 6,    /* Published RCA response */
-    sd_r7,        /* Operating voltage */
-    sd_r1b = -1,
-    sd_illegal = -2,
-} sd_rsp_type_t;
-
-enum SDCardModes {
-    sd_inactive,
-    sd_card_identification_mode,
-    sd_data_transfer_mode,
-};
-
-enum SDCardStates {
-    sd_inactive_state = -1,
-    sd_idle_state = 0,
-    sd_ready_state,
-    sd_identification_state,
-    sd_standby_state,
-    sd_transfer_state,
-    sd_sendingdata_state,
-    sd_receivingdata_state,
-    sd_programming_state,
-    sd_disconnect_state,
-};
-
-struct SDState {
-    uint32_t mode;    /* current card mode, one of SDCardModes */
-    int32_t state;    /* current card state, one of SDCardStates */
-    uint32_t ocr;
-    uint8_t scr[8];
-    uint8_t cid[16];
-    uint8_t csd[16];
-    uint16_t rca;
-    uint32_t card_status;
-    uint8_t sd_status[64];
-    uint32_t vhs;
-    bool wp_switch;
-    unsigned long *wp_groups;
-    int32_t wpgrps_size;
-    uint64_t size;
-    uint32_t blk_len;
-    uint32_t erase_start;
-    uint32_t erase_end;
-    uint8_t pwd[16];
-    uint32_t pwd_len;
-    uint8_t function_group[6];
-
-    bool spi;
-    uint8_t current_cmd;
-    /* True if we will handle the next command as an ACMD. Note that this does
-     * *not* track the APP_CMD status bit!
-     */
-    bool expecting_acmd;
-    uint32_t blk_written;
-    uint64_t data_start;
-    uint32_t data_offset;
-    uint8_t data[512];
-    qemu_irq readonly_cb;
-    qemu_irq inserted_cb;
-    BlockDriverState *bdrv;
-    uint8_t *buf;
-
-    bool enable;
-};
-
-static void sd_set_mode(SDState *sd)
-{
-    switch (sd->state) {
-    case sd_inactive_state:
-        sd->mode = sd_inactive;
-        break;
-
-    case sd_idle_state:
-    case sd_ready_state:
-    case sd_identification_state:
-        sd->mode = sd_card_identification_mode;
-        break;
-
-    case sd_standby_state:
-    case sd_transfer_state:
-    case sd_sendingdata_state:
-    case sd_receivingdata_state:
-    case sd_programming_state:
-    case sd_disconnect_state:
-        sd->mode = sd_data_transfer_mode;
-        break;
-    }
-}
-
-static const sd_cmd_type_t sd_cmd_type[64] = {
-    sd_bc,   sd_none, sd_bcr,  sd_bcr,  sd_none, sd_none, sd_none, sd_ac,
-    sd_bcr,  sd_ac,   sd_ac,   sd_adtc, sd_ac,   sd_ac,   sd_none, sd_ac,
-    sd_ac,   sd_adtc, sd_adtc, sd_none, sd_none, sd_none, sd_none, sd_none,
-    sd_adtc, sd_adtc, sd_adtc, sd_adtc, sd_ac,   sd_ac,   sd_adtc, sd_none,
-    sd_ac,   sd_ac,   sd_none, sd_none, sd_none, sd_none, sd_ac,   sd_none,
-    sd_none, sd_none, sd_bc,   sd_none, sd_none, sd_none, sd_none, sd_none,
-    sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_ac,
-    sd_adtc, sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_none,
-};
-
-static const sd_cmd_type_t sd_acmd_type[64] = {
-    sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_ac,   sd_none,
-    sd_none, sd_none, sd_none, sd_none, sd_none, sd_adtc, sd_none, sd_none,
-    sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_adtc, sd_ac,
-    sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_none,
-    sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_none,
-    sd_none, sd_bcr,  sd_ac,   sd_none, sd_none, sd_none, sd_none, sd_none,
-    sd_none, sd_none, sd_none, sd_adtc, sd_none, sd_none, sd_none, sd_none,
-    sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_none,
-};
-
-static const int sd_cmd_class[64] = {
-    0,  0,  0,  0,  0,  9, 10,  0,  0,  0,  0,  1,  0,  0,  0,  0,
-    2,  2,  2,  2,  3,  3,  3,  3,  4,  4,  4,  4,  6,  6,  6,  6,
-    5,  5, 10, 10, 10, 10,  5,  9,  9,  9,  7,  7,  7,  7,  7,  7,
-    7,  7, 10,  7,  9,  9,  9,  8,  8, 10,  8,  8,  8,  8,  8,  8,
-};
-
-static uint8_t sd_crc7(void *message, size_t width)
-{
-    int i, bit;
-    uint8_t shift_reg = 0x00;
-    uint8_t *msg = (uint8_t *) message;
-
-    for (i = 0; i < width; i ++, msg ++)
-        for (bit = 7; bit >= 0; bit --) {
-            shift_reg <<= 1;
-            if ((shift_reg >> 7) ^ ((*msg >> bit) & 1))
-                shift_reg ^= 0x89;
-        }
-
-    return shift_reg;
-}
-
-static uint16_t sd_crc16(void *message, size_t width)
-{
-    int i, bit;
-    uint16_t shift_reg = 0x0000;
-    uint16_t *msg = (uint16_t *) message;
-    width <<= 1;
-
-    for (i = 0; i < width; i ++, msg ++)
-        for (bit = 15; bit >= 0; bit --) {
-            shift_reg <<= 1;
-            if ((shift_reg >> 15) ^ ((*msg >> bit) & 1))
-                shift_reg ^= 0x1011;
-        }
-
-    return shift_reg;
-}
-
-static void sd_set_ocr(SDState *sd)
-{
-    /* All voltages OK, card power-up OK, Standard Capacity SD Memory Card */
-    sd->ocr = 0x80ffff00;
-}
-
-static void sd_set_scr(SDState *sd)
-{
-    sd->scr[0] = 0x00;         /* SCR Structure */
-    sd->scr[1] = 0x2f;         /* SD Security Support */
-    sd->scr[2] = 0x00;
-    sd->scr[3] = 0x00;
-    sd->scr[4] = 0x00;
-    sd->scr[5] = 0x00;
-    sd->scr[6] = 0x00;
-    sd->scr[7] = 0x00;
-}
-
-#define MID    0xaa
-#define OID    "XY"
-#define PNM    "QEMU!"
-#define PRV    0x01
-#define MDT_YR 2006
-#define MDT_MON        2
-
-static void sd_set_cid(SDState *sd)
-{
-    sd->cid[0] = MID;          /* Fake card manufacturer ID (MID) */
-    sd->cid[1] = OID[0];       /* OEM/Application ID (OID) */
-    sd->cid[2] = OID[1];
-    sd->cid[3] = PNM[0];       /* Fake product name (PNM) */
-    sd->cid[4] = PNM[1];
-    sd->cid[5] = PNM[2];
-    sd->cid[6] = PNM[3];
-    sd->cid[7] = PNM[4];
-    sd->cid[8] = PRV;          /* Fake product revision (PRV) */
-    sd->cid[9] = 0xde;         /* Fake serial number (PSN) */
-    sd->cid[10] = 0xad;
-    sd->cid[11] = 0xbe;
-    sd->cid[12] = 0xef;
-    sd->cid[13] = 0x00 |       /* Manufacture date (MDT) */
-        ((MDT_YR - 2000) / 10);
-    sd->cid[14] = ((MDT_YR % 10) << 4) | MDT_MON;
-    sd->cid[15] = (sd_crc7(sd->cid, 15) << 1) | 1;
-}
-
-#define HWBLOCK_SHIFT  9                       /* 512 bytes */
-#define SECTOR_SHIFT   5                       /* 16 kilobytes */
-#define WPGROUP_SHIFT  7                       /* 2 megs */
-#define CMULT_SHIFT    9                       /* 512 times HWBLOCK_SIZE */
-#define WPGROUP_SIZE   (1 << (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT))
-
-static const uint8_t sd_csd_rw_mask[16] = {
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xfe,
-};
-
-static void sd_set_csd(SDState *sd, uint64_t size)
-{
-    uint32_t csize = (size >> (CMULT_SHIFT + HWBLOCK_SHIFT)) - 1;
-    uint32_t sectsize = (1 << (SECTOR_SHIFT + 1)) - 1;
-    uint32_t wpsize = (1 << (WPGROUP_SHIFT + 1)) - 1;
-
-    if (size <= 0x40000000) {  /* Standard Capacity SD */
-        sd->csd[0] = 0x00;     /* CSD structure */
-        sd->csd[1] = 0x26;     /* Data read access-time-1 */
-        sd->csd[2] = 0x00;     /* Data read access-time-2 */
-        sd->csd[3] = 0x5a;     /* Max. data transfer rate */
-        sd->csd[4] = 0x5f;     /* Card Command Classes */
-        sd->csd[5] = 0x50 |    /* Max. read data block length */
-            HWBLOCK_SHIFT;
-        sd->csd[6] = 0xe0 |    /* Partial block for read allowed */
-            ((csize >> 10) & 0x03);
-        sd->csd[7] = 0x00 |    /* Device size */
-            ((csize >> 2) & 0xff);
-        sd->csd[8] = 0x3f |    /* Max. read current */
-            ((csize << 6) & 0xc0);
-        sd->csd[9] = 0xfc |    /* Max. write current */
-            ((CMULT_SHIFT - 2) >> 1);
-        sd->csd[10] = 0x40 |   /* Erase sector size */
-            (((CMULT_SHIFT - 2) << 7) & 0x80) | (sectsize >> 1);
-        sd->csd[11] = 0x00 |   /* Write protect group size */
-            ((sectsize << 7) & 0x80) | wpsize;
-        sd->csd[12] = 0x90 |   /* Write speed factor */
-            (HWBLOCK_SHIFT >> 2);
-        sd->csd[13] = 0x20 |   /* Max. write data block length */
-            ((HWBLOCK_SHIFT << 6) & 0xc0);
-        sd->csd[14] = 0x00;    /* File format group */
-        sd->csd[15] = (sd_crc7(sd->csd, 15) << 1) | 1;
-    } else {                   /* SDHC */
-        size /= 512 * 1024;
-        size -= 1;
-        sd->csd[0] = 0x40;
-        sd->csd[1] = 0x0e;
-        sd->csd[2] = 0x00;
-        sd->csd[3] = 0x32;
-        sd->csd[4] = 0x5b;
-        sd->csd[5] = 0x59;
-        sd->csd[6] = 0x00;
-        sd->csd[7] = (size >> 16) & 0xff;
-        sd->csd[8] = (size >> 8) & 0xff;
-        sd->csd[9] = (size & 0xff);
-        sd->csd[10] = 0x7f;
-        sd->csd[11] = 0x80;
-        sd->csd[12] = 0x0a;
-        sd->csd[13] = 0x40;
-        sd->csd[14] = 0x00;
-        sd->csd[15] = 0x00;
-        sd->ocr |= 1 << 30;    /* High Capacity SD Memort Card */
-    }
-}
-
-static void sd_set_rca(SDState *sd)
-{
-    sd->rca += 0x4567;
-}
-
-/* Card status bits, split by clear condition:
- * A : According to the card current state
- * B : Always related to the previous command
- * C : Cleared by read
- */
-#define CARD_STATUS_A  0x02004100
-#define CARD_STATUS_B  0x00c01e00
-#define CARD_STATUS_C  0xfd39a028
-
-static void sd_set_cardstatus(SDState *sd)
-{
-    sd->card_status = 0x00000100;
-}
-
-static void sd_set_sdstatus(SDState *sd)
-{
-    memset(sd->sd_status, 0, 64);
-}
-
-static int sd_req_crc_validate(SDRequest *req)
-{
-    uint8_t buffer[5];
-    buffer[0] = 0x40 | req->cmd;
-    buffer[1] = (req->arg >> 24) & 0xff;
-    buffer[2] = (req->arg >> 16) & 0xff;
-    buffer[3] = (req->arg >> 8) & 0xff;
-    buffer[4] = (req->arg >> 0) & 0xff;
-    return 0;
-    return sd_crc7(buffer, 5) != req->crc;     /* TODO */
-}
-
-static void sd_response_r1_make(SDState *sd, uint8_t *response)
-{
-    uint32_t status = sd->card_status;
-    /* Clear the "clear on read" status bits */
-    sd->card_status &= ~CARD_STATUS_C;
-
-    response[0] = (status >> 24) & 0xff;
-    response[1] = (status >> 16) & 0xff;
-    response[2] = (status >> 8) & 0xff;
-    response[3] = (status >> 0) & 0xff;
-}
-
-static void sd_response_r3_make(SDState *sd, uint8_t *response)
-{
-    response[0] = (sd->ocr >> 24) & 0xff;
-    response[1] = (sd->ocr >> 16) & 0xff;
-    response[2] = (sd->ocr >> 8) & 0xff;
-    response[3] = (sd->ocr >> 0) & 0xff;
-}
-
-static void sd_response_r6_make(SDState *sd, uint8_t *response)
-{
-    uint16_t arg;
-    uint16_t status;
-
-    arg = sd->rca;
-    status = ((sd->card_status >> 8) & 0xc000) |
-             ((sd->card_status >> 6) & 0x2000) |
-              (sd->card_status & 0x1fff);
-    sd->card_status &= ~(CARD_STATUS_C & 0xc81fff);
-
-    response[0] = (arg >> 8) & 0xff;
-    response[1] = arg & 0xff;
-    response[2] = (status >> 8) & 0xff;
-    response[3] = status & 0xff;
-}
-
-static void sd_response_r7_make(SDState *sd, uint8_t *response)
-{
-    response[0] = (sd->vhs >> 24) & 0xff;
-    response[1] = (sd->vhs >> 16) & 0xff;
-    response[2] = (sd->vhs >>  8) & 0xff;
-    response[3] = (sd->vhs >>  0) & 0xff;
-}
-
-static inline uint64_t sd_addr_to_wpnum(uint64_t addr)
-{
-    return addr >> (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT);
-}
-
-static void sd_reset(SDState *sd, BlockDriverState *bdrv)
-{
-    uint64_t size;
-    uint64_t sect;
-
-    if (bdrv) {
-        bdrv_get_geometry(bdrv, &sect);
-    } else {
-        sect = 0;
-    }
-    size = sect << 9;
-
-    sect = sd_addr_to_wpnum(size) + 1;
-
-    sd->state = sd_idle_state;
-    sd->rca = 0x0000;
-    sd_set_ocr(sd);
-    sd_set_scr(sd);
-    sd_set_cid(sd);
-    sd_set_csd(sd, size);
-    sd_set_cardstatus(sd);
-    sd_set_sdstatus(sd);
-
-    sd->bdrv = bdrv;
-
-    if (sd->wp_groups)
-        g_free(sd->wp_groups);
-    sd->wp_switch = bdrv ? bdrv_is_read_only(bdrv) : false;
-    sd->wpgrps_size = sect;
-    sd->wp_groups = bitmap_new(sd->wpgrps_size);
-    memset(sd->function_group, 0, sizeof(sd->function_group));
-    sd->erase_start = 0;
-    sd->erase_end = 0;
-    sd->size = size;
-    sd->blk_len = 0x200;
-    sd->pwd_len = 0;
-    sd->expecting_acmd = false;
-}
-
-static void sd_cardchange(void *opaque, bool load)
-{
-    SDState *sd = opaque;
-
-    qemu_set_irq(sd->inserted_cb, bdrv_is_inserted(sd->bdrv));
-    if (bdrv_is_inserted(sd->bdrv)) {
-        sd_reset(sd, sd->bdrv);
-        qemu_set_irq(sd->readonly_cb, sd->wp_switch);
-    }
-}
-
-static const BlockDevOps sd_block_ops = {
-    .change_media_cb = sd_cardchange,
-};
-
-static const VMStateDescription sd_vmstate = {
-    .name = "sd-card",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT32(mode, SDState),
-        VMSTATE_INT32(state, SDState),
-        VMSTATE_UINT8_ARRAY(cid, SDState, 16),
-        VMSTATE_UINT8_ARRAY(csd, SDState, 16),
-        VMSTATE_UINT16(rca, SDState),
-        VMSTATE_UINT32(card_status, SDState),
-        VMSTATE_PARTIAL_BUFFER(sd_status, SDState, 1),
-        VMSTATE_UINT32(vhs, SDState),
-        VMSTATE_BITMAP(wp_groups, SDState, 0, wpgrps_size),
-        VMSTATE_UINT32(blk_len, SDState),
-        VMSTATE_UINT32(erase_start, SDState),
-        VMSTATE_UINT32(erase_end, SDState),
-        VMSTATE_UINT8_ARRAY(pwd, SDState, 16),
-        VMSTATE_UINT32(pwd_len, SDState),
-        VMSTATE_UINT8_ARRAY(function_group, SDState, 6),
-        VMSTATE_UINT8(current_cmd, SDState),
-        VMSTATE_BOOL(expecting_acmd, SDState),
-        VMSTATE_UINT32(blk_written, SDState),
-        VMSTATE_UINT64(data_start, SDState),
-        VMSTATE_UINT32(data_offset, SDState),
-        VMSTATE_UINT8_ARRAY(data, SDState, 512),
-        VMSTATE_BUFFER_UNSAFE(buf, SDState, 1, 512),
-        VMSTATE_BOOL(enable, SDState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-/* We do not model the chip select pin, so allow the board to select
-   whether card should be in SSI or MMC/SD mode.  It is also up to the
-   board to ensure that ssi transfers only occur when the chip select
-   is asserted.  */
-SDState *sd_init(BlockDriverState *bs, bool is_spi)
-{
-    SDState *sd;
-
-    sd = (SDState *) g_malloc0(sizeof(SDState));
-    sd->buf = qemu_blockalign(bs, 512);
-    sd->spi = is_spi;
-    sd->enable = true;
-    sd_reset(sd, bs);
-    if (sd->bdrv) {
-        bdrv_attach_dev_nofail(sd->bdrv, sd);
-        bdrv_set_dev_ops(sd->bdrv, &sd_block_ops, sd);
-    }
-    vmstate_register(NULL, -1, &sd_vmstate, sd);
-    return sd;
-}
-
-void sd_set_cb(SDState *sd, qemu_irq readonly, qemu_irq insert)
-{
-    sd->readonly_cb = readonly;
-    sd->inserted_cb = insert;
-    qemu_set_irq(readonly, sd->bdrv ? bdrv_is_read_only(sd->bdrv) : 0);
-    qemu_set_irq(insert, sd->bdrv ? bdrv_is_inserted(sd->bdrv) : 0);
-}
-
-static void sd_erase(SDState *sd)
-{
-    int i;
-    uint64_t erase_start = sd->erase_start;
-    uint64_t erase_end = sd->erase_end;
-
-    if (!sd->erase_start || !sd->erase_end) {
-        sd->card_status |= ERASE_SEQ_ERROR;
-        return;
-    }
-
-    if (extract32(sd->ocr, OCR_CCS_BITN, 1)) {
-        /* High capacity memory card: erase units are 512 byte blocks */
-        erase_start *= 512;
-        erase_end *= 512;
-    }
-
-    erase_start = sd_addr_to_wpnum(erase_start);
-    erase_end = sd_addr_to_wpnum(erase_end);
-    sd->erase_start = 0;
-    sd->erase_end = 0;
-    sd->csd[14] |= 0x40;
-
-    for (i = erase_start; i <= erase_end; i++) {
-        if (test_bit(i, sd->wp_groups)) {
-            sd->card_status |= WP_ERASE_SKIP;
-        }
-    }
-}
-
-static uint32_t sd_wpbits(SDState *sd, uint64_t addr)
-{
-    uint32_t i, wpnum;
-    uint32_t ret = 0;
-
-    wpnum = sd_addr_to_wpnum(addr);
-
-    for (i = 0; i < 32; i++, wpnum++, addr += WPGROUP_SIZE) {
-        if (addr < sd->size && test_bit(wpnum, sd->wp_groups)) {
-            ret |= (1 << i);
-        }
-    }
-
-    return ret;
-}
-
-static void sd_function_switch(SDState *sd, uint32_t arg)
-{
-    int i, mode, new_func, crc;
-    mode = !!(arg & 0x80000000);
-
-    sd->data[0] = 0x00;                /* Maximum current consumption */
-    sd->data[1] = 0x01;
-    sd->data[2] = 0x80;                /* Supported group 6 functions */
-    sd->data[3] = 0x01;
-    sd->data[4] = 0x80;                /* Supported group 5 functions */
-    sd->data[5] = 0x01;
-    sd->data[6] = 0x80;                /* Supported group 4 functions */
-    sd->data[7] = 0x01;
-    sd->data[8] = 0x80;                /* Supported group 3 functions */
-    sd->data[9] = 0x01;
-    sd->data[10] = 0x80;       /* Supported group 2 functions */
-    sd->data[11] = 0x43;
-    sd->data[12] = 0x80;       /* Supported group 1 functions */
-    sd->data[13] = 0x03;
-    for (i = 0; i < 6; i ++) {
-        new_func = (arg >> (i * 4)) & 0x0f;
-        if (mode && new_func != 0x0f)
-            sd->function_group[i] = new_func;
-        sd->data[14 + (i >> 1)] = new_func << ((i * 4) & 4);
-    }
-    memset(&sd->data[17], 0, 47);
-    crc = sd_crc16(sd->data, 64);
-    sd->data[65] = crc >> 8;
-    sd->data[66] = crc & 0xff;
-}
-
-static inline bool sd_wp_addr(SDState *sd, uint64_t addr)
-{
-    return test_bit(sd_addr_to_wpnum(addr), sd->wp_groups);
-}
-
-static void sd_lock_command(SDState *sd)
-{
-    int erase, lock, clr_pwd, set_pwd, pwd_len;
-    erase = !!(sd->data[0] & 0x08);
-    lock = sd->data[0] & 0x04;
-    clr_pwd = sd->data[0] & 0x02;
-    set_pwd = sd->data[0] & 0x01;
-
-    if (sd->blk_len > 1)
-        pwd_len = sd->data[1];
-    else
-        pwd_len = 0;
-
-    if (erase) {
-        if (!(sd->card_status & CARD_IS_LOCKED) || sd->blk_len > 1 ||
-                        set_pwd || clr_pwd || lock || sd->wp_switch ||
-                        (sd->csd[14] & 0x20)) {
-            sd->card_status |= LOCK_UNLOCK_FAILED;
-            return;
-        }
-        bitmap_zero(sd->wp_groups, sd->wpgrps_size);
-        sd->csd[14] &= ~0x10;
-        sd->card_status &= ~CARD_IS_LOCKED;
-        sd->pwd_len = 0;
-        /* Erasing the entire card here! */
-        fprintf(stderr, "SD: Card force-erased by CMD42\n");
-        return;
-    }
-
-    if (sd->blk_len < 2 + pwd_len ||
-                    pwd_len <= sd->pwd_len ||
-                    pwd_len > sd->pwd_len + 16) {
-        sd->card_status |= LOCK_UNLOCK_FAILED;
-        return;
-    }
-
-    if (sd->pwd_len && memcmp(sd->pwd, sd->data + 2, sd->pwd_len)) {
-        sd->card_status |= LOCK_UNLOCK_FAILED;
-        return;
-    }
-
-    pwd_len -= sd->pwd_len;
-    if ((pwd_len && !set_pwd) ||
-                    (clr_pwd && (set_pwd || lock)) ||
-                    (lock && !sd->pwd_len && !set_pwd) ||
-                    (!set_pwd && !clr_pwd &&
-                     (((sd->card_status & CARD_IS_LOCKED) && lock) ||
-                      (!(sd->card_status & CARD_IS_LOCKED) && !lock)))) {
-        sd->card_status |= LOCK_UNLOCK_FAILED;
-        return;
-    }
-
-    if (set_pwd) {
-        memcpy(sd->pwd, sd->data + 2 + sd->pwd_len, pwd_len);
-        sd->pwd_len = pwd_len;
-    }
-
-    if (clr_pwd) {
-        sd->pwd_len = 0;
-    }
-
-    if (lock)
-        sd->card_status |= CARD_IS_LOCKED;
-    else
-        sd->card_status &= ~CARD_IS_LOCKED;
-}
-
-static sd_rsp_type_t sd_normal_command(SDState *sd,
-                                       SDRequest req)
-{
-    uint32_t rca = 0x0000;
-    uint64_t addr = (sd->ocr & (1 << 30)) ? (uint64_t) req.arg << 9 : req.arg;
-
-    /* Not interpreting this as an app command */
-    sd->card_status &= ~APP_CMD;
-
-    if (sd_cmd_type[req.cmd] == sd_ac || sd_cmd_type[req.cmd] == sd_adtc)
-        rca = req.arg >> 16;
-
-    DPRINTF("CMD%d 0x%08x state %d\n", req.cmd, req.arg, sd->state);
-    switch (req.cmd) {
-    /* Basic commands (Class 0 and Class 1) */
-    case 0:    /* CMD0:   GO_IDLE_STATE */
-        switch (sd->state) {
-        case sd_inactive_state:
-            return sd->spi ? sd_r1 : sd_r0;
-
-        default:
-            sd->state = sd_idle_state;
-            sd_reset(sd, sd->bdrv);
-            return sd->spi ? sd_r1 : sd_r0;
-        }
-        break;
-
-    case 1:    /* CMD1:   SEND_OP_CMD */
-        if (!sd->spi)
-            goto bad_cmd;
-
-        sd->state = sd_transfer_state;
-        return sd_r1;
-
-    case 2:    /* CMD2:   ALL_SEND_CID */
-        if (sd->spi)
-            goto bad_cmd;
-        switch (sd->state) {
-        case sd_ready_state:
-            sd->state = sd_identification_state;
-            return sd_r2_i;
-
-        default:
-            break;
-        }
-        break;
-
-    case 3:    /* CMD3:   SEND_RELATIVE_ADDR */
-        if (sd->spi)
-            goto bad_cmd;
-        switch (sd->state) {
-        case sd_identification_state:
-        case sd_standby_state:
-            sd->state = sd_standby_state;
-            sd_set_rca(sd);
-            return sd_r6;
-
-        default:
-            break;
-        }
-        break;
-
-    case 4:    /* CMD4:   SEND_DSR */
-        if (sd->spi)
-            goto bad_cmd;
-        switch (sd->state) {
-        case sd_standby_state:
-            break;
-
-        default:
-            break;
-        }
-        break;
-
-    case 5: /* CMD5: reserved for SDIO cards */
-        return sd_illegal;
-
-    case 6:    /* CMD6:   SWITCH_FUNCTION */
-        if (sd->spi)
-            goto bad_cmd;
-        switch (sd->mode) {
-        case sd_data_transfer_mode:
-            sd_function_switch(sd, req.arg);
-            sd->state = sd_sendingdata_state;
-            sd->data_start = 0;
-            sd->data_offset = 0;
-            return sd_r1;
-
-        default:
-            break;
-        }
-        break;
-
-    case 7:    /* CMD7:   SELECT/DESELECT_CARD */
-        if (sd->spi)
-            goto bad_cmd;
-        switch (sd->state) {
-        case sd_standby_state:
-            if (sd->rca != rca)
-                return sd_r0;
-
-            sd->state = sd_transfer_state;
-            return sd_r1b;
-
-        case sd_transfer_state:
-        case sd_sendingdata_state:
-            if (sd->rca == rca)
-                break;
-
-            sd->state = sd_standby_state;
-            return sd_r1b;
-
-        case sd_disconnect_state:
-            if (sd->rca != rca)
-                return sd_r0;
-
-            sd->state = sd_programming_state;
-            return sd_r1b;
-
-        case sd_programming_state:
-            if (sd->rca == rca)
-                break;
-
-            sd->state = sd_disconnect_state;
-            return sd_r1b;
-
-        default:
-            break;
-        }
-        break;
-
-    case 8:    /* CMD8:   SEND_IF_COND */
-        /* Physical Layer Specification Version 2.00 command */
-        switch (sd->state) {
-        case sd_idle_state:
-            sd->vhs = 0;
-
-            /* No response if not exactly one VHS bit is set.  */
-            if (!(req.arg >> 8) || (req.arg >> ffs(req.arg & ~0xff)))
-                return sd->spi ? sd_r7 : sd_r0;
-
-            /* Accept.  */
-            sd->vhs = req.arg;
-            return sd_r7;
-
-        default:
-            break;
-        }
-        break;
-
-    case 9:    /* CMD9:   SEND_CSD */
-        switch (sd->state) {
-        case sd_standby_state:
-            if (sd->rca != rca)
-                return sd_r0;
-
-            return sd_r2_s;
-
-        case sd_transfer_state:
-            if (!sd->spi)
-                break;
-            sd->state = sd_sendingdata_state;
-            memcpy(sd->data, sd->csd, 16);
-            sd->data_start = addr;
-            sd->data_offset = 0;
-            return sd_r1;
-
-        default:
-            break;
-        }
-        break;
-
-    case 10:   /* CMD10:  SEND_CID */
-        switch (sd->state) {
-        case sd_standby_state:
-            if (sd->rca != rca)
-                return sd_r0;
-
-            return sd_r2_i;
-
-        case sd_transfer_state:
-            if (!sd->spi)
-                break;
-            sd->state = sd_sendingdata_state;
-            memcpy(sd->data, sd->cid, 16);
-            sd->data_start = addr;
-            sd->data_offset = 0;
-            return sd_r1;
-
-        default:
-            break;
-        }
-        break;
-
-    case 11:   /* CMD11:  READ_DAT_UNTIL_STOP */
-        if (sd->spi)
-            goto bad_cmd;
-        switch (sd->state) {
-        case sd_transfer_state:
-            sd->state = sd_sendingdata_state;
-            sd->data_start = req.arg;
-            sd->data_offset = 0;
-
-            if (sd->data_start + sd->blk_len > sd->size)
-                sd->card_status |= ADDRESS_ERROR;
-            return sd_r0;
-
-        default:
-            break;
-        }
-        break;
-
-    case 12:   /* CMD12:  STOP_TRANSMISSION */
-        switch (sd->state) {
-        case sd_sendingdata_state:
-            sd->state = sd_transfer_state;
-            return sd_r1b;
-
-        case sd_receivingdata_state:
-            sd->state = sd_programming_state;
-            /* Bzzzzzzztt .... Operation complete.  */
-            sd->state = sd_transfer_state;
-            return sd_r1b;
-
-        default:
-            break;
-        }
-        break;
-
-    case 13:   /* CMD13:  SEND_STATUS */
-        switch (sd->mode) {
-        case sd_data_transfer_mode:
-            if (sd->rca != rca)
-                return sd_r0;
-
-            return sd_r1;
-
-        default:
-            break;
-        }
-        break;
-
-    case 15:   /* CMD15:  GO_INACTIVE_STATE */
-        if (sd->spi)
-            goto bad_cmd;
-        switch (sd->mode) {
-        case sd_data_transfer_mode:
-            if (sd->rca != rca)
-                return sd_r0;
-
-            sd->state = sd_inactive_state;
-            return sd_r0;
-
-        default:
-            break;
-        }
-        break;
-
-    /* Block read commands (Classs 2) */
-    case 16:   /* CMD16:  SET_BLOCKLEN */
-        switch (sd->state) {
-        case sd_transfer_state:
-            if (req.arg > (1 << HWBLOCK_SHIFT))
-                sd->card_status |= BLOCK_LEN_ERROR;
-            else
-                sd->blk_len = req.arg;
-
-            return sd_r1;
-
-        default:
-            break;
-        }
-        break;
-
-    case 17:   /* CMD17:  READ_SINGLE_BLOCK */
-        switch (sd->state) {
-        case sd_transfer_state:
-            sd->state = sd_sendingdata_state;
-            sd->data_start = addr;
-            sd->data_offset = 0;
-
-            if (sd->data_start + sd->blk_len > sd->size)
-                sd->card_status |= ADDRESS_ERROR;
-            return sd_r1;
-
-        default:
-            break;
-        }
-        break;
-
-    case 18:   /* CMD18:  READ_MULTIPLE_BLOCK */
-        switch (sd->state) {
-        case sd_transfer_state:
-            sd->state = sd_sendingdata_state;
-            sd->data_start = addr;
-            sd->data_offset = 0;
-
-            if (sd->data_start + sd->blk_len > sd->size)
-                sd->card_status |= ADDRESS_ERROR;
-            return sd_r1;
-
-        default:
-            break;
-        }
-        break;
-
-    /* Block write commands (Class 4) */
-    case 24:   /* CMD24:  WRITE_SINGLE_BLOCK */
-        if (sd->spi)
-            goto unimplemented_cmd;
-        switch (sd->state) {
-        case sd_transfer_state:
-            /* Writing in SPI mode not implemented.  */
-            if (sd->spi)
-                break;
-            sd->state = sd_receivingdata_state;
-            sd->data_start = addr;
-            sd->data_offset = 0;
-            sd->blk_written = 0;
-
-            if (sd->data_start + sd->blk_len > sd->size)
-                sd->card_status |= ADDRESS_ERROR;
-            if (sd_wp_addr(sd, sd->data_start))
-                sd->card_status |= WP_VIOLATION;
-            if (sd->csd[14] & 0x30)
-                sd->card_status |= WP_VIOLATION;
-            return sd_r1;
-
-        default:
-            break;
-        }
-        break;
-
-    case 25:   /* CMD25:  WRITE_MULTIPLE_BLOCK */
-        if (sd->spi)
-            goto unimplemented_cmd;
-        switch (sd->state) {
-        case sd_transfer_state:
-            /* Writing in SPI mode not implemented.  */
-            if (sd->spi)
-                break;
-            sd->state = sd_receivingdata_state;
-            sd->data_start = addr;
-            sd->data_offset = 0;
-            sd->blk_written = 0;
-
-            if (sd->data_start + sd->blk_len > sd->size)
-                sd->card_status |= ADDRESS_ERROR;
-            if (sd_wp_addr(sd, sd->data_start))
-                sd->card_status |= WP_VIOLATION;
-            if (sd->csd[14] & 0x30)
-                sd->card_status |= WP_VIOLATION;
-            return sd_r1;
-
-        default:
-            break;
-        }
-        break;
-
-    case 26:   /* CMD26:  PROGRAM_CID */
-        if (sd->spi)
-            goto bad_cmd;
-        switch (sd->state) {
-        case sd_transfer_state:
-            sd->state = sd_receivingdata_state;
-            sd->data_start = 0;
-            sd->data_offset = 0;
-            return sd_r1;
-
-        default:
-            break;
-        }
-        break;
-
-    case 27:   /* CMD27:  PROGRAM_CSD */
-        if (sd->spi)
-            goto unimplemented_cmd;
-        switch (sd->state) {
-        case sd_transfer_state:
-            sd->state = sd_receivingdata_state;
-            sd->data_start = 0;
-            sd->data_offset = 0;
-            return sd_r1;
-
-        default:
-            break;
-        }
-        break;
-
-    /* Write protection (Class 6) */
-    case 28:   /* CMD28:  SET_WRITE_PROT */
-        switch (sd->state) {
-        case sd_transfer_state:
-            if (addr >= sd->size) {
-                sd->card_status |= ADDRESS_ERROR;
-                return sd_r1b;
-            }
-
-            sd->state = sd_programming_state;
-            set_bit(sd_addr_to_wpnum(addr), sd->wp_groups);
-            /* Bzzzzzzztt .... Operation complete.  */
-            sd->state = sd_transfer_state;
-            return sd_r1b;
-
-        default:
-            break;
-        }
-        break;
-
-    case 29:   /* CMD29:  CLR_WRITE_PROT */
-        switch (sd->state) {
-        case sd_transfer_state:
-            if (addr >= sd->size) {
-                sd->card_status |= ADDRESS_ERROR;
-                return sd_r1b;
-            }
-
-            sd->state = sd_programming_state;
-            clear_bit(sd_addr_to_wpnum(addr), sd->wp_groups);
-            /* Bzzzzzzztt .... Operation complete.  */
-            sd->state = sd_transfer_state;
-            return sd_r1b;
-
-        default:
-            break;
-        }
-        break;
-
-    case 30:   /* CMD30:  SEND_WRITE_PROT */
-        switch (sd->state) {
-        case sd_transfer_state:
-            sd->state = sd_sendingdata_state;
-            *(uint32_t *) sd->data = sd_wpbits(sd, req.arg);
-            sd->data_start = addr;
-            sd->data_offset = 0;
-            return sd_r1b;
-
-        default:
-            break;
-        }
-        break;
-
-    /* Erase commands (Class 5) */
-    case 32:   /* CMD32:  ERASE_WR_BLK_START */
-        switch (sd->state) {
-        case sd_transfer_state:
-            sd->erase_start = req.arg;
-            return sd_r1;
-
-        default:
-            break;
-        }
-        break;
-
-    case 33:   /* CMD33:  ERASE_WR_BLK_END */
-        switch (sd->state) {
-        case sd_transfer_state:
-            sd->erase_end = req.arg;
-            return sd_r1;
-
-        default:
-            break;
-        }
-        break;
-
-    case 38:   /* CMD38:  ERASE */
-        switch (sd->state) {
-        case sd_transfer_state:
-            if (sd->csd[14] & 0x30) {
-                sd->card_status |= WP_VIOLATION;
-                return sd_r1b;
-            }
-
-            sd->state = sd_programming_state;
-            sd_erase(sd);
-            /* Bzzzzzzztt .... Operation complete.  */
-            sd->state = sd_transfer_state;
-            return sd_r1b;
-
-        default:
-            break;
-        }
-        break;
-
-    /* Lock card commands (Class 7) */
-    case 42:   /* CMD42:  LOCK_UNLOCK */
-        if (sd->spi)
-            goto unimplemented_cmd;
-        switch (sd->state) {
-        case sd_transfer_state:
-            sd->state = sd_receivingdata_state;
-            sd->data_start = 0;
-            sd->data_offset = 0;
-            return sd_r1;
-
-        default:
-            break;
-        }
-        break;
-
-    case 52:
-    case 53:
-        /* CMD52, CMD53: reserved for SDIO cards
-         * (see the SDIO Simplified Specification V2.0)
-         * Handle as illegal command but do not complain
-         * on stderr, as some OSes may use these in their
-         * probing for presence of an SDIO card.
-         */
-        return sd_illegal;
-
-    /* Application specific commands (Class 8) */
-    case 55:   /* CMD55:  APP_CMD */
-        if (sd->rca != rca)
-            return sd_r0;
-
-        sd->expecting_acmd = true;
-        sd->card_status |= APP_CMD;
-        return sd_r1;
-
-    case 56:   /* CMD56:  GEN_CMD */
-        fprintf(stderr, "SD: GEN_CMD 0x%08x\n", req.arg);
-
-        switch (sd->state) {
-        case sd_transfer_state:
-            sd->data_offset = 0;
-            if (req.arg & 1)
-                sd->state = sd_sendingdata_state;
-            else
-                sd->state = sd_receivingdata_state;
-            return sd_r1;
-
-        default:
-            break;
-        }
-        break;
-
-    default:
-    bad_cmd:
-        fprintf(stderr, "SD: Unknown CMD%i\n", req.cmd);
-        return sd_illegal;
-
-    unimplemented_cmd:
-        /* Commands that are recognised but not yet implemented in SPI mode.  */
-        fprintf(stderr, "SD: CMD%i not implemented in SPI mode\n", req.cmd);
-        return sd_illegal;
-    }
-
-    fprintf(stderr, "SD: CMD%i in a wrong state\n", req.cmd);
-    return sd_illegal;
-}
-
-static sd_rsp_type_t sd_app_command(SDState *sd,
-                                    SDRequest req)
-{
-    DPRINTF("ACMD%d 0x%08x\n", req.cmd, req.arg);
-    sd->card_status |= APP_CMD;
-    switch (req.cmd) {
-    case 6:    /* ACMD6:  SET_BUS_WIDTH */
-        switch (sd->state) {
-        case sd_transfer_state:
-            sd->sd_status[0] &= 0x3f;
-            sd->sd_status[0] |= (req.arg & 0x03) << 6;
-            return sd_r1;
-
-        default:
-            break;
-        }
-        break;
-
-    case 13:   /* ACMD13: SD_STATUS */
-        switch (sd->state) {
-        case sd_transfer_state:
-            sd->state = sd_sendingdata_state;
-            sd->data_start = 0;
-            sd->data_offset = 0;
-            return sd_r1;
-
-        default:
-            break;
-        }
-        break;
-
-    case 22:   /* ACMD22: SEND_NUM_WR_BLOCKS */
-        switch (sd->state) {
-        case sd_transfer_state:
-            *(uint32_t *) sd->data = sd->blk_written;
-
-            sd->state = sd_sendingdata_state;
-            sd->data_start = 0;
-            sd->data_offset = 0;
-            return sd_r1;
-
-        default:
-            break;
-        }
-        break;
-
-    case 23:   /* ACMD23: SET_WR_BLK_ERASE_COUNT */
-        switch (sd->state) {
-        case sd_transfer_state:
-            return sd_r1;
-
-        default:
-            break;
-        }
-        break;
-
-    case 41:   /* ACMD41: SD_APP_OP_COND */
-        if (sd->spi) {
-            /* SEND_OP_CMD */
-            sd->state = sd_transfer_state;
-            return sd_r1;
-        }
-        switch (sd->state) {
-        case sd_idle_state:
-            /* We accept any voltage.  10000 V is nothing.  */
-            if (req.arg)
-                sd->state = sd_ready_state;
-
-            return sd_r3;
-
-        default:
-            break;
-        }
-        break;
-
-    case 42:   /* ACMD42: SET_CLR_CARD_DETECT */
-        switch (sd->state) {
-        case sd_transfer_state:
-            /* Bringing in the 50KOhm pull-up resistor... Done.  */
-            return sd_r1;
-
-        default:
-            break;
-        }
-        break;
-
-    case 51:   /* ACMD51: SEND_SCR */
-        switch (sd->state) {
-        case sd_transfer_state:
-            sd->state = sd_sendingdata_state;
-            sd->data_start = 0;
-            sd->data_offset = 0;
-            return sd_r1;
-
-        default:
-            break;
-        }
-        break;
-
-    default:
-        /* Fall back to standard commands.  */
-        return sd_normal_command(sd, req);
-    }
-
-    fprintf(stderr, "SD: ACMD%i in a wrong state\n", req.cmd);
-    return sd_illegal;
-}
-
-static int cmd_valid_while_locked(SDState *sd, SDRequest *req)
-{
-    /* Valid commands in locked state:
-     * basic class (0)
-     * lock card class (7)
-     * CMD16
-     * implicitly, the ACMD prefix CMD55
-     * ACMD41 and ACMD42
-     * Anything else provokes an "illegal command" response.
-     */
-    if (sd->expecting_acmd) {
-        return req->cmd == 41 || req->cmd == 42;
-    }
-    if (req->cmd == 16 || req->cmd == 55) {
-        return 1;
-    }
-    return sd_cmd_class[req->cmd] == 0 || sd_cmd_class[req->cmd] == 7;
-}
-
-int sd_do_command(SDState *sd, SDRequest *req,
-                  uint8_t *response) {
-    int last_state;
-    sd_rsp_type_t rtype;
-    int rsplen;
-
-    if (!sd->bdrv || !bdrv_is_inserted(sd->bdrv) || !sd->enable) {
-        return 0;
-    }
-
-    if (sd_req_crc_validate(req)) {
-        sd->card_status |= COM_CRC_ERROR;
-        rtype = sd_illegal;
-        goto send_response;
-    }
-
-    if (sd->card_status & CARD_IS_LOCKED) {
-        if (!cmd_valid_while_locked(sd, req)) {
-            sd->card_status |= ILLEGAL_COMMAND;
-            sd->expecting_acmd = false;
-            fprintf(stderr, "SD: Card is locked\n");
-            rtype = sd_illegal;
-            goto send_response;
-        }
-    }
-
-    last_state = sd->state;
-    sd_set_mode(sd);
-
-    if (sd->expecting_acmd) {
-        sd->expecting_acmd = false;
-        rtype = sd_app_command(sd, *req);
-    } else {
-        rtype = sd_normal_command(sd, *req);
-    }
-
-    if (rtype == sd_illegal) {
-        sd->card_status |= ILLEGAL_COMMAND;
-    } else {
-        /* Valid command, we can update the 'state before command' bits.
-         * (Do this now so they appear in r1 responses.)
-         */
-        sd->current_cmd = req->cmd;
-        sd->card_status &= ~CURRENT_STATE;
-        sd->card_status |= (last_state << 9);
-    }
-
-send_response:
-    switch (rtype) {
-    case sd_r1:
-    case sd_r1b:
-        sd_response_r1_make(sd, response);
-        rsplen = 4;
-        break;
-
-    case sd_r2_i:
-        memcpy(response, sd->cid, sizeof(sd->cid));
-        rsplen = 16;
-        break;
-
-    case sd_r2_s:
-        memcpy(response, sd->csd, sizeof(sd->csd));
-        rsplen = 16;
-        break;
-
-    case sd_r3:
-        sd_response_r3_make(sd, response);
-        rsplen = 4;
-        break;
-
-    case sd_r6:
-        sd_response_r6_make(sd, response);
-        rsplen = 4;
-        break;
-
-    case sd_r7:
-        sd_response_r7_make(sd, response);
-        rsplen = 4;
-        break;
-
-    case sd_r0:
-    case sd_illegal:
-    default:
-        rsplen = 0;
-        break;
-    }
-
-    if (rtype != sd_illegal) {
-        /* Clear the "clear on valid command" status bits now we've
-         * sent any response
-         */
-        sd->card_status &= ~CARD_STATUS_B;
-    }
-
-#ifdef DEBUG_SD
-    if (rsplen) {
-        int i;
-        DPRINTF("Response:");
-        for (i = 0; i < rsplen; i++)
-            fprintf(stderr, " %02x", response[i]);
-        fprintf(stderr, " state %d\n", sd->state);
-    } else {
-        DPRINTF("No response %d\n", sd->state);
-    }
-#endif
-
-    return rsplen;
-}
-
-static void sd_blk_read(SDState *sd, uint64_t addr, uint32_t len)
-{
-    uint64_t end = addr + len;
-
-    DPRINTF("sd_blk_read: addr = 0x%08llx, len = %d\n",
-            (unsigned long long) addr, len);
-    if (!sd->bdrv || bdrv_read(sd->bdrv, addr >> 9, sd->buf, 1) < 0) {
-        fprintf(stderr, "sd_blk_read: read error on host side\n");
-        return;
-    }
-
-    if (end > (addr & ~511) + 512) {
-        memcpy(sd->data, sd->buf + (addr & 511), 512 - (addr & 511));
-
-        if (bdrv_read(sd->bdrv, end >> 9, sd->buf, 1) < 0) {
-            fprintf(stderr, "sd_blk_read: read error on host side\n");
-            return;
-        }
-        memcpy(sd->data + 512 - (addr & 511), sd->buf, end & 511);
-    } else
-        memcpy(sd->data, sd->buf + (addr & 511), len);
-}
-
-static void sd_blk_write(SDState *sd, uint64_t addr, uint32_t len)
-{
-    uint64_t end = addr + len;
-
-    if ((addr & 511) || len < 512)
-        if (!sd->bdrv || bdrv_read(sd->bdrv, addr >> 9, sd->buf, 1) < 0) {
-            fprintf(stderr, "sd_blk_write: read error on host side\n");
-            return;
-        }
-
-    if (end > (addr & ~511) + 512) {
-        memcpy(sd->buf + (addr & 511), sd->data, 512 - (addr & 511));
-        if (bdrv_write(sd->bdrv, addr >> 9, sd->buf, 1) < 0) {
-            fprintf(stderr, "sd_blk_write: write error on host side\n");
-            return;
-        }
-
-        if (bdrv_read(sd->bdrv, end >> 9, sd->buf, 1) < 0) {
-            fprintf(stderr, "sd_blk_write: read error on host side\n");
-            return;
-        }
-        memcpy(sd->buf, sd->data + 512 - (addr & 511), end & 511);
-        if (bdrv_write(sd->bdrv, end >> 9, sd->buf, 1) < 0) {
-            fprintf(stderr, "sd_blk_write: write error on host side\n");
-        }
-    } else {
-        memcpy(sd->buf + (addr & 511), sd->data, len);
-        if (!sd->bdrv || bdrv_write(sd->bdrv, addr >> 9, sd->buf, 1) < 0) {
-            fprintf(stderr, "sd_blk_write: write error on host side\n");
-        }
-    }
-}
-
-#define BLK_READ_BLOCK(a, len) sd_blk_read(sd, a, len)
-#define BLK_WRITE_BLOCK(a, len)        sd_blk_write(sd, a, len)
-#define APP_READ_BLOCK(a, len) memset(sd->data, 0xec, len)
-#define APP_WRITE_BLOCK(a, len)
-
-void sd_write_data(SDState *sd, uint8_t value)
-{
-    int i;
-
-    if (!sd->bdrv || !bdrv_is_inserted(sd->bdrv) || !sd->enable)
-        return;
-
-    if (sd->state != sd_receivingdata_state) {
-        fprintf(stderr, "sd_write_data: not in Receiving-Data state\n");
-        return;
-    }
-
-    if (sd->card_status & (ADDRESS_ERROR | WP_VIOLATION))
-        return;
-
-    switch (sd->current_cmd) {
-    case 24:   /* CMD24:  WRITE_SINGLE_BLOCK */
-        sd->data[sd->data_offset ++] = value;
-        if (sd->data_offset >= sd->blk_len) {
-            /* TODO: Check CRC before committing */
-            sd->state = sd_programming_state;
-            BLK_WRITE_BLOCK(sd->data_start, sd->data_offset);
-            sd->blk_written ++;
-            sd->csd[14] |= 0x40;
-            /* Bzzzzzzztt .... Operation complete.  */
-            sd->state = sd_transfer_state;
-        }
-        break;
-
-    case 25:   /* CMD25:  WRITE_MULTIPLE_BLOCK */
-        if (sd->data_offset == 0) {
-            /* Start of the block - lets check the address is valid */
-            if (sd->data_start + sd->blk_len > sd->size) {
-                sd->card_status |= ADDRESS_ERROR;
-                break;
-            }
-            if (sd_wp_addr(sd, sd->data_start)) {
-                sd->card_status |= WP_VIOLATION;
-                break;
-            }
-        }
-        sd->data[sd->data_offset++] = value;
-        if (sd->data_offset >= sd->blk_len) {
-            /* TODO: Check CRC before committing */
-            sd->state = sd_programming_state;
-            BLK_WRITE_BLOCK(sd->data_start, sd->data_offset);
-            sd->blk_written++;
-            sd->data_start += sd->blk_len;
-            sd->data_offset = 0;
-            sd->csd[14] |= 0x40;
-
-            /* Bzzzzzzztt .... Operation complete.  */
-            sd->state = sd_receivingdata_state;
-        }
-        break;
-
-    case 26:   /* CMD26:  PROGRAM_CID */
-        sd->data[sd->data_offset ++] = value;
-        if (sd->data_offset >= sizeof(sd->cid)) {
-            /* TODO: Check CRC before committing */
-            sd->state = sd_programming_state;
-            for (i = 0; i < sizeof(sd->cid); i ++)
-                if ((sd->cid[i] | 0x00) != sd->data[i])
-                    sd->card_status |= CID_CSD_OVERWRITE;
-
-            if (!(sd->card_status & CID_CSD_OVERWRITE))
-                for (i = 0; i < sizeof(sd->cid); i ++) {
-                    sd->cid[i] |= 0x00;
-                    sd->cid[i] &= sd->data[i];
-                }
-            /* Bzzzzzzztt .... Operation complete.  */
-            sd->state = sd_transfer_state;
-        }
-        break;
-
-    case 27:   /* CMD27:  PROGRAM_CSD */
-        sd->data[sd->data_offset ++] = value;
-        if (sd->data_offset >= sizeof(sd->csd)) {
-            /* TODO: Check CRC before committing */
-            sd->state = sd_programming_state;
-            for (i = 0; i < sizeof(sd->csd); i ++)
-                if ((sd->csd[i] | sd_csd_rw_mask[i]) !=
-                    (sd->data[i] | sd_csd_rw_mask[i]))
-                    sd->card_status |= CID_CSD_OVERWRITE;
-
-            /* Copy flag (OTP) & Permanent write protect */
-            if (sd->csd[14] & ~sd->data[14] & 0x60)
-                sd->card_status |= CID_CSD_OVERWRITE;
-
-            if (!(sd->card_status & CID_CSD_OVERWRITE))
-                for (i = 0; i < sizeof(sd->csd); i ++) {
-                    sd->csd[i] |= sd_csd_rw_mask[i];
-                    sd->csd[i] &= sd->data[i];
-                }
-            /* Bzzzzzzztt .... Operation complete.  */
-            sd->state = sd_transfer_state;
-        }
-        break;
-
-    case 42:   /* CMD42:  LOCK_UNLOCK */
-        sd->data[sd->data_offset ++] = value;
-        if (sd->data_offset >= sd->blk_len) {
-            /* TODO: Check CRC before committing */
-            sd->state = sd_programming_state;
-            sd_lock_command(sd);
-            /* Bzzzzzzztt .... Operation complete.  */
-            sd->state = sd_transfer_state;
-        }
-        break;
-
-    case 56:   /* CMD56:  GEN_CMD */
-        sd->data[sd->data_offset ++] = value;
-        if (sd->data_offset >= sd->blk_len) {
-            APP_WRITE_BLOCK(sd->data_start, sd->data_offset);
-            sd->state = sd_transfer_state;
-        }
-        break;
-
-    default:
-        fprintf(stderr, "sd_write_data: unknown command\n");
-        break;
-    }
-}
-
-uint8_t sd_read_data(SDState *sd)
-{
-    /* TODO: Append CRCs */
-    uint8_t ret;
-    int io_len;
-
-    if (!sd->bdrv || !bdrv_is_inserted(sd->bdrv) || !sd->enable)
-        return 0x00;
-
-    if (sd->state != sd_sendingdata_state) {
-        fprintf(stderr, "sd_read_data: not in Sending-Data state\n");
-        return 0x00;
-    }
-
-    if (sd->card_status & (ADDRESS_ERROR | WP_VIOLATION))
-        return 0x00;
-
-    io_len = (sd->ocr & (1 << 30)) ? 512 : sd->blk_len;
-
-    switch (sd->current_cmd) {
-    case 6:    /* CMD6:   SWITCH_FUNCTION */
-        ret = sd->data[sd->data_offset ++];
-
-        if (sd->data_offset >= 64)
-            sd->state = sd_transfer_state;
-        break;
-
-    case 9:    /* CMD9:   SEND_CSD */
-    case 10:   /* CMD10:  SEND_CID */
-        ret = sd->data[sd->data_offset ++];
-
-        if (sd->data_offset >= 16)
-            sd->state = sd_transfer_state;
-        break;
-
-    case 11:   /* CMD11:  READ_DAT_UNTIL_STOP */
-        if (sd->data_offset == 0)
-            BLK_READ_BLOCK(sd->data_start, io_len);
-        ret = sd->data[sd->data_offset ++];
-
-        if (sd->data_offset >= io_len) {
-            sd->data_start += io_len;
-            sd->data_offset = 0;
-            if (sd->data_start + io_len > sd->size) {
-                sd->card_status |= ADDRESS_ERROR;
-                break;
-            }
-        }
-        break;
-
-    case 13:   /* ACMD13: SD_STATUS */
-        ret = sd->sd_status[sd->data_offset ++];
-
-        if (sd->data_offset >= sizeof(sd->sd_status))
-            sd->state = sd_transfer_state;
-        break;
-
-    case 17:   /* CMD17:  READ_SINGLE_BLOCK */
-        if (sd->data_offset == 0)
-            BLK_READ_BLOCK(sd->data_start, io_len);
-        ret = sd->data[sd->data_offset ++];
-
-        if (sd->data_offset >= io_len)
-            sd->state = sd_transfer_state;
-        break;
-
-    case 18:   /* CMD18:  READ_MULTIPLE_BLOCK */
-        if (sd->data_offset == 0)
-            BLK_READ_BLOCK(sd->data_start, io_len);
-        ret = sd->data[sd->data_offset ++];
-
-        if (sd->data_offset >= io_len) {
-            sd->data_start += io_len;
-            sd->data_offset = 0;
-            if (sd->data_start + io_len > sd->size) {
-                sd->card_status |= ADDRESS_ERROR;
-                break;
-            }
-        }
-        break;
-
-    case 22:   /* ACMD22: SEND_NUM_WR_BLOCKS */
-        ret = sd->data[sd->data_offset ++];
-
-        if (sd->data_offset >= 4)
-            sd->state = sd_transfer_state;
-        break;
-
-    case 30:   /* CMD30:  SEND_WRITE_PROT */
-        ret = sd->data[sd->data_offset ++];
-
-        if (sd->data_offset >= 4)
-            sd->state = sd_transfer_state;
-        break;
-
-    case 51:   /* ACMD51: SEND_SCR */
-        ret = sd->scr[sd->data_offset ++];
-
-        if (sd->data_offset >= sizeof(sd->scr))
-            sd->state = sd_transfer_state;
-        break;
-
-    case 56:   /* CMD56:  GEN_CMD */
-        if (sd->data_offset == 0)
-            APP_READ_BLOCK(sd->data_start, sd->blk_len);
-        ret = sd->data[sd->data_offset ++];
-
-        if (sd->data_offset >= sd->blk_len)
-            sd->state = sd_transfer_state;
-        break;
-
-    default:
-        fprintf(stderr, "sd_read_data: unknown command\n");
-        return 0x00;
-    }
-
-    return ret;
-}
-
-bool sd_data_ready(SDState *sd)
-{
-    return sd->state == sd_sendingdata_state;
-}
-
-void sd_enable(SDState *sd, bool enable)
-{
-    sd->enable = enable;
-}
diff --git a/hw/sd.h b/hw/sd.h
deleted file mode 100644 (file)
index d9b97e4..0000000
--- a/hw/sd.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * SD Memory Card emulation.  Mostly correct for MMC too.
- *
- * Copyright (c) 2006 Andrzej Zaborowski  <balrog@zabor.org>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS''
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
- * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-#ifndef __hw_sd_h
-#define __hw_sd_h              1
-
-#define OUT_OF_RANGE           (1 << 31)
-#define ADDRESS_ERROR          (1 << 30)
-#define BLOCK_LEN_ERROR                (1 << 29)
-#define ERASE_SEQ_ERROR                (1 << 28)
-#define ERASE_PARAM            (1 << 27)
-#define WP_VIOLATION           (1 << 26)
-#define CARD_IS_LOCKED         (1 << 25)
-#define LOCK_UNLOCK_FAILED     (1 << 24)
-#define COM_CRC_ERROR          (1 << 23)
-#define ILLEGAL_COMMAND                (1 << 22)
-#define CARD_ECC_FAILED                (1 << 21)
-#define CC_ERROR               (1 << 20)
-#define SD_ERROR               (1 << 19)
-#define CID_CSD_OVERWRITE      (1 << 16)
-#define WP_ERASE_SKIP          (1 << 15)
-#define CARD_ECC_DISABLED      (1 << 14)
-#define ERASE_RESET            (1 << 13)
-#define CURRENT_STATE          (7 << 9)
-#define READY_FOR_DATA         (1 << 8)
-#define APP_CMD                        (1 << 5)
-#define AKE_SEQ_ERROR          (1 << 3)
-#define OCR_CCS_BITN        30
-
-typedef enum {
-    sd_none = -1,
-    sd_bc = 0, /* broadcast -- no response */
-    sd_bcr,    /* broadcast with response */
-    sd_ac,     /* addressed -- no data transfer */
-    sd_adtc,   /* addressed with data transfer */
-} sd_cmd_type_t;
-
-typedef struct {
-    uint8_t cmd;
-    uint32_t arg;
-    uint8_t crc;
-} SDRequest;
-
-typedef struct SDState SDState;
-
-SDState *sd_init(BlockDriverState *bs, bool is_spi);
-int sd_do_command(SDState *sd, SDRequest *req,
-                  uint8_t *response);
-void sd_write_data(SDState *sd, uint8_t value);
-uint8_t sd_read_data(SDState *sd);
-void sd_set_cb(SDState *sd, qemu_irq readonly, qemu_irq insert);
-bool sd_data_ready(SDState *sd);
-void sd_enable(SDState *sd, bool enable);
-
-#endif /* __hw_sd_h */
diff --git a/hw/sd/Makefile.objs b/hw/sd/Makefile.objs
new file mode 100644 (file)
index 0000000..f1aed83
--- /dev/null
@@ -0,0 +1,8 @@
+common-obj-$(CONFIG_PL181) += pl181.o
+common-obj-$(CONFIG_SSI_SD) += ssi-sd.o
+common-obj-$(CONFIG_SD) += sd.o
+common-obj-$(CONFIG_SDHCI) += sdhci.o
+
+obj-$(CONFIG_MILKYMIST) += milkymist-memcard.o
+obj-$(CONFIG_OMAP) += omap_mmc.o
+obj-$(CONFIG_PXA2XX) += pxa2xx_mmci.o
diff --git a/hw/sd/milkymist-memcard.c b/hw/sd/milkymist-memcard.c
new file mode 100644 (file)
index 0000000..d5944bc
--- /dev/null
@@ -0,0 +1,303 @@
+/*
+ *  QEMU model of the Milkymist SD Card Controller.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
+ *
+ * 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/>.
+ *
+ *
+ * Specification available at:
+ *   http://www.milkymist.org/socdoc/memcard.pdf
+ */
+
+#include "hw/hw.h"
+#include "hw/sysbus.h"
+#include "sysemu/sysemu.h"
+#include "trace.h"
+#include "qemu/error-report.h"
+#include "sysemu/blockdev.h"
+#include "hw/sd.h"
+
+enum {
+    ENABLE_CMD_TX   = (1<<0),
+    ENABLE_CMD_RX   = (1<<1),
+    ENABLE_DAT_TX   = (1<<2),
+    ENABLE_DAT_RX   = (1<<3),
+};
+
+enum {
+    PENDING_CMD_TX   = (1<<0),
+    PENDING_CMD_RX   = (1<<1),
+    PENDING_DAT_TX   = (1<<2),
+    PENDING_DAT_RX   = (1<<3),
+};
+
+enum {
+    START_CMD_TX    = (1<<0),
+    START_DAT_RX    = (1<<1),
+};
+
+enum {
+    R_CLK2XDIV = 0,
+    R_ENABLE,
+    R_PENDING,
+    R_START,
+    R_CMD,
+    R_DAT,
+    R_MAX
+};
+
+struct MilkymistMemcardState {
+    SysBusDevice busdev;
+    MemoryRegion regs_region;
+    SDState *card;
+
+    int command_write_ptr;
+    int response_read_ptr;
+    int response_len;
+    int ignore_next_cmd;
+    int enabled;
+    uint8_t command[6];
+    uint8_t response[17];
+    uint32_t regs[R_MAX];
+};
+typedef struct MilkymistMemcardState MilkymistMemcardState;
+
+static void update_pending_bits(MilkymistMemcardState *s)
+{
+    /* transmits are instantaneous, thus tx pending bits are never set */
+    s->regs[R_PENDING] = 0;
+    /* if rx is enabled the corresponding pending bits are always set */
+    if (s->regs[R_ENABLE] & ENABLE_CMD_RX) {
+        s->regs[R_PENDING] |= PENDING_CMD_RX;
+    }
+    if (s->regs[R_ENABLE] & ENABLE_DAT_RX) {
+        s->regs[R_PENDING] |= PENDING_DAT_RX;
+    }
+}
+
+static void memcard_sd_command(MilkymistMemcardState *s)
+{
+    SDRequest req;
+
+    req.cmd = s->command[0] & 0x3f;
+    req.arg = (s->command[1] << 24) | (s->command[2] << 16)
+              | (s->command[3] << 8) | s->command[4];
+    req.crc = s->command[5];
+
+    s->response[0] = req.cmd;
+    s->response_len = sd_do_command(s->card, &req, s->response+1);
+    s->response_read_ptr = 0;
+
+    if (s->response_len == 16) {
+        /* R2 response */
+        s->response[0] = 0x3f;
+        s->response_len += 1;
+    } else if (s->response_len == 4) {
+        /* no crc calculation, insert dummy byte */
+        s->response[5] = 0;
+        s->response_len += 2;
+    }
+
+    if (req.cmd == 0) {
+        /* next write is a dummy byte to clock the initialization of the sd
+         * card */
+        s->ignore_next_cmd = 1;
+    }
+}
+
+static uint64_t memcard_read(void *opaque, hwaddr addr,
+                             unsigned size)
+{
+    MilkymistMemcardState *s = opaque;
+    uint32_t r = 0;
+
+    addr >>= 2;
+    switch (addr) {
+    case R_CMD:
+        if (!s->enabled) {
+            r = 0xff;
+        } else {
+            r = s->response[s->response_read_ptr++];
+            if (s->response_read_ptr > s->response_len) {
+                error_report("milkymist_memcard: "
+                        "read more cmd bytes than available. Clipping.");
+                s->response_read_ptr = 0;
+            }
+        }
+        break;
+    case R_DAT:
+        if (!s->enabled) {
+            r = 0xffffffff;
+        } else {
+            r = 0;
+            r |= sd_read_data(s->card) << 24;
+            r |= sd_read_data(s->card) << 16;
+            r |= sd_read_data(s->card) << 8;
+            r |= sd_read_data(s->card);
+        }
+        break;
+    case R_CLK2XDIV:
+    case R_ENABLE:
+    case R_PENDING:
+    case R_START:
+        r = s->regs[addr];
+        break;
+
+    default:
+        error_report("milkymist_memcard: read access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+
+    trace_milkymist_memcard_memory_read(addr << 2, r);
+
+    return r;
+}
+
+static void memcard_write(void *opaque, hwaddr addr, uint64_t value,
+                          unsigned size)
+{
+    MilkymistMemcardState *s = opaque;
+
+    trace_milkymist_memcard_memory_write(addr, value);
+
+    addr >>= 2;
+    switch (addr) {
+    case R_PENDING:
+        /* clear rx pending bits */
+        s->regs[R_PENDING] &= ~(value & (PENDING_CMD_RX | PENDING_DAT_RX));
+        update_pending_bits(s);
+        break;
+    case R_CMD:
+        if (!s->enabled) {
+            break;
+        }
+        if (s->ignore_next_cmd) {
+            s->ignore_next_cmd = 0;
+            break;
+        }
+        s->command[s->command_write_ptr] = value & 0xff;
+        s->command_write_ptr = (s->command_write_ptr + 1) % 6;
+        if (s->command_write_ptr == 0) {
+            memcard_sd_command(s);
+        }
+        break;
+    case R_DAT:
+        if (!s->enabled) {
+            break;
+        }
+        sd_write_data(s->card, (value >> 24) & 0xff);
+        sd_write_data(s->card, (value >> 16) & 0xff);
+        sd_write_data(s->card, (value >> 8) & 0xff);
+        sd_write_data(s->card, value & 0xff);
+        break;
+    case R_ENABLE:
+        s->regs[addr] = value;
+        update_pending_bits(s);
+        break;
+    case R_CLK2XDIV:
+    case R_START:
+        s->regs[addr] = value;
+        break;
+
+    default:
+        error_report("milkymist_memcard: write access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+}
+
+static const MemoryRegionOps memcard_mmio_ops = {
+    .read = memcard_read,
+    .write = memcard_write,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void milkymist_memcard_reset(DeviceState *d)
+{
+    MilkymistMemcardState *s =
+            container_of(d, MilkymistMemcardState, busdev.qdev);
+    int i;
+
+    s->command_write_ptr = 0;
+    s->response_read_ptr = 0;
+    s->response_len = 0;
+
+    for (i = 0; i < R_MAX; i++) {
+        s->regs[i] = 0;
+    }
+}
+
+static int milkymist_memcard_init(SysBusDevice *dev)
+{
+    MilkymistMemcardState *s = FROM_SYSBUS(typeof(*s), dev);
+    DriveInfo *dinfo;
+
+    dinfo = drive_get_next(IF_SD);
+    s->card = sd_init(dinfo ? dinfo->bdrv : NULL, 0);
+    s->enabled = dinfo ? bdrv_is_inserted(dinfo->bdrv) : 0;
+
+    memory_region_init_io(&s->regs_region, &memcard_mmio_ops, s,
+            "milkymist-memcard", R_MAX * 4);
+    sysbus_init_mmio(dev, &s->regs_region);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_milkymist_memcard = {
+    .name = "milkymist-memcard",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_INT32(command_write_ptr, MilkymistMemcardState),
+        VMSTATE_INT32(response_read_ptr, MilkymistMemcardState),
+        VMSTATE_INT32(response_len, MilkymistMemcardState),
+        VMSTATE_INT32(ignore_next_cmd, MilkymistMemcardState),
+        VMSTATE_INT32(enabled, MilkymistMemcardState),
+        VMSTATE_UINT8_ARRAY(command, MilkymistMemcardState, 6),
+        VMSTATE_UINT8_ARRAY(response, MilkymistMemcardState, 17),
+        VMSTATE_UINT32_ARRAY(regs, MilkymistMemcardState, R_MAX),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+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 const 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_types(void)
+{
+    type_register_static(&milkymist_memcard_info);
+}
+
+type_init(milkymist_memcard_register_types)
diff --git a/hw/sd/omap_mmc.c b/hw/sd/omap_mmc.c
new file mode 100644 (file)
index 0000000..d4079cd
--- /dev/null
@@ -0,0 +1,641 @@
+/*
+ * OMAP on-chip MMC/SD host emulation.
+ *
+ * Copyright (C) 2006-2007 Andrzej Zaborowski  <balrog@zabor.org>
+ *
+ * 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 or
+ * (at your option) version 3 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
+ * 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 "hw/hw.h"
+#include "hw/arm/omap.h"
+#include "hw/sd.h"
+
+struct omap_mmc_s {
+    qemu_irq irq;
+    qemu_irq *dma;
+    qemu_irq coverswitch;
+    MemoryRegion iomem;
+    omap_clk clk;
+    SDState *card;
+    uint16_t last_cmd;
+    uint16_t sdio;
+    uint16_t rsp[8];
+    uint32_t arg;
+    int lines;
+    int dw;
+    int mode;
+    int enable;
+    int be;
+    int rev;
+    uint16_t status;
+    uint16_t mask;
+    uint8_t cto;
+    uint16_t dto;
+    int clkdiv;
+    uint16_t fifo[32];
+    int fifo_start;
+    int fifo_len;
+    uint16_t blen;
+    uint16_t blen_counter;
+    uint16_t nblk;
+    uint16_t nblk_counter;
+    int tx_dma;
+    int rx_dma;
+    int af_level;
+    int ae_level;
+
+    int ddir;
+    int transfer;
+
+    int cdet_wakeup;
+    int cdet_enable;
+    int cdet_state;
+    qemu_irq cdet;
+};
+
+static void omap_mmc_interrupts_update(struct omap_mmc_s *s)
+{
+    qemu_set_irq(s->irq, !!(s->status & s->mask));
+}
+
+static void omap_mmc_fifolevel_update(struct omap_mmc_s *host)
+{
+    if (!host->transfer && !host->fifo_len) {
+        host->status &= 0xf3ff;
+        return;
+    }
+
+    if (host->fifo_len > host->af_level && host->ddir) {
+        if (host->rx_dma) {
+            host->status &= 0xfbff;
+            qemu_irq_raise(host->dma[1]);
+        } else
+            host->status |= 0x0400;
+    } else {
+        host->status &= 0xfbff;
+        qemu_irq_lower(host->dma[1]);
+    }
+
+    if (host->fifo_len < host->ae_level && !host->ddir) {
+        if (host->tx_dma) {
+            host->status &= 0xf7ff;
+            qemu_irq_raise(host->dma[0]);
+        } else
+            host->status |= 0x0800;
+    } else {
+        qemu_irq_lower(host->dma[0]);
+        host->status &= 0xf7ff;
+    }
+}
+
+typedef enum {
+    sd_nore = 0,       /* no response */
+    sd_r1,             /* normal response command */
+    sd_r2,             /* CID, CSD registers */
+    sd_r3,             /* OCR register */
+    sd_r6 = 6,         /* Published RCA response */
+    sd_r1b = -1,
+} sd_rsp_type_t;
+
+static void omap_mmc_command(struct omap_mmc_s *host, int cmd, int dir,
+                sd_cmd_type_t type, int busy, sd_rsp_type_t resptype, int init)
+{
+    uint32_t rspstatus, mask;
+    int rsplen, timeout;
+    SDRequest request;
+    uint8_t response[16];
+
+    if (init && cmd == 0) {
+        host->status |= 0x0001;
+        return;
+    }
+
+    if (resptype == sd_r1 && busy)
+        resptype = sd_r1b;
+
+    if (type == sd_adtc) {
+        host->fifo_start = 0;
+        host->fifo_len = 0;
+        host->transfer = 1;
+        host->ddir = dir;
+    } else
+        host->transfer = 0;
+    timeout = 0;
+    mask = 0;
+    rspstatus = 0;
+
+    request.cmd = cmd;
+    request.arg = host->arg;
+    request.crc = 0; /* FIXME */
+
+    rsplen = sd_do_command(host->card, &request, response);
+
+    /* TODO: validate CRCs */
+    switch (resptype) {
+    case sd_nore:
+        rsplen = 0;
+        break;
+
+    case sd_r1:
+    case sd_r1b:
+        if (rsplen < 4) {
+            timeout = 1;
+            break;
+        }
+        rsplen = 4;
+
+        mask = OUT_OF_RANGE | ADDRESS_ERROR | BLOCK_LEN_ERROR |
+                ERASE_SEQ_ERROR | ERASE_PARAM | WP_VIOLATION |
+                LOCK_UNLOCK_FAILED | COM_CRC_ERROR | ILLEGAL_COMMAND |
+                CARD_ECC_FAILED | CC_ERROR | SD_ERROR |
+                CID_CSD_OVERWRITE;
+        if (host->sdio & (1 << 13))
+            mask |= AKE_SEQ_ERROR;
+        rspstatus = (response[0] << 24) | (response[1] << 16) |
+                (response[2] << 8) | (response[3] << 0);
+        break;
+
+    case sd_r2:
+        if (rsplen < 16) {
+            timeout = 1;
+            break;
+        }
+        rsplen = 16;
+        break;
+
+    case sd_r3:
+        if (rsplen < 4) {
+            timeout = 1;
+            break;
+        }
+        rsplen = 4;
+
+        rspstatus = (response[0] << 24) | (response[1] << 16) |
+                (response[2] << 8) | (response[3] << 0);
+        if (rspstatus & 0x80000000)
+            host->status &= 0xe000;
+        else
+            host->status |= 0x1000;
+        break;
+
+    case sd_r6:
+        if (rsplen < 4) {
+            timeout = 1;
+            break;
+        }
+        rsplen = 4;
+
+        mask = 0xe000 | AKE_SEQ_ERROR;
+        rspstatus = (response[2] << 8) | (response[3] << 0);
+    }
+
+    if (rspstatus & mask)
+        host->status |= 0x4000;
+    else
+        host->status &= 0xb000;
+
+    if (rsplen)
+        for (rsplen = 0; rsplen < 8; rsplen ++)
+            host->rsp[~rsplen & 7] = response[(rsplen << 1) | 1] |
+                    (response[(rsplen << 1) | 0] << 8);
+
+    if (timeout)
+        host->status |= 0x0080;
+    else if (cmd == 12)
+        host->status |= 0x0005;        /* Makes it more real */
+    else
+        host->status |= 0x0001;
+}
+
+static void omap_mmc_transfer(struct omap_mmc_s *host)
+{
+    uint8_t value;
+
+    if (!host->transfer)
+        return;
+
+    while (1) {
+        if (host->ddir) {
+            if (host->fifo_len > host->af_level)
+                break;
+
+            value = sd_read_data(host->card);
+            host->fifo[(host->fifo_start + host->fifo_len) & 31] = value;
+            if (-- host->blen_counter) {
+                value = sd_read_data(host->card);
+                host->fifo[(host->fifo_start + host->fifo_len) & 31] |=
+                        value << 8;
+                host->blen_counter --;
+            }
+
+            host->fifo_len ++;
+        } else {
+            if (!host->fifo_len)
+                break;
+
+            value = host->fifo[host->fifo_start] & 0xff;
+            sd_write_data(host->card, value);
+            if (-- host->blen_counter) {
+                value = host->fifo[host->fifo_start] >> 8;
+                sd_write_data(host->card, value);
+                host->blen_counter --;
+            }
+
+            host->fifo_start ++;
+            host->fifo_len --;
+            host->fifo_start &= 31;
+        }
+
+        if (host->blen_counter == 0) {
+            host->nblk_counter --;
+            host->blen_counter = host->blen;
+
+            if (host->nblk_counter == 0) {
+                host->nblk_counter = host->nblk;
+                host->transfer = 0;
+                host->status |= 0x0008;
+                break;
+            }
+        }
+    }
+}
+
+static void omap_mmc_update(void *opaque)
+{
+    struct omap_mmc_s *s = opaque;
+    omap_mmc_transfer(s);
+    omap_mmc_fifolevel_update(s);
+    omap_mmc_interrupts_update(s);
+}
+
+void omap_mmc_reset(struct omap_mmc_s *host)
+{
+    host->last_cmd = 0;
+    memset(host->rsp, 0, sizeof(host->rsp));
+    host->arg = 0;
+    host->dw = 0;
+    host->mode = 0;
+    host->enable = 0;
+    host->status = 0;
+    host->mask = 0;
+    host->cto = 0;
+    host->dto = 0;
+    host->fifo_len = 0;
+    host->blen = 0;
+    host->blen_counter = 0;
+    host->nblk = 0;
+    host->nblk_counter = 0;
+    host->tx_dma = 0;
+    host->rx_dma = 0;
+    host->ae_level = 0x00;
+    host->af_level = 0x1f;
+    host->transfer = 0;
+    host->cdet_wakeup = 0;
+    host->cdet_enable = 0;
+    qemu_set_irq(host->coverswitch, host->cdet_state);
+    host->clkdiv = 0;
+}
+
+static uint64_t omap_mmc_read(void *opaque, hwaddr offset,
+                              unsigned size)
+{
+    uint16_t i;
+    struct omap_mmc_s *s = (struct omap_mmc_s *) opaque;
+
+    if (size != 2) {
+        return omap_badwidth_read16(opaque, offset);
+    }
+
+    switch (offset) {
+    case 0x00: /* MMC_CMD */
+        return s->last_cmd;
+
+    case 0x04: /* MMC_ARGL */
+        return s->arg & 0x0000ffff;
+
+    case 0x08: /* MMC_ARGH */
+        return s->arg >> 16;
+
+    case 0x0c: /* MMC_CON */
+        return (s->dw << 15) | (s->mode << 12) | (s->enable << 11) | 
+                (s->be << 10) | s->clkdiv;
+
+    case 0x10: /* MMC_STAT */
+        return s->status;
+
+    case 0x14: /* MMC_IE */
+        return s->mask;
+
+    case 0x18: /* MMC_CTO */
+        return s->cto;
+
+    case 0x1c: /* MMC_DTO */
+        return s->dto;
+
+    case 0x20: /* MMC_DATA */
+        /* TODO: support 8-bit access */
+        i = s->fifo[s->fifo_start];
+        if (s->fifo_len == 0) {
+            printf("MMC: FIFO underrun\n");
+            return i;
+        }
+        s->fifo_start ++;
+        s->fifo_len --;
+        s->fifo_start &= 31;
+        omap_mmc_transfer(s);
+        omap_mmc_fifolevel_update(s);
+        omap_mmc_interrupts_update(s);
+        return i;
+
+    case 0x24: /* MMC_BLEN */
+        return s->blen_counter;
+
+    case 0x28: /* MMC_NBLK */
+        return s->nblk_counter;
+
+    case 0x2c: /* MMC_BUF */
+        return (s->rx_dma << 15) | (s->af_level << 8) |
+            (s->tx_dma << 7) | s->ae_level;
+
+    case 0x30: /* MMC_SPI */
+        return 0x0000;
+    case 0x34: /* MMC_SDIO */
+        return (s->cdet_wakeup << 2) | (s->cdet_enable) | s->sdio;
+    case 0x38: /* MMC_SYST */
+        return 0x0000;
+
+    case 0x3c: /* MMC_REV */
+        return s->rev;
+
+    case 0x40: /* MMC_RSP0 */
+    case 0x44: /* MMC_RSP1 */
+    case 0x48: /* MMC_RSP2 */
+    case 0x4c: /* MMC_RSP3 */
+    case 0x50: /* MMC_RSP4 */
+    case 0x54: /* MMC_RSP5 */
+    case 0x58: /* MMC_RSP6 */
+    case 0x5c: /* MMC_RSP7 */
+        return s->rsp[(offset - 0x40) >> 2];
+
+    /* OMAP2-specific */
+    case 0x60: /* MMC_IOSR */
+    case 0x64: /* MMC_SYSC */
+        return 0;
+    case 0x68: /* MMC_SYSS */
+        return 1;                                              /* RSTD */
+    }
+
+    OMAP_BAD_REG(offset);
+    return 0;
+}
+
+static void omap_mmc_write(void *opaque, hwaddr offset,
+                           uint64_t value, unsigned size)
+{
+    int i;
+    struct omap_mmc_s *s = (struct omap_mmc_s *) opaque;
+
+    if (size != 2) {
+        return omap_badwidth_write16(opaque, offset, value);
+    }
+
+    switch (offset) {
+    case 0x00: /* MMC_CMD */
+        if (!s->enable)
+            break;
+
+        s->last_cmd = value;
+        for (i = 0; i < 8; i ++)
+            s->rsp[i] = 0x0000;
+        omap_mmc_command(s, value & 63, (value >> 15) & 1,
+                (sd_cmd_type_t) ((value >> 12) & 3),
+                (value >> 11) & 1,
+                (sd_rsp_type_t) ((value >> 8) & 7),
+                (value >> 7) & 1);
+        omap_mmc_update(s);
+        break;
+
+    case 0x04: /* MMC_ARGL */
+        s->arg &= 0xffff0000;
+        s->arg |= 0x0000ffff & value;
+        break;
+
+    case 0x08: /* MMC_ARGH */
+        s->arg &= 0x0000ffff;
+        s->arg |= value << 16;
+        break;
+
+    case 0x0c: /* MMC_CON */
+        s->dw = (value >> 15) & 1;
+        s->mode = (value >> 12) & 3;
+        s->enable = (value >> 11) & 1;
+        s->be = (value >> 10) & 1;
+        s->clkdiv = (value >> 0) & (s->rev >= 2 ? 0x3ff : 0xff);
+        if (s->mode != 0)
+            printf("SD mode %i unimplemented!\n", s->mode);
+        if (s->be != 0)
+            printf("SD FIFO byte sex unimplemented!\n");
+        if (s->dw != 0 && s->lines < 4)
+            printf("4-bit SD bus enabled\n");
+        if (!s->enable)
+            omap_mmc_reset(s);
+        break;
+
+    case 0x10: /* MMC_STAT */
+        s->status &= ~value;
+        omap_mmc_interrupts_update(s);
+        break;
+
+    case 0x14: /* MMC_IE */
+        s->mask = value & 0x7fff;
+        omap_mmc_interrupts_update(s);
+        break;
+
+    case 0x18: /* MMC_CTO */
+        s->cto = value & 0xff;
+        if (s->cto > 0xfd && s->rev <= 1)
+            printf("MMC: CTO of 0xff and 0xfe cannot be used!\n");
+        break;
+
+    case 0x1c: /* MMC_DTO */
+        s->dto = value & 0xffff;
+        break;
+
+    case 0x20: /* MMC_DATA */
+        /* TODO: support 8-bit access */
+        if (s->fifo_len == 32)
+            break;
+        s->fifo[(s->fifo_start + s->fifo_len) & 31] = value;
+        s->fifo_len ++;
+        omap_mmc_transfer(s);
+        omap_mmc_fifolevel_update(s);
+        omap_mmc_interrupts_update(s);
+        break;
+
+    case 0x24: /* MMC_BLEN */
+        s->blen = (value & 0x07ff) + 1;
+        s->blen_counter = s->blen;
+        break;
+
+    case 0x28: /* MMC_NBLK */
+        s->nblk = (value & 0x07ff) + 1;
+        s->nblk_counter = s->nblk;
+        s->blen_counter = s->blen;
+        break;
+
+    case 0x2c: /* MMC_BUF */
+        s->rx_dma = (value >> 15) & 1;
+        s->af_level = (value >> 8) & 0x1f;
+        s->tx_dma = (value >> 7) & 1;
+        s->ae_level = value & 0x1f;
+
+        if (s->rx_dma)
+            s->status &= 0xfbff;
+        if (s->tx_dma)
+            s->status &= 0xf7ff;
+        omap_mmc_fifolevel_update(s);
+        omap_mmc_interrupts_update(s);
+        break;
+
+    /* SPI, SDIO and TEST modes unimplemented */
+    case 0x30: /* MMC_SPI (OMAP1 only) */
+        break;
+    case 0x34: /* MMC_SDIO */
+        s->sdio = value & (s->rev >= 2 ? 0xfbf3 : 0x2020);
+        s->cdet_wakeup = (value >> 9) & 1;
+        s->cdet_enable = (value >> 2) & 1;
+        break;
+    case 0x38: /* MMC_SYST */
+        break;
+
+    case 0x3c: /* MMC_REV */
+    case 0x40: /* MMC_RSP0 */
+    case 0x44: /* MMC_RSP1 */
+    case 0x48: /* MMC_RSP2 */
+    case 0x4c: /* MMC_RSP3 */
+    case 0x50: /* MMC_RSP4 */
+    case 0x54: /* MMC_RSP5 */
+    case 0x58: /* MMC_RSP6 */
+    case 0x5c: /* MMC_RSP7 */
+        OMAP_RO_REG(offset);
+        break;
+
+    /* OMAP2-specific */
+    case 0x60: /* MMC_IOSR */
+        if (value & 0xf)
+            printf("MMC: SDIO bits used!\n");
+        break;
+    case 0x64: /* MMC_SYSC */
+        if (value & (1 << 2))                                  /* SRTS */
+            omap_mmc_reset(s);
+        break;
+    case 0x68: /* MMC_SYSS */
+        OMAP_RO_REG(offset);
+        break;
+
+    default:
+        OMAP_BAD_REG(offset);
+    }
+}
+
+static const MemoryRegionOps omap_mmc_ops = {
+    .read = omap_mmc_read,
+    .write = omap_mmc_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void omap_mmc_cover_cb(void *opaque, int line, int level)
+{
+    struct omap_mmc_s *host = (struct omap_mmc_s *) opaque;
+
+    if (!host->cdet_state && level) {
+        host->status |= 0x0002;
+        omap_mmc_interrupts_update(host);
+        if (host->cdet_wakeup) {
+            /* TODO: Assert wake-up */
+        }
+    }
+
+    if (host->cdet_state != level) {
+        qemu_set_irq(host->coverswitch, level);
+        host->cdet_state = level;
+    }
+}
+
+struct omap_mmc_s *omap_mmc_init(hwaddr base,
+                MemoryRegion *sysmem,
+                BlockDriverState *bd,
+                qemu_irq irq, qemu_irq dma[], omap_clk clk)
+{
+    struct omap_mmc_s *s = (struct omap_mmc_s *)
+            g_malloc0(sizeof(struct omap_mmc_s));
+
+    s->irq = irq;
+    s->dma = dma;
+    s->clk = clk;
+    s->lines = 1;      /* TODO: needs to be settable per-board */
+    s->rev = 1;
+
+    omap_mmc_reset(s);
+
+    memory_region_init_io(&s->iomem, &omap_mmc_ops, s, "omap.mmc", 0x800);
+    memory_region_add_subregion(sysmem, base, &s->iomem);
+
+    /* Instantiate the storage */
+    s->card = sd_init(bd, 0);
+
+    return s;
+}
+
+struct omap_mmc_s *omap2_mmc_init(struct omap_target_agent_s *ta,
+                BlockDriverState *bd, qemu_irq irq, qemu_irq dma[],
+                omap_clk fclk, omap_clk iclk)
+{
+    struct omap_mmc_s *s = (struct omap_mmc_s *)
+            g_malloc0(sizeof(struct omap_mmc_s));
+
+    s->irq = irq;
+    s->dma = dma;
+    s->clk = fclk;
+    s->lines = 4;
+    s->rev = 2;
+
+    omap_mmc_reset(s);
+
+    memory_region_init_io(&s->iomem, &omap_mmc_ops, s, "omap.mmc",
+                          omap_l4_region_size(ta, 0));
+    omap_l4_attach(ta, 0, &s->iomem);
+
+    /* Instantiate the storage */
+    s->card = sd_init(bd, 0);
+
+    s->cdet = qemu_allocate_irqs(omap_mmc_cover_cb, s, 1)[0];
+    sd_set_cb(s->card, NULL, s->cdet);
+
+    return s;
+}
+
+void omap_mmc_handlers(struct omap_mmc_s *s, qemu_irq ro, qemu_irq cover)
+{
+    if (s->cdet) {
+        sd_set_cb(s->card, ro, s->cdet);
+        s->coverswitch = cover;
+        qemu_set_irq(cover, s->cdet_state);
+    } else
+        sd_set_cb(s->card, ro, cover);
+}
+
+void omap_mmc_enable(struct omap_mmc_s *s, int enable)
+{
+    sd_enable(s->card, enable);
+}
diff --git a/hw/sd/pl181.c b/hw/sd/pl181.c
new file mode 100644 (file)
index 0000000..2527296
--- /dev/null
@@ -0,0 +1,515 @@
+/*
+ * Arm PrimeCell PL181 MultiMedia Card Interface
+ *
+ * Copyright (c) 2007 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the GPL.
+ */
+
+#include "sysemu/blockdev.h"
+#include "hw/sysbus.h"
+#include "hw/sd.h"
+
+//#define DEBUG_PL181 1
+
+#ifdef DEBUG_PL181
+#define DPRINTF(fmt, ...) \
+do { printf("pl181: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while(0)
+#endif
+
+#define PL181_FIFO_LEN 16
+
+typedef struct {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    SDState *card;
+    uint32_t clock;
+    uint32_t power;
+    uint32_t cmdarg;
+    uint32_t cmd;
+    uint32_t datatimer;
+    uint32_t datalength;
+    uint32_t respcmd;
+    uint32_t response[4];
+    uint32_t datactrl;
+    uint32_t datacnt;
+    uint32_t status;
+    uint32_t mask[2];
+    int32_t fifo_pos;
+    int32_t fifo_len;
+    /* The linux 2.6.21 driver is buggy, and misbehaves if new data arrives
+       while it is reading the FIFO.  We hack around this be defering
+       subsequent transfers until after the driver polls the status word.
+       http://www.arm.linux.org.uk/developer/patches/viewpatch.php?id=4446/1
+     */
+    int32_t linux_hack;
+    uint32_t fifo[PL181_FIFO_LEN];
+    qemu_irq irq[2];
+    /* GPIO outputs for 'card is readonly' and 'card inserted' */
+    qemu_irq cardstatus[2];
+} pl181_state;
+
+static const VMStateDescription vmstate_pl181 = {
+    .name = "pl181",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(clock, pl181_state),
+        VMSTATE_UINT32(power, pl181_state),
+        VMSTATE_UINT32(cmdarg, pl181_state),
+        VMSTATE_UINT32(cmd, pl181_state),
+        VMSTATE_UINT32(datatimer, pl181_state),
+        VMSTATE_UINT32(datalength, pl181_state),
+        VMSTATE_UINT32(respcmd, pl181_state),
+        VMSTATE_UINT32_ARRAY(response, pl181_state, 4),
+        VMSTATE_UINT32(datactrl, pl181_state),
+        VMSTATE_UINT32(datacnt, pl181_state),
+        VMSTATE_UINT32(status, pl181_state),
+        VMSTATE_UINT32_ARRAY(mask, pl181_state, 2),
+        VMSTATE_INT32(fifo_pos, pl181_state),
+        VMSTATE_INT32(fifo_len, pl181_state),
+        VMSTATE_INT32(linux_hack, pl181_state),
+        VMSTATE_UINT32_ARRAY(fifo, pl181_state, PL181_FIFO_LEN),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+#define PL181_CMD_INDEX     0x3f
+#define PL181_CMD_RESPONSE  (1 << 6)
+#define PL181_CMD_LONGRESP  (1 << 7)
+#define PL181_CMD_INTERRUPT (1 << 8)
+#define PL181_CMD_PENDING   (1 << 9)
+#define PL181_CMD_ENABLE    (1 << 10)
+
+#define PL181_DATA_ENABLE             (1 << 0)
+#define PL181_DATA_DIRECTION          (1 << 1)
+#define PL181_DATA_MODE               (1 << 2)
+#define PL181_DATA_DMAENABLE          (1 << 3)
+
+#define PL181_STATUS_CMDCRCFAIL       (1 << 0)
+#define PL181_STATUS_DATACRCFAIL      (1 << 1)
+#define PL181_STATUS_CMDTIMEOUT       (1 << 2)
+#define PL181_STATUS_DATATIMEOUT      (1 << 3)
+#define PL181_STATUS_TXUNDERRUN       (1 << 4)
+#define PL181_STATUS_RXOVERRUN        (1 << 5)
+#define PL181_STATUS_CMDRESPEND       (1 << 6)
+#define PL181_STATUS_CMDSENT          (1 << 7)
+#define PL181_STATUS_DATAEND          (1 << 8)
+#define PL181_STATUS_DATABLOCKEND     (1 << 10)
+#define PL181_STATUS_CMDACTIVE        (1 << 11)
+#define PL181_STATUS_TXACTIVE         (1 << 12)
+#define PL181_STATUS_RXACTIVE         (1 << 13)
+#define PL181_STATUS_TXFIFOHALFEMPTY  (1 << 14)
+#define PL181_STATUS_RXFIFOHALFFULL   (1 << 15)
+#define PL181_STATUS_TXFIFOFULL       (1 << 16)
+#define PL181_STATUS_RXFIFOFULL       (1 << 17)
+#define PL181_STATUS_TXFIFOEMPTY      (1 << 18)
+#define PL181_STATUS_RXFIFOEMPTY      (1 << 19)
+#define PL181_STATUS_TXDATAAVLBL      (1 << 20)
+#define PL181_STATUS_RXDATAAVLBL      (1 << 21)
+
+#define PL181_STATUS_TX_FIFO (PL181_STATUS_TXACTIVE \
+                             |PL181_STATUS_TXFIFOHALFEMPTY \
+                             |PL181_STATUS_TXFIFOFULL \
+                             |PL181_STATUS_TXFIFOEMPTY \
+                             |PL181_STATUS_TXDATAAVLBL)
+#define PL181_STATUS_RX_FIFO (PL181_STATUS_RXACTIVE \
+                             |PL181_STATUS_RXFIFOHALFFULL \
+                             |PL181_STATUS_RXFIFOFULL \
+                             |PL181_STATUS_RXFIFOEMPTY \
+                             |PL181_STATUS_RXDATAAVLBL)
+
+static const unsigned char pl181_id[] =
+{ 0x81, 0x11, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
+
+static void pl181_update(pl181_state *s)
+{
+    int i;
+    for (i = 0; i < 2; i++) {
+        qemu_set_irq(s->irq[i], (s->status & s->mask[i]) != 0);
+    }
+}
+
+static void pl181_fifo_push(pl181_state *s, uint32_t value)
+{
+    int n;
+
+    if (s->fifo_len == PL181_FIFO_LEN) {
+        fprintf(stderr, "pl181: FIFO overflow\n");
+        return;
+    }
+    n = (s->fifo_pos + s->fifo_len) & (PL181_FIFO_LEN - 1);
+    s->fifo_len++;
+    s->fifo[n] = value;
+    DPRINTF("FIFO push %08x\n", (int)value);
+}
+
+static uint32_t pl181_fifo_pop(pl181_state *s)
+{
+    uint32_t value;
+
+    if (s->fifo_len == 0) {
+        fprintf(stderr, "pl181: FIFO underflow\n");
+        return 0;
+    }
+    value = s->fifo[s->fifo_pos];
+    s->fifo_len--;
+    s->fifo_pos = (s->fifo_pos + 1) & (PL181_FIFO_LEN - 1);
+    DPRINTF("FIFO pop %08x\n", (int)value);
+    return value;
+}
+
+static void pl181_send_command(pl181_state *s)
+{
+    SDRequest request;
+    uint8_t response[16];
+    int rlen;
+
+    request.cmd = s->cmd & PL181_CMD_INDEX;
+    request.arg = s->cmdarg;
+    DPRINTF("Command %d %08x\n", request.cmd, request.arg);
+    rlen = sd_do_command(s->card, &request, response);
+    if (rlen < 0)
+        goto error;
+    if (s->cmd & PL181_CMD_RESPONSE) {
+#define RWORD(n) ((response[n] << 24) | (response[n + 1] << 16) \
+                  | (response[n + 2] << 8) | response[n + 3])
+        if (rlen == 0 || (rlen == 4 && (s->cmd & PL181_CMD_LONGRESP)))
+            goto error;
+        if (rlen != 4 && rlen != 16)
+            goto error;
+        s->response[0] = RWORD(0);
+        if (rlen == 4) {
+            s->response[1] = s->response[2] = s->response[3] = 0;
+        } else {
+            s->response[1] = RWORD(4);
+            s->response[2] = RWORD(8);
+            s->response[3] = RWORD(12) & ~1;
+        }
+        DPRINTF("Response received\n");
+        s->status |= PL181_STATUS_CMDRESPEND;
+#undef RWORD
+    } else {
+        DPRINTF("Command sent\n");
+        s->status |= PL181_STATUS_CMDSENT;
+    }
+    return;
+
+error:
+    DPRINTF("Timeout\n");
+    s->status |= PL181_STATUS_CMDTIMEOUT;
+}
+
+/* Transfer data between the card and the FIFO.  This is complicated by
+   the FIFO holding 32-bit words and the card taking data in single byte
+   chunks.  FIFO bytes are transferred in little-endian order.  */
+
+static void pl181_fifo_run(pl181_state *s)
+{
+    uint32_t bits;
+    uint32_t value = 0;
+    int n;
+    int is_read;
+
+    is_read = (s->datactrl & PL181_DATA_DIRECTION) != 0;
+    if (s->datacnt != 0 && (!is_read || sd_data_ready(s->card))
+            && !s->linux_hack) {
+        if (is_read) {
+            n = 0;
+            while (s->datacnt && s->fifo_len < PL181_FIFO_LEN) {
+                value |= (uint32_t)sd_read_data(s->card) << (n * 8);
+                s->datacnt--;
+                n++;
+                if (n == 4) {
+                    pl181_fifo_push(s, value);
+                    n = 0;
+                    value = 0;
+                }
+            }
+            if (n != 0) {
+                pl181_fifo_push(s, value);
+            }
+        } else { /* write */
+            n = 0;
+            while (s->datacnt > 0 && (s->fifo_len > 0 || n > 0)) {
+                if (n == 0) {
+                    value = pl181_fifo_pop(s);
+                    n = 4;
+                }
+                n--;
+                s->datacnt--;
+                sd_write_data(s->card, value & 0xff);
+                value >>= 8;
+            }
+        }
+    }
+    s->status &= ~(PL181_STATUS_RX_FIFO | PL181_STATUS_TX_FIFO);
+    if (s->datacnt == 0) {
+        s->status |= PL181_STATUS_DATAEND;
+        /* HACK: */
+        s->status |= PL181_STATUS_DATABLOCKEND;
+        DPRINTF("Transfer Complete\n");
+    }
+    if (s->datacnt == 0 && s->fifo_len == 0) {
+        s->datactrl &= ~PL181_DATA_ENABLE;
+        DPRINTF("Data engine idle\n");
+    } else {
+        /* Update FIFO bits.  */
+        bits = PL181_STATUS_TXACTIVE | PL181_STATUS_RXACTIVE;
+        if (s->fifo_len == 0) {
+            bits |= PL181_STATUS_TXFIFOEMPTY;
+            bits |= PL181_STATUS_RXFIFOEMPTY;
+        } else {
+            bits |= PL181_STATUS_TXDATAAVLBL;
+            bits |= PL181_STATUS_RXDATAAVLBL;
+        }
+        if (s->fifo_len == 16) {
+            bits |= PL181_STATUS_TXFIFOFULL;
+            bits |= PL181_STATUS_RXFIFOFULL;
+        }
+        if (s->fifo_len <= 8) {
+            bits |= PL181_STATUS_TXFIFOHALFEMPTY;
+        }
+        if (s->fifo_len >= 8) {
+            bits |= PL181_STATUS_RXFIFOHALFFULL;
+        }
+        if (s->datactrl & PL181_DATA_DIRECTION) {
+            bits &= PL181_STATUS_RX_FIFO;
+        } else {
+            bits &= PL181_STATUS_TX_FIFO;
+        }
+        s->status |= bits;
+    }
+}
+
+static uint64_t pl181_read(void *opaque, hwaddr offset,
+                           unsigned size)
+{
+    pl181_state *s = (pl181_state *)opaque;
+    uint32_t tmp;
+
+    if (offset >= 0xfe0 && offset < 0x1000) {
+        return pl181_id[(offset - 0xfe0) >> 2];
+    }
+    switch (offset) {
+    case 0x00: /* Power */
+        return s->power;
+    case 0x04: /* Clock */
+        return s->clock;
+    case 0x08: /* Argument */
+        return s->cmdarg;
+    case 0x0c: /* Command */
+        return s->cmd;
+    case 0x10: /* RespCmd */
+        return s->respcmd;
+    case 0x14: /* Response0 */
+        return s->response[0];
+    case 0x18: /* Response1 */
+        return s->response[1];
+    case 0x1c: /* Response2 */
+        return s->response[2];
+    case 0x20: /* Response3 */
+        return s->response[3];
+    case 0x24: /* DataTimer */
+        return s->datatimer;
+    case 0x28: /* DataLength */
+        return s->datalength;
+    case 0x2c: /* DataCtrl */
+        return s->datactrl;
+    case 0x30: /* DataCnt */
+        return s->datacnt;
+    case 0x34: /* Status */
+        tmp = s->status;
+        if (s->linux_hack) {
+            s->linux_hack = 0;
+            pl181_fifo_run(s);
+            pl181_update(s);
+        }
+        return tmp;
+    case 0x3c: /* Mask0 */
+        return s->mask[0];
+    case 0x40: /* Mask1 */
+        return s->mask[1];
+    case 0x48: /* FifoCnt */
+        /* The documentation is somewhat vague about exactly what FifoCnt
+           does.  On real hardware it appears to be when decrememnted
+           when a word is transferred between the FIFO and the serial
+           data engine.  DataCnt is decremented after each byte is
+           transferred between the serial engine and the card.
+           We don't emulate this level of detail, so both can be the same.  */
+        tmp = (s->datacnt + 3) >> 2;
+        if (s->linux_hack) {
+            s->linux_hack = 0;
+            pl181_fifo_run(s);
+            pl181_update(s);
+        }
+        return tmp;
+    case 0x80: case 0x84: case 0x88: case 0x8c: /* FifoData */
+    case 0x90: case 0x94: case 0x98: case 0x9c:
+    case 0xa0: case 0xa4: case 0xa8: case 0xac:
+    case 0xb0: case 0xb4: case 0xb8: case 0xbc:
+        if (s->fifo_len == 0) {
+            qemu_log_mask(LOG_GUEST_ERROR, "pl181: Unexpected FIFO read\n");
+            return 0;
+        } else {
+            uint32_t value;
+            value = pl181_fifo_pop(s);
+            s->linux_hack = 1;
+            pl181_fifo_run(s);
+            pl181_update(s);
+            return value;
+        }
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "pl181_read: Bad offset %x\n", (int)offset);
+        return 0;
+    }
+}
+
+static void pl181_write(void *opaque, hwaddr offset,
+                        uint64_t value, unsigned size)
+{
+    pl181_state *s = (pl181_state *)opaque;
+
+    switch (offset) {
+    case 0x00: /* Power */
+        s->power = value & 0xff;
+        break;
+    case 0x04: /* Clock */
+        s->clock = value & 0xff;
+        break;
+    case 0x08: /* Argument */
+        s->cmdarg = value;
+        break;
+    case 0x0c: /* Command */
+        s->cmd = value;
+        if (s->cmd & PL181_CMD_ENABLE) {
+            if (s->cmd & PL181_CMD_INTERRUPT) {
+                qemu_log_mask(LOG_UNIMP,
+                              "pl181: Interrupt mode not implemented\n");
+            } if (s->cmd & PL181_CMD_PENDING) {
+                qemu_log_mask(LOG_UNIMP,
+                              "pl181: Pending commands not implemented\n");
+            } else {
+                pl181_send_command(s);
+                pl181_fifo_run(s);
+            }
+            /* The command has completed one way or the other.  */
+            s->cmd &= ~PL181_CMD_ENABLE;
+        }
+        break;
+    case 0x24: /* DataTimer */
+        s->datatimer = value;
+        break;
+    case 0x28: /* DataLength */
+        s->datalength = value & 0xffff;
+        break;
+    case 0x2c: /* DataCtrl */
+        s->datactrl = value & 0xff;
+        if (value & PL181_DATA_ENABLE) {
+            s->datacnt = s->datalength;
+            pl181_fifo_run(s);
+        }
+        break;
+    case 0x38: /* Clear */
+        s->status &= ~(value & 0x7ff);
+        break;
+    case 0x3c: /* Mask0 */
+        s->mask[0] = value;
+        break;
+    case 0x40: /* Mask1 */
+        s->mask[1] = value;
+        break;
+    case 0x80: case 0x84: case 0x88: case 0x8c: /* FifoData */
+    case 0x90: case 0x94: case 0x98: case 0x9c:
+    case 0xa0: case 0xa4: case 0xa8: case 0xac:
+    case 0xb0: case 0xb4: case 0xb8: case 0xbc:
+        if (s->datacnt == 0) {
+            qemu_log_mask(LOG_GUEST_ERROR, "pl181: Unexpected FIFO write\n");
+        } else {
+            pl181_fifo_push(s, value);
+            pl181_fifo_run(s);
+        }
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "pl181_write: Bad offset %x\n", (int)offset);
+    }
+    pl181_update(s);
+}
+
+static const MemoryRegionOps pl181_ops = {
+    .read = pl181_read,
+    .write = pl181_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void pl181_reset(DeviceState *d)
+{
+    pl181_state *s = DO_UPCAST(pl181_state, busdev.qdev, d);
+
+    s->power = 0;
+    s->cmdarg = 0;
+    s->cmd = 0;
+    s->datatimer = 0;
+    s->datalength = 0;
+    s->respcmd = 0;
+    s->response[0] = 0;
+    s->response[1] = 0;
+    s->response[2] = 0;
+    s->response[3] = 0;
+    s->datatimer = 0;
+    s->datalength = 0;
+    s->datactrl = 0;
+    s->datacnt = 0;
+    s->status = 0;
+    s->linux_hack = 0;
+    s->mask[0] = 0;
+    s->mask[1] = 0;
+
+    /* We can assume our GPIO outputs have been wired up now */
+    sd_set_cb(s->card, s->cardstatus[0], s->cardstatus[1]);
+}
+
+static int pl181_init(SysBusDevice *dev)
+{
+    pl181_state *s = FROM_SYSBUS(pl181_state, dev);
+    DriveInfo *dinfo;
+
+    memory_region_init_io(&s->iomem, &pl181_ops, s, "pl181", 0x1000);
+    sysbus_init_mmio(dev, &s->iomem);
+    sysbus_init_irq(dev, &s->irq[0]);
+    sysbus_init_irq(dev, &s->irq[1]);
+    qdev_init_gpio_out(&s->busdev.qdev, s->cardstatus, 2);
+    dinfo = drive_get_next(IF_SD);
+    s->card = sd_init(dinfo ? dinfo->bdrv : NULL, 0);
+    return 0;
+}
+
+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 const TypeInfo pl181_info = {
+    .name          = "pl181",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(pl181_state),
+    .class_init    = pl181_class_init,
+};
+
+static void pl181_register_types(void)
+{
+    type_register_static(&pl181_info);
+}
+
+type_init(pl181_register_types)
diff --git a/hw/sd/pxa2xx_mmci.c b/hw/sd/pxa2xx_mmci.c
new file mode 100644 (file)
index 0000000..2db1cab
--- /dev/null
@@ -0,0 +1,553 @@
+/*
+ * Intel XScale PXA255/270 MultiMediaCard/SD/SDIO Controller emulation.
+ *
+ * Copyright (c) 2006 Openedhand Ltd.
+ * Written by Andrzej Zaborowski <balrog@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/hw.h"
+#include "hw/arm/pxa.h"
+#include "hw/sd.h"
+#include "hw/qdev.h"
+
+struct PXA2xxMMCIState {
+    MemoryRegion iomem;
+    qemu_irq irq;
+    qemu_irq rx_dma;
+    qemu_irq tx_dma;
+
+    SDState *card;
+
+    uint32_t status;
+    uint32_t clkrt;
+    uint32_t spi;
+    uint32_t cmdat;
+    uint32_t resp_tout;
+    uint32_t read_tout;
+    int blklen;
+    int numblk;
+    uint32_t intmask;
+    uint32_t intreq;
+    int cmd;
+    uint32_t arg;
+
+    int active;
+    int bytesleft;
+    uint8_t tx_fifo[64];
+    int tx_start;
+    int tx_len;
+    uint8_t rx_fifo[32];
+    int rx_start;
+    int rx_len;
+    uint16_t resp_fifo[9];
+    int resp_len;
+
+    int cmdreq;
+    int ac_width;
+};
+
+#define MMC_STRPCL     0x00    /* MMC Clock Start/Stop register */
+#define MMC_STAT       0x04    /* MMC Status register */
+#define MMC_CLKRT      0x08    /* MMC Clock Rate register */
+#define MMC_SPI                0x0c    /* MMC SPI Mode register */
+#define MMC_CMDAT      0x10    /* MMC Command/Data register */
+#define MMC_RESTO      0x14    /* MMC Response Time-Out register */
+#define MMC_RDTO       0x18    /* MMC Read Time-Out register */
+#define MMC_BLKLEN     0x1c    /* MMC Block Length register */
+#define MMC_NUMBLK     0x20    /* MMC Number of Blocks register */
+#define MMC_PRTBUF     0x24    /* MMC Buffer Partly Full register */
+#define MMC_I_MASK     0x28    /* MMC Interrupt Mask register */
+#define MMC_I_REG      0x2c    /* MMC Interrupt Request register */
+#define MMC_CMD                0x30    /* MMC Command register */
+#define MMC_ARGH       0x34    /* MMC Argument High register */
+#define MMC_ARGL       0x38    /* MMC Argument Low register */
+#define MMC_RES                0x3c    /* MMC Response FIFO */
+#define MMC_RXFIFO     0x40    /* MMC Receive FIFO */
+#define MMC_TXFIFO     0x44    /* MMC Transmit FIFO */
+#define MMC_RDWAIT     0x48    /* MMC RD_WAIT register */
+#define MMC_BLKS_REM   0x4c    /* MMC Blocks Remaining register */
+
+/* Bitfield masks */
+#define STRPCL_STOP_CLK        (1 << 0)
+#define STRPCL_STRT_CLK        (1 << 1)
+#define STAT_TOUT_RES  (1 << 1)
+#define STAT_CLK_EN    (1 << 8)
+#define STAT_DATA_DONE (1 << 11)
+#define STAT_PRG_DONE  (1 << 12)
+#define STAT_END_CMDRES        (1 << 13)
+#define SPI_SPI_MODE   (1 << 0)
+#define CMDAT_RES_TYPE (3 << 0)
+#define CMDAT_DATA_EN  (1 << 2)
+#define CMDAT_WR_RD    (1 << 3)
+#define CMDAT_DMA_EN   (1 << 7)
+#define CMDAT_STOP_TRAN        (1 << 10)
+#define INT_DATA_DONE  (1 << 0)
+#define INT_PRG_DONE   (1 << 1)
+#define INT_END_CMD    (1 << 2)
+#define INT_STOP_CMD   (1 << 3)
+#define INT_CLK_OFF    (1 << 4)
+#define INT_RXFIFO_REQ (1 << 5)
+#define INT_TXFIFO_REQ (1 << 6)
+#define INT_TINT       (1 << 7)
+#define INT_DAT_ERR    (1 << 8)
+#define INT_RES_ERR    (1 << 9)
+#define INT_RD_STALLED (1 << 10)
+#define INT_SDIO_INT   (1 << 11)
+#define INT_SDIO_SACK  (1 << 12)
+#define PRTBUF_PRT_BUF (1 << 0)
+
+/* Route internal interrupt lines to the global IC and DMA */
+static void pxa2xx_mmci_int_update(PXA2xxMMCIState *s)
+{
+    uint32_t mask = s->intmask;
+    if (s->cmdat & CMDAT_DMA_EN) {
+        mask |= INT_RXFIFO_REQ | INT_TXFIFO_REQ;
+
+        qemu_set_irq(s->rx_dma, !!(s->intreq & INT_RXFIFO_REQ));
+        qemu_set_irq(s->tx_dma, !!(s->intreq & INT_TXFIFO_REQ));
+    }
+
+    qemu_set_irq(s->irq, !!(s->intreq & ~mask));
+}
+
+static void pxa2xx_mmci_fifo_update(PXA2xxMMCIState *s)
+{
+    if (!s->active)
+        return;
+
+    if (s->cmdat & CMDAT_WR_RD) {
+        while (s->bytesleft && s->tx_len) {
+            sd_write_data(s->card, s->tx_fifo[s->tx_start ++]);
+            s->tx_start &= 0x1f;
+            s->tx_len --;
+            s->bytesleft --;
+        }
+        if (s->bytesleft)
+            s->intreq |= INT_TXFIFO_REQ;
+    } else
+        while (s->bytesleft && s->rx_len < 32) {
+            s->rx_fifo[(s->rx_start + (s->rx_len ++)) & 0x1f] =
+                sd_read_data(s->card);
+            s->bytesleft --;
+            s->intreq |= INT_RXFIFO_REQ;
+        }
+
+    if (!s->bytesleft) {
+        s->active = 0;
+        s->intreq |= INT_DATA_DONE;
+        s->status |= STAT_DATA_DONE;
+
+        if (s->cmdat & CMDAT_WR_RD) {
+            s->intreq |= INT_PRG_DONE;
+            s->status |= STAT_PRG_DONE;
+        }
+    }
+
+    pxa2xx_mmci_int_update(s);
+}
+
+static void pxa2xx_mmci_wakequeues(PXA2xxMMCIState *s)
+{
+    int rsplen, i;
+    SDRequest request;
+    uint8_t response[16];
+
+    s->active = 1;
+    s->rx_len = 0;
+    s->tx_len = 0;
+    s->cmdreq = 0;
+
+    request.cmd = s->cmd;
+    request.arg = s->arg;
+    request.crc = 0;   /* FIXME */
+
+    rsplen = sd_do_command(s->card, &request, response);
+    s->intreq |= INT_END_CMD;
+
+    memset(s->resp_fifo, 0, sizeof(s->resp_fifo));
+    switch (s->cmdat & CMDAT_RES_TYPE) {
+#define PXAMMCI_RESP(wd, value0, value1)       \
+        s->resp_fifo[(wd) + 0] |= (value0);    \
+        s->resp_fifo[(wd) + 1] |= (value1) << 8;
+    case 0:    /* No response */
+        goto complete;
+
+    case 1:    /* R1, R4, R5 or R6 */
+        if (rsplen < 4)
+            goto timeout;
+        goto complete;
+
+    case 2:    /* R2 */
+        if (rsplen < 16)
+            goto timeout;
+        goto complete;
+
+    case 3:    /* R3 */
+        if (rsplen < 4)
+            goto timeout;
+        goto complete;
+
+    complete:
+        for (i = 0; rsplen > 0; i ++, rsplen -= 2) {
+            PXAMMCI_RESP(i, response[i * 2], response[i * 2 + 1]);
+        }
+        s->status |= STAT_END_CMDRES;
+
+        if (!(s->cmdat & CMDAT_DATA_EN))
+            s->active = 0;
+        else
+            s->bytesleft = s->numblk * s->blklen;
+
+        s->resp_len = 0;
+        break;
+
+    timeout:
+        s->active = 0;
+        s->status |= STAT_TOUT_RES;
+        break;
+    }
+
+    pxa2xx_mmci_fifo_update(s);
+}
+
+static uint32_t pxa2xx_mmci_read(void *opaque, hwaddr offset)
+{
+    PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque;
+    uint32_t ret;
+
+    switch (offset) {
+    case MMC_STRPCL:
+        return 0;
+    case MMC_STAT:
+        return s->status;
+    case MMC_CLKRT:
+        return s->clkrt;
+    case MMC_SPI:
+        return s->spi;
+    case MMC_CMDAT:
+        return s->cmdat;
+    case MMC_RESTO:
+        return s->resp_tout;
+    case MMC_RDTO:
+        return s->read_tout;
+    case MMC_BLKLEN:
+        return s->blklen;
+    case MMC_NUMBLK:
+        return s->numblk;
+    case MMC_PRTBUF:
+        return 0;
+    case MMC_I_MASK:
+        return s->intmask;
+    case MMC_I_REG:
+        return s->intreq;
+    case MMC_CMD:
+        return s->cmd | 0x40;
+    case MMC_ARGH:
+        return s->arg >> 16;
+    case MMC_ARGL:
+        return s->arg & 0xffff;
+    case MMC_RES:
+        if (s->resp_len < 9)
+            return s->resp_fifo[s->resp_len ++];
+        return 0;
+    case MMC_RXFIFO:
+        ret = 0;
+        while (s->ac_width -- && s->rx_len) {
+            ret |= s->rx_fifo[s->rx_start ++] << (s->ac_width << 3);
+            s->rx_start &= 0x1f;
+            s->rx_len --;
+        }
+        s->intreq &= ~INT_RXFIFO_REQ;
+        pxa2xx_mmci_fifo_update(s);
+        return ret;
+    case MMC_RDWAIT:
+        return 0;
+    case MMC_BLKS_REM:
+        return s->numblk;
+    default:
+        hw_error("%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset);
+    }
+
+    return 0;
+}
+
+static void pxa2xx_mmci_write(void *opaque,
+                hwaddr offset, uint32_t value)
+{
+    PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque;
+
+    switch (offset) {
+    case MMC_STRPCL:
+        if (value & STRPCL_STRT_CLK) {
+            s->status |= STAT_CLK_EN;
+            s->intreq &= ~INT_CLK_OFF;
+
+            if (s->cmdreq && !(s->cmdat & CMDAT_STOP_TRAN)) {
+                s->status &= STAT_CLK_EN;
+                pxa2xx_mmci_wakequeues(s);
+            }
+        }
+
+        if (value & STRPCL_STOP_CLK) {
+            s->status &= ~STAT_CLK_EN;
+            s->intreq |= INT_CLK_OFF;
+            s->active = 0;
+        }
+
+        pxa2xx_mmci_int_update(s);
+        break;
+
+    case MMC_CLKRT:
+        s->clkrt = value & 7;
+        break;
+
+    case MMC_SPI:
+        s->spi = value & 0xf;
+        if (value & SPI_SPI_MODE)
+            printf("%s: attempted to use card in SPI mode\n", __FUNCTION__);
+        break;
+
+    case MMC_CMDAT:
+        s->cmdat = value & 0x3dff;
+        s->active = 0;
+        s->cmdreq = 1;
+        if (!(value & CMDAT_STOP_TRAN)) {
+            s->status &= STAT_CLK_EN;
+
+            if (s->status & STAT_CLK_EN)
+                pxa2xx_mmci_wakequeues(s);
+        }
+
+        pxa2xx_mmci_int_update(s);
+        break;
+
+    case MMC_RESTO:
+        s->resp_tout = value & 0x7f;
+        break;
+
+    case MMC_RDTO:
+        s->read_tout = value & 0xffff;
+        break;
+
+    case MMC_BLKLEN:
+        s->blklen = value & 0xfff;
+        break;
+
+    case MMC_NUMBLK:
+        s->numblk = value & 0xffff;
+        break;
+
+    case MMC_PRTBUF:
+        if (value & PRTBUF_PRT_BUF) {
+            s->tx_start ^= 32;
+            s->tx_len = 0;
+        }
+        pxa2xx_mmci_fifo_update(s);
+        break;
+
+    case MMC_I_MASK:
+        s->intmask = value & 0x1fff;
+        pxa2xx_mmci_int_update(s);
+        break;
+
+    case MMC_CMD:
+        s->cmd = value & 0x3f;
+        break;
+
+    case MMC_ARGH:
+        s->arg &= 0x0000ffff;
+        s->arg |= value << 16;
+        break;
+
+    case MMC_ARGL:
+        s->arg &= 0xffff0000;
+        s->arg |= value & 0x0000ffff;
+        break;
+
+    case MMC_TXFIFO:
+        while (s->ac_width -- && s->tx_len < 0x20)
+            s->tx_fifo[(s->tx_start + (s->tx_len ++)) & 0x1f] =
+                    (value >> (s->ac_width << 3)) & 0xff;
+        s->intreq &= ~INT_TXFIFO_REQ;
+        pxa2xx_mmci_fifo_update(s);
+        break;
+
+    case MMC_RDWAIT:
+    case MMC_BLKS_REM:
+        break;
+
+    default:
+        hw_error("%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset);
+    }
+}
+
+static uint32_t pxa2xx_mmci_readb(void *opaque, hwaddr offset)
+{
+    PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque;
+    s->ac_width = 1;
+    return pxa2xx_mmci_read(opaque, offset);
+}
+
+static uint32_t pxa2xx_mmci_readh(void *opaque, hwaddr offset)
+{
+    PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque;
+    s->ac_width = 2;
+    return pxa2xx_mmci_read(opaque, offset);
+}
+
+static uint32_t pxa2xx_mmci_readw(void *opaque, hwaddr offset)
+{
+    PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque;
+    s->ac_width = 4;
+    return pxa2xx_mmci_read(opaque, offset);
+}
+
+static void pxa2xx_mmci_writeb(void *opaque,
+                hwaddr offset, uint32_t value)
+{
+    PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque;
+    s->ac_width = 1;
+    pxa2xx_mmci_write(opaque, offset, value);
+}
+
+static void pxa2xx_mmci_writeh(void *opaque,
+                hwaddr offset, uint32_t value)
+{
+    PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque;
+    s->ac_width = 2;
+    pxa2xx_mmci_write(opaque, offset, value);
+}
+
+static void pxa2xx_mmci_writew(void *opaque,
+                hwaddr offset, uint32_t value)
+{
+    PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque;
+    s->ac_width = 4;
+    pxa2xx_mmci_write(opaque, offset, value);
+}
+
+static const MemoryRegionOps pxa2xx_mmci_ops = {
+    .old_mmio = {
+        .read = { pxa2xx_mmci_readb,
+                  pxa2xx_mmci_readh,
+                  pxa2xx_mmci_readw, },
+        .write = { pxa2xx_mmci_writeb,
+                   pxa2xx_mmci_writeh,
+                   pxa2xx_mmci_writew, },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void pxa2xx_mmci_save(QEMUFile *f, void *opaque)
+{
+    PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque;
+    int i;
+
+    qemu_put_be32s(f, &s->status);
+    qemu_put_be32s(f, &s->clkrt);
+    qemu_put_be32s(f, &s->spi);
+    qemu_put_be32s(f, &s->cmdat);
+    qemu_put_be32s(f, &s->resp_tout);
+    qemu_put_be32s(f, &s->read_tout);
+    qemu_put_be32(f, s->blklen);
+    qemu_put_be32(f, s->numblk);
+    qemu_put_be32s(f, &s->intmask);
+    qemu_put_be32s(f, &s->intreq);
+    qemu_put_be32(f, s->cmd);
+    qemu_put_be32s(f, &s->arg);
+    qemu_put_be32(f, s->cmdreq);
+    qemu_put_be32(f, s->active);
+    qemu_put_be32(f, s->bytesleft);
+
+    qemu_put_byte(f, s->tx_len);
+    for (i = 0; i < s->tx_len; i ++)
+        qemu_put_byte(f, s->tx_fifo[(s->tx_start + i) & 63]);
+
+    qemu_put_byte(f, s->rx_len);
+    for (i = 0; i < s->rx_len; i ++)
+        qemu_put_byte(f, s->rx_fifo[(s->rx_start + i) & 31]);
+
+    qemu_put_byte(f, s->resp_len);
+    for (i = s->resp_len; i < 9; i ++)
+        qemu_put_be16s(f, &s->resp_fifo[i]);
+}
+
+static int pxa2xx_mmci_load(QEMUFile *f, void *opaque, int version_id)
+{
+    PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque;
+    int i;
+
+    qemu_get_be32s(f, &s->status);
+    qemu_get_be32s(f, &s->clkrt);
+    qemu_get_be32s(f, &s->spi);
+    qemu_get_be32s(f, &s->cmdat);
+    qemu_get_be32s(f, &s->resp_tout);
+    qemu_get_be32s(f, &s->read_tout);
+    s->blklen = qemu_get_be32(f);
+    s->numblk = qemu_get_be32(f);
+    qemu_get_be32s(f, &s->intmask);
+    qemu_get_be32s(f, &s->intreq);
+    s->cmd = qemu_get_be32(f);
+    qemu_get_be32s(f, &s->arg);
+    s->cmdreq = qemu_get_be32(f);
+    s->active = qemu_get_be32(f);
+    s->bytesleft = qemu_get_be32(f);
+
+    s->tx_len = qemu_get_byte(f);
+    s->tx_start = 0;
+    if (s->tx_len >= sizeof(s->tx_fifo) || s->tx_len < 0)
+        return -EINVAL;
+    for (i = 0; i < s->tx_len; i ++)
+        s->tx_fifo[i] = qemu_get_byte(f);
+
+    s->rx_len = qemu_get_byte(f);
+    s->rx_start = 0;
+    if (s->rx_len >= sizeof(s->rx_fifo) || s->rx_len < 0)
+        return -EINVAL;
+    for (i = 0; i < s->rx_len; i ++)
+        s->rx_fifo[i] = qemu_get_byte(f);
+
+    s->resp_len = qemu_get_byte(f);
+    if (s->resp_len > 9 || s->resp_len < 0)
+        return -EINVAL;
+    for (i = s->resp_len; i < 9; i ++)
+         qemu_get_be16s(f, &s->resp_fifo[i]);
+
+    return 0;
+}
+
+PXA2xxMMCIState *pxa2xx_mmci_init(MemoryRegion *sysmem,
+                hwaddr base,
+                BlockDriverState *bd, qemu_irq irq,
+                qemu_irq rx_dma, qemu_irq tx_dma)
+{
+    PXA2xxMMCIState *s;
+
+    s = (PXA2xxMMCIState *) g_malloc0(sizeof(PXA2xxMMCIState));
+    s->irq = irq;
+    s->rx_dma = rx_dma;
+    s->tx_dma = tx_dma;
+
+    memory_region_init_io(&s->iomem, &pxa2xx_mmci_ops, s,
+                          "pxa2xx-mmci", 0x00100000);
+    memory_region_add_subregion(sysmem, base, &s->iomem);
+
+    /* Instantiate the actual storage */
+    s->card = sd_init(bd, 0);
+
+    register_savevm(NULL, "pxa2xx_mmci", 0, 0,
+                    pxa2xx_mmci_save, pxa2xx_mmci_load, s);
+
+    return s;
+}
+
+void pxa2xx_mmci_handlers(PXA2xxMMCIState *s, qemu_irq readonly,
+                qemu_irq coverswitch)
+{
+    sd_set_cb(s->card, readonly, coverswitch);
+}
diff --git a/hw/sd/sd.c b/hw/sd/sd.c
new file mode 100644 (file)
index 0000000..66c4014
--- /dev/null
@@ -0,0 +1,1764 @@
+/*
+ * SD Memory Card emulation as defined in the "SD Memory Card Physical
+ * layer specification, Version 1.10."
+ *
+ * Copyright (c) 2006 Andrzej Zaborowski  <balrog@zabor.org>
+ * Copyright (c) 2007 CodeSourcery
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "hw/hw.h"
+#include "block/block.h"
+#include "hw/sd.h"
+#include "qemu/bitmap.h"
+
+//#define DEBUG_SD 1
+
+#ifdef DEBUG_SD
+#define DPRINTF(fmt, ...) \
+do { fprintf(stderr, "SD: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while(0)
+#endif
+
+typedef enum {
+    sd_r0 = 0,    /* no response */
+    sd_r1,        /* normal response command */
+    sd_r2_i,      /* CID register */
+    sd_r2_s,      /* CSD register */
+    sd_r3,        /* OCR register */
+    sd_r6 = 6,    /* Published RCA response */
+    sd_r7,        /* Operating voltage */
+    sd_r1b = -1,
+    sd_illegal = -2,
+} sd_rsp_type_t;
+
+enum SDCardModes {
+    sd_inactive,
+    sd_card_identification_mode,
+    sd_data_transfer_mode,
+};
+
+enum SDCardStates {
+    sd_inactive_state = -1,
+    sd_idle_state = 0,
+    sd_ready_state,
+    sd_identification_state,
+    sd_standby_state,
+    sd_transfer_state,
+    sd_sendingdata_state,
+    sd_receivingdata_state,
+    sd_programming_state,
+    sd_disconnect_state,
+};
+
+struct SDState {
+    uint32_t mode;    /* current card mode, one of SDCardModes */
+    int32_t state;    /* current card state, one of SDCardStates */
+    uint32_t ocr;
+    uint8_t scr[8];
+    uint8_t cid[16];
+    uint8_t csd[16];
+    uint16_t rca;
+    uint32_t card_status;
+    uint8_t sd_status[64];
+    uint32_t vhs;
+    bool wp_switch;
+    unsigned long *wp_groups;
+    int32_t wpgrps_size;
+    uint64_t size;
+    uint32_t blk_len;
+    uint32_t erase_start;
+    uint32_t erase_end;
+    uint8_t pwd[16];
+    uint32_t pwd_len;
+    uint8_t function_group[6];
+
+    bool spi;
+    uint8_t current_cmd;
+    /* True if we will handle the next command as an ACMD. Note that this does
+     * *not* track the APP_CMD status bit!
+     */
+    bool expecting_acmd;
+    uint32_t blk_written;
+    uint64_t data_start;
+    uint32_t data_offset;
+    uint8_t data[512];
+    qemu_irq readonly_cb;
+    qemu_irq inserted_cb;
+    BlockDriverState *bdrv;
+    uint8_t *buf;
+
+    bool enable;
+};
+
+static void sd_set_mode(SDState *sd)
+{
+    switch (sd->state) {
+    case sd_inactive_state:
+        sd->mode = sd_inactive;
+        break;
+
+    case sd_idle_state:
+    case sd_ready_state:
+    case sd_identification_state:
+        sd->mode = sd_card_identification_mode;
+        break;
+
+    case sd_standby_state:
+    case sd_transfer_state:
+    case sd_sendingdata_state:
+    case sd_receivingdata_state:
+    case sd_programming_state:
+    case sd_disconnect_state:
+        sd->mode = sd_data_transfer_mode;
+        break;
+    }
+}
+
+static const sd_cmd_type_t sd_cmd_type[64] = {
+    sd_bc,   sd_none, sd_bcr,  sd_bcr,  sd_none, sd_none, sd_none, sd_ac,
+    sd_bcr,  sd_ac,   sd_ac,   sd_adtc, sd_ac,   sd_ac,   sd_none, sd_ac,
+    sd_ac,   sd_adtc, sd_adtc, sd_none, sd_none, sd_none, sd_none, sd_none,
+    sd_adtc, sd_adtc, sd_adtc, sd_adtc, sd_ac,   sd_ac,   sd_adtc, sd_none,
+    sd_ac,   sd_ac,   sd_none, sd_none, sd_none, sd_none, sd_ac,   sd_none,
+    sd_none, sd_none, sd_bc,   sd_none, sd_none, sd_none, sd_none, sd_none,
+    sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_ac,
+    sd_adtc, sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_none,
+};
+
+static const sd_cmd_type_t sd_acmd_type[64] = {
+    sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_ac,   sd_none,
+    sd_none, sd_none, sd_none, sd_none, sd_none, sd_adtc, sd_none, sd_none,
+    sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_adtc, sd_ac,
+    sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_none,
+    sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_none,
+    sd_none, sd_bcr,  sd_ac,   sd_none, sd_none, sd_none, sd_none, sd_none,
+    sd_none, sd_none, sd_none, sd_adtc, sd_none, sd_none, sd_none, sd_none,
+    sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_none,
+};
+
+static const int sd_cmd_class[64] = {
+    0,  0,  0,  0,  0,  9, 10,  0,  0,  0,  0,  1,  0,  0,  0,  0,
+    2,  2,  2,  2,  3,  3,  3,  3,  4,  4,  4,  4,  6,  6,  6,  6,
+    5,  5, 10, 10, 10, 10,  5,  9,  9,  9,  7,  7,  7,  7,  7,  7,
+    7,  7, 10,  7,  9,  9,  9,  8,  8, 10,  8,  8,  8,  8,  8,  8,
+};
+
+static uint8_t sd_crc7(void *message, size_t width)
+{
+    int i, bit;
+    uint8_t shift_reg = 0x00;
+    uint8_t *msg = (uint8_t *) message;
+
+    for (i = 0; i < width; i ++, msg ++)
+        for (bit = 7; bit >= 0; bit --) {
+            shift_reg <<= 1;
+            if ((shift_reg >> 7) ^ ((*msg >> bit) & 1))
+                shift_reg ^= 0x89;
+        }
+
+    return shift_reg;
+}
+
+static uint16_t sd_crc16(void *message, size_t width)
+{
+    int i, bit;
+    uint16_t shift_reg = 0x0000;
+    uint16_t *msg = (uint16_t *) message;
+    width <<= 1;
+
+    for (i = 0; i < width; i ++, msg ++)
+        for (bit = 15; bit >= 0; bit --) {
+            shift_reg <<= 1;
+            if ((shift_reg >> 15) ^ ((*msg >> bit) & 1))
+                shift_reg ^= 0x1011;
+        }
+
+    return shift_reg;
+}
+
+static void sd_set_ocr(SDState *sd)
+{
+    /* All voltages OK, card power-up OK, Standard Capacity SD Memory Card */
+    sd->ocr = 0x80ffff00;
+}
+
+static void sd_set_scr(SDState *sd)
+{
+    sd->scr[0] = 0x00;         /* SCR Structure */
+    sd->scr[1] = 0x2f;         /* SD Security Support */
+    sd->scr[2] = 0x00;
+    sd->scr[3] = 0x00;
+    sd->scr[4] = 0x00;
+    sd->scr[5] = 0x00;
+    sd->scr[6] = 0x00;
+    sd->scr[7] = 0x00;
+}
+
+#define MID    0xaa
+#define OID    "XY"
+#define PNM    "QEMU!"
+#define PRV    0x01
+#define MDT_YR 2006
+#define MDT_MON        2
+
+static void sd_set_cid(SDState *sd)
+{
+    sd->cid[0] = MID;          /* Fake card manufacturer ID (MID) */
+    sd->cid[1] = OID[0];       /* OEM/Application ID (OID) */
+    sd->cid[2] = OID[1];
+    sd->cid[3] = PNM[0];       /* Fake product name (PNM) */
+    sd->cid[4] = PNM[1];
+    sd->cid[5] = PNM[2];
+    sd->cid[6] = PNM[3];
+    sd->cid[7] = PNM[4];
+    sd->cid[8] = PRV;          /* Fake product revision (PRV) */
+    sd->cid[9] = 0xde;         /* Fake serial number (PSN) */
+    sd->cid[10] = 0xad;
+    sd->cid[11] = 0xbe;
+    sd->cid[12] = 0xef;
+    sd->cid[13] = 0x00 |       /* Manufacture date (MDT) */
+        ((MDT_YR - 2000) / 10);
+    sd->cid[14] = ((MDT_YR % 10) << 4) | MDT_MON;
+    sd->cid[15] = (sd_crc7(sd->cid, 15) << 1) | 1;
+}
+
+#define HWBLOCK_SHIFT  9                       /* 512 bytes */
+#define SECTOR_SHIFT   5                       /* 16 kilobytes */
+#define WPGROUP_SHIFT  7                       /* 2 megs */
+#define CMULT_SHIFT    9                       /* 512 times HWBLOCK_SIZE */
+#define WPGROUP_SIZE   (1 << (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT))
+
+static const uint8_t sd_csd_rw_mask[16] = {
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xfe,
+};
+
+static void sd_set_csd(SDState *sd, uint64_t size)
+{
+    uint32_t csize = (size >> (CMULT_SHIFT + HWBLOCK_SHIFT)) - 1;
+    uint32_t sectsize = (1 << (SECTOR_SHIFT + 1)) - 1;
+    uint32_t wpsize = (1 << (WPGROUP_SHIFT + 1)) - 1;
+
+    if (size <= 0x40000000) {  /* Standard Capacity SD */
+        sd->csd[0] = 0x00;     /* CSD structure */
+        sd->csd[1] = 0x26;     /* Data read access-time-1 */
+        sd->csd[2] = 0x00;     /* Data read access-time-2 */
+        sd->csd[3] = 0x5a;     /* Max. data transfer rate */
+        sd->csd[4] = 0x5f;     /* Card Command Classes */
+        sd->csd[5] = 0x50 |    /* Max. read data block length */
+            HWBLOCK_SHIFT;
+        sd->csd[6] = 0xe0 |    /* Partial block for read allowed */
+            ((csize >> 10) & 0x03);
+        sd->csd[7] = 0x00 |    /* Device size */
+            ((csize >> 2) & 0xff);
+        sd->csd[8] = 0x3f |    /* Max. read current */
+            ((csize << 6) & 0xc0);
+        sd->csd[9] = 0xfc |    /* Max. write current */
+            ((CMULT_SHIFT - 2) >> 1);
+        sd->csd[10] = 0x40 |   /* Erase sector size */
+            (((CMULT_SHIFT - 2) << 7) & 0x80) | (sectsize >> 1);
+        sd->csd[11] = 0x00 |   /* Write protect group size */
+            ((sectsize << 7) & 0x80) | wpsize;
+        sd->csd[12] = 0x90 |   /* Write speed factor */
+            (HWBLOCK_SHIFT >> 2);
+        sd->csd[13] = 0x20 |   /* Max. write data block length */
+            ((HWBLOCK_SHIFT << 6) & 0xc0);
+        sd->csd[14] = 0x00;    /* File format group */
+        sd->csd[15] = (sd_crc7(sd->csd, 15) << 1) | 1;
+    } else {                   /* SDHC */
+        size /= 512 * 1024;
+        size -= 1;
+        sd->csd[0] = 0x40;
+        sd->csd[1] = 0x0e;
+        sd->csd[2] = 0x00;
+        sd->csd[3] = 0x32;
+        sd->csd[4] = 0x5b;
+        sd->csd[5] = 0x59;
+        sd->csd[6] = 0x00;
+        sd->csd[7] = (size >> 16) & 0xff;
+        sd->csd[8] = (size >> 8) & 0xff;
+        sd->csd[9] = (size & 0xff);
+        sd->csd[10] = 0x7f;
+        sd->csd[11] = 0x80;
+        sd->csd[12] = 0x0a;
+        sd->csd[13] = 0x40;
+        sd->csd[14] = 0x00;
+        sd->csd[15] = 0x00;
+        sd->ocr |= 1 << 30;    /* High Capacity SD Memort Card */
+    }
+}
+
+static void sd_set_rca(SDState *sd)
+{
+    sd->rca += 0x4567;
+}
+
+/* Card status bits, split by clear condition:
+ * A : According to the card current state
+ * B : Always related to the previous command
+ * C : Cleared by read
+ */
+#define CARD_STATUS_A  0x02004100
+#define CARD_STATUS_B  0x00c01e00
+#define CARD_STATUS_C  0xfd39a028
+
+static void sd_set_cardstatus(SDState *sd)
+{
+    sd->card_status = 0x00000100;
+}
+
+static void sd_set_sdstatus(SDState *sd)
+{
+    memset(sd->sd_status, 0, 64);
+}
+
+static int sd_req_crc_validate(SDRequest *req)
+{
+    uint8_t buffer[5];
+    buffer[0] = 0x40 | req->cmd;
+    buffer[1] = (req->arg >> 24) & 0xff;
+    buffer[2] = (req->arg >> 16) & 0xff;
+    buffer[3] = (req->arg >> 8) & 0xff;
+    buffer[4] = (req->arg >> 0) & 0xff;
+    return 0;
+    return sd_crc7(buffer, 5) != req->crc;     /* TODO */
+}
+
+static void sd_response_r1_make(SDState *sd, uint8_t *response)
+{
+    uint32_t status = sd->card_status;
+    /* Clear the "clear on read" status bits */
+    sd->card_status &= ~CARD_STATUS_C;
+
+    response[0] = (status >> 24) & 0xff;
+    response[1] = (status >> 16) & 0xff;
+    response[2] = (status >> 8) & 0xff;
+    response[3] = (status >> 0) & 0xff;
+}
+
+static void sd_response_r3_make(SDState *sd, uint8_t *response)
+{
+    response[0] = (sd->ocr >> 24) & 0xff;
+    response[1] = (sd->ocr >> 16) & 0xff;
+    response[2] = (sd->ocr >> 8) & 0xff;
+    response[3] = (sd->ocr >> 0) & 0xff;
+}
+
+static void sd_response_r6_make(SDState *sd, uint8_t *response)
+{
+    uint16_t arg;
+    uint16_t status;
+
+    arg = sd->rca;
+    status = ((sd->card_status >> 8) & 0xc000) |
+             ((sd->card_status >> 6) & 0x2000) |
+              (sd->card_status & 0x1fff);
+    sd->card_status &= ~(CARD_STATUS_C & 0xc81fff);
+
+    response[0] = (arg >> 8) & 0xff;
+    response[1] = arg & 0xff;
+    response[2] = (status >> 8) & 0xff;
+    response[3] = status & 0xff;
+}
+
+static void sd_response_r7_make(SDState *sd, uint8_t *response)
+{
+    response[0] = (sd->vhs >> 24) & 0xff;
+    response[1] = (sd->vhs >> 16) & 0xff;
+    response[2] = (sd->vhs >>  8) & 0xff;
+    response[3] = (sd->vhs >>  0) & 0xff;
+}
+
+static inline uint64_t sd_addr_to_wpnum(uint64_t addr)
+{
+    return addr >> (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT);
+}
+
+static void sd_reset(SDState *sd, BlockDriverState *bdrv)
+{
+    uint64_t size;
+    uint64_t sect;
+
+    if (bdrv) {
+        bdrv_get_geometry(bdrv, &sect);
+    } else {
+        sect = 0;
+    }
+    size = sect << 9;
+
+    sect = sd_addr_to_wpnum(size) + 1;
+
+    sd->state = sd_idle_state;
+    sd->rca = 0x0000;
+    sd_set_ocr(sd);
+    sd_set_scr(sd);
+    sd_set_cid(sd);
+    sd_set_csd(sd, size);
+    sd_set_cardstatus(sd);
+    sd_set_sdstatus(sd);
+
+    sd->bdrv = bdrv;
+
+    if (sd->wp_groups)
+        g_free(sd->wp_groups);
+    sd->wp_switch = bdrv ? bdrv_is_read_only(bdrv) : false;
+    sd->wpgrps_size = sect;
+    sd->wp_groups = bitmap_new(sd->wpgrps_size);
+    memset(sd->function_group, 0, sizeof(sd->function_group));
+    sd->erase_start = 0;
+    sd->erase_end = 0;
+    sd->size = size;
+    sd->blk_len = 0x200;
+    sd->pwd_len = 0;
+    sd->expecting_acmd = false;
+}
+
+static void sd_cardchange(void *opaque, bool load)
+{
+    SDState *sd = opaque;
+
+    qemu_set_irq(sd->inserted_cb, bdrv_is_inserted(sd->bdrv));
+    if (bdrv_is_inserted(sd->bdrv)) {
+        sd_reset(sd, sd->bdrv);
+        qemu_set_irq(sd->readonly_cb, sd->wp_switch);
+    }
+}
+
+static const BlockDevOps sd_block_ops = {
+    .change_media_cb = sd_cardchange,
+};
+
+static const VMStateDescription sd_vmstate = {
+    .name = "sd-card",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(mode, SDState),
+        VMSTATE_INT32(state, SDState),
+        VMSTATE_UINT8_ARRAY(cid, SDState, 16),
+        VMSTATE_UINT8_ARRAY(csd, SDState, 16),
+        VMSTATE_UINT16(rca, SDState),
+        VMSTATE_UINT32(card_status, SDState),
+        VMSTATE_PARTIAL_BUFFER(sd_status, SDState, 1),
+        VMSTATE_UINT32(vhs, SDState),
+        VMSTATE_BITMAP(wp_groups, SDState, 0, wpgrps_size),
+        VMSTATE_UINT32(blk_len, SDState),
+        VMSTATE_UINT32(erase_start, SDState),
+        VMSTATE_UINT32(erase_end, SDState),
+        VMSTATE_UINT8_ARRAY(pwd, SDState, 16),
+        VMSTATE_UINT32(pwd_len, SDState),
+        VMSTATE_UINT8_ARRAY(function_group, SDState, 6),
+        VMSTATE_UINT8(current_cmd, SDState),
+        VMSTATE_BOOL(expecting_acmd, SDState),
+        VMSTATE_UINT32(blk_written, SDState),
+        VMSTATE_UINT64(data_start, SDState),
+        VMSTATE_UINT32(data_offset, SDState),
+        VMSTATE_UINT8_ARRAY(data, SDState, 512),
+        VMSTATE_BUFFER_POINTER_UNSAFE(buf, SDState, 1, 512),
+        VMSTATE_BOOL(enable, SDState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+/* We do not model the chip select pin, so allow the board to select
+   whether card should be in SSI or MMC/SD mode.  It is also up to the
+   board to ensure that ssi transfers only occur when the chip select
+   is asserted.  */
+SDState *sd_init(BlockDriverState *bs, bool is_spi)
+{
+    SDState *sd;
+
+    sd = (SDState *) g_malloc0(sizeof(SDState));
+    sd->buf = qemu_blockalign(bs, 512);
+    sd->spi = is_spi;
+    sd->enable = true;
+    sd_reset(sd, bs);
+    if (sd->bdrv) {
+        bdrv_attach_dev_nofail(sd->bdrv, sd);
+        bdrv_set_dev_ops(sd->bdrv, &sd_block_ops, sd);
+    }
+    vmstate_register(NULL, -1, &sd_vmstate, sd);
+    return sd;
+}
+
+void sd_set_cb(SDState *sd, qemu_irq readonly, qemu_irq insert)
+{
+    sd->readonly_cb = readonly;
+    sd->inserted_cb = insert;
+    qemu_set_irq(readonly, sd->bdrv ? bdrv_is_read_only(sd->bdrv) : 0);
+    qemu_set_irq(insert, sd->bdrv ? bdrv_is_inserted(sd->bdrv) : 0);
+}
+
+static void sd_erase(SDState *sd)
+{
+    int i;
+    uint64_t erase_start = sd->erase_start;
+    uint64_t erase_end = sd->erase_end;
+
+    if (!sd->erase_start || !sd->erase_end) {
+        sd->card_status |= ERASE_SEQ_ERROR;
+        return;
+    }
+
+    if (extract32(sd->ocr, OCR_CCS_BITN, 1)) {
+        /* High capacity memory card: erase units are 512 byte blocks */
+        erase_start *= 512;
+        erase_end *= 512;
+    }
+
+    erase_start = sd_addr_to_wpnum(erase_start);
+    erase_end = sd_addr_to_wpnum(erase_end);
+    sd->erase_start = 0;
+    sd->erase_end = 0;
+    sd->csd[14] |= 0x40;
+
+    for (i = erase_start; i <= erase_end; i++) {
+        if (test_bit(i, sd->wp_groups)) {
+            sd->card_status |= WP_ERASE_SKIP;
+        }
+    }
+}
+
+static uint32_t sd_wpbits(SDState *sd, uint64_t addr)
+{
+    uint32_t i, wpnum;
+    uint32_t ret = 0;
+
+    wpnum = sd_addr_to_wpnum(addr);
+
+    for (i = 0; i < 32; i++, wpnum++, addr += WPGROUP_SIZE) {
+        if (addr < sd->size && test_bit(wpnum, sd->wp_groups)) {
+            ret |= (1 << i);
+        }
+    }
+
+    return ret;
+}
+
+static void sd_function_switch(SDState *sd, uint32_t arg)
+{
+    int i, mode, new_func, crc;
+    mode = !!(arg & 0x80000000);
+
+    sd->data[0] = 0x00;                /* Maximum current consumption */
+    sd->data[1] = 0x01;
+    sd->data[2] = 0x80;                /* Supported group 6 functions */
+    sd->data[3] = 0x01;
+    sd->data[4] = 0x80;                /* Supported group 5 functions */
+    sd->data[5] = 0x01;
+    sd->data[6] = 0x80;                /* Supported group 4 functions */
+    sd->data[7] = 0x01;
+    sd->data[8] = 0x80;                /* Supported group 3 functions */
+    sd->data[9] = 0x01;
+    sd->data[10] = 0x80;       /* Supported group 2 functions */
+    sd->data[11] = 0x43;
+    sd->data[12] = 0x80;       /* Supported group 1 functions */
+    sd->data[13] = 0x03;
+    for (i = 0; i < 6; i ++) {
+        new_func = (arg >> (i * 4)) & 0x0f;
+        if (mode && new_func != 0x0f)
+            sd->function_group[i] = new_func;
+        sd->data[14 + (i >> 1)] = new_func << ((i * 4) & 4);
+    }
+    memset(&sd->data[17], 0, 47);
+    crc = sd_crc16(sd->data, 64);
+    sd->data[65] = crc >> 8;
+    sd->data[66] = crc & 0xff;
+}
+
+static inline bool sd_wp_addr(SDState *sd, uint64_t addr)
+{
+    return test_bit(sd_addr_to_wpnum(addr), sd->wp_groups);
+}
+
+static void sd_lock_command(SDState *sd)
+{
+    int erase, lock, clr_pwd, set_pwd, pwd_len;
+    erase = !!(sd->data[0] & 0x08);
+    lock = sd->data[0] & 0x04;
+    clr_pwd = sd->data[0] & 0x02;
+    set_pwd = sd->data[0] & 0x01;
+
+    if (sd->blk_len > 1)
+        pwd_len = sd->data[1];
+    else
+        pwd_len = 0;
+
+    if (erase) {
+        if (!(sd->card_status & CARD_IS_LOCKED) || sd->blk_len > 1 ||
+                        set_pwd || clr_pwd || lock || sd->wp_switch ||
+                        (sd->csd[14] & 0x20)) {
+            sd->card_status |= LOCK_UNLOCK_FAILED;
+            return;
+        }
+        bitmap_zero(sd->wp_groups, sd->wpgrps_size);
+        sd->csd[14] &= ~0x10;
+        sd->card_status &= ~CARD_IS_LOCKED;
+        sd->pwd_len = 0;
+        /* Erasing the entire card here! */
+        fprintf(stderr, "SD: Card force-erased by CMD42\n");
+        return;
+    }
+
+    if (sd->blk_len < 2 + pwd_len ||
+                    pwd_len <= sd->pwd_len ||
+                    pwd_len > sd->pwd_len + 16) {
+        sd->card_status |= LOCK_UNLOCK_FAILED;
+        return;
+    }
+
+    if (sd->pwd_len && memcmp(sd->pwd, sd->data + 2, sd->pwd_len)) {
+        sd->card_status |= LOCK_UNLOCK_FAILED;
+        return;
+    }
+
+    pwd_len -= sd->pwd_len;
+    if ((pwd_len && !set_pwd) ||
+                    (clr_pwd && (set_pwd || lock)) ||
+                    (lock && !sd->pwd_len && !set_pwd) ||
+                    (!set_pwd && !clr_pwd &&
+                     (((sd->card_status & CARD_IS_LOCKED) && lock) ||
+                      (!(sd->card_status & CARD_IS_LOCKED) && !lock)))) {
+        sd->card_status |= LOCK_UNLOCK_FAILED;
+        return;
+    }
+
+    if (set_pwd) {
+        memcpy(sd->pwd, sd->data + 2 + sd->pwd_len, pwd_len);
+        sd->pwd_len = pwd_len;
+    }
+
+    if (clr_pwd) {
+        sd->pwd_len = 0;
+    }
+
+    if (lock)
+        sd->card_status |= CARD_IS_LOCKED;
+    else
+        sd->card_status &= ~CARD_IS_LOCKED;
+}
+
+static sd_rsp_type_t sd_normal_command(SDState *sd,
+                                       SDRequest req)
+{
+    uint32_t rca = 0x0000;
+    uint64_t addr = (sd->ocr & (1 << 30)) ? (uint64_t) req.arg << 9 : req.arg;
+
+    /* Not interpreting this as an app command */
+    sd->card_status &= ~APP_CMD;
+
+    if (sd_cmd_type[req.cmd] == sd_ac || sd_cmd_type[req.cmd] == sd_adtc)
+        rca = req.arg >> 16;
+
+    DPRINTF("CMD%d 0x%08x state %d\n", req.cmd, req.arg, sd->state);
+    switch (req.cmd) {
+    /* Basic commands (Class 0 and Class 1) */
+    case 0:    /* CMD0:   GO_IDLE_STATE */
+        switch (sd->state) {
+        case sd_inactive_state:
+            return sd->spi ? sd_r1 : sd_r0;
+
+        default:
+            sd->state = sd_idle_state;
+            sd_reset(sd, sd->bdrv);
+            return sd->spi ? sd_r1 : sd_r0;
+        }
+        break;
+
+    case 1:    /* CMD1:   SEND_OP_CMD */
+        if (!sd->spi)
+            goto bad_cmd;
+
+        sd->state = sd_transfer_state;
+        return sd_r1;
+
+    case 2:    /* CMD2:   ALL_SEND_CID */
+        if (sd->spi)
+            goto bad_cmd;
+        switch (sd->state) {
+        case sd_ready_state:
+            sd->state = sd_identification_state;
+            return sd_r2_i;
+
+        default:
+            break;
+        }
+        break;
+
+    case 3:    /* CMD3:   SEND_RELATIVE_ADDR */
+        if (sd->spi)
+            goto bad_cmd;
+        switch (sd->state) {
+        case sd_identification_state:
+        case sd_standby_state:
+            sd->state = sd_standby_state;
+            sd_set_rca(sd);
+            return sd_r6;
+
+        default:
+            break;
+        }
+        break;
+
+    case 4:    /* CMD4:   SEND_DSR */
+        if (sd->spi)
+            goto bad_cmd;
+        switch (sd->state) {
+        case sd_standby_state:
+            break;
+
+        default:
+            break;
+        }
+        break;
+
+    case 5: /* CMD5: reserved for SDIO cards */
+        return sd_illegal;
+
+    case 6:    /* CMD6:   SWITCH_FUNCTION */
+        if (sd->spi)
+            goto bad_cmd;
+        switch (sd->mode) {
+        case sd_data_transfer_mode:
+            sd_function_switch(sd, req.arg);
+            sd->state = sd_sendingdata_state;
+            sd->data_start = 0;
+            sd->data_offset = 0;
+            return sd_r1;
+
+        default:
+            break;
+        }
+        break;
+
+    case 7:    /* CMD7:   SELECT/DESELECT_CARD */
+        if (sd->spi)
+            goto bad_cmd;
+        switch (sd->state) {
+        case sd_standby_state:
+            if (sd->rca != rca)
+                return sd_r0;
+
+            sd->state = sd_transfer_state;
+            return sd_r1b;
+
+        case sd_transfer_state:
+        case sd_sendingdata_state:
+            if (sd->rca == rca)
+                break;
+
+            sd->state = sd_standby_state;
+            return sd_r1b;
+
+        case sd_disconnect_state:
+            if (sd->rca != rca)
+                return sd_r0;
+
+            sd->state = sd_programming_state;
+            return sd_r1b;
+
+        case sd_programming_state:
+            if (sd->rca == rca)
+                break;
+
+            sd->state = sd_disconnect_state;
+            return sd_r1b;
+
+        default:
+            break;
+        }
+        break;
+
+    case 8:    /* CMD8:   SEND_IF_COND */
+        /* Physical Layer Specification Version 2.00 command */
+        switch (sd->state) {
+        case sd_idle_state:
+            sd->vhs = 0;
+
+            /* No response if not exactly one VHS bit is set.  */
+            if (!(req.arg >> 8) || (req.arg >> ffs(req.arg & ~0xff)))
+                return sd->spi ? sd_r7 : sd_r0;
+
+            /* Accept.  */
+            sd->vhs = req.arg;
+            return sd_r7;
+
+        default:
+            break;
+        }
+        break;
+
+    case 9:    /* CMD9:   SEND_CSD */
+        switch (sd->state) {
+        case sd_standby_state:
+            if (sd->rca != rca)
+                return sd_r0;
+
+            return sd_r2_s;
+
+        case sd_transfer_state:
+            if (!sd->spi)
+                break;
+            sd->state = sd_sendingdata_state;
+            memcpy(sd->data, sd->csd, 16);
+            sd->data_start = addr;
+            sd->data_offset = 0;
+            return sd_r1;
+
+        default:
+            break;
+        }
+        break;
+
+    case 10:   /* CMD10:  SEND_CID */
+        switch (sd->state) {
+        case sd_standby_state:
+            if (sd->rca != rca)
+                return sd_r0;
+
+            return sd_r2_i;
+
+        case sd_transfer_state:
+            if (!sd->spi)
+                break;
+            sd->state = sd_sendingdata_state;
+            memcpy(sd->data, sd->cid, 16);
+            sd->data_start = addr;
+            sd->data_offset = 0;
+            return sd_r1;
+
+        default:
+            break;
+        }
+        break;
+
+    case 11:   /* CMD11:  READ_DAT_UNTIL_STOP */
+        if (sd->spi)
+            goto bad_cmd;
+        switch (sd->state) {
+        case sd_transfer_state:
+            sd->state = sd_sendingdata_state;
+            sd->data_start = req.arg;
+            sd->data_offset = 0;
+
+            if (sd->data_start + sd->blk_len > sd->size)
+                sd->card_status |= ADDRESS_ERROR;
+            return sd_r0;
+
+        default:
+            break;
+        }
+        break;
+
+    case 12:   /* CMD12:  STOP_TRANSMISSION */
+        switch (sd->state) {
+        case sd_sendingdata_state:
+            sd->state = sd_transfer_state;
+            return sd_r1b;
+
+        case sd_receivingdata_state:
+            sd->state = sd_programming_state;
+            /* Bzzzzzzztt .... Operation complete.  */
+            sd->state = sd_transfer_state;
+            return sd_r1b;
+
+        default:
+            break;
+        }
+        break;
+
+    case 13:   /* CMD13:  SEND_STATUS */
+        switch (sd->mode) {
+        case sd_data_transfer_mode:
+            if (sd->rca != rca)
+                return sd_r0;
+
+            return sd_r1;
+
+        default:
+            break;
+        }
+        break;
+
+    case 15:   /* CMD15:  GO_INACTIVE_STATE */
+        if (sd->spi)
+            goto bad_cmd;
+        switch (sd->mode) {
+        case sd_data_transfer_mode:
+            if (sd->rca != rca)
+                return sd_r0;
+
+            sd->state = sd_inactive_state;
+            return sd_r0;
+
+        default:
+            break;
+        }
+        break;
+
+    /* Block read commands (Classs 2) */
+    case 16:   /* CMD16:  SET_BLOCKLEN */
+        switch (sd->state) {
+        case sd_transfer_state:
+            if (req.arg > (1 << HWBLOCK_SHIFT))
+                sd->card_status |= BLOCK_LEN_ERROR;
+            else
+                sd->blk_len = req.arg;
+
+            return sd_r1;
+
+        default:
+            break;
+        }
+        break;
+
+    case 17:   /* CMD17:  READ_SINGLE_BLOCK */
+        switch (sd->state) {
+        case sd_transfer_state:
+            sd->state = sd_sendingdata_state;
+            sd->data_start = addr;
+            sd->data_offset = 0;
+
+            if (sd->data_start + sd->blk_len > sd->size)
+                sd->card_status |= ADDRESS_ERROR;
+            return sd_r1;
+
+        default:
+            break;
+        }
+        break;
+
+    case 18:   /* CMD18:  READ_MULTIPLE_BLOCK */
+        switch (sd->state) {
+        case sd_transfer_state:
+            sd->state = sd_sendingdata_state;
+            sd->data_start = addr;
+            sd->data_offset = 0;
+
+            if (sd->data_start + sd->blk_len > sd->size)
+                sd->card_status |= ADDRESS_ERROR;
+            return sd_r1;
+
+        default:
+            break;
+        }
+        break;
+
+    /* Block write commands (Class 4) */
+    case 24:   /* CMD24:  WRITE_SINGLE_BLOCK */
+        if (sd->spi)
+            goto unimplemented_cmd;
+        switch (sd->state) {
+        case sd_transfer_state:
+            /* Writing in SPI mode not implemented.  */
+            if (sd->spi)
+                break;
+            sd->state = sd_receivingdata_state;
+            sd->data_start = addr;
+            sd->data_offset = 0;
+            sd->blk_written = 0;
+
+            if (sd->data_start + sd->blk_len > sd->size)
+                sd->card_status |= ADDRESS_ERROR;
+            if (sd_wp_addr(sd, sd->data_start))
+                sd->card_status |= WP_VIOLATION;
+            if (sd->csd[14] & 0x30)
+                sd->card_status |= WP_VIOLATION;
+            return sd_r1;
+
+        default:
+            break;
+        }
+        break;
+
+    case 25:   /* CMD25:  WRITE_MULTIPLE_BLOCK */
+        if (sd->spi)
+            goto unimplemented_cmd;
+        switch (sd->state) {
+        case sd_transfer_state:
+            /* Writing in SPI mode not implemented.  */
+            if (sd->spi)
+                break;
+            sd->state = sd_receivingdata_state;
+            sd->data_start = addr;
+            sd->data_offset = 0;
+            sd->blk_written = 0;
+
+            if (sd->data_start + sd->blk_len > sd->size)
+                sd->card_status |= ADDRESS_ERROR;
+            if (sd_wp_addr(sd, sd->data_start))
+                sd->card_status |= WP_VIOLATION;
+            if (sd->csd[14] & 0x30)
+                sd->card_status |= WP_VIOLATION;
+            return sd_r1;
+
+        default:
+            break;
+        }
+        break;
+
+    case 26:   /* CMD26:  PROGRAM_CID */
+        if (sd->spi)
+            goto bad_cmd;
+        switch (sd->state) {
+        case sd_transfer_state:
+            sd->state = sd_receivingdata_state;
+            sd->data_start = 0;
+            sd->data_offset = 0;
+            return sd_r1;
+
+        default:
+            break;
+        }
+        break;
+
+    case 27:   /* CMD27:  PROGRAM_CSD */
+        if (sd->spi)
+            goto unimplemented_cmd;
+        switch (sd->state) {
+        case sd_transfer_state:
+            sd->state = sd_receivingdata_state;
+            sd->data_start = 0;
+            sd->data_offset = 0;
+            return sd_r1;
+
+        default:
+            break;
+        }
+        break;
+
+    /* Write protection (Class 6) */
+    case 28:   /* CMD28:  SET_WRITE_PROT */
+        switch (sd->state) {
+        case sd_transfer_state:
+            if (addr >= sd->size) {
+                sd->card_status |= ADDRESS_ERROR;
+                return sd_r1b;
+            }
+
+            sd->state = sd_programming_state;
+            set_bit(sd_addr_to_wpnum(addr), sd->wp_groups);
+            /* Bzzzzzzztt .... Operation complete.  */
+            sd->state = sd_transfer_state;
+            return sd_r1b;
+
+        default:
+            break;
+        }
+        break;
+
+    case 29:   /* CMD29:  CLR_WRITE_PROT */
+        switch (sd->state) {
+        case sd_transfer_state:
+            if (addr >= sd->size) {
+                sd->card_status |= ADDRESS_ERROR;
+                return sd_r1b;
+            }
+
+            sd->state = sd_programming_state;
+            clear_bit(sd_addr_to_wpnum(addr), sd->wp_groups);
+            /* Bzzzzzzztt .... Operation complete.  */
+            sd->state = sd_transfer_state;
+            return sd_r1b;
+
+        default:
+            break;
+        }
+        break;
+
+    case 30:   /* CMD30:  SEND_WRITE_PROT */
+        switch (sd->state) {
+        case sd_transfer_state:
+            sd->state = sd_sendingdata_state;
+            *(uint32_t *) sd->data = sd_wpbits(sd, req.arg);
+            sd->data_start = addr;
+            sd->data_offset = 0;
+            return sd_r1b;
+
+        default:
+            break;
+        }
+        break;
+
+    /* Erase commands (Class 5) */
+    case 32:   /* CMD32:  ERASE_WR_BLK_START */
+        switch (sd->state) {
+        case sd_transfer_state:
+            sd->erase_start = req.arg;
+            return sd_r1;
+
+        default:
+            break;
+        }
+        break;
+
+    case 33:   /* CMD33:  ERASE_WR_BLK_END */
+        switch (sd->state) {
+        case sd_transfer_state:
+            sd->erase_end = req.arg;
+            return sd_r1;
+
+        default:
+            break;
+        }
+        break;
+
+    case 38:   /* CMD38:  ERASE */
+        switch (sd->state) {
+        case sd_transfer_state:
+            if (sd->csd[14] & 0x30) {
+                sd->card_status |= WP_VIOLATION;
+                return sd_r1b;
+            }
+
+            sd->state = sd_programming_state;
+            sd_erase(sd);
+            /* Bzzzzzzztt .... Operation complete.  */
+            sd->state = sd_transfer_state;
+            return sd_r1b;
+
+        default:
+            break;
+        }
+        break;
+
+    /* Lock card commands (Class 7) */
+    case 42:   /* CMD42:  LOCK_UNLOCK */
+        if (sd->spi)
+            goto unimplemented_cmd;
+        switch (sd->state) {
+        case sd_transfer_state:
+            sd->state = sd_receivingdata_state;
+            sd->data_start = 0;
+            sd->data_offset = 0;
+            return sd_r1;
+
+        default:
+            break;
+        }
+        break;
+
+    case 52:
+    case 53:
+        /* CMD52, CMD53: reserved for SDIO cards
+         * (see the SDIO Simplified Specification V2.0)
+         * Handle as illegal command but do not complain
+         * on stderr, as some OSes may use these in their
+         * probing for presence of an SDIO card.
+         */
+        return sd_illegal;
+
+    /* Application specific commands (Class 8) */
+    case 55:   /* CMD55:  APP_CMD */
+        if (sd->rca != rca)
+            return sd_r0;
+
+        sd->expecting_acmd = true;
+        sd->card_status |= APP_CMD;
+        return sd_r1;
+
+    case 56:   /* CMD56:  GEN_CMD */
+        fprintf(stderr, "SD: GEN_CMD 0x%08x\n", req.arg);
+
+        switch (sd->state) {
+        case sd_transfer_state:
+            sd->data_offset = 0;
+            if (req.arg & 1)
+                sd->state = sd_sendingdata_state;
+            else
+                sd->state = sd_receivingdata_state;
+            return sd_r1;
+
+        default:
+            break;
+        }
+        break;
+
+    default:
+    bad_cmd:
+        fprintf(stderr, "SD: Unknown CMD%i\n", req.cmd);
+        return sd_illegal;
+
+    unimplemented_cmd:
+        /* Commands that are recognised but not yet implemented in SPI mode.  */
+        fprintf(stderr, "SD: CMD%i not implemented in SPI mode\n", req.cmd);
+        return sd_illegal;
+    }
+
+    fprintf(stderr, "SD: CMD%i in a wrong state\n", req.cmd);
+    return sd_illegal;
+}
+
+static sd_rsp_type_t sd_app_command(SDState *sd,
+                                    SDRequest req)
+{
+    DPRINTF("ACMD%d 0x%08x\n", req.cmd, req.arg);
+    sd->card_status |= APP_CMD;
+    switch (req.cmd) {
+    case 6:    /* ACMD6:  SET_BUS_WIDTH */
+        switch (sd->state) {
+        case sd_transfer_state:
+            sd->sd_status[0] &= 0x3f;
+            sd->sd_status[0] |= (req.arg & 0x03) << 6;
+            return sd_r1;
+
+        default:
+            break;
+        }
+        break;
+
+    case 13:   /* ACMD13: SD_STATUS */
+        switch (sd->state) {
+        case sd_transfer_state:
+            sd->state = sd_sendingdata_state;
+            sd->data_start = 0;
+            sd->data_offset = 0;
+            return sd_r1;
+
+        default:
+            break;
+        }
+        break;
+
+    case 22:   /* ACMD22: SEND_NUM_WR_BLOCKS */
+        switch (sd->state) {
+        case sd_transfer_state:
+            *(uint32_t *) sd->data = sd->blk_written;
+
+            sd->state = sd_sendingdata_state;
+            sd->data_start = 0;
+            sd->data_offset = 0;
+            return sd_r1;
+
+        default:
+            break;
+        }
+        break;
+
+    case 23:   /* ACMD23: SET_WR_BLK_ERASE_COUNT */
+        switch (sd->state) {
+        case sd_transfer_state:
+            return sd_r1;
+
+        default:
+            break;
+        }
+        break;
+
+    case 41:   /* ACMD41: SD_APP_OP_COND */
+        if (sd->spi) {
+            /* SEND_OP_CMD */
+            sd->state = sd_transfer_state;
+            return sd_r1;
+        }
+        switch (sd->state) {
+        case sd_idle_state:
+            /* We accept any voltage.  10000 V is nothing.  */
+            if (req.arg)
+                sd->state = sd_ready_state;
+
+            return sd_r3;
+
+        default:
+            break;
+        }
+        break;
+
+    case 42:   /* ACMD42: SET_CLR_CARD_DETECT */
+        switch (sd->state) {
+        case sd_transfer_state:
+            /* Bringing in the 50KOhm pull-up resistor... Done.  */
+            return sd_r1;
+
+        default:
+            break;
+        }
+        break;
+
+    case 51:   /* ACMD51: SEND_SCR */
+        switch (sd->state) {
+        case sd_transfer_state:
+            sd->state = sd_sendingdata_state;
+            sd->data_start = 0;
+            sd->data_offset = 0;
+            return sd_r1;
+
+        default:
+            break;
+        }
+        break;
+
+    default:
+        /* Fall back to standard commands.  */
+        return sd_normal_command(sd, req);
+    }
+
+    fprintf(stderr, "SD: ACMD%i in a wrong state\n", req.cmd);
+    return sd_illegal;
+}
+
+static int cmd_valid_while_locked(SDState *sd, SDRequest *req)
+{
+    /* Valid commands in locked state:
+     * basic class (0)
+     * lock card class (7)
+     * CMD16
+     * implicitly, the ACMD prefix CMD55
+     * ACMD41 and ACMD42
+     * Anything else provokes an "illegal command" response.
+     */
+    if (sd->expecting_acmd) {
+        return req->cmd == 41 || req->cmd == 42;
+    }
+    if (req->cmd == 16 || req->cmd == 55) {
+        return 1;
+    }
+    return sd_cmd_class[req->cmd] == 0 || sd_cmd_class[req->cmd] == 7;
+}
+
+int sd_do_command(SDState *sd, SDRequest *req,
+                  uint8_t *response) {
+    int last_state;
+    sd_rsp_type_t rtype;
+    int rsplen;
+
+    if (!sd->bdrv || !bdrv_is_inserted(sd->bdrv) || !sd->enable) {
+        return 0;
+    }
+
+    if (sd_req_crc_validate(req)) {
+        sd->card_status |= COM_CRC_ERROR;
+        rtype = sd_illegal;
+        goto send_response;
+    }
+
+    if (sd->card_status & CARD_IS_LOCKED) {
+        if (!cmd_valid_while_locked(sd, req)) {
+            sd->card_status |= ILLEGAL_COMMAND;
+            sd->expecting_acmd = false;
+            fprintf(stderr, "SD: Card is locked\n");
+            rtype = sd_illegal;
+            goto send_response;
+        }
+    }
+
+    last_state = sd->state;
+    sd_set_mode(sd);
+
+    if (sd->expecting_acmd) {
+        sd->expecting_acmd = false;
+        rtype = sd_app_command(sd, *req);
+    } else {
+        rtype = sd_normal_command(sd, *req);
+    }
+
+    if (rtype == sd_illegal) {
+        sd->card_status |= ILLEGAL_COMMAND;
+    } else {
+        /* Valid command, we can update the 'state before command' bits.
+         * (Do this now so they appear in r1 responses.)
+         */
+        sd->current_cmd = req->cmd;
+        sd->card_status &= ~CURRENT_STATE;
+        sd->card_status |= (last_state << 9);
+    }
+
+send_response:
+    switch (rtype) {
+    case sd_r1:
+    case sd_r1b:
+        sd_response_r1_make(sd, response);
+        rsplen = 4;
+        break;
+
+    case sd_r2_i:
+        memcpy(response, sd->cid, sizeof(sd->cid));
+        rsplen = 16;
+        break;
+
+    case sd_r2_s:
+        memcpy(response, sd->csd, sizeof(sd->csd));
+        rsplen = 16;
+        break;
+
+    case sd_r3:
+        sd_response_r3_make(sd, response);
+        rsplen = 4;
+        break;
+
+    case sd_r6:
+        sd_response_r6_make(sd, response);
+        rsplen = 4;
+        break;
+
+    case sd_r7:
+        sd_response_r7_make(sd, response);
+        rsplen = 4;
+        break;
+
+    case sd_r0:
+    case sd_illegal:
+    default:
+        rsplen = 0;
+        break;
+    }
+
+    if (rtype != sd_illegal) {
+        /* Clear the "clear on valid command" status bits now we've
+         * sent any response
+         */
+        sd->card_status &= ~CARD_STATUS_B;
+    }
+
+#ifdef DEBUG_SD
+    if (rsplen) {
+        int i;
+        DPRINTF("Response:");
+        for (i = 0; i < rsplen; i++)
+            fprintf(stderr, " %02x", response[i]);
+        fprintf(stderr, " state %d\n", sd->state);
+    } else {
+        DPRINTF("No response %d\n", sd->state);
+    }
+#endif
+
+    return rsplen;
+}
+
+static void sd_blk_read(SDState *sd, uint64_t addr, uint32_t len)
+{
+    uint64_t end = addr + len;
+
+    DPRINTF("sd_blk_read: addr = 0x%08llx, len = %d\n",
+            (unsigned long long) addr, len);
+    if (!sd->bdrv || bdrv_read(sd->bdrv, addr >> 9, sd->buf, 1) < 0) {
+        fprintf(stderr, "sd_blk_read: read error on host side\n");
+        return;
+    }
+
+    if (end > (addr & ~511) + 512) {
+        memcpy(sd->data, sd->buf + (addr & 511), 512 - (addr & 511));
+
+        if (bdrv_read(sd->bdrv, end >> 9, sd->buf, 1) < 0) {
+            fprintf(stderr, "sd_blk_read: read error on host side\n");
+            return;
+        }
+        memcpy(sd->data + 512 - (addr & 511), sd->buf, end & 511);
+    } else
+        memcpy(sd->data, sd->buf + (addr & 511), len);
+}
+
+static void sd_blk_write(SDState *sd, uint64_t addr, uint32_t len)
+{
+    uint64_t end = addr + len;
+
+    if ((addr & 511) || len < 512)
+        if (!sd->bdrv || bdrv_read(sd->bdrv, addr >> 9, sd->buf, 1) < 0) {
+            fprintf(stderr, "sd_blk_write: read error on host side\n");
+            return;
+        }
+
+    if (end > (addr & ~511) + 512) {
+        memcpy(sd->buf + (addr & 511), sd->data, 512 - (addr & 511));
+        if (bdrv_write(sd->bdrv, addr >> 9, sd->buf, 1) < 0) {
+            fprintf(stderr, "sd_blk_write: write error on host side\n");
+            return;
+        }
+
+        if (bdrv_read(sd->bdrv, end >> 9, sd->buf, 1) < 0) {
+            fprintf(stderr, "sd_blk_write: read error on host side\n");
+            return;
+        }
+        memcpy(sd->buf, sd->data + 512 - (addr & 511), end & 511);
+        if (bdrv_write(sd->bdrv, end >> 9, sd->buf, 1) < 0) {
+            fprintf(stderr, "sd_blk_write: write error on host side\n");
+        }
+    } else {
+        memcpy(sd->buf + (addr & 511), sd->data, len);
+        if (!sd->bdrv || bdrv_write(sd->bdrv, addr >> 9, sd->buf, 1) < 0) {
+            fprintf(stderr, "sd_blk_write: write error on host side\n");
+        }
+    }
+}
+
+#define BLK_READ_BLOCK(a, len) sd_blk_read(sd, a, len)
+#define BLK_WRITE_BLOCK(a, len)        sd_blk_write(sd, a, len)
+#define APP_READ_BLOCK(a, len) memset(sd->data, 0xec, len)
+#define APP_WRITE_BLOCK(a, len)
+
+void sd_write_data(SDState *sd, uint8_t value)
+{
+    int i;
+
+    if (!sd->bdrv || !bdrv_is_inserted(sd->bdrv) || !sd->enable)
+        return;
+
+    if (sd->state != sd_receivingdata_state) {
+        fprintf(stderr, "sd_write_data: not in Receiving-Data state\n");
+        return;
+    }
+
+    if (sd->card_status & (ADDRESS_ERROR | WP_VIOLATION))
+        return;
+
+    switch (sd->current_cmd) {
+    case 24:   /* CMD24:  WRITE_SINGLE_BLOCK */
+        sd->data[sd->data_offset ++] = value;
+        if (sd->data_offset >= sd->blk_len) {
+            /* TODO: Check CRC before committing */
+            sd->state = sd_programming_state;
+            BLK_WRITE_BLOCK(sd->data_start, sd->data_offset);
+            sd->blk_written ++;
+            sd->csd[14] |= 0x40;
+            /* Bzzzzzzztt .... Operation complete.  */
+            sd->state = sd_transfer_state;
+        }
+        break;
+
+    case 25:   /* CMD25:  WRITE_MULTIPLE_BLOCK */
+        if (sd->data_offset == 0) {
+            /* Start of the block - lets check the address is valid */
+            if (sd->data_start + sd->blk_len > sd->size) {
+                sd->card_status |= ADDRESS_ERROR;
+                break;
+            }
+            if (sd_wp_addr(sd, sd->data_start)) {
+                sd->card_status |= WP_VIOLATION;
+                break;
+            }
+        }
+        sd->data[sd->data_offset++] = value;
+        if (sd->data_offset >= sd->blk_len) {
+            /* TODO: Check CRC before committing */
+            sd->state = sd_programming_state;
+            BLK_WRITE_BLOCK(sd->data_start, sd->data_offset);
+            sd->blk_written++;
+            sd->data_start += sd->blk_len;
+            sd->data_offset = 0;
+            sd->csd[14] |= 0x40;
+
+            /* Bzzzzzzztt .... Operation complete.  */
+            sd->state = sd_receivingdata_state;
+        }
+        break;
+
+    case 26:   /* CMD26:  PROGRAM_CID */
+        sd->data[sd->data_offset ++] = value;
+        if (sd->data_offset >= sizeof(sd->cid)) {
+            /* TODO: Check CRC before committing */
+            sd->state = sd_programming_state;
+            for (i = 0; i < sizeof(sd->cid); i ++)
+                if ((sd->cid[i] | 0x00) != sd->data[i])
+                    sd->card_status |= CID_CSD_OVERWRITE;
+
+            if (!(sd->card_status & CID_CSD_OVERWRITE))
+                for (i = 0; i < sizeof(sd->cid); i ++) {
+                    sd->cid[i] |= 0x00;
+                    sd->cid[i] &= sd->data[i];
+                }
+            /* Bzzzzzzztt .... Operation complete.  */
+            sd->state = sd_transfer_state;
+        }
+        break;
+
+    case 27:   /* CMD27:  PROGRAM_CSD */
+        sd->data[sd->data_offset ++] = value;
+        if (sd->data_offset >= sizeof(sd->csd)) {
+            /* TODO: Check CRC before committing */
+            sd->state = sd_programming_state;
+            for (i = 0; i < sizeof(sd->csd); i ++)
+                if ((sd->csd[i] | sd_csd_rw_mask[i]) !=
+                    (sd->data[i] | sd_csd_rw_mask[i]))
+                    sd->card_status |= CID_CSD_OVERWRITE;
+
+            /* Copy flag (OTP) & Permanent write protect */
+            if (sd->csd[14] & ~sd->data[14] & 0x60)
+                sd->card_status |= CID_CSD_OVERWRITE;
+
+            if (!(sd->card_status & CID_CSD_OVERWRITE))
+                for (i = 0; i < sizeof(sd->csd); i ++) {
+                    sd->csd[i] |= sd_csd_rw_mask[i];
+                    sd->csd[i] &= sd->data[i];
+                }
+            /* Bzzzzzzztt .... Operation complete.  */
+            sd->state = sd_transfer_state;
+        }
+        break;
+
+    case 42:   /* CMD42:  LOCK_UNLOCK */
+        sd->data[sd->data_offset ++] = value;
+        if (sd->data_offset >= sd->blk_len) {
+            /* TODO: Check CRC before committing */
+            sd->state = sd_programming_state;
+            sd_lock_command(sd);
+            /* Bzzzzzzztt .... Operation complete.  */
+            sd->state = sd_transfer_state;
+        }
+        break;
+
+    case 56:   /* CMD56:  GEN_CMD */
+        sd->data[sd->data_offset ++] = value;
+        if (sd->data_offset >= sd->blk_len) {
+            APP_WRITE_BLOCK(sd->data_start, sd->data_offset);
+            sd->state = sd_transfer_state;
+        }
+        break;
+
+    default:
+        fprintf(stderr, "sd_write_data: unknown command\n");
+        break;
+    }
+}
+
+uint8_t sd_read_data(SDState *sd)
+{
+    /* TODO: Append CRCs */
+    uint8_t ret;
+    int io_len;
+
+    if (!sd->bdrv || !bdrv_is_inserted(sd->bdrv) || !sd->enable)
+        return 0x00;
+
+    if (sd->state != sd_sendingdata_state) {
+        fprintf(stderr, "sd_read_data: not in Sending-Data state\n");
+        return 0x00;
+    }
+
+    if (sd->card_status & (ADDRESS_ERROR | WP_VIOLATION))
+        return 0x00;
+
+    io_len = (sd->ocr & (1 << 30)) ? 512 : sd->blk_len;
+
+    switch (sd->current_cmd) {
+    case 6:    /* CMD6:   SWITCH_FUNCTION */
+        ret = sd->data[sd->data_offset ++];
+
+        if (sd->data_offset >= 64)
+            sd->state = sd_transfer_state;
+        break;
+
+    case 9:    /* CMD9:   SEND_CSD */
+    case 10:   /* CMD10:  SEND_CID */
+        ret = sd->data[sd->data_offset ++];
+
+        if (sd->data_offset >= 16)
+            sd->state = sd_transfer_state;
+        break;
+
+    case 11:   /* CMD11:  READ_DAT_UNTIL_STOP */
+        if (sd->data_offset == 0)
+            BLK_READ_BLOCK(sd->data_start, io_len);
+        ret = sd->data[sd->data_offset ++];
+
+        if (sd->data_offset >= io_len) {
+            sd->data_start += io_len;
+            sd->data_offset = 0;
+            if (sd->data_start + io_len > sd->size) {
+                sd->card_status |= ADDRESS_ERROR;
+                break;
+            }
+        }
+        break;
+
+    case 13:   /* ACMD13: SD_STATUS */
+        ret = sd->sd_status[sd->data_offset ++];
+
+        if (sd->data_offset >= sizeof(sd->sd_status))
+            sd->state = sd_transfer_state;
+        break;
+
+    case 17:   /* CMD17:  READ_SINGLE_BLOCK */
+        if (sd->data_offset == 0)
+            BLK_READ_BLOCK(sd->data_start, io_len);
+        ret = sd->data[sd->data_offset ++];
+
+        if (sd->data_offset >= io_len)
+            sd->state = sd_transfer_state;
+        break;
+
+    case 18:   /* CMD18:  READ_MULTIPLE_BLOCK */
+        if (sd->data_offset == 0)
+            BLK_READ_BLOCK(sd->data_start, io_len);
+        ret = sd->data[sd->data_offset ++];
+
+        if (sd->data_offset >= io_len) {
+            sd->data_start += io_len;
+            sd->data_offset = 0;
+            if (sd->data_start + io_len > sd->size) {
+                sd->card_status |= ADDRESS_ERROR;
+                break;
+            }
+        }
+        break;
+
+    case 22:   /* ACMD22: SEND_NUM_WR_BLOCKS */
+        ret = sd->data[sd->data_offset ++];
+
+        if (sd->data_offset >= 4)
+            sd->state = sd_transfer_state;
+        break;
+
+    case 30:   /* CMD30:  SEND_WRITE_PROT */
+        ret = sd->data[sd->data_offset ++];
+
+        if (sd->data_offset >= 4)
+            sd->state = sd_transfer_state;
+        break;
+
+    case 51:   /* ACMD51: SEND_SCR */
+        ret = sd->scr[sd->data_offset ++];
+
+        if (sd->data_offset >= sizeof(sd->scr))
+            sd->state = sd_transfer_state;
+        break;
+
+    case 56:   /* CMD56:  GEN_CMD */
+        if (sd->data_offset == 0)
+            APP_READ_BLOCK(sd->data_start, sd->blk_len);
+        ret = sd->data[sd->data_offset ++];
+
+        if (sd->data_offset >= sd->blk_len)
+            sd->state = sd_transfer_state;
+        break;
+
+    default:
+        fprintf(stderr, "sd_read_data: unknown command\n");
+        return 0x00;
+    }
+
+    return ret;
+}
+
+bool sd_data_ready(SDState *sd)
+{
+    return sd->state == sd_sendingdata_state;
+}
+
+void sd_enable(SDState *sd, bool enable)
+{
+    sd->enable = enable;
+}
diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c
new file mode 100644 (file)
index 0000000..91dc9b0
--- /dev/null
@@ -0,0 +1,1300 @@
+/*
+ * SD Association Host Standard Specification v2.0 controller emulation
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * Mitsyanko Igor <i.mitsyanko@samsung.com>
+ * Peter A.G. Crosthwaite <peter.crosthwaite@petalogix.com>
+ *
+ * Based on MMC controller for Samsung S5PC1xx-based board emulation
+ * by Alexey Merkulov and Vladimir Monakhov.
+ *
+ * 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 "hw/hw.h"
+#include "sysemu/blockdev.h"
+#include "sysemu/dma.h"
+#include "qemu/timer.h"
+#include "block/block_int.h"
+#include "qemu/bitops.h"
+
+#include "sdhci.h"
+
+/* host controller debug messages */
+#ifndef SDHC_DEBUG
+#define SDHC_DEBUG                        0
+#endif
+
+#if SDHC_DEBUG == 0
+    #define DPRINT_L1(fmt, args...)       do { } while (0)
+    #define DPRINT_L2(fmt, args...)       do { } while (0)
+    #define ERRPRINT(fmt, args...)        do { } while (0)
+#elif SDHC_DEBUG == 1
+    #define DPRINT_L1(fmt, args...)       \
+        do {fprintf(stderr, "QEMU SDHC: "fmt, ## args); } while (0)
+    #define DPRINT_L2(fmt, args...)       do { } while (0)
+    #define ERRPRINT(fmt, args...)        \
+        do {fprintf(stderr, "QEMU SDHC ERROR: "fmt, ## args); } while (0)
+#else
+    #define DPRINT_L1(fmt, args...)       \
+        do {fprintf(stderr, "QEMU SDHC: "fmt, ## args); } while (0)
+    #define DPRINT_L2(fmt, args...)       \
+        do {fprintf(stderr, "QEMU SDHC: "fmt, ## args); } while (0)
+    #define ERRPRINT(fmt, args...)        \
+        do {fprintf(stderr, "QEMU SDHC ERROR: "fmt, ## args); } while (0)
+#endif
+
+/* Default SD/MMC host controller features information, which will be
+ * presented in CAPABILITIES register of generic SD host controller at reset.
+ * If not stated otherwise:
+ * 0 - not supported, 1 - supported, other - prohibited.
+ */
+#define SDHC_CAPAB_64BITBUS       0ul        /* 64-bit System Bus Support */
+#define SDHC_CAPAB_18V            1ul        /* Voltage support 1.8v */
+#define SDHC_CAPAB_30V            0ul        /* Voltage support 3.0v */
+#define SDHC_CAPAB_33V            1ul        /* Voltage support 3.3v */
+#define SDHC_CAPAB_SUSPRESUME     0ul        /* Suspend/resume support */
+#define SDHC_CAPAB_SDMA           1ul        /* SDMA support */
+#define SDHC_CAPAB_HIGHSPEED      1ul        /* High speed support */
+#define SDHC_CAPAB_ADMA1          1ul        /* ADMA1 support */
+#define SDHC_CAPAB_ADMA2          1ul        /* ADMA2 support */
+/* Maximum host controller R/W buffers size
+ * Possible values: 512, 1024, 2048 bytes */
+#define SDHC_CAPAB_MAXBLOCKLENGTH 512ul
+/* Maximum clock frequency for SDclock in MHz
+ * value in range 10-63 MHz, 0 - not defined */
+#define SDHC_CAPAB_BASECLKFREQ    0ul
+#define SDHC_CAPAB_TOUNIT         1ul  /* Timeout clock unit 0 - kHz, 1 - MHz */
+/* Timeout clock frequency 1-63, 0 - not defined */
+#define SDHC_CAPAB_TOCLKFREQ      0ul
+
+/* Now check all parameters and calculate CAPABILITIES REGISTER value */
+#if SDHC_CAPAB_64BITBUS > 1 || SDHC_CAPAB_18V > 1 || SDHC_CAPAB_30V > 1 ||     \
+    SDHC_CAPAB_33V > 1 || SDHC_CAPAB_SUSPRESUME > 1 || SDHC_CAPAB_SDMA > 1 ||  \
+    SDHC_CAPAB_HIGHSPEED > 1 || SDHC_CAPAB_ADMA2 > 1 || SDHC_CAPAB_ADMA1 > 1 ||\
+    SDHC_CAPAB_TOUNIT > 1
+#error Capabilities features can have value 0 or 1 only!
+#endif
+
+#if SDHC_CAPAB_MAXBLOCKLENGTH == 512
+#define MAX_BLOCK_LENGTH 0ul
+#elif SDHC_CAPAB_MAXBLOCKLENGTH == 1024
+#define MAX_BLOCK_LENGTH 1ul
+#elif SDHC_CAPAB_MAXBLOCKLENGTH == 2048
+#define MAX_BLOCK_LENGTH 2ul
+#else
+#error Max host controller block size can have value 512, 1024 or 2048 only!
+#endif
+
+#if (SDHC_CAPAB_BASECLKFREQ > 0 && SDHC_CAPAB_BASECLKFREQ < 10) || \
+    SDHC_CAPAB_BASECLKFREQ > 63
+#error SDclock frequency can have value in range 0, 10-63 only!
+#endif
+
+#if SDHC_CAPAB_TOCLKFREQ > 63
+#error Timeout clock frequency can have value in range 0-63 only!
+#endif
+
+#define SDHC_CAPAB_REG_DEFAULT                                 \
+   ((SDHC_CAPAB_64BITBUS << 28) | (SDHC_CAPAB_18V << 26) |     \
+    (SDHC_CAPAB_30V << 25) | (SDHC_CAPAB_33V << 24) |          \
+    (SDHC_CAPAB_SUSPRESUME << 23) | (SDHC_CAPAB_SDMA << 22) |  \
+    (SDHC_CAPAB_HIGHSPEED << 21) | (SDHC_CAPAB_ADMA1 << 20) |  \
+    (SDHC_CAPAB_ADMA2 << 19) | (MAX_BLOCK_LENGTH << 16) |      \
+    (SDHC_CAPAB_BASECLKFREQ << 8) | (SDHC_CAPAB_TOUNIT << 7) | \
+    (SDHC_CAPAB_TOCLKFREQ))
+
+#define MASKED_WRITE(reg, mask, val)  (reg = (reg & (mask)) | (val))
+
+static uint8_t sdhci_slotint(SDHCIState *s)
+{
+    return (s->norintsts & s->norintsigen) || (s->errintsts & s->errintsigen) ||
+         ((s->norintsts & SDHC_NIS_INSERT) && (s->wakcon & SDHC_WKUP_ON_INS)) ||
+         ((s->norintsts & SDHC_NIS_REMOVE) && (s->wakcon & SDHC_WKUP_ON_RMV));
+}
+
+static inline void sdhci_update_irq(SDHCIState *s)
+{
+    qemu_set_irq(s->irq, sdhci_slotint(s));
+}
+
+static void sdhci_raise_insertion_irq(void *opaque)
+{
+    SDHCIState *s = (SDHCIState *)opaque;
+
+    if (s->norintsts & SDHC_NIS_REMOVE) {
+        qemu_mod_timer(s->insert_timer,
+                       qemu_get_clock_ns(vm_clock) + SDHC_INSERTION_DELAY);
+    } else {
+        s->prnsts = 0x1ff0000;
+        if (s->norintstsen & SDHC_NISEN_INSERT) {
+            s->norintsts |= SDHC_NIS_INSERT;
+        }
+        sdhci_update_irq(s);
+    }
+}
+
+static void sdhci_insert_eject_cb(void *opaque, int irq, int level)
+{
+    SDHCIState *s = (SDHCIState *)opaque;
+    DPRINT_L1("Card state changed: %s!\n", level ? "insert" : "eject");
+
+    if ((s->norintsts & SDHC_NIS_REMOVE) && level) {
+        /* Give target some time to notice card ejection */
+        qemu_mod_timer(s->insert_timer,
+                       qemu_get_clock_ns(vm_clock) + SDHC_INSERTION_DELAY);
+    } else {
+        if (level) {
+            s->prnsts = 0x1ff0000;
+            if (s->norintstsen & SDHC_NISEN_INSERT) {
+                s->norintsts |= SDHC_NIS_INSERT;
+            }
+        } else {
+            s->prnsts = 0x1fa0000;
+            s->pwrcon &= ~SDHC_POWER_ON;
+            s->clkcon &= ~SDHC_CLOCK_SDCLK_EN;
+            if (s->norintstsen & SDHC_NISEN_REMOVE) {
+                s->norintsts |= SDHC_NIS_REMOVE;
+            }
+        }
+        sdhci_update_irq(s);
+    }
+}
+
+static void sdhci_card_readonly_cb(void *opaque, int irq, int level)
+{
+    SDHCIState *s = (SDHCIState *)opaque;
+
+    if (level) {
+        s->prnsts &= ~SDHC_WRITE_PROTECT;
+    } else {
+        /* Write enabled */
+        s->prnsts |= SDHC_WRITE_PROTECT;
+    }
+}
+
+static void sdhci_reset(SDHCIState *s)
+{
+    qemu_del_timer(s->insert_timer);
+    qemu_del_timer(s->transfer_timer);
+    /* Set all registers to 0. Capabilities registers are not cleared
+     * and assumed to always preserve their value, given to them during
+     * initialization */
+    memset(&s->sdmasysad, 0, (uintptr_t)&s->capareg - (uintptr_t)&s->sdmasysad);
+
+    sd_set_cb(s->card, s->ro_cb, s->eject_cb);
+    s->data_count = 0;
+    s->stopped_state = sdhc_not_stopped;
+}
+
+static void sdhci_do_data_transfer(void *opaque)
+{
+    SDHCIState *s = (SDHCIState *)opaque;
+
+    SDHCI_GET_CLASS(s)->data_transfer(s);
+}
+
+static void sdhci_send_command(SDHCIState *s)
+{
+    SDRequest request;
+    uint8_t response[16];
+    int rlen;
+
+    s->errintsts = 0;
+    s->acmd12errsts = 0;
+    request.cmd = s->cmdreg >> 8;
+    request.arg = s->argument;
+    DPRINT_L1("sending CMD%u ARG[0x%08x]\n", request.cmd, request.arg);
+    rlen = sd_do_command(s->card, &request, response);
+
+    if (s->cmdreg & SDHC_CMD_RESPONSE) {
+        if (rlen == 4) {
+            s->rspreg[0] = (response[0] << 24) | (response[1] << 16) |
+                           (response[2] << 8)  |  response[3];
+            s->rspreg[1] = s->rspreg[2] = s->rspreg[3] = 0;
+            DPRINT_L1("Response: RSPREG[31..0]=0x%08x\n", s->rspreg[0]);
+        } else if (rlen == 16) {
+            s->rspreg[0] = (response[11] << 24) | (response[12] << 16) |
+                           (response[13] << 8) |  response[14];
+            s->rspreg[1] = (response[7] << 24) | (response[8] << 16) |
+                           (response[9] << 8)  |  response[10];
+            s->rspreg[2] = (response[3] << 24) | (response[4] << 16) |
+                           (response[5] << 8)  |  response[6];
+            s->rspreg[3] = (response[0] << 16) | (response[1] << 8) |
+                            response[2];
+            DPRINT_L1("Response received:\n RSPREG[127..96]=0x%08x, RSPREG[95.."
+                  "64]=0x%08x,\n RSPREG[63..32]=0x%08x, RSPREG[31..0]=0x%08x\n",
+                  s->rspreg[3], s->rspreg[2], s->rspreg[1], s->rspreg[0]);
+        } else {
+            ERRPRINT("Timeout waiting for command response\n");
+            if (s->errintstsen & SDHC_EISEN_CMDTIMEOUT) {
+                s->errintsts |= SDHC_EIS_CMDTIMEOUT;
+                s->norintsts |= SDHC_NIS_ERR;
+            }
+        }
+
+        if ((s->norintstsen & SDHC_NISEN_TRSCMP) &&
+            (s->cmdreg & SDHC_CMD_RESPONSE) == SDHC_CMD_RSP_WITH_BUSY) {
+            s->norintsts |= SDHC_NIS_TRSCMP;
+        }
+    } else if (rlen != 0 && (s->errintstsen & SDHC_EISEN_CMDIDX)) {
+        s->errintsts |= SDHC_EIS_CMDIDX;
+        s->norintsts |= SDHC_NIS_ERR;
+    }
+
+    if (s->norintstsen & SDHC_NISEN_CMDCMP) {
+        s->norintsts |= SDHC_NIS_CMDCMP;
+    }
+
+    sdhci_update_irq(s);
+
+    if (s->blksize && (s->cmdreg & SDHC_CMD_DATA_PRESENT)) {
+        sdhci_do_data_transfer(s);
+    }
+}
+
+static void sdhci_end_transfer(SDHCIState *s)
+{
+    /* Automatically send CMD12 to stop transfer if AutoCMD12 enabled */
+    if ((s->trnmod & SDHC_TRNS_ACMD12) != 0) {
+        SDRequest request;
+        uint8_t response[16];
+
+        request.cmd = 0x0C;
+        request.arg = 0;
+        DPRINT_L1("Automatically issue CMD%d %08x\n", request.cmd, request.arg);
+        sd_do_command(s->card, &request, response);
+        /* Auto CMD12 response goes to the upper Response register */
+        s->rspreg[3] = (response[0] << 24) | (response[1] << 16) |
+                (response[2] << 8) | response[3];
+    }
+
+    s->prnsts &= ~(SDHC_DOING_READ | SDHC_DOING_WRITE |
+            SDHC_DAT_LINE_ACTIVE | SDHC_DATA_INHIBIT |
+            SDHC_SPACE_AVAILABLE | SDHC_DATA_AVAILABLE);
+
+    if (s->norintstsen & SDHC_NISEN_TRSCMP) {
+        s->norintsts |= SDHC_NIS_TRSCMP;
+    }
+
+    sdhci_update_irq(s);
+}
+
+/*
+ * Programmed i/o data transfer
+ */
+
+/* Fill host controller's read buffer with BLKSIZE bytes of data from card */
+static void sdhci_read_block_from_card(SDHCIState *s)
+{
+    int index = 0;
+
+    if ((s->trnmod & SDHC_TRNS_MULTI) &&
+            (s->trnmod & SDHC_TRNS_BLK_CNT_EN) && (s->blkcnt == 0)) {
+        return;
+    }
+
+    for (index = 0; index < (s->blksize & 0x0fff); index++) {
+        s->fifo_buffer[index] = sd_read_data(s->card);
+    }
+
+    /* New data now available for READ through Buffer Port Register */
+    s->prnsts |= SDHC_DATA_AVAILABLE;
+    if (s->norintstsen & SDHC_NISEN_RBUFRDY) {
+        s->norintsts |= SDHC_NIS_RBUFRDY;
+    }
+
+    /* Clear DAT line active status if that was the last block */
+    if ((s->trnmod & SDHC_TRNS_MULTI) == 0 ||
+            ((s->trnmod & SDHC_TRNS_MULTI) && s->blkcnt == 1)) {
+        s->prnsts &= ~SDHC_DAT_LINE_ACTIVE;
+    }
+
+    /* If stop at block gap request was set and it's not the last block of
+     * data - generate Block Event interrupt */
+    if (s->stopped_state == sdhc_gap_read && (s->trnmod & SDHC_TRNS_MULTI) &&
+            s->blkcnt != 1)    {
+        s->prnsts &= ~SDHC_DAT_LINE_ACTIVE;
+        if (s->norintstsen & SDHC_EISEN_BLKGAP) {
+            s->norintsts |= SDHC_EIS_BLKGAP;
+        }
+    }
+
+    sdhci_update_irq(s);
+}
+
+/* Read @size byte of data from host controller @s BUFFER DATA PORT register */
+static uint32_t sdhci_read_dataport(SDHCIState *s, unsigned size)
+{
+    uint32_t value = 0;
+    int i;
+
+    /* first check that a valid data exists in host controller input buffer */
+    if ((s->prnsts & SDHC_DATA_AVAILABLE) == 0) {
+        ERRPRINT("Trying to read from empty buffer\n");
+        return 0;
+    }
+
+    for (i = 0; i < size; i++) {
+        value |= s->fifo_buffer[s->data_count] << i * 8;
+        s->data_count++;
+        /* check if we've read all valid data (blksize bytes) from buffer */
+        if ((s->data_count) >= (s->blksize & 0x0fff)) {
+            DPRINT_L2("All %u bytes of data have been read from input buffer\n",
+                    s->data_count);
+            s->prnsts &= ~SDHC_DATA_AVAILABLE; /* no more data in a buffer */
+            s->data_count = 0;  /* next buff read must start at position [0] */
+
+            if (s->trnmod & SDHC_TRNS_BLK_CNT_EN) {
+                s->blkcnt--;
+            }
+
+            /* if that was the last block of data */
+            if ((s->trnmod & SDHC_TRNS_MULTI) == 0 ||
+                ((s->trnmod & SDHC_TRNS_BLK_CNT_EN) && (s->blkcnt == 0)) ||
+                 /* stop at gap request */
+                (s->stopped_state == sdhc_gap_read &&
+                 !(s->prnsts & SDHC_DAT_LINE_ACTIVE))) {
+                SDHCI_GET_CLASS(s)->end_data_transfer(s);
+            } else { /* if there are more data, read next block from card */
+                SDHCI_GET_CLASS(s)->read_block_from_card(s);
+            }
+            break;
+        }
+    }
+
+    return value;
+}
+
+/* Write data from host controller FIFO to card */
+static void sdhci_write_block_to_card(SDHCIState *s)
+{
+    int index = 0;
+
+    if (s->prnsts & SDHC_SPACE_AVAILABLE) {
+        if (s->norintstsen & SDHC_NISEN_WBUFRDY) {
+            s->norintsts |= SDHC_NIS_WBUFRDY;
+        }
+        sdhci_update_irq(s);
+        return;
+    }
+
+    if (s->trnmod & SDHC_TRNS_BLK_CNT_EN) {
+        if (s->blkcnt == 0) {
+            return;
+        } else {
+            s->blkcnt--;
+        }
+    }
+
+    for (index = 0; index < (s->blksize & 0x0fff); index++) {
+        sd_write_data(s->card, s->fifo_buffer[index]);
+    }
+
+    /* Next data can be written through BUFFER DATORT register */
+    s->prnsts |= SDHC_SPACE_AVAILABLE;
+    if (s->norintstsen & SDHC_NISEN_WBUFRDY) {
+        s->norintsts |= SDHC_NIS_WBUFRDY;
+    }
+
+    /* Finish transfer if that was the last block of data */
+    if ((s->trnmod & SDHC_TRNS_MULTI) == 0 ||
+            ((s->trnmod & SDHC_TRNS_MULTI) &&
+            (s->trnmod & SDHC_TRNS_BLK_CNT_EN) && (s->blkcnt == 0))) {
+        SDHCI_GET_CLASS(s)->end_data_transfer(s);
+    }
+
+    /* Generate Block Gap Event if requested and if not the last block */
+    if (s->stopped_state == sdhc_gap_write && (s->trnmod & SDHC_TRNS_MULTI) &&
+            s->blkcnt > 0) {
+        s->prnsts &= ~SDHC_DOING_WRITE;
+        if (s->norintstsen & SDHC_EISEN_BLKGAP) {
+            s->norintsts |= SDHC_EIS_BLKGAP;
+        }
+        SDHCI_GET_CLASS(s)->end_data_transfer(s);
+    }
+
+    sdhci_update_irq(s);
+}
+
+/* Write @size bytes of @value data to host controller @s Buffer Data Port
+ * register */
+static void sdhci_write_dataport(SDHCIState *s, uint32_t value, unsigned size)
+{
+    unsigned i;
+
+    /* Check that there is free space left in a buffer */
+    if (!(s->prnsts & SDHC_SPACE_AVAILABLE)) {
+        ERRPRINT("Can't write to data buffer: buffer full\n");
+        return;
+    }
+
+    for (i = 0; i < size; i++) {
+        s->fifo_buffer[s->data_count] = value & 0xFF;
+        s->data_count++;
+        value >>= 8;
+        if (s->data_count >= (s->blksize & 0x0fff)) {
+            DPRINT_L2("write buffer filled with %u bytes of data\n",
+                    s->data_count);
+            s->data_count = 0;
+            s->prnsts &= ~SDHC_SPACE_AVAILABLE;
+            if (s->prnsts & SDHC_DOING_WRITE) {
+                SDHCI_GET_CLASS(s)->write_block_to_card(s);
+            }
+        }
+    }
+}
+
+/*
+ * Single DMA data transfer
+ */
+
+/* Multi block SDMA transfer */
+static void sdhci_sdma_transfer_multi_blocks(SDHCIState *s)
+{
+    bool page_aligned = false;
+    unsigned int n, begin;
+    const uint16_t block_size = s->blksize & 0x0fff;
+    uint32_t boundary_chk = 1 << (((s->blksize & 0xf000) >> 12) + 12);
+    uint32_t boundary_count = boundary_chk - (s->sdmasysad % boundary_chk);
+
+    /* XXX: Some sd/mmc drivers (for example, u-boot-slp) do not account for
+     * possible stop at page boundary if initial address is not page aligned,
+     * allow them to work properly */
+    if ((s->sdmasysad % boundary_chk) == 0) {
+        page_aligned = true;
+    }
+
+    if (s->trnmod & SDHC_TRNS_READ) {
+        s->prnsts |= SDHC_DOING_READ | SDHC_DATA_INHIBIT |
+                SDHC_DAT_LINE_ACTIVE;
+        while (s->blkcnt) {
+            if (s->data_count == 0) {
+                for (n = 0; n < block_size; n++) {
+                    s->fifo_buffer[n] = sd_read_data(s->card);
+                }
+            }
+            begin = s->data_count;
+            if (((boundary_count + begin) < block_size) && page_aligned) {
+                s->data_count = boundary_count + begin;
+                boundary_count = 0;
+             } else {
+                s->data_count = block_size;
+                boundary_count -= block_size - begin;
+                if (s->trnmod & SDHC_TRNS_BLK_CNT_EN) {
+                    s->blkcnt--;
+                }
+            }
+            dma_memory_write(&dma_context_memory, s->sdmasysad,
+                             &s->fifo_buffer[begin], s->data_count - begin);
+            s->sdmasysad += s->data_count - begin;
+            if (s->data_count == block_size) {
+                s->data_count = 0;
+            }
+            if (page_aligned && boundary_count == 0) {
+                break;
+            }
+        }
+    } else {
+        s->prnsts |= SDHC_DOING_WRITE | SDHC_DATA_INHIBIT |
+                SDHC_DAT_LINE_ACTIVE;
+        while (s->blkcnt) {
+            begin = s->data_count;
+            if (((boundary_count + begin) < block_size) && page_aligned) {
+                s->data_count = boundary_count + begin;
+                boundary_count = 0;
+             } else {
+                s->data_count = block_size;
+                boundary_count -= block_size - begin;
+            }
+            dma_memory_read(&dma_context_memory, s->sdmasysad,
+                            &s->fifo_buffer[begin], s->data_count);
+            s->sdmasysad += s->data_count - begin;
+            if (s->data_count == block_size) {
+                for (n = 0; n < block_size; n++) {
+                    sd_write_data(s->card, s->fifo_buffer[n]);
+                }
+                s->data_count = 0;
+                if (s->trnmod & SDHC_TRNS_BLK_CNT_EN) {
+                    s->blkcnt--;
+                }
+            }
+            if (page_aligned && boundary_count == 0) {
+                break;
+            }
+        }
+    }
+
+    if (s->blkcnt == 0) {
+        SDHCI_GET_CLASS(s)->end_data_transfer(s);
+    } else {
+        if (s->norintstsen & SDHC_NISEN_DMA) {
+            s->norintsts |= SDHC_NIS_DMA;
+        }
+        sdhci_update_irq(s);
+    }
+}
+
+/* single block SDMA transfer */
+
+static void sdhci_sdma_transfer_single_block(SDHCIState *s)
+{
+    int n;
+    uint32_t datacnt = s->blksize & 0x0fff;
+
+    if (s->trnmod & SDHC_TRNS_READ) {
+        for (n = 0; n < datacnt; n++) {
+            s->fifo_buffer[n] = sd_read_data(s->card);
+        }
+        dma_memory_write(&dma_context_memory, s->sdmasysad, s->fifo_buffer,
+                         datacnt);
+    } else {
+        dma_memory_read(&dma_context_memory, s->sdmasysad, s->fifo_buffer,
+                        datacnt);
+        for (n = 0; n < datacnt; n++) {
+            sd_write_data(s->card, s->fifo_buffer[n]);
+        }
+    }
+
+    if (s->trnmod & SDHC_TRNS_BLK_CNT_EN) {
+        s->blkcnt--;
+    }
+
+    SDHCI_GET_CLASS(s)->end_data_transfer(s);
+}
+
+typedef struct ADMADescr {
+    hwaddr addr;
+    uint16_t length;
+    uint8_t attr;
+    uint8_t incr;
+} ADMADescr;
+
+static void get_adma_description(SDHCIState *s, ADMADescr *dscr)
+{
+    uint32_t adma1 = 0;
+    uint64_t adma2 = 0;
+    hwaddr entry_addr = (hwaddr)s->admasysaddr;
+    switch (SDHC_DMA_TYPE(s->hostctl)) {
+    case SDHC_CTRL_ADMA2_32:
+        dma_memory_read(&dma_context_memory, entry_addr, (uint8_t *)&adma2,
+                        sizeof(adma2));
+        adma2 = le64_to_cpu(adma2);
+        /* The spec does not specify endianness of descriptor table.
+         * We currently assume that it is LE.
+         */
+        dscr->addr = (hwaddr)extract64(adma2, 32, 32) & ~0x3ull;
+        dscr->length = (uint16_t)extract64(adma2, 16, 16);
+        dscr->attr = (uint8_t)extract64(adma2, 0, 7);
+        dscr->incr = 8;
+        break;
+    case SDHC_CTRL_ADMA1_32:
+        dma_memory_read(&dma_context_memory, entry_addr, (uint8_t *)&adma1,
+                        sizeof(adma1));
+        adma1 = le32_to_cpu(adma1);
+        dscr->addr = (hwaddr)(adma1 & 0xFFFFF000);
+        dscr->attr = (uint8_t)extract32(adma1, 0, 7);
+        dscr->incr = 4;
+        if ((dscr->attr & SDHC_ADMA_ATTR_ACT_MASK) == SDHC_ADMA_ATTR_SET_LEN) {
+            dscr->length = (uint16_t)extract32(adma1, 12, 16);
+        } else {
+            dscr->length = 4096;
+        }
+        break;
+    case SDHC_CTRL_ADMA2_64:
+        dma_memory_read(&dma_context_memory, entry_addr,
+                        (uint8_t *)(&dscr->attr), 1);
+        dma_memory_read(&dma_context_memory, entry_addr + 2,
+                        (uint8_t *)(&dscr->length), 2);
+        dscr->length = le16_to_cpu(dscr->length);
+        dma_memory_read(&dma_context_memory, entry_addr + 4,
+                        (uint8_t *)(&dscr->addr), 8);
+        dscr->attr = le64_to_cpu(dscr->attr);
+        dscr->attr &= 0xfffffff8;
+        dscr->incr = 12;
+        break;
+    }
+}
+
+/* Advanced DMA data transfer */
+
+static void sdhci_do_adma(SDHCIState *s)
+{
+    unsigned int n, begin, length;
+    const uint16_t block_size = s->blksize & 0x0fff;
+    ADMADescr dscr;
+    int i;
+
+    for (i = 0; i < SDHC_ADMA_DESCS_PER_DELAY; ++i) {
+        s->admaerr &= ~SDHC_ADMAERR_LENGTH_MISMATCH;
+
+        get_adma_description(s, &dscr);
+        DPRINT_L2("ADMA loop: addr=" TARGET_FMT_plx ", len=%d, attr=%x\n",
+                dscr.addr, dscr.length, dscr.attr);
+
+        if ((dscr.attr & SDHC_ADMA_ATTR_VALID) == 0) {
+            /* Indicate that error occurred in ST_FDS state */
+            s->admaerr &= ~SDHC_ADMAERR_STATE_MASK;
+            s->admaerr |= SDHC_ADMAERR_STATE_ST_FDS;
+
+            /* Generate ADMA error interrupt */
+            if (s->errintstsen & SDHC_EISEN_ADMAERR) {
+                s->errintsts |= SDHC_EIS_ADMAERR;
+                s->norintsts |= SDHC_NIS_ERR;
+            }
+
+            sdhci_update_irq(s);
+            return;
+        }
+
+        length = dscr.length ? dscr.length : 65536;
+
+        switch (dscr.attr & SDHC_ADMA_ATTR_ACT_MASK) {
+        case SDHC_ADMA_ATTR_ACT_TRAN:  /* data transfer */
+
+            if (s->trnmod & SDHC_TRNS_READ) {
+                while (length) {
+                    if (s->data_count == 0) {
+                        for (n = 0; n < block_size; n++) {
+                            s->fifo_buffer[n] = sd_read_data(s->card);
+                        }
+                    }
+                    begin = s->data_count;
+                    if ((length + begin) < block_size) {
+                        s->data_count = length + begin;
+                        length = 0;
+                     } else {
+                        s->data_count = block_size;
+                        length -= block_size - begin;
+                    }
+                    dma_memory_write(&dma_context_memory, dscr.addr,
+                                     &s->fifo_buffer[begin],
+                                     s->data_count - begin);
+                    dscr.addr += s->data_count - begin;
+                    if (s->data_count == block_size) {
+                        s->data_count = 0;
+                        if (s->trnmod & SDHC_TRNS_BLK_CNT_EN) {
+                            s->blkcnt--;
+                            if (s->blkcnt == 0) {
+                                break;
+                            }
+                        }
+                    }
+                }
+            } else {
+                while (length) {
+                    begin = s->data_count;
+                    if ((length + begin) < block_size) {
+                        s->data_count = length + begin;
+                        length = 0;
+                     } else {
+                        s->data_count = block_size;
+                        length -= block_size - begin;
+                    }
+                    dma_memory_read(&dma_context_memory, dscr.addr,
+                                    &s->fifo_buffer[begin], s->data_count);
+                    dscr.addr += s->data_count - begin;
+                    if (s->data_count == block_size) {
+                        for (n = 0; n < block_size; n++) {
+                            sd_write_data(s->card, s->fifo_buffer[n]);
+                        }
+                        s->data_count = 0;
+                        if (s->trnmod & SDHC_TRNS_BLK_CNT_EN) {
+                            s->blkcnt--;
+                            if (s->blkcnt == 0) {
+                                break;
+                            }
+                        }
+                    }
+                }
+            }
+            s->admasysaddr += dscr.incr;
+            break;
+        case SDHC_ADMA_ATTR_ACT_LINK:   /* link to next descriptor table */
+            s->admasysaddr = dscr.addr;
+            DPRINT_L1("ADMA link: admasysaddr=0x%lx\n", s->admasysaddr);
+            break;
+        default:
+            s->admasysaddr += dscr.incr;
+            break;
+        }
+
+        /* ADMA transfer terminates if blkcnt == 0 or by END attribute */
+        if (((s->trnmod & SDHC_TRNS_BLK_CNT_EN) &&
+                    (s->blkcnt == 0)) || (dscr.attr & SDHC_ADMA_ATTR_END)) {
+            DPRINT_L2("ADMA transfer completed\n");
+            if (length || ((dscr.attr & SDHC_ADMA_ATTR_END) &&
+                (s->trnmod & SDHC_TRNS_BLK_CNT_EN) &&
+                s->blkcnt != 0)) {
+                ERRPRINT("SD/MMC host ADMA length mismatch\n");
+                s->admaerr |= SDHC_ADMAERR_LENGTH_MISMATCH |
+                        SDHC_ADMAERR_STATE_ST_TFR;
+                if (s->errintstsen & SDHC_EISEN_ADMAERR) {
+                    ERRPRINT("Set ADMA error flag\n");
+                    s->errintsts |= SDHC_EIS_ADMAERR;
+                    s->norintsts |= SDHC_NIS_ERR;
+                }
+
+                sdhci_update_irq(s);
+            }
+            SDHCI_GET_CLASS(s)->end_data_transfer(s);
+            return;
+        }
+
+        if (dscr.attr & SDHC_ADMA_ATTR_INT) {
+            DPRINT_L1("ADMA interrupt: admasysaddr=0x%lx\n", s->admasysaddr);
+            if (s->norintstsen & SDHC_NISEN_DMA) {
+                s->norintsts |= SDHC_NIS_DMA;
+            }
+
+            sdhci_update_irq(s);
+            return;
+        }
+    }
+
+    /* we have unfinished business - reschedule to continue ADMA */
+    qemu_mod_timer(s->transfer_timer,
+                   qemu_get_clock_ns(vm_clock) + SDHC_TRANSFER_DELAY);
+}
+
+/* Perform data transfer according to controller configuration */
+
+static void sdhci_data_transfer(SDHCIState *s)
+{
+    SDHCIClass *k = SDHCI_GET_CLASS(s);
+    s->data_count = 0;
+
+    if (s->trnmod & SDHC_TRNS_DMA) {
+        switch (SDHC_DMA_TYPE(s->hostctl)) {
+        case SDHC_CTRL_SDMA:
+            if ((s->trnmod & SDHC_TRNS_MULTI) &&
+                    (!(s->trnmod & SDHC_TRNS_BLK_CNT_EN) || s->blkcnt == 0)) {
+                break;
+            }
+
+            if ((s->blkcnt == 1) || !(s->trnmod & SDHC_TRNS_MULTI)) {
+                k->do_sdma_single(s);
+            } else {
+                k->do_sdma_multi(s);
+            }
+
+            break;
+        case SDHC_CTRL_ADMA1_32:
+            if (!(s->capareg & SDHC_CAN_DO_ADMA1)) {
+                ERRPRINT("ADMA1 not supported\n");
+                break;
+            }
+
+            k->do_adma(s);
+            break;
+        case SDHC_CTRL_ADMA2_32:
+            if (!(s->capareg & SDHC_CAN_DO_ADMA2)) {
+                ERRPRINT("ADMA2 not supported\n");
+                break;
+            }
+
+            k->do_adma(s);
+            break;
+        case SDHC_CTRL_ADMA2_64:
+            if (!(s->capareg & SDHC_CAN_DO_ADMA2) ||
+                    !(s->capareg & SDHC_64_BIT_BUS_SUPPORT)) {
+                ERRPRINT("64 bit ADMA not supported\n");
+                break;
+            }
+
+            k->do_adma(s);
+            break;
+        default:
+            ERRPRINT("Unsupported DMA type\n");
+            break;
+        }
+    } else {
+        if ((s->trnmod & SDHC_TRNS_READ) && sd_data_ready(s->card)) {
+            s->prnsts |= SDHC_DOING_READ | SDHC_DATA_INHIBIT |
+                    SDHC_DAT_LINE_ACTIVE;
+            SDHCI_GET_CLASS(s)->read_block_from_card(s);
+        } else {
+            s->prnsts |= SDHC_DOING_WRITE | SDHC_DAT_LINE_ACTIVE |
+                    SDHC_SPACE_AVAILABLE | SDHC_DATA_INHIBIT;
+            SDHCI_GET_CLASS(s)->write_block_to_card(s);
+        }
+    }
+}
+
+static bool sdhci_can_issue_command(SDHCIState *s)
+{
+    if (!SDHC_CLOCK_IS_ON(s->clkcon) || !(s->pwrcon & SDHC_POWER_ON) ||
+        (((s->prnsts & SDHC_DATA_INHIBIT) || s->stopped_state) &&
+        ((s->cmdreg & SDHC_CMD_DATA_PRESENT) ||
+        ((s->cmdreg & SDHC_CMD_RESPONSE) == SDHC_CMD_RSP_WITH_BUSY &&
+        !(SDHC_COMMAND_TYPE(s->cmdreg) == SDHC_CMD_ABORT))))) {
+        return false;
+    }
+
+    return true;
+}
+
+/* The Buffer Data Port register must be accessed in sequential and
+ * continuous manner */
+static inline bool
+sdhci_buff_access_is_sequential(SDHCIState *s, unsigned byte_num)
+{
+    if ((s->data_count & 0x3) != byte_num) {
+        ERRPRINT("Non-sequential access to Buffer Data Port register"
+                "is prohibited\n");
+        return false;
+    }
+    return true;
+}
+
+static uint32_t sdhci_read(SDHCIState *s, unsigned int offset, unsigned size)
+{
+    uint32_t ret = 0;
+
+    switch (offset & ~0x3) {
+    case SDHC_SYSAD:
+        ret = s->sdmasysad;
+        break;
+    case SDHC_BLKSIZE:
+        ret = s->blksize | (s->blkcnt << 16);
+        break;
+    case SDHC_ARGUMENT:
+        ret = s->argument;
+        break;
+    case SDHC_TRNMOD:
+        ret = s->trnmod | (s->cmdreg << 16);
+        break;
+    case SDHC_RSPREG0 ... SDHC_RSPREG3:
+        ret = s->rspreg[((offset & ~0x3) - SDHC_RSPREG0) >> 2];
+        break;
+    case  SDHC_BDATA:
+        if (sdhci_buff_access_is_sequential(s, offset - SDHC_BDATA)) {
+            ret = SDHCI_GET_CLASS(s)->bdata_read(s, size);
+            DPRINT_L2("read %ub: addr[0x%04x] -> %u\n", size, offset, ret);
+            return ret;
+        }
+        break;
+    case SDHC_PRNSTS:
+        ret = s->prnsts;
+        break;
+    case SDHC_HOSTCTL:
+        ret = s->hostctl | (s->pwrcon << 8) | (s->blkgap << 16) |
+              (s->wakcon << 24);
+        break;
+    case SDHC_CLKCON:
+        ret = s->clkcon | (s->timeoutcon << 16);
+        break;
+    case SDHC_NORINTSTS:
+        ret = s->norintsts | (s->errintsts << 16);
+        break;
+    case SDHC_NORINTSTSEN:
+        ret = s->norintstsen | (s->errintstsen << 16);
+        break;
+    case SDHC_NORINTSIGEN:
+        ret = s->norintsigen | (s->errintsigen << 16);
+        break;
+    case SDHC_ACMD12ERRSTS:
+        ret = s->acmd12errsts;
+        break;
+    case SDHC_CAPAREG:
+        ret = s->capareg;
+        break;
+    case SDHC_MAXCURR:
+        ret = s->maxcurr;
+        break;
+    case SDHC_ADMAERR:
+        ret =  s->admaerr;
+        break;
+    case SDHC_ADMASYSADDR:
+        ret = (uint32_t)s->admasysaddr;
+        break;
+    case SDHC_ADMASYSADDR + 4:
+        ret = (uint32_t)(s->admasysaddr >> 32);
+        break;
+    case SDHC_SLOT_INT_STATUS:
+        ret = (SD_HOST_SPECv2_VERS << 16) | sdhci_slotint(s);
+        break;
+    default:
+        ERRPRINT("bad %ub read: addr[0x%04x]\n", size, offset);
+        break;
+    }
+
+    ret >>= (offset & 0x3) * 8;
+    ret &= (1ULL << (size * 8)) - 1;
+    DPRINT_L2("read %ub: addr[0x%04x] -> %u(0x%x)\n", size, offset, ret, ret);
+    return ret;
+}
+
+static inline void sdhci_blkgap_write(SDHCIState *s, uint8_t value)
+{
+    if ((value & SDHC_STOP_AT_GAP_REQ) && (s->blkgap & SDHC_STOP_AT_GAP_REQ)) {
+        return;
+    }
+    s->blkgap = value & SDHC_STOP_AT_GAP_REQ;
+
+    if ((value & SDHC_CONTINUE_REQ) && s->stopped_state &&
+            (s->blkgap & SDHC_STOP_AT_GAP_REQ) == 0) {
+        if (s->stopped_state == sdhc_gap_read) {
+            s->prnsts |= SDHC_DAT_LINE_ACTIVE | SDHC_DOING_READ;
+            SDHCI_GET_CLASS(s)->read_block_from_card(s);
+        } else {
+            s->prnsts |= SDHC_DAT_LINE_ACTIVE | SDHC_DOING_WRITE;
+            SDHCI_GET_CLASS(s)->write_block_to_card(s);
+        }
+        s->stopped_state = sdhc_not_stopped;
+    } else if (!s->stopped_state && (value & SDHC_STOP_AT_GAP_REQ)) {
+        if (s->prnsts & SDHC_DOING_READ) {
+            s->stopped_state = sdhc_gap_read;
+        } else if (s->prnsts & SDHC_DOING_WRITE) {
+            s->stopped_state = sdhc_gap_write;
+        }
+    }
+}
+
+static inline void sdhci_reset_write(SDHCIState *s, uint8_t value)
+{
+    switch (value) {
+    case SDHC_RESET_ALL:
+        DEVICE_GET_CLASS(s)->reset(DEVICE(s));
+        break;
+    case SDHC_RESET_CMD:
+        s->prnsts &= ~SDHC_CMD_INHIBIT;
+        s->norintsts &= ~SDHC_NIS_CMDCMP;
+        break;
+    case SDHC_RESET_DATA:
+        s->data_count = 0;
+        s->prnsts &= ~(SDHC_SPACE_AVAILABLE | SDHC_DATA_AVAILABLE |
+                SDHC_DOING_READ | SDHC_DOING_WRITE |
+                SDHC_DATA_INHIBIT | SDHC_DAT_LINE_ACTIVE);
+        s->blkgap &= ~(SDHC_STOP_AT_GAP_REQ | SDHC_CONTINUE_REQ);
+        s->stopped_state = sdhc_not_stopped;
+        s->norintsts &= ~(SDHC_NIS_WBUFRDY | SDHC_NIS_RBUFRDY |
+                SDHC_NIS_DMA | SDHC_NIS_TRSCMP | SDHC_NIS_BLKGAP);
+        break;
+    }
+}
+
+static void
+sdhci_write(SDHCIState *s, unsigned int offset, uint32_t value, unsigned size)
+{
+    unsigned shift =  8 * (offset & 0x3);
+    uint32_t mask = ~(((1ULL << (size * 8)) - 1) << shift);
+    value <<= shift;
+
+    switch (offset & ~0x3) {
+    case SDHC_SYSAD:
+        s->sdmasysad = (s->sdmasysad & mask) | value;
+        MASKED_WRITE(s->sdmasysad, mask, value);
+        /* Writing to last byte of sdmasysad might trigger transfer */
+        if (!(mask & 0xFF000000) && TRANSFERRING_DATA(s->prnsts) && s->blkcnt &&
+                s->blksize && SDHC_DMA_TYPE(s->hostctl) == SDHC_CTRL_SDMA) {
+            SDHCI_GET_CLASS(s)->do_sdma_multi(s);
+        }
+        break;
+    case SDHC_BLKSIZE:
+        if (!TRANSFERRING_DATA(s->prnsts)) {
+            MASKED_WRITE(s->blksize, mask, value);
+            MASKED_WRITE(s->blkcnt, mask >> 16, value >> 16);
+        }
+        break;
+    case SDHC_ARGUMENT:
+        MASKED_WRITE(s->argument, mask, value);
+        break;
+    case SDHC_TRNMOD:
+        /* DMA can be enabled only if it is supported as indicated by
+         * capabilities register */
+        if (!(s->capareg & SDHC_CAN_DO_DMA)) {
+            value &= ~SDHC_TRNS_DMA;
+        }
+        MASKED_WRITE(s->trnmod, mask, value);
+        MASKED_WRITE(s->cmdreg, mask >> 16, value >> 16);
+
+        /* Writing to the upper byte of CMDREG triggers SD command generation */
+        if ((mask & 0xFF000000) || !SDHCI_GET_CLASS(s)->can_issue_command(s)) {
+            break;
+        }
+
+        SDHCI_GET_CLASS(s)->send_command(s);
+        break;
+    case  SDHC_BDATA:
+        if (sdhci_buff_access_is_sequential(s, offset - SDHC_BDATA)) {
+            SDHCI_GET_CLASS(s)->bdata_write(s, value >> shift, size);
+        }
+        break;
+    case SDHC_HOSTCTL:
+        if (!(mask & 0xFF0000)) {
+            sdhci_blkgap_write(s, value >> 16);
+        }
+        MASKED_WRITE(s->hostctl, mask, value);
+        MASKED_WRITE(s->pwrcon, mask >> 8, value >> 8);
+        MASKED_WRITE(s->wakcon, mask >> 24, value >> 24);
+        if (!(s->prnsts & SDHC_CARD_PRESENT) || ((s->pwrcon >> 1) & 0x7) < 5 ||
+                !(s->capareg & (1 << (31 - ((s->pwrcon >> 1) & 0x7))))) {
+            s->pwrcon &= ~SDHC_POWER_ON;
+        }
+        break;
+    case SDHC_CLKCON:
+        if (!(mask & 0xFF000000)) {
+            sdhci_reset_write(s, value >> 24);
+        }
+        MASKED_WRITE(s->clkcon, mask, value);
+        MASKED_WRITE(s->timeoutcon, mask >> 16, value >> 16);
+        if (s->clkcon & SDHC_CLOCK_INT_EN) {
+            s->clkcon |= SDHC_CLOCK_INT_STABLE;
+        } else {
+            s->clkcon &= ~SDHC_CLOCK_INT_STABLE;
+        }
+        break;
+    case SDHC_NORINTSTS:
+        if (s->norintstsen & SDHC_NISEN_CARDINT) {
+            value &= ~SDHC_NIS_CARDINT;
+        }
+        s->norintsts &= mask | ~value;
+        s->errintsts &= (mask >> 16) | ~(value >> 16);
+        if (s->errintsts) {
+            s->norintsts |= SDHC_NIS_ERR;
+        } else {
+            s->norintsts &= ~SDHC_NIS_ERR;
+        }
+        sdhci_update_irq(s);
+        break;
+    case SDHC_NORINTSTSEN:
+        MASKED_WRITE(s->norintstsen, mask, value);
+        MASKED_WRITE(s->errintstsen, mask >> 16, value >> 16);
+        s->norintsts &= s->norintstsen;
+        s->errintsts &= s->errintstsen;
+        if (s->errintsts) {
+            s->norintsts |= SDHC_NIS_ERR;
+        } else {
+            s->norintsts &= ~SDHC_NIS_ERR;
+        }
+        sdhci_update_irq(s);
+        break;
+    case SDHC_NORINTSIGEN:
+        MASKED_WRITE(s->norintsigen, mask, value);
+        MASKED_WRITE(s->errintsigen, mask >> 16, value >> 16);
+        sdhci_update_irq(s);
+        break;
+    case SDHC_ADMAERR:
+        MASKED_WRITE(s->admaerr, mask, value);
+        break;
+    case SDHC_ADMASYSADDR:
+        s->admasysaddr = (s->admasysaddr & (0xFFFFFFFF00000000ULL |
+                (uint64_t)mask)) | (uint64_t)value;
+        break;
+    case SDHC_ADMASYSADDR + 4:
+        s->admasysaddr = (s->admasysaddr & (0x00000000FFFFFFFFULL |
+                ((uint64_t)mask << 32))) | ((uint64_t)value << 32);
+        break;
+    case SDHC_FEAER:
+        s->acmd12errsts |= value;
+        s->errintsts |= (value >> 16) & s->errintstsen;
+        if (s->acmd12errsts) {
+            s->errintsts |= SDHC_EIS_CMD12ERR;
+        }
+        if (s->errintsts) {
+            s->norintsts |= SDHC_NIS_ERR;
+        }
+        sdhci_update_irq(s);
+        break;
+    default:
+        ERRPRINT("bad %ub write offset: addr[0x%04x] <- %u(0x%x)\n",
+                size, offset, value >> shift, value >> shift);
+        break;
+    }
+    DPRINT_L2("write %ub: addr[0x%04x] <- %u(0x%x)\n",
+            size, offset, value >> shift, value >> shift);
+}
+
+static uint64_t
+sdhci_readfn(void *opaque, hwaddr offset, unsigned size)
+{
+    SDHCIState *s = (SDHCIState *)opaque;
+
+    return SDHCI_GET_CLASS(s)->mem_read(s, offset, size);
+}
+
+static void
+sdhci_writefn(void *opaque, hwaddr off, uint64_t val, unsigned sz)
+{
+    SDHCIState *s = (SDHCIState *)opaque;
+
+    SDHCI_GET_CLASS(s)->mem_write(s, off, val, sz);
+}
+
+static const MemoryRegionOps sdhci_mmio_ops = {
+    .read = sdhci_readfn,
+    .write = sdhci_writefn,
+    .valid = {
+        .min_access_size = 1,
+        .max_access_size = 4,
+        .unaligned = false
+    },
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static inline unsigned int sdhci_get_fifolen(SDHCIState *s)
+{
+    switch (SDHC_CAPAB_BLOCKSIZE(s->capareg)) {
+    case 0:
+        return 512;
+    case 1:
+        return 1024;
+    case 2:
+        return 2048;
+    default:
+        hw_error("SDHC: unsupported value for maximum block size\n");
+        return 0;
+    }
+}
+
+static void sdhci_initfn(Object *obj)
+{
+    SDHCIState *s = SDHCI(obj);
+    DriveInfo *di;
+
+    di = drive_get_next(IF_SD);
+    s->card = sd_init(di ? di->bdrv : NULL, 0);
+    s->eject_cb = qemu_allocate_irqs(sdhci_insert_eject_cb, s, 1)[0];
+    s->ro_cb = qemu_allocate_irqs(sdhci_card_readonly_cb, s, 1)[0];
+    sd_set_cb(s->card, s->ro_cb, s->eject_cb);
+
+    s->insert_timer = qemu_new_timer_ns(vm_clock, sdhci_raise_insertion_irq, s);
+    s->transfer_timer = qemu_new_timer_ns(vm_clock, sdhci_do_data_transfer, s);
+}
+
+static void sdhci_uninitfn(Object *obj)
+{
+    SDHCIState *s = SDHCI(obj);
+
+    qemu_del_timer(s->insert_timer);
+    qemu_free_timer(s->insert_timer);
+    qemu_del_timer(s->transfer_timer);
+    qemu_free_timer(s->transfer_timer);
+    qemu_free_irqs(&s->eject_cb);
+    qemu_free_irqs(&s->ro_cb);
+
+    if (s->fifo_buffer) {
+        g_free(s->fifo_buffer);
+        s->fifo_buffer = NULL;
+    }
+}
+
+const VMStateDescription sdhci_vmstate = {
+    .name = "sdhci",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32(sdmasysad, SDHCIState),
+        VMSTATE_UINT16(blksize, SDHCIState),
+        VMSTATE_UINT16(blkcnt, SDHCIState),
+        VMSTATE_UINT32(argument, SDHCIState),
+        VMSTATE_UINT16(trnmod, SDHCIState),
+        VMSTATE_UINT16(cmdreg, SDHCIState),
+        VMSTATE_UINT32_ARRAY(rspreg, SDHCIState, 4),
+        VMSTATE_UINT32(prnsts, SDHCIState),
+        VMSTATE_UINT8(hostctl, SDHCIState),
+        VMSTATE_UINT8(pwrcon, SDHCIState),
+        VMSTATE_UINT8(blkgap, SDHCIState),
+        VMSTATE_UINT8(wakcon, SDHCIState),
+        VMSTATE_UINT16(clkcon, SDHCIState),
+        VMSTATE_UINT8(timeoutcon, SDHCIState),
+        VMSTATE_UINT8(admaerr, SDHCIState),
+        VMSTATE_UINT16(norintsts, SDHCIState),
+        VMSTATE_UINT16(errintsts, SDHCIState),
+        VMSTATE_UINT16(norintstsen, SDHCIState),
+        VMSTATE_UINT16(errintstsen, SDHCIState),
+        VMSTATE_UINT16(norintsigen, SDHCIState),
+        VMSTATE_UINT16(errintsigen, SDHCIState),
+        VMSTATE_UINT16(acmd12errsts, SDHCIState),
+        VMSTATE_UINT16(data_count, SDHCIState),
+        VMSTATE_UINT64(admasysaddr, SDHCIState),
+        VMSTATE_UINT8(stopped_state, SDHCIState),
+        VMSTATE_VBUFFER_UINT32(fifo_buffer, SDHCIState, 1, NULL, 0, buf_maxsz),
+        VMSTATE_TIMER(insert_timer, SDHCIState),
+        VMSTATE_TIMER(transfer_timer, SDHCIState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+/* Capabilities registers provide information on supported features of this
+ * specific host controller implementation */
+static Property sdhci_properties[] = {
+    DEFINE_PROP_HEX32("capareg", SDHCIState, capareg,
+            SDHC_CAPAB_REG_DEFAULT),
+    DEFINE_PROP_HEX32("maxcurr", SDHCIState, maxcurr, 0),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void sdhci_realize(DeviceState *dev, Error ** errp)
+{
+    SDHCIState *s = SDHCI(dev);
+    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+
+    s->buf_maxsz = sdhci_get_fifolen(s);
+    s->fifo_buffer = g_malloc0(s->buf_maxsz);
+    sysbus_init_irq(sbd, &s->irq);
+    memory_region_init_io(&s->iomem, &sdhci_mmio_ops, s, "sdhci",
+            SDHC_REGISTERS_MAP_SIZE);
+    sysbus_init_mmio(sbd, &s->iomem);
+}
+
+static void sdhci_generic_reset(DeviceState *ds)
+{
+    SDHCIState *s = SDHCI(ds);
+    SDHCI_GET_CLASS(s)->reset(s);
+}
+
+static void sdhci_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SDHCIClass *k = SDHCI_CLASS(klass);
+
+    dc->vmsd = &sdhci_vmstate;
+    dc->props = sdhci_properties;
+    dc->reset = sdhci_generic_reset;
+    dc->realize = sdhci_realize;
+
+    k->reset = sdhci_reset;
+    k->mem_read = sdhci_read;
+    k->mem_write = sdhci_write;
+    k->send_command = sdhci_send_command;
+    k->can_issue_command = sdhci_can_issue_command;
+    k->data_transfer = sdhci_data_transfer;
+    k->end_data_transfer = sdhci_end_transfer;
+    k->do_sdma_single = sdhci_sdma_transfer_single_block;
+    k->do_sdma_multi = sdhci_sdma_transfer_multi_blocks;
+    k->do_adma = sdhci_do_adma;
+    k->read_block_from_card = sdhci_read_block_from_card;
+    k->write_block_to_card = sdhci_write_block_to_card;
+    k->bdata_read = sdhci_read_dataport;
+    k->bdata_write = sdhci_write_dataport;
+}
+
+static const TypeInfo sdhci_type_info = {
+    .name = TYPE_SDHCI,
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(SDHCIState),
+    .instance_init = sdhci_initfn,
+    .instance_finalize = sdhci_uninitfn,
+    .class_init = sdhci_class_init,
+    .class_size = sizeof(SDHCIClass)
+};
+
+static void sdhci_register_types(void)
+{
+    type_register_static(&sdhci_type_info);
+}
+
+type_init(sdhci_register_types)
diff --git a/hw/sd/sdhci.h b/hw/sd/sdhci.h
new file mode 100644 (file)
index 0000000..a560c3c
--- /dev/null
@@ -0,0 +1,312 @@
+/*
+ * SD Association Host Standard Specification v2.0 controller emulation
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * Mitsyanko Igor <i.mitsyanko@samsung.com>
+ * Peter A.G. Crosthwaite <peter.crosthwaite@petalogix.com>
+ *
+ * Based on MMC controller for Samsung S5PC1xx-based board emulation
+ * by Alexey Merkulov and Vladimir Monakhov.
+ *
+ * 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 SDHCI_H
+#define SDHCI_H
+
+#include "qemu-common.h"
+#include "hw/sysbus.h"
+#include "hw/sd.h"
+
+/* R/W SDMA System Address register 0x0 */
+#define SDHC_SYSAD                     0x00
+
+/* R/W Host DMA Buffer Boundary and Transfer Block Size Register 0x0 */
+#define SDHC_BLKSIZE                   0x04
+
+/* R/W Blocks count for current transfer 0x0 */
+#define SDHC_BLKCNT                    0x06
+
+/* R/W Command Argument Register 0x0 */
+#define SDHC_ARGUMENT                  0x08
+
+/* R/W Transfer Mode Setting Register 0x0 */
+#define SDHC_TRNMOD                    0x0C
+#define SDHC_TRNS_DMA                  0x0001
+#define SDHC_TRNS_BLK_CNT_EN           0x0002
+#define SDHC_TRNS_ACMD12               0x0004
+#define SDHC_TRNS_READ                 0x0010
+#define SDHC_TRNS_MULTI                0x0020
+
+/* R/W Command Register 0x0 */
+#define SDHC_CMDREG                    0x0E
+#define SDHC_CMD_RSP_WITH_BUSY         (3 << 0)
+#define SDHC_CMD_DATA_PRESENT          (1 << 5)
+#define SDHC_CMD_SUSPEND               (1 << 6)
+#define SDHC_CMD_RESUME                (1 << 7)
+#define SDHC_CMD_ABORT                 ((1 << 6)|(1 << 7))
+#define SDHC_CMD_TYPE_MASK             ((1 << 6)|(1 << 7))
+#define SDHC_COMMAND_TYPE(x)           ((x) & SDHC_CMD_TYPE_MASK)
+
+/* ROC Response Register 0 0x0 */
+#define SDHC_RSPREG0                   0x10
+/* ROC Response Register 1 0x0 */
+#define SDHC_RSPREG1                   0x14
+/* ROC Response Register 2 0x0 */
+#define SDHC_RSPREG2                   0x18
+/* ROC Response Register 3 0x0 */
+#define SDHC_RSPREG3                   0x1C
+
+/* R/W Buffer Data Register 0x0 */
+#define SDHC_BDATA                     0x20
+
+/* R/ROC Present State Register 0x000A0000 */
+#define SDHC_PRNSTS                    0x24
+#define SDHC_CMD_INHIBIT               0x00000001
+#define SDHC_DATA_INHIBIT              0x00000002
+#define SDHC_DAT_LINE_ACTIVE           0x00000004
+#define SDHC_DOING_WRITE               0x00000100
+#define SDHC_DOING_READ                0x00000200
+#define SDHC_SPACE_AVAILABLE           0x00000400
+#define SDHC_DATA_AVAILABLE            0x00000800
+#define SDHC_CARD_PRESENT              0x00010000
+#define SDHC_CARD_DETECT               0x00040000
+#define SDHC_WRITE_PROTECT             0x00080000
+#define TRANSFERRING_DATA(x)           \
+    ((x) & (SDHC_DOING_READ | SDHC_DOING_WRITE))
+
+/* R/W Host control Register 0x0 */
+#define SDHC_HOSTCTL                   0x28
+#define SDHC_CTRL_DMA_CHECK_MASK       0x18
+#define SDHC_CTRL_SDMA                 0x00
+#define SDHC_CTRL_ADMA1_32             0x08
+#define SDHC_CTRL_ADMA2_32             0x10
+#define SDHC_CTRL_ADMA2_64             0x18
+#define SDHC_DMA_TYPE(x)               ((x) & SDHC_CTRL_DMA_CHECK_MASK)
+
+/* R/W Power Control Register 0x0 */
+#define SDHC_PWRCON                    0x29
+#define SDHC_POWER_ON                  (1 << 0)
+
+/* R/W Block Gap Control Register 0x0 */
+#define SDHC_BLKGAP                    0x2A
+#define SDHC_STOP_AT_GAP_REQ           0x01
+#define SDHC_CONTINUE_REQ              0x02
+
+/* R/W WakeUp Control Register 0x0 */
+#define SDHC_WAKCON                    0x2B
+#define SDHC_WKUP_ON_INS               (1 << 1)
+#define SDHC_WKUP_ON_RMV               (1 << 2)
+
+/* CLKCON */
+#define SDHC_CLKCON                    0x2C
+#define SDHC_CLOCK_INT_STABLE          0x0002
+#define SDHC_CLOCK_INT_EN              0x0001
+#define SDHC_CLOCK_SDCLK_EN            (1 << 2)
+#define SDHC_CLOCK_CHK_MASK            0x0007
+#define SDHC_CLOCK_IS_ON(x)            \
+    (((x) & SDHC_CLOCK_CHK_MASK) == SDHC_CLOCK_CHK_MASK)
+
+/* R/W Timeout Control Register 0x0 */
+#define SDHC_TIMEOUTCON                0x2E
+
+/* R/W Software Reset Register 0x0 */
+#define SDHC_SWRST                     0x2F
+#define SDHC_RESET_ALL                 0x01
+#define SDHC_RESET_CMD                 0x02
+#define SDHC_RESET_DATA                0x04
+
+/* ROC/RW1C Normal Interrupt Status Register 0x0 */
+#define SDHC_NORINTSTS                 0x30
+#define SDHC_NIS_ERR                   0x8000
+#define SDHC_NIS_CMDCMP                0x0001
+#define SDHC_NIS_TRSCMP                0x0002
+#define SDHC_NIS_BLKGAP                0x0004
+#define SDHC_NIS_DMA                   0x0008
+#define SDHC_NIS_WBUFRDY               0x0010
+#define SDHC_NIS_RBUFRDY               0x0020
+#define SDHC_NIS_INSERT                0x0040
+#define SDHC_NIS_REMOVE                0x0080
+#define SDHC_NIS_CARDINT               0x0100
+
+/* ROC/RW1C Error Interrupt Status Register 0x0 */
+#define SDHC_ERRINTSTS                 0x32
+#define SDHC_EIS_CMDTIMEOUT            0x0001
+#define SDHC_EIS_BLKGAP                0x0004
+#define SDHC_EIS_CMDIDX                0x0008
+#define SDHC_EIS_CMD12ERR              0x0100
+#define SDHC_EIS_ADMAERR               0x0200
+
+/* R/W Normal Interrupt Status Enable Register 0x0 */
+#define SDHC_NORINTSTSEN               0x34
+#define SDHC_NISEN_CMDCMP              0x0001
+#define SDHC_NISEN_TRSCMP              0x0002
+#define SDHC_NISEN_DMA                 0x0008
+#define SDHC_NISEN_WBUFRDY             0x0010
+#define SDHC_NISEN_RBUFRDY             0x0020
+#define SDHC_NISEN_INSERT              0x0040
+#define SDHC_NISEN_REMOVE              0x0080
+#define SDHC_NISEN_CARDINT             0x0100
+
+/* R/W Error Interrupt Status Enable Register 0x0 */
+#define SDHC_ERRINTSTSEN               0x36
+#define SDHC_EISEN_CMDTIMEOUT          0x0001
+#define SDHC_EISEN_BLKGAP              0x0004
+#define SDHC_EISEN_CMDIDX              0x0008
+#define SDHC_EISEN_ADMAERR             0x0200
+
+/* R/W Normal Interrupt Signal Enable Register 0x0 */
+#define SDHC_NORINTSIGEN               0x38
+#define SDHC_NORINTSIG_INSERT          (1 << 6)
+#define SDHC_NORINTSIG_REMOVE          (1 << 7)
+
+/* R/W Error Interrupt Signal Enable Register 0x0 */
+#define SDHC_ERRINTSIGEN               0x3A
+
+/* ROC Auto CMD12 error status register 0x0 */
+#define SDHC_ACMD12ERRSTS              0x3C
+
+/* HWInit Capabilities Register 0x05E80080 */
+#define SDHC_CAPAREG                   0x40
+#define SDHC_CAN_DO_DMA                0x00400000
+#define SDHC_CAN_DO_ADMA2              0x00080000
+#define SDHC_CAN_DO_ADMA1              0x00100000
+#define SDHC_64_BIT_BUS_SUPPORT        (1 << 28)
+#define SDHC_CAPAB_BLOCKSIZE(x)        (((x) >> 16) & 0x3)
+
+/* HWInit Maximum Current Capabilities Register 0x0 */
+#define SDHC_MAXCURR                   0x48
+
+/* W Force Event Auto CMD12 Error Interrupt Register 0x0000 */
+#define SDHC_FEAER                     0x50
+/* W Force Event Error Interrupt Register Error Interrupt 0x0000 */
+#define SDHC_FEERR                     0x52
+
+/* R/W ADMA Error Status Register 0x00 */
+#define SDHC_ADMAERR                   0x54
+#define SDHC_ADMAERR_LENGTH_MISMATCH   (1 << 2)
+#define SDHC_ADMAERR_STATE_ST_STOP     (0 << 0)
+#define SDHC_ADMAERR_STATE_ST_FDS      (1 << 0)
+#define SDHC_ADMAERR_STATE_ST_TFR      (3 << 0)
+#define SDHC_ADMAERR_STATE_MASK        (3 << 0)
+
+/* R/W ADMA System Address Register 0x00 */
+#define SDHC_ADMASYSADDR               0x58
+#define SDHC_ADMA_ATTR_SET_LEN         (1 << 4)
+#define SDHC_ADMA_ATTR_ACT_TRAN        (1 << 5)
+#define SDHC_ADMA_ATTR_ACT_LINK        (3 << 4)
+#define SDHC_ADMA_ATTR_INT             (1 << 2)
+#define SDHC_ADMA_ATTR_END             (1 << 1)
+#define SDHC_ADMA_ATTR_VALID           (1 << 0)
+#define SDHC_ADMA_ATTR_ACT_MASK        ((1 << 4)|(1 << 5))
+
+/* Slot interrupt status */
+#define SDHC_SLOT_INT_STATUS            0xFC
+
+/* HWInit Host Controller Version Register 0x0401 */
+#define SDHC_HCVER                      0xFE
+#define SD_HOST_SPECv2_VERS             0x2401
+
+#define SDHC_REGISTERS_MAP_SIZE         0x100
+#define SDHC_INSERTION_DELAY            (get_ticks_per_sec())
+#define SDHC_TRANSFER_DELAY             100
+#define SDHC_ADMA_DESCS_PER_DELAY       5
+#define SDHC_CMD_RESPONSE               (3 << 0)
+
+enum {
+    sdhc_not_stopped = 0, /* normal SDHC state */
+    sdhc_gap_read   = 1,  /* SDHC stopped at block gap during read operation */
+    sdhc_gap_write  = 2   /* SDHC stopped at block gap during write operation */
+};
+
+/* SD/MMC host controller state */
+typedef struct SDHCIState {
+    SysBusDevice busdev;
+    SDState *card;
+    MemoryRegion iomem;
+
+    QEMUTimer *insert_timer;       /* timer for 'changing' sd card. */
+    QEMUTimer *transfer_timer;
+    qemu_irq eject_cb;
+    qemu_irq ro_cb;
+    qemu_irq irq;
+
+    uint32_t sdmasysad;    /* SDMA System Address register */
+    uint16_t blksize;      /* Host DMA Buff Boundary and Transfer BlkSize Reg */
+    uint16_t blkcnt;       /* Blocks count for current transfer */
+    uint32_t argument;     /* Command Argument Register */
+    uint16_t trnmod;       /* Transfer Mode Setting Register */
+    uint16_t cmdreg;       /* Command Register */
+    uint32_t rspreg[4];    /* Response Registers 0-3 */
+    uint32_t prnsts;       /* Present State Register */
+    uint8_t  hostctl;      /* Host Control Register */
+    uint8_t  pwrcon;       /* Power control Register */
+    uint8_t  blkgap;       /* Block Gap Control Register */
+    uint8_t  wakcon;       /* WakeUp Control Register */
+    uint16_t clkcon;       /* Clock control Register */
+    uint8_t  timeoutcon;   /* Timeout Control Register */
+    uint8_t  admaerr;      /* ADMA Error Status Register */
+    uint16_t norintsts;    /* Normal Interrupt Status Register */
+    uint16_t errintsts;    /* Error Interrupt Status Register */
+    uint16_t norintstsen;  /* Normal Interrupt Status Enable Register */
+    uint16_t errintstsen;  /* Error Interrupt Status Enable Register */
+    uint16_t norintsigen;  /* Normal Interrupt Signal Enable Register */
+    uint16_t errintsigen;  /* Error Interrupt Signal Enable Register */
+    uint16_t acmd12errsts; /* Auto CMD12 error status register */
+    uint64_t admasysaddr;  /* ADMA System Address Register */
+
+    uint32_t capareg;      /* Capabilities Register */
+    uint32_t maxcurr;      /* Maximum Current Capabilities Register */
+    uint8_t  *fifo_buffer; /* SD host i/o FIFO buffer */
+    uint32_t buf_maxsz;
+    uint16_t data_count;   /* current element in FIFO buffer */
+    uint8_t  stopped_state;/* Current SDHC state */
+    /* Buffer Data Port Register - virtual access point to R and W buffers */
+    /* Software Reset Register - always reads as 0 */
+    /* Force Event Auto CMD12 Error Interrupt Reg - write only */
+    /* Force Event Error Interrupt Register- write only */
+    /* RO Host Controller Version Register always reads as 0x2401 */
+} SDHCIState;
+
+typedef struct SDHCIClass {
+    SysBusDeviceClass busdev_class;
+
+    void (*reset)(SDHCIState *s);
+    uint32_t (*mem_read)(SDHCIState *s, unsigned int offset, unsigned size);
+    void (*mem_write)(SDHCIState *s, unsigned int offset, uint32_t value,
+            unsigned size);
+    void (*send_command)(SDHCIState *s);
+    bool (*can_issue_command)(SDHCIState *s);
+    void (*data_transfer)(SDHCIState *s);
+    void (*end_data_transfer)(SDHCIState *s);
+    void (*do_sdma_single)(SDHCIState *s);
+    void (*do_sdma_multi)(SDHCIState *s);
+    void (*do_adma)(SDHCIState *s);
+    void (*read_block_from_card)(SDHCIState *s);
+    void (*write_block_to_card)(SDHCIState *s);
+    uint32_t (*bdata_read)(SDHCIState *s, unsigned size);
+    void (*bdata_write)(SDHCIState *s, uint32_t value, unsigned size);
+} SDHCIClass;
+
+extern const VMStateDescription sdhci_vmstate;
+
+#define TYPE_SDHCI            "generic-sdhci"
+#define SDHCI(obj)            \
+     OBJECT_CHECK(SDHCIState, (obj), TYPE_SDHCI)
+#define SDHCI_CLASS(klass)    \
+     OBJECT_CLASS_CHECK(SDHCIClass, (klass), TYPE_SDHCI)
+#define SDHCI_GET_CLASS(obj)  \
+     OBJECT_GET_CLASS(SDHCIClass, (obj), TYPE_SDHCI)
+
+#endif /* SDHCI_H */
diff --git a/hw/sd/ssi-sd.c b/hw/sd/ssi-sd.c
new file mode 100644 (file)
index 0000000..4d3c4f6
--- /dev/null
@@ -0,0 +1,274 @@
+/*
+ * SSI to SD card adapter.
+ *
+ * Copyright (c) 2007-2009 CodeSourcery.
+ * 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 "sysemu/blockdev.h"
+#include "hw/ssi.h"
+#include "hw/sd.h"
+
+//#define DEBUG_SSI_SD 1
+
+#ifdef DEBUG_SSI_SD
+#define DPRINTF(fmt, ...) \
+do { printf("ssi_sd: " fmt , ## __VA_ARGS__); } while (0)
+#define BADF(fmt, ...) \
+do { fprintf(stderr, "ssi_sd: error: " fmt , ## __VA_ARGS__); exit(1);} while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while(0)
+#define BADF(fmt, ...) \
+do { fprintf(stderr, "ssi_sd: error: " fmt , ## __VA_ARGS__);} while (0)
+#endif
+
+typedef enum {
+    SSI_SD_CMD,
+    SSI_SD_CMDARG,
+    SSI_SD_RESPONSE,
+    SSI_SD_DATA_START,
+    SSI_SD_DATA_READ,
+} ssi_sd_mode;
+
+typedef struct {
+    SSISlave ssidev;
+    ssi_sd_mode mode;
+    int cmd;
+    uint8_t cmdarg[4];
+    uint8_t response[5];
+    int arglen;
+    int response_pos;
+    int stopping;
+    SDState *sd;
+} ssi_sd_state;
+
+/* State word bits.  */
+#define SSI_SDR_LOCKED          0x0001
+#define SSI_SDR_WP_ERASE        0x0002
+#define SSI_SDR_ERROR           0x0004
+#define SSI_SDR_CC_ERROR        0x0008
+#define SSI_SDR_ECC_FAILED      0x0010
+#define SSI_SDR_WP_VIOLATION    0x0020
+#define SSI_SDR_ERASE_PARAM     0x0040
+#define SSI_SDR_OUT_OF_RANGE    0x0080
+#define SSI_SDR_IDLE            0x0100
+#define SSI_SDR_ERASE_RESET     0x0200
+#define SSI_SDR_ILLEGAL_COMMAND 0x0400
+#define SSI_SDR_COM_CRC_ERROR   0x0800
+#define SSI_SDR_ERASE_SEQ_ERROR 0x1000
+#define SSI_SDR_ADDRESS_ERROR   0x2000
+#define SSI_SDR_PARAMETER_ERROR 0x4000
+
+static uint32_t ssi_sd_transfer(SSISlave *dev, uint32_t val)
+{
+    ssi_sd_state *s = FROM_SSI_SLAVE(ssi_sd_state, dev);
+
+    /* Special case: allow CMD12 (STOP TRANSMISSION) while reading data.  */
+    if (s->mode == SSI_SD_DATA_READ && val == 0x4d) {
+        s->mode = SSI_SD_CMD;
+        /* There must be at least one byte delay before the card responds.  */
+        s->stopping = 1;
+    }
+
+    switch (s->mode) {
+    case SSI_SD_CMD:
+        if (val == 0xff) {
+            DPRINTF("NULL command\n");
+            return 0xff;
+        }
+        s->cmd = val & 0x3f;
+        s->mode = SSI_SD_CMDARG;
+        s->arglen = 0;
+        return 0xff;
+    case SSI_SD_CMDARG:
+        if (s->arglen == 4) {
+            SDRequest request;
+            uint8_t longresp[16];
+            /* FIXME: Check CRC.  */
+            request.cmd = s->cmd;
+            request.arg = (s->cmdarg[0] << 24) | (s->cmdarg[1] << 16)
+                           | (s->cmdarg[2] << 8) | s->cmdarg[3];
+            DPRINTF("CMD%d arg 0x%08x\n", s->cmd, request.arg);
+            s->arglen = sd_do_command(s->sd, &request, longresp);
+            if (s->arglen <= 0) {
+                s->arglen = 1;
+                s->response[0] = 4;
+                DPRINTF("SD command failed\n");
+            } else if (s->cmd == 58) {
+                /* CMD58 returns R3 response (OCR)  */
+                DPRINTF("Returned OCR\n");
+                s->arglen = 5;
+                s->response[0] = 1;
+                memcpy(&s->response[1], longresp, 4);
+            } else if (s->arglen != 4) {
+                BADF("Unexpected response to cmd %d\n", s->cmd);
+                /* Illegal command is about as near as we can get.  */
+                s->arglen = 1;
+                s->response[0] = 4;
+            } else {
+                /* All other commands return status.  */
+                uint32_t cardstatus;
+                uint16_t status;
+                /* CMD13 returns a 2-byte statuse work. Other commands
+                   only return the first byte.  */
+                s->arglen = (s->cmd == 13) ? 2 : 1;
+                cardstatus = (longresp[0] << 24) | (longresp[1] << 16)
+                             | (longresp[2] << 8) | longresp[3];
+                status = 0;
+                if (((cardstatus >> 9) & 0xf) < 4)
+                    status |= SSI_SDR_IDLE;
+                if (cardstatus & ERASE_RESET)
+                    status |= SSI_SDR_ERASE_RESET;
+                if (cardstatus & ILLEGAL_COMMAND)
+                    status |= SSI_SDR_ILLEGAL_COMMAND;
+                if (cardstatus & COM_CRC_ERROR)
+                    status |= SSI_SDR_COM_CRC_ERROR;
+                if (cardstatus & ERASE_SEQ_ERROR)
+                    status |= SSI_SDR_ERASE_SEQ_ERROR;
+                if (cardstatus & ADDRESS_ERROR)
+                    status |= SSI_SDR_ADDRESS_ERROR;
+                if (cardstatus & CARD_IS_LOCKED)
+                    status |= SSI_SDR_LOCKED;
+                if (cardstatus & (LOCK_UNLOCK_FAILED | WP_ERASE_SKIP))
+                    status |= SSI_SDR_WP_ERASE;
+                if (cardstatus & SD_ERROR)
+                    status |= SSI_SDR_ERROR;
+                if (cardstatus & CC_ERROR)
+                    status |= SSI_SDR_CC_ERROR;
+                if (cardstatus & CARD_ECC_FAILED)
+                    status |= SSI_SDR_ECC_FAILED;
+                if (cardstatus & WP_VIOLATION)
+                    status |= SSI_SDR_WP_VIOLATION;
+                if (cardstatus & ERASE_PARAM)
+                    status |= SSI_SDR_ERASE_PARAM;
+                if (cardstatus & (OUT_OF_RANGE | CID_CSD_OVERWRITE))
+                    status |= SSI_SDR_OUT_OF_RANGE;
+                /* ??? Don't know what Parameter Error really means, so
+                   assume it's set if the second byte is nonzero.  */
+                if (status & 0xff)
+                    status |= SSI_SDR_PARAMETER_ERROR;
+                s->response[0] = status >> 8;
+                s->response[1] = status;
+                DPRINTF("Card status 0x%02x\n", status);
+            }
+            s->mode = SSI_SD_RESPONSE;
+            s->response_pos = 0;
+        } else {
+            s->cmdarg[s->arglen++] = val;
+        }
+        return 0xff;
+    case SSI_SD_RESPONSE:
+        if (s->stopping) {
+            s->stopping = 0;
+            return 0xff;
+        }
+        if (s->response_pos < s->arglen) {
+            DPRINTF("Response 0x%02x\n", s->response[s->response_pos]);
+            return s->response[s->response_pos++];
+        }
+        if (sd_data_ready(s->sd)) {
+            DPRINTF("Data read\n");
+            s->mode = SSI_SD_DATA_START;
+        } else {
+            DPRINTF("End of command\n");
+            s->mode = SSI_SD_CMD;
+        }
+        return 0xff;
+    case SSI_SD_DATA_START:
+        DPRINTF("Start read block\n");
+        s->mode = SSI_SD_DATA_READ;
+        return 0xfe;
+    case SSI_SD_DATA_READ:
+        val = sd_read_data(s->sd);
+        if (!sd_data_ready(s->sd)) {
+            DPRINTF("Data read end\n");
+            s->mode = SSI_SD_CMD;
+        }
+        return val;
+    }
+    /* Should never happen.  */
+    return 0xff;
+}
+
+static void ssi_sd_save(QEMUFile *f, void *opaque)
+{
+    SSISlave *ss = SSI_SLAVE(opaque);
+    ssi_sd_state *s = (ssi_sd_state *)opaque;
+    int i;
+
+    qemu_put_be32(f, s->mode);
+    qemu_put_be32(f, s->cmd);
+    for (i = 0; i < 4; i++)
+        qemu_put_be32(f, s->cmdarg[i]);
+    for (i = 0; i < 5; i++)
+        qemu_put_be32(f, s->response[i]);
+    qemu_put_be32(f, s->arglen);
+    qemu_put_be32(f, s->response_pos);
+    qemu_put_be32(f, s->stopping);
+
+    qemu_put_be32(f, ss->cs);
+}
+
+static int ssi_sd_load(QEMUFile *f, void *opaque, int version_id)
+{
+    SSISlave *ss = SSI_SLAVE(opaque);
+    ssi_sd_state *s = (ssi_sd_state *)opaque;
+    int i;
+
+    if (version_id != 1)
+        return -EINVAL;
+
+    s->mode = qemu_get_be32(f);
+    s->cmd = qemu_get_be32(f);
+    for (i = 0; i < 4; i++)
+        s->cmdarg[i] = qemu_get_be32(f);
+    for (i = 0; i < 5; i++)
+        s->response[i] = qemu_get_be32(f);
+    s->arglen = qemu_get_be32(f);
+    s->response_pos = qemu_get_be32(f);
+    s->stopping = qemu_get_be32(f);
+
+    ss->cs = qemu_get_be32(f);
+
+    return 0;
+}
+
+static int ssi_sd_init(SSISlave *dev)
+{
+    ssi_sd_state *s = FROM_SSI_SLAVE(ssi_sd_state, dev);
+    DriveInfo *dinfo;
+
+    s->mode = SSI_SD_CMD;
+    dinfo = drive_get_next(IF_SD);
+    s->sd = sd_init(dinfo ? dinfo->bdrv : NULL, 1);
+    register_savevm(&dev->qdev, "ssi_sd", -1, 1, ssi_sd_save, ssi_sd_load, s);
+    return 0;
+}
+
+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;
+    k->cs_polarity = SSI_CS_LOW;
+}
+
+static const 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_types(void)
+{
+    type_register_static(&ssi_sd_info);
+}
+
+type_init(ssi_sd_register_types)
diff --git a/hw/sdhci.c b/hw/sdhci.c
deleted file mode 100644 (file)
index 4a29e6c..0000000
+++ /dev/null
@@ -1,1300 +0,0 @@
-/*
- * SD Association Host Standard Specification v2.0 controller emulation
- *
- * Copyright (c) 2011 Samsung Electronics Co., Ltd.
- * Mitsyanko Igor <i.mitsyanko@samsung.com>
- * Peter A.G. Crosthwaite <peter.crosthwaite@petalogix.com>
- *
- * Based on MMC controller for Samsung S5PC1xx-based board emulation
- * by Alexey Merkulov and Vladimir Monakhov.
- *
- * 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 "hw/hw.h"
-#include "sysemu/blockdev.h"
-#include "sysemu/dma.h"
-#include "qemu/timer.h"
-#include "block/block_int.h"
-#include "qemu/bitops.h"
-
-#include "hw/sdhci.h"
-
-/* host controller debug messages */
-#ifndef SDHC_DEBUG
-#define SDHC_DEBUG                        0
-#endif
-
-#if SDHC_DEBUG == 0
-    #define DPRINT_L1(fmt, args...)       do { } while (0)
-    #define DPRINT_L2(fmt, args...)       do { } while (0)
-    #define ERRPRINT(fmt, args...)        do { } while (0)
-#elif SDHC_DEBUG == 1
-    #define DPRINT_L1(fmt, args...)       \
-        do {fprintf(stderr, "QEMU SDHC: "fmt, ## args); } while (0)
-    #define DPRINT_L2(fmt, args...)       do { } while (0)
-    #define ERRPRINT(fmt, args...)        \
-        do {fprintf(stderr, "QEMU SDHC ERROR: "fmt, ## args); } while (0)
-#else
-    #define DPRINT_L1(fmt, args...)       \
-        do {fprintf(stderr, "QEMU SDHC: "fmt, ## args); } while (0)
-    #define DPRINT_L2(fmt, args...)       \
-        do {fprintf(stderr, "QEMU SDHC: "fmt, ## args); } while (0)
-    #define ERRPRINT(fmt, args...)        \
-        do {fprintf(stderr, "QEMU SDHC ERROR: "fmt, ## args); } while (0)
-#endif
-
-/* Default SD/MMC host controller features information, which will be
- * presented in CAPABILITIES register of generic SD host controller at reset.
- * If not stated otherwise:
- * 0 - not supported, 1 - supported, other - prohibited.
- */
-#define SDHC_CAPAB_64BITBUS       0ul        /* 64-bit System Bus Support */
-#define SDHC_CAPAB_18V            1ul        /* Voltage support 1.8v */
-#define SDHC_CAPAB_30V            0ul        /* Voltage support 3.0v */
-#define SDHC_CAPAB_33V            1ul        /* Voltage support 3.3v */
-#define SDHC_CAPAB_SUSPRESUME     0ul        /* Suspend/resume support */
-#define SDHC_CAPAB_SDMA           1ul        /* SDMA support */
-#define SDHC_CAPAB_HIGHSPEED      1ul        /* High speed support */
-#define SDHC_CAPAB_ADMA1          1ul        /* ADMA1 support */
-#define SDHC_CAPAB_ADMA2          1ul        /* ADMA2 support */
-/* Maximum host controller R/W buffers size
- * Possible values: 512, 1024, 2048 bytes */
-#define SDHC_CAPAB_MAXBLOCKLENGTH 512ul
-/* Maximum clock frequency for SDclock in MHz
- * value in range 10-63 MHz, 0 - not defined */
-#define SDHC_CAPAB_BASECLKFREQ    0ul
-#define SDHC_CAPAB_TOUNIT         1ul  /* Timeout clock unit 0 - kHz, 1 - MHz */
-/* Timeout clock frequency 1-63, 0 - not defined */
-#define SDHC_CAPAB_TOCLKFREQ      0ul
-
-/* Now check all parameters and calculate CAPABILITIES REGISTER value */
-#if SDHC_CAPAB_64BITBUS > 1 || SDHC_CAPAB_18V > 1 || SDHC_CAPAB_30V > 1 ||     \
-    SDHC_CAPAB_33V > 1 || SDHC_CAPAB_SUSPRESUME > 1 || SDHC_CAPAB_SDMA > 1 ||  \
-    SDHC_CAPAB_HIGHSPEED > 1 || SDHC_CAPAB_ADMA2 > 1 || SDHC_CAPAB_ADMA1 > 1 ||\
-    SDHC_CAPAB_TOUNIT > 1
-#error Capabilities features can have value 0 or 1 only!
-#endif
-
-#if SDHC_CAPAB_MAXBLOCKLENGTH == 512
-#define MAX_BLOCK_LENGTH 0ul
-#elif SDHC_CAPAB_MAXBLOCKLENGTH == 1024
-#define MAX_BLOCK_LENGTH 1ul
-#elif SDHC_CAPAB_MAXBLOCKLENGTH == 2048
-#define MAX_BLOCK_LENGTH 2ul
-#else
-#error Max host controller block size can have value 512, 1024 or 2048 only!
-#endif
-
-#if (SDHC_CAPAB_BASECLKFREQ > 0 && SDHC_CAPAB_BASECLKFREQ < 10) || \
-    SDHC_CAPAB_BASECLKFREQ > 63
-#error SDclock frequency can have value in range 0, 10-63 only!
-#endif
-
-#if SDHC_CAPAB_TOCLKFREQ > 63
-#error Timeout clock frequency can have value in range 0-63 only!
-#endif
-
-#define SDHC_CAPAB_REG_DEFAULT                                 \
-   ((SDHC_CAPAB_64BITBUS << 28) | (SDHC_CAPAB_18V << 26) |     \
-    (SDHC_CAPAB_30V << 25) | (SDHC_CAPAB_33V << 24) |          \
-    (SDHC_CAPAB_SUSPRESUME << 23) | (SDHC_CAPAB_SDMA << 22) |  \
-    (SDHC_CAPAB_HIGHSPEED << 21) | (SDHC_CAPAB_ADMA1 << 20) |  \
-    (SDHC_CAPAB_ADMA2 << 19) | (MAX_BLOCK_LENGTH << 16) |      \
-    (SDHC_CAPAB_BASECLKFREQ << 8) | (SDHC_CAPAB_TOUNIT << 7) | \
-    (SDHC_CAPAB_TOCLKFREQ))
-
-#define MASKED_WRITE(reg, mask, val)  (reg = (reg & (mask)) | (val))
-
-static uint8_t sdhci_slotint(SDHCIState *s)
-{
-    return (s->norintsts & s->norintsigen) || (s->errintsts & s->errintsigen) ||
-         ((s->norintsts & SDHC_NIS_INSERT) && (s->wakcon & SDHC_WKUP_ON_INS)) ||
-         ((s->norintsts & SDHC_NIS_REMOVE) && (s->wakcon & SDHC_WKUP_ON_RMV));
-}
-
-static inline void sdhci_update_irq(SDHCIState *s)
-{
-    qemu_set_irq(s->irq, sdhci_slotint(s));
-}
-
-static void sdhci_raise_insertion_irq(void *opaque)
-{
-    SDHCIState *s = (SDHCIState *)opaque;
-
-    if (s->norintsts & SDHC_NIS_REMOVE) {
-        qemu_mod_timer(s->insert_timer,
-                       qemu_get_clock_ns(vm_clock) + SDHC_INSERTION_DELAY);
-    } else {
-        s->prnsts = 0x1ff0000;
-        if (s->norintstsen & SDHC_NISEN_INSERT) {
-            s->norintsts |= SDHC_NIS_INSERT;
-        }
-        sdhci_update_irq(s);
-    }
-}
-
-static void sdhci_insert_eject_cb(void *opaque, int irq, int level)
-{
-    SDHCIState *s = (SDHCIState *)opaque;
-    DPRINT_L1("Card state changed: %s!\n", level ? "insert" : "eject");
-
-    if ((s->norintsts & SDHC_NIS_REMOVE) && level) {
-        /* Give target some time to notice card ejection */
-        qemu_mod_timer(s->insert_timer,
-                       qemu_get_clock_ns(vm_clock) + SDHC_INSERTION_DELAY);
-    } else {
-        if (level) {
-            s->prnsts = 0x1ff0000;
-            if (s->norintstsen & SDHC_NISEN_INSERT) {
-                s->norintsts |= SDHC_NIS_INSERT;
-            }
-        } else {
-            s->prnsts = 0x1fa0000;
-            s->pwrcon &= ~SDHC_POWER_ON;
-            s->clkcon &= ~SDHC_CLOCK_SDCLK_EN;
-            if (s->norintstsen & SDHC_NISEN_REMOVE) {
-                s->norintsts |= SDHC_NIS_REMOVE;
-            }
-        }
-        sdhci_update_irq(s);
-    }
-}
-
-static void sdhci_card_readonly_cb(void *opaque, int irq, int level)
-{
-    SDHCIState *s = (SDHCIState *)opaque;
-
-    if (level) {
-        s->prnsts &= ~SDHC_WRITE_PROTECT;
-    } else {
-        /* Write enabled */
-        s->prnsts |= SDHC_WRITE_PROTECT;
-    }
-}
-
-static void sdhci_reset(SDHCIState *s)
-{
-    qemu_del_timer(s->insert_timer);
-    qemu_del_timer(s->transfer_timer);
-    /* Set all registers to 0. Capabilities registers are not cleared
-     * and assumed to always preserve their value, given to them during
-     * initialization */
-    memset(&s->sdmasysad, 0, (uintptr_t)&s->capareg - (uintptr_t)&s->sdmasysad);
-
-    sd_set_cb(s->card, s->ro_cb, s->eject_cb);
-    s->data_count = 0;
-    s->stopped_state = sdhc_not_stopped;
-}
-
-static void sdhci_do_data_transfer(void *opaque)
-{
-    SDHCIState *s = (SDHCIState *)opaque;
-
-    SDHCI_GET_CLASS(s)->data_transfer(s);
-}
-
-static void sdhci_send_command(SDHCIState *s)
-{
-    SDRequest request;
-    uint8_t response[16];
-    int rlen;
-
-    s->errintsts = 0;
-    s->acmd12errsts = 0;
-    request.cmd = s->cmdreg >> 8;
-    request.arg = s->argument;
-    DPRINT_L1("sending CMD%u ARG[0x%08x]\n", request.cmd, request.arg);
-    rlen = sd_do_command(s->card, &request, response);
-
-    if (s->cmdreg & SDHC_CMD_RESPONSE) {
-        if (rlen == 4) {
-            s->rspreg[0] = (response[0] << 24) | (response[1] << 16) |
-                           (response[2] << 8)  |  response[3];
-            s->rspreg[1] = s->rspreg[2] = s->rspreg[3] = 0;
-            DPRINT_L1("Response: RSPREG[31..0]=0x%08x\n", s->rspreg[0]);
-        } else if (rlen == 16) {
-            s->rspreg[0] = (response[11] << 24) | (response[12] << 16) |
-                           (response[13] << 8) |  response[14];
-            s->rspreg[1] = (response[7] << 24) | (response[8] << 16) |
-                           (response[9] << 8)  |  response[10];
-            s->rspreg[2] = (response[3] << 24) | (response[4] << 16) |
-                           (response[5] << 8)  |  response[6];
-            s->rspreg[3] = (response[0] << 16) | (response[1] << 8) |
-                            response[2];
-            DPRINT_L1("Response received:\n RSPREG[127..96]=0x%08x, RSPREG[95.."
-                  "64]=0x%08x,\n RSPREG[63..32]=0x%08x, RSPREG[31..0]=0x%08x\n",
-                  s->rspreg[3], s->rspreg[2], s->rspreg[1], s->rspreg[0]);
-        } else {
-            ERRPRINT("Timeout waiting for command response\n");
-            if (s->errintstsen & SDHC_EISEN_CMDTIMEOUT) {
-                s->errintsts |= SDHC_EIS_CMDTIMEOUT;
-                s->norintsts |= SDHC_NIS_ERR;
-            }
-        }
-
-        if ((s->norintstsen & SDHC_NISEN_TRSCMP) &&
-            (s->cmdreg & SDHC_CMD_RESPONSE) == SDHC_CMD_RSP_WITH_BUSY) {
-            s->norintsts |= SDHC_NIS_TRSCMP;
-        }
-    } else if (rlen != 0 && (s->errintstsen & SDHC_EISEN_CMDIDX)) {
-        s->errintsts |= SDHC_EIS_CMDIDX;
-        s->norintsts |= SDHC_NIS_ERR;
-    }
-
-    if (s->norintstsen & SDHC_NISEN_CMDCMP) {
-        s->norintsts |= SDHC_NIS_CMDCMP;
-    }
-
-    sdhci_update_irq(s);
-
-    if (s->blksize && (s->cmdreg & SDHC_CMD_DATA_PRESENT)) {
-        sdhci_do_data_transfer(s);
-    }
-}
-
-static void sdhci_end_transfer(SDHCIState *s)
-{
-    /* Automatically send CMD12 to stop transfer if AutoCMD12 enabled */
-    if ((s->trnmod & SDHC_TRNS_ACMD12) != 0) {
-        SDRequest request;
-        uint8_t response[16];
-
-        request.cmd = 0x0C;
-        request.arg = 0;
-        DPRINT_L1("Automatically issue CMD%d %08x\n", request.cmd, request.arg);
-        sd_do_command(s->card, &request, response);
-        /* Auto CMD12 response goes to the upper Response register */
-        s->rspreg[3] = (response[0] << 24) | (response[1] << 16) |
-                (response[2] << 8) | response[3];
-    }
-
-    s->prnsts &= ~(SDHC_DOING_READ | SDHC_DOING_WRITE |
-            SDHC_DAT_LINE_ACTIVE | SDHC_DATA_INHIBIT |
-            SDHC_SPACE_AVAILABLE | SDHC_DATA_AVAILABLE);
-
-    if (s->norintstsen & SDHC_NISEN_TRSCMP) {
-        s->norintsts |= SDHC_NIS_TRSCMP;
-    }
-
-    sdhci_update_irq(s);
-}
-
-/*
- * Programmed i/o data transfer
- */
-
-/* Fill host controller's read buffer with BLKSIZE bytes of data from card */
-static void sdhci_read_block_from_card(SDHCIState *s)
-{
-    int index = 0;
-
-    if ((s->trnmod & SDHC_TRNS_MULTI) &&
-            (s->trnmod & SDHC_TRNS_BLK_CNT_EN) && (s->blkcnt == 0)) {
-        return;
-    }
-
-    for (index = 0; index < (s->blksize & 0x0fff); index++) {
-        s->fifo_buffer[index] = sd_read_data(s->card);
-    }
-
-    /* New data now available for READ through Buffer Port Register */
-    s->prnsts |= SDHC_DATA_AVAILABLE;
-    if (s->norintstsen & SDHC_NISEN_RBUFRDY) {
-        s->norintsts |= SDHC_NIS_RBUFRDY;
-    }
-
-    /* Clear DAT line active status if that was the last block */
-    if ((s->trnmod & SDHC_TRNS_MULTI) == 0 ||
-            ((s->trnmod & SDHC_TRNS_MULTI) && s->blkcnt == 1)) {
-        s->prnsts &= ~SDHC_DAT_LINE_ACTIVE;
-    }
-
-    /* If stop at block gap request was set and it's not the last block of
-     * data - generate Block Event interrupt */
-    if (s->stopped_state == sdhc_gap_read && (s->trnmod & SDHC_TRNS_MULTI) &&
-            s->blkcnt != 1)    {
-        s->prnsts &= ~SDHC_DAT_LINE_ACTIVE;
-        if (s->norintstsen & SDHC_EISEN_BLKGAP) {
-            s->norintsts |= SDHC_EIS_BLKGAP;
-        }
-    }
-
-    sdhci_update_irq(s);
-}
-
-/* Read @size byte of data from host controller @s BUFFER DATA PORT register */
-static uint32_t sdhci_read_dataport(SDHCIState *s, unsigned size)
-{
-    uint32_t value = 0;
-    int i;
-
-    /* first check that a valid data exists in host controller input buffer */
-    if ((s->prnsts & SDHC_DATA_AVAILABLE) == 0) {
-        ERRPRINT("Trying to read from empty buffer\n");
-        return 0;
-    }
-
-    for (i = 0; i < size; i++) {
-        value |= s->fifo_buffer[s->data_count] << i * 8;
-        s->data_count++;
-        /* check if we've read all valid data (blksize bytes) from buffer */
-        if ((s->data_count) >= (s->blksize & 0x0fff)) {
-            DPRINT_L2("All %u bytes of data have been read from input buffer\n",
-                    s->data_count);
-            s->prnsts &= ~SDHC_DATA_AVAILABLE; /* no more data in a buffer */
-            s->data_count = 0;  /* next buff read must start at position [0] */
-
-            if (s->trnmod & SDHC_TRNS_BLK_CNT_EN) {
-                s->blkcnt--;
-            }
-
-            /* if that was the last block of data */
-            if ((s->trnmod & SDHC_TRNS_MULTI) == 0 ||
-                ((s->trnmod & SDHC_TRNS_BLK_CNT_EN) && (s->blkcnt == 0)) ||
-                 /* stop at gap request */
-                (s->stopped_state == sdhc_gap_read &&
-                 !(s->prnsts & SDHC_DAT_LINE_ACTIVE))) {
-                SDHCI_GET_CLASS(s)->end_data_transfer(s);
-            } else { /* if there are more data, read next block from card */
-                SDHCI_GET_CLASS(s)->read_block_from_card(s);
-            }
-            break;
-        }
-    }
-
-    return value;
-}
-
-/* Write data from host controller FIFO to card */
-static void sdhci_write_block_to_card(SDHCIState *s)
-{
-    int index = 0;
-
-    if (s->prnsts & SDHC_SPACE_AVAILABLE) {
-        if (s->norintstsen & SDHC_NISEN_WBUFRDY) {
-            s->norintsts |= SDHC_NIS_WBUFRDY;
-        }
-        sdhci_update_irq(s);
-        return;
-    }
-
-    if (s->trnmod & SDHC_TRNS_BLK_CNT_EN) {
-        if (s->blkcnt == 0) {
-            return;
-        } else {
-            s->blkcnt--;
-        }
-    }
-
-    for (index = 0; index < (s->blksize & 0x0fff); index++) {
-        sd_write_data(s->card, s->fifo_buffer[index]);
-    }
-
-    /* Next data can be written through BUFFER DATORT register */
-    s->prnsts |= SDHC_SPACE_AVAILABLE;
-    if (s->norintstsen & SDHC_NISEN_WBUFRDY) {
-        s->norintsts |= SDHC_NIS_WBUFRDY;
-    }
-
-    /* Finish transfer if that was the last block of data */
-    if ((s->trnmod & SDHC_TRNS_MULTI) == 0 ||
-            ((s->trnmod & SDHC_TRNS_MULTI) &&
-            (s->trnmod & SDHC_TRNS_BLK_CNT_EN) && (s->blkcnt == 0))) {
-        SDHCI_GET_CLASS(s)->end_data_transfer(s);
-    }
-
-    /* Generate Block Gap Event if requested and if not the last block */
-    if (s->stopped_state == sdhc_gap_write && (s->trnmod & SDHC_TRNS_MULTI) &&
-            s->blkcnt > 0) {
-        s->prnsts &= ~SDHC_DOING_WRITE;
-        if (s->norintstsen & SDHC_EISEN_BLKGAP) {
-            s->norintsts |= SDHC_EIS_BLKGAP;
-        }
-        SDHCI_GET_CLASS(s)->end_data_transfer(s);
-    }
-
-    sdhci_update_irq(s);
-}
-
-/* Write @size bytes of @value data to host controller @s Buffer Data Port
- * register */
-static void sdhci_write_dataport(SDHCIState *s, uint32_t value, unsigned size)
-{
-    unsigned i;
-
-    /* Check that there is free space left in a buffer */
-    if (!(s->prnsts & SDHC_SPACE_AVAILABLE)) {
-        ERRPRINT("Can't write to data buffer: buffer full\n");
-        return;
-    }
-
-    for (i = 0; i < size; i++) {
-        s->fifo_buffer[s->data_count] = value & 0xFF;
-        s->data_count++;
-        value >>= 8;
-        if (s->data_count >= (s->blksize & 0x0fff)) {
-            DPRINT_L2("write buffer filled with %u bytes of data\n",
-                    s->data_count);
-            s->data_count = 0;
-            s->prnsts &= ~SDHC_SPACE_AVAILABLE;
-            if (s->prnsts & SDHC_DOING_WRITE) {
-                SDHCI_GET_CLASS(s)->write_block_to_card(s);
-            }
-        }
-    }
-}
-
-/*
- * Single DMA data transfer
- */
-
-/* Multi block SDMA transfer */
-static void sdhci_sdma_transfer_multi_blocks(SDHCIState *s)
-{
-    bool page_aligned = false;
-    unsigned int n, begin;
-    const uint16_t block_size = s->blksize & 0x0fff;
-    uint32_t boundary_chk = 1 << (((s->blksize & 0xf000) >> 12) + 12);
-    uint32_t boundary_count = boundary_chk - (s->sdmasysad % boundary_chk);
-
-    /* XXX: Some sd/mmc drivers (for example, u-boot-slp) do not account for
-     * possible stop at page boundary if initial address is not page aligned,
-     * allow them to work properly */
-    if ((s->sdmasysad % boundary_chk) == 0) {
-        page_aligned = true;
-    }
-
-    if (s->trnmod & SDHC_TRNS_READ) {
-        s->prnsts |= SDHC_DOING_READ | SDHC_DATA_INHIBIT |
-                SDHC_DAT_LINE_ACTIVE;
-        while (s->blkcnt) {
-            if (s->data_count == 0) {
-                for (n = 0; n < block_size; n++) {
-                    s->fifo_buffer[n] = sd_read_data(s->card);
-                }
-            }
-            begin = s->data_count;
-            if (((boundary_count + begin) < block_size) && page_aligned) {
-                s->data_count = boundary_count + begin;
-                boundary_count = 0;
-             } else {
-                s->data_count = block_size;
-                boundary_count -= block_size - begin;
-                if (s->trnmod & SDHC_TRNS_BLK_CNT_EN) {
-                    s->blkcnt--;
-                }
-            }
-            dma_memory_write(&dma_context_memory, s->sdmasysad,
-                             &s->fifo_buffer[begin], s->data_count - begin);
-            s->sdmasysad += s->data_count - begin;
-            if (s->data_count == block_size) {
-                s->data_count = 0;
-            }
-            if (page_aligned && boundary_count == 0) {
-                break;
-            }
-        }
-    } else {
-        s->prnsts |= SDHC_DOING_WRITE | SDHC_DATA_INHIBIT |
-                SDHC_DAT_LINE_ACTIVE;
-        while (s->blkcnt) {
-            begin = s->data_count;
-            if (((boundary_count + begin) < block_size) && page_aligned) {
-                s->data_count = boundary_count + begin;
-                boundary_count = 0;
-             } else {
-                s->data_count = block_size;
-                boundary_count -= block_size - begin;
-            }
-            dma_memory_read(&dma_context_memory, s->sdmasysad,
-                            &s->fifo_buffer[begin], s->data_count);
-            s->sdmasysad += s->data_count - begin;
-            if (s->data_count == block_size) {
-                for (n = 0; n < block_size; n++) {
-                    sd_write_data(s->card, s->fifo_buffer[n]);
-                }
-                s->data_count = 0;
-                if (s->trnmod & SDHC_TRNS_BLK_CNT_EN) {
-                    s->blkcnt--;
-                }
-            }
-            if (page_aligned && boundary_count == 0) {
-                break;
-            }
-        }
-    }
-
-    if (s->blkcnt == 0) {
-        SDHCI_GET_CLASS(s)->end_data_transfer(s);
-    } else {
-        if (s->norintstsen & SDHC_NISEN_DMA) {
-            s->norintsts |= SDHC_NIS_DMA;
-        }
-        sdhci_update_irq(s);
-    }
-}
-
-/* single block SDMA transfer */
-
-static void sdhci_sdma_transfer_single_block(SDHCIState *s)
-{
-    int n;
-    uint32_t datacnt = s->blksize & 0x0fff;
-
-    if (s->trnmod & SDHC_TRNS_READ) {
-        for (n = 0; n < datacnt; n++) {
-            s->fifo_buffer[n] = sd_read_data(s->card);
-        }
-        dma_memory_write(&dma_context_memory, s->sdmasysad, s->fifo_buffer,
-                         datacnt);
-    } else {
-        dma_memory_read(&dma_context_memory, s->sdmasysad, s->fifo_buffer,
-                        datacnt);
-        for (n = 0; n < datacnt; n++) {
-            sd_write_data(s->card, s->fifo_buffer[n]);
-        }
-    }
-
-    if (s->trnmod & SDHC_TRNS_BLK_CNT_EN) {
-        s->blkcnt--;
-    }
-
-    SDHCI_GET_CLASS(s)->end_data_transfer(s);
-}
-
-typedef struct ADMADescr {
-    hwaddr addr;
-    uint16_t length;
-    uint8_t attr;
-    uint8_t incr;
-} ADMADescr;
-
-static void get_adma_description(SDHCIState *s, ADMADescr *dscr)
-{
-    uint32_t adma1 = 0;
-    uint64_t adma2 = 0;
-    hwaddr entry_addr = (hwaddr)s->admasysaddr;
-    switch (SDHC_DMA_TYPE(s->hostctl)) {
-    case SDHC_CTRL_ADMA2_32:
-        dma_memory_read(&dma_context_memory, entry_addr, (uint8_t *)&adma2,
-                        sizeof(adma2));
-        adma2 = le64_to_cpu(adma2);
-        /* The spec does not specify endianness of descriptor table.
-         * We currently assume that it is LE.
-         */
-        dscr->addr = (hwaddr)extract64(adma2, 32, 32) & ~0x3ull;
-        dscr->length = (uint16_t)extract64(adma2, 16, 16);
-        dscr->attr = (uint8_t)extract64(adma2, 0, 7);
-        dscr->incr = 8;
-        break;
-    case SDHC_CTRL_ADMA1_32:
-        dma_memory_read(&dma_context_memory, entry_addr, (uint8_t *)&adma1,
-                        sizeof(adma1));
-        adma1 = le32_to_cpu(adma1);
-        dscr->addr = (hwaddr)(adma1 & 0xFFFFF000);
-        dscr->attr = (uint8_t)extract32(adma1, 0, 7);
-        dscr->incr = 4;
-        if ((dscr->attr & SDHC_ADMA_ATTR_ACT_MASK) == SDHC_ADMA_ATTR_SET_LEN) {
-            dscr->length = (uint16_t)extract32(adma1, 12, 16);
-        } else {
-            dscr->length = 4096;
-        }
-        break;
-    case SDHC_CTRL_ADMA2_64:
-        dma_memory_read(&dma_context_memory, entry_addr,
-                        (uint8_t *)(&dscr->attr), 1);
-        dma_memory_read(&dma_context_memory, entry_addr + 2,
-                        (uint8_t *)(&dscr->length), 2);
-        dscr->length = le16_to_cpu(dscr->length);
-        dma_memory_read(&dma_context_memory, entry_addr + 4,
-                        (uint8_t *)(&dscr->addr), 8);
-        dscr->attr = le64_to_cpu(dscr->attr);
-        dscr->attr &= 0xfffffff8;
-        dscr->incr = 12;
-        break;
-    }
-}
-
-/* Advanced DMA data transfer */
-
-static void sdhci_do_adma(SDHCIState *s)
-{
-    unsigned int n, begin, length;
-    const uint16_t block_size = s->blksize & 0x0fff;
-    ADMADescr dscr;
-    int i;
-
-    for (i = 0; i < SDHC_ADMA_DESCS_PER_DELAY; ++i) {
-        s->admaerr &= ~SDHC_ADMAERR_LENGTH_MISMATCH;
-
-        get_adma_description(s, &dscr);
-        DPRINT_L2("ADMA loop: addr=" TARGET_FMT_plx ", len=%d, attr=%x\n",
-                dscr.addr, dscr.length, dscr.attr);
-
-        if ((dscr.attr & SDHC_ADMA_ATTR_VALID) == 0) {
-            /* Indicate that error occurred in ST_FDS state */
-            s->admaerr &= ~SDHC_ADMAERR_STATE_MASK;
-            s->admaerr |= SDHC_ADMAERR_STATE_ST_FDS;
-
-            /* Generate ADMA error interrupt */
-            if (s->errintstsen & SDHC_EISEN_ADMAERR) {
-                s->errintsts |= SDHC_EIS_ADMAERR;
-                s->norintsts |= SDHC_NIS_ERR;
-            }
-
-            sdhci_update_irq(s);
-            return;
-        }
-
-        length = dscr.length ? dscr.length : 65536;
-
-        switch (dscr.attr & SDHC_ADMA_ATTR_ACT_MASK) {
-        case SDHC_ADMA_ATTR_ACT_TRAN:  /* data transfer */
-
-            if (s->trnmod & SDHC_TRNS_READ) {
-                while (length) {
-                    if (s->data_count == 0) {
-                        for (n = 0; n < block_size; n++) {
-                            s->fifo_buffer[n] = sd_read_data(s->card);
-                        }
-                    }
-                    begin = s->data_count;
-                    if ((length + begin) < block_size) {
-                        s->data_count = length + begin;
-                        length = 0;
-                     } else {
-                        s->data_count = block_size;
-                        length -= block_size - begin;
-                    }
-                    dma_memory_write(&dma_context_memory, dscr.addr,
-                                     &s->fifo_buffer[begin],
-                                     s->data_count - begin);
-                    dscr.addr += s->data_count - begin;
-                    if (s->data_count == block_size) {
-                        s->data_count = 0;
-                        if (s->trnmod & SDHC_TRNS_BLK_CNT_EN) {
-                            s->blkcnt--;
-                            if (s->blkcnt == 0) {
-                                break;
-                            }
-                        }
-                    }
-                }
-            } else {
-                while (length) {
-                    begin = s->data_count;
-                    if ((length + begin) < block_size) {
-                        s->data_count = length + begin;
-                        length = 0;
-                     } else {
-                        s->data_count = block_size;
-                        length -= block_size - begin;
-                    }
-                    dma_memory_read(&dma_context_memory, dscr.addr,
-                                    &s->fifo_buffer[begin], s->data_count);
-                    dscr.addr += s->data_count - begin;
-                    if (s->data_count == block_size) {
-                        for (n = 0; n < block_size; n++) {
-                            sd_write_data(s->card, s->fifo_buffer[n]);
-                        }
-                        s->data_count = 0;
-                        if (s->trnmod & SDHC_TRNS_BLK_CNT_EN) {
-                            s->blkcnt--;
-                            if (s->blkcnt == 0) {
-                                break;
-                            }
-                        }
-                    }
-                }
-            }
-            s->admasysaddr += dscr.incr;
-            break;
-        case SDHC_ADMA_ATTR_ACT_LINK:   /* link to next descriptor table */
-            s->admasysaddr = dscr.addr;
-            DPRINT_L1("ADMA link: admasysaddr=0x%lx\n", s->admasysaddr);
-            break;
-        default:
-            s->admasysaddr += dscr.incr;
-            break;
-        }
-
-        /* ADMA transfer terminates if blkcnt == 0 or by END attribute */
-        if (((s->trnmod & SDHC_TRNS_BLK_CNT_EN) &&
-                    (s->blkcnt == 0)) || (dscr.attr & SDHC_ADMA_ATTR_END)) {
-            DPRINT_L2("ADMA transfer completed\n");
-            if (length || ((dscr.attr & SDHC_ADMA_ATTR_END) &&
-                (s->trnmod & SDHC_TRNS_BLK_CNT_EN) &&
-                s->blkcnt != 0)) {
-                ERRPRINT("SD/MMC host ADMA length mismatch\n");
-                s->admaerr |= SDHC_ADMAERR_LENGTH_MISMATCH |
-                        SDHC_ADMAERR_STATE_ST_TFR;
-                if (s->errintstsen & SDHC_EISEN_ADMAERR) {
-                    ERRPRINT("Set ADMA error flag\n");
-                    s->errintsts |= SDHC_EIS_ADMAERR;
-                    s->norintsts |= SDHC_NIS_ERR;
-                }
-
-                sdhci_update_irq(s);
-            }
-            SDHCI_GET_CLASS(s)->end_data_transfer(s);
-            return;
-        }
-
-        if (dscr.attr & SDHC_ADMA_ATTR_INT) {
-            DPRINT_L1("ADMA interrupt: admasysaddr=0x%lx\n", s->admasysaddr);
-            if (s->norintstsen & SDHC_NISEN_DMA) {
-                s->norintsts |= SDHC_NIS_DMA;
-            }
-
-            sdhci_update_irq(s);
-            return;
-        }
-    }
-
-    /* we have unfinished business - reschedule to continue ADMA */
-    qemu_mod_timer(s->transfer_timer,
-                   qemu_get_clock_ns(vm_clock) + SDHC_TRANSFER_DELAY);
-}
-
-/* Perform data transfer according to controller configuration */
-
-static void sdhci_data_transfer(SDHCIState *s)
-{
-    SDHCIClass *k = SDHCI_GET_CLASS(s);
-    s->data_count = 0;
-
-    if (s->trnmod & SDHC_TRNS_DMA) {
-        switch (SDHC_DMA_TYPE(s->hostctl)) {
-        case SDHC_CTRL_SDMA:
-            if ((s->trnmod & SDHC_TRNS_MULTI) &&
-                    (!(s->trnmod & SDHC_TRNS_BLK_CNT_EN) || s->blkcnt == 0)) {
-                break;
-            }
-
-            if ((s->blkcnt == 1) || !(s->trnmod & SDHC_TRNS_MULTI)) {
-                k->do_sdma_single(s);
-            } else {
-                k->do_sdma_multi(s);
-            }
-
-            break;
-        case SDHC_CTRL_ADMA1_32:
-            if (!(s->capareg & SDHC_CAN_DO_ADMA1)) {
-                ERRPRINT("ADMA1 not supported\n");
-                break;
-            }
-
-            k->do_adma(s);
-            break;
-        case SDHC_CTRL_ADMA2_32:
-            if (!(s->capareg & SDHC_CAN_DO_ADMA2)) {
-                ERRPRINT("ADMA2 not supported\n");
-                break;
-            }
-
-            k->do_adma(s);
-            break;
-        case SDHC_CTRL_ADMA2_64:
-            if (!(s->capareg & SDHC_CAN_DO_ADMA2) ||
-                    !(s->capareg & SDHC_64_BIT_BUS_SUPPORT)) {
-                ERRPRINT("64 bit ADMA not supported\n");
-                break;
-            }
-
-            k->do_adma(s);
-            break;
-        default:
-            ERRPRINT("Unsupported DMA type\n");
-            break;
-        }
-    } else {
-        if ((s->trnmod & SDHC_TRNS_READ) && sd_data_ready(s->card)) {
-            s->prnsts |= SDHC_DOING_READ | SDHC_DATA_INHIBIT |
-                    SDHC_DAT_LINE_ACTIVE;
-            SDHCI_GET_CLASS(s)->read_block_from_card(s);
-        } else {
-            s->prnsts |= SDHC_DOING_WRITE | SDHC_DAT_LINE_ACTIVE |
-                    SDHC_SPACE_AVAILABLE | SDHC_DATA_INHIBIT;
-            SDHCI_GET_CLASS(s)->write_block_to_card(s);
-        }
-    }
-}
-
-static bool sdhci_can_issue_command(SDHCIState *s)
-{
-    if (!SDHC_CLOCK_IS_ON(s->clkcon) || !(s->pwrcon & SDHC_POWER_ON) ||
-        (((s->prnsts & SDHC_DATA_INHIBIT) || s->stopped_state) &&
-        ((s->cmdreg & SDHC_CMD_DATA_PRESENT) ||
-        ((s->cmdreg & SDHC_CMD_RESPONSE) == SDHC_CMD_RSP_WITH_BUSY &&
-        !(SDHC_COMMAND_TYPE(s->cmdreg) == SDHC_CMD_ABORT))))) {
-        return false;
-    }
-
-    return true;
-}
-
-/* The Buffer Data Port register must be accessed in sequential and
- * continuous manner */
-static inline bool
-sdhci_buff_access_is_sequential(SDHCIState *s, unsigned byte_num)
-{
-    if ((s->data_count & 0x3) != byte_num) {
-        ERRPRINT("Non-sequential access to Buffer Data Port register"
-                "is prohibited\n");
-        return false;
-    }
-    return true;
-}
-
-static uint32_t sdhci_read(SDHCIState *s, unsigned int offset, unsigned size)
-{
-    uint32_t ret = 0;
-
-    switch (offset & ~0x3) {
-    case SDHC_SYSAD:
-        ret = s->sdmasysad;
-        break;
-    case SDHC_BLKSIZE:
-        ret = s->blksize | (s->blkcnt << 16);
-        break;
-    case SDHC_ARGUMENT:
-        ret = s->argument;
-        break;
-    case SDHC_TRNMOD:
-        ret = s->trnmod | (s->cmdreg << 16);
-        break;
-    case SDHC_RSPREG0 ... SDHC_RSPREG3:
-        ret = s->rspreg[((offset & ~0x3) - SDHC_RSPREG0) >> 2];
-        break;
-    case  SDHC_BDATA:
-        if (sdhci_buff_access_is_sequential(s, offset - SDHC_BDATA)) {
-            ret = SDHCI_GET_CLASS(s)->bdata_read(s, size);
-            DPRINT_L2("read %ub: addr[0x%04x] -> %u\n", size, offset, ret);
-            return ret;
-        }
-        break;
-    case SDHC_PRNSTS:
-        ret = s->prnsts;
-        break;
-    case SDHC_HOSTCTL:
-        ret = s->hostctl | (s->pwrcon << 8) | (s->blkgap << 16) |
-              (s->wakcon << 24);
-        break;
-    case SDHC_CLKCON:
-        ret = s->clkcon | (s->timeoutcon << 16);
-        break;
-    case SDHC_NORINTSTS:
-        ret = s->norintsts | (s->errintsts << 16);
-        break;
-    case SDHC_NORINTSTSEN:
-        ret = s->norintstsen | (s->errintstsen << 16);
-        break;
-    case SDHC_NORINTSIGEN:
-        ret = s->norintsigen | (s->errintsigen << 16);
-        break;
-    case SDHC_ACMD12ERRSTS:
-        ret = s->acmd12errsts;
-        break;
-    case SDHC_CAPAREG:
-        ret = s->capareg;
-        break;
-    case SDHC_MAXCURR:
-        ret = s->maxcurr;
-        break;
-    case SDHC_ADMAERR:
-        ret =  s->admaerr;
-        break;
-    case SDHC_ADMASYSADDR:
-        ret = (uint32_t)s->admasysaddr;
-        break;
-    case SDHC_ADMASYSADDR + 4:
-        ret = (uint32_t)(s->admasysaddr >> 32);
-        break;
-    case SDHC_SLOT_INT_STATUS:
-        ret = (SD_HOST_SPECv2_VERS << 16) | sdhci_slotint(s);
-        break;
-    default:
-        ERRPRINT("bad %ub read: addr[0x%04x]\n", size, offset);
-        break;
-    }
-
-    ret >>= (offset & 0x3) * 8;
-    ret &= (1ULL << (size * 8)) - 1;
-    DPRINT_L2("read %ub: addr[0x%04x] -> %u(0x%x)\n", size, offset, ret, ret);
-    return ret;
-}
-
-static inline void sdhci_blkgap_write(SDHCIState *s, uint8_t value)
-{
-    if ((value & SDHC_STOP_AT_GAP_REQ) && (s->blkgap & SDHC_STOP_AT_GAP_REQ)) {
-        return;
-    }
-    s->blkgap = value & SDHC_STOP_AT_GAP_REQ;
-
-    if ((value & SDHC_CONTINUE_REQ) && s->stopped_state &&
-            (s->blkgap & SDHC_STOP_AT_GAP_REQ) == 0) {
-        if (s->stopped_state == sdhc_gap_read) {
-            s->prnsts |= SDHC_DAT_LINE_ACTIVE | SDHC_DOING_READ;
-            SDHCI_GET_CLASS(s)->read_block_from_card(s);
-        } else {
-            s->prnsts |= SDHC_DAT_LINE_ACTIVE | SDHC_DOING_WRITE;
-            SDHCI_GET_CLASS(s)->write_block_to_card(s);
-        }
-        s->stopped_state = sdhc_not_stopped;
-    } else if (!s->stopped_state && (value & SDHC_STOP_AT_GAP_REQ)) {
-        if (s->prnsts & SDHC_DOING_READ) {
-            s->stopped_state = sdhc_gap_read;
-        } else if (s->prnsts & SDHC_DOING_WRITE) {
-            s->stopped_state = sdhc_gap_write;
-        }
-    }
-}
-
-static inline void sdhci_reset_write(SDHCIState *s, uint8_t value)
-{
-    switch (value) {
-    case SDHC_RESET_ALL:
-        DEVICE_GET_CLASS(s)->reset(DEVICE(s));
-        break;
-    case SDHC_RESET_CMD:
-        s->prnsts &= ~SDHC_CMD_INHIBIT;
-        s->norintsts &= ~SDHC_NIS_CMDCMP;
-        break;
-    case SDHC_RESET_DATA:
-        s->data_count = 0;
-        s->prnsts &= ~(SDHC_SPACE_AVAILABLE | SDHC_DATA_AVAILABLE |
-                SDHC_DOING_READ | SDHC_DOING_WRITE |
-                SDHC_DATA_INHIBIT | SDHC_DAT_LINE_ACTIVE);
-        s->blkgap &= ~(SDHC_STOP_AT_GAP_REQ | SDHC_CONTINUE_REQ);
-        s->stopped_state = sdhc_not_stopped;
-        s->norintsts &= ~(SDHC_NIS_WBUFRDY | SDHC_NIS_RBUFRDY |
-                SDHC_NIS_DMA | SDHC_NIS_TRSCMP | SDHC_NIS_BLKGAP);
-        break;
-    }
-}
-
-static void
-sdhci_write(SDHCIState *s, unsigned int offset, uint32_t value, unsigned size)
-{
-    unsigned shift =  8 * (offset & 0x3);
-    uint32_t mask = ~(((1ULL << (size * 8)) - 1) << shift);
-    value <<= shift;
-
-    switch (offset & ~0x3) {
-    case SDHC_SYSAD:
-        s->sdmasysad = (s->sdmasysad & mask) | value;
-        MASKED_WRITE(s->sdmasysad, mask, value);
-        /* Writing to last byte of sdmasysad might trigger transfer */
-        if (!(mask & 0xFF000000) && TRANSFERRING_DATA(s->prnsts) && s->blkcnt &&
-                s->blksize && SDHC_DMA_TYPE(s->hostctl) == SDHC_CTRL_SDMA) {
-            SDHCI_GET_CLASS(s)->do_sdma_multi(s);
-        }
-        break;
-    case SDHC_BLKSIZE:
-        if (!TRANSFERRING_DATA(s->prnsts)) {
-            MASKED_WRITE(s->blksize, mask, value);
-            MASKED_WRITE(s->blkcnt, mask >> 16, value >> 16);
-        }
-        break;
-    case SDHC_ARGUMENT:
-        MASKED_WRITE(s->argument, mask, value);
-        break;
-    case SDHC_TRNMOD:
-        /* DMA can be enabled only if it is supported as indicated by
-         * capabilities register */
-        if (!(s->capareg & SDHC_CAN_DO_DMA)) {
-            value &= ~SDHC_TRNS_DMA;
-        }
-        MASKED_WRITE(s->trnmod, mask, value);
-        MASKED_WRITE(s->cmdreg, mask >> 16, value >> 16);
-
-        /* Writing to the upper byte of CMDREG triggers SD command generation */
-        if ((mask & 0xFF000000) || !SDHCI_GET_CLASS(s)->can_issue_command(s)) {
-            break;
-        }
-
-        SDHCI_GET_CLASS(s)->send_command(s);
-        break;
-    case  SDHC_BDATA:
-        if (sdhci_buff_access_is_sequential(s, offset - SDHC_BDATA)) {
-            SDHCI_GET_CLASS(s)->bdata_write(s, value >> shift, size);
-        }
-        break;
-    case SDHC_HOSTCTL:
-        if (!(mask & 0xFF0000)) {
-            sdhci_blkgap_write(s, value >> 16);
-        }
-        MASKED_WRITE(s->hostctl, mask, value);
-        MASKED_WRITE(s->pwrcon, mask >> 8, value >> 8);
-        MASKED_WRITE(s->wakcon, mask >> 24, value >> 24);
-        if (!(s->prnsts & SDHC_CARD_PRESENT) || ((s->pwrcon >> 1) & 0x7) < 5 ||
-                !(s->capareg & (1 << (31 - ((s->pwrcon >> 1) & 0x7))))) {
-            s->pwrcon &= ~SDHC_POWER_ON;
-        }
-        break;
-    case SDHC_CLKCON:
-        if (!(mask & 0xFF000000)) {
-            sdhci_reset_write(s, value >> 24);
-        }
-        MASKED_WRITE(s->clkcon, mask, value);
-        MASKED_WRITE(s->timeoutcon, mask >> 16, value >> 16);
-        if (s->clkcon & SDHC_CLOCK_INT_EN) {
-            s->clkcon |= SDHC_CLOCK_INT_STABLE;
-        } else {
-            s->clkcon &= ~SDHC_CLOCK_INT_STABLE;
-        }
-        break;
-    case SDHC_NORINTSTS:
-        if (s->norintstsen & SDHC_NISEN_CARDINT) {
-            value &= ~SDHC_NIS_CARDINT;
-        }
-        s->norintsts &= mask | ~value;
-        s->errintsts &= (mask >> 16) | ~(value >> 16);
-        if (s->errintsts) {
-            s->norintsts |= SDHC_NIS_ERR;
-        } else {
-            s->norintsts &= ~SDHC_NIS_ERR;
-        }
-        sdhci_update_irq(s);
-        break;
-    case SDHC_NORINTSTSEN:
-        MASKED_WRITE(s->norintstsen, mask, value);
-        MASKED_WRITE(s->errintstsen, mask >> 16, value >> 16);
-        s->norintsts &= s->norintstsen;
-        s->errintsts &= s->errintstsen;
-        if (s->errintsts) {
-            s->norintsts |= SDHC_NIS_ERR;
-        } else {
-            s->norintsts &= ~SDHC_NIS_ERR;
-        }
-        sdhci_update_irq(s);
-        break;
-    case SDHC_NORINTSIGEN:
-        MASKED_WRITE(s->norintsigen, mask, value);
-        MASKED_WRITE(s->errintsigen, mask >> 16, value >> 16);
-        sdhci_update_irq(s);
-        break;
-    case SDHC_ADMAERR:
-        MASKED_WRITE(s->admaerr, mask, value);
-        break;
-    case SDHC_ADMASYSADDR:
-        s->admasysaddr = (s->admasysaddr & (0xFFFFFFFF00000000ULL |
-                (uint64_t)mask)) | (uint64_t)value;
-        break;
-    case SDHC_ADMASYSADDR + 4:
-        s->admasysaddr = (s->admasysaddr & (0x00000000FFFFFFFFULL |
-                ((uint64_t)mask << 32))) | ((uint64_t)value << 32);
-        break;
-    case SDHC_FEAER:
-        s->acmd12errsts |= value;
-        s->errintsts |= (value >> 16) & s->errintstsen;
-        if (s->acmd12errsts) {
-            s->errintsts |= SDHC_EIS_CMD12ERR;
-        }
-        if (s->errintsts) {
-            s->norintsts |= SDHC_NIS_ERR;
-        }
-        sdhci_update_irq(s);
-        break;
-    default:
-        ERRPRINT("bad %ub write offset: addr[0x%04x] <- %u(0x%x)\n",
-                size, offset, value >> shift, value >> shift);
-        break;
-    }
-    DPRINT_L2("write %ub: addr[0x%04x] <- %u(0x%x)\n",
-            size, offset, value >> shift, value >> shift);
-}
-
-static uint64_t
-sdhci_readfn(void *opaque, hwaddr offset, unsigned size)
-{
-    SDHCIState *s = (SDHCIState *)opaque;
-
-    return SDHCI_GET_CLASS(s)->mem_read(s, offset, size);
-}
-
-static void
-sdhci_writefn(void *opaque, hwaddr off, uint64_t val, unsigned sz)
-{
-    SDHCIState *s = (SDHCIState *)opaque;
-
-    SDHCI_GET_CLASS(s)->mem_write(s, off, val, sz);
-}
-
-static const MemoryRegionOps sdhci_mmio_ops = {
-    .read = sdhci_readfn,
-    .write = sdhci_writefn,
-    .valid = {
-        .min_access_size = 1,
-        .max_access_size = 4,
-        .unaligned = false
-    },
-    .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static inline unsigned int sdhci_get_fifolen(SDHCIState *s)
-{
-    switch (SDHC_CAPAB_BLOCKSIZE(s->capareg)) {
-    case 0:
-        return 512;
-    case 1:
-        return 1024;
-    case 2:
-        return 2048;
-    default:
-        hw_error("SDHC: unsupported value for maximum block size\n");
-        return 0;
-    }
-}
-
-static void sdhci_initfn(Object *obj)
-{
-    SDHCIState *s = SDHCI(obj);
-    DriveInfo *di;
-
-    di = drive_get_next(IF_SD);
-    s->card = sd_init(di ? di->bdrv : NULL, 0);
-    s->eject_cb = qemu_allocate_irqs(sdhci_insert_eject_cb, s, 1)[0];
-    s->ro_cb = qemu_allocate_irqs(sdhci_card_readonly_cb, s, 1)[0];
-    sd_set_cb(s->card, s->ro_cb, s->eject_cb);
-
-    s->insert_timer = qemu_new_timer_ns(vm_clock, sdhci_raise_insertion_irq, s);
-    s->transfer_timer = qemu_new_timer_ns(vm_clock, sdhci_do_data_transfer, s);
-}
-
-static void sdhci_uninitfn(Object *obj)
-{
-    SDHCIState *s = SDHCI(obj);
-
-    qemu_del_timer(s->insert_timer);
-    qemu_free_timer(s->insert_timer);
-    qemu_del_timer(s->transfer_timer);
-    qemu_free_timer(s->transfer_timer);
-    qemu_free_irqs(&s->eject_cb);
-    qemu_free_irqs(&s->ro_cb);
-
-    if (s->fifo_buffer) {
-        g_free(s->fifo_buffer);
-        s->fifo_buffer = NULL;
-    }
-}
-
-const VMStateDescription sdhci_vmstate = {
-    .name = "sdhci",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .fields      = (VMStateField[]) {
-        VMSTATE_UINT32(sdmasysad, SDHCIState),
-        VMSTATE_UINT16(blksize, SDHCIState),
-        VMSTATE_UINT16(blkcnt, SDHCIState),
-        VMSTATE_UINT32(argument, SDHCIState),
-        VMSTATE_UINT16(trnmod, SDHCIState),
-        VMSTATE_UINT16(cmdreg, SDHCIState),
-        VMSTATE_UINT32_ARRAY(rspreg, SDHCIState, 4),
-        VMSTATE_UINT32(prnsts, SDHCIState),
-        VMSTATE_UINT8(hostctl, SDHCIState),
-        VMSTATE_UINT8(pwrcon, SDHCIState),
-        VMSTATE_UINT8(blkgap, SDHCIState),
-        VMSTATE_UINT8(wakcon, SDHCIState),
-        VMSTATE_UINT16(clkcon, SDHCIState),
-        VMSTATE_UINT8(timeoutcon, SDHCIState),
-        VMSTATE_UINT8(admaerr, SDHCIState),
-        VMSTATE_UINT16(norintsts, SDHCIState),
-        VMSTATE_UINT16(errintsts, SDHCIState),
-        VMSTATE_UINT16(norintstsen, SDHCIState),
-        VMSTATE_UINT16(errintstsen, SDHCIState),
-        VMSTATE_UINT16(norintsigen, SDHCIState),
-        VMSTATE_UINT16(errintsigen, SDHCIState),
-        VMSTATE_UINT16(acmd12errsts, SDHCIState),
-        VMSTATE_UINT16(data_count, SDHCIState),
-        VMSTATE_UINT64(admasysaddr, SDHCIState),
-        VMSTATE_UINT8(stopped_state, SDHCIState),
-        VMSTATE_VBUFFER_UINT32(fifo_buffer, SDHCIState, 1, NULL, 0, buf_maxsz),
-        VMSTATE_TIMER(insert_timer, SDHCIState),
-        VMSTATE_TIMER(transfer_timer, SDHCIState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-/* Capabilities registers provide information on supported features of this
- * specific host controller implementation */
-static Property sdhci_properties[] = {
-    DEFINE_PROP_HEX32("capareg", SDHCIState, capareg,
-            SDHC_CAPAB_REG_DEFAULT),
-    DEFINE_PROP_HEX32("maxcurr", SDHCIState, maxcurr, 0),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void sdhci_realize(DeviceState *dev, Error ** errp)
-{
-    SDHCIState *s = SDHCI(dev);
-    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
-
-    s->buf_maxsz = sdhci_get_fifolen(s);
-    s->fifo_buffer = g_malloc0(s->buf_maxsz);
-    sysbus_init_irq(sbd, &s->irq);
-    memory_region_init_io(&s->iomem, &sdhci_mmio_ops, s, "sdhci",
-            SDHC_REGISTERS_MAP_SIZE);
-    sysbus_init_mmio(sbd, &s->iomem);
-}
-
-static void sdhci_generic_reset(DeviceState *ds)
-{
-    SDHCIState *s = SDHCI(ds);
-    SDHCI_GET_CLASS(s)->reset(s);
-}
-
-static void sdhci_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SDHCIClass *k = SDHCI_CLASS(klass);
-
-    dc->vmsd = &sdhci_vmstate;
-    dc->props = sdhci_properties;
-    dc->reset = sdhci_generic_reset;
-    dc->realize = sdhci_realize;
-
-    k->reset = sdhci_reset;
-    k->mem_read = sdhci_read;
-    k->mem_write = sdhci_write;
-    k->send_command = sdhci_send_command;
-    k->can_issue_command = sdhci_can_issue_command;
-    k->data_transfer = sdhci_data_transfer;
-    k->end_data_transfer = sdhci_end_transfer;
-    k->do_sdma_single = sdhci_sdma_transfer_single_block;
-    k->do_sdma_multi = sdhci_sdma_transfer_multi_blocks;
-    k->do_adma = sdhci_do_adma;
-    k->read_block_from_card = sdhci_read_block_from_card;
-    k->write_block_to_card = sdhci_write_block_to_card;
-    k->bdata_read = sdhci_read_dataport;
-    k->bdata_write = sdhci_write_dataport;
-}
-
-static const TypeInfo sdhci_type_info = {
-    .name = TYPE_SDHCI,
-    .parent = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(SDHCIState),
-    .instance_init = sdhci_initfn,
-    .instance_finalize = sdhci_uninitfn,
-    .class_init = sdhci_class_init,
-    .class_size = sizeof(SDHCIClass)
-};
-
-static void sdhci_register_types(void)
-{
-    type_register_static(&sdhci_type_info);
-}
-
-type_init(sdhci_register_types)
diff --git a/hw/sdhci.h b/hw/sdhci.h
deleted file mode 100644 (file)
index a560c3c..0000000
+++ /dev/null
@@ -1,312 +0,0 @@
-/*
- * SD Association Host Standard Specification v2.0 controller emulation
- *
- * Copyright (c) 2011 Samsung Electronics Co., Ltd.
- * Mitsyanko Igor <i.mitsyanko@samsung.com>
- * Peter A.G. Crosthwaite <peter.crosthwaite@petalogix.com>
- *
- * Based on MMC controller for Samsung S5PC1xx-based board emulation
- * by Alexey Merkulov and Vladimir Monakhov.
- *
- * 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 SDHCI_H
-#define SDHCI_H
-
-#include "qemu-common.h"
-#include "hw/sysbus.h"
-#include "hw/sd.h"
-
-/* R/W SDMA System Address register 0x0 */
-#define SDHC_SYSAD                     0x00
-
-/* R/W Host DMA Buffer Boundary and Transfer Block Size Register 0x0 */
-#define SDHC_BLKSIZE                   0x04
-
-/* R/W Blocks count for current transfer 0x0 */
-#define SDHC_BLKCNT                    0x06
-
-/* R/W Command Argument Register 0x0 */
-#define SDHC_ARGUMENT                  0x08
-
-/* R/W Transfer Mode Setting Register 0x0 */
-#define SDHC_TRNMOD                    0x0C
-#define SDHC_TRNS_DMA                  0x0001
-#define SDHC_TRNS_BLK_CNT_EN           0x0002
-#define SDHC_TRNS_ACMD12               0x0004
-#define SDHC_TRNS_READ                 0x0010
-#define SDHC_TRNS_MULTI                0x0020
-
-/* R/W Command Register 0x0 */
-#define SDHC_CMDREG                    0x0E
-#define SDHC_CMD_RSP_WITH_BUSY         (3 << 0)
-#define SDHC_CMD_DATA_PRESENT          (1 << 5)
-#define SDHC_CMD_SUSPEND               (1 << 6)
-#define SDHC_CMD_RESUME                (1 << 7)
-#define SDHC_CMD_ABORT                 ((1 << 6)|(1 << 7))
-#define SDHC_CMD_TYPE_MASK             ((1 << 6)|(1 << 7))
-#define SDHC_COMMAND_TYPE(x)           ((x) & SDHC_CMD_TYPE_MASK)
-
-/* ROC Response Register 0 0x0 */
-#define SDHC_RSPREG0                   0x10
-/* ROC Response Register 1 0x0 */
-#define SDHC_RSPREG1                   0x14
-/* ROC Response Register 2 0x0 */
-#define SDHC_RSPREG2                   0x18
-/* ROC Response Register 3 0x0 */
-#define SDHC_RSPREG3                   0x1C
-
-/* R/W Buffer Data Register 0x0 */
-#define SDHC_BDATA                     0x20
-
-/* R/ROC Present State Register 0x000A0000 */
-#define SDHC_PRNSTS                    0x24
-#define SDHC_CMD_INHIBIT               0x00000001
-#define SDHC_DATA_INHIBIT              0x00000002
-#define SDHC_DAT_LINE_ACTIVE           0x00000004
-#define SDHC_DOING_WRITE               0x00000100
-#define SDHC_DOING_READ                0x00000200
-#define SDHC_SPACE_AVAILABLE           0x00000400
-#define SDHC_DATA_AVAILABLE            0x00000800
-#define SDHC_CARD_PRESENT              0x00010000
-#define SDHC_CARD_DETECT               0x00040000
-#define SDHC_WRITE_PROTECT             0x00080000
-#define TRANSFERRING_DATA(x)           \
-    ((x) & (SDHC_DOING_READ | SDHC_DOING_WRITE))
-
-/* R/W Host control Register 0x0 */
-#define SDHC_HOSTCTL                   0x28
-#define SDHC_CTRL_DMA_CHECK_MASK       0x18
-#define SDHC_CTRL_SDMA                 0x00
-#define SDHC_CTRL_ADMA1_32             0x08
-#define SDHC_CTRL_ADMA2_32             0x10
-#define SDHC_CTRL_ADMA2_64             0x18
-#define SDHC_DMA_TYPE(x)               ((x) & SDHC_CTRL_DMA_CHECK_MASK)
-
-/* R/W Power Control Register 0x0 */
-#define SDHC_PWRCON                    0x29
-#define SDHC_POWER_ON                  (1 << 0)
-
-/* R/W Block Gap Control Register 0x0 */
-#define SDHC_BLKGAP                    0x2A
-#define SDHC_STOP_AT_GAP_REQ           0x01
-#define SDHC_CONTINUE_REQ              0x02
-
-/* R/W WakeUp Control Register 0x0 */
-#define SDHC_WAKCON                    0x2B
-#define SDHC_WKUP_ON_INS               (1 << 1)
-#define SDHC_WKUP_ON_RMV               (1 << 2)
-
-/* CLKCON */
-#define SDHC_CLKCON                    0x2C
-#define SDHC_CLOCK_INT_STABLE          0x0002
-#define SDHC_CLOCK_INT_EN              0x0001
-#define SDHC_CLOCK_SDCLK_EN            (1 << 2)
-#define SDHC_CLOCK_CHK_MASK            0x0007
-#define SDHC_CLOCK_IS_ON(x)            \
-    (((x) & SDHC_CLOCK_CHK_MASK) == SDHC_CLOCK_CHK_MASK)
-
-/* R/W Timeout Control Register 0x0 */
-#define SDHC_TIMEOUTCON                0x2E
-
-/* R/W Software Reset Register 0x0 */
-#define SDHC_SWRST                     0x2F
-#define SDHC_RESET_ALL                 0x01
-#define SDHC_RESET_CMD                 0x02
-#define SDHC_RESET_DATA                0x04
-
-/* ROC/RW1C Normal Interrupt Status Register 0x0 */
-#define SDHC_NORINTSTS                 0x30
-#define SDHC_NIS_ERR                   0x8000
-#define SDHC_NIS_CMDCMP                0x0001
-#define SDHC_NIS_TRSCMP                0x0002
-#define SDHC_NIS_BLKGAP                0x0004
-#define SDHC_NIS_DMA                   0x0008
-#define SDHC_NIS_WBUFRDY               0x0010
-#define SDHC_NIS_RBUFRDY               0x0020
-#define SDHC_NIS_INSERT                0x0040
-#define SDHC_NIS_REMOVE                0x0080
-#define SDHC_NIS_CARDINT               0x0100
-
-/* ROC/RW1C Error Interrupt Status Register 0x0 */
-#define SDHC_ERRINTSTS                 0x32
-#define SDHC_EIS_CMDTIMEOUT            0x0001
-#define SDHC_EIS_BLKGAP                0x0004
-#define SDHC_EIS_CMDIDX                0x0008
-#define SDHC_EIS_CMD12ERR              0x0100
-#define SDHC_EIS_ADMAERR               0x0200
-
-/* R/W Normal Interrupt Status Enable Register 0x0 */
-#define SDHC_NORINTSTSEN               0x34
-#define SDHC_NISEN_CMDCMP              0x0001
-#define SDHC_NISEN_TRSCMP              0x0002
-#define SDHC_NISEN_DMA                 0x0008
-#define SDHC_NISEN_WBUFRDY             0x0010
-#define SDHC_NISEN_RBUFRDY             0x0020
-#define SDHC_NISEN_INSERT              0x0040
-#define SDHC_NISEN_REMOVE              0x0080
-#define SDHC_NISEN_CARDINT             0x0100
-
-/* R/W Error Interrupt Status Enable Register 0x0 */
-#define SDHC_ERRINTSTSEN               0x36
-#define SDHC_EISEN_CMDTIMEOUT          0x0001
-#define SDHC_EISEN_BLKGAP              0x0004
-#define SDHC_EISEN_CMDIDX              0x0008
-#define SDHC_EISEN_ADMAERR             0x0200
-
-/* R/W Normal Interrupt Signal Enable Register 0x0 */
-#define SDHC_NORINTSIGEN               0x38
-#define SDHC_NORINTSIG_INSERT          (1 << 6)
-#define SDHC_NORINTSIG_REMOVE          (1 << 7)
-
-/* R/W Error Interrupt Signal Enable Register 0x0 */
-#define SDHC_ERRINTSIGEN               0x3A
-
-/* ROC Auto CMD12 error status register 0x0 */
-#define SDHC_ACMD12ERRSTS              0x3C
-
-/* HWInit Capabilities Register 0x05E80080 */
-#define SDHC_CAPAREG                   0x40
-#define SDHC_CAN_DO_DMA                0x00400000
-#define SDHC_CAN_DO_ADMA2              0x00080000
-#define SDHC_CAN_DO_ADMA1              0x00100000
-#define SDHC_64_BIT_BUS_SUPPORT        (1 << 28)
-#define SDHC_CAPAB_BLOCKSIZE(x)        (((x) >> 16) & 0x3)
-
-/* HWInit Maximum Current Capabilities Register 0x0 */
-#define SDHC_MAXCURR                   0x48
-
-/* W Force Event Auto CMD12 Error Interrupt Register 0x0000 */
-#define SDHC_FEAER                     0x50
-/* W Force Event Error Interrupt Register Error Interrupt 0x0000 */
-#define SDHC_FEERR                     0x52
-
-/* R/W ADMA Error Status Register 0x00 */
-#define SDHC_ADMAERR                   0x54
-#define SDHC_ADMAERR_LENGTH_MISMATCH   (1 << 2)
-#define SDHC_ADMAERR_STATE_ST_STOP     (0 << 0)
-#define SDHC_ADMAERR_STATE_ST_FDS      (1 << 0)
-#define SDHC_ADMAERR_STATE_ST_TFR      (3 << 0)
-#define SDHC_ADMAERR_STATE_MASK        (3 << 0)
-
-/* R/W ADMA System Address Register 0x00 */
-#define SDHC_ADMASYSADDR               0x58
-#define SDHC_ADMA_ATTR_SET_LEN         (1 << 4)
-#define SDHC_ADMA_ATTR_ACT_TRAN        (1 << 5)
-#define SDHC_ADMA_ATTR_ACT_LINK        (3 << 4)
-#define SDHC_ADMA_ATTR_INT             (1 << 2)
-#define SDHC_ADMA_ATTR_END             (1 << 1)
-#define SDHC_ADMA_ATTR_VALID           (1 << 0)
-#define SDHC_ADMA_ATTR_ACT_MASK        ((1 << 4)|(1 << 5))
-
-/* Slot interrupt status */
-#define SDHC_SLOT_INT_STATUS            0xFC
-
-/* HWInit Host Controller Version Register 0x0401 */
-#define SDHC_HCVER                      0xFE
-#define SD_HOST_SPECv2_VERS             0x2401
-
-#define SDHC_REGISTERS_MAP_SIZE         0x100
-#define SDHC_INSERTION_DELAY            (get_ticks_per_sec())
-#define SDHC_TRANSFER_DELAY             100
-#define SDHC_ADMA_DESCS_PER_DELAY       5
-#define SDHC_CMD_RESPONSE               (3 << 0)
-
-enum {
-    sdhc_not_stopped = 0, /* normal SDHC state */
-    sdhc_gap_read   = 1,  /* SDHC stopped at block gap during read operation */
-    sdhc_gap_write  = 2   /* SDHC stopped at block gap during write operation */
-};
-
-/* SD/MMC host controller state */
-typedef struct SDHCIState {
-    SysBusDevice busdev;
-    SDState *card;
-    MemoryRegion iomem;
-
-    QEMUTimer *insert_timer;       /* timer for 'changing' sd card. */
-    QEMUTimer *transfer_timer;
-    qemu_irq eject_cb;
-    qemu_irq ro_cb;
-    qemu_irq irq;
-
-    uint32_t sdmasysad;    /* SDMA System Address register */
-    uint16_t blksize;      /* Host DMA Buff Boundary and Transfer BlkSize Reg */
-    uint16_t blkcnt;       /* Blocks count for current transfer */
-    uint32_t argument;     /* Command Argument Register */
-    uint16_t trnmod;       /* Transfer Mode Setting Register */
-    uint16_t cmdreg;       /* Command Register */
-    uint32_t rspreg[4];    /* Response Registers 0-3 */
-    uint32_t prnsts;       /* Present State Register */
-    uint8_t  hostctl;      /* Host Control Register */
-    uint8_t  pwrcon;       /* Power control Register */
-    uint8_t  blkgap;       /* Block Gap Control Register */
-    uint8_t  wakcon;       /* WakeUp Control Register */
-    uint16_t clkcon;       /* Clock control Register */
-    uint8_t  timeoutcon;   /* Timeout Control Register */
-    uint8_t  admaerr;      /* ADMA Error Status Register */
-    uint16_t norintsts;    /* Normal Interrupt Status Register */
-    uint16_t errintsts;    /* Error Interrupt Status Register */
-    uint16_t norintstsen;  /* Normal Interrupt Status Enable Register */
-    uint16_t errintstsen;  /* Error Interrupt Status Enable Register */
-    uint16_t norintsigen;  /* Normal Interrupt Signal Enable Register */
-    uint16_t errintsigen;  /* Error Interrupt Signal Enable Register */
-    uint16_t acmd12errsts; /* Auto CMD12 error status register */
-    uint64_t admasysaddr;  /* ADMA System Address Register */
-
-    uint32_t capareg;      /* Capabilities Register */
-    uint32_t maxcurr;      /* Maximum Current Capabilities Register */
-    uint8_t  *fifo_buffer; /* SD host i/o FIFO buffer */
-    uint32_t buf_maxsz;
-    uint16_t data_count;   /* current element in FIFO buffer */
-    uint8_t  stopped_state;/* Current SDHC state */
-    /* Buffer Data Port Register - virtual access point to R and W buffers */
-    /* Software Reset Register - always reads as 0 */
-    /* Force Event Auto CMD12 Error Interrupt Reg - write only */
-    /* Force Event Error Interrupt Register- write only */
-    /* RO Host Controller Version Register always reads as 0x2401 */
-} SDHCIState;
-
-typedef struct SDHCIClass {
-    SysBusDeviceClass busdev_class;
-
-    void (*reset)(SDHCIState *s);
-    uint32_t (*mem_read)(SDHCIState *s, unsigned int offset, unsigned size);
-    void (*mem_write)(SDHCIState *s, unsigned int offset, uint32_t value,
-            unsigned size);
-    void (*send_command)(SDHCIState *s);
-    bool (*can_issue_command)(SDHCIState *s);
-    void (*data_transfer)(SDHCIState *s);
-    void (*end_data_transfer)(SDHCIState *s);
-    void (*do_sdma_single)(SDHCIState *s);
-    void (*do_sdma_multi)(SDHCIState *s);
-    void (*do_adma)(SDHCIState *s);
-    void (*read_block_from_card)(SDHCIState *s);
-    void (*write_block_to_card)(SDHCIState *s);
-    uint32_t (*bdata_read)(SDHCIState *s, unsigned size);
-    void (*bdata_write)(SDHCIState *s, uint32_t value, unsigned size);
-} SDHCIClass;
-
-extern const VMStateDescription sdhci_vmstate;
-
-#define TYPE_SDHCI            "generic-sdhci"
-#define SDHCI(obj)            \
-     OBJECT_CHECK(SDHCIState, (obj), TYPE_SDHCI)
-#define SDHCI_CLASS(klass)    \
-     OBJECT_CLASS_CHECK(SDHCIClass, (klass), TYPE_SDHCI)
-#define SDHCI_GET_CLASS(obj)  \
-     OBJECT_GET_CLASS(SDHCIClass, (obj), TYPE_SDHCI)
-
-#endif /* SDHCI_H */
diff --git a/hw/serial-isa.c b/hw/serial-isa.c
deleted file mode 100644 (file)
index a630a7d..0000000
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * QEMU 16550A UART emulation
- *
- * Copyright (c) 2003-2004 Fabrice Bellard
- * Copyright (c) 2008 Citrix Systems, 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 "hw/serial.h"
-#include "hw/isa.h"
-
-typedef struct ISASerialState {
-    ISADevice dev;
-    uint32_t index;
-    uint32_t iobase;
-    uint32_t isairq;
-    SerialState state;
-} ISASerialState;
-
-static const int isa_serial_io[MAX_SERIAL_PORTS] = {
-    0x3f8, 0x2f8, 0x3e8, 0x2e8
-};
-static const int isa_serial_irq[MAX_SERIAL_PORTS] = {
-    4, 3, 4, 3
-};
-
-static int serial_isa_initfn(ISADevice *dev)
-{
-    static int index;
-    ISASerialState *isa = DO_UPCAST(ISASerialState, dev, dev);
-    SerialState *s = &isa->state;
-
-    if (isa->index == -1) {
-        isa->index = index;
-    }
-    if (isa->index >= MAX_SERIAL_PORTS) {
-        return -1;
-    }
-    if (isa->iobase == -1) {
-        isa->iobase = isa_serial_io[isa->index];
-    }
-    if (isa->isairq == -1) {
-        isa->isairq = isa_serial_irq[isa->index];
-    }
-    index++;
-
-    s->baudbase = 115200;
-    isa_init_irq(dev, &s->irq, isa->isairq);
-    serial_init_core(s);
-    qdev_set_legacy_instance_id(&dev->qdev, isa->iobase, 3);
-
-    memory_region_init_io(&s->io, &serial_io_ops, s, "serial", 8);
-    isa_register_ioport(dev, &s->io, isa->iobase);
-    return 0;
-}
-
-static const VMStateDescription vmstate_isa_serial = {
-    .name = "serial",
-    .version_id = 3,
-    .minimum_version_id = 2,
-    .fields = (VMStateField[]) {
-        VMSTATE_STRUCT(state, ISASerialState, 0, vmstate_serial, SerialState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static Property serial_isa_properties[] = {
-    DEFINE_PROP_UINT32("index",  ISASerialState, index,   -1),
-    DEFINE_PROP_HEX32("iobase",  ISASerialState, iobase,  -1),
-    DEFINE_PROP_UINT32("irq",    ISASerialState, isairq,  -1),
-    DEFINE_PROP_CHR("chardev",   ISASerialState, state.chr),
-    DEFINE_PROP_UINT32("wakeup", ISASerialState, state.wakeup, 0),
-    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 const 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_types(void)
-{
-    type_register_static(&serial_isa_info);
-}
-
-type_init(serial_register_types)
-
-bool serial_isa_init(ISABus *bus, int index, CharDriverState *chr)
-{
-    ISADevice *dev;
-
-    dev = isa_try_create(bus, "isa-serial");
-    if (!dev) {
-        return false;
-    }
-    qdev_prop_set_uint32(&dev->qdev, "index", index);
-    qdev_prop_set_chr(&dev->qdev, "chardev", chr);
-    if (qdev_init(&dev->qdev) < 0) {
-        return false;
-    }
-    return true;
-}
diff --git a/hw/serial-pci.c b/hw/serial-pci.c
deleted file mode 100644 (file)
index 954657b..0000000
+++ /dev/null
@@ -1,252 +0,0 @@
-/*
- * QEMU 16550A UART emulation
- *
- * Copyright (c) 2003-2004 Fabrice Bellard
- * Copyright (c) 2008 Citrix Systems, 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.
- */
-
-/* see docs/specs/pci-serial.txt */
-
-#include "hw/serial.h"
-#include "hw/pci/pci.h"
-
-#define PCI_SERIAL_MAX_PORTS 4
-
-typedef struct PCISerialState {
-    PCIDevice dev;
-    SerialState state;
-} PCISerialState;
-
-typedef struct PCIMultiSerialState {
-    PCIDevice    dev;
-    MemoryRegion iobar;
-    uint32_t     ports;
-    char         *name[PCI_SERIAL_MAX_PORTS];
-    SerialState  state[PCI_SERIAL_MAX_PORTS];
-    uint32_t     level[PCI_SERIAL_MAX_PORTS];
-    qemu_irq     *irqs;
-} PCIMultiSerialState;
-
-static int serial_pci_init(PCIDevice *dev)
-{
-    PCISerialState *pci = DO_UPCAST(PCISerialState, dev, dev);
-    SerialState *s = &pci->state;
-
-    s->baudbase = 115200;
-    serial_init_core(s);
-
-    pci->dev.config[PCI_INTERRUPT_PIN] = 0x01;
-    s->irq = pci->dev.irq[0];
-
-    memory_region_init_io(&s->io, &serial_io_ops, s, "serial", 8);
-    pci_register_bar(&pci->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io);
-    return 0;
-}
-
-static void multi_serial_irq_mux(void *opaque, int n, int level)
-{
-    PCIMultiSerialState *pci = opaque;
-    int i, pending = 0;
-
-    pci->level[n] = level;
-    for (i = 0; i < pci->ports; i++) {
-        if (pci->level[i]) {
-            pending = 1;
-        }
-    }
-    qemu_set_irq(pci->dev.irq[0], pending);
-}
-
-static int multi_serial_pci_init(PCIDevice *dev)
-{
-    PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev);
-    PCIMultiSerialState *pci = DO_UPCAST(PCIMultiSerialState, dev, dev);
-    SerialState *s;
-    int i;
-
-    switch (pc->device_id) {
-    case 0x0003:
-        pci->ports = 2;
-        break;
-    case 0x0004:
-        pci->ports = 4;
-        break;
-    }
-    assert(pci->ports > 0);
-    assert(pci->ports <= PCI_SERIAL_MAX_PORTS);
-
-    pci->dev.config[PCI_INTERRUPT_PIN] = 0x01;
-    memory_region_init(&pci->iobar, "multiserial", 8 * pci->ports);
-    pci_register_bar(&pci->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &pci->iobar);
-    pci->irqs = qemu_allocate_irqs(multi_serial_irq_mux, pci,
-                                   pci->ports);
-
-    for (i = 0; i < pci->ports; i++) {
-        s = pci->state + i;
-        s->baudbase = 115200;
-        serial_init_core(s);
-        s->irq = pci->irqs[i];
-        pci->name[i] = g_strdup_printf("uart #%d", i+1);
-        memory_region_init_io(&s->io, &serial_io_ops, s, pci->name[i], 8);
-        memory_region_add_subregion(&pci->iobar, 8 * i, &s->io);
-    }
-    return 0;
-}
-
-static void serial_pci_exit(PCIDevice *dev)
-{
-    PCISerialState *pci = DO_UPCAST(PCISerialState, dev, dev);
-    SerialState *s = &pci->state;
-
-    serial_exit_core(s);
-    memory_region_destroy(&s->io);
-}
-
-static void multi_serial_pci_exit(PCIDevice *dev)
-{
-    PCIMultiSerialState *pci = DO_UPCAST(PCIMultiSerialState, dev, dev);
-    SerialState *s;
-    int i;
-
-    for (i = 0; i < pci->ports; i++) {
-        s = pci->state + i;
-        serial_exit_core(s);
-        memory_region_destroy(&s->io);
-        g_free(pci->name[i]);
-    }
-    memory_region_destroy(&pci->iobar);
-    qemu_free_irqs(pci->irqs);
-}
-
-static const VMStateDescription vmstate_pci_serial = {
-    .name = "pci-serial",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .fields      = (VMStateField[]) {
-        VMSTATE_PCI_DEVICE(dev, PCISerialState),
-        VMSTATE_STRUCT(state, PCISerialState, 0, vmstate_serial, SerialState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static const VMStateDescription vmstate_pci_multi_serial = {
-    .name = "pci-serial-multi",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .fields      = (VMStateField[]) {
-        VMSTATE_PCI_DEVICE(dev, PCIMultiSerialState),
-        VMSTATE_STRUCT_ARRAY(state, PCIMultiSerialState, PCI_SERIAL_MAX_PORTS,
-                             0, vmstate_serial, SerialState),
-        VMSTATE_UINT32_ARRAY(level, PCIMultiSerialState, PCI_SERIAL_MAX_PORTS),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static Property serial_pci_properties[] = {
-    DEFINE_PROP_CHR("chardev",  PCISerialState, state.chr),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static Property multi_2x_serial_pci_properties[] = {
-    DEFINE_PROP_CHR("chardev1",  PCIMultiSerialState, state[0].chr),
-    DEFINE_PROP_CHR("chardev2",  PCIMultiSerialState, state[1].chr),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static Property multi_4x_serial_pci_properties[] = {
-    DEFINE_PROP_CHR("chardev1",  PCIMultiSerialState, state[0].chr),
-    DEFINE_PROP_CHR("chardev2",  PCIMultiSerialState, state[1].chr),
-    DEFINE_PROP_CHR("chardev3",  PCIMultiSerialState, state[2].chr),
-    DEFINE_PROP_CHR("chardev4",  PCIMultiSerialState, state[3].chr),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void serial_pci_class_initfn(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    PCIDeviceClass *pc = PCI_DEVICE_CLASS(klass);
-    pc->init = serial_pci_init;
-    pc->exit = serial_pci_exit;
-    pc->vendor_id = PCI_VENDOR_ID_REDHAT;
-    pc->device_id = PCI_DEVICE_ID_REDHAT_SERIAL;
-    pc->revision = 1;
-    pc->class_id = PCI_CLASS_COMMUNICATION_SERIAL;
-    dc->vmsd = &vmstate_pci_serial;
-    dc->props = serial_pci_properties;
-}
-
-static void multi_2x_serial_pci_class_initfn(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    PCIDeviceClass *pc = PCI_DEVICE_CLASS(klass);
-    pc->init = multi_serial_pci_init;
-    pc->exit = multi_serial_pci_exit;
-    pc->vendor_id = PCI_VENDOR_ID_REDHAT;
-    pc->device_id = PCI_DEVICE_ID_REDHAT_SERIAL2;
-    pc->revision = 1;
-    pc->class_id = PCI_CLASS_COMMUNICATION_SERIAL;
-    dc->vmsd = &vmstate_pci_multi_serial;
-    dc->props = multi_2x_serial_pci_properties;
-}
-
-static void multi_4x_serial_pci_class_initfn(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    PCIDeviceClass *pc = PCI_DEVICE_CLASS(klass);
-    pc->init = multi_serial_pci_init;
-    pc->exit = multi_serial_pci_exit;
-    pc->vendor_id = PCI_VENDOR_ID_REDHAT;
-    pc->device_id = PCI_DEVICE_ID_REDHAT_SERIAL4;
-    pc->revision = 1;
-    pc->class_id = PCI_CLASS_COMMUNICATION_SERIAL;
-    dc->vmsd = &vmstate_pci_multi_serial;
-    dc->props = multi_4x_serial_pci_properties;
-}
-
-static const TypeInfo serial_pci_info = {
-    .name          = "pci-serial",
-    .parent        = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(PCISerialState),
-    .class_init    = serial_pci_class_initfn,
-};
-
-static const TypeInfo multi_2x_serial_pci_info = {
-    .name          = "pci-serial-2x",
-    .parent        = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(PCIMultiSerialState),
-    .class_init    = multi_2x_serial_pci_class_initfn,
-};
-
-static const TypeInfo multi_4x_serial_pci_info = {
-    .name          = "pci-serial-4x",
-    .parent        = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(PCIMultiSerialState),
-    .class_init    = multi_4x_serial_pci_class_initfn,
-};
-
-static void serial_pci_register_types(void)
-{
-    type_register_static(&serial_pci_info);
-    type_register_static(&multi_2x_serial_pci_info);
-    type_register_static(&multi_4x_serial_pci_info);
-}
-
-type_init(serial_pci_register_types)
diff --git a/hw/serial.c b/hw/serial.c
deleted file mode 100644 (file)
index 0ccc499..0000000
+++ /dev/null
@@ -1,789 +0,0 @@
-/*
- * QEMU 16550A UART emulation
- *
- * Copyright (c) 2003-2004 Fabrice Bellard
- * Copyright (c) 2008 Citrix Systems, 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 "hw/serial.h"
-#include "char/char.h"
-#include "qemu/timer.h"
-#include "exec/address-spaces.h"
-
-//#define DEBUG_SERIAL
-
-#define UART_LCR_DLAB  0x80    /* Divisor latch access bit */
-
-#define UART_IER_MSI   0x08    /* Enable Modem status interrupt */
-#define UART_IER_RLSI  0x04    /* Enable receiver line status interrupt */
-#define UART_IER_THRI  0x02    /* Enable Transmitter holding register int. */
-#define UART_IER_RDI   0x01    /* Enable receiver data interrupt */
-
-#define UART_IIR_NO_INT        0x01    /* No interrupts pending */
-#define UART_IIR_ID    0x06    /* Mask for the interrupt ID */
-
-#define UART_IIR_MSI   0x00    /* Modem status interrupt */
-#define UART_IIR_THRI  0x02    /* Transmitter holding register empty */
-#define UART_IIR_RDI   0x04    /* Receiver data interrupt */
-#define UART_IIR_RLSI  0x06    /* Receiver line status interrupt */
-#define UART_IIR_CTI    0x0C    /* Character Timeout Indication */
-
-#define UART_IIR_FENF   0x80    /* Fifo enabled, but not functionning */
-#define UART_IIR_FE     0xC0    /* Fifo enabled */
-
-/*
- * These are the definitions for the Modem Control Register
- */
-#define UART_MCR_LOOP  0x10    /* Enable loopback test mode */
-#define UART_MCR_OUT2  0x08    /* Out2 complement */
-#define UART_MCR_OUT1  0x04    /* Out1 complement */
-#define UART_MCR_RTS   0x02    /* RTS complement */
-#define UART_MCR_DTR   0x01    /* DTR complement */
-
-/*
- * These are the definitions for the Modem Status Register
- */
-#define UART_MSR_DCD   0x80    /* Data Carrier Detect */
-#define UART_MSR_RI    0x40    /* Ring Indicator */
-#define UART_MSR_DSR   0x20    /* Data Set Ready */
-#define UART_MSR_CTS   0x10    /* Clear to Send */
-#define UART_MSR_DDCD  0x08    /* Delta DCD */
-#define UART_MSR_TERI  0x04    /* Trailing edge ring indicator */
-#define UART_MSR_DDSR  0x02    /* Delta DSR */
-#define UART_MSR_DCTS  0x01    /* Delta CTS */
-#define UART_MSR_ANY_DELTA 0x0F        /* Any of the delta bits! */
-
-#define UART_LSR_TEMT  0x40    /* Transmitter empty */
-#define UART_LSR_THRE  0x20    /* Transmit-hold-register empty */
-#define UART_LSR_BI    0x10    /* Break interrupt indicator */
-#define UART_LSR_FE    0x08    /* Frame error indicator */
-#define UART_LSR_PE    0x04    /* Parity error indicator */
-#define UART_LSR_OE    0x02    /* Overrun error indicator */
-#define UART_LSR_DR    0x01    /* Receiver data ready */
-#define UART_LSR_INT_ANY 0x1E  /* Any of the lsr-interrupt-triggering status bits */
-
-/* Interrupt trigger levels. The byte-counts are for 16550A - in newer UARTs the byte-count for each ITL is higher. */
-
-#define UART_FCR_ITL_1      0x00 /* 1 byte ITL */
-#define UART_FCR_ITL_2      0x40 /* 4 bytes ITL */
-#define UART_FCR_ITL_3      0x80 /* 8 bytes ITL */
-#define UART_FCR_ITL_4      0xC0 /* 14 bytes ITL */
-
-#define UART_FCR_DMS        0x08    /* DMA Mode Select */
-#define UART_FCR_XFR        0x04    /* XMIT Fifo Reset */
-#define UART_FCR_RFR        0x02    /* RCVR Fifo Reset */
-#define UART_FCR_FE         0x01    /* FIFO Enable */
-
-#define XMIT_FIFO           0
-#define RECV_FIFO           1
-#define MAX_XMIT_RETRY      4
-
-#ifdef DEBUG_SERIAL
-#define DPRINTF(fmt, ...) \
-do { fprintf(stderr, "serial: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...) \
-do {} while (0)
-#endif
-
-static void serial_receive1(void *opaque, const uint8_t *buf, int size);
-
-static void fifo_clear(SerialState *s, int fifo)
-{
-    SerialFIFO *f = (fifo) ? &s->recv_fifo : &s->xmit_fifo;
-    memset(f->data, 0, UART_FIFO_LENGTH);
-    f->count = 0;
-    f->head = 0;
-    f->tail = 0;
-}
-
-static int fifo_put(SerialState *s, int fifo, uint8_t chr)
-{
-    SerialFIFO *f = (fifo) ? &s->recv_fifo : &s->xmit_fifo;
-
-    /* Receive overruns do not overwrite FIFO contents. */
-    if (fifo == XMIT_FIFO || f->count < UART_FIFO_LENGTH) {
-
-        f->data[f->head++] = chr;
-
-        if (f->head == UART_FIFO_LENGTH)
-            f->head = 0;
-    }
-
-    if (f->count < UART_FIFO_LENGTH)
-        f->count++;
-    else if (fifo == RECV_FIFO)
-        s->lsr |= UART_LSR_OE;
-
-    return 1;
-}
-
-static uint8_t fifo_get(SerialState *s, int fifo)
-{
-    SerialFIFO *f = (fifo) ? &s->recv_fifo : &s->xmit_fifo;
-    uint8_t c;
-
-    if(f->count == 0)
-        return 0;
-
-    c = f->data[f->tail++];
-    if (f->tail == UART_FIFO_LENGTH)
-        f->tail = 0;
-    f->count--;
-
-    return c;
-}
-
-static void serial_update_irq(SerialState *s)
-{
-    uint8_t tmp_iir = UART_IIR_NO_INT;
-
-    if ((s->ier & UART_IER_RLSI) && (s->lsr & UART_LSR_INT_ANY)) {
-        tmp_iir = UART_IIR_RLSI;
-    } else if ((s->ier & UART_IER_RDI) && s->timeout_ipending) {
-        /* Note that(s->ier & UART_IER_RDI) can mask this interrupt,
-         * this is not in the specification but is observed on existing
-         * hardware.  */
-        tmp_iir = UART_IIR_CTI;
-    } else if ((s->ier & UART_IER_RDI) && (s->lsr & UART_LSR_DR) &&
-               (!(s->fcr & UART_FCR_FE) ||
-                s->recv_fifo.count >= s->recv_fifo.itl)) {
-        tmp_iir = UART_IIR_RDI;
-    } else if ((s->ier & UART_IER_THRI) && s->thr_ipending) {
-        tmp_iir = UART_IIR_THRI;
-    } else if ((s->ier & UART_IER_MSI) && (s->msr & UART_MSR_ANY_DELTA)) {
-        tmp_iir = UART_IIR_MSI;
-    }
-
-    s->iir = tmp_iir | (s->iir & 0xF0);
-
-    if (tmp_iir != UART_IIR_NO_INT) {
-        qemu_irq_raise(s->irq);
-    } else {
-        qemu_irq_lower(s->irq);
-    }
-}
-
-static void serial_update_parameters(SerialState *s)
-{
-    int speed, parity, data_bits, stop_bits, frame_size;
-    QEMUSerialSetParams ssp;
-
-    if (s->divider == 0)
-        return;
-
-    /* Start bit. */
-    frame_size = 1;
-    if (s->lcr & 0x08) {
-        /* Parity bit. */
-        frame_size++;
-        if (s->lcr & 0x10)
-            parity = 'E';
-        else
-            parity = 'O';
-    } else {
-            parity = 'N';
-    }
-    if (s->lcr & 0x04)
-        stop_bits = 2;
-    else
-        stop_bits = 1;
-
-    data_bits = (s->lcr & 0x03) + 5;
-    frame_size += data_bits + stop_bits;
-    speed = s->baudbase / s->divider;
-    ssp.speed = speed;
-    ssp.parity = parity;
-    ssp.data_bits = data_bits;
-    ssp.stop_bits = stop_bits;
-    s->char_transmit_time =  (get_ticks_per_sec() / speed) * frame_size;
-    qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
-
-    DPRINTF("speed=%d parity=%c data=%d stop=%d\n",
-           speed, parity, data_bits, stop_bits);
-}
-
-static void serial_update_msl(SerialState *s)
-{
-    uint8_t omsr;
-    int flags;
-
-    qemu_del_timer(s->modem_status_poll);
-
-    if (qemu_chr_fe_ioctl(s->chr,CHR_IOCTL_SERIAL_GET_TIOCM, &flags) == -ENOTSUP) {
-        s->poll_msl = -1;
-        return;
-    }
-
-    omsr = s->msr;
-
-    s->msr = (flags & CHR_TIOCM_CTS) ? s->msr | UART_MSR_CTS : s->msr & ~UART_MSR_CTS;
-    s->msr = (flags & CHR_TIOCM_DSR) ? s->msr | UART_MSR_DSR : s->msr & ~UART_MSR_DSR;
-    s->msr = (flags & CHR_TIOCM_CAR) ? s->msr | UART_MSR_DCD : s->msr & ~UART_MSR_DCD;
-    s->msr = (flags & CHR_TIOCM_RI) ? s->msr | UART_MSR_RI : s->msr & ~UART_MSR_RI;
-
-    if (s->msr != omsr) {
-         /* Set delta bits */
-         s->msr = s->msr | ((s->msr >> 4) ^ (omsr >> 4));
-         /* UART_MSR_TERI only if change was from 1 -> 0 */
-         if ((s->msr & UART_MSR_TERI) && !(omsr & UART_MSR_RI))
-             s->msr &= ~UART_MSR_TERI;
-         serial_update_irq(s);
-    }
-
-    /* The real 16550A apparently has a 250ns response latency to line status changes.
-       We'll be lazy and poll only every 10ms, and only poll it at all if MSI interrupts are turned on */
-
-    if (s->poll_msl)
-        qemu_mod_timer(s->modem_status_poll, qemu_get_clock_ns(vm_clock) + get_ticks_per_sec() / 100);
-}
-
-static gboolean serial_xmit(GIOChannel *chan, GIOCondition cond, void *opaque)
-{
-    SerialState *s = opaque;
-
-    if (s->tsr_retry <= 0) {
-        if (s->fcr & UART_FCR_FE) {
-            s->tsr = fifo_get(s,XMIT_FIFO);
-            if (!s->xmit_fifo.count)
-                s->lsr |= UART_LSR_THRE;
-        } else if ((s->lsr & UART_LSR_THRE)) {
-            return FALSE;
-        } else {
-            s->tsr = s->thr;
-            s->lsr |= UART_LSR_THRE;
-            s->lsr &= ~UART_LSR_TEMT;
-        }
-    }
-
-    if (s->mcr & UART_MCR_LOOP) {
-        /* in loopback mode, say that we just received a char */
-        serial_receive1(s, &s->tsr, 1);
-    } else if (qemu_chr_fe_write(s->chr, &s->tsr, 1) != 1) {
-        if (s->tsr_retry >= 0 && s->tsr_retry < MAX_XMIT_RETRY &&
-            qemu_chr_fe_add_watch(s->chr, G_IO_OUT, serial_xmit, s) > 0) {
-            s->tsr_retry++;
-            return FALSE;
-        }
-        s->tsr_retry = 0;
-    } else {
-        s->tsr_retry = 0;
-    }
-
-    s->last_xmit_ts = qemu_get_clock_ns(vm_clock);
-
-    if (s->lsr & UART_LSR_THRE) {
-        s->lsr |= UART_LSR_TEMT;
-        s->thr_ipending = 1;
-        serial_update_irq(s);
-    }
-
-    return FALSE;
-}
-
-
-static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val,
-                                unsigned size)
-{
-    SerialState *s = opaque;
-
-    addr &= 7;
-    DPRINTF("write addr=0x%" HWADDR_PRIx " val=0x%" PRIx64 "\n", addr, val);
-    switch(addr) {
-    default:
-    case 0:
-        if (s->lcr & UART_LCR_DLAB) {
-            s->divider = (s->divider & 0xff00) | val;
-            serial_update_parameters(s);
-        } else {
-            s->thr = (uint8_t) val;
-            if(s->fcr & UART_FCR_FE) {
-                fifo_put(s, XMIT_FIFO, s->thr);
-                s->thr_ipending = 0;
-                s->lsr &= ~UART_LSR_TEMT;
-                s->lsr &= ~UART_LSR_THRE;
-                serial_update_irq(s);
-            } else {
-                s->thr_ipending = 0;
-                s->lsr &= ~UART_LSR_THRE;
-                serial_update_irq(s);
-            }
-            serial_xmit(NULL, G_IO_OUT, s);
-        }
-        break;
-    case 1:
-        if (s->lcr & UART_LCR_DLAB) {
-            s->divider = (s->divider & 0x00ff) | (val << 8);
-            serial_update_parameters(s);
-        } else {
-            s->ier = val & 0x0f;
-            /* If the backend device is a real serial port, turn polling of the modem
-               status lines on physical port on or off depending on UART_IER_MSI state */
-            if (s->poll_msl >= 0) {
-                if (s->ier & UART_IER_MSI) {
-                     s->poll_msl = 1;
-                     serial_update_msl(s);
-                } else {
-                     qemu_del_timer(s->modem_status_poll);
-                     s->poll_msl = 0;
-                }
-            }
-            if (s->lsr & UART_LSR_THRE) {
-                s->thr_ipending = 1;
-                serial_update_irq(s);
-            }
-        }
-        break;
-    case 2:
-        val = val & 0xFF;
-
-        if (s->fcr == val)
-            break;
-
-        /* Did the enable/disable flag change? If so, make sure FIFOs get flushed */
-        if ((val ^ s->fcr) & UART_FCR_FE)
-            val |= UART_FCR_XFR | UART_FCR_RFR;
-
-        /* FIFO clear */
-
-        if (val & UART_FCR_RFR) {
-            qemu_del_timer(s->fifo_timeout_timer);
-            s->timeout_ipending=0;
-            fifo_clear(s,RECV_FIFO);
-        }
-
-        if (val & UART_FCR_XFR) {
-            fifo_clear(s,XMIT_FIFO);
-        }
-
-        if (val & UART_FCR_FE) {
-            s->iir |= UART_IIR_FE;
-            /* Set RECV_FIFO trigger Level */
-            switch (val & 0xC0) {
-            case UART_FCR_ITL_1:
-                s->recv_fifo.itl = 1;
-                break;
-            case UART_FCR_ITL_2:
-                s->recv_fifo.itl = 4;
-                break;
-            case UART_FCR_ITL_3:
-                s->recv_fifo.itl = 8;
-                break;
-            case UART_FCR_ITL_4:
-                s->recv_fifo.itl = 14;
-                break;
-            }
-        } else
-            s->iir &= ~UART_IIR_FE;
-
-        /* Set fcr - or at least the bits in it that are supposed to "stick" */
-        s->fcr = val & 0xC9;
-        serial_update_irq(s);
-        break;
-    case 3:
-        {
-            int break_enable;
-            s->lcr = val;
-            serial_update_parameters(s);
-            break_enable = (val >> 6) & 1;
-            if (break_enable != s->last_break_enable) {
-                s->last_break_enable = break_enable;
-                qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_BREAK,
-                               &break_enable);
-            }
-        }
-        break;
-    case 4:
-        {
-            int flags;
-            int old_mcr = s->mcr;
-            s->mcr = val & 0x1f;
-            if (val & UART_MCR_LOOP)
-                break;
-
-            if (s->poll_msl >= 0 && old_mcr != s->mcr) {
-
-                qemu_chr_fe_ioctl(s->chr,CHR_IOCTL_SERIAL_GET_TIOCM, &flags);
-
-                flags &= ~(CHR_TIOCM_RTS | CHR_TIOCM_DTR);
-
-                if (val & UART_MCR_RTS)
-                    flags |= CHR_TIOCM_RTS;
-                if (val & UART_MCR_DTR)
-                    flags |= CHR_TIOCM_DTR;
-
-                qemu_chr_fe_ioctl(s->chr,CHR_IOCTL_SERIAL_SET_TIOCM, &flags);
-                /* Update the modem status after a one-character-send wait-time, since there may be a response
-                   from the device/computer at the other end of the serial line */
-                qemu_mod_timer(s->modem_status_poll, qemu_get_clock_ns(vm_clock) + s->char_transmit_time);
-            }
-        }
-        break;
-    case 5:
-        break;
-    case 6:
-        break;
-    case 7:
-        s->scr = val;
-        break;
-    }
-}
-
-static uint64_t serial_ioport_read(void *opaque, hwaddr addr, unsigned size)
-{
-    SerialState *s = opaque;
-    uint32_t ret;
-
-    addr &= 7;
-    switch(addr) {
-    default:
-    case 0:
-        if (s->lcr & UART_LCR_DLAB) {
-            ret = s->divider & 0xff;
-        } else {
-            if(s->fcr & UART_FCR_FE) {
-                ret = fifo_get(s,RECV_FIFO);
-                if (s->recv_fifo.count == 0)
-                    s->lsr &= ~(UART_LSR_DR | UART_LSR_BI);
-                else
-                    qemu_mod_timer(s->fifo_timeout_timer, qemu_get_clock_ns (vm_clock) + s->char_transmit_time * 4);
-                s->timeout_ipending = 0;
-            } else {
-                ret = s->rbr;
-                s->lsr &= ~(UART_LSR_DR | UART_LSR_BI);
-            }
-            serial_update_irq(s);
-            if (!(s->mcr & UART_MCR_LOOP)) {
-                /* in loopback mode, don't receive any data */
-                qemu_chr_accept_input(s->chr);
-            }
-        }
-        break;
-    case 1:
-        if (s->lcr & UART_LCR_DLAB) {
-            ret = (s->divider >> 8) & 0xff;
-        } else {
-            ret = s->ier;
-        }
-        break;
-    case 2:
-        ret = s->iir;
-        if ((ret & UART_IIR_ID) == UART_IIR_THRI) {
-            s->thr_ipending = 0;
-            serial_update_irq(s);
-        }
-        break;
-    case 3:
-        ret = s->lcr;
-        break;
-    case 4:
-        ret = s->mcr;
-        break;
-    case 5:
-        ret = s->lsr;
-        /* Clear break and overrun interrupts */
-        if (s->lsr & (UART_LSR_BI|UART_LSR_OE)) {
-            s->lsr &= ~(UART_LSR_BI|UART_LSR_OE);
-            serial_update_irq(s);
-        }
-        break;
-    case 6:
-        if (s->mcr & UART_MCR_LOOP) {
-            /* in loopback, the modem output pins are connected to the
-               inputs */
-            ret = (s->mcr & 0x0c) << 4;
-            ret |= (s->mcr & 0x02) << 3;
-            ret |= (s->mcr & 0x01) << 5;
-        } else {
-            if (s->poll_msl >= 0)
-                serial_update_msl(s);
-            ret = s->msr;
-            /* Clear delta bits & msr int after read, if they were set */
-            if (s->msr & UART_MSR_ANY_DELTA) {
-                s->msr &= 0xF0;
-                serial_update_irq(s);
-            }
-        }
-        break;
-    case 7:
-        ret = s->scr;
-        break;
-    }
-    DPRINTF("read addr=0x%" HWADDR_PRIx " val=0x%02x\n", addr, ret);
-    return ret;
-}
-
-static int serial_can_receive(SerialState *s)
-{
-    if(s->fcr & UART_FCR_FE) {
-        if(s->recv_fifo.count < UART_FIFO_LENGTH)
-        /* Advertise (fifo.itl - fifo.count) bytes when count < ITL, and 1 if above. If UART_FIFO_LENGTH - fifo.count is
-        advertised the effect will be to almost always fill the fifo completely before the guest has a chance to respond,
-        effectively overriding the ITL that the guest has set. */
-             return (s->recv_fifo.count <= s->recv_fifo.itl) ? s->recv_fifo.itl - s->recv_fifo.count : 1;
-        else
-             return 0;
-    } else {
-    return !(s->lsr & UART_LSR_DR);
-    }
-}
-
-static void serial_receive_break(SerialState *s)
-{
-    s->rbr = 0;
-    /* When the LSR_DR is set a null byte is pushed into the fifo */
-    fifo_put(s, RECV_FIFO, '\0');
-    s->lsr |= UART_LSR_BI | UART_LSR_DR;
-    serial_update_irq(s);
-}
-
-/* There's data in recv_fifo and s->rbr has not been read for 4 char transmit times */
-static void fifo_timeout_int (void *opaque) {
-    SerialState *s = opaque;
-    if (s->recv_fifo.count) {
-        s->timeout_ipending = 1;
-        serial_update_irq(s);
-    }
-}
-
-static int serial_can_receive1(void *opaque)
-{
-    SerialState *s = opaque;
-    return serial_can_receive(s);
-}
-
-static void serial_receive1(void *opaque, const uint8_t *buf, int size)
-{
-    SerialState *s = opaque;
-
-    if (s->wakeup) {
-        qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER);
-    }
-    if(s->fcr & UART_FCR_FE) {
-        int i;
-        for (i = 0; i < size; i++) {
-            fifo_put(s, RECV_FIFO, buf[i]);
-        }
-        s->lsr |= UART_LSR_DR;
-        /* call the timeout receive callback in 4 char transmit time */
-        qemu_mod_timer(s->fifo_timeout_timer, qemu_get_clock_ns (vm_clock) + s->char_transmit_time * 4);
-    } else {
-        if (s->lsr & UART_LSR_DR)
-            s->lsr |= UART_LSR_OE;
-        s->rbr = buf[0];
-        s->lsr |= UART_LSR_DR;
-    }
-    serial_update_irq(s);
-}
-
-static void serial_event(void *opaque, int event)
-{
-    SerialState *s = opaque;
-    DPRINTF("event %x\n", event);
-    if (event == CHR_EVENT_BREAK)
-        serial_receive_break(s);
-}
-
-static void serial_pre_save(void *opaque)
-{
-    SerialState *s = opaque;
-    s->fcr_vmstate = s->fcr;
-}
-
-static int serial_post_load(void *opaque, int version_id)
-{
-    SerialState *s = opaque;
-
-    if (version_id < 3) {
-        s->fcr_vmstate = 0;
-    }
-    /* Initialize fcr via setter to perform essential side-effects */
-    serial_ioport_write(s, 0x02, s->fcr_vmstate, 1);
-    serial_update_parameters(s);
-    return 0;
-}
-
-const VMStateDescription vmstate_serial = {
-    .name = "serial",
-    .version_id = 3,
-    .minimum_version_id = 2,
-    .pre_save = serial_pre_save,
-    .post_load = serial_post_load,
-    .fields      = (VMStateField []) {
-        VMSTATE_UINT16_V(divider, SerialState, 2),
-        VMSTATE_UINT8(rbr, SerialState),
-        VMSTATE_UINT8(ier, SerialState),
-        VMSTATE_UINT8(iir, SerialState),
-        VMSTATE_UINT8(lcr, SerialState),
-        VMSTATE_UINT8(mcr, SerialState),
-        VMSTATE_UINT8(lsr, SerialState),
-        VMSTATE_UINT8(msr, SerialState),
-        VMSTATE_UINT8(scr, SerialState),
-        VMSTATE_UINT8_V(fcr_vmstate, SerialState, 3),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void serial_reset(void *opaque)
-{
-    SerialState *s = opaque;
-
-    s->rbr = 0;
-    s->ier = 0;
-    s->iir = UART_IIR_NO_INT;
-    s->lcr = 0;
-    s->lsr = UART_LSR_TEMT | UART_LSR_THRE;
-    s->msr = UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS;
-    /* Default to 9600 baud, 1 start bit, 8 data bits, 1 stop bit, no parity. */
-    s->divider = 0x0C;
-    s->mcr = UART_MCR_OUT2;
-    s->scr = 0;
-    s->tsr_retry = 0;
-    s->char_transmit_time = (get_ticks_per_sec() / 9600) * 10;
-    s->poll_msl = 0;
-
-    fifo_clear(s,RECV_FIFO);
-    fifo_clear(s,XMIT_FIFO);
-
-    s->last_xmit_ts = qemu_get_clock_ns(vm_clock);
-
-    s->thr_ipending = 0;
-    s->last_break_enable = 0;
-    qemu_irq_lower(s->irq);
-}
-
-void serial_init_core(SerialState *s)
-{
-    if (!s->chr) {
-        fprintf(stderr, "Can't create serial device, empty char device\n");
-       exit(1);
-    }
-
-    s->modem_status_poll = qemu_new_timer_ns(vm_clock, (QEMUTimerCB *) serial_update_msl, s);
-
-    s->fifo_timeout_timer = qemu_new_timer_ns(vm_clock, (QEMUTimerCB *) fifo_timeout_int, s);
-    qemu_register_reset(serial_reset, s);
-
-    qemu_chr_add_handlers(s->chr, serial_can_receive1, serial_receive1,
-                          serial_event, s);
-}
-
-void serial_exit_core(SerialState *s)
-{
-    qemu_chr_add_handlers(s->chr, NULL, NULL, NULL, NULL);
-    qemu_unregister_reset(serial_reset, s);
-}
-
-/* Change the main reference oscillator frequency. */
-void serial_set_frequency(SerialState *s, uint32_t frequency)
-{
-    s->baudbase = frequency;
-    serial_update_parameters(s);
-}
-
-const MemoryRegionOps serial_io_ops = {
-    .read = serial_ioport_read,
-    .write = serial_ioport_write,
-    .impl = {
-        .min_access_size = 1,
-        .max_access_size = 1,
-    },
-    .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-SerialState *serial_init(int base, qemu_irq irq, int baudbase,
-                         CharDriverState *chr, MemoryRegion *system_io)
-{
-    SerialState *s;
-
-    s = g_malloc0(sizeof(SerialState));
-
-    s->irq = irq;
-    s->baudbase = baudbase;
-    s->chr = chr;
-    serial_init_core(s);
-
-    vmstate_register(NULL, base, &vmstate_serial, s);
-
-    memory_region_init_io(&s->io, &serial_io_ops, s, "serial", 8);
-    memory_region_add_subregion(system_io, base, &s->io);
-
-    return s;
-}
-
-/* Memory mapped interface */
-static uint64_t serial_mm_read(void *opaque, hwaddr addr,
-                               unsigned size)
-{
-    SerialState *s = opaque;
-    return serial_ioport_read(s, addr >> s->it_shift, 1);
-}
-
-static void serial_mm_write(void *opaque, hwaddr addr,
-                            uint64_t value, unsigned size)
-{
-    SerialState *s = opaque;
-    value &= ~0u >> (32 - (size * 8));
-    serial_ioport_write(s, addr >> s->it_shift, value, 1);
-}
-
-static const MemoryRegionOps serial_mm_ops[3] = {
-    [DEVICE_NATIVE_ENDIAN] = {
-        .read = serial_mm_read,
-        .write = serial_mm_write,
-        .endianness = DEVICE_NATIVE_ENDIAN,
-    },
-    [DEVICE_LITTLE_ENDIAN] = {
-        .read = serial_mm_read,
-        .write = serial_mm_write,
-        .endianness = DEVICE_LITTLE_ENDIAN,
-    },
-    [DEVICE_BIG_ENDIAN] = {
-        .read = serial_mm_read,
-        .write = serial_mm_write,
-        .endianness = DEVICE_BIG_ENDIAN,
-    },
-};
-
-SerialState *serial_mm_init(MemoryRegion *address_space,
-                            hwaddr base, int it_shift,
-                            qemu_irq irq, int baudbase,
-                            CharDriverState *chr, enum device_endian end)
-{
-    SerialState *s;
-
-    s = g_malloc0(sizeof(SerialState));
-
-    s->it_shift = it_shift;
-    s->irq = irq;
-    s->baudbase = baudbase;
-    s->chr = chr;
-
-    serial_init_core(s);
-    vmstate_register(NULL, base, &vmstate_serial, s);
-
-    memory_region_init_io(&s->io, &serial_mm_ops[end], s,
-                          "serial", 8 << it_shift);
-    memory_region_add_subregion(address_space, base, &s->io);
-
-    serial_update_msl(s);
-    return s;
-}
diff --git a/hw/serial.h b/hw/serial.h
deleted file mode 100644 (file)
index e884499..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * QEMU 16550A UART emulation
- *
- * Copyright (c) 2003-2004 Fabrice Bellard
- * Copyright (c) 2008 Citrix Systems, 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.
- */
-#ifndef HW_SERIAL_H
-#define HW_SERIAL_H 1
-
-#include "hw/hw.h"
-#include "sysemu/sysemu.h"
-#include "exec/memory.h"
-
-#define UART_FIFO_LENGTH    16      /* 16550A Fifo Length */
-
-typedef struct SerialFIFO {
-    uint8_t data[UART_FIFO_LENGTH];
-    uint8_t count;
-    uint8_t itl;                        /* Interrupt Trigger Level */
-    uint8_t tail;
-    uint8_t head;
-} SerialFIFO;
-
-struct SerialState {
-    uint16_t divider;
-    uint8_t rbr; /* receive register */
-    uint8_t thr; /* transmit holding register */
-    uint8_t tsr; /* transmit shift register */
-    uint8_t ier;
-    uint8_t iir; /* read only */
-    uint8_t lcr;
-    uint8_t mcr;
-    uint8_t lsr; /* read only */
-    uint8_t msr; /* read only */
-    uint8_t scr;
-    uint8_t fcr;
-    uint8_t fcr_vmstate; /* we can't write directly this value
-                            it has side effects */
-    /* NOTE: this hidden state is necessary for tx irq generation as
-       it can be reset while reading iir */
-    int thr_ipending;
-    qemu_irq irq;
-    CharDriverState *chr;
-    int last_break_enable;
-    int it_shift;
-    int baudbase;
-    int tsr_retry;
-    uint32_t wakeup;
-
-    /* Time when the last byte was successfully sent out of the tsr */
-    uint64_t last_xmit_ts;
-    SerialFIFO recv_fifo;
-    SerialFIFO xmit_fifo;
-
-    struct QEMUTimer *fifo_timeout_timer;
-    int timeout_ipending;           /* timeout interrupt pending state */
-
-    uint64_t char_transmit_time;    /* time to transmit a char in ticks */
-    int poll_msl;
-
-    struct QEMUTimer *modem_status_poll;
-    MemoryRegion io;
-};
-
-extern const VMStateDescription vmstate_serial;
-extern const MemoryRegionOps serial_io_ops;
-
-void serial_init_core(SerialState *s);
-void serial_exit_core(SerialState *s);
-void serial_set_frequency(SerialState *s, uint32_t frequency);
-
-/* legacy pre qom */
-SerialState *serial_init(int base, qemu_irq irq, int baudbase,
-                         CharDriverState *chr, MemoryRegion *system_io);
-SerialState *serial_mm_init(MemoryRegion *address_space,
-                            hwaddr base, int it_shift,
-                            qemu_irq irq, int baudbase,
-                            CharDriverState *chr, enum device_endian end);
-
-/* serial-isa.c */
-bool serial_isa_init(ISABus *bus, int index, CharDriverState *chr);
-
-#endif
diff --git a/hw/sga.c b/hw/sga.c
deleted file mode 100644 (file)
index 4b1d4e5..0000000
--- a/hw/sga.c
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * QEMU dummy ISA device for loading sgabios option rom.
- *
- * Copyright (c) 2011 Glauber Costa, Red Hat 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.
- *
- * sgabios code originally available at code.google.com/p/sgabios
- *
- */
-#include "hw/pci/pci.h"
-#include "hw/pc.h"
-#include "hw/loader.h"
-#include "sysemu/sysemu.h"
-
-#define SGABIOS_FILENAME "sgabios.bin"
-
-typedef struct ISAGAState {
-    ISADevice dev;
-} ISASGAState;
-
-static int sga_initfn(ISADevice *dev)
-{
-    rom_add_vga(SGABIOS_FILENAME);
-    return 0;
-}
-static void sga_class_initfn(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
-    ic->init = sga_initfn;
-    dc->desc = "Serial Graphics Adapter";
-}
-
-static const TypeInfo sga_info = {
-    .name          = "sga",
-    .parent        = TYPE_ISA_DEVICE,
-    .instance_size = sizeof(ISASGAState),
-    .class_init    = sga_class_initfn,
-};
-
-static void sga_register_types(void)
-{
-    type_register_static(&sga_info);
-}
-
-type_init(sga_register_types)
diff --git a/hw/sh.h b/hw/sh.h
deleted file mode 100644 (file)
index 6230954..0000000
--- a/hw/sh.h
+++ /dev/null
@@ -1,57 +0,0 @@
-#ifndef QEMU_SH_H
-#define QEMU_SH_H
-/* Definitions for SH board emulation.  */
-
-#include "hw/sh_intc.h"
-
-#define A7ADDR(x) ((x) & 0x1fffffff)
-#define P4ADDR(x) ((x) | 0xe0000000)
-
-/* sh7750.c */
-struct SH7750State;
-struct MemoryRegion;
-
-struct SH7750State *sh7750_init(CPUSH4State * cpu, struct MemoryRegion *sysmem);
-
-typedef struct {
-    /* The callback will be triggered if any of the designated lines change */
-    uint16_t portamask_trigger;
-    uint16_t portbmask_trigger;
-    /* Return 0 if no action was taken */
-    int (*port_change_cb) (uint16_t porta, uint16_t portb,
-                          uint16_t * periph_pdtra,
-                          uint16_t * periph_portdira,
-                          uint16_t * periph_pdtrb,
-                          uint16_t * periph_portdirb);
-} sh7750_io_device;
-
-int sh7750_register_io_device(struct SH7750State *s,
-                             sh7750_io_device * device);
-/* sh_timer.c */
-#define TMU012_FEAT_TOCR   (1 << 0)
-#define TMU012_FEAT_3CHAN  (1 << 1)
-#define TMU012_FEAT_EXTCLK (1 << 2)
-void tmu012_init(struct MemoryRegion *sysmem, hwaddr base,
-                 int feat, uint32_t freq,
-                qemu_irq ch0_irq, qemu_irq ch1_irq,
-                qemu_irq ch2_irq0, qemu_irq ch2_irq1);
-
-
-/* sh_serial.c */
-#define SH_SERIAL_FEAT_SCIF (1 << 0)
-void sh_serial_init(MemoryRegion *sysmem,
-                    hwaddr base, int feat,
-                    uint32_t freq, CharDriverState *chr,
-                    qemu_irq eri_source,
-                    qemu_irq rxi_source,
-                    qemu_irq txi_source,
-                    qemu_irq tei_source,
-                    qemu_irq bri_source);
-
-/* sh7750.c */
-qemu_irq sh7750_irl(struct SH7750State *s);
-
-/* tc58128.c */
-int tc58128_init(struct SH7750State *s, const char *zone1, const char *zone2);
-
-#endif
index 72b6a1fcb43f0947e43327e20ea4b685aeec77a6..2393702c5768d628236daf65a5be2cfb5de79d27 100644 (file)
@@ -1,9 +1,4 @@
-obj-y = tc58128.o
-obj-y += sh_timer.o sh_serial.o sh_intc.o sh_pci.o sm501.o
-obj-y += ide/mmio.o
-
-obj-y := $(addprefix ../,$(obj-y))
-
 obj-y += shix.o r2d.o
 
 obj-y += sh7750.o sh7750_regnames.o
+obj-y += sh_pci.o
index faa03d2069357fa8d28f01aa22a01e55396c92c4..256a58c601340b0cf90a2063f163296d57a5b1bc 100644 (file)
 
 #include "hw/sysbus.h"
 #include "hw/hw.h"
-#include "hw/sh.h"
-#include "hw/devices.h"
+#include "hw/sh4/sh.h"
+#include "hw/arm/devices.h"
 #include "sysemu/sysemu.h"
 #include "hw/boards.h"
 #include "hw/pci/pci.h"
 #include "net/net.h"
-#include "hw/sh7750_regs.h"
+#include "sh7750_regs.h"
 #include "hw/ide.h"
 #include "hw/loader.h"
 #include "hw/usb.h"
-#include "hw/flash.h"
+#include "hw/block/flash.h"
 #include "sysemu/blockdev.h"
 #include "exec/address-spaces.h"
 
index e4d37ad6aca3a82af49cb154f10423242399ef92..2218b9ce6ad992ef17bf5917de3fd3e37cb98faa 100644 (file)
  */
 #include <stdio.h>
 #include "hw/hw.h"
-#include "hw/sh.h"
+#include "hw/sh4/sh.h"
 #include "sysemu/sysemu.h"
-#include "hw/sh7750_regs.h"
-#include "hw/sh7750_regnames.h"
-#include "hw/sh_intc.h"
+#include "sh7750_regs.h"
+#include "sh7750_regnames.h"
+#include "hw/sh4/sh_intc.h"
 #include "cpu.h"
 #include "exec/address-spaces.h"
 
index 389698d24af170c00efc60c56ddaad1b85550076..52ac1cc781b5358d923d7bf02ed27cbf298e89a8 100644 (file)
@@ -1,7 +1,7 @@
 #include "hw/hw.h"
-#include "hw/sh.h"
-#include "hw/sh7750_regs.h"
-#include "hw/sh7750_regnames.h"
+#include "hw/sh4/sh.h"
+#include "sh7750_regs.h"
+#include "sh7750_regnames.h"
 
 #define REGNAME(r) {r, #r},
 
diff --git a/hw/sh4/sh7750_regnames.h b/hw/sh4/sh7750_regnames.h
new file mode 100644 (file)
index 0000000..7463709
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef _SH7750_REGNAMES_H
+#define _SH7750_REGNAMES_H
+
+const char *regname(uint32_t addr);
+
+#endif                         /* _SH7750_REGNAMES_H */
diff --git a/hw/sh4/sh7750_regs.h b/hw/sh4/sh7750_regs.h
new file mode 100644 (file)
index 0000000..534aa48
--- /dev/null
@@ -0,0 +1,1277 @@
+/*
+ * SH-7750 memory-mapped registers
+ * This file based on information provided in the following document:
+ * "Hitachi SuperH (tm) RISC engine. SH7750 Series (SH7750, SH7750S)
+ *  Hardware Manual"
+ *  Document Number ADE-602-124C, Rev. 4.0, 4/21/00, Hitachi Ltd.
+ *
+ * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
+ * Author: Alexandra Kossovsky <sasha@oktet.ru>
+ *         Victor V. Vengerov <vvv@oktet.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ *  http://www.rtems.com/license/LICENSE.
+ *
+ * @(#) sh7750_regs.h,v 1.2.4.1 2003/09/04 18:46:00 joel Exp
+ */
+
+#ifndef __SH7750_REGS_H__
+#define __SH7750_REGS_H__
+
+/*
+ * All register has 2 addresses: in 0xff000000 - 0xffffffff (P4 address)  and
+ * in 0x1f000000 - 0x1fffffff (area 7 address)
+ */
+#define SH7750_P4_BASE       0xff000000        /* Accessible only in
+                                          privileged mode */
+#define SH7750_A7_BASE       0x1f000000        /* Accessible only using TLB */
+
+#define SH7750_P4_REG32(ofs) (SH7750_P4_BASE + (ofs))
+#define SH7750_A7_REG32(ofs) (SH7750_A7_BASE + (ofs))
+
+/*
+ * MMU Registers
+ */
+
+/* Page Table Entry High register - PTEH */
+#define SH7750_PTEH_REGOFS    0x000000 /* offset */
+#define SH7750_PTEH           SH7750_P4_REG32(SH7750_PTEH_REGOFS)
+#define SH7750_PTEH_A7        SH7750_A7_REG32(SH7750_PTEH_REGOFS)
+#define SH7750_PTEH_VPN       0xfffffd00       /* Virtual page number */
+#define SH7750_PTEH_VPN_S     10
+#define SH7750_PTEH_ASID      0x000000ff       /* Address space identifier */
+#define SH7750_PTEH_ASID_S    0
+
+/* Page Table Entry Low register - PTEL */
+#define SH7750_PTEL_REGOFS    0x000004 /* offset */
+#define SH7750_PTEL           SH7750_P4_REG32(SH7750_PTEL_REGOFS)
+#define SH7750_PTEL_A7        SH7750_A7_REG32(SH7750_PTEL_REGOFS)
+#define SH7750_PTEL_PPN       0x1ffffc00       /* Physical page number */
+#define SH7750_PTEL_PPN_S     10
+#define SH7750_PTEL_V         0x00000100       /* Validity (0-entry is invalid) */
+#define SH7750_PTEL_SZ1       0x00000080       /* Page size bit 1 */
+#define SH7750_PTEL_SZ0       0x00000010       /* Page size bit 0 */
+#define SH7750_PTEL_SZ_1KB    0x00000000       /*   1-kbyte page */
+#define SH7750_PTEL_SZ_4KB    0x00000010       /*   4-kbyte page */
+#define SH7750_PTEL_SZ_64KB   0x00000080       /*   64-kbyte page */
+#define SH7750_PTEL_SZ_1MB    0x00000090       /*   1-Mbyte page */
+#define SH7750_PTEL_PR        0x00000060       /* Protection Key Data */
+#define SH7750_PTEL_PR_ROPO   0x00000000       /*   read-only in priv mode */
+#define SH7750_PTEL_PR_RWPO   0x00000020       /*   read-write in priv mode */
+#define SH7750_PTEL_PR_ROPU   0x00000040       /*   read-only in priv or user mode */
+#define SH7750_PTEL_PR_RWPU   0x00000060       /*   read-write in priv or user mode */
+#define SH7750_PTEL_C         0x00000008       /* Cacheability
+                                                  (0 - page not cacheable) */
+#define SH7750_PTEL_D         0x00000004       /* Dirty bit (1 - write has been
+                                                  performed to a page) */
+#define SH7750_PTEL_SH        0x00000002       /* Share Status bit (1 - page are
+                                                  shared by processes) */
+#define SH7750_PTEL_WT        0x00000001       /* Write-through bit, specifies the
+                                                  cache write mode:
+                                                  0 - Copy-back mode
+                                                  1 - Write-through mode */
+
+/* Page Table Entry Assistance register - PTEA */
+#define SH7750_PTEA_REGOFS    0x000034 /* offset */
+#define SH7750_PTEA           SH7750_P4_REG32(SH7750_PTEA_REGOFS)
+#define SH7750_PTEA_A7        SH7750_A7_REG32(SH7750_PTEA_REGOFS)
+#define SH7750_PTEA_TC        0x00000008       /* Timing Control bit
+                                                  0 - use area 5 wait states
+                                                  1 - use area 6 wait states */
+#define SH7750_PTEA_SA        0x00000007       /* Space Attribute bits: */
+#define SH7750_PTEA_SA_UNDEF  0x00000000       /*    0 - undefined */
+#define SH7750_PTEA_SA_IOVAR  0x00000001       /*    1 - variable-size I/O space */
+#define SH7750_PTEA_SA_IO8    0x00000002       /*    2 - 8-bit I/O space */
+#define SH7750_PTEA_SA_IO16   0x00000003       /*    3 - 16-bit I/O space */
+#define SH7750_PTEA_SA_CMEM8  0x00000004       /*    4 - 8-bit common memory space */
+#define SH7750_PTEA_SA_CMEM16 0x00000005       /*    5 - 16-bit common memory space */
+#define SH7750_PTEA_SA_AMEM8  0x00000006       /*    6 - 8-bit attr memory space */
+#define SH7750_PTEA_SA_AMEM16 0x00000007       /*    7 - 16-bit attr memory space */
+
+
+/* Translation table base register */
+#define SH7750_TTB_REGOFS     0x000008 /* offset */
+#define SH7750_TTB            SH7750_P4_REG32(SH7750_TTB_REGOFS)
+#define SH7750_TTB_A7         SH7750_A7_REG32(SH7750_TTB_REGOFS)
+
+/* TLB exeption address register - TEA */
+#define SH7750_TEA_REGOFS     0x00000c /* offset */
+#define SH7750_TEA            SH7750_P4_REG32(SH7750_TEA_REGOFS)
+#define SH7750_TEA_A7         SH7750_A7_REG32(SH7750_TEA_REGOFS)
+
+/* MMU control register - MMUCR */
+#define SH7750_MMUCR_REGOFS   0x000010 /* offset */
+#define SH7750_MMUCR          SH7750_P4_REG32(SH7750_MMUCR_REGOFS)
+#define SH7750_MMUCR_A7       SH7750_A7_REG32(SH7750_MMUCR_REGOFS)
+#define SH7750_MMUCR_AT       0x00000001       /* Address translation bit */
+#define SH7750_MMUCR_TI       0x00000004       /* TLB invalidate */
+#define SH7750_MMUCR_SV       0x00000100       /* Single Virtual Mode bit */
+#define SH7750_MMUCR_SQMD     0x00000200       /* Store Queue Mode bit */
+#define SH7750_MMUCR_URC      0x0000FC00       /* UTLB Replace Counter */
+#define SH7750_MMUCR_URC_S    10
+#define SH7750_MMUCR_URB      0x00FC0000       /* UTLB Replace Boundary */
+#define SH7750_MMUCR_URB_S    18
+#define SH7750_MMUCR_LRUI     0xFC000000       /* Least Recently Used ITLB */
+#define SH7750_MMUCR_LRUI_S   26
+
+
+
+
+/*
+ * Cache registers
+ *   IC -- instructions cache
+ *   OC -- operand cache
+ */
+
+/* Cache Control Register - CCR */
+#define SH7750_CCR_REGOFS     0x00001c /* offset */
+#define SH7750_CCR            SH7750_P4_REG32(SH7750_CCR_REGOFS)
+#define SH7750_CCR_A7         SH7750_A7_REG32(SH7750_CCR_REGOFS)
+
+#define SH7750_CCR_IIX      0x00008000 /* IC index enable bit */
+#define SH7750_CCR_ICI      0x00000800 /* IC invalidation bit:
+                                          set it to clear IC */
+#define SH7750_CCR_ICE      0x00000100 /* IC enable bit */
+#define SH7750_CCR_OIX      0x00000080 /* OC index enable bit */
+#define SH7750_CCR_ORA      0x00000020 /* OC RAM enable bit
+                                          if you set OCE = 0,
+                                          you should set ORA = 0 */
+#define SH7750_CCR_OCI      0x00000008 /* OC invalidation bit */
+#define SH7750_CCR_CB       0x00000004 /* Copy-back bit for P1 area */
+#define SH7750_CCR_WT       0x00000002 /* Write-through bit for P0,U0,P3 area */
+#define SH7750_CCR_OCE      0x00000001 /* OC enable bit */
+
+/* Queue address control register 0 - QACR0 */
+#define SH7750_QACR0_REGOFS   0x000038 /* offset */
+#define SH7750_QACR0          SH7750_P4_REG32(SH7750_QACR0_REGOFS)
+#define SH7750_QACR0_A7       SH7750_A7_REG32(SH7750_QACR0_REGOFS)
+
+/* Queue address control register 1 - QACR1 */
+#define SH7750_QACR1_REGOFS   0x00003c /* offset */
+#define SH7750_QACR1          SH7750_P4_REG32(SH7750_QACR1_REGOFS)
+#define SH7750_QACR1_A7       SH7750_A7_REG32(SH7750_QACR1_REGOFS)
+
+
+/*
+ * Exeption-related registers
+ */
+
+/* Immediate data for TRAPA instruction - TRA */
+#define SH7750_TRA_REGOFS     0x000020 /* offset */
+#define SH7750_TRA            SH7750_P4_REG32(SH7750_TRA_REGOFS)
+#define SH7750_TRA_A7         SH7750_A7_REG32(SH7750_TRA_REGOFS)
+
+#define SH7750_TRA_IMM      0x000003fd /* Immediate data operand */
+#define SH7750_TRA_IMM_S    2
+
+/* Exeption event register - EXPEVT */
+#define SH7750_EXPEVT_REGOFS  0x000024
+#define SH7750_EXPEVT         SH7750_P4_REG32(SH7750_EXPEVT_REGOFS)
+#define SH7750_EXPEVT_A7      SH7750_A7_REG32(SH7750_EXPEVT_REGOFS)
+
+#define SH7750_EXPEVT_EX      0x00000fff       /* Exeption code */
+#define SH7750_EXPEVT_EX_S    0
+
+/* Interrupt event register */
+#define SH7750_INTEVT_REGOFS  0x000028
+#define SH7750_INTEVT         SH7750_P4_REG32(SH7750_INTEVT_REGOFS)
+#define SH7750_INTEVT_A7      SH7750_A7_REG32(SH7750_INTEVT_REGOFS)
+#define SH7750_INTEVT_EX    0x00000fff /* Exeption code */
+#define SH7750_INTEVT_EX_S  0
+
+/*
+ * Exception/interrupt codes
+ */
+#define SH7750_EVT_TO_NUM(evt)  ((evt) >> 5)
+
+/* Reset exception category */
+#define SH7750_EVT_POWER_ON_RST        0x000   /* Power-on reset */
+#define SH7750_EVT_MANUAL_RST          0x020   /* Manual reset */
+#define SH7750_EVT_TLB_MULT_HIT        0x140   /* TLB multiple-hit exception */
+
+/* General exception category */
+#define SH7750_EVT_USER_BREAK          0x1E0   /* User break */
+#define SH7750_EVT_IADDR_ERR           0x0E0   /* Instruction address error */
+#define SH7750_EVT_TLB_READ_MISS       0x040   /* ITLB miss exception /
+                                                  DTLB miss exception (read) */
+#define SH7750_EVT_TLB_READ_PROTV      0x0A0   /* ITLB protection violation /
+                                                  DTLB protection violation (read) */
+#define SH7750_EVT_ILLEGAL_INSTR       0x180   /* General Illegal Instruction
+                                                  exception */
+#define SH7750_EVT_SLOT_ILLEGAL_INSTR  0x1A0   /* Slot Illegal Instruction
+                                                  exception */
+#define SH7750_EVT_FPU_DISABLE         0x800   /* General FPU disable exception */
+#define SH7750_EVT_SLOT_FPU_DISABLE    0x820   /* Slot FPU disable exception */
+#define SH7750_EVT_DATA_READ_ERR       0x0E0   /* Data address error (read) */
+#define SH7750_EVT_DATA_WRITE_ERR      0x100   /* Data address error (write) */
+#define SH7750_EVT_DTLB_WRITE_MISS     0x060   /* DTLB miss exception (write) */
+#define SH7750_EVT_DTLB_WRITE_PROTV    0x0C0   /* DTLB protection violation
+                                                  exception (write) */
+#define SH7750_EVT_FPU_EXCEPTION       0x120   /* FPU exception */
+#define SH7750_EVT_INITIAL_PGWRITE     0x080   /* Initial Page Write exception */
+#define SH7750_EVT_TRAPA               0x160   /* Unconditional trap (TRAPA) */
+
+/* Interrupt exception category */
+#define SH7750_EVT_NMI                 0x1C0   /* Non-maskable interrupt */
+#define SH7750_EVT_IRQ0                0x200   /* External Interrupt 0 */
+#define SH7750_EVT_IRQ1                0x220   /* External Interrupt 1 */
+#define SH7750_EVT_IRQ2                0x240   /* External Interrupt 2 */
+#define SH7750_EVT_IRQ3                0x260   /* External Interrupt 3 */
+#define SH7750_EVT_IRQ4                0x280   /* External Interrupt 4 */
+#define SH7750_EVT_IRQ5                0x2A0   /* External Interrupt 5 */
+#define SH7750_EVT_IRQ6                0x2C0   /* External Interrupt 6 */
+#define SH7750_EVT_IRQ7                0x2E0   /* External Interrupt 7 */
+#define SH7750_EVT_IRQ8                0x300   /* External Interrupt 8 */
+#define SH7750_EVT_IRQ9                0x320   /* External Interrupt 9 */
+#define SH7750_EVT_IRQA                0x340   /* External Interrupt A */
+#define SH7750_EVT_IRQB                0x360   /* External Interrupt B */
+#define SH7750_EVT_IRQC                0x380   /* External Interrupt C */
+#define SH7750_EVT_IRQD                0x3A0   /* External Interrupt D */
+#define SH7750_EVT_IRQE                0x3C0   /* External Interrupt E */
+
+/* Peripheral Module Interrupts - Timer Unit (TMU) */
+#define SH7750_EVT_TUNI0               0x400   /* TMU Underflow Interrupt 0 */
+#define SH7750_EVT_TUNI1               0x420   /* TMU Underflow Interrupt 1 */
+#define SH7750_EVT_TUNI2               0x440   /* TMU Underflow Interrupt 2 */
+#define SH7750_EVT_TICPI2              0x460   /* TMU Input Capture Interrupt 2 */
+
+/* Peripheral Module Interrupts - Real-Time Clock (RTC) */
+#define SH7750_EVT_RTC_ATI             0x480   /* Alarm Interrupt Request */
+#define SH7750_EVT_RTC_PRI             0x4A0   /* Periodic Interrupt Request */
+#define SH7750_EVT_RTC_CUI             0x4C0   /* Carry Interrupt Request */
+
+/* Peripheral Module Interrupts - Serial Communication Interface (SCI) */
+#define SH7750_EVT_SCI_ERI             0x4E0   /* Receive Error */
+#define SH7750_EVT_SCI_RXI             0x500   /* Receive Data Register Full */
+#define SH7750_EVT_SCI_TXI             0x520   /* Transmit Data Register Empty */
+#define SH7750_EVT_SCI_TEI             0x540   /* Transmit End */
+
+/* Peripheral Module Interrupts - Watchdog Timer (WDT) */
+#define SH7750_EVT_WDT_ITI             0x560   /* Interval Timer Interrupt
+                                                  (used when WDT operates in
+                                                  interval timer mode) */
+
+/* Peripheral Module Interrupts - Memory Refresh Unit (REF) */
+#define SH7750_EVT_REF_RCMI            0x580   /* Compare-match Interrupt */
+#define SH7750_EVT_REF_ROVI            0x5A0   /* Refresh Counter Overflow
+                                                  interrupt */
+
+/* Peripheral Module Interrupts - Hitachi User Debug Interface (H-UDI) */
+#define SH7750_EVT_HUDI                0x600   /* UDI interrupt */
+
+/* Peripheral Module Interrupts - General-Purpose I/O (GPIO) */
+#define SH7750_EVT_GPIO                0x620   /* GPIO Interrupt */
+
+/* Peripheral Module Interrupts - DMA Controller (DMAC) */
+#define SH7750_EVT_DMAC_DMTE0          0x640   /* DMAC 0 Transfer End Interrupt */
+#define SH7750_EVT_DMAC_DMTE1          0x660   /* DMAC 1 Transfer End Interrupt */
+#define SH7750_EVT_DMAC_DMTE2          0x680   /* DMAC 2 Transfer End Interrupt */
+#define SH7750_EVT_DMAC_DMTE3          0x6A0   /* DMAC 3 Transfer End Interrupt */
+#define SH7750_EVT_DMAC_DMAE           0x6C0   /* DMAC Address Error Interrupt */
+
+/* Peripheral Module Interrupts - Serial Communication Interface with FIFO */
+/*                                                                  (SCIF) */
+#define SH7750_EVT_SCIF_ERI            0x700   /* Receive Error */
+#define SH7750_EVT_SCIF_RXI            0x720   /* Receive FIFO Data Full or
+                                                  Receive Data ready interrupt */
+#define SH7750_EVT_SCIF_BRI            0x740   /* Break or overrun error */
+#define SH7750_EVT_SCIF_TXI            0x760   /* Transmit FIFO Data Empty */
+
+/*
+ * Power Management
+ */
+#define SH7750_STBCR_REGOFS   0xC00004 /* offset */
+#define SH7750_STBCR          SH7750_P4_REG32(SH7750_STBCR_REGOFS)
+#define SH7750_STBCR_A7       SH7750_A7_REG32(SH7750_STBCR_REGOFS)
+
+#define SH7750_STBCR_STBY     0x80     /* Specifies a transition to standby mode:
+                                          0 - Transition to SLEEP mode on SLEEP
+                                          1 - Transition to STANDBY mode on SLEEP */
+#define SH7750_STBCR_PHZ      0x40     /* State of peripheral module pins in
+                                          standby mode:
+                                          0 - normal state
+                                          1 - high-impendance state */
+
+#define SH7750_STBCR_PPU      0x20     /* Peripheral module pins pull-up controls */
+#define SH7750_STBCR_MSTP4    0x10     /* Stopping the clock supply to DMAC */
+#define SH7750_STBCR_DMAC_STP SH7750_STBCR_MSTP4
+#define SH7750_STBCR_MSTP3    0x08     /* Stopping the clock supply to SCIF */
+#define SH7750_STBCR_SCIF_STP SH7750_STBCR_MSTP3
+#define SH7750_STBCR_MSTP2    0x04     /* Stopping the clock supply to TMU */
+#define SH7750_STBCR_TMU_STP  SH7750_STBCR_MSTP2
+#define SH7750_STBCR_MSTP1    0x02     /* Stopping the clock supply to RTC */
+#define SH7750_STBCR_RTC_STP  SH7750_STBCR_MSTP1
+#define SH7750_STBCR_MSPT0    0x01     /* Stopping the clock supply to SCI */
+#define SH7750_STBCR_SCI_STP  SH7750_STBCR_MSTP0
+
+#define SH7750_STBCR_STBY     0x80
+
+
+#define SH7750_STBCR2_REGOFS  0xC00010 /* offset */
+#define SH7750_STBCR2         SH7750_P4_REG32(SH7750_STBCR2_REGOFS)
+#define SH7750_STBCR2_A7      SH7750_A7_REG32(SH7750_STBCR2_REGOFS)
+
+#define SH7750_STBCR2_DSLP    0x80     /* Specifies transition to deep sleep mode:
+                                          0 - transition to sleep or standby mode
+                                          as it is specified in STBY bit
+                                          1 - transition to deep sleep mode on
+                                          execution of SLEEP instruction */
+#define SH7750_STBCR2_MSTP6   0x02     /* Stopping the clock supply to Store Queue
+                                          in the cache controller */
+#define SH7750_STBCR2_SQ_STP  SH7750_STBCR2_MSTP6
+#define SH7750_STBCR2_MSTP5   0x01     /* Stopping the clock supply to the User
+                                          Break Controller (UBC) */
+#define SH7750_STBCR2_UBC_STP SH7750_STBCR2_MSTP5
+
+/*
+ * Clock Pulse Generator (CPG)
+ */
+#define SH7750_FRQCR_REGOFS   0xC00000 /* offset */
+#define SH7750_FRQCR          SH7750_P4_REG32(SH7750_FRQCR_REGOFS)
+#define SH7750_FRQCR_A7       SH7750_A7_REG32(SH7750_FRQCR_REGOFS)
+
+#define SH7750_FRQCR_CKOEN    0x0800   /* Clock Output Enable
+                                          0 - CKIO pin goes to HiZ/pullup
+                                          1 - Clock is output from CKIO */
+#define SH7750_FRQCR_PLL1EN   0x0400   /* PLL circuit 1 enable */
+#define SH7750_FRQCR_PLL2EN   0x0200   /* PLL circuit 2 enable */
+
+#define SH7750_FRQCR_IFC      0x01C0   /* CPU clock frequency division ratio: */
+#define SH7750_FRQCR_IFCDIV1  0x0000   /*    0 - * 1 */
+#define SH7750_FRQCR_IFCDIV2  0x0040   /*    1 - * 1/2 */
+#define SH7750_FRQCR_IFCDIV3  0x0080   /*    2 - * 1/3 */
+#define SH7750_FRQCR_IFCDIV4  0x00C0   /*    3 - * 1/4 */
+#define SH7750_FRQCR_IFCDIV6  0x0100   /*    4 - * 1/6 */
+#define SH7750_FRQCR_IFCDIV8  0x0140   /*    5 - * 1/8 */
+
+#define SH7750_FRQCR_BFC      0x0038   /* Bus clock frequency division ratio: */
+#define SH7750_FRQCR_BFCDIV1  0x0000   /*    0 - * 1 */
+#define SH7750_FRQCR_BFCDIV2  0x0008   /*    1 - * 1/2 */
+#define SH7750_FRQCR_BFCDIV3  0x0010   /*    2 - * 1/3 */
+#define SH7750_FRQCR_BFCDIV4  0x0018   /*    3 - * 1/4 */
+#define SH7750_FRQCR_BFCDIV6  0x0020   /*    4 - * 1/6 */
+#define SH7750_FRQCR_BFCDIV8  0x0028   /*    5 - * 1/8 */
+
+#define SH7750_FRQCR_PFC      0x0007   /* Peripheral module clock frequency
+                                          division ratio: */
+#define SH7750_FRQCR_PFCDIV2  0x0000   /*    0 - * 1/2 */
+#define SH7750_FRQCR_PFCDIV3  0x0001   /*    1 - * 1/3 */
+#define SH7750_FRQCR_PFCDIV4  0x0002   /*    2 - * 1/4 */
+#define SH7750_FRQCR_PFCDIV6  0x0003   /*    3 - * 1/6 */
+#define SH7750_FRQCR_PFCDIV8  0x0004   /*    4 - * 1/8 */
+
+/*
+ * Watchdog Timer (WDT)
+ */
+
+/* Watchdog Timer Counter register - WTCNT */
+#define SH7750_WTCNT_REGOFS   0xC00008 /* offset */
+#define SH7750_WTCNT          SH7750_P4_REG32(SH7750_WTCNT_REGOFS)
+#define SH7750_WTCNT_A7       SH7750_A7_REG32(SH7750_WTCNT_REGOFS)
+#define SH7750_WTCNT_KEY      0x5A00   /* When WTCNT byte register written,
+                                          you have to set the upper byte to
+                                          0x5A */
+
+/* Watchdog Timer Control/Status register - WTCSR */
+#define SH7750_WTCSR_REGOFS   0xC0000C /* offset */
+#define SH7750_WTCSR          SH7750_P4_REG32(SH7750_WTCSR_REGOFS)
+#define SH7750_WTCSR_A7       SH7750_A7_REG32(SH7750_WTCSR_REGOFS)
+#define SH7750_WTCSR_KEY      0xA500   /* When WTCSR byte register written,
+                                          you have to set the upper byte to
+                                          0xA5 */
+#define SH7750_WTCSR_TME      0x80     /* Timer enable (1-upcount start) */
+#define SH7750_WTCSR_MODE     0x40     /* Timer Mode Select: */
+#define SH7750_WTCSR_MODE_WT  0x40     /*    Watchdog Timer Mode */
+#define SH7750_WTCSR_MODE_IT  0x00     /*    Interval Timer Mode */
+#define SH7750_WTCSR_RSTS     0x20     /* Reset Select: */
+#define SH7750_WTCSR_RST_MAN  0x20     /*    Manual Reset */
+#define SH7750_WTCSR_RST_PWR  0x00     /*    Power-on Reset */
+#define SH7750_WTCSR_WOVF     0x10     /* Watchdog Timer Overflow Flag */
+#define SH7750_WTCSR_IOVF     0x08     /* Interval Timer Overflow Flag */
+#define SH7750_WTCSR_CKS      0x07     /* Clock Select: */
+#define SH7750_WTCSR_CKS_DIV32   0x00  /*   1/32 of frequency divider 2 input */
+#define SH7750_WTCSR_CKS_DIV64   0x01  /*   1/64 */
+#define SH7750_WTCSR_CKS_DIV128  0x02  /*   1/128 */
+#define SH7750_WTCSR_CKS_DIV256  0x03  /*   1/256 */
+#define SH7750_WTCSR_CKS_DIV512  0x04  /*   1/512 */
+#define SH7750_WTCSR_CKS_DIV1024 0x05  /*   1/1024 */
+#define SH7750_WTCSR_CKS_DIV2048 0x06  /*   1/2048 */
+#define SH7750_WTCSR_CKS_DIV4096 0x07  /*   1/4096 */
+
+/*
+ * Real-Time Clock (RTC)
+ */
+/* 64-Hz Counter Register (byte, read-only) - R64CNT */
+#define SH7750_R64CNT_REGOFS  0xC80000 /* offset */
+#define SH7750_R64CNT         SH7750_P4_REG32(SH7750_R64CNT_REGOFS)
+#define SH7750_R64CNT_A7      SH7750_A7_REG32(SH7750_R64CNT_REGOFS)
+
+/* Second Counter Register (byte, BCD-coded) - RSECCNT */
+#define SH7750_RSECCNT_REGOFS 0xC80004 /* offset */
+#define SH7750_RSECCNT        SH7750_P4_REG32(SH7750_RSECCNT_REGOFS)
+#define SH7750_RSECCNT_A7     SH7750_A7_REG32(SH7750_RSECCNT_REGOFS)
+
+/* Minute Counter Register (byte, BCD-coded) - RMINCNT */
+#define SH7750_RMINCNT_REGOFS 0xC80008 /* offset */
+#define SH7750_RMINCNT        SH7750_P4_REG32(SH7750_RMINCNT_REGOFS)
+#define SH7750_RMINCNT_A7     SH7750_A7_REG32(SH7750_RMINCNT_REGOFS)
+
+/* Hour Counter Register (byte, BCD-coded) - RHRCNT */
+#define SH7750_RHRCNT_REGOFS  0xC8000C /* offset */
+#define SH7750_RHRCNT         SH7750_P4_REG32(SH7750_RHRCNT_REGOFS)
+#define SH7750_RHRCNT_A7      SH7750_A7_REG32(SH7750_RHRCNT_REGOFS)
+
+/* Day-of-Week Counter Register (byte) - RWKCNT */
+#define SH7750_RWKCNT_REGOFS  0xC80010 /* offset */
+#define SH7750_RWKCNT         SH7750_P4_REG32(SH7750_RWKCNT_REGOFS)
+#define SH7750_RWKCNT_A7      SH7750_A7_REG32(SH7750_RWKCNT_REGOFS)
+
+#define SH7750_RWKCNT_SUN     0        /* Sunday */
+#define SH7750_RWKCNT_MON     1        /* Monday */
+#define SH7750_RWKCNT_TUE     2        /* Tuesday */
+#define SH7750_RWKCNT_WED     3        /* Wednesday */
+#define SH7750_RWKCNT_THU     4        /* Thursday */
+#define SH7750_RWKCNT_FRI     5        /* Friday */
+#define SH7750_RWKCNT_SAT     6        /* Saturday */
+
+/* Day Counter Register (byte, BCD-coded) - RDAYCNT */
+#define SH7750_RDAYCNT_REGOFS 0xC80014 /* offset */
+#define SH7750_RDAYCNT        SH7750_P4_REG32(SH7750_RDAYCNT_REGOFS)
+#define SH7750_RDAYCNT_A7     SH7750_A7_REG32(SH7750_RDAYCNT_REGOFS)
+
+/* Month Counter Register (byte, BCD-coded) - RMONCNT */
+#define SH7750_RMONCNT_REGOFS 0xC80018 /* offset */
+#define SH7750_RMONCNT        SH7750_P4_REG32(SH7750_RMONCNT_REGOFS)
+#define SH7750_RMONCNT_A7     SH7750_A7_REG32(SH7750_RMONCNT_REGOFS)
+
+/* Year Counter Register (half, BCD-coded) - RYRCNT */
+#define SH7750_RYRCNT_REGOFS  0xC8001C /* offset */
+#define SH7750_RYRCNT         SH7750_P4_REG32(SH7750_RYRCNT_REGOFS)
+#define SH7750_RYRCNT_A7      SH7750_A7_REG32(SH7750_RYRCNT_REGOFS)
+
+/* Second Alarm Register (byte, BCD-coded) - RSECAR */
+#define SH7750_RSECAR_REGOFS  0xC80020 /* offset */
+#define SH7750_RSECAR         SH7750_P4_REG32(SH7750_RSECAR_REGOFS)
+#define SH7750_RSECAR_A7      SH7750_A7_REG32(SH7750_RSECAR_REGOFS)
+#define SH7750_RSECAR_ENB     0x80     /* Second Alarm Enable */
+
+/* Minute Alarm Register (byte, BCD-coded) - RMINAR */
+#define SH7750_RMINAR_REGOFS  0xC80024 /* offset */
+#define SH7750_RMINAR         SH7750_P4_REG32(SH7750_RMINAR_REGOFS)
+#define SH7750_RMINAR_A7      SH7750_A7_REG32(SH7750_RMINAR_REGOFS)
+#define SH7750_RMINAR_ENB     0x80     /* Minute Alarm Enable */
+
+/* Hour Alarm Register (byte, BCD-coded) - RHRAR */
+#define SH7750_RHRAR_REGOFS   0xC80028 /* offset */
+#define SH7750_RHRAR          SH7750_P4_REG32(SH7750_RHRAR_REGOFS)
+#define SH7750_RHRAR_A7       SH7750_A7_REG32(SH7750_RHRAR_REGOFS)
+#define SH7750_RHRAR_ENB      0x80     /* Hour Alarm Enable */
+
+/* Day-of-Week Alarm Register (byte) - RWKAR */
+#define SH7750_RWKAR_REGOFS   0xC8002C /* offset */
+#define SH7750_RWKAR          SH7750_P4_REG32(SH7750_RWKAR_REGOFS)
+#define SH7750_RWKAR_A7       SH7750_A7_REG32(SH7750_RWKAR_REGOFS)
+#define SH7750_RWKAR_ENB      0x80     /* Day-of-week Alarm Enable */
+
+#define SH7750_RWKAR_SUN      0        /* Sunday */
+#define SH7750_RWKAR_MON      1        /* Monday */
+#define SH7750_RWKAR_TUE      2        /* Tuesday */
+#define SH7750_RWKAR_WED      3        /* Wednesday */
+#define SH7750_RWKAR_THU      4        /* Thursday */
+#define SH7750_RWKAR_FRI      5        /* Friday */
+#define SH7750_RWKAR_SAT      6        /* Saturday */
+
+/* Day Alarm Register (byte, BCD-coded) - RDAYAR */
+#define SH7750_RDAYAR_REGOFS  0xC80030 /* offset */
+#define SH7750_RDAYAR         SH7750_P4_REG32(SH7750_RDAYAR_REGOFS)
+#define SH7750_RDAYAR_A7      SH7750_A7_REG32(SH7750_RDAYAR_REGOFS)
+#define SH7750_RDAYAR_ENB     0x80     /* Day Alarm Enable */
+
+/* Month Counter Register (byte, BCD-coded) - RMONAR */
+#define SH7750_RMONAR_REGOFS  0xC80034 /* offset */
+#define SH7750_RMONAR         SH7750_P4_REG32(SH7750_RMONAR_REGOFS)
+#define SH7750_RMONAR_A7      SH7750_A7_REG32(SH7750_RMONAR_REGOFS)
+#define SH7750_RMONAR_ENB     0x80     /* Month Alarm Enable */
+
+/* RTC Control Register 1 (byte) - RCR1 */
+#define SH7750_RCR1_REGOFS    0xC80038 /* offset */
+#define SH7750_RCR1           SH7750_P4_REG32(SH7750_RCR1_REGOFS)
+#define SH7750_RCR1_A7        SH7750_A7_REG32(SH7750_RCR1_REGOFS)
+#define SH7750_RCR1_CF        0x80     /* Carry Flag */
+#define SH7750_RCR1_CIE       0x10     /* Carry Interrupt Enable */
+#define SH7750_RCR1_AIE       0x08     /* Alarm Interrupt Enable */
+#define SH7750_RCR1_AF        0x01     /* Alarm Flag */
+
+/* RTC Control Register 2 (byte) - RCR2 */
+#define SH7750_RCR2_REGOFS    0xC8003C /* offset */
+#define SH7750_RCR2           SH7750_P4_REG32(SH7750_RCR2_REGOFS)
+#define SH7750_RCR2_A7        SH7750_A7_REG32(SH7750_RCR2_REGOFS)
+#define SH7750_RCR2_PEF        0x80    /* Periodic Interrupt Flag */
+#define SH7750_RCR2_PES        0x70    /* Periodic Interrupt Enable: */
+#define SH7750_RCR2_PES_DIS    0x00    /*   Periodic Interrupt Disabled */
+#define SH7750_RCR2_PES_DIV256 0x10    /*   Generated at 1/256 sec interval */
+#define SH7750_RCR2_PES_DIV64  0x20    /*   Generated at 1/64 sec interval */
+#define SH7750_RCR2_PES_DIV16  0x30    /*   Generated at 1/16 sec interval */
+#define SH7750_RCR2_PES_DIV4   0x40    /*   Generated at 1/4 sec interval */
+#define SH7750_RCR2_PES_DIV2   0x50    /*   Generated at 1/2 sec interval */
+#define SH7750_RCR2_PES_x1     0x60    /*   Generated at 1 sec interval */
+#define SH7750_RCR2_PES_x2     0x70    /*   Generated at 2 sec interval */
+#define SH7750_RCR2_RTCEN      0x08    /* RTC Crystal Oscillator is Operated */
+#define SH7750_RCR2_ADJ        0x04    /* 30-Second Adjastment */
+#define SH7750_RCR2_RESET      0x02    /* Frequency divider circuits are reset */
+#define SH7750_RCR2_START      0x01    /* 0 - sec, min, hr, day-of-week, month,
+                                          year counters are stopped
+                                          1 - sec, min, hr, day-of-week, month,
+                                          year counters operate normally */
+/*
+ * Bus State Controller - BSC
+ */
+/* Bus Control Register 1 - BCR1 */
+#define SH7750_BCR1_REGOFS    0x800000 /* offset */
+#define SH7750_BCR1           SH7750_P4_REG32(SH7750_BCR1_REGOFS)
+#define SH7750_BCR1_A7        SH7750_A7_REG32(SH7750_BCR1_REGOFS)
+#define SH7750_BCR1_ENDIAN    0x80000000       /* Endianness (1 - little endian) */
+#define SH7750_BCR1_MASTER    0x40000000       /* Master/Slave mode (1-master) */
+#define SH7750_BCR1_A0MPX     0x20000000       /* Area 0 Memory Type (0-SRAM,1-MPX) */
+#define SH7750_BCR1_IPUP      0x02000000       /* Input Pin Pull-up Control:
+                                                  0 - pull-up resistor is on for
+                                                  control input pins
+                                                  1 - pull-up resistor is off */
+#define SH7750_BCR1_OPUP      0x01000000       /* Output Pin Pull-up Control:
+                                                  0 - pull-up resistor is on for
+                                                  control output pins
+                                                  1 - pull-up resistor is off */
+#define SH7750_BCR1_A1MBC     0x00200000       /* Area 1 SRAM Byte Control Mode:
+                                                  0 - Area 1 SRAM is set to
+                                                  normal mode
+                                                  1 - Area 1 SRAM is set to byte
+                                                  control mode */
+#define SH7750_BCR1_A4MBC     0x00100000       /* Area 4 SRAM Byte Control Mode:
+                                                  0 - Area 4 SRAM is set to
+                                                  normal mode
+                                                  1 - Area 4 SRAM is set to byte
+                                                  control mode */
+#define SH7750_BCR1_BREQEN    0x00080000       /* BREQ Enable:
+                                                  0 - External requests are  not
+                                                  accepted
+                                                  1 - External requests are
+                                                  accepted */
+#define SH7750_BCR1_PSHR      0x00040000       /* Partial Sharing Bit:
+                                                  0 - Master Mode
+                                                  1 - Partial-sharing Mode */
+#define SH7750_BCR1_MEMMPX    0x00020000       /* Area 1 to 6 MPX Interface:
+                                                  0 - SRAM/burst ROM interface
+                                                  1 - MPX interface */
+#define SH7750_BCR1_HIZMEM    0x00008000       /* High Impendance Control. Specifies
+                                                  the state of A[25:0], BS\, CSn\,
+                                                  RD/WR\, CE2A\, CE2B\ in standby
+                                                  mode and when bus is released:
+                                                  0 - signals go to High-Z mode
+                                                  1 - signals driven */
+#define SH7750_BCR1_HIZCNT    0x00004000       /* High Impendance Control. Specifies
+                                                  the state of the RAS\, RAS2\, WEn\,
+                                                  CASn\, DQMn, RD\, CASS\, FRAME\,
+                                                  RD2\ signals in standby mode and
+                                                  when bus is released:
+                                                  0 - signals go to High-Z mode
+                                                  1 - signals driven */
+#define SH7750_BCR1_A0BST     0x00003800       /* Area 0 Burst ROM Control */
+#define SH7750_BCR1_A0BST_SRAM    0x0000       /*   Area 0 accessed as SRAM i/f */
+#define SH7750_BCR1_A0BST_ROM4    0x0800       /*   Area 0 accessed as burst ROM
+                                                  interface, 4 cosequtive access */
+#define SH7750_BCR1_A0BST_ROM8    0x1000       /*   Area 0 accessed as burst ROM
+                                                  interface, 8 cosequtive access */
+#define SH7750_BCR1_A0BST_ROM16   0x1800       /*   Area 0 accessed as burst ROM
+                                                  interface, 16 cosequtive access */
+#define SH7750_BCR1_A0BST_ROM32   0x2000       /*   Area 0 accessed as burst ROM
+                                                  interface, 32 cosequtive access */
+
+#define SH7750_BCR1_A5BST     0x00000700       /* Area 5 Burst ROM Control */
+#define SH7750_BCR1_A5BST_SRAM    0x0000       /*   Area 5 accessed as SRAM i/f */
+#define SH7750_BCR1_A5BST_ROM4    0x0100       /*   Area 5 accessed as burst ROM
+                                                  interface, 4 cosequtive access */
+#define SH7750_BCR1_A5BST_ROM8    0x0200       /*   Area 5 accessed as burst ROM
+                                                  interface, 8 cosequtive access */
+#define SH7750_BCR1_A5BST_ROM16   0x0300       /*   Area 5 accessed as burst ROM
+                                                  interface, 16 cosequtive access */
+#define SH7750_BCR1_A5BST_ROM32   0x0400       /*   Area 5 accessed as burst ROM
+                                                  interface, 32 cosequtive access */
+
+#define SH7750_BCR1_A6BST     0x000000E0       /* Area 6 Burst ROM Control */
+#define SH7750_BCR1_A6BST_SRAM    0x0000       /*   Area 6 accessed as SRAM i/f */
+#define SH7750_BCR1_A6BST_ROM4    0x0020       /*   Area 6 accessed as burst ROM
+                                                  interface, 4 cosequtive access */
+#define SH7750_BCR1_A6BST_ROM8    0x0040       /*   Area 6 accessed as burst ROM
+                                                  interface, 8 cosequtive access */
+#define SH7750_BCR1_A6BST_ROM16   0x0060       /*   Area 6 accessed as burst ROM
+                                                  interface, 16 cosequtive access */
+#define SH7750_BCR1_A6BST_ROM32   0x0080       /*   Area 6 accessed as burst ROM
+                                                  interface, 32 cosequtive access */
+
+#define SH7750_BCR1_DRAMTP        0x001C       /* Area 2 and 3 Memory Type */
+#define SH7750_BCR1_DRAMTP_2SRAM_3SRAM   0x0000        /* Area 2 and 3 are SRAM or MPX
+                                                  interface. */
+#define SH7750_BCR1_DRAMTP_2SRAM_3SDRAM  0x0008        /* Area 2 - SRAM/MPX, Area 3 -
+                                                  synchronous DRAM */
+#define SH7750_BCR1_DRAMTP_2SDRAM_3SDRAM 0x000C        /* Area 2 and 3 are synchronous
+                                                  DRAM interface */
+#define SH7750_BCR1_DRAMTP_2SRAM_3DRAM   0x0010        /* Area 2 - SRAM/MPX, Area 3 -
+                                                  DRAM interface */
+#define SH7750_BCR1_DRAMTP_2DRAM_3DRAM   0x0014        /* Area 2 and 3 are DRAM
+                                                  interface */
+
+#define SH7750_BCR1_A56PCM    0x00000001       /* Area 5 and 6 Bus Type:
+                                                  0 - SRAM interface
+                                                  1 - PCMCIA interface */
+
+/* Bus Control Register 2 (half) - BCR2 */
+#define SH7750_BCR2_REGOFS    0x800004 /* offset */
+#define SH7750_BCR2           SH7750_P4_REG32(SH7750_BCR2_REGOFS)
+#define SH7750_BCR2_A7        SH7750_A7_REG32(SH7750_BCR2_REGOFS)
+
+#define SH7750_BCR2_A0SZ      0xC000   /* Area 0 Bus Width */
+#define SH7750_BCR2_A0SZ_S    14
+#define SH7750_BCR2_A6SZ      0x3000   /* Area 6 Bus Width */
+#define SH7750_BCR2_A6SZ_S    12
+#define SH7750_BCR2_A5SZ      0x0C00   /* Area 5 Bus Width */
+#define SH7750_BCR2_A5SZ_S    10
+#define SH7750_BCR2_A4SZ      0x0300   /* Area 4 Bus Width */
+#define SH7750_BCR2_A4SZ_S    8
+#define SH7750_BCR2_A3SZ      0x00C0   /* Area 3 Bus Width */
+#define SH7750_BCR2_A3SZ_S    6
+#define SH7750_BCR2_A2SZ      0x0030   /* Area 2 Bus Width */
+#define SH7750_BCR2_A2SZ_S    4
+#define SH7750_BCR2_A1SZ      0x000C   /* Area 1 Bus Width */
+#define SH7750_BCR2_A1SZ_S    2
+#define SH7750_BCR2_SZ_64     0        /* 64 bits */
+#define SH7750_BCR2_SZ_8      1        /* 8 bits */
+#define SH7750_BCR2_SZ_16     2        /* 16 bits */
+#define SH7750_BCR2_SZ_32     3        /* 32 bits */
+#define SH7750_BCR2_PORTEN    0x0001   /* Port Function Enable :
+                                          0 - D51-D32 are not used as a port
+                                          1 - D51-D32 are used as a port */
+
+/* Wait Control Register 1 - WCR1 */
+#define SH7750_WCR1_REGOFS    0x800008 /* offset */
+#define SH7750_WCR1           SH7750_P4_REG32(SH7750_WCR1_REGOFS)
+#define SH7750_WCR1_A7        SH7750_A7_REG32(SH7750_WCR1_REGOFS)
+#define SH7750_WCR1_DMAIW     0x70000000       /* DACK Device Inter-Cycle Idle
+                                                  specification */
+#define SH7750_WCR1_DMAIW_S   28
+#define SH7750_WCR1_A6IW      0x07000000       /* Area 6 Inter-Cycle Idle spec. */
+#define SH7750_WCR1_A6IW_S    24
+#define SH7750_WCR1_A5IW      0x00700000       /* Area 5 Inter-Cycle Idle spec. */
+#define SH7750_WCR1_A5IW_S    20
+#define SH7750_WCR1_A4IW      0x00070000       /* Area 4 Inter-Cycle Idle spec. */
+#define SH7750_WCR1_A4IW_S    16
+#define SH7750_WCR1_A3IW      0x00007000       /* Area 3 Inter-Cycle Idle spec. */
+#define SH7750_WCR1_A3IW_S    12
+#define SH7750_WCR1_A2IW      0x00000700       /* Area 2 Inter-Cycle Idle spec. */
+#define SH7750_WCR1_A2IW_S    8
+#define SH7750_WCR1_A1IW      0x00000070       /* Area 1 Inter-Cycle Idle spec. */
+#define SH7750_WCR1_A1IW_S    4
+#define SH7750_WCR1_A0IW      0x00000007       /* Area 0 Inter-Cycle Idle spec. */
+#define SH7750_WCR1_A0IW_S    0
+
+/* Wait Control Register 2 - WCR2 */
+#define SH7750_WCR2_REGOFS    0x80000C /* offset */
+#define SH7750_WCR2           SH7750_P4_REG32(SH7750_WCR2_REGOFS)
+#define SH7750_WCR2_A7        SH7750_A7_REG32(SH7750_WCR2_REGOFS)
+
+#define SH7750_WCR2_A6W       0xE0000000       /* Area 6 Wait Control */
+#define SH7750_WCR2_A6W_S     29
+#define SH7750_WCR2_A6B       0x1C000000       /* Area 6 Burst Pitch */
+#define SH7750_WCR2_A6B_S     26
+#define SH7750_WCR2_A5W       0x03800000       /* Area 5 Wait Control */
+#define SH7750_WCR2_A5W_S     23
+#define SH7750_WCR2_A5B       0x00700000       /* Area 5 Burst Pitch */
+#define SH7750_WCR2_A5B_S     20
+#define SH7750_WCR2_A4W       0x000E0000       /* Area 4 Wait Control */
+#define SH7750_WCR2_A4W_S     17
+#define SH7750_WCR2_A3W       0x0000E000       /* Area 3 Wait Control */
+#define SH7750_WCR2_A3W_S     13
+#define SH7750_WCR2_A2W       0x00000E00       /* Area 2 Wait Control */
+#define SH7750_WCR2_A2W_S     9
+#define SH7750_WCR2_A1W       0x000001C0       /* Area 1 Wait Control */
+#define SH7750_WCR2_A1W_S     6
+#define SH7750_WCR2_A0W       0x00000038       /* Area 0 Wait Control */
+#define SH7750_WCR2_A0W_S     3
+#define SH7750_WCR2_A0B       0x00000007       /* Area 0 Burst Pitch */
+#define SH7750_WCR2_A0B_S     0
+
+#define SH7750_WCR2_WS0       0        /* 0 wait states inserted */
+#define SH7750_WCR2_WS1       1        /* 1 wait states inserted */
+#define SH7750_WCR2_WS2       2        /* 2 wait states inserted */
+#define SH7750_WCR2_WS3       3        /* 3 wait states inserted */
+#define SH7750_WCR2_WS6       4        /* 6 wait states inserted */
+#define SH7750_WCR2_WS9       5        /* 9 wait states inserted */
+#define SH7750_WCR2_WS12      6        /* 12 wait states inserted */
+#define SH7750_WCR2_WS15      7        /* 15 wait states inserted */
+
+#define SH7750_WCR2_BPWS0     0        /* 0 wait states inserted from 2nd access */
+#define SH7750_WCR2_BPWS1     1        /* 1 wait states inserted from 2nd access */
+#define SH7750_WCR2_BPWS2     2        /* 2 wait states inserted from 2nd access */
+#define SH7750_WCR2_BPWS3     3        /* 3 wait states inserted from 2nd access */
+#define SH7750_WCR2_BPWS4     4        /* 4 wait states inserted from 2nd access */
+#define SH7750_WCR2_BPWS5     5        /* 5 wait states inserted from 2nd access */
+#define SH7750_WCR2_BPWS6     6        /* 6 wait states inserted from 2nd access */
+#define SH7750_WCR2_BPWS7     7        /* 7 wait states inserted from 2nd access */
+
+/* DRAM CAS\ Assertion Delay (area 3,2) */
+#define SH7750_WCR2_DRAM_CAS_ASW1   0  /* 1 cycle */
+#define SH7750_WCR2_DRAM_CAS_ASW2   1  /* 2 cycles */
+#define SH7750_WCR2_DRAM_CAS_ASW3   2  /* 3 cycles */
+#define SH7750_WCR2_DRAM_CAS_ASW4   3  /* 4 cycles */
+#define SH7750_WCR2_DRAM_CAS_ASW7   4  /* 7 cycles */
+#define SH7750_WCR2_DRAM_CAS_ASW10  5  /* 10 cycles */
+#define SH7750_WCR2_DRAM_CAS_ASW13  6  /* 13 cycles */
+#define SH7750_WCR2_DRAM_CAS_ASW16  7  /* 16 cycles */
+
+/* SDRAM CAS\ Latency Cycles */
+#define SH7750_WCR2_SDRAM_CAS_LAT1  1  /* 1 cycle */
+#define SH7750_WCR2_SDRAM_CAS_LAT2  2  /* 2 cycles */
+#define SH7750_WCR2_SDRAM_CAS_LAT3  3  /* 3 cycles */
+#define SH7750_WCR2_SDRAM_CAS_LAT4  4  /* 4 cycles */
+#define SH7750_WCR2_SDRAM_CAS_LAT5  5  /* 5 cycles */
+
+/* Wait Control Register 3 - WCR3 */
+#define SH7750_WCR3_REGOFS    0x800010 /* offset */
+#define SH7750_WCR3           SH7750_P4_REG32(SH7750_WCR3_REGOFS)
+#define SH7750_WCR3_A7        SH7750_A7_REG32(SH7750_WCR3_REGOFS)
+
+#define SH7750_WCR3_A6S       0x04000000       /* Area 6 Write Strobe Setup time */
+#define SH7750_WCR3_A6H       0x03000000       /* Area 6 Data Hold Time */
+#define SH7750_WCR3_A6H_S     24
+#define SH7750_WCR3_A5S       0x00400000       /* Area 5 Write Strobe Setup time */
+#define SH7750_WCR3_A5H       0x00300000       /* Area 5 Data Hold Time */
+#define SH7750_WCR3_A5H_S     20
+#define SH7750_WCR3_A4S       0x00040000       /* Area 4 Write Strobe Setup time */
+#define SH7750_WCR3_A4H       0x00030000       /* Area 4 Data Hold Time */
+#define SH7750_WCR3_A4H_S     16
+#define SH7750_WCR3_A3S       0x00004000       /* Area 3 Write Strobe Setup time */
+#define SH7750_WCR3_A3H       0x00003000       /* Area 3 Data Hold Time */
+#define SH7750_WCR3_A3H_S     12
+#define SH7750_WCR3_A2S       0x00000400       /* Area 2 Write Strobe Setup time */
+#define SH7750_WCR3_A2H       0x00000300       /* Area 2 Data Hold Time */
+#define SH7750_WCR3_A2H_S     8
+#define SH7750_WCR3_A1S       0x00000040       /* Area 1 Write Strobe Setup time */
+#define SH7750_WCR3_A1H       0x00000030       /* Area 1 Data Hold Time */
+#define SH7750_WCR3_A1H_S     4
+#define SH7750_WCR3_A0S       0x00000004       /* Area 0 Write Strobe Setup time */
+#define SH7750_WCR3_A0H       0x00000003       /* Area 0 Data Hold Time */
+#define SH7750_WCR3_A0H_S     0
+
+#define SH7750_WCR3_DHWS_0    0        /* 0 wait states data hold time */
+#define SH7750_WCR3_DHWS_1    1        /* 1 wait states data hold time */
+#define SH7750_WCR3_DHWS_2    2        /* 2 wait states data hold time */
+#define SH7750_WCR3_DHWS_3    3        /* 3 wait states data hold time */
+
+#define SH7750_MCR_REGOFS     0x800014 /* offset */
+#define SH7750_MCR            SH7750_P4_REG32(SH7750_MCR_REGOFS)
+#define SH7750_MCR_A7         SH7750_A7_REG32(SH7750_MCR_REGOFS)
+
+#define SH7750_MCR_RASD       0x80000000       /* RAS Down mode */
+#define SH7750_MCR_MRSET      0x40000000       /* SDRAM Mode Register Set */
+#define SH7750_MCR_PALL       0x00000000       /* SDRAM Precharge All cmd. Mode */
+#define SH7750_MCR_TRC        0x38000000       /* RAS Precharge Time at End of
+                                                  Refresh: */
+#define SH7750_MCR_TRC_0      0x00000000       /*    0 */
+#define SH7750_MCR_TRC_3      0x08000000       /*    3 */
+#define SH7750_MCR_TRC_6      0x10000000       /*    6 */
+#define SH7750_MCR_TRC_9      0x18000000       /*    9 */
+#define SH7750_MCR_TRC_12     0x20000000       /*    12 */
+#define SH7750_MCR_TRC_15     0x28000000       /*    15 */
+#define SH7750_MCR_TRC_18     0x30000000       /*    18 */
+#define SH7750_MCR_TRC_21     0x38000000       /*    21 */
+
+#define SH7750_MCR_TCAS       0x00800000       /* CAS Negation Period */
+#define SH7750_MCR_TCAS_1     0x00000000       /*    1 */
+#define SH7750_MCR_TCAS_2     0x00800000       /*    2 */
+
+#define SH7750_MCR_TPC        0x00380000       /* DRAM: RAS Precharge Period
+                                                  SDRAM: minimum number of cycles
+                                                  until the next bank active cmd
+                                                  is output after precharging */
+#define SH7750_MCR_TPC_S      19
+#define SH7750_MCR_TPC_SDRAM_1 0x00000000      /* 1 cycle */
+#define SH7750_MCR_TPC_SDRAM_2 0x00080000      /* 2 cycles */
+#define SH7750_MCR_TPC_SDRAM_3 0x00100000      /* 3 cycles */
+#define SH7750_MCR_TPC_SDRAM_4 0x00180000      /* 4 cycles */
+#define SH7750_MCR_TPC_SDRAM_5 0x00200000      /* 5 cycles */
+#define SH7750_MCR_TPC_SDRAM_6 0x00280000      /* 6 cycles */
+#define SH7750_MCR_TPC_SDRAM_7 0x00300000      /* 7 cycles */
+#define SH7750_MCR_TPC_SDRAM_8 0x00380000      /* 8 cycles */
+
+#define SH7750_MCR_RCD        0x00030000       /* DRAM: RAS-CAS Assertion Delay time
+                                                  SDRAM: bank active-read/write cmd
+                                                  delay time */
+#define SH7750_MCR_RCD_DRAM_2  0x00000000      /* DRAM delay 2 clocks */
+#define SH7750_MCR_RCD_DRAM_3  0x00010000      /* DRAM delay 3 clocks */
+#define SH7750_MCR_RCD_DRAM_4  0x00020000      /* DRAM delay 4 clocks */
+#define SH7750_MCR_RCD_DRAM_5  0x00030000      /* DRAM delay 5 clocks */
+#define SH7750_MCR_RCD_SDRAM_2 0x00010000      /* DRAM delay 2 clocks */
+#define SH7750_MCR_RCD_SDRAM_3 0x00020000      /* DRAM delay 3 clocks */
+#define SH7750_MCR_RCD_SDRAM_4 0x00030000      /* DRAM delay 4 clocks */
+
+#define SH7750_MCR_TRWL       0x0000E000       /* SDRAM Write Precharge Delay */
+#define SH7750_MCR_TRWL_1     0x00000000       /*    1 */
+#define SH7750_MCR_TRWL_2     0x00002000       /*    2 */
+#define SH7750_MCR_TRWL_3     0x00004000       /*    3 */
+#define SH7750_MCR_TRWL_4     0x00006000       /*    4 */
+#define SH7750_MCR_TRWL_5     0x00008000       /*    5 */
+
+#define SH7750_MCR_TRAS       0x00001C00       /* DRAM: CAS-Before-RAS Refresh RAS
+                                                  asserting period
+                                                  SDRAM: Command interval after
+                                                  synchronous DRAM refresh */
+#define SH7750_MCR_TRAS_DRAM_2         0x00000000      /* 2 */
+#define SH7750_MCR_TRAS_DRAM_3         0x00000400      /* 3 */
+#define SH7750_MCR_TRAS_DRAM_4         0x00000800      /* 4 */
+#define SH7750_MCR_TRAS_DRAM_5         0x00000C00      /* 5 */
+#define SH7750_MCR_TRAS_DRAM_6         0x00001000      /* 6 */
+#define SH7750_MCR_TRAS_DRAM_7         0x00001400      /* 7 */
+#define SH7750_MCR_TRAS_DRAM_8         0x00001800      /* 8 */
+#define SH7750_MCR_TRAS_DRAM_9         0x00001C00      /* 9 */
+
+#define SH7750_MCR_TRAS_SDRAM_TRC_4    0x00000000      /* 4 + TRC */
+#define SH7750_MCR_TRAS_SDRAM_TRC_5    0x00000400      /* 5 + TRC */
+#define SH7750_MCR_TRAS_SDRAM_TRC_6    0x00000800      /* 6 + TRC */
+#define SH7750_MCR_TRAS_SDRAM_TRC_7    0x00000C00      /* 7 + TRC */
+#define SH7750_MCR_TRAS_SDRAM_TRC_8    0x00001000      /* 8 + TRC */
+#define SH7750_MCR_TRAS_SDRAM_TRC_9    0x00001400      /* 9 + TRC */
+#define SH7750_MCR_TRAS_SDRAM_TRC_10   0x00001800      /* 10 + TRC */
+#define SH7750_MCR_TRAS_SDRAM_TRC_11   0x00001C00      /* 11 + TRC */
+
+#define SH7750_MCR_BE         0x00000200       /* Burst Enable */
+#define SH7750_MCR_SZ         0x00000180       /* Memory Data Size */
+#define SH7750_MCR_SZ_64      0x00000000       /*    64 bits */
+#define SH7750_MCR_SZ_16      0x00000100       /*    16 bits */
+#define SH7750_MCR_SZ_32      0x00000180       /*    32 bits */
+
+#define SH7750_MCR_AMX        0x00000078       /* Address Multiplexing */
+#define SH7750_MCR_AMX_S      3
+#define SH7750_MCR_AMX_DRAM_8BIT_COL    0x00000000     /* 8-bit column addr */
+#define SH7750_MCR_AMX_DRAM_9BIT_COL    0x00000008     /* 9-bit column addr */
+#define SH7750_MCR_AMX_DRAM_10BIT_COL   0x00000010     /* 10-bit column addr */
+#define SH7750_MCR_AMX_DRAM_11BIT_COL   0x00000018     /* 11-bit column addr */
+#define SH7750_MCR_AMX_DRAM_12BIT_COL   0x00000020     /* 12-bit column addr */
+/* See SH7750 Hardware Manual for SDRAM address multiplexor selection */
+
+#define SH7750_MCR_RFSH       0x00000004       /* Refresh Control */
+#define SH7750_MCR_RMODE      0x00000002       /* Refresh Mode: */
+#define SH7750_MCR_RMODE_NORMAL 0x00000000     /* Normal Refresh Mode */
+#define SH7750_MCR_RMODE_SELF   0x00000002     /* Self-Refresh Mode */
+#define SH7750_MCR_RMODE_EDO    0x00000001     /* EDO Mode */
+
+/* SDRAM Mode Set address */
+#define SH7750_SDRAM_MODE_A2_BASE  0xFF900000
+#define SH7750_SDRAM_MODE_A3_BASE  0xFF940000
+#define SH7750_SDRAM_MODE_A2_32BIT(x) (SH7750_SDRAM_MODE_A2_BASE + ((x) << 2))
+#define SH7750_SDRAM_MODE_A3_32BIT(x) (SH7750_SDRAM_MODE_A3_BASE + ((x) << 2))
+#define SH7750_SDRAM_MODE_A2_64BIT(x) (SH7750_SDRAM_MODE_A2_BASE + ((x) << 3))
+#define SH7750_SDRAM_MODE_A3_64BIT(x) (SH7750_SDRAM_MODE_A3_BASE + ((x) << 3))
+
+
+/* PCMCIA Control Register (half) - PCR */
+#define SH7750_PCR_REGOFS     0x800018 /* offset */
+#define SH7750_PCR            SH7750_P4_REG32(SH7750_PCR_REGOFS)
+#define SH7750_PCR_A7         SH7750_A7_REG32(SH7750_PCR_REGOFS)
+
+#define SH7750_PCR_A5PCW      0xC000   /* Area 5 PCMCIA Wait - Number of wait
+                                          states to be added to the number of
+                                          waits specified by WCR2 in a low-speed
+                                          PCMCIA wait cycle */
+#define SH7750_PCR_A5PCW_0    0x0000   /*    0 waits inserted */
+#define SH7750_PCR_A5PCW_15   0x4000   /*    15 waits inserted */
+#define SH7750_PCR_A5PCW_30   0x8000   /*    30 waits inserted */
+#define SH7750_PCR_A5PCW_50   0xC000   /*    50 waits inserted */
+
+#define SH7750_PCR_A6PCW      0x3000   /* Area 6 PCMCIA Wait - Number of wait
+                                          states to be added to the number of
+                                          waits specified by WCR2 in a low-speed
+                                          PCMCIA wait cycle */
+#define SH7750_PCR_A6PCW_0    0x0000   /*    0 waits inserted */
+#define SH7750_PCR_A6PCW_15   0x1000   /*    15 waits inserted */
+#define SH7750_PCR_A6PCW_30   0x2000   /*    30 waits inserted */
+#define SH7750_PCR_A6PCW_50   0x3000   /*    50 waits inserted */
+
+#define SH7750_PCR_A5TED      0x0E00   /* Area 5 Address-OE\/WE\ Assertion Delay,
+                                          delay time from address output to
+                                          OE\/WE\ assertion on the connected
+                                          PCMCIA interface */
+#define SH7750_PCR_A5TED_S    9
+#define SH7750_PCR_A6TED      0x01C0   /* Area 6 Address-OE\/WE\ Assertion Delay */
+#define SH7750_PCR_A6TED_S    6
+
+#define SH7750_PCR_TED_0WS    0        /* 0 Waits inserted */
+#define SH7750_PCR_TED_1WS    1        /* 1 Waits inserted */
+#define SH7750_PCR_TED_2WS    2        /* 2 Waits inserted */
+#define SH7750_PCR_TED_3WS    3        /* 3 Waits inserted */
+#define SH7750_PCR_TED_6WS    4        /* 6 Waits inserted */
+#define SH7750_PCR_TED_9WS    5        /* 9 Waits inserted */
+#define SH7750_PCR_TED_12WS   6        /* 12 Waits inserted */
+#define SH7750_PCR_TED_15WS   7        /* 15 Waits inserted */
+
+#define SH7750_PCR_A5TEH      0x0038   /* Area 5 OE\/WE\ Negation Address delay,
+                                          address hold delay time from OE\/WE\
+                                          negation in a write on the connected
+                                          PCMCIA interface */
+#define SH7750_PCR_A5TEH_S    3
+
+#define SH7750_PCR_A6TEH      0x0007   /* Area 6 OE\/WE\ Negation Address delay */
+#define SH7750_PCR_A6TEH_S    0
+
+#define SH7750_PCR_TEH_0WS    0        /* 0 Waits inserted */
+#define SH7750_PCR_TEH_1WS    1        /* 1 Waits inserted */
+#define SH7750_PCR_TEH_2WS    2        /* 2 Waits inserted */
+#define SH7750_PCR_TEH_3WS    3        /* 3 Waits inserted */
+#define SH7750_PCR_TEH_6WS    4        /* 6 Waits inserted */
+#define SH7750_PCR_TEH_9WS    5        /* 9 Waits inserted */
+#define SH7750_PCR_TEH_12WS   6        /* 12 Waits inserted */
+#define SH7750_PCR_TEH_15WS   7        /* 15 Waits inserted */
+
+/* Refresh Timer Control/Status Register (half) - RTSCR */
+#define SH7750_RTCSR_REGOFS   0x80001C /* offset */
+#define SH7750_RTCSR          SH7750_P4_REG32(SH7750_RTCSR_REGOFS)
+#define SH7750_RTCSR_A7       SH7750_A7_REG32(SH7750_RTCSR_REGOFS)
+
+#define SH7750_RTCSR_KEY      0xA500   /* RTCSR write key */
+#define SH7750_RTCSR_CMF      0x0080   /* Compare-Match Flag (indicates a
+                                          match between the refresh timer
+                                          counter and refresh time constant) */
+#define SH7750_RTCSR_CMIE     0x0040   /* Compare-Match Interrupt Enable */
+#define SH7750_RTCSR_CKS      0x0038   /* Refresh Counter Clock Selects */
+#define SH7750_RTCSR_CKS_DIS          0x0000   /* Clock Input Disabled */
+#define SH7750_RTCSR_CKS_CKIO_DIV4    0x0008   /* Bus Clock / 4 */
+#define SH7750_RTCSR_CKS_CKIO_DIV16   0x0010   /* Bus Clock / 16 */
+#define SH7750_RTCSR_CKS_CKIO_DIV64   0x0018   /* Bus Clock / 64 */
+#define SH7750_RTCSR_CKS_CKIO_DIV256  0x0020   /* Bus Clock / 256 */
+#define SH7750_RTCSR_CKS_CKIO_DIV1024 0x0028   /* Bus Clock / 1024 */
+#define SH7750_RTCSR_CKS_CKIO_DIV2048 0x0030   /* Bus Clock / 2048 */
+#define SH7750_RTCSR_CKS_CKIO_DIV4096 0x0038   /* Bus Clock / 4096 */
+
+#define SH7750_RTCSR_OVF      0x0004   /* Refresh Count Overflow Flag */
+#define SH7750_RTCSR_OVIE     0x0002   /* Refresh Count Overflow Interrupt
+                                          Enable */
+#define SH7750_RTCSR_LMTS     0x0001   /* Refresh Count Overflow Limit Select */
+#define SH7750_RTCSR_LMTS_1024 0x0000  /* Count Limit is 1024 */
+#define SH7750_RTCSR_LMTS_512  0x0001  /* Count Limit is 512 */
+
+/* Refresh Timer Counter (half) - RTCNT */
+#define SH7750_RTCNT_REGOFS   0x800020 /* offset */
+#define SH7750_RTCNT          SH7750_P4_REG32(SH7750_RTCNT_REGOFS)
+#define SH7750_RTCNT_A7       SH7750_A7_REG32(SH7750_RTCNT_REGOFS)
+
+#define SH7750_RTCNT_KEY      0xA500   /* RTCNT write key */
+
+/* Refresh Time Constant Register (half) - RTCOR */
+#define SH7750_RTCOR_REGOFS   0x800024 /* offset */
+#define SH7750_RTCOR          SH7750_P4_REG32(SH7750_RTCOR_REGOFS)
+#define SH7750_RTCOR_A7       SH7750_A7_REG32(SH7750_RTCOR_REGOFS)
+
+#define SH7750_RTCOR_KEY      0xA500   /* RTCOR write key */
+
+/* Refresh Count Register (half) - RFCR */
+#define SH7750_RFCR_REGOFS    0x800028 /* offset */
+#define SH7750_RFCR           SH7750_P4_REG32(SH7750_RFCR_REGOFS)
+#define SH7750_RFCR_A7        SH7750_A7_REG32(SH7750_RFCR_REGOFS)
+
+#define SH7750_RFCR_KEY       0xA400   /* RFCR write key */
+
+/* Synchronous DRAM mode registers - SDMR */
+#define SH7750_SDMR2_REGOFS   0x900000 /* base offset */
+#define SH7750_SDMR2_REGNB    0x0FFC   /* nb of register */
+#define SH7750_SDMR2          SH7750_P4_REG32(SH7750_SDMR2_REGOFS)
+#define SH7750_SDMR2_A7       SH7750_A7_REG32(SH7750_SDMR2_REGOFS)
+
+#define SH7750_SDMR3_REGOFS   0x940000 /* offset */
+#define SH7750_SDMR3_REGNB    0x0FFC   /* nb of register */
+#define SH7750_SDMR3          SH7750_P4_REG32(SH7750_SDMR3_REGOFS)
+#define SH7750_SDMR3_A7       SH7750_A7_REG32(SH7750_SDMR3_REGOFS)
+
+/*
+ * Direct Memory Access Controller (DMAC)
+ */
+
+/* DMA Source Address Register - SAR0, SAR1, SAR2, SAR3 */
+#define SH7750_SAR_REGOFS(n)  (0xA00000 + ((n)*16))    /* offset */
+#define SH7750_SAR(n)         SH7750_P4_REG32(SH7750_SAR_REGOFS(n))
+#define SH7750_SAR_A7(n)      SH7750_A7_REG32(SH7750_SAR_REGOFS(n))
+#define SH7750_SAR0           SH7750_SAR(0)
+#define SH7750_SAR1           SH7750_SAR(1)
+#define SH7750_SAR2           SH7750_SAR(2)
+#define SH7750_SAR3           SH7750_SAR(3)
+#define SH7750_SAR0_A7        SH7750_SAR_A7(0)
+#define SH7750_SAR1_A7        SH7750_SAR_A7(1)
+#define SH7750_SAR2_A7        SH7750_SAR_A7(2)
+#define SH7750_SAR3_A7        SH7750_SAR_A7(3)
+
+/* DMA Destination Address Register - DAR0, DAR1, DAR2, DAR3 */
+#define SH7750_DAR_REGOFS(n)  (0xA00004 + ((n)*16))    /* offset */
+#define SH7750_DAR(n)         SH7750_P4_REG32(SH7750_DAR_REGOFS(n))
+#define SH7750_DAR_A7(n)      SH7750_A7_REG32(SH7750_DAR_REGOFS(n))
+#define SH7750_DAR0           SH7750_DAR(0)
+#define SH7750_DAR1           SH7750_DAR(1)
+#define SH7750_DAR2           SH7750_DAR(2)
+#define SH7750_DAR3           SH7750_DAR(3)
+#define SH7750_DAR0_A7        SH7750_DAR_A7(0)
+#define SH7750_DAR1_A7        SH7750_DAR_A7(1)
+#define SH7750_DAR2_A7        SH7750_DAR_A7(2)
+#define SH7750_DAR3_A7        SH7750_DAR_A7(3)
+
+/* DMA Transfer Count Register - DMATCR0, DMATCR1, DMATCR2, DMATCR3 */
+#define SH7750_DMATCR_REGOFS(n)  (0xA00008 + ((n)*16)) /* offset */
+#define SH7750_DMATCR(n)      SH7750_P4_REG32(SH7750_DMATCR_REGOFS(n))
+#define SH7750_DMATCR_A7(n)   SH7750_A7_REG32(SH7750_DMATCR_REGOFS(n))
+#define SH7750_DMATCR0_P4     SH7750_DMATCR(0)
+#define SH7750_DMATCR1_P4     SH7750_DMATCR(1)
+#define SH7750_DMATCR2_P4     SH7750_DMATCR(2)
+#define SH7750_DMATCR3_P4     SH7750_DMATCR(3)
+#define SH7750_DMATCR0_A7     SH7750_DMATCR_A7(0)
+#define SH7750_DMATCR1_A7     SH7750_DMATCR_A7(1)
+#define SH7750_DMATCR2_A7     SH7750_DMATCR_A7(2)
+#define SH7750_DMATCR3_A7     SH7750_DMATCR_A7(3)
+
+/* DMA Channel Control Register - CHCR0, CHCR1, CHCR2, CHCR3 */
+#define SH7750_CHCR_REGOFS(n)  (0xA0000C + ((n)*16))   /* offset */
+#define SH7750_CHCR(n)        SH7750_P4_REG32(SH7750_CHCR_REGOFS(n))
+#define SH7750_CHCR_A7(n)     SH7750_A7_REG32(SH7750_CHCR_REGOFS(n))
+#define SH7750_CHCR0          SH7750_CHCR(0)
+#define SH7750_CHCR1          SH7750_CHCR(1)
+#define SH7750_CHCR2          SH7750_CHCR(2)
+#define SH7750_CHCR3          SH7750_CHCR(3)
+#define SH7750_CHCR0_A7       SH7750_CHCR_A7(0)
+#define SH7750_CHCR1_A7       SH7750_CHCR_A7(1)
+#define SH7750_CHCR2_A7       SH7750_CHCR_A7(2)
+#define SH7750_CHCR3_A7       SH7750_CHCR_A7(3)
+
+#define SH7750_CHCR_SSA       0xE0000000       /* Source Address Space Attribute */
+#define SH7750_CHCR_SSA_PCMCIA  0x00000000     /* Reserved in PCMCIA access */
+#define SH7750_CHCR_SSA_DYNBSZ  0x20000000     /* Dynamic Bus Sizing I/O space */
+#define SH7750_CHCR_SSA_IO8     0x40000000     /* 8-bit I/O space */
+#define SH7750_CHCR_SSA_IO16    0x60000000     /* 16-bit I/O space */
+#define SH7750_CHCR_SSA_CMEM8   0x80000000     /* 8-bit common memory space */
+#define SH7750_CHCR_SSA_CMEM16  0xA0000000     /* 16-bit common memory space */
+#define SH7750_CHCR_SSA_AMEM8   0xC0000000     /* 8-bit attribute memory space */
+#define SH7750_CHCR_SSA_AMEM16  0xE0000000     /* 16-bit attribute memory space */
+
+#define SH7750_CHCR_STC       0x10000000       /* Source Address Wait Control Select,
+                                                  specifies CS5 or CS6 space wait
+                                                  control for PCMCIA access */
+
+#define SH7750_CHCR_DSA       0x0E000000       /* Source Address Space Attribute */
+#define SH7750_CHCR_DSA_PCMCIA  0x00000000     /* Reserved in PCMCIA access */
+#define SH7750_CHCR_DSA_DYNBSZ  0x02000000     /* Dynamic Bus Sizing I/O space */
+#define SH7750_CHCR_DSA_IO8     0x04000000     /* 8-bit I/O space */
+#define SH7750_CHCR_DSA_IO16    0x06000000     /* 16-bit I/O space */
+#define SH7750_CHCR_DSA_CMEM8   0x08000000     /* 8-bit common memory space */
+#define SH7750_CHCR_DSA_CMEM16  0x0A000000     /* 16-bit common memory space */
+#define SH7750_CHCR_DSA_AMEM8   0x0C000000     /* 8-bit attribute memory space */
+#define SH7750_CHCR_DSA_AMEM16  0x0E000000     /* 16-bit attribute memory space */
+
+#define SH7750_CHCR_DTC       0x01000000       /* Destination Address Wait Control
+                                                  Select, specifies CS5 or CS6
+                                                  space wait control for PCMCIA
+                                                  access */
+
+#define SH7750_CHCR_DS        0x00080000       /* DREQ\ Select : */
+#define SH7750_CHCR_DS_LOWLVL 0x00000000       /*     Low Level Detection */
+#define SH7750_CHCR_DS_FALL   0x00080000       /*     Falling Edge Detection */
+
+#define SH7750_CHCR_RL        0x00040000       /* Request Check Level: */
+#define SH7750_CHCR_RL_ACTH   0x00000000       /*     DRAK is an active high out */
+#define SH7750_CHCR_RL_ACTL   0x00040000       /*     DRAK is an active low out */
+
+#define SH7750_CHCR_AM        0x00020000       /* Acknowledge Mode: */
+#define SH7750_CHCR_AM_RD     0x00000000       /*     DACK is output in read cycle */
+#define SH7750_CHCR_AM_WR     0x00020000       /*     DACK is output in write cycle */
+
+#define SH7750_CHCR_AL        0x00010000       /* Acknowledge Level: */
+#define SH7750_CHCR_AL_ACTH   0x00000000       /*     DACK is an active high out */
+#define SH7750_CHCR_AL_ACTL   0x00010000       /*     DACK is an active low out */
+
+#define SH7750_CHCR_DM        0x0000C000       /* Destination Address Mode: */
+#define SH7750_CHCR_DM_FIX    0x00000000       /*     Destination Addr Fixed */
+#define SH7750_CHCR_DM_INC    0x00004000       /*     Destination Addr Incremented */
+#define SH7750_CHCR_DM_DEC    0x00008000       /*     Destination Addr Decremented */
+
+#define SH7750_CHCR_SM        0x00003000       /* Source Address Mode: */
+#define SH7750_CHCR_SM_FIX    0x00000000       /*     Source Addr Fixed */
+#define SH7750_CHCR_SM_INC    0x00001000       /*     Source Addr Incremented */
+#define SH7750_CHCR_SM_DEC    0x00002000       /*     Source Addr Decremented */
+
+#define SH7750_CHCR_RS        0x00000F00       /* Request Source Select: */
+#define SH7750_CHCR_RS_ER_DA_EA_TO_EA   0x000  /* External Request, Dual Address
+                                                  Mode (External Addr Space->
+                                                  External Addr Space) */
+#define SH7750_CHCR_RS_ER_SA_EA_TO_ED   0x200  /* External Request, Single
+                                                  Address Mode (External Addr
+                                                  Space -> External Device) */
+#define SH7750_CHCR_RS_ER_SA_ED_TO_EA   0x300  /* External Request, Single
+                                                  Address Mode, (External
+                                                  Device -> External Addr
+                                                  Space) */
+#define SH7750_CHCR_RS_AR_EA_TO_EA      0x400  /* Auto-Request (External Addr
+                                                  Space -> External Addr Space) */
+
+#define SH7750_CHCR_RS_AR_EA_TO_OCP     0x500  /* Auto-Request (External Addr
+                                                  Space -> On-chip Peripheral
+                                                  Module) */
+#define SH7750_CHCR_RS_AR_OCP_TO_EA     0x600  /* Auto-Request (On-chip
+                                                  Peripheral Module ->
+                                                  External Addr Space */
+#define SH7750_CHCR_RS_SCITX_EA_TO_SC   0x800  /* SCI Transmit-Data-Empty intr
+                                                  transfer request (external
+                                                  address space -> SCTDR1) */
+#define SH7750_CHCR_RS_SCIRX_SC_TO_EA   0x900  /* SCI Receive-Data-Full intr
+                                                  transfer request (SCRDR1 ->
+                                                  External Addr Space) */
+#define SH7750_CHCR_RS_SCIFTX_EA_TO_SC  0xA00  /* SCIF Transmit-Data-Empty intr
+                                                  transfer request (external
+                                                  address space -> SCFTDR1) */
+#define SH7750_CHCR_RS_SCIFRX_SC_TO_EA  0xB00  /* SCIF Receive-Data-Full intr
+                                                  transfer request (SCFRDR2 ->
+                                                  External Addr Space) */
+#define SH7750_CHCR_RS_TMU2_EA_TO_EA    0xC00  /* TMU Channel 2 (input capture
+                                                  interrupt), (external address
+                                                  space -> external address
+                                                  space) */
+#define SH7750_CHCR_RS_TMU2_EA_TO_OCP   0xD00  /* TMU Channel 2 (input capture
+                                                  interrupt), (external address
+                                                  space -> on-chip peripheral
+                                                  module) */
+#define SH7750_CHCR_RS_TMU2_OCP_TO_EA   0xE00  /* TMU Channel 2 (input capture
+                                                  interrupt), (on-chip
+                                                  peripheral module -> external
+                                                  address space) */
+
+#define SH7750_CHCR_TM        0x00000080       /* Transmit mode: */
+#define SH7750_CHCR_TM_CSTEAL 0x00000000       /*     Cycle Steal Mode */
+#define SH7750_CHCR_TM_BURST  0x00000080       /*     Burst Mode */
+
+#define SH7750_CHCR_TS        0x00000070       /* Transmit Size: */
+#define SH7750_CHCR_TS_QUAD   0x00000000       /*     Quadword Size (64 bits) */
+#define SH7750_CHCR_TS_BYTE   0x00000010       /*     Byte Size (8 bit) */
+#define SH7750_CHCR_TS_WORD   0x00000020       /*     Word Size (16 bit) */
+#define SH7750_CHCR_TS_LONG   0x00000030       /*     Longword Size (32 bit) */
+#define SH7750_CHCR_TS_BLOCK  0x00000040       /*     32-byte block transfer */
+
+#define SH7750_CHCR_IE        0x00000004       /* Interrupt Enable */
+#define SH7750_CHCR_TE        0x00000002       /* Transfer End */
+#define SH7750_CHCR_DE        0x00000001       /* DMAC Enable */
+
+/* DMA Operation Register - DMAOR */
+#define SH7750_DMAOR_REGOFS   0xA00040 /* offset */
+#define SH7750_DMAOR          SH7750_P4_REG32(SH7750_DMAOR_REGOFS)
+#define SH7750_DMAOR_A7       SH7750_A7_REG32(SH7750_DMAOR_REGOFS)
+
+#define SH7750_DMAOR_DDT      0x00008000       /* On-Demand Data Transfer Mode */
+
+#define SH7750_DMAOR_PR       0x00000300       /* Priority Mode: */
+#define SH7750_DMAOR_PR_0123  0x00000000       /*     CH0 > CH1 > CH2 > CH3 */
+#define SH7750_DMAOR_PR_0231  0x00000100       /*     CH0 > CH2 > CH3 > CH1 */
+#define SH7750_DMAOR_PR_2013  0x00000200       /*     CH2 > CH0 > CH1 > CH3 */
+#define SH7750_DMAOR_PR_RR    0x00000300       /*     Round-robin mode */
+
+#define SH7750_DMAOR_COD      0x00000010       /* Check Overrun for DREQ\ */
+#define SH7750_DMAOR_AE       0x00000004       /* Address Error flag */
+#define SH7750_DMAOR_NMIF     0x00000002       /* NMI Flag */
+#define SH7750_DMAOR_DME      0x00000001       /* DMAC Master Enable */
+
+/*
+ * I/O Ports
+ */
+/* Port Control Register A - PCTRA */
+#define SH7750_PCTRA_REGOFS   0x80002C /* offset */
+#define SH7750_PCTRA          SH7750_P4_REG32(SH7750_PCTRA_REGOFS)
+#define SH7750_PCTRA_A7       SH7750_A7_REG32(SH7750_PCTRA_REGOFS)
+
+#define SH7750_PCTRA_PBPUP(n) 0        /* Bit n is pulled up */
+#define SH7750_PCTRA_PBNPUP(n) (1 << ((n)*2+1))        /* Bit n is not pulled up */
+#define SH7750_PCTRA_PBINP(n) 0        /* Bit n is an input */
+#define SH7750_PCTRA_PBOUT(n) (1 << ((n)*2))   /* Bit n is an output */
+
+/* Port Data Register A - PDTRA(half) */
+#define SH7750_PDTRA_REGOFS   0x800030 /* offset */
+#define SH7750_PDTRA          SH7750_P4_REG32(SH7750_PDTRA_REGOFS)
+#define SH7750_PDTRA_A7       SH7750_A7_REG32(SH7750_PDTRA_REGOFS)
+
+#define SH7750_PDTRA_BIT(n) (1 << (n))
+
+/* Port Control Register B - PCTRB */
+#define SH7750_PCTRB_REGOFS   0x800040 /* offset */
+#define SH7750_PCTRB          SH7750_P4_REG32(SH7750_PCTRB_REGOFS)
+#define SH7750_PCTRB_A7       SH7750_A7_REG32(SH7750_PCTRB_REGOFS)
+
+#define SH7750_PCTRB_PBPUP(n) 0        /* Bit n is pulled up */
+#define SH7750_PCTRB_PBNPUP(n) (1 << ((n-16)*2+1))     /* Bit n is not pulled up */
+#define SH7750_PCTRB_PBINP(n) 0        /* Bit n is an input */
+#define SH7750_PCTRB_PBOUT(n) (1 << ((n-16)*2))        /* Bit n is an output */
+
+/* Port Data Register B - PDTRB(half) */
+#define SH7750_PDTRB_REGOFS   0x800044 /* offset */
+#define SH7750_PDTRB          SH7750_P4_REG32(SH7750_PDTRB_REGOFS)
+#define SH7750_PDTRB_A7       SH7750_A7_REG32(SH7750_PDTRB_REGOFS)
+
+#define SH7750_PDTRB_BIT(n) (1 << ((n)-16))
+
+/* GPIO Interrupt Control Register - GPIOIC(half) */
+#define SH7750_GPIOIC_REGOFS  0x800048 /* offset */
+#define SH7750_GPIOIC         SH7750_P4_REG32(SH7750_GPIOIC_REGOFS)
+#define SH7750_GPIOIC_A7      SH7750_A7_REG32(SH7750_GPIOIC_REGOFS)
+
+#define SH7750_GPIOIC_PTIREN(n) (1 << (n))     /* Port n is used as a GPIO int */
+
+/*
+ * Interrupt Controller - INTC
+ */
+/* Interrupt Control Register - ICR (half) */
+#define SH7750_ICR_REGOFS     0xD00000 /* offset */
+#define SH7750_ICR            SH7750_P4_REG32(SH7750_ICR_REGOFS)
+#define SH7750_ICR_A7         SH7750_A7_REG32(SH7750_ICR_REGOFS)
+
+#define SH7750_ICR_NMIL       0x8000   /* NMI Input Level */
+#define SH7750_ICR_MAI        0x4000   /* NMI Interrupt Mask */
+
+#define SH7750_ICR_NMIB       0x0200   /* NMI Block Mode: */
+#define SH7750_ICR_NMIB_BLK   0x0000   /*   NMI requests held pending while
+                                          SR.BL bit is set to 1 */
+#define SH7750_ICR_NMIB_NBLK  0x0200   /*   NMI requests detected when SR.BL bit
+                                          set to 1 */
+
+#define SH7750_ICR_NMIE       0x0100   /* NMI Edge Select: */
+#define SH7750_ICR_NMIE_FALL  0x0000   /*   Interrupt request detected on falling
+                                          edge of NMI input */
+#define SH7750_ICR_NMIE_RISE  0x0100   /*   Interrupt request detected on rising
+                                          edge of NMI input */
+
+#define SH7750_ICR_IRLM       0x0080   /* IRL Pin Mode: */
+#define SH7750_ICR_IRLM_ENC   0x0000   /*   IRL\ pins used as a level-encoded
+                                          interrupt requests */
+#define SH7750_ICR_IRLM_RAW   0x0080   /*   IRL\ pins used as a four independent
+                                          interrupt requests */
+
+/*
+ * User Break Controller registers
+ */
+#define SH7750_BARA           0x200000 /* Break address regiser A */
+#define SH7750_BAMRA          0x200004 /* Break address mask regiser A */
+#define SH7750_BBRA           0x200008 /* Break bus cycle regiser A */
+#define SH7750_BARB           0x20000c /* Break address regiser B */
+#define SH7750_BAMRB          0x200010 /* Break address mask regiser B */
+#define SH7750_BBRB           0x200014 /* Break bus cycle regiser B */
+#define SH7750_BASRB          0x000018 /* Break ASID regiser B */
+#define SH7750_BDRB           0x200018 /* Break data regiser B */
+#define SH7750_BDMRB          0x20001c /* Break data mask regiser B */
+#define SH7750_BRCR           0x200020 /* Break control register */
+
+#define SH7750_BRCR_UDBE        0x0001 /* User break debug enable bit */
+
+/*
+ * Missing in RTEMS, added for QEMU
+ */
+#define SH7750_BCR3_A7       0x1f800050
+#define SH7750_BCR4_A7       0x1e0a00f0
+
+#endif
diff --git a/hw/sh4/sh_pci.c b/hw/sh4/sh_pci.c
new file mode 100644 (file)
index 0000000..d213a90
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+ * SuperH on-chip PCIC emulation.
+ *
+ * Copyright (c) 2008 Takashi YOSHII
+ *
+ * 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 "hw/sysbus.h"
+#include "hw/sh4/sh.h"
+#include "hw/pci/pci.h"
+#include "hw/pci/pci_host.h"
+#include "qemu/bswap.h"
+#include "exec/address-spaces.h"
+
+typedef struct SHPCIState {
+    SysBusDevice busdev;
+    PCIBus *bus;
+    PCIDevice *dev;
+    qemu_irq irq[4];
+    MemoryRegion memconfig_p4;
+    MemoryRegion memconfig_a7;
+    MemoryRegion isa;
+    uint32_t par;
+    uint32_t mbr;
+    uint32_t iobr;
+} SHPCIState;
+
+static void sh_pci_reg_write (void *p, hwaddr addr, uint64_t val,
+                              unsigned size)
+{
+    SHPCIState *pcic = p;
+    switch(addr) {
+    case 0 ... 0xfc:
+        cpu_to_le32w((uint32_t*)(pcic->dev->config + addr), val);
+        break;
+    case 0x1c0:
+        pcic->par = val;
+        break;
+    case 0x1c4:
+        pcic->mbr = val & 0xff000001;
+        break;
+    case 0x1c8:
+        if ((val & 0xfffc0000) != (pcic->iobr & 0xfffc0000)) {
+            memory_region_del_subregion(get_system_memory(), &pcic->isa);
+            pcic->iobr = val & 0xfffc0001;
+            memory_region_add_subregion(get_system_memory(),
+                                        pcic->iobr & 0xfffc0000, &pcic->isa);
+        }
+        break;
+    case 0x220:
+        pci_data_write(pcic->bus, pcic->par, val, 4);
+        break;
+    }
+}
+
+static uint64_t sh_pci_reg_read (void *p, hwaddr addr,
+                                 unsigned size)
+{
+    SHPCIState *pcic = p;
+    switch(addr) {
+    case 0 ... 0xfc:
+        return le32_to_cpup((uint32_t*)(pcic->dev->config + addr));
+    case 0x1c0:
+        return pcic->par;
+    case 0x1c4:
+        return pcic->mbr;
+    case 0x1c8:
+        return pcic->iobr;
+    case 0x220:
+        return pci_data_read(pcic->bus, pcic->par, 4);
+    }
+    return 0;
+}
+
+static const MemoryRegionOps sh_pci_reg_ops = {
+    .read = sh_pci_reg_read,
+    .write = sh_pci_reg_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static int sh_pci_map_irq(PCIDevice *d, int irq_num)
+{
+    return (d->devfn >> 3);
+}
+
+static void sh_pci_set_irq(void *opaque, int irq_num, int level)
+{
+    qemu_irq *pic = opaque;
+
+    qemu_set_irq(pic[irq_num], level);
+}
+
+static int sh_pci_device_init(SysBusDevice *dev)
+{
+    SHPCIState *s;
+    int i;
+
+    s = FROM_SYSBUS(SHPCIState, dev);
+    for (i = 0; i < 4; i++) {
+        sysbus_init_irq(dev, &s->irq[i]);
+    }
+    s->bus = pci_register_bus(&s->busdev.qdev, "pci",
+                              sh_pci_set_irq, sh_pci_map_irq,
+                              s->irq,
+                              get_system_memory(),
+                              get_system_io(),
+                              PCI_DEVFN(0, 0), 4, TYPE_PCI_BUS);
+    memory_region_init_io(&s->memconfig_p4, &sh_pci_reg_ops, s,
+                          "sh_pci", 0x224);
+    memory_region_init_alias(&s->memconfig_a7, "sh_pci.2", &s->memconfig_p4,
+                             0, 0x224);
+    isa_mmio_setup(&s->isa, 0x40000);
+    sysbus_init_mmio(dev, &s->memconfig_p4);
+    sysbus_init_mmio(dev, &s->memconfig_a7);
+    s->iobr = 0xfe240000;
+    memory_region_add_subregion(get_system_memory(), s->iobr, &s->isa);
+
+    s->dev = pci_create_simple(s->bus, PCI_DEVFN(0, 0), "sh_pci_host");
+    return 0;
+}
+
+static int sh_pci_host_init(PCIDevice *d)
+{
+    pci_set_word(d->config + PCI_COMMAND, PCI_COMMAND_WAIT);
+    pci_set_word(d->config + PCI_STATUS, PCI_STATUS_CAP_LIST |
+                 PCI_STATUS_FAST_BACK | PCI_STATUS_DEVSEL_MEDIUM);
+    return 0;
+}
+
+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 const TypeInfo sh_pci_host_info = {
+    .name          = "sh_pci_host",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PCIDevice),
+    .class_init    = sh_pci_host_class_init,
+};
+
+static void sh_pci_device_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sdc->init = sh_pci_device_init;
+}
+
+static const 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_types(void)
+{
+    type_register_static(&sh_pci_device_info);
+    type_register_static(&sh_pci_host_info);
+}
+
+type_init(sh_pci_register_types)
index 192579d0658ba1b7ae1a3ec053e878424c4ce54e..c23d4afb10f17e825ef6c5935e666c221d55ab28 100644 (file)
@@ -28,7 +28,7 @@
    More information in target-sh4/README.sh4
 */
 #include "hw/hw.h"
-#include "hw/sh.h"
+#include "hw/sh4/sh.h"
 #include "sysemu/sysemu.h"
 #include "hw/boards.h"
 #include "hw/loader.h"
diff --git a/hw/sh7750_regnames.h b/hw/sh7750_regnames.h
deleted file mode 100644 (file)
index 7463709..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _SH7750_REGNAMES_H
-#define _SH7750_REGNAMES_H
-
-const char *regname(uint32_t addr);
-
-#endif                         /* _SH7750_REGNAMES_H */
diff --git a/hw/sh7750_regs.h b/hw/sh7750_regs.h
deleted file mode 100644 (file)
index 534aa48..0000000
+++ /dev/null
@@ -1,1277 +0,0 @@
-/*
- * SH-7750 memory-mapped registers
- * This file based on information provided in the following document:
- * "Hitachi SuperH (tm) RISC engine. SH7750 Series (SH7750, SH7750S)
- *  Hardware Manual"
- *  Document Number ADE-602-124C, Rev. 4.0, 4/21/00, Hitachi Ltd.
- *
- * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
- * Author: Alexandra Kossovsky <sasha@oktet.ru>
- *         Victor V. Vengerov <vvv@oktet.ru>
- *
- * The license and distribution terms for this file may be
- * found in the file LICENSE in this distribution or at
- *  http://www.rtems.com/license/LICENSE.
- *
- * @(#) sh7750_regs.h,v 1.2.4.1 2003/09/04 18:46:00 joel Exp
- */
-
-#ifndef __SH7750_REGS_H__
-#define __SH7750_REGS_H__
-
-/*
- * All register has 2 addresses: in 0xff000000 - 0xffffffff (P4 address)  and
- * in 0x1f000000 - 0x1fffffff (area 7 address)
- */
-#define SH7750_P4_BASE       0xff000000        /* Accessible only in
-                                          privileged mode */
-#define SH7750_A7_BASE       0x1f000000        /* Accessible only using TLB */
-
-#define SH7750_P4_REG32(ofs) (SH7750_P4_BASE + (ofs))
-#define SH7750_A7_REG32(ofs) (SH7750_A7_BASE + (ofs))
-
-/*
- * MMU Registers
- */
-
-/* Page Table Entry High register - PTEH */
-#define SH7750_PTEH_REGOFS    0x000000 /* offset */
-#define SH7750_PTEH           SH7750_P4_REG32(SH7750_PTEH_REGOFS)
-#define SH7750_PTEH_A7        SH7750_A7_REG32(SH7750_PTEH_REGOFS)
-#define SH7750_PTEH_VPN       0xfffffd00       /* Virtual page number */
-#define SH7750_PTEH_VPN_S     10
-#define SH7750_PTEH_ASID      0x000000ff       /* Address space identifier */
-#define SH7750_PTEH_ASID_S    0
-
-/* Page Table Entry Low register - PTEL */
-#define SH7750_PTEL_REGOFS    0x000004 /* offset */
-#define SH7750_PTEL           SH7750_P4_REG32(SH7750_PTEL_REGOFS)
-#define SH7750_PTEL_A7        SH7750_A7_REG32(SH7750_PTEL_REGOFS)
-#define SH7750_PTEL_PPN       0x1ffffc00       /* Physical page number */
-#define SH7750_PTEL_PPN_S     10
-#define SH7750_PTEL_V         0x00000100       /* Validity (0-entry is invalid) */
-#define SH7750_PTEL_SZ1       0x00000080       /* Page size bit 1 */
-#define SH7750_PTEL_SZ0       0x00000010       /* Page size bit 0 */
-#define SH7750_PTEL_SZ_1KB    0x00000000       /*   1-kbyte page */
-#define SH7750_PTEL_SZ_4KB    0x00000010       /*   4-kbyte page */
-#define SH7750_PTEL_SZ_64KB   0x00000080       /*   64-kbyte page */
-#define SH7750_PTEL_SZ_1MB    0x00000090       /*   1-Mbyte page */
-#define SH7750_PTEL_PR        0x00000060       /* Protection Key Data */
-#define SH7750_PTEL_PR_ROPO   0x00000000       /*   read-only in priv mode */
-#define SH7750_PTEL_PR_RWPO   0x00000020       /*   read-write in priv mode */
-#define SH7750_PTEL_PR_ROPU   0x00000040       /*   read-only in priv or user mode */
-#define SH7750_PTEL_PR_RWPU   0x00000060       /*   read-write in priv or user mode */
-#define SH7750_PTEL_C         0x00000008       /* Cacheability
-                                                  (0 - page not cacheable) */
-#define SH7750_PTEL_D         0x00000004       /* Dirty bit (1 - write has been
-                                                  performed to a page) */
-#define SH7750_PTEL_SH        0x00000002       /* Share Status bit (1 - page are
-                                                  shared by processes) */
-#define SH7750_PTEL_WT        0x00000001       /* Write-through bit, specifies the
-                                                  cache write mode:
-                                                  0 - Copy-back mode
-                                                  1 - Write-through mode */
-
-/* Page Table Entry Assistance register - PTEA */
-#define SH7750_PTEA_REGOFS    0x000034 /* offset */
-#define SH7750_PTEA           SH7750_P4_REG32(SH7750_PTEA_REGOFS)
-#define SH7750_PTEA_A7        SH7750_A7_REG32(SH7750_PTEA_REGOFS)
-#define SH7750_PTEA_TC        0x00000008       /* Timing Control bit
-                                                  0 - use area 5 wait states
-                                                  1 - use area 6 wait states */
-#define SH7750_PTEA_SA        0x00000007       /* Space Attribute bits: */
-#define SH7750_PTEA_SA_UNDEF  0x00000000       /*    0 - undefined */
-#define SH7750_PTEA_SA_IOVAR  0x00000001       /*    1 - variable-size I/O space */
-#define SH7750_PTEA_SA_IO8    0x00000002       /*    2 - 8-bit I/O space */
-#define SH7750_PTEA_SA_IO16   0x00000003       /*    3 - 16-bit I/O space */
-#define SH7750_PTEA_SA_CMEM8  0x00000004       /*    4 - 8-bit common memory space */
-#define SH7750_PTEA_SA_CMEM16 0x00000005       /*    5 - 16-bit common memory space */
-#define SH7750_PTEA_SA_AMEM8  0x00000006       /*    6 - 8-bit attr memory space */
-#define SH7750_PTEA_SA_AMEM16 0x00000007       /*    7 - 16-bit attr memory space */
-
-
-/* Translation table base register */
-#define SH7750_TTB_REGOFS     0x000008 /* offset */
-#define SH7750_TTB            SH7750_P4_REG32(SH7750_TTB_REGOFS)
-#define SH7750_TTB_A7         SH7750_A7_REG32(SH7750_TTB_REGOFS)
-
-/* TLB exeption address register - TEA */
-#define SH7750_TEA_REGOFS     0x00000c /* offset */
-#define SH7750_TEA            SH7750_P4_REG32(SH7750_TEA_REGOFS)
-#define SH7750_TEA_A7         SH7750_A7_REG32(SH7750_TEA_REGOFS)
-
-/* MMU control register - MMUCR */
-#define SH7750_MMUCR_REGOFS   0x000010 /* offset */
-#define SH7750_MMUCR          SH7750_P4_REG32(SH7750_MMUCR_REGOFS)
-#define SH7750_MMUCR_A7       SH7750_A7_REG32(SH7750_MMUCR_REGOFS)
-#define SH7750_MMUCR_AT       0x00000001       /* Address translation bit */
-#define SH7750_MMUCR_TI       0x00000004       /* TLB invalidate */
-#define SH7750_MMUCR_SV       0x00000100       /* Single Virtual Mode bit */
-#define SH7750_MMUCR_SQMD     0x00000200       /* Store Queue Mode bit */
-#define SH7750_MMUCR_URC      0x0000FC00       /* UTLB Replace Counter */
-#define SH7750_MMUCR_URC_S    10
-#define SH7750_MMUCR_URB      0x00FC0000       /* UTLB Replace Boundary */
-#define SH7750_MMUCR_URB_S    18
-#define SH7750_MMUCR_LRUI     0xFC000000       /* Least Recently Used ITLB */
-#define SH7750_MMUCR_LRUI_S   26
-
-
-
-
-/*
- * Cache registers
- *   IC -- instructions cache
- *   OC -- operand cache
- */
-
-/* Cache Control Register - CCR */
-#define SH7750_CCR_REGOFS     0x00001c /* offset */
-#define SH7750_CCR            SH7750_P4_REG32(SH7750_CCR_REGOFS)
-#define SH7750_CCR_A7         SH7750_A7_REG32(SH7750_CCR_REGOFS)
-
-#define SH7750_CCR_IIX      0x00008000 /* IC index enable bit */
-#define SH7750_CCR_ICI      0x00000800 /* IC invalidation bit:
-                                          set it to clear IC */
-#define SH7750_CCR_ICE      0x00000100 /* IC enable bit */
-#define SH7750_CCR_OIX      0x00000080 /* OC index enable bit */
-#define SH7750_CCR_ORA      0x00000020 /* OC RAM enable bit
-                                          if you set OCE = 0,
-                                          you should set ORA = 0 */
-#define SH7750_CCR_OCI      0x00000008 /* OC invalidation bit */
-#define SH7750_CCR_CB       0x00000004 /* Copy-back bit for P1 area */
-#define SH7750_CCR_WT       0x00000002 /* Write-through bit for P0,U0,P3 area */
-#define SH7750_CCR_OCE      0x00000001 /* OC enable bit */
-
-/* Queue address control register 0 - QACR0 */
-#define SH7750_QACR0_REGOFS   0x000038 /* offset */
-#define SH7750_QACR0          SH7750_P4_REG32(SH7750_QACR0_REGOFS)
-#define SH7750_QACR0_A7       SH7750_A7_REG32(SH7750_QACR0_REGOFS)
-
-/* Queue address control register 1 - QACR1 */
-#define SH7750_QACR1_REGOFS   0x00003c /* offset */
-#define SH7750_QACR1          SH7750_P4_REG32(SH7750_QACR1_REGOFS)
-#define SH7750_QACR1_A7       SH7750_A7_REG32(SH7750_QACR1_REGOFS)
-
-
-/*
- * Exeption-related registers
- */
-
-/* Immediate data for TRAPA instruction - TRA */
-#define SH7750_TRA_REGOFS     0x000020 /* offset */
-#define SH7750_TRA            SH7750_P4_REG32(SH7750_TRA_REGOFS)
-#define SH7750_TRA_A7         SH7750_A7_REG32(SH7750_TRA_REGOFS)
-
-#define SH7750_TRA_IMM      0x000003fd /* Immediate data operand */
-#define SH7750_TRA_IMM_S    2
-
-/* Exeption event register - EXPEVT */
-#define SH7750_EXPEVT_REGOFS  0x000024
-#define SH7750_EXPEVT         SH7750_P4_REG32(SH7750_EXPEVT_REGOFS)
-#define SH7750_EXPEVT_A7      SH7750_A7_REG32(SH7750_EXPEVT_REGOFS)
-
-#define SH7750_EXPEVT_EX      0x00000fff       /* Exeption code */
-#define SH7750_EXPEVT_EX_S    0
-
-/* Interrupt event register */
-#define SH7750_INTEVT_REGOFS  0x000028
-#define SH7750_INTEVT         SH7750_P4_REG32(SH7750_INTEVT_REGOFS)
-#define SH7750_INTEVT_A7      SH7750_A7_REG32(SH7750_INTEVT_REGOFS)
-#define SH7750_INTEVT_EX    0x00000fff /* Exeption code */
-#define SH7750_INTEVT_EX_S  0
-
-/*
- * Exception/interrupt codes
- */
-#define SH7750_EVT_TO_NUM(evt)  ((evt) >> 5)
-
-/* Reset exception category */
-#define SH7750_EVT_POWER_ON_RST        0x000   /* Power-on reset */
-#define SH7750_EVT_MANUAL_RST          0x020   /* Manual reset */
-#define SH7750_EVT_TLB_MULT_HIT        0x140   /* TLB multiple-hit exception */
-
-/* General exception category */
-#define SH7750_EVT_USER_BREAK          0x1E0   /* User break */
-#define SH7750_EVT_IADDR_ERR           0x0E0   /* Instruction address error */
-#define SH7750_EVT_TLB_READ_MISS       0x040   /* ITLB miss exception /
-                                                  DTLB miss exception (read) */
-#define SH7750_EVT_TLB_READ_PROTV      0x0A0   /* ITLB protection violation /
-                                                  DTLB protection violation (read) */
-#define SH7750_EVT_ILLEGAL_INSTR       0x180   /* General Illegal Instruction
-                                                  exception */
-#define SH7750_EVT_SLOT_ILLEGAL_INSTR  0x1A0   /* Slot Illegal Instruction
-                                                  exception */
-#define SH7750_EVT_FPU_DISABLE         0x800   /* General FPU disable exception */
-#define SH7750_EVT_SLOT_FPU_DISABLE    0x820   /* Slot FPU disable exception */
-#define SH7750_EVT_DATA_READ_ERR       0x0E0   /* Data address error (read) */
-#define SH7750_EVT_DATA_WRITE_ERR      0x100   /* Data address error (write) */
-#define SH7750_EVT_DTLB_WRITE_MISS     0x060   /* DTLB miss exception (write) */
-#define SH7750_EVT_DTLB_WRITE_PROTV    0x0C0   /* DTLB protection violation
-                                                  exception (write) */
-#define SH7750_EVT_FPU_EXCEPTION       0x120   /* FPU exception */
-#define SH7750_EVT_INITIAL_PGWRITE     0x080   /* Initial Page Write exception */
-#define SH7750_EVT_TRAPA               0x160   /* Unconditional trap (TRAPA) */
-
-/* Interrupt exception category */
-#define SH7750_EVT_NMI                 0x1C0   /* Non-maskable interrupt */
-#define SH7750_EVT_IRQ0                0x200   /* External Interrupt 0 */
-#define SH7750_EVT_IRQ1                0x220   /* External Interrupt 1 */
-#define SH7750_EVT_IRQ2                0x240   /* External Interrupt 2 */
-#define SH7750_EVT_IRQ3                0x260   /* External Interrupt 3 */
-#define SH7750_EVT_IRQ4                0x280   /* External Interrupt 4 */
-#define SH7750_EVT_IRQ5                0x2A0   /* External Interrupt 5 */
-#define SH7750_EVT_IRQ6                0x2C0   /* External Interrupt 6 */
-#define SH7750_EVT_IRQ7                0x2E0   /* External Interrupt 7 */
-#define SH7750_EVT_IRQ8                0x300   /* External Interrupt 8 */
-#define SH7750_EVT_IRQ9                0x320   /* External Interrupt 9 */
-#define SH7750_EVT_IRQA                0x340   /* External Interrupt A */
-#define SH7750_EVT_IRQB                0x360   /* External Interrupt B */
-#define SH7750_EVT_IRQC                0x380   /* External Interrupt C */
-#define SH7750_EVT_IRQD                0x3A0   /* External Interrupt D */
-#define SH7750_EVT_IRQE                0x3C0   /* External Interrupt E */
-
-/* Peripheral Module Interrupts - Timer Unit (TMU) */
-#define SH7750_EVT_TUNI0               0x400   /* TMU Underflow Interrupt 0 */
-#define SH7750_EVT_TUNI1               0x420   /* TMU Underflow Interrupt 1 */
-#define SH7750_EVT_TUNI2               0x440   /* TMU Underflow Interrupt 2 */
-#define SH7750_EVT_TICPI2              0x460   /* TMU Input Capture Interrupt 2 */
-
-/* Peripheral Module Interrupts - Real-Time Clock (RTC) */
-#define SH7750_EVT_RTC_ATI             0x480   /* Alarm Interrupt Request */
-#define SH7750_EVT_RTC_PRI             0x4A0   /* Periodic Interrupt Request */
-#define SH7750_EVT_RTC_CUI             0x4C0   /* Carry Interrupt Request */
-
-/* Peripheral Module Interrupts - Serial Communication Interface (SCI) */
-#define SH7750_EVT_SCI_ERI             0x4E0   /* Receive Error */
-#define SH7750_EVT_SCI_RXI             0x500   /* Receive Data Register Full */
-#define SH7750_EVT_SCI_TXI             0x520   /* Transmit Data Register Empty */
-#define SH7750_EVT_SCI_TEI             0x540   /* Transmit End */
-
-/* Peripheral Module Interrupts - Watchdog Timer (WDT) */
-#define SH7750_EVT_WDT_ITI             0x560   /* Interval Timer Interrupt
-                                                  (used when WDT operates in
-                                                  interval timer mode) */
-
-/* Peripheral Module Interrupts - Memory Refresh Unit (REF) */
-#define SH7750_EVT_REF_RCMI            0x580   /* Compare-match Interrupt */
-#define SH7750_EVT_REF_ROVI            0x5A0   /* Refresh Counter Overflow
-                                                  interrupt */
-
-/* Peripheral Module Interrupts - Hitachi User Debug Interface (H-UDI) */
-#define SH7750_EVT_HUDI                0x600   /* UDI interrupt */
-
-/* Peripheral Module Interrupts - General-Purpose I/O (GPIO) */
-#define SH7750_EVT_GPIO                0x620   /* GPIO Interrupt */
-
-/* Peripheral Module Interrupts - DMA Controller (DMAC) */
-#define SH7750_EVT_DMAC_DMTE0          0x640   /* DMAC 0 Transfer End Interrupt */
-#define SH7750_EVT_DMAC_DMTE1          0x660   /* DMAC 1 Transfer End Interrupt */
-#define SH7750_EVT_DMAC_DMTE2          0x680   /* DMAC 2 Transfer End Interrupt */
-#define SH7750_EVT_DMAC_DMTE3          0x6A0   /* DMAC 3 Transfer End Interrupt */
-#define SH7750_EVT_DMAC_DMAE           0x6C0   /* DMAC Address Error Interrupt */
-
-/* Peripheral Module Interrupts - Serial Communication Interface with FIFO */
-/*                                                                  (SCIF) */
-#define SH7750_EVT_SCIF_ERI            0x700   /* Receive Error */
-#define SH7750_EVT_SCIF_RXI            0x720   /* Receive FIFO Data Full or
-                                                  Receive Data ready interrupt */
-#define SH7750_EVT_SCIF_BRI            0x740   /* Break or overrun error */
-#define SH7750_EVT_SCIF_TXI            0x760   /* Transmit FIFO Data Empty */
-
-/*
- * Power Management
- */
-#define SH7750_STBCR_REGOFS   0xC00004 /* offset */
-#define SH7750_STBCR          SH7750_P4_REG32(SH7750_STBCR_REGOFS)
-#define SH7750_STBCR_A7       SH7750_A7_REG32(SH7750_STBCR_REGOFS)
-
-#define SH7750_STBCR_STBY     0x80     /* Specifies a transition to standby mode:
-                                          0 - Transition to SLEEP mode on SLEEP
-                                          1 - Transition to STANDBY mode on SLEEP */
-#define SH7750_STBCR_PHZ      0x40     /* State of peripheral module pins in
-                                          standby mode:
-                                          0 - normal state
-                                          1 - high-impendance state */
-
-#define SH7750_STBCR_PPU      0x20     /* Peripheral module pins pull-up controls */
-#define SH7750_STBCR_MSTP4    0x10     /* Stopping the clock supply to DMAC */
-#define SH7750_STBCR_DMAC_STP SH7750_STBCR_MSTP4
-#define SH7750_STBCR_MSTP3    0x08     /* Stopping the clock supply to SCIF */
-#define SH7750_STBCR_SCIF_STP SH7750_STBCR_MSTP3
-#define SH7750_STBCR_MSTP2    0x04     /* Stopping the clock supply to TMU */
-#define SH7750_STBCR_TMU_STP  SH7750_STBCR_MSTP2
-#define SH7750_STBCR_MSTP1    0x02     /* Stopping the clock supply to RTC */
-#define SH7750_STBCR_RTC_STP  SH7750_STBCR_MSTP1
-#define SH7750_STBCR_MSPT0    0x01     /* Stopping the clock supply to SCI */
-#define SH7750_STBCR_SCI_STP  SH7750_STBCR_MSTP0
-
-#define SH7750_STBCR_STBY     0x80
-
-
-#define SH7750_STBCR2_REGOFS  0xC00010 /* offset */
-#define SH7750_STBCR2         SH7750_P4_REG32(SH7750_STBCR2_REGOFS)
-#define SH7750_STBCR2_A7      SH7750_A7_REG32(SH7750_STBCR2_REGOFS)
-
-#define SH7750_STBCR2_DSLP    0x80     /* Specifies transition to deep sleep mode:
-                                          0 - transition to sleep or standby mode
-                                          as it is specified in STBY bit
-                                          1 - transition to deep sleep mode on
-                                          execution of SLEEP instruction */
-#define SH7750_STBCR2_MSTP6   0x02     /* Stopping the clock supply to Store Queue
-                                          in the cache controller */
-#define SH7750_STBCR2_SQ_STP  SH7750_STBCR2_MSTP6
-#define SH7750_STBCR2_MSTP5   0x01     /* Stopping the clock supply to the User
-                                          Break Controller (UBC) */
-#define SH7750_STBCR2_UBC_STP SH7750_STBCR2_MSTP5
-
-/*
- * Clock Pulse Generator (CPG)
- */
-#define SH7750_FRQCR_REGOFS   0xC00000 /* offset */
-#define SH7750_FRQCR          SH7750_P4_REG32(SH7750_FRQCR_REGOFS)
-#define SH7750_FRQCR_A7       SH7750_A7_REG32(SH7750_FRQCR_REGOFS)
-
-#define SH7750_FRQCR_CKOEN    0x0800   /* Clock Output Enable
-                                          0 - CKIO pin goes to HiZ/pullup
-                                          1 - Clock is output from CKIO */
-#define SH7750_FRQCR_PLL1EN   0x0400   /* PLL circuit 1 enable */
-#define SH7750_FRQCR_PLL2EN   0x0200   /* PLL circuit 2 enable */
-
-#define SH7750_FRQCR_IFC      0x01C0   /* CPU clock frequency division ratio: */
-#define SH7750_FRQCR_IFCDIV1  0x0000   /*    0 - * 1 */
-#define SH7750_FRQCR_IFCDIV2  0x0040   /*    1 - * 1/2 */
-#define SH7750_FRQCR_IFCDIV3  0x0080   /*    2 - * 1/3 */
-#define SH7750_FRQCR_IFCDIV4  0x00C0   /*    3 - * 1/4 */
-#define SH7750_FRQCR_IFCDIV6  0x0100   /*    4 - * 1/6 */
-#define SH7750_FRQCR_IFCDIV8  0x0140   /*    5 - * 1/8 */
-
-#define SH7750_FRQCR_BFC      0x0038   /* Bus clock frequency division ratio: */
-#define SH7750_FRQCR_BFCDIV1  0x0000   /*    0 - * 1 */
-#define SH7750_FRQCR_BFCDIV2  0x0008   /*    1 - * 1/2 */
-#define SH7750_FRQCR_BFCDIV3  0x0010   /*    2 - * 1/3 */
-#define SH7750_FRQCR_BFCDIV4  0x0018   /*    3 - * 1/4 */
-#define SH7750_FRQCR_BFCDIV6  0x0020   /*    4 - * 1/6 */
-#define SH7750_FRQCR_BFCDIV8  0x0028   /*    5 - * 1/8 */
-
-#define SH7750_FRQCR_PFC      0x0007   /* Peripheral module clock frequency
-                                          division ratio: */
-#define SH7750_FRQCR_PFCDIV2  0x0000   /*    0 - * 1/2 */
-#define SH7750_FRQCR_PFCDIV3  0x0001   /*    1 - * 1/3 */
-#define SH7750_FRQCR_PFCDIV4  0x0002   /*    2 - * 1/4 */
-#define SH7750_FRQCR_PFCDIV6  0x0003   /*    3 - * 1/6 */
-#define SH7750_FRQCR_PFCDIV8  0x0004   /*    4 - * 1/8 */
-
-/*
- * Watchdog Timer (WDT)
- */
-
-/* Watchdog Timer Counter register - WTCNT */
-#define SH7750_WTCNT_REGOFS   0xC00008 /* offset */
-#define SH7750_WTCNT          SH7750_P4_REG32(SH7750_WTCNT_REGOFS)
-#define SH7750_WTCNT_A7       SH7750_A7_REG32(SH7750_WTCNT_REGOFS)
-#define SH7750_WTCNT_KEY      0x5A00   /* When WTCNT byte register written,
-                                          you have to set the upper byte to
-                                          0x5A */
-
-/* Watchdog Timer Control/Status register - WTCSR */
-#define SH7750_WTCSR_REGOFS   0xC0000C /* offset */
-#define SH7750_WTCSR          SH7750_P4_REG32(SH7750_WTCSR_REGOFS)
-#define SH7750_WTCSR_A7       SH7750_A7_REG32(SH7750_WTCSR_REGOFS)
-#define SH7750_WTCSR_KEY      0xA500   /* When WTCSR byte register written,
-                                          you have to set the upper byte to
-                                          0xA5 */
-#define SH7750_WTCSR_TME      0x80     /* Timer enable (1-upcount start) */
-#define SH7750_WTCSR_MODE     0x40     /* Timer Mode Select: */
-#define SH7750_WTCSR_MODE_WT  0x40     /*    Watchdog Timer Mode */
-#define SH7750_WTCSR_MODE_IT  0x00     /*    Interval Timer Mode */
-#define SH7750_WTCSR_RSTS     0x20     /* Reset Select: */
-#define SH7750_WTCSR_RST_MAN  0x20     /*    Manual Reset */
-#define SH7750_WTCSR_RST_PWR  0x00     /*    Power-on Reset */
-#define SH7750_WTCSR_WOVF     0x10     /* Watchdog Timer Overflow Flag */
-#define SH7750_WTCSR_IOVF     0x08     /* Interval Timer Overflow Flag */
-#define SH7750_WTCSR_CKS      0x07     /* Clock Select: */
-#define SH7750_WTCSR_CKS_DIV32   0x00  /*   1/32 of frequency divider 2 input */
-#define SH7750_WTCSR_CKS_DIV64   0x01  /*   1/64 */
-#define SH7750_WTCSR_CKS_DIV128  0x02  /*   1/128 */
-#define SH7750_WTCSR_CKS_DIV256  0x03  /*   1/256 */
-#define SH7750_WTCSR_CKS_DIV512  0x04  /*   1/512 */
-#define SH7750_WTCSR_CKS_DIV1024 0x05  /*   1/1024 */
-#define SH7750_WTCSR_CKS_DIV2048 0x06  /*   1/2048 */
-#define SH7750_WTCSR_CKS_DIV4096 0x07  /*   1/4096 */
-
-/*
- * Real-Time Clock (RTC)
- */
-/* 64-Hz Counter Register (byte, read-only) - R64CNT */
-#define SH7750_R64CNT_REGOFS  0xC80000 /* offset */
-#define SH7750_R64CNT         SH7750_P4_REG32(SH7750_R64CNT_REGOFS)
-#define SH7750_R64CNT_A7      SH7750_A7_REG32(SH7750_R64CNT_REGOFS)
-
-/* Second Counter Register (byte, BCD-coded) - RSECCNT */
-#define SH7750_RSECCNT_REGOFS 0xC80004 /* offset */
-#define SH7750_RSECCNT        SH7750_P4_REG32(SH7750_RSECCNT_REGOFS)
-#define SH7750_RSECCNT_A7     SH7750_A7_REG32(SH7750_RSECCNT_REGOFS)
-
-/* Minute Counter Register (byte, BCD-coded) - RMINCNT */
-#define SH7750_RMINCNT_REGOFS 0xC80008 /* offset */
-#define SH7750_RMINCNT        SH7750_P4_REG32(SH7750_RMINCNT_REGOFS)
-#define SH7750_RMINCNT_A7     SH7750_A7_REG32(SH7750_RMINCNT_REGOFS)
-
-/* Hour Counter Register (byte, BCD-coded) - RHRCNT */
-#define SH7750_RHRCNT_REGOFS  0xC8000C /* offset */
-#define SH7750_RHRCNT         SH7750_P4_REG32(SH7750_RHRCNT_REGOFS)
-#define SH7750_RHRCNT_A7      SH7750_A7_REG32(SH7750_RHRCNT_REGOFS)
-
-/* Day-of-Week Counter Register (byte) - RWKCNT */
-#define SH7750_RWKCNT_REGOFS  0xC80010 /* offset */
-#define SH7750_RWKCNT         SH7750_P4_REG32(SH7750_RWKCNT_REGOFS)
-#define SH7750_RWKCNT_A7      SH7750_A7_REG32(SH7750_RWKCNT_REGOFS)
-
-#define SH7750_RWKCNT_SUN     0        /* Sunday */
-#define SH7750_RWKCNT_MON     1        /* Monday */
-#define SH7750_RWKCNT_TUE     2        /* Tuesday */
-#define SH7750_RWKCNT_WED     3        /* Wednesday */
-#define SH7750_RWKCNT_THU     4        /* Thursday */
-#define SH7750_RWKCNT_FRI     5        /* Friday */
-#define SH7750_RWKCNT_SAT     6        /* Saturday */
-
-/* Day Counter Register (byte, BCD-coded) - RDAYCNT */
-#define SH7750_RDAYCNT_REGOFS 0xC80014 /* offset */
-#define SH7750_RDAYCNT        SH7750_P4_REG32(SH7750_RDAYCNT_REGOFS)
-#define SH7750_RDAYCNT_A7     SH7750_A7_REG32(SH7750_RDAYCNT_REGOFS)
-
-/* Month Counter Register (byte, BCD-coded) - RMONCNT */
-#define SH7750_RMONCNT_REGOFS 0xC80018 /* offset */
-#define SH7750_RMONCNT        SH7750_P4_REG32(SH7750_RMONCNT_REGOFS)
-#define SH7750_RMONCNT_A7     SH7750_A7_REG32(SH7750_RMONCNT_REGOFS)
-
-/* Year Counter Register (half, BCD-coded) - RYRCNT */
-#define SH7750_RYRCNT_REGOFS  0xC8001C /* offset */
-#define SH7750_RYRCNT         SH7750_P4_REG32(SH7750_RYRCNT_REGOFS)
-#define SH7750_RYRCNT_A7      SH7750_A7_REG32(SH7750_RYRCNT_REGOFS)
-
-/* Second Alarm Register (byte, BCD-coded) - RSECAR */
-#define SH7750_RSECAR_REGOFS  0xC80020 /* offset */
-#define SH7750_RSECAR         SH7750_P4_REG32(SH7750_RSECAR_REGOFS)
-#define SH7750_RSECAR_A7      SH7750_A7_REG32(SH7750_RSECAR_REGOFS)
-#define SH7750_RSECAR_ENB     0x80     /* Second Alarm Enable */
-
-/* Minute Alarm Register (byte, BCD-coded) - RMINAR */
-#define SH7750_RMINAR_REGOFS  0xC80024 /* offset */
-#define SH7750_RMINAR         SH7750_P4_REG32(SH7750_RMINAR_REGOFS)
-#define SH7750_RMINAR_A7      SH7750_A7_REG32(SH7750_RMINAR_REGOFS)
-#define SH7750_RMINAR_ENB     0x80     /* Minute Alarm Enable */
-
-/* Hour Alarm Register (byte, BCD-coded) - RHRAR */
-#define SH7750_RHRAR_REGOFS   0xC80028 /* offset */
-#define SH7750_RHRAR          SH7750_P4_REG32(SH7750_RHRAR_REGOFS)
-#define SH7750_RHRAR_A7       SH7750_A7_REG32(SH7750_RHRAR_REGOFS)
-#define SH7750_RHRAR_ENB      0x80     /* Hour Alarm Enable */
-
-/* Day-of-Week Alarm Register (byte) - RWKAR */
-#define SH7750_RWKAR_REGOFS   0xC8002C /* offset */
-#define SH7750_RWKAR          SH7750_P4_REG32(SH7750_RWKAR_REGOFS)
-#define SH7750_RWKAR_A7       SH7750_A7_REG32(SH7750_RWKAR_REGOFS)
-#define SH7750_RWKAR_ENB      0x80     /* Day-of-week Alarm Enable */
-
-#define SH7750_RWKAR_SUN      0        /* Sunday */
-#define SH7750_RWKAR_MON      1        /* Monday */
-#define SH7750_RWKAR_TUE      2        /* Tuesday */
-#define SH7750_RWKAR_WED      3        /* Wednesday */
-#define SH7750_RWKAR_THU      4        /* Thursday */
-#define SH7750_RWKAR_FRI      5        /* Friday */
-#define SH7750_RWKAR_SAT      6        /* Saturday */
-
-/* Day Alarm Register (byte, BCD-coded) - RDAYAR */
-#define SH7750_RDAYAR_REGOFS  0xC80030 /* offset */
-#define SH7750_RDAYAR         SH7750_P4_REG32(SH7750_RDAYAR_REGOFS)
-#define SH7750_RDAYAR_A7      SH7750_A7_REG32(SH7750_RDAYAR_REGOFS)
-#define SH7750_RDAYAR_ENB     0x80     /* Day Alarm Enable */
-
-/* Month Counter Register (byte, BCD-coded) - RMONAR */
-#define SH7750_RMONAR_REGOFS  0xC80034 /* offset */
-#define SH7750_RMONAR         SH7750_P4_REG32(SH7750_RMONAR_REGOFS)
-#define SH7750_RMONAR_A7      SH7750_A7_REG32(SH7750_RMONAR_REGOFS)
-#define SH7750_RMONAR_ENB     0x80     /* Month Alarm Enable */
-
-/* RTC Control Register 1 (byte) - RCR1 */
-#define SH7750_RCR1_REGOFS    0xC80038 /* offset */
-#define SH7750_RCR1           SH7750_P4_REG32(SH7750_RCR1_REGOFS)
-#define SH7750_RCR1_A7        SH7750_A7_REG32(SH7750_RCR1_REGOFS)
-#define SH7750_RCR1_CF        0x80     /* Carry Flag */
-#define SH7750_RCR1_CIE       0x10     /* Carry Interrupt Enable */
-#define SH7750_RCR1_AIE       0x08     /* Alarm Interrupt Enable */
-#define SH7750_RCR1_AF        0x01     /* Alarm Flag */
-
-/* RTC Control Register 2 (byte) - RCR2 */
-#define SH7750_RCR2_REGOFS    0xC8003C /* offset */
-#define SH7750_RCR2           SH7750_P4_REG32(SH7750_RCR2_REGOFS)
-#define SH7750_RCR2_A7        SH7750_A7_REG32(SH7750_RCR2_REGOFS)
-#define SH7750_RCR2_PEF        0x80    /* Periodic Interrupt Flag */
-#define SH7750_RCR2_PES        0x70    /* Periodic Interrupt Enable: */
-#define SH7750_RCR2_PES_DIS    0x00    /*   Periodic Interrupt Disabled */
-#define SH7750_RCR2_PES_DIV256 0x10    /*   Generated at 1/256 sec interval */
-#define SH7750_RCR2_PES_DIV64  0x20    /*   Generated at 1/64 sec interval */
-#define SH7750_RCR2_PES_DIV16  0x30    /*   Generated at 1/16 sec interval */
-#define SH7750_RCR2_PES_DIV4   0x40    /*   Generated at 1/4 sec interval */
-#define SH7750_RCR2_PES_DIV2   0x50    /*   Generated at 1/2 sec interval */
-#define SH7750_RCR2_PES_x1     0x60    /*   Generated at 1 sec interval */
-#define SH7750_RCR2_PES_x2     0x70    /*   Generated at 2 sec interval */
-#define SH7750_RCR2_RTCEN      0x08    /* RTC Crystal Oscillator is Operated */
-#define SH7750_RCR2_ADJ        0x04    /* 30-Second Adjastment */
-#define SH7750_RCR2_RESET      0x02    /* Frequency divider circuits are reset */
-#define SH7750_RCR2_START      0x01    /* 0 - sec, min, hr, day-of-week, month,
-                                          year counters are stopped
-                                          1 - sec, min, hr, day-of-week, month,
-                                          year counters operate normally */
-/*
- * Bus State Controller - BSC
- */
-/* Bus Control Register 1 - BCR1 */
-#define SH7750_BCR1_REGOFS    0x800000 /* offset */
-#define SH7750_BCR1           SH7750_P4_REG32(SH7750_BCR1_REGOFS)
-#define SH7750_BCR1_A7        SH7750_A7_REG32(SH7750_BCR1_REGOFS)
-#define SH7750_BCR1_ENDIAN    0x80000000       /* Endianness (1 - little endian) */
-#define SH7750_BCR1_MASTER    0x40000000       /* Master/Slave mode (1-master) */
-#define SH7750_BCR1_A0MPX     0x20000000       /* Area 0 Memory Type (0-SRAM,1-MPX) */
-#define SH7750_BCR1_IPUP      0x02000000       /* Input Pin Pull-up Control:
-                                                  0 - pull-up resistor is on for
-                                                  control input pins
-                                                  1 - pull-up resistor is off */
-#define SH7750_BCR1_OPUP      0x01000000       /* Output Pin Pull-up Control:
-                                                  0 - pull-up resistor is on for
-                                                  control output pins
-                                                  1 - pull-up resistor is off */
-#define SH7750_BCR1_A1MBC     0x00200000       /* Area 1 SRAM Byte Control Mode:
-                                                  0 - Area 1 SRAM is set to
-                                                  normal mode
-                                                  1 - Area 1 SRAM is set to byte
-                                                  control mode */
-#define SH7750_BCR1_A4MBC     0x00100000       /* Area 4 SRAM Byte Control Mode:
-                                                  0 - Area 4 SRAM is set to
-                                                  normal mode
-                                                  1 - Area 4 SRAM is set to byte
-                                                  control mode */
-#define SH7750_BCR1_BREQEN    0x00080000       /* BREQ Enable:
-                                                  0 - External requests are  not
-                                                  accepted
-                                                  1 - External requests are
-                                                  accepted */
-#define SH7750_BCR1_PSHR      0x00040000       /* Partial Sharing Bit:
-                                                  0 - Master Mode
-                                                  1 - Partial-sharing Mode */
-#define SH7750_BCR1_MEMMPX    0x00020000       /* Area 1 to 6 MPX Interface:
-                                                  0 - SRAM/burst ROM interface
-                                                  1 - MPX interface */
-#define SH7750_BCR1_HIZMEM    0x00008000       /* High Impendance Control. Specifies
-                                                  the state of A[25:0], BS\, CSn\,
-                                                  RD/WR\, CE2A\, CE2B\ in standby
-                                                  mode and when bus is released:
-                                                  0 - signals go to High-Z mode
-                                                  1 - signals driven */
-#define SH7750_BCR1_HIZCNT    0x00004000       /* High Impendance Control. Specifies
-                                                  the state of the RAS\, RAS2\, WEn\,
-                                                  CASn\, DQMn, RD\, CASS\, FRAME\,
-                                                  RD2\ signals in standby mode and
-                                                  when bus is released:
-                                                  0 - signals go to High-Z mode
-                                                  1 - signals driven */
-#define SH7750_BCR1_A0BST     0x00003800       /* Area 0 Burst ROM Control */
-#define SH7750_BCR1_A0BST_SRAM    0x0000       /*   Area 0 accessed as SRAM i/f */
-#define SH7750_BCR1_A0BST_ROM4    0x0800       /*   Area 0 accessed as burst ROM
-                                                  interface, 4 cosequtive access */
-#define SH7750_BCR1_A0BST_ROM8    0x1000       /*   Area 0 accessed as burst ROM
-                                                  interface, 8 cosequtive access */
-#define SH7750_BCR1_A0BST_ROM16   0x1800       /*   Area 0 accessed as burst ROM
-                                                  interface, 16 cosequtive access */
-#define SH7750_BCR1_A0BST_ROM32   0x2000       /*   Area 0 accessed as burst ROM
-                                                  interface, 32 cosequtive access */
-
-#define SH7750_BCR1_A5BST     0x00000700       /* Area 5 Burst ROM Control */
-#define SH7750_BCR1_A5BST_SRAM    0x0000       /*   Area 5 accessed as SRAM i/f */
-#define SH7750_BCR1_A5BST_ROM4    0x0100       /*   Area 5 accessed as burst ROM
-                                                  interface, 4 cosequtive access */
-#define SH7750_BCR1_A5BST_ROM8    0x0200       /*   Area 5 accessed as burst ROM
-                                                  interface, 8 cosequtive access */
-#define SH7750_BCR1_A5BST_ROM16   0x0300       /*   Area 5 accessed as burst ROM
-                                                  interface, 16 cosequtive access */
-#define SH7750_BCR1_A5BST_ROM32   0x0400       /*   Area 5 accessed as burst ROM
-                                                  interface, 32 cosequtive access */
-
-#define SH7750_BCR1_A6BST     0x000000E0       /* Area 6 Burst ROM Control */
-#define SH7750_BCR1_A6BST_SRAM    0x0000       /*   Area 6 accessed as SRAM i/f */
-#define SH7750_BCR1_A6BST_ROM4    0x0020       /*   Area 6 accessed as burst ROM
-                                                  interface, 4 cosequtive access */
-#define SH7750_BCR1_A6BST_ROM8    0x0040       /*   Area 6 accessed as burst ROM
-                                                  interface, 8 cosequtive access */
-#define SH7750_BCR1_A6BST_ROM16   0x0060       /*   Area 6 accessed as burst ROM
-                                                  interface, 16 cosequtive access */
-#define SH7750_BCR1_A6BST_ROM32   0x0080       /*   Area 6 accessed as burst ROM
-                                                  interface, 32 cosequtive access */
-
-#define SH7750_BCR1_DRAMTP        0x001C       /* Area 2 and 3 Memory Type */
-#define SH7750_BCR1_DRAMTP_2SRAM_3SRAM   0x0000        /* Area 2 and 3 are SRAM or MPX
-                                                  interface. */
-#define SH7750_BCR1_DRAMTP_2SRAM_3SDRAM  0x0008        /* Area 2 - SRAM/MPX, Area 3 -
-                                                  synchronous DRAM */
-#define SH7750_BCR1_DRAMTP_2SDRAM_3SDRAM 0x000C        /* Area 2 and 3 are synchronous
-                                                  DRAM interface */
-#define SH7750_BCR1_DRAMTP_2SRAM_3DRAM   0x0010        /* Area 2 - SRAM/MPX, Area 3 -
-                                                  DRAM interface */
-#define SH7750_BCR1_DRAMTP_2DRAM_3DRAM   0x0014        /* Area 2 and 3 are DRAM
-                                                  interface */
-
-#define SH7750_BCR1_A56PCM    0x00000001       /* Area 5 and 6 Bus Type:
-                                                  0 - SRAM interface
-                                                  1 - PCMCIA interface */
-
-/* Bus Control Register 2 (half) - BCR2 */
-#define SH7750_BCR2_REGOFS    0x800004 /* offset */
-#define SH7750_BCR2           SH7750_P4_REG32(SH7750_BCR2_REGOFS)
-#define SH7750_BCR2_A7        SH7750_A7_REG32(SH7750_BCR2_REGOFS)
-
-#define SH7750_BCR2_A0SZ      0xC000   /* Area 0 Bus Width */
-#define SH7750_BCR2_A0SZ_S    14
-#define SH7750_BCR2_A6SZ      0x3000   /* Area 6 Bus Width */
-#define SH7750_BCR2_A6SZ_S    12
-#define SH7750_BCR2_A5SZ      0x0C00   /* Area 5 Bus Width */
-#define SH7750_BCR2_A5SZ_S    10
-#define SH7750_BCR2_A4SZ      0x0300   /* Area 4 Bus Width */
-#define SH7750_BCR2_A4SZ_S    8
-#define SH7750_BCR2_A3SZ      0x00C0   /* Area 3 Bus Width */
-#define SH7750_BCR2_A3SZ_S    6
-#define SH7750_BCR2_A2SZ      0x0030   /* Area 2 Bus Width */
-#define SH7750_BCR2_A2SZ_S    4
-#define SH7750_BCR2_A1SZ      0x000C   /* Area 1 Bus Width */
-#define SH7750_BCR2_A1SZ_S    2
-#define SH7750_BCR2_SZ_64     0        /* 64 bits */
-#define SH7750_BCR2_SZ_8      1        /* 8 bits */
-#define SH7750_BCR2_SZ_16     2        /* 16 bits */
-#define SH7750_BCR2_SZ_32     3        /* 32 bits */
-#define SH7750_BCR2_PORTEN    0x0001   /* Port Function Enable :
-                                          0 - D51-D32 are not used as a port
-                                          1 - D51-D32 are used as a port */
-
-/* Wait Control Register 1 - WCR1 */
-#define SH7750_WCR1_REGOFS    0x800008 /* offset */
-#define SH7750_WCR1           SH7750_P4_REG32(SH7750_WCR1_REGOFS)
-#define SH7750_WCR1_A7        SH7750_A7_REG32(SH7750_WCR1_REGOFS)
-#define SH7750_WCR1_DMAIW     0x70000000       /* DACK Device Inter-Cycle Idle
-                                                  specification */
-#define SH7750_WCR1_DMAIW_S   28
-#define SH7750_WCR1_A6IW      0x07000000       /* Area 6 Inter-Cycle Idle spec. */
-#define SH7750_WCR1_A6IW_S    24
-#define SH7750_WCR1_A5IW      0x00700000       /* Area 5 Inter-Cycle Idle spec. */
-#define SH7750_WCR1_A5IW_S    20
-#define SH7750_WCR1_A4IW      0x00070000       /* Area 4 Inter-Cycle Idle spec. */
-#define SH7750_WCR1_A4IW_S    16
-#define SH7750_WCR1_A3IW      0x00007000       /* Area 3 Inter-Cycle Idle spec. */
-#define SH7750_WCR1_A3IW_S    12
-#define SH7750_WCR1_A2IW      0x00000700       /* Area 2 Inter-Cycle Idle spec. */
-#define SH7750_WCR1_A2IW_S    8
-#define SH7750_WCR1_A1IW      0x00000070       /* Area 1 Inter-Cycle Idle spec. */
-#define SH7750_WCR1_A1IW_S    4
-#define SH7750_WCR1_A0IW      0x00000007       /* Area 0 Inter-Cycle Idle spec. */
-#define SH7750_WCR1_A0IW_S    0
-
-/* Wait Control Register 2 - WCR2 */
-#define SH7750_WCR2_REGOFS    0x80000C /* offset */
-#define SH7750_WCR2           SH7750_P4_REG32(SH7750_WCR2_REGOFS)
-#define SH7750_WCR2_A7        SH7750_A7_REG32(SH7750_WCR2_REGOFS)
-
-#define SH7750_WCR2_A6W       0xE0000000       /* Area 6 Wait Control */
-#define SH7750_WCR2_A6W_S     29
-#define SH7750_WCR2_A6B       0x1C000000       /* Area 6 Burst Pitch */
-#define SH7750_WCR2_A6B_S     26
-#define SH7750_WCR2_A5W       0x03800000       /* Area 5 Wait Control */
-#define SH7750_WCR2_A5W_S     23
-#define SH7750_WCR2_A5B       0x00700000       /* Area 5 Burst Pitch */
-#define SH7750_WCR2_A5B_S     20
-#define SH7750_WCR2_A4W       0x000E0000       /* Area 4 Wait Control */
-#define SH7750_WCR2_A4W_S     17
-#define SH7750_WCR2_A3W       0x0000E000       /* Area 3 Wait Control */
-#define SH7750_WCR2_A3W_S     13
-#define SH7750_WCR2_A2W       0x00000E00       /* Area 2 Wait Control */
-#define SH7750_WCR2_A2W_S     9
-#define SH7750_WCR2_A1W       0x000001C0       /* Area 1 Wait Control */
-#define SH7750_WCR2_A1W_S     6
-#define SH7750_WCR2_A0W       0x00000038       /* Area 0 Wait Control */
-#define SH7750_WCR2_A0W_S     3
-#define SH7750_WCR2_A0B       0x00000007       /* Area 0 Burst Pitch */
-#define SH7750_WCR2_A0B_S     0
-
-#define SH7750_WCR2_WS0       0        /* 0 wait states inserted */
-#define SH7750_WCR2_WS1       1        /* 1 wait states inserted */
-#define SH7750_WCR2_WS2       2        /* 2 wait states inserted */
-#define SH7750_WCR2_WS3       3        /* 3 wait states inserted */
-#define SH7750_WCR2_WS6       4        /* 6 wait states inserted */
-#define SH7750_WCR2_WS9       5        /* 9 wait states inserted */
-#define SH7750_WCR2_WS12      6        /* 12 wait states inserted */
-#define SH7750_WCR2_WS15      7        /* 15 wait states inserted */
-
-#define SH7750_WCR2_BPWS0     0        /* 0 wait states inserted from 2nd access */
-#define SH7750_WCR2_BPWS1     1        /* 1 wait states inserted from 2nd access */
-#define SH7750_WCR2_BPWS2     2        /* 2 wait states inserted from 2nd access */
-#define SH7750_WCR2_BPWS3     3        /* 3 wait states inserted from 2nd access */
-#define SH7750_WCR2_BPWS4     4        /* 4 wait states inserted from 2nd access */
-#define SH7750_WCR2_BPWS5     5        /* 5 wait states inserted from 2nd access */
-#define SH7750_WCR2_BPWS6     6        /* 6 wait states inserted from 2nd access */
-#define SH7750_WCR2_BPWS7     7        /* 7 wait states inserted from 2nd access */
-
-/* DRAM CAS\ Assertion Delay (area 3,2) */
-#define SH7750_WCR2_DRAM_CAS_ASW1   0  /* 1 cycle */
-#define SH7750_WCR2_DRAM_CAS_ASW2   1  /* 2 cycles */
-#define SH7750_WCR2_DRAM_CAS_ASW3   2  /* 3 cycles */
-#define SH7750_WCR2_DRAM_CAS_ASW4   3  /* 4 cycles */
-#define SH7750_WCR2_DRAM_CAS_ASW7   4  /* 7 cycles */
-#define SH7750_WCR2_DRAM_CAS_ASW10  5  /* 10 cycles */
-#define SH7750_WCR2_DRAM_CAS_ASW13  6  /* 13 cycles */
-#define SH7750_WCR2_DRAM_CAS_ASW16  7  /* 16 cycles */
-
-/* SDRAM CAS\ Latency Cycles */
-#define SH7750_WCR2_SDRAM_CAS_LAT1  1  /* 1 cycle */
-#define SH7750_WCR2_SDRAM_CAS_LAT2  2  /* 2 cycles */
-#define SH7750_WCR2_SDRAM_CAS_LAT3  3  /* 3 cycles */
-#define SH7750_WCR2_SDRAM_CAS_LAT4  4  /* 4 cycles */
-#define SH7750_WCR2_SDRAM_CAS_LAT5  5  /* 5 cycles */
-
-/* Wait Control Register 3 - WCR3 */
-#define SH7750_WCR3_REGOFS    0x800010 /* offset */
-#define SH7750_WCR3           SH7750_P4_REG32(SH7750_WCR3_REGOFS)
-#define SH7750_WCR3_A7        SH7750_A7_REG32(SH7750_WCR3_REGOFS)
-
-#define SH7750_WCR3_A6S       0x04000000       /* Area 6 Write Strobe Setup time */
-#define SH7750_WCR3_A6H       0x03000000       /* Area 6 Data Hold Time */
-#define SH7750_WCR3_A6H_S     24
-#define SH7750_WCR3_A5S       0x00400000       /* Area 5 Write Strobe Setup time */
-#define SH7750_WCR3_A5H       0x00300000       /* Area 5 Data Hold Time */
-#define SH7750_WCR3_A5H_S     20
-#define SH7750_WCR3_A4S       0x00040000       /* Area 4 Write Strobe Setup time */
-#define SH7750_WCR3_A4H       0x00030000       /* Area 4 Data Hold Time */
-#define SH7750_WCR3_A4H_S     16
-#define SH7750_WCR3_A3S       0x00004000       /* Area 3 Write Strobe Setup time */
-#define SH7750_WCR3_A3H       0x00003000       /* Area 3 Data Hold Time */
-#define SH7750_WCR3_A3H_S     12
-#define SH7750_WCR3_A2S       0x00000400       /* Area 2 Write Strobe Setup time */
-#define SH7750_WCR3_A2H       0x00000300       /* Area 2 Data Hold Time */
-#define SH7750_WCR3_A2H_S     8
-#define SH7750_WCR3_A1S       0x00000040       /* Area 1 Write Strobe Setup time */
-#define SH7750_WCR3_A1H       0x00000030       /* Area 1 Data Hold Time */
-#define SH7750_WCR3_A1H_S     4
-#define SH7750_WCR3_A0S       0x00000004       /* Area 0 Write Strobe Setup time */
-#define SH7750_WCR3_A0H       0x00000003       /* Area 0 Data Hold Time */
-#define SH7750_WCR3_A0H_S     0
-
-#define SH7750_WCR3_DHWS_0    0        /* 0 wait states data hold time */
-#define SH7750_WCR3_DHWS_1    1        /* 1 wait states data hold time */
-#define SH7750_WCR3_DHWS_2    2        /* 2 wait states data hold time */
-#define SH7750_WCR3_DHWS_3    3        /* 3 wait states data hold time */
-
-#define SH7750_MCR_REGOFS     0x800014 /* offset */
-#define SH7750_MCR            SH7750_P4_REG32(SH7750_MCR_REGOFS)
-#define SH7750_MCR_A7         SH7750_A7_REG32(SH7750_MCR_REGOFS)
-
-#define SH7750_MCR_RASD       0x80000000       /* RAS Down mode */
-#define SH7750_MCR_MRSET      0x40000000       /* SDRAM Mode Register Set */
-#define SH7750_MCR_PALL       0x00000000       /* SDRAM Precharge All cmd. Mode */
-#define SH7750_MCR_TRC        0x38000000       /* RAS Precharge Time at End of
-                                                  Refresh: */
-#define SH7750_MCR_TRC_0      0x00000000       /*    0 */
-#define SH7750_MCR_TRC_3      0x08000000       /*    3 */
-#define SH7750_MCR_TRC_6      0x10000000       /*    6 */
-#define SH7750_MCR_TRC_9      0x18000000       /*    9 */
-#define SH7750_MCR_TRC_12     0x20000000       /*    12 */
-#define SH7750_MCR_TRC_15     0x28000000       /*    15 */
-#define SH7750_MCR_TRC_18     0x30000000       /*    18 */
-#define SH7750_MCR_TRC_21     0x38000000       /*    21 */
-
-#define SH7750_MCR_TCAS       0x00800000       /* CAS Negation Period */
-#define SH7750_MCR_TCAS_1     0x00000000       /*    1 */
-#define SH7750_MCR_TCAS_2     0x00800000       /*    2 */
-
-#define SH7750_MCR_TPC        0x00380000       /* DRAM: RAS Precharge Period
-                                                  SDRAM: minimum number of cycles
-                                                  until the next bank active cmd
-                                                  is output after precharging */
-#define SH7750_MCR_TPC_S      19
-#define SH7750_MCR_TPC_SDRAM_1 0x00000000      /* 1 cycle */
-#define SH7750_MCR_TPC_SDRAM_2 0x00080000      /* 2 cycles */
-#define SH7750_MCR_TPC_SDRAM_3 0x00100000      /* 3 cycles */
-#define SH7750_MCR_TPC_SDRAM_4 0x00180000      /* 4 cycles */
-#define SH7750_MCR_TPC_SDRAM_5 0x00200000      /* 5 cycles */
-#define SH7750_MCR_TPC_SDRAM_6 0x00280000      /* 6 cycles */
-#define SH7750_MCR_TPC_SDRAM_7 0x00300000      /* 7 cycles */
-#define SH7750_MCR_TPC_SDRAM_8 0x00380000      /* 8 cycles */
-
-#define SH7750_MCR_RCD        0x00030000       /* DRAM: RAS-CAS Assertion Delay time
-                                                  SDRAM: bank active-read/write cmd
-                                                  delay time */
-#define SH7750_MCR_RCD_DRAM_2  0x00000000      /* DRAM delay 2 clocks */
-#define SH7750_MCR_RCD_DRAM_3  0x00010000      /* DRAM delay 3 clocks */
-#define SH7750_MCR_RCD_DRAM_4  0x00020000      /* DRAM delay 4 clocks */
-#define SH7750_MCR_RCD_DRAM_5  0x00030000      /* DRAM delay 5 clocks */
-#define SH7750_MCR_RCD_SDRAM_2 0x00010000      /* DRAM delay 2 clocks */
-#define SH7750_MCR_RCD_SDRAM_3 0x00020000      /* DRAM delay 3 clocks */
-#define SH7750_MCR_RCD_SDRAM_4 0x00030000      /* DRAM delay 4 clocks */
-
-#define SH7750_MCR_TRWL       0x0000E000       /* SDRAM Write Precharge Delay */
-#define SH7750_MCR_TRWL_1     0x00000000       /*    1 */
-#define SH7750_MCR_TRWL_2     0x00002000       /*    2 */
-#define SH7750_MCR_TRWL_3     0x00004000       /*    3 */
-#define SH7750_MCR_TRWL_4     0x00006000       /*    4 */
-#define SH7750_MCR_TRWL_5     0x00008000       /*    5 */
-
-#define SH7750_MCR_TRAS       0x00001C00       /* DRAM: CAS-Before-RAS Refresh RAS
-                                                  asserting period
-                                                  SDRAM: Command interval after
-                                                  synchronous DRAM refresh */
-#define SH7750_MCR_TRAS_DRAM_2         0x00000000      /* 2 */
-#define SH7750_MCR_TRAS_DRAM_3         0x00000400      /* 3 */
-#define SH7750_MCR_TRAS_DRAM_4         0x00000800      /* 4 */
-#define SH7750_MCR_TRAS_DRAM_5         0x00000C00      /* 5 */
-#define SH7750_MCR_TRAS_DRAM_6         0x00001000      /* 6 */
-#define SH7750_MCR_TRAS_DRAM_7         0x00001400      /* 7 */
-#define SH7750_MCR_TRAS_DRAM_8         0x00001800      /* 8 */
-#define SH7750_MCR_TRAS_DRAM_9         0x00001C00      /* 9 */
-
-#define SH7750_MCR_TRAS_SDRAM_TRC_4    0x00000000      /* 4 + TRC */
-#define SH7750_MCR_TRAS_SDRAM_TRC_5    0x00000400      /* 5 + TRC */
-#define SH7750_MCR_TRAS_SDRAM_TRC_6    0x00000800      /* 6 + TRC */
-#define SH7750_MCR_TRAS_SDRAM_TRC_7    0x00000C00      /* 7 + TRC */
-#define SH7750_MCR_TRAS_SDRAM_TRC_8    0x00001000      /* 8 + TRC */
-#define SH7750_MCR_TRAS_SDRAM_TRC_9    0x00001400      /* 9 + TRC */
-#define SH7750_MCR_TRAS_SDRAM_TRC_10   0x00001800      /* 10 + TRC */
-#define SH7750_MCR_TRAS_SDRAM_TRC_11   0x00001C00      /* 11 + TRC */
-
-#define SH7750_MCR_BE         0x00000200       /* Burst Enable */
-#define SH7750_MCR_SZ         0x00000180       /* Memory Data Size */
-#define SH7750_MCR_SZ_64      0x00000000       /*    64 bits */
-#define SH7750_MCR_SZ_16      0x00000100       /*    16 bits */
-#define SH7750_MCR_SZ_32      0x00000180       /*    32 bits */
-
-#define SH7750_MCR_AMX        0x00000078       /* Address Multiplexing */
-#define SH7750_MCR_AMX_S      3
-#define SH7750_MCR_AMX_DRAM_8BIT_COL    0x00000000     /* 8-bit column addr */
-#define SH7750_MCR_AMX_DRAM_9BIT_COL    0x00000008     /* 9-bit column addr */
-#define SH7750_MCR_AMX_DRAM_10BIT_COL   0x00000010     /* 10-bit column addr */
-#define SH7750_MCR_AMX_DRAM_11BIT_COL   0x00000018     /* 11-bit column addr */
-#define SH7750_MCR_AMX_DRAM_12BIT_COL   0x00000020     /* 12-bit column addr */
-/* See SH7750 Hardware Manual for SDRAM address multiplexor selection */
-
-#define SH7750_MCR_RFSH       0x00000004       /* Refresh Control */
-#define SH7750_MCR_RMODE      0x00000002       /* Refresh Mode: */
-#define SH7750_MCR_RMODE_NORMAL 0x00000000     /* Normal Refresh Mode */
-#define SH7750_MCR_RMODE_SELF   0x00000002     /* Self-Refresh Mode */
-#define SH7750_MCR_RMODE_EDO    0x00000001     /* EDO Mode */
-
-/* SDRAM Mode Set address */
-#define SH7750_SDRAM_MODE_A2_BASE  0xFF900000
-#define SH7750_SDRAM_MODE_A3_BASE  0xFF940000
-#define SH7750_SDRAM_MODE_A2_32BIT(x) (SH7750_SDRAM_MODE_A2_BASE + ((x) << 2))
-#define SH7750_SDRAM_MODE_A3_32BIT(x) (SH7750_SDRAM_MODE_A3_BASE + ((x) << 2))
-#define SH7750_SDRAM_MODE_A2_64BIT(x) (SH7750_SDRAM_MODE_A2_BASE + ((x) << 3))
-#define SH7750_SDRAM_MODE_A3_64BIT(x) (SH7750_SDRAM_MODE_A3_BASE + ((x) << 3))
-
-
-/* PCMCIA Control Register (half) - PCR */
-#define SH7750_PCR_REGOFS     0x800018 /* offset */
-#define SH7750_PCR            SH7750_P4_REG32(SH7750_PCR_REGOFS)
-#define SH7750_PCR_A7         SH7750_A7_REG32(SH7750_PCR_REGOFS)
-
-#define SH7750_PCR_A5PCW      0xC000   /* Area 5 PCMCIA Wait - Number of wait
-                                          states to be added to the number of
-                                          waits specified by WCR2 in a low-speed
-                                          PCMCIA wait cycle */
-#define SH7750_PCR_A5PCW_0    0x0000   /*    0 waits inserted */
-#define SH7750_PCR_A5PCW_15   0x4000   /*    15 waits inserted */
-#define SH7750_PCR_A5PCW_30   0x8000   /*    30 waits inserted */
-#define SH7750_PCR_A5PCW_50   0xC000   /*    50 waits inserted */
-
-#define SH7750_PCR_A6PCW      0x3000   /* Area 6 PCMCIA Wait - Number of wait
-                                          states to be added to the number of
-                                          waits specified by WCR2 in a low-speed
-                                          PCMCIA wait cycle */
-#define SH7750_PCR_A6PCW_0    0x0000   /*    0 waits inserted */
-#define SH7750_PCR_A6PCW_15   0x1000   /*    15 waits inserted */
-#define SH7750_PCR_A6PCW_30   0x2000   /*    30 waits inserted */
-#define SH7750_PCR_A6PCW_50   0x3000   /*    50 waits inserted */
-
-#define SH7750_PCR_A5TED      0x0E00   /* Area 5 Address-OE\/WE\ Assertion Delay,
-                                          delay time from address output to
-                                          OE\/WE\ assertion on the connected
-                                          PCMCIA interface */
-#define SH7750_PCR_A5TED_S    9
-#define SH7750_PCR_A6TED      0x01C0   /* Area 6 Address-OE\/WE\ Assertion Delay */
-#define SH7750_PCR_A6TED_S    6
-
-#define SH7750_PCR_TED_0WS    0        /* 0 Waits inserted */
-#define SH7750_PCR_TED_1WS    1        /* 1 Waits inserted */
-#define SH7750_PCR_TED_2WS    2        /* 2 Waits inserted */
-#define SH7750_PCR_TED_3WS    3        /* 3 Waits inserted */
-#define SH7750_PCR_TED_6WS    4        /* 6 Waits inserted */
-#define SH7750_PCR_TED_9WS    5        /* 9 Waits inserted */
-#define SH7750_PCR_TED_12WS   6        /* 12 Waits inserted */
-#define SH7750_PCR_TED_15WS   7        /* 15 Waits inserted */
-
-#define SH7750_PCR_A5TEH      0x0038   /* Area 5 OE\/WE\ Negation Address delay,
-                                          address hold delay time from OE\/WE\
-                                          negation in a write on the connected
-                                          PCMCIA interface */
-#define SH7750_PCR_A5TEH_S    3
-
-#define SH7750_PCR_A6TEH      0x0007   /* Area 6 OE\/WE\ Negation Address delay */
-#define SH7750_PCR_A6TEH_S    0
-
-#define SH7750_PCR_TEH_0WS    0        /* 0 Waits inserted */
-#define SH7750_PCR_TEH_1WS    1        /* 1 Waits inserted */
-#define SH7750_PCR_TEH_2WS    2        /* 2 Waits inserted */
-#define SH7750_PCR_TEH_3WS    3        /* 3 Waits inserted */
-#define SH7750_PCR_TEH_6WS    4        /* 6 Waits inserted */
-#define SH7750_PCR_TEH_9WS    5        /* 9 Waits inserted */
-#define SH7750_PCR_TEH_12WS   6        /* 12 Waits inserted */
-#define SH7750_PCR_TEH_15WS   7        /* 15 Waits inserted */
-
-/* Refresh Timer Control/Status Register (half) - RTSCR */
-#define SH7750_RTCSR_REGOFS   0x80001C /* offset */
-#define SH7750_RTCSR          SH7750_P4_REG32(SH7750_RTCSR_REGOFS)
-#define SH7750_RTCSR_A7       SH7750_A7_REG32(SH7750_RTCSR_REGOFS)
-
-#define SH7750_RTCSR_KEY      0xA500   /* RTCSR write key */
-#define SH7750_RTCSR_CMF      0x0080   /* Compare-Match Flag (indicates a
-                                          match between the refresh timer
-                                          counter and refresh time constant) */
-#define SH7750_RTCSR_CMIE     0x0040   /* Compare-Match Interrupt Enable */
-#define SH7750_RTCSR_CKS      0x0038   /* Refresh Counter Clock Selects */
-#define SH7750_RTCSR_CKS_DIS          0x0000   /* Clock Input Disabled */
-#define SH7750_RTCSR_CKS_CKIO_DIV4    0x0008   /* Bus Clock / 4 */
-#define SH7750_RTCSR_CKS_CKIO_DIV16   0x0010   /* Bus Clock / 16 */
-#define SH7750_RTCSR_CKS_CKIO_DIV64   0x0018   /* Bus Clock / 64 */
-#define SH7750_RTCSR_CKS_CKIO_DIV256  0x0020   /* Bus Clock / 256 */
-#define SH7750_RTCSR_CKS_CKIO_DIV1024 0x0028   /* Bus Clock / 1024 */
-#define SH7750_RTCSR_CKS_CKIO_DIV2048 0x0030   /* Bus Clock / 2048 */
-#define SH7750_RTCSR_CKS_CKIO_DIV4096 0x0038   /* Bus Clock / 4096 */
-
-#define SH7750_RTCSR_OVF      0x0004   /* Refresh Count Overflow Flag */
-#define SH7750_RTCSR_OVIE     0x0002   /* Refresh Count Overflow Interrupt
-                                          Enable */
-#define SH7750_RTCSR_LMTS     0x0001   /* Refresh Count Overflow Limit Select */
-#define SH7750_RTCSR_LMTS_1024 0x0000  /* Count Limit is 1024 */
-#define SH7750_RTCSR_LMTS_512  0x0001  /* Count Limit is 512 */
-
-/* Refresh Timer Counter (half) - RTCNT */
-#define SH7750_RTCNT_REGOFS   0x800020 /* offset */
-#define SH7750_RTCNT          SH7750_P4_REG32(SH7750_RTCNT_REGOFS)
-#define SH7750_RTCNT_A7       SH7750_A7_REG32(SH7750_RTCNT_REGOFS)
-
-#define SH7750_RTCNT_KEY      0xA500   /* RTCNT write key */
-
-/* Refresh Time Constant Register (half) - RTCOR */
-#define SH7750_RTCOR_REGOFS   0x800024 /* offset */
-#define SH7750_RTCOR          SH7750_P4_REG32(SH7750_RTCOR_REGOFS)
-#define SH7750_RTCOR_A7       SH7750_A7_REG32(SH7750_RTCOR_REGOFS)
-
-#define SH7750_RTCOR_KEY      0xA500   /* RTCOR write key */
-
-/* Refresh Count Register (half) - RFCR */
-#define SH7750_RFCR_REGOFS    0x800028 /* offset */
-#define SH7750_RFCR           SH7750_P4_REG32(SH7750_RFCR_REGOFS)
-#define SH7750_RFCR_A7        SH7750_A7_REG32(SH7750_RFCR_REGOFS)
-
-#define SH7750_RFCR_KEY       0xA400   /* RFCR write key */
-
-/* Synchronous DRAM mode registers - SDMR */
-#define SH7750_SDMR2_REGOFS   0x900000 /* base offset */
-#define SH7750_SDMR2_REGNB    0x0FFC   /* nb of register */
-#define SH7750_SDMR2          SH7750_P4_REG32(SH7750_SDMR2_REGOFS)
-#define SH7750_SDMR2_A7       SH7750_A7_REG32(SH7750_SDMR2_REGOFS)
-
-#define SH7750_SDMR3_REGOFS   0x940000 /* offset */
-#define SH7750_SDMR3_REGNB    0x0FFC   /* nb of register */
-#define SH7750_SDMR3          SH7750_P4_REG32(SH7750_SDMR3_REGOFS)
-#define SH7750_SDMR3_A7       SH7750_A7_REG32(SH7750_SDMR3_REGOFS)
-
-/*
- * Direct Memory Access Controller (DMAC)
- */
-
-/* DMA Source Address Register - SAR0, SAR1, SAR2, SAR3 */
-#define SH7750_SAR_REGOFS(n)  (0xA00000 + ((n)*16))    /* offset */
-#define SH7750_SAR(n)         SH7750_P4_REG32(SH7750_SAR_REGOFS(n))
-#define SH7750_SAR_A7(n)      SH7750_A7_REG32(SH7750_SAR_REGOFS(n))
-#define SH7750_SAR0           SH7750_SAR(0)
-#define SH7750_SAR1           SH7750_SAR(1)
-#define SH7750_SAR2           SH7750_SAR(2)
-#define SH7750_SAR3           SH7750_SAR(3)
-#define SH7750_SAR0_A7        SH7750_SAR_A7(0)
-#define SH7750_SAR1_A7        SH7750_SAR_A7(1)
-#define SH7750_SAR2_A7        SH7750_SAR_A7(2)
-#define SH7750_SAR3_A7        SH7750_SAR_A7(3)
-
-/* DMA Destination Address Register - DAR0, DAR1, DAR2, DAR3 */
-#define SH7750_DAR_REGOFS(n)  (0xA00004 + ((n)*16))    /* offset */
-#define SH7750_DAR(n)         SH7750_P4_REG32(SH7750_DAR_REGOFS(n))
-#define SH7750_DAR_A7(n)      SH7750_A7_REG32(SH7750_DAR_REGOFS(n))
-#define SH7750_DAR0           SH7750_DAR(0)
-#define SH7750_DAR1           SH7750_DAR(1)
-#define SH7750_DAR2           SH7750_DAR(2)
-#define SH7750_DAR3           SH7750_DAR(3)
-#define SH7750_DAR0_A7        SH7750_DAR_A7(0)
-#define SH7750_DAR1_A7        SH7750_DAR_A7(1)
-#define SH7750_DAR2_A7        SH7750_DAR_A7(2)
-#define SH7750_DAR3_A7        SH7750_DAR_A7(3)
-
-/* DMA Transfer Count Register - DMATCR0, DMATCR1, DMATCR2, DMATCR3 */
-#define SH7750_DMATCR_REGOFS(n)  (0xA00008 + ((n)*16)) /* offset */
-#define SH7750_DMATCR(n)      SH7750_P4_REG32(SH7750_DMATCR_REGOFS(n))
-#define SH7750_DMATCR_A7(n)   SH7750_A7_REG32(SH7750_DMATCR_REGOFS(n))
-#define SH7750_DMATCR0_P4     SH7750_DMATCR(0)
-#define SH7750_DMATCR1_P4     SH7750_DMATCR(1)
-#define SH7750_DMATCR2_P4     SH7750_DMATCR(2)
-#define SH7750_DMATCR3_P4     SH7750_DMATCR(3)
-#define SH7750_DMATCR0_A7     SH7750_DMATCR_A7(0)
-#define SH7750_DMATCR1_A7     SH7750_DMATCR_A7(1)
-#define SH7750_DMATCR2_A7     SH7750_DMATCR_A7(2)
-#define SH7750_DMATCR3_A7     SH7750_DMATCR_A7(3)
-
-/* DMA Channel Control Register - CHCR0, CHCR1, CHCR2, CHCR3 */
-#define SH7750_CHCR_REGOFS(n)  (0xA0000C + ((n)*16))   /* offset */
-#define SH7750_CHCR(n)        SH7750_P4_REG32(SH7750_CHCR_REGOFS(n))
-#define SH7750_CHCR_A7(n)     SH7750_A7_REG32(SH7750_CHCR_REGOFS(n))
-#define SH7750_CHCR0          SH7750_CHCR(0)
-#define SH7750_CHCR1          SH7750_CHCR(1)
-#define SH7750_CHCR2          SH7750_CHCR(2)
-#define SH7750_CHCR3          SH7750_CHCR(3)
-#define SH7750_CHCR0_A7       SH7750_CHCR_A7(0)
-#define SH7750_CHCR1_A7       SH7750_CHCR_A7(1)
-#define SH7750_CHCR2_A7       SH7750_CHCR_A7(2)
-#define SH7750_CHCR3_A7       SH7750_CHCR_A7(3)
-
-#define SH7750_CHCR_SSA       0xE0000000       /* Source Address Space Attribute */
-#define SH7750_CHCR_SSA_PCMCIA  0x00000000     /* Reserved in PCMCIA access */
-#define SH7750_CHCR_SSA_DYNBSZ  0x20000000     /* Dynamic Bus Sizing I/O space */
-#define SH7750_CHCR_SSA_IO8     0x40000000     /* 8-bit I/O space */
-#define SH7750_CHCR_SSA_IO16    0x60000000     /* 16-bit I/O space */
-#define SH7750_CHCR_SSA_CMEM8   0x80000000     /* 8-bit common memory space */
-#define SH7750_CHCR_SSA_CMEM16  0xA0000000     /* 16-bit common memory space */
-#define SH7750_CHCR_SSA_AMEM8   0xC0000000     /* 8-bit attribute memory space */
-#define SH7750_CHCR_SSA_AMEM16  0xE0000000     /* 16-bit attribute memory space */
-
-#define SH7750_CHCR_STC       0x10000000       /* Source Address Wait Control Select,
-                                                  specifies CS5 or CS6 space wait
-                                                  control for PCMCIA access */
-
-#define SH7750_CHCR_DSA       0x0E000000       /* Source Address Space Attribute */
-#define SH7750_CHCR_DSA_PCMCIA  0x00000000     /* Reserved in PCMCIA access */
-#define SH7750_CHCR_DSA_DYNBSZ  0x02000000     /* Dynamic Bus Sizing I/O space */
-#define SH7750_CHCR_DSA_IO8     0x04000000     /* 8-bit I/O space */
-#define SH7750_CHCR_DSA_IO16    0x06000000     /* 16-bit I/O space */
-#define SH7750_CHCR_DSA_CMEM8   0x08000000     /* 8-bit common memory space */
-#define SH7750_CHCR_DSA_CMEM16  0x0A000000     /* 16-bit common memory space */
-#define SH7750_CHCR_DSA_AMEM8   0x0C000000     /* 8-bit attribute memory space */
-#define SH7750_CHCR_DSA_AMEM16  0x0E000000     /* 16-bit attribute memory space */
-
-#define SH7750_CHCR_DTC       0x01000000       /* Destination Address Wait Control
-                                                  Select, specifies CS5 or CS6
-                                                  space wait control for PCMCIA
-                                                  access */
-
-#define SH7750_CHCR_DS        0x00080000       /* DREQ\ Select : */
-#define SH7750_CHCR_DS_LOWLVL 0x00000000       /*     Low Level Detection */
-#define SH7750_CHCR_DS_FALL   0x00080000       /*     Falling Edge Detection */
-
-#define SH7750_CHCR_RL        0x00040000       /* Request Check Level: */
-#define SH7750_CHCR_RL_ACTH   0x00000000       /*     DRAK is an active high out */
-#define SH7750_CHCR_RL_ACTL   0x00040000       /*     DRAK is an active low out */
-
-#define SH7750_CHCR_AM        0x00020000       /* Acknowledge Mode: */
-#define SH7750_CHCR_AM_RD     0x00000000       /*     DACK is output in read cycle */
-#define SH7750_CHCR_AM_WR     0x00020000       /*     DACK is output in write cycle */
-
-#define SH7750_CHCR_AL        0x00010000       /* Acknowledge Level: */
-#define SH7750_CHCR_AL_ACTH   0x00000000       /*     DACK is an active high out */
-#define SH7750_CHCR_AL_ACTL   0x00010000       /*     DACK is an active low out */
-
-#define SH7750_CHCR_DM        0x0000C000       /* Destination Address Mode: */
-#define SH7750_CHCR_DM_FIX    0x00000000       /*     Destination Addr Fixed */
-#define SH7750_CHCR_DM_INC    0x00004000       /*     Destination Addr Incremented */
-#define SH7750_CHCR_DM_DEC    0x00008000       /*     Destination Addr Decremented */
-
-#define SH7750_CHCR_SM        0x00003000       /* Source Address Mode: */
-#define SH7750_CHCR_SM_FIX    0x00000000       /*     Source Addr Fixed */
-#define SH7750_CHCR_SM_INC    0x00001000       /*     Source Addr Incremented */
-#define SH7750_CHCR_SM_DEC    0x00002000       /*     Source Addr Decremented */
-
-#define SH7750_CHCR_RS        0x00000F00       /* Request Source Select: */
-#define SH7750_CHCR_RS_ER_DA_EA_TO_EA   0x000  /* External Request, Dual Address
-                                                  Mode (External Addr Space->
-                                                  External Addr Space) */
-#define SH7750_CHCR_RS_ER_SA_EA_TO_ED   0x200  /* External Request, Single
-                                                  Address Mode (External Addr
-                                                  Space -> External Device) */
-#define SH7750_CHCR_RS_ER_SA_ED_TO_EA   0x300  /* External Request, Single
-                                                  Address Mode, (External
-                                                  Device -> External Addr
-                                                  Space) */
-#define SH7750_CHCR_RS_AR_EA_TO_EA      0x400  /* Auto-Request (External Addr
-                                                  Space -> External Addr Space) */
-
-#define SH7750_CHCR_RS_AR_EA_TO_OCP     0x500  /* Auto-Request (External Addr
-                                                  Space -> On-chip Peripheral
-                                                  Module) */
-#define SH7750_CHCR_RS_AR_OCP_TO_EA     0x600  /* Auto-Request (On-chip
-                                                  Peripheral Module ->
-                                                  External Addr Space */
-#define SH7750_CHCR_RS_SCITX_EA_TO_SC   0x800  /* SCI Transmit-Data-Empty intr
-                                                  transfer request (external
-                                                  address space -> SCTDR1) */
-#define SH7750_CHCR_RS_SCIRX_SC_TO_EA   0x900  /* SCI Receive-Data-Full intr
-                                                  transfer request (SCRDR1 ->
-                                                  External Addr Space) */
-#define SH7750_CHCR_RS_SCIFTX_EA_TO_SC  0xA00  /* SCIF Transmit-Data-Empty intr
-                                                  transfer request (external
-                                                  address space -> SCFTDR1) */
-#define SH7750_CHCR_RS_SCIFRX_SC_TO_EA  0xB00  /* SCIF Receive-Data-Full intr
-                                                  transfer request (SCFRDR2 ->
-                                                  External Addr Space) */
-#define SH7750_CHCR_RS_TMU2_EA_TO_EA    0xC00  /* TMU Channel 2 (input capture
-                                                  interrupt), (external address
-                                                  space -> external address
-                                                  space) */
-#define SH7750_CHCR_RS_TMU2_EA_TO_OCP   0xD00  /* TMU Channel 2 (input capture
-                                                  interrupt), (external address
-                                                  space -> on-chip peripheral
-                                                  module) */
-#define SH7750_CHCR_RS_TMU2_OCP_TO_EA   0xE00  /* TMU Channel 2 (input capture
-                                                  interrupt), (on-chip
-                                                  peripheral module -> external
-                                                  address space) */
-
-#define SH7750_CHCR_TM        0x00000080       /* Transmit mode: */
-#define SH7750_CHCR_TM_CSTEAL 0x00000000       /*     Cycle Steal Mode */
-#define SH7750_CHCR_TM_BURST  0x00000080       /*     Burst Mode */
-
-#define SH7750_CHCR_TS        0x00000070       /* Transmit Size: */
-#define SH7750_CHCR_TS_QUAD   0x00000000       /*     Quadword Size (64 bits) */
-#define SH7750_CHCR_TS_BYTE   0x00000010       /*     Byte Size (8 bit) */
-#define SH7750_CHCR_TS_WORD   0x00000020       /*     Word Size (16 bit) */
-#define SH7750_CHCR_TS_LONG   0x00000030       /*     Longword Size (32 bit) */
-#define SH7750_CHCR_TS_BLOCK  0x00000040       /*     32-byte block transfer */
-
-#define SH7750_CHCR_IE        0x00000004       /* Interrupt Enable */
-#define SH7750_CHCR_TE        0x00000002       /* Transfer End */
-#define SH7750_CHCR_DE        0x00000001       /* DMAC Enable */
-
-/* DMA Operation Register - DMAOR */
-#define SH7750_DMAOR_REGOFS   0xA00040 /* offset */
-#define SH7750_DMAOR          SH7750_P4_REG32(SH7750_DMAOR_REGOFS)
-#define SH7750_DMAOR_A7       SH7750_A7_REG32(SH7750_DMAOR_REGOFS)
-
-#define SH7750_DMAOR_DDT      0x00008000       /* On-Demand Data Transfer Mode */
-
-#define SH7750_DMAOR_PR       0x00000300       /* Priority Mode: */
-#define SH7750_DMAOR_PR_0123  0x00000000       /*     CH0 > CH1 > CH2 > CH3 */
-#define SH7750_DMAOR_PR_0231  0x00000100       /*     CH0 > CH2 > CH3 > CH1 */
-#define SH7750_DMAOR_PR_2013  0x00000200       /*     CH2 > CH0 > CH1 > CH3 */
-#define SH7750_DMAOR_PR_RR    0x00000300       /*     Round-robin mode */
-
-#define SH7750_DMAOR_COD      0x00000010       /* Check Overrun for DREQ\ */
-#define SH7750_DMAOR_AE       0x00000004       /* Address Error flag */
-#define SH7750_DMAOR_NMIF     0x00000002       /* NMI Flag */
-#define SH7750_DMAOR_DME      0x00000001       /* DMAC Master Enable */
-
-/*
- * I/O Ports
- */
-/* Port Control Register A - PCTRA */
-#define SH7750_PCTRA_REGOFS   0x80002C /* offset */
-#define SH7750_PCTRA          SH7750_P4_REG32(SH7750_PCTRA_REGOFS)
-#define SH7750_PCTRA_A7       SH7750_A7_REG32(SH7750_PCTRA_REGOFS)
-
-#define SH7750_PCTRA_PBPUP(n) 0        /* Bit n is pulled up */
-#define SH7750_PCTRA_PBNPUP(n) (1 << ((n)*2+1))        /* Bit n is not pulled up */
-#define SH7750_PCTRA_PBINP(n) 0        /* Bit n is an input */
-#define SH7750_PCTRA_PBOUT(n) (1 << ((n)*2))   /* Bit n is an output */
-
-/* Port Data Register A - PDTRA(half) */
-#define SH7750_PDTRA_REGOFS   0x800030 /* offset */
-#define SH7750_PDTRA          SH7750_P4_REG32(SH7750_PDTRA_REGOFS)
-#define SH7750_PDTRA_A7       SH7750_A7_REG32(SH7750_PDTRA_REGOFS)
-
-#define SH7750_PDTRA_BIT(n) (1 << (n))
-
-/* Port Control Register B - PCTRB */
-#define SH7750_PCTRB_REGOFS   0x800040 /* offset */
-#define SH7750_PCTRB          SH7750_P4_REG32(SH7750_PCTRB_REGOFS)
-#define SH7750_PCTRB_A7       SH7750_A7_REG32(SH7750_PCTRB_REGOFS)
-
-#define SH7750_PCTRB_PBPUP(n) 0        /* Bit n is pulled up */
-#define SH7750_PCTRB_PBNPUP(n) (1 << ((n-16)*2+1))     /* Bit n is not pulled up */
-#define SH7750_PCTRB_PBINP(n) 0        /* Bit n is an input */
-#define SH7750_PCTRB_PBOUT(n) (1 << ((n-16)*2))        /* Bit n is an output */
-
-/* Port Data Register B - PDTRB(half) */
-#define SH7750_PDTRB_REGOFS   0x800044 /* offset */
-#define SH7750_PDTRB          SH7750_P4_REG32(SH7750_PDTRB_REGOFS)
-#define SH7750_PDTRB_A7       SH7750_A7_REG32(SH7750_PDTRB_REGOFS)
-
-#define SH7750_PDTRB_BIT(n) (1 << ((n)-16))
-
-/* GPIO Interrupt Control Register - GPIOIC(half) */
-#define SH7750_GPIOIC_REGOFS  0x800048 /* offset */
-#define SH7750_GPIOIC         SH7750_P4_REG32(SH7750_GPIOIC_REGOFS)
-#define SH7750_GPIOIC_A7      SH7750_A7_REG32(SH7750_GPIOIC_REGOFS)
-
-#define SH7750_GPIOIC_PTIREN(n) (1 << (n))     /* Port n is used as a GPIO int */
-
-/*
- * Interrupt Controller - INTC
- */
-/* Interrupt Control Register - ICR (half) */
-#define SH7750_ICR_REGOFS     0xD00000 /* offset */
-#define SH7750_ICR            SH7750_P4_REG32(SH7750_ICR_REGOFS)
-#define SH7750_ICR_A7         SH7750_A7_REG32(SH7750_ICR_REGOFS)
-
-#define SH7750_ICR_NMIL       0x8000   /* NMI Input Level */
-#define SH7750_ICR_MAI        0x4000   /* NMI Interrupt Mask */
-
-#define SH7750_ICR_NMIB       0x0200   /* NMI Block Mode: */
-#define SH7750_ICR_NMIB_BLK   0x0000   /*   NMI requests held pending while
-                                          SR.BL bit is set to 1 */
-#define SH7750_ICR_NMIB_NBLK  0x0200   /*   NMI requests detected when SR.BL bit
-                                          set to 1 */
-
-#define SH7750_ICR_NMIE       0x0100   /* NMI Edge Select: */
-#define SH7750_ICR_NMIE_FALL  0x0000   /*   Interrupt request detected on falling
-                                          edge of NMI input */
-#define SH7750_ICR_NMIE_RISE  0x0100   /*   Interrupt request detected on rising
-                                          edge of NMI input */
-
-#define SH7750_ICR_IRLM       0x0080   /* IRL Pin Mode: */
-#define SH7750_ICR_IRLM_ENC   0x0000   /*   IRL\ pins used as a level-encoded
-                                          interrupt requests */
-#define SH7750_ICR_IRLM_RAW   0x0080   /*   IRL\ pins used as a four independent
-                                          interrupt requests */
-
-/*
- * User Break Controller registers
- */
-#define SH7750_BARA           0x200000 /* Break address regiser A */
-#define SH7750_BAMRA          0x200004 /* Break address mask regiser A */
-#define SH7750_BBRA           0x200008 /* Break bus cycle regiser A */
-#define SH7750_BARB           0x20000c /* Break address regiser B */
-#define SH7750_BAMRB          0x200010 /* Break address mask regiser B */
-#define SH7750_BBRB           0x200014 /* Break bus cycle regiser B */
-#define SH7750_BASRB          0x000018 /* Break ASID regiser B */
-#define SH7750_BDRB           0x200018 /* Break data regiser B */
-#define SH7750_BDMRB          0x20001c /* Break data mask regiser B */
-#define SH7750_BRCR           0x200020 /* Break control register */
-
-#define SH7750_BRCR_UDBE        0x0001 /* User break debug enable bit */
-
-/*
- * Missing in RTEMS, added for QEMU
- */
-#define SH7750_BCR3_A7       0x1f800050
-#define SH7750_BCR4_A7       0x1e0a00f0
-
-#endif
diff --git a/hw/sh_intc.c b/hw/sh_intc.c
deleted file mode 100644 (file)
index 29e3d8f..0000000
+++ /dev/null
@@ -1,513 +0,0 @@
-/*
- * SuperH interrupt controller module
- *
- * Copyright (c) 2007 Magnus Damm
- * Based on sh_timer.c and arm_timer.c by Paul Brook
- * Copyright (c) 2005-2006 CodeSourcery.
- *
- * This code is licensed under the GPL.
- */
-
-#include "hw/sh_intc.h"
-#include "hw/hw.h"
-#include "hw/sh.h"
-
-//#define DEBUG_INTC
-//#define DEBUG_INTC_SOURCES
-
-#define INTC_A7(x) ((x) & 0x1fffffff)
-
-void sh_intc_toggle_source(struct intc_source *source,
-                          int enable_adj, int assert_adj)
-{
-    int enable_changed = 0;
-    int pending_changed = 0;
-    int old_pending;
-
-    if ((source->enable_count == source->enable_max) && (enable_adj == -1))
-        enable_changed = -1;
-
-    source->enable_count += enable_adj;
-
-    if (source->enable_count == source->enable_max)
-        enable_changed = 1;
-
-    source->asserted += assert_adj;
-
-    old_pending = source->pending;
-    source->pending = source->asserted &&
-      (source->enable_count == source->enable_max);
-
-    if (old_pending != source->pending)
-        pending_changed = 1;
-
-    if (pending_changed) {
-        CPUState *cpu = CPU(sh_env_get_cpu(first_cpu));
-        if (source->pending) {
-            source->parent->pending++;
-            if (source->parent->pending == 1) {
-                cpu_interrupt(cpu, CPU_INTERRUPT_HARD);
-            }
-        } else {
-            source->parent->pending--;
-            if (source->parent->pending == 0) {
-                cpu_reset_interrupt(cpu, CPU_INTERRUPT_HARD);
-            }
-       }
-    }
-
-  if (enable_changed || assert_adj || pending_changed) {
-#ifdef DEBUG_INTC_SOURCES
-            printf("sh_intc: (%d/%d/%d/%d) interrupt source 0x%x %s%s%s\n",
-                  source->parent->pending,
-                  source->asserted,
-                  source->enable_count,
-                  source->enable_max,
-                  source->vect,
-                  source->asserted ? "asserted " :
-                  assert_adj ? "deasserted" : "",
-                  enable_changed == 1 ? "enabled " :
-                  enable_changed == -1 ? "disabled " : "",
-                  source->pending ? "pending" : "");
-#endif
-  }
-}
-
-static void sh_intc_set_irq (void *opaque, int n, int level)
-{
-  struct intc_desc *desc = opaque;
-  struct intc_source *source = &(desc->sources[n]);
-
-  if (level && !source->asserted)
-    sh_intc_toggle_source(source, 0, 1);
-  else if (!level && source->asserted)
-    sh_intc_toggle_source(source, 0, -1);
-}
-
-int sh_intc_get_pending_vector(struct intc_desc *desc, int imask)
-{
-    unsigned int i;
-
-    /* slow: use a linked lists of pending sources instead */
-    /* wrong: take interrupt priority into account (one list per priority) */
-
-    if (imask == 0x0f) {
-        return -1; /* FIXME, update code to include priority per source */
-    }
-
-    for (i = 0; i < desc->nr_sources; i++) {
-        struct intc_source *source = desc->sources + i;
-
-       if (source->pending) {
-#ifdef DEBUG_INTC_SOURCES
-            printf("sh_intc: (%d) returning interrupt source 0x%x\n",
-                  desc->pending, source->vect);
-#endif
-            return source->vect;
-       }
-    }
-
-    abort();
-}
-
-#define INTC_MODE_NONE       0
-#define INTC_MODE_DUAL_SET   1
-#define INTC_MODE_DUAL_CLR   2
-#define INTC_MODE_ENABLE_REG 3
-#define INTC_MODE_MASK_REG   4
-#define INTC_MODE_IS_PRIO    8
-
-static unsigned int sh_intc_mode(unsigned long address,
-                                unsigned long set_reg, unsigned long clr_reg)
-{
-    if ((address != INTC_A7(set_reg)) &&
-       (address != INTC_A7(clr_reg)))
-        return INTC_MODE_NONE;
-
-    if (set_reg && clr_reg) {
-        if (address == INTC_A7(set_reg))
-            return INTC_MODE_DUAL_SET;
-       else
-            return INTC_MODE_DUAL_CLR;
-    }
-
-    if (set_reg)
-        return INTC_MODE_ENABLE_REG;
-    else
-        return INTC_MODE_MASK_REG;
-}
-
-static void sh_intc_locate(struct intc_desc *desc,
-                          unsigned long address,
-                          unsigned long **datap,
-                          intc_enum **enums,
-                          unsigned int *first,
-                          unsigned int *width,
-                          unsigned int *modep)
-{
-    unsigned int i, mode;
-
-    /* this is slow but works for now */
-
-    if (desc->mask_regs) {
-        for (i = 0; i < desc->nr_mask_regs; i++) {
-           struct intc_mask_reg *mr = desc->mask_regs + i;
-
-           mode = sh_intc_mode(address, mr->set_reg, mr->clr_reg);
-           if (mode == INTC_MODE_NONE)
-                continue;
-
-           *modep = mode;
-           *datap = &mr->value;
-           *enums = mr->enum_ids;
-           *first = mr->reg_width - 1;
-           *width = 1;
-           return;
-       }
-    }
-
-    if (desc->prio_regs) {
-        for (i = 0; i < desc->nr_prio_regs; i++) {
-           struct intc_prio_reg *pr = desc->prio_regs + i;
-
-           mode = sh_intc_mode(address, pr->set_reg, pr->clr_reg);
-           if (mode == INTC_MODE_NONE)
-                continue;
-
-           *modep = mode | INTC_MODE_IS_PRIO;
-           *datap = &pr->value;
-           *enums = pr->enum_ids;
-           *first = (pr->reg_width / pr->field_width) - 1;
-           *width = pr->field_width;
-           return;
-       }
-    }
-
-    abort();
-}
-
-static void sh_intc_toggle_mask(struct intc_desc *desc, intc_enum id,
-                               int enable, int is_group)
-{
-    struct intc_source *source = desc->sources + id;
-
-    if (!id)
-       return;
-
-    if (!source->next_enum_id && (!source->enable_max || !source->vect)) {
-#ifdef DEBUG_INTC_SOURCES
-        printf("sh_intc: reserved interrupt source %d modified\n", id);
-#endif
-       return;
-    }
-
-    if (source->vect)
-        sh_intc_toggle_source(source, enable ? 1 : -1, 0);
-
-#ifdef DEBUG_INTC
-    else {
-        printf("setting interrupt group %d to %d\n", id, !!enable);
-    }
-#endif
-
-    if ((is_group || !source->vect) && source->next_enum_id) {
-        sh_intc_toggle_mask(desc, source->next_enum_id, enable, 1);
-    }
-
-#ifdef DEBUG_INTC
-    if (!source->vect) {
-        printf("setting interrupt group %d to %d - done\n", id, !!enable);
-    }
-#endif
-}
-
-static uint64_t sh_intc_read(void *opaque, hwaddr offset,
-                             unsigned size)
-{
-    struct intc_desc *desc = opaque;
-    intc_enum *enum_ids = NULL;
-    unsigned int first = 0;
-    unsigned int width = 0;
-    unsigned int mode = 0;
-    unsigned long *valuep;
-
-#ifdef DEBUG_INTC
-    printf("sh_intc_read 0x%lx\n", (unsigned long) offset);
-#endif
-
-    sh_intc_locate(desc, (unsigned long)offset, &valuep, 
-                  &enum_ids, &first, &width, &mode);
-    return *valuep;
-}
-
-static void sh_intc_write(void *opaque, hwaddr offset,
-                          uint64_t value, unsigned size)
-{
-    struct intc_desc *desc = opaque;
-    intc_enum *enum_ids = NULL;
-    unsigned int first = 0;
-    unsigned int width = 0;
-    unsigned int mode = 0;
-    unsigned int k;
-    unsigned long *valuep;
-    unsigned long mask;
-
-#ifdef DEBUG_INTC
-    printf("sh_intc_write 0x%lx 0x%08x\n", (unsigned long) offset, value);
-#endif
-
-    sh_intc_locate(desc, (unsigned long)offset, &valuep, 
-                  &enum_ids, &first, &width, &mode);
-
-    switch (mode) {
-    case INTC_MODE_ENABLE_REG | INTC_MODE_IS_PRIO: break;
-    case INTC_MODE_DUAL_SET: value |= *valuep; break;
-    case INTC_MODE_DUAL_CLR: value = *valuep & ~value; break;
-    default: abort();
-    }
-
-    for (k = 0; k <= first; k++) {
-        mask = ((1 << width) - 1) << ((first - k) * width);
-
-       if ((*valuep & mask) == (value & mask))
-            continue;
-#if 0
-       printf("k = %d, first = %d, enum = %d, mask = 0x%08x\n", 
-              k, first, enum_ids[k], (unsigned int)mask);
-#endif
-        sh_intc_toggle_mask(desc, enum_ids[k], value & mask, 0);
-    }
-
-    *valuep = value;
-
-#ifdef DEBUG_INTC
-    printf("sh_intc_write 0x%lx -> 0x%08x\n", (unsigned long) offset, value);
-#endif
-}
-
-static const MemoryRegionOps sh_intc_ops = {
-    .read = sh_intc_read,
-    .write = sh_intc_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-struct intc_source *sh_intc_source(struct intc_desc *desc, intc_enum id)
-{
-    if (id)
-        return desc->sources + id;
-
-    return NULL;
-}
-
-static unsigned int sh_intc_register(MemoryRegion *sysmem,
-                             struct intc_desc *desc,
-                             const unsigned long address,
-                             const char *type,
-                             const char *action,
-                             const unsigned int index)
-{
-    char name[60];
-    MemoryRegion *iomem, *iomem_p4, *iomem_a7;
-
-    if (!address) {
-        return 0;
-    }
-
-    iomem = &desc->iomem;
-    iomem_p4 = desc->iomem_aliases + index;
-    iomem_a7 = iomem_p4 + 1;
-
-#define SH_INTC_IOMEM_FORMAT "interrupt-controller-%s-%s-%s"
-    snprintf(name, sizeof(name), SH_INTC_IOMEM_FORMAT, type, action, "p4");
-    memory_region_init_alias(iomem_p4, name, iomem, INTC_A7(address), 4);
-    memory_region_add_subregion(sysmem, P4ADDR(address), iomem_p4);
-
-    snprintf(name, sizeof(name), SH_INTC_IOMEM_FORMAT, type, action, "a7");
-    memory_region_init_alias(iomem_a7, name, iomem, INTC_A7(address), 4);
-    memory_region_add_subregion(sysmem, A7ADDR(address), iomem_a7);
-#undef SH_INTC_IOMEM_FORMAT
-
-    /* used to increment aliases index */
-    return 2;
-}
-
-static void sh_intc_register_source(struct intc_desc *desc,
-                                   intc_enum source,
-                                   struct intc_group *groups,
-                                   int nr_groups)
-{
-    unsigned int i, k;
-    struct intc_source *s;
-
-    if (desc->mask_regs) {
-        for (i = 0; i < desc->nr_mask_regs; i++) {
-           struct intc_mask_reg *mr = desc->mask_regs + i;
-
-           for (k = 0; k < ARRAY_SIZE(mr->enum_ids); k++) {
-                if (mr->enum_ids[k] != source)
-                    continue;
-
-               s = sh_intc_source(desc, mr->enum_ids[k]);
-               if (s)
-                    s->enable_max++;
-           }
-       }
-    }
-
-    if (desc->prio_regs) {
-        for (i = 0; i < desc->nr_prio_regs; i++) {
-           struct intc_prio_reg *pr = desc->prio_regs + i;
-
-           for (k = 0; k < ARRAY_SIZE(pr->enum_ids); k++) {
-                if (pr->enum_ids[k] != source)
-                    continue;
-
-               s = sh_intc_source(desc, pr->enum_ids[k]);
-               if (s)
-                    s->enable_max++;
-           }
-       }
-    }
-
-    if (groups) {
-        for (i = 0; i < nr_groups; i++) {
-           struct intc_group *gr = groups + i;
-
-           for (k = 0; k < ARRAY_SIZE(gr->enum_ids); k++) {
-                if (gr->enum_ids[k] != source)
-                    continue;
-
-               s = sh_intc_source(desc, gr->enum_ids[k]);
-               if (s)
-                    s->enable_max++;
-           }
-       }
-    }
-
-}
-
-void sh_intc_register_sources(struct intc_desc *desc,
-                             struct intc_vect *vectors,
-                             int nr_vectors,
-                             struct intc_group *groups,
-                             int nr_groups)
-{
-    unsigned int i, k;
-    struct intc_source *s;
-
-    for (i = 0; i < nr_vectors; i++) {
-       struct intc_vect *vect = vectors + i;
-
-       sh_intc_register_source(desc, vect->enum_id, groups, nr_groups);
-       s = sh_intc_source(desc, vect->enum_id);
-        if (s) {
-            s->vect = vect->vect;
-
-#ifdef DEBUG_INTC_SOURCES
-            printf("sh_intc: registered source %d -> 0x%04x (%d/%d)\n",
-                   vect->enum_id, s->vect, s->enable_count, s->enable_max);
-#endif
-        }
-    }
-
-    if (groups) {
-        for (i = 0; i < nr_groups; i++) {
-           struct intc_group *gr = groups + i;
-
-           s = sh_intc_source(desc, gr->enum_id);
-           s->next_enum_id = gr->enum_ids[0];
-
-           for (k = 1; k < ARRAY_SIZE(gr->enum_ids); k++) {
-                if (!gr->enum_ids[k])
-                    continue;
-
-               s = sh_intc_source(desc, gr->enum_ids[k - 1]);
-               s->next_enum_id = gr->enum_ids[k];
-           }
-
-#ifdef DEBUG_INTC_SOURCES
-           printf("sh_intc: registered group %d (%d/%d)\n",
-                  gr->enum_id, s->enable_count, s->enable_max);
-#endif
-       }
-    }
-}
-
-int sh_intc_init(MemoryRegion *sysmem,
-         struct intc_desc *desc,
-                int nr_sources,
-                struct intc_mask_reg *mask_regs,
-                int nr_mask_regs,
-                struct intc_prio_reg *prio_regs,
-                int nr_prio_regs)
-{
-    unsigned int i, j;
-
-    desc->pending = 0;
-    desc->nr_sources = nr_sources;
-    desc->mask_regs = mask_regs;
-    desc->nr_mask_regs = nr_mask_regs;
-    desc->prio_regs = prio_regs;
-    desc->nr_prio_regs = nr_prio_regs;
-    /* Allocate 4 MemoryRegions per register (2 actions * 2 aliases).
-     **/
-    desc->iomem_aliases = g_new0(MemoryRegion,
-                                 (nr_mask_regs + nr_prio_regs) * 4);
-
-    j = 0;
-    i = sizeof(struct intc_source) * nr_sources;
-    desc->sources = g_malloc0(i);
-
-    for (i = 0; i < desc->nr_sources; i++) {
-        struct intc_source *source = desc->sources + i;
-
-        source->parent = desc;
-    }
-
-    desc->irqs = qemu_allocate_irqs(sh_intc_set_irq, desc, nr_sources);
-    memory_region_init_io(&desc->iomem, &sh_intc_ops, desc,
-                          "interrupt-controller", 0x100000000ULL);
-
-#define INT_REG_PARAMS(reg_struct, type, action, j) \
-        reg_struct->action##_reg, #type, #action, j
-    if (desc->mask_regs) {
-        for (i = 0; i < desc->nr_mask_regs; i++) {
-           struct intc_mask_reg *mr = desc->mask_regs + i;
-
-            j += sh_intc_register(sysmem, desc,
-                                  INT_REG_PARAMS(mr, mask, set, j));
-            j += sh_intc_register(sysmem, desc,
-                                  INT_REG_PARAMS(mr, mask, clr, j));
-       }
-    }
-
-    if (desc->prio_regs) {
-        for (i = 0; i < desc->nr_prio_regs; i++) {
-           struct intc_prio_reg *pr = desc->prio_regs + i;
-
-            j += sh_intc_register(sysmem, desc,
-                                  INT_REG_PARAMS(pr, prio, set, j));
-            j += sh_intc_register(sysmem, desc,
-                                  INT_REG_PARAMS(pr, prio, clr, j));
-       }
-    }
-#undef INT_REG_PARAMS
-
-    return 0;
-}
-
-/* Assert level <n> IRL interrupt. 
-   0:deassert. 1:lowest priority,... 15:highest priority. */
-void sh_intc_set_irl(void *opaque, int n, int level)
-{
-    struct intc_source *s = opaque;
-    int i, irl = level ^ 15;
-    for (i = 0; (s = sh_intc_source(s->parent, s->next_enum_id)); i++) {
-       if (i == irl)
-           sh_intc_toggle_source(s, s->enable_count?0:1, s->asserted?0:1);
-       else
-           if (s->asserted)
-               sh_intc_toggle_source(s, 0, -1);
-    }
-}
diff --git a/hw/sh_intc.h b/hw/sh_intc.h
deleted file mode 100644 (file)
index b7ddcb0..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-#ifndef __SH_INTC_H__
-#define __SH_INTC_H__
-
-#include "qemu-common.h"
-#include "hw/irq.h"
-#include "exec/address-spaces.h"
-
-typedef unsigned char intc_enum;
-
-struct intc_vect {
-    intc_enum enum_id;
-    unsigned short vect;
-};
-
-#define INTC_VECT(enum_id, vect) { enum_id, vect }
-
-struct intc_group {
-    intc_enum enum_id;
-    intc_enum enum_ids[32];
-};
-
-#define INTC_GROUP(enum_id, ...) { enum_id, {  __VA_ARGS__ } }
-
-struct intc_mask_reg {
-    unsigned long set_reg, clr_reg, reg_width;
-    intc_enum enum_ids[32];
-    unsigned long value;
-};
-
-struct intc_prio_reg {
-    unsigned long set_reg, clr_reg, reg_width, field_width;
-    intc_enum enum_ids[16];
-    unsigned long value;
-};
-
-#define _INTC_ARRAY(a) a, ARRAY_SIZE(a)
-
-struct intc_source {
-    unsigned short vect;
-    intc_enum next_enum_id;
-
-    int asserted; /* emulates the interrupt signal line from device to intc */
-    int enable_count;
-    int enable_max;
-    int pending; /* emulates the result of signal and masking */
-    struct intc_desc *parent;
-};
-
-struct intc_desc {
-    MemoryRegion iomem;
-    MemoryRegion *iomem_aliases;
-    qemu_irq *irqs;
-    struct intc_source *sources;
-    int nr_sources;
-    struct intc_mask_reg *mask_regs;
-    int nr_mask_regs;
-    struct intc_prio_reg *prio_regs;
-    int nr_prio_regs;
-    int pending; /* number of interrupt sources that has pending set */
-};
-
-int sh_intc_get_pending_vector(struct intc_desc *desc, int imask);
-struct intc_source *sh_intc_source(struct intc_desc *desc, intc_enum id);
-void sh_intc_toggle_source(struct intc_source *source,
-                          int enable_adj, int assert_adj);
-
-void sh_intc_register_sources(struct intc_desc *desc,
-                             struct intc_vect *vectors,
-                             int nr_vectors,
-                             struct intc_group *groups,
-                             int nr_groups);
-
-int sh_intc_init(MemoryRegion *sysmem,
-                 struct intc_desc *desc,
-                int nr_sources,
-                struct intc_mask_reg *mask_regs,
-                int nr_mask_regs,
-                struct intc_prio_reg *prio_regs,
-                int nr_prio_regs);
-
-void sh_intc_set_irl(void *opaque, int n, int level);
-
-#endif /* __SH_INTC_H__ */
diff --git a/hw/sh_pci.c b/hw/sh_pci.c
deleted file mode 100644 (file)
index e3e7550..0000000
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * SuperH on-chip PCIC emulation.
- *
- * Copyright (c) 2008 Takashi YOSHII
- *
- * 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 "hw/sysbus.h"
-#include "hw/sh.h"
-#include "hw/pci/pci.h"
-#include "hw/pci/pci_host.h"
-#include "qemu/bswap.h"
-#include "exec/address-spaces.h"
-
-typedef struct SHPCIState {
-    SysBusDevice busdev;
-    PCIBus *bus;
-    PCIDevice *dev;
-    qemu_irq irq[4];
-    MemoryRegion memconfig_p4;
-    MemoryRegion memconfig_a7;
-    MemoryRegion isa;
-    uint32_t par;
-    uint32_t mbr;
-    uint32_t iobr;
-} SHPCIState;
-
-static void sh_pci_reg_write (void *p, hwaddr addr, uint64_t val,
-                              unsigned size)
-{
-    SHPCIState *pcic = p;
-    switch(addr) {
-    case 0 ... 0xfc:
-        cpu_to_le32w((uint32_t*)(pcic->dev->config + addr), val);
-        break;
-    case 0x1c0:
-        pcic->par = val;
-        break;
-    case 0x1c4:
-        pcic->mbr = val & 0xff000001;
-        break;
-    case 0x1c8:
-        if ((val & 0xfffc0000) != (pcic->iobr & 0xfffc0000)) {
-            memory_region_del_subregion(get_system_memory(), &pcic->isa);
-            pcic->iobr = val & 0xfffc0001;
-            memory_region_add_subregion(get_system_memory(),
-                                        pcic->iobr & 0xfffc0000, &pcic->isa);
-        }
-        break;
-    case 0x220:
-        pci_data_write(pcic->bus, pcic->par, val, 4);
-        break;
-    }
-}
-
-static uint64_t sh_pci_reg_read (void *p, hwaddr addr,
-                                 unsigned size)
-{
-    SHPCIState *pcic = p;
-    switch(addr) {
-    case 0 ... 0xfc:
-        return le32_to_cpup((uint32_t*)(pcic->dev->config + addr));
-    case 0x1c0:
-        return pcic->par;
-    case 0x1c4:
-        return pcic->mbr;
-    case 0x1c8:
-        return pcic->iobr;
-    case 0x220:
-        return pci_data_read(pcic->bus, pcic->par, 4);
-    }
-    return 0;
-}
-
-static const MemoryRegionOps sh_pci_reg_ops = {
-    .read = sh_pci_reg_read,
-    .write = sh_pci_reg_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-};
-
-static int sh_pci_map_irq(PCIDevice *d, int irq_num)
-{
-    return (d->devfn >> 3);
-}
-
-static void sh_pci_set_irq(void *opaque, int irq_num, int level)
-{
-    qemu_irq *pic = opaque;
-
-    qemu_set_irq(pic[irq_num], level);
-}
-
-static int sh_pci_device_init(SysBusDevice *dev)
-{
-    SHPCIState *s;
-    int i;
-
-    s = FROM_SYSBUS(SHPCIState, dev);
-    for (i = 0; i < 4; i++) {
-        sysbus_init_irq(dev, &s->irq[i]);
-    }
-    s->bus = pci_register_bus(&s->busdev.qdev, "pci",
-                              sh_pci_set_irq, sh_pci_map_irq,
-                              s->irq,
-                              get_system_memory(),
-                              get_system_io(),
-                              PCI_DEVFN(0, 0), 4, TYPE_PCI_BUS);
-    memory_region_init_io(&s->memconfig_p4, &sh_pci_reg_ops, s,
-                          "sh_pci", 0x224);
-    memory_region_init_alias(&s->memconfig_a7, "sh_pci.2", &s->memconfig_p4,
-                             0, 0x224);
-    isa_mmio_setup(&s->isa, 0x40000);
-    sysbus_init_mmio(dev, &s->memconfig_p4);
-    sysbus_init_mmio(dev, &s->memconfig_a7);
-    s->iobr = 0xfe240000;
-    memory_region_add_subregion(get_system_memory(), s->iobr, &s->isa);
-
-    s->dev = pci_create_simple(s->bus, PCI_DEVFN(0, 0), "sh_pci_host");
-    return 0;
-}
-
-static int sh_pci_host_init(PCIDevice *d)
-{
-    pci_set_word(d->config + PCI_COMMAND, PCI_COMMAND_WAIT);
-    pci_set_word(d->config + PCI_STATUS, PCI_STATUS_CAP_LIST |
-                 PCI_STATUS_FAST_BACK | PCI_STATUS_DEVSEL_MEDIUM);
-    return 0;
-}
-
-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 const TypeInfo sh_pci_host_info = {
-    .name          = "sh_pci_host",
-    .parent        = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(PCIDevice),
-    .class_init    = sh_pci_host_class_init,
-};
-
-static void sh_pci_device_class_init(ObjectClass *klass, void *data)
-{
-    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
-
-    sdc->init = sh_pci_device_init;
-}
-
-static const 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_types(void)
-{
-    type_register_static(&sh_pci_device_info);
-    type_register_static(&sh_pci_host_info);
-}
-
-type_init(sh_pci_register_types)
diff --git a/hw/sh_serial.c b/hw/sh_serial.c
deleted file mode 100644 (file)
index 4629695..0000000
+++ /dev/null
@@ -1,410 +0,0 @@
-/*
- * QEMU SCI/SCIF serial port emulation
- *
- * Copyright (c) 2007 Magnus Damm
- *
- * Based on serial.c - QEMU 16450 UART 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.
- */
-#include "hw/hw.h"
-#include "hw/sh.h"
-#include "char/char.h"
-#include "exec/address-spaces.h"
-
-//#define DEBUG_SERIAL
-
-#define SH_SERIAL_FLAG_TEND (1 << 0)
-#define SH_SERIAL_FLAG_TDE  (1 << 1)
-#define SH_SERIAL_FLAG_RDF  (1 << 2)
-#define SH_SERIAL_FLAG_BRK  (1 << 3)
-#define SH_SERIAL_FLAG_DR   (1 << 4)
-
-#define SH_RX_FIFO_LENGTH (16)
-
-typedef struct {
-    MemoryRegion iomem;
-    MemoryRegion iomem_p4;
-    MemoryRegion iomem_a7;
-    uint8_t smr;
-    uint8_t brr;
-    uint8_t scr;
-    uint8_t dr; /* ftdr / tdr */
-    uint8_t sr; /* fsr / ssr */
-    uint16_t fcr;
-    uint8_t sptr;
-
-    uint8_t rx_fifo[SH_RX_FIFO_LENGTH]; /* frdr / rdr */
-    uint8_t rx_cnt;
-    uint8_t rx_tail;
-    uint8_t rx_head;
-
-    int freq;
-    int feat;
-    int flags;
-    int rtrg;
-
-    CharDriverState *chr;
-
-    qemu_irq eri;
-    qemu_irq rxi;
-    qemu_irq txi;
-    qemu_irq tei;
-    qemu_irq bri;
-} sh_serial_state;
-
-static void sh_serial_clear_fifo(sh_serial_state * s)
-{
-    memset(s->rx_fifo, 0, SH_RX_FIFO_LENGTH);
-    s->rx_cnt = 0;
-    s->rx_head = 0;
-    s->rx_tail = 0;
-}
-
-static void sh_serial_write(void *opaque, hwaddr offs,
-                            uint64_t val, unsigned size)
-{
-    sh_serial_state *s = opaque;
-    unsigned char ch;
-
-#ifdef DEBUG_SERIAL
-    printf("sh_serial: write offs=0x%02x val=0x%02x\n",
-          offs, val);
-#endif
-    switch(offs) {
-    case 0x00: /* SMR */
-        s->smr = val & ((s->feat & SH_SERIAL_FEAT_SCIF) ? 0x7b : 0xff);
-        return;
-    case 0x04: /* BRR */
-        s->brr = val;
-       return;
-    case 0x08: /* SCR */
-        /* TODO : For SH7751, SCIF mask should be 0xfb. */
-        s->scr = val & ((s->feat & SH_SERIAL_FEAT_SCIF) ? 0xfa : 0xff);
-        if (!(val & (1 << 5)))
-            s->flags |= SH_SERIAL_FLAG_TEND;
-        if ((s->feat & SH_SERIAL_FEAT_SCIF) && s->txi) {
-           qemu_set_irq(s->txi, val & (1 << 7));
-        }
-        if (!(val & (1 << 6))) {
-           qemu_set_irq(s->rxi, 0);
-        }
-        return;
-    case 0x0c: /* FTDR / TDR */
-        if (s->chr) {
-            ch = val;
-            qemu_chr_fe_write(s->chr, &ch, 1);
-       }
-       s->dr = val;
-       s->flags &= ~SH_SERIAL_FLAG_TDE;
-        return;
-#if 0
-    case 0x14: /* FRDR / RDR */
-        ret = 0;
-        break;
-#endif
-    }
-    if (s->feat & SH_SERIAL_FEAT_SCIF) {
-        switch(offs) {
-        case 0x10: /* FSR */
-            if (!(val & (1 << 6)))
-                s->flags &= ~SH_SERIAL_FLAG_TEND;
-            if (!(val & (1 << 5)))
-                s->flags &= ~SH_SERIAL_FLAG_TDE;
-            if (!(val & (1 << 4)))
-                s->flags &= ~SH_SERIAL_FLAG_BRK;
-            if (!(val & (1 << 1)))
-                s->flags &= ~SH_SERIAL_FLAG_RDF;
-            if (!(val & (1 << 0)))
-                s->flags &= ~SH_SERIAL_FLAG_DR;
-
-            if (!(val & (1 << 1)) || !(val & (1 << 0))) {
-                if (s->rxi) {
-                    qemu_set_irq(s->rxi, 0);
-                }
-            }
-            return;
-        case 0x18: /* FCR */
-            s->fcr = val;
-            switch ((val >> 6) & 3) {
-            case 0:
-                s->rtrg = 1;
-                break;
-            case 1:
-                s->rtrg = 4;
-                break;
-            case 2:
-                s->rtrg = 8;
-                break;
-            case 3:
-                s->rtrg = 14;
-                break;
-            }
-            if (val & (1 << 1)) {
-                sh_serial_clear_fifo(s);
-                s->sr &= ~(1 << 1);
-            }
-
-            return;
-        case 0x20: /* SPTR */
-            s->sptr = val & 0xf3;
-            return;
-        case 0x24: /* LSR */
-            return;
-        }
-    }
-    else {
-        switch(offs) {
-#if 0
-        case 0x0c:
-            ret = s->dr;
-            break;
-        case 0x10:
-            ret = 0;
-            break;
-#endif
-        case 0x1c:
-            s->sptr = val & 0x8f;
-            return;
-        }
-    }
-
-    fprintf(stderr, "sh_serial: unsupported write to 0x%02"
-            HWADDR_PRIx "\n", offs);
-    abort();
-}
-
-static uint64_t sh_serial_read(void *opaque, hwaddr offs,
-                               unsigned size)
-{
-    sh_serial_state *s = opaque;
-    uint32_t ret = ~0;
-
-#if 0
-    switch(offs) {
-    case 0x00:
-        ret = s->smr;
-        break;
-    case 0x04:
-        ret = s->brr;
-       break;
-    case 0x08:
-        ret = s->scr;
-        break;
-    case 0x14:
-        ret = 0;
-        break;
-    }
-#endif
-    if (s->feat & SH_SERIAL_FEAT_SCIF) {
-        switch(offs) {
-        case 0x00: /* SMR */
-            ret = s->smr;
-            break;
-        case 0x08: /* SCR */
-            ret = s->scr;
-            break;
-        case 0x10: /* FSR */
-            ret = 0;
-            if (s->flags & SH_SERIAL_FLAG_TEND)
-                ret |= (1 << 6);
-            if (s->flags & SH_SERIAL_FLAG_TDE)
-                ret |= (1 << 5);
-            if (s->flags & SH_SERIAL_FLAG_BRK)
-                ret |= (1 << 4);
-            if (s->flags & SH_SERIAL_FLAG_RDF)
-                ret |= (1 << 1);
-            if (s->flags & SH_SERIAL_FLAG_DR)
-                ret |= (1 << 0);
-
-            if (s->scr & (1 << 5))
-                s->flags |= SH_SERIAL_FLAG_TDE | SH_SERIAL_FLAG_TEND;
-
-            break;
-        case 0x14:
-            if (s->rx_cnt > 0) {
-                ret = s->rx_fifo[s->rx_tail++];
-                s->rx_cnt--;
-                if (s->rx_tail == SH_RX_FIFO_LENGTH)
-                    s->rx_tail = 0;
-                if (s->rx_cnt < s->rtrg)
-                    s->flags &= ~SH_SERIAL_FLAG_RDF;
-            }
-            break;
-#if 0
-        case 0x18:
-            ret = s->fcr;
-            break;
-#endif
-        case 0x1c:
-            ret = s->rx_cnt;
-            break;
-        case 0x20:
-            ret = s->sptr;
-            break;
-        case 0x24:
-            ret = 0;
-            break;
-        }
-    }
-    else {
-        switch(offs) {
-#if 0
-        case 0x0c:
-            ret = s->dr;
-            break;
-        case 0x10:
-            ret = 0;
-            break;
-        case 0x14:
-            ret = s->rx_fifo[0];
-            break;
-#endif
-        case 0x1c:
-            ret = s->sptr;
-            break;
-        }
-    }
-#ifdef DEBUG_SERIAL
-    printf("sh_serial: read offs=0x%02x val=0x%x\n",
-          offs, ret);
-#endif
-
-    if (ret & ~((1 << 16) - 1)) {
-        fprintf(stderr, "sh_serial: unsupported read from 0x%02"
-                HWADDR_PRIx "\n", offs);
-        abort();
-    }
-
-    return ret;
-}
-
-static int sh_serial_can_receive(sh_serial_state *s)
-{
-    return s->scr & (1 << 4);
-}
-
-static void sh_serial_receive_break(sh_serial_state *s)
-{
-    if (s->feat & SH_SERIAL_FEAT_SCIF)
-        s->sr |= (1 << 4);
-}
-
-static int sh_serial_can_receive1(void *opaque)
-{
-    sh_serial_state *s = opaque;
-    return sh_serial_can_receive(s);
-}
-
-static void sh_serial_receive1(void *opaque, const uint8_t *buf, int size)
-{
-    sh_serial_state *s = opaque;
-
-    if (s->feat & SH_SERIAL_FEAT_SCIF) {
-        int i;
-        for (i = 0; i < size; i++) {
-            if (s->rx_cnt < SH_RX_FIFO_LENGTH) {
-                s->rx_fifo[s->rx_head++] = buf[i];
-                if (s->rx_head == SH_RX_FIFO_LENGTH) {
-                    s->rx_head = 0;
-                }
-                s->rx_cnt++;
-                if (s->rx_cnt >= s->rtrg) {
-                    s->flags |= SH_SERIAL_FLAG_RDF;
-                    if (s->scr & (1 << 6) && s->rxi) {
-                        qemu_set_irq(s->rxi, 1);
-                    }
-                }
-            }
-        }
-    } else {
-        s->rx_fifo[0] = buf[0];
-    }
-}
-
-static void sh_serial_event(void *opaque, int event)
-{
-    sh_serial_state *s = opaque;
-    if (event == CHR_EVENT_BREAK)
-        sh_serial_receive_break(s);
-}
-
-static const MemoryRegionOps sh_serial_ops = {
-    .read = sh_serial_read,
-    .write = sh_serial_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-void sh_serial_init(MemoryRegion *sysmem,
-                    hwaddr base, int feat,
-                    uint32_t freq, CharDriverState *chr,
-                    qemu_irq eri_source,
-                    qemu_irq rxi_source,
-                    qemu_irq txi_source,
-                    qemu_irq tei_source,
-                    qemu_irq bri_source)
-{
-    sh_serial_state *s;
-
-    s = g_malloc0(sizeof(sh_serial_state));
-
-    s->feat = feat;
-    s->flags = SH_SERIAL_FLAG_TEND | SH_SERIAL_FLAG_TDE;
-    s->rtrg = 1;
-
-    s->smr = 0;
-    s->brr = 0xff;
-    s->scr = 1 << 5; /* pretend that TX is enabled so early printk works */
-    s->sptr = 0;
-
-    if (feat & SH_SERIAL_FEAT_SCIF) {
-        s->fcr = 0;
-    }
-    else {
-        s->dr = 0xff;
-    }
-
-    sh_serial_clear_fifo(s);
-
-    memory_region_init_io(&s->iomem, &sh_serial_ops, s,
-                          "serial", 0x100000000ULL);
-
-    memory_region_init_alias(&s->iomem_p4, "serial-p4", &s->iomem,
-                             0, 0x28);
-    memory_region_add_subregion(sysmem, P4ADDR(base), &s->iomem_p4);
-
-    memory_region_init_alias(&s->iomem_a7, "serial-a7", &s->iomem,
-                             0, 0x28);
-    memory_region_add_subregion(sysmem, A7ADDR(base), &s->iomem_a7);
-
-    s->chr = chr;
-
-    if (chr) {
-        qemu_chr_fe_claim_no_fail(chr);
-        qemu_chr_add_handlers(chr, sh_serial_can_receive1, sh_serial_receive1,
-                             sh_serial_event, s);
-    }
-
-    s->eri = eri_source;
-    s->rxi = rxi_source;
-    s->txi = txi_source;
-    s->tei = tei_source;
-    s->bri = bri_source;
-}
diff --git a/hw/sh_timer.c b/hw/sh_timer.c
deleted file mode 100644 (file)
index b450323..0000000
+++ /dev/null
@@ -1,333 +0,0 @@
-/*
- * SuperH Timer modules.
- *
- * Copyright (c) 2007 Magnus Damm
- * Based on arm_timer.c by Paul Brook
- * Copyright (c) 2005-2006 CodeSourcery.
- *
- * This code is licensed under the GPL.
- */
-
-#include "hw/hw.h"
-#include "hw/sh.h"
-#include "qemu/timer.h"
-#include "exec/address-spaces.h"
-#include "hw/ptimer.h"
-
-//#define DEBUG_TIMER
-
-#define TIMER_TCR_TPSC          (7 << 0)
-#define TIMER_TCR_CKEG          (3 << 3)
-#define TIMER_TCR_UNIE          (1 << 5)
-#define TIMER_TCR_ICPE          (3 << 6)
-#define TIMER_TCR_UNF           (1 << 8)
-#define TIMER_TCR_ICPF          (1 << 9)
-#define TIMER_TCR_RESERVED      (0x3f << 10)
-
-#define TIMER_FEAT_CAPT   (1 << 0)
-#define TIMER_FEAT_EXTCLK (1 << 1)
-
-#define OFFSET_TCOR   0
-#define OFFSET_TCNT   1
-#define OFFSET_TCR    2
-#define OFFSET_TCPR   3
-
-typedef struct {
-    ptimer_state *timer;
-    uint32_t tcnt;
-    uint32_t tcor;
-    uint32_t tcr;
-    uint32_t tcpr;
-    int freq;
-    int int_level;
-    int old_level;
-    int feat;
-    int enabled;
-    qemu_irq irq;
-} sh_timer_state;
-
-/* Check all active timers, and schedule the next timer interrupt. */
-
-static void sh_timer_update(sh_timer_state *s)
-{
-    int new_level = s->int_level && (s->tcr & TIMER_TCR_UNIE);
-
-    if (new_level != s->old_level)
-      qemu_set_irq (s->irq, new_level);
-
-    s->old_level = s->int_level;
-    s->int_level = new_level;
-}
-
-static uint32_t sh_timer_read(void *opaque, hwaddr offset)
-{
-    sh_timer_state *s = (sh_timer_state *)opaque;
-
-    switch (offset >> 2) {
-    case OFFSET_TCOR:
-        return s->tcor;
-    case OFFSET_TCNT:
-        return ptimer_get_count(s->timer);
-    case OFFSET_TCR:
-        return s->tcr | (s->int_level ? TIMER_TCR_UNF : 0);
-    case OFFSET_TCPR:
-        if (s->feat & TIMER_FEAT_CAPT)
-            return s->tcpr;
-    default:
-        hw_error("sh_timer_read: Bad offset %x\n", (int)offset);
-        return 0;
-    }
-}
-
-static void sh_timer_write(void *opaque, hwaddr offset,
-                            uint32_t value)
-{
-    sh_timer_state *s = (sh_timer_state *)opaque;
-    int freq;
-
-    switch (offset >> 2) {
-    case OFFSET_TCOR:
-        s->tcor = value;
-        ptimer_set_limit(s->timer, s->tcor, 0);
-        break;
-    case OFFSET_TCNT:
-        s->tcnt = value;
-        ptimer_set_count(s->timer, s->tcnt);
-        break;
-    case OFFSET_TCR:
-        if (s->enabled) {
-            /* Pause the timer if it is running.  This may cause some
-               inaccuracy dure to rounding, but avoids a whole lot of other
-               messyness.  */
-            ptimer_stop(s->timer);
-        }
-        freq = s->freq;
-        /* ??? Need to recalculate expiry time after changing divisor.  */
-        switch (value & TIMER_TCR_TPSC) {
-        case 0: freq >>= 2; break;
-        case 1: freq >>= 4; break;
-        case 2: freq >>= 6; break;
-        case 3: freq >>= 8; break;
-        case 4: freq >>= 10; break;
-       case 6:
-       case 7: if (s->feat & TIMER_FEAT_EXTCLK) break;
-       default: hw_error("sh_timer_write: Reserved TPSC value\n"); break;
-        }
-        switch ((value & TIMER_TCR_CKEG) >> 3) {
-       case 0: break;
-        case 1:
-        case 2:
-        case 3: if (s->feat & TIMER_FEAT_EXTCLK) break;
-       default: hw_error("sh_timer_write: Reserved CKEG value\n"); break;
-        }
-        switch ((value & TIMER_TCR_ICPE) >> 6) {
-       case 0: break;
-        case 2:
-        case 3: if (s->feat & TIMER_FEAT_CAPT) break;
-       default: hw_error("sh_timer_write: Reserved ICPE value\n"); break;
-        }
-       if ((value & TIMER_TCR_UNF) == 0)
-            s->int_level = 0;
-
-       value &= ~TIMER_TCR_UNF;
-
-       if ((value & TIMER_TCR_ICPF) && (!(s->feat & TIMER_FEAT_CAPT)))
-            hw_error("sh_timer_write: Reserved ICPF value\n");
-
-       value &= ~TIMER_TCR_ICPF; /* capture not supported */
-
-       if (value & TIMER_TCR_RESERVED)
-            hw_error("sh_timer_write: Reserved TCR bits set\n");
-        s->tcr = value;
-        ptimer_set_limit(s->timer, s->tcor, 0);
-        ptimer_set_freq(s->timer, freq);
-        if (s->enabled) {
-            /* Restart the timer if still enabled.  */
-            ptimer_run(s->timer, 0);
-        }
-        break;
-    case OFFSET_TCPR:
-        if (s->feat & TIMER_FEAT_CAPT) {
-            s->tcpr = value;
-           break;
-       }
-    default:
-        hw_error("sh_timer_write: Bad offset %x\n", (int)offset);
-    }
-    sh_timer_update(s);
-}
-
-static void sh_timer_start_stop(void *opaque, int enable)
-{
-    sh_timer_state *s = (sh_timer_state *)opaque;
-
-#ifdef DEBUG_TIMER
-    printf("sh_timer_start_stop %d (%d)\n", enable, s->enabled);
-#endif
-
-    if (s->enabled && !enable) {
-        ptimer_stop(s->timer);
-    }
-    if (!s->enabled && enable) {
-        ptimer_run(s->timer, 0);
-    }
-    s->enabled = !!enable;
-
-#ifdef DEBUG_TIMER
-    printf("sh_timer_start_stop done %d\n", s->enabled);
-#endif
-}
-
-static void sh_timer_tick(void *opaque)
-{
-    sh_timer_state *s = (sh_timer_state *)opaque;
-    s->int_level = s->enabled;
-    sh_timer_update(s);
-}
-
-static void *sh_timer_init(uint32_t freq, int feat, qemu_irq irq)
-{
-    sh_timer_state *s;
-    QEMUBH *bh;
-
-    s = (sh_timer_state *)g_malloc0(sizeof(sh_timer_state));
-    s->freq = freq;
-    s->feat = feat;
-    s->tcor = 0xffffffff;
-    s->tcnt = 0xffffffff;
-    s->tcpr = 0xdeadbeef;
-    s->tcr = 0;
-    s->enabled = 0;
-    s->irq = irq;
-
-    bh = qemu_bh_new(sh_timer_tick, s);
-    s->timer = ptimer_init(bh);
-
-    sh_timer_write(s, OFFSET_TCOR >> 2, s->tcor);
-    sh_timer_write(s, OFFSET_TCNT >> 2, s->tcnt);
-    sh_timer_write(s, OFFSET_TCPR >> 2, s->tcpr);
-    sh_timer_write(s, OFFSET_TCR  >> 2, s->tcpr);
-    /* ??? Save/restore.  */
-    return s;
-}
-
-typedef struct {
-    MemoryRegion iomem;
-    MemoryRegion iomem_p4;
-    MemoryRegion iomem_a7;
-    void *timer[3];
-    int level[3];
-    uint32_t tocr;
-    uint32_t tstr;
-    int feat;
-} tmu012_state;
-
-static uint64_t tmu012_read(void *opaque, hwaddr offset,
-                            unsigned size)
-{
-    tmu012_state *s = (tmu012_state *)opaque;
-
-#ifdef DEBUG_TIMER
-    printf("tmu012_read 0x%lx\n", (unsigned long) offset);
-#endif
-
-    if (offset >= 0x20) {
-        if (!(s->feat & TMU012_FEAT_3CHAN))
-           hw_error("tmu012_write: Bad channel offset %x\n", (int)offset);
-        return sh_timer_read(s->timer[2], offset - 0x20);
-    }
-
-    if (offset >= 0x14)
-        return sh_timer_read(s->timer[1], offset - 0x14);
-
-    if (offset >= 0x08)
-        return sh_timer_read(s->timer[0], offset - 0x08);
-
-    if (offset == 4)
-        return s->tstr;
-
-    if ((s->feat & TMU012_FEAT_TOCR) && offset == 0)
-        return s->tocr;
-
-    hw_error("tmu012_write: Bad offset %x\n", (int)offset);
-    return 0;
-}
-
-static void tmu012_write(void *opaque, hwaddr offset,
-                        uint64_t value, unsigned size)
-{
-    tmu012_state *s = (tmu012_state *)opaque;
-
-#ifdef DEBUG_TIMER
-    printf("tmu012_write 0x%lx 0x%08x\n", (unsigned long) offset, value);
-#endif
-
-    if (offset >= 0x20) {
-        if (!(s->feat & TMU012_FEAT_3CHAN))
-           hw_error("tmu012_write: Bad channel offset %x\n", (int)offset);
-        sh_timer_write(s->timer[2], offset - 0x20, value);
-       return;
-    }
-
-    if (offset >= 0x14) {
-        sh_timer_write(s->timer[1], offset - 0x14, value);
-       return;
-    }
-
-    if (offset >= 0x08) {
-        sh_timer_write(s->timer[0], offset - 0x08, value);
-       return;
-    }
-
-    if (offset == 4) {
-        sh_timer_start_stop(s->timer[0], value & (1 << 0));
-        sh_timer_start_stop(s->timer[1], value & (1 << 1));
-        if (s->feat & TMU012_FEAT_3CHAN)
-            sh_timer_start_stop(s->timer[2], value & (1 << 2));
-       else
-            if (value & (1 << 2))
-                hw_error("tmu012_write: Bad channel\n");
-
-       s->tstr = value;
-       return;
-    }
-
-    if ((s->feat & TMU012_FEAT_TOCR) && offset == 0) {
-        s->tocr = value & (1 << 0);
-    }
-}
-
-static const MemoryRegionOps tmu012_ops = {
-    .read = tmu012_read,
-    .write = tmu012_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-void tmu012_init(MemoryRegion *sysmem, hwaddr base,
-                 int feat, uint32_t freq,
-                qemu_irq ch0_irq, qemu_irq ch1_irq,
-                qemu_irq ch2_irq0, qemu_irq ch2_irq1)
-{
-    tmu012_state *s;
-    int timer_feat = (feat & TMU012_FEAT_EXTCLK) ? TIMER_FEAT_EXTCLK : 0;
-
-    s = (tmu012_state *)g_malloc0(sizeof(tmu012_state));
-    s->feat = feat;
-    s->timer[0] = sh_timer_init(freq, timer_feat, ch0_irq);
-    s->timer[1] = sh_timer_init(freq, timer_feat, ch1_irq);
-    if (feat & TMU012_FEAT_3CHAN)
-        s->timer[2] = sh_timer_init(freq, timer_feat | TIMER_FEAT_CAPT,
-                                   ch2_irq0); /* ch2_irq1 not supported */
-
-    memory_region_init_io(&s->iomem, &tmu012_ops, s,
-                          "timer", 0x100000000ULL);
-
-    memory_region_init_alias(&s->iomem_p4, "timer-p4",
-                             &s->iomem, 0, 0x1000);
-    memory_region_add_subregion(sysmem, P4ADDR(base), &s->iomem_p4);
-
-    memory_region_init_alias(&s->iomem_a7, "timer-a7",
-                             &s->iomem, 0, 0x1000);
-    memory_region_add_subregion(sysmem, A7ADDR(base), &s->iomem_a7);
-    /* ??? Save/restore.  */
-}
diff --git a/hw/sharpsl.h b/hw/sharpsl.h
deleted file mode 100644 (file)
index 13981a6..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * Common declarations for the Zaurii.
- *
- * This file is licensed under the GNU GPL.
- */
-#ifndef QEMU_SHARPSL_H
-#define QEMU_SHARPSL_H
-
-#define zaurus_printf(format, ...)     \
-    fprintf(stderr, "%s: " format, __FUNCTION__, ##__VA_ARGS__)
-
-/* zaurus.c */
-
-#define SL_PXA_PARAM_BASE      0xa0000a00
-void sl_bootparam_write(hwaddr ptr);
-
-#endif
diff --git a/hw/slavio_intctl.c b/hw/slavio_intctl.c
deleted file mode 100644 (file)
index b60592b..0000000
+++ /dev/null
@@ -1,471 +0,0 @@
-/*
- * QEMU Sparc SLAVIO interrupt controller emulation
- *
- * Copyright (c) 2003-2005 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.
- */
-
-#include "hw/sun4m.h"
-#include "monitor/monitor.h"
-#include "hw/sysbus.h"
-#include "trace.h"
-
-//#define DEBUG_IRQ_COUNT
-
-/*
- * Registers of interrupt controller in sun4m.
- *
- * This is the interrupt controller part of chip STP2001 (Slave I/O), also
- * produced as NCR89C105. See
- * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
- *
- * There is a system master controller and one for each cpu.
- *
- */
-
-#define MAX_CPUS 16
-#define MAX_PILS 16
-
-struct SLAVIO_INTCTLState;
-
-typedef struct SLAVIO_CPUINTCTLState {
-    MemoryRegion iomem;
-    struct SLAVIO_INTCTLState *master;
-    uint32_t intreg_pending;
-    uint32_t cpu;
-    uint32_t irl_out;
-} SLAVIO_CPUINTCTLState;
-
-typedef struct SLAVIO_INTCTLState {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-#ifdef DEBUG_IRQ_COUNT
-    uint64_t irq_count[32];
-#endif
-    qemu_irq cpu_irqs[MAX_CPUS][MAX_PILS];
-    SLAVIO_CPUINTCTLState slaves[MAX_CPUS];
-    uint32_t intregm_pending;
-    uint32_t intregm_disabled;
-    uint32_t target_cpu;
-} SLAVIO_INTCTLState;
-
-#define INTCTL_MAXADDR 0xf
-#define INTCTL_SIZE (INTCTL_MAXADDR + 1)
-#define INTCTLM_SIZE 0x14
-#define MASTER_IRQ_MASK ~0x0fa2007f
-#define MASTER_DISABLE 0x80000000
-#define CPU_SOFTIRQ_MASK 0xfffe0000
-#define CPU_IRQ_INT15_IN (1 << 15)
-#define CPU_IRQ_TIMER_IN (1 << 14)
-
-static void slavio_check_interrupts(SLAVIO_INTCTLState *s, int set_irqs);
-
-// per-cpu interrupt controller
-static uint64_t slavio_intctl_mem_readl(void *opaque, hwaddr addr,
-                                        unsigned size)
-{
-    SLAVIO_CPUINTCTLState *s = opaque;
-    uint32_t saddr, ret;
-
-    saddr = addr >> 2;
-    switch (saddr) {
-    case 0:
-        ret = s->intreg_pending;
-        break;
-    default:
-        ret = 0;
-        break;
-    }
-    trace_slavio_intctl_mem_readl(s->cpu, addr, ret);
-
-    return ret;
-}
-
-static void slavio_intctl_mem_writel(void *opaque, hwaddr addr,
-                                     uint64_t val, unsigned size)
-{
-    SLAVIO_CPUINTCTLState *s = opaque;
-    uint32_t saddr;
-
-    saddr = addr >> 2;
-    trace_slavio_intctl_mem_writel(s->cpu, addr, val);
-    switch (saddr) {
-    case 1: // clear pending softints
-        val &= CPU_SOFTIRQ_MASK | CPU_IRQ_INT15_IN;
-        s->intreg_pending &= ~val;
-        slavio_check_interrupts(s->master, 1);
-        trace_slavio_intctl_mem_writel_clear(s->cpu, val, s->intreg_pending);
-        break;
-    case 2: // set softint
-        val &= CPU_SOFTIRQ_MASK;
-        s->intreg_pending |= val;
-        slavio_check_interrupts(s->master, 1);
-        trace_slavio_intctl_mem_writel_set(s->cpu, val, s->intreg_pending);
-        break;
-    default:
-        break;
-    }
-}
-
-static const MemoryRegionOps slavio_intctl_mem_ops = {
-    .read = slavio_intctl_mem_readl,
-    .write = slavio_intctl_mem_writel,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-};
-
-// master system interrupt controller
-static uint64_t slavio_intctlm_mem_readl(void *opaque, hwaddr addr,
-                                         unsigned size)
-{
-    SLAVIO_INTCTLState *s = opaque;
-    uint32_t saddr, ret;
-
-    saddr = addr >> 2;
-    switch (saddr) {
-    case 0:
-        ret = s->intregm_pending & ~MASTER_DISABLE;
-        break;
-    case 1:
-        ret = s->intregm_disabled & MASTER_IRQ_MASK;
-        break;
-    case 4:
-        ret = s->target_cpu;
-        break;
-    default:
-        ret = 0;
-        break;
-    }
-    trace_slavio_intctlm_mem_readl(addr, ret);
-
-    return ret;
-}
-
-static void slavio_intctlm_mem_writel(void *opaque, hwaddr addr,
-                                      uint64_t val, unsigned size)
-{
-    SLAVIO_INTCTLState *s = opaque;
-    uint32_t saddr;
-
-    saddr = addr >> 2;
-    trace_slavio_intctlm_mem_writel(addr, val);
-    switch (saddr) {
-    case 2: // clear (enable)
-        // Force clear unused bits
-        val &= MASTER_IRQ_MASK;
-        s->intregm_disabled &= ~val;
-        trace_slavio_intctlm_mem_writel_enable(val, s->intregm_disabled);
-        slavio_check_interrupts(s, 1);
-        break;
-    case 3: // set (disable; doesn't affect pending)
-        // Force clear unused bits
-        val &= MASTER_IRQ_MASK;
-        s->intregm_disabled |= val;
-        slavio_check_interrupts(s, 1);
-        trace_slavio_intctlm_mem_writel_disable(val, s->intregm_disabled);
-        break;
-    case 4:
-        s->target_cpu = val & (MAX_CPUS - 1);
-        slavio_check_interrupts(s, 1);
-        trace_slavio_intctlm_mem_writel_target(s->target_cpu);
-        break;
-    default:
-        break;
-    }
-}
-
-static const MemoryRegionOps slavio_intctlm_mem_ops = {
-    .read = slavio_intctlm_mem_readl,
-    .write = slavio_intctlm_mem_writel,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-};
-
-void slavio_pic_info(Monitor *mon, DeviceState *dev)
-{
-    SysBusDevice *sd;
-    SLAVIO_INTCTLState *s;
-    int i;
-
-    sd = SYS_BUS_DEVICE(dev);
-    s = FROM_SYSBUS(SLAVIO_INTCTLState, sd);
-    for (i = 0; i < MAX_CPUS; i++) {
-        monitor_printf(mon, "per-cpu %d: pending 0x%08x\n", i,
-                       s->slaves[i].intreg_pending);
-    }
-    monitor_printf(mon, "master: pending 0x%08x, disabled 0x%08x\n",
-                   s->intregm_pending, s->intregm_disabled);
-}
-
-void slavio_irq_info(Monitor *mon, DeviceState *dev)
-{
-#ifndef DEBUG_IRQ_COUNT
-    monitor_printf(mon, "irq statistic code not compiled.\n");
-#else
-    SysBusDevice *sd;
-    SLAVIO_INTCTLState *s;
-    int i;
-    int64_t count;
-
-    sd = SYS_BUS_DEVICE(dev);
-    s = FROM_SYSBUS(SLAVIO_INTCTLState, sd);
-    monitor_printf(mon, "IRQ statistics:\n");
-    for (i = 0; i < 32; i++) {
-        count = s->irq_count[i];
-        if (count > 0)
-            monitor_printf(mon, "%2d: %" PRId64 "\n", i, count);
-    }
-#endif
-}
-
-static const uint32_t intbit_to_level[] = {
-    2, 3, 5, 7, 9, 11, 13, 2,   3, 5, 7, 9, 11, 13, 12, 12,
-    6, 13, 4, 10, 8, 9, 11, 0,  0, 0, 0, 15, 15, 15, 15, 0,
-};
-
-static void slavio_check_interrupts(SLAVIO_INTCTLState *s, int set_irqs)
-{
-    uint32_t pending = s->intregm_pending, pil_pending;
-    unsigned int i, j;
-
-    pending &= ~s->intregm_disabled;
-
-    trace_slavio_check_interrupts(pending, s->intregm_disabled);
-    for (i = 0; i < MAX_CPUS; i++) {
-        pil_pending = 0;
-
-        /* If we are the current interrupt target, get hard interrupts */
-        if (pending && !(s->intregm_disabled & MASTER_DISABLE) &&
-            (i == s->target_cpu)) {
-            for (j = 0; j < 32; j++) {
-                if ((pending & (1 << j)) && intbit_to_level[j]) {
-                    pil_pending |= 1 << intbit_to_level[j];
-                }
-            }
-        }
-
-        /* Calculate current pending hard interrupts for display */
-        s->slaves[i].intreg_pending &= CPU_SOFTIRQ_MASK | CPU_IRQ_INT15_IN |
-            CPU_IRQ_TIMER_IN;
-        if (i == s->target_cpu) {
-            for (j = 0; j < 32; j++) {
-                if ((s->intregm_pending & (1 << j)) && intbit_to_level[j]) {
-                    s->slaves[i].intreg_pending |= 1 << intbit_to_level[j];
-                }
-            }
-        }
-
-        /* Level 15 and CPU timer interrupts are only masked when
-           the MASTER_DISABLE bit is set */
-        if (!(s->intregm_disabled & MASTER_DISABLE)) {
-            pil_pending |= s->slaves[i].intreg_pending &
-                (CPU_IRQ_INT15_IN | CPU_IRQ_TIMER_IN);
-        }
-
-        /* Add soft interrupts */
-        pil_pending |= (s->slaves[i].intreg_pending & CPU_SOFTIRQ_MASK) >> 16;
-
-        if (set_irqs) {
-            /* Since there is not really an interrupt 0 (and pil_pending
-             * and irl_out bit zero are thus always zero) there is no need
-             * to do anything with cpu_irqs[i][0] and it is OK not to do
-             * the j=0 iteration of this loop.
-             */
-            for (j = MAX_PILS-1; j > 0; j--) {
-                if (pil_pending & (1 << j)) {
-                    if (!(s->slaves[i].irl_out & (1 << j))) {
-                        qemu_irq_raise(s->cpu_irqs[i][j]);
-                    }
-                } else {
-                    if (s->slaves[i].irl_out & (1 << j)) {
-                        qemu_irq_lower(s->cpu_irqs[i][j]);
-                    }
-                }
-            }
-        }
-        s->slaves[i].irl_out = pil_pending;
-    }
-}
-
-/*
- * "irq" here is the bit number in the system interrupt register to
- * separate serial and keyboard interrupts sharing a level.
- */
-static void slavio_set_irq(void *opaque, int irq, int level)
-{
-    SLAVIO_INTCTLState *s = opaque;
-    uint32_t mask = 1 << irq;
-    uint32_t pil = intbit_to_level[irq];
-    unsigned int i;
-
-    trace_slavio_set_irq(s->target_cpu, irq, pil, level);
-    if (pil > 0) {
-        if (level) {
-#ifdef DEBUG_IRQ_COUNT
-            s->irq_count[pil]++;
-#endif
-            s->intregm_pending |= mask;
-            if (pil == 15) {
-                for (i = 0; i < MAX_CPUS; i++) {
-                    s->slaves[i].intreg_pending |= 1 << pil;
-                }
-            }
-        } else {
-            s->intregm_pending &= ~mask;
-            if (pil == 15) {
-                for (i = 0; i < MAX_CPUS; i++) {
-                    s->slaves[i].intreg_pending &= ~(1 << pil);
-                }
-            }
-        }
-        slavio_check_interrupts(s, 1);
-    }
-}
-
-static void slavio_set_timer_irq_cpu(void *opaque, int cpu, int level)
-{
-    SLAVIO_INTCTLState *s = opaque;
-
-    trace_slavio_set_timer_irq_cpu(cpu, level);
-
-    if (level) {
-        s->slaves[cpu].intreg_pending |= CPU_IRQ_TIMER_IN;
-    } else {
-        s->slaves[cpu].intreg_pending &= ~CPU_IRQ_TIMER_IN;
-    }
-
-    slavio_check_interrupts(s, 1);
-}
-
-static void slavio_set_irq_all(void *opaque, int irq, int level)
-{
-    if (irq < 32) {
-        slavio_set_irq(opaque, irq, level);
-    } else {
-        slavio_set_timer_irq_cpu(opaque, irq - 32, level);
-    }
-}
-
-static int vmstate_intctl_post_load(void *opaque, int version_id)
-{
-    SLAVIO_INTCTLState *s = opaque;
-
-    slavio_check_interrupts(s, 0);
-    return 0;
-}
-
-static const VMStateDescription vmstate_intctl_cpu = {
-    .name ="slavio_intctl_cpu",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField []) {
-        VMSTATE_UINT32(intreg_pending, SLAVIO_CPUINTCTLState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static const VMStateDescription vmstate_intctl = {
-    .name ="slavio_intctl",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .post_load = vmstate_intctl_post_load,
-    .fields      = (VMStateField []) {
-        VMSTATE_STRUCT_ARRAY(slaves, SLAVIO_INTCTLState, MAX_CPUS, 1,
-                             vmstate_intctl_cpu, SLAVIO_CPUINTCTLState),
-        VMSTATE_UINT32(intregm_pending, SLAVIO_INTCTLState),
-        VMSTATE_UINT32(intregm_disabled, SLAVIO_INTCTLState),
-        VMSTATE_UINT32(target_cpu, SLAVIO_INTCTLState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void slavio_intctl_reset(DeviceState *d)
-{
-    SLAVIO_INTCTLState *s = container_of(d, SLAVIO_INTCTLState, busdev.qdev);
-    int i;
-
-    for (i = 0; i < MAX_CPUS; i++) {
-        s->slaves[i].intreg_pending = 0;
-        s->slaves[i].irl_out = 0;
-    }
-    s->intregm_disabled = ~MASTER_IRQ_MASK;
-    s->intregm_pending = 0;
-    s->target_cpu = 0;
-    slavio_check_interrupts(s, 0);
-}
-
-static int slavio_intctl_init1(SysBusDevice *dev)
-{
-    SLAVIO_INTCTLState *s = FROM_SYSBUS(SLAVIO_INTCTLState, dev);
-    unsigned int i, j;
-    char slave_name[45];
-
-    qdev_init_gpio_in(&dev->qdev, slavio_set_irq_all, 32 + MAX_CPUS);
-    memory_region_init_io(&s->iomem, &slavio_intctlm_mem_ops, s,
-                          "master-interrupt-controller", INTCTLM_SIZE);
-    sysbus_init_mmio(dev, &s->iomem);
-
-    for (i = 0; i < MAX_CPUS; i++) {
-        snprintf(slave_name, sizeof(slave_name),
-                 "slave-interrupt-controller-%i", i);
-        for (j = 0; j < MAX_PILS; j++) {
-            sysbus_init_irq(dev, &s->cpu_irqs[i][j]);
-        }
-        memory_region_init_io(&s->slaves[i].iomem, &slavio_intctl_mem_ops,
-                              &s->slaves[i], slave_name, INTCTL_SIZE);
-        sysbus_init_mmio(dev, &s->slaves[i].iomem);
-        s->slaves[i].cpu = i;
-        s->slaves[i].master = s;
-    }
-
-    return 0;
-}
-
-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 const 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_types(void)
-{
-    type_register_static(&slavio_intctl_info);
-}
-
-type_init(slavio_intctl_register_types)
diff --git a/hw/slavio_misc.c b/hw/slavio_misc.c
deleted file mode 100644 (file)
index a7a9368..0000000
+++ /dev/null
@@ -1,508 +0,0 @@
-/*
- * QEMU Sparc SLAVIO aux io port emulation
- *
- * Copyright (c) 2005 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.
- */
-
-#include "sysemu/sysemu.h"
-#include "hw/sysbus.h"
-#include "trace.h"
-
-/*
- * This is the auxio port, chip control and system control part of
- * chip STP2001 (Slave I/O), also produced as NCR89C105. See
- * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
- *
- * This also includes the PMC CPU idle controller.
- */
-
-typedef struct MiscState {
-    SysBusDevice busdev;
-    MemoryRegion cfg_iomem;
-    MemoryRegion diag_iomem;
-    MemoryRegion mdm_iomem;
-    MemoryRegion led_iomem;
-    MemoryRegion sysctrl_iomem;
-    MemoryRegion aux1_iomem;
-    MemoryRegion aux2_iomem;
-    qemu_irq irq;
-    qemu_irq fdc_tc;
-    uint32_t dummy;
-    uint8_t config;
-    uint8_t aux1, aux2;
-    uint8_t diag, mctrl;
-    uint8_t sysctrl;
-    uint16_t leds;
-} MiscState;
-
-typedef struct APCState {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-    qemu_irq cpu_halt;
-} APCState;
-
-#define MISC_SIZE 1
-#define SYSCTRL_SIZE 4
-
-#define AUX1_TC        0x02
-
-#define AUX2_PWROFF    0x01
-#define AUX2_PWRINTCLR 0x02
-#define AUX2_PWRFAIL   0x20
-
-#define CFG_PWRINTEN   0x08
-
-#define SYS_RESET      0x01
-#define SYS_RESETSTAT  0x02
-
-static void slavio_misc_update_irq(void *opaque)
-{
-    MiscState *s = opaque;
-
-    if ((s->aux2 & AUX2_PWRFAIL) && (s->config & CFG_PWRINTEN)) {
-        trace_slavio_misc_update_irq_raise();
-        qemu_irq_raise(s->irq);
-    } else {
-        trace_slavio_misc_update_irq_lower();
-        qemu_irq_lower(s->irq);
-    }
-}
-
-static void slavio_misc_reset(DeviceState *d)
-{
-    MiscState *s = container_of(d, MiscState, busdev.qdev);
-
-    // Diagnostic and system control registers not cleared in reset
-    s->config = s->aux1 = s->aux2 = s->mctrl = 0;
-}
-
-static void slavio_set_power_fail(void *opaque, int irq, int power_failing)
-{
-    MiscState *s = opaque;
-
-    trace_slavio_set_power_fail(power_failing, s->config);
-    if (power_failing && (s->config & CFG_PWRINTEN)) {
-        s->aux2 |= AUX2_PWRFAIL;
-    } else {
-        s->aux2 &= ~AUX2_PWRFAIL;
-    }
-    slavio_misc_update_irq(s);
-}
-
-static void slavio_cfg_mem_writeb(void *opaque, hwaddr addr,
-                                  uint64_t val, unsigned size)
-{
-    MiscState *s = opaque;
-
-    trace_slavio_cfg_mem_writeb(val & 0xff);
-    s->config = val & 0xff;
-    slavio_misc_update_irq(s);
-}
-
-static uint64_t slavio_cfg_mem_readb(void *opaque, hwaddr addr,
-                                     unsigned size)
-{
-    MiscState *s = opaque;
-    uint32_t ret = 0;
-
-    ret = s->config;
-    trace_slavio_cfg_mem_readb(ret);
-    return ret;
-}
-
-static const MemoryRegionOps slavio_cfg_mem_ops = {
-    .read = slavio_cfg_mem_readb,
-    .write = slavio_cfg_mem_writeb,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid = {
-        .min_access_size = 1,
-        .max_access_size = 1,
-    },
-};
-
-static void slavio_diag_mem_writeb(void *opaque, hwaddr addr,
-                                   uint64_t val, unsigned size)
-{
-    MiscState *s = opaque;
-
-    trace_slavio_diag_mem_writeb(val & 0xff);
-    s->diag = val & 0xff;
-}
-
-static uint64_t slavio_diag_mem_readb(void *opaque, hwaddr addr,
-                                      unsigned size)
-{
-    MiscState *s = opaque;
-    uint32_t ret = 0;
-
-    ret = s->diag;
-    trace_slavio_diag_mem_readb(ret);
-    return ret;
-}
-
-static const MemoryRegionOps slavio_diag_mem_ops = {
-    .read = slavio_diag_mem_readb,
-    .write = slavio_diag_mem_writeb,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid = {
-        .min_access_size = 1,
-        .max_access_size = 1,
-    },
-};
-
-static void slavio_mdm_mem_writeb(void *opaque, hwaddr addr,
-                                  uint64_t val, unsigned size)
-{
-    MiscState *s = opaque;
-
-    trace_slavio_mdm_mem_writeb(val & 0xff);
-    s->mctrl = val & 0xff;
-}
-
-static uint64_t slavio_mdm_mem_readb(void *opaque, hwaddr addr,
-                                     unsigned size)
-{
-    MiscState *s = opaque;
-    uint32_t ret = 0;
-
-    ret = s->mctrl;
-    trace_slavio_mdm_mem_readb(ret);
-    return ret;
-}
-
-static const MemoryRegionOps slavio_mdm_mem_ops = {
-    .read = slavio_mdm_mem_readb,
-    .write = slavio_mdm_mem_writeb,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid = {
-        .min_access_size = 1,
-        .max_access_size = 1,
-    },
-};
-
-static void slavio_aux1_mem_writeb(void *opaque, hwaddr addr,
-                                   uint64_t val, unsigned size)
-{
-    MiscState *s = opaque;
-
-    trace_slavio_aux1_mem_writeb(val & 0xff);
-    if (val & AUX1_TC) {
-        // Send a pulse to floppy terminal count line
-        if (s->fdc_tc) {
-            qemu_irq_raise(s->fdc_tc);
-            qemu_irq_lower(s->fdc_tc);
-        }
-        val &= ~AUX1_TC;
-    }
-    s->aux1 = val & 0xff;
-}
-
-static uint64_t slavio_aux1_mem_readb(void *opaque, hwaddr addr,
-                                      unsigned size)
-{
-    MiscState *s = opaque;
-    uint32_t ret = 0;
-
-    ret = s->aux1;
-    trace_slavio_aux1_mem_readb(ret);
-    return ret;
-}
-
-static const MemoryRegionOps slavio_aux1_mem_ops = {
-    .read = slavio_aux1_mem_readb,
-    .write = slavio_aux1_mem_writeb,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid = {
-        .min_access_size = 1,
-        .max_access_size = 1,
-    },
-};
-
-static void slavio_aux2_mem_writeb(void *opaque, hwaddr addr,
-                                   uint64_t val, unsigned size)
-{
-    MiscState *s = opaque;
-
-    val &= AUX2_PWRINTCLR | AUX2_PWROFF;
-    trace_slavio_aux2_mem_writeb(val & 0xff);
-    val |= s->aux2 & AUX2_PWRFAIL;
-    if (val & AUX2_PWRINTCLR) // Clear Power Fail int
-        val &= AUX2_PWROFF;
-    s->aux2 = val;
-    if (val & AUX2_PWROFF)
-        qemu_system_shutdown_request();
-    slavio_misc_update_irq(s);
-}
-
-static uint64_t slavio_aux2_mem_readb(void *opaque, hwaddr addr,
-                                      unsigned size)
-{
-    MiscState *s = opaque;
-    uint32_t ret = 0;
-
-    ret = s->aux2;
-    trace_slavio_aux2_mem_readb(ret);
-    return ret;
-}
-
-static const MemoryRegionOps slavio_aux2_mem_ops = {
-    .read = slavio_aux2_mem_readb,
-    .write = slavio_aux2_mem_writeb,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid = {
-        .min_access_size = 1,
-        .max_access_size = 1,
-    },
-};
-
-static void apc_mem_writeb(void *opaque, hwaddr addr,
-                           uint64_t val, unsigned size)
-{
-    APCState *s = opaque;
-
-    trace_apc_mem_writeb(val & 0xff);
-    qemu_irq_raise(s->cpu_halt);
-}
-
-static uint64_t apc_mem_readb(void *opaque, hwaddr addr,
-                              unsigned size)
-{
-    uint32_t ret = 0;
-
-    trace_apc_mem_readb(ret);
-    return ret;
-}
-
-static const MemoryRegionOps apc_mem_ops = {
-    .read = apc_mem_readb,
-    .write = apc_mem_writeb,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid = {
-        .min_access_size = 1,
-        .max_access_size = 1,
-    }
-};
-
-static uint64_t slavio_sysctrl_mem_readl(void *opaque, hwaddr addr,
-                                         unsigned size)
-{
-    MiscState *s = opaque;
-    uint32_t ret = 0;
-
-    switch (addr) {
-    case 0:
-        ret = s->sysctrl;
-        break;
-    default:
-        break;
-    }
-    trace_slavio_sysctrl_mem_readl(ret);
-    return ret;
-}
-
-static void slavio_sysctrl_mem_writel(void *opaque, hwaddr addr,
-                                      uint64_t val, unsigned size)
-{
-    MiscState *s = opaque;
-
-    trace_slavio_sysctrl_mem_writel(val);
-    switch (addr) {
-    case 0:
-        if (val & SYS_RESET) {
-            s->sysctrl = SYS_RESETSTAT;
-            qemu_system_reset_request();
-        }
-        break;
-    default:
-        break;
-    }
-}
-
-static const MemoryRegionOps slavio_sysctrl_mem_ops = {
-    .read = slavio_sysctrl_mem_readl,
-    .write = slavio_sysctrl_mem_writel,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-};
-
-static uint64_t slavio_led_mem_readw(void *opaque, hwaddr addr,
-                                     unsigned size)
-{
-    MiscState *s = opaque;
-    uint32_t ret = 0;
-
-    switch (addr) {
-    case 0:
-        ret = s->leds;
-        break;
-    default:
-        break;
-    }
-    trace_slavio_led_mem_readw(ret);
-    return ret;
-}
-
-static void slavio_led_mem_writew(void *opaque, hwaddr addr,
-                                  uint64_t val, unsigned size)
-{
-    MiscState *s = opaque;
-
-    trace_slavio_led_mem_readw(val & 0xffff);
-    switch (addr) {
-    case 0:
-        s->leds = val;
-        break;
-    default:
-        break;
-    }
-}
-
-static const MemoryRegionOps slavio_led_mem_ops = {
-    .read = slavio_led_mem_readw,
-    .write = slavio_led_mem_writew,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid = {
-        .min_access_size = 2,
-        .max_access_size = 2,
-    },
-};
-
-static const VMStateDescription vmstate_misc = {
-    .name ="slavio_misc",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField []) {
-        VMSTATE_UINT32(dummy, MiscState),
-        VMSTATE_UINT8(config, MiscState),
-        VMSTATE_UINT8(aux1, MiscState),
-        VMSTATE_UINT8(aux2, MiscState),
-        VMSTATE_UINT8(diag, MiscState),
-        VMSTATE_UINT8(mctrl, MiscState),
-        VMSTATE_UINT8(sysctrl, MiscState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static int apc_init1(SysBusDevice *dev)
-{
-    APCState *s = FROM_SYSBUS(APCState, dev);
-
-    sysbus_init_irq(dev, &s->cpu_halt);
-
-    /* Power management (APC) XXX: not a Slavio device */
-    memory_region_init_io(&s->iomem, &apc_mem_ops, s,
-                          "apc", MISC_SIZE);
-    sysbus_init_mmio(dev, &s->iomem);
-    return 0;
-}
-
-static int slavio_misc_init1(SysBusDevice *dev)
-{
-    MiscState *s = FROM_SYSBUS(MiscState, dev);
-
-    sysbus_init_irq(dev, &s->irq);
-    sysbus_init_irq(dev, &s->fdc_tc);
-
-    /* 8 bit registers */
-    /* Slavio control */
-    memory_region_init_io(&s->cfg_iomem, &slavio_cfg_mem_ops, s,
-                          "configuration", MISC_SIZE);
-    sysbus_init_mmio(dev, &s->cfg_iomem);
-
-    /* Diagnostics */
-    memory_region_init_io(&s->diag_iomem, &slavio_diag_mem_ops, s,
-                          "diagnostic", MISC_SIZE);
-    sysbus_init_mmio(dev, &s->diag_iomem);
-
-    /* Modem control */
-    memory_region_init_io(&s->mdm_iomem, &slavio_mdm_mem_ops, s,
-                          "modem", MISC_SIZE);
-    sysbus_init_mmio(dev, &s->mdm_iomem);
-
-    /* 16 bit registers */
-    /* ss600mp diag LEDs */
-    memory_region_init_io(&s->led_iomem, &slavio_led_mem_ops, s,
-                          "leds", MISC_SIZE);
-    sysbus_init_mmio(dev, &s->led_iomem);
-
-    /* 32 bit registers */
-    /* System control */
-    memory_region_init_io(&s->sysctrl_iomem, &slavio_sysctrl_mem_ops, s,
-                          "system-control", MISC_SIZE);
-    sysbus_init_mmio(dev, &s->sysctrl_iomem);
-
-    /* AUX 1 (Misc System Functions) */
-    memory_region_init_io(&s->aux1_iomem, &slavio_aux1_mem_ops, s,
-                          "misc-system-functions", MISC_SIZE);
-    sysbus_init_mmio(dev, &s->aux1_iomem);
-
-    /* AUX 2 (Software Powerdown Control) */
-    memory_region_init_io(&s->aux2_iomem, &slavio_aux2_mem_ops, s,
-                          "software-powerdown-control", MISC_SIZE);
-    sysbus_init_mmio(dev, &s->aux2_iomem);
-
-    qdev_init_gpio_in(&dev->qdev, slavio_set_power_fail, 1);
-
-    return 0;
-}
-
-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 const 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)
-{
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = apc_init1;
-}
-
-static const TypeInfo apc_info = {
-    .name          = "apc",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(MiscState),
-    .class_init    = apc_class_init,
-};
-
-static void slavio_misc_register_types(void)
-{
-    type_register_static(&slavio_misc_info);
-    type_register_static(&apc_info);
-}
-
-type_init(slavio_misc_register_types)
diff --git a/hw/slavio_timer.c b/hw/slavio_timer.c
deleted file mode 100644 (file)
index 83f22a0..0000000
+++ /dev/null
@@ -1,435 +0,0 @@
-/*
- * QEMU Sparc SLAVIO timer controller emulation
- *
- * Copyright (c) 2003-2005 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.
- */
-
-#include "hw/sun4m.h"
-#include "qemu/timer.h"
-#include "hw/ptimer.h"
-#include "hw/sysbus.h"
-#include "trace.h"
-
-/*
- * Registers of hardware timer in sun4m.
- *
- * This is the timer/counter part of chip STP2001 (Slave I/O), also
- * produced as NCR89C105. See
- * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
- *
- * The 31-bit counter is incremented every 500ns by bit 9. Bits 8..0
- * are zero. Bit 31 is 1 when count has been reached.
- *
- * Per-CPU timers interrupt local CPU, system timer uses normal
- * interrupt routing.
- *
- */
-
-#define MAX_CPUS 16
-
-typedef struct CPUTimerState {
-    qemu_irq irq;
-    ptimer_state *timer;
-    uint32_t count, counthigh, reached;
-    /* processor only */
-    uint32_t running;
-    uint64_t limit;
-} CPUTimerState;
-
-typedef struct SLAVIO_TIMERState {
-    SysBusDevice busdev;
-    uint32_t num_cpus;
-    uint32_t cputimer_mode;
-    CPUTimerState cputimer[MAX_CPUS + 1];
-} SLAVIO_TIMERState;
-
-typedef struct TimerContext {
-    MemoryRegion iomem;
-    SLAVIO_TIMERState *s;
-    unsigned int timer_index; /* 0 for system, 1 ... MAX_CPUS for CPU timers */
-} TimerContext;
-
-#define SYS_TIMER_SIZE 0x14
-#define CPU_TIMER_SIZE 0x10
-
-#define TIMER_LIMIT         0
-#define TIMER_COUNTER       1
-#define TIMER_COUNTER_NORST 2
-#define TIMER_STATUS        3
-#define TIMER_MODE          4
-
-#define TIMER_COUNT_MASK32 0xfffffe00
-#define TIMER_LIMIT_MASK32 0x7fffffff
-#define TIMER_MAX_COUNT64  0x7ffffffffffffe00ULL
-#define TIMER_MAX_COUNT32  0x7ffffe00ULL
-#define TIMER_REACHED      0x80000000
-#define TIMER_PERIOD       500ULL // 500ns
-#define LIMIT_TO_PERIODS(l) (((l) >> 9) - 1)
-#define PERIODS_TO_LIMIT(l) (((l) + 1) << 9)
-
-static int slavio_timer_is_user(TimerContext *tc)
-{
-    SLAVIO_TIMERState *s = tc->s;
-    unsigned int timer_index = tc->timer_index;
-
-    return timer_index != 0 && (s->cputimer_mode & (1 << (timer_index - 1)));
-}
-
-// Update count, set irq, update expire_time
-// Convert from ptimer countdown units
-static void slavio_timer_get_out(CPUTimerState *t)
-{
-    uint64_t count, limit;
-
-    if (t->limit == 0) { /* free-run system or processor counter */
-        limit = TIMER_MAX_COUNT32;
-    } else {
-        limit = t->limit;
-    }
-    count = limit - PERIODS_TO_LIMIT(ptimer_get_count(t->timer));
-
-    trace_slavio_timer_get_out(t->limit, t->counthigh, t->count);
-    t->count = count & TIMER_COUNT_MASK32;
-    t->counthigh = count >> 32;
-}
-
-// timer callback
-static void slavio_timer_irq(void *opaque)
-{
-    TimerContext *tc = opaque;
-    SLAVIO_TIMERState *s = tc->s;
-    CPUTimerState *t = &s->cputimer[tc->timer_index];
-
-    slavio_timer_get_out(t);
-    trace_slavio_timer_irq(t->counthigh, t->count);
-    /* if limit is 0 (free-run), there will be no match */
-    if (t->limit != 0) {
-        t->reached = TIMER_REACHED;
-    }
-    /* there is no interrupt if user timer or free-run */
-    if (!slavio_timer_is_user(tc) && t->limit != 0) {
-        qemu_irq_raise(t->irq);
-    }
-}
-
-static uint64_t slavio_timer_mem_readl(void *opaque, hwaddr addr,
-                                       unsigned size)
-{
-    TimerContext *tc = opaque;
-    SLAVIO_TIMERState *s = tc->s;
-    uint32_t saddr, ret;
-    unsigned int timer_index = tc->timer_index;
-    CPUTimerState *t = &s->cputimer[timer_index];
-
-    saddr = addr >> 2;
-    switch (saddr) {
-    case TIMER_LIMIT:
-        // read limit (system counter mode) or read most signifying
-        // part of counter (user mode)
-        if (slavio_timer_is_user(tc)) {
-            // read user timer MSW
-            slavio_timer_get_out(t);
-            ret = t->counthigh | t->reached;
-        } else {
-            // read limit
-            // clear irq
-            qemu_irq_lower(t->irq);
-            t->reached = 0;
-            ret = t->limit & TIMER_LIMIT_MASK32;
-        }
-        break;
-    case TIMER_COUNTER:
-        // read counter and reached bit (system mode) or read lsbits
-        // of counter (user mode)
-        slavio_timer_get_out(t);
-        if (slavio_timer_is_user(tc)) { // read user timer LSW
-            ret = t->count & TIMER_MAX_COUNT64;
-        } else { // read limit
-            ret = (t->count & TIMER_MAX_COUNT32) |
-                t->reached;
-        }
-        break;
-    case TIMER_STATUS:
-        // only available in processor counter/timer
-        // read start/stop status
-        if (timer_index > 0) {
-            ret = t->running;
-        } else {
-            ret = 0;
-        }
-        break;
-    case TIMER_MODE:
-        // only available in system counter
-        // read user/system mode
-        ret = s->cputimer_mode;
-        break;
-    default:
-        trace_slavio_timer_mem_readl_invalid(addr);
-        ret = 0;
-        break;
-    }
-    trace_slavio_timer_mem_readl(addr, ret);
-    return ret;
-}
-
-static void slavio_timer_mem_writel(void *opaque, hwaddr addr,
-                                    uint64_t val, unsigned size)
-{
-    TimerContext *tc = opaque;
-    SLAVIO_TIMERState *s = tc->s;
-    uint32_t saddr;
-    unsigned int timer_index = tc->timer_index;
-    CPUTimerState *t = &s->cputimer[timer_index];
-
-    trace_slavio_timer_mem_writel(addr, val);
-    saddr = addr >> 2;
-    switch (saddr) {
-    case TIMER_LIMIT:
-        if (slavio_timer_is_user(tc)) {
-            uint64_t count;
-
-            // set user counter MSW, reset counter
-            t->limit = TIMER_MAX_COUNT64;
-            t->counthigh = val & (TIMER_MAX_COUNT64 >> 32);
-            t->reached = 0;
-            count = ((uint64_t)t->counthigh << 32) | t->count;
-            trace_slavio_timer_mem_writel_limit(timer_index, count);
-            ptimer_set_count(t->timer, LIMIT_TO_PERIODS(t->limit - count));
-        } else {
-            // set limit, reset counter
-            qemu_irq_lower(t->irq);
-            t->limit = val & TIMER_MAX_COUNT32;
-            if (t->timer) {
-                if (t->limit == 0) { /* free-run */
-                    ptimer_set_limit(t->timer,
-                                     LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 1);
-                } else {
-                    ptimer_set_limit(t->timer, LIMIT_TO_PERIODS(t->limit), 1);
-                }
-            }
-        }
-        break;
-    case TIMER_COUNTER:
-        if (slavio_timer_is_user(tc)) {
-            uint64_t count;
-
-            // set user counter LSW, reset counter
-            t->limit = TIMER_MAX_COUNT64;
-            t->count = val & TIMER_MAX_COUNT64;
-            t->reached = 0;
-            count = ((uint64_t)t->counthigh) << 32 | t->count;
-            trace_slavio_timer_mem_writel_limit(timer_index, count);
-            ptimer_set_count(t->timer, LIMIT_TO_PERIODS(t->limit - count));
-        } else {
-            trace_slavio_timer_mem_writel_counter_invalid();
-        }
-        break;
-    case TIMER_COUNTER_NORST:
-        // set limit without resetting counter
-        t->limit = val & TIMER_MAX_COUNT32;
-        if (t->limit == 0) { /* free-run */
-            ptimer_set_limit(t->timer, LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 0);
-        } else {
-            ptimer_set_limit(t->timer, LIMIT_TO_PERIODS(t->limit), 0);
-        }
-        break;
-    case TIMER_STATUS:
-        if (slavio_timer_is_user(tc)) {
-            // start/stop user counter
-            if ((val & 1) && !t->running) {
-                trace_slavio_timer_mem_writel_status_start(timer_index);
-                ptimer_run(t->timer, 0);
-                t->running = 1;
-            } else if (!(val & 1) && t->running) {
-                trace_slavio_timer_mem_writel_status_stop(timer_index);
-                ptimer_stop(t->timer);
-                t->running = 0;
-            }
-        }
-        break;
-    case TIMER_MODE:
-        if (timer_index == 0) {
-            unsigned int i;
-
-            for (i = 0; i < s->num_cpus; i++) {
-                unsigned int processor = 1 << i;
-                CPUTimerState *curr_timer = &s->cputimer[i + 1];
-
-                // check for a change in timer mode for this processor
-                if ((val & processor) != (s->cputimer_mode & processor)) {
-                    if (val & processor) { // counter -> user timer
-                        qemu_irq_lower(curr_timer->irq);
-                        // counters are always running
-                        ptimer_stop(curr_timer->timer);
-                        curr_timer->running = 0;
-                        // user timer limit is always the same
-                        curr_timer->limit = TIMER_MAX_COUNT64;
-                        ptimer_set_limit(curr_timer->timer,
-                                         LIMIT_TO_PERIODS(curr_timer->limit),
-                                         1);
-                        // set this processors user timer bit in config
-                        // register
-                        s->cputimer_mode |= processor;
-                        trace_slavio_timer_mem_writel_mode_user(timer_index);
-                    } else { // user timer -> counter
-                        // stop the user timer if it is running
-                        if (curr_timer->running) {
-                            ptimer_stop(curr_timer->timer);
-                        }
-                        // start the counter
-                        ptimer_run(curr_timer->timer, 0);
-                        curr_timer->running = 1;
-                        // clear this processors user timer bit in config
-                        // register
-                        s->cputimer_mode &= ~processor;
-                        trace_slavio_timer_mem_writel_mode_counter(timer_index);
-                    }
-                }
-            }
-        } else {
-            trace_slavio_timer_mem_writel_mode_invalid();
-        }
-        break;
-    default:
-        trace_slavio_timer_mem_writel_invalid(addr);
-        break;
-    }
-}
-
-static const MemoryRegionOps slavio_timer_mem_ops = {
-    .read = slavio_timer_mem_readl,
-    .write = slavio_timer_mem_writel,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-};
-
-static const VMStateDescription vmstate_timer = {
-    .name ="timer",
-    .version_id = 3,
-    .minimum_version_id = 3,
-    .minimum_version_id_old = 3,
-    .fields      = (VMStateField []) {
-        VMSTATE_UINT64(limit, CPUTimerState),
-        VMSTATE_UINT32(count, CPUTimerState),
-        VMSTATE_UINT32(counthigh, CPUTimerState),
-        VMSTATE_UINT32(reached, CPUTimerState),
-        VMSTATE_UINT32(running, CPUTimerState),
-        VMSTATE_PTIMER(timer, CPUTimerState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static const VMStateDescription vmstate_slavio_timer = {
-    .name ="slavio_timer",
-    .version_id = 3,
-    .minimum_version_id = 3,
-    .minimum_version_id_old = 3,
-    .fields      = (VMStateField []) {
-        VMSTATE_STRUCT_ARRAY(cputimer, SLAVIO_TIMERState, MAX_CPUS + 1, 3,
-                             vmstate_timer, CPUTimerState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void slavio_timer_reset(DeviceState *d)
-{
-    SLAVIO_TIMERState *s = container_of(d, SLAVIO_TIMERState, busdev.qdev);
-    unsigned int i;
-    CPUTimerState *curr_timer;
-
-    for (i = 0; i <= MAX_CPUS; i++) {
-        curr_timer = &s->cputimer[i];
-        curr_timer->limit = 0;
-        curr_timer->count = 0;
-        curr_timer->reached = 0;
-        if (i <= s->num_cpus) {
-            ptimer_set_limit(curr_timer->timer,
-                             LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 1);
-            ptimer_run(curr_timer->timer, 0);
-            curr_timer->running = 1;
-        }
-    }
-    s->cputimer_mode = 0;
-}
-
-static int slavio_timer_init1(SysBusDevice *dev)
-{
-    SLAVIO_TIMERState *s = FROM_SYSBUS(SLAVIO_TIMERState, dev);
-    QEMUBH *bh;
-    unsigned int i;
-    TimerContext *tc;
-
-    for (i = 0; i <= MAX_CPUS; i++) {
-        uint64_t size;
-        char timer_name[20];
-
-        tc = g_malloc0(sizeof(TimerContext));
-        tc->s = s;
-        tc->timer_index = i;
-
-        bh = qemu_bh_new(slavio_timer_irq, tc);
-        s->cputimer[i].timer = ptimer_init(bh);
-        ptimer_set_period(s->cputimer[i].timer, TIMER_PERIOD);
-
-        size = i == 0 ? SYS_TIMER_SIZE : CPU_TIMER_SIZE;
-        snprintf(timer_name, sizeof(timer_name), "timer-%i", i);
-        memory_region_init_io(&tc->iomem, &slavio_timer_mem_ops, tc,
-                              timer_name, size);
-        sysbus_init_mmio(dev, &tc->iomem);
-
-        sysbus_init_irq(dev, &s->cputimer[i].irq);
-    }
-
-    return 0;
-}
-
-static Property slavio_timer_properties[] = {
-    DEFINE_PROP_UINT32("num_cpus",  SLAVIO_TIMERState, num_cpus,  0),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void slavio_timer_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = slavio_timer_init1;
-    dc->reset = slavio_timer_reset;
-    dc->vmsd = &vmstate_slavio_timer;
-    dc->props = slavio_timer_properties;
-}
-
-static const 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_types(void)
-{
-    type_register_static(&slavio_timer_info);
-}
-
-type_init(slavio_timer_register_types)
diff --git a/hw/sm501.c b/hw/sm501.c
deleted file mode 100644 (file)
index 93a06c9..0000000
+++ /dev/null
@@ -1,1450 +0,0 @@
-/*
- * QEMU SM501 Device
- *
- * Copyright (c) 2008 Shin-ichiro KAWASAKI
- *
- * 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 <stdio.h>
-#include "hw/hw.h"
-#include "hw/serial.h"
-#include "ui/console.h"
-#include "hw/devices.h"
-#include "hw/sysbus.h"
-#include "hw/qdev-addr.h"
-#include "qemu/range.h"
-#include "ui/pixel_ops.h"
-
-/*
- * Status: 2010/05/07
- *   - Minimum implementation for Linux console : mmio regs and CRT layer.
- *   - 2D grapihcs acceleration partially supported : only fill rectangle.
- *
- * TODO:
- *   - Panel support
- *   - Touch panel support
- *   - USB support
- *   - UART support
- *   - More 2D graphics engine support
- *   - Performance tuning
- */
-
-//#define DEBUG_SM501
-//#define DEBUG_BITBLT
-
-#ifdef DEBUG_SM501
-#define SM501_DPRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__)
-#else
-#define SM501_DPRINTF(fmt, ...) do {} while(0)
-#endif
-
-
-#define MMIO_BASE_OFFSET 0x3e00000
-
-/* SM501 register definitions taken from "linux/include/linux/sm501-regs.h" */
-
-/* System Configuration area */
-/* System config base */
-#define SM501_SYS_CONFIG               (0x000000)
-
-/* config 1 */
-#define SM501_SYSTEM_CONTROL           (0x000000)
-
-#define SM501_SYSCTRL_PANEL_TRISTATE   (1<<0)
-#define SM501_SYSCTRL_MEM_TRISTATE     (1<<1)
-#define SM501_SYSCTRL_CRT_TRISTATE     (1<<2)
-
-#define SM501_SYSCTRL_PCI_SLAVE_BURST_MASK (3<<4)
-#define SM501_SYSCTRL_PCI_SLAVE_BURST_1        (0<<4)
-#define SM501_SYSCTRL_PCI_SLAVE_BURST_2        (1<<4)
-#define SM501_SYSCTRL_PCI_SLAVE_BURST_4        (2<<4)
-#define SM501_SYSCTRL_PCI_SLAVE_BURST_8        (3<<4)
-
-#define SM501_SYSCTRL_PCI_CLOCK_RUN_EN (1<<6)
-#define SM501_SYSCTRL_PCI_RETRY_DISABLE        (1<<7)
-#define SM501_SYSCTRL_PCI_SUBSYS_LOCK  (1<<11)
-#define SM501_SYSCTRL_PCI_BURST_READ_EN        (1<<15)
-
-/* miscellaneous control */
-
-#define SM501_MISC_CONTROL             (0x000004)
-
-#define SM501_MISC_BUS_SH              (0x0)
-#define SM501_MISC_BUS_PCI             (0x1)
-#define SM501_MISC_BUS_XSCALE          (0x2)
-#define SM501_MISC_BUS_NEC             (0x6)
-#define SM501_MISC_BUS_MASK            (0x7)
-
-#define SM501_MISC_VR_62MB             (1<<3)
-#define SM501_MISC_CDR_RESET           (1<<7)
-#define SM501_MISC_USB_LB              (1<<8)
-#define SM501_MISC_USB_SLAVE           (1<<9)
-#define SM501_MISC_BL_1                        (1<<10)
-#define SM501_MISC_MC                  (1<<11)
-#define SM501_MISC_DAC_POWER           (1<<12)
-#define SM501_MISC_IRQ_INVERT          (1<<16)
-#define SM501_MISC_SH                  (1<<17)
-
-#define SM501_MISC_HOLD_EMPTY          (0<<18)
-#define SM501_MISC_HOLD_8              (1<<18)
-#define SM501_MISC_HOLD_16             (2<<18)
-#define SM501_MISC_HOLD_24             (3<<18)
-#define SM501_MISC_HOLD_32             (4<<18)
-#define SM501_MISC_HOLD_MASK           (7<<18)
-
-#define SM501_MISC_FREQ_12             (1<<24)
-#define SM501_MISC_PNL_24BIT           (1<<25)
-#define SM501_MISC_8051_LE             (1<<26)
-
-
-
-#define SM501_GPIO31_0_CONTROL         (0x000008)
-#define SM501_GPIO63_32_CONTROL                (0x00000C)
-#define SM501_DRAM_CONTROL             (0x000010)
-
-/* command list */
-#define SM501_ARBTRTN_CONTROL          (0x000014)
-
-/* command list */
-#define SM501_COMMAND_LIST_STATUS      (0x000024)
-
-/* interrupt debug */
-#define SM501_RAW_IRQ_STATUS           (0x000028)
-#define SM501_RAW_IRQ_CLEAR            (0x000028)
-#define SM501_IRQ_STATUS               (0x00002C)
-#define SM501_IRQ_MASK                 (0x000030)
-#define SM501_DEBUG_CONTROL            (0x000034)
-
-/* power management */
-#define SM501_POWERMODE_P2X_SRC                (1<<29)
-#define SM501_POWERMODE_V2X_SRC                (1<<20)
-#define SM501_POWERMODE_M_SRC          (1<<12)
-#define SM501_POWERMODE_M1_SRC         (1<<4)
-
-#define SM501_CURRENT_GATE             (0x000038)
-#define SM501_CURRENT_CLOCK            (0x00003C)
-#define SM501_POWER_MODE_0_GATE                (0x000040)
-#define SM501_POWER_MODE_0_CLOCK       (0x000044)
-#define SM501_POWER_MODE_1_GATE                (0x000048)
-#define SM501_POWER_MODE_1_CLOCK       (0x00004C)
-#define SM501_SLEEP_MODE_GATE          (0x000050)
-#define SM501_POWER_MODE_CONTROL       (0x000054)
-
-/* power gates for units within the 501 */
-#define SM501_GATE_HOST                        (0)
-#define SM501_GATE_MEMORY              (1)
-#define SM501_GATE_DISPLAY             (2)
-#define SM501_GATE_2D_ENGINE           (3)
-#define SM501_GATE_CSC                 (4)
-#define SM501_GATE_ZVPORT              (5)
-#define SM501_GATE_GPIO                        (6)
-#define SM501_GATE_UART0               (7)
-#define SM501_GATE_UART1               (8)
-#define SM501_GATE_SSP                 (10)
-#define SM501_GATE_USB_HOST            (11)
-#define SM501_GATE_USB_GADGET          (12)
-#define SM501_GATE_UCONTROLLER         (17)
-#define SM501_GATE_AC97                        (18)
-
-/* panel clock */
-#define SM501_CLOCK_P2XCLK             (24)
-/* crt clock */
-#define SM501_CLOCK_V2XCLK             (16)
-/* main clock */
-#define SM501_CLOCK_MCLK               (8)
-/* SDRAM controller clock */
-#define SM501_CLOCK_M1XCLK             (0)
-
-/* config 2 */
-#define SM501_PCI_MASTER_BASE          (0x000058)
-#define SM501_ENDIAN_CONTROL           (0x00005C)
-#define SM501_DEVICEID                 (0x000060)
-/* 0x050100A0 */
-
-#define SM501_DEVICEID_SM501           (0x05010000)
-#define SM501_DEVICEID_IDMASK          (0xffff0000)
-#define SM501_DEVICEID_REVMASK         (0x000000ff)
-
-#define SM501_PLLCLOCK_COUNT           (0x000064)
-#define SM501_MISC_TIMING              (0x000068)
-#define SM501_CURRENT_SDRAM_CLOCK      (0x00006C)
-
-#define SM501_PROGRAMMABLE_PLL_CONTROL (0x000074)
-
-/* GPIO base */
-#define SM501_GPIO                     (0x010000)
-#define SM501_GPIO_DATA_LOW            (0x00)
-#define SM501_GPIO_DATA_HIGH           (0x04)
-#define SM501_GPIO_DDR_LOW             (0x08)
-#define SM501_GPIO_DDR_HIGH            (0x0C)
-#define SM501_GPIO_IRQ_SETUP           (0x10)
-#define SM501_GPIO_IRQ_STATUS          (0x14)
-#define SM501_GPIO_IRQ_RESET           (0x14)
-
-/* I2C controller base */
-#define SM501_I2C                      (0x010040)
-#define SM501_I2C_BYTE_COUNT           (0x00)
-#define SM501_I2C_CONTROL              (0x01)
-#define SM501_I2C_STATUS               (0x02)
-#define SM501_I2C_RESET                        (0x02)
-#define SM501_I2C_SLAVE_ADDRESS                (0x03)
-#define SM501_I2C_DATA                 (0x04)
-
-/* SSP base */
-#define SM501_SSP                      (0x020000)
-
-/* Uart 0 base */
-#define SM501_UART0                    (0x030000)
-
-/* Uart 1 base */
-#define SM501_UART1                    (0x030020)
-
-/* USB host port base */
-#define SM501_USB_HOST                 (0x040000)
-
-/* USB slave/gadget base */
-#define SM501_USB_GADGET               (0x060000)
-
-/* USB slave/gadget data port base */
-#define SM501_USB_GADGET_DATA          (0x070000)
-
-/* Display controller/video engine base */
-#define SM501_DC                       (0x080000)
-
-/* common defines for the SM501 address registers */
-#define SM501_ADDR_FLIP                        (1<<31)
-#define SM501_ADDR_EXT                 (1<<27)
-#define SM501_ADDR_CS1                 (1<<26)
-#define SM501_ADDR_MASK                        (0x3f << 26)
-
-#define SM501_FIFO_MASK                        (0x3 << 16)
-#define SM501_FIFO_1                   (0x0 << 16)
-#define SM501_FIFO_3                   (0x1 << 16)
-#define SM501_FIFO_7                   (0x2 << 16)
-#define SM501_FIFO_11                  (0x3 << 16)
-
-/* common registers for panel and the crt */
-#define SM501_OFF_DC_H_TOT             (0x000)
-#define SM501_OFF_DC_V_TOT             (0x008)
-#define SM501_OFF_DC_H_SYNC            (0x004)
-#define SM501_OFF_DC_V_SYNC            (0x00C)
-
-#define SM501_DC_PANEL_CONTROL         (0x000)
-
-#define SM501_DC_PANEL_CONTROL_FPEN    (1<<27)
-#define SM501_DC_PANEL_CONTROL_BIAS    (1<<26)
-#define SM501_DC_PANEL_CONTROL_DATA    (1<<25)
-#define SM501_DC_PANEL_CONTROL_VDD     (1<<24)
-#define SM501_DC_PANEL_CONTROL_DP      (1<<23)
-
-#define SM501_DC_PANEL_CONTROL_TFT_888 (0<<21)
-#define SM501_DC_PANEL_CONTROL_TFT_333 (1<<21)
-#define SM501_DC_PANEL_CONTROL_TFT_444 (2<<21)
-
-#define SM501_DC_PANEL_CONTROL_DE      (1<<20)
-
-#define SM501_DC_PANEL_CONTROL_LCD_TFT (0<<18)
-#define SM501_DC_PANEL_CONTROL_LCD_STN8        (1<<18)
-#define SM501_DC_PANEL_CONTROL_LCD_STN12 (2<<18)
-
-#define SM501_DC_PANEL_CONTROL_CP      (1<<14)
-#define SM501_DC_PANEL_CONTROL_VSP     (1<<13)
-#define SM501_DC_PANEL_CONTROL_HSP     (1<<12)
-#define SM501_DC_PANEL_CONTROL_CK      (1<<9)
-#define SM501_DC_PANEL_CONTROL_TE      (1<<8)
-#define SM501_DC_PANEL_CONTROL_VPD     (1<<7)
-#define SM501_DC_PANEL_CONTROL_VP      (1<<6)
-#define SM501_DC_PANEL_CONTROL_HPD     (1<<5)
-#define SM501_DC_PANEL_CONTROL_HP      (1<<4)
-#define SM501_DC_PANEL_CONTROL_GAMMA   (1<<3)
-#define SM501_DC_PANEL_CONTROL_EN      (1<<2)
-
-#define SM501_DC_PANEL_CONTROL_8BPP    (0<<0)
-#define SM501_DC_PANEL_CONTROL_16BPP   (1<<0)
-#define SM501_DC_PANEL_CONTROL_32BPP   (2<<0)
-
-
-#define SM501_DC_PANEL_PANNING_CONTROL (0x004)
-#define SM501_DC_PANEL_COLOR_KEY       (0x008)
-#define SM501_DC_PANEL_FB_ADDR         (0x00C)
-#define SM501_DC_PANEL_FB_OFFSET       (0x010)
-#define SM501_DC_PANEL_FB_WIDTH                (0x014)
-#define SM501_DC_PANEL_FB_HEIGHT       (0x018)
-#define SM501_DC_PANEL_TL_LOC          (0x01C)
-#define SM501_DC_PANEL_BR_LOC          (0x020)
-#define SM501_DC_PANEL_H_TOT           (0x024)
-#define SM501_DC_PANEL_H_SYNC          (0x028)
-#define SM501_DC_PANEL_V_TOT           (0x02C)
-#define SM501_DC_PANEL_V_SYNC          (0x030)
-#define SM501_DC_PANEL_CUR_LINE                (0x034)
-
-#define SM501_DC_VIDEO_CONTROL         (0x040)
-#define SM501_DC_VIDEO_FB0_ADDR                (0x044)
-#define SM501_DC_VIDEO_FB_WIDTH                (0x048)
-#define SM501_DC_VIDEO_FB0_LAST_ADDR   (0x04C)
-#define SM501_DC_VIDEO_TL_LOC          (0x050)
-#define SM501_DC_VIDEO_BR_LOC          (0x054)
-#define SM501_DC_VIDEO_SCALE           (0x058)
-#define SM501_DC_VIDEO_INIT_SCALE      (0x05C)
-#define SM501_DC_VIDEO_YUV_CONSTANTS   (0x060)
-#define SM501_DC_VIDEO_FB1_ADDR                (0x064)
-#define SM501_DC_VIDEO_FB1_LAST_ADDR   (0x068)
-
-#define SM501_DC_VIDEO_ALPHA_CONTROL   (0x080)
-#define SM501_DC_VIDEO_ALPHA_FB_ADDR   (0x084)
-#define SM501_DC_VIDEO_ALPHA_FB_OFFSET (0x088)
-#define SM501_DC_VIDEO_ALPHA_FB_LAST_ADDR      (0x08C)
-#define SM501_DC_VIDEO_ALPHA_TL_LOC    (0x090)
-#define SM501_DC_VIDEO_ALPHA_BR_LOC    (0x094)
-#define SM501_DC_VIDEO_ALPHA_SCALE     (0x098)
-#define SM501_DC_VIDEO_ALPHA_INIT_SCALE        (0x09C)
-#define SM501_DC_VIDEO_ALPHA_CHROMA_KEY        (0x0A0)
-#define SM501_DC_VIDEO_ALPHA_COLOR_LOOKUP      (0x0A4)
-
-#define SM501_DC_PANEL_HWC_BASE                (0x0F0)
-#define SM501_DC_PANEL_HWC_ADDR                (0x0F0)
-#define SM501_DC_PANEL_HWC_LOC         (0x0F4)
-#define SM501_DC_PANEL_HWC_COLOR_1_2   (0x0F8)
-#define SM501_DC_PANEL_HWC_COLOR_3     (0x0FC)
-
-#define SM501_HWC_EN                   (1<<31)
-
-#define SM501_OFF_HWC_ADDR             (0x00)
-#define SM501_OFF_HWC_LOC              (0x04)
-#define SM501_OFF_HWC_COLOR_1_2                (0x08)
-#define SM501_OFF_HWC_COLOR_3          (0x0C)
-
-#define SM501_DC_ALPHA_CONTROL         (0x100)
-#define SM501_DC_ALPHA_FB_ADDR         (0x104)
-#define SM501_DC_ALPHA_FB_OFFSET       (0x108)
-#define SM501_DC_ALPHA_TL_LOC          (0x10C)
-#define SM501_DC_ALPHA_BR_LOC          (0x110)
-#define SM501_DC_ALPHA_CHROMA_KEY      (0x114)
-#define SM501_DC_ALPHA_COLOR_LOOKUP    (0x118)
-
-#define SM501_DC_CRT_CONTROL           (0x200)
-
-#define SM501_DC_CRT_CONTROL_TVP       (1<<15)
-#define SM501_DC_CRT_CONTROL_CP                (1<<14)
-#define SM501_DC_CRT_CONTROL_VSP       (1<<13)
-#define SM501_DC_CRT_CONTROL_HSP       (1<<12)
-#define SM501_DC_CRT_CONTROL_VS                (1<<11)
-#define SM501_DC_CRT_CONTROL_BLANK     (1<<10)
-#define SM501_DC_CRT_CONTROL_SEL       (1<<9)
-#define SM501_DC_CRT_CONTROL_TE                (1<<8)
-#define SM501_DC_CRT_CONTROL_PIXEL_MASK (0xF << 4)
-#define SM501_DC_CRT_CONTROL_GAMMA     (1<<3)
-#define SM501_DC_CRT_CONTROL_ENABLE    (1<<2)
-
-#define SM501_DC_CRT_CONTROL_8BPP      (0<<0)
-#define SM501_DC_CRT_CONTROL_16BPP     (1<<0)
-#define SM501_DC_CRT_CONTROL_32BPP     (2<<0)
-
-#define SM501_DC_CRT_FB_ADDR           (0x204)
-#define SM501_DC_CRT_FB_OFFSET         (0x208)
-#define SM501_DC_CRT_H_TOT             (0x20C)
-#define SM501_DC_CRT_H_SYNC            (0x210)
-#define SM501_DC_CRT_V_TOT             (0x214)
-#define SM501_DC_CRT_V_SYNC            (0x218)
-#define SM501_DC_CRT_SIGNATURE_ANALYZER        (0x21C)
-#define SM501_DC_CRT_CUR_LINE          (0x220)
-#define SM501_DC_CRT_MONITOR_DETECT    (0x224)
-
-#define SM501_DC_CRT_HWC_BASE          (0x230)
-#define SM501_DC_CRT_HWC_ADDR          (0x230)
-#define SM501_DC_CRT_HWC_LOC           (0x234)
-#define SM501_DC_CRT_HWC_COLOR_1_2     (0x238)
-#define SM501_DC_CRT_HWC_COLOR_3       (0x23C)
-
-#define SM501_DC_PANEL_PALETTE         (0x400)
-
-#define SM501_DC_VIDEO_PALETTE         (0x800)
-
-#define SM501_DC_CRT_PALETTE           (0xC00)
-
-/* Zoom Video port base */
-#define SM501_ZVPORT                   (0x090000)
-
-/* AC97/I2S base */
-#define SM501_AC97                     (0x0A0000)
-
-/* 8051 micro controller base */
-#define SM501_UCONTROLLER              (0x0B0000)
-
-/* 8051 micro controller SRAM base */
-#define SM501_UCONTROLLER_SRAM         (0x0C0000)
-
-/* DMA base */
-#define SM501_DMA                      (0x0D0000)
-
-/* 2d engine base */
-#define SM501_2D_ENGINE                        (0x100000)
-#define SM501_2D_SOURCE                        (0x00)
-#define SM501_2D_DESTINATION           (0x04)
-#define SM501_2D_DIMENSION             (0x08)
-#define SM501_2D_CONTROL               (0x0C)
-#define SM501_2D_PITCH                 (0x10)
-#define SM501_2D_FOREGROUND            (0x14)
-#define SM501_2D_BACKGROUND            (0x18)
-#define SM501_2D_STRETCH               (0x1C)
-#define SM501_2D_COLOR_COMPARE         (0x20)
-#define SM501_2D_COLOR_COMPARE_MASK    (0x24)
-#define SM501_2D_MASK                  (0x28)
-#define SM501_2D_CLIP_TL               (0x2C)
-#define SM501_2D_CLIP_BR               (0x30)
-#define SM501_2D_MONO_PATTERN_LOW      (0x34)
-#define SM501_2D_MONO_PATTERN_HIGH     (0x38)
-#define SM501_2D_WINDOW_WIDTH          (0x3C)
-#define SM501_2D_SOURCE_BASE           (0x40)
-#define SM501_2D_DESTINATION_BASE      (0x44)
-#define SM501_2D_ALPHA                 (0x48)
-#define SM501_2D_WRAP                  (0x4C)
-#define SM501_2D_STATUS                        (0x50)
-
-#define SM501_CSC_Y_SOURCE_BASE                (0xC8)
-#define SM501_CSC_CONSTANTS            (0xCC)
-#define SM501_CSC_Y_SOURCE_X           (0xD0)
-#define SM501_CSC_Y_SOURCE_Y           (0xD4)
-#define SM501_CSC_U_SOURCE_BASE                (0xD8)
-#define SM501_CSC_V_SOURCE_BASE                (0xDC)
-#define SM501_CSC_SOURCE_DIMENSION     (0xE0)
-#define SM501_CSC_SOURCE_PITCH         (0xE4)
-#define SM501_CSC_DESTINATION          (0xE8)
-#define SM501_CSC_DESTINATION_DIMENSION        (0xEC)
-#define SM501_CSC_DESTINATION_PITCH    (0xF0)
-#define SM501_CSC_SCALE_FACTOR         (0xF4)
-#define SM501_CSC_DESTINATION_BASE     (0xF8)
-#define SM501_CSC_CONTROL              (0xFC)
-
-/* 2d engine data port base */
-#define SM501_2D_ENGINE_DATA           (0x110000)
-
-/* end of register definitions */
-
-#define SM501_HWC_WIDTH                       (64)
-#define SM501_HWC_HEIGHT                      (64)
-
-/* SM501 local memory size taken from "linux/drivers/mfd/sm501.c" */
-static const uint32_t sm501_mem_local_size[] = {
-       [0]     = 4*1024*1024,
-       [1]     = 8*1024*1024,
-       [2]     = 16*1024*1024,
-       [3]     = 32*1024*1024,
-       [4]     = 64*1024*1024,
-       [5]     = 2*1024*1024,
-};
-#define get_local_mem_size(s) sm501_mem_local_size[(s)->local_mem_size_index]
-
-typedef struct SM501State {
-    /* graphic console status */
-    QemuConsole *con;
-
-    /* status & internal resources */
-    hwaddr base;
-    uint32_t local_mem_size_index;
-    uint8_t * local_mem;
-    MemoryRegion local_mem_region;
-    uint32_t last_width;
-    uint32_t last_height;
-
-    /* mmio registers */
-    uint32_t system_control;
-    uint32_t misc_control;
-    uint32_t gpio_31_0_control;
-    uint32_t gpio_63_32_control;
-    uint32_t dram_control;
-    uint32_t irq_mask;
-    uint32_t misc_timing;
-    uint32_t power_mode_control;
-
-    uint32_t uart0_ier;
-    uint32_t uart0_lcr;
-    uint32_t uart0_mcr;
-    uint32_t uart0_scr;
-
-    uint8_t dc_palette[0x400 * 3];
-
-    uint32_t dc_panel_control;
-    uint32_t dc_panel_panning_control;
-    uint32_t dc_panel_fb_addr;
-    uint32_t dc_panel_fb_offset;
-    uint32_t dc_panel_fb_width;
-    uint32_t dc_panel_fb_height;
-    uint32_t dc_panel_tl_location;
-    uint32_t dc_panel_br_location;
-    uint32_t dc_panel_h_total;
-    uint32_t dc_panel_h_sync;
-    uint32_t dc_panel_v_total;
-    uint32_t dc_panel_v_sync;
-
-    uint32_t dc_panel_hwc_addr;
-    uint32_t dc_panel_hwc_location;
-    uint32_t dc_panel_hwc_color_1_2;
-    uint32_t dc_panel_hwc_color_3;
-
-    uint32_t dc_crt_control;
-    uint32_t dc_crt_fb_addr;
-    uint32_t dc_crt_fb_offset;
-    uint32_t dc_crt_h_total;
-    uint32_t dc_crt_h_sync;
-    uint32_t dc_crt_v_total;
-    uint32_t dc_crt_v_sync;
-
-    uint32_t dc_crt_hwc_addr;
-    uint32_t dc_crt_hwc_location;
-    uint32_t dc_crt_hwc_color_1_2;
-    uint32_t dc_crt_hwc_color_3;
-
-    uint32_t twoD_source;
-    uint32_t twoD_destination;
-    uint32_t twoD_dimension;
-    uint32_t twoD_control;
-    uint32_t twoD_pitch;
-    uint32_t twoD_foreground;
-    uint32_t twoD_stretch;
-    uint32_t twoD_color_compare_mask;
-    uint32_t twoD_mask;
-    uint32_t twoD_window_width;
-    uint32_t twoD_source_base;
-    uint32_t twoD_destination_base;
-
-} SM501State;
-
-static uint32_t get_local_mem_size_index(uint32_t size)
-{
-    uint32_t norm_size = 0;
-    int i, index = 0;
-
-    for (i = 0; i < ARRAY_SIZE(sm501_mem_local_size); i++) {
-       uint32_t new_size = sm501_mem_local_size[i];
-       if (new_size >= size) {
-           if (norm_size == 0 || norm_size > new_size) {
-               norm_size = new_size;
-               index = i;
-           }
-       }
-    }
-
-    return index;
-}
-
-/**
- * Check the availability of hardware cursor.
- * @param crt  0 for PANEL, 1 for CRT.
- */
-static inline int is_hwc_enabled(SM501State *state, int crt)
-{
-    uint32_t addr = crt ? state->dc_crt_hwc_addr : state->dc_panel_hwc_addr;
-    return addr & 0x80000000;
-}
-
-/**
- * Get the address which holds cursor pattern data.
- * @param crt  0 for PANEL, 1 for CRT.
- */
-static inline uint32_t get_hwc_address(SM501State *state, int crt)
-{
-    uint32_t addr = crt ? state->dc_crt_hwc_addr : state->dc_panel_hwc_addr;
-    return (addr & 0x03FFFFF0)/* >> 4*/;
-}
-
-/**
- * Get the cursor position in y coordinate.
- * @param crt  0 for PANEL, 1 for CRT.
- */
-static inline uint32_t get_hwc_y(SM501State *state, int crt)
-{
-    uint32_t location = crt ? state->dc_crt_hwc_location
-                            : state->dc_panel_hwc_location;
-    return (location & 0x07FF0000) >> 16;
-}
-
-/**
- * Get the cursor position in x coordinate.
- * @param crt  0 for PANEL, 1 for CRT.
- */
-static inline uint32_t get_hwc_x(SM501State *state, int crt)
-{
-    uint32_t location = crt ? state->dc_crt_hwc_location
-                            : state->dc_panel_hwc_location;
-    return location & 0x000007FF;
-}
-
-/**
- * Get the cursor position in x coordinate.
- * @param crt  0 for PANEL, 1 for CRT.
- * @param index  0, 1, 2 or 3 which specifies color of corsor dot.
- */
-static inline uint16_t get_hwc_color(SM501State *state, int crt, int index)
-{
-    uint32_t color_reg = 0;
-    uint16_t color_565 = 0;
-
-    if (index == 0) {
-        return 0;
-    }
-
-    switch (index) {
-    case 1:
-    case 2:
-        color_reg = crt ? state->dc_crt_hwc_color_1_2
-                        : state->dc_panel_hwc_color_1_2;
-        break;
-    case 3:
-        color_reg = crt ? state->dc_crt_hwc_color_3
-                        : state->dc_panel_hwc_color_3;
-        break;
-    default:
-        printf("invalid hw cursor color.\n");
-        abort();
-    }
-
-    switch (index) {
-    case 1:
-    case 3:
-        color_565 = (uint16_t)(color_reg & 0xFFFF);
-        break;
-    case 2:
-        color_565 = (uint16_t)((color_reg >> 16) & 0xFFFF);
-        break;
-    }
-    return color_565;
-}
-
-static int within_hwc_y_range(SM501State *state, int y, int crt)
-{
-    int hwc_y = get_hwc_y(state, crt);
-    return (hwc_y <= y && y < hwc_y + SM501_HWC_HEIGHT);
-}
-
-static void sm501_2d_operation(SM501State * s)
-{
-    /* obtain operation parameters */
-    int operation = (s->twoD_control >> 16) & 0x1f;
-    int rtl = s->twoD_control & 0x8000000;
-    int src_x = (s->twoD_source >> 16) & 0x01FFF;
-    int src_y = s->twoD_source & 0xFFFF;
-    int dst_x = (s->twoD_destination >> 16) & 0x01FFF;
-    int dst_y = s->twoD_destination & 0xFFFF;
-    int operation_width = (s->twoD_dimension >> 16) & 0x1FFF;
-    int operation_height = s->twoD_dimension & 0xFFFF;
-    uint32_t color = s->twoD_foreground;
-    int format_flags = (s->twoD_stretch >> 20) & 0x3;
-    int addressing = (s->twoD_stretch >> 16) & 0xF;
-
-    /* get frame buffer info */
-    uint8_t * src = s->local_mem + (s->twoD_source_base & 0x03FFFFFF);
-    uint8_t * dst = s->local_mem + (s->twoD_destination_base & 0x03FFFFFF);
-    int src_width = (s->dc_crt_h_total & 0x00000FFF) + 1;
-    int dst_width = (s->dc_crt_h_total & 0x00000FFF) + 1;
-
-    if (addressing != 0x0) {
-        printf("%s: only XY addressing is supported.\n", __func__);
-        abort();
-    }
-
-    if ((s->twoD_source_base & 0x08000000) ||
-        (s->twoD_destination_base & 0x08000000)) {
-        printf("%s: only local memory is supported.\n", __func__);
-        abort();
-    }
-
-    switch (operation) {
-    case 0x00: /* copy area */
-#define COPY_AREA(_bpp, _pixel_type, rtl) {                                 \
-        int y, x, index_d, index_s;                                         \
-        for (y = 0; y < operation_height; y++) {                            \
-            for (x = 0; x < operation_width; x++) {                         \
-                if (rtl) {                                                  \
-                    index_s = ((src_y - y) * src_width + src_x - x) * _bpp; \
-                    index_d = ((dst_y - y) * dst_width + dst_x - x) * _bpp; \
-                } else {                                                    \
-                    index_s = ((src_y + y) * src_width + src_x + x) * _bpp; \
-                    index_d = ((dst_y + y) * dst_width + dst_x + x) * _bpp; \
-                }                                                           \
-                *(_pixel_type*)&dst[index_d] = *(_pixel_type*)&src[index_s];\
-            }                                                               \
-        }                                                                   \
-    }
-        switch (format_flags) {
-        case 0:
-            COPY_AREA(1, uint8_t, rtl);
-            break;
-        case 1:
-            COPY_AREA(2, uint16_t, rtl);
-            break;
-        case 2:
-            COPY_AREA(4, uint32_t, rtl);
-            break;
-        }
-        break;
-
-    case 0x01: /* fill rectangle */
-#define FILL_RECT(_bpp, _pixel_type) {                                      \
-        int y, x;                                                           \
-        for (y = 0; y < operation_height; y++) {                            \
-            for (x = 0; x < operation_width; x++) {                         \
-                int index = ((dst_y + y) * dst_width + dst_x + x) * _bpp;   \
-                *(_pixel_type*)&dst[index] = (_pixel_type)color;            \
-            }                                                               \
-        }                                                                   \
-    }
-
-        switch (format_flags) {
-        case 0:
-            FILL_RECT(1, uint8_t);
-            break;
-        case 1:
-            FILL_RECT(2, uint16_t);
-            break;
-        case 2:
-            FILL_RECT(4, uint32_t);
-            break;
-        }
-        break;
-
-    default:
-        printf("non-implemented SM501 2D operation. %d\n", operation);
-        abort();
-        break;
-    }
-}
-
-static uint64_t sm501_system_config_read(void *opaque, hwaddr addr,
-                                         unsigned size)
-{
-    SM501State * s = (SM501State *)opaque;
-    uint32_t ret = 0;
-    SM501_DPRINTF("sm501 system config regs : read addr=%x\n", (int)addr);
-
-    switch(addr) {
-    case SM501_SYSTEM_CONTROL:
-       ret = s->system_control;
-       break;
-    case SM501_MISC_CONTROL:
-       ret = s->misc_control;
-       break;
-    case SM501_GPIO31_0_CONTROL:
-       ret = s->gpio_31_0_control;
-       break;
-    case SM501_GPIO63_32_CONTROL:
-       ret = s->gpio_63_32_control;
-       break;
-    case SM501_DEVICEID:
-       ret = 0x050100A0;
-       break;
-    case SM501_DRAM_CONTROL:
-       ret = (s->dram_control & 0x07F107C0) | s->local_mem_size_index << 13;
-       break;
-    case SM501_IRQ_MASK:
-       ret = s->irq_mask;
-       break;
-    case SM501_MISC_TIMING:
-       /* TODO : simulate gate control */
-       ret = s->misc_timing;
-       break;
-    case SM501_CURRENT_GATE:
-       /* TODO : simulate gate control */
-       ret = 0x00021807;
-       break;
-    case SM501_CURRENT_CLOCK:
-       ret = 0x2A1A0A09;
-       break;
-    case SM501_POWER_MODE_CONTROL:
-       ret = s->power_mode_control;
-       break;
-
-    default:
-       printf("sm501 system config : not implemented register read."
-              " addr=%x\n", (int)addr);
-        abort();
-    }
-
-    return ret;
-}
-
-static void sm501_system_config_write(void *opaque, hwaddr addr,
-                                      uint64_t value, unsigned size)
-{
-    SM501State * s = (SM501State *)opaque;
-    SM501_DPRINTF("sm501 system config regs : write addr=%x, val=%x\n",
-                 (uint32_t)addr, (uint32_t)value);
-
-    switch(addr) {
-    case SM501_SYSTEM_CONTROL:
-       s->system_control = value & 0xE300B8F7;
-       break;
-    case SM501_MISC_CONTROL:
-       s->misc_control = value & 0xFF7FFF20;
-       break;
-    case SM501_GPIO31_0_CONTROL:
-       s->gpio_31_0_control = value;
-       break;
-    case SM501_GPIO63_32_CONTROL:
-       s->gpio_63_32_control = value;
-       break;
-    case SM501_DRAM_CONTROL:
-       s->local_mem_size_index = (value >> 13) & 0x7;
-       /* rODO : check validity of size change */
-       s->dram_control |=  value & 0x7FFFFFC3;
-       break;
-    case SM501_IRQ_MASK:
-       s->irq_mask = value;
-       break;
-    case SM501_MISC_TIMING:
-       s->misc_timing = value & 0xF31F1FFF;
-       break;
-    case SM501_POWER_MODE_0_GATE:
-    case SM501_POWER_MODE_1_GATE:
-    case SM501_POWER_MODE_0_CLOCK:
-    case SM501_POWER_MODE_1_CLOCK:
-       /* TODO : simulate gate & clock control */
-       break;
-    case SM501_POWER_MODE_CONTROL:
-       s->power_mode_control = value & 0x00000003;
-       break;
-
-    default:
-       printf("sm501 system config : not implemented register write."
-              " addr=%x, val=%x\n", (int)addr, (uint32_t)value);
-        abort();
-    }
-}
-
-static const MemoryRegionOps sm501_system_config_ops = {
-    .read = sm501_system_config_read,
-    .write = sm501_system_config_write,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static uint32_t sm501_palette_read(void *opaque, hwaddr addr)
-{
-    SM501State * s = (SM501State *)opaque;
-    SM501_DPRINTF("sm501 palette read addr=%x\n", (int)addr);
-
-    /* TODO : consider BYTE/WORD access */
-    /* TODO : consider endian */
-
-    assert(range_covers_byte(0, 0x400 * 3, addr));
-    return *(uint32_t*)&s->dc_palette[addr];
-}
-
-static void sm501_palette_write(void *opaque,
-                               hwaddr addr, uint32_t value)
-{
-    SM501State * s = (SM501State *)opaque;
-    SM501_DPRINTF("sm501 palette write addr=%x, val=%x\n",
-                 (int)addr, value);
-
-    /* TODO : consider BYTE/WORD access */
-    /* TODO : consider endian */
-
-    assert(range_covers_byte(0, 0x400 * 3, addr));
-    *(uint32_t*)&s->dc_palette[addr] = value;
-}
-
-static uint64_t sm501_disp_ctrl_read(void *opaque, hwaddr addr,
-                                     unsigned size)
-{
-    SM501State * s = (SM501State *)opaque;
-    uint32_t ret = 0;
-    SM501_DPRINTF("sm501 disp ctrl regs : read addr=%x\n", (int)addr);
-
-    switch(addr) {
-
-    case SM501_DC_PANEL_CONTROL:
-       ret = s->dc_panel_control;
-       break;
-    case SM501_DC_PANEL_PANNING_CONTROL:
-       ret = s->dc_panel_panning_control;
-       break;
-    case SM501_DC_PANEL_FB_ADDR:
-       ret = s->dc_panel_fb_addr;
-       break;
-    case SM501_DC_PANEL_FB_OFFSET:
-       ret = s->dc_panel_fb_offset;
-       break;
-    case SM501_DC_PANEL_FB_WIDTH:
-       ret = s->dc_panel_fb_width;
-       break;
-    case SM501_DC_PANEL_FB_HEIGHT:
-       ret = s->dc_panel_fb_height;
-       break;
-    case SM501_DC_PANEL_TL_LOC:
-       ret = s->dc_panel_tl_location;
-       break;
-    case SM501_DC_PANEL_BR_LOC:
-       ret = s->dc_panel_br_location;
-       break;
-
-    case SM501_DC_PANEL_H_TOT:
-       ret = s->dc_panel_h_total;
-       break;
-    case SM501_DC_PANEL_H_SYNC:
-       ret = s->dc_panel_h_sync;
-       break;
-    case SM501_DC_PANEL_V_TOT:
-       ret = s->dc_panel_v_total;
-       break;
-    case SM501_DC_PANEL_V_SYNC:
-       ret = s->dc_panel_v_sync;
-       break;
-
-    case SM501_DC_CRT_CONTROL:
-       ret = s->dc_crt_control;
-       break;
-    case SM501_DC_CRT_FB_ADDR:
-       ret = s->dc_crt_fb_addr;
-       break;
-    case SM501_DC_CRT_FB_OFFSET:
-       ret = s->dc_crt_fb_offset;
-       break;
-    case SM501_DC_CRT_H_TOT:
-       ret = s->dc_crt_h_total;
-       break;
-    case SM501_DC_CRT_H_SYNC:
-       ret = s->dc_crt_h_sync;
-       break;
-    case SM501_DC_CRT_V_TOT:
-       ret = s->dc_crt_v_total;
-       break;
-    case SM501_DC_CRT_V_SYNC:
-       ret = s->dc_crt_v_sync;
-       break;
-
-    case SM501_DC_CRT_HWC_ADDR:
-       ret = s->dc_crt_hwc_addr;
-       break;
-    case SM501_DC_CRT_HWC_LOC:
-       ret = s->dc_crt_hwc_location;
-       break;
-    case SM501_DC_CRT_HWC_COLOR_1_2:
-       ret = s->dc_crt_hwc_color_1_2;
-       break;
-    case SM501_DC_CRT_HWC_COLOR_3:
-       ret = s->dc_crt_hwc_color_3;
-       break;
-
-    case SM501_DC_PANEL_PALETTE ... SM501_DC_PANEL_PALETTE + 0x400*3 - 4:
-        ret = sm501_palette_read(opaque, addr - SM501_DC_PANEL_PALETTE);
-        break;
-
-    default:
-       printf("sm501 disp ctrl : not implemented register read."
-              " addr=%x\n", (int)addr);
-        abort();
-    }
-
-    return ret;
-}
-
-static void sm501_disp_ctrl_write(void *opaque, hwaddr addr,
-                                  uint64_t value, unsigned size)
-{
-    SM501State * s = (SM501State *)opaque;
-    SM501_DPRINTF("sm501 disp ctrl regs : write addr=%x, val=%x\n",
-                 (unsigned)addr, (unsigned)value);
-
-    switch(addr) {
-    case SM501_DC_PANEL_CONTROL:
-       s->dc_panel_control = value & 0x0FFF73FF;
-       break;
-    case SM501_DC_PANEL_PANNING_CONTROL:
-       s->dc_panel_panning_control = value & 0xFF3FFF3F;
-       break;
-    case SM501_DC_PANEL_FB_ADDR:
-       s->dc_panel_fb_addr = value & 0x8FFFFFF0;
-       break;
-    case SM501_DC_PANEL_FB_OFFSET:
-       s->dc_panel_fb_offset = value & 0x3FF03FF0;
-       break;
-    case SM501_DC_PANEL_FB_WIDTH:
-       s->dc_panel_fb_width = value & 0x0FFF0FFF;
-       break;
-    case SM501_DC_PANEL_FB_HEIGHT:
-       s->dc_panel_fb_height = value & 0x0FFF0FFF;
-       break;
-    case SM501_DC_PANEL_TL_LOC:
-       s->dc_panel_tl_location = value & 0x07FF07FF;
-       break;
-    case SM501_DC_PANEL_BR_LOC:
-       s->dc_panel_br_location = value & 0x07FF07FF;
-       break;
-
-    case SM501_DC_PANEL_H_TOT:
-       s->dc_panel_h_total = value & 0x0FFF0FFF;
-       break;
-    case SM501_DC_PANEL_H_SYNC:
-       s->dc_panel_h_sync = value & 0x00FF0FFF;
-       break;
-    case SM501_DC_PANEL_V_TOT:
-       s->dc_panel_v_total = value & 0x0FFF0FFF;
-       break;
-    case SM501_DC_PANEL_V_SYNC:
-       s->dc_panel_v_sync = value & 0x003F0FFF;
-       break;
-
-    case SM501_DC_PANEL_HWC_ADDR:
-       s->dc_panel_hwc_addr = value & 0x8FFFFFF0;
-       break;
-    case SM501_DC_PANEL_HWC_LOC:
-       s->dc_panel_hwc_location = value & 0x0FFF0FFF;
-       break;
-    case SM501_DC_PANEL_HWC_COLOR_1_2:
-       s->dc_panel_hwc_color_1_2 = value;
-       break;
-    case SM501_DC_PANEL_HWC_COLOR_3:
-       s->dc_panel_hwc_color_3 = value & 0x0000FFFF;
-       break;
-
-    case SM501_DC_CRT_CONTROL:
-       s->dc_crt_control = value & 0x0003FFFF;
-       break;
-    case SM501_DC_CRT_FB_ADDR:
-       s->dc_crt_fb_addr = value & 0x8FFFFFF0;
-       break;
-    case SM501_DC_CRT_FB_OFFSET:
-       s->dc_crt_fb_offset = value & 0x3FF03FF0;
-       break;
-    case SM501_DC_CRT_H_TOT:
-       s->dc_crt_h_total = value & 0x0FFF0FFF;
-       break;
-    case SM501_DC_CRT_H_SYNC:
-       s->dc_crt_h_sync = value & 0x00FF0FFF;
-       break;
-    case SM501_DC_CRT_V_TOT:
-       s->dc_crt_v_total = value & 0x0FFF0FFF;
-       break;
-    case SM501_DC_CRT_V_SYNC:
-       s->dc_crt_v_sync = value & 0x003F0FFF;
-       break;
-
-    case SM501_DC_CRT_HWC_ADDR:
-       s->dc_crt_hwc_addr = value & 0x8FFFFFF0;
-       break;
-    case SM501_DC_CRT_HWC_LOC:
-       s->dc_crt_hwc_location = value & 0x0FFF0FFF;
-       break;
-    case SM501_DC_CRT_HWC_COLOR_1_2:
-       s->dc_crt_hwc_color_1_2 = value;
-       break;
-    case SM501_DC_CRT_HWC_COLOR_3:
-       s->dc_crt_hwc_color_3 = value & 0x0000FFFF;
-       break;
-
-    case SM501_DC_PANEL_PALETTE ... SM501_DC_PANEL_PALETTE + 0x400*3 - 4:
-        sm501_palette_write(opaque, addr - SM501_DC_PANEL_PALETTE, value);
-        break;
-
-    default:
-       printf("sm501 disp ctrl : not implemented register write."
-              " addr=%x, val=%x\n", (int)addr, (unsigned)value);
-        abort();
-    }
-}
-
-static const MemoryRegionOps sm501_disp_ctrl_ops = {
-    .read = sm501_disp_ctrl_read,
-    .write = sm501_disp_ctrl_write,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static uint64_t sm501_2d_engine_read(void *opaque, hwaddr addr,
-                                     unsigned size)
-{
-    SM501State * s = (SM501State *)opaque;
-    uint32_t ret = 0;
-    SM501_DPRINTF("sm501 2d engine regs : read addr=%x\n", (int)addr);
-
-    switch(addr) {
-    case SM501_2D_SOURCE_BASE:
-        ret = s->twoD_source_base;
-        break;
-    default:
-        printf("sm501 disp ctrl : not implemented register read."
-               " addr=%x\n", (int)addr);
-        abort();
-    }
-
-    return ret;
-}
-
-static void sm501_2d_engine_write(void *opaque, hwaddr addr,
-                                  uint64_t value, unsigned size)
-{
-    SM501State * s = (SM501State *)opaque;
-    SM501_DPRINTF("sm501 2d engine regs : write addr=%x, val=%x\n",
-                  (unsigned)addr, (unsigned)value);
-
-    switch(addr) {
-    case SM501_2D_SOURCE:
-        s->twoD_source = value;
-        break;
-    case SM501_2D_DESTINATION:
-        s->twoD_destination = value;
-        break;
-    case SM501_2D_DIMENSION:
-        s->twoD_dimension = value;
-        break;
-    case SM501_2D_CONTROL:
-        s->twoD_control = value;
-
-        /* do 2d operation if start flag is set. */
-        if (value & 0x80000000) {
-            sm501_2d_operation(s);
-            s->twoD_control &= ~0x80000000; /* start flag down */
-        }
-
-        break;
-    case SM501_2D_PITCH:
-        s->twoD_pitch = value;
-        break;
-    case SM501_2D_FOREGROUND:
-        s->twoD_foreground = value;
-        break;
-    case SM501_2D_STRETCH:
-        s->twoD_stretch = value;
-        break;
-    case SM501_2D_COLOR_COMPARE_MASK:
-        s->twoD_color_compare_mask = value;
-        break;
-    case SM501_2D_MASK:
-        s->twoD_mask = value;
-        break;
-    case SM501_2D_WINDOW_WIDTH:
-        s->twoD_window_width = value;
-        break;
-    case SM501_2D_SOURCE_BASE:
-        s->twoD_source_base = value;
-        break;
-    case SM501_2D_DESTINATION_BASE:
-        s->twoD_destination_base = value;
-        break;
-    default:
-        printf("sm501 2d engine : not implemented register write."
-               " addr=%x, val=%x\n", (int)addr, (unsigned)value);
-        abort();
-    }
-}
-
-static const MemoryRegionOps sm501_2d_engine_ops = {
-    .read = sm501_2d_engine_read,
-    .write = sm501_2d_engine_write,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-/* draw line functions for all console modes */
-
-typedef void draw_line_func(uint8_t *d, const uint8_t *s,
-                           int width, const uint32_t *pal);
-
-typedef void draw_hwc_line_func(SM501State * s, int crt, uint8_t * palette,
-                                int c_y, uint8_t *d, int width);
-
-#define DEPTH 8
-#include "hw/sm501_template.h"
-
-#define DEPTH 15
-#include "hw/sm501_template.h"
-
-#define BGR_FORMAT
-#define DEPTH 15
-#include "hw/sm501_template.h"
-
-#define DEPTH 16
-#include "hw/sm501_template.h"
-
-#define BGR_FORMAT
-#define DEPTH 16
-#include "hw/sm501_template.h"
-
-#define DEPTH 32
-#include "hw/sm501_template.h"
-
-#define BGR_FORMAT
-#define DEPTH 32
-#include "hw/sm501_template.h"
-
-static draw_line_func * draw_line8_funcs[] = {
-    draw_line8_8,
-    draw_line8_15,
-    draw_line8_16,
-    draw_line8_32,
-    draw_line8_32bgr,
-    draw_line8_15bgr,
-    draw_line8_16bgr,
-};
-
-static draw_line_func * draw_line16_funcs[] = {
-    draw_line16_8,
-    draw_line16_15,
-    draw_line16_16,
-    draw_line16_32,
-    draw_line16_32bgr,
-    draw_line16_15bgr,
-    draw_line16_16bgr,
-};
-
-static draw_line_func * draw_line32_funcs[] = {
-    draw_line32_8,
-    draw_line32_15,
-    draw_line32_16,
-    draw_line32_32,
-    draw_line32_32bgr,
-    draw_line32_15bgr,
-    draw_line32_16bgr,
-};
-
-static draw_hwc_line_func * draw_hwc_line_funcs[] = {
-    draw_hwc_line_8,
-    draw_hwc_line_15,
-    draw_hwc_line_16,
-    draw_hwc_line_32,
-    draw_hwc_line_32bgr,
-    draw_hwc_line_15bgr,
-    draw_hwc_line_16bgr,
-};
-
-static inline int get_depth_index(DisplaySurface *surface)
-{
-    switch (surface_bits_per_pixel(surface)) {
-    default:
-    case 8:
-       return 0;
-    case 15:
-        return 1;
-    case 16:
-        return 2;
-    case 32:
-        if (is_surface_bgr(surface)) {
-            return 4;
-        } else {
-            return 3;
-        }
-    }
-}
-
-static void sm501_draw_crt(SM501State * s)
-{
-    DisplaySurface *surface = qemu_console_surface(s->con);
-    int y;
-    int width = (s->dc_crt_h_total & 0x00000FFF) + 1;
-    int height = (s->dc_crt_v_total & 0x00000FFF) + 1;
-
-    uint8_t  * src = s->local_mem;
-    int src_bpp = 0;
-    int dst_bpp = surface_bytes_per_pixel(surface);
-    uint32_t * palette = (uint32_t *)&s->dc_palette[SM501_DC_CRT_PALETTE
-                                                   - SM501_DC_PANEL_PALETTE];
-    uint8_t hwc_palette[3 * 3];
-    int ds_depth_index = get_depth_index(surface);
-    draw_line_func * draw_line = NULL;
-    draw_hwc_line_func * draw_hwc_line = NULL;
-    int full_update = 0;
-    int y_start = -1;
-    ram_addr_t page_min = ~0l;
-    ram_addr_t page_max = 0l;
-    ram_addr_t offset = 0;
-
-    /* choose draw_line function */
-    switch (s->dc_crt_control & 3) {
-    case SM501_DC_CRT_CONTROL_8BPP:
-       src_bpp = 1;
-       draw_line = draw_line8_funcs[ds_depth_index];
-       break;
-    case SM501_DC_CRT_CONTROL_16BPP:
-       src_bpp = 2;
-       draw_line = draw_line16_funcs[ds_depth_index];
-       break;
-    case SM501_DC_CRT_CONTROL_32BPP:
-       src_bpp = 4;
-       draw_line = draw_line32_funcs[ds_depth_index];
-       break;
-    default:
-       printf("sm501 draw crt : invalid DC_CRT_CONTROL=%x.\n",
-              s->dc_crt_control);
-        abort();
-       break;
-    }
-
-    /* set up to draw hardware cursor */
-    if (is_hwc_enabled(s, 1)) {
-        int i;
-
-        /* get cursor palette */
-        for (i = 0; i < 3; i++) {
-            uint16_t rgb565 = get_hwc_color(s, 1, i + 1);
-            hwc_palette[i * 3 + 0] = (rgb565 & 0xf800) >> 8; /* red */
-            hwc_palette[i * 3 + 1] = (rgb565 & 0x07e0) >> 3; /* green */
-            hwc_palette[i * 3 + 2] = (rgb565 & 0x001f) << 3; /* blue */
-        }
-
-        /* choose cursor draw line function */
-        draw_hwc_line = draw_hwc_line_funcs[ds_depth_index];
-    }
-
-    /* adjust console size */
-    if (s->last_width != width || s->last_height != height) {
-        qemu_console_resize(s->con, width, height);
-        surface = qemu_console_surface(s->con);
-       s->last_width = width;
-       s->last_height = height;
-       full_update = 1;
-    }
-
-    /* draw each line according to conditions */
-    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;
-        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 - page0, DIRTY_MEMORY_VGA);
-
-       /* draw line and change status */
-       if (update) {
-            uint8_t *d = surface_data(surface);
-            d +=  y * width * dst_bpp;
-
-            /* draw graphics layer */
-            draw_line(d, src, width, palette);
-
-            /* draw haredware cursor */
-            if (update_hwc) {
-                draw_hwc_line(s, 1, hwc_palette, y - get_hwc_y(s, 1), d, width);
-            }
-
-           if (y_start < 0)
-               y_start = y;
-           if (page0 < page_min)
-               page_min = page0;
-           if (page1 > page_max)
-               page_max = page1;
-       } else {
-           if (y_start >= 0) {
-               /* flush to display */
-                dpy_gfx_update(s->con, 0, y_start, width, y - y_start);
-               y_start = -1;
-           }
-       }
-
-       src += width * src_bpp;
-       offset += width * src_bpp;
-    }
-
-    /* complete flush to display */
-    if (y_start >= 0)
-        dpy_gfx_update(s->con, 0, y_start, width, y - y_start);
-
-    /* clear dirty flags */
-    if (page_min != ~0l) {
-       memory_region_reset_dirty(&s->local_mem_region,
-                                  page_min, page_max + TARGET_PAGE_SIZE,
-                                  DIRTY_MEMORY_VGA);
-    }
-}
-
-static void sm501_update_display(void *opaque)
-{
-    SM501State * s = (SM501State *)opaque;
-
-    if (s->dc_crt_control & SM501_DC_CRT_CONTROL_ENABLE)
-       sm501_draw_crt(s);
-}
-
-void sm501_init(MemoryRegion *address_space_mem, uint32_t base,
-                uint32_t local_mem_bytes, qemu_irq irq, CharDriverState *chr)
-{
-    SM501State * s;
-    DeviceState *dev;
-    MemoryRegion *sm501_system_config = g_new(MemoryRegion, 1);
-    MemoryRegion *sm501_disp_ctrl = g_new(MemoryRegion, 1);
-    MemoryRegion *sm501_2d_engine = g_new(MemoryRegion, 1);
-
-    /* allocate management data region */
-    s = (SM501State *)g_malloc0(sizeof(SM501State));
-    s->base = base;
-    s->local_mem_size_index
-       = get_local_mem_size_index(local_mem_bytes);
-    SM501_DPRINTF("local mem size=%x. index=%d\n", get_local_mem_size(s),
-                 s->local_mem_size_index);
-    s->system_control = 0x00100000;
-    s->misc_control = 0x00001000; /* assumes SH, active=low */
-    s->dc_panel_control = 0x00010000;
-    s->dc_crt_control = 0x00010000;
-
-    /* allocate local memory */
-    memory_region_init_ram(&s->local_mem_region, "sm501.local",
-                           local_mem_bytes);
-    vmstate_register_ram_global(&s->local_mem_region);
-    s->local_mem = memory_region_get_ram_ptr(&s->local_mem_region);
-    memory_region_add_subregion(address_space_mem, base, &s->local_mem_region);
-
-    /* map mmio */
-    memory_region_init_io(sm501_system_config, &sm501_system_config_ops, s,
-                          "sm501-system-config", 0x6c);
-    memory_region_add_subregion(address_space_mem, base + MMIO_BASE_OFFSET,
-                                sm501_system_config);
-    memory_region_init_io(sm501_disp_ctrl, &sm501_disp_ctrl_ops, s,
-                          "sm501-disp-ctrl", 0x1000);
-    memory_region_add_subregion(address_space_mem,
-                                base + MMIO_BASE_OFFSET + SM501_DC,
-                                sm501_disp_ctrl);
-    memory_region_init_io(sm501_2d_engine, &sm501_2d_engine_ops, s,
-                          "sm501-2d-engine", 0x54);
-    memory_region_add_subregion(address_space_mem,
-                                base + MMIO_BASE_OFFSET + SM501_2D_ENGINE,
-                                sm501_2d_engine);
-
-    /* bridge to usb host emulation module */
-    dev = qdev_create(NULL, "sysbus-ohci");
-    qdev_prop_set_uint32(dev, "num-ports", 2);
-    qdev_prop_set_taddr(dev, "dma-offset", base);
-    qdev_init_nofail(dev);
-    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0,
-                    base + MMIO_BASE_OFFSET + SM501_USB_HOST);
-    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq);
-
-    /* bridge to serial emulation module */
-    if (chr) {
-        serial_mm_init(address_space_mem,
-                       base + MMIO_BASE_OFFSET + SM501_UART0, 2,
-                       NULL, /* TODO : chain irq to IRL */
-                       115200, chr, DEVICE_NATIVE_ENDIAN);
-    }
-
-    /* create qemu graphic console */
-    s->con = graphic_console_init(sm501_update_display, NULL,
-                                  NULL, NULL, s);
-}
diff --git a/hw/sm501_template.h b/hw/sm501_template.h
deleted file mode 100644 (file)
index 2d4a3d8..0000000
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Pixel drawing function templates for QEMU SM501 Device
- *
- * Copyright (c) 2008 Shin-ichiro KAWASAKI
- *
- * 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
-#define PIXEL_TYPE uint8_t
-#elif DEPTH == 15 || DEPTH == 16
-#define BPP 2
-#define PIXEL_TYPE uint16_t
-#elif DEPTH == 32
-#define BPP 4
-#define PIXEL_TYPE uint32_t
-#else
-#error unsupport depth
-#endif
-
-#ifdef BGR_FORMAT
-#define PIXEL_NAME glue(DEPTH, bgr)
-#else
-#define PIXEL_NAME DEPTH
-#endif /* BGR_FORMAT */
-
-
-static void glue(draw_line8_, PIXEL_NAME)(
-                 uint8_t *d, const uint8_t *s, int width, const uint32_t *pal)
-{
-    uint8_t v, r, g, b;
-    do {
-       v = ldub_raw(s);
-       r = (pal[v] >> 16) & 0xff;
-       g = (pal[v] >>  8) & 0xff;
-       b = (pal[v] >>  0) & 0xff;
-       ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b);
-       s ++;
-       d += BPP;
-    } while (-- width != 0);
-}
-
-static void glue(draw_line16_, PIXEL_NAME)(
-                uint8_t *d, const uint8_t *s, int width, const uint32_t *pal)
-{
-    uint16_t rgb565;
-    uint8_t r, g, b;
-
-    do {
-       rgb565 = lduw_raw(s);
-       r = ((rgb565 >> 11) & 0x1f) << 3;
-       g = ((rgb565 >>  5) & 0x3f) << 2;
-       b = ((rgb565 >>  0) & 0x1f) << 3;
-       ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b);
-       s += 2;
-       d += BPP;
-    } while (-- width != 0);
-}
-
-static void glue(draw_line32_, PIXEL_NAME)(
-                uint8_t *d, const uint8_t *s, int width, const uint32_t *pal)
-{
-    uint8_t r, g, b;
-
-    do {
-       ldub_raw(s);
-#if defined(TARGET_WORDS_BIGENDIAN)
-        r = s[1];
-        g = s[2];
-        b = s[3];
-#else
-        b = s[0];
-        g = s[1];
-        r = s[2];
-#endif
-       ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b);
-       s += 4;
-       d += BPP;
-    } while (-- width != 0);
-}
-
-/**
- * Draw hardware cursor image on the given line.
- */
-static void glue(draw_hwc_line_, PIXEL_NAME)(SM501State * s, int crt,
-                         uint8_t * palette, int c_y, uint8_t *d, int width)
-{
-    int x, i;
-    uint8_t bitset = 0;
-
-    /* get hardware cursor pattern */
-    uint32_t cursor_addr = get_hwc_address(s, crt);
-    assert(0 <= c_y && c_y < SM501_HWC_HEIGHT);
-    cursor_addr += 64 * c_y / 4;  /* 4 pixels per byte */
-    cursor_addr += s->base;
-
-    /* get cursor position */
-    x = get_hwc_x(s, crt);
-    d += x * BPP;
-
-    for (i = 0; i < SM501_HWC_WIDTH && x + i < width; i++) {
-        uint8_t v;
-
-        /* get pixel value */
-        if (i % 4 == 0) {
-            bitset = ldub_phys(cursor_addr);
-            cursor_addr++;
-        }
-        v = bitset & 3;
-        bitset >>= 2;
-
-        /* write pixel */
-        if (v) {
-            v--;
-            uint8_t r = palette[v * 3 + 0];
-            uint8_t g = palette[v * 3 + 1];
-            uint8_t b = palette[v * 3 + 2];
-            ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b);
-        }
-        d += BPP;
-    }
-}
-
-#undef DEPTH
-#undef BPP
-#undef PIXEL_TYPE
-#undef PIXEL_NAME
-#undef BGR_FORMAT
diff --git a/hw/smbios.h b/hw/smbios.h
deleted file mode 100644 (file)
index 94e3641..0000000
+++ /dev/null
@@ -1,162 +0,0 @@
-#ifndef QEMU_SMBIOS_H
-#define QEMU_SMBIOS_H
-/*
- * SMBIOS Support
- *
- * Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
- *
- * Authors:
- *  Alex Williamson <alex.williamson@hp.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2.  See
- * the COPYING file in the top-level directory.
- *
- */
-
-int smbios_entry_add(const char *t);
-void smbios_add_field(int type, int offset, int len, void *data);
-uint8_t *smbios_get_table(size_t *length);
-
-/*
- * SMBIOS spec defined tables
- */
-
-/* This goes at the beginning of every SMBIOS structure. */
-struct smbios_structure_header {
-    uint8_t type;
-    uint8_t length;
-    uint16_t handle;
-} QEMU_PACKED;
-
-/* SMBIOS type 0 - BIOS Information */
-struct smbios_type_0 {
-    struct smbios_structure_header header;
-    uint8_t vendor_str;
-    uint8_t bios_version_str;
-    uint16_t bios_starting_address_segment;
-    uint8_t bios_release_date_str;
-    uint8_t bios_rom_size;
-    uint8_t bios_characteristics[8];
-    uint8_t bios_characteristics_extension_bytes[2];
-    uint8_t system_bios_major_release;
-    uint8_t system_bios_minor_release;
-    uint8_t embedded_controller_major_release;
-    uint8_t embedded_controller_minor_release;
-} QEMU_PACKED;
-
-/* SMBIOS type 1 - System Information */
-struct smbios_type_1 {
-    struct smbios_structure_header header;
-    uint8_t manufacturer_str;
-    uint8_t product_name_str;
-    uint8_t version_str;
-    uint8_t serial_number_str;
-    uint8_t uuid[16];
-    uint8_t wake_up_type;
-    uint8_t sku_number_str;
-    uint8_t family_str;
-} QEMU_PACKED;
-
-/* SMBIOS type 3 - System Enclosure (v2.3) */
-struct smbios_type_3 {
-    struct smbios_structure_header header;
-    uint8_t manufacturer_str;
-    uint8_t type;
-    uint8_t version_str;
-    uint8_t serial_number_str;
-    uint8_t asset_tag_number_str;
-    uint8_t boot_up_state;
-    uint8_t power_supply_state;
-    uint8_t thermal_state;
-    uint8_t security_status;
-    uint32_t oem_defined;
-    uint8_t height;
-    uint8_t number_of_power_cords;
-    uint8_t contained_element_count;
-    // contained elements follow
-} QEMU_PACKED;
-
-/* SMBIOS type 4 - Processor Information (v2.0) */
-struct smbios_type_4 {
-    struct smbios_structure_header header;
-    uint8_t socket_designation_str;
-    uint8_t processor_type;
-    uint8_t processor_family;
-    uint8_t processor_manufacturer_str;
-    uint32_t processor_id[2];
-    uint8_t processor_version_str;
-    uint8_t voltage;
-    uint16_t external_clock;
-    uint16_t max_speed;
-    uint16_t current_speed;
-    uint8_t status;
-    uint8_t processor_upgrade;
-    uint16_t l1_cache_handle;
-    uint16_t l2_cache_handle;
-    uint16_t l3_cache_handle;
-} QEMU_PACKED;
-
-/* SMBIOS type 16 - Physical Memory Array
- *   Associated with one type 17 (Memory Device).
- */
-struct smbios_type_16 {
-    struct smbios_structure_header header;
-    uint8_t location;
-    uint8_t use;
-    uint8_t error_correction;
-    uint32_t maximum_capacity;
-    uint16_t memory_error_information_handle;
-    uint16_t number_of_memory_devices;
-} QEMU_PACKED;
-/* SMBIOS type 17 - Memory Device
- *   Associated with one type 19
- */
-struct smbios_type_17 {
-    struct smbios_structure_header header;
-    uint16_t physical_memory_array_handle;
-    uint16_t memory_error_information_handle;
-    uint16_t total_width;
-    uint16_t data_width;
-    uint16_t size;
-    uint8_t form_factor;
-    uint8_t device_set;
-    uint8_t device_locator_str;
-    uint8_t bank_locator_str;
-    uint8_t memory_type;
-    uint16_t type_detail;
-} QEMU_PACKED;
-
-/* SMBIOS type 19 - Memory Array Mapped Address */
-struct smbios_type_19 {
-    struct smbios_structure_header header;
-    uint32_t starting_address;
-    uint32_t ending_address;
-    uint16_t memory_array_handle;
-    uint8_t partition_width;
-} QEMU_PACKED;
-
-/* SMBIOS type 20 - Memory Device Mapped Address */
-struct smbios_type_20 {
-    struct smbios_structure_header header;
-    uint32_t starting_address;
-    uint32_t ending_address;
-    uint16_t memory_device_handle;
-    uint16_t memory_array_mapped_address_handle;
-    uint8_t partition_row_position;
-    uint8_t interleave_position;
-    uint8_t interleaved_data_depth;
-} QEMU_PACKED;
-
-/* SMBIOS type 32 - System Boot Information */
-struct smbios_type_32 {
-    struct smbios_structure_header header;
-    uint8_t reserved[6];
-    uint8_t boot_status;
-} QEMU_PACKED;
-
-/* SMBIOS type 127 -- End-of-table */
-struct smbios_type_127 {
-    struct smbios_structure_header header;
-} QEMU_PACKED;
-
-#endif /*QEMU_SMBIOS_H */
diff --git a/hw/smbus.c b/hw/smbus.c
deleted file mode 100644 (file)
index 9626415..0000000
+++ /dev/null
@@ -1,335 +0,0 @@
-/*
- * QEMU SMBus device emulation.
- *
- * Copyright (c) 2007 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the LGPL.
- */
-
-/* TODO: Implement PEC.  */
-
-#include "hw/hw.h"
-#include "hw/i2c.h"
-#include "hw/smbus.h"
-
-//#define DEBUG_SMBUS 1
-
-#ifdef DEBUG_SMBUS
-#define DPRINTF(fmt, ...) \
-do { printf("smbus(%02x): " fmt , dev->i2c.address, ## __VA_ARGS__); } while (0)
-#define BADF(fmt, ...) \
-do { fprintf(stderr, "smbus: error: " fmt , ## __VA_ARGS__); exit(1);} while (0)
-#else
-#define DPRINTF(fmt, ...) do {} while(0)
-#define BADF(fmt, ...) \
-do { fprintf(stderr, "smbus: error: " fmt , ## __VA_ARGS__);} while (0)
-#endif
-
-enum {
-    SMBUS_IDLE,
-    SMBUS_WRITE_DATA,
-    SMBUS_RECV_BYTE,
-    SMBUS_READ_DATA,
-    SMBUS_DONE,
-    SMBUS_CONFUSED = -1
-};
-
-static void smbus_do_quick_cmd(SMBusDevice *dev, int recv)
-{
-    SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev);
-
-    DPRINTF("Quick Command %d\n", recv);
-    if (sc->quick_cmd) {
-        sc->quick_cmd(dev, recv);
-    }
-}
-
-static void smbus_do_write(SMBusDevice *dev)
-{
-    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 (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 (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 = SMBUS_DEVICE(s);
-
-    switch (event) {
-    case I2C_START_SEND:
-        switch (dev->mode) {
-        case SMBUS_IDLE:
-            DPRINTF("Incoming data\n");
-            dev->mode = SMBUS_WRITE_DATA;
-            break;
-        default:
-            BADF("Unexpected send start condition in state %d\n", dev->mode);
-            dev->mode = SMBUS_CONFUSED;
-            break;
-        }
-        break;
-
-    case I2C_START_RECV:
-        switch (dev->mode) {
-        case SMBUS_IDLE:
-            DPRINTF("Read mode\n");
-            dev->mode = SMBUS_RECV_BYTE;
-            break;
-        case SMBUS_WRITE_DATA:
-            if (dev->data_len == 0) {
-                BADF("Read after write with no data\n");
-                dev->mode = SMBUS_CONFUSED;
-            } else {
-                if (dev->data_len > 1) {
-                    smbus_do_write(dev);
-                } else {
-                    dev->command = dev->data_buf[0];
-                    DPRINTF("%02x: Command %d\n", dev->i2c.address,
-                            dev->command);
-                }
-                DPRINTF("Read mode\n");
-                dev->data_len = 0;
-                dev->mode = SMBUS_READ_DATA;
-            }
-            break;
-        default:
-            BADF("Unexpected recv start condition in state %d\n", dev->mode);
-            dev->mode = SMBUS_CONFUSED;
-            break;
-        }
-        break;
-
-    case I2C_FINISH:
-        switch (dev->mode) {
-        case SMBUS_WRITE_DATA:
-            smbus_do_write(dev);
-            break;
-        case SMBUS_RECV_BYTE:
-            smbus_do_quick_cmd(dev, 1);
-            break;
-        case SMBUS_READ_DATA:
-            BADF("Unexpected stop during receive\n");
-            break;
-        default:
-            /* Nothing to do.  */
-            break;
-        }
-        dev->mode = SMBUS_IDLE;
-        dev->data_len = 0;
-        break;
-
-    case I2C_NACK:
-        switch (dev->mode) {
-        case SMBUS_DONE:
-            /* Nothing to do.  */
-            break;
-        case SMBUS_READ_DATA:
-            dev->mode = SMBUS_DONE;
-            break;
-        default:
-            BADF("Unexpected NACK in state %d\n", dev->mode);
-            dev->mode = SMBUS_CONFUSED;
-            break;
-        }
-    }
-}
-
-static int smbus_i2c_recv(I2CSlave *s)
-{
-    SMBusDevice *dev = SMBUS_DEVICE(s);
-    SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev);
-    int ret;
-
-    switch (dev->mode) {
-    case SMBUS_RECV_BYTE:
-        if (sc->receive_byte) {
-            ret = sc->receive_byte(dev);
-        } else {
-            ret = 0;
-        }
-        DPRINTF("Receive Byte %02x\n", ret);
-        dev->mode = SMBUS_DONE;
-        break;
-    case SMBUS_READ_DATA:
-        if (sc->read_data) {
-            ret = sc->read_data(dev, dev->command, dev->data_len);
-            dev->data_len++;
-        } else {
-            ret = 0;
-        }
-        DPRINTF("Read data %02x\n", ret);
-        break;
-    default:
-        BADF("Unexpected read in state %d\n", dev->mode);
-        dev->mode = SMBUS_CONFUSED;
-        ret = 0;
-        break;
-    }
-    return ret;
-}
-
-static int smbus_i2c_send(I2CSlave *s, uint8_t data)
-{
-    SMBusDevice *dev = SMBUS_DEVICE(s);
-
-    switch (dev->mode) {
-    case SMBUS_WRITE_DATA:
-        DPRINTF("Write data %02x\n", data);
-        dev->data_buf[dev->data_len++] = data;
-        break;
-    default:
-        BADF("Unexpected write in state %d\n", dev->mode);
-        break;
-    }
-    return 0;
-}
-
-static int smbus_device_init(I2CSlave *i2c)
-{
-    SMBusDevice *dev = SMBUS_DEVICE(i2c);
-    SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev);
-
-    return sc->init(dev);
-}
-
-/* Master device commands.  */
-void smbus_quick_command(i2c_bus *bus, uint8_t addr, int read)
-{
-    i2c_start_transfer(bus, addr, read);
-    i2c_end_transfer(bus);
-}
-
-uint8_t smbus_receive_byte(i2c_bus *bus, uint8_t addr)
-{
-    uint8_t data;
-
-    i2c_start_transfer(bus, addr, 1);
-    data = i2c_recv(bus);
-    i2c_nack(bus);
-    i2c_end_transfer(bus);
-    return data;
-}
-
-void smbus_send_byte(i2c_bus *bus, uint8_t addr, uint8_t data)
-{
-    i2c_start_transfer(bus, addr, 0);
-    i2c_send(bus, data);
-    i2c_end_transfer(bus);
-}
-
-uint8_t smbus_read_byte(i2c_bus *bus, uint8_t addr, uint8_t command)
-{
-    uint8_t data;
-    i2c_start_transfer(bus, addr, 0);
-    i2c_send(bus, command);
-    i2c_start_transfer(bus, addr, 1);
-    data = i2c_recv(bus);
-    i2c_nack(bus);
-    i2c_end_transfer(bus);
-    return data;
-}
-
-void smbus_write_byte(i2c_bus *bus, uint8_t addr, uint8_t command, uint8_t data)
-{
-    i2c_start_transfer(bus, addr, 0);
-    i2c_send(bus, command);
-    i2c_send(bus, data);
-    i2c_end_transfer(bus);
-}
-
-uint16_t smbus_read_word(i2c_bus *bus, uint8_t addr, uint8_t command)
-{
-    uint16_t data;
-    i2c_start_transfer(bus, addr, 0);
-    i2c_send(bus, command);
-    i2c_start_transfer(bus, addr, 1);
-    data = i2c_recv(bus);
-    data |= i2c_recv(bus) << 8;
-    i2c_nack(bus);
-    i2c_end_transfer(bus);
-    return data;
-}
-
-void smbus_write_word(i2c_bus *bus, uint8_t addr, uint8_t command, uint16_t data)
-{
-    i2c_start_transfer(bus, addr, 0);
-    i2c_send(bus, command);
-    i2c_send(bus, data & 0xff);
-    i2c_send(bus, data >> 8);
-    i2c_end_transfer(bus);
-}
-
-int smbus_read_block(i2c_bus *bus, uint8_t addr, uint8_t command, uint8_t *data)
-{
-    int len;
-    int i;
-
-    i2c_start_transfer(bus, addr, 0);
-    i2c_send(bus, command);
-    i2c_start_transfer(bus, addr, 1);
-    len = i2c_recv(bus);
-    if (len > 32)
-        len = 0;
-    for (i = 0; i < len; i++)
-        data[i] = i2c_recv(bus);
-    i2c_nack(bus);
-    i2c_end_transfer(bus);
-    return len;
-}
-
-void smbus_write_block(i2c_bus *bus, uint8_t addr, uint8_t command, uint8_t *data,
-                       int len)
-{
-    int i;
-
-    if (len > 32)
-        len = 32;
-
-    i2c_start_transfer(bus, addr, 0);
-    i2c_send(bus, command);
-    i2c_send(bus, len);
-    for (i = 0; i < len; i++)
-        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 const 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_types(void)
-{
-    type_register_static(&smbus_device_type_info);
-}
-
-type_init(smbus_device_register_types)
diff --git a/hw/smbus.h b/hw/smbus.h
deleted file mode 100644 (file)
index c3db620..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-#ifndef QEMU_SMBUS_H
-#define QEMU_SMBUS_H
-
-/*
- * QEMU SMBus API
- *
- * Copyright (c) 2007 Arastra, 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 "hw/i2c.h"
-
-#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 SMBusDeviceClass
-{
-    I2CSlaveClass parent_class;
-    int (*init)(SMBusDevice *dev);
-    void (*quick_cmd)(SMBusDevice *dev, uint8_t read);
-    void (*send_byte)(SMBusDevice *dev, uint8_t val);
-    uint8_t (*receive_byte)(SMBusDevice *dev);
-    /* We can't distinguish between a word write and a block write with
-       length 1, so pass the whole data block including the length byte
-       (if present).  The device is responsible figuring out what type of
-       command  this is.  */
-    void (*write_data)(SMBusDevice *dev, uint8_t cmd, uint8_t *buf, int len);
-    /* Likewise we can't distinguish between different reads, or even know
-       the length of the read until the read is complete, so read data a
-       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);
-} SMBusDeviceClass;
-
-struct SMBusDevice {
-    /* The SMBus protocol is implemented on top of I2C.  */
-    I2CSlave i2c;
-
-    /* Remaining fields for internal use only.  */
-    int mode;
-    int data_len;
-    uint8_t data_buf[34]; /* command + len + 32 bytes of data.  */
-    uint8_t command;
-};
-
-/* Master device commands.  */
-void smbus_quick_command(i2c_bus *bus, uint8_t addr, int read);
-uint8_t smbus_receive_byte(i2c_bus *bus, uint8_t addr);
-void smbus_send_byte(i2c_bus *bus, uint8_t addr, uint8_t data);
-uint8_t smbus_read_byte(i2c_bus *bus, uint8_t addr, uint8_t command);
-void smbus_write_byte(i2c_bus *bus, uint8_t addr, uint8_t command, uint8_t data);
-uint16_t smbus_read_word(i2c_bus *bus, uint8_t addr, uint8_t command);
-void smbus_write_word(i2c_bus *bus, uint8_t addr, uint8_t command, uint16_t data);
-int smbus_read_block(i2c_bus *bus, uint8_t addr, uint8_t command, uint8_t *data);
-void smbus_write_block(i2c_bus *bus, uint8_t addr, uint8_t command, uint8_t *data,
-                       int len);
-
-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
deleted file mode 100644 (file)
index dff8403..0000000
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * QEMU SMBus EEPROM device
- *
- * Copyright (c) 2007 Arastra, 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 "hw/hw.h"
-#include "hw/i2c.h"
-#include "hw/smbus.h"
-
-//#define DEBUG
-
-typedef struct SMBusEEPROMDevice {
-    SMBusDevice smbusdev;
-    void *data;
-    uint8_t offset;
-} SMBusEEPROMDevice;
-
-static void eeprom_quick_cmd(SMBusDevice *dev, uint8_t read)
-{
-#ifdef DEBUG
-    printf("eeprom_quick_cmd: addr=0x%02x read=%d\n", dev->i2c.address, read);
-#endif
-}
-
-static void eeprom_send_byte(SMBusDevice *dev, uint8_t val)
-{
-    SMBusEEPROMDevice *eeprom = (SMBusEEPROMDevice *) dev;
-#ifdef DEBUG
-    printf("eeprom_send_byte: addr=0x%02x val=0x%02x\n",
-           dev->i2c.address, val);
-#endif
-    eeprom->offset = val;
-}
-
-static uint8_t eeprom_receive_byte(SMBusDevice *dev)
-{
-    SMBusEEPROMDevice *eeprom = (SMBusEEPROMDevice *) dev;
-    uint8_t *data = eeprom->data;
-    uint8_t val = data[eeprom->offset++];
-#ifdef DEBUG
-    printf("eeprom_receive_byte: addr=0x%02x val=0x%02x\n",
-           dev->i2c.address, val);
-#endif
-    return val;
-}
-
-static void eeprom_write_data(SMBusDevice *dev, uint8_t cmd, uint8_t *buf, int len)
-{
-    SMBusEEPROMDevice *eeprom = (SMBusEEPROMDevice *) dev;
-    int n;
-#ifdef DEBUG
-    printf("eeprom_write_byte: addr=0x%02x cmd=0x%02x val=0x%02x\n",
-           dev->i2c.address, cmd, buf[0]);
-#endif
-    /* An page write operation is not a valid SMBus command.
-       It is a block write without a length byte.  Fortunately we
-       get the full block anyway.  */
-    /* TODO: Should this set the current location?  */
-    if (cmd + len > 256)
-        n = 256 - cmd;
-    else
-        n = len;
-    memcpy(eeprom->data + cmd, buf, n);
-    len -= n;
-    if (len)
-        memcpy(eeprom->data, buf + n, len);
-}
-
-static uint8_t eeprom_read_data(SMBusDevice *dev, uint8_t cmd, int n)
-{
-    SMBusEEPROMDevice *eeprom = (SMBusEEPROMDevice *) dev;
-    /* If this is the first byte then set the current position.  */
-    if (n == 0)
-        eeprom->offset = cmd;
-    /* As with writes, we implement block reads without the
-       SMBus length byte.  */
-    return eeprom_receive_byte(dev);
-}
-
-static int smbus_eeprom_initfn(SMBusDevice *dev)
-{
-    SMBusEEPROMDevice *eeprom = (SMBusEEPROMDevice *)dev;
-
-    eeprom->offset = 0;
-    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;
-    sc->quick_cmd = eeprom_quick_cmd;
-    sc->send_byte = eeprom_send_byte;
-    sc->receive_byte = eeprom_receive_byte;
-    sc->write_data = eeprom_write_data;
-    sc->read_data = eeprom_read_data;
-    dc->props = smbus_eeprom_properties;
-}
-
-static const 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_types(void)
-{
-    type_register_static(&smbus_eeprom_info);
-}
-
-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)
-{
-    int i;
-    uint8_t *eeprom_buf = g_malloc0(8 * 256); /* XXX: make this persistent */
-    if (eeprom_spd_size > 0) {
-        memcpy(eeprom_buf, eeprom_spd, eeprom_spd_size);
-    }
-
-    for (i = 0; i < nb_eeprom; i++) {
-        DeviceState *eeprom;
-        eeprom = qdev_create((BusState *)smbus, "smbus-eeprom");
-        qdev_prop_set_uint8(eeprom, "address", 0x50 + i);
-        qdev_prop_set_ptr(eeprom, "data", eeprom_buf + (i * 256));
-        qdev_init_nofail(eeprom);
-    }
-}
diff --git a/hw/smbus_ich9.c b/hw/smbus_ich9.c
deleted file mode 100644 (file)
index 732ebd3..0000000
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * ACPI implementation
- *
- * Copyright (c) 2006 Fabrice Bellard
- * Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp>
- *               VA Linux Systems Japan K.K.
- * Copyright (C) 2012 Jason Baron <jbaron@redhat.com>
- *
- * This is based on acpi.c, but heavily rewritten.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License version 2 as published by the Free Software Foundation.
- *
- * 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/>
- *
- * 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/hw.h"
-#include "hw/pc.h"
-#include "hw/pm_smbus.h"
-#include "hw/pci/pci.h"
-#include "sysemu/sysemu.h"
-#include "hw/i2c.h"
-#include "hw/smbus.h"
-
-#include "hw/ich9.h"
-
-#define TYPE_ICH9_SMB_DEVICE "ICH9 SMB"
-#define ICH9_SMB_DEVICE(obj) \
-     OBJECT_CHECK(ICH9SMBState, (obj), TYPE_ICH9_SMB_DEVICE)
-
-typedef struct ICH9SMBState {
-    PCIDevice dev;
-
-    PMSMBus smb;
-} ICH9SMBState;
-
-static const VMStateDescription vmstate_ich9_smbus = {
-    .name = "ich9_smb",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_PCI_DEVICE(dev, struct ICH9SMBState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void ich9_smbus_write_config(PCIDevice *d, uint32_t address,
-                                    uint32_t val, int len)
-{
-    ICH9SMBState *s = ICH9_SMB_DEVICE(d);
-
-    pci_default_write_config(d, address, val, len);
-    if (range_covers_byte(address, len, ICH9_SMB_HOSTC)) {
-        uint8_t hostc = s->dev.config[ICH9_SMB_HOSTC];
-        if ((hostc & ICH9_SMB_HOSTC_HST_EN) &&
-            !(hostc & ICH9_SMB_HOSTC_I2C_EN)) {
-            memory_region_set_enabled(&s->smb.io, true);
-        } else {
-            memory_region_set_enabled(&s->smb.io, false);
-        }
-    }
-}
-
-static int ich9_smbus_initfn(PCIDevice *d)
-{
-    ICH9SMBState *s = ICH9_SMB_DEVICE(d);
-
-    /* TODO? D31IP.SMIP in chipset configuration space */
-    pci_config_set_interrupt_pin(d->config, 0x01); /* interrupt pin 1 */
-
-    pci_set_byte(d->config + ICH9_SMB_HOSTC, 0);
-    /* TODO bar0, bar1: 64bit BAR support*/
-
-    pm_smbus_init(&d->qdev, &s->smb);
-    pci_register_bar(d, ICH9_SMB_SMB_BASE_BAR, PCI_BASE_ADDRESS_SPACE_IO,
-                     &s->smb.io);
-    return 0;
-}
-
-static void ich9_smb_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
-    k->vendor_id = PCI_VENDOR_ID_INTEL;
-    k->device_id = PCI_DEVICE_ID_INTEL_ICH9_6;
-    k->revision = ICH9_A2_SMB_REVISION;
-    k->class_id = PCI_CLASS_SERIAL_SMBUS;
-    dc->no_user = 1;
-    dc->vmsd = &vmstate_ich9_smbus;
-    dc->desc = "ICH9 SMBUS Bridge";
-    k->init = ich9_smbus_initfn;
-    k->config_write = ich9_smbus_write_config;
-}
-
-i2c_bus *ich9_smb_init(PCIBus *bus, int devfn, uint32_t smb_io_base)
-{
-    PCIDevice *d =
-        pci_create_simple_multifunction(bus, devfn, true, TYPE_ICH9_SMB_DEVICE);
-    ICH9SMBState *s = ICH9_SMB_DEVICE(d);
-    return s->smb.smbus;
-}
-
-static const TypeInfo ich9_smb_info = {
-    .name   = TYPE_ICH9_SMB_DEVICE,
-    .parent = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(ICH9SMBState),
-    .class_init = ich9_smb_class_init,
-};
-
-static void ich9_smb_register(void)
-{
-    type_register_static(&ich9_smb_info);
-}
-
-type_init(ich9_smb_register);
diff --git a/hw/smc91c111.c b/hw/smc91c111.c
deleted file mode 100644 (file)
index c2feae6..0000000
+++ /dev/null
@@ -1,806 +0,0 @@
-/*
- * SMSC 91C111 Ethernet interface emulation
- *
- * Copyright (c) 2005 CodeSourcery, LLC.
- * Written by Paul Brook
- *
- * This code is licensed under the GPL
- */
-
-#include "hw/sysbus.h"
-#include "net/net.h"
-#include "hw/devices.h"
-/* For crc32 */
-#include <zlib.h>
-
-/* Number of 2k memory pages available.  */
-#define NUM_PACKETS 4
-
-typedef struct {
-    SysBusDevice busdev;
-    NICState *nic;
-    NICConf conf;
-    uint16_t tcr;
-    uint16_t rcr;
-    uint16_t cr;
-    uint16_t ctr;
-    uint16_t gpr;
-    uint16_t ptr;
-    uint16_t ercv;
-    qemu_irq irq;
-    int bank;
-    int packet_num;
-    int tx_alloc;
-    /* Bitmask of allocated packets.  */
-    int allocated;
-    int tx_fifo_len;
-    int tx_fifo[NUM_PACKETS];
-    int rx_fifo_len;
-    int rx_fifo[NUM_PACKETS];
-    int tx_fifo_done_len;
-    int tx_fifo_done[NUM_PACKETS];
-    /* Packet buffer memory.  */
-    uint8_t data[NUM_PACKETS][2048];
-    uint8_t int_level;
-    uint8_t int_mask;
-    MemoryRegion mmio;
-} smc91c111_state;
-
-static const VMStateDescription vmstate_smc91c111 = {
-    .name = "smc91c111",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .fields      = (VMStateField []) {
-        VMSTATE_UINT16(tcr, smc91c111_state),
-        VMSTATE_UINT16(rcr, smc91c111_state),
-        VMSTATE_UINT16(cr, smc91c111_state),
-        VMSTATE_UINT16(ctr, smc91c111_state),
-        VMSTATE_UINT16(gpr, smc91c111_state),
-        VMSTATE_UINT16(ptr, smc91c111_state),
-        VMSTATE_UINT16(ercv, smc91c111_state),
-        VMSTATE_INT32(bank, smc91c111_state),
-        VMSTATE_INT32(packet_num, smc91c111_state),
-        VMSTATE_INT32(tx_alloc, smc91c111_state),
-        VMSTATE_INT32(allocated, smc91c111_state),
-        VMSTATE_INT32(tx_fifo_len, smc91c111_state),
-        VMSTATE_INT32_ARRAY(tx_fifo, smc91c111_state, NUM_PACKETS),
-        VMSTATE_INT32(rx_fifo_len, smc91c111_state),
-        VMSTATE_INT32_ARRAY(rx_fifo, smc91c111_state, NUM_PACKETS),
-        VMSTATE_INT32(tx_fifo_done_len, smc91c111_state),
-        VMSTATE_INT32_ARRAY(tx_fifo_done, smc91c111_state, NUM_PACKETS),
-        VMSTATE_BUFFER_UNSAFE(data, smc91c111_state, 0, NUM_PACKETS * 2048),
-        VMSTATE_UINT8(int_level, smc91c111_state),
-        VMSTATE_UINT8(int_mask, smc91c111_state),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-#define RCR_SOFT_RST  0x8000
-#define RCR_STRIP_CRC 0x0200
-#define RCR_RXEN      0x0100
-
-#define TCR_EPH_LOOP  0x2000
-#define TCR_NOCRC     0x0100
-#define TCR_PAD_EN    0x0080
-#define TCR_FORCOL    0x0004
-#define TCR_LOOP      0x0002
-#define TCR_TXEN      0x0001
-
-#define INT_MD        0x80
-#define INT_ERCV      0x40
-#define INT_EPH       0x20
-#define INT_RX_OVRN   0x10
-#define INT_ALLOC     0x08
-#define INT_TX_EMPTY  0x04
-#define INT_TX        0x02
-#define INT_RCV       0x01
-
-#define CTR_AUTO_RELEASE  0x0800
-#define CTR_RELOAD        0x0002
-#define CTR_STORE         0x0001
-
-#define RS_ALGNERR      0x8000
-#define RS_BRODCAST     0x4000
-#define RS_BADCRC       0x2000
-#define RS_ODDFRAME     0x1000
-#define RS_TOOLONG      0x0800
-#define RS_TOOSHORT     0x0400
-#define RS_MULTICAST    0x0001
-
-/* Update interrupt status.  */
-static void smc91c111_update(smc91c111_state *s)
-{
-    int level;
-
-    if (s->tx_fifo_len == 0)
-        s->int_level |= INT_TX_EMPTY;
-    if (s->tx_fifo_done_len != 0)
-        s->int_level |= INT_TX;
-    level = (s->int_level & s->int_mask) != 0;
-    qemu_set_irq(s->irq, level);
-}
-
-/* Try to allocate a packet.  Returns 0x80 on failure.  */
-static int smc91c111_allocate_packet(smc91c111_state *s)
-{
-    int i;
-    if (s->allocated == (1 << NUM_PACKETS) - 1) {
-        return 0x80;
-    }
-
-    for (i = 0; i < NUM_PACKETS; i++) {
-        if ((s->allocated & (1 << i)) == 0)
-            break;
-    }
-    s->allocated |= 1 << i;
-    return i;
-}
-
-
-/* Process a pending TX allocate.  */
-static void smc91c111_tx_alloc(smc91c111_state *s)
-{
-    s->tx_alloc = smc91c111_allocate_packet(s);
-    if (s->tx_alloc == 0x80)
-        return;
-    s->int_level |= INT_ALLOC;
-    smc91c111_update(s);
-}
-
-/* Remove and item from the RX FIFO.  */
-static void smc91c111_pop_rx_fifo(smc91c111_state *s)
-{
-    int i;
-
-    s->rx_fifo_len--;
-    if (s->rx_fifo_len) {
-        for (i = 0; i < s->rx_fifo_len; i++)
-            s->rx_fifo[i] = s->rx_fifo[i + 1];
-        s->int_level |= INT_RCV;
-    } else {
-        s->int_level &= ~INT_RCV;
-    }
-    smc91c111_update(s);
-}
-
-/* Remove an item from the TX completion FIFO.  */
-static void smc91c111_pop_tx_fifo_done(smc91c111_state *s)
-{
-    int i;
-
-    if (s->tx_fifo_done_len == 0)
-        return;
-    s->tx_fifo_done_len--;
-    for (i = 0; i < s->tx_fifo_done_len; i++)
-        s->tx_fifo_done[i] = s->tx_fifo_done[i + 1];
-}
-
-/* Release the memory allocated to a packet.  */
-static void smc91c111_release_packet(smc91c111_state *s, int packet)
-{
-    s->allocated &= ~(1 << packet);
-    if (s->tx_alloc == 0x80)
-        smc91c111_tx_alloc(s);
-}
-
-/* Flush the TX FIFO.  */
-static void smc91c111_do_tx(smc91c111_state *s)
-{
-    int i;
-    int len;
-    int control;
-    int packetnum;
-    uint8_t *p;
-
-    if ((s->tcr & TCR_TXEN) == 0)
-        return;
-    if (s->tx_fifo_len == 0)
-        return;
-    for (i = 0; i < s->tx_fifo_len; i++) {
-        packetnum = s->tx_fifo[i];
-        p = &s->data[packetnum][0];
-        /* Set status word.  */
-        *(p++) = 0x01;
-        *(p++) = 0x40;
-        len = *(p++);
-        len |= ((int)*(p++)) << 8;
-        len -= 6;
-        control = p[len + 1];
-        if (control & 0x20)
-            len++;
-        /* ??? This overwrites the data following the buffer.
-           Don't know what real hardware does.  */
-        if (len < 64 && (s->tcr & TCR_PAD_EN)) {
-            memset(p + len, 0, 64 - len);
-            len = 64;
-        }
-#if 0
-        {
-            int add_crc;
-
-            /* The card is supposed to append the CRC to the frame.
-               However none of the other network traffic has the CRC
-               appended.  Suspect this is low level ethernet detail we
-               don't need to worry about.  */
-            add_crc = (control & 0x10) || (s->tcr & TCR_NOCRC) == 0;
-            if (add_crc) {
-                uint32_t crc;
-
-                crc = crc32(~0, p, len);
-                memcpy(p + len, &crc, 4);
-                len += 4;
-            }
-        }
-#endif
-        if (s->ctr & CTR_AUTO_RELEASE)
-            /* Race?  */
-            smc91c111_release_packet(s, packetnum);
-        else if (s->tx_fifo_done_len < NUM_PACKETS)
-            s->tx_fifo_done[s->tx_fifo_done_len++] = packetnum;
-        qemu_send_packet(qemu_get_queue(s->nic), p, len);
-    }
-    s->tx_fifo_len = 0;
-    smc91c111_update(s);
-}
-
-/* Add a packet to the TX FIFO.  */
-static void smc91c111_queue_tx(smc91c111_state *s, int packet)
-{
-    if (s->tx_fifo_len == NUM_PACKETS)
-        return;
-    s->tx_fifo[s->tx_fifo_len++] = packet;
-    smc91c111_do_tx(s);
-}
-
-static void smc91c111_reset(DeviceState *dev)
-{
-    smc91c111_state *s = FROM_SYSBUS(smc91c111_state, SYS_BUS_DEVICE(dev));
-    s->bank = 0;
-    s->tx_fifo_len = 0;
-    s->tx_fifo_done_len = 0;
-    s->rx_fifo_len = 0;
-    s->allocated = 0;
-    s->packet_num = 0;
-    s->tx_alloc = 0;
-    s->tcr = 0;
-    s->rcr = 0;
-    s->cr = 0xa0b1;
-    s->ctr = 0x1210;
-    s->ptr = 0;
-    s->ercv = 0x1f;
-    s->int_level = INT_TX_EMPTY;
-    s->int_mask = 0;
-    smc91c111_update(s);
-}
-
-#define SET_LOW(name, val) s->name = (s->name & 0xff00) | val
-#define SET_HIGH(name, val) s->name = (s->name & 0xff) | (val << 8)
-
-static void smc91c111_writeb(void *opaque, hwaddr offset,
-                             uint32_t value)
-{
-    smc91c111_state *s = (smc91c111_state *)opaque;
-
-    offset = offset & 0xf;
-    if (offset == 14) {
-        s->bank = value;
-        return;
-    }
-    if (offset == 15)
-        return;
-    switch (s->bank) {
-    case 0:
-        switch (offset) {
-        case 0: /* TCR */
-            SET_LOW(tcr, value);
-            return;
-        case 1:
-            SET_HIGH(tcr, value);
-            return;
-        case 4: /* RCR */
-            SET_LOW(rcr, value);
-            return;
-        case 5:
-            SET_HIGH(rcr, value);
-            if (s->rcr & RCR_SOFT_RST)
-                smc91c111_reset(&s->busdev.qdev);
-            return;
-        case 10: case 11: /* RPCR */
-            /* Ignored */
-            return;
-        case 12: case 13: /* Reserved */
-            return;
-        }
-        break;
-
-    case 1:
-        switch (offset) {
-        case 0: /* CONFIG */
-            SET_LOW(cr, value);
-            return;
-        case 1:
-            SET_HIGH(cr,value);
-            return;
-        case 2: case 3: /* BASE */
-        case 4: case 5: case 6: case 7: case 8: case 9: /* IA */
-            /* Not implemented.  */
-            return;
-        case 10: /* Genral Purpose */
-            SET_LOW(gpr, value);
-            return;
-        case 11:
-            SET_HIGH(gpr, value);
-            return;
-        case 12: /* Control */
-            if (value & 1)
-                fprintf(stderr, "smc91c111:EEPROM store not implemented\n");
-            if (value & 2)
-                fprintf(stderr, "smc91c111:EEPROM reload not implemented\n");
-            value &= ~3;
-            SET_LOW(ctr, value);
-            return;
-        case 13:
-            SET_HIGH(ctr, value);
-            return;
-        }
-        break;
-
-    case 2:
-        switch (offset) {
-        case 0: /* MMU Command */
-            switch (value >> 5) {
-            case 0: /* no-op */
-                break;
-            case 1: /* Allocate for TX.  */
-                s->tx_alloc = 0x80;
-                s->int_level &= ~INT_ALLOC;
-                smc91c111_update(s);
-                smc91c111_tx_alloc(s);
-                break;
-            case 2: /* Reset MMU.  */
-                s->allocated = 0;
-                s->tx_fifo_len = 0;
-                s->tx_fifo_done_len = 0;
-                s->rx_fifo_len = 0;
-                s->tx_alloc = 0;
-                break;
-            case 3: /* Remove from RX FIFO.  */
-                smc91c111_pop_rx_fifo(s);
-                break;
-            case 4: /* Remove from RX FIFO and release.  */
-                if (s->rx_fifo_len > 0) {
-                    smc91c111_release_packet(s, s->rx_fifo[0]);
-                }
-                smc91c111_pop_rx_fifo(s);
-                break;
-            case 5: /* Release.  */
-                smc91c111_release_packet(s, s->packet_num);
-                break;
-            case 6: /* Add to TX FIFO.  */
-                smc91c111_queue_tx(s, s->packet_num);
-                break;
-            case 7: /* Reset TX FIFO.  */
-                s->tx_fifo_len = 0;
-                s->tx_fifo_done_len = 0;
-                break;
-            }
-            return;
-        case 1:
-            /* Ignore.  */
-            return;
-        case 2: /* Packet Number Register */
-            s->packet_num = value;
-            return;
-        case 3: case 4: case 5:
-            /* Should be readonly, but linux writes to them anyway. Ignore.  */
-            return;
-        case 6: /* Pointer */
-            SET_LOW(ptr, value);
-            return;
-        case 7:
-            SET_HIGH(ptr, value);
-            return;
-        case 8: case 9: case 10: case 11: /* Data */
-            {
-                int p;
-                int n;
-
-                if (s->ptr & 0x8000)
-                    n = s->rx_fifo[0];
-                else
-                    n = s->packet_num;
-                p = s->ptr & 0x07ff;
-                if (s->ptr & 0x4000) {
-                    s->ptr = (s->ptr & 0xf800) | ((s->ptr + 1) & 0x7ff);
-                } else {
-                    p += (offset & 3);
-                }
-                s->data[n][p] = value;
-            }
-            return;
-        case 12: /* Interrupt ACK.  */
-            s->int_level &= ~(value & 0xd6);
-            if (value & INT_TX)
-                smc91c111_pop_tx_fifo_done(s);
-            smc91c111_update(s);
-            return;
-        case 13: /* Interrupt mask.  */
-            s->int_mask = value;
-            smc91c111_update(s);
-            return;
-        }
-        break;
-
-    case 3:
-        switch (offset) {
-        case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
-            /* Multicast table.  */
-            /* Not implemented.  */
-            return;
-        case 8: case 9: /* Management Interface.  */
-            /* Not implemented.  */
-            return;
-        case 12: /* Early receive.  */
-            s->ercv = value & 0x1f;
-            return;
-        case 13:
-            /* Ignore.  */
-            return;
-        }
-        break;
-    }
-    hw_error("smc91c111_write: Bad reg %d:%x\n", s->bank, (int)offset);
-}
-
-static uint32_t smc91c111_readb(void *opaque, hwaddr offset)
-{
-    smc91c111_state *s = (smc91c111_state *)opaque;
-
-    offset = offset & 0xf;
-    if (offset == 14) {
-        return s->bank;
-    }
-    if (offset == 15)
-        return 0x33;
-    switch (s->bank) {
-    case 0:
-        switch (offset) {
-        case 0: /* TCR */
-            return s->tcr & 0xff;
-        case 1:
-            return s->tcr >> 8;
-        case 2: /* EPH Status */
-            return 0;
-        case 3:
-            return 0x40;
-        case 4: /* RCR */
-            return s->rcr & 0xff;
-        case 5:
-            return s->rcr >> 8;
-        case 6: /* Counter */
-        case 7:
-            /* Not implemented.  */
-            return 0;
-        case 8: /* Memory size.  */
-            return NUM_PACKETS;
-        case 9: /* Free memory available.  */
-            {
-                int i;
-                int n;
-                n = 0;
-                for (i = 0; i < NUM_PACKETS; i++) {
-                    if (s->allocated & (1 << i))
-                        n++;
-                }
-                return n;
-            }
-        case 10: case 11: /* RPCR */
-            /* Not implemented.  */
-            return 0;
-        case 12: case 13: /* Reserved */
-            return 0;
-        }
-        break;
-
-    case 1:
-        switch (offset) {
-        case 0: /* CONFIG */
-            return s->cr & 0xff;
-        case 1:
-            return s->cr >> 8;
-        case 2: case 3: /* BASE */
-            /* Not implemented.  */
-            return 0;
-        case 4: case 5: case 6: case 7: case 8: case 9: /* IA */
-            return s->conf.macaddr.a[offset - 4];
-        case 10: /* General Purpose */
-            return s->gpr & 0xff;
-        case 11:
-            return s->gpr >> 8;
-        case 12: /* Control */
-            return s->ctr & 0xff;
-        case 13:
-            return s->ctr >> 8;
-        }
-        break;
-
-    case 2:
-        switch (offset) {
-        case 0: case 1: /* MMUCR Busy bit.  */
-            return 0;
-        case 2: /* Packet Number.  */
-            return s->packet_num;
-        case 3: /* Allocation Result.  */
-            return s->tx_alloc;
-        case 4: /* TX FIFO */
-            if (s->tx_fifo_done_len == 0)
-                return 0x80;
-            else
-                return s->tx_fifo_done[0];
-        case 5: /* RX FIFO */
-            if (s->rx_fifo_len == 0)
-                return 0x80;
-            else
-                return s->rx_fifo[0];
-        case 6: /* Pointer */
-            return s->ptr & 0xff;
-        case 7:
-            return (s->ptr >> 8) & 0xf7;
-        case 8: case 9: case 10: case 11: /* Data */
-            {
-                int p;
-                int n;
-
-                if (s->ptr & 0x8000)
-                    n = s->rx_fifo[0];
-                else
-                    n = s->packet_num;
-                p = s->ptr & 0x07ff;
-                if (s->ptr & 0x4000) {
-                    s->ptr = (s->ptr & 0xf800) | ((s->ptr + 1) & 0x07ff);
-                } else {
-                    p += (offset & 3);
-                }
-                return s->data[n][p];
-            }
-        case 12: /* Interrupt status.  */
-            return s->int_level;
-        case 13: /* Interrupt mask.  */
-            return s->int_mask;
-        }
-        break;
-
-    case 3:
-        switch (offset) {
-        case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
-            /* Multicast table.  */
-            /* Not implemented.  */
-            return 0;
-        case 8: /* Management Interface.  */
-            /* Not implemented.  */
-            return 0x30;
-        case 9:
-            return 0x33;
-        case 10: /* Revision.  */
-            return 0x91;
-        case 11:
-            return 0x33;
-        case 12:
-            return s->ercv;
-        case 13:
-            return 0;
-        }
-        break;
-    }
-    hw_error("smc91c111_read: Bad reg %d:%x\n", s->bank, (int)offset);
-    return 0;
-}
-
-static void smc91c111_writew(void *opaque, hwaddr offset,
-                             uint32_t value)
-{
-    smc91c111_writeb(opaque, offset, value & 0xff);
-    smc91c111_writeb(opaque, offset + 1, value >> 8);
-}
-
-static void smc91c111_writel(void *opaque, hwaddr offset,
-                             uint32_t value)
-{
-    /* 32-bit writes to offset 0xc only actually write to the bank select
-       register (offset 0xe)  */
-    if (offset != 0xc)
-        smc91c111_writew(opaque, offset, value & 0xffff);
-    smc91c111_writew(opaque, offset + 2, value >> 16);
-}
-
-static uint32_t smc91c111_readw(void *opaque, hwaddr offset)
-{
-    uint32_t val;
-    val = smc91c111_readb(opaque, offset);
-    val |= smc91c111_readb(opaque, offset + 1) << 8;
-    return val;
-}
-
-static uint32_t smc91c111_readl(void *opaque, hwaddr offset)
-{
-    uint32_t val;
-    val = smc91c111_readw(opaque, offset);
-    val |= smc91c111_readw(opaque, offset + 2) << 16;
-    return val;
-}
-
-static int smc91c111_can_receive(NetClientState *nc)
-{
-    smc91c111_state *s = qemu_get_nic_opaque(nc);
-
-    if ((s->rcr & RCR_RXEN) == 0 || (s->rcr & RCR_SOFT_RST))
-        return 1;
-    if (s->allocated == (1 << NUM_PACKETS) - 1)
-        return 0;
-    return 1;
-}
-
-static ssize_t smc91c111_receive(NetClientState *nc, const uint8_t *buf, size_t size)
-{
-    smc91c111_state *s = qemu_get_nic_opaque(nc);
-    int status;
-    int packetsize;
-    uint32_t crc;
-    int packetnum;
-    uint8_t *p;
-
-    if ((s->rcr & RCR_RXEN) == 0 || (s->rcr & RCR_SOFT_RST))
-        return -1;
-    /* Short packets are padded with zeros.  Receiving a packet
-       < 64 bytes long is considered an error condition.  */
-    if (size < 64)
-        packetsize = 64;
-    else
-        packetsize = (size & ~1);
-    packetsize += 6;
-    crc = (s->rcr & RCR_STRIP_CRC) == 0;
-    if (crc)
-        packetsize += 4;
-    /* TODO: Flag overrun and receive errors.  */
-    if (packetsize > 2048)
-        return -1;
-    packetnum = smc91c111_allocate_packet(s);
-    if (packetnum == 0x80)
-        return -1;
-    s->rx_fifo[s->rx_fifo_len++] = packetnum;
-
-    p = &s->data[packetnum][0];
-    /* ??? Multicast packets?  */
-    status = 0;
-    if (size > 1518)
-        status |= RS_TOOLONG;
-    if (size & 1)
-        status |= RS_ODDFRAME;
-    *(p++) = status & 0xff;
-    *(p++) = status >> 8;
-    *(p++) = packetsize & 0xff;
-    *(p++) = packetsize >> 8;
-    memcpy(p, buf, size & ~1);
-    p += (size & ~1);
-    /* Pad short packets.  */
-    if (size < 64) {
-        int pad;
-
-        if (size & 1)
-            *(p++) = buf[size - 1];
-        pad = 64 - size;
-        memset(p, 0, pad);
-        p += pad;
-        size = 64;
-    }
-    /* It's not clear if the CRC should go before or after the last byte in
-       odd sized packets.  Linux disables the CRC, so that's no help.
-       The pictures in the documentation show the CRC aligned on a 16-bit
-       boundary before the last odd byte, so that's what we do.  */
-    if (crc) {
-        crc = crc32(~0, buf, size);
-        *(p++) = crc & 0xff; crc >>= 8;
-        *(p++) = crc & 0xff; crc >>= 8;
-        *(p++) = crc & 0xff; crc >>= 8;
-        *(p++) = crc & 0xff;
-    }
-    if (size & 1) {
-        *(p++) = buf[size - 1];
-        *p = 0x60;
-    } else {
-        *(p++) = 0;
-        *p = 0x40;
-    }
-    /* TODO: Raise early RX interrupt?  */
-    s->int_level |= INT_RCV;
-    smc91c111_update(s);
-
-    return size;
-}
-
-static const MemoryRegionOps smc91c111_mem_ops = {
-    /* The special case for 32 bit writes to 0xc means we can't just
-     * set .impl.min/max_access_size to 1, unfortunately
-     */
-    .old_mmio = {
-        .read = { smc91c111_readb, smc91c111_readw, smc91c111_readl, },
-        .write = { smc91c111_writeb, smc91c111_writew, smc91c111_writel, },
-    },
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void smc91c111_cleanup(NetClientState *nc)
-{
-    smc91c111_state *s = qemu_get_nic_opaque(nc);
-
-    s->nic = NULL;
-}
-
-static NetClientInfo net_smc91c111_info = {
-    .type = NET_CLIENT_OPTIONS_KIND_NIC,
-    .size = sizeof(NICState),
-    .can_receive = smc91c111_can_receive,
-    .receive = smc91c111_receive,
-    .cleanup = smc91c111_cleanup,
-};
-
-static int smc91c111_init1(SysBusDevice *dev)
-{
-    smc91c111_state *s = FROM_SYSBUS(smc91c111_state, dev);
-    memory_region_init_io(&s->mmio, &smc91c111_mem_ops, s,
-                          "smc91c111-mmio", 16);
-    sysbus_init_mmio(dev, &s->mmio);
-    sysbus_init_irq(dev, &s->irq);
-    qemu_macaddr_default_if_unset(&s->conf.macaddr);
-    s->nic = qemu_new_nic(&net_smc91c111_info, &s->conf,
-                          object_get_typename(OBJECT(dev)), dev->qdev.id, s);
-    qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
-    /* ??? Save/restore.  */
-    return 0;
-}
-
-static Property smc91c111_properties[] = {
-    DEFINE_NIC_PROPERTIES(smc91c111_state, conf),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void smc91c111_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = smc91c111_init1;
-    dc->reset = smc91c111_reset;
-    dc->vmsd = &vmstate_smc91c111;
-    dc->props = smc91c111_properties;
-}
-
-static const TypeInfo smc91c111_info = {
-    .name          = "smc91c111",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(smc91c111_state),
-    .class_init    = smc91c111_class_init,
-};
-
-static void smc91c111_register_types(void)
-{
-    type_register_static(&smc91c111_info);
-}
-
-/* Legacy helper function.  Should go away when machine config files are
-   implemented.  */
-void smc91c111_init(NICInfo *nd, uint32_t base, qemu_irq irq)
-{
-    DeviceState *dev;
-    SysBusDevice *s;
-
-    qemu_check_nic_model(nd, "smc91c111");
-    dev = qdev_create(NULL, "smc91c111");
-    qdev_set_nic_properties(dev, nd);
-    qdev_init_nofail(dev);
-    s = SYS_BUS_DEVICE(dev);
-    sysbus_mmio_map(s, 0, base);
-    sysbus_connect_irq(s, 0, irq);
-}
-
-type_init(smc91c111_register_types)
diff --git a/hw/soc_dma.c b/hw/soc_dma.c
deleted file mode 100644 (file)
index db5d609..0000000
+++ /dev/null
@@ -1,366 +0,0 @@
-/*
- * On-chip DMA controller framework.
- *
- * Copyright (C) 2008 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.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 or
- * (at your option) version 3 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
- * 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 "qemu/timer.h"
-#include "hw/soc_dma.h"
-
-static void transfer_mem2mem(struct soc_dma_ch_s *ch)
-{
-    memcpy(ch->paddr[0], ch->paddr[1], ch->bytes);
-    ch->paddr[0] += ch->bytes;
-    ch->paddr[1] += ch->bytes;
-}
-
-static void transfer_mem2fifo(struct soc_dma_ch_s *ch)
-{
-    ch->io_fn[1](ch->io_opaque[1], ch->paddr[0], ch->bytes);
-    ch->paddr[0] += ch->bytes;
-}
-
-static void transfer_fifo2mem(struct soc_dma_ch_s *ch)
-{
-    ch->io_fn[0](ch->io_opaque[0], ch->paddr[1], ch->bytes);
-    ch->paddr[1] += ch->bytes;
-}
-
-/* This is further optimisable but isn't very important because often
- * DMA peripherals forbid this kind of transfers and even when they don't,
- * oprating systems may not need to use them.  */
-static void *fifo_buf;
-static int fifo_size;
-static void transfer_fifo2fifo(struct soc_dma_ch_s *ch)
-{
-    if (ch->bytes > fifo_size)
-        fifo_buf = g_realloc(fifo_buf, fifo_size = ch->bytes);
-
-    /* Implement as transfer_fifo2linear + transfer_linear2fifo.  */
-    ch->io_fn[0](ch->io_opaque[0], fifo_buf, ch->bytes);
-    ch->io_fn[1](ch->io_opaque[1], fifo_buf, ch->bytes);
-}
-
-struct dma_s {
-    struct soc_dma_s soc;
-    int chnum;
-    uint64_t ch_enable_mask;
-    int64_t channel_freq;
-    int enabled_count;
-
-    struct memmap_entry_s {
-        enum soc_dma_port_type type;
-        hwaddr addr;
-        union {
-           struct {
-               void *opaque;
-               soc_dma_io_t fn;
-               int out;
-           } fifo;
-           struct {
-               void *base;
-               size_t size;
-           } mem;
-        } u;
-    } *memmap;
-    int memmap_size;
-
-    struct soc_dma_ch_s ch[0];
-};
-
-static void soc_dma_ch_schedule(struct soc_dma_ch_s *ch, int delay_bytes)
-{
-    int64_t now = qemu_get_clock_ns(vm_clock);
-    struct dma_s *dma = (struct dma_s *) ch->dma;
-
-    qemu_mod_timer(ch->timer, now + delay_bytes / dma->channel_freq);
-}
-
-static void soc_dma_ch_run(void *opaque)
-{
-    struct soc_dma_ch_s *ch = (struct soc_dma_ch_s *) opaque;
-
-    ch->running = 1;
-    ch->dma->setup_fn(ch);
-    ch->transfer_fn(ch);
-    ch->running = 0;
-
-    if (ch->enable)
-        soc_dma_ch_schedule(ch, ch->bytes);
-    ch->bytes = 0;
-}
-
-static inline struct memmap_entry_s *soc_dma_lookup(struct dma_s *dma,
-                hwaddr addr)
-{
-    struct memmap_entry_s *lo;
-    int hi;
-
-    lo = dma->memmap;
-    hi = dma->memmap_size;
-
-    while (hi > 1) {
-        hi /= 2;
-        if (lo[hi].addr <= addr)
-            lo += hi;
-    }
-
-    return lo;
-}
-
-static inline enum soc_dma_port_type soc_dma_ch_update_type(
-                struct soc_dma_ch_s *ch, int port)
-{
-    struct dma_s *dma = (struct dma_s *) ch->dma;
-    struct memmap_entry_s *entry = soc_dma_lookup(dma, ch->vaddr[port]);
-
-    if (entry->type == soc_dma_port_fifo) {
-        while (entry < dma->memmap + dma->memmap_size &&
-                        entry->u.fifo.out != port)
-            entry ++;
-        if (entry->addr != ch->vaddr[port] || entry->u.fifo.out != port)
-            return soc_dma_port_other;
-
-        if (ch->type[port] != soc_dma_access_const)
-            return soc_dma_port_other;
-
-        ch->io_fn[port] = entry->u.fifo.fn;
-        ch->io_opaque[port] = entry->u.fifo.opaque;
-        return soc_dma_port_fifo;
-    } else if (entry->type == soc_dma_port_mem) {
-        if (entry->addr > ch->vaddr[port] ||
-                        entry->addr + entry->u.mem.size <= ch->vaddr[port])
-            return soc_dma_port_other;
-
-        /* TODO: support constant memory address for source port as used for
-         * drawing solid rectangles by PalmOS(R).  */
-        if (ch->type[port] != soc_dma_access_const)
-            return soc_dma_port_other;
-
-        ch->paddr[port] = (uint8_t *) entry->u.mem.base +
-                (ch->vaddr[port] - entry->addr);
-        /* TODO: save bytes left to the end of the mapping somewhere so we
-         * can check we're not reading beyond it.  */
-        return soc_dma_port_mem;
-    } else
-        return soc_dma_port_other;
-}
-
-void soc_dma_ch_update(struct soc_dma_ch_s *ch)
-{
-    enum soc_dma_port_type src, dst;
-
-    src = soc_dma_ch_update_type(ch, 0);
-    if (src == soc_dma_port_other) {
-        ch->update = 0;
-        ch->transfer_fn = ch->dma->transfer_fn;
-        return;
-    }
-    dst = soc_dma_ch_update_type(ch, 1);
-
-    /* TODO: use src and dst as array indices.  */
-    if (src == soc_dma_port_mem && dst == soc_dma_port_mem)
-        ch->transfer_fn = transfer_mem2mem;
-    else if (src == soc_dma_port_mem && dst == soc_dma_port_fifo)
-        ch->transfer_fn = transfer_mem2fifo;
-    else if (src == soc_dma_port_fifo && dst == soc_dma_port_mem)
-        ch->transfer_fn = transfer_fifo2mem;
-    else if (src == soc_dma_port_fifo && dst == soc_dma_port_fifo)
-        ch->transfer_fn = transfer_fifo2fifo;
-    else
-        ch->transfer_fn = ch->dma->transfer_fn;
-
-    ch->update = (dst != soc_dma_port_other);
-}
-
-static void soc_dma_ch_freq_update(struct dma_s *s)
-{
-    if (s->enabled_count)
-        /* We completely ignore channel priorities and stuff */
-        s->channel_freq = s->soc.freq / s->enabled_count;
-    else {
-        /* TODO: Signal that we want to disable the functional clock and let
-         * the platform code decide what to do with it, i.e. check that
-         * auto-idle is enabled in the clock controller and if we are stopping
-         * the clock, do the same with any parent clocks that had only one
-         * user keeping them on and auto-idle enabled.  */
-    }
-}
-
-void soc_dma_set_request(struct soc_dma_ch_s *ch, int level)
-{
-    struct dma_s *dma = (struct dma_s *) ch->dma;
-
-    dma->enabled_count += level - ch->enable;
-
-    if (level)
-        dma->ch_enable_mask |= 1 << ch->num;
-    else
-        dma->ch_enable_mask &= ~(1 << ch->num);
-
-    if (level != ch->enable) {
-        soc_dma_ch_freq_update(dma);
-        ch->enable = level;
-
-        if (!ch->enable)
-            qemu_del_timer(ch->timer);
-        else if (!ch->running)
-            soc_dma_ch_run(ch);
-        else
-            soc_dma_ch_schedule(ch, 1);
-    }
-}
-
-void soc_dma_reset(struct soc_dma_s *soc)
-{
-    struct dma_s *s = (struct dma_s *) soc;
-
-    s->soc.drqbmp = 0;
-    s->ch_enable_mask = 0;
-    s->enabled_count = 0;
-    soc_dma_ch_freq_update(s);
-}
-
-/* TODO: take a functional-clock argument */
-struct soc_dma_s *soc_dma_init(int n)
-{
-    int i;
-    struct dma_s *s = g_malloc0(sizeof(*s) + n * sizeof(*s->ch));
-
-    s->chnum = n;
-    s->soc.ch = s->ch;
-    for (i = 0; i < n; i ++) {
-        s->ch[i].dma = &s->soc;
-        s->ch[i].num = i;
-        s->ch[i].timer = qemu_new_timer_ns(vm_clock, soc_dma_ch_run, &s->ch[i]);
-    }
-
-    soc_dma_reset(&s->soc);
-    fifo_size = 0;
-
-    return &s->soc;
-}
-
-void soc_dma_port_add_fifo(struct soc_dma_s *soc, hwaddr virt_base,
-                soc_dma_io_t fn, void *opaque, int out)
-{
-    struct memmap_entry_s *entry;
-    struct dma_s *dma = (struct dma_s *) soc;
-
-    dma->memmap = g_realloc(dma->memmap, sizeof(*entry) *
-                    (dma->memmap_size + 1));
-    entry = soc_dma_lookup(dma, virt_base);
-
-    if (dma->memmap_size) {
-        if (entry->type == soc_dma_port_mem) {
-            if (entry->addr <= virt_base &&
-                            entry->addr + entry->u.mem.size > virt_base) {
-                fprintf(stderr, "%s: FIFO at " TARGET_FMT_lx
-                                " collides with RAM region at " TARGET_FMT_lx
-                                "-" TARGET_FMT_lx "\n", __FUNCTION__,
-                                (target_ulong) virt_base,
-                                (target_ulong) entry->addr, (target_ulong)
-                                (entry->addr + entry->u.mem.size));
-                exit(-1);
-            }
-
-            if (entry->addr <= virt_base)
-                entry ++;
-        } else
-            while (entry < dma->memmap + dma->memmap_size &&
-                            entry->addr <= virt_base) {
-                if (entry->addr == virt_base && entry->u.fifo.out == out) {
-                    fprintf(stderr, "%s: FIFO at " TARGET_FMT_lx
-                                    " collides FIFO at " TARGET_FMT_lx "\n",
-                                    __FUNCTION__, (target_ulong) virt_base,
-                                    (target_ulong) entry->addr);
-                    exit(-1);
-                }
-
-                entry ++;
-            }
-
-        memmove(entry + 1, entry,
-                        (uint8_t *) (dma->memmap + dma->memmap_size ++) -
-                        (uint8_t *) entry);
-    } else
-        dma->memmap_size ++;
-
-    entry->addr          = virt_base;
-    entry->type          = soc_dma_port_fifo;
-    entry->u.fifo.fn     = fn;
-    entry->u.fifo.opaque = opaque;
-    entry->u.fifo.out    = out;
-}
-
-void soc_dma_port_add_mem(struct soc_dma_s *soc, uint8_t *phys_base,
-                hwaddr virt_base, size_t size)
-{
-    struct memmap_entry_s *entry;
-    struct dma_s *dma = (struct dma_s *) soc;
-
-    dma->memmap = g_realloc(dma->memmap, sizeof(*entry) *
-                    (dma->memmap_size + 1));
-    entry = soc_dma_lookup(dma, virt_base);
-
-    if (dma->memmap_size) {
-        if (entry->type == soc_dma_port_mem) {
-            if ((entry->addr >= virt_base && entry->addr < virt_base + size) ||
-                            (entry->addr <= virt_base &&
-                             entry->addr + entry->u.mem.size > virt_base)) {
-                fprintf(stderr, "%s: RAM at " TARGET_FMT_lx "-" TARGET_FMT_lx
-                                " collides with RAM region at " TARGET_FMT_lx
-                                "-" TARGET_FMT_lx "\n", __FUNCTION__,
-                                (target_ulong) virt_base,
-                                (target_ulong) (virt_base + size),
-                                (target_ulong) entry->addr, (target_ulong)
-                                (entry->addr + entry->u.mem.size));
-                exit(-1);
-            }
-
-            if (entry->addr <= virt_base)
-                entry ++;
-        } else {
-            if (entry->addr >= virt_base &&
-                            entry->addr < virt_base + size) {
-                fprintf(stderr, "%s: RAM at " TARGET_FMT_lx "-" TARGET_FMT_lx
-                                " collides with FIFO at " TARGET_FMT_lx
-                                "\n", __FUNCTION__,
-                                (target_ulong) virt_base,
-                                (target_ulong) (virt_base + size),
-                                (target_ulong) entry->addr);
-                exit(-1);
-            }
-
-            while (entry < dma->memmap + dma->memmap_size &&
-                            entry->addr <= virt_base)
-                entry ++;
-       }
-
-        memmove(entry + 1, entry,
-                        (uint8_t *) (dma->memmap + dma->memmap_size ++) -
-                        (uint8_t *) entry);
-    } else
-        dma->memmap_size ++;
-
-    entry->addr          = virt_base;
-    entry->type          = soc_dma_port_mem;
-    entry->u.mem.base    = phys_base;
-    entry->u.mem.size    = size;
-}
-
-/* TODO: port removal for ports like PCMCIA memory */
diff --git a/hw/soc_dma.h b/hw/soc_dma.h
deleted file mode 100644 (file)
index 7379731..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * On-chip DMA controller framework.
- *
- * Copyright (C) 2008 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.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 or
- * (at your option) version 3 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
- * 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 HW_SOC_DMA_H
-#define HW_SOC_DMA_H 1
-
-
-#include "exec/memory.h"
-#include "hw/irq.h"
-
-struct soc_dma_s;
-struct soc_dma_ch_s;
-typedef void (*soc_dma_io_t)(void *opaque, uint8_t *buf, int len);
-typedef void (*soc_dma_transfer_t)(struct soc_dma_ch_s *ch);
-
-enum soc_dma_port_type {
-    soc_dma_port_mem,
-    soc_dma_port_fifo,
-    soc_dma_port_other,
-};
-
-enum soc_dma_access_type {
-    soc_dma_access_const,
-    soc_dma_access_linear,
-    soc_dma_access_other,
-};
-
-struct soc_dma_ch_s {
-    /* Private */
-    struct soc_dma_s *dma;
-    int num;
-    QEMUTimer *timer;
-
-    /* Set by soc_dma.c */
-    int enable;
-    int update;
-
-    /* This should be set by dma->setup_fn().  */
-    int bytes;
-    /* Initialised by the DMA module, call soc_dma_ch_update after writing.  */
-    enum soc_dma_access_type type[2];
-    hwaddr vaddr[2];   /* Updated by .transfer_fn().  */
-    /* Private */
-    void *paddr[2];
-    soc_dma_io_t io_fn[2];
-    void *io_opaque[2];
-
-    int running;
-    soc_dma_transfer_t transfer_fn;
-
-    /* Set and used by the DMA module.  */
-    void *opaque;
-};
-
-struct soc_dma_s {
-    /* Following fields are set by the SoC DMA module and can be used
-     * by anybody.  */
-    uint64_t drqbmp;   /* Is zeroed by soc_dma_reset() */
-    qemu_irq *drq;
-    void *opaque;
-    int64_t freq;
-    soc_dma_transfer_t transfer_fn;
-    soc_dma_transfer_t setup_fn;
-    /* Set by soc_dma_init() for use by the DMA module.  */
-    struct soc_dma_ch_s *ch;
-};
-
-/* Call to activate or stop a DMA channel.  */
-void soc_dma_set_request(struct soc_dma_ch_s *ch, int level);
-/* Call after every write to one of the following fields and before
- * calling soc_dma_set_request(ch, 1):
- *   ch->type[0...1],
- *   ch->vaddr[0...1],
- *   ch->paddr[0...1],
- * or after a soc_dma_port_add_fifo() or soc_dma_port_add_mem().  */
-void soc_dma_ch_update(struct soc_dma_ch_s *ch);
-
-/* The SoC should call this when the DMA module is being reset.  */
-void soc_dma_reset(struct soc_dma_s *s);
-struct soc_dma_s *soc_dma_init(int n);
-
-void soc_dma_port_add_fifo(struct soc_dma_s *dma, hwaddr virt_base,
-                soc_dma_io_t fn, void *opaque, int out);
-void soc_dma_port_add_mem(struct soc_dma_s *dma, uint8_t *phys_base,
-                hwaddr virt_base, size_t size);
-
-static inline void soc_dma_port_add_fifo_in(struct soc_dma_s *dma,
-                hwaddr virt_base, soc_dma_io_t fn, void *opaque)
-{
-    return soc_dma_port_add_fifo(dma, virt_base, fn, opaque, 0);
-}
-
-static inline void soc_dma_port_add_fifo_out(struct soc_dma_s *dma,
-                hwaddr virt_base, soc_dma_io_t fn, void *opaque)
-{
-    return soc_dma_port_add_fifo(dma, virt_base, fn, opaque, 1);
-}
-
-#endif
diff --git a/hw/spapr.h b/hw/spapr.h
deleted file mode 100644 (file)
index 3a1f69f..0000000
+++ /dev/null
@@ -1,358 +0,0 @@
-#if !defined(__HW_SPAPR_H__)
-#define __HW_SPAPR_H__
-
-#include "sysemu/dma.h"
-#include "hw/xics.h"
-
-struct VIOsPAPRBus;
-struct sPAPRPHBState;
-struct sPAPRNVRAM;
-struct icp_state;
-
-typedef struct sPAPREnvironment {
-    struct VIOsPAPRBus *vio_bus;
-    QLIST_HEAD(, sPAPRPHBState) phbs;
-    struct sPAPRNVRAM *nvram;
-    struct icp_state *icp;
-
-    hwaddr ram_limit;
-    void *htab;
-    long htab_shift;
-    hwaddr rma_size;
-    int vrma_adjust;
-    hwaddr fdt_addr, rtas_addr;
-    long rtas_size;
-    void *fdt_skel;
-    target_ulong entry_point;
-    int next_irq;
-    int rtc_offset;
-    char *cpu_model;
-    bool has_graphics;
-
-    uint32_t epow_irq;
-    Notifier epow_notifier;
-} sPAPREnvironment;
-
-#define H_SUCCESS         0
-#define H_BUSY            1        /* Hardware busy -- retry later */
-#define H_CLOSED          2        /* Resource closed */
-#define H_NOT_AVAILABLE   3
-#define H_CONSTRAINED     4        /* Resource request constrained to max allowed */
-#define H_PARTIAL         5
-#define H_IN_PROGRESS     14       /* Kind of like busy */
-#define H_PAGE_REGISTERED 15
-#define H_PARTIAL_STORE   16
-#define H_PENDING         17       /* returned from H_POLL_PENDING */
-#define H_CONTINUE        18       /* Returned from H_Join on success */
-#define H_LONG_BUSY_START_RANGE         9900  /* Start of long busy range */
-#define H_LONG_BUSY_ORDER_1_MSEC        9900  /* Long busy, hint that 1msec \
-                                                 is a good time to retry */
-#define H_LONG_BUSY_ORDER_10_MSEC       9901  /* Long busy, hint that 10msec \
-                                                 is a good time to retry */
-#define H_LONG_BUSY_ORDER_100_MSEC      9902  /* Long busy, hint that 100msec \
-                                                 is a good time to retry */
-#define H_LONG_BUSY_ORDER_1_SEC         9903  /* Long busy, hint that 1sec \
-                                                 is a good time to retry */
-#define H_LONG_BUSY_ORDER_10_SEC        9904  /* Long busy, hint that 10sec \
-                                                 is a good time to retry */
-#define H_LONG_BUSY_ORDER_100_SEC       9905  /* Long busy, hint that 100sec \
-                                                 is a good time to retry */
-#define H_LONG_BUSY_END_RANGE           9905  /* End of long busy range */
-#define H_HARDWARE        -1       /* Hardware error */
-#define H_FUNCTION        -2       /* Function not supported */
-#define H_PRIVILEGE       -3       /* Caller not privileged */
-#define H_PARAMETER       -4       /* Parameter invalid, out-of-range or conflicting */
-#define H_BAD_MODE        -5       /* Illegal msr value */
-#define H_PTEG_FULL       -6       /* PTEG is full */
-#define H_NOT_FOUND       -7       /* PTE was not found" */
-#define H_RESERVED_DABR   -8       /* DABR address is reserved by the hypervisor on this processor" */
-#define H_NO_MEM          -9
-#define H_AUTHORITY       -10
-#define H_PERMISSION      -11
-#define H_DROPPED         -12
-#define H_SOURCE_PARM     -13
-#define H_DEST_PARM       -14
-#define H_REMOTE_PARM     -15
-#define H_RESOURCE        -16
-#define H_ADAPTER_PARM    -17
-#define H_RH_PARM         -18
-#define H_RCQ_PARM        -19
-#define H_SCQ_PARM        -20
-#define H_EQ_PARM         -21
-#define H_RT_PARM         -22
-#define H_ST_PARM         -23
-#define H_SIGT_PARM       -24
-#define H_TOKEN_PARM      -25
-#define H_MLENGTH_PARM    -27
-#define H_MEM_PARM        -28
-#define H_MEM_ACCESS_PARM -29
-#define H_ATTR_PARM       -30
-#define H_PORT_PARM       -31
-#define H_MCG_PARM        -32
-#define H_VL_PARM         -33
-#define H_TSIZE_PARM      -34
-#define H_TRACE_PARM      -35
-
-#define H_MASK_PARM       -37
-#define H_MCG_FULL        -38
-#define H_ALIAS_EXIST     -39
-#define H_P_COUNTER       -40
-#define H_TABLE_FULL      -41
-#define H_ALT_TABLE       -42
-#define H_MR_CONDITION    -43
-#define H_NOT_ENOUGH_RESOURCES -44
-#define H_R_STATE         -45
-#define H_RESCINDEND      -46
-#define H_MULTI_THREADS_ACTIVE -9005
-
-
-/* Long Busy is a condition that can be returned by the firmware
- * when a call cannot be completed now, but the identical call
- * should be retried later.  This prevents calls blocking in the
- * firmware for long periods of time.  Annoyingly the firmware can return
- * a range of return codes, hinting at how long we should wait before
- * retrying.  If you don't care for the hint, the macro below is a good
- * way to check for the long_busy return codes
- */
-#define H_IS_LONG_BUSY(x)  ((x >= H_LONG_BUSY_START_RANGE) \
-                            && (x <= H_LONG_BUSY_END_RANGE))
-
-/* Flags */
-#define H_LARGE_PAGE      (1ULL<<(63-16))
-#define H_EXACT           (1ULL<<(63-24))       /* Use exact PTE or return H_PTEG_FULL */
-#define H_R_XLATE         (1ULL<<(63-25))       /* include a valid logical page num in the pte if the valid bit is set */
-#define H_READ_4          (1ULL<<(63-26))       /* Return 4 PTEs */
-#define H_PAGE_STATE_CHANGE (1ULL<<(63-28))
-#define H_PAGE_UNUSED     ((1ULL<<(63-29)) | (1ULL<<(63-30)))
-#define H_PAGE_SET_UNUSED (H_PAGE_STATE_CHANGE | H_PAGE_UNUSED)
-#define H_PAGE_SET_LOANED (H_PAGE_SET_UNUSED | (1ULL<<(63-31)))
-#define H_PAGE_SET_ACTIVE H_PAGE_STATE_CHANGE
-#define H_AVPN            (1ULL<<(63-32))       /* An avpn is provided as a sanity test */
-#define H_ANDCOND         (1ULL<<(63-33))
-#define H_ICACHE_INVALIDATE (1ULL<<(63-40))     /* icbi, etc.  (ignored for IO pages) */
-#define H_ICACHE_SYNCHRONIZE (1ULL<<(63-41))    /* dcbst, icbi, etc (ignored for IO pages */
-#define H_ZERO_PAGE       (1ULL<<(63-48))       /* zero the page before mapping (ignored for IO pages) */
-#define H_COPY_PAGE       (1ULL<<(63-49))
-#define H_N               (1ULL<<(63-61))
-#define H_PP1             (1ULL<<(63-62))
-#define H_PP2             (1ULL<<(63-63))
-
-/* VASI States */
-#define H_VASI_INVALID    0
-#define H_VASI_ENABLED    1
-#define H_VASI_ABORTED    2
-#define H_VASI_SUSPENDING 3
-#define H_VASI_SUSPENDED  4
-#define H_VASI_RESUMED    5
-#define H_VASI_COMPLETED  6
-
-/* DABRX flags */
-#define H_DABRX_HYPERVISOR (1ULL<<(63-61))
-#define H_DABRX_KERNEL     (1ULL<<(63-62))
-#define H_DABRX_USER       (1ULL<<(63-63))
-
-/* Each control block has to be on a 4K boundary */
-#define H_CB_ALIGNMENT     4096
-
-/* pSeries hypervisor opcodes */
-#define H_REMOVE                0x04
-#define H_ENTER                 0x08
-#define H_READ                  0x0c
-#define H_CLEAR_MOD             0x10
-#define H_CLEAR_REF             0x14
-#define H_PROTECT               0x18
-#define H_GET_TCE               0x1c
-#define H_PUT_TCE               0x20
-#define H_SET_SPRG0             0x24
-#define H_SET_DABR              0x28
-#define H_PAGE_INIT             0x2c
-#define H_SET_ASR               0x30
-#define H_ASR_ON                0x34
-#define H_ASR_OFF               0x38
-#define H_LOGICAL_CI_LOAD       0x3c
-#define H_LOGICAL_CI_STORE      0x40
-#define H_LOGICAL_CACHE_LOAD    0x44
-#define H_LOGICAL_CACHE_STORE   0x48
-#define H_LOGICAL_ICBI          0x4c
-#define H_LOGICAL_DCBF          0x50
-#define H_GET_TERM_CHAR         0x54
-#define H_PUT_TERM_CHAR         0x58
-#define H_REAL_TO_LOGICAL       0x5c
-#define H_HYPERVISOR_DATA       0x60
-#define H_EOI                   0x64
-#define H_CPPR                  0x68
-#define H_IPI                   0x6c
-#define H_IPOLL                 0x70
-#define H_XIRR                  0x74
-#define H_PERFMON               0x7c
-#define H_MIGRATE_DMA           0x78
-#define H_REGISTER_VPA          0xDC
-#define H_CEDE                  0xE0
-#define H_CONFER                0xE4
-#define H_PROD                  0xE8
-#define H_GET_PPP               0xEC
-#define H_SET_PPP               0xF0
-#define H_PURR                  0xF4
-#define H_PIC                   0xF8
-#define H_REG_CRQ               0xFC
-#define H_FREE_CRQ              0x100
-#define H_VIO_SIGNAL            0x104
-#define H_SEND_CRQ              0x108
-#define H_COPY_RDMA             0x110
-#define H_REGISTER_LOGICAL_LAN  0x114
-#define H_FREE_LOGICAL_LAN      0x118
-#define H_ADD_LOGICAL_LAN_BUFFER 0x11C
-#define H_SEND_LOGICAL_LAN      0x120
-#define H_BULK_REMOVE           0x124
-#define H_MULTICAST_CTRL        0x130
-#define H_SET_XDABR             0x134
-#define H_STUFF_TCE             0x138
-#define H_PUT_TCE_INDIRECT      0x13C
-#define H_CHANGE_LOGICAL_LAN_MAC 0x14C
-#define H_VTERM_PARTNER_INFO    0x150
-#define H_REGISTER_VTERM        0x154
-#define H_FREE_VTERM            0x158
-#define H_RESET_EVENTS          0x15C
-#define H_ALLOC_RESOURCE        0x160
-#define H_FREE_RESOURCE         0x164
-#define H_MODIFY_QP             0x168
-#define H_QUERY_QP              0x16C
-#define H_REREGISTER_PMR        0x170
-#define H_REGISTER_SMR          0x174
-#define H_QUERY_MR              0x178
-#define H_QUERY_MW              0x17C
-#define H_QUERY_HCA             0x180
-#define H_QUERY_PORT            0x184
-#define H_MODIFY_PORT           0x188
-#define H_DEFINE_AQP1           0x18C
-#define H_GET_TRACE_BUFFER      0x190
-#define H_DEFINE_AQP0           0x194
-#define H_RESIZE_MR             0x198
-#define H_ATTACH_MCQP           0x19C
-#define H_DETACH_MCQP           0x1A0
-#define H_CREATE_RPT            0x1A4
-#define H_REMOVE_RPT            0x1A8
-#define H_REGISTER_RPAGES       0x1AC
-#define H_DISABLE_AND_GETC      0x1B0
-#define H_ERROR_DATA            0x1B4
-#define H_GET_HCA_INFO          0x1B8
-#define H_GET_PERF_COUNT        0x1BC
-#define H_MANAGE_TRACE          0x1C0
-#define H_FREE_LOGICAL_LAN_BUFFER 0x1D4
-#define H_QUERY_INT_STATE       0x1E4
-#define H_POLL_PENDING          0x1D8
-#define H_ILLAN_ATTRIBUTES      0x244
-#define H_MODIFY_HEA_QP         0x250
-#define H_QUERY_HEA_QP          0x254
-#define H_QUERY_HEA             0x258
-#define H_QUERY_HEA_PORT        0x25C
-#define H_MODIFY_HEA_PORT       0x260
-#define H_REG_BCMC              0x264
-#define H_DEREG_BCMC            0x268
-#define H_REGISTER_HEA_RPAGES   0x26C
-#define H_DISABLE_AND_GET_HEA   0x270
-#define H_GET_HEA_INFO          0x274
-#define H_ALLOC_HEA_RESOURCE    0x278
-#define H_ADD_CONN              0x284
-#define H_DEL_CONN              0x288
-#define H_JOIN                  0x298
-#define H_VASI_STATE            0x2A4
-#define H_ENABLE_CRQ            0x2B0
-#define H_GET_EM_PARMS          0x2B8
-#define H_SET_MPP               0x2D0
-#define H_GET_MPP               0x2D4
-#define MAX_HCALL_OPCODE        H_GET_MPP
-
-/* The hcalls above are standardized in PAPR and implemented by pHyp
- * as well.
- *
- * We also need some hcalls which are specific to qemu / KVM-on-POWER.
- * So far we just need one for H_RTAS, but in future we'll need more
- * for extensions like virtio.  We put those into the 0xf000-0xfffc
- * range which is reserved by PAPR for "platform-specific" hcalls.
- */
-#define KVMPPC_HCALL_BASE       0xf000
-#define KVMPPC_H_RTAS           (KVMPPC_HCALL_BASE + 0x0)
-#define KVMPPC_H_LOGICAL_MEMOP  (KVMPPC_HCALL_BASE + 0x1)
-#define KVMPPC_HCALL_MAX        KVMPPC_H_LOGICAL_MEMOP
-
-extern sPAPREnvironment *spapr;
-
-/*#define DEBUG_SPAPR_HCALLS*/
-
-#ifdef DEBUG_SPAPR_HCALLS
-#define hcall_dprintf(fmt, ...) \
-    do { fprintf(stderr, "%s: " fmt, __func__, ## __VA_ARGS__); } while (0)
-#else
-#define hcall_dprintf(fmt, ...) \
-    do { } while (0)
-#endif
-
-typedef target_ulong (*spapr_hcall_fn)(PowerPCCPU *cpu, sPAPREnvironment *spapr,
-                                       target_ulong opcode,
-                                       target_ulong *args);
-
-void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn);
-target_ulong spapr_hypercall(PowerPCCPU *cpu, target_ulong opcode,
-                             target_ulong *args);
-
-int spapr_allocate_irq(int hint, bool lsi);
-int spapr_allocate_irq_block(int num, bool lsi);
-
-static inline int spapr_allocate_msi(int hint)
-{
-    return spapr_allocate_irq(hint, false);
-}
-
-static inline int spapr_allocate_lsi(int hint)
-{
-    return spapr_allocate_irq(hint, true);
-}
-
-static inline uint32_t rtas_ld(target_ulong phys, int n)
-{
-    return ldl_be_phys(phys + 4*n);
-}
-
-static inline void rtas_st(target_ulong phys, int n, uint32_t val)
-{
-    stl_be_phys(phys + 4*n, val);
-}
-
-typedef void (*spapr_rtas_fn)(sPAPREnvironment *spapr, uint32_t token,
-                              uint32_t nargs, target_ulong args,
-                              uint32_t nret, target_ulong rets);
-int spapr_rtas_register(const char *name, spapr_rtas_fn fn);
-target_ulong spapr_rtas_call(sPAPREnvironment *spapr,
-                             uint32_t token, uint32_t nargs, target_ulong args,
-                             uint32_t nret, target_ulong rets);
-int spapr_rtas_device_tree_setup(void *fdt, hwaddr rtas_addr,
-                                 hwaddr rtas_size);
-
-#define SPAPR_TCE_PAGE_SHIFT   12
-#define SPAPR_TCE_PAGE_SIZE    (1ULL << SPAPR_TCE_PAGE_SHIFT)
-#define SPAPR_TCE_PAGE_MASK    (SPAPR_TCE_PAGE_SIZE - 1)
-
-typedef struct sPAPRTCE {
-    uint64_t tce;
-} sPAPRTCE;
-
-#define SPAPR_VIO_BASE_LIOBN    0x00000000
-#define SPAPR_PCI_BASE_LIOBN    0x80000000
-
-#define RTAS_ERROR_LOG_MAX      2048
-
-
-void spapr_iommu_init(void);
-void spapr_events_init(sPAPREnvironment *spapr);
-void spapr_events_fdt_skel(void *fdt, uint32_t epow_irq);
-DMAContext *spapr_tce_new_dma_context(uint32_t liobn, size_t window_size);
-void spapr_tce_free(DMAContext *dma);
-void spapr_tce_reset(DMAContext *dma);
-void spapr_tce_set_bypass(DMAContext *dma, bool bypass);
-int spapr_dma_dt(void *fdt, int node_off, const char *propname,
-                 uint32_t liobn, uint64_t window, uint32_t size);
-int spapr_tcet_dma_dt(void *fdt, int node_off, const char *propname,
-                      DMAContext *dma);
-
-#endif /* !defined (__HW_SPAPR_H__) */
diff --git a/hw/spapr_llan.c b/hw/spapr_llan.c
deleted file mode 100644 (file)
index 19701e7..0000000
+++ /dev/null
@@ -1,531 +0,0 @@
-/*
- * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator
- *
- * PAPR Inter-VM Logical Lan, aka ibmveth
- *
- * Copyright (c) 2010,2011 David Gibson, IBM Corporation.
- *
- * 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 "hw/hw.h"
-#include "net/net.h"
-#include "hw/qdev.h"
-#include "hw/spapr.h"
-#include "hw/spapr_vio.h"
-
-#include <libfdt.h>
-
-#define ETH_ALEN        6
-#define MAX_PACKET_SIZE 65536
-
-/*#define DEBUG*/
-
-#ifdef DEBUG
-#define dprintf(fmt...) do { fprintf(stderr, fmt); } while (0)
-#else
-#define dprintf(fmt...)
-#endif
-
-/*
- * Virtual LAN device
- */
-
-typedef uint64_t vlan_bd_t;
-
-#define VLAN_BD_VALID        0x8000000000000000ULL
-#define VLAN_BD_TOGGLE       0x4000000000000000ULL
-#define VLAN_BD_NO_CSUM      0x0200000000000000ULL
-#define VLAN_BD_CSUM_GOOD    0x0100000000000000ULL
-#define VLAN_BD_LEN_MASK     0x00ffffff00000000ULL
-#define VLAN_BD_LEN(bd)      (((bd) & VLAN_BD_LEN_MASK) >> 32)
-#define VLAN_BD_ADDR_MASK    0x00000000ffffffffULL
-#define VLAN_BD_ADDR(bd)     ((bd) & VLAN_BD_ADDR_MASK)
-
-#define VLAN_VALID_BD(addr, len) (VLAN_BD_VALID | \
-                                  (((len) << 32) & VLAN_BD_LEN_MASK) |  \
-                                  (addr & VLAN_BD_ADDR_MASK))
-
-#define VLAN_RXQC_TOGGLE     0x80
-#define VLAN_RXQC_VALID      0x40
-#define VLAN_RXQC_NO_CSUM    0x02
-#define VLAN_RXQC_CSUM_GOOD  0x01
-
-#define VLAN_RQ_ALIGNMENT    16
-#define VLAN_RXQ_BD_OFF      0
-#define VLAN_FILTER_BD_OFF   8
-#define VLAN_RX_BDS_OFF      16
-#define VLAN_MAX_BUFS        ((SPAPR_TCE_PAGE_SIZE - VLAN_RX_BDS_OFF) / 8)
-
-typedef struct VIOsPAPRVLANDevice {
-    VIOsPAPRDevice sdev;
-    NICConf nicconf;
-    NICState *nic;
-    int isopen;
-    target_ulong buf_list;
-    int add_buf_ptr, use_buf_ptr, rx_bufs;
-    target_ulong rxq_ptr;
-} VIOsPAPRVLANDevice;
-
-static int spapr_vlan_can_receive(NetClientState *nc)
-{
-    VIOsPAPRVLANDevice *dev = qemu_get_nic_opaque(nc);
-
-    return (dev->isopen && dev->rx_bufs > 0);
-}
-
-static ssize_t spapr_vlan_receive(NetClientState *nc, const uint8_t *buf,
-                                  size_t size)
-{
-    VIOsPAPRDevice *sdev = qemu_get_nic_opaque(nc);
-    VIOsPAPRVLANDevice *dev = (VIOsPAPRVLANDevice *)sdev;
-    vlan_bd_t rxq_bd = vio_ldq(sdev, dev->buf_list + VLAN_RXQ_BD_OFF);
-    vlan_bd_t bd;
-    int buf_ptr = dev->use_buf_ptr;
-    uint64_t handle;
-    uint8_t control;
-
-    dprintf("spapr_vlan_receive() [%s] rx_bufs=%d\n", sdev->qdev.id,
-            dev->rx_bufs);
-
-    if (!dev->isopen) {
-        return -1;
-    }
-
-    if (!dev->rx_bufs) {
-        return -1;
-    }
-
-    do {
-        buf_ptr += 8;
-        if (buf_ptr >= SPAPR_TCE_PAGE_SIZE) {
-            buf_ptr = VLAN_RX_BDS_OFF;
-        }
-
-        bd = vio_ldq(sdev, dev->buf_list + buf_ptr);
-        dprintf("use_buf_ptr=%d bd=0x%016llx\n",
-                buf_ptr, (unsigned long long)bd);
-    } while ((!(bd & VLAN_BD_VALID) || (VLAN_BD_LEN(bd) < (size + 8)))
-             && (buf_ptr != dev->use_buf_ptr));
-
-    if (!(bd & VLAN_BD_VALID) || (VLAN_BD_LEN(bd) < (size + 8))) {
-        /* Failed to find a suitable buffer */
-        return -1;
-    }
-
-    /* Remove the buffer from the pool */
-    dev->rx_bufs--;
-    dev->use_buf_ptr = buf_ptr;
-    vio_stq(sdev, dev->buf_list + dev->use_buf_ptr, 0);
-
-    dprintf("Found buffer: ptr=%d num=%d\n", dev->use_buf_ptr, dev->rx_bufs);
-
-    /* Transfer the packet data */
-    if (spapr_vio_dma_write(sdev, VLAN_BD_ADDR(bd) + 8, buf, size) < 0) {
-        return -1;
-    }
-
-    dprintf("spapr_vlan_receive: DMA write completed\n");
-
-    /* Update the receive queue */
-    control = VLAN_RXQC_TOGGLE | VLAN_RXQC_VALID;
-    if (rxq_bd & VLAN_BD_TOGGLE) {
-        control ^= VLAN_RXQC_TOGGLE;
-    }
-
-    handle = vio_ldq(sdev, VLAN_BD_ADDR(bd));
-    vio_stq(sdev, VLAN_BD_ADDR(rxq_bd) + dev->rxq_ptr + 8, handle);
-    vio_stl(sdev, VLAN_BD_ADDR(rxq_bd) + dev->rxq_ptr + 4, size);
-    vio_sth(sdev, VLAN_BD_ADDR(rxq_bd) + dev->rxq_ptr + 2, 8);
-    vio_stb(sdev, VLAN_BD_ADDR(rxq_bd) + dev->rxq_ptr, control);
-
-    dprintf("wrote rxq entry (ptr=0x%llx): 0x%016llx 0x%016llx\n",
-            (unsigned long long)dev->rxq_ptr,
-            (unsigned long long)vio_ldq(sdev, VLAN_BD_ADDR(rxq_bd) +
-                                        dev->rxq_ptr),
-            (unsigned long long)vio_ldq(sdev, VLAN_BD_ADDR(rxq_bd) +
-                                        dev->rxq_ptr + 8));
-
-    dev->rxq_ptr += 16;
-    if (dev->rxq_ptr >= VLAN_BD_LEN(rxq_bd)) {
-        dev->rxq_ptr = 0;
-        vio_stq(sdev, dev->buf_list + VLAN_RXQ_BD_OFF, rxq_bd ^ VLAN_BD_TOGGLE);
-    }
-
-    if (sdev->signal_state & 1) {
-        qemu_irq_pulse(spapr_vio_qirq(sdev));
-    }
-
-    return size;
-}
-
-static void spapr_vlan_cleanup(NetClientState *nc)
-{
-    VIOsPAPRVLANDevice *dev = qemu_get_nic_opaque(nc);
-
-    dev->nic = NULL;
-}
-
-static NetClientInfo net_spapr_vlan_info = {
-    .type = NET_CLIENT_OPTIONS_KIND_NIC,
-    .size = sizeof(NICState),
-    .can_receive = spapr_vlan_can_receive,
-    .receive = spapr_vlan_receive,
-    .cleanup = spapr_vlan_cleanup,
-};
-
-static void spapr_vlan_reset(VIOsPAPRDevice *sdev)
-{
-    VIOsPAPRVLANDevice *dev = DO_UPCAST(VIOsPAPRVLANDevice, sdev, sdev);
-
-    dev->buf_list = 0;
-    dev->rx_bufs = 0;
-    dev->isopen = 0;
-}
-
-static int spapr_vlan_init(VIOsPAPRDevice *sdev)
-{
-    VIOsPAPRVLANDevice *dev = (VIOsPAPRVLANDevice *)sdev;
-
-    qemu_macaddr_default_if_unset(&dev->nicconf.macaddr);
-
-    dev->nic = qemu_new_nic(&net_spapr_vlan_info, &dev->nicconf,
-                            object_get_typename(OBJECT(sdev)), sdev->qdev.id, dev);
-    qemu_format_nic_info_str(qemu_get_queue(dev->nic), dev->nicconf.macaddr.a);
-
-    return 0;
-}
-
-void spapr_vlan_create(VIOsPAPRBus *bus, NICInfo *nd)
-{
-    DeviceState *dev;
-
-    dev = qdev_create(&bus->bus, "spapr-vlan");
-
-    qdev_set_nic_properties(dev, nd);
-
-    qdev_init_nofail(dev);
-}
-
-static int spapr_vlan_devnode(VIOsPAPRDevice *dev, void *fdt, int node_off)
-{
-    VIOsPAPRVLANDevice *vdev = (VIOsPAPRVLANDevice *)dev;
-    uint8_t padded_mac[8] = {0, 0};
-    int ret;
-
-    /* Some old phyp versions give the mac address in an 8-byte
-     * property.  The kernel driver has an insane workaround for this;
-     * rather than doing the obvious thing and checking the property
-     * length, it checks whether the first byte has 0b10 in the low
-     * bits.  If a correct 6-byte property has a different first byte
-     * the kernel will get the wrong mac address, overrunning its
-     * buffer in the process (read only, thank goodness).
-     *
-     * Here we workaround the kernel workaround by always supplying an
-     * 8-byte property, with the mac address in the last six bytes */
-    memcpy(&padded_mac[2], &vdev->nicconf.macaddr, ETH_ALEN);
-    ret = fdt_setprop(fdt, node_off, "local-mac-address",
-                      padded_mac, sizeof(padded_mac));
-    if (ret < 0) {
-        return ret;
-    }
-
-    ret = fdt_setprop_cell(fdt, node_off, "ibm,mac-address-filters", 0);
-    if (ret < 0) {
-        return ret;
-    }
-
-    return 0;
-}
-
-static int check_bd(VIOsPAPRVLANDevice *dev, vlan_bd_t bd,
-                    target_ulong alignment)
-{
-    if ((VLAN_BD_ADDR(bd) % alignment)
-        || (VLAN_BD_LEN(bd) % alignment)) {
-        return -1;
-    }
-
-    if (!spapr_vio_dma_valid(&dev->sdev, VLAN_BD_ADDR(bd),
-                             VLAN_BD_LEN(bd), DMA_DIRECTION_FROM_DEVICE)
-        || !spapr_vio_dma_valid(&dev->sdev, VLAN_BD_ADDR(bd),
-                                VLAN_BD_LEN(bd), DMA_DIRECTION_TO_DEVICE)) {
-        return -1;
-    }
-
-    return 0;
-}
-
-static target_ulong h_register_logical_lan(PowerPCCPU *cpu,
-                                           sPAPREnvironment *spapr,
-                                           target_ulong opcode,
-                                           target_ulong *args)
-{
-    target_ulong reg = args[0];
-    target_ulong buf_list = args[1];
-    target_ulong rec_queue = args[2];
-    target_ulong filter_list = args[3];
-    VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
-    VIOsPAPRVLANDevice *dev = (VIOsPAPRVLANDevice *)sdev;
-    vlan_bd_t filter_list_bd;
-
-    if (!dev) {
-        return H_PARAMETER;
-    }
-
-    if (dev->isopen) {
-        hcall_dprintf("H_REGISTER_LOGICAL_LAN called twice without "
-                      "H_FREE_LOGICAL_LAN\n");
-        return H_RESOURCE;
-    }
-
-    if (check_bd(dev, VLAN_VALID_BD(buf_list, SPAPR_TCE_PAGE_SIZE),
-                 SPAPR_TCE_PAGE_SIZE) < 0) {
-        hcall_dprintf("Bad buf_list 0x" TARGET_FMT_lx "\n", buf_list);
-        return H_PARAMETER;
-    }
-
-    filter_list_bd = VLAN_VALID_BD(filter_list, SPAPR_TCE_PAGE_SIZE);
-    if (check_bd(dev, filter_list_bd, SPAPR_TCE_PAGE_SIZE) < 0) {
-        hcall_dprintf("Bad filter_list 0x" TARGET_FMT_lx "\n", filter_list);
-        return H_PARAMETER;
-    }
-
-    if (!(rec_queue & VLAN_BD_VALID)
-        || (check_bd(dev, rec_queue, VLAN_RQ_ALIGNMENT) < 0)) {
-        hcall_dprintf("Bad receive queue\n");
-        return H_PARAMETER;
-    }
-
-    dev->buf_list = buf_list;
-    sdev->signal_state = 0;
-
-    rec_queue &= ~VLAN_BD_TOGGLE;
-
-    /* Initialize the buffer list */
-    vio_stq(sdev, buf_list, rec_queue);
-    vio_stq(sdev, buf_list + 8, filter_list_bd);
-    spapr_vio_dma_set(sdev, buf_list + VLAN_RX_BDS_OFF, 0,
-                      SPAPR_TCE_PAGE_SIZE - VLAN_RX_BDS_OFF);
-    dev->add_buf_ptr = VLAN_RX_BDS_OFF - 8;
-    dev->use_buf_ptr = VLAN_RX_BDS_OFF - 8;
-    dev->rx_bufs = 0;
-    dev->rxq_ptr = 0;
-
-    /* Initialize the receive queue */
-    spapr_vio_dma_set(sdev, VLAN_BD_ADDR(rec_queue), 0, VLAN_BD_LEN(rec_queue));
-
-    dev->isopen = 1;
-    return H_SUCCESS;
-}
-
-
-static target_ulong h_free_logical_lan(PowerPCCPU *cpu, sPAPREnvironment *spapr,
-                                       target_ulong opcode, target_ulong *args)
-{
-    target_ulong reg = args[0];
-    VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
-    VIOsPAPRVLANDevice *dev = (VIOsPAPRVLANDevice *)sdev;
-
-    if (!dev) {
-        return H_PARAMETER;
-    }
-
-    if (!dev->isopen) {
-        hcall_dprintf("H_FREE_LOGICAL_LAN called without "
-                      "H_REGISTER_LOGICAL_LAN\n");
-        return H_RESOURCE;
-    }
-
-    spapr_vlan_reset(sdev);
-    return H_SUCCESS;
-}
-
-static target_ulong h_add_logical_lan_buffer(PowerPCCPU *cpu,
-                                             sPAPREnvironment *spapr,
-                                             target_ulong opcode,
-                                             target_ulong *args)
-{
-    target_ulong reg = args[0];
-    target_ulong buf = args[1];
-    VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
-    VIOsPAPRVLANDevice *dev = (VIOsPAPRVLANDevice *)sdev;
-    vlan_bd_t bd;
-
-    dprintf("H_ADD_LOGICAL_LAN_BUFFER(0x" TARGET_FMT_lx
-            ", 0x" TARGET_FMT_lx ")\n", reg, buf);
-
-    if (!sdev) {
-        hcall_dprintf("Bad device\n");
-        return H_PARAMETER;
-    }
-
-    if ((check_bd(dev, buf, 4) < 0)
-        || (VLAN_BD_LEN(buf) < 16)) {
-        hcall_dprintf("Bad buffer enqueued\n");
-        return H_PARAMETER;
-    }
-
-    if (!dev->isopen || dev->rx_bufs >= VLAN_MAX_BUFS) {
-        return H_RESOURCE;
-    }
-
-    do {
-        dev->add_buf_ptr += 8;
-        if (dev->add_buf_ptr >= SPAPR_TCE_PAGE_SIZE) {
-            dev->add_buf_ptr = VLAN_RX_BDS_OFF;
-        }
-
-        bd = vio_ldq(sdev, dev->buf_list + dev->add_buf_ptr);
-    } while (bd & VLAN_BD_VALID);
-
-    vio_stq(sdev, dev->buf_list + dev->add_buf_ptr, buf);
-
-    dev->rx_bufs++;
-
-    dprintf("h_add_logical_lan_buffer():  Added buf  ptr=%d  rx_bufs=%d"
-            " bd=0x%016llx\n", dev->add_buf_ptr, dev->rx_bufs,
-            (unsigned long long)buf);
-
-    return H_SUCCESS;
-}
-
-static target_ulong h_send_logical_lan(PowerPCCPU *cpu, sPAPREnvironment *spapr,
-                                       target_ulong opcode, target_ulong *args)
-{
-    target_ulong reg = args[0];
-    target_ulong *bufs = args + 1;
-    target_ulong continue_token = args[7];
-    VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
-    VIOsPAPRVLANDevice *dev = (VIOsPAPRVLANDevice *)sdev;
-    unsigned total_len;
-    uint8_t *lbuf, *p;
-    int i, nbufs;
-    int ret;
-
-    dprintf("H_SEND_LOGICAL_LAN(0x" TARGET_FMT_lx ", <bufs>, 0x"
-            TARGET_FMT_lx ")\n", reg, continue_token);
-
-    if (!sdev) {
-        return H_PARAMETER;
-    }
-
-    dprintf("rxbufs = %d\n", dev->rx_bufs);
-
-    if (!dev->isopen) {
-        return H_DROPPED;
-    }
-
-    if (continue_token) {
-        return H_HARDWARE; /* FIXME actually handle this */
-    }
-
-    total_len = 0;
-    for (i = 0; i < 6; i++) {
-        dprintf("   buf desc: 0x" TARGET_FMT_lx "\n", bufs[i]);
-        if (!(bufs[i] & VLAN_BD_VALID)) {
-            break;
-        }
-        total_len += VLAN_BD_LEN(bufs[i]);
-    }
-
-    nbufs = i;
-    dprintf("h_send_logical_lan() %d buffers, total length 0x%x\n",
-            nbufs, total_len);
-
-    if (total_len == 0) {
-        return H_SUCCESS;
-    }
-
-    if (total_len > MAX_PACKET_SIZE) {
-        /* Don't let the guest force too large an allocation */
-        return H_RESOURCE;
-    }
-
-    lbuf = alloca(total_len);
-    p = lbuf;
-    for (i = 0; i < nbufs; i++) {
-        ret = spapr_vio_dma_read(sdev, VLAN_BD_ADDR(bufs[i]),
-                                 p, VLAN_BD_LEN(bufs[i]));
-        if (ret < 0) {
-            return ret;
-        }
-
-        p += VLAN_BD_LEN(bufs[i]);
-    }
-
-    qemu_send_packet(qemu_get_queue(dev->nic), lbuf, total_len);
-
-    return H_SUCCESS;
-}
-
-static target_ulong h_multicast_ctrl(PowerPCCPU *cpu, sPAPREnvironment *spapr,
-                                     target_ulong opcode, target_ulong *args)
-{
-    target_ulong reg = args[0];
-    VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
-
-    if (!dev) {
-        return H_PARAMETER;
-    }
-
-    return H_SUCCESS;
-}
-
-static Property spapr_vlan_properties[] = {
-    DEFINE_SPAPR_PROPERTIES(VIOsPAPRVLANDevice, sdev),
-    DEFINE_NIC_PROPERTIES(VIOsPAPRVLANDevice, nicconf),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void spapr_vlan_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    VIOsPAPRDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass);
-
-    k->init = spapr_vlan_init;
-    k->reset = spapr_vlan_reset;
-    k->devnode = spapr_vlan_devnode;
-    k->dt_name = "l-lan";
-    k->dt_type = "network";
-    k->dt_compatible = "IBM,l-lan";
-    k->signal_mask = 0x1;
-    dc->props = spapr_vlan_properties;
-    k->rtce_window_size = 0x10000000;
-}
-
-static const 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_types(void)
-{
-    spapr_register_hypercall(H_REGISTER_LOGICAL_LAN, h_register_logical_lan);
-    spapr_register_hypercall(H_FREE_LOGICAL_LAN, h_free_logical_lan);
-    spapr_register_hypercall(H_SEND_LOGICAL_LAN, h_send_logical_lan);
-    spapr_register_hypercall(H_ADD_LOGICAL_LAN_BUFFER,
-                             h_add_logical_lan_buffer);
-    spapr_register_hypercall(H_MULTICAST_CTRL, h_multicast_ctrl);
-    type_register_static(&spapr_vlan_info);
-}
-
-type_init(spapr_vlan_register_types)
diff --git a/hw/spapr_nvram.c b/hw/spapr_nvram.c
deleted file mode 100644 (file)
index 680cdba..0000000
+++ /dev/null
@@ -1,196 +0,0 @@
-/*
- * QEMU sPAPR NVRAM emulation
- *
- * Copyright (C) 2012 David Gibson, IBM Corporation.
- *
- * 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 <libfdt.h>
-
-#include "sysemu/device_tree.h"
-#include "hw/sysbus.h"
-#include "hw/spapr.h"
-#include "hw/spapr_vio.h"
-
-typedef struct sPAPRNVRAM {
-    VIOsPAPRDevice sdev;
-    uint32_t size;
-    uint8_t *buf;
-    BlockDriverState *drive;
-} sPAPRNVRAM;
-
-#define MIN_NVRAM_SIZE 8192
-#define DEFAULT_NVRAM_SIZE 65536
-#define MAX_NVRAM_SIZE (UINT16_MAX * 16)
-
-static void rtas_nvram_fetch(sPAPREnvironment *spapr,
-                             uint32_t token, uint32_t nargs,
-                             target_ulong args,
-                             uint32_t nret, target_ulong rets)
-{
-    sPAPRNVRAM *nvram = spapr->nvram;
-    hwaddr offset, buffer, len;
-    int alen;
-    void *membuf;
-
-    if ((nargs != 3) || (nret != 2)) {
-        rtas_st(rets, 0, -3);
-        return;
-    }
-
-    if (!nvram) {
-        rtas_st(rets, 0, -1);
-        rtas_st(rets, 1, 0);
-        return;
-    }
-
-    offset = rtas_ld(args, 0);
-    buffer = rtas_ld(args, 1);
-    len = rtas_ld(args, 2);
-
-    if (((offset + len) < offset)
-        || ((offset + len) > nvram->size)) {
-        rtas_st(rets, 0, -3);
-        rtas_st(rets, 1, 0);
-        return;
-    }
-
-    membuf = cpu_physical_memory_map(buffer, &len, 1);
-    if (nvram->drive) {
-        alen = bdrv_pread(nvram->drive, offset, membuf, len);
-    } else {
-        assert(nvram->buf);
-
-        memcpy(membuf, nvram->buf + offset, len);
-        alen = len;
-    }
-    cpu_physical_memory_unmap(membuf, len, 1, len);
-
-    rtas_st(rets, 0, (alen < len) ? -1 : 0);
-    rtas_st(rets, 1, (alen < 0) ? 0 : alen);
-}
-
-static void rtas_nvram_store(sPAPREnvironment *spapr,
-                             uint32_t token, uint32_t nargs,
-                             target_ulong args,
-                             uint32_t nret, target_ulong rets)
-{
-    sPAPRNVRAM *nvram = spapr->nvram;
-    hwaddr offset, buffer, len;
-    int alen;
-    void *membuf;
-
-    if ((nargs != 3) || (nret != 2)) {
-        rtas_st(rets, 0, -3);
-        return;
-    }
-
-    if (!nvram) {
-        rtas_st(rets, 0, -1);
-        return;
-    }
-
-    offset = rtas_ld(args, 0);
-    buffer = rtas_ld(args, 1);
-    len = rtas_ld(args, 2);
-
-    if (((offset + len) < offset)
-        || ((offset + len) > nvram->size)) {
-        rtas_st(rets, 0, -3);
-        return;
-    }
-
-    membuf = cpu_physical_memory_map(buffer, &len, 0);
-    if (nvram->drive) {
-        alen = bdrv_pwrite(nvram->drive, offset, membuf, len);
-    } else {
-        assert(nvram->buf);
-
-        memcpy(nvram->buf + offset, membuf, len);
-        alen = len;
-    }
-    cpu_physical_memory_unmap(membuf, len, 0, len);
-
-    rtas_st(rets, 0, (alen < len) ? -1 : 0);
-    rtas_st(rets, 1, (alen < 0) ? 0 : alen);
-}
-
-static int spapr_nvram_init(VIOsPAPRDevice *dev)
-{
-    sPAPRNVRAM *nvram = (sPAPRNVRAM *)dev;
-
-    if (nvram->drive) {
-        nvram->size = bdrv_getlength(nvram->drive);
-    } else {
-        nvram->size = DEFAULT_NVRAM_SIZE;
-        nvram->buf = g_malloc0(nvram->size);
-    }
-
-    if ((nvram->size < MIN_NVRAM_SIZE) || (nvram->size > MAX_NVRAM_SIZE)) {
-        fprintf(stderr, "spapr-nvram must be between %d and %d bytes in size\n",
-                MIN_NVRAM_SIZE, MAX_NVRAM_SIZE);
-        return -1;
-    }
-
-    spapr_rtas_register("nvram-fetch", rtas_nvram_fetch);
-    spapr_rtas_register("nvram-store", rtas_nvram_store);
-
-    return 0;
-}
-
-static int spapr_nvram_devnode(VIOsPAPRDevice *dev, void *fdt, int node_off)
-{
-    sPAPRNVRAM *nvram = (sPAPRNVRAM *)dev;
-
-    return fdt_setprop_cell(fdt, node_off, "#bytes", nvram->size);
-}
-
-static Property spapr_nvram_properties[] = {
-    DEFINE_SPAPR_PROPERTIES(sPAPRNVRAM, sdev),
-    DEFINE_PROP_DRIVE("drive", sPAPRNVRAM, drive),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void spapr_nvram_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    VIOsPAPRDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass);
-
-    k->init = spapr_nvram_init;
-    k->devnode = spapr_nvram_devnode;
-    k->dt_name = "nvram";
-    k->dt_type = "nvram";
-    k->dt_compatible = "qemu,spapr-nvram";
-    dc->props = spapr_nvram_properties;
-}
-
-static const TypeInfo spapr_nvram_type_info = {
-    .name          = "spapr-nvram",
-    .parent        = TYPE_VIO_SPAPR_DEVICE,
-    .instance_size = sizeof(sPAPRNVRAM),
-    .class_init    = spapr_nvram_class_init,
-};
-
-static void spapr_nvram_register_types(void)
-{
-    type_register_static(&spapr_nvram_type_info);
-}
-
-type_init(spapr_nvram_register_types)
diff --git a/hw/spapr_pci.c b/hw/spapr_pci.c
deleted file mode 100644 (file)
index 3e0d8d1..0000000
+++ /dev/null
@@ -1,839 +0,0 @@
-/*
- * QEMU sPAPR PCI host originated from Uninorth PCI host
- *
- * Copyright (c) 2011 Alexey Kardashevskiy, IBM Corporation.
- * Copyright (C) 2011 David Gibson, IBM Corporation.
- *
- * 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 "hw/hw.h"
-#include "hw/pci/pci.h"
-#include "hw/pci/msi.h"
-#include "hw/pci/msix.h"
-#include "hw/pci/pci_host.h"
-#include "hw/spapr.h"
-#include "hw/spapr_pci.h"
-#include "exec/address-spaces.h"
-#include <libfdt.h>
-#include "trace.h"
-
-#include "hw/pci/pci_bus.h"
-
-/* Copied from the kernel arch/powerpc/platforms/pseries/msi.c */
-#define RTAS_QUERY_FN           0
-#define RTAS_CHANGE_FN          1
-#define RTAS_RESET_FN           2
-#define RTAS_CHANGE_MSI_FN      3
-#define RTAS_CHANGE_MSIX_FN     4
-
-/* Interrupt types to return on RTAS_CHANGE_* */
-#define RTAS_TYPE_MSI           1
-#define RTAS_TYPE_MSIX          2
-
-static sPAPRPHBState *find_phb(sPAPREnvironment *spapr, uint64_t buid)
-{
-    sPAPRPHBState *sphb;
-
-    QLIST_FOREACH(sphb, &spapr->phbs, list) {
-        if (sphb->buid != buid) {
-            continue;
-        }
-        return sphb;
-    }
-
-    return NULL;
-}
-
-static PCIDevice *find_dev(sPAPREnvironment *spapr, uint64_t buid,
-                           uint32_t config_addr)
-{
-    sPAPRPHBState *sphb = find_phb(spapr, buid);
-    PCIHostState *phb = PCI_HOST_BRIDGE(sphb);
-    BusState *bus = BUS(phb->bus);
-    BusChild *kid;
-    int devfn = (config_addr >> 8) & 0xFF;
-
-    if (!phb) {
-        return NULL;
-    }
-
-    QTAILQ_FOREACH(kid, &bus->children, sibling) {
-        PCIDevice *dev = (PCIDevice *)kid->child;
-        if (dev->devfn == devfn) {
-            return dev;
-        }
-    }
-
-    return NULL;
-}
-
-static uint32_t rtas_pci_cfgaddr(uint32_t arg)
-{
-    /* This handles the encoding of extended config space addresses */
-    return ((arg >> 20) & 0xf00) | (arg & 0xff);
-}
-
-static void finish_read_pci_config(sPAPREnvironment *spapr, uint64_t buid,
-                                   uint32_t addr, uint32_t size,
-                                   target_ulong rets)
-{
-    PCIDevice *pci_dev;
-    uint32_t val;
-
-    if ((size != 1) && (size != 2) && (size != 4)) {
-        /* access must be 1, 2 or 4 bytes */
-        rtas_st(rets, 0, -1);
-        return;
-    }
-
-    pci_dev = find_dev(spapr, buid, addr);
-    addr = rtas_pci_cfgaddr(addr);
-
-    if (!pci_dev || (addr % size) || (addr >= pci_config_size(pci_dev))) {
-        /* Access must be to a valid device, within bounds and
-         * naturally aligned */
-        rtas_st(rets, 0, -1);
-        return;
-    }
-
-    val = pci_host_config_read_common(pci_dev, addr,
-                                      pci_config_size(pci_dev), size);
-
-    rtas_st(rets, 0, 0);
-    rtas_st(rets, 1, val);
-}
-
-static void rtas_ibm_read_pci_config(sPAPREnvironment *spapr,
-                                     uint32_t token, uint32_t nargs,
-                                     target_ulong args,
-                                     uint32_t nret, target_ulong rets)
-{
-    uint64_t buid;
-    uint32_t size, addr;
-
-    if ((nargs != 4) || (nret != 2)) {
-        rtas_st(rets, 0, -1);
-        return;
-    }
-
-    buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2);
-    size = rtas_ld(args, 3);
-    addr = rtas_ld(args, 0);
-
-    finish_read_pci_config(spapr, buid, addr, size, rets);
-}
-
-static void rtas_read_pci_config(sPAPREnvironment *spapr,
-                                 uint32_t token, uint32_t nargs,
-                                 target_ulong args,
-                                 uint32_t nret, target_ulong rets)
-{
-    uint32_t size, addr;
-
-    if ((nargs != 2) || (nret != 2)) {
-        rtas_st(rets, 0, -1);
-        return;
-    }
-
-    size = rtas_ld(args, 1);
-    addr = rtas_ld(args, 0);
-
-    finish_read_pci_config(spapr, 0, addr, size, rets);
-}
-
-static void finish_write_pci_config(sPAPREnvironment *spapr, uint64_t buid,
-                                    uint32_t addr, uint32_t size,
-                                    uint32_t val, target_ulong rets)
-{
-    PCIDevice *pci_dev;
-
-    if ((size != 1) && (size != 2) && (size != 4)) {
-        /* access must be 1, 2 or 4 bytes */
-        rtas_st(rets, 0, -1);
-        return;
-    }
-
-    pci_dev = find_dev(spapr, buid, addr);
-    addr = rtas_pci_cfgaddr(addr);
-
-    if (!pci_dev || (addr % size) || (addr >= pci_config_size(pci_dev))) {
-        /* Access must be to a valid device, within bounds and
-         * naturally aligned */
-        rtas_st(rets, 0, -1);
-        return;
-    }
-
-    pci_host_config_write_common(pci_dev, addr, pci_config_size(pci_dev),
-                                 val, size);
-
-    rtas_st(rets, 0, 0);
-}
-
-static void rtas_ibm_write_pci_config(sPAPREnvironment *spapr,
-                                      uint32_t token, uint32_t nargs,
-                                      target_ulong args,
-                                      uint32_t nret, target_ulong rets)
-{
-    uint64_t buid;
-    uint32_t val, size, addr;
-
-    if ((nargs != 5) || (nret != 1)) {
-        rtas_st(rets, 0, -1);
-        return;
-    }
-
-    buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2);
-    val = rtas_ld(args, 4);
-    size = rtas_ld(args, 3);
-    addr = rtas_ld(args, 0);
-
-    finish_write_pci_config(spapr, buid, addr, size, val, rets);
-}
-
-static void rtas_write_pci_config(sPAPREnvironment *spapr,
-                                  uint32_t token, uint32_t nargs,
-                                  target_ulong args,
-                                  uint32_t nret, target_ulong rets)
-{
-    uint32_t val, size, addr;
-
-    if ((nargs != 3) || (nret != 1)) {
-        rtas_st(rets, 0, -1);
-        return;
-    }
-
-
-    val = rtas_ld(args, 2);
-    size = rtas_ld(args, 1);
-    addr = rtas_ld(args, 0);
-
-    finish_write_pci_config(spapr, 0, addr, size, val, rets);
-}
-
-/*
- * Find an entry with config_addr or returns the empty one if not found AND
- * alloc_new is set.
- * At the moment the msi_table entries are never released so there is
- * no point to look till the end of the list if we need to find the free entry.
- */
-static int spapr_msicfg_find(sPAPRPHBState *phb, uint32_t config_addr,
-                             bool alloc_new)
-{
-    int i;
-
-    for (i = 0; i < SPAPR_MSIX_MAX_DEVS; ++i) {
-        if (!phb->msi_table[i].nvec) {
-            break;
-        }
-        if (phb->msi_table[i].config_addr == config_addr) {
-            return i;
-        }
-    }
-    if ((i < SPAPR_MSIX_MAX_DEVS) && alloc_new) {
-        trace_spapr_pci_msi("Allocating new MSI config", i, config_addr);
-        return i;
-    }
-
-    return -1;
-}
-
-/*
- * Set MSI/MSIX message data.
- * This is required for msi_notify()/msix_notify() which
- * will write at the addresses via spapr_msi_write().
- */
-static void spapr_msi_setmsg(PCIDevice *pdev, hwaddr addr,
-                             bool msix, unsigned req_num)
-{
-    unsigned i;
-    MSIMessage msg = { .address = addr, .data = 0 };
-
-    if (!msix) {
-        msi_set_message(pdev, msg);
-        trace_spapr_pci_msi_setup(pdev->name, 0, msg.address);
-        return;
-    }
-
-    for (i = 0; i < req_num; ++i) {
-        msg.address = addr | (i << 2);
-        msix_set_message(pdev, i, msg);
-        trace_spapr_pci_msi_setup(pdev->name, i, msg.address);
-    }
-}
-
-static void rtas_ibm_change_msi(sPAPREnvironment *spapr,
-                                uint32_t token, uint32_t nargs,
-                                target_ulong args, uint32_t nret,
-                                target_ulong rets)
-{
-    uint32_t config_addr = rtas_ld(args, 0);
-    uint64_t buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2);
-    unsigned int func = rtas_ld(args, 3);
-    unsigned int req_num = rtas_ld(args, 4); /* 0 == remove all */
-    unsigned int seq_num = rtas_ld(args, 5);
-    unsigned int ret_intr_type;
-    int ndev, irq;
-    sPAPRPHBState *phb = NULL;
-    PCIDevice *pdev = NULL;
-
-    switch (func) {
-    case RTAS_CHANGE_MSI_FN:
-    case RTAS_CHANGE_FN:
-        ret_intr_type = RTAS_TYPE_MSI;
-        break;
-    case RTAS_CHANGE_MSIX_FN:
-        ret_intr_type = RTAS_TYPE_MSIX;
-        break;
-    default:
-        fprintf(stderr, "rtas_ibm_change_msi(%u) is not implemented\n", func);
-        rtas_st(rets, 0, -3); /* Parameter error */
-        return;
-    }
-
-    /* Fins sPAPRPHBState */
-    phb = find_phb(spapr, buid);
-    if (phb) {
-        pdev = find_dev(spapr, buid, config_addr);
-    }
-    if (!phb || !pdev) {
-        rtas_st(rets, 0, -3); /* Parameter error */
-        return;
-    }
-
-    /* Releasing MSIs */
-    if (!req_num) {
-        ndev = spapr_msicfg_find(phb, config_addr, false);
-        if (ndev < 0) {
-            trace_spapr_pci_msi("MSI has not been enabled", -1, config_addr);
-            rtas_st(rets, 0, -1); /* Hardware error */
-            return;
-        }
-        trace_spapr_pci_msi("Released MSIs", ndev, config_addr);
-        rtas_st(rets, 0, 0);
-        rtas_st(rets, 1, 0);
-        return;
-    }
-
-    /* Enabling MSI */
-
-    /* Find a device number in the map to add or reuse the existing one */
-    ndev = spapr_msicfg_find(phb, config_addr, true);
-    if (ndev >= SPAPR_MSIX_MAX_DEVS || ndev < 0) {
-        fprintf(stderr, "No free entry for a new MSI device\n");
-        rtas_st(rets, 0, -1); /* Hardware error */
-        return;
-    }
-    trace_spapr_pci_msi("Configuring MSI", ndev, config_addr);
-
-    /* Check if there is an old config and MSI number has not changed */
-    if (phb->msi_table[ndev].nvec && (req_num != phb->msi_table[ndev].nvec)) {
-        /* Unexpected behaviour */
-        fprintf(stderr, "Cannot reuse MSI config for device#%d", ndev);
-        rtas_st(rets, 0, -1); /* Hardware error */
-        return;
-    }
-
-    /* There is no cached config, allocate MSIs */
-    if (!phb->msi_table[ndev].nvec) {
-        irq = spapr_allocate_irq_block(req_num, false);
-        if (irq < 0) {
-            fprintf(stderr, "Cannot allocate MSIs for device#%d", ndev);
-            rtas_st(rets, 0, -1); /* Hardware error */
-            return;
-        }
-        phb->msi_table[ndev].irq = irq;
-        phb->msi_table[ndev].nvec = req_num;
-        phb->msi_table[ndev].config_addr = config_addr;
-    }
-
-    /* Setup MSI/MSIX vectors in the device (via cfgspace or MSIX BAR) */
-    spapr_msi_setmsg(pdev, phb->msi_win_addr | (ndev << 16),
-                     ret_intr_type == RTAS_TYPE_MSIX, req_num);
-
-    rtas_st(rets, 0, 0);
-    rtas_st(rets, 1, req_num);
-    rtas_st(rets, 2, ++seq_num);
-    rtas_st(rets, 3, ret_intr_type);
-
-    trace_spapr_pci_rtas_ibm_change_msi(func, req_num);
-}
-
-static void rtas_ibm_query_interrupt_source_number(sPAPREnvironment *spapr,
-                                                   uint32_t token,
-                                                   uint32_t nargs,
-                                                   target_ulong args,
-                                                   uint32_t nret,
-                                                   target_ulong rets)
-{
-    uint32_t config_addr = rtas_ld(args, 0);
-    uint64_t buid = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 2);
-    unsigned int intr_src_num = -1, ioa_intr_num = rtas_ld(args, 3);
-    int ndev;
-    sPAPRPHBState *phb = NULL;
-
-    /* Fins sPAPRPHBState */
-    phb = find_phb(spapr, buid);
-    if (!phb) {
-        rtas_st(rets, 0, -3); /* Parameter error */
-        return;
-    }
-
-    /* Find device descriptor and start IRQ */
-    ndev = spapr_msicfg_find(phb, config_addr, false);
-    if (ndev < 0) {
-        trace_spapr_pci_msi("MSI has not been enabled", -1, config_addr);
-        rtas_st(rets, 0, -1); /* Hardware error */
-        return;
-    }
-
-    intr_src_num = phb->msi_table[ndev].irq + ioa_intr_num;
-    trace_spapr_pci_rtas_ibm_query_interrupt_source_number(ioa_intr_num,
-                                                           intr_src_num);
-
-    rtas_st(rets, 0, 0);
-    rtas_st(rets, 1, intr_src_num);
-    rtas_st(rets, 2, 1);/* 0 == level; 1 == edge */
-}
-
-static int pci_spapr_swizzle(int slot, int pin)
-{
-    return (slot + pin) % PCI_NUM_PINS;
-}
-
-static int pci_spapr_map_irq(PCIDevice *pci_dev, int irq_num)
-{
-    /*
-     * Here we need to convert pci_dev + irq_num to some unique value
-     * which is less than number of IRQs on the specific bus (4).  We
-     * use standard PCI swizzling, that is (slot number + pin number)
-     * % 4.
-     */
-    return pci_spapr_swizzle(PCI_SLOT(pci_dev->devfn), irq_num);
-}
-
-static void pci_spapr_set_irq(void *opaque, int irq_num, int level)
-{
-    /*
-     * Here we use the number returned by pci_spapr_map_irq to find a
-     * corresponding qemu_irq.
-     */
-    sPAPRPHBState *phb = opaque;
-
-    trace_spapr_pci_lsi_set(phb->dtbusname, irq_num, phb->lsi_table[irq_num].irq);
-    qemu_set_irq(spapr_phb_lsi_qirq(phb, irq_num), level);
-}
-
-static uint64_t spapr_io_read(void *opaque, hwaddr addr,
-                              unsigned size)
-{
-    switch (size) {
-    case 1:
-        return cpu_inb(addr);
-    case 2:
-        return cpu_inw(addr);
-    case 4:
-        return cpu_inl(addr);
-    }
-    assert(0);
-}
-
-static void spapr_io_write(void *opaque, hwaddr addr,
-                           uint64_t data, unsigned size)
-{
-    switch (size) {
-    case 1:
-        cpu_outb(addr, data);
-        return;
-    case 2:
-        cpu_outw(addr, data);
-        return;
-    case 4:
-        cpu_outl(addr, data);
-        return;
-    }
-    assert(0);
-}
-
-static const MemoryRegionOps spapr_io_ops = {
-    .endianness = DEVICE_LITTLE_ENDIAN,
-    .read = spapr_io_read,
-    .write = spapr_io_write
-};
-
-/*
- * MSI/MSIX memory region implementation.
- * The handler handles both MSI and MSIX.
- * For MSI-X, the vector number is encoded as a part of the address,
- * data is set to 0.
- * For MSI, the vector number is encoded in least bits in data.
- */
-static void spapr_msi_write(void *opaque, hwaddr addr,
-                            uint64_t data, unsigned size)
-{
-    sPAPRPHBState *phb = opaque;
-    int ndev = addr >> 16;
-    int vec = ((addr & 0xFFFF) >> 2) | data;
-    uint32_t irq = phb->msi_table[ndev].irq + vec;
-
-    trace_spapr_pci_msi_write(addr, data, irq);
-
-    qemu_irq_pulse(xics_get_qirq(spapr->icp, irq));
-}
-
-static const MemoryRegionOps spapr_msi_ops = {
-    /* There is no .read as the read result is undefined by PCI spec */
-    .read = NULL,
-    .write = spapr_msi_write,
-    .endianness = DEVICE_LITTLE_ENDIAN
-};
-
-/*
- * PHB PCI device
- */
-static DMAContext *spapr_pci_dma_context_fn(PCIBus *bus, void *opaque,
-                                            int devfn)
-{
-    sPAPRPHBState *phb = opaque;
-
-    return phb->dma;
-}
-
-static int spapr_phb_init(SysBusDevice *s)
-{
-    sPAPRPHBState *sphb = SPAPR_PCI_HOST_BRIDGE(s);
-    PCIHostState *phb = PCI_HOST_BRIDGE(s);
-    const char *busname;
-    char *namebuf;
-    int i;
-    PCIBus *bus;
-
-    if (sphb->index != -1) {
-        hwaddr windows_base;
-
-        if ((sphb->buid != -1) || (sphb->dma_liobn != -1)
-            || (sphb->mem_win_addr != -1)
-            || (sphb->io_win_addr != -1)
-            || (sphb->msi_win_addr != -1)) {
-            fprintf(stderr, "Either \"index\" or other parameters must"
-                    " be specified for PAPR PHB, not both\n");
-            return -1;
-        }
-
-        sphb->buid = SPAPR_PCI_BASE_BUID + sphb->index;
-        sphb->dma_liobn = SPAPR_PCI_BASE_LIOBN + sphb->index;
-
-        windows_base = SPAPR_PCI_WINDOW_BASE
-            + sphb->index * SPAPR_PCI_WINDOW_SPACING;
-        sphb->mem_win_addr = windows_base + SPAPR_PCI_MMIO_WIN_OFF;
-        sphb->io_win_addr = windows_base + SPAPR_PCI_IO_WIN_OFF;
-        sphb->msi_win_addr = windows_base + SPAPR_PCI_MSI_WIN_OFF;
-    }
-
-    if (sphb->buid == -1) {
-        fprintf(stderr, "BUID not specified for PHB\n");
-        return -1;
-    }
-
-    if (sphb->dma_liobn == -1) {
-        fprintf(stderr, "LIOBN not specified for PHB\n");
-        return -1;
-    }
-
-    if (sphb->mem_win_addr == -1) {
-        fprintf(stderr, "Memory window address not specified for PHB\n");
-        return -1;
-    }
-
-    if (sphb->io_win_addr == -1) {
-        fprintf(stderr, "IO window address not specified for PHB\n");
-        return -1;
-    }
-
-    if (sphb->msi_win_addr == -1) {
-        fprintf(stderr, "MSI window address not specified for PHB\n");
-        return -1;
-    }
-
-    if (find_phb(spapr, sphb->buid)) {
-        fprintf(stderr, "PCI host bridges must have unique BUIDs\n");
-        return -1;
-    }
-
-    sphb->dtbusname = g_strdup_printf("pci@%" PRIx64, sphb->buid);
-
-    namebuf = alloca(strlen(sphb->dtbusname) + 32);
-
-    /* Initialize memory regions */
-    sprintf(namebuf, "%s.mmio", sphb->dtbusname);
-    memory_region_init(&sphb->memspace, namebuf, INT64_MAX);
-
-    sprintf(namebuf, "%s.mmio-alias", sphb->dtbusname);
-    memory_region_init_alias(&sphb->memwindow, namebuf, &sphb->memspace,
-                             SPAPR_PCI_MEM_WIN_BUS_OFFSET, sphb->mem_win_size);
-    memory_region_add_subregion(get_system_memory(), sphb->mem_win_addr,
-                                &sphb->memwindow);
-
-    /* On ppc, we only have MMIO no specific IO space from the CPU
-     * perspective.  In theory we ought to be able to embed the PCI IO
-     * memory region direction in the system memory space.  However,
-     * if any of the IO BAR subregions use the old_portio mechanism,
-     * that won't be processed properly unless accessed from the
-     * system io address space.  This hack to bounce things via
-     * system_io works around the problem until all the users of
-     * old_portion are updated */
-    sprintf(namebuf, "%s.io", sphb->dtbusname);
-    memory_region_init(&sphb->iospace, namebuf, SPAPR_PCI_IO_WIN_SIZE);
-    /* FIXME: fix to support multiple PHBs */
-    memory_region_add_subregion(get_system_io(), 0, &sphb->iospace);
-
-    sprintf(namebuf, "%s.io-alias", sphb->dtbusname);
-    memory_region_init_io(&sphb->iowindow, &spapr_io_ops, sphb,
-                          namebuf, SPAPR_PCI_IO_WIN_SIZE);
-    memory_region_add_subregion(get_system_memory(), sphb->io_win_addr,
-                                &sphb->iowindow);
-
-    /* As MSI/MSIX interrupts trigger by writing at MSI/MSIX vectors,
-     * we need to allocate some memory to catch those writes coming
-     * from msi_notify()/msix_notify() */
-    if (msi_supported) {
-        sprintf(namebuf, "%s.msi", sphb->dtbusname);
-        memory_region_init_io(&sphb->msiwindow, &spapr_msi_ops, sphb,
-                              namebuf, SPAPR_MSIX_MAX_DEVS * 0x10000);
-        memory_region_add_subregion(get_system_memory(), sphb->msi_win_addr,
-                                    &sphb->msiwindow);
-    }
-
-    /*
-     * Selecting a busname is more complex than you'd think, due to
-     * interacting constraints.  If the user has specified an id
-     * explicitly for the phb , then we want to use the qdev default
-     * of naming the bus based on the bridge device (so the user can
-     * then assign devices to it in the way they expect).  For the
-     * first / default PCI bus (index=0) we want to use just "pci"
-     * because libvirt expects there to be a bus called, simply,
-     * "pci".  Otherwise, we use the same name as in the device tree,
-     * since it's unique by construction, and makes the guest visible
-     * BUID clear.
-     */
-    if (s->qdev.id) {
-        busname = NULL;
-    } else if (sphb->index == 0) {
-        busname = "pci";
-    } else {
-        busname = sphb->dtbusname;
-    }
-    bus = pci_register_bus(DEVICE(s), busname,
-                           pci_spapr_set_irq, pci_spapr_map_irq, sphb,
-                           &sphb->memspace, &sphb->iospace,
-                           PCI_DEVFN(0, 0), PCI_NUM_PINS, TYPE_PCI_BUS);
-    phb->bus = bus;
-
-    sphb->dma_window_start = 0;
-    sphb->dma_window_size = 0x40000000;
-    sphb->dma = spapr_tce_new_dma_context(sphb->dma_liobn, sphb->dma_window_size);
-    if (!sphb->dma) {
-        fprintf(stderr, "Unable to create TCE table for %s\n", sphb->dtbusname);
-        return -1;
-    }
-    pci_setup_iommu(bus, spapr_pci_dma_context_fn, sphb);
-
-    QLIST_INSERT_HEAD(&spapr->phbs, sphb, list);
-
-    /* Initialize the LSI table */
-    for (i = 0; i < PCI_NUM_PINS; i++) {
-        uint32_t irq;
-
-        irq = spapr_allocate_lsi(0);
-        if (!irq) {
-            return -1;
-        }
-
-        sphb->lsi_table[i].irq = irq;
-    }
-
-    return 0;
-}
-
-static void spapr_phb_reset(DeviceState *qdev)
-{
-    SysBusDevice *s = SYS_BUS_DEVICE(qdev);
-    sPAPRPHBState *sphb = SPAPR_PCI_HOST_BRIDGE(s);
-
-    /* Reset the IOMMU state */
-    spapr_tce_reset(sphb->dma);
-}
-
-static Property spapr_phb_properties[] = {
-    DEFINE_PROP_INT32("index", sPAPRPHBState, index, -1),
-    DEFINE_PROP_HEX64("buid", sPAPRPHBState, buid, -1),
-    DEFINE_PROP_HEX32("liobn", sPAPRPHBState, dma_liobn, -1),
-    DEFINE_PROP_HEX64("mem_win_addr", sPAPRPHBState, mem_win_addr, -1),
-    DEFINE_PROP_HEX64("mem_win_size", sPAPRPHBState, mem_win_size,
-                      SPAPR_PCI_MMIO_WIN_SIZE),
-    DEFINE_PROP_HEX64("io_win_addr", sPAPRPHBState, io_win_addr, -1),
-    DEFINE_PROP_HEX64("io_win_size", sPAPRPHBState, io_win_size,
-                      SPAPR_PCI_IO_WIN_SIZE),
-    DEFINE_PROP_HEX64("msi_win_addr", sPAPRPHBState, msi_win_addr, -1),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void spapr_phb_class_init(ObjectClass *klass, void *data)
-{
-    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
-    DeviceClass *dc = DEVICE_CLASS(klass);
-
-    sdc->init = spapr_phb_init;
-    dc->props = spapr_phb_properties;
-    dc->reset = spapr_phb_reset;
-}
-
-static const TypeInfo spapr_phb_info = {
-    .name          = TYPE_SPAPR_PCI_HOST_BRIDGE,
-    .parent        = TYPE_PCI_HOST_BRIDGE,
-    .instance_size = sizeof(sPAPRPHBState),
-    .class_init    = spapr_phb_class_init,
-};
-
-PCIHostState *spapr_create_phb(sPAPREnvironment *spapr, int index)
-{
-    DeviceState *dev;
-
-    dev = qdev_create(NULL, TYPE_SPAPR_PCI_HOST_BRIDGE);
-    qdev_prop_set_uint32(dev, "index", index);
-    qdev_init_nofail(dev);
-
-    return PCI_HOST_BRIDGE(dev);
-}
-
-/* Macros to operate with address in OF binding to PCI */
-#define b_x(x, p, l)    (((x) & ((1<<(l))-1)) << (p))
-#define b_n(x)          b_x((x), 31, 1) /* 0 if relocatable */
-#define b_p(x)          b_x((x), 30, 1) /* 1 if prefetchable */
-#define b_t(x)          b_x((x), 29, 1) /* 1 if the address is aliased */
-#define b_ss(x)         b_x((x), 24, 2) /* the space code */
-#define b_bbbbbbbb(x)   b_x((x), 16, 8) /* bus number */
-#define b_ddddd(x)      b_x((x), 11, 5) /* device number */
-#define b_fff(x)        b_x((x), 8, 3)  /* function number */
-#define b_rrrrrrrr(x)   b_x((x), 0, 8)  /* register number */
-
-int spapr_populate_pci_dt(sPAPRPHBState *phb,
-                          uint32_t xics_phandle,
-                          void *fdt)
-{
-    int bus_off, i, j;
-    char nodename[256];
-    uint32_t bus_range[] = { cpu_to_be32(0), cpu_to_be32(0xff) };
-    struct {
-        uint32_t hi;
-        uint64_t child;
-        uint64_t parent;
-        uint64_t size;
-    } QEMU_PACKED ranges[] = {
-        {
-            cpu_to_be32(b_ss(1)), cpu_to_be64(0),
-            cpu_to_be64(phb->io_win_addr),
-            cpu_to_be64(memory_region_size(&phb->iospace)),
-        },
-        {
-            cpu_to_be32(b_ss(2)), cpu_to_be64(SPAPR_PCI_MEM_WIN_BUS_OFFSET),
-            cpu_to_be64(phb->mem_win_addr),
-            cpu_to_be64(memory_region_size(&phb->memwindow)),
-        },
-    };
-    uint64_t bus_reg[] = { cpu_to_be64(phb->buid), 0 };
-    uint32_t interrupt_map_mask[] = {
-        cpu_to_be32(b_ddddd(-1)|b_fff(0)), 0x0, 0x0, cpu_to_be32(-1)};
-    uint32_t interrupt_map[PCI_SLOT_MAX * PCI_NUM_PINS][7];
-
-    /* Start populating the FDT */
-    sprintf(nodename, "pci@%" PRIx64, phb->buid);
-    bus_off = fdt_add_subnode(fdt, 0, nodename);
-    if (bus_off < 0) {
-        return bus_off;
-    }
-
-#define _FDT(exp) \
-    do { \
-        int ret = (exp);                                           \
-        if (ret < 0) {                                             \
-            return ret;                                            \
-        }                                                          \
-    } while (0)
-
-    /* Write PHB properties */
-    _FDT(fdt_setprop_string(fdt, bus_off, "device_type", "pci"));
-    _FDT(fdt_setprop_string(fdt, bus_off, "compatible", "IBM,Logical_PHB"));
-    _FDT(fdt_setprop_cell(fdt, bus_off, "#address-cells", 0x3));
-    _FDT(fdt_setprop_cell(fdt, bus_off, "#size-cells", 0x2));
-    _FDT(fdt_setprop_cell(fdt, bus_off, "#interrupt-cells", 0x1));
-    _FDT(fdt_setprop(fdt, bus_off, "used-by-rtas", NULL, 0));
-    _FDT(fdt_setprop(fdt, bus_off, "bus-range", &bus_range, sizeof(bus_range)));
-    _FDT(fdt_setprop(fdt, bus_off, "ranges", &ranges, sizeof(ranges)));
-    _FDT(fdt_setprop(fdt, bus_off, "reg", &bus_reg, sizeof(bus_reg)));
-    _FDT(fdt_setprop_cell(fdt, bus_off, "ibm,pci-config-space-type", 0x1));
-
-    /* Build the interrupt-map, this must matches what is done
-     * in pci_spapr_map_irq
-     */
-    _FDT(fdt_setprop(fdt, bus_off, "interrupt-map-mask",
-                     &interrupt_map_mask, sizeof(interrupt_map_mask)));
-    for (i = 0; i < PCI_SLOT_MAX; i++) {
-        for (j = 0; j < PCI_NUM_PINS; j++) {
-            uint32_t *irqmap = interrupt_map[i*PCI_NUM_PINS + j];
-            int lsi_num = pci_spapr_swizzle(i, j);
-
-            irqmap[0] = cpu_to_be32(b_ddddd(i)|b_fff(0));
-            irqmap[1] = 0;
-            irqmap[2] = 0;
-            irqmap[3] = cpu_to_be32(j+1);
-            irqmap[4] = cpu_to_be32(xics_phandle);
-            irqmap[5] = cpu_to_be32(phb->lsi_table[lsi_num].irq);
-            irqmap[6] = cpu_to_be32(0x8);
-        }
-    }
-    /* Write interrupt map */
-    _FDT(fdt_setprop(fdt, bus_off, "interrupt-map", &interrupt_map,
-                     sizeof(interrupt_map)));
-
-    spapr_dma_dt(fdt, bus_off, "ibm,dma-window",
-                 phb->dma_liobn, phb->dma_window_start,
-                 phb->dma_window_size);
-
-    return 0;
-}
-
-void spapr_pci_rtas_init(void)
-{
-    spapr_rtas_register("read-pci-config", rtas_read_pci_config);
-    spapr_rtas_register("write-pci-config", rtas_write_pci_config);
-    spapr_rtas_register("ibm,read-pci-config", rtas_ibm_read_pci_config);
-    spapr_rtas_register("ibm,write-pci-config", rtas_ibm_write_pci_config);
-    if (msi_supported) {
-        spapr_rtas_register("ibm,query-interrupt-source-number",
-                            rtas_ibm_query_interrupt_source_number);
-        spapr_rtas_register("ibm,change-msi", rtas_ibm_change_msi);
-    }
-}
-
-static void spapr_pci_register_types(void)
-{
-    type_register_static(&spapr_phb_info);
-}
-
-type_init(spapr_pci_register_types)
diff --git a/hw/spapr_pci.h b/hw/spapr_pci.h
deleted file mode 100644 (file)
index 8bd8a66..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * QEMU SPAPR PCI BUS definitions
- *
- * Copyright (c) 2011 Alexey Kardashevskiy <aik@au1.ibm.com>
- *
- * 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/>.
- */
-#if !defined(__HW_SPAPR_H__)
-#error Please include spapr.h before this file!
-#endif
-
-#if !defined(__HW_SPAPR_PCI_H__)
-#define __HW_SPAPR_PCI_H__
-
-#include "hw/pci/pci.h"
-#include "hw/pci/pci_host.h"
-#include "hw/xics.h"
-
-#define SPAPR_MSIX_MAX_DEVS 32
-
-#define TYPE_SPAPR_PCI_HOST_BRIDGE "spapr-pci-host-bridge"
-
-#define SPAPR_PCI_HOST_BRIDGE(obj) \
-    OBJECT_CHECK(sPAPRPHBState, (obj), TYPE_SPAPR_PCI_HOST_BRIDGE)
-
-typedef struct sPAPRPHBState {
-    PCIHostState parent_obj;
-
-    int32_t index;
-    uint64_t buid;
-    char *dtbusname;
-
-    MemoryRegion memspace, iospace;
-    hwaddr mem_win_addr, mem_win_size, io_win_addr, io_win_size;
-    hwaddr msi_win_addr;
-    MemoryRegion memwindow, iowindow, msiwindow;
-
-    uint32_t dma_liobn;
-    uint64_t dma_window_start;
-    uint64_t dma_window_size;
-    DMAContext *dma;
-
-    struct {
-        uint32_t irq;
-    } lsi_table[PCI_NUM_PINS];
-
-    struct {
-        uint32_t config_addr;
-        uint32_t irq;
-        int nvec;
-    } msi_table[SPAPR_MSIX_MAX_DEVS];
-
-    QLIST_ENTRY(sPAPRPHBState) list;
-} sPAPRPHBState;
-
-#define SPAPR_PCI_BASE_BUID          0x800000020000000ULL
-
-#define SPAPR_PCI_WINDOW_BASE        0x10000000000ULL
-#define SPAPR_PCI_WINDOW_SPACING     0x1000000000ULL
-#define SPAPR_PCI_MMIO_WIN_OFF       0xA0000000
-#define SPAPR_PCI_MMIO_WIN_SIZE      0x20000000
-#define SPAPR_PCI_IO_WIN_OFF         0x80000000
-#define SPAPR_PCI_IO_WIN_SIZE        0x10000
-#define SPAPR_PCI_MSI_WIN_OFF        0x90000000
-
-#define SPAPR_PCI_MEM_WIN_BUS_OFFSET 0x80000000ULL
-
-static inline qemu_irq spapr_phb_lsi_qirq(struct sPAPRPHBState *phb, int pin)
-{
-    return xics_get_qirq(spapr->icp, phb->lsi_table[pin].irq);
-}
-
-PCIHostState *spapr_create_phb(sPAPREnvironment *spapr, int index);
-
-int spapr_populate_pci_dt(sPAPRPHBState *phb,
-                          uint32_t xics_phandle,
-                          void *fdt);
-
-void spapr_pci_rtas_init(void);
-
-#endif /* __HW_SPAPR_PCI_H__ */
diff --git a/hw/spapr_vio.h b/hw/spapr_vio.h
deleted file mode 100644 (file)
index f98ec0a..0000000
+++ /dev/null
@@ -1,136 +0,0 @@
-#ifndef _HW_SPAPR_VIO_H
-#define _HW_SPAPR_VIO_H
-/*
- * QEMU sPAPR VIO bus definitions
- *
- * Copyright (c) 2010 David Gibson, IBM Corporation <david@gibson.dropbear.id.au>
- * Based on the s390 virtio bus definitions:
- * Copyright (c) 2009 Alexander Graf <agraf@suse.de>
- *
- * 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 "sysemu/dma.h"
-
-#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)
-
-#define TYPE_SPAPR_VIO_BUS "spapr-vio-bus"
-#define SPAPR_VIO_BUS(obj) OBJECT_CHECK(VIOsPAPRBus, (obj), TYPE_SPAPR_VIO_BUS)
-
-struct VIOsPAPRDevice;
-
-typedef struct VIOsPAPR_CRQ {
-    uint64_t qladdr;
-    uint32_t qsize;
-    uint32_t qnext;
-    int(*SendFunc)(struct VIOsPAPRDevice *vdev, uint8_t *crq);
-} VIOsPAPR_CRQ;
-
-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;
-    uint32_t rtce_window_size;
-    int (*init)(VIOsPAPRDevice *dev);
-    void (*reset)(VIOsPAPRDevice *dev);
-    int (*devnode)(VIOsPAPRDevice *dev, void *fdt, int node_off);
-} VIOsPAPRDeviceClass;
-
-struct VIOsPAPRDevice {
-    DeviceState qdev;
-    uint32_t reg;
-    uint32_t irq;
-    target_ulong signal_state;
-    VIOsPAPR_CRQ crq;
-    DMAContext *dma;
-};
-
-#define DEFINE_SPAPR_PROPERTIES(type, field)           \
-        DEFINE_PROP_UINT32("reg", type, field.reg, -1)
-
-struct VIOsPAPRBus {
-    BusState bus;
-    uint32_t next_reg;
-    int (*init)(VIOsPAPRDevice *dev);
-    int (*devnode)(VIOsPAPRDevice *dev, void *fdt, int node_off);
-};
-
-extern VIOsPAPRBus *spapr_vio_bus_init(void);
-extern VIOsPAPRDevice *spapr_vio_find_by_reg(VIOsPAPRBus *bus, uint32_t reg);
-extern int spapr_populate_vdevice(VIOsPAPRBus *bus, void *fdt);
-extern int spapr_populate_chosen_stdout(void *fdt, VIOsPAPRBus *bus);
-
-extern int spapr_vio_signal(VIOsPAPRDevice *dev, target_ulong mode);
-
-static inline qemu_irq spapr_vio_qirq(VIOsPAPRDevice *dev)
-{
-    return xics_get_qirq(spapr->icp, dev->irq);
-}
-
-static inline bool spapr_vio_dma_valid(VIOsPAPRDevice *dev, uint64_t taddr,
-                                       uint32_t size, DMADirection dir)
-{
-    return dma_memory_valid(dev->dma, taddr, size, dir);
-}
-
-static inline int spapr_vio_dma_read(VIOsPAPRDevice *dev, uint64_t taddr,
-                                     void *buf, uint32_t size)
-{
-    return (dma_memory_read(dev->dma, taddr, buf, size) != 0) ?
-        H_DEST_PARM : H_SUCCESS;
-}
-
-static inline int spapr_vio_dma_write(VIOsPAPRDevice *dev, uint64_t taddr,
-                                      const void *buf, uint32_t size)
-{
-    return (dma_memory_write(dev->dma, taddr, buf, size) != 0) ?
-        H_DEST_PARM : H_SUCCESS;
-}
-
-static inline int spapr_vio_dma_set(VIOsPAPRDevice *dev, uint64_t taddr,
-                                    uint8_t c, uint32_t size)
-{
-    return (dma_memory_set(dev->dma, taddr, c, size) != 0) ?
-        H_DEST_PARM : H_SUCCESS;
-}
-
-#define vio_stb(_dev, _addr, _val) (stb_dma((_dev)->dma, (_addr), (_val)))
-#define vio_sth(_dev, _addr, _val) (stw_be_dma((_dev)->dma, (_addr), (_val)))
-#define vio_stl(_dev, _addr, _val) (stl_be_dma((_dev)->dma, (_addr), (_val)))
-#define vio_stq(_dev, _addr, _val) (stq_be_dma((_dev)->dma, (_addr), (_val)))
-#define vio_ldq(_dev, _addr) (ldq_be_dma((_dev)->dma, (_addr)))
-
-int spapr_vio_send_crq(VIOsPAPRDevice *dev, uint8_t *crq);
-
-VIOsPAPRDevice *vty_lookup(sPAPREnvironment *spapr, target_ulong reg);
-void vty_putchars(VIOsPAPRDevice *sdev, uint8_t *buf, int len);
-void spapr_vty_create(VIOsPAPRBus *bus, CharDriverState *chardev);
-void spapr_vlan_create(VIOsPAPRBus *bus, NICInfo *nd);
-void spapr_vscsi_create(VIOsPAPRBus *bus);
-
-VIOsPAPRDevice *spapr_vty_get_default(VIOsPAPRBus *bus);
-
-void spapr_vio_quiesce(void);
-
-#endif /* _HW_SPAPR_VIO_H */
diff --git a/hw/spapr_vscsi.c b/hw/spapr_vscsi.c
deleted file mode 100644 (file)
index 2794094..0000000
+++ /dev/null
@@ -1,982 +0,0 @@
-/*
- * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator
- *
- * PAPR Virtual SCSI, aka ibmvscsi
- *
- * Copyright (c) 2010,2011 Benjamin Herrenschmidt, IBM Corporation.
- *
- * 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.
- *
- * TODO:
- *
- *  - Cleanups :-)
- *  - Sort out better how to assign devices to VSCSI instances
- *  - Fix residual counts
- *  - Add indirect descriptors support
- *  - Maybe do autosense (PAPR seems to mandate it, linux doesn't care)
- */
-#include "hw/hw.h"
-#include "hw/scsi.h"
-#include "hw/scsi-defs.h"
-#include "hw/srp.h"
-#include "hw/qdev.h"
-#include "hw/spapr.h"
-#include "hw/spapr_vio.h"
-#include "hw/ppc-viosrp.h"
-
-#include <libfdt.h>
-
-/*#define DEBUG_VSCSI*/
-
-#ifdef DEBUG_VSCSI
-#define dprintf(fmt, ...) \
-    do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
-#else
-#define dprintf(fmt, ...) \
-    do { } while (0)
-#endif
-
-/*
- * Virtual SCSI device
- */
-
-/* Random numbers */
-#define VSCSI_MAX_SECTORS       4096
-#define VSCSI_REQ_LIMIT         24
-
-#define SCSI_SENSE_BUF_SIZE     96
-#define SRP_RSP_SENSE_DATA_LEN  18
-
-typedef union vscsi_crq {
-    struct viosrp_crq s;
-    uint8_t raw[16];
-} vscsi_crq;
-
-typedef struct vscsi_req {
-    vscsi_crq               crq;
-    union viosrp_iu         iu;
-
-    /* SCSI request tracking */
-    SCSIRequest             *sreq;
-    uint32_t                qtag; /* qemu tag != srp tag */
-    int                     lun;
-    int                     active;
-    long                    data_len;
-    int                     writing;
-    int                     senselen;
-    uint8_t                 sense[SCSI_SENSE_BUF_SIZE];
-
-    /* RDMA related bits */
-    uint8_t                 dma_fmt;
-    struct srp_direct_buf   ext_desc;
-    struct srp_direct_buf   *cur_desc;
-    struct srp_indirect_buf *ind_desc;
-    int                     local_desc;
-    int                     total_desc;
-} vscsi_req;
-
-
-typedef struct {
-    VIOsPAPRDevice vdev;
-    SCSIBus bus;
-    vscsi_req reqs[VSCSI_REQ_LIMIT];
-} VSCSIState;
-
-static struct vscsi_req *vscsi_get_req(VSCSIState *s)
-{
-    vscsi_req *req;
-    int i;
-
-    for (i = 0; i < VSCSI_REQ_LIMIT; i++) {
-        req = &s->reqs[i];
-        if (!req->active) {
-            memset(req, 0, sizeof(*req));
-            req->qtag = i;
-            req->active = 1;
-            return req;
-        }
-    }
-    return NULL;
-}
-
-static void vscsi_put_req(vscsi_req *req)
-{
-    if (req->sreq != NULL) {
-        scsi_req_unref(req->sreq);
-    }
-    req->sreq = NULL;
-    req->active = 0;
-}
-
-static SCSIDevice *vscsi_device_find(SCSIBus *bus, uint64_t srp_lun, int *lun)
-{
-    int channel = 0, id = 0;
-
-retry:
-    switch (srp_lun >> 62) {
-    case 0:
-        if ((srp_lun >> 56) != 0) {
-            channel = (srp_lun >> 56) & 0x3f;
-            id = (srp_lun >> 48) & 0xff;
-            srp_lun <<= 16;
-            goto retry;
-        }
-        *lun = (srp_lun >> 48) & 0xff;
-        break;
-
-    case 1:
-        *lun = (srp_lun >> 48) & 0x3fff;
-        break;
-    case 2:
-        channel = (srp_lun >> 53) & 0x7;
-        id = (srp_lun >> 56) & 0x3f;
-        *lun = (srp_lun >> 48) & 0x1f;
-        break;
-    case 3:
-        *lun = -1;
-        return NULL;
-    default:
-        abort();
-    }
-
-    return scsi_device_find(bus, channel, id, *lun);
-}
-
-static int vscsi_send_iu(VSCSIState *s, vscsi_req *req,
-                         uint64_t length, uint8_t format)
-{
-    long rc, rc1;
-
-    /* First copy the SRP */
-    rc = spapr_vio_dma_write(&s->vdev, req->crq.s.IU_data_ptr,
-                             &req->iu, length);
-    if (rc) {
-        fprintf(stderr, "vscsi_send_iu: DMA write failure !\n");
-    }
-
-    req->crq.s.valid = 0x80;
-    req->crq.s.format = format;
-    req->crq.s.reserved = 0x00;
-    req->crq.s.timeout = cpu_to_be16(0x0000);
-    req->crq.s.IU_length = cpu_to_be16(length);
-    req->crq.s.IU_data_ptr = req->iu.srp.rsp.tag; /* right byte order */
-
-    if (rc == 0) {
-        req->crq.s.status = 0x99; /* Just needs to be non-zero */
-    } else {
-        req->crq.s.status = 0x00;
-    }
-
-    rc1 = spapr_vio_send_crq(&s->vdev, req->crq.raw);
-    if (rc1) {
-        fprintf(stderr, "vscsi_send_iu: Error sending response\n");
-        return rc1;
-    }
-
-    return rc;
-}
-
-static void vscsi_makeup_sense(VSCSIState *s, vscsi_req *req,
-                               uint8_t key, uint8_t asc, uint8_t ascq)
-{
-    req->senselen = SRP_RSP_SENSE_DATA_LEN;
-
-    /* Valid bit and 'current errors' */
-    req->sense[0] = (0x1 << 7 | 0x70);
-    /* Sense key */
-    req->sense[2] = key;
-    /* Additional sense length */
-    req->sense[7] = 0xa; /* 10 bytes */
-    /* Additional sense code */
-    req->sense[12] = asc;
-    req->sense[13] = ascq;
-}
-
-static int vscsi_send_rsp(VSCSIState *s, vscsi_req *req,
-                          uint8_t status, int32_t res_in, int32_t res_out)
-{
-    union viosrp_iu *iu = &req->iu;
-    uint64_t tag = iu->srp.rsp.tag;
-    int total_len = sizeof(iu->srp.rsp);
-
-    dprintf("VSCSI: Sending resp status: 0x%x, "
-            "res_in: %d, res_out: %d\n", status, res_in, res_out);
-
-    memset(iu, 0, sizeof(struct srp_rsp));
-    iu->srp.rsp.opcode = SRP_RSP;
-    iu->srp.rsp.req_lim_delta = cpu_to_be32(1);
-    iu->srp.rsp.tag = tag;
-
-    /* Handle residuals */
-    if (res_in < 0) {
-        iu->srp.rsp.flags |= SRP_RSP_FLAG_DIUNDER;
-        res_in = -res_in;
-    } else if (res_in) {
-        iu->srp.rsp.flags |= SRP_RSP_FLAG_DIOVER;
-    }
-    if (res_out < 0) {
-        iu->srp.rsp.flags |= SRP_RSP_FLAG_DOUNDER;
-        res_out = -res_out;
-    } else if (res_out) {
-        iu->srp.rsp.flags |= SRP_RSP_FLAG_DOOVER;
-    }
-    iu->srp.rsp.data_in_res_cnt = cpu_to_be32(res_in);
-    iu->srp.rsp.data_out_res_cnt = cpu_to_be32(res_out);
-
-    /* We don't do response data */
-    /* iu->srp.rsp.flags &= ~SRP_RSP_FLAG_RSPVALID; */
-    iu->srp.rsp.resp_data_len = cpu_to_be32(0);
-
-    /* Handle success vs. failure */
-    iu->srp.rsp.status = status;
-    if (status) {
-        iu->srp.rsp.sol_not = (iu->srp.cmd.sol_not & 0x04) >> 2;
-        if (req->senselen) {
-            req->iu.srp.rsp.flags |= SRP_RSP_FLAG_SNSVALID;
-            req->iu.srp.rsp.sense_data_len = cpu_to_be32(req->senselen);
-            memcpy(req->iu.srp.rsp.data, req->sense, req->senselen);
-            total_len += req->senselen;
-        }
-    } else {
-        iu->srp.rsp.sol_not = (iu->srp.cmd.sol_not & 0x02) >> 1;
-    }
-
-    vscsi_send_iu(s, req, total_len, VIOSRP_SRP_FORMAT);
-    return 0;
-}
-
-static inline void vscsi_swap_desc(struct srp_direct_buf *desc)
-{
-    desc->va = be64_to_cpu(desc->va);
-    desc->len = be32_to_cpu(desc->len);
-}
-
-static int vscsi_srp_direct_data(VSCSIState *s, vscsi_req *req,
-                                 uint8_t *buf, uint32_t len)
-{
-    struct srp_direct_buf *md = req->cur_desc;
-    uint32_t llen;
-    int rc = 0;
-
-    dprintf("VSCSI: direct segment 0x%x bytes, va=0x%llx desc len=0x%x\n",
-            len, (unsigned long long)md->va, md->len);
-
-    llen = MIN(len, md->len);
-    if (llen) {
-        if (req->writing) { /* writing = to device = reading from memory */
-            rc = spapr_vio_dma_read(&s->vdev, md->va, buf, llen);
-        } else {
-            rc = spapr_vio_dma_write(&s->vdev, md->va, buf, llen);
-        }
-    }
-    md->len -= llen;
-    md->va += llen;
-
-    if (rc) {
-        return -1;
-    }
-    return llen;
-}
-
-static int vscsi_srp_indirect_data(VSCSIState *s, vscsi_req *req,
-                                   uint8_t *buf, uint32_t len)
-{
-    struct srp_direct_buf *td = &req->ind_desc->table_desc;
-    struct srp_direct_buf *md = req->cur_desc;
-    int rc = 0;
-    uint32_t llen, total = 0;
-
-    dprintf("VSCSI: indirect segment 0x%x bytes, td va=0x%llx len=0x%x\n",
-            len, (unsigned long long)td->va, td->len);
-
-    /* While we have data ... */
-    while (len) {
-        /* If we have a descriptor but it's empty, go fetch a new one */
-        if (md && md->len == 0) {
-            /* More local available, use one */
-            if (req->local_desc) {
-                md = ++req->cur_desc;
-                --req->local_desc;
-                --req->total_desc;
-                td->va += sizeof(struct srp_direct_buf);
-            } else {
-                md = req->cur_desc = NULL;
-            }
-        }
-        /* No descriptor at hand, fetch one */
-        if (!md) {
-            if (!req->total_desc) {
-                dprintf("VSCSI:   Out of descriptors !\n");
-                break;
-            }
-            md = req->cur_desc = &req->ext_desc;
-            dprintf("VSCSI:   Reading desc from 0x%llx\n",
-                    (unsigned long long)td->va);
-            rc = spapr_vio_dma_read(&s->vdev, td->va, md,
-                                    sizeof(struct srp_direct_buf));
-            if (rc) {
-                dprintf("VSCSI: spapr_vio_dma_read -> %d reading ext_desc\n",
-                        rc);
-                break;
-            }
-            vscsi_swap_desc(md);
-            td->va += sizeof(struct srp_direct_buf);
-            --req->total_desc;
-        }
-        dprintf("VSCSI:   [desc va=0x%llx,len=0x%x] remaining=0x%x\n",
-                (unsigned long long)md->va, md->len, len);
-
-        /* Perform transfer */
-        llen = MIN(len, md->len);
-        if (req->writing) { /* writing = to device = reading from memory */
-            rc = spapr_vio_dma_read(&s->vdev, md->va, buf, llen);
-        } else {
-            rc = spapr_vio_dma_write(&s->vdev, md->va, buf, llen);
-        }
-        if (rc) {
-            dprintf("VSCSI: spapr_vio_dma_r/w(%d) -> %d\n", req->writing, rc);
-            break;
-        }
-        dprintf("VSCSI:     data: %02x %02x %02x %02x...\n",
-                buf[0], buf[1], buf[2], buf[3]);
-
-        len -= llen;
-        buf += llen;
-        total += llen;
-        md->va += llen;
-        md->len -= llen;
-    }
-    return rc ? -1 : total;
-}
-
-static int vscsi_srp_transfer_data(VSCSIState *s, vscsi_req *req,
-                                   int writing, uint8_t *buf, uint32_t len)
-{
-    int err = 0;
-
-    switch (req->dma_fmt) {
-    case SRP_NO_DATA_DESC:
-        dprintf("VSCSI: no data desc transfer, skipping 0x%x bytes\n", len);
-        break;
-    case SRP_DATA_DESC_DIRECT:
-        err = vscsi_srp_direct_data(s, req, buf, len);
-        break;
-    case SRP_DATA_DESC_INDIRECT:
-        err = vscsi_srp_indirect_data(s, req, buf, len);
-        break;
-    }
-    return err;
-}
-
-/* Bits from linux srp */
-static int data_out_desc_size(struct srp_cmd *cmd)
-{
-    int size = 0;
-    uint8_t fmt = cmd->buf_fmt >> 4;
-
-    switch (fmt) {
-    case SRP_NO_DATA_DESC:
-        break;
-    case SRP_DATA_DESC_DIRECT:
-        size = sizeof(struct srp_direct_buf);
-        break;
-    case SRP_DATA_DESC_INDIRECT:
-        size = sizeof(struct srp_indirect_buf) +
-            sizeof(struct srp_direct_buf)*cmd->data_out_desc_cnt;
-        break;
-    default:
-        break;
-    }
-    return size;
-}
-
-static int vscsi_preprocess_desc(vscsi_req *req)
-{
-    struct srp_cmd *cmd = &req->iu.srp.cmd;
-    int offset, i;
-
-    offset = cmd->add_cdb_len & ~3;
-
-    if (req->writing) {
-        req->dma_fmt = cmd->buf_fmt >> 4;
-    } else {
-        offset += data_out_desc_size(cmd);
-        req->dma_fmt = cmd->buf_fmt & ((1U << 4) - 1);
-    }
-
-    switch (req->dma_fmt) {
-    case SRP_NO_DATA_DESC:
-        break;
-    case SRP_DATA_DESC_DIRECT:
-        req->cur_desc = (struct srp_direct_buf *)(cmd->add_data + offset);
-        req->total_desc = req->local_desc = 1;
-        vscsi_swap_desc(req->cur_desc);
-        dprintf("VSCSI: using direct RDMA %s, 0x%x bytes MD: 0x%llx\n",
-                req->writing ? "write" : "read",
-                req->cur_desc->len, (unsigned long long)req->cur_desc->va);
-        break;
-    case SRP_DATA_DESC_INDIRECT:
-        req->ind_desc = (struct srp_indirect_buf *)(cmd->add_data + offset);
-        vscsi_swap_desc(&req->ind_desc->table_desc);
-        req->total_desc = req->ind_desc->table_desc.len /
-            sizeof(struct srp_direct_buf);
-        req->local_desc = req->writing ? cmd->data_out_desc_cnt :
-            cmd->data_in_desc_cnt;
-        for (i = 0; i < req->local_desc; i++) {
-            vscsi_swap_desc(&req->ind_desc->desc_list[i]);
-        }
-        req->cur_desc = req->local_desc ? &req->ind_desc->desc_list[0] : NULL;
-        dprintf("VSCSI: using indirect RDMA %s, 0x%x bytes %d descs "
-                "(%d local) VA: 0x%llx\n",
-                req->writing ? "read" : "write",
-                be32_to_cpu(req->ind_desc->len),
-                req->total_desc, req->local_desc,
-                (unsigned long long)req->ind_desc->table_desc.va);
-        break;
-    default:
-        fprintf(stderr,
-                "vscsi_preprocess_desc: Unknown format %x\n", req->dma_fmt);
-        return -1;
-    }
-
-    return 0;
-}
-
-/* Callback to indicate that the SCSI layer has completed a transfer.  */
-static void vscsi_transfer_data(SCSIRequest *sreq, uint32_t len)
-{
-    VSCSIState *s = DO_UPCAST(VSCSIState, vdev.qdev, sreq->bus->qbus.parent);
-    vscsi_req *req = sreq->hba_private;
-    uint8_t *buf;
-    int rc = 0;
-
-    dprintf("VSCSI: SCSI xfer complete tag=0x%x len=0x%x, req=%p\n",
-            sreq->tag, len, req);
-    if (req == NULL) {
-        fprintf(stderr, "VSCSI: Can't find request for tag 0x%x\n", sreq->tag);
-        return;
-    }
-
-    if (len) {
-        buf = scsi_req_get_buf(sreq);
-        rc = vscsi_srp_transfer_data(s, req, req->writing, buf, len);
-    }
-    if (rc < 0) {
-        fprintf(stderr, "VSCSI: RDMA error rc=%d!\n", rc);
-        vscsi_makeup_sense(s, req, HARDWARE_ERROR, 0, 0);
-        scsi_req_abort(req->sreq, CHECK_CONDITION);
-        return;
-    }
-
-    /* Start next chunk */
-    req->data_len -= rc;
-    scsi_req_continue(sreq);
-}
-
-/* Callback to indicate that the SCSI layer has completed a transfer.  */
-static void vscsi_command_complete(SCSIRequest *sreq, uint32_t status, size_t resid)
-{
-    VSCSIState *s = DO_UPCAST(VSCSIState, vdev.qdev, sreq->bus->qbus.parent);
-    vscsi_req *req = sreq->hba_private;
-    int32_t res_in = 0, res_out = 0;
-
-    dprintf("VSCSI: SCSI cmd complete, r=0x%x tag=0x%x status=0x%x, req=%p\n",
-            reason, sreq->tag, status, req);
-    if (req == NULL) {
-        fprintf(stderr, "VSCSI: Can't find request for tag 0x%x\n", sreq->tag);
-        return;
-    }
-
-    if (status == CHECK_CONDITION) {
-        req->senselen = scsi_req_get_sense(req->sreq, req->sense,
-                                           sizeof(req->sense));
-        dprintf("VSCSI: Sense data, %d bytes:\n", len);
-        dprintf("       %02x  %02x  %02x  %02x  %02x  %02x  %02x  %02x\n",
-                req->sense[0], req->sense[1], req->sense[2], req->sense[3],
-                req->sense[4], req->sense[5], req->sense[6], req->sense[7]);
-        dprintf("       %02x  %02x  %02x  %02x  %02x  %02x  %02x  %02x\n",
-                req->sense[8], req->sense[9], req->sense[10], req->sense[11],
-                req->sense[12], req->sense[13], req->sense[14], req->sense[15]);
-    }
-
-    dprintf("VSCSI: Command complete err=%d\n", status);
-    if (status == 0) {
-        /* We handle overflows, not underflows for normal commands,
-         * but hopefully nobody cares
-         */
-        if (req->writing) {
-            res_out = req->data_len;
-        } else {
-            res_in = req->data_len;
-        }
-    }
-    vscsi_send_rsp(s, req, status, res_in, res_out);
-    vscsi_put_req(req);
-}
-
-static void vscsi_request_cancelled(SCSIRequest *sreq)
-{
-    vscsi_req *req = sreq->hba_private;
-
-    vscsi_put_req(req);
-}
-
-static void vscsi_process_login(VSCSIState *s, vscsi_req *req)
-{
-    union viosrp_iu *iu = &req->iu;
-    struct srp_login_rsp *rsp = &iu->srp.login_rsp;
-    uint64_t tag = iu->srp.rsp.tag;
-
-    dprintf("VSCSI: Got login, sendin response !\n");
-
-    /* TODO handle case that requested size is wrong and
-     * buffer format is wrong
-     */
-    memset(iu, 0, sizeof(struct srp_login_rsp));
-    rsp->opcode = SRP_LOGIN_RSP;
-    /* Don't advertise quite as many request as we support to
-     * keep room for management stuff etc...
-     */
-    rsp->req_lim_delta = cpu_to_be32(VSCSI_REQ_LIMIT-2);
-    rsp->tag = tag;
-    rsp->max_it_iu_len = cpu_to_be32(sizeof(union srp_iu));
-    rsp->max_ti_iu_len = cpu_to_be32(sizeof(union srp_iu));
-    /* direct and indirect */
-    rsp->buf_fmt = cpu_to_be16(SRP_BUF_FORMAT_DIRECT | SRP_BUF_FORMAT_INDIRECT);
-
-    vscsi_send_iu(s, req, sizeof(*rsp), VIOSRP_SRP_FORMAT);
-}
-
-static void vscsi_inquiry_no_target(VSCSIState *s, vscsi_req *req)
-{
-    uint8_t *cdb = req->iu.srp.cmd.cdb;
-    uint8_t resp_data[36];
-    int rc, len, alen;
-
-    /* We dont do EVPD. Also check that page_code is 0 */
-    if ((cdb[1] & 0x01) || (cdb[1] & 0x01) || cdb[2] != 0) {
-        /* Send INVALID FIELD IN CDB */
-        vscsi_makeup_sense(s, req, ILLEGAL_REQUEST, 0x24, 0);
-        vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0);
-        return;
-    }
-    alen = cdb[3];
-    alen = (alen << 8) | cdb[4];
-    len = MIN(alen, 36);
-
-    /* Fake up inquiry using PQ=3 */
-    memset(resp_data, 0, 36);
-    resp_data[0] = 0x7f;   /* Not capable of supporting a device here */
-    resp_data[2] = 0x06;   /* SPS-4 */
-    resp_data[3] = 0x02;   /* Resp data format */
-    resp_data[4] = 36 - 5; /* Additional length */
-    resp_data[7] = 0x10;   /* Sync transfers */
-    memcpy(&resp_data[16], "QEMU EMPTY      ", 16);
-    memcpy(&resp_data[8], "QEMU    ", 8);
-
-    req->writing = 0;
-    vscsi_preprocess_desc(req);
-    rc = vscsi_srp_transfer_data(s, req, 0, resp_data, len);
-    if (rc < 0) {
-        vscsi_makeup_sense(s, req, HARDWARE_ERROR, 0, 0);
-        vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0);
-    } else {
-        vscsi_send_rsp(s, req, 0, 36 - rc, 0);
-    }
-}
-
-static int vscsi_queue_cmd(VSCSIState *s, vscsi_req *req)
-{
-    union srp_iu *srp = &req->iu.srp;
-    SCSIDevice *sdev;
-    int n, lun;
-
-    sdev = vscsi_device_find(&s->bus, be64_to_cpu(srp->cmd.lun), &lun);
-    if (!sdev) {
-        dprintf("VSCSI: Command for lun %08" PRIx64 " with no drive\n", be64_to_cpu(srp->cmd.lun));
-        if (srp->cmd.cdb[0] == INQUIRY) {
-            vscsi_inquiry_no_target(s, req);
-        } else {
-            vscsi_makeup_sense(s, req, ILLEGAL_REQUEST, 0x24, 0x00);
-            vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0);
-        } return 1;
-    }
-
-    req->lun = lun;
-    req->sreq = scsi_req_new(sdev, req->qtag, lun, srp->cmd.cdb, req);
-    n = scsi_req_enqueue(req->sreq);
-
-    dprintf("VSCSI: Queued command tag 0x%x CMD 0x%x ID %d LUN %d ret: %d\n",
-            req->qtag, srp->cmd.cdb[0], id, lun, n);
-
-    if (n) {
-        /* Transfer direction must be set before preprocessing the
-         * descriptors
-         */
-        req->writing = (n < 1);
-
-        /* Preprocess RDMA descriptors */
-        vscsi_preprocess_desc(req);
-
-        /* Get transfer direction and initiate transfer */
-        if (n > 0) {
-            req->data_len = n;
-        } else if (n < 0) {
-            req->data_len = -n;
-        }
-        scsi_req_continue(req->sreq);
-    }
-    /* Don't touch req here, it may have been recycled already */
-
-    return 0;
-}
-
-static int vscsi_process_tsk_mgmt(VSCSIState *s, vscsi_req *req)
-{
-    union viosrp_iu *iu = &req->iu;
-    int fn;
-
-    fprintf(stderr, "vscsi_process_tsk_mgmt %02x\n",
-            iu->srp.tsk_mgmt.tsk_mgmt_func);
-
-    switch (iu->srp.tsk_mgmt.tsk_mgmt_func) {
-#if 0 /* We really don't deal with these for now */
-    case SRP_TSK_ABORT_TASK:
-        fn = ABORT_TASK;
-        break;
-    case SRP_TSK_ABORT_TASK_SET:
-        fn = ABORT_TASK_SET;
-        break;
-    case SRP_TSK_CLEAR_TASK_SET:
-        fn = CLEAR_TASK_SET;
-        break;
-    case SRP_TSK_LUN_RESET:
-        fn = LOGICAL_UNIT_RESET;
-        break;
-    case SRP_TSK_CLEAR_ACA:
-        fn = CLEAR_ACA;
-        break;
-#endif
-    default:
-        fn = 0;
-    }
-    if (fn) {
-        /* XXX Send/Handle target task management */
-        ;
-    } else {
-        vscsi_makeup_sense(s, req, ILLEGAL_REQUEST, 0x20, 0);
-        vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0);
-    }
-    return !fn;
-}
-
-static int vscsi_handle_srp_req(VSCSIState *s, vscsi_req *req)
-{
-    union srp_iu *srp = &req->iu.srp;
-    int done = 1;
-    uint8_t opcode = srp->rsp.opcode;
-
-    switch (opcode) {
-    case SRP_LOGIN_REQ:
-        vscsi_process_login(s, req);
-        break;
-    case SRP_TSK_MGMT:
-        done = vscsi_process_tsk_mgmt(s, req);
-        break;
-    case SRP_CMD:
-        done = vscsi_queue_cmd(s, req);
-        break;
-    case SRP_LOGIN_RSP:
-    case SRP_I_LOGOUT:
-    case SRP_T_LOGOUT:
-    case SRP_RSP:
-    case SRP_CRED_REQ:
-    case SRP_CRED_RSP:
-    case SRP_AER_REQ:
-    case SRP_AER_RSP:
-        fprintf(stderr, "VSCSI: Unsupported opcode %02x\n", opcode);
-        break;
-    default:
-        fprintf(stderr, "VSCSI: Unknown type %02x\n", opcode);
-    }
-
-    return done;
-}
-
-static int vscsi_send_adapter_info(VSCSIState *s, vscsi_req *req)
-{
-    struct viosrp_adapter_info *sinfo;
-    struct mad_adapter_info_data info;
-    int rc;
-
-    sinfo = &req->iu.mad.adapter_info;
-
-#if 0 /* What for ? */
-    rc = spapr_vio_dma_read(&s->vdev, be64_to_cpu(sinfo->buffer),
-                            &info, be16_to_cpu(sinfo->common.length));
-    if (rc) {
-        fprintf(stderr, "vscsi_send_adapter_info: DMA read failure !\n");
-    }
-#endif
-    memset(&info, 0, sizeof(info));
-    strcpy(info.srp_version, SRP_VERSION);
-    memcpy(info.partition_name, "qemu", sizeof("qemu"));
-    info.partition_number = cpu_to_be32(0);
-    info.mad_version = cpu_to_be32(1);
-    info.os_type = cpu_to_be32(2);
-    info.port_max_txu[0] = cpu_to_be32(VSCSI_MAX_SECTORS << 9);
-
-    rc = spapr_vio_dma_write(&s->vdev, be64_to_cpu(sinfo->buffer),
-                             &info, be16_to_cpu(sinfo->common.length));
-    if (rc)  {
-        fprintf(stderr, "vscsi_send_adapter_info: DMA write failure !\n");
-    }
-
-    sinfo->common.status = rc ? cpu_to_be32(1) : 0;
-
-    return vscsi_send_iu(s, req, sizeof(*sinfo), VIOSRP_MAD_FORMAT);
-}
-
-static int vscsi_handle_mad_req(VSCSIState *s, vscsi_req *req)
-{
-    union mad_iu *mad = &req->iu.mad;
-
-    switch (be32_to_cpu(mad->empty_iu.common.type)) {
-    case VIOSRP_EMPTY_IU_TYPE:
-        fprintf(stderr, "Unsupported EMPTY MAD IU\n");
-        break;
-    case VIOSRP_ERROR_LOG_TYPE:
-        fprintf(stderr, "Unsupported ERROR LOG MAD IU\n");
-        mad->error_log.common.status = cpu_to_be16(1);
-        vscsi_send_iu(s, req, sizeof(mad->error_log), VIOSRP_MAD_FORMAT);
-        break;
-    case VIOSRP_ADAPTER_INFO_TYPE:
-        vscsi_send_adapter_info(s, req);
-        break;
-    case VIOSRP_HOST_CONFIG_TYPE:
-        mad->host_config.common.status = cpu_to_be16(1);
-        vscsi_send_iu(s, req, sizeof(mad->host_config), VIOSRP_MAD_FORMAT);
-        break;
-    default:
-        fprintf(stderr, "VSCSI: Unknown MAD type %02x\n",
-                be32_to_cpu(mad->empty_iu.common.type));
-    }
-
-    return 1;
-}
-
-static void vscsi_got_payload(VSCSIState *s, vscsi_crq *crq)
-{
-    vscsi_req *req;
-    int done;
-
-    req = vscsi_get_req(s);
-    if (req == NULL) {
-        fprintf(stderr, "VSCSI: Failed to get a request !\n");
-        return;
-    }
-
-    /* We only support a limited number of descriptors, we know
-     * the ibmvscsi driver uses up to 10 max, so it should fit
-     * in our 256 bytes IUs. If not we'll have to increase the size
-     * of the structure.
-     */
-    if (crq->s.IU_length > sizeof(union viosrp_iu)) {
-        fprintf(stderr, "VSCSI: SRP IU too long (%d bytes) !\n",
-                crq->s.IU_length);
-        vscsi_put_req(req);
-        return;
-    }
-
-    /* XXX Handle failure differently ? */
-    if (spapr_vio_dma_read(&s->vdev, crq->s.IU_data_ptr, &req->iu,
-                           crq->s.IU_length)) {
-        fprintf(stderr, "vscsi_got_payload: DMA read failure !\n");
-        vscsi_put_req(req);
-        return;
-    }
-    memcpy(&req->crq, crq, sizeof(vscsi_crq));
-
-    if (crq->s.format == VIOSRP_MAD_FORMAT) {
-        done = vscsi_handle_mad_req(s, req);
-    } else {
-        done = vscsi_handle_srp_req(s, req);
-    }
-
-    if (done) {
-        vscsi_put_req(req);
-    }
-}
-
-
-static int vscsi_do_crq(struct VIOsPAPRDevice *dev, uint8_t *crq_data)
-{
-    VSCSIState *s = DO_UPCAST(VSCSIState, vdev, dev);
-    vscsi_crq crq;
-
-    memcpy(crq.raw, crq_data, 16);
-    crq.s.timeout = be16_to_cpu(crq.s.timeout);
-    crq.s.IU_length = be16_to_cpu(crq.s.IU_length);
-    crq.s.IU_data_ptr = be64_to_cpu(crq.s.IU_data_ptr);
-
-    dprintf("VSCSI: do_crq %02x %02x ...\n", crq.raw[0], crq.raw[1]);
-
-    switch (crq.s.valid) {
-    case 0xc0: /* Init command/response */
-
-        /* Respond to initialization request */
-        if (crq.s.format == 0x01) {
-            memset(crq.raw, 0, 16);
-            crq.s.valid = 0xc0;
-            crq.s.format = 0x02;
-            spapr_vio_send_crq(dev, crq.raw);
-        }
-
-        /* Note that in hotplug cases, we might get a 0x02
-         * as a result of us emitting the init request
-         */
-
-        break;
-    case 0xff: /* Link event */
-
-        /* Not handled for now */
-
-        break;
-    case 0x80: /* Payloads */
-        switch (crq.s.format) {
-        case VIOSRP_SRP_FORMAT: /* AKA VSCSI request */
-        case VIOSRP_MAD_FORMAT: /* AKA VSCSI response */
-            vscsi_got_payload(s, &crq);
-            break;
-        case VIOSRP_OS400_FORMAT:
-        case VIOSRP_AIX_FORMAT:
-        case VIOSRP_LINUX_FORMAT:
-        case VIOSRP_INLINE_FORMAT:
-            fprintf(stderr, "vscsi_do_srq: Unsupported payload format %02x\n",
-                    crq.s.format);
-            break;
-        default:
-            fprintf(stderr, "vscsi_do_srq: Unknown payload format %02x\n",
-                    crq.s.format);
-        }
-        break;
-    default:
-        fprintf(stderr, "vscsi_do_crq: unknown CRQ %02x %02x ...\n",
-                crq.raw[0], crq.raw[1]);
-    };
-
-    return 0;
-}
-
-static const struct SCSIBusInfo vscsi_scsi_info = {
-    .tcq = true,
-    .max_channel = 7, /* logical unit addressing format */
-    .max_target = 63,
-    .max_lun = 31,
-
-    .transfer_data = vscsi_transfer_data,
-    .complete = vscsi_command_complete,
-    .cancel = vscsi_request_cancelled
-};
-
-static void spapr_vscsi_reset(VIOsPAPRDevice *dev)
-{
-    VSCSIState *s = DO_UPCAST(VSCSIState, vdev, dev);
-    int i;
-
-    memset(s->reqs, 0, sizeof(s->reqs));
-    for (i = 0; i < VSCSI_REQ_LIMIT; i++) {
-        s->reqs[i].qtag = i;
-    }
-}
-
-static int spapr_vscsi_init(VIOsPAPRDevice *dev)
-{
-    VSCSIState *s = DO_UPCAST(VSCSIState, vdev, dev);
-
-    dev->crq.SendFunc = vscsi_do_crq;
-
-    scsi_bus_new(&s->bus, &dev->qdev, &vscsi_scsi_info);
-    if (!dev->qdev.hotplugged) {
-        scsi_bus_legacy_handle_cmdline(&s->bus);
-    }
-
-    return 0;
-}
-
-void spapr_vscsi_create(VIOsPAPRBus *bus)
-{
-    DeviceState *dev;
-
-    dev = qdev_create(&bus->bus, "spapr-vscsi");
-
-    qdev_init_nofail(dev);
-}
-
-static int spapr_vscsi_devnode(VIOsPAPRDevice *dev, void *fdt, int node_off)
-{
-    int ret;
-
-    ret = fdt_setprop_cell(fdt, node_off, "#address-cells", 2);
-    if (ret < 0) {
-        return ret;
-    }
-
-    ret = fdt_setprop_cell(fdt, node_off, "#size-cells", 0);
-    if (ret < 0) {
-        return ret;
-    }
-
-    return 0;
-}
-
-static Property spapr_vscsi_properties[] = {
-    DEFINE_SPAPR_PROPERTIES(VSCSIState, vdev),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void spapr_vscsi_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    VIOsPAPRDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass);
-
-    k->init = spapr_vscsi_init;
-    k->reset = spapr_vscsi_reset;
-    k->devnode = spapr_vscsi_devnode;
-    k->dt_name = "v-scsi";
-    k->dt_type = "vscsi";
-    k->dt_compatible = "IBM,v-scsi";
-    k->signal_mask = 0x00000001;
-    dc->props = spapr_vscsi_properties;
-    k->rtce_window_size = 0x10000000;
-}
-
-static const 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_types(void)
-{
-    type_register_static(&spapr_vscsi_info);
-}
-
-type_init(spapr_vscsi_register_types)
diff --git a/hw/spapr_vty.c b/hw/spapr_vty.c
deleted file mode 100644 (file)
index be08571..0000000
+++ /dev/null
@@ -1,221 +0,0 @@
-#include "hw/qdev.h"
-#include "char/char.h"
-#include "hw/spapr.h"
-#include "hw/spapr_vio.h"
-
-#define VTERM_BUFSIZE   16
-
-typedef struct VIOsPAPRVTYDevice {
-    VIOsPAPRDevice sdev;
-    CharDriverState *chardev;
-    uint32_t in, out;
-    uint8_t buf[VTERM_BUFSIZE];
-} VIOsPAPRVTYDevice;
-
-static int vty_can_receive(void *opaque)
-{
-    VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)opaque;
-
-    return (dev->in - dev->out) < VTERM_BUFSIZE;
-}
-
-static void vty_receive(void *opaque, const uint8_t *buf, int size)
-{
-    VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)opaque;
-    int i;
-
-    if ((dev->in == dev->out) && size) {
-        /* toggle line to simulate edge interrupt */
-        qemu_irq_pulse(spapr_vio_qirq(&dev->sdev));
-    }
-    for (i = 0; i < size; i++) {
-        assert((dev->in - dev->out) < VTERM_BUFSIZE);
-        dev->buf[dev->in++ % VTERM_BUFSIZE] = buf[i];
-    }
-}
-
-static int vty_getchars(VIOsPAPRDevice *sdev, uint8_t *buf, int max)
-{
-    VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)sdev;
-    int n = 0;
-
-    while ((n < max) && (dev->out != dev->in)) {
-        buf[n++] = dev->buf[dev->out++ % VTERM_BUFSIZE];
-    }
-
-    return n;
-}
-
-void vty_putchars(VIOsPAPRDevice *sdev, uint8_t *buf, int len)
-{
-    VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)sdev;
-
-    /* FIXME: should check the qemu_chr_fe_write() return value */
-    qemu_chr_fe_write(dev->chardev, buf, len);
-}
-
-static int spapr_vty_init(VIOsPAPRDevice *sdev)
-{
-    VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)sdev;
-
-    if (!dev->chardev) {
-        fprintf(stderr, "spapr-vty: Can't create vty without a chardev!\n");
-        exit(1);
-    }
-
-    qemu_chr_add_handlers(dev->chardev, vty_can_receive,
-                          vty_receive, NULL, dev);
-
-    return 0;
-}
-
-/* Forward declaration */
-static target_ulong h_put_term_char(PowerPCCPU *cpu, sPAPREnvironment *spapr,
-                                    target_ulong opcode, target_ulong *args)
-{
-    target_ulong reg = args[0];
-    target_ulong len = args[1];
-    target_ulong char0_7 = args[2];
-    target_ulong char8_15 = args[3];
-    VIOsPAPRDevice *sdev;
-    uint8_t buf[16];
-
-    sdev = vty_lookup(spapr, reg);
-    if (!sdev) {
-        return H_PARAMETER;
-    }
-
-    if (len > 16) {
-        return H_PARAMETER;
-    }
-
-    *((uint64_t *)buf) = cpu_to_be64(char0_7);
-    *((uint64_t *)buf + 1) = cpu_to_be64(char8_15);
-
-    vty_putchars(sdev, buf, len);
-
-    return H_SUCCESS;
-}
-
-static target_ulong h_get_term_char(PowerPCCPU *cpu, sPAPREnvironment *spapr,
-                                    target_ulong opcode, target_ulong *args)
-{
-    target_ulong reg = args[0];
-    target_ulong *len = args + 0;
-    target_ulong *char0_7 = args + 1;
-    target_ulong *char8_15 = args + 2;
-    VIOsPAPRDevice *sdev;
-    uint8_t buf[16];
-
-    sdev = vty_lookup(spapr, reg);
-    if (!sdev) {
-        return H_PARAMETER;
-    }
-
-    *len = vty_getchars(sdev, buf, sizeof(buf));
-    if (*len < 16) {
-        memset(buf + *len, 0, 16 - *len);
-    }
-
-    *char0_7 = be64_to_cpu(*((uint64_t *)buf));
-    *char8_15 = be64_to_cpu(*((uint64_t *)buf + 1));
-
-    return H_SUCCESS;
-}
-
-void spapr_vty_create(VIOsPAPRBus *bus, CharDriverState *chardev)
-{
-    DeviceState *dev;
-
-    dev = qdev_create(&bus->bus, "spapr-vty");
-    qdev_prop_set_chr(dev, "chardev", chardev);
-    qdev_init_nofail(dev);
-}
-
-static Property spapr_vty_properties[] = {
-    DEFINE_SPAPR_PROPERTIES(VIOsPAPRVTYDevice, sdev),
-    DEFINE_PROP_CHR("chardev", VIOsPAPRVTYDevice, chardev),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void spapr_vty_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    VIOsPAPRDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass);
-
-    k->init = spapr_vty_init;
-    k->dt_name = "vty";
-    k->dt_type = "serial";
-    k->dt_compatible = "hvterm1";
-    dc->props = spapr_vty_properties;
-}
-
-static const 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)
-{
-    VIOsPAPRDevice *sdev, *selected;
-    BusChild *kid;
-
-    /*
-     * To avoid the console bouncing around we want one VTY to be
-     * the "default". We haven't really got anything to go on, so
-     * arbitrarily choose the one with the lowest reg value.
-     */
-
-    selected = NULL;
-    QTAILQ_FOREACH(kid, &bus->bus.children, sibling) {
-        DeviceState *iter = kid->child;
-
-        /* Only look at VTY devices */
-        if (!object_dynamic_cast(OBJECT(iter), "spapr-vty")) {
-            continue;
-        }
-
-        sdev = DO_UPCAST(VIOsPAPRDevice, qdev, iter);
-
-        /* First VTY we've found, so it is selected for now */
-        if (!selected) {
-            selected = sdev;
-            continue;
-        }
-
-        /* Choose VTY with lowest reg value */
-        if (sdev->reg < selected->reg) {
-            selected = sdev;
-        }
-    }
-
-    return selected;
-}
-
-VIOsPAPRDevice *vty_lookup(sPAPREnvironment *spapr, target_ulong reg)
-{
-    VIOsPAPRDevice *sdev;
-
-    sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
-    if (!sdev && reg == 0) {
-        /* Hack for kernel early debug, which always specifies reg==0.
-         * We search all VIO devices, and grab the vty with the lowest
-         * reg.  This attempts to mimic existing PowerVM behaviour
-         * (early debug does work there, despite having no vty with
-         * reg==0. */
-        return spapr_vty_get_default(spapr->vio_bus);
-    }
-
-    return sdev;
-}
-
-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);
-}
-
-type_init(spapr_vty_register_types)
index 71bbddf8c31c8e441360c7a762aaefe508e01e07..c987b5b5df1c786c02f0c644eedd21c0c02b143c 100644 (file)
@@ -1,10 +1 @@
-obj-y = lance.o tcx.o sun4m_iommu.o slavio_intctl.o
-obj-y += slavio_timer.o slavio_misc.o sparc32_dma.o
-obj-y += cs4231.o eccmemctl.o sbi.o sun4c_intctl.o
-
-# GRLIB
-obj-y += grlib_gptimer.o grlib_irqmp.o grlib_apbuart.o
-
-obj-y := $(addprefix ../,$(obj-y))
-
 obj-y += sun4m.o leon3.o
index bf06bf4b51c376e92a59a594c9ca421766018c0c..3b27d4019a7b0652e989c0d75b592afaf21b8e56 100644 (file)
@@ -32,7 +32,7 @@
 #include "trace.h"
 #include "exec/address-spaces.h"
 
-#include "hw/grlib.h"
+#include "hw/sparc/grlib.h"
 
 /* Default system clock.  */
 #define CPU_CLK (40 * 1000 * 1000)
index 9ebda02aa13ff1b2d36d3b262619d5a8fb78d228..31beb328858a4377af1ba485a741785746b6fd8f 100644 (file)
  */
 #include "hw/sysbus.h"
 #include "qemu/timer.h"
-#include "hw/sun4m.h"
-#include "hw/nvram.h"
-#include "hw/sparc32_dma.h"
-#include "hw/fdc.h"
+#include "hw/sparc/sun4m.h"
+#include "hw/timer/m48t59.h"
+#include "hw/sparc/sparc32_dma.h"
+#include "hw/block/fdc.h"
 #include "sysemu/sysemu.h"
 #include "net/net.h"
 #include "hw/boards.h"
-#include "hw/firmware_abi.h"
-#include "hw/esp.h"
-#include "hw/pc.h"
-#include "hw/isa.h"
-#include "hw/fw_cfg.h"
-#include "hw/escc.h"
+#include "hw/sparc/firmware_abi.h"
+#include "hw/scsi/esp.h"
+#include "hw/i386/pc.h"
+#include "hw/isa/isa.h"
+#include "hw/nvram/fw_cfg.h"
+#include "hw/char/escc.h"
 #include "hw/empty_slot.h"
 #include "hw/qdev-addr.h"
 #include "hw/loader.h"
diff --git a/hw/sparc32_dma.c b/hw/sparc32_dma.c
deleted file mode 100644 (file)
index 18e368e..0000000
+++ /dev/null
@@ -1,315 +0,0 @@
-/*
- * QEMU Sparc32 DMA controller emulation
- *
- * Copyright (c) 2006 Fabrice Bellard
- *
- * Modifications:
- *  2010-Feb-14 Artyom Tarasenko : reworked irq generation
- *
- * 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 "hw/hw.h"
-#include "hw/sparc32_dma.h"
-#include "hw/sun4m.h"
-#include "hw/sysbus.h"
-#include "trace.h"
-
-/*
- * This is the DMA controller part of chip STP2000 (Master I/O), also
- * produced as NCR89C100. See
- * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C100.txt
- * and
- * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/DMA2.txt
- */
-
-#define DMA_REGS 4
-#define DMA_SIZE (4 * sizeof(uint32_t))
-/* We need the mask, because one instance of the device is not page
-   aligned (ledma, start address 0x0010) */
-#define DMA_MASK (DMA_SIZE - 1)
-/* OBP says 0x20 bytes for ledma, the extras are aliased to espdma */
-#define DMA_ETH_SIZE (8 * sizeof(uint32_t))
-#define DMA_MAX_REG_OFFSET (2 * DMA_SIZE - 1)
-
-#define DMA_VER 0xa0000000
-#define DMA_INTR 1
-#define DMA_INTREN 0x10
-#define DMA_WRITE_MEM 0x100
-#define DMA_EN 0x200
-#define DMA_LOADED 0x04000000
-#define DMA_DRAIN_FIFO 0x40
-#define DMA_RESET 0x80
-
-/* XXX SCSI and ethernet should have different read-only bit masks */
-#define DMA_CSR_RO_MASK 0xfe000007
-
-typedef struct DMAState DMAState;
-
-struct DMAState {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-    uint32_t dmaregs[DMA_REGS];
-    qemu_irq irq;
-    void *iommu;
-    qemu_irq gpio[2];
-    uint32_t is_ledma;
-};
-
-enum {
-    GPIO_RESET = 0,
-    GPIO_DMA,
-};
-
-/* Note: on sparc, the lance 16 bit bus is swapped */
-void ledma_memory_read(void *opaque, hwaddr addr,
-                       uint8_t *buf, int len, int do_bswap)
-{
-    DMAState *s = opaque;
-    int i;
-
-    addr |= s->dmaregs[3];
-    trace_ledma_memory_read(addr);
-    if (do_bswap) {
-        sparc_iommu_memory_read(s->iommu, addr, buf, len);
-    } else {
-        addr &= ~1;
-        len &= ~1;
-        sparc_iommu_memory_read(s->iommu, addr, buf, len);
-        for(i = 0; i < len; i += 2) {
-            bswap16s((uint16_t *)(buf + i));
-        }
-    }
-}
-
-void ledma_memory_write(void *opaque, hwaddr addr,
-                        uint8_t *buf, int len, int do_bswap)
-{
-    DMAState *s = opaque;
-    int l, i;
-    uint16_t tmp_buf[32];
-
-    addr |= s->dmaregs[3];
-    trace_ledma_memory_write(addr);
-    if (do_bswap) {
-        sparc_iommu_memory_write(s->iommu, addr, buf, len);
-    } else {
-        addr &= ~1;
-        len &= ~1;
-        while (len > 0) {
-            l = len;
-            if (l > sizeof(tmp_buf))
-                l = sizeof(tmp_buf);
-            for(i = 0; i < l; i += 2) {
-                tmp_buf[i >> 1] = bswap16(*(uint16_t *)(buf + i));
-            }
-            sparc_iommu_memory_write(s->iommu, addr, (uint8_t *)tmp_buf, l);
-            len -= l;
-            buf += l;
-            addr += l;
-        }
-    }
-}
-
-static void dma_set_irq(void *opaque, int irq, int level)
-{
-    DMAState *s = opaque;
-    if (level) {
-        s->dmaregs[0] |= DMA_INTR;
-        if (s->dmaregs[0] & DMA_INTREN) {
-            trace_sparc32_dma_set_irq_raise();
-            qemu_irq_raise(s->irq);
-        }
-    } else {
-        if (s->dmaregs[0] & DMA_INTR) {
-            s->dmaregs[0] &= ~DMA_INTR;
-            if (s->dmaregs[0] & DMA_INTREN) {
-                trace_sparc32_dma_set_irq_lower();
-                qemu_irq_lower(s->irq);
-            }
-        }
-    }
-}
-
-void espdma_memory_read(void *opaque, uint8_t *buf, int len)
-{
-    DMAState *s = opaque;
-
-    trace_espdma_memory_read(s->dmaregs[1]);
-    sparc_iommu_memory_read(s->iommu, s->dmaregs[1], buf, len);
-    s->dmaregs[1] += len;
-}
-
-void espdma_memory_write(void *opaque, uint8_t *buf, int len)
-{
-    DMAState *s = opaque;
-
-    trace_espdma_memory_write(s->dmaregs[1]);
-    sparc_iommu_memory_write(s->iommu, s->dmaregs[1], buf, len);
-    s->dmaregs[1] += len;
-}
-
-static uint64_t dma_mem_read(void *opaque, hwaddr addr,
-                             unsigned size)
-{
-    DMAState *s = opaque;
-    uint32_t saddr;
-
-    if (s->is_ledma && (addr > DMA_MAX_REG_OFFSET)) {
-        /* aliased to espdma, but we can't get there from here */
-        /* buggy driver if using undocumented behavior, just return 0 */
-        trace_sparc32_dma_mem_readl(addr, 0);
-        return 0;
-    }
-    saddr = (addr & DMA_MASK) >> 2;
-    trace_sparc32_dma_mem_readl(addr, s->dmaregs[saddr]);
-    return s->dmaregs[saddr];
-}
-
-static void dma_mem_write(void *opaque, hwaddr addr,
-                          uint64_t val, unsigned size)
-{
-    DMAState *s = opaque;
-    uint32_t saddr;
-
-    if (s->is_ledma && (addr > DMA_MAX_REG_OFFSET)) {
-        /* aliased to espdma, but we can't get there from here */
-        trace_sparc32_dma_mem_writel(addr, 0, val);
-        return;
-    }
-    saddr = (addr & DMA_MASK) >> 2;
-    trace_sparc32_dma_mem_writel(addr, s->dmaregs[saddr], val);
-    switch (saddr) {
-    case 0:
-        if (val & DMA_INTREN) {
-            if (s->dmaregs[0] & DMA_INTR) {
-                trace_sparc32_dma_set_irq_raise();
-                qemu_irq_raise(s->irq);
-            }
-        } else {
-            if (s->dmaregs[0] & (DMA_INTR | DMA_INTREN)) {
-                trace_sparc32_dma_set_irq_lower();
-                qemu_irq_lower(s->irq);
-            }
-        }
-        if (val & DMA_RESET) {
-            qemu_irq_raise(s->gpio[GPIO_RESET]);
-            qemu_irq_lower(s->gpio[GPIO_RESET]);
-        } else if (val & DMA_DRAIN_FIFO) {
-            val &= ~DMA_DRAIN_FIFO;
-        } else if (val == 0)
-            val = DMA_DRAIN_FIFO;
-
-        if (val & DMA_EN && !(s->dmaregs[0] & DMA_EN)) {
-            trace_sparc32_dma_enable_raise();
-            qemu_irq_raise(s->gpio[GPIO_DMA]);
-        } else if (!(val & DMA_EN) && !!(s->dmaregs[0] & DMA_EN)) {
-            trace_sparc32_dma_enable_lower();
-            qemu_irq_lower(s->gpio[GPIO_DMA]);
-        }
-
-        val &= ~DMA_CSR_RO_MASK;
-        val |= DMA_VER;
-        s->dmaregs[0] = (s->dmaregs[0] & DMA_CSR_RO_MASK) | val;
-        break;
-    case 1:
-        s->dmaregs[0] |= DMA_LOADED;
-        /* fall through */
-    default:
-        s->dmaregs[saddr] = val;
-        break;
-    }
-}
-
-static const MemoryRegionOps dma_mem_ops = {
-    .read = dma_mem_read,
-    .write = dma_mem_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-};
-
-static void dma_reset(DeviceState *d)
-{
-    DMAState *s = container_of(d, DMAState, busdev.qdev);
-
-    memset(s->dmaregs, 0, DMA_SIZE);
-    s->dmaregs[0] = DMA_VER;
-}
-
-static const VMStateDescription vmstate_dma = {
-    .name ="sparc32_dma",
-    .version_id = 2,
-    .minimum_version_id = 2,
-    .minimum_version_id_old = 2,
-    .fields      = (VMStateField []) {
-        VMSTATE_UINT32_ARRAY(dmaregs, DMAState, DMA_REGS),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static int sparc32_dma_init1(SysBusDevice *dev)
-{
-    DMAState *s = FROM_SYSBUS(DMAState, dev);
-    int reg_size;
-
-    sysbus_init_irq(dev, &s->irq);
-
-    reg_size = s->is_ledma ? DMA_ETH_SIZE : DMA_SIZE;
-    memory_region_init_io(&s->iomem, &dma_mem_ops, s, "dma", reg_size);
-    sysbus_init_mmio(dev, &s->iomem);
-
-    qdev_init_gpio_in(&dev->qdev, dma_set_irq, 1);
-    qdev_init_gpio_out(&dev->qdev, s->gpio, 2);
-
-    return 0;
-}
-
-static Property sparc32_dma_properties[] = {
-    DEFINE_PROP_PTR("iommu_opaque", DMAState, iommu),
-    DEFINE_PROP_UINT32("is_ledma", DMAState, is_ledma, 0),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void sparc32_dma_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = sparc32_dma_init1;
-    dc->reset = dma_reset;
-    dc->vmsd = &vmstate_dma;
-    dc->props = sparc32_dma_properties;
-}
-
-static const 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_types(void)
-{
-    type_register_static(&sparc32_dma_info);
-}
-
-type_init(sparc32_dma_register_types)
diff --git a/hw/sparc32_dma.h b/hw/sparc32_dma.h
deleted file mode 100644 (file)
index 9497b13..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-#ifndef SPARC32_DMA_H
-#define SPARC32_DMA_H
-
-/* sparc32_dma.c */
-void ledma_memory_read(void *opaque, hwaddr addr,
-                       uint8_t *buf, int len, int do_bswap);
-void ledma_memory_write(void *opaque, hwaddr addr,
-                        uint8_t *buf, int len, int do_bswap);
-void espdma_memory_read(void *opaque, uint8_t *buf, int len);
-void espdma_memory_write(void *opaque, uint8_t *buf, int len);
-
-#endif
index 4df0d90ec24cdacc3a294751839bd39c7909dbe6..a84cfe3ec79c845ffe9b439e74b09df7aac1e0b7 100644 (file)
@@ -1,6 +1 @@
-obj-y = apb_pci.o
-obj-y += mc146818rtc.o
-
-obj-y := $(addprefix ../,$(obj-y))
-
 obj-y += sun4u.o
index 4c39cf660705425fea7bd8ab4edccd913bc01ba0..0d29620094c8ece3214983e9c3ef6f72664d7126 100644 (file)
  */
 #include "hw/hw.h"
 #include "hw/pci/pci.h"
-#include "hw/apb_pci.h"
-#include "hw/pc.h"
-#include "hw/serial.h"
-#include "hw/nvram.h"
-#include "hw/fdc.h"
+#include "hw/pci-host/apb.h"
+#include "hw/i386/pc.h"
+#include "hw/char/serial.h"
+#include "hw/timer/m48t59.h"
+#include "hw/block/fdc.h"
 #include "net/net.h"
 #include "qemu/timer.h"
 #include "sysemu/sysemu.h"
 #include "hw/boards.h"
-#include "hw/firmware_abi.h"
-#include "hw/fw_cfg.h"
+#include "hw/sparc/firmware_abi.h"
+#include "hw/nvram/fw_cfg.h"
 #include "hw/sysbus.h"
 #include "hw/ide.h"
 #include "hw/loader.h"
diff --git a/hw/srp.h b/hw/srp.h
deleted file mode 100644 (file)
index 5e0cad5..0000000
--- a/hw/srp.h
+++ /dev/null
@@ -1,240 +0,0 @@
-/*
- * Copyright (c) 2005 Cisco Systems.  All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses.  You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- *     Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *      - Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *
- *      - Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- * 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 SCSI_SRP_H
-#define SCSI_SRP_H
-
-/*
- * Structures and constants for the SCSI RDMA Protocol (SRP) as
- * defined by the INCITS T10 committee.  This file was written using
- * draft Revision 16a of the SRP standard.
- */
-
-enum {
-
-    SRP_LOGIN_REQ = 0x00,
-    SRP_TSK_MGMT  = 0x01,
-    SRP_CMD       = 0x02,
-    SRP_I_LOGOUT  = 0x03,
-    SRP_LOGIN_RSP = 0xc0,
-    SRP_RSP       = 0xc1,
-    SRP_LOGIN_REJ = 0xc2,
-    SRP_T_LOGOUT  = 0x80,
-    SRP_CRED_REQ  = 0x81,
-    SRP_AER_REQ   = 0x82,
-    SRP_CRED_RSP  = 0x41,
-    SRP_AER_RSP   = 0x42
-};
-
-enum {
-    SRP_BUF_FORMAT_DIRECT   = 1 << 1,
-    SRP_BUF_FORMAT_INDIRECT = 1 << 2
-};
-
-enum {
-    SRP_NO_DATA_DESC       = 0,
-    SRP_DATA_DESC_DIRECT   = 1,
-    SRP_DATA_DESC_INDIRECT = 2
-};
-
-enum {
-    SRP_TSK_ABORT_TASK     = 0x01,
-    SRP_TSK_ABORT_TASK_SET = 0x02,
-    SRP_TSK_CLEAR_TASK_SET = 0x04,
-    SRP_TSK_LUN_RESET      = 0x08,
-    SRP_TSK_CLEAR_ACA      = 0x40
-};
-
-enum srp_login_rej_reason {
-    SRP_LOGIN_REJ_UNABLE_ESTABLISH_CHANNEL   = 0x00010000,
-    SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES     = 0x00010001,
-    SRP_LOGIN_REJ_REQ_IT_IU_LENGTH_TOO_LARGE = 0x00010002,
-    SRP_LOGIN_REJ_UNABLE_ASSOCIATE_CHANNEL   = 0x00010003,
-    SRP_LOGIN_REJ_UNSUPPORTED_DESCRIPTOR_FMT = 0x00010004,
-    SRP_LOGIN_REJ_MULTI_CHANNEL_UNSUPPORTED  = 0x00010005,
-    SRP_LOGIN_REJ_CHANNEL_LIMIT_REACHED      = 0x00010006
-};
-
-enum {
-    SRP_REV10_IB_IO_CLASS  = 0xff00,
-    SRP_REV16A_IB_IO_CLASS = 0x0100
-};
-
-struct srp_direct_buf {
-    uint64_t    va;
-    uint32_t    key;
-    uint32_t    len;
-};
-
-/*
- * We need the packed attribute because the SRP spec puts the list of
- * descriptors at an offset of 20, which is not aligned to the size of
- * struct srp_direct_buf.  The whole structure must be packed to avoid
- * having the 20-byte structure padded to 24 bytes on 64-bit architectures.
- */
-struct srp_indirect_buf {
-    struct srp_direct_buf    table_desc;
-    uint32_t                 len;
-    struct srp_direct_buf    desc_list[0];
-} QEMU_PACKED;
-
-enum {
-    SRP_MULTICHAN_SINGLE = 0,
-    SRP_MULTICHAN_MULTI  = 1
-};
-
-struct srp_login_req {
-    uint8_t    opcode;
-    uint8_t    reserved1[7];
-    uint64_t   tag;
-    uint32_t   req_it_iu_len;
-    uint8_t    reserved2[4];
-    uint16_t   req_buf_fmt;
-    uint8_t    req_flags;
-    uint8_t    reserved3[5];
-    uint8_t    initiator_port_id[16];
-    uint8_t    target_port_id[16];
-};
-
-/*
- * The SRP spec defines the size of the LOGIN_RSP structure to be 52
- * bytes, so it needs to be packed to avoid having it padded to 56
- * bytes on 64-bit architectures.
- */
-struct srp_login_rsp {
-    uint8_t    opcode;
-    uint8_t    reserved1[3];
-    uint32_t   req_lim_delta;
-    uint64_t   tag;
-    uint32_t   max_it_iu_len;
-    uint32_t   max_ti_iu_len;
-    uint16_t   buf_fmt;
-    uint8_t    rsp_flags;
-    uint8_t    reserved2[25];
-} QEMU_PACKED;
-
-struct srp_login_rej {
-    uint8_t    opcode;
-    uint8_t    reserved1[3];
-    uint32_t   reason;
-    uint64_t   tag;
-    uint8_t    reserved2[8];
-    uint16_t   buf_fmt;
-    uint8_t    reserved3[6];
-};
-
-struct srp_i_logout {
-    uint8_t    opcode;
-    uint8_t    reserved[7];
-    uint64_t   tag;
-};
-
-struct srp_t_logout {
-    uint8_t    opcode;
-    uint8_t    sol_not;
-    uint8_t    reserved[2];
-    uint32_t   reason;
-    uint64_t   tag;
-};
-
-/*
- * We need the packed attribute because the SRP spec only aligns the
- * 8-byte LUN field to 4 bytes.
- */
-struct srp_tsk_mgmt {
-    uint8_t    opcode;
-    uint8_t    sol_not;
-    uint8_t    reserved1[6];
-    uint64_t   tag;
-    uint8_t    reserved2[4];
-    uint64_t   lun;
-    uint8_t    reserved3[2];
-    uint8_t    tsk_mgmt_func;
-    uint8_t    reserved4;
-    uint64_t   task_tag;
-    uint8_t    reserved5[8];
-} QEMU_PACKED;
-
-/*
- * We need the packed attribute because the SRP spec only aligns the
- * 8-byte LUN field to 4 bytes.
- */
-struct srp_cmd {
-    uint8_t    opcode;
-    uint8_t    sol_not;
-    uint8_t    reserved1[3];
-    uint8_t    buf_fmt;
-    uint8_t    data_out_desc_cnt;
-    uint8_t    data_in_desc_cnt;
-    uint64_t   tag;
-    uint8_t    reserved2[4];
-    uint64_t   lun;
-    uint8_t    reserved3;
-    uint8_t    task_attr;
-    uint8_t    reserved4;
-    uint8_t    add_cdb_len;
-    uint8_t    cdb[16];
-    uint8_t    add_data[0];
-} QEMU_PACKED;
-
-enum {
-    SRP_RSP_FLAG_RSPVALID = 1 << 0,
-    SRP_RSP_FLAG_SNSVALID = 1 << 1,
-    SRP_RSP_FLAG_DOOVER   = 1 << 2,
-    SRP_RSP_FLAG_DOUNDER  = 1 << 3,
-    SRP_RSP_FLAG_DIOVER   = 1 << 4,
-    SRP_RSP_FLAG_DIUNDER  = 1 << 5
-};
-
-/*
- * The SRP spec defines the size of the RSP structure to be 36 bytes,
- * so it needs to be packed to avoid having it padded to 40 bytes on
- * 64-bit architectures.
- */
-struct srp_rsp {
-    uint8_t    opcode;
-    uint8_t    sol_not;
-    uint8_t    reserved1[2];
-    uint32_t   req_lim_delta;
-    uint64_t   tag;
-    uint8_t    reserved2[2];
-    uint8_t    flags;
-    uint8_t    status;
-    uint32_t   data_out_res_cnt;
-    uint32_t   data_in_res_cnt;
-    uint32_t   sense_data_len;
-    uint32_t   resp_data_len;
-    uint8_t    data[0];
-} QEMU_PACKED;
-
-#endif /* SCSI_SRP_H */
diff --git a/hw/ssd0303.c b/hw/ssd0303.c
deleted file mode 100644 (file)
index 68d1f24..0000000
+++ /dev/null
@@ -1,322 +0,0 @@
-/*
- * SSD0303 OLED controller with OSRAM Pictiva 96x16 display.
- *
- * Copyright (c) 2006-2007 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the GPL.
- */
-
-/* The controller can support a variety of different displays, but we only
-   implement one.  Most of the commends relating to brightness and geometry
-   setup are ignored. */
-#include "hw/i2c.h"
-#include "ui/console.h"
-
-//#define DEBUG_SSD0303 1
-
-#ifdef DEBUG_SSD0303
-#define DPRINTF(fmt, ...) \
-do { printf("ssd0303: " fmt , ## __VA_ARGS__); } while (0)
-#define BADF(fmt, ...) \
-do { fprintf(stderr, "ssd0303: error: " fmt , ## __VA_ARGS__); exit(1);} while (0)
-#else
-#define DPRINTF(fmt, ...) do {} while(0)
-#define BADF(fmt, ...) \
-do { fprintf(stderr, "ssd0303: error: " fmt , ## __VA_ARGS__);} while (0)
-#endif
-
-/* Scaling factor for pixels.  */
-#define MAGNIFY 4
-
-enum ssd0303_mode
-{
-    SSD0303_IDLE,
-    SSD0303_DATA,
-    SSD0303_CMD
-};
-
-enum ssd0303_cmd {
-    SSD0303_CMD_NONE,
-    SSD0303_CMD_SKIP1
-};
-
-typedef struct {
-    I2CSlave i2c;
-    QemuConsole *con;
-    int row;
-    int col;
-    int start_line;
-    int mirror;
-    int flash;
-    int enabled;
-    int inverse;
-    int redraw;
-    enum ssd0303_mode mode;
-    enum ssd0303_cmd cmd_state;
-    uint8_t framebuffer[132*8];
-} ssd0303_state;
-
-static int ssd0303_recv(I2CSlave *i2c)
-{
-    BADF("Reads not implemented\n");
-    return -1;
-}
-
-static int ssd0303_send(I2CSlave *i2c, uint8_t data)
-{
-    ssd0303_state *s = (ssd0303_state *)i2c;
-    enum ssd0303_cmd old_cmd_state;
-    switch (s->mode) {
-    case SSD0303_IDLE:
-        DPRINTF("byte 0x%02x\n", data);
-        if (data == 0x80)
-            s->mode = SSD0303_CMD;
-        else if (data == 0x40)
-            s->mode = SSD0303_DATA;
-        else
-            BADF("Unexpected byte 0x%x\n", data);
-        break;
-    case SSD0303_DATA:
-        DPRINTF("data 0x%02x\n", data);
-        if (s->col < 132) {
-            s->framebuffer[s->col + s->row * 132] = data;
-            s->col++;
-            s->redraw = 1;
-        }
-        break;
-    case SSD0303_CMD:
-        old_cmd_state = s->cmd_state;
-        s->cmd_state = SSD0303_CMD_NONE;
-        switch (old_cmd_state) {
-        case SSD0303_CMD_NONE:
-            DPRINTF("cmd 0x%02x\n", data);
-            s->mode = SSD0303_IDLE;
-            switch (data) {
-            case 0x00 ... 0x0f: /* Set lower column address.  */
-                s->col = (s->col & 0xf0) | (data & 0xf);
-                break;
-            case 0x10 ... 0x20: /* Set higher column address.  */
-                s->col = (s->col & 0x0f) | ((data & 0xf) << 4);
-                break;
-            case 0x40 ... 0x7f: /* Set start line.  */
-                s->start_line = 0;
-                break;
-            case 0x81: /* Set contrast (Ignored).  */
-                s->cmd_state = SSD0303_CMD_SKIP1;
-                break;
-            case 0xa0: /* Mirror off.  */
-                s->mirror = 0;
-                break;
-            case 0xa1: /* Mirror off.  */
-                s->mirror = 1;
-                break;
-            case 0xa4: /* Entire display off.  */
-                s->flash = 0;
-                break;
-            case 0xa5: /* Entire display on.  */
-                s->flash = 1;
-                break;
-            case 0xa6: /* Inverse off.  */
-                s->inverse = 0;
-                break;
-            case 0xa7: /* Inverse on.  */
-                s->inverse = 1;
-                break;
-            case 0xa8: /* Set multiplied ratio (Ignored).  */
-                s->cmd_state = SSD0303_CMD_SKIP1;
-                break;
-            case 0xad: /* DC-DC power control.  */
-                s->cmd_state = SSD0303_CMD_SKIP1;
-                break;
-            case 0xae: /* Display off.  */
-                s->enabled = 0;
-                break;
-            case 0xaf: /* Display on.  */
-                s->enabled = 1;
-                break;
-            case 0xb0 ... 0xbf: /* Set Page address.  */
-                s->row = data & 7;
-                break;
-            case 0xc0 ... 0xc8: /* Set COM output direction (Ignored).  */
-                break;
-            case 0xd3: /* Set display offset (Ignored).  */
-                s->cmd_state = SSD0303_CMD_SKIP1;
-                break;
-            case 0xd5: /* Set display clock (Ignored).  */
-                s->cmd_state = SSD0303_CMD_SKIP1;
-                break;
-            case 0xd8: /* Set color and power mode (Ignored).  */
-                s->cmd_state = SSD0303_CMD_SKIP1;
-                break;
-            case 0xd9: /* Set pre-charge period (Ignored).  */
-                s->cmd_state = SSD0303_CMD_SKIP1;
-                break;
-            case 0xda: /* Set COM pin configuration (Ignored).  */
-                s->cmd_state = SSD0303_CMD_SKIP1;
-                break;
-            case 0xdb: /* Set VCOM dselect level (Ignored).  */
-                s->cmd_state = SSD0303_CMD_SKIP1;
-                break;
-            case 0xe3: /* no-op.  */
-                break;
-            default:
-                BADF("Unknown command: 0x%x\n", data);
-            }
-            break;
-        case SSD0303_CMD_SKIP1:
-            DPRINTF("skip 0x%02x\n", data);
-            break;
-        }
-        break;
-    }
-    return 0;
-}
-
-static void ssd0303_event(I2CSlave *i2c, enum i2c_event event)
-{
-    ssd0303_state *s = (ssd0303_state *)i2c;
-    switch (event) {
-    case I2C_FINISH:
-        s->mode = SSD0303_IDLE;
-        break;
-    case I2C_START_RECV:
-    case I2C_START_SEND:
-    case I2C_NACK:
-        /* Nothing to do.  */
-        break;
-    }
-}
-
-static void ssd0303_update_display(void *opaque)
-{
-    ssd0303_state *s = (ssd0303_state *)opaque;
-    DisplaySurface *surface = qemu_console_surface(s->con);
-    uint8_t *dest;
-    uint8_t *src;
-    int x;
-    int y;
-    int line;
-    char *colors[2];
-    char colortab[MAGNIFY * 8];
-    int dest_width;
-    uint8_t mask;
-
-    if (!s->redraw)
-        return;
-
-    switch (surface_bits_per_pixel(surface)) {
-    case 0:
-        return;
-    case 15:
-        dest_width = 2;
-        break;
-    case 16:
-        dest_width = 2;
-        break;
-    case 24:
-        dest_width = 3;
-        break;
-    case 32:
-        dest_width = 4;
-        break;
-    default:
-        BADF("Bad color depth\n");
-        return;
-    }
-    dest_width *= MAGNIFY;
-    memset(colortab, 0xff, dest_width);
-    memset(colortab + dest_width, 0, dest_width);
-    if (s->flash) {
-        colors[0] = colortab;
-        colors[1] = colortab;
-    } else if (s->inverse) {
-        colors[0] = colortab;
-        colors[1] = colortab + dest_width;
-    } else {
-        colors[0] = colortab + dest_width;
-        colors[1] = colortab;
-    }
-    dest = surface_data(surface);
-    for (y = 0; y < 16; y++) {
-        line = (y + s->start_line) & 63;
-        src = s->framebuffer + 132 * (line >> 3) + 36;
-        mask = 1 << (line & 7);
-        for (x = 0; x < 96; x++) {
-            memcpy(dest, colors[(*src & mask) != 0], dest_width);
-            dest += dest_width;
-            src++;
-        }
-        for (x = 1; x < MAGNIFY; x++) {
-            memcpy(dest, dest - dest_width * 96, dest_width * 96);
-            dest += dest_width * 96;
-        }
-    }
-    s->redraw = 0;
-    dpy_gfx_update(s->con, 0, 0, 96 * MAGNIFY, 16 * MAGNIFY);
-}
-
-static void ssd0303_invalidate_display(void * opaque)
-{
-    ssd0303_state *s = (ssd0303_state *)opaque;
-    s->redraw = 1;
-}
-
-static const VMStateDescription vmstate_ssd0303 = {
-    .name = "ssd0303_oled",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField []) {
-        VMSTATE_INT32(row, ssd0303_state),
-        VMSTATE_INT32(col, ssd0303_state),
-        VMSTATE_INT32(start_line, ssd0303_state),
-        VMSTATE_INT32(mirror, ssd0303_state),
-        VMSTATE_INT32(flash, ssd0303_state),
-        VMSTATE_INT32(enabled, ssd0303_state),
-        VMSTATE_INT32(inverse, ssd0303_state),
-        VMSTATE_INT32(redraw, ssd0303_state),
-        VMSTATE_UINT32(mode, ssd0303_state),
-        VMSTATE_UINT32(cmd_state, ssd0303_state),
-        VMSTATE_BUFFER(framebuffer, ssd0303_state),
-        VMSTATE_I2C_SLAVE(i2c, ssd0303_state),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static int ssd0303_init(I2CSlave *i2c)
-{
-    ssd0303_state *s = FROM_I2C_SLAVE(ssd0303_state, i2c);
-
-    s->con = graphic_console_init(ssd0303_update_display,
-                                  ssd0303_invalidate_display,
-                                  NULL, NULL, s);
-    qemu_console_resize(s->con, 96 * MAGNIFY, 16 * MAGNIFY);
-    return 0;
-}
-
-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 const TypeInfo ssd0303_info = {
-    .name          = "ssd0303",
-    .parent        = TYPE_I2C_SLAVE,
-    .instance_size = sizeof(ssd0303_state),
-    .class_init    = ssd0303_class_init,
-};
-
-static void ssd0303_register_types(void)
-{
-    type_register_static(&ssd0303_info);
-}
-
-type_init(ssd0303_register_types)
diff --git a/hw/ssd0323.c b/hw/ssd0323.c
deleted file mode 100644 (file)
index 5cf2f70..0000000
+++ /dev/null
@@ -1,373 +0,0 @@
-/*
- * SSD0323 OLED controller with OSRAM Pictiva 128x64 display.
- *
- * Copyright (c) 2006-2007 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the GPL.
- */
-
-/* The controller can support a variety of different displays, but we only
-   implement one.  Most of the commends relating to brightness and geometry
-   setup are ignored. */
-#include "hw/ssi.h"
-#include "ui/console.h"
-
-//#define DEBUG_SSD0323 1
-
-#ifdef DEBUG_SSD0323
-#define DPRINTF(fmt, ...) \
-do { printf("ssd0323: " fmt , ## __VA_ARGS__); } while (0)
-#define BADF(fmt, ...) \
-do { \
-    fprintf(stderr, "ssd0323: error: " fmt , ## __VA_ARGS__); abort(); \
-} while (0)
-#else
-#define DPRINTF(fmt, ...) do {} while(0)
-#define BADF(fmt, ...) \
-do { fprintf(stderr, "ssd0323: error: " fmt , ## __VA_ARGS__);} while (0)
-#endif
-
-/* Scaling factor for pixels.  */
-#define MAGNIFY 4
-
-#define REMAP_SWAP_COLUMN 0x01
-#define REMAP_SWAP_NYBBLE 0x02
-#define REMAP_VERTICAL    0x04
-#define REMAP_SWAP_COM    0x10
-#define REMAP_SPLIT_COM   0x40
-
-enum ssd0323_mode
-{
-    SSD0323_CMD,
-    SSD0323_DATA
-};
-
-typedef struct {
-    SSISlave ssidev;
-    QemuConsole *con;
-
-    int cmd_len;
-    int cmd;
-    int cmd_data[8];
-    int row;
-    int row_start;
-    int row_end;
-    int col;
-    int col_start;
-    int col_end;
-    int redraw;
-    int remap;
-    enum ssd0323_mode mode;
-    uint8_t framebuffer[128 * 80 / 2];
-} ssd0323_state;
-
-static uint32_t ssd0323_transfer(SSISlave *dev, uint32_t data)
-{
-    ssd0323_state *s = FROM_SSI_SLAVE(ssd0323_state, dev);
-
-    switch (s->mode) {
-    case SSD0323_DATA:
-        DPRINTF("data 0x%02x\n", data);
-        s->framebuffer[s->col + s->row * 64] = data;
-        if (s->remap & REMAP_VERTICAL) {
-            s->row++;
-            if (s->row > s->row_end) {
-                s->row = s->row_start;
-                s->col++;
-            }
-            if (s->col > s->col_end) {
-                s->col = s->col_start;
-            }
-        } else {
-            s->col++;
-            if (s->col > s->col_end) {
-                s->row++;
-                s->col = s->col_start;
-            }
-            if (s->row > s->row_end) {
-                s->row = s->row_start;
-            }
-        }
-        s->redraw = 1;
-        break;
-    case SSD0323_CMD:
-        DPRINTF("cmd 0x%02x\n", data);
-        if (s->cmd_len == 0) {
-            s->cmd = data;
-        } else {
-            s->cmd_data[s->cmd_len - 1] = data;
-        }
-        s->cmd_len++;
-        switch (s->cmd) {
-#define DATA(x) if (s->cmd_len <= (x)) return 0
-        case 0x15: /* Set column.  */
-            DATA(2);
-            s->col = s->col_start = s->cmd_data[0] % 64;
-            s->col_end = s->cmd_data[1] % 64;
-            break;
-        case 0x75: /* Set row.  */
-            DATA(2);
-            s->row = s->row_start = s->cmd_data[0] % 80;
-            s->row_end = s->cmd_data[1] % 80;
-            break;
-        case 0x81: /* Set contrast */
-            DATA(1);
-            break;
-        case 0x84: case 0x85: case 0x86: /* Max current.  */
-            DATA(0);
-            break;
-        case 0xa0: /* Set remapping.  */
-            /* FIXME: Implement this.  */
-            DATA(1);
-            s->remap = s->cmd_data[0];
-            break;
-        case 0xa1: /* Set display start line.  */
-        case 0xa2: /* Set display offset.  */
-            /* FIXME: Implement these.  */
-            DATA(1);
-            break;
-        case 0xa4: /* Normal mode.  */
-        case 0xa5: /* All on.  */
-        case 0xa6: /* All off.  */
-        case 0xa7: /* Inverse.  */
-            /* FIXME: Implement these.  */
-            DATA(0);
-            break;
-        case 0xa8: /* Set multiplex ratio.  */
-        case 0xad: /* Set DC-DC converter.  */
-            DATA(1);
-            /* Ignored.  Don't care.  */
-            break;
-        case 0xae: /* Display off.  */
-        case 0xaf: /* Display on.  */
-            DATA(0);
-            /* TODO: Implement power control.  */
-            break;
-        case 0xb1: /* Set phase length.  */
-        case 0xb2: /* Set row period.  */
-        case 0xb3: /* Set clock rate.  */
-        case 0xbc: /* Set precharge.  */
-        case 0xbe: /* Set VCOMH.  */
-        case 0xbf: /* Set segment low.  */
-            DATA(1);
-            /* Ignored.  Don't care.  */
-            break;
-        case 0xb8: /* Set grey scale table.  */
-            /* FIXME: Implement this.  */
-            DATA(8);
-            break;
-        case 0xe3: /* NOP.  */
-            DATA(0);
-            break;
-        case 0xff: /* Nasty hack because we don't handle chip selects
-                      properly.  */
-            break;
-        default:
-            BADF("Unknown command: 0x%x\n", data);
-        }
-        s->cmd_len = 0;
-        return 0;
-    }
-    return 0;
-}
-
-static void ssd0323_update_display(void *opaque)
-{
-    ssd0323_state *s = (ssd0323_state *)opaque;
-    DisplaySurface *surface = qemu_console_surface(s->con);
-    uint8_t *dest;
-    uint8_t *src;
-    int x;
-    int y;
-    int i;
-    int line;
-    char *colors[16];
-    char colortab[MAGNIFY * 64];
-    char *p;
-    int dest_width;
-
-    if (!s->redraw)
-        return;
-
-    switch (surface_bits_per_pixel(surface)) {
-    case 0:
-        return;
-    case 15:
-        dest_width = 2;
-        break;
-    case 16:
-        dest_width = 2;
-        break;
-    case 24:
-        dest_width = 3;
-        break;
-    case 32:
-        dest_width = 4;
-        break;
-    default:
-        BADF("Bad color depth\n");
-        return;
-    }
-    p = colortab;
-    for (i = 0; i < 16; i++) {
-        int n;
-        colors[i] = p;
-        switch (surface_bits_per_pixel(surface)) {
-        case 15:
-            n = i * 2 + (i >> 3);
-            p[0] = n | (n << 5);
-            p[1] = (n << 2) | (n >> 3);
-            break;
-        case 16:
-            n = i * 2 + (i >> 3);
-            p[0] = n | (n << 6) | ((n << 1) & 0x20);
-            p[1] = (n << 3) | (n >> 2);
-            break;
-        case 24:
-        case 32:
-            n = (i << 4) | i;
-            p[0] = p[1] = p[2] = n;
-            break;
-        default:
-            BADF("Bad color depth\n");
-            return;
-        }
-        p += dest_width;
-    }
-    /* TODO: Implement row/column remapping.  */
-    dest = surface_data(surface);
-    for (y = 0; y < 64; y++) {
-        line = y;
-        src = s->framebuffer + 64 * line;
-        for (x = 0; x < 64; x++) {
-            int val;
-            val = *src >> 4;
-            for (i = 0; i < MAGNIFY; i++) {
-                memcpy(dest, colors[val], dest_width);
-                dest += dest_width;
-            }
-            val = *src & 0xf;
-            for (i = 0; i < MAGNIFY; i++) {
-                memcpy(dest, colors[val], dest_width);
-                dest += dest_width;
-            }
-            src++;
-        }
-        for (i = 1; i < MAGNIFY; i++) {
-            memcpy(dest, dest - dest_width * MAGNIFY * 128,
-                   dest_width * 128 * MAGNIFY);
-            dest += dest_width * 128 * MAGNIFY;
-        }
-    }
-    s->redraw = 0;
-    dpy_gfx_update(s->con, 0, 0, 128 * MAGNIFY, 64 * MAGNIFY);
-}
-
-static void ssd0323_invalidate_display(void * opaque)
-{
-    ssd0323_state *s = (ssd0323_state *)opaque;
-    s->redraw = 1;
-}
-
-/* Command/data input.  */
-static void ssd0323_cd(void *opaque, int n, int level)
-{
-    ssd0323_state *s = (ssd0323_state *)opaque;
-    DPRINTF("%s mode\n", level ? "Data" : "Command");
-    s->mode = level ? SSD0323_DATA : SSD0323_CMD;
-}
-
-static void ssd0323_save(QEMUFile *f, void *opaque)
-{
-    SSISlave *ss = SSI_SLAVE(opaque);
-    ssd0323_state *s = (ssd0323_state *)opaque;
-    int i;
-
-    qemu_put_be32(f, s->cmd_len);
-    qemu_put_be32(f, s->cmd);
-    for (i = 0; i < 8; i++)
-        qemu_put_be32(f, s->cmd_data[i]);
-    qemu_put_be32(f, s->row);
-    qemu_put_be32(f, s->row_start);
-    qemu_put_be32(f, s->row_end);
-    qemu_put_be32(f, s->col);
-    qemu_put_be32(f, s->col_start);
-    qemu_put_be32(f, s->col_end);
-    qemu_put_be32(f, s->redraw);
-    qemu_put_be32(f, s->remap);
-    qemu_put_be32(f, s->mode);
-    qemu_put_buffer(f, s->framebuffer, sizeof(s->framebuffer));
-
-    qemu_put_be32(f, ss->cs);
-}
-
-static int ssd0323_load(QEMUFile *f, void *opaque, int version_id)
-{
-    SSISlave *ss = SSI_SLAVE(opaque);
-    ssd0323_state *s = (ssd0323_state *)opaque;
-    int i;
-
-    if (version_id != 1)
-        return -EINVAL;
-
-    s->cmd_len = qemu_get_be32(f);
-    s->cmd = qemu_get_be32(f);
-    for (i = 0; i < 8; i++)
-        s->cmd_data[i] = qemu_get_be32(f);
-    s->row = qemu_get_be32(f);
-    s->row_start = qemu_get_be32(f);
-    s->row_end = qemu_get_be32(f);
-    s->col = qemu_get_be32(f);
-    s->col_start = qemu_get_be32(f);
-    s->col_end = qemu_get_be32(f);
-    s->redraw = qemu_get_be32(f);
-    s->remap = qemu_get_be32(f);
-    s->mode = qemu_get_be32(f);
-    qemu_get_buffer(f, s->framebuffer, sizeof(s->framebuffer));
-
-    ss->cs = qemu_get_be32(f);
-
-    return 0;
-}
-
-static int ssd0323_init(SSISlave *dev)
-{
-    ssd0323_state *s = FROM_SSI_SLAVE(ssd0323_state, dev);
-
-    s->col_end = 63;
-    s->row_end = 79;
-    s->con = graphic_console_init(ssd0323_update_display,
-                                  ssd0323_invalidate_display,
-                                  NULL, NULL, s);
-    qemu_console_resize(s->con, 128 * MAGNIFY, 64 * MAGNIFY);
-
-    qdev_init_gpio_in(&dev->qdev, ssd0323_cd, 1);
-
-    register_savevm(&dev->qdev, "ssd0323_oled", -1, 1,
-                    ssd0323_save, ssd0323_load, s);
-    return 0;
-}
-
-static void ssd0323_class_init(ObjectClass *klass, void *data)
-{
-    SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
-
-    k->init = ssd0323_init;
-    k->transfer = ssd0323_transfer;
-    k->cs_polarity = SSI_CS_HIGH;
-}
-
-static const TypeInfo ssd0323_info = {
-    .name          = "ssd0323",
-    .parent        = TYPE_SSI_SLAVE,
-    .instance_size = sizeof(ssd0323_state),
-    .class_init    = ssd0323_class_init,
-};
-
-static void ssd03232_register_types(void)
-{
-    type_register_static(&ssd0323_info);
-}
-
-type_init(ssd03232_register_types)
diff --git a/hw/ssi-sd.c b/hw/ssi-sd.c
deleted file mode 100644 (file)
index 4d3c4f6..0000000
+++ /dev/null
@@ -1,274 +0,0 @@
-/*
- * SSI to SD card adapter.
- *
- * Copyright (c) 2007-2009 CodeSourcery.
- * 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 "sysemu/blockdev.h"
-#include "hw/ssi.h"
-#include "hw/sd.h"
-
-//#define DEBUG_SSI_SD 1
-
-#ifdef DEBUG_SSI_SD
-#define DPRINTF(fmt, ...) \
-do { printf("ssi_sd: " fmt , ## __VA_ARGS__); } while (0)
-#define BADF(fmt, ...) \
-do { fprintf(stderr, "ssi_sd: error: " fmt , ## __VA_ARGS__); exit(1);} while (0)
-#else
-#define DPRINTF(fmt, ...) do {} while(0)
-#define BADF(fmt, ...) \
-do { fprintf(stderr, "ssi_sd: error: " fmt , ## __VA_ARGS__);} while (0)
-#endif
-
-typedef enum {
-    SSI_SD_CMD,
-    SSI_SD_CMDARG,
-    SSI_SD_RESPONSE,
-    SSI_SD_DATA_START,
-    SSI_SD_DATA_READ,
-} ssi_sd_mode;
-
-typedef struct {
-    SSISlave ssidev;
-    ssi_sd_mode mode;
-    int cmd;
-    uint8_t cmdarg[4];
-    uint8_t response[5];
-    int arglen;
-    int response_pos;
-    int stopping;
-    SDState *sd;
-} ssi_sd_state;
-
-/* State word bits.  */
-#define SSI_SDR_LOCKED          0x0001
-#define SSI_SDR_WP_ERASE        0x0002
-#define SSI_SDR_ERROR           0x0004
-#define SSI_SDR_CC_ERROR        0x0008
-#define SSI_SDR_ECC_FAILED      0x0010
-#define SSI_SDR_WP_VIOLATION    0x0020
-#define SSI_SDR_ERASE_PARAM     0x0040
-#define SSI_SDR_OUT_OF_RANGE    0x0080
-#define SSI_SDR_IDLE            0x0100
-#define SSI_SDR_ERASE_RESET     0x0200
-#define SSI_SDR_ILLEGAL_COMMAND 0x0400
-#define SSI_SDR_COM_CRC_ERROR   0x0800
-#define SSI_SDR_ERASE_SEQ_ERROR 0x1000
-#define SSI_SDR_ADDRESS_ERROR   0x2000
-#define SSI_SDR_PARAMETER_ERROR 0x4000
-
-static uint32_t ssi_sd_transfer(SSISlave *dev, uint32_t val)
-{
-    ssi_sd_state *s = FROM_SSI_SLAVE(ssi_sd_state, dev);
-
-    /* Special case: allow CMD12 (STOP TRANSMISSION) while reading data.  */
-    if (s->mode == SSI_SD_DATA_READ && val == 0x4d) {
-        s->mode = SSI_SD_CMD;
-        /* There must be at least one byte delay before the card responds.  */
-        s->stopping = 1;
-    }
-
-    switch (s->mode) {
-    case SSI_SD_CMD:
-        if (val == 0xff) {
-            DPRINTF("NULL command\n");
-            return 0xff;
-        }
-        s->cmd = val & 0x3f;
-        s->mode = SSI_SD_CMDARG;
-        s->arglen = 0;
-        return 0xff;
-    case SSI_SD_CMDARG:
-        if (s->arglen == 4) {
-            SDRequest request;
-            uint8_t longresp[16];
-            /* FIXME: Check CRC.  */
-            request.cmd = s->cmd;
-            request.arg = (s->cmdarg[0] << 24) | (s->cmdarg[1] << 16)
-                           | (s->cmdarg[2] << 8) | s->cmdarg[3];
-            DPRINTF("CMD%d arg 0x%08x\n", s->cmd, request.arg);
-            s->arglen = sd_do_command(s->sd, &request, longresp);
-            if (s->arglen <= 0) {
-                s->arglen = 1;
-                s->response[0] = 4;
-                DPRINTF("SD command failed\n");
-            } else if (s->cmd == 58) {
-                /* CMD58 returns R3 response (OCR)  */
-                DPRINTF("Returned OCR\n");
-                s->arglen = 5;
-                s->response[0] = 1;
-                memcpy(&s->response[1], longresp, 4);
-            } else if (s->arglen != 4) {
-                BADF("Unexpected response to cmd %d\n", s->cmd);
-                /* Illegal command is about as near as we can get.  */
-                s->arglen = 1;
-                s->response[0] = 4;
-            } else {
-                /* All other commands return status.  */
-                uint32_t cardstatus;
-                uint16_t status;
-                /* CMD13 returns a 2-byte statuse work. Other commands
-                   only return the first byte.  */
-                s->arglen = (s->cmd == 13) ? 2 : 1;
-                cardstatus = (longresp[0] << 24) | (longresp[1] << 16)
-                             | (longresp[2] << 8) | longresp[3];
-                status = 0;
-                if (((cardstatus >> 9) & 0xf) < 4)
-                    status |= SSI_SDR_IDLE;
-                if (cardstatus & ERASE_RESET)
-                    status |= SSI_SDR_ERASE_RESET;
-                if (cardstatus & ILLEGAL_COMMAND)
-                    status |= SSI_SDR_ILLEGAL_COMMAND;
-                if (cardstatus & COM_CRC_ERROR)
-                    status |= SSI_SDR_COM_CRC_ERROR;
-                if (cardstatus & ERASE_SEQ_ERROR)
-                    status |= SSI_SDR_ERASE_SEQ_ERROR;
-                if (cardstatus & ADDRESS_ERROR)
-                    status |= SSI_SDR_ADDRESS_ERROR;
-                if (cardstatus & CARD_IS_LOCKED)
-                    status |= SSI_SDR_LOCKED;
-                if (cardstatus & (LOCK_UNLOCK_FAILED | WP_ERASE_SKIP))
-                    status |= SSI_SDR_WP_ERASE;
-                if (cardstatus & SD_ERROR)
-                    status |= SSI_SDR_ERROR;
-                if (cardstatus & CC_ERROR)
-                    status |= SSI_SDR_CC_ERROR;
-                if (cardstatus & CARD_ECC_FAILED)
-                    status |= SSI_SDR_ECC_FAILED;
-                if (cardstatus & WP_VIOLATION)
-                    status |= SSI_SDR_WP_VIOLATION;
-                if (cardstatus & ERASE_PARAM)
-                    status |= SSI_SDR_ERASE_PARAM;
-                if (cardstatus & (OUT_OF_RANGE | CID_CSD_OVERWRITE))
-                    status |= SSI_SDR_OUT_OF_RANGE;
-                /* ??? Don't know what Parameter Error really means, so
-                   assume it's set if the second byte is nonzero.  */
-                if (status & 0xff)
-                    status |= SSI_SDR_PARAMETER_ERROR;
-                s->response[0] = status >> 8;
-                s->response[1] = status;
-                DPRINTF("Card status 0x%02x\n", status);
-            }
-            s->mode = SSI_SD_RESPONSE;
-            s->response_pos = 0;
-        } else {
-            s->cmdarg[s->arglen++] = val;
-        }
-        return 0xff;
-    case SSI_SD_RESPONSE:
-        if (s->stopping) {
-            s->stopping = 0;
-            return 0xff;
-        }
-        if (s->response_pos < s->arglen) {
-            DPRINTF("Response 0x%02x\n", s->response[s->response_pos]);
-            return s->response[s->response_pos++];
-        }
-        if (sd_data_ready(s->sd)) {
-            DPRINTF("Data read\n");
-            s->mode = SSI_SD_DATA_START;
-        } else {
-            DPRINTF("End of command\n");
-            s->mode = SSI_SD_CMD;
-        }
-        return 0xff;
-    case SSI_SD_DATA_START:
-        DPRINTF("Start read block\n");
-        s->mode = SSI_SD_DATA_READ;
-        return 0xfe;
-    case SSI_SD_DATA_READ:
-        val = sd_read_data(s->sd);
-        if (!sd_data_ready(s->sd)) {
-            DPRINTF("Data read end\n");
-            s->mode = SSI_SD_CMD;
-        }
-        return val;
-    }
-    /* Should never happen.  */
-    return 0xff;
-}
-
-static void ssi_sd_save(QEMUFile *f, void *opaque)
-{
-    SSISlave *ss = SSI_SLAVE(opaque);
-    ssi_sd_state *s = (ssi_sd_state *)opaque;
-    int i;
-
-    qemu_put_be32(f, s->mode);
-    qemu_put_be32(f, s->cmd);
-    for (i = 0; i < 4; i++)
-        qemu_put_be32(f, s->cmdarg[i]);
-    for (i = 0; i < 5; i++)
-        qemu_put_be32(f, s->response[i]);
-    qemu_put_be32(f, s->arglen);
-    qemu_put_be32(f, s->response_pos);
-    qemu_put_be32(f, s->stopping);
-
-    qemu_put_be32(f, ss->cs);
-}
-
-static int ssi_sd_load(QEMUFile *f, void *opaque, int version_id)
-{
-    SSISlave *ss = SSI_SLAVE(opaque);
-    ssi_sd_state *s = (ssi_sd_state *)opaque;
-    int i;
-
-    if (version_id != 1)
-        return -EINVAL;
-
-    s->mode = qemu_get_be32(f);
-    s->cmd = qemu_get_be32(f);
-    for (i = 0; i < 4; i++)
-        s->cmdarg[i] = qemu_get_be32(f);
-    for (i = 0; i < 5; i++)
-        s->response[i] = qemu_get_be32(f);
-    s->arglen = qemu_get_be32(f);
-    s->response_pos = qemu_get_be32(f);
-    s->stopping = qemu_get_be32(f);
-
-    ss->cs = qemu_get_be32(f);
-
-    return 0;
-}
-
-static int ssi_sd_init(SSISlave *dev)
-{
-    ssi_sd_state *s = FROM_SSI_SLAVE(ssi_sd_state, dev);
-    DriveInfo *dinfo;
-
-    s->mode = SSI_SD_CMD;
-    dinfo = drive_get_next(IF_SD);
-    s->sd = sd_init(dinfo ? dinfo->bdrv : NULL, 1);
-    register_savevm(&dev->qdev, "ssi_sd", -1, 1, ssi_sd_save, ssi_sd_load, s);
-    return 0;
-}
-
-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;
-    k->cs_polarity = SSI_CS_LOW;
-}
-
-static const 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_types(void)
-{
-    type_register_static(&ssi_sd_info);
-}
-
-type_init(ssi_sd_register_types)
diff --git a/hw/ssi.c b/hw/ssi.c
deleted file mode 100644 (file)
index 1264d9d..0000000
--- a/hw/ssi.c
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * QEMU Synchronous Serial Interface support
- *
- * Copyright (c) 2009 CodeSourcery.
- * Copyright (c) 2012 Peter A.G. Crosthwaite (peter.crosthwaite@petalogix.com)
- * Copyright (c) 2012 PetaLogix Pty Ltd.
- * 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 "hw/ssi.h"
-
-struct SSIBus {
-    BusState qbus;
-};
-
-#define TYPE_SSI_BUS "SSI"
-#define SSI_BUS(obj) OBJECT_CHECK(SSIBus, (obj), TYPE_SSI_BUS)
-
-static const TypeInfo ssi_bus_info = {
-    .name = TYPE_SSI_BUS,
-    .parent = TYPE_BUS,
-    .instance_size = sizeof(SSIBus),
-};
-
-static void ssi_cs_default(void *opaque, int n, int level)
-{
-    SSISlave *s = SSI_SLAVE(opaque);
-    bool cs = !!level;
-    assert(n == 0);
-    if (s->cs != cs) {
-        SSISlaveClass *ssc = SSI_SLAVE_GET_CLASS(s);
-        if (ssc->set_cs) {
-            ssc->set_cs(s, cs);
-        }
-    }
-    s->cs = cs;
-}
-
-static uint32_t ssi_transfer_raw_default(SSISlave *dev, uint32_t val)
-{
-    SSISlaveClass *ssc = SSI_SLAVE_GET_CLASS(dev);
-
-    if ((dev->cs && ssc->cs_polarity == SSI_CS_HIGH) ||
-            (!dev->cs && ssc->cs_polarity == SSI_CS_LOW) ||
-            ssc->cs_polarity == SSI_CS_NONE) {
-        return ssc->transfer(dev, val);
-    }
-    return 0;
-}
-
-static int ssi_slave_init(DeviceState *dev)
-{
-    SSISlave *s = SSI_SLAVE(dev);
-    SSISlaveClass *ssc = SSI_SLAVE_GET_CLASS(s);
-
-    if (ssc->transfer_raw == ssi_transfer_raw_default &&
-            ssc->cs_polarity != SSI_CS_NONE) {
-        qdev_init_gpio_in(&s->qdev, ssi_cs_default, 1);
-    }
-
-    return ssc->init(s);
-}
-
-static void ssi_slave_class_init(ObjectClass *klass, void *data)
-{
-    SSISlaveClass *ssc = SSI_SLAVE_CLASS(klass);
-    DeviceClass *dc = DEVICE_CLASS(klass);
-
-    dc->init = ssi_slave_init;
-    dc->bus_type = TYPE_SSI_BUS;
-    if (!ssc->transfer_raw) {
-        ssc->transfer_raw = ssi_transfer_raw_default;
-    }
-}
-
-static const 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_no_init(SSIBus *bus, const char *name)
-{
-    return qdev_create(&bus->qbus, name);
-}
-
-DeviceState *ssi_create_slave(SSIBus *bus, const char *name)
-{
-    DeviceState *dev = ssi_create_slave_no_init(bus, name);
-
-    qdev_init_nofail(dev);
-    return dev;
-}
-
-SSIBus *ssi_create_bus(DeviceState *parent, const char *name)
-{
-    BusState *bus;
-    bus = qbus_create(TYPE_SSI_BUS, parent, name);
-    return FROM_QBUS(SSIBus, bus);
-}
-
-uint32_t ssi_transfer(SSIBus *bus, uint32_t val)
-{
-    BusChild *kid;
-    SSISlaveClass *ssc;
-    uint32_t r = 0;
-
-    QTAILQ_FOREACH(kid, &bus->qbus.children, sibling) {
-        SSISlave *slave = SSI_SLAVE(kid->child);
-        ssc = SSI_SLAVE_GET_CLASS(slave);
-        r |= ssc->transfer_raw(slave, val);
-    }
-
-    return r;
-}
-
-const VMStateDescription vmstate_ssi_slave = {
-    .name = "SSISlave",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField[]) {
-        VMSTATE_BOOL(cs, SSISlave),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void ssi_slave_register_types(void)
-{
-    type_register_static(&ssi_bus_info);
-    type_register_static(&ssi_slave_info);
-}
-
-type_init(ssi_slave_register_types)
-
-typedef struct SSIAutoConnectArg {
-    qemu_irq **cs_linep;
-    SSIBus *bus;
-} SSIAutoConnectArg;
-
-static int ssi_auto_connect_slave(Object *child, void *opaque)
-{
-    SSIAutoConnectArg *arg = opaque;
-    SSISlave *dev = (SSISlave *)object_dynamic_cast(child, TYPE_SSI_SLAVE);
-    qemu_irq cs_line;
-
-    if (!dev) {
-        return 0;
-    }
-
-    cs_line = qdev_get_gpio_in(DEVICE(dev), 0);
-    qdev_set_parent_bus(DEVICE(dev), &arg->bus->qbus);
-    **arg->cs_linep = cs_line;
-    (*arg->cs_linep)++;
-    return 0;
-}
-
-void ssi_auto_connect_slaves(DeviceState *parent, qemu_irq *cs_line,
-                             SSIBus *bus)
-{
-    SSIAutoConnectArg arg = {
-        .cs_linep = &cs_line,
-        .bus = bus
-    };
-
-    object_child_foreach(OBJECT(parent), ssi_auto_connect_slave, &arg);
-}
diff --git a/hw/ssi.h b/hw/ssi.h
deleted file mode 100644 (file)
index fdae317..0000000
--- a/hw/ssi.h
+++ /dev/null
@@ -1,93 +0,0 @@
-/* QEMU Synchronous Serial Interface support.  */
-
-/* In principle SSI is a point-point interface.  As such the qemu
-   implementation has a single slave device on a "bus".
-   However it is fairly common for boards to have multiple slaves
-   connected to a single master, and select devices with an external
-   chip select.  This is implemented in qemu by having an explicit mux device.
-   It is assumed that master and slave are both using the same transfer width.
-   */
-
-#ifndef QEMU_SSI_H
-#define QEMU_SSI_H
-
-#include "hw/qdev.h"
-
-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)
-
-typedef enum {
-    SSI_CS_NONE = 0,
-    SSI_CS_LOW,
-    SSI_CS_HIGH,
-} SSICSMode;
-
-/* Slave devices.  */
-typedef struct SSISlaveClass {
-    DeviceClass parent_class;
-
-    int (*init)(SSISlave *dev);
-
-    /* if you have standard or no CS behaviour, just override transfer.
-     * This is called when the device cs is active (true by default).
-     */
-    uint32_t (*transfer)(SSISlave *dev, uint32_t val);
-    /* called when the CS line changes. Optional, devices only need to implement
-     * this if they have side effects associated with the cs line (beyond
-     * tristating the txrx lines).
-     */
-    int (*set_cs)(SSISlave *dev, bool select);
-    /* define whether or not CS exists and is active low/high */
-    SSICSMode cs_polarity;
-
-    /* if you have non-standard CS behaviour override this to take control
-     * of the CS behaviour at the device level. transfer, set_cs, and
-     * cs_polarity are unused if this is overwritten. Transfer_raw will
-     * always be called for the device for every txrx access to the parent bus
-     */
-    uint32_t (*transfer_raw)(SSISlave *dev, uint32_t val);
-} SSISlaveClass;
-
-struct SSISlave {
-    DeviceState qdev;
-
-    /* Chip select state */
-    bool cs;
-};
-
-#define SSI_SLAVE_FROM_QDEV(dev) DO_UPCAST(SSISlave, qdev, dev)
-#define FROM_SSI_SLAVE(type, dev) DO_UPCAST(type, ssidev, dev)
-
-extern const VMStateDescription vmstate_ssi_slave;
-
-#define VMSTATE_SSI_SLAVE(_field, _state) {                          \
-    .name       = (stringify(_field)),                               \
-    .size       = sizeof(SSISlave),                                  \
-    .vmsd       = &vmstate_ssi_slave,                                \
-    .flags      = VMS_STRUCT,                                        \
-    .offset     = vmstate_offset_value(_state, _field, SSISlave),    \
-}
-
-DeviceState *ssi_create_slave(SSIBus *bus, const char *name);
-DeviceState *ssi_create_slave_no_init(SSIBus *bus, const char *name);
-
-/* Master interface.  */
-SSIBus *ssi_create_bus(DeviceState *parent, const char *name);
-
-uint32_t ssi_transfer(SSIBus *bus, uint32_t val);
-
-/* Automatically connect all children nodes a spi controller as slaves */
-void ssi_auto_connect_slaves(DeviceState *parent, qemu_irq *cs_lines,
-                             SSIBus *bus);
-
-/* max111x.c */
-void max111x_set_input(DeviceState *dev, int line, uint8_t value);
-
-#endif
diff --git a/hw/ssi/Makefile.objs b/hw/ssi/Makefile.objs
new file mode 100644 (file)
index 0000000..9555825
--- /dev/null
@@ -0,0 +1,6 @@
+common-obj-$(CONFIG_PL022) += pl022.o
+common-obj-$(CONFIG_SSI) += ssi.o
+common-obj-$(CONFIG_XILINX_SPI) += xilinx_spi.o
+common-obj-$(CONFIG_XILINX_SPIPS) += xilinx_spips.o
+
+obj-$(CONFIG_OMAP) += omap_spi.o
diff --git a/hw/ssi/omap_spi.c b/hw/ssi/omap_spi.c
new file mode 100644 (file)
index 0000000..11403c4
--- /dev/null
@@ -0,0 +1,373 @@
+/*
+ * TI OMAP processor's Multichannel SPI emulation.
+ *
+ * Copyright (C) 2007-2009 Nokia Corporation
+ *
+ * Original code for OMAP2 by Andrzej Zaborowski <andrew@openedhand.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 or
+ * (at your option) any later version 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
+ * 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, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#include "hw/hw.h"
+#include "hw/arm/omap.h"
+
+/* Multichannel SPI */
+struct omap_mcspi_s {
+    MemoryRegion iomem;
+    qemu_irq irq;
+    int chnum;
+
+    uint32_t sysconfig;
+    uint32_t systest;
+    uint32_t irqst;
+    uint32_t irqen;
+    uint32_t wken;
+    uint32_t control;
+
+    struct omap_mcspi_ch_s {
+        qemu_irq txdrq;
+        qemu_irq rxdrq;
+        uint32_t (*txrx)(void *opaque, uint32_t, int);
+        void *opaque;
+
+        uint32_t tx;
+        uint32_t rx;
+
+        uint32_t config;
+        uint32_t status;
+        uint32_t control;
+    } ch[4];
+};
+
+static inline void omap_mcspi_interrupt_update(struct omap_mcspi_s *s)
+{
+    qemu_set_irq(s->irq, s->irqst & s->irqen);
+}
+
+static inline void omap_mcspi_dmarequest_update(struct omap_mcspi_ch_s *ch)
+{
+    qemu_set_irq(ch->txdrq,
+                    (ch->control & 1) &&               /* EN */
+                    (ch->config & (1 << 14)) &&                /* DMAW */
+                    (ch->status & (1 << 1)) &&         /* TXS */
+                    ((ch->config >> 12) & 3) != 1);    /* TRM */
+    qemu_set_irq(ch->rxdrq,
+                    (ch->control & 1) &&               /* EN */
+                    (ch->config & (1 << 15)) &&                /* DMAW */
+                    (ch->status & (1 << 0)) &&         /* RXS */
+                    ((ch->config >> 12) & 3) != 2);    /* TRM */
+}
+
+static void omap_mcspi_transfer_run(struct omap_mcspi_s *s, int chnum)
+{
+    struct omap_mcspi_ch_s *ch = s->ch + chnum;
+
+    if (!(ch->control & 1))                            /* EN */
+        return;
+    if ((ch->status & (1 << 0)) &&                     /* RXS */
+                    ((ch->config >> 12) & 3) != 2 &&   /* TRM */
+                    !(ch->config & (1 << 19)))         /* TURBO */
+        goto intr_update;
+    if ((ch->status & (1 << 1)) &&                     /* TXS */
+                    ((ch->config >> 12) & 3) != 1)     /* TRM */
+        goto intr_update;
+
+    if (!(s->control & 1) ||                           /* SINGLE */
+                    (ch->config & (1 << 20))) {                /* FORCE */
+        if (ch->txrx)
+            ch->rx = ch->txrx(ch->opaque, ch->tx,      /* WL */
+                            1 + (0x1f & (ch->config >> 7)));
+    }
+
+    ch->tx = 0;
+    ch->status |= 1 << 2;                              /* EOT */
+    ch->status |= 1 << 1;                              /* TXS */
+    if (((ch->config >> 12) & 3) != 2)                 /* TRM */
+        ch->status |= 1 << 0;                          /* RXS */
+
+intr_update:
+    if ((ch->status & (1 << 0)) &&                     /* RXS */
+                    ((ch->config >> 12) & 3) != 2 &&   /* TRM */
+                    !(ch->config & (1 << 19)))         /* TURBO */
+        s->irqst |= 1 << (2 + 4 * chnum);              /* RX_FULL */
+    if ((ch->status & (1 << 1)) &&                     /* TXS */
+                    ((ch->config >> 12) & 3) != 1)     /* TRM */
+        s->irqst |= 1 << (0 + 4 * chnum);              /* TX_EMPTY */
+    omap_mcspi_interrupt_update(s);
+    omap_mcspi_dmarequest_update(ch);
+}
+
+void omap_mcspi_reset(struct omap_mcspi_s *s)
+{
+    int ch;
+
+    s->sysconfig = 0;
+    s->systest = 0;
+    s->irqst = 0;
+    s->irqen = 0;
+    s->wken = 0;
+    s->control = 4;
+
+    for (ch = 0; ch < 4; ch ++) {
+        s->ch[ch].config = 0x060000;
+        s->ch[ch].status = 2;                          /* TXS */
+        s->ch[ch].control = 0;
+
+        omap_mcspi_dmarequest_update(s->ch + ch);
+    }
+
+    omap_mcspi_interrupt_update(s);
+}
+
+static uint64_t omap_mcspi_read(void *opaque, hwaddr addr,
+                                unsigned size)
+{
+    struct omap_mcspi_s *s = (struct omap_mcspi_s *) opaque;
+    int ch = 0;
+    uint32_t ret;
+
+    if (size != 4) {
+        return omap_badwidth_read32(opaque, addr);
+    }
+
+    switch (addr) {
+    case 0x00: /* MCSPI_REVISION */
+        return 0x91;
+
+    case 0x10: /* MCSPI_SYSCONFIG */
+        return s->sysconfig;
+
+    case 0x14: /* MCSPI_SYSSTATUS */
+        return 1;                                      /* RESETDONE */
+
+    case 0x18: /* MCSPI_IRQSTATUS */
+        return s->irqst;
+
+    case 0x1c: /* MCSPI_IRQENABLE */
+        return s->irqen;
+
+    case 0x20: /* MCSPI_WAKEUPENABLE */
+        return s->wken;
+
+    case 0x24: /* MCSPI_SYST */
+        return s->systest;
+
+    case 0x28: /* MCSPI_MODULCTRL */
+        return s->control;
+
+    case 0x68: ch ++;
+        /* fall through */
+    case 0x54: ch ++;
+        /* fall through */
+    case 0x40: ch ++;
+        /* fall through */
+    case 0x2c: /* MCSPI_CHCONF */
+        return s->ch[ch].config;
+
+    case 0x6c: ch ++;
+        /* fall through */
+    case 0x58: ch ++;
+        /* fall through */
+    case 0x44: ch ++;
+        /* fall through */
+    case 0x30: /* MCSPI_CHSTAT */
+        return s->ch[ch].status;
+
+    case 0x70: ch ++;
+        /* fall through */
+    case 0x5c: ch ++;
+        /* fall through */
+    case 0x48: ch ++;
+        /* fall through */
+    case 0x34: /* MCSPI_CHCTRL */
+        return s->ch[ch].control;
+
+    case 0x74: ch ++;
+        /* fall through */
+    case 0x60: ch ++;
+        /* fall through */
+    case 0x4c: ch ++;
+        /* fall through */
+    case 0x38: /* MCSPI_TX */
+        return s->ch[ch].tx;
+
+    case 0x78: ch ++;
+        /* fall through */
+    case 0x64: ch ++;
+        /* fall through */
+    case 0x50: ch ++;
+        /* fall through */
+    case 0x3c: /* MCSPI_RX */
+        s->ch[ch].status &= ~(1 << 0);                 /* RXS */
+        ret = s->ch[ch].rx;
+        omap_mcspi_transfer_run(s, ch);
+        return ret;
+    }
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_mcspi_write(void *opaque, hwaddr addr,
+                             uint64_t value, unsigned size)
+{
+    struct omap_mcspi_s *s = (struct omap_mcspi_s *) opaque;
+    int ch = 0;
+
+    if (size != 4) {
+        return omap_badwidth_write32(opaque, addr, value);
+    }
+
+    switch (addr) {
+    case 0x00: /* MCSPI_REVISION */
+    case 0x14: /* MCSPI_SYSSTATUS */
+    case 0x30: /* MCSPI_CHSTAT0 */
+    case 0x3c: /* MCSPI_RX0 */
+    case 0x44: /* MCSPI_CHSTAT1 */
+    case 0x50: /* MCSPI_RX1 */
+    case 0x58: /* MCSPI_CHSTAT2 */
+    case 0x64: /* MCSPI_RX2 */
+    case 0x6c: /* MCSPI_CHSTAT3 */
+    case 0x78: /* MCSPI_RX3 */
+        OMAP_RO_REG(addr);
+        return;
+
+    case 0x10: /* MCSPI_SYSCONFIG */
+        if (value & (1 << 1))                          /* SOFTRESET */
+            omap_mcspi_reset(s);
+        s->sysconfig = value & 0x31d;
+        break;
+
+    case 0x18: /* MCSPI_IRQSTATUS */
+        if (!((s->control & (1 << 3)) && (s->systest & (1 << 11)))) {
+            s->irqst &= ~value;
+            omap_mcspi_interrupt_update(s);
+        }
+        break;
+
+    case 0x1c: /* MCSPI_IRQENABLE */
+        s->irqen = value & 0x1777f;
+        omap_mcspi_interrupt_update(s);
+        break;
+
+    case 0x20: /* MCSPI_WAKEUPENABLE */
+        s->wken = value & 1;
+        break;
+
+    case 0x24: /* MCSPI_SYST */
+        if (s->control & (1 << 3))                     /* SYSTEM_TEST */
+            if (value & (1 << 11)) {                   /* SSB */
+                s->irqst |= 0x1777f;
+                omap_mcspi_interrupt_update(s);
+            }
+        s->systest = value & 0xfff;
+        break;
+
+    case 0x28: /* MCSPI_MODULCTRL */
+        if (value & (1 << 3))                          /* SYSTEM_TEST */
+            if (s->systest & (1 << 11)) {              /* SSB */
+                s->irqst |= 0x1777f;
+                omap_mcspi_interrupt_update(s);
+            }
+        s->control = value & 0xf;
+        break;
+
+    case 0x68: ch ++;
+        /* fall through */
+    case 0x54: ch ++;
+        /* fall through */
+    case 0x40: ch ++;
+        /* fall through */
+    case 0x2c: /* MCSPI_CHCONF */
+        if ((value ^ s->ch[ch].config) & (3 << 14))    /* DMAR | DMAW */
+            omap_mcspi_dmarequest_update(s->ch + ch);
+        if (((value >> 12) & 3) == 3)                  /* TRM */
+            fprintf(stderr, "%s: invalid TRM value (3)\n", __FUNCTION__);
+        if (((value >> 7) & 0x1f) < 3)                 /* WL */
+            fprintf(stderr, "%s: invalid WL value (%" PRIx64 ")\n",
+                            __FUNCTION__, (value >> 7) & 0x1f);
+        s->ch[ch].config = value & 0x7fffff;
+        break;
+
+    case 0x70: ch ++;
+        /* fall through */
+    case 0x5c: ch ++;
+        /* fall through */
+    case 0x48: ch ++;
+        /* fall through */
+    case 0x34: /* MCSPI_CHCTRL */
+        if (value & ~s->ch[ch].control & 1) {          /* EN */
+            s->ch[ch].control |= 1;
+            omap_mcspi_transfer_run(s, ch);
+        } else
+            s->ch[ch].control = value & 1;
+        break;
+
+    case 0x74: ch ++;
+        /* fall through */
+    case 0x60: ch ++;
+        /* fall through */
+    case 0x4c: ch ++;
+        /* fall through */
+    case 0x38: /* MCSPI_TX */
+        s->ch[ch].tx = value;
+        s->ch[ch].status &= ~(1 << 1);                 /* TXS */
+        omap_mcspi_transfer_run(s, ch);
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+        return;
+    }
+}
+
+static const MemoryRegionOps omap_mcspi_ops = {
+    .read = omap_mcspi_read,
+    .write = omap_mcspi_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+struct omap_mcspi_s *omap_mcspi_init(struct omap_target_agent_s *ta, int chnum,
+                qemu_irq irq, qemu_irq *drq, omap_clk fclk, omap_clk iclk)
+{
+    struct omap_mcspi_s *s = (struct omap_mcspi_s *)
+            g_malloc0(sizeof(struct omap_mcspi_s));
+    struct omap_mcspi_ch_s *ch = s->ch;
+
+    s->irq = irq;
+    s->chnum = chnum;
+    while (chnum --) {
+        ch->txdrq = *drq ++;
+        ch->rxdrq = *drq ++;
+        ch ++;
+    }
+    omap_mcspi_reset(s);
+
+    memory_region_init_io(&s->iomem, &omap_mcspi_ops, s, "omap.mcspi",
+                          omap_l4_region_size(ta, 0));
+    omap_l4_attach(ta, 0, &s->iomem);
+
+    return s;
+}
+
+void omap_mcspi_attach(struct omap_mcspi_s *s,
+                uint32_t (*txrx)(void *opaque, uint32_t, int), void *opaque,
+                int chipselect)
+{
+    if (chipselect < 0 || chipselect >= s->chnum)
+        hw_error("%s: Bad chipselect %i\n", __FUNCTION__, chipselect);
+
+    s->ch[chipselect].txrx = txrx;
+    s->ch[chipselect].opaque = opaque;
+}
diff --git a/hw/ssi/pl022.c b/hw/ssi/pl022.c
new file mode 100644 (file)
index 0000000..536c216
--- /dev/null
@@ -0,0 +1,308 @@
+/*
+ * Arm PrimeCell PL022 Synchronous Serial Port
+ *
+ * Copyright (c) 2007 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the GPL.
+ */
+
+#include "hw/sysbus.h"
+#include "hw/ssi.h"
+
+//#define DEBUG_PL022 1
+
+#ifdef DEBUG_PL022
+#define DPRINTF(fmt, ...) \
+do { printf("pl022: " fmt , ## __VA_ARGS__); } while (0)
+#define BADF(fmt, ...) \
+do { fprintf(stderr, "pl022: error: " fmt , ## __VA_ARGS__); exit(1);} while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while(0)
+#define BADF(fmt, ...) \
+do { fprintf(stderr, "pl022: error: " fmt , ## __VA_ARGS__);} while (0)
+#endif
+
+#define PL022_CR1_LBM 0x01
+#define PL022_CR1_SSE 0x02
+#define PL022_CR1_MS  0x04
+#define PL022_CR1_SDO 0x08
+
+#define PL022_SR_TFE  0x01
+#define PL022_SR_TNF  0x02
+#define PL022_SR_RNE  0x04
+#define PL022_SR_RFF  0x08
+#define PL022_SR_BSY  0x10
+
+#define PL022_INT_ROR 0x01
+#define PL022_INT_RT  0x04
+#define PL022_INT_RX  0x04
+#define PL022_INT_TX  0x08
+
+typedef struct {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    uint32_t cr0;
+    uint32_t cr1;
+    uint32_t bitmask;
+    uint32_t sr;
+    uint32_t cpsr;
+    uint32_t is;
+    uint32_t im;
+    /* The FIFO head points to the next empty entry.  */
+    int tx_fifo_head;
+    int rx_fifo_head;
+    int tx_fifo_len;
+    int rx_fifo_len;
+    uint16_t tx_fifo[8];
+    uint16_t rx_fifo[8];
+    qemu_irq irq;
+    SSIBus *ssi;
+} pl022_state;
+
+static const unsigned char pl022_id[8] =
+  { 0x22, 0x10, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
+
+static void pl022_update(pl022_state *s)
+{
+    s->sr = 0;
+    if (s->tx_fifo_len == 0)
+        s->sr |= PL022_SR_TFE;
+    if (s->tx_fifo_len != 8)
+        s->sr |= PL022_SR_TNF;
+    if (s->rx_fifo_len != 0)
+        s->sr |= PL022_SR_RNE;
+    if (s->rx_fifo_len == 8)
+        s->sr |= PL022_SR_RFF;
+    if (s->tx_fifo_len)
+        s->sr |= PL022_SR_BSY;
+    s->is = 0;
+    if (s->rx_fifo_len >= 4)
+        s->is |= PL022_INT_RX;
+    if (s->tx_fifo_len <= 4)
+        s->is |= PL022_INT_TX;
+
+    qemu_set_irq(s->irq, (s->is & s->im) != 0);
+}
+
+static void pl022_xfer(pl022_state *s)
+{
+    int i;
+    int o;
+    int val;
+
+    if ((s->cr1 & PL022_CR1_SSE) == 0) {
+        pl022_update(s);
+        DPRINTF("Disabled\n");
+        return;
+    }
+
+    DPRINTF("Maybe xfer %d/%d\n", s->tx_fifo_len, s->rx_fifo_len);
+    i = (s->tx_fifo_head - s->tx_fifo_len) & 7;
+    o = s->rx_fifo_head;
+    /* ??? We do not emulate the line speed.
+       This may break some applications.  The are two problematic cases:
+        (a) A driver feeds data into the TX FIFO until it is full,
+         and only then drains the RX FIFO.  On real hardware the CPU can
+         feed data fast enough that the RX fifo never gets chance to overflow.
+        (b) A driver transmits data, deliberately allowing the RX FIFO to
+         overflow because it ignores the RX data anyway.
+
+       We choose to support (a) by stalling the transmit engine if it would
+       cause the RX FIFO to overflow.  In practice much transmit-only code
+       falls into (a) because it flushes the RX FIFO to determine when
+       the transfer has completed.  */
+    while (s->tx_fifo_len && s->rx_fifo_len < 8) {
+        DPRINTF("xfer\n");
+        val = s->tx_fifo[i];
+        if (s->cr1 & PL022_CR1_LBM) {
+            /* Loopback mode.  */
+        } else {
+            val = ssi_transfer(s->ssi, val);
+        }
+        s->rx_fifo[o] = val & s->bitmask;
+        i = (i + 1) & 7;
+        o = (o + 1) & 7;
+        s->tx_fifo_len--;
+        s->rx_fifo_len++;
+    }
+    s->rx_fifo_head = o;
+    pl022_update(s);
+}
+
+static uint64_t pl022_read(void *opaque, hwaddr offset,
+                           unsigned size)
+{
+    pl022_state *s = (pl022_state *)opaque;
+    int val;
+
+    if (offset >= 0xfe0 && offset < 0x1000) {
+        return pl022_id[(offset - 0xfe0) >> 2];
+    }
+    switch (offset) {
+    case 0x00: /* CR0 */
+      return s->cr0;
+    case 0x04: /* CR1 */
+      return s->cr1;
+    case 0x08: /* DR */
+        if (s->rx_fifo_len) {
+            val = s->rx_fifo[(s->rx_fifo_head - s->rx_fifo_len) & 7];
+            DPRINTF("RX %02x\n", val);
+            s->rx_fifo_len--;
+            pl022_xfer(s);
+        } else {
+            val = 0;
+        }
+        return val;
+    case 0x0c: /* SR */
+        return s->sr;
+    case 0x10: /* CPSR */
+        return s->cpsr;
+    case 0x14: /* IMSC */
+        return s->im;
+    case 0x18: /* RIS */
+        return s->is;
+    case 0x1c: /* MIS */
+        return s->im & s->is;
+    case 0x20: /* DMACR */
+        /* Not implemented.  */
+        return 0;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "pl022_read: Bad offset %x\n", (int)offset);
+        return 0;
+    }
+}
+
+static void pl022_write(void *opaque, hwaddr offset,
+                        uint64_t value, unsigned size)
+{
+    pl022_state *s = (pl022_state *)opaque;
+
+    switch (offset) {
+    case 0x00: /* CR0 */
+        s->cr0 = value;
+        /* Clock rate and format are ignored.  */
+        s->bitmask = (1 << ((value & 15) + 1)) - 1;
+        break;
+    case 0x04: /* CR1 */
+        s->cr1 = value;
+        if ((s->cr1 & (PL022_CR1_MS | PL022_CR1_SSE))
+                   == (PL022_CR1_MS | PL022_CR1_SSE)) {
+            BADF("SPI slave mode not implemented\n");
+        }
+        pl022_xfer(s);
+        break;
+    case 0x08: /* DR */
+        if (s->tx_fifo_len < 8) {
+            DPRINTF("TX %02x\n", (unsigned)value);
+            s->tx_fifo[s->tx_fifo_head] = value & s->bitmask;
+            s->tx_fifo_head = (s->tx_fifo_head + 1) & 7;
+            s->tx_fifo_len++;
+            pl022_xfer(s);
+        }
+        break;
+    case 0x10: /* CPSR */
+        /* Prescaler.  Ignored.  */
+        s->cpsr = value & 0xff;
+        break;
+    case 0x14: /* IMSC */
+        s->im = value;
+        pl022_update(s);
+        break;
+    case 0x20: /* DMACR */
+        if (value) {
+            qemu_log_mask(LOG_UNIMP, "pl022: DMA not implemented\n");
+        }
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "pl022_write: Bad offset %x\n", (int)offset);
+    }
+}
+
+static void pl022_reset(pl022_state *s)
+{
+    s->rx_fifo_len = 0;
+    s->tx_fifo_len = 0;
+    s->im = 0;
+    s->is = PL022_INT_TX;
+    s->sr = PL022_SR_TFE | PL022_SR_TNF;
+}
+
+static const MemoryRegionOps pl022_ops = {
+    .read = pl022_read,
+    .write = pl022_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static const VMStateDescription vmstate_pl022 = {
+    .name = "pl022_ssp",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32(cr0, pl022_state),
+        VMSTATE_UINT32(cr1, pl022_state),
+        VMSTATE_UINT32(bitmask, pl022_state),
+        VMSTATE_UINT32(sr, pl022_state),
+        VMSTATE_UINT32(cpsr, pl022_state),
+        VMSTATE_UINT32(is, pl022_state),
+        VMSTATE_UINT32(im, pl022_state),
+        VMSTATE_INT32(tx_fifo_head, pl022_state),
+        VMSTATE_INT32(rx_fifo_head, pl022_state),
+        VMSTATE_INT32(tx_fifo_len, pl022_state),
+        VMSTATE_INT32(rx_fifo_len, pl022_state),
+        VMSTATE_UINT16(tx_fifo[0], pl022_state),
+        VMSTATE_UINT16(rx_fifo[0], pl022_state),
+        VMSTATE_UINT16(tx_fifo[1], pl022_state),
+        VMSTATE_UINT16(rx_fifo[1], pl022_state),
+        VMSTATE_UINT16(tx_fifo[2], pl022_state),
+        VMSTATE_UINT16(rx_fifo[2], pl022_state),
+        VMSTATE_UINT16(tx_fifo[3], pl022_state),
+        VMSTATE_UINT16(rx_fifo[3], pl022_state),
+        VMSTATE_UINT16(tx_fifo[4], pl022_state),
+        VMSTATE_UINT16(rx_fifo[4], pl022_state),
+        VMSTATE_UINT16(tx_fifo[5], pl022_state),
+        VMSTATE_UINT16(rx_fifo[5], pl022_state),
+        VMSTATE_UINT16(tx_fifo[6], pl022_state),
+        VMSTATE_UINT16(rx_fifo[6], pl022_state),
+        VMSTATE_UINT16(tx_fifo[7], pl022_state),
+        VMSTATE_UINT16(rx_fifo[7], pl022_state),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int pl022_init(SysBusDevice *dev)
+{
+    pl022_state *s = FROM_SYSBUS(pl022_state, dev);
+
+    memory_region_init_io(&s->iomem, &pl022_ops, s, "pl022", 0x1000);
+    sysbus_init_mmio(dev, &s->iomem);
+    sysbus_init_irq(dev, &s->irq);
+    s->ssi = ssi_create_bus(&dev->qdev, "ssi");
+    pl022_reset(s);
+    vmstate_register(&dev->qdev, -1, &vmstate_pl022, s);
+    return 0;
+}
+
+static void pl022_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sdc->init = pl022_init;
+}
+
+static const TypeInfo pl022_info = {
+    .name          = "pl022",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(pl022_state),
+    .class_init    = pl022_class_init,
+};
+
+static void pl022_register_types(void)
+{
+    type_register_static(&pl022_info);
+}
+
+type_init(pl022_register_types)
diff --git a/hw/ssi/ssi.c b/hw/ssi/ssi.c
new file mode 100644 (file)
index 0000000..1264d9d
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ * QEMU Synchronous Serial Interface support
+ *
+ * Copyright (c) 2009 CodeSourcery.
+ * Copyright (c) 2012 Peter A.G. Crosthwaite (peter.crosthwaite@petalogix.com)
+ * Copyright (c) 2012 PetaLogix Pty Ltd.
+ * 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 "hw/ssi.h"
+
+struct SSIBus {
+    BusState qbus;
+};
+
+#define TYPE_SSI_BUS "SSI"
+#define SSI_BUS(obj) OBJECT_CHECK(SSIBus, (obj), TYPE_SSI_BUS)
+
+static const TypeInfo ssi_bus_info = {
+    .name = TYPE_SSI_BUS,
+    .parent = TYPE_BUS,
+    .instance_size = sizeof(SSIBus),
+};
+
+static void ssi_cs_default(void *opaque, int n, int level)
+{
+    SSISlave *s = SSI_SLAVE(opaque);
+    bool cs = !!level;
+    assert(n == 0);
+    if (s->cs != cs) {
+        SSISlaveClass *ssc = SSI_SLAVE_GET_CLASS(s);
+        if (ssc->set_cs) {
+            ssc->set_cs(s, cs);
+        }
+    }
+    s->cs = cs;
+}
+
+static uint32_t ssi_transfer_raw_default(SSISlave *dev, uint32_t val)
+{
+    SSISlaveClass *ssc = SSI_SLAVE_GET_CLASS(dev);
+
+    if ((dev->cs && ssc->cs_polarity == SSI_CS_HIGH) ||
+            (!dev->cs && ssc->cs_polarity == SSI_CS_LOW) ||
+            ssc->cs_polarity == SSI_CS_NONE) {
+        return ssc->transfer(dev, val);
+    }
+    return 0;
+}
+
+static int ssi_slave_init(DeviceState *dev)
+{
+    SSISlave *s = SSI_SLAVE(dev);
+    SSISlaveClass *ssc = SSI_SLAVE_GET_CLASS(s);
+
+    if (ssc->transfer_raw == ssi_transfer_raw_default &&
+            ssc->cs_polarity != SSI_CS_NONE) {
+        qdev_init_gpio_in(&s->qdev, ssi_cs_default, 1);
+    }
+
+    return ssc->init(s);
+}
+
+static void ssi_slave_class_init(ObjectClass *klass, void *data)
+{
+    SSISlaveClass *ssc = SSI_SLAVE_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->init = ssi_slave_init;
+    dc->bus_type = TYPE_SSI_BUS;
+    if (!ssc->transfer_raw) {
+        ssc->transfer_raw = ssi_transfer_raw_default;
+    }
+}
+
+static const 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_no_init(SSIBus *bus, const char *name)
+{
+    return qdev_create(&bus->qbus, name);
+}
+
+DeviceState *ssi_create_slave(SSIBus *bus, const char *name)
+{
+    DeviceState *dev = ssi_create_slave_no_init(bus, name);
+
+    qdev_init_nofail(dev);
+    return dev;
+}
+
+SSIBus *ssi_create_bus(DeviceState *parent, const char *name)
+{
+    BusState *bus;
+    bus = qbus_create(TYPE_SSI_BUS, parent, name);
+    return FROM_QBUS(SSIBus, bus);
+}
+
+uint32_t ssi_transfer(SSIBus *bus, uint32_t val)
+{
+    BusChild *kid;
+    SSISlaveClass *ssc;
+    uint32_t r = 0;
+
+    QTAILQ_FOREACH(kid, &bus->qbus.children, sibling) {
+        SSISlave *slave = SSI_SLAVE(kid->child);
+        ssc = SSI_SLAVE_GET_CLASS(slave);
+        r |= ssc->transfer_raw(slave, val);
+    }
+
+    return r;
+}
+
+const VMStateDescription vmstate_ssi_slave = {
+    .name = "SSISlave",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_BOOL(cs, SSISlave),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void ssi_slave_register_types(void)
+{
+    type_register_static(&ssi_bus_info);
+    type_register_static(&ssi_slave_info);
+}
+
+type_init(ssi_slave_register_types)
+
+typedef struct SSIAutoConnectArg {
+    qemu_irq **cs_linep;
+    SSIBus *bus;
+} SSIAutoConnectArg;
+
+static int ssi_auto_connect_slave(Object *child, void *opaque)
+{
+    SSIAutoConnectArg *arg = opaque;
+    SSISlave *dev = (SSISlave *)object_dynamic_cast(child, TYPE_SSI_SLAVE);
+    qemu_irq cs_line;
+
+    if (!dev) {
+        return 0;
+    }
+
+    cs_line = qdev_get_gpio_in(DEVICE(dev), 0);
+    qdev_set_parent_bus(DEVICE(dev), &arg->bus->qbus);
+    **arg->cs_linep = cs_line;
+    (*arg->cs_linep)++;
+    return 0;
+}
+
+void ssi_auto_connect_slaves(DeviceState *parent, qemu_irq *cs_line,
+                             SSIBus *bus)
+{
+    SSIAutoConnectArg arg = {
+        .cs_linep = &cs_line,
+        .bus = bus
+    };
+
+    object_child_foreach(OBJECT(parent), ssi_auto_connect_slave, &arg);
+}
diff --git a/hw/ssi/xilinx_spi.c b/hw/ssi/xilinx_spi.c
new file mode 100644 (file)
index 0000000..f6bd3ba
--- /dev/null
@@ -0,0 +1,385 @@
+/*
+ * QEMU model of the Xilinx SPI Controller
+ *
+ * Copyright (C) 2010 Edgar E. Iglesias.
+ * Copyright (C) 2012 Peter A. G. Crosthwaite <peter.crosthwaite@petalogix.com>
+ * Copyright (C) 2012 PetaLogix
+ *
+ * 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 "hw/sysbus.h"
+#include "sysemu/sysemu.h"
+#include "qemu/log.h"
+#include "qemu/fifo8.h"
+
+#include "hw/ssi.h"
+
+#ifdef XILINX_SPI_ERR_DEBUG
+#define DB_PRINT(...) do { \
+    fprintf(stderr,  ": %s: ", __func__); \
+    fprintf(stderr, ## __VA_ARGS__); \
+    } while (0);
+#else
+    #define DB_PRINT(...)
+#endif
+
+#define R_DGIER     (0x1c / 4)
+#define R_DGIER_IE  (1 << 31)
+
+#define R_IPISR     (0x20 / 4)
+#define IRQ_DRR_NOT_EMPTY    (1 << (31 - 23))
+#define IRQ_DRR_OVERRUN      (1 << (31 - 26))
+#define IRQ_DRR_FULL         (1 << (31 - 27))
+#define IRQ_TX_FF_HALF_EMPTY (1 << 6)
+#define IRQ_DTR_UNDERRUN     (1 << 3)
+#define IRQ_DTR_EMPTY        (1 << (31 - 29))
+
+#define R_IPIER     (0x28 / 4)
+#define R_SRR       (0x40 / 4)
+#define R_SPICR     (0x60 / 4)
+#define R_SPICR_TXFF_RST     (1 << 5)
+#define R_SPICR_RXFF_RST     (1 << 6)
+#define R_SPICR_MTI          (1 << 8)
+
+#define R_SPISR     (0x64 / 4)
+#define SR_TX_FULL    (1 << 3)
+#define SR_TX_EMPTY   (1 << 2)
+#define SR_RX_FULL    (1 << 1)
+#define SR_RX_EMPTY   (1 << 0)
+
+#define R_SPIDTR    (0x68 / 4)
+#define R_SPIDRR    (0x6C / 4)
+#define R_SPISSR    (0x70 / 4)
+#define R_TX_FF_OCY (0x74 / 4)
+#define R_RX_FF_OCY (0x78 / 4)
+#define R_MAX       (0x7C / 4)
+
+#define FIFO_CAPACITY 256
+
+typedef struct XilinxSPI {
+    SysBusDevice busdev;
+    MemoryRegion mmio;
+
+    qemu_irq irq;
+    int irqline;
+
+    uint8_t num_cs;
+    qemu_irq *cs_lines;
+
+    SSIBus *spi;
+
+    Fifo8 rx_fifo;
+    Fifo8 tx_fifo;
+
+    uint32_t regs[R_MAX];
+} XilinxSPI;
+
+static void txfifo_reset(XilinxSPI *s)
+{
+    fifo8_reset(&s->tx_fifo);
+
+    s->regs[R_SPISR] &= ~SR_TX_FULL;
+    s->regs[R_SPISR] |= SR_TX_EMPTY;
+}
+
+static void rxfifo_reset(XilinxSPI *s)
+{
+    fifo8_reset(&s->rx_fifo);
+
+    s->regs[R_SPISR] |= SR_RX_EMPTY;
+    s->regs[R_SPISR] &= ~SR_RX_FULL;
+}
+
+static void xlx_spi_update_cs(XilinxSPI *s)
+{
+   int i;
+
+    for (i = 0; i < s->num_cs; ++i) {
+        qemu_set_irq(s->cs_lines[i], !(~s->regs[R_SPISSR] & 1 << i));
+    }
+}
+
+static void xlx_spi_update_irq(XilinxSPI *s)
+{
+    uint32_t pending;
+
+    s->regs[R_IPISR] |=
+            (!fifo8_is_empty(&s->rx_fifo) ? IRQ_DRR_NOT_EMPTY : 0) |
+            (fifo8_is_full(&s->rx_fifo) ? IRQ_DRR_FULL : 0);
+
+    pending = s->regs[R_IPISR] & s->regs[R_IPIER];
+
+    pending = pending && (s->regs[R_DGIER] & R_DGIER_IE);
+    pending = !!pending;
+
+    /* This call lies right in the data paths so don't call the
+       irq chain unless things really changed.  */
+    if (pending != s->irqline) {
+        s->irqline = pending;
+        DB_PRINT("irq_change of state %d ISR:%x IER:%X\n",
+                    pending, s->regs[R_IPISR], s->regs[R_IPIER]);
+        qemu_set_irq(s->irq, pending);
+    }
+
+}
+
+static void xlx_spi_do_reset(XilinxSPI *s)
+{
+    memset(s->regs, 0, sizeof s->regs);
+
+    rxfifo_reset(s);
+    txfifo_reset(s);
+
+    s->regs[R_SPISSR] = ~0;
+    xlx_spi_update_irq(s);
+    xlx_spi_update_cs(s);
+}
+
+static void xlx_spi_reset(DeviceState *d)
+{
+    xlx_spi_do_reset(DO_UPCAST(XilinxSPI, busdev.qdev, d));
+}
+
+static inline int spi_master_enabled(XilinxSPI *s)
+{
+    return !(s->regs[R_SPICR] & R_SPICR_MTI);
+}
+
+static void spi_flush_txfifo(XilinxSPI *s)
+{
+    uint32_t tx;
+    uint32_t rx;
+
+    while (!fifo8_is_empty(&s->tx_fifo)) {
+        tx = (uint32_t)fifo8_pop(&s->tx_fifo);
+        DB_PRINT("data tx:%x\n", tx);
+        rx = ssi_transfer(s->spi, tx);
+        DB_PRINT("data rx:%x\n", rx);
+        if (fifo8_is_full(&s->rx_fifo)) {
+            s->regs[R_IPISR] |= IRQ_DRR_OVERRUN;
+        } else {
+            fifo8_push(&s->rx_fifo, (uint8_t)rx);
+            if (fifo8_is_full(&s->rx_fifo)) {
+                s->regs[R_SPISR] |= SR_RX_FULL;
+                s->regs[R_IPISR] |= IRQ_DRR_FULL;
+            }
+        }
+
+        s->regs[R_SPISR] &= ~SR_RX_EMPTY;
+        s->regs[R_SPISR] &= ~SR_TX_FULL;
+        s->regs[R_SPISR] |= SR_TX_EMPTY;
+
+        s->regs[R_IPISR] |= IRQ_DTR_EMPTY;
+        s->regs[R_IPISR] |= IRQ_DRR_NOT_EMPTY;
+    }
+
+}
+
+static uint64_t
+spi_read(void *opaque, hwaddr addr, unsigned int size)
+{
+    XilinxSPI *s = opaque;
+    uint32_t r = 0;
+
+    addr >>= 2;
+    switch (addr) {
+    case R_SPIDRR:
+        if (fifo8_is_empty(&s->rx_fifo)) {
+            DB_PRINT("Read from empty FIFO!\n");
+            return 0xdeadbeef;
+        }
+
+        s->regs[R_SPISR] &= ~SR_RX_FULL;
+        r = fifo8_pop(&s->rx_fifo);
+        if (fifo8_is_empty(&s->rx_fifo)) {
+            s->regs[R_SPISR] |= SR_RX_EMPTY;
+        }
+        break;
+
+    case R_SPISR:
+        r = s->regs[addr];
+        break;
+
+    default:
+        if (addr < ARRAY_SIZE(s->regs)) {
+            r = s->regs[addr];
+        }
+        break;
+
+    }
+    DB_PRINT("addr=" TARGET_FMT_plx " = %x\n", addr * 4, r);
+    xlx_spi_update_irq(s);
+    return r;
+}
+
+static void
+spi_write(void *opaque, hwaddr addr,
+            uint64_t val64, unsigned int size)
+{
+    XilinxSPI *s = opaque;
+    uint32_t value = val64;
+
+    DB_PRINT("addr=" TARGET_FMT_plx " = %x\n", addr, value);
+    addr >>= 2;
+    switch (addr) {
+    case R_SRR:
+        if (value != 0xa) {
+            DB_PRINT("Invalid write to SRR %x\n", value);
+        } else {
+            xlx_spi_do_reset(s);
+        }
+        break;
+
+    case R_SPIDTR:
+        s->regs[R_SPISR] &= ~SR_TX_EMPTY;
+        fifo8_push(&s->tx_fifo, (uint8_t)value);
+        if (fifo8_is_full(&s->tx_fifo)) {
+            s->regs[R_SPISR] |= SR_TX_FULL;
+        }
+        if (!spi_master_enabled(s)) {
+            goto done;
+        } else {
+            DB_PRINT("DTR and master enabled\n");
+        }
+        spi_flush_txfifo(s);
+        break;
+
+    case R_SPISR:
+        DB_PRINT("Invalid write to SPISR %x\n", value);
+        break;
+
+    case R_IPISR:
+        /* Toggle the bits.  */
+        s->regs[addr] ^= value;
+        break;
+
+    /* Slave Select Register.  */
+    case R_SPISSR:
+        s->regs[addr] = value;
+        xlx_spi_update_cs(s);
+        break;
+
+    case R_SPICR:
+        /* FIXME: reset irq and sr state to empty queues.  */
+        if (value & R_SPICR_RXFF_RST) {
+            rxfifo_reset(s);
+        }
+
+        if (value & R_SPICR_TXFF_RST) {
+            txfifo_reset(s);
+        }
+        value &= ~(R_SPICR_RXFF_RST | R_SPICR_TXFF_RST);
+        s->regs[addr] = value;
+
+        if (!(value & R_SPICR_MTI)) {
+            spi_flush_txfifo(s);
+        }
+        break;
+
+    default:
+        if (addr < ARRAY_SIZE(s->regs)) {
+            s->regs[addr] = value;
+        }
+        break;
+    }
+
+done:
+    xlx_spi_update_irq(s);
+}
+
+static const MemoryRegionOps spi_ops = {
+    .read = spi_read,
+    .write = spi_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4
+    }
+};
+
+static int xilinx_spi_init(SysBusDevice *dev)
+{
+    int i;
+    XilinxSPI *s = FROM_SYSBUS(typeof(*s), dev);
+
+    DB_PRINT("\n");
+
+    s->spi = ssi_create_bus(&dev->qdev, "spi");
+
+    sysbus_init_irq(dev, &s->irq);
+    s->cs_lines = g_new(qemu_irq, s->num_cs);
+    ssi_auto_connect_slaves(DEVICE(s), s->cs_lines, s->spi);
+    for (i = 0; i < s->num_cs; ++i) {
+        sysbus_init_irq(dev, &s->cs_lines[i]);
+    }
+
+    memory_region_init_io(&s->mmio, &spi_ops, s, "xilinx-spi", R_MAX * 4);
+    sysbus_init_mmio(dev, &s->mmio);
+
+    s->irqline = -1;
+
+    fifo8_create(&s->tx_fifo, FIFO_CAPACITY);
+    fifo8_create(&s->rx_fifo, FIFO_CAPACITY);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_xilinx_spi = {
+    .name = "xilinx_spi",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_FIFO8(tx_fifo, XilinxSPI),
+        VMSTATE_FIFO8(rx_fifo, XilinxSPI),
+        VMSTATE_UINT32_ARRAY(regs, XilinxSPI, R_MAX),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static Property xilinx_spi_properties[] = {
+    DEFINE_PROP_UINT8("num-ss-bits", XilinxSPI, num_cs, 1),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void xilinx_spi_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = xilinx_spi_init;
+    dc->reset = xlx_spi_reset;
+    dc->props = xilinx_spi_properties;
+    dc->vmsd = &vmstate_xilinx_spi;
+}
+
+static const TypeInfo xilinx_spi_info = {
+    .name           = "xlnx.xps-spi",
+    .parent         = TYPE_SYS_BUS_DEVICE,
+    .instance_size  = sizeof(XilinxSPI),
+    .class_init     = xilinx_spi_class_init,
+};
+
+static void xilinx_spi_register_types(void)
+{
+    type_register_static(&xilinx_spi_info);
+}
+
+type_init(xilinx_spi_register_types)
diff --git a/hw/ssi/xilinx_spips.c b/hw/ssi/xilinx_spips.c
new file mode 100644 (file)
index 0000000..b2397f4
--- /dev/null
@@ -0,0 +1,595 @@
+/*
+ * QEMU model of the Xilinx Zynq SPI controller
+ *
+ * Copyright (c) 2012 Peter A. G. Crosthwaite
+ *
+ * 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 "hw/sysbus.h"
+#include "sysemu/sysemu.h"
+#include "hw/ptimer.h"
+#include "qemu/log.h"
+#include "qemu/fifo8.h"
+#include "hw/ssi.h"
+#include "qemu/bitops.h"
+
+#ifdef XILINX_SPIPS_ERR_DEBUG
+#define DB_PRINT(...) do { \
+    fprintf(stderr,  ": %s: ", __func__); \
+    fprintf(stderr, ## __VA_ARGS__); \
+    } while (0);
+#else
+    #define DB_PRINT(...)
+#endif
+
+/* config register */
+#define R_CONFIG            (0x00 / 4)
+#define IFMODE              (1 << 31)
+#define ENDIAN              (1 << 26)
+#define MODEFAIL_GEN_EN     (1 << 17)
+#define MAN_START_COM       (1 << 16)
+#define MAN_START_EN        (1 << 15)
+#define MANUAL_CS           (1 << 14)
+#define CS                  (0xF << 10)
+#define CS_SHIFT            (10)
+#define PERI_SEL            (1 << 9)
+#define REF_CLK             (1 << 8)
+#define FIFO_WIDTH          (3 << 6)
+#define BAUD_RATE_DIV       (7 << 3)
+#define CLK_PH              (1 << 2)
+#define CLK_POL             (1 << 1)
+#define MODE_SEL            (1 << 0)
+
+/* interrupt mechanism */
+#define R_INTR_STATUS       (0x04 / 4)
+#define R_INTR_EN           (0x08 / 4)
+#define R_INTR_DIS          (0x0C / 4)
+#define R_INTR_MASK         (0x10 / 4)
+#define IXR_TX_FIFO_UNDERFLOW   (1 << 6)
+#define IXR_RX_FIFO_FULL        (1 << 5)
+#define IXR_RX_FIFO_NOT_EMPTY   (1 << 4)
+#define IXR_TX_FIFO_FULL        (1 << 3)
+#define IXR_TX_FIFO_NOT_FULL    (1 << 2)
+#define IXR_TX_FIFO_MODE_FAIL   (1 << 1)
+#define IXR_RX_FIFO_OVERFLOW    (1 << 0)
+#define IXR_ALL                 ((IXR_TX_FIFO_UNDERFLOW<<1)-1)
+
+#define R_EN                (0x14 / 4)
+#define R_DELAY             (0x18 / 4)
+#define R_TX_DATA           (0x1C / 4)
+#define R_RX_DATA           (0x20 / 4)
+#define R_SLAVE_IDLE_COUNT  (0x24 / 4)
+#define R_TX_THRES          (0x28 / 4)
+#define R_RX_THRES          (0x2C / 4)
+#define R_TXD1              (0x80 / 4)
+#define R_TXD2              (0x84 / 4)
+#define R_TXD3              (0x88 / 4)
+
+#define R_LQSPI_CFG         (0xa0 / 4)
+#define R_LQSPI_CFG_RESET       0x03A002EB
+#define LQSPI_CFG_LQ_MODE       (1 << 31)
+#define LQSPI_CFG_TWO_MEM       (1 << 30)
+#define LQSPI_CFG_SEP_BUS       (1 << 30)
+#define LQSPI_CFG_U_PAGE        (1 << 28)
+#define LQSPI_CFG_MODE_EN       (1 << 25)
+#define LQSPI_CFG_MODE_WIDTH    8
+#define LQSPI_CFG_MODE_SHIFT    16
+#define LQSPI_CFG_DUMMY_WIDTH   3
+#define LQSPI_CFG_DUMMY_SHIFT   8
+#define LQSPI_CFG_INST_CODE     0xFF
+
+#define R_LQSPI_STS         (0xA4 / 4)
+#define LQSPI_STS_WR_RECVD      (1 << 1)
+
+#define R_MOD_ID            (0xFC / 4)
+
+#define R_MAX (R_MOD_ID+1)
+
+/* size of TXRX FIFOs */
+#define RXFF_A          32
+#define TXFF_A          32
+
+/* 16MB per linear region */
+#define LQSPI_ADDRESS_BITS 24
+/* Bite off 4k chunks at a time */
+#define LQSPI_CACHE_SIZE 1024
+
+#define SNOOP_CHECKING 0xFF
+#define SNOOP_NONE 0xFE
+#define SNOOP_STRIPING 0
+
+typedef enum {
+    READ = 0x3,
+    FAST_READ = 0xb,
+    DOR = 0x3b,
+    QOR = 0x6b,
+    DIOR = 0xbb,
+    QIOR = 0xeb,
+
+    PP = 0x2,
+    DPP = 0xa2,
+    QPP = 0x32,
+} FlashCMD;
+
+typedef struct {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    MemoryRegion mmlqspi;
+
+    qemu_irq irq;
+    int irqline;
+
+    uint8_t num_cs;
+    uint8_t num_busses;
+
+    uint8_t snoop_state;
+    qemu_irq *cs_lines;
+    SSIBus **spi;
+
+    Fifo8 rx_fifo;
+    Fifo8 tx_fifo;
+
+    uint8_t num_txrx_bytes;
+
+    uint32_t regs[R_MAX];
+
+    uint32_t lqspi_buf[LQSPI_CACHE_SIZE];
+    hwaddr lqspi_cached_addr;
+} XilinxSPIPS;
+
+#define TYPE_XILINX_SPIPS "xilinx,spips"
+
+#define XILINX_SPIPS(obj) \
+     OBJECT_CHECK(XilinxSPIPS, (obj), TYPE_XILINX_SPIPS)
+
+static inline int num_effective_busses(XilinxSPIPS *s)
+{
+    return (s->regs[R_LQSPI_CFG] & LQSPI_CFG_SEP_BUS &&
+            s->regs[R_LQSPI_CFG] & LQSPI_CFG_TWO_MEM) ? s->num_busses : 1;
+}
+
+static void xilinx_spips_update_cs_lines(XilinxSPIPS *s)
+{
+    int i, j;
+    bool found = false;
+    int field = s->regs[R_CONFIG] >> CS_SHIFT;
+
+    for (i = 0; i < s->num_cs; i++) {
+        for (j = 0; j < num_effective_busses(s); j++) {
+            int upage = !!(s->regs[R_LQSPI_STS] & LQSPI_CFG_U_PAGE);
+            int cs_to_set = (j * s->num_cs + i + upage) %
+                                (s->num_cs * s->num_busses);
+
+            if (~field & (1 << i) && !found) {
+                DB_PRINT("selecting slave %d\n", i);
+                qemu_set_irq(s->cs_lines[cs_to_set], 0);
+            } else {
+                qemu_set_irq(s->cs_lines[cs_to_set], 1);
+            }
+        }
+        if (~field & (1 << i)) {
+            found = true;
+        }
+    }
+    if (!found) {
+        s->snoop_state = SNOOP_CHECKING;
+    }
+}
+
+static void xilinx_spips_update_ixr(XilinxSPIPS *s)
+{
+    /* These are set/cleared as they occur */
+    s->regs[R_INTR_STATUS] &= (IXR_TX_FIFO_UNDERFLOW | IXR_RX_FIFO_OVERFLOW |
+                                IXR_TX_FIFO_MODE_FAIL);
+    /* these are pure functions of fifo state, set them here */
+    s->regs[R_INTR_STATUS] |=
+        (fifo8_is_full(&s->rx_fifo) ? IXR_RX_FIFO_FULL : 0) |
+        (s->rx_fifo.num >= s->regs[R_RX_THRES] ? IXR_RX_FIFO_NOT_EMPTY : 0) |
+        (fifo8_is_full(&s->tx_fifo) ? IXR_TX_FIFO_FULL : 0) |
+        (s->tx_fifo.num < s->regs[R_TX_THRES] ? IXR_TX_FIFO_NOT_FULL : 0);
+    /* drive external interrupt pin */
+    int new_irqline = !!(s->regs[R_INTR_MASK] & s->regs[R_INTR_STATUS] &
+                                                                IXR_ALL);
+    if (new_irqline != s->irqline) {
+        s->irqline = new_irqline;
+        qemu_set_irq(s->irq, s->irqline);
+    }
+}
+
+static void xilinx_spips_reset(DeviceState *d)
+{
+    XilinxSPIPS *s = XILINX_SPIPS(d);
+
+    int i;
+    for (i = 0; i < R_MAX; i++) {
+        s->regs[i] = 0;
+    }
+
+    fifo8_reset(&s->rx_fifo);
+    fifo8_reset(&s->rx_fifo);
+    /* non zero resets */
+    s->regs[R_CONFIG] |= MODEFAIL_GEN_EN;
+    s->regs[R_SLAVE_IDLE_COUNT] = 0xFF;
+    s->regs[R_TX_THRES] = 1;
+    s->regs[R_RX_THRES] = 1;
+    /* FIXME: move magic number definition somewhere sensible */
+    s->regs[R_MOD_ID] = 0x01090106;
+    s->regs[R_LQSPI_CFG] = R_LQSPI_CFG_RESET;
+    s->snoop_state = SNOOP_CHECKING;
+    xilinx_spips_update_ixr(s);
+    xilinx_spips_update_cs_lines(s);
+}
+
+static void xilinx_spips_flush_txfifo(XilinxSPIPS *s)
+{
+    for (;;) {
+        int i;
+        uint8_t rx;
+        uint8_t tx = 0;
+
+        for (i = 0; i < num_effective_busses(s); ++i) {
+            if (!i || s->snoop_state == SNOOP_STRIPING) {
+                if (fifo8_is_empty(&s->tx_fifo)) {
+                    s->regs[R_INTR_STATUS] |= IXR_TX_FIFO_UNDERFLOW;
+                    xilinx_spips_update_ixr(s);
+                    return;
+                } else {
+                    tx = fifo8_pop(&s->tx_fifo);
+                }
+            }
+            rx = ssi_transfer(s->spi[i], (uint32_t)tx);
+            DB_PRINT("tx = %02x rx = %02x\n", tx, rx);
+            if (!i || s->snoop_state == SNOOP_STRIPING) {
+                if (fifo8_is_full(&s->rx_fifo)) {
+                    s->regs[R_INTR_STATUS] |= IXR_RX_FIFO_OVERFLOW;
+                    DB_PRINT("rx FIFO overflow");
+                } else {
+                    fifo8_push(&s->rx_fifo, (uint8_t)rx);
+                }
+            }
+        }
+
+        switch (s->snoop_state) {
+        case (SNOOP_CHECKING):
+            switch (tx) { /* new instruction code */
+            case READ: /* 3 address bytes, no dummy bytes/cycles */
+            case PP:
+            case DPP:
+            case QPP:
+                s->snoop_state = 3;
+                break;
+            case FAST_READ: /* 3 address bytes, 1 dummy byte */
+            case DOR:
+            case QOR:
+            case DIOR: /* FIXME: these vary between vendor - set to spansion */
+                s->snoop_state = 4;
+                break;
+            case QIOR: /* 3 address bytes, 2 dummy bytes */
+                s->snoop_state = 6;
+                break;
+            default:
+                s->snoop_state = SNOOP_NONE;
+            }
+            break;
+        case (SNOOP_STRIPING):
+        case (SNOOP_NONE):
+            break;
+        default:
+            s->snoop_state--;
+        }
+    }
+}
+
+static inline void rx_data_bytes(XilinxSPIPS *s, uint32_t *value, int max)
+{
+    int i;
+
+    *value = 0;
+    for (i = 0; i < max && !fifo8_is_empty(&s->rx_fifo); ++i) {
+        uint32_t next = fifo8_pop(&s->rx_fifo) & 0xFF;
+        *value |= next << 8 * (s->regs[R_CONFIG] & ENDIAN ? 3-i : i);
+    }
+}
+
+static uint64_t xilinx_spips_read(void *opaque, hwaddr addr,
+                                                        unsigned size)
+{
+    XilinxSPIPS *s = opaque;
+    uint32_t mask = ~0;
+    uint32_t ret;
+
+    addr >>= 2;
+    switch (addr) {
+    case R_CONFIG:
+        mask = 0x0002FFFF;
+        break;
+    case R_INTR_STATUS:
+    case R_INTR_MASK:
+        mask = IXR_ALL;
+        break;
+    case  R_EN:
+        mask = 0x1;
+        break;
+    case R_SLAVE_IDLE_COUNT:
+        mask = 0xFF;
+        break;
+    case R_MOD_ID:
+        mask = 0x01FFFFFF;
+        break;
+    case R_INTR_EN:
+    case R_INTR_DIS:
+    case R_TX_DATA:
+        mask = 0;
+        break;
+    case R_RX_DATA:
+        rx_data_bytes(s, &ret, s->num_txrx_bytes);
+        DB_PRINT("addr=" TARGET_FMT_plx " = %x\n", addr * 4, ret);
+        xilinx_spips_update_ixr(s);
+        return ret;
+    }
+    DB_PRINT("addr=" TARGET_FMT_plx " = %x\n", addr * 4, s->regs[addr] & mask);
+    return s->regs[addr] & mask;
+
+}
+
+static inline void tx_data_bytes(XilinxSPIPS *s, uint32_t value, int num)
+{
+    int i;
+    for (i = 0; i < num && !fifo8_is_full(&s->tx_fifo); ++i) {
+        if (s->regs[R_CONFIG] & ENDIAN) {
+            fifo8_push(&s->tx_fifo, (uint8_t)(value >> 24));
+            value <<= 8;
+        } else {
+            fifo8_push(&s->tx_fifo, (uint8_t)value);
+            value >>= 8;
+        }
+    }
+}
+
+static void xilinx_spips_write(void *opaque, hwaddr addr,
+                                        uint64_t value, unsigned size)
+{
+    int mask = ~0;
+    int man_start_com = 0;
+    XilinxSPIPS *s = opaque;
+
+    DB_PRINT("addr=" TARGET_FMT_plx " = %x\n", addr, (unsigned)value);
+    addr >>= 2;
+    switch (addr) {
+    case R_CONFIG:
+        mask = 0x0002FFFF;
+        if (value & MAN_START_COM) {
+            man_start_com = 1;
+        }
+        break;
+    case R_INTR_STATUS:
+        mask = IXR_ALL;
+        s->regs[R_INTR_STATUS] &= ~(mask & value);
+        goto no_reg_update;
+    case R_INTR_DIS:
+        mask = IXR_ALL;
+        s->regs[R_INTR_MASK] &= ~(mask & value);
+        goto no_reg_update;
+    case R_INTR_EN:
+        mask = IXR_ALL;
+        s->regs[R_INTR_MASK] |= mask & value;
+        goto no_reg_update;
+    case R_EN:
+        mask = 0x1;
+        break;
+    case R_SLAVE_IDLE_COUNT:
+        mask = 0xFF;
+        break;
+    case R_RX_DATA:
+    case R_INTR_MASK:
+    case R_MOD_ID:
+        mask = 0;
+        break;
+    case R_TX_DATA:
+        tx_data_bytes(s, (uint32_t)value, s->num_txrx_bytes);
+        goto no_reg_update;
+    case R_TXD1:
+        tx_data_bytes(s, (uint32_t)value, 1);
+        goto no_reg_update;
+    case R_TXD2:
+        tx_data_bytes(s, (uint32_t)value, 2);
+        goto no_reg_update;
+    case R_TXD3:
+        tx_data_bytes(s, (uint32_t)value, 3);
+        goto no_reg_update;
+    }
+    s->regs[addr] = (s->regs[addr] & ~mask) | (value & mask);
+no_reg_update:
+    if (man_start_com) {
+        xilinx_spips_flush_txfifo(s);
+    }
+    xilinx_spips_update_ixr(s);
+    xilinx_spips_update_cs_lines(s);
+}
+
+static const MemoryRegionOps spips_ops = {
+    .read = xilinx_spips_read,
+    .write = xilinx_spips_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+#define LQSPI_CACHE_SIZE 1024
+
+static uint64_t
+lqspi_read(void *opaque, hwaddr addr, unsigned int size)
+{
+    int i;
+    XilinxSPIPS *s = opaque;
+
+    if (addr >= s->lqspi_cached_addr &&
+            addr <= s->lqspi_cached_addr + LQSPI_CACHE_SIZE - 4) {
+        return s->lqspi_buf[(addr - s->lqspi_cached_addr) >> 2];
+    } else {
+        int flash_addr = (addr / num_effective_busses(s));
+        int slave = flash_addr >> LQSPI_ADDRESS_BITS;
+        int cache_entry = 0;
+
+        DB_PRINT("config reg status: %08x\n", s->regs[R_LQSPI_CFG]);
+
+        fifo8_reset(&s->tx_fifo);
+        fifo8_reset(&s->rx_fifo);
+
+        s->regs[R_CONFIG] &= ~CS;
+        s->regs[R_CONFIG] |= (~(1 << slave) << CS_SHIFT) & CS;
+        xilinx_spips_update_cs_lines(s);
+
+        /* instruction */
+        DB_PRINT("pushing read instruction: %02x\n",
+                 (uint8_t)(s->regs[R_LQSPI_CFG] & LQSPI_CFG_INST_CODE));
+        fifo8_push(&s->tx_fifo, s->regs[R_LQSPI_CFG] & LQSPI_CFG_INST_CODE);
+        /* read address */
+        DB_PRINT("pushing read address %06x\n", flash_addr);
+        fifo8_push(&s->tx_fifo, (uint8_t)(flash_addr >> 16));
+        fifo8_push(&s->tx_fifo, (uint8_t)(flash_addr >> 8));
+        fifo8_push(&s->tx_fifo, (uint8_t)flash_addr);
+        /* mode bits */
+        if (s->regs[R_LQSPI_CFG] & LQSPI_CFG_MODE_EN) {
+            fifo8_push(&s->tx_fifo, extract32(s->regs[R_LQSPI_CFG],
+                                              LQSPI_CFG_MODE_SHIFT,
+                                              LQSPI_CFG_MODE_WIDTH));
+        }
+        /* dummy bytes */
+        for (i = 0; i < (extract32(s->regs[R_LQSPI_CFG], LQSPI_CFG_DUMMY_SHIFT,
+                                   LQSPI_CFG_DUMMY_WIDTH)); ++i) {
+            DB_PRINT("pushing dummy byte\n");
+            fifo8_push(&s->tx_fifo, 0);
+        }
+        xilinx_spips_flush_txfifo(s);
+        fifo8_reset(&s->rx_fifo);
+
+        DB_PRINT("starting QSPI data read\n");
+
+        for (i = 0; i < LQSPI_CACHE_SIZE / 4; ++i) {
+            tx_data_bytes(s, 0, 4);
+            xilinx_spips_flush_txfifo(s);
+            rx_data_bytes(s, &s->lqspi_buf[cache_entry], 4);
+            cache_entry++;
+        }
+
+        s->regs[R_CONFIG] |= CS;
+        xilinx_spips_update_cs_lines(s);
+
+        s->lqspi_cached_addr = addr;
+        return lqspi_read(opaque, addr, size);
+    }
+}
+
+static const MemoryRegionOps lqspi_ops = {
+    .read = lqspi_read,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4
+    }
+};
+
+static void xilinx_spips_realize(DeviceState *dev, Error **errp)
+{
+    XilinxSPIPS *s = XILINX_SPIPS(dev);
+    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+    int i;
+
+    DB_PRINT("inited device model\n");
+
+    s->spi = g_new(SSIBus *, s->num_busses);
+    for (i = 0; i < s->num_busses; ++i) {
+        char bus_name[16];
+        snprintf(bus_name, 16, "spi%d", i);
+        s->spi[i] = ssi_create_bus(dev, bus_name);
+    }
+
+    s->cs_lines = g_new0(qemu_irq, s->num_cs * s->num_busses);
+    ssi_auto_connect_slaves(DEVICE(s), s->cs_lines, s->spi[0]);
+    ssi_auto_connect_slaves(DEVICE(s), s->cs_lines, s->spi[1]);
+    sysbus_init_irq(sbd, &s->irq);
+    for (i = 0; i < s->num_cs * s->num_busses; ++i) {
+        sysbus_init_irq(sbd, &s->cs_lines[i]);
+    }
+
+    memory_region_init_io(&s->iomem, &spips_ops, s, "spi", R_MAX*4);
+    sysbus_init_mmio(sbd, &s->iomem);
+
+    memory_region_init_io(&s->mmlqspi, &lqspi_ops, s, "lqspi",
+                          (1 << LQSPI_ADDRESS_BITS) * 2);
+    sysbus_init_mmio(sbd, &s->mmlqspi);
+
+    s->irqline = -1;
+    s->lqspi_cached_addr = ~0ULL;
+
+    fifo8_create(&s->rx_fifo, RXFF_A);
+    fifo8_create(&s->tx_fifo, TXFF_A);
+}
+
+static int xilinx_spips_post_load(void *opaque, int version_id)
+{
+    xilinx_spips_update_ixr((XilinxSPIPS *)opaque);
+    xilinx_spips_update_cs_lines((XilinxSPIPS *)opaque);
+    return 0;
+}
+
+static const VMStateDescription vmstate_xilinx_spips = {
+    .name = "xilinx_spips",
+    .version_id = 2,
+    .minimum_version_id = 2,
+    .minimum_version_id_old = 2,
+    .post_load = xilinx_spips_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_FIFO8(tx_fifo, XilinxSPIPS),
+        VMSTATE_FIFO8(rx_fifo, XilinxSPIPS),
+        VMSTATE_UINT32_ARRAY(regs, XilinxSPIPS, R_MAX),
+        VMSTATE_UINT8(snoop_state, XilinxSPIPS),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static Property xilinx_spips_properties[] = {
+    DEFINE_PROP_UINT8("num-busses", XilinxSPIPS, num_busses, 1),
+    DEFINE_PROP_UINT8("num-ss-bits", XilinxSPIPS, num_cs, 4),
+    DEFINE_PROP_UINT8("num-txrx-bytes", XilinxSPIPS, num_txrx_bytes, 1),
+    DEFINE_PROP_END_OF_LIST(),
+};
+static void xilinx_spips_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->realize = xilinx_spips_realize;
+    dc->reset = xilinx_spips_reset;
+    dc->props = xilinx_spips_properties;
+    dc->vmsd = &vmstate_xilinx_spips;
+}
+
+static const TypeInfo xilinx_spips_info = {
+    .name  = TYPE_XILINX_SPIPS,
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size  = sizeof(XilinxSPIPS),
+    .class_init = xilinx_spips_class_init,
+};
+
+static void xilinx_spips_register_types(void)
+{
+    type_register_static(&xilinx_spips_info);
+}
+
+type_init(xilinx_spips_register_types)
diff --git a/hw/stellaris_enet.c b/hw/stellaris_enet.c
deleted file mode 100644 (file)
index 59b8456..0000000
+++ /dev/null
@@ -1,450 +0,0 @@
-/*
- * Luminary Micro Stellaris Ethernet Controller
- *
- * Copyright (c) 2007 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the GPL.
- */
-#include "hw/sysbus.h"
-#include "net/net.h"
-#include <zlib.h>
-
-//#define DEBUG_STELLARIS_ENET 1
-
-#ifdef DEBUG_STELLARIS_ENET
-#define DPRINTF(fmt, ...) \
-do { printf("stellaris_enet: " fmt , ## __VA_ARGS__); } while (0)
-#define BADF(fmt, ...) \
-do { fprintf(stderr, "stellaris_enet: error: " fmt , ## __VA_ARGS__); exit(1);} while (0)
-#else
-#define DPRINTF(fmt, ...) do {} while(0)
-#define BADF(fmt, ...) \
-do { fprintf(stderr, "stellaris_enet: error: " fmt , ## __VA_ARGS__);} while (0)
-#endif
-
-#define SE_INT_RX       0x01
-#define SE_INT_TXER     0x02
-#define SE_INT_TXEMP    0x04
-#define SE_INT_FOV      0x08
-#define SE_INT_RXER     0x10
-#define SE_INT_MD       0x20
-#define SE_INT_PHY      0x40
-
-#define SE_RCTL_RXEN    0x01
-#define SE_RCTL_AMUL    0x02
-#define SE_RCTL_PRMS    0x04
-#define SE_RCTL_BADCRC  0x08
-#define SE_RCTL_RSTFIFO 0x10
-
-#define SE_TCTL_TXEN    0x01
-#define SE_TCTL_PADEN   0x02
-#define SE_TCTL_CRC     0x04
-#define SE_TCTL_DUPLEX  0x08
-
-typedef struct {
-    SysBusDevice busdev;
-    uint32_t ris;
-    uint32_t im;
-    uint32_t rctl;
-    uint32_t tctl;
-    uint32_t thr;
-    uint32_t mctl;
-    uint32_t mdv;
-    uint32_t mtxd;
-    uint32_t mrxd;
-    uint32_t np;
-    int tx_frame_len;
-    int tx_fifo_len;
-    uint8_t tx_fifo[2048];
-    /* Real hardware has a 2k fifo, which works out to be at most 31 packets.
-       We implement a full 31 packet fifo.  */
-    struct {
-        uint8_t data[2048];
-        int len;
-    } rx[31];
-    uint8_t *rx_fifo;
-    int rx_fifo_len;
-    int next_packet;
-    NICState *nic;
-    NICConf conf;
-    qemu_irq irq;
-    MemoryRegion mmio;
-} stellaris_enet_state;
-
-static void stellaris_enet_update(stellaris_enet_state *s)
-{
-    qemu_set_irq(s->irq, (s->ris & s->im) != 0);
-}
-
-/* TODO: Implement MAC address filtering.  */
-static ssize_t stellaris_enet_receive(NetClientState *nc, const uint8_t *buf, size_t size)
-{
-    stellaris_enet_state *s = qemu_get_nic_opaque(nc);
-    int n;
-    uint8_t *p;
-    uint32_t crc;
-
-    if ((s->rctl & SE_RCTL_RXEN) == 0)
-        return -1;
-    if (s->np >= 31) {
-        DPRINTF("Packet dropped\n");
-        return -1;
-    }
-
-    DPRINTF("Received packet len=%d\n", size);
-    n = s->next_packet + s->np;
-    if (n >= 31)
-        n -= 31;
-    s->np++;
-
-    s->rx[n].len = size + 6;
-    p = s->rx[n].data;
-    *(p++) = (size + 6);
-    *(p++) = (size + 6) >> 8;
-    memcpy (p, buf, size);
-    p += size;
-    crc = crc32(~0, buf, size);
-    *(p++) = crc;
-    *(p++) = crc >> 8;
-    *(p++) = crc >> 16;
-    *(p++) = crc >> 24;
-    /* Clear the remaining bytes in the last word.  */
-    if ((size & 3) != 2) {
-        memset(p, 0, (6 - size) & 3);
-    }
-
-    s->ris |= SE_INT_RX;
-    stellaris_enet_update(s);
-
-    return size;
-}
-
-static int stellaris_enet_can_receive(NetClientState *nc)
-{
-    stellaris_enet_state *s = qemu_get_nic_opaque(nc);
-
-    if ((s->rctl & SE_RCTL_RXEN) == 0)
-        return 1;
-
-    return (s->np < 31);
-}
-
-static uint64_t stellaris_enet_read(void *opaque, hwaddr offset,
-                                    unsigned size)
-{
-    stellaris_enet_state *s = (stellaris_enet_state *)opaque;
-    uint32_t val;
-
-    switch (offset) {
-    case 0x00: /* RIS */
-        DPRINTF("IRQ status %02x\n", s->ris);
-        return s->ris;
-    case 0x04: /* IM */
-        return s->im;
-    case 0x08: /* RCTL */
-        return s->rctl;
-    case 0x0c: /* TCTL */
-        return s->tctl;
-    case 0x10: /* DATA */
-        if (s->rx_fifo_len == 0) {
-            if (s->np == 0) {
-                BADF("RX underflow\n");
-                return 0;
-            }
-            s->rx_fifo_len = s->rx[s->next_packet].len;
-            s->rx_fifo = s->rx[s->next_packet].data;
-            DPRINTF("RX FIFO start packet len=%d\n", s->rx_fifo_len);
-        }
-        val = s->rx_fifo[0] | (s->rx_fifo[1] << 8) | (s->rx_fifo[2] << 16)
-              | (s->rx_fifo[3] << 24);
-        s->rx_fifo += 4;
-        s->rx_fifo_len -= 4;
-        if (s->rx_fifo_len <= 0) {
-            s->rx_fifo_len = 0;
-            s->next_packet++;
-            if (s->next_packet >= 31)
-                s->next_packet = 0;
-            s->np--;
-            DPRINTF("RX done np=%d\n", s->np);
-        }
-        return val;
-    case 0x14: /* IA0 */
-        return s->conf.macaddr.a[0] | (s->conf.macaddr.a[1] << 8)
-               | (s->conf.macaddr.a[2] << 16) | (s->conf.macaddr.a[3] << 24);
-    case 0x18: /* IA1 */
-        return s->conf.macaddr.a[4] | (s->conf.macaddr.a[5] << 8);
-    case 0x1c: /* THR */
-        return s->thr;
-    case 0x20: /* MCTL */
-        return s->mctl;
-    case 0x24: /* MDV */
-        return s->mdv;
-    case 0x28: /* MADD */
-        return 0;
-    case 0x2c: /* MTXD */
-        return s->mtxd;
-    case 0x30: /* MRXD */
-        return s->mrxd;
-    case 0x34: /* NP */
-        return s->np;
-    case 0x38: /* TR */
-        return 0;
-    case 0x3c: /* Undocuented: Timestamp? */
-        return 0;
-    default:
-        hw_error("stellaris_enet_read: Bad offset %x\n", (int)offset);
-        return 0;
-    }
-}
-
-static void stellaris_enet_write(void *opaque, hwaddr offset,
-                                 uint64_t value, unsigned size)
-{
-    stellaris_enet_state *s = (stellaris_enet_state *)opaque;
-
-    switch (offset) {
-    case 0x00: /* IACK */
-        s->ris &= ~value;
-        DPRINTF("IRQ ack %02x/%02x\n", value, s->ris);
-        stellaris_enet_update(s);
-        /* Clearing TXER also resets the TX fifo.  */
-        if (value & SE_INT_TXER)
-            s->tx_frame_len = -1;
-        break;
-    case 0x04: /* IM */
-        DPRINTF("IRQ mask %02x/%02x\n", value, s->ris);
-        s->im = value;
-        stellaris_enet_update(s);
-        break;
-    case 0x08: /* RCTL */
-        s->rctl = value;
-        if (value & SE_RCTL_RSTFIFO) {
-            s->rx_fifo_len = 0;
-            s->np = 0;
-            stellaris_enet_update(s);
-        }
-        break;
-    case 0x0c: /* TCTL */
-        s->tctl = value;
-        break;
-    case 0x10: /* DATA */
-        if (s->tx_frame_len == -1) {
-            s->tx_frame_len = value & 0xffff;
-            if (s->tx_frame_len > 2032) {
-                DPRINTF("TX frame too long (%d)\n", s->tx_frame_len);
-                s->tx_frame_len = 0;
-                s->ris |= SE_INT_TXER;
-                stellaris_enet_update(s);
-            } else {
-                DPRINTF("Start TX frame len=%d\n", s->tx_frame_len);
-                /* The value written does not include the ethernet header.  */
-                s->tx_frame_len += 14;
-                if ((s->tctl & SE_TCTL_CRC) == 0)
-                    s->tx_frame_len += 4;
-                s->tx_fifo_len = 0;
-                s->tx_fifo[s->tx_fifo_len++] = value >> 16;
-                s->tx_fifo[s->tx_fifo_len++] = value >> 24;
-            }
-        } else {
-            s->tx_fifo[s->tx_fifo_len++] = value;
-            s->tx_fifo[s->tx_fifo_len++] = value >> 8;
-            s->tx_fifo[s->tx_fifo_len++] = value >> 16;
-            s->tx_fifo[s->tx_fifo_len++] = value >> 24;
-            if (s->tx_fifo_len >= s->tx_frame_len) {
-                /* We don't implement explicit CRC, so just chop it off.  */
-                if ((s->tctl & SE_TCTL_CRC) == 0)
-                    s->tx_frame_len -= 4;
-                if ((s->tctl & SE_TCTL_PADEN) && s->tx_frame_len < 60) {
-                    memset(&s->tx_fifo[s->tx_frame_len], 0, 60 - s->tx_frame_len);
-                    s->tx_fifo_len = 60;
-                }
-                qemu_send_packet(qemu_get_queue(s->nic), s->tx_fifo,
-                                 s->tx_frame_len);
-                s->tx_frame_len = -1;
-                s->ris |= SE_INT_TXEMP;
-                stellaris_enet_update(s);
-                DPRINTF("Done TX\n");
-            }
-        }
-        break;
-    case 0x14: /* IA0 */
-        s->conf.macaddr.a[0] = value;
-        s->conf.macaddr.a[1] = value >> 8;
-        s->conf.macaddr.a[2] = value >> 16;
-        s->conf.macaddr.a[3] = value >> 24;
-        break;
-    case 0x18: /* IA1 */
-        s->conf.macaddr.a[4] = value;
-        s->conf.macaddr.a[5] = value >> 8;
-        break;
-    case 0x1c: /* THR */
-        s->thr = value;
-        break;
-    case 0x20: /* MCTL */
-        s->mctl = value;
-        break;
-    case 0x24: /* MDV */
-        s->mdv = value;
-        break;
-    case 0x28: /* MADD */
-        /* ignored.  */
-        break;
-    case 0x2c: /* MTXD */
-        s->mtxd = value & 0xff;
-        break;
-    case 0x30: /* MRXD */
-    case 0x34: /* NP */
-    case 0x38: /* TR */
-        /* Ignored.  */
-    case 0x3c: /* Undocuented: Timestamp? */
-        /* Ignored.  */
-        break;
-    default:
-        hw_error("stellaris_enet_write: Bad offset %x\n", (int)offset);
-    }
-}
-
-static const MemoryRegionOps stellaris_enet_ops = {
-    .read = stellaris_enet_read,
-    .write = stellaris_enet_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void stellaris_enet_reset(stellaris_enet_state *s)
-{
-    s->mdv = 0x80;
-    s->rctl = SE_RCTL_BADCRC;
-    s->im = SE_INT_PHY | SE_INT_MD | SE_INT_RXER | SE_INT_FOV | SE_INT_TXEMP
-            | SE_INT_TXER | SE_INT_RX;
-    s->thr = 0x3f;
-    s->tx_frame_len = -1;
-}
-
-static void stellaris_enet_save(QEMUFile *f, void *opaque)
-{
-    stellaris_enet_state *s = (stellaris_enet_state *)opaque;
-    int i;
-
-    qemu_put_be32(f, s->ris);
-    qemu_put_be32(f, s->im);
-    qemu_put_be32(f, s->rctl);
-    qemu_put_be32(f, s->tctl);
-    qemu_put_be32(f, s->thr);
-    qemu_put_be32(f, s->mctl);
-    qemu_put_be32(f, s->mdv);
-    qemu_put_be32(f, s->mtxd);
-    qemu_put_be32(f, s->mrxd);
-    qemu_put_be32(f, s->np);
-    qemu_put_be32(f, s->tx_frame_len);
-    qemu_put_be32(f, s->tx_fifo_len);
-    qemu_put_buffer(f, s->tx_fifo, sizeof(s->tx_fifo));
-    for (i = 0; i < 31; i++) {
-        qemu_put_be32(f, s->rx[i].len);
-        qemu_put_buffer(f, s->rx[i].data, sizeof(s->rx[i].data));
-
-    }
-    qemu_put_be32(f, s->next_packet);
-    qemu_put_be32(f, s->rx_fifo - s->rx[s->next_packet].data);
-    qemu_put_be32(f, s->rx_fifo_len);
-}
-
-static int stellaris_enet_load(QEMUFile *f, void *opaque, int version_id)
-{
-    stellaris_enet_state *s = (stellaris_enet_state *)opaque;
-    int i;
-
-    if (version_id != 1)
-        return -EINVAL;
-
-    s->ris = qemu_get_be32(f);
-    s->im = qemu_get_be32(f);
-    s->rctl = qemu_get_be32(f);
-    s->tctl = qemu_get_be32(f);
-    s->thr = qemu_get_be32(f);
-    s->mctl = qemu_get_be32(f);
-    s->mdv = qemu_get_be32(f);
-    s->mtxd = qemu_get_be32(f);
-    s->mrxd = qemu_get_be32(f);
-    s->np = qemu_get_be32(f);
-    s->tx_frame_len = qemu_get_be32(f);
-    s->tx_fifo_len = qemu_get_be32(f);
-    qemu_get_buffer(f, s->tx_fifo, sizeof(s->tx_fifo));
-    for (i = 0; i < 31; i++) {
-        s->rx[i].len = qemu_get_be32(f);
-        qemu_get_buffer(f, s->rx[i].data, sizeof(s->rx[i].data));
-
-    }
-    s->next_packet = qemu_get_be32(f);
-    s->rx_fifo = s->rx[s->next_packet].data + qemu_get_be32(f);
-    s->rx_fifo_len = qemu_get_be32(f);
-
-    return 0;
-}
-
-static void stellaris_enet_cleanup(NetClientState *nc)
-{
-    stellaris_enet_state *s = qemu_get_nic_opaque(nc);
-
-    unregister_savevm(&s->busdev.qdev, "stellaris_enet", s);
-
-    memory_region_destroy(&s->mmio);
-
-    g_free(s);
-}
-
-static NetClientInfo net_stellaris_enet_info = {
-    .type = NET_CLIENT_OPTIONS_KIND_NIC,
-    .size = sizeof(NICState),
-    .can_receive = stellaris_enet_can_receive,
-    .receive = stellaris_enet_receive,
-    .cleanup = stellaris_enet_cleanup,
-};
-
-static int stellaris_enet_init(SysBusDevice *dev)
-{
-    stellaris_enet_state *s = FROM_SYSBUS(stellaris_enet_state, dev);
-
-    memory_region_init_io(&s->mmio, &stellaris_enet_ops, s, "stellaris_enet",
-                          0x1000);
-    sysbus_init_mmio(dev, &s->mmio);
-    sysbus_init_irq(dev, &s->irq);
-    qemu_macaddr_default_if_unset(&s->conf.macaddr);
-
-    s->nic = qemu_new_nic(&net_stellaris_enet_info, &s->conf,
-                          object_get_typename(OBJECT(dev)), dev->qdev.id, s);
-    qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
-
-    stellaris_enet_reset(s);
-    register_savevm(&s->busdev.qdev, "stellaris_enet", -1, 1,
-                    stellaris_enet_save, stellaris_enet_load, s);
-    return 0;
-}
-
-static Property stellaris_enet_properties[] = {
-    DEFINE_NIC_PROPERTIES(stellaris_enet_state, conf),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void stellaris_enet_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = stellaris_enet_init;
-    dc->props = stellaris_enet_properties;
-}
-
-static const 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_types(void)
-{
-    type_register_static(&stellaris_enet_info);
-}
-
-type_init(stellaris_enet_register_types)
diff --git a/hw/stellaris_input.c b/hw/stellaris_input.c
deleted file mode 100644 (file)
index 4e40792..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Gamepad style buttons connected to IRQ/GPIO lines
- *
- * Copyright (c) 2007 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the GPL.
- */
-#include "hw/hw.h"
-#include "hw/devices.h"
-#include "ui/console.h"
-
-typedef struct {
-    qemu_irq irq;
-    int keycode;
-    uint8_t pressed;
-} gamepad_button;
-
-typedef struct {
-    gamepad_button *buttons;
-    int num_buttons;
-    int extension;
-} gamepad_state;
-
-static void stellaris_gamepad_put_key(void * opaque, int keycode)
-{
-    gamepad_state *s = (gamepad_state *)opaque;
-    int i;
-    int down;
-
-    if (keycode == 0xe0 && !s->extension) {
-        s->extension = 0x80;
-        return;
-    }
-
-    down = (keycode & 0x80) == 0;
-    keycode = (keycode & 0x7f) | s->extension;
-
-    for (i = 0; i < s->num_buttons; i++) {
-        if (s->buttons[i].keycode == keycode
-                && s->buttons[i].pressed != down) {
-            s->buttons[i].pressed = down;
-            qemu_set_irq(s->buttons[i].irq, down);
-        }
-    }
-
-    s->extension = 0;
-}
-
-static const VMStateDescription vmstate_stellaris_button = {
-    .name = "stellaris_button",
-    .version_id = 0,
-    .minimum_version_id = 0,
-    .minimum_version_id_old = 0,
-    .fields      = (VMStateField[]) {
-        VMSTATE_UINT8(pressed, gamepad_button),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static const VMStateDescription vmstate_stellaris_gamepad = {
-    .name = "stellaris_gamepad",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField[]) {
-        VMSTATE_INT32(extension, gamepad_state),
-        VMSTATE_STRUCT_VARRAY_INT32(buttons, gamepad_state, num_buttons, 0,
-                              vmstate_stellaris_button, gamepad_button),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-/* Returns an array 5 ouput slots.  */
-void stellaris_gamepad_init(int n, qemu_irq *irq, const int *keycode)
-{
-    gamepad_state *s;
-    int i;
-
-    s = (gamepad_state *)g_malloc0(sizeof (gamepad_state));
-    s->buttons = (gamepad_button *)g_malloc0(n * sizeof (gamepad_button));
-    for (i = 0; i < n; i++) {
-        s->buttons[i].irq = irq[i];
-        s->buttons[i].keycode = keycode[i];
-    }
-    s->num_buttons = n;
-    qemu_add_kbd_event_handler(stellaris_gamepad_put_key, s);
-    vmstate_register(NULL, -1, &vmstate_stellaris_gamepad, s);
-}
diff --git a/hw/stream.c b/hw/stream.c
deleted file mode 100644 (file)
index a07d6a5..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-#include "hw/stream.h"
-
-void
-stream_push(StreamSlave *sink, uint8_t *buf, size_t len, uint32_t *app)
-{
-    StreamSlaveClass *k =  STREAM_SLAVE_GET_CLASS(sink);
-
-    k->push(sink, buf, len, app);
-}
-
-static const TypeInfo stream_slave_info = {
-    .name          = TYPE_STREAM_SLAVE,
-    .parent        = TYPE_INTERFACE,
-    .class_size = sizeof(StreamSlaveClass),
-};
-
-
-static void stream_slave_register_types(void)
-{
-    type_register_static(&stream_slave_info);
-}
-
-type_init(stream_slave_register_types)
diff --git a/hw/stream.h b/hw/stream.h
deleted file mode 100644 (file)
index f6137d6..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef STREAM_H
-#define STREAM_H 1
-
-#include "qemu-common.h"
-#include "qom/object.h"
-
-/* stream slave. Used until qdev provides a generic way.  */
-#define TYPE_STREAM_SLAVE "stream-slave"
-
-#define STREAM_SLAVE_CLASS(klass) \
-     OBJECT_CLASS_CHECK(StreamSlaveClass, (klass), TYPE_STREAM_SLAVE)
-#define STREAM_SLAVE_GET_CLASS(obj) \
-    OBJECT_GET_CLASS(StreamSlaveClass, (obj), TYPE_STREAM_SLAVE)
-#define STREAM_SLAVE(obj) \
-     INTERFACE_CHECK(StreamSlave, (obj), TYPE_STREAM_SLAVE)
-
-typedef struct StreamSlave {
-    Object Parent;
-} StreamSlave;
-
-typedef struct StreamSlaveClass {
-    InterfaceClass parent;
-
-    void (*push)(StreamSlave *obj, unsigned char *buf, size_t len,
-                                                    uint32_t *app);
-} StreamSlaveClass;
-
-void
-stream_push(StreamSlave *sink, uint8_t *buf, size_t len, uint32_t *app);
-
-#endif /* STREAM_H */
diff --git a/hw/strongarm.c b/hw/strongarm.c
deleted file mode 100644 (file)
index 49f9577..0000000
+++ /dev/null
@@ -1,1623 +0,0 @@
-/*
- * StrongARM SA-1100/SA-1110 emulation
- *
- * Copyright (C) 2011 Dmitry Eremin-Solenikov
- *
- * Largely based on StrongARM emulation:
- * Copyright (c) 2006 Openedhand Ltd.
- * Written by Andrzej Zaborowski <balrog@zabor.org>
- *
- * UART code based on QEMU 16550A UART emulation
- * Copyright (c) 2003-2004 Fabrice Bellard
- * Copyright (c) 2008 Citrix Systems, Inc.
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License version 2 as
- *  published by the Free Software Foundation.
- *
- *  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/>.
- *
- *  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/sysbus.h"
-#include "hw/strongarm.h"
-#include "qemu/error-report.h"
-#include "hw/arm-misc.h"
-#include "char/char.h"
-#include "sysemu/sysemu.h"
-#include "hw/ssi.h"
-
-//#define DEBUG
-
-/*
- TODO
- - Implement cp15, c14 ?
- - Implement cp15, c15 !!! (idle used in L)
- - Implement idle mode handling/DIM
- - Implement sleep mode/Wake sources
- - Implement reset control
- - Implement memory control regs
- - PCMCIA handling
- - Maybe support MBGNT/MBREQ
- - DMA channels
- - GPCLK
- - IrDA
- - MCP
- - Enhance UART with modem signals
- */
-
-#ifdef DEBUG
-# define DPRINTF(format, ...) printf(format , ## __VA_ARGS__)
-#else
-# define DPRINTF(format, ...) do { } while (0)
-#endif
-
-static struct {
-    hwaddr io_base;
-    int irq;
-} sa_serial[] = {
-    { 0x80010000, SA_PIC_UART1 },
-    { 0x80030000, SA_PIC_UART2 },
-    { 0x80050000, SA_PIC_UART3 },
-    { 0, 0 }
-};
-
-/* Interrupt Controller */
-typedef struct {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-    qemu_irq    irq;
-    qemu_irq    fiq;
-
-    uint32_t pending;
-    uint32_t enabled;
-    uint32_t is_fiq;
-    uint32_t int_idle;
-} StrongARMPICState;
-
-#define ICIP    0x00
-#define ICMR    0x04
-#define ICLR    0x08
-#define ICFP    0x10
-#define ICPR    0x20
-#define ICCR    0x0c
-
-#define SA_PIC_SRCS     32
-
-
-static void strongarm_pic_update(void *opaque)
-{
-    StrongARMPICState *s = opaque;
-
-    /* FIXME: reflect DIM */
-    qemu_set_irq(s->fiq, s->pending & s->enabled &  s->is_fiq);
-    qemu_set_irq(s->irq, s->pending & s->enabled & ~s->is_fiq);
-}
-
-static void strongarm_pic_set_irq(void *opaque, int irq, int level)
-{
-    StrongARMPICState *s = opaque;
-
-    if (level) {
-        s->pending |= 1 << irq;
-    } else {
-        s->pending &= ~(1 << irq);
-    }
-
-    strongarm_pic_update(s);
-}
-
-static uint64_t strongarm_pic_mem_read(void *opaque, hwaddr offset,
-                                       unsigned size)
-{
-    StrongARMPICState *s = opaque;
-
-    switch (offset) {
-    case ICIP:
-        return s->pending & ~s->is_fiq & s->enabled;
-    case ICMR:
-        return s->enabled;
-    case ICLR:
-        return s->is_fiq;
-    case ICCR:
-        return s->int_idle == 0;
-    case ICFP:
-        return s->pending & s->is_fiq & s->enabled;
-    case ICPR:
-        return s->pending;
-    default:
-        printf("%s: Bad register offset 0x" TARGET_FMT_plx "\n",
-                        __func__, offset);
-        return 0;
-    }
-}
-
-static void strongarm_pic_mem_write(void *opaque, hwaddr offset,
-                                    uint64_t value, unsigned size)
-{
-    StrongARMPICState *s = opaque;
-
-    switch (offset) {
-    case ICMR:
-        s->enabled = value;
-        break;
-    case ICLR:
-        s->is_fiq = value;
-        break;
-    case ICCR:
-        s->int_idle = (value & 1) ? 0 : ~0;
-        break;
-    default:
-        printf("%s: Bad register offset 0x" TARGET_FMT_plx "\n",
-                        __func__, offset);
-        break;
-    }
-    strongarm_pic_update(s);
-}
-
-static const MemoryRegionOps strongarm_pic_ops = {
-    .read = strongarm_pic_mem_read,
-    .write = strongarm_pic_mem_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int strongarm_pic_initfn(SysBusDevice *dev)
-{
-    StrongARMPICState *s = FROM_SYSBUS(StrongARMPICState, dev);
-
-    qdev_init_gpio_in(&dev->qdev, strongarm_pic_set_irq, SA_PIC_SRCS);
-    memory_region_init_io(&s->iomem, &strongarm_pic_ops, s, "pic", 0x1000);
-    sysbus_init_mmio(dev, &s->iomem);
-    sysbus_init_irq(dev, &s->irq);
-    sysbus_init_irq(dev, &s->fiq);
-
-    return 0;
-}
-
-static int strongarm_pic_post_load(void *opaque, int version_id)
-{
-    strongarm_pic_update(opaque);
-    return 0;
-}
-
-static VMStateDescription vmstate_strongarm_pic_regs = {
-    .name = "strongarm_pic",
-    .version_id = 0,
-    .minimum_version_id = 0,
-    .minimum_version_id_old = 0,
-    .post_load = strongarm_pic_post_load,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT32(pending, StrongARMPICState),
-        VMSTATE_UINT32(enabled, StrongARMPICState),
-        VMSTATE_UINT32(is_fiq, StrongARMPICState),
-        VMSTATE_UINT32(int_idle, StrongARMPICState),
-        VMSTATE_END_OF_LIST(),
-    },
-};
-
-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 const 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 */
-#define RTAR 0x00 /* RTC Alarm register */
-#define RCNR 0x04 /* RTC Counter register */
-#define RTTR 0x08 /* RTC Timer Trim register */
-#define RTSR 0x10 /* RTC Status register */
-
-#define RTSR_AL (1 << 0) /* RTC Alarm detected */
-#define RTSR_HZ (1 << 1) /* RTC 1Hz detected */
-#define RTSR_ALE (1 << 2) /* RTC Alarm enable */
-#define RTSR_HZE (1 << 3) /* RTC 1Hz enable */
-
-/* 16 LSB of RTTR are clockdiv for internal trim logic,
- * trim delete isn't emulated, so
- * f = 32 768 / (RTTR_trim + 1) */
-
-typedef struct {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-    uint32_t rttr;
-    uint32_t rtsr;
-    uint32_t rtar;
-    uint32_t last_rcnr;
-    int64_t last_hz;
-    QEMUTimer *rtc_alarm;
-    QEMUTimer *rtc_hz;
-    qemu_irq rtc_irq;
-    qemu_irq rtc_hz_irq;
-} StrongARMRTCState;
-
-static inline void strongarm_rtc_int_update(StrongARMRTCState *s)
-{
-    qemu_set_irq(s->rtc_irq, s->rtsr & RTSR_AL);
-    qemu_set_irq(s->rtc_hz_irq, s->rtsr & RTSR_HZ);
-}
-
-static void strongarm_rtc_hzupdate(StrongARMRTCState *s)
-{
-    int64_t rt = qemu_get_clock_ms(rtc_clock);
-    s->last_rcnr += ((rt - s->last_hz) << 15) /
-            (1000 * ((s->rttr & 0xffff) + 1));
-    s->last_hz = rt;
-}
-
-static inline void strongarm_rtc_timer_update(StrongARMRTCState *s)
-{
-    if ((s->rtsr & RTSR_HZE) && !(s->rtsr & RTSR_HZ)) {
-        qemu_mod_timer(s->rtc_hz, s->last_hz + 1000);
-    } else {
-        qemu_del_timer(s->rtc_hz);
-    }
-
-    if ((s->rtsr & RTSR_ALE) && !(s->rtsr & RTSR_AL)) {
-        qemu_mod_timer(s->rtc_alarm, s->last_hz +
-                (((s->rtar - s->last_rcnr) * 1000 *
-                  ((s->rttr & 0xffff) + 1)) >> 15));
-    } else {
-        qemu_del_timer(s->rtc_alarm);
-    }
-}
-
-static inline void strongarm_rtc_alarm_tick(void *opaque)
-{
-    StrongARMRTCState *s = opaque;
-    s->rtsr |= RTSR_AL;
-    strongarm_rtc_timer_update(s);
-    strongarm_rtc_int_update(s);
-}
-
-static inline void strongarm_rtc_hz_tick(void *opaque)
-{
-    StrongARMRTCState *s = opaque;
-    s->rtsr |= RTSR_HZ;
-    strongarm_rtc_timer_update(s);
-    strongarm_rtc_int_update(s);
-}
-
-static uint64_t strongarm_rtc_read(void *opaque, hwaddr addr,
-                                   unsigned size)
-{
-    StrongARMRTCState *s = opaque;
-
-    switch (addr) {
-    case RTTR:
-        return s->rttr;
-    case RTSR:
-        return s->rtsr;
-    case RTAR:
-        return s->rtar;
-    case RCNR:
-        return s->last_rcnr +
-                ((qemu_get_clock_ms(rtc_clock) - s->last_hz) << 15) /
-                (1000 * ((s->rttr & 0xffff) + 1));
-    default:
-        printf("%s: Bad register 0x" TARGET_FMT_plx "\n", __func__, addr);
-        return 0;
-    }
-}
-
-static void strongarm_rtc_write(void *opaque, hwaddr addr,
-                                uint64_t value, unsigned size)
-{
-    StrongARMRTCState *s = opaque;
-    uint32_t old_rtsr;
-
-    switch (addr) {
-    case RTTR:
-        strongarm_rtc_hzupdate(s);
-        s->rttr = value;
-        strongarm_rtc_timer_update(s);
-        break;
-
-    case RTSR:
-        old_rtsr = s->rtsr;
-        s->rtsr = (value & (RTSR_ALE | RTSR_HZE)) |
-                  (s->rtsr & ~(value & (RTSR_AL | RTSR_HZ)));
-
-        if (s->rtsr != old_rtsr) {
-            strongarm_rtc_timer_update(s);
-        }
-
-        strongarm_rtc_int_update(s);
-        break;
-
-    case RTAR:
-        s->rtar = value;
-        strongarm_rtc_timer_update(s);
-        break;
-
-    case RCNR:
-        strongarm_rtc_hzupdate(s);
-        s->last_rcnr = value;
-        strongarm_rtc_timer_update(s);
-        break;
-
-    default:
-        printf("%s: Bad register 0x" TARGET_FMT_plx "\n", __func__, addr);
-    }
-}
-
-static const MemoryRegionOps strongarm_rtc_ops = {
-    .read = strongarm_rtc_read,
-    .write = strongarm_rtc_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int strongarm_rtc_init(SysBusDevice *dev)
-{
-    StrongARMRTCState *s = FROM_SYSBUS(StrongARMRTCState, dev);
-    struct tm tm;
-
-    s->rttr = 0x0;
-    s->rtsr = 0;
-
-    qemu_get_timedate(&tm, 0);
-
-    s->last_rcnr = (uint32_t) mktimegm(&tm);
-    s->last_hz = qemu_get_clock_ms(rtc_clock);
-
-    s->rtc_alarm = qemu_new_timer_ms(rtc_clock, strongarm_rtc_alarm_tick, s);
-    s->rtc_hz = qemu_new_timer_ms(rtc_clock, strongarm_rtc_hz_tick, s);
-
-    sysbus_init_irq(dev, &s->rtc_irq);
-    sysbus_init_irq(dev, &s->rtc_hz_irq);
-
-    memory_region_init_io(&s->iomem, &strongarm_rtc_ops, s, "rtc", 0x10000);
-    sysbus_init_mmio(dev, &s->iomem);
-
-    return 0;
-}
-
-static void strongarm_rtc_pre_save(void *opaque)
-{
-    StrongARMRTCState *s = opaque;
-
-    strongarm_rtc_hzupdate(s);
-}
-
-static int strongarm_rtc_post_load(void *opaque, int version_id)
-{
-    StrongARMRTCState *s = opaque;
-
-    strongarm_rtc_timer_update(s);
-    strongarm_rtc_int_update(s);
-
-    return 0;
-}
-
-static const VMStateDescription vmstate_strongarm_rtc_regs = {
-    .name = "strongarm-rtc",
-    .version_id = 0,
-    .minimum_version_id = 0,
-    .minimum_version_id_old = 0,
-    .pre_save = strongarm_rtc_pre_save,
-    .post_load = strongarm_rtc_post_load,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT32(rttr, StrongARMRTCState),
-        VMSTATE_UINT32(rtsr, StrongARMRTCState),
-        VMSTATE_UINT32(rtar, StrongARMRTCState),
-        VMSTATE_UINT32(last_rcnr, StrongARMRTCState),
-        VMSTATE_INT64(last_hz, StrongARMRTCState),
-        VMSTATE_END_OF_LIST(),
-    },
-};
-
-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 const 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 */
-#define GPLR 0x00
-#define GPDR 0x04
-#define GPSR 0x08
-#define GPCR 0x0c
-#define GRER 0x10
-#define GFER 0x14
-#define GEDR 0x18
-#define GAFR 0x1c
-
-typedef struct StrongARMGPIOInfo StrongARMGPIOInfo;
-struct StrongARMGPIOInfo {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-    qemu_irq handler[28];
-    qemu_irq irqs[11];
-    qemu_irq irqX;
-
-    uint32_t ilevel;
-    uint32_t olevel;
-    uint32_t dir;
-    uint32_t rising;
-    uint32_t falling;
-    uint32_t status;
-    uint32_t gpsr;
-    uint32_t gafr;
-
-    uint32_t prev_level;
-};
-
-
-static void strongarm_gpio_irq_update(StrongARMGPIOInfo *s)
-{
-    int i;
-    for (i = 0; i < 11; i++) {
-        qemu_set_irq(s->irqs[i], s->status & (1 << i));
-    }
-
-    qemu_set_irq(s->irqX, (s->status & ~0x7ff));
-}
-
-static void strongarm_gpio_set(void *opaque, int line, int level)
-{
-    StrongARMGPIOInfo *s = opaque;
-    uint32_t mask;
-
-    mask = 1 << line;
-
-    if (level) {
-        s->status |= s->rising & mask &
-                ~s->ilevel & ~s->dir;
-        s->ilevel |= mask;
-    } else {
-        s->status |= s->falling & mask &
-                s->ilevel & ~s->dir;
-        s->ilevel &= ~mask;
-    }
-
-    if (s->status & mask) {
-        strongarm_gpio_irq_update(s);
-    }
-}
-
-static void strongarm_gpio_handler_update(StrongARMGPIOInfo *s)
-{
-    uint32_t level, diff;
-    int bit;
-
-    level = s->olevel & s->dir;
-
-    for (diff = s->prev_level ^ level; diff; diff ^= 1 << bit) {
-        bit = ffs(diff) - 1;
-        qemu_set_irq(s->handler[bit], (level >> bit) & 1);
-    }
-
-    s->prev_level = level;
-}
-
-static uint64_t strongarm_gpio_read(void *opaque, hwaddr offset,
-                                    unsigned size)
-{
-    StrongARMGPIOInfo *s = opaque;
-
-    switch (offset) {
-    case GPDR:        /* GPIO Pin-Direction registers */
-        return s->dir;
-
-    case GPSR:        /* GPIO Pin-Output Set registers */
-        DPRINTF("%s: Read from a write-only register 0x" TARGET_FMT_plx "\n",
-                        __func__, offset);
-        return s->gpsr;    /* Return last written value.  */
-
-    case GPCR:        /* GPIO Pin-Output Clear registers */
-        DPRINTF("%s: Read from a write-only register 0x" TARGET_FMT_plx "\n",
-                        __func__, offset);
-        return 31337;        /* Specified as unpredictable in the docs.  */
-
-    case GRER:        /* GPIO Rising-Edge Detect Enable registers */
-        return s->rising;
-
-    case GFER:        /* GPIO Falling-Edge Detect Enable registers */
-        return s->falling;
-
-    case GAFR:        /* GPIO Alternate Function registers */
-        return s->gafr;
-
-    case GPLR:        /* GPIO Pin-Level registers */
-        return (s->olevel & s->dir) |
-               (s->ilevel & ~s->dir);
-
-    case GEDR:        /* GPIO Edge Detect Status registers */
-        return s->status;
-
-    default:
-        printf("%s: Bad offset 0x" TARGET_FMT_plx "\n", __func__, offset);
-    }
-
-    return 0;
-}
-
-static void strongarm_gpio_write(void *opaque, hwaddr offset,
-                                 uint64_t value, unsigned size)
-{
-    StrongARMGPIOInfo *s = opaque;
-
-    switch (offset) {
-    case GPDR:        /* GPIO Pin-Direction registers */
-        s->dir = value;
-        strongarm_gpio_handler_update(s);
-        break;
-
-    case GPSR:        /* GPIO Pin-Output Set registers */
-        s->olevel |= value;
-        strongarm_gpio_handler_update(s);
-        s->gpsr = value;
-        break;
-
-    case GPCR:        /* GPIO Pin-Output Clear registers */
-        s->olevel &= ~value;
-        strongarm_gpio_handler_update(s);
-        break;
-
-    case GRER:        /* GPIO Rising-Edge Detect Enable registers */
-        s->rising = value;
-        break;
-
-    case GFER:        /* GPIO Falling-Edge Detect Enable registers */
-        s->falling = value;
-        break;
-
-    case GAFR:        /* GPIO Alternate Function registers */
-        s->gafr = value;
-        break;
-
-    case GEDR:        /* GPIO Edge Detect Status registers */
-        s->status &= ~value;
-        strongarm_gpio_irq_update(s);
-        break;
-
-    default:
-        printf("%s: Bad offset 0x" TARGET_FMT_plx "\n", __func__, offset);
-    }
-}
-
-static const MemoryRegionOps strongarm_gpio_ops = {
-    .read = strongarm_gpio_read,
-    .write = strongarm_gpio_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static DeviceState *strongarm_gpio_init(hwaddr base,
-                DeviceState *pic)
-{
-    DeviceState *dev;
-    int i;
-
-    dev = qdev_create(NULL, "strongarm-gpio");
-    qdev_init_nofail(dev);
-
-    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
-    for (i = 0; i < 12; i++)
-        sysbus_connect_irq(SYS_BUS_DEVICE(dev), i,
-                    qdev_get_gpio_in(pic, SA_PIC_GPIO0_EDGE + i));
-
-    return dev;
-}
-
-static int strongarm_gpio_initfn(SysBusDevice *dev)
-{
-    StrongARMGPIOInfo *s;
-    int i;
-
-    s = FROM_SYSBUS(StrongARMGPIOInfo, dev);
-
-    qdev_init_gpio_in(&dev->qdev, strongarm_gpio_set, 28);
-    qdev_init_gpio_out(&dev->qdev, s->handler, 28);
-
-    memory_region_init_io(&s->iomem, &strongarm_gpio_ops, s, "gpio", 0x1000);
-
-    sysbus_init_mmio(dev, &s->iomem);
-    for (i = 0; i < 11; i++) {
-        sysbus_init_irq(dev, &s->irqs[i]);
-    }
-    sysbus_init_irq(dev, &s->irqX);
-
-    return 0;
-}
-
-static const VMStateDescription vmstate_strongarm_gpio_regs = {
-    .name = "strongarm-gpio",
-    .version_id = 0,
-    .minimum_version_id = 0,
-    .minimum_version_id_old = 0,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT32(ilevel, StrongARMGPIOInfo),
-        VMSTATE_UINT32(olevel, StrongARMGPIOInfo),
-        VMSTATE_UINT32(dir, StrongARMGPIOInfo),
-        VMSTATE_UINT32(rising, StrongARMGPIOInfo),
-        VMSTATE_UINT32(falling, StrongARMGPIOInfo),
-        VMSTATE_UINT32(status, StrongARMGPIOInfo),
-        VMSTATE_UINT32(gafr, StrongARMGPIOInfo),
-        VMSTATE_END_OF_LIST(),
-    },
-};
-
-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 const 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 */
-#define PPDR 0x00
-#define PPSR 0x04
-#define PPAR 0x08
-#define PSDR 0x0c
-#define PPFR 0x10
-
-typedef struct StrongARMPPCInfo StrongARMPPCInfo;
-struct StrongARMPPCInfo {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-    qemu_irq handler[28];
-
-    uint32_t ilevel;
-    uint32_t olevel;
-    uint32_t dir;
-    uint32_t ppar;
-    uint32_t psdr;
-    uint32_t ppfr;
-
-    uint32_t prev_level;
-};
-
-static void strongarm_ppc_set(void *opaque, int line, int level)
-{
-    StrongARMPPCInfo *s = opaque;
-
-    if (level) {
-        s->ilevel |= 1 << line;
-    } else {
-        s->ilevel &= ~(1 << line);
-    }
-}
-
-static void strongarm_ppc_handler_update(StrongARMPPCInfo *s)
-{
-    uint32_t level, diff;
-    int bit;
-
-    level = s->olevel & s->dir;
-
-    for (diff = s->prev_level ^ level; diff; diff ^= 1 << bit) {
-        bit = ffs(diff) - 1;
-        qemu_set_irq(s->handler[bit], (level >> bit) & 1);
-    }
-
-    s->prev_level = level;
-}
-
-static uint64_t strongarm_ppc_read(void *opaque, hwaddr offset,
-                                   unsigned size)
-{
-    StrongARMPPCInfo *s = opaque;
-
-    switch (offset) {
-    case PPDR:        /* PPC Pin Direction registers */
-        return s->dir | ~0x3fffff;
-
-    case PPSR:        /* PPC Pin State registers */
-        return (s->olevel & s->dir) |
-               (s->ilevel & ~s->dir) |
-               ~0x3fffff;
-
-    case PPAR:
-        return s->ppar | ~0x41000;
-
-    case PSDR:
-        return s->psdr;
-
-    case PPFR:
-        return s->ppfr | ~0x7f001;
-
-    default:
-        printf("%s: Bad offset 0x" TARGET_FMT_plx "\n", __func__, offset);
-    }
-
-    return 0;
-}
-
-static void strongarm_ppc_write(void *opaque, hwaddr offset,
-                                uint64_t value, unsigned size)
-{
-    StrongARMPPCInfo *s = opaque;
-
-    switch (offset) {
-    case PPDR:        /* PPC Pin Direction registers */
-        s->dir = value & 0x3fffff;
-        strongarm_ppc_handler_update(s);
-        break;
-
-    case PPSR:        /* PPC Pin State registers */
-        s->olevel = value & s->dir & 0x3fffff;
-        strongarm_ppc_handler_update(s);
-        break;
-
-    case PPAR:
-        s->ppar = value & 0x41000;
-        break;
-
-    case PSDR:
-        s->psdr = value & 0x3fffff;
-        break;
-
-    case PPFR:
-        s->ppfr = value & 0x7f001;
-        break;
-
-    default:
-        printf("%s: Bad offset 0x" TARGET_FMT_plx "\n", __func__, offset);
-    }
-}
-
-static const MemoryRegionOps strongarm_ppc_ops = {
-    .read = strongarm_ppc_read,
-    .write = strongarm_ppc_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int strongarm_ppc_init(SysBusDevice *dev)
-{
-    StrongARMPPCInfo *s;
-
-    s = FROM_SYSBUS(StrongARMPPCInfo, dev);
-
-    qdev_init_gpio_in(&dev->qdev, strongarm_ppc_set, 22);
-    qdev_init_gpio_out(&dev->qdev, s->handler, 22);
-
-    memory_region_init_io(&s->iomem, &strongarm_ppc_ops, s, "ppc", 0x1000);
-
-    sysbus_init_mmio(dev, &s->iomem);
-
-    return 0;
-}
-
-static const VMStateDescription vmstate_strongarm_ppc_regs = {
-    .name = "strongarm-ppc",
-    .version_id = 0,
-    .minimum_version_id = 0,
-    .minimum_version_id_old = 0,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT32(ilevel, StrongARMPPCInfo),
-        VMSTATE_UINT32(olevel, StrongARMPPCInfo),
-        VMSTATE_UINT32(dir, StrongARMPPCInfo),
-        VMSTATE_UINT32(ppar, StrongARMPPCInfo),
-        VMSTATE_UINT32(psdr, StrongARMPPCInfo),
-        VMSTATE_UINT32(ppfr, StrongARMPPCInfo),
-        VMSTATE_END_OF_LIST(),
-    },
-};
-
-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 const TypeInfo strongarm_ppc_info = {
-    .name          = "strongarm-ppc",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(StrongARMPPCInfo),
-    .class_init    = strongarm_ppc_class_init,
-};
-
-/* UART Ports */
-#define UTCR0 0x00
-#define UTCR1 0x04
-#define UTCR2 0x08
-#define UTCR3 0x0c
-#define UTDR  0x14
-#define UTSR0 0x1c
-#define UTSR1 0x20
-
-#define UTCR0_PE  (1 << 0) /* Parity enable */
-#define UTCR0_OES (1 << 1) /* Even parity */
-#define UTCR0_SBS (1 << 2) /* 2 stop bits */
-#define UTCR0_DSS (1 << 3) /* 8-bit data */
-
-#define UTCR3_RXE (1 << 0) /* Rx enable */
-#define UTCR3_TXE (1 << 1) /* Tx enable */
-#define UTCR3_BRK (1 << 2) /* Force Break */
-#define UTCR3_RIE (1 << 3) /* Rx int enable */
-#define UTCR3_TIE (1 << 4) /* Tx int enable */
-#define UTCR3_LBM (1 << 5) /* Loopback */
-
-#define UTSR0_TFS (1 << 0) /* Tx FIFO nearly empty */
-#define UTSR0_RFS (1 << 1) /* Rx FIFO nearly full */
-#define UTSR0_RID (1 << 2) /* Receiver Idle */
-#define UTSR0_RBB (1 << 3) /* Receiver begin break */
-#define UTSR0_REB (1 << 4) /* Receiver end break */
-#define UTSR0_EIF (1 << 5) /* Error in FIFO */
-
-#define UTSR1_RNE (1 << 1) /* Receive FIFO not empty */
-#define UTSR1_TNF (1 << 2) /* Transmit FIFO not full */
-#define UTSR1_PRE (1 << 3) /* Parity error */
-#define UTSR1_FRE (1 << 4) /* Frame error */
-#define UTSR1_ROR (1 << 5) /* Receive Over Run */
-
-#define RX_FIFO_PRE (1 << 8)
-#define RX_FIFO_FRE (1 << 9)
-#define RX_FIFO_ROR (1 << 10)
-
-typedef struct {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-    CharDriverState *chr;
-    qemu_irq irq;
-
-    uint8_t utcr0;
-    uint16_t brd;
-    uint8_t utcr3;
-    uint8_t utsr0;
-    uint8_t utsr1;
-
-    uint8_t tx_fifo[8];
-    uint8_t tx_start;
-    uint8_t tx_len;
-    uint16_t rx_fifo[12]; /* value + error flags in high bits */
-    uint8_t rx_start;
-    uint8_t rx_len;
-
-    uint64_t char_transmit_time; /* time to transmit a char in ticks*/
-    bool wait_break_end;
-    QEMUTimer *rx_timeout_timer;
-    QEMUTimer *tx_timer;
-} StrongARMUARTState;
-
-static void strongarm_uart_update_status(StrongARMUARTState *s)
-{
-    uint16_t utsr1 = 0;
-
-    if (s->tx_len != 8) {
-        utsr1 |= UTSR1_TNF;
-    }
-
-    if (s->rx_len != 0) {
-        uint16_t ent = s->rx_fifo[s->rx_start];
-
-        utsr1 |= UTSR1_RNE;
-        if (ent & RX_FIFO_PRE) {
-            s->utsr1 |= UTSR1_PRE;
-        }
-        if (ent & RX_FIFO_FRE) {
-            s->utsr1 |= UTSR1_FRE;
-        }
-        if (ent & RX_FIFO_ROR) {
-            s->utsr1 |= UTSR1_ROR;
-        }
-    }
-
-    s->utsr1 = utsr1;
-}
-
-static void strongarm_uart_update_int_status(StrongARMUARTState *s)
-{
-    uint16_t utsr0 = s->utsr0 &
-            (UTSR0_REB | UTSR0_RBB | UTSR0_RID);
-    int i;
-
-    if ((s->utcr3 & UTCR3_TXE) &&
-                (s->utcr3 & UTCR3_TIE) &&
-                s->tx_len <= 4) {
-        utsr0 |= UTSR0_TFS;
-    }
-
-    if ((s->utcr3 & UTCR3_RXE) &&
-                (s->utcr3 & UTCR3_RIE) &&
-                s->rx_len > 4) {
-        utsr0 |= UTSR0_RFS;
-    }
-
-    for (i = 0; i < s->rx_len && i < 4; i++)
-        if (s->rx_fifo[(s->rx_start + i) % 12] & ~0xff) {
-            utsr0 |= UTSR0_EIF;
-            break;
-        }
-
-    s->utsr0 = utsr0;
-    qemu_set_irq(s->irq, utsr0);
-}
-
-static void strongarm_uart_update_parameters(StrongARMUARTState *s)
-{
-    int speed, parity, data_bits, stop_bits, frame_size;
-    QEMUSerialSetParams ssp;
-
-    /* Start bit. */
-    frame_size = 1;
-    if (s->utcr0 & UTCR0_PE) {
-        /* Parity bit. */
-        frame_size++;
-        if (s->utcr0 & UTCR0_OES) {
-            parity = 'E';
-        } else {
-            parity = 'O';
-        }
-    } else {
-            parity = 'N';
-    }
-    if (s->utcr0 & UTCR0_SBS) {
-        stop_bits = 2;
-    } else {
-        stop_bits = 1;
-    }
-
-    data_bits = (s->utcr0 & UTCR0_DSS) ? 8 : 7;
-    frame_size += data_bits + stop_bits;
-    speed = 3686400 / 16 / (s->brd + 1);
-    ssp.speed = speed;
-    ssp.parity = parity;
-    ssp.data_bits = data_bits;
-    ssp.stop_bits = stop_bits;
-    s->char_transmit_time =  (get_ticks_per_sec() / speed) * frame_size;
-    if (s->chr) {
-        qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
-    }
-
-    DPRINTF(stderr, "%s speed=%d parity=%c data=%d stop=%d\n", s->chr->label,
-            speed, parity, data_bits, stop_bits);
-}
-
-static void strongarm_uart_rx_to(void *opaque)
-{
-    StrongARMUARTState *s = opaque;
-
-    if (s->rx_len) {
-        s->utsr0 |= UTSR0_RID;
-        strongarm_uart_update_int_status(s);
-    }
-}
-
-static void strongarm_uart_rx_push(StrongARMUARTState *s, uint16_t c)
-{
-    if ((s->utcr3 & UTCR3_RXE) == 0) {
-        /* rx disabled */
-        return;
-    }
-
-    if (s->wait_break_end) {
-        s->utsr0 |= UTSR0_REB;
-        s->wait_break_end = false;
-    }
-
-    if (s->rx_len < 12) {
-        s->rx_fifo[(s->rx_start + s->rx_len) % 12] = c;
-        s->rx_len++;
-    } else
-        s->rx_fifo[(s->rx_start + 11) % 12] |= RX_FIFO_ROR;
-}
-
-static int strongarm_uart_can_receive(void *opaque)
-{
-    StrongARMUARTState *s = opaque;
-
-    if (s->rx_len == 12) {
-        return 0;
-    }
-    /* It's best not to get more than 2/3 of RX FIFO, so advertise that much */
-    if (s->rx_len < 8) {
-        return 8 - s->rx_len;
-    }
-    return 1;
-}
-
-static void strongarm_uart_receive(void *opaque, const uint8_t *buf, int size)
-{
-    StrongARMUARTState *s = opaque;
-    int i;
-
-    for (i = 0; i < size; i++) {
-        strongarm_uart_rx_push(s, buf[i]);
-    }
-
-    /* call the timeout receive callback in 3 char transmit time */
-    qemu_mod_timer(s->rx_timeout_timer,
-                    qemu_get_clock_ns(vm_clock) + s->char_transmit_time * 3);
-
-    strongarm_uart_update_status(s);
-    strongarm_uart_update_int_status(s);
-}
-
-static void strongarm_uart_event(void *opaque, int event)
-{
-    StrongARMUARTState *s = opaque;
-    if (event == CHR_EVENT_BREAK) {
-        s->utsr0 |= UTSR0_RBB;
-        strongarm_uart_rx_push(s, RX_FIFO_FRE);
-        s->wait_break_end = true;
-        strongarm_uart_update_status(s);
-        strongarm_uart_update_int_status(s);
-    }
-}
-
-static void strongarm_uart_tx(void *opaque)
-{
-    StrongARMUARTState *s = opaque;
-    uint64_t new_xmit_ts = qemu_get_clock_ns(vm_clock);
-
-    if (s->utcr3 & UTCR3_LBM) /* loopback */ {
-        strongarm_uart_receive(s, &s->tx_fifo[s->tx_start], 1);
-    } else if (s->chr) {
-        qemu_chr_fe_write(s->chr, &s->tx_fifo[s->tx_start], 1);
-    }
-
-    s->tx_start = (s->tx_start + 1) % 8;
-    s->tx_len--;
-    if (s->tx_len) {
-        qemu_mod_timer(s->tx_timer, new_xmit_ts + s->char_transmit_time);
-    }
-    strongarm_uart_update_status(s);
-    strongarm_uart_update_int_status(s);
-}
-
-static uint64_t strongarm_uart_read(void *opaque, hwaddr addr,
-                                    unsigned size)
-{
-    StrongARMUARTState *s = opaque;
-    uint16_t ret;
-
-    switch (addr) {
-    case UTCR0:
-        return s->utcr0;
-
-    case UTCR1:
-        return s->brd >> 8;
-
-    case UTCR2:
-        return s->brd & 0xff;
-
-    case UTCR3:
-        return s->utcr3;
-
-    case UTDR:
-        if (s->rx_len != 0) {
-            ret = s->rx_fifo[s->rx_start];
-            s->rx_start = (s->rx_start + 1) % 12;
-            s->rx_len--;
-            strongarm_uart_update_status(s);
-            strongarm_uart_update_int_status(s);
-            return ret;
-        }
-        return 0;
-
-    case UTSR0:
-        return s->utsr0;
-
-    case UTSR1:
-        return s->utsr1;
-
-    default:
-        printf("%s: Bad register 0x" TARGET_FMT_plx "\n", __func__, addr);
-        return 0;
-    }
-}
-
-static void strongarm_uart_write(void *opaque, hwaddr addr,
-                                 uint64_t value, unsigned size)
-{
-    StrongARMUARTState *s = opaque;
-
-    switch (addr) {
-    case UTCR0:
-        s->utcr0 = value & 0x7f;
-        strongarm_uart_update_parameters(s);
-        break;
-
-    case UTCR1:
-        s->brd = (s->brd & 0xff) | ((value & 0xf) << 8);
-        strongarm_uart_update_parameters(s);
-        break;
-
-    case UTCR2:
-        s->brd = (s->brd & 0xf00) | (value & 0xff);
-        strongarm_uart_update_parameters(s);
-        break;
-
-    case UTCR3:
-        s->utcr3 = value & 0x3f;
-        if ((s->utcr3 & UTCR3_RXE) == 0) {
-            s->rx_len = 0;
-        }
-        if ((s->utcr3 & UTCR3_TXE) == 0) {
-            s->tx_len = 0;
-        }
-        strongarm_uart_update_status(s);
-        strongarm_uart_update_int_status(s);
-        break;
-
-    case UTDR:
-        if ((s->utcr3 & UTCR3_TXE) && s->tx_len != 8) {
-            s->tx_fifo[(s->tx_start + s->tx_len) % 8] = value;
-            s->tx_len++;
-            strongarm_uart_update_status(s);
-            strongarm_uart_update_int_status(s);
-            if (s->tx_len == 1) {
-                strongarm_uart_tx(s);
-            }
-        }
-        break;
-
-    case UTSR0:
-        s->utsr0 = s->utsr0 & ~(value &
-                (UTSR0_REB | UTSR0_RBB | UTSR0_RID));
-        strongarm_uart_update_int_status(s);
-        break;
-
-    default:
-        printf("%s: Bad register 0x" TARGET_FMT_plx "\n", __func__, addr);
-    }
-}
-
-static const MemoryRegionOps strongarm_uart_ops = {
-    .read = strongarm_uart_read,
-    .write = strongarm_uart_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int strongarm_uart_init(SysBusDevice *dev)
-{
-    StrongARMUARTState *s = FROM_SYSBUS(StrongARMUARTState, dev);
-
-    memory_region_init_io(&s->iomem, &strongarm_uart_ops, s, "uart", 0x10000);
-    sysbus_init_mmio(dev, &s->iomem);
-    sysbus_init_irq(dev, &s->irq);
-
-    s->rx_timeout_timer = qemu_new_timer_ns(vm_clock, strongarm_uart_rx_to, s);
-    s->tx_timer = qemu_new_timer_ns(vm_clock, strongarm_uart_tx, s);
-
-    if (s->chr) {
-        qemu_chr_add_handlers(s->chr,
-                        strongarm_uart_can_receive,
-                        strongarm_uart_receive,
-                        strongarm_uart_event,
-                        s);
-    }
-
-    return 0;
-}
-
-static void strongarm_uart_reset(DeviceState *dev)
-{
-    StrongARMUARTState *s = DO_UPCAST(StrongARMUARTState, busdev.qdev, dev);
-
-    s->utcr0 = UTCR0_DSS; /* 8 data, no parity */
-    s->brd = 23;    /* 9600 */
-    /* enable send & recv - this actually violates spec */
-    s->utcr3 = UTCR3_TXE | UTCR3_RXE;
-
-    s->rx_len = s->tx_len = 0;
-
-    strongarm_uart_update_parameters(s);
-    strongarm_uart_update_status(s);
-    strongarm_uart_update_int_status(s);
-}
-
-static int strongarm_uart_post_load(void *opaque, int version_id)
-{
-    StrongARMUARTState *s = opaque;
-
-    strongarm_uart_update_parameters(s);
-    strongarm_uart_update_status(s);
-    strongarm_uart_update_int_status(s);
-
-    /* tx and restart timer */
-    if (s->tx_len) {
-        strongarm_uart_tx(s);
-    }
-
-    /* restart rx timeout timer */
-    if (s->rx_len) {
-        qemu_mod_timer(s->rx_timeout_timer,
-                qemu_get_clock_ns(vm_clock) + s->char_transmit_time * 3);
-    }
-
-    return 0;
-}
-
-static const VMStateDescription vmstate_strongarm_uart_regs = {
-    .name = "strongarm-uart",
-    .version_id = 0,
-    .minimum_version_id = 0,
-    .minimum_version_id_old = 0,
-    .post_load = strongarm_uart_post_load,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT8(utcr0, StrongARMUARTState),
-        VMSTATE_UINT16(brd, StrongARMUARTState),
-        VMSTATE_UINT8(utcr3, StrongARMUARTState),
-        VMSTATE_UINT8(utsr0, StrongARMUARTState),
-        VMSTATE_UINT8_ARRAY(tx_fifo, StrongARMUARTState, 8),
-        VMSTATE_UINT8(tx_start, StrongARMUARTState),
-        VMSTATE_UINT8(tx_len, StrongARMUARTState),
-        VMSTATE_UINT16_ARRAY(rx_fifo, StrongARMUARTState, 12),
-        VMSTATE_UINT8(rx_start, StrongARMUARTState),
-        VMSTATE_UINT8(rx_len, StrongARMUARTState),
-        VMSTATE_BOOL(wait_break_end, StrongARMUARTState),
-        VMSTATE_END_OF_LIST(),
-    },
-};
-
-static Property strongarm_uart_properties[] = {
-    DEFINE_PROP_CHR("chardev", StrongARMUARTState, chr),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void strongarm_uart_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = strongarm_uart_init;
-    dc->desc = "StrongARM UART controller";
-    dc->reset = strongarm_uart_reset;
-    dc->vmsd = &vmstate_strongarm_uart_regs;
-    dc->props = strongarm_uart_properties;
-}
-
-static const 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 */
-typedef struct {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-    qemu_irq irq;
-    SSIBus *bus;
-
-    uint16_t sscr[2];
-    uint16_t sssr;
-
-    uint16_t rx_fifo[8];
-    uint8_t rx_level;
-    uint8_t rx_start;
-} StrongARMSSPState;
-
-#define SSCR0 0x60 /* SSP Control register 0 */
-#define SSCR1 0x64 /* SSP Control register 1 */
-#define SSDR  0x6c /* SSP Data register */
-#define SSSR  0x74 /* SSP Status register */
-
-/* Bitfields for above registers */
-#define SSCR0_SPI(x)    (((x) & 0x30) == 0x00)
-#define SSCR0_SSP(x)    (((x) & 0x30) == 0x10)
-#define SSCR0_UWIRE(x)  (((x) & 0x30) == 0x20)
-#define SSCR0_PSP(x)    (((x) & 0x30) == 0x30)
-#define SSCR0_SSE       (1 << 7)
-#define SSCR0_DSS(x)    (((x) & 0xf) + 1)
-#define SSCR1_RIE       (1 << 0)
-#define SSCR1_TIE       (1 << 1)
-#define SSCR1_LBM       (1 << 2)
-#define SSSR_TNF        (1 << 2)
-#define SSSR_RNE        (1 << 3)
-#define SSSR_TFS        (1 << 5)
-#define SSSR_RFS        (1 << 6)
-#define SSSR_ROR        (1 << 7)
-#define SSSR_RW         0x0080
-
-static void strongarm_ssp_int_update(StrongARMSSPState *s)
-{
-    int level = 0;
-
-    level |= (s->sssr & SSSR_ROR);
-    level |= (s->sssr & SSSR_RFS)  &&  (s->sscr[1] & SSCR1_RIE);
-    level |= (s->sssr & SSSR_TFS)  &&  (s->sscr[1] & SSCR1_TIE);
-    qemu_set_irq(s->irq, level);
-}
-
-static void strongarm_ssp_fifo_update(StrongARMSSPState *s)
-{
-    s->sssr &= ~SSSR_TFS;
-    s->sssr &= ~SSSR_TNF;
-    if (s->sscr[0] & SSCR0_SSE) {
-        if (s->rx_level >= 4) {
-            s->sssr |= SSSR_RFS;
-        } else {
-            s->sssr &= ~SSSR_RFS;
-        }
-        if (s->rx_level) {
-            s->sssr |= SSSR_RNE;
-        } else {
-            s->sssr &= ~SSSR_RNE;
-        }
-        /* TX FIFO is never filled, so it is always in underrun
-           condition if SSP is enabled */
-        s->sssr |= SSSR_TFS;
-        s->sssr |= SSSR_TNF;
-    }
-
-    strongarm_ssp_int_update(s);
-}
-
-static uint64_t strongarm_ssp_read(void *opaque, hwaddr addr,
-                                   unsigned size)
-{
-    StrongARMSSPState *s = opaque;
-    uint32_t retval;
-
-    switch (addr) {
-    case SSCR0:
-        return s->sscr[0];
-    case SSCR1:
-        return s->sscr[1];
-    case SSSR:
-        return s->sssr;
-    case SSDR:
-        if (~s->sscr[0] & SSCR0_SSE) {
-            return 0xffffffff;
-        }
-        if (s->rx_level < 1) {
-            printf("%s: SSP Rx Underrun\n", __func__);
-            return 0xffffffff;
-        }
-        s->rx_level--;
-        retval = s->rx_fifo[s->rx_start++];
-        s->rx_start &= 0x7;
-        strongarm_ssp_fifo_update(s);
-        return retval;
-    default:
-        printf("%s: Bad register 0x" TARGET_FMT_plx "\n", __func__, addr);
-        break;
-    }
-    return 0;
-}
-
-static void strongarm_ssp_write(void *opaque, hwaddr addr,
-                                uint64_t value, unsigned size)
-{
-    StrongARMSSPState *s = opaque;
-
-    switch (addr) {
-    case SSCR0:
-        s->sscr[0] = value & 0xffbf;
-        if ((s->sscr[0] & SSCR0_SSE) && SSCR0_DSS(value) < 4) {
-            printf("%s: Wrong data size: %i bits\n", __func__,
-                   (int)SSCR0_DSS(value));
-        }
-        if (!(value & SSCR0_SSE)) {
-            s->sssr = 0;
-            s->rx_level = 0;
-        }
-        strongarm_ssp_fifo_update(s);
-        break;
-
-    case SSCR1:
-        s->sscr[1] = value & 0x2f;
-        if (value & SSCR1_LBM) {
-            printf("%s: Attempt to use SSP LBM mode\n", __func__);
-        }
-        strongarm_ssp_fifo_update(s);
-        break;
-
-    case SSSR:
-        s->sssr &= ~(value & SSSR_RW);
-        strongarm_ssp_int_update(s);
-        break;
-
-    case SSDR:
-        if (SSCR0_UWIRE(s->sscr[0])) {
-            value &= 0xff;
-        } else
-            /* Note how 32bits overflow does no harm here */
-            value &= (1 << SSCR0_DSS(s->sscr[0])) - 1;
-
-        /* Data goes from here to the Tx FIFO and is shifted out from
-         * there directly to the slave, no need to buffer it.
-         */
-        if (s->sscr[0] & SSCR0_SSE) {
-            uint32_t readval;
-            if (s->sscr[1] & SSCR1_LBM) {
-                readval = value;
-            } else {
-                readval = ssi_transfer(s->bus, value);
-            }
-
-            if (s->rx_level < 0x08) {
-                s->rx_fifo[(s->rx_start + s->rx_level++) & 0x7] = readval;
-            } else {
-                s->sssr |= SSSR_ROR;
-            }
-        }
-        strongarm_ssp_fifo_update(s);
-        break;
-
-    default:
-        printf("%s: Bad register 0x" TARGET_FMT_plx "\n", __func__, addr);
-        break;
-    }
-}
-
-static const MemoryRegionOps strongarm_ssp_ops = {
-    .read = strongarm_ssp_read,
-    .write = strongarm_ssp_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int strongarm_ssp_post_load(void *opaque, int version_id)
-{
-    StrongARMSSPState *s = opaque;
-
-    strongarm_ssp_fifo_update(s);
-
-    return 0;
-}
-
-static int strongarm_ssp_init(SysBusDevice *dev)
-{
-    StrongARMSSPState *s = FROM_SYSBUS(StrongARMSSPState, dev);
-
-    sysbus_init_irq(dev, &s->irq);
-
-    memory_region_init_io(&s->iomem, &strongarm_ssp_ops, s, "ssp", 0x1000);
-    sysbus_init_mmio(dev, &s->iomem);
-
-    s->bus = ssi_create_bus(&dev->qdev, "ssi");
-    return 0;
-}
-
-static void strongarm_ssp_reset(DeviceState *dev)
-{
-    StrongARMSSPState *s = DO_UPCAST(StrongARMSSPState, busdev.qdev, dev);
-    s->sssr = 0x03; /* 3 bit data, SPI, disabled */
-    s->rx_start = 0;
-    s->rx_level = 0;
-}
-
-static const VMStateDescription vmstate_strongarm_ssp_regs = {
-    .name = "strongarm-ssp",
-    .version_id = 0,
-    .minimum_version_id = 0,
-    .minimum_version_id_old = 0,
-    .post_load = strongarm_ssp_post_load,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT16_ARRAY(sscr, StrongARMSSPState, 2),
-        VMSTATE_UINT16(sssr, StrongARMSSPState),
-        VMSTATE_UINT16_ARRAY(rx_fifo, StrongARMSSPState, 8),
-        VMSTATE_UINT8(rx_start, StrongARMSSPState),
-        VMSTATE_UINT8(rx_level, StrongARMSSPState),
-        VMSTATE_END_OF_LIST(),
-    },
-};
-
-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 const 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 */
-StrongARMState *sa1110_init(MemoryRegion *sysmem,
-                            unsigned int sdram_size, const char *rev)
-{
-    StrongARMState *s;
-    qemu_irq *pic;
-    int i;
-
-    s = g_malloc0(sizeof(StrongARMState));
-
-    if (!rev) {
-        rev = "sa1110-b5";
-    }
-
-    if (strncmp(rev, "sa1110", 6)) {
-        error_report("Machine requires a SA1110 processor.");
-        exit(1);
-    }
-
-    s->cpu = cpu_arm_init(rev);
-
-    if (!s->cpu) {
-        error_report("Unable to find CPU definition");
-        exit(1);
-    }
-
-    memory_region_init_ram(&s->sdram, "strongarm.sdram", sdram_size);
-    vmstate_register_ram_global(&s->sdram);
-    memory_region_add_subregion(sysmem, SA_SDCS0, &s->sdram);
-
-    pic = arm_pic_init_cpu(s->cpu);
-    s->pic = sysbus_create_varargs("strongarm_pic", 0x90050000,
-                    pic[ARM_PIC_CPU_IRQ], pic[ARM_PIC_CPU_FIQ], NULL);
-
-    sysbus_create_varargs("pxa25x-timer", 0x90000000,
-                    qdev_get_gpio_in(s->pic, SA_PIC_OSTC0),
-                    qdev_get_gpio_in(s->pic, SA_PIC_OSTC1),
-                    qdev_get_gpio_in(s->pic, SA_PIC_OSTC2),
-                    qdev_get_gpio_in(s->pic, SA_PIC_OSTC3),
-                    NULL);
-
-    sysbus_create_simple("strongarm-rtc", 0x90010000,
-                    qdev_get_gpio_in(s->pic, SA_PIC_RTC_ALARM));
-
-    s->gpio = strongarm_gpio_init(0x90040000, s->pic);
-
-    s->ppc = sysbus_create_varargs("strongarm-ppc", 0x90060000, NULL);
-
-    for (i = 0; sa_serial[i].io_base; i++) {
-        DeviceState *dev = qdev_create(NULL, "strongarm-uart");
-        qdev_prop_set_chr(dev, "chardev", serial_hds[i]);
-        qdev_init_nofail(dev);
-        sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0,
-                sa_serial[i].io_base);
-        sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0,
-                qdev_get_gpio_in(s->pic, sa_serial[i].irq));
-    }
-
-    s->ssp = sysbus_create_varargs("strongarm-ssp", 0x80070000,
-                qdev_get_gpio_in(s->pic, SA_PIC_SSP), NULL);
-    s->ssp_bus = (SSIBus *)qdev_get_child_bus(s->ssp, "ssi");
-
-    return s;
-}
-
-static void strongarm_register_types(void)
-{
-    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);
-}
-
-type_init(strongarm_register_types)
diff --git a/hw/strongarm.h b/hw/strongarm.h
deleted file mode 100644 (file)
index 2893f94..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-#ifndef _STRONGARM_H
-#define _STRONGARM_H
-
-#include "exec/memory.h"
-
-#define SA_CS0          0x00000000
-#define SA_CS1          0x08000000
-#define SA_CS2          0x10000000
-#define SA_CS3          0x18000000
-#define SA_PCMCIA_CS0   0x20000000
-#define SA_PCMCIA_CS1   0x30000000
-#define SA_CS4          0x40000000
-#define SA_CS5          0x48000000
-/* system registers here */
-#define SA_SDCS0        0xc0000000
-#define SA_SDCS1        0xc8000000
-#define SA_SDCS2        0xd0000000
-#define SA_SDCS3        0xd8000000
-
-enum {
-    SA_PIC_GPIO0_EDGE = 0,
-    SA_PIC_GPIO1_EDGE,
-    SA_PIC_GPIO2_EDGE,
-    SA_PIC_GPIO3_EDGE,
-    SA_PIC_GPIO4_EDGE,
-    SA_PIC_GPIO5_EDGE,
-    SA_PIC_GPIO6_EDGE,
-    SA_PIC_GPIO7_EDGE,
-    SA_PIC_GPIO8_EDGE,
-    SA_PIC_GPIO9_EDGE,
-    SA_PIC_GPIO10_EDGE,
-    SA_PIC_GPIOX_EDGE,
-    SA_PIC_LCD,
-    SA_PIC_UDC,
-    SA_PIC_RSVD1,
-    SA_PIC_UART1,
-    SA_PIC_UART2,
-    SA_PIC_UART3,
-    SA_PIC_MCP,
-    SA_PIC_SSP,
-    SA_PIC_DMA_CH0,
-    SA_PIC_DMA_CH1,
-    SA_PIC_DMA_CH2,
-    SA_PIC_DMA_CH3,
-    SA_PIC_DMA_CH4,
-    SA_PIC_DMA_CH5,
-    SA_PIC_OSTC0,
-    SA_PIC_OSTC1,
-    SA_PIC_OSTC2,
-    SA_PIC_OSTC3,
-    SA_PIC_RTC_HZ,
-    SA_PIC_RTC_ALARM,
-};
-
-typedef struct {
-    ARMCPU *cpu;
-    MemoryRegion sdram;
-    DeviceState *pic;
-    DeviceState *gpio;
-    DeviceState *ppc;
-    DeviceState *ssp;
-    SSIBus *ssp_bus;
-} StrongARMState;
-
-StrongARMState *sa1110_init(MemoryRegion *sysmem,
-                            unsigned int sdram_size, const char *rev);
-
-#endif
diff --git a/hw/sun4c_intctl.c b/hw/sun4c_intctl.c
deleted file mode 100644 (file)
index 9d443d1..0000000
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
- * QEMU Sparc Sun4c interrupt controller emulation
- *
- * Based on slavio_intctl, copyright (c) 2003-2005 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.
- */
-
-#include "hw/hw.h"
-#include "hw/sun4m.h"
-#include "monitor/monitor.h"
-#include "hw/sysbus.h"
-
-//#define DEBUG_IRQ_COUNT
-//#define DEBUG_IRQ
-
-#ifdef DEBUG_IRQ
-#define DPRINTF(fmt, ...)                                       \
-    do { printf("IRQ: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...)
-#endif
-
-/*
- * Registers of interrupt controller in sun4c.
- *
- */
-
-#define MAX_PILS 16
-
-typedef struct Sun4c_INTCTLState {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-#ifdef DEBUG_IRQ_COUNT
-    uint64_t irq_count;
-#endif
-    qemu_irq cpu_irqs[MAX_PILS];
-    const uint32_t *intbit_to_level;
-    uint32_t pil_out;
-    uint8_t reg;
-    uint8_t pending;
-} Sun4c_INTCTLState;
-
-#define INTCTL_SIZE 1
-
-static void sun4c_check_interrupts(void *opaque);
-
-static uint64_t sun4c_intctl_mem_read(void *opaque, hwaddr addr,
-                                      unsigned size)
-{
-    Sun4c_INTCTLState *s = opaque;
-    uint32_t ret;
-
-    ret = s->reg;
-    DPRINTF("read reg 0x" TARGET_FMT_plx " = %x\n", addr, ret);
-
-    return ret;
-}
-
-static void sun4c_intctl_mem_write(void *opaque, hwaddr addr,
-                                   uint64_t val, unsigned size)
-{
-    Sun4c_INTCTLState *s = opaque;
-
-    DPRINTF("write reg 0x" TARGET_FMT_plx " = %x\n", addr, (unsigned)val);
-    val &= 0xbf;
-    s->reg = val;
-    sun4c_check_interrupts(s);
-}
-
-static const MemoryRegionOps sun4c_intctl_mem_ops = {
-    .read = sun4c_intctl_mem_read,
-    .write = sun4c_intctl_mem_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid = {
-        .min_access_size = 1,
-        .max_access_size = 1,
-    },
-};
-
-static const uint32_t intbit_to_level[] = { 0, 1, 4, 6, 8, 10, 0, 14, };
-
-static void sun4c_check_interrupts(void *opaque)
-{
-    Sun4c_INTCTLState *s = opaque;
-    uint32_t pil_pending;
-    unsigned int i;
-
-    pil_pending = 0;
-    if (s->pending && !(s->reg & 0x80000000)) {
-        for (i = 0; i < 8; i++) {
-            if (s->pending & (1 << i))
-                pil_pending |= 1 << intbit_to_level[i];
-        }
-    }
-
-    for (i = 0; i < MAX_PILS; i++) {
-        if (pil_pending & (1 << i)) {
-            if (!(s->pil_out & (1 << i)))
-                qemu_irq_raise(s->cpu_irqs[i]);
-        } else {
-            if (s->pil_out & (1 << i))
-                qemu_irq_lower(s->cpu_irqs[i]);
-        }
-    }
-    s->pil_out = pil_pending;
-}
-
-/*
- * "irq" here is the bit number in the system interrupt register
- */
-static void sun4c_set_irq(void *opaque, int irq, int level)
-{
-    Sun4c_INTCTLState *s = opaque;
-    uint32_t mask = 1 << irq;
-    uint32_t pil = intbit_to_level[irq];
-
-    DPRINTF("Set irq %d -> pil %d level %d\n", irq, pil,
-            level);
-    if (pil > 0) {
-        if (level) {
-#ifdef DEBUG_IRQ_COUNT
-            s->irq_count++;
-#endif
-            s->pending |= mask;
-        } else {
-            s->pending &= ~mask;
-        }
-        sun4c_check_interrupts(s);
-    }
-}
-
-static const VMStateDescription vmstate_sun4c_intctl = {
-    .name ="sun4c_intctl",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField []) {
-        VMSTATE_UINT8(reg, Sun4c_INTCTLState),
-        VMSTATE_UINT8(pending, Sun4c_INTCTLState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void sun4c_intctl_reset(DeviceState *d)
-{
-    Sun4c_INTCTLState *s = container_of(d, Sun4c_INTCTLState, busdev.qdev);
-
-    s->reg = 1;
-    s->pending = 0;
-}
-
-static int sun4c_intctl_init1(SysBusDevice *dev)
-{
-    Sun4c_INTCTLState *s = FROM_SYSBUS(Sun4c_INTCTLState, dev);
-    unsigned int i;
-
-    memory_region_init_io(&s->iomem, &sun4c_intctl_mem_ops, s,
-                          "intctl", INTCTL_SIZE);
-    sysbus_init_mmio(dev, &s->iomem);
-    qdev_init_gpio_in(&dev->qdev, sun4c_set_irq, 8);
-
-    for (i = 0; i < MAX_PILS; i++) {
-        sysbus_init_irq(dev, &s->cpu_irqs[i]);
-    }
-
-    return 0;
-}
-
-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 const 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_types(void)
-{
-    type_register_static(&sun4c_intctl_info);
-}
-
-type_init(sun4c_intctl_register_types)
diff --git a/hw/sun4m.h b/hw/sun4m.h
deleted file mode 100644 (file)
index 0d2cfb8..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-#ifndef SUN4M_H
-#define SUN4M_H
-
-#include "qemu-common.h"
-
-/* Devices used by sparc32 system.  */
-
-/* iommu.c */
-void sparc_iommu_memory_rw(void *opaque, hwaddr addr,
-                                 uint8_t *buf, int len, int is_write);
-static inline void sparc_iommu_memory_read(void *opaque,
-                                           hwaddr addr,
-                                           uint8_t *buf, int len)
-{
-    sparc_iommu_memory_rw(opaque, addr, buf, len, 0);
-}
-
-static inline void sparc_iommu_memory_write(void *opaque,
-                                            hwaddr addr,
-                                            uint8_t *buf, int len)
-{
-    sparc_iommu_memory_rw(opaque, addr, buf, len, 1);
-}
-
-/* slavio_intctl.c */
-void slavio_pic_info(Monitor *mon, DeviceState *dev);
-void slavio_irq_info(Monitor *mon, DeviceState *dev);
-
-/* sun4m.c */
-void sun4m_pic_info(Monitor *mon, const QDict *qdict);
-void sun4m_irq_info(Monitor *mon, const QDict *qdict);
-
-/* sparc32_dma.c */
-#include "hw/sparc32_dma.h"
-
-#endif
diff --git a/hw/sun4m_iommu.c b/hw/sun4m_iommu.c
deleted file mode 100644 (file)
index 33e77b0..0000000
+++ /dev/null
@@ -1,388 +0,0 @@
-/*
- * QEMU Sun4m iommu emulation
- *
- * Copyright (c) 2003-2005 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.
- */
-
-#include "hw/sun4m.h"
-#include "hw/sysbus.h"
-#include "trace.h"
-
-/*
- * I/O MMU used by Sun4m systems
- *
- * Chipset docs:
- * "Sun-4M System Architecture (revision 2.0) by Chuck Narad", 950-1373-01,
- * http://mediacast.sun.com/users/Barton808/media/Sun4M_SystemArchitecture_edited2.pdf
- */
-
-#define IOMMU_NREGS         (4*4096/4)
-#define IOMMU_CTRL          (0x0000 >> 2)
-#define IOMMU_CTRL_IMPL     0xf0000000 /* Implementation */
-#define IOMMU_CTRL_VERS     0x0f000000 /* Version */
-#define IOMMU_CTRL_RNGE     0x0000001c /* Mapping RANGE */
-#define IOMMU_RNGE_16MB     0x00000000 /* 0xff000000 -> 0xffffffff */
-#define IOMMU_RNGE_32MB     0x00000004 /* 0xfe000000 -> 0xffffffff */
-#define IOMMU_RNGE_64MB     0x00000008 /* 0xfc000000 -> 0xffffffff */
-#define IOMMU_RNGE_128MB    0x0000000c /* 0xf8000000 -> 0xffffffff */
-#define IOMMU_RNGE_256MB    0x00000010 /* 0xf0000000 -> 0xffffffff */
-#define IOMMU_RNGE_512MB    0x00000014 /* 0xe0000000 -> 0xffffffff */
-#define IOMMU_RNGE_1GB      0x00000018 /* 0xc0000000 -> 0xffffffff */
-#define IOMMU_RNGE_2GB      0x0000001c /* 0x80000000 -> 0xffffffff */
-#define IOMMU_CTRL_ENAB     0x00000001 /* IOMMU Enable */
-#define IOMMU_CTRL_MASK     0x0000001d
-
-#define IOMMU_BASE          (0x0004 >> 2)
-#define IOMMU_BASE_MASK     0x07fffc00
-
-#define IOMMU_TLBFLUSH      (0x0014 >> 2)
-#define IOMMU_TLBFLUSH_MASK 0xffffffff
-
-#define IOMMU_PGFLUSH       (0x0018 >> 2)
-#define IOMMU_PGFLUSH_MASK  0xffffffff
-
-#define IOMMU_AFSR          (0x1000 >> 2)
-#define IOMMU_AFSR_ERR      0x80000000 /* LE, TO, or BE asserted */
-#define IOMMU_AFSR_LE       0x40000000 /* SBUS reports error after
-                                          transaction */
-#define IOMMU_AFSR_TO       0x20000000 /* Write access took more than
-                                          12.8 us. */
-#define IOMMU_AFSR_BE       0x10000000 /* Write access received error
-                                          acknowledge */
-#define IOMMU_AFSR_SIZE     0x0e000000 /* Size of transaction causing error */
-#define IOMMU_AFSR_S        0x01000000 /* Sparc was in supervisor mode */
-#define IOMMU_AFSR_RESV     0x00800000 /* Reserved, forced to 0x8 by
-                                          hardware */
-#define IOMMU_AFSR_ME       0x00080000 /* Multiple errors occurred */
-#define IOMMU_AFSR_RD       0x00040000 /* A read operation was in progress */
-#define IOMMU_AFSR_FAV      0x00020000 /* IOMMU afar has valid contents */
-#define IOMMU_AFSR_MASK     0xff0fffff
-
-#define IOMMU_AFAR          (0x1004 >> 2)
-
-#define IOMMU_AER           (0x1008 >> 2) /* Arbiter Enable Register */
-#define IOMMU_AER_EN_P0_ARB 0x00000001    /* MBus master 0x8 (Always 1) */
-#define IOMMU_AER_EN_P1_ARB 0x00000002    /* MBus master 0x9 */
-#define IOMMU_AER_EN_P2_ARB 0x00000004    /* MBus master 0xa */
-#define IOMMU_AER_EN_P3_ARB 0x00000008    /* MBus master 0xb */
-#define IOMMU_AER_EN_0      0x00010000    /* SBus slot 0 */
-#define IOMMU_AER_EN_1      0x00020000    /* SBus slot 1 */
-#define IOMMU_AER_EN_2      0x00040000    /* SBus slot 2 */
-#define IOMMU_AER_EN_3      0x00080000    /* SBus slot 3 */
-#define IOMMU_AER_EN_F      0x00100000    /* SBus on-board */
-#define IOMMU_AER_SBW       0x80000000    /* S-to-M asynchronous writes */
-#define IOMMU_AER_MASK      0x801f000f
-
-#define IOMMU_SBCFG0        (0x1010 >> 2) /* SBUS configration per-slot */
-#define IOMMU_SBCFG1        (0x1014 >> 2) /* SBUS configration per-slot */
-#define IOMMU_SBCFG2        (0x1018 >> 2) /* SBUS configration per-slot */
-#define IOMMU_SBCFG3        (0x101c >> 2) /* SBUS configration per-slot */
-#define IOMMU_SBCFG_SAB30   0x00010000 /* Phys-address bit 30 when
-                                          bypass enabled */
-#define IOMMU_SBCFG_BA16    0x00000004 /* Slave supports 16 byte bursts */
-#define IOMMU_SBCFG_BA8     0x00000002 /* Slave supports 8 byte bursts */
-#define IOMMU_SBCFG_BYPASS  0x00000001 /* Bypass IOMMU, treat all addresses
-                                          produced by this device as pure
-                                          physical. */
-#define IOMMU_SBCFG_MASK    0x00010003
-
-#define IOMMU_ARBEN         (0x2000 >> 2) /* SBUS arbitration enable */
-#define IOMMU_ARBEN_MASK    0x001f0000
-#define IOMMU_MID           0x00000008
-
-#define IOMMU_MASK_ID       (0x3018 >> 2) /* Mask ID */
-#define IOMMU_MASK_ID_MASK  0x00ffffff
-
-#define IOMMU_MSII_MASK     0x26000000 /* microSPARC II mask number */
-#define IOMMU_TS_MASK       0x23000000 /* turboSPARC mask number */
-
-/* The format of an iopte in the page tables */
-#define IOPTE_PAGE          0xffffff00 /* Physical page number (PA[35:12]) */
-#define IOPTE_CACHE         0x00000080 /* Cached (in vme IOCACHE or
-                                          Viking/MXCC) */
-#define IOPTE_WRITE         0x00000004 /* Writable */
-#define IOPTE_VALID         0x00000002 /* IOPTE is valid */
-#define IOPTE_WAZ           0x00000001 /* Write as zeros */
-
-#define IOMMU_PAGE_SHIFT    12
-#define IOMMU_PAGE_SIZE     (1 << IOMMU_PAGE_SHIFT)
-#define IOMMU_PAGE_MASK     ~(IOMMU_PAGE_SIZE - 1)
-
-typedef struct IOMMUState {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-    uint32_t regs[IOMMU_NREGS];
-    hwaddr iostart;
-    qemu_irq irq;
-    uint32_t version;
-} IOMMUState;
-
-static uint64_t iommu_mem_read(void *opaque, hwaddr addr,
-                               unsigned size)
-{
-    IOMMUState *s = opaque;
-    hwaddr saddr;
-    uint32_t ret;
-
-    saddr = addr >> 2;
-    switch (saddr) {
-    default:
-        ret = s->regs[saddr];
-        break;
-    case IOMMU_AFAR:
-    case IOMMU_AFSR:
-        ret = s->regs[saddr];
-        qemu_irq_lower(s->irq);
-        break;
-    }
-    trace_sun4m_iommu_mem_readl(saddr, ret);
-    return ret;
-}
-
-static void iommu_mem_write(void *opaque, hwaddr addr,
-                            uint64_t val, unsigned size)
-{
-    IOMMUState *s = opaque;
-    hwaddr saddr;
-
-    saddr = addr >> 2;
-    trace_sun4m_iommu_mem_writel(saddr, val);
-    switch (saddr) {
-    case IOMMU_CTRL:
-        switch (val & IOMMU_CTRL_RNGE) {
-        case IOMMU_RNGE_16MB:
-            s->iostart = 0xffffffffff000000ULL;
-            break;
-        case IOMMU_RNGE_32MB:
-            s->iostart = 0xfffffffffe000000ULL;
-            break;
-        case IOMMU_RNGE_64MB:
-            s->iostart = 0xfffffffffc000000ULL;
-            break;
-        case IOMMU_RNGE_128MB:
-            s->iostart = 0xfffffffff8000000ULL;
-            break;
-        case IOMMU_RNGE_256MB:
-            s->iostart = 0xfffffffff0000000ULL;
-            break;
-        case IOMMU_RNGE_512MB:
-            s->iostart = 0xffffffffe0000000ULL;
-            break;
-        case IOMMU_RNGE_1GB:
-            s->iostart = 0xffffffffc0000000ULL;
-            break;
-        default:
-        case IOMMU_RNGE_2GB:
-            s->iostart = 0xffffffff80000000ULL;
-            break;
-        }
-        trace_sun4m_iommu_mem_writel_ctrl(s->iostart);
-        s->regs[saddr] = ((val & IOMMU_CTRL_MASK) | s->version);
-        break;
-    case IOMMU_BASE:
-        s->regs[saddr] = val & IOMMU_BASE_MASK;
-        break;
-    case IOMMU_TLBFLUSH:
-        trace_sun4m_iommu_mem_writel_tlbflush(val);
-        s->regs[saddr] = val & IOMMU_TLBFLUSH_MASK;
-        break;
-    case IOMMU_PGFLUSH:
-        trace_sun4m_iommu_mem_writel_pgflush(val);
-        s->regs[saddr] = val & IOMMU_PGFLUSH_MASK;
-        break;
-    case IOMMU_AFAR:
-        s->regs[saddr] = val;
-        qemu_irq_lower(s->irq);
-        break;
-    case IOMMU_AER:
-        s->regs[saddr] = (val & IOMMU_AER_MASK) | IOMMU_AER_EN_P0_ARB;
-        break;
-    case IOMMU_AFSR:
-        s->regs[saddr] = (val & IOMMU_AFSR_MASK) | IOMMU_AFSR_RESV;
-        qemu_irq_lower(s->irq);
-        break;
-    case IOMMU_SBCFG0:
-    case IOMMU_SBCFG1:
-    case IOMMU_SBCFG2:
-    case IOMMU_SBCFG3:
-        s->regs[saddr] = val & IOMMU_SBCFG_MASK;
-        break;
-    case IOMMU_ARBEN:
-        // XXX implement SBus probing: fault when reading unmapped
-        // addresses, fault cause and address stored to MMU/IOMMU
-        s->regs[saddr] = (val & IOMMU_ARBEN_MASK) | IOMMU_MID;
-        break;
-    case IOMMU_MASK_ID:
-        s->regs[saddr] |= val & IOMMU_MASK_ID_MASK;
-        break;
-    default:
-        s->regs[saddr] = val;
-        break;
-    }
-}
-
-static const MemoryRegionOps iommu_mem_ops = {
-    .read = iommu_mem_read,
-    .write = iommu_mem_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-};
-
-static uint32_t iommu_page_get_flags(IOMMUState *s, hwaddr addr)
-{
-    uint32_t ret;
-    hwaddr iopte;
-    hwaddr pa = addr;
-
-    iopte = s->regs[IOMMU_BASE] << 4;
-    addr &= ~s->iostart;
-    iopte += (addr >> (IOMMU_PAGE_SHIFT - 2)) & ~3;
-    cpu_physical_memory_read(iopte, (uint8_t *)&ret, 4);
-    tswap32s(&ret);
-    trace_sun4m_iommu_page_get_flags(pa, iopte, ret);
-    return ret;
-}
-
-static hwaddr iommu_translate_pa(hwaddr addr,
-                                             uint32_t pte)
-{
-    hwaddr pa;
-
-    pa = ((pte & IOPTE_PAGE) << 4) + (addr & ~IOMMU_PAGE_MASK);
-    trace_sun4m_iommu_translate_pa(addr, pa, pte);
-    return pa;
-}
-
-static void iommu_bad_addr(IOMMUState *s, hwaddr addr,
-                           int is_write)
-{
-    trace_sun4m_iommu_bad_addr(addr);
-    s->regs[IOMMU_AFSR] = IOMMU_AFSR_ERR | IOMMU_AFSR_LE | IOMMU_AFSR_RESV |
-        IOMMU_AFSR_FAV;
-    if (!is_write)
-        s->regs[IOMMU_AFSR] |= IOMMU_AFSR_RD;
-    s->regs[IOMMU_AFAR] = addr;
-    qemu_irq_raise(s->irq);
-}
-
-void sparc_iommu_memory_rw(void *opaque, hwaddr addr,
-                           uint8_t *buf, int len, int is_write)
-{
-    int l;
-    uint32_t flags;
-    hwaddr page, phys_addr;
-
-    while (len > 0) {
-        page = addr & IOMMU_PAGE_MASK;
-        l = (page + IOMMU_PAGE_SIZE) - addr;
-        if (l > len)
-            l = len;
-        flags = iommu_page_get_flags(opaque, page);
-        if (!(flags & IOPTE_VALID)) {
-            iommu_bad_addr(opaque, page, is_write);
-            return;
-        }
-        phys_addr = iommu_translate_pa(addr, flags);
-        if (is_write) {
-            if (!(flags & IOPTE_WRITE)) {
-                iommu_bad_addr(opaque, page, is_write);
-                return;
-            }
-            cpu_physical_memory_write(phys_addr, buf, l);
-        } else {
-            cpu_physical_memory_read(phys_addr, buf, l);
-        }
-        len -= l;
-        buf += l;
-        addr += l;
-    }
-}
-
-static const VMStateDescription vmstate_iommu = {
-    .name ="iommu",
-    .version_id = 2,
-    .minimum_version_id = 2,
-    .minimum_version_id_old = 2,
-    .fields      = (VMStateField []) {
-        VMSTATE_UINT32_ARRAY(regs, IOMMUState, IOMMU_NREGS),
-        VMSTATE_UINT64(iostart, IOMMUState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void iommu_reset(DeviceState *d)
-{
-    IOMMUState *s = container_of(d, IOMMUState, busdev.qdev);
-
-    memset(s->regs, 0, IOMMU_NREGS * 4);
-    s->iostart = 0;
-    s->regs[IOMMU_CTRL] = s->version;
-    s->regs[IOMMU_ARBEN] = IOMMU_MID;
-    s->regs[IOMMU_AFSR] = IOMMU_AFSR_RESV;
-    s->regs[IOMMU_AER] = IOMMU_AER_EN_P0_ARB | IOMMU_AER_EN_P1_ARB;
-    s->regs[IOMMU_MASK_ID] = IOMMU_TS_MASK;
-}
-
-static int iommu_init1(SysBusDevice *dev)
-{
-    IOMMUState *s = FROM_SYSBUS(IOMMUState, dev);
-
-    sysbus_init_irq(dev, &s->irq);
-
-    memory_region_init_io(&s->iomem, &iommu_mem_ops, s, "iommu",
-                          IOMMU_NREGS * sizeof(uint32_t));
-    sysbus_init_mmio(dev, &s->iomem);
-
-    return 0;
-}
-
-static Property iommu_properties[] = {
-    DEFINE_PROP_HEX32("version", IOMMUState, version, 0),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void iommu_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = iommu_init1;
-    dc->reset = iommu_reset;
-    dc->vmsd = &vmstate_iommu;
-    dc->props = iommu_properties;
-}
-
-static const TypeInfo iommu_info = {
-    .name          = "iommu",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(IOMMUState),
-    .class_init    = iommu_class_init,
-};
-
-static void iommu_register_types(void)
-{
-    type_register_static(&iommu_info);
-}
-
-type_init(iommu_register_types)
diff --git a/hw/sysbus.c b/hw/sysbus.c
deleted file mode 100644 (file)
index 9004d8c..0000000
+++ /dev/null
@@ -1,301 +0,0 @@
-/*
- *  System (CPU) Bus device support code
- *
- *  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 "hw/sysbus.h"
-#include "monitor/monitor.h"
-#include "exec/address-spaces.h"
-
-static void sysbus_dev_print(Monitor *mon, DeviceState *dev, int indent);
-static char *sysbus_get_fw_dev_path(DeviceState *dev);
-
-static void system_bus_class_init(ObjectClass *klass, void *data)
-{
-    BusClass *k = BUS_CLASS(klass);
-
-    k->print_dev = sysbus_dev_print;
-    k->get_fw_dev_path = sysbus_get_fw_dev_path;
-}
-
-static const TypeInfo system_bus_info = {
-    .name = TYPE_SYSTEM_BUS,
-    .parent = TYPE_BUS,
-    .instance_size = sizeof(BusState),
-    .class_init = system_bus_class_init,
-};
-
-void sysbus_connect_irq(SysBusDevice *dev, int n, qemu_irq irq)
-{
-    assert(n >= 0 && n < dev->num_irq);
-    dev->irqs[n] = NULL;
-    if (dev->irqp[n]) {
-        *dev->irqp[n] = irq;
-    }
-}
-
-static void sysbus_mmio_map_common(SysBusDevice *dev, int n, hwaddr addr,
-                                   bool may_overlap, unsigned priority)
-{
-    assert(n >= 0 && n < dev->num_mmio);
-
-    if (dev->mmio[n].addr == addr) {
-        /* ??? region already mapped here.  */
-        return;
-    }
-    if (dev->mmio[n].addr != (hwaddr)-1) {
-        /* Unregister previous mapping.  */
-        memory_region_del_subregion(get_system_memory(), dev->mmio[n].memory);
-    }
-    dev->mmio[n].addr = addr;
-    if (may_overlap) {
-        memory_region_add_subregion_overlap(get_system_memory(),
-                                            addr,
-                                            dev->mmio[n].memory,
-                                            priority);
-    }
-    else {
-        memory_region_add_subregion(get_system_memory(),
-                                    addr,
-                                    dev->mmio[n].memory);
-    }
-}
-
-void sysbus_mmio_map(SysBusDevice *dev, int n, hwaddr addr)
-{
-    sysbus_mmio_map_common(dev, n, addr, false, 0);
-}
-
-void sysbus_mmio_map_overlap(SysBusDevice *dev, int n, hwaddr addr,
-                             unsigned priority)
-{
-    sysbus_mmio_map_common(dev, n, addr, true, priority);
-}
-
-/* Request an IRQ source.  The actual IRQ object may be populated later.  */
-void sysbus_init_irq(SysBusDevice *dev, qemu_irq *p)
-{
-    int n;
-
-    assert(dev->num_irq < QDEV_MAX_IRQ);
-    n = dev->num_irq++;
-    dev->irqp[n] = p;
-}
-
-/* Pass IRQs from a target device.  */
-void sysbus_pass_irq(SysBusDevice *dev, SysBusDevice *target)
-{
-    int i;
-    assert(dev->num_irq == 0);
-    dev->num_irq = target->num_irq;
-    for (i = 0; i < dev->num_irq; i++) {
-        dev->irqp[i] = target->irqp[i];
-    }
-}
-
-void sysbus_init_mmio(SysBusDevice *dev, MemoryRegion *memory)
-{
-    int n;
-
-    assert(dev->num_mmio < QDEV_MAX_MMIO);
-    n = dev->num_mmio++;
-    dev->mmio[n].addr = -1;
-    dev->mmio[n].memory = memory;
-}
-
-MemoryRegion *sysbus_mmio_get_region(SysBusDevice *dev, int n)
-{
-    return dev->mmio[n].memory;
-}
-
-void sysbus_init_ioports(SysBusDevice *dev, pio_addr_t ioport, pio_addr_t size)
-{
-    pio_addr_t i;
-
-    for (i = 0; i < size; i++) {
-        assert(dev->num_pio < QDEV_MAX_PIO);
-        dev->pio[dev->num_pio++] = ioport++;
-    }
-}
-
-static int sysbus_device_init(DeviceState *dev)
-{
-    SysBusDevice *sd = SYS_BUS_DEVICE(dev);
-    SysBusDeviceClass *sbc = SYS_BUS_DEVICE_GET_CLASS(sd);
-
-    if (!sbc->init) {
-        return 0;
-    }
-    return sbc->init(sd);
-}
-
-DeviceState *sysbus_create_varargs(const char *name,
-                                   hwaddr addr, ...)
-{
-    DeviceState *dev;
-    SysBusDevice *s;
-    va_list va;
-    qemu_irq irq;
-    int n;
-
-    dev = qdev_create(NULL, name);
-    s = SYS_BUS_DEVICE(dev);
-    qdev_init_nofail(dev);
-    if (addr != (hwaddr)-1) {
-        sysbus_mmio_map(s, 0, addr);
-    }
-    va_start(va, addr);
-    n = 0;
-    while (1) {
-        irq = va_arg(va, qemu_irq);
-        if (!irq) {
-            break;
-        }
-        sysbus_connect_irq(s, n, irq);
-        n++;
-    }
-    va_end(va);
-    return dev;
-}
-
-DeviceState *sysbus_try_create_varargs(const char *name,
-                                       hwaddr addr, ...)
-{
-    DeviceState *dev;
-    SysBusDevice *s;
-    va_list va;
-    qemu_irq irq;
-    int n;
-
-    dev = qdev_try_create(NULL, name);
-    if (!dev) {
-        return NULL;
-    }
-    s = SYS_BUS_DEVICE(dev);
-    qdev_init_nofail(dev);
-    if (addr != (hwaddr)-1) {
-        sysbus_mmio_map(s, 0, addr);
-    }
-    va_start(va, addr);
-    n = 0;
-    while (1) {
-        irq = va_arg(va, qemu_irq);
-        if (!irq) {
-            break;
-        }
-        sysbus_connect_irq(s, n, irq);
-        n++;
-    }
-    va_end(va);
-    return dev;
-}
-
-static void sysbus_dev_print(Monitor *mon, DeviceState *dev, int indent)
-{
-    SysBusDevice *s = SYS_BUS_DEVICE(dev);
-    hwaddr size;
-    int i;
-
-    monitor_printf(mon, "%*sirq %d\n", indent, "", s->num_irq);
-    for (i = 0; i < s->num_mmio; i++) {
-        size = memory_region_size(s->mmio[i].memory);
-        monitor_printf(mon, "%*smmio " TARGET_FMT_plx "/" TARGET_FMT_plx "\n",
-                       indent, "", s->mmio[i].addr, size);
-    }
-}
-
-static char *sysbus_get_fw_dev_path(DeviceState *dev)
-{
-    SysBusDevice *s = SYS_BUS_DEVICE(dev);
-    char path[40];
-    int off;
-
-    off = snprintf(path, sizeof(path), "%s", qdev_fw_name(dev));
-
-    if (s->num_mmio) {
-        snprintf(path + off, sizeof(path) - off, "@"TARGET_FMT_plx,
-                 s->mmio[0].addr);
-    } else if (s->num_pio) {
-        snprintf(path + off, sizeof(path) - off, "@i%04x", s->pio[0]);
-    }
-
-    return g_strdup(path);
-}
-
-void sysbus_add_io(SysBusDevice *dev, hwaddr addr,
-                       MemoryRegion *mem)
-{
-    memory_region_add_subregion(get_system_io(), addr, mem);
-}
-
-void sysbus_del_io(SysBusDevice *dev, MemoryRegion *mem)
-{
-    memory_region_del_subregion(get_system_io(), mem);
-}
-
-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_type = TYPE_SYSTEM_BUS;
-}
-
-static const 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,
-};
-
-/* This is a nasty hack to allow passing a NULL bus to qdev_create.  */
-static BusState *main_system_bus;
-
-static void main_system_bus_create(void)
-{
-    /* assign main_system_bus before qbus_create_inplace()
-     * in order to make "if (bus != sysbus_get_default())" work */
-    main_system_bus = g_malloc0(system_bus_info.instance_size);
-    qbus_create_inplace(main_system_bus, TYPE_SYSTEM_BUS, NULL,
-                        "main-system-bus");
-    OBJECT(main_system_bus)->free = g_free;
-    object_property_add_child(container_get(qdev_get_machine(),
-                                            "/unattached"),
-                              "sysbus", OBJECT(main_system_bus), NULL);
-}
-
-BusState *sysbus_get_default(void)
-{
-    if (!main_system_bus) {
-        main_system_bus_create();
-    }
-    return main_system_bus;
-}
-
-static void sysbus_register_types(void)
-{
-    type_register_static(&system_bus_info);
-    type_register_static(&sysbus_device_type_info);
-}
-
-type_init(sysbus_register_types)
diff --git a/hw/sysbus.h b/hw/sysbus.h
deleted file mode 100644 (file)
index 7c2e316..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-#ifndef HW_SYSBUS_H
-#define HW_SYSBUS_H 1
-
-/* Devices attached directly to the main system bus.  */
-
-#include "hw/qdev.h"
-#include "exec/memory.h"
-
-#define QDEV_MAX_MMIO 32
-#define QDEV_MAX_PIO 32
-#define QDEV_MAX_IRQ 512
-
-#define TYPE_SYSTEM_BUS "System"
-#define SYSTEM_BUS(obj) OBJECT_CHECK(IDEBus, (obj), TYPE_IDE_BUS)
-
-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;
-    qemu_irq irqs[QDEV_MAX_IRQ];
-    qemu_irq *irqp[QDEV_MAX_IRQ];
-    int num_mmio;
-    struct {
-        hwaddr addr;
-        MemoryRegion *memory;
-    } mmio[QDEV_MAX_MMIO];
-    int num_pio;
-    pio_addr_t pio[QDEV_MAX_PIO];
-};
-
-/* Macros to compensate for lack of type inheritance in C.  */
-#define FROM_SYSBUS(type, dev) DO_UPCAST(type, busdev, dev)
-
-void *sysbus_new(void);
-void sysbus_init_mmio(SysBusDevice *dev, MemoryRegion *memory);
-MemoryRegion *sysbus_mmio_get_region(SysBusDevice *dev, int n);
-void sysbus_init_irq(SysBusDevice *dev, qemu_irq *p);
-void sysbus_pass_irq(SysBusDevice *dev, SysBusDevice *target);
-void sysbus_init_ioports(SysBusDevice *dev, pio_addr_t ioport, pio_addr_t size);
-
-
-void sysbus_connect_irq(SysBusDevice *dev, int n, qemu_irq irq);
-void sysbus_mmio_map(SysBusDevice *dev, int n, hwaddr addr);
-void sysbus_mmio_map_overlap(SysBusDevice *dev, int n, hwaddr addr,
-                             unsigned priority);
-void sysbus_add_io(SysBusDevice *dev, hwaddr addr,
-                   MemoryRegion *mem);
-void sysbus_del_io(SysBusDevice *dev, MemoryRegion *mem);
-MemoryRegion *sysbus_address_space(SysBusDevice *dev);
-
-/* Legacy helper function for creating devices.  */
-DeviceState *sysbus_create_varargs(const char *name,
-                                 hwaddr addr, ...);
-DeviceState *sysbus_try_create_varargs(const char *name,
-                                       hwaddr addr, ...);
-static inline DeviceState *sysbus_create_simple(const char *name,
-                                              hwaddr addr,
-                                              qemu_irq irq)
-{
-    return sysbus_create_varargs(name, addr, irq, NULL);
-}
-
-static inline DeviceState *sysbus_try_create_simple(const char *name,
-                                                    hwaddr addr,
-                                                    qemu_irq irq)
-{
-    return sysbus_try_create_varargs(name, addr, irq, NULL);
-}
-
-#endif /* !HW_SYSBUS_H */
diff --git a/hw/tc58128.c b/hw/tc58128.c
deleted file mode 100644 (file)
index f76f96d..0000000
+++ /dev/null
@@ -1,178 +0,0 @@
-#include "hw/hw.h"
-#include "hw/sh.h"
-#include "hw/loader.h"
-
-#define CE1  0x0100
-#define CE2  0x0200
-#define RE   0x0400
-#define WE   0x0800
-#define ALE  0x1000
-#define CLE  0x2000
-#define RDY1 0x4000
-#define RDY2 0x8000
-#define RDY(n) ((n) == 0 ? RDY1 : RDY2)
-
-typedef enum { WAIT, READ1, READ2, READ3 } state_t;
-
-typedef struct {
-    uint8_t *flash_contents;
-    state_t state;
-    uint32_t address;
-    uint8_t address_cycle;
-} tc58128_dev;
-
-static tc58128_dev tc58128_devs[2];
-
-#define FLASH_SIZE (16*1024*1024)
-
-static void init_dev(tc58128_dev * dev, const char *filename)
-{
-    int ret, blocks;
-
-    dev->state = WAIT;
-    dev->flash_contents = g_malloc(FLASH_SIZE);
-    memset(dev->flash_contents, 0xff, FLASH_SIZE);
-    if (filename) {
-       /* Load flash image skipping the first block */
-       ret = load_image(filename, dev->flash_contents + 528 * 32);
-       if (ret < 0) {
-           fprintf(stderr, "ret=%d\n", ret);
-           fprintf(stderr, "qemu: could not load flash image %s\n",
-                   filename);
-           exit(1);
-       } else {
-           /* Build first block with number of blocks */
-           blocks = (ret + 528 * 32 - 1) / (528 * 32);
-           dev->flash_contents[0] = blocks & 0xff;
-           dev->flash_contents[1] = (blocks >> 8) & 0xff;
-           dev->flash_contents[2] = (blocks >> 16) & 0xff;
-           dev->flash_contents[3] = (blocks >> 24) & 0xff;
-           fprintf(stderr, "loaded %d bytes for %s into flash\n", ret,
-                   filename);
-       }
-    }
-}
-
-static void handle_command(tc58128_dev * dev, uint8_t command)
-{
-    switch (command) {
-    case 0xff:
-       fprintf(stderr, "reset flash device\n");
-       dev->state = WAIT;
-       break;
-    case 0x00:
-       fprintf(stderr, "read mode 1\n");
-       dev->state = READ1;
-       dev->address_cycle = 0;
-       break;
-    case 0x01:
-       fprintf(stderr, "read mode 2\n");
-       dev->state = READ2;
-       dev->address_cycle = 0;
-       break;
-    case 0x50:
-       fprintf(stderr, "read mode 3\n");
-       dev->state = READ3;
-       dev->address_cycle = 0;
-       break;
-    default:
-       fprintf(stderr, "unknown flash command 0x%02x\n", command);
-        abort();
-    }
-}
-
-static void handle_address(tc58128_dev * dev, uint8_t data)
-{
-    switch (dev->state) {
-    case READ1:
-    case READ2:
-    case READ3:
-       switch (dev->address_cycle) {
-       case 0:
-           dev->address = data;
-           if (dev->state == READ2)
-               dev->address |= 0x100;
-           else if (dev->state == READ3)
-               dev->address |= 0x200;
-           break;
-       case 1:
-           dev->address += data * 528 * 0x100;
-           break;
-       case 2:
-           dev->address += data * 528;
-           fprintf(stderr, "address pointer in flash: 0x%08x\n",
-                   dev->address);
-           break;
-       default:
-           /* Invalid data */
-            abort();
-       }
-       dev->address_cycle++;
-       break;
-    default:
-        abort();
-    }
-}
-
-static uint8_t handle_read(tc58128_dev * dev)
-{
-#if 0
-    if (dev->address % 0x100000 == 0)
-       fprintf(stderr, "reading flash at address 0x%08x\n", dev->address);
-#endif
-    return dev->flash_contents[dev->address++];
-}
-
-/* We never mark the device as busy, so interrupts cannot be triggered
-   XXXXX */
-
-static int tc58128_cb(uint16_t porta, uint16_t portb,
-                      uint16_t * periph_pdtra, uint16_t * periph_portadir,
-                      uint16_t * periph_pdtrb, uint16_t * periph_portbdir)
-{
-    int dev;
-
-    if ((porta & CE1) == 0)
-       dev = 0;
-    else if ((porta & CE2) == 0)
-       dev = 1;
-    else
-       return 0;               /* No device selected */
-
-    if ((porta & RE) && (porta & WE)) {
-       /* Nothing to do, assert ready and return to input state */
-       *periph_portadir &= 0xff00;
-       *periph_portadir |= RDY(dev);
-       *periph_pdtra |= RDY(dev);
-       return 1;
-    }
-
-    if (porta & CLE) {
-       /* Command */
-       assert((porta & WE) == 0);
-       handle_command(&tc58128_devs[dev], porta & 0x00ff);
-    } else if (porta & ALE) {
-       assert((porta & WE) == 0);
-       handle_address(&tc58128_devs[dev], porta & 0x00ff);
-    } else if ((porta & RE) == 0) {
-       *periph_portadir |= 0x00ff;
-       *periph_pdtra &= 0xff00;
-       *periph_pdtra |= handle_read(&tc58128_devs[dev]);
-    } else {
-        abort();
-    }
-    return 1;
-}
-
-static sh7750_io_device tc58128 = {
-    RE | WE,                   /* Port A triggers */
-    0,                         /* Port B triggers */
-    tc58128_cb                 /* Callback */
-};
-
-int tc58128_init(struct SH7750State *s, const char *zone1, const char *zone2)
-{
-    init_dev(&tc58128_devs[0], zone1);
-    init_dev(&tc58128_devs[1], zone2);
-    return sh7750_register_io_device(s, &tc58128);
-}
diff --git a/hw/tc6393xb.c b/hw/tc6393xb.c
deleted file mode 100644 (file)
index 79c971b..0000000
+++ /dev/null
@@ -1,593 +0,0 @@
-/*
- * Toshiba TC6393XB I/O Controller.
- * Found in Sharp Zaurus SL-6000 (tosa) or some
- * Toshiba e-Series PDAs.
- *
- * 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/hw.h"
-#include "hw/devices.h"
-#include "hw/flash.h"
-#include "ui/console.h"
-#include "ui/pixel_ops.h"
-#include "sysemu/blockdev.h"
-
-#define IRQ_TC6393_NAND                0
-#define IRQ_TC6393_MMC         1
-#define IRQ_TC6393_OHCI                2
-#define IRQ_TC6393_SERIAL      3
-#define IRQ_TC6393_FB          4
-
-#define        TC6393XB_NR_IRQS        8
-
-#define TC6393XB_GPIOS  16
-
-#define SCR_REVID      0x08            /* b Revision ID        */
-#define SCR_ISR                0x50            /* b Interrupt Status   */
-#define SCR_IMR                0x52            /* b Interrupt Mask     */
-#define SCR_IRR                0x54            /* b Interrupt Routing  */
-#define SCR_GPER       0x60            /* w GP Enable          */
-#define SCR_GPI_SR(i)  (0x64 + (i))    /* b3 GPI Status        */
-#define SCR_GPI_IMR(i) (0x68 + (i))    /* b3 GPI INT Mask      */
-#define SCR_GPI_EDER(i)        (0x6c + (i))    /* b3 GPI Edge Detect Enable */
-#define SCR_GPI_LIR(i) (0x70 + (i))    /* b3 GPI Level Invert  */
-#define SCR_GPO_DSR(i) (0x78 + (i))    /* b3 GPO Data Set      */
-#define SCR_GPO_DOECR(i) (0x7c + (i))  /* b3 GPO Data OE Control */
-#define SCR_GP_IARCR(i)        (0x80 + (i))    /* b3 GP Internal Active Register Control */
-#define SCR_GP_IARLCR(i) (0x84 + (i))  /* b3 GP INTERNAL Active Register Level Control */
-#define SCR_GPI_BCR(i) (0x88 + (i))    /* b3 GPI Buffer Control */
-#define SCR_GPA_IARCR  0x8c            /* w GPa Internal Active Register Control */
-#define SCR_GPA_IARLCR 0x90            /* w GPa Internal Active Register Level Control */
-#define SCR_GPA_BCR    0x94            /* w GPa Buffer Control */
-#define SCR_CCR                0x98            /* w Clock Control      */
-#define SCR_PLL2CR     0x9a            /* w PLL2 Control       */
-#define SCR_PLL1CR     0x9c            /* l PLL1 Control       */
-#define SCR_DIARCR     0xa0            /* b Device Internal Active Register Control */
-#define SCR_DBOCR      0xa1            /* b Device Buffer Off Control */
-#define SCR_FER                0xe0            /* b Function Enable    */
-#define SCR_MCR                0xe4            /* w Mode Control       */
-#define SCR_CONFIG     0xfc            /* b Configuration Control */
-#define SCR_DEBUG      0xff            /* b Debug              */
-
-#define NAND_CFG_COMMAND    0x04    /* w Command        */
-#define NAND_CFG_BASE       0x10    /* l Control Base Address */
-#define NAND_CFG_INTP       0x3d    /* b Interrupt Pin  */
-#define NAND_CFG_INTE       0x48    /* b Int Enable     */
-#define NAND_CFG_EC         0x4a    /* b Event Control  */
-#define NAND_CFG_ICC        0x4c    /* b Internal Clock Control */
-#define NAND_CFG_ECCC       0x5b    /* b ECC Control    */
-#define NAND_CFG_NFTC       0x60    /* b NAND Flash Transaction Control */
-#define NAND_CFG_NFM        0x61    /* b NAND Flash Monitor */
-#define NAND_CFG_NFPSC      0x62    /* b NAND Flash Power Supply Control */
-#define NAND_CFG_NFDC       0x63    /* b NAND Flash Detect Control */
-
-#define NAND_DATA   0x00        /* l Data       */
-#define NAND_MODE   0x04        /* b Mode       */
-#define NAND_STATUS 0x05        /* b Status     */
-#define NAND_ISR    0x06        /* b Interrupt Status */
-#define NAND_IMR    0x07        /* b Interrupt Mask */
-
-#define NAND_MODE_WP        0x80
-#define NAND_MODE_CE        0x10
-#define NAND_MODE_ALE       0x02
-#define NAND_MODE_CLE       0x01
-#define NAND_MODE_ECC_MASK  0x60
-#define NAND_MODE_ECC_EN    0x20
-#define NAND_MODE_ECC_READ  0x40
-#define NAND_MODE_ECC_RST   0x60
-
-struct TC6393xbState {
-    MemoryRegion iomem;
-    qemu_irq irq;
-    qemu_irq *sub_irqs;
-    struct {
-        uint8_t ISR;
-        uint8_t IMR;
-        uint8_t IRR;
-        uint16_t GPER;
-        uint8_t GPI_SR[3];
-        uint8_t GPI_IMR[3];
-        uint8_t GPI_EDER[3];
-        uint8_t GPI_LIR[3];
-        uint8_t GP_IARCR[3];
-        uint8_t GP_IARLCR[3];
-        uint8_t GPI_BCR[3];
-        uint16_t GPA_IARCR;
-        uint16_t GPA_IARLCR;
-        uint16_t CCR;
-        uint16_t PLL2CR;
-        uint32_t PLL1CR;
-        uint8_t DIARCR;
-        uint8_t DBOCR;
-        uint8_t FER;
-        uint16_t MCR;
-        uint8_t CONFIG;
-        uint8_t DEBUG;
-    } scr;
-    uint32_t gpio_dir;
-    uint32_t gpio_level;
-    uint32_t prev_level;
-    qemu_irq handler[TC6393XB_GPIOS];
-    qemu_irq *gpio_in;
-
-    struct {
-        uint8_t mode;
-        uint8_t isr;
-        uint8_t imr;
-    } nand;
-    int nand_enable;
-    uint32_t nand_phys;
-    DeviceState *flash;
-    ECCState ecc;
-
-    QemuConsole *con;
-    MemoryRegion vram;
-    uint16_t *vram_ptr;
-    uint32_t scr_width, scr_height; /* in pixels */
-    qemu_irq l3v;
-    unsigned blank : 1,
-             blanked : 1;
-};
-
-qemu_irq *tc6393xb_gpio_in_get(TC6393xbState *s)
-{
-    return s->gpio_in;
-}
-
-static void tc6393xb_gpio_set(void *opaque, int line, int level)
-{
-//    TC6393xbState *s = opaque;
-
-    if (line > TC6393XB_GPIOS) {
-        printf("%s: No GPIO pin %i\n", __FUNCTION__, line);
-        return;
-    }
-
-    // FIXME: how does the chip reflect the GPIO input level change?
-}
-
-void tc6393xb_gpio_out_set(TC6393xbState *s, int line,
-                    qemu_irq handler)
-{
-    if (line >= TC6393XB_GPIOS) {
-        fprintf(stderr, "TC6393xb: no GPIO pin %d\n", line);
-        return;
-    }
-
-    s->handler[line] = handler;
-}
-
-static void tc6393xb_gpio_handler_update(TC6393xbState *s)
-{
-    uint32_t level, diff;
-    int bit;
-
-    level = s->gpio_level & s->gpio_dir;
-
-    for (diff = s->prev_level ^ level; diff; diff ^= 1 << bit) {
-        bit = ffs(diff) - 1;
-        qemu_set_irq(s->handler[bit], (level >> bit) & 1);
-    }
-
-    s->prev_level = level;
-}
-
-qemu_irq tc6393xb_l3v_get(TC6393xbState *s)
-{
-    return s->l3v;
-}
-
-static void tc6393xb_l3v(void *opaque, int line, int level)
-{
-    TC6393xbState *s = opaque;
-    s->blank = !level;
-    fprintf(stderr, "L3V: %d\n", level);
-}
-
-static void tc6393xb_sub_irq(void *opaque, int line, int level) {
-    TC6393xbState *s = opaque;
-    uint8_t isr = s->scr.ISR;
-    if (level)
-        isr |= 1 << line;
-    else
-        isr &= ~(1 << line);
-    s->scr.ISR = isr;
-    qemu_set_irq(s->irq, isr & s->scr.IMR);
-}
-
-#define SCR_REG_B(N)                            \
-    case SCR_ ##N: return s->scr.N
-#define SCR_REG_W(N)                            \
-    case SCR_ ##N: return s->scr.N;             \
-    case SCR_ ##N + 1: return s->scr.N >> 8;
-#define SCR_REG_L(N)                            \
-    case SCR_ ##N: return s->scr.N;             \
-    case SCR_ ##N + 1: return s->scr.N >> 8;    \
-    case SCR_ ##N + 2: return s->scr.N >> 16;   \
-    case SCR_ ##N + 3: return s->scr.N >> 24;
-#define SCR_REG_A(N)                            \
-    case SCR_ ##N(0): return s->scr.N[0];       \
-    case SCR_ ##N(1): return s->scr.N[1];       \
-    case SCR_ ##N(2): return s->scr.N[2]
-
-static uint32_t tc6393xb_scr_readb(TC6393xbState *s, hwaddr addr)
-{
-    switch (addr) {
-        case SCR_REVID:
-            return 3;
-        case SCR_REVID+1:
-            return 0;
-        SCR_REG_B(ISR);
-        SCR_REG_B(IMR);
-        SCR_REG_B(IRR);
-        SCR_REG_W(GPER);
-        SCR_REG_A(GPI_SR);
-        SCR_REG_A(GPI_IMR);
-        SCR_REG_A(GPI_EDER);
-        SCR_REG_A(GPI_LIR);
-        case SCR_GPO_DSR(0):
-        case SCR_GPO_DSR(1):
-        case SCR_GPO_DSR(2):
-            return (s->gpio_level >> ((addr - SCR_GPO_DSR(0)) * 8)) & 0xff;
-        case SCR_GPO_DOECR(0):
-        case SCR_GPO_DOECR(1):
-        case SCR_GPO_DOECR(2):
-            return (s->gpio_dir >> ((addr - SCR_GPO_DOECR(0)) * 8)) & 0xff;
-        SCR_REG_A(GP_IARCR);
-        SCR_REG_A(GP_IARLCR);
-        SCR_REG_A(GPI_BCR);
-        SCR_REG_W(GPA_IARCR);
-        SCR_REG_W(GPA_IARLCR);
-        SCR_REG_W(CCR);
-        SCR_REG_W(PLL2CR);
-        SCR_REG_L(PLL1CR);
-        SCR_REG_B(DIARCR);
-        SCR_REG_B(DBOCR);
-        SCR_REG_B(FER);
-        SCR_REG_W(MCR);
-        SCR_REG_B(CONFIG);
-        SCR_REG_B(DEBUG);
-    }
-    fprintf(stderr, "tc6393xb_scr: unhandled read at %08x\n", (uint32_t) addr);
-    return 0;
-}
-#undef SCR_REG_B
-#undef SCR_REG_W
-#undef SCR_REG_L
-#undef SCR_REG_A
-
-#define SCR_REG_B(N)                                \
-    case SCR_ ##N: s->scr.N = value; return;
-#define SCR_REG_W(N)                                \
-    case SCR_ ##N: s->scr.N = (s->scr.N & ~0xff) | (value & 0xff); return; \
-    case SCR_ ##N + 1: s->scr.N = (s->scr.N & 0xff) | (value << 8); return
-#define SCR_REG_L(N)                                \
-    case SCR_ ##N: s->scr.N = (s->scr.N & ~0xff) | (value & 0xff); return;   \
-    case SCR_ ##N + 1: s->scr.N = (s->scr.N & ~(0xff << 8)) | (value & (0xff << 8)); return;     \
-    case SCR_ ##N + 2: s->scr.N = (s->scr.N & ~(0xff << 16)) | (value & (0xff << 16)); return;   \
-    case SCR_ ##N + 3: s->scr.N = (s->scr.N & ~(0xff << 24)) | (value & (0xff << 24)); return;
-#define SCR_REG_A(N)                                \
-    case SCR_ ##N(0): s->scr.N[0] = value; return;   \
-    case SCR_ ##N(1): s->scr.N[1] = value; return;   \
-    case SCR_ ##N(2): s->scr.N[2] = value; return
-
-static void tc6393xb_scr_writeb(TC6393xbState *s, hwaddr addr, uint32_t value)
-{
-    switch (addr) {
-        SCR_REG_B(ISR);
-        SCR_REG_B(IMR);
-        SCR_REG_B(IRR);
-        SCR_REG_W(GPER);
-        SCR_REG_A(GPI_SR);
-        SCR_REG_A(GPI_IMR);
-        SCR_REG_A(GPI_EDER);
-        SCR_REG_A(GPI_LIR);
-        case SCR_GPO_DSR(0):
-        case SCR_GPO_DSR(1):
-        case SCR_GPO_DSR(2):
-            s->gpio_level = (s->gpio_level & ~(0xff << ((addr - SCR_GPO_DSR(0))*8))) | ((value & 0xff) << ((addr - SCR_GPO_DSR(0))*8));
-            tc6393xb_gpio_handler_update(s);
-            return;
-        case SCR_GPO_DOECR(0):
-        case SCR_GPO_DOECR(1):
-        case SCR_GPO_DOECR(2):
-            s->gpio_dir = (s->gpio_dir & ~(0xff << ((addr - SCR_GPO_DOECR(0))*8))) | ((value & 0xff) << ((addr - SCR_GPO_DOECR(0))*8));
-            tc6393xb_gpio_handler_update(s);
-            return;
-        SCR_REG_A(GP_IARCR);
-        SCR_REG_A(GP_IARLCR);
-        SCR_REG_A(GPI_BCR);
-        SCR_REG_W(GPA_IARCR);
-        SCR_REG_W(GPA_IARLCR);
-        SCR_REG_W(CCR);
-        SCR_REG_W(PLL2CR);
-        SCR_REG_L(PLL1CR);
-        SCR_REG_B(DIARCR);
-        SCR_REG_B(DBOCR);
-        SCR_REG_B(FER);
-        SCR_REG_W(MCR);
-        SCR_REG_B(CONFIG);
-        SCR_REG_B(DEBUG);
-    }
-    fprintf(stderr, "tc6393xb_scr: unhandled write at %08x: %02x\n",
-                                       (uint32_t) addr, value & 0xff);
-}
-#undef SCR_REG_B
-#undef SCR_REG_W
-#undef SCR_REG_L
-#undef SCR_REG_A
-
-static void tc6393xb_nand_irq(TC6393xbState *s) {
-    qemu_set_irq(s->sub_irqs[IRQ_TC6393_NAND],
-            (s->nand.imr & 0x80) && (s->nand.imr & s->nand.isr));
-}
-
-static uint32_t tc6393xb_nand_cfg_readb(TC6393xbState *s, hwaddr addr) {
-    switch (addr) {
-        case NAND_CFG_COMMAND:
-            return s->nand_enable ? 2 : 0;
-        case NAND_CFG_BASE:
-        case NAND_CFG_BASE + 1:
-        case NAND_CFG_BASE + 2:
-        case NAND_CFG_BASE + 3:
-            return s->nand_phys >> (addr - NAND_CFG_BASE);
-    }
-    fprintf(stderr, "tc6393xb_nand_cfg: unhandled read at %08x\n", (uint32_t) addr);
-    return 0;
-}
-static void tc6393xb_nand_cfg_writeb(TC6393xbState *s, hwaddr addr, uint32_t value) {
-    switch (addr) {
-        case NAND_CFG_COMMAND:
-            s->nand_enable = (value & 0x2);
-            return;
-        case NAND_CFG_BASE:
-        case NAND_CFG_BASE + 1:
-        case NAND_CFG_BASE + 2:
-        case NAND_CFG_BASE + 3:
-            s->nand_phys &= ~(0xff << ((addr - NAND_CFG_BASE) * 8));
-            s->nand_phys |= (value & 0xff) << ((addr - NAND_CFG_BASE) * 8);
-            return;
-    }
-    fprintf(stderr, "tc6393xb_nand_cfg: unhandled write at %08x: %02x\n",
-                                       (uint32_t) addr, value & 0xff);
-}
-
-static uint32_t tc6393xb_nand_readb(TC6393xbState *s, hwaddr addr) {
-    switch (addr) {
-        case NAND_DATA + 0:
-        case NAND_DATA + 1:
-        case NAND_DATA + 2:
-        case NAND_DATA + 3:
-            return nand_getio(s->flash);
-        case NAND_MODE:
-            return s->nand.mode;
-        case NAND_STATUS:
-            return 0x14;
-        case NAND_ISR:
-            return s->nand.isr;
-        case NAND_IMR:
-            return s->nand.imr;
-    }
-    fprintf(stderr, "tc6393xb_nand: unhandled read at %08x\n", (uint32_t) addr);
-    return 0;
-}
-static void tc6393xb_nand_writeb(TC6393xbState *s, hwaddr addr, uint32_t value) {
-//    fprintf(stderr, "tc6393xb_nand: write at %08x: %02x\n",
-//                                     (uint32_t) addr, value & 0xff);
-    switch (addr) {
-        case NAND_DATA + 0:
-        case NAND_DATA + 1:
-        case NAND_DATA + 2:
-        case NAND_DATA + 3:
-            nand_setio(s->flash, value);
-            s->nand.isr |= 1;
-            tc6393xb_nand_irq(s);
-            return;
-        case NAND_MODE:
-            s->nand.mode = value;
-            nand_setpins(s->flash,
-                    value & NAND_MODE_CLE,
-                    value & NAND_MODE_ALE,
-                    !(value & NAND_MODE_CE),
-                    value & NAND_MODE_WP,
-                    0); // FIXME: gnd
-            switch (value & NAND_MODE_ECC_MASK) {
-                case NAND_MODE_ECC_RST:
-                    ecc_reset(&s->ecc);
-                    break;
-                case NAND_MODE_ECC_READ:
-                    // FIXME
-                    break;
-                case NAND_MODE_ECC_EN:
-                    ecc_reset(&s->ecc);
-            }
-            return;
-        case NAND_ISR:
-            s->nand.isr = value;
-            tc6393xb_nand_irq(s);
-            return;
-        case NAND_IMR:
-            s->nand.imr = value;
-            tc6393xb_nand_irq(s);
-            return;
-    }
-    fprintf(stderr, "tc6393xb_nand: unhandled write at %08x: %02x\n",
-                                       (uint32_t) addr, value & 0xff);
-}
-
-#define BITS 8
-#include "hw/tc6393xb_template.h"
-#define BITS 15
-#include "hw/tc6393xb_template.h"
-#define BITS 16
-#include "hw/tc6393xb_template.h"
-#define BITS 24
-#include "hw/tc6393xb_template.h"
-#define BITS 32
-#include "hw/tc6393xb_template.h"
-
-static void tc6393xb_draw_graphic(TC6393xbState *s, int full_update)
-{
-    DisplaySurface *surface = qemu_console_surface(s->con);
-
-    switch (surface_bits_per_pixel(surface)) {
-        case 8:
-            tc6393xb_draw_graphic8(s);
-            break;
-        case 15:
-            tc6393xb_draw_graphic15(s);
-            break;
-        case 16:
-            tc6393xb_draw_graphic16(s);
-            break;
-        case 24:
-            tc6393xb_draw_graphic24(s);
-            break;
-        case 32:
-            tc6393xb_draw_graphic32(s);
-            break;
-        default:
-            printf("tc6393xb: unknown depth %d\n",
-                   surface_bits_per_pixel(surface));
-            return;
-    }
-
-    dpy_gfx_update(s->con, 0, 0, s->scr_width, s->scr_height);
-}
-
-static void tc6393xb_draw_blank(TC6393xbState *s, int full_update)
-{
-    DisplaySurface *surface = qemu_console_surface(s->con);
-    int i, w;
-    uint8_t *d;
-
-    if (!full_update)
-        return;
-
-    w = s->scr_width * surface_bytes_per_pixel(surface);
-    d = surface_data(surface);
-    for(i = 0; i < s->scr_height; i++) {
-        memset(d, 0, w);
-        d += surface_stride(surface);
-    }
-
-    dpy_gfx_update(s->con, 0, 0, s->scr_width, s->scr_height);
-}
-
-static void tc6393xb_update_display(void *opaque)
-{
-    TC6393xbState *s = opaque;
-    DisplaySurface *surface = qemu_console_surface(s->con);
-    int full_update;
-
-    if (s->scr_width == 0 || s->scr_height == 0)
-        return;
-
-    full_update = 0;
-    if (s->blanked != s->blank) {
-        s->blanked = s->blank;
-        full_update = 1;
-    }
-    if (s->scr_width != surface_width(surface) ||
-        s->scr_height != surface_height(surface)) {
-        qemu_console_resize(s->con, s->scr_width, s->scr_height);
-        full_update = 1;
-    }
-    if (s->blanked)
-        tc6393xb_draw_blank(s, full_update);
-    else
-        tc6393xb_draw_graphic(s, full_update);
-}
-
-
-static uint64_t tc6393xb_readb(void *opaque, hwaddr addr,
-                               unsigned size)
-{
-    TC6393xbState *s = opaque;
-
-    switch (addr >> 8) {
-        case 0:
-            return tc6393xb_scr_readb(s, addr & 0xff);
-        case 1:
-            return tc6393xb_nand_cfg_readb(s, addr & 0xff);
-    };
-
-    if ((addr &~0xff) == s->nand_phys && s->nand_enable) {
-//        return tc6393xb_nand_readb(s, addr & 0xff);
-        uint8_t d = tc6393xb_nand_readb(s, addr & 0xff);
-//        fprintf(stderr, "tc6393xb_nand: read at %08x: %02hhx\n", (uint32_t) addr, d);
-        return d;
-    }
-
-//    fprintf(stderr, "tc6393xb: unhandled read at %08x\n", (uint32_t) addr);
-    return 0;
-}
-
-static void tc6393xb_writeb(void *opaque, hwaddr addr,
-                            uint64_t value, unsigned size) {
-    TC6393xbState *s = opaque;
-
-    switch (addr >> 8) {
-        case 0:
-            tc6393xb_scr_writeb(s, addr & 0xff, value);
-            return;
-        case 1:
-            tc6393xb_nand_cfg_writeb(s, addr & 0xff, value);
-            return;
-    };
-
-    if ((addr &~0xff) == s->nand_phys && s->nand_enable)
-        tc6393xb_nand_writeb(s, addr & 0xff, value);
-    else
-        fprintf(stderr, "tc6393xb: unhandled write at %08x: %02x\n",
-                (uint32_t) addr, (int)value & 0xff);
-}
-
-TC6393xbState *tc6393xb_init(MemoryRegion *sysmem, uint32_t base, qemu_irq irq)
-{
-    TC6393xbState *s;
-    DriveInfo *nand;
-    static const MemoryRegionOps tc6393xb_ops = {
-        .read = tc6393xb_readb,
-        .write = tc6393xb_writeb,
-        .endianness = DEVICE_NATIVE_ENDIAN,
-        .impl = {
-            .min_access_size = 1,
-            .max_access_size = 1,
-        },
-    };
-
-    s = (TC6393xbState *) g_malloc0(sizeof(TC6393xbState));
-    s->irq = irq;
-    s->gpio_in = qemu_allocate_irqs(tc6393xb_gpio_set, s, TC6393XB_GPIOS);
-
-    s->l3v = *qemu_allocate_irqs(tc6393xb_l3v, s, 1);
-    s->blanked = 1;
-
-    s->sub_irqs = qemu_allocate_irqs(tc6393xb_sub_irq, s, TC6393XB_NR_IRQS);
-
-    nand = drive_get(IF_MTD, 0, 0);
-    s->flash = nand_init(nand ? nand->bdrv : NULL, NAND_MFR_TOSHIBA, 0x76);
-
-    memory_region_init_io(&s->iomem, &tc6393xb_ops, s, "tc6393xb", 0x10000);
-    memory_region_add_subregion(sysmem, base, &s->iomem);
-
-    memory_region_init_ram(&s->vram, "tc6393xb.vram", 0x100000);
-    vmstate_register_ram_global(&s->vram);
-    s->vram_ptr = memory_region_get_ram_ptr(&s->vram);
-    memory_region_add_subregion(sysmem, base + 0x100000, &s->vram);
-    s->scr_width = 480;
-    s->scr_height = 640;
-    s->con = graphic_console_init(tc6393xb_update_display,
-            NULL, /* invalidate */
-            NULL, /* screen_dump */
-            NULL, /* text_update */
-            s);
-
-    return s;
-}
diff --git a/hw/tc6393xb_template.h b/hw/tc6393xb_template.h
deleted file mode 100644 (file)
index 154aafd..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Toshiba TC6393XB I/O Controller.
- * Found in Sharp Zaurus SL-6000 (tosa) or some
- * Toshiba e-Series PDAs.
- *
- * FB support code. Based on G364 fb emulator
- *
- * Copyright (c) 2007 Hervé Poussineau
- *
- * 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/>.
- */
-
-#if BITS == 8
-# define SET_PIXEL(addr, color)        *(uint8_t*)addr = color;
-#elif BITS == 15 || BITS == 16
-# define SET_PIXEL(addr, color)        *(uint16_t*)addr = color;
-#elif BITS == 24
-# define SET_PIXEL(addr, color)        \
-    addr[0] = color; addr[1] = (color) >> 8; addr[2] = (color) >> 16;
-#elif BITS == 32
-# define SET_PIXEL(addr, color)        *(uint32_t*)addr = color;
-#else
-# error unknown bit depth
-#endif
-
-
-static void glue(tc6393xb_draw_graphic, BITS)(TC6393xbState *s)
-{
-    DisplaySurface *surface = qemu_console_surface(s->con);
-    int i;
-    uint16_t *data_buffer;
-    uint8_t *data_display;
-
-    data_buffer = s->vram_ptr;
-    data_display = surface_data(surface);
-    for(i = 0; i < s->scr_height; i++) {
-#if (BITS == 16)
-        memcpy(data_display, data_buffer, s->scr_width * 2);
-        data_buffer += s->scr_width;
-        data_display += surface_stride(surface);
-#else
-        int j;
-        for (j = 0; j < s->scr_width; j++, data_display += BITS / 8, data_buffer++) {
-            uint16_t color = *data_buffer;
-            uint32_t dest_color = glue(rgb_to_pixel, BITS)(
-                           ((color & 0xf800) * 0x108) >> 11,
-                           ((color & 0x7e0) * 0x41) >> 9,
-                           ((color & 0x1f) * 0x21) >> 2
-                           );
-            SET_PIXEL(data_display, dest_color);
-        }
-#endif
-    }
-}
-
-#undef BITS
-#undef SET_PIXEL
diff --git a/hw/tcx.c b/hw/tcx.c
deleted file mode 100644 (file)
index c44068e..0000000
--- a/hw/tcx.c
+++ /dev/null
@@ -1,739 +0,0 @@
-/*
- * QEMU TCX Frame buffer
- *
- * Copyright (c) 2003-2005 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.
- */
-
-#include "qemu-common.h"
-#include "ui/console.h"
-#include "ui/pixel_ops.h"
-#include "hw/sysbus.h"
-#include "hw/qdev-addr.h"
-
-#define MAXX 1024
-#define MAXY 768
-#define TCX_DAC_NREGS 16
-#define TCX_THC_NREGS_8  0x081c
-#define TCX_THC_NREGS_24 0x1000
-#define TCX_TEC_NREGS    0x1000
-
-typedef struct TCXState {
-    SysBusDevice busdev;
-    QemuConsole *con;
-    uint8_t *vram;
-    uint32_t *vram24, *cplane;
-    MemoryRegion vram_mem;
-    MemoryRegion vram_8bit;
-    MemoryRegion vram_24bit;
-    MemoryRegion vram_cplane;
-    MemoryRegion dac;
-    MemoryRegion tec;
-    MemoryRegion thc24;
-    MemoryRegion thc8;
-    ram_addr_t vram24_offset, cplane_offset;
-    uint32_t vram_size;
-    uint32_t palette[256];
-    uint8_t r[256], g[256], b[256];
-    uint16_t width, height, depth;
-    uint8_t dac_index, dac_state;
-} TCXState;
-
-static void tcx_screen_dump(void *opaque, const char *filename, bool cswitch,
-                            Error **errp);
-static void tcx24_screen_dump(void *opaque, const char *filename, bool cswitch,
-                            Error **errp);
-
-static void tcx_set_dirty(TCXState *s)
-{
-    memory_region_set_dirty(&s->vram_mem, 0, MAXX * MAXY);
-}
-
-static void tcx24_set_dirty(TCXState *s)
-{
-    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)
-{
-    DisplaySurface *surface = qemu_console_surface(s->con);
-    int i;
-
-    for (i = start; i < end; i++) {
-        switch (surface_bits_per_pixel(surface)) {
-        default:
-        case 8:
-            s->palette[i] = rgb_to_pixel8(s->r[i], s->g[i], s->b[i]);
-            break;
-        case 15:
-            s->palette[i] = rgb_to_pixel15(s->r[i], s->g[i], s->b[i]);
-            break;
-        case 16:
-            s->palette[i] = rgb_to_pixel16(s->r[i], s->g[i], s->b[i]);
-            break;
-        case 32:
-            if (is_surface_bgr(surface)) {
-                s->palette[i] = rgb_to_pixel32bgr(s->r[i], s->g[i], s->b[i]);
-            } else {
-                s->palette[i] = rgb_to_pixel32(s->r[i], s->g[i], s->b[i]);
-            }
-            break;
-        }
-    }
-    if (s->depth == 24) {
-        tcx24_set_dirty(s);
-    } else {
-        tcx_set_dirty(s);
-    }
-}
-
-static void tcx_draw_line32(TCXState *s1, uint8_t *d,
-                            const uint8_t *s, int width)
-{
-    int x;
-    uint8_t val;
-    uint32_t *p = (uint32_t *)d;
-
-    for(x = 0; x < width; x++) {
-        val = *s++;
-        *p++ = s1->palette[val];
-    }
-}
-
-static void tcx_draw_line16(TCXState *s1, uint8_t *d,
-                            const uint8_t *s, int width)
-{
-    int x;
-    uint8_t val;
-    uint16_t *p = (uint16_t *)d;
-
-    for(x = 0; x < width; x++) {
-        val = *s++;
-        *p++ = s1->palette[val];
-    }
-}
-
-static void tcx_draw_line8(TCXState *s1, uint8_t *d,
-                           const uint8_t *s, int width)
-{
-    int x;
-    uint8_t val;
-
-    for(x = 0; x < width; x++) {
-        val = *s++;
-        *d++ = s1->palette[val];
-    }
-}
-
-/*
-  XXX Could be much more optimal:
-  * detect if line/page/whole screen is in 24 bit mode
-  * if destination is also BGR, use memcpy
-  */
-static inline void tcx24_draw_line32(TCXState *s1, uint8_t *d,
-                                     const uint8_t *s, int width,
-                                     const uint32_t *cplane,
-                                     const uint32_t *s24)
-{
-    DisplaySurface *surface = qemu_console_surface(s1->con);
-    int x, bgr, r, g, b;
-    uint8_t val, *p8;
-    uint32_t *p = (uint32_t *)d;
-    uint32_t dval;
-
-    bgr = is_surface_bgr(surface);
-    for(x = 0; x < width; x++, s++, s24++) {
-        if ((be32_to_cpu(*cplane++) & 0xff000000) == 0x03000000) {
-            // 24-bit direct, BGR order
-            p8 = (uint8_t *)s24;
-            p8++;
-            b = *p8++;
-            g = *p8++;
-            r = *p8;
-            if (bgr)
-                dval = rgb_to_pixel32bgr(r, g, b);
-            else
-                dval = rgb_to_pixel32(r, g, b);
-        } else {
-            val = *s;
-            dval = s1->palette[val];
-        }
-        *p++ = dval;
-    }
-}
-
-static inline int check_dirty(TCXState *s, ram_addr_t page, ram_addr_t page24,
-                              ram_addr_t cpage)
-{
-    int ret;
-
-    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;
-}
-
-static inline void reset_dirty(TCXState *ts, ram_addr_t page_min,
-                               ram_addr_t page_max, ram_addr_t page24,
-                              ram_addr_t cpage)
-{
-    memory_region_reset_dirty(&ts->vram_mem,
-                              page_min, page_max + TARGET_PAGE_SIZE,
-                              DIRTY_MEMORY_VGA);
-    memory_region_reset_dirty(&ts->vram_mem,
-                              page24 + page_min * 4,
-                              page24 + page_max * 4 + TARGET_PAGE_SIZE,
-                              DIRTY_MEMORY_VGA);
-    memory_region_reset_dirty(&ts->vram_mem,
-                              cpage + page_min * 4,
-                              cpage + page_max * 4 + TARGET_PAGE_SIZE,
-                              DIRTY_MEMORY_VGA);
-}
-
-/* Fixed line length 1024 allows us to do nice tricks not possible on
-   VGA... */
-static void tcx_update_display(void *opaque)
-{
-    TCXState *ts = opaque;
-    DisplaySurface *surface = qemu_console_surface(ts->con);
-    ram_addr_t page, page_min, page_max;
-    int y, y_start, dd, ds;
-    uint8_t *d, *s;
-    void (*f)(TCXState *s1, uint8_t *dst, const uint8_t *src, int width);
-
-    if (surface_bits_per_pixel(surface) == 0) {
-        return;
-    }
-
-    page = 0;
-    y_start = -1;
-    page_min = -1;
-    page_max = 0;
-    d = surface_data(surface);
-    s = ts->vram;
-    dd = surface_stride(surface);
-    ds = 1024;
-
-    switch (surface_bits_per_pixel(surface)) {
-    case 32:
-        f = tcx_draw_line32;
-        break;
-    case 15:
-    case 16:
-        f = tcx_draw_line16;
-        break;
-    default:
-    case 8:
-        f = tcx_draw_line8;
-        break;
-    case 0:
-        return;
-    }
-
-    for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE) {
-        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)
-                page_min = page;
-            if (page > page_max)
-                page_max = page;
-            f(ts, d, s, ts->width);
-            d += dd;
-            s += ds;
-            f(ts, d, s, ts->width);
-            d += dd;
-            s += ds;
-            f(ts, d, s, ts->width);
-            d += dd;
-            s += ds;
-            f(ts, d, s, ts->width);
-            d += dd;
-            s += ds;
-        } else {
-            if (y_start >= 0) {
-                /* flush to display */
-                dpy_gfx_update(ts->con, 0, y_start,
-                               ts->width, y - y_start);
-                y_start = -1;
-            }
-            d += dd * 4;
-            s += ds * 4;
-        }
-    }
-    if (y_start >= 0) {
-        /* flush to display */
-        dpy_gfx_update(ts->con, 0, y_start,
-                       ts->width, y - y_start);
-    }
-    /* reset modified pages */
-    if (page_max >= page_min) {
-        memory_region_reset_dirty(&ts->vram_mem,
-                                  page_min, page_max + TARGET_PAGE_SIZE,
-                                  DIRTY_MEMORY_VGA);
-    }
-}
-
-static void tcx24_update_display(void *opaque)
-{
-    TCXState *ts = opaque;
-    DisplaySurface *surface = qemu_console_surface(ts->con);
-    ram_addr_t page, page_min, page_max, cpage, page24;
-    int y, y_start, dd, ds;
-    uint8_t *d, *s;
-    uint32_t *cptr, *s24;
-
-    if (surface_bits_per_pixel(surface) != 32) {
-            return;
-    }
-
-    page = 0;
-    page24 = ts->vram24_offset;
-    cpage = ts->cplane_offset;
-    y_start = -1;
-    page_min = -1;
-    page_max = 0;
-    d = surface_data(surface);
-    s = ts->vram;
-    s24 = ts->vram24;
-    cptr = ts->cplane;
-    dd = surface_stride(surface);
-    ds = 1024;
-
-    for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE,
-            page24 += TARGET_PAGE_SIZE, cpage += TARGET_PAGE_SIZE) {
-        if (check_dirty(ts, page, page24, cpage)) {
-            if (y_start < 0)
-                y_start = y;
-            if (page < page_min)
-                page_min = page;
-            if (page > page_max)
-                page_max = page;
-            tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
-            d += dd;
-            s += ds;
-            cptr += ds;
-            s24 += ds;
-            tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
-            d += dd;
-            s += ds;
-            cptr += ds;
-            s24 += ds;
-            tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
-            d += dd;
-            s += ds;
-            cptr += ds;
-            s24 += ds;
-            tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
-            d += dd;
-            s += ds;
-            cptr += ds;
-            s24 += ds;
-        } else {
-            if (y_start >= 0) {
-                /* flush to display */
-                dpy_gfx_update(ts->con, 0, y_start,
-                               ts->width, y - y_start);
-                y_start = -1;
-            }
-            d += dd * 4;
-            s += ds * 4;
-            cptr += ds * 4;
-            s24 += ds * 4;
-        }
-    }
-    if (y_start >= 0) {
-        /* flush to display */
-        dpy_gfx_update(ts->con, 0, y_start,
-                       ts->width, y - y_start);
-    }
-    /* reset modified pages */
-    if (page_max >= page_min) {
-        reset_dirty(ts, page_min, page_max, page24, cpage);
-    }
-}
-
-static void tcx_invalidate_display(void *opaque)
-{
-    TCXState *s = opaque;
-
-    tcx_set_dirty(s);
-    qemu_console_resize(s->con, s->width, s->height);
-}
-
-static void tcx24_invalidate_display(void *opaque)
-{
-    TCXState *s = opaque;
-
-    tcx_set_dirty(s);
-    tcx24_set_dirty(s);
-    qemu_console_resize(s->con, s->width, s->height);
-}
-
-static int vmstate_tcx_post_load(void *opaque, int version_id)
-{
-    TCXState *s = opaque;
-
-    update_palette_entries(s, 0, 256);
-    if (s->depth == 24) {
-        tcx24_set_dirty(s);
-    } else {
-        tcx_set_dirty(s);
-    }
-
-    return 0;
-}
-
-static const VMStateDescription vmstate_tcx = {
-    .name ="tcx",
-    .version_id = 4,
-    .minimum_version_id = 4,
-    .minimum_version_id_old = 4,
-    .post_load = vmstate_tcx_post_load,
-    .fields      = (VMStateField []) {
-        VMSTATE_UINT16(height, TCXState),
-        VMSTATE_UINT16(width, TCXState),
-        VMSTATE_UINT16(depth, TCXState),
-        VMSTATE_BUFFER(r, TCXState),
-        VMSTATE_BUFFER(g, TCXState),
-        VMSTATE_BUFFER(b, TCXState),
-        VMSTATE_UINT8(dac_index, TCXState),
-        VMSTATE_UINT8(dac_state, TCXState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void tcx_reset(DeviceState *d)
-{
-    TCXState *s = container_of(d, TCXState, busdev.qdev);
-
-    /* Initialize palette */
-    memset(s->r, 0, 256);
-    memset(s->g, 0, 256);
-    memset(s->b, 0, 256);
-    s->r[255] = s->g[255] = s->b[255] = 255;
-    update_palette_entries(s, 0, 256);
-    memset(s->vram, 0, MAXX*MAXY);
-    memory_region_reset_dirty(&s->vram_mem, 0, MAXX * MAXY * (1 + 4 + 4),
-                              DIRTY_MEMORY_VGA);
-    s->dac_index = 0;
-    s->dac_state = 0;
-}
-
-static uint64_t tcx_dac_readl(void *opaque, hwaddr addr,
-                              unsigned size)
-{
-    return 0;
-}
-
-static void tcx_dac_writel(void *opaque, hwaddr addr, uint64_t val,
-                           unsigned size)
-{
-    TCXState *s = opaque;
-
-    switch (addr) {
-    case 0:
-        s->dac_index = val >> 24;
-        s->dac_state = 0;
-        break;
-    case 4:
-        switch (s->dac_state) {
-        case 0:
-            s->r[s->dac_index] = val >> 24;
-            update_palette_entries(s, s->dac_index, s->dac_index + 1);
-            s->dac_state++;
-            break;
-        case 1:
-            s->g[s->dac_index] = val >> 24;
-            update_palette_entries(s, s->dac_index, s->dac_index + 1);
-            s->dac_state++;
-            break;
-        case 2:
-            s->b[s->dac_index] = val >> 24;
-            update_palette_entries(s, s->dac_index, s->dac_index + 1);
-            s->dac_index = (s->dac_index + 1) & 255; // Index autoincrement
-        default:
-            s->dac_state = 0;
-            break;
-        }
-        break;
-    default:
-        break;
-    }
-}
-
-static const MemoryRegionOps tcx_dac_ops = {
-    .read = tcx_dac_readl,
-    .write = tcx_dac_writel,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-};
-
-static uint64_t dummy_readl(void *opaque, hwaddr addr,
-                            unsigned size)
-{
-    return 0;
-}
-
-static void dummy_writel(void *opaque, hwaddr addr,
-                         uint64_t val, unsigned size)
-{
-}
-
-static const MemoryRegionOps dummy_ops = {
-    .read = dummy_readl,
-    .write = dummy_writel,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-};
-
-static int tcx_init1(SysBusDevice *dev)
-{
-    TCXState *s = FROM_SYSBUS(TCXState, dev);
-    ram_addr_t vram_offset = 0;
-    int size;
-    uint8_t *vram_base;
-
-    memory_region_init_ram(&s->vram_mem, "tcx.vram",
-                           s->vram_size * (1 + 4 + 4));
-    vmstate_register_ram_global(&s->vram_mem);
-    vram_base = memory_region_get_ram_ptr(&s->vram_mem);
-
-    /* 8-bit plane */
-    s->vram = vram_base;
-    size = s->vram_size;
-    memory_region_init_alias(&s->vram_8bit, "tcx.vram.8bit",
-                             &s->vram_mem, vram_offset, size);
-    sysbus_init_mmio(dev, &s->vram_8bit);
-    vram_offset += size;
-    vram_base += size;
-
-    /* DAC */
-    memory_region_init_io(&s->dac, &tcx_dac_ops, s, "tcx.dac", TCX_DAC_NREGS);
-    sysbus_init_mmio(dev, &s->dac);
-
-    /* TEC (dummy) */
-    memory_region_init_io(&s->tec, &dummy_ops, s, "tcx.tec", TCX_TEC_NREGS);
-    sysbus_init_mmio(dev, &s->tec);
-    /* THC: NetBSD writes here even with 8-bit display: dummy */
-    memory_region_init_io(&s->thc24, &dummy_ops, s, "tcx.thc24",
-                          TCX_THC_NREGS_24);
-    sysbus_init_mmio(dev, &s->thc24);
-
-    if (s->depth == 24) {
-        /* 24-bit plane */
-        size = s->vram_size * 4;
-        s->vram24 = (uint32_t *)vram_base;
-        s->vram24_offset = vram_offset;
-        memory_region_init_alias(&s->vram_24bit, "tcx.vram.24bit",
-                                 &s->vram_mem, vram_offset, size);
-        sysbus_init_mmio(dev, &s->vram_24bit);
-        vram_offset += size;
-        vram_base += size;
-
-        /* Control plane */
-        size = s->vram_size * 4;
-        s->cplane = (uint32_t *)vram_base;
-        s->cplane_offset = vram_offset;
-        memory_region_init_alias(&s->vram_cplane, "tcx.vram.cplane",
-                                 &s->vram_mem, vram_offset, size);
-        sysbus_init_mmio(dev, &s->vram_cplane);
-
-        s->con = graphic_console_init(tcx24_update_display,
-                                      tcx24_invalidate_display,
-                                      tcx24_screen_dump, NULL, s);
-    } else {
-        /* THC 8 bit (dummy) */
-        memory_region_init_io(&s->thc8, &dummy_ops, s, "tcx.thc8",
-                              TCX_THC_NREGS_8);
-        sysbus_init_mmio(dev, &s->thc8);
-
-        s->con = graphic_console_init(tcx_update_display,
-                                      tcx_invalidate_display,
-                                      tcx_screen_dump, NULL, s);
-    }
-
-    qemu_console_resize(s->con, s->width, s->height);
-    return 0;
-}
-
-static void tcx_screen_dump(void *opaque, const char *filename, bool cswitch,
-                            Error **errp)
-{
-    TCXState *s = opaque;
-    FILE *f;
-    uint8_t *d, *d1, v;
-    int ret, y, x;
-
-    f = fopen(filename, "wb");
-    if (!f) {
-        error_setg(errp, "failed to open file '%s': %s", filename,
-                   strerror(errno));
-        return;
-    }
-    ret = fprintf(f, "P6\n%d %d\n%d\n", s->width, s->height, 255);
-    if (ret < 0) {
-        goto write_err;
-    }
-    d1 = s->vram;
-    for(y = 0; y < s->height; y++) {
-        d = d1;
-        for(x = 0; x < s->width; x++) {
-            v = *d;
-            ret = fputc(s->r[v], f);
-            if (ret == EOF) {
-                goto write_err;
-            }
-            ret = fputc(s->g[v], f);
-            if (ret == EOF) {
-                goto write_err;
-            }
-            ret = fputc(s->b[v], f);
-            if (ret == EOF) {
-                goto write_err;
-            }
-            d++;
-        }
-        d1 += MAXX;
-    }
-
-out:
-    fclose(f);
-    return;
-
-write_err:
-    error_setg(errp, "failed to write to file '%s': %s", filename,
-               strerror(errno));
-    unlink(filename);
-    goto out;
-}
-
-static void tcx24_screen_dump(void *opaque, const char *filename, bool cswitch,
-                              Error **errp)
-{
-    TCXState *s = opaque;
-    FILE *f;
-    uint8_t *d, *d1, v;
-    uint32_t *s24, *cptr, dval;
-    int ret, y, x;
-
-    f = fopen(filename, "wb");
-    if (!f) {
-        error_setg(errp, "failed to open file '%s': %s", filename,
-                   strerror(errno));
-        return;
-    }
-    ret = fprintf(f, "P6\n%d %d\n%d\n", s->width, s->height, 255);
-    if (ret < 0) {
-        goto write_err;
-    }
-    d1 = s->vram;
-    s24 = s->vram24;
-    cptr = s->cplane;
-    for(y = 0; y < s->height; y++) {
-        d = d1;
-        for(x = 0; x < s->width; x++, d++, s24++) {
-            if ((*cptr++ & 0xff000000) == 0x03000000) { // 24-bit direct
-                dval = *s24 & 0x00ffffff;
-                ret = fputc((dval >> 16) & 0xff, f);
-                if (ret == EOF) {
-                    goto write_err;
-                }
-                ret = fputc((dval >> 8) & 0xff, f);
-                if (ret == EOF) {
-                    goto write_err;
-                }
-                ret = fputc(dval & 0xff, f);
-                if (ret == EOF) {
-                    goto write_err;
-                }
-            } else {
-                v = *d;
-                ret = fputc(s->r[v], f);
-                if (ret == EOF) {
-                    goto write_err;
-                }
-                ret = fputc(s->g[v], f);
-                if (ret == EOF) {
-                    goto write_err;
-                }
-                ret = fputc(s->b[v], f);
-                if (ret == EOF) {
-                    goto write_err;
-                }
-            }
-        }
-        d1 += MAXX;
-    }
-
-out:
-    fclose(f);
-    return;
-
-write_err:
-    error_setg(errp, "failed to write to file '%s': %s", filename,
-               strerror(errno));
-    unlink(filename);
-    goto out;
-}
-
-static Property tcx_properties[] = {
-    DEFINE_PROP_HEX32("vram_size", TCXState, vram_size, -1),
-    DEFINE_PROP_UINT16("width",    TCXState, width,     -1),
-    DEFINE_PROP_UINT16("height",   TCXState, height,    -1),
-    DEFINE_PROP_UINT16("depth",    TCXState, depth,     -1),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void tcx_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = tcx_init1;
-    dc->reset = tcx_reset;
-    dc->vmsd = &vmstate_tcx;
-    dc->props = tcx_properties;
-}
-
-static const TypeInfo tcx_info = {
-    .name          = "SUNW,tcx",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(TCXState),
-    .class_init    = tcx_class_init,
-};
-
-static void tcx_register_types(void)
-{
-    type_register_static(&tcx_info);
-}
-
-type_init(tcx_register_types)
diff --git a/hw/timer/Makefile.objs b/hw/timer/Makefile.objs
new file mode 100644 (file)
index 0000000..e4bd17f
--- /dev/null
@@ -0,0 +1,28 @@
+common-obj-$(CONFIG_ARM_TIMER) += arm_timer.o
+common-obj-$(CONFIG_CADENCE) += cadence_ttc.o
+common-obj-$(CONFIG_DS1338) += ds1338.o
+common-obj-$(CONFIG_HPET) += hpet.o
+common-obj-$(CONFIG_I8254) += i8254_common.o i8254.o
+common-obj-$(CONFIG_M48T59) += m48t59.o
+common-obj-$(CONFIG_PL031) += pl031.o
+common-obj-$(CONFIG_PUV3) += puv3_ost.o
+common-obj-$(CONFIG_TWL92230) += twl92230.o
+common-obj-$(CONFIG_XILINX) += xilinx_timer.o
+common-obj-$(CONFIG_SLAVIO) += slavio_timer.o
+common-obj-$(CONFIG_ETRAXFS) += etraxfs_timer.o
+common-obj-$(CONFIG_GRLIB) += grlib_gptimer.o
+common-obj-$(CONFIG_IMX) += imx_timer.o
+common-obj-$(CONFIG_LM32) += lm32_timer.o
+common-obj-$(CONFIG_MILKYMIST) += milkymist-sysctl.o
+
+obj-$(CONFIG_EXYNOS4) += exynos4210_mct.o
+obj-$(CONFIG_EXYNOS4) += exynos4210_pwm.o
+obj-$(CONFIG_EXYNOS4) += exynos4210_rtc.o
+obj-$(CONFIG_OMAP) += omap_gptimer.o
+obj-$(CONFIG_OMAP) += omap_synctimer.o
+obj-$(CONFIG_PXA2XX) += pxa2xx_timer.o
+obj-$(CONFIG_SH4) += sh_timer.o
+obj-$(CONFIG_TUSB6010) += tusb6010.o
+
+obj-$(CONFIG_ARM_MPTIMER) += arm_mptimer.o
+obj-$(CONFIG_MC146818RTC) += mc146818rtc.o
diff --git a/hw/timer/arm_mptimer.c b/hw/timer/arm_mptimer.c
new file mode 100644 (file)
index 0000000..317f5e4
--- /dev/null
@@ -0,0 +1,309 @@
+/*
+ * Private peripheral timer/watchdog blocks for ARM 11MPCore and A9MP
+ *
+ * Copyright (c) 2006-2007 CodeSourcery.
+ * Copyright (c) 2011 Linaro Limited
+ * Written by Paul Brook, 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 "hw/sysbus.h"
+#include "qemu/timer.h"
+
+/* This device implements the per-cpu private timer and watchdog block
+ * which is used in both the ARM11MPCore and Cortex-A9MP.
+ */
+
+#define MAX_CPUS 4
+
+/* State of a single timer or watchdog block */
+typedef struct {
+    uint32_t count;
+    uint32_t load;
+    uint32_t control;
+    uint32_t status;
+    int64_t tick;
+    QEMUTimer *timer;
+    qemu_irq irq;
+    MemoryRegion iomem;
+} TimerBlock;
+
+typedef struct {
+    SysBusDevice busdev;
+    uint32_t num_cpu;
+    TimerBlock timerblock[MAX_CPUS];
+    MemoryRegion iomem;
+} ARMMPTimerState;
+
+static inline int get_current_cpu(ARMMPTimerState *s)
+{
+    CPUState *cpu_single_cpu = ENV_GET_CPU(cpu_single_env);
+
+    if (cpu_single_cpu->cpu_index >= s->num_cpu) {
+        hw_error("arm_mptimer: num-cpu %d but this cpu is %d!\n",
+                 s->num_cpu, cpu_single_cpu->cpu_index);
+    }
+    return cpu_single_cpu->cpu_index;
+}
+
+static inline void timerblock_update_irq(TimerBlock *tb)
+{
+    qemu_set_irq(tb->irq, tb->status);
+}
+
+/* Return conversion factor from mpcore timer ticks to qemu timer ticks.  */
+static inline uint32_t timerblock_scale(TimerBlock *tb)
+{
+    return (((tb->control >> 8) & 0xff) + 1) * 10;
+}
+
+static void timerblock_reload(TimerBlock *tb, int restart)
+{
+    if (tb->count == 0) {
+        return;
+    }
+    if (restart) {
+        tb->tick = qemu_get_clock_ns(vm_clock);
+    }
+    tb->tick += (int64_t)tb->count * timerblock_scale(tb);
+    qemu_mod_timer(tb->timer, tb->tick);
+}
+
+static void timerblock_tick(void *opaque)
+{
+    TimerBlock *tb = (TimerBlock *)opaque;
+    tb->status = 1;
+    if (tb->control & 2) {
+        tb->count = tb->load;
+        timerblock_reload(tb, 0);
+    } else {
+        tb->count = 0;
+    }
+    timerblock_update_irq(tb);
+}
+
+static uint64_t timerblock_read(void *opaque, hwaddr addr,
+                                unsigned size)
+{
+    TimerBlock *tb = (TimerBlock *)opaque;
+    int64_t val;
+    switch (addr) {
+    case 0: /* Load */
+        return tb->load;
+    case 4: /* Counter.  */
+        if (((tb->control & 1) == 0) || (tb->count == 0)) {
+            return 0;
+        }
+        /* Slow and ugly, but hopefully won't happen too often.  */
+        val = tb->tick - qemu_get_clock_ns(vm_clock);
+        val /= timerblock_scale(tb);
+        if (val < 0) {
+            val = 0;
+        }
+        return val;
+    case 8: /* Control.  */
+        return tb->control;
+    case 12: /* Interrupt status.  */
+        return tb->status;
+    default:
+        return 0;
+    }
+}
+
+static void timerblock_write(void *opaque, hwaddr addr,
+                             uint64_t value, unsigned size)
+{
+    TimerBlock *tb = (TimerBlock *)opaque;
+    int64_t old;
+    switch (addr) {
+    case 0: /* Load */
+        tb->load = value;
+        /* Fall through.  */
+    case 4: /* Counter.  */
+        if ((tb->control & 1) && tb->count) {
+            /* Cancel the previous timer.  */
+            qemu_del_timer(tb->timer);
+        }
+        tb->count = value;
+        if (tb->control & 1) {
+            timerblock_reload(tb, 1);
+        }
+        break;
+    case 8: /* Control.  */
+        old = tb->control;
+        tb->control = value;
+        if (((old & 1) == 0) && (value & 1)) {
+            if (tb->count == 0 && (tb->control & 2)) {
+                tb->count = tb->load;
+            }
+            timerblock_reload(tb, 1);
+        }
+        break;
+    case 12: /* Interrupt status.  */
+        tb->status &= ~value;
+        timerblock_update_irq(tb);
+        break;
+    }
+}
+
+/* Wrapper functions to implement the "read timer/watchdog for
+ * the current CPU" memory regions.
+ */
+static uint64_t arm_thistimer_read(void *opaque, hwaddr addr,
+                                   unsigned size)
+{
+    ARMMPTimerState *s = (ARMMPTimerState *)opaque;
+    int id = get_current_cpu(s);
+    return timerblock_read(&s->timerblock[id], addr, size);
+}
+
+static void arm_thistimer_write(void *opaque, hwaddr addr,
+                                uint64_t value, unsigned size)
+{
+    ARMMPTimerState *s = (ARMMPTimerState *)opaque;
+    int id = get_current_cpu(s);
+    timerblock_write(&s->timerblock[id], addr, value, size);
+}
+
+static const MemoryRegionOps arm_thistimer_ops = {
+    .read = arm_thistimer_read,
+    .write = arm_thistimer_write,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static const MemoryRegionOps timerblock_ops = {
+    .read = timerblock_read,
+    .write = timerblock_write,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void timerblock_reset(TimerBlock *tb)
+{
+    tb->count = 0;
+    tb->load = 0;
+    tb->control = 0;
+    tb->status = 0;
+    tb->tick = 0;
+    if (tb->timer) {
+        qemu_del_timer(tb->timer);
+    }
+}
+
+static void arm_mptimer_reset(DeviceState *dev)
+{
+    ARMMPTimerState *s =
+        FROM_SYSBUS(ARMMPTimerState, SYS_BUS_DEVICE(dev));
+    int i;
+    for (i = 0; i < ARRAY_SIZE(s->timerblock); i++) {
+        timerblock_reset(&s->timerblock[i]);
+    }
+}
+
+static int arm_mptimer_init(SysBusDevice *dev)
+{
+    ARMMPTimerState *s = FROM_SYSBUS(ARMMPTimerState, dev);
+    int i;
+    if (s->num_cpu < 1 || s->num_cpu > MAX_CPUS) {
+        hw_error("%s: num-cpu must be between 1 and %d\n", __func__, MAX_CPUS);
+    }
+    /* We implement one timer block per CPU, and expose multiple MMIO regions:
+     *  * region 0 is "timer for this core"
+     *  * region 1 is "timer for core 0"
+     *  * region 2 is "timer for core 1"
+     * and so on.
+     * The outgoing interrupt lines are
+     *  * timer for core 0
+     *  * timer for core 1
+     * and so on.
+     */
+    memory_region_init_io(&s->iomem, &arm_thistimer_ops, s,
+                          "arm_mptimer_timer", 0x20);
+    sysbus_init_mmio(dev, &s->iomem);
+    for (i = 0; i < s->num_cpu; i++) {
+        TimerBlock *tb = &s->timerblock[i];
+        tb->timer = qemu_new_timer_ns(vm_clock, timerblock_tick, tb);
+        sysbus_init_irq(dev, &tb->irq);
+        memory_region_init_io(&tb->iomem, &timerblock_ops, tb,
+                              "arm_mptimer_timerblock", 0x20);
+        sysbus_init_mmio(dev, &tb->iomem);
+    }
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_timerblock = {
+    .name = "arm_mptimer_timerblock",
+    .version_id = 2,
+    .minimum_version_id = 2,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(count, TimerBlock),
+        VMSTATE_UINT32(load, TimerBlock),
+        VMSTATE_UINT32(control, TimerBlock),
+        VMSTATE_UINT32(status, TimerBlock),
+        VMSTATE_INT64(tick, TimerBlock),
+        VMSTATE_TIMER(timer, TimerBlock),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_arm_mptimer = {
+    .name = "arm_mptimer",
+    .version_id = 2,
+    .minimum_version_id = 2,
+    .fields = (VMStateField[]) {
+        VMSTATE_STRUCT_VARRAY_UINT32(timerblock, ARMMPTimerState, num_cpu,
+                                     2, vmstate_timerblock, TimerBlock),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static Property arm_mptimer_properties[] = {
+    DEFINE_PROP_UINT32("num-cpu", ARMMPTimerState, 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 const TypeInfo arm_mptimer_info = {
+    .name          = "arm_mptimer",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(ARMMPTimerState),
+    .class_init    = arm_mptimer_class_init,
+};
+
+static void arm_mptimer_register_types(void)
+{
+    type_register_static(&arm_mptimer_info);
+}
+
+type_init(arm_mptimer_register_types)
diff --git a/hw/timer/arm_timer.c b/hw/timer/arm_timer.c
new file mode 100644 (file)
index 0000000..6449870
--- /dev/null
@@ -0,0 +1,399 @@
+/*
+ * ARM PrimeCell Timer modules.
+ *
+ * Copyright (c) 2005-2006 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the GPL.
+ */
+
+#include "hw/sysbus.h"
+#include "qemu/timer.h"
+#include "qemu-common.h"
+#include "hw/qdev.h"
+#include "hw/ptimer.h"
+
+/* Common timer implementation.  */
+
+#define TIMER_CTRL_ONESHOT      (1 << 0)
+#define TIMER_CTRL_32BIT        (1 << 1)
+#define TIMER_CTRL_DIV1         (0 << 2)
+#define TIMER_CTRL_DIV16        (1 << 2)
+#define TIMER_CTRL_DIV256       (2 << 2)
+#define TIMER_CTRL_IE           (1 << 5)
+#define TIMER_CTRL_PERIODIC     (1 << 6)
+#define TIMER_CTRL_ENABLE       (1 << 7)
+
+typedef struct {
+    ptimer_state *timer;
+    uint32_t control;
+    uint32_t limit;
+    int freq;
+    int int_level;
+    qemu_irq irq;
+} arm_timer_state;
+
+/* Check all active timers, and schedule the next timer interrupt.  */
+
+static void arm_timer_update(arm_timer_state *s)
+{
+    /* Update interrupts.  */
+    if (s->int_level && (s->control & TIMER_CTRL_IE)) {
+        qemu_irq_raise(s->irq);
+    } else {
+        qemu_irq_lower(s->irq);
+    }
+}
+
+static uint32_t arm_timer_read(void *opaque, hwaddr offset)
+{
+    arm_timer_state *s = (arm_timer_state *)opaque;
+
+    switch (offset >> 2) {
+    case 0: /* TimerLoad */
+    case 6: /* TimerBGLoad */
+        return s->limit;
+    case 1: /* TimerValue */
+        return ptimer_get_count(s->timer);
+    case 2: /* TimerControl */
+        return s->control;
+    case 4: /* TimerRIS */
+        return s->int_level;
+    case 5: /* TimerMIS */
+        if ((s->control & TIMER_CTRL_IE) == 0)
+            return 0;
+        return s->int_level;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: Bad offset %x\n", __func__, (int)offset);
+        return 0;
+    }
+}
+
+/* Reset the timer limit after settings have changed.  */
+static void arm_timer_recalibrate(arm_timer_state *s, int reload)
+{
+    uint32_t limit;
+
+    if ((s->control & (TIMER_CTRL_PERIODIC | TIMER_CTRL_ONESHOT)) == 0) {
+        /* Free running.  */
+        if (s->control & TIMER_CTRL_32BIT)
+            limit = 0xffffffff;
+        else
+            limit = 0xffff;
+    } else {
+          /* Periodic.  */
+          limit = s->limit;
+    }
+    ptimer_set_limit(s->timer, limit, reload);
+}
+
+static void arm_timer_write(void *opaque, hwaddr offset,
+                            uint32_t value)
+{
+    arm_timer_state *s = (arm_timer_state *)opaque;
+    int freq;
+
+    switch (offset >> 2) {
+    case 0: /* TimerLoad */
+        s->limit = value;
+        arm_timer_recalibrate(s, 1);
+        break;
+    case 1: /* TimerValue */
+        /* ??? Linux seems to want to write to this readonly register.
+           Ignore it.  */
+        break;
+    case 2: /* TimerControl */
+        if (s->control & TIMER_CTRL_ENABLE) {
+            /* Pause the timer if it is running.  This may cause some
+               inaccuracy dure to rounding, but avoids a whole lot of other
+               messyness.  */
+            ptimer_stop(s->timer);
+        }
+        s->control = value;
+        freq = s->freq;
+        /* ??? Need to recalculate expiry time after changing divisor.  */
+        switch ((value >> 2) & 3) {
+        case 1: freq >>= 4; break;
+        case 2: freq >>= 8; break;
+        }
+        arm_timer_recalibrate(s, s->control & TIMER_CTRL_ENABLE);
+        ptimer_set_freq(s->timer, freq);
+        if (s->control & TIMER_CTRL_ENABLE) {
+            /* Restart the timer if still enabled.  */
+            ptimer_run(s->timer, (s->control & TIMER_CTRL_ONESHOT) != 0);
+        }
+        break;
+    case 3: /* TimerIntClr */
+        s->int_level = 0;
+        break;
+    case 6: /* TimerBGLoad */
+        s->limit = value;
+        arm_timer_recalibrate(s, 0);
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: Bad offset %x\n", __func__, (int)offset);
+    }
+    arm_timer_update(s);
+}
+
+static void arm_timer_tick(void *opaque)
+{
+    arm_timer_state *s = (arm_timer_state *)opaque;
+    s->int_level = 1;
+    arm_timer_update(s);
+}
+
+static const VMStateDescription vmstate_arm_timer = {
+    .name = "arm_timer",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32(control, arm_timer_state),
+        VMSTATE_UINT32(limit, arm_timer_state),
+        VMSTATE_INT32(int_level, arm_timer_state),
+        VMSTATE_PTIMER(timer, arm_timer_state),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static arm_timer_state *arm_timer_init(uint32_t freq)
+{
+    arm_timer_state *s;
+    QEMUBH *bh;
+
+    s = (arm_timer_state *)g_malloc0(sizeof(arm_timer_state));
+    s->freq = freq;
+    s->control = TIMER_CTRL_IE;
+
+    bh = qemu_bh_new(arm_timer_tick, s);
+    s->timer = ptimer_init(bh);
+    vmstate_register(NULL, -1, &vmstate_arm_timer, s);
+    return s;
+}
+
+/* ARM PrimeCell SP804 dual timer module.
+ * Docs at
+ * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0271d/index.html
+*/
+
+typedef struct {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    arm_timer_state *timer[2];
+    uint32_t freq0, freq1;
+    int level[2];
+    qemu_irq irq;
+} sp804_state;
+
+static const uint8_t sp804_ids[] = {
+    /* Timer ID */
+    0x04, 0x18, 0x14, 0,
+    /* PrimeCell ID */
+    0xd, 0xf0, 0x05, 0xb1
+};
+
+/* Merge the IRQs from the two component devices.  */
+static void sp804_set_irq(void *opaque, int irq, int level)
+{
+    sp804_state *s = (sp804_state *)opaque;
+
+    s->level[irq] = level;
+    qemu_set_irq(s->irq, s->level[0] || s->level[1]);
+}
+
+static uint64_t sp804_read(void *opaque, hwaddr offset,
+                           unsigned size)
+{
+    sp804_state *s = (sp804_state *)opaque;
+
+    if (offset < 0x20) {
+        return arm_timer_read(s->timer[0], offset);
+    }
+    if (offset < 0x40) {
+        return arm_timer_read(s->timer[1], offset - 0x20);
+    }
+
+    /* TimerPeriphID */
+    if (offset >= 0xfe0 && offset <= 0xffc) {
+        return sp804_ids[(offset - 0xfe0) >> 2];
+    }
+
+    switch (offset) {
+    /* Integration Test control registers, which we won't support */
+    case 0xf00: /* TimerITCR */
+    case 0xf04: /* TimerITOP (strictly write only but..) */
+        qemu_log_mask(LOG_UNIMP,
+                      "%s: integration test registers unimplemented\n",
+                      __func__);
+        return 0;
+    }
+
+    qemu_log_mask(LOG_GUEST_ERROR,
+                  "%s: Bad offset %x\n", __func__, (int)offset);
+    return 0;
+}
+
+static void sp804_write(void *opaque, hwaddr offset,
+                        uint64_t value, unsigned size)
+{
+    sp804_state *s = (sp804_state *)opaque;
+
+    if (offset < 0x20) {
+        arm_timer_write(s->timer[0], offset, value);
+        return;
+    }
+
+    if (offset < 0x40) {
+        arm_timer_write(s->timer[1], offset - 0x20, value);
+        return;
+    }
+
+    /* Technically we could be writing to the Test Registers, but not likely */
+    qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %x\n",
+                  __func__, (int)offset);
+}
+
+static const MemoryRegionOps sp804_ops = {
+    .read = sp804_read,
+    .write = sp804_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static const VMStateDescription vmstate_sp804 = {
+    .name = "sp804",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_INT32_ARRAY(level, sp804_state, 2),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int sp804_init(SysBusDevice *dev)
+{
+    sp804_state *s = FROM_SYSBUS(sp804_state, dev);
+    qemu_irq *qi;
+
+    qi = qemu_allocate_irqs(sp804_set_irq, s, 2);
+    sysbus_init_irq(dev, &s->irq);
+    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);
+    sysbus_init_mmio(dev, &s->iomem);
+    vmstate_register(&dev->qdev, -1, &vmstate_sp804, s);
+    return 0;
+}
+
+/* Integrator/CP timer module.  */
+
+typedef struct {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    arm_timer_state *timer[3];
+} icp_pit_state;
+
+static uint64_t icp_pit_read(void *opaque, hwaddr offset,
+                             unsigned size)
+{
+    icp_pit_state *s = (icp_pit_state *)opaque;
+    int n;
+
+    /* ??? Don't know the PrimeCell ID for this device.  */
+    n = offset >> 8;
+    if (n > 2) {
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad timer %d\n", __func__, n);
+    }
+
+    return arm_timer_read(s->timer[n], offset & 0xff);
+}
+
+static void icp_pit_write(void *opaque, hwaddr offset,
+                          uint64_t value, unsigned size)
+{
+    icp_pit_state *s = (icp_pit_state *)opaque;
+    int n;
+
+    n = offset >> 8;
+    if (n > 2) {
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad timer %d\n", __func__, n);
+    }
+
+    arm_timer_write(s->timer[n], offset & 0xff, value);
+}
+
+static const MemoryRegionOps icp_pit_ops = {
+    .read = icp_pit_read,
+    .write = icp_pit_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int icp_pit_init(SysBusDevice *dev)
+{
+    icp_pit_state *s = FROM_SYSBUS(icp_pit_state, dev);
+
+    /* Timer 0 runs at the system clock speed (40MHz).  */
+    s->timer[0] = arm_timer_init(40000000);
+    /* The other two timers run at 1MHz.  */
+    s->timer[1] = arm_timer_init(1000000);
+    s->timer[2] = arm_timer_init(1000000);
+
+    sysbus_init_irq(dev, &s->timer[0]->irq);
+    sysbus_init_irq(dev, &s->timer[1]->irq);
+    sysbus_init_irq(dev, &s->timer[2]->irq);
+
+    memory_region_init_io(&s->iomem, &icp_pit_ops, s, "icp_pit", 0x1000);
+    sysbus_init_mmio(dev, &s->iomem);
+    /* This device has no state to save/restore.  The component timers will
+       save themselves.  */
+    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 const 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 const 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_types(void)
+{
+    type_register_static(&icp_pit_info);
+    type_register_static(&sp804_info);
+}
+
+type_init(arm_timer_register_types)
diff --git a/hw/timer/cadence_ttc.c b/hw/timer/cadence_ttc.c
new file mode 100644 (file)
index 0000000..ba584f4
--- /dev/null
@@ -0,0 +1,489 @@
+/*
+ * Xilinx Zynq cadence TTC model
+ *
+ * Copyright (c) 2011 Xilinx Inc.
+ * Copyright (c) 2012 Peter A.G. Crosthwaite (peter.crosthwaite@petalogix.com)
+ * Copyright (c) 2012 PetaLogix Pty Ltd.
+ * Written By Haibing Ma
+ *            M. Habib
+ *
+ * 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.
+ *
+ * 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 "hw/sysbus.h"
+#include "qemu/timer.h"
+
+#ifdef CADENCE_TTC_ERR_DEBUG
+#define DB_PRINT(...) do { \
+    fprintf(stderr,  ": %s: ", __func__); \
+    fprintf(stderr, ## __VA_ARGS__); \
+    } while (0);
+#else
+    #define DB_PRINT(...)
+#endif
+
+#define COUNTER_INTR_IV     0x00000001
+#define COUNTER_INTR_M1     0x00000002
+#define COUNTER_INTR_M2     0x00000004
+#define COUNTER_INTR_M3     0x00000008
+#define COUNTER_INTR_OV     0x00000010
+#define COUNTER_INTR_EV     0x00000020
+
+#define COUNTER_CTRL_DIS    0x00000001
+#define COUNTER_CTRL_INT    0x00000002
+#define COUNTER_CTRL_DEC    0x00000004
+#define COUNTER_CTRL_MATCH  0x00000008
+#define COUNTER_CTRL_RST    0x00000010
+
+#define CLOCK_CTRL_PS_EN    0x00000001
+#define CLOCK_CTRL_PS_V     0x0000001e
+
+typedef struct {
+    QEMUTimer *timer;
+    int freq;
+
+    uint32_t reg_clock;
+    uint32_t reg_count;
+    uint32_t reg_value;
+    uint16_t reg_interval;
+    uint16_t reg_match[3];
+    uint32_t reg_intr;
+    uint32_t reg_intr_en;
+    uint32_t reg_event_ctrl;
+    uint32_t reg_event;
+
+    uint64_t cpu_time;
+    unsigned int cpu_time_valid;
+
+    qemu_irq irq;
+} CadenceTimerState;
+
+typedef struct {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    CadenceTimerState timer[3];
+} CadenceTTCState;
+
+static void cadence_timer_update(CadenceTimerState *s)
+{
+    qemu_set_irq(s->irq, !!(s->reg_intr & s->reg_intr_en));
+}
+
+static CadenceTimerState *cadence_timer_from_addr(void *opaque,
+                                        hwaddr offset)
+{
+    unsigned int index;
+    CadenceTTCState *s = (CadenceTTCState *)opaque;
+
+    index = (offset >> 2) % 3;
+
+    return &s->timer[index];
+}
+
+static uint64_t cadence_timer_get_ns(CadenceTimerState *s, uint64_t timer_steps)
+{
+    /* timer_steps has max value of 0x100000000. double check it
+     * (or overflow can happen below) */
+    assert(timer_steps <= 1ULL << 32);
+
+    uint64_t r = timer_steps * 1000000000ULL;
+    if (s->reg_clock & CLOCK_CTRL_PS_EN) {
+        r >>= 16 - (((s->reg_clock & CLOCK_CTRL_PS_V) >> 1) + 1);
+    } else {
+        r >>= 16;
+    }
+    r /= (uint64_t)s->freq;
+    return r;
+}
+
+static uint64_t cadence_timer_get_steps(CadenceTimerState *s, uint64_t ns)
+{
+    uint64_t to_divide = 1000000000ULL;
+
+    uint64_t r = ns;
+     /* for very large intervals (> 8s) do some division first to stop
+      * overflow (costs some prescision) */
+    while (r >= 8ULL << 30 && to_divide > 1) {
+        r /= 1000;
+        to_divide /= 1000;
+    }
+    r <<= 16;
+    /* keep early-dividing as needed */
+    while (r >= 8ULL << 30 && to_divide > 1) {
+        r /= 1000;
+        to_divide /= 1000;
+    }
+    r *= (uint64_t)s->freq;
+    if (s->reg_clock & CLOCK_CTRL_PS_EN) {
+        r /= 1 << (((s->reg_clock & CLOCK_CTRL_PS_V) >> 1) + 1);
+    }
+
+    r /= to_divide;
+    return r;
+}
+
+/* determine if x is in between a and b, exclusive of a, inclusive of b */
+
+static inline int64_t is_between(int64_t x, int64_t a, int64_t b)
+{
+    if (a < b) {
+        return x > a && x <= b;
+    }
+    return x < a && x >= b;
+}
+
+static void cadence_timer_run(CadenceTimerState *s)
+{
+    int i;
+    int64_t event_interval, next_value;
+
+    assert(s->cpu_time_valid); /* cadence_timer_sync must be called first */
+
+    if (s->reg_count & COUNTER_CTRL_DIS) {
+        s->cpu_time_valid = 0;
+        return;
+    }
+
+    { /* figure out what's going to happen next (rollover or match) */
+        int64_t interval = (uint64_t)((s->reg_count & COUNTER_CTRL_INT) ?
+                (int64_t)s->reg_interval + 1 : 0x10000ULL) << 16;
+        next_value = (s->reg_count & COUNTER_CTRL_DEC) ? -1ULL : interval;
+        for (i = 0; i < 3; ++i) {
+            int64_t cand = (uint64_t)s->reg_match[i] << 16;
+            if (is_between(cand, (uint64_t)s->reg_value, next_value)) {
+                next_value = cand;
+            }
+        }
+    }
+    DB_PRINT("next timer event value: %09llx\n",
+            (unsigned long long)next_value);
+
+    event_interval = next_value - (int64_t)s->reg_value;
+    event_interval = (event_interval < 0) ? -event_interval : event_interval;
+
+    qemu_mod_timer(s->timer, s->cpu_time +
+                cadence_timer_get_ns(s, event_interval));
+}
+
+static void cadence_timer_sync(CadenceTimerState *s)
+{
+    int i;
+    int64_t r, x;
+    int64_t interval = ((s->reg_count & COUNTER_CTRL_INT) ?
+            (int64_t)s->reg_interval + 1 : 0x10000ULL) << 16;
+    uint64_t old_time = s->cpu_time;
+
+    s->cpu_time = qemu_get_clock_ns(vm_clock);
+    DB_PRINT("cpu time: %lld ns\n", (long long)old_time);
+
+    if (!s->cpu_time_valid || old_time == s->cpu_time) {
+        s->cpu_time_valid = 1;
+        return;
+    }
+
+    r = (int64_t)cadence_timer_get_steps(s, s->cpu_time - old_time);
+    x = (int64_t)s->reg_value + ((s->reg_count & COUNTER_CTRL_DEC) ? -r : r);
+
+    for (i = 0; i < 3; ++i) {
+        int64_t m = (int64_t)s->reg_match[i] << 16;
+        if (m > interval) {
+            continue;
+        }
+        /* check to see if match event has occurred. check m +/- interval
+         * to account for match events in wrap around cases */
+        if (is_between(m, s->reg_value, x) ||
+            is_between(m + interval, s->reg_value, x) ||
+            is_between(m - interval, s->reg_value, x)) {
+            s->reg_intr |= (2 << i);
+        }
+    }
+    while (x < 0) {
+        x += interval;
+    }
+    s->reg_value = (uint32_t)(x % interval);
+
+    if (s->reg_value != x) {
+        s->reg_intr |= (s->reg_count & COUNTER_CTRL_INT) ?
+            COUNTER_INTR_IV : COUNTER_INTR_OV;
+    }
+    cadence_timer_update(s);
+}
+
+static void cadence_timer_tick(void *opaque)
+{
+    CadenceTimerState *s = opaque;
+
+    DB_PRINT("\n");
+    cadence_timer_sync(s);
+    cadence_timer_run(s);
+}
+
+static uint32_t cadence_ttc_read_imp(void *opaque, hwaddr offset)
+{
+    CadenceTimerState *s = cadence_timer_from_addr(opaque, offset);
+    uint32_t value;
+
+    cadence_timer_sync(s);
+    cadence_timer_run(s);
+
+    switch (offset) {
+    case 0x00: /* clock control */
+    case 0x04:
+    case 0x08:
+        return s->reg_clock;
+
+    case 0x0c: /* counter control */
+    case 0x10:
+    case 0x14:
+        return s->reg_count;
+
+    case 0x18: /* counter value */
+    case 0x1c:
+    case 0x20:
+        return (uint16_t)(s->reg_value >> 16);
+
+    case 0x24: /* reg_interval counter */
+    case 0x28:
+    case 0x2c:
+        return s->reg_interval;
+
+    case 0x30: /* match 1 counter */
+    case 0x34:
+    case 0x38:
+        return s->reg_match[0];
+
+    case 0x3c: /* match 2 counter */
+    case 0x40:
+    case 0x44:
+        return s->reg_match[1];
+
+    case 0x48: /* match 3 counter */
+    case 0x4c:
+    case 0x50:
+        return s->reg_match[2];
+
+    case 0x54: /* interrupt register */
+    case 0x58:
+    case 0x5c:
+        /* cleared after read */
+        value = s->reg_intr;
+        s->reg_intr = 0;
+        cadence_timer_update(s);
+        return value;
+
+    case 0x60: /* interrupt enable */
+    case 0x64:
+    case 0x68:
+        return s->reg_intr_en;
+
+    case 0x6c:
+    case 0x70:
+    case 0x74:
+        return s->reg_event_ctrl;
+
+    case 0x78:
+    case 0x7c:
+    case 0x80:
+        return s->reg_event;
+
+    default:
+        return 0;
+    }
+}
+
+static uint64_t cadence_ttc_read(void *opaque, hwaddr offset,
+    unsigned size)
+{
+    uint32_t ret = cadence_ttc_read_imp(opaque, offset);
+
+    DB_PRINT("addr: %08x data: %08x\n", (unsigned)offset, (unsigned)ret);
+    return ret;
+}
+
+static void cadence_ttc_write(void *opaque, hwaddr offset,
+        uint64_t value, unsigned size)
+{
+    CadenceTimerState *s = cadence_timer_from_addr(opaque, offset);
+
+    DB_PRINT("addr: %08x data %08x\n", (unsigned)offset, (unsigned)value);
+
+    cadence_timer_sync(s);
+
+    switch (offset) {
+    case 0x00: /* clock control */
+    case 0x04:
+    case 0x08:
+        s->reg_clock = value & 0x3F;
+        break;
+
+    case 0x0c: /* counter control */
+    case 0x10:
+    case 0x14:
+        if (value & COUNTER_CTRL_RST) {
+            s->reg_value = 0;
+        }
+        s->reg_count = value & 0x3f & ~COUNTER_CTRL_RST;
+        break;
+
+    case 0x24: /* interval register */
+    case 0x28:
+    case 0x2c:
+        s->reg_interval = value & 0xffff;
+        break;
+
+    case 0x30: /* match register */
+    case 0x34:
+    case 0x38:
+        s->reg_match[0] = value & 0xffff;
+
+    case 0x3c: /* match register */
+    case 0x40:
+    case 0x44:
+        s->reg_match[1] = value & 0xffff;
+
+    case 0x48: /* match register */
+    case 0x4c:
+    case 0x50:
+        s->reg_match[2] = value & 0xffff;
+        break;
+
+    case 0x54: /* interrupt register */
+    case 0x58:
+    case 0x5c:
+        break;
+
+    case 0x60: /* interrupt enable */
+    case 0x64:
+    case 0x68:
+        s->reg_intr_en = value & 0x3f;
+        break;
+
+    case 0x6c: /* event control */
+    case 0x70:
+    case 0x74:
+        s->reg_event_ctrl = value & 0x07;
+        break;
+
+    default:
+        return;
+    }
+
+    cadence_timer_run(s);
+    cadence_timer_update(s);
+}
+
+static const MemoryRegionOps cadence_ttc_ops = {
+    .read = cadence_ttc_read,
+    .write = cadence_ttc_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void cadence_timer_reset(CadenceTimerState *s)
+{
+   s->reg_count = 0x21;
+}
+
+static void cadence_timer_init(uint32_t freq, CadenceTimerState *s)
+{
+    memset(s, 0, sizeof(CadenceTimerState));
+    s->freq = freq;
+
+    cadence_timer_reset(s);
+
+    s->timer = qemu_new_timer_ns(vm_clock, cadence_timer_tick, s);
+}
+
+static int cadence_ttc_init(SysBusDevice *dev)
+{
+    CadenceTTCState *s = FROM_SYSBUS(CadenceTTCState, dev);
+    int i;
+
+    for (i = 0; i < 3; ++i) {
+        cadence_timer_init(133000000, &s->timer[i]);
+        sysbus_init_irq(dev, &s->timer[i].irq);
+    }
+
+    memory_region_init_io(&s->iomem, &cadence_ttc_ops, s, "timer", 0x1000);
+    sysbus_init_mmio(dev, &s->iomem);
+
+    return 0;
+}
+
+static void cadence_timer_pre_save(void *opaque)
+{
+    cadence_timer_sync((CadenceTimerState *)opaque);
+}
+
+static int cadence_timer_post_load(void *opaque, int version_id)
+{
+    CadenceTimerState *s = opaque;
+
+    s->cpu_time_valid = 0;
+    cadence_timer_sync(s);
+    cadence_timer_run(s);
+    cadence_timer_update(s);
+    return 0;
+}
+
+static const VMStateDescription vmstate_cadence_timer = {
+    .name = "cadence_timer",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .pre_save = cadence_timer_pre_save,
+    .post_load = cadence_timer_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(reg_clock, CadenceTimerState),
+        VMSTATE_UINT32(reg_count, CadenceTimerState),
+        VMSTATE_UINT32(reg_value, CadenceTimerState),
+        VMSTATE_UINT16(reg_interval, CadenceTimerState),
+        VMSTATE_UINT16_ARRAY(reg_match, CadenceTimerState, 3),
+        VMSTATE_UINT32(reg_intr, CadenceTimerState),
+        VMSTATE_UINT32(reg_intr_en, CadenceTimerState),
+        VMSTATE_UINT32(reg_event_ctrl, CadenceTimerState),
+        VMSTATE_UINT32(reg_event, CadenceTimerState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_cadence_ttc = {
+    .name = "cadence_TTC",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_STRUCT_ARRAY(timer, CadenceTTCState, 3, 0,
+                            vmstate_cadence_timer,
+                            CadenceTimerState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void cadence_ttc_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sdc->init = cadence_ttc_init;
+    dc->vmsd = &vmstate_cadence_ttc;
+}
+
+static const TypeInfo cadence_ttc_info = {
+    .name  = "cadence_ttc",
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size  = sizeof(CadenceTTCState),
+    .class_init = cadence_ttc_class_init,
+};
+
+static void cadence_ttc_register_types(void)
+{
+    type_register_static(&cadence_ttc_info);
+}
+
+type_init(cadence_ttc_register_types)
diff --git a/hw/timer/ds1338.c b/hw/timer/ds1338.c
new file mode 100644 (file)
index 0000000..8987cdc
--- /dev/null
@@ -0,0 +1,236 @@
+/*
+ * MAXIM DS1338 I2C RTC+NVRAM
+ *
+ * Copyright (c) 2009 CodeSourcery.
+ * 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 "hw/i2c/i2c.h"
+
+/* Size of NVRAM including both the user-accessible area and the
+ * secondary register area.
+ */
+#define NVRAM_SIZE 64
+
+/* Flags definitions */
+#define SECONDS_CH 0x80
+#define HOURS_12   0x40
+#define HOURS_PM   0x20
+#define CTRL_OSF   0x20
+
+typedef struct {
+    I2CSlave i2c;
+    int64_t offset;
+    uint8_t wday_offset;
+    uint8_t nvram[NVRAM_SIZE];
+    int32_t ptr;
+    bool addr_byte;
+} DS1338State;
+
+static const VMStateDescription vmstate_ds1338 = {
+    .name = "ds1338",
+    .version_id = 2,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_I2C_SLAVE(i2c, DS1338State),
+        VMSTATE_INT64(offset, DS1338State),
+        VMSTATE_UINT8_V(wday_offset, DS1338State, 2),
+        VMSTATE_UINT8_ARRAY(nvram, DS1338State, NVRAM_SIZE),
+        VMSTATE_INT32(ptr, DS1338State),
+        VMSTATE_BOOL(addr_byte, DS1338State),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void capture_current_time(DS1338State *s)
+{
+    /* Capture the current time into the secondary registers
+     * which will be actually read by the data transfer operation.
+     */
+    struct tm now;
+    qemu_get_timedate(&now, s->offset);
+    s->nvram[0] = to_bcd(now.tm_sec);
+    s->nvram[1] = to_bcd(now.tm_min);
+    if (s->nvram[2] & HOURS_12) {
+        int tmp = now.tm_hour;
+        if (tmp % 12 == 0) {
+            tmp += 12;
+        }
+        if (tmp <= 12) {
+            s->nvram[2] = HOURS_12 | to_bcd(tmp);
+        } else {
+            s->nvram[2] = HOURS_12 | HOURS_PM | to_bcd(tmp - 12);
+        }
+    } else {
+        s->nvram[2] = to_bcd(now.tm_hour);
+    }
+    s->nvram[3] = (now.tm_wday + s->wday_offset) % 7 + 1;
+    s->nvram[4] = to_bcd(now.tm_mday);
+    s->nvram[5] = to_bcd(now.tm_mon + 1);
+    s->nvram[6] = to_bcd(now.tm_year - 100);
+}
+
+static void inc_regptr(DS1338State *s)
+{
+    /* The register pointer wraps around after 0x3F; wraparound
+     * causes the current time/date to be retransferred into
+     * the secondary registers.
+     */
+    s->ptr = (s->ptr + 1) & (NVRAM_SIZE - 1);
+    if (!s->ptr) {
+        capture_current_time(s);
+    }
+}
+
+static void ds1338_event(I2CSlave *i2c, enum i2c_event event)
+{
+    DS1338State *s = FROM_I2C_SLAVE(DS1338State, i2c);
+
+    switch (event) {
+    case I2C_START_RECV:
+        /* In h/w, capture happens on any START condition, not just a
+         * START_RECV, but there is no need to actually capture on
+         * START_SEND, because the guest can't get at that data
+         * without going through a START_RECV which would overwrite it.
+         */
+        capture_current_time(s);
+        break;
+    case I2C_START_SEND:
+        s->addr_byte = true;
+        break;
+    default:
+        break;
+    }
+}
+
+static int ds1338_recv(I2CSlave *i2c)
+{
+    DS1338State *s = FROM_I2C_SLAVE(DS1338State, i2c);
+    uint8_t res;
+
+    res  = s->nvram[s->ptr];
+    inc_regptr(s);
+    return res;
+}
+
+static int ds1338_send(I2CSlave *i2c, uint8_t data)
+{
+    DS1338State *s = FROM_I2C_SLAVE(DS1338State, i2c);
+    if (s->addr_byte) {
+        s->ptr = data & (NVRAM_SIZE - 1);
+        s->addr_byte = false;
+        return 0;
+    }
+    if (s->ptr < 7) {
+        /* Time register. */
+        struct tm now;
+        qemu_get_timedate(&now, s->offset);
+        switch(s->ptr) {
+        case 0:
+            /* TODO: Implement CH (stop) bit.  */
+            now.tm_sec = from_bcd(data & 0x7f);
+            break;
+        case 1:
+            now.tm_min = from_bcd(data & 0x7f);
+            break;
+        case 2:
+            if (data & HOURS_12) {
+                int tmp = from_bcd(data & (HOURS_PM - 1));
+                if (data & HOURS_PM) {
+                    tmp += 12;
+                }
+                if (tmp % 12 == 0) {
+                    tmp -= 12;
+                }
+                now.tm_hour = tmp;
+            } else {
+                now.tm_hour = from_bcd(data & (HOURS_12 - 1));
+            }
+            break;
+        case 3:
+            {
+                /* The day field is supposed to contain a value in
+                   the range 1-7. Otherwise behavior is undefined.
+                 */
+                int user_wday = (data & 7) - 1;
+                s->wday_offset = (user_wday - now.tm_wday + 7) % 7;
+            }
+            break;
+        case 4:
+            now.tm_mday = from_bcd(data & 0x3f);
+            break;
+        case 5:
+            now.tm_mon = from_bcd(data & 0x1f) - 1;
+            break;
+        case 6:
+            now.tm_year = from_bcd(data) + 100;
+            break;
+        }
+        s->offset = qemu_timedate_diff(&now);
+    } else if (s->ptr == 7) {
+        /* Control register. */
+
+        /* Ensure bits 2, 3 and 6 will read back as zero. */
+        data &= 0xB3;
+
+        /* Attempting to write the OSF flag to logic 1 leaves the
+           value unchanged. */
+        data = (data & ~CTRL_OSF) | (data & s->nvram[s->ptr] & CTRL_OSF);
+
+        s->nvram[s->ptr] = data;
+    } else {
+        s->nvram[s->ptr] = data;
+    }
+    inc_regptr(s);
+    return 0;
+}
+
+static int ds1338_init(I2CSlave *i2c)
+{
+    return 0;
+}
+
+static void ds1338_reset(DeviceState *dev)
+{
+    DS1338State *s = FROM_I2C_SLAVE(DS1338State, I2C_SLAVE(dev));
+
+    /* The clock is running and synchronized with the host */
+    s->offset = 0;
+    s->wday_offset = 0;
+    memset(s->nvram, 0, NVRAM_SIZE);
+    s->ptr = 0;
+    s->addr_byte = false;
+}
+
+static void ds1338_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
+
+    k->init = ds1338_init;
+    k->event = ds1338_event;
+    k->recv = ds1338_recv;
+    k->send = ds1338_send;
+    dc->reset = ds1338_reset;
+    dc->vmsd = &vmstate_ds1338;
+}
+
+static const TypeInfo ds1338_info = {
+    .name          = "ds1338",
+    .parent        = TYPE_I2C_SLAVE,
+    .instance_size = sizeof(DS1338State),
+    .class_init    = ds1338_class_init,
+};
+
+static void ds1338_register_types(void)
+{
+    type_register_static(&ds1338_info);
+}
+
+type_init(ds1338_register_types)
diff --git a/hw/timer/etraxfs_timer.c b/hw/timer/etraxfs_timer.c
new file mode 100644 (file)
index 0000000..3cd9476
--- /dev/null
@@ -0,0 +1,351 @@
+/*
+ * QEMU ETRAX Timers
+ *
+ * Copyright (c) 2007 Edgar E. Iglesias, Axis Communications AB.
+ *
+ * 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 "hw/sysbus.h"
+#include "sysemu/sysemu.h"
+#include "qemu/timer.h"
+#include "hw/ptimer.h"
+
+#define D(x)
+
+#define RW_TMR0_DIV   0x00
+#define R_TMR0_DATA   0x04
+#define RW_TMR0_CTRL  0x08
+#define RW_TMR1_DIV   0x10
+#define R_TMR1_DATA   0x14
+#define RW_TMR1_CTRL  0x18
+#define R_TIME        0x38
+#define RW_WD_CTRL    0x40
+#define R_WD_STAT     0x44
+#define RW_INTR_MASK  0x48
+#define RW_ACK_INTR   0x4c
+#define R_INTR        0x50
+#define R_MASKED_INTR 0x54
+
+struct etrax_timer {
+    SysBusDevice busdev;
+    MemoryRegion mmio;
+    qemu_irq irq;
+    qemu_irq nmi;
+
+    QEMUBH *bh_t0;
+    QEMUBH *bh_t1;
+    QEMUBH *bh_wd;
+    ptimer_state *ptimer_t0;
+    ptimer_state *ptimer_t1;
+    ptimer_state *ptimer_wd;
+
+    int wd_hits;
+
+    /* Control registers.  */
+    uint32_t rw_tmr0_div;
+    uint32_t r_tmr0_data;
+    uint32_t rw_tmr0_ctrl;
+
+    uint32_t rw_tmr1_div;
+    uint32_t r_tmr1_data;
+    uint32_t rw_tmr1_ctrl;
+
+    uint32_t rw_wd_ctrl;
+
+    uint32_t rw_intr_mask;
+    uint32_t rw_ack_intr;
+    uint32_t r_intr;
+    uint32_t r_masked_intr;
+};
+
+static uint64_t
+timer_read(void *opaque, hwaddr addr, unsigned int size)
+{
+    struct etrax_timer *t = opaque;
+    uint32_t r = 0;
+
+    switch (addr) {
+    case R_TMR0_DATA:
+        r = ptimer_get_count(t->ptimer_t0);
+        break;
+    case R_TMR1_DATA:
+        r = ptimer_get_count(t->ptimer_t1);
+        break;
+    case R_TIME:
+        r = qemu_get_clock_ns(vm_clock) / 10;
+        break;
+    case RW_INTR_MASK:
+        r = t->rw_intr_mask;
+        break;
+    case R_MASKED_INTR:
+        r = t->r_intr & t->rw_intr_mask;
+        break;
+    default:
+        D(printf ("%s %x\n", __func__, addr));
+        break;
+    }
+    return r;
+}
+
+static void update_ctrl(struct etrax_timer *t, int tnum)
+{
+    unsigned int op;
+    unsigned int freq;
+    unsigned int freq_hz;
+    unsigned int div;
+    uint32_t ctrl;
+
+    ptimer_state *timer;
+
+    if (tnum == 0) {
+        ctrl = t->rw_tmr0_ctrl;
+        div = t->rw_tmr0_div;
+        timer = t->ptimer_t0;
+    } else {
+        ctrl = t->rw_tmr1_ctrl;
+        div = t->rw_tmr1_div;
+        timer = t->ptimer_t1;
+    }
+
+
+    op = ctrl & 3;
+    freq = ctrl >> 2;
+    freq_hz = 32000000;
+
+    switch (freq)
+    {
+    case 0:
+    case 1:
+        D(printf ("extern or disabled timer clock?\n"));
+        break;
+    case 4: freq_hz =  29493000; break;
+    case 5: freq_hz =  32000000; break;
+    case 6: freq_hz =  32768000; break;
+    case 7: freq_hz = 100000000; break;
+    default:
+        abort();
+        break;
+    }
+
+    D(printf ("freq_hz=%d div=%d\n", freq_hz, div));
+    ptimer_set_freq(timer, freq_hz);
+    ptimer_set_limit(timer, div, 0);
+
+    switch (op)
+    {
+        case 0:
+            /* Load.  */
+            ptimer_set_limit(timer, div, 1);
+            break;
+        case 1:
+            /* Hold.  */
+            ptimer_stop(timer);
+            break;
+        case 2:
+            /* Run.  */
+            ptimer_run(timer, 0);
+            break;
+        default:
+            abort();
+            break;
+    }
+}
+
+static void timer_update_irq(struct etrax_timer *t)
+{
+    t->r_intr &= ~(t->rw_ack_intr);
+    t->r_masked_intr = t->r_intr & t->rw_intr_mask;
+
+    D(printf("%s: masked_intr=%x\n", __func__, t->r_masked_intr));
+    qemu_set_irq(t->irq, !!t->r_masked_intr);
+}
+
+static void timer0_hit(void *opaque)
+{
+    struct etrax_timer *t = opaque;
+    t->r_intr |= 1;
+    timer_update_irq(t);
+}
+
+static void timer1_hit(void *opaque)
+{
+    struct etrax_timer *t = opaque;
+    t->r_intr |= 2;
+    timer_update_irq(t);
+}
+
+static void watchdog_hit(void *opaque)
+{
+    struct etrax_timer *t = opaque;
+    if (t->wd_hits == 0) {
+        /* real hw gives a single tick before reseting but we are
+           a bit friendlier to compensate for our slower execution.  */
+        ptimer_set_count(t->ptimer_wd, 10);
+        ptimer_run(t->ptimer_wd, 1);
+        qemu_irq_raise(t->nmi);
+    }
+    else
+        qemu_system_reset_request();
+
+    t->wd_hits++;
+}
+
+static inline void timer_watchdog_update(struct etrax_timer *t, uint32_t value)
+{
+    unsigned int wd_en = t->rw_wd_ctrl & (1 << 8);
+    unsigned int wd_key = t->rw_wd_ctrl >> 9;
+    unsigned int wd_cnt = t->rw_wd_ctrl & 511;
+    unsigned int new_key = value >> 9 & ((1 << 7) - 1);
+    unsigned int new_cmd = (value >> 8) & 1;
+
+    /* If the watchdog is enabled, they written key must match the
+       complement of the previous.  */
+    wd_key = ~wd_key & ((1 << 7) - 1);
+
+    if (wd_en && wd_key != new_key)
+        return;
+
+    D(printf("en=%d new_key=%x oldkey=%x cmd=%d cnt=%d\n", 
+         wd_en, new_key, wd_key, new_cmd, wd_cnt));
+
+    if (t->wd_hits)
+        qemu_irq_lower(t->nmi);
+
+    t->wd_hits = 0;
+
+    ptimer_set_freq(t->ptimer_wd, 760);
+    if (wd_cnt == 0)
+        wd_cnt = 256;
+    ptimer_set_count(t->ptimer_wd, wd_cnt);
+    if (new_cmd)
+        ptimer_run(t->ptimer_wd, 1);
+    else
+        ptimer_stop(t->ptimer_wd);
+
+    t->rw_wd_ctrl = value;
+}
+
+static void
+timer_write(void *opaque, hwaddr addr,
+            uint64_t val64, unsigned int size)
+{
+    struct etrax_timer *t = opaque;
+    uint32_t value = val64;
+
+    switch (addr)
+    {
+        case RW_TMR0_DIV:
+            t->rw_tmr0_div = value;
+            break;
+        case RW_TMR0_CTRL:
+            D(printf ("RW_TMR0_CTRL=%x\n", value));
+            t->rw_tmr0_ctrl = value;
+            update_ctrl(t, 0);
+            break;
+        case RW_TMR1_DIV:
+            t->rw_tmr1_div = value;
+            break;
+        case RW_TMR1_CTRL:
+            D(printf ("RW_TMR1_CTRL=%x\n", value));
+            t->rw_tmr1_ctrl = value;
+            update_ctrl(t, 1);
+            break;
+        case RW_INTR_MASK:
+            D(printf ("RW_INTR_MASK=%x\n", value));
+            t->rw_intr_mask = value;
+            timer_update_irq(t);
+            break;
+        case RW_WD_CTRL:
+            timer_watchdog_update(t, value);
+            break;
+        case RW_ACK_INTR:
+            t->rw_ack_intr = value;
+            timer_update_irq(t);
+            t->rw_ack_intr = 0;
+            break;
+        default:
+            printf ("%s " TARGET_FMT_plx " %x\n",
+                __func__, addr, value);
+            break;
+    }
+}
+
+static const MemoryRegionOps timer_ops = {
+    .read = timer_read,
+    .write = timer_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4
+    }
+};
+
+static void etraxfs_timer_reset(void *opaque)
+{
+    struct etrax_timer *t = opaque;
+
+    ptimer_stop(t->ptimer_t0);
+    ptimer_stop(t->ptimer_t1);
+    ptimer_stop(t->ptimer_wd);
+    t->rw_wd_ctrl = 0;
+    t->r_intr = 0;
+    t->rw_intr_mask = 0;
+    qemu_irq_lower(t->irq);
+}
+
+static int etraxfs_timer_init(SysBusDevice *dev)
+{
+    struct etrax_timer *t = FROM_SYSBUS(typeof (*t), dev);
+
+    t->bh_t0 = qemu_bh_new(timer0_hit, t);
+    t->bh_t1 = qemu_bh_new(timer1_hit, t);
+    t->bh_wd = qemu_bh_new(watchdog_hit, t);
+    t->ptimer_t0 = ptimer_init(t->bh_t0);
+    t->ptimer_t1 = ptimer_init(t->bh_t1);
+    t->ptimer_wd = ptimer_init(t->bh_wd);
+
+    sysbus_init_irq(dev, &t->irq);
+    sysbus_init_irq(dev, &t->nmi);
+
+    memory_region_init_io(&t->mmio, &timer_ops, t, "etraxfs-timer", 0x5c);
+    sysbus_init_mmio(dev, &t->mmio);
+    qemu_register_reset(etraxfs_timer_reset, t);
+    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 const 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_types(void)
+{
+    type_register_static(&etraxfs_timer_info);
+}
+
+type_init(etraxfs_timer_register_types)
diff --git a/hw/timer/exynos4210_mct.c b/hw/timer/exynos4210_mct.c
new file mode 100644 (file)
index 0000000..87ce75b
--- /dev/null
@@ -0,0 +1,1482 @@
+/*
+ * Samsung exynos4210 Multi Core timer
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd.
+ * All rights reserved.
+ *
+ * Evgeny Voevodin <e.voevodin@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 "hw/sysbus.h"
+#include "qemu/timer.h"
+#include "qemu-common.h"
+#include "hw/ptimer.h"
+
+#include "hw/arm/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);
+    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) {
+        distance = MCT_GT_COUNTER_STEP;
+    }
+    exynos4210_gfrc_set_count(&s->g_timer, distance);
+
+    exynos4210_gfrc_start(&s->g_timer);
+}
+
+/*
+ * 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 its 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, hwaddr 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, hwaddr 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 const 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)
diff --git a/hw/timer/exynos4210_pwm.c b/hw/timer/exynos4210_pwm.c
new file mode 100644 (file)
index 0000000..185ccb9
--- /dev/null
@@ -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@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 "hw/sysbus.h"
+#include "qemu/timer.h"
+#include "qemu-common.h"
+#include "hw/ptimer.h"
+
+#include "hw/arm/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, hwaddr 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, hwaddr 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 const 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)
diff --git a/hw/timer/exynos4210_rtc.c b/hw/timer/exynos4210_rtc.c
new file mode 100644 (file)
index 0000000..bceee44
--- /dev/null
@@ -0,0 +1,592 @@
+/*
+ * Samsung exynos4210 Real Time Clock
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *  Ogurtsov Oleg <o.ogurtsov@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/>.
+ *
+ */
+
+/* Description:
+ * Register RTCCON:
+ *  CLKSEL Bit[1] not used
+ *  CLKOUTEN Bit[9] not used
+ */
+
+#include "hw/sysbus.h"
+#include "qemu/timer.h"
+#include "qemu-common.h"
+#include "hw/ptimer.h"
+
+#include "hw/hw.h"
+#include "qemu/timer.h"
+#include "sysemu/sysemu.h"
+
+#include "hw/arm/exynos4210.h"
+
+#define DEBUG_RTC 0
+
+#if DEBUG_RTC
+#define DPRINTF(fmt, ...) \
+        do { fprintf(stdout, "RTC: [%24s:%5d] " fmt, __func__, __LINE__, \
+                ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while (0)
+#endif
+
+#define     EXYNOS4210_RTC_REG_MEM_SIZE     0x0100
+
+#define     INTP            0x0030
+#define     RTCCON          0x0040
+#define     TICCNT          0x0044
+#define     RTCALM          0x0050
+#define     ALMSEC          0x0054
+#define     ALMMIN          0x0058
+#define     ALMHOUR         0x005C
+#define     ALMDAY          0x0060
+#define     ALMMON          0x0064
+#define     ALMYEAR         0x0068
+#define     BCDSEC          0x0070
+#define     BCDMIN          0x0074
+#define     BCDHOUR         0x0078
+#define     BCDDAY          0x007C
+#define     BCDDAYWEEK      0x0080
+#define     BCDMON          0x0084
+#define     BCDYEAR         0x0088
+#define     CURTICNT        0x0090
+
+#define     TICK_TIMER_ENABLE   0x0100
+#define     TICNT_THRESHHOLD    2
+
+
+#define     RTC_ENABLE          0x0001
+
+#define     INTP_TICK_ENABLE    0x0001
+#define     INTP_ALM_ENABLE     0x0002
+
+#define     ALARM_INT_ENABLE    0x0040
+
+#define     RTC_BASE_FREQ       32768
+
+typedef struct Exynos4210RTCState {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+
+    /* registers */
+    uint32_t    reg_intp;
+    uint32_t    reg_rtccon;
+    uint32_t    reg_ticcnt;
+    uint32_t    reg_rtcalm;
+    uint32_t    reg_almsec;
+    uint32_t    reg_almmin;
+    uint32_t    reg_almhour;
+    uint32_t    reg_almday;
+    uint32_t    reg_almmon;
+    uint32_t    reg_almyear;
+    uint32_t    reg_curticcnt;
+
+    ptimer_state    *ptimer;        /* tick timer */
+    ptimer_state    *ptimer_1Hz;    /* clock timer */
+    uint32_t        freq;
+
+    qemu_irq        tick_irq;   /* Time Tick Generator irq */
+    qemu_irq        alm_irq;    /* alarm irq */
+
+    struct tm   current_tm;     /* current time */
+} Exynos4210RTCState;
+
+#define TICCKSEL(value) ((value & (0x0F << 4)) >> 4)
+
+/*** VMState ***/
+static const VMStateDescription vmstate_exynos4210_rtc_state = {
+    .name = "exynos4210.rtc",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(reg_intp, Exynos4210RTCState),
+        VMSTATE_UINT32(reg_rtccon, Exynos4210RTCState),
+        VMSTATE_UINT32(reg_ticcnt, Exynos4210RTCState),
+        VMSTATE_UINT32(reg_rtcalm, Exynos4210RTCState),
+        VMSTATE_UINT32(reg_almsec, Exynos4210RTCState),
+        VMSTATE_UINT32(reg_almmin, Exynos4210RTCState),
+        VMSTATE_UINT32(reg_almhour, Exynos4210RTCState),
+        VMSTATE_UINT32(reg_almday, Exynos4210RTCState),
+        VMSTATE_UINT32(reg_almmon, Exynos4210RTCState),
+        VMSTATE_UINT32(reg_almyear, Exynos4210RTCState),
+        VMSTATE_UINT32(reg_curticcnt, Exynos4210RTCState),
+        VMSTATE_PTIMER(ptimer, Exynos4210RTCState),
+        VMSTATE_PTIMER(ptimer_1Hz, Exynos4210RTCState),
+        VMSTATE_UINT32(freq, Exynos4210RTCState),
+        VMSTATE_INT32(current_tm.tm_sec, Exynos4210RTCState),
+        VMSTATE_INT32(current_tm.tm_min, Exynos4210RTCState),
+        VMSTATE_INT32(current_tm.tm_hour, Exynos4210RTCState),
+        VMSTATE_INT32(current_tm.tm_wday, Exynos4210RTCState),
+        VMSTATE_INT32(current_tm.tm_mday, Exynos4210RTCState),
+        VMSTATE_INT32(current_tm.tm_mon, Exynos4210RTCState),
+        VMSTATE_INT32(current_tm.tm_year, Exynos4210RTCState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+#define BCD3DIGITS(x) \
+    ((uint32_t)to_bcd((uint8_t)(x % 100)) + \
+    ((uint32_t)to_bcd((uint8_t)((x % 1000) / 100)) << 8))
+
+static void check_alarm_raise(Exynos4210RTCState *s)
+{
+    unsigned int alarm_raise = 0;
+    struct tm stm = s->current_tm;
+
+    if ((s->reg_rtcalm & 0x01) &&
+        (to_bcd((uint8_t)stm.tm_sec) == (uint8_t)s->reg_almsec)) {
+        alarm_raise = 1;
+    }
+    if ((s->reg_rtcalm & 0x02) &&
+        (to_bcd((uint8_t)stm.tm_min) == (uint8_t)s->reg_almmin)) {
+        alarm_raise = 1;
+    }
+    if ((s->reg_rtcalm & 0x04) &&
+        (to_bcd((uint8_t)stm.tm_hour) == (uint8_t)s->reg_almhour)) {
+        alarm_raise = 1;
+    }
+    if ((s->reg_rtcalm & 0x08) &&
+        (to_bcd((uint8_t)stm.tm_mday) == (uint8_t)s->reg_almday)) {
+        alarm_raise = 1;
+    }
+    if ((s->reg_rtcalm & 0x10) &&
+         (to_bcd((uint8_t)stm.tm_mon) == (uint8_t)s->reg_almmon)) {
+        alarm_raise = 1;
+    }
+    if ((s->reg_rtcalm & 0x20) &&
+        (BCD3DIGITS(stm.tm_year) == s->reg_almyear)) {
+        alarm_raise = 1;
+    }
+
+    if (alarm_raise) {
+        DPRINTF("ALARM IRQ\n");
+        /* set irq status */
+        s->reg_intp |= INTP_ALM_ENABLE;
+        qemu_irq_raise(s->alm_irq);
+    }
+}
+
+/*
+ * RTC update frequency
+ * Parameters:
+ *     reg_value - current RTCCON register or his new value
+ */
+static void exynos4210_rtc_update_freq(Exynos4210RTCState *s,
+                                       uint32_t reg_value)
+{
+    uint32_t freq;
+
+    freq = s->freq;
+    /* set frequncy for time generator */
+    s->freq = RTC_BASE_FREQ / (1 << TICCKSEL(reg_value));
+
+    if (freq != s->freq) {
+        ptimer_set_freq(s->ptimer, s->freq);
+        DPRINTF("freq=%dHz\n", s->freq);
+    }
+}
+
+/* month is between 0 and 11. */
+static int get_days_in_month(int month, int year)
+{
+    static const int days_tab[12] = {
+        31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+    };
+    int d;
+    if ((unsigned)month >= 12) {
+        return 31;
+    }
+    d = days_tab[month];
+    if (month == 1) {
+        if ((year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0)) {
+            d++;
+        }
+    }
+    return d;
+}
+
+/* update 'tm' to the next second */
+static void rtc_next_second(struct tm *tm)
+{
+    int days_in_month;
+
+    tm->tm_sec++;
+    if ((unsigned)tm->tm_sec >= 60) {
+        tm->tm_sec = 0;
+        tm->tm_min++;
+        if ((unsigned)tm->tm_min >= 60) {
+            tm->tm_min = 0;
+            tm->tm_hour++;
+            if ((unsigned)tm->tm_hour >= 24) {
+                tm->tm_hour = 0;
+                /* next day */
+                tm->tm_wday++;
+                if ((unsigned)tm->tm_wday >= 7) {
+                    tm->tm_wday = 0;
+                }
+                days_in_month = get_days_in_month(tm->tm_mon,
+                                                  tm->tm_year + 1900);
+                tm->tm_mday++;
+                if (tm->tm_mday < 1) {
+                    tm->tm_mday = 1;
+                } else if (tm->tm_mday > days_in_month) {
+                    tm->tm_mday = 1;
+                    tm->tm_mon++;
+                    if (tm->tm_mon >= 12) {
+                        tm->tm_mon = 0;
+                        tm->tm_year++;
+                    }
+                }
+            }
+        }
+    }
+}
+
+/*
+ * tick handler
+ */
+static void exynos4210_rtc_tick(void *opaque)
+{
+    Exynos4210RTCState *s = (Exynos4210RTCState *)opaque;
+
+    DPRINTF("TICK IRQ\n");
+    /* set irq status */
+    s->reg_intp |= INTP_TICK_ENABLE;
+    /* raise IRQ */
+    qemu_irq_raise(s->tick_irq);
+
+    /* restart timer */
+    ptimer_set_count(s->ptimer, s->reg_ticcnt);
+    ptimer_run(s->ptimer, 1);
+}
+
+/*
+ * 1Hz clock handler
+ */
+static void exynos4210_rtc_1Hz_tick(void *opaque)
+{
+    Exynos4210RTCState *s = (Exynos4210RTCState *)opaque;
+
+    rtc_next_second(&s->current_tm);
+    /* DPRINTF("1Hz tick\n"); */
+
+    /* raise IRQ */
+    if (s->reg_rtcalm & ALARM_INT_ENABLE) {
+        check_alarm_raise(s);
+    }
+
+    ptimer_set_count(s->ptimer_1Hz, RTC_BASE_FREQ);
+    ptimer_run(s->ptimer_1Hz, 1);
+}
+
+/*
+ * RTC Read
+ */
+static uint64_t exynos4210_rtc_read(void *opaque, hwaddr offset,
+        unsigned size)
+{
+    uint32_t value = 0;
+    Exynos4210RTCState *s = (Exynos4210RTCState *)opaque;
+
+    switch (offset) {
+    case INTP:
+        value = s->reg_intp;
+        break;
+    case RTCCON:
+        value = s->reg_rtccon;
+        break;
+    case TICCNT:
+        value = s->reg_ticcnt;
+        break;
+    case RTCALM:
+        value = s->reg_rtcalm;
+        break;
+    case ALMSEC:
+        value = s->reg_almsec;
+        break;
+    case ALMMIN:
+        value = s->reg_almmin;
+        break;
+    case ALMHOUR:
+        value = s->reg_almhour;
+        break;
+    case ALMDAY:
+        value = s->reg_almday;
+        break;
+    case ALMMON:
+        value = s->reg_almmon;
+        break;
+    case ALMYEAR:
+        value = s->reg_almyear;
+        break;
+
+    case BCDSEC:
+        value = (uint32_t)to_bcd((uint8_t)s->current_tm.tm_sec);
+        break;
+    case BCDMIN:
+        value = (uint32_t)to_bcd((uint8_t)s->current_tm.tm_min);
+        break;
+    case BCDHOUR:
+        value = (uint32_t)to_bcd((uint8_t)s->current_tm.tm_hour);
+        break;
+    case BCDDAYWEEK:
+        value = (uint32_t)to_bcd((uint8_t)s->current_tm.tm_wday);
+        break;
+    case BCDDAY:
+        value = (uint32_t)to_bcd((uint8_t)s->current_tm.tm_mday);
+        break;
+    case BCDMON:
+        value = (uint32_t)to_bcd((uint8_t)s->current_tm.tm_mon + 1);
+        break;
+    case BCDYEAR:
+        value = BCD3DIGITS(s->current_tm.tm_year);
+        break;
+
+    case CURTICNT:
+        s->reg_curticcnt = ptimer_get_count(s->ptimer);
+        value = s->reg_curticcnt;
+        break;
+
+    default:
+        fprintf(stderr,
+                "[exynos4210.rtc: bad read offset " TARGET_FMT_plx "]\n",
+                offset);
+        break;
+    }
+    return value;
+}
+
+/*
+ * RTC Write
+ */
+static void exynos4210_rtc_write(void *opaque, hwaddr offset,
+        uint64_t value, unsigned size)
+{
+    Exynos4210RTCState *s = (Exynos4210RTCState *)opaque;
+
+    switch (offset) {
+    case INTP:
+        if (value & INTP_ALM_ENABLE) {
+            qemu_irq_lower(s->alm_irq);
+            s->reg_intp &= (~INTP_ALM_ENABLE);
+        }
+        if (value & INTP_TICK_ENABLE) {
+            qemu_irq_lower(s->tick_irq);
+            s->reg_intp &= (~INTP_TICK_ENABLE);
+        }
+        break;
+    case RTCCON:
+        if (value & RTC_ENABLE) {
+            exynos4210_rtc_update_freq(s, value);
+        }
+        if ((value & RTC_ENABLE) > (s->reg_rtccon & RTC_ENABLE)) {
+            /* clock timer */
+            ptimer_set_count(s->ptimer_1Hz, RTC_BASE_FREQ);
+            ptimer_run(s->ptimer_1Hz, 1);
+            DPRINTF("run clock timer\n");
+        }
+        if ((value & RTC_ENABLE) < (s->reg_rtccon & RTC_ENABLE)) {
+            /* tick timer */
+            ptimer_stop(s->ptimer);
+            /* clock timer */
+            ptimer_stop(s->ptimer_1Hz);
+            DPRINTF("stop all timers\n");
+        }
+        if (value & RTC_ENABLE) {
+            if ((value & TICK_TIMER_ENABLE) >
+                (s->reg_rtccon & TICK_TIMER_ENABLE) &&
+                (s->reg_ticcnt)) {
+                ptimer_set_count(s->ptimer, s->reg_ticcnt);
+                ptimer_run(s->ptimer, 1);
+                DPRINTF("run tick timer\n");
+            }
+            if ((value & TICK_TIMER_ENABLE) <
+                (s->reg_rtccon & TICK_TIMER_ENABLE)) {
+                ptimer_stop(s->ptimer);
+            }
+        }
+        s->reg_rtccon = value;
+        break;
+    case TICCNT:
+        if (value > TICNT_THRESHHOLD) {
+            s->reg_ticcnt = value;
+        } else {
+            fprintf(stderr,
+                    "[exynos4210.rtc: bad TICNT value %u ]\n",
+                    (uint32_t)value);
+        }
+        break;
+
+    case RTCALM:
+        s->reg_rtcalm = value;
+        break;
+    case ALMSEC:
+        s->reg_almsec = (value & 0x7f);
+        break;
+    case ALMMIN:
+        s->reg_almmin = (value & 0x7f);
+        break;
+    case ALMHOUR:
+        s->reg_almhour = (value & 0x3f);
+        break;
+    case ALMDAY:
+        s->reg_almday = (value & 0x3f);
+        break;
+    case ALMMON:
+        s->reg_almmon = (value & 0x1f);
+        break;
+    case ALMYEAR:
+        s->reg_almyear = (value & 0x0fff);
+        break;
+
+    case BCDSEC:
+        if (s->reg_rtccon & RTC_ENABLE) {
+            s->current_tm.tm_sec = (int)from_bcd((uint8_t)value);
+        }
+        break;
+    case BCDMIN:
+        if (s->reg_rtccon & RTC_ENABLE) {
+            s->current_tm.tm_min = (int)from_bcd((uint8_t)value);
+        }
+        break;
+    case BCDHOUR:
+        if (s->reg_rtccon & RTC_ENABLE) {
+            s->current_tm.tm_hour = (int)from_bcd((uint8_t)value);
+        }
+        break;
+    case BCDDAYWEEK:
+        if (s->reg_rtccon & RTC_ENABLE) {
+            s->current_tm.tm_wday = (int)from_bcd((uint8_t)value);
+        }
+        break;
+    case BCDDAY:
+        if (s->reg_rtccon & RTC_ENABLE) {
+            s->current_tm.tm_mday = (int)from_bcd((uint8_t)value);
+        }
+        break;
+    case BCDMON:
+        if (s->reg_rtccon & RTC_ENABLE) {
+            s->current_tm.tm_mon = (int)from_bcd((uint8_t)value) - 1;
+        }
+        break;
+    case BCDYEAR:
+        if (s->reg_rtccon & RTC_ENABLE) {
+            /* 3 digits */
+            s->current_tm.tm_year = (int)from_bcd((uint8_t)value) +
+                    (int)from_bcd((uint8_t)((value >> 8) & 0x0f)) * 100;
+        }
+        break;
+
+    default:
+        fprintf(stderr,
+                "[exynos4210.rtc: bad write offset " TARGET_FMT_plx "]\n",
+                offset);
+        break;
+
+    }
+}
+
+/*
+ * Set default values to timer fields and registers
+ */
+static void exynos4210_rtc_reset(DeviceState *d)
+{
+    Exynos4210RTCState *s = (Exynos4210RTCState *)d;
+
+    qemu_get_timedate(&s->current_tm, 0);
+
+    DPRINTF("Get time from host: %d-%d-%d %2d:%02d:%02d\n",
+            s->current_tm.tm_year, s->current_tm.tm_mon, s->current_tm.tm_mday,
+            s->current_tm.tm_hour, s->current_tm.tm_min, s->current_tm.tm_sec);
+
+    s->reg_intp = 0;
+    s->reg_rtccon = 0;
+    s->reg_ticcnt = 0;
+    s->reg_rtcalm = 0;
+    s->reg_almsec = 0;
+    s->reg_almmin = 0;
+    s->reg_almhour = 0;
+    s->reg_almday = 0;
+    s->reg_almmon = 0;
+    s->reg_almyear = 0;
+
+    s->reg_curticcnt = 0;
+
+    exynos4210_rtc_update_freq(s, s->reg_rtccon);
+    ptimer_stop(s->ptimer);
+    ptimer_stop(s->ptimer_1Hz);
+}
+
+static const MemoryRegionOps exynos4210_rtc_ops = {
+    .read = exynos4210_rtc_read,
+    .write = exynos4210_rtc_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+/*
+ * RTC timer initialization
+ */
+static int exynos4210_rtc_init(SysBusDevice *dev)
+{
+    Exynos4210RTCState *s = FROM_SYSBUS(Exynos4210RTCState, dev);
+    QEMUBH *bh;
+
+    bh = qemu_bh_new(exynos4210_rtc_tick, s);
+    s->ptimer = ptimer_init(bh);
+    ptimer_set_freq(s->ptimer, RTC_BASE_FREQ);
+    exynos4210_rtc_update_freq(s, 0);
+
+    bh = qemu_bh_new(exynos4210_rtc_1Hz_tick, s);
+    s->ptimer_1Hz = ptimer_init(bh);
+    ptimer_set_freq(s->ptimer_1Hz, RTC_BASE_FREQ);
+
+    sysbus_init_irq(dev, &s->alm_irq);
+    sysbus_init_irq(dev, &s->tick_irq);
+
+    memory_region_init_io(&s->iomem, &exynos4210_rtc_ops, s, "exynos4210-rtc",
+            EXYNOS4210_RTC_REG_MEM_SIZE);
+    sysbus_init_mmio(dev, &s->iomem);
+
+    return 0;
+}
+
+static void exynos4210_rtc_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = exynos4210_rtc_init;
+    dc->reset = exynos4210_rtc_reset;
+    dc->vmsd = &vmstate_exynos4210_rtc_state;
+}
+
+static const TypeInfo exynos4210_rtc_info = {
+    .name          = "exynos4210.rtc",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(Exynos4210RTCState),
+    .class_init    = exynos4210_rtc_class_init,
+};
+
+static void exynos4210_rtc_register_types(void)
+{
+    type_register_static(&exynos4210_rtc_info);
+}
+
+type_init(exynos4210_rtc_register_types)
diff --git a/hw/timer/grlib_gptimer.c b/hw/timer/grlib_gptimer.c
new file mode 100644 (file)
index 0000000..7043a34
--- /dev/null
@@ -0,0 +1,404 @@
+/*
+ * QEMU GRLIB GPTimer Emulator
+ *
+ * Copyright (c) 2010-2011 AdaCore
+ *
+ * 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 "hw/sysbus.h"
+#include "qemu/timer.h"
+#include "hw/ptimer.h"
+
+#include "trace.h"
+
+#define UNIT_REG_SIZE    16     /* Size of memory mapped regs for the unit */
+#define GPTIMER_REG_SIZE 16     /* Size of memory mapped regs for a GPTimer */
+
+#define GPTIMER_MAX_TIMERS 8
+
+/* GPTimer Config register fields */
+#define GPTIMER_ENABLE      (1 << 0)
+#define GPTIMER_RESTART     (1 << 1)
+#define GPTIMER_LOAD        (1 << 2)
+#define GPTIMER_INT_ENABLE  (1 << 3)
+#define GPTIMER_INT_PENDING (1 << 4)
+#define GPTIMER_CHAIN       (1 << 5) /* Not supported */
+#define GPTIMER_DEBUG_HALT  (1 << 6) /* Not supported */
+
+/* Memory mapped register offsets */
+#define SCALER_OFFSET         0x00
+#define SCALER_RELOAD_OFFSET  0x04
+#define CONFIG_OFFSET         0x08
+#define COUNTER_OFFSET        0x00
+#define COUNTER_RELOAD_OFFSET 0x04
+#define TIMER_BASE            0x10
+
+typedef struct GPTimer     GPTimer;
+typedef struct GPTimerUnit GPTimerUnit;
+
+struct GPTimer {
+    QEMUBH *bh;
+    struct ptimer_state *ptimer;
+
+    qemu_irq     irq;
+    int          id;
+    GPTimerUnit *unit;
+
+    /* registers */
+    uint32_t counter;
+    uint32_t reload;
+    uint32_t config;
+};
+
+struct GPTimerUnit {
+    SysBusDevice  busdev;
+    MemoryRegion iomem;
+
+    uint32_t nr_timers;         /* Number of timers available */
+    uint32_t freq_hz;           /* System frequency */
+    uint32_t irq_line;          /* Base irq line */
+
+    GPTimer *timers;
+
+    /* registers */
+    uint32_t scaler;
+    uint32_t reload;
+    uint32_t config;
+};
+
+static void grlib_gptimer_enable(GPTimer *timer)
+{
+    assert(timer != NULL);
+
+
+    ptimer_stop(timer->ptimer);
+
+    if (!(timer->config & GPTIMER_ENABLE)) {
+        /* Timer disabled */
+        trace_grlib_gptimer_disabled(timer->id, timer->config);
+        return;
+    }
+
+    /* ptimer is triggered when the counter reach 0 but GPTimer is triggered at
+       underflow. Set count + 1 to simulate the GPTimer behavior. */
+
+    trace_grlib_gptimer_enable(timer->id, timer->counter + 1);
+
+    ptimer_set_count(timer->ptimer, timer->counter + 1);
+    ptimer_run(timer->ptimer, 1);
+}
+
+static void grlib_gptimer_restart(GPTimer *timer)
+{
+    assert(timer != NULL);
+
+    trace_grlib_gptimer_restart(timer->id, timer->reload);
+
+    timer->counter = timer->reload;
+    grlib_gptimer_enable(timer);
+}
+
+static void grlib_gptimer_set_scaler(GPTimerUnit *unit, uint32_t scaler)
+{
+    int i = 0;
+    uint32_t value = 0;
+
+    assert(unit != NULL);
+
+    if (scaler > 0) {
+        value = unit->freq_hz / (scaler + 1);
+    } else {
+        value = unit->freq_hz;
+    }
+
+    trace_grlib_gptimer_set_scaler(scaler, value);
+
+    for (i = 0; i < unit->nr_timers; i++) {
+        ptimer_set_freq(unit->timers[i].ptimer, value);
+    }
+}
+
+static void grlib_gptimer_hit(void *opaque)
+{
+    GPTimer *timer = opaque;
+    assert(timer != NULL);
+
+    trace_grlib_gptimer_hit(timer->id);
+
+    /* Timer expired */
+
+    if (timer->config & GPTIMER_INT_ENABLE) {
+        /* Set the pending bit (only unset by write in the config register) */
+        timer->config |= GPTIMER_INT_PENDING;
+        qemu_irq_pulse(timer->irq);
+    }
+
+    if (timer->config & GPTIMER_RESTART) {
+        grlib_gptimer_restart(timer);
+    }
+}
+
+static uint64_t grlib_gptimer_read(void *opaque, hwaddr addr,
+                                   unsigned size)
+{
+    GPTimerUnit        *unit  = opaque;
+    hwaddr  timer_addr;
+    int                 id;
+    uint32_t            value = 0;
+
+    addr &= 0xff;
+
+    /* Unit registers */
+    switch (addr) {
+    case SCALER_OFFSET:
+        trace_grlib_gptimer_readl(-1, addr, unit->scaler);
+        return unit->scaler;
+
+    case SCALER_RELOAD_OFFSET:
+        trace_grlib_gptimer_readl(-1, addr, unit->reload);
+        return unit->reload;
+
+    case CONFIG_OFFSET:
+        trace_grlib_gptimer_readl(-1, addr, unit->config);
+        return unit->config;
+
+    default:
+        break;
+    }
+
+    timer_addr = (addr % TIMER_BASE);
+    id         = (addr - TIMER_BASE) / TIMER_BASE;
+
+    if (id >= 0 && id < unit->nr_timers) {
+
+        /* GPTimer registers */
+        switch (timer_addr) {
+        case COUNTER_OFFSET:
+            value = ptimer_get_count(unit->timers[id].ptimer);
+            trace_grlib_gptimer_readl(id, addr, value);
+            return value;
+
+        case COUNTER_RELOAD_OFFSET:
+            value = unit->timers[id].reload;
+            trace_grlib_gptimer_readl(id, addr, value);
+            return value;
+
+        case CONFIG_OFFSET:
+            trace_grlib_gptimer_readl(id, addr, unit->timers[id].config);
+            return unit->timers[id].config;
+
+        default:
+            break;
+        }
+
+    }
+
+    trace_grlib_gptimer_readl(-1, addr, 0);
+    return 0;
+}
+
+static void grlib_gptimer_write(void *opaque, hwaddr addr,
+                                uint64_t value, unsigned size)
+{
+    GPTimerUnit        *unit = opaque;
+    hwaddr  timer_addr;
+    int                 id;
+
+    addr &= 0xff;
+
+    /* Unit registers */
+    switch (addr) {
+    case SCALER_OFFSET:
+        value &= 0xFFFF; /* clean up the value */
+        unit->scaler = value;
+        trace_grlib_gptimer_writel(-1, addr, unit->scaler);
+        return;
+
+    case SCALER_RELOAD_OFFSET:
+        value &= 0xFFFF; /* clean up the value */
+        unit->reload = value;
+        trace_grlib_gptimer_writel(-1, addr, unit->reload);
+        grlib_gptimer_set_scaler(unit, value);
+        return;
+
+    case CONFIG_OFFSET:
+        /* Read Only (disable timer freeze not supported) */
+        trace_grlib_gptimer_writel(-1, addr, 0);
+        return;
+
+    default:
+        break;
+    }
+
+    timer_addr = (addr % TIMER_BASE);
+    id         = (addr - TIMER_BASE) / TIMER_BASE;
+
+    if (id >= 0 && id < unit->nr_timers) {
+
+        /* GPTimer registers */
+        switch (timer_addr) {
+        case COUNTER_OFFSET:
+            trace_grlib_gptimer_writel(id, addr, value);
+            unit->timers[id].counter = value;
+            grlib_gptimer_enable(&unit->timers[id]);
+            return;
+
+        case COUNTER_RELOAD_OFFSET:
+            trace_grlib_gptimer_writel(id, addr, value);
+            unit->timers[id].reload = value;
+            return;
+
+        case CONFIG_OFFSET:
+            trace_grlib_gptimer_writel(id, addr, value);
+
+            if (value & GPTIMER_INT_PENDING) {
+                /* clear pending bit */
+                value &= ~GPTIMER_INT_PENDING;
+            } else {
+                /* keep pending bit */
+                value |= unit->timers[id].config & GPTIMER_INT_PENDING;
+            }
+
+            unit->timers[id].config = value;
+
+            /* gptimer_restart calls gptimer_enable, so if "enable" and "load"
+               bits are present, we just have to call restart. */
+
+            if (value & GPTIMER_LOAD) {
+                grlib_gptimer_restart(&unit->timers[id]);
+            } else if (value & GPTIMER_ENABLE) {
+                grlib_gptimer_enable(&unit->timers[id]);
+            }
+
+            /* These fields must always be read as 0 */
+            value &= ~(GPTIMER_LOAD & GPTIMER_DEBUG_HALT);
+
+            unit->timers[id].config = value;
+            return;
+
+        default:
+            break;
+        }
+
+    }
+
+    trace_grlib_gptimer_writel(-1, addr, value);
+}
+
+static const MemoryRegionOps grlib_gptimer_ops = {
+    .read = grlib_gptimer_read,
+    .write = grlib_gptimer_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static void grlib_gptimer_reset(DeviceState *d)
+{
+    GPTimerUnit *unit = container_of(d, GPTimerUnit, busdev.qdev);
+    int          i    = 0;
+
+    assert(unit != NULL);
+
+    unit->scaler = 0;
+    unit->reload = 0;
+    unit->config = 0;
+
+    unit->config  = unit->nr_timers;
+    unit->config |= unit->irq_line << 3;
+    unit->config |= 1 << 8;     /* separate interrupt */
+    unit->config |= 1 << 9;     /* Disable timer freeze */
+
+
+    for (i = 0; i < unit->nr_timers; i++) {
+        GPTimer *timer = &unit->timers[i];
+
+        timer->counter = 0;
+        timer->reload = 0;
+        timer->config = 0;
+        ptimer_stop(timer->ptimer);
+        ptimer_set_count(timer->ptimer, 0);
+        ptimer_set_freq(timer->ptimer, unit->freq_hz);
+    }
+}
+
+static int grlib_gptimer_init(SysBusDevice *dev)
+{
+    GPTimerUnit  *unit = FROM_SYSBUS(typeof(*unit), dev);
+    unsigned int  i;
+
+    assert(unit->nr_timers > 0);
+    assert(unit->nr_timers <= GPTIMER_MAX_TIMERS);
+
+    unit->timers = g_malloc0(sizeof unit->timers[0] * unit->nr_timers);
+
+    for (i = 0; i < unit->nr_timers; i++) {
+        GPTimer *timer = &unit->timers[i];
+
+        timer->unit   = unit;
+        timer->bh     = qemu_bh_new(grlib_gptimer_hit, timer);
+        timer->ptimer = ptimer_init(timer->bh);
+        timer->id     = i;
+
+        /* One IRQ line for each timer */
+        sysbus_init_irq(dev, &timer->irq);
+
+        ptimer_set_freq(timer->ptimer, unit->freq_hz);
+    }
+
+    memory_region_init_io(&unit->iomem, &grlib_gptimer_ops, unit, "gptimer",
+                          UNIT_REG_SIZE + GPTIMER_REG_SIZE * unit->nr_timers);
+
+    sysbus_init_mmio(dev, &unit->iomem);
+    return 0;
+}
+
+static Property grlib_gptimer_properties[] = {
+    DEFINE_PROP_UINT32("frequency", GPTimerUnit, freq_hz,   40000000),
+    DEFINE_PROP_UINT32("irq-line",  GPTimerUnit, irq_line,  8),
+    DEFINE_PROP_UINT32("nr-timers", GPTimerUnit, nr_timers, 2),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void grlib_gptimer_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = grlib_gptimer_init;
+    dc->reset = grlib_gptimer_reset;
+    dc->props = grlib_gptimer_properties;
+}
+
+static const 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_types(void)
+{
+    type_register_static(&grlib_gptimer_info);
+}
+
+type_init(grlib_gptimer_register_types)
diff --git a/hw/timer/hpet.c b/hw/timer/hpet.c
new file mode 100644 (file)
index 0000000..95dd01d
--- /dev/null
@@ -0,0 +1,760 @@
+/*
+ *  High Precisition Event Timer emulation
+ *
+ *  Copyright (c) 2007 Alexander Graf
+ *  Copyright (c) 2008 IBM Corporation
+ *
+ *  Authors: Beth Kon <bkon@us.ibm.com>
+ *
+ * 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/>.
+ *
+ * *****************************************************************
+ *
+ * This driver attempts to emulate an HPET device in software.
+ */
+
+#include "hw/hw.h"
+#include "hw/i386/pc.h"
+#include "ui/console.h"
+#include "qemu/timer.h"
+#include "hw/timer/hpet.h"
+#include "hw/sysbus.h"
+#include "hw/timer/mc146818rtc.h"
+#include "hw/timer/i8254.h"
+
+//#define HPET_DEBUG
+#ifdef HPET_DEBUG
+#define DPRINTF printf
+#else
+#define DPRINTF(...)
+#endif
+
+#define HPET_MSI_SUPPORT        0
+
+struct HPETState;
+typedef struct HPETTimer {  /* timers */
+    uint8_t tn;             /*timer number*/
+    QEMUTimer *qemu_timer;
+    struct HPETState *state;
+    /* Memory-mapped, software visible timer registers */
+    uint64_t config;        /* configuration/cap */
+    uint64_t cmp;           /* comparator */
+    uint64_t fsb;           /* FSB route */
+    /* Hidden register state */
+    uint64_t period;        /* Last value written to comparator */
+    uint8_t wrap_flag;      /* timer pop will indicate wrap for one-shot 32-bit
+                             * mode. Next pop will be actual timer expiration.
+                             */
+} HPETTimer;
+
+typedef struct HPETState {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    uint64_t hpet_offset;
+    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];
+
+    /* Memory-mapped, software visible registers */
+    uint64_t capability;        /* capabilities */
+    uint64_t config;            /* configuration */
+    uint64_t isr;               /* interrupt status reg */
+    uint64_t hpet_counter;      /* main counter */
+    uint8_t  hpet_id;           /* instance id */
+} HPETState;
+
+static uint32_t hpet_in_legacy_mode(HPETState *s)
+{
+    return s->config & HPET_CFG_LEGACY;
+}
+
+static uint32_t timer_int_route(struct HPETTimer *timer)
+{
+    return (timer->config & HPET_TN_INT_ROUTE_MASK) >> HPET_TN_INT_ROUTE_SHIFT;
+}
+
+static uint32_t timer_fsb_route(HPETTimer *t)
+{
+    return t->config & HPET_TN_FSB_ENABLE;
+}
+
+static uint32_t hpet_enabled(HPETState *s)
+{
+    return s->config & HPET_CFG_ENABLE;
+}
+
+static uint32_t timer_is_periodic(HPETTimer *t)
+{
+    return t->config & HPET_TN_PERIODIC;
+}
+
+static uint32_t timer_enabled(HPETTimer *t)
+{
+    return t->config & HPET_TN_ENABLE;
+}
+
+static uint32_t hpet_time_after(uint64_t a, uint64_t b)
+{
+    return ((int32_t)(b) - (int32_t)(a) < 0);
+}
+
+static uint32_t hpet_time_after64(uint64_t a, uint64_t b)
+{
+    return ((int64_t)(b) - (int64_t)(a) < 0);
+}
+
+static uint64_t ticks_to_ns(uint64_t value)
+{
+    return (muldiv64(value, HPET_CLK_PERIOD, FS_PER_NS));
+}
+
+static uint64_t ns_to_ticks(uint64_t value)
+{
+    return (muldiv64(value, FS_PER_NS, HPET_CLK_PERIOD));
+}
+
+static uint64_t hpet_fixup_reg(uint64_t new, uint64_t old, uint64_t mask)
+{
+    new &= mask;
+    new |= old & ~mask;
+    return new;
+}
+
+static int activating_bit(uint64_t old, uint64_t new, uint64_t mask)
+{
+    return (!(old & mask) && (new & mask));
+}
+
+static int deactivating_bit(uint64_t old, uint64_t new, uint64_t mask)
+{
+    return ((old & mask) && !(new & mask));
+}
+
+static uint64_t hpet_get_ticks(HPETState *s)
+{
+    return ns_to_ticks(qemu_get_clock_ns(vm_clock) + s->hpet_offset);
+}
+
+/*
+ * calculate diff between comparator value and current ticks
+ */
+static inline uint64_t hpet_calculate_diff(HPETTimer *t, uint64_t current)
+{
+
+    if (t->config & HPET_TN_32BIT) {
+        uint32_t diff, cmp;
+
+        cmp = (uint32_t)t->cmp;
+        diff = cmp - (uint32_t)current;
+        diff = (int32_t)diff > 0 ? diff : (uint32_t)1;
+        return (uint64_t)diff;
+    } else {
+        uint64_t diff, cmp;
+
+        cmp = t->cmp;
+        diff = cmp - current;
+        diff = (int64_t)diff > 0 ? diff : (uint64_t)1;
+        return diff;
+    }
+}
+
+static void update_irq(struct HPETTimer *timer, int set)
+{
+    uint64_t mask;
+    HPETState *s;
+    int route;
+
+    if (timer->tn <= 1 && hpet_in_legacy_mode(timer->state)) {
+        /* if LegacyReplacementRoute bit is set, HPET specification requires
+         * timer0 be routed to IRQ0 in NON-APIC or IRQ2 in the I/O APIC,
+         * timer1 be routed to IRQ8 in NON-APIC or IRQ8 in the I/O APIC.
+         */
+        route = (timer->tn == 0) ? 0 : RTC_ISA_IRQ;
+    } else {
+        route = timer_int_route(timer);
+    }
+    s = timer->state;
+    mask = 1 << timer->tn;
+    if (!set || !timer_enabled(timer) || !hpet_enabled(timer->state)) {
+        s->isr &= ~mask;
+        if (!timer_fsb_route(timer)) {
+            qemu_irq_lower(s->irqs[route]);
+        }
+    } else if (timer_fsb_route(timer)) {
+        stl_le_phys(timer->fsb >> 32, timer->fsb & 0xffffffff);
+    } else if (timer->config & HPET_TN_TYPE_LEVEL) {
+        s->isr |= mask;
+        qemu_irq_raise(s->irqs[route]);
+    } else {
+        s->isr &= ~mask;
+        qemu_irq_pulse(s->irqs[route]);
+    }
+}
+
+static void hpet_pre_save(void *opaque)
+{
+    HPETState *s = opaque;
+
+    /* save current counter value */
+    s->hpet_counter = hpet_get_ticks(s);
+}
+
+static int hpet_pre_load(void *opaque)
+{
+    HPETState *s = opaque;
+
+    /* version 1 only supports 3, later versions will load the actual value */
+    s->num_timers = HPET_MIN_TIMERS;
+    return 0;
+}
+
+static int hpet_post_load(void *opaque, int version_id)
+{
+    HPETState *s = opaque;
+
+    /* Recalculate the offset between the main counter and guest time */
+    s->hpet_offset = ticks_to_ns(s->hpet_counter) - qemu_get_clock_ns(vm_clock);
+
+    /* Push number of timers into capability returned via HPET_ID */
+    s->capability &= ~HPET_ID_NUM_TIM_MASK;
+    s->capability |= (s->num_timers - 1) << HPET_ID_NUM_TIM_SHIFT;
+    hpet_cfg.hpet[s->hpet_id].event_timer_block_id = (uint32_t)s->capability;
+
+    /* Derive HPET_MSI_SUPPORT from the capability of the first timer. */
+    s->flags &= ~(1 << HPET_MSI_SUPPORT);
+    if (s->timer[0].config & HPET_TN_FSB_CAP) {
+        s->flags |= 1 << HPET_MSI_SUPPORT;
+    }
+    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,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT8(tn, HPETTimer),
+        VMSTATE_UINT64(config, HPETTimer),
+        VMSTATE_UINT64(cmp, HPETTimer),
+        VMSTATE_UINT64(fsb, HPETTimer),
+        VMSTATE_UINT64(period, HPETTimer),
+        VMSTATE_UINT8(wrap_flag, HPETTimer),
+        VMSTATE_TIMER(qemu_timer, HPETTimer),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_hpet = {
+    .name = "hpet",
+    .version_id = 2,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .pre_save = hpet_pre_save,
+    .pre_load = hpet_pre_load,
+    .post_load = hpet_post_load,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT64(config, HPETState),
+        VMSTATE_UINT64(isr, HPETState),
+        VMSTATE_UINT64(hpet_counter, HPETState),
+        VMSTATE_UINT8_V(num_timers, HPETState, 2),
+        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 */
+        }
+    }
+};
+
+/*
+ * timer expiration callback
+ */
+static void hpet_timer(void *opaque)
+{
+    HPETTimer *t = opaque;
+    uint64_t diff;
+
+    uint64_t period = t->period;
+    uint64_t cur_tick = hpet_get_ticks(t->state);
+
+    if (timer_is_periodic(t) && period != 0) {
+        if (t->config & HPET_TN_32BIT) {
+            while (hpet_time_after(cur_tick, t->cmp)) {
+                t->cmp = (uint32_t)(t->cmp + t->period);
+            }
+        } else {
+            while (hpet_time_after64(cur_tick, t->cmp)) {
+                t->cmp += period;
+            }
+        }
+        diff = hpet_calculate_diff(t, cur_tick);
+        qemu_mod_timer(t->qemu_timer,
+                       qemu_get_clock_ns(vm_clock) + (int64_t)ticks_to_ns(diff));
+    } else if (t->config & HPET_TN_32BIT && !timer_is_periodic(t)) {
+        if (t->wrap_flag) {
+            diff = hpet_calculate_diff(t, cur_tick);
+            qemu_mod_timer(t->qemu_timer, qemu_get_clock_ns(vm_clock) +
+                           (int64_t)ticks_to_ns(diff));
+            t->wrap_flag = 0;
+        }
+    }
+    update_irq(t, 1);
+}
+
+static void hpet_set_timer(HPETTimer *t)
+{
+    uint64_t diff;
+    uint32_t wrap_diff;  /* how many ticks until we wrap? */
+    uint64_t cur_tick = hpet_get_ticks(t->state);
+
+    /* whenever new timer is being set up, make sure wrap_flag is 0 */
+    t->wrap_flag = 0;
+    diff = hpet_calculate_diff(t, cur_tick);
+
+    /* hpet spec says in one-shot 32-bit mode, generate an interrupt when
+     * counter wraps in addition to an interrupt with comparator match.
+     */
+    if (t->config & HPET_TN_32BIT && !timer_is_periodic(t)) {
+        wrap_diff = 0xffffffff - (uint32_t)cur_tick;
+        if (wrap_diff < (uint32_t)diff) {
+            diff = wrap_diff;
+            t->wrap_flag = 1;
+        }
+    }
+    qemu_mod_timer(t->qemu_timer,
+                   qemu_get_clock_ns(vm_clock) + (int64_t)ticks_to_ns(diff));
+}
+
+static void hpet_del_timer(HPETTimer *t)
+{
+    qemu_del_timer(t->qemu_timer);
+    update_irq(t, 0);
+}
+
+#ifdef HPET_DEBUG
+static uint32_t hpet_ram_readb(void *opaque, hwaddr addr)
+{
+    printf("qemu: hpet_read b at %" PRIx64 "\n", addr);
+    return 0;
+}
+
+static uint32_t hpet_ram_readw(void *opaque, hwaddr addr)
+{
+    printf("qemu: hpet_read w at %" PRIx64 "\n", addr);
+    return 0;
+}
+#endif
+
+static uint64_t hpet_ram_read(void *opaque, hwaddr addr,
+                              unsigned size)
+{
+    HPETState *s = opaque;
+    uint64_t cur_tick, index;
+
+    DPRINTF("qemu: Enter hpet_ram_readl at %" PRIx64 "\n", addr);
+    index = addr;
+    /*address range of all TN regs*/
+    if (index >= 0x100 && index <= 0x3ff) {
+        uint8_t timer_id = (addr - 0x100) / 0x20;
+        HPETTimer *timer = &s->timer[timer_id];
+
+        if (timer_id > s->num_timers) {
+            DPRINTF("qemu: timer id out of range\n");
+            return 0;
+        }
+
+        switch ((addr - 0x100) % 0x20) {
+        case HPET_TN_CFG:
+            return timer->config;
+        case HPET_TN_CFG + 4: // Interrupt capabilities
+            return timer->config >> 32;
+        case HPET_TN_CMP: // comparator register
+            return timer->cmp;
+        case HPET_TN_CMP + 4:
+            return timer->cmp >> 32;
+        case HPET_TN_ROUTE:
+            return timer->fsb;
+        case HPET_TN_ROUTE + 4:
+            return timer->fsb >> 32;
+        default:
+            DPRINTF("qemu: invalid hpet_ram_readl\n");
+            break;
+        }
+    } else {
+        switch (index) {
+        case HPET_ID:
+            return s->capability;
+        case HPET_PERIOD:
+            return s->capability >> 32;
+        case HPET_CFG:
+            return s->config;
+        case HPET_CFG + 4:
+            DPRINTF("qemu: invalid HPET_CFG + 4 hpet_ram_readl\n");
+            return 0;
+        case HPET_COUNTER:
+            if (hpet_enabled(s)) {
+                cur_tick = hpet_get_ticks(s);
+            } else {
+                cur_tick = s->hpet_counter;
+            }
+            DPRINTF("qemu: reading counter  = %" PRIx64 "\n", cur_tick);
+            return cur_tick;
+        case HPET_COUNTER + 4:
+            if (hpet_enabled(s)) {
+                cur_tick = hpet_get_ticks(s);
+            } else {
+                cur_tick = s->hpet_counter;
+            }
+            DPRINTF("qemu: reading counter + 4  = %" PRIx64 "\n", cur_tick);
+            return cur_tick >> 32;
+        case HPET_STATUS:
+            return s->isr;
+        default:
+            DPRINTF("qemu: invalid hpet_ram_readl\n");
+            break;
+        }
+    }
+    return 0;
+}
+
+static void hpet_ram_write(void *opaque, hwaddr addr,
+                           uint64_t value, unsigned size)
+{
+    int i;
+    HPETState *s = opaque;
+    uint64_t old_val, new_val, val, index;
+
+    DPRINTF("qemu: Enter hpet_ram_writel at %" PRIx64 " = %#x\n", addr, value);
+    index = addr;
+    old_val = hpet_ram_read(opaque, addr, 4);
+    new_val = value;
+
+    /*address range of all TN regs*/
+    if (index >= 0x100 && index <= 0x3ff) {
+        uint8_t timer_id = (addr - 0x100) / 0x20;
+        HPETTimer *timer = &s->timer[timer_id];
+
+        DPRINTF("qemu: hpet_ram_writel timer_id = %#x\n", timer_id);
+        if (timer_id > s->num_timers) {
+            DPRINTF("qemu: timer id out of range\n");
+            return;
+        }
+        switch ((addr - 0x100) % 0x20) {
+        case HPET_TN_CFG:
+            DPRINTF("qemu: hpet_ram_writel HPET_TN_CFG\n");
+            if (activating_bit(old_val, new_val, HPET_TN_FSB_ENABLE)) {
+                update_irq(timer, 0);
+            }
+            val = hpet_fixup_reg(new_val, old_val, HPET_TN_CFG_WRITE_MASK);
+            timer->config = (timer->config & 0xffffffff00000000ULL) | val;
+            if (new_val & HPET_TN_32BIT) {
+                timer->cmp = (uint32_t)timer->cmp;
+                timer->period = (uint32_t)timer->period;
+            }
+            if (activating_bit(old_val, new_val, HPET_TN_ENABLE)) {
+                hpet_set_timer(timer);
+            } else if (deactivating_bit(old_val, new_val, HPET_TN_ENABLE)) {
+                hpet_del_timer(timer);
+            }
+            break;
+        case HPET_TN_CFG + 4: // Interrupt capabilities
+            DPRINTF("qemu: invalid HPET_TN_CFG+4 write\n");
+            break;
+        case HPET_TN_CMP: // comparator register
+            DPRINTF("qemu: hpet_ram_writel HPET_TN_CMP\n");
+            if (timer->config & HPET_TN_32BIT) {
+                new_val = (uint32_t)new_val;
+            }
+            if (!timer_is_periodic(timer)
+                || (timer->config & HPET_TN_SETVAL)) {
+                timer->cmp = (timer->cmp & 0xffffffff00000000ULL) | new_val;
+            }
+            if (timer_is_periodic(timer)) {
+                /*
+                 * FIXME: Clamp period to reasonable min value?
+                 * Clamp period to reasonable max value
+                 */
+                new_val &= (timer->config & HPET_TN_32BIT ? ~0u : ~0ull) >> 1;
+                timer->period =
+                    (timer->period & 0xffffffff00000000ULL) | new_val;
+            }
+            timer->config &= ~HPET_TN_SETVAL;
+            if (hpet_enabled(s)) {
+                hpet_set_timer(timer);
+            }
+            break;
+        case HPET_TN_CMP + 4: // comparator register high order
+            DPRINTF("qemu: hpet_ram_writel HPET_TN_CMP + 4\n");
+            if (!timer_is_periodic(timer)
+                || (timer->config & HPET_TN_SETVAL)) {
+                timer->cmp = (timer->cmp & 0xffffffffULL) | new_val << 32;
+            } else {
+                /*
+                 * FIXME: Clamp period to reasonable min value?
+                 * Clamp period to reasonable max value
+                 */
+                new_val &= (timer->config & HPET_TN_32BIT ? ~0u : ~0ull) >> 1;
+                timer->period =
+                    (timer->period & 0xffffffffULL) | new_val << 32;
+                }
+                timer->config &= ~HPET_TN_SETVAL;
+                if (hpet_enabled(s)) {
+                    hpet_set_timer(timer);
+                }
+                break;
+        case HPET_TN_ROUTE:
+            timer->fsb = (timer->fsb & 0xffffffff00000000ULL) | new_val;
+            break;
+        case HPET_TN_ROUTE + 4:
+            timer->fsb = (new_val << 32) | (timer->fsb & 0xffffffff);
+            break;
+        default:
+            DPRINTF("qemu: invalid hpet_ram_writel\n");
+            break;
+        }
+        return;
+    } else {
+        switch (index) {
+        case HPET_ID:
+            return;
+        case HPET_CFG:
+            val = hpet_fixup_reg(new_val, old_val, HPET_CFG_WRITE_MASK);
+            s->config = (s->config & 0xffffffff00000000ULL) | val;
+            if (activating_bit(old_val, new_val, HPET_CFG_ENABLE)) {
+                /* Enable main counter and interrupt generation. */
+                s->hpet_offset =
+                    ticks_to_ns(s->hpet_counter) - qemu_get_clock_ns(vm_clock);
+                for (i = 0; i < s->num_timers; i++) {
+                    if ((&s->timer[i])->cmp != ~0ULL) {
+                        hpet_set_timer(&s->timer[i]);
+                    }
+                }
+            } else if (deactivating_bit(old_val, new_val, HPET_CFG_ENABLE)) {
+                /* Halt main counter and disable interrupt generation. */
+                s->hpet_counter = hpet_get_ticks(s);
+                for (i = 0; i < s->num_timers; i++) {
+                    hpet_del_timer(&s->timer[i]);
+                }
+            }
+            /* i8254 and RTC output pins are disabled
+             * when HPET is in legacy mode */
+            if (activating_bit(old_val, new_val, HPET_CFG_LEGACY)) {
+                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)) {
+                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;
+        case HPET_CFG + 4:
+            DPRINTF("qemu: invalid HPET_CFG+4 write\n");
+            break;
+        case HPET_STATUS:
+            val = new_val & s->isr;
+            for (i = 0; i < s->num_timers; i++) {
+                if (val & (1 << i)) {
+                    update_irq(&s->timer[i], 0);
+                }
+            }
+            break;
+        case HPET_COUNTER:
+            if (hpet_enabled(s)) {
+                DPRINTF("qemu: Writing counter while HPET enabled!\n");
+            }
+            s->hpet_counter =
+                (s->hpet_counter & 0xffffffff00000000ULL) | value;
+            DPRINTF("qemu: HPET counter written. ctr = %#x -> %" PRIx64 "\n",
+                    value, s->hpet_counter);
+            break;
+        case HPET_COUNTER + 4:
+            if (hpet_enabled(s)) {
+                DPRINTF("qemu: Writing counter while HPET enabled!\n");
+            }
+            s->hpet_counter =
+                (s->hpet_counter & 0xffffffffULL) | (((uint64_t)value) << 32);
+            DPRINTF("qemu: HPET counter + 4 written. ctr = %#x -> %" PRIx64 "\n",
+                    value, s->hpet_counter);
+            break;
+        default:
+            DPRINTF("qemu: invalid hpet_ram_writel\n");
+            break;
+        }
+    }
+}
+
+static const MemoryRegionOps hpet_ram_ops = {
+    .read = hpet_ram_read,
+    .write = hpet_ram_write,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void hpet_reset(DeviceState *d)
+{
+    HPETState *s = FROM_SYSBUS(HPETState, SYS_BUS_DEVICE(d));
+    int i;
+
+    for (i = 0; i < s->num_timers; i++) {
+        HPETTimer *timer = &s->timer[i];
+
+        hpet_del_timer(timer);
+        timer->cmp = ~0ULL;
+        timer->config = HPET_TN_PERIODIC_CAP | HPET_TN_SIZE_CAP;
+        if (s->flags & (1 << HPET_MSI_SUPPORT)) {
+            timer->config |= HPET_TN_FSB_CAP;
+        }
+        /* advertise availability of ioapic inti2 */
+        timer->config |=  0x00000004ULL << 32;
+        timer->period = 0ULL;
+        timer->wrap_flag = 0;
+    }
+
+    qemu_set_irq(s->pit_enabled, 1);
+    s->hpet_counter = 0ULL;
+    s->hpet_offset = 0ULL;
+    s->config = 0ULL;
+    hpet_cfg.hpet[s->hpet_id].event_timer_block_id = (uint32_t)s->capability;
+    hpet_cfg.hpet[s->hpet_id].address = SYS_BUS_DEVICE(d)->mmio[0].addr;
+
+    /* to document that the RTC lowers its output on reset as well */
+    s->rtc_irq_level = 0;
+}
+
+static void hpet_handle_legacy_irq(void *opaque, int n, int level)
+{
+    HPETState *s = FROM_SYSBUS(HPETState, opaque);
+
+    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);
+        }
+    }
+}
+
+static int hpet_init(SysBusDevice *dev)
+{
+    HPETState *s = FROM_SYSBUS(HPETState, dev);
+    int i;
+    HPETTimer *timer;
+
+    if (hpet_cfg.count == UINT8_MAX) {
+        /* first instance */
+        hpet_cfg.count = 0;
+    }
+
+    if (hpet_cfg.count == 8) {
+        fprintf(stderr, "Only 8 instances of HPET is allowed\n");
+        return -1;
+    }
+
+    s->hpet_id = hpet_cfg.count++;
+
+    for (i = 0; i < HPET_NUM_IRQ_ROUTES; i++) {
+        sysbus_init_irq(dev, &s->irqs[i]);
+    }
+
+    if (s->num_timers < HPET_MIN_TIMERS) {
+        s->num_timers = HPET_MIN_TIMERS;
+    } else if (s->num_timers > HPET_MAX_TIMERS) {
+        s->num_timers = HPET_MAX_TIMERS;
+    }
+    for (i = 0; i < HPET_MAX_TIMERS; i++) {
+        timer = &s->timer[i];
+        timer->qemu_timer = qemu_new_timer_ns(vm_clock, hpet_timer, timer);
+        timer->tn = i;
+        timer->state = s;
+    }
+
+    /* 64-bit main counter; LegacyReplacementRoute. */
+    s->capability = 0x8086a001ULL;
+    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_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);
+    sysbus_init_mmio(dev, &s->iomem);
+    return 0;
+}
+
+static Property hpet_device_properties[] = {
+    DEFINE_PROP_UINT8("timers", HPETState, num_timers, HPET_MIN_TIMERS),
+    DEFINE_PROP_BIT("msi", HPETState, flags, HPET_MSI_SUPPORT, false),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void hpet_device_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = hpet_init;
+    dc->no_user = 1;
+    dc->reset = hpet_reset;
+    dc->vmsd = &vmstate_hpet;
+    dc->props = hpet_device_properties;
+}
+
+static const 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_types(void)
+{
+    type_register_static(&hpet_device_info);
+}
+
+type_init(hpet_register_types)
diff --git a/hw/timer/i8254.c b/hw/timer/i8254.c
new file mode 100644 (file)
index 0000000..20c0c36
--- /dev/null
@@ -0,0 +1,362 @@
+/*
+ * 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.
+ */
+#include "hw/hw.h"
+#include "hw/i386/pc.h"
+#include "hw/isa/isa.h"
+#include "qemu/timer.h"
+#include "hw/timer/i8254.h"
+#include "hw/timer/i8254_internal.h"
+
+//#define DEBUG_PIT
+
+#define RW_STATE_LSB 1
+#define RW_STATE_MSB 2
+#define RW_STATE_WORD0 3
+#define RW_STATE_WORD1 4
+
+static void pit_irq_timer_update(PITChannelState *s, int64_t current_time);
+
+static int pit_get_count(PITChannelState *s)
+{
+    uint64_t d;
+    int counter;
+
+    d = muldiv64(qemu_get_clock_ns(vm_clock) - s->count_load_time, PIT_FREQ,
+                 get_ticks_per_sec());
+    switch(s->mode) {
+    case 0:
+    case 1:
+    case 4:
+    case 5:
+        counter = (s->count - d) & 0xffff;
+        break;
+    case 3:
+        /* XXX: may be incorrect for odd counts */
+        counter = s->count - ((2 * d) % s->count);
+        break;
+    default:
+        counter = s->count - (d % s->count);
+        break;
+    }
+    return counter;
+}
+
+/* val must be 0 or 1 */
+static void pit_set_channel_gate(PITCommonState *s, PITChannelState *sc,
+                                 int val)
+{
+    switch (sc->mode) {
+    default:
+    case 0:
+    case 4:
+        /* XXX: just disable/enable counting */
+        break;
+    case 1:
+    case 5:
+        if (sc->gate < val) {
+            /* restart counting on rising edge */
+            sc->count_load_time = qemu_get_clock_ns(vm_clock);
+            pit_irq_timer_update(sc, sc->count_load_time);
+        }
+        break;
+    case 2:
+    case 3:
+        if (sc->gate < val) {
+            /* restart counting on rising edge */
+            sc->count_load_time = qemu_get_clock_ns(vm_clock);
+            pit_irq_timer_update(sc, sc->count_load_time);
+        }
+        /* XXX: disable/enable counting */
+        break;
+    }
+    sc->gate = val;
+}
+
+static inline void pit_load_count(PITChannelState *s, int val)
+{
+    if (val == 0)
+        val = 0x10000;
+    s->count_load_time = qemu_get_clock_ns(vm_clock);
+    s->count = val;
+    pit_irq_timer_update(s, s->count_load_time);
+}
+
+/* if already latched, do not latch again */
+static void pit_latch_count(PITChannelState *s)
+{
+    if (!s->count_latched) {
+        s->latched_count = pit_get_count(s);
+        s->count_latched = s->rw_mode;
+    }
+}
+
+static void pit_ioport_write(void *opaque, hwaddr addr,
+                             uint64_t val, unsigned size)
+{
+    PITCommonState *pit = opaque;
+    int channel, access;
+    PITChannelState *s;
+
+    addr &= 3;
+    if (addr == 3) {
+        channel = val >> 6;
+        if (channel == 3) {
+            /* read back command */
+            for(channel = 0; channel < 3; channel++) {
+                s = &pit->channels[channel];
+                if (val & (2 << channel)) {
+                    if (!(val & 0x20)) {
+                        pit_latch_count(s);
+                    }
+                    if (!(val & 0x10) && !s->status_latched) {
+                        /* status latch */
+                        /* XXX: add BCD and null count */
+                        s->status =
+                            (pit_get_out(s,
+                                         qemu_get_clock_ns(vm_clock)) << 7) |
+                            (s->rw_mode << 4) |
+                            (s->mode << 1) |
+                            s->bcd;
+                        s->status_latched = 1;
+                    }
+                }
+            }
+        } else {
+            s = &pit->channels[channel];
+            access = (val >> 4) & 3;
+            if (access == 0) {
+                pit_latch_count(s);
+            } else {
+                s->rw_mode = access;
+                s->read_state = access;
+                s->write_state = access;
+
+                s->mode = (val >> 1) & 7;
+                s->bcd = val & 1;
+                /* XXX: update irq timer ? */
+            }
+        }
+    } else {
+        s = &pit->channels[addr];
+        switch(s->write_state) {
+        default:
+        case RW_STATE_LSB:
+            pit_load_count(s, val);
+            break;
+        case RW_STATE_MSB:
+            pit_load_count(s, val << 8);
+            break;
+        case RW_STATE_WORD0:
+            s->write_latch = val;
+            s->write_state = RW_STATE_WORD1;
+            break;
+        case RW_STATE_WORD1:
+            pit_load_count(s, s->write_latch | (val << 8));
+            s->write_state = RW_STATE_WORD0;
+            break;
+        }
+    }
+}
+
+static uint64_t pit_ioport_read(void *opaque, hwaddr addr,
+                                unsigned size)
+{
+    PITCommonState *pit = opaque;
+    int ret, count;
+    PITChannelState *s;
+
+    addr &= 3;
+    s = &pit->channels[addr];
+    if (s->status_latched) {
+        s->status_latched = 0;
+        ret = s->status;
+    } else if (s->count_latched) {
+        switch(s->count_latched) {
+        default:
+        case RW_STATE_LSB:
+            ret = s->latched_count & 0xff;
+            s->count_latched = 0;
+            break;
+        case RW_STATE_MSB:
+            ret = s->latched_count >> 8;
+            s->count_latched = 0;
+            break;
+        case RW_STATE_WORD0:
+            ret = s->latched_count & 0xff;
+            s->count_latched = RW_STATE_MSB;
+            break;
+        }
+    } else {
+        switch(s->read_state) {
+        default:
+        case RW_STATE_LSB:
+            count = pit_get_count(s);
+            ret = count & 0xff;
+            break;
+        case RW_STATE_MSB:
+            count = pit_get_count(s);
+            ret = (count >> 8) & 0xff;
+            break;
+        case RW_STATE_WORD0:
+            count = pit_get_count(s);
+            ret = count & 0xff;
+            s->read_state = RW_STATE_WORD1;
+            break;
+        case RW_STATE_WORD1:
+            count = pit_get_count(s);
+            ret = (count >> 8) & 0xff;
+            s->read_state = RW_STATE_WORD0;
+            break;
+        }
+    }
+    return ret;
+}
+
+static void pit_irq_timer_update(PITChannelState *s, int64_t current_time)
+{
+    int64_t expire_time;
+    int irq_level;
+
+    if (!s->irq_timer || s->irq_disabled) {
+        return;
+    }
+    expire_time = pit_get_next_transition_time(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",
+           irq_level,
+           (double)(expire_time - current_time) / get_ticks_per_sec());
+#endif
+    s->next_transition_time = expire_time;
+    if (expire_time != -1)
+        qemu_mod_timer(s->irq_timer, expire_time);
+    else
+        qemu_del_timer(s->irq_timer);
+}
+
+static void pit_irq_timer(void *opaque)
+{
+    PITChannelState *s = opaque;
+
+    pit_irq_timer_update(s, s->next_transition_time);
+}
+
+static void pit_reset(DeviceState *dev)
+{
+    PITCommonState *pit = DO_UPCAST(PITCommonState, dev.qdev, dev);
+    PITChannelState *s;
+
+    pit_reset_common(pit);
+
+    s = &pit->channels[0];
+    if (!s->irq_disabled) {
+        qemu_mod_timer(s->irq_timer, s->next_transition_time);
+    }
+}
+
+/* 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)
+{
+    PITCommonState *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 MemoryRegionOps pit_ioport_ops = {
+    .read = pit_ioport_read,
+    .write = pit_ioport_write,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void pit_post_load(PITCommonState *s)
+{
+    PITChannelState *sc = &s->channels[0];
+
+    if (sc->next_transition_time != -1) {
+        qemu_mod_timer(sc->irq_timer, sc->next_transition_time);
+    } else {
+        qemu_del_timer(sc->irq_timer);
+    }
+}
+
+static int pit_initfn(PITCommonState *pit)
+{
+    PITChannelState *s;
+
+    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);
+    qdev_init_gpio_out(&pit->dev.qdev, &s->irq, 1);
+
+    memory_region_init_io(&pit->ioports, &pit_ioport_ops, pit, "pit", 4);
+
+    qdev_init_gpio_in(&pit->dev.qdev, pit_irq_control, 1);
+
+    return 0;
+}
+
+static Property pit_properties[] = {
+    DEFINE_PROP_HEX32("iobase", PITCommonState, iobase,  -1),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void pit_class_initfn(ObjectClass *klass, void *data)
+{
+    PITCommonClass *k = PIT_COMMON_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    k->init = pit_initfn;
+    k->set_channel_gate = pit_set_channel_gate;
+    k->get_channel_info = pit_get_channel_info_common;
+    k->post_load = pit_post_load;
+    dc->reset = pit_reset;
+    dc->props = pit_properties;
+}
+
+static const TypeInfo pit_info = {
+    .name          = "isa-pit",
+    .parent        = TYPE_PIT_COMMON,
+    .instance_size = sizeof(PITCommonState),
+    .class_init    = pit_class_initfn,
+};
+
+static void pit_register_types(void)
+{
+    type_register_static(&pit_info);
+}
+
+type_init(pit_register_types)
diff --git a/hw/timer/i8254_common.c b/hw/timer/i8254_common.c
new file mode 100644 (file)
index 0000000..5342df4
--- /dev/null
@@ -0,0 +1,311 @@
+/*
+ * QEMU 8253/8254 - common bits of emulated and KVM kernel model
+ *
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ * Copyright (c) 2012      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 "hw/hw.h"
+#include "hw/i386/pc.h"
+#include "hw/isa/isa.h"
+#include "qemu/timer.h"
+#include "hw/timer/i8254.h"
+#include "hw/timer/i8254_internal.h"
+
+/* val must be 0 or 1 */
+void pit_set_gate(ISADevice *dev, int channel, int val)
+{
+    PITCommonState *pit = PIT_COMMON(dev);
+    PITChannelState *s = &pit->channels[channel];
+    PITCommonClass *c = PIT_COMMON_GET_CLASS(pit);
+
+    c->set_channel_gate(pit, s, val);
+}
+
+/* get pit output bit */
+int pit_get_out(PITChannelState *s, int64_t current_time)
+{
+    uint64_t d;
+    int out;
+
+    d = muldiv64(current_time - s->count_load_time, PIT_FREQ,
+                 get_ticks_per_sec());
+    switch (s->mode) {
+    default:
+    case 0:
+        out = (d >= s->count);
+        break;
+    case 1:
+        out = (d < s->count);
+        break;
+    case 2:
+        if ((d % s->count) == 0 && d != 0) {
+            out = 1;
+        } else {
+            out = 0;
+        }
+        break;
+    case 3:
+        out = (d % s->count) < ((s->count + 1) >> 1);
+        break;
+    case 4:
+    case 5:
+        out = (d == s->count);
+        break;
+    }
+    return out;
+}
+
+/* return -1 if no transition will occur.  */
+int64_t pit_get_next_transition_time(PITChannelState *s, int64_t current_time)
+{
+    uint64_t d, next_time, base;
+    int period2;
+
+    d = muldiv64(current_time - s->count_load_time, PIT_FREQ,
+                 get_ticks_per_sec());
+    switch (s->mode) {
+    default:
+    case 0:
+    case 1:
+        if (d < s->count) {
+            next_time = s->count;
+        } else {
+            return -1;
+        }
+        break;
+    case 2:
+        base = (d / s->count) * s->count;
+        if ((d - base) == 0 && d != 0) {
+            next_time = base + s->count;
+        } else {
+            next_time = base + s->count + 1;
+        }
+        break;
+    case 3:
+        base = (d / s->count) * s->count;
+        period2 = ((s->count + 1) >> 1);
+        if ((d - base) < period2) {
+            next_time = base + period2;
+        } else {
+            next_time = base + s->count;
+        }
+        break;
+    case 4:
+    case 5:
+        if (d < s->count) {
+            next_time = s->count;
+        } else if (d == s->count) {
+            next_time = s->count + 1;
+        } else {
+            return -1;
+        }
+        break;
+    }
+    /* convert to timer units */
+    next_time = s->count_load_time + muldiv64(next_time, get_ticks_per_sec(),
+                                              PIT_FREQ);
+    /* fix potential rounding problems */
+    /* XXX: better solution: use a clock at PIT_FREQ Hz */
+    if (next_time <= current_time) {
+        next_time = current_time + 1;
+    }
+    return next_time;
+}
+
+void pit_get_channel_info_common(PITCommonState *s, PITChannelState *sc,
+                                 PITChannelInfo *info)
+{
+    info->gate = sc->gate;
+    info->mode = sc->mode;
+    info->initial_count = sc->count;
+    info->out = pit_get_out(sc, qemu_get_clock_ns(vm_clock));
+}
+
+void pit_get_channel_info(ISADevice *dev, int channel, PITChannelInfo *info)
+{
+    PITCommonState *pit = PIT_COMMON(dev);
+    PITChannelState *s = &pit->channels[channel];
+    PITCommonClass *c = PIT_COMMON_GET_CLASS(pit);
+
+    c->get_channel_info(pit, s, info);
+}
+
+void pit_reset_common(PITCommonState *pit)
+{
+    PITChannelState *s;
+    int i;
+
+    for (i = 0; i < 3; i++) {
+        s = &pit->channels[i];
+        s->mode = 3;
+        s->gate = (i != 2);
+        s->count_load_time = qemu_get_clock_ns(vm_clock);
+        s->count = 0x10000;
+        if (i == 0 && !s->irq_disabled) {
+            s->next_transition_time =
+                pit_get_next_transition_time(s, s->count_load_time);
+        }
+    }
+}
+
+static int pit_init_common(ISADevice *dev)
+{
+    PITCommonState *pit = PIT_COMMON(dev);
+    PITCommonClass *c = PIT_COMMON_GET_CLASS(pit);
+    int ret;
+
+    ret = c->init(pit);
+    if (ret < 0) {
+        return ret;
+    }
+
+    isa_register_ioport(dev, &pit->ioports, pit->iobase);
+
+    qdev_set_legacy_instance_id(&dev->qdev, pit->iobase, 2);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_pit_channel = {
+    .name = "pit channel",
+    .version_id = 2,
+    .minimum_version_id = 2,
+    .minimum_version_id_old = 2,
+    .fields = (VMStateField[]) {
+        VMSTATE_INT32(count, PITChannelState),
+        VMSTATE_UINT16(latched_count, PITChannelState),
+        VMSTATE_UINT8(count_latched, PITChannelState),
+        VMSTATE_UINT8(status_latched, PITChannelState),
+        VMSTATE_UINT8(status, PITChannelState),
+        VMSTATE_UINT8(read_state, PITChannelState),
+        VMSTATE_UINT8(write_state, PITChannelState),
+        VMSTATE_UINT8(write_latch, PITChannelState),
+        VMSTATE_UINT8(rw_mode, PITChannelState),
+        VMSTATE_UINT8(mode, PITChannelState),
+        VMSTATE_UINT8(bcd, PITChannelState),
+        VMSTATE_UINT8(gate, PITChannelState),
+        VMSTATE_INT64(count_load_time, PITChannelState),
+        VMSTATE_INT64(next_transition_time, PITChannelState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int pit_load_old(QEMUFile *f, void *opaque, int version_id)
+{
+    PITCommonState *pit = opaque;
+    PITCommonClass *c = PIT_COMMON_GET_CLASS(pit);
+    PITChannelState *s;
+    int i;
+
+    if (version_id != 1) {
+        return -EINVAL;
+    }
+
+    for (i = 0; i < 3; i++) {
+        s = &pit->channels[i];
+        s->count = qemu_get_be32(f);
+        qemu_get_be16s(f, &s->latched_count);
+        qemu_get_8s(f, &s->count_latched);
+        qemu_get_8s(f, &s->status_latched);
+        qemu_get_8s(f, &s->status);
+        qemu_get_8s(f, &s->read_state);
+        qemu_get_8s(f, &s->write_state);
+        qemu_get_8s(f, &s->write_latch);
+        qemu_get_8s(f, &s->rw_mode);
+        qemu_get_8s(f, &s->mode);
+        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 (i == 0) {
+            s->next_transition_time = qemu_get_be64(f);
+        }
+    }
+    if (c->post_load) {
+        c->post_load(pit);
+    }
+    return 0;
+}
+
+static void pit_dispatch_pre_save(void *opaque)
+{
+    PITCommonState *s = opaque;
+    PITCommonClass *c = PIT_COMMON_GET_CLASS(s);
+
+    if (c->pre_save) {
+        c->pre_save(s);
+    }
+}
+
+static int pit_dispatch_post_load(void *opaque, int version_id)
+{
+    PITCommonState *s = opaque;
+    PITCommonClass *c = PIT_COMMON_GET_CLASS(s);
+
+    if (c->post_load) {
+        c->post_load(s);
+    }
+    return 0;
+}
+
+static const VMStateDescription vmstate_pit_common = {
+    .name = "i8254",
+    .version_id = 3,
+    .minimum_version_id = 2,
+    .minimum_version_id_old = 1,
+    .load_state_old = pit_load_old,
+    .pre_save = pit_dispatch_pre_save,
+    .post_load = pit_dispatch_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32_V(channels[0].irq_disabled, PITCommonState, 3),
+        VMSTATE_STRUCT_ARRAY(channels, PITCommonState, 3, 2,
+                             vmstate_pit_channel, PITChannelState),
+        VMSTATE_INT64(channels[0].next_transition_time,
+                      PITCommonState), /* formerly irq_timer */
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void pit_common_class_init(ObjectClass *klass, void *data)
+{
+    ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    ic->init = pit_init_common;
+    dc->vmsd = &vmstate_pit_common;
+    dc->no_user = 1;
+}
+
+static const TypeInfo pit_common_type = {
+    .name          = TYPE_PIT_COMMON,
+    .parent        = TYPE_ISA_DEVICE,
+    .instance_size = sizeof(PITCommonState),
+    .class_size    = sizeof(PITCommonClass),
+    .class_init    = pit_common_class_init,
+    .abstract      = true,
+};
+
+static void register_devices(void)
+{
+    type_register_static(&pit_common_type);
+}
+
+type_init(register_devices);
diff --git a/hw/timer/imx_timer.c b/hw/timer/imx_timer.c
new file mode 100644 (file)
index 0000000..03197e3
--- /dev/null
@@ -0,0 +1,689 @@
+/*
+ * IMX31 Timer
+ *
+ * Copyright (c) 2008 OK Labs
+ * Copyright (c) 2011 NICTA Pty Ltd
+ * Originally written by Hans Jiang
+ * Updated by Peter Chubb
+ *
+ * This code is licensed under GPL version 2 or later.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "hw/hw.h"
+#include "qemu/timer.h"
+#include "hw/ptimer.h"
+#include "hw/sysbus.h"
+#include "hw/arm/imx.h"
+
+//#define DEBUG_TIMER 1
+#ifdef DEBUG_TIMER
+#  define DPRINTF(fmt, args...) \
+      do { printf("imx_timer: " fmt , ##args); } while (0)
+#else
+#  define DPRINTF(fmt, args...) do {} while (0)
+#endif
+
+/*
+ * Define to 1 for messages about attempts to
+ * access unimplemented registers or similar.
+ */
+#define DEBUG_IMPLEMENTATION 1
+#if DEBUG_IMPLEMENTATION
+#  define IPRINTF(fmt, args...)                                         \
+    do  { fprintf(stderr, "imx_timer: " fmt, ##args); } while (0)
+#else
+#  define IPRINTF(fmt, args...) do {} while (0)
+#endif
+
+/*
+ * GPT : General purpose timer
+ *
+ * This timer counts up continuously while it is enabled, resetting itself
+ * to 0 when it reaches TIMER_MAX (in freerun mode) or when it
+ * reaches the value of ocr1 (in periodic mode).  WE simulate this using a
+ * QEMU ptimer counting down from ocr1 and reloading from ocr1 in
+ * periodic mode, or counting from ocr1 to zero, then TIMER_MAX - ocr1.
+ * waiting_rov is set when counting from TIMER_MAX.
+ *
+ * In the real hardware, there are three comparison registers that can
+ * trigger interrupts, and compare channel 1 can be used to
+ * force-reset the timer. However, this is a `bare-bones'
+ * implementation: only what Linux 3.x uses has been implemented
+ * (free-running timer from 0 to OCR1 or TIMER_MAX) .
+ */
+
+
+#define TIMER_MAX  0XFFFFFFFFUL
+
+/* Control register.  Not all of these bits have any effect (yet) */
+#define GPT_CR_EN     (1 << 0)  /* GPT Enable */
+#define GPT_CR_ENMOD  (1 << 1)  /* GPT Enable Mode */
+#define GPT_CR_DBGEN  (1 << 2)  /* GPT Debug mode enable */
+#define GPT_CR_WAITEN (1 << 3)  /* GPT Wait Mode Enable  */
+#define GPT_CR_DOZEN  (1 << 4)  /* GPT Doze mode enable */
+#define GPT_CR_STOPEN (1 << 5)  /* GPT Stop Mode Enable */
+#define GPT_CR_CLKSRC_SHIFT (6)
+#define GPT_CR_CLKSRC_MASK  (0x7)
+
+#define GPT_CR_FRR    (1 << 9)  /* Freerun or Restart */
+#define GPT_CR_SWR    (1 << 15) /* Software Reset */
+#define GPT_CR_IM1    (3 << 16) /* Input capture channel 1 mode (2 bits) */
+#define GPT_CR_IM2    (3 << 18) /* Input capture channel 2 mode (2 bits) */
+#define GPT_CR_OM1    (7 << 20) /* Output Compare Channel 1 Mode (3 bits) */
+#define GPT_CR_OM2    (7 << 23) /* Output Compare Channel 2 Mode (3 bits) */
+#define GPT_CR_OM3    (7 << 26) /* Output Compare Channel 3 Mode (3 bits) */
+#define GPT_CR_FO1    (1 << 29) /* Force Output Compare Channel 1 */
+#define GPT_CR_FO2    (1 << 30) /* Force Output Compare Channel 2 */
+#define GPT_CR_FO3    (1 << 31) /* Force Output Compare Channel 3 */
+
+#define GPT_SR_OF1  (1 << 0)
+#define GPT_SR_ROV  (1 << 5)
+
+#define GPT_IR_OF1IE  (1 << 0)
+#define GPT_IR_ROVIE  (1 << 5)
+
+typedef struct {
+    SysBusDevice busdev;
+    ptimer_state *timer;
+    MemoryRegion iomem;
+    DeviceState *ccm;
+
+    uint32_t cr;
+    uint32_t pr;
+    uint32_t sr;
+    uint32_t ir;
+    uint32_t ocr1;
+    uint32_t cnt;
+
+    uint32_t waiting_rov;
+    qemu_irq irq;
+} IMXTimerGState;
+
+static const VMStateDescription vmstate_imx_timerg = {
+    .name = "imx-timerg",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32(cr, IMXTimerGState),
+        VMSTATE_UINT32(pr, IMXTimerGState),
+        VMSTATE_UINT32(sr, IMXTimerGState),
+        VMSTATE_UINT32(ir, IMXTimerGState),
+        VMSTATE_UINT32(ocr1, IMXTimerGState),
+        VMSTATE_UINT32(cnt, IMXTimerGState),
+        VMSTATE_UINT32(waiting_rov, IMXTimerGState),
+        VMSTATE_PTIMER(timer, IMXTimerGState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const IMXClk imx_timerg_clocks[] = {
+    NOCLK,    /* 000 No clock source */
+    IPG,      /* 001 ipg_clk, 532MHz*/
+    IPG,      /* 010 ipg_clk_highfreq */
+    NOCLK,    /* 011 not defined */
+    CLK_32k,  /* 100 ipg_clk_32k */
+    NOCLK,    /* 101 not defined */
+    NOCLK,    /* 110 not defined */
+    NOCLK,    /* 111 not defined */
+};
+
+
+static void imx_timerg_set_freq(IMXTimerGState *s)
+{
+    int clksrc;
+    uint32_t freq;
+
+    clksrc = (s->cr >> GPT_CR_CLKSRC_SHIFT) & GPT_CR_CLKSRC_MASK;
+    freq = imx_clock_frequency(s->ccm, imx_timerg_clocks[clksrc]) / (1 + s->pr);
+
+    DPRINTF("Setting gtimer clksrc %d to frequency %d\n", clksrc, freq);
+    if (freq) {
+        ptimer_set_freq(s->timer, freq);
+    }
+}
+
+static void imx_timerg_update(IMXTimerGState *s)
+{
+    uint32_t flags = s->sr & s->ir & (GPT_SR_OF1 | GPT_SR_ROV);
+
+    DPRINTF("g-timer SR: %s %s IR=%s %s, %s\n",
+            s->sr & GPT_SR_OF1 ? "OF1" : "",
+            s->sr & GPT_SR_ROV ? "ROV" : "",
+            s->ir & GPT_SR_OF1 ? "OF1" : "",
+            s->ir & GPT_SR_ROV ? "ROV" : "",
+            s->cr & GPT_CR_EN ? "CR_EN" : "Not Enabled");
+
+
+    qemu_set_irq(s->irq, (s->cr & GPT_CR_EN) && flags);
+}
+
+static uint32_t imx_timerg_update_counts(IMXTimerGState *s)
+{
+    uint64_t target = s->waiting_rov ? TIMER_MAX : s->ocr1;
+    uint64_t cnt = ptimer_get_count(s->timer);
+    s->cnt = target - cnt;
+    return s->cnt;
+}
+
+static void imx_timerg_reload(IMXTimerGState *s, uint32_t timeout)
+{
+    uint64_t diff_cnt;
+
+    if (!(s->cr & GPT_CR_FRR)) {
+        IPRINTF("IMX_timerg_reload --- called in reset-mode\n");
+        return;
+    }
+
+    /*
+     * For small timeouts, qemu sometimes runs too slow.
+     * Better deliver a late interrupt than none.
+     *
+     * In Reset mode (FRR bit clear)
+     * the ptimer reloads itself from OCR1;
+     * in free-running mode we need to fake
+     * running from 0 to ocr1 to TIMER_MAX
+     */
+    if (timeout > s->cnt) {
+        diff_cnt = timeout - s->cnt;
+    } else {
+        diff_cnt = 0;
+    }
+    ptimer_set_count(s->timer, diff_cnt);
+}
+
+static uint64_t imx_timerg_read(void *opaque, hwaddr offset,
+                                unsigned size)
+{
+    IMXTimerGState *s = (IMXTimerGState *)opaque;
+
+    DPRINTF("g-read(offset=%x)", offset >> 2);
+    switch (offset >> 2) {
+    case 0: /* Control Register */
+        DPRINTF(" cr = %x\n", s->cr);
+        return s->cr;
+
+    case 1: /* prescaler */
+        DPRINTF(" pr = %x\n", s->pr);
+        return s->pr;
+
+    case 2: /* Status Register */
+        DPRINTF(" sr = %x\n", s->sr);
+        return s->sr;
+
+    case 3: /* Interrupt Register */
+        DPRINTF(" ir = %x\n", s->ir);
+        return s->ir;
+
+    case 4: /* Output Compare Register 1 */
+        DPRINTF(" ocr1 = %x\n", s->ocr1);
+        return s->ocr1;
+
+
+    case 9: /* cnt */
+        imx_timerg_update_counts(s);
+        DPRINTF(" cnt = %x\n", s->cnt);
+        return s->cnt;
+    }
+
+    IPRINTF("imx_timerg_read: Bad offset %x\n",
+            (int)offset >> 2);
+    return 0;
+}
+
+static void imx_timerg_reset(DeviceState *dev)
+{
+    IMXTimerGState *s = container_of(dev, IMXTimerGState, busdev.qdev);
+
+    /*
+     * Soft reset doesn't touch some bits; hard reset clears them
+     */
+    s->cr &= ~(GPT_CR_EN|GPT_CR_DOZEN|GPT_CR_WAITEN|GPT_CR_DBGEN);
+    s->sr = 0;
+    s->pr = 0;
+    s->ir = 0;
+    s->cnt = 0;
+    s->ocr1 = TIMER_MAX;
+    ptimer_stop(s->timer);
+    ptimer_set_limit(s->timer, TIMER_MAX, 1);
+    imx_timerg_set_freq(s);
+}
+
+static void imx_timerg_write(void *opaque, hwaddr offset,
+                             uint64_t value, unsigned size)
+{
+    IMXTimerGState *s = (IMXTimerGState *)opaque;
+    DPRINTF("g-write(offset=%x, value = 0x%x)\n", (unsigned int)offset >> 2,
+            (unsigned int)value);
+
+    switch (offset >> 2) {
+    case 0: {
+        uint32_t oldcr = s->cr;
+        /* CR */
+        if (value & GPT_CR_SWR) { /* force reset */
+            value &= ~GPT_CR_SWR;
+            imx_timerg_reset(&s->busdev.qdev);
+            imx_timerg_update(s);
+        }
+
+        s->cr = value & ~0x7c00;
+        imx_timerg_set_freq(s);
+        if ((oldcr ^ value) & GPT_CR_EN) {
+            if (value & GPT_CR_EN) {
+                if (value & GPT_CR_ENMOD) {
+                    ptimer_set_count(s->timer, s->ocr1);
+                    s->cnt = 0;
+                }
+                ptimer_run(s->timer,
+                           (value & GPT_CR_FRR) && (s->ocr1 != TIMER_MAX));
+            } else {
+                ptimer_stop(s->timer);
+            };
+        }
+        return;
+    }
+
+    case 1: /* Prescaler */
+        s->pr = value & 0xfff;
+        imx_timerg_set_freq(s);
+        return;
+
+    case 2: /* SR */
+        /*
+         * No point in implementing the status register bits to do with
+         * external interrupt sources.
+         */
+        value &= GPT_SR_OF1 | GPT_SR_ROV;
+        s->sr &= ~value;
+        imx_timerg_update(s);
+        return;
+
+    case 3: /* IR -- interrupt register */
+        s->ir = value & 0x3f;
+        imx_timerg_update(s);
+        return;
+
+    case 4: /* OCR1 -- output compare register */
+        /* In non-freerun mode, reset count when this register is written */
+        if (!(s->cr & GPT_CR_FRR)) {
+            s->waiting_rov = 0;
+            ptimer_set_limit(s->timer, value, 1);
+        } else {
+            imx_timerg_update_counts(s);
+            if (value > s->cnt) {
+                s->waiting_rov = 0;
+                imx_timerg_reload(s, value);
+            } else {
+                s->waiting_rov = 1;
+                imx_timerg_reload(s, TIMER_MAX - s->cnt);
+            }
+        }
+        s->ocr1 = value;
+        return;
+
+    default:
+        IPRINTF("imx_timerg_write: Bad offset %x\n",
+                (int)offset >> 2);
+    }
+}
+
+static void imx_timerg_timeout(void *opaque)
+{
+    IMXTimerGState *s = (IMXTimerGState *)opaque;
+
+    DPRINTF("imx_timerg_timeout, waiting rov=%d\n", s->waiting_rov);
+    if (s->cr & GPT_CR_FRR) {
+        /*
+         * Free running timer from 0 -> TIMERMAX
+         * Generates interrupt at TIMER_MAX and at cnt==ocr1
+         * If ocr1 == TIMER_MAX, then no need to reload timer.
+         */
+        if (s->ocr1 == TIMER_MAX) {
+            DPRINTF("s->ocr1 == TIMER_MAX, FRR\n");
+            s->sr |= GPT_SR_OF1 | GPT_SR_ROV;
+            imx_timerg_update(s);
+            return;
+        }
+
+        if (s->waiting_rov) {
+            /*
+             * We were waiting for cnt==TIMER_MAX
+             */
+            s->sr |= GPT_SR_ROV;
+            s->waiting_rov = 0;
+            s->cnt = 0;
+            imx_timerg_reload(s, s->ocr1);
+        } else {
+            /* Must have got a cnt==ocr1 timeout. */
+            s->sr |= GPT_SR_OF1;
+            s->cnt = s->ocr1;
+            s->waiting_rov = 1;
+            imx_timerg_reload(s, TIMER_MAX);
+        }
+        imx_timerg_update(s);
+        return;
+    }
+
+    s->sr |= GPT_SR_OF1;
+    imx_timerg_update(s);
+}
+
+static const MemoryRegionOps imx_timerg_ops = {
+    .read = imx_timerg_read,
+    .write = imx_timerg_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+
+static int imx_timerg_init(SysBusDevice *dev)
+{
+    IMXTimerGState *s = FROM_SYSBUS(IMXTimerGState, dev);
+    QEMUBH *bh;
+
+    sysbus_init_irq(dev, &s->irq);
+    memory_region_init_io(&s->iomem, &imx_timerg_ops,
+                          s, "imxg-timer",
+                          0x00001000);
+    sysbus_init_mmio(dev, &s->iomem);
+
+    bh = qemu_bh_new(imx_timerg_timeout, s);
+    s->timer = ptimer_init(bh);
+
+    /* Hard reset resets extra bits in CR */
+    s->cr = 0;
+    return 0;
+}
+
+
+
+/*
+ * EPIT: Enhanced periodic interrupt timer
+ */
+
+#define CR_EN       (1 << 0)
+#define CR_ENMOD    (1 << 1)
+#define CR_OCIEN    (1 << 2)
+#define CR_RLD      (1 << 3)
+#define CR_PRESCALE_SHIFT (4)
+#define CR_PRESCALE_MASK  (0xfff)
+#define CR_SWR      (1 << 16)
+#define CR_IOVW     (1 << 17)
+#define CR_DBGEN    (1 << 18)
+#define CR_EPIT     (1 << 19)
+#define CR_DOZEN    (1 << 20)
+#define CR_STOPEN   (1 << 21)
+#define CR_CLKSRC_SHIFT (24)
+#define CR_CLKSRC_MASK  (0x3 << CR_CLKSRC_SHIFT)
+
+
+/*
+ * Exact clock frequencies vary from board to board.
+ * These are typical.
+ */
+static const IMXClk imx_timerp_clocks[] =  {
+    0,        /* disabled */
+    IPG, /* ipg_clk, ~532MHz */
+    IPG, /* ipg_clk_highfreq */
+    CLK_32k,    /* ipg_clk_32k -- ~32kHz */
+};
+
+typedef struct {
+    SysBusDevice busdev;
+    ptimer_state *timer;
+    MemoryRegion iomem;
+    DeviceState *ccm;
+
+    uint32_t cr;
+    uint32_t lr;
+    uint32_t cmp;
+
+    uint32_t freq;
+    int int_level;
+    qemu_irq irq;
+} IMXTimerPState;
+
+/*
+ * Update interrupt status
+ */
+static void imx_timerp_update(IMXTimerPState *s)
+{
+    if (s->int_level && (s->cr & CR_OCIEN)) {
+        qemu_irq_raise(s->irq);
+    } else {
+        qemu_irq_lower(s->irq);
+    }
+}
+
+static void imx_timerp_reset(DeviceState *dev)
+{
+    IMXTimerPState *s = container_of(dev, IMXTimerPState, busdev.qdev);
+
+    s->cr = 0;
+    s->lr = TIMER_MAX;
+    s->int_level = 0;
+    s->cmp = 0;
+    ptimer_stop(s->timer);
+    ptimer_set_count(s->timer, TIMER_MAX);
+}
+
+static uint64_t imx_timerp_read(void *opaque, hwaddr offset,
+                                unsigned size)
+{
+    IMXTimerPState *s = (IMXTimerPState *)opaque;
+
+    DPRINTF("p-read(offset=%x)", offset >> 2);
+    switch (offset >> 2) {
+    case 0: /* Control Register */
+        DPRINTF("cr %x\n", s->cr);
+        return s->cr;
+
+    case 1: /* Status Register */
+        DPRINTF("int_level %x\n", s->int_level);
+        return s->int_level;
+
+    case 2: /* LR - ticks*/
+        DPRINTF("lr %x\n", s->lr);
+        return s->lr;
+
+    case 3: /* CMP */
+        DPRINTF("cmp %x\n", s->cmp);
+        return s->cmp;
+
+    case 4: /* CNT */
+        return ptimer_get_count(s->timer);
+    }
+    IPRINTF("imx_timerp_read: Bad offset %x\n",
+            (int)offset >> 2);
+    return 0;
+}
+
+static void set_timerp_freq(IMXTimerPState *s)
+{
+    int clksrc;
+    unsigned prescaler;
+    uint32_t freq;
+
+    clksrc = (s->cr & CR_CLKSRC_MASK) >> CR_CLKSRC_SHIFT;
+    prescaler = 1 + ((s->cr >> CR_PRESCALE_SHIFT) & CR_PRESCALE_MASK);
+    freq = imx_clock_frequency(s->ccm, imx_timerp_clocks[clksrc]) / prescaler;
+
+    s->freq = freq;
+    DPRINTF("Setting ptimer frequency to %u\n", freq);
+
+    if (freq) {
+        ptimer_set_freq(s->timer, freq);
+    }
+}
+
+static void imx_timerp_write(void *opaque, hwaddr offset,
+                             uint64_t value, unsigned size)
+{
+    IMXTimerPState *s = (IMXTimerPState *)opaque;
+    DPRINTF("p-write(offset=%x, value = %x)\n", (unsigned int)offset >> 2,
+            (unsigned int)value);
+
+    switch (offset >> 2) {
+    case 0: /* CR */
+        if (value & CR_SWR) {
+            imx_timerp_reset(&s->busdev.qdev);
+            value &= ~CR_SWR;
+        }
+        s->cr = value & 0x03ffffff;
+        set_timerp_freq(s);
+
+        if (s->freq && (s->cr & CR_EN)) {
+            if (!(s->cr & CR_ENMOD)) {
+                ptimer_set_count(s->timer, s->lr);
+            }
+            ptimer_run(s->timer, 0);
+        } else {
+            ptimer_stop(s->timer);
+        }
+        break;
+
+    case 1: /* SR - ACK*/
+        s->int_level = 0;
+        imx_timerp_update(s);
+        break;
+
+    case 2: /* LR - set ticks */
+        s->lr = value;
+        ptimer_set_limit(s->timer, value, !!(s->cr & CR_IOVW));
+        break;
+
+    case 3: /* CMP */
+        s->cmp = value;
+        if (value) {
+            IPRINTF(
+                "Values for EPIT comparison other than zero not supported\n"
+            );
+        }
+        break;
+
+    default:
+        IPRINTF("imx_timerp_write: Bad offset %x\n",
+                   (int)offset >> 2);
+    }
+}
+
+static void imx_timerp_tick(void *opaque)
+{
+    IMXTimerPState *s = (IMXTimerPState *)opaque;
+
+   DPRINTF("imxp tick\n");
+    if (!(s->cr & CR_RLD)) {
+        ptimer_set_count(s->timer, TIMER_MAX);
+    }
+    s->int_level = 1;
+    imx_timerp_update(s);
+}
+
+void imx_timerp_create(const hwaddr addr,
+                              qemu_irq irq,
+                              DeviceState *ccm)
+{
+    IMXTimerPState *pp;
+    DeviceState *dev;
+
+    dev = sysbus_create_simple("imx_timerp", addr, irq);
+    pp = container_of(dev, IMXTimerPState, busdev.qdev);
+    pp->ccm = ccm;
+}
+
+static const MemoryRegionOps imx_timerp_ops = {
+  .read = imx_timerp_read,
+  .write = imx_timerp_write,
+  .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static const VMStateDescription vmstate_imx_timerp = {
+    .name = "imx-timerp",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32(cr, IMXTimerPState),
+        VMSTATE_UINT32(lr, IMXTimerPState),
+        VMSTATE_UINT32(cmp, IMXTimerPState),
+        VMSTATE_UINT32(freq, IMXTimerPState),
+        VMSTATE_INT32(int_level, IMXTimerPState),
+        VMSTATE_PTIMER(timer, IMXTimerPState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int imx_timerp_init(SysBusDevice *dev)
+{
+    IMXTimerPState *s = FROM_SYSBUS(IMXTimerPState, dev);
+    QEMUBH *bh;
+
+    DPRINTF("imx_timerp_init\n");
+
+    sysbus_init_irq(dev, &s->irq);
+    memory_region_init_io(&s->iomem, &imx_timerp_ops,
+                          s, "imxp-timer",
+                          0x00001000);
+    sysbus_init_mmio(dev, &s->iomem);
+
+    bh = qemu_bh_new(imx_timerp_tick, s);
+    s->timer = ptimer_init(bh);
+
+    return 0;
+}
+
+
+void imx_timerg_create(const hwaddr addr,
+                              qemu_irq irq,
+                              DeviceState *ccm)
+{
+    IMXTimerGState *pp;
+    DeviceState *dev;
+
+    dev = sysbus_create_simple("imx_timerg", addr, irq);
+    pp = container_of(dev, IMXTimerGState, busdev.qdev);
+    pp->ccm = ccm;
+}
+
+static void imx_timerg_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc  = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+    k->init = imx_timerg_init;
+    dc->vmsd = &vmstate_imx_timerg;
+    dc->reset = imx_timerg_reset;
+    dc->desc = "i.MX general timer";
+}
+
+static void imx_timerp_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc  = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+    k->init = imx_timerp_init;
+    dc->vmsd = &vmstate_imx_timerp;
+    dc->reset = imx_timerp_reset;
+    dc->desc = "i.MX periodic timer";
+}
+
+static const TypeInfo imx_timerp_info = {
+    .name = "imx_timerp",
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(IMXTimerPState),
+    .class_init = imx_timerp_class_init,
+};
+
+static const TypeInfo imx_timerg_info = {
+    .name = "imx_timerg",
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(IMXTimerGState),
+    .class_init = imx_timerg_class_init,
+};
+
+static void imx_timer_register_types(void)
+{
+    type_register_static(&imx_timerp_info);
+    type_register_static(&imx_timerg_info);
+}
+
+type_init(imx_timer_register_types)
diff --git a/hw/timer/lm32_timer.c b/hw/timer/lm32_timer.c
new file mode 100644 (file)
index 0000000..e06fac7
--- /dev/null
@@ -0,0 +1,230 @@
+/*
+ *  QEMU model of the LatticeMico32 timer block.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
+ *
+ * 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/>.
+ *
+ *
+ * Specification available at:
+ *   http://www.latticesemi.com/documents/mico32timer.pdf
+ */
+
+#include "hw/hw.h"
+#include "hw/sysbus.h"
+#include "trace.h"
+#include "qemu/timer.h"
+#include "hw/ptimer.h"
+#include "qemu/error-report.h"
+
+#define DEFAULT_FREQUENCY (50*1000000)
+
+enum {
+    R_SR = 0,
+    R_CR,
+    R_PERIOD,
+    R_SNAPSHOT,
+    R_MAX
+};
+
+enum {
+    SR_TO    = (1 << 0),
+    SR_RUN   = (1 << 1),
+};
+
+enum {
+    CR_ITO   = (1 << 0),
+    CR_CONT  = (1 << 1),
+    CR_START = (1 << 2),
+    CR_STOP  = (1 << 3),
+};
+
+struct LM32TimerState {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+
+    QEMUBH *bh;
+    ptimer_state *ptimer;
+
+    qemu_irq irq;
+    uint32_t freq_hz;
+
+    uint32_t regs[R_MAX];
+};
+typedef struct LM32TimerState LM32TimerState;
+
+static void timer_update_irq(LM32TimerState *s)
+{
+    int state = (s->regs[R_SR] & SR_TO) && (s->regs[R_CR] & CR_ITO);
+
+    trace_lm32_timer_irq_state(state);
+    qemu_set_irq(s->irq, state);
+}
+
+static uint64_t timer_read(void *opaque, hwaddr addr, unsigned size)
+{
+    LM32TimerState *s = opaque;
+    uint32_t r = 0;
+
+    addr >>= 2;
+    switch (addr) {
+    case R_SR:
+    case R_CR:
+    case R_PERIOD:
+        r = s->regs[addr];
+        break;
+    case R_SNAPSHOT:
+        r = (uint32_t)ptimer_get_count(s->ptimer);
+        break;
+    default:
+        error_report("lm32_timer: read access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+
+    trace_lm32_timer_memory_read(addr << 2, r);
+    return r;
+}
+
+static void timer_write(void *opaque, hwaddr addr,
+                        uint64_t value, unsigned size)
+{
+    LM32TimerState *s = opaque;
+
+    trace_lm32_timer_memory_write(addr, value);
+
+    addr >>= 2;
+    switch (addr) {
+    case R_SR:
+        s->regs[R_SR] &= ~SR_TO;
+        break;
+    case R_CR:
+        s->regs[R_CR] = value;
+        if (s->regs[R_CR] & CR_START) {
+            ptimer_run(s->ptimer, 1);
+        }
+        if (s->regs[R_CR] & CR_STOP) {
+            ptimer_stop(s->ptimer);
+        }
+        break;
+    case R_PERIOD:
+        s->regs[R_PERIOD] = value;
+        ptimer_set_count(s->ptimer, value);
+        break;
+    case R_SNAPSHOT:
+        error_report("lm32_timer: write access to read only register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    default:
+        error_report("lm32_timer: write access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+    timer_update_irq(s);
+}
+
+static const MemoryRegionOps timer_ops = {
+    .read = timer_read,
+    .write = timer_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static void timer_hit(void *opaque)
+{
+    LM32TimerState *s = opaque;
+
+    trace_lm32_timer_hit();
+
+    s->regs[R_SR] |= SR_TO;
+
+    if (s->regs[R_CR] & CR_CONT) {
+        ptimer_set_count(s->ptimer, s->regs[R_PERIOD]);
+        ptimer_run(s->ptimer, 1);
+    }
+    timer_update_irq(s);
+}
+
+static void timer_reset(DeviceState *d)
+{
+    LM32TimerState *s = container_of(d, LM32TimerState, busdev.qdev);
+    int i;
+
+    for (i = 0; i < R_MAX; i++) {
+        s->regs[i] = 0;
+    }
+    ptimer_stop(s->ptimer);
+}
+
+static int lm32_timer_init(SysBusDevice *dev)
+{
+    LM32TimerState *s = FROM_SYSBUS(typeof(*s), dev);
+
+    sysbus_init_irq(dev, &s->irq);
+
+    s->bh = qemu_bh_new(timer_hit, s);
+    s->ptimer = ptimer_init(s->bh);
+    ptimer_set_freq(s->ptimer, s->freq_hz);
+
+    memory_region_init_io(&s->iomem, &timer_ops, s, "timer", R_MAX * 4);
+    sysbus_init_mmio(dev, &s->iomem);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_lm32_timer = {
+    .name = "lm32-timer",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_PTIMER(ptimer, LM32TimerState),
+        VMSTATE_UINT32(freq_hz, LM32TimerState),
+        VMSTATE_UINT32_ARRAY(regs, LM32TimerState, R_MAX),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static Property lm32_timer_properties[] = {
+    DEFINE_PROP_UINT32("frequency", LM32TimerState, freq_hz, DEFAULT_FREQUENCY),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void lm32_timer_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = lm32_timer_init;
+    dc->reset = timer_reset;
+    dc->vmsd = &vmstate_lm32_timer;
+    dc->props = lm32_timer_properties;
+}
+
+static const 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_types(void)
+{
+    type_register_static(&lm32_timer_info);
+}
+
+type_init(lm32_timer_register_types)
diff --git a/hw/timer/m48t59.c b/hw/timer/m48t59.c
new file mode 100644 (file)
index 0000000..5019e06
--- /dev/null
@@ -0,0 +1,778 @@
+/*
+ * QEMU M48T59 and M48T08 NVRAM emulation for PPC PREP and Sparc platforms
+ *
+ * Copyright (c) 2003-2005, 2007 Jocelyn Mayer
+ *
+ * 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 "hw/hw.h"
+#include "hw/timer/m48t59.h"
+#include "qemu/timer.h"
+#include "sysemu/sysemu.h"
+#include "hw/sysbus.h"
+#include "hw/isa/isa.h"
+#include "exec/address-spaces.h"
+
+//#define DEBUG_NVRAM
+
+#if defined(DEBUG_NVRAM)
+#define NVRAM_PRINTF(fmt, ...) do { printf(fmt , ## __VA_ARGS__); } while (0)
+#else
+#define NVRAM_PRINTF(fmt, ...) do { } while (0)
+#endif
+
+/*
+ * The M48T02, M48T08 and M48T59 chips are very similar. The newer '59 has
+ * alarm and a watchdog timer and related control registers. In the
+ * PPC platform there is also a nvram lock function.
+ */
+
+/*
+ * Chipset docs:
+ * http://www.st.com/stonline/products/literature/ds/2410/m48t02.pdf
+ * http://www.st.com/stonline/products/literature/ds/2411/m48t08.pdf
+ * http://www.st.com/stonline/products/literature/od/7001/m48t59y.pdf
+ */
+
+struct M48t59State {
+    /* Hardware parameters */
+    qemu_irq IRQ;
+    MemoryRegion iomem;
+    uint32_t io_base;
+    uint32_t size;
+    /* RTC management */
+    time_t   time_offset;
+    time_t   stop_time;
+    /* Alarm & watchdog */
+    struct tm alarm;
+    struct QEMUTimer *alrm_timer;
+    struct QEMUTimer *wd_timer;
+    /* NVRAM storage */
+    uint8_t *buffer;
+    /* Model parameters */
+    uint32_t model; /* 2 = m48t02, 8 = m48t08, 59 = m48t59 */
+    /* NVRAM storage */
+    uint16_t addr;
+    uint8_t  lock;
+};
+
+typedef struct M48t59ISAState {
+    ISADevice busdev;
+    M48t59State state;
+    MemoryRegion io;
+} M48t59ISAState;
+
+typedef struct M48t59SysBusState {
+    SysBusDevice busdev;
+    M48t59State state;
+    MemoryRegion io;
+} M48t59SysBusState;
+
+/* Fake timer functions */
+
+/* Alarm management */
+static void alarm_cb (void *opaque)
+{
+    struct tm tm;
+    uint64_t next_time;
+    M48t59State *NVRAM = opaque;
+
+    qemu_set_irq(NVRAM->IRQ, 1);
+    if ((NVRAM->buffer[0x1FF5] & 0x80) == 0 &&
+       (NVRAM->buffer[0x1FF4] & 0x80) == 0 &&
+       (NVRAM->buffer[0x1FF3] & 0x80) == 0 &&
+       (NVRAM->buffer[0x1FF2] & 0x80) == 0) {
+        /* Repeat once a month */
+        qemu_get_timedate(&tm, NVRAM->time_offset);
+        tm.tm_mon++;
+        if (tm.tm_mon == 13) {
+            tm.tm_mon = 1;
+            tm.tm_year++;
+        }
+        next_time = qemu_timedate_diff(&tm) - NVRAM->time_offset;
+    } else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 &&
+              (NVRAM->buffer[0x1FF4] & 0x80) == 0 &&
+              (NVRAM->buffer[0x1FF3] & 0x80) == 0 &&
+              (NVRAM->buffer[0x1FF2] & 0x80) == 0) {
+        /* Repeat once a day */
+        next_time = 24 * 60 * 60;
+    } else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 &&
+              (NVRAM->buffer[0x1FF4] & 0x80) != 0 &&
+              (NVRAM->buffer[0x1FF3] & 0x80) == 0 &&
+              (NVRAM->buffer[0x1FF2] & 0x80) == 0) {
+        /* Repeat once an hour */
+        next_time = 60 * 60;
+    } else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 &&
+              (NVRAM->buffer[0x1FF4] & 0x80) != 0 &&
+              (NVRAM->buffer[0x1FF3] & 0x80) != 0 &&
+              (NVRAM->buffer[0x1FF2] & 0x80) == 0) {
+        /* Repeat once a minute */
+        next_time = 60;
+    } else {
+        /* Repeat once a second */
+        next_time = 1;
+    }
+    qemu_mod_timer(NVRAM->alrm_timer, qemu_get_clock_ns(rtc_clock) +
+                    next_time * 1000);
+    qemu_set_irq(NVRAM->IRQ, 0);
+}
+
+static void set_alarm(M48t59State *NVRAM)
+{
+    int diff;
+    if (NVRAM->alrm_timer != NULL) {
+        qemu_del_timer(NVRAM->alrm_timer);
+        diff = qemu_timedate_diff(&NVRAM->alarm) - NVRAM->time_offset;
+        if (diff > 0)
+            qemu_mod_timer(NVRAM->alrm_timer, diff * 1000);
+    }
+}
+
+/* RTC management helpers */
+static inline void get_time(M48t59State *NVRAM, struct tm *tm)
+{
+    qemu_get_timedate(tm, NVRAM->time_offset);
+}
+
+static void set_time(M48t59State *NVRAM, struct tm *tm)
+{
+    NVRAM->time_offset = qemu_timedate_diff(tm);
+    set_alarm(NVRAM);
+}
+
+/* Watchdog management */
+static void watchdog_cb (void *opaque)
+{
+    M48t59State *NVRAM = opaque;
+
+    NVRAM->buffer[0x1FF0] |= 0x80;
+    if (NVRAM->buffer[0x1FF7] & 0x80) {
+       NVRAM->buffer[0x1FF7] = 0x00;
+       NVRAM->buffer[0x1FFC] &= ~0x40;
+        /* May it be a hw CPU Reset instead ? */
+        qemu_system_reset_request();
+    } else {
+       qemu_set_irq(NVRAM->IRQ, 1);
+       qemu_set_irq(NVRAM->IRQ, 0);
+    }
+}
+
+static void set_up_watchdog(M48t59State *NVRAM, uint8_t value)
+{
+    uint64_t interval; /* in 1/16 seconds */
+
+    NVRAM->buffer[0x1FF0] &= ~0x80;
+    if (NVRAM->wd_timer != NULL) {
+        qemu_del_timer(NVRAM->wd_timer);
+        if (value != 0) {
+            interval = (1 << (2 * (value & 0x03))) * ((value >> 2) & 0x1F);
+            qemu_mod_timer(NVRAM->wd_timer, ((uint64_t)time(NULL) * 1000) +
+                           ((interval * 1000) >> 4));
+        }
+    }
+}
+
+/* Direct access to NVRAM */
+void m48t59_write (void *opaque, uint32_t addr, uint32_t val)
+{
+    M48t59State *NVRAM = opaque;
+    struct tm tm;
+    int tmp;
+
+    if (addr > 0x1FF8 && addr < 0x2000)
+       NVRAM_PRINTF("%s: 0x%08x => 0x%08x\n", __func__, addr, val);
+
+    /* check for NVRAM access */
+    if ((NVRAM->model == 2 && addr < 0x7f8) ||
+        (NVRAM->model == 8 && addr < 0x1ff8) ||
+        (NVRAM->model == 59 && addr < 0x1ff0)) {
+        goto do_write;
+    }
+
+    /* TOD access */
+    switch (addr) {
+    case 0x1FF0:
+        /* flags register : read-only */
+        break;
+    case 0x1FF1:
+        /* unused */
+        break;
+    case 0x1FF2:
+        /* alarm seconds */
+        tmp = from_bcd(val & 0x7F);
+        if (tmp >= 0 && tmp <= 59) {
+            NVRAM->alarm.tm_sec = tmp;
+            NVRAM->buffer[0x1FF2] = val;
+            set_alarm(NVRAM);
+        }
+        break;
+    case 0x1FF3:
+        /* alarm minutes */
+        tmp = from_bcd(val & 0x7F);
+        if (tmp >= 0 && tmp <= 59) {
+            NVRAM->alarm.tm_min = tmp;
+            NVRAM->buffer[0x1FF3] = val;
+            set_alarm(NVRAM);
+        }
+        break;
+    case 0x1FF4:
+        /* alarm hours */
+        tmp = from_bcd(val & 0x3F);
+        if (tmp >= 0 && tmp <= 23) {
+            NVRAM->alarm.tm_hour = tmp;
+            NVRAM->buffer[0x1FF4] = val;
+            set_alarm(NVRAM);
+        }
+        break;
+    case 0x1FF5:
+        /* alarm date */
+        tmp = from_bcd(val & 0x3F);
+        if (tmp != 0) {
+            NVRAM->alarm.tm_mday = tmp;
+            NVRAM->buffer[0x1FF5] = val;
+            set_alarm(NVRAM);
+        }
+        break;
+    case 0x1FF6:
+        /* interrupts */
+        NVRAM->buffer[0x1FF6] = val;
+        break;
+    case 0x1FF7:
+        /* watchdog */
+        NVRAM->buffer[0x1FF7] = val;
+        set_up_watchdog(NVRAM, val);
+        break;
+    case 0x1FF8:
+    case 0x07F8:
+        /* control */
+       NVRAM->buffer[addr] = (val & ~0xA0) | 0x90;
+        break;
+    case 0x1FF9:
+    case 0x07F9:
+        /* seconds (BCD) */
+       tmp = from_bcd(val & 0x7F);
+       if (tmp >= 0 && tmp <= 59) {
+           get_time(NVRAM, &tm);
+           tm.tm_sec = tmp;
+           set_time(NVRAM, &tm);
+       }
+        if ((val & 0x80) ^ (NVRAM->buffer[addr] & 0x80)) {
+           if (val & 0x80) {
+               NVRAM->stop_time = time(NULL);
+           } else {
+               NVRAM->time_offset += NVRAM->stop_time - time(NULL);
+               NVRAM->stop_time = 0;
+           }
+       }
+        NVRAM->buffer[addr] = val & 0x80;
+        break;
+    case 0x1FFA:
+    case 0x07FA:
+        /* minutes (BCD) */
+       tmp = from_bcd(val & 0x7F);
+       if (tmp >= 0 && tmp <= 59) {
+           get_time(NVRAM, &tm);
+           tm.tm_min = tmp;
+           set_time(NVRAM, &tm);
+       }
+        break;
+    case 0x1FFB:
+    case 0x07FB:
+        /* hours (BCD) */
+       tmp = from_bcd(val & 0x3F);
+       if (tmp >= 0 && tmp <= 23) {
+           get_time(NVRAM, &tm);
+           tm.tm_hour = tmp;
+           set_time(NVRAM, &tm);
+       }
+        break;
+    case 0x1FFC:
+    case 0x07FC:
+        /* day of the week / century */
+       tmp = from_bcd(val & 0x07);
+       get_time(NVRAM, &tm);
+       tm.tm_wday = tmp;
+       set_time(NVRAM, &tm);
+        NVRAM->buffer[addr] = val & 0x40;
+        break;
+    case 0x1FFD:
+    case 0x07FD:
+        /* date (BCD) */
+       tmp = from_bcd(val & 0x3F);
+       if (tmp != 0) {
+           get_time(NVRAM, &tm);
+           tm.tm_mday = tmp;
+           set_time(NVRAM, &tm);
+       }
+        break;
+    case 0x1FFE:
+    case 0x07FE:
+        /* month */
+       tmp = from_bcd(val & 0x1F);
+       if (tmp >= 1 && tmp <= 12) {
+           get_time(NVRAM, &tm);
+           tm.tm_mon = tmp - 1;
+           set_time(NVRAM, &tm);
+       }
+        break;
+    case 0x1FFF:
+    case 0x07FF:
+        /* year */
+       tmp = from_bcd(val);
+       if (tmp >= 0 && tmp <= 99) {
+           get_time(NVRAM, &tm);
+            if (NVRAM->model == 8) {
+                tm.tm_year = from_bcd(val) + 68; // Base year is 1968
+            } else {
+                tm.tm_year = from_bcd(val);
+            }
+           set_time(NVRAM, &tm);
+       }
+        break;
+    default:
+        /* Check lock registers state */
+        if (addr >= 0x20 && addr <= 0x2F && (NVRAM->lock & 1))
+            break;
+        if (addr >= 0x30 && addr <= 0x3F && (NVRAM->lock & 2))
+            break;
+    do_write:
+        if (addr < NVRAM->size) {
+            NVRAM->buffer[addr] = val & 0xFF;
+       }
+        break;
+    }
+}
+
+uint32_t m48t59_read (void *opaque, uint32_t addr)
+{
+    M48t59State *NVRAM = opaque;
+    struct tm tm;
+    uint32_t retval = 0xFF;
+
+    /* check for NVRAM access */
+    if ((NVRAM->model == 2 && addr < 0x078f) ||
+        (NVRAM->model == 8 && addr < 0x1ff8) ||
+        (NVRAM->model == 59 && addr < 0x1ff0)) {
+        goto do_read;
+    }
+
+    /* TOD access */
+    switch (addr) {
+    case 0x1FF0:
+        /* flags register */
+       goto do_read;
+    case 0x1FF1:
+        /* unused */
+       retval = 0;
+        break;
+    case 0x1FF2:
+        /* alarm seconds */
+       goto do_read;
+    case 0x1FF3:
+        /* alarm minutes */
+       goto do_read;
+    case 0x1FF4:
+        /* alarm hours */
+       goto do_read;
+    case 0x1FF5:
+        /* alarm date */
+       goto do_read;
+    case 0x1FF6:
+        /* interrupts */
+       goto do_read;
+    case 0x1FF7:
+       /* A read resets the watchdog */
+       set_up_watchdog(NVRAM, NVRAM->buffer[0x1FF7]);
+       goto do_read;
+    case 0x1FF8:
+    case 0x07F8:
+        /* control */
+       goto do_read;
+    case 0x1FF9:
+    case 0x07F9:
+        /* seconds (BCD) */
+        get_time(NVRAM, &tm);
+        retval = (NVRAM->buffer[addr] & 0x80) | to_bcd(tm.tm_sec);
+        break;
+    case 0x1FFA:
+    case 0x07FA:
+        /* minutes (BCD) */
+        get_time(NVRAM, &tm);
+        retval = to_bcd(tm.tm_min);
+        break;
+    case 0x1FFB:
+    case 0x07FB:
+        /* hours (BCD) */
+        get_time(NVRAM, &tm);
+        retval = to_bcd(tm.tm_hour);
+        break;
+    case 0x1FFC:
+    case 0x07FC:
+        /* day of the week / century */
+        get_time(NVRAM, &tm);
+        retval = NVRAM->buffer[addr] | tm.tm_wday;
+        break;
+    case 0x1FFD:
+    case 0x07FD:
+        /* date */
+        get_time(NVRAM, &tm);
+        retval = to_bcd(tm.tm_mday);
+        break;
+    case 0x1FFE:
+    case 0x07FE:
+        /* month */
+        get_time(NVRAM, &tm);
+        retval = to_bcd(tm.tm_mon + 1);
+        break;
+    case 0x1FFF:
+    case 0x07FF:
+        /* year */
+        get_time(NVRAM, &tm);
+        if (NVRAM->model == 8) {
+            retval = to_bcd(tm.tm_year - 68); // Base year is 1968
+        } else {
+            retval = to_bcd(tm.tm_year);
+        }
+        break;
+    default:
+        /* Check lock registers state */
+        if (addr >= 0x20 && addr <= 0x2F && (NVRAM->lock & 1))
+            break;
+        if (addr >= 0x30 && addr <= 0x3F && (NVRAM->lock & 2))
+            break;
+    do_read:
+        if (addr < NVRAM->size) {
+            retval = NVRAM->buffer[addr];
+       }
+        break;
+    }
+    if (addr > 0x1FF9 && addr < 0x2000)
+       NVRAM_PRINTF("%s: 0x%08x <= 0x%08x\n", __func__, addr, retval);
+
+    return retval;
+}
+
+void m48t59_toggle_lock (void *opaque, int lock)
+{
+    M48t59State *NVRAM = opaque;
+
+    NVRAM->lock ^= 1 << lock;
+}
+
+/* IO access to NVRAM */
+static void NVRAM_writeb(void *opaque, hwaddr addr, uint64_t val,
+                         unsigned size)
+{
+    M48t59State *NVRAM = opaque;
+
+    NVRAM_PRINTF("%s: 0x%08x => 0x%08x\n", __func__, addr, val);
+    switch (addr) {
+    case 0:
+        NVRAM->addr &= ~0x00FF;
+        NVRAM->addr |= val;
+        break;
+    case 1:
+        NVRAM->addr &= ~0xFF00;
+        NVRAM->addr |= val << 8;
+        break;
+    case 3:
+        m48t59_write(NVRAM, NVRAM->addr, val);
+        NVRAM->addr = 0x0000;
+        break;
+    default:
+        break;
+    }
+}
+
+static uint64_t NVRAM_readb(void *opaque, hwaddr addr, unsigned size)
+{
+    M48t59State *NVRAM = opaque;
+    uint32_t retval;
+
+    switch (addr) {
+    case 3:
+        retval = m48t59_read(NVRAM, NVRAM->addr);
+        break;
+    default:
+        retval = -1;
+        break;
+    }
+    NVRAM_PRINTF("%s: 0x%08x <= 0x%08x\n", __func__, addr, retval);
+
+    return retval;
+}
+
+static void nvram_writeb (void *opaque, hwaddr addr, uint32_t value)
+{
+    M48t59State *NVRAM = opaque;
+
+    m48t59_write(NVRAM, addr, value & 0xff);
+}
+
+static void nvram_writew (void *opaque, hwaddr addr, uint32_t value)
+{
+    M48t59State *NVRAM = opaque;
+
+    m48t59_write(NVRAM, addr, (value >> 8) & 0xff);
+    m48t59_write(NVRAM, addr + 1, value & 0xff);
+}
+
+static void nvram_writel (void *opaque, hwaddr addr, uint32_t value)
+{
+    M48t59State *NVRAM = opaque;
+
+    m48t59_write(NVRAM, addr, (value >> 24) & 0xff);
+    m48t59_write(NVRAM, addr + 1, (value >> 16) & 0xff);
+    m48t59_write(NVRAM, addr + 2, (value >> 8) & 0xff);
+    m48t59_write(NVRAM, addr + 3, value & 0xff);
+}
+
+static uint32_t nvram_readb (void *opaque, hwaddr addr)
+{
+    M48t59State *NVRAM = opaque;
+    uint32_t retval;
+
+    retval = m48t59_read(NVRAM, addr);
+    return retval;
+}
+
+static uint32_t nvram_readw (void *opaque, hwaddr addr)
+{
+    M48t59State *NVRAM = opaque;
+    uint32_t retval;
+
+    retval = m48t59_read(NVRAM, addr) << 8;
+    retval |= m48t59_read(NVRAM, addr + 1);
+    return retval;
+}
+
+static uint32_t nvram_readl (void *opaque, hwaddr addr)
+{
+    M48t59State *NVRAM = opaque;
+    uint32_t retval;
+
+    retval = m48t59_read(NVRAM, addr) << 24;
+    retval |= m48t59_read(NVRAM, addr + 1) << 16;
+    retval |= m48t59_read(NVRAM, addr + 2) << 8;
+    retval |= m48t59_read(NVRAM, addr + 3);
+    return retval;
+}
+
+static const MemoryRegionOps nvram_ops = {
+    .old_mmio = {
+        .read = { nvram_readb, nvram_readw, nvram_readl, },
+        .write = { nvram_writeb, nvram_writew, nvram_writel, },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static const VMStateDescription vmstate_m48t59 = {
+    .name = "m48t59",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT8(lock, M48t59State),
+        VMSTATE_UINT16(addr, M48t59State),
+        VMSTATE_VBUFFER_UINT32(buffer, M48t59State, 0, NULL, 0, size),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void m48t59_reset_common(M48t59State *NVRAM)
+{
+    NVRAM->addr = 0;
+    NVRAM->lock = 0;
+    if (NVRAM->alrm_timer != NULL)
+        qemu_del_timer(NVRAM->alrm_timer);
+
+    if (NVRAM->wd_timer != NULL)
+        qemu_del_timer(NVRAM->wd_timer);
+}
+
+static void m48t59_reset_isa(DeviceState *d)
+{
+    M48t59ISAState *isa = container_of(d, M48t59ISAState, busdev.qdev);
+    M48t59State *NVRAM = &isa->state;
+
+    m48t59_reset_common(NVRAM);
+}
+
+static void m48t59_reset_sysbus(DeviceState *d)
+{
+    M48t59SysBusState *sys = container_of(d, M48t59SysBusState, busdev.qdev);
+    M48t59State *NVRAM = &sys->state;
+
+    m48t59_reset_common(NVRAM);
+}
+
+static const MemoryRegionOps m48t59_io_ops = {
+    .read = NVRAM_readb,
+    .write = NVRAM_writeb,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+/* Initialisation routine */
+M48t59State *m48t59_init(qemu_irq IRQ, hwaddr mem_base,
+                         uint32_t io_base, uint16_t size, int model)
+{
+    DeviceState *dev;
+    SysBusDevice *s;
+    M48t59SysBusState *d;
+    M48t59State *state;
+
+    dev = qdev_create(NULL, "m48t59");
+    qdev_prop_set_uint32(dev, "model", model);
+    qdev_prop_set_uint32(dev, "size", size);
+    qdev_prop_set_uint32(dev, "io_base", io_base);
+    qdev_init_nofail(dev);
+    s = SYS_BUS_DEVICE(dev);
+    d = FROM_SYSBUS(M48t59SysBusState, s);
+    state = &d->state;
+    sysbus_connect_irq(s, 0, IRQ);
+    memory_region_init_io(&d->io, &m48t59_io_ops, state, "m48t59", 4);
+    if (io_base != 0) {
+        memory_region_add_subregion(get_system_io(), io_base, &d->io);
+    }
+    if (mem_base != 0) {
+        sysbus_mmio_map(s, 0, mem_base);
+    }
+
+    return state;
+}
+
+M48t59State *m48t59_init_isa(ISABus *bus, uint32_t io_base, uint16_t size,
+                             int model)
+{
+    M48t59ISAState *d;
+    ISADevice *dev;
+    M48t59State *s;
+
+    dev = isa_create(bus, "m48t59_isa");
+    qdev_prop_set_uint32(&dev->qdev, "model", model);
+    qdev_prop_set_uint32(&dev->qdev, "size", size);
+    qdev_prop_set_uint32(&dev->qdev, "io_base", io_base);
+    qdev_init_nofail(&dev->qdev);
+    d = DO_UPCAST(M48t59ISAState, busdev, dev);
+    s = &d->state;
+
+    memory_region_init_io(&d->io, &m48t59_io_ops, s, "m48t59", 4);
+    if (io_base != 0) {
+        isa_register_ioport(dev, &d->io, io_base);
+    }
+
+    return s;
+}
+
+static void m48t59_init_common(M48t59State *s)
+{
+    s->buffer = g_malloc0(s->size);
+    if (s->model == 59) {
+        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);
+
+    vmstate_register(NULL, -1, &vmstate_m48t59, s);
+}
+
+static int m48t59_init_isa1(ISADevice *dev)
+{
+    M48t59ISAState *d = DO_UPCAST(M48t59ISAState, busdev, dev);
+    M48t59State *s = &d->state;
+
+    isa_init_irq(dev, &s->IRQ, 8);
+    m48t59_init_common(s);
+
+    return 0;
+}
+
+static int m48t59_init1(SysBusDevice *dev)
+{
+    M48t59SysBusState *d = FROM_SYSBUS(M48t59SysBusState, dev);
+    M48t59State *s = &d->state;
+
+    sysbus_init_irq(dev, &s->IRQ);
+
+    memory_region_init_io(&s->iomem, &nvram_ops, s, "m48t59.nvram", s->size);
+    sysbus_init_mmio(dev, &s->iomem);
+    m48t59_init_common(s);
+
+    return 0;
+}
+
+static Property m48t59_isa_properties[] = {
+    DEFINE_PROP_UINT32("size",    M48t59ISAState, state.size,    -1),
+    DEFINE_PROP_UINT32("model",   M48t59ISAState, state.model,   -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 const TypeInfo m48t59_isa_info = {
+    .name          = "m48t59_isa",
+    .parent        = TYPE_ISA_DEVICE,
+    .instance_size = sizeof(M48t59ISAState),
+    .class_init    = m48t59_init_class_isa1,
+};
+
+static Property m48t59_properties[] = {
+    DEFINE_PROP_UINT32("size",    M48t59SysBusState, state.size,    -1),
+    DEFINE_PROP_UINT32("model",   M48t59SysBusState, state.model,   -1),
+    DEFINE_PROP_HEX32( "io_base", M48t59SysBusState, state.io_base,  0),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void m48t59_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = m48t59_init1;
+    dc->reset = m48t59_reset_sysbus;
+    dc->props = m48t59_properties;
+}
+
+static const TypeInfo m48t59_info = {
+    .name          = "m48t59",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(M48t59SysBusState),
+    .class_init    = m48t59_class_init,
+};
+
+static void m48t59_register_types(void)
+{
+    type_register_static(&m48t59_info);
+    type_register_static(&m48t59_isa_info);
+}
+
+type_init(m48t59_register_types)
diff --git a/hw/timer/mc146818rtc.c b/hw/timer/mc146818rtc.c
new file mode 100644 (file)
index 0000000..69e6844
--- /dev/null
@@ -0,0 +1,913 @@
+/*
+ * QEMU MC146818 RTC 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.
+ */
+#include "hw/hw.h"
+#include "qemu/timer.h"
+#include "sysemu/sysemu.h"
+#include "hw/timer/mc146818rtc.h"
+#include "qapi/visitor.h"
+
+#ifdef TARGET_I386
+#include "hw/i386/apic.h"
+#endif
+
+//#define DEBUG_CMOS
+//#define DEBUG_COALESCED
+
+#ifdef DEBUG_CMOS
+# define CMOS_DPRINTF(format, ...)      printf(format, ## __VA_ARGS__)
+#else
+# define CMOS_DPRINTF(format, ...)      do { } while (0)
+#endif
+
+#ifdef DEBUG_COALESCED
+# define DPRINTF_C(format, ...)      printf(format, ## __VA_ARGS__)
+#else
+# define DPRINTF_C(format, ...)      do { } while (0)
+#endif
+
+#define NSEC_PER_SEC    1000000000LL
+#define SEC_PER_MIN     60
+#define MIN_PER_HOUR    60
+#define SEC_PER_HOUR    3600
+#define HOUR_PER_DAY    24
+#define SEC_PER_DAY     86400
+
+#define RTC_REINJECT_ON_ACK_COUNT 20
+#define RTC_CLOCK_RATE            32768
+#define UIP_HOLD_LENGTH           (8 * NSEC_PER_SEC / 32768)
+
+typedef struct RTCState {
+    ISADevice dev;
+    MemoryRegion io;
+    uint8_t cmos_data[128];
+    uint8_t cmos_index;
+    int32_t base_year;
+    uint64_t base_rtc;
+    uint64_t last_update;
+    int64_t offset;
+    qemu_irq irq;
+    qemu_irq sqw_irq;
+    int it_shift;
+    /* periodic timer */
+    QEMUTimer *periodic_timer;
+    int64_t next_periodic_time;
+    /* update-ended timer */
+    QEMUTimer *update_timer;
+    uint64_t next_alarm_time;
+    uint16_t irq_reinject_on_ack_count;
+    uint32_t irq_coalesced;
+    uint32_t period;
+    QEMUTimer *coalesced_timer;
+    Notifier clock_reset_notifier;
+    LostTickPolicy lost_tick_policy;
+    Notifier suspend_notifier;
+} RTCState;
+
+static void rtc_set_time(RTCState *s);
+static void rtc_update_time(RTCState *s);
+static void rtc_set_cmos(RTCState *s, const struct tm *tm);
+static inline int rtc_from_bcd(RTCState *s, int a);
+static uint64_t get_next_alarm(RTCState *s);
+
+static inline bool rtc_running(RTCState *s)
+{
+    return (!(s->cmos_data[RTC_REG_B] & REG_B_SET) &&
+            (s->cmos_data[RTC_REG_A] & 0x70) <= 0x20);
+}
+
+static uint64_t get_guest_rtc_ns(RTCState *s)
+{
+    uint64_t guest_rtc;
+    uint64_t guest_clock = qemu_get_clock_ns(rtc_clock);
+
+    guest_rtc = s->base_rtc * NSEC_PER_SEC
+                 + guest_clock - s->last_update + s->offset;
+    return guest_rtc;
+}
+
+#ifdef TARGET_I386
+static void rtc_coalesced_timer_update(RTCState *s)
+{
+    if (s->irq_coalesced == 0) {
+        qemu_del_timer(s->coalesced_timer);
+    } else {
+        /* divide each RTC interval to 2 - 8 smaller intervals */
+        int c = MIN(s->irq_coalesced, 7) + 1; 
+        int64_t next_clock = qemu_get_clock_ns(rtc_clock) +
+            muldiv64(s->period / c, get_ticks_per_sec(), RTC_CLOCK_RATE);
+        qemu_mod_timer(s->coalesced_timer, next_clock);
+    }
+}
+
+static void rtc_coalesced_timer(void *opaque)
+{
+    RTCState *s = opaque;
+
+    if (s->irq_coalesced != 0) {
+        apic_reset_irq_delivered();
+        s->cmos_data[RTC_REG_C] |= 0xc0;
+        DPRINTF_C("cmos: injecting from timer\n");
+        qemu_irq_raise(s->irq);
+        if (apic_get_irq_delivered()) {
+            s->irq_coalesced--;
+            DPRINTF_C("cmos: coalesced irqs decreased to %d\n",
+                      s->irq_coalesced);
+        }
+    }
+
+    rtc_coalesced_timer_update(s);
+}
+#endif
+
+/* handle periodic timer */
+static void periodic_timer_update(RTCState *s, int64_t current_time)
+{
+    int period_code, period;
+    int64_t cur_clock, next_irq_clock;
+
+    period_code = s->cmos_data[RTC_REG_A] & 0x0f;
+    if (period_code != 0
+        && ((s->cmos_data[RTC_REG_B] & REG_B_PIE)
+            || ((s->cmos_data[RTC_REG_B] & REG_B_SQWE) && s->sqw_irq))) {
+        if (period_code <= 2)
+            period_code += 7;
+        /* period in 32 Khz cycles */
+        period = 1 << (period_code - 1);
+#ifdef TARGET_I386
+        if (period != s->period) {
+            s->irq_coalesced = (s->irq_coalesced * s->period) / period;
+            DPRINTF_C("cmos: coalesced irqs scaled to %d\n", s->irq_coalesced);
+        }
+        s->period = period;
+#endif
+        /* compute 32 khz clock */
+        cur_clock = muldiv64(current_time, RTC_CLOCK_RATE, get_ticks_per_sec());
+        next_irq_clock = (cur_clock & ~(period - 1)) + period;
+        s->next_periodic_time =
+            muldiv64(next_irq_clock, get_ticks_per_sec(), RTC_CLOCK_RATE) + 1;
+        qemu_mod_timer(s->periodic_timer, s->next_periodic_time);
+    } else {
+#ifdef TARGET_I386
+        s->irq_coalesced = 0;
+#endif
+        qemu_del_timer(s->periodic_timer);
+    }
+}
+
+static void rtc_periodic_timer(void *opaque)
+{
+    RTCState *s = opaque;
+
+    periodic_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] |= REG_C_IRQF;
+#ifdef TARGET_I386
+        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();
+            qemu_irq_raise(s->irq);
+            if (!apic_get_irq_delivered()) {
+                s->irq_coalesced++;
+                rtc_coalesced_timer_update(s);
+                DPRINTF_C("cmos: coalesced irqs increased to %d\n",
+                          s->irq_coalesced);
+            }
+        } else
+#endif
+        qemu_irq_raise(s->irq);
+    }
+    if (s->cmos_data[RTC_REG_B] & REG_B_SQWE) {
+        /* Not square wave at all but we don't want 2048Hz interrupts!
+           Must be seen as a pulse.  */
+        qemu_irq_raise(s->sqw_irq);
+    }
+}
+
+/* handle update-ended timer */
+static void check_update_timer(RTCState *s)
+{
+    uint64_t next_update_time;
+    uint64_t guest_nsec;
+    int next_alarm_sec;
+
+    /* From the data sheet: "Holding the dividers in reset prevents
+     * interrupts from operating, while setting the SET bit allows"
+     * them to occur.  However, it will prevent an alarm interrupt
+     * from occurring, because the time of day is not updated.
+     */
+    if ((s->cmos_data[RTC_REG_A] & 0x60) == 0x60) {
+        qemu_del_timer(s->update_timer);
+        return;
+    }
+    if ((s->cmos_data[RTC_REG_C] & REG_C_UF) &&
+        (s->cmos_data[RTC_REG_B] & REG_B_SET)) {
+        qemu_del_timer(s->update_timer);
+        return;
+    }
+    if ((s->cmos_data[RTC_REG_C] & REG_C_UF) &&
+        (s->cmos_data[RTC_REG_C] & REG_C_AF)) {
+        qemu_del_timer(s->update_timer);
+        return;
+    }
+
+    guest_nsec = get_guest_rtc_ns(s) % NSEC_PER_SEC;
+    /* if UF is clear, reprogram to next second */
+    next_update_time = qemu_get_clock_ns(rtc_clock)
+        + NSEC_PER_SEC - guest_nsec;
+
+    /* Compute time of next alarm.  One second is already accounted
+     * for in next_update_time.
+     */
+    next_alarm_sec = get_next_alarm(s);
+    s->next_alarm_time = next_update_time + (next_alarm_sec - 1) * NSEC_PER_SEC;
+
+    if (s->cmos_data[RTC_REG_C] & REG_C_UF) {
+        /* UF is set, but AF is clear.  Program the timer to target
+         * the alarm time.  */
+        next_update_time = s->next_alarm_time;
+    }
+    if (next_update_time != qemu_timer_expire_time_ns(s->update_timer)) {
+        qemu_mod_timer(s->update_timer, next_update_time);
+    }
+}
+
+static inline uint8_t convert_hour(RTCState *s, uint8_t hour)
+{
+    if (!(s->cmos_data[RTC_REG_B] & REG_B_24H)) {
+        hour %= 12;
+        if (s->cmos_data[RTC_HOURS] & 0x80) {
+            hour += 12;
+        }
+    }
+    return hour;
+}
+
+static uint64_t get_next_alarm(RTCState *s)
+{
+    int32_t alarm_sec, alarm_min, alarm_hour, cur_hour, cur_min, cur_sec;
+    int32_t hour, min, sec;
+
+    rtc_update_time(s);
+
+    alarm_sec = rtc_from_bcd(s, s->cmos_data[RTC_SECONDS_ALARM]);
+    alarm_min = rtc_from_bcd(s, s->cmos_data[RTC_MINUTES_ALARM]);
+    alarm_hour = rtc_from_bcd(s, s->cmos_data[RTC_HOURS_ALARM]);
+    alarm_hour = alarm_hour == -1 ? -1 : convert_hour(s, alarm_hour);
+
+    cur_sec = rtc_from_bcd(s, s->cmos_data[RTC_SECONDS]);
+    cur_min = rtc_from_bcd(s, s->cmos_data[RTC_MINUTES]);
+    cur_hour = rtc_from_bcd(s, s->cmos_data[RTC_HOURS]);
+    cur_hour = convert_hour(s, cur_hour);
+
+    if (alarm_hour == -1) {
+        alarm_hour = cur_hour;
+        if (alarm_min == -1) {
+            alarm_min = cur_min;
+            if (alarm_sec == -1) {
+                alarm_sec = cur_sec + 1;
+            } else if (cur_sec > alarm_sec) {
+                alarm_min++;
+            }
+        } else if (cur_min == alarm_min) {
+            if (alarm_sec == -1) {
+                alarm_sec = cur_sec + 1;
+            } else {
+                if (cur_sec > alarm_sec) {
+                    alarm_hour++;
+                }
+            }
+            if (alarm_sec == SEC_PER_MIN) {
+                /* wrap to next hour, minutes is not in don't care mode */
+                alarm_sec = 0;
+                alarm_hour++;
+            }
+        } else if (cur_min > alarm_min) {
+            alarm_hour++;
+        }
+    } else if (cur_hour == alarm_hour) {
+        if (alarm_min == -1) {
+            alarm_min = cur_min;
+            if (alarm_sec == -1) {
+                alarm_sec = cur_sec + 1;
+            } else if (cur_sec > alarm_sec) {
+                alarm_min++;
+            }
+
+            if (alarm_sec == SEC_PER_MIN) {
+                alarm_sec = 0;
+                alarm_min++;
+            }
+            /* wrap to next day, hour is not in don't care mode */
+            alarm_min %= MIN_PER_HOUR;
+        } else if (cur_min == alarm_min) {
+            if (alarm_sec == -1) {
+                alarm_sec = cur_sec + 1;
+            }
+            /* wrap to next day, hours+minutes not in don't care mode */
+            alarm_sec %= SEC_PER_MIN;
+        }
+    }
+
+    /* values that are still don't care fire at the next min/sec */
+    if (alarm_min == -1) {
+        alarm_min = 0;
+    }
+    if (alarm_sec == -1) {
+        alarm_sec = 0;
+    }
+
+    /* keep values in range */
+    if (alarm_sec == SEC_PER_MIN) {
+        alarm_sec = 0;
+        alarm_min++;
+    }
+    if (alarm_min == MIN_PER_HOUR) {
+        alarm_min = 0;
+        alarm_hour++;
+    }
+    alarm_hour %= HOUR_PER_DAY;
+
+    hour = alarm_hour - cur_hour;
+    min = hour * MIN_PER_HOUR + alarm_min - cur_min;
+    sec = min * SEC_PER_MIN + alarm_sec - cur_sec;
+    return sec <= 0 ? sec + SEC_PER_DAY : sec;
+}
+
+static void rtc_update_timer(void *opaque)
+{
+    RTCState *s = opaque;
+    int32_t irqs = REG_C_UF;
+    int32_t new_irqs;
+
+    assert((s->cmos_data[RTC_REG_A] & 0x60) != 0x60);
+
+    /* UIP might have been latched, update time and clear it.  */
+    rtc_update_time(s);
+    s->cmos_data[RTC_REG_A] &= ~REG_A_UIP;
+
+    if (qemu_get_clock_ns(rtc_clock) >= s->next_alarm_time) {
+        irqs |= REG_C_AF;
+        if (s->cmos_data[RTC_REG_B] & REG_B_AIE) {
+            qemu_system_wakeup_request(QEMU_WAKEUP_REASON_RTC);
+        }
+    }
+
+    new_irqs = irqs & ~s->cmos_data[RTC_REG_C];
+    s->cmos_data[RTC_REG_C] |= irqs;
+    if ((new_irqs & s->cmos_data[RTC_REG_B]) != 0) {
+        s->cmos_data[RTC_REG_C] |= REG_C_IRQF;
+        qemu_irq_raise(s->irq);
+    }
+    check_update_timer(s);
+}
+
+static void cmos_ioport_write(void *opaque, hwaddr addr,
+                              uint64_t data, unsigned size)
+{
+    RTCState *s = opaque;
+
+    if ((addr & 1) == 0) {
+        s->cmos_index = data & 0x7f;
+    } else {
+        CMOS_DPRINTF("cmos: write index=0x%02x val=0x%02x\n",
+                     s->cmos_index, data);
+        switch(s->cmos_index) {
+        case RTC_SECONDS_ALARM:
+        case RTC_MINUTES_ALARM:
+        case RTC_HOURS_ALARM:
+            s->cmos_data[s->cmos_index] = data;
+            check_update_timer(s);
+            break;
+       case RTC_IBM_PS2_CENTURY_BYTE:
+            s->cmos_index = RTC_CENTURY;
+            /* fall through */
+        case RTC_CENTURY:
+        case RTC_SECONDS:
+        case RTC_MINUTES:
+        case RTC_HOURS:
+        case RTC_DAY_OF_WEEK:
+        case RTC_DAY_OF_MONTH:
+        case RTC_MONTH:
+        case RTC_YEAR:
+            s->cmos_data[s->cmos_index] = data;
+            /* if in set mode, do not update the time */
+            if (rtc_running(s)) {
+                rtc_set_time(s);
+                check_update_timer(s);
+            }
+            break;
+        case RTC_REG_A:
+            if ((data & 0x60) == 0x60) {
+                if (rtc_running(s)) {
+                    rtc_update_time(s);
+                }
+                /* What happens to UIP when divider reset is enabled is
+                 * unclear from the datasheet.  Shouldn't matter much
+                 * though.
+                 */
+                s->cmos_data[RTC_REG_A] &= ~REG_A_UIP;
+            } else if (((s->cmos_data[RTC_REG_A] & 0x60) == 0x60) &&
+                    (data & 0x70)  <= 0x20) {
+                /* when the divider reset is removed, the first update cycle
+                 * begins one-half second later*/
+                if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) {
+                    s->offset = 500000000;
+                    rtc_set_time(s);
+                }
+                s->cmos_data[RTC_REG_A] &= ~REG_A_UIP;
+            }
+            /* UIP bit is read only */
+            s->cmos_data[RTC_REG_A] = (data & ~REG_A_UIP) |
+                (s->cmos_data[RTC_REG_A] & REG_A_UIP);
+            periodic_timer_update(s, qemu_get_clock_ns(rtc_clock));
+            check_update_timer(s);
+            break;
+        case RTC_REG_B:
+            if (data & REG_B_SET) {
+                /* update cmos to when the rtc was stopping */
+                if (rtc_running(s)) {
+                    rtc_update_time(s);
+                }
+                /* set mode: reset UIP mode */
+                s->cmos_data[RTC_REG_A] &= ~REG_A_UIP;
+                data &= ~REG_B_UIE;
+            } else {
+                /* if disabling set mode, update the time */
+                if ((s->cmos_data[RTC_REG_B] & REG_B_SET) &&
+                    (s->cmos_data[RTC_REG_A] & 0x70) <= 0x20) {
+                    s->offset = get_guest_rtc_ns(s) % NSEC_PER_SEC;
+                    rtc_set_time(s);
+                }
+            }
+            /* if an interrupt flag is already set when the interrupt
+             * becomes enabled, raise an interrupt immediately.  */
+            if (data & s->cmos_data[RTC_REG_C] & REG_C_MASK) {
+                s->cmos_data[RTC_REG_C] |= REG_C_IRQF;
+                qemu_irq_raise(s->irq);
+            } else {
+                s->cmos_data[RTC_REG_C] &= ~REG_C_IRQF;
+                qemu_irq_lower(s->irq);
+            }
+            s->cmos_data[RTC_REG_B] = data;
+            periodic_timer_update(s, qemu_get_clock_ns(rtc_clock));
+            check_update_timer(s);
+            break;
+        case RTC_REG_C:
+        case RTC_REG_D:
+            /* cannot write to them */
+            break;
+        default:
+            s->cmos_data[s->cmos_index] = data;
+            break;
+        }
+    }
+}
+
+static inline int rtc_to_bcd(RTCState *s, int a)
+{
+    if (s->cmos_data[RTC_REG_B] & REG_B_DM) {
+        return a;
+    } else {
+        return ((a / 10) << 4) | (a % 10);
+    }
+}
+
+static inline int rtc_from_bcd(RTCState *s, int a)
+{
+    if ((a & 0xc0) == 0xc0) {
+        return -1;
+    }
+    if (s->cmos_data[RTC_REG_B] & REG_B_DM) {
+        return a;
+    } else {
+        return ((a >> 4) * 10) + (a & 0x0f);
+    }
+}
+
+static void rtc_get_time(RTCState *s, struct tm *tm)
+{
+    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)) {
+        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]);
+    tm->tm_mon = rtc_from_bcd(s, s->cmos_data[RTC_MONTH]) - 1;
+    tm->tm_year =
+        rtc_from_bcd(s, s->cmos_data[RTC_YEAR]) + s->base_year +
+        rtc_from_bcd(s, s->cmos_data[RTC_CENTURY]) * 100 - 1900;
+}
+
+static void rtc_set_time(RTCState *s)
+{
+    struct tm tm;
+
+    rtc_get_time(s, &tm);
+    s->base_rtc = mktimegm(&tm);
+    s->last_update = qemu_get_clock_ns(rtc_clock);
+
+    rtc_change_mon_event(&tm);
+}
+
+static void rtc_set_cmos(RTCState *s, const struct tm *tm)
+{
+    int year;
+
+    s->cmos_data[RTC_SECONDS] = rtc_to_bcd(s, tm->tm_sec);
+    s->cmos_data[RTC_MINUTES] = rtc_to_bcd(s, tm->tm_min);
+    if (s->cmos_data[RTC_REG_B] & REG_B_24H) {
+        /* 24 hour format */
+        s->cmos_data[RTC_HOURS] = rtc_to_bcd(s, tm->tm_hour);
+    } else {
+        /* 12 hour format */
+        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;
+    }
+    s->cmos_data[RTC_DAY_OF_WEEK] = rtc_to_bcd(s, tm->tm_wday + 1);
+    s->cmos_data[RTC_DAY_OF_MONTH] = rtc_to_bcd(s, tm->tm_mday);
+    s->cmos_data[RTC_MONTH] = rtc_to_bcd(s, tm->tm_mon + 1);
+    year = tm->tm_year + 1900 - s->base_year;
+    s->cmos_data[RTC_YEAR] = rtc_to_bcd(s, year % 100);
+    s->cmos_data[RTC_CENTURY] = rtc_to_bcd(s, year / 100);
+}
+
+static void rtc_update_time(RTCState *s)
+{
+    struct tm ret;
+    time_t guest_sec;
+    int64_t guest_nsec;
+
+    guest_nsec = get_guest_rtc_ns(s);
+    guest_sec = guest_nsec / NSEC_PER_SEC;
+    gmtime_r(&guest_sec, &ret);
+
+    /* Is SET flag of Register B disabled? */
+    if ((s->cmos_data[RTC_REG_B] & REG_B_SET) == 0) {
+        rtc_set_cmos(s, &ret);
+    }
+}
+
+static int update_in_progress(RTCState *s)
+{
+    int64_t guest_nsec;
+
+    if (!rtc_running(s)) {
+        return 0;
+    }
+    if (qemu_timer_pending(s->update_timer)) {
+        int64_t next_update_time = qemu_timer_expire_time_ns(s->update_timer);
+        /* Latch UIP until the timer expires.  */
+        if (qemu_get_clock_ns(rtc_clock) >= (next_update_time - UIP_HOLD_LENGTH)) {
+            s->cmos_data[RTC_REG_A] |= REG_A_UIP;
+            return 1;
+        }
+    }
+
+    guest_nsec = get_guest_rtc_ns(s);
+    /* UIP bit will be set at last 244us of every second. */
+    if ((guest_nsec % NSEC_PER_SEC) >= (NSEC_PER_SEC - UIP_HOLD_LENGTH)) {
+        return 1;
+    }
+    return 0;
+}
+
+static uint64_t cmos_ioport_read(void *opaque, hwaddr addr,
+                                 unsigned size)
+{
+    RTCState *s = opaque;
+    int ret;
+    if ((addr & 1) == 0) {
+        return 0xff;
+    } else {
+        switch(s->cmos_index) {
+       case RTC_IBM_PS2_CENTURY_BYTE:
+            s->cmos_index = RTC_CENTURY;
+            /* fall through */
+        case RTC_CENTURY:
+        case RTC_SECONDS:
+        case RTC_MINUTES:
+        case RTC_HOURS:
+        case RTC_DAY_OF_WEEK:
+        case RTC_DAY_OF_MONTH:
+        case RTC_MONTH:
+        case RTC_YEAR:
+            /* if not in set mode, calibrate cmos before
+             * reading*/
+            if (rtc_running(s)) {
+                rtc_update_time(s);
+            }
+            ret = s->cmos_data[s->cmos_index];
+            break;
+        case RTC_REG_A:
+            if (update_in_progress(s)) {
+                s->cmos_data[s->cmos_index] |= REG_A_UIP;
+            } else {
+                s->cmos_data[s->cmos_index] &= ~REG_A_UIP;
+            }
+            ret = s->cmos_data[s->cmos_index];
+            break;
+        case RTC_REG_C:
+            ret = s->cmos_data[s->cmos_index];
+            qemu_irq_lower(s->irq);
+            s->cmos_data[RTC_REG_C] = 0x00;
+            if (ret & (REG_C_UF | REG_C_AF)) {
+                check_update_timer(s);
+            }
+#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);
+                if (apic_get_irq_delivered()) {
+                    s->irq_coalesced--;
+                    DPRINTF_C("cmos: coalesced irqs decreased to %d\n",
+                              s->irq_coalesced);
+                }
+            }
+#endif
+            break;
+        default:
+            ret = s->cmos_data[s->cmos_index];
+            break;
+        }
+        CMOS_DPRINTF("cmos: read index=0x%02x val=0x%02x\n",
+                     s->cmos_index, ret);
+        return ret;
+    }
+}
+
+void rtc_set_memory(ISADevice *dev, int addr, int val)
+{
+    RTCState *s = DO_UPCAST(RTCState, dev, dev);
+    if (addr >= 0 && addr <= 127)
+        s->cmos_data[addr] = val;
+}
+
+static void rtc_set_date_from_host(ISADevice *dev)
+{
+    RTCState *s = DO_UPCAST(RTCState, dev, dev);
+    struct tm tm;
+
+    qemu_get_timedate(&tm, 0);
+
+    s->base_rtc = mktimegm(&tm);
+    s->last_update = qemu_get_clock_ns(rtc_clock);
+    s->offset = 0;
+
+    /* set the CMOS date */
+    rtc_set_cmos(s, &tm);
+}
+
+static int rtc_post_load(void *opaque, int version_id)
+{
+    RTCState *s = opaque;
+
+    if (version_id <= 2) {
+        rtc_set_time(s);
+        s->offset = 0;
+        check_update_timer(s);
+    }
+
+#ifdef TARGET_I386
+    if (version_id >= 2) {
+        if (s->lost_tick_policy == LOST_TICK_SLEW) {
+            rtc_coalesced_timer_update(s);
+        }
+    }
+#endif
+    return 0;
+}
+
+static const VMStateDescription vmstate_rtc = {
+    .name = "mc146818rtc",
+    .version_id = 3,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .post_load = rtc_post_load,
+    .fields      = (VMStateField []) {
+        VMSTATE_BUFFER(cmos_data, RTCState),
+        VMSTATE_UINT8(cmos_index, RTCState),
+        VMSTATE_UNUSED(7*4),
+        VMSTATE_TIMER(periodic_timer, RTCState),
+        VMSTATE_INT64(next_periodic_time, RTCState),
+        VMSTATE_UNUSED(3*8),
+        VMSTATE_UINT32_V(irq_coalesced, RTCState, 2),
+        VMSTATE_UINT32_V(period, RTCState, 2),
+        VMSTATE_UINT64_V(base_rtc, RTCState, 3),
+        VMSTATE_UINT64_V(last_update, RTCState, 3),
+        VMSTATE_INT64_V(offset, RTCState, 3),
+        VMSTATE_TIMER_V(update_timer, RTCState, 3),
+        VMSTATE_UINT64_V(next_alarm_time, RTCState, 3),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void rtc_notify_clock_reset(Notifier *notifier, void *data)
+{
+    RTCState *s = container_of(notifier, RTCState, clock_reset_notifier);
+    int64_t now = *(int64_t *)data;
+
+    rtc_set_date_from_host(&s->dev);
+    periodic_timer_update(s, now);
+    check_update_timer(s);
+#ifdef TARGET_I386
+    if (s->lost_tick_policy == LOST_TICK_SLEW) {
+        rtc_coalesced_timer_update(s);
+    }
+#endif
+}
+
+/* set CMOS shutdown status register (index 0xF) as S3_resume(0xFE)
+   BIOS will read it and start S3 resume at POST Entry */
+static void rtc_notify_suspend(Notifier *notifier, void *data)
+{
+    RTCState *s = container_of(notifier, RTCState, suspend_notifier);
+    rtc_set_memory(&s->dev, 0xF, 0xFE);
+}
+
+static void rtc_reset(void *opaque)
+{
+    RTCState *s = opaque;
+
+    s->cmos_data[RTC_REG_B] &= ~(REG_B_PIE | REG_B_AIE | REG_B_SQWE);
+    s->cmos_data[RTC_REG_C] &= ~(REG_C_UF | REG_C_IRQF | REG_C_PF | REG_C_AF);
+    check_update_timer(s);
+
+    qemu_irq_lower(s->irq);
+
+#ifdef TARGET_I386
+    if (s->lost_tick_policy == LOST_TICK_SLEW) {
+        s->irq_coalesced = 0;
+    }
+#endif
+}
+
+static const MemoryRegionOps cmos_ops = {
+    .read = cmos_ioport_read,
+    .write = cmos_ioport_write,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void rtc_get_date(Object *obj, Visitor *v, void *opaque,
+                         const char *name, Error **errp)
+{
+    ISADevice *isa = ISA_DEVICE(obj);
+    RTCState *s = DO_UPCAST(RTCState, dev, isa);
+    struct tm current_tm;
+
+    rtc_update_time(s);
+    rtc_get_time(s, &current_tm);
+    visit_start_struct(v, NULL, "struct tm", name, 0, errp);
+    visit_type_int32(v, &current_tm.tm_year, "tm_year", errp);
+    visit_type_int32(v, &current_tm.tm_mon, "tm_mon", errp);
+    visit_type_int32(v, &current_tm.tm_mday, "tm_mday", errp);
+    visit_type_int32(v, &current_tm.tm_hour, "tm_hour", errp);
+    visit_type_int32(v, &current_tm.tm_min, "tm_min", errp);
+    visit_type_int32(v, &current_tm.tm_sec, "tm_sec", errp);
+    visit_end_struct(v, errp);
+}
+
+static int rtc_initfn(ISADevice *dev)
+{
+    RTCState *s = DO_UPCAST(RTCState, dev, dev);
+    int base = 0x70;
+
+    s->cmos_data[RTC_REG_A] = 0x26;
+    s->cmos_data[RTC_REG_B] = 0x02;
+    s->cmos_data[RTC_REG_C] = 0x00;
+    s->cmos_data[RTC_REG_D] = 0x80;
+
+    /* This is for historical reasons.  The default base year qdev property
+     * was set to 2000 for most machine types before the century byte was
+     * implemented.
+     *
+     * This if statement means that the century byte will be always 0
+     * (at least until 2079...) for base_year = 1980, but will be set
+     * correctly for base_year = 2000.
+     */
+    if (s->base_year == 2000) {
+        s->base_year = 0;
+    }
+
+    rtc_set_date_from_host(dev);
+
+#ifdef TARGET_I386
+    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->update_timer = qemu_new_timer_ns(rtc_clock, rtc_update_timer, s);
+    check_update_timer(s);
+
+    s->clock_reset_notifier.notify = rtc_notify_clock_reset;
+    qemu_register_clock_reset_notifier(rtc_clock, &s->clock_reset_notifier);
+
+    s->suspend_notifier.notify = rtc_notify_suspend;
+    qemu_register_suspend_notifier(&s->suspend_notifier);
+
+    memory_region_init_io(&s->io, &cmos_ops, s, "rtc", 2);
+    isa_register_ioport(dev, &s->io, base);
+
+    qdev_set_legacy_instance_id(&dev->qdev, base, 3);
+    qemu_register_reset(rtc_reset, s);
+
+    object_property_add(OBJECT(s), "date", "struct tm",
+                        rtc_get_date, NULL, NULL, s, NULL);
+
+    return 0;
+}
+
+ISADevice *rtc_init(ISABus *bus, int base_year, qemu_irq intercept_irq)
+{
+    ISADevice *dev;
+    RTCState *s;
+
+    dev = isa_create(bus, "mc146818rtc");
+    s = DO_UPCAST(RTCState, dev, dev);
+    qdev_prop_set_int32(&dev->qdev, "base_year", base_year);
+    qdev_init_nofail(&dev->qdev);
+    if (intercept_irq) {
+        s->irq = intercept_irq;
+    } else {
+        isa_init_irq(dev, &s->irq, RTC_ISA_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 const TypeInfo mc146818rtc_info = {
+    .name          = "mc146818rtc",
+    .parent        = TYPE_ISA_DEVICE,
+    .instance_size = sizeof(RTCState),
+    .class_init    = rtc_class_initfn,
+};
+
+static void mc146818rtc_register_types(void)
+{
+    type_register_static(&mc146818rtc_info);
+}
+
+type_init(mc146818rtc_register_types)
diff --git a/hw/timer/milkymist-sysctl.c b/hw/timer/milkymist-sysctl.c
new file mode 100644 (file)
index 0000000..e083a28
--- /dev/null
@@ -0,0 +1,338 @@
+/*
+ *  QEMU model of the Milkymist System Controller.
+ *
+ *  Copyright (c) 2010-2012 Michael Walle <michael@walle.cc>
+ *
+ * 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/>.
+ *
+ *
+ * Specification available at:
+ *   http://www.milkymist.org/socdoc/sysctl.pdf
+ */
+
+#include "hw/hw.h"
+#include "hw/sysbus.h"
+#include "sysemu/sysemu.h"
+#include "trace.h"
+#include "qemu/timer.h"
+#include "hw/ptimer.h"
+#include "qemu/error-report.h"
+
+enum {
+    CTRL_ENABLE      = (1<<0),
+    CTRL_AUTORESTART = (1<<1),
+};
+
+enum {
+    ICAP_READY       = (1<<0),
+};
+
+enum {
+    R_GPIO_IN         = 0,
+    R_GPIO_OUT,
+    R_GPIO_INTEN,
+    R_TIMER0_CONTROL  = 4,
+    R_TIMER0_COMPARE,
+    R_TIMER0_COUNTER,
+    R_TIMER1_CONTROL  = 8,
+    R_TIMER1_COMPARE,
+    R_TIMER1_COUNTER,
+    R_ICAP = 16,
+    R_DBG_SCRATCHPAD  = 20,
+    R_DBG_WRITE_LOCK,
+    R_CLK_FREQUENCY   = 29,
+    R_CAPABILITIES,
+    R_SYSTEM_ID,
+    R_MAX
+};
+
+struct MilkymistSysctlState {
+    SysBusDevice busdev;
+    MemoryRegion regs_region;
+
+    QEMUBH *bh0;
+    QEMUBH *bh1;
+    ptimer_state *ptimer0;
+    ptimer_state *ptimer1;
+
+    uint32_t freq_hz;
+    uint32_t capabilities;
+    uint32_t systemid;
+    uint32_t strappings;
+
+    uint32_t regs[R_MAX];
+
+    qemu_irq gpio_irq;
+    qemu_irq timer0_irq;
+    qemu_irq timer1_irq;
+};
+typedef struct MilkymistSysctlState MilkymistSysctlState;
+
+static void sysctl_icap_write(MilkymistSysctlState *s, uint32_t value)
+{
+    trace_milkymist_sysctl_icap_write(value);
+    switch (value & 0xffff) {
+    case 0x000e:
+        qemu_system_shutdown_request();
+        break;
+    }
+}
+
+static uint64_t sysctl_read(void *opaque, hwaddr addr,
+                            unsigned size)
+{
+    MilkymistSysctlState *s = opaque;
+    uint32_t r = 0;
+
+    addr >>= 2;
+    switch (addr) {
+    case R_TIMER0_COUNTER:
+        r = (uint32_t)ptimer_get_count(s->ptimer0);
+        /* milkymist timer counts up */
+        r = s->regs[R_TIMER0_COMPARE] - r;
+        break;
+    case R_TIMER1_COUNTER:
+        r = (uint32_t)ptimer_get_count(s->ptimer1);
+        /* milkymist timer counts up */
+        r = s->regs[R_TIMER1_COMPARE] - r;
+        break;
+    case R_GPIO_IN:
+    case R_GPIO_OUT:
+    case R_GPIO_INTEN:
+    case R_TIMER0_CONTROL:
+    case R_TIMER0_COMPARE:
+    case R_TIMER1_CONTROL:
+    case R_TIMER1_COMPARE:
+    case R_ICAP:
+    case R_DBG_SCRATCHPAD:
+    case R_DBG_WRITE_LOCK:
+    case R_CLK_FREQUENCY:
+    case R_CAPABILITIES:
+    case R_SYSTEM_ID:
+        r = s->regs[addr];
+        break;
+
+    default:
+        error_report("milkymist_sysctl: read access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+
+    trace_milkymist_sysctl_memory_read(addr << 2, r);
+
+    return r;
+}
+
+static void sysctl_write(void *opaque, hwaddr addr, uint64_t value,
+                         unsigned size)
+{
+    MilkymistSysctlState *s = opaque;
+
+    trace_milkymist_sysctl_memory_write(addr, value);
+
+    addr >>= 2;
+    switch (addr) {
+    case R_GPIO_OUT:
+    case R_GPIO_INTEN:
+    case R_TIMER0_COUNTER:
+    case R_TIMER1_COUNTER:
+    case R_DBG_SCRATCHPAD:
+        s->regs[addr] = value;
+        break;
+    case R_TIMER0_COMPARE:
+        ptimer_set_limit(s->ptimer0, value, 0);
+        s->regs[addr] = value;
+        break;
+    case R_TIMER1_COMPARE:
+        ptimer_set_limit(s->ptimer1, value, 0);
+        s->regs[addr] = value;
+        break;
+    case R_TIMER0_CONTROL:
+        s->regs[addr] = value;
+        if (s->regs[R_TIMER0_CONTROL] & CTRL_ENABLE) {
+            trace_milkymist_sysctl_start_timer0();
+            ptimer_set_count(s->ptimer0,
+                    s->regs[R_TIMER0_COMPARE] - s->regs[R_TIMER0_COUNTER]);
+            ptimer_run(s->ptimer0, 0);
+        } else {
+            trace_milkymist_sysctl_stop_timer0();
+            ptimer_stop(s->ptimer0);
+        }
+        break;
+    case R_TIMER1_CONTROL:
+        s->regs[addr] = value;
+        if (s->regs[R_TIMER1_CONTROL] & CTRL_ENABLE) {
+            trace_milkymist_sysctl_start_timer1();
+            ptimer_set_count(s->ptimer1,
+                    s->regs[R_TIMER1_COMPARE] - s->regs[R_TIMER1_COUNTER]);
+            ptimer_run(s->ptimer1, 0);
+        } else {
+            trace_milkymist_sysctl_stop_timer1();
+            ptimer_stop(s->ptimer1);
+        }
+        break;
+    case R_ICAP:
+        sysctl_icap_write(s, value);
+        break;
+    case R_DBG_WRITE_LOCK:
+        s->regs[addr] = 1;
+        break;
+    case R_SYSTEM_ID:
+        qemu_system_reset_request();
+        break;
+
+    case R_GPIO_IN:
+    case R_CLK_FREQUENCY:
+    case R_CAPABILITIES:
+        error_report("milkymist_sysctl: write to read-only register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+
+    default:
+        error_report("milkymist_sysctl: write access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+}
+
+static const MemoryRegionOps sysctl_mmio_ops = {
+    .read = sysctl_read,
+    .write = sysctl_write,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void timer0_hit(void *opaque)
+{
+    MilkymistSysctlState *s = opaque;
+
+    if (!(s->regs[R_TIMER0_CONTROL] & CTRL_AUTORESTART)) {
+        s->regs[R_TIMER0_CONTROL] &= ~CTRL_ENABLE;
+        trace_milkymist_sysctl_stop_timer0();
+        ptimer_stop(s->ptimer0);
+    }
+
+    trace_milkymist_sysctl_pulse_irq_timer0();
+    qemu_irq_pulse(s->timer0_irq);
+}
+
+static void timer1_hit(void *opaque)
+{
+    MilkymistSysctlState *s = opaque;
+
+    if (!(s->regs[R_TIMER1_CONTROL] & CTRL_AUTORESTART)) {
+        s->regs[R_TIMER1_CONTROL] &= ~CTRL_ENABLE;
+        trace_milkymist_sysctl_stop_timer1();
+        ptimer_stop(s->ptimer1);
+    }
+
+    trace_milkymist_sysctl_pulse_irq_timer1();
+    qemu_irq_pulse(s->timer1_irq);
+}
+
+static void milkymist_sysctl_reset(DeviceState *d)
+{
+    MilkymistSysctlState *s =
+            container_of(d, MilkymistSysctlState, busdev.qdev);
+    int i;
+
+    for (i = 0; i < R_MAX; i++) {
+        s->regs[i] = 0;
+    }
+
+    ptimer_stop(s->ptimer0);
+    ptimer_stop(s->ptimer1);
+
+    /* defaults */
+    s->regs[R_ICAP] = ICAP_READY;
+    s->regs[R_SYSTEM_ID] = s->systemid;
+    s->regs[R_CLK_FREQUENCY] = s->freq_hz;
+    s->regs[R_CAPABILITIES] = s->capabilities;
+    s->regs[R_GPIO_IN] = s->strappings;
+}
+
+static int milkymist_sysctl_init(SysBusDevice *dev)
+{
+    MilkymistSysctlState *s = FROM_SYSBUS(typeof(*s), dev);
+
+    sysbus_init_irq(dev, &s->gpio_irq);
+    sysbus_init_irq(dev, &s->timer0_irq);
+    sysbus_init_irq(dev, &s->timer1_irq);
+
+    s->bh0 = qemu_bh_new(timer0_hit, s);
+    s->bh1 = qemu_bh_new(timer1_hit, s);
+    s->ptimer0 = ptimer_init(s->bh0);
+    s->ptimer1 = ptimer_init(s->bh1);
+    ptimer_set_freq(s->ptimer0, s->freq_hz);
+    ptimer_set_freq(s->ptimer1, s->freq_hz);
+
+    memory_region_init_io(&s->regs_region, &sysctl_mmio_ops, s,
+            "milkymist-sysctl", R_MAX * 4);
+    sysbus_init_mmio(dev, &s->regs_region);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_milkymist_sysctl = {
+    .name = "milkymist-sysctl",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(regs, MilkymistSysctlState, R_MAX),
+        VMSTATE_PTIMER(ptimer0, MilkymistSysctlState),
+        VMSTATE_PTIMER(ptimer1, MilkymistSysctlState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static Property milkymist_sysctl_properties[] = {
+    DEFINE_PROP_UINT32("frequency", MilkymistSysctlState,
+    freq_hz, 80000000),
+    DEFINE_PROP_UINT32("capabilities", MilkymistSysctlState,
+    capabilities, 0x00000000),
+    DEFINE_PROP_UINT32("systemid", MilkymistSysctlState,
+    systemid, 0x10014d31),
+    DEFINE_PROP_UINT32("gpio_strappings", MilkymistSysctlState,
+    strappings, 0x00000001),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void milkymist_sysctl_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = milkymist_sysctl_init;
+    dc->reset = milkymist_sysctl_reset;
+    dc->vmsd = &vmstate_milkymist_sysctl;
+    dc->props = milkymist_sysctl_properties;
+}
+
+static const 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_types(void)
+{
+    type_register_static(&milkymist_sysctl_info);
+}
+
+type_init(milkymist_sysctl_register_types)
diff --git a/hw/timer/omap_gptimer.c b/hw/timer/omap_gptimer.c
new file mode 100644 (file)
index 0000000..9b0e9dd
--- /dev/null
@@ -0,0 +1,488 @@
+/*
+ * TI OMAP2 general purpose timers emulation.
+ *
+ * Copyright (C) 2007-2008 Nokia Corporation
+ * Written by Andrzej Zaborowski <andrew@openedhand.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 or
+ * (at your option) any later version 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
+ * 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 "hw/hw.h"
+#include "qemu/timer.h"
+#include "hw/arm/omap.h"
+
+/* GP timers */
+struct omap_gp_timer_s {
+    MemoryRegion iomem;
+    qemu_irq irq;
+    qemu_irq wkup;
+    qemu_irq in;
+    qemu_irq out;
+    omap_clk clk;
+    QEMUTimer *timer;
+    QEMUTimer *match;
+    struct omap_target_agent_s *ta;
+
+    int in_val;
+    int out_val;
+    int64_t time;
+    int64_t rate;
+    int64_t ticks_per_sec;
+
+    int16_t config;
+    int status;
+    int it_ena;
+    int wu_ena;
+    int enable;
+    int inout;
+    int capt2;
+    int pt;
+    enum {
+        gpt_trigger_none, gpt_trigger_overflow, gpt_trigger_both
+    } trigger;
+    enum {
+        gpt_capture_none, gpt_capture_rising,
+        gpt_capture_falling, gpt_capture_both
+    } capture;
+    int scpwm;
+    int ce;
+    int pre;
+    int ptv;
+    int ar;
+    int st;
+    int posted;
+    uint32_t val;
+    uint32_t load_val;
+    uint32_t capture_val[2];
+    uint32_t match_val;
+    int capt_num;
+
+    uint16_t writeh;   /* LSB */
+    uint16_t readh;    /* MSB */
+};
+
+#define GPT_TCAR_IT    (1 << 2)
+#define GPT_OVF_IT     (1 << 1)
+#define GPT_MAT_IT     (1 << 0)
+
+static inline void omap_gp_timer_intr(struct omap_gp_timer_s *timer, int it)
+{
+    if (timer->it_ena & it) {
+        if (!timer->status)
+            qemu_irq_raise(timer->irq);
+
+        timer->status |= it;
+        /* Or are the status bits set even when masked?
+         * i.e. is masking applied before or after the status register?  */
+    }
+
+    if (timer->wu_ena & it)
+        qemu_irq_pulse(timer->wkup);
+}
+
+static inline void omap_gp_timer_out(struct omap_gp_timer_s *timer, int level)
+{
+    if (!timer->inout && timer->out_val != level) {
+        timer->out_val = level;
+        qemu_set_irq(timer->out, level);
+    }
+}
+
+static inline uint32_t omap_gp_timer_read(struct omap_gp_timer_s *timer)
+{
+    uint64_t distance;
+
+    if (timer->st && timer->rate) {
+        distance = qemu_get_clock_ns(vm_clock) - timer->time;
+        distance = muldiv64(distance, timer->rate, timer->ticks_per_sec);
+
+        if (distance >= 0xffffffff - timer->val)
+            return 0xffffffff;
+        else
+            return timer->val + distance;
+    } else
+        return timer->val;
+}
+
+static inline void omap_gp_timer_sync(struct omap_gp_timer_s *timer)
+{
+    if (timer->st) {
+        timer->val = omap_gp_timer_read(timer);
+        timer->time = qemu_get_clock_ns(vm_clock);
+    }
+}
+
+static inline void omap_gp_timer_update(struct omap_gp_timer_s *timer)
+{
+    int64_t expires, matches;
+
+    if (timer->st && timer->rate) {
+        expires = muldiv64(0x100000000ll - timer->val,
+                        timer->ticks_per_sec, timer->rate);
+        qemu_mod_timer(timer->timer, timer->time + expires);
+
+        if (timer->ce && timer->match_val >= timer->val) {
+            matches = muldiv64(timer->match_val - timer->val,
+                            timer->ticks_per_sec, timer->rate);
+            qemu_mod_timer(timer->match, timer->time + matches);
+        } else
+            qemu_del_timer(timer->match);
+    } else {
+        qemu_del_timer(timer->timer);
+        qemu_del_timer(timer->match);
+        omap_gp_timer_out(timer, timer->scpwm);
+    }
+}
+
+static inline void omap_gp_timer_trigger(struct omap_gp_timer_s *timer)
+{
+    if (timer->pt)
+        /* TODO in overflow-and-match mode if the first event to
+         * occur is the match, don't toggle.  */
+        omap_gp_timer_out(timer, !timer->out_val);
+    else
+        /* TODO inverted pulse on timer->out_val == 1?  */
+        qemu_irq_pulse(timer->out);
+}
+
+static void omap_gp_timer_tick(void *opaque)
+{
+    struct omap_gp_timer_s *timer = (struct omap_gp_timer_s *) opaque;
+
+    if (!timer->ar) {
+        timer->st = 0;
+        timer->val = 0;
+    } else {
+        timer->val = timer->load_val;
+        timer->time = qemu_get_clock_ns(vm_clock);
+    }
+
+    if (timer->trigger == gpt_trigger_overflow ||
+                    timer->trigger == gpt_trigger_both)
+        omap_gp_timer_trigger(timer);
+
+    omap_gp_timer_intr(timer, GPT_OVF_IT);
+    omap_gp_timer_update(timer);
+}
+
+static void omap_gp_timer_match(void *opaque)
+{
+    struct omap_gp_timer_s *timer = (struct omap_gp_timer_s *) opaque;
+
+    if (timer->trigger == gpt_trigger_both)
+        omap_gp_timer_trigger(timer);
+
+    omap_gp_timer_intr(timer, GPT_MAT_IT);
+}
+
+static void omap_gp_timer_input(void *opaque, int line, int on)
+{
+    struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque;
+    int trigger;
+
+    switch (s->capture) {
+    default:
+    case gpt_capture_none:
+        trigger = 0;
+        break;
+    case gpt_capture_rising:
+        trigger = !s->in_val && on;
+        break;
+    case gpt_capture_falling:
+        trigger = s->in_val && !on;
+        break;
+    case gpt_capture_both:
+        trigger = (s->in_val == !on);
+        break;
+    }
+    s->in_val = on;
+
+    if (s->inout && trigger && s->capt_num < 2) {
+        s->capture_val[s->capt_num] = omap_gp_timer_read(s);
+
+        if (s->capt2 == s->capt_num ++)
+            omap_gp_timer_intr(s, GPT_TCAR_IT);
+    }
+}
+
+static void omap_gp_timer_clk_update(void *opaque, int line, int on)
+{
+    struct omap_gp_timer_s *timer = (struct omap_gp_timer_s *) opaque;
+
+    omap_gp_timer_sync(timer);
+    timer->rate = on ? omap_clk_getrate(timer->clk) : 0;
+    omap_gp_timer_update(timer);
+}
+
+static void omap_gp_timer_clk_setup(struct omap_gp_timer_s *timer)
+{
+    omap_clk_adduser(timer->clk,
+                    qemu_allocate_irqs(omap_gp_timer_clk_update, timer, 1)[0]);
+    timer->rate = omap_clk_getrate(timer->clk);
+}
+
+void omap_gp_timer_reset(struct omap_gp_timer_s *s)
+{
+    s->config = 0x000;
+    s->status = 0;
+    s->it_ena = 0;
+    s->wu_ena = 0;
+    s->inout = 0;
+    s->capt2 = 0;
+    s->capt_num = 0;
+    s->pt = 0;
+    s->trigger = gpt_trigger_none;
+    s->capture = gpt_capture_none;
+    s->scpwm = 0;
+    s->ce = 0;
+    s->pre = 0;
+    s->ptv = 0;
+    s->ar = 0;
+    s->st = 0;
+    s->posted = 1;
+    s->val = 0x00000000;
+    s->load_val = 0x00000000;
+    s->capture_val[0] = 0x00000000;
+    s->capture_val[1] = 0x00000000;
+    s->match_val = 0x00000000;
+    omap_gp_timer_update(s);
+}
+
+static uint32_t omap_gp_timer_readw(void *opaque, hwaddr addr)
+{
+    struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque;
+
+    switch (addr) {
+    case 0x00: /* TIDR */
+        return 0x21;
+
+    case 0x10: /* TIOCP_CFG */
+        return s->config;
+
+    case 0x14: /* TISTAT */
+        /* ??? When's this bit reset? */
+        return 1;                                              /* RESETDONE */
+
+    case 0x18: /* TISR */
+        return s->status;
+
+    case 0x1c: /* TIER */
+        return s->it_ena;
+
+    case 0x20: /* TWER */
+        return s->wu_ena;
+
+    case 0x24: /* TCLR */
+        return (s->inout << 14) |
+                (s->capt2 << 13) |
+                (s->pt << 12) |
+                (s->trigger << 10) |
+                (s->capture << 8) |
+                (s->scpwm << 7) |
+                (s->ce << 6) |
+                (s->pre << 5) |
+                (s->ptv << 2) |
+                (s->ar << 1) |
+                (s->st << 0);
+
+    case 0x28: /* TCRR */
+        return omap_gp_timer_read(s);
+
+    case 0x2c: /* TLDR */
+        return s->load_val;
+
+    case 0x30: /* TTGR */
+        return 0xffffffff;
+
+    case 0x34: /* TWPS */
+        return 0x00000000;     /* No posted writes pending.  */
+
+    case 0x38: /* TMAR */
+        return s->match_val;
+
+    case 0x3c: /* TCAR1 */
+        return s->capture_val[0];
+
+    case 0x40: /* TSICR */
+        return s->posted << 2;
+
+    case 0x44: /* TCAR2 */
+        return s->capture_val[1];
+    }
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static uint32_t omap_gp_timer_readh(void *opaque, hwaddr addr)
+{
+    struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque;
+    uint32_t ret;
+
+    if (addr & 2)
+        return s->readh;
+    else {
+        ret = omap_gp_timer_readw(opaque, addr);
+        s->readh = ret >> 16;
+        return ret & 0xffff;
+    }
+}
+
+static void omap_gp_timer_write(void *opaque, hwaddr addr,
+                uint32_t value)
+{
+    struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque;
+
+    switch (addr) {
+    case 0x00: /* TIDR */
+    case 0x14: /* TISTAT */
+    case 0x34: /* TWPS */
+    case 0x3c: /* TCAR1 */
+    case 0x44: /* TCAR2 */
+        OMAP_RO_REG(addr);
+        break;
+
+    case 0x10: /* TIOCP_CFG */
+        s->config = value & 0x33d;
+        if (((value >> 3) & 3) == 3)                           /* IDLEMODE */
+            fprintf(stderr, "%s: illegal IDLEMODE value in TIOCP_CFG\n",
+                            __FUNCTION__);
+        if (value & 2)                                         /* SOFTRESET */
+            omap_gp_timer_reset(s);
+        break;
+
+    case 0x18: /* TISR */
+        if (value & GPT_TCAR_IT)
+            s->capt_num = 0;
+        if (s->status && !(s->status &= ~value))
+            qemu_irq_lower(s->irq);
+        break;
+
+    case 0x1c: /* TIER */
+        s->it_ena = value & 7;
+        break;
+
+    case 0x20: /* TWER */
+        s->wu_ena = value & 7;
+        break;
+
+    case 0x24: /* TCLR */
+        omap_gp_timer_sync(s);
+        s->inout = (value >> 14) & 1;
+        s->capt2 = (value >> 13) & 1;
+        s->pt = (value >> 12) & 1;
+        s->trigger = (value >> 10) & 3;
+        if (s->capture == gpt_capture_none &&
+                        ((value >> 8) & 3) != gpt_capture_none)
+            s->capt_num = 0;
+        s->capture = (value >> 8) & 3;
+        s->scpwm = (value >> 7) & 1;
+        s->ce = (value >> 6) & 1;
+        s->pre = (value >> 5) & 1;
+        s->ptv = (value >> 2) & 7;
+        s->ar = (value >> 1) & 1;
+        s->st = (value >> 0) & 1;
+        if (s->inout && s->trigger != gpt_trigger_none)
+            fprintf(stderr, "%s: GP timer pin must be an output "
+                            "for this trigger mode\n", __FUNCTION__);
+        if (!s->inout && s->capture != gpt_capture_none)
+            fprintf(stderr, "%s: GP timer pin must be an input "
+                            "for this capture mode\n", __FUNCTION__);
+        if (s->trigger == gpt_trigger_none)
+            omap_gp_timer_out(s, s->scpwm);
+        /* TODO: make sure this doesn't overflow 32-bits */
+        s->ticks_per_sec = get_ticks_per_sec() << (s->pre ? s->ptv + 1 : 0);
+        omap_gp_timer_update(s);
+        break;
+
+    case 0x28: /* TCRR */
+        s->time = qemu_get_clock_ns(vm_clock);
+        s->val = value;
+        omap_gp_timer_update(s);
+        break;
+
+    case 0x2c: /* TLDR */
+        s->load_val = value;
+        break;
+
+    case 0x30: /* TTGR */
+        s->time = qemu_get_clock_ns(vm_clock);
+        s->val = s->load_val;
+        omap_gp_timer_update(s);
+        break;
+
+    case 0x38: /* TMAR */
+        omap_gp_timer_sync(s);
+        s->match_val = value;
+        omap_gp_timer_update(s);
+        break;
+
+    case 0x40: /* TSICR */
+        s->posted = (value >> 2) & 1;
+        if (value & 2) /* How much exactly are we supposed to reset? */
+            omap_gp_timer_reset(s);
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+    }
+}
+
+static void omap_gp_timer_writeh(void *opaque, hwaddr addr,
+                uint32_t value)
+{
+    struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque;
+
+    if (addr & 2)
+        return omap_gp_timer_write(opaque, addr, (value << 16) | s->writeh);
+    else
+        s->writeh = (uint16_t) value;
+}
+
+static const MemoryRegionOps omap_gp_timer_ops = {
+    .old_mmio = {
+        .read = {
+            omap_badwidth_read32,
+            omap_gp_timer_readh,
+            omap_gp_timer_readw,
+        },
+        .write = {
+            omap_badwidth_write32,
+            omap_gp_timer_writeh,
+            omap_gp_timer_write,
+        },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+struct omap_gp_timer_s *omap_gp_timer_init(struct omap_target_agent_s *ta,
+                qemu_irq irq, omap_clk fclk, omap_clk iclk)
+{
+    struct omap_gp_timer_s *s = (struct omap_gp_timer_s *)
+            g_malloc0(sizeof(struct omap_gp_timer_s));
+
+    s->ta = ta;
+    s->irq = irq;
+    s->clk = fclk;
+    s->timer = qemu_new_timer_ns(vm_clock, omap_gp_timer_tick, s);
+    s->match = qemu_new_timer_ns(vm_clock, omap_gp_timer_match, s);
+    s->in = qemu_allocate_irqs(omap_gp_timer_input, s, 1)[0];
+    omap_gp_timer_reset(s);
+    omap_gp_timer_clk_setup(s);
+
+    memory_region_init_io(&s->iomem, &omap_gp_timer_ops, s, "omap.gptimer",
+                          omap_l4_region_size(ta, 0));
+    omap_l4_attach(ta, 0, &s->iomem);
+
+    return s;
+}
diff --git a/hw/timer/omap_synctimer.c b/hw/timer/omap_synctimer.c
new file mode 100644 (file)
index 0000000..a24f35c
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * TI OMAP2 32kHz sync timer emulation.
+ *
+ * Copyright (C) 2007-2008 Nokia Corporation
+ * Written by Andrzej Zaborowski <andrew@openedhand.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 or
+ * (at your option) any later version 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
+ * 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 "hw/hw.h"
+#include "qemu/timer.h"
+#include "hw/arm/omap.h"
+struct omap_synctimer_s {
+    MemoryRegion iomem;
+    uint32_t val;
+    uint16_t readh;
+};
+
+/* 32-kHz Sync Timer of the OMAP2 */
+static uint32_t omap_synctimer_read(struct omap_synctimer_s *s) {
+    return muldiv64(qemu_get_clock_ns(vm_clock), 0x8000, get_ticks_per_sec());
+}
+
+void omap_synctimer_reset(struct omap_synctimer_s *s)
+{
+    s->val = omap_synctimer_read(s);
+}
+
+static uint32_t omap_synctimer_readw(void *opaque, hwaddr addr)
+{
+    struct omap_synctimer_s *s = (struct omap_synctimer_s *) opaque;
+
+    switch (addr) {
+    case 0x00: /* 32KSYNCNT_REV */
+        return 0x21;
+
+    case 0x10: /* CR */
+        return omap_synctimer_read(s) - s->val;
+    }
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static uint32_t omap_synctimer_readh(void *opaque, hwaddr addr)
+{
+    struct omap_synctimer_s *s = (struct omap_synctimer_s *) opaque;
+    uint32_t ret;
+
+    if (addr & 2)
+        return s->readh;
+    else {
+        ret = omap_synctimer_readw(opaque, addr);
+        s->readh = ret >> 16;
+        return ret & 0xffff;
+    }
+}
+
+static void omap_synctimer_write(void *opaque, hwaddr addr,
+                uint32_t value)
+{
+    OMAP_BAD_REG(addr);
+}
+
+static const MemoryRegionOps omap_synctimer_ops = {
+    .old_mmio = {
+        .read = {
+            omap_badwidth_read32,
+            omap_synctimer_readh,
+            omap_synctimer_readw,
+        },
+        .write = {
+            omap_badwidth_write32,
+            omap_synctimer_write,
+            omap_synctimer_write,
+        },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+struct omap_synctimer_s *omap_synctimer_init(struct omap_target_agent_s *ta,
+                struct omap_mpu_state_s *mpu, omap_clk fclk, omap_clk iclk)
+{
+    struct omap_synctimer_s *s = g_malloc0(sizeof(*s));
+
+    omap_synctimer_reset(s);
+    memory_region_init_io(&s->iomem, &omap_synctimer_ops, s, "omap.synctimer",
+                          omap_l4_region_size(ta, 0));
+    omap_l4_attach(ta, 0, &s->iomem);
+
+    return s;
+}
diff --git a/hw/timer/pl031.c b/hw/timer/pl031.c
new file mode 100644 (file)
index 0000000..764940b
--- /dev/null
@@ -0,0 +1,265 @@
+/*
+ * ARM AMBA PrimeCell PL031 RTC
+ *
+ * Copyright (c) 2007 CodeSourcery
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * 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 "hw/sysbus.h"
+#include "qemu/timer.h"
+#include "sysemu/sysemu.h"
+
+//#define DEBUG_PL031
+
+#ifdef DEBUG_PL031
+#define DPRINTF(fmt, ...) \
+do { printf("pl031: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while(0)
+#endif
+
+#define RTC_DR      0x00    /* Data read register */
+#define RTC_MR      0x04    /* Match register */
+#define RTC_LR      0x08    /* Data load register */
+#define RTC_CR      0x0c    /* Control register */
+#define RTC_IMSC    0x10    /* Interrupt mask and set register */
+#define RTC_RIS     0x14    /* Raw interrupt status register */
+#define RTC_MIS     0x18    /* Masked interrupt status register */
+#define RTC_ICR     0x1c    /* Interrupt clear register */
+
+typedef struct {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    QEMUTimer *timer;
+    qemu_irq irq;
+
+    /* Needed to preserve the tick_count across migration, even if the
+     * absolute value of the rtc_clock is different on the source and
+     * destination.
+     */
+    uint32_t tick_offset_vmstate;
+    uint32_t tick_offset;
+
+    uint32_t mr;
+    uint32_t lr;
+    uint32_t cr;
+    uint32_t im;
+    uint32_t is;
+} pl031_state;
+
+static const unsigned char pl031_id[] = {
+    0x31, 0x10, 0x14, 0x00,         /* Device ID        */
+    0x0d, 0xf0, 0x05, 0xb1          /* Cell ID      */
+};
+
+static void pl031_update(pl031_state *s)
+{
+    qemu_set_irq(s->irq, s->is & s->im);
+}
+
+static void pl031_interrupt(void * opaque)
+{
+    pl031_state *s = (pl031_state *)opaque;
+
+    s->is = 1;
+    DPRINTF("Alarm raised\n");
+    pl031_update(s);
+}
+
+static uint32_t pl031_get_count(pl031_state *s)
+{
+    int64_t now = qemu_get_clock_ns(rtc_clock);
+    return s->tick_offset + now / get_ticks_per_sec();
+}
+
+static void pl031_set_alarm(pl031_state *s)
+{
+    uint32_t ticks;
+
+    /* The timer wraps around.  This subtraction also wraps in the same way,
+       and gives correct results when alarm < now_ticks.  */
+    ticks = s->mr - pl031_get_count(s);
+    DPRINTF("Alarm set in %ud ticks\n", ticks);
+    if (ticks == 0) {
+        qemu_del_timer(s->timer);
+        pl031_interrupt(s);
+    } else {
+        int64_t now = qemu_get_clock_ns(rtc_clock);
+        qemu_mod_timer(s->timer, now + (int64_t)ticks * get_ticks_per_sec());
+    }
+}
+
+static uint64_t pl031_read(void *opaque, hwaddr offset,
+                           unsigned size)
+{
+    pl031_state *s = (pl031_state *)opaque;
+
+    if (offset >= 0xfe0  &&  offset < 0x1000)
+        return pl031_id[(offset - 0xfe0) >> 2];
+
+    switch (offset) {
+    case RTC_DR:
+        return pl031_get_count(s);
+    case RTC_MR:
+        return s->mr;
+    case RTC_IMSC:
+        return s->im;
+    case RTC_RIS:
+        return s->is;
+    case RTC_LR:
+        return s->lr;
+    case RTC_CR:
+        /* RTC is permanently enabled.  */
+        return 1;
+    case RTC_MIS:
+        return s->is & s->im;
+    case RTC_ICR:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "pl031: read of write-only register at offset 0x%x\n",
+                      (int)offset);
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "pl031_read: Bad offset 0x%x\n", (int)offset);
+        break;
+    }
+
+    return 0;
+}
+
+static void pl031_write(void * opaque, hwaddr offset,
+                        uint64_t value, unsigned size)
+{
+    pl031_state *s = (pl031_state *)opaque;
+
+
+    switch (offset) {
+    case RTC_LR:
+        s->tick_offset += value - pl031_get_count(s);
+        pl031_set_alarm(s);
+        break;
+    case RTC_MR:
+        s->mr = value;
+        pl031_set_alarm(s);
+        break;
+    case RTC_IMSC:
+        s->im = value & 1;
+        DPRINTF("Interrupt mask %d\n", s->im);
+        pl031_update(s);
+        break;
+    case RTC_ICR:
+        /* The PL031 documentation (DDI0224B) states that the interrupt is
+           cleared when bit 0 of the written value is set.  However the
+           arm926e documentation (DDI0287B) states that the interrupt is
+           cleared when any value is written.  */
+        DPRINTF("Interrupt cleared");
+        s->is = 0;
+        pl031_update(s);
+        break;
+    case RTC_CR:
+        /* Written value is ignored.  */
+        break;
+
+    case RTC_DR:
+    case RTC_MIS:
+    case RTC_RIS:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "pl031: write to read-only register at offset 0x%x\n",
+                      (int)offset);
+        break;
+
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "pl031_write: Bad offset 0x%x\n", (int)offset);
+        break;
+    }
+}
+
+static const MemoryRegionOps pl031_ops = {
+    .read = pl031_read,
+    .write = pl031_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int pl031_init(SysBusDevice *dev)
+{
+    pl031_state *s = FROM_SYSBUS(pl031_state, dev);
+    struct tm tm;
+
+    memory_region_init_io(&s->iomem, &pl031_ops, s, "pl031", 0x1000);
+    sysbus_init_mmio(dev, &s->iomem);
+
+    sysbus_init_irq(dev, &s->irq);
+    qemu_get_timedate(&tm, 0);
+    s->tick_offset = mktimegm(&tm) - qemu_get_clock_ns(rtc_clock) / get_ticks_per_sec();
+
+    s->timer = qemu_new_timer_ns(rtc_clock, pl031_interrupt, s);
+    return 0;
+}
+
+static void pl031_pre_save(void *opaque)
+{
+    pl031_state *s = opaque;
+
+    /* tick_offset is base_time - rtc_clock base time.  Instead, we want to
+     * store the base time relative to the vm_clock for backwards-compatibility.  */
+    int64_t delta = qemu_get_clock_ns(rtc_clock) - qemu_get_clock_ns(vm_clock);
+    s->tick_offset_vmstate = s->tick_offset + delta / get_ticks_per_sec();
+}
+
+static int pl031_post_load(void *opaque, int version_id)
+{
+    pl031_state *s = opaque;
+
+    int64_t delta = qemu_get_clock_ns(rtc_clock) - qemu_get_clock_ns(vm_clock);
+    s->tick_offset = s->tick_offset_vmstate - delta / get_ticks_per_sec();
+    pl031_set_alarm(s);
+    return 0;
+}
+
+static const VMStateDescription vmstate_pl031 = {
+    .name = "pl031",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .pre_save = pl031_pre_save,
+    .post_load = pl031_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(tick_offset_vmstate, pl031_state),
+        VMSTATE_UINT32(mr, pl031_state),
+        VMSTATE_UINT32(lr, pl031_state),
+        VMSTATE_UINT32(cr, pl031_state),
+        VMSTATE_UINT32(im, pl031_state),
+        VMSTATE_UINT32(is, pl031_state),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+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 const TypeInfo pl031_info = {
+    .name          = "pl031",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(pl031_state),
+    .class_init    = pl031_class_init,
+};
+
+static void pl031_register_types(void)
+{
+    type_register_static(&pl031_info);
+}
+
+type_init(pl031_register_types)
diff --git a/hw/timer/puv3_ost.c b/hw/timer/puv3_ost.c
new file mode 100644 (file)
index 0000000..0c3d827
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * OSTimer device simulation in PKUnity SoC
+ *
+ * Copyright (C) 2010-2012 Guan Xuetao
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation, or any later version.
+ * See the COPYING file in the top-level directory.
+ */
+#include "hw/sysbus.h"
+#include "hw/ptimer.h"
+
+#undef DEBUG_PUV3
+#include "hw/unicore32/puv3.h"
+
+/* puv3 ostimer implementation. */
+typedef struct {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    QEMUBH *bh;
+    qemu_irq irq;
+    ptimer_state *ptimer;
+
+    uint32_t reg_OSMR0;
+    uint32_t reg_OSCR;
+    uint32_t reg_OSSR;
+    uint32_t reg_OIER;
+} PUV3OSTState;
+
+static uint64_t puv3_ost_read(void *opaque, hwaddr offset,
+        unsigned size)
+{
+    PUV3OSTState *s = opaque;
+    uint32_t ret = 0;
+
+    switch (offset) {
+    case 0x10: /* Counter Register */
+        ret = s->reg_OSMR0 - (uint32_t)ptimer_get_count(s->ptimer);
+        break;
+    case 0x14: /* Status Register */
+        ret = s->reg_OSSR;
+        break;
+    case 0x1c: /* Interrupt Enable Register */
+        ret = s->reg_OIER;
+        break;
+    default:
+        DPRINTF("Bad offset %x\n", (int)offset);
+    }
+    DPRINTF("offset 0x%x, value 0x%x\n", offset, ret);
+    return ret;
+}
+
+static void puv3_ost_write(void *opaque, hwaddr offset,
+        uint64_t value, unsigned size)
+{
+    PUV3OSTState *s = opaque;
+
+    DPRINTF("offset 0x%x, value 0x%x\n", offset, value);
+    switch (offset) {
+    case 0x00: /* Match Register 0 */
+        s->reg_OSMR0 = value;
+        if (s->reg_OSMR0 > s->reg_OSCR) {
+            ptimer_set_count(s->ptimer, s->reg_OSMR0 - s->reg_OSCR);
+        } else {
+            ptimer_set_count(s->ptimer, s->reg_OSMR0 +
+                    (0xffffffff - s->reg_OSCR));
+        }
+        ptimer_run(s->ptimer, 2);
+        break;
+    case 0x14: /* Status Register */
+        assert(value == 0);
+        if (s->reg_OSSR) {
+            s->reg_OSSR = value;
+            qemu_irq_lower(s->irq);
+        }
+        break;
+    case 0x1c: /* Interrupt Enable Register */
+        s->reg_OIER = value;
+        break;
+    default:
+        DPRINTF("Bad offset %x\n", (int)offset);
+    }
+}
+
+static const MemoryRegionOps puv3_ost_ops = {
+    .read = puv3_ost_read,
+    .write = puv3_ost_write,
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void puv3_ost_tick(void *opaque)
+{
+    PUV3OSTState *s = opaque;
+
+    DPRINTF("ost hit when ptimer counter from 0x%x to 0x%x!\n",
+            s->reg_OSCR, s->reg_OSMR0);
+
+    s->reg_OSCR = s->reg_OSMR0;
+    if (s->reg_OIER) {
+        s->reg_OSSR = 1;
+        qemu_irq_raise(s->irq);
+    }
+}
+
+static int puv3_ost_init(SysBusDevice *dev)
+{
+    PUV3OSTState *s = FROM_SYSBUS(PUV3OSTState, dev);
+
+    s->reg_OIER = 0;
+    s->reg_OSSR = 0;
+    s->reg_OSMR0 = 0;
+    s->reg_OSCR = 0;
+
+    sysbus_init_irq(dev, &s->irq);
+
+    s->bh = qemu_bh_new(puv3_ost_tick, s);
+    s->ptimer = ptimer_init(s->bh);
+    ptimer_set_freq(s->ptimer, 50 * 1000 * 1000);
+
+    memory_region_init_io(&s->iomem, &puv3_ost_ops, s, "puv3_ost",
+            PUV3_REGS_OFFSET);
+    sysbus_init_mmio(dev, &s->iomem);
+
+    return 0;
+}
+
+static void puv3_ost_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+    sdc->init = puv3_ost_init;
+}
+
+static const TypeInfo puv3_ost_info = {
+    .name = "puv3_ost",
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(PUV3OSTState),
+    .class_init = puv3_ost_class_init,
+};
+
+static void puv3_ost_register_type(void)
+{
+    type_register_static(&puv3_ost_info);
+}
+
+type_init(puv3_ost_register_type)
diff --git a/hw/timer/pxa2xx_timer.c b/hw/timer/pxa2xx_timer.c
new file mode 100644 (file)
index 0000000..8ea2416
--- /dev/null
@@ -0,0 +1,583 @@
+/*
+ * Intel XScale PXA255/270 OS Timers.
+ *
+ * Copyright (c) 2006 Openedhand Ltd.
+ * Copyright (c) 2006 Thorsten Zitterell
+ *
+ * This code is licensed under the GPL.
+ */
+
+#include "hw/hw.h"
+#include "qemu/timer.h"
+#include "sysemu/sysemu.h"
+#include "hw/arm/pxa.h"
+#include "hw/sysbus.h"
+
+#define OSMR0  0x00
+#define OSMR1  0x04
+#define OSMR2  0x08
+#define OSMR3  0x0c
+#define OSMR4  0x80
+#define OSMR5  0x84
+#define OSMR6  0x88
+#define OSMR7  0x8c
+#define OSMR8  0x90
+#define OSMR9  0x94
+#define OSMR10 0x98
+#define OSMR11 0x9c
+#define OSCR   0x10    /* OS Timer Count */
+#define OSCR4  0x40
+#define OSCR5  0x44
+#define OSCR6  0x48
+#define OSCR7  0x4c
+#define OSCR8  0x50
+#define OSCR9  0x54
+#define OSCR10 0x58
+#define OSCR11 0x5c
+#define OSSR   0x14    /* Timer status register */
+#define OWER   0x18
+#define OIER   0x1c    /* Interrupt enable register  3-0 to E3-E0 */
+#define OMCR4  0xc0    /* OS Match Control registers */
+#define OMCR5  0xc4
+#define OMCR6  0xc8
+#define OMCR7  0xcc
+#define OMCR8  0xd0
+#define OMCR9  0xd4
+#define OMCR10 0xd8
+#define OMCR11 0xdc
+#define OSNR   0x20
+
+#define PXA25X_FREQ    3686400 /* 3.6864 MHz */
+#define PXA27X_FREQ    3250000 /* 3.25 MHz */
+
+static int pxa2xx_timer4_freq[8] = {
+    [0] = 0,
+    [1] = 32768,
+    [2] = 1000,
+    [3] = 1,
+    [4] = 1000000,
+    /* [5] is the "Externally supplied clock".  Assign if necessary.  */
+    [5 ... 7] = 0,
+};
+
+typedef struct PXA2xxTimerInfo PXA2xxTimerInfo;
+
+typedef struct {
+    uint32_t value;
+    qemu_irq irq;
+    QEMUTimer *qtimer;
+    int num;
+    PXA2xxTimerInfo *info;
+} PXA2xxTimer0;
+
+typedef struct {
+    PXA2xxTimer0 tm;
+    int32_t oldclock;
+    int32_t clock;
+    uint64_t lastload;
+    uint32_t freq;
+    uint32_t control;
+} PXA2xxTimer4;
+
+struct PXA2xxTimerInfo {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    uint32_t flags;
+
+    int32_t clock;
+    int32_t oldclock;
+    uint64_t lastload;
+    uint32_t freq;
+    PXA2xxTimer0 timer[4];
+    uint32_t events;
+    uint32_t irq_enabled;
+    uint32_t reset3;
+    uint32_t snapshot;
+
+    qemu_irq irq4;
+    PXA2xxTimer4 tm4[8];
+};
+
+#define PXA2XX_TIMER_HAVE_TM4  0
+
+static inline int pxa2xx_timer_has_tm4(PXA2xxTimerInfo *s)
+{
+    return s->flags & (1 << PXA2XX_TIMER_HAVE_TM4);
+}
+
+static void pxa2xx_timer_update(void *opaque, uint64_t now_qemu)
+{
+    PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque;
+    int i;
+    uint32_t now_vm;
+    uint64_t new_qemu;
+
+    now_vm = s->clock +
+            muldiv64(now_qemu - s->lastload, s->freq, get_ticks_per_sec());
+
+    for (i = 0; i < 4; i ++) {
+        new_qemu = now_qemu + muldiv64((uint32_t) (s->timer[i].value - now_vm),
+                        get_ticks_per_sec(), s->freq);
+        qemu_mod_timer(s->timer[i].qtimer, new_qemu);
+    }
+}
+
+static void pxa2xx_timer_update4(void *opaque, uint64_t now_qemu, int n)
+{
+    PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque;
+    uint32_t now_vm;
+    uint64_t new_qemu;
+    static const int counters[8] = { 0, 0, 0, 0, 4, 4, 6, 6 };
+    int counter;
+
+    if (s->tm4[n].control & (1 << 7))
+        counter = n;
+    else
+        counter = counters[n];
+
+    if (!s->tm4[counter].freq) {
+        qemu_del_timer(s->tm4[n].tm.qtimer);
+        return;
+    }
+
+    now_vm = s->tm4[counter].clock + muldiv64(now_qemu -
+                    s->tm4[counter].lastload,
+                    s->tm4[counter].freq, get_ticks_per_sec());
+
+    new_qemu = now_qemu + muldiv64((uint32_t) (s->tm4[n].tm.value - now_vm),
+                    get_ticks_per_sec(), s->tm4[counter].freq);
+    qemu_mod_timer(s->tm4[n].tm.qtimer, new_qemu);
+}
+
+static uint64_t pxa2xx_timer_read(void *opaque, hwaddr offset,
+                                  unsigned size)
+{
+    PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque;
+    int tm = 0;
+
+    switch (offset) {
+    case OSMR3:  tm ++;
+        /* fall through */
+    case OSMR2:  tm ++;
+        /* fall through */
+    case OSMR1:  tm ++;
+        /* fall through */
+    case OSMR0:
+        return s->timer[tm].value;
+    case OSMR11: tm ++;
+        /* fall through */
+    case OSMR10: tm ++;
+        /* fall through */
+    case OSMR9:  tm ++;
+        /* fall through */
+    case OSMR8:  tm ++;
+        /* fall through */
+    case OSMR7:  tm ++;
+        /* fall through */
+    case OSMR6:  tm ++;
+        /* fall through */
+    case OSMR5:  tm ++;
+        /* fall through */
+    case OSMR4:
+        if (!pxa2xx_timer_has_tm4(s))
+            goto badreg;
+        return s->tm4[tm].tm.value;
+    case OSCR:
+        return s->clock + muldiv64(qemu_get_clock_ns(vm_clock) -
+                        s->lastload, s->freq, get_ticks_per_sec());
+    case OSCR11: tm ++;
+        /* fall through */
+    case OSCR10: tm ++;
+        /* fall through */
+    case OSCR9:  tm ++;
+        /* fall through */
+    case OSCR8:  tm ++;
+        /* fall through */
+    case OSCR7:  tm ++;
+        /* fall through */
+    case OSCR6:  tm ++;
+        /* fall through */
+    case OSCR5:  tm ++;
+        /* fall through */
+    case OSCR4:
+        if (!pxa2xx_timer_has_tm4(s))
+            goto badreg;
+
+        if ((tm == 9 - 4 || tm == 11 - 4) && (s->tm4[tm].control & (1 << 9))) {
+            if (s->tm4[tm - 1].freq)
+                s->snapshot = s->tm4[tm - 1].clock + muldiv64(
+                                qemu_get_clock_ns(vm_clock) -
+                                s->tm4[tm - 1].lastload,
+                                s->tm4[tm - 1].freq, get_ticks_per_sec());
+            else
+                s->snapshot = s->tm4[tm - 1].clock;
+        }
+
+        if (!s->tm4[tm].freq)
+            return s->tm4[tm].clock;
+        return s->tm4[tm].clock + muldiv64(qemu_get_clock_ns(vm_clock) -
+                        s->tm4[tm].lastload, s->tm4[tm].freq, get_ticks_per_sec());
+    case OIER:
+        return s->irq_enabled;
+    case OSSR: /* Status register */
+        return s->events;
+    case OWER:
+        return s->reset3;
+    case OMCR11: tm ++;
+        /* fall through */
+    case OMCR10: tm ++;
+        /* fall through */
+    case OMCR9:  tm ++;
+        /* fall through */
+    case OMCR8:  tm ++;
+        /* fall through */
+    case OMCR7:  tm ++;
+        /* fall through */
+    case OMCR6:  tm ++;
+        /* fall through */
+    case OMCR5:  tm ++;
+        /* fall through */
+    case OMCR4:
+        if (!pxa2xx_timer_has_tm4(s))
+            goto badreg;
+        return s->tm4[tm].control;
+    case OSNR:
+        return s->snapshot;
+    default:
+    badreg:
+        hw_error("pxa2xx_timer_read: Bad offset " REG_FMT "\n", offset);
+    }
+
+    return 0;
+}
+
+static void pxa2xx_timer_write(void *opaque, hwaddr offset,
+                               uint64_t value, unsigned size)
+{
+    int i, tm = 0;
+    PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque;
+
+    switch (offset) {
+    case OSMR3:  tm ++;
+        /* fall through */
+    case OSMR2:  tm ++;
+        /* fall through */
+    case OSMR1:  tm ++;
+        /* fall through */
+    case OSMR0:
+        s->timer[tm].value = value;
+        pxa2xx_timer_update(s, qemu_get_clock_ns(vm_clock));
+        break;
+    case OSMR11: tm ++;
+        /* fall through */
+    case OSMR10: tm ++;
+        /* fall through */
+    case OSMR9:  tm ++;
+        /* fall through */
+    case OSMR8:  tm ++;
+        /* fall through */
+    case OSMR7:  tm ++;
+        /* fall through */
+    case OSMR6:  tm ++;
+        /* fall through */
+    case OSMR5:  tm ++;
+        /* fall through */
+    case OSMR4:
+        if (!pxa2xx_timer_has_tm4(s))
+            goto badreg;
+        s->tm4[tm].tm.value = value;
+        pxa2xx_timer_update4(s, qemu_get_clock_ns(vm_clock), tm);
+        break;
+    case OSCR:
+        s->oldclock = s->clock;
+        s->lastload = qemu_get_clock_ns(vm_clock);
+        s->clock = value;
+        pxa2xx_timer_update(s, s->lastload);
+        break;
+    case OSCR11: tm ++;
+        /* fall through */
+    case OSCR10: tm ++;
+        /* fall through */
+    case OSCR9:  tm ++;
+        /* fall through */
+    case OSCR8:  tm ++;
+        /* fall through */
+    case OSCR7:  tm ++;
+        /* fall through */
+    case OSCR6:  tm ++;
+        /* fall through */
+    case OSCR5:  tm ++;
+        /* fall through */
+    case OSCR4:
+        if (!pxa2xx_timer_has_tm4(s))
+            goto badreg;
+        s->tm4[tm].oldclock = s->tm4[tm].clock;
+        s->tm4[tm].lastload = qemu_get_clock_ns(vm_clock);
+        s->tm4[tm].clock = value;
+        pxa2xx_timer_update4(s, s->tm4[tm].lastload, tm);
+        break;
+    case OIER:
+        s->irq_enabled = value & 0xfff;
+        break;
+    case OSSR: /* Status register */
+        value &= s->events;
+        s->events &= ~value;
+        for (i = 0; i < 4; i ++, value >>= 1)
+            if (value & 1)
+                qemu_irq_lower(s->timer[i].irq);
+        if (pxa2xx_timer_has_tm4(s) && !(s->events & 0xff0) && value)
+            qemu_irq_lower(s->irq4);
+        break;
+    case OWER: /* XXX: Reset on OSMR3 match? */
+        s->reset3 = value;
+        break;
+    case OMCR7:  tm ++;
+        /* fall through */
+    case OMCR6:  tm ++;
+        /* fall through */
+    case OMCR5:  tm ++;
+        /* fall through */
+    case OMCR4:
+        if (!pxa2xx_timer_has_tm4(s))
+            goto badreg;
+        s->tm4[tm].control = value & 0x0ff;
+        /* XXX Stop if running (shouldn't happen) */
+        if ((value & (1 << 7)) || tm == 0)
+            s->tm4[tm].freq = pxa2xx_timer4_freq[value & 7];
+        else {
+            s->tm4[tm].freq = 0;
+            pxa2xx_timer_update4(s, qemu_get_clock_ns(vm_clock), tm);
+        }
+        break;
+    case OMCR11: tm ++;
+        /* fall through */
+    case OMCR10: tm ++;
+        /* fall through */
+    case OMCR9:  tm ++;
+        /* fall through */
+    case OMCR8:  tm += 4;
+        if (!pxa2xx_timer_has_tm4(s))
+            goto badreg;
+        s->tm4[tm].control = value & 0x3ff;
+        /* XXX Stop if running (shouldn't happen) */
+        if ((value & (1 << 7)) || !(tm & 1))
+            s->tm4[tm].freq =
+                    pxa2xx_timer4_freq[(value & (1 << 8)) ?  0 : (value & 7)];
+        else {
+            s->tm4[tm].freq = 0;
+            pxa2xx_timer_update4(s, qemu_get_clock_ns(vm_clock), tm);
+        }
+        break;
+    default:
+    badreg:
+        hw_error("pxa2xx_timer_write: Bad offset " REG_FMT "\n", offset);
+    }
+}
+
+static const MemoryRegionOps pxa2xx_timer_ops = {
+    .read = pxa2xx_timer_read,
+    .write = pxa2xx_timer_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void pxa2xx_timer_tick(void *opaque)
+{
+    PXA2xxTimer0 *t = (PXA2xxTimer0 *) opaque;
+    PXA2xxTimerInfo *i = t->info;
+
+    if (i->irq_enabled & (1 << t->num)) {
+        i->events |= 1 << t->num;
+        qemu_irq_raise(t->irq);
+    }
+
+    if (t->num == 3)
+        if (i->reset3 & 1) {
+            i->reset3 = 0;
+            qemu_system_reset_request();
+        }
+}
+
+static void pxa2xx_timer_tick4(void *opaque)
+{
+    PXA2xxTimer4 *t = (PXA2xxTimer4 *) opaque;
+    PXA2xxTimerInfo *i = (PXA2xxTimerInfo *) t->tm.info;
+
+    pxa2xx_timer_tick(&t->tm);
+    if (t->control & (1 << 3))
+        t->clock = 0;
+    if (t->control & (1 << 6))
+        pxa2xx_timer_update4(i, qemu_get_clock_ns(vm_clock), t->tm.num - 4);
+    if (i->events & 0xff0)
+        qemu_irq_raise(i->irq4);
+}
+
+static int pxa25x_timer_post_load(void *opaque, int version_id)
+{
+    PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque;
+    int64_t now;
+    int i;
+
+    now = qemu_get_clock_ns(vm_clock);
+    pxa2xx_timer_update(s, now);
+
+    if (pxa2xx_timer_has_tm4(s))
+        for (i = 0; i < 8; i ++)
+            pxa2xx_timer_update4(s, now, i);
+
+    return 0;
+}
+
+static int pxa2xx_timer_init(SysBusDevice *dev)
+{
+    int i;
+    PXA2xxTimerInfo *s;
+
+    s = FROM_SYSBUS(PXA2xxTimerInfo, dev);
+    s->irq_enabled = 0;
+    s->oldclock = 0;
+    s->clock = 0;
+    s->lastload = qemu_get_clock_ns(vm_clock);
+    s->reset3 = 0;
+
+    for (i = 0; i < 4; i ++) {
+        s->timer[i].value = 0;
+        sysbus_init_irq(dev, &s->timer[i].irq);
+        s->timer[i].info = s;
+        s->timer[i].num = i;
+        s->timer[i].qtimer = qemu_new_timer_ns(vm_clock,
+                        pxa2xx_timer_tick, &s->timer[i]);
+    }
+    if (s->flags & (1 << PXA2XX_TIMER_HAVE_TM4)) {
+        sysbus_init_irq(dev, &s->irq4);
+
+        for (i = 0; i < 8; i ++) {
+            s->tm4[i].tm.value = 0;
+            s->tm4[i].tm.info = s;
+            s->tm4[i].tm.num = i + 4;
+            s->tm4[i].freq = 0;
+            s->tm4[i].control = 0x0;
+            s->tm4[i].tm.qtimer = qemu_new_timer_ns(vm_clock,
+                        pxa2xx_timer_tick4, &s->tm4[i]);
+        }
+    }
+
+    memory_region_init_io(&s->iomem, &pxa2xx_timer_ops, s,
+                          "pxa2xx-timer", 0x00001000);
+    sysbus_init_mmio(dev, &s->iomem);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_pxa2xx_timer0_regs = {
+    .name = "pxa2xx_timer0",
+    .version_id = 2,
+    .minimum_version_id = 2,
+    .minimum_version_id_old = 2,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(value, PXA2xxTimer0),
+        VMSTATE_END_OF_LIST(),
+    },
+};
+
+static const VMStateDescription vmstate_pxa2xx_timer4_regs = {
+    .name = "pxa2xx_timer4",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_STRUCT(tm, PXA2xxTimer4, 1,
+                        vmstate_pxa2xx_timer0_regs, PXA2xxTimer0),
+        VMSTATE_INT32(oldclock, PXA2xxTimer4),
+        VMSTATE_INT32(clock, PXA2xxTimer4),
+        VMSTATE_UINT64(lastload, PXA2xxTimer4),
+        VMSTATE_UINT32(freq, PXA2xxTimer4),
+        VMSTATE_UINT32(control, PXA2xxTimer4),
+        VMSTATE_END_OF_LIST(),
+    },
+};
+
+static bool pxa2xx_timer_has_tm4_test(void *opaque, int version_id)
+{
+    return pxa2xx_timer_has_tm4(opaque);
+}
+
+static const VMStateDescription vmstate_pxa2xx_timer_regs = {
+    .name = "pxa2xx_timer",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .post_load = pxa25x_timer_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_INT32(clock, PXA2xxTimerInfo),
+        VMSTATE_INT32(oldclock, PXA2xxTimerInfo),
+        VMSTATE_UINT64(lastload, PXA2xxTimerInfo),
+        VMSTATE_STRUCT_ARRAY(timer, PXA2xxTimerInfo, 4, 1,
+                        vmstate_pxa2xx_timer0_regs, PXA2xxTimer0),
+        VMSTATE_UINT32(events, PXA2xxTimerInfo),
+        VMSTATE_UINT32(irq_enabled, PXA2xxTimerInfo),
+        VMSTATE_UINT32(reset3, PXA2xxTimerInfo),
+        VMSTATE_UINT32(snapshot, PXA2xxTimerInfo),
+        VMSTATE_STRUCT_ARRAY_TEST(tm4, PXA2xxTimerInfo, 8,
+                        pxa2xx_timer_has_tm4_test, 0,
+                        vmstate_pxa2xx_timer4_regs, PXA2xxTimer4),
+        VMSTATE_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 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 const TypeInfo pxa25x_timer_dev_info = {
+    .name          = "pxa25x-timer",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(PXA2xxTimerInfo),
+    .class_init    = pxa25x_timer_dev_class_init,
+};
+
+static Property pxa27x_timer_dev_properties[] = {
+    DEFINE_PROP_UINT32("freq", PXA2xxTimerInfo, freq, PXA27X_FREQ),
+    DEFINE_PROP_BIT("tm4", PXA2xxTimerInfo, flags,
+    PXA2XX_TIMER_HAVE_TM4, true),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void pxa27x_timer_dev_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = pxa2xx_timer_init;
+    dc->desc = "PXA27x timer";
+    dc->vmsd = &vmstate_pxa2xx_timer_regs;
+    dc->props = pxa27x_timer_dev_properties;
+}
+
+static const 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_types(void)
+{
+    type_register_static(&pxa25x_timer_dev_info);
+    type_register_static(&pxa27x_timer_dev_info);
+}
+
+type_init(pxa2xx_timer_register_types)
diff --git a/hw/timer/sh_timer.c b/hw/timer/sh_timer.c
new file mode 100644 (file)
index 0000000..f92ff4f
--- /dev/null
@@ -0,0 +1,333 @@
+/*
+ * SuperH Timer modules.
+ *
+ * Copyright (c) 2007 Magnus Damm
+ * Based on arm_timer.c by Paul Brook
+ * Copyright (c) 2005-2006 CodeSourcery.
+ *
+ * This code is licensed under the GPL.
+ */
+
+#include "hw/hw.h"
+#include "hw/sh4/sh.h"
+#include "qemu/timer.h"
+#include "exec/address-spaces.h"
+#include "hw/ptimer.h"
+
+//#define DEBUG_TIMER
+
+#define TIMER_TCR_TPSC          (7 << 0)
+#define TIMER_TCR_CKEG          (3 << 3)
+#define TIMER_TCR_UNIE          (1 << 5)
+#define TIMER_TCR_ICPE          (3 << 6)
+#define TIMER_TCR_UNF           (1 << 8)
+#define TIMER_TCR_ICPF          (1 << 9)
+#define TIMER_TCR_RESERVED      (0x3f << 10)
+
+#define TIMER_FEAT_CAPT   (1 << 0)
+#define TIMER_FEAT_EXTCLK (1 << 1)
+
+#define OFFSET_TCOR   0
+#define OFFSET_TCNT   1
+#define OFFSET_TCR    2
+#define OFFSET_TCPR   3
+
+typedef struct {
+    ptimer_state *timer;
+    uint32_t tcnt;
+    uint32_t tcor;
+    uint32_t tcr;
+    uint32_t tcpr;
+    int freq;
+    int int_level;
+    int old_level;
+    int feat;
+    int enabled;
+    qemu_irq irq;
+} sh_timer_state;
+
+/* Check all active timers, and schedule the next timer interrupt. */
+
+static void sh_timer_update(sh_timer_state *s)
+{
+    int new_level = s->int_level && (s->tcr & TIMER_TCR_UNIE);
+
+    if (new_level != s->old_level)
+      qemu_set_irq (s->irq, new_level);
+
+    s->old_level = s->int_level;
+    s->int_level = new_level;
+}
+
+static uint32_t sh_timer_read(void *opaque, hwaddr offset)
+{
+    sh_timer_state *s = (sh_timer_state *)opaque;
+
+    switch (offset >> 2) {
+    case OFFSET_TCOR:
+        return s->tcor;
+    case OFFSET_TCNT:
+        return ptimer_get_count(s->timer);
+    case OFFSET_TCR:
+        return s->tcr | (s->int_level ? TIMER_TCR_UNF : 0);
+    case OFFSET_TCPR:
+        if (s->feat & TIMER_FEAT_CAPT)
+            return s->tcpr;
+    default:
+        hw_error("sh_timer_read: Bad offset %x\n", (int)offset);
+        return 0;
+    }
+}
+
+static void sh_timer_write(void *opaque, hwaddr offset,
+                            uint32_t value)
+{
+    sh_timer_state *s = (sh_timer_state *)opaque;
+    int freq;
+
+    switch (offset >> 2) {
+    case OFFSET_TCOR:
+        s->tcor = value;
+        ptimer_set_limit(s->timer, s->tcor, 0);
+        break;
+    case OFFSET_TCNT:
+        s->tcnt = value;
+        ptimer_set_count(s->timer, s->tcnt);
+        break;
+    case OFFSET_TCR:
+        if (s->enabled) {
+            /* Pause the timer if it is running.  This may cause some
+               inaccuracy dure to rounding, but avoids a whole lot of other
+               messyness.  */
+            ptimer_stop(s->timer);
+        }
+        freq = s->freq;
+        /* ??? Need to recalculate expiry time after changing divisor.  */
+        switch (value & TIMER_TCR_TPSC) {
+        case 0: freq >>= 2; break;
+        case 1: freq >>= 4; break;
+        case 2: freq >>= 6; break;
+        case 3: freq >>= 8; break;
+        case 4: freq >>= 10; break;
+       case 6:
+       case 7: if (s->feat & TIMER_FEAT_EXTCLK) break;
+       default: hw_error("sh_timer_write: Reserved TPSC value\n"); break;
+        }
+        switch ((value & TIMER_TCR_CKEG) >> 3) {
+       case 0: break;
+        case 1:
+        case 2:
+        case 3: if (s->feat & TIMER_FEAT_EXTCLK) break;
+       default: hw_error("sh_timer_write: Reserved CKEG value\n"); break;
+        }
+        switch ((value & TIMER_TCR_ICPE) >> 6) {
+       case 0: break;
+        case 2:
+        case 3: if (s->feat & TIMER_FEAT_CAPT) break;
+       default: hw_error("sh_timer_write: Reserved ICPE value\n"); break;
+        }
+       if ((value & TIMER_TCR_UNF) == 0)
+            s->int_level = 0;
+
+       value &= ~TIMER_TCR_UNF;
+
+       if ((value & TIMER_TCR_ICPF) && (!(s->feat & TIMER_FEAT_CAPT)))
+            hw_error("sh_timer_write: Reserved ICPF value\n");
+
+       value &= ~TIMER_TCR_ICPF; /* capture not supported */
+
+       if (value & TIMER_TCR_RESERVED)
+            hw_error("sh_timer_write: Reserved TCR bits set\n");
+        s->tcr = value;
+        ptimer_set_limit(s->timer, s->tcor, 0);
+        ptimer_set_freq(s->timer, freq);
+        if (s->enabled) {
+            /* Restart the timer if still enabled.  */
+            ptimer_run(s->timer, 0);
+        }
+        break;
+    case OFFSET_TCPR:
+        if (s->feat & TIMER_FEAT_CAPT) {
+            s->tcpr = value;
+           break;
+       }
+    default:
+        hw_error("sh_timer_write: Bad offset %x\n", (int)offset);
+    }
+    sh_timer_update(s);
+}
+
+static void sh_timer_start_stop(void *opaque, int enable)
+{
+    sh_timer_state *s = (sh_timer_state *)opaque;
+
+#ifdef DEBUG_TIMER
+    printf("sh_timer_start_stop %d (%d)\n", enable, s->enabled);
+#endif
+
+    if (s->enabled && !enable) {
+        ptimer_stop(s->timer);
+    }
+    if (!s->enabled && enable) {
+        ptimer_run(s->timer, 0);
+    }
+    s->enabled = !!enable;
+
+#ifdef DEBUG_TIMER
+    printf("sh_timer_start_stop done %d\n", s->enabled);
+#endif
+}
+
+static void sh_timer_tick(void *opaque)
+{
+    sh_timer_state *s = (sh_timer_state *)opaque;
+    s->int_level = s->enabled;
+    sh_timer_update(s);
+}
+
+static void *sh_timer_init(uint32_t freq, int feat, qemu_irq irq)
+{
+    sh_timer_state *s;
+    QEMUBH *bh;
+
+    s = (sh_timer_state *)g_malloc0(sizeof(sh_timer_state));
+    s->freq = freq;
+    s->feat = feat;
+    s->tcor = 0xffffffff;
+    s->tcnt = 0xffffffff;
+    s->tcpr = 0xdeadbeef;
+    s->tcr = 0;
+    s->enabled = 0;
+    s->irq = irq;
+
+    bh = qemu_bh_new(sh_timer_tick, s);
+    s->timer = ptimer_init(bh);
+
+    sh_timer_write(s, OFFSET_TCOR >> 2, s->tcor);
+    sh_timer_write(s, OFFSET_TCNT >> 2, s->tcnt);
+    sh_timer_write(s, OFFSET_TCPR >> 2, s->tcpr);
+    sh_timer_write(s, OFFSET_TCR  >> 2, s->tcpr);
+    /* ??? Save/restore.  */
+    return s;
+}
+
+typedef struct {
+    MemoryRegion iomem;
+    MemoryRegion iomem_p4;
+    MemoryRegion iomem_a7;
+    void *timer[3];
+    int level[3];
+    uint32_t tocr;
+    uint32_t tstr;
+    int feat;
+} tmu012_state;
+
+static uint64_t tmu012_read(void *opaque, hwaddr offset,
+                            unsigned size)
+{
+    tmu012_state *s = (tmu012_state *)opaque;
+
+#ifdef DEBUG_TIMER
+    printf("tmu012_read 0x%lx\n", (unsigned long) offset);
+#endif
+
+    if (offset >= 0x20) {
+        if (!(s->feat & TMU012_FEAT_3CHAN))
+           hw_error("tmu012_write: Bad channel offset %x\n", (int)offset);
+        return sh_timer_read(s->timer[2], offset - 0x20);
+    }
+
+    if (offset >= 0x14)
+        return sh_timer_read(s->timer[1], offset - 0x14);
+
+    if (offset >= 0x08)
+        return sh_timer_read(s->timer[0], offset - 0x08);
+
+    if (offset == 4)
+        return s->tstr;
+
+    if ((s->feat & TMU012_FEAT_TOCR) && offset == 0)
+        return s->tocr;
+
+    hw_error("tmu012_write: Bad offset %x\n", (int)offset);
+    return 0;
+}
+
+static void tmu012_write(void *opaque, hwaddr offset,
+                        uint64_t value, unsigned size)
+{
+    tmu012_state *s = (tmu012_state *)opaque;
+
+#ifdef DEBUG_TIMER
+    printf("tmu012_write 0x%lx 0x%08x\n", (unsigned long) offset, value);
+#endif
+
+    if (offset >= 0x20) {
+        if (!(s->feat & TMU012_FEAT_3CHAN))
+           hw_error("tmu012_write: Bad channel offset %x\n", (int)offset);
+        sh_timer_write(s->timer[2], offset - 0x20, value);
+       return;
+    }
+
+    if (offset >= 0x14) {
+        sh_timer_write(s->timer[1], offset - 0x14, value);
+       return;
+    }
+
+    if (offset >= 0x08) {
+        sh_timer_write(s->timer[0], offset - 0x08, value);
+       return;
+    }
+
+    if (offset == 4) {
+        sh_timer_start_stop(s->timer[0], value & (1 << 0));
+        sh_timer_start_stop(s->timer[1], value & (1 << 1));
+        if (s->feat & TMU012_FEAT_3CHAN)
+            sh_timer_start_stop(s->timer[2], value & (1 << 2));
+       else
+            if (value & (1 << 2))
+                hw_error("tmu012_write: Bad channel\n");
+
+       s->tstr = value;
+       return;
+    }
+
+    if ((s->feat & TMU012_FEAT_TOCR) && offset == 0) {
+        s->tocr = value & (1 << 0);
+    }
+}
+
+static const MemoryRegionOps tmu012_ops = {
+    .read = tmu012_read,
+    .write = tmu012_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+void tmu012_init(MemoryRegion *sysmem, hwaddr base,
+                 int feat, uint32_t freq,
+                qemu_irq ch0_irq, qemu_irq ch1_irq,
+                qemu_irq ch2_irq0, qemu_irq ch2_irq1)
+{
+    tmu012_state *s;
+    int timer_feat = (feat & TMU012_FEAT_EXTCLK) ? TIMER_FEAT_EXTCLK : 0;
+
+    s = (tmu012_state *)g_malloc0(sizeof(tmu012_state));
+    s->feat = feat;
+    s->timer[0] = sh_timer_init(freq, timer_feat, ch0_irq);
+    s->timer[1] = sh_timer_init(freq, timer_feat, ch1_irq);
+    if (feat & TMU012_FEAT_3CHAN)
+        s->timer[2] = sh_timer_init(freq, timer_feat | TIMER_FEAT_CAPT,
+                                   ch2_irq0); /* ch2_irq1 not supported */
+
+    memory_region_init_io(&s->iomem, &tmu012_ops, s,
+                          "timer", 0x100000000ULL);
+
+    memory_region_init_alias(&s->iomem_p4, "timer-p4",
+                             &s->iomem, 0, 0x1000);
+    memory_region_add_subregion(sysmem, P4ADDR(base), &s->iomem_p4);
+
+    memory_region_init_alias(&s->iomem_a7, "timer-a7",
+                             &s->iomem, 0, 0x1000);
+    memory_region_add_subregion(sysmem, A7ADDR(base), &s->iomem_a7);
+    /* ??? Save/restore.  */
+}
diff --git a/hw/timer/slavio_timer.c b/hw/timer/slavio_timer.c
new file mode 100644 (file)
index 0000000..1145a87
--- /dev/null
@@ -0,0 +1,435 @@
+/*
+ * QEMU Sparc SLAVIO timer controller emulation
+ *
+ * Copyright (c) 2003-2005 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.
+ */
+
+#include "hw/sparc/sun4m.h"
+#include "qemu/timer.h"
+#include "hw/ptimer.h"
+#include "hw/sysbus.h"
+#include "trace.h"
+
+/*
+ * Registers of hardware timer in sun4m.
+ *
+ * This is the timer/counter part of chip STP2001 (Slave I/O), also
+ * produced as NCR89C105. See
+ * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
+ *
+ * The 31-bit counter is incremented every 500ns by bit 9. Bits 8..0
+ * are zero. Bit 31 is 1 when count has been reached.
+ *
+ * Per-CPU timers interrupt local CPU, system timer uses normal
+ * interrupt routing.
+ *
+ */
+
+#define MAX_CPUS 16
+
+typedef struct CPUTimerState {
+    qemu_irq irq;
+    ptimer_state *timer;
+    uint32_t count, counthigh, reached;
+    /* processor only */
+    uint32_t running;
+    uint64_t limit;
+} CPUTimerState;
+
+typedef struct SLAVIO_TIMERState {
+    SysBusDevice busdev;
+    uint32_t num_cpus;
+    uint32_t cputimer_mode;
+    CPUTimerState cputimer[MAX_CPUS + 1];
+} SLAVIO_TIMERState;
+
+typedef struct TimerContext {
+    MemoryRegion iomem;
+    SLAVIO_TIMERState *s;
+    unsigned int timer_index; /* 0 for system, 1 ... MAX_CPUS for CPU timers */
+} TimerContext;
+
+#define SYS_TIMER_SIZE 0x14
+#define CPU_TIMER_SIZE 0x10
+
+#define TIMER_LIMIT         0
+#define TIMER_COUNTER       1
+#define TIMER_COUNTER_NORST 2
+#define TIMER_STATUS        3
+#define TIMER_MODE          4
+
+#define TIMER_COUNT_MASK32 0xfffffe00
+#define TIMER_LIMIT_MASK32 0x7fffffff
+#define TIMER_MAX_COUNT64  0x7ffffffffffffe00ULL
+#define TIMER_MAX_COUNT32  0x7ffffe00ULL
+#define TIMER_REACHED      0x80000000
+#define TIMER_PERIOD       500ULL // 500ns
+#define LIMIT_TO_PERIODS(l) (((l) >> 9) - 1)
+#define PERIODS_TO_LIMIT(l) (((l) + 1) << 9)
+
+static int slavio_timer_is_user(TimerContext *tc)
+{
+    SLAVIO_TIMERState *s = tc->s;
+    unsigned int timer_index = tc->timer_index;
+
+    return timer_index != 0 && (s->cputimer_mode & (1 << (timer_index - 1)));
+}
+
+// Update count, set irq, update expire_time
+// Convert from ptimer countdown units
+static void slavio_timer_get_out(CPUTimerState *t)
+{
+    uint64_t count, limit;
+
+    if (t->limit == 0) { /* free-run system or processor counter */
+        limit = TIMER_MAX_COUNT32;
+    } else {
+        limit = t->limit;
+    }
+    count = limit - PERIODS_TO_LIMIT(ptimer_get_count(t->timer));
+
+    trace_slavio_timer_get_out(t->limit, t->counthigh, t->count);
+    t->count = count & TIMER_COUNT_MASK32;
+    t->counthigh = count >> 32;
+}
+
+// timer callback
+static void slavio_timer_irq(void *opaque)
+{
+    TimerContext *tc = opaque;
+    SLAVIO_TIMERState *s = tc->s;
+    CPUTimerState *t = &s->cputimer[tc->timer_index];
+
+    slavio_timer_get_out(t);
+    trace_slavio_timer_irq(t->counthigh, t->count);
+    /* if limit is 0 (free-run), there will be no match */
+    if (t->limit != 0) {
+        t->reached = TIMER_REACHED;
+    }
+    /* there is no interrupt if user timer or free-run */
+    if (!slavio_timer_is_user(tc) && t->limit != 0) {
+        qemu_irq_raise(t->irq);
+    }
+}
+
+static uint64_t slavio_timer_mem_readl(void *opaque, hwaddr addr,
+                                       unsigned size)
+{
+    TimerContext *tc = opaque;
+    SLAVIO_TIMERState *s = tc->s;
+    uint32_t saddr, ret;
+    unsigned int timer_index = tc->timer_index;
+    CPUTimerState *t = &s->cputimer[timer_index];
+
+    saddr = addr >> 2;
+    switch (saddr) {
+    case TIMER_LIMIT:
+        // read limit (system counter mode) or read most signifying
+        // part of counter (user mode)
+        if (slavio_timer_is_user(tc)) {
+            // read user timer MSW
+            slavio_timer_get_out(t);
+            ret = t->counthigh | t->reached;
+        } else {
+            // read limit
+            // clear irq
+            qemu_irq_lower(t->irq);
+            t->reached = 0;
+            ret = t->limit & TIMER_LIMIT_MASK32;
+        }
+        break;
+    case TIMER_COUNTER:
+        // read counter and reached bit (system mode) or read lsbits
+        // of counter (user mode)
+        slavio_timer_get_out(t);
+        if (slavio_timer_is_user(tc)) { // read user timer LSW
+            ret = t->count & TIMER_MAX_COUNT64;
+        } else { // read limit
+            ret = (t->count & TIMER_MAX_COUNT32) |
+                t->reached;
+        }
+        break;
+    case TIMER_STATUS:
+        // only available in processor counter/timer
+        // read start/stop status
+        if (timer_index > 0) {
+            ret = t->running;
+        } else {
+            ret = 0;
+        }
+        break;
+    case TIMER_MODE:
+        // only available in system counter
+        // read user/system mode
+        ret = s->cputimer_mode;
+        break;
+    default:
+        trace_slavio_timer_mem_readl_invalid(addr);
+        ret = 0;
+        break;
+    }
+    trace_slavio_timer_mem_readl(addr, ret);
+    return ret;
+}
+
+static void slavio_timer_mem_writel(void *opaque, hwaddr addr,
+                                    uint64_t val, unsigned size)
+{
+    TimerContext *tc = opaque;
+    SLAVIO_TIMERState *s = tc->s;
+    uint32_t saddr;
+    unsigned int timer_index = tc->timer_index;
+    CPUTimerState *t = &s->cputimer[timer_index];
+
+    trace_slavio_timer_mem_writel(addr, val);
+    saddr = addr >> 2;
+    switch (saddr) {
+    case TIMER_LIMIT:
+        if (slavio_timer_is_user(tc)) {
+            uint64_t count;
+
+            // set user counter MSW, reset counter
+            t->limit = TIMER_MAX_COUNT64;
+            t->counthigh = val & (TIMER_MAX_COUNT64 >> 32);
+            t->reached = 0;
+            count = ((uint64_t)t->counthigh << 32) | t->count;
+            trace_slavio_timer_mem_writel_limit(timer_index, count);
+            ptimer_set_count(t->timer, LIMIT_TO_PERIODS(t->limit - count));
+        } else {
+            // set limit, reset counter
+            qemu_irq_lower(t->irq);
+            t->limit = val & TIMER_MAX_COUNT32;
+            if (t->timer) {
+                if (t->limit == 0) { /* free-run */
+                    ptimer_set_limit(t->timer,
+                                     LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 1);
+                } else {
+                    ptimer_set_limit(t->timer, LIMIT_TO_PERIODS(t->limit), 1);
+                }
+            }
+        }
+        break;
+    case TIMER_COUNTER:
+        if (slavio_timer_is_user(tc)) {
+            uint64_t count;
+
+            // set user counter LSW, reset counter
+            t->limit = TIMER_MAX_COUNT64;
+            t->count = val & TIMER_MAX_COUNT64;
+            t->reached = 0;
+            count = ((uint64_t)t->counthigh) << 32 | t->count;
+            trace_slavio_timer_mem_writel_limit(timer_index, count);
+            ptimer_set_count(t->timer, LIMIT_TO_PERIODS(t->limit - count));
+        } else {
+            trace_slavio_timer_mem_writel_counter_invalid();
+        }
+        break;
+    case TIMER_COUNTER_NORST:
+        // set limit without resetting counter
+        t->limit = val & TIMER_MAX_COUNT32;
+        if (t->limit == 0) { /* free-run */
+            ptimer_set_limit(t->timer, LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 0);
+        } else {
+            ptimer_set_limit(t->timer, LIMIT_TO_PERIODS(t->limit), 0);
+        }
+        break;
+    case TIMER_STATUS:
+        if (slavio_timer_is_user(tc)) {
+            // start/stop user counter
+            if ((val & 1) && !t->running) {
+                trace_slavio_timer_mem_writel_status_start(timer_index);
+                ptimer_run(t->timer, 0);
+                t->running = 1;
+            } else if (!(val & 1) && t->running) {
+                trace_slavio_timer_mem_writel_status_stop(timer_index);
+                ptimer_stop(t->timer);
+                t->running = 0;
+            }
+        }
+        break;
+    case TIMER_MODE:
+        if (timer_index == 0) {
+            unsigned int i;
+
+            for (i = 0; i < s->num_cpus; i++) {
+                unsigned int processor = 1 << i;
+                CPUTimerState *curr_timer = &s->cputimer[i + 1];
+
+                // check for a change in timer mode for this processor
+                if ((val & processor) != (s->cputimer_mode & processor)) {
+                    if (val & processor) { // counter -> user timer
+                        qemu_irq_lower(curr_timer->irq);
+                        // counters are always running
+                        ptimer_stop(curr_timer->timer);
+                        curr_timer->running = 0;
+                        // user timer limit is always the same
+                        curr_timer->limit = TIMER_MAX_COUNT64;
+                        ptimer_set_limit(curr_timer->timer,
+                                         LIMIT_TO_PERIODS(curr_timer->limit),
+                                         1);
+                        // set this processors user timer bit in config
+                        // register
+                        s->cputimer_mode |= processor;
+                        trace_slavio_timer_mem_writel_mode_user(timer_index);
+                    } else { // user timer -> counter
+                        // stop the user timer if it is running
+                        if (curr_timer->running) {
+                            ptimer_stop(curr_timer->timer);
+                        }
+                        // start the counter
+                        ptimer_run(curr_timer->timer, 0);
+                        curr_timer->running = 1;
+                        // clear this processors user timer bit in config
+                        // register
+                        s->cputimer_mode &= ~processor;
+                        trace_slavio_timer_mem_writel_mode_counter(timer_index);
+                    }
+                }
+            }
+        } else {
+            trace_slavio_timer_mem_writel_mode_invalid();
+        }
+        break;
+    default:
+        trace_slavio_timer_mem_writel_invalid(addr);
+        break;
+    }
+}
+
+static const MemoryRegionOps slavio_timer_mem_ops = {
+    .read = slavio_timer_mem_readl,
+    .write = slavio_timer_mem_writel,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static const VMStateDescription vmstate_timer = {
+    .name ="timer",
+    .version_id = 3,
+    .minimum_version_id = 3,
+    .minimum_version_id_old = 3,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT64(limit, CPUTimerState),
+        VMSTATE_UINT32(count, CPUTimerState),
+        VMSTATE_UINT32(counthigh, CPUTimerState),
+        VMSTATE_UINT32(reached, CPUTimerState),
+        VMSTATE_UINT32(running, CPUTimerState),
+        VMSTATE_PTIMER(timer, CPUTimerState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_slavio_timer = {
+    .name ="slavio_timer",
+    .version_id = 3,
+    .minimum_version_id = 3,
+    .minimum_version_id_old = 3,
+    .fields      = (VMStateField []) {
+        VMSTATE_STRUCT_ARRAY(cputimer, SLAVIO_TIMERState, MAX_CPUS + 1, 3,
+                             vmstate_timer, CPUTimerState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void slavio_timer_reset(DeviceState *d)
+{
+    SLAVIO_TIMERState *s = container_of(d, SLAVIO_TIMERState, busdev.qdev);
+    unsigned int i;
+    CPUTimerState *curr_timer;
+
+    for (i = 0; i <= MAX_CPUS; i++) {
+        curr_timer = &s->cputimer[i];
+        curr_timer->limit = 0;
+        curr_timer->count = 0;
+        curr_timer->reached = 0;
+        if (i <= s->num_cpus) {
+            ptimer_set_limit(curr_timer->timer,
+                             LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 1);
+            ptimer_run(curr_timer->timer, 0);
+            curr_timer->running = 1;
+        }
+    }
+    s->cputimer_mode = 0;
+}
+
+static int slavio_timer_init1(SysBusDevice *dev)
+{
+    SLAVIO_TIMERState *s = FROM_SYSBUS(SLAVIO_TIMERState, dev);
+    QEMUBH *bh;
+    unsigned int i;
+    TimerContext *tc;
+
+    for (i = 0; i <= MAX_CPUS; i++) {
+        uint64_t size;
+        char timer_name[20];
+
+        tc = g_malloc0(sizeof(TimerContext));
+        tc->s = s;
+        tc->timer_index = i;
+
+        bh = qemu_bh_new(slavio_timer_irq, tc);
+        s->cputimer[i].timer = ptimer_init(bh);
+        ptimer_set_period(s->cputimer[i].timer, TIMER_PERIOD);
+
+        size = i == 0 ? SYS_TIMER_SIZE : CPU_TIMER_SIZE;
+        snprintf(timer_name, sizeof(timer_name), "timer-%i", i);
+        memory_region_init_io(&tc->iomem, &slavio_timer_mem_ops, tc,
+                              timer_name, size);
+        sysbus_init_mmio(dev, &tc->iomem);
+
+        sysbus_init_irq(dev, &s->cputimer[i].irq);
+    }
+
+    return 0;
+}
+
+static Property slavio_timer_properties[] = {
+    DEFINE_PROP_UINT32("num_cpus",  SLAVIO_TIMERState, num_cpus,  0),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void slavio_timer_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = slavio_timer_init1;
+    dc->reset = slavio_timer_reset;
+    dc->vmsd = &vmstate_slavio_timer;
+    dc->props = slavio_timer_properties;
+}
+
+static const 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_types(void)
+{
+    type_register_static(&slavio_timer_info);
+}
+
+type_init(slavio_timer_register_types)
diff --git a/hw/timer/tusb6010.c b/hw/timer/tusb6010.c
new file mode 100644 (file)
index 0000000..533938a
--- /dev/null
@@ -0,0 +1,813 @@
+/*
+ * Texas Instruments TUSB6010 emulation.
+ * Based on reverse-engineering of a linux driver.
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ * Written by Andrzej Zaborowski <andrew@openedhand.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 or
+ * (at your option) version 3 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
+ * 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 "qemu/timer.h"
+#include "hw/usb.h"
+#include "hw/arm/omap.h"
+#include "hw/irq.h"
+#include "hw/arm/devices.h"
+#include "hw/sysbus.h"
+
+typedef struct TUSBState {
+    SysBusDevice busdev;
+    MemoryRegion iomem[2];
+    qemu_irq irq;
+    MUSBState *musb;
+    QEMUTimer *otg_timer;
+    QEMUTimer *pwr_timer;
+
+    int power;
+    uint32_t scratch;
+    uint16_t test_reset;
+    uint32_t prcm_config;
+    uint32_t prcm_mngmt;
+    uint16_t otg_status;
+    uint32_t dev_config;
+    int host_mode;
+    uint32_t intr;
+    uint32_t intr_ok;
+    uint32_t mask;
+    uint32_t usbip_intr;
+    uint32_t usbip_mask;
+    uint32_t gpio_intr;
+    uint32_t gpio_mask;
+    uint32_t gpio_config;
+    uint32_t dma_intr;
+    uint32_t dma_mask;
+    uint32_t dma_map;
+    uint32_t dma_config;
+    uint32_t ep0_config;
+    uint32_t rx_config[15];
+    uint32_t tx_config[15];
+    uint32_t wkup_mask;
+    uint32_t pullup[2];
+    uint32_t control_config;
+    uint32_t otg_timer_val;
+} TUSBState;
+
+#define TUSB_DEVCLOCK                  60000000        /* 60 MHz */
+
+#define TUSB_VLYNQ_CTRL                        0x004
+
+/* Mentor Graphics OTG core registers.  */
+#define TUSB_BASE_OFFSET               0x400
+
+/* FIFO registers, 32-bit.  */
+#define TUSB_FIFO_BASE                 0x600
+
+/* Device System & Control registers, 32-bit.  */
+#define TUSB_SYS_REG_BASE              0x800
+
+#define TUSB_DEV_CONF                  (TUSB_SYS_REG_BASE + 0x000)
+#define        TUSB_DEV_CONF_USB_HOST_MODE     (1 << 16)
+#define        TUSB_DEV_CONF_PROD_TEST_MODE    (1 << 15)
+#define        TUSB_DEV_CONF_SOFT_ID           (1 << 1)
+#define        TUSB_DEV_CONF_ID_SEL            (1 << 0)
+
+#define TUSB_PHY_OTG_CTRL_ENABLE       (TUSB_SYS_REG_BASE + 0x004)
+#define TUSB_PHY_OTG_CTRL              (TUSB_SYS_REG_BASE + 0x008)
+#define        TUSB_PHY_OTG_CTRL_WRPROTECT     (0xa5 << 24)
+#define        TUSB_PHY_OTG_CTRL_O_ID_PULLUP   (1 << 23)
+#define        TUSB_PHY_OTG_CTRL_O_VBUS_DET_EN (1 << 19)
+#define        TUSB_PHY_OTG_CTRL_O_SESS_END_EN (1 << 18)
+#define        TUSB_PHY_OTG_CTRL_TESTM2        (1 << 17)
+#define        TUSB_PHY_OTG_CTRL_TESTM1        (1 << 16)
+#define        TUSB_PHY_OTG_CTRL_TESTM0        (1 << 15)
+#define        TUSB_PHY_OTG_CTRL_TX_DATA2      (1 << 14)
+#define        TUSB_PHY_OTG_CTRL_TX_GZ2        (1 << 13)
+#define        TUSB_PHY_OTG_CTRL_TX_ENABLE2    (1 << 12)
+#define        TUSB_PHY_OTG_CTRL_DM_PULLDOWN   (1 << 11)
+#define        TUSB_PHY_OTG_CTRL_DP_PULLDOWN   (1 << 10)
+#define        TUSB_PHY_OTG_CTRL_OSC_EN        (1 << 9)
+#define        TUSB_PHY_OTG_CTRL_PHYREF_CLK(v) (((v) & 3) << 7)
+#define        TUSB_PHY_OTG_CTRL_PD            (1 << 6)
+#define        TUSB_PHY_OTG_CTRL_PLL_ON        (1 << 5)
+#define        TUSB_PHY_OTG_CTRL_EXT_RPU       (1 << 4)
+#define        TUSB_PHY_OTG_CTRL_PWR_GOOD      (1 << 3)
+#define        TUSB_PHY_OTG_CTRL_RESET         (1 << 2)
+#define        TUSB_PHY_OTG_CTRL_SUSPENDM      (1 << 1)
+#define        TUSB_PHY_OTG_CTRL_CLK_MODE      (1 << 0)
+
+/* OTG status register */
+#define TUSB_DEV_OTG_STAT              (TUSB_SYS_REG_BASE + 0x00c)
+#define        TUSB_DEV_OTG_STAT_PWR_CLK_GOOD  (1 << 8)
+#define        TUSB_DEV_OTG_STAT_SESS_END      (1 << 7)
+#define        TUSB_DEV_OTG_STAT_SESS_VALID    (1 << 6)
+#define        TUSB_DEV_OTG_STAT_VBUS_VALID    (1 << 5)
+#define        TUSB_DEV_OTG_STAT_VBUS_SENSE    (1 << 4)
+#define        TUSB_DEV_OTG_STAT_ID_STATUS     (1 << 3)
+#define        TUSB_DEV_OTG_STAT_HOST_DISCON   (1 << 2)
+#define        TUSB_DEV_OTG_STAT_LINE_STATE    (3 << 0)
+#define        TUSB_DEV_OTG_STAT_DP_ENABLE     (1 << 1)
+#define        TUSB_DEV_OTG_STAT_DM_ENABLE     (1 << 0)
+
+#define TUSB_DEV_OTG_TIMER             (TUSB_SYS_REG_BASE + 0x010)
+#define TUSB_DEV_OTG_TIMER_ENABLE      (1 << 31)
+#define TUSB_DEV_OTG_TIMER_VAL(v)      ((v) & 0x07ffffff)
+#define TUSB_PRCM_REV                  (TUSB_SYS_REG_BASE + 0x014)
+
+/* PRCM configuration register */
+#define TUSB_PRCM_CONF                 (TUSB_SYS_REG_BASE + 0x018)
+#define        TUSB_PRCM_CONF_SFW_CPEN         (1 << 24)
+#define        TUSB_PRCM_CONF_SYS_CLKSEL(v)    (((v) & 3) << 16)
+
+/* PRCM management register */
+#define TUSB_PRCM_MNGMT                        (TUSB_SYS_REG_BASE + 0x01c)
+#define        TUSB_PRCM_MNGMT_SRP_FIX_TMR(v)  (((v) & 0xf) << 25)
+#define        TUSB_PRCM_MNGMT_SRP_FIX_EN      (1 << 24)
+#define        TUSB_PRCM_MNGMT_VBUS_VAL_TMR(v) (((v) & 0xf) << 20)
+#define        TUSB_PRCM_MNGMT_VBUS_VAL_FLT_EN (1 << 19)
+#define        TUSB_PRCM_MNGMT_DFT_CLK_DIS     (1 << 18)
+#define        TUSB_PRCM_MNGMT_VLYNQ_CLK_DIS   (1 << 17)
+#define        TUSB_PRCM_MNGMT_OTG_SESS_END_EN (1 << 10)
+#define        TUSB_PRCM_MNGMT_OTG_VBUS_DET_EN (1 << 9)
+#define        TUSB_PRCM_MNGMT_OTG_ID_PULLUP   (1 << 8)
+#define        TUSB_PRCM_MNGMT_15_SW_EN        (1 << 4)
+#define        TUSB_PRCM_MNGMT_33_SW_EN        (1 << 3)
+#define        TUSB_PRCM_MNGMT_5V_CPEN         (1 << 2)
+#define        TUSB_PRCM_MNGMT_PM_IDLE         (1 << 1)
+#define        TUSB_PRCM_MNGMT_DEV_IDLE        (1 << 0)
+
+/* Wake-up source clear and mask registers */
+#define TUSB_PRCM_WAKEUP_SOURCE                (TUSB_SYS_REG_BASE + 0x020)
+#define TUSB_PRCM_WAKEUP_CLEAR         (TUSB_SYS_REG_BASE + 0x028)
+#define TUSB_PRCM_WAKEUP_MASK          (TUSB_SYS_REG_BASE + 0x02c)
+#define        TUSB_PRCM_WAKEUP_RESERVED_BITS  (0xffffe << 13)
+#define        TUSB_PRCM_WGPIO_7               (1 << 12)
+#define        TUSB_PRCM_WGPIO_6               (1 << 11)
+#define        TUSB_PRCM_WGPIO_5               (1 << 10)
+#define        TUSB_PRCM_WGPIO_4               (1 << 9)
+#define        TUSB_PRCM_WGPIO_3               (1 << 8)
+#define        TUSB_PRCM_WGPIO_2               (1 << 7)
+#define        TUSB_PRCM_WGPIO_1               (1 << 6)
+#define        TUSB_PRCM_WGPIO_0               (1 << 5)
+#define        TUSB_PRCM_WHOSTDISCON           (1 << 4)        /* Host disconnect */
+#define        TUSB_PRCM_WBUS                  (1 << 3)        /* USB bus resume */
+#define        TUSB_PRCM_WNORCS                (1 << 2)        /* NOR chip select */
+#define        TUSB_PRCM_WVBUS                 (1 << 1)        /* OTG PHY VBUS */
+#define        TUSB_PRCM_WID                   (1 << 0)        /* OTG PHY ID detect */
+
+#define TUSB_PULLUP_1_CTRL             (TUSB_SYS_REG_BASE + 0x030)
+#define TUSB_PULLUP_2_CTRL             (TUSB_SYS_REG_BASE + 0x034)
+#define TUSB_INT_CTRL_REV              (TUSB_SYS_REG_BASE + 0x038)
+#define TUSB_INT_CTRL_CONF             (TUSB_SYS_REG_BASE + 0x03c)
+#define TUSB_USBIP_INT_SRC             (TUSB_SYS_REG_BASE + 0x040)
+#define TUSB_USBIP_INT_SET             (TUSB_SYS_REG_BASE + 0x044)
+#define TUSB_USBIP_INT_CLEAR           (TUSB_SYS_REG_BASE + 0x048)
+#define TUSB_USBIP_INT_MASK            (TUSB_SYS_REG_BASE + 0x04c)
+#define TUSB_DMA_INT_SRC               (TUSB_SYS_REG_BASE + 0x050)
+#define TUSB_DMA_INT_SET               (TUSB_SYS_REG_BASE + 0x054)
+#define TUSB_DMA_INT_CLEAR             (TUSB_SYS_REG_BASE + 0x058)
+#define TUSB_DMA_INT_MASK              (TUSB_SYS_REG_BASE + 0x05c)
+#define TUSB_GPIO_INT_SRC              (TUSB_SYS_REG_BASE + 0x060)
+#define TUSB_GPIO_INT_SET              (TUSB_SYS_REG_BASE + 0x064)
+#define TUSB_GPIO_INT_CLEAR            (TUSB_SYS_REG_BASE + 0x068)
+#define TUSB_GPIO_INT_MASK             (TUSB_SYS_REG_BASE + 0x06c)
+
+/* NOR flash interrupt source registers */
+#define TUSB_INT_SRC                   (TUSB_SYS_REG_BASE + 0x070)
+#define TUSB_INT_SRC_SET               (TUSB_SYS_REG_BASE + 0x074)
+#define TUSB_INT_SRC_CLEAR             (TUSB_SYS_REG_BASE + 0x078)
+#define TUSB_INT_MASK                  (TUSB_SYS_REG_BASE + 0x07c)
+#define        TUSB_INT_SRC_TXRX_DMA_DONE      (1 << 24)
+#define        TUSB_INT_SRC_USB_IP_CORE        (1 << 17)
+#define        TUSB_INT_SRC_OTG_TIMEOUT        (1 << 16)
+#define        TUSB_INT_SRC_VBUS_SENSE_CHNG    (1 << 15)
+#define        TUSB_INT_SRC_ID_STATUS_CHNG     (1 << 14)
+#define        TUSB_INT_SRC_DEV_WAKEUP         (1 << 13)
+#define        TUSB_INT_SRC_DEV_READY          (1 << 12)
+#define        TUSB_INT_SRC_USB_IP_TX          (1 << 9)
+#define        TUSB_INT_SRC_USB_IP_RX          (1 << 8)
+#define        TUSB_INT_SRC_USB_IP_VBUS_ERR    (1 << 7)
+#define        TUSB_INT_SRC_USB_IP_VBUS_REQ    (1 << 6)
+#define        TUSB_INT_SRC_USB_IP_DISCON      (1 << 5)
+#define        TUSB_INT_SRC_USB_IP_CONN        (1 << 4)
+#define        TUSB_INT_SRC_USB_IP_SOF         (1 << 3)
+#define        TUSB_INT_SRC_USB_IP_RST_BABBLE  (1 << 2)
+#define        TUSB_INT_SRC_USB_IP_RESUME      (1 << 1)
+#define        TUSB_INT_SRC_USB_IP_SUSPEND     (1 << 0)
+
+#define TUSB_GPIO_REV                  (TUSB_SYS_REG_BASE + 0x080)
+#define TUSB_GPIO_CONF                 (TUSB_SYS_REG_BASE + 0x084)
+#define TUSB_DMA_CTRL_REV              (TUSB_SYS_REG_BASE + 0x100)
+#define TUSB_DMA_REQ_CONF              (TUSB_SYS_REG_BASE + 0x104)
+#define TUSB_EP0_CONF                  (TUSB_SYS_REG_BASE + 0x108)
+#define TUSB_EP_IN_SIZE                        (TUSB_SYS_REG_BASE + 0x10c)
+#define TUSB_DMA_EP_MAP                        (TUSB_SYS_REG_BASE + 0x148)
+#define TUSB_EP_OUT_SIZE               (TUSB_SYS_REG_BASE + 0x14c)
+#define TUSB_EP_MAX_PACKET_SIZE_OFFSET (TUSB_SYS_REG_BASE + 0x188)
+#define TUSB_SCRATCH_PAD               (TUSB_SYS_REG_BASE + 0x1c4)
+#define TUSB_WAIT_COUNT                        (TUSB_SYS_REG_BASE + 0x1c8)
+#define TUSB_PROD_TEST_RESET           (TUSB_SYS_REG_BASE + 0x1d8)
+
+#define TUSB_DIDR1_LO                  (TUSB_SYS_REG_BASE + 0x1f8)
+#define TUSB_DIDR1_HI                  (TUSB_SYS_REG_BASE + 0x1fc)
+
+/* Device System & Control register bitfields */
+#define TUSB_INT_CTRL_CONF_INT_RLCYC(v)        (((v) & 0x7) << 18)
+#define TUSB_INT_CTRL_CONF_INT_POLARITY        (1 << 17)
+#define TUSB_INT_CTRL_CONF_INT_MODE    (1 << 16)
+#define TUSB_GPIO_CONF_DMAREQ(v)       (((v) & 0x3f) << 24)
+#define TUSB_DMA_REQ_CONF_BURST_SIZE(v)        (((v) & 3) << 26)
+#define TUSB_DMA_REQ_CONF_DMA_RQ_EN(v) (((v) & 0x3f) << 20)
+#define TUSB_DMA_REQ_CONF_DMA_RQ_ASR(v)        (((v) & 0xf) << 16)
+#define TUSB_EP0_CONFIG_SW_EN          (1 << 8)
+#define TUSB_EP0_CONFIG_DIR_TX         (1 << 7)
+#define TUSB_EP0_CONFIG_XFR_SIZE(v)    ((v) & 0x7f)
+#define TUSB_EP_CONFIG_SW_EN           (1 << 31)
+#define TUSB_EP_CONFIG_XFR_SIZE(v)     ((v) & 0x7fffffff)
+#define TUSB_PROD_TEST_RESET_VAL       0xa596
+
+static void tusb_intr_update(TUSBState *s)
+{
+    if (s->control_config & TUSB_INT_CTRL_CONF_INT_POLARITY)
+        qemu_set_irq(s->irq, s->intr & ~s->mask & s->intr_ok);
+    else
+        qemu_set_irq(s->irq, (!(s->intr & ~s->mask)) & s->intr_ok);
+}
+
+static void tusb_usbip_intr_update(TUSBState *s)
+{
+    /* TX interrupt in the MUSB */
+    if (s->usbip_intr & 0x0000ffff & ~s->usbip_mask)
+        s->intr |= TUSB_INT_SRC_USB_IP_TX;
+    else
+        s->intr &= ~TUSB_INT_SRC_USB_IP_TX;
+
+    /* RX interrupt in the MUSB */
+    if (s->usbip_intr & 0xffff0000 & ~s->usbip_mask)
+        s->intr |= TUSB_INT_SRC_USB_IP_RX;
+    else
+        s->intr &= ~TUSB_INT_SRC_USB_IP_RX;
+
+    /* XXX: What about TUSB_INT_SRC_USB_IP_CORE?  */
+
+    tusb_intr_update(s);
+}
+
+static void tusb_dma_intr_update(TUSBState *s)
+{
+    if (s->dma_intr & ~s->dma_mask)
+        s->intr |= TUSB_INT_SRC_TXRX_DMA_DONE;
+    else
+        s->intr &= ~TUSB_INT_SRC_TXRX_DMA_DONE;
+
+    tusb_intr_update(s);
+}
+
+static void tusb_gpio_intr_update(TUSBState *s)
+{
+    /* TODO: How is this signalled?  */
+}
+
+extern CPUReadMemoryFunc * const musb_read[];
+extern CPUWriteMemoryFunc * const musb_write[];
+
+static uint32_t tusb_async_readb(void *opaque, hwaddr addr)
+{
+    TUSBState *s = (TUSBState *) opaque;
+
+    switch (addr & 0xfff) {
+    case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff):
+        return musb_read[0](s->musb, addr & 0x1ff);
+
+    case TUSB_FIFO_BASE ... (TUSB_FIFO_BASE | 0x1ff):
+        return musb_read[0](s->musb, 0x20 + ((addr >> 3) & 0x3c));
+    }
+
+    printf("%s: unknown register at %03x\n",
+                    __FUNCTION__, (int) (addr & 0xfff));
+    return 0;
+}
+
+static uint32_t tusb_async_readh(void *opaque, hwaddr addr)
+{
+    TUSBState *s = (TUSBState *) opaque;
+
+    switch (addr & 0xfff) {
+    case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff):
+        return musb_read[1](s->musb, addr & 0x1ff);
+
+    case TUSB_FIFO_BASE ... (TUSB_FIFO_BASE | 0x1ff):
+        return musb_read[1](s->musb, 0x20 + ((addr >> 3) & 0x3c));
+    }
+
+    printf("%s: unknown register at %03x\n",
+                    __FUNCTION__, (int) (addr & 0xfff));
+    return 0;
+}
+
+static uint32_t tusb_async_readw(void *opaque, hwaddr addr)
+{
+    TUSBState *s = (TUSBState *) opaque;
+    int offset = addr & 0xfff;
+    int epnum;
+    uint32_t ret;
+
+    switch (offset) {
+    case TUSB_DEV_CONF:
+        return s->dev_config;
+
+    case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff):
+        return musb_read[2](s->musb, offset & 0x1ff);
+
+    case TUSB_FIFO_BASE ... (TUSB_FIFO_BASE | 0x1ff):
+        return musb_read[2](s->musb, 0x20 + ((addr >> 3) & 0x3c));
+
+    case TUSB_PHY_OTG_CTRL_ENABLE:
+    case TUSB_PHY_OTG_CTRL:
+        return 0x00;   /* TODO */
+
+    case TUSB_DEV_OTG_STAT:
+        ret = s->otg_status;
+#if 0
+        if (!(s->prcm_mngmt & TUSB_PRCM_MNGMT_OTG_VBUS_DET_EN))
+            ret &= ~TUSB_DEV_OTG_STAT_VBUS_VALID;
+#endif
+        return ret;
+    case TUSB_DEV_OTG_TIMER:
+        return s->otg_timer_val;
+
+    case TUSB_PRCM_REV:
+        return 0x20;
+    case TUSB_PRCM_CONF:
+        return s->prcm_config;
+    case TUSB_PRCM_MNGMT:
+        return s->prcm_mngmt;
+    case TUSB_PRCM_WAKEUP_SOURCE:
+    case TUSB_PRCM_WAKEUP_CLEAR:       /* TODO: What does this one return?  */
+        return 0x00000000;
+    case TUSB_PRCM_WAKEUP_MASK:
+        return s->wkup_mask;
+
+    case TUSB_PULLUP_1_CTRL:
+        return s->pullup[0];
+    case TUSB_PULLUP_2_CTRL:
+        return s->pullup[1];
+
+    case TUSB_INT_CTRL_REV:
+        return 0x20;
+    case TUSB_INT_CTRL_CONF:
+        return s->control_config;
+
+    case TUSB_USBIP_INT_SRC:
+    case TUSB_USBIP_INT_SET:   /* TODO: What do these two return?  */
+    case TUSB_USBIP_INT_CLEAR:
+        return s->usbip_intr;
+    case TUSB_USBIP_INT_MASK:
+        return s->usbip_mask;
+
+    case TUSB_DMA_INT_SRC:
+    case TUSB_DMA_INT_SET:     /* TODO: What do these two return?  */
+    case TUSB_DMA_INT_CLEAR:
+        return s->dma_intr;
+    case TUSB_DMA_INT_MASK:
+        return s->dma_mask;
+
+    case TUSB_GPIO_INT_SRC:    /* TODO: What do these two return?  */
+    case TUSB_GPIO_INT_SET:
+    case TUSB_GPIO_INT_CLEAR:
+        return s->gpio_intr;
+    case TUSB_GPIO_INT_MASK:
+        return s->gpio_mask;
+
+    case TUSB_INT_SRC:
+    case TUSB_INT_SRC_SET:     /* TODO: What do these two return?  */
+    case TUSB_INT_SRC_CLEAR:
+        return s->intr;
+    case TUSB_INT_MASK:
+        return s->mask;
+
+    case TUSB_GPIO_REV:
+        return 0x30;
+    case TUSB_GPIO_CONF:
+        return s->gpio_config;
+
+    case TUSB_DMA_CTRL_REV:
+        return 0x30;
+    case TUSB_DMA_REQ_CONF:
+        return s->dma_config;
+    case TUSB_EP0_CONF:
+        return s->ep0_config;
+    case TUSB_EP_IN_SIZE ... (TUSB_EP_IN_SIZE + 0x3b):
+        epnum = (offset - TUSB_EP_IN_SIZE) >> 2;
+        return s->tx_config[epnum];
+    case TUSB_DMA_EP_MAP:
+        return s->dma_map;
+    case TUSB_EP_OUT_SIZE ... (TUSB_EP_OUT_SIZE + 0x3b):
+        epnum = (offset - TUSB_EP_OUT_SIZE) >> 2;
+        return s->rx_config[epnum];
+    case TUSB_EP_MAX_PACKET_SIZE_OFFSET ...
+            (TUSB_EP_MAX_PACKET_SIZE_OFFSET + 0x3b):
+        return 0x00000000;     /* TODO */
+    case TUSB_WAIT_COUNT:
+        return 0x00;           /* TODO */
+
+    case TUSB_SCRATCH_PAD:
+        return s->scratch;
+
+    case TUSB_PROD_TEST_RESET:
+        return s->test_reset;
+
+    /* DIE IDs */
+    case TUSB_DIDR1_LO:
+        return 0xa9453c59;
+    case TUSB_DIDR1_HI:
+        return 0x54059adf;
+    }
+
+    printf("%s: unknown register at %03x\n", __FUNCTION__, offset);
+    return 0;
+}
+
+static void tusb_async_writeb(void *opaque, hwaddr addr,
+                uint32_t value)
+{
+    TUSBState *s = (TUSBState *) opaque;
+
+    switch (addr & 0xfff) {
+    case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff):
+        musb_write[0](s->musb, addr & 0x1ff, value);
+        break;
+
+    case TUSB_FIFO_BASE ... (TUSB_FIFO_BASE | 0x1ff):
+        musb_write[0](s->musb, 0x20 + ((addr >> 3) & 0x3c), value);
+        break;
+
+    default:
+        printf("%s: unknown register at %03x\n",
+                        __FUNCTION__, (int) (addr & 0xfff));
+        return;
+    }
+}
+
+static void tusb_async_writeh(void *opaque, hwaddr addr,
+                uint32_t value)
+{
+    TUSBState *s = (TUSBState *) opaque;
+
+    switch (addr & 0xfff) {
+    case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff):
+        musb_write[1](s->musb, addr & 0x1ff, value);
+        break;
+
+    case TUSB_FIFO_BASE ... (TUSB_FIFO_BASE | 0x1ff):
+        musb_write[1](s->musb, 0x20 + ((addr >> 3) & 0x3c), value);
+        break;
+
+    default:
+        printf("%s: unknown register at %03x\n",
+                        __FUNCTION__, (int) (addr & 0xfff));
+        return;
+    }
+}
+
+static void tusb_async_writew(void *opaque, hwaddr addr,
+                uint32_t value)
+{
+    TUSBState *s = (TUSBState *) opaque;
+    int offset = addr & 0xfff;
+    int epnum;
+
+    switch (offset) {
+    case TUSB_VLYNQ_CTRL:
+        break;
+
+    case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff):
+        musb_write[2](s->musb, offset & 0x1ff, value);
+        break;
+
+    case TUSB_FIFO_BASE ... (TUSB_FIFO_BASE | 0x1ff):
+        musb_write[2](s->musb, 0x20 + ((addr >> 3) & 0x3c), value);
+        break;
+
+    case TUSB_DEV_CONF:
+        s->dev_config = value;
+        s->host_mode = (value & TUSB_DEV_CONF_USB_HOST_MODE);
+        if (value & TUSB_DEV_CONF_PROD_TEST_MODE)
+            hw_error("%s: Product Test mode not allowed\n", __FUNCTION__);
+        break;
+
+    case TUSB_PHY_OTG_CTRL_ENABLE:
+    case TUSB_PHY_OTG_CTRL:
+        return;                /* TODO */
+    case TUSB_DEV_OTG_TIMER:
+        s->otg_timer_val = value;
+        if (value & TUSB_DEV_OTG_TIMER_ENABLE)
+            qemu_mod_timer(s->otg_timer, qemu_get_clock_ns(vm_clock) +
+                            muldiv64(TUSB_DEV_OTG_TIMER_VAL(value),
+                                     get_ticks_per_sec(), TUSB_DEVCLOCK));
+        else
+            qemu_del_timer(s->otg_timer);
+        break;
+
+    case TUSB_PRCM_CONF:
+        s->prcm_config = value;
+        break;
+    case TUSB_PRCM_MNGMT:
+        s->prcm_mngmt = value;
+        break;
+    case TUSB_PRCM_WAKEUP_CLEAR:
+        break;
+    case TUSB_PRCM_WAKEUP_MASK:
+        s->wkup_mask = value;
+        break;
+
+    case TUSB_PULLUP_1_CTRL:
+        s->pullup[0] = value;
+        break;
+    case TUSB_PULLUP_2_CTRL:
+        s->pullup[1] = value;
+        break;
+    case TUSB_INT_CTRL_CONF:
+        s->control_config = value;
+        tusb_intr_update(s);
+        break;
+
+    case TUSB_USBIP_INT_SET:
+        s->usbip_intr |= value;
+        tusb_usbip_intr_update(s);
+        break;
+    case TUSB_USBIP_INT_CLEAR:
+        s->usbip_intr &= ~value;
+        tusb_usbip_intr_update(s);
+        musb_core_intr_clear(s->musb, ~value);
+        break;
+    case TUSB_USBIP_INT_MASK:
+        s->usbip_mask = value;
+        tusb_usbip_intr_update(s);
+        break;
+
+    case TUSB_DMA_INT_SET:
+        s->dma_intr |= value;
+        tusb_dma_intr_update(s);
+        break;
+    case TUSB_DMA_INT_CLEAR:
+        s->dma_intr &= ~value;
+        tusb_dma_intr_update(s);
+        break;
+    case TUSB_DMA_INT_MASK:
+        s->dma_mask = value;
+        tusb_dma_intr_update(s);
+        break;
+
+    case TUSB_GPIO_INT_SET:
+        s->gpio_intr |= value;
+        tusb_gpio_intr_update(s);
+        break;
+    case TUSB_GPIO_INT_CLEAR:
+        s->gpio_intr &= ~value;
+        tusb_gpio_intr_update(s);
+        break;
+    case TUSB_GPIO_INT_MASK:
+        s->gpio_mask = value;
+        tusb_gpio_intr_update(s);
+        break;
+
+    case TUSB_INT_SRC_SET:
+        s->intr |= value;
+        tusb_intr_update(s);
+        break;
+    case TUSB_INT_SRC_CLEAR:
+        s->intr &= ~value;
+        tusb_intr_update(s);
+        break;
+    case TUSB_INT_MASK:
+        s->mask = value;
+        tusb_intr_update(s);
+        break;
+
+    case TUSB_GPIO_CONF:
+        s->gpio_config = value;
+        break;
+    case TUSB_DMA_REQ_CONF:
+        s->dma_config = value;
+        break;
+    case TUSB_EP0_CONF:
+        s->ep0_config = value & 0x1ff;
+        musb_set_size(s->musb, 0, TUSB_EP0_CONFIG_XFR_SIZE(value),
+                        value & TUSB_EP0_CONFIG_DIR_TX);
+        break;
+    case TUSB_EP_IN_SIZE ... (TUSB_EP_IN_SIZE + 0x3b):
+        epnum = (offset - TUSB_EP_IN_SIZE) >> 2;
+        s->tx_config[epnum] = value;
+        musb_set_size(s->musb, epnum + 1, TUSB_EP_CONFIG_XFR_SIZE(value), 1);
+        break;
+    case TUSB_DMA_EP_MAP:
+        s->dma_map = value;
+        break;
+    case TUSB_EP_OUT_SIZE ... (TUSB_EP_OUT_SIZE + 0x3b):
+        epnum = (offset - TUSB_EP_OUT_SIZE) >> 2;
+        s->rx_config[epnum] = value;
+        musb_set_size(s->musb, epnum + 1, TUSB_EP_CONFIG_XFR_SIZE(value), 0);
+        break;
+    case TUSB_EP_MAX_PACKET_SIZE_OFFSET ...
+            (TUSB_EP_MAX_PACKET_SIZE_OFFSET + 0x3b):
+        return;                /* TODO */
+    case TUSB_WAIT_COUNT:
+        return;                /* TODO */
+
+    case TUSB_SCRATCH_PAD:
+        s->scratch = value;
+        break;
+
+    case TUSB_PROD_TEST_RESET:
+        s->test_reset = value;
+        break;
+
+    default:
+        printf("%s: unknown register at %03x\n", __FUNCTION__, offset);
+        return;
+    }
+}
+
+static const MemoryRegionOps tusb_async_ops = {
+    .old_mmio = {
+        .read = { tusb_async_readb, tusb_async_readh, tusb_async_readw, },
+        .write =  { tusb_async_writeb, tusb_async_writeh, tusb_async_writew, },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void tusb_otg_tick(void *opaque)
+{
+    TUSBState *s = (TUSBState *) opaque;
+
+    s->otg_timer_val = 0;
+    s->intr |= TUSB_INT_SRC_OTG_TIMEOUT;
+    tusb_intr_update(s);
+}
+
+static void tusb_power_tick(void *opaque)
+{
+    TUSBState *s = (TUSBState *) opaque;
+
+    if (s->power) {
+        s->intr_ok = ~0;
+        tusb_intr_update(s);
+    }
+}
+
+static void tusb_musb_core_intr(void *opaque, int source, int level)
+{
+    TUSBState *s = (TUSBState *) opaque;
+    uint16_t otg_status = s->otg_status;
+
+    switch (source) {
+    case musb_set_vbus:
+        if (level)
+            otg_status |= TUSB_DEV_OTG_STAT_VBUS_VALID;
+        else
+            otg_status &= ~TUSB_DEV_OTG_STAT_VBUS_VALID;
+
+        /* XXX: only if TUSB_PHY_OTG_CTRL_OTG_VBUS_DET_EN set?  */
+        /* XXX: only if TUSB_PRCM_MNGMT_OTG_VBUS_DET_EN set?  */
+        if (s->otg_status != otg_status) {
+            s->otg_status = otg_status;
+            s->intr |= TUSB_INT_SRC_VBUS_SENSE_CHNG;
+            tusb_intr_update(s);
+        }
+        break;
+
+    case musb_set_session:
+        /* XXX: only if TUSB_PHY_OTG_CTRL_OTG_SESS_END_EN set?  */
+        /* XXX: only if TUSB_PRCM_MNGMT_OTG_SESS_END_EN set?  */
+        if (level) {
+            s->otg_status |= TUSB_DEV_OTG_STAT_SESS_VALID;
+            s->otg_status &= ~TUSB_DEV_OTG_STAT_SESS_END;
+        } else {
+            s->otg_status &= ~TUSB_DEV_OTG_STAT_SESS_VALID;
+            s->otg_status |= TUSB_DEV_OTG_STAT_SESS_END;
+        }
+
+        /* XXX: some IRQ or anything?  */
+        break;
+
+    case musb_irq_tx:
+    case musb_irq_rx:
+        s->usbip_intr = musb_core_intr_get(s->musb);
+        /* Fall through.  */
+    default:
+        if (level)
+            s->intr |= 1 << source;
+        else
+            s->intr &= ~(1 << source);
+        tusb_intr_update(s);
+        break;
+    }
+}
+
+static void tusb6010_power(TUSBState *s, int on)
+{
+    if (!on) {
+        s->power = 0;
+    } else if (!s->power && on) {
+        s->power = 1;
+        /* Pull the interrupt down after TUSB6010 comes up.  */
+        s->intr_ok = 0;
+        tusb_intr_update(s);
+        qemu_mod_timer(s->pwr_timer,
+                       qemu_get_clock_ns(vm_clock) + get_ticks_per_sec() / 2);
+    }
+}
+
+static void tusb6010_irq(void *opaque, int source, int level)
+{
+    if (source) {
+        tusb_musb_core_intr(opaque, source - 1, level);
+    } else {
+        tusb6010_power(opaque, level);
+    }
+}
+
+static void tusb6010_reset(DeviceState *dev)
+{
+    TUSBState *s = FROM_SYSBUS(TUSBState, SYS_BUS_DEVICE(dev));
+    int i;
+
+    s->test_reset = TUSB_PROD_TEST_RESET_VAL;
+    s->host_mode = 0;
+    s->dev_config = 0;
+    s->otg_status = 0; /* !TUSB_DEV_OTG_STAT_ID_STATUS means host mode */
+    s->power = 0;
+    s->mask = 0xffffffff;
+    s->intr = 0x00000000;
+    s->otg_timer_val = 0;
+    s->scratch = 0;
+    s->prcm_config = 0;
+    s->prcm_mngmt = 0;
+    s->intr_ok = 0;
+    s->usbip_intr = 0;
+    s->usbip_mask = 0;
+    s->gpio_intr = 0;
+    s->gpio_mask = 0;
+    s->gpio_config = 0;
+    s->dma_intr = 0;
+    s->dma_mask = 0;
+    s->dma_map = 0;
+    s->dma_config = 0;
+    s->ep0_config = 0;
+    s->wkup_mask = 0;
+    s->pullup[0] = s->pullup[1] = 0;
+    s->control_config = 0;
+    for (i = 0; i < 15; i++) {
+        s->rx_config[i] = s->tx_config[i] = 0;
+    }
+    musb_reset(s->musb);
+}
+
+static int tusb6010_init(SysBusDevice *dev)
+{
+    TUSBState *s = FROM_SYSBUS(TUSBState, dev);
+    s->otg_timer = qemu_new_timer_ns(vm_clock, tusb_otg_tick, s);
+    s->pwr_timer = qemu_new_timer_ns(vm_clock, tusb_power_tick, s);
+    memory_region_init_io(&s->iomem[1], &tusb_async_ops, s, "tusb-async",
+                          UINT32_MAX);
+    sysbus_init_mmio(dev, &s->iomem[0]);
+    sysbus_init_mmio(dev, &s->iomem[1]);
+    sysbus_init_irq(dev, &s->irq);
+    qdev_init_gpio_in(&dev->qdev, tusb6010_irq, musb_irq_max + 1);
+    s->musb = musb_init(&dev->qdev, 1);
+    return 0;
+}
+
+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 const TypeInfo tusb6010_info = {
+    .name          = "tusb6010",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(TUSBState),
+    .class_init    = tusb6010_class_init,
+};
+
+static void tusb6010_register_types(void)
+{
+    type_register_static(&tusb6010_info);
+}
+
+type_init(tusb6010_register_types)
diff --git a/hw/timer/twl92230.c b/hw/timer/twl92230.c
new file mode 100644 (file)
index 0000000..b730d85
--- /dev/null
@@ -0,0 +1,882 @@
+/*
+ * TI TWL92230C energy-management companion device for the OMAP24xx.
+ * Aka. Menelaus (N4200 MENELAUS1_V2.2)
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ * Written by Andrzej Zaborowski <andrew@openedhand.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 or
+ * (at your option) version 3 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
+ * 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 "hw/hw.h"
+#include "qemu/timer.h"
+#include "hw/i2c/i2c.h"
+#include "sysemu/sysemu.h"
+#include "ui/console.h"
+
+#define VERBOSE 1
+
+typedef struct {
+    I2CSlave i2c;
+
+    int firstbyte;
+    uint8_t reg;
+
+    uint8_t vcore[5];
+    uint8_t dcdc[3];
+    uint8_t ldo[8];
+    uint8_t sleep[2];
+    uint8_t osc;
+    uint8_t detect;
+    uint16_t mask;
+    uint16_t status;
+    uint8_t dir;
+    uint8_t inputs;
+    uint8_t outputs;
+    uint8_t bbsms;
+    uint8_t pull[4];
+    uint8_t mmc_ctrl[3];
+    uint8_t mmc_debounce;
+    struct {
+        uint8_t ctrl;
+        uint16_t comp;
+        QEMUTimer *hz_tm;
+        int64_t next;
+        struct tm tm;
+        struct tm new;
+        struct tm alm;
+        int sec_offset;
+        int alm_sec;
+        int next_comp;
+    } rtc;
+    uint16_t rtc_next_vmstate;
+    qemu_irq out[4];
+    uint8_t pwrbtn_state;
+} MenelausState;
+
+static inline void menelaus_update(MenelausState *s)
+{
+    qemu_set_irq(s->out[3], s->status & ~s->mask);
+}
+
+static inline void menelaus_rtc_start(MenelausState *s)
+{
+    s->rtc.next += qemu_get_clock_ms(rtc_clock);
+    qemu_mod_timer(s->rtc.hz_tm, s->rtc.next);
+}
+
+static inline void menelaus_rtc_stop(MenelausState *s)
+{
+    qemu_del_timer(s->rtc.hz_tm);
+    s->rtc.next -= qemu_get_clock_ms(rtc_clock);
+    if (s->rtc.next < 1)
+        s->rtc.next = 1;
+}
+
+static void menelaus_rtc_update(MenelausState *s)
+{
+    qemu_get_timedate(&s->rtc.tm, s->rtc.sec_offset);
+}
+
+static void menelaus_alm_update(MenelausState *s)
+{
+    if ((s->rtc.ctrl & 3) == 3)
+        s->rtc.alm_sec = qemu_timedate_diff(&s->rtc.alm) - s->rtc.sec_offset;
+}
+
+static void menelaus_rtc_hz(void *opaque)
+{
+    MenelausState *s = (MenelausState *) opaque;
+
+    s->rtc.next_comp --;
+    s->rtc.alm_sec --;
+    s->rtc.next += 1000;
+    qemu_mod_timer(s->rtc.hz_tm, s->rtc.next);
+    if ((s->rtc.ctrl >> 3) & 3) {                              /* EVERY */
+        menelaus_rtc_update(s);
+        if (((s->rtc.ctrl >> 3) & 3) == 1 && !s->rtc.tm.tm_sec)
+            s->status |= 1 << 8;                               /* RTCTMR */
+        else if (((s->rtc.ctrl >> 3) & 3) == 2 && !s->rtc.tm.tm_min)
+            s->status |= 1 << 8;                               /* RTCTMR */
+        else if (!s->rtc.tm.tm_hour)
+            s->status |= 1 << 8;                               /* RTCTMR */
+    } else
+        s->status |= 1 << 8;                                   /* RTCTMR */
+    if ((s->rtc.ctrl >> 1) & 1) {                              /* RTC_AL_EN */
+        if (s->rtc.alm_sec == 0)
+            s->status |= 1 << 9;                               /* RTCALM */
+        /* TODO: wake-up */
+    }
+    if (s->rtc.next_comp <= 0) {
+        s->rtc.next -= muldiv64((int16_t) s->rtc.comp, 1000, 0x8000);
+        s->rtc.next_comp = 3600;
+    }
+    menelaus_update(s);
+}
+
+static void menelaus_reset(I2CSlave *i2c)
+{
+    MenelausState *s = (MenelausState *) i2c;
+    s->reg = 0x00;
+
+    s->vcore[0] = 0x0c;        /* XXX: X-loader needs 0x8c? check!  */
+    s->vcore[1] = 0x05;
+    s->vcore[2] = 0x02;
+    s->vcore[3] = 0x0c;
+    s->vcore[4] = 0x03;
+    s->dcdc[0] = 0x33; /* Depends on wiring */
+    s->dcdc[1] = 0x03;
+    s->dcdc[2] = 0x00;
+    s->ldo[0] = 0x95;
+    s->ldo[1] = 0x7e;
+    s->ldo[2] = 0x00;
+    s->ldo[3] = 0x00;  /* Depends on wiring */
+    s->ldo[4] = 0x03;  /* Depends on wiring */
+    s->ldo[5] = 0x00;
+    s->ldo[6] = 0x00;
+    s->ldo[7] = 0x00;
+    s->sleep[0] = 0x00;
+    s->sleep[1] = 0x00;
+    s->osc = 0x01;
+    s->detect = 0x09;
+    s->mask = 0x0fff;
+    s->status = 0;
+    s->dir = 0x07;
+    s->outputs = 0x00;
+    s->bbsms = 0x00;
+    s->pull[0] = 0x00;
+    s->pull[1] = 0x00;
+    s->pull[2] = 0x00;
+    s->pull[3] = 0x00;
+    s->mmc_ctrl[0] = 0x03;
+    s->mmc_ctrl[1] = 0xc0;
+    s->mmc_ctrl[2] = 0x00;
+    s->mmc_debounce = 0x05;
+
+    if (s->rtc.ctrl & 1)
+        menelaus_rtc_stop(s);
+    s->rtc.ctrl = 0x00;
+    s->rtc.comp = 0x0000;
+    s->rtc.next = 1000;
+    s->rtc.sec_offset = 0;
+    s->rtc.next_comp = 1800;
+    s->rtc.alm_sec = 1800;
+    s->rtc.alm.tm_sec = 0x00;
+    s->rtc.alm.tm_min = 0x00;
+    s->rtc.alm.tm_hour = 0x00;
+    s->rtc.alm.tm_mday = 0x01;
+    s->rtc.alm.tm_mon = 0x00;
+    s->rtc.alm.tm_year = 2004;
+    menelaus_update(s);
+}
+
+static void menelaus_gpio_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 */
+        menelaus_update(s);
+    }
+    s->pwrbtn_state = level;
+}
+
+#define MENELAUS_REV           0x01
+#define MENELAUS_VCORE_CTRL1   0x02
+#define MENELAUS_VCORE_CTRL2   0x03
+#define MENELAUS_VCORE_CTRL3   0x04
+#define MENELAUS_VCORE_CTRL4   0x05
+#define MENELAUS_VCORE_CTRL5   0x06
+#define MENELAUS_DCDC_CTRL1    0x07
+#define MENELAUS_DCDC_CTRL2    0x08
+#define MENELAUS_DCDC_CTRL3    0x09
+#define MENELAUS_LDO_CTRL1     0x0a
+#define MENELAUS_LDO_CTRL2     0x0b
+#define MENELAUS_LDO_CTRL3     0x0c
+#define MENELAUS_LDO_CTRL4     0x0d
+#define MENELAUS_LDO_CTRL5     0x0e
+#define MENELAUS_LDO_CTRL6     0x0f
+#define MENELAUS_LDO_CTRL7     0x10
+#define MENELAUS_LDO_CTRL8     0x11
+#define MENELAUS_SLEEP_CTRL1   0x12
+#define MENELAUS_SLEEP_CTRL2   0x13
+#define MENELAUS_DEVICE_OFF    0x14
+#define MENELAUS_OSC_CTRL      0x15
+#define MENELAUS_DETECT_CTRL   0x16
+#define MENELAUS_INT_MASK1     0x17
+#define MENELAUS_INT_MASK2     0x18
+#define MENELAUS_INT_STATUS1   0x19
+#define MENELAUS_INT_STATUS2   0x1a
+#define MENELAUS_INT_ACK1      0x1b
+#define MENELAUS_INT_ACK2      0x1c
+#define MENELAUS_GPIO_CTRL     0x1d
+#define MENELAUS_GPIO_IN       0x1e
+#define MENELAUS_GPIO_OUT      0x1f
+#define MENELAUS_BBSMS         0x20
+#define MENELAUS_RTC_CTRL      0x21
+#define MENELAUS_RTC_UPDATE    0x22
+#define MENELAUS_RTC_SEC       0x23
+#define MENELAUS_RTC_MIN       0x24
+#define MENELAUS_RTC_HR                0x25
+#define MENELAUS_RTC_DAY       0x26
+#define MENELAUS_RTC_MON       0x27
+#define MENELAUS_RTC_YR                0x28
+#define MENELAUS_RTC_WKDAY     0x29
+#define MENELAUS_RTC_AL_SEC    0x2a
+#define MENELAUS_RTC_AL_MIN    0x2b
+#define MENELAUS_RTC_AL_HR     0x2c
+#define MENELAUS_RTC_AL_DAY    0x2d
+#define MENELAUS_RTC_AL_MON    0x2e
+#define MENELAUS_RTC_AL_YR     0x2f
+#define MENELAUS_RTC_COMP_MSB  0x30
+#define MENELAUS_RTC_COMP_LSB  0x31
+#define MENELAUS_S1_PULL_EN    0x32
+#define MENELAUS_S1_PULL_DIR   0x33
+#define MENELAUS_S2_PULL_EN    0x34
+#define MENELAUS_S2_PULL_DIR   0x35
+#define MENELAUS_MCT_CTRL1     0x36
+#define MENELAUS_MCT_CTRL2     0x37
+#define MENELAUS_MCT_CTRL3     0x38
+#define MENELAUS_MCT_PIN_ST    0x39
+#define MENELAUS_DEBOUNCE1     0x3a
+
+static uint8_t menelaus_read(void *opaque, uint8_t addr)
+{
+    MenelausState *s = (MenelausState *) opaque;
+    int reg = 0;
+
+    switch (addr) {
+    case MENELAUS_REV:
+        return 0x22;
+
+    case MENELAUS_VCORE_CTRL5: reg ++;
+    case MENELAUS_VCORE_CTRL4: reg ++;
+    case MENELAUS_VCORE_CTRL3: reg ++;
+    case MENELAUS_VCORE_CTRL2: reg ++;
+    case MENELAUS_VCORE_CTRL1:
+        return s->vcore[reg];
+
+    case MENELAUS_DCDC_CTRL3: reg ++;
+    case MENELAUS_DCDC_CTRL2: reg ++;
+    case MENELAUS_DCDC_CTRL1:
+        return s->dcdc[reg];
+
+    case MENELAUS_LDO_CTRL8: reg ++;
+    case MENELAUS_LDO_CTRL7: reg ++;
+    case MENELAUS_LDO_CTRL6: reg ++;
+    case MENELAUS_LDO_CTRL5: reg ++;
+    case MENELAUS_LDO_CTRL4: reg ++;
+    case MENELAUS_LDO_CTRL3: reg ++;
+    case MENELAUS_LDO_CTRL2: reg ++;
+    case MENELAUS_LDO_CTRL1:
+        return s->ldo[reg];
+
+    case MENELAUS_SLEEP_CTRL2: reg ++;
+    case MENELAUS_SLEEP_CTRL1:
+        return s->sleep[reg];
+
+    case MENELAUS_DEVICE_OFF:
+        return 0;
+
+    case MENELAUS_OSC_CTRL:
+        return s->osc | (1 << 7);                      /* CLK32K_GOOD */
+
+    case MENELAUS_DETECT_CTRL:
+        return s->detect;
+
+    case MENELAUS_INT_MASK1:
+        return (s->mask >> 0) & 0xff;
+    case MENELAUS_INT_MASK2:
+        return (s->mask >> 8) & 0xff;
+
+    case MENELAUS_INT_STATUS1:
+        return (s->status >> 0) & 0xff;
+    case MENELAUS_INT_STATUS2:
+        return (s->status >> 8) & 0xff;
+
+    case MENELAUS_INT_ACK1:
+    case MENELAUS_INT_ACK2:
+        return 0;
+
+    case MENELAUS_GPIO_CTRL:
+        return s->dir;
+    case MENELAUS_GPIO_IN:
+        return s->inputs | (~s->dir & s->outputs);
+    case MENELAUS_GPIO_OUT:
+        return s->outputs;
+
+    case MENELAUS_BBSMS:
+        return s->bbsms;
+
+    case MENELAUS_RTC_CTRL:
+        return s->rtc.ctrl;
+    case MENELAUS_RTC_UPDATE:
+        return 0x00;
+    case MENELAUS_RTC_SEC:
+        menelaus_rtc_update(s);
+        return to_bcd(s->rtc.tm.tm_sec);
+    case MENELAUS_RTC_MIN:
+        menelaus_rtc_update(s);
+        return to_bcd(s->rtc.tm.tm_min);
+    case MENELAUS_RTC_HR:
+        menelaus_rtc_update(s);
+        if ((s->rtc.ctrl >> 2) & 1)                    /* MODE12_n24 */
+            return to_bcd((s->rtc.tm.tm_hour % 12) + 1) |
+                    (!!(s->rtc.tm.tm_hour >= 12) << 7);        /* PM_nAM */
+        else
+            return to_bcd(s->rtc.tm.tm_hour);
+    case MENELAUS_RTC_DAY:
+        menelaus_rtc_update(s);
+        return to_bcd(s->rtc.tm.tm_mday);
+    case MENELAUS_RTC_MON:
+        menelaus_rtc_update(s);
+        return to_bcd(s->rtc.tm.tm_mon + 1);
+    case MENELAUS_RTC_YR:
+        menelaus_rtc_update(s);
+        return to_bcd(s->rtc.tm.tm_year - 2000);
+    case MENELAUS_RTC_WKDAY:
+        menelaus_rtc_update(s);
+        return to_bcd(s->rtc.tm.tm_wday);
+    case MENELAUS_RTC_AL_SEC:
+        return to_bcd(s->rtc.alm.tm_sec);
+    case MENELAUS_RTC_AL_MIN:
+        return to_bcd(s->rtc.alm.tm_min);
+    case MENELAUS_RTC_AL_HR:
+        if ((s->rtc.ctrl >> 2) & 1)                    /* MODE12_n24 */
+            return to_bcd((s->rtc.alm.tm_hour % 12) + 1) |
+                    (!!(s->rtc.alm.tm_hour >= 12) << 7);/* AL_PM_nAM */
+        else
+            return to_bcd(s->rtc.alm.tm_hour);
+    case MENELAUS_RTC_AL_DAY:
+        return to_bcd(s->rtc.alm.tm_mday);
+    case MENELAUS_RTC_AL_MON:
+        return to_bcd(s->rtc.alm.tm_mon + 1);
+    case MENELAUS_RTC_AL_YR:
+        return to_bcd(s->rtc.alm.tm_year - 2000);
+    case MENELAUS_RTC_COMP_MSB:
+        return (s->rtc.comp >> 8) & 0xff;
+    case MENELAUS_RTC_COMP_LSB:
+        return (s->rtc.comp >> 0) & 0xff;
+
+    case MENELAUS_S1_PULL_EN:
+        return s->pull[0];
+    case MENELAUS_S1_PULL_DIR:
+        return s->pull[1];
+    case MENELAUS_S2_PULL_EN:
+        return s->pull[2];
+    case MENELAUS_S2_PULL_DIR:
+        return s->pull[3];
+
+    case MENELAUS_MCT_CTRL3: reg ++;
+    case MENELAUS_MCT_CTRL2: reg ++;
+    case MENELAUS_MCT_CTRL1:
+        return s->mmc_ctrl[reg];
+    case MENELAUS_MCT_PIN_ST:
+        /* TODO: return the real Card Detect */
+        return 0;
+    case MENELAUS_DEBOUNCE1:
+        return s->mmc_debounce;
+
+    default:
+#ifdef VERBOSE
+        printf("%s: unknown register %02x\n", __FUNCTION__, addr);
+#endif
+        break;
+    }
+    return 0;
+}
+
+static void menelaus_write(void *opaque, uint8_t addr, uint8_t value)
+{
+    MenelausState *s = (MenelausState *) opaque;
+    int line;
+    int reg = 0;
+    struct tm tm;
+
+    switch (addr) {
+    case MENELAUS_VCORE_CTRL1:
+        s->vcore[0] = (value & 0xe) | MIN(value & 0x1f, 0x12);
+        break;
+    case MENELAUS_VCORE_CTRL2:
+        s->vcore[1] = value;
+        break;
+    case MENELAUS_VCORE_CTRL3:
+        s->vcore[2] = MIN(value & 0x1f, 0x12);
+        break;
+    case MENELAUS_VCORE_CTRL4:
+        s->vcore[3] = MIN(value & 0x1f, 0x12);
+        break;
+    case MENELAUS_VCORE_CTRL5:
+        s->vcore[4] = value & 3;
+        /* XXX
+         * auto set to 3 on M_Active, nRESWARM
+         * auto set to 0 on M_WaitOn, M_Backup
+         */
+        break;
+
+    case MENELAUS_DCDC_CTRL1:
+        s->dcdc[0] = value & 0x3f;
+        break;
+    case MENELAUS_DCDC_CTRL2:
+        s->dcdc[1] = value & 0x07;
+        /* XXX
+         * auto set to 3 on M_Active, nRESWARM
+         * auto set to 0 on M_WaitOn, M_Backup
+         */
+        break;
+    case MENELAUS_DCDC_CTRL3:
+        s->dcdc[2] = value & 0x07;
+        break;
+
+    case MENELAUS_LDO_CTRL1:
+        s->ldo[0] = value;
+        break;
+    case MENELAUS_LDO_CTRL2:
+        s->ldo[1] = value & 0x7f;
+        /* XXX
+         * auto set to 0x7e on M_WaitOn, M_Backup
+         */
+        break;
+    case MENELAUS_LDO_CTRL3:
+        s->ldo[2] = value & 3;
+        /* XXX
+         * auto set to 3 on M_Active, nRESWARM
+         * auto set to 0 on M_WaitOn, M_Backup
+         */
+        break;
+    case MENELAUS_LDO_CTRL4:
+        s->ldo[3] = value & 3;
+        /* XXX
+         * auto set to 3 on M_Active, nRESWARM
+         * auto set to 0 on M_WaitOn, M_Backup
+         */
+        break;
+    case MENELAUS_LDO_CTRL5:
+        s->ldo[4] = value & 3;
+        /* XXX
+         * auto set to 3 on M_Active, nRESWARM
+         * auto set to 0 on M_WaitOn, M_Backup
+         */
+        break;
+    case MENELAUS_LDO_CTRL6:
+        s->ldo[5] = value & 3;
+        break;
+    case MENELAUS_LDO_CTRL7:
+        s->ldo[6] = value & 3;
+        break;
+    case MENELAUS_LDO_CTRL8:
+        s->ldo[7] = value & 3;
+        break;
+
+    case MENELAUS_SLEEP_CTRL2: reg ++;
+    case MENELAUS_SLEEP_CTRL1:
+        s->sleep[reg] = value;
+        break;
+
+    case MENELAUS_DEVICE_OFF:
+        if (value & 1)
+            menelaus_reset(&s->i2c);
+        break;
+
+    case MENELAUS_OSC_CTRL:
+        s->osc = value & 7;
+        break;
+
+    case MENELAUS_DETECT_CTRL:
+        s->detect = value & 0x7f;
+        break;
+
+    case MENELAUS_INT_MASK1:
+        s->mask &= 0xf00;
+        s->mask |= value << 0;
+        menelaus_update(s);
+        break;
+    case MENELAUS_INT_MASK2:
+        s->mask &= 0x0ff;
+        s->mask |= value << 8;
+        menelaus_update(s);
+        break;
+
+    case MENELAUS_INT_ACK1:
+        s->status &= ~(((uint16_t) value) << 0);
+        menelaus_update(s);
+        break;
+    case MENELAUS_INT_ACK2:
+        s->status &= ~(((uint16_t) value) << 8);
+        menelaus_update(s);
+        break;
+
+    case MENELAUS_GPIO_CTRL:
+        for (line = 0; line < 3; line ++) {
+            if (((s->dir ^ value) >> line) & 1) {
+                qemu_set_irq(s->out[line],
+                             ((s->outputs & ~s->dir) >> line) & 1);
+            }
+        }
+        s->dir = value & 0x67;
+        break;
+    case MENELAUS_GPIO_OUT:
+        for (line = 0; line < 3; line ++) {
+            if ((((s->outputs ^ value) & ~s->dir) >> line) & 1) {
+                qemu_set_irq(s->out[line], (s->outputs >> line) & 1);
+            }
+        }
+        s->outputs = value & 0x07;
+        break;
+
+    case MENELAUS_BBSMS:
+        s->bbsms = 0x0d;
+        break;
+
+    case MENELAUS_RTC_CTRL:
+        if ((s->rtc.ctrl ^ value) & 1) {                       /* RTC_EN */
+            if (value & 1)
+                menelaus_rtc_start(s);
+            else
+                menelaus_rtc_stop(s);
+        }
+        s->rtc.ctrl = value & 0x1f;
+        menelaus_alm_update(s);
+        break;
+    case MENELAUS_RTC_UPDATE:
+        menelaus_rtc_update(s);
+        memcpy(&tm, &s->rtc.tm, sizeof(tm));
+        switch (value & 0xf) {
+        case 0:
+            break;
+        case 1:
+            tm.tm_sec = s->rtc.new.tm_sec;
+            break;
+        case 2:
+            tm.tm_min = s->rtc.new.tm_min;
+            break;
+        case 3:
+            if (s->rtc.new.tm_hour > 23)
+                goto rtc_badness;
+            tm.tm_hour = s->rtc.new.tm_hour;
+            break;
+        case 4:
+            if (s->rtc.new.tm_mday < 1)
+                goto rtc_badness;
+            /* TODO check range */
+            tm.tm_mday = s->rtc.new.tm_mday;
+            break;
+        case 5:
+            if (s->rtc.new.tm_mon < 0 || s->rtc.new.tm_mon > 11)
+                goto rtc_badness;
+            tm.tm_mon = s->rtc.new.tm_mon;
+            break;
+        case 6:
+            tm.tm_year = s->rtc.new.tm_year;
+            break;
+        case 7:
+            /* TODO set .tm_mday instead */
+            tm.tm_wday = s->rtc.new.tm_wday;
+            break;
+        case 8:
+            if (s->rtc.new.tm_hour > 23)
+                goto rtc_badness;
+            if (s->rtc.new.tm_mday < 1)
+                goto rtc_badness;
+            if (s->rtc.new.tm_mon < 0 || s->rtc.new.tm_mon > 11)
+                goto rtc_badness;
+            tm.tm_sec = s->rtc.new.tm_sec;
+            tm.tm_min = s->rtc.new.tm_min;
+            tm.tm_hour = s->rtc.new.tm_hour;
+            tm.tm_mday = s->rtc.new.tm_mday;
+            tm.tm_mon = s->rtc.new.tm_mon;
+            tm.tm_year = s->rtc.new.tm_year;
+            break;
+        rtc_badness:
+        default:
+            fprintf(stderr, "%s: bad RTC_UPDATE value %02x\n",
+                            __FUNCTION__, value);
+            s->status |= 1 << 10;                              /* RTCERR */
+            menelaus_update(s);
+        }
+        s->rtc.sec_offset = qemu_timedate_diff(&tm);
+        break;
+    case MENELAUS_RTC_SEC:
+        s->rtc.tm.tm_sec = from_bcd(value & 0x7f);
+        break;
+    case MENELAUS_RTC_MIN:
+        s->rtc.tm.tm_min = from_bcd(value & 0x7f);
+        break;
+    case MENELAUS_RTC_HR:
+        s->rtc.tm.tm_hour = (s->rtc.ctrl & (1 << 2)) ? /* MODE12_n24 */
+                MIN(from_bcd(value & 0x3f), 12) + ((value >> 7) ? 11 : -1) :
+                from_bcd(value & 0x3f);
+        break;
+    case MENELAUS_RTC_DAY:
+        s->rtc.tm.tm_mday = from_bcd(value);
+        break;
+    case MENELAUS_RTC_MON:
+        s->rtc.tm.tm_mon = MAX(1, from_bcd(value)) - 1;
+        break;
+    case MENELAUS_RTC_YR:
+        s->rtc.tm.tm_year = 2000 + from_bcd(value);
+        break;
+    case MENELAUS_RTC_WKDAY:
+        s->rtc.tm.tm_mday = from_bcd(value);
+        break;
+    case MENELAUS_RTC_AL_SEC:
+        s->rtc.alm.tm_sec = from_bcd(value & 0x7f);
+        menelaus_alm_update(s);
+        break;
+    case MENELAUS_RTC_AL_MIN:
+        s->rtc.alm.tm_min = from_bcd(value & 0x7f);
+        menelaus_alm_update(s);
+        break;
+    case MENELAUS_RTC_AL_HR:
+        s->rtc.alm.tm_hour = (s->rtc.ctrl & (1 << 2)) ?        /* MODE12_n24 */
+                MIN(from_bcd(value & 0x3f), 12) + ((value >> 7) ? 11 : -1) :
+                from_bcd(value & 0x3f);
+        menelaus_alm_update(s);
+        break;
+    case MENELAUS_RTC_AL_DAY:
+        s->rtc.alm.tm_mday = from_bcd(value);
+        menelaus_alm_update(s);
+        break;
+    case MENELAUS_RTC_AL_MON:
+        s->rtc.alm.tm_mon = MAX(1, from_bcd(value)) - 1;
+        menelaus_alm_update(s);
+        break;
+    case MENELAUS_RTC_AL_YR:
+        s->rtc.alm.tm_year = 2000 + from_bcd(value);
+        menelaus_alm_update(s);
+        break;
+    case MENELAUS_RTC_COMP_MSB:
+        s->rtc.comp &= 0xff;
+        s->rtc.comp |= value << 8;
+        break;
+    case MENELAUS_RTC_COMP_LSB:
+        s->rtc.comp &= 0xff << 8;
+        s->rtc.comp |= value;
+        break;
+
+    case MENELAUS_S1_PULL_EN:
+        s->pull[0] = value;
+        break;
+    case MENELAUS_S1_PULL_DIR:
+        s->pull[1] = value & 0x1f;
+        break;
+    case MENELAUS_S2_PULL_EN:
+        s->pull[2] = value;
+        break;
+    case MENELAUS_S2_PULL_DIR:
+        s->pull[3] = value & 0x1f;
+        break;
+
+    case MENELAUS_MCT_CTRL1:
+        s->mmc_ctrl[0] = value & 0x7f;
+        break;
+    case MENELAUS_MCT_CTRL2:
+        s->mmc_ctrl[1] = value;
+        /* TODO update Card Detect interrupts */
+        break;
+    case MENELAUS_MCT_CTRL3:
+        s->mmc_ctrl[2] = value & 0xf;
+        break;
+    case MENELAUS_DEBOUNCE1:
+        s->mmc_debounce = value & 0x3f;
+        break;
+
+    default:
+#ifdef VERBOSE
+        printf("%s: unknown register %02x\n", __FUNCTION__, addr);
+#endif
+    }
+}
+
+static void menelaus_event(I2CSlave *i2c, enum i2c_event event)
+{
+    MenelausState *s = (MenelausState *) i2c;
+
+    if (event == I2C_START_SEND)
+        s->firstbyte = 1;
+}
+
+static int menelaus_tx(I2CSlave *i2c, uint8_t data)
+{
+    MenelausState *s = (MenelausState *) i2c;
+    /* Interpret register address byte */
+    if (s->firstbyte) {
+        s->reg = data;
+        s->firstbyte = 0;
+    } else
+        menelaus_write(s, s->reg ++, data);
+
+    return 0;
+}
+
+static int menelaus_rx(I2CSlave *i2c)
+{
+    MenelausState *s = (MenelausState *) i2c;
+
+    return menelaus_read(s, s->reg ++);
+}
+
+/* Save restore 32 bit int as uint16_t
+   This is a Big hack, but it is how the old state did it.
+   Or we broke compatibility in the state, or we can't use struct tm
+ */
+
+static int get_int32_as_uint16(QEMUFile *f, void *pv, size_t size)
+{
+    int *v = pv;
+    *v = qemu_get_be16(f);
+    return 0;
+}
+
+static void put_int32_as_uint16(QEMUFile *f, void *pv, size_t size)
+{
+    int *v = pv;
+    qemu_put_be16(f, *v);
+}
+
+static const VMStateInfo vmstate_hack_int32_as_uint16 = {
+    .name = "int32_as_uint16",
+    .get  = get_int32_as_uint16,
+    .put  = put_int32_as_uint16,
+};
+
+#define VMSTATE_UINT16_HACK(_f, _s)                                  \
+    VMSTATE_SINGLE(_f, _s, 0, vmstate_hack_int32_as_uint16, int32_t)
+
+
+static const VMStateDescription vmstate_menelaus_tm = {
+    .name = "menelaus_tm",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT16_HACK(tm_sec, struct tm),
+        VMSTATE_UINT16_HACK(tm_min, struct tm),
+        VMSTATE_UINT16_HACK(tm_hour, struct tm),
+        VMSTATE_UINT16_HACK(tm_mday, struct tm),
+        VMSTATE_UINT16_HACK(tm_min, struct tm),
+        VMSTATE_UINT16_HACK(tm_year, struct tm),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void menelaus_pre_save(void *opaque)
+{
+    MenelausState *s = opaque;
+    /* Should be <= 1000 */
+    s->rtc_next_vmstate =  s->rtc.next - qemu_get_clock_ms(rtc_clock);
+}
+
+static int menelaus_post_load(void *opaque, int version_id)
+{
+    MenelausState *s = opaque;
+
+    if (s->rtc.ctrl & 1)                                       /* RTC_EN */
+        menelaus_rtc_stop(s);
+
+    s->rtc.next = s->rtc_next_vmstate;
+
+    menelaus_alm_update(s);
+    menelaus_update(s);
+    if (s->rtc.ctrl & 1)                                       /* RTC_EN */
+        menelaus_rtc_start(s);
+    return 0;
+}
+
+static const VMStateDescription vmstate_menelaus = {
+    .name = "menelaus",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .pre_save = menelaus_pre_save,
+    .post_load = menelaus_post_load,
+    .fields      = (VMStateField []) {
+        VMSTATE_INT32(firstbyte, MenelausState),
+        VMSTATE_UINT8(reg, MenelausState),
+        VMSTATE_UINT8_ARRAY(vcore, MenelausState, 5),
+        VMSTATE_UINT8_ARRAY(dcdc, MenelausState, 3),
+        VMSTATE_UINT8_ARRAY(ldo, MenelausState, 8),
+        VMSTATE_UINT8_ARRAY(sleep, MenelausState, 2),
+        VMSTATE_UINT8(osc, MenelausState),
+        VMSTATE_UINT8(detect, MenelausState),
+        VMSTATE_UINT16(mask, MenelausState),
+        VMSTATE_UINT16(status, MenelausState),
+        VMSTATE_UINT8(dir, MenelausState),
+        VMSTATE_UINT8(inputs, MenelausState),
+        VMSTATE_UINT8(outputs, MenelausState),
+        VMSTATE_UINT8(bbsms, MenelausState),
+        VMSTATE_UINT8_ARRAY(pull, MenelausState, 4),
+        VMSTATE_UINT8_ARRAY(mmc_ctrl, MenelausState, 3),
+        VMSTATE_UINT8(mmc_debounce, MenelausState),
+        VMSTATE_UINT8(rtc.ctrl, MenelausState),
+        VMSTATE_UINT16(rtc.comp, MenelausState),
+        VMSTATE_UINT16(rtc_next_vmstate, MenelausState),
+        VMSTATE_STRUCT(rtc.new, MenelausState, 0, vmstate_menelaus_tm,
+                       struct tm),
+        VMSTATE_STRUCT(rtc.alm, MenelausState, 0, vmstate_menelaus_tm,
+                       struct tm),
+        VMSTATE_UINT8(pwrbtn_state, MenelausState),
+        VMSTATE_I2C_SLAVE(i2c, MenelausState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int twl92230_init(I2CSlave *i2c)
+{
+    MenelausState *s = FROM_I2C_SLAVE(MenelausState, i2c);
+
+    s->rtc.hz_tm = qemu_new_timer_ms(rtc_clock, menelaus_rtc_hz, s);
+    /* Three output pins plus one interrupt pin.  */
+    qdev_init_gpio_out(&i2c->qdev, s->out, 4);
+
+    /* Three input pins plus one power-button pin.  */
+    qdev_init_gpio_in(&i2c->qdev, menelaus_gpio_set, 4);
+
+    menelaus_reset(&s->i2c);
+
+    return 0;
+}
+
+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 const TypeInfo twl92230_info = {
+    .name          = "twl92230",
+    .parent        = TYPE_I2C_SLAVE,
+    .instance_size = sizeof(MenelausState),
+    .class_init    = twl92230_class_init,
+};
+
+static void twl92230_register_types(void)
+{
+    type_register_static(&twl92230_info);
+}
+
+type_init(twl92230_register_types)
diff --git a/hw/timer/xilinx_timer.c b/hw/timer/xilinx_timer.c
new file mode 100644 (file)
index 0000000..0c39cff
--- /dev/null
@@ -0,0 +1,255 @@
+/*
+ * QEMU model of the Xilinx timer block.
+ *
+ * Copyright (c) 2009 Edgar E. Iglesias.
+ *
+ * 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 "hw/sysbus.h"
+#include "hw/ptimer.h"
+#include "qemu/log.h"
+
+#define D(x)
+
+#define R_TCSR     0
+#define R_TLR      1
+#define R_TCR      2
+#define R_MAX      4
+
+#define TCSR_MDT        (1<<0)
+#define TCSR_UDT        (1<<1)
+#define TCSR_GENT       (1<<2)
+#define TCSR_CAPT       (1<<3)
+#define TCSR_ARHT       (1<<4)
+#define TCSR_LOAD       (1<<5)
+#define TCSR_ENIT       (1<<6)
+#define TCSR_ENT        (1<<7)
+#define TCSR_TINT       (1<<8)
+#define TCSR_PWMA       (1<<9)
+#define TCSR_ENALL      (1<<10)
+
+struct xlx_timer
+{
+    QEMUBH *bh;
+    ptimer_state *ptimer;
+    void *parent;
+    int nr; /* for debug.  */
+
+    unsigned long timer_div;
+
+    uint32_t regs[R_MAX];
+};
+
+struct timerblock
+{
+    SysBusDevice busdev;
+    MemoryRegion mmio;
+    qemu_irq irq;
+    uint8_t one_timer_only;
+    uint32_t freq_hz;
+    struct xlx_timer *timers;
+};
+
+static inline unsigned int num_timers(struct timerblock *t)
+{
+    return 2 - t->one_timer_only;
+}
+
+static inline unsigned int timer_from_addr(hwaddr addr)
+{
+    /* Timers get a 4x32bit control reg area each.  */
+    return addr >> 2;
+}
+
+static void timer_update_irq(struct timerblock *t)
+{
+    unsigned int i, irq = 0;
+    uint32_t csr;
+
+    for (i = 0; i < num_timers(t); i++) {
+        csr = t->timers[i].regs[R_TCSR];
+        irq |= (csr & TCSR_TINT) && (csr & TCSR_ENIT);
+    }
+
+    /* All timers within the same slave share a single IRQ line.  */
+    qemu_set_irq(t->irq, !!irq);
+}
+
+static uint64_t
+timer_read(void *opaque, hwaddr addr, unsigned int size)
+{
+    struct timerblock *t = opaque;
+    struct xlx_timer *xt;
+    uint32_t r = 0;
+    unsigned int timer;
+
+    addr >>= 2;
+    timer = timer_from_addr(addr);
+    xt = &t->timers[timer];
+    /* Further decoding to address a specific timers reg.  */
+    addr &= 0x3;
+    switch (addr)
+    {
+        case R_TCR:
+                r = ptimer_get_count(xt->ptimer);
+                if (!(xt->regs[R_TCSR] & TCSR_UDT))
+                    r = ~r;
+                D(qemu_log("xlx_timer t=%d read counter=%x udt=%d\n",
+                         timer, r, xt->regs[R_TCSR] & TCSR_UDT));
+            break;
+        default:
+            if (addr < ARRAY_SIZE(xt->regs))
+                r = xt->regs[addr];
+            break;
+
+    }
+    D(fprintf(stderr, "%s timer=%d %x=%x\n", __func__, timer, addr * 4, r));
+    return r;
+}
+
+static void timer_enable(struct xlx_timer *xt)
+{
+    uint64_t count;
+
+    D(fprintf(stderr, "%s timer=%d down=%d\n", __func__,
+              xt->nr, xt->regs[R_TCSR] & TCSR_UDT));
+
+    ptimer_stop(xt->ptimer);
+
+    if (xt->regs[R_TCSR] & TCSR_UDT)
+        count = xt->regs[R_TLR];
+    else
+        count = ~0 - xt->regs[R_TLR];
+    ptimer_set_limit(xt->ptimer, count, 1);
+    ptimer_run(xt->ptimer, 1);
+}
+
+static void
+timer_write(void *opaque, hwaddr addr,
+            uint64_t val64, unsigned int size)
+{
+    struct timerblock *t = opaque;
+    struct xlx_timer *xt;
+    unsigned int timer;
+    uint32_t value = val64;
+
+    addr >>= 2;
+    timer = timer_from_addr(addr);
+    xt = &t->timers[timer];
+    D(fprintf(stderr, "%s addr=%x val=%x (timer=%d off=%d)\n",
+             __func__, addr * 4, value, timer, addr & 3));
+    /* Further decoding to address a specific timers reg.  */
+    addr &= 3;
+    switch (addr) 
+    {
+        case R_TCSR:
+            if (value & TCSR_TINT)
+                value &= ~TCSR_TINT;
+
+            xt->regs[addr] = value;
+            if (value & TCSR_ENT)
+                timer_enable(xt);
+            break;
+        default:
+            if (addr < ARRAY_SIZE(xt->regs))
+                xt->regs[addr] = value;
+            break;
+    }
+    timer_update_irq(t);
+}
+
+static const MemoryRegionOps timer_ops = {
+    .read = timer_read,
+    .write = timer_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4
+    }
+};
+
+static void timer_hit(void *opaque)
+{
+    struct xlx_timer *xt = opaque;
+    struct timerblock *t = xt->parent;
+    D(fprintf(stderr, "%s %d\n", __func__, xt->nr));
+    xt->regs[R_TCSR] |= TCSR_TINT;
+
+    if (xt->regs[R_TCSR] & TCSR_ARHT)
+        timer_enable(xt);
+    timer_update_irq(t);
+}
+
+static int xilinx_timer_init(SysBusDevice *dev)
+{
+    struct timerblock *t = FROM_SYSBUS(typeof (*t), dev);
+    unsigned int i;
+
+    /* All timers share a single irq line.  */
+    sysbus_init_irq(dev, &t->irq);
+
+    /* Init all the ptimers.  */
+    t->timers = g_malloc0(sizeof t->timers[0] * num_timers(t));
+    for (i = 0; i < num_timers(t); i++) {
+        struct xlx_timer *xt = &t->timers[i];
+
+        xt->parent = t;
+        xt->nr = i;
+        xt->bh = qemu_bh_new(timer_hit, xt);
+        xt->ptimer = ptimer_init(xt->bh);
+        ptimer_set_freq(xt->ptimer, t->freq_hz);
+    }
+
+    memory_region_init_io(&t->mmio, &timer_ops, t, "xlnx.xps-timer",
+                          R_MAX * 4 * num_timers(t));
+    sysbus_init_mmio(dev, &t->mmio);
+    return 0;
+}
+
+static Property xilinx_timer_properties[] = {
+    DEFINE_PROP_UINT32("clock-frequency", struct timerblock, freq_hz,
+                                                                62 * 1000000),
+    DEFINE_PROP_UINT8("one-timer-only", struct timerblock, one_timer_only, 0),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void xilinx_timer_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = xilinx_timer_init;
+    dc->props = xilinx_timer_properties;
+}
+
+static const TypeInfo xilinx_timer_info = {
+    .name          = "xlnx.xps-timer",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(struct timerblock),
+    .class_init    = xilinx_timer_class_init,
+};
+
+static void xilinx_timer_register_types(void)
+{
+    type_register_static(&xilinx_timer_info);
+}
+
+type_init(xilinx_timer_register_types)
diff --git a/hw/tmp105.c b/hw/tmp105.c
deleted file mode 100644 (file)
index 47e5437..0000000
+++ /dev/null
@@ -1,269 +0,0 @@
-/*
- * Texas Instruments TMP105 temperature sensor.
- *
- * Copyright (C) 2008 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.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 or
- * (at your option) version 3 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
- * 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 "hw/hw.h"
-#include "hw/i2c.h"
-#include "hw/tmp105.h"
-#include "qapi/visitor.h"
-
-static void tmp105_interrupt_update(TMP105State *s)
-{
-    qemu_set_irq(s->pin, s->alarm ^ ((~s->config >> 2) & 1));  /* POL */
-}
-
-static void tmp105_alarm_update(TMP105State *s)
-{
-    if ((s->config >> 0) & 1) {                                        /* SD */
-        if ((s->config >> 7) & 1)                              /* OS */
-            s->config &= ~(1 << 7);                            /* OS */
-        else
-            return;
-    }
-
-    if ((s->config >> 1) & 1) {                                        /* TM */
-        if (s->temperature >= s->limit[1])
-            s->alarm = 1;
-        else if (s->temperature < s->limit[0])
-            s->alarm = 1;
-    } else {
-        if (s->temperature >= s->limit[1])
-            s->alarm = 1;
-        else if (s->temperature < s->limit[0])
-            s->alarm = 0;
-    }
-
-    tmp105_interrupt_update(s);
-}
-
-static void tmp105_get_temperature(Object *obj, Visitor *v, void *opaque,
-                                   const char *name, Error **errp)
-{
-    TMP105State *s = TMP105(obj);
-    int64_t value = s->temperature;
-
-    visit_type_int(v, &value, name, errp);
-}
-
-/* Units are 0.001 centigrades relative to 0 C.  */
-static void tmp105_set_temperature(Object *obj, Visitor *v, void *opaque,
-                                   const char *name, Error **errp)
-{
-    TMP105State *s = TMP105(obj);
-    int64_t temp;
-
-    visit_type_int(v, &temp, name, errp);
-    if (error_is_set(errp)) {
-        return;
-    }
-    if (temp >= 128000 || temp < -128000) {
-        error_setg(errp, "value %" PRId64 ".%03" PRIu64 " Â°C is out of range",
-                   temp / 1000, temp % 1000);
-        return;
-    }
-
-    s->temperature = ((int16_t) (temp * 0x800 / 128000)) << 4;
-
-    tmp105_alarm_update(s);
-}
-
-static const int tmp105_faultq[4] = { 1, 2, 4, 6 };
-
-static void tmp105_read(TMP105State *s)
-{
-    s->len = 0;
-
-    if ((s->config >> 1) & 1) {                                        /* TM */
-        s->alarm = 0;
-        tmp105_interrupt_update(s);
-    }
-
-    switch (s->pointer & 3) {
-    case TMP105_REG_TEMPERATURE:
-        s->buf[s->len ++] = (((uint16_t) s->temperature) >> 8);
-        s->buf[s->len ++] = (((uint16_t) s->temperature) >> 0) &
-                (0xf0 << ((~s->config >> 5) & 3));             /* R */
-        break;
-
-    case TMP105_REG_CONFIG:
-        s->buf[s->len ++] = s->config;
-        break;
-
-    case TMP105_REG_T_LOW:
-        s->buf[s->len ++] = ((uint16_t) s->limit[0]) >> 8;
-        s->buf[s->len ++] = ((uint16_t) s->limit[0]) >> 0;
-        break;
-
-    case TMP105_REG_T_HIGH:
-        s->buf[s->len ++] = ((uint16_t) s->limit[1]) >> 8;
-        s->buf[s->len ++] = ((uint16_t) s->limit[1]) >> 0;
-        break;
-    }
-}
-
-static void tmp105_write(TMP105State *s)
-{
-    switch (s->pointer & 3) {
-    case TMP105_REG_TEMPERATURE:
-        break;
-
-    case TMP105_REG_CONFIG:
-        if (s->buf[0] & ~s->config & (1 << 0))                 /* SD */
-            printf("%s: TMP105 shutdown\n", __FUNCTION__);
-        s->config = s->buf[0];
-        s->faults = tmp105_faultq[(s->config >> 3) & 3];       /* F */
-        tmp105_alarm_update(s);
-        break;
-
-    case TMP105_REG_T_LOW:
-    case TMP105_REG_T_HIGH:
-        if (s->len >= 3)
-            s->limit[s->pointer & 1] = (int16_t)
-                    ((((uint16_t) s->buf[0]) << 8) | s->buf[1]);
-        tmp105_alarm_update(s);
-        break;
-    }
-}
-
-static int tmp105_rx(I2CSlave *i2c)
-{
-    TMP105State *s = TMP105(i2c);
-
-    if (s->len < 2) {
-        return s->buf[s->len ++];
-    } else {
-        return 0xff;
-    }
-}
-
-static int tmp105_tx(I2CSlave *i2c, uint8_t data)
-{
-    TMP105State *s = TMP105(i2c);
-
-    if (s->len == 0) {
-        s->pointer = data;
-        s->len++;
-    } else {
-        if (s->len <= 2) {
-            s->buf[s->len - 1] = data;
-        }
-        s->len++;
-        tmp105_write(s);
-    }
-
-    return 0;
-}
-
-static void tmp105_event(I2CSlave *i2c, enum i2c_event event)
-{
-    TMP105State *s = TMP105(i2c);
-
-    if (event == I2C_START_RECV) {
-        tmp105_read(s);
-    }
-
-    s->len = 0;
-}
-
-static int tmp105_post_load(void *opaque, int version_id)
-{
-    TMP105State *s = opaque;
-
-    s->faults = tmp105_faultq[(s->config >> 3) & 3];           /* F */
-
-    tmp105_interrupt_update(s);
-    return 0;
-}
-
-static const VMStateDescription vmstate_tmp105 = {
-    .name = "TMP105",
-    .version_id = 0,
-    .minimum_version_id = 0,
-    .minimum_version_id_old = 0,
-    .post_load = tmp105_post_load,
-    .fields      = (VMStateField []) {
-        VMSTATE_UINT8(len, TMP105State),
-        VMSTATE_UINT8_ARRAY(buf, TMP105State, 2),
-        VMSTATE_UINT8(pointer, TMP105State),
-        VMSTATE_UINT8(config, TMP105State),
-        VMSTATE_INT16(temperature, TMP105State),
-        VMSTATE_INT16_ARRAY(limit, TMP105State, 2),
-        VMSTATE_UINT8(alarm, TMP105State),
-        VMSTATE_I2C_SLAVE(i2c, TMP105State),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void tmp105_reset(I2CSlave *i2c)
-{
-    TMP105State *s = TMP105(i2c);
-
-    s->temperature = 0;
-    s->pointer = 0;
-    s->config = 0;
-    s->faults = tmp105_faultq[(s->config >> 3) & 3];
-    s->alarm = 0;
-
-    tmp105_interrupt_update(s);
-}
-
-static int tmp105_init(I2CSlave *i2c)
-{
-    TMP105State *s = TMP105(i2c);
-
-    qdev_init_gpio_out(&i2c->qdev, &s->pin, 1);
-
-    tmp105_reset(&s->i2c);
-
-    return 0;
-}
-
-static void tmp105_initfn(Object *obj)
-{
-    object_property_add(obj, "temperature", "int",
-                        tmp105_get_temperature,
-                        tmp105_set_temperature, NULL, NULL, NULL);
-}
-
-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 const TypeInfo tmp105_info = {
-    .name          = TYPE_TMP105,
-    .parent        = TYPE_I2C_SLAVE,
-    .instance_size = sizeof(TMP105State),
-    .instance_init = tmp105_initfn,
-    .class_init    = tmp105_class_init,
-};
-
-static void tmp105_register_types(void)
-{
-    type_register_static(&tmp105_info);
-}
-
-type_init(tmp105_register_types)
diff --git a/hw/tmp105.h b/hw/tmp105.h
deleted file mode 100644 (file)
index 9a9632c..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Texas Instruments TMP105 Temperature Sensor
- *
- * Browse the data sheet:
- *
- *    http://www.ti.com/lit/gpn/tmp105
- *
- * Copyright (C) 2012 Alex Horn <alex.horn@cs.ox.ac.uk>
- * Copyright (C) 2008-2012 Andrzej Zaborowski <balrogg@gmail.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_TMP105_H
-#define QEMU_TMP105_H
-
-#include "hw/i2c.h"
-#include "hw/tmp105_regs.h"
-
-#define TYPE_TMP105 "tmp105"
-#define TMP105(obj) OBJECT_CHECK(TMP105State, (obj), TYPE_TMP105)
-
-/**
- * TMP105State:
- * @config: Bits 5 and 6 (value 32 and 64) determine the precision of the
- * temperature. See Table 8 in the data sheet.
- *
- * @see_also: http://www.ti.com/lit/gpn/tmp105
- */
-typedef struct TMP105State {
-    /*< private >*/
-    I2CSlave i2c;
-    /*< public >*/
-
-    uint8_t len;
-    uint8_t buf[2];
-    qemu_irq pin;
-
-    uint8_t pointer;
-    uint8_t config;
-    int16_t temperature;
-    int16_t limit[2];
-    int faults;
-    uint8_t alarm;
-} TMP105State;
-
-#endif
diff --git a/hw/tmp105_regs.h b/hw/tmp105_regs.h
deleted file mode 100644 (file)
index 9b55aba..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Texas Instruments TMP105 Temperature Sensor I2C messages
- *
- * Browse the data sheet:
- *
- *    http://www.ti.com/lit/gpn/tmp105
- *
- * Copyright (C) 2012 Alex Horn <alex.horn@cs.ox.ac.uk>
- * Copyright (C) 2008-2012 Andrzej Zaborowski <balrogg@gmail.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_TMP105_MSGS_H
-#define QEMU_TMP105_MSGS_H
-
-/**
- * TMP105Reg:
- * @TMP105_REG_TEMPERATURE: Temperature register
- * @TMP105_REG_CONFIG: Configuration register
- * @TMP105_REG_T_LOW: Low temperature register (also known as T_hyst)
- * @TMP105_REG_T_HIGH: High temperature register (also known as T_OS)
- *
- * The following temperature sensors are
- * compatible with the TMP105 registers:
- * - adt75
- * - ds1775
- * - ds75
- * - lm75
- * - lm75a
- * - max6625
- * - max6626
- * - mcp980x
- * - stds75
- * - tcn75
- * - tmp100
- * - tmp101
- * - tmp105
- * - tmp175
- * - tmp275
- * - tmp75
- **/
-typedef enum TMP105Reg {
-    TMP105_REG_TEMPERATURE = 0,
-    TMP105_REG_CONFIG,
-    TMP105_REG_T_LOW,
-    TMP105_REG_T_HIGH,
-} TMP105Reg;
-
-#endif
diff --git a/hw/tpci200.c b/hw/tpci200.c
deleted file mode 100644 (file)
index e3408ef..0000000
+++ /dev/null
@@ -1,671 +0,0 @@
-/*
- * QEMU TEWS TPCI200 IndustryPack carrier emulation
- *
- * Copyright (C) 2012 Igalia, S.L.
- * Author: Alberto Garcia <agarcia@igalia.com>
- *
- * This code is licensed under the GNU GPL v2 or (at your option) any
- * later version.
- */
-
-#include "hw/ipack.h"
-#include "hw/pci/pci.h"
-#include "qemu/bitops.h"
-#include <stdio.h>
-
-/* #define DEBUG_TPCI */
-
-#ifdef DEBUG_TPCI
-#define DPRINTF(fmt, ...) \
-    do { fprintf(stderr, "TPCI200: " fmt, ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...) do { } while (0)
-#endif
-
-#define N_MODULES 4
-
-#define IP_ID_SPACE  2
-#define IP_INT_SPACE 3
-#define IP_IO_SPACE_ADDR_MASK  0x7F
-#define IP_ID_SPACE_ADDR_MASK  0x3F
-#define IP_INT_SPACE_ADDR_MASK 0x3F
-
-#define STATUS_INT(IP, INTNO) BIT((IP) * 2 + (INTNO))
-#define STATUS_TIME(IP)       BIT((IP) + 12)
-#define STATUS_ERR_ANY        0xF00
-
-#define CTRL_CLKRATE          BIT(0)
-#define CTRL_RECOVER          BIT(1)
-#define CTRL_TIME_INT         BIT(2)
-#define CTRL_ERR_INT          BIT(3)
-#define CTRL_INT_EDGE(INTNO)  BIT(4 + (INTNO))
-#define CTRL_INT(INTNO)       BIT(6 + (INTNO))
-
-#define REG_REV_ID    0x00
-#define REG_IP_A_CTRL 0x02
-#define REG_IP_B_CTRL 0x04
-#define REG_IP_C_CTRL 0x06
-#define REG_IP_D_CTRL 0x08
-#define REG_RESET     0x0A
-#define REG_STATUS    0x0C
-#define IP_N_FROM_REG(REG) ((REG) / 2 - 1)
-
-typedef struct {
-    PCIDevice dev;
-    IPackBus bus;
-    MemoryRegion mmio;
-    MemoryRegion io;
-    MemoryRegion las0;
-    MemoryRegion las1;
-    MemoryRegion las2;
-    MemoryRegion las3;
-    bool big_endian[3];
-    uint8_t ctrl[N_MODULES];
-    uint16_t status;
-    uint8_t int_set;
-} TPCI200State;
-
-#define TYPE_TPCI200 "tpci200"
-
-#define TPCI200(obj) \
-    OBJECT_CHECK(TPCI200State, (obj), TYPE_TPCI200)
-
-static const uint8_t local_config_regs[] = {
-    0x00, 0xFF, 0xFF, 0x0F, 0x00, 0xFC, 0xFF, 0x0F, 0x00, 0x00, 0x00,
-    0x0E, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
-    0x00, 0x08, 0x01, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00, 0x00, 0x01,
-    0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0xA0, 0x60, 0x41, 0xD4,
-    0xA2, 0x20, 0x41, 0x14, 0xA2, 0x20, 0x41, 0x14, 0xA2, 0x20, 0x01,
-    0x14, 0x00, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x08, 0x01, 0x02,
-    0x00, 0x04, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x80, 0x02, 0x41,
-    0x00, 0x00, 0x00, 0x00, 0x40, 0x7A, 0x00, 0x52, 0x92, 0x24, 0x02
-};
-
-static void adjust_addr(bool big_endian, hwaddr *addr, unsigned size)
-{
-    /* During 8 bit access in big endian mode,
-       odd and even addresses are swapped */
-    if (big_endian && size == 1) {
-        *addr ^= 1;
-    }
-}
-
-static uint64_t adjust_value(bool big_endian, uint64_t *val, unsigned size)
-{
-    /* Local spaces only support 8/16 bit access,
-     * so there's no need to care for sizes > 2 */
-    if (big_endian && size == 2) {
-        *val = bswap16(*val);
-    }
-    return *val;
-}
-
-static void tpci200_set_irq(void *opaque, int intno, int level)
-{
-    IPackDevice *ip = opaque;
-    IPackBus *bus = IPACK_BUS(qdev_get_parent_bus(DEVICE(ip)));
-    PCIDevice *pcidev = PCI_DEVICE(BUS(bus)->parent);
-    TPCI200State *dev = TPCI200(pcidev);
-    unsigned ip_n = ip->slot;
-    uint16_t prev_status = dev->status;
-
-    assert(ip->slot >= 0 && ip->slot < N_MODULES);
-
-    /* The requested interrupt must be enabled in the IP CONTROL
-     * register */
-    if (!(dev->ctrl[ip_n] & CTRL_INT(intno))) {
-        return;
-    }
-
-    /* Update the interrupt status in the IP STATUS register */
-    if (level) {
-        dev->status |=  STATUS_INT(ip_n, intno);
-    } else {
-        dev->status &= ~STATUS_INT(ip_n, intno);
-    }
-
-    /* Return if there are no changes */
-    if (dev->status == prev_status) {
-        return;
-    }
-
-    DPRINTF("IP %u INT%u#: %u\n", ip_n, intno, level);
-
-    /* Check if the interrupt is edge sensitive */
-    if (dev->ctrl[ip_n] & CTRL_INT_EDGE(intno)) {
-        if (level) {
-            qemu_set_irq(dev->dev.irq[0], !dev->int_set);
-            qemu_set_irq(dev->dev.irq[0],  dev->int_set);
-        }
-    } else {
-        unsigned i, j;
-        uint16_t level_status = dev->status;
-
-        /* Check if there are any level sensitive interrupts set by
-           removing the ones that are edge sensitive from the status
-           register */
-        for (i = 0; i < N_MODULES; i++) {
-            for (j = 0; j < 2; j++) {
-                if (dev->ctrl[i] & CTRL_INT_EDGE(j)) {
-                    level_status &= ~STATUS_INT(i, j);
-                }
-            }
-        }
-
-        if (level_status && !dev->int_set) {
-            qemu_irq_raise(dev->dev.irq[0]);
-            dev->int_set = 1;
-        } else if (!level_status && dev->int_set) {
-            qemu_irq_lower(dev->dev.irq[0]);
-            dev->int_set = 0;
-        }
-    }
-}
-
-static uint64_t tpci200_read_cfg(void *opaque, hwaddr addr, unsigned size)
-{
-    TPCI200State *s = opaque;
-    uint8_t ret = 0;
-    if (addr < ARRAY_SIZE(local_config_regs)) {
-        ret = local_config_regs[addr];
-    }
-    /* Endianness is stored in the first bit of these registers */
-    if ((addr == 0x2b && s->big_endian[0]) ||
-        (addr == 0x2f && s->big_endian[1]) ||
-        (addr == 0x33 && s->big_endian[2])) {
-        ret |= 1;
-    }
-    DPRINTF("Read from LCR 0x%x: 0x%x\n", (unsigned) addr, (unsigned) ret);
-    return ret;
-}
-
-static void tpci200_write_cfg(void *opaque, hwaddr addr, uint64_t val,
-                              unsigned size)
-{
-    TPCI200State *s = opaque;
-    /* Endianness is stored in the first bit of these registers */
-    if (addr == 0x2b || addr == 0x2f || addr == 0x33) {
-        unsigned las = (addr - 0x2b) / 4;
-        s->big_endian[las] = val & 1;
-        DPRINTF("LAS%u big endian mode: %u\n", las, (unsigned) val & 1);
-    } else {
-        DPRINTF("Write to LCR 0x%x: 0x%x\n", (unsigned) addr, (unsigned) val);
-    }
-}
-
-static uint64_t tpci200_read_las0(void *opaque, hwaddr addr, unsigned size)
-{
-    TPCI200State *s = opaque;
-    uint64_t ret = 0;
-
-    switch (addr) {
-
-    case REG_REV_ID:
-        DPRINTF("Read REVISION ID\n"); /* Current value is 0x00 */
-        break;
-
-    case REG_IP_A_CTRL:
-    case REG_IP_B_CTRL:
-    case REG_IP_C_CTRL:
-    case REG_IP_D_CTRL:
-        {
-            unsigned ip_n = IP_N_FROM_REG(addr);
-            ret = s->ctrl[ip_n];
-            DPRINTF("Read IP %c CONTROL: 0x%x\n", 'A' + ip_n, (unsigned) ret);
-        }
-        break;
-
-    case REG_RESET:
-        DPRINTF("Read RESET\n"); /* Not implemented */
-        break;
-
-    case REG_STATUS:
-        ret = s->status;
-        DPRINTF("Read STATUS: 0x%x\n", (unsigned) ret);
-        break;
-
-    /* Reserved */
-    default:
-        DPRINTF("Unsupported read from LAS0 0x%x\n", (unsigned) addr);
-        break;
-    }
-
-    return adjust_value(s->big_endian[0], &ret, size);
-}
-
-static void tpci200_write_las0(void *opaque, hwaddr addr, uint64_t val,
-                               unsigned size)
-{
-    TPCI200State *s = opaque;
-
-    adjust_value(s->big_endian[0], &val, size);
-
-    switch (addr) {
-
-    case REG_REV_ID:
-        DPRINTF("Write Revision ID: 0x%x\n", (unsigned) val); /* No effect */
-        break;
-
-    case REG_IP_A_CTRL:
-    case REG_IP_B_CTRL:
-    case REG_IP_C_CTRL:
-    case REG_IP_D_CTRL:
-        {
-            unsigned ip_n = IP_N_FROM_REG(addr);
-            s->ctrl[ip_n] = val;
-            DPRINTF("Write IP %c CONTROL: 0x%x\n", 'A' + ip_n, (unsigned) val);
-        }
-        break;
-
-    case REG_RESET:
-        DPRINTF("Write RESET: 0x%x\n", (unsigned) val); /* Not implemented */
-        break;
-
-    case REG_STATUS:
-        {
-            unsigned i;
-
-            for (i = 0; i < N_MODULES; i++) {
-                IPackDevice *ip = ipack_device_find(&s->bus, i);
-
-                if (ip != NULL) {
-                    if (val & STATUS_INT(i, 0)) {
-                        DPRINTF("Clear IP %c INT0# status\n", 'A' + i);
-                        qemu_irq_lower(ip->irq[0]);
-                    }
-                    if (val & STATUS_INT(i, 1)) {
-                        DPRINTF("Clear IP %c INT1# status\n", 'A' + i);
-                        qemu_irq_lower(ip->irq[1]);
-                    }
-                }
-
-                if (val & STATUS_TIME(i)) {
-                    DPRINTF("Clear IP %c timeout\n", 'A' + i);
-                    s->status &= ~STATUS_TIME(i);
-                }
-            }
-
-            if (val & STATUS_ERR_ANY) {
-                DPRINTF("Unexpected write to STATUS register: 0x%x\n",
-                        (unsigned) val);
-            }
-        }
-        break;
-
-    /* Reserved */
-    default:
-        DPRINTF("Unsupported write to LAS0 0x%x: 0x%x\n",
-                (unsigned) addr, (unsigned) val);
-        break;
-    }
-}
-
-static uint64_t tpci200_read_las1(void *opaque, hwaddr addr, unsigned size)
-{
-    TPCI200State *s = opaque;
-    IPackDevice *ip;
-    uint64_t ret = 0;
-    unsigned ip_n, space;
-    uint8_t offset;
-
-    adjust_addr(s->big_endian[1], &addr, size);
-
-    /*
-     * The address is divided into the IP module number (0-4), the IP
-     * address space (I/O, ID, INT) and the offset within that space.
-     */
-    ip_n = addr >> 8;
-    space = (addr >> 6) & 3;
-    ip = ipack_device_find(&s->bus, ip_n);
-
-    if (ip == NULL) {
-        DPRINTF("Read LAS1: IP module %u not installed\n", ip_n);
-    } else {
-        IPackDeviceClass *k = IPACK_DEVICE_GET_CLASS(ip);
-        switch (space) {
-
-        case IP_ID_SPACE:
-            offset = addr & IP_ID_SPACE_ADDR_MASK;
-            if (k->id_read) {
-                ret = k->id_read(ip, offset);
-            }
-            break;
-
-        case IP_INT_SPACE:
-            offset = addr & IP_INT_SPACE_ADDR_MASK;
-
-            /* Read address 0 to ACK IP INT0# and address 2 to ACK IP INT1# */
-            if (offset == 0 || offset == 2) {
-                unsigned intno = offset / 2;
-                bool int_set = s->status & STATUS_INT(ip_n, intno);
-                bool int_edge_sensitive = s->ctrl[ip_n] & CTRL_INT_EDGE(intno);
-                if (int_set && !int_edge_sensitive) {
-                    qemu_irq_lower(ip->irq[intno]);
-                }
-            }
-
-            if (k->int_read) {
-                ret = k->int_read(ip, offset);
-            }
-            break;
-
-        default:
-            offset = addr & IP_IO_SPACE_ADDR_MASK;
-            if (k->io_read) {
-                ret = k->io_read(ip, offset);
-            }
-            break;
-        }
-    }
-
-    return adjust_value(s->big_endian[1], &ret, size);
-}
-
-static void tpci200_write_las1(void *opaque, hwaddr addr, uint64_t val,
-                               unsigned size)
-{
-    TPCI200State *s = opaque;
-    IPackDevice *ip;
-    unsigned ip_n, space;
-    uint8_t offset;
-
-    adjust_addr(s->big_endian[1], &addr, size);
-    adjust_value(s->big_endian[1], &val, size);
-
-    /*
-     * The address is divided into the IP module number, the IP
-     * address space (I/O, ID, INT) and the offset within that space.
-     */
-    ip_n = addr >> 8;
-    space = (addr >> 6) & 3;
-    ip = ipack_device_find(&s->bus, ip_n);
-
-    if (ip == NULL) {
-        DPRINTF("Write LAS1: IP module %u not installed\n", ip_n);
-    } else {
-        IPackDeviceClass *k = IPACK_DEVICE_GET_CLASS(ip);
-        switch (space) {
-
-        case IP_ID_SPACE:
-            offset = addr & IP_ID_SPACE_ADDR_MASK;
-            if (k->id_write) {
-                k->id_write(ip, offset, val);
-            }
-            break;
-
-        case IP_INT_SPACE:
-            offset = addr & IP_INT_SPACE_ADDR_MASK;
-            if (k->int_write) {
-                k->int_write(ip, offset, val);
-            }
-            break;
-
-        default:
-            offset = addr & IP_IO_SPACE_ADDR_MASK;
-            if (k->io_write) {
-                k->io_write(ip, offset, val);
-            }
-            break;
-        }
-    }
-}
-
-static uint64_t tpci200_read_las2(void *opaque, hwaddr addr, unsigned size)
-{
-    TPCI200State *s = opaque;
-    IPackDevice *ip;
-    uint64_t ret = 0;
-    unsigned ip_n;
-    uint32_t offset;
-
-    adjust_addr(s->big_endian[2], &addr, size);
-
-    /*
-     * The address is divided into the IP module number and the offset
-     * within the IP module MEM space.
-     */
-    ip_n = addr >> 23;
-    offset = addr & 0x7fffff;
-    ip = ipack_device_find(&s->bus, ip_n);
-
-    if (ip == NULL) {
-        DPRINTF("Read LAS2: IP module %u not installed\n", ip_n);
-    } else {
-        IPackDeviceClass *k = IPACK_DEVICE_GET_CLASS(ip);
-        if (k->mem_read16) {
-            ret = k->mem_read16(ip, offset);
-        }
-    }
-
-    return adjust_value(s->big_endian[2], &ret, size);
-}
-
-static void tpci200_write_las2(void *opaque, hwaddr addr, uint64_t val,
-                               unsigned size)
-{
-    TPCI200State *s = opaque;
-    IPackDevice *ip;
-    unsigned ip_n;
-    uint32_t offset;
-
-    adjust_addr(s->big_endian[2], &addr, size);
-    adjust_value(s->big_endian[2], &val, size);
-
-    /*
-     * The address is divided into the IP module number and the offset
-     * within the IP module MEM space.
-     */
-    ip_n = addr >> 23;
-    offset = addr & 0x7fffff;
-    ip = ipack_device_find(&s->bus, ip_n);
-
-    if (ip == NULL) {
-        DPRINTF("Write LAS2: IP module %u not installed\n", ip_n);
-    } else {
-        IPackDeviceClass *k = IPACK_DEVICE_GET_CLASS(ip);
-        if (k->mem_write16) {
-            k->mem_write16(ip, offset, val);
-        }
-    }
-}
-
-static uint64_t tpci200_read_las3(void *opaque, hwaddr addr, unsigned size)
-{
-    TPCI200State *s = opaque;
-    IPackDevice *ip;
-    uint64_t ret = 0;
-    /*
-     * The address is divided into the IP module number and the offset
-     * within the IP module MEM space.
-     */
-    unsigned ip_n = addr >> 22;
-    uint32_t offset = addr & 0x3fffff;
-
-    ip = ipack_device_find(&s->bus, ip_n);
-
-    if (ip == NULL) {
-        DPRINTF("Read LAS3: IP module %u not installed\n", ip_n);
-    } else {
-        IPackDeviceClass *k = IPACK_DEVICE_GET_CLASS(ip);
-        if (k->mem_read8) {
-            ret = k->mem_read8(ip, offset);
-        }
-    }
-
-    return ret;
-}
-
-static void tpci200_write_las3(void *opaque, hwaddr addr, uint64_t val,
-                               unsigned size)
-{
-    TPCI200State *s = opaque;
-    IPackDevice *ip;
-    /*
-     * The address is divided into the IP module number and the offset
-     * within the IP module MEM space.
-     */
-    unsigned ip_n = addr >> 22;
-    uint32_t offset = addr & 0x3fffff;
-
-    ip = ipack_device_find(&s->bus, ip_n);
-
-    if (ip == NULL) {
-        DPRINTF("Write LAS3: IP module %u not installed\n", ip_n);
-    } else {
-        IPackDeviceClass *k = IPACK_DEVICE_GET_CLASS(ip);
-        if (k->mem_write8) {
-            k->mem_write8(ip, offset, val);
-        }
-    }
-}
-
-static const MemoryRegionOps tpci200_cfg_ops = {
-    .read = tpci200_read_cfg,
-    .write = tpci200_write_cfg,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid =  {
-        .min_access_size = 1,
-        .max_access_size = 4
-    },
-    .impl = {
-        .min_access_size = 1,
-        .max_access_size = 1
-    }
-};
-
-static const MemoryRegionOps tpci200_las0_ops = {
-    .read = tpci200_read_las0,
-    .write = tpci200_write_las0,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid =  {
-        .min_access_size = 2,
-        .max_access_size = 2
-    }
-};
-
-static const MemoryRegionOps tpci200_las1_ops = {
-    .read = tpci200_read_las1,
-    .write = tpci200_write_las1,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid =  {
-        .min_access_size = 1,
-        .max_access_size = 2
-    }
-};
-
-static const MemoryRegionOps tpci200_las2_ops = {
-    .read = tpci200_read_las2,
-    .write = tpci200_write_las2,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid =  {
-        .min_access_size = 1,
-        .max_access_size = 2
-    }
-};
-
-static const MemoryRegionOps tpci200_las3_ops = {
-    .read = tpci200_read_las3,
-    .write = tpci200_write_las3,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid =  {
-        .min_access_size = 1,
-        .max_access_size = 1
-    }
-};
-
-static int tpci200_initfn(PCIDevice *pci_dev)
-{
-    TPCI200State *s = TPCI200(pci_dev);
-    uint8_t *c = s->dev.config;
-
-    pci_set_word(c + PCI_COMMAND, 0x0003);
-    pci_set_word(c + PCI_STATUS,  0x0280);
-
-    pci_set_byte(c + PCI_INTERRUPT_PIN, 0x01); /* Interrupt pin A */
-
-    pci_set_byte(c + PCI_CAPABILITY_LIST, 0x40);
-    pci_set_long(c + 0x40, 0x48014801);
-    pci_set_long(c + 0x48, 0x00024C06);
-    pci_set_long(c + 0x4C, 0x00000003);
-
-    memory_region_init_io(&s->mmio, &tpci200_cfg_ops,
-                          s, "tpci200_mmio", 128);
-    memory_region_init_io(&s->io,   &tpci200_cfg_ops,
-                          s, "tpci200_io",   128);
-    memory_region_init_io(&s->las0, &tpci200_las0_ops,
-                          s, "tpci200_las0", 256);
-    memory_region_init_io(&s->las1, &tpci200_las1_ops,
-                          s, "tpci200_las1", 1024);
-    memory_region_init_io(&s->las2, &tpci200_las2_ops,
-                          s, "tpci200_las2", 1024*1024*32);
-    memory_region_init_io(&s->las3, &tpci200_las3_ops,
-                          s, "tpci200_las3", 1024*1024*16);
-    pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mmio);
-    pci_register_bar(&s->dev, 1, PCI_BASE_ADDRESS_SPACE_IO,     &s->io);
-    pci_register_bar(&s->dev, 2, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->las0);
-    pci_register_bar(&s->dev, 3, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->las1);
-    pci_register_bar(&s->dev, 4, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->las2);
-    pci_register_bar(&s->dev, 5, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->las3);
-
-    ipack_bus_new_inplace(&s->bus, DEVICE(&s->dev), NULL,
-                          N_MODULES, tpci200_set_irq);
-
-    return 0;
-}
-
-static void tpci200_exitfn(PCIDevice *pci_dev)
-{
-    TPCI200State *s = TPCI200(pci_dev);
-
-    memory_region_destroy(&s->mmio);
-    memory_region_destroy(&s->io);
-    memory_region_destroy(&s->las0);
-    memory_region_destroy(&s->las1);
-    memory_region_destroy(&s->las2);
-    memory_region_destroy(&s->las3);
-}
-
-static const VMStateDescription vmstate_tpci200 = {
-    .name = "tpci200",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField[]) {
-        VMSTATE_PCI_DEVICE(dev, TPCI200State),
-        VMSTATE_BOOL_ARRAY(big_endian, TPCI200State, 3),
-        VMSTATE_UINT8_ARRAY(ctrl, TPCI200State, N_MODULES),
-        VMSTATE_UINT16(status, TPCI200State),
-        VMSTATE_UINT8(int_set, TPCI200State),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void tpci200_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
-    k->init = tpci200_initfn;
-    k->exit = tpci200_exitfn;
-    k->vendor_id = PCI_VENDOR_ID_TEWS;
-    k->device_id = PCI_DEVICE_ID_TEWS_TPCI200;
-    k->class_id = PCI_CLASS_BRIDGE_OTHER;
-    k->subsystem_vendor_id = PCI_VENDOR_ID_TEWS;
-    k->subsystem_id = 0x300A;
-    dc->desc = "TEWS TPCI200 IndustryPack carrier";
-    dc->vmsd = &vmstate_tpci200;
-}
-
-static const TypeInfo tpci200_info = {
-    .name          = TYPE_TPCI200,
-    .parent        = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(TPCI200State),
-    .class_init    = tpci200_class_init,
-};
-
-static void tpci200_register_types(void)
-{
-    type_register_static(&tpci200_info);
-}
-
-type_init(tpci200_register_types)
diff --git a/hw/tsc2005.c b/hw/tsc2005.c
deleted file mode 100644 (file)
index a771cd5..0000000
+++ /dev/null
@@ -1,593 +0,0 @@
-/*
- * TI TSC2005 emulator.
- *
- * Copyright (c) 2006 Andrzej Zaborowski  <balrog@zabor.org>
- * Copyright (C) 2008 Nokia Corporation
- *
- * 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 or
- * (at your option) version 3 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
- * 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 "hw/hw.h"
-#include "qemu/timer.h"
-#include "ui/console.h"
-#include "hw/devices.h"
-
-#define TSC_CUT_RESOLUTION(value, p)   ((value) >> (16 - (p ? 12 : 10)))
-
-typedef struct {
-    qemu_irq pint;     /* Combination of the nPENIRQ and DAV signals */
-    QEMUTimer *timer;
-    uint16_t model;
-
-    int x, y;
-    int pressure;
-
-    int state, reg, irq, command;
-    uint16_t data, dav;
-
-    int busy;
-    int enabled;
-    int host_mode;
-    int function;
-    int nextfunction;
-    int precision;
-    int nextprecision;
-    int filter;
-    int pin_func;
-    int timing[2];
-    int noise;
-    int reset;
-    int pdst;
-    int pnd0;
-    uint16_t temp_thr[2];
-    uint16_t aux_thr[2];
-
-    int tr[8];
-} TSC2005State;
-
-enum {
-    TSC_MODE_XYZ_SCAN  = 0x0,
-    TSC_MODE_XY_SCAN,
-    TSC_MODE_X,
-    TSC_MODE_Y,
-    TSC_MODE_Z,
-    TSC_MODE_AUX,
-    TSC_MODE_TEMP1,
-    TSC_MODE_TEMP2,
-    TSC_MODE_AUX_SCAN,
-    TSC_MODE_X_TEST,
-    TSC_MODE_Y_TEST,
-    TSC_MODE_TS_TEST,
-    TSC_MODE_RESERVED,
-    TSC_MODE_XX_DRV,
-    TSC_MODE_YY_DRV,
-    TSC_MODE_YX_DRV,
-};
-
-static const uint16_t mode_regs[16] = {
-    0xf000,    /* X, Y, Z scan */
-    0xc000,    /* X, Y scan */
-    0x8000,    /* X */
-    0x4000,    /* Y */
-    0x3000,    /* Z */
-    0x0800,    /* AUX */
-    0x0400,    /* TEMP1 */
-    0x0200,    /* TEMP2 */
-    0x0800,    /* AUX scan */
-    0x0040,    /* X test */
-    0x0020,    /* Y test */
-    0x0080,    /* Short-circuit test */
-    0x0000,    /* Reserved */
-    0x0000,    /* X+, X- drivers */
-    0x0000,    /* Y+, Y- drivers */
-    0x0000,    /* Y+, X- drivers */
-};
-
-#define X_TRANSFORM(s)                 \
-    ((s->y * s->tr[0] - s->x * s->tr[1]) / s->tr[2] + s->tr[3])
-#define Y_TRANSFORM(s)                 \
-    ((s->y * s->tr[4] - s->x * s->tr[5]) / s->tr[6] + s->tr[7])
-#define Z1_TRANSFORM(s)                        \
-    ((400 - ((s)->x >> 7) + ((s)->pressure << 10)) << 4)
-#define Z2_TRANSFORM(s)                        \
-    ((4000 + ((s)->y >> 7) - ((s)->pressure << 10)) << 4)
-
-#define AUX_VAL                                (700 << 4)      /* +/- 3 at 12-bit */
-#define TEMP1_VAL                      (1264 << 4)     /* +/- 5 at 12-bit */
-#define TEMP2_VAL                      (1531 << 4)     /* +/- 5 at 12-bit */
-
-static uint16_t tsc2005_read(TSC2005State *s, int reg)
-{
-    uint16_t ret;
-
-    switch (reg) {
-    case 0x0:  /* X */
-        s->dav &= ~mode_regs[TSC_MODE_X];
-        return TSC_CUT_RESOLUTION(X_TRANSFORM(s), s->precision) +
-                (s->noise & 3);
-    case 0x1:  /* Y */
-        s->dav &= ~mode_regs[TSC_MODE_Y];
-        s->noise ++;
-        return TSC_CUT_RESOLUTION(Y_TRANSFORM(s), s->precision) ^
-                (s->noise & 3);
-    case 0x2:  /* Z1 */
-        s->dav &= 0xdfff;
-        return TSC_CUT_RESOLUTION(Z1_TRANSFORM(s), s->precision) -
-                (s->noise & 3);
-    case 0x3:  /* Z2 */
-        s->dav &= 0xefff;
-        return TSC_CUT_RESOLUTION(Z2_TRANSFORM(s), s->precision) |
-                (s->noise & 3);
-
-    case 0x4:  /* AUX */
-        s->dav &= ~mode_regs[TSC_MODE_AUX];
-        return TSC_CUT_RESOLUTION(AUX_VAL, s->precision);
-
-    case 0x5:  /* TEMP1 */
-        s->dav &= ~mode_regs[TSC_MODE_TEMP1];
-        return TSC_CUT_RESOLUTION(TEMP1_VAL, s->precision) -
-                (s->noise & 5);
-    case 0x6:  /* TEMP2 */
-        s->dav &= 0xdfff;
-        s->dav &= ~mode_regs[TSC_MODE_TEMP2];
-        return TSC_CUT_RESOLUTION(TEMP2_VAL, s->precision) ^
-                (s->noise & 3);
-
-    case 0x7:  /* Status */
-        ret = s->dav | (s->reset << 7) | (s->pdst << 2) | 0x0;
-        s->dav &= ~(mode_regs[TSC_MODE_X_TEST] | mode_regs[TSC_MODE_Y_TEST] |
-                        mode_regs[TSC_MODE_TS_TEST]);
-        s->reset = 1;
-        return ret;
-
-    case 0x8:  /* AUX high treshold */
-        return s->aux_thr[1];
-    case 0x9:  /* AUX low treshold */
-        return s->aux_thr[0];
-
-    case 0xa:  /* TEMP high treshold */
-        return s->temp_thr[1];
-    case 0xb:  /* TEMP low treshold */
-        return s->temp_thr[0];
-
-    case 0xc:  /* CFR0 */
-        return (s->pressure << 15) | ((!s->busy) << 14) |
-                (s->nextprecision << 13) | s->timing[0]; 
-    case 0xd:  /* CFR1 */
-        return s->timing[1];
-    case 0xe:  /* CFR2 */
-        return (s->pin_func << 14) | s->filter;
-
-    case 0xf:  /* Function select status */
-        return s->function >= 0 ? 1 << s->function : 0;
-    }
-
-    /* Never gets here */
-    return 0xffff;
-}
-
-static void tsc2005_write(TSC2005State *s, int reg, uint16_t data)
-{
-    switch (reg) {
-    case 0x8:  /* AUX high treshold */
-        s->aux_thr[1] = data;
-        break;
-    case 0x9:  /* AUX low treshold */
-        s->aux_thr[0] = data;
-        break;
-
-    case 0xa:  /* TEMP high treshold */
-        s->temp_thr[1] = data;
-        break;
-    case 0xb:  /* TEMP low treshold */
-        s->temp_thr[0] = data;
-        break;
-
-    case 0xc:  /* CFR0 */
-        s->host_mode = data >> 15;
-        if (s->enabled != !(data & 0x4000)) {
-            s->enabled = !(data & 0x4000);
-            fprintf(stderr, "%s: touchscreen sense %sabled\n",
-                            __FUNCTION__, s->enabled ? "en" : "dis");
-            if (s->busy && !s->enabled)
-                qemu_del_timer(s->timer);
-            s->busy &= s->enabled;
-        }
-        s->nextprecision = (data >> 13) & 1;
-        s->timing[0] = data & 0x1fff;
-        if ((s->timing[0] >> 11) == 3)
-            fprintf(stderr, "%s: illegal conversion clock setting\n",
-                            __FUNCTION__);
-        break;
-    case 0xd:  /* CFR1 */
-        s->timing[1] = data & 0xf07;
-        break;
-    case 0xe:  /* CFR2 */
-        s->pin_func = (data >> 14) & 3;
-        s->filter = data & 0x3fff;
-        break;
-
-    default:
-        fprintf(stderr, "%s: write into read-only register %x\n",
-                        __FUNCTION__, reg);
-    }
-}
-
-/* This handles most of the chip's logic.  */
-static void tsc2005_pin_update(TSC2005State *s)
-{
-    int64_t expires;
-    int pin_state;
-
-    switch (s->pin_func) {
-    case 0:
-        pin_state = !s->pressure && !!s->dav;
-        break;
-    case 1:
-    case 3:
-    default:
-        pin_state = !s->dav;
-        break;
-    case 2:
-        pin_state = !s->pressure;
-    }
-
-    if (pin_state != s->irq) {
-        s->irq = pin_state;
-        qemu_set_irq(s->pint, s->irq);
-    }
-
-    switch (s->nextfunction) {
-    case TSC_MODE_XYZ_SCAN:
-    case TSC_MODE_XY_SCAN:
-        if (!s->host_mode && s->dav)
-            s->enabled = 0;
-        if (!s->pressure)
-            return;
-        /* Fall through */
-    case TSC_MODE_AUX_SCAN:
-        break;
-
-    case TSC_MODE_X:
-    case TSC_MODE_Y:
-    case TSC_MODE_Z:
-        if (!s->pressure)
-            return;
-        /* Fall through */
-    case TSC_MODE_AUX:
-    case TSC_MODE_TEMP1:
-    case TSC_MODE_TEMP2:
-    case TSC_MODE_X_TEST:
-    case TSC_MODE_Y_TEST:
-    case TSC_MODE_TS_TEST:
-        if (s->dav)
-            s->enabled = 0;
-        break;
-
-    case TSC_MODE_RESERVED:
-    case TSC_MODE_XX_DRV:
-    case TSC_MODE_YY_DRV:
-    case TSC_MODE_YX_DRV:
-    default:
-        return;
-    }
-
-    if (!s->enabled || s->busy)
-        return;
-
-    s->busy = 1;
-    s->precision = s->nextprecision;
-    s->function = s->nextfunction;
-    s->pdst = !s->pnd0;        /* Synchronised on internal clock */
-    expires = qemu_get_clock_ns(vm_clock) + (get_ticks_per_sec() >> 7);
-    qemu_mod_timer(s->timer, expires);
-}
-
-static void tsc2005_reset(TSC2005State *s)
-{
-    s->state = 0;
-    s->pin_func = 0;
-    s->enabled = 0;
-    s->busy = 0;
-    s->nextprecision = 0;
-    s->nextfunction = 0;
-    s->timing[0] = 0;
-    s->timing[1] = 0;
-    s->irq = 0;
-    s->dav = 0;
-    s->reset = 0;
-    s->pdst = 1;
-    s->pnd0 = 0;
-    s->function = -1;
-    s->temp_thr[0] = 0x000;
-    s->temp_thr[1] = 0xfff;
-    s->aux_thr[0] = 0x000;
-    s->aux_thr[1] = 0xfff;
-
-    tsc2005_pin_update(s);
-}
-
-static uint8_t tsc2005_txrx_word(void *opaque, uint8_t value)
-{
-    TSC2005State *s = opaque;
-    uint32_t ret = 0;
-
-    switch (s->state ++) {
-    case 0:
-        if (value & 0x80) {
-            /* Command */
-            if (value & (1 << 1))
-                tsc2005_reset(s);
-            else {
-                s->nextfunction = (value >> 3) & 0xf;
-                s->nextprecision = (value >> 2) & 1;
-                if (s->enabled != !(value & 1)) {
-                    s->enabled = !(value & 1);
-                    fprintf(stderr, "%s: touchscreen sense %sabled\n",
-                                    __FUNCTION__, s->enabled ? "en" : "dis");
-                    if (s->busy && !s->enabled)
-                        qemu_del_timer(s->timer);
-                    s->busy &= s->enabled;
-                }
-                tsc2005_pin_update(s);
-            }
-
-            s->state = 0;
-        } else if (value) {
-            /* Data transfer */
-            s->reg = (value >> 3) & 0xf;
-            s->pnd0 = (value >> 1) & 1;
-            s->command = value & 1;
-
-            if (s->command) {
-                /* Read */
-                s->data = tsc2005_read(s, s->reg);
-                tsc2005_pin_update(s);
-            } else
-                s->data = 0;
-        } else
-            s->state = 0;
-        break;
-
-    case 1:
-        if (s->command)
-            ret = (s->data >> 8) & 0xff;
-        else
-            s->data |= value << 8;
-        break;
-
-    case 2:
-        if (s->command)
-            ret = s->data & 0xff;
-        else {
-            s->data |= value;
-            tsc2005_write(s, s->reg, s->data);
-            tsc2005_pin_update(s);
-        }
-
-        s->state = 0;
-        break;
-    }
-
-    return ret;
-}
-
-uint32_t tsc2005_txrx(void *opaque, uint32_t value, int len)
-{
-    uint32_t ret = 0;
-
-    len &= ~7;
-    while (len > 0) {
-        len -= 8;
-        ret |= tsc2005_txrx_word(opaque, (value >> len) & 0xff) << len;
-    }
-
-    return ret;
-}
-
-static void tsc2005_timer_tick(void *opaque)
-{
-    TSC2005State *s = opaque;
-
-    /* Timer ticked -- a set of conversions has been finished.  */
-
-    if (!s->busy)
-        return;
-
-    s->busy = 0;
-    s->dav |= mode_regs[s->function];
-    s->function = -1;
-    tsc2005_pin_update(s);
-}
-
-static void tsc2005_touchscreen_event(void *opaque,
-                int x, int y, int z, int buttons_state)
-{
-    TSC2005State *s = opaque;
-    int p = s->pressure;
-
-    if (buttons_state) {
-        s->x = x;
-        s->y = y;
-    }
-    s->pressure = !!buttons_state;
-
-    /*
-     * Note: We would get better responsiveness in the guest by
-     * signaling TS events immediately, but for now we simulate
-     * the first conversion delay for sake of correctness.
-     */
-    if (p != s->pressure)
-        tsc2005_pin_update(s);
-}
-
-static void tsc2005_save(QEMUFile *f, void *opaque)
-{
-    TSC2005State *s = (TSC2005State *) opaque;
-    int i;
-
-    qemu_put_be16(f, s->x);
-    qemu_put_be16(f, s->y);
-    qemu_put_byte(f, s->pressure);
-
-    qemu_put_byte(f, s->state);
-    qemu_put_byte(f, s->reg);
-    qemu_put_byte(f, s->command);
-
-    qemu_put_byte(f, s->irq);
-    qemu_put_be16s(f, &s->dav);
-    qemu_put_be16s(f, &s->data);
-
-    qemu_put_timer(f, s->timer);
-    qemu_put_byte(f, s->enabled);
-    qemu_put_byte(f, s->host_mode);
-    qemu_put_byte(f, s->function);
-    qemu_put_byte(f, s->nextfunction);
-    qemu_put_byte(f, s->precision);
-    qemu_put_byte(f, s->nextprecision);
-    qemu_put_be16(f, s->filter);
-    qemu_put_byte(f, s->pin_func);
-    qemu_put_be16(f, s->timing[0]);
-    qemu_put_be16(f, s->timing[1]);
-    qemu_put_be16s(f, &s->temp_thr[0]);
-    qemu_put_be16s(f, &s->temp_thr[1]);
-    qemu_put_be16s(f, &s->aux_thr[0]);
-    qemu_put_be16s(f, &s->aux_thr[1]);
-    qemu_put_be32(f, s->noise);
-    qemu_put_byte(f, s->reset);
-    qemu_put_byte(f, s->pdst);
-    qemu_put_byte(f, s->pnd0);
-
-    for (i = 0; i < 8; i ++)
-        qemu_put_be32(f, s->tr[i]);
-}
-
-static int tsc2005_load(QEMUFile *f, void *opaque, int version_id)
-{
-    TSC2005State *s = (TSC2005State *) opaque;
-    int i;
-
-    s->x = qemu_get_be16(f);
-    s->y = qemu_get_be16(f);
-    s->pressure = qemu_get_byte(f);
-
-    s->state = qemu_get_byte(f);
-    s->reg = qemu_get_byte(f);
-    s->command = qemu_get_byte(f);
-
-    s->irq = qemu_get_byte(f);
-    qemu_get_be16s(f, &s->dav);
-    qemu_get_be16s(f, &s->data);
-
-    qemu_get_timer(f, s->timer);
-    s->enabled = qemu_get_byte(f);
-    s->host_mode = qemu_get_byte(f);
-    s->function = qemu_get_byte(f);
-    s->nextfunction = qemu_get_byte(f);
-    s->precision = qemu_get_byte(f);
-    s->nextprecision = qemu_get_byte(f);
-    s->filter = qemu_get_be16(f);
-    s->pin_func = qemu_get_byte(f);
-    s->timing[0] = qemu_get_be16(f);
-    s->timing[1] = qemu_get_be16(f);
-    qemu_get_be16s(f, &s->temp_thr[0]);
-    qemu_get_be16s(f, &s->temp_thr[1]);
-    qemu_get_be16s(f, &s->aux_thr[0]);
-    qemu_get_be16s(f, &s->aux_thr[1]);
-    s->noise = qemu_get_be32(f);
-    s->reset = qemu_get_byte(f);
-    s->pdst = qemu_get_byte(f);
-    s->pnd0 = qemu_get_byte(f);
-
-    for (i = 0; i < 8; i ++)
-        s->tr[i] = qemu_get_be32(f);
-
-    s->busy = qemu_timer_pending(s->timer);
-    tsc2005_pin_update(s);
-
-    return 0;
-}
-
-void *tsc2005_init(qemu_irq pintdav)
-{
-    TSC2005State *s;
-
-    s = (TSC2005State *)
-            g_malloc0(sizeof(TSC2005State));
-    s->x = 400;
-    s->y = 240;
-    s->pressure = 0;
-    s->precision = s->nextprecision = 0;
-    s->timer = qemu_new_timer_ns(vm_clock, tsc2005_timer_tick, s);
-    s->pint = pintdav;
-    s->model = 0x2005;
-
-    s->tr[0] = 0;
-    s->tr[1] = 1;
-    s->tr[2] = 1;
-    s->tr[3] = 0;
-    s->tr[4] = 1;
-    s->tr[5] = 0;
-    s->tr[6] = 1;
-    s->tr[7] = 0;
-
-    tsc2005_reset(s);
-
-    qemu_add_mouse_event_handler(tsc2005_touchscreen_event, s, 1,
-                    "QEMU TSC2005-driven Touchscreen");
-
-    qemu_register_reset((void *) tsc2005_reset, s);
-    register_savevm(NULL, "tsc2005", -1, 0, tsc2005_save, tsc2005_load, s);
-
-    return s;
-}
-
-/*
- * Use tslib generated calibration data to generate ADC input values
- * from the touchscreen.  Assuming 12-bit precision was used during
- * tslib calibration.
- */
-void tsc2005_set_transform(void *opaque, MouseTransformInfo *info)
-{
-    TSC2005State *s = (TSC2005State *) opaque;
-
-    /* This version assumes touchscreen X & Y axis are parallel or
-     * perpendicular to LCD's  X & Y axis in some way.  */
-    if (abs(info->a[0]) > abs(info->a[1])) {
-        s->tr[0] = 0;
-        s->tr[1] = -info->a[6] * info->x;
-        s->tr[2] = info->a[0];
-        s->tr[3] = -info->a[2] / info->a[0];
-        s->tr[4] = info->a[6] * info->y;
-        s->tr[5] = 0;
-        s->tr[6] = info->a[4];
-        s->tr[7] = -info->a[5] / info->a[4];
-    } else {
-        s->tr[0] = info->a[6] * info->y;
-        s->tr[1] = 0;
-        s->tr[2] = info->a[1];
-        s->tr[3] = -info->a[2] / info->a[1];
-        s->tr[4] = 0;
-        s->tr[5] = -info->a[6] * info->x;
-        s->tr[6] = info->a[3];
-        s->tr[7] = -info->a[5] / info->a[3];
-    }
-
-    s->tr[0] >>= 11;
-    s->tr[1] >>= 11;
-    s->tr[3] <<= 4;
-    s->tr[4] >>= 11;
-    s->tr[5] >>= 11;
-    s->tr[7] <<= 4;
-}
diff --git a/hw/tsc210x.c b/hw/tsc210x.c
deleted file mode 100644 (file)
index b93e502..0000000
+++ /dev/null
@@ -1,1293 +0,0 @@
-/*
- * TI TSC2102 (touchscreen/sensors/audio controller) emulator.
- * TI TSC2301 (touchscreen/sensors/keypad).
- *
- * Copyright (c) 2006 Andrzej Zaborowski  <balrog@zabor.org>
- * Copyright (C) 2008 Nokia Corporation
- *
- * 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 or
- * (at your option) version 3 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
- * 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 "hw/hw.h"
-#include "audio/audio.h"
-#include "qemu/timer.h"
-#include "ui/console.h"
-#include "hw/omap.h"   /* For I2SCodec and uWireSlave */
-#include "hw/devices.h"
-
-#define TSC_DATA_REGISTERS_PAGE                0x0
-#define TSC_CONTROL_REGISTERS_PAGE     0x1
-#define TSC_AUDIO_REGISTERS_PAGE       0x2
-
-#define TSC_VERBOSE
-
-#define TSC_CUT_RESOLUTION(value, p)   ((value) >> (16 - resolution[p]))
-
-typedef struct {
-    qemu_irq pint;
-    qemu_irq kbint;
-    qemu_irq davint;
-    QEMUTimer *timer;
-    QEMUSoundCard card;
-    uWireSlave chip;
-    I2SCodec codec;
-    uint8_t in_fifo[16384];
-    uint8_t out_fifo[16384];
-    uint16_t model;
-
-    int x, y;
-    int pressure;
-
-    int state, page, offset, irq;
-    uint16_t command, dav;
-
-    int busy;
-    int enabled;
-    int host_mode;
-    int function;
-    int nextfunction;
-    int precision;
-    int nextprecision;
-    int filter;
-    int pin_func;
-    int ref;
-    int timing;
-    int noise;
-
-    uint16_t audio_ctrl1;
-    uint16_t audio_ctrl2;
-    uint16_t audio_ctrl3;
-    uint16_t pll[3];
-    uint16_t volume;
-    int64_t volume_change;
-    int softstep;
-    uint16_t dac_power;
-    int64_t powerdown;
-    uint16_t filter_data[0x14];
-
-    const char *name;
-    SWVoiceIn *adc_voice[1];
-    SWVoiceOut *dac_voice[1];
-    int i2s_rx_rate;
-    int i2s_tx_rate;
-
-    int tr[8];
-
-    struct {
-        uint16_t down;
-        uint16_t mask;
-        int scan;
-        int debounce;
-        int mode;
-        int intr;
-    } kb;
-} TSC210xState;
-
-static const int resolution[4] = { 12, 8, 10, 12 };
-
-#define TSC_MODE_NO_SCAN       0x0
-#define TSC_MODE_XY_SCAN       0x1
-#define TSC_MODE_XYZ_SCAN      0x2
-#define TSC_MODE_X             0x3
-#define TSC_MODE_Y             0x4
-#define TSC_MODE_Z             0x5
-#define TSC_MODE_BAT1          0x6
-#define TSC_MODE_BAT2          0x7
-#define TSC_MODE_AUX           0x8
-#define TSC_MODE_AUX_SCAN      0x9
-#define TSC_MODE_TEMP1         0xa
-#define TSC_MODE_PORT_SCAN     0xb
-#define TSC_MODE_TEMP2         0xc
-#define TSC_MODE_XX_DRV                0xd
-#define TSC_MODE_YY_DRV                0xe
-#define TSC_MODE_YX_DRV                0xf
-
-static const uint16_t mode_regs[16] = {
-    0x0000,    /* No scan */
-    0x0600,    /* X, Y scan */
-    0x0780,    /* X, Y, Z scan */
-    0x0400,    /* X */
-    0x0200,    /* Y */
-    0x0180,    /* Z */
-    0x0040,    /* BAT1 */
-    0x0030,    /* BAT2 */
-    0x0010,    /* AUX */
-    0x0010,    /* AUX scan */
-    0x0004,    /* TEMP1 */
-    0x0070,    /* Port scan */
-    0x0002,    /* TEMP2 */
-    0x0000,    /* X+, X- drivers */
-    0x0000,    /* Y+, Y- drivers */
-    0x0000,    /* Y+, X- drivers */
-};
-
-#define X_TRANSFORM(s)                 \
-    ((s->y * s->tr[0] - s->x * s->tr[1]) / s->tr[2] + s->tr[3])
-#define Y_TRANSFORM(s)                 \
-    ((s->y * s->tr[4] - s->x * s->tr[5]) / s->tr[6] + s->tr[7])
-#define Z1_TRANSFORM(s)                        \
-    ((400 - ((s)->x >> 7) + ((s)->pressure << 10)) << 4)
-#define Z2_TRANSFORM(s)                        \
-    ((4000 + ((s)->y >> 7) - ((s)->pressure << 10)) << 4)
-
-#define BAT1_VAL                       0x8660
-#define BAT2_VAL                       0x0000
-#define AUX1_VAL                       0x35c0
-#define AUX2_VAL                       0xffff
-#define TEMP1_VAL                      0x8c70
-#define TEMP2_VAL                      0xa5b0
-
-#define TSC_POWEROFF_DELAY             50
-#define TSC_SOFTSTEP_DELAY             50
-
-static void tsc210x_reset(TSC210xState *s)
-{
-    s->state = 0;
-    s->pin_func = 2;
-    s->enabled = 0;
-    s->busy = 0;
-    s->nextfunction = 0;
-    s->ref = 0;
-    s->timing = 0;
-    s->irq = 0;
-    s->dav = 0;
-
-    s->audio_ctrl1 = 0x0000;
-    s->audio_ctrl2 = 0x4410;
-    s->audio_ctrl3 = 0x0000;
-    s->pll[0] = 0x1004;
-    s->pll[1] = 0x0000;
-    s->pll[2] = 0x1fff;
-    s->volume = 0xffff;
-    s->dac_power = 0x8540;
-    s->softstep = 1;
-    s->volume_change = 0;
-    s->powerdown = 0;
-    s->filter_data[0x00] = 0x6be3;
-    s->filter_data[0x01] = 0x9666;
-    s->filter_data[0x02] = 0x675d;
-    s->filter_data[0x03] = 0x6be3;
-    s->filter_data[0x04] = 0x9666;
-    s->filter_data[0x05] = 0x675d;
-    s->filter_data[0x06] = 0x7d83;
-    s->filter_data[0x07] = 0x84ee;
-    s->filter_data[0x08] = 0x7d83;
-    s->filter_data[0x09] = 0x84ee;
-    s->filter_data[0x0a] = 0x6be3;
-    s->filter_data[0x0b] = 0x9666;
-    s->filter_data[0x0c] = 0x675d;
-    s->filter_data[0x0d] = 0x6be3;
-    s->filter_data[0x0e] = 0x9666;
-    s->filter_data[0x0f] = 0x675d;
-    s->filter_data[0x10] = 0x7d83;
-    s->filter_data[0x11] = 0x84ee;
-    s->filter_data[0x12] = 0x7d83;
-    s->filter_data[0x13] = 0x84ee;
-
-    s->i2s_tx_rate = 0;
-    s->i2s_rx_rate = 0;
-
-    s->kb.scan = 1;
-    s->kb.debounce = 0;
-    s->kb.mask = 0x0000;
-    s->kb.mode = 3;
-    s->kb.intr = 0;
-
-    qemu_set_irq(s->pint, !s->irq);
-    qemu_set_irq(s->davint, !s->dav);
-    qemu_irq_raise(s->kbint);
-}
-
-typedef struct {
-    int rate;
-    int dsor;
-    int fsref;
-} TSC210xRateInfo;
-
-/*  { rate,  dsor,  fsref } */
-static const TSC210xRateInfo tsc2101_rates[] = {
-    /* Fsref / 6.0 */
-    { 7350,    7,      1 },
-    { 8000,    7,      0 },
-    /* Fsref / 5.5 */
-    { 8018,    6,      1 },
-    { 8727,    6,      0 },
-    /* Fsref / 5.0 */
-    { 8820,    5,      1 },
-    { 9600,    5,      0 },
-    /* Fsref / 4.0 */
-    { 11025,   4,      1 },
-    { 12000,   4,      0 },
-    /* Fsref / 3.0 */
-    { 14700,   3,      1 },
-    { 16000,   3,      0 },
-    /* Fsref / 2.0 */
-    { 22050,   2,      1 },
-    { 24000,   2,      0 },
-    /* Fsref / 1.5 */
-    { 29400,   1,      1 },
-    { 32000,   1,      0 },
-    /* Fsref */
-    { 44100,   0,      1 },
-    { 48000,   0,      0 },
-
-    { 0,       0,      0 },
-};
-
-/*  { rate,   dsor, fsref }    */
-static const TSC210xRateInfo tsc2102_rates[] = {
-    /* Fsref / 6.0 */
-    { 7350,    63,     1 },
-    { 8000,    63,     0 },
-    /* Fsref / 6.0 */
-    { 7350,    54,     1 },
-    { 8000,    54,     0 },
-    /* Fsref / 5.0 */
-    { 8820,    45,     1 },
-    { 9600,    45,     0 },
-    /* Fsref / 4.0 */
-    { 11025,   36,     1 },
-    { 12000,   36,     0 },
-    /* Fsref / 3.0 */
-    { 14700,   27,     1 },
-    { 16000,   27,     0 },
-    /* Fsref / 2.0 */
-    { 22050,   18,     1 },
-    { 24000,   18,     0 },
-    /* Fsref / 1.5 */
-    { 29400,   9,      1 },
-    { 32000,   9,      0 },
-    /* Fsref */
-    { 44100,   0,      1 },
-    { 48000,   0,      0 },
-
-    { 0,       0,      0 },
-};
-
-static inline void tsc210x_out_flush(TSC210xState *s, int len)
-{
-    uint8_t *data = s->codec.out.fifo + s->codec.out.start;
-    uint8_t *end = data + len;
-
-    while (data < end)
-        data += AUD_write(s->dac_voice[0], data, end - data) ?: (end - data);
-
-    s->codec.out.len -= len;
-    if (s->codec.out.len)
-        memmove(s->codec.out.fifo, end, s->codec.out.len);
-    s->codec.out.start = 0;
-}
-
-static void tsc210x_audio_out_cb(TSC210xState *s, int free_b)
-{
-    if (s->codec.out.len >= free_b) {
-        tsc210x_out_flush(s, free_b);
-        return;
-    }
-
-    s->codec.out.size = MIN(free_b, 16384);
-    qemu_irq_raise(s->codec.tx_start);
-}
-
-static void tsc2102_audio_rate_update(TSC210xState *s)
-{
-    const TSC210xRateInfo *rate;
-
-    s->codec.tx_rate = 0;
-    s->codec.rx_rate = 0;
-    if (s->dac_power & (1 << 15))                              /* PWDNC */
-        return;
-
-    for (rate = tsc2102_rates; rate->rate; rate ++)
-        if (rate->dsor == (s->audio_ctrl1 & 0x3f) &&           /* DACFS */
-                        rate->fsref == ((s->audio_ctrl3 >> 13) & 1))/* REFFS */
-            break;
-    if (!rate->rate) {
-        printf("%s: unknown sampling rate configured\n", __FUNCTION__);
-        return;
-    }
-
-    s->codec.tx_rate = rate->rate;
-}
-
-static void tsc2102_audio_output_update(TSC210xState *s)
-{
-    int enable;
-    struct audsettings fmt;
-
-    if (s->dac_voice[0]) {
-        tsc210x_out_flush(s, s->codec.out.len);
-        s->codec.out.size = 0;
-        AUD_set_active_out(s->dac_voice[0], 0);
-        AUD_close_out(&s->card, s->dac_voice[0]);
-        s->dac_voice[0] = NULL;
-    }
-    s->codec.cts = 0;
-
-    enable =
-            (~s->dac_power & (1 << 15)) &&                     /* PWDNC */
-            (~s->dac_power & (1 << 10));                       /* DAPWDN */
-    if (!enable || !s->codec.tx_rate)
-        return;
-
-    /* Force our own sampling rate even in slave DAC mode */
-    fmt.endianness = 0;
-    fmt.nchannels = 2;
-    fmt.freq = s->codec.tx_rate;
-    fmt.fmt = AUD_FMT_S16;
-
-    s->dac_voice[0] = AUD_open_out(&s->card, s->dac_voice[0],
-                    "tsc2102.sink", s, (void *) tsc210x_audio_out_cb, &fmt);
-    if (s->dac_voice[0]) {
-        s->codec.cts = 1;
-        AUD_set_active_out(s->dac_voice[0], 1);
-    }
-}
-
-static uint16_t tsc2102_data_register_read(TSC210xState *s, int reg)
-{
-    switch (reg) {
-    case 0x00: /* X */
-        s->dav &= 0xfbff;
-        return TSC_CUT_RESOLUTION(X_TRANSFORM(s), s->precision) +
-                (s->noise & 3);
-
-    case 0x01: /* Y */
-        s->noise ++;
-        s->dav &= 0xfdff;
-        return TSC_CUT_RESOLUTION(Y_TRANSFORM(s), s->precision) ^
-                (s->noise & 3);
-
-    case 0x02: /* Z1 */
-        s->dav &= 0xfeff;
-        return TSC_CUT_RESOLUTION(Z1_TRANSFORM(s), s->precision) -
-                (s->noise & 3);
-
-    case 0x03: /* Z2 */
-        s->dav &= 0xff7f;
-        return TSC_CUT_RESOLUTION(Z2_TRANSFORM(s), s->precision) |
-                (s->noise & 3);
-
-    case 0x04: /* KPData */
-        if ((s->model & 0xff00) == 0x2300) {
-            if (s->kb.intr && (s->kb.mode & 2)) {
-                s->kb.intr = 0;
-                qemu_irq_raise(s->kbint);
-            }
-            return s->kb.down;
-        }
-
-        return 0xffff;
-
-    case 0x05: /* BAT1 */
-        s->dav &= 0xffbf;
-        return TSC_CUT_RESOLUTION(BAT1_VAL, s->precision) +
-                (s->noise & 6);
-
-    case 0x06: /* BAT2 */
-        s->dav &= 0xffdf;
-        return TSC_CUT_RESOLUTION(BAT2_VAL, s->precision);
-
-    case 0x07: /* AUX1 */
-        s->dav &= 0xffef;
-        return TSC_CUT_RESOLUTION(AUX1_VAL, s->precision);
-
-    case 0x08: /* AUX2 */
-        s->dav &= 0xfff7;
-        return 0xffff;
-
-    case 0x09: /* TEMP1 */
-        s->dav &= 0xfffb;
-        return TSC_CUT_RESOLUTION(TEMP1_VAL, s->precision) -
-                (s->noise & 5);
-
-    case 0x0a: /* TEMP2 */
-        s->dav &= 0xfffd;
-        return TSC_CUT_RESOLUTION(TEMP2_VAL, s->precision) ^
-                (s->noise & 3);
-
-    case 0x0b: /* DAC */
-        s->dav &= 0xfffe;
-        return 0xffff;
-
-    default:
-#ifdef TSC_VERBOSE
-        fprintf(stderr, "tsc2102_data_register_read: "
-                        "no such register: 0x%02x\n", reg);
-#endif
-        return 0xffff;
-    }
-}
-
-static uint16_t tsc2102_control_register_read(
-                TSC210xState *s, int reg)
-{
-    switch (reg) {
-    case 0x00: /* TSC ADC */
-        return (s->pressure << 15) | ((!s->busy) << 14) |
-                (s->nextfunction << 10) | (s->nextprecision << 8) | s->filter; 
-
-    case 0x01: /* Status / Keypad Control */
-        if ((s->model & 0xff00) == 0x2100)
-            return (s->pin_func << 14) | ((!s->enabled) << 13) |
-                    (s->host_mode << 12) | ((!!s->dav) << 11) | s->dav;
-        else
-            return (s->kb.intr << 15) | ((s->kb.scan || !s->kb.down) << 14) |
-                    (s->kb.debounce << 11);
-
-    case 0x02: /* DAC Control */
-        if ((s->model & 0xff00) == 0x2300)
-            return s->dac_power & 0x8000;
-        else
-            goto bad_reg;
-
-    case 0x03: /* Reference */
-        return s->ref;
-
-    case 0x04: /* Reset */
-        return 0xffff;
-
-    case 0x05: /* Configuration */
-        return s->timing;
-
-    case 0x06: /* Secondary configuration */
-        if ((s->model & 0xff00) == 0x2100)
-            goto bad_reg;
-        return ((!s->dav) << 15) | ((s->kb.mode & 1) << 14) | s->pll[2];
-
-    case 0x10: /* Keypad Mask */
-        if ((s->model & 0xff00) == 0x2100)
-            goto bad_reg;
-        return s->kb.mask;
-
-    default:
-    bad_reg:
-#ifdef TSC_VERBOSE
-        fprintf(stderr, "tsc2102_control_register_read: "
-                        "no such register: 0x%02x\n", reg);
-#endif
-        return 0xffff;
-    }
-}
-
-static uint16_t tsc2102_audio_register_read(TSC210xState *s, int reg)
-{
-    int l_ch, r_ch;
-    uint16_t val;
-
-    switch (reg) {
-    case 0x00: /* Audio Control 1 */
-        return s->audio_ctrl1;
-
-    case 0x01:
-        return 0xff00;
-
-    case 0x02: /* DAC Volume Control */
-        return s->volume;
-
-    case 0x03:
-        return 0x8b00;
-
-    case 0x04: /* Audio Control 2 */
-        l_ch = 1;
-        r_ch = 1;
-        if (s->softstep && !(s->dac_power & (1 << 10))) {
-            l_ch = (qemu_get_clock_ns(vm_clock) >
-                            s->volume_change + TSC_SOFTSTEP_DELAY);
-            r_ch = (qemu_get_clock_ns(vm_clock) >
-                            s->volume_change + TSC_SOFTSTEP_DELAY);
-        }
-
-        return s->audio_ctrl2 | (l_ch << 3) | (r_ch << 2);
-
-    case 0x05: /* Stereo DAC Power Control */
-        return 0x2aa0 | s->dac_power |
-                (((s->dac_power & (1 << 10)) &&
-                  (qemu_get_clock_ns(vm_clock) >
-                   s->powerdown + TSC_POWEROFF_DELAY)) << 6);
-
-    case 0x06: /* Audio Control 3 */
-        val = s->audio_ctrl3 | 0x0001;
-        s->audio_ctrl3 &= 0xff3f;
-        return val;
-
-    case 0x07: /* LCH_BASS_BOOST_N0 */
-    case 0x08: /* LCH_BASS_BOOST_N1 */
-    case 0x09: /* LCH_BASS_BOOST_N2 */
-    case 0x0a: /* LCH_BASS_BOOST_N3 */
-    case 0x0b: /* LCH_BASS_BOOST_N4 */
-    case 0x0c: /* LCH_BASS_BOOST_N5 */
-    case 0x0d: /* LCH_BASS_BOOST_D1 */
-    case 0x0e: /* LCH_BASS_BOOST_D2 */
-    case 0x0f: /* LCH_BASS_BOOST_D4 */
-    case 0x10: /* LCH_BASS_BOOST_D5 */
-    case 0x11: /* RCH_BASS_BOOST_N0 */
-    case 0x12: /* RCH_BASS_BOOST_N1 */
-    case 0x13: /* RCH_BASS_BOOST_N2 */
-    case 0x14: /* RCH_BASS_BOOST_N3 */
-    case 0x15: /* RCH_BASS_BOOST_N4 */
-    case 0x16: /* RCH_BASS_BOOST_N5 */
-    case 0x17: /* RCH_BASS_BOOST_D1 */
-    case 0x18: /* RCH_BASS_BOOST_D2 */
-    case 0x19: /* RCH_BASS_BOOST_D4 */
-    case 0x1a: /* RCH_BASS_BOOST_D5 */
-        return s->filter_data[reg - 0x07];
-
-    case 0x1b: /* PLL Programmability 1 */
-        return s->pll[0];
-
-    case 0x1c: /* PLL Programmability 2 */
-        return s->pll[1];
-
-    case 0x1d: /* Audio Control 4 */
-        return (!s->softstep) << 14;
-
-    default:
-#ifdef TSC_VERBOSE
-        fprintf(stderr, "tsc2102_audio_register_read: "
-                        "no such register: 0x%02x\n", reg);
-#endif
-        return 0xffff;
-    }
-}
-
-static void tsc2102_data_register_write(
-                TSC210xState *s, int reg, uint16_t value)
-{
-    switch (reg) {
-    case 0x00: /* X */
-    case 0x01: /* Y */
-    case 0x02: /* Z1 */
-    case 0x03: /* Z2 */
-    case 0x05: /* BAT1 */
-    case 0x06: /* BAT2 */
-    case 0x07: /* AUX1 */
-    case 0x08: /* AUX2 */
-    case 0x09: /* TEMP1 */
-    case 0x0a: /* TEMP2 */
-        return;
-
-    default:
-#ifdef TSC_VERBOSE
-        fprintf(stderr, "tsc2102_data_register_write: "
-                        "no such register: 0x%02x\n", reg);
-#endif
-    }
-}
-
-static void tsc2102_control_register_write(
-                TSC210xState *s, int reg, uint16_t value)
-{
-    switch (reg) {
-    case 0x00: /* TSC ADC */
-        s->host_mode = value >> 15;
-        s->enabled = !(value & 0x4000);
-        if (s->busy && !s->enabled)
-            qemu_del_timer(s->timer);
-        s->busy &= s->enabled;
-        s->nextfunction = (value >> 10) & 0xf;
-        s->nextprecision = (value >> 8) & 3;
-        s->filter = value & 0xff;
-        return;
-
-    case 0x01: /* Status / Keypad Control */
-        if ((s->model & 0xff00) == 0x2100)
-            s->pin_func = value >> 14;
-       else {
-            s->kb.scan = (value >> 14) & 1;
-            s->kb.debounce = (value >> 11) & 7;
-            if (s->kb.intr && s->kb.scan) {
-                s->kb.intr = 0;
-                qemu_irq_raise(s->kbint);
-            }
-        }
-        return;
-
-    case 0x02: /* DAC Control */
-        if ((s->model & 0xff00) == 0x2300) {
-            s->dac_power &= 0x7fff;
-            s->dac_power |= 0x8000 & value;
-        } else
-            goto bad_reg;
-        break;
-
-    case 0x03: /* Reference */
-        s->ref = value & 0x1f;
-        return;
-
-    case 0x04: /* Reset */
-        if (value == 0xbb00) {
-            if (s->busy)
-                qemu_del_timer(s->timer);
-            tsc210x_reset(s);
-#ifdef TSC_VERBOSE
-        } else {
-            fprintf(stderr, "tsc2102_control_register_write: "
-                            "wrong value written into RESET\n");
-#endif
-        }
-        return;
-
-    case 0x05: /* Configuration */
-        s->timing = value & 0x3f;
-#ifdef TSC_VERBOSE
-        if (value & ~0x3f)
-            fprintf(stderr, "tsc2102_control_register_write: "
-                            "wrong value written into CONFIG\n");
-#endif
-        return;
-
-    case 0x06: /* Secondary configuration */
-        if ((s->model & 0xff00) == 0x2100)
-            goto bad_reg;
-        s->kb.mode = value >> 14;
-        s->pll[2] = value & 0x3ffff;
-        return;
-
-    case 0x10: /* Keypad Mask */
-        if ((s->model & 0xff00) == 0x2100)
-            goto bad_reg;
-        s->kb.mask = value;
-        return;
-
-    default:
-    bad_reg:
-#ifdef TSC_VERBOSE
-        fprintf(stderr, "tsc2102_control_register_write: "
-                        "no such register: 0x%02x\n", reg);
-#endif
-    }
-}
-
-static void tsc2102_audio_register_write(
-                TSC210xState *s, int reg, uint16_t value)
-{
-    switch (reg) {
-    case 0x00: /* Audio Control 1 */
-        s->audio_ctrl1 = value & 0x0f3f;
-#ifdef TSC_VERBOSE
-        if ((value & ~0x0f3f) || ((value & 7) != ((value >> 3) & 7)))
-            fprintf(stderr, "tsc2102_audio_register_write: "
-                            "wrong value written into Audio 1\n");
-#endif
-        tsc2102_audio_rate_update(s);
-        tsc2102_audio_output_update(s);
-        return;
-
-    case 0x01:
-#ifdef TSC_VERBOSE
-        if (value != 0xff00)
-            fprintf(stderr, "tsc2102_audio_register_write: "
-                            "wrong value written into reg 0x01\n");
-#endif
-        return;
-
-    case 0x02: /* DAC Volume Control */
-        s->volume = value;
-        s->volume_change = qemu_get_clock_ns(vm_clock);
-        return;
-
-    case 0x03:
-#ifdef TSC_VERBOSE
-        if (value != 0x8b00)
-            fprintf(stderr, "tsc2102_audio_register_write: "
-                            "wrong value written into reg 0x03\n");
-#endif
-        return;
-
-    case 0x04: /* Audio Control 2 */
-        s->audio_ctrl2 = value & 0xf7f2;
-#ifdef TSC_VERBOSE
-        if (value & ~0xf7fd)
-            fprintf(stderr, "tsc2102_audio_register_write: "
-                            "wrong value written into Audio 2\n");
-#endif
-        return;
-
-    case 0x05: /* Stereo DAC Power Control */
-        if ((value & ~s->dac_power) & (1 << 10))
-            s->powerdown = qemu_get_clock_ns(vm_clock);
-
-        s->dac_power = value & 0x9543;
-#ifdef TSC_VERBOSE
-        if ((value & ~0x9543) != 0x2aa0)
-            fprintf(stderr, "tsc2102_audio_register_write: "
-                            "wrong value written into Power\n");
-#endif
-        tsc2102_audio_rate_update(s);
-        tsc2102_audio_output_update(s);
-        return;
-
-    case 0x06: /* Audio Control 3 */
-        s->audio_ctrl3 &= 0x00c0;
-        s->audio_ctrl3 |= value & 0xf800;
-#ifdef TSC_VERBOSE
-        if (value & ~0xf8c7)
-            fprintf(stderr, "tsc2102_audio_register_write: "
-                            "wrong value written into Audio 3\n");
-#endif
-        tsc2102_audio_output_update(s);
-        return;
-
-    case 0x07: /* LCH_BASS_BOOST_N0 */
-    case 0x08: /* LCH_BASS_BOOST_N1 */
-    case 0x09: /* LCH_BASS_BOOST_N2 */
-    case 0x0a: /* LCH_BASS_BOOST_N3 */
-    case 0x0b: /* LCH_BASS_BOOST_N4 */
-    case 0x0c: /* LCH_BASS_BOOST_N5 */
-    case 0x0d: /* LCH_BASS_BOOST_D1 */
-    case 0x0e: /* LCH_BASS_BOOST_D2 */
-    case 0x0f: /* LCH_BASS_BOOST_D4 */
-    case 0x10: /* LCH_BASS_BOOST_D5 */
-    case 0x11: /* RCH_BASS_BOOST_N0 */
-    case 0x12: /* RCH_BASS_BOOST_N1 */
-    case 0x13: /* RCH_BASS_BOOST_N2 */
-    case 0x14: /* RCH_BASS_BOOST_N3 */
-    case 0x15: /* RCH_BASS_BOOST_N4 */
-    case 0x16: /* RCH_BASS_BOOST_N5 */
-    case 0x17: /* RCH_BASS_BOOST_D1 */
-    case 0x18: /* RCH_BASS_BOOST_D2 */
-    case 0x19: /* RCH_BASS_BOOST_D4 */
-    case 0x1a: /* RCH_BASS_BOOST_D5 */
-        s->filter_data[reg - 0x07] = value;
-        return;
-
-    case 0x1b: /* PLL Programmability 1 */
-        s->pll[0] = value & 0xfffc;
-#ifdef TSC_VERBOSE
-        if (value & ~0xfffc)
-            fprintf(stderr, "tsc2102_audio_register_write: "
-                            "wrong value written into PLL 1\n");
-#endif
-        return;
-
-    case 0x1c: /* PLL Programmability 2 */
-        s->pll[1] = value & 0xfffc;
-#ifdef TSC_VERBOSE
-        if (value & ~0xfffc)
-            fprintf(stderr, "tsc2102_audio_register_write: "
-                            "wrong value written into PLL 2\n");
-#endif
-        return;
-
-    case 0x1d: /* Audio Control 4 */
-        s->softstep = !(value & 0x4000);
-#ifdef TSC_VERBOSE
-        if (value & ~0x4000)
-            fprintf(stderr, "tsc2102_audio_register_write: "
-                            "wrong value written into Audio 4\n");
-#endif
-        return;
-
-    default:
-#ifdef TSC_VERBOSE
-        fprintf(stderr, "tsc2102_audio_register_write: "
-                        "no such register: 0x%02x\n", reg);
-#endif
-    }
-}
-
-/* This handles most of the chip logic.  */
-static void tsc210x_pin_update(TSC210xState *s)
-{
-    int64_t expires;
-    int pin_state;
-
-    switch (s->pin_func) {
-    case 0:
-        pin_state = s->pressure;
-        break;
-    case 1:
-        pin_state = !!s->dav;
-        break;
-    case 2:
-    default:
-        pin_state = s->pressure && !s->dav;
-    }
-
-    if (!s->enabled)
-        pin_state = 0;
-
-    if (pin_state != s->irq) {
-        s->irq = pin_state;
-        qemu_set_irq(s->pint, !s->irq);
-    }
-
-    switch (s->nextfunction) {
-    case TSC_MODE_XY_SCAN:
-    case TSC_MODE_XYZ_SCAN:
-        if (!s->pressure)
-            return;
-        break;
-
-    case TSC_MODE_X:
-    case TSC_MODE_Y:
-    case TSC_MODE_Z:
-        if (!s->pressure)
-            return;
-        /* Fall through */
-    case TSC_MODE_BAT1:
-    case TSC_MODE_BAT2:
-    case TSC_MODE_AUX:
-    case TSC_MODE_TEMP1:
-    case TSC_MODE_TEMP2:
-        if (s->dav)
-            s->enabled = 0;
-        break;
-
-    case TSC_MODE_AUX_SCAN:
-    case TSC_MODE_PORT_SCAN:
-        break;
-
-    case TSC_MODE_NO_SCAN:
-    case TSC_MODE_XX_DRV:
-    case TSC_MODE_YY_DRV:
-    case TSC_MODE_YX_DRV:
-    default:
-        return;
-    }
-
-    if (!s->enabled || s->busy || s->dav)
-        return;
-
-    s->busy = 1;
-    s->precision = s->nextprecision;
-    s->function = s->nextfunction;
-    expires = qemu_get_clock_ns(vm_clock) + (get_ticks_per_sec() >> 10);
-    qemu_mod_timer(s->timer, expires);
-}
-
-static uint16_t tsc210x_read(TSC210xState *s)
-{
-    uint16_t ret = 0x0000;
-
-    if (!s->command)
-        fprintf(stderr, "tsc210x_read: SPI underrun!\n");
-
-    switch (s->page) {
-    case TSC_DATA_REGISTERS_PAGE:
-        ret = tsc2102_data_register_read(s, s->offset);
-        if (!s->dav)
-            qemu_irq_raise(s->davint);
-        break;
-    case TSC_CONTROL_REGISTERS_PAGE:
-        ret = tsc2102_control_register_read(s, s->offset);
-        break;
-    case TSC_AUDIO_REGISTERS_PAGE:
-        ret = tsc2102_audio_register_read(s, s->offset);
-        break;
-    default:
-        hw_error("tsc210x_read: wrong memory page\n");
-    }
-
-    tsc210x_pin_update(s);
-
-    /* Allow sequential reads.  */
-    s->offset ++;
-    s->state = 0;
-    return ret;
-}
-
-static void tsc210x_write(TSC210xState *s, uint16_t value)
-{
-    /*
-     * This is a two-state state machine for reading
-     * command and data every second time.
-     */
-    if (!s->state) {
-        s->command = value >> 15;
-        s->page = (value >> 11) & 0x0f;
-        s->offset = (value >> 5) & 0x3f;
-        s->state = 1;
-    } else {
-        if (s->command)
-            fprintf(stderr, "tsc210x_write: SPI overrun!\n");
-        else
-            switch (s->page) {
-            case TSC_DATA_REGISTERS_PAGE:
-                tsc2102_data_register_write(s, s->offset, value);
-                break;
-            case TSC_CONTROL_REGISTERS_PAGE:
-                tsc2102_control_register_write(s, s->offset, value);
-                break;
-            case TSC_AUDIO_REGISTERS_PAGE:
-                tsc2102_audio_register_write(s, s->offset, value);
-                break;
-            default:
-                hw_error("tsc210x_write: wrong memory page\n");
-            }
-
-        tsc210x_pin_update(s);
-        s->state = 0;
-    }
-}
-
-uint32_t tsc210x_txrx(void *opaque, uint32_t value, int len)
-{
-    TSC210xState *s = opaque;
-    uint32_t ret = 0;
-
-    if (len != 16)
-        hw_error("%s: FIXME: bad SPI word width %i\n", __FUNCTION__, len);
-
-    /* TODO: sequential reads etc - how do we make sure the host doesn't
-     * unintentionally read out a conversion result from a register while
-     * transmitting the command word of the next command?  */
-    if (!value || (s->state && s->command))
-        ret = tsc210x_read(s);
-    if (value || (s->state && !s->command))
-        tsc210x_write(s, value);
-
-    return ret;
-}
-
-static void tsc210x_timer_tick(void *opaque)
-{
-    TSC210xState *s = opaque;
-
-    /* Timer ticked -- a set of conversions has been finished.  */
-
-    if (!s->busy)
-        return;
-
-    s->busy = 0;
-    s->dav |= mode_regs[s->function];
-    tsc210x_pin_update(s);
-    qemu_irq_lower(s->davint);
-}
-
-static void tsc210x_touchscreen_event(void *opaque,
-                int x, int y, int z, int buttons_state)
-{
-    TSC210xState *s = opaque;
-    int p = s->pressure;
-
-    if (buttons_state) {
-        s->x = x;
-        s->y = y;
-    }
-    s->pressure = !!buttons_state;
-
-    /*
-     * Note: We would get better responsiveness in the guest by
-     * signaling TS events immediately, but for now we simulate
-     * the first conversion delay for sake of correctness.
-     */
-    if (p != s->pressure)
-        tsc210x_pin_update(s);
-}
-
-static void tsc210x_i2s_swallow(TSC210xState *s)
-{
-    if (s->dac_voice[0])
-        tsc210x_out_flush(s, s->codec.out.len);
-    else
-        s->codec.out.len = 0;
-}
-
-static void tsc210x_i2s_set_rate(TSC210xState *s, int in, int out)
-{
-    s->i2s_tx_rate = out;
-    s->i2s_rx_rate = in;
-}
-
-static void tsc210x_save(QEMUFile *f, void *opaque)
-{
-    TSC210xState *s = (TSC210xState *) opaque;
-    int64_t now = qemu_get_clock_ns(vm_clock);
-    int i;
-
-    qemu_put_be16(f, s->x);
-    qemu_put_be16(f, s->y);
-    qemu_put_byte(f, s->pressure);
-
-    qemu_put_byte(f, s->state);
-    qemu_put_byte(f, s->page);
-    qemu_put_byte(f, s->offset);
-    qemu_put_byte(f, s->command);
-
-    qemu_put_byte(f, s->irq);
-    qemu_put_be16s(f, &s->dav);
-
-    qemu_put_timer(f, s->timer);
-    qemu_put_byte(f, s->enabled);
-    qemu_put_byte(f, s->host_mode);
-    qemu_put_byte(f, s->function);
-    qemu_put_byte(f, s->nextfunction);
-    qemu_put_byte(f, s->precision);
-    qemu_put_byte(f, s->nextprecision);
-    qemu_put_byte(f, s->filter);
-    qemu_put_byte(f, s->pin_func);
-    qemu_put_byte(f, s->ref);
-    qemu_put_byte(f, s->timing);
-    qemu_put_be32(f, s->noise);
-
-    qemu_put_be16s(f, &s->audio_ctrl1);
-    qemu_put_be16s(f, &s->audio_ctrl2);
-    qemu_put_be16s(f, &s->audio_ctrl3);
-    qemu_put_be16s(f, &s->pll[0]);
-    qemu_put_be16s(f, &s->pll[1]);
-    qemu_put_be16s(f, &s->volume);
-    qemu_put_sbe64(f, (s->volume_change - now));
-    qemu_put_sbe64(f, (s->powerdown - now));
-    qemu_put_byte(f, s->softstep);
-    qemu_put_be16s(f, &s->dac_power);
-
-    for (i = 0; i < 0x14; i ++)
-        qemu_put_be16s(f, &s->filter_data[i]);
-}
-
-static int tsc210x_load(QEMUFile *f, void *opaque, int version_id)
-{
-    TSC210xState *s = (TSC210xState *) opaque;
-    int64_t now = qemu_get_clock_ns(vm_clock);
-    int i;
-
-    s->x = qemu_get_be16(f);
-    s->y = qemu_get_be16(f);
-    s->pressure = qemu_get_byte(f);
-
-    s->state = qemu_get_byte(f);
-    s->page = qemu_get_byte(f);
-    s->offset = qemu_get_byte(f);
-    s->command = qemu_get_byte(f);
-
-    s->irq = qemu_get_byte(f);
-    qemu_get_be16s(f, &s->dav);
-
-    qemu_get_timer(f, s->timer);
-    s->enabled = qemu_get_byte(f);
-    s->host_mode = qemu_get_byte(f);
-    s->function = qemu_get_byte(f);
-    s->nextfunction = qemu_get_byte(f);
-    s->precision = qemu_get_byte(f);
-    s->nextprecision = qemu_get_byte(f);
-    s->filter = qemu_get_byte(f);
-    s->pin_func = qemu_get_byte(f);
-    s->ref = qemu_get_byte(f);
-    s->timing = qemu_get_byte(f);
-    s->noise = qemu_get_be32(f);
-
-    qemu_get_be16s(f, &s->audio_ctrl1);
-    qemu_get_be16s(f, &s->audio_ctrl2);
-    qemu_get_be16s(f, &s->audio_ctrl3);
-    qemu_get_be16s(f, &s->pll[0]);
-    qemu_get_be16s(f, &s->pll[1]);
-    qemu_get_be16s(f, &s->volume);
-    s->volume_change = qemu_get_sbe64(f) + now;
-    s->powerdown = qemu_get_sbe64(f) + now;
-    s->softstep = qemu_get_byte(f);
-    qemu_get_be16s(f, &s->dac_power);
-
-    for (i = 0; i < 0x14; i ++)
-        qemu_get_be16s(f, &s->filter_data[i]);
-
-    s->busy = qemu_timer_pending(s->timer);
-    qemu_set_irq(s->pint, !s->irq);
-    qemu_set_irq(s->davint, !s->dav);
-
-    return 0;
-}
-
-uWireSlave *tsc2102_init(qemu_irq pint)
-{
-    TSC210xState *s;
-
-    s = (TSC210xState *)
-            g_malloc0(sizeof(TSC210xState));
-    memset(s, 0, sizeof(TSC210xState));
-    s->x = 160;
-    s->y = 160;
-    s->pressure = 0;
-    s->precision = s->nextprecision = 0;
-    s->timer = qemu_new_timer_ns(vm_clock, tsc210x_timer_tick, s);
-    s->pint = pint;
-    s->model = 0x2102;
-    s->name = "tsc2102";
-
-    s->tr[0] = 0;
-    s->tr[1] = 1;
-    s->tr[2] = 1;
-    s->tr[3] = 0;
-    s->tr[4] = 1;
-    s->tr[5] = 0;
-    s->tr[6] = 1;
-    s->tr[7] = 0;
-
-    s->chip.opaque = s;
-    s->chip.send = (void *) tsc210x_write;
-    s->chip.receive = (void *) tsc210x_read;
-
-    s->codec.opaque = s;
-    s->codec.tx_swallow = (void *) tsc210x_i2s_swallow;
-    s->codec.set_rate = (void *) tsc210x_i2s_set_rate;
-    s->codec.in.fifo = s->in_fifo;
-    s->codec.out.fifo = s->out_fifo;
-
-    tsc210x_reset(s);
-
-    qemu_add_mouse_event_handler(tsc210x_touchscreen_event, s, 1,
-                    "QEMU TSC2102-driven Touchscreen");
-
-    AUD_register_card(s->name, &s->card);
-
-    qemu_register_reset((void *) tsc210x_reset, s);
-    register_savevm(NULL, s->name, -1, 0,
-                    tsc210x_save, tsc210x_load, s);
-
-    return &s->chip;
-}
-
-uWireSlave *tsc2301_init(qemu_irq penirq, qemu_irq kbirq, qemu_irq dav)
-{
-    TSC210xState *s;
-
-    s = (TSC210xState *)
-            g_malloc0(sizeof(TSC210xState));
-    memset(s, 0, sizeof(TSC210xState));
-    s->x = 400;
-    s->y = 240;
-    s->pressure = 0;
-    s->precision = s->nextprecision = 0;
-    s->timer = qemu_new_timer_ns(vm_clock, tsc210x_timer_tick, s);
-    s->pint = penirq;
-    s->kbint = kbirq;
-    s->davint = dav;
-    s->model = 0x2301;
-    s->name = "tsc2301";
-
-    s->tr[0] = 0;
-    s->tr[1] = 1;
-    s->tr[2] = 1;
-    s->tr[3] = 0;
-    s->tr[4] = 1;
-    s->tr[5] = 0;
-    s->tr[6] = 1;
-    s->tr[7] = 0;
-
-    s->chip.opaque = s;
-    s->chip.send = (void *) tsc210x_write;
-    s->chip.receive = (void *) tsc210x_read;
-
-    s->codec.opaque = s;
-    s->codec.tx_swallow = (void *) tsc210x_i2s_swallow;
-    s->codec.set_rate = (void *) tsc210x_i2s_set_rate;
-    s->codec.in.fifo = s->in_fifo;
-    s->codec.out.fifo = s->out_fifo;
-
-    tsc210x_reset(s);
-
-    qemu_add_mouse_event_handler(tsc210x_touchscreen_event, s, 1,
-                    "QEMU TSC2301-driven Touchscreen");
-
-    AUD_register_card(s->name, &s->card);
-
-    qemu_register_reset((void *) tsc210x_reset, s);
-    register_savevm(NULL, s->name, -1, 0, tsc210x_save, tsc210x_load, s);
-
-    return &s->chip;
-}
-
-I2SCodec *tsc210x_codec(uWireSlave *chip)
-{
-    TSC210xState *s = (TSC210xState *) chip->opaque;
-
-    return &s->codec;
-}
-
-/*
- * Use tslib generated calibration data to generate ADC input values
- * from the touchscreen.  Assuming 12-bit precision was used during
- * tslib calibration.
- */
-void tsc210x_set_transform(uWireSlave *chip,
-                MouseTransformInfo *info)
-{
-    TSC210xState *s = (TSC210xState *) chip->opaque;
-#if 0
-    int64_t ltr[8];
-
-    ltr[0] = (int64_t) info->a[1] * info->y;
-    ltr[1] = (int64_t) info->a[4] * info->x;
-    ltr[2] = (int64_t) info->a[1] * info->a[3] -
-            (int64_t) info->a[4] * info->a[0];
-    ltr[3] = (int64_t) info->a[2] * info->a[4] -
-            (int64_t) info->a[5] * info->a[1];
-    ltr[4] = (int64_t) info->a[0] * info->y;
-    ltr[5] = (int64_t) info->a[3] * info->x;
-    ltr[6] = (int64_t) info->a[4] * info->a[0] -
-            (int64_t) info->a[1] * info->a[3];
-    ltr[7] = (int64_t) info->a[2] * info->a[3] -
-            (int64_t) info->a[5] * info->a[0];
-
-    /* Avoid integer overflow */
-    s->tr[0] = ltr[0] >> 11;
-    s->tr[1] = ltr[1] >> 11;
-    s->tr[2] = muldiv64(ltr[2], 1, info->a[6]);
-    s->tr[3] = muldiv64(ltr[3], 1 << 4, ltr[2]);
-    s->tr[4] = ltr[4] >> 11;
-    s->tr[5] = ltr[5] >> 11;
-    s->tr[6] = muldiv64(ltr[6], 1, info->a[6]);
-    s->tr[7] = muldiv64(ltr[7], 1 << 4, ltr[6]);
-#else
-
-    /* This version assumes touchscreen X & Y axis are parallel or
-     * perpendicular to LCD's  X & Y axis in some way.  */
-    if (abs(info->a[0]) > abs(info->a[1])) {
-        s->tr[0] = 0;
-        s->tr[1] = -info->a[6] * info->x;
-        s->tr[2] = info->a[0];
-        s->tr[3] = -info->a[2] / info->a[0];
-        s->tr[4] = info->a[6] * info->y;
-        s->tr[5] = 0;
-        s->tr[6] = info->a[4];
-        s->tr[7] = -info->a[5] / info->a[4];
-    } else {
-        s->tr[0] = info->a[6] * info->y;
-        s->tr[1] = 0;
-        s->tr[2] = info->a[1];
-        s->tr[3] = -info->a[2] / info->a[1];
-        s->tr[4] = 0;
-        s->tr[5] = -info->a[6] * info->x;
-        s->tr[6] = info->a[3];
-        s->tr[7] = -info->a[5] / info->a[3];
-    }
-
-    s->tr[0] >>= 11;
-    s->tr[1] >>= 11;
-    s->tr[3] <<= 4;
-    s->tr[4] >>= 11;
-    s->tr[5] >>= 11;
-    s->tr[7] <<= 4;
-#endif
-}
-
-void tsc210x_key_event(uWireSlave *chip, int key, int down)
-{
-    TSC210xState *s = (TSC210xState *) chip->opaque;
-
-    if (down)
-        s->kb.down |= 1 << key;
-    else
-        s->kb.down &= ~(1 << key);
-
-    if (down && (s->kb.down & ~s->kb.mask) && !s->kb.intr) {
-        s->kb.intr = 1;
-        qemu_irq_lower(s->kbint);
-    } else if (s->kb.intr && !(s->kb.down & ~s->kb.mask) &&
-                    !(s->kb.mode & 1)) {
-        s->kb.intr = 0;
-        qemu_irq_raise(s->kbint);
-    }
-}
diff --git a/hw/tusb6010.c b/hw/tusb6010.c
deleted file mode 100644 (file)
index a5251a3..0000000
+++ /dev/null
@@ -1,813 +0,0 @@
-/*
- * Texas Instruments TUSB6010 emulation.
- * Based on reverse-engineering of a linux driver.
- *
- * Copyright (C) 2008 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.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 or
- * (at your option) version 3 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
- * 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 "qemu/timer.h"
-#include "hw/usb.h"
-#include "hw/omap.h"
-#include "hw/irq.h"
-#include "hw/devices.h"
-#include "hw/sysbus.h"
-
-typedef struct TUSBState {
-    SysBusDevice busdev;
-    MemoryRegion iomem[2];
-    qemu_irq irq;
-    MUSBState *musb;
-    QEMUTimer *otg_timer;
-    QEMUTimer *pwr_timer;
-
-    int power;
-    uint32_t scratch;
-    uint16_t test_reset;
-    uint32_t prcm_config;
-    uint32_t prcm_mngmt;
-    uint16_t otg_status;
-    uint32_t dev_config;
-    int host_mode;
-    uint32_t intr;
-    uint32_t intr_ok;
-    uint32_t mask;
-    uint32_t usbip_intr;
-    uint32_t usbip_mask;
-    uint32_t gpio_intr;
-    uint32_t gpio_mask;
-    uint32_t gpio_config;
-    uint32_t dma_intr;
-    uint32_t dma_mask;
-    uint32_t dma_map;
-    uint32_t dma_config;
-    uint32_t ep0_config;
-    uint32_t rx_config[15];
-    uint32_t tx_config[15];
-    uint32_t wkup_mask;
-    uint32_t pullup[2];
-    uint32_t control_config;
-    uint32_t otg_timer_val;
-} TUSBState;
-
-#define TUSB_DEVCLOCK                  60000000        /* 60 MHz */
-
-#define TUSB_VLYNQ_CTRL                        0x004
-
-/* Mentor Graphics OTG core registers.  */
-#define TUSB_BASE_OFFSET               0x400
-
-/* FIFO registers, 32-bit.  */
-#define TUSB_FIFO_BASE                 0x600
-
-/* Device System & Control registers, 32-bit.  */
-#define TUSB_SYS_REG_BASE              0x800
-
-#define TUSB_DEV_CONF                  (TUSB_SYS_REG_BASE + 0x000)
-#define        TUSB_DEV_CONF_USB_HOST_MODE     (1 << 16)
-#define        TUSB_DEV_CONF_PROD_TEST_MODE    (1 << 15)
-#define        TUSB_DEV_CONF_SOFT_ID           (1 << 1)
-#define        TUSB_DEV_CONF_ID_SEL            (1 << 0)
-
-#define TUSB_PHY_OTG_CTRL_ENABLE       (TUSB_SYS_REG_BASE + 0x004)
-#define TUSB_PHY_OTG_CTRL              (TUSB_SYS_REG_BASE + 0x008)
-#define        TUSB_PHY_OTG_CTRL_WRPROTECT     (0xa5 << 24)
-#define        TUSB_PHY_OTG_CTRL_O_ID_PULLUP   (1 << 23)
-#define        TUSB_PHY_OTG_CTRL_O_VBUS_DET_EN (1 << 19)
-#define        TUSB_PHY_OTG_CTRL_O_SESS_END_EN (1 << 18)
-#define        TUSB_PHY_OTG_CTRL_TESTM2        (1 << 17)
-#define        TUSB_PHY_OTG_CTRL_TESTM1        (1 << 16)
-#define        TUSB_PHY_OTG_CTRL_TESTM0        (1 << 15)
-#define        TUSB_PHY_OTG_CTRL_TX_DATA2      (1 << 14)
-#define        TUSB_PHY_OTG_CTRL_TX_GZ2        (1 << 13)
-#define        TUSB_PHY_OTG_CTRL_TX_ENABLE2    (1 << 12)
-#define        TUSB_PHY_OTG_CTRL_DM_PULLDOWN   (1 << 11)
-#define        TUSB_PHY_OTG_CTRL_DP_PULLDOWN   (1 << 10)
-#define        TUSB_PHY_OTG_CTRL_OSC_EN        (1 << 9)
-#define        TUSB_PHY_OTG_CTRL_PHYREF_CLK(v) (((v) & 3) << 7)
-#define        TUSB_PHY_OTG_CTRL_PD            (1 << 6)
-#define        TUSB_PHY_OTG_CTRL_PLL_ON        (1 << 5)
-#define        TUSB_PHY_OTG_CTRL_EXT_RPU       (1 << 4)
-#define        TUSB_PHY_OTG_CTRL_PWR_GOOD      (1 << 3)
-#define        TUSB_PHY_OTG_CTRL_RESET         (1 << 2)
-#define        TUSB_PHY_OTG_CTRL_SUSPENDM      (1 << 1)
-#define        TUSB_PHY_OTG_CTRL_CLK_MODE      (1 << 0)
-
-/* OTG status register */
-#define TUSB_DEV_OTG_STAT              (TUSB_SYS_REG_BASE + 0x00c)
-#define        TUSB_DEV_OTG_STAT_PWR_CLK_GOOD  (1 << 8)
-#define        TUSB_DEV_OTG_STAT_SESS_END      (1 << 7)
-#define        TUSB_DEV_OTG_STAT_SESS_VALID    (1 << 6)
-#define        TUSB_DEV_OTG_STAT_VBUS_VALID    (1 << 5)
-#define        TUSB_DEV_OTG_STAT_VBUS_SENSE    (1 << 4)
-#define        TUSB_DEV_OTG_STAT_ID_STATUS     (1 << 3)
-#define        TUSB_DEV_OTG_STAT_HOST_DISCON   (1 << 2)
-#define        TUSB_DEV_OTG_STAT_LINE_STATE    (3 << 0)
-#define        TUSB_DEV_OTG_STAT_DP_ENABLE     (1 << 1)
-#define        TUSB_DEV_OTG_STAT_DM_ENABLE     (1 << 0)
-
-#define TUSB_DEV_OTG_TIMER             (TUSB_SYS_REG_BASE + 0x010)
-#define TUSB_DEV_OTG_TIMER_ENABLE      (1 << 31)
-#define TUSB_DEV_OTG_TIMER_VAL(v)      ((v) & 0x07ffffff)
-#define TUSB_PRCM_REV                  (TUSB_SYS_REG_BASE + 0x014)
-
-/* PRCM configuration register */
-#define TUSB_PRCM_CONF                 (TUSB_SYS_REG_BASE + 0x018)
-#define        TUSB_PRCM_CONF_SFW_CPEN         (1 << 24)
-#define        TUSB_PRCM_CONF_SYS_CLKSEL(v)    (((v) & 3) << 16)
-
-/* PRCM management register */
-#define TUSB_PRCM_MNGMT                        (TUSB_SYS_REG_BASE + 0x01c)
-#define        TUSB_PRCM_MNGMT_SRP_FIX_TMR(v)  (((v) & 0xf) << 25)
-#define        TUSB_PRCM_MNGMT_SRP_FIX_EN      (1 << 24)
-#define        TUSB_PRCM_MNGMT_VBUS_VAL_TMR(v) (((v) & 0xf) << 20)
-#define        TUSB_PRCM_MNGMT_VBUS_VAL_FLT_EN (1 << 19)
-#define        TUSB_PRCM_MNGMT_DFT_CLK_DIS     (1 << 18)
-#define        TUSB_PRCM_MNGMT_VLYNQ_CLK_DIS   (1 << 17)
-#define        TUSB_PRCM_MNGMT_OTG_SESS_END_EN (1 << 10)
-#define        TUSB_PRCM_MNGMT_OTG_VBUS_DET_EN (1 << 9)
-#define        TUSB_PRCM_MNGMT_OTG_ID_PULLUP   (1 << 8)
-#define        TUSB_PRCM_MNGMT_15_SW_EN        (1 << 4)
-#define        TUSB_PRCM_MNGMT_33_SW_EN        (1 << 3)
-#define        TUSB_PRCM_MNGMT_5V_CPEN         (1 << 2)
-#define        TUSB_PRCM_MNGMT_PM_IDLE         (1 << 1)
-#define        TUSB_PRCM_MNGMT_DEV_IDLE        (1 << 0)
-
-/* Wake-up source clear and mask registers */
-#define TUSB_PRCM_WAKEUP_SOURCE                (TUSB_SYS_REG_BASE + 0x020)
-#define TUSB_PRCM_WAKEUP_CLEAR         (TUSB_SYS_REG_BASE + 0x028)
-#define TUSB_PRCM_WAKEUP_MASK          (TUSB_SYS_REG_BASE + 0x02c)
-#define        TUSB_PRCM_WAKEUP_RESERVED_BITS  (0xffffe << 13)
-#define        TUSB_PRCM_WGPIO_7               (1 << 12)
-#define        TUSB_PRCM_WGPIO_6               (1 << 11)
-#define        TUSB_PRCM_WGPIO_5               (1 << 10)
-#define        TUSB_PRCM_WGPIO_4               (1 << 9)
-#define        TUSB_PRCM_WGPIO_3               (1 << 8)
-#define        TUSB_PRCM_WGPIO_2               (1 << 7)
-#define        TUSB_PRCM_WGPIO_1               (1 << 6)
-#define        TUSB_PRCM_WGPIO_0               (1 << 5)
-#define        TUSB_PRCM_WHOSTDISCON           (1 << 4)        /* Host disconnect */
-#define        TUSB_PRCM_WBUS                  (1 << 3)        /* USB bus resume */
-#define        TUSB_PRCM_WNORCS                (1 << 2)        /* NOR chip select */
-#define        TUSB_PRCM_WVBUS                 (1 << 1)        /* OTG PHY VBUS */
-#define        TUSB_PRCM_WID                   (1 << 0)        /* OTG PHY ID detect */
-
-#define TUSB_PULLUP_1_CTRL             (TUSB_SYS_REG_BASE + 0x030)
-#define TUSB_PULLUP_2_CTRL             (TUSB_SYS_REG_BASE + 0x034)
-#define TUSB_INT_CTRL_REV              (TUSB_SYS_REG_BASE + 0x038)
-#define TUSB_INT_CTRL_CONF             (TUSB_SYS_REG_BASE + 0x03c)
-#define TUSB_USBIP_INT_SRC             (TUSB_SYS_REG_BASE + 0x040)
-#define TUSB_USBIP_INT_SET             (TUSB_SYS_REG_BASE + 0x044)
-#define TUSB_USBIP_INT_CLEAR           (TUSB_SYS_REG_BASE + 0x048)
-#define TUSB_USBIP_INT_MASK            (TUSB_SYS_REG_BASE + 0x04c)
-#define TUSB_DMA_INT_SRC               (TUSB_SYS_REG_BASE + 0x050)
-#define TUSB_DMA_INT_SET               (TUSB_SYS_REG_BASE + 0x054)
-#define TUSB_DMA_INT_CLEAR             (TUSB_SYS_REG_BASE + 0x058)
-#define TUSB_DMA_INT_MASK              (TUSB_SYS_REG_BASE + 0x05c)
-#define TUSB_GPIO_INT_SRC              (TUSB_SYS_REG_BASE + 0x060)
-#define TUSB_GPIO_INT_SET              (TUSB_SYS_REG_BASE + 0x064)
-#define TUSB_GPIO_INT_CLEAR            (TUSB_SYS_REG_BASE + 0x068)
-#define TUSB_GPIO_INT_MASK             (TUSB_SYS_REG_BASE + 0x06c)
-
-/* NOR flash interrupt source registers */
-#define TUSB_INT_SRC                   (TUSB_SYS_REG_BASE + 0x070)
-#define TUSB_INT_SRC_SET               (TUSB_SYS_REG_BASE + 0x074)
-#define TUSB_INT_SRC_CLEAR             (TUSB_SYS_REG_BASE + 0x078)
-#define TUSB_INT_MASK                  (TUSB_SYS_REG_BASE + 0x07c)
-#define        TUSB_INT_SRC_TXRX_DMA_DONE      (1 << 24)
-#define        TUSB_INT_SRC_USB_IP_CORE        (1 << 17)
-#define        TUSB_INT_SRC_OTG_TIMEOUT        (1 << 16)
-#define        TUSB_INT_SRC_VBUS_SENSE_CHNG    (1 << 15)
-#define        TUSB_INT_SRC_ID_STATUS_CHNG     (1 << 14)
-#define        TUSB_INT_SRC_DEV_WAKEUP         (1 << 13)
-#define        TUSB_INT_SRC_DEV_READY          (1 << 12)
-#define        TUSB_INT_SRC_USB_IP_TX          (1 << 9)
-#define        TUSB_INT_SRC_USB_IP_RX          (1 << 8)
-#define        TUSB_INT_SRC_USB_IP_VBUS_ERR    (1 << 7)
-#define        TUSB_INT_SRC_USB_IP_VBUS_REQ    (1 << 6)
-#define        TUSB_INT_SRC_USB_IP_DISCON      (1 << 5)
-#define        TUSB_INT_SRC_USB_IP_CONN        (1 << 4)
-#define        TUSB_INT_SRC_USB_IP_SOF         (1 << 3)
-#define        TUSB_INT_SRC_USB_IP_RST_BABBLE  (1 << 2)
-#define        TUSB_INT_SRC_USB_IP_RESUME      (1 << 1)
-#define        TUSB_INT_SRC_USB_IP_SUSPEND     (1 << 0)
-
-#define TUSB_GPIO_REV                  (TUSB_SYS_REG_BASE + 0x080)
-#define TUSB_GPIO_CONF                 (TUSB_SYS_REG_BASE + 0x084)
-#define TUSB_DMA_CTRL_REV              (TUSB_SYS_REG_BASE + 0x100)
-#define TUSB_DMA_REQ_CONF              (TUSB_SYS_REG_BASE + 0x104)
-#define TUSB_EP0_CONF                  (TUSB_SYS_REG_BASE + 0x108)
-#define TUSB_EP_IN_SIZE                        (TUSB_SYS_REG_BASE + 0x10c)
-#define TUSB_DMA_EP_MAP                        (TUSB_SYS_REG_BASE + 0x148)
-#define TUSB_EP_OUT_SIZE               (TUSB_SYS_REG_BASE + 0x14c)
-#define TUSB_EP_MAX_PACKET_SIZE_OFFSET (TUSB_SYS_REG_BASE + 0x188)
-#define TUSB_SCRATCH_PAD               (TUSB_SYS_REG_BASE + 0x1c4)
-#define TUSB_WAIT_COUNT                        (TUSB_SYS_REG_BASE + 0x1c8)
-#define TUSB_PROD_TEST_RESET           (TUSB_SYS_REG_BASE + 0x1d8)
-
-#define TUSB_DIDR1_LO                  (TUSB_SYS_REG_BASE + 0x1f8)
-#define TUSB_DIDR1_HI                  (TUSB_SYS_REG_BASE + 0x1fc)
-
-/* Device System & Control register bitfields */
-#define TUSB_INT_CTRL_CONF_INT_RLCYC(v)        (((v) & 0x7) << 18)
-#define TUSB_INT_CTRL_CONF_INT_POLARITY        (1 << 17)
-#define TUSB_INT_CTRL_CONF_INT_MODE    (1 << 16)
-#define TUSB_GPIO_CONF_DMAREQ(v)       (((v) & 0x3f) << 24)
-#define TUSB_DMA_REQ_CONF_BURST_SIZE(v)        (((v) & 3) << 26)
-#define TUSB_DMA_REQ_CONF_DMA_RQ_EN(v) (((v) & 0x3f) << 20)
-#define TUSB_DMA_REQ_CONF_DMA_RQ_ASR(v)        (((v) & 0xf) << 16)
-#define TUSB_EP0_CONFIG_SW_EN          (1 << 8)
-#define TUSB_EP0_CONFIG_DIR_TX         (1 << 7)
-#define TUSB_EP0_CONFIG_XFR_SIZE(v)    ((v) & 0x7f)
-#define TUSB_EP_CONFIG_SW_EN           (1 << 31)
-#define TUSB_EP_CONFIG_XFR_SIZE(v)     ((v) & 0x7fffffff)
-#define TUSB_PROD_TEST_RESET_VAL       0xa596
-
-static void tusb_intr_update(TUSBState *s)
-{
-    if (s->control_config & TUSB_INT_CTRL_CONF_INT_POLARITY)
-        qemu_set_irq(s->irq, s->intr & ~s->mask & s->intr_ok);
-    else
-        qemu_set_irq(s->irq, (!(s->intr & ~s->mask)) & s->intr_ok);
-}
-
-static void tusb_usbip_intr_update(TUSBState *s)
-{
-    /* TX interrupt in the MUSB */
-    if (s->usbip_intr & 0x0000ffff & ~s->usbip_mask)
-        s->intr |= TUSB_INT_SRC_USB_IP_TX;
-    else
-        s->intr &= ~TUSB_INT_SRC_USB_IP_TX;
-
-    /* RX interrupt in the MUSB */
-    if (s->usbip_intr & 0xffff0000 & ~s->usbip_mask)
-        s->intr |= TUSB_INT_SRC_USB_IP_RX;
-    else
-        s->intr &= ~TUSB_INT_SRC_USB_IP_RX;
-
-    /* XXX: What about TUSB_INT_SRC_USB_IP_CORE?  */
-
-    tusb_intr_update(s);
-}
-
-static void tusb_dma_intr_update(TUSBState *s)
-{
-    if (s->dma_intr & ~s->dma_mask)
-        s->intr |= TUSB_INT_SRC_TXRX_DMA_DONE;
-    else
-        s->intr &= ~TUSB_INT_SRC_TXRX_DMA_DONE;
-
-    tusb_intr_update(s);
-}
-
-static void tusb_gpio_intr_update(TUSBState *s)
-{
-    /* TODO: How is this signalled?  */
-}
-
-extern CPUReadMemoryFunc * const musb_read[];
-extern CPUWriteMemoryFunc * const musb_write[];
-
-static uint32_t tusb_async_readb(void *opaque, hwaddr addr)
-{
-    TUSBState *s = (TUSBState *) opaque;
-
-    switch (addr & 0xfff) {
-    case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff):
-        return musb_read[0](s->musb, addr & 0x1ff);
-
-    case TUSB_FIFO_BASE ... (TUSB_FIFO_BASE | 0x1ff):
-        return musb_read[0](s->musb, 0x20 + ((addr >> 3) & 0x3c));
-    }
-
-    printf("%s: unknown register at %03x\n",
-                    __FUNCTION__, (int) (addr & 0xfff));
-    return 0;
-}
-
-static uint32_t tusb_async_readh(void *opaque, hwaddr addr)
-{
-    TUSBState *s = (TUSBState *) opaque;
-
-    switch (addr & 0xfff) {
-    case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff):
-        return musb_read[1](s->musb, addr & 0x1ff);
-
-    case TUSB_FIFO_BASE ... (TUSB_FIFO_BASE | 0x1ff):
-        return musb_read[1](s->musb, 0x20 + ((addr >> 3) & 0x3c));
-    }
-
-    printf("%s: unknown register at %03x\n",
-                    __FUNCTION__, (int) (addr & 0xfff));
-    return 0;
-}
-
-static uint32_t tusb_async_readw(void *opaque, hwaddr addr)
-{
-    TUSBState *s = (TUSBState *) opaque;
-    int offset = addr & 0xfff;
-    int epnum;
-    uint32_t ret;
-
-    switch (offset) {
-    case TUSB_DEV_CONF:
-        return s->dev_config;
-
-    case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff):
-        return musb_read[2](s->musb, offset & 0x1ff);
-
-    case TUSB_FIFO_BASE ... (TUSB_FIFO_BASE | 0x1ff):
-        return musb_read[2](s->musb, 0x20 + ((addr >> 3) & 0x3c));
-
-    case TUSB_PHY_OTG_CTRL_ENABLE:
-    case TUSB_PHY_OTG_CTRL:
-        return 0x00;   /* TODO */
-
-    case TUSB_DEV_OTG_STAT:
-        ret = s->otg_status;
-#if 0
-        if (!(s->prcm_mngmt & TUSB_PRCM_MNGMT_OTG_VBUS_DET_EN))
-            ret &= ~TUSB_DEV_OTG_STAT_VBUS_VALID;
-#endif
-        return ret;
-    case TUSB_DEV_OTG_TIMER:
-        return s->otg_timer_val;
-
-    case TUSB_PRCM_REV:
-        return 0x20;
-    case TUSB_PRCM_CONF:
-        return s->prcm_config;
-    case TUSB_PRCM_MNGMT:
-        return s->prcm_mngmt;
-    case TUSB_PRCM_WAKEUP_SOURCE:
-    case TUSB_PRCM_WAKEUP_CLEAR:       /* TODO: What does this one return?  */
-        return 0x00000000;
-    case TUSB_PRCM_WAKEUP_MASK:
-        return s->wkup_mask;
-
-    case TUSB_PULLUP_1_CTRL:
-        return s->pullup[0];
-    case TUSB_PULLUP_2_CTRL:
-        return s->pullup[1];
-
-    case TUSB_INT_CTRL_REV:
-        return 0x20;
-    case TUSB_INT_CTRL_CONF:
-        return s->control_config;
-
-    case TUSB_USBIP_INT_SRC:
-    case TUSB_USBIP_INT_SET:   /* TODO: What do these two return?  */
-    case TUSB_USBIP_INT_CLEAR:
-        return s->usbip_intr;
-    case TUSB_USBIP_INT_MASK:
-        return s->usbip_mask;
-
-    case TUSB_DMA_INT_SRC:
-    case TUSB_DMA_INT_SET:     /* TODO: What do these two return?  */
-    case TUSB_DMA_INT_CLEAR:
-        return s->dma_intr;
-    case TUSB_DMA_INT_MASK:
-        return s->dma_mask;
-
-    case TUSB_GPIO_INT_SRC:    /* TODO: What do these two return?  */
-    case TUSB_GPIO_INT_SET:
-    case TUSB_GPIO_INT_CLEAR:
-        return s->gpio_intr;
-    case TUSB_GPIO_INT_MASK:
-        return s->gpio_mask;
-
-    case TUSB_INT_SRC:
-    case TUSB_INT_SRC_SET:     /* TODO: What do these two return?  */
-    case TUSB_INT_SRC_CLEAR:
-        return s->intr;
-    case TUSB_INT_MASK:
-        return s->mask;
-
-    case TUSB_GPIO_REV:
-        return 0x30;
-    case TUSB_GPIO_CONF:
-        return s->gpio_config;
-
-    case TUSB_DMA_CTRL_REV:
-        return 0x30;
-    case TUSB_DMA_REQ_CONF:
-        return s->dma_config;
-    case TUSB_EP0_CONF:
-        return s->ep0_config;
-    case TUSB_EP_IN_SIZE ... (TUSB_EP_IN_SIZE + 0x3b):
-        epnum = (offset - TUSB_EP_IN_SIZE) >> 2;
-        return s->tx_config[epnum];
-    case TUSB_DMA_EP_MAP:
-        return s->dma_map;
-    case TUSB_EP_OUT_SIZE ... (TUSB_EP_OUT_SIZE + 0x3b):
-        epnum = (offset - TUSB_EP_OUT_SIZE) >> 2;
-        return s->rx_config[epnum];
-    case TUSB_EP_MAX_PACKET_SIZE_OFFSET ...
-            (TUSB_EP_MAX_PACKET_SIZE_OFFSET + 0x3b):
-        return 0x00000000;     /* TODO */
-    case TUSB_WAIT_COUNT:
-        return 0x00;           /* TODO */
-
-    case TUSB_SCRATCH_PAD:
-        return s->scratch;
-
-    case TUSB_PROD_TEST_RESET:
-        return s->test_reset;
-
-    /* DIE IDs */
-    case TUSB_DIDR1_LO:
-        return 0xa9453c59;
-    case TUSB_DIDR1_HI:
-        return 0x54059adf;
-    }
-
-    printf("%s: unknown register at %03x\n", __FUNCTION__, offset);
-    return 0;
-}
-
-static void tusb_async_writeb(void *opaque, hwaddr addr,
-                uint32_t value)
-{
-    TUSBState *s = (TUSBState *) opaque;
-
-    switch (addr & 0xfff) {
-    case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff):
-        musb_write[0](s->musb, addr & 0x1ff, value);
-        break;
-
-    case TUSB_FIFO_BASE ... (TUSB_FIFO_BASE | 0x1ff):
-        musb_write[0](s->musb, 0x20 + ((addr >> 3) & 0x3c), value);
-        break;
-
-    default:
-        printf("%s: unknown register at %03x\n",
-                        __FUNCTION__, (int) (addr & 0xfff));
-        return;
-    }
-}
-
-static void tusb_async_writeh(void *opaque, hwaddr addr,
-                uint32_t value)
-{
-    TUSBState *s = (TUSBState *) opaque;
-
-    switch (addr & 0xfff) {
-    case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff):
-        musb_write[1](s->musb, addr & 0x1ff, value);
-        break;
-
-    case TUSB_FIFO_BASE ... (TUSB_FIFO_BASE | 0x1ff):
-        musb_write[1](s->musb, 0x20 + ((addr >> 3) & 0x3c), value);
-        break;
-
-    default:
-        printf("%s: unknown register at %03x\n",
-                        __FUNCTION__, (int) (addr & 0xfff));
-        return;
-    }
-}
-
-static void tusb_async_writew(void *opaque, hwaddr addr,
-                uint32_t value)
-{
-    TUSBState *s = (TUSBState *) opaque;
-    int offset = addr & 0xfff;
-    int epnum;
-
-    switch (offset) {
-    case TUSB_VLYNQ_CTRL:
-        break;
-
-    case TUSB_BASE_OFFSET ... (TUSB_BASE_OFFSET | 0x1ff):
-        musb_write[2](s->musb, offset & 0x1ff, value);
-        break;
-
-    case TUSB_FIFO_BASE ... (TUSB_FIFO_BASE | 0x1ff):
-        musb_write[2](s->musb, 0x20 + ((addr >> 3) & 0x3c), value);
-        break;
-
-    case TUSB_DEV_CONF:
-        s->dev_config = value;
-        s->host_mode = (value & TUSB_DEV_CONF_USB_HOST_MODE);
-        if (value & TUSB_DEV_CONF_PROD_TEST_MODE)
-            hw_error("%s: Product Test mode not allowed\n", __FUNCTION__);
-        break;
-
-    case TUSB_PHY_OTG_CTRL_ENABLE:
-    case TUSB_PHY_OTG_CTRL:
-        return;                /* TODO */
-    case TUSB_DEV_OTG_TIMER:
-        s->otg_timer_val = value;
-        if (value & TUSB_DEV_OTG_TIMER_ENABLE)
-            qemu_mod_timer(s->otg_timer, qemu_get_clock_ns(vm_clock) +
-                            muldiv64(TUSB_DEV_OTG_TIMER_VAL(value),
-                                     get_ticks_per_sec(), TUSB_DEVCLOCK));
-        else
-            qemu_del_timer(s->otg_timer);
-        break;
-
-    case TUSB_PRCM_CONF:
-        s->prcm_config = value;
-        break;
-    case TUSB_PRCM_MNGMT:
-        s->prcm_mngmt = value;
-        break;
-    case TUSB_PRCM_WAKEUP_CLEAR:
-        break;
-    case TUSB_PRCM_WAKEUP_MASK:
-        s->wkup_mask = value;
-        break;
-
-    case TUSB_PULLUP_1_CTRL:
-        s->pullup[0] = value;
-        break;
-    case TUSB_PULLUP_2_CTRL:
-        s->pullup[1] = value;
-        break;
-    case TUSB_INT_CTRL_CONF:
-        s->control_config = value;
-        tusb_intr_update(s);
-        break;
-
-    case TUSB_USBIP_INT_SET:
-        s->usbip_intr |= value;
-        tusb_usbip_intr_update(s);
-        break;
-    case TUSB_USBIP_INT_CLEAR:
-        s->usbip_intr &= ~value;
-        tusb_usbip_intr_update(s);
-        musb_core_intr_clear(s->musb, ~value);
-        break;
-    case TUSB_USBIP_INT_MASK:
-        s->usbip_mask = value;
-        tusb_usbip_intr_update(s);
-        break;
-
-    case TUSB_DMA_INT_SET:
-        s->dma_intr |= value;
-        tusb_dma_intr_update(s);
-        break;
-    case TUSB_DMA_INT_CLEAR:
-        s->dma_intr &= ~value;
-        tusb_dma_intr_update(s);
-        break;
-    case TUSB_DMA_INT_MASK:
-        s->dma_mask = value;
-        tusb_dma_intr_update(s);
-        break;
-
-    case TUSB_GPIO_INT_SET:
-        s->gpio_intr |= value;
-        tusb_gpio_intr_update(s);
-        break;
-    case TUSB_GPIO_INT_CLEAR:
-        s->gpio_intr &= ~value;
-        tusb_gpio_intr_update(s);
-        break;
-    case TUSB_GPIO_INT_MASK:
-        s->gpio_mask = value;
-        tusb_gpio_intr_update(s);
-        break;
-
-    case TUSB_INT_SRC_SET:
-        s->intr |= value;
-        tusb_intr_update(s);
-        break;
-    case TUSB_INT_SRC_CLEAR:
-        s->intr &= ~value;
-        tusb_intr_update(s);
-        break;
-    case TUSB_INT_MASK:
-        s->mask = value;
-        tusb_intr_update(s);
-        break;
-
-    case TUSB_GPIO_CONF:
-        s->gpio_config = value;
-        break;
-    case TUSB_DMA_REQ_CONF:
-        s->dma_config = value;
-        break;
-    case TUSB_EP0_CONF:
-        s->ep0_config = value & 0x1ff;
-        musb_set_size(s->musb, 0, TUSB_EP0_CONFIG_XFR_SIZE(value),
-                        value & TUSB_EP0_CONFIG_DIR_TX);
-        break;
-    case TUSB_EP_IN_SIZE ... (TUSB_EP_IN_SIZE + 0x3b):
-        epnum = (offset - TUSB_EP_IN_SIZE) >> 2;
-        s->tx_config[epnum] = value;
-        musb_set_size(s->musb, epnum + 1, TUSB_EP_CONFIG_XFR_SIZE(value), 1);
-        break;
-    case TUSB_DMA_EP_MAP:
-        s->dma_map = value;
-        break;
-    case TUSB_EP_OUT_SIZE ... (TUSB_EP_OUT_SIZE + 0x3b):
-        epnum = (offset - TUSB_EP_OUT_SIZE) >> 2;
-        s->rx_config[epnum] = value;
-        musb_set_size(s->musb, epnum + 1, TUSB_EP_CONFIG_XFR_SIZE(value), 0);
-        break;
-    case TUSB_EP_MAX_PACKET_SIZE_OFFSET ...
-            (TUSB_EP_MAX_PACKET_SIZE_OFFSET + 0x3b):
-        return;                /* TODO */
-    case TUSB_WAIT_COUNT:
-        return;                /* TODO */
-
-    case TUSB_SCRATCH_PAD:
-        s->scratch = value;
-        break;
-
-    case TUSB_PROD_TEST_RESET:
-        s->test_reset = value;
-        break;
-
-    default:
-        printf("%s: unknown register at %03x\n", __FUNCTION__, offset);
-        return;
-    }
-}
-
-static const MemoryRegionOps tusb_async_ops = {
-    .old_mmio = {
-        .read = { tusb_async_readb, tusb_async_readh, tusb_async_readw, },
-        .write =  { tusb_async_writeb, tusb_async_writeh, tusb_async_writew, },
-    },
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void tusb_otg_tick(void *opaque)
-{
-    TUSBState *s = (TUSBState *) opaque;
-
-    s->otg_timer_val = 0;
-    s->intr |= TUSB_INT_SRC_OTG_TIMEOUT;
-    tusb_intr_update(s);
-}
-
-static void tusb_power_tick(void *opaque)
-{
-    TUSBState *s = (TUSBState *) opaque;
-
-    if (s->power) {
-        s->intr_ok = ~0;
-        tusb_intr_update(s);
-    }
-}
-
-static void tusb_musb_core_intr(void *opaque, int source, int level)
-{
-    TUSBState *s = (TUSBState *) opaque;
-    uint16_t otg_status = s->otg_status;
-
-    switch (source) {
-    case musb_set_vbus:
-        if (level)
-            otg_status |= TUSB_DEV_OTG_STAT_VBUS_VALID;
-        else
-            otg_status &= ~TUSB_DEV_OTG_STAT_VBUS_VALID;
-
-        /* XXX: only if TUSB_PHY_OTG_CTRL_OTG_VBUS_DET_EN set?  */
-        /* XXX: only if TUSB_PRCM_MNGMT_OTG_VBUS_DET_EN set?  */
-        if (s->otg_status != otg_status) {
-            s->otg_status = otg_status;
-            s->intr |= TUSB_INT_SRC_VBUS_SENSE_CHNG;
-            tusb_intr_update(s);
-        }
-        break;
-
-    case musb_set_session:
-        /* XXX: only if TUSB_PHY_OTG_CTRL_OTG_SESS_END_EN set?  */
-        /* XXX: only if TUSB_PRCM_MNGMT_OTG_SESS_END_EN set?  */
-        if (level) {
-            s->otg_status |= TUSB_DEV_OTG_STAT_SESS_VALID;
-            s->otg_status &= ~TUSB_DEV_OTG_STAT_SESS_END;
-        } else {
-            s->otg_status &= ~TUSB_DEV_OTG_STAT_SESS_VALID;
-            s->otg_status |= TUSB_DEV_OTG_STAT_SESS_END;
-        }
-
-        /* XXX: some IRQ or anything?  */
-        break;
-
-    case musb_irq_tx:
-    case musb_irq_rx:
-        s->usbip_intr = musb_core_intr_get(s->musb);
-        /* Fall through.  */
-    default:
-        if (level)
-            s->intr |= 1 << source;
-        else
-            s->intr &= ~(1 << source);
-        tusb_intr_update(s);
-        break;
-    }
-}
-
-static void tusb6010_power(TUSBState *s, int on)
-{
-    if (!on) {
-        s->power = 0;
-    } else if (!s->power && on) {
-        s->power = 1;
-        /* Pull the interrupt down after TUSB6010 comes up.  */
-        s->intr_ok = 0;
-        tusb_intr_update(s);
-        qemu_mod_timer(s->pwr_timer,
-                       qemu_get_clock_ns(vm_clock) + get_ticks_per_sec() / 2);
-    }
-}
-
-static void tusb6010_irq(void *opaque, int source, int level)
-{
-    if (source) {
-        tusb_musb_core_intr(opaque, source - 1, level);
-    } else {
-        tusb6010_power(opaque, level);
-    }
-}
-
-static void tusb6010_reset(DeviceState *dev)
-{
-    TUSBState *s = FROM_SYSBUS(TUSBState, SYS_BUS_DEVICE(dev));
-    int i;
-
-    s->test_reset = TUSB_PROD_TEST_RESET_VAL;
-    s->host_mode = 0;
-    s->dev_config = 0;
-    s->otg_status = 0; /* !TUSB_DEV_OTG_STAT_ID_STATUS means host mode */
-    s->power = 0;
-    s->mask = 0xffffffff;
-    s->intr = 0x00000000;
-    s->otg_timer_val = 0;
-    s->scratch = 0;
-    s->prcm_config = 0;
-    s->prcm_mngmt = 0;
-    s->intr_ok = 0;
-    s->usbip_intr = 0;
-    s->usbip_mask = 0;
-    s->gpio_intr = 0;
-    s->gpio_mask = 0;
-    s->gpio_config = 0;
-    s->dma_intr = 0;
-    s->dma_mask = 0;
-    s->dma_map = 0;
-    s->dma_config = 0;
-    s->ep0_config = 0;
-    s->wkup_mask = 0;
-    s->pullup[0] = s->pullup[1] = 0;
-    s->control_config = 0;
-    for (i = 0; i < 15; i++) {
-        s->rx_config[i] = s->tx_config[i] = 0;
-    }
-    musb_reset(s->musb);
-}
-
-static int tusb6010_init(SysBusDevice *dev)
-{
-    TUSBState *s = FROM_SYSBUS(TUSBState, dev);
-    s->otg_timer = qemu_new_timer_ns(vm_clock, tusb_otg_tick, s);
-    s->pwr_timer = qemu_new_timer_ns(vm_clock, tusb_power_tick, s);
-    memory_region_init_io(&s->iomem[1], &tusb_async_ops, s, "tusb-async",
-                          UINT32_MAX);
-    sysbus_init_mmio(dev, &s->iomem[0]);
-    sysbus_init_mmio(dev, &s->iomem[1]);
-    sysbus_init_irq(dev, &s->irq);
-    qdev_init_gpio_in(&dev->qdev, tusb6010_irq, musb_irq_max + 1);
-    s->musb = musb_init(&dev->qdev, 1);
-    return 0;
-}
-
-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 const TypeInfo tusb6010_info = {
-    .name          = "tusb6010",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(TUSBState),
-    .class_init    = tusb6010_class_init,
-};
-
-static void tusb6010_register_types(void)
-{
-    type_register_static(&tusb6010_info);
-}
-
-type_init(tusb6010_register_types)
diff --git a/hw/twl92230.c b/hw/twl92230.c
deleted file mode 100644 (file)
index 7d020c4..0000000
+++ /dev/null
@@ -1,882 +0,0 @@
-/*
- * TI TWL92230C energy-management companion device for the OMAP24xx.
- * Aka. Menelaus (N4200 MENELAUS1_V2.2)
- *
- * Copyright (C) 2008 Nokia Corporation
- * Written by Andrzej Zaborowski <andrew@openedhand.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 or
- * (at your option) version 3 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
- * 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 "hw/hw.h"
-#include "qemu/timer.h"
-#include "hw/i2c.h"
-#include "sysemu/sysemu.h"
-#include "ui/console.h"
-
-#define VERBOSE 1
-
-typedef struct {
-    I2CSlave i2c;
-
-    int firstbyte;
-    uint8_t reg;
-
-    uint8_t vcore[5];
-    uint8_t dcdc[3];
-    uint8_t ldo[8];
-    uint8_t sleep[2];
-    uint8_t osc;
-    uint8_t detect;
-    uint16_t mask;
-    uint16_t status;
-    uint8_t dir;
-    uint8_t inputs;
-    uint8_t outputs;
-    uint8_t bbsms;
-    uint8_t pull[4];
-    uint8_t mmc_ctrl[3];
-    uint8_t mmc_debounce;
-    struct {
-        uint8_t ctrl;
-        uint16_t comp;
-        QEMUTimer *hz_tm;
-        int64_t next;
-        struct tm tm;
-        struct tm new;
-        struct tm alm;
-        int sec_offset;
-        int alm_sec;
-        int next_comp;
-    } rtc;
-    uint16_t rtc_next_vmstate;
-    qemu_irq out[4];
-    uint8_t pwrbtn_state;
-} MenelausState;
-
-static inline void menelaus_update(MenelausState *s)
-{
-    qemu_set_irq(s->out[3], s->status & ~s->mask);
-}
-
-static inline void menelaus_rtc_start(MenelausState *s)
-{
-    s->rtc.next += qemu_get_clock_ms(rtc_clock);
-    qemu_mod_timer(s->rtc.hz_tm, s->rtc.next);
-}
-
-static inline void menelaus_rtc_stop(MenelausState *s)
-{
-    qemu_del_timer(s->rtc.hz_tm);
-    s->rtc.next -= qemu_get_clock_ms(rtc_clock);
-    if (s->rtc.next < 1)
-        s->rtc.next = 1;
-}
-
-static void menelaus_rtc_update(MenelausState *s)
-{
-    qemu_get_timedate(&s->rtc.tm, s->rtc.sec_offset);
-}
-
-static void menelaus_alm_update(MenelausState *s)
-{
-    if ((s->rtc.ctrl & 3) == 3)
-        s->rtc.alm_sec = qemu_timedate_diff(&s->rtc.alm) - s->rtc.sec_offset;
-}
-
-static void menelaus_rtc_hz(void *opaque)
-{
-    MenelausState *s = (MenelausState *) opaque;
-
-    s->rtc.next_comp --;
-    s->rtc.alm_sec --;
-    s->rtc.next += 1000;
-    qemu_mod_timer(s->rtc.hz_tm, s->rtc.next);
-    if ((s->rtc.ctrl >> 3) & 3) {                              /* EVERY */
-        menelaus_rtc_update(s);
-        if (((s->rtc.ctrl >> 3) & 3) == 1 && !s->rtc.tm.tm_sec)
-            s->status |= 1 << 8;                               /* RTCTMR */
-        else if (((s->rtc.ctrl >> 3) & 3) == 2 && !s->rtc.tm.tm_min)
-            s->status |= 1 << 8;                               /* RTCTMR */
-        else if (!s->rtc.tm.tm_hour)
-            s->status |= 1 << 8;                               /* RTCTMR */
-    } else
-        s->status |= 1 << 8;                                   /* RTCTMR */
-    if ((s->rtc.ctrl >> 1) & 1) {                              /* RTC_AL_EN */
-        if (s->rtc.alm_sec == 0)
-            s->status |= 1 << 9;                               /* RTCALM */
-        /* TODO: wake-up */
-    }
-    if (s->rtc.next_comp <= 0) {
-        s->rtc.next -= muldiv64((int16_t) s->rtc.comp, 1000, 0x8000);
-        s->rtc.next_comp = 3600;
-    }
-    menelaus_update(s);
-}
-
-static void menelaus_reset(I2CSlave *i2c)
-{
-    MenelausState *s = (MenelausState *) i2c;
-    s->reg = 0x00;
-
-    s->vcore[0] = 0x0c;        /* XXX: X-loader needs 0x8c? check!  */
-    s->vcore[1] = 0x05;
-    s->vcore[2] = 0x02;
-    s->vcore[3] = 0x0c;
-    s->vcore[4] = 0x03;
-    s->dcdc[0] = 0x33; /* Depends on wiring */
-    s->dcdc[1] = 0x03;
-    s->dcdc[2] = 0x00;
-    s->ldo[0] = 0x95;
-    s->ldo[1] = 0x7e;
-    s->ldo[2] = 0x00;
-    s->ldo[3] = 0x00;  /* Depends on wiring */
-    s->ldo[4] = 0x03;  /* Depends on wiring */
-    s->ldo[5] = 0x00;
-    s->ldo[6] = 0x00;
-    s->ldo[7] = 0x00;
-    s->sleep[0] = 0x00;
-    s->sleep[1] = 0x00;
-    s->osc = 0x01;
-    s->detect = 0x09;
-    s->mask = 0x0fff;
-    s->status = 0;
-    s->dir = 0x07;
-    s->outputs = 0x00;
-    s->bbsms = 0x00;
-    s->pull[0] = 0x00;
-    s->pull[1] = 0x00;
-    s->pull[2] = 0x00;
-    s->pull[3] = 0x00;
-    s->mmc_ctrl[0] = 0x03;
-    s->mmc_ctrl[1] = 0xc0;
-    s->mmc_ctrl[2] = 0x00;
-    s->mmc_debounce = 0x05;
-
-    if (s->rtc.ctrl & 1)
-        menelaus_rtc_stop(s);
-    s->rtc.ctrl = 0x00;
-    s->rtc.comp = 0x0000;
-    s->rtc.next = 1000;
-    s->rtc.sec_offset = 0;
-    s->rtc.next_comp = 1800;
-    s->rtc.alm_sec = 1800;
-    s->rtc.alm.tm_sec = 0x00;
-    s->rtc.alm.tm_min = 0x00;
-    s->rtc.alm.tm_hour = 0x00;
-    s->rtc.alm.tm_mday = 0x01;
-    s->rtc.alm.tm_mon = 0x00;
-    s->rtc.alm.tm_year = 2004;
-    menelaus_update(s);
-}
-
-static void menelaus_gpio_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 */
-        menelaus_update(s);
-    }
-    s->pwrbtn_state = level;
-}
-
-#define MENELAUS_REV           0x01
-#define MENELAUS_VCORE_CTRL1   0x02
-#define MENELAUS_VCORE_CTRL2   0x03
-#define MENELAUS_VCORE_CTRL3   0x04
-#define MENELAUS_VCORE_CTRL4   0x05
-#define MENELAUS_VCORE_CTRL5   0x06
-#define MENELAUS_DCDC_CTRL1    0x07
-#define MENELAUS_DCDC_CTRL2    0x08
-#define MENELAUS_DCDC_CTRL3    0x09
-#define MENELAUS_LDO_CTRL1     0x0a
-#define MENELAUS_LDO_CTRL2     0x0b
-#define MENELAUS_LDO_CTRL3     0x0c
-#define MENELAUS_LDO_CTRL4     0x0d
-#define MENELAUS_LDO_CTRL5     0x0e
-#define MENELAUS_LDO_CTRL6     0x0f
-#define MENELAUS_LDO_CTRL7     0x10
-#define MENELAUS_LDO_CTRL8     0x11
-#define MENELAUS_SLEEP_CTRL1   0x12
-#define MENELAUS_SLEEP_CTRL2   0x13
-#define MENELAUS_DEVICE_OFF    0x14
-#define MENELAUS_OSC_CTRL      0x15
-#define MENELAUS_DETECT_CTRL   0x16
-#define MENELAUS_INT_MASK1     0x17
-#define MENELAUS_INT_MASK2     0x18
-#define MENELAUS_INT_STATUS1   0x19
-#define MENELAUS_INT_STATUS2   0x1a
-#define MENELAUS_INT_ACK1      0x1b
-#define MENELAUS_INT_ACK2      0x1c
-#define MENELAUS_GPIO_CTRL     0x1d
-#define MENELAUS_GPIO_IN       0x1e
-#define MENELAUS_GPIO_OUT      0x1f
-#define MENELAUS_BBSMS         0x20
-#define MENELAUS_RTC_CTRL      0x21
-#define MENELAUS_RTC_UPDATE    0x22
-#define MENELAUS_RTC_SEC       0x23
-#define MENELAUS_RTC_MIN       0x24
-#define MENELAUS_RTC_HR                0x25
-#define MENELAUS_RTC_DAY       0x26
-#define MENELAUS_RTC_MON       0x27
-#define MENELAUS_RTC_YR                0x28
-#define MENELAUS_RTC_WKDAY     0x29
-#define MENELAUS_RTC_AL_SEC    0x2a
-#define MENELAUS_RTC_AL_MIN    0x2b
-#define MENELAUS_RTC_AL_HR     0x2c
-#define MENELAUS_RTC_AL_DAY    0x2d
-#define MENELAUS_RTC_AL_MON    0x2e
-#define MENELAUS_RTC_AL_YR     0x2f
-#define MENELAUS_RTC_COMP_MSB  0x30
-#define MENELAUS_RTC_COMP_LSB  0x31
-#define MENELAUS_S1_PULL_EN    0x32
-#define MENELAUS_S1_PULL_DIR   0x33
-#define MENELAUS_S2_PULL_EN    0x34
-#define MENELAUS_S2_PULL_DIR   0x35
-#define MENELAUS_MCT_CTRL1     0x36
-#define MENELAUS_MCT_CTRL2     0x37
-#define MENELAUS_MCT_CTRL3     0x38
-#define MENELAUS_MCT_PIN_ST    0x39
-#define MENELAUS_DEBOUNCE1     0x3a
-
-static uint8_t menelaus_read(void *opaque, uint8_t addr)
-{
-    MenelausState *s = (MenelausState *) opaque;
-    int reg = 0;
-
-    switch (addr) {
-    case MENELAUS_REV:
-        return 0x22;
-
-    case MENELAUS_VCORE_CTRL5: reg ++;
-    case MENELAUS_VCORE_CTRL4: reg ++;
-    case MENELAUS_VCORE_CTRL3: reg ++;
-    case MENELAUS_VCORE_CTRL2: reg ++;
-    case MENELAUS_VCORE_CTRL1:
-        return s->vcore[reg];
-
-    case MENELAUS_DCDC_CTRL3: reg ++;
-    case MENELAUS_DCDC_CTRL2: reg ++;
-    case MENELAUS_DCDC_CTRL1:
-        return s->dcdc[reg];
-
-    case MENELAUS_LDO_CTRL8: reg ++;
-    case MENELAUS_LDO_CTRL7: reg ++;
-    case MENELAUS_LDO_CTRL6: reg ++;
-    case MENELAUS_LDO_CTRL5: reg ++;
-    case MENELAUS_LDO_CTRL4: reg ++;
-    case MENELAUS_LDO_CTRL3: reg ++;
-    case MENELAUS_LDO_CTRL2: reg ++;
-    case MENELAUS_LDO_CTRL1:
-        return s->ldo[reg];
-
-    case MENELAUS_SLEEP_CTRL2: reg ++;
-    case MENELAUS_SLEEP_CTRL1:
-        return s->sleep[reg];
-
-    case MENELAUS_DEVICE_OFF:
-        return 0;
-
-    case MENELAUS_OSC_CTRL:
-        return s->osc | (1 << 7);                      /* CLK32K_GOOD */
-
-    case MENELAUS_DETECT_CTRL:
-        return s->detect;
-
-    case MENELAUS_INT_MASK1:
-        return (s->mask >> 0) & 0xff;
-    case MENELAUS_INT_MASK2:
-        return (s->mask >> 8) & 0xff;
-
-    case MENELAUS_INT_STATUS1:
-        return (s->status >> 0) & 0xff;
-    case MENELAUS_INT_STATUS2:
-        return (s->status >> 8) & 0xff;
-
-    case MENELAUS_INT_ACK1:
-    case MENELAUS_INT_ACK2:
-        return 0;
-
-    case MENELAUS_GPIO_CTRL:
-        return s->dir;
-    case MENELAUS_GPIO_IN:
-        return s->inputs | (~s->dir & s->outputs);
-    case MENELAUS_GPIO_OUT:
-        return s->outputs;
-
-    case MENELAUS_BBSMS:
-        return s->bbsms;
-
-    case MENELAUS_RTC_CTRL:
-        return s->rtc.ctrl;
-    case MENELAUS_RTC_UPDATE:
-        return 0x00;
-    case MENELAUS_RTC_SEC:
-        menelaus_rtc_update(s);
-        return to_bcd(s->rtc.tm.tm_sec);
-    case MENELAUS_RTC_MIN:
-        menelaus_rtc_update(s);
-        return to_bcd(s->rtc.tm.tm_min);
-    case MENELAUS_RTC_HR:
-        menelaus_rtc_update(s);
-        if ((s->rtc.ctrl >> 2) & 1)                    /* MODE12_n24 */
-            return to_bcd((s->rtc.tm.tm_hour % 12) + 1) |
-                    (!!(s->rtc.tm.tm_hour >= 12) << 7);        /* PM_nAM */
-        else
-            return to_bcd(s->rtc.tm.tm_hour);
-    case MENELAUS_RTC_DAY:
-        menelaus_rtc_update(s);
-        return to_bcd(s->rtc.tm.tm_mday);
-    case MENELAUS_RTC_MON:
-        menelaus_rtc_update(s);
-        return to_bcd(s->rtc.tm.tm_mon + 1);
-    case MENELAUS_RTC_YR:
-        menelaus_rtc_update(s);
-        return to_bcd(s->rtc.tm.tm_year - 2000);
-    case MENELAUS_RTC_WKDAY:
-        menelaus_rtc_update(s);
-        return to_bcd(s->rtc.tm.tm_wday);
-    case MENELAUS_RTC_AL_SEC:
-        return to_bcd(s->rtc.alm.tm_sec);
-    case MENELAUS_RTC_AL_MIN:
-        return to_bcd(s->rtc.alm.tm_min);
-    case MENELAUS_RTC_AL_HR:
-        if ((s->rtc.ctrl >> 2) & 1)                    /* MODE12_n24 */
-            return to_bcd((s->rtc.alm.tm_hour % 12) + 1) |
-                    (!!(s->rtc.alm.tm_hour >= 12) << 7);/* AL_PM_nAM */
-        else
-            return to_bcd(s->rtc.alm.tm_hour);
-    case MENELAUS_RTC_AL_DAY:
-        return to_bcd(s->rtc.alm.tm_mday);
-    case MENELAUS_RTC_AL_MON:
-        return to_bcd(s->rtc.alm.tm_mon + 1);
-    case MENELAUS_RTC_AL_YR:
-        return to_bcd(s->rtc.alm.tm_year - 2000);
-    case MENELAUS_RTC_COMP_MSB:
-        return (s->rtc.comp >> 8) & 0xff;
-    case MENELAUS_RTC_COMP_LSB:
-        return (s->rtc.comp >> 0) & 0xff;
-
-    case MENELAUS_S1_PULL_EN:
-        return s->pull[0];
-    case MENELAUS_S1_PULL_DIR:
-        return s->pull[1];
-    case MENELAUS_S2_PULL_EN:
-        return s->pull[2];
-    case MENELAUS_S2_PULL_DIR:
-        return s->pull[3];
-
-    case MENELAUS_MCT_CTRL3: reg ++;
-    case MENELAUS_MCT_CTRL2: reg ++;
-    case MENELAUS_MCT_CTRL1:
-        return s->mmc_ctrl[reg];
-    case MENELAUS_MCT_PIN_ST:
-        /* TODO: return the real Card Detect */
-        return 0;
-    case MENELAUS_DEBOUNCE1:
-        return s->mmc_debounce;
-
-    default:
-#ifdef VERBOSE
-        printf("%s: unknown register %02x\n", __FUNCTION__, addr);
-#endif
-        break;
-    }
-    return 0;
-}
-
-static void menelaus_write(void *opaque, uint8_t addr, uint8_t value)
-{
-    MenelausState *s = (MenelausState *) opaque;
-    int line;
-    int reg = 0;
-    struct tm tm;
-
-    switch (addr) {
-    case MENELAUS_VCORE_CTRL1:
-        s->vcore[0] = (value & 0xe) | MIN(value & 0x1f, 0x12);
-        break;
-    case MENELAUS_VCORE_CTRL2:
-        s->vcore[1] = value;
-        break;
-    case MENELAUS_VCORE_CTRL3:
-        s->vcore[2] = MIN(value & 0x1f, 0x12);
-        break;
-    case MENELAUS_VCORE_CTRL4:
-        s->vcore[3] = MIN(value & 0x1f, 0x12);
-        break;
-    case MENELAUS_VCORE_CTRL5:
-        s->vcore[4] = value & 3;
-        /* XXX
-         * auto set to 3 on M_Active, nRESWARM
-         * auto set to 0 on M_WaitOn, M_Backup
-         */
-        break;
-
-    case MENELAUS_DCDC_CTRL1:
-        s->dcdc[0] = value & 0x3f;
-        break;
-    case MENELAUS_DCDC_CTRL2:
-        s->dcdc[1] = value & 0x07;
-        /* XXX
-         * auto set to 3 on M_Active, nRESWARM
-         * auto set to 0 on M_WaitOn, M_Backup
-         */
-        break;
-    case MENELAUS_DCDC_CTRL3:
-        s->dcdc[2] = value & 0x07;
-        break;
-
-    case MENELAUS_LDO_CTRL1:
-        s->ldo[0] = value;
-        break;
-    case MENELAUS_LDO_CTRL2:
-        s->ldo[1] = value & 0x7f;
-        /* XXX
-         * auto set to 0x7e on M_WaitOn, M_Backup
-         */
-        break;
-    case MENELAUS_LDO_CTRL3:
-        s->ldo[2] = value & 3;
-        /* XXX
-         * auto set to 3 on M_Active, nRESWARM
-         * auto set to 0 on M_WaitOn, M_Backup
-         */
-        break;
-    case MENELAUS_LDO_CTRL4:
-        s->ldo[3] = value & 3;
-        /* XXX
-         * auto set to 3 on M_Active, nRESWARM
-         * auto set to 0 on M_WaitOn, M_Backup
-         */
-        break;
-    case MENELAUS_LDO_CTRL5:
-        s->ldo[4] = value & 3;
-        /* XXX
-         * auto set to 3 on M_Active, nRESWARM
-         * auto set to 0 on M_WaitOn, M_Backup
-         */
-        break;
-    case MENELAUS_LDO_CTRL6:
-        s->ldo[5] = value & 3;
-        break;
-    case MENELAUS_LDO_CTRL7:
-        s->ldo[6] = value & 3;
-        break;
-    case MENELAUS_LDO_CTRL8:
-        s->ldo[7] = value & 3;
-        break;
-
-    case MENELAUS_SLEEP_CTRL2: reg ++;
-    case MENELAUS_SLEEP_CTRL1:
-        s->sleep[reg] = value;
-        break;
-
-    case MENELAUS_DEVICE_OFF:
-        if (value & 1)
-            menelaus_reset(&s->i2c);
-        break;
-
-    case MENELAUS_OSC_CTRL:
-        s->osc = value & 7;
-        break;
-
-    case MENELAUS_DETECT_CTRL:
-        s->detect = value & 0x7f;
-        break;
-
-    case MENELAUS_INT_MASK1:
-        s->mask &= 0xf00;
-        s->mask |= value << 0;
-        menelaus_update(s);
-        break;
-    case MENELAUS_INT_MASK2:
-        s->mask &= 0x0ff;
-        s->mask |= value << 8;
-        menelaus_update(s);
-        break;
-
-    case MENELAUS_INT_ACK1:
-        s->status &= ~(((uint16_t) value) << 0);
-        menelaus_update(s);
-        break;
-    case MENELAUS_INT_ACK2:
-        s->status &= ~(((uint16_t) value) << 8);
-        menelaus_update(s);
-        break;
-
-    case MENELAUS_GPIO_CTRL:
-        for (line = 0; line < 3; line ++) {
-            if (((s->dir ^ value) >> line) & 1) {
-                qemu_set_irq(s->out[line],
-                             ((s->outputs & ~s->dir) >> line) & 1);
-            }
-        }
-        s->dir = value & 0x67;
-        break;
-    case MENELAUS_GPIO_OUT:
-        for (line = 0; line < 3; line ++) {
-            if ((((s->outputs ^ value) & ~s->dir) >> line) & 1) {
-                qemu_set_irq(s->out[line], (s->outputs >> line) & 1);
-            }
-        }
-        s->outputs = value & 0x07;
-        break;
-
-    case MENELAUS_BBSMS:
-        s->bbsms = 0x0d;
-        break;
-
-    case MENELAUS_RTC_CTRL:
-        if ((s->rtc.ctrl ^ value) & 1) {                       /* RTC_EN */
-            if (value & 1)
-                menelaus_rtc_start(s);
-            else
-                menelaus_rtc_stop(s);
-        }
-        s->rtc.ctrl = value & 0x1f;
-        menelaus_alm_update(s);
-        break;
-    case MENELAUS_RTC_UPDATE:
-        menelaus_rtc_update(s);
-        memcpy(&tm, &s->rtc.tm, sizeof(tm));
-        switch (value & 0xf) {
-        case 0:
-            break;
-        case 1:
-            tm.tm_sec = s->rtc.new.tm_sec;
-            break;
-        case 2:
-            tm.tm_min = s->rtc.new.tm_min;
-            break;
-        case 3:
-            if (s->rtc.new.tm_hour > 23)
-                goto rtc_badness;
-            tm.tm_hour = s->rtc.new.tm_hour;
-            break;
-        case 4:
-            if (s->rtc.new.tm_mday < 1)
-                goto rtc_badness;
-            /* TODO check range */
-            tm.tm_mday = s->rtc.new.tm_mday;
-            break;
-        case 5:
-            if (s->rtc.new.tm_mon < 0 || s->rtc.new.tm_mon > 11)
-                goto rtc_badness;
-            tm.tm_mon = s->rtc.new.tm_mon;
-            break;
-        case 6:
-            tm.tm_year = s->rtc.new.tm_year;
-            break;
-        case 7:
-            /* TODO set .tm_mday instead */
-            tm.tm_wday = s->rtc.new.tm_wday;
-            break;
-        case 8:
-            if (s->rtc.new.tm_hour > 23)
-                goto rtc_badness;
-            if (s->rtc.new.tm_mday < 1)
-                goto rtc_badness;
-            if (s->rtc.new.tm_mon < 0 || s->rtc.new.tm_mon > 11)
-                goto rtc_badness;
-            tm.tm_sec = s->rtc.new.tm_sec;
-            tm.tm_min = s->rtc.new.tm_min;
-            tm.tm_hour = s->rtc.new.tm_hour;
-            tm.tm_mday = s->rtc.new.tm_mday;
-            tm.tm_mon = s->rtc.new.tm_mon;
-            tm.tm_year = s->rtc.new.tm_year;
-            break;
-        rtc_badness:
-        default:
-            fprintf(stderr, "%s: bad RTC_UPDATE value %02x\n",
-                            __FUNCTION__, value);
-            s->status |= 1 << 10;                              /* RTCERR */
-            menelaus_update(s);
-        }
-        s->rtc.sec_offset = qemu_timedate_diff(&tm);
-        break;
-    case MENELAUS_RTC_SEC:
-        s->rtc.tm.tm_sec = from_bcd(value & 0x7f);
-        break;
-    case MENELAUS_RTC_MIN:
-        s->rtc.tm.tm_min = from_bcd(value & 0x7f);
-        break;
-    case MENELAUS_RTC_HR:
-        s->rtc.tm.tm_hour = (s->rtc.ctrl & (1 << 2)) ? /* MODE12_n24 */
-                MIN(from_bcd(value & 0x3f), 12) + ((value >> 7) ? 11 : -1) :
-                from_bcd(value & 0x3f);
-        break;
-    case MENELAUS_RTC_DAY:
-        s->rtc.tm.tm_mday = from_bcd(value);
-        break;
-    case MENELAUS_RTC_MON:
-        s->rtc.tm.tm_mon = MAX(1, from_bcd(value)) - 1;
-        break;
-    case MENELAUS_RTC_YR:
-        s->rtc.tm.tm_year = 2000 + from_bcd(value);
-        break;
-    case MENELAUS_RTC_WKDAY:
-        s->rtc.tm.tm_mday = from_bcd(value);
-        break;
-    case MENELAUS_RTC_AL_SEC:
-        s->rtc.alm.tm_sec = from_bcd(value & 0x7f);
-        menelaus_alm_update(s);
-        break;
-    case MENELAUS_RTC_AL_MIN:
-        s->rtc.alm.tm_min = from_bcd(value & 0x7f);
-        menelaus_alm_update(s);
-        break;
-    case MENELAUS_RTC_AL_HR:
-        s->rtc.alm.tm_hour = (s->rtc.ctrl & (1 << 2)) ?        /* MODE12_n24 */
-                MIN(from_bcd(value & 0x3f), 12) + ((value >> 7) ? 11 : -1) :
-                from_bcd(value & 0x3f);
-        menelaus_alm_update(s);
-        break;
-    case MENELAUS_RTC_AL_DAY:
-        s->rtc.alm.tm_mday = from_bcd(value);
-        menelaus_alm_update(s);
-        break;
-    case MENELAUS_RTC_AL_MON:
-        s->rtc.alm.tm_mon = MAX(1, from_bcd(value)) - 1;
-        menelaus_alm_update(s);
-        break;
-    case MENELAUS_RTC_AL_YR:
-        s->rtc.alm.tm_year = 2000 + from_bcd(value);
-        menelaus_alm_update(s);
-        break;
-    case MENELAUS_RTC_COMP_MSB:
-        s->rtc.comp &= 0xff;
-        s->rtc.comp |= value << 8;
-        break;
-    case MENELAUS_RTC_COMP_LSB:
-        s->rtc.comp &= 0xff << 8;
-        s->rtc.comp |= value;
-        break;
-
-    case MENELAUS_S1_PULL_EN:
-        s->pull[0] = value;
-        break;
-    case MENELAUS_S1_PULL_DIR:
-        s->pull[1] = value & 0x1f;
-        break;
-    case MENELAUS_S2_PULL_EN:
-        s->pull[2] = value;
-        break;
-    case MENELAUS_S2_PULL_DIR:
-        s->pull[3] = value & 0x1f;
-        break;
-
-    case MENELAUS_MCT_CTRL1:
-        s->mmc_ctrl[0] = value & 0x7f;
-        break;
-    case MENELAUS_MCT_CTRL2:
-        s->mmc_ctrl[1] = value;
-        /* TODO update Card Detect interrupts */
-        break;
-    case MENELAUS_MCT_CTRL3:
-        s->mmc_ctrl[2] = value & 0xf;
-        break;
-    case MENELAUS_DEBOUNCE1:
-        s->mmc_debounce = value & 0x3f;
-        break;
-
-    default:
-#ifdef VERBOSE
-        printf("%s: unknown register %02x\n", __FUNCTION__, addr);
-#endif
-    }
-}
-
-static void menelaus_event(I2CSlave *i2c, enum i2c_event event)
-{
-    MenelausState *s = (MenelausState *) i2c;
-
-    if (event == I2C_START_SEND)
-        s->firstbyte = 1;
-}
-
-static int menelaus_tx(I2CSlave *i2c, uint8_t data)
-{
-    MenelausState *s = (MenelausState *) i2c;
-    /* Interpret register address byte */
-    if (s->firstbyte) {
-        s->reg = data;
-        s->firstbyte = 0;
-    } else
-        menelaus_write(s, s->reg ++, data);
-
-    return 0;
-}
-
-static int menelaus_rx(I2CSlave *i2c)
-{
-    MenelausState *s = (MenelausState *) i2c;
-
-    return menelaus_read(s, s->reg ++);
-}
-
-/* Save restore 32 bit int as uint16_t
-   This is a Big hack, but it is how the old state did it.
-   Or we broke compatibility in the state, or we can't use struct tm
- */
-
-static int get_int32_as_uint16(QEMUFile *f, void *pv, size_t size)
-{
-    int *v = pv;
-    *v = qemu_get_be16(f);
-    return 0;
-}
-
-static void put_int32_as_uint16(QEMUFile *f, void *pv, size_t size)
-{
-    int *v = pv;
-    qemu_put_be16(f, *v);
-}
-
-static const VMStateInfo vmstate_hack_int32_as_uint16 = {
-    .name = "int32_as_uint16",
-    .get  = get_int32_as_uint16,
-    .put  = put_int32_as_uint16,
-};
-
-#define VMSTATE_UINT16_HACK(_f, _s)                                  \
-    VMSTATE_SINGLE(_f, _s, 0, vmstate_hack_int32_as_uint16, int32_t)
-
-
-static const VMStateDescription vmstate_menelaus_tm = {
-    .name = "menelaus_tm",
-    .version_id = 0,
-    .minimum_version_id = 0,
-    .minimum_version_id_old = 0,
-    .fields      = (VMStateField []) {
-        VMSTATE_UINT16_HACK(tm_sec, struct tm),
-        VMSTATE_UINT16_HACK(tm_min, struct tm),
-        VMSTATE_UINT16_HACK(tm_hour, struct tm),
-        VMSTATE_UINT16_HACK(tm_mday, struct tm),
-        VMSTATE_UINT16_HACK(tm_min, struct tm),
-        VMSTATE_UINT16_HACK(tm_year, struct tm),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void menelaus_pre_save(void *opaque)
-{
-    MenelausState *s = opaque;
-    /* Should be <= 1000 */
-    s->rtc_next_vmstate =  s->rtc.next - qemu_get_clock_ms(rtc_clock);
-}
-
-static int menelaus_post_load(void *opaque, int version_id)
-{
-    MenelausState *s = opaque;
-
-    if (s->rtc.ctrl & 1)                                       /* RTC_EN */
-        menelaus_rtc_stop(s);
-
-    s->rtc.next = s->rtc_next_vmstate;
-
-    menelaus_alm_update(s);
-    menelaus_update(s);
-    if (s->rtc.ctrl & 1)                                       /* RTC_EN */
-        menelaus_rtc_start(s);
-    return 0;
-}
-
-static const VMStateDescription vmstate_menelaus = {
-    .name = "menelaus",
-    .version_id = 0,
-    .minimum_version_id = 0,
-    .minimum_version_id_old = 0,
-    .pre_save = menelaus_pre_save,
-    .post_load = menelaus_post_load,
-    .fields      = (VMStateField []) {
-        VMSTATE_INT32(firstbyte, MenelausState),
-        VMSTATE_UINT8(reg, MenelausState),
-        VMSTATE_UINT8_ARRAY(vcore, MenelausState, 5),
-        VMSTATE_UINT8_ARRAY(dcdc, MenelausState, 3),
-        VMSTATE_UINT8_ARRAY(ldo, MenelausState, 8),
-        VMSTATE_UINT8_ARRAY(sleep, MenelausState, 2),
-        VMSTATE_UINT8(osc, MenelausState),
-        VMSTATE_UINT8(detect, MenelausState),
-        VMSTATE_UINT16(mask, MenelausState),
-        VMSTATE_UINT16(status, MenelausState),
-        VMSTATE_UINT8(dir, MenelausState),
-        VMSTATE_UINT8(inputs, MenelausState),
-        VMSTATE_UINT8(outputs, MenelausState),
-        VMSTATE_UINT8(bbsms, MenelausState),
-        VMSTATE_UINT8_ARRAY(pull, MenelausState, 4),
-        VMSTATE_UINT8_ARRAY(mmc_ctrl, MenelausState, 3),
-        VMSTATE_UINT8(mmc_debounce, MenelausState),
-        VMSTATE_UINT8(rtc.ctrl, MenelausState),
-        VMSTATE_UINT16(rtc.comp, MenelausState),
-        VMSTATE_UINT16(rtc_next_vmstate, MenelausState),
-        VMSTATE_STRUCT(rtc.new, MenelausState, 0, vmstate_menelaus_tm,
-                       struct tm),
-        VMSTATE_STRUCT(rtc.alm, MenelausState, 0, vmstate_menelaus_tm,
-                       struct tm),
-        VMSTATE_UINT8(pwrbtn_state, MenelausState),
-        VMSTATE_I2C_SLAVE(i2c, MenelausState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static int twl92230_init(I2CSlave *i2c)
-{
-    MenelausState *s = FROM_I2C_SLAVE(MenelausState, i2c);
-
-    s->rtc.hz_tm = qemu_new_timer_ms(rtc_clock, menelaus_rtc_hz, s);
-    /* Three output pins plus one interrupt pin.  */
-    qdev_init_gpio_out(&i2c->qdev, s->out, 4);
-
-    /* Three input pins plus one power-button pin.  */
-    qdev_init_gpio_in(&i2c->qdev, menelaus_gpio_set, 4);
-
-    menelaus_reset(&s->i2c);
-
-    return 0;
-}
-
-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 const TypeInfo twl92230_info = {
-    .name          = "twl92230",
-    .parent        = TYPE_I2C_SLAVE,
-    .instance_size = sizeof(MenelausState),
-    .class_init    = twl92230_class_init,
-};
-
-static void twl92230_register_types(void)
-{
-    type_register_static(&twl92230_info);
-}
-
-type_init(twl92230_register_types)
diff --git a/hw/uboot_image.h b/hw/uboot_image.h
deleted file mode 100644 (file)
index 9fc2760..0000000
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * (C) Copyright 2000-2005
- * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
- *
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * 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/>.
- *
- ********************************************************************
- * NOTE: This header file defines an interface to U-Boot. Including
- * this (unmodified) header file in another file is considered normal
- * use of U-Boot, and does *not* fall under the heading of "derived
- * work".
- ********************************************************************
- */
-
-#ifndef __UBOOT_IMAGE_H__
-#define __UBOOT_IMAGE_H__
-
-/*
- * Operating System Codes
- */
-#define IH_OS_INVALID          0       /* Invalid OS   */
-#define IH_OS_OPENBSD          1       /* OpenBSD      */
-#define IH_OS_NETBSD           2       /* NetBSD       */
-#define IH_OS_FREEBSD          3       /* FreeBSD      */
-#define IH_OS_4_4BSD           4       /* 4.4BSD       */
-#define IH_OS_LINUX            5       /* Linux        */
-#define IH_OS_SVR4             6       /* SVR4         */
-#define IH_OS_ESIX             7       /* Esix         */
-#define IH_OS_SOLARIS          8       /* Solaris      */
-#define IH_OS_IRIX             9       /* Irix         */
-#define IH_OS_SCO              10      /* SCO          */
-#define IH_OS_DELL             11      /* Dell         */
-#define IH_OS_NCR              12      /* NCR          */
-#define IH_OS_LYNXOS           13      /* LynxOS       */
-#define IH_OS_VXWORKS          14      /* VxWorks      */
-#define IH_OS_PSOS             15      /* pSOS         */
-#define IH_OS_QNX              16      /* QNX          */
-#define IH_OS_U_BOOT           17      /* Firmware     */
-#define IH_OS_RTEMS            18      /* RTEMS        */
-#define IH_OS_ARTOS            19      /* ARTOS        */
-#define IH_OS_UNITY            20      /* Unity OS     */
-
-/*
- * CPU Architecture Codes (supported by Linux)
- */
-#define IH_CPU_INVALID         0       /* Invalid CPU  */
-#define IH_CPU_ALPHA           1       /* Alpha        */
-#define IH_CPU_ARM             2       /* ARM          */
-#define IH_CPU_I386            3       /* Intel x86    */
-#define IH_CPU_IA64            4       /* IA64         */
-#define IH_CPU_MIPS            5       /* MIPS         */
-#define IH_CPU_MIPS64          6       /* MIPS  64 Bit */
-#define IH_CPU_PPC             7       /* PowerPC      */
-#define IH_CPU_S390            8       /* IBM S390     */
-#define IH_CPU_SH              9       /* SuperH       */
-#define IH_CPU_SPARC           10      /* Sparc        */
-#define IH_CPU_SPARC64         11      /* Sparc 64 Bit */
-#define IH_CPU_M68K            12      /* M68K         */
-#define IH_CPU_NIOS            13      /* Nios-32      */
-#define IH_CPU_MICROBLAZE      14      /* MicroBlaze   */
-#define IH_CPU_NIOS2           15      /* Nios-II      */
-#define IH_CPU_BLACKFIN                16      /* Blackfin     */
-#define IH_CPU_AVR32           17      /* AVR32        */
-
-/*
- * Image Types
- *
- * "Standalone Programs" are directly runnable in the environment
- *     provided by U-Boot; it is expected that (if they behave
- *     well) you can continue to work in U-Boot after return from
- *     the Standalone Program.
- * "OS Kernel Images" are usually images of some Embedded OS which
- *     will take over control completely. Usually these programs
- *     will install their own set of exception handlers, device
- *     drivers, set up the MMU, etc. - this means, that you cannot
- *     expect to re-enter U-Boot except by resetting the CPU.
- * "RAMDisk Images" are more or less just data blocks, and their
- *     parameters (address, size) are passed to an OS kernel that is
- *     being started.
- * "Multi-File Images" contain several images, typically an OS
- *     (Linux) kernel image and one or more data images like
- *     RAMDisks. This construct is useful for instance when you want
- *     to boot over the network using BOOTP etc., where the boot
- *     server provides just a single image file, but you want to get
- *     for instance an OS kernel and a RAMDisk image.
- *
- *     "Multi-File Images" start with a list of image sizes, each
- *     image size (in bytes) specified by an "uint32_t" in network
- *     byte order. This list is terminated by an "(uint32_t)0".
- *     Immediately after the terminating 0 follow the images, one by
- *     one, all aligned on "uint32_t" boundaries (size rounded up to
- *     a multiple of 4 bytes - except for the last file).
- *
- * "Firmware Images" are binary images containing firmware (like
- *     U-Boot or FPGA images) which usually will be programmed to
- *     flash memory.
- *
- * "Script files" are command sequences that will be executed by
- *     U-Boot's command interpreter; this feature is especially
- *     useful when you configure U-Boot to use a real shell (hush)
- *     as command interpreter (=> Shell Scripts).
- */
-
-#define IH_TYPE_INVALID                0       /* Invalid Image                */
-#define IH_TYPE_STANDALONE     1       /* Standalone Program           */
-#define IH_TYPE_KERNEL         2       /* OS Kernel Image              */
-#define IH_TYPE_RAMDISK                3       /* RAMDisk Image                */
-#define IH_TYPE_MULTI          4       /* Multi-File Image             */
-#define IH_TYPE_FIRMWARE       5       /* Firmware Image               */
-#define IH_TYPE_SCRIPT         6       /* Script file                  */
-#define IH_TYPE_FILESYSTEM     7       /* Filesystem Image (any type)  */
-#define IH_TYPE_FLATDT         8       /* Binary Flat Device Tree Blob */
-
-/*
- * Compression Types
- */
-#define IH_COMP_NONE           0       /*  No   Compression Used       */
-#define IH_COMP_GZIP           1       /* gzip  Compression Used       */
-#define IH_COMP_BZIP2          2       /* bzip2 Compression Used       */
-
-#define IH_MAGIC       0x27051956      /* Image Magic Number           */
-#define IH_NMLEN               32      /* Image Name Length            */
-
-/*
- * all data in network byte order (aka natural aka bigendian)
- */
-
-typedef struct uboot_image_header {
-       uint32_t        ih_magic;       /* Image Header Magic Number    */
-       uint32_t        ih_hcrc;        /* Image Header CRC Checksum    */
-       uint32_t        ih_time;        /* Image Creation Timestamp     */
-       uint32_t        ih_size;        /* Image Data Size              */
-       uint32_t        ih_load;        /* Data  Load  Address          */
-       uint32_t        ih_ep;          /* Entry Point Address          */
-       uint32_t        ih_dcrc;        /* Image Data CRC Checksum      */
-       uint8_t         ih_os;          /* Operating System             */
-       uint8_t         ih_arch;        /* CPU architecture             */
-       uint8_t         ih_type;        /* Image Type                   */
-       uint8_t         ih_comp;        /* Compression Type             */
-       uint8_t         ih_name[IH_NMLEN];      /* Image Name           */
-} uboot_image_header_t;
-
-
-#endif /* __IMAGE_H__ */
index 78ab13f9ed1b79d9b0e921a4eeebef5643a60fdb..7c8fc364c84fbef8f718378dc889476a4461d1cf 100644 (file)
 #include "hw/sysbus.h"
 #include "hw/boards.h"
 #include "hw/loader.h"
-#include "hw/pc.h"
+#include "hw/i386/pc.h"
 
 #undef DEBUG_PUV3
-#include "hw/puv3.h"
+#include "hw/unicore32/puv3.h"
 
 #define KERNEL_LOAD_ADDR        0x03000000
 #define KERNEL_MAX_SIZE         0x00800000 /* Just a guess */
diff --git a/hw/unin_pci.c b/hw/unin_pci.c
deleted file mode 100644 (file)
index fff235d..0000000
+++ /dev/null
@@ -1,492 +0,0 @@
-/*
- * QEMU Uninorth PCI host (for all Mac99 and newer machines)
- *
- * Copyright (c) 2006 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.
- */
-#include "hw/hw.h"
-#include "hw/ppc/mac.h"
-#include "hw/pci/pci.h"
-#include "hw/pci/pci_host.h"
-
-/* debug UniNorth */
-//#define DEBUG_UNIN
-
-#ifdef DEBUG_UNIN
-#define UNIN_DPRINTF(fmt, ...)                                  \
-    do { printf("UNIN: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define UNIN_DPRINTF(fmt, ...)
-#endif
-
-static const int unin_irq_line[] = { 0x1b, 0x1c, 0x1d, 0x1e };
-
-#define TYPE_UNI_NORTH_PCI_HOST_BRIDGE "uni-north-pci-pcihost"
-#define TYPE_UNI_NORTH_AGP_HOST_BRIDGE "uni-north-agp-pcihost"
-#define TYPE_UNI_NORTH_INTERNAL_PCI_HOST_BRIDGE "uni-north-internal-pci-pcihost"
-#define TYPE_U3_AGP_HOST_BRIDGE "u3-agp-pcihost"
-
-#define UNI_NORTH_PCI_HOST_BRIDGE(obj) \
-    OBJECT_CHECK(UNINState, (obj), TYPE_UNI_NORTH_PCI_HOST_BRIDGE)
-#define UNI_NORTH_AGP_HOST_BRIDGE(obj) \
-    OBJECT_CHECK(UNINState, (obj), TYPE_UNI_NORTH_AGP_HOST_BRIDGE)
-#define UNI_NORTH_INTERNAL_PCI_HOST_BRIDGE(obj) \
-    OBJECT_CHECK(UNINState, (obj), TYPE_UNI_NORTH_INTERNAL_PCI_HOST_BRIDGE)
-#define U3_AGP_HOST_BRIDGE(obj) \
-    OBJECT_CHECK(UNINState, (obj), TYPE_U3_AGP_HOST_BRIDGE)
-
-typedef struct UNINState {
-    PCIHostState parent_obj;
-
-    MemoryRegion pci_mmio;
-    MemoryRegion pci_hole;
-} UNINState;
-
-static int pci_unin_map_irq(PCIDevice *pci_dev, int irq_num)
-{
-    int retval;
-    int devfn = pci_dev->devfn & 0x00FFFFFF;
-
-    retval = (((devfn >> 11) & 0x1F) + irq_num) & 3;
-
-    return retval;
-}
-
-static void pci_unin_set_irq(void *opaque, int irq_num, int level)
-{
-    qemu_irq *pic = opaque;
-
-    UNIN_DPRINTF("%s: setting INT %d = %d\n", __func__,
-                 unin_irq_line[irq_num], level);
-    qemu_set_irq(pic[unin_irq_line[irq_num]], level);
-}
-
-static uint32_t unin_get_config_reg(uint32_t reg, uint32_t addr)
-{
-    uint32_t retval;
-
-    if (reg & (1u << 31)) {
-        /* XXX OpenBIOS compatibility hack */
-        retval = reg | (addr & 3);
-    } else if (reg & 1) {
-        /* CFA1 style */
-        retval = (reg & ~7u) | (addr & 7);
-    } else {
-        uint32_t slot, func;
-
-        /* Grab CFA0 style values */
-        slot = ffs(reg & 0xfffff800) - 1;
-        func = (reg >> 8) & 7;
-
-        /* ... and then convert them to x86 format */
-        /* config pointer */
-        retval = (reg & (0xff - 7)) | (addr & 7);
-        /* slot */
-        retval |= slot << 11;
-        /* fn */
-        retval |= func << 8;
-    }
-
-
-    UNIN_DPRINTF("Converted config space accessor %08x/%08x -> %08x\n",
-                 reg, addr, retval);
-
-    return retval;
-}
-
-static void unin_data_write(void *opaque, hwaddr addr,
-                            uint64_t val, unsigned len)
-{
-    UNINState *s = opaque;
-    PCIHostState *phb = PCI_HOST_BRIDGE(s);
-    UNIN_DPRINTF("write addr %" TARGET_FMT_plx " len %d val %"PRIx64"\n",
-                 addr, len, val);
-    pci_data_write(phb->bus,
-                   unin_get_config_reg(phb->config_reg, addr),
-                   val, len);
-}
-
-static uint64_t unin_data_read(void *opaque, hwaddr addr,
-                               unsigned len)
-{
-    UNINState *s = opaque;
-    PCIHostState *phb = PCI_HOST_BRIDGE(s);
-    uint32_t val;
-
-    val = pci_data_read(phb->bus,
-                        unin_get_config_reg(phb->config_reg, addr),
-                        len);
-    UNIN_DPRINTF("read addr %" TARGET_FMT_plx " len %d val %x\n",
-                 addr, len, val);
-    return val;
-}
-
-static const MemoryRegionOps unin_data_ops = {
-    .read = unin_data_read,
-    .write = unin_data_write,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static int pci_unin_main_init_device(SysBusDevice *dev)
-{
-    PCIHostState *h;
-
-    /* Use values found on a real PowerMac */
-    /* Uninorth main bus */
-    h = PCI_HOST_BRIDGE(dev);
-
-    memory_region_init_io(&h->conf_mem, &pci_host_conf_le_ops,
-                          dev, "pci-conf-idx", 0x1000);
-    memory_region_init_io(&h->data_mem, &unin_data_ops, dev,
-                          "pci-conf-data", 0x1000);
-    sysbus_init_mmio(dev, &h->conf_mem);
-    sysbus_init_mmio(dev, &h->data_mem);
-
-    return 0;
-}
-
-
-static int pci_u3_agp_init_device(SysBusDevice *dev)
-{
-    PCIHostState *h;
-
-    /* Uninorth U3 AGP bus */
-    h = PCI_HOST_BRIDGE(dev);
-
-    memory_region_init_io(&h->conf_mem, &pci_host_conf_le_ops,
-                          dev, "pci-conf-idx", 0x1000);
-    memory_region_init_io(&h->data_mem, &unin_data_ops, dev,
-                          "pci-conf-data", 0x1000);
-    sysbus_init_mmio(dev, &h->conf_mem);
-    sysbus_init_mmio(dev, &h->data_mem);
-
-    return 0;
-}
-
-static int pci_unin_agp_init_device(SysBusDevice *dev)
-{
-    PCIHostState *h;
-
-    /* Uninorth AGP bus */
-    h = PCI_HOST_BRIDGE(dev);
-
-    memory_region_init_io(&h->conf_mem, &pci_host_conf_le_ops,
-                          dev, "pci-conf-idx", 0x1000);
-    memory_region_init_io(&h->data_mem, &pci_host_data_le_ops,
-                          dev, "pci-conf-data", 0x1000);
-    sysbus_init_mmio(dev, &h->conf_mem);
-    sysbus_init_mmio(dev, &h->data_mem);
-    return 0;
-}
-
-static int pci_unin_internal_init_device(SysBusDevice *dev)
-{
-    PCIHostState *h;
-
-    /* Uninorth internal bus */
-    h = PCI_HOST_BRIDGE(dev);
-
-    memory_region_init_io(&h->conf_mem, &pci_host_conf_le_ops,
-                          dev, "pci-conf-idx", 0x1000);
-    memory_region_init_io(&h->data_mem, &pci_host_data_le_ops,
-                          dev, "pci-conf-data", 0x1000);
-    sysbus_init_mmio(dev, &h->conf_mem);
-    sysbus_init_mmio(dev, &h->data_mem);
-    return 0;
-}
-
-PCIBus *pci_pmac_init(qemu_irq *pic,
-                      MemoryRegion *address_space_mem,
-                      MemoryRegion *address_space_io)
-{
-    DeviceState *dev;
-    SysBusDevice *s;
-    PCIHostState *h;
-    UNINState *d;
-
-    /* Use values found on a real PowerMac */
-    /* Uninorth main bus */
-    dev = qdev_create(NULL, TYPE_UNI_NORTH_PCI_HOST_BRIDGE);
-    qdev_init_nofail(dev);
-    s = SYS_BUS_DEVICE(dev);
-    h = PCI_HOST_BRIDGE(s);
-    d = UNI_NORTH_PCI_HOST_BRIDGE(dev);
-    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);
-
-    h->bus = pci_register_bus(dev, "pci",
-                              pci_unin_set_irq, pci_unin_map_irq,
-                              pic,
-                              &d->pci_mmio,
-                              address_space_io,
-                              PCI_DEVFN(11, 0), 4, TYPE_PCI_BUS);
-
-#if 0
-    pci_create_simple(h->bus, PCI_DEVFN(11, 0), "uni-north");
-#endif
-
-    sysbus_mmio_map(s, 0, 0xf2800000);
-    sysbus_mmio_map(s, 1, 0xf2c00000);
-
-    /* DEC 21154 bridge */
-#if 0
-    /* XXX: not activated as PPC BIOS doesn't handle multiple buses properly */
-    pci_create_simple(h->bus, PCI_DEVFN(12, 0), "dec-21154");
-#endif
-
-    /* Uninorth AGP bus */
-    pci_create_simple(h->bus, PCI_DEVFN(11, 0), "uni-north-agp");
-    dev = qdev_create(NULL, TYPE_UNI_NORTH_AGP_HOST_BRIDGE);
-    qdev_init_nofail(dev);
-    s = SYS_BUS_DEVICE(dev);
-    sysbus_mmio_map(s, 0, 0xf0800000);
-    sysbus_mmio_map(s, 1, 0xf0c00000);
-
-    /* Uninorth internal bus */
-#if 0
-    /* XXX: not needed for now */
-    pci_create_simple(h->bus, PCI_DEVFN(14, 0),
-                      "uni-north-internal-pci");
-    dev = qdev_create(NULL, TYPE_UNI_NORTH_INTERNAL_PCI_HOST_BRIDGE);
-    qdev_init_nofail(dev);
-    s = SYS_BUS_DEVICE(dev);
-    sysbus_mmio_map(s, 0, 0xf4800000);
-    sysbus_mmio_map(s, 1, 0xf4c00000);
-#endif
-
-    return h->bus;
-}
-
-PCIBus *pci_pmac_u3_init(qemu_irq *pic,
-                         MemoryRegion *address_space_mem,
-                         MemoryRegion *address_space_io)
-{
-    DeviceState *dev;
-    SysBusDevice *s;
-    PCIHostState *h;
-    UNINState *d;
-
-    /* Uninorth AGP bus */
-
-    dev = qdev_create(NULL, TYPE_U3_AGP_HOST_BRIDGE);
-    qdev_init_nofail(dev);
-    s = SYS_BUS_DEVICE(dev);
-    h = PCI_HOST_BRIDGE(dev);
-    d = U3_AGP_HOST_BRIDGE(dev);
-
-    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);
-
-    h->bus = pci_register_bus(dev, "pci",
-                              pci_unin_set_irq, pci_unin_map_irq,
-                              pic,
-                              &d->pci_mmio,
-                              address_space_io,
-                              PCI_DEVFN(11, 0), 4, TYPE_PCI_BUS);
-
-    sysbus_mmio_map(s, 0, 0xf0800000);
-    sysbus_mmio_map(s, 1, 0xf0c00000);
-
-    pci_create_simple(h->bus, 11 << 3, "u3-agp");
-
-    return h->bus;
-}
-
-static int unin_main_pci_host_init(PCIDevice *d)
-{
-    d->config[0x0C] = 0x08; // cache_line_size
-    d->config[0x0D] = 0x10; // latency_timer
-    d->config[0x34] = 0x00; // capabilities_pointer
-    return 0;
-}
-
-static int unin_agp_pci_host_init(PCIDevice *d)
-{
-    d->config[0x0C] = 0x08; // cache_line_size
-    d->config[0x0D] = 0x10; // latency_timer
-    //    d->config[0x34] = 0x80; // capabilities_pointer
-    return 0;
-}
-
-static int u3_agp_pci_host_init(PCIDevice *d)
-{
-    /* cache line size */
-    d->config[0x0C] = 0x08;
-    /* latency timer */
-    d->config[0x0D] = 0x10;
-    return 0;
-}
-
-static int unin_internal_pci_host_init(PCIDevice *d)
-{
-    d->config[0x0C] = 0x08; // cache_line_size
-    d->config[0x0D] = 0x10; // latency_timer
-    d->config[0x34] = 0x00; // capabilities_pointer
-    return 0;
-}
-
-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 const TypeInfo unin_main_pci_host_info = {
-    .name = "uni-north-pci",
-    .parent = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(PCIDevice),
-    .class_init = unin_main_pci_host_class_init,
-};
-
-static void u3_agp_pci_host_class_init(ObjectClass *klass, void *data)
-{
-    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
-    k->init      = u3_agp_pci_host_init;
-    k->vendor_id = PCI_VENDOR_ID_APPLE;
-    k->device_id = PCI_DEVICE_ID_APPLE_U3_AGP;
-    k->revision  = 0x00;
-    k->class_id  = PCI_CLASS_BRIDGE_HOST;
-}
-
-static const TypeInfo u3_agp_pci_host_info = {
-    .name = "u3-agp",
-    .parent = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(PCIDevice),
-    .class_init = u3_agp_pci_host_class_init,
-};
-
-static void unin_agp_pci_host_class_init(ObjectClass *klass, void *data)
-{
-    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
-    k->init      = unin_agp_pci_host_init;
-    k->vendor_id = PCI_VENDOR_ID_APPLE;
-    k->device_id = PCI_DEVICE_ID_APPLE_UNI_N_AGP;
-    k->revision  = 0x00;
-    k->class_id  = PCI_CLASS_BRIDGE_HOST;
-}
-
-static const TypeInfo unin_agp_pci_host_info = {
-    .name = "uni-north-agp",
-    .parent = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(PCIDevice),
-    .class_init = unin_agp_pci_host_class_init,
-};
-
-static void unin_internal_pci_host_class_init(ObjectClass *klass, void *data)
-{
-    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
-    k->init      = unin_internal_pci_host_init;
-    k->vendor_id = PCI_VENDOR_ID_APPLE;
-    k->device_id = PCI_DEVICE_ID_APPLE_UNI_N_I_PCI;
-    k->revision  = 0x00;
-    k->class_id  = PCI_CLASS_BRIDGE_HOST;
-}
-
-static const TypeInfo unin_internal_pci_host_info = {
-    .name = "uni-north-internal-pci",
-    .parent = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(PCIDevice),
-    .class_init = unin_internal_pci_host_class_init,
-};
-
-static 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 const TypeInfo pci_unin_main_info = {
-    .name          = TYPE_UNI_NORTH_PCI_HOST_BRIDGE,
-    .parent        = TYPE_PCI_HOST_BRIDGE,
-    .instance_size = sizeof(UNINState),
-    .class_init    = pci_unin_main_class_init,
-};
-
-static void pci_u3_agp_class_init(ObjectClass *klass, void *data)
-{
-    SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
-
-    sbc->init = pci_u3_agp_init_device;
-}
-
-static const TypeInfo pci_u3_agp_info = {
-    .name          = TYPE_U3_AGP_HOST_BRIDGE,
-    .parent        = TYPE_PCI_HOST_BRIDGE,
-    .instance_size = sizeof(UNINState),
-    .class_init    = pci_u3_agp_class_init,
-};
-
-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 const TypeInfo pci_unin_agp_info = {
-    .name          = TYPE_UNI_NORTH_AGP_HOST_BRIDGE,
-    .parent        = TYPE_PCI_HOST_BRIDGE,
-    .instance_size = sizeof(UNINState),
-    .class_init    = pci_unin_agp_class_init,
-};
-
-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 const TypeInfo pci_unin_internal_info = {
-    .name          = TYPE_UNI_NORTH_INTERNAL_PCI_HOST_BRIDGE,
-    .parent        = TYPE_PCI_HOST_BRIDGE,
-    .instance_size = sizeof(UNINState),
-    .class_init    = pci_unin_internal_class_init,
-};
-
-static void unin_register_types(void)
-{
-    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);
-}
-
-type_init(unin_register_types)
diff --git a/hw/usb.h b/hw/usb.h
deleted file mode 100644 (file)
index 1b10684..0000000
--- a/hw/usb.h
+++ /dev/null
@@ -1,570 +0,0 @@
-#ifndef QEMU_USB_H
-#define QEMU_USB_H
-
-/*
- * QEMU USB API
- *
- * Copyright (c) 2005 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.
- */
-
-#include "hw/qdev.h"
-#include "qemu/queue.h"
-
-/* Constants related to the USB / PCI interaction */
-#define USB_SBRN    0x60 /* Serial Bus Release Number Register */
-#define USB_RELEASE_1  0x10 /* USB 1.0 */
-#define USB_RELEASE_2  0x20 /* USB 2.0 */
-#define USB_RELEASE_3  0x30 /* USB 3.0 */
-
-#define USB_TOKEN_SETUP 0x2d
-#define USB_TOKEN_IN    0x69 /* device -> host */
-#define USB_TOKEN_OUT   0xe1 /* host -> device */
-
-#define USB_RET_SUCCESS           (0)
-#define USB_RET_NODEV             (-1)
-#define USB_RET_NAK               (-2)
-#define USB_RET_STALL             (-3)
-#define USB_RET_BABBLE            (-4)
-#define USB_RET_IOERROR           (-5)
-#define USB_RET_ASYNC             (-6)
-#define USB_RET_ADD_TO_QUEUE      (-7)
-#define USB_RET_REMOVE_FROM_QUEUE (-8)
-
-#define USB_SPEED_LOW   0
-#define USB_SPEED_FULL  1
-#define USB_SPEED_HIGH  2
-#define USB_SPEED_SUPER 3
-
-#define USB_SPEED_MASK_LOW   (1 << USB_SPEED_LOW)
-#define USB_SPEED_MASK_FULL  (1 << USB_SPEED_FULL)
-#define USB_SPEED_MASK_HIGH  (1 << USB_SPEED_HIGH)
-#define USB_SPEED_MASK_SUPER (1 << USB_SPEED_SUPER)
-
-#define USB_STATE_NOTATTACHED 0
-#define USB_STATE_ATTACHED    1
-//#define USB_STATE_POWERED     2
-#define USB_STATE_DEFAULT     3
-//#define USB_STATE_ADDRESS     4
-//#define      USB_STATE_CONFIGURED  5
-#define USB_STATE_SUSPENDED   6
-
-#define USB_CLASS_AUDIO                        1
-#define USB_CLASS_COMM                 2
-#define USB_CLASS_HID                  3
-#define USB_CLASS_PHYSICAL             5
-#define USB_CLASS_STILL_IMAGE          6
-#define USB_CLASS_PRINTER              7
-#define USB_CLASS_MASS_STORAGE         8
-#define USB_CLASS_HUB                  9
-#define USB_CLASS_CDC_DATA             0x0a
-#define USB_CLASS_CSCID                        0x0b
-#define USB_CLASS_CONTENT_SEC          0x0d
-#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
-
-#define USB_TYPE_MASK                  (0x03 << 5)
-#define USB_TYPE_STANDARD              (0x00 << 5)
-#define USB_TYPE_CLASS                 (0x01 << 5)
-#define USB_TYPE_VENDOR                        (0x02 << 5)
-#define USB_TYPE_RESERVED              (0x03 << 5)
-
-#define USB_RECIP_MASK                 0x1f
-#define USB_RECIP_DEVICE               0x00
-#define USB_RECIP_INTERFACE            0x01
-#define USB_RECIP_ENDPOINT             0x02
-#define USB_RECIP_OTHER                        0x03
-
-#define DeviceRequest ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE)<<8)
-#define DeviceOutRequest ((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_DEVICE)<<8)
-#define InterfaceRequest \
-        ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8)
-#define InterfaceOutRequest \
-        ((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8)
-#define EndpointRequest ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_ENDPOINT)<<8)
-#define EndpointOutRequest \
-        ((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_ENDPOINT)<<8)
-#define ClassInterfaceRequest \
-        ((USB_DIR_IN|USB_TYPE_CLASS|USB_RECIP_INTERFACE)<<8)
-#define ClassInterfaceOutRequest \
-        ((USB_DIR_OUT|USB_TYPE_CLASS|USB_RECIP_INTERFACE)<<8)
-
-#define USB_REQ_GET_STATUS             0x00
-#define USB_REQ_CLEAR_FEATURE          0x01
-#define USB_REQ_SET_FEATURE            0x03
-#define USB_REQ_SET_ADDRESS            0x05
-#define USB_REQ_GET_DESCRIPTOR         0x06
-#define USB_REQ_SET_DESCRIPTOR         0x07
-#define USB_REQ_GET_CONFIGURATION      0x08
-#define USB_REQ_SET_CONFIGURATION      0x09
-#define USB_REQ_GET_INTERFACE          0x0A
-#define USB_REQ_SET_INTERFACE          0x0B
-#define USB_REQ_SYNCH_FRAME            0x0C
-
-#define USB_DEVICE_SELF_POWERED                0
-#define USB_DEVICE_REMOTE_WAKEUP       1
-
-#define USB_DT_DEVICE                  0x01
-#define USB_DT_CONFIG                  0x02
-#define USB_DT_STRING                  0x03
-#define USB_DT_INTERFACE               0x04
-#define USB_DT_ENDPOINT                        0x05
-#define USB_DT_DEVICE_QUALIFIER         0x06
-#define USB_DT_OTHER_SPEED_CONFIG       0x07
-#define USB_DT_DEBUG                    0x0A
-#define USB_DT_INTERFACE_ASSOC          0x0B
-#define USB_DT_BOS                      0x0F
-#define USB_DT_DEVICE_CAPABILITY        0x10
-#define USB_DT_CS_INTERFACE             0x24
-#define USB_DT_CS_ENDPOINT              0x25
-#define USB_DT_ENDPOINT_COMPANION       0x30
-
-#define USB_DEV_CAP_WIRELESS            0x01
-#define USB_DEV_CAP_USB2_EXT            0x02
-#define USB_DEV_CAP_SUPERSPEED          0x03
-
-#define USB_ENDPOINT_XFER_CONTROL      0
-#define USB_ENDPOINT_XFER_ISOC         1
-#define USB_ENDPOINT_XFER_BULK         2
-#define USB_ENDPOINT_XFER_INT          3
-#define USB_ENDPOINT_XFER_INVALID     255
-
-#define USB_INTERFACE_INVALID         255
-
-typedef struct USBBus USBBus;
-typedef struct USBBusOps USBBusOps;
-typedef struct USBPort USBPort;
-typedef struct USBDevice USBDevice;
-typedef struct USBPacket USBPacket;
-typedef struct USBCombinedPacket USBCombinedPacket;
-typedef struct USBEndpoint USBEndpoint;
-
-typedef struct USBDesc USBDesc;
-typedef struct USBDescID USBDescID;
-typedef struct USBDescDevice USBDescDevice;
-typedef struct USBDescConfig USBDescConfig;
-typedef struct USBDescIfaceAssoc USBDescIfaceAssoc;
-typedef struct USBDescIface USBDescIface;
-typedef struct USBDescEndpoint USBDescEndpoint;
-typedef struct USBDescOther USBDescOther;
-typedef struct USBDescString USBDescString;
-
-struct USBDescString {
-    uint8_t index;
-    char *str;
-    QLIST_ENTRY(USBDescString) next;
-};
-
-#define USB_MAX_ENDPOINTS  15
-#define USB_MAX_INTERFACES 16
-
-struct USBEndpoint {
-    uint8_t nr;
-    uint8_t pid;
-    uint8_t type;
-    uint8_t ifnum;
-    int max_packet_size;
-    bool pipeline;
-    bool halted;
-    USBDevice *dev;
-    QTAILQ_HEAD(, USBPacket) queue;
-};
-
-enum USBDeviceFlags {
-    USB_DEV_FLAG_FULL_PATH,
-    USB_DEV_FLAG_IS_HOST,
-};
-
-/* definition of a USB device */
-struct USBDevice {
-    DeviceState qdev;
-    USBPort *port;
-    char *port_path;
-    void *opaque;
-    uint32_t flags;
-
-    /* Actual connected speed */
-    int speed;
-    /* Supported speeds, not in info because it may be variable (hostdevs) */
-    int speedmask;
-    uint8_t addr;
-    char product_desc[32];
-    int auto_attach;
-    int attached;
-
-    int32_t state;
-    uint8_t setup_buf[8];
-    uint8_t data_buf[4096];
-    int32_t remote_wakeup;
-    int32_t setup_state;
-    int32_t setup_len;
-    int32_t setup_index;
-
-    USBEndpoint ep_ctl;
-    USBEndpoint ep_in[USB_MAX_ENDPOINTS];
-    USBEndpoint ep_out[USB_MAX_ENDPOINTS];
-
-    QLIST_HEAD(, USBDescString) strings;
-    const USBDesc *usb_desc; /* Overrides class usb_desc if not NULL */
-    const USBDescDevice *device;
-
-    int configuration;
-    int ninterfaces;
-    int altsetting[USB_MAX_INTERFACES];
-    const USBDescConfig *config;
-    const USBDescIface  *ifaces[USB_MAX_INTERFACES];
-};
-
-#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);
-
-    /*
-     * Walk (enabled) downstream ports, check for a matching device.
-     * Only hubs implement this.
-     */
-    USBDevice *(*find_device)(USBDevice *dev, uint8_t addr);
-
-    /*
-     * Called when a packet is canceled.
-     */
-    void (*cancel_packet)(USBDevice *dev, USBPacket *p);
-
-    /*
-     * Called when device is destroyed.
-     */
-    void (*handle_destroy)(USBDevice *dev);
-
-    /*
-     * Attach the device
-     */
-    void (*handle_attach)(USBDevice *dev);
-
-    /*
-     * Reset the device
-     */
-    void (*handle_reset)(USBDevice *dev);
-
-    /*
-     * Process control request.
-     * Called from handle_packet().
-     *
-     * Status gets stored in p->status, and if p->status == USB_RET_SUCCESS
-     * then the number of bytes transferred is stored in p->actual_length
-     */
-    void (*handle_control)(USBDevice *dev, USBPacket *p, int request, int value,
-                           int index, int length, uint8_t *data);
-
-    /*
-     * Process data transfers (both BULK and ISOC).
-     * Called from handle_packet().
-     *
-     * Status gets stored in p->status, and if p->status == USB_RET_SUCCESS
-     * then the number of bytes transferred is stored in p->actual_length
-     */
-    void (*handle_data)(USBDevice *dev, USBPacket *p);
-
-    void (*set_interface)(USBDevice *dev, int interface,
-                          int alt_old, int alt_new);
-
-    /*
-     * Called when the hcd is done queuing packets for an endpoint, only
-     * necessary for devices which can return USB_RET_ADD_TO_QUEUE.
-     */
-    void (*flush_ep_queue)(USBDevice *dev, USBEndpoint *ep);
-
-    /*
-     * Called by the hcd to let the device know the queue for an endpoint
-     * has been unlinked / stopped. Optional may be NULL.
-     */
-    void (*ep_stopped)(USBDevice *dev, USBEndpoint *ep);
-
-    const char *product_desc;
-    const USBDesc *usb_desc;
-} USBDeviceClass;
-
-typedef struct USBPortOps {
-    void (*attach)(USBPort *port);
-    void (*detach)(USBPort *port);
-    /*
-     * This gets called when a device downstream from the device attached to
-     * the port (iow attached through a hub) gets detached.
-     */
-    void (*child_detach)(USBPort *port, USBDevice *child);
-    void (*wakeup)(USBPort *port);
-    /*
-     * Note that port->dev will be different then the device from which
-     * the packet originated when a hub is involved.
-     */
-    void (*complete)(USBPort *port, USBPacket *p);
-} USBPortOps;
-
-/* USB port on which a device can be connected */
-struct USBPort {
-    USBDevice *dev;
-    int speedmask;
-    char path[16];
-    USBPortOps *ops;
-    void *opaque;
-    int index; /* internal port index, may be used with the opaque */
-    QTAILQ_ENTRY(USBPort) next;
-};
-
-typedef void USBCallback(USBPacket * packet, void *opaque);
-
-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;
-    uint64_t id;
-    USBEndpoint *ep;
-    unsigned int stream;
-    QEMUIOVector iov;
-    uint64_t parameter; /* control transfers */
-    bool short_not_ok;
-    bool int_req;
-    int status; /* USB_RET_* status code */
-    int actual_length; /* Number of bytes actually transferred */
-    /* Internal use by the USB layer.  */
-    USBPacketState state;
-    USBCombinedPacket *combined;
-    QTAILQ_ENTRY(USBPacket) queue;
-    QTAILQ_ENTRY(USBPacket) combined_entry;
-};
-
-struct USBCombinedPacket {
-    USBPacket *first;
-    QTAILQ_HEAD(packets_head, USBPacket) packets;
-    QEMUIOVector iov;
-};
-
-void usb_packet_init(USBPacket *p);
-void usb_packet_set_state(USBPacket *p, USBPacketState state);
-void usb_packet_check_state(USBPacket *p, USBPacketState expected);
-void usb_packet_setup(USBPacket *p, int pid,
-                      USBEndpoint *ep, unsigned int stream,
-                      uint64_t id, bool short_not_ok, bool int_req);
-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, QEMUSGList *sgl);
-void usb_packet_copy(USBPacket *p, void *ptr, size_t bytes);
-void usb_packet_skip(USBPacket *p, size_t bytes);
-size_t usb_packet_size(USBPacket *p);
-void usb_packet_cleanup(USBPacket *p);
-
-static inline bool usb_packet_is_inflight(USBPacket *p)
-{
-    return (p->state == USB_PACKET_QUEUED ||
-            p->state == USB_PACKET_ASYNC);
-}
-
-USBDevice *usb_find_device(USBPort *port, uint8_t addr);
-
-void usb_handle_packet(USBDevice *dev, USBPacket *p);
-void usb_packet_complete(USBDevice *dev, USBPacket *p);
-void usb_packet_complete_one(USBDevice *dev, USBPacket *p);
-void usb_cancel_packet(USBPacket * p);
-
-void usb_ep_init(USBDevice *dev);
-void usb_ep_reset(USBDevice *dev);
-void usb_ep_dump(USBDevice *dev);
-struct USBEndpoint *usb_ep_get(USBDevice *dev, int pid, int ep);
-uint8_t usb_ep_get_type(USBDevice *dev, int pid, int ep);
-uint8_t usb_ep_get_ifnum(USBDevice *dev, int pid, int ep);
-void usb_ep_set_type(USBDevice *dev, int pid, int ep, uint8_t type);
-void usb_ep_set_ifnum(USBDevice *dev, int pid, int ep, uint8_t ifnum);
-void usb_ep_set_max_packet_size(USBDevice *dev, int pid, int ep,
-                                uint16_t raw);
-int usb_ep_get_max_packet_size(USBDevice *dev, int pid, int ep);
-void usb_ep_set_pipeline(USBDevice *dev, int pid, int ep, bool enabled);
-void usb_ep_set_halted(USBDevice *dev, int pid, int ep, bool halted);
-USBPacket *usb_ep_find_packet_by_id(USBDevice *dev, int pid, int ep,
-                                    uint64_t id);
-
-void usb_ep_combine_input_packets(USBEndpoint *ep);
-void usb_combined_input_packet_complete(USBDevice *dev, USBPacket *p);
-void usb_combined_packet_cancel(USBDevice *dev, USBPacket *p);
-
-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(USBEndpoint *ep, unsigned int stream);
-void usb_generic_async_ctrl_complete(USBDevice *s, USBPacket *p);
-int set_usb_string(uint8_t *buf, const char *str);
-
-/* usb-linux.c */
-USBDevice *usb_host_device_open(USBBus *bus, const char *devname);
-void usb_host_info(Monitor *mon, const QDict *qdict);
-
-/* usb-bt.c */
-USBDevice *usb_bt_init(USBBus *bus, HCIInfo *hci);
-
-/* usb ports of the VM */
-
-#define VM_USB_HUB_SIZE 8
-
-/* usb-musb.c */
-enum musb_irq_source_e {
-    musb_irq_suspend = 0,
-    musb_irq_resume,
-    musb_irq_rst_babble,
-    musb_irq_sof,
-    musb_irq_connect,
-    musb_irq_disconnect,
-    musb_irq_vbus_request,
-    musb_irq_vbus_error,
-    musb_irq_rx,
-    musb_irq_tx,
-    musb_set_vbus,
-    musb_set_session,
-    /* Add new interrupts here */
-    musb_irq_max, /* total number of interrupts defined */
-};
-
-typedef struct MUSBState MUSBState;
-MUSBState *musb_init(DeviceState *parent_device, int gpio_base);
-void musb_reset(MUSBState *s);
-uint32_t musb_core_intr_get(MUSBState *s);
-void musb_core_intr_clear(MUSBState *s, uint32_t mask);
-void musb_set_size(MUSBState *s, int epnum, int size, int is_tx);
-
-/* usb-bus.c */
-
-#define TYPE_USB_BUS "usb-bus"
-#define USB_BUS(obj) OBJECT_CHECK(USBBus, (obj), TYPE_USB_BUS)
-
-struct USBBus {
-    BusState qbus;
-    USBBusOps *ops;
-    int busnr;
-    int nfree;
-    int nused;
-    QTAILQ_HEAD(, USBPort) free;
-    QTAILQ_HEAD(, USBPort) used;
-    QTAILQ_ENTRY(USBBus) next;
-};
-
-struct USBBusOps {
-    int (*register_companion)(USBBus *bus, USBPort *ports[],
-                              uint32_t portcount, uint32_t firstport);
-    void (*wakeup_endpoint)(USBBus *bus, USBEndpoint *ep, unsigned int stream);
-};
-
-void usb_bus_new(USBBus *bus, USBBusOps *ops, DeviceState *host);
-USBBus *usb_bus_find(int busnr);
-void usb_legacy_register(const char *typename, const char *usbdevice_name,
-                         USBDevice *(*usbdevice_init)(USBBus *bus,
-                                                      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);
-void usb_register_port(USBBus *bus, USBPort *port, void *opaque, int index,
-                       USBPortOps *ops, int speedmask);
-int usb_register_companion(const char *masterbus, USBPort *ports[],
-                           uint32_t portcount, uint32_t firstport,
-                           void *opaque, USBPortOps *ops, int speedmask);
-void usb_port_location(USBPort *downstream, USBPort *upstream, int portnr);
-void usb_unregister_port(USBBus *bus, USBPort *port);
-int usb_claim_port(USBDevice *dev);
-void usb_release_port(USBDevice *dev);
-int usb_device_attach(USBDevice *dev);
-int usb_device_detach(USBDevice *dev);
-int usb_device_delete_addr(int busnr, int addr);
-
-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),   \
-}
-
-USBDevice *usb_device_find_device(USBDevice *dev, uint8_t addr);
-
-void usb_device_cancel_packet(USBDevice *dev, USBPacket *p);
-
-void usb_device_handle_attach(USBDevice *dev);
-
-void usb_device_handle_reset(USBDevice *dev);
-
-void usb_device_handle_control(USBDevice *dev, USBPacket *p, int request,
-                               int val, int index, int length, uint8_t *data);
-
-void usb_device_handle_data(USBDevice *dev, USBPacket *p);
-
-void usb_device_set_interface(USBDevice *dev, int interface,
-                              int alt_old, int alt_new);
-
-void usb_device_flush_ep_queue(USBDevice *dev, USBEndpoint *ep);
-
-void usb_device_ep_stopped(USBDevice *dev, USBEndpoint *ep);
-
-const char *usb_device_get_product_desc(USBDevice *dev);
-
-const USBDesc *usb_device_get_usb_desc(USBDevice *dev);
-
-int ehci_create_ich9_with_companions(PCIBus *bus, int slot);
-
-/* quirks.c */
-
-/* In bulk endpoints are streaming data sources (iow behave like isoc eps) */
-#define USB_QUIRK_BUFFER_BULK_IN       0x01
-/* Bulk pkts in FTDI format, need special handling when combining packets */
-#define USB_QUIRK_IS_FTDI              0x02
-
-int usb_get_quirks(uint16_t vendor_id, uint16_t product_id,
-                   uint8_t interface_class, uint8_t interface_subclass,
-                   uint8_t interface_protocol);
-
-#endif
index e63e287ce0db32d46246c09a3f890af674af978b..f9695e7d8a48eb2efe4900a234800242963f882e 100644 (file)
@@ -7,6 +7,7 @@ common-obj-$(CONFIG_USB_UHCI) += hcd-uhci.o
 common-obj-$(CONFIG_USB_OHCI) += hcd-ohci.o
 common-obj-$(CONFIG_USB_EHCI) += hcd-ehci.o hcd-ehci-pci.o hcd-ehci-sysbus.o
 common-obj-$(CONFIG_USB_XHCI) += hcd-xhci.o
+common-obj-$(CONFIG_USB_MUSB) += hcd-musb.o
 
 # emulated usb devices
 common-obj-y += dev-hub.o
@@ -21,7 +22,12 @@ common-obj-$(CONFIG_USB_NETWORK)      += dev-network.o
 # FIXME: make configurable too
 CONFIG_USB_BLUETOOTH := y
 common-obj-$(CONFIG_USB_BLUETOOTH)    += dev-bluetooth.o
-common-obj-$(CONFIG_USB_SMARTCARD)    += dev-smartcard-reader.o
+
+ifeq ($(CONFIG_USB_SMARTCARD),y)
+common-obj-y                          += dev-smartcard-reader.o
+common-obj-y                          += ccid-card-passthru.o
+common-obj-$(CONFIG_SMARTCARD_NSS)    += ccid-card-emulated.o
+endif
 
 # usb redirection
 common-obj-$(CONFIG_USB_REDIR) += redirect.o quirks.o
index e58cd9ade2306a35110a79a687cf986c726f3b67..b10c290cf40d437745a21244538c4df6960d150a 100644 (file)
@@ -341,8 +341,10 @@ void usb_port_location(USBPort *downstream, USBPort *upstream, int portnr)
     if (upstream) {
         snprintf(downstream->path, sizeof(downstream->path), "%s.%d",
                  upstream->path, portnr);
+        downstream->hubcount = upstream->hubcount + 1;
     } else {
         snprintf(downstream->path, sizeof(downstream->path), "%d", portnr);
+        downstream->hubcount = 0;
     }
 }
 
diff --git a/hw/usb/ccid-card-emulated.c b/hw/usb/ccid-card-emulated.c
new file mode 100644 (file)
index 0000000..29dcd7a
--- /dev/null
@@ -0,0 +1,602 @@
+/*
+ * CCID Card Device. Emulated card.
+ *
+ * Copyright (c) 2011 Red Hat.
+ * Written by Alon Levy.
+ *
+ * This code is licensed under the GNU LGPL, version 2 or later.
+ */
+
+/*
+ * It can be used to provide access to the local hardware in a non exclusive
+ * way, or it can use certificates. It requires the usb-ccid bus.
+ *
+ * Usage 1: standard, mirror hardware reader+card:
+ * qemu .. -usb -device usb-ccid -device ccid-card-emulated
+ *
+ * Usage 2: use certificates, no hardware required
+ * one time: create the certificates:
+ *  for i in 1 2 3; do
+ *      certutil -d /etc/pki/nssdb -x -t "CT,CT,CT" -S -s "CN=user$i" -n user$i
+ *  done
+ * qemu .. -usb -device usb-ccid \
+ *  -device ccid-card-emulated,cert1=user1,cert2=user2,cert3=user3
+ *
+ * If you use a non default db for the certificates you can specify it using
+ * the db parameter.
+ */
+
+#include <eventt.h>
+#include <vevent.h>
+#include <vreader.h>
+#include <vcard_emul.h>
+
+#include "qemu/thread.h"
+#include "char/char.h"
+#include "monitor/monitor.h"
+#include "ccid.h"
+
+#define DPRINTF(card, lvl, fmt, ...) \
+do {\
+    if (lvl <= card->debug) {\
+        printf("ccid-card-emul: %s: " fmt , __func__, ## __VA_ARGS__);\
+    } \
+} while (0)
+
+#define EMULATED_DEV_NAME "ccid-card-emulated"
+
+#define BACKEND_NSS_EMULATED_NAME "nss-emulated"
+#define BACKEND_CERTIFICATES_NAME "certificates"
+
+enum {
+    BACKEND_NSS_EMULATED = 1,
+    BACKEND_CERTIFICATES
+};
+
+#define DEFAULT_BACKEND BACKEND_NSS_EMULATED
+
+typedef struct EmulatedState EmulatedState;
+
+enum {
+    EMUL_READER_INSERT = 0,
+    EMUL_READER_REMOVE,
+    EMUL_CARD_INSERT,
+    EMUL_CARD_REMOVE,
+    EMUL_GUEST_APDU,
+    EMUL_RESPONSE_APDU,
+    EMUL_ERROR,
+};
+
+static const char *emul_event_to_string(uint32_t emul_event)
+{
+    switch (emul_event) {
+    case EMUL_READER_INSERT:
+        return "EMUL_READER_INSERT";
+    case EMUL_READER_REMOVE:
+        return "EMUL_READER_REMOVE";
+    case EMUL_CARD_INSERT:
+        return "EMUL_CARD_INSERT";
+    case EMUL_CARD_REMOVE:
+        return "EMUL_CARD_REMOVE";
+    case EMUL_GUEST_APDU:
+        return "EMUL_GUEST_APDU";
+    case EMUL_RESPONSE_APDU:
+        return "EMUL_RESPONSE_APDU";
+    case EMUL_ERROR:
+        return "EMUL_ERROR";
+    }
+    return "UNKNOWN";
+}
+
+typedef struct EmulEvent {
+    QSIMPLEQ_ENTRY(EmulEvent) entry;
+    union {
+        struct {
+            uint32_t type;
+        } gen;
+        struct {
+            uint32_t type;
+            uint64_t code;
+        } error;
+        struct {
+            uint32_t type;
+            uint32_t len;
+            uint8_t data[];
+        } data;
+    } p;
+} EmulEvent;
+
+#define MAX_ATR_SIZE 40
+struct EmulatedState {
+    CCIDCardState base;
+    uint8_t  debug;
+    char    *backend_str;
+    uint32_t backend;
+    char    *cert1;
+    char    *cert2;
+    char    *cert3;
+    char    *db;
+    uint8_t  atr[MAX_ATR_SIZE];
+    uint8_t  atr_length;
+    QSIMPLEQ_HEAD(event_list, EmulEvent) event_list;
+    QemuMutex event_list_mutex;
+    QemuThread event_thread_id;
+    VReader *reader;
+    QSIMPLEQ_HEAD(guest_apdu_list, EmulEvent) guest_apdu_list;
+    QemuMutex vreader_mutex; /* and guest_apdu_list mutex */
+    QemuMutex handle_apdu_mutex;
+    QemuCond handle_apdu_cond;
+    int      pipe[2];
+    int      quit_apdu_thread;
+    QemuThread apdu_thread_id;
+};
+
+static void emulated_apdu_from_guest(CCIDCardState *base,
+    const uint8_t *apdu, uint32_t len)
+{
+    EmulatedState *card = DO_UPCAST(EmulatedState, base, base);
+    EmulEvent *event = (EmulEvent *)g_malloc(sizeof(EmulEvent) + len);
+
+    assert(event);
+    event->p.data.type = EMUL_GUEST_APDU;
+    event->p.data.len = len;
+    memcpy(event->p.data.data, apdu, len);
+    qemu_mutex_lock(&card->vreader_mutex);
+    QSIMPLEQ_INSERT_TAIL(&card->guest_apdu_list, event, entry);
+    qemu_mutex_unlock(&card->vreader_mutex);
+    qemu_mutex_lock(&card->handle_apdu_mutex);
+    qemu_cond_signal(&card->handle_apdu_cond);
+    qemu_mutex_unlock(&card->handle_apdu_mutex);
+}
+
+static const uint8_t *emulated_get_atr(CCIDCardState *base, uint32_t *len)
+{
+    EmulatedState *card = DO_UPCAST(EmulatedState, base, base);
+
+    *len = card->atr_length;
+    return card->atr;
+}
+
+static void emulated_push_event(EmulatedState *card, EmulEvent *event)
+{
+    qemu_mutex_lock(&card->event_list_mutex);
+    QSIMPLEQ_INSERT_TAIL(&(card->event_list), event, entry);
+    qemu_mutex_unlock(&card->event_list_mutex);
+    if (write(card->pipe[1], card, 1) != 1) {
+        DPRINTF(card, 1, "write to pipe failed\n");
+    }
+}
+
+static void emulated_push_type(EmulatedState *card, uint32_t type)
+{
+    EmulEvent *event = (EmulEvent *)g_malloc(sizeof(EmulEvent));
+
+    assert(event);
+    event->p.gen.type = type;
+    emulated_push_event(card, event);
+}
+
+static void emulated_push_error(EmulatedState *card, uint64_t code)
+{
+    EmulEvent *event = (EmulEvent *)g_malloc(sizeof(EmulEvent));
+
+    assert(event);
+    event->p.error.type = EMUL_ERROR;
+    event->p.error.code = code;
+    emulated_push_event(card, event);
+}
+
+static void emulated_push_data_type(EmulatedState *card, uint32_t type,
+    const uint8_t *data, uint32_t len)
+{
+    EmulEvent *event = (EmulEvent *)g_malloc(sizeof(EmulEvent) + len);
+
+    assert(event);
+    event->p.data.type = type;
+    event->p.data.len = len;
+    memcpy(event->p.data.data, data, len);
+    emulated_push_event(card, event);
+}
+
+static void emulated_push_reader_insert(EmulatedState *card)
+{
+    emulated_push_type(card, EMUL_READER_INSERT);
+}
+
+static void emulated_push_reader_remove(EmulatedState *card)
+{
+    emulated_push_type(card, EMUL_READER_REMOVE);
+}
+
+static void emulated_push_card_insert(EmulatedState *card,
+    const uint8_t *atr, uint32_t len)
+{
+    emulated_push_data_type(card, EMUL_CARD_INSERT, atr, len);
+}
+
+static void emulated_push_card_remove(EmulatedState *card)
+{
+    emulated_push_type(card, EMUL_CARD_REMOVE);
+}
+
+static void emulated_push_response_apdu(EmulatedState *card,
+    const uint8_t *apdu, uint32_t len)
+{
+    emulated_push_data_type(card, EMUL_RESPONSE_APDU, apdu, len);
+}
+
+#define APDU_BUF_SIZE 270
+static void *handle_apdu_thread(void* arg)
+{
+    EmulatedState *card = arg;
+    uint8_t recv_data[APDU_BUF_SIZE];
+    int recv_len;
+    VReaderStatus reader_status;
+    EmulEvent *event;
+
+    while (1) {
+        qemu_mutex_lock(&card->handle_apdu_mutex);
+        qemu_cond_wait(&card->handle_apdu_cond, &card->handle_apdu_mutex);
+        qemu_mutex_unlock(&card->handle_apdu_mutex);
+        if (card->quit_apdu_thread) {
+            card->quit_apdu_thread = 0; /* debugging */
+            break;
+        }
+        qemu_mutex_lock(&card->vreader_mutex);
+        while (!QSIMPLEQ_EMPTY(&card->guest_apdu_list)) {
+            event = QSIMPLEQ_FIRST(&card->guest_apdu_list);
+            assert((unsigned long)event > 1000);
+            QSIMPLEQ_REMOVE_HEAD(&card->guest_apdu_list, entry);
+            if (event->p.data.type != EMUL_GUEST_APDU) {
+                DPRINTF(card, 1, "unexpected message in handle_apdu_thread\n");
+                g_free(event);
+                continue;
+            }
+            if (card->reader == NULL) {
+                DPRINTF(card, 1, "reader is NULL\n");
+                g_free(event);
+                continue;
+            }
+            recv_len = sizeof(recv_data);
+            reader_status = vreader_xfr_bytes(card->reader,
+                    event->p.data.data, event->p.data.len,
+                    recv_data, &recv_len);
+            DPRINTF(card, 2, "got back apdu of length %d\n", recv_len);
+            if (reader_status == VREADER_OK) {
+                emulated_push_response_apdu(card, recv_data, recv_len);
+            } else {
+                emulated_push_error(card, reader_status);
+            }
+            g_free(event);
+        }
+        qemu_mutex_unlock(&card->vreader_mutex);
+    }
+    return NULL;
+}
+
+static void *event_thread(void *arg)
+{
+    int atr_len = MAX_ATR_SIZE;
+    uint8_t atr[MAX_ATR_SIZE];
+    VEvent *event = NULL;
+    EmulatedState *card = arg;
+
+    while (1) {
+        const char *reader_name;
+
+        event = vevent_wait_next_vevent();
+        if (event == NULL || event->type == VEVENT_LAST) {
+            break;
+        }
+        if (event->type != VEVENT_READER_INSERT) {
+            if (card->reader == NULL && event->reader != NULL) {
+                /* Happens after device_add followed by card remove or insert.
+                 * XXX: create synthetic add_reader events if vcard_emul_init
+                 * already called, which happens if device_del and device_add
+                 * are called */
+                card->reader = vreader_reference(event->reader);
+            } else {
+                if (event->reader != card->reader) {
+                    fprintf(stderr,
+                        "ERROR: wrong reader: quiting event_thread\n");
+                    break;
+                }
+            }
+        }
+        switch (event->type) {
+        case VEVENT_READER_INSERT:
+            /* TODO: take a specific reader. i.e. track which reader
+             * we are seeing here, check it is the one we want (the first,
+             * or by a particular name), and ignore if we don't want it.
+             */
+            reader_name = vreader_get_name(event->reader);
+            if (card->reader != NULL) {
+                DPRINTF(card, 2, "READER INSERT - replacing %s with %s\n",
+                    vreader_get_name(card->reader), reader_name);
+                qemu_mutex_lock(&card->vreader_mutex);
+                vreader_free(card->reader);
+                qemu_mutex_unlock(&card->vreader_mutex);
+                emulated_push_reader_remove(card);
+            }
+            qemu_mutex_lock(&card->vreader_mutex);
+            DPRINTF(card, 2, "READER INSERT %s\n", reader_name);
+            card->reader = vreader_reference(event->reader);
+            qemu_mutex_unlock(&card->vreader_mutex);
+            emulated_push_reader_insert(card);
+            break;
+        case VEVENT_READER_REMOVE:
+            DPRINTF(card, 2, " READER REMOVE: %s\n",
+                    vreader_get_name(event->reader));
+            qemu_mutex_lock(&card->vreader_mutex);
+            vreader_free(card->reader);
+            card->reader = NULL;
+            qemu_mutex_unlock(&card->vreader_mutex);
+            emulated_push_reader_remove(card);
+            break;
+        case VEVENT_CARD_INSERT:
+            /* get the ATR (intended as a response to a power on from the
+             * reader */
+            atr_len = MAX_ATR_SIZE;
+            vreader_power_on(event->reader, atr, &atr_len);
+            card->atr_length = (uint8_t)atr_len;
+            DPRINTF(card, 2, " CARD INSERT\n");
+            emulated_push_card_insert(card, atr, atr_len);
+            break;
+        case VEVENT_CARD_REMOVE:
+            DPRINTF(card, 2, " CARD REMOVE\n");
+            emulated_push_card_remove(card);
+            break;
+        case VEVENT_LAST: /* quit */
+            vevent_delete(event);
+            return NULL;
+            break;
+        default:
+            break;
+        }
+        vevent_delete(event);
+    }
+    return NULL;
+}
+
+static void pipe_read(void *opaque)
+{
+    EmulatedState *card = opaque;
+    EmulEvent *event, *next;
+    char dummy;
+    int len;
+
+    do {
+        len = read(card->pipe[0], &dummy, sizeof(dummy));
+    } while (len == sizeof(dummy));
+    qemu_mutex_lock(&card->event_list_mutex);
+    QSIMPLEQ_FOREACH_SAFE(event, &card->event_list, entry, next) {
+        DPRINTF(card, 2, "event %s\n", emul_event_to_string(event->p.gen.type));
+        switch (event->p.gen.type) {
+        case EMUL_RESPONSE_APDU:
+            ccid_card_send_apdu_to_guest(&card->base, event->p.data.data,
+                event->p.data.len);
+            break;
+        case EMUL_READER_INSERT:
+            ccid_card_ccid_attach(&card->base);
+            break;
+        case EMUL_READER_REMOVE:
+            ccid_card_ccid_detach(&card->base);
+            break;
+        case EMUL_CARD_INSERT:
+            assert(event->p.data.len <= MAX_ATR_SIZE);
+            card->atr_length = event->p.data.len;
+            memcpy(card->atr, event->p.data.data, card->atr_length);
+            ccid_card_card_inserted(&card->base);
+            break;
+        case EMUL_CARD_REMOVE:
+            ccid_card_card_removed(&card->base);
+            break;
+        case EMUL_ERROR:
+            ccid_card_card_error(&card->base, event->p.error.code);
+            break;
+        default:
+            DPRINTF(card, 2, "unexpected event\n");
+            break;
+        }
+        g_free(event);
+    }
+    QSIMPLEQ_INIT(&card->event_list);
+    qemu_mutex_unlock(&card->event_list_mutex);
+}
+
+static int init_pipe_signaling(EmulatedState *card)
+{
+    if (pipe(card->pipe) < 0) {
+        DPRINTF(card, 2, "pipe creation failed\n");
+        return -1;
+    }
+    fcntl(card->pipe[0], F_SETFL, O_NONBLOCK);
+    fcntl(card->pipe[1], F_SETFL, O_NONBLOCK);
+    fcntl(card->pipe[0], F_SETOWN, getpid());
+    qemu_set_fd_handler(card->pipe[0], pipe_read, NULL, card);
+    return 0;
+}
+
+#define CERTIFICATES_DEFAULT_DB "/etc/pki/nssdb"
+#define CERTIFICATES_ARGS_TEMPLATE\
+    "db=\"%s\" use_hw=no soft=(,Virtual Reader,CAC,,%s,%s,%s)"
+
+static int wrap_vcard_emul_init(VCardEmulOptions *options)
+{
+    static int called;
+    static int options_was_null;
+
+    if (called) {
+        if ((options == NULL) != options_was_null) {
+            printf("%s: warning: running emulated with certificates"
+                   " and emulated side by side is not supported\n",
+                   __func__);
+            return VCARD_EMUL_FAIL;
+        }
+        vcard_emul_replay_insertion_events();
+        return VCARD_EMUL_OK;
+    }
+    options_was_null = (options == NULL);
+    called = 1;
+    return vcard_emul_init(options);
+}
+
+static int emulated_initialize_vcard_from_certificates(EmulatedState *card)
+{
+    char emul_args[200];
+    VCardEmulOptions *options = NULL;
+
+    snprintf(emul_args, sizeof(emul_args) - 1, CERTIFICATES_ARGS_TEMPLATE,
+        card->db ? card->db : CERTIFICATES_DEFAULT_DB,
+        card->cert1, card->cert2, card->cert3);
+    options = vcard_emul_options(emul_args);
+    if (options == NULL) {
+        printf("%s: warning: not using certificates due to"
+               " initialization error\n", __func__);
+    }
+    return wrap_vcard_emul_init(options);
+}
+
+typedef struct EnumTable {
+    const char *name;
+    uint32_t value;
+} EnumTable;
+
+EnumTable backend_enum_table[] = {
+    {BACKEND_NSS_EMULATED_NAME, BACKEND_NSS_EMULATED},
+    {BACKEND_CERTIFICATES_NAME, BACKEND_CERTIFICATES},
+    {NULL, 0},
+};
+
+static uint32_t parse_enumeration(char *str,
+    EnumTable *table, uint32_t not_found_value)
+{
+    uint32_t ret = not_found_value;
+
+    while (table->name != NULL) {
+        if (strcmp(table->name, str) == 0) {
+            ret = table->value;
+            break;
+        }
+        table++;
+    }
+    return ret;
+}
+
+static int emulated_initfn(CCIDCardState *base)
+{
+    EmulatedState *card = DO_UPCAST(EmulatedState, base, base);
+    VCardEmulError ret;
+    EnumTable *ptable;
+
+    QSIMPLEQ_INIT(&card->event_list);
+    QSIMPLEQ_INIT(&card->guest_apdu_list);
+    qemu_mutex_init(&card->event_list_mutex);
+    qemu_mutex_init(&card->vreader_mutex);
+    qemu_mutex_init(&card->handle_apdu_mutex);
+    qemu_cond_init(&card->handle_apdu_cond);
+    card->reader = NULL;
+    card->quit_apdu_thread = 0;
+    if (init_pipe_signaling(card) < 0) {
+        return -1;
+    }
+    card->backend = parse_enumeration(card->backend_str, backend_enum_table, 0);
+    if (card->backend == 0) {
+        printf("unknown backend, must be one of:\n");
+        for (ptable = backend_enum_table; ptable->name != NULL; ++ptable) {
+            printf("%s\n", ptable->name);
+        }
+        return -1;
+    }
+
+    /* TODO: a passthru backened that works on local machine. third card type?*/
+    if (card->backend == BACKEND_CERTIFICATES) {
+        if (card->cert1 != NULL && card->cert2 != NULL && card->cert3 != NULL) {
+            ret = emulated_initialize_vcard_from_certificates(card);
+        } else {
+            printf("%s: you must provide all three certs for"
+                   " certificates backend\n", EMULATED_DEV_NAME);
+            return -1;
+        }
+    } else {
+        if (card->backend != BACKEND_NSS_EMULATED) {
+            printf("%s: bad backend specified. The options are:\n%s (default),"
+                " %s.\n", EMULATED_DEV_NAME, BACKEND_NSS_EMULATED_NAME,
+                BACKEND_CERTIFICATES_NAME);
+            return -1;
+        }
+        if (card->cert1 != NULL || card->cert2 != NULL || card->cert3 != NULL) {
+            printf("%s: unexpected cert parameters to nss emulated backend\n",
+                   EMULATED_DEV_NAME);
+            return -1;
+        }
+        /* default to mirroring the local hardware readers */
+        ret = wrap_vcard_emul_init(NULL);
+    }
+    if (ret != VCARD_EMUL_OK) {
+        printf("%s: failed to initialize vcard\n", EMULATED_DEV_NAME);
+        return -1;
+    }
+    qemu_thread_create(&card->event_thread_id, event_thread, card,
+                       QEMU_THREAD_JOINABLE);
+    qemu_thread_create(&card->apdu_thread_id, handle_apdu_thread, card,
+                       QEMU_THREAD_JOINABLE);
+    return 0;
+}
+
+static int emulated_exitfn(CCIDCardState *base)
+{
+    EmulatedState *card = DO_UPCAST(EmulatedState, base, base);
+    VEvent *vevent = vevent_new(VEVENT_LAST, NULL, NULL);
+
+    vevent_queue_vevent(vevent); /* stop vevent thread */
+    qemu_thread_join(&card->event_thread_id);
+
+    card->quit_apdu_thread = 1; /* stop handle_apdu thread */
+    qemu_cond_signal(&card->handle_apdu_cond);
+    qemu_thread_join(&card->apdu_thread_id);
+
+    /* threads exited, can destroy all condvars/mutexes */
+    qemu_cond_destroy(&card->handle_apdu_cond);
+    qemu_mutex_destroy(&card->handle_apdu_mutex);
+    qemu_mutex_destroy(&card->vreader_mutex);
+    qemu_mutex_destroy(&card->event_list_mutex);
+    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 const 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_types(void)
+{
+    type_register_static(&emulated_card_info);
+}
+
+type_init(ccid_card_emulated_register_types)
diff --git a/hw/usb/ccid-card-passthru.c b/hw/usb/ccid-card-passthru.c
new file mode 100644 (file)
index 0000000..5e017ae
--- /dev/null
@@ -0,0 +1,351 @@
+/*
+ * CCID Passthru Card Device emulation
+ *
+ * Copyright (c) 2011 Red Hat.
+ * Written by Alon Levy.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.1 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "char/char.h"
+#include "qemu/sockets.h"
+#include "monitor/monitor.h"
+#include "ccid.h"
+#include "libcacard/vscard_common.h"
+
+#define DPRINTF(card, lvl, fmt, ...)                    \
+do {                                                    \
+    if (lvl <= card->debug) {                           \
+        printf("ccid-card-passthru: " fmt , ## __VA_ARGS__);     \
+    }                                                   \
+} while (0)
+
+#define D_WARN 1
+#define D_INFO 2
+#define D_MORE_INFO 3
+#define D_VERBOSE 4
+
+/* TODO: do we still need this? */
+uint8_t DEFAULT_ATR[] = {
+/*
+ * From some example somewhere
+ * 0x3B, 0xB0, 0x18, 0x00, 0xD1, 0x81, 0x05, 0xB1, 0x40, 0x38, 0x1F, 0x03, 0x28
+ */
+
+/* From an Athena smart card */
+ 0x3B, 0xD5, 0x18, 0xFF, 0x80, 0x91, 0xFE, 0x1F, 0xC3, 0x80, 0x73, 0xC8, 0x21,
+ 0x13, 0x08
+};
+
+
+#define PASSTHRU_DEV_NAME "ccid-card-passthru"
+#define VSCARD_IN_SIZE 65536
+
+/* maximum size of ATR - from 7816-3 */
+#define MAX_ATR_SIZE        40
+
+typedef struct PassthruState PassthruState;
+
+struct PassthruState {
+    CCIDCardState base;
+    CharDriverState *cs;
+    uint8_t  vscard_in_data[VSCARD_IN_SIZE];
+    uint32_t vscard_in_pos;
+    uint32_t vscard_in_hdr;
+    uint8_t  atr[MAX_ATR_SIZE];
+    uint8_t  atr_length;
+    uint8_t  debug;
+};
+
+/*
+ * VSCard protocol over chardev
+ * This code should not depend on the card type.
+ */
+
+static void ccid_card_vscard_send_msg(PassthruState *s,
+        VSCMsgType type, uint32_t reader_id,
+        const uint8_t *payload, uint32_t length)
+{
+    VSCMsgHeader scr_msg_header;
+
+    scr_msg_header.type = htonl(type);
+    scr_msg_header.reader_id = htonl(reader_id);
+    scr_msg_header.length = htonl(length);
+    qemu_chr_fe_write(s->cs, (uint8_t *)&scr_msg_header, sizeof(VSCMsgHeader));
+    qemu_chr_fe_write(s->cs, payload, length);
+}
+
+static void ccid_card_vscard_send_apdu(PassthruState *s,
+    const uint8_t *apdu, uint32_t length)
+{
+    ccid_card_vscard_send_msg(
+        s, VSC_APDU, VSCARD_MINIMAL_READER_ID, apdu, length);
+}
+
+static void ccid_card_vscard_send_error(PassthruState *s,
+                    uint32_t reader_id, VSCErrorCode code)
+{
+    VSCMsgError msg = {.code = htonl(code)};
+
+    ccid_card_vscard_send_msg(
+        s, VSC_Error, reader_id, (uint8_t *)&msg, sizeof(msg));
+}
+
+static void ccid_card_vscard_send_init(PassthruState *s)
+{
+    VSCMsgInit msg = {
+        .version = htonl(VSCARD_VERSION),
+        .magic = VSCARD_MAGIC,
+        .capabilities = {0}
+    };
+
+    ccid_card_vscard_send_msg(s, VSC_Init, VSCARD_UNDEFINED_READER_ID,
+                         (uint8_t *)&msg, sizeof(msg));
+}
+
+static int ccid_card_vscard_can_read(void *opaque)
+{
+    PassthruState *card = opaque;
+
+    return VSCARD_IN_SIZE >= card->vscard_in_pos ?
+           VSCARD_IN_SIZE - card->vscard_in_pos : 0;
+}
+
+static void ccid_card_vscard_handle_init(
+    PassthruState *card, VSCMsgHeader *hdr, VSCMsgInit *init)
+{
+    uint32_t *capabilities;
+    int num_capabilities;
+    int i;
+
+    capabilities = init->capabilities;
+    num_capabilities =
+        1 + ((hdr->length - sizeof(VSCMsgInit)) / sizeof(uint32_t));
+    init->version = ntohl(init->version);
+    for (i = 0 ; i < num_capabilities; ++i) {
+        capabilities[i] = ntohl(capabilities[i]);
+    }
+    if (init->magic != VSCARD_MAGIC) {
+        error_report("wrong magic");
+        /* we can't disconnect the chardev */
+    }
+    if (init->version != VSCARD_VERSION) {
+        DPRINTF(card, D_WARN,
+            "got version %d, have %d", init->version, VSCARD_VERSION);
+    }
+    /* future handling of capabilities, none exist atm */
+    ccid_card_vscard_send_init(card);
+}
+
+static void ccid_card_vscard_handle_message(PassthruState *card,
+    VSCMsgHeader *scr_msg_header)
+{
+    uint8_t *data = (uint8_t *)&scr_msg_header[1];
+
+    switch (scr_msg_header->type) {
+    case VSC_ATR:
+        DPRINTF(card, D_INFO, "VSC_ATR %d\n", scr_msg_header->length);
+        if (scr_msg_header->length > MAX_ATR_SIZE) {
+            error_report("ATR size exceeds spec, ignoring");
+            ccid_card_vscard_send_error(card, scr_msg_header->reader_id,
+                                        VSC_GENERAL_ERROR);
+            break;
+        }
+        memcpy(card->atr, data, scr_msg_header->length);
+        card->atr_length = scr_msg_header->length;
+        ccid_card_card_inserted(&card->base);
+        ccid_card_vscard_send_error(card, scr_msg_header->reader_id,
+                                    VSC_SUCCESS);
+        break;
+    case VSC_APDU:
+        ccid_card_send_apdu_to_guest(
+            &card->base, data, scr_msg_header->length);
+        break;
+    case VSC_CardRemove:
+        DPRINTF(card, D_INFO, "VSC_CardRemove\n");
+        ccid_card_card_removed(&card->base);
+        ccid_card_vscard_send_error(card,
+            scr_msg_header->reader_id, VSC_SUCCESS);
+        break;
+    case VSC_Init:
+        ccid_card_vscard_handle_init(
+            card, scr_msg_header, (VSCMsgInit *)data);
+        break;
+    case VSC_Error:
+        ccid_card_card_error(&card->base, *(uint32_t *)data);
+        break;
+    case VSC_ReaderAdd:
+        if (ccid_card_ccid_attach(&card->base) < 0) {
+            ccid_card_vscard_send_error(card, VSCARD_UNDEFINED_READER_ID,
+                                      VSC_CANNOT_ADD_MORE_READERS);
+        } else {
+            ccid_card_vscard_send_error(card, VSCARD_MINIMAL_READER_ID,
+                                        VSC_SUCCESS);
+        }
+        break;
+    case VSC_ReaderRemove:
+        ccid_card_ccid_detach(&card->base);
+        ccid_card_vscard_send_error(card,
+            scr_msg_header->reader_id, VSC_SUCCESS);
+        break;
+    default:
+        printf("usb-ccid: chardev: unexpected message of type %X\n",
+               scr_msg_header->type);
+        ccid_card_vscard_send_error(card, scr_msg_header->reader_id,
+            VSC_GENERAL_ERROR);
+    }
+}
+
+static void ccid_card_vscard_drop_connection(PassthruState *card)
+{
+    qemu_chr_delete(card->cs);
+    card->vscard_in_pos = card->vscard_in_hdr = 0;
+}
+
+static void ccid_card_vscard_read(void *opaque, const uint8_t *buf, int size)
+{
+    PassthruState *card = opaque;
+    VSCMsgHeader *hdr;
+
+    if (card->vscard_in_pos + size > VSCARD_IN_SIZE) {
+        error_report(
+            "no room for data: pos %d +  size %d > %d. dropping connection.",
+            card->vscard_in_pos, size, VSCARD_IN_SIZE);
+        ccid_card_vscard_drop_connection(card);
+        return;
+    }
+    assert(card->vscard_in_pos < VSCARD_IN_SIZE);
+    assert(card->vscard_in_hdr < VSCARD_IN_SIZE);
+    memcpy(card->vscard_in_data + card->vscard_in_pos, buf, size);
+    card->vscard_in_pos += size;
+    hdr = (VSCMsgHeader *)(card->vscard_in_data + card->vscard_in_hdr);
+
+    while ((card->vscard_in_pos - card->vscard_in_hdr >= sizeof(VSCMsgHeader))
+         &&(card->vscard_in_pos - card->vscard_in_hdr >=
+                                  sizeof(VSCMsgHeader) + ntohl(hdr->length))) {
+        hdr->reader_id = ntohl(hdr->reader_id);
+        hdr->length = ntohl(hdr->length);
+        hdr->type = ntohl(hdr->type);
+        ccid_card_vscard_handle_message(card, hdr);
+        card->vscard_in_hdr += hdr->length + sizeof(VSCMsgHeader);
+        hdr = (VSCMsgHeader *)(card->vscard_in_data + card->vscard_in_hdr);
+    }
+    if (card->vscard_in_hdr == card->vscard_in_pos) {
+        card->vscard_in_pos = card->vscard_in_hdr = 0;
+    }
+}
+
+static void ccid_card_vscard_event(void *opaque, int event)
+{
+    PassthruState *card = opaque;
+
+    switch (event) {
+    case CHR_EVENT_BREAK:
+        card->vscard_in_pos = card->vscard_in_hdr = 0;
+        break;
+    case CHR_EVENT_FOCUS:
+        break;
+    case CHR_EVENT_OPENED:
+        DPRINTF(card, D_INFO, "%s: CHR_EVENT_OPENED\n", __func__);
+        break;
+    }
+}
+
+/* End VSCard handling */
+
+static void passthru_apdu_from_guest(
+    CCIDCardState *base, const uint8_t *apdu, uint32_t len)
+{
+    PassthruState *card = DO_UPCAST(PassthruState, base, base);
+
+    if (!card->cs) {
+        printf("ccid-passthru: no chardev, discarding apdu length %d\n", len);
+        return;
+    }
+    ccid_card_vscard_send_apdu(card, apdu, len);
+}
+
+static const uint8_t *passthru_get_atr(CCIDCardState *base, uint32_t *len)
+{
+    PassthruState *card = DO_UPCAST(PassthruState, base, base);
+
+    *len = card->atr_length;
+    return card->atr;
+}
+
+static int passthru_initfn(CCIDCardState *base)
+{
+    PassthruState *card = DO_UPCAST(PassthruState, base, base);
+
+    card->vscard_in_pos = 0;
+    card->vscard_in_hdr = 0;
+    if (card->cs) {
+        DPRINTF(card, D_INFO, "initing chardev\n");
+        qemu_chr_add_handlers(card->cs,
+            ccid_card_vscard_can_read,
+            ccid_card_vscard_read,
+            ccid_card_vscard_event, card);
+        ccid_card_vscard_send_init(card);
+    } else {
+        error_report("missing chardev");
+        return -1;
+    }
+    assert(sizeof(DEFAULT_ATR) <= MAX_ATR_SIZE);
+    memcpy(card->atr, DEFAULT_ATR, sizeof(DEFAULT_ATR));
+    card->atr_length = sizeof(DEFAULT_ATR);
+    return 0;
+}
+
+static int passthru_exitfn(CCIDCardState *base)
+{
+    return 0;
+}
+
+static VMStateDescription passthru_vmstate = {
+    .name = PASSTHRU_DEV_NAME,
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_BUFFER(vscard_in_data, PassthruState),
+        VMSTATE_UINT32(vscard_in_pos, PassthruState),
+        VMSTATE_UINT32(vscard_in_hdr, PassthruState),
+        VMSTATE_BUFFER(atr, PassthruState),
+        VMSTATE_UINT8(atr_length, PassthruState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static Property passthru_card_properties[] = {
+    DEFINE_PROP_CHR("chardev", PassthruState, cs),
+    DEFINE_PROP_UINT8("debug", PassthruState, debug, 0),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void passthru_class_initfn(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    CCIDCardClass *cc = CCID_CARD_CLASS(klass);
+
+    cc->initfn = passthru_initfn;
+    cc->exitfn = passthru_exitfn;
+    cc->get_atr = passthru_get_atr;
+    cc->apdu_from_guest = passthru_apdu_from_guest;
+    dc->desc = "passthrough smartcard";
+    dc->vmsd = &passthru_vmstate;
+    dc->props = passthru_card_properties;
+}
+
+static const 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_types(void)
+{
+    type_register_static(&passthru_card_info);
+}
+
+type_init(ccid_card_passthru_register_types)
diff --git a/hw/usb/ccid.h b/hw/usb/ccid.h
new file mode 100644 (file)
index 0000000..9334da8
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * CCID Passthru Card Device emulation
+ *
+ * Copyright (c) 2011 Red Hat.
+ * Written by Alon Levy.
+ *
+ * This code is licensed under the GNU LGPL, version 2 or later.
+ */
+
+#ifndef CCID_H
+#define CCID_H
+
+#include "hw/qdev.h"
+
+typedef struct CCIDCardState CCIDCardState;
+typedef struct CCIDCardInfo CCIDCardInfo;
+
+#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)
+ */
+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. */
+};
+
+/*
+ * API for smartcard calling the CCID device (used by hw/ccid-card-*.c)
+ */
+void ccid_card_send_apdu_to_guest(CCIDCardState *card,
+                                  uint8_t *apdu,
+                                  uint32_t len);
+void ccid_card_card_removed(CCIDCardState *card);
+void ccid_card_card_inserted(CCIDCardState *card);
+void ccid_card_card_error(CCIDCardState *card, uint64_t error);
+
+/*
+ * support guest visible insertion/removal of ccid devices based on actual
+ * devices connected/removed. Called by card implementation (passthru, local)
+ */
+int ccid_card_ccid_attach(CCIDCardState *card);
+void ccid_card_ccid_detach(CCIDCardState *card);
+
+#endif /* CCID_H */
index b8c79b85e930bf894c9717c4bb55b17cb0f86963..44fc43f4c41067837dab9ec70e8297fcd4766ec3 100644 (file)
@@ -33,7 +33,7 @@
 #include "hw/usb.h"
 #include "hw/usb/desc.h"
 #include "hw/hw.h"
-#include "hw/audiodev.h"
+#include "hw/audio/audio.h"
 #include "audio/audio.h"
 
 #define USBAUDIO_VENDOR_NUM     0x46f4 /* CRC16() of "QEMU" */
index 97010488872cacd0aa529a17da07b1ca004e14de..b48899d5007559abcbc1bfe96a2fd13bec5ea30a 100644 (file)
@@ -27,7 +27,7 @@
 #include "hw/usb.h"
 #include "hw/usb/desc.h"
 #include "qemu/timer.h"
-#include "hw/hid.h"
+#include "hw/input/hid.h"
 
 /* HID interface requests */
 #define GET_REPORT   0xa101
@@ -236,7 +236,7 @@ static const USBDescDevice desc_device_tablet2 = {
             .bNumInterfaces        = 1,
             .bConfigurationValue   = 1,
             .iConfiguration        = STR_CONFIG_TABLET,
-            .bmAttributes          = 0xa0,
+            .bmAttributes          = 0x80,
             .bMaxPower             = 50,
             .nif = 1,
             .ifs = &desc_iface_tablet2,
index 504c98c35008f0f0490967fc9343d36300e59322..0b71abd0287e9f8b0e808046b641ccc838cc095a 100644 (file)
@@ -25,6 +25,7 @@
 #include "trace.h"
 #include "hw/usb.h"
 #include "hw/usb/desc.h"
+#include "qemu/error-report.h"
 
 #define NUM_PORTS 8
 
@@ -32,6 +33,7 @@ typedef struct USBHubPort {
     USBPort port;
     uint16_t wPortStatus;
     uint16_t wPortChange;
+    uint16_t wPortChange_reported;
 } USBHubPort;
 
 typedef struct USBHubState {
@@ -466,8 +468,11 @@ static void usb_hub_handle_data(USBDevice *dev, USBPacket *p)
             status = 0;
             for(i = 0; i < NUM_PORTS; i++) {
                 port = &s->ports[i];
-                if (port->wPortChange)
+                if (port->wPortChange &&
+                    port->wPortChange_reported != port->wPortChange) {
                     status |= (1 << (i + 1));
+                }
+                port->wPortChange_reported = port->wPortChange;
             }
             if (status != 0) {
                 for(i = 0; i < n; i++) {
@@ -514,6 +519,11 @@ static int usb_hub_initfn(USBDevice *dev)
     USBHubPort *port;
     int i;
 
+    if (dev->port->hubcount == 5) {
+        error_report("usb hub chain too deep");
+        return -1;
+    }
+
     usb_desc_create_serial(dev);
     usb_desc_init(dev);
     s->intr = usb_ep_get(dev, USB_TOKEN_IN, 1);
index caebc1c3fffa8e27476184bb41b564a960a141cb..db8ce021514900acf9439929ac3aa42c6f822c07 100644 (file)
@@ -40,7 +40,7 @@
 #include "hw/usb/desc.h"
 #include "monitor/monitor.h"
 
-#include "hw/ccid.h"
+#include "ccid.h"
 
 #define DPRINTF(s, lvl, fmt, ...) \
 do { \
index d3f01aa2a75d531570865c5d5f2db8f73cdbc6dc..06f0171c46c8ddc8bb9722508bd3c20d6b81d11f 100644 (file)
@@ -12,7 +12,7 @@
 #include "qemu/config-file.h"
 #include "hw/usb.h"
 #include "hw/usb/desc.h"
-#include "hw/scsi.h"
+#include "hw/scsi/scsi.h"
 #include "ui/console.h"
 #include "monitor/monitor.h"
 #include "sysemu/sysemu.h"
@@ -625,7 +625,7 @@ static int usb_msd_initfn_storage(USBDevice *dev)
     usb_desc_init(dev);
     scsi_bus_new(&s->bus, &s->dev.qdev, &usb_msd_scsi_info_storage);
     scsi_dev = scsi_bus_legacy_add_drive(&s->bus, bs, 0, !!s->removable,
-                                            s->conf.bootindex);
+                                            s->conf.bootindex, s->serial);
     if (!scsi_dev) {
         return -1;
     }
index 1ac5117ba77f8e3efef39a50b667d50fef349886..c8c42eefb5b85e5e0c32ddf2ea86cb860f0023b5 100644 (file)
@@ -16,8 +16,8 @@
 
 #include "hw/usb.h"
 #include "hw/usb/desc.h"
-#include "hw/scsi.h"
-#include "hw/scsi-defs.h"
+#include "hw/scsi/scsi.h"
+#include "block/scsi.h"
 
 /* --------------------------------------------------------------------- */
 
index 5aa342bda5a99ff4660198e41d354790b5d0607f..efd4b0dbdea0d4a5f0938aa50faec4faba07b78c 100644 (file)
@@ -452,7 +452,6 @@ struct XHCIState {
     MemoryRegion mem_oper;
     MemoryRegion mem_runtime;
     MemoryRegion mem_doorbell;
-    const char *name;
     unsigned int devaddr;
 
     /* properties */
@@ -1172,8 +1171,6 @@ static void xhci_set_ep_state(XHCIState *xhci, XHCIEPContext *epctx,
     uint32_t ctx[5];
     uint32_t ctx2[2];
 
-    fprintf(stderr, "%s: epid %d, state %d\n",
-            __func__, epctx->epid, state);
     xhci_dma_read_u32s(xhci, epctx->pctx, ctx, sizeof(ctx));
     ctx[0] &= ~EP_STATE_MASK;
     ctx[0] |= state;
@@ -2568,7 +2565,7 @@ static void xhci_process_commands(XHCIState *xhci)
         }
         break;
         default:
-            fprintf(stderr, "xhci: unimplemented command %d\n", type);
+            trace_usb_xhci_unimplemented("command", type);
             event.ccode = CC_TRB_ERROR;
             break;
         }
@@ -2767,7 +2764,7 @@ static uint64_t xhci_cap_read(void *ptr, hwaddr reg, unsigned size)
         ret = 0x00000000; /* reserved */
         break;
     default:
-        fprintf(stderr, "xhci_cap_read: reg %d unimplemented\n", (int)reg);
+        trace_usb_xhci_unimplemented("cap read", reg);
         ret = 0;
     }
 
@@ -2790,8 +2787,7 @@ static uint64_t xhci_port_read(void *ptr, hwaddr reg, unsigned size)
         break;
     case 0x0c: /* reserved */
     default:
-        fprintf(stderr, "xhci_port_read (port %d): reg 0x%x unimplemented\n",
-                port->portnr, (uint32_t)reg);
+        trace_usb_xhci_unimplemented("port read", reg);
         ret = 0;
     }
 
@@ -2831,8 +2827,7 @@ static void xhci_port_write(void *ptr, hwaddr reg,
     case 0x04: /* PORTPMSC */
     case 0x08: /* PORTLI */
     default:
-        fprintf(stderr, "xhci_port_write (port %d): reg 0x%x unimplemented\n",
-                port->portnr, (uint32_t)reg);
+        trace_usb_xhci_unimplemented("port write", reg);
     }
 }
 
@@ -2870,7 +2865,7 @@ static uint64_t xhci_oper_read(void *ptr, hwaddr reg, unsigned size)
         ret = xhci->config;
         break;
     default:
-        fprintf(stderr, "xhci_oper_read: reg 0x%x unimplemented\n", (int)reg);
+        trace_usb_xhci_unimplemented("oper read", reg);
         ret = 0;
     }
 
@@ -2935,7 +2930,7 @@ static void xhci_oper_write(void *ptr, hwaddr reg,
         xhci->config = val & 0xff;
         break;
     default:
-        fprintf(stderr, "xhci_oper_write: reg 0x%x unimplemented\n", (int)reg);
+        trace_usb_xhci_unimplemented("oper write", reg);
     }
 }
 
@@ -2951,8 +2946,7 @@ static uint64_t xhci_runtime_read(void *ptr, hwaddr reg,
             ret = xhci_mfindex_get(xhci) & 0x3fff;
             break;
         default:
-            fprintf(stderr, "xhci_runtime_read: reg 0x%x unimplemented\n",
-                    (int)reg);
+            trace_usb_xhci_unimplemented("runtime read", reg);
             break;
         }
     } else {
@@ -2996,7 +2990,7 @@ static void xhci_runtime_write(void *ptr, hwaddr reg,
     trace_usb_xhci_runtime_write(reg, val);
 
     if (reg < 0x20) {
-        fprintf(stderr, "%s: reg 0x%x unimplemented\n", __func__, (int)reg);
+        trace_usb_xhci_unimplemented("runtime write", reg);
         return;
     }
 
@@ -3038,8 +3032,7 @@ static void xhci_runtime_write(void *ptr, hwaddr reg,
         xhci_events_update(xhci, v);
         break;
     default:
-        fprintf(stderr, "xhci_oper_write: reg 0x%x unimplemented\n",
-                (int)reg);
+        trace_usb_xhci_unimplemented("oper write", reg);
     }
 }
 
@@ -3290,6 +3283,9 @@ static int usb_xhci_initfn(struct PCIDevice *dev)
     if (xhci->numintrs > MAXINTRS) {
         xhci->numintrs = MAXINTRS;
     }
+    while (xhci->numintrs & (xhci->numintrs - 1)) {   /* ! power of 2 */
+        xhci->numintrs++;
+    }
     if (xhci->numintrs < 1) {
         xhci->numintrs = 1;
     }
index d02a7b94c415143812a8d347f4e2a6b195ef1e10..0ddb0818d8ed6434f75161bf322bfd798e8f782f 100644 (file)
@@ -104,6 +104,8 @@ struct USBRedirDevice {
     /* Data passed from chardev the fd_read cb to the usbredirparser read cb */
     const uint8_t *read_buf;
     int read_buf_size;
+    /* Active chardev-watch-tag */
+    guint watch;
     /* For async handling of close */
     QEMUBH *chardev_close_bh;
     /* To delay the usb attach in case of quick chardev close + open */
@@ -254,9 +256,21 @@ static int usbredir_read(void *priv, uint8_t *data, int count)
     return count;
 }
 
+static gboolean usbredir_write_unblocked(GIOChannel *chan, GIOCondition cond,
+                                         void *opaque)
+{
+    USBRedirDevice *dev = opaque;
+
+    dev->watch = 0;
+    usbredirparser_do_write(dev->parser);
+
+    return FALSE;
+}
+
 static int usbredir_write(void *priv, uint8_t *data, int count)
 {
     USBRedirDevice *dev = priv;
+    int r;
 
     if (!dev->cs->be_open) {
         return 0;
@@ -267,7 +281,17 @@ static int usbredir_write(void *priv, uint8_t *data, int count)
         return 0;
     }
 
-    return qemu_chr_fe_write(dev->cs, data, count);
+    r = qemu_chr_fe_write(dev->cs, data, count);
+    if (r < count) {
+        if (!dev->watch) {
+            dev->watch = qemu_chr_fe_add_watch(dev->cs, G_IO_OUT,
+                                               usbredir_write_unblocked, dev);
+        }
+        if (r < 0) {
+            r = 0;
+        }
+    }
+    return r;
 }
 
 /*
@@ -1085,6 +1109,10 @@ static void usbredir_chardev_close_bh(void *opaque)
         usbredirparser_destroy(dev->parser);
         dev->parser = NULL;
     }
+    if (dev->watch) {
+        g_source_remove(dev->watch);
+        dev->watch = 0;
+    }
 }
 
 static void usbredir_create_parser(USBRedirDevice *dev)
@@ -1317,6 +1345,9 @@ static void usbredir_handle_destroy(USBDevice *udev)
     if (dev->parser) {
         usbredirparser_destroy(dev->parser);
     }
+    if (dev->watch) {
+        g_source_remove(dev->watch);
+    }
 
     free(dev->filter_rules);
 }
@@ -1973,6 +2004,10 @@ static int usbredir_post_load(void *priv, int version_id)
 {
     USBRedirDevice *dev = priv;
 
+    if (dev->parser == NULL) {
+        return 0;
+    }
+
     switch (dev->device_info.speed) {
     case usb_redir_speed_low:
         dev->dev.speed = USB_SPEED_LOW;
diff --git a/hw/versatile_i2c.c b/hw/versatile_i2c.c
deleted file mode 100644 (file)
index d0444ae..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * ARM Versatile I2C controller
- *
- * Copyright (c) 2006-2007 CodeSourcery.
- * Copyright (c) 2012 Oskar Andero <oskar.andero@gmail.com>
- *
- * This file is derived from hw/realview.c by Paul Brook
- *
- * 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 "hw/sysbus.h"
-#include "hw/bitbang_i2c.h"
-
-typedef struct {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-    bitbang_i2c_interface *bitbang;
-    int out;
-    int in;
-} VersatileI2CState;
-
-static uint64_t versatile_i2c_read(void *opaque, hwaddr offset,
-                                   unsigned size)
-{
-    VersatileI2CState *s = (VersatileI2CState *)opaque;
-
-    if (offset == 0) {
-        return (s->out & 1) | (s->in << 1);
-    } else {
-        qemu_log_mask(LOG_GUEST_ERROR,
-                      "%s: Bad offset 0x%x\n", __func__, (int)offset);
-        return -1;
-    }
-}
-
-static void versatile_i2c_write(void *opaque, hwaddr offset,
-                                uint64_t value, unsigned size)
-{
-    VersatileI2CState *s = (VersatileI2CState *)opaque;
-
-    switch (offset) {
-    case 0:
-        s->out |= value & 3;
-        break;
-    case 4:
-        s->out &= ~value;
-        break;
-    default:
-        qemu_log_mask(LOG_GUEST_ERROR,
-                      "%s: Bad offset 0x%x\n", __func__, (int)offset);
-    }
-    bitbang_i2c_set(s->bitbang, BITBANG_I2C_SCL, (s->out & 1) != 0);
-    s->in = bitbang_i2c_set(s->bitbang, BITBANG_I2C_SDA, (s->out & 2) != 0);
-}
-
-static const MemoryRegionOps versatile_i2c_ops = {
-    .read = versatile_i2c_read,
-    .write = versatile_i2c_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int versatile_i2c_init(SysBusDevice *dev)
-{
-    VersatileI2CState *s = FROM_SYSBUS(VersatileI2CState, dev);
-    i2c_bus *bus;
-
-    bus = i2c_init_bus(&dev->qdev, "i2c");
-    s->bitbang = bitbang_i2c_init(bus);
-    memory_region_init_io(&s->iomem, &versatile_i2c_ops, s,
-                          "versatile_i2c", 0x1000);
-    sysbus_init_mmio(dev, &s->iomem);
-    return 0;
-}
-
-static void versatile_i2c_class_init(ObjectClass *klass, void *data)
-{
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = versatile_i2c_init;
-}
-
-static const TypeInfo versatile_i2c_info = {
-    .name          = "versatile_i2c",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(VersatileI2CState),
-    .class_init    = versatile_i2c_class_init,
-};
-
-static void versatile_i2c_register_types(void)
-{
-    type_register_static(&versatile_i2c_info);
-}
-
-type_init(versatile_i2c_register_types)
diff --git a/hw/versatile_pci.c b/hw/versatile_pci.c
deleted file mode 100644 (file)
index d67ca79..0000000
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * ARM Versatile/PB PCI host controller
- *
- * Copyright (c) 2006-2009 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the LGPL.
- */
-
-#include "hw/sysbus.h"
-#include "hw/pci/pci.h"
-#include "hw/pci/pci_host.h"
-#include "exec/address-spaces.h"
-
-typedef struct {
-    SysBusDevice busdev;
-    qemu_irq irq[4];
-    int realview;
-    MemoryRegion mem_config;
-    MemoryRegion mem_config2;
-    MemoryRegion isa;
-} PCIVPBState;
-
-static inline uint32_t vpb_pci_config_addr(hwaddr addr)
-{
-    return addr & 0xffffff;
-}
-
-static void pci_vpb_config_write(void *opaque, hwaddr addr,
-                                 uint64_t val, unsigned size)
-{
-    pci_data_write(opaque, vpb_pci_config_addr(addr), val, size);
-}
-
-static uint64_t pci_vpb_config_read(void *opaque, hwaddr addr,
-                                    unsigned size)
-{
-    uint32_t val;
-    val = pci_data_read(opaque, vpb_pci_config_addr(addr), size);
-    return val;
-}
-
-static const MemoryRegionOps pci_vpb_config_ops = {
-    .read = pci_vpb_config_read,
-    .write = pci_vpb_config_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int pci_vpb_map_irq(PCIDevice *d, int irq_num)
-{
-    return irq_num;
-}
-
-static void pci_vpb_set_irq(void *opaque, int irq_num, int level)
-{
-    qemu_irq *pic = opaque;
-
-    qemu_set_irq(pic[irq_num], level);
-}
-
-static int pci_vpb_init(SysBusDevice *dev)
-{
-    PCIVPBState *s = FROM_SYSBUS(PCIVPBState, dev);
-    PCIBus *bus;
-    int i;
-
-    for (i = 0; i < 4; i++) {
-        sysbus_init_irq(dev, &s->irq[i]);
-    }
-    bus = pci_register_bus(&dev->qdev, "pci",
-                           pci_vpb_set_irq, pci_vpb_map_irq, s->irq,
-                           get_system_memory(), get_system_io(),
-                           PCI_DEVFN(11, 0), 4, TYPE_PCI_BUS);
-
-    /* ??? Register memory space.  */
-
-    /* Our memory regions are:
-     * 0 : PCI self config window
-     * 1 : PCI config window
-     * 2 : PCI IO window (realview_pci only)
-     */
-    memory_region_init_io(&s->mem_config, &pci_vpb_config_ops, bus,
-                          "pci-vpb-selfconfig", 0x1000000);
-    sysbus_init_mmio(dev, &s->mem_config);
-    memory_region_init_io(&s->mem_config2, &pci_vpb_config_ops, bus,
-                          "pci-vpb-config", 0x1000000);
-    sysbus_init_mmio(dev, &s->mem_config2);
-    if (s->realview) {
-        isa_mmio_setup(&s->isa, 0x0100000);
-        sysbus_init_mmio(dev, &s->isa);
-    }
-
-    pci_create_simple(bus, -1, "versatile_pci_host");
-    return 0;
-}
-
-static int pci_realview_init(SysBusDevice *dev)
-{
-    PCIVPBState *s = FROM_SYSBUS(PCIVPBState, dev);
-    s->realview = 1;
-    return pci_vpb_init(dev);
-}
-
-static int versatile_pci_host_init(PCIDevice *d)
-{
-    pci_set_word(d->config + PCI_STATUS,
-                PCI_STATUS_66MHZ | PCI_STATUS_DEVSEL_MEDIUM);
-    pci_set_byte(d->config + PCI_LATENCY_TIMER, 0x10);
-    return 0;
-}
-
-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 const TypeInfo versatile_pci_host_info = {
-    .name          = "versatile_pci_host",
-    .parent        = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(PCIDevice),
-    .class_init    = versatile_pci_host_class_init,
-};
-
-static void pci_vpb_class_init(ObjectClass *klass, void *data)
-{
-    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
-
-    sdc->init = pci_vpb_init;
-}
-
-static const TypeInfo pci_vpb_info = {
-    .name          = "versatile_pci",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(PCIVPBState),
-    .class_init    = pci_vpb_class_init,
-};
-
-static void pci_realview_class_init(ObjectClass *klass, void *data)
-{
-    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
-
-    sdc->init = pci_realview_init;
-}
-
-static const 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_types(void)
-{
-    type_register_static(&pci_vpb_info);
-    type_register_static(&pci_realview_info);
-    type_register_static(&versatile_pci_host_info);
-}
-
-type_init(versatile_pci_register_types)
diff --git a/hw/vfio_pci.c b/hw/vfio_pci.c
deleted file mode 100644 (file)
index 693a9ff..0000000
+++ /dev/null
@@ -1,3206 +0,0 @@
-/*
- * vfio based device assignment support
- *
- * Copyright Red Hat, Inc. 2012
- *
- * Authors:
- *  Alex Williamson <alex.williamson@redhat.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2.  See
- * the COPYING file in the top-level directory.
- *
- * Based on qemu-kvm device-assignment:
- *  Adapted for KVM by Qumranet.
- *  Copyright (c) 2007, Neocleus, Alex Novik (alex@neocleus.com)
- *  Copyright (c) 2007, Neocleus, Guy Zana (guy@neocleus.com)
- *  Copyright (C) 2008, Qumranet, Amit Shah (amit.shah@qumranet.com)
- *  Copyright (C) 2008, Red Hat, Amit Shah (amit.shah@redhat.com)
- *  Copyright (C) 2008, IBM, Muli Ben-Yehuda (muli@il.ibm.com)
- */
-
-#include <dirent.h>
-#include <linux/vfio.h>
-#include <sys/ioctl.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include "config.h"
-#include "exec/address-spaces.h"
-#include "exec/memory.h"
-#include "hw/pci/msi.h"
-#include "hw/pci/msix.h"
-#include "hw/pci/pci.h"
-#include "qemu-common.h"
-#include "qemu/error-report.h"
-#include "qemu/event_notifier.h"
-#include "qemu/queue.h"
-#include "qemu/range.h"
-#include "sysemu/kvm.h"
-#include "sysemu/sysemu.h"
-
-/* #define DEBUG_VFIO */
-#ifdef DEBUG_VFIO
-#define DPRINTF(fmt, ...) \
-    do { fprintf(stderr, "vfio: " fmt, ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...) \
-    do { } while (0)
-#endif
-
-/* Extra debugging, trap acceleration paths for more logging */
-#define VFIO_ALLOW_MMAP 1
-#define VFIO_ALLOW_KVM_INTX 1
-
-struct VFIODevice;
-
-typedef struct VFIOQuirk {
-    MemoryRegion mem;
-    struct VFIODevice *vdev;
-    QLIST_ENTRY(VFIOQuirk) next;
-    uint32_t data;
-    uint32_t data2;
-} VFIOQuirk;
-
-typedef struct VFIOBAR {
-    off_t fd_offset; /* offset of BAR within device fd */
-    int fd; /* device fd, allows us to pass VFIOBAR as opaque data */
-    MemoryRegion mem; /* slow, read/write access */
-    MemoryRegion mmap_mem; /* direct mapped access */
-    void *mmap;
-    size_t size;
-    uint32_t flags; /* VFIO region flags (rd/wr/mmap) */
-    uint8_t nr; /* cache the BAR number for debug */
-    QLIST_HEAD(, VFIOQuirk) quirks;
-} VFIOBAR;
-
-typedef struct VFIOVGARegion {
-    MemoryRegion mem;
-    off_t offset;
-    int nr;
-    QLIST_HEAD(, VFIOQuirk) quirks;
-} VFIOVGARegion;
-
-typedef struct VFIOVGA {
-    off_t fd_offset;
-    int fd;
-    VFIOVGARegion region[QEMU_PCI_VGA_NUM_REGIONS];
-} VFIOVGA;
-
-typedef struct VFIOINTx {
-    bool pending; /* interrupt pending */
-    bool kvm_accel; /* set when QEMU bypass through KVM enabled */
-    uint8_t pin; /* which pin to pull for qemu_set_irq */
-    EventNotifier interrupt; /* eventfd triggered on interrupt */
-    EventNotifier unmask; /* eventfd for unmask on QEMU bypass */
-    PCIINTxRoute route; /* routing info for QEMU bypass */
-    uint32_t mmap_timeout; /* delay to re-enable mmaps after interrupt */
-    QEMUTimer *mmap_timer; /* enable mmaps after periods w/o interrupts */
-} VFIOINTx;
-
-typedef struct VFIOMSIVector {
-    EventNotifier interrupt; /* eventfd triggered on interrupt */
-    struct VFIODevice *vdev; /* back pointer to device */
-    int virq; /* KVM irqchip route for QEMU bypass */
-    bool use;
-} VFIOMSIVector;
-
-enum {
-    VFIO_INT_NONE = 0,
-    VFIO_INT_INTx = 1,
-    VFIO_INT_MSI  = 2,
-    VFIO_INT_MSIX = 3,
-};
-
-struct VFIOGroup;
-
-typedef struct VFIOContainer {
-    int fd; /* /dev/vfio/vfio, empowered by the attached groups */
-    struct {
-        /* enable abstraction to support various iommu backends */
-        union {
-            MemoryListener listener; /* Used by type1 iommu */
-        };
-        void (*release)(struct VFIOContainer *);
-    } iommu_data;
-    QLIST_HEAD(, VFIOGroup) group_list;
-    QLIST_ENTRY(VFIOContainer) next;
-} VFIOContainer;
-
-/* Cache of MSI-X setup plus extra mmap and memory region for split BAR map */
-typedef struct VFIOMSIXInfo {
-    uint8_t table_bar;
-    uint8_t pba_bar;
-    uint16_t entries;
-    uint32_t table_offset;
-    uint32_t pba_offset;
-    MemoryRegion mmap_mem;
-    void *mmap;
-} VFIOMSIXInfo;
-
-typedef struct VFIODevice {
-    PCIDevice pdev;
-    int fd;
-    VFIOINTx intx;
-    unsigned int config_size;
-    uint8_t *emulated_config_bits; /* QEMU emulated bits, little-endian */
-    off_t config_offset; /* Offset of config space region within device fd */
-    unsigned int rom_size;
-    off_t rom_offset; /* Offset of ROM region within device fd */
-    int msi_cap_size;
-    VFIOMSIVector *msi_vectors;
-    VFIOMSIXInfo *msix;
-    int nr_vectors; /* Number of MSI/MSIX vectors currently in use */
-    int interrupt; /* Current interrupt type */
-    VFIOBAR bars[PCI_NUM_REGIONS - 1]; /* No ROM */
-    VFIOVGA vga; /* 0xa0000, 0x3b0, 0x3c0 */
-    PCIHostDeviceAddress host;
-    QLIST_ENTRY(VFIODevice) next;
-    struct VFIOGroup *group;
-    uint32_t features;
-#define VFIO_FEATURE_ENABLE_VGA_BIT 0
-#define VFIO_FEATURE_ENABLE_VGA (1 << VFIO_FEATURE_ENABLE_VGA_BIT)
-    int32_t bootindex;
-    uint8_t pm_cap;
-    bool reset_works;
-    bool has_vga;
-} VFIODevice;
-
-typedef struct VFIOGroup {
-    int fd;
-    int groupid;
-    VFIOContainer *container;
-    QLIST_HEAD(, VFIODevice) device_list;
-    QLIST_ENTRY(VFIOGroup) next;
-    QLIST_ENTRY(VFIOGroup) container_next;
-} VFIOGroup;
-
-#define MSIX_CAP_LENGTH 12
-
-static QLIST_HEAD(, VFIOContainer)
-    container_list = QLIST_HEAD_INITIALIZER(container_list);
-
-static QLIST_HEAD(, VFIOGroup)
-    group_list = QLIST_HEAD_INITIALIZER(group_list);
-
-static void vfio_disable_interrupts(VFIODevice *vdev);
-static uint32_t vfio_pci_read_config(PCIDevice *pdev, uint32_t addr, int len);
-static void vfio_pci_write_config(PCIDevice *pdev, uint32_t addr,
-                                  uint32_t val, int len);
-static void vfio_mmap_set_enabled(VFIODevice *vdev, bool enabled);
-
-/*
- * Common VFIO interrupt disable
- */
-static void vfio_disable_irqindex(VFIODevice *vdev, int index)
-{
-    struct vfio_irq_set irq_set = {
-        .argsz = sizeof(irq_set),
-        .flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_TRIGGER,
-        .index = index,
-        .start = 0,
-        .count = 0,
-    };
-
-    ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, &irq_set);
-}
-
-/*
- * INTx
- */
-static void vfio_unmask_intx(VFIODevice *vdev)
-{
-    struct vfio_irq_set irq_set = {
-        .argsz = sizeof(irq_set),
-        .flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_UNMASK,
-        .index = VFIO_PCI_INTX_IRQ_INDEX,
-        .start = 0,
-        .count = 1,
-    };
-
-    ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, &irq_set);
-}
-
-#ifdef CONFIG_KVM /* Unused outside of CONFIG_KVM code */
-static void vfio_mask_intx(VFIODevice *vdev)
-{
-    struct vfio_irq_set irq_set = {
-        .argsz = sizeof(irq_set),
-        .flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_MASK,
-        .index = VFIO_PCI_INTX_IRQ_INDEX,
-        .start = 0,
-        .count = 1,
-    };
-
-    ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, &irq_set);
-}
-#endif
-
-/*
- * Disabling BAR mmaping can be slow, but toggling it around INTx can
- * also be a huge overhead.  We try to get the best of both worlds by
- * waiting until an interrupt to disable mmaps (subsequent transitions
- * to the same state are effectively no overhead).  If the interrupt has
- * been serviced and the time gap is long enough, we re-enable mmaps for
- * performance.  This works well for things like graphics cards, which
- * may not use their interrupt at all and are penalized to an unusable
- * level by read/write BAR traps.  Other devices, like NICs, have more
- * regular interrupts and see much better latency by staying in non-mmap
- * mode.  We therefore set the default mmap_timeout such that a ping
- * is just enough to keep the mmap disabled.  Users can experiment with
- * other options with the x-intx-mmap-timeout-ms parameter (a value of
- * zero disables the timer).
- */
-static void vfio_intx_mmap_enable(void *opaque)
-{
-    VFIODevice *vdev = opaque;
-
-    if (vdev->intx.pending) {
-        qemu_mod_timer(vdev->intx.mmap_timer,
-                       qemu_get_clock_ms(vm_clock) + vdev->intx.mmap_timeout);
-        return;
-    }
-
-    vfio_mmap_set_enabled(vdev, true);
-}
-
-static void vfio_intx_interrupt(void *opaque)
-{
-    VFIODevice *vdev = opaque;
-
-    if (!event_notifier_test_and_clear(&vdev->intx.interrupt)) {
-        return;
-    }
-
-    DPRINTF("%s(%04x:%02x:%02x.%x) Pin %c\n", __func__, vdev->host.domain,
-            vdev->host.bus, vdev->host.slot, vdev->host.function,
-            'A' + vdev->intx.pin);
-
-    vdev->intx.pending = true;
-    qemu_set_irq(vdev->pdev.irq[vdev->intx.pin], 1);
-    vfio_mmap_set_enabled(vdev, false);
-    if (vdev->intx.mmap_timeout) {
-        qemu_mod_timer(vdev->intx.mmap_timer,
-                       qemu_get_clock_ms(vm_clock) + vdev->intx.mmap_timeout);
-    }
-}
-
-static void vfio_eoi(VFIODevice *vdev)
-{
-    if (!vdev->intx.pending) {
-        return;
-    }
-
-    DPRINTF("%s(%04x:%02x:%02x.%x) EOI\n", __func__, vdev->host.domain,
-            vdev->host.bus, vdev->host.slot, vdev->host.function);
-
-    vdev->intx.pending = false;
-    qemu_set_irq(vdev->pdev.irq[vdev->intx.pin], 0);
-    vfio_unmask_intx(vdev);
-}
-
-static void vfio_enable_intx_kvm(VFIODevice *vdev)
-{
-#ifdef CONFIG_KVM
-    struct kvm_irqfd irqfd = {
-        .fd = event_notifier_get_fd(&vdev->intx.interrupt),
-        .gsi = vdev->intx.route.irq,
-        .flags = KVM_IRQFD_FLAG_RESAMPLE,
-    };
-    struct vfio_irq_set *irq_set;
-    int ret, argsz;
-    int32_t *pfd;
-
-    if (!VFIO_ALLOW_KVM_INTX || !kvm_irqfds_enabled() ||
-        vdev->intx.route.mode != PCI_INTX_ENABLED ||
-        !kvm_check_extension(kvm_state, KVM_CAP_IRQFD_RESAMPLE)) {
-        return;
-    }
-
-    /* Get to a known interrupt state */
-    qemu_set_fd_handler(irqfd.fd, NULL, NULL, vdev);
-    vfio_mask_intx(vdev);
-    vdev->intx.pending = false;
-    qemu_set_irq(vdev->pdev.irq[vdev->intx.pin], 0);
-
-    /* Get an eventfd for resample/unmask */
-    if (event_notifier_init(&vdev->intx.unmask, 0)) {
-        error_report("vfio: Error: event_notifier_init failed eoi");
-        goto fail;
-    }
-
-    /* KVM triggers it, VFIO listens for it */
-    irqfd.resamplefd = event_notifier_get_fd(&vdev->intx.unmask);
-
-    if (kvm_vm_ioctl(kvm_state, KVM_IRQFD, &irqfd)) {
-        error_report("vfio: Error: Failed to setup resample irqfd: %m");
-        goto fail_irqfd;
-    }
-
-    argsz = sizeof(*irq_set) + sizeof(*pfd);
-
-    irq_set = g_malloc0(argsz);
-    irq_set->argsz = argsz;
-    irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_UNMASK;
-    irq_set->index = VFIO_PCI_INTX_IRQ_INDEX;
-    irq_set->start = 0;
-    irq_set->count = 1;
-    pfd = (int32_t *)&irq_set->data;
-
-    *pfd = irqfd.resamplefd;
-
-    ret = ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, irq_set);
-    g_free(irq_set);
-    if (ret) {
-        error_report("vfio: Error: Failed to setup INTx unmask fd: %m");
-        goto fail_vfio;
-    }
-
-    /* Let'em rip */
-    vfio_unmask_intx(vdev);
-
-    vdev->intx.kvm_accel = true;
-
-    DPRINTF("%s(%04x:%02x:%02x.%x) KVM INTx accel enabled\n",
-            __func__, vdev->host.domain, vdev->host.bus,
-            vdev->host.slot, vdev->host.function);
-
-    return;
-
-fail_vfio:
-    irqfd.flags = KVM_IRQFD_FLAG_DEASSIGN;
-    kvm_vm_ioctl(kvm_state, KVM_IRQFD, &irqfd);
-fail_irqfd:
-    event_notifier_cleanup(&vdev->intx.unmask);
-fail:
-    qemu_set_fd_handler(irqfd.fd, vfio_intx_interrupt, NULL, vdev);
-    vfio_unmask_intx(vdev);
-#endif
-}
-
-static void vfio_disable_intx_kvm(VFIODevice *vdev)
-{
-#ifdef CONFIG_KVM
-    struct kvm_irqfd irqfd = {
-        .fd = event_notifier_get_fd(&vdev->intx.interrupt),
-        .gsi = vdev->intx.route.irq,
-        .flags = KVM_IRQFD_FLAG_DEASSIGN,
-    };
-
-    if (!vdev->intx.kvm_accel) {
-        return;
-    }
-
-    /*
-     * Get to a known state, hardware masked, QEMU ready to accept new
-     * interrupts, QEMU IRQ de-asserted.
-     */
-    vfio_mask_intx(vdev);
-    vdev->intx.pending = false;
-    qemu_set_irq(vdev->pdev.irq[vdev->intx.pin], 0);
-
-    /* Tell KVM to stop listening for an INTx irqfd */
-    if (kvm_vm_ioctl(kvm_state, KVM_IRQFD, &irqfd)) {
-        error_report("vfio: Error: Failed to disable INTx irqfd: %m");
-    }
-
-    /* We only need to close the eventfd for VFIO to cleanup the kernel side */
-    event_notifier_cleanup(&vdev->intx.unmask);
-
-    /* QEMU starts listening for interrupt events. */
-    qemu_set_fd_handler(irqfd.fd, vfio_intx_interrupt, NULL, vdev);
-
-    vdev->intx.kvm_accel = false;
-
-    /* If we've missed an event, let it re-fire through QEMU */
-    vfio_unmask_intx(vdev);
-
-    DPRINTF("%s(%04x:%02x:%02x.%x) KVM INTx accel disabled\n",
-            __func__, vdev->host.domain, vdev->host.bus,
-            vdev->host.slot, vdev->host.function);
-#endif
-}
-
-static void vfio_update_irq(PCIDevice *pdev)
-{
-    VFIODevice *vdev = DO_UPCAST(VFIODevice, pdev, pdev);
-    PCIINTxRoute route;
-
-    if (vdev->interrupt != VFIO_INT_INTx) {
-        return;
-    }
-
-    route = pci_device_route_intx_to_irq(&vdev->pdev, vdev->intx.pin);
-
-    if (!pci_intx_route_changed(&vdev->intx.route, &route)) {
-        return; /* Nothing changed */
-    }
-
-    DPRINTF("%s(%04x:%02x:%02x.%x) IRQ moved %d -> %d\n", __func__,
-            vdev->host.domain, vdev->host.bus, vdev->host.slot,
-            vdev->host.function, vdev->intx.route.irq, route.irq);
-
-    vfio_disable_intx_kvm(vdev);
-
-    vdev->intx.route = route;
-
-    if (route.mode != PCI_INTX_ENABLED) {
-        return;
-    }
-
-    vfio_enable_intx_kvm(vdev);
-
-    /* Re-enable the interrupt in cased we missed an EOI */
-    vfio_eoi(vdev);
-}
-
-static int vfio_enable_intx(VFIODevice *vdev)
-{
-    uint8_t pin = vfio_pci_read_config(&vdev->pdev, PCI_INTERRUPT_PIN, 1);
-    int ret, argsz;
-    struct vfio_irq_set *irq_set;
-    int32_t *pfd;
-
-    if (!pin) {
-        return 0;
-    }
-
-    vfio_disable_interrupts(vdev);
-
-    vdev->intx.pin = pin - 1; /* Pin A (1) -> irq[0] */
-
-#ifdef CONFIG_KVM
-    /*
-     * Only conditional to avoid generating error messages on platforms
-     * where we won't actually use the result anyway.
-     */
-    if (kvm_irqfds_enabled() &&
-        kvm_check_extension(kvm_state, KVM_CAP_IRQFD_RESAMPLE)) {
-        vdev->intx.route = pci_device_route_intx_to_irq(&vdev->pdev,
-                                                        vdev->intx.pin);
-    }
-#endif
-
-    ret = event_notifier_init(&vdev->intx.interrupt, 0);
-    if (ret) {
-        error_report("vfio: Error: event_notifier_init failed");
-        return ret;
-    }
-
-    argsz = sizeof(*irq_set) + sizeof(*pfd);
-
-    irq_set = g_malloc0(argsz);
-    irq_set->argsz = argsz;
-    irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_TRIGGER;
-    irq_set->index = VFIO_PCI_INTX_IRQ_INDEX;
-    irq_set->start = 0;
-    irq_set->count = 1;
-    pfd = (int32_t *)&irq_set->data;
-
-    *pfd = event_notifier_get_fd(&vdev->intx.interrupt);
-    qemu_set_fd_handler(*pfd, vfio_intx_interrupt, NULL, vdev);
-
-    ret = ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, irq_set);
-    g_free(irq_set);
-    if (ret) {
-        error_report("vfio: Error: Failed to setup INTx fd: %m");
-        qemu_set_fd_handler(*pfd, NULL, NULL, vdev);
-        event_notifier_cleanup(&vdev->intx.interrupt);
-        return -errno;
-    }
-
-    vfio_enable_intx_kvm(vdev);
-
-    vdev->interrupt = VFIO_INT_INTx;
-
-    DPRINTF("%s(%04x:%02x:%02x.%x)\n", __func__, vdev->host.domain,
-            vdev->host.bus, vdev->host.slot, vdev->host.function);
-
-    return 0;
-}
-
-static void vfio_disable_intx(VFIODevice *vdev)
-{
-    int fd;
-
-    qemu_del_timer(vdev->intx.mmap_timer);
-    vfio_disable_intx_kvm(vdev);
-    vfio_disable_irqindex(vdev, VFIO_PCI_INTX_IRQ_INDEX);
-    vdev->intx.pending = false;
-    qemu_set_irq(vdev->pdev.irq[vdev->intx.pin], 0);
-    vfio_mmap_set_enabled(vdev, true);
-
-    fd = event_notifier_get_fd(&vdev->intx.interrupt);
-    qemu_set_fd_handler(fd, NULL, NULL, vdev);
-    event_notifier_cleanup(&vdev->intx.interrupt);
-
-    vdev->interrupt = VFIO_INT_NONE;
-
-    DPRINTF("%s(%04x:%02x:%02x.%x)\n", __func__, vdev->host.domain,
-            vdev->host.bus, vdev->host.slot, vdev->host.function);
-}
-
-/*
- * MSI/X
- */
-static void vfio_msi_interrupt(void *opaque)
-{
-    VFIOMSIVector *vector = opaque;
-    VFIODevice *vdev = vector->vdev;
-    int nr = vector - vdev->msi_vectors;
-
-    if (!event_notifier_test_and_clear(&vector->interrupt)) {
-        return;
-    }
-
-    DPRINTF("%s(%04x:%02x:%02x.%x) vector %d\n", __func__,
-            vdev->host.domain, vdev->host.bus, vdev->host.slot,
-            vdev->host.function, nr);
-
-    if (vdev->interrupt == VFIO_INT_MSIX) {
-        msix_notify(&vdev->pdev, nr);
-    } else if (vdev->interrupt == VFIO_INT_MSI) {
-        msi_notify(&vdev->pdev, nr);
-    } else {
-        error_report("vfio: MSI interrupt receieved, but not enabled?");
-    }
-}
-
-static int vfio_enable_vectors(VFIODevice *vdev, bool msix)
-{
-    struct vfio_irq_set *irq_set;
-    int ret = 0, i, argsz;
-    int32_t *fds;
-
-    argsz = sizeof(*irq_set) + (vdev->nr_vectors * sizeof(*fds));
-
-    irq_set = g_malloc0(argsz);
-    irq_set->argsz = argsz;
-    irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_TRIGGER;
-    irq_set->index = msix ? VFIO_PCI_MSIX_IRQ_INDEX : VFIO_PCI_MSI_IRQ_INDEX;
-    irq_set->start = 0;
-    irq_set->count = vdev->nr_vectors;
-    fds = (int32_t *)&irq_set->data;
-
-    for (i = 0; i < vdev->nr_vectors; i++) {
-        if (!vdev->msi_vectors[i].use) {
-            fds[i] = -1;
-            continue;
-        }
-
-        fds[i] = event_notifier_get_fd(&vdev->msi_vectors[i].interrupt);
-    }
-
-    ret = ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, irq_set);
-
-    g_free(irq_set);
-
-    return ret;
-}
-
-static int vfio_msix_vector_do_use(PCIDevice *pdev, unsigned int nr,
-                                   MSIMessage *msg, IOHandler *handler)
-{
-    VFIODevice *vdev = DO_UPCAST(VFIODevice, pdev, pdev);
-    VFIOMSIVector *vector;
-    int ret;
-
-    DPRINTF("%s(%04x:%02x:%02x.%x) vector %d used\n", __func__,
-            vdev->host.domain, vdev->host.bus, vdev->host.slot,
-            vdev->host.function, nr);
-
-    vector = &vdev->msi_vectors[nr];
-    vector->vdev = vdev;
-    vector->use = true;
-
-    msix_vector_use(pdev, nr);
-
-    if (event_notifier_init(&vector->interrupt, 0)) {
-        error_report("vfio: Error: event_notifier_init failed");
-    }
-
-    /*
-     * Attempt to enable route through KVM irqchip,
-     * default to userspace handling if unavailable.
-     */
-    vector->virq = msg ? kvm_irqchip_add_msi_route(kvm_state, *msg) : -1;
-    if (vector->virq < 0 ||
-        kvm_irqchip_add_irqfd_notifier(kvm_state, &vector->interrupt,
-                                       vector->virq) < 0) {
-        if (vector->virq >= 0) {
-            kvm_irqchip_release_virq(kvm_state, vector->virq);
-            vector->virq = -1;
-        }
-        qemu_set_fd_handler(event_notifier_get_fd(&vector->interrupt),
-                            handler, NULL, vector);
-    }
-
-    /*
-     * We don't want to have the host allocate all possible MSI vectors
-     * for a device if they're not in use, so we shutdown and incrementally
-     * increase them as needed.
-     */
-    if (vdev->nr_vectors < nr + 1) {
-        vfio_disable_irqindex(vdev, VFIO_PCI_MSIX_IRQ_INDEX);
-        vdev->nr_vectors = nr + 1;
-        ret = vfio_enable_vectors(vdev, true);
-        if (ret) {
-            error_report("vfio: failed to enable vectors, %d", ret);
-        }
-    } else {
-        int argsz;
-        struct vfio_irq_set *irq_set;
-        int32_t *pfd;
-
-        argsz = sizeof(*irq_set) + sizeof(*pfd);
-
-        irq_set = g_malloc0(argsz);
-        irq_set->argsz = argsz;
-        irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD |
-                         VFIO_IRQ_SET_ACTION_TRIGGER;
-        irq_set->index = VFIO_PCI_MSIX_IRQ_INDEX;
-        irq_set->start = nr;
-        irq_set->count = 1;
-        pfd = (int32_t *)&irq_set->data;
-
-        *pfd = event_notifier_get_fd(&vector->interrupt);
-
-        ret = ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, irq_set);
-        g_free(irq_set);
-        if (ret) {
-            error_report("vfio: failed to modify vector, %d", ret);
-        }
-    }
-
-    return 0;
-}
-
-static int vfio_msix_vector_use(PCIDevice *pdev,
-                                unsigned int nr, MSIMessage msg)
-{
-    return vfio_msix_vector_do_use(pdev, nr, &msg, vfio_msi_interrupt);
-}
-
-static void vfio_msix_vector_release(PCIDevice *pdev, unsigned int nr)
-{
-    VFIODevice *vdev = DO_UPCAST(VFIODevice, pdev, pdev);
-    VFIOMSIVector *vector = &vdev->msi_vectors[nr];
-    int argsz;
-    struct vfio_irq_set *irq_set;
-    int32_t *pfd;
-
-    DPRINTF("%s(%04x:%02x:%02x.%x) vector %d released\n", __func__,
-            vdev->host.domain, vdev->host.bus, vdev->host.slot,
-            vdev->host.function, nr);
-
-    /*
-     * XXX What's the right thing to do here?  This turns off the interrupt
-     * completely, but do we really just want to switch the interrupt to
-     * bouncing through userspace and let msix.c drop it?  Not sure.
-     */
-    msix_vector_unuse(pdev, nr);
-
-    argsz = sizeof(*irq_set) + sizeof(*pfd);
-
-    irq_set = g_malloc0(argsz);
-    irq_set->argsz = argsz;
-    irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD |
-                     VFIO_IRQ_SET_ACTION_TRIGGER;
-    irq_set->index = VFIO_PCI_MSIX_IRQ_INDEX;
-    irq_set->start = nr;
-    irq_set->count = 1;
-    pfd = (int32_t *)&irq_set->data;
-
-    *pfd = -1;
-
-    ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, irq_set);
-
-    g_free(irq_set);
-
-    if (vector->virq < 0) {
-        qemu_set_fd_handler(event_notifier_get_fd(&vector->interrupt),
-                            NULL, NULL, NULL);
-    } else {
-        kvm_irqchip_remove_irqfd_notifier(kvm_state, &vector->interrupt,
-                                          vector->virq);
-        kvm_irqchip_release_virq(kvm_state, vector->virq);
-        vector->virq = -1;
-    }
-
-    event_notifier_cleanup(&vector->interrupt);
-    vector->use = false;
-}
-
-static void vfio_enable_msix(VFIODevice *vdev)
-{
-    vfio_disable_interrupts(vdev);
-
-    vdev->msi_vectors = g_malloc0(vdev->msix->entries * sizeof(VFIOMSIVector));
-
-    vdev->interrupt = VFIO_INT_MSIX;
-
-    /*
-     * Some communication channels between VF & PF or PF & fw rely on the
-     * physical state of the device and expect that enabling MSI-X from the
-     * guest enables the same on the host.  When our guest is Linux, the
-     * guest driver call to pci_enable_msix() sets the enabling bit in the
-     * MSI-X capability, but leaves the vector table masked.  We therefore
-     * can't rely on a vector_use callback (from request_irq() in the guest)
-     * to switch the physical device into MSI-X mode because that may come a
-     * long time after pci_enable_msix().  This code enables vector 0 with
-     * triggering to userspace, then immediately release the vector, leaving
-     * the physical device with no vectors enabled, but MSI-X enabled, just
-     * like the guest view.
-     */
-    vfio_msix_vector_do_use(&vdev->pdev, 0, NULL, NULL);
-    vfio_msix_vector_release(&vdev->pdev, 0);
-
-    if (msix_set_vector_notifiers(&vdev->pdev, vfio_msix_vector_use,
-                                  vfio_msix_vector_release, NULL)) {
-        error_report("vfio: msix_set_vector_notifiers failed");
-    }
-
-    DPRINTF("%s(%04x:%02x:%02x.%x)\n", __func__, vdev->host.domain,
-            vdev->host.bus, vdev->host.slot, vdev->host.function);
-}
-
-static void vfio_enable_msi(VFIODevice *vdev)
-{
-    int ret, i;
-
-    vfio_disable_interrupts(vdev);
-
-    vdev->nr_vectors = msi_nr_vectors_allocated(&vdev->pdev);
-retry:
-    vdev->msi_vectors = g_malloc0(vdev->nr_vectors * sizeof(VFIOMSIVector));
-
-    for (i = 0; i < vdev->nr_vectors; i++) {
-        MSIMessage msg;
-        VFIOMSIVector *vector = &vdev->msi_vectors[i];
-
-        vector->vdev = vdev;
-        vector->use = true;
-
-        if (event_notifier_init(&vector->interrupt, 0)) {
-            error_report("vfio: Error: event_notifier_init failed");
-        }
-
-        msg = msi_get_message(&vdev->pdev, i);
-
-        /*
-         * Attempt to enable route through KVM irqchip,
-         * default to userspace handling if unavailable.
-         */
-        vector->virq = kvm_irqchip_add_msi_route(kvm_state, msg);
-        if (vector->virq < 0 ||
-            kvm_irqchip_add_irqfd_notifier(kvm_state, &vector->interrupt,
-                                           vector->virq) < 0) {
-            qemu_set_fd_handler(event_notifier_get_fd(&vector->interrupt),
-                                vfio_msi_interrupt, NULL, vector);
-        }
-    }
-
-    ret = vfio_enable_vectors(vdev, false);
-    if (ret) {
-        if (ret < 0) {
-            error_report("vfio: Error: Failed to setup MSI fds: %m");
-        } else if (ret != vdev->nr_vectors) {
-            error_report("vfio: Error: Failed to enable %d "
-                         "MSI vectors, retry with %d", vdev->nr_vectors, ret);
-        }
-
-        for (i = 0; i < vdev->nr_vectors; i++) {
-            VFIOMSIVector *vector = &vdev->msi_vectors[i];
-            if (vector->virq >= 0) {
-                kvm_irqchip_remove_irqfd_notifier(kvm_state, &vector->interrupt,
-                                                  vector->virq);
-                kvm_irqchip_release_virq(kvm_state, vector->virq);
-                vector->virq = -1;
-            } else {
-                qemu_set_fd_handler(event_notifier_get_fd(&vector->interrupt),
-                                    NULL, NULL, NULL);
-            }
-            event_notifier_cleanup(&vector->interrupt);
-        }
-
-        g_free(vdev->msi_vectors);
-
-        if (ret > 0 && ret != vdev->nr_vectors) {
-            vdev->nr_vectors = ret;
-            goto retry;
-        }
-        vdev->nr_vectors = 0;
-
-        return;
-    }
-
-    vdev->interrupt = VFIO_INT_MSI;
-
-    DPRINTF("%s(%04x:%02x:%02x.%x) Enabled %d MSI vectors\n", __func__,
-            vdev->host.domain, vdev->host.bus, vdev->host.slot,
-            vdev->host.function, vdev->nr_vectors);
-}
-
-static void vfio_disable_msi_common(VFIODevice *vdev)
-{
-    g_free(vdev->msi_vectors);
-    vdev->msi_vectors = NULL;
-    vdev->nr_vectors = 0;
-    vdev->interrupt = VFIO_INT_NONE;
-
-    vfio_enable_intx(vdev);
-}
-
-static void vfio_disable_msix(VFIODevice *vdev)
-{
-    msix_unset_vector_notifiers(&vdev->pdev);
-
-    if (vdev->nr_vectors) {
-        vfio_disable_irqindex(vdev, VFIO_PCI_MSIX_IRQ_INDEX);
-    }
-
-    vfio_disable_msi_common(vdev);
-
-    DPRINTF("%s(%04x:%02x:%02x.%x)\n", __func__, vdev->host.domain,
-            vdev->host.bus, vdev->host.slot, vdev->host.function);
-}
-
-static void vfio_disable_msi(VFIODevice *vdev)
-{
-    int i;
-
-    vfio_disable_irqindex(vdev, VFIO_PCI_MSI_IRQ_INDEX);
-
-    for (i = 0; i < vdev->nr_vectors; i++) {
-        VFIOMSIVector *vector = &vdev->msi_vectors[i];
-
-        if (!vector->use) {
-            continue;
-        }
-
-        if (vector->virq >= 0) {
-            kvm_irqchip_remove_irqfd_notifier(kvm_state,
-                                              &vector->interrupt, vector->virq);
-            kvm_irqchip_release_virq(kvm_state, vector->virq);
-            vector->virq = -1;
-        } else {
-            qemu_set_fd_handler(event_notifier_get_fd(&vector->interrupt),
-                                NULL, NULL, NULL);
-        }
-
-        event_notifier_cleanup(&vector->interrupt);
-    }
-
-    vfio_disable_msi_common(vdev);
-
-    DPRINTF("%s(%04x:%02x:%02x.%x)\n", __func__, vdev->host.domain,
-            vdev->host.bus, vdev->host.slot, vdev->host.function);
-}
-
-/*
- * IO Port/MMIO - Beware of the endians, VFIO is always little endian
- */
-static void vfio_bar_write(void *opaque, hwaddr addr,
-                           uint64_t data, unsigned size)
-{
-    VFIOBAR *bar = opaque;
-    union {
-        uint8_t byte;
-        uint16_t word;
-        uint32_t dword;
-        uint64_t qword;
-    } buf;
-
-    switch (size) {
-    case 1:
-        buf.byte = data;
-        break;
-    case 2:
-        buf.word = cpu_to_le16(data);
-        break;
-    case 4:
-        buf.dword = cpu_to_le32(data);
-        break;
-    default:
-        hw_error("vfio: unsupported write size, %d bytes\n", size);
-        break;
-    }
-
-    if (pwrite(bar->fd, &buf, size, bar->fd_offset + addr) != size) {
-        error_report("%s(,0x%"HWADDR_PRIx", 0x%"PRIx64", %d) failed: %m",
-                     __func__, addr, data, size);
-    }
-
-#ifdef DEBUG_VFIO
-    {
-        VFIODevice *vdev = container_of(bar, VFIODevice, bars[bar->nr]);
-
-        DPRINTF("%s(%04x:%02x:%02x.%x:BAR%d+0x%"HWADDR_PRIx", 0x%"PRIx64
-                ", %d)\n", __func__, vdev->host.domain, vdev->host.bus,
-                vdev->host.slot, vdev->host.function, bar->nr, addr,
-                data, size);
-    }
-#endif
-
-    /*
-     * A read or write to a BAR always signals an INTx EOI.  This will
-     * do nothing if not pending (including not in INTx mode).  We assume
-     * that a BAR access is in response to an interrupt and that BAR
-     * accesses will service the interrupt.  Unfortunately, we don't know
-     * which access will service the interrupt, so we're potentially
-     * getting quite a few host interrupts per guest interrupt.
-     */
-    vfio_eoi(container_of(bar, VFIODevice, bars[bar->nr]));
-}
-
-static uint64_t vfio_bar_read(void *opaque,
-                              hwaddr addr, unsigned size)
-{
-    VFIOBAR *bar = opaque;
-    union {
-        uint8_t byte;
-        uint16_t word;
-        uint32_t dword;
-        uint64_t qword;
-    } buf;
-    uint64_t data = 0;
-
-    if (pread(bar->fd, &buf, size, bar->fd_offset + addr) != size) {
-        error_report("%s(,0x%"HWADDR_PRIx", %d) failed: %m",
-                     __func__, addr, size);
-        return (uint64_t)-1;
-    }
-
-    switch (size) {
-    case 1:
-        data = buf.byte;
-        break;
-    case 2:
-        data = le16_to_cpu(buf.word);
-        break;
-    case 4:
-        data = le32_to_cpu(buf.dword);
-        break;
-    default:
-        hw_error("vfio: unsupported read size, %d bytes\n", size);
-        break;
-    }
-
-#ifdef DEBUG_VFIO
-    {
-        VFIODevice *vdev = container_of(bar, VFIODevice, bars[bar->nr]);
-
-        DPRINTF("%s(%04x:%02x:%02x.%x:BAR%d+0x%"HWADDR_PRIx
-                ", %d) = 0x%"PRIx64"\n", __func__, vdev->host.domain,
-                vdev->host.bus, vdev->host.slot, vdev->host.function,
-                bar->nr, addr, size, data);
-    }
-#endif
-
-    /* Same as write above */
-    vfio_eoi(container_of(bar, VFIODevice, bars[bar->nr]));
-
-    return data;
-}
-
-static const MemoryRegionOps vfio_bar_ops = {
-    .read = vfio_bar_read,
-    .write = vfio_bar_write,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static void vfio_vga_write(void *opaque, hwaddr addr,
-                           uint64_t data, unsigned size)
-{
-    VFIOVGARegion *region = opaque;
-    VFIOVGA *vga = container_of(region, VFIOVGA, region[region->nr]);
-    union {
-        uint8_t byte;
-        uint16_t word;
-        uint32_t dword;
-        uint64_t qword;
-    } buf;
-    off_t offset = vga->fd_offset + region->offset + addr;
-
-    switch (size) {
-    case 1:
-        buf.byte = data;
-        break;
-    case 2:
-        buf.word = cpu_to_le16(data);
-        break;
-    case 4:
-        buf.dword = cpu_to_le32(data);
-        break;
-    default:
-        hw_error("vfio: unsupported write size, %d bytes\n", size);
-        break;
-    }
-
-    if (pwrite(vga->fd, &buf, size, offset) != size) {
-        error_report("%s(,0x%"HWADDR_PRIx", 0x%"PRIx64", %d) failed: %m",
-                     __func__, region->offset + addr, data, size);
-    }
-
-    DPRINTF("%s(0x%"HWADDR_PRIx", 0x%"PRIx64", %d)\n",
-            __func__, region->offset + addr, data, size);
-}
-
-static uint64_t vfio_vga_read(void *opaque, hwaddr addr, unsigned size)
-{
-    VFIOVGARegion *region = opaque;
-    VFIOVGA *vga = container_of(region, VFIOVGA, region[region->nr]);
-    union {
-        uint8_t byte;
-        uint16_t word;
-        uint32_t dword;
-        uint64_t qword;
-    } buf;
-    uint64_t data = 0;
-    off_t offset = vga->fd_offset + region->offset + addr;
-
-    if (pread(vga->fd, &buf, size, offset) != size) {
-        error_report("%s(,0x%"HWADDR_PRIx", %d) failed: %m",
-                     __func__, region->offset + addr, size);
-        return (uint64_t)-1;
-    }
-
-    switch (size) {
-    case 1:
-        data = buf.byte;
-        break;
-    case 2:
-        data = le16_to_cpu(buf.word);
-        break;
-    case 4:
-        data = le32_to_cpu(buf.dword);
-        break;
-    default:
-        hw_error("vfio: unsupported read size, %d bytes\n", size);
-        break;
-    }
-
-    DPRINTF("%s(0x%"HWADDR_PRIx", %d) = 0x%"PRIx64"\n",
-            __func__, region->offset + addr, size, data);
-
-    return data;
-}
-
-static const MemoryRegionOps vfio_vga_ops = {
-    .read = vfio_vga_read,
-    .write = vfio_vga_write,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-/*
- * Device specific quirks
- */
-
-#define PCI_VENDOR_ID_ATI               0x1002
-
-/*
- * Device 1002:68f9 (Advanced Micro Devices [AMD] nee ATI Cedar PRO [Radeon
- * HD 5450/6350]) reports the upper byte of the physical address of the
- * I/O port BAR4 through VGA register 0x3c3.  The BAR is 256 bytes, so the
- * lower byte is known to be zero.  Probing for this quirk reads 0xff from
- * port 0x3c3 on some devices so we store the physical address and replace
- * reads with the virtual address any time it matches.  XXX Research when
- * to enable quirk.
- */
-static uint64_t vfio_ati_3c3_quirk_read(void *opaque,
-                                        hwaddr addr, unsigned size)
-{
-    VFIOQuirk *quirk = opaque;
-    VFIODevice *vdev = quirk->vdev;
-    PCIDevice *pdev = &vdev->pdev;
-    uint64_t data = vfio_vga_read(&vdev->vga.region[QEMU_PCI_VGA_IO_HI],
-                                  addr + 0x3, size);
-
-    if (data == quirk->data) {
-        data = pci_get_byte(pdev->config + PCI_BASE_ADDRESS_4 + 1);
-        DPRINTF("%s(0x3c3, 1) = 0x%"PRIx64"\n", __func__, data);
-    }
-
-    return data;
-}
-
-static const MemoryRegionOps vfio_ati_3c3_quirk = {
-    .read = vfio_ati_3c3_quirk_read,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static void vfio_vga_probe_ati_3c3_quirk(VFIODevice *vdev)
-{
-    PCIDevice *pdev = &vdev->pdev;
-    off_t physoffset = vdev->config_offset + PCI_BASE_ADDRESS_4;
-    uint32_t physbar;
-    VFIOQuirk *quirk;
-
-    if (pci_get_word(pdev->config + PCI_VENDOR_ID) != PCI_VENDOR_ID_ATI ||
-        vdev->bars[4].size < 256) {
-        return;
-    }
-
-    /* Get I/O port BAR physical address */
-    if (pread(vdev->fd, &physbar, 4, physoffset) != 4) {
-        error_report("vfio: probe failed for ATI/AMD 0x3c3 quirk on device "
-                     "%04x:%02x:%02x.%x", vdev->host.domain,
-                     vdev->host.bus, vdev->host.slot, vdev->host.function);
-        return;
-    }
-
-    quirk = g_malloc0(sizeof(*quirk));
-    quirk->vdev = vdev;
-    quirk->data = (physbar >> 8) & 0xff;
-
-    memory_region_init_io(&quirk->mem, &vfio_ati_3c3_quirk, quirk,
-                          "vfio-ati-3c3-quirk", 1);
-    memory_region_add_subregion(&vdev->vga.region[QEMU_PCI_VGA_IO_HI].mem, 3,
-                                &quirk->mem);
-
-    QLIST_INSERT_HEAD(&vdev->vga.region[QEMU_PCI_VGA_IO_HI].quirks,
-                      quirk, next);
-
-    DPRINTF("Enabled ATI/AMD quirk 0x3c3 for device %04x:%02x:%02x.%x\n",
-            vdev->host.domain, vdev->host.bus, vdev->host.slot,
-            vdev->host.function);
-}
-
-/*
- * Device 1002:68f9 (Advanced Micro Devices [AMD] nee ATI Cedar PRO [Radeon
- * HD 5450/6350]) reports the physical address of MMIO BAR0 through a
- * write/read operation on I/O port BAR4.  When uint32_t 0x4010 is written
- * to offset 0x0, the subsequent read from offset 0x4 returns the contents
- * of BAR0.  Test for this quirk on all ATI/AMD devices.  XXX - Note that
- * 0x10 is the offset of BAR0 in config sapce, is this a window to all of
- * config space?
- */
-static uint64_t vfio_ati_4010_quirk_read(void *opaque,
-                                         hwaddr addr, unsigned size)
-{
-    VFIOQuirk *quirk = opaque;
-    VFIODevice *vdev = quirk->vdev;
-    PCIDevice *pdev = &vdev->pdev;
-    uint64_t data = vfio_bar_read(&vdev->bars[4], addr, size);
-
-    if (addr == 4 && size == 4 && quirk->data) {
-        data = pci_get_long(pdev->config + PCI_BASE_ADDRESS_0);
-        DPRINTF("%s(BAR4+0x4) = 0x%"PRIx64"\n", __func__, data);
-    }
-
-    quirk->data = 0;
-
-    return data;
-}
-
-static void vfio_ati_4010_quirk_write(void *opaque, hwaddr addr,
-                                      uint64_t data, unsigned size)
-{
-    VFIOQuirk *quirk = opaque;
-    VFIODevice *vdev = quirk->vdev;
-
-    vfio_bar_write(&vdev->bars[4], addr, data, size);
-
-    quirk->data = (addr == 0 && size == 4 && data == 0x4010) ? 1 : 0;
-}
-
-static const MemoryRegionOps vfio_ati_4010_quirk = {
-    .read = vfio_ati_4010_quirk_read,
-    .write = vfio_ati_4010_quirk_write,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static void vfio_probe_ati_4010_quirk(VFIODevice *vdev, int nr)
-{
-    PCIDevice *pdev = &vdev->pdev;
-    off_t physoffset = vdev->config_offset + PCI_BASE_ADDRESS_0;
-    uint32_t physbar0;
-    uint64_t data;
-    VFIOQuirk *quirk;
-
-    if (!vdev->has_vga || nr != 4 || !vdev->bars[0].size ||
-        pci_get_word(pdev->config + PCI_VENDOR_ID) != PCI_VENDOR_ID_ATI) {
-        return;
-    }
-
-    /* Get I/O port BAR physical address */
-    if (pread(vdev->fd, &physbar0, 4, physoffset) != 4) {
-        error_report("vfio: probe failed for ATI/AMD 0x4010 quirk on device "
-                     "%04x:%02x:%02x.%x", vdev->host.domain,
-                     vdev->host.bus, vdev->host.slot, vdev->host.function);
-        return;
-    }
-
-    /* Write 0x4010 to I/O port BAR offset 0 */
-    vfio_bar_write(&vdev->bars[4], 0, 0x4010, 4);
-    /* Read back result */
-    data = vfio_bar_read(&vdev->bars[4], 4, 4);
-
-    /* If the register matches the physical address of BAR0, we need a quirk */
-    if (data != physbar0) {
-        return;
-    }
-
-    quirk = g_malloc0(sizeof(*quirk));
-    quirk->vdev = vdev;
-
-    memory_region_init_io(&quirk->mem, &vfio_ati_4010_quirk, quirk,
-                          "vfio-ati-4010-quirk", 8);
-    memory_region_add_subregion_overlap(&vdev->bars[nr].mem, 0, &quirk->mem, 1);
-
-    QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next);
-
-    DPRINTF("Enabled ATI/AMD quirk 0x4010 for device %04x:%02x:%02x.%x\n",
-            vdev->host.domain, vdev->host.bus, vdev->host.slot,
-            vdev->host.function);
-}
-
-/*
- * Device 1002:5b63 (Advanced Micro Devices [AMD] nee ATI RV370 [Radeon X550])
- * retrieves the upper half of the MMIO BAR0 physical address by writing
- * 0xf10 to I/O port BAR1 offset 0 and reading the result from offset 6.
- * XXX - 0x10 is the offset of BAR0 in PCI config space, this could provide
- * full access to config space.  Config space is little endian, so the data
- * register probably starts at 0x4.
- */
-static uint64_t vfio_ati_f10_quirk_read(void *opaque,
-                                        hwaddr addr, unsigned size)
-{
-    VFIOQuirk *quirk = opaque;
-    VFIODevice *vdev = quirk->vdev;
-    PCIDevice *pdev = &vdev->pdev;
-    uint64_t data = vfio_bar_read(&vdev->bars[1], addr, size);
-
-    if (addr == 6 && size == 2 && quirk->data) {
-        data = pci_get_word(pdev->config + PCI_BASE_ADDRESS_0 + 2);
-        DPRINTF("%s(BAR1+0x6) = 0x%"PRIx64"\n", __func__, data);
-    }
-
-    quirk->data = 0;
-
-    return data;
-}
-
-static void vfio_ati_f10_quirk_write(void *opaque, hwaddr addr,
-                                     uint64_t data, unsigned size)
-{
-    VFIOQuirk *quirk = opaque;
-    VFIODevice *vdev = quirk->vdev;
-
-    vfio_bar_write(&vdev->bars[1], addr, data, size);
-
-    quirk->data = (addr == 0 && size == 4 && data == 0xf10) ? 1 : 0;
-}
-
-static const MemoryRegionOps vfio_ati_f10_quirk = {
-    .read = vfio_ati_f10_quirk_read,
-    .write = vfio_ati_f10_quirk_write,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static void vfio_probe_ati_f10_quirk(VFIODevice *vdev, int nr)
-{
-    PCIDevice *pdev = &vdev->pdev;
-    off_t physoffset = vdev->config_offset + PCI_BASE_ADDRESS_0;
-    uint32_t physbar0;
-    uint64_t data;
-    VFIOQuirk *quirk;
-
-    if (!vdev->has_vga || nr != 1 || !vdev->bars[0].size ||
-        pci_get_word(pdev->config + PCI_VENDOR_ID) != PCI_VENDOR_ID_ATI) {
-        return;
-    }
-
-    /* Get I/O port BAR physical address */
-    if (pread(vdev->fd, &physbar0, 4, physoffset) != 4) {
-        error_report("vfio: probe failed for ATI/AMD 0xf10 quirk on device "
-                     "%04x:%02x:%02x.%x", vdev->host.domain,
-                     vdev->host.bus, vdev->host.slot, vdev->host.function);
-        return;
-    }
-
-    vfio_bar_write(&vdev->bars[1], 0, 0xf10, 4);
-    data = vfio_bar_read(&vdev->bars[1], 0x6, 2);
-
-    /* If the register matches the physical address of BAR0, we need a quirk */
-    if (data != (le32_to_cpu(physbar0) >> 16)) {
-        return;
-    }
-
-    quirk = g_malloc0(sizeof(*quirk));
-    quirk->vdev = vdev;
-
-    memory_region_init_io(&quirk->mem, &vfio_ati_f10_quirk, quirk,
-                          "vfio-ati-f10-quirk", 8);
-    memory_region_add_subregion_overlap(&vdev->bars[nr].mem, 0, &quirk->mem, 1);
-
-    QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next);
-
-    DPRINTF("Enabled ATI/AMD quirk 0xf10 for device %04x:%02x:%02x.%x\n",
-            vdev->host.domain, vdev->host.bus, vdev->host.slot,
-            vdev->host.function);
-}
-
-#define PCI_VENDOR_ID_NVIDIA                    0x10de
-
-/*
- * Nvidia has several different methods to get to config space, the
- * nouveu project has several of these documented here:
- * https://github.com/pathscale/envytools/tree/master/hwdocs
- *
- * The first quirk is actually not documented in envytools and is found
- * on 10de:01d1 (NVIDIA Corporation G72 [GeForce 7300 LE]).  This is an
- * NV46 chipset.  The backdoor uses the legacy VGA I/O ports to access
- * the mirror of PCI config space found at BAR0 offset 0x1800.  The access
- * sequence first writes 0x338 to I/O port 0x3d4.  The target offset is
- * then written to 0x3d0.  Finally 0x538 is written for a read and 0x738
- * is written for a write to 0x3d4.  The BAR0 offset is then accessible
- * through 0x3d0.  This quirk doesn't seem to be necessary on newer cards
- * that use the I/O port BAR5 window but it doesn't hurt to leave it.
- */
-enum {
-    NV_3D0_NONE,
-    NV_3D0_SELECT,
-    NV_3D0_WINDOW,
-    NV_3D0_READ,
-    NV_3D0_WRITE,
-};
-
-static uint64_t vfio_nvidia_3d0_quirk_read(void *opaque,
-                                           hwaddr addr, unsigned size)
-{
-    VFIOQuirk *quirk = opaque;
-    VFIODevice *vdev = quirk->vdev;
-    PCIDevice *pdev = &vdev->pdev;
-    uint64_t data = vfio_vga_read(&vdev->vga.region[QEMU_PCI_VGA_IO_HI],
-                                  addr + 0x10, size);
-
-    if (quirk->data == NV_3D0_READ && addr == 0) {
-        data = vfio_pci_read_config(pdev, quirk->data2, size);
-        DPRINTF("%s(0x3d0, %d) = 0x%"PRIx64"\n", __func__, size, data);
-    }
-
-    quirk->data = NV_3D0_NONE;
-
-    return data;
-}
-
-static void vfio_nvidia_3d0_quirk_write(void *opaque, hwaddr addr,
-                                        uint64_t data, unsigned size)
-{
-    VFIOQuirk *quirk = opaque;
-    VFIODevice *vdev = quirk->vdev;
-    PCIDevice *pdev = &vdev->pdev;
-
-    switch (quirk->data) {
-    case NV_3D0_NONE:
-        if (addr == 4 && data == 0x338) {
-            quirk->data = NV_3D0_SELECT;
-        }
-        break;
-    case NV_3D0_SELECT:
-        quirk->data = NV_3D0_NONE;
-        if (addr == 0 && (data & ~0xff) == 0x1800) {
-            quirk->data = NV_3D0_WINDOW;
-            quirk->data2 = data & 0xff;
-        }
-        break;
-    case NV_3D0_WINDOW:
-        quirk->data = NV_3D0_NONE;
-        if (addr == 4) {
-            if (data == 0x538) {
-                quirk->data = NV_3D0_READ;
-            } else if (data == 0x738) {
-                quirk->data = NV_3D0_WRITE;
-            }
-        }
-        break;
-    case NV_3D0_WRITE:
-        quirk->data = NV_3D0_NONE;
-        if (addr == 0) {
-            vfio_pci_write_config(pdev, quirk->data2, data, size);
-            DPRINTF("%s(0x3d0, 0x%"PRIx64", %d)\n", __func__, data, size);
-            return;
-        }
-        break;
-    default:
-        quirk->data = NV_3D0_NONE;
-    }
-
-    vfio_vga_write(&vdev->vga.region[QEMU_PCI_VGA_IO_HI],
-                   addr + 0x10, data, size);
-}
-
-static const MemoryRegionOps vfio_nvidia_3d0_quirk = {
-    .read = vfio_nvidia_3d0_quirk_read,
-    .write = vfio_nvidia_3d0_quirk_write,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static void vfio_vga_probe_nvidia_3d0_quirk(VFIODevice *vdev)
-{
-    PCIDevice *pdev = &vdev->pdev;
-    VFIOQuirk *quirk;
-
-    if (pci_get_word(pdev->config + PCI_VENDOR_ID) != PCI_VENDOR_ID_NVIDIA ||
-        !vdev->bars[1].size) {
-        return;
-    }
-
-    quirk = g_malloc0(sizeof(*quirk));
-    quirk->vdev = vdev;
-
-    memory_region_init_io(&quirk->mem, &vfio_nvidia_3d0_quirk, quirk,
-                          "vfio-nvidia-3d0-quirk", 6);
-    memory_region_add_subregion(&vdev->vga.region[QEMU_PCI_VGA_IO_HI].mem,
-                                0x10, &quirk->mem);
-
-    QLIST_INSERT_HEAD(&vdev->vga.region[QEMU_PCI_VGA_IO_HI].quirks,
-                      quirk, next);
-
-    DPRINTF("Enabled NVIDIA VGA 0x3d0 quirk for device %04x:%02x:%02x.%x\n",
-            vdev->host.domain, vdev->host.bus, vdev->host.slot,
-            vdev->host.function);
-}
-
-/*
- * The second quirk is documented in envytools.  The I/O port BAR5 is just
- * a set of address/data ports to the MMIO BARs.  The BAR we care about is
- * again BAR0.  This backdoor is apparently a bit newer than the one above
- * so we need to not only trap 256 bytes @0x1800, but all of PCI config
- * space, including extended space is available at the 4k @0x88000.
- */
-enum {
-    NV_BAR5_ADDRESS = 0x1,
-    NV_BAR5_ENABLE = 0x2,
-    NV_BAR5_MASTER = 0x4,
-    NV_BAR5_VALID = 0x7,
-};
-
-static uint64_t vfio_nvidia_bar5_window_quirk_read(void *opaque,
-                                                   hwaddr addr, unsigned size)
-{
-    VFIOQuirk *quirk = opaque;
-    VFIODevice *vdev = quirk->vdev;
-    uint64_t data = vfio_bar_read(&vdev->bars[5], addr, size);
-
-    if (addr == 0xc && quirk->data == NV_BAR5_VALID) {
-        data = vfio_pci_read_config(&vdev->pdev, quirk->data2, size);
-        DPRINTF("%s(%04x:%02x:%02x.%x:BAR5+0x%"HWADDR_PRIx", %d) = 0x%"
-                PRIx64"\n", __func__, vdev->host.domain, vdev->host.bus,
-                vdev->host.slot, vdev->host.function, addr, size, data);
-    }
-
-    return data;
-}
-
-static void vfio_nvidia_bar5_window_quirk_write(void *opaque, hwaddr addr,
-                                                uint64_t data, unsigned size)
-{
-    VFIOQuirk *quirk = opaque;
-    VFIODevice *vdev = quirk->vdev;
-
-    /*
-     * Use quirk->data to track enables and quirk->data2 for the offset
-     */
-    switch (addr) {
-    case 0x0:
-        if (data & 0x1) {
-            quirk->data |= NV_BAR5_MASTER;
-        } else {
-            quirk->data &= ~NV_BAR5_MASTER;
-        }
-        break;
-    case 0x4:
-        if (data & 0x1) {
-            quirk->data |= NV_BAR5_ENABLE;
-        } else {
-            quirk->data &= ~NV_BAR5_ENABLE;
-        }
-        break;
-    case 0x8:
-        if (quirk->data & NV_BAR5_MASTER) {
-            if ((data & ~0xfff) == 0x88000) {
-                quirk->data |= NV_BAR5_ADDRESS;
-                quirk->data2 = data & 0xfff;
-            } else if ((data & ~0xff) == 0x1800) {
-                quirk->data |= NV_BAR5_ADDRESS;
-                quirk->data2 = data & 0xff;
-            } else {
-                quirk->data &= ~NV_BAR5_ADDRESS;
-            }
-        }
-        break;
-    case 0xc:
-        if (quirk->data == NV_BAR5_VALID) {
-            vfio_pci_write_config(&vdev->pdev, quirk->data2, data, size);
-            DPRINTF("%s(%04x:%02x:%02x.%x:BAR5+0x%"HWADDR_PRIx", 0x%"
-                    PRIx64", %d)\n", __func__, vdev->host.domain,
-                    vdev->host.bus, vdev->host.slot, vdev->host.function,
-                    addr, data, size);
-            return;
-        }
-    }
-
-    vfio_bar_write(&vdev->bars[5], addr, data, size);
-}
-
-static const MemoryRegionOps vfio_nvidia_bar5_window_quirk = {
-    .read = vfio_nvidia_bar5_window_quirk_read,
-    .write = vfio_nvidia_bar5_window_quirk_write,
-    .valid.min_access_size = 4,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static void vfio_probe_nvidia_bar5_window_quirk(VFIODevice *vdev, int nr)
-{
-    PCIDevice *pdev = &vdev->pdev;
-    VFIOQuirk *quirk;
-
-    if (!vdev->has_vga || nr != 5 ||
-        pci_get_word(pdev->config + PCI_VENDOR_ID) != PCI_VENDOR_ID_NVIDIA) {
-        return;
-    }
-
-    quirk = g_malloc0(sizeof(*quirk));
-    quirk->vdev = vdev;
-
-    memory_region_init_io(&quirk->mem, &vfio_nvidia_bar5_window_quirk, quirk,
-                          "vfio-nvidia-bar5-window-quirk", 16);
-    memory_region_add_subregion_overlap(&vdev->bars[nr].mem, 0, &quirk->mem, 1);
-
-    QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next);
-
-    DPRINTF("Enabled NVIDIA BAR5 window quirk for device %04x:%02x:%02x.%x\n",
-            vdev->host.domain, vdev->host.bus, vdev->host.slot,
-            vdev->host.function);
-}
-
-/*
- * Finally, BAR0 itself.  We want to redirect any accesses to either
- * 0x1800 or 0x88000 through the PCI config space access functions.
- *
- * NB - quirk at a page granularity or else they don't seem to work when
- *      BARs are mmap'd
- *
- * Here's offset 0x88000...
- */
-static uint64_t vfio_nvidia_bar0_88000_quirk_read(void *opaque,
-                                                  hwaddr addr, unsigned size)
-{
-    VFIOQuirk *quirk = opaque;
-    VFIODevice *vdev = quirk->vdev;
-    hwaddr base = 0x88000 & TARGET_PAGE_MASK;
-    hwaddr offset = 0x88000 & ~TARGET_PAGE_MASK;
-    uint64_t data = vfio_bar_read(&vdev->bars[0], addr + base, size);
-
-    if (ranges_overlap(addr, size, offset, PCI_CONFIG_SPACE_SIZE)) {
-        data = vfio_pci_read_config(&vdev->pdev, addr - offset, size);
-
-        DPRINTF("%s(%04x:%02x:%02x.%x:BAR0+0x%"HWADDR_PRIx", %d) = 0x%"
-                PRIx64"\n", __func__, vdev->host.domain, vdev->host.bus,
-                vdev->host.slot, vdev->host.function, addr + base, size, data);
-    }
-
-    return data;
-}
-
-static void vfio_nvidia_bar0_88000_quirk_write(void *opaque, hwaddr addr,
-                                               uint64_t data, unsigned size)
-{
-    VFIOQuirk *quirk = opaque;
-    VFIODevice *vdev = quirk->vdev;
-    hwaddr base = 0x88000 & TARGET_PAGE_MASK;
-    hwaddr offset = 0x88000 & ~TARGET_PAGE_MASK;
-
-    if (ranges_overlap(addr, size, offset, PCI_CONFIG_SPACE_SIZE)) {
-        vfio_pci_write_config(&vdev->pdev, addr - offset, data, size);
-
-        DPRINTF("%s(%04x:%02x:%02x.%x:BAR0+0x%"HWADDR_PRIx", 0x%"
-                PRIx64", %d)\n", __func__, vdev->host.domain, vdev->host.bus,
-                vdev->host.slot, vdev->host.function, addr + base, data, size);
-    } else {
-        vfio_bar_write(&vdev->bars[0], addr + base, data, size);
-    }
-}
-
-static const MemoryRegionOps vfio_nvidia_bar0_88000_quirk = {
-    .read = vfio_nvidia_bar0_88000_quirk_read,
-    .write = vfio_nvidia_bar0_88000_quirk_write,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static void vfio_probe_nvidia_bar0_88000_quirk(VFIODevice *vdev, int nr)
-{
-    PCIDevice *pdev = &vdev->pdev;
-    VFIOQuirk *quirk;
-
-    if (!vdev->has_vga || nr != 0 ||
-        pci_get_word(pdev->config + PCI_VENDOR_ID) != PCI_VENDOR_ID_NVIDIA) {
-        return;
-    }
-
-    quirk = g_malloc0(sizeof(*quirk));
-    quirk->vdev = vdev;
-
-    memory_region_init_io(&quirk->mem, &vfio_nvidia_bar0_88000_quirk, quirk,
-                          "vfio-nvidia-bar0-88000-quirk",
-                          TARGET_PAGE_ALIGN(PCIE_CONFIG_SPACE_SIZE));
-    memory_region_add_subregion_overlap(&vdev->bars[nr].mem,
-                                        0x88000 & TARGET_PAGE_MASK,
-                                        &quirk->mem, 1);
-
-    QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next);
-
-    DPRINTF("Enabled NVIDIA BAR0 0x88000 quirk for device %04x:%02x:%02x.%x\n",
-            vdev->host.domain, vdev->host.bus, vdev->host.slot,
-            vdev->host.function);
-}
-
-/*
- * And here's the same for BAR0 offset 0x1800...
- */
-static uint64_t vfio_nvidia_bar0_1800_quirk_read(void *opaque,
-                                                 hwaddr addr, unsigned size)
-{
-    VFIOQuirk *quirk = opaque;
-    VFIODevice *vdev = quirk->vdev;
-    hwaddr base = 0x1800 & TARGET_PAGE_MASK;
-    hwaddr offset = 0x1800 & ~TARGET_PAGE_MASK;
-    uint64_t data = vfio_bar_read(&vdev->bars[0], addr + base, size);
-
-    if (ranges_overlap(addr, size, offset, PCI_CONFIG_SPACE_SIZE)) {
-        data = vfio_pci_read_config(&vdev->pdev, addr - offset, size);
-
-        DPRINTF("%s(%04x:%02x:%02x.%x:BAR0+0x%"HWADDR_PRIx", %d) = 0x%"
-                PRIx64"\n", __func__, vdev->host.domain, vdev->host.bus,
-                vdev->host.slot, vdev->host.function, addr + base, size, data);
-    }
-
-    return data;
-}
-
-static void vfio_nvidia_bar0_1800_quirk_write(void *opaque, hwaddr addr,
-                                              uint64_t data, unsigned size)
-{
-    VFIOQuirk *quirk = opaque;
-    VFIODevice *vdev = quirk->vdev;
-    hwaddr base = 0x1800 & TARGET_PAGE_MASK;
-    hwaddr offset = 0x1800 & ~TARGET_PAGE_MASK;
-
-    if (ranges_overlap(addr, size, offset, PCI_CONFIG_SPACE_SIZE)) {
-        vfio_pci_write_config(&vdev->pdev, addr - offset, data, size);
-
-        DPRINTF("%s(%04x:%02x:%02x.%x:BAR0+0x%"HWADDR_PRIx", 0x%"
-                PRIx64", %d)\n", __func__, vdev->host.domain, vdev->host.bus,
-                vdev->host.slot, vdev->host.function, addr + base, data, size);
-    } else {
-        vfio_bar_write(&vdev->bars[0], addr + base, data, size);
-    }
-}
-
-static const MemoryRegionOps vfio_nvidia_bar0_1800_quirk = {
-    .read = vfio_nvidia_bar0_1800_quirk_read,
-    .write = vfio_nvidia_bar0_1800_quirk_write,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static void vfio_probe_nvidia_bar0_1800_quirk(VFIODevice *vdev, int nr)
-{
-    PCIDevice *pdev = &vdev->pdev;
-    VFIOQuirk *quirk;
-
-    if (!vdev->has_vga || nr != 0 ||
-        pci_get_word(pdev->config + PCI_VENDOR_ID) != PCI_VENDOR_ID_NVIDIA) {
-        return;
-    }
-
-    /* Log the chipset ID */
-    DPRINTF("Nvidia NV%02x\n",
-            (unsigned int)(vfio_bar_read(&vdev->bars[0], 0, 4) >> 20) & 0xff);
-
-    quirk = g_malloc0(sizeof(*quirk));
-    quirk->vdev = vdev;
-
-    memory_region_init_io(&quirk->mem, &vfio_nvidia_bar0_1800_quirk, quirk,
-                          "vfio-nvidia-bar0-1800-quirk",
-                          TARGET_PAGE_ALIGN(PCI_CONFIG_SPACE_SIZE));
-    memory_region_add_subregion_overlap(&vdev->bars[nr].mem,
-                                        0x1800 & TARGET_PAGE_MASK,
-                                        &quirk->mem, 1);
-
-    QLIST_INSERT_HEAD(&vdev->bars[nr].quirks, quirk, next);
-
-    DPRINTF("Enabled NVIDIA BAR0 0x1800 quirk for device %04x:%02x:%02x.%x\n",
-            vdev->host.domain, vdev->host.bus, vdev->host.slot,
-            vdev->host.function);
-}
-
-/*
- * TODO - Some Nvidia devices provide config access to their companion HDA
- * device and even to their parent bridge via these config space mirrors.
- * Add quirks for those regions.
- */
-
-/*
- * Common quirk probe entry points.
- */
-static void vfio_vga_quirk_setup(VFIODevice *vdev)
-{
-    vfio_vga_probe_ati_3c3_quirk(vdev);
-    vfio_vga_probe_nvidia_3d0_quirk(vdev);
-}
-
-static void vfio_vga_quirk_teardown(VFIODevice *vdev)
-{
-    int i;
-
-    for (i = 0; i < ARRAY_SIZE(vdev->vga.region); i++) {
-        while (!QLIST_EMPTY(&vdev->vga.region[i].quirks)) {
-            VFIOQuirk *quirk = QLIST_FIRST(&vdev->vga.region[i].quirks);
-            memory_region_del_subregion(&vdev->vga.region[i].mem, &quirk->mem);
-            QLIST_REMOVE(quirk, next);
-            g_free(quirk);
-        }
-    }
-}
-
-static void vfio_bar_quirk_setup(VFIODevice *vdev, int nr)
-{
-    vfio_probe_ati_4010_quirk(vdev, nr);
-    vfio_probe_ati_f10_quirk(vdev, nr);
-    vfio_probe_nvidia_bar5_window_quirk(vdev, nr);
-    vfio_probe_nvidia_bar0_88000_quirk(vdev, nr);
-    vfio_probe_nvidia_bar0_1800_quirk(vdev, nr);
-}
-
-static void vfio_bar_quirk_teardown(VFIODevice *vdev, int nr)
-{
-    VFIOBAR *bar = &vdev->bars[nr];
-
-    while (!QLIST_EMPTY(&bar->quirks)) {
-        VFIOQuirk *quirk = QLIST_FIRST(&bar->quirks);
-        memory_region_del_subregion(&bar->mem, &quirk->mem);
-        QLIST_REMOVE(quirk, next);
-        g_free(quirk);
-    }
-}
-
-/*
- * PCI config space
- */
-static uint32_t vfio_pci_read_config(PCIDevice *pdev, uint32_t addr, int len)
-{
-    VFIODevice *vdev = DO_UPCAST(VFIODevice, pdev, pdev);
-    uint32_t emu_bits = 0, emu_val = 0, phys_val = 0, val;
-
-    memcpy(&emu_bits, vdev->emulated_config_bits + addr, len);
-    emu_bits = le32_to_cpu(emu_bits);
-
-    if (emu_bits) {
-        emu_val = pci_default_read_config(pdev, addr, len);
-    }
-
-    if (~emu_bits & (0xffffffffU >> (32 - len * 8))) {
-        ssize_t ret;
-
-        ret = pread(vdev->fd, &phys_val, len, vdev->config_offset + addr);
-        if (ret != len) {
-            error_report("%s(%04x:%02x:%02x.%x, 0x%x, 0x%x) failed: %m",
-                         __func__, vdev->host.domain, vdev->host.bus,
-                         vdev->host.slot, vdev->host.function, addr, len);
-            return -errno;
-        }
-        phys_val = le32_to_cpu(phys_val);
-    }
-
-    val = (emu_val & emu_bits) | (phys_val & ~emu_bits);
-
-    DPRINTF("%s(%04x:%02x:%02x.%x, @0x%x, len=0x%x) %x\n", __func__,
-            vdev->host.domain, vdev->host.bus, vdev->host.slot,
-            vdev->host.function, addr, len, val);
-
-    return val;
-}
-
-static void vfio_pci_write_config(PCIDevice *pdev, uint32_t addr,
-                                  uint32_t val, int len)
-{
-    VFIODevice *vdev = DO_UPCAST(VFIODevice, pdev, pdev);
-    uint32_t val_le = cpu_to_le32(val);
-
-    DPRINTF("%s(%04x:%02x:%02x.%x, @0x%x, 0x%x, len=0x%x)\n", __func__,
-            vdev->host.domain, vdev->host.bus, vdev->host.slot,
-            vdev->host.function, addr, val, len);
-
-    /* Write everything to VFIO, let it filter out what we can't write */
-    if (pwrite(vdev->fd, &val_le, len, vdev->config_offset + addr) != len) {
-        error_report("%s(%04x:%02x:%02x.%x, 0x%x, 0x%x, 0x%x) failed: %m",
-                     __func__, vdev->host.domain, vdev->host.bus,
-                     vdev->host.slot, vdev->host.function, addr, val, len);
-    }
-
-    /* MSI/MSI-X Enabling/Disabling */
-    if (pdev->cap_present & QEMU_PCI_CAP_MSI &&
-        ranges_overlap(addr, len, pdev->msi_cap, vdev->msi_cap_size)) {
-        int is_enabled, was_enabled = msi_enabled(pdev);
-
-        pci_default_write_config(pdev, addr, val, len);
-
-        is_enabled = msi_enabled(pdev);
-
-        if (!was_enabled && is_enabled) {
-            vfio_enable_msi(vdev);
-        } else if (was_enabled && !is_enabled) {
-            vfio_disable_msi(vdev);
-        }
-    } else if (pdev->cap_present & QEMU_PCI_CAP_MSIX &&
-        ranges_overlap(addr, len, pdev->msix_cap, MSIX_CAP_LENGTH)) {
-        int is_enabled, was_enabled = msix_enabled(pdev);
-
-        pci_default_write_config(pdev, addr, val, len);
-
-        is_enabled = msix_enabled(pdev);
-
-        if (!was_enabled && is_enabled) {
-            vfio_enable_msix(vdev);
-        } else if (was_enabled && !is_enabled) {
-            vfio_disable_msix(vdev);
-        }
-    } else {
-        /* Write everything to QEMU to keep emulated bits correct */
-        pci_default_write_config(pdev, addr, val, len);
-    }
-}
-
-/*
- * DMA - Mapping and unmapping for the "type1" IOMMU interface used on x86
- */
-static int vfio_dma_unmap(VFIOContainer *container,
-                          hwaddr iova, ram_addr_t size)
-{
-    struct vfio_iommu_type1_dma_unmap unmap = {
-        .argsz = sizeof(unmap),
-        .flags = 0,
-        .iova = iova,
-        .size = size,
-    };
-
-    if (ioctl(container->fd, VFIO_IOMMU_UNMAP_DMA, &unmap)) {
-        DPRINTF("VFIO_UNMAP_DMA: %d\n", -errno);
-        return -errno;
-    }
-
-    return 0;
-}
-
-static int vfio_dma_map(VFIOContainer *container, hwaddr iova,
-                        ram_addr_t size, void *vaddr, bool readonly)
-{
-    struct vfio_iommu_type1_dma_map map = {
-        .argsz = sizeof(map),
-        .flags = VFIO_DMA_MAP_FLAG_READ,
-        .vaddr = (__u64)(uintptr_t)vaddr,
-        .iova = iova,
-        .size = size,
-    };
-
-    if (!readonly) {
-        map.flags |= VFIO_DMA_MAP_FLAG_WRITE;
-    }
-
-    /*
-     * Try the mapping, if it fails with EBUSY, unmap the region and try
-     * again.  This shouldn't be necessary, but we sometimes see it in
-     * the the VGA ROM space.
-     */
-    if (ioctl(container->fd, VFIO_IOMMU_MAP_DMA, &map) == 0 ||
-        (errno == EBUSY && vfio_dma_unmap(container, iova, size) == 0 &&
-         ioctl(container->fd, VFIO_IOMMU_MAP_DMA, &map) == 0)) {
-        return 0;
-    }
-
-    DPRINTF("VFIO_MAP_DMA: %d\n", -errno);
-    return -errno;
-}
-
-static bool vfio_listener_skipped_section(MemoryRegionSection *section)
-{
-    return !memory_region_is_ram(section->mr);
-}
-
-static void vfio_listener_region_add(MemoryListener *listener,
-                                     MemoryRegionSection *section)
-{
-    VFIOContainer *container = container_of(listener, VFIOContainer,
-                                            iommu_data.listener);
-    hwaddr iova, end;
-    void *vaddr;
-    int ret;
-
-    if (vfio_listener_skipped_section(section)) {
-        DPRINTF("SKIPPING region_add %"HWADDR_PRIx" - %"PRIx64"\n",
-                section->offset_within_address_space,
-                section->offset_within_address_space + section->size - 1);
-        return;
-    }
-
-    if (unlikely((section->offset_within_address_space & ~TARGET_PAGE_MASK) !=
-                 (section->offset_within_region & ~TARGET_PAGE_MASK))) {
-        error_report("%s received unaligned region", __func__);
-        return;
-    }
-
-    iova = TARGET_PAGE_ALIGN(section->offset_within_address_space);
-    end = (section->offset_within_address_space + section->size) &
-          TARGET_PAGE_MASK;
-
-    if (iova >= end) {
-        return;
-    }
-
-    vaddr = memory_region_get_ram_ptr(section->mr) +
-            section->offset_within_region +
-            (iova - section->offset_within_address_space);
-
-    DPRINTF("region_add %"HWADDR_PRIx" - %"HWADDR_PRIx" [%p]\n",
-            iova, end - 1, vaddr);
-
-    ret = vfio_dma_map(container, iova, end - iova, vaddr, section->readonly);
-    if (ret) {
-        error_report("vfio_dma_map(%p, 0x%"HWADDR_PRIx", "
-                     "0x%"HWADDR_PRIx", %p) = %d (%m)",
-                     container, iova, end - iova, vaddr, ret);
-    }
-}
-
-static void vfio_listener_region_del(MemoryListener *listener,
-                                     MemoryRegionSection *section)
-{
-    VFIOContainer *container = container_of(listener, VFIOContainer,
-                                            iommu_data.listener);
-    hwaddr iova, end;
-    int ret;
-
-    if (vfio_listener_skipped_section(section)) {
-        DPRINTF("SKIPPING region_del %"HWADDR_PRIx" - %"PRIx64"\n",
-                section->offset_within_address_space,
-                section->offset_within_address_space + section->size - 1);
-        return;
-    }
-
-    if (unlikely((section->offset_within_address_space & ~TARGET_PAGE_MASK) !=
-                 (section->offset_within_region & ~TARGET_PAGE_MASK))) {
-        error_report("%s received unaligned region", __func__);
-        return;
-    }
-
-    iova = TARGET_PAGE_ALIGN(section->offset_within_address_space);
-    end = (section->offset_within_address_space + section->size) &
-          TARGET_PAGE_MASK;
-
-    if (iova >= end) {
-        return;
-    }
-
-    DPRINTF("region_del %"HWADDR_PRIx" - %"HWADDR_PRIx"\n",
-            iova, end - 1);
-
-    ret = vfio_dma_unmap(container, iova, end - iova);
-    if (ret) {
-        error_report("vfio_dma_unmap(%p, 0x%"HWADDR_PRIx", "
-                     "0x%"HWADDR_PRIx") = %d (%m)",
-                     container, iova, end - iova, ret);
-    }
-}
-
-static MemoryListener vfio_memory_listener = {
-    .region_add = vfio_listener_region_add,
-    .region_del = vfio_listener_region_del,
-};
-
-static void vfio_listener_release(VFIOContainer *container)
-{
-    memory_listener_unregister(&container->iommu_data.listener);
-}
-
-/*
- * Interrupt setup
- */
-static void vfio_disable_interrupts(VFIODevice *vdev)
-{
-    switch (vdev->interrupt) {
-    case VFIO_INT_INTx:
-        vfio_disable_intx(vdev);
-        break;
-    case VFIO_INT_MSI:
-        vfio_disable_msi(vdev);
-        break;
-    case VFIO_INT_MSIX:
-        vfio_disable_msix(vdev);
-        break;
-    }
-}
-
-static int vfio_setup_msi(VFIODevice *vdev, int pos)
-{
-    uint16_t ctrl;
-    bool msi_64bit, msi_maskbit;
-    int ret, entries;
-
-    if (pread(vdev->fd, &ctrl, sizeof(ctrl),
-              vdev->config_offset + pos + PCI_CAP_FLAGS) != sizeof(ctrl)) {
-        return -errno;
-    }
-    ctrl = le16_to_cpu(ctrl);
-
-    msi_64bit = !!(ctrl & PCI_MSI_FLAGS_64BIT);
-    msi_maskbit = !!(ctrl & PCI_MSI_FLAGS_MASKBIT);
-    entries = 1 << ((ctrl & PCI_MSI_FLAGS_QMASK) >> 1);
-
-    DPRINTF("%04x:%02x:%02x.%x PCI MSI CAP @0x%x\n", vdev->host.domain,
-            vdev->host.bus, vdev->host.slot, vdev->host.function, pos);
-
-    ret = msi_init(&vdev->pdev, pos, entries, msi_64bit, msi_maskbit);
-    if (ret < 0) {
-        if (ret == -ENOTSUP) {
-            return 0;
-        }
-        error_report("vfio: msi_init failed");
-        return ret;
-    }
-    vdev->msi_cap_size = 0xa + (msi_maskbit ? 0xa : 0) + (msi_64bit ? 0x4 : 0);
-
-    return 0;
-}
-
-/*
- * We don't have any control over how pci_add_capability() inserts
- * capabilities into the chain.  In order to setup MSI-X we need a
- * MemoryRegion for the BAR.  In order to setup the BAR and not
- * attempt to mmap the MSI-X table area, which VFIO won't allow, we
- * need to first look for where the MSI-X table lives.  So we
- * unfortunately split MSI-X setup across two functions.
- */
-static int vfio_early_setup_msix(VFIODevice *vdev)
-{
-    uint8_t pos;
-    uint16_t ctrl;
-    uint32_t table, pba;
-
-    pos = pci_find_capability(&vdev->pdev, PCI_CAP_ID_MSIX);
-    if (!pos) {
-        return 0;
-    }
-
-    if (pread(vdev->fd, &ctrl, sizeof(ctrl),
-              vdev->config_offset + pos + PCI_CAP_FLAGS) != sizeof(ctrl)) {
-        return -errno;
-    }
-
-    if (pread(vdev->fd, &table, sizeof(table),
-              vdev->config_offset + pos + PCI_MSIX_TABLE) != sizeof(table)) {
-        return -errno;
-    }
-
-    if (pread(vdev->fd, &pba, sizeof(pba),
-              vdev->config_offset + pos + PCI_MSIX_PBA) != sizeof(pba)) {
-        return -errno;
-    }
-
-    ctrl = le16_to_cpu(ctrl);
-    table = le32_to_cpu(table);
-    pba = le32_to_cpu(pba);
-
-    vdev->msix = g_malloc0(sizeof(*(vdev->msix)));
-    vdev->msix->table_bar = table & PCI_MSIX_FLAGS_BIRMASK;
-    vdev->msix->table_offset = table & ~PCI_MSIX_FLAGS_BIRMASK;
-    vdev->msix->pba_bar = pba & PCI_MSIX_FLAGS_BIRMASK;
-    vdev->msix->pba_offset = pba & ~PCI_MSIX_FLAGS_BIRMASK;
-    vdev->msix->entries = (ctrl & PCI_MSIX_FLAGS_QSIZE) + 1;
-
-    DPRINTF("%04x:%02x:%02x.%x "
-            "PCI MSI-X CAP @0x%x, BAR %d, offset 0x%x, entries %d\n",
-            vdev->host.domain, vdev->host.bus, vdev->host.slot,
-            vdev->host.function, pos, vdev->msix->table_bar,
-            vdev->msix->table_offset, vdev->msix->entries);
-
-    return 0;
-}
-
-static int vfio_setup_msix(VFIODevice *vdev, int pos)
-{
-    int ret;
-
-    ret = msix_init(&vdev->pdev, vdev->msix->entries,
-                    &vdev->bars[vdev->msix->table_bar].mem,
-                    vdev->msix->table_bar, vdev->msix->table_offset,
-                    &vdev->bars[vdev->msix->pba_bar].mem,
-                    vdev->msix->pba_bar, vdev->msix->pba_offset, pos);
-    if (ret < 0) {
-        if (ret == -ENOTSUP) {
-            return 0;
-        }
-        error_report("vfio: msix_init failed");
-        return ret;
-    }
-
-    return 0;
-}
-
-static void vfio_teardown_msi(VFIODevice *vdev)
-{
-    msi_uninit(&vdev->pdev);
-
-    if (vdev->msix) {
-        msix_uninit(&vdev->pdev, &vdev->bars[vdev->msix->table_bar].mem,
-                    &vdev->bars[vdev->msix->pba_bar].mem);
-    }
-}
-
-/*
- * Resource setup
- */
-static void vfio_mmap_set_enabled(VFIODevice *vdev, bool enabled)
-{
-    int i;
-
-    for (i = 0; i < PCI_ROM_SLOT; i++) {
-        VFIOBAR *bar = &vdev->bars[i];
-
-        if (!bar->size) {
-            continue;
-        }
-
-        memory_region_set_enabled(&bar->mmap_mem, enabled);
-        if (vdev->msix && vdev->msix->table_bar == i) {
-            memory_region_set_enabled(&vdev->msix->mmap_mem, enabled);
-        }
-    }
-}
-
-static void vfio_unmap_bar(VFIODevice *vdev, int nr)
-{
-    VFIOBAR *bar = &vdev->bars[nr];
-
-    if (!bar->size) {
-        return;
-    }
-
-    vfio_bar_quirk_teardown(vdev, nr);
-
-    memory_region_del_subregion(&bar->mem, &bar->mmap_mem);
-    munmap(bar->mmap, memory_region_size(&bar->mmap_mem));
-
-    if (vdev->msix && vdev->msix->table_bar == nr) {
-        memory_region_del_subregion(&bar->mem, &vdev->msix->mmap_mem);
-        munmap(vdev->msix->mmap, memory_region_size(&vdev->msix->mmap_mem));
-    }
-
-    memory_region_destroy(&bar->mem);
-}
-
-static int vfio_mmap_bar(VFIOBAR *bar, MemoryRegion *mem, MemoryRegion *submem,
-                         void **map, size_t size, off_t offset,
-                         const char *name)
-{
-    int ret = 0;
-
-    if (VFIO_ALLOW_MMAP && size && bar->flags & VFIO_REGION_INFO_FLAG_MMAP) {
-        int prot = 0;
-
-        if (bar->flags & VFIO_REGION_INFO_FLAG_READ) {
-            prot |= PROT_READ;
-        }
-
-        if (bar->flags & VFIO_REGION_INFO_FLAG_WRITE) {
-            prot |= PROT_WRITE;
-        }
-
-        *map = mmap(NULL, size, prot, MAP_SHARED,
-                    bar->fd, bar->fd_offset + offset);
-        if (*map == MAP_FAILED) {
-            *map = NULL;
-            ret = -errno;
-            goto empty_region;
-        }
-
-        memory_region_init_ram_ptr(submem, name, size, *map);
-    } else {
-empty_region:
-        /* Create a zero sized sub-region to make cleanup easy. */
-        memory_region_init(submem, name, 0);
-    }
-
-    memory_region_add_subregion(mem, offset, submem);
-
-    return ret;
-}
-
-static void vfio_map_bar(VFIODevice *vdev, int nr)
-{
-    VFIOBAR *bar = &vdev->bars[nr];
-    unsigned size = bar->size;
-    char name[64];
-    uint32_t pci_bar;
-    uint8_t type;
-    int ret;
-
-    /* Skip both unimplemented BARs and the upper half of 64bit BARS. */
-    if (!size) {
-        return;
-    }
-
-    snprintf(name, sizeof(name), "VFIO %04x:%02x:%02x.%x BAR %d",
-             vdev->host.domain, vdev->host.bus, vdev->host.slot,
-             vdev->host.function, nr);
-
-    /* Determine what type of BAR this is for registration */
-    ret = pread(vdev->fd, &pci_bar, sizeof(pci_bar),
-                vdev->config_offset + PCI_BASE_ADDRESS_0 + (4 * nr));
-    if (ret != sizeof(pci_bar)) {
-        error_report("vfio: Failed to read BAR %d (%m)", nr);
-        return;
-    }
-
-    pci_bar = le32_to_cpu(pci_bar);
-    type = pci_bar & (pci_bar & PCI_BASE_ADDRESS_SPACE_IO ?
-           ~PCI_BASE_ADDRESS_IO_MASK : ~PCI_BASE_ADDRESS_MEM_MASK);
-
-    /* A "slow" read/write mapping underlies all BARs */
-    memory_region_init_io(&bar->mem, &vfio_bar_ops, bar, name, size);
-    pci_register_bar(&vdev->pdev, nr, type, &bar->mem);
-
-    /*
-     * We can't mmap areas overlapping the MSIX vector table, so we
-     * potentially insert a direct-mapped subregion before and after it.
-     */
-    if (vdev->msix && vdev->msix->table_bar == nr) {
-        size = vdev->msix->table_offset & TARGET_PAGE_MASK;
-    }
-
-    strncat(name, " mmap", sizeof(name) - strlen(name) - 1);
-    if (vfio_mmap_bar(bar, &bar->mem,
-                      &bar->mmap_mem, &bar->mmap, size, 0, name)) {
-        error_report("%s unsupported. Performance may be slow", name);
-    }
-
-    if (vdev->msix && vdev->msix->table_bar == nr) {
-        unsigned start;
-
-        start = TARGET_PAGE_ALIGN(vdev->msix->table_offset +
-                                  (vdev->msix->entries * PCI_MSIX_ENTRY_SIZE));
-
-        size = start < bar->size ? bar->size - start : 0;
-        strncat(name, " msix-hi", sizeof(name) - strlen(name) - 1);
-        /* VFIOMSIXInfo contains another MemoryRegion for this mapping */
-        if (vfio_mmap_bar(bar, &bar->mem, &vdev->msix->mmap_mem,
-                          &vdev->msix->mmap, size, start, name)) {
-            error_report("%s unsupported. Performance may be slow", name);
-        }
-    }
-
-    vfio_bar_quirk_setup(vdev, nr);
-}
-
-static void vfio_map_bars(VFIODevice *vdev)
-{
-    int i;
-
-    for (i = 0; i < PCI_ROM_SLOT; i++) {
-        vfio_map_bar(vdev, i);
-    }
-
-    if (vdev->has_vga) {
-        memory_region_init_io(&vdev->vga.region[QEMU_PCI_VGA_MEM].mem,
-                              &vfio_vga_ops,
-                              &vdev->vga.region[QEMU_PCI_VGA_MEM],
-                              "vfio-vga-mmio@0xa0000",
-                              QEMU_PCI_VGA_MEM_SIZE);
-        memory_region_init_io(&vdev->vga.region[QEMU_PCI_VGA_IO_LO].mem,
-                              &vfio_vga_ops,
-                              &vdev->vga.region[QEMU_PCI_VGA_IO_LO],
-                              "vfio-vga-io@0x3b0",
-                              QEMU_PCI_VGA_IO_LO_SIZE);
-        memory_region_init_io(&vdev->vga.region[QEMU_PCI_VGA_IO_HI].mem,
-                              &vfio_vga_ops,
-                              &vdev->vga.region[QEMU_PCI_VGA_IO_HI],
-                              "vfio-vga-io@0x3c0",
-                              QEMU_PCI_VGA_IO_HI_SIZE);
-
-        pci_register_vga(&vdev->pdev, &vdev->vga.region[QEMU_PCI_VGA_MEM].mem,
-                         &vdev->vga.region[QEMU_PCI_VGA_IO_LO].mem,
-                         &vdev->vga.region[QEMU_PCI_VGA_IO_HI].mem);
-        vfio_vga_quirk_setup(vdev);
-    }
-}
-
-static void vfio_unmap_bars(VFIODevice *vdev)
-{
-    int i;
-
-    for (i = 0; i < PCI_ROM_SLOT; i++) {
-        vfio_unmap_bar(vdev, i);
-    }
-
-    if (vdev->has_vga) {
-        vfio_vga_quirk_teardown(vdev);
-        pci_unregister_vga(&vdev->pdev);
-        memory_region_destroy(&vdev->vga.region[QEMU_PCI_VGA_MEM].mem);
-        memory_region_destroy(&vdev->vga.region[QEMU_PCI_VGA_IO_LO].mem);
-        memory_region_destroy(&vdev->vga.region[QEMU_PCI_VGA_IO_HI].mem);
-    }
-}
-
-/*
- * General setup
- */
-static uint8_t vfio_std_cap_max_size(PCIDevice *pdev, uint8_t pos)
-{
-    uint8_t tmp, next = 0xff;
-
-    for (tmp = pdev->config[PCI_CAPABILITY_LIST]; tmp;
-         tmp = pdev->config[tmp + 1]) {
-        if (tmp > pos && tmp < next) {
-            next = tmp;
-        }
-    }
-
-    return next - pos;
-}
-
-static void vfio_set_word_bits(uint8_t *buf, uint16_t val, uint16_t mask)
-{
-    pci_set_word(buf, (pci_get_word(buf) & ~mask) | val);
-}
-
-static void vfio_add_emulated_word(VFIODevice *vdev, int pos,
-                                   uint16_t val, uint16_t mask)
-{
-    vfio_set_word_bits(vdev->pdev.config + pos, val, mask);
-    vfio_set_word_bits(vdev->pdev.wmask + pos, ~mask, mask);
-    vfio_set_word_bits(vdev->emulated_config_bits + pos, mask, mask);
-}
-
-static void vfio_set_long_bits(uint8_t *buf, uint32_t val, uint32_t mask)
-{
-    pci_set_long(buf, (pci_get_long(buf) & ~mask) | val);
-}
-
-static void vfio_add_emulated_long(VFIODevice *vdev, int pos,
-                                   uint32_t val, uint32_t mask)
-{
-    vfio_set_long_bits(vdev->pdev.config + pos, val, mask);
-    vfio_set_long_bits(vdev->pdev.wmask + pos, ~mask, mask);
-    vfio_set_long_bits(vdev->emulated_config_bits + pos, mask, mask);
-}
-
-static int vfio_setup_pcie_cap(VFIODevice *vdev, int pos, uint8_t size)
-{
-    uint16_t flags;
-    uint8_t type;
-
-    flags = pci_get_word(vdev->pdev.config + pos + PCI_CAP_FLAGS);
-    type = (flags & PCI_EXP_FLAGS_TYPE) >> 4;
-
-    if (type != PCI_EXP_TYPE_ENDPOINT &&
-        type != PCI_EXP_TYPE_LEG_END &&
-        type != PCI_EXP_TYPE_RC_END) {
-
-        error_report("vfio: Assignment of PCIe type 0x%x "
-                     "devices is not currently supported", type);
-        return -EINVAL;
-    }
-
-    if (!pci_bus_is_express(vdev->pdev.bus)) {
-        /*
-         * Use express capability as-is on PCI bus.  It doesn't make much
-         * sense to even expose, but some drivers (ex. tg3) depend on it
-         * and guests don't seem to be particular about it.  We'll need
-         * to revist this or force express devices to express buses if we
-         * ever expose an IOMMU to the guest.
-         */
-    } else if (pci_bus_is_root(vdev->pdev.bus)) {
-        /*
-         * On a Root Complex bus Endpoints become Root Complex Integrated
-         * Endpoints, which changes the type and clears the LNK & LNK2 fields.
-         */
-        if (type == PCI_EXP_TYPE_ENDPOINT) {
-            vfio_add_emulated_word(vdev, pos + PCI_CAP_FLAGS,
-                                   PCI_EXP_TYPE_RC_END << 4,
-                                   PCI_EXP_FLAGS_TYPE);
-
-            /* Link Capabilities, Status, and Control goes away */
-            if (size > PCI_EXP_LNKCTL) {
-                vfio_add_emulated_long(vdev, pos + PCI_EXP_LNKCAP, 0, ~0);
-                vfio_add_emulated_word(vdev, pos + PCI_EXP_LNKCTL, 0, ~0);
-                vfio_add_emulated_word(vdev, pos + PCI_EXP_LNKSTA, 0, ~0);
-
-#ifndef PCI_EXP_LNKCAP2
-#define PCI_EXP_LNKCAP2 44
-#endif
-#ifndef PCI_EXP_LNKSTA2
-#define PCI_EXP_LNKSTA2 50
-#endif
-                /* Link 2 Capabilities, Status, and Control goes away */
-                if (size > PCI_EXP_LNKCAP2) {
-                    vfio_add_emulated_long(vdev, pos + PCI_EXP_LNKCAP2, 0, ~0);
-                    vfio_add_emulated_word(vdev, pos + PCI_EXP_LNKCTL2, 0, ~0);
-                    vfio_add_emulated_word(vdev, pos + PCI_EXP_LNKSTA2, 0, ~0);
-                }
-            }
-
-        } else if (type == PCI_EXP_TYPE_LEG_END) {
-            /*
-             * Legacy endpoints don't belong on the root complex.  Windows
-             * seems to be happier with devices if we skip the capability.
-             */
-            return 0;
-        }
-
-    } else {
-        /*
-         * Convert Root Complex Integrated Endpoints to regular endpoints.
-         * These devices don't support LNK/LNK2 capabilities, so make them up.
-         */
-        if (type == PCI_EXP_TYPE_RC_END) {
-            vfio_add_emulated_word(vdev, pos + PCI_CAP_FLAGS,
-                                   PCI_EXP_TYPE_ENDPOINT << 4,
-                                   PCI_EXP_FLAGS_TYPE);
-            vfio_add_emulated_long(vdev, pos + PCI_EXP_LNKCAP,
-                                   PCI_EXP_LNK_MLW_1 | PCI_EXP_LNK_LS_25, ~0);
-            vfio_add_emulated_word(vdev, pos + PCI_EXP_LNKCTL, 0, ~0);
-        }
-
-        /* Mark the Link Status bits as emulated to allow virtual negotiation */
-        vfio_add_emulated_word(vdev, pos + PCI_EXP_LNKSTA,
-                               pci_get_word(vdev->pdev.config + pos +
-                                            PCI_EXP_LNKSTA),
-                               PCI_EXP_LNKCAP_MLW | PCI_EXP_LNKCAP_SLS);
-    }
-
-    pos = pci_add_capability(&vdev->pdev, PCI_CAP_ID_EXP, pos, size);
-    if (pos >= 0) {
-        vdev->pdev.exp.exp_cap = pos;
-    }
-
-    return pos;
-}
-
-static int vfio_add_std_cap(VFIODevice *vdev, uint8_t pos)
-{
-    PCIDevice *pdev = &vdev->pdev;
-    uint8_t cap_id, next, size;
-    int ret;
-
-    cap_id = pdev->config[pos];
-    next = pdev->config[pos + 1];
-
-    /*
-     * If it becomes important to configure capabilities to their actual
-     * size, use this as the default when it's something we don't recognize.
-     * Since QEMU doesn't actually handle many of the config accesses,
-     * exact size doesn't seem worthwhile.
-     */
-    size = vfio_std_cap_max_size(pdev, pos);
-
-    /*
-     * pci_add_capability always inserts the new capability at the head
-     * of the chain.  Therefore to end up with a chain that matches the
-     * physical device, we insert from the end by making this recursive.
-     * This is also why we pre-caclulate size above as cached config space
-     * will be changed as we unwind the stack.
-     */
-    if (next) {
-        ret = vfio_add_std_cap(vdev, next);
-        if (ret) {
-            return ret;
-        }
-    } else {
-        /* Begin the rebuild, use QEMU emulated list bits */
-        pdev->config[PCI_CAPABILITY_LIST] = 0;
-        vdev->emulated_config_bits[PCI_CAPABILITY_LIST] = 0xff;
-        vdev->emulated_config_bits[PCI_STATUS] |= PCI_STATUS_CAP_LIST;
-    }
-
-    /* Use emulated next pointer to allow dropping caps */
-    pci_set_byte(vdev->emulated_config_bits + pos + 1, 0xff);
-
-    switch (cap_id) {
-    case PCI_CAP_ID_MSI:
-        ret = vfio_setup_msi(vdev, pos);
-        break;
-    case PCI_CAP_ID_EXP:
-        ret = vfio_setup_pcie_cap(vdev, pos, size);
-        break;
-    case PCI_CAP_ID_MSIX:
-        ret = vfio_setup_msix(vdev, pos);
-        break;
-    case PCI_CAP_ID_PM:
-        vdev->pm_cap = pos;
-    default:
-        ret = pci_add_capability(pdev, cap_id, pos, size);
-        break;
-    }
-
-    if (ret < 0) {
-        error_report("vfio: %04x:%02x:%02x.%x Error adding PCI capability "
-                     "0x%x[0x%x]@0x%x: %d", vdev->host.domain,
-                     vdev->host.bus, vdev->host.slot, vdev->host.function,
-                     cap_id, size, pos, ret);
-        return ret;
-    }
-
-    return 0;
-}
-
-static int vfio_add_capabilities(VFIODevice *vdev)
-{
-    PCIDevice *pdev = &vdev->pdev;
-
-    if (!(pdev->config[PCI_STATUS] & PCI_STATUS_CAP_LIST) ||
-        !pdev->config[PCI_CAPABILITY_LIST]) {
-        return 0; /* Nothing to add */
-    }
-
-    return vfio_add_std_cap(vdev, pdev->config[PCI_CAPABILITY_LIST]);
-}
-
-static int vfio_load_rom(VFIODevice *vdev)
-{
-    uint64_t size = vdev->rom_size;
-    char name[32];
-    off_t off = 0, voff = vdev->rom_offset;
-    ssize_t bytes;
-    void *ptr;
-
-    /* If loading ROM from file, pci handles it */
-    if (vdev->pdev.romfile || !vdev->pdev.rom_bar || !size) {
-        return 0;
-    }
-
-    DPRINTF("%s(%04x:%02x:%02x.%x)\n", __func__, vdev->host.domain,
-            vdev->host.bus, vdev->host.slot, vdev->host.function);
-
-    snprintf(name, sizeof(name), "vfio[%04x:%02x:%02x.%x].rom",
-             vdev->host.domain, vdev->host.bus, vdev->host.slot,
-             vdev->host.function);
-    memory_region_init_ram(&vdev->pdev.rom, name, size);
-    ptr = memory_region_get_ram_ptr(&vdev->pdev.rom);
-    memset(ptr, 0xff, size);
-
-    while (size) {
-        bytes = pread(vdev->fd, ptr + off, size, voff + off);
-        if (bytes == 0) {
-            break; /* expect that we could get back less than the ROM BAR */
-        } else if (bytes > 0) {
-            off += bytes;
-            size -= bytes;
-        } else {
-            if (errno == EINTR || errno == EAGAIN) {
-                continue;
-            }
-            error_report("vfio: Error reading device ROM: %m");
-            memory_region_destroy(&vdev->pdev.rom);
-            return -errno;
-        }
-    }
-
-    pci_register_bar(&vdev->pdev, PCI_ROM_SLOT, 0, &vdev->pdev.rom);
-    vdev->pdev.has_rom = true;
-    return 0;
-}
-
-static int vfio_connect_container(VFIOGroup *group)
-{
-    VFIOContainer *container;
-    int ret, fd;
-
-    if (group->container) {
-        return 0;
-    }
-
-    QLIST_FOREACH(container, &container_list, next) {
-        if (!ioctl(group->fd, VFIO_GROUP_SET_CONTAINER, &container->fd)) {
-            group->container = container;
-            QLIST_INSERT_HEAD(&container->group_list, group, container_next);
-            return 0;
-        }
-    }
-
-    fd = qemu_open("/dev/vfio/vfio", O_RDWR);
-    if (fd < 0) {
-        error_report("vfio: failed to open /dev/vfio/vfio: %m");
-        return -errno;
-    }
-
-    ret = ioctl(fd, VFIO_GET_API_VERSION);
-    if (ret != VFIO_API_VERSION) {
-        error_report("vfio: supported vfio version: %d, "
-                     "reported version: %d", VFIO_API_VERSION, ret);
-        close(fd);
-        return -EINVAL;
-    }
-
-    container = g_malloc0(sizeof(*container));
-    container->fd = fd;
-
-    if (ioctl(fd, VFIO_CHECK_EXTENSION, VFIO_TYPE1_IOMMU)) {
-        ret = ioctl(group->fd, VFIO_GROUP_SET_CONTAINER, &fd);
-        if (ret) {
-            error_report("vfio: failed to set group container: %m");
-            g_free(container);
-            close(fd);
-            return -errno;
-        }
-
-        ret = ioctl(fd, VFIO_SET_IOMMU, VFIO_TYPE1_IOMMU);
-        if (ret) {
-            error_report("vfio: failed to set iommu for container: %m");
-            g_free(container);
-            close(fd);
-            return -errno;
-        }
-
-        container->iommu_data.listener = vfio_memory_listener;
-        container->iommu_data.release = vfio_listener_release;
-
-        memory_listener_register(&container->iommu_data.listener, &address_space_memory);
-    } else {
-        error_report("vfio: No available IOMMU models");
-        g_free(container);
-        close(fd);
-        return -EINVAL;
-    }
-
-    QLIST_INIT(&container->group_list);
-    QLIST_INSERT_HEAD(&container_list, container, next);
-
-    group->container = container;
-    QLIST_INSERT_HEAD(&container->group_list, group, container_next);
-
-    return 0;
-}
-
-static void vfio_disconnect_container(VFIOGroup *group)
-{
-    VFIOContainer *container = group->container;
-
-    if (ioctl(group->fd, VFIO_GROUP_UNSET_CONTAINER, &container->fd)) {
-        error_report("vfio: error disconnecting group %d from container",
-                     group->groupid);
-    }
-
-    QLIST_REMOVE(group, container_next);
-    group->container = NULL;
-
-    if (QLIST_EMPTY(&container->group_list)) {
-        if (container->iommu_data.release) {
-            container->iommu_data.release(container);
-        }
-        QLIST_REMOVE(container, next);
-        DPRINTF("vfio_disconnect_container: close container->fd\n");
-        close(container->fd);
-        g_free(container);
-    }
-}
-
-static VFIOGroup *vfio_get_group(int groupid)
-{
-    VFIOGroup *group;
-    char path[32];
-    struct vfio_group_status status = { .argsz = sizeof(status) };
-
-    QLIST_FOREACH(group, &group_list, next) {
-        if (group->groupid == groupid) {
-            return group;
-        }
-    }
-
-    group = g_malloc0(sizeof(*group));
-
-    snprintf(path, sizeof(path), "/dev/vfio/%d", groupid);
-    group->fd = qemu_open(path, O_RDWR);
-    if (group->fd < 0) {
-        error_report("vfio: error opening %s: %m", path);
-        g_free(group);
-        return NULL;
-    }
-
-    if (ioctl(group->fd, VFIO_GROUP_GET_STATUS, &status)) {
-        error_report("vfio: error getting group status: %m");
-        close(group->fd);
-        g_free(group);
-        return NULL;
-    }
-
-    if (!(status.flags & VFIO_GROUP_FLAGS_VIABLE)) {
-        error_report("vfio: error, group %d is not viable, please ensure "
-                     "all devices within the iommu_group are bound to their "
-                     "vfio bus driver.", groupid);
-        close(group->fd);
-        g_free(group);
-        return NULL;
-    }
-
-    group->groupid = groupid;
-    QLIST_INIT(&group->device_list);
-
-    if (vfio_connect_container(group)) {
-        error_report("vfio: failed to setup container for group %d", groupid);
-        close(group->fd);
-        g_free(group);
-        return NULL;
-    }
-
-    QLIST_INSERT_HEAD(&group_list, group, next);
-
-    return group;
-}
-
-static void vfio_put_group(VFIOGroup *group)
-{
-    if (!QLIST_EMPTY(&group->device_list)) {
-        return;
-    }
-
-    vfio_disconnect_container(group);
-    QLIST_REMOVE(group, next);
-    DPRINTF("vfio_put_group: close group->fd\n");
-    close(group->fd);
-    g_free(group);
-}
-
-static int vfio_get_device(VFIOGroup *group, const char *name, VFIODevice *vdev)
-{
-    struct vfio_device_info dev_info = { .argsz = sizeof(dev_info) };
-    struct vfio_region_info reg_info = { .argsz = sizeof(reg_info) };
-    int ret, i;
-
-    ret = ioctl(group->fd, VFIO_GROUP_GET_DEVICE_FD, name);
-    if (ret < 0) {
-        error_report("vfio: error getting device %s from group %d: %m",
-                     name, group->groupid);
-        error_printf("Verify all devices in group %d are bound to vfio-pci "
-                     "or pci-stub and not already in use\n", group->groupid);
-        return ret;
-    }
-
-    vdev->fd = ret;
-    vdev->group = group;
-    QLIST_INSERT_HEAD(&group->device_list, vdev, next);
-
-    /* Sanity check device */
-    ret = ioctl(vdev->fd, VFIO_DEVICE_GET_INFO, &dev_info);
-    if (ret) {
-        error_report("vfio: error getting device info: %m");
-        goto error;
-    }
-
-    DPRINTF("Device %s flags: %u, regions: %u, irgs: %u\n", name,
-            dev_info.flags, dev_info.num_regions, dev_info.num_irqs);
-
-    if (!(dev_info.flags & VFIO_DEVICE_FLAGS_PCI)) {
-        error_report("vfio: Um, this isn't a PCI device");
-        goto error;
-    }
-
-    vdev->reset_works = !!(dev_info.flags & VFIO_DEVICE_FLAGS_RESET);
-    if (!vdev->reset_works) {
-        error_report("Warning, device %s does not support reset", name);
-    }
-
-    if (dev_info.num_regions < VFIO_PCI_CONFIG_REGION_INDEX + 1) {
-        error_report("vfio: unexpected number of io regions %u",
-                     dev_info.num_regions);
-        goto error;
-    }
-
-    if (dev_info.num_irqs < VFIO_PCI_MSIX_IRQ_INDEX + 1) {
-        error_report("vfio: unexpected number of irqs %u", dev_info.num_irqs);
-        goto error;
-    }
-
-    for (i = VFIO_PCI_BAR0_REGION_INDEX; i < VFIO_PCI_ROM_REGION_INDEX; i++) {
-        reg_info.index = i;
-
-        ret = ioctl(vdev->fd, VFIO_DEVICE_GET_REGION_INFO, &reg_info);
-        if (ret) {
-            error_report("vfio: Error getting region %d info: %m", i);
-            goto error;
-        }
-
-        DPRINTF("Device %s region %d:\n", name, i);
-        DPRINTF("  size: 0x%lx, offset: 0x%lx, flags: 0x%lx\n",
-                (unsigned long)reg_info.size, (unsigned long)reg_info.offset,
-                (unsigned long)reg_info.flags);
-
-        vdev->bars[i].flags = reg_info.flags;
-        vdev->bars[i].size = reg_info.size;
-        vdev->bars[i].fd_offset = reg_info.offset;
-        vdev->bars[i].fd = vdev->fd;
-        vdev->bars[i].nr = i;
-        QLIST_INIT(&vdev->bars[i].quirks);
-    }
-
-    reg_info.index = VFIO_PCI_ROM_REGION_INDEX;
-
-    ret = ioctl(vdev->fd, VFIO_DEVICE_GET_REGION_INFO, &reg_info);
-    if (ret) {
-        error_report("vfio: Error getting ROM info: %m");
-        goto error;
-    }
-
-    DPRINTF("Device %s ROM:\n", name);
-    DPRINTF("  size: 0x%lx, offset: 0x%lx, flags: 0x%lx\n",
-            (unsigned long)reg_info.size, (unsigned long)reg_info.offset,
-            (unsigned long)reg_info.flags);
-
-    vdev->rom_size = reg_info.size;
-    vdev->rom_offset = reg_info.offset;
-
-    reg_info.index = VFIO_PCI_CONFIG_REGION_INDEX;
-
-    ret = ioctl(vdev->fd, VFIO_DEVICE_GET_REGION_INFO, &reg_info);
-    if (ret) {
-        error_report("vfio: Error getting config info: %m");
-        goto error;
-    }
-
-    DPRINTF("Device %s config:\n", name);
-    DPRINTF("  size: 0x%lx, offset: 0x%lx, flags: 0x%lx\n",
-            (unsigned long)reg_info.size, (unsigned long)reg_info.offset,
-            (unsigned long)reg_info.flags);
-
-    vdev->config_size = reg_info.size;
-    if (vdev->config_size == PCI_CONFIG_SPACE_SIZE) {
-        vdev->pdev.cap_present &= ~QEMU_PCI_CAP_EXPRESS;
-    }
-    vdev->config_offset = reg_info.offset;
-
-    if ((vdev->features & VFIO_FEATURE_ENABLE_VGA) &&
-        dev_info.num_regions > VFIO_PCI_VGA_REGION_INDEX) {
-        struct vfio_region_info vga_info = {
-            .argsz = sizeof(vga_info),
-            .index = VFIO_PCI_VGA_REGION_INDEX,
-         };
-
-        ret = ioctl(vdev->fd, VFIO_DEVICE_GET_REGION_INFO, &vga_info);
-        if (ret) {
-            error_report(
-                "vfio: Device does not support requested feature x-vga");
-            goto error;
-        }
-
-        if (!(vga_info.flags & VFIO_REGION_INFO_FLAG_READ) ||
-            !(vga_info.flags & VFIO_REGION_INFO_FLAG_WRITE) ||
-            vga_info.size < 0xbffff + 1) {
-            error_report("vfio: Unexpected VGA info, flags 0x%lx, size 0x%lx",
-                         (unsigned long)vga_info.flags,
-                         (unsigned long)vga_info.size);
-            goto error;
-        }
-
-        vdev->vga.fd_offset = vga_info.offset;
-        vdev->vga.fd = vdev->fd;
-
-        vdev->vga.region[QEMU_PCI_VGA_MEM].offset = QEMU_PCI_VGA_MEM_BASE;
-        vdev->vga.region[QEMU_PCI_VGA_MEM].nr = QEMU_PCI_VGA_MEM;
-        QLIST_INIT(&vdev->vga.region[QEMU_PCI_VGA_MEM].quirks);
-
-        vdev->vga.region[QEMU_PCI_VGA_IO_LO].offset = QEMU_PCI_VGA_IO_LO_BASE;
-        vdev->vga.region[QEMU_PCI_VGA_IO_LO].nr = QEMU_PCI_VGA_IO_LO;
-        QLIST_INIT(&vdev->vga.region[QEMU_PCI_VGA_IO_LO].quirks);
-
-        vdev->vga.region[QEMU_PCI_VGA_IO_HI].offset = QEMU_PCI_VGA_IO_HI_BASE;
-        vdev->vga.region[QEMU_PCI_VGA_IO_HI].nr = QEMU_PCI_VGA_IO_HI;
-        QLIST_INIT(&vdev->vga.region[QEMU_PCI_VGA_IO_HI].quirks);
-
-        vdev->has_vga = true;
-    }
-
-error:
-    if (ret) {
-        QLIST_REMOVE(vdev, next);
-        vdev->group = NULL;
-        close(vdev->fd);
-    }
-    return ret;
-}
-
-static void vfio_put_device(VFIODevice *vdev)
-{
-    QLIST_REMOVE(vdev, next);
-    vdev->group = NULL;
-    DPRINTF("vfio_put_device: close vdev->fd\n");
-    close(vdev->fd);
-    if (vdev->msix) {
-        g_free(vdev->msix);
-        vdev->msix = NULL;
-    }
-}
-
-static int vfio_initfn(PCIDevice *pdev)
-{
-    VFIODevice *pvdev, *vdev = DO_UPCAST(VFIODevice, pdev, pdev);
-    VFIOGroup *group;
-    char path[PATH_MAX], iommu_group_path[PATH_MAX], *group_name;
-    ssize_t len;
-    struct stat st;
-    int groupid;
-    int ret;
-
-    /* Check that the host device exists */
-    snprintf(path, sizeof(path),
-             "/sys/bus/pci/devices/%04x:%02x:%02x.%01x/",
-             vdev->host.domain, vdev->host.bus, vdev->host.slot,
-             vdev->host.function);
-    if (stat(path, &st) < 0) {
-        error_report("vfio: error: no such host device: %s", path);
-        return -errno;
-    }
-
-    strncat(path, "iommu_group", sizeof(path) - strlen(path) - 1);
-
-    len = readlink(path, iommu_group_path, PATH_MAX);
-    if (len <= 0) {
-        error_report("vfio: error no iommu_group for device");
-        return -errno;
-    }
-
-    iommu_group_path[len] = 0;
-    group_name = basename(iommu_group_path);
-
-    if (sscanf(group_name, "%d", &groupid) != 1) {
-        error_report("vfio: error reading %s: %m", path);
-        return -errno;
-    }
-
-    DPRINTF("%s(%04x:%02x:%02x.%x) group %d\n", __func__, vdev->host.domain,
-            vdev->host.bus, vdev->host.slot, vdev->host.function, groupid);
-
-    group = vfio_get_group(groupid);
-    if (!group) {
-        error_report("vfio: failed to get group %d", groupid);
-        return -ENOENT;
-    }
-
-    snprintf(path, sizeof(path), "%04x:%02x:%02x.%01x",
-            vdev->host.domain, vdev->host.bus, vdev->host.slot,
-            vdev->host.function);
-
-    QLIST_FOREACH(pvdev, &group->device_list, next) {
-        if (pvdev->host.domain == vdev->host.domain &&
-            pvdev->host.bus == vdev->host.bus &&
-            pvdev->host.slot == vdev->host.slot &&
-            pvdev->host.function == vdev->host.function) {
-
-            error_report("vfio: error: device %s is already attached", path);
-            vfio_put_group(group);
-            return -EBUSY;
-        }
-    }
-
-    ret = vfio_get_device(group, path, vdev);
-    if (ret) {
-        error_report("vfio: failed to get device %s", path);
-        vfio_put_group(group);
-        return ret;
-    }
-
-    /* Get a copy of config space */
-    ret = pread(vdev->fd, vdev->pdev.config,
-                MIN(pci_config_size(&vdev->pdev), vdev->config_size),
-                vdev->config_offset);
-    if (ret < (int)MIN(pci_config_size(&vdev->pdev), vdev->config_size)) {
-        ret = ret < 0 ? -errno : -EFAULT;
-        error_report("vfio: Failed to read device config space");
-        goto out_put;
-    }
-
-    /* vfio emulates a lot for us, but some bits need extra love */
-    vdev->emulated_config_bits = g_malloc0(vdev->config_size);
-
-    /* QEMU can choose to expose the ROM or not */
-    memset(vdev->emulated_config_bits + PCI_ROM_ADDRESS, 0xff, 4);
-
-    /* QEMU can change multi-function devices to single function, or reverse */
-    vdev->emulated_config_bits[PCI_HEADER_TYPE] =
-                                              PCI_HEADER_TYPE_MULTI_FUNCTION;
-
-    /*
-     * Clear host resource mapping info.  If we choose not to register a
-     * BAR, such as might be the case with the option ROM, we can get
-     * confusing, unwritable, residual addresses from the host here.
-     */
-    memset(&vdev->pdev.config[PCI_BASE_ADDRESS_0], 0, 24);
-    memset(&vdev->pdev.config[PCI_ROM_ADDRESS], 0, 4);
-
-    vfio_load_rom(vdev);
-
-    ret = vfio_early_setup_msix(vdev);
-    if (ret) {
-        goto out_put;
-    }
-
-    vfio_map_bars(vdev);
-
-    ret = vfio_add_capabilities(vdev);
-    if (ret) {
-        goto out_teardown;
-    }
-
-    /* QEMU emulates all of MSI & MSIX */
-    if (pdev->cap_present & QEMU_PCI_CAP_MSIX) {
-        memset(vdev->emulated_config_bits + pdev->msix_cap, 0xff,
-               MSIX_CAP_LENGTH);
-    }
-
-    if (pdev->cap_present & QEMU_PCI_CAP_MSI) {
-        memset(vdev->emulated_config_bits + pdev->msi_cap, 0xff,
-               vdev->msi_cap_size);
-    }
-
-    if (vfio_pci_read_config(&vdev->pdev, PCI_INTERRUPT_PIN, 1)) {
-        vdev->intx.mmap_timer = qemu_new_timer_ms(vm_clock,
-                                                  vfio_intx_mmap_enable, vdev);
-        pci_device_set_intx_routing_notifier(&vdev->pdev, vfio_update_irq);
-        ret = vfio_enable_intx(vdev);
-        if (ret) {
-            goto out_teardown;
-        }
-    }
-
-    add_boot_device_path(vdev->bootindex, &pdev->qdev, NULL);
-
-    return 0;
-
-out_teardown:
-    pci_device_set_intx_routing_notifier(&vdev->pdev, NULL);
-    vfio_teardown_msi(vdev);
-    vfio_unmap_bars(vdev);
-out_put:
-    g_free(vdev->emulated_config_bits);
-    vfio_put_device(vdev);
-    vfio_put_group(group);
-    return ret;
-}
-
-static void vfio_exitfn(PCIDevice *pdev)
-{
-    VFIODevice *vdev = DO_UPCAST(VFIODevice, pdev, pdev);
-    VFIOGroup *group = vdev->group;
-
-    pci_device_set_intx_routing_notifier(&vdev->pdev, NULL);
-    vfio_disable_interrupts(vdev);
-    if (vdev->intx.mmap_timer) {
-        qemu_free_timer(vdev->intx.mmap_timer);
-    }
-    vfio_teardown_msi(vdev);
-    vfio_unmap_bars(vdev);
-    g_free(vdev->emulated_config_bits);
-    vfio_put_device(vdev);
-    vfio_put_group(group);
-}
-
-static void vfio_pci_reset(DeviceState *dev)
-{
-    PCIDevice *pdev = DO_UPCAST(PCIDevice, qdev, dev);
-    VFIODevice *vdev = DO_UPCAST(VFIODevice, pdev, pdev);
-    uint16_t cmd;
-
-    DPRINTF("%s(%04x:%02x:%02x.%x)\n", __func__, vdev->host.domain,
-            vdev->host.bus, vdev->host.slot, vdev->host.function);
-
-    vfio_disable_interrupts(vdev);
-
-    /* Make sure the device is in D0 */
-    if (vdev->pm_cap) {
-        uint16_t pmcsr;
-        uint8_t state;
-
-        pmcsr = vfio_pci_read_config(pdev, vdev->pm_cap + PCI_PM_CTRL, 2);
-        state = pmcsr & PCI_PM_CTRL_STATE_MASK;
-        if (state) {
-            pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
-            vfio_pci_write_config(pdev, vdev->pm_cap + PCI_PM_CTRL, pmcsr, 2);
-            /* vfio handles the necessary delay here */
-            pmcsr = vfio_pci_read_config(pdev, vdev->pm_cap + PCI_PM_CTRL, 2);
-            state = pmcsr & PCI_PM_CTRL_STATE_MASK;
-            if (state) {
-                error_report("vfio: Unable to power on device, stuck in D%d\n",
-                             state);
-            }
-        }
-    }
-
-    /*
-     * Stop any ongoing DMA by disconecting I/O, MMIO, and bus master.
-     * Also put INTx Disable in known state.
-     */
-    cmd = vfio_pci_read_config(pdev, PCI_COMMAND, 2);
-    cmd &= ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
-             PCI_COMMAND_INTX_DISABLE);
-    vfio_pci_write_config(pdev, PCI_COMMAND, cmd, 2);
-
-    if (vdev->reset_works) {
-        if (ioctl(vdev->fd, VFIO_DEVICE_RESET)) {
-            error_report("vfio: Error unable to reset physical device "
-                         "(%04x:%02x:%02x.%x): %m", vdev->host.domain,
-                         vdev->host.bus, vdev->host.slot, vdev->host.function);
-        }
-    }
-
-    vfio_enable_intx(vdev);
-}
-
-static Property vfio_pci_dev_properties[] = {
-    DEFINE_PROP_PCI_HOST_DEVADDR("host", VFIODevice, host),
-    DEFINE_PROP_UINT32("x-intx-mmap-timeout-ms", VFIODevice,
-                       intx.mmap_timeout, 1100),
-    DEFINE_PROP_BIT("x-vga", VFIODevice, features,
-                    VFIO_FEATURE_ENABLE_VGA_BIT, false),
-    DEFINE_PROP_INT32("bootindex", VFIODevice, bootindex, -1),
-    /*
-     * TODO - support passed fds... is this necessary?
-     * DEFINE_PROP_STRING("vfiofd", VFIODevice, vfiofd_name),
-     * DEFINE_PROP_STRING("vfiogroupfd, VFIODevice, vfiogroupfd_name),
-     */
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static const VMStateDescription vfio_pci_vmstate = {
-    .name = "vfio-pci",
-    .unmigratable = 1,
-};
-
-static void vfio_pci_dev_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    PCIDeviceClass *pdc = PCI_DEVICE_CLASS(klass);
-
-    dc->reset = vfio_pci_reset;
-    dc->props = vfio_pci_dev_properties;
-    dc->vmsd = &vfio_pci_vmstate;
-    dc->desc = "VFIO-based PCI device assignment";
-    pdc->init = vfio_initfn;
-    pdc->exit = vfio_exitfn;
-    pdc->config_read = vfio_pci_read_config;
-    pdc->config_write = vfio_pci_write_config;
-    pdc->is_express = 1; /* We might be */
-}
-
-static const TypeInfo vfio_pci_dev_info = {
-    .name = "vfio-pci",
-    .parent = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(VFIODevice),
-    .class_init = vfio_pci_dev_class_init,
-};
-
-static void register_vfio_pci_dev_type(void)
-{
-    type_register_static(&vfio_pci_dev_info);
-}
-
-type_init(register_vfio_pci_dev_type)
diff --git a/hw/vga-isa-mm.c b/hw/vga-isa-mm.c
deleted file mode 100644 (file)
index 02356d4..0000000
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * QEMU ISA MM VGA Emulator.
- *
- * 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.
- */
-#include "hw/hw.h"
-#include "ui/console.h"
-#include "hw/pc.h"
-#include "hw/vga_int.h"
-#include "ui/pixel_ops.h"
-#include "qemu/timer.h"
-
-#define VGA_RAM_SIZE (8192 * 1024)
-
-typedef struct ISAVGAMMState {
-    VGACommonState vga;
-    int it_shift;
-} ISAVGAMMState;
-
-/* Memory mapped interface */
-static uint32_t vga_mm_readb (void *opaque, hwaddr addr)
-{
-    ISAVGAMMState *s = opaque;
-
-    return vga_ioport_read(&s->vga, addr >> s->it_shift) & 0xff;
-}
-
-static void vga_mm_writeb (void *opaque,
-                           hwaddr addr, uint32_t value)
-{
-    ISAVGAMMState *s = opaque;
-
-    vga_ioport_write(&s->vga, addr >> s->it_shift, value & 0xff);
-}
-
-static uint32_t vga_mm_readw (void *opaque, hwaddr addr)
-{
-    ISAVGAMMState *s = opaque;
-
-    return vga_ioport_read(&s->vga, addr >> s->it_shift) & 0xffff;
-}
-
-static void vga_mm_writew (void *opaque,
-                           hwaddr addr, uint32_t value)
-{
-    ISAVGAMMState *s = opaque;
-
-    vga_ioport_write(&s->vga, addr >> s->it_shift, value & 0xffff);
-}
-
-static uint32_t vga_mm_readl (void *opaque, hwaddr addr)
-{
-    ISAVGAMMState *s = opaque;
-
-    return vga_ioport_read(&s->vga, addr >> s->it_shift);
-}
-
-static void vga_mm_writel (void *opaque,
-                           hwaddr addr, uint32_t value)
-{
-    ISAVGAMMState *s = opaque;
-
-    vga_ioport_write(&s->vga, addr >> s->it_shift, value);
-}
-
-static const MemoryRegionOps vga_mm_ctrl_ops = {
-    .old_mmio = {
-        .read = {
-            vga_mm_readb,
-            vga_mm_readw,
-            vga_mm_readl,
-        },
-        .write = {
-            vga_mm_writeb,
-            vga_mm_writew,
-            vga_mm_writel,
-        },
-    },
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void vga_mm_init(ISAVGAMMState *s, hwaddr vram_base,
-                        hwaddr ctrl_base, int it_shift,
-                        MemoryRegion *address_space)
-{
-    MemoryRegion *s_ioport_ctrl, *vga_io_memory;
-
-    s->it_shift = it_shift;
-    s_ioport_ctrl = g_malloc(sizeof(*s_ioport_ctrl));
-    memory_region_init_io(s_ioport_ctrl, &vga_mm_ctrl_ops, s,
-                          "vga-mm-ctrl", 0x100000);
-    memory_region_set_flush_coalesced(s_ioport_ctrl);
-
-    vga_io_memory = g_malloc(sizeof(*vga_io_memory));
-    /* XXX: endianness? */
-    memory_region_init_io(vga_io_memory, &vga_mem_ops, &s->vga,
-                          "vga-mem", 0x20000);
-
-    vmstate_register(NULL, 0, &vmstate_vga_common, s);
-
-    memory_region_add_subregion(address_space, ctrl_base, s_ioport_ctrl);
-    s->vga.bank_offset = 0;
-    memory_region_add_subregion(address_space,
-                                vram_base + 0x000a0000, vga_io_memory);
-    memory_region_set_coalescing(vga_io_memory);
-}
-
-int isa_vga_mm_init(hwaddr vram_base,
-                    hwaddr ctrl_base, int it_shift,
-                    MemoryRegion *address_space)
-{
-    ISAVGAMMState *s;
-
-    s = g_malloc0(sizeof(*s));
-
-    s->vga.vram_size_mb = VGA_RAM_SIZE >> 20;
-    vga_common_init(&s->vga);
-    vga_mm_init(s, vram_base, ctrl_base, it_shift, address_space);
-
-    s->vga.con = graphic_console_init(s->vga.update, s->vga.invalidate,
-                                      s->vga.screen_dump, s->vga.text_update,
-                                      s);
-
-    vga_init_vbe(&s->vga, address_space);
-    return 0;
-}
diff --git a/hw/vga-isa.c b/hw/vga-isa.c
deleted file mode 100644 (file)
index 9e29321..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * QEMU ISA VGA Emulator.
- *
- * see docs/specs/standard-vga.txt for virtual hardware specs.
- *
- * 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.
- */
-#include "hw/hw.h"
-#include "ui/console.h"
-#include "hw/pc.h"
-#include "hw/vga_int.h"
-#include "ui/pixel_ops.h"
-#include "qemu/timer.h"
-#include "hw/loader.h"
-
-typedef struct ISAVGAState {
-    ISADevice dev;
-    struct VGACommonState state;
-} ISAVGAState;
-
-static void vga_reset_isa(DeviceState *dev)
-{
-    ISAVGAState *d = container_of(dev, ISAVGAState, dev.qdev);
-    VGACommonState *s = &d->state;
-
-    vga_common_reset(s);
-}
-
-static int vga_initfn(ISADevice *dev)
-{
-    ISAVGAState *d = DO_UPCAST(ISAVGAState, dev, dev);
-    VGACommonState *s = &d->state;
-    MemoryRegion *vga_io_memory;
-    const MemoryRegionPortio *vga_ports, *vbe_ports;
-
-    vga_common_init(s);
-    s->legacy_address_space = isa_address_space(dev);
-    vga_io_memory = vga_init_io(s, &vga_ports, &vbe_ports);
-    isa_register_portio_list(dev, 0x3b0, vga_ports, s, "vga");
-    if (vbe_ports) {
-        isa_register_portio_list(dev, 0x1ce, vbe_ports, s, "vbe");
-    }
-    memory_region_add_subregion_overlap(isa_address_space(dev),
-                                        isa_mem_base + 0x000a0000,
-                                        vga_io_memory, 1);
-    memory_region_set_coalescing(vga_io_memory);
-    s->con = graphic_console_init(s->update, s->invalidate,
-                                  s->screen_dump, s->text_update, s);
-
-    vga_init_vbe(s, isa_address_space(dev));
-    /* ROM BIOS */
-    rom_add_vga(VGABIOS_FILENAME);
-    return 0;
-}
-
-static Property vga_isa_properties[] = {
-    DEFINE_PROP_UINT32("vgamem_mb", ISAVGAState, state.vram_size_mb, 8),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-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;
-    dc->props = vga_isa_properties;
-}
-
-static const TypeInfo vga_info = {
-    .name          = "isa-vga",
-    .parent        = TYPE_ISA_DEVICE,
-    .instance_size = sizeof(ISAVGAState),
-    .class_init    = vga_class_initfn,
-};
-
-static void vga_register_types(void)
-{
-    type_register_static(&vga_info);
-}
-
-type_init(vga_register_types)
diff --git a/hw/vga-pci.c b/hw/vga-pci.c
deleted file mode 100644 (file)
index 05fa9bc..0000000
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- * QEMU PCI VGA Emulator.
- *
- * see docs/specs/standard-vga.txt for virtual hardware specs.
- *
- * 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.
- */
-#include "hw/hw.h"
-#include "ui/console.h"
-#include "hw/pci/pci.h"
-#include "hw/vga_int.h"
-#include "ui/pixel_ops.h"
-#include "qemu/timer.h"
-#include "hw/loader.h"
-
-#define PCI_VGA_IOPORT_OFFSET 0x400
-#define PCI_VGA_IOPORT_SIZE   (0x3e0 - 0x3c0)
-#define PCI_VGA_BOCHS_OFFSET  0x500
-#define PCI_VGA_BOCHS_SIZE    (0x0b * 2)
-#define PCI_VGA_MMIO_SIZE     0x1000
-
-enum vga_pci_flags {
-    PCI_VGA_FLAG_ENABLE_MMIO = 1,
-};
-
-typedef struct PCIVGAState {
-    PCIDevice dev;
-    VGACommonState vga;
-    uint32_t flags;
-    MemoryRegion mmio;
-    MemoryRegion ioport;
-    MemoryRegion bochs;
-} PCIVGAState;
-
-static const VMStateDescription vmstate_vga_pci = {
-    .name = "vga",
-    .version_id = 2,
-    .minimum_version_id = 2,
-    .minimum_version_id_old = 2,
-    .fields      = (VMStateField []) {
-        VMSTATE_PCI_DEVICE(dev, PCIVGAState),
-        VMSTATE_STRUCT(vga, PCIVGAState, 0, vmstate_vga_common, VGACommonState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static uint64_t pci_vga_ioport_read(void *ptr, hwaddr addr,
-                                    unsigned size)
-{
-    PCIVGAState *d = ptr;
-    uint64_t ret = 0;
-
-    switch (size) {
-    case 1:
-        ret = vga_ioport_read(&d->vga, addr);
-        break;
-    case 2:
-        ret  = vga_ioport_read(&d->vga, addr);
-        ret |= vga_ioport_read(&d->vga, addr+1) << 8;
-        break;
-    }
-    return ret;
-}
-
-static void pci_vga_ioport_write(void *ptr, hwaddr addr,
-                                 uint64_t val, unsigned size)
-{
-    PCIVGAState *d = ptr;
-
-    switch (size) {
-    case 1:
-        vga_ioport_write(&d->vga, addr + 0x3c0, val);
-        break;
-    case 2:
-        /*
-         * Update bytes in little endian order.  Allows to update
-         * indexed registers with a single word write because the
-         * index byte is updated first.
-         */
-        vga_ioport_write(&d->vga, addr + 0x3c0, val & 0xff);
-        vga_ioport_write(&d->vga, addr + 0x3c1, (val >> 8) & 0xff);
-        break;
-    }
-}
-
-static const MemoryRegionOps pci_vga_ioport_ops = {
-    .read = pci_vga_ioport_read,
-    .write = pci_vga_ioport_write,
-    .valid.min_access_size = 1,
-    .valid.max_access_size = 4,
-    .impl.min_access_size = 1,
-    .impl.max_access_size = 2,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static uint64_t pci_vga_bochs_read(void *ptr, hwaddr addr,
-                                   unsigned size)
-{
-    PCIVGAState *d = ptr;
-    int index = addr >> 1;
-
-    vbe_ioport_write_index(&d->vga, 0, index);
-    return vbe_ioport_read_data(&d->vga, 0);
-}
-
-static void pci_vga_bochs_write(void *ptr, hwaddr addr,
-                                uint64_t val, unsigned size)
-{
-    PCIVGAState *d = ptr;
-    int index = addr >> 1;
-
-    vbe_ioport_write_index(&d->vga, 0, index);
-    vbe_ioport_write_data(&d->vga, 0, val);
-}
-
-static const MemoryRegionOps pci_vga_bochs_ops = {
-    .read = pci_vga_bochs_read,
-    .write = pci_vga_bochs_write,
-    .valid.min_access_size = 1,
-    .valid.max_access_size = 4,
-    .impl.min_access_size = 2,
-    .impl.max_access_size = 2,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static int pci_std_vga_initfn(PCIDevice *dev)
-{
-    PCIVGAState *d = DO_UPCAST(PCIVGAState, dev, dev);
-    VGACommonState *s = &d->vga;
-
-    /* vga + console init */
-    vga_common_init(s);
-    vga_init(s, pci_address_space(dev), pci_address_space_io(dev), true);
-
-    s->con = graphic_console_init(s->update, s->invalidate,
-                                  s->screen_dump, s->text_update, s);
-
-    /* XXX: VGA_RAM_SIZE must be a power of two */
-    pci_register_bar(&d->dev, 0, PCI_BASE_ADDRESS_MEM_PREFETCH, &s->vram);
-
-    /* mmio bar for vga register access */
-    if (d->flags & (1 << PCI_VGA_FLAG_ENABLE_MMIO)) {
-        memory_region_init(&d->mmio, "vga.mmio", 4096);
-        memory_region_init_io(&d->ioport, &pci_vga_ioport_ops, d,
-                              "vga ioports remapped", PCI_VGA_IOPORT_SIZE);
-        memory_region_init_io(&d->bochs, &pci_vga_bochs_ops, d,
-                              "bochs dispi interface", PCI_VGA_BOCHS_SIZE);
-
-        memory_region_add_subregion(&d->mmio, PCI_VGA_IOPORT_OFFSET,
-                                    &d->ioport);
-        memory_region_add_subregion(&d->mmio, PCI_VGA_BOCHS_OFFSET,
-                                    &d->bochs);
-        pci_register_bar(&d->dev, 2, PCI_BASE_ADDRESS_SPACE_MEMORY, &d->mmio);
-    }
-
-    if (!dev->rom_bar) {
-        /* compatibility with pc-0.13 and older */
-        vga_init_vbe(s, pci_address_space(dev));
-    }
-
-    return 0;
-}
-
-static Property vga_pci_properties[] = {
-    DEFINE_PROP_UINT32("vgamem_mb", PCIVGAState, vga.vram_size_mb, 16),
-    DEFINE_PROP_BIT("mmio", PCIVGAState, flags, PCI_VGA_FLAG_ENABLE_MMIO, true),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void vga_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
-    k->no_hotplug = 1;
-    k->init = pci_std_vga_initfn;
-    k->romfile = "vgabios-stdvga.bin";
-    k->vendor_id = PCI_VENDOR_ID_QEMU;
-    k->device_id = PCI_DEVICE_ID_QEMU_VGA;
-    k->class_id = PCI_CLASS_DISPLAY_VGA;
-    dc->vmsd = &vmstate_vga_pci;
-    dc->props = vga_pci_properties;
-}
-
-static const TypeInfo vga_info = {
-    .name          = "VGA",
-    .parent        = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(PCIVGAState),
-    .class_init    = vga_class_init,
-};
-
-static void vga_register_types(void)
-{
-    type_register_static(&vga_info);
-}
-
-type_init(vga_register_types)
diff --git a/hw/vga.c b/hw/vga.c
deleted file mode 100644 (file)
index 59bfb22..0000000
--- a/hw/vga.c
+++ /dev/null
@@ -1,2457 +0,0 @@
-/*
- * QEMU VGA Emulator.
- *
- * 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.
- */
-#include "hw/hw.h"
-#include "hw/vga.h"
-#include "ui/console.h"
-#include "hw/pc.h"
-#include "hw/pci/pci.h"
-#include "hw/vga_int.h"
-#include "ui/pixel_ops.h"
-#include "qemu/timer.h"
-#include "hw/xen.h"
-#include "trace.h"
-
-//#define DEBUG_VGA
-//#define DEBUG_VGA_MEM
-//#define DEBUG_VGA_REG
-
-//#define DEBUG_BOCHS_VBE
-
-/* 16 state changes per vertical frame @60 Hz */
-#define VGA_TEXT_CURSOR_PERIOD_MS       (1000 * 2 * 16 / 60)
-
-/*
- * 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,
-    0x3d,
-    0x0f,
-    0x3f,
-    0x0e,
-    0x00,
-    0x00,
-    0xff,
-};
-
-const uint8_t gr_mask[16] = {
-    0x0f, /* 0x00 */
-    0x0f, /* 0x01 */
-    0x0f, /* 0x02 */
-    0x1f, /* 0x03 */
-    0x03, /* 0x04 */
-    0x7b, /* 0x05 */
-    0x0f, /* 0x06 */
-    0x0f, /* 0x07 */
-    0xff, /* 0x08 */
-    0x00, /* 0x09 */
-    0x00, /* 0x0a */
-    0x00, /* 0x0b */
-    0x00, /* 0x0c */
-    0x00, /* 0x0d */
-    0x00, /* 0x0e */
-    0x00, /* 0x0f */
-};
-
-#define cbswap_32(__x) \
-((uint32_t)( \
-               (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
-               (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) <<  8) | \
-               (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >>  8) | \
-               (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
-
-#ifdef HOST_WORDS_BIGENDIAN
-#define PAT(x) cbswap_32(x)
-#else
-#define PAT(x) (x)
-#endif
-
-#ifdef HOST_WORDS_BIGENDIAN
-#define BIG 1
-#else
-#define BIG 0
-#endif
-
-#ifdef HOST_WORDS_BIGENDIAN
-#define GET_PLANE(data, p) (((data) >> (24 - (p) * 8)) & 0xff)
-#else
-#define GET_PLANE(data, p) (((data) >> ((p) * 8)) & 0xff)
-#endif
-
-static const uint32_t mask16[16] = {
-    PAT(0x00000000),
-    PAT(0x000000ff),
-    PAT(0x0000ff00),
-    PAT(0x0000ffff),
-    PAT(0x00ff0000),
-    PAT(0x00ff00ff),
-    PAT(0x00ffff00),
-    PAT(0x00ffffff),
-    PAT(0xff000000),
-    PAT(0xff0000ff),
-    PAT(0xff00ff00),
-    PAT(0xff00ffff),
-    PAT(0xffff0000),
-    PAT(0xffff00ff),
-    PAT(0xffffff00),
-    PAT(0xffffffff),
-};
-
-#undef PAT
-
-#ifdef HOST_WORDS_BIGENDIAN
-#define PAT(x) (x)
-#else
-#define PAT(x) cbswap_32(x)
-#endif
-
-static const uint32_t dmask16[16] = {
-    PAT(0x00000000),
-    PAT(0x000000ff),
-    PAT(0x0000ff00),
-    PAT(0x0000ffff),
-    PAT(0x00ff0000),
-    PAT(0x00ff00ff),
-    PAT(0x00ffff00),
-    PAT(0x00ffffff),
-    PAT(0xff000000),
-    PAT(0xff0000ff),
-    PAT(0xff00ff00),
-    PAT(0xff00ffff),
-    PAT(0xffff0000),
-    PAT(0xffff00ff),
-    PAT(0xffffff00),
-    PAT(0xffffffff),
-};
-
-static const uint32_t dmask4[4] = {
-    PAT(0x00000000),
-    PAT(0x0000ffff),
-    PAT(0xffff0000),
-    PAT(0xffffffff),
-};
-
-static uint32_t expand4[256];
-static uint16_t expand2[256];
-static uint8_t expand4to8[16];
-
-static void vga_screen_dump(void *opaque, const char *filename, bool cswitch,
-                            Error **errp);
-
-static void vga_update_memory_access(VGACommonState *s)
-{
-    MemoryRegion *region, *old_region = s->chain4_alias;
-    hwaddr base, offset, size;
-
-    s->chain4_alias = NULL;
-
-    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[VGA_GFX_MISC] >> 2) & 3) {
-        case 0:
-            base = 0xa0000;
-            size = 0x20000;
-            break;
-        case 1:
-            base = 0xa0000;
-            size = 0x10000;
-            offset = s->bank_offset;
-            break;
-        case 2:
-            base = 0xb0000;
-            size = 0x8000;
-            break;
-        case 3:
-        default:
-            base = 0xb8000;
-            size = 0x8000;
-            break;
-        }
-        base += isa_mem_base;
-        region = g_malloc(sizeof(*region));
-        memory_region_init_alias(region, "vga.chain4", &s->vram, offset, size);
-        memory_region_add_subregion_overlap(s->legacy_address_space, base,
-                                            region, 2);
-        s->chain4_alias = region;
-    }
-    if (old_region) {
-        memory_region_del_subregion(s->legacy_address_space, old_region);
-        memory_region_destroy(old_region);
-        g_free(old_region);
-        s->plane_updated = 0xf;
-    }
-}
-
-static void vga_dumb_update_retrace_info(VGACommonState *s)
-{
-    (void) s;
-}
-
-static void vga_precise_update_retrace_info(VGACommonState *s)
-{
-    int htotal_chars;
-    int hretr_start_char;
-    int hretr_skew_chars;
-    int hretr_end_char;
-
-    int vtotal_lines;
-    int vretr_start_line;
-    int vretr_end_line;
-
-    int dots;
-#if 0
-    int div2, sldiv2;
-#endif
-    int clocking_mode;
-    int clock_sel;
-    const int clk_hz[] = {25175000, 28322000, 25175000, 25175000};
-    int64_t chars_per_sec;
-    struct vga_precise_retrace *r = &s->retrace_info.precise;
-
-    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[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[VGA_SEQ_CLOCK_MODE] >> 3) & 1;
-    clock_sel = (s->msr >> 2) & 3;
-    dots = (s->msr & 1) ? 8 : 9;
-
-    chars_per_sec = clk_hz[clock_sel] / dots;
-
-    htotal_chars <<= clocking_mode;
-
-    r->total_chars = vtotal_lines * htotal_chars;
-    if (r->freq) {
-        r->ticks_per_char = get_ticks_per_sec() / (r->total_chars * r->freq);
-    } else {
-        r->ticks_per_char = get_ticks_per_sec() / chars_per_sec;
-    }
-
-    r->vstart = vretr_start_line;
-    r->vend = r->vstart + vretr_end_line + 1;
-
-    r->hstart = hretr_start_char + hretr_skew_chars;
-    r->hend = r->hstart + hretr_end_char + 1;
-    r->htotal = htotal_chars;
-
-#if 0
-    div2 = (s->cr[VGA_CRTC_MODE] >> 2) & 1;
-    sldiv2 = (s->cr[VGA_CRTC_MODE] >> 3) & 1;
-    printf (
-        "hz=%f\n"
-        "htotal = %d\n"
-        "hretr_start = %d\n"
-        "hretr_skew = %d\n"
-        "hretr_end = %d\n"
-        "vtotal = %d\n"
-        "vretr_start = %d\n"
-        "vretr_end = %d\n"
-        "div2 = %d sldiv2 = %d\n"
-        "clocking_mode = %d\n"
-        "clock_sel = %d %d\n"
-        "dots = %d\n"
-        "ticks/char = %" PRId64 "\n"
-        "\n",
-        (double) get_ticks_per_sec() / (r->ticks_per_char * r->total_chars),
-        htotal_chars,
-        hretr_start_char,
-        hretr_skew_chars,
-        hretr_end_char,
-        vtotal_lines,
-        vretr_start_line,
-        vretr_end_line,
-        div2, sldiv2,
-        clocking_mode,
-        clock_sel,
-        clk_hz[clock_sel],
-        dots,
-        r->ticks_per_char
-        );
-#endif
-}
-
-static uint8_t vga_precise_retrace(VGACommonState *s)
-{
-    struct vga_precise_retrace *r = &s->retrace_info.precise;
-    uint8_t val = s->st01 & ~(ST01_V_RETRACE | ST01_DISP_ENABLE);
-
-    if (r->total_chars) {
-        int cur_line, cur_line_char, cur_char;
-        int64_t cur_tick;
-
-        cur_tick = qemu_get_clock_ns(vm_clock);
-
-        cur_char = (cur_tick / r->ticks_per_char) % r->total_chars;
-        cur_line = cur_char / r->htotal;
-
-        if (cur_line >= r->vstart && cur_line <= r->vend) {
-            val |= ST01_V_RETRACE | ST01_DISP_ENABLE;
-        } else {
-            cur_line_char = cur_char % r->htotal;
-            if (cur_line_char >= r->hstart && cur_line_char <= r->hend) {
-                val |= ST01_DISP_ENABLE;
-            }
-        }
-
-        return val;
-    } else {
-        return s->st01 ^ (ST01_V_RETRACE | ST01_DISP_ENABLE);
-    }
-}
-
-static uint8_t vga_dumb_retrace(VGACommonState *s)
-{
-    return s->st01 ^ (ST01_V_RETRACE | ST01_DISP_ENABLE);
-}
-
-int vga_ioport_invalid(VGACommonState *s, uint32_t addr)
-{
-    if (s->msr & VGA_MIS_COLOR) {
-        /* Color */
-        return (addr >= 0x3b0 && addr <= 0x3bf);
-    } else {
-        /* Monochrome */
-        return (addr >= 0x3d0 && addr <= 0x3df);
-    }
-}
-
-uint32_t vga_ioport_read(void *opaque, uint32_t addr)
-{
-    VGACommonState *s = opaque;
-    int val, index;
-
-    qemu_flush_coalesced_mmio_buffer();
-
-    if (vga_ioport_invalid(s, addr)) {
-        val = 0xff;
-    } else {
-        switch(addr) {
-        case VGA_ATT_W:
-            if (s->ar_flip_flop == 0) {
-                val = s->ar_index;
-            } else {
-                val = 0;
-            }
-            break;
-        case VGA_ATT_R:
-            index = s->ar_index & 0x1f;
-            if (index < VGA_ATT_C) {
-                val = s->ar[index];
-            } else {
-                val = 0;
-            }
-            break;
-        case VGA_MIS_W:
-            val = s->st00;
-            break;
-        case VGA_SEQ_I:
-            val = s->sr_index;
-            break;
-        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 VGA_PEL_IR:
-            val = s->dac_state;
-            break;
-        case VGA_PEL_IW:
-            val = s->dac_write_index;
-            break;
-        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 VGA_FTC_R:
-            val = s->fcr;
-            break;
-        case VGA_MIS_R:
-            val = s->msr;
-            break;
-        case VGA_GFX_I:
-            val = s->gr_index;
-            break;
-        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 VGA_CRT_IM:
-        case VGA_CRT_IC:
-            val = s->cr_index;
-            break;
-        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 VGA_IS1_RM:
-        case VGA_IS1_RC:
-            /* just toggle to fool polling */
-            val = s->st01 = s->retrace(s);
-            s->ar_flip_flop = 0;
-            break;
-        default:
-            val = 0x00;
-            break;
-        }
-    }
-#if defined(DEBUG_VGA)
-    printf("VGA: read addr=0x%04x data=0x%02x\n", addr, val);
-#endif
-    return val;
-}
-
-void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
-{
-    VGACommonState *s = opaque;
-    int index;
-
-    qemu_flush_coalesced_mmio_buffer();
-
-    /* check port range access depending on color/monochrome mode */
-    if (vga_ioport_invalid(s, addr)) {
-        return;
-    }
-#ifdef DEBUG_VGA
-    printf("VGA: write addr=0x%04x data=0x%02x\n", addr, val);
-#endif
-
-    switch(addr) {
-    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 VGA_ATC_PALETTE0 ... VGA_ATC_PALETTEF:
-                s->ar[index] = val & 0x3f;
-                break;
-            case VGA_ATC_MODE:
-                s->ar[index] = val & ~0x10;
-                break;
-            case VGA_ATC_OVERSCAN:
-                s->ar[index] = val;
-                break;
-            case VGA_ATC_PLANE_ENABLE:
-                s->ar[index] = val & ~0xc0;
-                break;
-            case VGA_ATC_PEL:
-                s->ar[index] = val & ~0xf0;
-                break;
-            case VGA_ATC_COLOR_PAGE:
-                s->ar[index] = val & ~0xf0;
-                break;
-            default:
-                break;
-            }
-        }
-        s->ar_flip_flop ^= 1;
-        break;
-    case VGA_MIS_W:
-        s->msr = val & ~0x10;
-        s->update_retrace_info(s);
-        break;
-    case VGA_SEQ_I:
-        s->sr_index = val & 7;
-        break;
-    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 == VGA_SEQ_CLOCK_MODE) {
-            s->update_retrace_info(s);
-        }
-        vga_update_memory_access(s);
-        break;
-    case VGA_PEL_IR:
-        s->dac_read_index = val;
-        s->dac_sub_index = 0;
-        s->dac_state = 3;
-        break;
-    case VGA_PEL_IW:
-        s->dac_write_index = val;
-        s->dac_sub_index = 0;
-        s->dac_state = 0;
-        break;
-    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);
-            s->dac_sub_index = 0;
-            s->dac_write_index++;
-        }
-        break;
-    case VGA_GFX_I:
-        s->gr_index = val & 0x0f;
-        break;
-    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 VGA_CRT_IM:
-    case VGA_CRT_IC:
-        s->cr_index = val;
-        break;
-    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[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 == 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 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 VGA_IS1_RM:
-    case VGA_IS1_RC:
-        s->fcr = val & 0x10;
-        break;
-    }
-}
-
-static uint32_t vbe_ioport_read_index(void *opaque, uint32_t addr)
-{
-    VGACommonState *s = opaque;
-    uint32_t val;
-    val = s->vbe_index;
-    return val;
-}
-
-uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr)
-{
-    VGACommonState *s = opaque;
-    uint32_t val;
-
-    if (s->vbe_index < VBE_DISPI_INDEX_NB) {
-        if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_GETCAPS) {
-            switch(s->vbe_index) {
-                /* XXX: do not hardcode ? */
-            case VBE_DISPI_INDEX_XRES:
-                val = VBE_DISPI_MAX_XRES;
-                break;
-            case VBE_DISPI_INDEX_YRES:
-                val = VBE_DISPI_MAX_YRES;
-                break;
-            case VBE_DISPI_INDEX_BPP:
-                val = VBE_DISPI_MAX_BPP;
-                break;
-            default:
-                val = s->vbe_regs[s->vbe_index];
-                break;
-            }
-        } else {
-            val = s->vbe_regs[s->vbe_index];
-        }
-    } else if (s->vbe_index == VBE_DISPI_INDEX_VIDEO_MEMORY_64K) {
-        val = s->vram_size / (64 * 1024);
-    } else {
-        val = 0;
-    }
-#ifdef DEBUG_BOCHS_VBE
-    printf("VBE: read index=0x%x val=0x%x\n", s->vbe_index, val);
-#endif
-    return val;
-}
-
-void vbe_ioport_write_index(void *opaque, uint32_t addr, uint32_t val)
-{
-    VGACommonState *s = opaque;
-    s->vbe_index = val;
-}
-
-void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
-{
-    VGACommonState *s = opaque;
-
-    if (s->vbe_index <= VBE_DISPI_INDEX_NB) {
-#ifdef DEBUG_BOCHS_VBE
-        printf("VBE: write index=0x%x val=0x%x\n", s->vbe_index, val);
-#endif
-        switch(s->vbe_index) {
-        case VBE_DISPI_INDEX_ID:
-            if (val == VBE_DISPI_ID0 ||
-                val == VBE_DISPI_ID1 ||
-                val == VBE_DISPI_ID2 ||
-                val == VBE_DISPI_ID3 ||
-                val == VBE_DISPI_ID4) {
-                s->vbe_regs[s->vbe_index] = val;
-            }
-            break;
-        case VBE_DISPI_INDEX_XRES:
-            if ((val <= VBE_DISPI_MAX_XRES) && ((val & 7) == 0)) {
-                s->vbe_regs[s->vbe_index] = val;
-            }
-            break;
-        case VBE_DISPI_INDEX_YRES:
-            if (val <= VBE_DISPI_MAX_YRES) {
-                s->vbe_regs[s->vbe_index] = val;
-            }
-            break;
-        case VBE_DISPI_INDEX_BPP:
-            if (val == 0)
-                val = 8;
-            if (val == 4 || val == 8 || val == 15 ||
-                val == 16 || val == 24 || val == 32) {
-                s->vbe_regs[s->vbe_index] = val;
-            }
-            break;
-        case VBE_DISPI_INDEX_BANK:
-            if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
-              val &= (s->vbe_bank_mask >> 2);
-            } else {
-              val &= s->vbe_bank_mask;
-            }
-            s->vbe_regs[s->vbe_index] = val;
-            s->bank_offset = (val << 16);
-            vga_update_memory_access(s);
-            break;
-        case VBE_DISPI_INDEX_ENABLE:
-            if ((val & VBE_DISPI_ENABLED) &&
-                !(s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
-                int h, shift_control;
-
-                s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] =
-                    s->vbe_regs[VBE_DISPI_INDEX_XRES];
-                s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] =
-                    s->vbe_regs[VBE_DISPI_INDEX_YRES];
-                s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] = 0;
-                s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] = 0;
-
-                if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
-                    s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 1;
-                else
-                    s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] *
-                        ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
-                s->vbe_start_addr = 0;
-
-                /* clear the screen (should be done in BIOS) */
-                if (!(val & VBE_DISPI_NOCLEARMEM)) {
-                    memset(s->vram_ptr, 0,
-                           s->vbe_regs[VBE_DISPI_INDEX_YRES] * s->vbe_line_offset);
-                }
-
-                /* we initialize the VGA graphic mode (should be done
-                   in BIOS) */
-                /* 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[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[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[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[VGA_SEQ_CLOCK_MODE] &= ~8; /* no double line */
-                } else {
-                    shift_control = 2;
-                    /* 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[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;
-            }
-            s->dac_8bit = (val & VBE_DISPI_8BIT_DAC) > 0;
-            s->vbe_regs[s->vbe_index] = val;
-            vga_update_memory_access(s);
-            break;
-        case VBE_DISPI_INDEX_VIRT_WIDTH:
-            {
-                int w, h, line_offset;
-
-                if (val < s->vbe_regs[VBE_DISPI_INDEX_XRES])
-                    return;
-                w = val;
-                if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
-                    line_offset = w >> 1;
-                else
-                    line_offset = w * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
-                h = s->vram_size / line_offset;
-                /* XXX: support weird bochs semantics ? */
-                if (h < s->vbe_regs[VBE_DISPI_INDEX_YRES])
-                    return;
-                s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = w;
-                s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] = h;
-                s->vbe_line_offset = line_offset;
-            }
-            break;
-        case VBE_DISPI_INDEX_X_OFFSET:
-        case VBE_DISPI_INDEX_Y_OFFSET:
-            {
-                int x;
-                s->vbe_regs[s->vbe_index] = val;
-                s->vbe_start_addr = s->vbe_line_offset * s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET];
-                x = s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET];
-                if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
-                    s->vbe_start_addr += x >> 1;
-                else
-                    s->vbe_start_addr += x * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
-                s->vbe_start_addr >>= 2;
-            }
-            break;
-        default:
-            break;
-        }
-    }
-}
-
-/* called for accesses between 0xa0000 and 0xc0000 */
-uint32_t vga_mem_readb(VGACommonState *s, hwaddr addr)
-{
-    int memory_map_mode, plane;
-    uint32_t ret;
-
-    /* convert to VGA memory offset */
-    memory_map_mode = (s->gr[VGA_GFX_MISC] >> 2) & 3;
-    addr &= 0x1ffff;
-    switch(memory_map_mode) {
-    case 0:
-        break;
-    case 1:
-        if (addr >= 0x10000)
-            return 0xff;
-        addr += s->bank_offset;
-        break;
-    case 2:
-        addr -= 0x10000;
-        if (addr >= 0x8000)
-            return 0xff;
-        break;
-    default:
-    case 3:
-        addr -= 0x18000;
-        if (addr >= 0x8000)
-            return 0xff;
-        break;
-    }
-
-    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[VGA_GFX_MODE] & 0x10) {
-        /* odd/even mode (aka text mode mapping) */
-        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[VGA_GFX_MODE] & 0x08)) {
-            /* read mode 0 */
-            plane = s->gr[VGA_GFX_PLANE_READ];
-            ret = GET_PLANE(s->latch, plane);
-        } else {
-            /* read mode 1 */
-            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;
-        }
-    }
-    return ret;
-}
-
-/* called for accesses between 0xa0000 and 0xc0000 */
-void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val)
-{
-    int memory_map_mode, plane, write_mode, b, func_select, mask;
-    uint32_t write_mask, bit_mask, set_mask;
-
-#ifdef DEBUG_VGA_MEM
-    printf("vga: [0x" TARGET_FMT_plx "] = 0x%02x\n", addr, val);
-#endif
-    /* convert to VGA memory offset */
-    memory_map_mode = (s->gr[VGA_GFX_MISC] >> 2) & 3;
-    addr &= 0x1ffff;
-    switch(memory_map_mode) {
-    case 0:
-        break;
-    case 1:
-        if (addr >= 0x10000)
-            return;
-        addr += s->bank_offset;
-        break;
-    case 2:
-        addr -= 0x10000;
-        if (addr >= 0x8000)
-            return;
-        break;
-    default:
-    case 3:
-        addr -= 0x18000;
-        if (addr >= 0x8000)
-            return;
-        break;
-    }
-
-    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[VGA_SEQ_PLANE_WRITE] & mask) {
-            s->vram_ptr[addr] = val;
-#ifdef DEBUG_VGA_MEM
-            printf("vga: chain4: [0x" TARGET_FMT_plx "]\n", addr);
-#endif
-            s->plane_updated |= mask; /* only used to detect font change */
-            memory_region_set_dirty(&s->vram, addr, 1);
-        }
-    } else if (s->gr[VGA_GFX_MODE] & 0x10) {
-        /* odd/even mode (aka text mode mapping) */
-        plane = (s->gr[VGA_GFX_PLANE_READ] & 2) | (addr & 1);
-        mask = (1 << plane);
-        if (s->sr[VGA_SEQ_PLANE_WRITE] & mask) {
-            addr = ((addr & ~1) << 1) | plane;
-            s->vram_ptr[addr] = val;
-#ifdef DEBUG_VGA_MEM
-            printf("vga: odd/even: [0x" TARGET_FMT_plx "]\n", addr);
-#endif
-            s->plane_updated |= mask; /* only used to detect font change */
-            memory_region_set_dirty(&s->vram, addr, 1);
-        }
-    } else {
-        /* standard VGA latched access */
-        write_mode = s->gr[VGA_GFX_MODE] & 3;
-        switch(write_mode) {
-        default:
-        case 0:
-            /* rotate */
-            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[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[VGA_GFX_BIT_MASK];
-            break;
-        case 3:
-            /* rotate */
-            b = s->gr[VGA_GFX_DATA_ROTATE] & 7;
-            val = (val >> b) | (val << (8 - b));
-
-            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[VGA_GFX_DATA_ROTATE] >> 3;
-        switch(func_select) {
-        case 0:
-        default:
-            /* nothing to do */
-            break;
-        case 1:
-            /* and */
-            val &= s->latch;
-            break;
-        case 2:
-            /* or */
-            val |= s->latch;
-            break;
-        case 3:
-            /* xor */
-            val ^= s->latch;
-            break;
-        }
-
-        /* apply bit mask */
-        bit_mask |= bit_mask << 8;
-        bit_mask |= bit_mask << 16;
-        val = (val & bit_mask) | (s->latch & ~bit_mask);
-
-    do_write:
-        /* mask data according to 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] =
-            (((uint32_t *)s->vram_ptr)[addr] & ~write_mask) |
-            (val & write_mask);
-#ifdef DEBUG_VGA_MEM
-        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, sizeof(uint32_t));
-    }
-}
-
-typedef void vga_draw_glyph8_func(uint8_t *d, int linesize,
-                             const uint8_t *font_ptr, int h,
-                             uint32_t fgcol, uint32_t bgcol);
-typedef void vga_draw_glyph9_func(uint8_t *d, int linesize,
-                                  const uint8_t *font_ptr, int h,
-                                  uint32_t fgcol, uint32_t bgcol, int dup9);
-typedef void vga_draw_line_func(VGACommonState *s1, uint8_t *d,
-                                const uint8_t *s, int width);
-
-#define DEPTH 8
-#include "hw/vga_template.h"
-
-#define DEPTH 15
-#include "hw/vga_template.h"
-
-#define BGR_FORMAT
-#define DEPTH 15
-#include "hw/vga_template.h"
-
-#define DEPTH 16
-#include "hw/vga_template.h"
-
-#define BGR_FORMAT
-#define DEPTH 16
-#include "hw/vga_template.h"
-
-#define DEPTH 32
-#include "hw/vga_template.h"
-
-#define BGR_FORMAT
-#define DEPTH 32
-#include "hw/vga_template.h"
-
-static unsigned int rgb_to_pixel8_dup(unsigned int r, unsigned int g, unsigned b)
-{
-    unsigned int col;
-    col = rgb_to_pixel8(r, g, b);
-    col |= col << 8;
-    col |= col << 16;
-    return col;
-}
-
-static unsigned int rgb_to_pixel15_dup(unsigned int r, unsigned int g, unsigned b)
-{
-    unsigned int col;
-    col = rgb_to_pixel15(r, g, b);
-    col |= col << 16;
-    return col;
-}
-
-static unsigned int rgb_to_pixel15bgr_dup(unsigned int r, unsigned int g,
-                                          unsigned int b)
-{
-    unsigned int col;
-    col = rgb_to_pixel15bgr(r, g, b);
-    col |= col << 16;
-    return col;
-}
-
-static unsigned int rgb_to_pixel16_dup(unsigned int r, unsigned int g, unsigned b)
-{
-    unsigned int col;
-    col = rgb_to_pixel16(r, g, b);
-    col |= col << 16;
-    return col;
-}
-
-static unsigned int rgb_to_pixel16bgr_dup(unsigned int r, unsigned int g,
-                                          unsigned int b)
-{
-    unsigned int col;
-    col = rgb_to_pixel16bgr(r, g, b);
-    col |= col << 16;
-    return col;
-}
-
-static unsigned int rgb_to_pixel32_dup(unsigned int r, unsigned int g, unsigned b)
-{
-    unsigned int col;
-    col = rgb_to_pixel32(r, g, b);
-    return col;
-}
-
-static unsigned int rgb_to_pixel32bgr_dup(unsigned int r, unsigned int g, unsigned b)
-{
-    unsigned int col;
-    col = rgb_to_pixel32bgr(r, g, b);
-    return col;
-}
-
-/* return true if the palette was modified */
-static int update_palette16(VGACommonState *s)
-{
-    int full_update, i;
-    uint32_t v, col, *palette;
-
-    full_update = 0;
-    palette = s->last_palette;
-    for(i = 0; i < 16; i++) {
-        v = s->ar[i];
-        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]),
-                              c6_to_8(s->palette[v + 2]));
-        if (col != palette[i]) {
-            full_update = 1;
-            palette[i] = col;
-        }
-    }
-    return full_update;
-}
-
-/* return true if the palette was modified */
-static int update_palette256(VGACommonState *s)
-{
-    int full_update, i;
-    uint32_t v, col, *palette;
-
-    full_update = 0;
-    palette = s->last_palette;
-    v = 0;
-    for(i = 0; i < 256; i++) {
-        if (s->dac_8bit) {
-          col = s->rgb_to_pixel(s->palette[v],
-                                s->palette[v + 1],
-                                s->palette[v + 2]);
-        } else {
-          col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
-                                c6_to_8(s->palette[v + 1]),
-                                c6_to_8(s->palette[v + 2]));
-        }
-        if (col != palette[i]) {
-            full_update = 1;
-            palette[i] = col;
-        }
-        v += 3;
-    }
-    return full_update;
-}
-
-static void vga_get_offsets(VGACommonState *s,
-                            uint32_t *pline_offset,
-                            uint32_t *pstart_addr,
-                            uint32_t *pline_compare)
-{
-    uint32_t start_addr, line_offset, line_compare;
-
-    if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
-        line_offset = s->vbe_line_offset;
-        start_addr = s->vbe_start_addr;
-        line_compare = 65535;
-    } else {
-        /* compute line_offset in bytes */
-        line_offset = s->cr[VGA_CRTC_OFFSET];
-        line_offset <<= 3;
-
-        /* starting address */
-        start_addr = s->cr[VGA_CRTC_START_LO] |
-            (s->cr[VGA_CRTC_START_HI] << 8);
-
-        /* line compare */
-        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;
-    *pline_compare = line_compare;
-}
-
-/* update start_addr and line_offset. Return TRUE if modified */
-static int update_basic_params(VGACommonState *s)
-{
-    int full_update;
-    uint32_t start_addr, line_offset, line_compare;
-
-    full_update = 0;
-
-    s->get_offsets(s, &line_offset, &start_addr, &line_compare);
-
-    if (line_offset != s->line_offset ||
-        start_addr != s->start_addr ||
-        line_compare != s->line_compare) {
-        s->line_offset = line_offset;
-        s->start_addr = start_addr;
-        s->line_compare = line_compare;
-        full_update = 1;
-    }
-    return full_update;
-}
-
-#define NB_DEPTHS 7
-
-static inline int get_depth_index(DisplaySurface *s)
-{
-    switch (surface_bits_per_pixel(s)) {
-    default:
-    case 8:
-        return 0;
-    case 15:
-        return 1;
-    case 16:
-        return 2;
-    case 32:
-        if (is_surface_bgr(s)) {
-            return 4;
-        } else {
-            return 3;
-        }
-    }
-}
-
-static vga_draw_glyph8_func * const vga_draw_glyph8_table[NB_DEPTHS] = {
-    vga_draw_glyph8_8,
-    vga_draw_glyph8_16,
-    vga_draw_glyph8_16,
-    vga_draw_glyph8_32,
-    vga_draw_glyph8_32,
-    vga_draw_glyph8_16,
-    vga_draw_glyph8_16,
-};
-
-static vga_draw_glyph8_func * const vga_draw_glyph16_table[NB_DEPTHS] = {
-    vga_draw_glyph16_8,
-    vga_draw_glyph16_16,
-    vga_draw_glyph16_16,
-    vga_draw_glyph16_32,
-    vga_draw_glyph16_32,
-    vga_draw_glyph16_16,
-    vga_draw_glyph16_16,
-};
-
-static vga_draw_glyph9_func * const vga_draw_glyph9_table[NB_DEPTHS] = {
-    vga_draw_glyph9_8,
-    vga_draw_glyph9_16,
-    vga_draw_glyph9_16,
-    vga_draw_glyph9_32,
-    vga_draw_glyph9_32,
-    vga_draw_glyph9_16,
-    vga_draw_glyph9_16,
-};
-
-static const uint8_t cursor_glyph[32 * 4] = {
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-};
-
-static void vga_get_text_resolution(VGACommonState *s, int *pwidth, int *pheight,
-                                    int *pcwidth, int *pcheight)
-{
-    int width, cwidth, height, cheight;
-
-    /* total width & height */
-    cheight = (s->cr[VGA_CRTC_MAX_SCAN] & 0x1f) + 1;
-    cwidth = 8;
-    if (!(s->sr[VGA_SEQ_CLOCK_MODE] & VGA_SR01_CHAR_CLK_8DOTS)) {
-        cwidth = 9;
-    }
-    if (s->sr[VGA_SEQ_CLOCK_MODE] & 0x08) {
-        cwidth = 16; /* NOTE: no 18 pixel wide */
-    }
-    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[VGA_CRTC_V_DISP_END] |
-            ((s->cr[VGA_CRTC_OVERFLOW] & 0x02) << 7) |
-            ((s->cr[VGA_CRTC_OVERFLOW] & 0x40) << 3);
-        height = (height + 1) / cheight;
-    }
-
-    *pwidth = width;
-    *pheight = height;
-    *pcwidth = cwidth;
-    *pcheight = cheight;
-}
-
-typedef unsigned int rgb_to_pixel_dup_func(unsigned int r, unsigned int g, unsigned b);
-
-static rgb_to_pixel_dup_func * const rgb_to_pixel_dup_table[NB_DEPTHS] = {
-    rgb_to_pixel8_dup,
-    rgb_to_pixel15_dup,
-    rgb_to_pixel16_dup,
-    rgb_to_pixel32_dup,
-    rgb_to_pixel32bgr_dup,
-    rgb_to_pixel15bgr_dup,
-    rgb_to_pixel16bgr_dup,
-};
-
-/*
- * Text mode update
- * Missing:
- * - double scan
- * - double width
- * - underline
- * - flashing
- */
-static void vga_draw_text(VGACommonState *s, int full_update)
-{
-    DisplaySurface *surface = qemu_console_surface(s->con);
-    int cx, cy, cheight, cw, ch, cattr, height, width, ch_attr;
-    int cx_min, cx_max, linesize, x_incr, line, line1;
-    uint32_t offset, fgcol, bgcol, v, cursor_offset;
-    uint8_t *d1, *d, *src, *dest, *cursor_ptr;
-    const uint8_t *font_ptr, *font_base[2];
-    int dup9, line_offset, depth_index;
-    uint32_t *palette;
-    uint32_t *ch_attr_ptr;
-    vga_draw_glyph8_func *vga_draw_glyph8;
-    vga_draw_glyph9_func *vga_draw_glyph9;
-    int64_t now = qemu_get_clock_ms(vm_clock);
-
-    /* compute font data address (in plane 2) */
-    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;
-        full_update = 1;
-    }
-    font_base[0] = s->vram_ptr + offset;
-
-    offset = (((v >> 5) & 1) | ((v >> 1) & 6)) * 8192 * 4 + 2;
-    font_base[1] = s->vram_ptr + offset;
-    if (offset != s->font_offsets[1]) {
-        s->font_offsets[1] = offset;
-        full_update = 1;
-    }
-    if (s->plane_updated & (1 << 2) || s->chain4_alias) {
-        /* if the plane 2 was modified since the last display, it
-           indicates the font may have been modified */
-        s->plane_updated = 0;
-        full_update = 1;
-    }
-    full_update |= update_basic_params(s);
-
-    line_offset = s->line_offset;
-
-    vga_get_text_resolution(s, &width, &height, &cw, &cheight);
-    if ((height * width) <= 1) {
-        /* better than nothing: exit if transient size is too small */
-        return;
-    }
-    if ((height * width) > CH_ATTR_SIZE) {
-        /* better than nothing: exit if transient size is too big */
-        return;
-    }
-
-    if (width != s->last_width || height != s->last_height ||
-        cw != s->last_cw || cheight != s->last_ch || s->last_depth) {
-        s->last_scr_width = width * cw;
-        s->last_scr_height = height * cheight;
-        qemu_console_resize(s->con, s->last_scr_width, s->last_scr_height);
-        surface = qemu_console_surface(s->con);
-        dpy_text_resize(s->con, width, height);
-        s->last_depth = 0;
-        s->last_width = width;
-        s->last_height = height;
-        s->last_ch = cheight;
-        s->last_cw = cw;
-        full_update = 1;
-    }
-    s->rgb_to_pixel =
-        rgb_to_pixel_dup_table[get_depth_index(surface)];
-    full_update |= update_palette16(s);
-    palette = s->last_palette;
-    x_incr = cw * surface_bytes_per_pixel(surface);
-
-    if (full_update) {
-        s->full_update_text = 1;
-    }
-    if (s->full_update_gfx) {
-        s->full_update_gfx = 0;
-        full_update |= 1;
-    }
-
-    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[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)
-            s->last_ch_attr[s->cursor_offset] = -1;
-        if (cursor_offset < CH_ATTR_SIZE)
-            s->last_ch_attr[cursor_offset] = -1;
-        s->cursor_offset = cursor_offset;
-        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;
-    if (now >= s->cursor_blink_time) {
-        s->cursor_blink_time = now + VGA_TEXT_CURSOR_PERIOD_MS / 2;
-        s->cursor_visible_phase = !s->cursor_visible_phase;
-    }
-
-    depth_index = get_depth_index(surface);
-    if (cw == 16)
-        vga_draw_glyph8 = vga_draw_glyph16_table[depth_index];
-    else
-        vga_draw_glyph8 = vga_draw_glyph8_table[depth_index];
-    vga_draw_glyph9 = vga_draw_glyph9_table[depth_index];
-
-    dest = surface_data(surface);
-    linesize = surface_stride(surface);
-    ch_attr_ptr = s->last_ch_attr;
-    line = 0;
-    offset = s->start_addr * 4;
-    for(cy = 0; cy < height; cy++) {
-        d1 = dest;
-        src = s->vram_ptr + offset;
-        cx_min = width;
-        cx_max = -1;
-        for(cx = 0; cx < width; cx++) {
-            ch_attr = *(uint16_t *)src;
-            if (full_update || ch_attr != *ch_attr_ptr || src == cursor_ptr) {
-                if (cx < cx_min)
-                    cx_min = cx;
-                if (cx > cx_max)
-                    cx_max = cx;
-                *ch_attr_ptr = ch_attr;
-#ifdef HOST_WORDS_BIGENDIAN
-                ch = ch_attr >> 8;
-                cattr = ch_attr & 0xff;
-#else
-                ch = ch_attr & 0xff;
-                cattr = ch_attr >> 8;
-#endif
-                font_ptr = font_base[(cattr >> 3) & 1];
-                font_ptr += 32 * 4 * ch;
-                bgcol = palette[cattr >> 4];
-                fgcol = palette[cattr & 0x0f];
-                if (cw != 9) {
-                    vga_draw_glyph8(d1, linesize,
-                                    font_ptr, cheight, fgcol, bgcol);
-                } else {
-                    dup9 = 0;
-                    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[VGA_CRTC_CURSOR_START] & 0x20) &&
-                    s->cursor_visible_phase) {
-                    int line_start, line_last, h;
-                    /* draw the cursor */
-                    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;
-                    if (line_last >= line_start && line_start < cheight) {
-                        h = line_last - line_start + 1;
-                        d = d1 + linesize * line_start;
-                        if (cw != 9) {
-                            vga_draw_glyph8(d, linesize,
-                                            cursor_glyph, h, fgcol, bgcol);
-                        } else {
-                            vga_draw_glyph9(d, linesize,
-                                            cursor_glyph, h, fgcol, bgcol, 1);
-                        }
-                    }
-                }
-            }
-            d1 += x_incr;
-            src += 4;
-            ch_attr_ptr++;
-        }
-        if (cx_max != -1) {
-            dpy_gfx_update(s->con, cx_min * cw, cy * cheight,
-                           (cx_max - cx_min + 1) * cw, cheight);
-        }
-        dest += linesize * cheight;
-        line1 = line + cheight;
-        offset += line_offset;
-        if (line < s->line_compare && line1 >= s->line_compare) {
-            offset = 0;
-        }
-        line = line1;
-    }
-}
-
-enum {
-    VGA_DRAW_LINE2,
-    VGA_DRAW_LINE2D2,
-    VGA_DRAW_LINE4,
-    VGA_DRAW_LINE4D2,
-    VGA_DRAW_LINE8D2,
-    VGA_DRAW_LINE8,
-    VGA_DRAW_LINE15,
-    VGA_DRAW_LINE16,
-    VGA_DRAW_LINE24,
-    VGA_DRAW_LINE32,
-    VGA_DRAW_LINE_NB,
-};
-
-static vga_draw_line_func * const vga_draw_line_table[NB_DEPTHS * VGA_DRAW_LINE_NB] = {
-    vga_draw_line2_8,
-    vga_draw_line2_16,
-    vga_draw_line2_16,
-    vga_draw_line2_32,
-    vga_draw_line2_32,
-    vga_draw_line2_16,
-    vga_draw_line2_16,
-
-    vga_draw_line2d2_8,
-    vga_draw_line2d2_16,
-    vga_draw_line2d2_16,
-    vga_draw_line2d2_32,
-    vga_draw_line2d2_32,
-    vga_draw_line2d2_16,
-    vga_draw_line2d2_16,
-
-    vga_draw_line4_8,
-    vga_draw_line4_16,
-    vga_draw_line4_16,
-    vga_draw_line4_32,
-    vga_draw_line4_32,
-    vga_draw_line4_16,
-    vga_draw_line4_16,
-
-    vga_draw_line4d2_8,
-    vga_draw_line4d2_16,
-    vga_draw_line4d2_16,
-    vga_draw_line4d2_32,
-    vga_draw_line4d2_32,
-    vga_draw_line4d2_16,
-    vga_draw_line4d2_16,
-
-    vga_draw_line8d2_8,
-    vga_draw_line8d2_16,
-    vga_draw_line8d2_16,
-    vga_draw_line8d2_32,
-    vga_draw_line8d2_32,
-    vga_draw_line8d2_16,
-    vga_draw_line8d2_16,
-
-    vga_draw_line8_8,
-    vga_draw_line8_16,
-    vga_draw_line8_16,
-    vga_draw_line8_32,
-    vga_draw_line8_32,
-    vga_draw_line8_16,
-    vga_draw_line8_16,
-
-    vga_draw_line15_8,
-    vga_draw_line15_15,
-    vga_draw_line15_16,
-    vga_draw_line15_32,
-    vga_draw_line15_32bgr,
-    vga_draw_line15_15bgr,
-    vga_draw_line15_16bgr,
-
-    vga_draw_line16_8,
-    vga_draw_line16_15,
-    vga_draw_line16_16,
-    vga_draw_line16_32,
-    vga_draw_line16_32bgr,
-    vga_draw_line16_15bgr,
-    vga_draw_line16_16bgr,
-
-    vga_draw_line24_8,
-    vga_draw_line24_15,
-    vga_draw_line24_16,
-    vga_draw_line24_32,
-    vga_draw_line24_32bgr,
-    vga_draw_line24_15bgr,
-    vga_draw_line24_16bgr,
-
-    vga_draw_line32_8,
-    vga_draw_line32_15,
-    vga_draw_line32_16,
-    vga_draw_line32_32,
-    vga_draw_line32_32bgr,
-    vga_draw_line32_15bgr,
-    vga_draw_line32_16bgr,
-};
-
-static int vga_get_bpp(VGACommonState *s)
-{
-    int ret;
-
-    if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
-        ret = s->vbe_regs[VBE_DISPI_INDEX_BPP];
-    } else {
-        ret = 0;
-    }
-    return ret;
-}
-
-static void vga_get_resolution(VGACommonState *s, int *pwidth, int *pheight)
-{
-    int width, height;
-
-    if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
-        width = s->vbe_regs[VBE_DISPI_INDEX_XRES];
-        height = s->vbe_regs[VBE_DISPI_INDEX_YRES];
-    } else {
-        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;
-    *pheight = height;
-}
-
-void vga_invalidate_scanlines(VGACommonState *s, int y1, int y2)
-{
-    int y;
-    if (y1 >= VGA_MAX_HEIGHT)
-        return;
-    if (y2 >= VGA_MAX_HEIGHT)
-        y2 = VGA_MAX_HEIGHT;
-    for(y = y1; y < y2; y++) {
-        s->invalidated_y_table[y >> 5] |= 1 << (y & 0x1f);
-    }
-}
-
-void vga_sync_dirty_bitmap(VGACommonState *s)
-{
-    memory_region_sync_dirty_bitmap(&s->vram);
-}
-
-void vga_dirty_log_start(VGACommonState *s)
-{
-    memory_region_set_log(&s->vram, true, DIRTY_MEMORY_VGA);
-}
-
-void vga_dirty_log_stop(VGACommonState *s)
-{
-    memory_region_set_log(&s->vram, false, DIRTY_MEMORY_VGA);
-}
-
-/*
- * graphic modes
- */
-static void vga_draw_graphic(VGACommonState *s, int full_update)
-{
-    DisplaySurface *surface = qemu_console_surface(s->con);
-    int y1, y, update, linesize, y_start, double_scan, mask, depth;
-    int width, height, shift_control, line_offset, bwidth, bits;
-    ram_addr_t page0, page1, page_min, page_max;
-    int disp_width, multi_scan, multi_run;
-    uint8_t *d;
-    uint32_t v, addr1, addr;
-    vga_draw_line_func *vga_draw_line;
-#if defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
-    static const bool byteswap = false;
-#else
-    static const bool byteswap = true;
-#endif
-
-    full_update |= update_basic_params(s);
-
-    if (!full_update)
-        vga_sync_dirty_bitmap(s);
-
-    s->get_resolution(s, &width, &height);
-    disp_width = width;
-
-    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[VGA_CRTC_MAX_SCAN] & 0x1f) + 1) << double_scan)
-            - 1;
-    } else {
-        /* in CGA modes, multi_scan is ignored */
-        /* XXX: is it correct ? */
-        multi_scan = double_scan;
-    }
-    multi_run = multi_scan;
-    if (shift_control != s->shift_control ||
-        double_scan != s->double_scan) {
-        full_update = 1;
-        s->shift_control = shift_control;
-        s->double_scan = double_scan;
-    }
-
-    if (shift_control == 0) {
-        if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) {
-            disp_width <<= 1;
-        }
-    } else if (shift_control == 1) {
-        if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) {
-            disp_width <<= 1;
-        }
-    }
-
-    depth = s->get_bpp(s);
-    if (s->line_offset != s->last_line_offset ||
-        disp_width != s->last_width ||
-        height != s->last_height ||
-        s->last_depth != depth) {
-        if (depth == 32 || (depth == 16 && !byteswap)) {
-            surface = qemu_create_displaysurface_from(disp_width,
-                    height, depth, s->line_offset,
-                    s->vram_ptr + (s->start_addr * 4), byteswap);
-            dpy_gfx_replace_surface(s->con, surface);
-        } else {
-            qemu_console_resize(s->con, disp_width, height);
-            surface = qemu_console_surface(s->con);
-        }
-        s->last_scr_width = disp_width;
-        s->last_scr_height = height;
-        s->last_width = disp_width;
-        s->last_height = height;
-        s->last_line_offset = s->line_offset;
-        s->last_depth = depth;
-        full_update = 1;
-    } else if (is_buffer_shared(surface) &&
-               (full_update || surface_data(surface) != s->vram_ptr
-                + (s->start_addr * 4))) {
-        DisplaySurface *surface;
-        surface = qemu_create_displaysurface_from(disp_width,
-                height, depth, s->line_offset,
-                s->vram_ptr + (s->start_addr * 4), byteswap);
-        dpy_gfx_replace_surface(s->con, surface);
-    }
-
-    s->rgb_to_pixel =
-        rgb_to_pixel_dup_table[get_depth_index(surface)];
-
-    if (shift_control == 0) {
-        full_update |= update_palette16(s);
-        if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) {
-            v = VGA_DRAW_LINE4D2;
-        } else {
-            v = VGA_DRAW_LINE4;
-        }
-        bits = 4;
-    } else if (shift_control == 1) {
-        full_update |= update_palette16(s);
-        if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) {
-            v = VGA_DRAW_LINE2D2;
-        } else {
-            v = VGA_DRAW_LINE2;
-        }
-        bits = 4;
-    } else {
-        switch(s->get_bpp(s)) {
-        default:
-        case 0:
-            full_update |= update_palette256(s);
-            v = VGA_DRAW_LINE8D2;
-            bits = 4;
-            break;
-        case 8:
-            full_update |= update_palette256(s);
-            v = VGA_DRAW_LINE8;
-            bits = 8;
-            break;
-        case 15:
-            v = VGA_DRAW_LINE15;
-            bits = 16;
-            break;
-        case 16:
-            v = VGA_DRAW_LINE16;
-            bits = 16;
-            break;
-        case 24:
-            v = VGA_DRAW_LINE24;
-            bits = 24;
-            break;
-        case 32:
-            v = VGA_DRAW_LINE32;
-            bits = 32;
-            break;
-        }
-    }
-    vga_draw_line = vga_draw_line_table[v * NB_DEPTHS +
-                                        get_depth_index(surface)];
-
-    if (!is_buffer_shared(surface) && s->cursor_invalidate) {
-        s->cursor_invalidate(s);
-    }
-
-    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[VGA_CRTC_MODE],
-           s->line_compare, s->sr[VGA_SEQ_CLOCK_MODE]);
-#endif
-    addr1 = (s->start_addr * 4);
-    bwidth = (width * bits + 7) / 8;
-    y_start = -1;
-    page_min = -1;
-    page_max = 0;
-    d = surface_data(surface);
-    linesize = surface_stride(surface);
-    y1 = 0;
-    for(y = 0; y < height; y++) {
-        addr = addr1;
-        if (!(s->cr[VGA_CRTC_MODE] & 1)) {
-            int shift;
-            /* CGA compatibility handling */
-            shift = 14 + ((s->cr[VGA_CRTC_MODE] >> 6) & 1);
-            addr = (addr & ~(1 << shift)) | ((y1 & 1) << shift);
-        }
-        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);
-        /* explicit invalidation for the hardware cursor */
-        update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1;
-        if (update) {
-            if (y_start < 0)
-                y_start = y;
-            if (page0 < page_min)
-                page_min = page0;
-            if (page1 > page_max)
-                page_max = page1;
-            if (!(is_buffer_shared(surface))) {
-                vga_draw_line(s, d, s->vram_ptr + addr, width);
-                if (s->cursor_draw_line)
-                    s->cursor_draw_line(s, d, y);
-            }
-        } else {
-            if (y_start >= 0) {
-                /* flush to display */
-                dpy_gfx_update(s->con, 0, y_start,
-                               disp_width, y - y_start);
-                y_start = -1;
-            }
-        }
-        if (!multi_run) {
-            mask = (s->cr[VGA_CRTC_MODE] & 3) ^ 3;
-            if ((y1 & mask) == mask)
-                addr1 += line_offset;
-            y1++;
-            multi_run = multi_scan;
-        } else {
-            multi_run--;
-        }
-        /* line compare acts on the displayed lines */
-        if (y == s->line_compare)
-            addr1 = 0;
-        d += linesize;
-    }
-    if (y_start >= 0) {
-        /* flush to display */
-        dpy_gfx_update(s->con, 0, y_start,
-                       disp_width, y - y_start);
-    }
-    /* reset modified pages */
-    if (page_max >= page_min) {
-        memory_region_reset_dirty(&s->vram,
-                                  page_min,
-                                  page_max - page_min,
-                                  DIRTY_MEMORY_VGA);
-    }
-    memset(s->invalidated_y_table, 0, ((height + 31) >> 5) * 4);
-}
-
-static void vga_draw_blank(VGACommonState *s, int full_update)
-{
-    DisplaySurface *surface = qemu_console_surface(s->con);
-    int i, w, val;
-    uint8_t *d;
-
-    if (!full_update)
-        return;
-    if (s->last_scr_width <= 0 || s->last_scr_height <= 0)
-        return;
-
-    s->rgb_to_pixel =
-        rgb_to_pixel_dup_table[get_depth_index(surface)];
-    if (surface_bits_per_pixel(surface) == 8) {
-        val = s->rgb_to_pixel(0, 0, 0);
-    } else {
-        val = 0;
-    }
-    w = s->last_scr_width * surface_bytes_per_pixel(surface);
-    d = surface_data(surface);
-    for(i = 0; i < s->last_scr_height; i++) {
-        memset(d, val, w);
-        d += surface_stride(surface);
-    }
-    dpy_gfx_update(s->con, 0, 0,
-                   s->last_scr_width, s->last_scr_height);
-}
-
-#define GMODE_TEXT     0
-#define GMODE_GRAPH    1
-#define GMODE_BLANK 2
-
-static void vga_update_display(void *opaque)
-{
-    VGACommonState *s = opaque;
-    DisplaySurface *surface = qemu_console_surface(s->con);
-    int full_update, graphic_mode;
-
-    qemu_flush_coalesced_mmio_buffer();
-
-    if (surface_bits_per_pixel(surface) == 0) {
-        /* nothing to do */
-    } else {
-        full_update = 0;
-        if (!(s->ar_index & 0x20)) {
-            graphic_mode = GMODE_BLANK;
-        } else {
-            graphic_mode = s->gr[VGA_GFX_MISC] & VGA_GR06_GRAPHICS_MODE;
-        }
-        if (graphic_mode != s->graphic_mode) {
-            s->graphic_mode = graphic_mode;
-            s->cursor_blink_time = qemu_get_clock_ms(vm_clock);
-            full_update = 1;
-        }
-        switch(graphic_mode) {
-        case GMODE_TEXT:
-            vga_draw_text(s, full_update);
-            break;
-        case GMODE_GRAPH:
-            vga_draw_graphic(s, full_update);
-            break;
-        case GMODE_BLANK:
-        default:
-            vga_draw_blank(s, full_update);
-            break;
-        }
-    }
-}
-
-/* force a full display refresh */
-static void vga_invalidate_display(void *opaque)
-{
-    VGACommonState *s = opaque;
-
-    s->last_width = -1;
-    s->last_height = -1;
-}
-
-void vga_common_reset(VGACommonState *s)
-{
-    s->sr_index = 0;
-    memset(s->sr, '\0', sizeof(s->sr));
-    s->gr_index = 0;
-    memset(s->gr, '\0', sizeof(s->gr));
-    s->ar_index = 0;
-    memset(s->ar, '\0', sizeof(s->ar));
-    s->ar_flip_flop = 0;
-    s->cr_index = 0;
-    memset(s->cr, '\0', sizeof(s->cr));
-    s->msr = 0;
-    s->fcr = 0;
-    s->st00 = 0;
-    s->st01 = 0;
-    s->dac_state = 0;
-    s->dac_sub_index = 0;
-    s->dac_read_index = 0;
-    s->dac_write_index = 0;
-    memset(s->dac_cache, '\0', sizeof(s->dac_cache));
-    s->dac_8bit = 0;
-    memset(s->palette, '\0', sizeof(s->palette));
-    s->bank_offset = 0;
-    s->vbe_index = 0;
-    memset(s->vbe_regs, '\0', sizeof(s->vbe_regs));
-    s->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID5;
-    s->vbe_start_addr = 0;
-    s->vbe_line_offset = 0;
-    s->vbe_bank_mask = (s->vram_size >> 16) - 1;
-    memset(s->font_offsets, '\0', sizeof(s->font_offsets));
-    s->graphic_mode = -1; /* force full update */
-    s->shift_control = 0;
-    s->double_scan = 0;
-    s->line_offset = 0;
-    s->line_compare = 0;
-    s->start_addr = 0;
-    s->plane_updated = 0;
-    s->last_cw = 0;
-    s->last_ch = 0;
-    s->last_width = 0;
-    s->last_height = 0;
-    s->last_scr_width = 0;
-    s->last_scr_height = 0;
-    s->cursor_start = 0;
-    s->cursor_end = 0;
-    s->cursor_offset = 0;
-    memset(s->invalidated_y_table, '\0', sizeof(s->invalidated_y_table));
-    memset(s->last_palette, '\0', sizeof(s->last_palette));
-    memset(s->last_ch_attr, '\0', sizeof(s->last_ch_attr));
-    switch (vga_retrace_method) {
-    case VGA_RETRACE_DUMB:
-        break;
-    case VGA_RETRACE_PRECISE:
-        memset(&s->retrace_info, 0, sizeof (s->retrace_info));
-        break;
-    }
-    vga_update_memory_access(s);
-}
-
-static void vga_reset(void *opaque)
-{
-    VGACommonState *s =  opaque;
-    vga_common_reset(s);
-}
-
-#define TEXTMODE_X(x)  ((x) % width)
-#define TEXTMODE_Y(x)  ((x) / width)
-#define VMEM2CHTYPE(v) ((v & 0xff0007ff) | \
-        ((v & 0x00000800) << 10) | ((v & 0x00007000) >> 1))
-/* relay text rendering to the display driver
- * instead of doing a full vga_update_display() */
-static void vga_update_text(void *opaque, console_ch_t *chardata)
-{
-    VGACommonState *s =  opaque;
-    int graphic_mode, i, cursor_offset, cursor_visible;
-    int cw, cheight, width, height, size, c_min, c_max;
-    uint32_t *src;
-    console_ch_t *dst, val;
-    char msg_buffer[80];
-    int full_update = 0;
-
-    qemu_flush_coalesced_mmio_buffer();
-
-    if (!(s->ar_index & 0x20)) {
-        graphic_mode = GMODE_BLANK;
-    } else {
-        graphic_mode = s->gr[VGA_GFX_MISC] & VGA_GR06_GRAPHICS_MODE;
-    }
-    if (graphic_mode != s->graphic_mode) {
-        s->graphic_mode = graphic_mode;
-        full_update = 1;
-    }
-    if (s->last_width == -1) {
-        s->last_width = 0;
-        full_update = 1;
-    }
-
-    switch (graphic_mode) {
-    case GMODE_TEXT:
-        /* TODO: update palette */
-        full_update |= update_basic_params(s);
-
-        /* total width & height */
-        cheight = (s->cr[VGA_CRTC_MAX_SCAN] & 0x1f) + 1;
-        cw = 8;
-        if (!(s->sr[VGA_SEQ_CLOCK_MODE] & VGA_SR01_CHAR_CLK_8DOTS)) {
-            cw = 9;
-        }
-        if (s->sr[VGA_SEQ_CLOCK_MODE] & 0x08) {
-            cw = 16; /* NOTE: no 18 pixel wide */
-        }
-        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[VGA_CRTC_V_DISP_END] |
-                ((s->cr[VGA_CRTC_OVERFLOW] & 0x02) << 7) |
-                ((s->cr[VGA_CRTC_OVERFLOW] & 0x40) << 3);
-            height = (height + 1) / cheight;
-        }
-
-        size = (height * width);
-        if (size > CH_ATTR_SIZE) {
-            if (!full_update)
-                return;
-
-            snprintf(msg_buffer, sizeof(msg_buffer), "%i x %i Text mode",
-                     width, height);
-            break;
-        }
-
-        if (width != s->last_width || height != s->last_height ||
-            cw != s->last_cw || cheight != s->last_ch) {
-            s->last_scr_width = width * cw;
-            s->last_scr_height = height * cheight;
-            qemu_console_resize(s->con, s->last_scr_width, s->last_scr_height);
-            dpy_text_resize(s->con, width, height);
-            s->last_depth = 0;
-            s->last_width = width;
-            s->last_height = height;
-            s->last_ch = cheight;
-            s->last_cw = cw;
-            full_update = 1;
-        }
-
-        if (full_update) {
-            s->full_update_gfx = 1;
-        }
-        if (s->full_update_text) {
-            s->full_update_text = 0;
-            full_update |= 1;
-        }
-
-        /* Update "hardware" cursor */
-        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[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_text_cursor(s->con,
-                                TEXTMODE_X(cursor_offset),
-                                TEXTMODE_Y(cursor_offset));
-            else
-                dpy_text_cursor(s->con, -1, -1);
-            s->cursor_offset = cursor_offset;
-            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;
-        dst = chardata;
-
-        if (full_update) {
-            for (i = 0; i < size; src ++, dst ++, i ++)
-                console_write_ch(dst, VMEM2CHTYPE(le32_to_cpu(*src)));
-
-            dpy_text_update(s->con, 0, 0, width, height);
-        } else {
-            c_max = 0;
-
-            for (i = 0; i < size; src ++, dst ++, i ++) {
-                console_write_ch(&val, VMEM2CHTYPE(le32_to_cpu(*src)));
-                if (*dst != val) {
-                    *dst = val;
-                    c_max = i;
-                    break;
-                }
-            }
-            c_min = i;
-            for (; i < size; src ++, dst ++, i ++) {
-                console_write_ch(&val, VMEM2CHTYPE(le32_to_cpu(*src)));
-                if (*dst != val) {
-                    *dst = val;
-                    c_max = i;
-                }
-            }
-
-            if (c_min <= c_max) {
-                i = TEXTMODE_Y(c_min);
-                dpy_text_update(s->con, 0, i, width, TEXTMODE_Y(c_max) - i + 1);
-            }
-        }
-
-        return;
-    case GMODE_GRAPH:
-        if (!full_update)
-            return;
-
-        s->get_resolution(s, &width, &height);
-        snprintf(msg_buffer, sizeof(msg_buffer), "%i x %i Graphic mode",
-                 width, height);
-        break;
-    case GMODE_BLANK:
-    default:
-        if (!full_update)
-            return;
-
-        snprintf(msg_buffer, sizeof(msg_buffer), "VGA Blank mode");
-        break;
-    }
-
-    /* Display a message */
-    s->last_width = 60;
-    s->last_height = height = 3;
-    dpy_text_cursor(s->con, -1, -1);
-    dpy_text_resize(s->con, s->last_width, height);
-
-    for (dst = chardata, i = 0; i < s->last_width * height; i ++)
-        console_write_ch(dst ++, ' ');
-
-    size = strlen(msg_buffer);
-    width = (s->last_width - size) / 2;
-    dst = chardata + s->last_width + width;
-    for (i = 0; i < size; i ++)
-        console_write_ch(dst ++, 0x00200100 | msg_buffer[i]);
-
-    dpy_text_update(s->con, 0, 0, s->last_width, height);
-}
-
-static uint64_t vga_mem_read(void *opaque, hwaddr addr,
-                             unsigned size)
-{
-    VGACommonState *s = opaque;
-
-    return vga_mem_readb(s, addr);
-}
-
-static void vga_mem_write(void *opaque, hwaddr addr,
-                          uint64_t data, unsigned size)
-{
-    VGACommonState *s = opaque;
-
-    return vga_mem_writeb(s, addr, data);
-}
-
-const MemoryRegionOps vga_mem_ops = {
-    .read = vga_mem_read,
-    .write = vga_mem_write,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-    .impl = {
-        .min_access_size = 1,
-        .max_access_size = 1,
-    },
-};
-
-static int vga_common_post_load(void *opaque, int version_id)
-{
-    VGACommonState *s = opaque;
-
-    /* force refresh */
-    s->graphic_mode = -1;
-    return 0;
-}
-
-const VMStateDescription vmstate_vga_common = {
-    .name = "vga",
-    .version_id = 2,
-    .minimum_version_id = 2,
-    .minimum_version_id_old = 2,
-    .post_load = vga_common_post_load,
-    .fields      = (VMStateField []) {
-        VMSTATE_UINT32(latch, VGACommonState),
-        VMSTATE_UINT8(sr_index, VGACommonState),
-        VMSTATE_PARTIAL_BUFFER(sr, VGACommonState, 8),
-        VMSTATE_UINT8(gr_index, VGACommonState),
-        VMSTATE_PARTIAL_BUFFER(gr, VGACommonState, 16),
-        VMSTATE_UINT8(ar_index, VGACommonState),
-        VMSTATE_BUFFER(ar, VGACommonState),
-        VMSTATE_INT32(ar_flip_flop, VGACommonState),
-        VMSTATE_UINT8(cr_index, VGACommonState),
-        VMSTATE_BUFFER(cr, VGACommonState),
-        VMSTATE_UINT8(msr, VGACommonState),
-        VMSTATE_UINT8(fcr, VGACommonState),
-        VMSTATE_UINT8(st00, VGACommonState),
-        VMSTATE_UINT8(st01, VGACommonState),
-
-        VMSTATE_UINT8(dac_state, VGACommonState),
-        VMSTATE_UINT8(dac_sub_index, VGACommonState),
-        VMSTATE_UINT8(dac_read_index, VGACommonState),
-        VMSTATE_UINT8(dac_write_index, VGACommonState),
-        VMSTATE_BUFFER(dac_cache, VGACommonState),
-        VMSTATE_BUFFER(palette, VGACommonState),
-
-        VMSTATE_INT32(bank_offset, VGACommonState),
-        VMSTATE_UINT8_EQUAL(is_vbe_vmstate, VGACommonState),
-        VMSTATE_UINT16(vbe_index, VGACommonState),
-        VMSTATE_UINT16_ARRAY(vbe_regs, VGACommonState, VBE_DISPI_INDEX_NB),
-        VMSTATE_UINT32(vbe_start_addr, VGACommonState),
-        VMSTATE_UINT32(vbe_line_offset, VGACommonState),
-        VMSTATE_UINT32(vbe_bank_mask, VGACommonState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-void vga_common_init(VGACommonState *s)
-{
-    int i, j, v, b;
-
-    for(i = 0;i < 256; i++) {
-        v = 0;
-        for(j = 0; j < 8; j++) {
-            v |= ((i >> j) & 1) << (j * 4);
-        }
-        expand4[i] = v;
-
-        v = 0;
-        for(j = 0; j < 4; j++) {
-            v |= ((i >> (2 * j)) & 3) << (j * 4);
-        }
-        expand2[i] = v;
-    }
-    for(i = 0; i < 16; i++) {
-        v = 0;
-        for(j = 0; j < 4; j++) {
-            b = ((i >> j) & 1);
-            v |= b << (2 * j);
-            v |= b << (2 * j + 1);
-        }
-        expand4to8[i] = v;
-    }
-
-    /* valid range: 1 MB -> 256 MB */
-    s->vram_size = 1024 * 1024;
-    while (s->vram_size < (s->vram_size_mb << 20) &&
-           s->vram_size < (256 << 20)) {
-        s->vram_size <<= 1;
-    }
-    s->vram_size_mb = s->vram_size >> 20;
-
-    s->is_vbe_vmstate = 1;
-    memory_region_init_ram(&s->vram, "vga.vram", s->vram_size);
-    vmstate_register_ram_global(&s->vram);
-    xen_register_framebuffer(&s->vram);
-    s->vram_ptr = memory_region_get_ram_ptr(&s->vram);
-    s->get_bpp = vga_get_bpp;
-    s->get_offsets = vga_get_offsets;
-    s->get_resolution = vga_get_resolution;
-    s->update = vga_update_display;
-    s->invalidate = vga_invalidate_display;
-    s->screen_dump = vga_screen_dump;
-    s->text_update = vga_update_text;
-    switch (vga_retrace_method) {
-    case VGA_RETRACE_DUMB:
-        s->retrace = vga_dumb_retrace;
-        s->update_retrace_info = vga_dumb_update_retrace_info;
-        break;
-
-    case VGA_RETRACE_PRECISE:
-        s->retrace = vga_precise_retrace;
-        s->update_retrace_info = vga_precise_update_retrace_info;
-        break;
-    }
-    vga_dirty_log_start(s);
-}
-
-static const MemoryRegionPortio vga_portio_list[] = {
-    { 0x04,  2, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3b4 */
-    { 0x0a,  1, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3ba */
-    { 0x10, 16, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3c0 */
-    { 0x24,  2, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3d4 */
-    { 0x2a,  1, 1, .read = vga_ioport_read, .write = vga_ioport_write }, /* 3da */
-    PORTIO_END_OF_LIST(),
-};
-
-static const MemoryRegionPortio vbe_portio_list[] = {
-    { 0, 1, 2, .read = vbe_ioport_read_index, .write = vbe_ioport_write_index },
-# ifdef TARGET_I386
-    { 1, 1, 2, .read = vbe_ioport_read_data, .write = vbe_ioport_write_data },
-# endif
-    { 2, 1, 2, .read = vbe_ioport_read_data, .write = vbe_ioport_write_data },
-    PORTIO_END_OF_LIST(),
-};
-
-/* Used by both ISA and PCI */
-MemoryRegion *vga_init_io(VGACommonState *s,
-                          const MemoryRegionPortio **vga_ports,
-                          const MemoryRegionPortio **vbe_ports)
-{
-    MemoryRegion *vga_mem;
-
-    *vga_ports = vga_portio_list;
-    *vbe_ports = vbe_portio_list;
-
-    vga_mem = g_malloc(sizeof(*vga_mem));
-    memory_region_init_io(vga_mem, &vga_mem_ops, s,
-                          "vga-lowmem", 0x20000);
-    memory_region_set_flush_coalesced(vga_mem);
-
-    return vga_mem;
-}
-
-void vga_init(VGACommonState *s, MemoryRegion *address_space,
-              MemoryRegion *address_space_io, bool init_vga_ports)
-{
-    MemoryRegion *vga_io_memory;
-    const MemoryRegionPortio *vga_ports, *vbe_ports;
-    PortioList *vga_port_list = g_new(PortioList, 1);
-    PortioList *vbe_port_list = g_new(PortioList, 1);
-
-    qemu_register_reset(vga_reset, s);
-
-    s->bank_offset = 0;
-
-    s->legacy_address_space = address_space;
-
-    vga_io_memory = vga_init_io(s, &vga_ports, &vbe_ports);
-    memory_region_add_subregion_overlap(address_space,
-                                        isa_mem_base + 0x000a0000,
-                                        vga_io_memory,
-                                        1);
-    memory_region_set_coalescing(vga_io_memory);
-    if (init_vga_ports) {
-        portio_list_init(vga_port_list, vga_ports, s, "vga");
-        portio_list_add(vga_port_list, address_space_io, 0x3b0);
-    }
-    if (vbe_ports) {
-        portio_list_init(vbe_port_list, vbe_ports, s, "vbe");
-        portio_list_add(vbe_port_list, address_space_io, 0x1ce);
-    }
-}
-
-void vga_init_vbe(VGACommonState *s, MemoryRegion *system_memory)
-{
-    /* With pc-0.12 and below we map both the PCI BAR and the fixed VBE region,
-     * so use an alias to avoid double-mapping the same region.
-     */
-    memory_region_init_alias(&s->vram_vbe, "vram.vbe",
-                             &s->vram, 0, memory_region_size(&s->vram));
-    /* XXX: use optimized standard vga accesses */
-    memory_region_add_subregion(system_memory,
-                                VBE_DISPI_LFB_PHYSICAL_ADDRESS,
-                                &s->vram_vbe);
-    s->vbe_mapped = 1;
-}
-/********************************************************/
-/* vga screen dump */
-
-void ppm_save(const char *filename, struct DisplaySurface *ds, Error **errp)
-{
-    int width = pixman_image_get_width(ds->image);
-    int height = pixman_image_get_height(ds->image);
-    FILE *f;
-    int y;
-    int ret;
-    pixman_image_t *linebuf;
-
-    trace_ppm_save(filename, ds);
-    f = fopen(filename, "wb");
-    if (!f) {
-        error_setg(errp, "failed to open file '%s': %s", filename,
-                   strerror(errno));
-        return;
-    }
-    ret = fprintf(f, "P6\n%d %d\n%d\n", width, height, 255);
-    if (ret < 0) {
-        linebuf = NULL;
-        goto write_err;
-    }
-    linebuf = qemu_pixman_linebuf_create(PIXMAN_BE_r8g8b8, width);
-    for (y = 0; y < height; y++) {
-        qemu_pixman_linebuf_fill(linebuf, ds->image, width, 0, y);
-        clearerr(f);
-        ret = fwrite(pixman_image_get_data(linebuf), 1,
-                     pixman_image_get_stride(linebuf), f);
-        (void)ret;
-        if (ferror(f)) {
-            goto write_err;
-        }
-    }
-
-out:
-    qemu_pixman_image_unref(linebuf);
-    fclose(f);
-    return;
-
-write_err:
-    error_setg(errp, "failed to write to file '%s': %s", filename,
-               strerror(errno));
-    unlink(filename);
-    goto out;
-}
-
-/* save the vga display in a PPM image even if no display is
-   available */
-static void vga_screen_dump(void *opaque, const char *filename, bool cswitch,
-                            Error **errp)
-{
-    VGACommonState *s = opaque;
-    DisplaySurface *surface = qemu_console_surface(s->con);
-
-    if (cswitch) {
-        vga_invalidate_display(s);
-    }
-    vga_hw_update();
-    ppm_save(filename, surface, errp);
-}
diff --git a/hw/vga.h b/hw/vga.h
deleted file mode 100644 (file)
index d917046..0000000
--- a/hw/vga.h
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * linux/include/video/vga.h -- standard VGA chipset interaction
- *
- * Copyright 1999 Jeff Garzik <jgarzik@pobox.com>
- *
- * Copyright history from vga16fb.c:
- *     Copyright 1999 Ben Pfaff and Petr Vandrovec
- *     Based on VGA info at http://www.osdever.net/FreeVGA/home.htm
- *     Based on VESA framebuffer (c) 1998 Gerd Knorr
- *
- * This file is subject to the terms and conditions of the GNU General
- * Public License.  See the file COPYING in the main directory of this
- * archive for more details.
- *
- */
-
-#ifndef __linux_video_vga_h__
-#define __linux_video_vga_h__
-
-/* Some of the code below is taken from SVGAlib.  The original,
-   unmodified copyright notice for that code is below. */
-/* VGAlib version 1.2 - (c) 1993 Tommy Frandsen                    */
-/*                                                                 */
-/* This library is free software; you can redistribute it and/or   */
-/* modify it without any restrictions. This library is distributed */
-/* in the hope that it will be useful, but without any warranty.   */
-
-/* Multi-chipset support Copyright 1993 Harm Hanemaayer */
-/* partially copyrighted (C) 1993 by Hartmut Schirmer */
-
-/* VGA data register ports */
-#define VGA_CRT_DC      0x3D5   /* CRT Controller Data Register - color emulation */
-#define VGA_CRT_DM      0x3B5   /* CRT Controller Data Register - mono emulation */
-#define VGA_ATT_R       0x3C1   /* Attribute Controller Data Read Register */
-#define VGA_ATT_W       0x3C0   /* Attribute Controller Data Write Register */
-#define VGA_GFX_D       0x3CF   /* Graphics Controller Data Register */
-#define VGA_SEQ_D       0x3C5   /* Sequencer Data Register */
-#define VGA_MIS_R       0x3CC   /* Misc Output Read Register */
-#define VGA_MIS_W       0x3C2   /* Misc Output Write Register */
-#define VGA_FTC_R       0x3CA   /* Feature Control Read Register */
-#define VGA_IS1_RC      0x3DA   /* Input Status Register 1 - color emulation */
-#define VGA_IS1_RM      0x3BA   /* Input Status Register 1 - mono emulation */
-#define VGA_PEL_D       0x3C9   /* PEL Data Register */
-#define VGA_PEL_MSK     0x3C6   /* PEL mask register */
-
-/* EGA-specific registers */
-#define EGA_GFX_E0      0x3CC   /* Graphics enable processor 0 */
-#define EGA_GFX_E1      0x3CA   /* Graphics enable processor 1 */
-
-/* VGA index register ports */
-#define VGA_CRT_IC      0x3D4   /* CRT Controller Index - color emulation */
-#define VGA_CRT_IM      0x3B4   /* CRT Controller Index - mono emulation */
-#define VGA_ATT_IW      0x3C0   /* Attribute Controller Index & Data Write Register */
-#define VGA_GFX_I       0x3CE   /* Graphics Controller Index */
-#define VGA_SEQ_I       0x3C4   /* Sequencer Index */
-#define VGA_PEL_IW      0x3C8   /* PEL Write Index */
-#define VGA_PEL_IR      0x3C7   /* PEL Read Index */
-
-/* standard VGA indexes max counts */
-#define VGA_CRT_C       0x19    /* Number of CRT Controller Registers */
-#define VGA_ATT_C       0x15    /* Number of Attribute Controller Registers */
-#define VGA_GFX_C       0x09    /* Number of Graphics Controller Registers */
-#define VGA_SEQ_C       0x05    /* Number of Sequencer Registers */
-#define VGA_MIS_C       0x01    /* Number of Misc Output Register */
-
-/* VGA misc register bit masks */
-#define VGA_MIS_COLOR           0x01
-#define VGA_MIS_ENB_MEM_ACCESS  0x02
-#define VGA_MIS_DCLK_28322_720  0x04
-#define VGA_MIS_ENB_PLL_LOAD    (0x04 | 0x08)
-#define VGA_MIS_SEL_HIGH_PAGE   0x20
-
-/* VGA CRT controller register indices */
-#define VGA_CRTC_H_TOTAL        0
-#define VGA_CRTC_H_DISP         1
-#define VGA_CRTC_H_BLANK_START  2
-#define VGA_CRTC_H_BLANK_END    3
-#define VGA_CRTC_H_SYNC_START   4
-#define VGA_CRTC_H_SYNC_END     5
-#define VGA_CRTC_V_TOTAL        6
-#define VGA_CRTC_OVERFLOW       7
-#define VGA_CRTC_PRESET_ROW     8
-#define VGA_CRTC_MAX_SCAN       9
-#define VGA_CRTC_CURSOR_START   0x0A
-#define VGA_CRTC_CURSOR_END     0x0B
-#define VGA_CRTC_START_HI       0x0C
-#define VGA_CRTC_START_LO       0x0D
-#define VGA_CRTC_CURSOR_HI      0x0E
-#define VGA_CRTC_CURSOR_LO      0x0F
-#define VGA_CRTC_V_SYNC_START   0x10
-#define VGA_CRTC_V_SYNC_END     0x11
-#define VGA_CRTC_V_DISP_END     0x12
-#define VGA_CRTC_OFFSET         0x13
-#define VGA_CRTC_UNDERLINE      0x14
-#define VGA_CRTC_V_BLANK_START  0x15
-#define VGA_CRTC_V_BLANK_END    0x16
-#define VGA_CRTC_MODE           0x17
-#define VGA_CRTC_LINE_COMPARE   0x18
-#define VGA_CRTC_REGS           VGA_CRT_C
-
-/* VGA CRT controller bit masks */
-#define VGA_CR11_LOCK_CR0_CR7   0x80 /* lock writes to CR0 - CR7 */
-#define VGA_CR17_H_V_SIGNALS_ENABLED 0x80
-
-/* VGA attribute controller register indices */
-#define VGA_ATC_PALETTE0        0x00
-#define VGA_ATC_PALETTE1        0x01
-#define VGA_ATC_PALETTE2        0x02
-#define VGA_ATC_PALETTE3        0x03
-#define VGA_ATC_PALETTE4        0x04
-#define VGA_ATC_PALETTE5        0x05
-#define VGA_ATC_PALETTE6        0x06
-#define VGA_ATC_PALETTE7        0x07
-#define VGA_ATC_PALETTE8        0x08
-#define VGA_ATC_PALETTE9        0x09
-#define VGA_ATC_PALETTEA        0x0A
-#define VGA_ATC_PALETTEB        0x0B
-#define VGA_ATC_PALETTEC        0x0C
-#define VGA_ATC_PALETTED        0x0D
-#define VGA_ATC_PALETTEE        0x0E
-#define VGA_ATC_PALETTEF        0x0F
-#define VGA_ATC_MODE            0x10
-#define VGA_ATC_OVERSCAN        0x11
-#define VGA_ATC_PLANE_ENABLE    0x12
-#define VGA_ATC_PEL             0x13
-#define VGA_ATC_COLOR_PAGE      0x14
-
-#define VGA_AR_ENABLE_DISPLAY   0x20
-
-/* VGA sequencer register indices */
-#define VGA_SEQ_RESET           0x00
-#define VGA_SEQ_CLOCK_MODE      0x01
-#define VGA_SEQ_PLANE_WRITE     0x02
-#define VGA_SEQ_CHARACTER_MAP   0x03
-#define VGA_SEQ_MEMORY_MODE     0x04
-
-/* VGA sequencer register bit masks */
-#define VGA_SR01_CHAR_CLK_8DOTS 0x01 /* bit 0: character clocks 8 dots wide are generated */
-#define VGA_SR01_SCREEN_OFF     0x20 /* bit 5: Screen is off */
-#define VGA_SR02_ALL_PLANES     0x0F /* bits 3-0: enable access to all planes */
-#define VGA_SR04_EXT_MEM        0x02 /* bit 1: allows complete mem access to 256K */
-#define VGA_SR04_SEQ_MODE       0x04 /* bit 2: directs system to use a sequential addressing mode */
-#define VGA_SR04_CHN_4M         0x08 /* bit 3: selects modulo 4 addressing for CPU access to display memory */
-
-/* VGA graphics controller register indices */
-#define VGA_GFX_SR_VALUE        0x00
-#define VGA_GFX_SR_ENABLE       0x01
-#define VGA_GFX_COMPARE_VALUE   0x02
-#define VGA_GFX_DATA_ROTATE     0x03
-#define VGA_GFX_PLANE_READ      0x04
-#define VGA_GFX_MODE            0x05
-#define VGA_GFX_MISC            0x06
-#define VGA_GFX_COMPARE_MASK    0x07
-#define VGA_GFX_BIT_MASK        0x08
-
-/* VGA graphics controller bit masks */
-#define VGA_GR06_GRAPHICS_MODE  0x01
-
-#endif /* __linux_video_vga_h__ */
diff --git a/hw/vga_int.h b/hw/vga_int.h
deleted file mode 100644 (file)
index 260f7d6..0000000
+++ /dev/null
@@ -1,218 +0,0 @@
-/*
- * QEMU internal VGA defines.
- *
- * 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_VGA_INT_H
-#define HW_VGA_INT_H 1
-
-#include <hw/hw.h>
-#include "qapi/error.h"
-#include "exec/memory.h"
-
-#define ST01_V_RETRACE      0x08
-#define ST01_DISP_ENABLE    0x01
-
-#define VBE_DISPI_MAX_XRES              16000
-#define VBE_DISPI_MAX_YRES              12000
-#define VBE_DISPI_MAX_BPP               32
-
-#define VBE_DISPI_INDEX_ID              0x0
-#define VBE_DISPI_INDEX_XRES            0x1
-#define VBE_DISPI_INDEX_YRES            0x2
-#define VBE_DISPI_INDEX_BPP             0x3
-#define VBE_DISPI_INDEX_ENABLE          0x4
-#define VBE_DISPI_INDEX_BANK            0x5
-#define VBE_DISPI_INDEX_VIRT_WIDTH      0x6
-#define VBE_DISPI_INDEX_VIRT_HEIGHT     0x7
-#define VBE_DISPI_INDEX_X_OFFSET        0x8
-#define VBE_DISPI_INDEX_Y_OFFSET        0x9
-#define VBE_DISPI_INDEX_NB              0xa /* size of vbe_regs[] */
-#define VBE_DISPI_INDEX_VIDEO_MEMORY_64K 0xa /* read-only, not in vbe_regs */
-
-#define VBE_DISPI_ID0                   0xB0C0
-#define VBE_DISPI_ID1                   0xB0C1
-#define VBE_DISPI_ID2                   0xB0C2
-#define VBE_DISPI_ID3                   0xB0C3
-#define VBE_DISPI_ID4                   0xB0C4
-#define VBE_DISPI_ID5                   0xB0C5
-
-#define VBE_DISPI_DISABLED              0x00
-#define VBE_DISPI_ENABLED               0x01
-#define VBE_DISPI_GETCAPS               0x02
-#define VBE_DISPI_8BIT_DAC              0x20
-#define VBE_DISPI_LFB_ENABLED           0x40
-#define VBE_DISPI_NOCLEARMEM            0x80
-
-#define VBE_DISPI_LFB_PHYSICAL_ADDRESS  0xE0000000
-
-#define CH_ATTR_SIZE (160 * 100)
-#define VGA_MAX_HEIGHT 2048
-
-struct vga_precise_retrace {
-    int64_t ticks_per_char;
-    int64_t total_chars;
-    int htotal;
-    int hstart;
-    int hend;
-    int vstart;
-    int vend;
-    int freq;
-};
-
-union vga_retrace {
-    struct vga_precise_retrace precise;
-};
-
-struct VGACommonState;
-typedef uint8_t (* vga_retrace_fn)(struct VGACommonState *s);
-typedef void (* vga_update_retrace_info_fn)(struct VGACommonState *s);
-
-typedef struct VGACommonState {
-    MemoryRegion *legacy_address_space;
-    uint8_t *vram_ptr;
-    MemoryRegion vram;
-    MemoryRegion vram_vbe;
-    uint32_t vram_size;
-    uint32_t vram_size_mb; /* property */
-    uint32_t latch;
-    MemoryRegion *chain4_alias;
-    uint8_t sr_index;
-    uint8_t sr[256];
-    uint8_t gr_index;
-    uint8_t gr[256];
-    uint8_t ar_index;
-    uint8_t ar[21];
-    int ar_flip_flop;
-    uint8_t cr_index;
-    uint8_t cr[256]; /* CRT registers */
-    uint8_t msr; /* Misc Output Register */
-    uint8_t fcr; /* Feature Control Register */
-    uint8_t st00; /* status 0 */
-    uint8_t st01; /* status 1 */
-    uint8_t dac_state;
-    uint8_t dac_sub_index;
-    uint8_t dac_read_index;
-    uint8_t dac_write_index;
-    uint8_t dac_cache[3]; /* used when writing */
-    int dac_8bit;
-    uint8_t palette[768];
-    int32_t bank_offset;
-    int (*get_bpp)(struct VGACommonState *s);
-    void (*get_offsets)(struct VGACommonState *s,
-                        uint32_t *pline_offset,
-                        uint32_t *pstart_addr,
-                        uint32_t *pline_compare);
-    void (*get_resolution)(struct VGACommonState *s,
-                        int *pwidth,
-                        int *pheight);
-    /* bochs vbe state */
-    uint16_t vbe_index;
-    uint16_t vbe_regs[VBE_DISPI_INDEX_NB];
-    uint32_t vbe_start_addr;
-    uint32_t vbe_line_offset;
-    uint32_t vbe_bank_mask;
-    int vbe_mapped;
-    /* display refresh support */
-    QemuConsole *con;
-    uint32_t font_offsets[2];
-    int graphic_mode;
-    uint8_t shift_control;
-    uint8_t double_scan;
-    uint32_t line_offset;
-    uint32_t line_compare;
-    uint32_t start_addr;
-    uint32_t plane_updated;
-    uint32_t last_line_offset;
-    uint8_t last_cw, last_ch;
-    uint32_t last_width, last_height; /* in chars or pixels */
-    uint32_t last_scr_width, last_scr_height; /* in pixels */
-    uint32_t last_depth; /* in bits */
-    uint8_t cursor_start, cursor_end;
-    bool cursor_visible_phase;
-    int64_t cursor_blink_time;
-    uint32_t cursor_offset;
-    unsigned int (*rgb_to_pixel)(unsigned int r,
-                                 unsigned int g, unsigned b);
-    vga_hw_update_ptr update;
-    vga_hw_invalidate_ptr invalidate;
-    vga_hw_screen_dump_ptr screen_dump;
-    vga_hw_text_update_ptr text_update;
-    bool full_update_text;
-    bool full_update_gfx;
-    /* hardware mouse cursor support */
-    uint32_t invalidated_y_table[VGA_MAX_HEIGHT / 32];
-    void (*cursor_invalidate)(struct VGACommonState *s);
-    void (*cursor_draw_line)(struct VGACommonState *s, uint8_t *d, int y);
-    /* tell for each page if it has been updated since the last time */
-    uint32_t last_palette[256];
-    uint32_t last_ch_attr[CH_ATTR_SIZE]; /* XXX: make it dynamic */
-    /* retrace */
-    vga_retrace_fn retrace;
-    vga_update_retrace_info_fn update_retrace_info;
-    union vga_retrace retrace_info;
-    uint8_t is_vbe_vmstate;
-} VGACommonState;
-
-static inline int c6_to_8(int v)
-{
-    int b;
-    v &= 0x3f;
-    b = v & 1;
-    return (v << 2) | (b << 1) | b;
-}
-
-void vga_common_init(VGACommonState *s);
-void vga_init(VGACommonState *s, MemoryRegion *address_space,
-              MemoryRegion *address_space_io, bool init_vga_ports);
-MemoryRegion *vga_init_io(VGACommonState *s,
-                          const MemoryRegionPortio **vga_ports,
-                          const MemoryRegionPortio **vbe_ports);
-void vga_common_reset(VGACommonState *s);
-
-void vga_sync_dirty_bitmap(VGACommonState *s);
-void vga_dirty_log_start(VGACommonState *s);
-void vga_dirty_log_stop(VGACommonState *s);
-
-extern const VMStateDescription vmstate_vga_common;
-uint32_t vga_ioport_read(void *opaque, uint32_t addr);
-void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val);
-uint32_t vga_mem_readb(VGACommonState *s, hwaddr addr);
-void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val);
-void vga_invalidate_scanlines(VGACommonState *s, int y1, int y2);
-void ppm_save(const char *filename, struct DisplaySurface *ds, Error **errp);
-
-int vga_ioport_invalid(VGACommonState *s, uint32_t addr);
-
-void vga_init_vbe(VGACommonState *s, MemoryRegion *address_space);
-uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr);
-void vbe_ioport_write_index(void *opaque, uint32_t addr, uint32_t val);
-void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val);
-
-extern const uint8_t sr_mask[8];
-extern const uint8_t gr_mask[16];
-
-#define VGABIOS_FILENAME "vgabios.bin"
-#define VGABIOS_CIRRUS_FILENAME "vgabios-cirrus.bin"
-
-extern const MemoryRegionOps vga_mem_ops;
-
-#endif
diff --git a/hw/vga_template.h b/hw/vga_template.h
deleted file mode 100644 (file)
index f6f6a01..0000000
+++ /dev/null
@@ -1,459 +0,0 @@
-/*
- * QEMU 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
-#define PIXEL_TYPE uint8_t
-#elif DEPTH == 15 || DEPTH == 16
-#define BPP 2
-#define PIXEL_TYPE uint16_t
-#elif DEPTH == 32
-#define BPP 4
-#define PIXEL_TYPE uint32_t
-#else
-#error unsupport depth
-#endif
-
-#ifdef BGR_FORMAT
-#define PIXEL_NAME glue(DEPTH, bgr)
-#else
-#define PIXEL_NAME DEPTH
-#endif /* BGR_FORMAT */
-
-#if DEPTH != 15 && !defined(BGR_FORMAT)
-
-static inline void glue(vga_draw_glyph_line_, DEPTH)(uint8_t *d,
-                                                     uint32_t font_data,
-                                                     uint32_t xorcol,
-                                                     uint32_t bgcol)
-{
-#if BPP == 1
-        ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
-        ((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
-#elif BPP == 2
-        ((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol;
-        ((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol;
-        ((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol;
-        ((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
-#else
-        ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
-        ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
-        ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
-        ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
-        ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
-        ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
-        ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
-        ((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
-#endif
-}
-
-static void glue(vga_draw_glyph8_, DEPTH)(uint8_t *d, int linesize,
-                                          const uint8_t *font_ptr, int h,
-                                          uint32_t fgcol, uint32_t bgcol)
-{
-    uint32_t font_data, xorcol;
-
-    xorcol = bgcol ^ fgcol;
-    do {
-        font_data = font_ptr[0];
-        glue(vga_draw_glyph_line_, DEPTH)(d, font_data, xorcol, bgcol);
-        font_ptr += 4;
-        d += linesize;
-    } while (--h);
-}
-
-static void glue(vga_draw_glyph16_, DEPTH)(uint8_t *d, int linesize,
-                                          const uint8_t *font_ptr, int h,
-                                          uint32_t fgcol, uint32_t bgcol)
-{
-    uint32_t font_data, xorcol;
-
-    xorcol = bgcol ^ fgcol;
-    do {
-        font_data = font_ptr[0];
-        glue(vga_draw_glyph_line_, DEPTH)(d,
-                                          expand4to8[font_data >> 4],
-                                          xorcol, bgcol);
-        glue(vga_draw_glyph_line_, DEPTH)(d + 8 * BPP,
-                                          expand4to8[font_data & 0x0f],
-                                          xorcol, bgcol);
-        font_ptr += 4;
-        d += linesize;
-    } while (--h);
-}
-
-static void glue(vga_draw_glyph9_, DEPTH)(uint8_t *d, int linesize,
-                                          const uint8_t *font_ptr, int h,
-                                          uint32_t fgcol, uint32_t bgcol, int dup9)
-{
-    uint32_t font_data, xorcol, v;
-
-    xorcol = bgcol ^ fgcol;
-    do {
-        font_data = font_ptr[0];
-#if BPP == 1
-        cpu_to_32wu((uint32_t *)d, (dmask16[(font_data >> 4)] & xorcol) ^ bgcol);
-        v = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
-        cpu_to_32wu(((uint32_t *)d)+1, v);
-        if (dup9)
-            ((uint8_t *)d)[8] = v >> (24 * (1 - BIG));
-        else
-            ((uint8_t *)d)[8] = bgcol;
-
-#elif BPP == 2
-        cpu_to_32wu(((uint32_t *)d)+0, (dmask4[(font_data >> 6)] & xorcol) ^ bgcol);
-        cpu_to_32wu(((uint32_t *)d)+1, (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol);
-        cpu_to_32wu(((uint32_t *)d)+2, (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol);
-        v = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
-        cpu_to_32wu(((uint32_t *)d)+3, v);
-        if (dup9)
-            ((uint16_t *)d)[8] = v >> (16 * (1 - BIG));
-        else
-            ((uint16_t *)d)[8] = bgcol;
-#else
-        ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
-        ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
-        ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
-        ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
-        ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
-        ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
-        ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
-        v = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
-        ((uint32_t *)d)[7] = v;
-        if (dup9)
-            ((uint32_t *)d)[8] = v;
-        else
-            ((uint32_t *)d)[8] = bgcol;
-#endif
-        font_ptr += 4;
-        d += linesize;
-    } while (--h);
-}
-
-/*
- * 4 color mode
- */
-static void glue(vga_draw_line2_, DEPTH)(VGACommonState *s1, uint8_t *d,
-                                         const uint8_t *s, int width)
-{
-    uint32_t plane_mask, *palette, data, v;
-    int x;
-
-    palette = s1->last_palette;
-    plane_mask = mask16[s1->ar[VGA_ATC_PLANE_ENABLE] & 0xf];
-    width >>= 3;
-    for(x = 0; x < width; x++) {
-        data = ((uint32_t *)s)[0];
-        data &= plane_mask;
-        v = expand2[GET_PLANE(data, 0)];
-        v |= expand2[GET_PLANE(data, 2)] << 2;
-        ((PIXEL_TYPE *)d)[0] = palette[v >> 12];
-        ((PIXEL_TYPE *)d)[1] = palette[(v >> 8) & 0xf];
-        ((PIXEL_TYPE *)d)[2] = palette[(v >> 4) & 0xf];
-        ((PIXEL_TYPE *)d)[3] = palette[(v >> 0) & 0xf];
-
-        v = expand2[GET_PLANE(data, 1)];
-        v |= expand2[GET_PLANE(data, 3)] << 2;
-        ((PIXEL_TYPE *)d)[4] = palette[v >> 12];
-        ((PIXEL_TYPE *)d)[5] = palette[(v >> 8) & 0xf];
-        ((PIXEL_TYPE *)d)[6] = palette[(v >> 4) & 0xf];
-        ((PIXEL_TYPE *)d)[7] = palette[(v >> 0) & 0xf];
-        d += BPP * 8;
-        s += 4;
-    }
-}
-
-#if BPP == 1
-#define PUT_PIXEL2(d, n, v) ((uint16_t *)d)[(n)] = (v)
-#elif BPP == 2
-#define PUT_PIXEL2(d, n, v) ((uint32_t *)d)[(n)] = (v)
-#else
-#define PUT_PIXEL2(d, n, v) \
-((uint32_t *)d)[2*(n)] = ((uint32_t *)d)[2*(n)+1] = (v)
-#endif
-
-/*
- * 4 color mode, dup2 horizontal
- */
-static void glue(vga_draw_line2d2_, DEPTH)(VGACommonState *s1, uint8_t *d,
-                                           const uint8_t *s, int width)
-{
-    uint32_t plane_mask, *palette, data, v;
-    int x;
-
-    palette = s1->last_palette;
-    plane_mask = mask16[s1->ar[VGA_ATC_PLANE_ENABLE] & 0xf];
-    width >>= 3;
-    for(x = 0; x < width; x++) {
-        data = ((uint32_t *)s)[0];
-        data &= plane_mask;
-        v = expand2[GET_PLANE(data, 0)];
-        v |= expand2[GET_PLANE(data, 2)] << 2;
-        PUT_PIXEL2(d, 0, palette[v >> 12]);
-        PUT_PIXEL2(d, 1, palette[(v >> 8) & 0xf]);
-        PUT_PIXEL2(d, 2, palette[(v >> 4) & 0xf]);
-        PUT_PIXEL2(d, 3, palette[(v >> 0) & 0xf]);
-
-        v = expand2[GET_PLANE(data, 1)];
-        v |= expand2[GET_PLANE(data, 3)] << 2;
-        PUT_PIXEL2(d, 4, palette[v >> 12]);
-        PUT_PIXEL2(d, 5, palette[(v >> 8) & 0xf]);
-        PUT_PIXEL2(d, 6, palette[(v >> 4) & 0xf]);
-        PUT_PIXEL2(d, 7, palette[(v >> 0) & 0xf]);
-        d += BPP * 16;
-        s += 4;
-    }
-}
-
-/*
- * 16 color mode
- */
-static void glue(vga_draw_line4_, DEPTH)(VGACommonState *s1, uint8_t *d,
-                                         const uint8_t *s, int width)
-{
-    uint32_t plane_mask, data, v, *palette;
-    int x;
-
-    palette = s1->last_palette;
-    plane_mask = mask16[s1->ar[VGA_ATC_PLANE_ENABLE] & 0xf];
-    width >>= 3;
-    for(x = 0; x < width; x++) {
-        data = ((uint32_t *)s)[0];
-        data &= plane_mask;
-        v = expand4[GET_PLANE(data, 0)];
-        v |= expand4[GET_PLANE(data, 1)] << 1;
-        v |= expand4[GET_PLANE(data, 2)] << 2;
-        v |= expand4[GET_PLANE(data, 3)] << 3;
-        ((PIXEL_TYPE *)d)[0] = palette[v >> 28];
-        ((PIXEL_TYPE *)d)[1] = palette[(v >> 24) & 0xf];
-        ((PIXEL_TYPE *)d)[2] = palette[(v >> 20) & 0xf];
-        ((PIXEL_TYPE *)d)[3] = palette[(v >> 16) & 0xf];
-        ((PIXEL_TYPE *)d)[4] = palette[(v >> 12) & 0xf];
-        ((PIXEL_TYPE *)d)[5] = palette[(v >> 8) & 0xf];
-        ((PIXEL_TYPE *)d)[6] = palette[(v >> 4) & 0xf];
-        ((PIXEL_TYPE *)d)[7] = palette[(v >> 0) & 0xf];
-        d += BPP * 8;
-        s += 4;
-    }
-}
-
-/*
- * 16 color mode, dup2 horizontal
- */
-static void glue(vga_draw_line4d2_, DEPTH)(VGACommonState *s1, uint8_t *d,
-                                           const uint8_t *s, int width)
-{
-    uint32_t plane_mask, data, v, *palette;
-    int x;
-
-    palette = s1->last_palette;
-    plane_mask = mask16[s1->ar[VGA_ATC_PLANE_ENABLE] & 0xf];
-    width >>= 3;
-    for(x = 0; x < width; x++) {
-        data = ((uint32_t *)s)[0];
-        data &= plane_mask;
-        v = expand4[GET_PLANE(data, 0)];
-        v |= expand4[GET_PLANE(data, 1)] << 1;
-        v |= expand4[GET_PLANE(data, 2)] << 2;
-        v |= expand4[GET_PLANE(data, 3)] << 3;
-        PUT_PIXEL2(d, 0, palette[v >> 28]);
-        PUT_PIXEL2(d, 1, palette[(v >> 24) & 0xf]);
-        PUT_PIXEL2(d, 2, palette[(v >> 20) & 0xf]);
-        PUT_PIXEL2(d, 3, palette[(v >> 16) & 0xf]);
-        PUT_PIXEL2(d, 4, palette[(v >> 12) & 0xf]);
-        PUT_PIXEL2(d, 5, palette[(v >> 8) & 0xf]);
-        PUT_PIXEL2(d, 6, palette[(v >> 4) & 0xf]);
-        PUT_PIXEL2(d, 7, palette[(v >> 0) & 0xf]);
-        d += BPP * 16;
-        s += 4;
-    }
-}
-
-/*
- * 256 color mode, double pixels
- *
- * XXX: add plane_mask support (never used in standard VGA modes)
- */
-static void glue(vga_draw_line8d2_, DEPTH)(VGACommonState *s1, uint8_t *d,
-                                           const uint8_t *s, int width)
-{
-    uint32_t *palette;
-    int x;
-
-    palette = s1->last_palette;
-    width >>= 3;
-    for(x = 0; x < width; x++) {
-        PUT_PIXEL2(d, 0, palette[s[0]]);
-        PUT_PIXEL2(d, 1, palette[s[1]]);
-        PUT_PIXEL2(d, 2, palette[s[2]]);
-        PUT_PIXEL2(d, 3, palette[s[3]]);
-        d += BPP * 8;
-        s += 4;
-    }
-}
-
-/*
- * standard 256 color mode
- *
- * XXX: add plane_mask support (never used in standard VGA modes)
- */
-static void glue(vga_draw_line8_, DEPTH)(VGACommonState *s1, uint8_t *d,
-                                         const uint8_t *s, int width)
-{
-    uint32_t *palette;
-    int x;
-
-    palette = s1->last_palette;
-    width >>= 3;
-    for(x = 0; x < width; x++) {
-        ((PIXEL_TYPE *)d)[0] = palette[s[0]];
-        ((PIXEL_TYPE *)d)[1] = palette[s[1]];
-        ((PIXEL_TYPE *)d)[2] = palette[s[2]];
-        ((PIXEL_TYPE *)d)[3] = palette[s[3]];
-        ((PIXEL_TYPE *)d)[4] = palette[s[4]];
-        ((PIXEL_TYPE *)d)[5] = palette[s[5]];
-        ((PIXEL_TYPE *)d)[6] = palette[s[6]];
-        ((PIXEL_TYPE *)d)[7] = palette[s[7]];
-        d += BPP * 8;
-        s += 8;
-    }
-}
-
-#endif /* DEPTH != 15 */
-
-
-/* XXX: optimize */
-
-/*
- * 15 bit color
- */
-static void glue(vga_draw_line15_, PIXEL_NAME)(VGACommonState *s1, uint8_t *d,
-                                          const uint8_t *s, int width)
-{
-#if DEPTH == 15 && defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
-    memcpy(d, s, width * 2);
-#else
-    int w;
-    uint32_t v, r, g, b;
-
-    w = width;
-    do {
-        v = lduw_raw((void *)s);
-        r = (v >> 7) & 0xf8;
-        g = (v >> 2) & 0xf8;
-        b = (v << 3) & 0xf8;
-        ((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b);
-        s += 2;
-        d += BPP;
-    } while (--w != 0);
-#endif
-}
-
-/*
- * 16 bit color
- */
-static void glue(vga_draw_line16_, PIXEL_NAME)(VGACommonState *s1, uint8_t *d,
-                                          const uint8_t *s, int width)
-{
-#if DEPTH == 16 && defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
-    memcpy(d, s, width * 2);
-#else
-    int w;
-    uint32_t v, r, g, b;
-
-    w = width;
-    do {
-        v = lduw_raw((void *)s);
-        r = (v >> 8) & 0xf8;
-        g = (v >> 3) & 0xfc;
-        b = (v << 3) & 0xf8;
-        ((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b);
-        s += 2;
-        d += BPP;
-    } while (--w != 0);
-#endif
-}
-
-/*
- * 24 bit color
- */
-static void glue(vga_draw_line24_, PIXEL_NAME)(VGACommonState *s1, uint8_t *d,
-                                          const uint8_t *s, int width)
-{
-    int w;
-    uint32_t r, g, b;
-
-    w = width;
-    do {
-#if defined(TARGET_WORDS_BIGENDIAN)
-        r = s[0];
-        g = s[1];
-        b = s[2];
-#else
-        b = s[0];
-        g = s[1];
-        r = s[2];
-#endif
-        ((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b);
-        s += 3;
-        d += BPP;
-    } while (--w != 0);
-}
-
-/*
- * 32 bit color
- */
-static void glue(vga_draw_line32_, PIXEL_NAME)(VGACommonState *s1, uint8_t *d,
-                                          const uint8_t *s, int width)
-{
-#if DEPTH == 32 && defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN) && !defined(BGR_FORMAT)
-    memcpy(d, s, width * 4);
-#else
-    int w;
-    uint32_t r, g, b;
-
-    w = width;
-    do {
-#if defined(TARGET_WORDS_BIGENDIAN)
-        r = s[1];
-        g = s[2];
-        b = s[3];
-#else
-        b = s[0];
-        g = s[1];
-        r = s[2];
-#endif
-        ((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b);
-        s += 4;
-        d += BPP;
-    } while (--w != 0);
-#endif
-}
-
-#undef PUT_PIXEL2
-#undef DEPTH
-#undef BPP
-#undef PIXEL_TYPE
-#undef PIXEL_NAME
-#undef BGR_FORMAT
diff --git a/hw/vhost.c b/hw/vhost.c
deleted file mode 100644 (file)
index 4d6aee3..0000000
+++ /dev/null
@@ -1,1042 +0,0 @@
-/*
- * vhost support
- *
- * Copyright Red Hat, Inc. 2010
- *
- * Authors:
- *  Michael S. Tsirkin <mst@redhat.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 <sys/ioctl.h>
-#include "hw/vhost.h"
-#include "hw/hw.h"
-#include "qemu/range.h"
-#include <linux/vhost.h>
-#include "exec/address-spaces.h"
-
-static void vhost_dev_sync_region(struct vhost_dev *dev,
-                                  MemoryRegionSection *section,
-                                  uint64_t mfirst, uint64_t mlast,
-                                  uint64_t rfirst, uint64_t rlast)
-{
-    uint64_t start = MAX(mfirst, rfirst);
-    uint64_t end = MIN(mlast, rlast);
-    vhost_log_chunk_t *from = dev->log + start / VHOST_LOG_CHUNK;
-    vhost_log_chunk_t *to = dev->log + end / VHOST_LOG_CHUNK + 1;
-    uint64_t addr = (start / VHOST_LOG_CHUNK) * VHOST_LOG_CHUNK;
-
-    if (end < start) {
-        return;
-    }
-    assert(end / VHOST_LOG_CHUNK < dev->log_size);
-    assert(start / VHOST_LOG_CHUNK < dev->log_size);
-
-    for (;from < to; ++from) {
-        vhost_log_chunk_t log;
-        int bit;
-        /* We first check with non-atomic: much cheaper,
-         * and we expect non-dirty to be the common case. */
-        if (!*from) {
-            addr += VHOST_LOG_CHUNK;
-            continue;
-        }
-        /* Data must be read atomically. We don't really
-         * need the barrier semantics of __sync
-         * builtins, but it's easier to use them than
-         * roll our own. */
-        log = __sync_fetch_and_and(from, 0);
-        while ((bit = sizeof(log) > sizeof(int) ?
-                ffsll(log) : ffs(log))) {
-            hwaddr page_addr;
-            hwaddr section_offset;
-            hwaddr mr_offset;
-            bit -= 1;
-            page_addr = addr + bit * VHOST_LOG_PAGE;
-            section_offset = page_addr - section->offset_within_address_space;
-            mr_offset = section_offset + section->offset_within_region;
-            memory_region_set_dirty(section->mr, mr_offset, VHOST_LOG_PAGE);
-            log &= ~(0x1ull << bit);
-        }
-        addr += VHOST_LOG_CHUNK;
-    }
-}
-
-static int vhost_sync_dirty_bitmap(struct vhost_dev *dev,
-                                   MemoryRegionSection *section,
-                                   hwaddr first,
-                                   hwaddr last)
-{
-    int i;
-    hwaddr start_addr;
-    hwaddr end_addr;
-
-    if (!dev->log_enabled || !dev->started) {
-        return 0;
-    }
-    start_addr = section->offset_within_address_space;
-    end_addr = range_get_last(start_addr, section->size);
-    start_addr = MAX(first, start_addr);
-    end_addr = MIN(last, end_addr);
-
-    for (i = 0; i < dev->mem->nregions; ++i) {
-        struct vhost_memory_region *reg = dev->mem->regions + i;
-        vhost_dev_sync_region(dev, section, start_addr, end_addr,
-                              reg->guest_phys_addr,
-                              range_get_last(reg->guest_phys_addr,
-                                             reg->memory_size));
-    }
-    for (i = 0; i < dev->nvqs; ++i) {
-        struct vhost_virtqueue *vq = dev->vqs + i;
-        vhost_dev_sync_region(dev, section, start_addr, end_addr, vq->used_phys,
-                              range_get_last(vq->used_phys, vq->used_size));
-    }
-    return 0;
-}
-
-static void vhost_log_sync(MemoryListener *listener,
-                          MemoryRegionSection *section)
-{
-    struct vhost_dev *dev = container_of(listener, struct vhost_dev,
-                                         memory_listener);
-    vhost_sync_dirty_bitmap(dev, section, 0x0, ~0x0ULL);
-}
-
-static void vhost_log_sync_range(struct vhost_dev *dev,
-                                 hwaddr first, hwaddr last)
-{
-    int i;
-    /* FIXME: this is N^2 in number of sections */
-    for (i = 0; i < dev->n_mem_sections; ++i) {
-        MemoryRegionSection *section = &dev->mem_sections[i];
-        vhost_sync_dirty_bitmap(dev, section, first, last);
-    }
-}
-
-/* Assign/unassign. Keep an unsorted array of non-overlapping
- * memory regions in dev->mem. */
-static void vhost_dev_unassign_memory(struct vhost_dev *dev,
-                                      uint64_t start_addr,
-                                      uint64_t size)
-{
-    int from, to, n = dev->mem->nregions;
-    /* Track overlapping/split regions for sanity checking. */
-    int overlap_start = 0, overlap_end = 0, overlap_middle = 0, split = 0;
-
-    for (from = 0, to = 0; from < n; ++from, ++to) {
-        struct vhost_memory_region *reg = dev->mem->regions + to;
-        uint64_t reglast;
-        uint64_t memlast;
-        uint64_t change;
-
-        /* clone old region */
-        if (to != from) {
-            memcpy(reg, dev->mem->regions + from, sizeof *reg);
-        }
-
-        /* No overlap is simple */
-        if (!ranges_overlap(reg->guest_phys_addr, reg->memory_size,
-                            start_addr, size)) {
-            continue;
-        }
-
-        /* Split only happens if supplied region
-         * is in the middle of an existing one. Thus it can not
-         * overlap with any other existing region. */
-        assert(!split);
-
-        reglast = range_get_last(reg->guest_phys_addr, reg->memory_size);
-        memlast = range_get_last(start_addr, size);
-
-        /* Remove whole region */
-        if (start_addr <= reg->guest_phys_addr && memlast >= reglast) {
-            --dev->mem->nregions;
-            --to;
-            ++overlap_middle;
-            continue;
-        }
-
-        /* Shrink region */
-        if (memlast >= reglast) {
-            reg->memory_size = start_addr - reg->guest_phys_addr;
-            assert(reg->memory_size);
-            assert(!overlap_end);
-            ++overlap_end;
-            continue;
-        }
-
-        /* Shift region */
-        if (start_addr <= reg->guest_phys_addr) {
-            change = memlast + 1 - reg->guest_phys_addr;
-            reg->memory_size -= change;
-            reg->guest_phys_addr += change;
-            reg->userspace_addr += change;
-            assert(reg->memory_size);
-            assert(!overlap_start);
-            ++overlap_start;
-            continue;
-        }
-
-        /* This only happens if supplied region
-         * is in the middle of an existing one. Thus it can not
-         * overlap with any other existing region. */
-        assert(!overlap_start);
-        assert(!overlap_end);
-        assert(!overlap_middle);
-        /* Split region: shrink first part, shift second part. */
-        memcpy(dev->mem->regions + n, reg, sizeof *reg);
-        reg->memory_size = start_addr - reg->guest_phys_addr;
-        assert(reg->memory_size);
-        change = memlast + 1 - reg->guest_phys_addr;
-        reg = dev->mem->regions + n;
-        reg->memory_size -= change;
-        assert(reg->memory_size);
-        reg->guest_phys_addr += change;
-        reg->userspace_addr += change;
-        /* Never add more than 1 region */
-        assert(dev->mem->nregions == n);
-        ++dev->mem->nregions;
-        ++split;
-    }
-}
-
-/* Called after unassign, so no regions overlap the given range. */
-static void vhost_dev_assign_memory(struct vhost_dev *dev,
-                                    uint64_t start_addr,
-                                    uint64_t size,
-                                    uint64_t uaddr)
-{
-    int from, to;
-    struct vhost_memory_region *merged = NULL;
-    for (from = 0, to = 0; from < dev->mem->nregions; ++from, ++to) {
-        struct vhost_memory_region *reg = dev->mem->regions + to;
-        uint64_t prlast, urlast;
-        uint64_t pmlast, umlast;
-        uint64_t s, e, u;
-
-        /* clone old region */
-        if (to != from) {
-            memcpy(reg, dev->mem->regions + from, sizeof *reg);
-        }
-        prlast = range_get_last(reg->guest_phys_addr, reg->memory_size);
-        pmlast = range_get_last(start_addr, size);
-        urlast = range_get_last(reg->userspace_addr, reg->memory_size);
-        umlast = range_get_last(uaddr, size);
-
-        /* check for overlapping regions: should never happen. */
-        assert(prlast < start_addr || pmlast < reg->guest_phys_addr);
-        /* Not an adjacent or overlapping region - do not merge. */
-        if ((prlast + 1 != start_addr || urlast + 1 != uaddr) &&
-            (pmlast + 1 != reg->guest_phys_addr ||
-             umlast + 1 != reg->userspace_addr)) {
-            continue;
-        }
-
-        if (merged) {
-            --to;
-            assert(to >= 0);
-        } else {
-            merged = reg;
-        }
-        u = MIN(uaddr, reg->userspace_addr);
-        s = MIN(start_addr, reg->guest_phys_addr);
-        e = MAX(pmlast, prlast);
-        uaddr = merged->userspace_addr = u;
-        start_addr = merged->guest_phys_addr = s;
-        size = merged->memory_size = e - s + 1;
-        assert(merged->memory_size);
-    }
-
-    if (!merged) {
-        struct vhost_memory_region *reg = dev->mem->regions + to;
-        memset(reg, 0, sizeof *reg);
-        reg->memory_size = size;
-        assert(reg->memory_size);
-        reg->guest_phys_addr = start_addr;
-        reg->userspace_addr = uaddr;
-        ++to;
-    }
-    assert(to <= dev->mem->nregions + 1);
-    dev->mem->nregions = to;
-}
-
-static uint64_t vhost_get_log_size(struct vhost_dev *dev)
-{
-    uint64_t log_size = 0;
-    int i;
-    for (i = 0; i < dev->mem->nregions; ++i) {
-        struct vhost_memory_region *reg = dev->mem->regions + i;
-        uint64_t last = range_get_last(reg->guest_phys_addr,
-                                       reg->memory_size);
-        log_size = MAX(log_size, last / VHOST_LOG_CHUNK + 1);
-    }
-    for (i = 0; i < dev->nvqs; ++i) {
-        struct vhost_virtqueue *vq = dev->vqs + i;
-        uint64_t last = vq->used_phys + vq->used_size - 1;
-        log_size = MAX(log_size, last / VHOST_LOG_CHUNK + 1);
-    }
-    return log_size;
-}
-
-static inline void vhost_dev_log_resize(struct vhost_dev* dev, uint64_t size)
-{
-    vhost_log_chunk_t *log;
-    uint64_t log_base;
-    int r;
-
-    log = g_malloc0(size * sizeof *log);
-    log_base = (uint64_t)(unsigned long)log;
-    r = ioctl(dev->control, VHOST_SET_LOG_BASE, &log_base);
-    assert(r >= 0);
-    /* Sync only the range covered by the old log */
-    if (dev->log_size) {
-        vhost_log_sync_range(dev, 0, dev->log_size * VHOST_LOG_CHUNK - 1);
-    }
-    if (dev->log) {
-        g_free(dev->log);
-    }
-    dev->log = log;
-    dev->log_size = size;
-}
-
-static int vhost_verify_ring_mappings(struct vhost_dev *dev,
-                                      uint64_t start_addr,
-                                      uint64_t size)
-{
-    int i;
-    for (i = 0; i < dev->nvqs; ++i) {
-        struct vhost_virtqueue *vq = dev->vqs + i;
-        hwaddr l;
-        void *p;
-
-        if (!ranges_overlap(start_addr, size, vq->ring_phys, vq->ring_size)) {
-            continue;
-        }
-        l = vq->ring_size;
-        p = cpu_physical_memory_map(vq->ring_phys, &l, 1);
-        if (!p || l != vq->ring_size) {
-            fprintf(stderr, "Unable to map ring buffer for ring %d\n", i);
-            return -ENOMEM;
-        }
-        if (p != vq->ring) {
-            fprintf(stderr, "Ring buffer relocated for ring %d\n", i);
-            return -EBUSY;
-        }
-        cpu_physical_memory_unmap(p, l, 0, 0);
-    }
-    return 0;
-}
-
-static struct vhost_memory_region *vhost_dev_find_reg(struct vhost_dev *dev,
-                                                     uint64_t start_addr,
-                                                     uint64_t size)
-{
-    int i, n = dev->mem->nregions;
-    for (i = 0; i < n; ++i) {
-        struct vhost_memory_region *reg = dev->mem->regions + i;
-        if (ranges_overlap(reg->guest_phys_addr, reg->memory_size,
-                           start_addr, size)) {
-            return reg;
-        }
-    }
-    return NULL;
-}
-
-static bool vhost_dev_cmp_memory(struct vhost_dev *dev,
-                                 uint64_t start_addr,
-                                 uint64_t size,
-                                 uint64_t uaddr)
-{
-    struct vhost_memory_region *reg = vhost_dev_find_reg(dev, start_addr, size);
-    uint64_t reglast;
-    uint64_t memlast;
-
-    if (!reg) {
-        return true;
-    }
-
-    reglast = range_get_last(reg->guest_phys_addr, reg->memory_size);
-    memlast = range_get_last(start_addr, size);
-
-    /* Need to extend region? */
-    if (start_addr < reg->guest_phys_addr || memlast > reglast) {
-        return true;
-    }
-    /* userspace_addr changed? */
-    return uaddr != reg->userspace_addr + start_addr - reg->guest_phys_addr;
-}
-
-static void vhost_set_memory(MemoryListener *listener,
-                             MemoryRegionSection *section,
-                             bool add)
-{
-    struct vhost_dev *dev = container_of(listener, struct vhost_dev,
-                                         memory_listener);
-    hwaddr start_addr = section->offset_within_address_space;
-    ram_addr_t size = section->size;
-    bool log_dirty = memory_region_is_logging(section->mr);
-    int s = offsetof(struct vhost_memory, regions) +
-        (dev->mem->nregions + 1) * sizeof dev->mem->regions[0];
-    uint64_t log_size;
-    int r;
-    void *ram;
-
-    dev->mem = g_realloc(dev->mem, s);
-
-    if (log_dirty) {
-        add = false;
-    }
-
-    assert(size);
-
-    /* Optimize no-change case. At least cirrus_vga does this a lot at this time. */
-    ram = memory_region_get_ram_ptr(section->mr) + section->offset_within_region;
-    if (add) {
-        if (!vhost_dev_cmp_memory(dev, start_addr, size, (uintptr_t)ram)) {
-            /* Region exists with same address. Nothing to do. */
-            return;
-        }
-    } else {
-        if (!vhost_dev_find_reg(dev, start_addr, size)) {
-            /* Removing region that we don't access. Nothing to do. */
-            return;
-        }
-    }
-
-    vhost_dev_unassign_memory(dev, start_addr, size);
-    if (add) {
-        /* Add given mapping, merging adjacent regions if any */
-        vhost_dev_assign_memory(dev, start_addr, size, (uintptr_t)ram);
-    } else {
-        /* Remove old mapping for this memory, if any. */
-        vhost_dev_unassign_memory(dev, start_addr, size);
-    }
-
-    if (!dev->started) {
-        return;
-    }
-
-    if (dev->started) {
-        r = vhost_verify_ring_mappings(dev, start_addr, size);
-        assert(r >= 0);
-    }
-
-    if (!dev->log_enabled) {
-        r = ioctl(dev->control, VHOST_SET_MEM_TABLE, dev->mem);
-        assert(r >= 0);
-        return;
-    }
-    log_size = vhost_get_log_size(dev);
-    /* We allocate an extra 4K bytes to log,
-     * to reduce the * number of reallocations. */
-#define VHOST_LOG_BUFFER (0x1000 / sizeof *dev->log)
-    /* To log more, must increase log size before table update. */
-    if (dev->log_size < log_size) {
-        vhost_dev_log_resize(dev, log_size + VHOST_LOG_BUFFER);
-    }
-    r = ioctl(dev->control, VHOST_SET_MEM_TABLE, dev->mem);
-    assert(r >= 0);
-    /* To log less, can only decrease log size after table update. */
-    if (dev->log_size > log_size + VHOST_LOG_BUFFER) {
-        vhost_dev_log_resize(dev, log_size);
-    }
-}
-
-static bool vhost_section(MemoryRegionSection *section)
-{
-    return memory_region_is_ram(section->mr);
-}
-
-static void vhost_begin(MemoryListener *listener)
-{
-}
-
-static void vhost_commit(MemoryListener *listener)
-{
-}
-
-static void vhost_region_add(MemoryListener *listener,
-                             MemoryRegionSection *section)
-{
-    struct vhost_dev *dev = container_of(listener, struct vhost_dev,
-                                         memory_listener);
-
-    if (!vhost_section(section)) {
-        return;
-    }
-
-    ++dev->n_mem_sections;
-    dev->mem_sections = g_renew(MemoryRegionSection, dev->mem_sections,
-                                dev->n_mem_sections);
-    dev->mem_sections[dev->n_mem_sections - 1] = *section;
-    vhost_set_memory(listener, section, true);
-}
-
-static void vhost_region_del(MemoryListener *listener,
-                             MemoryRegionSection *section)
-{
-    struct vhost_dev *dev = container_of(listener, struct vhost_dev,
-                                         memory_listener);
-    int i;
-
-    if (!vhost_section(section)) {
-        return;
-    }
-
-    vhost_set_memory(listener, section, false);
-    for (i = 0; i < dev->n_mem_sections; ++i) {
-        if (dev->mem_sections[i].offset_within_address_space
-            == section->offset_within_address_space) {
-            --dev->n_mem_sections;
-            memmove(&dev->mem_sections[i], &dev->mem_sections[i+1],
-                    (dev->n_mem_sections - i) * sizeof(*dev->mem_sections));
-            break;
-        }
-    }
-}
-
-static void vhost_region_nop(MemoryListener *listener,
-                             MemoryRegionSection *section)
-{
-}
-
-static int vhost_virtqueue_set_addr(struct vhost_dev *dev,
-                                    struct vhost_virtqueue *vq,
-                                    unsigned idx, bool enable_log)
-{
-    struct vhost_vring_addr addr = {
-        .index = idx,
-        .desc_user_addr = (uint64_t)(unsigned long)vq->desc,
-        .avail_user_addr = (uint64_t)(unsigned long)vq->avail,
-        .used_user_addr = (uint64_t)(unsigned long)vq->used,
-        .log_guest_addr = vq->used_phys,
-        .flags = enable_log ? (1 << VHOST_VRING_F_LOG) : 0,
-    };
-    int r = ioctl(dev->control, VHOST_SET_VRING_ADDR, &addr);
-    if (r < 0) {
-        return -errno;
-    }
-    return 0;
-}
-
-static int vhost_dev_set_features(struct vhost_dev *dev, bool enable_log)
-{
-    uint64_t features = dev->acked_features;
-    int r;
-    if (enable_log) {
-        features |= 0x1 << VHOST_F_LOG_ALL;
-    }
-    r = ioctl(dev->control, VHOST_SET_FEATURES, &features);
-    return r < 0 ? -errno : 0;
-}
-
-static int vhost_dev_set_log(struct vhost_dev *dev, bool enable_log)
-{
-    int r, t, i;
-    r = vhost_dev_set_features(dev, enable_log);
-    if (r < 0) {
-        goto err_features;
-    }
-    for (i = 0; i < dev->nvqs; ++i) {
-        r = vhost_virtqueue_set_addr(dev, dev->vqs + i, i,
-                                     enable_log);
-        if (r < 0) {
-            goto err_vq;
-        }
-    }
-    return 0;
-err_vq:
-    for (; i >= 0; --i) {
-        t = vhost_virtqueue_set_addr(dev, dev->vqs + i, i,
-                                     dev->log_enabled);
-        assert(t >= 0);
-    }
-    t = vhost_dev_set_features(dev, dev->log_enabled);
-    assert(t >= 0);
-err_features:
-    return r;
-}
-
-static int vhost_migration_log(MemoryListener *listener, int enable)
-{
-    struct vhost_dev *dev = container_of(listener, struct vhost_dev,
-                                         memory_listener);
-    int r;
-    if (!!enable == dev->log_enabled) {
-        return 0;
-    }
-    if (!dev->started) {
-        dev->log_enabled = enable;
-        return 0;
-    }
-    if (!enable) {
-        r = vhost_dev_set_log(dev, false);
-        if (r < 0) {
-            return r;
-        }
-        if (dev->log) {
-            g_free(dev->log);
-        }
-        dev->log = NULL;
-        dev->log_size = 0;
-    } else {
-        vhost_dev_log_resize(dev, vhost_get_log_size(dev));
-        r = vhost_dev_set_log(dev, true);
-        if (r < 0) {
-            return r;
-        }
-    }
-    dev->log_enabled = enable;
-    return 0;
-}
-
-static void vhost_log_global_start(MemoryListener *listener)
-{
-    int r;
-
-    r = vhost_migration_log(listener, true);
-    if (r < 0) {
-        abort();
-    }
-}
-
-static void vhost_log_global_stop(MemoryListener *listener)
-{
-    int r;
-
-    r = vhost_migration_log(listener, false);
-    if (r < 0) {
-        abort();
-    }
-}
-
-static void vhost_log_start(MemoryListener *listener,
-                            MemoryRegionSection *section)
-{
-    /* FIXME: implement */
-}
-
-static void vhost_log_stop(MemoryListener *listener,
-                           MemoryRegionSection *section)
-{
-    /* FIXME: implement */
-}
-
-static int vhost_virtqueue_start(struct vhost_dev *dev,
-                                struct VirtIODevice *vdev,
-                                struct vhost_virtqueue *vq,
-                                unsigned idx)
-{
-    hwaddr s, l, a;
-    int r;
-    int vhost_vq_index = idx - dev->vq_index;
-    struct vhost_vring_file file = {
-        .index = vhost_vq_index
-    };
-    struct vhost_vring_state state = {
-        .index = vhost_vq_index
-    };
-    struct VirtQueue *vvq = virtio_get_queue(vdev, idx);
-
-    assert(idx >= dev->vq_index && idx < dev->vq_index + dev->nvqs);
-
-    vq->num = state.num = virtio_queue_get_num(vdev, idx);
-    r = ioctl(dev->control, VHOST_SET_VRING_NUM, &state);
-    if (r) {
-        return -errno;
-    }
-
-    state.num = virtio_queue_get_last_avail_idx(vdev, idx);
-    r = ioctl(dev->control, VHOST_SET_VRING_BASE, &state);
-    if (r) {
-        return -errno;
-    }
-
-    s = l = virtio_queue_get_desc_size(vdev, idx);
-    a = virtio_queue_get_desc_addr(vdev, idx);
-    vq->desc = cpu_physical_memory_map(a, &l, 0);
-    if (!vq->desc || l != s) {
-        r = -ENOMEM;
-        goto fail_alloc_desc;
-    }
-    s = l = virtio_queue_get_avail_size(vdev, idx);
-    a = virtio_queue_get_avail_addr(vdev, idx);
-    vq->avail = cpu_physical_memory_map(a, &l, 0);
-    if (!vq->avail || l != s) {
-        r = -ENOMEM;
-        goto fail_alloc_avail;
-    }
-    vq->used_size = s = l = virtio_queue_get_used_size(vdev, idx);
-    vq->used_phys = a = virtio_queue_get_used_addr(vdev, idx);
-    vq->used = cpu_physical_memory_map(a, &l, 1);
-    if (!vq->used || l != s) {
-        r = -ENOMEM;
-        goto fail_alloc_used;
-    }
-
-    vq->ring_size = s = l = virtio_queue_get_ring_size(vdev, idx);
-    vq->ring_phys = a = virtio_queue_get_ring_addr(vdev, idx);
-    vq->ring = cpu_physical_memory_map(a, &l, 1);
-    if (!vq->ring || l != s) {
-        r = -ENOMEM;
-        goto fail_alloc_ring;
-    }
-
-    r = vhost_virtqueue_set_addr(dev, vq, vhost_vq_index, dev->log_enabled);
-    if (r < 0) {
-        r = -errno;
-        goto fail_alloc;
-    }
-
-    file.fd = event_notifier_get_fd(virtio_queue_get_host_notifier(vvq));
-    r = ioctl(dev->control, VHOST_SET_VRING_KICK, &file);
-    if (r) {
-        r = -errno;
-        goto fail_kick;
-    }
-
-    /* Clear and discard previous events if any. */
-    event_notifier_test_and_clear(&vq->masked_notifier);
-
-    return 0;
-
-fail_kick:
-fail_alloc:
-    cpu_physical_memory_unmap(vq->ring, virtio_queue_get_ring_size(vdev, idx),
-                              0, 0);
-fail_alloc_ring:
-    cpu_physical_memory_unmap(vq->used, virtio_queue_get_used_size(vdev, idx),
-                              0, 0);
-fail_alloc_used:
-    cpu_physical_memory_unmap(vq->avail, virtio_queue_get_avail_size(vdev, idx),
-                              0, 0);
-fail_alloc_avail:
-    cpu_physical_memory_unmap(vq->desc, virtio_queue_get_desc_size(vdev, idx),
-                              0, 0);
-fail_alloc_desc:
-    return r;
-}
-
-static void vhost_virtqueue_stop(struct vhost_dev *dev,
-                                    struct VirtIODevice *vdev,
-                                    struct vhost_virtqueue *vq,
-                                    unsigned idx)
-{
-    struct vhost_vring_state state = {
-        .index = idx - dev->vq_index
-    };
-    int r;
-    assert(idx >= dev->vq_index && idx < dev->vq_index + dev->nvqs);
-    r = ioctl(dev->control, VHOST_GET_VRING_BASE, &state);
-    if (r < 0) {
-        fprintf(stderr, "vhost VQ %d ring restore failed: %d\n", idx, r);
-        fflush(stderr);
-    }
-    virtio_queue_set_last_avail_idx(vdev, idx, state.num);
-    assert (r >= 0);
-    cpu_physical_memory_unmap(vq->ring, virtio_queue_get_ring_size(vdev, idx),
-                              0, virtio_queue_get_ring_size(vdev, idx));
-    cpu_physical_memory_unmap(vq->used, virtio_queue_get_used_size(vdev, idx),
-                              1, virtio_queue_get_used_size(vdev, idx));
-    cpu_physical_memory_unmap(vq->avail, virtio_queue_get_avail_size(vdev, idx),
-                              0, virtio_queue_get_avail_size(vdev, idx));
-    cpu_physical_memory_unmap(vq->desc, virtio_queue_get_desc_size(vdev, idx),
-                              0, virtio_queue_get_desc_size(vdev, idx));
-}
-
-static void vhost_eventfd_add(MemoryListener *listener,
-                              MemoryRegionSection *section,
-                              bool match_data, uint64_t data, EventNotifier *e)
-{
-}
-
-static void vhost_eventfd_del(MemoryListener *listener,
-                              MemoryRegionSection *section,
-                              bool match_data, uint64_t data, EventNotifier *e)
-{
-}
-
-static int vhost_virtqueue_init(struct vhost_dev *dev,
-                                struct vhost_virtqueue *vq, int n)
-{
-    struct vhost_vring_file file = {
-        .index = n,
-    };
-    int r = event_notifier_init(&vq->masked_notifier, 0);
-    if (r < 0) {
-        return r;
-    }
-
-    file.fd = event_notifier_get_fd(&vq->masked_notifier);
-    r = ioctl(dev->control, VHOST_SET_VRING_CALL, &file);
-    if (r) {
-        r = -errno;
-        goto fail_call;
-    }
-    return 0;
-fail_call:
-    event_notifier_cleanup(&vq->masked_notifier);
-    return r;
-}
-
-static void vhost_virtqueue_cleanup(struct vhost_virtqueue *vq)
-{
-    event_notifier_cleanup(&vq->masked_notifier);
-}
-
-int vhost_dev_init(struct vhost_dev *hdev, int devfd, const char *devpath,
-                   bool force)
-{
-    uint64_t features;
-    int i, r;
-    if (devfd >= 0) {
-        hdev->control = devfd;
-    } else {
-        hdev->control = open(devpath, O_RDWR);
-        if (hdev->control < 0) {
-            return -errno;
-        }
-    }
-    r = ioctl(hdev->control, VHOST_SET_OWNER, NULL);
-    if (r < 0) {
-        goto fail;
-    }
-
-    r = ioctl(hdev->control, VHOST_GET_FEATURES, &features);
-    if (r < 0) {
-        goto fail;
-    }
-
-    for (i = 0; i < hdev->nvqs; ++i) {
-        r = vhost_virtqueue_init(hdev, hdev->vqs + i, i);
-        if (r < 0) {
-            goto fail_vq;
-        }
-    }
-    hdev->features = features;
-
-    hdev->memory_listener = (MemoryListener) {
-        .begin = vhost_begin,
-        .commit = vhost_commit,
-        .region_add = vhost_region_add,
-        .region_del = vhost_region_del,
-        .region_nop = vhost_region_nop,
-        .log_start = vhost_log_start,
-        .log_stop = vhost_log_stop,
-        .log_sync = vhost_log_sync,
-        .log_global_start = vhost_log_global_start,
-        .log_global_stop = vhost_log_global_stop,
-        .eventfd_add = vhost_eventfd_add,
-        .eventfd_del = vhost_eventfd_del,
-        .priority = 10
-    };
-    hdev->mem = g_malloc0(offsetof(struct vhost_memory, regions));
-    hdev->n_mem_sections = 0;
-    hdev->mem_sections = NULL;
-    hdev->log = NULL;
-    hdev->log_size = 0;
-    hdev->log_enabled = false;
-    hdev->started = false;
-    memory_listener_register(&hdev->memory_listener, &address_space_memory);
-    hdev->force = force;
-    return 0;
-fail_vq:
-    while (--i >= 0) {
-        vhost_virtqueue_cleanup(hdev->vqs + i);
-    }
-fail:
-    r = -errno;
-    close(hdev->control);
-    return r;
-}
-
-void vhost_dev_cleanup(struct vhost_dev *hdev)
-{
-    int i;
-    for (i = 0; i < hdev->nvqs; ++i) {
-        vhost_virtqueue_cleanup(hdev->vqs + i);
-    }
-    memory_listener_unregister(&hdev->memory_listener);
-    g_free(hdev->mem);
-    g_free(hdev->mem_sections);
-    close(hdev->control);
-}
-
-bool vhost_dev_query(struct vhost_dev *hdev, VirtIODevice *vdev)
-{
-    return !vdev->binding->query_guest_notifiers ||
-        vdev->binding->query_guest_notifiers(vdev->binding_opaque) ||
-        hdev->force;
-}
-
-/* Stop processing guest IO notifications in qemu.
- * Start processing them in vhost in kernel.
- */
-int vhost_dev_enable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev)
-{
-    int i, r;
-    if (!vdev->binding->set_host_notifier) {
-        fprintf(stderr, "binding does not support host notifiers\n");
-        r = -ENOSYS;
-        goto fail;
-    }
-
-    for (i = 0; i < hdev->nvqs; ++i) {
-        r = vdev->binding->set_host_notifier(vdev->binding_opaque,
-                                             hdev->vq_index + i,
-                                             true);
-        if (r < 0) {
-            fprintf(stderr, "vhost VQ %d notifier binding failed: %d\n", i, -r);
-            goto fail_vq;
-        }
-    }
-
-    return 0;
-fail_vq:
-    while (--i >= 0) {
-        r = vdev->binding->set_host_notifier(vdev->binding_opaque,
-                                             hdev->vq_index + i,
-                                             false);
-        if (r < 0) {
-            fprintf(stderr, "vhost VQ %d notifier cleanup error: %d\n", i, -r);
-            fflush(stderr);
-        }
-        assert (r >= 0);
-    }
-fail:
-    return r;
-}
-
-/* Stop processing guest IO notifications in vhost.
- * Start processing them in qemu.
- * This might actually run the qemu handlers right away,
- * so virtio in qemu must be completely setup when this is called.
- */
-void vhost_dev_disable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev)
-{
-    int i, r;
-
-    for (i = 0; i < hdev->nvqs; ++i) {
-        r = vdev->binding->set_host_notifier(vdev->binding_opaque,
-                                             hdev->vq_index + i,
-                                             false);
-        if (r < 0) {
-            fprintf(stderr, "vhost VQ %d notifier cleanup failed: %d\n", i, -r);
-            fflush(stderr);
-        }
-        assert (r >= 0);
-    }
-}
-
-/* Test and clear event pending status.
- * Should be called after unmask to avoid losing events.
- */
-bool vhost_virtqueue_pending(struct vhost_dev *hdev, int n)
-{
-    struct vhost_virtqueue *vq = hdev->vqs + n - hdev->vq_index;
-    assert(hdev->started);
-    assert(n >= hdev->vq_index && n < hdev->vq_index + hdev->nvqs);
-    return event_notifier_test_and_clear(&vq->masked_notifier);
-}
-
-/* Mask/unmask events from this vq. */
-void vhost_virtqueue_mask(struct vhost_dev *hdev, VirtIODevice *vdev, int n,
-                         bool mask)
-{
-    struct VirtQueue *vvq = virtio_get_queue(vdev, n);
-    int r, index = n - hdev->vq_index;
-
-    assert(hdev->started);
-    assert(n >= hdev->vq_index && n < hdev->vq_index + hdev->nvqs);
-
-    struct vhost_vring_file file = {
-        .index = index
-    };
-    if (mask) {
-        file.fd = event_notifier_get_fd(&hdev->vqs[index].masked_notifier);
-    } else {
-        file.fd = event_notifier_get_fd(virtio_queue_get_guest_notifier(vvq));
-    }
-    r = ioctl(hdev->control, VHOST_SET_VRING_CALL, &file);
-    assert(r >= 0);
-}
-
-/* Host notifiers must be enabled at this point. */
-int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev)
-{
-    int i, r;
-
-    hdev->started = true;
-
-    r = vhost_dev_set_features(hdev, hdev->log_enabled);
-    if (r < 0) {
-        goto fail_features;
-    }
-    r = ioctl(hdev->control, VHOST_SET_MEM_TABLE, hdev->mem);
-    if (r < 0) {
-        r = -errno;
-        goto fail_mem;
-    }
-    for (i = 0; i < hdev->nvqs; ++i) {
-        r = vhost_virtqueue_start(hdev,
-                                  vdev,
-                                  hdev->vqs + i,
-                                  hdev->vq_index + i);
-        if (r < 0) {
-            goto fail_vq;
-        }
-    }
-
-    if (hdev->log_enabled) {
-        hdev->log_size = vhost_get_log_size(hdev);
-        hdev->log = hdev->log_size ?
-            g_malloc0(hdev->log_size * sizeof *hdev->log) : NULL;
-        r = ioctl(hdev->control, VHOST_SET_LOG_BASE,
-                  (uint64_t)(unsigned long)hdev->log);
-        if (r < 0) {
-            r = -errno;
-            goto fail_log;
-        }
-    }
-
-    return 0;
-fail_log:
-fail_vq:
-    while (--i >= 0) {
-        vhost_virtqueue_stop(hdev,
-                             vdev,
-                             hdev->vqs + i,
-                             hdev->vq_index + i);
-    }
-    i = hdev->nvqs;
-fail_mem:
-fail_features:
-
-    hdev->started = false;
-    return r;
-}
-
-/* Host notifiers must be enabled at this point. */
-void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev)
-{
-    int i;
-
-    for (i = 0; i < hdev->nvqs; ++i) {
-        vhost_virtqueue_stop(hdev,
-                             vdev,
-                             hdev->vqs + i,
-                             hdev->vq_index + i);
-    }
-    vhost_log_sync_range(hdev, 0, ~0x0ull);
-
-    hdev->started = false;
-    g_free(hdev->log);
-    hdev->log = NULL;
-    hdev->log_size = 0;
-}
-
diff --git a/hw/vhost.h b/hw/vhost.h
deleted file mode 100644 (file)
index f062d48..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-#ifndef VHOST_H
-#define VHOST_H
-
-#include "hw/hw.h"
-#include "hw/virtio.h"
-#include "exec/memory.h"
-
-/* Generic structures common for any vhost based device. */
-struct vhost_virtqueue {
-    int kick;
-    int call;
-    void *desc;
-    void *avail;
-    void *used;
-    int num;
-    unsigned long long used_phys;
-    unsigned used_size;
-    void *ring;
-    unsigned long long ring_phys;
-    unsigned ring_size;
-    EventNotifier masked_notifier;
-};
-
-typedef unsigned long vhost_log_chunk_t;
-#define VHOST_LOG_PAGE 0x1000
-#define VHOST_LOG_BITS (8 * sizeof(vhost_log_chunk_t))
-#define VHOST_LOG_CHUNK (VHOST_LOG_PAGE * VHOST_LOG_BITS)
-
-struct vhost_memory;
-struct vhost_dev {
-    MemoryListener memory_listener;
-    int control;
-    struct vhost_memory *mem;
-    int n_mem_sections;
-    MemoryRegionSection *mem_sections;
-    struct vhost_virtqueue *vqs;
-    int nvqs;
-    /* the first virtuque which would be used by this vhost dev */
-    int vq_index;
-    unsigned long long features;
-    unsigned long long acked_features;
-    unsigned long long backend_features;
-    bool started;
-    bool log_enabled;
-    vhost_log_chunk_t *log;
-    unsigned long long log_size;
-    bool force;
-};
-
-int vhost_dev_init(struct vhost_dev *hdev, int devfd, const char *devpath,
-                   bool force);
-void vhost_dev_cleanup(struct vhost_dev *hdev);
-bool vhost_dev_query(struct vhost_dev *hdev, VirtIODevice *vdev);
-int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev);
-void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev);
-int vhost_dev_enable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev);
-void vhost_dev_disable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev);
-
-/* Test and clear masked event pending status.
- * Should be called after unmask to avoid losing events.
- */
-bool vhost_virtqueue_pending(struct vhost_dev *hdev, int n);
-
-/* Mask/unmask events from this vq.
- */
-void vhost_virtqueue_mask(struct vhost_dev *hdev, VirtIODevice *vdev, int n,
-                          bool mask);
-#endif
diff --git a/hw/vhost_net.c b/hw/vhost_net.c
deleted file mode 100644 (file)
index d3218a0..0000000
+++ /dev/null
@@ -1,328 +0,0 @@
-/*
- * vhost-net support
- *
- * Copyright Red Hat, Inc. 2010
- *
- * Authors:
- *  Michael S. Tsirkin <mst@redhat.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 "net/net.h"
-#include "net/tap.h"
-
-#include "hw/virtio-net.h"
-#include "hw/vhost_net.h"
-#include "qemu/error-report.h"
-
-#include "config.h"
-
-#ifdef CONFIG_VHOST_NET
-#include <linux/vhost.h>
-#include <sys/socket.h>
-#include <linux/kvm.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <linux/virtio_ring.h>
-#include <netpacket/packet.h>
-#include <net/ethernet.h>
-#include <net/if.h>
-#include <netinet/in.h>
-
-#include <stdio.h>
-
-#include "hw/vhost.h"
-
-struct vhost_net {
-    struct vhost_dev dev;
-    struct vhost_virtqueue vqs[2];
-    int backend;
-    NetClientState *nc;
-};
-
-unsigned vhost_net_get_features(struct vhost_net *net, unsigned features)
-{
-    /* Clear features not supported by host kernel. */
-    if (!(net->dev.features & (1 << VIRTIO_F_NOTIFY_ON_EMPTY))) {
-        features &= ~(1 << VIRTIO_F_NOTIFY_ON_EMPTY);
-    }
-    if (!(net->dev.features & (1 << VIRTIO_RING_F_INDIRECT_DESC))) {
-        features &= ~(1 << VIRTIO_RING_F_INDIRECT_DESC);
-    }
-    if (!(net->dev.features & (1 << VIRTIO_RING_F_EVENT_IDX))) {
-        features &= ~(1 << VIRTIO_RING_F_EVENT_IDX);
-    }
-    if (!(net->dev.features & (1 << VIRTIO_NET_F_MRG_RXBUF))) {
-        features &= ~(1 << VIRTIO_NET_F_MRG_RXBUF);
-    }
-    return features;
-}
-
-void vhost_net_ack_features(struct vhost_net *net, unsigned features)
-{
-    net->dev.acked_features = net->dev.backend_features;
-    if (features & (1 << VIRTIO_F_NOTIFY_ON_EMPTY)) {
-        net->dev.acked_features |= (1 << VIRTIO_F_NOTIFY_ON_EMPTY);
-    }
-    if (features & (1 << VIRTIO_RING_F_INDIRECT_DESC)) {
-        net->dev.acked_features |= (1 << VIRTIO_RING_F_INDIRECT_DESC);
-    }
-    if (features & (1 << VIRTIO_RING_F_EVENT_IDX)) {
-        net->dev.acked_features |= (1 << VIRTIO_RING_F_EVENT_IDX);
-    }
-    if (features & (1 << VIRTIO_NET_F_MRG_RXBUF)) {
-        net->dev.acked_features |= (1 << VIRTIO_NET_F_MRG_RXBUF);
-    }
-}
-
-static int vhost_net_get_fd(NetClientState *backend)
-{
-    switch (backend->info->type) {
-    case NET_CLIENT_OPTIONS_KIND_TAP:
-        return tap_get_fd(backend);
-    default:
-        fprintf(stderr, "vhost-net requires tap backend\n");
-        return -EBADFD;
-    }
-}
-
-struct vhost_net *vhost_net_init(NetClientState *backend, int devfd,
-                                 bool force)
-{
-    int r;
-    struct vhost_net *net = g_malloc(sizeof *net);
-    if (!backend) {
-        fprintf(stderr, "vhost-net requires backend to be setup\n");
-        goto fail;
-    }
-    r = vhost_net_get_fd(backend);
-    if (r < 0) {
-        goto fail;
-    }
-    net->nc = backend;
-    net->dev.backend_features = tap_has_vnet_hdr(backend) ? 0 :
-        (1 << VHOST_NET_F_VIRTIO_NET_HDR);
-    net->backend = r;
-
-    net->dev.nvqs = 2;
-    net->dev.vqs = net->vqs;
-
-    r = vhost_dev_init(&net->dev, devfd, "/dev/vhost-net", force);
-    if (r < 0) {
-        goto fail;
-    }
-    if (!tap_has_vnet_hdr_len(backend,
-                              sizeof(struct virtio_net_hdr_mrg_rxbuf))) {
-        net->dev.features &= ~(1 << VIRTIO_NET_F_MRG_RXBUF);
-    }
-    if (~net->dev.features & net->dev.backend_features) {
-        fprintf(stderr, "vhost lacks feature mask %" PRIu64 " for backend\n",
-                (uint64_t)(~net->dev.features & net->dev.backend_features));
-        vhost_dev_cleanup(&net->dev);
-        goto fail;
-    }
-
-    /* Set sane init value. Override when guest acks. */
-    vhost_net_ack_features(net, 0);
-    return net;
-fail:
-    g_free(net);
-    return NULL;
-}
-
-bool vhost_net_query(VHostNetState *net, VirtIODevice *dev)
-{
-    return vhost_dev_query(&net->dev, dev);
-}
-
-static int vhost_net_start_one(struct vhost_net *net,
-                               VirtIODevice *dev,
-                               int vq_index)
-{
-    struct vhost_vring_file file = { };
-    int r;
-
-    if (net->dev.started) {
-        return 0;
-    }
-
-    net->dev.nvqs = 2;
-    net->dev.vqs = net->vqs;
-    net->dev.vq_index = vq_index;
-
-    r = vhost_dev_enable_notifiers(&net->dev, dev);
-    if (r < 0) {
-        goto fail_notifiers;
-    }
-
-    r = vhost_dev_start(&net->dev, dev);
-    if (r < 0) {
-        goto fail_start;
-    }
-
-    net->nc->info->poll(net->nc, false);
-    qemu_set_fd_handler(net->backend, NULL, NULL, NULL);
-    file.fd = net->backend;
-    for (file.index = 0; file.index < net->dev.nvqs; ++file.index) {
-        r = ioctl(net->dev.control, VHOST_NET_SET_BACKEND, &file);
-        if (r < 0) {
-            r = -errno;
-            goto fail;
-        }
-    }
-    return 0;
-fail:
-    file.fd = -1;
-    while (file.index-- > 0) {
-        int r = ioctl(net->dev.control, VHOST_NET_SET_BACKEND, &file);
-        assert(r >= 0);
-    }
-    net->nc->info->poll(net->nc, true);
-    vhost_dev_stop(&net->dev, dev);
-fail_start:
-    vhost_dev_disable_notifiers(&net->dev, dev);
-fail_notifiers:
-    return r;
-}
-
-static void vhost_net_stop_one(struct vhost_net *net,
-                               VirtIODevice *dev)
-{
-    struct vhost_vring_file file = { .fd = -1 };
-
-    if (!net->dev.started) {
-        return;
-    }
-
-    for (file.index = 0; file.index < net->dev.nvqs; ++file.index) {
-        int r = ioctl(net->dev.control, VHOST_NET_SET_BACKEND, &file);
-        assert(r >= 0);
-    }
-    net->nc->info->poll(net->nc, true);
-    vhost_dev_stop(&net->dev, dev);
-    vhost_dev_disable_notifiers(&net->dev, dev);
-}
-
-int vhost_net_start(VirtIODevice *dev, NetClientState *ncs,
-                    int total_queues)
-{
-    int r, i = 0;
-
-    if (!dev->binding->set_guest_notifiers) {
-        error_report("binding does not support guest notifiers");
-        r = -ENOSYS;
-        goto err;
-    }
-
-    for (i = 0; i < total_queues; i++) {
-        r = vhost_net_start_one(tap_get_vhost_net(ncs[i].peer), dev, i * 2);
-
-        if (r < 0) {
-            goto err;
-        }
-    }
-
-    r = dev->binding->set_guest_notifiers(dev->binding_opaque,
-                                          total_queues * 2,
-                                          true);
-    if (r < 0) {
-        error_report("Error binding guest notifier: %d", -r);
-        goto err;
-    }
-
-    return 0;
-
-err:
-    while (--i >= 0) {
-        vhost_net_stop_one(tap_get_vhost_net(ncs[i].peer), dev);
-    }
-    return r;
-}
-
-void vhost_net_stop(VirtIODevice *dev, NetClientState *ncs,
-                    int total_queues)
-{
-    int i, r;
-
-    r = dev->binding->set_guest_notifiers(dev->binding_opaque,
-                                          total_queues * 2,
-                                          false);
-    if (r < 0) {
-        fprintf(stderr, "vhost guest notifier cleanup failed: %d\n", r);
-        fflush(stderr);
-    }
-    assert(r >= 0);
-
-    for (i = 0; i < total_queues; i++) {
-        vhost_net_stop_one(tap_get_vhost_net(ncs[i].peer), dev);
-    }
-}
-
-void vhost_net_cleanup(struct vhost_net *net)
-{
-    vhost_dev_cleanup(&net->dev);
-    g_free(net);
-}
-
-bool vhost_net_virtqueue_pending(VHostNetState *net, int idx)
-{
-    return vhost_virtqueue_pending(&net->dev, idx);
-}
-
-void vhost_net_virtqueue_mask(VHostNetState *net, VirtIODevice *dev,
-                              int idx, bool mask)
-{
-    vhost_virtqueue_mask(&net->dev, dev, idx, mask);
-}
-#else
-struct vhost_net *vhost_net_init(NetClientState *backend, int devfd,
-                                 bool force)
-{
-    error_report("vhost-net support is not compiled in");
-    return NULL;
-}
-
-bool vhost_net_query(VHostNetState *net, VirtIODevice *dev)
-{
-    return false;
-}
-
-int vhost_net_start(VirtIODevice *dev,
-                    NetClientState *ncs,
-                    int total_queues)
-{
-    return -ENOSYS;
-}
-void vhost_net_stop(VirtIODevice *dev,
-                    NetClientState *ncs,
-                    int total_queues)
-{
-}
-
-void vhost_net_cleanup(struct vhost_net *net)
-{
-}
-
-unsigned vhost_net_get_features(struct vhost_net *net, unsigned features)
-{
-    return features;
-}
-void vhost_net_ack_features(struct vhost_net *net, unsigned features)
-{
-}
-
-bool vhost_net_virtqueue_pending(VHostNetState *net, int idx)
-{
-    return -ENOSYS;
-}
-
-void vhost_net_virtqueue_mask(VHostNetState *net, VirtIODevice *dev,
-                              int idx, bool mask)
-{
-}
-#endif
diff --git a/hw/vhost_net.h b/hw/vhost_net.h
deleted file mode 100644 (file)
index 2d936bb..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-#ifndef VHOST_NET_H
-#define VHOST_NET_H
-
-#include "net/net.h"
-
-struct vhost_net;
-typedef struct vhost_net VHostNetState;
-
-VHostNetState *vhost_net_init(NetClientState *backend, int devfd, bool force);
-
-bool vhost_net_query(VHostNetState *net, VirtIODevice *dev);
-int vhost_net_start(VirtIODevice *dev, NetClientState *ncs, int total_queues);
-void vhost_net_stop(VirtIODevice *dev, NetClientState *ncs, int total_queues);
-
-void vhost_net_cleanup(VHostNetState *net);
-
-unsigned vhost_net_get_features(VHostNetState *net, unsigned features);
-void vhost_net_ack_features(VHostNetState *net, unsigned features);
-
-bool vhost_net_virtqueue_pending(VHostNetState *net, int n);
-void vhost_net_virtqueue_mask(VHostNetState *net, VirtIODevice *dev,
-                              int idx, bool mask);
-#endif
diff --git a/hw/virtio-balloon.c b/hw/virtio-balloon.c
deleted file mode 100644 (file)
index b382bd4..0000000
+++ /dev/null
@@ -1,416 +0,0 @@
-/*
- * Virtio Balloon Device
- *
- * Copyright IBM, Corp. 2008
- * Copyright (C) 2011 Red Hat, Inc.
- * Copyright (C) 2011 Amit Shah <amit.shah@redhat.com>
- *
- * Authors:
- *  Anthony Liguori   <aliguori@us.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 "qemu/iov.h"
-#include "qemu/timer.h"
-#include "qemu-common.h"
-#include "hw/virtio.h"
-#include "hw/pc.h"
-#include "cpu.h"
-#include "sysemu/balloon.h"
-#include "hw/virtio-balloon.h"
-#include "sysemu/kvm.h"
-#include "exec/address-spaces.h"
-#include "qapi/visitor.h"
-
-#if defined(__linux__)
-#include <sys/mman.h>
-#endif
-
-#include "hw/virtio-bus.h"
-
-static void balloon_page(void *addr, int deflate)
-{
-#if defined(__linux__)
-    if (!kvm_enabled() || kvm_has_sync_mmu())
-        qemu_madvise(addr, TARGET_PAGE_SIZE,
-                deflate ? QEMU_MADV_WILLNEED : QEMU_MADV_DONTNEED);
-#endif
-}
-
-static const char *balloon_stat_names[] = {
-   [VIRTIO_BALLOON_S_SWAP_IN] = "stat-swap-in",
-   [VIRTIO_BALLOON_S_SWAP_OUT] = "stat-swap-out",
-   [VIRTIO_BALLOON_S_MAJFLT] = "stat-major-faults",
-   [VIRTIO_BALLOON_S_MINFLT] = "stat-minor-faults",
-   [VIRTIO_BALLOON_S_MEMFREE] = "stat-free-memory",
-   [VIRTIO_BALLOON_S_MEMTOT] = "stat-total-memory",
-   [VIRTIO_BALLOON_S_NR] = NULL
-};
-
-/*
- * reset_stats - Mark all items in the stats array as unset
- *
- * This function needs to be called at device intialization and before
- * before updating to a set of newly-generated stats.  This will ensure that no
- * stale values stick around in case the guest reports a subset of the supported
- * statistics.
- */
-static inline void reset_stats(VirtIOBalloon *dev)
-{
-    int i;
-    for (i = 0; i < VIRTIO_BALLOON_S_NR; dev->stats[i++] = -1);
-}
-
-static bool balloon_stats_supported(const VirtIOBalloon *s)
-{
-    VirtIODevice *vdev = VIRTIO_DEVICE(s);
-    return vdev->guest_features & (1 << VIRTIO_BALLOON_F_STATS_VQ);
-}
-
-static bool balloon_stats_enabled(const VirtIOBalloon *s)
-{
-    return s->stats_poll_interval > 0;
-}
-
-static void balloon_stats_destroy_timer(VirtIOBalloon *s)
-{
-    if (balloon_stats_enabled(s)) {
-        qemu_del_timer(s->stats_timer);
-        qemu_free_timer(s->stats_timer);
-        s->stats_timer = NULL;
-        s->stats_poll_interval = 0;
-    }
-}
-
-static void balloon_stats_change_timer(VirtIOBalloon *s, int secs)
-{
-    qemu_mod_timer(s->stats_timer, qemu_get_clock_ms(vm_clock) + secs * 1000);
-}
-
-static void balloon_stats_poll_cb(void *opaque)
-{
-    VirtIOBalloon *s = opaque;
-    VirtIODevice *vdev = VIRTIO_DEVICE(s);
-
-    if (!balloon_stats_supported(s)) {
-        /* re-schedule */
-        balloon_stats_change_timer(s, s->stats_poll_interval);
-        return;
-    }
-
-    virtqueue_push(s->svq, &s->stats_vq_elem, s->stats_vq_offset);
-    virtio_notify(vdev, s->svq);
-}
-
-static void balloon_stats_get_all(Object *obj, struct Visitor *v,
-                                  void *opaque, const char *name, Error **errp)
-{
-    VirtIOBalloon *s = opaque;
-    int i;
-
-    if (!s->stats_last_update) {
-        error_setg(errp, "guest hasn't updated any stats yet");
-        return;
-    }
-
-    visit_start_struct(v, NULL, "guest-stats", name, 0, errp);
-    visit_type_int(v, &s->stats_last_update, "last-update", errp);
-
-    visit_start_struct(v, NULL, NULL, "stats", 0, errp);
-    for (i = 0; i < VIRTIO_BALLOON_S_NR; i++) {
-        visit_type_int64(v, (int64_t *) &s->stats[i], balloon_stat_names[i],
-                         errp);
-    }
-    visit_end_struct(v, errp);
-
-    visit_end_struct(v, errp);
-}
-
-static void balloon_stats_get_poll_interval(Object *obj, struct Visitor *v,
-                                            void *opaque, const char *name,
-                                            Error **errp)
-{
-    VirtIOBalloon *s = opaque;
-    visit_type_int(v, &s->stats_poll_interval, name, errp);
-}
-
-static void balloon_stats_set_poll_interval(Object *obj, struct Visitor *v,
-                                            void *opaque, const char *name,
-                                            Error **errp)
-{
-    VirtIOBalloon *s = opaque;
-    int64_t value;
-
-    visit_type_int(v, &value, name, errp);
-    if (error_is_set(errp)) {
-        return;
-    }
-
-    if (value < 0) {
-        error_setg(errp, "timer value must be greater than zero");
-        return;
-    }
-
-    if (value == s->stats_poll_interval) {
-        return;
-    }
-
-    if (value == 0) {
-        /* timer=0 disables the timer */
-        balloon_stats_destroy_timer(s);
-        return;
-    }
-
-    if (balloon_stats_enabled(s)) {
-        /* timer interval change */
-        s->stats_poll_interval = value;
-        balloon_stats_change_timer(s, value);
-        return;
-    }
-
-    /* create a new timer */
-    g_assert(s->stats_timer == NULL);
-    s->stats_timer = qemu_new_timer_ms(vm_clock, balloon_stats_poll_cb, s);
-    s->stats_poll_interval = value;
-    balloon_stats_change_timer(s, 0);
-}
-
-static void virtio_balloon_handle_output(VirtIODevice *vdev, VirtQueue *vq)
-{
-    VirtIOBalloon *s = VIRTIO_BALLOON(vdev);
-    VirtQueueElement elem;
-    MemoryRegionSection section;
-
-    while (virtqueue_pop(vq, &elem)) {
-        size_t offset = 0;
-        uint32_t pfn;
-
-        while (iov_to_buf(elem.out_sg, elem.out_num, offset, &pfn, 4) == 4) {
-            ram_addr_t pa;
-            ram_addr_t addr;
-
-            pa = (ram_addr_t)ldl_p(&pfn) << VIRTIO_BALLOON_PFN_SHIFT;
-            offset += 4;
-
-            /* FIXME: remove get_system_memory(), but how? */
-            section = memory_region_find(get_system_memory(), pa, 1);
-            if (!section.size || !memory_region_is_ram(section.mr))
-                continue;
-
-            /* Using memory_region_get_ram_ptr is bending the rules a bit, but
-               should be OK because we only want a single page.  */
-            addr = section.offset_within_region;
-            balloon_page(memory_region_get_ram_ptr(section.mr) + addr,
-                         !!(vq == s->dvq));
-        }
-
-        virtqueue_push(vq, &elem, offset);
-        virtio_notify(vdev, vq);
-    }
-}
-
-static void virtio_balloon_receive_stats(VirtIODevice *vdev, VirtQueue *vq)
-{
-    VirtIOBalloon *s = VIRTIO_BALLOON(vdev);
-    VirtQueueElement *elem = &s->stats_vq_elem;
-    VirtIOBalloonStat stat;
-    size_t offset = 0;
-    qemu_timeval tv;
-
-    if (!virtqueue_pop(vq, elem)) {
-        goto out;
-    }
-
-    /* Initialize the stats to get rid of any stale values.  This is only
-     * needed to handle the case where a guest supports fewer stats than it
-     * used to (ie. it has booted into an old kernel).
-     */
-    reset_stats(s);
-
-    while (iov_to_buf(elem->out_sg, elem->out_num, offset, &stat, sizeof(stat))
-           == sizeof(stat)) {
-        uint16_t tag = tswap16(stat.tag);
-        uint64_t val = tswap64(stat.val);
-
-        offset += sizeof(stat);
-        if (tag < VIRTIO_BALLOON_S_NR)
-            s->stats[tag] = val;
-    }
-    s->stats_vq_offset = offset;
-
-    if (qemu_gettimeofday(&tv) < 0) {
-        fprintf(stderr, "warning: %s: failed to get time of day\n", __func__);
-        goto out;
-    }
-
-    s->stats_last_update = tv.tv_sec;
-
-out:
-    if (balloon_stats_enabled(s)) {
-        balloon_stats_change_timer(s, s->stats_poll_interval);
-    }
-}
-
-static void virtio_balloon_get_config(VirtIODevice *vdev, uint8_t *config_data)
-{
-    VirtIOBalloon *dev = VIRTIO_BALLOON(vdev);
-    struct virtio_balloon_config config;
-
-    config.num_pages = cpu_to_le32(dev->num_pages);
-    config.actual = cpu_to_le32(dev->actual);
-
-    memcpy(config_data, &config, 8);
-}
-
-static void virtio_balloon_set_config(VirtIODevice *vdev,
-                                      const uint8_t *config_data)
-{
-    VirtIOBalloon *dev = VIRTIO_BALLOON(vdev);
-    struct virtio_balloon_config config;
-    uint32_t oldactual = dev->actual;
-    memcpy(&config, config_data, 8);
-    dev->actual = le32_to_cpu(config.actual);
-    if (dev->actual != oldactual) {
-        qemu_balloon_changed(ram_size -
-                             (dev->actual << VIRTIO_BALLOON_PFN_SHIFT));
-    }
-}
-
-static uint32_t virtio_balloon_get_features(VirtIODevice *vdev, uint32_t f)
-{
-    f |= (1 << VIRTIO_BALLOON_F_STATS_VQ);
-    return f;
-}
-
-static void virtio_balloon_stat(void *opaque, BalloonInfo *info)
-{
-    VirtIOBalloon *dev = opaque;
-    info->actual = ram_size - ((uint64_t) dev->actual <<
-                               VIRTIO_BALLOON_PFN_SHIFT);
-}
-
-static void virtio_balloon_to_target(void *opaque, ram_addr_t target)
-{
-    VirtIOBalloon *dev = VIRTIO_BALLOON(opaque);
-    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
-
-    if (target > ram_size) {
-        target = ram_size;
-    }
-    if (target) {
-        dev->num_pages = (ram_size - target) >> VIRTIO_BALLOON_PFN_SHIFT;
-        virtio_notify_config(vdev);
-    }
-}
-
-static void virtio_balloon_save(QEMUFile *f, void *opaque)
-{
-    VirtIOBalloon *s = VIRTIO_BALLOON(opaque);
-    VirtIODevice *vdev = VIRTIO_DEVICE(s);
-
-    virtio_save(vdev, f);
-
-    qemu_put_be32(f, s->num_pages);
-    qemu_put_be32(f, s->actual);
-}
-
-static int virtio_balloon_load(QEMUFile *f, void *opaque, int version_id)
-{
-    VirtIOBalloon *s = VIRTIO_BALLOON(opaque);
-    VirtIODevice *vdev = VIRTIO_DEVICE(s);
-    int ret;
-
-    if (version_id != 1)
-        return -EINVAL;
-
-    ret = virtio_load(vdev, f);
-    if (ret) {
-        return ret;
-    }
-
-    s->num_pages = qemu_get_be32(f);
-    s->actual = qemu_get_be32(f);
-    return 0;
-}
-
-static int virtio_balloon_device_init(VirtIODevice *vdev)
-{
-    DeviceState *qdev = DEVICE(vdev);
-    VirtIOBalloon *s = VIRTIO_BALLOON(vdev);
-    int ret;
-
-    virtio_init(vdev, "virtio-balloon", VIRTIO_ID_BALLOON, 8);
-
-    vdev->get_config = virtio_balloon_get_config;
-    vdev->set_config = virtio_balloon_set_config;
-    vdev->get_features = virtio_balloon_get_features;
-
-    ret = qemu_add_balloon_handler(virtio_balloon_to_target,
-                                   virtio_balloon_stat, s);
-
-    if (ret < 0) {
-        virtio_common_cleanup(VIRTIO_DEVICE(s));
-        return -1;
-    }
-
-    s->ivq = virtio_add_queue(vdev, 128, virtio_balloon_handle_output);
-    s->dvq = virtio_add_queue(vdev, 128, virtio_balloon_handle_output);
-    s->svq = virtio_add_queue(vdev, 128, virtio_balloon_receive_stats);
-
-    register_savevm(qdev, "virtio-balloon", -1, 1,
-                    virtio_balloon_save, virtio_balloon_load, s);
-
-    object_property_add(OBJECT(qdev), "guest-stats", "guest statistics",
-                        balloon_stats_get_all, NULL, NULL, s, NULL);
-
-    object_property_add(OBJECT(qdev), "guest-stats-polling-interval", "int",
-                        balloon_stats_get_poll_interval,
-                        balloon_stats_set_poll_interval,
-                        NULL, s, NULL);
-    return 0;
-}
-
-static int virtio_balloon_device_exit(DeviceState *qdev)
-{
-    VirtIOBalloon *s = VIRTIO_BALLOON(qdev);
-    VirtIODevice *vdev = VIRTIO_DEVICE(qdev);
-
-    balloon_stats_destroy_timer(s);
-    qemu_remove_balloon_handler(s);
-    unregister_savevm(qdev, "virtio-balloon", s);
-    virtio_common_cleanup(vdev);
-    return 0;
-}
-
-static Property virtio_balloon_properties[] = {
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void virtio_balloon_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
-    dc->exit = virtio_balloon_device_exit;
-    dc->props = virtio_balloon_properties;
-    vdc->init = virtio_balloon_device_init;
-    vdc->get_config = virtio_balloon_get_config;
-    vdc->set_config = virtio_balloon_set_config;
-    vdc->get_features = virtio_balloon_get_features;
-}
-
-static const TypeInfo virtio_balloon_info = {
-    .name = TYPE_VIRTIO_BALLOON,
-    .parent = TYPE_VIRTIO_DEVICE,
-    .instance_size = sizeof(VirtIOBalloon),
-    .class_init = virtio_balloon_class_init,
-};
-
-static void virtio_register_types(void)
-{
-    type_register_static(&virtio_balloon_info);
-}
-
-type_init(virtio_register_types)
diff --git a/hw/virtio-balloon.h b/hw/virtio-balloon.h
deleted file mode 100644 (file)
index d898315..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Virtio Support
- *
- * Copyright IBM, Corp. 2007-2008
- *
- * Authors:
- *  Anthony Liguori   <aliguori@us.ibm.com>
- *  Rusty Russell     <rusty@rustcorp.com.au>
- *
- * This work is licensed under the terms of the GNU GPL, version 2.  See
- * the COPYING file in the top-level directory.
- *
- */
-
-#ifndef _QEMU_VIRTIO_BALLOON_H
-#define _QEMU_VIRTIO_BALLOON_H
-
-#include "hw/virtio.h"
-#include "hw/pci/pci.h"
-
-#define TYPE_VIRTIO_BALLOON "virtio-balloon"
-#define VIRTIO_BALLOON(obj) \
-        OBJECT_CHECK(VirtIOBalloon, (obj), TYPE_VIRTIO_BALLOON)
-
-/* from Linux's linux/virtio_balloon.h */
-
-/* The ID for virtio_balloon */
-#define VIRTIO_ID_BALLOON 5
-
-/* The feature bitmap for virtio balloon */
-#define VIRTIO_BALLOON_F_MUST_TELL_HOST 0 /* Tell before reclaiming pages */
-#define VIRTIO_BALLOON_F_STATS_VQ 1       /* Memory stats virtqueue */
-
-/* Size of a PFN in the balloon interface. */
-#define VIRTIO_BALLOON_PFN_SHIFT 12
-
-struct virtio_balloon_config
-{
-    /* Number of pages host wants Guest to give up. */
-    uint32_t num_pages;
-    /* Number of pages we've actually got in balloon. */
-    uint32_t actual;
-};
-
-/* Memory Statistics */
-#define VIRTIO_BALLOON_S_SWAP_IN  0   /* Amount of memory swapped in */
-#define VIRTIO_BALLOON_S_SWAP_OUT 1   /* Amount of memory swapped out */
-#define VIRTIO_BALLOON_S_MAJFLT   2   /* Number of major faults */
-#define VIRTIO_BALLOON_S_MINFLT   3   /* Number of minor faults */
-#define VIRTIO_BALLOON_S_MEMFREE  4   /* Total amount of free memory */
-#define VIRTIO_BALLOON_S_MEMTOT   5   /* Total amount of memory */
-#define VIRTIO_BALLOON_S_NR       6
-
-typedef struct VirtIOBalloonStat {
-    uint16_t tag;
-    uint64_t val;
-} QEMU_PACKED VirtIOBalloonStat;
-
-typedef struct VirtIOBalloon {
-    VirtIODevice parent_obj;
-    VirtQueue *ivq, *dvq, *svq;
-    uint32_t num_pages;
-    uint32_t actual;
-    uint64_t stats[VIRTIO_BALLOON_S_NR];
-    VirtQueueElement stats_vq_elem;
-    size_t stats_vq_offset;
-    QEMUTimer *stats_timer;
-    int64_t stats_last_update;
-    int64_t stats_poll_interval;
-} VirtIOBalloon;
-
-#endif
diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c
deleted file mode 100644 (file)
index f2143fd..0000000
+++ /dev/null
@@ -1,729 +0,0 @@
-/*
- * Virtio Block Device
- *
- * Copyright IBM, Corp. 2007
- *
- * Authors:
- *  Anthony Liguori   <aliguori@us.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 "qemu-common.h"
-#include "qemu/error-report.h"
-#include "trace.h"
-#include "hw/block-common.h"
-#include "sysemu/blockdev.h"
-#include "hw/virtio-blk.h"
-#include "hw/scsi-defs.h"
-#ifdef __linux__
-# include <scsi/sg.h>
-#endif
-#include "hw/virtio-bus.h"
-
-typedef struct VirtIOBlockReq
-{
-    VirtIOBlock *dev;
-    VirtQueueElement elem;
-    struct virtio_blk_inhdr *in;
-    struct virtio_blk_outhdr *out;
-    struct virtio_scsi_inhdr *scsi;
-    QEMUIOVector qiov;
-    struct VirtIOBlockReq *next;
-    BlockAcctCookie acct;
-} VirtIOBlockReq;
-
-static void virtio_blk_req_complete(VirtIOBlockReq *req, int status)
-{
-    VirtIOBlock *s = req->dev;
-    VirtIODevice *vdev = VIRTIO_DEVICE(s);
-
-    trace_virtio_blk_req_complete(req, status);
-
-    stb_p(&req->in->status, status);
-    virtqueue_push(s->vq, &req->elem, req->qiov.size + sizeof(*req->in));
-    virtio_notify(vdev, s->vq);
-}
-
-static int virtio_blk_handle_rw_error(VirtIOBlockReq *req, int error,
-    bool is_read)
-{
-    BlockErrorAction action = bdrv_get_error_action(req->dev->bs, is_read, error);
-    VirtIOBlock *s = req->dev;
-
-    if (action == BDRV_ACTION_STOP) {
-        req->next = s->rq;
-        s->rq = req;
-    } else if (action == BDRV_ACTION_REPORT) {
-        virtio_blk_req_complete(req, VIRTIO_BLK_S_IOERR);
-        bdrv_acct_done(s->bs, &req->acct);
-        g_free(req);
-    }
-
-    bdrv_error_action(s->bs, action, is_read, error);
-    return action != BDRV_ACTION_IGNORE;
-}
-
-static void virtio_blk_rw_complete(void *opaque, int ret)
-{
-    VirtIOBlockReq *req = opaque;
-
-    trace_virtio_blk_rw_complete(req, ret);
-
-    if (ret) {
-        bool is_read = !(ldl_p(&req->out->type) & VIRTIO_BLK_T_OUT);
-        if (virtio_blk_handle_rw_error(req, -ret, is_read))
-            return;
-    }
-
-    virtio_blk_req_complete(req, VIRTIO_BLK_S_OK);
-    bdrv_acct_done(req->dev->bs, &req->acct);
-    g_free(req);
-}
-
-static void virtio_blk_flush_complete(void *opaque, int ret)
-{
-    VirtIOBlockReq *req = opaque;
-
-    if (ret) {
-        if (virtio_blk_handle_rw_error(req, -ret, 0)) {
-            return;
-        }
-    }
-
-    virtio_blk_req_complete(req, VIRTIO_BLK_S_OK);
-    bdrv_acct_done(req->dev->bs, &req->acct);
-    g_free(req);
-}
-
-static VirtIOBlockReq *virtio_blk_alloc_request(VirtIOBlock *s)
-{
-    VirtIOBlockReq *req = g_malloc(sizeof(*req));
-    req->dev = s;
-    req->qiov.size = 0;
-    req->next = NULL;
-    return req;
-}
-
-static VirtIOBlockReq *virtio_blk_get_request(VirtIOBlock *s)
-{
-    VirtIOBlockReq *req = virtio_blk_alloc_request(s);
-
-    if (req != NULL) {
-        if (!virtqueue_pop(s->vq, &req->elem)) {
-            g_free(req);
-            return NULL;
-        }
-    }
-
-    return req;
-}
-
-static void virtio_blk_handle_scsi(VirtIOBlockReq *req)
-{
-#ifdef __linux__
-    int ret;
-    int i;
-#endif
-    int status = VIRTIO_BLK_S_OK;
-
-    /*
-     * We require at least one output segment each for the virtio_blk_outhdr
-     * and the SCSI command block.
-     *
-     * We also at least require the virtio_blk_inhdr, the virtio_scsi_inhdr
-     * and the sense buffer pointer in the input segments.
-     */
-    if (req->elem.out_num < 2 || req->elem.in_num < 3) {
-        virtio_blk_req_complete(req, VIRTIO_BLK_S_IOERR);
-        g_free(req);
-        return;
-    }
-
-    /*
-     * The scsi inhdr is placed in the second-to-last input segment, just
-     * before the regular inhdr.
-     */
-    req->scsi = (void *)req->elem.in_sg[req->elem.in_num - 2].iov_base;
-
-    if (!req->dev->blk.scsi) {
-        status = VIRTIO_BLK_S_UNSUPP;
-        goto fail;
-    }
-
-    /*
-     * No support for bidirection commands yet.
-     */
-    if (req->elem.out_num > 2 && req->elem.in_num > 3) {
-        status = VIRTIO_BLK_S_UNSUPP;
-        goto fail;
-    }
-
-#ifdef __linux__
-    struct sg_io_hdr hdr;
-    memset(&hdr, 0, sizeof(struct sg_io_hdr));
-    hdr.interface_id = 'S';
-    hdr.cmd_len = req->elem.out_sg[1].iov_len;
-    hdr.cmdp = req->elem.out_sg[1].iov_base;
-    hdr.dxfer_len = 0;
-
-    if (req->elem.out_num > 2) {
-        /*
-         * If there are more than the minimally required 2 output segments
-         * there is write payload starting from the third iovec.
-         */
-        hdr.dxfer_direction = SG_DXFER_TO_DEV;
-        hdr.iovec_count = req->elem.out_num - 2;
-
-        for (i = 0; i < hdr.iovec_count; i++)
-            hdr.dxfer_len += req->elem.out_sg[i + 2].iov_len;
-
-        hdr.dxferp = req->elem.out_sg + 2;
-
-    } else if (req->elem.in_num > 3) {
-        /*
-         * If we have more than 3 input segments the guest wants to actually
-         * read data.
-         */
-        hdr.dxfer_direction = SG_DXFER_FROM_DEV;
-        hdr.iovec_count = req->elem.in_num - 3;
-        for (i = 0; i < hdr.iovec_count; i++)
-            hdr.dxfer_len += req->elem.in_sg[i].iov_len;
-
-        hdr.dxferp = req->elem.in_sg;
-    } else {
-        /*
-         * Some SCSI commands don't actually transfer any data.
-         */
-        hdr.dxfer_direction = SG_DXFER_NONE;
-    }
-
-    hdr.sbp = req->elem.in_sg[req->elem.in_num - 3].iov_base;
-    hdr.mx_sb_len = req->elem.in_sg[req->elem.in_num - 3].iov_len;
-
-    ret = bdrv_ioctl(req->dev->bs, SG_IO, &hdr);
-    if (ret) {
-        status = VIRTIO_BLK_S_UNSUPP;
-        goto fail;
-    }
-
-    /*
-     * From SCSI-Generic-HOWTO: "Some lower level drivers (e.g. ide-scsi)
-     * clear the masked_status field [hence status gets cleared too, see
-     * block/scsi_ioctl.c] even when a CHECK_CONDITION or COMMAND_TERMINATED
-     * status has occurred.  However they do set DRIVER_SENSE in driver_status
-     * field. Also a (sb_len_wr > 0) indicates there is a sense buffer.
-     */
-    if (hdr.status == 0 && hdr.sb_len_wr > 0) {
-        hdr.status = CHECK_CONDITION;
-    }
-
-    stl_p(&req->scsi->errors,
-          hdr.status | (hdr.msg_status << 8) |
-          (hdr.host_status << 16) | (hdr.driver_status << 24));
-    stl_p(&req->scsi->residual, hdr.resid);
-    stl_p(&req->scsi->sense_len, hdr.sb_len_wr);
-    stl_p(&req->scsi->data_len, hdr.dxfer_len);
-
-    virtio_blk_req_complete(req, status);
-    g_free(req);
-    return;
-#else
-    abort();
-#endif
-
-fail:
-    /* Just put anything nonzero so that the ioctl fails in the guest.  */
-    stl_p(&req->scsi->errors, 255);
-    virtio_blk_req_complete(req, status);
-    g_free(req);
-}
-
-typedef struct MultiReqBuffer {
-    BlockRequest        blkreq[32];
-    unsigned int        num_writes;
-} MultiReqBuffer;
-
-static void virtio_submit_multiwrite(BlockDriverState *bs, MultiReqBuffer *mrb)
-{
-    int i, ret;
-
-    if (!mrb->num_writes) {
-        return;
-    }
-
-    ret = bdrv_aio_multiwrite(bs, mrb->blkreq, mrb->num_writes);
-    if (ret != 0) {
-        for (i = 0; i < mrb->num_writes; i++) {
-            if (mrb->blkreq[i].error) {
-                virtio_blk_rw_complete(mrb->blkreq[i].opaque, -EIO);
-            }
-        }
-    }
-
-    mrb->num_writes = 0;
-}
-
-static void virtio_blk_handle_flush(VirtIOBlockReq *req, MultiReqBuffer *mrb)
-{
-    bdrv_acct_start(req->dev->bs, &req->acct, 0, BDRV_ACCT_FLUSH);
-
-    /*
-     * Make sure all outstanding writes are posted to the backing device.
-     */
-    virtio_submit_multiwrite(req->dev->bs, mrb);
-    bdrv_aio_flush(req->dev->bs, virtio_blk_flush_complete, req);
-}
-
-static void virtio_blk_handle_write(VirtIOBlockReq *req, MultiReqBuffer *mrb)
-{
-    BlockRequest *blkreq;
-    uint64_t sector;
-
-    sector = ldq_p(&req->out->sector);
-
-    bdrv_acct_start(req->dev->bs, &req->acct, req->qiov.size, BDRV_ACCT_WRITE);
-
-    trace_virtio_blk_handle_write(req, sector, req->qiov.size / 512);
-
-    if (sector & req->dev->sector_mask) {
-        virtio_blk_rw_complete(req, -EIO);
-        return;
-    }
-    if (req->qiov.size % req->dev->conf->logical_block_size) {
-        virtio_blk_rw_complete(req, -EIO);
-        return;
-    }
-
-    if (mrb->num_writes == 32) {
-        virtio_submit_multiwrite(req->dev->bs, mrb);
-    }
-
-    blkreq = &mrb->blkreq[mrb->num_writes];
-    blkreq->sector = sector;
-    blkreq->nb_sectors = req->qiov.size / BDRV_SECTOR_SIZE;
-    blkreq->qiov = &req->qiov;
-    blkreq->cb = virtio_blk_rw_complete;
-    blkreq->opaque = req;
-    blkreq->error = 0;
-
-    mrb->num_writes++;
-}
-
-static void virtio_blk_handle_read(VirtIOBlockReq *req)
-{
-    uint64_t sector;
-
-    sector = ldq_p(&req->out->sector);
-
-    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;
-    }
-    if (req->qiov.size % req->dev->conf->logical_block_size) {
-        virtio_blk_rw_complete(req, -EIO);
-        return;
-    }
-    bdrv_aio_readv(req->dev->bs, sector, &req->qiov,
-                   req->qiov.size / BDRV_SECTOR_SIZE,
-                   virtio_blk_rw_complete, req);
-}
-
-static void virtio_blk_handle_request(VirtIOBlockReq *req,
-    MultiReqBuffer *mrb)
-{
-    uint32_t type;
-
-    if (req->elem.out_num < 1 || req->elem.in_num < 1) {
-        error_report("virtio-blk missing headers");
-        exit(1);
-    }
-
-    if (req->elem.out_sg[0].iov_len < sizeof(*req->out) ||
-        req->elem.in_sg[req->elem.in_num - 1].iov_len < sizeof(*req->in)) {
-        error_report("virtio-blk header not in correct element");
-        exit(1);
-    }
-
-    req->out = (void *)req->elem.out_sg[0].iov_base;
-    req->in = (void *)req->elem.in_sg[req->elem.in_num - 1].iov_base;
-
-    type = ldl_p(&req->out->type);
-
-    if (type & VIRTIO_BLK_T_FLUSH) {
-        virtio_blk_handle_flush(req, mrb);
-    } else if (type & VIRTIO_BLK_T_SCSI_CMD) {
-        virtio_blk_handle_scsi(req);
-    } else if (type & VIRTIO_BLK_T_GET_ID) {
-        VirtIOBlock *s = req->dev;
-
-        /*
-         * NB: per existing s/n string convention the string is
-         * terminated by '\0' only when shorter than buffer.
-         */
-        strncpy(req->elem.in_sg[0].iov_base,
-                s->blk.serial ? s->blk.serial : "",
-                MIN(req->elem.in_sg[0].iov_len, VIRTIO_BLK_ID_BYTES));
-        virtio_blk_req_complete(req, VIRTIO_BLK_S_OK);
-        g_free(req);
-    } else if (type & VIRTIO_BLK_T_OUT) {
-        qemu_iovec_init_external(&req->qiov, &req->elem.out_sg[1],
-                                 req->elem.out_num - 1);
-        virtio_blk_handle_write(req, mrb);
-    } else if (type == VIRTIO_BLK_T_IN || type == VIRTIO_BLK_T_BARRIER) {
-        /* VIRTIO_BLK_T_IN is 0, so we can't just & it. */
-        qemu_iovec_init_external(&req->qiov, &req->elem.in_sg[0],
-                                 req->elem.in_num - 1);
-        virtio_blk_handle_read(req);
-    } else {
-        virtio_blk_req_complete(req, VIRTIO_BLK_S_UNSUPP);
-        g_free(req);
-    }
-}
-
-static void virtio_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq)
-{
-    VirtIOBlock *s = VIRTIO_BLK(vdev);
-    VirtIOBlockReq *req;
-    MultiReqBuffer mrb = {
-        .num_writes = 0,
-    };
-
-#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE
-    /* Some guests kick before setting VIRTIO_CONFIG_S_DRIVER_OK so start
-     * dataplane here instead of waiting for .set_status().
-     */
-    if (s->dataplane) {
-        virtio_blk_data_plane_start(s->dataplane);
-        return;
-    }
-#endif
-
-    while ((req = virtio_blk_get_request(s))) {
-        virtio_blk_handle_request(req, &mrb);
-    }
-
-    virtio_submit_multiwrite(s->bs, &mrb);
-
-    /*
-     * FIXME: Want to check for completions before returning to guest mode,
-     * so cached reads and writes are reported as quickly as possible. But
-     * that should be done in the generic block layer.
-     */
-}
-
-static void virtio_blk_dma_restart_bh(void *opaque)
-{
-    VirtIOBlock *s = opaque;
-    VirtIOBlockReq *req = s->rq;
-    MultiReqBuffer mrb = {
-        .num_writes = 0,
-    };
-
-    qemu_bh_delete(s->bh);
-    s->bh = NULL;
-
-    s->rq = NULL;
-
-    while (req) {
-        virtio_blk_handle_request(req, &mrb);
-        req = req->next;
-    }
-
-    virtio_submit_multiwrite(s->bs, &mrb);
-}
-
-static void virtio_blk_dma_restart_cb(void *opaque, int running,
-                                      RunState state)
-{
-    VirtIOBlock *s = opaque;
-
-    if (!running) {
-        return;
-    }
-
-    if (!s->bh) {
-        s->bh = qemu_bh_new(virtio_blk_dma_restart_bh, s);
-        qemu_bh_schedule(s->bh);
-    }
-}
-
-static void virtio_blk_reset(VirtIODevice *vdev)
-{
-#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE
-    VirtIOBlock *s = VIRTIO_BLK(vdev);
-
-    if (s->dataplane) {
-        virtio_blk_data_plane_stop(s->dataplane);
-    }
-#endif
-
-    /*
-     * This should cancel pending requests, but can't do nicely until there
-     * are per-device request lists.
-     */
-    bdrv_drain_all();
-}
-
-/* coalesce internal state, copy to pci i/o region 0
- */
-static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config)
-{
-    VirtIOBlock *s = VIRTIO_BLK(vdev);
-    struct virtio_blk_config blkcfg;
-    uint64_t capacity;
-    int blk_size = s->conf->logical_block_size;
-
-    bdrv_get_geometry(s->bs, &capacity);
-    memset(&blkcfg, 0, sizeof(blkcfg));
-    stq_raw(&blkcfg.capacity, capacity);
-    stl_raw(&blkcfg.seg_max, 128 - 2);
-    stw_raw(&blkcfg.cylinders, s->conf->cyls);
-    stl_raw(&blkcfg.blk_size, blk_size);
-    stw_raw(&blkcfg.min_io_size, s->conf->min_io_size / blk_size);
-    stw_raw(&blkcfg.opt_io_size, s->conf->opt_io_size / blk_size);
-    blkcfg.heads = s->conf->heads;
-    /*
-     * We must ensure that the block device capacity is a multiple of
-     * the logical block size. If that is not the case, lets use
-     * sector_mask to adopt the geometry to have a correct picture.
-     * For those devices where the capacity is ok for the given geometry
-     * we dont touch the sector value of the geometry, since some devices
-     * (like s390 dasd) need a specific value. Here the capacity is already
-     * cyls*heads*secs*blk_size and the sector value is not block size
-     * divided by 512 - instead it is the amount of blk_size blocks
-     * per track (cylinder).
-     */
-    if (bdrv_getlength(s->bs) /  s->conf->heads / s->conf->secs % blk_size) {
-        blkcfg.sectors = s->conf->secs & ~s->sector_mask;
-    } else {
-        blkcfg.sectors = s->conf->secs;
-    }
-    blkcfg.size_max = 0;
-    blkcfg.physical_block_exp = get_physical_block_exp(s->conf);
-    blkcfg.alignment_offset = 0;
-    blkcfg.wce = bdrv_enable_write_cache(s->bs);
-    memcpy(config, &blkcfg, sizeof(struct virtio_blk_config));
-}
-
-static void virtio_blk_set_config(VirtIODevice *vdev, const uint8_t *config)
-{
-    VirtIOBlock *s = VIRTIO_BLK(vdev);
-    struct virtio_blk_config blkcfg;
-
-    memcpy(&blkcfg, config, sizeof(blkcfg));
-    bdrv_set_enable_write_cache(s->bs, blkcfg.wce != 0);
-}
-
-static uint32_t virtio_blk_get_features(VirtIODevice *vdev, uint32_t features)
-{
-    VirtIOBlock *s = VIRTIO_BLK(vdev);
-
-    features |= (1 << VIRTIO_BLK_F_SEG_MAX);
-    features |= (1 << VIRTIO_BLK_F_GEOMETRY);
-    features |= (1 << VIRTIO_BLK_F_TOPOLOGY);
-    features |= (1 << VIRTIO_BLK_F_BLK_SIZE);
-    features |= (1 << VIRTIO_BLK_F_SCSI);
-
-    if (s->blk.config_wce) {
-        features |= (1 << VIRTIO_BLK_F_CONFIG_WCE);
-    }
-    if (bdrv_enable_write_cache(s->bs))
-        features |= (1 << VIRTIO_BLK_F_WCE);
-
-    if (bdrv_is_read_only(s->bs))
-        features |= 1 << VIRTIO_BLK_F_RO;
-
-    return features;
-}
-
-static void virtio_blk_set_status(VirtIODevice *vdev, uint8_t status)
-{
-    VirtIOBlock *s = VIRTIO_BLK(vdev);
-    uint32_t features;
-
-#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE
-    if (s->dataplane && !(status & (VIRTIO_CONFIG_S_DRIVER |
-                                    VIRTIO_CONFIG_S_DRIVER_OK))) {
-        virtio_blk_data_plane_stop(s->dataplane);
-    }
-#endif
-
-    if (!(status & VIRTIO_CONFIG_S_DRIVER_OK)) {
-        return;
-    }
-
-    features = vdev->guest_features;
-    bdrv_set_enable_write_cache(s->bs, !!(features & (1 << VIRTIO_BLK_F_WCE)));
-}
-
-static void virtio_blk_save(QEMUFile *f, void *opaque)
-{
-    VirtIOBlock *s = opaque;
-    VirtIODevice *vdev = VIRTIO_DEVICE(s);
-    VirtIOBlockReq *req = s->rq;
-
-    virtio_save(vdev, f);
-    
-    while (req) {
-        qemu_put_sbyte(f, 1);
-        qemu_put_buffer(f, (unsigned char*)&req->elem, sizeof(req->elem));
-        req = req->next;
-    }
-    qemu_put_sbyte(f, 0);
-}
-
-static int virtio_blk_load(QEMUFile *f, void *opaque, int version_id)
-{
-    VirtIOBlock *s = opaque;
-    VirtIODevice *vdev = VIRTIO_DEVICE(s);
-    int ret;
-
-    if (version_id != 2)
-        return -EINVAL;
-
-    ret = virtio_load(vdev, f);
-    if (ret) {
-        return ret;
-    }
-
-    while (qemu_get_sbyte(f)) {
-        VirtIOBlockReq *req = virtio_blk_alloc_request(s);
-        qemu_get_buffer(f, (unsigned char*)&req->elem, sizeof(req->elem));
-        req->next = s->rq;
-        s->rq = req;
-
-        virtqueue_map_sg(req->elem.in_sg, req->elem.in_addr,
-            req->elem.in_num, 1);
-        virtqueue_map_sg(req->elem.out_sg, req->elem.out_addr,
-            req->elem.out_num, 0);
-    }
-
-    return 0;
-}
-
-static void virtio_blk_resize(void *opaque)
-{
-    VirtIODevice *vdev = VIRTIO_DEVICE(opaque);
-
-    virtio_notify_config(vdev);
-}
-
-static const BlockDevOps virtio_block_ops = {
-    .resize_cb = virtio_blk_resize,
-};
-
-void virtio_blk_set_conf(DeviceState *dev, VirtIOBlkConf *blk)
-{
-    VirtIOBlock *s = VIRTIO_BLK(dev);
-    memcpy(&(s->blk), blk, sizeof(struct VirtIOBlkConf));
-}
-
-static int virtio_blk_device_init(VirtIODevice *vdev)
-{
-    DeviceState *qdev = DEVICE(vdev);
-    VirtIOBlock *s = VIRTIO_BLK(vdev);
-    VirtIOBlkConf *blk = &(s->blk);
-    static int virtio_blk_id;
-
-    if (!blk->conf.bs) {
-        error_report("drive property not set");
-        return -1;
-    }
-    if (!bdrv_is_inserted(blk->conf.bs)) {
-        error_report("Device needs media, but drive is empty");
-        return -1;
-    }
-
-    blkconf_serial(&blk->conf, &blk->serial);
-    if (blkconf_geometry(&blk->conf, NULL, 65535, 255, 255) < 0) {
-        return -1;
-    }
-
-    virtio_init(vdev, "virtio-blk", VIRTIO_ID_BLOCK,
-                sizeof(struct virtio_blk_config));
-
-    vdev->get_config = virtio_blk_update_config;
-    vdev->set_config = virtio_blk_set_config;
-    vdev->get_features = virtio_blk_get_features;
-    vdev->set_status = virtio_blk_set_status;
-    vdev->reset = virtio_blk_reset;
-    s->bs = blk->conf.bs;
-    s->conf = &blk->conf;
-    memcpy(&(s->blk), blk, sizeof(struct VirtIOBlkConf));
-    s->rq = NULL;
-    s->sector_mask = (s->conf->logical_block_size / BDRV_SECTOR_SIZE) - 1;
-
-    s->vq = virtio_add_queue(vdev, 128, virtio_blk_handle_output);
-#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE
-    if (!virtio_blk_data_plane_create(vdev, blk, &s->dataplane)) {
-        virtio_common_cleanup(vdev);
-        return -1;
-    }
-#endif
-
-    s->change = qemu_add_vm_change_state_handler(virtio_blk_dma_restart_cb, s);
-    register_savevm(qdev, "virtio-blk", virtio_blk_id++, 2,
-                    virtio_blk_save, virtio_blk_load, s);
-    bdrv_set_dev_ops(s->bs, &virtio_block_ops, s);
-    bdrv_set_buffer_alignment(s->bs, s->conf->logical_block_size);
-
-    bdrv_iostatus_enable(s->bs);
-
-    add_boot_device_path(s->conf->bootindex, qdev, "/disk@0,0");
-    return 0;
-}
-
-static int virtio_blk_device_exit(DeviceState *dev)
-{
-    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
-    VirtIOBlock *s = VIRTIO_BLK(dev);
-#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE
-    virtio_blk_data_plane_destroy(s->dataplane);
-    s->dataplane = NULL;
-#endif
-    qemu_del_vm_change_state_handler(s->change);
-    unregister_savevm(dev, "virtio-blk", s);
-    blockdev_mark_auto_del(s->bs);
-    virtio_common_cleanup(vdev);
-    return 0;
-}
-
-static Property virtio_blk_properties[] = {
-    DEFINE_VIRTIO_BLK_PROPERTIES(VirtIOBlock, blk),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void virtio_blk_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
-    dc->exit = virtio_blk_device_exit;
-    dc->props = virtio_blk_properties;
-    vdc->init = virtio_blk_device_init;
-    vdc->get_config = virtio_blk_update_config;
-    vdc->set_config = virtio_blk_set_config;
-    vdc->get_features = virtio_blk_get_features;
-    vdc->set_status = virtio_blk_set_status;
-    vdc->reset = virtio_blk_reset;
-}
-
-static const TypeInfo virtio_device_info = {
-    .name = TYPE_VIRTIO_BLK,
-    .parent = TYPE_VIRTIO_DEVICE,
-    .instance_size = sizeof(VirtIOBlock),
-    .class_init = virtio_blk_class_init,
-};
-
-static void virtio_register_types(void)
-{
-    type_register_static(&virtio_device_info);
-}
-
-type_init(virtio_register_types)
diff --git a/hw/virtio-blk.h b/hw/virtio-blk.h
deleted file mode 100644 (file)
index 8c6c78b..0000000
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Virtio Block Device
- *
- * Copyright IBM, Corp. 2007
- *
- * Authors:
- *  Anthony Liguori   <aliguori@us.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2.  See
- * the COPYING file in the top-level directory.
- *
- */
-
-#ifndef _QEMU_VIRTIO_BLK_H
-#define _QEMU_VIRTIO_BLK_H
-
-#include "hw/virtio.h"
-#include "hw/block-common.h"
-#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE
-#include "dataplane/virtio-blk.h"
-#endif
-
-#define TYPE_VIRTIO_BLK "virtio-blk"
-#define VIRTIO_BLK(obj) \
-        OBJECT_CHECK(VirtIOBlock, (obj), TYPE_VIRTIO_BLK)
-
-/* from Linux's linux/virtio_blk.h */
-
-/* The ID for virtio_block */
-#define VIRTIO_ID_BLOCK 2
-
-/* Feature bits */
-#define VIRTIO_BLK_F_BARRIER    0       /* Does host support barriers? */
-#define VIRTIO_BLK_F_SIZE_MAX   1       /* Indicates maximum segment size */
-#define VIRTIO_BLK_F_SEG_MAX    2       /* Indicates maximum # of segments */
-#define VIRTIO_BLK_F_GEOMETRY   4       /* Indicates support of legacy geometry */
-#define VIRTIO_BLK_F_RO         5       /* Disk is read-only */
-#define VIRTIO_BLK_F_BLK_SIZE   6       /* Block size of disk is available*/
-#define VIRTIO_BLK_F_SCSI       7       /* Supports scsi command passthru */
-/* #define VIRTIO_BLK_F_IDENTIFY   8       ATA IDENTIFY supported, DEPRECATED */
-#define VIRTIO_BLK_F_WCE        9       /* write cache enabled */
-#define VIRTIO_BLK_F_TOPOLOGY   10      /* Topology information is available */
-#define VIRTIO_BLK_F_CONFIG_WCE 11      /* write cache configurable */
-
-#define VIRTIO_BLK_ID_BYTES     20      /* ID string length */
-
-struct virtio_blk_config
-{
-    uint64_t capacity;
-    uint32_t size_max;
-    uint32_t seg_max;
-    uint16_t cylinders;
-    uint8_t heads;
-    uint8_t sectors;
-    uint32_t blk_size;
-    uint8_t physical_block_exp;
-    uint8_t alignment_offset;
-    uint16_t min_io_size;
-    uint32_t opt_io_size;
-    uint8_t wce;
-} QEMU_PACKED;
-
-/* These two define direction. */
-#define VIRTIO_BLK_T_IN         0
-#define VIRTIO_BLK_T_OUT        1
-
-/* This bit says it's a scsi command, not an actual read or write. */
-#define VIRTIO_BLK_T_SCSI_CMD   2
-
-/* Flush the volatile write cache */
-#define VIRTIO_BLK_T_FLUSH      4
-
-/* return the device ID string */
-#define VIRTIO_BLK_T_GET_ID     8
-
-/* Barrier before this op. */
-#define VIRTIO_BLK_T_BARRIER    0x80000000
-
-/* This is the first element of the read scatter-gather list. */
-struct virtio_blk_outhdr
-{
-    /* VIRTIO_BLK_T* */
-    uint32_t type;
-    /* io priority. */
-    uint32_t ioprio;
-    /* Sector (ie. 512 byte offset) */
-    uint64_t sector;
-};
-
-#define VIRTIO_BLK_S_OK         0
-#define VIRTIO_BLK_S_IOERR      1
-#define VIRTIO_BLK_S_UNSUPP     2
-
-/* This is the last element of the write scatter-gather list */
-struct virtio_blk_inhdr
-{
-    unsigned char status;
-};
-
-/* SCSI pass-through header */
-struct virtio_scsi_inhdr
-{
-    uint32_t errors;
-    uint32_t data_len;
-    uint32_t sense_len;
-    uint32_t residual;
-};
-
-struct VirtIOBlkConf
-{
-    BlockConf conf;
-    char *serial;
-    uint32_t scsi;
-    uint32_t config_wce;
-    uint32_t data_plane;
-};
-
-typedef struct VirtIOBlock {
-    VirtIODevice parent_obj;
-    BlockDriverState *bs;
-    VirtQueue *vq;
-    void *rq;
-    QEMUBH *bh;
-    BlockConf *conf;
-    VirtIOBlkConf blk;
-    unsigned short sector_mask;
-    VMChangeStateEntry *change;
-#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE
-    VirtIOBlockDataPlane *dataplane;
-#endif
-} VirtIOBlock;
-
-#define DEFINE_VIRTIO_BLK_FEATURES(_state, _field) \
-        DEFINE_VIRTIO_COMMON_FEATURES(_state, _field)
-
-#ifdef __linux__
-#define DEFINE_VIRTIO_BLK_PROPERTIES(_state, _field)                          \
-        DEFINE_BLOCK_PROPERTIES(_state, _field.conf),                         \
-        DEFINE_BLOCK_CHS_PROPERTIES(_state, _field.conf),                     \
-        DEFINE_PROP_STRING("serial", _state, _field.serial),                  \
-        DEFINE_PROP_BIT("config-wce", _state, _field.config_wce, 0, true),    \
-        DEFINE_PROP_BIT("scsi", _state, _field.scsi, 0, true)
-#else
-#define DEFINE_VIRTIO_BLK_PROPERTIES(_state, _field)                          \
-        DEFINE_BLOCK_PROPERTIES(_state, _field.conf),                         \
-        DEFINE_BLOCK_CHS_PROPERTIES(_state, _field.conf),                     \
-        DEFINE_PROP_STRING("serial", _state, _field.serial),                  \
-        DEFINE_PROP_BIT("config-wce", _state, _field.config_wce, 0, true)
-#endif /* __linux__ */
-
-void virtio_blk_set_conf(DeviceState *dev, VirtIOBlkConf *blk);
-
-#endif
diff --git a/hw/virtio-bus.c b/hw/virtio-bus.c
deleted file mode 100644 (file)
index 6c2aab0..0000000
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * VirtioBus
- *
- *  Copyright (C) 2012 : GreenSocs Ltd
- *      http://www.greensocs.com/ , email: info@greensocs.com
- *
- *  Developed by :
- *  Frederic Konrad   <fred.konrad@greensocs.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 "hw/hw.h"
-#include "qemu/error-report.h"
-#include "hw/qdev.h"
-#include "hw/virtio-bus.h"
-#include "hw/virtio.h"
-
-/* #define DEBUG_VIRTIO_BUS */
-
-#ifdef DEBUG_VIRTIO_BUS
-#define DPRINTF(fmt, ...) \
-do { printf("virtio_bus: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...) do { } while (0)
-#endif
-
-/* Plug the VirtIODevice */
-int virtio_bus_plug_device(VirtIODevice *vdev)
-{
-    DeviceState *qdev = DEVICE(vdev);
-    BusState *qbus = BUS(qdev_get_parent_bus(qdev));
-    VirtioBusState *bus = VIRTIO_BUS(qbus);
-    VirtioBusClass *klass = VIRTIO_BUS_GET_CLASS(bus);
-    DPRINTF("%s: plug device.\n", qbus->name);
-
-    bus->vdev = vdev;
-
-    /*
-     * The lines below will disappear when we drop VirtIOBindings, at the end
-     * of the series.
-     */
-    bus->bindings.notify = klass->notify;
-    bus->bindings.save_config = klass->save_config;
-    bus->bindings.save_queue = klass->save_queue;
-    bus->bindings.load_config = klass->load_config;
-    bus->bindings.load_queue = klass->load_queue;
-    bus->bindings.load_done = klass->load_done;
-    bus->bindings.get_features = klass->get_features;
-    bus->bindings.query_guest_notifiers = klass->query_guest_notifiers;
-    bus->bindings.set_guest_notifiers = klass->set_guest_notifiers;
-    bus->bindings.set_host_notifier = klass->set_host_notifier;
-    bus->bindings.vmstate_change = klass->vmstate_change;
-    virtio_bind_device(bus->vdev, &bus->bindings, qbus->parent);
-
-    if (klass->device_plugged != NULL) {
-        klass->device_plugged(qbus->parent);
-    }
-
-    return 0;
-}
-
-/* Reset the virtio_bus */
-void virtio_bus_reset(VirtioBusState *bus)
-{
-    DPRINTF("%s: reset device.\n", qbus->name);
-    if (bus->vdev != NULL) {
-        virtio_reset(bus->vdev);
-    }
-}
-
-/* Destroy the VirtIODevice */
-void virtio_bus_destroy_device(VirtioBusState *bus)
-{
-    DeviceState *qdev;
-    BusState *qbus = BUS(bus);
-    VirtioBusClass *klass = VIRTIO_BUS_GET_CLASS(bus);
-    DPRINTF("%s: remove device.\n", qbus->name);
-
-    if (bus->vdev != NULL) {
-        if (klass->device_unplug != NULL) {
-            klass->device_unplug(qbus->parent);
-        }
-        qdev = DEVICE(bus->vdev);
-        qdev_free(qdev);
-        bus->vdev = NULL;
-    }
-}
-
-/* Get the device id of the plugged device. */
-uint16_t virtio_bus_get_vdev_id(VirtioBusState *bus)
-{
-    assert(bus->vdev != NULL);
-    return bus->vdev->device_id;
-}
-
-/* Get the config_len field of the plugged device. */
-size_t virtio_bus_get_vdev_config_len(VirtioBusState *bus)
-{
-    assert(bus->vdev != NULL);
-    return bus->vdev->config_len;
-}
-
-/* Get the features of the plugged device. */
-uint32_t virtio_bus_get_vdev_features(VirtioBusState *bus,
-                                    uint32_t requested_features)
-{
-    VirtioDeviceClass *k;
-    assert(bus->vdev != NULL);
-    k = VIRTIO_DEVICE_GET_CLASS(bus->vdev);
-    assert(k->get_features != NULL);
-    return k->get_features(bus->vdev, requested_features);
-}
-
-/* Get bad features of the plugged device. */
-uint32_t virtio_bus_get_vdev_bad_features(VirtioBusState *bus)
-{
-    VirtioDeviceClass *k;
-    assert(bus->vdev != NULL);
-    k = VIRTIO_DEVICE_GET_CLASS(bus->vdev);
-    if (k->bad_features != NULL) {
-        return k->bad_features(bus->vdev);
-    } else {
-        return 0;
-    }
-}
-
-/* Get config of the plugged device. */
-void virtio_bus_get_vdev_config(VirtioBusState *bus, uint8_t *config)
-{
-    VirtioDeviceClass *k;
-    assert(bus->vdev != NULL);
-    k = VIRTIO_DEVICE_GET_CLASS(bus->vdev);
-    if (k->get_config != NULL) {
-        k->get_config(bus->vdev, config);
-    }
-}
-
-static const TypeInfo virtio_bus_info = {
-    .name = TYPE_VIRTIO_BUS,
-    .parent = TYPE_BUS,
-    .instance_size = sizeof(VirtioBusState),
-    .abstract = true,
-    .class_size = sizeof(VirtioBusClass),
-};
-
-static void virtio_register_types(void)
-{
-    type_register_static(&virtio_bus_info);
-}
-
-type_init(virtio_register_types)
diff --git a/hw/virtio-bus.h b/hw/virtio-bus.h
deleted file mode 100644 (file)
index ae0f707..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * VirtioBus
- *
- *  Copyright (C) 2012 : GreenSocs Ltd
- *      http://www.greensocs.com/ , email: info@greensocs.com
- *
- *  Developed by :
- *  Frederic Konrad   <fred.konrad@greensocs.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 VIRTIO_BUS_H
-#define VIRTIO_BUS_H
-
-#include "hw/qdev.h"
-#include "sysemu/sysemu.h"
-#include "hw/virtio.h"
-
-#define TYPE_VIRTIO_BUS "virtio-bus"
-#define VIRTIO_BUS_GET_CLASS(obj) \
-        OBJECT_GET_CLASS(VirtioBusClass, obj, TYPE_VIRTIO_BUS)
-#define VIRTIO_BUS_CLASS(klass) \
-        OBJECT_CLASS_CHECK(VirtioBusClass, klass, TYPE_VIRTIO_BUS)
-#define VIRTIO_BUS(obj) OBJECT_CHECK(VirtioBusState, (obj), TYPE_VIRTIO_BUS)
-
-typedef struct VirtioBusState VirtioBusState;
-
-typedef struct VirtioBusClass {
-    /* This is what a VirtioBus must implement */
-    BusClass parent;
-    void (*notify)(DeviceState *d, uint16_t vector);
-    void (*save_config)(DeviceState *d, QEMUFile *f);
-    void (*save_queue)(DeviceState *d, int n, QEMUFile *f);
-    int (*load_config)(DeviceState *d, QEMUFile *f);
-    int (*load_queue)(DeviceState *d, int n, QEMUFile *f);
-    int (*load_done)(DeviceState *d, QEMUFile *f);
-    unsigned (*get_features)(DeviceState *d);
-    bool (*query_guest_notifiers)(DeviceState *d);
-    int (*set_guest_notifiers)(DeviceState *d, int nvqs, bool assign);
-    int (*set_host_notifier)(DeviceState *d, int n, bool assigned);
-    void (*vmstate_change)(DeviceState *d, bool running);
-    /*
-     * transport independent init function.
-     * This is called by virtio-bus just after the device is plugged.
-     */
-    void (*device_plugged)(DeviceState *d);
-    /*
-     * transport independent exit function.
-     * This is called by virtio-bus just before the device is unplugged.
-     */
-    void (*device_unplug)(DeviceState *d);
-} VirtioBusClass;
-
-struct VirtioBusState {
-    BusState parent_obj;
-    /*
-     * Only one VirtIODevice can be plugged on the bus.
-     */
-    VirtIODevice *vdev;
-    /*
-     * This will be removed at the end of the series.
-     */
-    VirtIOBindings bindings;
-};
-
-int virtio_bus_plug_device(VirtIODevice *vdev);
-void virtio_bus_reset(VirtioBusState *bus);
-void virtio_bus_destroy_device(VirtioBusState *bus);
-/* Get the device id of the plugged device. */
-uint16_t virtio_bus_get_vdev_id(VirtioBusState *bus);
-/* Get the config_len field of the plugged device. */
-size_t virtio_bus_get_vdev_config_len(VirtioBusState *bus);
-/* Get the features of the plugged device. */
-uint32_t virtio_bus_get_vdev_features(VirtioBusState *bus,
-                                    uint32_t requested_features);
-/* Get bad features of the plugged device. */
-uint32_t virtio_bus_get_vdev_bad_features(VirtioBusState *bus);
-/* Get config of the plugged device. */
-void virtio_bus_get_vdev_config(VirtioBusState *bus, uint8_t *config);
-
-#endif /* VIRTIO_BUS_H */
diff --git a/hw/virtio-console.c b/hw/virtio-console.c
deleted file mode 100644 (file)
index 284180f..0000000
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * Virtio Console and Generic Serial Port Devices
- *
- * Copyright Red Hat, Inc. 2009, 2010
- *
- * Authors:
- *  Amit Shah <amit.shah@redhat.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2.  See
- * the COPYING file in the top-level directory.
- */
-
-#include "char/char.h"
-#include "qemu/error-report.h"
-#include "trace.h"
-#include "hw/virtio-serial.h"
-
-typedef struct VirtConsole {
-    VirtIOSerialPort port;
-    CharDriverState *chr;
-} VirtConsole;
-
-/*
- * Callback function that's called from chardevs when backend becomes
- * writable.
- */
-static gboolean chr_write_unblocked(GIOChannel *chan, GIOCondition cond,
-                                    void *opaque)
-{
-    VirtConsole *vcon = opaque;
-
-    virtio_serial_throttle_port(&vcon->port, false);
-    return FALSE;
-}
-
-/* Callback function that's called when the guest sends us data */
-static ssize_t flush_buf(VirtIOSerialPort *port, const uint8_t *buf, size_t len)
-{
-    VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
-    ssize_t ret;
-
-    if (!vcon->chr) {
-        /* If there's no backend, we can just say we consumed all data. */
-        return len;
-    }
-
-    ret = qemu_chr_fe_write(vcon->chr, buf, len);
-    trace_virtio_console_flush_buf(port->id, len, ret);
-
-    if (ret <= 0) {
-        VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_GET_CLASS(port);
-
-        /*
-         * Ideally we'd get a better error code than just -1, but
-         * that's what the chardev interface gives us right now.  If
-         * we had a finer-grained message, like -EPIPE, we could close
-         * this connection.
-         */
-        ret = 0;
-        if (!k->is_console) {
-            virtio_serial_throttle_port(port, true);
-            qemu_chr_fe_add_watch(vcon->chr, G_IO_OUT, chr_write_unblocked,
-                                  vcon);
-        }
-    }
-    return ret;
-}
-
-/* Callback function that's called when the guest opens/closes the port */
-static void set_guest_connected(VirtIOSerialPort *port, int guest_connected)
-{
-    VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
-
-    if (!vcon->chr) {
-        return;
-    }
-    qemu_chr_fe_set_open(vcon->chr, guest_connected);
-}
-
-/* Readiness of the guest to accept data on a port */
-static int chr_can_read(void *opaque)
-{
-    VirtConsole *vcon = opaque;
-
-    return virtio_serial_guest_ready(&vcon->port);
-}
-
-/* Send data from a char device over to the guest */
-static void chr_read(void *opaque, const uint8_t *buf, int size)
-{
-    VirtConsole *vcon = opaque;
-
-    trace_virtio_console_chr_read(vcon->port.id, size);
-    virtio_serial_write(&vcon->port, buf, size);
-}
-
-static void chr_event(void *opaque, int event)
-{
-    VirtConsole *vcon = opaque;
-
-    trace_virtio_console_chr_event(vcon->port.id, event);
-    switch (event) {
-    case CHR_EVENT_OPENED:
-        virtio_serial_open(&vcon->port);
-        break;
-    case CHR_EVENT_CLOSED:
-        virtio_serial_close(&vcon->port);
-        break;
-    }
-}
-
-static int virtconsole_initfn(VirtIOSerialPort *port)
-{
-    VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
-    VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_GET_CLASS(port);
-
-    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;
-    }
-
-    if (vcon->chr) {
-        vcon->chr->explicit_fe_open = 1;
-        qemu_chr_add_handlers(vcon->chr, chr_can_read, chr_read, chr_event,
-                              vcon);
-    }
-
-    return 0;
-}
-
-static Property virtconsole_properties[] = {
-    DEFINE_PROP_CHR("chardev", VirtConsole, chr),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void virtconsole_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_CLASS(klass);
-
-    k->is_console = true;
-    k->init = virtconsole_initfn;
-    k->have_data = flush_buf;
-    k->set_guest_connected = set_guest_connected;
-    dc->props = virtconsole_properties;
-}
-
-static const TypeInfo virtconsole_info = {
-    .name          = "virtconsole",
-    .parent        = TYPE_VIRTIO_SERIAL_PORT,
-    .instance_size = sizeof(VirtConsole),
-    .class_init    = virtconsole_class_init,
-};
-
-static Property virtserialport_properties[] = {
-    DEFINE_PROP_CHR("chardev", VirtConsole, chr),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void virtserialport_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_CLASS(klass);
-
-    k->init = virtconsole_initfn;
-    k->have_data = flush_buf;
-    k->set_guest_connected = set_guest_connected;
-    dc->props = virtserialport_properties;
-}
-
-static const TypeInfo virtserialport_info = {
-    .name          = "virtserialport",
-    .parent        = TYPE_VIRTIO_SERIAL_PORT,
-    .instance_size = sizeof(VirtConsole),
-    .class_init    = virtserialport_class_init,
-};
-
-static void virtconsole_register_types(void)
-{
-    type_register_static(&virtconsole_info);
-    type_register_static(&virtserialport_info);
-}
-
-type_init(virtconsole_register_types)
diff --git a/hw/virtio-net.c b/hw/virtio-net.c
deleted file mode 100644 (file)
index 5917740..0000000
+++ /dev/null
@@ -1,1370 +0,0 @@
-/*
- * Virtio Network Device
- *
- * Copyright IBM, Corp. 2007
- *
- * Authors:
- *  Anthony Liguori   <aliguori@us.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 "qemu/iov.h"
-#include "hw/virtio.h"
-#include "net/net.h"
-#include "net/checksum.h"
-#include "net/tap.h"
-#include "qemu/error-report.h"
-#include "qemu/timer.h"
-#include "hw/virtio-net.h"
-#include "hw/vhost_net.h"
-
-#define VIRTIO_NET_VM_VERSION    11
-
-#define MAC_TABLE_ENTRIES    64
-#define MAX_VLAN    (1 << 12)   /* Per 802.1Q definition */
-
-/*
- * Calculate the number of bytes up to and including the given 'field' of
- * 'container'.
- */
-#define endof(container, field) \
-    (offsetof(container, field) + sizeof(((container *)0)->field))
-
-typedef struct VirtIOFeature {
-    uint32_t flags;
-    size_t end;
-} VirtIOFeature;
-
-static VirtIOFeature feature_sizes[] = {
-    {.flags = 1 << VIRTIO_NET_F_MAC,
-     .end = endof(struct virtio_net_config, mac)},
-    {.flags = 1 << VIRTIO_NET_F_STATUS,
-     .end = endof(struct virtio_net_config, status)},
-    {.flags = 1 << VIRTIO_NET_F_MQ,
-     .end = endof(struct virtio_net_config, max_virtqueue_pairs)},
-    {}
-};
-
-static VirtIONetQueue *virtio_net_get_subqueue(NetClientState *nc)
-{
-    VirtIONet *n = qemu_get_nic_opaque(nc);
-
-    return &n->vqs[nc->queue_index];
-}
-
-static int vq2q(int queue_index)
-{
-    return queue_index / 2;
-}
-
-/* TODO
- * - we could suppress RX interrupt if we were so inclined.
- */
-
-static VirtIONet *to_virtio_net(VirtIODevice *vdev)
-{
-    return (VirtIONet *)vdev;
-}
-
-static void virtio_net_get_config(VirtIODevice *vdev, uint8_t *config)
-{
-    VirtIONet *n = to_virtio_net(vdev);
-    struct virtio_net_config netcfg;
-
-    stw_p(&netcfg.status, n->status);
-    stw_p(&netcfg.max_virtqueue_pairs, n->max_queues);
-    memcpy(netcfg.mac, n->mac, ETH_ALEN);
-    memcpy(config, &netcfg, n->config_size);
-}
-
-static void virtio_net_set_config(VirtIODevice *vdev, const uint8_t *config)
-{
-    VirtIONet *n = to_virtio_net(vdev);
-    struct virtio_net_config netcfg = {};
-
-    memcpy(&netcfg, config, n->config_size);
-
-    if (!(n->vdev.guest_features >> VIRTIO_NET_F_CTRL_MAC_ADDR & 1) &&
-        memcmp(netcfg.mac, n->mac, ETH_ALEN)) {
-        memcpy(n->mac, netcfg.mac, ETH_ALEN);
-        qemu_format_nic_info_str(qemu_get_queue(n->nic), n->mac);
-    }
-}
-
-static bool virtio_net_started(VirtIONet *n, uint8_t status)
-{
-    return (status & VIRTIO_CONFIG_S_DRIVER_OK) &&
-        (n->status & VIRTIO_NET_S_LINK_UP) && n->vdev.vm_running;
-}
-
-static void virtio_net_vhost_status(VirtIONet *n, uint8_t status)
-{
-    NetClientState *nc = qemu_get_queue(n->nic);
-    int queues = n->multiqueue ? n->max_queues : 1;
-
-    if (!nc->peer) {
-        return;
-    }
-    if (nc->peer->info->type != NET_CLIENT_OPTIONS_KIND_TAP) {
-        return;
-    }
-
-    if (!tap_get_vhost_net(nc->peer)) {
-        return;
-    }
-
-    if (!!n->vhost_started == virtio_net_started(n, status) &&
-                              !nc->peer->link_down) {
-        return;
-    }
-    if (!n->vhost_started) {
-        int r;
-        if (!vhost_net_query(tap_get_vhost_net(nc->peer), &n->vdev)) {
-            return;
-        }
-        n->vhost_started = 1;
-        r = vhost_net_start(&n->vdev, n->nic->ncs, queues);
-        if (r < 0) {
-            error_report("unable to start vhost net: %d: "
-                         "falling back on userspace virtio", -r);
-            n->vhost_started = 0;
-        }
-    } else {
-        vhost_net_stop(&n->vdev, n->nic->ncs, queues);
-        n->vhost_started = 0;
-    }
-}
-
-static void virtio_net_set_status(struct VirtIODevice *vdev, uint8_t status)
-{
-    VirtIONet *n = to_virtio_net(vdev);
-    VirtIONetQueue *q;
-    int i;
-    uint8_t queue_status;
-
-    virtio_net_vhost_status(n, status);
-
-    for (i = 0; i < n->max_queues; i++) {
-        q = &n->vqs[i];
-
-        if ((!n->multiqueue && i != 0) || i >= n->curr_queues) {
-            queue_status = 0;
-        } else {
-            queue_status = status;
-        }
-
-        if (!q->tx_waiting) {
-            continue;
-        }
-
-        if (virtio_net_started(n, queue_status) && !n->vhost_started) {
-            if (q->tx_timer) {
-                qemu_mod_timer(q->tx_timer,
-                               qemu_get_clock_ns(vm_clock) + n->tx_timeout);
-            } else {
-                qemu_bh_schedule(q->tx_bh);
-            }
-        } else {
-            if (q->tx_timer) {
-                qemu_del_timer(q->tx_timer);
-            } else {
-                qemu_bh_cancel(q->tx_bh);
-            }
-        }
-    }
-}
-
-static void virtio_net_set_link_status(NetClientState *nc)
-{
-    VirtIONet *n = qemu_get_nic_opaque(nc);
-    uint16_t old_status = n->status;
-
-    if (nc->link_down)
-        n->status &= ~VIRTIO_NET_S_LINK_UP;
-    else
-        n->status |= VIRTIO_NET_S_LINK_UP;
-
-    if (n->status != old_status)
-        virtio_notify_config(&n->vdev);
-
-    virtio_net_set_status(&n->vdev, n->vdev.status);
-}
-
-static void virtio_net_reset(VirtIODevice *vdev)
-{
-    VirtIONet *n = to_virtio_net(vdev);
-
-    /* Reset back to compatibility mode */
-    n->promisc = 1;
-    n->allmulti = 0;
-    n->alluni = 0;
-    n->nomulti = 0;
-    n->nouni = 0;
-    n->nobcast = 0;
-    /* multiqueue is disabled by default */
-    n->curr_queues = 1;
-
-    /* Flush any MAC and VLAN filter table state */
-    n->mac_table.in_use = 0;
-    n->mac_table.first_multi = 0;
-    n->mac_table.multi_overflow = 0;
-    n->mac_table.uni_overflow = 0;
-    memset(n->mac_table.macs, 0, MAC_TABLE_ENTRIES * ETH_ALEN);
-    memcpy(&n->mac[0], &n->nic->conf->macaddr, sizeof(n->mac));
-    memset(n->vlans, 0, MAX_VLAN >> 3);
-}
-
-static void peer_test_vnet_hdr(VirtIONet *n)
-{
-    NetClientState *nc = qemu_get_queue(n->nic);
-    if (!nc->peer) {
-        return;
-    }
-
-    if (nc->peer->info->type != NET_CLIENT_OPTIONS_KIND_TAP) {
-        return;
-    }
-
-    n->has_vnet_hdr = tap_has_vnet_hdr(nc->peer);
-}
-
-static int peer_has_vnet_hdr(VirtIONet *n)
-{
-    return n->has_vnet_hdr;
-}
-
-static int peer_has_ufo(VirtIONet *n)
-{
-    if (!peer_has_vnet_hdr(n))
-        return 0;
-
-    n->has_ufo = tap_has_ufo(qemu_get_queue(n->nic)->peer);
-
-    return n->has_ufo;
-}
-
-static void virtio_net_set_mrg_rx_bufs(VirtIONet *n, int mergeable_rx_bufs)
-{
-    int i;
-    NetClientState *nc;
-
-    n->mergeable_rx_bufs = mergeable_rx_bufs;
-
-    n->guest_hdr_len = n->mergeable_rx_bufs ?
-        sizeof(struct virtio_net_hdr_mrg_rxbuf) : sizeof(struct virtio_net_hdr);
-
-    for (i = 0; i < n->max_queues; i++) {
-        nc = qemu_get_subqueue(n->nic, i);
-
-        if (peer_has_vnet_hdr(n) &&
-            tap_has_vnet_hdr_len(nc->peer, n->guest_hdr_len)) {
-            tap_set_vnet_hdr_len(nc->peer, n->guest_hdr_len);
-            n->host_hdr_len = n->guest_hdr_len;
-        }
-    }
-}
-
-static int peer_attach(VirtIONet *n, int index)
-{
-    NetClientState *nc = qemu_get_subqueue(n->nic, index);
-
-    if (!nc->peer) {
-        return 0;
-    }
-
-    if (nc->peer->info->type != NET_CLIENT_OPTIONS_KIND_TAP) {
-        return 0;
-    }
-
-    return tap_enable(nc->peer);
-}
-
-static int peer_detach(VirtIONet *n, int index)
-{
-    NetClientState *nc = qemu_get_subqueue(n->nic, index);
-
-    if (!nc->peer) {
-        return 0;
-    }
-
-    if (nc->peer->info->type !=  NET_CLIENT_OPTIONS_KIND_TAP) {
-        return 0;
-    }
-
-    return tap_disable(nc->peer);
-}
-
-static void virtio_net_set_queues(VirtIONet *n)
-{
-    int i;
-
-    for (i = 0; i < n->max_queues; i++) {
-        if (i < n->curr_queues) {
-            assert(!peer_attach(n, i));
-        } else {
-            assert(!peer_detach(n, i));
-        }
-    }
-}
-
-static void virtio_net_set_multiqueue(VirtIONet *n, int multiqueue, int ctrl);
-
-static uint32_t virtio_net_get_features(VirtIODevice *vdev, uint32_t features)
-{
-    VirtIONet *n = to_virtio_net(vdev);
-    NetClientState *nc = qemu_get_queue(n->nic);
-
-    features |= (1 << VIRTIO_NET_F_MAC);
-
-    if (!peer_has_vnet_hdr(n)) {
-        features &= ~(0x1 << VIRTIO_NET_F_CSUM);
-        features &= ~(0x1 << VIRTIO_NET_F_HOST_TSO4);
-        features &= ~(0x1 << VIRTIO_NET_F_HOST_TSO6);
-        features &= ~(0x1 << VIRTIO_NET_F_HOST_ECN);
-
-        features &= ~(0x1 << VIRTIO_NET_F_GUEST_CSUM);
-        features &= ~(0x1 << VIRTIO_NET_F_GUEST_TSO4);
-        features &= ~(0x1 << VIRTIO_NET_F_GUEST_TSO6);
-        features &= ~(0x1 << VIRTIO_NET_F_GUEST_ECN);
-    }
-
-    if (!peer_has_vnet_hdr(n) || !peer_has_ufo(n)) {
-        features &= ~(0x1 << VIRTIO_NET_F_GUEST_UFO);
-        features &= ~(0x1 << VIRTIO_NET_F_HOST_UFO);
-    }
-
-    if (!nc->peer || nc->peer->info->type != NET_CLIENT_OPTIONS_KIND_TAP) {
-        return features;
-    }
-    if (!tap_get_vhost_net(nc->peer)) {
-        return features;
-    }
-    return vhost_net_get_features(tap_get_vhost_net(nc->peer), features);
-}
-
-static uint32_t virtio_net_bad_features(VirtIODevice *vdev)
-{
-    uint32_t features = 0;
-
-    /* Linux kernel 2.6.25.  It understood MAC (as everyone must),
-     * but also these: */
-    features |= (1 << VIRTIO_NET_F_MAC);
-    features |= (1 << VIRTIO_NET_F_CSUM);
-    features |= (1 << VIRTIO_NET_F_HOST_TSO4);
-    features |= (1 << VIRTIO_NET_F_HOST_TSO6);
-    features |= (1 << VIRTIO_NET_F_HOST_ECN);
-
-    return features;
-}
-
-static void virtio_net_set_features(VirtIODevice *vdev, uint32_t features)
-{
-    VirtIONet *n = to_virtio_net(vdev);
-    int i;
-
-    virtio_net_set_multiqueue(n, !!(features & (1 << VIRTIO_NET_F_MQ)),
-                              !!(features & (1 << VIRTIO_NET_F_CTRL_VQ)));
-
-    virtio_net_set_mrg_rx_bufs(n, !!(features & (1 << VIRTIO_NET_F_MRG_RXBUF)));
-
-    if (n->has_vnet_hdr) {
-        tap_set_offload(qemu_get_subqueue(n->nic, 0)->peer,
-                        (features >> VIRTIO_NET_F_GUEST_CSUM) & 1,
-                        (features >> VIRTIO_NET_F_GUEST_TSO4) & 1,
-                        (features >> VIRTIO_NET_F_GUEST_TSO6) & 1,
-                        (features >> VIRTIO_NET_F_GUEST_ECN)  & 1,
-                        (features >> VIRTIO_NET_F_GUEST_UFO)  & 1);
-    }
-
-    for (i = 0;  i < n->max_queues; i++) {
-        NetClientState *nc = qemu_get_subqueue(n->nic, i);
-
-        if (!nc->peer || nc->peer->info->type != NET_CLIENT_OPTIONS_KIND_TAP) {
-            continue;
-        }
-        if (!tap_get_vhost_net(nc->peer)) {
-            continue;
-        }
-        vhost_net_ack_features(tap_get_vhost_net(nc->peer), features);
-    }
-}
-
-static int virtio_net_handle_rx_mode(VirtIONet *n, uint8_t cmd,
-                                     struct iovec *iov, unsigned int iov_cnt)
-{
-    uint8_t on;
-    size_t s;
-
-    s = iov_to_buf(iov, iov_cnt, 0, &on, sizeof(on));
-    if (s != sizeof(on)) {
-        return VIRTIO_NET_ERR;
-    }
-
-    if (cmd == VIRTIO_NET_CTRL_RX_PROMISC) {
-        n->promisc = on;
-    } else if (cmd == VIRTIO_NET_CTRL_RX_ALLMULTI) {
-        n->allmulti = on;
-    } else if (cmd == VIRTIO_NET_CTRL_RX_ALLUNI) {
-        n->alluni = on;
-    } else if (cmd == VIRTIO_NET_CTRL_RX_NOMULTI) {
-        n->nomulti = on;
-    } else if (cmd == VIRTIO_NET_CTRL_RX_NOUNI) {
-        n->nouni = on;
-    } else if (cmd == VIRTIO_NET_CTRL_RX_NOBCAST) {
-        n->nobcast = on;
-    } else {
-        return VIRTIO_NET_ERR;
-    }
-
-    return VIRTIO_NET_OK;
-}
-
-static int virtio_net_handle_mac(VirtIONet *n, uint8_t cmd,
-                                 struct iovec *iov, unsigned int iov_cnt)
-{
-    struct virtio_net_ctrl_mac mac_data;
-    size_t s;
-
-    if (cmd == VIRTIO_NET_CTRL_MAC_ADDR_SET) {
-        if (iov_size(iov, iov_cnt) != sizeof(n->mac)) {
-            return VIRTIO_NET_ERR;
-        }
-        s = iov_to_buf(iov, iov_cnt, 0, &n->mac, sizeof(n->mac));
-        assert(s == sizeof(n->mac));
-        qemu_format_nic_info_str(qemu_get_queue(n->nic), n->mac);
-        return VIRTIO_NET_OK;
-    }
-
-    if (cmd != VIRTIO_NET_CTRL_MAC_TABLE_SET) {
-        return VIRTIO_NET_ERR;
-    }
-
-    n->mac_table.in_use = 0;
-    n->mac_table.first_multi = 0;
-    n->mac_table.uni_overflow = 0;
-    n->mac_table.multi_overflow = 0;
-    memset(n->mac_table.macs, 0, MAC_TABLE_ENTRIES * ETH_ALEN);
-
-    s = iov_to_buf(iov, iov_cnt, 0, &mac_data.entries,
-                   sizeof(mac_data.entries));
-    mac_data.entries = ldl_p(&mac_data.entries);
-    if (s != sizeof(mac_data.entries)) {
-        return VIRTIO_NET_ERR;
-    }
-    iov_discard_front(&iov, &iov_cnt, s);
-
-    if (mac_data.entries * ETH_ALEN > iov_size(iov, iov_cnt)) {
-        return VIRTIO_NET_ERR;
-    }
-
-    if (mac_data.entries <= MAC_TABLE_ENTRIES) {
-        s = iov_to_buf(iov, iov_cnt, 0, n->mac_table.macs,
-                       mac_data.entries * ETH_ALEN);
-        if (s != mac_data.entries * ETH_ALEN) {
-            return VIRTIO_NET_ERR;
-        }
-        n->mac_table.in_use += mac_data.entries;
-    } else {
-        n->mac_table.uni_overflow = 1;
-    }
-
-    iov_discard_front(&iov, &iov_cnt, mac_data.entries * ETH_ALEN);
-
-    n->mac_table.first_multi = n->mac_table.in_use;
-
-    s = iov_to_buf(iov, iov_cnt, 0, &mac_data.entries,
-                   sizeof(mac_data.entries));
-    mac_data.entries = ldl_p(&mac_data.entries);
-    if (s != sizeof(mac_data.entries)) {
-        return VIRTIO_NET_ERR;
-    }
-
-    iov_discard_front(&iov, &iov_cnt, s);
-
-    if (mac_data.entries * ETH_ALEN != iov_size(iov, iov_cnt)) {
-        return VIRTIO_NET_ERR;
-    }
-
-    if (n->mac_table.in_use + mac_data.entries <= MAC_TABLE_ENTRIES) {
-        s = iov_to_buf(iov, iov_cnt, 0, n->mac_table.macs,
-                       mac_data.entries * ETH_ALEN);
-        if (s != mac_data.entries * ETH_ALEN) {
-            return VIRTIO_NET_ERR;
-        }
-        n->mac_table.in_use += mac_data.entries;
-    } else {
-        n->mac_table.multi_overflow = 1;
-    }
-
-    return VIRTIO_NET_OK;
-}
-
-static int virtio_net_handle_vlan_table(VirtIONet *n, uint8_t cmd,
-                                        struct iovec *iov, unsigned int iov_cnt)
-{
-    uint16_t vid;
-    size_t s;
-
-    s = iov_to_buf(iov, iov_cnt, 0, &vid, sizeof(vid));
-    vid = lduw_p(&vid);
-    if (s != sizeof(vid)) {
-        return VIRTIO_NET_ERR;
-    }
-
-    if (vid >= MAX_VLAN)
-        return VIRTIO_NET_ERR;
-
-    if (cmd == VIRTIO_NET_CTRL_VLAN_ADD)
-        n->vlans[vid >> 5] |= (1U << (vid & 0x1f));
-    else if (cmd == VIRTIO_NET_CTRL_VLAN_DEL)
-        n->vlans[vid >> 5] &= ~(1U << (vid & 0x1f));
-    else
-        return VIRTIO_NET_ERR;
-
-    return VIRTIO_NET_OK;
-}
-
-static int virtio_net_handle_mq(VirtIONet *n, uint8_t cmd,
-                                struct iovec *iov, unsigned int iov_cnt)
-{
-    struct virtio_net_ctrl_mq mq;
-    size_t s;
-    uint16_t queues;
-
-    s = iov_to_buf(iov, iov_cnt, 0, &mq, sizeof(mq));
-    if (s != sizeof(mq)) {
-        return VIRTIO_NET_ERR;
-    }
-
-    if (cmd != VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET) {
-        return VIRTIO_NET_ERR;
-    }
-
-    queues = lduw_p(&mq.virtqueue_pairs);
-
-    if (queues < VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN ||
-        queues > VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX ||
-        queues > n->max_queues ||
-        !n->multiqueue) {
-        return VIRTIO_NET_ERR;
-    }
-
-    n->curr_queues = queues;
-    /* stop the backend before changing the number of queues to avoid handling a
-     * disabled queue */
-    virtio_net_set_status(&n->vdev, n->vdev.status);
-    virtio_net_set_queues(n);
-
-    return VIRTIO_NET_OK;
-}
-static void virtio_net_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
-{
-    VirtIONet *n = to_virtio_net(vdev);
-    struct virtio_net_ctrl_hdr ctrl;
-    virtio_net_ctrl_ack status = VIRTIO_NET_ERR;
-    VirtQueueElement elem;
-    size_t s;
-    struct iovec *iov;
-    unsigned int iov_cnt;
-
-    while (virtqueue_pop(vq, &elem)) {
-        if (iov_size(elem.in_sg, elem.in_num) < sizeof(status) ||
-            iov_size(elem.out_sg, elem.out_num) < sizeof(ctrl)) {
-            error_report("virtio-net ctrl missing headers");
-            exit(1);
-        }
-
-        iov = elem.out_sg;
-        iov_cnt = elem.out_num;
-        s = iov_to_buf(iov, iov_cnt, 0, &ctrl, sizeof(ctrl));
-        iov_discard_front(&iov, &iov_cnt, sizeof(ctrl));
-        if (s != sizeof(ctrl)) {
-            status = VIRTIO_NET_ERR;
-        } else if (ctrl.class == VIRTIO_NET_CTRL_RX) {
-            status = virtio_net_handle_rx_mode(n, ctrl.cmd, iov, iov_cnt);
-        } else if (ctrl.class == VIRTIO_NET_CTRL_MAC) {
-            status = virtio_net_handle_mac(n, ctrl.cmd, iov, iov_cnt);
-        } else if (ctrl.class == VIRTIO_NET_CTRL_VLAN) {
-            status = virtio_net_handle_vlan_table(n, ctrl.cmd, iov, iov_cnt);
-        } else if (ctrl.class == VIRTIO_NET_CTRL_MQ) {
-            status = virtio_net_handle_mq(n, ctrl.cmd, iov, iov_cnt);
-        }
-
-        s = iov_from_buf(elem.in_sg, elem.in_num, 0, &status, sizeof(status));
-        assert(s == sizeof(status));
-
-        virtqueue_push(vq, &elem, sizeof(status));
-        virtio_notify(vdev, vq);
-    }
-}
-
-/* RX */
-
-static void virtio_net_handle_rx(VirtIODevice *vdev, VirtQueue *vq)
-{
-    VirtIONet *n = to_virtio_net(vdev);
-    int queue_index = vq2q(virtio_get_queue_index(vq));
-
-    qemu_flush_queued_packets(qemu_get_subqueue(n->nic, queue_index));
-}
-
-static int virtio_net_can_receive(NetClientState *nc)
-{
-    VirtIONet *n = qemu_get_nic_opaque(nc);
-    VirtIONetQueue *q = virtio_net_get_subqueue(nc);
-
-    if (!n->vdev.vm_running) {
-        return 0;
-    }
-
-    if (nc->queue_index >= n->curr_queues) {
-        return 0;
-    }
-
-    if (!virtio_queue_ready(q->rx_vq) ||
-        !(n->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK)) {
-        return 0;
-    }
-
-    return 1;
-}
-
-static int virtio_net_has_buffers(VirtIONetQueue *q, int bufsize)
-{
-    VirtIONet *n = q->n;
-    if (virtio_queue_empty(q->rx_vq) ||
-        (n->mergeable_rx_bufs &&
-         !virtqueue_avail_bytes(q->rx_vq, bufsize, 0))) {
-        virtio_queue_set_notification(q->rx_vq, 1);
-
-        /* To avoid a race condition where the guest has made some buffers
-         * available after the above check but before notification was
-         * enabled, check for available buffers again.
-         */
-        if (virtio_queue_empty(q->rx_vq) ||
-            (n->mergeable_rx_bufs &&
-             !virtqueue_avail_bytes(q->rx_vq, bufsize, 0))) {
-            return 0;
-        }
-    }
-
-    virtio_queue_set_notification(q->rx_vq, 0);
-    return 1;
-}
-
-/* dhclient uses AF_PACKET but doesn't pass auxdata to the kernel so
- * it never finds out that the packets don't have valid checksums.  This
- * causes dhclient to get upset.  Fedora's carried a patch for ages to
- * fix this with Xen but it hasn't appeared in an upstream release of
- * dhclient yet.
- *
- * To avoid breaking existing guests, we catch udp packets and add
- * checksums.  This is terrible but it's better than hacking the guest
- * kernels.
- *
- * N.B. if we introduce a zero-copy API, this operation is no longer free so
- * we should provide a mechanism to disable it to avoid polluting the host
- * cache.
- */
-static void work_around_broken_dhclient(struct virtio_net_hdr *hdr,
-                                        uint8_t *buf, size_t size)
-{
-    if ((hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) && /* missing csum */
-        (size > 27 && size < 1500) && /* normal sized MTU */
-        (buf[12] == 0x08 && buf[13] == 0x00) && /* ethertype == IPv4 */
-        (buf[23] == 17) && /* ip.protocol == UDP */
-        (buf[34] == 0 && buf[35] == 67)) { /* udp.srcport == bootps */
-        net_checksum_calculate(buf, size);
-        hdr->flags &= ~VIRTIO_NET_HDR_F_NEEDS_CSUM;
-    }
-}
-
-static void receive_header(VirtIONet *n, const struct iovec *iov, int iov_cnt,
-                           const void *buf, size_t size)
-{
-    if (n->has_vnet_hdr) {
-        /* FIXME this cast is evil */
-        void *wbuf = (void *)buf;
-        work_around_broken_dhclient(wbuf, wbuf + n->host_hdr_len,
-                                    size - n->host_hdr_len);
-        iov_from_buf(iov, iov_cnt, 0, buf, sizeof(struct virtio_net_hdr));
-    } else {
-        struct virtio_net_hdr hdr = {
-            .flags = 0,
-            .gso_type = VIRTIO_NET_HDR_GSO_NONE
-        };
-        iov_from_buf(iov, iov_cnt, 0, &hdr, sizeof hdr);
-    }
-}
-
-static int receive_filter(VirtIONet *n, const uint8_t *buf, int size)
-{
-    static const uint8_t bcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
-    static const uint8_t vlan[] = {0x81, 0x00};
-    uint8_t *ptr = (uint8_t *)buf;
-    int i;
-
-    if (n->promisc)
-        return 1;
-
-    ptr += n->host_hdr_len;
-
-    if (!memcmp(&ptr[12], vlan, sizeof(vlan))) {
-        int vid = be16_to_cpup((uint16_t *)(ptr + 14)) & 0xfff;
-        if (!(n->vlans[vid >> 5] & (1U << (vid & 0x1f))))
-            return 0;
-    }
-
-    if (ptr[0] & 1) { // multicast
-        if (!memcmp(ptr, bcast, sizeof(bcast))) {
-            return !n->nobcast;
-        } else if (n->nomulti) {
-            return 0;
-        } else if (n->allmulti || n->mac_table.multi_overflow) {
-            return 1;
-        }
-
-        for (i = n->mac_table.first_multi; i < n->mac_table.in_use; i++) {
-            if (!memcmp(ptr, &n->mac_table.macs[i * ETH_ALEN], ETH_ALEN)) {
-                return 1;
-            }
-        }
-    } else { // unicast
-        if (n->nouni) {
-            return 0;
-        } else if (n->alluni || n->mac_table.uni_overflow) {
-            return 1;
-        } else if (!memcmp(ptr, n->mac, ETH_ALEN)) {
-            return 1;
-        }
-
-        for (i = 0; i < n->mac_table.first_multi; i++) {
-            if (!memcmp(ptr, &n->mac_table.macs[i * ETH_ALEN], ETH_ALEN)) {
-                return 1;
-            }
-        }
-    }
-
-    return 0;
-}
-
-static ssize_t virtio_net_receive(NetClientState *nc, const uint8_t *buf, size_t size)
-{
-    VirtIONet *n = qemu_get_nic_opaque(nc);
-    VirtIONetQueue *q = virtio_net_get_subqueue(nc);
-    struct iovec mhdr_sg[VIRTQUEUE_MAX_SIZE];
-    struct virtio_net_hdr_mrg_rxbuf mhdr;
-    unsigned mhdr_cnt = 0;
-    size_t offset, i, guest_offset;
-
-    if (!virtio_net_can_receive(nc)) {
-        return -1;
-    }
-
-    /* hdr_len refers to the header we supply to the guest */
-    if (!virtio_net_has_buffers(q, size + n->guest_hdr_len - n->host_hdr_len)) {
-        return 0;
-    }
-
-    if (!receive_filter(n, buf, size))
-        return size;
-
-    offset = i = 0;
-
-    while (offset < size) {
-        VirtQueueElement elem;
-        int len, total;
-        const struct iovec *sg = elem.in_sg;
-
-        total = 0;
-
-        if (virtqueue_pop(q->rx_vq, &elem) == 0) {
-            if (i == 0)
-                return -1;
-            error_report("virtio-net unexpected empty queue: "
-                    "i %zd mergeable %d offset %zd, size %zd, "
-                    "guest hdr len %zd, host hdr len %zd guest features 0x%x",
-                    i, n->mergeable_rx_bufs, offset, size,
-                    n->guest_hdr_len, n->host_hdr_len, n->vdev.guest_features);
-            exit(1);
-        }
-
-        if (elem.in_num < 1) {
-            error_report("virtio-net receive queue contains no in buffers");
-            exit(1);
-        }
-
-        if (i == 0) {
-            assert(offset == 0);
-            if (n->mergeable_rx_bufs) {
-                mhdr_cnt = iov_copy(mhdr_sg, ARRAY_SIZE(mhdr_sg),
-                                    sg, elem.in_num,
-                                    offsetof(typeof(mhdr), num_buffers),
-                                    sizeof(mhdr.num_buffers));
-            }
-
-            receive_header(n, sg, elem.in_num, buf, size);
-            offset = n->host_hdr_len;
-            total += n->guest_hdr_len;
-            guest_offset = n->guest_hdr_len;
-        } else {
-            guest_offset = 0;
-        }
-
-        /* copy in packet.  ugh */
-        len = iov_from_buf(sg, elem.in_num, guest_offset,
-                           buf + offset, size - offset);
-        total += len;
-        offset += len;
-        /* If buffers can't be merged, at this point we
-         * must have consumed the complete packet.
-         * Otherwise, drop it. */
-        if (!n->mergeable_rx_bufs && offset < size) {
-#if 0
-            error_report("virtio-net truncated non-mergeable packet: "
-                         "i %zd mergeable %d offset %zd, size %zd, "
-                         "guest hdr len %zd, host hdr len %zd",
-                         i, n->mergeable_rx_bufs,
-                         offset, size, n->guest_hdr_len, n->host_hdr_len);
-#endif
-            return size;
-        }
-
-        /* signal other side */
-        virtqueue_fill(q->rx_vq, &elem, total, i++);
-    }
-
-    if (mhdr_cnt) {
-        stw_p(&mhdr.num_buffers, i);
-        iov_from_buf(mhdr_sg, mhdr_cnt,
-                     0,
-                     &mhdr.num_buffers, sizeof mhdr.num_buffers);
-    }
-
-    virtqueue_flush(q->rx_vq, i);
-    virtio_notify(&n->vdev, q->rx_vq);
-
-    return size;
-}
-
-static int32_t virtio_net_flush_tx(VirtIONetQueue *q);
-
-static void virtio_net_tx_complete(NetClientState *nc, ssize_t len)
-{
-    VirtIONet *n = qemu_get_nic_opaque(nc);
-    VirtIONetQueue *q = virtio_net_get_subqueue(nc);
-
-    virtqueue_push(q->tx_vq, &q->async_tx.elem, 0);
-    virtio_notify(&n->vdev, q->tx_vq);
-
-    q->async_tx.elem.out_num = q->async_tx.len = 0;
-
-    virtio_queue_set_notification(q->tx_vq, 1);
-    virtio_net_flush_tx(q);
-}
-
-/* TX */
-static int32_t virtio_net_flush_tx(VirtIONetQueue *q)
-{
-    VirtIONet *n = q->n;
-    VirtQueueElement elem;
-    int32_t num_packets = 0;
-    int queue_index = vq2q(virtio_get_queue_index(q->tx_vq));
-    if (!(n->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK)) {
-        return num_packets;
-    }
-
-    assert(n->vdev.vm_running);
-
-    if (q->async_tx.elem.out_num) {
-        virtio_queue_set_notification(q->tx_vq, 0);
-        return num_packets;
-    }
-
-    while (virtqueue_pop(q->tx_vq, &elem)) {
-        ssize_t ret, len;
-        unsigned int out_num = elem.out_num;
-        struct iovec *out_sg = &elem.out_sg[0];
-        struct iovec sg[VIRTQUEUE_MAX_SIZE];
-
-        if (out_num < 1) {
-            error_report("virtio-net header not in first element");
-            exit(1);
-        }
-
-        /*
-         * If host wants to see the guest header as is, we can
-         * pass it on unchanged. Otherwise, copy just the parts
-         * that host is interested in.
-         */
-        assert(n->host_hdr_len <= n->guest_hdr_len);
-        if (n->host_hdr_len != n->guest_hdr_len) {
-            unsigned sg_num = iov_copy(sg, ARRAY_SIZE(sg),
-                                       out_sg, out_num,
-                                       0, n->host_hdr_len);
-            sg_num += iov_copy(sg + sg_num, ARRAY_SIZE(sg) - sg_num,
-                             out_sg, out_num,
-                             n->guest_hdr_len, -1);
-            out_num = sg_num;
-            out_sg = sg;
-        }
-
-        len = n->guest_hdr_len;
-
-        ret = qemu_sendv_packet_async(qemu_get_subqueue(n->nic, queue_index),
-                                      out_sg, out_num, virtio_net_tx_complete);
-        if (ret == 0) {
-            virtio_queue_set_notification(q->tx_vq, 0);
-            q->async_tx.elem = elem;
-            q->async_tx.len  = len;
-            return -EBUSY;
-        }
-
-        len += ret;
-
-        virtqueue_push(q->tx_vq, &elem, 0);
-        virtio_notify(&n->vdev, q->tx_vq);
-
-        if (++num_packets >= n->tx_burst) {
-            break;
-        }
-    }
-    return num_packets;
-}
-
-static void virtio_net_handle_tx_timer(VirtIODevice *vdev, VirtQueue *vq)
-{
-    VirtIONet *n = to_virtio_net(vdev);
-    VirtIONetQueue *q = &n->vqs[vq2q(virtio_get_queue_index(vq))];
-
-    /* This happens when device was stopped but VCPU wasn't. */
-    if (!n->vdev.vm_running) {
-        q->tx_waiting = 1;
-        return;
-    }
-
-    if (q->tx_waiting) {
-        virtio_queue_set_notification(vq, 1);
-        qemu_del_timer(q->tx_timer);
-        q->tx_waiting = 0;
-        virtio_net_flush_tx(q);
-    } else {
-        qemu_mod_timer(q->tx_timer,
-                       qemu_get_clock_ns(vm_clock) + n->tx_timeout);
-        q->tx_waiting = 1;
-        virtio_queue_set_notification(vq, 0);
-    }
-}
-
-static void virtio_net_handle_tx_bh(VirtIODevice *vdev, VirtQueue *vq)
-{
-    VirtIONet *n = to_virtio_net(vdev);
-    VirtIONetQueue *q = &n->vqs[vq2q(virtio_get_queue_index(vq))];
-
-    if (unlikely(q->tx_waiting)) {
-        return;
-    }
-    q->tx_waiting = 1;
-    /* This happens when device was stopped but VCPU wasn't. */
-    if (!n->vdev.vm_running) {
-        return;
-    }
-    virtio_queue_set_notification(vq, 0);
-    qemu_bh_schedule(q->tx_bh);
-}
-
-static void virtio_net_tx_timer(void *opaque)
-{
-    VirtIONetQueue *q = opaque;
-    VirtIONet *n = q->n;
-    assert(n->vdev.vm_running);
-
-    q->tx_waiting = 0;
-
-    /* Just in case the driver is not ready on more */
-    if (!(n->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK))
-        return;
-
-    virtio_queue_set_notification(q->tx_vq, 1);
-    virtio_net_flush_tx(q);
-}
-
-static void virtio_net_tx_bh(void *opaque)
-{
-    VirtIONetQueue *q = opaque;
-    VirtIONet *n = q->n;
-    int32_t ret;
-
-    assert(n->vdev.vm_running);
-
-    q->tx_waiting = 0;
-
-    /* Just in case the driver is not ready on more */
-    if (unlikely(!(n->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK)))
-        return;
-
-    ret = virtio_net_flush_tx(q);
-    if (ret == -EBUSY) {
-        return; /* Notification re-enable handled by tx_complete */
-    }
-
-    /* If we flush a full burst of packets, assume there are
-     * more coming and immediately reschedule */
-    if (ret >= n->tx_burst) {
-        qemu_bh_schedule(q->tx_bh);
-        q->tx_waiting = 1;
-        return;
-    }
-
-    /* If less than a full burst, re-enable notification and flush
-     * anything that may have come in while we weren't looking.  If
-     * we find something, assume the guest is still active and reschedule */
-    virtio_queue_set_notification(q->tx_vq, 1);
-    if (virtio_net_flush_tx(q) > 0) {
-        virtio_queue_set_notification(q->tx_vq, 0);
-        qemu_bh_schedule(q->tx_bh);
-        q->tx_waiting = 1;
-    }
-}
-
-static void virtio_net_set_multiqueue(VirtIONet *n, int multiqueue, int ctrl)
-{
-    VirtIODevice *vdev = &n->vdev;
-    int i, max = multiqueue ? n->max_queues : 1;
-
-    n->multiqueue = multiqueue;
-
-    for (i = 2; i <= n->max_queues * 2 + 1; i++) {
-        virtio_del_queue(vdev, i);
-    }
-
-    for (i = 1; i < max; i++) {
-        n->vqs[i].rx_vq = virtio_add_queue(vdev, 256, virtio_net_handle_rx);
-        if (n->vqs[i].tx_timer) {
-            n->vqs[i].tx_vq =
-                virtio_add_queue(vdev, 256, virtio_net_handle_tx_timer);
-            n->vqs[i].tx_timer = qemu_new_timer_ns(vm_clock,
-                                                   virtio_net_tx_timer,
-                                                   &n->vqs[i]);
-        } else {
-            n->vqs[i].tx_vq =
-                virtio_add_queue(vdev, 256, virtio_net_handle_tx_bh);
-            n->vqs[i].tx_bh = qemu_bh_new(virtio_net_tx_bh, &n->vqs[i]);
-        }
-
-        n->vqs[i].tx_waiting = 0;
-        n->vqs[i].n = n;
-    }
-
-    if (ctrl) {
-        n->ctrl_vq = virtio_add_queue(vdev, 64, virtio_net_handle_ctrl);
-    }
-
-    virtio_net_set_queues(n);
-}
-
-static void virtio_net_save(QEMUFile *f, void *opaque)
-{
-    int i;
-    VirtIONet *n = opaque;
-
-    /* At this point, backend must be stopped, otherwise
-     * it might keep writing to memory. */
-    assert(!n->vhost_started);
-    virtio_save(&n->vdev, f);
-
-    qemu_put_buffer(f, n->mac, ETH_ALEN);
-    qemu_put_be32(f, n->vqs[0].tx_waiting);
-    qemu_put_be32(f, n->mergeable_rx_bufs);
-    qemu_put_be16(f, n->status);
-    qemu_put_byte(f, n->promisc);
-    qemu_put_byte(f, n->allmulti);
-    qemu_put_be32(f, n->mac_table.in_use);
-    qemu_put_buffer(f, n->mac_table.macs, n->mac_table.in_use * ETH_ALEN);
-    qemu_put_buffer(f, (uint8_t *)n->vlans, MAX_VLAN >> 3);
-    qemu_put_be32(f, n->has_vnet_hdr);
-    qemu_put_byte(f, n->mac_table.multi_overflow);
-    qemu_put_byte(f, n->mac_table.uni_overflow);
-    qemu_put_byte(f, n->alluni);
-    qemu_put_byte(f, n->nomulti);
-    qemu_put_byte(f, n->nouni);
-    qemu_put_byte(f, n->nobcast);
-    qemu_put_byte(f, n->has_ufo);
-    if (n->max_queues > 1) {
-        qemu_put_be16(f, n->max_queues);
-        qemu_put_be16(f, n->curr_queues);
-        for (i = 1; i < n->curr_queues; i++) {
-            qemu_put_be32(f, n->vqs[i].tx_waiting);
-        }
-    }
-}
-
-static int virtio_net_load(QEMUFile *f, void *opaque, int version_id)
-{
-    VirtIONet *n = opaque;
-    int ret, i, link_down;
-
-    if (version_id < 2 || version_id > VIRTIO_NET_VM_VERSION)
-        return -EINVAL;
-
-    ret = virtio_load(&n->vdev, f);
-    if (ret) {
-        return ret;
-    }
-
-    qemu_get_buffer(f, n->mac, ETH_ALEN);
-    n->vqs[0].tx_waiting = qemu_get_be32(f);
-
-    virtio_net_set_mrg_rx_bufs(n, qemu_get_be32(f));
-
-    if (version_id >= 3)
-        n->status = qemu_get_be16(f);
-
-    if (version_id >= 4) {
-        if (version_id < 8) {
-            n->promisc = qemu_get_be32(f);
-            n->allmulti = qemu_get_be32(f);
-        } else {
-            n->promisc = qemu_get_byte(f);
-            n->allmulti = qemu_get_byte(f);
-        }
-    }
-
-    if (version_id >= 5) {
-        n->mac_table.in_use = qemu_get_be32(f);
-        /* MAC_TABLE_ENTRIES may be different from the saved image */
-        if (n->mac_table.in_use <= MAC_TABLE_ENTRIES) {
-            qemu_get_buffer(f, n->mac_table.macs,
-                            n->mac_table.in_use * ETH_ALEN);
-        } else if (n->mac_table.in_use) {
-            uint8_t *buf = g_malloc0(n->mac_table.in_use);
-            qemu_get_buffer(f, buf, n->mac_table.in_use * ETH_ALEN);
-            g_free(buf);
-            n->mac_table.multi_overflow = n->mac_table.uni_overflow = 1;
-            n->mac_table.in_use = 0;
-        }
-    }
-    if (version_id >= 6)
-        qemu_get_buffer(f, (uint8_t *)n->vlans, MAX_VLAN >> 3);
-
-    if (version_id >= 7) {
-        if (qemu_get_be32(f) && !peer_has_vnet_hdr(n)) {
-            error_report("virtio-net: saved image requires vnet_hdr=on");
-            return -1;
-        }
-
-        if (n->has_vnet_hdr) {
-            tap_set_offload(qemu_get_queue(n->nic)->peer,
-                    (n->vdev.guest_features >> VIRTIO_NET_F_GUEST_CSUM) & 1,
-                    (n->vdev.guest_features >> VIRTIO_NET_F_GUEST_TSO4) & 1,
-                    (n->vdev.guest_features >> VIRTIO_NET_F_GUEST_TSO6) & 1,
-                    (n->vdev.guest_features >> VIRTIO_NET_F_GUEST_ECN)  & 1,
-                    (n->vdev.guest_features >> VIRTIO_NET_F_GUEST_UFO)  & 1);
-        }
-    }
-
-    if (version_id >= 9) {
-        n->mac_table.multi_overflow = qemu_get_byte(f);
-        n->mac_table.uni_overflow = qemu_get_byte(f);
-    }
-
-    if (version_id >= 10) {
-        n->alluni = qemu_get_byte(f);
-        n->nomulti = qemu_get_byte(f);
-        n->nouni = qemu_get_byte(f);
-        n->nobcast = qemu_get_byte(f);
-    }
-
-    if (version_id >= 11) {
-        if (qemu_get_byte(f) && !peer_has_ufo(n)) {
-            error_report("virtio-net: saved image requires TUN_F_UFO support");
-            return -1;
-        }
-    }
-
-    if (n->max_queues > 1) {
-        if (n->max_queues != qemu_get_be16(f)) {
-            error_report("virtio-net: different max_queues ");
-            return -1;
-        }
-
-        n->curr_queues = qemu_get_be16(f);
-        for (i = 1; i < n->curr_queues; i++) {
-            n->vqs[i].tx_waiting = qemu_get_be32(f);
-        }
-    }
-
-    virtio_net_set_queues(n);
-
-    /* Find the first multicast entry in the saved MAC filter */
-    for (i = 0; i < n->mac_table.in_use; i++) {
-        if (n->mac_table.macs[i * ETH_ALEN] & 1) {
-            break;
-        }
-    }
-    n->mac_table.first_multi = i;
-
-    /* nc.link_down can't be migrated, so infer link_down according
-     * to link status bit in n->status */
-    link_down = (n->status & VIRTIO_NET_S_LINK_UP) == 0;
-    for (i = 0; i < n->max_queues; i++) {
-        qemu_get_subqueue(n->nic, i)->link_down = link_down;
-    }
-
-    return 0;
-}
-
-static void virtio_net_cleanup(NetClientState *nc)
-{
-    VirtIONet *n = qemu_get_nic_opaque(nc);
-
-    n->nic = NULL;
-}
-
-static NetClientInfo net_virtio_info = {
-    .type = NET_CLIENT_OPTIONS_KIND_NIC,
-    .size = sizeof(NICState),
-    .can_receive = virtio_net_can_receive,
-    .receive = virtio_net_receive,
-        .cleanup = virtio_net_cleanup,
-    .link_status_changed = virtio_net_set_link_status,
-};
-
-static bool virtio_net_guest_notifier_pending(VirtIODevice *vdev, int idx)
-{
-    VirtIONet *n = to_virtio_net(vdev);
-    NetClientState *nc = qemu_get_subqueue(n->nic, vq2q(idx));
-    assert(n->vhost_started);
-    return vhost_net_virtqueue_pending(tap_get_vhost_net(nc->peer), idx);
-}
-
-static void virtio_net_guest_notifier_mask(VirtIODevice *vdev, int idx,
-                                           bool mask)
-{
-    VirtIONet *n = to_virtio_net(vdev);
-    NetClientState *nc = qemu_get_subqueue(n->nic, vq2q(idx));
-    assert(n->vhost_started);
-    vhost_net_virtqueue_mask(tap_get_vhost_net(nc->peer),
-                             vdev, idx, mask);
-}
-
-VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf,
-                              virtio_net_conf *net, uint32_t host_features)
-{
-    VirtIONet *n;
-    int i, config_size = 0;
-
-    for (i = 0; feature_sizes[i].flags != 0; i++) {
-        if (host_features & feature_sizes[i].flags) {
-            config_size = MAX(feature_sizes[i].end, config_size);
-        }
-    }
-
-    n = (VirtIONet *)virtio_common_init("virtio-net", VIRTIO_ID_NET,
-                                        config_size, sizeof(VirtIONet));
-
-    n->config_size = config_size;
-    n->vdev.get_config = virtio_net_get_config;
-    n->vdev.set_config = virtio_net_set_config;
-    n->vdev.get_features = virtio_net_get_features;
-    n->vdev.set_features = virtio_net_set_features;
-    n->vdev.bad_features = virtio_net_bad_features;
-    n->vdev.reset = virtio_net_reset;
-    n->vdev.set_status = virtio_net_set_status;
-    n->vdev.guest_notifier_mask = virtio_net_guest_notifier_mask;
-    n->vdev.guest_notifier_pending = virtio_net_guest_notifier_pending;
-    n->max_queues = MAX(conf->queues, 1);
-    n->vqs = g_malloc0(sizeof(VirtIONetQueue) * n->max_queues);
-    n->vqs[0].rx_vq = virtio_add_queue(&n->vdev, 256, virtio_net_handle_rx);
-    n->curr_queues = 1;
-    n->vqs[0].n = n;
-    n->tx_timeout = net->txtimer;
-
-    if (net->tx && strcmp(net->tx, "timer") && strcmp(net->tx, "bh")) {
-        error_report("virtio-net: "
-                     "Unknown option tx=%s, valid options: \"timer\" \"bh\"",
-                     net->tx);
-        error_report("Defaulting to \"bh\"");
-    }
-
-    if (net->tx && !strcmp(net->tx, "timer")) {
-        n->vqs[0].tx_vq = virtio_add_queue(&n->vdev, 256,
-                                           virtio_net_handle_tx_timer);
-        n->vqs[0].tx_timer = qemu_new_timer_ns(vm_clock, virtio_net_tx_timer,
-                                               &n->vqs[0]);
-    } else {
-        n->vqs[0].tx_vq = virtio_add_queue(&n->vdev, 256,
-                                           virtio_net_handle_tx_bh);
-        n->vqs[0].tx_bh = qemu_bh_new(virtio_net_tx_bh, &n->vqs[0]);
-    }
-    n->ctrl_vq = virtio_add_queue(&n->vdev, 64, virtio_net_handle_ctrl);
-    qemu_macaddr_default_if_unset(&conf->macaddr);
-    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, object_get_typename(OBJECT(dev)), dev->id, n);
-    peer_test_vnet_hdr(n);
-    if (peer_has_vnet_hdr(n)) {
-        for (i = 0; i < n->max_queues; i++) {
-            tap_using_vnet_hdr(qemu_get_subqueue(n->nic, i)->peer, true);
-        }
-        n->host_hdr_len = sizeof(struct virtio_net_hdr);
-    } else {
-        n->host_hdr_len = 0;
-    }
-
-    qemu_format_nic_info_str(qemu_get_queue(n->nic), conf->macaddr.a);
-
-    n->vqs[0].tx_waiting = 0;
-    n->tx_burst = net->txburst;
-    virtio_net_set_mrg_rx_bufs(n, 0);
-    n->promisc = 1; /* for compatibility */
-
-    n->mac_table.macs = g_malloc0(MAC_TABLE_ENTRIES * ETH_ALEN);
-
-    n->vlans = g_malloc0(MAX_VLAN >> 3);
-
-    n->qdev = dev;
-    register_savevm(dev, "virtio-net", -1, VIRTIO_NET_VM_VERSION,
-                    virtio_net_save, virtio_net_load, n);
-
-    add_boot_device_path(conf->bootindex, dev, "/ethernet-phy@0");
-
-    return &n->vdev;
-}
-
-void virtio_net_exit(VirtIODevice *vdev)
-{
-    VirtIONet *n = DO_UPCAST(VirtIONet, vdev, vdev);
-    int i;
-
-    /* This will stop vhost backend if appropriate. */
-    virtio_net_set_status(vdev, 0);
-
-    unregister_savevm(n->qdev, "virtio-net", n);
-
-    g_free(n->mac_table.macs);
-    g_free(n->vlans);
-
-    for (i = 0; i < n->max_queues; i++) {
-        VirtIONetQueue *q = &n->vqs[i];
-        NetClientState *nc = qemu_get_subqueue(n->nic, i);
-
-        qemu_purge_queued_packets(nc);
-
-        if (q->tx_timer) {
-            qemu_del_timer(q->tx_timer);
-            qemu_free_timer(q->tx_timer);
-        } else {
-            qemu_bh_delete(q->tx_bh);
-        }
-    }
-
-    g_free(n->vqs);
-    qemu_del_nic(n->nic);
-    virtio_cleanup(&n->vdev);
-}
diff --git a/hw/virtio-net.h b/hw/virtio-net.h
deleted file mode 100644 (file)
index 4d1a8cd..0000000
+++ /dev/null
@@ -1,246 +0,0 @@
-/*
- * Virtio Network Device
- *
- * Copyright IBM, Corp. 2007
- *
- * Authors:
- *  Anthony Liguori   <aliguori@us.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2.  See
- * the COPYING file in the top-level directory.
- *
- */
-
-#ifndef _QEMU_VIRTIO_NET_H
-#define _QEMU_VIRTIO_NET_H
-
-#include "hw/virtio.h"
-#include "hw/pci/pci.h"
-
-#define ETH_ALEN    6
-
-/* from Linux's virtio_net.h */
-
-/* The ID for virtio_net */
-#define VIRTIO_ID_NET   1
-
-/* The feature bitmap for virtio net */
-#define VIRTIO_NET_F_CSUM       0       /* Host handles pkts w/ partial csum */
-#define VIRTIO_NET_F_GUEST_CSUM 1       /* Guest handles pkts w/ partial csum */
-#define VIRTIO_NET_F_MAC        5       /* Host has given MAC address. */
-#define VIRTIO_NET_F_GSO        6       /* Host handles pkts w/ any GSO type */
-#define VIRTIO_NET_F_GUEST_TSO4 7       /* Guest can handle TSOv4 in. */
-#define VIRTIO_NET_F_GUEST_TSO6 8       /* Guest can handle TSOv6 in. */
-#define VIRTIO_NET_F_GUEST_ECN  9       /* Guest can handle TSO[6] w/ ECN in. */
-#define VIRTIO_NET_F_GUEST_UFO  10      /* Guest can handle UFO in. */
-#define VIRTIO_NET_F_HOST_TSO4  11      /* Host can handle TSOv4 in. */
-#define VIRTIO_NET_F_HOST_TSO6  12      /* Host can handle TSOv6 in. */
-#define VIRTIO_NET_F_HOST_ECN   13      /* Host can handle TSO[6] w/ ECN in. */
-#define VIRTIO_NET_F_HOST_UFO   14      /* Host can handle UFO in. */
-#define VIRTIO_NET_F_MRG_RXBUF  15      /* Host can merge receive buffers. */
-#define VIRTIO_NET_F_STATUS     16      /* virtio_net_config.status available */
-#define VIRTIO_NET_F_CTRL_VQ    17      /* Control channel available */
-#define VIRTIO_NET_F_CTRL_RX    18      /* Control channel RX mode support */
-#define VIRTIO_NET_F_CTRL_VLAN  19      /* Control channel VLAN filtering */
-#define VIRTIO_NET_F_CTRL_RX_EXTRA 20   /* Extra RX mode control support */
-#define VIRTIO_NET_F_MQ         22      /* Device supports Receive Flow
-                                         * Steering */
-
-#define VIRTIO_NET_F_CTRL_MAC_ADDR   23 /* Set MAC address */
-
-#define VIRTIO_NET_S_LINK_UP    1       /* Link is up */
-
-#define TX_TIMER_INTERVAL 150000 /* 150 us */
-
-/* Limit the number of packets that can be sent via a single flush
- * of the TX queue.  This gives us a guaranteed exit condition and
- * ensures fairness in the io path.  256 conveniently matches the
- * length of the TX queue and shows a good balance of performance
- * and latency. */
-#define TX_BURST 256
-
-typedef struct virtio_net_conf
-{
-    uint32_t txtimer;
-    int32_t txburst;
-    char *tx;
-} virtio_net_conf;
-
-/* Maximum packet size we can receive from tap device: header + 64k */
-#define VIRTIO_NET_MAX_BUFSIZE (sizeof(struct virtio_net_hdr) + (64 << 10))
-
-struct virtio_net_config
-{
-    /* The config defining mac address ($ETH_ALEN bytes) */
-    uint8_t mac[ETH_ALEN];
-    /* See VIRTIO_NET_F_STATUS and VIRTIO_NET_S_* above */
-    uint16_t status;
-    /* Max virtqueue pairs supported by the device */
-    uint16_t max_virtqueue_pairs;
-} QEMU_PACKED;
-
-/*
- * Control virtqueue data structures
- *
- * The control virtqueue expects a header in the first sg entry
- * and an ack/status response in the last entry.  Data for the
- * command goes in between.
- */
-struct virtio_net_ctrl_hdr {
-    uint8_t class;
-    uint8_t cmd;
-};
-
-typedef uint8_t virtio_net_ctrl_ack;
-
-#define VIRTIO_NET_OK     0
-#define VIRTIO_NET_ERR    1
-
-/*
- * Control the RX mode, ie. promisucous, allmulti, etc...
- * All commands require an "out" sg entry containing a 1 byte
- * state value, zero = disable, non-zero = enable.  Commands
- * 0 and 1 are supported with the VIRTIO_NET_F_CTRL_RX feature.
- * Commands 2-5 are added with VIRTIO_NET_F_CTRL_RX_EXTRA.
- */
-#define VIRTIO_NET_CTRL_RX    0
- #define VIRTIO_NET_CTRL_RX_PROMISC      0
- #define VIRTIO_NET_CTRL_RX_ALLMULTI     1
- #define VIRTIO_NET_CTRL_RX_ALLUNI       2
- #define VIRTIO_NET_CTRL_RX_NOMULTI      3
- #define VIRTIO_NET_CTRL_RX_NOUNI        4
- #define VIRTIO_NET_CTRL_RX_NOBCAST      5
-
-/*
- * Control the MAC
- *
- * The MAC filter table is managed by the hypervisor, the guest should
- * assume the size is infinite.  Filtering should be considered
- * non-perfect, ie. based on hypervisor resources, the guest may
- * received packets from sources not specified in the filter list.
- *
- * In addition to the class/cmd header, the TABLE_SET command requires
- * two out scatterlists.  Each contains a 4 byte count of entries followed
- * by a concatenated byte stream of the ETH_ALEN MAC addresses.  The
- * first sg list contains unicast addresses, the second is for multicast.
- * This functionality is present if the VIRTIO_NET_F_CTRL_RX feature
- * is available.
- *
- * The ADDR_SET command requests one out scatterlist, it contains a
- * 6 bytes MAC address. This functionality is present if the
- * VIRTIO_NET_F_CTRL_MAC_ADDR feature is available.
- */
-struct virtio_net_ctrl_mac {
-    uint32_t entries;
-    uint8_t macs[][ETH_ALEN];
-};
-
-typedef struct VirtIONetQueue {
-    VirtQueue *rx_vq;
-    VirtQueue *tx_vq;
-    QEMUTimer *tx_timer;
-    QEMUBH *tx_bh;
-    int tx_waiting;
-    struct {
-        VirtQueueElement elem;
-        ssize_t len;
-    } async_tx;
-    struct VirtIONet *n;
-} VirtIONetQueue;
-
-typedef struct VirtIONet {
-    VirtIODevice vdev;
-    uint8_t mac[ETH_ALEN];
-    uint16_t status;
-    VirtIONetQueue *vqs;
-    VirtQueue *ctrl_vq;
-    NICState *nic;
-    uint32_t tx_timeout;
-    int32_t tx_burst;
-    uint32_t has_vnet_hdr;
-    size_t host_hdr_len;
-    size_t guest_hdr_len;
-    uint8_t has_ufo;
-    int mergeable_rx_bufs;
-    uint8_t promisc;
-    uint8_t allmulti;
-    uint8_t alluni;
-    uint8_t nomulti;
-    uint8_t nouni;
-    uint8_t nobcast;
-    uint8_t vhost_started;
-    struct {
-        int in_use;
-        int first_multi;
-        uint8_t multi_overflow;
-        uint8_t uni_overflow;
-        uint8_t *macs;
-    } mac_table;
-    uint32_t *vlans;
-    DeviceState *qdev;
-    int multiqueue;
-    uint16_t max_queues;
-    uint16_t curr_queues;
-    size_t config_size;
-} VirtIONet;
-
-#define VIRTIO_NET_CTRL_MAC    1
- #define VIRTIO_NET_CTRL_MAC_TABLE_SET        0
- #define VIRTIO_NET_CTRL_MAC_ADDR_SET         1
-
-/*
- * Control VLAN filtering
- *
- * The VLAN filter table is controlled via a simple ADD/DEL interface.
- * VLAN IDs not added may be filterd by the hypervisor.  Del is the
- * opposite of add.  Both commands expect an out entry containing a 2
- * byte VLAN ID.  VLAN filterting is available with the
- * VIRTIO_NET_F_CTRL_VLAN feature bit.
- */
-#define VIRTIO_NET_CTRL_VLAN       2
- #define VIRTIO_NET_CTRL_VLAN_ADD             0
- #define VIRTIO_NET_CTRL_VLAN_DEL             1
-
-/*
- * Control Multiqueue
- *
- * The command VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET
- * enables multiqueue, specifying the number of the transmit and
- * receive queues that will be used. After the command is consumed and acked by
- * the device, the device will not steer new packets on receive virtqueues
- * other than specified nor read from transmit virtqueues other than specified.
- * Accordingly, driver should not transmit new packets  on virtqueues other than
- * specified.
- */
-struct virtio_net_ctrl_mq {
-    uint16_t virtqueue_pairs;
-};
-
-#define VIRTIO_NET_CTRL_MQ   4
- #define VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET        0
- #define VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN        1
- #define VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX        0x8000
-
-#define DEFINE_VIRTIO_NET_FEATURES(_state, _field) \
-        DEFINE_VIRTIO_COMMON_FEATURES(_state, _field), \
-        DEFINE_PROP_BIT("csum", _state, _field, VIRTIO_NET_F_CSUM, true), \
-        DEFINE_PROP_BIT("guest_csum", _state, _field, VIRTIO_NET_F_GUEST_CSUM, true), \
-        DEFINE_PROP_BIT("gso", _state, _field, VIRTIO_NET_F_GSO, true), \
-        DEFINE_PROP_BIT("guest_tso4", _state, _field, VIRTIO_NET_F_GUEST_TSO4, true), \
-        DEFINE_PROP_BIT("guest_tso6", _state, _field, VIRTIO_NET_F_GUEST_TSO6, true), \
-        DEFINE_PROP_BIT("guest_ecn", _state, _field, VIRTIO_NET_F_GUEST_ECN, true), \
-        DEFINE_PROP_BIT("guest_ufo", _state, _field, VIRTIO_NET_F_GUEST_UFO, true), \
-        DEFINE_PROP_BIT("host_tso4", _state, _field, VIRTIO_NET_F_HOST_TSO4, true), \
-        DEFINE_PROP_BIT("host_tso6", _state, _field, VIRTIO_NET_F_HOST_TSO6, true), \
-        DEFINE_PROP_BIT("host_ecn", _state, _field, VIRTIO_NET_F_HOST_ECN, true), \
-        DEFINE_PROP_BIT("host_ufo", _state, _field, VIRTIO_NET_F_HOST_UFO, true), \
-        DEFINE_PROP_BIT("mrg_rxbuf", _state, _field, VIRTIO_NET_F_MRG_RXBUF, true), \
-        DEFINE_PROP_BIT("status", _state, _field, VIRTIO_NET_F_STATUS, true), \
-        DEFINE_PROP_BIT("ctrl_vq", _state, _field, VIRTIO_NET_F_CTRL_VQ, true), \
-        DEFINE_PROP_BIT("ctrl_rx", _state, _field, VIRTIO_NET_F_CTRL_RX, true), \
-        DEFINE_PROP_BIT("ctrl_vlan", _state, _field, VIRTIO_NET_F_CTRL_VLAN, true), \
-        DEFINE_PROP_BIT("ctrl_rx_extra", _state, _field, VIRTIO_NET_F_CTRL_RX_EXTRA, true), \
-        DEFINE_PROP_BIT("ctrl_mac_addr", _state, _field, VIRTIO_NET_F_CTRL_MAC_ADDR, true), \
-        DEFINE_PROP_BIT("mq", _state, _field, VIRTIO_NET_F_MQ, false)
-
-#endif
diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c
deleted file mode 100644 (file)
index fb20722..0000000
+++ /dev/null
@@ -1,1514 +0,0 @@
-/*
- * Virtio PCI Bindings
- *
- * Copyright IBM, Corp. 2007
- * Copyright (c) 2009 CodeSourcery
- *
- * Authors:
- *  Anthony Liguori   <aliguori@us.ibm.com>
- *  Paul Brook        <paul@codesourcery.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 <inttypes.h>
-
-#include "hw/virtio.h"
-#include "hw/virtio-blk.h"
-#include "hw/virtio-net.h"
-#include "hw/virtio-serial.h"
-#include "hw/virtio-scsi.h"
-#include "hw/virtio-balloon.h"
-#include "hw/pci/pci.h"
-#include "qemu/error-report.h"
-#include "hw/pci/msi.h"
-#include "hw/pci/msix.h"
-#include "hw/loader.h"
-#include "sysemu/kvm.h"
-#include "sysemu/blockdev.h"
-#include "hw/virtio-pci.h"
-#include "qemu/range.h"
-#include "hw/virtio-bus.h"
-
-/* from Linux's linux/virtio_pci.h */
-
-/* A 32-bit r/o bitmask of the features supported by the host */
-#define VIRTIO_PCI_HOST_FEATURES        0
-
-/* A 32-bit r/w bitmask of features activated by the guest */
-#define VIRTIO_PCI_GUEST_FEATURES       4
-
-/* A 32-bit r/w PFN for the currently selected queue */
-#define VIRTIO_PCI_QUEUE_PFN            8
-
-/* A 16-bit r/o queue size for the currently selected queue */
-#define VIRTIO_PCI_QUEUE_NUM            12
-
-/* A 16-bit r/w queue selector */
-#define VIRTIO_PCI_QUEUE_SEL            14
-
-/* A 16-bit r/w queue notifier */
-#define VIRTIO_PCI_QUEUE_NOTIFY         16
-
-/* An 8-bit device status register.  */
-#define VIRTIO_PCI_STATUS               18
-
-/* An 8-bit r/o interrupt status register.  Reading the value will return the
- * current contents of the ISR and will also clear it.  This is effectively
- * a read-and-acknowledge. */
-#define VIRTIO_PCI_ISR                  19
-
-/* MSI-X registers: only enabled if MSI-X is enabled. */
-/* A 16-bit vector for configuration changes. */
-#define VIRTIO_MSI_CONFIG_VECTOR        20
-/* A 16-bit vector for selected queue notifications. */
-#define VIRTIO_MSI_QUEUE_VECTOR         22
-
-/* Config space size */
-#define VIRTIO_PCI_CONFIG_NOMSI         20
-#define VIRTIO_PCI_CONFIG_MSI           24
-#define VIRTIO_PCI_REGION_SIZE(dev)     (msix_present(dev) ? \
-                                         VIRTIO_PCI_CONFIG_MSI : \
-                                         VIRTIO_PCI_CONFIG_NOMSI)
-
-/* The remaining space is defined by each driver as the per-driver
- * configuration space */
-#define VIRTIO_PCI_CONFIG(dev)          (msix_enabled(dev) ? \
-                                         VIRTIO_PCI_CONFIG_MSI : \
-                                         VIRTIO_PCI_CONFIG_NOMSI)
-
-/* How many bits to shift physical queue address written to QUEUE_PFN.
- * 12 is historical, and due to x86 page size. */
-#define VIRTIO_PCI_QUEUE_ADDR_SHIFT    12
-
-/* Flags track per-device state like workarounds for quirks in older guests. */
-#define VIRTIO_PCI_FLAG_BUS_MASTER_BUG  (1 << 0)
-
-/* QEMU doesn't strictly need write barriers since everything runs in
- * lock-step.  We'll leave the calls to wmb() in though to make it obvious for
- * KVM or if kqemu gets SMP support.
- */
-#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 */
-/* DeviceState to VirtIOPCIProxy. For use off data-path. TODO: use QOM. */
-static inline VirtIOPCIProxy *to_virtio_pci_proxy(DeviceState *d)
-{
-    return container_of(d, VirtIOPCIProxy, pci_dev.qdev);
-}
-
-/* DeviceState to VirtIOPCIProxy. Note: used on datapath,
- * be careful and test performance if you change this.
- */
-static inline VirtIOPCIProxy *to_virtio_pci_proxy_fast(DeviceState *d)
-{
-    return container_of(d, VirtIOPCIProxy, pci_dev.qdev);
-}
-
-static void virtio_pci_notify(DeviceState *d, uint16_t vector)
-{
-    VirtIOPCIProxy *proxy = to_virtio_pci_proxy_fast(d);
-    if (msix_enabled(&proxy->pci_dev))
-        msix_notify(&proxy->pci_dev, vector);
-    else
-        qemu_set_irq(proxy->pci_dev.irq[0], proxy->vdev->isr & 1);
-}
-
-static void virtio_pci_save_config(DeviceState *d, QEMUFile *f)
-{
-    VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
-    pci_device_save(&proxy->pci_dev, f);
-    msix_save(&proxy->pci_dev, f);
-    if (msix_present(&proxy->pci_dev))
-        qemu_put_be16(f, proxy->vdev->config_vector);
-}
-
-static void virtio_pci_save_queue(DeviceState *d, int n, QEMUFile *f)
-{
-    VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
-    if (msix_present(&proxy->pci_dev))
-        qemu_put_be16(f, virtio_queue_vector(proxy->vdev, n));
-}
-
-static int virtio_pci_load_config(DeviceState *d, QEMUFile *f)
-{
-    VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
-    int ret;
-    ret = pci_device_load(&proxy->pci_dev, f);
-    if (ret) {
-        return ret;
-    }
-    msix_unuse_all_vectors(&proxy->pci_dev);
-    msix_load(&proxy->pci_dev, f);
-    if (msix_present(&proxy->pci_dev)) {
-        qemu_get_be16s(f, &proxy->vdev->config_vector);
-    } else {
-        proxy->vdev->config_vector = VIRTIO_NO_VECTOR;
-    }
-    if (proxy->vdev->config_vector != VIRTIO_NO_VECTOR) {
-        return msix_vector_use(&proxy->pci_dev, proxy->vdev->config_vector);
-    }
-    return 0;
-}
-
-static int virtio_pci_load_queue(DeviceState *d, int n, QEMUFile *f)
-{
-    VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
-    uint16_t vector;
-    if (msix_present(&proxy->pci_dev)) {
-        qemu_get_be16s(f, &vector);
-    } else {
-        vector = VIRTIO_NO_VECTOR;
-    }
-    virtio_queue_set_vector(proxy->vdev, n, vector);
-    if (vector != VIRTIO_NO_VECTOR) {
-        return msix_vector_use(&proxy->pci_dev, vector);
-    }
-    return 0;
-}
-
-static int virtio_pci_set_host_notifier_internal(VirtIOPCIProxy *proxy,
-                                                 int n, bool assign, bool set_handler)
-{
-    VirtQueue *vq = virtio_get_queue(proxy->vdev, n);
-    EventNotifier *notifier = virtio_queue_get_host_notifier(vq);
-    int r = 0;
-
-    if (assign) {
-        r = event_notifier_init(notifier, 1);
-        if (r < 0) {
-            error_report("%s: unable to init event notifier: %d",
-                         __func__, r);
-            return r;
-        }
-        virtio_queue_set_host_notifier_fd_handler(vq, true, set_handler);
-        memory_region_add_eventfd(&proxy->bar, VIRTIO_PCI_QUEUE_NOTIFY, 2,
-                                  true, n, notifier);
-    } else {
-        memory_region_del_eventfd(&proxy->bar, VIRTIO_PCI_QUEUE_NOTIFY, 2,
-                                  true, n, notifier);
-        virtio_queue_set_host_notifier_fd_handler(vq, false, false);
-        event_notifier_cleanup(notifier);
-    }
-    return r;
-}
-
-static void virtio_pci_start_ioeventfd(VirtIOPCIProxy *proxy)
-{
-    int n, r;
-
-    if (!(proxy->flags & VIRTIO_PCI_FLAG_USE_IOEVENTFD) ||
-        proxy->ioeventfd_disabled ||
-        proxy->ioeventfd_started) {
-        return;
-    }
-
-    for (n = 0; n < VIRTIO_PCI_QUEUE_MAX; n++) {
-        if (!virtio_queue_get_num(proxy->vdev, n)) {
-            continue;
-        }
-
-        r = virtio_pci_set_host_notifier_internal(proxy, n, true, true);
-        if (r < 0) {
-            goto assign_error;
-        }
-    }
-    proxy->ioeventfd_started = true;
-    return;
-
-assign_error:
-    while (--n >= 0) {
-        if (!virtio_queue_get_num(proxy->vdev, n)) {
-            continue;
-        }
-
-        r = virtio_pci_set_host_notifier_internal(proxy, n, false, false);
-        assert(r >= 0);
-    }
-    proxy->ioeventfd_started = false;
-    error_report("%s: failed. Fallback to a userspace (slower).", __func__);
-}
-
-static void virtio_pci_stop_ioeventfd(VirtIOPCIProxy *proxy)
-{
-    int r;
-    int n;
-
-    if (!proxy->ioeventfd_started) {
-        return;
-    }
-
-    for (n = 0; n < VIRTIO_PCI_QUEUE_MAX; n++) {
-        if (!virtio_queue_get_num(proxy->vdev, n)) {
-            continue;
-        }
-
-        r = virtio_pci_set_host_notifier_internal(proxy, n, false, false);
-        assert(r >= 0);
-    }
-    proxy->ioeventfd_started = false;
-}
-
-static void virtio_pci_reset(DeviceState *d)
-{
-    VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
-    virtio_pci_stop_ioeventfd(proxy);
-    virtio_reset(proxy->vdev);
-    msix_unuse_all_vectors(&proxy->pci_dev);
-    proxy->flags &= ~VIRTIO_PCI_FLAG_BUS_MASTER_BUG;
-}
-
-static void virtio_ioport_write(void *opaque, uint32_t addr, uint32_t val)
-{
-    VirtIOPCIProxy *proxy = opaque;
-    VirtIODevice *vdev = proxy->vdev;
-    hwaddr pa;
-
-    switch (addr) {
-    case VIRTIO_PCI_GUEST_FEATURES:
-       /* Guest does not negotiate properly?  We have to assume nothing. */
-       if (val & (1 << VIRTIO_F_BAD_FEATURE)) {
-            val = vdev->bad_features ? vdev->bad_features(vdev) : 0;
-       }
-        virtio_set_features(vdev, val);
-        break;
-    case VIRTIO_PCI_QUEUE_PFN:
-        pa = (hwaddr)val << VIRTIO_PCI_QUEUE_ADDR_SHIFT;
-        if (pa == 0) {
-            virtio_pci_stop_ioeventfd(proxy);
-            virtio_reset(proxy->vdev);
-            msix_unuse_all_vectors(&proxy->pci_dev);
-        }
-        else
-            virtio_queue_set_addr(vdev, vdev->queue_sel, pa);
-        break;
-    case VIRTIO_PCI_QUEUE_SEL:
-        if (val < VIRTIO_PCI_QUEUE_MAX)
-            vdev->queue_sel = val;
-        break;
-    case VIRTIO_PCI_QUEUE_NOTIFY:
-        if (val < VIRTIO_PCI_QUEUE_MAX) {
-            virtio_queue_notify(vdev, val);
-        }
-        break;
-    case VIRTIO_PCI_STATUS:
-        if (!(val & VIRTIO_CONFIG_S_DRIVER_OK)) {
-            virtio_pci_stop_ioeventfd(proxy);
-        }
-
-        virtio_set_status(vdev, val & 0xFF);
-
-        if (val & VIRTIO_CONFIG_S_DRIVER_OK) {
-            virtio_pci_start_ioeventfd(proxy);
-        }
-
-        if (vdev->status == 0) {
-            virtio_reset(proxy->vdev);
-            msix_unuse_all_vectors(&proxy->pci_dev);
-        }
-
-        /* Linux before 2.6.34 sets the device as OK without enabling
-           the PCI device bus master bit. In this case we need to disable
-           some safety checks. */
-        if ((val & VIRTIO_CONFIG_S_DRIVER_OK) &&
-            !(proxy->pci_dev.config[PCI_COMMAND] & PCI_COMMAND_MASTER)) {
-            proxy->flags |= VIRTIO_PCI_FLAG_BUS_MASTER_BUG;
-        }
-        break;
-    case VIRTIO_MSI_CONFIG_VECTOR:
-        msix_vector_unuse(&proxy->pci_dev, vdev->config_vector);
-        /* Make it possible for guest to discover an error took place. */
-        if (msix_vector_use(&proxy->pci_dev, val) < 0)
-            val = VIRTIO_NO_VECTOR;
-        vdev->config_vector = val;
-        break;
-    case VIRTIO_MSI_QUEUE_VECTOR:
-        msix_vector_unuse(&proxy->pci_dev,
-                          virtio_queue_vector(vdev, vdev->queue_sel));
-        /* Make it possible for guest to discover an error took place. */
-        if (msix_vector_use(&proxy->pci_dev, val) < 0)
-            val = VIRTIO_NO_VECTOR;
-        virtio_queue_set_vector(vdev, vdev->queue_sel, val);
-        break;
-    default:
-        error_report("%s: unexpected address 0x%x value 0x%x",
-                     __func__, addr, val);
-        break;
-    }
-}
-
-static uint32_t virtio_ioport_read(VirtIOPCIProxy *proxy, uint32_t addr)
-{
-    VirtIODevice *vdev = proxy->vdev;
-    uint32_t ret = 0xFFFFFFFF;
-
-    switch (addr) {
-    case VIRTIO_PCI_HOST_FEATURES:
-        ret = proxy->host_features;
-        break;
-    case VIRTIO_PCI_GUEST_FEATURES:
-        ret = vdev->guest_features;
-        break;
-    case VIRTIO_PCI_QUEUE_PFN:
-        ret = virtio_queue_get_addr(vdev, vdev->queue_sel)
-              >> VIRTIO_PCI_QUEUE_ADDR_SHIFT;
-        break;
-    case VIRTIO_PCI_QUEUE_NUM:
-        ret = virtio_queue_get_num(vdev, vdev->queue_sel);
-        break;
-    case VIRTIO_PCI_QUEUE_SEL:
-        ret = vdev->queue_sel;
-        break;
-    case VIRTIO_PCI_STATUS:
-        ret = vdev->status;
-        break;
-    case VIRTIO_PCI_ISR:
-        /* reading from the ISR also clears it. */
-        ret = vdev->isr;
-        vdev->isr = 0;
-        qemu_set_irq(proxy->pci_dev.irq[0], 0);
-        break;
-    case VIRTIO_MSI_CONFIG_VECTOR:
-        ret = vdev->config_vector;
-        break;
-    case VIRTIO_MSI_QUEUE_VECTOR:
-        ret = virtio_queue_vector(vdev, vdev->queue_sel);
-        break;
-    default:
-        break;
-    }
-
-    return ret;
-}
-
-static uint64_t virtio_pci_config_read(void *opaque, hwaddr addr,
-                                       unsigned size)
-{
-    VirtIOPCIProxy *proxy = opaque;
-    uint32_t config = VIRTIO_PCI_CONFIG(&proxy->pci_dev);
-    uint64_t val = 0;
-    if (addr < config) {
-        return virtio_ioport_read(proxy, addr);
-    }
-    addr -= config;
-
-    switch (size) {
-    case 1:
-        val = virtio_config_readb(proxy->vdev, addr);
-        break;
-    case 2:
-        val = virtio_config_readw(proxy->vdev, addr);
-        if (virtio_is_big_endian()) {
-            val = bswap16(val);
-        }
-        break;
-    case 4:
-        val = virtio_config_readl(proxy->vdev, addr);
-        if (virtio_is_big_endian()) {
-            val = bswap32(val);
-        }
-        break;
-    }
-    return val;
-}
-
-static void virtio_pci_config_write(void *opaque, hwaddr addr,
-                                    uint64_t val, unsigned size)
-{
-    VirtIOPCIProxy *proxy = opaque;
-    uint32_t config = VIRTIO_PCI_CONFIG(&proxy->pci_dev);
-    if (addr < config) {
-        virtio_ioport_write(proxy, addr, val);
-        return;
-    }
-    addr -= config;
-    /*
-     * Virtio-PCI is odd. Ioports are LE but config space is target native
-     * endian.
-     */
-    switch (size) {
-    case 1:
-        virtio_config_writeb(proxy->vdev, addr, val);
-        break;
-    case 2:
-        if (virtio_is_big_endian()) {
-            val = bswap16(val);
-        }
-        virtio_config_writew(proxy->vdev, addr, val);
-        break;
-    case 4:
-        if (virtio_is_big_endian()) {
-            val = bswap32(val);
-        }
-        virtio_config_writel(proxy->vdev, addr, val);
-        break;
-    }
-}
-
-static const MemoryRegionOps virtio_pci_config_ops = {
-    .read = virtio_pci_config_read,
-    .write = virtio_pci_config_write,
-    .impl = {
-        .min_access_size = 1,
-        .max_access_size = 4,
-    },
-    .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static void virtio_write_config(PCIDevice *pci_dev, uint32_t address,
-                                uint32_t val, int len)
-{
-    VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
-
-    pci_default_write_config(pci_dev, address, val, len);
-
-    if (range_covers_byte(address, len, PCI_COMMAND) &&
-        !(pci_dev->config[PCI_COMMAND] & PCI_COMMAND_MASTER) &&
-        !(proxy->flags & VIRTIO_PCI_FLAG_BUS_MASTER_BUG)) {
-        virtio_pci_stop_ioeventfd(proxy);
-        virtio_set_status(proxy->vdev,
-                          proxy->vdev->status & ~VIRTIO_CONFIG_S_DRIVER_OK);
-    }
-}
-
-static unsigned virtio_pci_get_features(DeviceState *d)
-{
-    VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
-    return proxy->host_features;
-}
-
-static int kvm_virtio_pci_vq_vector_use(VirtIOPCIProxy *proxy,
-                                        unsigned int queue_no,
-                                        unsigned int vector,
-                                        MSIMessage msg)
-{
-    VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector];
-    int ret;
-
-    if (irqfd->users == 0) {
-        ret = kvm_irqchip_add_msi_route(kvm_state, msg);
-        if (ret < 0) {
-            return ret;
-        }
-        irqfd->virq = ret;
-    }
-    irqfd->users++;
-    return 0;
-}
-
-static void kvm_virtio_pci_vq_vector_release(VirtIOPCIProxy *proxy,
-                                             unsigned int vector)
-{
-    VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector];
-    if (--irqfd->users == 0) {
-        kvm_irqchip_release_virq(kvm_state, irqfd->virq);
-    }
-}
-
-static int kvm_virtio_pci_irqfd_use(VirtIOPCIProxy *proxy,
-                                 unsigned int queue_no,
-                                 unsigned int vector)
-{
-    VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector];
-    VirtQueue *vq = virtio_get_queue(proxy->vdev, queue_no);
-    EventNotifier *n = virtio_queue_get_guest_notifier(vq);
-    int ret;
-    ret = kvm_irqchip_add_irqfd_notifier(kvm_state, n, irqfd->virq);
-    return ret;
-}
-
-static void kvm_virtio_pci_irqfd_release(VirtIOPCIProxy *proxy,
-                                      unsigned int queue_no,
-                                      unsigned int vector)
-{
-    VirtQueue *vq = virtio_get_queue(proxy->vdev, queue_no);
-    EventNotifier *n = virtio_queue_get_guest_notifier(vq);
-    VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector];
-    int ret;
-
-    ret = kvm_irqchip_remove_irqfd_notifier(kvm_state, n, irqfd->virq);
-    assert(ret == 0);
-}
-
-static int kvm_virtio_pci_vector_use(VirtIOPCIProxy *proxy, int nvqs)
-{
-    PCIDevice *dev = &proxy->pci_dev;
-    VirtIODevice *vdev = proxy->vdev;
-    unsigned int vector;
-    int ret, queue_no;
-    MSIMessage msg;
-
-    for (queue_no = 0; queue_no < nvqs; queue_no++) {
-        if (!virtio_queue_get_num(vdev, queue_no)) {
-            break;
-        }
-        vector = virtio_queue_vector(vdev, queue_no);
-        if (vector >= msix_nr_vectors_allocated(dev)) {
-            continue;
-        }
-        msg = msix_get_message(dev, vector);
-        ret = kvm_virtio_pci_vq_vector_use(proxy, queue_no, vector, msg);
-        if (ret < 0) {
-            goto undo;
-        }
-        /* If guest supports masking, set up irqfd now.
-         * Otherwise, delay until unmasked in the frontend.
-         */
-        if (proxy->vdev->guest_notifier_mask) {
-            ret = kvm_virtio_pci_irqfd_use(proxy, queue_no, vector);
-            if (ret < 0) {
-                kvm_virtio_pci_vq_vector_release(proxy, vector);
-                goto undo;
-            }
-        }
-    }
-    return 0;
-
-undo:
-    while (--queue_no >= 0) {
-        vector = virtio_queue_vector(vdev, queue_no);
-        if (vector >= msix_nr_vectors_allocated(dev)) {
-            continue;
-        }
-        if (proxy->vdev->guest_notifier_mask) {
-            kvm_virtio_pci_irqfd_release(proxy, queue_no, vector);
-        }
-        kvm_virtio_pci_vq_vector_release(proxy, vector);
-    }
-    return ret;
-}
-
-static void kvm_virtio_pci_vector_release(VirtIOPCIProxy *proxy, int nvqs)
-{
-    PCIDevice *dev = &proxy->pci_dev;
-    VirtIODevice *vdev = proxy->vdev;
-    unsigned int vector;
-    int queue_no;
-
-    for (queue_no = 0; queue_no < nvqs; queue_no++) {
-        if (!virtio_queue_get_num(vdev, queue_no)) {
-            break;
-        }
-        vector = virtio_queue_vector(vdev, queue_no);
-        if (vector >= msix_nr_vectors_allocated(dev)) {
-            continue;
-        }
-        /* If guest supports masking, clean up irqfd now.
-         * Otherwise, it was cleaned when masked in the frontend.
-         */
-        if (proxy->vdev->guest_notifier_mask) {
-            kvm_virtio_pci_irqfd_release(proxy, queue_no, vector);
-        }
-        kvm_virtio_pci_vq_vector_release(proxy, vector);
-    }
-}
-
-static int virtio_pci_vq_vector_unmask(VirtIOPCIProxy *proxy,
-                                       unsigned int queue_no,
-                                       unsigned int vector,
-                                       MSIMessage msg)
-{
-    VirtQueue *vq = virtio_get_queue(proxy->vdev, queue_no);
-    EventNotifier *n = virtio_queue_get_guest_notifier(vq);
-    VirtIOIRQFD *irqfd;
-    int ret = 0;
-
-    if (proxy->vector_irqfd) {
-        irqfd = &proxy->vector_irqfd[vector];
-        if (irqfd->msg.data != msg.data || irqfd->msg.address != msg.address) {
-            ret = kvm_irqchip_update_msi_route(kvm_state, irqfd->virq, msg);
-            if (ret < 0) {
-                return ret;
-            }
-        }
-    }
-
-    /* If guest supports masking, irqfd is already setup, unmask it.
-     * Otherwise, set it up now.
-     */
-    if (proxy->vdev->guest_notifier_mask) {
-        proxy->vdev->guest_notifier_mask(proxy->vdev, queue_no, false);
-        /* Test after unmasking to avoid losing events. */
-        if (proxy->vdev->guest_notifier_pending &&
-            proxy->vdev->guest_notifier_pending(proxy->vdev, queue_no)) {
-            event_notifier_set(n);
-        }
-    } else {
-        ret = kvm_virtio_pci_irqfd_use(proxy, queue_no, vector);
-    }
-    return ret;
-}
-
-static void virtio_pci_vq_vector_mask(VirtIOPCIProxy *proxy,
-                                             unsigned int queue_no,
-                                             unsigned int vector)
-{
-    /* If guest supports masking, keep irqfd but mask it.
-     * Otherwise, clean it up now.
-     */ 
-    if (proxy->vdev->guest_notifier_mask) {
-        proxy->vdev->guest_notifier_mask(proxy->vdev, queue_no, true);
-    } else {
-        kvm_virtio_pci_irqfd_release(proxy, queue_no, vector);
-    }
-}
-
-static int virtio_pci_vector_unmask(PCIDevice *dev, unsigned vector,
-                                    MSIMessage msg)
-{
-    VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev);
-    VirtIODevice *vdev = proxy->vdev;
-    int ret, queue_no;
-
-    for (queue_no = 0; queue_no < proxy->nvqs_with_notifiers; queue_no++) {
-        if (!virtio_queue_get_num(vdev, queue_no)) {
-            break;
-        }
-        if (virtio_queue_vector(vdev, queue_no) != vector) {
-            continue;
-        }
-        ret = virtio_pci_vq_vector_unmask(proxy, queue_no, vector, msg);
-        if (ret < 0) {
-            goto undo;
-        }
-    }
-    return 0;
-
-undo:
-    while (--queue_no >= 0) {
-        if (virtio_queue_vector(vdev, queue_no) != vector) {
-            continue;
-        }
-        virtio_pci_vq_vector_mask(proxy, queue_no, vector);
-    }
-    return ret;
-}
-
-static void virtio_pci_vector_mask(PCIDevice *dev, unsigned vector)
-{
-    VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev);
-    VirtIODevice *vdev = proxy->vdev;
-    int queue_no;
-
-    for (queue_no = 0; queue_no < proxy->nvqs_with_notifiers; queue_no++) {
-        if (!virtio_queue_get_num(vdev, queue_no)) {
-            break;
-        }
-        if (virtio_queue_vector(vdev, queue_no) != vector) {
-            continue;
-        }
-        virtio_pci_vq_vector_mask(proxy, queue_no, vector);
-    }
-}
-
-static void virtio_pci_vector_poll(PCIDevice *dev,
-                                   unsigned int vector_start,
-                                   unsigned int vector_end)
-{
-    VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev);
-    VirtIODevice *vdev = proxy->vdev;
-    int queue_no;
-    unsigned int vector;
-    EventNotifier *notifier;
-    VirtQueue *vq;
-
-    for (queue_no = 0; queue_no < proxy->nvqs_with_notifiers; queue_no++) {
-        if (!virtio_queue_get_num(vdev, queue_no)) {
-            break;
-        }
-        vector = virtio_queue_vector(vdev, queue_no);
-        if (vector < vector_start || vector >= vector_end ||
-            !msix_is_masked(dev, vector)) {
-            continue;
-        }
-        vq = virtio_get_queue(vdev, queue_no);
-        notifier = virtio_queue_get_guest_notifier(vq);
-        if (vdev->guest_notifier_pending) {
-            if (vdev->guest_notifier_pending(vdev, queue_no)) {
-                msix_set_pending(dev, vector);
-            }
-        } else if (event_notifier_test_and_clear(notifier)) {
-            msix_set_pending(dev, vector);
-        }
-    }
-}
-
-static int virtio_pci_set_guest_notifier(DeviceState *d, int n, bool assign,
-                                         bool with_irqfd)
-{
-    VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
-    VirtQueue *vq = virtio_get_queue(proxy->vdev, n);
-    EventNotifier *notifier = virtio_queue_get_guest_notifier(vq);
-
-    if (assign) {
-        int r = event_notifier_init(notifier, 0);
-        if (r < 0) {
-            return r;
-        }
-        virtio_queue_set_guest_notifier_fd_handler(vq, true, with_irqfd);
-    } else {
-        virtio_queue_set_guest_notifier_fd_handler(vq, false, with_irqfd);
-        event_notifier_cleanup(notifier);
-    }
-
-    return 0;
-}
-
-static bool virtio_pci_query_guest_notifiers(DeviceState *d)
-{
-    VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
-    return msix_enabled(&proxy->pci_dev);
-}
-
-static int virtio_pci_set_guest_notifiers(DeviceState *d, int nvqs, bool assign)
-{
-    VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
-    VirtIODevice *vdev = proxy->vdev;
-    int r, n;
-    bool with_irqfd = msix_enabled(&proxy->pci_dev) &&
-        kvm_msi_via_irqfd_enabled();
-
-    nvqs = MIN(nvqs, VIRTIO_PCI_QUEUE_MAX);
-
-    /* When deassigning, pass a consistent nvqs value
-     * to avoid leaking notifiers.
-     */
-    assert(assign || nvqs == proxy->nvqs_with_notifiers);
-
-    proxy->nvqs_with_notifiers = nvqs;
-
-    /* Must unset vector notifier while guest notifier is still assigned */
-    if ((proxy->vector_irqfd || vdev->guest_notifier_mask) && !assign) {
-        msix_unset_vector_notifiers(&proxy->pci_dev);
-        if (proxy->vector_irqfd) {
-            kvm_virtio_pci_vector_release(proxy, nvqs);
-            g_free(proxy->vector_irqfd);
-            proxy->vector_irqfd = NULL;
-        }
-    }
-
-    for (n = 0; n < nvqs; n++) {
-        if (!virtio_queue_get_num(vdev, n)) {
-            break;
-        }
-
-        r = virtio_pci_set_guest_notifier(d, n, assign,
-                                          kvm_msi_via_irqfd_enabled());
-        if (r < 0) {
-            goto assign_error;
-        }
-    }
-
-    /* Must set vector notifier after guest notifier has been assigned */
-    if ((with_irqfd || vdev->guest_notifier_mask) && assign) {
-        if (with_irqfd) {
-            proxy->vector_irqfd =
-                g_malloc0(sizeof(*proxy->vector_irqfd) *
-                          msix_nr_vectors_allocated(&proxy->pci_dev));
-            r = kvm_virtio_pci_vector_use(proxy, nvqs);
-            if (r < 0) {
-                goto assign_error;
-            }
-        }
-        r = msix_set_vector_notifiers(&proxy->pci_dev,
-                                      virtio_pci_vector_unmask,
-                                      virtio_pci_vector_mask,
-                                      virtio_pci_vector_poll);
-        if (r < 0) {
-            goto notifiers_error;
-        }
-    }
-
-    return 0;
-
-notifiers_error:
-    if (with_irqfd) {
-        assert(assign);
-        kvm_virtio_pci_vector_release(proxy, nvqs);
-    }
-
-assign_error:
-    /* We get here on assignment failure. Recover by undoing for VQs 0 .. n. */
-    assert(assign);
-    while (--n >= 0) {
-        virtio_pci_set_guest_notifier(d, n, !assign, with_irqfd);
-    }
-    return r;
-}
-
-static int virtio_pci_set_host_notifier(DeviceState *d, int n, bool assign)
-{
-    VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
-
-    /* Stop using ioeventfd for virtqueue kick if the device starts using host
-     * notifiers.  This makes it easy to avoid stepping on each others' toes.
-     */
-    proxy->ioeventfd_disabled = assign;
-    if (assign) {
-        virtio_pci_stop_ioeventfd(proxy);
-    }
-    /* We don't need to start here: it's not needed because backend
-     * currently only stops on status change away from ok,
-     * reset, vmstop and such. If we do add code to start here,
-     * need to check vmstate, device state etc. */
-    return virtio_pci_set_host_notifier_internal(proxy, n, assign, false);
-}
-
-static void virtio_pci_vmstate_change(DeviceState *d, bool running)
-{
-    VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
-
-    if (running) {
-        /* Try to find out if the guest has bus master disabled, but is
-           in ready state. Then we have a buggy guest OS. */
-        if ((proxy->vdev->status & VIRTIO_CONFIG_S_DRIVER_OK) &&
-            !(proxy->pci_dev.config[PCI_COMMAND] & PCI_COMMAND_MASTER)) {
-            proxy->flags |= VIRTIO_PCI_FLAG_BUS_MASTER_BUG;
-        }
-        virtio_pci_start_ioeventfd(proxy);
-    } else {
-        virtio_pci_stop_ioeventfd(proxy);
-    }
-}
-
-static const VirtIOBindings virtio_pci_bindings = {
-    .notify = virtio_pci_notify,
-    .save_config = virtio_pci_save_config,
-    .load_config = virtio_pci_load_config,
-    .save_queue = virtio_pci_save_queue,
-    .load_queue = virtio_pci_load_queue,
-    .get_features = virtio_pci_get_features,
-    .query_guest_notifiers = virtio_pci_query_guest_notifiers,
-    .set_host_notifier = virtio_pci_set_host_notifier,
-    .set_guest_notifiers = virtio_pci_set_guest_notifiers,
-    .vmstate_change = virtio_pci_vmstate_change,
-};
-
-void virtio_init_pci(VirtIOPCIProxy *proxy, VirtIODevice *vdev)
-{
-    uint8_t *config;
-    uint32_t size;
-
-    proxy->vdev = vdev;
-
-    config = proxy->pci_dev.config;
-
-    if (proxy->class_code) {
-        pci_config_set_class(config, proxy->class_code);
-    }
-    pci_set_word(config + PCI_SUBSYSTEM_VENDOR_ID,
-                 pci_get_word(config + PCI_VENDOR_ID));
-    pci_set_word(config + PCI_SUBSYSTEM_ID, vdev->device_id);
-    config[PCI_INTERRUPT_PIN] = 1;
-
-    if (vdev->nvectors &&
-        msix_init_exclusive_bar(&proxy->pci_dev, vdev->nvectors, 1)) {
-        vdev->nvectors = 0;
-    }
-
-    proxy->pci_dev.config_write = virtio_write_config;
-
-    size = VIRTIO_PCI_REGION_SIZE(&proxy->pci_dev) + vdev->config_len;
-    if (size & (size-1))
-        size = 1 << qemu_fls(size);
-
-    memory_region_init_io(&proxy->bar, &virtio_pci_config_ops, proxy,
-                          "virtio-pci", size);
-    pci_register_bar(&proxy->pci_dev, 0, PCI_BASE_ADDRESS_SPACE_IO,
-                     &proxy->bar);
-
-    if (!kvm_has_many_ioeventfds()) {
-        proxy->flags &= ~VIRTIO_PCI_FLAG_USE_IOEVENTFD;
-    }
-
-    virtio_bind_device(vdev, &virtio_pci_bindings, DEVICE(proxy));
-    proxy->host_features |= 0x1 << VIRTIO_F_NOTIFY_ON_EMPTY;
-    proxy->host_features |= 0x1 << VIRTIO_F_BAD_FEATURE;
-    proxy->host_features = vdev->get_features(vdev, proxy->host_features);
-}
-
-static void virtio_exit_pci(PCIDevice *pci_dev)
-{
-    VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
-
-    memory_region_destroy(&proxy->bar);
-    msix_uninit_exclusive_bar(pci_dev);
-}
-
-static int virtio_serial_init_pci(PCIDevice *pci_dev)
-{
-    VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
-    VirtIODevice *vdev;
-
-    if (proxy->class_code != PCI_CLASS_COMMUNICATION_OTHER &&
-        proxy->class_code != PCI_CLASS_DISPLAY_OTHER && /* qemu 0.10 */
-        proxy->class_code != PCI_CLASS_OTHERS)          /* qemu-kvm  */
-        proxy->class_code = PCI_CLASS_COMMUNICATION_OTHER;
-
-    vdev = virtio_serial_init(&pci_dev->qdev, &proxy->serial);
-    if (!vdev) {
-        return -1;
-    }
-
-    /* backwards-compatibility with machines that were created with
-       DEV_NVECTORS_UNSPECIFIED */
-    vdev->nvectors = proxy->nvectors == DEV_NVECTORS_UNSPECIFIED
-                                        ? proxy->serial.max_virtserial_ports + 1
-                                        : proxy->nvectors;
-    virtio_init_pci(proxy, vdev);
-    proxy->nvectors = vdev->nvectors;
-    return 0;
-}
-
-static void virtio_serial_exit_pci(PCIDevice *pci_dev)
-{
-    VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
-
-    virtio_pci_stop_ioeventfd(proxy);
-    virtio_serial_exit(proxy->vdev);
-    virtio_exit_pci(pci_dev);
-}
-
-static int virtio_net_init_pci(PCIDevice *pci_dev)
-{
-    VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
-    VirtIODevice *vdev;
-
-    vdev = virtio_net_init(&pci_dev->qdev, &proxy->nic, &proxy->net,
-                           proxy->host_features);
-
-    vdev->nvectors = proxy->nvectors;
-    virtio_init_pci(proxy, vdev);
-
-    /* make the actual value visible */
-    proxy->nvectors = vdev->nvectors;
-    return 0;
-}
-
-static void virtio_net_exit_pci(PCIDevice *pci_dev)
-{
-    VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
-
-    virtio_pci_stop_ioeventfd(proxy);
-    virtio_net_exit(proxy->vdev);
-    virtio_exit_pci(pci_dev);
-}
-
-static int virtio_rng_init_pci(PCIDevice *pci_dev)
-{
-    VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
-    VirtIODevice *vdev;
-
-    if (proxy->rng.rng == NULL) {
-        proxy->rng.default_backend = RNG_RANDOM(object_new(TYPE_RNG_RANDOM));
-
-        object_property_add_child(OBJECT(pci_dev),
-                                  "default-backend",
-                                  OBJECT(proxy->rng.default_backend),
-                                  NULL);
-
-        object_property_set_link(OBJECT(pci_dev),
-                                 OBJECT(proxy->rng.default_backend),
-                                 "rng", NULL);
-    }
-
-    vdev = virtio_rng_init(&pci_dev->qdev, &proxy->rng);
-    if (!vdev) {
-        return -1;
-    }
-    virtio_init_pci(proxy, vdev);
-    return 0;
-}
-
-static void virtio_rng_exit_pci(PCIDevice *pci_dev)
-{
-    VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
-
-    virtio_pci_stop_ioeventfd(proxy);
-    virtio_rng_exit(proxy->vdev);
-    virtio_exit_pci(pci_dev);
-}
-
-static Property virtio_net_properties[] = {
-    DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, false),
-    DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 3),
-    DEFINE_VIRTIO_NET_FEATURES(VirtIOPCIProxy, host_features),
-    DEFINE_NIC_PROPERTIES(VirtIOPCIProxy, nic),
-    DEFINE_PROP_UINT32("x-txtimer", VirtIOPCIProxy, net.txtimer, TX_TIMER_INTERVAL),
-    DEFINE_PROP_INT32("x-txburst", VirtIOPCIProxy, net.txburst, TX_BURST),
-    DEFINE_PROP_STRING("tx", VirtIOPCIProxy, net.tx),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void virtio_net_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
-    k->init = virtio_net_init_pci;
-    k->exit = virtio_net_exit_pci;
-    k->romfile = "efi-virtio.rom";
-    k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
-    k->device_id = PCI_DEVICE_ID_VIRTIO_NET;
-    k->revision = VIRTIO_PCI_ABI_VERSION;
-    k->class_id = PCI_CLASS_NETWORK_ETHERNET;
-    dc->reset = virtio_pci_reset;
-    dc->props = virtio_net_properties;
-}
-
-static const TypeInfo virtio_net_info = {
-    .name          = "virtio-net-pci",
-    .parent        = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(VirtIOPCIProxy),
-    .class_init    = virtio_net_class_init,
-};
-
-static Property virtio_serial_properties[] = {
-    DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
-    DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
-    DEFINE_PROP_HEX32("class", VirtIOPCIProxy, class_code, 0),
-    DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
-    DEFINE_PROP_UINT32("max_ports", VirtIOPCIProxy, serial.max_virtserial_ports, 31),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void virtio_serial_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
-    k->init = virtio_serial_init_pci;
-    k->exit = virtio_serial_exit_pci;
-    k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
-    k->device_id = PCI_DEVICE_ID_VIRTIO_CONSOLE;
-    k->revision = VIRTIO_PCI_ABI_VERSION;
-    k->class_id = PCI_CLASS_COMMUNICATION_OTHER;
-    dc->reset = virtio_pci_reset;
-    dc->props = virtio_serial_properties;
-}
-
-static const TypeInfo virtio_serial_info = {
-    .name          = "virtio-serial-pci",
-    .parent        = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(VirtIOPCIProxy),
-    .class_init    = virtio_serial_class_init,
-};
-
-static void virtio_rng_initfn(Object *obj)
-{
-    PCIDevice *pci_dev = PCI_DEVICE(obj);
-    VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
-
-    object_property_add_link(obj, "rng", TYPE_RNG_BACKEND,
-                             (Object **)&proxy->rng.rng, NULL);
-}
-
-static Property virtio_rng_properties[] = {
-    DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
-    /* Set a default rate limit of 2^47 bytes per minute or roughly 2TB/s.  If
-       you have an entropy source capable of generating more entropy than this
-       and you can pass it through via virtio-rng, then hats off to you.  Until
-       then, this is unlimited for all practical purposes.
-    */
-    DEFINE_PROP_UINT64("max-bytes", VirtIOPCIProxy, rng.max_bytes, INT64_MAX),
-    DEFINE_PROP_UINT32("period", VirtIOPCIProxy, rng.period_ms, 1 << 16),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void virtio_rng_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
-    k->init = virtio_rng_init_pci;
-    k->exit = virtio_rng_exit_pci;
-    k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
-    k->device_id = PCI_DEVICE_ID_VIRTIO_RNG;
-    k->revision = VIRTIO_PCI_ABI_VERSION;
-    k->class_id = PCI_CLASS_OTHERS;
-    dc->reset = virtio_pci_reset;
-    dc->props = virtio_rng_properties;
-}
-
-static const TypeInfo virtio_rng_info = {
-    .name          = "virtio-rng-pci",
-    .parent        = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(VirtIOPCIProxy),
-    .instance_init = virtio_rng_initfn,
-    .class_init    = virtio_rng_class_init,
-};
-
-#ifdef CONFIG_VIRTFS
-static int virtio_9p_init_pci(PCIDevice *pci_dev)
-{
-    VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
-    VirtIODevice *vdev;
-
-    vdev = virtio_9p_init(&pci_dev->qdev, &proxy->fsconf);
-    vdev->nvectors = proxy->nvectors;
-    virtio_init_pci(proxy, vdev);
-    /* make the actual value visible */
-    proxy->nvectors = vdev->nvectors;
-    return 0;
-}
-
-static Property virtio_9p_properties[] = {
-    DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
-    DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
-    DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
-    DEFINE_PROP_STRING("mount_tag", VirtIOPCIProxy, fsconf.tag),
-    DEFINE_PROP_STRING("fsdev", VirtIOPCIProxy, fsconf.fsdev_id),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void virtio_9p_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
-    k->init = virtio_9p_init_pci;
-    k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
-    k->device_id = PCI_DEVICE_ID_VIRTIO_9P;
-    k->revision = VIRTIO_PCI_ABI_VERSION;
-    k->class_id = 0x2;
-    dc->props = virtio_9p_properties;
-    dc->reset = virtio_pci_reset;
-}
-
-static const TypeInfo virtio_9p_info = {
-    .name          = "virtio-9p-pci",
-    .parent        = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(VirtIOPCIProxy),
-    .class_init    = virtio_9p_class_init,
-};
-#endif
-
-/*
- * virtio-pci: This is the PCIDevice which has a virtio-pci-bus.
- */
-
-/* This is called by virtio-bus just after the device is plugged. */
-static void virtio_pci_device_plugged(DeviceState *d)
-{
-    VirtIOPCIProxy *proxy = VIRTIO_PCI(d);
-    VirtioBusState *bus = &proxy->bus;
-    uint8_t *config;
-    uint32_t size;
-
-    proxy->vdev = bus->vdev;
-
-    config = proxy->pci_dev.config;
-    if (proxy->class_code) {
-        pci_config_set_class(config, proxy->class_code);
-    }
-    pci_set_word(config + PCI_SUBSYSTEM_VENDOR_ID,
-                 pci_get_word(config + PCI_VENDOR_ID));
-    pci_set_word(config + PCI_SUBSYSTEM_ID, virtio_bus_get_vdev_id(bus));
-    config[PCI_INTERRUPT_PIN] = 1;
-
-    if (proxy->nvectors &&
-        msix_init_exclusive_bar(&proxy->pci_dev, proxy->nvectors, 1)) {
-        proxy->nvectors = 0;
-    }
-
-    proxy->pci_dev.config_write = virtio_write_config;
-
-    size = VIRTIO_PCI_REGION_SIZE(&proxy->pci_dev)
-         + virtio_bus_get_vdev_config_len(bus);
-    if (size & (size - 1)) {
-        size = 1 << qemu_fls(size);
-    }
-
-    memory_region_init_io(&proxy->bar, &virtio_pci_config_ops, proxy,
-                          "virtio-pci", size);
-    pci_register_bar(&proxy->pci_dev, 0, PCI_BASE_ADDRESS_SPACE_IO,
-                     &proxy->bar);
-
-    if (!kvm_has_many_ioeventfds()) {
-        proxy->flags &= ~VIRTIO_PCI_FLAG_USE_IOEVENTFD;
-    }
-
-    proxy->host_features |= 0x1 << VIRTIO_F_NOTIFY_ON_EMPTY;
-    proxy->host_features |= 0x1 << VIRTIO_F_BAD_FEATURE;
-    proxy->host_features = virtio_bus_get_vdev_features(bus,
-                                                      proxy->host_features);
-}
-
-static int virtio_pci_init(PCIDevice *pci_dev)
-{
-    VirtIOPCIProxy *dev = VIRTIO_PCI(pci_dev);
-    VirtioPCIClass *k = VIRTIO_PCI_GET_CLASS(pci_dev);
-    virtio_pci_bus_new(&dev->bus, dev);
-    if (k->init != NULL) {
-        return k->init(dev);
-    }
-    return 0;
-}
-
-static void virtio_pci_exit(PCIDevice *pci_dev)
-{
-    VirtIOPCIProxy *proxy = VIRTIO_PCI(pci_dev);
-    virtio_pci_stop_ioeventfd(proxy);
-    virtio_exit_pci(pci_dev);
-}
-
-/*
- * This will be renamed virtio_pci_reset at the end of the series.
- * virtio_pci_reset is still in use at this moment.
- */
-static void virtio_pci_rst(DeviceState *qdev)
-{
-    VirtIOPCIProxy *proxy = VIRTIO_PCI(qdev);
-    VirtioBusState *bus = VIRTIO_BUS(&proxy->bus);
-    virtio_pci_stop_ioeventfd(proxy);
-    virtio_bus_reset(bus);
-    msix_unuse_all_vectors(&proxy->pci_dev);
-    proxy->flags &= ~VIRTIO_PCI_FLAG_BUS_MASTER_BUG;
-}
-
-static void virtio_pci_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
-    k->init = virtio_pci_init;
-    k->exit = virtio_pci_exit;
-    k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
-    k->revision = VIRTIO_PCI_ABI_VERSION;
-    k->class_id = PCI_CLASS_OTHERS;
-    dc->reset = virtio_pci_rst;
-}
-
-static const TypeInfo virtio_pci_info = {
-    .name          = TYPE_VIRTIO_PCI,
-    .parent        = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(VirtIOPCIProxy),
-    .class_init    = virtio_pci_class_init,
-    .class_size    = sizeof(VirtioPCIClass),
-    .abstract      = true,
-};
-
-/* virtio-blk-pci */
-
-static Property virtio_blk_pci_properties[] = {
-    DEFINE_PROP_HEX32("class", VirtIOPCIProxy, class_code, 0),
-    DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
-                    VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
-    DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
-#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE
-    DEFINE_PROP_BIT("x-data-plane", VirtIOBlkPCI, blk.data_plane, 0, false),
-#endif
-    DEFINE_VIRTIO_BLK_FEATURES(VirtIOPCIProxy, host_features),
-    DEFINE_VIRTIO_BLK_PROPERTIES(VirtIOBlkPCI, blk),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static int virtio_blk_pci_init(VirtIOPCIProxy *vpci_dev)
-{
-    VirtIOBlkPCI *dev = VIRTIO_BLK_PCI(vpci_dev);
-    DeviceState *vdev = DEVICE(&dev->vdev);
-    virtio_blk_set_conf(vdev, &(dev->blk));
-    qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
-    if (qdev_init(vdev) < 0) {
-        return -1;
-    }
-    return 0;
-}
-
-static void virtio_blk_pci_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
-    PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
-
-    dc->props = virtio_blk_pci_properties;
-    k->init = virtio_blk_pci_init;
-    pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
-    pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_BLOCK;
-    pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
-    pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI;
-}
-
-static void virtio_blk_pci_instance_init(Object *obj)
-{
-    VirtIOBlkPCI *dev = VIRTIO_BLK_PCI(obj);
-    object_initialize(OBJECT(&dev->vdev), TYPE_VIRTIO_BLK);
-    object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
-}
-
-static const TypeInfo virtio_blk_pci_info = {
-    .name          = TYPE_VIRTIO_BLK_PCI,
-    .parent        = TYPE_VIRTIO_PCI,
-    .instance_size = sizeof(VirtIOBlkPCI),
-    .instance_init = virtio_blk_pci_instance_init,
-    .class_init    = virtio_blk_pci_class_init,
-};
-
-/* virtio-scsi-pci */
-
-static Property virtio_scsi_pci_properties[] = {
-    DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
-                    VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
-    DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors,
-                       DEV_NVECTORS_UNSPECIFIED),
-    DEFINE_VIRTIO_SCSI_FEATURES(VirtIOPCIProxy, host_features),
-    DEFINE_VIRTIO_SCSI_PROPERTIES(VirtIOSCSIPCI, vdev.conf),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static int virtio_scsi_pci_init_pci(VirtIOPCIProxy *vpci_dev)
-{
-    VirtIOSCSIPCI *dev = VIRTIO_SCSI_PCI(vpci_dev);
-    DeviceState *vdev = DEVICE(&dev->vdev);
-
-    if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) {
-        vpci_dev->nvectors = dev->vdev.conf.num_queues + 3;
-    }
-
-    qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
-    if (qdev_init(vdev) < 0) {
-        return -1;
-    }
-    return 0;
-}
-
-static void virtio_scsi_pci_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
-    PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
-    k->init = virtio_scsi_pci_init_pci;
-    dc->props = virtio_scsi_pci_properties;
-    pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
-    pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_SCSI;
-    pcidev_k->revision = 0x00;
-    pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI;
-}
-
-static void virtio_scsi_pci_instance_init(Object *obj)
-{
-    VirtIOSCSIPCI *dev = VIRTIO_SCSI_PCI(obj);
-    object_initialize(OBJECT(&dev->vdev), TYPE_VIRTIO_SCSI);
-    object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
-}
-
-static const TypeInfo virtio_scsi_pci_info = {
-    .name          = TYPE_VIRTIO_SCSI_PCI,
-    .parent        = TYPE_VIRTIO_PCI,
-    .instance_size = sizeof(VirtIOSCSIPCI),
-    .instance_init = virtio_scsi_pci_instance_init,
-    .class_init    = virtio_scsi_pci_class_init,
-};
-
-/* virtio-balloon-pci */
-
-static Property virtio_balloon_pci_properties[] = {
-    DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
-    DEFINE_PROP_HEX32("class", VirtIOPCIProxy, class_code, 0),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static int virtio_balloon_pci_init(VirtIOPCIProxy *vpci_dev)
-{
-    VirtIOBalloonPCI *dev = VIRTIO_BALLOON_PCI(vpci_dev);
-    DeviceState *vdev = DEVICE(&dev->vdev);
-
-    if (vpci_dev->class_code != PCI_CLASS_OTHERS &&
-        vpci_dev->class_code != PCI_CLASS_MEMORY_RAM) { /* qemu < 1.1 */
-        vpci_dev->class_code = PCI_CLASS_OTHERS;
-    }
-
-    qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
-    if (qdev_init(vdev) < 0) {
-        return -1;
-    }
-    return 0;
-}
-
-static void virtio_balloon_pci_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
-    PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
-    k->init = virtio_balloon_pci_init;
-    dc->props = virtio_balloon_pci_properties;
-    pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
-    pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_BALLOON;
-    pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
-    pcidev_k->class_id = PCI_CLASS_OTHERS;
-}
-
-static void virtio_balloon_pci_instance_init(Object *obj)
-{
-    VirtIOBalloonPCI *dev = VIRTIO_BALLOON_PCI(obj);
-    object_initialize(OBJECT(&dev->vdev), TYPE_VIRTIO_BALLOON);
-    object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
-}
-
-static const TypeInfo virtio_balloon_pci_info = {
-    .name          = TYPE_VIRTIO_BALLOON_PCI,
-    .parent        = TYPE_VIRTIO_PCI,
-    .instance_size = sizeof(VirtIOBalloonPCI),
-    .instance_init = virtio_balloon_pci_instance_init,
-    .class_init    = virtio_balloon_pci_class_init,
-};
-
-/* virtio-pci-bus */
-
-void virtio_pci_bus_new(VirtioBusState *bus, VirtIOPCIProxy *dev)
-{
-    DeviceState *qdev = DEVICE(dev);
-    BusState *qbus;
-    qbus_create_inplace((BusState *)bus, TYPE_VIRTIO_PCI_BUS, qdev, NULL);
-    qbus = BUS(bus);
-    qbus->allow_hotplug = 1;
-}
-
-static void virtio_pci_bus_class_init(ObjectClass *klass, void *data)
-{
-    BusClass *bus_class = BUS_CLASS(klass);
-    VirtioBusClass *k = VIRTIO_BUS_CLASS(klass);
-    bus_class->max_dev = 1;
-    k->notify = virtio_pci_notify;
-    k->save_config = virtio_pci_save_config;
-    k->load_config = virtio_pci_load_config;
-    k->save_queue = virtio_pci_save_queue;
-    k->load_queue = virtio_pci_load_queue;
-    k->get_features = virtio_pci_get_features;
-    k->query_guest_notifiers = virtio_pci_query_guest_notifiers;
-    k->set_host_notifier = virtio_pci_set_host_notifier;
-    k->set_guest_notifiers = virtio_pci_set_guest_notifiers;
-    k->vmstate_change = virtio_pci_vmstate_change;
-    k->device_plugged = virtio_pci_device_plugged;
-}
-
-static const TypeInfo virtio_pci_bus_info = {
-    .name          = TYPE_VIRTIO_PCI_BUS,
-    .parent        = TYPE_VIRTIO_BUS,
-    .instance_size = sizeof(VirtioPCIBusState),
-    .class_init    = virtio_pci_bus_class_init,
-};
-
-static void virtio_pci_register_types(void)
-{
-    type_register_static(&virtio_net_info);
-    type_register_static(&virtio_serial_info);
-    type_register_static(&virtio_rng_info);
-    type_register_static(&virtio_pci_bus_info);
-    type_register_static(&virtio_pci_info);
-#ifdef CONFIG_VIRTFS
-    type_register_static(&virtio_9p_info);
-#endif
-    type_register_static(&virtio_blk_pci_info);
-    type_register_static(&virtio_scsi_pci_info);
-    type_register_static(&virtio_balloon_pci_info);
-}
-
-type_init(virtio_pci_register_types)
diff --git a/hw/virtio-pci.h b/hw/virtio-pci.h
deleted file mode 100644 (file)
index f99f2eb..0000000
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Virtio PCI Bindings
- *
- * Copyright IBM, Corp. 2007
- * Copyright (c) 2009 CodeSourcery
- *
- * Authors:
- *  Anthony Liguori   <aliguori@us.ibm.com>
- *  Paul Brook        <paul@codesourcery.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2.  See
- * the COPYING file in the top-level directory.
- */
-
-#ifndef QEMU_VIRTIO_PCI_H
-#define QEMU_VIRTIO_PCI_H
-
-#include "hw/pci/msi.h"
-#include "hw/virtio-blk.h"
-#include "hw/virtio-net.h"
-#include "hw/virtio-rng.h"
-#include "hw/virtio-serial.h"
-#include "hw/virtio-scsi.h"
-#include "hw/virtio-balloon.h"
-#include "hw/virtio-bus.h"
-#include "hw/9pfs/virtio-9p-device.h"
-
-typedef struct VirtIOPCIProxy VirtIOPCIProxy;
-typedef struct VirtIOBlkPCI VirtIOBlkPCI;
-typedef struct VirtIOSCSIPCI VirtIOSCSIPCI;
-typedef struct VirtIOBalloonPCI VirtIOBalloonPCI;
-
-/* virtio-pci-bus */
-
-typedef struct VirtioBusState VirtioPCIBusState;
-typedef struct VirtioBusClass VirtioPCIBusClass;
-
-#define TYPE_VIRTIO_PCI_BUS "virtio-pci-bus"
-#define VIRTIO_PCI_BUS(obj) \
-        OBJECT_CHECK(VirtioPCIBusState, (obj), TYPE_VIRTIO_PCI_BUS)
-#define VIRTIO_PCI_BUS_GET_CLASS(obj) \
-        OBJECT_GET_CLASS(VirtioPCIBusClass, obj, TYPE_VIRTIO_PCI_BUS)
-#define VIRTIO_PCI_BUS_CLASS(klass) \
-        OBJECT_CLASS_CHECK(VirtioPCIBusClass, klass, TYPE_VIRTIO_PCI_BUS)
-
-/* Performance improves when virtqueue kick processing is decoupled from the
- * vcpu thread using ioeventfd for some devices. */
-#define VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT 1
-#define VIRTIO_PCI_FLAG_USE_IOEVENTFD   (1 << VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT)
-
-typedef struct {
-    MSIMessage msg;
-    int virq;
-    unsigned int users;
-} VirtIOIRQFD;
-
-/*
- * virtio-pci: This is the PCIDevice which has a virtio-pci-bus.
- */
-#define TYPE_VIRTIO_PCI "virtio-pci"
-#define VIRTIO_PCI_GET_CLASS(obj) \
-        OBJECT_GET_CLASS(VirtioPCIClass, obj, TYPE_VIRTIO_PCI)
-#define VIRTIO_PCI_CLASS(klass) \
-        OBJECT_CLASS_CHECK(VirtioPCIClass, klass, TYPE_VIRTIO_PCI)
-#define VIRTIO_PCI(obj) \
-        OBJECT_CHECK(VirtIOPCIProxy, (obj), TYPE_VIRTIO_PCI)
-
-typedef struct VirtioPCIClass {
-    PCIDeviceClass parent_class;
-    int (*init)(VirtIOPCIProxy *vpci_dev);
-} VirtioPCIClass;
-
-struct VirtIOPCIProxy {
-    PCIDevice pci_dev;
-    VirtIODevice *vdev;
-    MemoryRegion bar;
-    uint32_t flags;
-    uint32_t class_code;
-    uint32_t nvectors;
-    NICConf nic;
-    uint32_t host_features;
-#ifdef CONFIG_VIRTFS
-    V9fsConf fsconf;
-#endif
-    virtio_serial_conf serial;
-    virtio_net_conf net;
-    VirtIORNGConf rng;
-    bool ioeventfd_disabled;
-    bool ioeventfd_started;
-    VirtIOIRQFD *vector_irqfd;
-    int nvqs_with_notifiers;
-    VirtioBusState bus;
-};
-
-
-/*
- * virtio-scsi-pci: This extends VirtioPCIProxy.
- */
-#define TYPE_VIRTIO_SCSI_PCI "virtio-scsi-pci"
-#define VIRTIO_SCSI_PCI(obj) \
-        OBJECT_CHECK(VirtIOSCSIPCI, (obj), TYPE_VIRTIO_SCSI_PCI)
-
-struct VirtIOSCSIPCI {
-    VirtIOPCIProxy parent_obj;
-    VirtIOSCSI vdev;
-};
-
-/*
- * virtio-blk-pci: This extends VirtioPCIProxy.
- */
-#define TYPE_VIRTIO_BLK_PCI "virtio-blk-pci"
-#define VIRTIO_BLK_PCI(obj) \
-        OBJECT_CHECK(VirtIOBlkPCI, (obj), TYPE_VIRTIO_BLK_PCI)
-
-struct VirtIOBlkPCI {
-    VirtIOPCIProxy parent_obj;
-    VirtIOBlock vdev;
-    VirtIOBlkConf blk;
-};
-
-/*
- * virtio-balloon-pci: This extends VirtioPCIProxy.
- */
-#define TYPE_VIRTIO_BALLOON_PCI "virtio-balloon-pci"
-#define VIRTIO_BALLOON_PCI(obj) \
-        OBJECT_CHECK(VirtIOBalloonPCI, (obj), TYPE_VIRTIO_BALLOON_PCI)
-
-struct VirtIOBalloonPCI {
-    VirtIOPCIProxy parent_obj;
-    VirtIOBalloon vdev;
-};
-
-void virtio_init_pci(VirtIOPCIProxy *proxy, VirtIODevice *vdev);
-void virtio_pci_bus_new(VirtioBusState *bus, VirtIOPCIProxy *dev);
-
-/* Virtio ABI version, if we increment this, we break the guest driver. */
-#define VIRTIO_PCI_ABI_VERSION          0
-
-#endif
diff --git a/hw/virtio-rng.c b/hw/virtio-rng.c
deleted file mode 100644 (file)
index fa8e8f3..0000000
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * A virtio device implementing a hardware random number generator.
- *
- * Copyright 2012 Red Hat, Inc.
- * Copyright 2012 Amit Shah <amit.shah@redhat.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or
- * (at your option) any later version.  See the COPYING file in the
- * top-level directory.
- */
-
-#include "qemu/iov.h"
-#include "hw/qdev.h"
-#include "qapi/qmp/qerror.h"
-#include "hw/virtio.h"
-#include "hw/virtio-rng.h"
-#include "qemu/rng.h"
-
-static bool is_guest_ready(VirtIORNG *vrng)
-{
-    if (virtio_queue_ready(vrng->vq)
-        && (vrng->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK)) {
-        return true;
-    }
-    return false;
-}
-
-static size_t get_request_size(VirtQueue *vq, unsigned quota)
-{
-    unsigned int in, out;
-
-    virtqueue_get_avail_bytes(vq, &in, &out, quota, 0);
-    return in;
-}
-
-static void virtio_rng_process(VirtIORNG *vrng);
-
-/* Send data from a char device over to the guest */
-static void chr_read(void *opaque, const void *buf, size_t size)
-{
-    VirtIORNG *vrng = opaque;
-    VirtQueueElement elem;
-    size_t len;
-    int offset;
-
-    if (!is_guest_ready(vrng)) {
-        return;
-    }
-
-    vrng->quota_remaining -= size;
-
-    offset = 0;
-    while (offset < size) {
-        if (!virtqueue_pop(vrng->vq, &elem)) {
-            break;
-        }
-        len = iov_from_buf(elem.in_sg, elem.in_num,
-                           0, buf + offset, size - offset);
-        offset += len;
-
-        virtqueue_push(vrng->vq, &elem, len);
-    }
-    virtio_notify(&vrng->vdev, vrng->vq);
-}
-
-static void virtio_rng_process(VirtIORNG *vrng)
-{
-    size_t size;
-    unsigned quota;
-
-    if (!is_guest_ready(vrng)) {
-        return;
-    }
-
-    if (vrng->quota_remaining < 0) {
-        quota = 0;
-    } else {
-        quota = MIN((uint64_t)vrng->quota_remaining, (uint64_t)UINT32_MAX);
-    }
-    size = get_request_size(vrng->vq, quota);
-    size = MIN(vrng->quota_remaining, size);
-    if (size) {
-        rng_backend_request_entropy(vrng->rng, size, chr_read, vrng);
-    }
-}
-
-static void handle_input(VirtIODevice *vdev, VirtQueue *vq)
-{
-    VirtIORNG *vrng = DO_UPCAST(VirtIORNG, vdev, vdev);
-    virtio_rng_process(vrng);
-}
-
-static uint32_t get_features(VirtIODevice *vdev, uint32_t f)
-{
-    return f;
-}
-
-static void virtio_rng_save(QEMUFile *f, void *opaque)
-{
-    VirtIORNG *vrng = opaque;
-
-    virtio_save(&vrng->vdev, f);
-}
-
-static int virtio_rng_load(QEMUFile *f, void *opaque, int version_id)
-{
-    VirtIORNG *vrng = opaque;
-
-    if (version_id != 1) {
-        return -EINVAL;
-    }
-    virtio_load(&vrng->vdev, f);
-
-    /* We may have an element ready but couldn't process it due to a quota
-     * limit.  Make sure to try again after live migration when the quota may
-     * have been reset.
-     */
-    virtio_rng_process(vrng);
-
-    return 0;
-}
-
-static void check_rate_limit(void *opaque)
-{
-    VirtIORNG *s = opaque;
-
-    s->quota_remaining = s->conf->max_bytes;
-    virtio_rng_process(s);
-    qemu_mod_timer(s->rate_limit_timer,
-                   qemu_get_clock_ms(vm_clock) + s->conf->period_ms);
-}
-
-
-VirtIODevice *virtio_rng_init(DeviceState *dev, VirtIORNGConf *conf)
-{
-    VirtIORNG *vrng;
-    VirtIODevice *vdev;
-    Error *local_err = NULL;
-
-    vdev = virtio_common_init("virtio-rng", VIRTIO_ID_RNG, 0,
-                              sizeof(VirtIORNG));
-
-    vrng = DO_UPCAST(VirtIORNG, vdev, vdev);
-
-    vrng->rng = conf->rng;
-    if (vrng->rng == NULL) {
-        qerror_report(QERR_INVALID_PARAMETER_VALUE, "rng", "a valid object");
-        return NULL;
-    }
-
-    rng_backend_open(vrng->rng, &local_err);
-    if (local_err) {
-        qerror_report_err(local_err);
-        error_free(local_err);
-        return NULL;
-    }
-
-    vrng->vq = virtio_add_queue(vdev, 8, handle_input);
-    vrng->vdev.get_features = get_features;
-
-    vrng->qdev = dev;
-    vrng->conf = conf;
-
-    assert(vrng->conf->max_bytes <= INT64_MAX);
-    vrng->quota_remaining = vrng->conf->max_bytes;
-
-    vrng->rate_limit_timer = qemu_new_timer_ms(vm_clock,
-                                               check_rate_limit, vrng);
-
-    qemu_mod_timer(vrng->rate_limit_timer,
-                   qemu_get_clock_ms(vm_clock) + vrng->conf->period_ms);
-
-    register_savevm(dev, "virtio-rng", -1, 1, virtio_rng_save,
-                    virtio_rng_load, vrng);
-
-    return vdev;
-}
-
-void virtio_rng_exit(VirtIODevice *vdev)
-{
-    VirtIORNG *vrng = DO_UPCAST(VirtIORNG, vdev, vdev);
-
-    qemu_del_timer(vrng->rate_limit_timer);
-    qemu_free_timer(vrng->rate_limit_timer);
-    unregister_savevm(vrng->qdev, "virtio-rng", vrng);
-    virtio_cleanup(vdev);
-}
diff --git a/hw/virtio-rng.h b/hw/virtio-rng.h
deleted file mode 100644 (file)
index 3711c97..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Virtio RNG Support
- *
- * Copyright Red Hat, Inc. 2012
- * Copyright Amit Shah <amit.shah@redhat.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or
- * (at your option) any later version.  See the COPYING file in the
- * top-level directory.
- */
-
-#ifndef _QEMU_VIRTIO_RNG_H
-#define _QEMU_VIRTIO_RNG_H
-
-#include "qemu/rng.h"
-#include "qemu/rng-random.h"
-
-/* The Virtio ID for the virtio rng device */
-#define VIRTIO_ID_RNG    4
-
-struct VirtIORNGConf {
-    RngBackend *rng;
-    uint64_t max_bytes;
-    uint32_t period_ms;
-    RndRandom *default_backend;
-};
-
-typedef struct VirtIORNG {
-    VirtIODevice vdev;
-
-    DeviceState *qdev;
-
-    /* Only one vq - guest puts buffer(s) on it when it needs entropy */
-    VirtQueue *vq;
-
-    VirtIORNGConf *conf;
-
-    RngBackend *rng;
-
-    /* We purposefully don't migrate this state.  The quota will reset on the
-     * destination as a result.  Rate limiting is host state, not guest state.
-     */
-    QEMUTimer *rate_limit_timer;
-    int64_t quota_remaining;
-} VirtIORNG;
-
-#endif
diff --git a/hw/virtio-scsi.c b/hw/virtio-scsi.c
deleted file mode 100644 (file)
index 06a58a6..0000000
+++ /dev/null
@@ -1,774 +0,0 @@
-/*
- * Virtio SCSI HBA
- *
- * Copyright IBM, Corp. 2010
- * Copyright Red Hat, Inc. 2011
- *
- * Authors:
- *   Stefan Hajnoczi    <stefanha@linux.vnet.ibm.com>
- *   Paolo Bonzini      <pbonzini@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 "hw/virtio-scsi.h"
-#include "qemu/error-report.h"
-#include <hw/scsi.h>
-#include <hw/scsi-defs.h>
-#include "hw/virtio-bus.h"
-
-#define VIRTIO_SCSI_VQ_SIZE     128
-#define VIRTIO_SCSI_CDB_SIZE    32
-#define VIRTIO_SCSI_SENSE_SIZE  96
-#define VIRTIO_SCSI_MAX_CHANNEL 0
-#define VIRTIO_SCSI_MAX_TARGET  255
-#define VIRTIO_SCSI_MAX_LUN     16383
-
-/* Response codes */
-#define VIRTIO_SCSI_S_OK                       0
-#define VIRTIO_SCSI_S_OVERRUN                  1
-#define VIRTIO_SCSI_S_ABORTED                  2
-#define VIRTIO_SCSI_S_BAD_TARGET               3
-#define VIRTIO_SCSI_S_RESET                    4
-#define VIRTIO_SCSI_S_BUSY                     5
-#define VIRTIO_SCSI_S_TRANSPORT_FAILURE        6
-#define VIRTIO_SCSI_S_TARGET_FAILURE           7
-#define VIRTIO_SCSI_S_NEXUS_FAILURE            8
-#define VIRTIO_SCSI_S_FAILURE                  9
-#define VIRTIO_SCSI_S_FUNCTION_SUCCEEDED       10
-#define VIRTIO_SCSI_S_FUNCTION_REJECTED        11
-#define VIRTIO_SCSI_S_INCORRECT_LUN            12
-
-/* Controlq type codes.  */
-#define VIRTIO_SCSI_T_TMF                      0
-#define VIRTIO_SCSI_T_AN_QUERY                 1
-#define VIRTIO_SCSI_T_AN_SUBSCRIBE             2
-
-/* Valid TMF subtypes.  */
-#define VIRTIO_SCSI_T_TMF_ABORT_TASK           0
-#define VIRTIO_SCSI_T_TMF_ABORT_TASK_SET       1
-#define VIRTIO_SCSI_T_TMF_CLEAR_ACA            2
-#define VIRTIO_SCSI_T_TMF_CLEAR_TASK_SET       3
-#define VIRTIO_SCSI_T_TMF_I_T_NEXUS_RESET      4
-#define VIRTIO_SCSI_T_TMF_LOGICAL_UNIT_RESET   5
-#define VIRTIO_SCSI_T_TMF_QUERY_TASK           6
-#define VIRTIO_SCSI_T_TMF_QUERY_TASK_SET       7
-
-/* Events.  */
-#define VIRTIO_SCSI_T_EVENTS_MISSED            0x80000000
-#define VIRTIO_SCSI_T_NO_EVENT                 0
-#define VIRTIO_SCSI_T_TRANSPORT_RESET          1
-#define VIRTIO_SCSI_T_ASYNC_NOTIFY             2
-#define VIRTIO_SCSI_T_PARAM_CHANGE             3
-
-/* Reasons for transport reset event */
-#define VIRTIO_SCSI_EVT_RESET_HARD             0
-#define VIRTIO_SCSI_EVT_RESET_RESCAN           1
-#define VIRTIO_SCSI_EVT_RESET_REMOVED          2
-
-/* SCSI command request, followed by data-out */
-typedef struct {
-    uint8_t lun[8];              /* Logical Unit Number */
-    uint64_t tag;                /* Command identifier */
-    uint8_t task_attr;           /* Task attribute */
-    uint8_t prio;
-    uint8_t crn;
-    uint8_t cdb[];
-} QEMU_PACKED VirtIOSCSICmdReq;
-
-/* Response, followed by sense data and data-in */
-typedef struct {
-    uint32_t sense_len;          /* Sense data length */
-    uint32_t resid;              /* Residual bytes in data buffer */
-    uint16_t status_qualifier;   /* Status qualifier */
-    uint8_t status;              /* Command completion status */
-    uint8_t response;            /* Response values */
-    uint8_t sense[];
-} QEMU_PACKED VirtIOSCSICmdResp;
-
-/* Task Management Request */
-typedef struct {
-    uint32_t type;
-    uint32_t subtype;
-    uint8_t lun[8];
-    uint64_t tag;
-} QEMU_PACKED VirtIOSCSICtrlTMFReq;
-
-typedef struct {
-    uint8_t response;
-} QEMU_PACKED VirtIOSCSICtrlTMFResp;
-
-/* Asynchronous notification query/subscription */
-typedef struct {
-    uint32_t type;
-    uint8_t lun[8];
-    uint32_t event_requested;
-} QEMU_PACKED VirtIOSCSICtrlANReq;
-
-typedef struct {
-    uint32_t event_actual;
-    uint8_t response;
-} QEMU_PACKED VirtIOSCSICtrlANResp;
-
-typedef struct {
-    uint32_t event;
-    uint8_t lun[8];
-    uint32_t reason;
-} QEMU_PACKED VirtIOSCSIEvent;
-
-typedef struct {
-    uint32_t num_queues;
-    uint32_t seg_max;
-    uint32_t max_sectors;
-    uint32_t cmd_per_lun;
-    uint32_t event_info_size;
-    uint32_t sense_size;
-    uint32_t cdb_size;
-    uint16_t max_channel;
-    uint16_t max_target;
-    uint32_t max_lun;
-} QEMU_PACKED VirtIOSCSIConfig;
-
-typedef struct VirtIOSCSIReq {
-    VirtIOSCSI *dev;
-    VirtQueue *vq;
-    VirtQueueElement elem;
-    QEMUSGList qsgl;
-    SCSIRequest *sreq;
-    union {
-        char                  *buf;
-        VirtIOSCSICmdReq      *cmd;
-        VirtIOSCSICtrlTMFReq  *tmf;
-        VirtIOSCSICtrlANReq   *an;
-    } req;
-    union {
-        char                  *buf;
-        VirtIOSCSICmdResp     *cmd;
-        VirtIOSCSICtrlTMFResp *tmf;
-        VirtIOSCSICtrlANResp  *an;
-        VirtIOSCSIEvent       *event;
-    } resp;
-} VirtIOSCSIReq;
-
-static inline int virtio_scsi_get_lun(uint8_t *lun)
-{
-    return ((lun[2] << 8) | lun[3]) & 0x3FFF;
-}
-
-static inline SCSIDevice *virtio_scsi_device_find(VirtIOSCSI *s, uint8_t *lun)
-{
-    if (lun[0] != 1) {
-        return NULL;
-    }
-    if (lun[2] != 0 && !(lun[2] >= 0x40 && lun[2] < 0x80)) {
-        return NULL;
-    }
-    return scsi_device_find(&s->bus, 0, lun[1], virtio_scsi_get_lun(lun));
-}
-
-static void virtio_scsi_complete_req(VirtIOSCSIReq *req)
-{
-    VirtIOSCSI *s = req->dev;
-    VirtQueue *vq = req->vq;
-    VirtIODevice *vdev = VIRTIO_DEVICE(s);
-    virtqueue_push(vq, &req->elem, req->qsgl.size + req->elem.in_sg[0].iov_len);
-    qemu_sglist_destroy(&req->qsgl);
-    if (req->sreq) {
-        req->sreq->hba_private = NULL;
-        scsi_req_unref(req->sreq);
-    }
-    g_free(req);
-    virtio_notify(vdev, vq);
-}
-
-static void virtio_scsi_bad_req(void)
-{
-    error_report("wrong size for virtio-scsi headers");
-    exit(1);
-}
-
-static void qemu_sgl_init_external(QEMUSGList *qsgl, struct iovec *sg,
-                                   hwaddr *addr, int num)
-{
-    qemu_sglist_init(qsgl, num, &dma_context_memory);
-    while (num--) {
-        qemu_sglist_add(qsgl, *(addr++), (sg++)->iov_len);
-    }
-}
-
-static void virtio_scsi_parse_req(VirtIOSCSI *s, VirtQueue *vq,
-                                  VirtIOSCSIReq *req)
-{
-    assert(req->elem.in_num);
-    req->vq = vq;
-    req->dev = s;
-    req->sreq = NULL;
-    if (req->elem.out_num) {
-        req->req.buf = req->elem.out_sg[0].iov_base;
-    }
-    req->resp.buf = req->elem.in_sg[0].iov_base;
-
-    if (req->elem.out_num > 1) {
-        qemu_sgl_init_external(&req->qsgl, &req->elem.out_sg[1],
-                               &req->elem.out_addr[1],
-                               req->elem.out_num - 1);
-    } else {
-        qemu_sgl_init_external(&req->qsgl, &req->elem.in_sg[1],
-                               &req->elem.in_addr[1],
-                               req->elem.in_num - 1);
-    }
-}
-
-static VirtIOSCSIReq *virtio_scsi_pop_req(VirtIOSCSI *s, VirtQueue *vq)
-{
-    VirtIOSCSIReq *req;
-    req = g_malloc(sizeof(*req));
-    if (!virtqueue_pop(vq, &req->elem)) {
-        g_free(req);
-        return NULL;
-    }
-
-    virtio_scsi_parse_req(s, vq, req);
-    return req;
-}
-
-static void virtio_scsi_save_request(QEMUFile *f, SCSIRequest *sreq)
-{
-    VirtIOSCSIReq *req = sreq->hba_private;
-    uint32_t n = virtio_queue_get_id(req->vq) - 2;
-
-    assert(n < req->dev->conf.num_queues);
-    qemu_put_be32s(f, &n);
-    qemu_put_buffer(f, (unsigned char *)&req->elem, sizeof(req->elem));
-}
-
-static void *virtio_scsi_load_request(QEMUFile *f, SCSIRequest *sreq)
-{
-    SCSIBus *bus = sreq->bus;
-    VirtIOSCSI *s = container_of(bus, VirtIOSCSI, bus);
-    VirtIOSCSIReq *req;
-    uint32_t n;
-
-    req = g_malloc(sizeof(*req));
-    qemu_get_be32s(f, &n);
-    assert(n < s->conf.num_queues);
-    qemu_get_buffer(f, (unsigned char *)&req->elem, sizeof(req->elem));
-    virtio_scsi_parse_req(s, s->cmd_vqs[n], req);
-
-    scsi_req_ref(sreq);
-    req->sreq = sreq;
-    if (req->sreq->cmd.mode != SCSI_XFER_NONE) {
-        int req_mode =
-            (req->elem.in_num > 1 ? SCSI_XFER_FROM_DEV : SCSI_XFER_TO_DEV);
-
-        assert(req->sreq->cmd.mode == req_mode);
-    }
-    return req;
-}
-
-static void virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req)
-{
-    SCSIDevice *d = virtio_scsi_device_find(s, req->req.tmf->lun);
-    SCSIRequest *r, *next;
-    BusChild *kid;
-    int target;
-
-    /* Here VIRTIO_SCSI_S_OK means "FUNCTION COMPLETE".  */
-    req->resp.tmf->response = VIRTIO_SCSI_S_OK;
-
-    switch (req->req.tmf->subtype) {
-    case VIRTIO_SCSI_T_TMF_ABORT_TASK:
-    case VIRTIO_SCSI_T_TMF_QUERY_TASK:
-        if (!d) {
-            goto fail;
-        }
-        if (d->lun != virtio_scsi_get_lun(req->req.tmf->lun)) {
-            goto incorrect_lun;
-        }
-        QTAILQ_FOREACH_SAFE(r, &d->requests, next, next) {
-            VirtIOSCSIReq *cmd_req = r->hba_private;
-            if (cmd_req && cmd_req->req.cmd->tag == req->req.tmf->tag) {
-                break;
-            }
-        }
-        if (r) {
-            /*
-             * Assert that the request has not been completed yet, we
-             * check for it in the loop above.
-             */
-            assert(r->hba_private);
-            if (req->req.tmf->subtype == VIRTIO_SCSI_T_TMF_QUERY_TASK) {
-                /* "If the specified command is present in the task set, then
-                 * return a service response set to FUNCTION SUCCEEDED".
-                 */
-                req->resp.tmf->response = VIRTIO_SCSI_S_FUNCTION_SUCCEEDED;
-            } else {
-                scsi_req_cancel(r);
-            }
-        }
-        break;
-
-    case VIRTIO_SCSI_T_TMF_LOGICAL_UNIT_RESET:
-        if (!d) {
-            goto fail;
-        }
-        if (d->lun != virtio_scsi_get_lun(req->req.tmf->lun)) {
-            goto incorrect_lun;
-        }
-        s->resetting++;
-        qdev_reset_all(&d->qdev);
-        s->resetting--;
-        break;
-
-    case VIRTIO_SCSI_T_TMF_ABORT_TASK_SET:
-    case VIRTIO_SCSI_T_TMF_CLEAR_TASK_SET:
-    case VIRTIO_SCSI_T_TMF_QUERY_TASK_SET:
-        if (!d) {
-            goto fail;
-        }
-        if (d->lun != virtio_scsi_get_lun(req->req.tmf->lun)) {
-            goto incorrect_lun;
-        }
-        QTAILQ_FOREACH_SAFE(r, &d->requests, next, next) {
-            if (r->hba_private) {
-                if (req->req.tmf->subtype == VIRTIO_SCSI_T_TMF_QUERY_TASK_SET) {
-                    /* "If there is any command present in the task set, then
-                     * return a service response set to FUNCTION SUCCEEDED".
-                     */
-                    req->resp.tmf->response = VIRTIO_SCSI_S_FUNCTION_SUCCEEDED;
-                    break;
-                } else {
-                    scsi_req_cancel(r);
-                }
-            }
-        }
-        break;
-
-    case VIRTIO_SCSI_T_TMF_I_T_NEXUS_RESET:
-        target = req->req.tmf->lun[1];
-        s->resetting++;
-        QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) {
-             d = DO_UPCAST(SCSIDevice, qdev, kid->child);
-             if (d->channel == 0 && d->id == target) {
-                qdev_reset_all(&d->qdev);
-             }
-        }
-        s->resetting--;
-        break;
-
-    case VIRTIO_SCSI_T_TMF_CLEAR_ACA:
-    default:
-        req->resp.tmf->response = VIRTIO_SCSI_S_FUNCTION_REJECTED;
-        break;
-    }
-
-    return;
-
-incorrect_lun:
-    req->resp.tmf->response = VIRTIO_SCSI_S_INCORRECT_LUN;
-    return;
-
-fail:
-    req->resp.tmf->response = VIRTIO_SCSI_S_BAD_TARGET;
-}
-
-static void virtio_scsi_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
-{
-    VirtIOSCSI *s = (VirtIOSCSI *)vdev;
-    VirtIOSCSIReq *req;
-
-    while ((req = virtio_scsi_pop_req(s, vq))) {
-        int out_size, in_size;
-        if (req->elem.out_num < 1 || req->elem.in_num < 1) {
-            virtio_scsi_bad_req();
-            continue;
-        }
-
-        out_size = req->elem.out_sg[0].iov_len;
-        in_size = req->elem.in_sg[0].iov_len;
-        if (req->req.tmf->type == VIRTIO_SCSI_T_TMF) {
-            if (out_size < sizeof(VirtIOSCSICtrlTMFReq) ||
-                in_size < sizeof(VirtIOSCSICtrlTMFResp)) {
-                virtio_scsi_bad_req();
-            }
-            virtio_scsi_do_tmf(s, req);
-
-        } else if (req->req.tmf->type == VIRTIO_SCSI_T_AN_QUERY ||
-                   req->req.tmf->type == VIRTIO_SCSI_T_AN_SUBSCRIBE) {
-            if (out_size < sizeof(VirtIOSCSICtrlANReq) ||
-                in_size < sizeof(VirtIOSCSICtrlANResp)) {
-                virtio_scsi_bad_req();
-            }
-            req->resp.an->event_actual = 0;
-            req->resp.an->response = VIRTIO_SCSI_S_OK;
-        }
-        virtio_scsi_complete_req(req);
-    }
-}
-
-static void virtio_scsi_command_complete(SCSIRequest *r, uint32_t status,
-                                         size_t resid)
-{
-    VirtIOSCSIReq *req = r->hba_private;
-    uint32_t sense_len;
-
-    req->resp.cmd->response = VIRTIO_SCSI_S_OK;
-    req->resp.cmd->status = status;
-    if (req->resp.cmd->status == GOOD) {
-        req->resp.cmd->resid = tswap32(resid);
-    } else {
-        req->resp.cmd->resid = 0;
-        sense_len = scsi_req_get_sense(r, req->resp.cmd->sense,
-                                       VIRTIO_SCSI_SENSE_SIZE);
-        req->resp.cmd->sense_len = tswap32(sense_len);
-    }
-    virtio_scsi_complete_req(req);
-}
-
-static QEMUSGList *virtio_scsi_get_sg_list(SCSIRequest *r)
-{
-    VirtIOSCSIReq *req = r->hba_private;
-
-    return &req->qsgl;
-}
-
-static void virtio_scsi_request_cancelled(SCSIRequest *r)
-{
-    VirtIOSCSIReq *req = r->hba_private;
-
-    if (!req) {
-        return;
-    }
-    if (req->dev->resetting) {
-        req->resp.cmd->response = VIRTIO_SCSI_S_RESET;
-    } else {
-        req->resp.cmd->response = VIRTIO_SCSI_S_ABORTED;
-    }
-    virtio_scsi_complete_req(req);
-}
-
-static void virtio_scsi_fail_cmd_req(VirtIOSCSIReq *req)
-{
-    req->resp.cmd->response = VIRTIO_SCSI_S_FAILURE;
-    virtio_scsi_complete_req(req);
-}
-
-static void virtio_scsi_handle_cmd(VirtIODevice *vdev, VirtQueue *vq)
-{
-    VirtIOSCSI *s = (VirtIOSCSI *)vdev;
-    VirtIOSCSIReq *req;
-    int n;
-
-    while ((req = virtio_scsi_pop_req(s, vq))) {
-        SCSIDevice *d;
-        int out_size, in_size;
-        if (req->elem.out_num < 1 || req->elem.in_num < 1) {
-            virtio_scsi_bad_req();
-        }
-
-        out_size = req->elem.out_sg[0].iov_len;
-        in_size = req->elem.in_sg[0].iov_len;
-        if (out_size < sizeof(VirtIOSCSICmdReq) + s->cdb_size ||
-            in_size < sizeof(VirtIOSCSICmdResp) + s->sense_size) {
-            virtio_scsi_bad_req();
-        }
-
-        if (req->elem.out_num > 1 && req->elem.in_num > 1) {
-            virtio_scsi_fail_cmd_req(req);
-            continue;
-        }
-
-        d = virtio_scsi_device_find(s, req->req.cmd->lun);
-        if (!d) {
-            req->resp.cmd->response = VIRTIO_SCSI_S_BAD_TARGET;
-            virtio_scsi_complete_req(req);
-            continue;
-        }
-        req->sreq = scsi_req_new(d, req->req.cmd->tag,
-                                 virtio_scsi_get_lun(req->req.cmd->lun),
-                                 req->req.cmd->cdb, req);
-
-        if (req->sreq->cmd.mode != SCSI_XFER_NONE) {
-            int req_mode =
-                (req->elem.in_num > 1 ? SCSI_XFER_FROM_DEV : SCSI_XFER_TO_DEV);
-
-            if (req->sreq->cmd.mode != req_mode ||
-                req->sreq->cmd.xfer > req->qsgl.size) {
-                req->resp.cmd->response = VIRTIO_SCSI_S_OVERRUN;
-                virtio_scsi_complete_req(req);
-                continue;
-            }
-        }
-
-        n = scsi_req_enqueue(req->sreq);
-        if (n) {
-            scsi_req_continue(req->sreq);
-        }
-    }
-}
-
-static void virtio_scsi_get_config(VirtIODevice *vdev,
-                                   uint8_t *config)
-{
-    VirtIOSCSIConfig *scsiconf = (VirtIOSCSIConfig *)config;
-    VirtIOSCSI *s = (VirtIOSCSI *)vdev;
-
-    stl_raw(&scsiconf->num_queues, s->conf.num_queues);
-    stl_raw(&scsiconf->seg_max, 128 - 2);
-    stl_raw(&scsiconf->max_sectors, s->conf.max_sectors);
-    stl_raw(&scsiconf->cmd_per_lun, s->conf.cmd_per_lun);
-    stl_raw(&scsiconf->event_info_size, sizeof(VirtIOSCSIEvent));
-    stl_raw(&scsiconf->sense_size, s->sense_size);
-    stl_raw(&scsiconf->cdb_size, s->cdb_size);
-    stw_raw(&scsiconf->max_channel, VIRTIO_SCSI_MAX_CHANNEL);
-    stw_raw(&scsiconf->max_target, VIRTIO_SCSI_MAX_TARGET);
-    stl_raw(&scsiconf->max_lun, VIRTIO_SCSI_MAX_LUN);
-}
-
-static void virtio_scsi_set_config(VirtIODevice *vdev,
-                                   const uint8_t *config)
-{
-    VirtIOSCSIConfig *scsiconf = (VirtIOSCSIConfig *)config;
-    VirtIOSCSI *s = (VirtIOSCSI *)vdev;
-
-    if ((uint32_t) ldl_raw(&scsiconf->sense_size) >= 65536 ||
-        (uint32_t) ldl_raw(&scsiconf->cdb_size) >= 256) {
-        error_report("bad data written to virtio-scsi configuration space");
-        exit(1);
-    }
-
-    s->sense_size = ldl_raw(&scsiconf->sense_size);
-    s->cdb_size = ldl_raw(&scsiconf->cdb_size);
-}
-
-static uint32_t virtio_scsi_get_features(VirtIODevice *vdev,
-                                         uint32_t requested_features)
-{
-    return requested_features;
-}
-
-static void virtio_scsi_reset(VirtIODevice *vdev)
-{
-    VirtIOSCSI *s = (VirtIOSCSI *)vdev;
-
-    s->resetting++;
-    qbus_reset_all(&s->bus.qbus);
-    s->resetting--;
-
-    s->sense_size = VIRTIO_SCSI_SENSE_SIZE;
-    s->cdb_size = VIRTIO_SCSI_CDB_SIZE;
-    s->events_dropped = false;
-}
-
-/* The device does not have anything to save beyond the virtio data.
- * Request data is saved with callbacks from SCSI devices.
- */
-static void virtio_scsi_save(QEMUFile *f, void *opaque)
-{
-    VirtIODevice *vdev = VIRTIO_DEVICE(opaque);
-    virtio_save(vdev, f);
-}
-
-static int virtio_scsi_load(QEMUFile *f, void *opaque, int version_id)
-{
-    VirtIODevice *vdev = VIRTIO_DEVICE(opaque);
-    int ret;
-
-    ret = virtio_load(vdev, f);
-    if (ret) {
-        return ret;
-    }
-    return 0;
-}
-
-static void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev,
-                                   uint32_t event, uint32_t reason)
-{
-    VirtIOSCSIReq *req = virtio_scsi_pop_req(s, s->event_vq);
-    VirtIOSCSIEvent *evt;
-    VirtIODevice *vdev = VIRTIO_DEVICE(s);
-    int in_size;
-
-    if (!(vdev->status & VIRTIO_CONFIG_S_DRIVER_OK)) {
-        return;
-    }
-
-    if (!req) {
-        s->events_dropped = true;
-        return;
-    }
-
-    if (req->elem.out_num || req->elem.in_num != 1) {
-        virtio_scsi_bad_req();
-    }
-
-    if (s->events_dropped) {
-        event |= VIRTIO_SCSI_T_EVENTS_MISSED;
-        s->events_dropped = false;
-    }
-
-    in_size = req->elem.in_sg[0].iov_len;
-    if (in_size < sizeof(VirtIOSCSIEvent)) {
-        virtio_scsi_bad_req();
-    }
-
-    evt = req->resp.event;
-    memset(evt, 0, sizeof(VirtIOSCSIEvent));
-    evt->event = event;
-    evt->reason = reason;
-    if (!dev) {
-        assert(event == VIRTIO_SCSI_T_NO_EVENT);
-    } else {
-        evt->lun[0] = 1;
-        evt->lun[1] = dev->id;
-
-        /* Linux wants us to keep the same encoding we use for REPORT LUNS.  */
-        if (dev->lun >= 256) {
-            evt->lun[2] = (dev->lun >> 8) | 0x40;
-        }
-        evt->lun[3] = dev->lun & 0xFF;
-    }
-    virtio_scsi_complete_req(req);
-}
-
-static void virtio_scsi_handle_event(VirtIODevice *vdev, VirtQueue *vq)
-{
-    VirtIOSCSI *s = VIRTIO_SCSI(vdev);
-
-    if (s->events_dropped) {
-        virtio_scsi_push_event(s, NULL, VIRTIO_SCSI_T_NO_EVENT, 0);
-    }
-}
-
-static void virtio_scsi_change(SCSIBus *bus, SCSIDevice *dev, SCSISense sense)
-{
-    VirtIOSCSI *s = container_of(bus, VirtIOSCSI, bus);
-    VirtIODevice *vdev = VIRTIO_DEVICE(s);
-
-    if (((vdev->guest_features >> VIRTIO_SCSI_F_CHANGE) & 1) &&
-        dev->type != TYPE_ROM) {
-        virtio_scsi_push_event(s, dev, VIRTIO_SCSI_T_PARAM_CHANGE,
-                               sense.asc | (sense.ascq << 8));
-    }
-}
-
-static void virtio_scsi_hotplug(SCSIBus *bus, SCSIDevice *dev)
-{
-    VirtIOSCSI *s = container_of(bus, VirtIOSCSI, bus);
-    VirtIODevice *vdev = VIRTIO_DEVICE(s);
-
-    if ((vdev->guest_features >> VIRTIO_SCSI_F_HOTPLUG) & 1) {
-        virtio_scsi_push_event(s, dev, VIRTIO_SCSI_T_TRANSPORT_RESET,
-                               VIRTIO_SCSI_EVT_RESET_RESCAN);
-    }
-}
-
-static void virtio_scsi_hot_unplug(SCSIBus *bus, SCSIDevice *dev)
-{
-    VirtIOSCSI *s = container_of(bus, VirtIOSCSI, bus);
-    VirtIODevice *vdev = VIRTIO_DEVICE(s);
-
-    if ((vdev->guest_features >> VIRTIO_SCSI_F_HOTPLUG) & 1) {
-        virtio_scsi_push_event(s, dev, VIRTIO_SCSI_T_TRANSPORT_RESET,
-                               VIRTIO_SCSI_EVT_RESET_REMOVED);
-    }
-}
-
-static struct SCSIBusInfo virtio_scsi_scsi_info = {
-    .tcq = true,
-    .max_channel = VIRTIO_SCSI_MAX_CHANNEL,
-    .max_target = VIRTIO_SCSI_MAX_TARGET,
-    .max_lun = VIRTIO_SCSI_MAX_LUN,
-
-    .complete = virtio_scsi_command_complete,
-    .cancel = virtio_scsi_request_cancelled,
-    .change = virtio_scsi_change,
-    .hotplug = virtio_scsi_hotplug,
-    .hot_unplug = virtio_scsi_hot_unplug,
-    .get_sg_list = virtio_scsi_get_sg_list,
-    .save_request = virtio_scsi_save_request,
-    .load_request = virtio_scsi_load_request,
-};
-
-static int virtio_scsi_device_init(VirtIODevice *vdev)
-{
-    DeviceState *qdev = DEVICE(vdev);
-    VirtIOSCSI *s = VIRTIO_SCSI(vdev);
-    static int virtio_scsi_id;
-    int i;
-
-    virtio_init(VIRTIO_DEVICE(s), "virtio-scsi", VIRTIO_ID_SCSI,
-                sizeof(VirtIOSCSIConfig));
-
-    s->cmd_vqs = g_malloc0(s->conf.num_queues * sizeof(VirtQueue *));
-
-    /* TODO set up vdev function pointers */
-    vdev->get_config = virtio_scsi_get_config;
-    vdev->set_config = virtio_scsi_set_config;
-    vdev->get_features = virtio_scsi_get_features;
-    vdev->reset = virtio_scsi_reset;
-
-    s->ctrl_vq = virtio_add_queue(vdev, VIRTIO_SCSI_VQ_SIZE,
-                                  virtio_scsi_handle_ctrl);
-    s->event_vq = virtio_add_queue(vdev, VIRTIO_SCSI_VQ_SIZE,
-                                   virtio_scsi_handle_event);
-    for (i = 0; i < s->conf.num_queues; i++) {
-        s->cmd_vqs[i] = virtio_add_queue(vdev, VIRTIO_SCSI_VQ_SIZE,
-                                         virtio_scsi_handle_cmd);
-    }
-
-    scsi_bus_new(&s->bus, qdev, &virtio_scsi_scsi_info);
-    if (!qdev->hotplugged) {
-        scsi_bus_legacy_handle_cmdline(&s->bus);
-    }
-
-    register_savevm(qdev, "virtio-scsi", virtio_scsi_id++, 1,
-                    virtio_scsi_save, virtio_scsi_load, s);
-
-    return 0;
-}
-
-static int virtio_scsi_device_exit(DeviceState *qdev)
-{
-    VirtIOSCSI *s = VIRTIO_SCSI(qdev);
-    VirtIODevice *vdev = VIRTIO_DEVICE(qdev);
-
-    unregister_savevm(qdev, "virtio-scsi", s);
-    g_free(s->cmd_vqs);
-    virtio_common_cleanup(vdev);
-    return 0;
-}
-
-static Property virtio_scsi_properties[] = {
-    DEFINE_VIRTIO_SCSI_PROPERTIES(VirtIOSCSI, conf),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void virtio_scsi_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
-    dc->exit = virtio_scsi_device_exit;
-    dc->props = virtio_scsi_properties;
-    vdc->init = virtio_scsi_device_init;
-    vdc->get_config = virtio_scsi_get_config;
-    vdc->set_config = virtio_scsi_set_config;
-    vdc->get_features = virtio_scsi_get_features;
-    vdc->reset = virtio_scsi_reset;
-}
-
-static const TypeInfo virtio_scsi_info = {
-    .name = TYPE_VIRTIO_SCSI,
-    .parent = TYPE_VIRTIO_DEVICE,
-    .instance_size = sizeof(VirtIOSCSI),
-    .class_init = virtio_scsi_class_init,
-};
-
-static void virtio_register_types(void)
-{
-    type_register_static(&virtio_scsi_info);
-}
-
-type_init(virtio_register_types)
diff --git a/hw/virtio-scsi.h b/hw/virtio-scsi.h
deleted file mode 100644 (file)
index 31e97bb..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Virtio SCSI HBA
- *
- * Copyright IBM, Corp. 2010
- *
- * Authors:
- *  Stefan Hajnoczi    <stefanha@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.
- *
- */
-
-#ifndef _QEMU_VIRTIO_SCSI_H
-#define _QEMU_VIRTIO_SCSI_H
-
-#include "hw/virtio.h"
-#include "hw/pci/pci.h"
-#include "hw/scsi.h"
-
-#define TYPE_VIRTIO_SCSI "virtio-scsi"
-#define VIRTIO_SCSI(obj) \
-        OBJECT_CHECK(VirtIOSCSI, (obj), TYPE_VIRTIO_SCSI)
-
-
-/* The ID for virtio_scsi */
-#define VIRTIO_ID_SCSI  8
-
-/* Feature Bits */
-#define VIRTIO_SCSI_F_INOUT                    0
-#define VIRTIO_SCSI_F_HOTPLUG                  1
-#define VIRTIO_SCSI_F_CHANGE                   2
-
-struct VirtIOSCSIConf {
-    uint32_t num_queues;
-    uint32_t max_sectors;
-    uint32_t cmd_per_lun;
-};
-
-typedef struct VirtIOSCSI {
-    VirtIODevice parent_obj;
-    VirtIOSCSIConf conf;
-
-    SCSIBus bus;
-    uint32_t sense_size;
-    uint32_t cdb_size;
-    int resetting;
-    bool events_dropped;
-    VirtQueue *ctrl_vq;
-    VirtQueue *event_vq;
-    VirtQueue **cmd_vqs;
-} VirtIOSCSI;
-
-#define DEFINE_VIRTIO_SCSI_PROPERTIES(_state, _conf_field)                     \
-    DEFINE_PROP_UINT32("num_queues", _state, _conf_field.num_queues, 1),       \
-    DEFINE_PROP_UINT32("max_sectors", _state, _conf_field.max_sectors, 0xFFFF),\
-    DEFINE_PROP_UINT32("cmd_per_lun", _state, _conf_field.cmd_per_lun, 128)
-
-#define DEFINE_VIRTIO_SCSI_FEATURES(_state, _feature_field)                    \
-    DEFINE_VIRTIO_COMMON_FEATURES(_state, _feature_field),                     \
-    DEFINE_PROP_BIT("hotplug", _state, _feature_field, VIRTIO_SCSI_F_HOTPLUG,  \
-                                                       true),                  \
-    DEFINE_PROP_BIT("param_change", _state, _feature_field,                    \
-                                            VIRTIO_SCSI_F_CHANGE, true)
-
-#endif /* _QEMU_VIRTIO_SCSI_H */
diff --git a/hw/virtio-serial-bus.c b/hw/virtio-serial-bus.c
deleted file mode 100644 (file)
index a9cb114..0000000
+++ /dev/null
@@ -1,1018 +0,0 @@
-/*
- * A bus for connecting virtio serial and console ports
- *
- * Copyright (C) 2009, 2010 Red Hat, Inc.
- *
- * Author(s):
- *  Amit Shah <amit.shah@redhat.com>
- *
- * Some earlier parts are:
- *  Copyright IBM, Corp. 2008
- * authored by
- *  Christian Ehrhardt <ehrhardt@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.
- *
- * 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/iov.h"
-#include "monitor/monitor.h"
-#include "qemu/queue.h"
-#include "hw/sysbus.h"
-#include "trace.h"
-#include "hw/virtio-serial.h"
-
-static VirtIOSerialPort *find_port_by_id(VirtIOSerial *vser, uint32_t id)
-{
-    VirtIOSerialPort *port;
-
-    if (id == VIRTIO_CONSOLE_BAD_ID) {
-        return NULL;
-    }
-
-    QTAILQ_FOREACH(port, &vser->ports, next) {
-        if (port->id == id)
-            return port;
-    }
-    return NULL;
-}
-
-static VirtIOSerialPort *find_port_by_vq(VirtIOSerial *vser, VirtQueue *vq)
-{
-    VirtIOSerialPort *port;
-
-    QTAILQ_FOREACH(port, &vser->ports, next) {
-        if (port->ivq == vq || port->ovq == vq)
-            return port;
-    }
-    return NULL;
-}
-
-static bool use_multiport(VirtIOSerial *vser)
-{
-    return vser->vdev.guest_features & (1 << VIRTIO_CONSOLE_F_MULTIPORT);
-}
-
-static size_t write_to_port(VirtIOSerialPort *port,
-                            const uint8_t *buf, size_t size)
-{
-    VirtQueueElement elem;
-    VirtQueue *vq;
-    size_t offset;
-
-    vq = port->ivq;
-    if (!virtio_queue_ready(vq)) {
-        return 0;
-    }
-
-    offset = 0;
-    while (offset < size) {
-        size_t len;
-
-        if (!virtqueue_pop(vq, &elem)) {
-            break;
-        }
-
-        len = iov_from_buf(elem.in_sg, elem.in_num, 0,
-                           buf + offset, size - offset);
-        offset += len;
-
-        virtqueue_push(vq, &elem, len);
-    }
-
-    virtio_notify(&port->vser->vdev, vq);
-    return offset;
-}
-
-static void discard_vq_data(VirtQueue *vq, VirtIODevice *vdev)
-{
-    VirtQueueElement elem;
-
-    if (!virtio_queue_ready(vq)) {
-        return;
-    }
-    while (virtqueue_pop(vq, &elem)) {
-        virtqueue_push(vq, &elem, 0);
-    }
-    virtio_notify(vdev, vq);
-}
-
-static void do_flush_queued_data(VirtIOSerialPort *port, VirtQueue *vq,
-                                 VirtIODevice *vdev)
-{
-    VirtIOSerialPortClass *vsc;
-
-    assert(port);
-    assert(virtio_queue_ready(vq));
-
-    vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port);
-
-    while (!port->throttled) {
-        unsigned int i;
-
-        /* Pop an elem only if we haven't left off a previous one mid-way */
-        if (!port->elem.out_num) {
-            if (!virtqueue_pop(vq, &port->elem)) {
-                break;
-            }
-            port->iov_idx = 0;
-            port->iov_offset = 0;
-        }
-
-        for (i = port->iov_idx; i < port->elem.out_num; i++) {
-            size_t buf_size;
-            ssize_t ret;
-
-            buf_size = port->elem.out_sg[i].iov_len - port->iov_offset;
-            ret = vsc->have_data(port,
-                                  port->elem.out_sg[i].iov_base
-                                  + port->iov_offset,
-                                  buf_size);
-            if (port->throttled) {
-                port->iov_idx = i;
-                if (ret > 0) {
-                    port->iov_offset += ret;
-                }
-                break;
-            }
-            port->iov_offset = 0;
-        }
-        if (port->throttled) {
-            break;
-        }
-        virtqueue_push(vq, &port->elem, 0);
-        port->elem.out_num = 0;
-    }
-    virtio_notify(vdev, vq);
-}
-
-static void flush_queued_data(VirtIOSerialPort *port)
-{
-    assert(port);
-
-    if (!virtio_queue_ready(port->ovq)) {
-        return;
-    }
-    do_flush_queued_data(port, port->ovq, &port->vser->vdev);
-}
-
-static size_t send_control_msg(VirtIOSerial *vser, void *buf, size_t len)
-{
-    VirtQueueElement elem;
-    VirtQueue *vq;
-
-    vq = vser->c_ivq;
-    if (!virtio_queue_ready(vq)) {
-        return 0;
-    }
-    if (!virtqueue_pop(vq, &elem)) {
-        return 0;
-    }
-
-    memcpy(elem.in_sg[0].iov_base, buf, len);
-
-    virtqueue_push(vq, &elem, len);
-    virtio_notify(&vser->vdev, vq);
-    return len;
-}
-
-static size_t send_control_event(VirtIOSerial *vser, uint32_t port_id,
-                                 uint16_t event, uint16_t value)
-{
-    struct virtio_console_control cpkt;
-
-    stl_p(&cpkt.id, port_id);
-    stw_p(&cpkt.event, event);
-    stw_p(&cpkt.value, value);
-
-    trace_virtio_serial_send_control_event(port_id, event, value);
-    return send_control_msg(vser, &cpkt, sizeof(cpkt));
-}
-
-/* Functions for use inside qemu to open and read from/write to ports */
-int virtio_serial_open(VirtIOSerialPort *port)
-{
-    /* Don't allow opening an already-open port */
-    if (port->host_connected) {
-        return 0;
-    }
-    /* Send port open notification to the guest */
-    port->host_connected = true;
-    send_control_event(port->vser, port->id, VIRTIO_CONSOLE_PORT_OPEN, 1);
-
-    return 0;
-}
-
-int virtio_serial_close(VirtIOSerialPort *port)
-{
-    port->host_connected = false;
-    /*
-     * If there's any data the guest sent which the app didn't
-     * consume, reset the throttling flag and discard the data.
-     */
-    port->throttled = false;
-    discard_vq_data(port->ovq, &port->vser->vdev);
-
-    send_control_event(port->vser, port->id, VIRTIO_CONSOLE_PORT_OPEN, 0);
-
-    return 0;
-}
-
-/* Individual ports/apps call this function to write to the guest. */
-ssize_t virtio_serial_write(VirtIOSerialPort *port, const uint8_t *buf,
-                            size_t size)
-{
-    if (!port || !port->host_connected || !port->guest_connected) {
-        return 0;
-    }
-    return write_to_port(port, buf, size);
-}
-
-/*
- * Readiness of the guest to accept data on a port.
- * Returns max. data the guest can receive
- */
-size_t virtio_serial_guest_ready(VirtIOSerialPort *port)
-{
-    VirtQueue *vq = port->ivq;
-    unsigned int bytes;
-
-    if (!virtio_queue_ready(vq) ||
-        !(port->vser->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK) ||
-        virtio_queue_empty(vq)) {
-        return 0;
-    }
-    if (use_multiport(port->vser) && !port->guest_connected) {
-        return 0;
-    }
-    virtqueue_get_avail_bytes(vq, &bytes, NULL, 4096, 0);
-    return bytes;
-}
-
-static void flush_queued_data_bh(void *opaque)
-{
-    VirtIOSerialPort *port = opaque;
-
-    flush_queued_data(port);
-}
-
-void virtio_serial_throttle_port(VirtIOSerialPort *port, bool throttle)
-{
-    if (!port) {
-        return;
-    }
-
-    trace_virtio_serial_throttle_port(port->id, throttle);
-    port->throttled = throttle;
-    if (throttle) {
-        return;
-    }
-    qemu_bh_schedule(port->bh);
-}
-
-/* Guest wants to notify us of some event */
-static void handle_control_message(VirtIOSerial *vser, void *buf, size_t len)
-{
-    struct VirtIOSerialPort *port;
-    VirtIOSerialPortClass *vsc;
-    struct virtio_console_control cpkt, *gcpkt;
-    uint8_t *buffer;
-    size_t buffer_len;
-
-    gcpkt = buf;
-
-    if (len < sizeof(cpkt)) {
-        /* The guest sent an invalid control packet */
-        return;
-    }
-
-    cpkt.event = lduw_p(&gcpkt->event);
-    cpkt.value = lduw_p(&gcpkt->value);
-
-    trace_virtio_serial_handle_control_message(cpkt.event, cpkt.value);
-
-    if (cpkt.event == VIRTIO_CONSOLE_DEVICE_READY) {
-        if (!cpkt.value) {
-            error_report("virtio-serial-bus: Guest failure in adding device %s",
-                         vser->bus.qbus.name);
-            return;
-        }
-        /*
-         * The device is up, we can now tell the device about all the
-         * ports we have here.
-         */
-        QTAILQ_FOREACH(port, &vser->ports, next) {
-            send_control_event(vser, port->id, VIRTIO_CONSOLE_PORT_ADD, 1);
-        }
-        return;
-    }
-
-    port = find_port_by_id(vser, ldl_p(&gcpkt->id));
-    if (!port) {
-        error_report("virtio-serial-bus: Unexpected port id %u for device %s",
-                     ldl_p(&gcpkt->id), vser->bus.qbus.name);
-        return;
-    }
-
-    trace_virtio_serial_handle_control_message_port(port->id);
-
-    vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port);
-
-    switch(cpkt.event) {
-    case VIRTIO_CONSOLE_PORT_READY:
-        if (!cpkt.value) {
-            error_report("virtio-serial-bus: Guest failure in adding port %u for device %s",
-                         port->id, vser->bus.qbus.name);
-            break;
-        }
-        /*
-         * Now that we know the guest asked for the port name, we're
-         * sure the guest has initialised whatever state is necessary
-         * for this port. Now's a good time to let the guest know if
-         * this port is a console port so that the guest can hook it
-         * up to hvc.
-         */
-        if (vsc->is_console) {
-            send_control_event(vser, port->id, VIRTIO_CONSOLE_CONSOLE_PORT, 1);
-        }
-
-        if (port->name) {
-            stl_p(&cpkt.id, port->id);
-            stw_p(&cpkt.event, VIRTIO_CONSOLE_PORT_NAME);
-            stw_p(&cpkt.value, 1);
-
-            buffer_len = sizeof(cpkt) + strlen(port->name) + 1;
-            buffer = g_malloc(buffer_len);
-
-            memcpy(buffer, &cpkt, sizeof(cpkt));
-            memcpy(buffer + sizeof(cpkt), port->name, strlen(port->name));
-            buffer[buffer_len - 1] = 0;
-
-            send_control_msg(vser, buffer, buffer_len);
-            g_free(buffer);
-        }
-
-        if (port->host_connected) {
-            send_control_event(vser, port->id, VIRTIO_CONSOLE_PORT_OPEN, 1);
-        }
-
-        /*
-         * When the guest has asked us for this information it means
-         * the guest is all setup and has its virtqueues
-         * initialised. If some app is interested in knowing about
-         * this event, let it know.
-         */
-        if (vsc->guest_ready) {
-            vsc->guest_ready(port);
-        }
-        break;
-
-    case VIRTIO_CONSOLE_PORT_OPEN:
-        port->guest_connected = cpkt.value;
-        if (vsc->set_guest_connected) {
-            /* Send the guest opened notification if an app is interested */
-            vsc->set_guest_connected(port, cpkt.value);
-        }
-        break;
-    }
-}
-
-static void control_in(VirtIODevice *vdev, VirtQueue *vq)
-{
-}
-
-static void control_out(VirtIODevice *vdev, VirtQueue *vq)
-{
-    VirtQueueElement elem;
-    VirtIOSerial *vser;
-    uint8_t *buf;
-    size_t len;
-
-    vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
-
-    len = 0;
-    buf = NULL;
-    while (virtqueue_pop(vq, &elem)) {
-        size_t cur_len;
-
-        cur_len = iov_size(elem.out_sg, elem.out_num);
-        /*
-         * Allocate a new buf only if we didn't have one previously or
-         * if the size of the buf differs
-         */
-        if (cur_len > len) {
-            g_free(buf);
-
-            buf = g_malloc(cur_len);
-            len = cur_len;
-        }
-        iov_to_buf(elem.out_sg, elem.out_num, 0, buf, cur_len);
-
-        handle_control_message(vser, buf, cur_len);
-        virtqueue_push(vq, &elem, 0);
-    }
-    g_free(buf);
-    virtio_notify(vdev, vq);
-}
-
-/* Guest wrote something to some port. */
-static void handle_output(VirtIODevice *vdev, VirtQueue *vq)
-{
-    VirtIOSerial *vser;
-    VirtIOSerialPort *port;
-
-    vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
-    port = find_port_by_vq(vser, vq);
-
-    if (!port || !port->host_connected) {
-        discard_vq_data(vq, vdev);
-        return;
-    }
-
-    if (!port->throttled) {
-        do_flush_queued_data(port, vq, vdev);
-        return;
-    }
-}
-
-static void handle_input(VirtIODevice *vdev, VirtQueue *vq)
-{
-}
-
-static uint32_t get_features(VirtIODevice *vdev, uint32_t features)
-{
-    VirtIOSerial *vser;
-
-    vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
-
-    if (vser->bus.max_nr_ports > 1) {
-        features |= (1 << VIRTIO_CONSOLE_F_MULTIPORT);
-    }
-    return features;
-}
-
-/* Guest requested config info */
-static void get_config(VirtIODevice *vdev, uint8_t *config_data)
-{
-    VirtIOSerial *vser;
-
-    vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
-    memcpy(config_data, &vser->config, sizeof(struct virtio_console_config));
-}
-
-static void set_config(VirtIODevice *vdev, const uint8_t *config_data)
-{
-    struct virtio_console_config config;
-
-    memcpy(&config, config_data, sizeof(config));
-}
-
-static void guest_reset(VirtIOSerial *vser)
-{
-    VirtIOSerialPort *port;
-    VirtIOSerialPortClass *vsc;
-
-    QTAILQ_FOREACH(port, &vser->ports, next) {
-        vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port);
-        if (port->guest_connected) {
-            port->guest_connected = false;
-            if (vsc->set_guest_connected) {
-                vsc->set_guest_connected(port, false);
-            }
-        }
-    }
-}
-
-static void set_status(VirtIODevice *vdev, uint8_t status)
-{
-    VirtIOSerial *vser;
-    VirtIOSerialPort *port;
-
-    vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
-    port = find_port_by_id(vser, 0);
-
-    if (port && !use_multiport(port->vser)
-        && (status & VIRTIO_CONFIG_S_DRIVER_OK)) {
-        /*
-         * Non-multiport guests won't be able to tell us guest
-         * open/close status.  Such guests can only have a port at id
-         * 0, so set guest_connected for such ports as soon as guest
-         * is up.
-         */
-        port->guest_connected = true;
-    }
-    if (!(status & VIRTIO_CONFIG_S_DRIVER_OK)) {
-        guest_reset(vser);
-    }
-}
-
-static void vser_reset(VirtIODevice *vdev)
-{
-    VirtIOSerial *vser;
-
-    vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
-    guest_reset(vser);
-}
-
-static void virtio_serial_save(QEMUFile *f, void *opaque)
-{
-    VirtIOSerial *s = opaque;
-    VirtIOSerialPort *port;
-    uint32_t nr_active_ports;
-    unsigned int i, max_nr_ports;
-
-    /* The virtio device */
-    virtio_save(&s->vdev, f);
-
-    /* The config space */
-    qemu_put_be16s(f, &s->config.cols);
-    qemu_put_be16s(f, &s->config.rows);
-
-    qemu_put_be32s(f, &s->config.max_nr_ports);
-
-    /* The ports map */
-    max_nr_ports = tswap32(s->config.max_nr_ports);
-    for (i = 0; i < (max_nr_ports + 31) / 32; i++) {
-        qemu_put_be32s(f, &s->ports_map[i]);
-    }
-
-    /* Ports */
-
-    nr_active_ports = 0;
-    QTAILQ_FOREACH(port, &s->ports, next) {
-        nr_active_ports++;
-    }
-
-    qemu_put_be32s(f, &nr_active_ports);
-
-    /*
-     * Items in struct VirtIOSerialPort.
-     */
-    QTAILQ_FOREACH(port, &s->ports, next) {
-        uint32_t elem_popped;
-
-        qemu_put_be32s(f, &port->id);
-        qemu_put_byte(f, port->guest_connected);
-        qemu_put_byte(f, port->host_connected);
-
-       elem_popped = 0;
-        if (port->elem.out_num) {
-            elem_popped = 1;
-        }
-        qemu_put_be32s(f, &elem_popped);
-        if (elem_popped) {
-            qemu_put_be32s(f, &port->iov_idx);
-            qemu_put_be64s(f, &port->iov_offset);
-
-            qemu_put_buffer(f, (unsigned char *)&port->elem,
-                            sizeof(port->elem));
-        }
-    }
-}
-
-static void virtio_serial_post_load_timer_cb(void *opaque)
-{
-    uint32_t i;
-    VirtIOSerial *s = opaque;
-    VirtIOSerialPort *port;
-    uint8_t host_connected;
-    VirtIOSerialPortClass *vsc;
-
-    if (!s->post_load) {
-        return;
-    }
-    for (i = 0 ; i < s->post_load->nr_active_ports; ++i) {
-        port = s->post_load->connected[i].port;
-        host_connected = s->post_load->connected[i].host_connected;
-        if (host_connected != port->host_connected) {
-            /*
-             * We have to let the guest know of the host connection
-             * status change
-             */
-            send_control_event(s, port->id, VIRTIO_CONSOLE_PORT_OPEN,
-                               port->host_connected);
-        }
-        vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port);
-        if (vsc->set_guest_connected) {
-            vsc->set_guest_connected(port, port->guest_connected);
-        }
-    }
-    g_free(s->post_load->connected);
-    qemu_free_timer(s->post_load->timer);
-    g_free(s->post_load);
-    s->post_load = NULL;
-}
-
-static int fetch_active_ports_list(QEMUFile *f, int version_id,
-                                   VirtIOSerial *s, uint32_t nr_active_ports)
-{
-    uint32_t i;
-
-    s->post_load = g_malloc0(sizeof(*s->post_load));
-    s->post_load->nr_active_ports = nr_active_ports;
-    s->post_load->connected =
-        g_malloc0(sizeof(*s->post_load->connected) * nr_active_ports);
-
-    s->post_load->timer = qemu_new_timer_ns(vm_clock,
-                                            virtio_serial_post_load_timer_cb,
-                                            s);
-
-    /* Items in struct VirtIOSerialPort */
-    for (i = 0; i < nr_active_ports; i++) {
-        VirtIOSerialPort *port;
-        uint32_t id;
-
-        id = qemu_get_be32(f);
-        port = find_port_by_id(s, id);
-        if (!port) {
-            return -EINVAL;
-        }
-
-        port->guest_connected = qemu_get_byte(f);
-        s->post_load->connected[i].port = port;
-        s->post_load->connected[i].host_connected = qemu_get_byte(f);
-
-        if (version_id > 2) {
-            uint32_t elem_popped;
-
-            qemu_get_be32s(f, &elem_popped);
-            if (elem_popped) {
-                qemu_get_be32s(f, &port->iov_idx);
-                qemu_get_be64s(f, &port->iov_offset);
-
-                qemu_get_buffer(f, (unsigned char *)&port->elem,
-                                sizeof(port->elem));
-                virtqueue_map_sg(port->elem.in_sg, port->elem.in_addr,
-                                 port->elem.in_num, 1);
-                virtqueue_map_sg(port->elem.out_sg, port->elem.out_addr,
-                                 port->elem.out_num, 1);
-
-                /*
-                 *  Port was throttled on source machine.  Let's
-                 *  unthrottle it here so data starts flowing again.
-                 */
-                virtio_serial_throttle_port(port, false);
-            }
-        }
-    }
-    qemu_mod_timer(s->post_load->timer, 1);
-    return 0;
-}
-
-static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id)
-{
-    VirtIOSerial *s = opaque;
-    uint32_t max_nr_ports, nr_active_ports, ports_map;
-    unsigned int i;
-    int ret;
-
-    if (version_id > 3) {
-        return -EINVAL;
-    }
-
-    /* The virtio device */
-    ret = virtio_load(&s->vdev, f);
-    if (ret) {
-        return ret;
-    }
-
-    if (version_id < 2) {
-        return 0;
-    }
-
-    /* The config space */
-    qemu_get_be16s(f, &s->config.cols);
-    qemu_get_be16s(f, &s->config.rows);
-
-    qemu_get_be32s(f, &max_nr_ports);
-    tswap32s(&max_nr_ports);
-    if (max_nr_ports > tswap32(s->config.max_nr_ports)) {
-        /* Source could have had more ports than us. Fail migration. */
-        return -EINVAL;
-    }
-
-    for (i = 0; i < (max_nr_ports + 31) / 32; i++) {
-        qemu_get_be32s(f, &ports_map);
-
-        if (ports_map != s->ports_map[i]) {
-            /*
-             * Ports active on source and destination don't
-             * match. Fail migration.
-             */
-            return -EINVAL;
-        }
-    }
-
-    qemu_get_be32s(f, &nr_active_ports);
-
-    if (nr_active_ports) {
-        ret = fetch_active_ports_list(f, version_id, s, nr_active_ports);
-        if (ret) {
-            return ret;
-        }
-    }
-    return 0;
-}
-
-static void virtser_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent);
-
-static Property virtser_props[] = {
-    DEFINE_PROP_UINT32("nr", VirtIOSerialPort, id, VIRTIO_CONSOLE_BAD_ID),
-    DEFINE_PROP_STRING("name", VirtIOSerialPort, name),
-    DEFINE_PROP_END_OF_LIST()
-};
-
-#define TYPE_VIRTIO_SERIAL_BUS "virtio-serial-bus"
-#define VIRTIO_SERIAL_BUS(obj) \
-      OBJECT_CHECK(VirtIOSerialBus, (obj), TYPE_VIRTIO_SERIAL_BUS)
-
-static void virtser_bus_class_init(ObjectClass *klass, void *data)
-{
-    BusClass *k = BUS_CLASS(klass);
-    k->print_dev = virtser_bus_dev_print;
-}
-
-static const TypeInfo virtser_bus_info = {
-    .name = TYPE_VIRTIO_SERIAL_BUS,
-    .parent = TYPE_BUS,
-    .instance_size = sizeof(VirtIOSerialBus),
-    .class_init = virtser_bus_class_init,
-};
-
-static void virtser_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent)
-{
-    VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, qdev);
-
-    monitor_printf(mon, "%*sport %d, guest %s, host %s, throttle %s\n",
-                   indent, "", port->id,
-                   port->guest_connected ? "on" : "off",
-                   port->host_connected ? "on" : "off",
-                   port->throttled ? "on" : "off");
-}
-
-/* This function is only used if a port id is not provided by the user */
-static uint32_t find_free_port_id(VirtIOSerial *vser)
-{
-    unsigned int i, max_nr_ports;
-
-    max_nr_ports = tswap32(vser->config.max_nr_ports);
-    for (i = 0; i < (max_nr_ports + 31) / 32; i++) {
-        uint32_t map, bit;
-
-        map = vser->ports_map[i];
-        bit = ffs(~map);
-        if (bit) {
-            return (bit - 1) + i * 32;
-        }
-    }
-    return VIRTIO_CONSOLE_BAD_ID;
-}
-
-static void mark_port_added(VirtIOSerial *vser, uint32_t port_id)
-{
-    unsigned int i;
-
-    i = port_id / 32;
-    vser->ports_map[i] |= 1U << (port_id % 32);
-}
-
-static void add_port(VirtIOSerial *vser, uint32_t port_id)
-{
-    mark_port_added(vser, port_id);
-    send_control_event(vser, port_id, VIRTIO_CONSOLE_PORT_ADD, 1);
-}
-
-static void remove_port(VirtIOSerial *vser, uint32_t port_id)
-{
-    VirtIOSerialPort *port;
-    unsigned int i;
-
-    i = port_id / 32;
-    vser->ports_map[i] &= ~(1U << (port_id % 32));
-
-    port = find_port_by_id(vser, port_id);
-    /*
-     * This function is only called from qdev's unplug callback; if we
-     * get a NULL port here, we're in trouble.
-     */
-    assert(port);
-
-    /* Flush out any unconsumed buffers first */
-    discard_vq_data(port->ovq, &port->vser->vdev);
-
-    send_control_event(vser, port->id, VIRTIO_CONSOLE_PORT_REMOVE, 1);
-}
-
-static int virtser_port_qdev_init(DeviceState *qdev)
-{
-    VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, qdev);
-    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;
-
-    port->vser = bus->vser;
-    port->bh = qemu_bh_new(flush_queued_data_bh, port);
-
-    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 = 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",
-                     port->id);
-        return -1;
-    }
-
-    if (port->id == VIRTIO_CONSOLE_BAD_ID) {
-        if (plugging_port0) {
-            port->id = 0;
-        } else {
-            port->id = find_free_port_id(port->vser);
-            if (port->id == VIRTIO_CONSOLE_BAD_ID) {
-                error_report("virtio-serial-bus: Maximum port limit for this device reached");
-                return -1;
-            }
-        }
-    }
-
-    max_nr_ports = tswap32(port->vser->config.max_nr_ports);
-    if (port->id >= max_nr_ports) {
-        error_report("virtio-serial-bus: Out-of-range port id specified, max. allowed: %u",
-                     max_nr_ports - 1);
-        return -1;
-    }
-
-    ret = vsc->init(port);
-    if (ret) {
-        return ret;
-    }
-
-    port->elem.out_num = 0;
-
-    QTAILQ_INSERT_TAIL(&port->vser->ports, port, next);
-    port->ivq = port->vser->ivqs[port->id];
-    port->ovq = port->vser->ovqs[port->id];
-
-    add_port(port->vser, port->id);
-
-    /* Send an update to the guest about this new port added */
-    virtio_notify_config(&port->vser->vdev);
-
-    return ret;
-}
-
-static int virtser_port_qdev_exit(DeviceState *qdev)
-{
-    VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, qdev);
-    VirtIOSerialPortClass *vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port);
-    VirtIOSerial *vser = port->vser;
-
-    qemu_bh_delete(port->bh);
-    remove_port(port->vser, port->id);
-
-    QTAILQ_REMOVE(&vser->ports, port, next);
-
-    if (vsc->exit) {
-        vsc->exit(port);
-    }
-    return 0;
-}
-
-VirtIODevice *virtio_serial_init(DeviceState *dev, virtio_serial_conf *conf)
-{
-    VirtIOSerial *vser;
-    VirtIODevice *vdev;
-    uint32_t i, max_supported_ports;
-
-    if (!conf->max_virtserial_ports)
-        return NULL;
-
-    /* Each port takes 2 queues, and one pair is for the control queue */
-    max_supported_ports = VIRTIO_PCI_QUEUE_MAX / 2 - 1;
-
-    if (conf->max_virtserial_ports > max_supported_ports) {
-        error_report("maximum ports supported: %u", max_supported_ports);
-        return NULL;
-    }
-
-    vdev = virtio_common_init("virtio-serial", VIRTIO_ID_CONSOLE,
-                              sizeof(struct virtio_console_config),
-                              sizeof(VirtIOSerial));
-
-    vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
-
-    /* Spawn a new virtio-serial bus on which the ports will ride as devices */
-    qbus_create_inplace(&vser->bus.qbus, TYPE_VIRTIO_SERIAL_BUS, dev, NULL);
-    vser->bus.qbus.allow_hotplug = 1;
-    vser->bus.vser = vser;
-    QTAILQ_INIT(&vser->ports);
-
-    vser->bus.max_nr_ports = conf->max_virtserial_ports;
-    vser->ivqs = g_malloc(conf->max_virtserial_ports * sizeof(VirtQueue *));
-    vser->ovqs = g_malloc(conf->max_virtserial_ports * sizeof(VirtQueue *));
-
-    /* Add a queue for host to guest transfers for port 0 (backward compat) */
-    vser->ivqs[0] = virtio_add_queue(vdev, 128, handle_input);
-    /* Add a queue for guest to host transfers for port 0 (backward compat) */
-    vser->ovqs[0] = virtio_add_queue(vdev, 128, handle_output);
-
-    /* TODO: host to guest notifications can get dropped
-     * if the queue fills up. Implement queueing in host,
-     * this might also make it possible to reduce the control
-     * queue size: as guest preposts buffers there,
-     * this will save 4Kbyte of guest memory per entry. */
-
-    /* control queue: host to guest */
-    vser->c_ivq = virtio_add_queue(vdev, 32, control_in);
-    /* control queue: guest to host */
-    vser->c_ovq = virtio_add_queue(vdev, 32, control_out);
-
-    for (i = 1; i < vser->bus.max_nr_ports; i++) {
-        /* Add a per-port queue for host to guest transfers */
-        vser->ivqs[i] = virtio_add_queue(vdev, 128, handle_input);
-        /* Add a per-per queue for guest to host transfers */
-        vser->ovqs[i] = virtio_add_queue(vdev, 128, handle_output);
-    }
-
-    vser->config.max_nr_ports = tswap32(conf->max_virtserial_ports);
-    vser->ports_map = g_malloc0(((conf->max_virtserial_ports + 31) / 32)
-        * sizeof(vser->ports_map[0]));
-    /*
-     * Reserve location 0 for a console port for backward compat
-     * (old kernel, new qemu)
-     */
-    mark_port_added(vser, 0);
-
-    vser->vdev.get_features = get_features;
-    vser->vdev.get_config = get_config;
-    vser->vdev.set_config = set_config;
-    vser->vdev.set_status = set_status;
-    vser->vdev.reset = vser_reset;
-
-    vser->qdev = dev;
-
-    vser->post_load = NULL;
-
-    /*
-     * Register for the savevm section with the virtio-console name
-     * to preserve backward compat
-     */
-    register_savevm(dev, "virtio-console", -1, 3, virtio_serial_save,
-                    virtio_serial_load, vser);
-
-    return vdev;
-}
-
-void virtio_serial_exit(VirtIODevice *vdev)
-{
-    VirtIOSerial *vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
-
-    unregister_savevm(vser->qdev, "virtio-console", vser);
-
-    g_free(vser->ivqs);
-    g_free(vser->ovqs);
-    g_free(vser->ports_map);
-    if (vser->post_load) {
-        g_free(vser->post_load->connected);
-        qemu_del_timer(vser->post_load->timer);
-        qemu_free_timer(vser->post_load->timer);
-        g_free(vser->post_load);
-    }
-    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_type = TYPE_VIRTIO_SERIAL_BUS;
-    k->exit = virtser_port_qdev_exit;
-    k->unplug = qdev_simple_unplug_cb;
-    k->props = virtser_props;
-}
-
-static const 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_types(void)
-{
-    type_register_static(&virtser_bus_info);
-    type_register_static(&virtio_serial_port_type_info);
-}
-
-type_init(virtio_serial_register_types)
diff --git a/hw/virtio-serial.h b/hw/virtio-serial.h
deleted file mode 100644 (file)
index 516400f..0000000
+++ /dev/null
@@ -1,247 +0,0 @@
-/*
- * Virtio Serial / Console Support
- *
- * Copyright IBM, Corp. 2008
- * Copyright Red Hat, Inc. 2009, 2010
- *
- * Authors:
- *  Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com>
- *  Amit Shah <amit.shah@redhat.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2.  See
- * the COPYING file in the top-level directory.
- *
- */
-#ifndef _QEMU_VIRTIO_SERIAL_H
-#define _QEMU_VIRTIO_SERIAL_H
-
-#include "hw/qdev.h"
-#include "hw/virtio.h"
-
-/* == Interface shared between the guest kernel and qemu == */
-
-/* The Virtio ID for virtio console / serial ports */
-#define VIRTIO_ID_CONSOLE              3
-
-/* Features supported */
-#define VIRTIO_CONSOLE_F_MULTIPORT     1
-
-#define VIRTIO_CONSOLE_BAD_ID           (~(uint32_t)0)
-
-struct virtio_console_config {
-    /*
-     * These two fields are used by VIRTIO_CONSOLE_F_SIZE which
-     * isn't implemented here yet
-     */
-    uint16_t cols;
-    uint16_t rows;
-
-    uint32_t max_nr_ports;
-} QEMU_PACKED;
-
-struct virtio_console_control {
-    uint32_t id;               /* Port number */
-    uint16_t event;            /* The kind of control event (see below) */
-    uint16_t value;            /* Extra information for the key */
-};
-
-struct virtio_serial_conf {
-    /* Max. number of ports we can have for a virtio-serial device */
-    uint32_t max_virtserial_ports;
-};
-
-/* Some events for the internal messages (control packets) */
-#define VIRTIO_CONSOLE_DEVICE_READY    0
-#define VIRTIO_CONSOLE_PORT_ADD                1
-#define VIRTIO_CONSOLE_PORT_REMOVE     2
-#define VIRTIO_CONSOLE_PORT_READY      3
-#define VIRTIO_CONSOLE_CONSOLE_PORT    4
-#define VIRTIO_CONSOLE_RESIZE          5
-#define VIRTIO_CONSOLE_PORT_OPEN       6
-#define VIRTIO_CONSOLE_PORT_NAME       7
-
-/* == 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 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/closed device. */
-    void (*set_guest_connected)(VirtIOSerialPort *port, int guest_connected);
-
-        /* 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
- * state is configurable via command-line options. Some of it can be
- * set by individual devices in their initfn routines. Some of the
- * state is set by the generic qdev device init routine.
- */
-struct VirtIOSerialPort {
-    DeviceState dev;
-
-    QTAILQ_ENTRY(VirtIOSerialPort) next;
-
-    /*
-     * This field gives us the virtio device as well as the qdev bus
-     * that we are associated with
-     */
-    VirtIOSerial *vser;
-
-    VirtQueue *ivq, *ovq;
-
-    /*
-     * This name is sent to the guest and exported via sysfs.
-     * The guest could create symlinks based on this information.
-     * The name is in the reverse fqdn format, like org.qemu.console.0
-     */
-    char *name;
-
-    /*
-     * This id helps identify ports between the guest and the host.
-     * The guest sends a "header" with this id with each data packet
-     * that it sends and the host can then find out which associated
-     * device to send out this data to
-     */
-    uint32_t id;
-
-    /*
-     * This is the elem that we pop from the virtqueue.  A slow
-     * backend that consumes guest data (e.g. the file backend for
-     * qemu chardevs) can cause the guest to block till all the output
-     * is flushed.  This isn't desired, so we keep a note of the last
-     * element popped and continue consuming it once the backend
-     * becomes writable again.
-     */
-    VirtQueueElement elem;
-
-    /*
-     * The index and the offset into the iov buffer that was popped in
-     * elem above.
-     */
-    uint32_t iov_idx;
-    uint64_t iov_offset;
-
-    /*
-     * When unthrottling we use a bottom-half to call flush_queued_data.
-     */
-    QEMUBH *bh;
-
-    /* Is the corresponding guest device open? */
-    bool guest_connected;
-    /* Is this device open for IO on the host? */
-    bool host_connected;
-    /* Do apps not want to receive data? */
-    bool throttled;
-};
-
-/* The virtio-serial bus on top of which the ports will ride as devices */
-struct VirtIOSerialBus {
-    BusState qbus;
-
-    /* This is the parent device that provides the bus for ports. */
-    VirtIOSerial *vser;
-
-    /* The maximum number of ports that can ride on top of this bus */
-    uint32_t max_nr_ports;
-};
-
-typedef struct VirtIOSerialPostLoad {
-    QEMUTimer *timer;
-    uint32_t nr_active_ports;
-    struct {
-        VirtIOSerialPort *port;
-        uint8_t host_connected;
-    } *connected;
-} VirtIOSerialPostLoad;
-
-struct VirtIOSerial {
-    VirtIODevice vdev;
-
-    VirtQueue *c_ivq, *c_ovq;
-    /* Arrays of ivqs and ovqs: one per port */
-    VirtQueue **ivqs, **ovqs;
-
-    VirtIOSerialBus bus;
-
-    DeviceState *qdev;
-
-    QTAILQ_HEAD(, VirtIOSerialPort) ports;
-
-    /* bitmap for identifying active ports */
-    uint32_t *ports_map;
-
-    struct virtio_console_config config;
-
-    struct VirtIOSerialPostLoad *post_load;
-};
-
-/* Interface to the virtio-serial bus */
-
-/*
- * Open a connection to the port
- *   Returns 0 on success (always).
- */
-int virtio_serial_open(VirtIOSerialPort *port);
-
-/*
- * Close the connection to the port
- *   Returns 0 on success (always).
- */
-int virtio_serial_close(VirtIOSerialPort *port);
-
-/*
- * Send data to Guest
- */
-ssize_t virtio_serial_write(VirtIOSerialPort *port, const uint8_t *buf,
-                            size_t size);
-
-/*
- * Query whether a guest is ready to receive data.
- */
-size_t virtio_serial_guest_ready(VirtIOSerialPort *port);
-
-/*
- * Flow control: Ports can signal to the virtio-serial core to stop
- * sending data or re-start sending data, depending on the 'throttle'
- * value here.
- */
-void virtio_serial_throttle_port(VirtIOSerialPort *port, bool throttle);
-
-#endif
diff --git a/hw/virtio.c b/hw/virtio.c
deleted file mode 100644 (file)
index 26fbc79..0000000
+++ /dev/null
@@ -1,1121 +0,0 @@
-/*
- * Virtio Support
- *
- * Copyright IBM, Corp. 2007
- *
- * Authors:
- *  Anthony Liguori   <aliguori@us.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 <inttypes.h>
-
-#include "trace.h"
-#include "qemu/error-report.h"
-#include "hw/virtio.h"
-#include "qemu/atomic.h"
-#include "hw/virtio-bus.h"
-
-/* The alignment to use between consumer and producer parts of vring.
- * x86 pagesize again. */
-#define VIRTIO_PCI_VRING_ALIGN         4096
-
-typedef struct VRingDesc
-{
-    uint64_t addr;
-    uint32_t len;
-    uint16_t flags;
-    uint16_t next;
-} VRingDesc;
-
-typedef struct VRingAvail
-{
-    uint16_t flags;
-    uint16_t idx;
-    uint16_t ring[0];
-} VRingAvail;
-
-typedef struct VRingUsedElem
-{
-    uint32_t id;
-    uint32_t len;
-} VRingUsedElem;
-
-typedef struct VRingUsed
-{
-    uint16_t flags;
-    uint16_t idx;
-    VRingUsedElem ring[0];
-} VRingUsed;
-
-typedef struct VRing
-{
-    unsigned int num;
-    hwaddr desc;
-    hwaddr avail;
-    hwaddr used;
-} VRing;
-
-struct VirtQueue
-{
-    VRing vring;
-    hwaddr pa;
-    uint16_t last_avail_idx;
-    /* Last used index value we have signalled on */
-    uint16_t signalled_used;
-
-    /* Last used index value we have signalled on */
-    bool signalled_used_valid;
-
-    /* Notification enabled? */
-    bool notification;
-
-    uint16_t queue_index;
-
-    int inuse;
-
-    uint16_t vector;
-    void (*handle_output)(VirtIODevice *vdev, VirtQueue *vq);
-    VirtIODevice *vdev;
-    EventNotifier guest_notifier;
-    EventNotifier host_notifier;
-};
-
-/* virt queue functions */
-static void virtqueue_init(VirtQueue *vq)
-{
-    hwaddr pa = vq->pa;
-
-    vq->vring.desc = pa;
-    vq->vring.avail = pa + vq->vring.num * sizeof(VRingDesc);
-    vq->vring.used = vring_align(vq->vring.avail +
-                                 offsetof(VRingAvail, ring[vq->vring.num]),
-                                 VIRTIO_PCI_VRING_ALIGN);
-}
-
-static inline uint64_t vring_desc_addr(hwaddr desc_pa, int i)
-{
-    hwaddr pa;
-    pa = desc_pa + sizeof(VRingDesc) * i + offsetof(VRingDesc, addr);
-    return ldq_phys(pa);
-}
-
-static inline uint32_t vring_desc_len(hwaddr desc_pa, int i)
-{
-    hwaddr pa;
-    pa = desc_pa + sizeof(VRingDesc) * i + offsetof(VRingDesc, len);
-    return ldl_phys(pa);
-}
-
-static inline uint16_t vring_desc_flags(hwaddr desc_pa, int i)
-{
-    hwaddr pa;
-    pa = desc_pa + sizeof(VRingDesc) * i + offsetof(VRingDesc, flags);
-    return lduw_phys(pa);
-}
-
-static inline uint16_t vring_desc_next(hwaddr desc_pa, int i)
-{
-    hwaddr pa;
-    pa = desc_pa + sizeof(VRingDesc) * i + offsetof(VRingDesc, next);
-    return lduw_phys(pa);
-}
-
-static inline uint16_t vring_avail_flags(VirtQueue *vq)
-{
-    hwaddr pa;
-    pa = vq->vring.avail + offsetof(VRingAvail, flags);
-    return lduw_phys(pa);
-}
-
-static inline uint16_t vring_avail_idx(VirtQueue *vq)
-{
-    hwaddr pa;
-    pa = vq->vring.avail + offsetof(VRingAvail, idx);
-    return lduw_phys(pa);
-}
-
-static inline uint16_t vring_avail_ring(VirtQueue *vq, int i)
-{
-    hwaddr pa;
-    pa = vq->vring.avail + offsetof(VRingAvail, ring[i]);
-    return lduw_phys(pa);
-}
-
-static inline uint16_t vring_used_event(VirtQueue *vq)
-{
-    return vring_avail_ring(vq, vq->vring.num);
-}
-
-static inline void vring_used_ring_id(VirtQueue *vq, int i, uint32_t val)
-{
-    hwaddr pa;
-    pa = vq->vring.used + offsetof(VRingUsed, ring[i].id);
-    stl_phys(pa, val);
-}
-
-static inline void vring_used_ring_len(VirtQueue *vq, int i, uint32_t val)
-{
-    hwaddr pa;
-    pa = vq->vring.used + offsetof(VRingUsed, ring[i].len);
-    stl_phys(pa, val);
-}
-
-static uint16_t vring_used_idx(VirtQueue *vq)
-{
-    hwaddr pa;
-    pa = vq->vring.used + offsetof(VRingUsed, idx);
-    return lduw_phys(pa);
-}
-
-static inline void vring_used_idx_set(VirtQueue *vq, uint16_t val)
-{
-    hwaddr pa;
-    pa = vq->vring.used + offsetof(VRingUsed, idx);
-    stw_phys(pa, val);
-}
-
-static inline void vring_used_flags_set_bit(VirtQueue *vq, int mask)
-{
-    hwaddr pa;
-    pa = vq->vring.used + offsetof(VRingUsed, flags);
-    stw_phys(pa, lduw_phys(pa) | mask);
-}
-
-static inline void vring_used_flags_unset_bit(VirtQueue *vq, int mask)
-{
-    hwaddr pa;
-    pa = vq->vring.used + offsetof(VRingUsed, flags);
-    stw_phys(pa, lduw_phys(pa) & ~mask);
-}
-
-static inline void vring_avail_event(VirtQueue *vq, uint16_t val)
-{
-    hwaddr pa;
-    if (!vq->notification) {
-        return;
-    }
-    pa = vq->vring.used + offsetof(VRingUsed, ring[vq->vring.num]);
-    stw_phys(pa, val);
-}
-
-void virtio_queue_set_notification(VirtQueue *vq, int enable)
-{
-    vq->notification = enable;
-    if (vq->vdev->guest_features & (1 << VIRTIO_RING_F_EVENT_IDX)) {
-        vring_avail_event(vq, vring_avail_idx(vq));
-    } else if (enable) {
-        vring_used_flags_unset_bit(vq, VRING_USED_F_NO_NOTIFY);
-    } else {
-        vring_used_flags_set_bit(vq, VRING_USED_F_NO_NOTIFY);
-    }
-    if (enable) {
-        /* Expose avail event/used flags before caller checks the avail idx. */
-        smp_mb();
-    }
-}
-
-int virtio_queue_ready(VirtQueue *vq)
-{
-    return vq->vring.avail != 0;
-}
-
-int virtio_queue_empty(VirtQueue *vq)
-{
-    return vring_avail_idx(vq) == vq->last_avail_idx;
-}
-
-void virtqueue_fill(VirtQueue *vq, const VirtQueueElement *elem,
-                    unsigned int len, unsigned int idx)
-{
-    unsigned int offset;
-    int i;
-
-    trace_virtqueue_fill(vq, elem, len, idx);
-
-    offset = 0;
-    for (i = 0; i < elem->in_num; i++) {
-        size_t size = MIN(len - offset, elem->in_sg[i].iov_len);
-
-        cpu_physical_memory_unmap(elem->in_sg[i].iov_base,
-                                  elem->in_sg[i].iov_len,
-                                  1, size);
-
-        offset += size;
-    }
-
-    for (i = 0; i < elem->out_num; i++)
-        cpu_physical_memory_unmap(elem->out_sg[i].iov_base,
-                                  elem->out_sg[i].iov_len,
-                                  0, elem->out_sg[i].iov_len);
-
-    idx = (idx + vring_used_idx(vq)) % vq->vring.num;
-
-    /* Get a pointer to the next entry in the used ring. */
-    vring_used_ring_id(vq, idx, elem->index);
-    vring_used_ring_len(vq, idx, len);
-}
-
-void virtqueue_flush(VirtQueue *vq, unsigned int count)
-{
-    uint16_t old, new;
-    /* Make sure buffer is written before we update index. */
-    smp_wmb();
-    trace_virtqueue_flush(vq, count);
-    old = vring_used_idx(vq);
-    new = old + count;
-    vring_used_idx_set(vq, new);
-    vq->inuse -= count;
-    if (unlikely((int16_t)(new - vq->signalled_used) < (uint16_t)(new - old)))
-        vq->signalled_used_valid = false;
-}
-
-void virtqueue_push(VirtQueue *vq, const VirtQueueElement *elem,
-                    unsigned int len)
-{
-    virtqueue_fill(vq, elem, len, 0);
-    virtqueue_flush(vq, 1);
-}
-
-static int virtqueue_num_heads(VirtQueue *vq, unsigned int idx)
-{
-    uint16_t num_heads = vring_avail_idx(vq) - idx;
-
-    /* Check it isn't doing very strange things with descriptor numbers. */
-    if (num_heads > vq->vring.num) {
-        error_report("Guest moved used index from %u to %u",
-                     idx, vring_avail_idx(vq));
-        exit(1);
-    }
-    /* On success, callers read a descriptor at vq->last_avail_idx.
-     * Make sure descriptor read does not bypass avail index read. */
-    if (num_heads) {
-        smp_rmb();
-    }
-
-    return num_heads;
-}
-
-static unsigned int virtqueue_get_head(VirtQueue *vq, unsigned int idx)
-{
-    unsigned int head;
-
-    /* Grab the next descriptor number they're advertising, and increment
-     * the index we've seen. */
-    head = vring_avail_ring(vq, idx % vq->vring.num);
-
-    /* If their number is silly, that's a fatal mistake. */
-    if (head >= vq->vring.num) {
-        error_report("Guest says index %u is available", head);
-        exit(1);
-    }
-
-    return head;
-}
-
-static unsigned virtqueue_next_desc(hwaddr desc_pa,
-                                    unsigned int i, unsigned int max)
-{
-    unsigned int next;
-
-    /* If this descriptor says it doesn't chain, we're done. */
-    if (!(vring_desc_flags(desc_pa, i) & VRING_DESC_F_NEXT))
-        return max;
-
-    /* Check they're not leading us off end of descriptors. */
-    next = vring_desc_next(desc_pa, i);
-    /* Make sure compiler knows to grab that: we don't want it changing! */
-    smp_wmb();
-
-    if (next >= max) {
-        error_report("Desc next is %u", next);
-        exit(1);
-    }
-
-    return next;
-}
-
-void virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes,
-                               unsigned int *out_bytes,
-                               unsigned max_in_bytes, unsigned max_out_bytes)
-{
-    unsigned int idx;
-    unsigned int total_bufs, in_total, out_total;
-
-    idx = vq->last_avail_idx;
-
-    total_bufs = in_total = out_total = 0;
-    while (virtqueue_num_heads(vq, idx)) {
-        unsigned int max, num_bufs, indirect = 0;
-        hwaddr desc_pa;
-        int i;
-
-        max = vq->vring.num;
-        num_bufs = total_bufs;
-        i = virtqueue_get_head(vq, idx++);
-        desc_pa = vq->vring.desc;
-
-        if (vring_desc_flags(desc_pa, i) & VRING_DESC_F_INDIRECT) {
-            if (vring_desc_len(desc_pa, i) % sizeof(VRingDesc)) {
-                error_report("Invalid size for indirect buffer table");
-                exit(1);
-            }
-
-            /* If we've got too many, that implies a descriptor loop. */
-            if (num_bufs >= max) {
-                error_report("Looped descriptor");
-                exit(1);
-            }
-
-            /* loop over the indirect descriptor table */
-            indirect = 1;
-            max = vring_desc_len(desc_pa, i) / sizeof(VRingDesc);
-            num_bufs = i = 0;
-            desc_pa = vring_desc_addr(desc_pa, i);
-        }
-
-        do {
-            /* If we've got too many, that implies a descriptor loop. */
-            if (++num_bufs > max) {
-                error_report("Looped descriptor");
-                exit(1);
-            }
-
-            if (vring_desc_flags(desc_pa, i) & VRING_DESC_F_WRITE) {
-                in_total += vring_desc_len(desc_pa, i);
-            } else {
-                out_total += vring_desc_len(desc_pa, i);
-            }
-            if (in_total >= max_in_bytes && out_total >= max_out_bytes) {
-                goto done;
-            }
-        } while ((i = virtqueue_next_desc(desc_pa, i, max)) != max);
-
-        if (!indirect)
-            total_bufs = num_bufs;
-        else
-            total_bufs++;
-    }
-done:
-    if (in_bytes) {
-        *in_bytes = in_total;
-    }
-    if (out_bytes) {
-        *out_bytes = out_total;
-    }
-}
-
-int virtqueue_avail_bytes(VirtQueue *vq, unsigned int in_bytes,
-                          unsigned int out_bytes)
-{
-    unsigned int in_total, out_total;
-
-    virtqueue_get_avail_bytes(vq, &in_total, &out_total, in_bytes, out_bytes);
-    return in_bytes <= in_total && out_bytes <= out_total;
-}
-
-void virtqueue_map_sg(struct iovec *sg, hwaddr *addr,
-    size_t num_sg, int is_write)
-{
-    unsigned int i;
-    hwaddr len;
-
-    for (i = 0; i < num_sg; i++) {
-        len = sg[i].iov_len;
-        sg[i].iov_base = cpu_physical_memory_map(addr[i], &len, is_write);
-        if (sg[i].iov_base == NULL || len != sg[i].iov_len) {
-            error_report("virtio: trying to map MMIO memory");
-            exit(1);
-        }
-    }
-}
-
-int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem)
-{
-    unsigned int i, head, max;
-    hwaddr desc_pa = vq->vring.desc;
-
-    if (!virtqueue_num_heads(vq, vq->last_avail_idx))
-        return 0;
-
-    /* When we start there are none of either input nor output. */
-    elem->out_num = elem->in_num = 0;
-
-    max = vq->vring.num;
-
-    i = head = virtqueue_get_head(vq, vq->last_avail_idx++);
-    if (vq->vdev->guest_features & (1 << VIRTIO_RING_F_EVENT_IDX)) {
-        vring_avail_event(vq, vring_avail_idx(vq));
-    }
-
-    if (vring_desc_flags(desc_pa, i) & VRING_DESC_F_INDIRECT) {
-        if (vring_desc_len(desc_pa, i) % sizeof(VRingDesc)) {
-            error_report("Invalid size for indirect buffer table");
-            exit(1);
-        }
-
-        /* loop over the indirect descriptor table */
-        max = vring_desc_len(desc_pa, i) / sizeof(VRingDesc);
-        desc_pa = vring_desc_addr(desc_pa, i);
-        i = 0;
-    }
-
-    /* Collect all the descriptors */
-    do {
-        struct iovec *sg;
-
-        if (vring_desc_flags(desc_pa, i) & VRING_DESC_F_WRITE) {
-            if (elem->in_num >= ARRAY_SIZE(elem->in_sg)) {
-                error_report("Too many write descriptors in indirect table");
-                exit(1);
-            }
-            elem->in_addr[elem->in_num] = vring_desc_addr(desc_pa, i);
-            sg = &elem->in_sg[elem->in_num++];
-        } else {
-            if (elem->out_num >= ARRAY_SIZE(elem->out_sg)) {
-                error_report("Too many read descriptors in indirect table");
-                exit(1);
-            }
-            elem->out_addr[elem->out_num] = vring_desc_addr(desc_pa, i);
-            sg = &elem->out_sg[elem->out_num++];
-        }
-
-        sg->iov_len = vring_desc_len(desc_pa, i);
-
-        /* If we've got too many, that implies a descriptor loop. */
-        if ((elem->in_num + elem->out_num) > max) {
-            error_report("Looped descriptor");
-            exit(1);
-        }
-    } while ((i = virtqueue_next_desc(desc_pa, i, max)) != max);
-
-    /* Now map what we have collected */
-    virtqueue_map_sg(elem->in_sg, elem->in_addr, elem->in_num, 1);
-    virtqueue_map_sg(elem->out_sg, elem->out_addr, elem->out_num, 0);
-
-    elem->index = head;
-
-    vq->inuse++;
-
-    trace_virtqueue_pop(vq, elem, elem->in_num, elem->out_num);
-    return elem->in_num + elem->out_num;
-}
-
-/* virtio device */
-static void virtio_notify_vector(VirtIODevice *vdev, uint16_t vector)
-{
-    if (vdev->binding->notify) {
-        vdev->binding->notify(vdev->binding_opaque, vector);
-    }
-}
-
-void virtio_update_irq(VirtIODevice *vdev)
-{
-    virtio_notify_vector(vdev, VIRTIO_NO_VECTOR);
-}
-
-void virtio_set_status(VirtIODevice *vdev, uint8_t val)
-{
-    trace_virtio_set_status(vdev, val);
-
-    if (vdev->set_status) {
-        vdev->set_status(vdev, val);
-    }
-    vdev->status = val;
-}
-
-void virtio_reset(void *opaque)
-{
-    VirtIODevice *vdev = opaque;
-    int i;
-
-    virtio_set_status(vdev, 0);
-
-    if (vdev->reset)
-        vdev->reset(vdev);
-
-    vdev->guest_features = 0;
-    vdev->queue_sel = 0;
-    vdev->status = 0;
-    vdev->isr = 0;
-    vdev->config_vector = VIRTIO_NO_VECTOR;
-    virtio_notify_vector(vdev, vdev->config_vector);
-
-    for(i = 0; i < VIRTIO_PCI_QUEUE_MAX; i++) {
-        vdev->vq[i].vring.desc = 0;
-        vdev->vq[i].vring.avail = 0;
-        vdev->vq[i].vring.used = 0;
-        vdev->vq[i].last_avail_idx = 0;
-        vdev->vq[i].pa = 0;
-        vdev->vq[i].vector = VIRTIO_NO_VECTOR;
-        vdev->vq[i].signalled_used = 0;
-        vdev->vq[i].signalled_used_valid = false;
-        vdev->vq[i].notification = true;
-    }
-}
-
-uint32_t virtio_config_readb(VirtIODevice *vdev, uint32_t addr)
-{
-    uint8_t val;
-
-    vdev->get_config(vdev, vdev->config);
-
-    if (addr > (vdev->config_len - sizeof(val)))
-        return (uint32_t)-1;
-
-    val = ldub_p(vdev->config + addr);
-    return val;
-}
-
-uint32_t virtio_config_readw(VirtIODevice *vdev, uint32_t addr)
-{
-    uint16_t val;
-
-    vdev->get_config(vdev, vdev->config);
-
-    if (addr > (vdev->config_len - sizeof(val)))
-        return (uint32_t)-1;
-
-    val = lduw_p(vdev->config + addr);
-    return val;
-}
-
-uint32_t virtio_config_readl(VirtIODevice *vdev, uint32_t addr)
-{
-    uint32_t val;
-
-    vdev->get_config(vdev, vdev->config);
-
-    if (addr > (vdev->config_len - sizeof(val)))
-        return (uint32_t)-1;
-
-    val = ldl_p(vdev->config + addr);
-    return val;
-}
-
-void virtio_config_writeb(VirtIODevice *vdev, uint32_t addr, uint32_t data)
-{
-    uint8_t val = data;
-
-    if (addr > (vdev->config_len - sizeof(val)))
-        return;
-
-    stb_p(vdev->config + addr, val);
-
-    if (vdev->set_config)
-        vdev->set_config(vdev, vdev->config);
-}
-
-void virtio_config_writew(VirtIODevice *vdev, uint32_t addr, uint32_t data)
-{
-    uint16_t val = data;
-
-    if (addr > (vdev->config_len - sizeof(val)))
-        return;
-
-    stw_p(vdev->config + addr, val);
-
-    if (vdev->set_config)
-        vdev->set_config(vdev, vdev->config);
-}
-
-void virtio_config_writel(VirtIODevice *vdev, uint32_t addr, uint32_t data)
-{
-    uint32_t val = data;
-
-    if (addr > (vdev->config_len - sizeof(val)))
-        return;
-
-    stl_p(vdev->config + addr, val);
-
-    if (vdev->set_config)
-        vdev->set_config(vdev, vdev->config);
-}
-
-void virtio_queue_set_addr(VirtIODevice *vdev, int n, hwaddr addr)
-{
-    vdev->vq[n].pa = addr;
-    virtqueue_init(&vdev->vq[n]);
-}
-
-hwaddr virtio_queue_get_addr(VirtIODevice *vdev, int n)
-{
-    return vdev->vq[n].pa;
-}
-
-int virtio_queue_get_num(VirtIODevice *vdev, int n)
-{
-    return vdev->vq[n].vring.num;
-}
-
-int virtio_queue_get_id(VirtQueue *vq)
-{
-    VirtIODevice *vdev = vq->vdev;
-    assert(vq >= &vdev->vq[0] && vq < &vdev->vq[VIRTIO_PCI_QUEUE_MAX]);
-    return vq - &vdev->vq[0];
-}
-
-void virtio_queue_notify_vq(VirtQueue *vq)
-{
-    if (vq->vring.desc) {
-        VirtIODevice *vdev = vq->vdev;
-        trace_virtio_queue_notify(vdev, vq - vdev->vq, vq);
-        vq->handle_output(vdev, vq);
-    }
-}
-
-void virtio_queue_notify(VirtIODevice *vdev, int n)
-{
-    virtio_queue_notify_vq(&vdev->vq[n]);
-}
-
-uint16_t virtio_queue_vector(VirtIODevice *vdev, int n)
-{
-    return n < VIRTIO_PCI_QUEUE_MAX ? vdev->vq[n].vector :
-        VIRTIO_NO_VECTOR;
-}
-
-void virtio_queue_set_vector(VirtIODevice *vdev, int n, uint16_t vector)
-{
-    if (n < VIRTIO_PCI_QUEUE_MAX)
-        vdev->vq[n].vector = vector;
-}
-
-VirtQueue *virtio_add_queue(VirtIODevice *vdev, int queue_size,
-                            void (*handle_output)(VirtIODevice *, VirtQueue *))
-{
-    int i;
-
-    for (i = 0; i < VIRTIO_PCI_QUEUE_MAX; i++) {
-        if (vdev->vq[i].vring.num == 0)
-            break;
-    }
-
-    if (i == VIRTIO_PCI_QUEUE_MAX || queue_size > VIRTQUEUE_MAX_SIZE)
-        abort();
-
-    vdev->vq[i].vring.num = queue_size;
-    vdev->vq[i].handle_output = handle_output;
-
-    return &vdev->vq[i];
-}
-
-void virtio_del_queue(VirtIODevice *vdev, int n)
-{
-    if (n < 0 || n >= VIRTIO_PCI_QUEUE_MAX) {
-        abort();
-    }
-
-    vdev->vq[n].vring.num = 0;
-}
-
-void virtio_irq(VirtQueue *vq)
-{
-    trace_virtio_irq(vq);
-    vq->vdev->isr |= 0x01;
-    virtio_notify_vector(vq->vdev, vq->vector);
-}
-
-/* Assuming a given event_idx value from the other size, if
- * we have just incremented index from old to new_idx,
- * should we trigger an event? */
-static inline int vring_need_event(uint16_t event, uint16_t new, uint16_t old)
-{
-       /* Note: Xen has similar logic for notification hold-off
-        * in include/xen/interface/io/ring.h with req_event and req_prod
-        * corresponding to event_idx + 1 and new respectively.
-        * Note also that req_event and req_prod in Xen start at 1,
-        * event indexes in virtio start at 0. */
-       return (uint16_t)(new - event - 1) < (uint16_t)(new - old);
-}
-
-static bool vring_notify(VirtIODevice *vdev, VirtQueue *vq)
-{
-    uint16_t old, new;
-    bool v;
-    /* We need to expose used array entries before checking used event. */
-    smp_mb();
-    /* Always notify when queue is empty (when feature acknowledge) */
-    if (((vdev->guest_features & (1 << VIRTIO_F_NOTIFY_ON_EMPTY)) &&
-         !vq->inuse && vring_avail_idx(vq) == vq->last_avail_idx)) {
-        return true;
-    }
-
-    if (!(vdev->guest_features & (1 << VIRTIO_RING_F_EVENT_IDX))) {
-        return !(vring_avail_flags(vq) & VRING_AVAIL_F_NO_INTERRUPT);
-    }
-
-    v = vq->signalled_used_valid;
-    vq->signalled_used_valid = true;
-    old = vq->signalled_used;
-    new = vq->signalled_used = vring_used_idx(vq);
-    return !v || vring_need_event(vring_used_event(vq), new, old);
-}
-
-void virtio_notify(VirtIODevice *vdev, VirtQueue *vq)
-{
-    if (!vring_notify(vdev, vq)) {
-        return;
-    }
-
-    trace_virtio_notify(vdev, vq);
-    vdev->isr |= 0x01;
-    virtio_notify_vector(vdev, vq->vector);
-}
-
-void virtio_notify_config(VirtIODevice *vdev)
-{
-    if (!(vdev->status & VIRTIO_CONFIG_S_DRIVER_OK))
-        return;
-
-    vdev->isr |= 0x03;
-    virtio_notify_vector(vdev, vdev->config_vector);
-}
-
-void virtio_save(VirtIODevice *vdev, QEMUFile *f)
-{
-    int i;
-
-    if (vdev->binding->save_config)
-        vdev->binding->save_config(vdev->binding_opaque, f);
-
-    qemu_put_8s(f, &vdev->status);
-    qemu_put_8s(f, &vdev->isr);
-    qemu_put_be16s(f, &vdev->queue_sel);
-    qemu_put_be32s(f, &vdev->guest_features);
-    qemu_put_be32(f, vdev->config_len);
-    qemu_put_buffer(f, vdev->config, vdev->config_len);
-
-    for (i = 0; i < VIRTIO_PCI_QUEUE_MAX; i++) {
-        if (vdev->vq[i].vring.num == 0)
-            break;
-    }
-
-    qemu_put_be32(f, i);
-
-    for (i = 0; i < VIRTIO_PCI_QUEUE_MAX; i++) {
-        if (vdev->vq[i].vring.num == 0)
-            break;
-
-        qemu_put_be32(f, vdev->vq[i].vring.num);
-        qemu_put_be64(f, vdev->vq[i].pa);
-        qemu_put_be16s(f, &vdev->vq[i].last_avail_idx);
-        if (vdev->binding->save_queue)
-            vdev->binding->save_queue(vdev->binding_opaque, i, f);
-    }
-}
-
-int virtio_set_features(VirtIODevice *vdev, uint32_t val)
-{
-    uint32_t supported_features =
-        vdev->binding->get_features(vdev->binding_opaque);
-    bool bad = (val & ~supported_features) != 0;
-
-    val &= supported_features;
-    if (vdev->set_features) {
-        vdev->set_features(vdev, val);
-    }
-    vdev->guest_features = val;
-    return bad ? -1 : 0;
-}
-
-int virtio_load(VirtIODevice *vdev, QEMUFile *f)
-{
-    int num, i, ret;
-    uint32_t features;
-    uint32_t supported_features;
-
-    if (vdev->binding->load_config) {
-        ret = vdev->binding->load_config(vdev->binding_opaque, f);
-        if (ret)
-            return ret;
-    }
-
-    qemu_get_8s(f, &vdev->status);
-    qemu_get_8s(f, &vdev->isr);
-    qemu_get_be16s(f, &vdev->queue_sel);
-    qemu_get_be32s(f, &features);
-
-    if (virtio_set_features(vdev, features) < 0) {
-        supported_features = vdev->binding->get_features(vdev->binding_opaque);
-        error_report("Features 0x%x unsupported. Allowed features: 0x%x",
-                     features, supported_features);
-        return -1;
-    }
-    vdev->config_len = qemu_get_be32(f);
-    qemu_get_buffer(f, vdev->config, vdev->config_len);
-
-    num = qemu_get_be32(f);
-
-    for (i = 0; i < num; i++) {
-        vdev->vq[i].vring.num = qemu_get_be32(f);
-        vdev->vq[i].pa = qemu_get_be64(f);
-        qemu_get_be16s(f, &vdev->vq[i].last_avail_idx);
-        vdev->vq[i].signalled_used_valid = false;
-        vdev->vq[i].notification = true;
-
-        if (vdev->vq[i].pa) {
-            uint16_t nheads;
-            virtqueue_init(&vdev->vq[i]);
-            nheads = vring_avail_idx(&vdev->vq[i]) - vdev->vq[i].last_avail_idx;
-            /* Check it isn't doing very strange things with descriptor numbers. */
-            if (nheads > vdev->vq[i].vring.num) {
-                error_report("VQ %d size 0x%x Guest index 0x%x "
-                             "inconsistent with Host index 0x%x: delta 0x%x",
-                             i, vdev->vq[i].vring.num,
-                             vring_avail_idx(&vdev->vq[i]),
-                             vdev->vq[i].last_avail_idx, nheads);
-                return -1;
-            }
-        } else if (vdev->vq[i].last_avail_idx) {
-            error_report("VQ %d address 0x0 "
-                         "inconsistent with Host index 0x%x",
-                         i, vdev->vq[i].last_avail_idx);
-                return -1;
-       }
-        if (vdev->binding->load_queue) {
-            ret = vdev->binding->load_queue(vdev->binding_opaque, i, f);
-            if (ret)
-                return ret;
-        }
-    }
-
-    virtio_notify_vector(vdev, VIRTIO_NO_VECTOR);
-    return 0;
-}
-
-void virtio_common_cleanup(VirtIODevice *vdev)
-{
-    qemu_del_vm_change_state_handler(vdev->vmstate);
-    g_free(vdev->config);
-    g_free(vdev->vq);
-}
-
-void virtio_cleanup(VirtIODevice *vdev)
-{
-    virtio_common_cleanup(vdev);
-    g_free(vdev);
-}
-
-static void virtio_vmstate_change(void *opaque, int running, RunState state)
-{
-    VirtIODevice *vdev = opaque;
-    bool backend_run = running && (vdev->status & VIRTIO_CONFIG_S_DRIVER_OK);
-    vdev->vm_running = running;
-
-    if (backend_run) {
-        virtio_set_status(vdev, vdev->status);
-    }
-
-    if (vdev->binding->vmstate_change) {
-        vdev->binding->vmstate_change(vdev->binding_opaque, backend_run);
-    }
-
-    if (!backend_run) {
-        virtio_set_status(vdev, vdev->status);
-    }
-}
-
-void virtio_init(VirtIODevice *vdev, const char *name,
-                 uint16_t device_id, size_t config_size)
-{
-    int i;
-    vdev->device_id = device_id;
-    vdev->status = 0;
-    vdev->isr = 0;
-    vdev->queue_sel = 0;
-    vdev->config_vector = VIRTIO_NO_VECTOR;
-    vdev->vq = g_malloc0(sizeof(VirtQueue) * VIRTIO_PCI_QUEUE_MAX);
-    vdev->vm_running = runstate_is_running();
-    for (i = 0; i < VIRTIO_PCI_QUEUE_MAX; i++) {
-        vdev->vq[i].vector = VIRTIO_NO_VECTOR;
-        vdev->vq[i].vdev = vdev;
-        vdev->vq[i].queue_index = i;
-    }
-
-    vdev->name = name;
-    vdev->config_len = config_size;
-    if (vdev->config_len) {
-        vdev->config = g_malloc0(config_size);
-    } else {
-        vdev->config = NULL;
-    }
-    vdev->vmstate = qemu_add_vm_change_state_handler(virtio_vmstate_change,
-                                                     vdev);
-}
-
-VirtIODevice *virtio_common_init(const char *name, uint16_t device_id,
-                                 size_t config_size, size_t struct_size)
-{
-    VirtIODevice *vdev;
-    vdev = g_malloc0(struct_size);
-    virtio_init(vdev, name, device_id, config_size);
-    return vdev;
-}
-
-void virtio_bind_device(VirtIODevice *vdev, const VirtIOBindings *binding,
-                        DeviceState *opaque)
-{
-    vdev->binding = binding;
-    vdev->binding_opaque = opaque;
-}
-
-hwaddr virtio_queue_get_desc_addr(VirtIODevice *vdev, int n)
-{
-    return vdev->vq[n].vring.desc;
-}
-
-hwaddr virtio_queue_get_avail_addr(VirtIODevice *vdev, int n)
-{
-    return vdev->vq[n].vring.avail;
-}
-
-hwaddr virtio_queue_get_used_addr(VirtIODevice *vdev, int n)
-{
-    return vdev->vq[n].vring.used;
-}
-
-hwaddr virtio_queue_get_ring_addr(VirtIODevice *vdev, int n)
-{
-    return vdev->vq[n].vring.desc;
-}
-
-hwaddr virtio_queue_get_desc_size(VirtIODevice *vdev, int n)
-{
-    return sizeof(VRingDesc) * vdev->vq[n].vring.num;
-}
-
-hwaddr virtio_queue_get_avail_size(VirtIODevice *vdev, int n)
-{
-    return offsetof(VRingAvail, ring) +
-        sizeof(uint64_t) * vdev->vq[n].vring.num;
-}
-
-hwaddr virtio_queue_get_used_size(VirtIODevice *vdev, int n)
-{
-    return offsetof(VRingUsed, ring) +
-        sizeof(VRingUsedElem) * vdev->vq[n].vring.num;
-}
-
-hwaddr virtio_queue_get_ring_size(VirtIODevice *vdev, int n)
-{
-    return vdev->vq[n].vring.used - vdev->vq[n].vring.desc +
-           virtio_queue_get_used_size(vdev, n);
-}
-
-uint16_t virtio_queue_get_last_avail_idx(VirtIODevice *vdev, int n)
-{
-    return vdev->vq[n].last_avail_idx;
-}
-
-void virtio_queue_set_last_avail_idx(VirtIODevice *vdev, int n, uint16_t idx)
-{
-    vdev->vq[n].last_avail_idx = idx;
-}
-
-VirtQueue *virtio_get_queue(VirtIODevice *vdev, int n)
-{
-    return vdev->vq + n;
-}
-
-uint16_t virtio_get_queue_index(VirtQueue *vq)
-{
-    return vq->queue_index;
-}
-
-static void virtio_queue_guest_notifier_read(EventNotifier *n)
-{
-    VirtQueue *vq = container_of(n, VirtQueue, guest_notifier);
-    if (event_notifier_test_and_clear(n)) {
-        virtio_irq(vq);
-    }
-}
-
-void virtio_queue_set_guest_notifier_fd_handler(VirtQueue *vq, bool assign,
-                                                bool with_irqfd)
-{
-    if (assign && !with_irqfd) {
-        event_notifier_set_handler(&vq->guest_notifier,
-                                   virtio_queue_guest_notifier_read);
-    } else {
-        event_notifier_set_handler(&vq->guest_notifier, NULL);
-    }
-    if (!assign) {
-        /* Test and clear notifier before closing it,
-         * in case poll callback didn't have time to run. */
-        virtio_queue_guest_notifier_read(&vq->guest_notifier);
-    }
-}
-
-EventNotifier *virtio_queue_get_guest_notifier(VirtQueue *vq)
-{
-    return &vq->guest_notifier;
-}
-
-static void virtio_queue_host_notifier_read(EventNotifier *n)
-{
-    VirtQueue *vq = container_of(n, VirtQueue, host_notifier);
-    if (event_notifier_test_and_clear(n)) {
-        virtio_queue_notify_vq(vq);
-    }
-}
-
-void virtio_queue_set_host_notifier_fd_handler(VirtQueue *vq, bool assign,
-                                               bool set_handler)
-{
-    if (assign && set_handler) {
-        event_notifier_set_handler(&vq->host_notifier,
-                                   virtio_queue_host_notifier_read);
-    } else {
-        event_notifier_set_handler(&vq->host_notifier, NULL);
-    }
-    if (!assign) {
-        /* Test and clear notifier before after disabling event,
-         * in case poll callback didn't have time to run. */
-        virtio_queue_host_notifier_read(&vq->host_notifier);
-    }
-}
-
-EventNotifier *virtio_queue_get_host_notifier(VirtQueue *vq)
-{
-    return &vq->host_notifier;
-}
-
-static int virtio_device_init(DeviceState *qdev)
-{
-    VirtIODevice *vdev = VIRTIO_DEVICE(qdev);
-    VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(qdev);
-    assert(k->init != NULL);
-    if (k->init(vdev) < 0) {
-        return -1;
-    }
-    virtio_bus_plug_device(vdev);
-    return 0;
-}
-
-static void virtio_device_class_init(ObjectClass *klass, void *data)
-{
-    /* Set the default value here. */
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    dc->init = virtio_device_init;
-    dc->bus_type = TYPE_VIRTIO_BUS;
-}
-
-static const TypeInfo virtio_device_info = {
-    .name = TYPE_VIRTIO_DEVICE,
-    .parent = TYPE_DEVICE,
-    .instance_size = sizeof(VirtIODevice),
-    .class_init = virtio_device_class_init,
-    .abstract = true,
-    .class_size = sizeof(VirtioDeviceClass),
-};
-
-static void virtio_register_types(void)
-{
-    type_register_static(&virtio_device_info);
-}
-
-type_init(virtio_register_types)
diff --git a/hw/virtio.h b/hw/virtio.h
deleted file mode 100644 (file)
index fdbe931..0000000
+++ /dev/null
@@ -1,292 +0,0 @@
-/*
- * Virtio Support
- *
- * Copyright IBM, Corp. 2007
- *
- * Authors:
- *  Anthony Liguori   <aliguori@us.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2.  See
- * the COPYING file in the top-level directory.
- *
- */
-
-#ifndef _QEMU_VIRTIO_H
-#define _QEMU_VIRTIO_H
-
-#include "hw/hw.h"
-#include "net/net.h"
-#include "hw/qdev.h"
-#include "sysemu/sysemu.h"
-#include "qemu/event_notifier.h"
-#ifdef CONFIG_VIRTFS
-#include "hw/9pfs/virtio-9p-device.h"
-#endif
-
-/* from Linux's linux/virtio_config.h */
-
-/* Status byte for guest to report progress, and synchronize features. */
-/* We have seen device and processed generic fields (VIRTIO_CONFIG_F_VIRTIO) */
-#define VIRTIO_CONFIG_S_ACKNOWLEDGE     1
-/* We have found a driver for the device. */
-#define VIRTIO_CONFIG_S_DRIVER          2
-/* Driver has used its parts of the config, and is happy */
-#define VIRTIO_CONFIG_S_DRIVER_OK       4
-/* We've given up on this device. */
-#define VIRTIO_CONFIG_S_FAILED          0x80
-
-/* Some virtio feature bits (currently bits 28 through 31) are reserved for the
- * transport being used (eg. virtio_ring), the rest are per-device feature bits. */
-#define VIRTIO_TRANSPORT_F_START        28
-#define VIRTIO_TRANSPORT_F_END          32
-
-/* We notify when the ring is completely used, even if the guest is suppressing
- * callbacks */
-#define VIRTIO_F_NOTIFY_ON_EMPTY        24
-/* We support indirect buffer descriptors */
-#define VIRTIO_RING_F_INDIRECT_DESC     28
-/* The Guest publishes the used index for which it expects an interrupt
- * at the end of the avail ring. Host should ignore the avail->flags field. */
-/* The Host publishes the avail index for which it expects a kick
- * at the end of the used ring. Guest should ignore the used->flags field. */
-#define VIRTIO_RING_F_EVENT_IDX         29
-/* A guest should never accept this.  It implies negotiation is broken. */
-#define VIRTIO_F_BAD_FEATURE           30
-
-/* from Linux's linux/virtio_ring.h */
-
-/* This marks a buffer as continuing via the next field. */
-#define VRING_DESC_F_NEXT       1
-/* This marks a buffer as write-only (otherwise read-only). */
-#define VRING_DESC_F_WRITE      2
-/* This means the buffer contains a list of buffer descriptors. */
-#define VRING_DESC_F_INDIRECT  4
-
-/* This means don't notify other side when buffer added. */
-#define VRING_USED_F_NO_NOTIFY  1
-/* This means don't interrupt guest when buffer consumed. */
-#define VRING_AVAIL_F_NO_INTERRUPT      1
-
-struct VirtQueue;
-
-static inline hwaddr vring_align(hwaddr addr,
-                                             unsigned long align)
-{
-    return (addr + align - 1) & ~(align - 1);
-}
-
-typedef struct VirtQueue VirtQueue;
-
-#define VIRTQUEUE_MAX_SIZE 1024
-
-typedef struct VirtQueueElement
-{
-    unsigned int index;
-    unsigned int out_num;
-    unsigned int in_num;
-    hwaddr in_addr[VIRTQUEUE_MAX_SIZE];
-    hwaddr out_addr[VIRTQUEUE_MAX_SIZE];
-    struct iovec in_sg[VIRTQUEUE_MAX_SIZE];
-    struct iovec out_sg[VIRTQUEUE_MAX_SIZE];
-} VirtQueueElement;
-
-typedef struct {
-    void (*notify)(DeviceState *d, uint16_t vector);
-    void (*save_config)(DeviceState *d, QEMUFile *f);
-    void (*save_queue)(DeviceState *d, int n, QEMUFile *f);
-    int (*load_config)(DeviceState *d, QEMUFile *f);
-    int (*load_queue)(DeviceState *d, int n, QEMUFile *f);
-    int (*load_done)(DeviceState *d, QEMUFile *f);
-    unsigned (*get_features)(DeviceState *d);
-    bool (*query_guest_notifiers)(DeviceState *d);
-    int (*set_guest_notifiers)(DeviceState *d, int nvqs, bool assigned);
-    int (*set_host_notifier)(DeviceState *d, int n, bool assigned);
-    void (*vmstate_change)(DeviceState *d, bool running);
-} VirtIOBindings;
-
-#define VIRTIO_PCI_QUEUE_MAX 64
-
-#define VIRTIO_NO_VECTOR 0xffff
-
-#define TYPE_VIRTIO_DEVICE "virtio-device"
-#define VIRTIO_DEVICE_GET_CLASS(obj) \
-        OBJECT_GET_CLASS(VirtioDeviceClass, obj, TYPE_VIRTIO_DEVICE)
-#define VIRTIO_DEVICE_CLASS(klass) \
-        OBJECT_CLASS_CHECK(VirtioDeviceClass, klass, TYPE_VIRTIO_DEVICE)
-#define VIRTIO_DEVICE(obj) \
-        OBJECT_CHECK(VirtIODevice, (obj), TYPE_VIRTIO_DEVICE)
-
-struct VirtIODevice
-{
-    DeviceState parent_obj;
-    const char *name;
-    uint8_t status;
-    uint8_t isr;
-    uint16_t queue_sel;
-    uint32_t guest_features;
-    size_t config_len;
-    void *config;
-    uint16_t config_vector;
-    int nvectors;
-    /*
-     * Function pointers will be removed at the end of the series as they are in
-     * VirtioDeviceClass.
-     */
-    uint32_t (*get_features)(VirtIODevice *vdev, uint32_t requested_features);
-    uint32_t (*bad_features)(VirtIODevice *vdev);
-    void (*set_features)(VirtIODevice *vdev, uint32_t val);
-    void (*get_config)(VirtIODevice *vdev, uint8_t *config);
-    void (*set_config)(VirtIODevice *vdev, const uint8_t *config);
-    void (*reset)(VirtIODevice *vdev);
-    void (*set_status)(VirtIODevice *vdev, uint8_t val);
-    /* Test and clear event pending status.
-     * Should be called after unmask to avoid losing events.
-     * If backend does not support masking,
-     * must check in frontend instead.
-     */
-    bool (*guest_notifier_pending)(VirtIODevice *vdev, int n);
-    /* Mask/unmask events from this vq. Any events reported
-     * while masked will become pending.
-     * If backend does not support masking,
-     * must mask in frontend instead.
-     */
-    void (*guest_notifier_mask)(VirtIODevice *vdev, int n, bool mask);
-
-    VirtQueue *vq;
-    const VirtIOBindings *binding;
-    DeviceState *binding_opaque;
-    uint16_t device_id;
-    bool vm_running;
-    VMChangeStateEntry *vmstate;
-};
-
-typedef struct VirtioDeviceClass {
-    /* This is what a VirtioDevice must implement */
-    DeviceClass parent;
-    int (*init)(VirtIODevice *vdev);
-    uint32_t (*get_features)(VirtIODevice *vdev, uint32_t requested_features);
-    uint32_t (*bad_features)(VirtIODevice *vdev);
-    void (*set_features)(VirtIODevice *vdev, uint32_t val);
-    void (*get_config)(VirtIODevice *vdev, uint8_t *config);
-    void (*set_config)(VirtIODevice *vdev, const uint8_t *config);
-    void (*reset)(VirtIODevice *vdev);
-    void (*set_status)(VirtIODevice *vdev, uint8_t val);
-} VirtioDeviceClass;
-
-void virtio_init(VirtIODevice *vdev, const char *name,
-                         uint16_t device_id, size_t config_size);
-void virtio_common_cleanup(VirtIODevice *vdev);
-
-VirtQueue *virtio_add_queue(VirtIODevice *vdev, int queue_size,
-                            void (*handle_output)(VirtIODevice *,
-                                                  VirtQueue *));
-
-void virtio_del_queue(VirtIODevice *vdev, int n);
-
-void virtqueue_push(VirtQueue *vq, const VirtQueueElement *elem,
-                    unsigned int len);
-void virtqueue_flush(VirtQueue *vq, unsigned int count);
-void virtqueue_fill(VirtQueue *vq, const VirtQueueElement *elem,
-                    unsigned int len, unsigned int idx);
-
-void virtqueue_map_sg(struct iovec *sg, hwaddr *addr,
-    size_t num_sg, int is_write);
-int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem);
-int virtqueue_avail_bytes(VirtQueue *vq, unsigned int in_bytes,
-                          unsigned int out_bytes);
-void virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes,
-                               unsigned int *out_bytes,
-                               unsigned max_in_bytes, unsigned max_out_bytes);
-
-void virtio_notify(VirtIODevice *vdev, VirtQueue *vq);
-
-void virtio_save(VirtIODevice *vdev, QEMUFile *f);
-
-int virtio_load(VirtIODevice *vdev, QEMUFile *f);
-
-void virtio_cleanup(VirtIODevice *vdev);
-
-void virtio_notify_config(VirtIODevice *vdev);
-
-void virtio_queue_set_notification(VirtQueue *vq, int enable);
-
-int virtio_queue_ready(VirtQueue *vq);
-
-int virtio_queue_empty(VirtQueue *vq);
-
-/* Host binding interface.  */
-
-VirtIODevice *virtio_common_init(const char *name, uint16_t device_id,
-                                 size_t config_size, size_t struct_size);
-uint32_t virtio_config_readb(VirtIODevice *vdev, uint32_t addr);
-uint32_t virtio_config_readw(VirtIODevice *vdev, uint32_t addr);
-uint32_t virtio_config_readl(VirtIODevice *vdev, uint32_t addr);
-void virtio_config_writeb(VirtIODevice *vdev, uint32_t addr, uint32_t data);
-void virtio_config_writew(VirtIODevice *vdev, uint32_t addr, uint32_t data);
-void virtio_config_writel(VirtIODevice *vdev, uint32_t addr, uint32_t data);
-void virtio_queue_set_addr(VirtIODevice *vdev, int n, hwaddr addr);
-hwaddr virtio_queue_get_addr(VirtIODevice *vdev, int n);
-int virtio_queue_get_num(VirtIODevice *vdev, int n);
-void virtio_queue_notify(VirtIODevice *vdev, int n);
-uint16_t virtio_queue_vector(VirtIODevice *vdev, int n);
-void virtio_queue_set_vector(VirtIODevice *vdev, int n, uint16_t vector);
-void virtio_set_status(VirtIODevice *vdev, uint8_t val);
-void virtio_reset(void *opaque);
-void virtio_update_irq(VirtIODevice *vdev);
-int virtio_set_features(VirtIODevice *vdev, uint32_t val);
-
-void virtio_bind_device(VirtIODevice *vdev, const VirtIOBindings *binding,
-                        DeviceState *opaque);
-
-/* Base devices.  */
-typedef struct VirtIOBlkConf VirtIOBlkConf;
-struct virtio_net_conf;
-VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf,
-                              struct virtio_net_conf *net,
-                              uint32_t host_features);
-typedef struct virtio_serial_conf virtio_serial_conf;
-VirtIODevice *virtio_serial_init(DeviceState *dev, virtio_serial_conf *serial);
-VirtIODevice *virtio_balloon_init(DeviceState *dev);
-typedef struct VirtIOSCSIConf VirtIOSCSIConf;
-VirtIODevice *virtio_scsi_init(DeviceState *dev, VirtIOSCSIConf *conf);
-typedef struct VirtIORNGConf VirtIORNGConf;
-VirtIODevice *virtio_rng_init(DeviceState *dev, VirtIORNGConf *conf);
-#ifdef CONFIG_VIRTFS
-VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf);
-#endif
-
-
-void virtio_net_exit(VirtIODevice *vdev);
-void virtio_serial_exit(VirtIODevice *vdev);
-void virtio_balloon_exit(VirtIODevice *vdev);
-void virtio_scsi_exit(VirtIODevice *vdev);
-void virtio_rng_exit(VirtIODevice *vdev);
-
-#define DEFINE_VIRTIO_COMMON_FEATURES(_state, _field) \
-       DEFINE_PROP_BIT("indirect_desc", _state, _field, \
-                       VIRTIO_RING_F_INDIRECT_DESC, true), \
-       DEFINE_PROP_BIT("event_idx", _state, _field, \
-                       VIRTIO_RING_F_EVENT_IDX, true)
-
-hwaddr virtio_queue_get_desc_addr(VirtIODevice *vdev, int n);
-hwaddr virtio_queue_get_avail_addr(VirtIODevice *vdev, int n);
-hwaddr virtio_queue_get_used_addr(VirtIODevice *vdev, int n);
-hwaddr virtio_queue_get_ring_addr(VirtIODevice *vdev, int n);
-hwaddr virtio_queue_get_desc_size(VirtIODevice *vdev, int n);
-hwaddr virtio_queue_get_avail_size(VirtIODevice *vdev, int n);
-hwaddr virtio_queue_get_used_size(VirtIODevice *vdev, int n);
-hwaddr virtio_queue_get_ring_size(VirtIODevice *vdev, int n);
-uint16_t virtio_queue_get_last_avail_idx(VirtIODevice *vdev, int n);
-void virtio_queue_set_last_avail_idx(VirtIODevice *vdev, int n, uint16_t idx);
-VirtQueue *virtio_get_queue(VirtIODevice *vdev, int n);
-uint16_t virtio_get_queue_index(VirtQueue *vq);
-int virtio_queue_get_id(VirtQueue *vq);
-EventNotifier *virtio_queue_get_guest_notifier(VirtQueue *vq);
-void virtio_queue_set_guest_notifier_fd_handler(VirtQueue *vq, bool assign,
-                                                bool with_irqfd);
-EventNotifier *virtio_queue_get_host_notifier(VirtQueue *vq);
-void virtio_queue_set_host_notifier_fd_handler(VirtQueue *vq, bool assign,
-                                               bool set_handler);
-void virtio_queue_notify_vq(VirtQueue *vq);
-void virtio_irq(VirtQueue *vq);
-#endif
diff --git a/hw/virtio/Makefile.objs b/hw/virtio/Makefile.objs
new file mode 100644 (file)
index 0000000..c7e8013
--- /dev/null
@@ -0,0 +1,7 @@
+common-obj-$(CONFIG_VIRTIO) += virtio-rng.o
+common-obj-$(CONFIG_VIRTIO_PCI) += virtio-pci.o
+common-obj-$(CONFIG_VIRTIO) += virtio-bus.o
+common-obj-$(CONFIG_VIRTIO_BLK_DATA_PLANE) += dataplane/
+
+obj-$(CONFIG_VIRTIO) += virtio.o virtio-balloon.o 
+obj-$(CONFIG_VHOST_NET) += vhost.o
diff --git a/hw/virtio/dataplane/Makefile.objs b/hw/virtio/dataplane/Makefile.objs
new file mode 100644 (file)
index 0000000..a91bf33
--- /dev/null
@@ -0,0 +1 @@
+common-obj-y += hostmem.o vring.o
diff --git a/hw/virtio/dataplane/hostmem.c b/hw/virtio/dataplane/hostmem.c
new file mode 100644 (file)
index 0000000..37292ff
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ * Thread-safe guest to host memory mapping
+ *
+ * Copyright 2012 Red Hat, Inc. and/or its affiliates
+ *
+ * Authors:
+ *   Stefan Hajnoczi <stefanha@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 "exec/address-spaces.h"
+#include "hw/virtio/dataplane/hostmem.h"
+
+static int hostmem_lookup_cmp(const void *phys_, const void *region_)
+{
+    hwaddr phys = *(const hwaddr *)phys_;
+    const HostMemRegion *region = region_;
+
+    if (phys < region->guest_addr) {
+        return -1;
+    } else if (phys >= region->guest_addr + region->size) {
+        return 1;
+    } else {
+        return 0;
+    }
+}
+
+/**
+ * Map guest physical address to host pointer
+ */
+void *hostmem_lookup(HostMem *hostmem, hwaddr phys, hwaddr len, bool is_write)
+{
+    HostMemRegion *region;
+    void *host_addr = NULL;
+    hwaddr offset_within_region;
+
+    qemu_mutex_lock(&hostmem->current_regions_lock);
+    region = bsearch(&phys, hostmem->current_regions,
+                     hostmem->num_current_regions,
+                     sizeof(hostmem->current_regions[0]),
+                     hostmem_lookup_cmp);
+    if (!region) {
+        goto out;
+    }
+    if (is_write && region->readonly) {
+        goto out;
+    }
+    offset_within_region = phys - region->guest_addr;
+    if (len <= region->size - offset_within_region) {
+        host_addr = region->host_addr + offset_within_region;
+    }
+out:
+    qemu_mutex_unlock(&hostmem->current_regions_lock);
+
+    return host_addr;
+}
+
+/**
+ * Install new regions list
+ */
+static void hostmem_listener_commit(MemoryListener *listener)
+{
+    HostMem *hostmem = container_of(listener, HostMem, listener);
+
+    qemu_mutex_lock(&hostmem->current_regions_lock);
+    g_free(hostmem->current_regions);
+    hostmem->current_regions = hostmem->new_regions;
+    hostmem->num_current_regions = hostmem->num_new_regions;
+    qemu_mutex_unlock(&hostmem->current_regions_lock);
+
+    /* Reset new regions list */
+    hostmem->new_regions = NULL;
+    hostmem->num_new_regions = 0;
+}
+
+/**
+ * Add a MemoryRegionSection to the new regions list
+ */
+static void hostmem_append_new_region(HostMem *hostmem,
+                                      MemoryRegionSection *section)
+{
+    void *ram_ptr = memory_region_get_ram_ptr(section->mr);
+    size_t num = hostmem->num_new_regions;
+    size_t new_size = (num + 1) * sizeof(hostmem->new_regions[0]);
+
+    hostmem->new_regions = g_realloc(hostmem->new_regions, new_size);
+    hostmem->new_regions[num] = (HostMemRegion){
+        .host_addr = ram_ptr + section->offset_within_region,
+        .guest_addr = section->offset_within_address_space,
+        .size = section->size,
+        .readonly = section->readonly,
+    };
+    hostmem->num_new_regions++;
+}
+
+static void hostmem_listener_append_region(MemoryListener *listener,
+                                           MemoryRegionSection *section)
+{
+    HostMem *hostmem = container_of(listener, HostMem, listener);
+
+    /* Ignore non-RAM regions, we may not be able to map them */
+    if (!memory_region_is_ram(section->mr)) {
+        return;
+    }
+
+    /* Ignore regions with dirty logging, we cannot mark them dirty */
+    if (memory_region_is_logging(section->mr)) {
+        return;
+    }
+
+    hostmem_append_new_region(hostmem, section);
+}
+
+/* We don't implement most MemoryListener callbacks, use these nop stubs */
+static void hostmem_listener_dummy(MemoryListener *listener)
+{
+}
+
+static void hostmem_listener_section_dummy(MemoryListener *listener,
+                                           MemoryRegionSection *section)
+{
+}
+
+static void hostmem_listener_eventfd_dummy(MemoryListener *listener,
+                                           MemoryRegionSection *section,
+                                           bool match_data, uint64_t data,
+                                           EventNotifier *e)
+{
+}
+
+static void hostmem_listener_coalesced_mmio_dummy(MemoryListener *listener,
+                                                  MemoryRegionSection *section,
+                                                  hwaddr addr, hwaddr len)
+{
+}
+
+void hostmem_init(HostMem *hostmem)
+{
+    memset(hostmem, 0, sizeof(*hostmem));
+
+    qemu_mutex_init(&hostmem->current_regions_lock);
+
+    hostmem->listener = (MemoryListener){
+        .begin = hostmem_listener_dummy,
+        .commit = hostmem_listener_commit,
+        .region_add = hostmem_listener_append_region,
+        .region_del = hostmem_listener_section_dummy,
+        .region_nop = hostmem_listener_append_region,
+        .log_start = hostmem_listener_section_dummy,
+        .log_stop = hostmem_listener_section_dummy,
+        .log_sync = hostmem_listener_section_dummy,
+        .log_global_start = hostmem_listener_dummy,
+        .log_global_stop = hostmem_listener_dummy,
+        .eventfd_add = hostmem_listener_eventfd_dummy,
+        .eventfd_del = hostmem_listener_eventfd_dummy,
+        .coalesced_mmio_add = hostmem_listener_coalesced_mmio_dummy,
+        .coalesced_mmio_del = hostmem_listener_coalesced_mmio_dummy,
+        .priority = 10,
+    };
+
+    memory_listener_register(&hostmem->listener, &address_space_memory);
+    if (hostmem->num_new_regions > 0) {
+        hostmem_listener_commit(&hostmem->listener);
+    }
+}
+
+void hostmem_finalize(HostMem *hostmem)
+{
+    memory_listener_unregister(&hostmem->listener);
+    g_free(hostmem->new_regions);
+    g_free(hostmem->current_regions);
+    qemu_mutex_destroy(&hostmem->current_regions_lock);
+}
diff --git a/hw/virtio/dataplane/vring.c b/hw/virtio/dataplane/vring.c
new file mode 100644 (file)
index 0000000..e0d6e83
--- /dev/null
@@ -0,0 +1,363 @@
+/* Copyright 2012 Red Hat, Inc.
+ * Copyright IBM, Corp. 2012
+ *
+ * Based on Linux 2.6.39 vhost code:
+ * Copyright (C) 2009 Red Hat, Inc.
+ * Copyright (C) 2006 Rusty Russell IBM Corporation
+ *
+ * Author: Michael S. Tsirkin <mst@redhat.com>
+ *         Stefan Hajnoczi <stefanha@redhat.com>
+ *
+ * Inspiration, some code, and most witty comments come from
+ * Documentation/virtual/lguest/lguest.c, by Rusty Russell
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.
+ */
+
+#include "trace.h"
+#include "hw/virtio/dataplane/vring.h"
+#include "qemu/error-report.h"
+
+/* Map the guest's vring to host memory */
+bool vring_setup(Vring *vring, VirtIODevice *vdev, int n)
+{
+    hwaddr vring_addr = virtio_queue_get_ring_addr(vdev, n);
+    hwaddr vring_size = virtio_queue_get_ring_size(vdev, n);
+    void *vring_ptr;
+
+    vring->broken = false;
+
+    hostmem_init(&vring->hostmem);
+    vring_ptr = hostmem_lookup(&vring->hostmem, vring_addr, vring_size, true);
+    if (!vring_ptr) {
+        error_report("Failed to map vring "
+                     "addr %#" HWADDR_PRIx " size %" HWADDR_PRIu,
+                     vring_addr, vring_size);
+        vring->broken = true;
+        return false;
+    }
+
+    vring_init(&vring->vr, virtio_queue_get_num(vdev, n), vring_ptr, 4096);
+
+    vring->last_avail_idx = 0;
+    vring->last_used_idx = 0;
+    vring->signalled_used = 0;
+    vring->signalled_used_valid = false;
+
+    trace_vring_setup(virtio_queue_get_ring_addr(vdev, n),
+                      vring->vr.desc, vring->vr.avail, vring->vr.used);
+    return true;
+}
+
+void vring_teardown(Vring *vring)
+{
+    hostmem_finalize(&vring->hostmem);
+}
+
+/* Disable guest->host notifies */
+void vring_disable_notification(VirtIODevice *vdev, Vring *vring)
+{
+    if (!(vdev->guest_features & (1 << VIRTIO_RING_F_EVENT_IDX))) {
+        vring->vr.used->flags |= VRING_USED_F_NO_NOTIFY;
+    }
+}
+
+/* Enable guest->host notifies
+ *
+ * Return true if the vring is empty, false if there are more requests.
+ */
+bool vring_enable_notification(VirtIODevice *vdev, Vring *vring)
+{
+    if (vdev->guest_features & (1 << VIRTIO_RING_F_EVENT_IDX)) {
+        vring_avail_event(&vring->vr) = vring->vr.avail->idx;
+    } else {
+        vring->vr.used->flags &= ~VRING_USED_F_NO_NOTIFY;
+    }
+    smp_mb(); /* ensure update is seen before reading avail_idx */
+    return !vring_more_avail(vring);
+}
+
+/* This is stolen from linux/drivers/vhost/vhost.c:vhost_notify() */
+bool vring_should_notify(VirtIODevice *vdev, Vring *vring)
+{
+    uint16_t old, new;
+    bool v;
+    /* Flush out used index updates. This is paired
+     * with the barrier that the Guest executes when enabling
+     * interrupts. */
+    smp_mb();
+
+    if ((vdev->guest_features & VIRTIO_F_NOTIFY_ON_EMPTY) &&
+        unlikely(vring->vr.avail->idx == vring->last_avail_idx)) {
+        return true;
+    }
+
+    if (!(vdev->guest_features & VIRTIO_RING_F_EVENT_IDX)) {
+        return !(vring->vr.avail->flags & VRING_AVAIL_F_NO_INTERRUPT);
+    }
+    old = vring->signalled_used;
+    v = vring->signalled_used_valid;
+    new = vring->signalled_used = vring->last_used_idx;
+    vring->signalled_used_valid = true;
+
+    if (unlikely(!v)) {
+        return true;
+    }
+
+    return vring_need_event(vring_used_event(&vring->vr), new, old);
+}
+
+/* This is stolen from linux/drivers/vhost/vhost.c. */
+static int get_indirect(Vring *vring,
+                        struct iovec iov[], struct iovec *iov_end,
+                        unsigned int *out_num, unsigned int *in_num,
+                        struct vring_desc *indirect)
+{
+    struct vring_desc desc;
+    unsigned int i = 0, count, found = 0;
+
+    /* Sanity check */
+    if (unlikely(indirect->len % sizeof(desc))) {
+        error_report("Invalid length in indirect descriptor: "
+                     "len %#x not multiple of %#zx",
+                     indirect->len, sizeof(desc));
+        vring->broken = true;
+        return -EFAULT;
+    }
+
+    count = indirect->len / sizeof(desc);
+    /* Buffers are chained via a 16 bit next field, so
+     * we can have at most 2^16 of these. */
+    if (unlikely(count > USHRT_MAX + 1)) {
+        error_report("Indirect buffer length too big: %d", indirect->len);
+        vring->broken = true;
+        return -EFAULT;
+    }
+
+    do {
+        struct vring_desc *desc_ptr;
+
+        /* Translate indirect descriptor */
+        desc_ptr = hostmem_lookup(&vring->hostmem,
+                                  indirect->addr + found * sizeof(desc),
+                                  sizeof(desc), false);
+        if (!desc_ptr) {
+            error_report("Failed to map indirect descriptor "
+                         "addr %#" PRIx64 " len %zu",
+                         (uint64_t)indirect->addr + found * sizeof(desc),
+                         sizeof(desc));
+            vring->broken = true;
+            return -EFAULT;
+        }
+        desc = *desc_ptr;
+
+        /* Ensure descriptor has been loaded before accessing fields */
+        barrier(); /* read_barrier_depends(); */
+
+        if (unlikely(++found > count)) {
+            error_report("Loop detected: last one at %u "
+                         "indirect size %u", i, count);
+            vring->broken = true;
+            return -EFAULT;
+        }
+
+        if (unlikely(desc.flags & VRING_DESC_F_INDIRECT)) {
+            error_report("Nested indirect descriptor");
+            vring->broken = true;
+            return -EFAULT;
+        }
+
+        /* Stop for now if there are not enough iovecs available. */
+        if (iov >= iov_end) {
+            return -ENOBUFS;
+        }
+
+        iov->iov_base = hostmem_lookup(&vring->hostmem, desc.addr, desc.len,
+                                       desc.flags & VRING_DESC_F_WRITE);
+        if (!iov->iov_base) {
+            error_report("Failed to map indirect descriptor"
+                         "addr %#" PRIx64 " len %u",
+                         (uint64_t)desc.addr, desc.len);
+            vring->broken = true;
+            return -EFAULT;
+        }
+        iov->iov_len = desc.len;
+        iov++;
+
+        /* If this is an input descriptor, increment that count. */
+        if (desc.flags & VRING_DESC_F_WRITE) {
+            *in_num += 1;
+        } else {
+            /* If it's an output descriptor, they're all supposed
+             * to come before any input descriptors. */
+            if (unlikely(*in_num)) {
+                error_report("Indirect descriptor "
+                             "has out after in: idx %u", i);
+                vring->broken = true;
+                return -EFAULT;
+            }
+            *out_num += 1;
+        }
+        i = desc.next;
+    } while (desc.flags & VRING_DESC_F_NEXT);
+    return 0;
+}
+
+/* This looks in the virtqueue and for the first available buffer, and converts
+ * it to an iovec for convenient access.  Since descriptors consist of some
+ * number of output then some number of input descriptors, it's actually two
+ * iovecs, but we pack them into one and note how many of each there were.
+ *
+ * This function returns the descriptor number found, or vq->num (which is
+ * never a valid descriptor number) if none was found.  A negative code is
+ * returned on error.
+ *
+ * Stolen from linux/drivers/vhost/vhost.c.
+ */
+int vring_pop(VirtIODevice *vdev, Vring *vring,
+              struct iovec iov[], struct iovec *iov_end,
+              unsigned int *out_num, unsigned int *in_num)
+{
+    struct vring_desc desc;
+    unsigned int i, head, found = 0, num = vring->vr.num;
+    uint16_t avail_idx, last_avail_idx;
+
+    /* If there was a fatal error then refuse operation */
+    if (vring->broken) {
+        return -EFAULT;
+    }
+
+    /* Check it isn't doing very strange things with descriptor numbers. */
+    last_avail_idx = vring->last_avail_idx;
+    avail_idx = vring->vr.avail->idx;
+    barrier(); /* load indices now and not again later */
+
+    if (unlikely((uint16_t)(avail_idx - last_avail_idx) > num)) {
+        error_report("Guest moved used index from %u to %u",
+                     last_avail_idx, avail_idx);
+        vring->broken = true;
+        return -EFAULT;
+    }
+
+    /* If there's nothing new since last we looked. */
+    if (avail_idx == last_avail_idx) {
+        return -EAGAIN;
+    }
+
+    /* Only get avail ring entries after they have been exposed by guest. */
+    smp_rmb();
+
+    /* Grab the next descriptor number they're advertising, and increment
+     * the index we've seen. */
+    head = vring->vr.avail->ring[last_avail_idx % num];
+
+    /* If their number is silly, that's an error. */
+    if (unlikely(head >= num)) {
+        error_report("Guest says index %u > %u is available", head, num);
+        vring->broken = true;
+        return -EFAULT;
+    }
+
+    if (vdev->guest_features & (1 << VIRTIO_RING_F_EVENT_IDX)) {
+        vring_avail_event(&vring->vr) = vring->vr.avail->idx;
+    }
+
+    /* When we start there are none of either input nor output. */
+    *out_num = *in_num = 0;
+
+    i = head;
+    do {
+        if (unlikely(i >= num)) {
+            error_report("Desc index is %u > %u, head = %u", i, num, head);
+            vring->broken = true;
+            return -EFAULT;
+        }
+        if (unlikely(++found > num)) {
+            error_report("Loop detected: last one at %u vq size %u head %u",
+                         i, num, head);
+            vring->broken = true;
+            return -EFAULT;
+        }
+        desc = vring->vr.desc[i];
+
+        /* Ensure descriptor is loaded before accessing fields */
+        barrier();
+
+        if (desc.flags & VRING_DESC_F_INDIRECT) {
+            int ret = get_indirect(vring, iov, iov_end, out_num, in_num, &desc);
+            if (ret < 0) {
+                return ret;
+            }
+            continue;
+        }
+
+        /* If there are not enough iovecs left, stop for now.  The caller
+         * should check if there are more descs available once they have dealt
+         * with the current set.
+         */
+        if (iov >= iov_end) {
+            return -ENOBUFS;
+        }
+
+        /* TODO handle non-contiguous memory across region boundaries */
+        iov->iov_base = hostmem_lookup(&vring->hostmem, desc.addr, desc.len,
+                                       desc.flags & VRING_DESC_F_WRITE);
+        if (!iov->iov_base) {
+            error_report("Failed to map vring desc addr %#" PRIx64 " len %u",
+                         (uint64_t)desc.addr, desc.len);
+            vring->broken = true;
+            return -EFAULT;
+        }
+        iov->iov_len  = desc.len;
+        iov++;
+
+        if (desc.flags & VRING_DESC_F_WRITE) {
+            /* If this is an input descriptor,
+             * increment that count. */
+            *in_num += 1;
+        } else {
+            /* If it's an output descriptor, they're all supposed
+             * to come before any input descriptors. */
+            if (unlikely(*in_num)) {
+                error_report("Descriptor has out after in: idx %d", i);
+                vring->broken = true;
+                return -EFAULT;
+            }
+            *out_num += 1;
+        }
+        i = desc.next;
+    } while (desc.flags & VRING_DESC_F_NEXT);
+
+    /* On success, increment avail index. */
+    vring->last_avail_idx++;
+    return head;
+}
+
+/* After we've used one of their buffers, we tell them about it.
+ *
+ * Stolen from linux/drivers/vhost/vhost.c.
+ */
+void vring_push(Vring *vring, unsigned int head, int len)
+{
+    struct vring_used_elem *used;
+    uint16_t new;
+
+    /* Don't touch vring if a fatal error occurred */
+    if (vring->broken) {
+        return;
+    }
+
+    /* The virtqueue contains a ring of used buffers.  Get a pointer to the
+     * next entry in that used ring. */
+    used = &vring->vr.used->ring[vring->last_used_idx % vring->vr.num];
+    used->id = head;
+    used->len = len;
+
+    /* Make sure buffer is written before we update index. */
+    smp_wmb();
+
+    new = vring->vr.used->idx = ++vring->last_used_idx;
+    if (unlikely((int16_t)(new - vring->signalled_used) < (uint16_t)1)) {
+        vring->signalled_used_valid = false;
+    }
+}
diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
new file mode 100644 (file)
index 0000000..636fad0
--- /dev/null
@@ -0,0 +1,1042 @@
+/*
+ * vhost support
+ *
+ * Copyright Red Hat, Inc. 2010
+ *
+ * Authors:
+ *  Michael S. Tsirkin <mst@redhat.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 <sys/ioctl.h>
+#include "hw/virtio/vhost.h"
+#include "hw/hw.h"
+#include "qemu/range.h"
+#include <linux/vhost.h>
+#include "exec/address-spaces.h"
+
+static void vhost_dev_sync_region(struct vhost_dev *dev,
+                                  MemoryRegionSection *section,
+                                  uint64_t mfirst, uint64_t mlast,
+                                  uint64_t rfirst, uint64_t rlast)
+{
+    uint64_t start = MAX(mfirst, rfirst);
+    uint64_t end = MIN(mlast, rlast);
+    vhost_log_chunk_t *from = dev->log + start / VHOST_LOG_CHUNK;
+    vhost_log_chunk_t *to = dev->log + end / VHOST_LOG_CHUNK + 1;
+    uint64_t addr = (start / VHOST_LOG_CHUNK) * VHOST_LOG_CHUNK;
+
+    if (end < start) {
+        return;
+    }
+    assert(end / VHOST_LOG_CHUNK < dev->log_size);
+    assert(start / VHOST_LOG_CHUNK < dev->log_size);
+
+    for (;from < to; ++from) {
+        vhost_log_chunk_t log;
+        int bit;
+        /* We first check with non-atomic: much cheaper,
+         * and we expect non-dirty to be the common case. */
+        if (!*from) {
+            addr += VHOST_LOG_CHUNK;
+            continue;
+        }
+        /* Data must be read atomically. We don't really
+         * need the barrier semantics of __sync
+         * builtins, but it's easier to use them than
+         * roll our own. */
+        log = __sync_fetch_and_and(from, 0);
+        while ((bit = sizeof(log) > sizeof(int) ?
+                ffsll(log) : ffs(log))) {
+            hwaddr page_addr;
+            hwaddr section_offset;
+            hwaddr mr_offset;
+            bit -= 1;
+            page_addr = addr + bit * VHOST_LOG_PAGE;
+            section_offset = page_addr - section->offset_within_address_space;
+            mr_offset = section_offset + section->offset_within_region;
+            memory_region_set_dirty(section->mr, mr_offset, VHOST_LOG_PAGE);
+            log &= ~(0x1ull << bit);
+        }
+        addr += VHOST_LOG_CHUNK;
+    }
+}
+
+static int vhost_sync_dirty_bitmap(struct vhost_dev *dev,
+                                   MemoryRegionSection *section,
+                                   hwaddr first,
+                                   hwaddr last)
+{
+    int i;
+    hwaddr start_addr;
+    hwaddr end_addr;
+
+    if (!dev->log_enabled || !dev->started) {
+        return 0;
+    }
+    start_addr = section->offset_within_address_space;
+    end_addr = range_get_last(start_addr, section->size);
+    start_addr = MAX(first, start_addr);
+    end_addr = MIN(last, end_addr);
+
+    for (i = 0; i < dev->mem->nregions; ++i) {
+        struct vhost_memory_region *reg = dev->mem->regions + i;
+        vhost_dev_sync_region(dev, section, start_addr, end_addr,
+                              reg->guest_phys_addr,
+                              range_get_last(reg->guest_phys_addr,
+                                             reg->memory_size));
+    }
+    for (i = 0; i < dev->nvqs; ++i) {
+        struct vhost_virtqueue *vq = dev->vqs + i;
+        vhost_dev_sync_region(dev, section, start_addr, end_addr, vq->used_phys,
+                              range_get_last(vq->used_phys, vq->used_size));
+    }
+    return 0;
+}
+
+static void vhost_log_sync(MemoryListener *listener,
+                          MemoryRegionSection *section)
+{
+    struct vhost_dev *dev = container_of(listener, struct vhost_dev,
+                                         memory_listener);
+    vhost_sync_dirty_bitmap(dev, section, 0x0, ~0x0ULL);
+}
+
+static void vhost_log_sync_range(struct vhost_dev *dev,
+                                 hwaddr first, hwaddr last)
+{
+    int i;
+    /* FIXME: this is N^2 in number of sections */
+    for (i = 0; i < dev->n_mem_sections; ++i) {
+        MemoryRegionSection *section = &dev->mem_sections[i];
+        vhost_sync_dirty_bitmap(dev, section, first, last);
+    }
+}
+
+/* Assign/unassign. Keep an unsorted array of non-overlapping
+ * memory regions in dev->mem. */
+static void vhost_dev_unassign_memory(struct vhost_dev *dev,
+                                      uint64_t start_addr,
+                                      uint64_t size)
+{
+    int from, to, n = dev->mem->nregions;
+    /* Track overlapping/split regions for sanity checking. */
+    int overlap_start = 0, overlap_end = 0, overlap_middle = 0, split = 0;
+
+    for (from = 0, to = 0; from < n; ++from, ++to) {
+        struct vhost_memory_region *reg = dev->mem->regions + to;
+        uint64_t reglast;
+        uint64_t memlast;
+        uint64_t change;
+
+        /* clone old region */
+        if (to != from) {
+            memcpy(reg, dev->mem->regions + from, sizeof *reg);
+        }
+
+        /* No overlap is simple */
+        if (!ranges_overlap(reg->guest_phys_addr, reg->memory_size,
+                            start_addr, size)) {
+            continue;
+        }
+
+        /* Split only happens if supplied region
+         * is in the middle of an existing one. Thus it can not
+         * overlap with any other existing region. */
+        assert(!split);
+
+        reglast = range_get_last(reg->guest_phys_addr, reg->memory_size);
+        memlast = range_get_last(start_addr, size);
+
+        /* Remove whole region */
+        if (start_addr <= reg->guest_phys_addr && memlast >= reglast) {
+            --dev->mem->nregions;
+            --to;
+            ++overlap_middle;
+            continue;
+        }
+
+        /* Shrink region */
+        if (memlast >= reglast) {
+            reg->memory_size = start_addr - reg->guest_phys_addr;
+            assert(reg->memory_size);
+            assert(!overlap_end);
+            ++overlap_end;
+            continue;
+        }
+
+        /* Shift region */
+        if (start_addr <= reg->guest_phys_addr) {
+            change = memlast + 1 - reg->guest_phys_addr;
+            reg->memory_size -= change;
+            reg->guest_phys_addr += change;
+            reg->userspace_addr += change;
+            assert(reg->memory_size);
+            assert(!overlap_start);
+            ++overlap_start;
+            continue;
+        }
+
+        /* This only happens if supplied region
+         * is in the middle of an existing one. Thus it can not
+         * overlap with any other existing region. */
+        assert(!overlap_start);
+        assert(!overlap_end);
+        assert(!overlap_middle);
+        /* Split region: shrink first part, shift second part. */
+        memcpy(dev->mem->regions + n, reg, sizeof *reg);
+        reg->memory_size = start_addr - reg->guest_phys_addr;
+        assert(reg->memory_size);
+        change = memlast + 1 - reg->guest_phys_addr;
+        reg = dev->mem->regions + n;
+        reg->memory_size -= change;
+        assert(reg->memory_size);
+        reg->guest_phys_addr += change;
+        reg->userspace_addr += change;
+        /* Never add more than 1 region */
+        assert(dev->mem->nregions == n);
+        ++dev->mem->nregions;
+        ++split;
+    }
+}
+
+/* Called after unassign, so no regions overlap the given range. */
+static void vhost_dev_assign_memory(struct vhost_dev *dev,
+                                    uint64_t start_addr,
+                                    uint64_t size,
+                                    uint64_t uaddr)
+{
+    int from, to;
+    struct vhost_memory_region *merged = NULL;
+    for (from = 0, to = 0; from < dev->mem->nregions; ++from, ++to) {
+        struct vhost_memory_region *reg = dev->mem->regions + to;
+        uint64_t prlast, urlast;
+        uint64_t pmlast, umlast;
+        uint64_t s, e, u;
+
+        /* clone old region */
+        if (to != from) {
+            memcpy(reg, dev->mem->regions + from, sizeof *reg);
+        }
+        prlast = range_get_last(reg->guest_phys_addr, reg->memory_size);
+        pmlast = range_get_last(start_addr, size);
+        urlast = range_get_last(reg->userspace_addr, reg->memory_size);
+        umlast = range_get_last(uaddr, size);
+
+        /* check for overlapping regions: should never happen. */
+        assert(prlast < start_addr || pmlast < reg->guest_phys_addr);
+        /* Not an adjacent or overlapping region - do not merge. */
+        if ((prlast + 1 != start_addr || urlast + 1 != uaddr) &&
+            (pmlast + 1 != reg->guest_phys_addr ||
+             umlast + 1 != reg->userspace_addr)) {
+            continue;
+        }
+
+        if (merged) {
+            --to;
+            assert(to >= 0);
+        } else {
+            merged = reg;
+        }
+        u = MIN(uaddr, reg->userspace_addr);
+        s = MIN(start_addr, reg->guest_phys_addr);
+        e = MAX(pmlast, prlast);
+        uaddr = merged->userspace_addr = u;
+        start_addr = merged->guest_phys_addr = s;
+        size = merged->memory_size = e - s + 1;
+        assert(merged->memory_size);
+    }
+
+    if (!merged) {
+        struct vhost_memory_region *reg = dev->mem->regions + to;
+        memset(reg, 0, sizeof *reg);
+        reg->memory_size = size;
+        assert(reg->memory_size);
+        reg->guest_phys_addr = start_addr;
+        reg->userspace_addr = uaddr;
+        ++to;
+    }
+    assert(to <= dev->mem->nregions + 1);
+    dev->mem->nregions = to;
+}
+
+static uint64_t vhost_get_log_size(struct vhost_dev *dev)
+{
+    uint64_t log_size = 0;
+    int i;
+    for (i = 0; i < dev->mem->nregions; ++i) {
+        struct vhost_memory_region *reg = dev->mem->regions + i;
+        uint64_t last = range_get_last(reg->guest_phys_addr,
+                                       reg->memory_size);
+        log_size = MAX(log_size, last / VHOST_LOG_CHUNK + 1);
+    }
+    for (i = 0; i < dev->nvqs; ++i) {
+        struct vhost_virtqueue *vq = dev->vqs + i;
+        uint64_t last = vq->used_phys + vq->used_size - 1;
+        log_size = MAX(log_size, last / VHOST_LOG_CHUNK + 1);
+    }
+    return log_size;
+}
+
+static inline void vhost_dev_log_resize(struct vhost_dev* dev, uint64_t size)
+{
+    vhost_log_chunk_t *log;
+    uint64_t log_base;
+    int r;
+
+    log = g_malloc0(size * sizeof *log);
+    log_base = (uint64_t)(unsigned long)log;
+    r = ioctl(dev->control, VHOST_SET_LOG_BASE, &log_base);
+    assert(r >= 0);
+    /* Sync only the range covered by the old log */
+    if (dev->log_size) {
+        vhost_log_sync_range(dev, 0, dev->log_size * VHOST_LOG_CHUNK - 1);
+    }
+    if (dev->log) {
+        g_free(dev->log);
+    }
+    dev->log = log;
+    dev->log_size = size;
+}
+
+static int vhost_verify_ring_mappings(struct vhost_dev *dev,
+                                      uint64_t start_addr,
+                                      uint64_t size)
+{
+    int i;
+    for (i = 0; i < dev->nvqs; ++i) {
+        struct vhost_virtqueue *vq = dev->vqs + i;
+        hwaddr l;
+        void *p;
+
+        if (!ranges_overlap(start_addr, size, vq->ring_phys, vq->ring_size)) {
+            continue;
+        }
+        l = vq->ring_size;
+        p = cpu_physical_memory_map(vq->ring_phys, &l, 1);
+        if (!p || l != vq->ring_size) {
+            fprintf(stderr, "Unable to map ring buffer for ring %d\n", i);
+            return -ENOMEM;
+        }
+        if (p != vq->ring) {
+            fprintf(stderr, "Ring buffer relocated for ring %d\n", i);
+            return -EBUSY;
+        }
+        cpu_physical_memory_unmap(p, l, 0, 0);
+    }
+    return 0;
+}
+
+static struct vhost_memory_region *vhost_dev_find_reg(struct vhost_dev *dev,
+                                                     uint64_t start_addr,
+                                                     uint64_t size)
+{
+    int i, n = dev->mem->nregions;
+    for (i = 0; i < n; ++i) {
+        struct vhost_memory_region *reg = dev->mem->regions + i;
+        if (ranges_overlap(reg->guest_phys_addr, reg->memory_size,
+                           start_addr, size)) {
+            return reg;
+        }
+    }
+    return NULL;
+}
+
+static bool vhost_dev_cmp_memory(struct vhost_dev *dev,
+                                 uint64_t start_addr,
+                                 uint64_t size,
+                                 uint64_t uaddr)
+{
+    struct vhost_memory_region *reg = vhost_dev_find_reg(dev, start_addr, size);
+    uint64_t reglast;
+    uint64_t memlast;
+
+    if (!reg) {
+        return true;
+    }
+
+    reglast = range_get_last(reg->guest_phys_addr, reg->memory_size);
+    memlast = range_get_last(start_addr, size);
+
+    /* Need to extend region? */
+    if (start_addr < reg->guest_phys_addr || memlast > reglast) {
+        return true;
+    }
+    /* userspace_addr changed? */
+    return uaddr != reg->userspace_addr + start_addr - reg->guest_phys_addr;
+}
+
+static void vhost_set_memory(MemoryListener *listener,
+                             MemoryRegionSection *section,
+                             bool add)
+{
+    struct vhost_dev *dev = container_of(listener, struct vhost_dev,
+                                         memory_listener);
+    hwaddr start_addr = section->offset_within_address_space;
+    ram_addr_t size = section->size;
+    bool log_dirty = memory_region_is_logging(section->mr);
+    int s = offsetof(struct vhost_memory, regions) +
+        (dev->mem->nregions + 1) * sizeof dev->mem->regions[0];
+    uint64_t log_size;
+    int r;
+    void *ram;
+
+    dev->mem = g_realloc(dev->mem, s);
+
+    if (log_dirty) {
+        add = false;
+    }
+
+    assert(size);
+
+    /* Optimize no-change case. At least cirrus_vga does this a lot at this time. */
+    ram = memory_region_get_ram_ptr(section->mr) + section->offset_within_region;
+    if (add) {
+        if (!vhost_dev_cmp_memory(dev, start_addr, size, (uintptr_t)ram)) {
+            /* Region exists with same address. Nothing to do. */
+            return;
+        }
+    } else {
+        if (!vhost_dev_find_reg(dev, start_addr, size)) {
+            /* Removing region that we don't access. Nothing to do. */
+            return;
+        }
+    }
+
+    vhost_dev_unassign_memory(dev, start_addr, size);
+    if (add) {
+        /* Add given mapping, merging adjacent regions if any */
+        vhost_dev_assign_memory(dev, start_addr, size, (uintptr_t)ram);
+    } else {
+        /* Remove old mapping for this memory, if any. */
+        vhost_dev_unassign_memory(dev, start_addr, size);
+    }
+
+    if (!dev->started) {
+        return;
+    }
+
+    if (dev->started) {
+        r = vhost_verify_ring_mappings(dev, start_addr, size);
+        assert(r >= 0);
+    }
+
+    if (!dev->log_enabled) {
+        r = ioctl(dev->control, VHOST_SET_MEM_TABLE, dev->mem);
+        assert(r >= 0);
+        return;
+    }
+    log_size = vhost_get_log_size(dev);
+    /* We allocate an extra 4K bytes to log,
+     * to reduce the * number of reallocations. */
+#define VHOST_LOG_BUFFER (0x1000 / sizeof *dev->log)
+    /* To log more, must increase log size before table update. */
+    if (dev->log_size < log_size) {
+        vhost_dev_log_resize(dev, log_size + VHOST_LOG_BUFFER);
+    }
+    r = ioctl(dev->control, VHOST_SET_MEM_TABLE, dev->mem);
+    assert(r >= 0);
+    /* To log less, can only decrease log size after table update. */
+    if (dev->log_size > log_size + VHOST_LOG_BUFFER) {
+        vhost_dev_log_resize(dev, log_size);
+    }
+}
+
+static bool vhost_section(MemoryRegionSection *section)
+{
+    return memory_region_is_ram(section->mr);
+}
+
+static void vhost_begin(MemoryListener *listener)
+{
+}
+
+static void vhost_commit(MemoryListener *listener)
+{
+}
+
+static void vhost_region_add(MemoryListener *listener,
+                             MemoryRegionSection *section)
+{
+    struct vhost_dev *dev = container_of(listener, struct vhost_dev,
+                                         memory_listener);
+
+    if (!vhost_section(section)) {
+        return;
+    }
+
+    ++dev->n_mem_sections;
+    dev->mem_sections = g_renew(MemoryRegionSection, dev->mem_sections,
+                                dev->n_mem_sections);
+    dev->mem_sections[dev->n_mem_sections - 1] = *section;
+    vhost_set_memory(listener, section, true);
+}
+
+static void vhost_region_del(MemoryListener *listener,
+                             MemoryRegionSection *section)
+{
+    struct vhost_dev *dev = container_of(listener, struct vhost_dev,
+                                         memory_listener);
+    int i;
+
+    if (!vhost_section(section)) {
+        return;
+    }
+
+    vhost_set_memory(listener, section, false);
+    for (i = 0; i < dev->n_mem_sections; ++i) {
+        if (dev->mem_sections[i].offset_within_address_space
+            == section->offset_within_address_space) {
+            --dev->n_mem_sections;
+            memmove(&dev->mem_sections[i], &dev->mem_sections[i+1],
+                    (dev->n_mem_sections - i) * sizeof(*dev->mem_sections));
+            break;
+        }
+    }
+}
+
+static void vhost_region_nop(MemoryListener *listener,
+                             MemoryRegionSection *section)
+{
+}
+
+static int vhost_virtqueue_set_addr(struct vhost_dev *dev,
+                                    struct vhost_virtqueue *vq,
+                                    unsigned idx, bool enable_log)
+{
+    struct vhost_vring_addr addr = {
+        .index = idx,
+        .desc_user_addr = (uint64_t)(unsigned long)vq->desc,
+        .avail_user_addr = (uint64_t)(unsigned long)vq->avail,
+        .used_user_addr = (uint64_t)(unsigned long)vq->used,
+        .log_guest_addr = vq->used_phys,
+        .flags = enable_log ? (1 << VHOST_VRING_F_LOG) : 0,
+    };
+    int r = ioctl(dev->control, VHOST_SET_VRING_ADDR, &addr);
+    if (r < 0) {
+        return -errno;
+    }
+    return 0;
+}
+
+static int vhost_dev_set_features(struct vhost_dev *dev, bool enable_log)
+{
+    uint64_t features = dev->acked_features;
+    int r;
+    if (enable_log) {
+        features |= 0x1 << VHOST_F_LOG_ALL;
+    }
+    r = ioctl(dev->control, VHOST_SET_FEATURES, &features);
+    return r < 0 ? -errno : 0;
+}
+
+static int vhost_dev_set_log(struct vhost_dev *dev, bool enable_log)
+{
+    int r, t, i;
+    r = vhost_dev_set_features(dev, enable_log);
+    if (r < 0) {
+        goto err_features;
+    }
+    for (i = 0; i < dev->nvqs; ++i) {
+        r = vhost_virtqueue_set_addr(dev, dev->vqs + i, i,
+                                     enable_log);
+        if (r < 0) {
+            goto err_vq;
+        }
+    }
+    return 0;
+err_vq:
+    for (; i >= 0; --i) {
+        t = vhost_virtqueue_set_addr(dev, dev->vqs + i, i,
+                                     dev->log_enabled);
+        assert(t >= 0);
+    }
+    t = vhost_dev_set_features(dev, dev->log_enabled);
+    assert(t >= 0);
+err_features:
+    return r;
+}
+
+static int vhost_migration_log(MemoryListener *listener, int enable)
+{
+    struct vhost_dev *dev = container_of(listener, struct vhost_dev,
+                                         memory_listener);
+    int r;
+    if (!!enable == dev->log_enabled) {
+        return 0;
+    }
+    if (!dev->started) {
+        dev->log_enabled = enable;
+        return 0;
+    }
+    if (!enable) {
+        r = vhost_dev_set_log(dev, false);
+        if (r < 0) {
+            return r;
+        }
+        if (dev->log) {
+            g_free(dev->log);
+        }
+        dev->log = NULL;
+        dev->log_size = 0;
+    } else {
+        vhost_dev_log_resize(dev, vhost_get_log_size(dev));
+        r = vhost_dev_set_log(dev, true);
+        if (r < 0) {
+            return r;
+        }
+    }
+    dev->log_enabled = enable;
+    return 0;
+}
+
+static void vhost_log_global_start(MemoryListener *listener)
+{
+    int r;
+
+    r = vhost_migration_log(listener, true);
+    if (r < 0) {
+        abort();
+    }
+}
+
+static void vhost_log_global_stop(MemoryListener *listener)
+{
+    int r;
+
+    r = vhost_migration_log(listener, false);
+    if (r < 0) {
+        abort();
+    }
+}
+
+static void vhost_log_start(MemoryListener *listener,
+                            MemoryRegionSection *section)
+{
+    /* FIXME: implement */
+}
+
+static void vhost_log_stop(MemoryListener *listener,
+                           MemoryRegionSection *section)
+{
+    /* FIXME: implement */
+}
+
+static int vhost_virtqueue_start(struct vhost_dev *dev,
+                                struct VirtIODevice *vdev,
+                                struct vhost_virtqueue *vq,
+                                unsigned idx)
+{
+    hwaddr s, l, a;
+    int r;
+    int vhost_vq_index = idx - dev->vq_index;
+    struct vhost_vring_file file = {
+        .index = vhost_vq_index
+    };
+    struct vhost_vring_state state = {
+        .index = vhost_vq_index
+    };
+    struct VirtQueue *vvq = virtio_get_queue(vdev, idx);
+
+    assert(idx >= dev->vq_index && idx < dev->vq_index + dev->nvqs);
+
+    vq->num = state.num = virtio_queue_get_num(vdev, idx);
+    r = ioctl(dev->control, VHOST_SET_VRING_NUM, &state);
+    if (r) {
+        return -errno;
+    }
+
+    state.num = virtio_queue_get_last_avail_idx(vdev, idx);
+    r = ioctl(dev->control, VHOST_SET_VRING_BASE, &state);
+    if (r) {
+        return -errno;
+    }
+
+    s = l = virtio_queue_get_desc_size(vdev, idx);
+    a = virtio_queue_get_desc_addr(vdev, idx);
+    vq->desc = cpu_physical_memory_map(a, &l, 0);
+    if (!vq->desc || l != s) {
+        r = -ENOMEM;
+        goto fail_alloc_desc;
+    }
+    s = l = virtio_queue_get_avail_size(vdev, idx);
+    a = virtio_queue_get_avail_addr(vdev, idx);
+    vq->avail = cpu_physical_memory_map(a, &l, 0);
+    if (!vq->avail || l != s) {
+        r = -ENOMEM;
+        goto fail_alloc_avail;
+    }
+    vq->used_size = s = l = virtio_queue_get_used_size(vdev, idx);
+    vq->used_phys = a = virtio_queue_get_used_addr(vdev, idx);
+    vq->used = cpu_physical_memory_map(a, &l, 1);
+    if (!vq->used || l != s) {
+        r = -ENOMEM;
+        goto fail_alloc_used;
+    }
+
+    vq->ring_size = s = l = virtio_queue_get_ring_size(vdev, idx);
+    vq->ring_phys = a = virtio_queue_get_ring_addr(vdev, idx);
+    vq->ring = cpu_physical_memory_map(a, &l, 1);
+    if (!vq->ring || l != s) {
+        r = -ENOMEM;
+        goto fail_alloc_ring;
+    }
+
+    r = vhost_virtqueue_set_addr(dev, vq, vhost_vq_index, dev->log_enabled);
+    if (r < 0) {
+        r = -errno;
+        goto fail_alloc;
+    }
+
+    file.fd = event_notifier_get_fd(virtio_queue_get_host_notifier(vvq));
+    r = ioctl(dev->control, VHOST_SET_VRING_KICK, &file);
+    if (r) {
+        r = -errno;
+        goto fail_kick;
+    }
+
+    /* Clear and discard previous events if any. */
+    event_notifier_test_and_clear(&vq->masked_notifier);
+
+    return 0;
+
+fail_kick:
+fail_alloc:
+    cpu_physical_memory_unmap(vq->ring, virtio_queue_get_ring_size(vdev, idx),
+                              0, 0);
+fail_alloc_ring:
+    cpu_physical_memory_unmap(vq->used, virtio_queue_get_used_size(vdev, idx),
+                              0, 0);
+fail_alloc_used:
+    cpu_physical_memory_unmap(vq->avail, virtio_queue_get_avail_size(vdev, idx),
+                              0, 0);
+fail_alloc_avail:
+    cpu_physical_memory_unmap(vq->desc, virtio_queue_get_desc_size(vdev, idx),
+                              0, 0);
+fail_alloc_desc:
+    return r;
+}
+
+static void vhost_virtqueue_stop(struct vhost_dev *dev,
+                                    struct VirtIODevice *vdev,
+                                    struct vhost_virtqueue *vq,
+                                    unsigned idx)
+{
+    struct vhost_vring_state state = {
+        .index = idx - dev->vq_index
+    };
+    int r;
+    assert(idx >= dev->vq_index && idx < dev->vq_index + dev->nvqs);
+    r = ioctl(dev->control, VHOST_GET_VRING_BASE, &state);
+    if (r < 0) {
+        fprintf(stderr, "vhost VQ %d ring restore failed: %d\n", idx, r);
+        fflush(stderr);
+    }
+    virtio_queue_set_last_avail_idx(vdev, idx, state.num);
+    assert (r >= 0);
+    cpu_physical_memory_unmap(vq->ring, virtio_queue_get_ring_size(vdev, idx),
+                              0, virtio_queue_get_ring_size(vdev, idx));
+    cpu_physical_memory_unmap(vq->used, virtio_queue_get_used_size(vdev, idx),
+                              1, virtio_queue_get_used_size(vdev, idx));
+    cpu_physical_memory_unmap(vq->avail, virtio_queue_get_avail_size(vdev, idx),
+                              0, virtio_queue_get_avail_size(vdev, idx));
+    cpu_physical_memory_unmap(vq->desc, virtio_queue_get_desc_size(vdev, idx),
+                              0, virtio_queue_get_desc_size(vdev, idx));
+}
+
+static void vhost_eventfd_add(MemoryListener *listener,
+                              MemoryRegionSection *section,
+                              bool match_data, uint64_t data, EventNotifier *e)
+{
+}
+
+static void vhost_eventfd_del(MemoryListener *listener,
+                              MemoryRegionSection *section,
+                              bool match_data, uint64_t data, EventNotifier *e)
+{
+}
+
+static int vhost_virtqueue_init(struct vhost_dev *dev,
+                                struct vhost_virtqueue *vq, int n)
+{
+    struct vhost_vring_file file = {
+        .index = n,
+    };
+    int r = event_notifier_init(&vq->masked_notifier, 0);
+    if (r < 0) {
+        return r;
+    }
+
+    file.fd = event_notifier_get_fd(&vq->masked_notifier);
+    r = ioctl(dev->control, VHOST_SET_VRING_CALL, &file);
+    if (r) {
+        r = -errno;
+        goto fail_call;
+    }
+    return 0;
+fail_call:
+    event_notifier_cleanup(&vq->masked_notifier);
+    return r;
+}
+
+static void vhost_virtqueue_cleanup(struct vhost_virtqueue *vq)
+{
+    event_notifier_cleanup(&vq->masked_notifier);
+}
+
+int vhost_dev_init(struct vhost_dev *hdev, int devfd, const char *devpath,
+                   bool force)
+{
+    uint64_t features;
+    int i, r;
+    if (devfd >= 0) {
+        hdev->control = devfd;
+    } else {
+        hdev->control = open(devpath, O_RDWR);
+        if (hdev->control < 0) {
+            return -errno;
+        }
+    }
+    r = ioctl(hdev->control, VHOST_SET_OWNER, NULL);
+    if (r < 0) {
+        goto fail;
+    }
+
+    r = ioctl(hdev->control, VHOST_GET_FEATURES, &features);
+    if (r < 0) {
+        goto fail;
+    }
+
+    for (i = 0; i < hdev->nvqs; ++i) {
+        r = vhost_virtqueue_init(hdev, hdev->vqs + i, i);
+        if (r < 0) {
+            goto fail_vq;
+        }
+    }
+    hdev->features = features;
+
+    hdev->memory_listener = (MemoryListener) {
+        .begin = vhost_begin,
+        .commit = vhost_commit,
+        .region_add = vhost_region_add,
+        .region_del = vhost_region_del,
+        .region_nop = vhost_region_nop,
+        .log_start = vhost_log_start,
+        .log_stop = vhost_log_stop,
+        .log_sync = vhost_log_sync,
+        .log_global_start = vhost_log_global_start,
+        .log_global_stop = vhost_log_global_stop,
+        .eventfd_add = vhost_eventfd_add,
+        .eventfd_del = vhost_eventfd_del,
+        .priority = 10
+    };
+    hdev->mem = g_malloc0(offsetof(struct vhost_memory, regions));
+    hdev->n_mem_sections = 0;
+    hdev->mem_sections = NULL;
+    hdev->log = NULL;
+    hdev->log_size = 0;
+    hdev->log_enabled = false;
+    hdev->started = false;
+    memory_listener_register(&hdev->memory_listener, &address_space_memory);
+    hdev->force = force;
+    return 0;
+fail_vq:
+    while (--i >= 0) {
+        vhost_virtqueue_cleanup(hdev->vqs + i);
+    }
+fail:
+    r = -errno;
+    close(hdev->control);
+    return r;
+}
+
+void vhost_dev_cleanup(struct vhost_dev *hdev)
+{
+    int i;
+    for (i = 0; i < hdev->nvqs; ++i) {
+        vhost_virtqueue_cleanup(hdev->vqs + i);
+    }
+    memory_listener_unregister(&hdev->memory_listener);
+    g_free(hdev->mem);
+    g_free(hdev->mem_sections);
+    close(hdev->control);
+}
+
+bool vhost_dev_query(struct vhost_dev *hdev, VirtIODevice *vdev)
+{
+    return !vdev->binding->query_guest_notifiers ||
+        vdev->binding->query_guest_notifiers(vdev->binding_opaque) ||
+        hdev->force;
+}
+
+/* Stop processing guest IO notifications in qemu.
+ * Start processing them in vhost in kernel.
+ */
+int vhost_dev_enable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev)
+{
+    int i, r;
+    if (!vdev->binding->set_host_notifier) {
+        fprintf(stderr, "binding does not support host notifiers\n");
+        r = -ENOSYS;
+        goto fail;
+    }
+
+    for (i = 0; i < hdev->nvqs; ++i) {
+        r = vdev->binding->set_host_notifier(vdev->binding_opaque,
+                                             hdev->vq_index + i,
+                                             true);
+        if (r < 0) {
+            fprintf(stderr, "vhost VQ %d notifier binding failed: %d\n", i, -r);
+            goto fail_vq;
+        }
+    }
+
+    return 0;
+fail_vq:
+    while (--i >= 0) {
+        r = vdev->binding->set_host_notifier(vdev->binding_opaque,
+                                             hdev->vq_index + i,
+                                             false);
+        if (r < 0) {
+            fprintf(stderr, "vhost VQ %d notifier cleanup error: %d\n", i, -r);
+            fflush(stderr);
+        }
+        assert (r >= 0);
+    }
+fail:
+    return r;
+}
+
+/* Stop processing guest IO notifications in vhost.
+ * Start processing them in qemu.
+ * This might actually run the qemu handlers right away,
+ * so virtio in qemu must be completely setup when this is called.
+ */
+void vhost_dev_disable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev)
+{
+    int i, r;
+
+    for (i = 0; i < hdev->nvqs; ++i) {
+        r = vdev->binding->set_host_notifier(vdev->binding_opaque,
+                                             hdev->vq_index + i,
+                                             false);
+        if (r < 0) {
+            fprintf(stderr, "vhost VQ %d notifier cleanup failed: %d\n", i, -r);
+            fflush(stderr);
+        }
+        assert (r >= 0);
+    }
+}
+
+/* Test and clear event pending status.
+ * Should be called after unmask to avoid losing events.
+ */
+bool vhost_virtqueue_pending(struct vhost_dev *hdev, int n)
+{
+    struct vhost_virtqueue *vq = hdev->vqs + n - hdev->vq_index;
+    assert(hdev->started);
+    assert(n >= hdev->vq_index && n < hdev->vq_index + hdev->nvqs);
+    return event_notifier_test_and_clear(&vq->masked_notifier);
+}
+
+/* Mask/unmask events from this vq. */
+void vhost_virtqueue_mask(struct vhost_dev *hdev, VirtIODevice *vdev, int n,
+                         bool mask)
+{
+    struct VirtQueue *vvq = virtio_get_queue(vdev, n);
+    int r, index = n - hdev->vq_index;
+
+    assert(hdev->started);
+    assert(n >= hdev->vq_index && n < hdev->vq_index + hdev->nvqs);
+
+    struct vhost_vring_file file = {
+        .index = index
+    };
+    if (mask) {
+        file.fd = event_notifier_get_fd(&hdev->vqs[index].masked_notifier);
+    } else {
+        file.fd = event_notifier_get_fd(virtio_queue_get_guest_notifier(vvq));
+    }
+    r = ioctl(hdev->control, VHOST_SET_VRING_CALL, &file);
+    assert(r >= 0);
+}
+
+/* Host notifiers must be enabled at this point. */
+int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev)
+{
+    int i, r;
+
+    hdev->started = true;
+
+    r = vhost_dev_set_features(hdev, hdev->log_enabled);
+    if (r < 0) {
+        goto fail_features;
+    }
+    r = ioctl(hdev->control, VHOST_SET_MEM_TABLE, hdev->mem);
+    if (r < 0) {
+        r = -errno;
+        goto fail_mem;
+    }
+    for (i = 0; i < hdev->nvqs; ++i) {
+        r = vhost_virtqueue_start(hdev,
+                                  vdev,
+                                  hdev->vqs + i,
+                                  hdev->vq_index + i);
+        if (r < 0) {
+            goto fail_vq;
+        }
+    }
+
+    if (hdev->log_enabled) {
+        hdev->log_size = vhost_get_log_size(hdev);
+        hdev->log = hdev->log_size ?
+            g_malloc0(hdev->log_size * sizeof *hdev->log) : NULL;
+        r = ioctl(hdev->control, VHOST_SET_LOG_BASE,
+                  (uint64_t)(unsigned long)hdev->log);
+        if (r < 0) {
+            r = -errno;
+            goto fail_log;
+        }
+    }
+
+    return 0;
+fail_log:
+fail_vq:
+    while (--i >= 0) {
+        vhost_virtqueue_stop(hdev,
+                             vdev,
+                             hdev->vqs + i,
+                             hdev->vq_index + i);
+    }
+    i = hdev->nvqs;
+fail_mem:
+fail_features:
+
+    hdev->started = false;
+    return r;
+}
+
+/* Host notifiers must be enabled at this point. */
+void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev)
+{
+    int i;
+
+    for (i = 0; i < hdev->nvqs; ++i) {
+        vhost_virtqueue_stop(hdev,
+                             vdev,
+                             hdev->vqs + i,
+                             hdev->vq_index + i);
+    }
+    vhost_log_sync_range(hdev, 0, ~0x0ull);
+
+    hdev->started = false;
+    g_free(hdev->log);
+    hdev->log = NULL;
+    hdev->log_size = 0;
+}
+
diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c
new file mode 100644 (file)
index 0000000..c2c446e
--- /dev/null
@@ -0,0 +1,416 @@
+/*
+ * Virtio Balloon Device
+ *
+ * Copyright IBM, Corp. 2008
+ * Copyright (C) 2011 Red Hat, Inc.
+ * Copyright (C) 2011 Amit Shah <amit.shah@redhat.com>
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.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 "qemu/iov.h"
+#include "qemu/timer.h"
+#include "qemu-common.h"
+#include "hw/virtio/virtio.h"
+#include "hw/i386/pc.h"
+#include "cpu.h"
+#include "sysemu/balloon.h"
+#include "hw/virtio/virtio-balloon.h"
+#include "sysemu/kvm.h"
+#include "exec/address-spaces.h"
+#include "qapi/visitor.h"
+
+#if defined(__linux__)
+#include <sys/mman.h>
+#endif
+
+#include "hw/virtio/virtio-bus.h"
+
+static void balloon_page(void *addr, int deflate)
+{
+#if defined(__linux__)
+    if (!kvm_enabled() || kvm_has_sync_mmu())
+        qemu_madvise(addr, TARGET_PAGE_SIZE,
+                deflate ? QEMU_MADV_WILLNEED : QEMU_MADV_DONTNEED);
+#endif
+}
+
+static const char *balloon_stat_names[] = {
+   [VIRTIO_BALLOON_S_SWAP_IN] = "stat-swap-in",
+   [VIRTIO_BALLOON_S_SWAP_OUT] = "stat-swap-out",
+   [VIRTIO_BALLOON_S_MAJFLT] = "stat-major-faults",
+   [VIRTIO_BALLOON_S_MINFLT] = "stat-minor-faults",
+   [VIRTIO_BALLOON_S_MEMFREE] = "stat-free-memory",
+   [VIRTIO_BALLOON_S_MEMTOT] = "stat-total-memory",
+   [VIRTIO_BALLOON_S_NR] = NULL
+};
+
+/*
+ * reset_stats - Mark all items in the stats array as unset
+ *
+ * This function needs to be called at device intialization and before
+ * before updating to a set of newly-generated stats.  This will ensure that no
+ * stale values stick around in case the guest reports a subset of the supported
+ * statistics.
+ */
+static inline void reset_stats(VirtIOBalloon *dev)
+{
+    int i;
+    for (i = 0; i < VIRTIO_BALLOON_S_NR; dev->stats[i++] = -1);
+}
+
+static bool balloon_stats_supported(const VirtIOBalloon *s)
+{
+    VirtIODevice *vdev = VIRTIO_DEVICE(s);
+    return vdev->guest_features & (1 << VIRTIO_BALLOON_F_STATS_VQ);
+}
+
+static bool balloon_stats_enabled(const VirtIOBalloon *s)
+{
+    return s->stats_poll_interval > 0;
+}
+
+static void balloon_stats_destroy_timer(VirtIOBalloon *s)
+{
+    if (balloon_stats_enabled(s)) {
+        qemu_del_timer(s->stats_timer);
+        qemu_free_timer(s->stats_timer);
+        s->stats_timer = NULL;
+        s->stats_poll_interval = 0;
+    }
+}
+
+static void balloon_stats_change_timer(VirtIOBalloon *s, int secs)
+{
+    qemu_mod_timer(s->stats_timer, qemu_get_clock_ms(vm_clock) + secs * 1000);
+}
+
+static void balloon_stats_poll_cb(void *opaque)
+{
+    VirtIOBalloon *s = opaque;
+    VirtIODevice *vdev = VIRTIO_DEVICE(s);
+
+    if (!balloon_stats_supported(s)) {
+        /* re-schedule */
+        balloon_stats_change_timer(s, s->stats_poll_interval);
+        return;
+    }
+
+    virtqueue_push(s->svq, &s->stats_vq_elem, s->stats_vq_offset);
+    virtio_notify(vdev, s->svq);
+}
+
+static void balloon_stats_get_all(Object *obj, struct Visitor *v,
+                                  void *opaque, const char *name, Error **errp)
+{
+    VirtIOBalloon *s = opaque;
+    int i;
+
+    if (!s->stats_last_update) {
+        error_setg(errp, "guest hasn't updated any stats yet");
+        return;
+    }
+
+    visit_start_struct(v, NULL, "guest-stats", name, 0, errp);
+    visit_type_int(v, &s->stats_last_update, "last-update", errp);
+
+    visit_start_struct(v, NULL, NULL, "stats", 0, errp);
+    for (i = 0; i < VIRTIO_BALLOON_S_NR; i++) {
+        visit_type_int64(v, (int64_t *) &s->stats[i], balloon_stat_names[i],
+                         errp);
+    }
+    visit_end_struct(v, errp);
+
+    visit_end_struct(v, errp);
+}
+
+static void balloon_stats_get_poll_interval(Object *obj, struct Visitor *v,
+                                            void *opaque, const char *name,
+                                            Error **errp)
+{
+    VirtIOBalloon *s = opaque;
+    visit_type_int(v, &s->stats_poll_interval, name, errp);
+}
+
+static void balloon_stats_set_poll_interval(Object *obj, struct Visitor *v,
+                                            void *opaque, const char *name,
+                                            Error **errp)
+{
+    VirtIOBalloon *s = opaque;
+    int64_t value;
+
+    visit_type_int(v, &value, name, errp);
+    if (error_is_set(errp)) {
+        return;
+    }
+
+    if (value < 0) {
+        error_setg(errp, "timer value must be greater than zero");
+        return;
+    }
+
+    if (value == s->stats_poll_interval) {
+        return;
+    }
+
+    if (value == 0) {
+        /* timer=0 disables the timer */
+        balloon_stats_destroy_timer(s);
+        return;
+    }
+
+    if (balloon_stats_enabled(s)) {
+        /* timer interval change */
+        s->stats_poll_interval = value;
+        balloon_stats_change_timer(s, value);
+        return;
+    }
+
+    /* create a new timer */
+    g_assert(s->stats_timer == NULL);
+    s->stats_timer = qemu_new_timer_ms(vm_clock, balloon_stats_poll_cb, s);
+    s->stats_poll_interval = value;
+    balloon_stats_change_timer(s, 0);
+}
+
+static void virtio_balloon_handle_output(VirtIODevice *vdev, VirtQueue *vq)
+{
+    VirtIOBalloon *s = VIRTIO_BALLOON(vdev);
+    VirtQueueElement elem;
+    MemoryRegionSection section;
+
+    while (virtqueue_pop(vq, &elem)) {
+        size_t offset = 0;
+        uint32_t pfn;
+
+        while (iov_to_buf(elem.out_sg, elem.out_num, offset, &pfn, 4) == 4) {
+            ram_addr_t pa;
+            ram_addr_t addr;
+
+            pa = (ram_addr_t)ldl_p(&pfn) << VIRTIO_BALLOON_PFN_SHIFT;
+            offset += 4;
+
+            /* FIXME: remove get_system_memory(), but how? */
+            section = memory_region_find(get_system_memory(), pa, 1);
+            if (!section.size || !memory_region_is_ram(section.mr))
+                continue;
+
+            /* Using memory_region_get_ram_ptr is bending the rules a bit, but
+               should be OK because we only want a single page.  */
+            addr = section.offset_within_region;
+            balloon_page(memory_region_get_ram_ptr(section.mr) + addr,
+                         !!(vq == s->dvq));
+        }
+
+        virtqueue_push(vq, &elem, offset);
+        virtio_notify(vdev, vq);
+    }
+}
+
+static void virtio_balloon_receive_stats(VirtIODevice *vdev, VirtQueue *vq)
+{
+    VirtIOBalloon *s = VIRTIO_BALLOON(vdev);
+    VirtQueueElement *elem = &s->stats_vq_elem;
+    VirtIOBalloonStat stat;
+    size_t offset = 0;
+    qemu_timeval tv;
+
+    if (!virtqueue_pop(vq, elem)) {
+        goto out;
+    }
+
+    /* Initialize the stats to get rid of any stale values.  This is only
+     * needed to handle the case where a guest supports fewer stats than it
+     * used to (ie. it has booted into an old kernel).
+     */
+    reset_stats(s);
+
+    while (iov_to_buf(elem->out_sg, elem->out_num, offset, &stat, sizeof(stat))
+           == sizeof(stat)) {
+        uint16_t tag = tswap16(stat.tag);
+        uint64_t val = tswap64(stat.val);
+
+        offset += sizeof(stat);
+        if (tag < VIRTIO_BALLOON_S_NR)
+            s->stats[tag] = val;
+    }
+    s->stats_vq_offset = offset;
+
+    if (qemu_gettimeofday(&tv) < 0) {
+        fprintf(stderr, "warning: %s: failed to get time of day\n", __func__);
+        goto out;
+    }
+
+    s->stats_last_update = tv.tv_sec;
+
+out:
+    if (balloon_stats_enabled(s)) {
+        balloon_stats_change_timer(s, s->stats_poll_interval);
+    }
+}
+
+static void virtio_balloon_get_config(VirtIODevice *vdev, uint8_t *config_data)
+{
+    VirtIOBalloon *dev = VIRTIO_BALLOON(vdev);
+    struct virtio_balloon_config config;
+
+    config.num_pages = cpu_to_le32(dev->num_pages);
+    config.actual = cpu_to_le32(dev->actual);
+
+    memcpy(config_data, &config, 8);
+}
+
+static void virtio_balloon_set_config(VirtIODevice *vdev,
+                                      const uint8_t *config_data)
+{
+    VirtIOBalloon *dev = VIRTIO_BALLOON(vdev);
+    struct virtio_balloon_config config;
+    uint32_t oldactual = dev->actual;
+    memcpy(&config, config_data, 8);
+    dev->actual = le32_to_cpu(config.actual);
+    if (dev->actual != oldactual) {
+        qemu_balloon_changed(ram_size -
+                             (dev->actual << VIRTIO_BALLOON_PFN_SHIFT));
+    }
+}
+
+static uint32_t virtio_balloon_get_features(VirtIODevice *vdev, uint32_t f)
+{
+    f |= (1 << VIRTIO_BALLOON_F_STATS_VQ);
+    return f;
+}
+
+static void virtio_balloon_stat(void *opaque, BalloonInfo *info)
+{
+    VirtIOBalloon *dev = opaque;
+    info->actual = ram_size - ((uint64_t) dev->actual <<
+                               VIRTIO_BALLOON_PFN_SHIFT);
+}
+
+static void virtio_balloon_to_target(void *opaque, ram_addr_t target)
+{
+    VirtIOBalloon *dev = VIRTIO_BALLOON(opaque);
+    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+
+    if (target > ram_size) {
+        target = ram_size;
+    }
+    if (target) {
+        dev->num_pages = (ram_size - target) >> VIRTIO_BALLOON_PFN_SHIFT;
+        virtio_notify_config(vdev);
+    }
+}
+
+static void virtio_balloon_save(QEMUFile *f, void *opaque)
+{
+    VirtIOBalloon *s = VIRTIO_BALLOON(opaque);
+    VirtIODevice *vdev = VIRTIO_DEVICE(s);
+
+    virtio_save(vdev, f);
+
+    qemu_put_be32(f, s->num_pages);
+    qemu_put_be32(f, s->actual);
+}
+
+static int virtio_balloon_load(QEMUFile *f, void *opaque, int version_id)
+{
+    VirtIOBalloon *s = VIRTIO_BALLOON(opaque);
+    VirtIODevice *vdev = VIRTIO_DEVICE(s);
+    int ret;
+
+    if (version_id != 1)
+        return -EINVAL;
+
+    ret = virtio_load(vdev, f);
+    if (ret) {
+        return ret;
+    }
+
+    s->num_pages = qemu_get_be32(f);
+    s->actual = qemu_get_be32(f);
+    return 0;
+}
+
+static int virtio_balloon_device_init(VirtIODevice *vdev)
+{
+    DeviceState *qdev = DEVICE(vdev);
+    VirtIOBalloon *s = VIRTIO_BALLOON(vdev);
+    int ret;
+
+    virtio_init(vdev, "virtio-balloon", VIRTIO_ID_BALLOON, 8);
+
+    vdev->get_config = virtio_balloon_get_config;
+    vdev->set_config = virtio_balloon_set_config;
+    vdev->get_features = virtio_balloon_get_features;
+
+    ret = qemu_add_balloon_handler(virtio_balloon_to_target,
+                                   virtio_balloon_stat, s);
+
+    if (ret < 0) {
+        virtio_common_cleanup(VIRTIO_DEVICE(s));
+        return -1;
+    }
+
+    s->ivq = virtio_add_queue(vdev, 128, virtio_balloon_handle_output);
+    s->dvq = virtio_add_queue(vdev, 128, virtio_balloon_handle_output);
+    s->svq = virtio_add_queue(vdev, 128, virtio_balloon_receive_stats);
+
+    register_savevm(qdev, "virtio-balloon", -1, 1,
+                    virtio_balloon_save, virtio_balloon_load, s);
+
+    object_property_add(OBJECT(qdev), "guest-stats", "guest statistics",
+                        balloon_stats_get_all, NULL, NULL, s, NULL);
+
+    object_property_add(OBJECT(qdev), "guest-stats-polling-interval", "int",
+                        balloon_stats_get_poll_interval,
+                        balloon_stats_set_poll_interval,
+                        NULL, s, NULL);
+    return 0;
+}
+
+static int virtio_balloon_device_exit(DeviceState *qdev)
+{
+    VirtIOBalloon *s = VIRTIO_BALLOON(qdev);
+    VirtIODevice *vdev = VIRTIO_DEVICE(qdev);
+
+    balloon_stats_destroy_timer(s);
+    qemu_remove_balloon_handler(s);
+    unregister_savevm(qdev, "virtio-balloon", s);
+    virtio_common_cleanup(vdev);
+    return 0;
+}
+
+static Property virtio_balloon_properties[] = {
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void virtio_balloon_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
+    dc->exit = virtio_balloon_device_exit;
+    dc->props = virtio_balloon_properties;
+    vdc->init = virtio_balloon_device_init;
+    vdc->get_config = virtio_balloon_get_config;
+    vdc->set_config = virtio_balloon_set_config;
+    vdc->get_features = virtio_balloon_get_features;
+}
+
+static const TypeInfo virtio_balloon_info = {
+    .name = TYPE_VIRTIO_BALLOON,
+    .parent = TYPE_VIRTIO_DEVICE,
+    .instance_size = sizeof(VirtIOBalloon),
+    .class_init = virtio_balloon_class_init,
+};
+
+static void virtio_register_types(void)
+{
+    type_register_static(&virtio_balloon_info);
+}
+
+type_init(virtio_register_types)
diff --git a/hw/virtio/virtio-bus.c b/hw/virtio/virtio-bus.c
new file mode 100644 (file)
index 0000000..1596a1c
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * VirtioBus
+ *
+ *  Copyright (C) 2012 : GreenSocs Ltd
+ *      http://www.greensocs.com/ , email: info@greensocs.com
+ *
+ *  Developed by :
+ *  Frederic Konrad   <fred.konrad@greensocs.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 "hw/hw.h"
+#include "qemu/error-report.h"
+#include "hw/qdev.h"
+#include "hw/virtio/virtio-bus.h"
+#include "hw/virtio/virtio.h"
+
+/* #define DEBUG_VIRTIO_BUS */
+
+#ifdef DEBUG_VIRTIO_BUS
+#define DPRINTF(fmt, ...) \
+do { printf("virtio_bus: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) do { } while (0)
+#endif
+
+/* Plug the VirtIODevice */
+int virtio_bus_plug_device(VirtIODevice *vdev)
+{
+    DeviceState *qdev = DEVICE(vdev);
+    BusState *qbus = BUS(qdev_get_parent_bus(qdev));
+    VirtioBusState *bus = VIRTIO_BUS(qbus);
+    VirtioBusClass *klass = VIRTIO_BUS_GET_CLASS(bus);
+    DPRINTF("%s: plug device.\n", qbus->name);
+
+    bus->vdev = vdev;
+
+    /*
+     * The lines below will disappear when we drop VirtIOBindings, at the end
+     * of the series.
+     */
+    bus->bindings.notify = klass->notify;
+    bus->bindings.save_config = klass->save_config;
+    bus->bindings.save_queue = klass->save_queue;
+    bus->bindings.load_config = klass->load_config;
+    bus->bindings.load_queue = klass->load_queue;
+    bus->bindings.load_done = klass->load_done;
+    bus->bindings.get_features = klass->get_features;
+    bus->bindings.query_guest_notifiers = klass->query_guest_notifiers;
+    bus->bindings.set_guest_notifiers = klass->set_guest_notifiers;
+    bus->bindings.set_host_notifier = klass->set_host_notifier;
+    bus->bindings.vmstate_change = klass->vmstate_change;
+    virtio_bind_device(bus->vdev, &bus->bindings, qbus->parent);
+
+    if (klass->device_plugged != NULL) {
+        klass->device_plugged(qbus->parent);
+    }
+
+    return 0;
+}
+
+/* Reset the virtio_bus */
+void virtio_bus_reset(VirtioBusState *bus)
+{
+    DPRINTF("%s: reset device.\n", qbus->name);
+    if (bus->vdev != NULL) {
+        virtio_reset(bus->vdev);
+    }
+}
+
+/* Destroy the VirtIODevice */
+void virtio_bus_destroy_device(VirtioBusState *bus)
+{
+    DeviceState *qdev;
+    BusState *qbus = BUS(bus);
+    VirtioBusClass *klass = VIRTIO_BUS_GET_CLASS(bus);
+    DPRINTF("%s: remove device.\n", qbus->name);
+
+    if (bus->vdev != NULL) {
+        if (klass->device_unplug != NULL) {
+            klass->device_unplug(qbus->parent);
+        }
+        qdev = DEVICE(bus->vdev);
+        qdev_free(qdev);
+        bus->vdev = NULL;
+    }
+}
+
+/* Get the device id of the plugged device. */
+uint16_t virtio_bus_get_vdev_id(VirtioBusState *bus)
+{
+    assert(bus->vdev != NULL);
+    return bus->vdev->device_id;
+}
+
+/* Get the config_len field of the plugged device. */
+size_t virtio_bus_get_vdev_config_len(VirtioBusState *bus)
+{
+    assert(bus->vdev != NULL);
+    return bus->vdev->config_len;
+}
+
+/* Get the features of the plugged device. */
+uint32_t virtio_bus_get_vdev_features(VirtioBusState *bus,
+                                    uint32_t requested_features)
+{
+    VirtioDeviceClass *k;
+    assert(bus->vdev != NULL);
+    k = VIRTIO_DEVICE_GET_CLASS(bus->vdev);
+    assert(k->get_features != NULL);
+    return k->get_features(bus->vdev, requested_features);
+}
+
+/* Get bad features of the plugged device. */
+uint32_t virtio_bus_get_vdev_bad_features(VirtioBusState *bus)
+{
+    VirtioDeviceClass *k;
+    assert(bus->vdev != NULL);
+    k = VIRTIO_DEVICE_GET_CLASS(bus->vdev);
+    if (k->bad_features != NULL) {
+        return k->bad_features(bus->vdev);
+    } else {
+        return 0;
+    }
+}
+
+/* Get config of the plugged device. */
+void virtio_bus_get_vdev_config(VirtioBusState *bus, uint8_t *config)
+{
+    VirtioDeviceClass *k;
+    assert(bus->vdev != NULL);
+    k = VIRTIO_DEVICE_GET_CLASS(bus->vdev);
+    if (k->get_config != NULL) {
+        k->get_config(bus->vdev, config);
+    }
+}
+
+static const TypeInfo virtio_bus_info = {
+    .name = TYPE_VIRTIO_BUS,
+    .parent = TYPE_BUS,
+    .instance_size = sizeof(VirtioBusState),
+    .abstract = true,
+    .class_size = sizeof(VirtioBusClass),
+};
+
+static void virtio_register_types(void)
+{
+    type_register_static(&virtio_bus_info);
+}
+
+type_init(virtio_register_types)
diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
new file mode 100644 (file)
index 0000000..2b22588
--- /dev/null
@@ -0,0 +1,1514 @@
+/*
+ * Virtio PCI Bindings
+ *
+ * Copyright IBM, Corp. 2007
+ * Copyright (c) 2009 CodeSourcery
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *  Paul Brook        <paul@codesourcery.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 <inttypes.h>
+
+#include "hw/virtio/virtio.h"
+#include "hw/virtio/virtio-blk.h"
+#include "hw/virtio/virtio-net.h"
+#include "hw/virtio/virtio-serial.h"
+#include "hw/virtio/virtio-scsi.h"
+#include "hw/virtio/virtio-balloon.h"
+#include "hw/pci/pci.h"
+#include "qemu/error-report.h"
+#include "hw/pci/msi.h"
+#include "hw/pci/msix.h"
+#include "hw/loader.h"
+#include "sysemu/kvm.h"
+#include "sysemu/blockdev.h"
+#include "virtio-pci.h"
+#include "qemu/range.h"
+#include "hw/virtio/virtio-bus.h"
+
+/* from Linux's linux/virtio_pci.h */
+
+/* A 32-bit r/o bitmask of the features supported by the host */
+#define VIRTIO_PCI_HOST_FEATURES        0
+
+/* A 32-bit r/w bitmask of features activated by the guest */
+#define VIRTIO_PCI_GUEST_FEATURES       4
+
+/* A 32-bit r/w PFN for the currently selected queue */
+#define VIRTIO_PCI_QUEUE_PFN            8
+
+/* A 16-bit r/o queue size for the currently selected queue */
+#define VIRTIO_PCI_QUEUE_NUM            12
+
+/* A 16-bit r/w queue selector */
+#define VIRTIO_PCI_QUEUE_SEL            14
+
+/* A 16-bit r/w queue notifier */
+#define VIRTIO_PCI_QUEUE_NOTIFY         16
+
+/* An 8-bit device status register.  */
+#define VIRTIO_PCI_STATUS               18
+
+/* An 8-bit r/o interrupt status register.  Reading the value will return the
+ * current contents of the ISR and will also clear it.  This is effectively
+ * a read-and-acknowledge. */
+#define VIRTIO_PCI_ISR                  19
+
+/* MSI-X registers: only enabled if MSI-X is enabled. */
+/* A 16-bit vector for configuration changes. */
+#define VIRTIO_MSI_CONFIG_VECTOR        20
+/* A 16-bit vector for selected queue notifications. */
+#define VIRTIO_MSI_QUEUE_VECTOR         22
+
+/* Config space size */
+#define VIRTIO_PCI_CONFIG_NOMSI         20
+#define VIRTIO_PCI_CONFIG_MSI           24
+#define VIRTIO_PCI_REGION_SIZE(dev)     (msix_present(dev) ? \
+                                         VIRTIO_PCI_CONFIG_MSI : \
+                                         VIRTIO_PCI_CONFIG_NOMSI)
+
+/* The remaining space is defined by each driver as the per-driver
+ * configuration space */
+#define VIRTIO_PCI_CONFIG(dev)          (msix_enabled(dev) ? \
+                                         VIRTIO_PCI_CONFIG_MSI : \
+                                         VIRTIO_PCI_CONFIG_NOMSI)
+
+/* How many bits to shift physical queue address written to QUEUE_PFN.
+ * 12 is historical, and due to x86 page size. */
+#define VIRTIO_PCI_QUEUE_ADDR_SHIFT    12
+
+/* Flags track per-device state like workarounds for quirks in older guests. */
+#define VIRTIO_PCI_FLAG_BUS_MASTER_BUG  (1 << 0)
+
+/* QEMU doesn't strictly need write barriers since everything runs in
+ * lock-step.  We'll leave the calls to wmb() in though to make it obvious for
+ * KVM or if kqemu gets SMP support.
+ */
+#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 */
+/* DeviceState to VirtIOPCIProxy. For use off data-path. TODO: use QOM. */
+static inline VirtIOPCIProxy *to_virtio_pci_proxy(DeviceState *d)
+{
+    return container_of(d, VirtIOPCIProxy, pci_dev.qdev);
+}
+
+/* DeviceState to VirtIOPCIProxy. Note: used on datapath,
+ * be careful and test performance if you change this.
+ */
+static inline VirtIOPCIProxy *to_virtio_pci_proxy_fast(DeviceState *d)
+{
+    return container_of(d, VirtIOPCIProxy, pci_dev.qdev);
+}
+
+static void virtio_pci_notify(DeviceState *d, uint16_t vector)
+{
+    VirtIOPCIProxy *proxy = to_virtio_pci_proxy_fast(d);
+    if (msix_enabled(&proxy->pci_dev))
+        msix_notify(&proxy->pci_dev, vector);
+    else
+        qemu_set_irq(proxy->pci_dev.irq[0], proxy->vdev->isr & 1);
+}
+
+static void virtio_pci_save_config(DeviceState *d, QEMUFile *f)
+{
+    VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
+    pci_device_save(&proxy->pci_dev, f);
+    msix_save(&proxy->pci_dev, f);
+    if (msix_present(&proxy->pci_dev))
+        qemu_put_be16(f, proxy->vdev->config_vector);
+}
+
+static void virtio_pci_save_queue(DeviceState *d, int n, QEMUFile *f)
+{
+    VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
+    if (msix_present(&proxy->pci_dev))
+        qemu_put_be16(f, virtio_queue_vector(proxy->vdev, n));
+}
+
+static int virtio_pci_load_config(DeviceState *d, QEMUFile *f)
+{
+    VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
+    int ret;
+    ret = pci_device_load(&proxy->pci_dev, f);
+    if (ret) {
+        return ret;
+    }
+    msix_unuse_all_vectors(&proxy->pci_dev);
+    msix_load(&proxy->pci_dev, f);
+    if (msix_present(&proxy->pci_dev)) {
+        qemu_get_be16s(f, &proxy->vdev->config_vector);
+    } else {
+        proxy->vdev->config_vector = VIRTIO_NO_VECTOR;
+    }
+    if (proxy->vdev->config_vector != VIRTIO_NO_VECTOR) {
+        return msix_vector_use(&proxy->pci_dev, proxy->vdev->config_vector);
+    }
+    return 0;
+}
+
+static int virtio_pci_load_queue(DeviceState *d, int n, QEMUFile *f)
+{
+    VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
+    uint16_t vector;
+    if (msix_present(&proxy->pci_dev)) {
+        qemu_get_be16s(f, &vector);
+    } else {
+        vector = VIRTIO_NO_VECTOR;
+    }
+    virtio_queue_set_vector(proxy->vdev, n, vector);
+    if (vector != VIRTIO_NO_VECTOR) {
+        return msix_vector_use(&proxy->pci_dev, vector);
+    }
+    return 0;
+}
+
+static int virtio_pci_set_host_notifier_internal(VirtIOPCIProxy *proxy,
+                                                 int n, bool assign, bool set_handler)
+{
+    VirtQueue *vq = virtio_get_queue(proxy->vdev, n);
+    EventNotifier *notifier = virtio_queue_get_host_notifier(vq);
+    int r = 0;
+
+    if (assign) {
+        r = event_notifier_init(notifier, 1);
+        if (r < 0) {
+            error_report("%s: unable to init event notifier: %d",
+                         __func__, r);
+            return r;
+        }
+        virtio_queue_set_host_notifier_fd_handler(vq, true, set_handler);
+        memory_region_add_eventfd(&proxy->bar, VIRTIO_PCI_QUEUE_NOTIFY, 2,
+                                  true, n, notifier);
+    } else {
+        memory_region_del_eventfd(&proxy->bar, VIRTIO_PCI_QUEUE_NOTIFY, 2,
+                                  true, n, notifier);
+        virtio_queue_set_host_notifier_fd_handler(vq, false, false);
+        event_notifier_cleanup(notifier);
+    }
+    return r;
+}
+
+static void virtio_pci_start_ioeventfd(VirtIOPCIProxy *proxy)
+{
+    int n, r;
+
+    if (!(proxy->flags & VIRTIO_PCI_FLAG_USE_IOEVENTFD) ||
+        proxy->ioeventfd_disabled ||
+        proxy->ioeventfd_started) {
+        return;
+    }
+
+    for (n = 0; n < VIRTIO_PCI_QUEUE_MAX; n++) {
+        if (!virtio_queue_get_num(proxy->vdev, n)) {
+            continue;
+        }
+
+        r = virtio_pci_set_host_notifier_internal(proxy, n, true, true);
+        if (r < 0) {
+            goto assign_error;
+        }
+    }
+    proxy->ioeventfd_started = true;
+    return;
+
+assign_error:
+    while (--n >= 0) {
+        if (!virtio_queue_get_num(proxy->vdev, n)) {
+            continue;
+        }
+
+        r = virtio_pci_set_host_notifier_internal(proxy, n, false, false);
+        assert(r >= 0);
+    }
+    proxy->ioeventfd_started = false;
+    error_report("%s: failed. Fallback to a userspace (slower).", __func__);
+}
+
+static void virtio_pci_stop_ioeventfd(VirtIOPCIProxy *proxy)
+{
+    int r;
+    int n;
+
+    if (!proxy->ioeventfd_started) {
+        return;
+    }
+
+    for (n = 0; n < VIRTIO_PCI_QUEUE_MAX; n++) {
+        if (!virtio_queue_get_num(proxy->vdev, n)) {
+            continue;
+        }
+
+        r = virtio_pci_set_host_notifier_internal(proxy, n, false, false);
+        assert(r >= 0);
+    }
+    proxy->ioeventfd_started = false;
+}
+
+static void virtio_pci_reset(DeviceState *d)
+{
+    VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
+    virtio_pci_stop_ioeventfd(proxy);
+    virtio_reset(proxy->vdev);
+    msix_unuse_all_vectors(&proxy->pci_dev);
+    proxy->flags &= ~VIRTIO_PCI_FLAG_BUS_MASTER_BUG;
+}
+
+static void virtio_ioport_write(void *opaque, uint32_t addr, uint32_t val)
+{
+    VirtIOPCIProxy *proxy = opaque;
+    VirtIODevice *vdev = proxy->vdev;
+    hwaddr pa;
+
+    switch (addr) {
+    case VIRTIO_PCI_GUEST_FEATURES:
+       /* Guest does not negotiate properly?  We have to assume nothing. */
+       if (val & (1 << VIRTIO_F_BAD_FEATURE)) {
+            val = vdev->bad_features ? vdev->bad_features(vdev) : 0;
+       }
+        virtio_set_features(vdev, val);
+        break;
+    case VIRTIO_PCI_QUEUE_PFN:
+        pa = (hwaddr)val << VIRTIO_PCI_QUEUE_ADDR_SHIFT;
+        if (pa == 0) {
+            virtio_pci_stop_ioeventfd(proxy);
+            virtio_reset(proxy->vdev);
+            msix_unuse_all_vectors(&proxy->pci_dev);
+        }
+        else
+            virtio_queue_set_addr(vdev, vdev->queue_sel, pa);
+        break;
+    case VIRTIO_PCI_QUEUE_SEL:
+        if (val < VIRTIO_PCI_QUEUE_MAX)
+            vdev->queue_sel = val;
+        break;
+    case VIRTIO_PCI_QUEUE_NOTIFY:
+        if (val < VIRTIO_PCI_QUEUE_MAX) {
+            virtio_queue_notify(vdev, val);
+        }
+        break;
+    case VIRTIO_PCI_STATUS:
+        if (!(val & VIRTIO_CONFIG_S_DRIVER_OK)) {
+            virtio_pci_stop_ioeventfd(proxy);
+        }
+
+        virtio_set_status(vdev, val & 0xFF);
+
+        if (val & VIRTIO_CONFIG_S_DRIVER_OK) {
+            virtio_pci_start_ioeventfd(proxy);
+        }
+
+        if (vdev->status == 0) {
+            virtio_reset(proxy->vdev);
+            msix_unuse_all_vectors(&proxy->pci_dev);
+        }
+
+        /* Linux before 2.6.34 sets the device as OK without enabling
+           the PCI device bus master bit. In this case we need to disable
+           some safety checks. */
+        if ((val & VIRTIO_CONFIG_S_DRIVER_OK) &&
+            !(proxy->pci_dev.config[PCI_COMMAND] & PCI_COMMAND_MASTER)) {
+            proxy->flags |= VIRTIO_PCI_FLAG_BUS_MASTER_BUG;
+        }
+        break;
+    case VIRTIO_MSI_CONFIG_VECTOR:
+        msix_vector_unuse(&proxy->pci_dev, vdev->config_vector);
+        /* Make it possible for guest to discover an error took place. */
+        if (msix_vector_use(&proxy->pci_dev, val) < 0)
+            val = VIRTIO_NO_VECTOR;
+        vdev->config_vector = val;
+        break;
+    case VIRTIO_MSI_QUEUE_VECTOR:
+        msix_vector_unuse(&proxy->pci_dev,
+                          virtio_queue_vector(vdev, vdev->queue_sel));
+        /* Make it possible for guest to discover an error took place. */
+        if (msix_vector_use(&proxy->pci_dev, val) < 0)
+            val = VIRTIO_NO_VECTOR;
+        virtio_queue_set_vector(vdev, vdev->queue_sel, val);
+        break;
+    default:
+        error_report("%s: unexpected address 0x%x value 0x%x",
+                     __func__, addr, val);
+        break;
+    }
+}
+
+static uint32_t virtio_ioport_read(VirtIOPCIProxy *proxy, uint32_t addr)
+{
+    VirtIODevice *vdev = proxy->vdev;
+    uint32_t ret = 0xFFFFFFFF;
+
+    switch (addr) {
+    case VIRTIO_PCI_HOST_FEATURES:
+        ret = proxy->host_features;
+        break;
+    case VIRTIO_PCI_GUEST_FEATURES:
+        ret = vdev->guest_features;
+        break;
+    case VIRTIO_PCI_QUEUE_PFN:
+        ret = virtio_queue_get_addr(vdev, vdev->queue_sel)
+              >> VIRTIO_PCI_QUEUE_ADDR_SHIFT;
+        break;
+    case VIRTIO_PCI_QUEUE_NUM:
+        ret = virtio_queue_get_num(vdev, vdev->queue_sel);
+        break;
+    case VIRTIO_PCI_QUEUE_SEL:
+        ret = vdev->queue_sel;
+        break;
+    case VIRTIO_PCI_STATUS:
+        ret = vdev->status;
+        break;
+    case VIRTIO_PCI_ISR:
+        /* reading from the ISR also clears it. */
+        ret = vdev->isr;
+        vdev->isr = 0;
+        qemu_set_irq(proxy->pci_dev.irq[0], 0);
+        break;
+    case VIRTIO_MSI_CONFIG_VECTOR:
+        ret = vdev->config_vector;
+        break;
+    case VIRTIO_MSI_QUEUE_VECTOR:
+        ret = virtio_queue_vector(vdev, vdev->queue_sel);
+        break;
+    default:
+        break;
+    }
+
+    return ret;
+}
+
+static uint64_t virtio_pci_config_read(void *opaque, hwaddr addr,
+                                       unsigned size)
+{
+    VirtIOPCIProxy *proxy = opaque;
+    uint32_t config = VIRTIO_PCI_CONFIG(&proxy->pci_dev);
+    uint64_t val = 0;
+    if (addr < config) {
+        return virtio_ioport_read(proxy, addr);
+    }
+    addr -= config;
+
+    switch (size) {
+    case 1:
+        val = virtio_config_readb(proxy->vdev, addr);
+        break;
+    case 2:
+        val = virtio_config_readw(proxy->vdev, addr);
+        if (virtio_is_big_endian()) {
+            val = bswap16(val);
+        }
+        break;
+    case 4:
+        val = virtio_config_readl(proxy->vdev, addr);
+        if (virtio_is_big_endian()) {
+            val = bswap32(val);
+        }
+        break;
+    }
+    return val;
+}
+
+static void virtio_pci_config_write(void *opaque, hwaddr addr,
+                                    uint64_t val, unsigned size)
+{
+    VirtIOPCIProxy *proxy = opaque;
+    uint32_t config = VIRTIO_PCI_CONFIG(&proxy->pci_dev);
+    if (addr < config) {
+        virtio_ioport_write(proxy, addr, val);
+        return;
+    }
+    addr -= config;
+    /*
+     * Virtio-PCI is odd. Ioports are LE but config space is target native
+     * endian.
+     */
+    switch (size) {
+    case 1:
+        virtio_config_writeb(proxy->vdev, addr, val);
+        break;
+    case 2:
+        if (virtio_is_big_endian()) {
+            val = bswap16(val);
+        }
+        virtio_config_writew(proxy->vdev, addr, val);
+        break;
+    case 4:
+        if (virtio_is_big_endian()) {
+            val = bswap32(val);
+        }
+        virtio_config_writel(proxy->vdev, addr, val);
+        break;
+    }
+}
+
+static const MemoryRegionOps virtio_pci_config_ops = {
+    .read = virtio_pci_config_read,
+    .write = virtio_pci_config_write,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 4,
+    },
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void virtio_write_config(PCIDevice *pci_dev, uint32_t address,
+                                uint32_t val, int len)
+{
+    VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
+
+    pci_default_write_config(pci_dev, address, val, len);
+
+    if (range_covers_byte(address, len, PCI_COMMAND) &&
+        !(pci_dev->config[PCI_COMMAND] & PCI_COMMAND_MASTER) &&
+        !(proxy->flags & VIRTIO_PCI_FLAG_BUS_MASTER_BUG)) {
+        virtio_pci_stop_ioeventfd(proxy);
+        virtio_set_status(proxy->vdev,
+                          proxy->vdev->status & ~VIRTIO_CONFIG_S_DRIVER_OK);
+    }
+}
+
+static unsigned virtio_pci_get_features(DeviceState *d)
+{
+    VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
+    return proxy->host_features;
+}
+
+static int kvm_virtio_pci_vq_vector_use(VirtIOPCIProxy *proxy,
+                                        unsigned int queue_no,
+                                        unsigned int vector,
+                                        MSIMessage msg)
+{
+    VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector];
+    int ret;
+
+    if (irqfd->users == 0) {
+        ret = kvm_irqchip_add_msi_route(kvm_state, msg);
+        if (ret < 0) {
+            return ret;
+        }
+        irqfd->virq = ret;
+    }
+    irqfd->users++;
+    return 0;
+}
+
+static void kvm_virtio_pci_vq_vector_release(VirtIOPCIProxy *proxy,
+                                             unsigned int vector)
+{
+    VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector];
+    if (--irqfd->users == 0) {
+        kvm_irqchip_release_virq(kvm_state, irqfd->virq);
+    }
+}
+
+static int kvm_virtio_pci_irqfd_use(VirtIOPCIProxy *proxy,
+                                 unsigned int queue_no,
+                                 unsigned int vector)
+{
+    VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector];
+    VirtQueue *vq = virtio_get_queue(proxy->vdev, queue_no);
+    EventNotifier *n = virtio_queue_get_guest_notifier(vq);
+    int ret;
+    ret = kvm_irqchip_add_irqfd_notifier(kvm_state, n, irqfd->virq);
+    return ret;
+}
+
+static void kvm_virtio_pci_irqfd_release(VirtIOPCIProxy *proxy,
+                                      unsigned int queue_no,
+                                      unsigned int vector)
+{
+    VirtQueue *vq = virtio_get_queue(proxy->vdev, queue_no);
+    EventNotifier *n = virtio_queue_get_guest_notifier(vq);
+    VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector];
+    int ret;
+
+    ret = kvm_irqchip_remove_irqfd_notifier(kvm_state, n, irqfd->virq);
+    assert(ret == 0);
+}
+
+static int kvm_virtio_pci_vector_use(VirtIOPCIProxy *proxy, int nvqs)
+{
+    PCIDevice *dev = &proxy->pci_dev;
+    VirtIODevice *vdev = proxy->vdev;
+    unsigned int vector;
+    int ret, queue_no;
+    MSIMessage msg;
+
+    for (queue_no = 0; queue_no < nvqs; queue_no++) {
+        if (!virtio_queue_get_num(vdev, queue_no)) {
+            break;
+        }
+        vector = virtio_queue_vector(vdev, queue_no);
+        if (vector >= msix_nr_vectors_allocated(dev)) {
+            continue;
+        }
+        msg = msix_get_message(dev, vector);
+        ret = kvm_virtio_pci_vq_vector_use(proxy, queue_no, vector, msg);
+        if (ret < 0) {
+            goto undo;
+        }
+        /* If guest supports masking, set up irqfd now.
+         * Otherwise, delay until unmasked in the frontend.
+         */
+        if (proxy->vdev->guest_notifier_mask) {
+            ret = kvm_virtio_pci_irqfd_use(proxy, queue_no, vector);
+            if (ret < 0) {
+                kvm_virtio_pci_vq_vector_release(proxy, vector);
+                goto undo;
+            }
+        }
+    }
+    return 0;
+
+undo:
+    while (--queue_no >= 0) {
+        vector = virtio_queue_vector(vdev, queue_no);
+        if (vector >= msix_nr_vectors_allocated(dev)) {
+            continue;
+        }
+        if (proxy->vdev->guest_notifier_mask) {
+            kvm_virtio_pci_irqfd_release(proxy, queue_no, vector);
+        }
+        kvm_virtio_pci_vq_vector_release(proxy, vector);
+    }
+    return ret;
+}
+
+static void kvm_virtio_pci_vector_release(VirtIOPCIProxy *proxy, int nvqs)
+{
+    PCIDevice *dev = &proxy->pci_dev;
+    VirtIODevice *vdev = proxy->vdev;
+    unsigned int vector;
+    int queue_no;
+
+    for (queue_no = 0; queue_no < nvqs; queue_no++) {
+        if (!virtio_queue_get_num(vdev, queue_no)) {
+            break;
+        }
+        vector = virtio_queue_vector(vdev, queue_no);
+        if (vector >= msix_nr_vectors_allocated(dev)) {
+            continue;
+        }
+        /* If guest supports masking, clean up irqfd now.
+         * Otherwise, it was cleaned when masked in the frontend.
+         */
+        if (proxy->vdev->guest_notifier_mask) {
+            kvm_virtio_pci_irqfd_release(proxy, queue_no, vector);
+        }
+        kvm_virtio_pci_vq_vector_release(proxy, vector);
+    }
+}
+
+static int virtio_pci_vq_vector_unmask(VirtIOPCIProxy *proxy,
+                                       unsigned int queue_no,
+                                       unsigned int vector,
+                                       MSIMessage msg)
+{
+    VirtQueue *vq = virtio_get_queue(proxy->vdev, queue_no);
+    EventNotifier *n = virtio_queue_get_guest_notifier(vq);
+    VirtIOIRQFD *irqfd;
+    int ret = 0;
+
+    if (proxy->vector_irqfd) {
+        irqfd = &proxy->vector_irqfd[vector];
+        if (irqfd->msg.data != msg.data || irqfd->msg.address != msg.address) {
+            ret = kvm_irqchip_update_msi_route(kvm_state, irqfd->virq, msg);
+            if (ret < 0) {
+                return ret;
+            }
+        }
+    }
+
+    /* If guest supports masking, irqfd is already setup, unmask it.
+     * Otherwise, set it up now.
+     */
+    if (proxy->vdev->guest_notifier_mask) {
+        proxy->vdev->guest_notifier_mask(proxy->vdev, queue_no, false);
+        /* Test after unmasking to avoid losing events. */
+        if (proxy->vdev->guest_notifier_pending &&
+            proxy->vdev->guest_notifier_pending(proxy->vdev, queue_no)) {
+            event_notifier_set(n);
+        }
+    } else {
+        ret = kvm_virtio_pci_irqfd_use(proxy, queue_no, vector);
+    }
+    return ret;
+}
+
+static void virtio_pci_vq_vector_mask(VirtIOPCIProxy *proxy,
+                                             unsigned int queue_no,
+                                             unsigned int vector)
+{
+    /* If guest supports masking, keep irqfd but mask it.
+     * Otherwise, clean it up now.
+     */ 
+    if (proxy->vdev->guest_notifier_mask) {
+        proxy->vdev->guest_notifier_mask(proxy->vdev, queue_no, true);
+    } else {
+        kvm_virtio_pci_irqfd_release(proxy, queue_no, vector);
+    }
+}
+
+static int virtio_pci_vector_unmask(PCIDevice *dev, unsigned vector,
+                                    MSIMessage msg)
+{
+    VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev);
+    VirtIODevice *vdev = proxy->vdev;
+    int ret, queue_no;
+
+    for (queue_no = 0; queue_no < proxy->nvqs_with_notifiers; queue_no++) {
+        if (!virtio_queue_get_num(vdev, queue_no)) {
+            break;
+        }
+        if (virtio_queue_vector(vdev, queue_no) != vector) {
+            continue;
+        }
+        ret = virtio_pci_vq_vector_unmask(proxy, queue_no, vector, msg);
+        if (ret < 0) {
+            goto undo;
+        }
+    }
+    return 0;
+
+undo:
+    while (--queue_no >= 0) {
+        if (virtio_queue_vector(vdev, queue_no) != vector) {
+            continue;
+        }
+        virtio_pci_vq_vector_mask(proxy, queue_no, vector);
+    }
+    return ret;
+}
+
+static void virtio_pci_vector_mask(PCIDevice *dev, unsigned vector)
+{
+    VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev);
+    VirtIODevice *vdev = proxy->vdev;
+    int queue_no;
+
+    for (queue_no = 0; queue_no < proxy->nvqs_with_notifiers; queue_no++) {
+        if (!virtio_queue_get_num(vdev, queue_no)) {
+            break;
+        }
+        if (virtio_queue_vector(vdev, queue_no) != vector) {
+            continue;
+        }
+        virtio_pci_vq_vector_mask(proxy, queue_no, vector);
+    }
+}
+
+static void virtio_pci_vector_poll(PCIDevice *dev,
+                                   unsigned int vector_start,
+                                   unsigned int vector_end)
+{
+    VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev);
+    VirtIODevice *vdev = proxy->vdev;
+    int queue_no;
+    unsigned int vector;
+    EventNotifier *notifier;
+    VirtQueue *vq;
+
+    for (queue_no = 0; queue_no < proxy->nvqs_with_notifiers; queue_no++) {
+        if (!virtio_queue_get_num(vdev, queue_no)) {
+            break;
+        }
+        vector = virtio_queue_vector(vdev, queue_no);
+        if (vector < vector_start || vector >= vector_end ||
+            !msix_is_masked(dev, vector)) {
+            continue;
+        }
+        vq = virtio_get_queue(vdev, queue_no);
+        notifier = virtio_queue_get_guest_notifier(vq);
+        if (vdev->guest_notifier_pending) {
+            if (vdev->guest_notifier_pending(vdev, queue_no)) {
+                msix_set_pending(dev, vector);
+            }
+        } else if (event_notifier_test_and_clear(notifier)) {
+            msix_set_pending(dev, vector);
+        }
+    }
+}
+
+static int virtio_pci_set_guest_notifier(DeviceState *d, int n, bool assign,
+                                         bool with_irqfd)
+{
+    VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
+    VirtQueue *vq = virtio_get_queue(proxy->vdev, n);
+    EventNotifier *notifier = virtio_queue_get_guest_notifier(vq);
+
+    if (assign) {
+        int r = event_notifier_init(notifier, 0);
+        if (r < 0) {
+            return r;
+        }
+        virtio_queue_set_guest_notifier_fd_handler(vq, true, with_irqfd);
+    } else {
+        virtio_queue_set_guest_notifier_fd_handler(vq, false, with_irqfd);
+        event_notifier_cleanup(notifier);
+    }
+
+    return 0;
+}
+
+static bool virtio_pci_query_guest_notifiers(DeviceState *d)
+{
+    VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
+    return msix_enabled(&proxy->pci_dev);
+}
+
+static int virtio_pci_set_guest_notifiers(DeviceState *d, int nvqs, bool assign)
+{
+    VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
+    VirtIODevice *vdev = proxy->vdev;
+    int r, n;
+    bool with_irqfd = msix_enabled(&proxy->pci_dev) &&
+        kvm_msi_via_irqfd_enabled();
+
+    nvqs = MIN(nvqs, VIRTIO_PCI_QUEUE_MAX);
+
+    /* When deassigning, pass a consistent nvqs value
+     * to avoid leaking notifiers.
+     */
+    assert(assign || nvqs == proxy->nvqs_with_notifiers);
+
+    proxy->nvqs_with_notifiers = nvqs;
+
+    /* Must unset vector notifier while guest notifier is still assigned */
+    if ((proxy->vector_irqfd || vdev->guest_notifier_mask) && !assign) {
+        msix_unset_vector_notifiers(&proxy->pci_dev);
+        if (proxy->vector_irqfd) {
+            kvm_virtio_pci_vector_release(proxy, nvqs);
+            g_free(proxy->vector_irqfd);
+            proxy->vector_irqfd = NULL;
+        }
+    }
+
+    for (n = 0; n < nvqs; n++) {
+        if (!virtio_queue_get_num(vdev, n)) {
+            break;
+        }
+
+        r = virtio_pci_set_guest_notifier(d, n, assign,
+                                          kvm_msi_via_irqfd_enabled());
+        if (r < 0) {
+            goto assign_error;
+        }
+    }
+
+    /* Must set vector notifier after guest notifier has been assigned */
+    if ((with_irqfd || vdev->guest_notifier_mask) && assign) {
+        if (with_irqfd) {
+            proxy->vector_irqfd =
+                g_malloc0(sizeof(*proxy->vector_irqfd) *
+                          msix_nr_vectors_allocated(&proxy->pci_dev));
+            r = kvm_virtio_pci_vector_use(proxy, nvqs);
+            if (r < 0) {
+                goto assign_error;
+            }
+        }
+        r = msix_set_vector_notifiers(&proxy->pci_dev,
+                                      virtio_pci_vector_unmask,
+                                      virtio_pci_vector_mask,
+                                      virtio_pci_vector_poll);
+        if (r < 0) {
+            goto notifiers_error;
+        }
+    }
+
+    return 0;
+
+notifiers_error:
+    if (with_irqfd) {
+        assert(assign);
+        kvm_virtio_pci_vector_release(proxy, nvqs);
+    }
+
+assign_error:
+    /* We get here on assignment failure. Recover by undoing for VQs 0 .. n. */
+    assert(assign);
+    while (--n >= 0) {
+        virtio_pci_set_guest_notifier(d, n, !assign, with_irqfd);
+    }
+    return r;
+}
+
+static int virtio_pci_set_host_notifier(DeviceState *d, int n, bool assign)
+{
+    VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
+
+    /* Stop using ioeventfd for virtqueue kick if the device starts using host
+     * notifiers.  This makes it easy to avoid stepping on each others' toes.
+     */
+    proxy->ioeventfd_disabled = assign;
+    if (assign) {
+        virtio_pci_stop_ioeventfd(proxy);
+    }
+    /* We don't need to start here: it's not needed because backend
+     * currently only stops on status change away from ok,
+     * reset, vmstop and such. If we do add code to start here,
+     * need to check vmstate, device state etc. */
+    return virtio_pci_set_host_notifier_internal(proxy, n, assign, false);
+}
+
+static void virtio_pci_vmstate_change(DeviceState *d, bool running)
+{
+    VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
+
+    if (running) {
+        /* Try to find out if the guest has bus master disabled, but is
+           in ready state. Then we have a buggy guest OS. */
+        if ((proxy->vdev->status & VIRTIO_CONFIG_S_DRIVER_OK) &&
+            !(proxy->pci_dev.config[PCI_COMMAND] & PCI_COMMAND_MASTER)) {
+            proxy->flags |= VIRTIO_PCI_FLAG_BUS_MASTER_BUG;
+        }
+        virtio_pci_start_ioeventfd(proxy);
+    } else {
+        virtio_pci_stop_ioeventfd(proxy);
+    }
+}
+
+static const VirtIOBindings virtio_pci_bindings = {
+    .notify = virtio_pci_notify,
+    .save_config = virtio_pci_save_config,
+    .load_config = virtio_pci_load_config,
+    .save_queue = virtio_pci_save_queue,
+    .load_queue = virtio_pci_load_queue,
+    .get_features = virtio_pci_get_features,
+    .query_guest_notifiers = virtio_pci_query_guest_notifiers,
+    .set_host_notifier = virtio_pci_set_host_notifier,
+    .set_guest_notifiers = virtio_pci_set_guest_notifiers,
+    .vmstate_change = virtio_pci_vmstate_change,
+};
+
+void virtio_init_pci(VirtIOPCIProxy *proxy, VirtIODevice *vdev)
+{
+    uint8_t *config;
+    uint32_t size;
+
+    proxy->vdev = vdev;
+
+    config = proxy->pci_dev.config;
+
+    if (proxy->class_code) {
+        pci_config_set_class(config, proxy->class_code);
+    }
+    pci_set_word(config + PCI_SUBSYSTEM_VENDOR_ID,
+                 pci_get_word(config + PCI_VENDOR_ID));
+    pci_set_word(config + PCI_SUBSYSTEM_ID, vdev->device_id);
+    config[PCI_INTERRUPT_PIN] = 1;
+
+    if (vdev->nvectors &&
+        msix_init_exclusive_bar(&proxy->pci_dev, vdev->nvectors, 1)) {
+        vdev->nvectors = 0;
+    }
+
+    proxy->pci_dev.config_write = virtio_write_config;
+
+    size = VIRTIO_PCI_REGION_SIZE(&proxy->pci_dev) + vdev->config_len;
+    if (size & (size-1))
+        size = 1 << qemu_fls(size);
+
+    memory_region_init_io(&proxy->bar, &virtio_pci_config_ops, proxy,
+                          "virtio-pci", size);
+    pci_register_bar(&proxy->pci_dev, 0, PCI_BASE_ADDRESS_SPACE_IO,
+                     &proxy->bar);
+
+    if (!kvm_has_many_ioeventfds()) {
+        proxy->flags &= ~VIRTIO_PCI_FLAG_USE_IOEVENTFD;
+    }
+
+    virtio_bind_device(vdev, &virtio_pci_bindings, DEVICE(proxy));
+    proxy->host_features |= 0x1 << VIRTIO_F_NOTIFY_ON_EMPTY;
+    proxy->host_features |= 0x1 << VIRTIO_F_BAD_FEATURE;
+    proxy->host_features = vdev->get_features(vdev, proxy->host_features);
+}
+
+static void virtio_exit_pci(PCIDevice *pci_dev)
+{
+    VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
+
+    memory_region_destroy(&proxy->bar);
+    msix_uninit_exclusive_bar(pci_dev);
+}
+
+static int virtio_serial_init_pci(PCIDevice *pci_dev)
+{
+    VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
+    VirtIODevice *vdev;
+
+    if (proxy->class_code != PCI_CLASS_COMMUNICATION_OTHER &&
+        proxy->class_code != PCI_CLASS_DISPLAY_OTHER && /* qemu 0.10 */
+        proxy->class_code != PCI_CLASS_OTHERS)          /* qemu-kvm  */
+        proxy->class_code = PCI_CLASS_COMMUNICATION_OTHER;
+
+    vdev = virtio_serial_init(&pci_dev->qdev, &proxy->serial);
+    if (!vdev) {
+        return -1;
+    }
+
+    /* backwards-compatibility with machines that were created with
+       DEV_NVECTORS_UNSPECIFIED */
+    vdev->nvectors = proxy->nvectors == DEV_NVECTORS_UNSPECIFIED
+                                        ? proxy->serial.max_virtserial_ports + 1
+                                        : proxy->nvectors;
+    virtio_init_pci(proxy, vdev);
+    proxy->nvectors = vdev->nvectors;
+    return 0;
+}
+
+static void virtio_serial_exit_pci(PCIDevice *pci_dev)
+{
+    VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
+
+    virtio_pci_stop_ioeventfd(proxy);
+    virtio_serial_exit(proxy->vdev);
+    virtio_exit_pci(pci_dev);
+}
+
+static int virtio_net_init_pci(PCIDevice *pci_dev)
+{
+    VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
+    VirtIODevice *vdev;
+
+    vdev = virtio_net_init(&pci_dev->qdev, &proxy->nic, &proxy->net,
+                           proxy->host_features);
+
+    vdev->nvectors = proxy->nvectors;
+    virtio_init_pci(proxy, vdev);
+
+    /* make the actual value visible */
+    proxy->nvectors = vdev->nvectors;
+    return 0;
+}
+
+static void virtio_net_exit_pci(PCIDevice *pci_dev)
+{
+    VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
+
+    virtio_pci_stop_ioeventfd(proxy);
+    virtio_net_exit(proxy->vdev);
+    virtio_exit_pci(pci_dev);
+}
+
+static int virtio_rng_init_pci(PCIDevice *pci_dev)
+{
+    VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
+    VirtIODevice *vdev;
+
+    if (proxy->rng.rng == NULL) {
+        proxy->rng.default_backend = RNG_RANDOM(object_new(TYPE_RNG_RANDOM));
+
+        object_property_add_child(OBJECT(pci_dev),
+                                  "default-backend",
+                                  OBJECT(proxy->rng.default_backend),
+                                  NULL);
+
+        object_property_set_link(OBJECT(pci_dev),
+                                 OBJECT(proxy->rng.default_backend),
+                                 "rng", NULL);
+    }
+
+    vdev = virtio_rng_init(&pci_dev->qdev, &proxy->rng);
+    if (!vdev) {
+        return -1;
+    }
+    virtio_init_pci(proxy, vdev);
+    return 0;
+}
+
+static void virtio_rng_exit_pci(PCIDevice *pci_dev)
+{
+    VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
+
+    virtio_pci_stop_ioeventfd(proxy);
+    virtio_rng_exit(proxy->vdev);
+    virtio_exit_pci(pci_dev);
+}
+
+static Property virtio_net_properties[] = {
+    DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, false),
+    DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 3),
+    DEFINE_VIRTIO_NET_FEATURES(VirtIOPCIProxy, host_features),
+    DEFINE_NIC_PROPERTIES(VirtIOPCIProxy, nic),
+    DEFINE_PROP_UINT32("x-txtimer", VirtIOPCIProxy, net.txtimer, TX_TIMER_INTERVAL),
+    DEFINE_PROP_INT32("x-txburst", VirtIOPCIProxy, net.txburst, TX_BURST),
+    DEFINE_PROP_STRING("tx", VirtIOPCIProxy, net.tx),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void virtio_net_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = virtio_net_init_pci;
+    k->exit = virtio_net_exit_pci;
+    k->romfile = "efi-virtio.rom";
+    k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
+    k->device_id = PCI_DEVICE_ID_VIRTIO_NET;
+    k->revision = VIRTIO_PCI_ABI_VERSION;
+    k->class_id = PCI_CLASS_NETWORK_ETHERNET;
+    dc->reset = virtio_pci_reset;
+    dc->props = virtio_net_properties;
+}
+
+static const TypeInfo virtio_net_info = {
+    .name          = "virtio-net-pci",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(VirtIOPCIProxy),
+    .class_init    = virtio_net_class_init,
+};
+
+static Property virtio_serial_properties[] = {
+    DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
+    DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
+    DEFINE_PROP_HEX32("class", VirtIOPCIProxy, class_code, 0),
+    DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
+    DEFINE_PROP_UINT32("max_ports", VirtIOPCIProxy, serial.max_virtserial_ports, 31),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void virtio_serial_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = virtio_serial_init_pci;
+    k->exit = virtio_serial_exit_pci;
+    k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
+    k->device_id = PCI_DEVICE_ID_VIRTIO_CONSOLE;
+    k->revision = VIRTIO_PCI_ABI_VERSION;
+    k->class_id = PCI_CLASS_COMMUNICATION_OTHER;
+    dc->reset = virtio_pci_reset;
+    dc->props = virtio_serial_properties;
+}
+
+static const TypeInfo virtio_serial_info = {
+    .name          = "virtio-serial-pci",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(VirtIOPCIProxy),
+    .class_init    = virtio_serial_class_init,
+};
+
+static void virtio_rng_initfn(Object *obj)
+{
+    PCIDevice *pci_dev = PCI_DEVICE(obj);
+    VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
+
+    object_property_add_link(obj, "rng", TYPE_RNG_BACKEND,
+                             (Object **)&proxy->rng.rng, NULL);
+}
+
+static Property virtio_rng_properties[] = {
+    DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
+    /* Set a default rate limit of 2^47 bytes per minute or roughly 2TB/s.  If
+       you have an entropy source capable of generating more entropy than this
+       and you can pass it through via virtio-rng, then hats off to you.  Until
+       then, this is unlimited for all practical purposes.
+    */
+    DEFINE_PROP_UINT64("max-bytes", VirtIOPCIProxy, rng.max_bytes, INT64_MAX),
+    DEFINE_PROP_UINT32("period", VirtIOPCIProxy, rng.period_ms, 1 << 16),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void virtio_rng_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = virtio_rng_init_pci;
+    k->exit = virtio_rng_exit_pci;
+    k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
+    k->device_id = PCI_DEVICE_ID_VIRTIO_RNG;
+    k->revision = VIRTIO_PCI_ABI_VERSION;
+    k->class_id = PCI_CLASS_OTHERS;
+    dc->reset = virtio_pci_reset;
+    dc->props = virtio_rng_properties;
+}
+
+static const TypeInfo virtio_rng_info = {
+    .name          = "virtio-rng-pci",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(VirtIOPCIProxy),
+    .instance_init = virtio_rng_initfn,
+    .class_init    = virtio_rng_class_init,
+};
+
+#ifdef CONFIG_VIRTFS
+static int virtio_9p_init_pci(PCIDevice *pci_dev)
+{
+    VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
+    VirtIODevice *vdev;
+
+    vdev = virtio_9p_init(&pci_dev->qdev, &proxy->fsconf);
+    vdev->nvectors = proxy->nvectors;
+    virtio_init_pci(proxy, vdev);
+    /* make the actual value visible */
+    proxy->nvectors = vdev->nvectors;
+    return 0;
+}
+
+static Property virtio_9p_properties[] = {
+    DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
+    DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
+    DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
+    DEFINE_PROP_STRING("mount_tag", VirtIOPCIProxy, fsconf.tag),
+    DEFINE_PROP_STRING("fsdev", VirtIOPCIProxy, fsconf.fsdev_id),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void virtio_9p_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = virtio_9p_init_pci;
+    k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
+    k->device_id = PCI_DEVICE_ID_VIRTIO_9P;
+    k->revision = VIRTIO_PCI_ABI_VERSION;
+    k->class_id = 0x2;
+    dc->props = virtio_9p_properties;
+    dc->reset = virtio_pci_reset;
+}
+
+static const TypeInfo virtio_9p_info = {
+    .name          = "virtio-9p-pci",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(VirtIOPCIProxy),
+    .class_init    = virtio_9p_class_init,
+};
+#endif
+
+/*
+ * virtio-pci: This is the PCIDevice which has a virtio-pci-bus.
+ */
+
+/* This is called by virtio-bus just after the device is plugged. */
+static void virtio_pci_device_plugged(DeviceState *d)
+{
+    VirtIOPCIProxy *proxy = VIRTIO_PCI(d);
+    VirtioBusState *bus = &proxy->bus;
+    uint8_t *config;
+    uint32_t size;
+
+    proxy->vdev = bus->vdev;
+
+    config = proxy->pci_dev.config;
+    if (proxy->class_code) {
+        pci_config_set_class(config, proxy->class_code);
+    }
+    pci_set_word(config + PCI_SUBSYSTEM_VENDOR_ID,
+                 pci_get_word(config + PCI_VENDOR_ID));
+    pci_set_word(config + PCI_SUBSYSTEM_ID, virtio_bus_get_vdev_id(bus));
+    config[PCI_INTERRUPT_PIN] = 1;
+
+    if (proxy->nvectors &&
+        msix_init_exclusive_bar(&proxy->pci_dev, proxy->nvectors, 1)) {
+        proxy->nvectors = 0;
+    }
+
+    proxy->pci_dev.config_write = virtio_write_config;
+
+    size = VIRTIO_PCI_REGION_SIZE(&proxy->pci_dev)
+         + virtio_bus_get_vdev_config_len(bus);
+    if (size & (size - 1)) {
+        size = 1 << qemu_fls(size);
+    }
+
+    memory_region_init_io(&proxy->bar, &virtio_pci_config_ops, proxy,
+                          "virtio-pci", size);
+    pci_register_bar(&proxy->pci_dev, 0, PCI_BASE_ADDRESS_SPACE_IO,
+                     &proxy->bar);
+
+    if (!kvm_has_many_ioeventfds()) {
+        proxy->flags &= ~VIRTIO_PCI_FLAG_USE_IOEVENTFD;
+    }
+
+    proxy->host_features |= 0x1 << VIRTIO_F_NOTIFY_ON_EMPTY;
+    proxy->host_features |= 0x1 << VIRTIO_F_BAD_FEATURE;
+    proxy->host_features = virtio_bus_get_vdev_features(bus,
+                                                      proxy->host_features);
+}
+
+static int virtio_pci_init(PCIDevice *pci_dev)
+{
+    VirtIOPCIProxy *dev = VIRTIO_PCI(pci_dev);
+    VirtioPCIClass *k = VIRTIO_PCI_GET_CLASS(pci_dev);
+    virtio_pci_bus_new(&dev->bus, dev);
+    if (k->init != NULL) {
+        return k->init(dev);
+    }
+    return 0;
+}
+
+static void virtio_pci_exit(PCIDevice *pci_dev)
+{
+    VirtIOPCIProxy *proxy = VIRTIO_PCI(pci_dev);
+    virtio_pci_stop_ioeventfd(proxy);
+    virtio_exit_pci(pci_dev);
+}
+
+/*
+ * This will be renamed virtio_pci_reset at the end of the series.
+ * virtio_pci_reset is still in use at this moment.
+ */
+static void virtio_pci_rst(DeviceState *qdev)
+{
+    VirtIOPCIProxy *proxy = VIRTIO_PCI(qdev);
+    VirtioBusState *bus = VIRTIO_BUS(&proxy->bus);
+    virtio_pci_stop_ioeventfd(proxy);
+    virtio_bus_reset(bus);
+    msix_unuse_all_vectors(&proxy->pci_dev);
+    proxy->flags &= ~VIRTIO_PCI_FLAG_BUS_MASTER_BUG;
+}
+
+static void virtio_pci_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = virtio_pci_init;
+    k->exit = virtio_pci_exit;
+    k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
+    k->revision = VIRTIO_PCI_ABI_VERSION;
+    k->class_id = PCI_CLASS_OTHERS;
+    dc->reset = virtio_pci_rst;
+}
+
+static const TypeInfo virtio_pci_info = {
+    .name          = TYPE_VIRTIO_PCI,
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(VirtIOPCIProxy),
+    .class_init    = virtio_pci_class_init,
+    .class_size    = sizeof(VirtioPCIClass),
+    .abstract      = true,
+};
+
+/* virtio-blk-pci */
+
+static Property virtio_blk_pci_properties[] = {
+    DEFINE_PROP_HEX32("class", VirtIOPCIProxy, class_code, 0),
+    DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
+                    VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
+    DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
+#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE
+    DEFINE_PROP_BIT("x-data-plane", VirtIOBlkPCI, blk.data_plane, 0, false),
+#endif
+    DEFINE_VIRTIO_BLK_FEATURES(VirtIOPCIProxy, host_features),
+    DEFINE_VIRTIO_BLK_PROPERTIES(VirtIOBlkPCI, blk),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static int virtio_blk_pci_init(VirtIOPCIProxy *vpci_dev)
+{
+    VirtIOBlkPCI *dev = VIRTIO_BLK_PCI(vpci_dev);
+    DeviceState *vdev = DEVICE(&dev->vdev);
+    virtio_blk_set_conf(vdev, &(dev->blk));
+    qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
+    if (qdev_init(vdev) < 0) {
+        return -1;
+    }
+    return 0;
+}
+
+static void virtio_blk_pci_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
+    PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
+
+    dc->props = virtio_blk_pci_properties;
+    k->init = virtio_blk_pci_init;
+    pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
+    pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_BLOCK;
+    pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
+    pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI;
+}
+
+static void virtio_blk_pci_instance_init(Object *obj)
+{
+    VirtIOBlkPCI *dev = VIRTIO_BLK_PCI(obj);
+    object_initialize(OBJECT(&dev->vdev), TYPE_VIRTIO_BLK);
+    object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
+}
+
+static const TypeInfo virtio_blk_pci_info = {
+    .name          = TYPE_VIRTIO_BLK_PCI,
+    .parent        = TYPE_VIRTIO_PCI,
+    .instance_size = sizeof(VirtIOBlkPCI),
+    .instance_init = virtio_blk_pci_instance_init,
+    .class_init    = virtio_blk_pci_class_init,
+};
+
+/* virtio-scsi-pci */
+
+static Property virtio_scsi_pci_properties[] = {
+    DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
+                    VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
+    DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors,
+                       DEV_NVECTORS_UNSPECIFIED),
+    DEFINE_VIRTIO_SCSI_FEATURES(VirtIOPCIProxy, host_features),
+    DEFINE_VIRTIO_SCSI_PROPERTIES(VirtIOSCSIPCI, vdev.conf),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static int virtio_scsi_pci_init_pci(VirtIOPCIProxy *vpci_dev)
+{
+    VirtIOSCSIPCI *dev = VIRTIO_SCSI_PCI(vpci_dev);
+    DeviceState *vdev = DEVICE(&dev->vdev);
+
+    if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) {
+        vpci_dev->nvectors = dev->vdev.conf.num_queues + 3;
+    }
+
+    qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
+    if (qdev_init(vdev) < 0) {
+        return -1;
+    }
+    return 0;
+}
+
+static void virtio_scsi_pci_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
+    PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
+    k->init = virtio_scsi_pci_init_pci;
+    dc->props = virtio_scsi_pci_properties;
+    pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
+    pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_SCSI;
+    pcidev_k->revision = 0x00;
+    pcidev_k->class_id = PCI_CLASS_STORAGE_SCSI;
+}
+
+static void virtio_scsi_pci_instance_init(Object *obj)
+{
+    VirtIOSCSIPCI *dev = VIRTIO_SCSI_PCI(obj);
+    object_initialize(OBJECT(&dev->vdev), TYPE_VIRTIO_SCSI);
+    object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
+}
+
+static const TypeInfo virtio_scsi_pci_info = {
+    .name          = TYPE_VIRTIO_SCSI_PCI,
+    .parent        = TYPE_VIRTIO_PCI,
+    .instance_size = sizeof(VirtIOSCSIPCI),
+    .instance_init = virtio_scsi_pci_instance_init,
+    .class_init    = virtio_scsi_pci_class_init,
+};
+
+/* virtio-balloon-pci */
+
+static Property virtio_balloon_pci_properties[] = {
+    DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
+    DEFINE_PROP_HEX32("class", VirtIOPCIProxy, class_code, 0),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static int virtio_balloon_pci_init(VirtIOPCIProxy *vpci_dev)
+{
+    VirtIOBalloonPCI *dev = VIRTIO_BALLOON_PCI(vpci_dev);
+    DeviceState *vdev = DEVICE(&dev->vdev);
+
+    if (vpci_dev->class_code != PCI_CLASS_OTHERS &&
+        vpci_dev->class_code != PCI_CLASS_MEMORY_RAM) { /* qemu < 1.1 */
+        vpci_dev->class_code = PCI_CLASS_OTHERS;
+    }
+
+    qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
+    if (qdev_init(vdev) < 0) {
+        return -1;
+    }
+    return 0;
+}
+
+static void virtio_balloon_pci_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
+    PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
+    k->init = virtio_balloon_pci_init;
+    dc->props = virtio_balloon_pci_properties;
+    pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
+    pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_BALLOON;
+    pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
+    pcidev_k->class_id = PCI_CLASS_OTHERS;
+}
+
+static void virtio_balloon_pci_instance_init(Object *obj)
+{
+    VirtIOBalloonPCI *dev = VIRTIO_BALLOON_PCI(obj);
+    object_initialize(OBJECT(&dev->vdev), TYPE_VIRTIO_BALLOON);
+    object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
+}
+
+static const TypeInfo virtio_balloon_pci_info = {
+    .name          = TYPE_VIRTIO_BALLOON_PCI,
+    .parent        = TYPE_VIRTIO_PCI,
+    .instance_size = sizeof(VirtIOBalloonPCI),
+    .instance_init = virtio_balloon_pci_instance_init,
+    .class_init    = virtio_balloon_pci_class_init,
+};
+
+/* virtio-pci-bus */
+
+void virtio_pci_bus_new(VirtioBusState *bus, VirtIOPCIProxy *dev)
+{
+    DeviceState *qdev = DEVICE(dev);
+    BusState *qbus;
+    qbus_create_inplace((BusState *)bus, TYPE_VIRTIO_PCI_BUS, qdev, NULL);
+    qbus = BUS(bus);
+    qbus->allow_hotplug = 1;
+}
+
+static void virtio_pci_bus_class_init(ObjectClass *klass, void *data)
+{
+    BusClass *bus_class = BUS_CLASS(klass);
+    VirtioBusClass *k = VIRTIO_BUS_CLASS(klass);
+    bus_class->max_dev = 1;
+    k->notify = virtio_pci_notify;
+    k->save_config = virtio_pci_save_config;
+    k->load_config = virtio_pci_load_config;
+    k->save_queue = virtio_pci_save_queue;
+    k->load_queue = virtio_pci_load_queue;
+    k->get_features = virtio_pci_get_features;
+    k->query_guest_notifiers = virtio_pci_query_guest_notifiers;
+    k->set_host_notifier = virtio_pci_set_host_notifier;
+    k->set_guest_notifiers = virtio_pci_set_guest_notifiers;
+    k->vmstate_change = virtio_pci_vmstate_change;
+    k->device_plugged = virtio_pci_device_plugged;
+}
+
+static const TypeInfo virtio_pci_bus_info = {
+    .name          = TYPE_VIRTIO_PCI_BUS,
+    .parent        = TYPE_VIRTIO_BUS,
+    .instance_size = sizeof(VirtioPCIBusState),
+    .class_init    = virtio_pci_bus_class_init,
+};
+
+static void virtio_pci_register_types(void)
+{
+    type_register_static(&virtio_net_info);
+    type_register_static(&virtio_serial_info);
+    type_register_static(&virtio_rng_info);
+    type_register_static(&virtio_pci_bus_info);
+    type_register_static(&virtio_pci_info);
+#ifdef CONFIG_VIRTFS
+    type_register_static(&virtio_9p_info);
+#endif
+    type_register_static(&virtio_blk_pci_info);
+    type_register_static(&virtio_scsi_pci_info);
+    type_register_static(&virtio_balloon_pci_info);
+}
+
+type_init(virtio_pci_register_types)
diff --git a/hw/virtio/virtio-pci.h b/hw/virtio/virtio-pci.h
new file mode 100644 (file)
index 0000000..fb83155
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * Virtio PCI Bindings
+ *
+ * Copyright IBM, Corp. 2007
+ * Copyright (c) 2009 CodeSourcery
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *  Paul Brook        <paul@codesourcery.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ */
+
+#ifndef QEMU_VIRTIO_PCI_H
+#define QEMU_VIRTIO_PCI_H
+
+#include "hw/pci/msi.h"
+#include "hw/virtio/virtio-blk.h"
+#include "hw/virtio/virtio-net.h"
+#include "hw/virtio/virtio-rng.h"
+#include "hw/virtio/virtio-serial.h"
+#include "hw/virtio/virtio-scsi.h"
+#include "hw/virtio/virtio-balloon.h"
+#include "hw/virtio/virtio-bus.h"
+#include "hw/virtio/virtio-9p.h"
+
+typedef struct VirtIOPCIProxy VirtIOPCIProxy;
+typedef struct VirtIOBlkPCI VirtIOBlkPCI;
+typedef struct VirtIOSCSIPCI VirtIOSCSIPCI;
+typedef struct VirtIOBalloonPCI VirtIOBalloonPCI;
+
+/* virtio-pci-bus */
+
+typedef struct VirtioBusState VirtioPCIBusState;
+typedef struct VirtioBusClass VirtioPCIBusClass;
+
+#define TYPE_VIRTIO_PCI_BUS "virtio-pci-bus"
+#define VIRTIO_PCI_BUS(obj) \
+        OBJECT_CHECK(VirtioPCIBusState, (obj), TYPE_VIRTIO_PCI_BUS)
+#define VIRTIO_PCI_BUS_GET_CLASS(obj) \
+        OBJECT_GET_CLASS(VirtioPCIBusClass, obj, TYPE_VIRTIO_PCI_BUS)
+#define VIRTIO_PCI_BUS_CLASS(klass) \
+        OBJECT_CLASS_CHECK(VirtioPCIBusClass, klass, TYPE_VIRTIO_PCI_BUS)
+
+/* Performance improves when virtqueue kick processing is decoupled from the
+ * vcpu thread using ioeventfd for some devices. */
+#define VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT 1
+#define VIRTIO_PCI_FLAG_USE_IOEVENTFD   (1 << VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT)
+
+typedef struct {
+    MSIMessage msg;
+    int virq;
+    unsigned int users;
+} VirtIOIRQFD;
+
+/*
+ * virtio-pci: This is the PCIDevice which has a virtio-pci-bus.
+ */
+#define TYPE_VIRTIO_PCI "virtio-pci"
+#define VIRTIO_PCI_GET_CLASS(obj) \
+        OBJECT_GET_CLASS(VirtioPCIClass, obj, TYPE_VIRTIO_PCI)
+#define VIRTIO_PCI_CLASS(klass) \
+        OBJECT_CLASS_CHECK(VirtioPCIClass, klass, TYPE_VIRTIO_PCI)
+#define VIRTIO_PCI(obj) \
+        OBJECT_CHECK(VirtIOPCIProxy, (obj), TYPE_VIRTIO_PCI)
+
+typedef struct VirtioPCIClass {
+    PCIDeviceClass parent_class;
+    int (*init)(VirtIOPCIProxy *vpci_dev);
+} VirtioPCIClass;
+
+struct VirtIOPCIProxy {
+    PCIDevice pci_dev;
+    VirtIODevice *vdev;
+    MemoryRegion bar;
+    uint32_t flags;
+    uint32_t class_code;
+    uint32_t nvectors;
+    NICConf nic;
+    uint32_t host_features;
+#ifdef CONFIG_VIRTFS
+    V9fsConf fsconf;
+#endif
+    virtio_serial_conf serial;
+    virtio_net_conf net;
+    VirtIORNGConf rng;
+    bool ioeventfd_disabled;
+    bool ioeventfd_started;
+    VirtIOIRQFD *vector_irqfd;
+    int nvqs_with_notifiers;
+    VirtioBusState bus;
+};
+
+
+/*
+ * virtio-scsi-pci: This extends VirtioPCIProxy.
+ */
+#define TYPE_VIRTIO_SCSI_PCI "virtio-scsi-pci"
+#define VIRTIO_SCSI_PCI(obj) \
+        OBJECT_CHECK(VirtIOSCSIPCI, (obj), TYPE_VIRTIO_SCSI_PCI)
+
+struct VirtIOSCSIPCI {
+    VirtIOPCIProxy parent_obj;
+    VirtIOSCSI vdev;
+};
+
+/*
+ * virtio-blk-pci: This extends VirtioPCIProxy.
+ */
+#define TYPE_VIRTIO_BLK_PCI "virtio-blk-pci"
+#define VIRTIO_BLK_PCI(obj) \
+        OBJECT_CHECK(VirtIOBlkPCI, (obj), TYPE_VIRTIO_BLK_PCI)
+
+struct VirtIOBlkPCI {
+    VirtIOPCIProxy parent_obj;
+    VirtIOBlock vdev;
+    VirtIOBlkConf blk;
+};
+
+/*
+ * virtio-balloon-pci: This extends VirtioPCIProxy.
+ */
+#define TYPE_VIRTIO_BALLOON_PCI "virtio-balloon-pci"
+#define VIRTIO_BALLOON_PCI(obj) \
+        OBJECT_CHECK(VirtIOBalloonPCI, (obj), TYPE_VIRTIO_BALLOON_PCI)
+
+struct VirtIOBalloonPCI {
+    VirtIOPCIProxy parent_obj;
+    VirtIOBalloon vdev;
+};
+
+void virtio_init_pci(VirtIOPCIProxy *proxy, VirtIODevice *vdev);
+void virtio_pci_bus_new(VirtioBusState *bus, VirtIOPCIProxy *dev);
+
+/* Virtio ABI version, if we increment this, we break the guest driver. */
+#define VIRTIO_PCI_ABI_VERSION          0
+
+#endif
diff --git a/hw/virtio/virtio-rng.c b/hw/virtio/virtio-rng.c
new file mode 100644 (file)
index 0000000..6079b2a
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * A virtio device implementing a hardware random number generator.
+ *
+ * Copyright 2012 Red Hat, Inc.
+ * Copyright 2012 Amit Shah <amit.shah@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or
+ * (at your option) any later version.  See the COPYING file in the
+ * top-level directory.
+ */
+
+#include "qemu/iov.h"
+#include "hw/qdev.h"
+#include "qapi/qmp/qerror.h"
+#include "hw/virtio/virtio.h"
+#include "hw/virtio/virtio-rng.h"
+#include "qemu/rng.h"
+
+static bool is_guest_ready(VirtIORNG *vrng)
+{
+    if (virtio_queue_ready(vrng->vq)
+        && (vrng->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK)) {
+        return true;
+    }
+    return false;
+}
+
+static size_t get_request_size(VirtQueue *vq, unsigned quota)
+{
+    unsigned int in, out;
+
+    virtqueue_get_avail_bytes(vq, &in, &out, quota, 0);
+    return in;
+}
+
+static void virtio_rng_process(VirtIORNG *vrng);
+
+/* Send data from a char device over to the guest */
+static void chr_read(void *opaque, const void *buf, size_t size)
+{
+    VirtIORNG *vrng = opaque;
+    VirtQueueElement elem;
+    size_t len;
+    int offset;
+
+    if (!is_guest_ready(vrng)) {
+        return;
+    }
+
+    vrng->quota_remaining -= size;
+
+    offset = 0;
+    while (offset < size) {
+        if (!virtqueue_pop(vrng->vq, &elem)) {
+            break;
+        }
+        len = iov_from_buf(elem.in_sg, elem.in_num,
+                           0, buf + offset, size - offset);
+        offset += len;
+
+        virtqueue_push(vrng->vq, &elem, len);
+    }
+    virtio_notify(&vrng->vdev, vrng->vq);
+}
+
+static void virtio_rng_process(VirtIORNG *vrng)
+{
+    size_t size;
+    unsigned quota;
+
+    if (!is_guest_ready(vrng)) {
+        return;
+    }
+
+    if (vrng->quota_remaining < 0) {
+        quota = 0;
+    } else {
+        quota = MIN((uint64_t)vrng->quota_remaining, (uint64_t)UINT32_MAX);
+    }
+    size = get_request_size(vrng->vq, quota);
+    size = MIN(vrng->quota_remaining, size);
+    if (size) {
+        rng_backend_request_entropy(vrng->rng, size, chr_read, vrng);
+    }
+}
+
+static void handle_input(VirtIODevice *vdev, VirtQueue *vq)
+{
+    VirtIORNG *vrng = DO_UPCAST(VirtIORNG, vdev, vdev);
+    virtio_rng_process(vrng);
+}
+
+static uint32_t get_features(VirtIODevice *vdev, uint32_t f)
+{
+    return f;
+}
+
+static void virtio_rng_save(QEMUFile *f, void *opaque)
+{
+    VirtIORNG *vrng = opaque;
+
+    virtio_save(&vrng->vdev, f);
+}
+
+static int virtio_rng_load(QEMUFile *f, void *opaque, int version_id)
+{
+    VirtIORNG *vrng = opaque;
+
+    if (version_id != 1) {
+        return -EINVAL;
+    }
+    virtio_load(&vrng->vdev, f);
+
+    /* We may have an element ready but couldn't process it due to a quota
+     * limit.  Make sure to try again after live migration when the quota may
+     * have been reset.
+     */
+    virtio_rng_process(vrng);
+
+    return 0;
+}
+
+static void check_rate_limit(void *opaque)
+{
+    VirtIORNG *s = opaque;
+
+    s->quota_remaining = s->conf->max_bytes;
+    virtio_rng_process(s);
+    qemu_mod_timer(s->rate_limit_timer,
+                   qemu_get_clock_ms(vm_clock) + s->conf->period_ms);
+}
+
+
+VirtIODevice *virtio_rng_init(DeviceState *dev, VirtIORNGConf *conf)
+{
+    VirtIORNG *vrng;
+    VirtIODevice *vdev;
+    Error *local_err = NULL;
+
+    vdev = virtio_common_init("virtio-rng", VIRTIO_ID_RNG, 0,
+                              sizeof(VirtIORNG));
+
+    vrng = DO_UPCAST(VirtIORNG, vdev, vdev);
+
+    vrng->rng = conf->rng;
+    if (vrng->rng == NULL) {
+        qerror_report(QERR_INVALID_PARAMETER_VALUE, "rng", "a valid object");
+        return NULL;
+    }
+
+    rng_backend_open(vrng->rng, &local_err);
+    if (local_err) {
+        qerror_report_err(local_err);
+        error_free(local_err);
+        return NULL;
+    }
+
+    vrng->vq = virtio_add_queue(vdev, 8, handle_input);
+    vrng->vdev.get_features = get_features;
+
+    vrng->qdev = dev;
+    vrng->conf = conf;
+
+    assert(vrng->conf->max_bytes <= INT64_MAX);
+    vrng->quota_remaining = vrng->conf->max_bytes;
+
+    vrng->rate_limit_timer = qemu_new_timer_ms(vm_clock,
+                                               check_rate_limit, vrng);
+
+    qemu_mod_timer(vrng->rate_limit_timer,
+                   qemu_get_clock_ms(vm_clock) + vrng->conf->period_ms);
+
+    register_savevm(dev, "virtio-rng", -1, 1, virtio_rng_save,
+                    virtio_rng_load, vrng);
+
+    return vdev;
+}
+
+void virtio_rng_exit(VirtIODevice *vdev)
+{
+    VirtIORNG *vrng = DO_UPCAST(VirtIORNG, vdev, vdev);
+
+    qemu_del_timer(vrng->rate_limit_timer);
+    qemu_free_timer(vrng->rate_limit_timer);
+    unregister_savevm(vrng->qdev, "virtio-rng", vrng);
+    virtio_cleanup(vdev);
+}
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
new file mode 100644 (file)
index 0000000..1c2282c
--- /dev/null
@@ -0,0 +1,1121 @@
+/*
+ * Virtio Support
+ *
+ * Copyright IBM, Corp. 2007
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.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 <inttypes.h>
+
+#include "trace.h"
+#include "qemu/error-report.h"
+#include "hw/virtio/virtio.h"
+#include "qemu/atomic.h"
+#include "hw/virtio/virtio-bus.h"
+
+/* The alignment to use between consumer and producer parts of vring.
+ * x86 pagesize again. */
+#define VIRTIO_PCI_VRING_ALIGN         4096
+
+typedef struct VRingDesc
+{
+    uint64_t addr;
+    uint32_t len;
+    uint16_t flags;
+    uint16_t next;
+} VRingDesc;
+
+typedef struct VRingAvail
+{
+    uint16_t flags;
+    uint16_t idx;
+    uint16_t ring[0];
+} VRingAvail;
+
+typedef struct VRingUsedElem
+{
+    uint32_t id;
+    uint32_t len;
+} VRingUsedElem;
+
+typedef struct VRingUsed
+{
+    uint16_t flags;
+    uint16_t idx;
+    VRingUsedElem ring[0];
+} VRingUsed;
+
+typedef struct VRing
+{
+    unsigned int num;
+    hwaddr desc;
+    hwaddr avail;
+    hwaddr used;
+} VRing;
+
+struct VirtQueue
+{
+    VRing vring;
+    hwaddr pa;
+    uint16_t last_avail_idx;
+    /* Last used index value we have signalled on */
+    uint16_t signalled_used;
+
+    /* Last used index value we have signalled on */
+    bool signalled_used_valid;
+
+    /* Notification enabled? */
+    bool notification;
+
+    uint16_t queue_index;
+
+    int inuse;
+
+    uint16_t vector;
+    void (*handle_output)(VirtIODevice *vdev, VirtQueue *vq);
+    VirtIODevice *vdev;
+    EventNotifier guest_notifier;
+    EventNotifier host_notifier;
+};
+
+/* virt queue functions */
+static void virtqueue_init(VirtQueue *vq)
+{
+    hwaddr pa = vq->pa;
+
+    vq->vring.desc = pa;
+    vq->vring.avail = pa + vq->vring.num * sizeof(VRingDesc);
+    vq->vring.used = vring_align(vq->vring.avail +
+                                 offsetof(VRingAvail, ring[vq->vring.num]),
+                                 VIRTIO_PCI_VRING_ALIGN);
+}
+
+static inline uint64_t vring_desc_addr(hwaddr desc_pa, int i)
+{
+    hwaddr pa;
+    pa = desc_pa + sizeof(VRingDesc) * i + offsetof(VRingDesc, addr);
+    return ldq_phys(pa);
+}
+
+static inline uint32_t vring_desc_len(hwaddr desc_pa, int i)
+{
+    hwaddr pa;
+    pa = desc_pa + sizeof(VRingDesc) * i + offsetof(VRingDesc, len);
+    return ldl_phys(pa);
+}
+
+static inline uint16_t vring_desc_flags(hwaddr desc_pa, int i)
+{
+    hwaddr pa;
+    pa = desc_pa + sizeof(VRingDesc) * i + offsetof(VRingDesc, flags);
+    return lduw_phys(pa);
+}
+
+static inline uint16_t vring_desc_next(hwaddr desc_pa, int i)
+{
+    hwaddr pa;
+    pa = desc_pa + sizeof(VRingDesc) * i + offsetof(VRingDesc, next);
+    return lduw_phys(pa);
+}
+
+static inline uint16_t vring_avail_flags(VirtQueue *vq)
+{
+    hwaddr pa;
+    pa = vq->vring.avail + offsetof(VRingAvail, flags);
+    return lduw_phys(pa);
+}
+
+static inline uint16_t vring_avail_idx(VirtQueue *vq)
+{
+    hwaddr pa;
+    pa = vq->vring.avail + offsetof(VRingAvail, idx);
+    return lduw_phys(pa);
+}
+
+static inline uint16_t vring_avail_ring(VirtQueue *vq, int i)
+{
+    hwaddr pa;
+    pa = vq->vring.avail + offsetof(VRingAvail, ring[i]);
+    return lduw_phys(pa);
+}
+
+static inline uint16_t vring_used_event(VirtQueue *vq)
+{
+    return vring_avail_ring(vq, vq->vring.num);
+}
+
+static inline void vring_used_ring_id(VirtQueue *vq, int i, uint32_t val)
+{
+    hwaddr pa;
+    pa = vq->vring.used + offsetof(VRingUsed, ring[i].id);
+    stl_phys(pa, val);
+}
+
+static inline void vring_used_ring_len(VirtQueue *vq, int i, uint32_t val)
+{
+    hwaddr pa;
+    pa = vq->vring.used + offsetof(VRingUsed, ring[i].len);
+    stl_phys(pa, val);
+}
+
+static uint16_t vring_used_idx(VirtQueue *vq)
+{
+    hwaddr pa;
+    pa = vq->vring.used + offsetof(VRingUsed, idx);
+    return lduw_phys(pa);
+}
+
+static inline void vring_used_idx_set(VirtQueue *vq, uint16_t val)
+{
+    hwaddr pa;
+    pa = vq->vring.used + offsetof(VRingUsed, idx);
+    stw_phys(pa, val);
+}
+
+static inline void vring_used_flags_set_bit(VirtQueue *vq, int mask)
+{
+    hwaddr pa;
+    pa = vq->vring.used + offsetof(VRingUsed, flags);
+    stw_phys(pa, lduw_phys(pa) | mask);
+}
+
+static inline void vring_used_flags_unset_bit(VirtQueue *vq, int mask)
+{
+    hwaddr pa;
+    pa = vq->vring.used + offsetof(VRingUsed, flags);
+    stw_phys(pa, lduw_phys(pa) & ~mask);
+}
+
+static inline void vring_avail_event(VirtQueue *vq, uint16_t val)
+{
+    hwaddr pa;
+    if (!vq->notification) {
+        return;
+    }
+    pa = vq->vring.used + offsetof(VRingUsed, ring[vq->vring.num]);
+    stw_phys(pa, val);
+}
+
+void virtio_queue_set_notification(VirtQueue *vq, int enable)
+{
+    vq->notification = enable;
+    if (vq->vdev->guest_features & (1 << VIRTIO_RING_F_EVENT_IDX)) {
+        vring_avail_event(vq, vring_avail_idx(vq));
+    } else if (enable) {
+        vring_used_flags_unset_bit(vq, VRING_USED_F_NO_NOTIFY);
+    } else {
+        vring_used_flags_set_bit(vq, VRING_USED_F_NO_NOTIFY);
+    }
+    if (enable) {
+        /* Expose avail event/used flags before caller checks the avail idx. */
+        smp_mb();
+    }
+}
+
+int virtio_queue_ready(VirtQueue *vq)
+{
+    return vq->vring.avail != 0;
+}
+
+int virtio_queue_empty(VirtQueue *vq)
+{
+    return vring_avail_idx(vq) == vq->last_avail_idx;
+}
+
+void virtqueue_fill(VirtQueue *vq, const VirtQueueElement *elem,
+                    unsigned int len, unsigned int idx)
+{
+    unsigned int offset;
+    int i;
+
+    trace_virtqueue_fill(vq, elem, len, idx);
+
+    offset = 0;
+    for (i = 0; i < elem->in_num; i++) {
+        size_t size = MIN(len - offset, elem->in_sg[i].iov_len);
+
+        cpu_physical_memory_unmap(elem->in_sg[i].iov_base,
+                                  elem->in_sg[i].iov_len,
+                                  1, size);
+
+        offset += size;
+    }
+
+    for (i = 0; i < elem->out_num; i++)
+        cpu_physical_memory_unmap(elem->out_sg[i].iov_base,
+                                  elem->out_sg[i].iov_len,
+                                  0, elem->out_sg[i].iov_len);
+
+    idx = (idx + vring_used_idx(vq)) % vq->vring.num;
+
+    /* Get a pointer to the next entry in the used ring. */
+    vring_used_ring_id(vq, idx, elem->index);
+    vring_used_ring_len(vq, idx, len);
+}
+
+void virtqueue_flush(VirtQueue *vq, unsigned int count)
+{
+    uint16_t old, new;
+    /* Make sure buffer is written before we update index. */
+    smp_wmb();
+    trace_virtqueue_flush(vq, count);
+    old = vring_used_idx(vq);
+    new = old + count;
+    vring_used_idx_set(vq, new);
+    vq->inuse -= count;
+    if (unlikely((int16_t)(new - vq->signalled_used) < (uint16_t)(new - old)))
+        vq->signalled_used_valid = false;
+}
+
+void virtqueue_push(VirtQueue *vq, const VirtQueueElement *elem,
+                    unsigned int len)
+{
+    virtqueue_fill(vq, elem, len, 0);
+    virtqueue_flush(vq, 1);
+}
+
+static int virtqueue_num_heads(VirtQueue *vq, unsigned int idx)
+{
+    uint16_t num_heads = vring_avail_idx(vq) - idx;
+
+    /* Check it isn't doing very strange things with descriptor numbers. */
+    if (num_heads > vq->vring.num) {
+        error_report("Guest moved used index from %u to %u",
+                     idx, vring_avail_idx(vq));
+        exit(1);
+    }
+    /* On success, callers read a descriptor at vq->last_avail_idx.
+     * Make sure descriptor read does not bypass avail index read. */
+    if (num_heads) {
+        smp_rmb();
+    }
+
+    return num_heads;
+}
+
+static unsigned int virtqueue_get_head(VirtQueue *vq, unsigned int idx)
+{
+    unsigned int head;
+
+    /* Grab the next descriptor number they're advertising, and increment
+     * the index we've seen. */
+    head = vring_avail_ring(vq, idx % vq->vring.num);
+
+    /* If their number is silly, that's a fatal mistake. */
+    if (head >= vq->vring.num) {
+        error_report("Guest says index %u is available", head);
+        exit(1);
+    }
+
+    return head;
+}
+
+static unsigned virtqueue_next_desc(hwaddr desc_pa,
+                                    unsigned int i, unsigned int max)
+{
+    unsigned int next;
+
+    /* If this descriptor says it doesn't chain, we're done. */
+    if (!(vring_desc_flags(desc_pa, i) & VRING_DESC_F_NEXT))
+        return max;
+
+    /* Check they're not leading us off end of descriptors. */
+    next = vring_desc_next(desc_pa, i);
+    /* Make sure compiler knows to grab that: we don't want it changing! */
+    smp_wmb();
+
+    if (next >= max) {
+        error_report("Desc next is %u", next);
+        exit(1);
+    }
+
+    return next;
+}
+
+void virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes,
+                               unsigned int *out_bytes,
+                               unsigned max_in_bytes, unsigned max_out_bytes)
+{
+    unsigned int idx;
+    unsigned int total_bufs, in_total, out_total;
+
+    idx = vq->last_avail_idx;
+
+    total_bufs = in_total = out_total = 0;
+    while (virtqueue_num_heads(vq, idx)) {
+        unsigned int max, num_bufs, indirect = 0;
+        hwaddr desc_pa;
+        int i;
+
+        max = vq->vring.num;
+        num_bufs = total_bufs;
+        i = virtqueue_get_head(vq, idx++);
+        desc_pa = vq->vring.desc;
+
+        if (vring_desc_flags(desc_pa, i) & VRING_DESC_F_INDIRECT) {
+            if (vring_desc_len(desc_pa, i) % sizeof(VRingDesc)) {
+                error_report("Invalid size for indirect buffer table");
+                exit(1);
+            }
+
+            /* If we've got too many, that implies a descriptor loop. */
+            if (num_bufs >= max) {
+                error_report("Looped descriptor");
+                exit(1);
+            }
+
+            /* loop over the indirect descriptor table */
+            indirect = 1;
+            max = vring_desc_len(desc_pa, i) / sizeof(VRingDesc);
+            num_bufs = i = 0;
+            desc_pa = vring_desc_addr(desc_pa, i);
+        }
+
+        do {
+            /* If we've got too many, that implies a descriptor loop. */
+            if (++num_bufs > max) {
+                error_report("Looped descriptor");
+                exit(1);
+            }
+
+            if (vring_desc_flags(desc_pa, i) & VRING_DESC_F_WRITE) {
+                in_total += vring_desc_len(desc_pa, i);
+            } else {
+                out_total += vring_desc_len(desc_pa, i);
+            }
+            if (in_total >= max_in_bytes && out_total >= max_out_bytes) {
+                goto done;
+            }
+        } while ((i = virtqueue_next_desc(desc_pa, i, max)) != max);
+
+        if (!indirect)
+            total_bufs = num_bufs;
+        else
+            total_bufs++;
+    }
+done:
+    if (in_bytes) {
+        *in_bytes = in_total;
+    }
+    if (out_bytes) {
+        *out_bytes = out_total;
+    }
+}
+
+int virtqueue_avail_bytes(VirtQueue *vq, unsigned int in_bytes,
+                          unsigned int out_bytes)
+{
+    unsigned int in_total, out_total;
+
+    virtqueue_get_avail_bytes(vq, &in_total, &out_total, in_bytes, out_bytes);
+    return in_bytes <= in_total && out_bytes <= out_total;
+}
+
+void virtqueue_map_sg(struct iovec *sg, hwaddr *addr,
+    size_t num_sg, int is_write)
+{
+    unsigned int i;
+    hwaddr len;
+
+    for (i = 0; i < num_sg; i++) {
+        len = sg[i].iov_len;
+        sg[i].iov_base = cpu_physical_memory_map(addr[i], &len, is_write);
+        if (sg[i].iov_base == NULL || len != sg[i].iov_len) {
+            error_report("virtio: trying to map MMIO memory");
+            exit(1);
+        }
+    }
+}
+
+int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem)
+{
+    unsigned int i, head, max;
+    hwaddr desc_pa = vq->vring.desc;
+
+    if (!virtqueue_num_heads(vq, vq->last_avail_idx))
+        return 0;
+
+    /* When we start there are none of either input nor output. */
+    elem->out_num = elem->in_num = 0;
+
+    max = vq->vring.num;
+
+    i = head = virtqueue_get_head(vq, vq->last_avail_idx++);
+    if (vq->vdev->guest_features & (1 << VIRTIO_RING_F_EVENT_IDX)) {
+        vring_avail_event(vq, vring_avail_idx(vq));
+    }
+
+    if (vring_desc_flags(desc_pa, i) & VRING_DESC_F_INDIRECT) {
+        if (vring_desc_len(desc_pa, i) % sizeof(VRingDesc)) {
+            error_report("Invalid size for indirect buffer table");
+            exit(1);
+        }
+
+        /* loop over the indirect descriptor table */
+        max = vring_desc_len(desc_pa, i) / sizeof(VRingDesc);
+        desc_pa = vring_desc_addr(desc_pa, i);
+        i = 0;
+    }
+
+    /* Collect all the descriptors */
+    do {
+        struct iovec *sg;
+
+        if (vring_desc_flags(desc_pa, i) & VRING_DESC_F_WRITE) {
+            if (elem->in_num >= ARRAY_SIZE(elem->in_sg)) {
+                error_report("Too many write descriptors in indirect table");
+                exit(1);
+            }
+            elem->in_addr[elem->in_num] = vring_desc_addr(desc_pa, i);
+            sg = &elem->in_sg[elem->in_num++];
+        } else {
+            if (elem->out_num >= ARRAY_SIZE(elem->out_sg)) {
+                error_report("Too many read descriptors in indirect table");
+                exit(1);
+            }
+            elem->out_addr[elem->out_num] = vring_desc_addr(desc_pa, i);
+            sg = &elem->out_sg[elem->out_num++];
+        }
+
+        sg->iov_len = vring_desc_len(desc_pa, i);
+
+        /* If we've got too many, that implies a descriptor loop. */
+        if ((elem->in_num + elem->out_num) > max) {
+            error_report("Looped descriptor");
+            exit(1);
+        }
+    } while ((i = virtqueue_next_desc(desc_pa, i, max)) != max);
+
+    /* Now map what we have collected */
+    virtqueue_map_sg(elem->in_sg, elem->in_addr, elem->in_num, 1);
+    virtqueue_map_sg(elem->out_sg, elem->out_addr, elem->out_num, 0);
+
+    elem->index = head;
+
+    vq->inuse++;
+
+    trace_virtqueue_pop(vq, elem, elem->in_num, elem->out_num);
+    return elem->in_num + elem->out_num;
+}
+
+/* virtio device */
+static void virtio_notify_vector(VirtIODevice *vdev, uint16_t vector)
+{
+    if (vdev->binding->notify) {
+        vdev->binding->notify(vdev->binding_opaque, vector);
+    }
+}
+
+void virtio_update_irq(VirtIODevice *vdev)
+{
+    virtio_notify_vector(vdev, VIRTIO_NO_VECTOR);
+}
+
+void virtio_set_status(VirtIODevice *vdev, uint8_t val)
+{
+    trace_virtio_set_status(vdev, val);
+
+    if (vdev->set_status) {
+        vdev->set_status(vdev, val);
+    }
+    vdev->status = val;
+}
+
+void virtio_reset(void *opaque)
+{
+    VirtIODevice *vdev = opaque;
+    int i;
+
+    virtio_set_status(vdev, 0);
+
+    if (vdev->reset)
+        vdev->reset(vdev);
+
+    vdev->guest_features = 0;
+    vdev->queue_sel = 0;
+    vdev->status = 0;
+    vdev->isr = 0;
+    vdev->config_vector = VIRTIO_NO_VECTOR;
+    virtio_notify_vector(vdev, vdev->config_vector);
+
+    for(i = 0; i < VIRTIO_PCI_QUEUE_MAX; i++) {
+        vdev->vq[i].vring.desc = 0;
+        vdev->vq[i].vring.avail = 0;
+        vdev->vq[i].vring.used = 0;
+        vdev->vq[i].last_avail_idx = 0;
+        vdev->vq[i].pa = 0;
+        vdev->vq[i].vector = VIRTIO_NO_VECTOR;
+        vdev->vq[i].signalled_used = 0;
+        vdev->vq[i].signalled_used_valid = false;
+        vdev->vq[i].notification = true;
+    }
+}
+
+uint32_t virtio_config_readb(VirtIODevice *vdev, uint32_t addr)
+{
+    uint8_t val;
+
+    vdev->get_config(vdev, vdev->config);
+
+    if (addr > (vdev->config_len - sizeof(val)))
+        return (uint32_t)-1;
+
+    val = ldub_p(vdev->config + addr);
+    return val;
+}
+
+uint32_t virtio_config_readw(VirtIODevice *vdev, uint32_t addr)
+{
+    uint16_t val;
+
+    vdev->get_config(vdev, vdev->config);
+
+    if (addr > (vdev->config_len - sizeof(val)))
+        return (uint32_t)-1;
+
+    val = lduw_p(vdev->config + addr);
+    return val;
+}
+
+uint32_t virtio_config_readl(VirtIODevice *vdev, uint32_t addr)
+{
+    uint32_t val;
+
+    vdev->get_config(vdev, vdev->config);
+
+    if (addr > (vdev->config_len - sizeof(val)))
+        return (uint32_t)-1;
+
+    val = ldl_p(vdev->config + addr);
+    return val;
+}
+
+void virtio_config_writeb(VirtIODevice *vdev, uint32_t addr, uint32_t data)
+{
+    uint8_t val = data;
+
+    if (addr > (vdev->config_len - sizeof(val)))
+        return;
+
+    stb_p(vdev->config + addr, val);
+
+    if (vdev->set_config)
+        vdev->set_config(vdev, vdev->config);
+}
+
+void virtio_config_writew(VirtIODevice *vdev, uint32_t addr, uint32_t data)
+{
+    uint16_t val = data;
+
+    if (addr > (vdev->config_len - sizeof(val)))
+        return;
+
+    stw_p(vdev->config + addr, val);
+
+    if (vdev->set_config)
+        vdev->set_config(vdev, vdev->config);
+}
+
+void virtio_config_writel(VirtIODevice *vdev, uint32_t addr, uint32_t data)
+{
+    uint32_t val = data;
+
+    if (addr > (vdev->config_len - sizeof(val)))
+        return;
+
+    stl_p(vdev->config + addr, val);
+
+    if (vdev->set_config)
+        vdev->set_config(vdev, vdev->config);
+}
+
+void virtio_queue_set_addr(VirtIODevice *vdev, int n, hwaddr addr)
+{
+    vdev->vq[n].pa = addr;
+    virtqueue_init(&vdev->vq[n]);
+}
+
+hwaddr virtio_queue_get_addr(VirtIODevice *vdev, int n)
+{
+    return vdev->vq[n].pa;
+}
+
+int virtio_queue_get_num(VirtIODevice *vdev, int n)
+{
+    return vdev->vq[n].vring.num;
+}
+
+int virtio_queue_get_id(VirtQueue *vq)
+{
+    VirtIODevice *vdev = vq->vdev;
+    assert(vq >= &vdev->vq[0] && vq < &vdev->vq[VIRTIO_PCI_QUEUE_MAX]);
+    return vq - &vdev->vq[0];
+}
+
+void virtio_queue_notify_vq(VirtQueue *vq)
+{
+    if (vq->vring.desc) {
+        VirtIODevice *vdev = vq->vdev;
+        trace_virtio_queue_notify(vdev, vq - vdev->vq, vq);
+        vq->handle_output(vdev, vq);
+    }
+}
+
+void virtio_queue_notify(VirtIODevice *vdev, int n)
+{
+    virtio_queue_notify_vq(&vdev->vq[n]);
+}
+
+uint16_t virtio_queue_vector(VirtIODevice *vdev, int n)
+{
+    return n < VIRTIO_PCI_QUEUE_MAX ? vdev->vq[n].vector :
+        VIRTIO_NO_VECTOR;
+}
+
+void virtio_queue_set_vector(VirtIODevice *vdev, int n, uint16_t vector)
+{
+    if (n < VIRTIO_PCI_QUEUE_MAX)
+        vdev->vq[n].vector = vector;
+}
+
+VirtQueue *virtio_add_queue(VirtIODevice *vdev, int queue_size,
+                            void (*handle_output)(VirtIODevice *, VirtQueue *))
+{
+    int i;
+
+    for (i = 0; i < VIRTIO_PCI_QUEUE_MAX; i++) {
+        if (vdev->vq[i].vring.num == 0)
+            break;
+    }
+
+    if (i == VIRTIO_PCI_QUEUE_MAX || queue_size > VIRTQUEUE_MAX_SIZE)
+        abort();
+
+    vdev->vq[i].vring.num = queue_size;
+    vdev->vq[i].handle_output = handle_output;
+
+    return &vdev->vq[i];
+}
+
+void virtio_del_queue(VirtIODevice *vdev, int n)
+{
+    if (n < 0 || n >= VIRTIO_PCI_QUEUE_MAX) {
+        abort();
+    }
+
+    vdev->vq[n].vring.num = 0;
+}
+
+void virtio_irq(VirtQueue *vq)
+{
+    trace_virtio_irq(vq);
+    vq->vdev->isr |= 0x01;
+    virtio_notify_vector(vq->vdev, vq->vector);
+}
+
+/* Assuming a given event_idx value from the other size, if
+ * we have just incremented index from old to new_idx,
+ * should we trigger an event? */
+static inline int vring_need_event(uint16_t event, uint16_t new, uint16_t old)
+{
+       /* Note: Xen has similar logic for notification hold-off
+        * in include/xen/interface/io/ring.h with req_event and req_prod
+        * corresponding to event_idx + 1 and new respectively.
+        * Note also that req_event and req_prod in Xen start at 1,
+        * event indexes in virtio start at 0. */
+       return (uint16_t)(new - event - 1) < (uint16_t)(new - old);
+}
+
+static bool vring_notify(VirtIODevice *vdev, VirtQueue *vq)
+{
+    uint16_t old, new;
+    bool v;
+    /* We need to expose used array entries before checking used event. */
+    smp_mb();
+    /* Always notify when queue is empty (when feature acknowledge) */
+    if (((vdev->guest_features & (1 << VIRTIO_F_NOTIFY_ON_EMPTY)) &&
+         !vq->inuse && vring_avail_idx(vq) == vq->last_avail_idx)) {
+        return true;
+    }
+
+    if (!(vdev->guest_features & (1 << VIRTIO_RING_F_EVENT_IDX))) {
+        return !(vring_avail_flags(vq) & VRING_AVAIL_F_NO_INTERRUPT);
+    }
+
+    v = vq->signalled_used_valid;
+    vq->signalled_used_valid = true;
+    old = vq->signalled_used;
+    new = vq->signalled_used = vring_used_idx(vq);
+    return !v || vring_need_event(vring_used_event(vq), new, old);
+}
+
+void virtio_notify(VirtIODevice *vdev, VirtQueue *vq)
+{
+    if (!vring_notify(vdev, vq)) {
+        return;
+    }
+
+    trace_virtio_notify(vdev, vq);
+    vdev->isr |= 0x01;
+    virtio_notify_vector(vdev, vq->vector);
+}
+
+void virtio_notify_config(VirtIODevice *vdev)
+{
+    if (!(vdev->status & VIRTIO_CONFIG_S_DRIVER_OK))
+        return;
+
+    vdev->isr |= 0x03;
+    virtio_notify_vector(vdev, vdev->config_vector);
+}
+
+void virtio_save(VirtIODevice *vdev, QEMUFile *f)
+{
+    int i;
+
+    if (vdev->binding->save_config)
+        vdev->binding->save_config(vdev->binding_opaque, f);
+
+    qemu_put_8s(f, &vdev->status);
+    qemu_put_8s(f, &vdev->isr);
+    qemu_put_be16s(f, &vdev->queue_sel);
+    qemu_put_be32s(f, &vdev->guest_features);
+    qemu_put_be32(f, vdev->config_len);
+    qemu_put_buffer(f, vdev->config, vdev->config_len);
+
+    for (i = 0; i < VIRTIO_PCI_QUEUE_MAX; i++) {
+        if (vdev->vq[i].vring.num == 0)
+            break;
+    }
+
+    qemu_put_be32(f, i);
+
+    for (i = 0; i < VIRTIO_PCI_QUEUE_MAX; i++) {
+        if (vdev->vq[i].vring.num == 0)
+            break;
+
+        qemu_put_be32(f, vdev->vq[i].vring.num);
+        qemu_put_be64(f, vdev->vq[i].pa);
+        qemu_put_be16s(f, &vdev->vq[i].last_avail_idx);
+        if (vdev->binding->save_queue)
+            vdev->binding->save_queue(vdev->binding_opaque, i, f);
+    }
+}
+
+int virtio_set_features(VirtIODevice *vdev, uint32_t val)
+{
+    uint32_t supported_features =
+        vdev->binding->get_features(vdev->binding_opaque);
+    bool bad = (val & ~supported_features) != 0;
+
+    val &= supported_features;
+    if (vdev->set_features) {
+        vdev->set_features(vdev, val);
+    }
+    vdev->guest_features = val;
+    return bad ? -1 : 0;
+}
+
+int virtio_load(VirtIODevice *vdev, QEMUFile *f)
+{
+    int num, i, ret;
+    uint32_t features;
+    uint32_t supported_features;
+
+    if (vdev->binding->load_config) {
+        ret = vdev->binding->load_config(vdev->binding_opaque, f);
+        if (ret)
+            return ret;
+    }
+
+    qemu_get_8s(f, &vdev->status);
+    qemu_get_8s(f, &vdev->isr);
+    qemu_get_be16s(f, &vdev->queue_sel);
+    qemu_get_be32s(f, &features);
+
+    if (virtio_set_features(vdev, features) < 0) {
+        supported_features = vdev->binding->get_features(vdev->binding_opaque);
+        error_report("Features 0x%x unsupported. Allowed features: 0x%x",
+                     features, supported_features);
+        return -1;
+    }
+    vdev->config_len = qemu_get_be32(f);
+    qemu_get_buffer(f, vdev->config, vdev->config_len);
+
+    num = qemu_get_be32(f);
+
+    for (i = 0; i < num; i++) {
+        vdev->vq[i].vring.num = qemu_get_be32(f);
+        vdev->vq[i].pa = qemu_get_be64(f);
+        qemu_get_be16s(f, &vdev->vq[i].last_avail_idx);
+        vdev->vq[i].signalled_used_valid = false;
+        vdev->vq[i].notification = true;
+
+        if (vdev->vq[i].pa) {
+            uint16_t nheads;
+            virtqueue_init(&vdev->vq[i]);
+            nheads = vring_avail_idx(&vdev->vq[i]) - vdev->vq[i].last_avail_idx;
+            /* Check it isn't doing very strange things with descriptor numbers. */
+            if (nheads > vdev->vq[i].vring.num) {
+                error_report("VQ %d size 0x%x Guest index 0x%x "
+                             "inconsistent with Host index 0x%x: delta 0x%x",
+                             i, vdev->vq[i].vring.num,
+                             vring_avail_idx(&vdev->vq[i]),
+                             vdev->vq[i].last_avail_idx, nheads);
+                return -1;
+            }
+        } else if (vdev->vq[i].last_avail_idx) {
+            error_report("VQ %d address 0x0 "
+                         "inconsistent with Host index 0x%x",
+                         i, vdev->vq[i].last_avail_idx);
+                return -1;
+       }
+        if (vdev->binding->load_queue) {
+            ret = vdev->binding->load_queue(vdev->binding_opaque, i, f);
+            if (ret)
+                return ret;
+        }
+    }
+
+    virtio_notify_vector(vdev, VIRTIO_NO_VECTOR);
+    return 0;
+}
+
+void virtio_common_cleanup(VirtIODevice *vdev)
+{
+    qemu_del_vm_change_state_handler(vdev->vmstate);
+    g_free(vdev->config);
+    g_free(vdev->vq);
+}
+
+void virtio_cleanup(VirtIODevice *vdev)
+{
+    virtio_common_cleanup(vdev);
+    g_free(vdev);
+}
+
+static void virtio_vmstate_change(void *opaque, int running, RunState state)
+{
+    VirtIODevice *vdev = opaque;
+    bool backend_run = running && (vdev->status & VIRTIO_CONFIG_S_DRIVER_OK);
+    vdev->vm_running = running;
+
+    if (backend_run) {
+        virtio_set_status(vdev, vdev->status);
+    }
+
+    if (vdev->binding->vmstate_change) {
+        vdev->binding->vmstate_change(vdev->binding_opaque, backend_run);
+    }
+
+    if (!backend_run) {
+        virtio_set_status(vdev, vdev->status);
+    }
+}
+
+void virtio_init(VirtIODevice *vdev, const char *name,
+                 uint16_t device_id, size_t config_size)
+{
+    int i;
+    vdev->device_id = device_id;
+    vdev->status = 0;
+    vdev->isr = 0;
+    vdev->queue_sel = 0;
+    vdev->config_vector = VIRTIO_NO_VECTOR;
+    vdev->vq = g_malloc0(sizeof(VirtQueue) * VIRTIO_PCI_QUEUE_MAX);
+    vdev->vm_running = runstate_is_running();
+    for (i = 0; i < VIRTIO_PCI_QUEUE_MAX; i++) {
+        vdev->vq[i].vector = VIRTIO_NO_VECTOR;
+        vdev->vq[i].vdev = vdev;
+        vdev->vq[i].queue_index = i;
+    }
+
+    vdev->name = name;
+    vdev->config_len = config_size;
+    if (vdev->config_len) {
+        vdev->config = g_malloc0(config_size);
+    } else {
+        vdev->config = NULL;
+    }
+    vdev->vmstate = qemu_add_vm_change_state_handler(virtio_vmstate_change,
+                                                     vdev);
+}
+
+VirtIODevice *virtio_common_init(const char *name, uint16_t device_id,
+                                 size_t config_size, size_t struct_size)
+{
+    VirtIODevice *vdev;
+    vdev = g_malloc0(struct_size);
+    virtio_init(vdev, name, device_id, config_size);
+    return vdev;
+}
+
+void virtio_bind_device(VirtIODevice *vdev, const VirtIOBindings *binding,
+                        DeviceState *opaque)
+{
+    vdev->binding = binding;
+    vdev->binding_opaque = opaque;
+}
+
+hwaddr virtio_queue_get_desc_addr(VirtIODevice *vdev, int n)
+{
+    return vdev->vq[n].vring.desc;
+}
+
+hwaddr virtio_queue_get_avail_addr(VirtIODevice *vdev, int n)
+{
+    return vdev->vq[n].vring.avail;
+}
+
+hwaddr virtio_queue_get_used_addr(VirtIODevice *vdev, int n)
+{
+    return vdev->vq[n].vring.used;
+}
+
+hwaddr virtio_queue_get_ring_addr(VirtIODevice *vdev, int n)
+{
+    return vdev->vq[n].vring.desc;
+}
+
+hwaddr virtio_queue_get_desc_size(VirtIODevice *vdev, int n)
+{
+    return sizeof(VRingDesc) * vdev->vq[n].vring.num;
+}
+
+hwaddr virtio_queue_get_avail_size(VirtIODevice *vdev, int n)
+{
+    return offsetof(VRingAvail, ring) +
+        sizeof(uint64_t) * vdev->vq[n].vring.num;
+}
+
+hwaddr virtio_queue_get_used_size(VirtIODevice *vdev, int n)
+{
+    return offsetof(VRingUsed, ring) +
+        sizeof(VRingUsedElem) * vdev->vq[n].vring.num;
+}
+
+hwaddr virtio_queue_get_ring_size(VirtIODevice *vdev, int n)
+{
+    return vdev->vq[n].vring.used - vdev->vq[n].vring.desc +
+           virtio_queue_get_used_size(vdev, n);
+}
+
+uint16_t virtio_queue_get_last_avail_idx(VirtIODevice *vdev, int n)
+{
+    return vdev->vq[n].last_avail_idx;
+}
+
+void virtio_queue_set_last_avail_idx(VirtIODevice *vdev, int n, uint16_t idx)
+{
+    vdev->vq[n].last_avail_idx = idx;
+}
+
+VirtQueue *virtio_get_queue(VirtIODevice *vdev, int n)
+{
+    return vdev->vq + n;
+}
+
+uint16_t virtio_get_queue_index(VirtQueue *vq)
+{
+    return vq->queue_index;
+}
+
+static void virtio_queue_guest_notifier_read(EventNotifier *n)
+{
+    VirtQueue *vq = container_of(n, VirtQueue, guest_notifier);
+    if (event_notifier_test_and_clear(n)) {
+        virtio_irq(vq);
+    }
+}
+
+void virtio_queue_set_guest_notifier_fd_handler(VirtQueue *vq, bool assign,
+                                                bool with_irqfd)
+{
+    if (assign && !with_irqfd) {
+        event_notifier_set_handler(&vq->guest_notifier,
+                                   virtio_queue_guest_notifier_read);
+    } else {
+        event_notifier_set_handler(&vq->guest_notifier, NULL);
+    }
+    if (!assign) {
+        /* Test and clear notifier before closing it,
+         * in case poll callback didn't have time to run. */
+        virtio_queue_guest_notifier_read(&vq->guest_notifier);
+    }
+}
+
+EventNotifier *virtio_queue_get_guest_notifier(VirtQueue *vq)
+{
+    return &vq->guest_notifier;
+}
+
+static void virtio_queue_host_notifier_read(EventNotifier *n)
+{
+    VirtQueue *vq = container_of(n, VirtQueue, host_notifier);
+    if (event_notifier_test_and_clear(n)) {
+        virtio_queue_notify_vq(vq);
+    }
+}
+
+void virtio_queue_set_host_notifier_fd_handler(VirtQueue *vq, bool assign,
+                                               bool set_handler)
+{
+    if (assign && set_handler) {
+        event_notifier_set_handler(&vq->host_notifier,
+                                   virtio_queue_host_notifier_read);
+    } else {
+        event_notifier_set_handler(&vq->host_notifier, NULL);
+    }
+    if (!assign) {
+        /* Test and clear notifier before after disabling event,
+         * in case poll callback didn't have time to run. */
+        virtio_queue_host_notifier_read(&vq->host_notifier);
+    }
+}
+
+EventNotifier *virtio_queue_get_host_notifier(VirtQueue *vq)
+{
+    return &vq->host_notifier;
+}
+
+static int virtio_device_init(DeviceState *qdev)
+{
+    VirtIODevice *vdev = VIRTIO_DEVICE(qdev);
+    VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(qdev);
+    assert(k->init != NULL);
+    if (k->init(vdev) < 0) {
+        return -1;
+    }
+    virtio_bus_plug_device(vdev);
+    return 0;
+}
+
+static void virtio_device_class_init(ObjectClass *klass, void *data)
+{
+    /* Set the default value here. */
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    dc->init = virtio_device_init;
+    dc->bus_type = TYPE_VIRTIO_BUS;
+}
+
+static const TypeInfo virtio_device_info = {
+    .name = TYPE_VIRTIO_DEVICE,
+    .parent = TYPE_DEVICE,
+    .instance_size = sizeof(VirtIODevice),
+    .class_init = virtio_device_class_init,
+    .abstract = true,
+    .class_size = sizeof(VirtioDeviceClass),
+};
+
+static void virtio_register_types(void)
+{
+    type_register_static(&virtio_device_info);
+}
+
+type_init(virtio_register_types)
diff --git a/hw/vmmouse.c b/hw/vmmouse.c
deleted file mode 100644 (file)
index a9d227e..0000000
+++ /dev/null
@@ -1,301 +0,0 @@
-/*
- * QEMU VMMouse emulation
- *
- * Copyright (C) 2007 Anthony Liguori <anthony@codemonkey.ws>
- *
- * 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 "hw/hw.h"
-#include "ui/console.h"
-#include "hw/ps2.h"
-#include "hw/pc.h"
-#include "hw/qdev.h"
-
-/* debug only vmmouse */
-//#define DEBUG_VMMOUSE
-
-/* VMMouse Commands */
-#define VMMOUSE_GETVERSION     10
-#define VMMOUSE_DATA           39
-#define VMMOUSE_STATUS         40
-#define VMMOUSE_COMMAND                41
-
-#define VMMOUSE_READ_ID                        0x45414552
-#define VMMOUSE_DISABLE                        0x000000f5
-#define VMMOUSE_REQUEST_RELATIVE       0x4c455252
-#define VMMOUSE_REQUEST_ABSOLUTE       0x53424152
-
-#define VMMOUSE_QUEUE_SIZE     1024
-
-#define VMMOUSE_VERSION                0x3442554a
-
-#ifdef DEBUG_VMMOUSE
-#define DPRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__)
-#else
-#define DPRINTF(fmt, ...) do { } while (0)
-#endif
-
-typedef struct _VMMouseState
-{
-    ISADevice dev;
-    uint32_t queue[VMMOUSE_QUEUE_SIZE];
-    int32_t queue_size;
-    uint16_t nb_queue;
-    uint16_t status;
-    uint8_t absolute;
-    QEMUPutMouseEntry *entry;
-    void *ps2_mouse;
-} VMMouseState;
-
-static uint32_t vmmouse_get_status(VMMouseState *s)
-{
-    DPRINTF("vmmouse_get_status()\n");
-    return (s->status << 16) | s->nb_queue;
-}
-
-static void vmmouse_mouse_event(void *opaque, int x, int y, int dz, int buttons_state)
-{
-    VMMouseState *s = opaque;
-    int buttons = 0;
-
-    if (s->nb_queue > (VMMOUSE_QUEUE_SIZE - 4))
-        return;
-
-    DPRINTF("vmmouse_mouse_event(%d, %d, %d, %d)\n",
-            x, y, dz, buttons_state);
-
-    if ((buttons_state & MOUSE_EVENT_LBUTTON))
-        buttons |= 0x20;
-    if ((buttons_state & MOUSE_EVENT_RBUTTON))
-        buttons |= 0x10;
-    if ((buttons_state & MOUSE_EVENT_MBUTTON))
-        buttons |= 0x08;
-
-    if (s->absolute) {
-        x <<= 1;
-        y <<= 1;
-    }
-
-    s->queue[s->nb_queue++] = buttons;
-    s->queue[s->nb_queue++] = x;
-    s->queue[s->nb_queue++] = y;
-    s->queue[s->nb_queue++] = dz;
-
-    /* need to still generate PS2 events to notify driver to
-       read from queue */
-    i8042_isa_mouse_fake_event(s->ps2_mouse);
-}
-
-static void vmmouse_remove_handler(VMMouseState *s)
-{
-    if (s->entry) {
-        qemu_remove_mouse_event_handler(s->entry);
-        s->entry = NULL;
-    }
-}
-
-static void vmmouse_update_handler(VMMouseState *s, int absolute)
-{
-    if (s->status != 0) {
-        return;
-    }
-    if (s->absolute != absolute) {
-        s->absolute = absolute;
-        vmmouse_remove_handler(s);
-    }
-    if (s->entry == NULL) {
-        s->entry = qemu_add_mouse_event_handler(vmmouse_mouse_event,
-                                                s, s->absolute,
-                                                "vmmouse");
-        qemu_activate_mouse_event_handler(s->entry);
-    }
-}
-
-static void vmmouse_read_id(VMMouseState *s)
-{
-    DPRINTF("vmmouse_read_id()\n");
-
-    if (s->nb_queue == VMMOUSE_QUEUE_SIZE)
-        return;
-
-    s->queue[s->nb_queue++] = VMMOUSE_VERSION;
-    s->status = 0;
-}
-
-static void vmmouse_request_relative(VMMouseState *s)
-{
-    DPRINTF("vmmouse_request_relative()\n");
-    vmmouse_update_handler(s, 0);
-}
-
-static void vmmouse_request_absolute(VMMouseState *s)
-{
-    DPRINTF("vmmouse_request_absolute()\n");
-    vmmouse_update_handler(s, 1);
-}
-
-static void vmmouse_disable(VMMouseState *s)
-{
-    DPRINTF("vmmouse_disable()\n");
-    s->status = 0xffff;
-    vmmouse_remove_handler(s);
-}
-
-static void vmmouse_data(VMMouseState *s, uint32_t *data, uint32_t size)
-{
-    int i;
-
-    DPRINTF("vmmouse_data(%d)\n", size);
-
-    if (size == 0 || size > 6 || size > s->nb_queue) {
-        printf("vmmouse: driver requested too much data %d\n", size);
-        s->status = 0xffff;
-        vmmouse_remove_handler(s);
-        return;
-    }
-
-    for (i = 0; i < size; i++)
-        data[i] = s->queue[i];
-
-    s->nb_queue -= size;
-    if (s->nb_queue)
-        memmove(s->queue, &s->queue[size], sizeof(s->queue[0]) * s->nb_queue);
-}
-
-static uint32_t vmmouse_ioport_read(void *opaque, uint32_t addr)
-{
-    VMMouseState *s = opaque;
-    uint32_t data[6];
-    uint16_t command;
-
-    vmmouse_get_data(data);
-
-    command = data[2] & 0xFFFF;
-
-    switch (command) {
-    case VMMOUSE_STATUS:
-        data[0] = vmmouse_get_status(s);
-        break;
-    case VMMOUSE_COMMAND:
-        switch (data[1]) {
-        case VMMOUSE_DISABLE:
-            vmmouse_disable(s);
-            break;
-        case VMMOUSE_READ_ID:
-            vmmouse_read_id(s);
-            break;
-        case VMMOUSE_REQUEST_RELATIVE:
-            vmmouse_request_relative(s);
-            break;
-        case VMMOUSE_REQUEST_ABSOLUTE:
-            vmmouse_request_absolute(s);
-            break;
-        default:
-            printf("vmmouse: unknown command %x\n", data[1]);
-            break;
-        }
-        break;
-    case VMMOUSE_DATA:
-        vmmouse_data(s, data, data[1]);
-        break;
-    default:
-        printf("vmmouse: unknown command %x\n", command);
-        break;
-    }
-
-    vmmouse_set_data(data);
-    return data[0];
-}
-
-static int vmmouse_post_load(void *opaque, int version_id)
-{
-    VMMouseState *s = opaque;
-
-    vmmouse_remove_handler(s);
-    vmmouse_update_handler(s, s->absolute);
-    return 0;
-}
-
-static const VMStateDescription vmstate_vmmouse = {
-    .name = "vmmouse",
-    .version_id = 0,
-    .minimum_version_id = 0,
-    .minimum_version_id_old = 0,
-    .post_load = vmmouse_post_load,
-    .fields      = (VMStateField []) {
-        VMSTATE_INT32_EQUAL(queue_size, VMMouseState),
-        VMSTATE_UINT32_ARRAY(queue, VMMouseState, VMMOUSE_QUEUE_SIZE),
-        VMSTATE_UINT16(nb_queue, VMMouseState),
-        VMSTATE_UINT16(status, VMMouseState),
-        VMSTATE_UINT8(absolute, VMMouseState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void vmmouse_reset(DeviceState *d)
-{
-    VMMouseState *s = container_of(d, VMMouseState, dev.qdev);
-
-    s->queue_size = VMMOUSE_QUEUE_SIZE;
-
-    vmmouse_disable(s);
-}
-
-static int vmmouse_initfn(ISADevice *dev)
-{
-    VMMouseState *s = DO_UPCAST(VMMouseState, dev, dev);
-
-    DPRINTF("vmmouse_init\n");
-
-    vmport_register(VMMOUSE_STATUS, vmmouse_ioport_read, s);
-    vmport_register(VMMOUSE_COMMAND, vmmouse_ioport_read, s);
-    vmport_register(VMMOUSE_DATA, vmmouse_ioport_read, s);
-
-    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 const TypeInfo vmmouse_info = {
-    .name          = "vmmouse",
-    .parent        = TYPE_ISA_DEVICE,
-    .instance_size = sizeof(VMMouseState),
-    .class_init    = vmmouse_class_initfn,
-};
-
-static void vmmouse_register_types(void)
-{
-    type_register_static(&vmmouse_info);
-}
-
-type_init(vmmouse_register_types)
diff --git a/hw/vmport.c b/hw/vmport.c
deleted file mode 100644 (file)
index cc1466a..0000000
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * QEMU VMPort emulation
- *
- * Copyright (C) 2007 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 "hw/hw.h"
-#include "hw/isa.h"
-#include "hw/pc.h"
-#include "sysemu/kvm.h"
-#include "hw/qdev.h"
-
-//#define VMPORT_DEBUG
-
-#define VMPORT_CMD_GETVERSION 0x0a
-#define VMPORT_CMD_GETRAMSIZE 0x14
-
-#define VMPORT_ENTRIES 0x2c
-#define VMPORT_MAGIC   0x564D5868
-
-typedef struct _VMPortState
-{
-    ISADevice dev;
-    MemoryRegion io;
-    IOPortReadFunc *func[VMPORT_ENTRIES];
-    void *opaque[VMPORT_ENTRIES];
-} VMPortState;
-
-static VMPortState *port_state;
-
-void vmport_register(unsigned char command, IOPortReadFunc *func, void *opaque)
-{
-    if (command >= VMPORT_ENTRIES)
-        return;
-
-    port_state->func[command] = func;
-    port_state->opaque[command] = opaque;
-}
-
-static uint64_t vmport_ioport_read(void *opaque, hwaddr addr,
-                                   unsigned size)
-{
-    VMPortState *s = opaque;
-    CPUX86State *env = cpu_single_env;
-    unsigned char command;
-    uint32_t eax;
-
-    cpu_synchronize_state(env);
-
-    eax = env->regs[R_EAX];
-    if (eax != VMPORT_MAGIC)
-        return eax;
-
-    command = env->regs[R_ECX];
-    if (command >= VMPORT_ENTRIES)
-        return eax;
-    if (!s->func[command])
-    {
-#ifdef VMPORT_DEBUG
-        fprintf(stderr, "vmport: unknown command %x\n", command);
-#endif
-        return eax;
-    }
-
-    return s->func[command](s->opaque[command], addr);
-}
-
-static void vmport_ioport_write(void *opaque, hwaddr addr,
-                                uint64_t val, unsigned size)
-{
-    CPUX86State *env = cpu_single_env;
-
-    env->regs[R_EAX] = vmport_ioport_read(opaque, addr, 4);
-}
-
-static uint32_t vmport_cmd_get_version(void *opaque, uint32_t addr)
-{
-    CPUX86State *env = cpu_single_env;
-    env->regs[R_EBX] = VMPORT_MAGIC;
-    return 6;
-}
-
-static uint32_t vmport_cmd_ram_size(void *opaque, uint32_t addr)
-{
-    CPUX86State *env = cpu_single_env;
-    env->regs[R_EBX] = 0x1177;
-    return ram_size;
-}
-
-/* vmmouse helpers */
-void vmmouse_get_data(uint32_t *data)
-{
-    CPUX86State *env = cpu_single_env;
-
-    data[0] = env->regs[R_EAX]; data[1] = env->regs[R_EBX];
-    data[2] = env->regs[R_ECX]; data[3] = env->regs[R_EDX];
-    data[4] = env->regs[R_ESI]; data[5] = env->regs[R_EDI];
-}
-
-void vmmouse_set_data(const uint32_t *data)
-{
-    CPUX86State *env = cpu_single_env;
-
-    env->regs[R_EAX] = data[0]; env->regs[R_EBX] = data[1];
-    env->regs[R_ECX] = data[2]; env->regs[R_EDX] = data[3];
-    env->regs[R_ESI] = data[4]; env->regs[R_EDI] = data[5];
-}
-
-static const MemoryRegionOps vmport_ops = {
-    .read = vmport_ioport_read,
-    .write = vmport_ioport_write,
-    .impl = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-    .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static int vmport_initfn(ISADevice *dev)
-{
-    VMPortState *s = DO_UPCAST(VMPortState, dev, dev);
-
-    memory_region_init_io(&s->io, &vmport_ops, s, "vmport", 1);
-    isa_register_ioport(dev, &s->io, 0x5658);
-
-    port_state = s;
-    /* Register some generic port commands */
-    vmport_register(VMPORT_CMD_GETVERSION, vmport_cmd_get_version, NULL);
-    vmport_register(VMPORT_CMD_GETRAMSIZE, vmport_cmd_ram_size, NULL);
-    return 0;
-}
-
-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 const TypeInfo vmport_info = {
-    .name          = "vmport",
-    .parent        = TYPE_ISA_DEVICE,
-    .instance_size = sizeof(VMPortState),
-    .class_init    = vmport_class_initfn,
-};
-
-static void vmport_register_types(void)
-{
-    type_register_static(&vmport_info);
-}
-
-type_init(vmport_register_types)
diff --git a/hw/vmware_utils.h b/hw/vmware_utils.h
deleted file mode 100644 (file)
index 5307e2c..0000000
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * QEMU VMWARE paravirtual devices - auxiliary code
- *
- * Copyright (c) 2012 Ravello Systems LTD (http://ravellosystems.com)
- *
- * Developed by Daynix Computing LTD (http://www.daynix.com)
- *
- * Authors:
- * Dmitry Fleytman <dmitry@daynix.com>
- * Yan Vugenfirer <yan@daynix.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 VMWARE_UTILS_H
-#define VMWARE_UTILS_H
-
-#include "qemu/range.h"
-
-#ifndef VMW_SHPRN
-#define VMW_SHPRN(fmt, ...) do {} while (0)
-#endif
-
-/*
- * Shared memory access functions with byte swap support
- * Each function contains printout for reverse-engineering needs
- *
- */
-static inline void
-vmw_shmem_read(hwaddr addr, void *buf, int len)
-{
-    VMW_SHPRN("SHMEM r: %" PRIx64 ", len: %d to %p", addr, len, buf);
-    cpu_physical_memory_read(addr, buf, len);
-}
-
-static inline void
-vmw_shmem_write(hwaddr addr, void *buf, int len)
-{
-    VMW_SHPRN("SHMEM w: %" PRIx64 ", len: %d to %p", addr, len, buf);
-    cpu_physical_memory_write(addr, buf, len);
-}
-
-static inline void
-vmw_shmem_rw(hwaddr addr, void *buf, int len, int is_write)
-{
-    VMW_SHPRN("SHMEM r/w: %" PRIx64 ", len: %d (to %p), is write: %d",
-              addr, len, buf, is_write);
-
-    cpu_physical_memory_rw(addr, buf, len, is_write);
-}
-
-static inline void
-vmw_shmem_set(hwaddr addr, uint8 val, int len)
-{
-    int i;
-    VMW_SHPRN("SHMEM set: %" PRIx64 ", len: %d (value 0x%X)", addr, len, val);
-
-    for (i = 0; i < len; i++) {
-        cpu_physical_memory_write(addr + i, &val, 1);
-    }
-}
-
-static inline uint32_t
-vmw_shmem_ld8(hwaddr addr)
-{
-    uint8_t res = ldub_phys(addr);
-    VMW_SHPRN("SHMEM load8: %" PRIx64 " (value 0x%X)", addr, res);
-    return res;
-}
-
-static inline void
-vmw_shmem_st8(hwaddr addr, uint8_t value)
-{
-    VMW_SHPRN("SHMEM store8: %" PRIx64 " (value 0x%X)", addr, value);
-    stb_phys(addr, value);
-}
-
-static inline uint32_t
-vmw_shmem_ld16(hwaddr addr)
-{
-    uint16_t res = lduw_le_phys(addr);
-    VMW_SHPRN("SHMEM load16: %" PRIx64 " (value 0x%X)", addr, res);
-    return res;
-}
-
-static inline void
-vmw_shmem_st16(hwaddr addr, uint16_t value)
-{
-    VMW_SHPRN("SHMEM store16: %" PRIx64 " (value 0x%X)", addr, value);
-    stw_le_phys(addr, value);
-}
-
-static inline uint32_t
-vmw_shmem_ld32(hwaddr addr)
-{
-    uint32_t res = ldl_le_phys(addr);
-    VMW_SHPRN("SHMEM load32: %" PRIx64 " (value 0x%X)", addr, res);
-    return res;
-}
-
-static inline void
-vmw_shmem_st32(hwaddr addr, uint32_t value)
-{
-    VMW_SHPRN("SHMEM store32: %" PRIx64 " (value 0x%X)", addr, value);
-    stl_le_phys(addr, value);
-}
-
-static inline uint64_t
-vmw_shmem_ld64(hwaddr addr)
-{
-    uint64_t res = ldq_le_phys(addr);
-    VMW_SHPRN("SHMEM load64: %" PRIx64 " (value %" PRIx64 ")", addr, res);
-    return res;
-}
-
-static inline void
-vmw_shmem_st64(hwaddr addr, uint64_t value)
-{
-    VMW_SHPRN("SHMEM store64: %" PRIx64 " (value %" PRIx64 ")", addr, value);
-    stq_le_phys(addr, value);
-}
-
-/* Macros for simplification of operations on array-style registers */
-
-/*
- * Whether <addr> lies inside of array-style register defined by <base>,
- * number of elements (<cnt>) and element size (<regsize>)
- *
-*/
-#define VMW_IS_MULTIREG_ADDR(addr, base, cnt, regsize)                 \
-    range_covers_byte(base, cnt * regsize, addr)
-
-/*
- * Returns index of given register (<addr>) in array-style register defined by
- * <base> and element size (<regsize>)
- *
-*/
-#define VMW_MULTIREG_IDX_BY_ADDR(addr, base, regsize)                  \
-    (((addr) - (base)) / (regsize))
-
-#endif
diff --git a/hw/vmware_vga.c b/hw/vmware_vga.c
deleted file mode 100644 (file)
index 5b9ce8f..0000000
+++ /dev/null
@@ -1,1282 +0,0 @@
-/*
- * QEMU VMware-SVGA "chipset".
- *
- * Copyright (c) 2007 Andrzej Zaborowski  <balrog@zabor.org>
- *
- * 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 "hw/hw.h"
-#include "hw/loader.h"
-#include "ui/console.h"
-#include "hw/pci/pci.h"
-
-#undef VERBOSE
-#define HW_RECT_ACCEL
-#define HW_FILL_ACCEL
-#define HW_MOUSE_ACCEL
-
-#include "hw/vga_int.h"
-
-/* See http://vmware-svga.sf.net/ for some documentation on VMWare SVGA */
-
-struct vmsvga_state_s {
-    VGACommonState vga;
-
-    int invalidated;
-    int depth;
-    int bypp;
-    int enable;
-    int config;
-    struct {
-        int id;
-        int x;
-        int y;
-        int on;
-    } cursor;
-
-    int index;
-    int scratch_size;
-    uint32_t *scratch;
-    int new_width;
-    int new_height;
-    uint32_t guest;
-    uint32_t svgaid;
-    int syncing;
-
-    MemoryRegion fifo_ram;
-    uint8_t *fifo_ptr;
-    unsigned int fifo_size;
-
-    union {
-        uint32_t *fifo;
-        struct QEMU_PACKED {
-            uint32_t min;
-            uint32_t max;
-            uint32_t next_cmd;
-            uint32_t stop;
-            /* Add registers here when adding capabilities.  */
-            uint32_t fifo[0];
-        } *cmd;
-    };
-
-#define REDRAW_FIFO_LEN  512
-    struct vmsvga_rect_s {
-        int x, y, w, h;
-    } redraw_fifo[REDRAW_FIFO_LEN];
-    int redraw_fifo_first, redraw_fifo_last;
-};
-
-struct pci_vmsvga_state_s {
-    PCIDevice card;
-    struct vmsvga_state_s chip;
-    MemoryRegion io_bar;
-};
-
-#define SVGA_MAGIC              0x900000UL
-#define SVGA_MAKE_ID(ver)       (SVGA_MAGIC << 8 | (ver))
-#define SVGA_ID_0               SVGA_MAKE_ID(0)
-#define SVGA_ID_1               SVGA_MAKE_ID(1)
-#define SVGA_ID_2               SVGA_MAKE_ID(2)
-
-#define SVGA_LEGACY_BASE_PORT   0x4560
-#define SVGA_INDEX_PORT         0x0
-#define SVGA_VALUE_PORT         0x1
-#define SVGA_BIOS_PORT          0x2
-
-#define SVGA_VERSION_2
-
-#ifdef SVGA_VERSION_2
-# define SVGA_ID                SVGA_ID_2
-# define SVGA_IO_BASE           SVGA_LEGACY_BASE_PORT
-# define SVGA_IO_MUL            1
-# define SVGA_FIFO_SIZE         0x10000
-# define SVGA_PCI_DEVICE_ID     PCI_DEVICE_ID_VMWARE_SVGA2
-#else
-# define SVGA_ID                SVGA_ID_1
-# define SVGA_IO_BASE           SVGA_LEGACY_BASE_PORT
-# define SVGA_IO_MUL            4
-# define SVGA_FIFO_SIZE         0x10000
-# define SVGA_PCI_DEVICE_ID     PCI_DEVICE_ID_VMWARE_SVGA
-#endif
-
-enum {
-    /* ID 0, 1 and 2 registers */
-    SVGA_REG_ID = 0,
-    SVGA_REG_ENABLE = 1,
-    SVGA_REG_WIDTH = 2,
-    SVGA_REG_HEIGHT = 3,
-    SVGA_REG_MAX_WIDTH = 4,
-    SVGA_REG_MAX_HEIGHT = 5,
-    SVGA_REG_DEPTH = 6,
-    SVGA_REG_BITS_PER_PIXEL = 7,        /* Current bpp in the guest */
-    SVGA_REG_PSEUDOCOLOR = 8,
-    SVGA_REG_RED_MASK = 9,
-    SVGA_REG_GREEN_MASK = 10,
-    SVGA_REG_BLUE_MASK = 11,
-    SVGA_REG_BYTES_PER_LINE = 12,
-    SVGA_REG_FB_START = 13,
-    SVGA_REG_FB_OFFSET = 14,
-    SVGA_REG_VRAM_SIZE = 15,
-    SVGA_REG_FB_SIZE = 16,
-
-    /* ID 1 and 2 registers */
-    SVGA_REG_CAPABILITIES = 17,
-    SVGA_REG_MEM_START = 18,            /* Memory for command FIFO */
-    SVGA_REG_MEM_SIZE = 19,
-    SVGA_REG_CONFIG_DONE = 20,          /* Set when memory area configured */
-    SVGA_REG_SYNC = 21,                 /* Write to force synchronization */
-    SVGA_REG_BUSY = 22,                 /* Read to check if sync is done */
-    SVGA_REG_GUEST_ID = 23,             /* Set guest OS identifier */
-    SVGA_REG_CURSOR_ID = 24,            /* ID of cursor */
-    SVGA_REG_CURSOR_X = 25,             /* Set cursor X position */
-    SVGA_REG_CURSOR_Y = 26,             /* Set cursor Y position */
-    SVGA_REG_CURSOR_ON = 27,            /* Turn cursor on/off */
-    SVGA_REG_HOST_BITS_PER_PIXEL = 28,  /* Current bpp in the host */
-    SVGA_REG_SCRATCH_SIZE = 29,         /* Number of scratch registers */
-    SVGA_REG_MEM_REGS = 30,             /* Number of FIFO registers */
-    SVGA_REG_NUM_DISPLAYS = 31,         /* Number of guest displays */
-    SVGA_REG_PITCHLOCK = 32,            /* Fixed pitch for all modes */
-
-    SVGA_PALETTE_BASE = 1024,           /* Base of SVGA color map */
-    SVGA_PALETTE_END  = SVGA_PALETTE_BASE + 767,
-    SVGA_SCRATCH_BASE = SVGA_PALETTE_BASE + 768,
-};
-
-#define SVGA_CAP_NONE                   0
-#define SVGA_CAP_RECT_FILL              (1 << 0)
-#define SVGA_CAP_RECT_COPY              (1 << 1)
-#define SVGA_CAP_RECT_PAT_FILL          (1 << 2)
-#define SVGA_CAP_LEGACY_OFFSCREEN       (1 << 3)
-#define SVGA_CAP_RASTER_OP              (1 << 4)
-#define SVGA_CAP_CURSOR                 (1 << 5)
-#define SVGA_CAP_CURSOR_BYPASS          (1 << 6)
-#define SVGA_CAP_CURSOR_BYPASS_2        (1 << 7)
-#define SVGA_CAP_8BIT_EMULATION         (1 << 8)
-#define SVGA_CAP_ALPHA_CURSOR           (1 << 9)
-#define SVGA_CAP_GLYPH                  (1 << 10)
-#define SVGA_CAP_GLYPH_CLIPPING         (1 << 11)
-#define SVGA_CAP_OFFSCREEN_1            (1 << 12)
-#define SVGA_CAP_ALPHA_BLEND            (1 << 13)
-#define SVGA_CAP_3D                     (1 << 14)
-#define SVGA_CAP_EXTENDED_FIFO          (1 << 15)
-#define SVGA_CAP_MULTIMON               (1 << 16)
-#define SVGA_CAP_PITCHLOCK              (1 << 17)
-
-/*
- * FIFO offsets (seen as an array of 32-bit words)
- */
-enum {
-    /*
-     * The original defined FIFO offsets
-     */
-    SVGA_FIFO_MIN = 0,
-    SVGA_FIFO_MAX,      /* The distance from MIN to MAX must be at least 10K */
-    SVGA_FIFO_NEXT_CMD,
-    SVGA_FIFO_STOP,
-
-    /*
-     * Additional offsets added as of SVGA_CAP_EXTENDED_FIFO
-     */
-    SVGA_FIFO_CAPABILITIES = 4,
-    SVGA_FIFO_FLAGS,
-    SVGA_FIFO_FENCE,
-    SVGA_FIFO_3D_HWVERSION,
-    SVGA_FIFO_PITCHLOCK,
-};
-
-#define SVGA_FIFO_CAP_NONE              0
-#define SVGA_FIFO_CAP_FENCE             (1 << 0)
-#define SVGA_FIFO_CAP_ACCELFRONT        (1 << 1)
-#define SVGA_FIFO_CAP_PITCHLOCK         (1 << 2)
-
-#define SVGA_FIFO_FLAG_NONE             0
-#define SVGA_FIFO_FLAG_ACCELFRONT       (1 << 0)
-
-/* These values can probably be changed arbitrarily.  */
-#define SVGA_SCRATCH_SIZE               0x8000
-#define SVGA_MAX_WIDTH                  2360
-#define SVGA_MAX_HEIGHT                 1770
-
-#ifdef VERBOSE
-# define GUEST_OS_BASE          0x5001
-static const char *vmsvga_guest_id[] = {
-    [0x00] = "Dos",
-    [0x01] = "Windows 3.1",
-    [0x02] = "Windows 95",
-    [0x03] = "Windows 98",
-    [0x04] = "Windows ME",
-    [0x05] = "Windows NT",
-    [0x06] = "Windows 2000",
-    [0x07] = "Linux",
-    [0x08] = "OS/2",
-    [0x09] = "an unknown OS",
-    [0x0a] = "BSD",
-    [0x0b] = "Whistler",
-    [0x0c] = "an unknown OS",
-    [0x0d] = "an unknown OS",
-    [0x0e] = "an unknown OS",
-    [0x0f] = "an unknown OS",
-    [0x10] = "an unknown OS",
-    [0x11] = "an unknown OS",
-    [0x12] = "an unknown OS",
-    [0x13] = "an unknown OS",
-    [0x14] = "an unknown OS",
-    [0x15] = "Windows 2003",
-};
-#endif
-
-enum {
-    SVGA_CMD_INVALID_CMD = 0,
-    SVGA_CMD_UPDATE = 1,
-    SVGA_CMD_RECT_FILL = 2,
-    SVGA_CMD_RECT_COPY = 3,
-    SVGA_CMD_DEFINE_BITMAP = 4,
-    SVGA_CMD_DEFINE_BITMAP_SCANLINE = 5,
-    SVGA_CMD_DEFINE_PIXMAP = 6,
-    SVGA_CMD_DEFINE_PIXMAP_SCANLINE = 7,
-    SVGA_CMD_RECT_BITMAP_FILL = 8,
-    SVGA_CMD_RECT_PIXMAP_FILL = 9,
-    SVGA_CMD_RECT_BITMAP_COPY = 10,
-    SVGA_CMD_RECT_PIXMAP_COPY = 11,
-    SVGA_CMD_FREE_OBJECT = 12,
-    SVGA_CMD_RECT_ROP_FILL = 13,
-    SVGA_CMD_RECT_ROP_COPY = 14,
-    SVGA_CMD_RECT_ROP_BITMAP_FILL = 15,
-    SVGA_CMD_RECT_ROP_PIXMAP_FILL = 16,
-    SVGA_CMD_RECT_ROP_BITMAP_COPY = 17,
-    SVGA_CMD_RECT_ROP_PIXMAP_COPY = 18,
-    SVGA_CMD_DEFINE_CURSOR = 19,
-    SVGA_CMD_DISPLAY_CURSOR = 20,
-    SVGA_CMD_MOVE_CURSOR = 21,
-    SVGA_CMD_DEFINE_ALPHA_CURSOR = 22,
-    SVGA_CMD_DRAW_GLYPH = 23,
-    SVGA_CMD_DRAW_GLYPH_CLIPPED = 24,
-    SVGA_CMD_UPDATE_VERBOSE = 25,
-    SVGA_CMD_SURFACE_FILL = 26,
-    SVGA_CMD_SURFACE_COPY = 27,
-    SVGA_CMD_SURFACE_ALPHA_BLEND = 28,
-    SVGA_CMD_FRONT_ROP_FILL = 29,
-    SVGA_CMD_FENCE = 30,
-};
-
-/* Legal values for the SVGA_REG_CURSOR_ON register in cursor bypass mode */
-enum {
-    SVGA_CURSOR_ON_HIDE = 0,
-    SVGA_CURSOR_ON_SHOW = 1,
-    SVGA_CURSOR_ON_REMOVE_FROM_FB = 2,
-    SVGA_CURSOR_ON_RESTORE_TO_FB = 3,
-};
-
-static inline void vmsvga_update_rect(struct vmsvga_state_s *s,
-                int x, int y, int w, int h)
-{
-    DisplaySurface *surface = qemu_console_surface(s->vga.con);
-    int line;
-    int bypl;
-    int width;
-    int start;
-    uint8_t *src;
-    uint8_t *dst;
-
-    if (x < 0) {
-        fprintf(stderr, "%s: update x was < 0 (%d)\n", __func__, x);
-        w += x;
-        x = 0;
-    }
-    if (w < 0) {
-        fprintf(stderr, "%s: update w was < 0 (%d)\n", __func__, w);
-        w = 0;
-    }
-    if (x + w > surface_width(surface)) {
-        fprintf(stderr, "%s: update width too large x: %d, w: %d\n",
-                __func__, x, w);
-        x = MIN(x, surface_width(surface));
-        w = surface_width(surface) - x;
-    }
-
-    if (y < 0) {
-        fprintf(stderr, "%s: update y was < 0 (%d)\n",  __func__, y);
-        h += y;
-        y = 0;
-    }
-    if (h < 0) {
-        fprintf(stderr, "%s: update h was < 0 (%d)\n",  __func__, h);
-        h = 0;
-    }
-    if (y + h > surface_height(surface)) {
-        fprintf(stderr, "%s: update height too large y: %d, h: %d\n",
-                __func__, y, h);
-        y = MIN(y, surface_height(surface));
-        h = surface_height(surface) - y;
-    }
-
-    bypl = surface_stride(surface);
-    width = surface_bytes_per_pixel(surface) * w;
-    start = surface_bytes_per_pixel(surface) * x + bypl * y;
-    src = s->vga.vram_ptr + start;
-    dst = surface_data(surface) + start;
-
-    for (line = h; line > 0; line--, src += bypl, dst += bypl) {
-        memcpy(dst, src, width);
-    }
-    dpy_gfx_update(s->vga.con, x, y, w, h);
-}
-
-static inline void vmsvga_update_rect_delayed(struct vmsvga_state_s *s,
-                int x, int y, int w, int h)
-{
-    struct vmsvga_rect_s *rect = &s->redraw_fifo[s->redraw_fifo_last++];
-
-    s->redraw_fifo_last &= REDRAW_FIFO_LEN - 1;
-    rect->x = x;
-    rect->y = y;
-    rect->w = w;
-    rect->h = h;
-}
-
-static inline void vmsvga_update_rect_flush(struct vmsvga_state_s *s)
-{
-    struct vmsvga_rect_s *rect;
-
-    if (s->invalidated) {
-        s->redraw_fifo_first = s->redraw_fifo_last;
-        return;
-    }
-    /* Overlapping region updates can be optimised out here - if someone
-     * knows a smart algorithm to do that, please share.  */
-    while (s->redraw_fifo_first != s->redraw_fifo_last) {
-        rect = &s->redraw_fifo[s->redraw_fifo_first++];
-        s->redraw_fifo_first &= REDRAW_FIFO_LEN - 1;
-        vmsvga_update_rect(s, rect->x, rect->y, rect->w, rect->h);
-    }
-}
-
-#ifdef HW_RECT_ACCEL
-static inline void vmsvga_copy_rect(struct vmsvga_state_s *s,
-                int x0, int y0, int x1, int y1, int w, int h)
-{
-    DisplaySurface *surface = qemu_console_surface(s->vga.con);
-    uint8_t *vram = s->vga.vram_ptr;
-    int bypl = surface_stride(surface);
-    int bypp = surface_bytes_per_pixel(surface);
-    int width = bypp * w;
-    int line = h;
-    uint8_t *ptr[2];
-
-    if (y1 > y0) {
-        ptr[0] = vram + bypp * x0 + bypl * (y0 + h - 1);
-        ptr[1] = vram + bypp * x1 + bypl * (y1 + h - 1);
-        for (; line > 0; line --, ptr[0] -= bypl, ptr[1] -= bypl) {
-            memmove(ptr[1], ptr[0], width);
-        }
-    } else {
-        ptr[0] = vram + bypp * x0 + bypl * y0;
-        ptr[1] = vram + bypp * x1 + bypl * y1;
-        for (; line > 0; line --, ptr[0] += bypl, ptr[1] += bypl) {
-            memmove(ptr[1], ptr[0], width);
-        }
-    }
-
-    vmsvga_update_rect_delayed(s, x1, y1, w, h);
-}
-#endif
-
-#ifdef HW_FILL_ACCEL
-static inline void vmsvga_fill_rect(struct vmsvga_state_s *s,
-                uint32_t c, int x, int y, int w, int h)
-{
-    DisplaySurface *surface = qemu_console_surface(s->vga.con);
-    int bypl = surface_stride(surface);
-    int width = surface_bytes_per_pixel(surface) * w;
-    int line = h;
-    int column;
-    uint8_t *fst;
-    uint8_t *dst;
-    uint8_t *src;
-    uint8_t col[4];
-
-    col[0] = c;
-    col[1] = c >> 8;
-    col[2] = c >> 16;
-    col[3] = c >> 24;
-
-    fst = s->vga.vram_ptr + surface_bytes_per_pixel(surface) * x + bypl * y;
-
-    if (line--) {
-        dst = fst;
-        src = col;
-        for (column = width; column > 0; column--) {
-            *(dst++) = *(src++);
-            if (src - col == surface_bytes_per_pixel(surface)) {
-                src = col;
-            }
-        }
-        dst = fst;
-        for (; line > 0; line--) {
-            dst += bypl;
-            memcpy(dst, fst, width);
-        }
-    }
-
-    vmsvga_update_rect_delayed(s, x, y, w, h);
-}
-#endif
-
-struct vmsvga_cursor_definition_s {
-    int width;
-    int height;
-    int id;
-    int bpp;
-    int hot_x;
-    int hot_y;
-    uint32_t mask[1024];
-    uint32_t image[4096];
-};
-
-#define SVGA_BITMAP_SIZE(w, h)          ((((w) + 31) >> 5) * (h))
-#define SVGA_PIXMAP_SIZE(w, h, bpp)     (((((w) * (bpp)) + 31) >> 5) * (h))
-
-#ifdef HW_MOUSE_ACCEL
-static inline void vmsvga_cursor_define(struct vmsvga_state_s *s,
-                struct vmsvga_cursor_definition_s *c)
-{
-    QEMUCursor *qc;
-    int i, pixels;
-
-    qc = cursor_alloc(c->width, c->height);
-    qc->hot_x = c->hot_x;
-    qc->hot_y = c->hot_y;
-    switch (c->bpp) {
-    case 1:
-        cursor_set_mono(qc, 0xffffff, 0x000000, (void *)c->image,
-                        1, (void *)c->mask);
-#ifdef DEBUG
-        cursor_print_ascii_art(qc, "vmware/mono");
-#endif
-        break;
-    case 32:
-        /* fill alpha channel from mask, set color to zero */
-        cursor_set_mono(qc, 0x000000, 0x000000, (void *)c->mask,
-                        1, (void *)c->mask);
-        /* add in rgb values */
-        pixels = c->width * c->height;
-        for (i = 0; i < pixels; i++) {
-            qc->data[i] |= c->image[i] & 0xffffff;
-        }
-#ifdef DEBUG
-        cursor_print_ascii_art(qc, "vmware/32bit");
-#endif
-        break;
-    default:
-        fprintf(stderr, "%s: unhandled bpp %d, using fallback cursor\n",
-                __func__, c->bpp);
-        cursor_put(qc);
-        qc = cursor_builtin_left_ptr();
-    }
-
-    dpy_cursor_define(s->vga.con, qc);
-    cursor_put(qc);
-}
-#endif
-
-#define CMD(f)  le32_to_cpu(s->cmd->f)
-
-static inline int vmsvga_fifo_length(struct vmsvga_state_s *s)
-{
-    int num;
-
-    if (!s->config || !s->enable) {
-        return 0;
-    }
-    num = CMD(next_cmd) - CMD(stop);
-    if (num < 0) {
-        num += CMD(max) - CMD(min);
-    }
-    return num >> 2;
-}
-
-static inline uint32_t vmsvga_fifo_read_raw(struct vmsvga_state_s *s)
-{
-    uint32_t cmd = s->fifo[CMD(stop) >> 2];
-
-    s->cmd->stop = cpu_to_le32(CMD(stop) + 4);
-    if (CMD(stop) >= CMD(max)) {
-        s->cmd->stop = s->cmd->min;
-    }
-    return cmd;
-}
-
-static inline uint32_t vmsvga_fifo_read(struct vmsvga_state_s *s)
-{
-    return le32_to_cpu(vmsvga_fifo_read_raw(s));
-}
-
-static void vmsvga_fifo_run(struct vmsvga_state_s *s)
-{
-    uint32_t cmd, colour;
-    int args, len;
-    int x, y, dx, dy, width, height;
-    struct vmsvga_cursor_definition_s cursor;
-    uint32_t cmd_start;
-
-    len = vmsvga_fifo_length(s);
-    while (len > 0) {
-        /* May need to go back to the start of the command if incomplete */
-        cmd_start = s->cmd->stop;
-
-        switch (cmd = vmsvga_fifo_read(s)) {
-        case SVGA_CMD_UPDATE:
-        case SVGA_CMD_UPDATE_VERBOSE:
-            len -= 5;
-            if (len < 0) {
-                goto rewind;
-            }
-
-            x = vmsvga_fifo_read(s);
-            y = vmsvga_fifo_read(s);
-            width = vmsvga_fifo_read(s);
-            height = vmsvga_fifo_read(s);
-            vmsvga_update_rect_delayed(s, x, y, width, height);
-            break;
-
-        case SVGA_CMD_RECT_FILL:
-            len -= 6;
-            if (len < 0) {
-                goto rewind;
-            }
-
-            colour = vmsvga_fifo_read(s);
-            x = vmsvga_fifo_read(s);
-            y = vmsvga_fifo_read(s);
-            width = vmsvga_fifo_read(s);
-            height = vmsvga_fifo_read(s);
-#ifdef HW_FILL_ACCEL
-            vmsvga_fill_rect(s, colour, x, y, width, height);
-            break;
-#else
-            args = 0;
-            goto badcmd;
-#endif
-
-        case SVGA_CMD_RECT_COPY:
-            len -= 7;
-            if (len < 0) {
-                goto rewind;
-            }
-
-            x = vmsvga_fifo_read(s);
-            y = vmsvga_fifo_read(s);
-            dx = vmsvga_fifo_read(s);
-            dy = vmsvga_fifo_read(s);
-            width = vmsvga_fifo_read(s);
-            height = vmsvga_fifo_read(s);
-#ifdef HW_RECT_ACCEL
-            vmsvga_copy_rect(s, x, y, dx, dy, width, height);
-            break;
-#else
-            args = 0;
-            goto badcmd;
-#endif
-
-        case SVGA_CMD_DEFINE_CURSOR:
-            len -= 8;
-            if (len < 0) {
-                goto rewind;
-            }
-
-            cursor.id = vmsvga_fifo_read(s);
-            cursor.hot_x = vmsvga_fifo_read(s);
-            cursor.hot_y = vmsvga_fifo_read(s);
-            cursor.width = x = vmsvga_fifo_read(s);
-            cursor.height = y = vmsvga_fifo_read(s);
-            vmsvga_fifo_read(s);
-            cursor.bpp = vmsvga_fifo_read(s);
-
-            args = SVGA_BITMAP_SIZE(x, y) + SVGA_PIXMAP_SIZE(x, y, cursor.bpp);
-            if (SVGA_BITMAP_SIZE(x, y) > sizeof cursor.mask ||
-                SVGA_PIXMAP_SIZE(x, y, cursor.bpp) > sizeof cursor.image) {
-                    goto badcmd;
-            }
-
-            len -= args;
-            if (len < 0) {
-                goto rewind;
-            }
-
-            for (args = 0; args < SVGA_BITMAP_SIZE(x, y); args++) {
-                cursor.mask[args] = vmsvga_fifo_read_raw(s);
-            }
-            for (args = 0; args < SVGA_PIXMAP_SIZE(x, y, cursor.bpp); args++) {
-                cursor.image[args] = vmsvga_fifo_read_raw(s);
-            }
-#ifdef HW_MOUSE_ACCEL
-            vmsvga_cursor_define(s, &cursor);
-            break;
-#else
-            args = 0;
-            goto badcmd;
-#endif
-
-        /*
-         * Other commands that we at least know the number of arguments
-         * for so we can avoid FIFO desync if driver uses them illegally.
-         */
-        case SVGA_CMD_DEFINE_ALPHA_CURSOR:
-            len -= 6;
-            if (len < 0) {
-                goto rewind;
-            }
-            vmsvga_fifo_read(s);
-            vmsvga_fifo_read(s);
-            vmsvga_fifo_read(s);
-            x = vmsvga_fifo_read(s);
-            y = vmsvga_fifo_read(s);
-            args = x * y;
-            goto badcmd;
-        case SVGA_CMD_RECT_ROP_FILL:
-            args = 6;
-            goto badcmd;
-        case SVGA_CMD_RECT_ROP_COPY:
-            args = 7;
-            goto badcmd;
-        case SVGA_CMD_DRAW_GLYPH_CLIPPED:
-            len -= 4;
-            if (len < 0) {
-                goto rewind;
-            }
-            vmsvga_fifo_read(s);
-            vmsvga_fifo_read(s);
-            args = 7 + (vmsvga_fifo_read(s) >> 2);
-            goto badcmd;
-        case SVGA_CMD_SURFACE_ALPHA_BLEND:
-            args = 12;
-            goto badcmd;
-
-        /*
-         * Other commands that are not listed as depending on any
-         * CAPABILITIES bits, but are not described in the README either.
-         */
-        case SVGA_CMD_SURFACE_FILL:
-        case SVGA_CMD_SURFACE_COPY:
-        case SVGA_CMD_FRONT_ROP_FILL:
-        case SVGA_CMD_FENCE:
-        case SVGA_CMD_INVALID_CMD:
-            break; /* Nop */
-
-        default:
-            args = 0;
-        badcmd:
-            len -= args;
-            if (len < 0) {
-                goto rewind;
-            }
-            while (args--) {
-                vmsvga_fifo_read(s);
-            }
-            printf("%s: Unknown command 0x%02x in SVGA command FIFO\n",
-                   __func__, cmd);
-            break;
-
-        rewind:
-            s->cmd->stop = cmd_start;
-            break;
-        }
-    }
-
-    s->syncing = 0;
-}
-
-static uint32_t vmsvga_index_read(void *opaque, uint32_t address)
-{
-    struct vmsvga_state_s *s = opaque;
-
-    return s->index;
-}
-
-static void vmsvga_index_write(void *opaque, uint32_t address, uint32_t index)
-{
-    struct vmsvga_state_s *s = opaque;
-
-    s->index = index;
-}
-
-static uint32_t vmsvga_value_read(void *opaque, uint32_t address)
-{
-    uint32_t caps;
-    struct vmsvga_state_s *s = opaque;
-    DisplaySurface *surface = qemu_console_surface(s->vga.con);
-
-    switch (s->index) {
-    case SVGA_REG_ID:
-        return s->svgaid;
-
-    case SVGA_REG_ENABLE:
-        return s->enable;
-
-    case SVGA_REG_WIDTH:
-        return surface_width(surface);
-
-    case SVGA_REG_HEIGHT:
-        return surface_height(surface);
-
-    case SVGA_REG_MAX_WIDTH:
-        return SVGA_MAX_WIDTH;
-
-    case SVGA_REG_MAX_HEIGHT:
-        return SVGA_MAX_HEIGHT;
-
-    case SVGA_REG_DEPTH:
-        return s->depth;
-
-    case SVGA_REG_BITS_PER_PIXEL:
-        return (s->depth + 7) & ~7;
-
-    case SVGA_REG_PSEUDOCOLOR:
-        return 0x0;
-
-    case SVGA_REG_RED_MASK:
-        return surface->pf.rmask;
-
-    case SVGA_REG_GREEN_MASK:
-        return surface->pf.gmask;
-
-    case SVGA_REG_BLUE_MASK:
-        return surface->pf.bmask;
-
-    case SVGA_REG_BYTES_PER_LINE:
-        return s->bypp * s->new_width;
-
-    case SVGA_REG_FB_START: {
-        struct pci_vmsvga_state_s *pci_vmsvga
-            = container_of(s, struct pci_vmsvga_state_s, chip);
-        return pci_get_bar_addr(&pci_vmsvga->card, 1);
-    }
-
-    case SVGA_REG_FB_OFFSET:
-        return 0x0;
-
-    case SVGA_REG_VRAM_SIZE:
-        return s->vga.vram_size; /* No physical VRAM besides the framebuffer */
-
-    case SVGA_REG_FB_SIZE:
-        return s->vga.vram_size;
-
-    case SVGA_REG_CAPABILITIES:
-        caps = SVGA_CAP_NONE;
-#ifdef HW_RECT_ACCEL
-        caps |= SVGA_CAP_RECT_COPY;
-#endif
-#ifdef HW_FILL_ACCEL
-        caps |= SVGA_CAP_RECT_FILL;
-#endif
-#ifdef HW_MOUSE_ACCEL
-        if (dpy_cursor_define_supported(s->vga.con)) {
-            caps |= SVGA_CAP_CURSOR | SVGA_CAP_CURSOR_BYPASS_2 |
-                    SVGA_CAP_CURSOR_BYPASS;
-        }
-#endif
-        return caps;
-
-    case SVGA_REG_MEM_START: {
-        struct pci_vmsvga_state_s *pci_vmsvga
-            = container_of(s, struct pci_vmsvga_state_s, chip);
-        return pci_get_bar_addr(&pci_vmsvga->card, 2);
-    }
-
-    case SVGA_REG_MEM_SIZE:
-        return s->fifo_size;
-
-    case SVGA_REG_CONFIG_DONE:
-        return s->config;
-
-    case SVGA_REG_SYNC:
-    case SVGA_REG_BUSY:
-        return s->syncing;
-
-    case SVGA_REG_GUEST_ID:
-        return s->guest;
-
-    case SVGA_REG_CURSOR_ID:
-        return s->cursor.id;
-
-    case SVGA_REG_CURSOR_X:
-        return s->cursor.x;
-
-    case SVGA_REG_CURSOR_Y:
-        return s->cursor.x;
-
-    case SVGA_REG_CURSOR_ON:
-        return s->cursor.on;
-
-    case SVGA_REG_HOST_BITS_PER_PIXEL:
-        return (s->depth + 7) & ~7;
-
-    case SVGA_REG_SCRATCH_SIZE:
-        return s->scratch_size;
-
-    case SVGA_REG_MEM_REGS:
-    case SVGA_REG_NUM_DISPLAYS:
-    case SVGA_REG_PITCHLOCK:
-    case SVGA_PALETTE_BASE ... SVGA_PALETTE_END:
-        return 0;
-
-    default:
-        if (s->index >= SVGA_SCRATCH_BASE &&
-            s->index < SVGA_SCRATCH_BASE + s->scratch_size) {
-            return s->scratch[s->index - SVGA_SCRATCH_BASE];
-        }
-        printf("%s: Bad register %02x\n", __func__, s->index);
-    }
-
-    return 0;
-}
-
-static void vmsvga_value_write(void *opaque, uint32_t address, uint32_t value)
-{
-    struct vmsvga_state_s *s = opaque;
-
-    switch (s->index) {
-    case SVGA_REG_ID:
-        if (value == SVGA_ID_2 || value == SVGA_ID_1 || value == SVGA_ID_0) {
-            s->svgaid = value;
-        }
-        break;
-
-    case SVGA_REG_ENABLE:
-        s->enable = !!value;
-        s->invalidated = 1;
-        s->vga.invalidate(&s->vga);
-        if (s->enable && s->config) {
-            vga_dirty_log_stop(&s->vga);
-        } else {
-            vga_dirty_log_start(&s->vga);
-        }
-        break;
-
-    case SVGA_REG_WIDTH:
-        if (value <= SVGA_MAX_WIDTH) {
-            s->new_width = value;
-            s->invalidated = 1;
-        } else {
-            printf("%s: Bad width: %i\n", __func__, value);
-        }
-        break;
-
-    case SVGA_REG_HEIGHT:
-        if (value <= SVGA_MAX_HEIGHT) {
-            s->new_height = value;
-            s->invalidated = 1;
-        } else {
-            printf("%s: Bad height: %i\n", __func__, value);
-        }
-        break;
-
-    case SVGA_REG_BITS_PER_PIXEL:
-        if (value != s->depth) {
-            printf("%s: Bad bits per pixel: %i bits\n", __func__, value);
-            s->config = 0;
-        }
-        break;
-
-    case SVGA_REG_CONFIG_DONE:
-        if (value) {
-            s->fifo = (uint32_t *) s->fifo_ptr;
-            /* Check range and alignment.  */
-            if ((CMD(min) | CMD(max) | CMD(next_cmd) | CMD(stop)) & 3) {
-                break;
-            }
-            if (CMD(min) < (uint8_t *) s->cmd->fifo - (uint8_t *) s->fifo) {
-                break;
-            }
-            if (CMD(max) > SVGA_FIFO_SIZE) {
-                break;
-            }
-            if (CMD(max) < CMD(min) + 10 * 1024) {
-                break;
-            }
-            vga_dirty_log_stop(&s->vga);
-        }
-        s->config = !!value;
-        break;
-
-    case SVGA_REG_SYNC:
-        s->syncing = 1;
-        vmsvga_fifo_run(s); /* Or should we just wait for update_display? */
-        break;
-
-    case SVGA_REG_GUEST_ID:
-        s->guest = value;
-#ifdef VERBOSE
-        if (value >= GUEST_OS_BASE && value < GUEST_OS_BASE +
-            ARRAY_SIZE(vmsvga_guest_id)) {
-            printf("%s: guest runs %s.\n", __func__,
-                   vmsvga_guest_id[value - GUEST_OS_BASE]);
-        }
-#endif
-        break;
-
-    case SVGA_REG_CURSOR_ID:
-        s->cursor.id = value;
-        break;
-
-    case SVGA_REG_CURSOR_X:
-        s->cursor.x = value;
-        break;
-
-    case SVGA_REG_CURSOR_Y:
-        s->cursor.y = value;
-        break;
-
-    case SVGA_REG_CURSOR_ON:
-        s->cursor.on |= (value == SVGA_CURSOR_ON_SHOW);
-        s->cursor.on &= (value != SVGA_CURSOR_ON_HIDE);
-#ifdef HW_MOUSE_ACCEL
-        if (value <= SVGA_CURSOR_ON_SHOW) {
-            dpy_mouse_set(s->vga.con, s->cursor.x, s->cursor.y, s->cursor.on);
-        }
-#endif
-        break;
-
-    case SVGA_REG_DEPTH:
-    case SVGA_REG_MEM_REGS:
-    case SVGA_REG_NUM_DISPLAYS:
-    case SVGA_REG_PITCHLOCK:
-    case SVGA_PALETTE_BASE ... SVGA_PALETTE_END:
-        break;
-
-    default:
-        if (s->index >= SVGA_SCRATCH_BASE &&
-                s->index < SVGA_SCRATCH_BASE + s->scratch_size) {
-            s->scratch[s->index - SVGA_SCRATCH_BASE] = value;
-            break;
-        }
-        printf("%s: Bad register %02x\n", __func__, s->index);
-    }
-}
-
-static uint32_t vmsvga_bios_read(void *opaque, uint32_t address)
-{
-    printf("%s: what are we supposed to return?\n", __func__);
-    return 0xcafe;
-}
-
-static void vmsvga_bios_write(void *opaque, uint32_t address, uint32_t data)
-{
-    printf("%s: what are we supposed to do with (%08x)?\n", __func__, data);
-}
-
-static inline void vmsvga_check_size(struct vmsvga_state_s *s)
-{
-    DisplaySurface *surface = qemu_console_surface(s->vga.con);
-
-    if (s->new_width != surface_width(surface) ||
-        s->new_height != surface_height(surface)) {
-        qemu_console_resize(s->vga.con, s->new_width, s->new_height);
-        s->invalidated = 1;
-    }
-}
-
-static void vmsvga_update_display(void *opaque)
-{
-    struct vmsvga_state_s *s = opaque;
-    DisplaySurface *surface = qemu_console_surface(s->vga.con);
-    bool dirty = false;
-
-    if (!s->enable) {
-        s->vga.update(&s->vga);
-        return;
-    }
-
-    vmsvga_check_size(s);
-
-    vmsvga_fifo_run(s);
-    vmsvga_update_rect_flush(s);
-
-    /*
-     * Is it more efficient to look at vram VGA-dirty bits or wait
-     * for the driver to issue SVGA_CMD_UPDATE?
-     */
-    if (memory_region_is_logging(&s->vga.vram)) {
-        vga_sync_dirty_bitmap(&s->vga);
-        dirty = memory_region_get_dirty(&s->vga.vram, 0,
-            surface_stride(surface) * surface_height(surface),
-            DIRTY_MEMORY_VGA);
-    }
-    if (s->invalidated || dirty) {
-        s->invalidated = 0;
-        memcpy(surface_data(surface), s->vga.vram_ptr,
-               surface_stride(surface) * surface_height(surface));
-        dpy_gfx_update(s->vga.con, 0, 0,
-                   surface_width(surface), surface_height(surface));
-    }
-    if (dirty) {
-        memory_region_reset_dirty(&s->vga.vram, 0,
-            surface_stride(surface) * surface_height(surface),
-            DIRTY_MEMORY_VGA);
-    }
-}
-
-static void vmsvga_reset(DeviceState *dev)
-{
-    struct pci_vmsvga_state_s *pci =
-        DO_UPCAST(struct pci_vmsvga_state_s, card.qdev, dev);
-    struct vmsvga_state_s *s = &pci->chip;
-
-    s->index = 0;
-    s->enable = 0;
-    s->config = 0;
-    s->svgaid = SVGA_ID;
-    s->cursor.on = 0;
-    s->redraw_fifo_first = 0;
-    s->redraw_fifo_last = 0;
-    s->syncing = 0;
-
-    vga_dirty_log_start(&s->vga);
-}
-
-static void vmsvga_invalidate_display(void *opaque)
-{
-    struct vmsvga_state_s *s = opaque;
-    if (!s->enable) {
-        s->vga.invalidate(&s->vga);
-        return;
-    }
-
-    s->invalidated = 1;
-}
-
-/* save the vga display in a PPM image even if no display is
-   available */
-static void vmsvga_screen_dump(void *opaque, const char *filename, bool cswitch,
-                               Error **errp)
-{
-    struct vmsvga_state_s *s = opaque;
-    DisplaySurface *surface = qemu_console_surface(s->vga.con);
-
-    if (!s->enable) {
-        s->vga.screen_dump(&s->vga, filename, cswitch, errp);
-        return;
-    }
-
-    if (surface_bits_per_pixel(surface) == 32) {
-        DisplaySurface *ds = qemu_create_displaysurface_from(
-                                 surface_width(surface),
-                                 surface_height(surface),
-                                 32,
-                                 surface_stride(surface),
-                                 s->vga.vram_ptr, false);
-        ppm_save(filename, ds, errp);
-        g_free(ds);
-    }
-}
-
-static void vmsvga_text_update(void *opaque, console_ch_t *chardata)
-{
-    struct vmsvga_state_s *s = opaque;
-
-    if (s->vga.text_update) {
-        s->vga.text_update(&s->vga, chardata);
-    }
-}
-
-static int vmsvga_post_load(void *opaque, int version_id)
-{
-    struct vmsvga_state_s *s = opaque;
-
-    s->invalidated = 1;
-    if (s->config) {
-        s->fifo = (uint32_t *) s->fifo_ptr;
-    }
-    return 0;
-}
-
-static const VMStateDescription vmstate_vmware_vga_internal = {
-    .name = "vmware_vga_internal",
-    .version_id = 0,
-    .minimum_version_id = 0,
-    .minimum_version_id_old = 0,
-    .post_load = vmsvga_post_load,
-    .fields      = (VMStateField[]) {
-        VMSTATE_INT32_EQUAL(depth, struct vmsvga_state_s),
-        VMSTATE_INT32(enable, struct vmsvga_state_s),
-        VMSTATE_INT32(config, struct vmsvga_state_s),
-        VMSTATE_INT32(cursor.id, struct vmsvga_state_s),
-        VMSTATE_INT32(cursor.x, struct vmsvga_state_s),
-        VMSTATE_INT32(cursor.y, struct vmsvga_state_s),
-        VMSTATE_INT32(cursor.on, struct vmsvga_state_s),
-        VMSTATE_INT32(index, struct vmsvga_state_s),
-        VMSTATE_VARRAY_INT32(scratch, struct vmsvga_state_s,
-                             scratch_size, 0, vmstate_info_uint32, uint32_t),
-        VMSTATE_INT32(new_width, struct vmsvga_state_s),
-        VMSTATE_INT32(new_height, struct vmsvga_state_s),
-        VMSTATE_UINT32(guest, struct vmsvga_state_s),
-        VMSTATE_UINT32(svgaid, struct vmsvga_state_s),
-        VMSTATE_INT32(syncing, struct vmsvga_state_s),
-        VMSTATE_UNUSED(4), /* was fb_size */
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static const VMStateDescription vmstate_vmware_vga = {
-    .name = "vmware_vga",
-    .version_id = 0,
-    .minimum_version_id = 0,
-    .minimum_version_id_old = 0,
-    .fields      = (VMStateField[]) {
-        VMSTATE_PCI_DEVICE(card, struct pci_vmsvga_state_s),
-        VMSTATE_STRUCT(chip, struct pci_vmsvga_state_s, 0,
-                       vmstate_vmware_vga_internal, struct vmsvga_state_s),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void vmsvga_init(struct vmsvga_state_s *s,
-                        MemoryRegion *address_space, MemoryRegion *io)
-{
-    DisplaySurface *surface;
-
-    s->scratch_size = SVGA_SCRATCH_SIZE;
-    s->scratch = g_malloc(s->scratch_size * 4);
-
-    s->vga.con = graphic_console_init(vmsvga_update_display,
-                                      vmsvga_invalidate_display,
-                                      vmsvga_screen_dump,
-                                      vmsvga_text_update, s);
-    surface = qemu_console_surface(s->vga.con);
-
-    s->fifo_size = SVGA_FIFO_SIZE;
-    memory_region_init_ram(&s->fifo_ram, "vmsvga.fifo", s->fifo_size);
-    vmstate_register_ram_global(&s->fifo_ram);
-    s->fifo_ptr = memory_region_get_ram_ptr(&s->fifo_ram);
-
-    vga_common_init(&s->vga);
-    vga_init(&s->vga, address_space, io, true);
-    vmstate_register(NULL, 0, &vmstate_vga_common, &s->vga);
-    /* Save some values here in case they are changed later.
-     * This is suspicious and needs more though why it is needed. */
-    s->depth = surface_bits_per_pixel(surface);
-    s->bypp = surface_bytes_per_pixel(surface);
-}
-
-static uint64_t vmsvga_io_read(void *opaque, hwaddr addr, unsigned size)
-{
-    struct vmsvga_state_s *s = opaque;
-
-    switch (addr) {
-    case SVGA_IO_MUL * SVGA_INDEX_PORT: return vmsvga_index_read(s, addr);
-    case SVGA_IO_MUL * SVGA_VALUE_PORT: return vmsvga_value_read(s, addr);
-    case SVGA_IO_MUL * SVGA_BIOS_PORT: return vmsvga_bios_read(s, addr);
-    default: return -1u;
-    }
-}
-
-static void vmsvga_io_write(void *opaque, hwaddr addr,
-                            uint64_t data, unsigned size)
-{
-    struct vmsvga_state_s *s = opaque;
-
-    switch (addr) {
-    case SVGA_IO_MUL * SVGA_INDEX_PORT:
-        vmsvga_index_write(s, addr, data);
-        break;
-    case SVGA_IO_MUL * SVGA_VALUE_PORT:
-        vmsvga_value_write(s, addr, data);
-        break;
-    case SVGA_IO_MUL * SVGA_BIOS_PORT:
-        vmsvga_bios_write(s, addr, data);
-        break;
-    }
-}
-
-static const MemoryRegionOps vmsvga_io_ops = {
-    .read = vmsvga_io_read,
-    .write = vmsvga_io_write,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-};
-
-static int pci_vmsvga_initfn(PCIDevice *dev)
-{
-    struct pci_vmsvga_state_s *s =
-        DO_UPCAST(struct pci_vmsvga_state_s, card, dev);
-
-    s->card.config[PCI_CACHE_LINE_SIZE] = 0x08;         /* Cache line size */
-    s->card.config[PCI_LATENCY_TIMER] = 0x40;           /* Latency timer */
-    s->card.config[PCI_INTERRUPT_LINE] = 0xff;          /* End */
-
-    memory_region_init_io(&s->io_bar, &vmsvga_io_ops, &s->chip,
-                          "vmsvga-io", 0x10);
-    memory_region_set_flush_coalesced(&s->io_bar);
-    pci_register_bar(&s->card, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io_bar);
-
-    vmsvga_init(&s->chip, pci_address_space(dev), pci_address_space_io(dev));
-
-    pci_register_bar(&s->card, 1, PCI_BASE_ADDRESS_MEM_PREFETCH,
-                     &s->chip.vga.vram);
-    pci_register_bar(&s->card, 2, PCI_BASE_ADDRESS_MEM_PREFETCH,
-                     &s->chip.fifo_ram);
-
-    if (!dev->rom_bar) {
-        /* compatibility with pc-0.13 and older */
-        vga_init_vbe(&s->chip.vga, pci_address_space(dev));
-    }
-
-    return 0;
-}
-
-static Property vga_vmware_properties[] = {
-    DEFINE_PROP_UINT32("vgamem_mb", struct pci_vmsvga_state_s,
-                       chip.vga.vram_size_mb, 16),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void vmsvga_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
-    k->no_hotplug = 1;
-    k->init = pci_vmsvga_initfn;
-    k->romfile = "vgabios-vmware.bin";
-    k->vendor_id = PCI_VENDOR_ID_VMWARE;
-    k->device_id = SVGA_PCI_DEVICE_ID;
-    k->class_id = PCI_CLASS_DISPLAY_VGA;
-    k->subsystem_vendor_id = PCI_VENDOR_ID_VMWARE;
-    k->subsystem_id = SVGA_PCI_DEVICE_ID;
-    dc->reset = vmsvga_reset;
-    dc->vmsd = &vmstate_vmware_vga;
-    dc->props = vga_vmware_properties;
-}
-
-static const 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_types(void)
-{
-    type_register_static(&vmsvga_info);
-}
-
-type_init(vmsvga_register_types)
diff --git a/hw/vmxnet3.c b/hw/vmxnet3.c
deleted file mode 100644 (file)
index bdd256e..0000000
+++ /dev/null
@@ -1,2461 +0,0 @@
-/*
- * QEMU VMWARE VMXNET3 paravirtual NIC
- *
- * Copyright (c) 2012 Ravello Systems LTD (http://ravellosystems.com)
- *
- * Developed by Daynix Computing LTD (http://www.daynix.com)
- *
- * Authors:
- * Dmitry Fleytman <dmitry@daynix.com>
- * Tamir Shomer <tamirs@daynix.com>
- * Yan Vugenfirer <yan@daynix.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.h"
-#include "pci/pci.h"
-#include "net/net.h"
-#include "virtio-net.h"
-#include "net/tap.h"
-#include "net/checksum.h"
-#include "sysemu/sysemu.h"
-#include "qemu-common.h"
-#include "qemu/bswap.h"
-#include "pci/msix.h"
-#include "pci/msi.h"
-
-#include "vmxnet3.h"
-#include "vmxnet_debug.h"
-#include "vmware_utils.h"
-#include "vmxnet_tx_pkt.h"
-#include "vmxnet_rx_pkt.h"
-
-#define PCI_DEVICE_ID_VMWARE_VMXNET3_REVISION 0x1
-#define VMXNET3_MSIX_BAR_SIZE 0x2000
-
-#define VMXNET3_BAR0_IDX      (0)
-#define VMXNET3_BAR1_IDX      (1)
-#define VMXNET3_MSIX_BAR_IDX  (2)
-
-#define VMXNET3_OFF_MSIX_TABLE (0x000)
-#define VMXNET3_OFF_MSIX_PBA   (0x800)
-
-/* Link speed in Mbps should be shifted by 16 */
-#define VMXNET3_LINK_SPEED      (1000 << 16)
-
-/* Link status: 1 - up, 0 - down. */
-#define VMXNET3_LINK_STATUS_UP  0x1
-
-/* Least significant bit should be set for revision and version */
-#define VMXNET3_DEVICE_VERSION    0x1
-#define VMXNET3_DEVICE_REVISION   0x1
-
-/* Macros for rings descriptors access */
-#define VMXNET3_READ_TX_QUEUE_DESCR8(dpa, field) \
-    (vmw_shmem_ld8(dpa + offsetof(struct Vmxnet3_TxQueueDesc, field)))
-
-#define VMXNET3_WRITE_TX_QUEUE_DESCR8(dpa, field, value) \
-    (vmw_shmem_st8(dpa + offsetof(struct Vmxnet3_TxQueueDesc, field, value)))
-
-#define VMXNET3_READ_TX_QUEUE_DESCR32(dpa, field) \
-    (vmw_shmem_ld32(dpa + offsetof(struct Vmxnet3_TxQueueDesc, field)))
-
-#define VMXNET3_WRITE_TX_QUEUE_DESCR32(dpa, field, value) \
-    (vmw_shmem_st32(dpa + offsetof(struct Vmxnet3_TxQueueDesc, field), value))
-
-#define VMXNET3_READ_TX_QUEUE_DESCR64(dpa, field) \
-    (vmw_shmem_ld64(dpa + offsetof(struct Vmxnet3_TxQueueDesc, field)))
-
-#define VMXNET3_WRITE_TX_QUEUE_DESCR64(dpa, field, value) \
-    (vmw_shmem_st64(dpa + offsetof(struct Vmxnet3_TxQueueDesc, field), value))
-
-#define VMXNET3_READ_RX_QUEUE_DESCR64(dpa, field) \
-    (vmw_shmem_ld64(dpa + offsetof(struct Vmxnet3_RxQueueDesc, field)))
-
-#define VMXNET3_READ_RX_QUEUE_DESCR32(dpa, field) \
-    (vmw_shmem_ld32(dpa + offsetof(struct Vmxnet3_RxQueueDesc, field)))
-
-#define VMXNET3_WRITE_RX_QUEUE_DESCR64(dpa, field, value) \
-    (vmw_shmem_st64(dpa + offsetof(struct Vmxnet3_RxQueueDesc, field), value))
-
-#define VMXNET3_WRITE_RX_QUEUE_DESCR8(dpa, field, value) \
-    (vmw_shmem_st8(dpa + offsetof(struct Vmxnet3_RxQueueDesc, field), value))
-
-/* Macros for guest driver shared area access */
-#define VMXNET3_READ_DRV_SHARED64(shpa, field) \
-    (vmw_shmem_ld64(shpa + offsetof(struct Vmxnet3_DriverShared, field)))
-
-#define VMXNET3_READ_DRV_SHARED32(shpa, field) \
-    (vmw_shmem_ld32(shpa + offsetof(struct Vmxnet3_DriverShared, field)))
-
-#define VMXNET3_WRITE_DRV_SHARED32(shpa, field, val) \
-    (vmw_shmem_st32(shpa + offsetof(struct Vmxnet3_DriverShared, field), val))
-
-#define VMXNET3_READ_DRV_SHARED16(shpa, field) \
-    (vmw_shmem_ld16(shpa + offsetof(struct Vmxnet3_DriverShared, field)))
-
-#define VMXNET3_READ_DRV_SHARED8(shpa, field) \
-    (vmw_shmem_ld8(shpa + offsetof(struct Vmxnet3_DriverShared, field)))
-
-#define VMXNET3_READ_DRV_SHARED(shpa, field, b, l) \
-    (vmw_shmem_read(shpa + offsetof(struct Vmxnet3_DriverShared, field), b, l))
-
-#define VMXNET_FLAG_IS_SET(field, flag) (((field) & (flag)) == (flag))
-
-#define TYPE_VMXNET3 "vmxnet3"
-#define VMXNET3(obj) OBJECT_CHECK(VMXNET3State, (obj), TYPE_VMXNET3)
-
-/* Cyclic ring abstraction */
-typedef struct {
-    hwaddr pa;
-    size_t size;
-    size_t cell_size;
-    size_t next;
-    uint8_t gen;
-} Vmxnet3Ring;
-
-static inline void vmxnet3_ring_init(Vmxnet3Ring *ring,
-                                     hwaddr pa,
-                                     size_t size,
-                                     size_t cell_size,
-                                     bool zero_region)
-{
-    ring->pa = pa;
-    ring->size = size;
-    ring->cell_size = cell_size;
-    ring->gen = VMXNET3_INIT_GEN;
-    ring->next = 0;
-
-    if (zero_region) {
-        vmw_shmem_set(pa, 0, size * cell_size);
-    }
-}
-
-#define VMXNET3_RING_DUMP(macro, ring_name, ridx, r)                         \
-    macro("%s#%d: base %" PRIx64 " size %lu cell_size %lu gen %d next %lu",  \
-          (ring_name), (ridx),                                               \
-          (r)->pa, (r)->size, (r)->cell_size, (r)->gen, (r)->next)
-
-static inline void vmxnet3_ring_inc(Vmxnet3Ring *ring)
-{
-    if (++ring->next >= ring->size) {
-        ring->next = 0;
-        ring->gen ^= 1;
-    }
-}
-
-static inline void vmxnet3_ring_dec(Vmxnet3Ring *ring)
-{
-    if (ring->next-- == 0) {
-        ring->next = ring->size - 1;
-        ring->gen ^= 1;
-    }
-}
-
-static inline hwaddr vmxnet3_ring_curr_cell_pa(Vmxnet3Ring *ring)
-{
-    return ring->pa + ring->next * ring->cell_size;
-}
-
-static inline void vmxnet3_ring_read_curr_cell(Vmxnet3Ring *ring, void *buff)
-{
-    vmw_shmem_read(vmxnet3_ring_curr_cell_pa(ring), buff, ring->cell_size);
-}
-
-static inline void vmxnet3_ring_write_curr_cell(Vmxnet3Ring *ring, void *buff)
-{
-    vmw_shmem_write(vmxnet3_ring_curr_cell_pa(ring), buff, ring->cell_size);
-}
-
-static inline size_t vmxnet3_ring_curr_cell_idx(Vmxnet3Ring *ring)
-{
-    return ring->next;
-}
-
-static inline uint8_t vmxnet3_ring_curr_gen(Vmxnet3Ring *ring)
-{
-    return ring->gen;
-}
-
-/* Debug trace-related functions */
-static inline void
-vmxnet3_dump_tx_descr(struct Vmxnet3_TxDesc *descr)
-{
-    VMW_PKPRN("TX DESCR: "
-              "addr %" PRIx64 ", len: %d, gen: %d, rsvd: %d, "
-              "dtype: %d, ext1: %d, msscof: %d, hlen: %d, om: %d, "
-              "eop: %d, cq: %d, ext2: %d, ti: %d, tci: %d",
-              le64_to_cpu(descr->addr), descr->len, descr->gen, descr->rsvd,
-              descr->dtype, descr->ext1, descr->msscof, descr->hlen, descr->om,
-              descr->eop, descr->cq, descr->ext2, descr->ti, descr->tci);
-}
-
-static inline void
-vmxnet3_dump_virt_hdr(struct virtio_net_hdr *vhdr)
-{
-    VMW_PKPRN("VHDR: flags 0x%x, gso_type: 0x%x, hdr_len: %d, gso_size: %d, "
-              "csum_start: %d, csum_offset: %d",
-              vhdr->flags, vhdr->gso_type, vhdr->hdr_len, vhdr->gso_size,
-              vhdr->csum_start, vhdr->csum_offset);
-}
-
-static inline void
-vmxnet3_dump_rx_descr(struct Vmxnet3_RxDesc *descr)
-{
-    VMW_PKPRN("RX DESCR: addr %" PRIx64 ", len: %d, gen: %d, rsvd: %d, "
-              "dtype: %d, ext1: %d, btype: %d",
-              le64_to_cpu(descr->addr), descr->len, descr->gen,
-              descr->rsvd, descr->dtype, descr->ext1, descr->btype);
-}
-
-/* Device state and helper functions */
-#define VMXNET3_RX_RINGS_PER_QUEUE (2)
-
-typedef struct {
-    Vmxnet3Ring tx_ring;
-    Vmxnet3Ring comp_ring;
-
-    uint8_t intr_idx;
-    hwaddr tx_stats_pa;
-    struct UPT1_TxStats txq_stats;
-} Vmxnet3TxqDescr;
-
-typedef struct {
-    Vmxnet3Ring rx_ring[VMXNET3_RX_RINGS_PER_QUEUE];
-    Vmxnet3Ring comp_ring;
-    uint8_t intr_idx;
-    hwaddr rx_stats_pa;
-    struct UPT1_RxStats rxq_stats;
-} Vmxnet3RxqDescr;
-
-typedef struct {
-    bool is_masked;
-    bool is_pending;
-    bool is_asserted;
-} Vmxnet3IntState;
-
-typedef struct {
-        PCIDevice parent_obj;
-        NICState *nic;
-        NICConf conf;
-        MemoryRegion bar0;
-        MemoryRegion bar1;
-        MemoryRegion msix_bar;
-
-        Vmxnet3RxqDescr rxq_descr[VMXNET3_DEVICE_MAX_RX_QUEUES];
-        Vmxnet3TxqDescr txq_descr[VMXNET3_DEVICE_MAX_TX_QUEUES];
-
-        /* Whether MSI-X support was installed successfully */
-        bool msix_used;
-        /* Whether MSI support was installed successfully */
-        bool msi_used;
-        hwaddr drv_shmem;
-        hwaddr temp_shared_guest_driver_memory;
-
-        uint8_t txq_num;
-
-        /* This boolean tells whether RX packet being indicated has to */
-        /* be split into head and body chunks from different RX rings  */
-        bool rx_packets_compound;
-
-        bool rx_vlan_stripping;
-        bool lro_supported;
-
-        uint8_t rxq_num;
-
-        /* Network MTU */
-        uint32_t mtu;
-
-        /* Maximum number of fragments for indicated TX packets */
-        uint32_t max_tx_frags;
-
-        /* Maximum number of fragments for indicated RX packets */
-        uint16_t max_rx_frags;
-
-        /* Index for events interrupt */
-        uint8_t event_int_idx;
-
-        /* Whether automatic interrupts masking enabled */
-        bool auto_int_masking;
-
-        bool peer_has_vhdr;
-
-        /* TX packets to QEMU interface */
-        struct VmxnetTxPkt *tx_pkt;
-        uint32_t offload_mode;
-        uint32_t cso_or_gso_size;
-        uint16_t tci;
-        bool needs_vlan;
-
-        struct VmxnetRxPkt *rx_pkt;
-
-        bool tx_sop;
-        bool skip_current_tx_pkt;
-
-        uint32_t device_active;
-        uint32_t last_command;
-
-        uint32_t link_status_and_speed;
-
-        Vmxnet3IntState interrupt_states[VMXNET3_MAX_INTRS];
-
-        uint32_t temp_mac;   /* To store the low part first */
-
-        MACAddr perm_mac;
-        uint32_t vlan_table[VMXNET3_VFT_SIZE];
-        uint32_t rx_mode;
-        MACAddr *mcast_list;
-        uint32_t mcast_list_len;
-        uint32_t mcast_list_buff_size; /* needed for live migration. */
-} VMXNET3State;
-
-/* Interrupt management */
-
-/*
- *This function returns sign whether interrupt line is in asserted state
- * This depends on the type of interrupt used. For INTX interrupt line will
- * be asserted until explicit deassertion, for MSI(X) interrupt line will
- * be deasserted automatically due to notification semantics of the MSI(X)
- * interrupts
- */
-static bool _vmxnet3_assert_interrupt_line(VMXNET3State *s, uint32_t int_idx)
-{
-    PCIDevice *d = PCI_DEVICE(s);
-
-    if (s->msix_used && msix_enabled(d)) {
-        VMW_IRPRN("Sending MSI-X notification for vector %u", int_idx);
-        msix_notify(d, int_idx);
-        return false;
-    }
-    if (s->msi_used && msi_enabled(d)) {
-        VMW_IRPRN("Sending MSI notification for vector %u", int_idx);
-        msi_notify(d, int_idx);
-        return false;
-    }
-
-    VMW_IRPRN("Asserting line for interrupt %u", int_idx);
-    qemu_set_irq(d->irq[int_idx], 1);
-    return true;
-}
-
-static void _vmxnet3_deassert_interrupt_line(VMXNET3State *s, int lidx)
-{
-    PCIDevice *d = PCI_DEVICE(s);
-
-    /*
-     * This function should never be called for MSI(X) interrupts
-     * because deassertion never required for message interrupts
-     */
-    assert(!s->msix_used || !msix_enabled(d));
-    /*
-     * This function should never be called for MSI(X) interrupts
-     * because deassertion never required for message interrupts
-     */
-    assert(!s->msi_used || !msi_enabled(d));
-
-    VMW_IRPRN("Deasserting line for interrupt %u", lidx);
-    qemu_set_irq(d->irq[lidx], 0);
-}
-
-static void vmxnet3_update_interrupt_line_state(VMXNET3State *s, int lidx)
-{
-    if (!s->interrupt_states[lidx].is_pending &&
-       s->interrupt_states[lidx].is_asserted) {
-        VMW_IRPRN("New interrupt line state for index %d is DOWN", lidx);
-        _vmxnet3_deassert_interrupt_line(s, lidx);
-        s->interrupt_states[lidx].is_asserted = false;
-        return;
-    }
-
-    if (s->interrupt_states[lidx].is_pending &&
-       !s->interrupt_states[lidx].is_masked &&
-       !s->interrupt_states[lidx].is_asserted) {
-        VMW_IRPRN("New interrupt line state for index %d is UP", lidx);
-        s->interrupt_states[lidx].is_asserted =
-            _vmxnet3_assert_interrupt_line(s, lidx);
-        s->interrupt_states[lidx].is_pending = false;
-        return;
-    }
-}
-
-static void vmxnet3_trigger_interrupt(VMXNET3State *s, int lidx)
-{
-    PCIDevice *d = PCI_DEVICE(s);
-    s->interrupt_states[lidx].is_pending = true;
-    vmxnet3_update_interrupt_line_state(s, lidx);
-
-    if (s->msix_used && msix_enabled(d) && s->auto_int_masking) {
-        goto do_automask;
-    }
-
-    if (s->msi_used && msi_enabled(d) && s->auto_int_masking) {
-        goto do_automask;
-    }
-
-    return;
-
-do_automask:
-    s->interrupt_states[lidx].is_masked = true;
-    vmxnet3_update_interrupt_line_state(s, lidx);
-}
-
-static bool vmxnet3_interrupt_asserted(VMXNET3State *s, int lidx)
-{
-    return s->interrupt_states[lidx].is_asserted;
-}
-
-static void vmxnet3_clear_interrupt(VMXNET3State *s, int int_idx)
-{
-    s->interrupt_states[int_idx].is_pending = false;
-    if (s->auto_int_masking) {
-        s->interrupt_states[int_idx].is_masked = true;
-    }
-    vmxnet3_update_interrupt_line_state(s, int_idx);
-}
-
-static void
-vmxnet3_on_interrupt_mask_changed(VMXNET3State *s, int lidx, bool is_masked)
-{
-    s->interrupt_states[lidx].is_masked = is_masked;
-    vmxnet3_update_interrupt_line_state(s, lidx);
-}
-
-static bool vmxnet3_verify_driver_magic(hwaddr dshmem)
-{
-    return (VMXNET3_READ_DRV_SHARED32(dshmem, magic) == VMXNET3_REV1_MAGIC);
-}
-
-#define VMXNET3_GET_BYTE(x, byte_num) (((x) >> (byte_num)*8) & 0xFF)
-#define VMXNET3_MAKE_BYTE(byte_num, val) \
-    (((uint32_t)((val) & 0xFF)) << (byte_num)*8)
-
-static void vmxnet3_set_variable_mac(VMXNET3State *s, uint32_t h, uint32_t l)
-{
-    s->conf.macaddr.a[0] = VMXNET3_GET_BYTE(l,  0);
-    s->conf.macaddr.a[1] = VMXNET3_GET_BYTE(l,  1);
-    s->conf.macaddr.a[2] = VMXNET3_GET_BYTE(l,  2);
-    s->conf.macaddr.a[3] = VMXNET3_GET_BYTE(l,  3);
-    s->conf.macaddr.a[4] = VMXNET3_GET_BYTE(h, 0);
-    s->conf.macaddr.a[5] = VMXNET3_GET_BYTE(h, 1);
-
-    VMW_CFPRN("Variable MAC: " VMXNET_MF, VMXNET_MA(s->conf.macaddr.a));
-
-    qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
-}
-
-static uint64_t vmxnet3_get_mac_low(MACAddr *addr)
-{
-    return VMXNET3_MAKE_BYTE(0, addr->a[0]) |
-           VMXNET3_MAKE_BYTE(1, addr->a[1]) |
-           VMXNET3_MAKE_BYTE(2, addr->a[2]) |
-           VMXNET3_MAKE_BYTE(3, addr->a[3]);
-}
-
-static uint64_t vmxnet3_get_mac_high(MACAddr *addr)
-{
-    return VMXNET3_MAKE_BYTE(0, addr->a[4]) |
-           VMXNET3_MAKE_BYTE(1, addr->a[5]);
-}
-
-static void
-vmxnet3_inc_tx_consumption_counter(VMXNET3State *s, int qidx)
-{
-    vmxnet3_ring_inc(&s->txq_descr[qidx].tx_ring);
-}
-
-static inline void
-vmxnet3_inc_rx_consumption_counter(VMXNET3State *s, int qidx, int ridx)
-{
-    vmxnet3_ring_inc(&s->rxq_descr[qidx].rx_ring[ridx]);
-}
-
-static inline void
-vmxnet3_inc_tx_completion_counter(VMXNET3State *s, int qidx)
-{
-    vmxnet3_ring_inc(&s->txq_descr[qidx].comp_ring);
-}
-
-static void
-vmxnet3_inc_rx_completion_counter(VMXNET3State *s, int qidx)
-{
-    vmxnet3_ring_inc(&s->rxq_descr[qidx].comp_ring);
-}
-
-static void
-vmxnet3_dec_rx_completion_counter(VMXNET3State *s, int qidx)
-{
-    vmxnet3_ring_dec(&s->rxq_descr[qidx].comp_ring);
-}
-
-static void vmxnet3_complete_packet(VMXNET3State *s, int qidx, uint32 tx_ridx)
-{
-    struct Vmxnet3_TxCompDesc txcq_descr;
-
-    VMXNET3_RING_DUMP(VMW_RIPRN, "TXC", qidx, &s->txq_descr[qidx].comp_ring);
-
-    txcq_descr.txdIdx = tx_ridx;
-    txcq_descr.gen = vmxnet3_ring_curr_gen(&s->txq_descr[qidx].comp_ring);
-
-    vmxnet3_ring_write_curr_cell(&s->txq_descr[qidx].comp_ring, &txcq_descr);
-
-    /* Flush changes in TX descriptor before changing the counter value */
-    smp_wmb();
-
-    vmxnet3_inc_tx_completion_counter(s, qidx);
-    vmxnet3_trigger_interrupt(s, s->txq_descr[qidx].intr_idx);
-}
-
-static bool
-vmxnet3_setup_tx_offloads(VMXNET3State *s)
-{
-    switch (s->offload_mode) {
-    case VMXNET3_OM_NONE:
-        vmxnet_tx_pkt_build_vheader(s->tx_pkt, false, false, 0);
-        break;
-
-    case VMXNET3_OM_CSUM:
-        vmxnet_tx_pkt_build_vheader(s->tx_pkt, false, true, 0);
-        VMW_PKPRN("L4 CSO requested\n");
-        break;
-
-    case VMXNET3_OM_TSO:
-        vmxnet_tx_pkt_build_vheader(s->tx_pkt, true, true,
-            s->cso_or_gso_size);
-        vmxnet_tx_pkt_update_ip_checksums(s->tx_pkt);
-        VMW_PKPRN("GSO offload requested.");
-        break;
-
-    default:
-        assert(false);
-        return false;
-    }
-
-    return true;
-}
-
-static void
-vmxnet3_tx_retrieve_metadata(VMXNET3State *s,
-                             const struct Vmxnet3_TxDesc *txd)
-{
-    s->offload_mode = txd->om;
-    s->cso_or_gso_size = txd->msscof;
-    s->tci = txd->tci;
-    s->needs_vlan = txd->ti;
-}
-
-typedef enum {
-    VMXNET3_PKT_STATUS_OK,
-    VMXNET3_PKT_STATUS_ERROR,
-    VMXNET3_PKT_STATUS_DISCARD,/* only for tx */
-    VMXNET3_PKT_STATUS_OUT_OF_BUF /* only for rx */
-} Vmxnet3PktStatus;
-
-static void
-vmxnet3_on_tx_done_update_stats(VMXNET3State *s, int qidx,
-    Vmxnet3PktStatus status)
-{
-    size_t tot_len = vmxnet_tx_pkt_get_total_len(s->tx_pkt);
-    struct UPT1_TxStats *stats = &s->txq_descr[qidx].txq_stats;
-
-    switch (status) {
-    case VMXNET3_PKT_STATUS_OK:
-        switch (vmxnet_tx_pkt_get_packet_type(s->tx_pkt)) {
-        case ETH_PKT_BCAST:
-            stats->bcastPktsTxOK++;
-            stats->bcastBytesTxOK += tot_len;
-            break;
-        case ETH_PKT_MCAST:
-            stats->mcastPktsTxOK++;
-            stats->mcastBytesTxOK += tot_len;
-            break;
-        case ETH_PKT_UCAST:
-            stats->ucastPktsTxOK++;
-            stats->ucastBytesTxOK += tot_len;
-            break;
-        default:
-            assert(false);
-        }
-
-        if (s->offload_mode == VMXNET3_OM_TSO) {
-            /*
-             * According to VMWARE headers this statistic is a number
-             * of packets after segmentation but since we don't have
-             * this information in QEMU model, the best we can do is to
-             * provide number of non-segmented packets
-             */
-            stats->TSOPktsTxOK++;
-            stats->TSOBytesTxOK += tot_len;
-        }
-        break;
-
-    case VMXNET3_PKT_STATUS_DISCARD:
-        stats->pktsTxDiscard++;
-        break;
-
-    case VMXNET3_PKT_STATUS_ERROR:
-        stats->pktsTxError++;
-        break;
-
-    default:
-        assert(false);
-    }
-}
-
-static void
-vmxnet3_on_rx_done_update_stats(VMXNET3State *s,
-                                int qidx,
-                                Vmxnet3PktStatus status)
-{
-    struct UPT1_RxStats *stats = &s->rxq_descr[qidx].rxq_stats;
-    size_t tot_len = vmxnet_rx_pkt_get_total_len(s->rx_pkt);
-
-    switch (status) {
-    case VMXNET3_PKT_STATUS_OUT_OF_BUF:
-        stats->pktsRxOutOfBuf++;
-        break;
-
-    case VMXNET3_PKT_STATUS_ERROR:
-        stats->pktsRxError++;
-        break;
-    case VMXNET3_PKT_STATUS_OK:
-        switch (vmxnet_rx_pkt_get_packet_type(s->rx_pkt)) {
-        case ETH_PKT_BCAST:
-            stats->bcastPktsRxOK++;
-            stats->bcastBytesRxOK += tot_len;
-            break;
-        case ETH_PKT_MCAST:
-            stats->mcastPktsRxOK++;
-            stats->mcastBytesRxOK += tot_len;
-            break;
-        case ETH_PKT_UCAST:
-            stats->ucastPktsRxOK++;
-            stats->ucastBytesRxOK += tot_len;
-            break;
-        default:
-            assert(false);
-        }
-
-        if (tot_len > s->mtu) {
-            stats->LROPktsRxOK++;
-            stats->LROBytesRxOK += tot_len;
-        }
-        break;
-    default:
-        assert(false);
-    }
-}
-
-static inline bool
-vmxnet3_pop_next_tx_descr(VMXNET3State *s,
-                          int qidx,
-                          struct Vmxnet3_TxDesc *txd,
-                          uint32_t *descr_idx)
-{
-    Vmxnet3Ring *ring = &s->txq_descr[qidx].tx_ring;
-
-    vmxnet3_ring_read_curr_cell(ring, txd);
-    if (txd->gen == vmxnet3_ring_curr_gen(ring)) {
-        /* Only read after generation field verification */
-        smp_rmb();
-        /* Re-read to be sure we got the latest version */
-        vmxnet3_ring_read_curr_cell(ring, txd);
-        VMXNET3_RING_DUMP(VMW_RIPRN, "TX", qidx, ring);
-        *descr_idx = vmxnet3_ring_curr_cell_idx(ring);
-        vmxnet3_inc_tx_consumption_counter(s, qidx);
-        return true;
-    }
-
-    return false;
-}
-
-static bool
-vmxnet3_send_packet(VMXNET3State *s, uint32_t qidx)
-{
-    Vmxnet3PktStatus status = VMXNET3_PKT_STATUS_OK;
-
-    if (!vmxnet3_setup_tx_offloads(s)) {
-        status = VMXNET3_PKT_STATUS_ERROR;
-        goto func_exit;
-    }
-
-    /* debug prints */
-    vmxnet3_dump_virt_hdr(vmxnet_tx_pkt_get_vhdr(s->tx_pkt));
-    vmxnet_tx_pkt_dump(s->tx_pkt);
-
-    if (!vmxnet_tx_pkt_send(s->tx_pkt, qemu_get_queue(s->nic))) {
-        status = VMXNET3_PKT_STATUS_DISCARD;
-        goto func_exit;
-    }
-
-func_exit:
-    vmxnet3_on_tx_done_update_stats(s, qidx, status);
-    return (status == VMXNET3_PKT_STATUS_OK);
-}
-
-static void vmxnet3_process_tx_queue(VMXNET3State *s, int qidx)
-{
-    struct Vmxnet3_TxDesc txd;
-    uint32_t txd_idx;
-    uint32_t data_len;
-    hwaddr data_pa;
-
-    for (;;) {
-        if (!vmxnet3_pop_next_tx_descr(s, qidx, &txd, &txd_idx)) {
-            break;
-        }
-
-        vmxnet3_dump_tx_descr(&txd);
-
-        if (!s->skip_current_tx_pkt) {
-            data_len = (txd.len > 0) ? txd.len : VMXNET3_MAX_TX_BUF_SIZE;
-            data_pa = le64_to_cpu(txd.addr);
-
-            if (!vmxnet_tx_pkt_add_raw_fragment(s->tx_pkt,
-                                                data_pa,
-                                                data_len)) {
-                s->skip_current_tx_pkt = true;
-            }
-        }
-
-        if (s->tx_sop) {
-            vmxnet3_tx_retrieve_metadata(s, &txd);
-            s->tx_sop = false;
-        }
-
-        if (txd.eop) {
-            if (!s->skip_current_tx_pkt) {
-                vmxnet_tx_pkt_parse(s->tx_pkt);
-
-                if (s->needs_vlan) {
-                    vmxnet_tx_pkt_setup_vlan_header(s->tx_pkt, s->tci);
-                }
-
-                vmxnet3_send_packet(s, qidx);
-            } else {
-                vmxnet3_on_tx_done_update_stats(s, qidx,
-                                                VMXNET3_PKT_STATUS_ERROR);
-            }
-
-            vmxnet3_complete_packet(s, qidx, txd_idx);
-            s->tx_sop = true;
-            s->skip_current_tx_pkt = false;
-            vmxnet_tx_pkt_reset(s->tx_pkt);
-        }
-    }
-}
-
-static inline void
-vmxnet3_read_next_rx_descr(VMXNET3State *s, int qidx, int ridx,
-                           struct Vmxnet3_RxDesc *dbuf, uint32_t *didx)
-{
-    Vmxnet3Ring *ring = &s->rxq_descr[qidx].rx_ring[ridx];
-    *didx = vmxnet3_ring_curr_cell_idx(ring);
-    vmxnet3_ring_read_curr_cell(ring, dbuf);
-}
-
-static inline uint8_t
-vmxnet3_get_rx_ring_gen(VMXNET3State *s, int qidx, int ridx)
-{
-    return s->rxq_descr[qidx].rx_ring[ridx].gen;
-}
-
-static inline hwaddr
-vmxnet3_pop_rxc_descr(VMXNET3State *s, int qidx, uint32_t *descr_gen)
-{
-    uint8_t ring_gen;
-    struct Vmxnet3_RxCompDesc rxcd;
-
-    hwaddr daddr =
-        vmxnet3_ring_curr_cell_pa(&s->rxq_descr[qidx].comp_ring);
-
-    cpu_physical_memory_read(daddr, &rxcd, sizeof(struct Vmxnet3_RxCompDesc));
-    ring_gen = vmxnet3_ring_curr_gen(&s->rxq_descr[qidx].comp_ring);
-
-    if (rxcd.gen != ring_gen) {
-        *descr_gen = ring_gen;
-        vmxnet3_inc_rx_completion_counter(s, qidx);
-        return daddr;
-    }
-
-    return 0;
-}
-
-static inline void
-vmxnet3_revert_rxc_descr(VMXNET3State *s, int qidx)
-{
-    vmxnet3_dec_rx_completion_counter(s, qidx);
-}
-
-#define RXQ_IDX      (0)
-#define RX_HEAD_BODY_RING (0)
-#define RX_BODY_ONLY_RING (1)
-
-static bool
-vmxnet3_get_next_head_rx_descr(VMXNET3State *s,
-                               struct Vmxnet3_RxDesc *descr_buf,
-                               uint32_t *descr_idx,
-                               uint32_t *ridx)
-{
-    for (;;) {
-        uint32_t ring_gen;
-        vmxnet3_read_next_rx_descr(s, RXQ_IDX, RX_HEAD_BODY_RING,
-                                   descr_buf, descr_idx);
-
-        /* If no more free descriptors - return */
-        ring_gen = vmxnet3_get_rx_ring_gen(s, RXQ_IDX, RX_HEAD_BODY_RING);
-        if (descr_buf->gen != ring_gen) {
-            return false;
-        }
-
-        /* Only read after generation field verification */
-        smp_rmb();
-        /* Re-read to be sure we got the latest version */
-        vmxnet3_read_next_rx_descr(s, RXQ_IDX, RX_HEAD_BODY_RING,
-                                   descr_buf, descr_idx);
-
-        /* Mark current descriptor as used/skipped */
-        vmxnet3_inc_rx_consumption_counter(s, RXQ_IDX, RX_HEAD_BODY_RING);
-
-        /* If this is what we are looking for - return */
-        if (descr_buf->btype == VMXNET3_RXD_BTYPE_HEAD) {
-            *ridx = RX_HEAD_BODY_RING;
-            return true;
-        }
-    }
-}
-
-static bool
-vmxnet3_get_next_body_rx_descr(VMXNET3State *s,
-                               struct Vmxnet3_RxDesc *d,
-                               uint32_t *didx,
-                               uint32_t *ridx)
-{
-    vmxnet3_read_next_rx_descr(s, RXQ_IDX, RX_HEAD_BODY_RING, d, didx);
-
-    /* Try to find corresponding descriptor in head/body ring */
-    if (d->gen == vmxnet3_get_rx_ring_gen(s, RXQ_IDX, RX_HEAD_BODY_RING)) {
-        /* Only read after generation field verification */
-        smp_rmb();
-        /* Re-read to be sure we got the latest version */
-        vmxnet3_read_next_rx_descr(s, RXQ_IDX, RX_HEAD_BODY_RING, d, didx);
-        if (d->btype == VMXNET3_RXD_BTYPE_BODY) {
-            vmxnet3_inc_rx_consumption_counter(s, RXQ_IDX, RX_HEAD_BODY_RING);
-            *ridx = RX_HEAD_BODY_RING;
-            return true;
-        }
-    }
-
-    /*
-     * If there is no free descriptors on head/body ring or next free
-     * descriptor is a head descriptor switch to body only ring
-     */
-    vmxnet3_read_next_rx_descr(s, RXQ_IDX, RX_BODY_ONLY_RING, d, didx);
-
-    /* If no more free descriptors - return */
-    if (d->gen == vmxnet3_get_rx_ring_gen(s, RXQ_IDX, RX_BODY_ONLY_RING)) {
-        /* Only read after generation field verification */
-        smp_rmb();
-        /* Re-read to be sure we got the latest version */
-        vmxnet3_read_next_rx_descr(s, RXQ_IDX, RX_BODY_ONLY_RING, d, didx);
-        assert(d->btype == VMXNET3_RXD_BTYPE_BODY);
-        *ridx = RX_BODY_ONLY_RING;
-        vmxnet3_inc_rx_consumption_counter(s, RXQ_IDX, RX_BODY_ONLY_RING);
-        return true;
-    }
-
-    return false;
-}
-
-static inline bool
-vmxnet3_get_next_rx_descr(VMXNET3State *s, bool is_head,
-                          struct Vmxnet3_RxDesc *descr_buf,
-                          uint32_t *descr_idx,
-                          uint32_t *ridx)
-{
-    if (is_head || !s->rx_packets_compound) {
-        return vmxnet3_get_next_head_rx_descr(s, descr_buf, descr_idx, ridx);
-    } else {
-        return vmxnet3_get_next_body_rx_descr(s, descr_buf, descr_idx, ridx);
-    }
-}
-
-static void vmxnet3_rx_update_descr(struct VmxnetRxPkt *pkt,
-    struct Vmxnet3_RxCompDesc *rxcd)
-{
-    int csum_ok, is_gso;
-    bool isip4, isip6, istcp, isudp;
-    struct virtio_net_hdr *vhdr;
-    uint8_t offload_type;
-
-    if (vmxnet_rx_pkt_is_vlan_stripped(pkt)) {
-        rxcd->ts = 1;
-        rxcd->tci = vmxnet_rx_pkt_get_vlan_tag(pkt);
-    }
-
-    if (!vmxnet_rx_pkt_has_virt_hdr(pkt)) {
-        goto nocsum;
-    }
-
-    vhdr = vmxnet_rx_pkt_get_vhdr(pkt);
-    /*
-     * Checksum is valid when lower level tell so or when lower level
-     * requires checksum offload telling that packet produced/bridged
-     * locally and did travel over network after last checksum calculation
-     * or production
-     */
-    csum_ok = VMXNET_FLAG_IS_SET(vhdr->flags, VIRTIO_NET_HDR_F_DATA_VALID) ||
-              VMXNET_FLAG_IS_SET(vhdr->flags, VIRTIO_NET_HDR_F_NEEDS_CSUM);
-
-    offload_type = vhdr->gso_type & ~VIRTIO_NET_HDR_GSO_ECN;
-    is_gso = (offload_type != VIRTIO_NET_HDR_GSO_NONE) ? 1 : 0;
-
-    if (!csum_ok && !is_gso) {
-        goto nocsum;
-    }
-
-    vmxnet_rx_pkt_get_protocols(pkt, &isip4, &isip6, &isudp, &istcp);
-    if ((!istcp && !isudp) || (!isip4 && !isip6)) {
-        goto nocsum;
-    }
-
-    rxcd->cnc = 0;
-    rxcd->v4 = isip4 ? 1 : 0;
-    rxcd->v6 = isip6 ? 1 : 0;
-    rxcd->tcp = istcp ? 1 : 0;
-    rxcd->udp = isudp ? 1 : 0;
-    rxcd->fcs = rxcd->tuc = rxcd->ipc = 1;
-    return;
-
-nocsum:
-    rxcd->cnc = 1;
-    return;
-}
-
-static void
-vmxnet3_physical_memory_writev(const struct iovec *iov,
-                               size_t start_iov_off,
-                               hwaddr target_addr,
-                               size_t bytes_to_copy)
-{
-    size_t curr_off = 0;
-    size_t copied = 0;
-
-    while (bytes_to_copy) {
-        if (start_iov_off < (curr_off + iov->iov_len)) {
-            size_t chunk_len =
-                MIN((curr_off + iov->iov_len) - start_iov_off, bytes_to_copy);
-
-            cpu_physical_memory_write(target_addr + copied,
-                                      iov->iov_base + start_iov_off - curr_off,
-                                      chunk_len);
-
-            copied += chunk_len;
-            start_iov_off += chunk_len;
-            curr_off = start_iov_off;
-            bytes_to_copy -= chunk_len;
-        } else {
-            curr_off += iov->iov_len;
-        }
-        iov++;
-    }
-}
-
-static bool
-vmxnet3_indicate_packet(VMXNET3State *s)
-{
-    struct Vmxnet3_RxDesc rxd;
-    bool is_head = true;
-    uint32_t rxd_idx;
-    uint32_t rx_ridx = 0;
-
-    struct Vmxnet3_RxCompDesc rxcd;
-    uint32_t new_rxcd_gen = VMXNET3_INIT_GEN;
-    hwaddr new_rxcd_pa = 0;
-    hwaddr ready_rxcd_pa = 0;
-    struct iovec *data = vmxnet_rx_pkt_get_iovec(s->rx_pkt);
-    size_t bytes_copied = 0;
-    size_t bytes_left = vmxnet_rx_pkt_get_total_len(s->rx_pkt);
-    uint16_t num_frags = 0;
-    size_t chunk_size;
-
-    vmxnet_rx_pkt_dump(s->rx_pkt);
-
-    while (bytes_left > 0) {
-
-        /* cannot add more frags to packet */
-        if (num_frags == s->max_rx_frags) {
-            break;
-        }
-
-        new_rxcd_pa = vmxnet3_pop_rxc_descr(s, RXQ_IDX, &new_rxcd_gen);
-        if (!new_rxcd_pa) {
-            break;
-        }
-
-        if (!vmxnet3_get_next_rx_descr(s, is_head, &rxd, &rxd_idx, &rx_ridx)) {
-            break;
-        }
-
-        chunk_size = MIN(bytes_left, rxd.len);
-        vmxnet3_physical_memory_writev(data, bytes_copied,
-                                       le64_to_cpu(rxd.addr), chunk_size);
-        bytes_copied += chunk_size;
-        bytes_left -= chunk_size;
-
-        vmxnet3_dump_rx_descr(&rxd);
-
-        if (0 != ready_rxcd_pa) {
-            cpu_physical_memory_write(ready_rxcd_pa, &rxcd, sizeof(rxcd));
-        }
-
-        memset(&rxcd, 0, sizeof(struct Vmxnet3_RxCompDesc));
-        rxcd.rxdIdx = rxd_idx;
-        rxcd.len = chunk_size;
-        rxcd.sop = is_head;
-        rxcd.gen = new_rxcd_gen;
-        rxcd.rqID = RXQ_IDX + rx_ridx * s->rxq_num;
-
-        if (0 == bytes_left) {
-            vmxnet3_rx_update_descr(s->rx_pkt, &rxcd);
-        }
-
-        VMW_RIPRN("RX Completion descriptor: rxRing: %lu rxIdx %lu len %lu "
-                  "sop %d csum_correct %lu",
-                  (unsigned long) rx_ridx,
-                  (unsigned long) rxcd.rxdIdx,
-                  (unsigned long) rxcd.len,
-                  (int) rxcd.sop,
-                  (unsigned long) rxcd.tuc);
-
-        is_head = false;
-        ready_rxcd_pa = new_rxcd_pa;
-        new_rxcd_pa = 0;
-    }
-
-    if (0 != ready_rxcd_pa) {
-        rxcd.eop = 1;
-        rxcd.err = (0 != bytes_left);
-        cpu_physical_memory_write(ready_rxcd_pa, &rxcd, sizeof(rxcd));
-
-        /* Flush RX descriptor changes */
-        smp_wmb();
-    }
-
-    if (0 != new_rxcd_pa) {
-        vmxnet3_revert_rxc_descr(s, RXQ_IDX);
-    }
-
-    vmxnet3_trigger_interrupt(s, s->rxq_descr[RXQ_IDX].intr_idx);
-
-    if (bytes_left == 0) {
-        vmxnet3_on_rx_done_update_stats(s, RXQ_IDX, VMXNET3_PKT_STATUS_OK);
-        return true;
-    } else if (num_frags == s->max_rx_frags) {
-        vmxnet3_on_rx_done_update_stats(s, RXQ_IDX, VMXNET3_PKT_STATUS_ERROR);
-        return false;
-    } else {
-        vmxnet3_on_rx_done_update_stats(s, RXQ_IDX,
-                                        VMXNET3_PKT_STATUS_OUT_OF_BUF);
-        return false;
-    }
-}
-
-static void
-vmxnet3_io_bar0_write(void *opaque, hwaddr addr,
-                      uint64_t val, unsigned size)
-{
-    VMXNET3State *s = opaque;
-
-    if (VMW_IS_MULTIREG_ADDR(addr, VMXNET3_REG_TXPROD,
-                        VMXNET3_DEVICE_MAX_TX_QUEUES, VMXNET3_REG_ALIGN)) {
-        int tx_queue_idx =
-            VMW_MULTIREG_IDX_BY_ADDR(addr, VMXNET3_REG_TXPROD,
-                                     VMXNET3_REG_ALIGN);
-        assert(tx_queue_idx <= s->txq_num);
-        vmxnet3_process_tx_queue(s, tx_queue_idx);
-        return;
-    }
-
-    if (VMW_IS_MULTIREG_ADDR(addr, VMXNET3_REG_IMR,
-                        VMXNET3_MAX_INTRS, VMXNET3_REG_ALIGN)) {
-        int l = VMW_MULTIREG_IDX_BY_ADDR(addr, VMXNET3_REG_IMR,
-                                         VMXNET3_REG_ALIGN);
-
-        VMW_CBPRN("Interrupt mask for line %d written: 0x%" PRIx64, l, val);
-
-        vmxnet3_on_interrupt_mask_changed(s, l, val);
-        return;
-    }
-
-    if (VMW_IS_MULTIREG_ADDR(addr, VMXNET3_REG_RXPROD,
-                        VMXNET3_DEVICE_MAX_RX_QUEUES, VMXNET3_REG_ALIGN) ||
-       VMW_IS_MULTIREG_ADDR(addr, VMXNET3_REG_RXPROD2,
-                        VMXNET3_DEVICE_MAX_RX_QUEUES, VMXNET3_REG_ALIGN)) {
-        return;
-    }
-
-    VMW_WRPRN("BAR0 unknown write [%" PRIx64 "] = %" PRIx64 ", size %d",
-              (uint64_t) addr, val, size);
-}
-
-static uint64_t
-vmxnet3_io_bar0_read(void *opaque, hwaddr addr, unsigned size)
-{
-    if (VMW_IS_MULTIREG_ADDR(addr, VMXNET3_REG_IMR,
-                        VMXNET3_MAX_INTRS, VMXNET3_REG_ALIGN)) {
-        assert(false);
-    }
-
-    VMW_CBPRN("BAR0 unknown read [%" PRIx64 "], size %d", addr, size);
-    return 0;
-}
-
-static void vmxnet3_reset_interrupt_states(VMXNET3State *s)
-{
-    int i;
-    for (i = 0; i < ARRAY_SIZE(s->interrupt_states); i++) {
-        s->interrupt_states[i].is_asserted = false;
-        s->interrupt_states[i].is_pending = false;
-        s->interrupt_states[i].is_masked = true;
-    }
-}
-
-static void vmxnet3_reset_mac(VMXNET3State *s)
-{
-    memcpy(&s->conf.macaddr.a, &s->perm_mac.a, sizeof(s->perm_mac.a));
-    VMW_CFPRN("MAC address set to: " VMXNET_MF, VMXNET_MA(s->conf.macaddr.a));
-}
-
-static void vmxnet3_deactivate_device(VMXNET3State *s)
-{
-    VMW_CBPRN("Deactivating vmxnet3...");
-    s->device_active = false;
-}
-
-static void vmxnet3_reset(VMXNET3State *s)
-{
-    VMW_CBPRN("Resetting vmxnet3...");
-
-    vmxnet3_deactivate_device(s);
-    vmxnet3_reset_interrupt_states(s);
-    vmxnet_tx_pkt_reset(s->tx_pkt);
-    s->drv_shmem = 0;
-    s->tx_sop = true;
-    s->skip_current_tx_pkt = false;
-}
-
-static void vmxnet3_update_rx_mode(VMXNET3State *s)
-{
-    s->rx_mode = VMXNET3_READ_DRV_SHARED32(s->drv_shmem,
-                                           devRead.rxFilterConf.rxMode);
-    VMW_CFPRN("RX mode: 0x%08X", s->rx_mode);
-}
-
-static void vmxnet3_update_vlan_filters(VMXNET3State *s)
-{
-    int i;
-
-    /* Copy configuration from shared memory */
-    VMXNET3_READ_DRV_SHARED(s->drv_shmem,
-                            devRead.rxFilterConf.vfTable,
-                            s->vlan_table,
-                            sizeof(s->vlan_table));
-
-    /* Invert byte order when needed */
-    for (i = 0; i < ARRAY_SIZE(s->vlan_table); i++) {
-        s->vlan_table[i] = le32_to_cpu(s->vlan_table[i]);
-    }
-
-    /* Dump configuration for debugging purposes */
-    VMW_CFPRN("Configured VLANs:");
-    for (i = 0; i < sizeof(s->vlan_table) * 8; i++) {
-        if (VMXNET3_VFTABLE_ENTRY_IS_SET(s->vlan_table, i)) {
-            VMW_CFPRN("\tVLAN %d is present", i);
-        }
-    }
-}
-
-static void vmxnet3_update_mcast_filters(VMXNET3State *s)
-{
-    uint16_t list_bytes =
-        VMXNET3_READ_DRV_SHARED16(s->drv_shmem,
-                                  devRead.rxFilterConf.mfTableLen);
-
-    s->mcast_list_len = list_bytes / sizeof(s->mcast_list[0]);
-
-    s->mcast_list = g_realloc(s->mcast_list, list_bytes);
-    if (NULL == s->mcast_list) {
-        if (0 == s->mcast_list_len) {
-            VMW_CFPRN("Current multicast list is empty");
-        } else {
-            VMW_ERPRN("Failed to allocate multicast list of %d elements",
-                      s->mcast_list_len);
-        }
-        s->mcast_list_len = 0;
-    } else {
-        int i;
-        hwaddr mcast_list_pa =
-            VMXNET3_READ_DRV_SHARED64(s->drv_shmem,
-                                      devRead.rxFilterConf.mfTablePA);
-
-        cpu_physical_memory_read(mcast_list_pa, s->mcast_list, list_bytes);
-        VMW_CFPRN("Current multicast list len is %d:", s->mcast_list_len);
-        for (i = 0; i < s->mcast_list_len; i++) {
-            VMW_CFPRN("\t" VMXNET_MF, VMXNET_MA(s->mcast_list[i].a));
-        }
-    }
-}
-
-static void vmxnet3_setup_rx_filtering(VMXNET3State *s)
-{
-    vmxnet3_update_rx_mode(s);
-    vmxnet3_update_vlan_filters(s);
-    vmxnet3_update_mcast_filters(s);
-}
-
-static uint32_t vmxnet3_get_interrupt_config(VMXNET3State *s)
-{
-    uint32_t interrupt_mode = VMXNET3_IT_AUTO | (VMXNET3_IMM_AUTO << 2);
-    VMW_CFPRN("Interrupt config is 0x%X", interrupt_mode);
-    return interrupt_mode;
-}
-
-static void vmxnet3_fill_stats(VMXNET3State *s)
-{
-    int i;
-    for (i = 0; i < s->txq_num; i++) {
-        cpu_physical_memory_write(s->txq_descr[i].tx_stats_pa,
-                                  &s->txq_descr[i].txq_stats,
-                                  sizeof(s->txq_descr[i].txq_stats));
-    }
-
-    for (i = 0; i < s->rxq_num; i++) {
-        cpu_physical_memory_write(s->rxq_descr[i].rx_stats_pa,
-                                  &s->rxq_descr[i].rxq_stats,
-                                  sizeof(s->rxq_descr[i].rxq_stats));
-    }
-}
-
-static void vmxnet3_adjust_by_guest_type(VMXNET3State *s)
-{
-    struct Vmxnet3_GOSInfo gos;
-
-    VMXNET3_READ_DRV_SHARED(s->drv_shmem, devRead.misc.driverInfo.gos,
-                            &gos, sizeof(gos));
-    s->rx_packets_compound =
-        (gos.gosType == VMXNET3_GOS_TYPE_WIN) ? false : true;
-
-    VMW_CFPRN("Guest type specifics: RXCOMPOUND: %d", s->rx_packets_compound);
-}
-
-static void
-vmxnet3_dump_conf_descr(const char *name,
-                        struct Vmxnet3_VariableLenConfDesc *pm_descr)
-{
-    VMW_CFPRN("%s descriptor dump: Version %u, Length %u",
-              name, pm_descr->confVer, pm_descr->confLen);
-
-};
-
-static void vmxnet3_update_pm_state(VMXNET3State *s)
-{
-    struct Vmxnet3_VariableLenConfDesc pm_descr;
-
-    pm_descr.confLen =
-        VMXNET3_READ_DRV_SHARED32(s->drv_shmem, devRead.pmConfDesc.confLen);
-    pm_descr.confVer =
-        VMXNET3_READ_DRV_SHARED32(s->drv_shmem, devRead.pmConfDesc.confVer);
-    pm_descr.confPA =
-        VMXNET3_READ_DRV_SHARED64(s->drv_shmem, devRead.pmConfDesc.confPA);
-
-    vmxnet3_dump_conf_descr("PM State", &pm_descr);
-}
-
-static void vmxnet3_update_features(VMXNET3State *s)
-{
-    uint32_t guest_features;
-    int rxcso_supported;
-
-    guest_features = VMXNET3_READ_DRV_SHARED32(s->drv_shmem,
-                                               devRead.misc.uptFeatures);
-
-    rxcso_supported = VMXNET_FLAG_IS_SET(guest_features, UPT1_F_RXCSUM);
-    s->rx_vlan_stripping = VMXNET_FLAG_IS_SET(guest_features, UPT1_F_RXVLAN);
-    s->lro_supported = VMXNET_FLAG_IS_SET(guest_features, UPT1_F_LRO);
-
-    VMW_CFPRN("Features configuration: LRO: %d, RXCSUM: %d, VLANSTRIP: %d",
-              s->lro_supported, rxcso_supported,
-              s->rx_vlan_stripping);
-    if (s->peer_has_vhdr) {
-        tap_set_offload(qemu_get_queue(s->nic)->peer,
-                        rxcso_supported,
-                        s->lro_supported,
-                        s->lro_supported,
-                        0,
-                        0);
-    }
-}
-
-static void vmxnet3_activate_device(VMXNET3State *s)
-{
-    int i;
-    static const uint32_t VMXNET3_DEF_TX_THRESHOLD = 1;
-    hwaddr qdescr_table_pa;
-    uint64_t pa;
-    uint32_t size;
-
-    /* Verify configuration consistency */
-    if (!vmxnet3_verify_driver_magic(s->drv_shmem)) {
-        VMW_ERPRN("Device configuration received from driver is invalid");
-        return;
-    }
-
-    vmxnet3_adjust_by_guest_type(s);
-    vmxnet3_update_features(s);
-    vmxnet3_update_pm_state(s);
-    vmxnet3_setup_rx_filtering(s);
-    /* Cache fields from shared memory */
-    s->mtu = VMXNET3_READ_DRV_SHARED32(s->drv_shmem, devRead.misc.mtu);
-    VMW_CFPRN("MTU is %u", s->mtu);
-
-    s->max_rx_frags =
-        VMXNET3_READ_DRV_SHARED16(s->drv_shmem, devRead.misc.maxNumRxSG);
-
-    VMW_CFPRN("Max RX fragments is %u", s->max_rx_frags);
-
-    s->event_int_idx =
-        VMXNET3_READ_DRV_SHARED8(s->drv_shmem, devRead.intrConf.eventIntrIdx);
-    VMW_CFPRN("Events interrupt line is %u", s->event_int_idx);
-
-    s->auto_int_masking =
-        VMXNET3_READ_DRV_SHARED8(s->drv_shmem, devRead.intrConf.autoMask);
-    VMW_CFPRN("Automatic interrupt masking is %d", (int)s->auto_int_masking);
-
-    s->txq_num =
-        VMXNET3_READ_DRV_SHARED8(s->drv_shmem, devRead.misc.numTxQueues);
-    s->rxq_num =
-        VMXNET3_READ_DRV_SHARED8(s->drv_shmem, devRead.misc.numRxQueues);
-
-    VMW_CFPRN("Number of TX/RX queues %u/%u", s->txq_num, s->rxq_num);
-    assert(s->txq_num <= VMXNET3_DEVICE_MAX_TX_QUEUES);
-
-    qdescr_table_pa =
-        VMXNET3_READ_DRV_SHARED64(s->drv_shmem, devRead.misc.queueDescPA);
-    VMW_CFPRN("TX queues descriptors table is at 0x%" PRIx64, qdescr_table_pa);
-
-    /*
-     * Worst-case scenario is a packet that holds all TX rings space so
-     * we calculate total size of all TX rings for max TX fragments number
-     */
-    s->max_tx_frags = 0;
-
-    /* TX queues */
-    for (i = 0; i < s->txq_num; i++) {
-        hwaddr qdescr_pa =
-            qdescr_table_pa + i * sizeof(struct Vmxnet3_TxQueueDesc);
-
-        /* Read interrupt number for this TX queue */
-        s->txq_descr[i].intr_idx =
-            VMXNET3_READ_TX_QUEUE_DESCR8(qdescr_pa, conf.intrIdx);
-
-        VMW_CFPRN("TX Queue %d interrupt: %d", i, s->txq_descr[i].intr_idx);
-
-        /* Read rings memory locations for TX queues */
-        pa = VMXNET3_READ_TX_QUEUE_DESCR64(qdescr_pa, conf.txRingBasePA);
-        size = VMXNET3_READ_TX_QUEUE_DESCR32(qdescr_pa, conf.txRingSize);
-
-        vmxnet3_ring_init(&s->txq_descr[i].tx_ring, pa, size,
-                          sizeof(struct Vmxnet3_TxDesc), false);
-        VMXNET3_RING_DUMP(VMW_CFPRN, "TX", i, &s->txq_descr[i].tx_ring);
-
-        s->max_tx_frags += size;
-
-        /* TXC ring */
-        pa = VMXNET3_READ_TX_QUEUE_DESCR64(qdescr_pa, conf.compRingBasePA);
-        size = VMXNET3_READ_TX_QUEUE_DESCR32(qdescr_pa, conf.compRingSize);
-        vmxnet3_ring_init(&s->txq_descr[i].comp_ring, pa, size,
-                          sizeof(struct Vmxnet3_TxCompDesc), true);
-        VMXNET3_RING_DUMP(VMW_CFPRN, "TXC", i, &s->txq_descr[i].comp_ring);
-
-        s->txq_descr[i].tx_stats_pa =
-            qdescr_pa + offsetof(struct Vmxnet3_TxQueueDesc, stats);
-
-        memset(&s->txq_descr[i].txq_stats, 0,
-               sizeof(s->txq_descr[i].txq_stats));
-
-        /* Fill device-managed parameters for queues */
-        VMXNET3_WRITE_TX_QUEUE_DESCR32(qdescr_pa,
-                                       ctrl.txThreshold,
-                                       VMXNET3_DEF_TX_THRESHOLD);
-    }
-
-    /* Preallocate TX packet wrapper */
-    VMW_CFPRN("Max TX fragments is %u", s->max_tx_frags);
-    vmxnet_tx_pkt_init(&s->tx_pkt, s->max_tx_frags, s->peer_has_vhdr);
-    vmxnet_rx_pkt_init(&s->rx_pkt, s->peer_has_vhdr);
-
-    /* Read rings memory locations for RX queues */
-    for (i = 0; i < s->rxq_num; i++) {
-        int j;
-        hwaddr qd_pa =
-            qdescr_table_pa + s->txq_num * sizeof(struct Vmxnet3_TxQueueDesc) +
-            i * sizeof(struct Vmxnet3_RxQueueDesc);
-
-        /* Read interrupt number for this RX queue */
-        s->rxq_descr[i].intr_idx =
-            VMXNET3_READ_TX_QUEUE_DESCR8(qd_pa, conf.intrIdx);
-
-        VMW_CFPRN("RX Queue %d interrupt: %d", i, s->rxq_descr[i].intr_idx);
-
-        /* Read rings memory locations */
-        for (j = 0; j < VMXNET3_RX_RINGS_PER_QUEUE; j++) {
-            /* RX rings */
-            pa = VMXNET3_READ_RX_QUEUE_DESCR64(qd_pa, conf.rxRingBasePA[j]);
-            size = VMXNET3_READ_RX_QUEUE_DESCR32(qd_pa, conf.rxRingSize[j]);
-            vmxnet3_ring_init(&s->rxq_descr[i].rx_ring[j], pa, size,
-                              sizeof(struct Vmxnet3_RxDesc), false);
-            VMW_CFPRN("RX queue %d:%d: Base: %" PRIx64 ", Size: %d",
-                      i, j, pa, size);
-        }
-
-        /* RXC ring */
-        pa = VMXNET3_READ_RX_QUEUE_DESCR64(qd_pa, conf.compRingBasePA);
-        size = VMXNET3_READ_RX_QUEUE_DESCR32(qd_pa, conf.compRingSize);
-        vmxnet3_ring_init(&s->rxq_descr[i].comp_ring, pa, size,
-                          sizeof(struct Vmxnet3_RxCompDesc), true);
-        VMW_CFPRN("RXC queue %d: Base: %" PRIx64 ", Size: %d", i, pa, size);
-
-        s->rxq_descr[i].rx_stats_pa =
-            qd_pa + offsetof(struct Vmxnet3_RxQueueDesc, stats);
-        memset(&s->rxq_descr[i].rxq_stats, 0,
-               sizeof(s->rxq_descr[i].rxq_stats));
-    }
-
-    /* Make sure everything is in place before device activation */
-    smp_wmb();
-
-    vmxnet3_reset_mac(s);
-
-    s->device_active = true;
-}
-
-static void vmxnet3_handle_command(VMXNET3State *s, uint64_t cmd)
-{
-    s->last_command = cmd;
-
-    switch (cmd) {
-    case VMXNET3_CMD_GET_PERM_MAC_HI:
-        VMW_CBPRN("Set: Get upper part of permanent MAC");
-        break;
-
-    case VMXNET3_CMD_GET_PERM_MAC_LO:
-        VMW_CBPRN("Set: Get lower part of permanent MAC");
-        break;
-
-    case VMXNET3_CMD_GET_STATS:
-        VMW_CBPRN("Set: Get device statistics");
-        vmxnet3_fill_stats(s);
-        break;
-
-    case VMXNET3_CMD_ACTIVATE_DEV:
-        VMW_CBPRN("Set: Activating vmxnet3 device");
-        vmxnet3_activate_device(s);
-        break;
-
-    case VMXNET3_CMD_UPDATE_RX_MODE:
-        VMW_CBPRN("Set: Update rx mode");
-        vmxnet3_update_rx_mode(s);
-        break;
-
-    case VMXNET3_CMD_UPDATE_VLAN_FILTERS:
-        VMW_CBPRN("Set: Update VLAN filters");
-        vmxnet3_update_vlan_filters(s);
-        break;
-
-    case VMXNET3_CMD_UPDATE_MAC_FILTERS:
-        VMW_CBPRN("Set: Update MAC filters");
-        vmxnet3_update_mcast_filters(s);
-        break;
-
-    case VMXNET3_CMD_UPDATE_FEATURE:
-        VMW_CBPRN("Set: Update features");
-        vmxnet3_update_features(s);
-        break;
-
-    case VMXNET3_CMD_UPDATE_PMCFG:
-        VMW_CBPRN("Set: Update power management config");
-        vmxnet3_update_pm_state(s);
-        break;
-
-    case VMXNET3_CMD_GET_LINK:
-        VMW_CBPRN("Set: Get link");
-        break;
-
-    case VMXNET3_CMD_RESET_DEV:
-        VMW_CBPRN("Set: Reset device");
-        vmxnet3_reset(s);
-        break;
-
-    case VMXNET3_CMD_QUIESCE_DEV:
-        VMW_CBPRN("Set: VMXNET3_CMD_QUIESCE_DEV - pause the device");
-        vmxnet3_deactivate_device(s);
-        break;
-
-    case VMXNET3_CMD_GET_CONF_INTR:
-        VMW_CBPRN("Set: VMXNET3_CMD_GET_CONF_INTR - interrupt configuration");
-        break;
-
-    default:
-        VMW_CBPRN("Received unknown command: %" PRIx64, cmd);
-        break;
-    }
-}
-
-static uint64_t vmxnet3_get_command_status(VMXNET3State *s)
-{
-    uint64_t ret;
-
-    switch (s->last_command) {
-    case VMXNET3_CMD_ACTIVATE_DEV:
-        ret = (s->device_active) ? 0 : -1;
-        VMW_CFPRN("Device active: %" PRIx64, ret);
-        break;
-
-    case VMXNET3_CMD_GET_LINK:
-        ret = s->link_status_and_speed;
-        VMW_CFPRN("Link and speed: %" PRIx64, ret);
-        break;
-
-    case VMXNET3_CMD_GET_PERM_MAC_LO:
-        ret = vmxnet3_get_mac_low(&s->perm_mac);
-        break;
-
-    case VMXNET3_CMD_GET_PERM_MAC_HI:
-        ret = vmxnet3_get_mac_high(&s->perm_mac);
-        break;
-
-    case VMXNET3_CMD_GET_CONF_INTR:
-        ret = vmxnet3_get_interrupt_config(s);
-        break;
-
-    default:
-        VMW_WRPRN("Received request for unknown command: %x", s->last_command);
-        ret = -1;
-        break;
-    }
-
-    return ret;
-}
-
-static void vmxnet3_set_events(VMXNET3State *s, uint32_t val)
-{
-    uint32_t events;
-
-    VMW_CBPRN("Setting events: 0x%x", val);
-    events = VMXNET3_READ_DRV_SHARED32(s->drv_shmem, ecr) | val;
-    VMXNET3_WRITE_DRV_SHARED32(s->drv_shmem, ecr, events);
-}
-
-static void vmxnet3_ack_events(VMXNET3State *s, uint32_t val)
-{
-    uint32_t events;
-
-    VMW_CBPRN("Clearing events: 0x%x", val);
-    events = VMXNET3_READ_DRV_SHARED32(s->drv_shmem, ecr) & ~val;
-    VMXNET3_WRITE_DRV_SHARED32(s->drv_shmem, ecr, events);
-}
-
-static void
-vmxnet3_io_bar1_write(void *opaque,
-                      hwaddr addr,
-                      uint64_t val,
-                      unsigned size)
-{
-    VMXNET3State *s = opaque;
-
-    switch (addr) {
-    /* Vmxnet3 Revision Report Selection */
-    case VMXNET3_REG_VRRS:
-        VMW_CBPRN("Write BAR1 [VMXNET3_REG_VRRS] = %" PRIx64 ", size %d",
-                  val, size);
-        break;
-
-    /* UPT Version Report Selection */
-    case VMXNET3_REG_UVRS:
-        VMW_CBPRN("Write BAR1 [VMXNET3_REG_UVRS] = %" PRIx64 ", size %d",
-                  val, size);
-        break;
-
-    /* Driver Shared Address Low */
-    case VMXNET3_REG_DSAL:
-        VMW_CBPRN("Write BAR1 [VMXNET3_REG_DSAL] = %" PRIx64 ", size %d",
-                  val, size);
-        /*
-         * Guest driver will first write the low part of the shared
-         * memory address. We save it to temp variable and set the
-         * shared address only after we get the high part
-         */
-        if (0 == val) {
-            s->device_active = false;
-        }
-        s->temp_shared_guest_driver_memory = val;
-        s->drv_shmem = 0;
-        break;
-
-    /* Driver Shared Address High */
-    case VMXNET3_REG_DSAH:
-        VMW_CBPRN("Write BAR1 [VMXNET3_REG_DSAH] = %" PRIx64 ", size %d",
-                  val, size);
-        /*
-         * Set the shared memory between guest driver and device.
-         * We already should have low address part.
-         */
-        s->drv_shmem = s->temp_shared_guest_driver_memory | (val << 32);
-        break;
-
-    /* Command */
-    case VMXNET3_REG_CMD:
-        VMW_CBPRN("Write BAR1 [VMXNET3_REG_CMD] = %" PRIx64 ", size %d",
-                  val, size);
-        vmxnet3_handle_command(s, val);
-        break;
-
-    /* MAC Address Low */
-    case VMXNET3_REG_MACL:
-        VMW_CBPRN("Write BAR1 [VMXNET3_REG_MACL] = %" PRIx64 ", size %d",
-                  val, size);
-        s->temp_mac = val;
-        break;
-
-    /* MAC Address High */
-    case VMXNET3_REG_MACH:
-        VMW_CBPRN("Write BAR1 [VMXNET3_REG_MACH] = %" PRIx64 ", size %d",
-                  val, size);
-        vmxnet3_set_variable_mac(s, val, s->temp_mac);
-        break;
-
-    /* Interrupt Cause Register */
-    case VMXNET3_REG_ICR:
-        VMW_CBPRN("Write BAR1 [VMXNET3_REG_ICR] = %" PRIx64 ", size %d",
-                  val, size);
-        assert(false);
-        break;
-
-    /* Event Cause Register */
-    case VMXNET3_REG_ECR:
-        VMW_CBPRN("Write BAR1 [VMXNET3_REG_ECR] = %" PRIx64 ", size %d",
-                  val, size);
-        vmxnet3_ack_events(s, val);
-        break;
-
-    default:
-        VMW_CBPRN("Unknown Write to BAR1 [%" PRIx64 "] = %" PRIx64 ", size %d",
-                  addr, val, size);
-        break;
-    }
-}
-
-static uint64_t
-vmxnet3_io_bar1_read(void *opaque, hwaddr addr, unsigned size)
-{
-        VMXNET3State *s = opaque;
-        uint64_t ret = 0;
-
-        switch (addr) {
-        /* Vmxnet3 Revision Report Selection */
-        case VMXNET3_REG_VRRS:
-            VMW_CBPRN("Read BAR1 [VMXNET3_REG_VRRS], size %d", size);
-            ret = VMXNET3_DEVICE_REVISION;
-            break;
-
-        /* UPT Version Report Selection */
-        case VMXNET3_REG_UVRS:
-            VMW_CBPRN("Read BAR1 [VMXNET3_REG_UVRS], size %d", size);
-            ret = VMXNET3_DEVICE_VERSION;
-            break;
-
-        /* Command */
-        case VMXNET3_REG_CMD:
-            VMW_CBPRN("Read BAR1 [VMXNET3_REG_CMD], size %d", size);
-            ret = vmxnet3_get_command_status(s);
-            break;
-
-        /* MAC Address Low */
-        case VMXNET3_REG_MACL:
-            VMW_CBPRN("Read BAR1 [VMXNET3_REG_MACL], size %d", size);
-            ret = vmxnet3_get_mac_low(&s->conf.macaddr);
-            break;
-
-        /* MAC Address High */
-        case VMXNET3_REG_MACH:
-            VMW_CBPRN("Read BAR1 [VMXNET3_REG_MACH], size %d", size);
-            ret = vmxnet3_get_mac_high(&s->conf.macaddr);
-            break;
-
-        /*
-         * Interrupt Cause Register
-         * Used for legacy interrupts only so interrupt index always 0
-         */
-        case VMXNET3_REG_ICR:
-            VMW_CBPRN("Read BAR1 [VMXNET3_REG_ICR], size %d", size);
-            if (vmxnet3_interrupt_asserted(s, 0)) {
-                vmxnet3_clear_interrupt(s, 0);
-                ret = true;
-            } else {
-                ret = false;
-            }
-            break;
-
-        default:
-            VMW_CBPRN("Unknow read BAR1[%" PRIx64 "], %d bytes", addr, size);
-            break;
-        }
-
-        return ret;
-}
-
-static int
-vmxnet3_can_receive(NetClientState *nc)
-{
-    VMXNET3State *s = qemu_get_nic_opaque(nc);
-    return s->device_active &&
-           VMXNET_FLAG_IS_SET(s->link_status_and_speed, VMXNET3_LINK_STATUS_UP);
-}
-
-static inline bool
-vmxnet3_is_registered_vlan(VMXNET3State *s, const void *data)
-{
-    uint16_t vlan_tag = eth_get_pkt_tci(data) & VLAN_VID_MASK;
-    if (IS_SPECIAL_VLAN_ID(vlan_tag)) {
-        return true;
-    }
-
-    return VMXNET3_VFTABLE_ENTRY_IS_SET(s->vlan_table, vlan_tag);
-}
-
-static bool
-vmxnet3_is_allowed_mcast_group(VMXNET3State *s, const uint8_t *group_mac)
-{
-    int i;
-    for (i = 0; i < s->mcast_list_len; i++) {
-        if (!memcmp(group_mac, s->mcast_list[i].a, sizeof(s->mcast_list[i]))) {
-            return true;
-        }
-    }
-    return false;
-}
-
-static bool
-vmxnet3_rx_filter_may_indicate(VMXNET3State *s, const void *data,
-    size_t size)
-{
-    struct eth_header *ehdr = PKT_GET_ETH_HDR(data);
-
-    if (VMXNET_FLAG_IS_SET(s->rx_mode, VMXNET3_RXM_PROMISC)) {
-        return true;
-    }
-
-    if (!vmxnet3_is_registered_vlan(s, data)) {
-        return false;
-    }
-
-    switch (vmxnet_rx_pkt_get_packet_type(s->rx_pkt)) {
-    case ETH_PKT_UCAST:
-        if (!VMXNET_FLAG_IS_SET(s->rx_mode, VMXNET3_RXM_UCAST)) {
-            return false;
-        }
-        if (memcmp(s->conf.macaddr.a, ehdr->h_dest, ETH_ALEN)) {
-            return false;
-        }
-        break;
-
-    case ETH_PKT_BCAST:
-        if (!VMXNET_FLAG_IS_SET(s->rx_mode, VMXNET3_RXM_BCAST)) {
-            return false;
-        }
-        break;
-
-    case ETH_PKT_MCAST:
-        if (VMXNET_FLAG_IS_SET(s->rx_mode, VMXNET3_RXM_ALL_MULTI)) {
-            return true;
-        }
-        if (!VMXNET_FLAG_IS_SET(s->rx_mode, VMXNET3_RXM_MCAST)) {
-            return false;
-        }
-        if (!vmxnet3_is_allowed_mcast_group(s, ehdr->h_dest)) {
-            return false;
-        }
-        break;
-
-    default:
-        assert(false);
-    }
-
-    return true;
-}
-
-static ssize_t
-vmxnet3_receive(NetClientState *nc, const uint8_t *buf, size_t size)
-{
-    VMXNET3State *s = qemu_get_nic_opaque(nc);
-    size_t bytes_indicated;
-
-    if (!vmxnet3_can_receive(nc)) {
-        VMW_PKPRN("Cannot receive now");
-        return -1;
-    }
-
-    if (s->peer_has_vhdr) {
-        vmxnet_rx_pkt_set_vhdr(s->rx_pkt, (struct virtio_net_hdr *)buf);
-        buf += sizeof(struct virtio_net_hdr);
-        size -= sizeof(struct virtio_net_hdr);
-    }
-
-    vmxnet_rx_pkt_set_packet_type(s->rx_pkt,
-        get_eth_packet_type(PKT_GET_ETH_HDR(buf)));
-
-    if (vmxnet3_rx_filter_may_indicate(s, buf, size)) {
-        vmxnet_rx_pkt_attach_data(s->rx_pkt, buf, size, s->rx_vlan_stripping);
-        bytes_indicated = vmxnet3_indicate_packet(s) ? size : -1;
-        if (bytes_indicated < size) {
-            VMW_PKPRN("RX: %lu of %lu bytes indicated", bytes_indicated, size);
-        }
-    } else {
-        VMW_PKPRN("Packet dropped by RX filter");
-        bytes_indicated = size;
-    }
-
-    assert(size > 0);
-    assert(bytes_indicated != 0);
-    return bytes_indicated;
-}
-
-static void vmxnet3_cleanup(NetClientState *nc)
-{
-    VMXNET3State *s = qemu_get_nic_opaque(nc);
-    s->nic = NULL;
-}
-
-static void vmxnet3_set_link_status(NetClientState *nc)
-{
-    VMXNET3State *s = qemu_get_nic_opaque(nc);
-
-    if (nc->link_down) {
-        s->link_status_and_speed &= ~VMXNET3_LINK_STATUS_UP;
-    } else {
-        s->link_status_and_speed |= VMXNET3_LINK_STATUS_UP;
-    }
-
-    vmxnet3_set_events(s, VMXNET3_ECR_LINK);
-    vmxnet3_trigger_interrupt(s, s->event_int_idx);
-}
-
-static NetClientInfo net_vmxnet3_info = {
-        .type = NET_CLIENT_OPTIONS_KIND_NIC,
-        .size = sizeof(NICState),
-        .can_receive = vmxnet3_can_receive,
-        .receive = vmxnet3_receive,
-        .cleanup = vmxnet3_cleanup,
-        .link_status_changed = vmxnet3_set_link_status,
-};
-
-static bool vmxnet3_peer_has_vnet_hdr(VMXNET3State *s)
-{
-    NetClientState *peer = qemu_get_queue(s->nic)->peer;
-
-    if ((NULL != peer)                              &&
-        (peer->info->type == NET_CLIENT_OPTIONS_KIND_TAP)   &&
-        tap_has_vnet_hdr(peer)) {
-        return true;
-    }
-
-    VMW_WRPRN("Peer has no virtio extension. Task offloads will be emulated.");
-    return false;
-}
-
-static void vmxnet3_net_uninit(VMXNET3State *s)
-{
-    g_free(s->mcast_list);
-    vmxnet_tx_pkt_reset(s->tx_pkt);
-    vmxnet_tx_pkt_uninit(s->tx_pkt);
-    vmxnet_rx_pkt_uninit(s->rx_pkt);
-    qemu_del_net_client(qemu_get_queue(s->nic));
-}
-
-static void vmxnet3_net_init(VMXNET3State *s)
-{
-    DeviceState *d = DEVICE(s);
-
-    VMW_CBPRN("vmxnet3_net_init called...");
-
-    qemu_macaddr_default_if_unset(&s->conf.macaddr);
-
-    /* Windows guest will query the address that was set on init */
-    memcpy(&s->perm_mac.a, &s->conf.macaddr.a, sizeof(s->perm_mac.a));
-
-    s->mcast_list = NULL;
-    s->mcast_list_len = 0;
-
-    s->link_status_and_speed = VMXNET3_LINK_SPEED | VMXNET3_LINK_STATUS_UP;
-
-    VMW_CFPRN("Permanent MAC: " MAC_FMT, MAC_ARG(s->perm_mac.a));
-
-    s->nic = qemu_new_nic(&net_vmxnet3_info, &s->conf,
-                          object_get_typename(OBJECT(s)),
-                          d->id, s);
-
-    s->peer_has_vhdr = vmxnet3_peer_has_vnet_hdr(s);
-    s->tx_sop = true;
-    s->skip_current_tx_pkt = false;
-    s->tx_pkt = NULL;
-    s->rx_pkt = NULL;
-    s->rx_vlan_stripping = false;
-    s->lro_supported = false;
-
-    if (s->peer_has_vhdr) {
-        tap_set_vnet_hdr_len(qemu_get_queue(s->nic)->peer,
-            sizeof(struct virtio_net_hdr));
-
-        tap_using_vnet_hdr(qemu_get_queue(s->nic)->peer, 1);
-    }
-
-    qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
-}
-
-static void
-vmxnet3_unuse_msix_vectors(VMXNET3State *s, int num_vectors)
-{
-    PCIDevice *d = PCI_DEVICE(s);
-    int i;
-    for (i = 0; i < num_vectors; i++) {
-        msix_vector_unuse(d, i);
-    }
-}
-
-static bool
-vmxnet3_use_msix_vectors(VMXNET3State *s, int num_vectors)
-{
-    PCIDevice *d = PCI_DEVICE(s);
-    int i;
-    for (i = 0; i < num_vectors; i++) {
-        int res = msix_vector_use(d, i);
-        if (0 > res) {
-            VMW_WRPRN("Failed to use MSI-X vector %d, error %d", i, res);
-            vmxnet3_unuse_msix_vectors(s, i);
-            return false;
-        }
-    }
-    return true;
-}
-
-static bool
-vmxnet3_init_msix(VMXNET3State *s)
-{
-    PCIDevice *d = PCI_DEVICE(s);
-    int res = msix_init(d, VMXNET3_MAX_INTRS,
-                        &s->msix_bar,
-                        VMXNET3_MSIX_BAR_IDX, VMXNET3_OFF_MSIX_TABLE,
-                        &s->msix_bar,
-                        VMXNET3_MSIX_BAR_IDX, VMXNET3_OFF_MSIX_PBA,
-                        0);
-
-    if (0 > res) {
-        VMW_WRPRN("Failed to initialize MSI-X, error %d", res);
-        s->msix_used = false;
-    } else {
-        if (!vmxnet3_use_msix_vectors(s, VMXNET3_MAX_INTRS)) {
-            VMW_WRPRN("Failed to use MSI-X vectors, error %d", res);
-            msix_uninit(d, &s->msix_bar, &s->msix_bar);
-            s->msix_used = false;
-        } else {
-            s->msix_used = true;
-        }
-    }
-    return s->msix_used;
-}
-
-static void
-vmxnet3_cleanup_msix(VMXNET3State *s)
-{
-    PCIDevice *d = PCI_DEVICE(s);
-
-    if (s->msix_used) {
-        msix_vector_unuse(d, VMXNET3_MAX_INTRS);
-        msix_uninit(d, &s->msix_bar, &s->msix_bar);
-    }
-}
-
-#define VMXNET3_MSI_NUM_VECTORS   (1)
-#define VMXNET3_MSI_OFFSET        (0x50)
-#define VMXNET3_USE_64BIT         (true)
-#define VMXNET3_PER_VECTOR_MASK   (false)
-
-static bool
-vmxnet3_init_msi(VMXNET3State *s)
-{
-    PCIDevice *d = PCI_DEVICE(s);
-    int res;
-
-    res = msi_init(d, VMXNET3_MSI_OFFSET, VMXNET3_MSI_NUM_VECTORS,
-                   VMXNET3_USE_64BIT, VMXNET3_PER_VECTOR_MASK);
-    if (0 > res) {
-        VMW_WRPRN("Failed to initialize MSI, error %d", res);
-        s->msi_used = false;
-    } else {
-        s->msi_used = true;
-    }
-
-    return s->msi_used;
-}
-
-static void
-vmxnet3_cleanup_msi(VMXNET3State *s)
-{
-    PCIDevice *d = PCI_DEVICE(s);
-
-    if (s->msi_used) {
-        msi_uninit(d);
-    }
-}
-
-static void
-vmxnet3_msix_save(QEMUFile *f, void *opaque)
-{
-    PCIDevice *d = PCI_DEVICE(opaque);
-    msix_save(d, f);
-}
-
-static int
-vmxnet3_msix_load(QEMUFile *f, void *opaque, int version_id)
-{
-    PCIDevice *d = PCI_DEVICE(opaque);
-    msix_load(d, f);
-    return 0;
-}
-
-static const MemoryRegionOps b0_ops = {
-    .read = vmxnet3_io_bar0_read,
-    .write = vmxnet3_io_bar0_write,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-    .impl = {
-            .min_access_size = 4,
-            .max_access_size = 4,
-    },
-};
-
-static const MemoryRegionOps b1_ops = {
-    .read = vmxnet3_io_bar1_read,
-    .write = vmxnet3_io_bar1_write,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-    .impl = {
-            .min_access_size = 4,
-            .max_access_size = 4,
-    },
-};
-
-static int vmxnet3_pci_init(PCIDevice *pci_dev)
-{
-    DeviceState *dev = DEVICE(pci_dev);
-    VMXNET3State *s = VMXNET3(pci_dev);
-
-    VMW_CBPRN("Starting init...");
-
-    memory_region_init_io(&s->bar0, &b0_ops, s,
-                          "vmxnet3-b0", VMXNET3_PT_REG_SIZE);
-    pci_register_bar(pci_dev, VMXNET3_BAR0_IDX,
-                     PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar0);
-
-    memory_region_init_io(&s->bar1, &b1_ops, s,
-                          "vmxnet3-b1", VMXNET3_VD_REG_SIZE);
-    pci_register_bar(pci_dev, VMXNET3_BAR1_IDX,
-                     PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar1);
-
-    memory_region_init(&s->msix_bar, "vmxnet3-msix-bar",
-                       VMXNET3_MSIX_BAR_SIZE);
-    pci_register_bar(pci_dev, VMXNET3_MSIX_BAR_IDX,
-                     PCI_BASE_ADDRESS_SPACE_MEMORY, &s->msix_bar);
-
-    vmxnet3_reset_interrupt_states(s);
-
-    /* Interrupt pin A */
-    pci_dev->config[PCI_INTERRUPT_PIN] = 0x01;
-
-    if (!vmxnet3_init_msix(s)) {
-        VMW_WRPRN("Failed to initialize MSI-X, configuration is inconsistent.");
-    }
-
-    if (!vmxnet3_init_msi(s)) {
-        VMW_WRPRN("Failed to initialize MSI, configuration is inconsistent.");
-    }
-
-    vmxnet3_net_init(s);
-
-    register_savevm(dev, "vmxnet3-msix", -1, 1,
-                    vmxnet3_msix_save, vmxnet3_msix_load, s);
-
-    add_boot_device_path(s->conf.bootindex, dev, "/ethernet-phy@0");
-
-    return 0;
-}
-
-
-static void vmxnet3_pci_uninit(PCIDevice *pci_dev)
-{
-    DeviceState *dev = DEVICE(pci_dev);
-    VMXNET3State *s = VMXNET3(pci_dev);
-
-    VMW_CBPRN("Starting uninit...");
-
-    unregister_savevm(dev, "vmxnet3-msix", s);
-
-    vmxnet3_net_uninit(s);
-
-    vmxnet3_cleanup_msix(s);
-
-    vmxnet3_cleanup_msi(s);
-
-    memory_region_destroy(&s->bar0);
-    memory_region_destroy(&s->bar1);
-    memory_region_destroy(&s->msix_bar);
-}
-
-static void vmxnet3_qdev_reset(DeviceState *dev)
-{
-    PCIDevice *d = PCI_DEVICE(dev);
-    VMXNET3State *s = VMXNET3(d);
-
-    VMW_CBPRN("Starting QDEV reset...");
-    vmxnet3_reset(s);
-}
-
-static bool vmxnet3_mc_list_needed(void *opaque)
-{
-    return true;
-}
-
-static int vmxnet3_mcast_list_pre_load(void *opaque)
-{
-    VMXNET3State *s = opaque;
-
-    s->mcast_list = g_malloc(s->mcast_list_buff_size);
-
-    return 0;
-}
-
-
-static void vmxnet3_pre_save(void *opaque)
-{
-    VMXNET3State *s = opaque;
-
-    s->mcast_list_buff_size = s->mcast_list_len * sizeof(MACAddr);
-}
-
-static const VMStateDescription vmxstate_vmxnet3_mcast_list = {
-    .name = "vmxnet3/mcast_list",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .pre_load = vmxnet3_mcast_list_pre_load,
-    .fields = (VMStateField[]) {
-        VMSTATE_VBUFFER_UINT32(mcast_list, VMXNET3State, 0, NULL, 0,
-            mcast_list_buff_size),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void vmxnet3_get_ring_from_file(QEMUFile *f, Vmxnet3Ring *r)
-{
-    r->pa = qemu_get_be64(f);
-    r->size = qemu_get_be32(f);
-    r->cell_size = qemu_get_be32(f);
-    r->next = qemu_get_be32(f);
-    r->gen = qemu_get_byte(f);
-}
-
-static void vmxnet3_put_ring_to_file(QEMUFile *f, Vmxnet3Ring *r)
-{
-    qemu_put_be64(f, r->pa);
-    qemu_put_be32(f, r->size);
-    qemu_put_be32(f, r->cell_size);
-    qemu_put_be32(f, r->next);
-    qemu_put_byte(f, r->gen);
-}
-
-static void vmxnet3_get_tx_stats_from_file(QEMUFile *f,
-    struct UPT1_TxStats *tx_stat)
-{
-    tx_stat->TSOPktsTxOK = qemu_get_be64(f);
-    tx_stat->TSOBytesTxOK = qemu_get_be64(f);
-    tx_stat->ucastPktsTxOK = qemu_get_be64(f);
-    tx_stat->ucastBytesTxOK = qemu_get_be64(f);
-    tx_stat->mcastPktsTxOK = qemu_get_be64(f);
-    tx_stat->mcastBytesTxOK = qemu_get_be64(f);
-    tx_stat->bcastPktsTxOK = qemu_get_be64(f);
-    tx_stat->bcastBytesTxOK = qemu_get_be64(f);
-    tx_stat->pktsTxError = qemu_get_be64(f);
-    tx_stat->pktsTxDiscard = qemu_get_be64(f);
-}
-
-static void vmxnet3_put_tx_stats_to_file(QEMUFile *f,
-    struct UPT1_TxStats *tx_stat)
-{
-    qemu_put_be64(f, tx_stat->TSOPktsTxOK);
-    qemu_put_be64(f, tx_stat->TSOBytesTxOK);
-    qemu_put_be64(f, tx_stat->ucastPktsTxOK);
-    qemu_put_be64(f, tx_stat->ucastBytesTxOK);
-    qemu_put_be64(f, tx_stat->mcastPktsTxOK);
-    qemu_put_be64(f, tx_stat->mcastBytesTxOK);
-    qemu_put_be64(f, tx_stat->bcastPktsTxOK);
-    qemu_put_be64(f, tx_stat->bcastBytesTxOK);
-    qemu_put_be64(f, tx_stat->pktsTxError);
-    qemu_put_be64(f, tx_stat->pktsTxDiscard);
-}
-
-static int vmxnet3_get_txq_descr(QEMUFile *f, void *pv, size_t size)
-{
-    Vmxnet3TxqDescr *r = pv;
-
-    vmxnet3_get_ring_from_file(f, &r->tx_ring);
-    vmxnet3_get_ring_from_file(f, &r->comp_ring);
-    r->intr_idx = qemu_get_byte(f);
-    r->tx_stats_pa = qemu_get_be64(f);
-
-    vmxnet3_get_tx_stats_from_file(f, &r->txq_stats);
-
-    return 0;
-}
-
-static void vmxnet3_put_txq_descr(QEMUFile *f, void *pv, size_t size)
-{
-    Vmxnet3TxqDescr *r = pv;
-
-    vmxnet3_put_ring_to_file(f, &r->tx_ring);
-    vmxnet3_put_ring_to_file(f, &r->comp_ring);
-    qemu_put_byte(f, r->intr_idx);
-    qemu_put_be64(f, r->tx_stats_pa);
-    vmxnet3_put_tx_stats_to_file(f, &r->txq_stats);
-}
-
-const VMStateInfo txq_descr_info = {
-    .name = "txq_descr",
-    .get = vmxnet3_get_txq_descr,
-    .put = vmxnet3_put_txq_descr
-};
-
-static void vmxnet3_get_rx_stats_from_file(QEMUFile *f,
-    struct UPT1_RxStats *rx_stat)
-{
-    rx_stat->LROPktsRxOK = qemu_get_be64(f);
-    rx_stat->LROBytesRxOK = qemu_get_be64(f);
-    rx_stat->ucastPktsRxOK = qemu_get_be64(f);
-    rx_stat->ucastBytesRxOK = qemu_get_be64(f);
-    rx_stat->mcastPktsRxOK = qemu_get_be64(f);
-    rx_stat->mcastBytesRxOK = qemu_get_be64(f);
-    rx_stat->bcastPktsRxOK = qemu_get_be64(f);
-    rx_stat->bcastBytesRxOK = qemu_get_be64(f);
-    rx_stat->pktsRxOutOfBuf = qemu_get_be64(f);
-    rx_stat->pktsRxError = qemu_get_be64(f);
-}
-
-static void vmxnet3_put_rx_stats_to_file(QEMUFile *f,
-    struct UPT1_RxStats *rx_stat)
-{
-    qemu_put_be64(f, rx_stat->LROPktsRxOK);
-    qemu_put_be64(f, rx_stat->LROBytesRxOK);
-    qemu_put_be64(f, rx_stat->ucastPktsRxOK);
-    qemu_put_be64(f, rx_stat->ucastBytesRxOK);
-    qemu_put_be64(f, rx_stat->mcastPktsRxOK);
-    qemu_put_be64(f, rx_stat->mcastBytesRxOK);
-    qemu_put_be64(f, rx_stat->bcastPktsRxOK);
-    qemu_put_be64(f, rx_stat->bcastBytesRxOK);
-    qemu_put_be64(f, rx_stat->pktsRxOutOfBuf);
-    qemu_put_be64(f, rx_stat->pktsRxError);
-}
-
-static int vmxnet3_get_rxq_descr(QEMUFile *f, void *pv, size_t size)
-{
-    Vmxnet3RxqDescr *r = pv;
-    int i;
-
-    for (i = 0; i < VMXNET3_RX_RINGS_PER_QUEUE; i++) {
-        vmxnet3_get_ring_from_file(f, &r->rx_ring[i]);
-    }
-
-    vmxnet3_get_ring_from_file(f, &r->comp_ring);
-    r->intr_idx = qemu_get_byte(f);
-    r->rx_stats_pa = qemu_get_be64(f);
-
-    vmxnet3_get_rx_stats_from_file(f, &r->rxq_stats);
-
-    return 0;
-}
-
-static void vmxnet3_put_rxq_descr(QEMUFile *f, void *pv, size_t size)
-{
-    Vmxnet3RxqDescr *r = pv;
-    int i;
-
-    for (i = 0; i < VMXNET3_RX_RINGS_PER_QUEUE; i++) {
-        vmxnet3_put_ring_to_file(f, &r->rx_ring[i]);
-    }
-
-    vmxnet3_put_ring_to_file(f, &r->comp_ring);
-    qemu_put_byte(f, r->intr_idx);
-    qemu_put_be64(f, r->rx_stats_pa);
-    vmxnet3_put_rx_stats_to_file(f, &r->rxq_stats);
-}
-
-static int vmxnet3_post_load(void *opaque, int version_id)
-{
-    VMXNET3State *s = opaque;
-    PCIDevice *d = PCI_DEVICE(s);
-
-    vmxnet_tx_pkt_init(&s->tx_pkt, s->max_tx_frags, s->peer_has_vhdr);
-    vmxnet_rx_pkt_init(&s->rx_pkt, s->peer_has_vhdr);
-
-    if (s->msix_used) {
-        if  (!vmxnet3_use_msix_vectors(s, VMXNET3_MAX_INTRS)) {
-            VMW_WRPRN("Failed to re-use MSI-X vectors");
-            msix_uninit(d, &s->msix_bar, &s->msix_bar);
-            s->msix_used = false;
-            return -1;
-        }
-    }
-
-    return 0;
-}
-
-const VMStateInfo rxq_descr_info = {
-    .name = "rxq_descr",
-    .get = vmxnet3_get_rxq_descr,
-    .put = vmxnet3_put_rxq_descr
-};
-
-static int vmxnet3_get_int_state(QEMUFile *f, void *pv, size_t size)
-{
-    Vmxnet3IntState *r = pv;
-
-    r->is_masked = qemu_get_byte(f);
-    r->is_pending = qemu_get_byte(f);
-    r->is_asserted = qemu_get_byte(f);
-
-    return 0;
-}
-
-static void vmxnet3_put_int_state(QEMUFile *f, void *pv, size_t size)
-{
-    Vmxnet3IntState *r = pv;
-
-    qemu_put_byte(f, r->is_masked);
-    qemu_put_byte(f, r->is_pending);
-    qemu_put_byte(f, r->is_asserted);
-}
-
-const VMStateInfo int_state_info = {
-    .name = "int_state",
-    .get = vmxnet3_get_int_state,
-    .put = vmxnet3_put_int_state
-};
-
-static const VMStateDescription vmstate_vmxnet3 = {
-    .name = "vmxnet3",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .pre_save = vmxnet3_pre_save,
-    .post_load = vmxnet3_post_load,
-    .fields      = (VMStateField[]) {
-            VMSTATE_PCI_DEVICE(parent_obj, VMXNET3State),
-            VMSTATE_BOOL(rx_packets_compound, VMXNET3State),
-            VMSTATE_BOOL(rx_vlan_stripping, VMXNET3State),
-            VMSTATE_BOOL(lro_supported, VMXNET3State),
-            VMSTATE_UINT32(rx_mode, VMXNET3State),
-            VMSTATE_UINT32(mcast_list_len, VMXNET3State),
-            VMSTATE_UINT32(mcast_list_buff_size, VMXNET3State),
-            VMSTATE_UINT32_ARRAY(vlan_table, VMXNET3State, VMXNET3_VFT_SIZE),
-            VMSTATE_UINT32(mtu, VMXNET3State),
-            VMSTATE_UINT16(max_rx_frags, VMXNET3State),
-            VMSTATE_UINT32(max_tx_frags, VMXNET3State),
-            VMSTATE_UINT8(event_int_idx, VMXNET3State),
-            VMSTATE_BOOL(auto_int_masking, VMXNET3State),
-            VMSTATE_UINT8(txq_num, VMXNET3State),
-            VMSTATE_UINT8(rxq_num, VMXNET3State),
-            VMSTATE_UINT32(device_active, VMXNET3State),
-            VMSTATE_UINT32(last_command, VMXNET3State),
-            VMSTATE_UINT32(link_status_and_speed, VMXNET3State),
-            VMSTATE_UINT32(temp_mac, VMXNET3State),
-            VMSTATE_UINT64(drv_shmem, VMXNET3State),
-            VMSTATE_UINT64(temp_shared_guest_driver_memory, VMXNET3State),
-
-            VMSTATE_ARRAY(txq_descr, VMXNET3State,
-                VMXNET3_DEVICE_MAX_TX_QUEUES, 0, txq_descr_info,
-                Vmxnet3TxqDescr),
-            VMSTATE_ARRAY(rxq_descr, VMXNET3State,
-                VMXNET3_DEVICE_MAX_RX_QUEUES, 0, rxq_descr_info,
-                Vmxnet3RxqDescr),
-            VMSTATE_ARRAY(interrupt_states, VMXNET3State, VMXNET3_MAX_INTRS,
-                0, int_state_info, Vmxnet3IntState),
-
-            VMSTATE_END_OF_LIST()
-    },
-    .subsections = (VMStateSubsection[]) {
-        {
-            .vmsd = &vmxstate_vmxnet3_mcast_list,
-            .needed = vmxnet3_mc_list_needed
-        },
-        {
-            /* empty element. */
-        }
-    }
-};
-
-static void
-vmxnet3_write_config(PCIDevice *pci_dev, uint32_t addr, uint32_t val, int len)
-{
-    pci_default_write_config(pci_dev, addr, val, len);
-    msix_write_config(pci_dev, addr, val, len);
-    msi_write_config(pci_dev, addr, val, len);
-}
-
-static Property vmxnet3_properties[] = {
-    DEFINE_NIC_PROPERTIES(VMXNET3State, conf),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void vmxnet3_class_init(ObjectClass *class, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(class);
-    PCIDeviceClass *c = PCI_DEVICE_CLASS(class);
-
-    c->init = vmxnet3_pci_init;
-    c->exit = vmxnet3_pci_uninit;
-    c->vendor_id = PCI_VENDOR_ID_VMWARE;
-    c->device_id = PCI_DEVICE_ID_VMWARE_VMXNET3;
-    c->revision = PCI_DEVICE_ID_VMWARE_VMXNET3_REVISION;
-    c->class_id = PCI_CLASS_NETWORK_ETHERNET;
-    c->subsystem_vendor_id = PCI_VENDOR_ID_VMWARE;
-    c->subsystem_id = PCI_DEVICE_ID_VMWARE_VMXNET3;
-    c->config_write = vmxnet3_write_config,
-    dc->desc = "VMWare Paravirtualized Ethernet v3";
-    dc->reset = vmxnet3_qdev_reset;
-    dc->vmsd = &vmstate_vmxnet3;
-    dc->props = vmxnet3_properties;
-}
-
-static const TypeInfo vmxnet3_info = {
-    .name          = TYPE_VMXNET3,
-    .parent        = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(VMXNET3State),
-    .class_init    = vmxnet3_class_init,
-};
-
-static void vmxnet3_register_types(void)
-{
-    VMW_CBPRN("vmxnet3_register_types called...");
-    type_register_static(&vmxnet3_info);
-}
-
-type_init(vmxnet3_register_types)
diff --git a/hw/vmxnet3.h b/hw/vmxnet3.h
deleted file mode 100644 (file)
index 7db0c8f..0000000
+++ /dev/null
@@ -1,760 +0,0 @@
-/*
- * QEMU VMWARE VMXNET3 paravirtual NIC interface definitions
- *
- * Copyright (c) 2012 Ravello Systems LTD (http://ravellosystems.com)
- *
- * Developed by Daynix Computing LTD (http://www.daynix.com)
- *
- * Authors:
- * Dmitry Fleytman <dmitry@daynix.com>
- * Tamir Shomer <tamirs@daynix.com>
- * Yan Vugenfirer <yan@daynix.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2.
- * See the COPYING file in the top-level directory.
- *
- */
-
-#ifndef _QEMU_VMXNET3_H
-#define _QEMU_VMXNET3_H
-
-#define VMXNET3_DEVICE_MAX_TX_QUEUES 8
-#define VMXNET3_DEVICE_MAX_RX_QUEUES 8   /* Keep this value as a power of 2 */
-
-/*
- * VMWARE headers we got from Linux kernel do not fully comply QEMU coding
- * standards in sense of types and defines used.
- * Since we didn't want to change VMWARE code, following set of typedefs
- * and defines needed to compile these headers with QEMU introduced.
- */
-#define u64     uint64_t
-#define u32     uint32_t
-#define u16     uint16_t
-#define u8      uint8_t
-#define __le16  uint16_t
-#define __le32  uint32_t
-#define __le64  uint64_t
-#define __packed QEMU_PACKED
-
-#if defined(HOST_WORDS_BIGENDIAN)
-#define const_cpu_to_le64(x) bswap_64(x)
-#define __BIG_ENDIAN_BITFIELD
-#else
-#define const_cpu_to_le64(x) (x)
-#endif
-
-/*
- * Following is an interface definition for
- * VMXNET3 device as provided by VMWARE
- * See original copyright from Linux kernel v3.2.8
- * header file drivers/net/vmxnet3/vmxnet3_defs.h below.
- */
-
-/*
- * Linux driver for VMware's vmxnet3 ethernet NIC.
- *
- * Copyright (C) 2008-2009, VMware, Inc. All Rights Reserved.
- *
- * 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; version 2 of the License and no 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, GOOD TITLE or
- * NON INFRINGEMENT.  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, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * The full GNU General Public License is included in this distribution in
- * the file called "COPYING".
- *
- * Maintained by: Shreyas Bhatewara <pv-drivers@vmware.com>
- *
- */
-
-struct UPT1_TxStats {
-    u64            TSOPktsTxOK;  /* TSO pkts post-segmentation */
-    u64            TSOBytesTxOK;
-    u64            ucastPktsTxOK;
-    u64            ucastBytesTxOK;
-    u64            mcastPktsTxOK;
-    u64            mcastBytesTxOK;
-    u64            bcastPktsTxOK;
-    u64            bcastBytesTxOK;
-    u64            pktsTxError;
-    u64            pktsTxDiscard;
-};
-
-struct UPT1_RxStats {
-    u64            LROPktsRxOK;    /* LRO pkts */
-    u64            LROBytesRxOK;   /* bytes from LRO pkts */
-    /* the following counters are for pkts from the wire, i.e., pre-LRO */
-    u64            ucastPktsRxOK;
-    u64            ucastBytesRxOK;
-    u64            mcastPktsRxOK;
-    u64            mcastBytesRxOK;
-    u64            bcastPktsRxOK;
-    u64            bcastBytesRxOK;
-    u64            pktsRxOutOfBuf;
-    u64            pktsRxError;
-};
-
-/* interrupt moderation level */
-enum {
-    UPT1_IML_NONE        = 0, /* no interrupt moderation */
-    UPT1_IML_HIGHEST    = 7, /* least intr generated */
-    UPT1_IML_ADAPTIVE    = 8, /* adpative intr moderation */
-};
-/* values for UPT1_RSSConf.hashFunc */
-enum {
-    UPT1_RSS_HASH_TYPE_NONE      = 0x0,
-    UPT1_RSS_HASH_TYPE_IPV4      = 0x01,
-    UPT1_RSS_HASH_TYPE_TCP_IPV4  = 0x02,
-    UPT1_RSS_HASH_TYPE_IPV6      = 0x04,
-    UPT1_RSS_HASH_TYPE_TCP_IPV6  = 0x08,
-};
-
-enum {
-    UPT1_RSS_HASH_FUNC_NONE      = 0x0,
-    UPT1_RSS_HASH_FUNC_TOEPLITZ  = 0x01,
-};
-
-#define UPT1_RSS_MAX_KEY_SIZE        40
-#define UPT1_RSS_MAX_IND_TABLE_SIZE  128
-
-struct UPT1_RSSConf {
-    u16            hashType;
-    u16            hashFunc;
-    u16            hashKeySize;
-    u16            indTableSize;
-    u8            hashKey[UPT1_RSS_MAX_KEY_SIZE];
-    u8            indTable[UPT1_RSS_MAX_IND_TABLE_SIZE];
-};
-
-/* features */
-enum {
-    UPT1_F_RXCSUM        = const_cpu_to_le64(0x0001), /* rx csum verification */
-    UPT1_F_RSS        = const_cpu_to_le64(0x0002),
-    UPT1_F_RXVLAN        = const_cpu_to_le64(0x0004), /* VLAN tag stripping */
-    UPT1_F_LRO        = const_cpu_to_le64(0x0008),
-};
-
-/* all registers are 32 bit wide */
-/* BAR 1 */
-enum {
-    VMXNET3_REG_VRRS    = 0x0,    /* Vmxnet3 Revision Report Selection */
-    VMXNET3_REG_UVRS    = 0x8,    /* UPT Version Report Selection */
-    VMXNET3_REG_DSAL    = 0x10,    /* Driver Shared Address Low */
-    VMXNET3_REG_DSAH    = 0x18,    /* Driver Shared Address High */
-    VMXNET3_REG_CMD        = 0x20,    /* Command */
-    VMXNET3_REG_MACL    = 0x28,    /* MAC Address Low */
-    VMXNET3_REG_MACH    = 0x30,    /* MAC Address High */
-    VMXNET3_REG_ICR        = 0x38,    /* Interrupt Cause Register */
-    VMXNET3_REG_ECR        = 0x40    /* Event Cause Register */
-};
-
-/* BAR 0 */
-enum {
-    VMXNET3_REG_IMR        = 0x0,     /* Interrupt Mask Register */
-    VMXNET3_REG_TXPROD    = 0x600, /* Tx Producer Index */
-    VMXNET3_REG_RXPROD    = 0x800, /* Rx Producer Index for ring 1 */
-    VMXNET3_REG_RXPROD2    = 0xA00     /* Rx Producer Index for ring 2 */
-};
-
-#define VMXNET3_PT_REG_SIZE     4096    /* BAR 0 */
-#define VMXNET3_VD_REG_SIZE     4096    /* BAR 1 */
-
-#define VMXNET3_REG_ALIGN       8    /* All registers are 8-byte aligned. */
-#define VMXNET3_REG_ALIGN_MASK  0x7
-
-/* I/O Mapped access to registers */
-#define VMXNET3_IO_TYPE_PT              0
-#define VMXNET3_IO_TYPE_VD              1
-#define VMXNET3_IO_ADDR(type, reg)      (((type) << 24) | ((reg) & 0xFFFFFF))
-#define VMXNET3_IO_TYPE(addr)           ((addr) >> 24)
-#define VMXNET3_IO_REG(addr)            ((addr) & 0xFFFFFF)
-
-enum {
-    VMXNET3_CMD_FIRST_SET = 0xCAFE0000,
-    VMXNET3_CMD_ACTIVATE_DEV = VMXNET3_CMD_FIRST_SET, /* 0xCAFE0000 */
-    VMXNET3_CMD_QUIESCE_DEV,                          /* 0xCAFE0001 */
-    VMXNET3_CMD_RESET_DEV,                            /* 0xCAFE0002 */
-    VMXNET3_CMD_UPDATE_RX_MODE,                       /* 0xCAFE0003 */
-    VMXNET3_CMD_UPDATE_MAC_FILTERS,                   /* 0xCAFE0004 */
-    VMXNET3_CMD_UPDATE_VLAN_FILTERS,                  /* 0xCAFE0005 */
-    VMXNET3_CMD_UPDATE_RSSIDT,                        /* 0xCAFE0006 */
-    VMXNET3_CMD_UPDATE_IML,                           /* 0xCAFE0007 */
-    VMXNET3_CMD_UPDATE_PMCFG,                         /* 0xCAFE0008 */
-    VMXNET3_CMD_UPDATE_FEATURE,                       /* 0xCAFE0009 */
-    VMXNET3_CMD_LOAD_PLUGIN,                          /* 0xCAFE000A */
-
-    VMXNET3_CMD_FIRST_GET = 0xF00D0000,
-    VMXNET3_CMD_GET_QUEUE_STATUS = VMXNET3_CMD_FIRST_GET, /* 0xF00D0000 */
-    VMXNET3_CMD_GET_STATS,                                /* 0xF00D0001 */
-    VMXNET3_CMD_GET_LINK,                                 /* 0xF00D0002 */
-    VMXNET3_CMD_GET_PERM_MAC_LO,                          /* 0xF00D0003 */
-    VMXNET3_CMD_GET_PERM_MAC_HI,                          /* 0xF00D0004 */
-    VMXNET3_CMD_GET_DID_LO,                               /* 0xF00D0005 */
-    VMXNET3_CMD_GET_DID_HI,                               /* 0xF00D0006 */
-    VMXNET3_CMD_GET_DEV_EXTRA_INFO,                       /* 0xF00D0007 */
-    VMXNET3_CMD_GET_CONF_INTR                             /* 0xF00D0008 */
-};
-
-/*
- *    Little Endian layout of bitfields -
- *    Byte 0 :    7.....len.....0
- *    Byte 1 :    rsvd gen 13.len.8
- *    Byte 2 :     5.msscof.0 ext1  dtype
- *    Byte 3 :     13...msscof...6
- *
- *    Big Endian layout of bitfields -
- *    Byte 0:        13...msscof...6
- *    Byte 1 :     5.msscof.0 ext1  dtype
- *    Byte 2 :    rsvd gen 13.len.8
- *    Byte 3 :    7.....len.....0
- *
- *    Thus, le32_to_cpu on the dword will allow the big endian driver to read
- *    the bit fields correctly. And cpu_to_le32 will convert bitfields
- *    bit fields written by big endian driver to format required by device.
- */
-
-struct Vmxnet3_TxDesc {
-    __le64 addr;
-
-#ifdef __BIG_ENDIAN_BITFIELD
-    u32 msscof:14;  /* MSS, checksum offset, flags */
-    u32 ext1:1;
-    u32 dtype:1;    /* descriptor type */
-    u32 rsvd:1;
-    u32 gen:1;      /* generation bit */
-    u32 len:14;
-#else
-    u32 len:14;
-    u32 gen:1;      /* generation bit */
-    u32 rsvd:1;
-    u32 dtype:1;    /* descriptor type */
-    u32 ext1:1;
-    u32 msscof:14;  /* MSS, checksum offset, flags */
-#endif  /* __BIG_ENDIAN_BITFIELD */
-
-#ifdef __BIG_ENDIAN_BITFIELD
-    u32 tci:16;     /* Tag to Insert */
-    u32 ti:1;       /* VLAN Tag Insertion */
-    u32 ext2:1;
-    u32 cq:1;       /* completion request */
-    u32 eop:1;      /* End Of Packet */
-    u32 om:2;       /* offload mode */
-    u32 hlen:10;    /* header len */
-#else
-    u32 hlen:10;    /* header len */
-    u32 om:2;       /* offload mode */
-    u32 eop:1;      /* End Of Packet */
-    u32 cq:1;       /* completion request */
-    u32 ext2:1;
-    u32 ti:1;       /* VLAN Tag Insertion */
-    u32 tci:16;     /* Tag to Insert */
-#endif  /* __BIG_ENDIAN_BITFIELD */
-};
-
-/* TxDesc.OM values */
-#define VMXNET3_OM_NONE        0
-#define VMXNET3_OM_CSUM        2
-#define VMXNET3_OM_TSO        3
-
-/* fields in TxDesc we access w/o using bit fields */
-#define VMXNET3_TXD_EOP_SHIFT    12
-#define VMXNET3_TXD_CQ_SHIFT    13
-#define VMXNET3_TXD_GEN_SHIFT    14
-#define VMXNET3_TXD_EOP_DWORD_SHIFT 3
-#define VMXNET3_TXD_GEN_DWORD_SHIFT 2
-
-#define VMXNET3_TXD_CQ        (1 << VMXNET3_TXD_CQ_SHIFT)
-#define VMXNET3_TXD_EOP        (1 << VMXNET3_TXD_EOP_SHIFT)
-#define VMXNET3_TXD_GEN        (1 << VMXNET3_TXD_GEN_SHIFT)
-
-#define VMXNET3_HDR_COPY_SIZE   128
-
-
-struct Vmxnet3_TxDataDesc {
-    u8        data[VMXNET3_HDR_COPY_SIZE];
-};
-
-#define VMXNET3_TCD_GEN_SHIFT    31
-#define VMXNET3_TCD_GEN_SIZE    1
-#define VMXNET3_TCD_TXIDX_SHIFT    0
-#define VMXNET3_TCD_TXIDX_SIZE    12
-#define VMXNET3_TCD_GEN_DWORD_SHIFT    3
-
-struct Vmxnet3_TxCompDesc {
-    u32        txdIdx:12;    /* Index of the EOP TxDesc */
-    u32        ext1:20;
-
-    __le32        ext2;
-    __le32        ext3;
-
-    u32        rsvd:24;
-    u32        type:7;       /* completion type */
-    u32        gen:1;        /* generation bit */
-};
-
-struct Vmxnet3_RxDesc {
-    __le64        addr;
-
-#ifdef __BIG_ENDIAN_BITFIELD
-    u32        gen:1;        /* Generation bit */
-    u32        rsvd:15;
-    u32        dtype:1;      /* Descriptor type */
-    u32        btype:1;      /* Buffer Type */
-    u32        len:14;
-#else
-    u32        len:14;
-    u32        btype:1;      /* Buffer Type */
-    u32        dtype:1;      /* Descriptor type */
-    u32        rsvd:15;
-    u32        gen:1;        /* Generation bit */
-#endif
-    u32        ext1;
-};
-
-/* values of RXD.BTYPE */
-#define VMXNET3_RXD_BTYPE_HEAD   0    /* head only */
-#define VMXNET3_RXD_BTYPE_BODY   1    /* body only */
-
-/* fields in RxDesc we access w/o using bit fields */
-#define VMXNET3_RXD_BTYPE_SHIFT  14
-#define VMXNET3_RXD_GEN_SHIFT    31
-
-struct Vmxnet3_RxCompDesc {
-#ifdef __BIG_ENDIAN_BITFIELD
-    u32        ext2:1;
-    u32        cnc:1;        /* Checksum Not Calculated */
-    u32        rssType:4;    /* RSS hash type used */
-    u32        rqID:10;      /* rx queue/ring ID */
-    u32        sop:1;        /* Start of Packet */
-    u32        eop:1;        /* End of Packet */
-    u32        ext1:2;
-    u32        rxdIdx:12;    /* Index of the RxDesc */
-#else
-    u32        rxdIdx:12;    /* Index of the RxDesc */
-    u32        ext1:2;
-    u32        eop:1;        /* End of Packet */
-    u32        sop:1;        /* Start of Packet */
-    u32        rqID:10;      /* rx queue/ring ID */
-    u32        rssType:4;    /* RSS hash type used */
-    u32        cnc:1;        /* Checksum Not Calculated */
-    u32        ext2:1;
-#endif  /* __BIG_ENDIAN_BITFIELD */
-
-    __le32        rssHash;      /* RSS hash value */
-
-#ifdef __BIG_ENDIAN_BITFIELD
-    u32        tci:16;       /* Tag stripped */
-    u32        ts:1;         /* Tag is stripped */
-    u32        err:1;        /* Error */
-    u32        len:14;       /* data length */
-#else
-    u32        len:14;       /* data length */
-    u32        err:1;        /* Error */
-    u32        ts:1;         /* Tag is stripped */
-    u32        tci:16;       /* Tag stripped */
-#endif  /* __BIG_ENDIAN_BITFIELD */
-
-
-#ifdef __BIG_ENDIAN_BITFIELD
-    u32        gen:1;        /* generation bit */
-    u32        type:7;       /* completion type */
-    u32        fcs:1;        /* Frame CRC correct */
-    u32        frg:1;        /* IP Fragment */
-    u32        v4:1;         /* IPv4 */
-    u32        v6:1;         /* IPv6 */
-    u32        ipc:1;        /* IP Checksum Correct */
-    u32        tcp:1;        /* TCP packet */
-    u32        udp:1;        /* UDP packet */
-    u32        tuc:1;        /* TCP/UDP Checksum Correct */
-    u32        csum:16;
-#else
-    u32        csum:16;
-    u32        tuc:1;        /* TCP/UDP Checksum Correct */
-    u32        udp:1;        /* UDP packet */
-    u32        tcp:1;        /* TCP packet */
-    u32        ipc:1;        /* IP Checksum Correct */
-    u32        v6:1;         /* IPv6 */
-    u32        v4:1;         /* IPv4 */
-    u32        frg:1;        /* IP Fragment */
-    u32        fcs:1;        /* Frame CRC correct */
-    u32        type:7;       /* completion type */
-    u32        gen:1;        /* generation bit */
-#endif  /* __BIG_ENDIAN_BITFIELD */
-};
-
-/* fields in RxCompDesc we access via Vmxnet3_GenericDesc.dword[3] */
-#define VMXNET3_RCD_TUC_SHIFT    16
-#define VMXNET3_RCD_IPC_SHIFT    19
-
-/* fields in RxCompDesc we access via Vmxnet3_GenericDesc.qword[1] */
-#define VMXNET3_RCD_TYPE_SHIFT    56
-#define VMXNET3_RCD_GEN_SHIFT    63
-
-/* csum OK for TCP/UDP pkts over IP */
-#define VMXNET3_RCD_CSUM_OK (1 << VMXNET3_RCD_TUC_SHIFT | \
-                     1 << VMXNET3_RCD_IPC_SHIFT)
-#define VMXNET3_TXD_GEN_SIZE 1
-#define VMXNET3_TXD_EOP_SIZE 1
-
-/* value of RxCompDesc.rssType */
-enum {
-    VMXNET3_RCD_RSS_TYPE_NONE     = 0,
-    VMXNET3_RCD_RSS_TYPE_IPV4     = 1,
-    VMXNET3_RCD_RSS_TYPE_TCPIPV4  = 2,
-    VMXNET3_RCD_RSS_TYPE_IPV6     = 3,
-    VMXNET3_RCD_RSS_TYPE_TCPIPV6  = 4,
-};
-
-
-/* a union for accessing all cmd/completion descriptors */
-union Vmxnet3_GenericDesc {
-    __le64                qword[2];
-    __le32                dword[4];
-    __le16                word[8];
-    struct Vmxnet3_TxDesc        txd;
-    struct Vmxnet3_RxDesc        rxd;
-    struct Vmxnet3_TxCompDesc    tcd;
-    struct Vmxnet3_RxCompDesc    rcd;
-};
-
-#define VMXNET3_INIT_GEN       1
-
-/* Max size of a single tx buffer */
-#define VMXNET3_MAX_TX_BUF_SIZE  (1 << 14)
-
-/* # of tx desc needed for a tx buffer size */
-#define VMXNET3_TXD_NEEDED(size) (((size) + VMXNET3_MAX_TX_BUF_SIZE - 1) / \
-                    VMXNET3_MAX_TX_BUF_SIZE)
-
-/* max # of tx descs for a non-tso pkt */
-#define VMXNET3_MAX_TXD_PER_PKT 16
-
-/* Max size of a single rx buffer */
-#define VMXNET3_MAX_RX_BUF_SIZE  ((1 << 14) - 1)
-/* Minimum size of a type 0 buffer */
-#define VMXNET3_MIN_T0_BUF_SIZE  128
-#define VMXNET3_MAX_CSUM_OFFSET  1024
-
-/* Ring base address alignment */
-#define VMXNET3_RING_BA_ALIGN   512
-#define VMXNET3_RING_BA_MASK    (VMXNET3_RING_BA_ALIGN - 1)
-
-/* Ring size must be a multiple of 32 */
-#define VMXNET3_RING_SIZE_ALIGN 32
-#define VMXNET3_RING_SIZE_MASK  (VMXNET3_RING_SIZE_ALIGN - 1)
-
-/* Max ring size */
-#define VMXNET3_TX_RING_MAX_SIZE   4096
-#define VMXNET3_TC_RING_MAX_SIZE   4096
-#define VMXNET3_RX_RING_MAX_SIZE   4096
-#define VMXNET3_RC_RING_MAX_SIZE   8192
-
-/* a list of reasons for queue stop */
-
-enum {
- VMXNET3_ERR_NOEOP        = 0x80000000, /* cannot find the EOP desc of a pkt */
- VMXNET3_ERR_TXD_REUSE    = 0x80000001, /* reuse TxDesc before tx completion */
- VMXNET3_ERR_BIG_PKT      = 0x80000002, /* too many TxDesc for a pkt */
- VMXNET3_ERR_DESC_NOT_SPT = 0x80000003, /* descriptor type not supported */
- VMXNET3_ERR_SMALL_BUF    = 0x80000004, /* type 0 buffer too small */
- VMXNET3_ERR_STRESS       = 0x80000005, /* stress option firing in vmkernel */
- VMXNET3_ERR_SWITCH       = 0x80000006, /* mode switch failure */
- VMXNET3_ERR_TXD_INVALID  = 0x80000007, /* invalid TxDesc */
-};
-
-/* completion descriptor types */
-#define VMXNET3_CDTYPE_TXCOMP      0    /* Tx Completion Descriptor */
-#define VMXNET3_CDTYPE_RXCOMP      3    /* Rx Completion Descriptor */
-
-enum {
-    VMXNET3_GOS_BITS_UNK    = 0,   /* unknown */
-    VMXNET3_GOS_BITS_32     = 1,
-    VMXNET3_GOS_BITS_64     = 2,
-};
-
-#define VMXNET3_GOS_TYPE_UNK        0 /* unknown */
-#define VMXNET3_GOS_TYPE_LINUX      1
-#define VMXNET3_GOS_TYPE_WIN        2
-#define VMXNET3_GOS_TYPE_SOLARIS    3
-#define VMXNET3_GOS_TYPE_FREEBSD    4
-#define VMXNET3_GOS_TYPE_PXE        5
-
-struct Vmxnet3_GOSInfo {
-#ifdef __BIG_ENDIAN_BITFIELD
-    u32        gosMisc:10;    /* other info about gos */
-    u32        gosVer:16;     /* gos version */
-    u32        gosType:4;     /* which guest */
-    u32        gosBits:2;    /* 32-bit or 64-bit? */
-#else
-    u32        gosBits:2;     /* 32-bit or 64-bit? */
-    u32        gosType:4;     /* which guest */
-    u32        gosVer:16;     /* gos version */
-    u32        gosMisc:10;    /* other info about gos */
-#endif  /* __BIG_ENDIAN_BITFIELD */
-};
-
-struct Vmxnet3_DriverInfo {
-    __le32                version;
-    struct Vmxnet3_GOSInfo        gos;
-    __le32                vmxnet3RevSpt;
-    __le32                uptVerSpt;
-};
-
-
-#define VMXNET3_REV1_MAGIC  0xbabefee1
-
-/*
- * QueueDescPA must be 128 bytes aligned. It points to an array of
- * Vmxnet3_TxQueueDesc followed by an array of Vmxnet3_RxQueueDesc.
- * The number of Vmxnet3_TxQueueDesc/Vmxnet3_RxQueueDesc are specified by
- * Vmxnet3_MiscConf.numTxQueues/numRxQueues, respectively.
- */
-#define VMXNET3_QUEUE_DESC_ALIGN  128
-
-
-struct Vmxnet3_MiscConf {
-    struct Vmxnet3_DriverInfo driverInfo;
-    __le64        uptFeatures;
-    __le64        ddPA;         /* driver data PA */
-    __le64        queueDescPA;  /* queue descriptor table PA */
-    __le32        ddLen;        /* driver data len */
-    __le32        queueDescLen; /* queue desc. table len in bytes */
-    __le32        mtu;
-    __le16        maxNumRxSG;
-    u8        numTxQueues;
-    u8        numRxQueues;
-    __le32        reserved[4];
-};
-
-
-struct Vmxnet3_TxQueueConf {
-    __le64        txRingBasePA;
-    __le64        dataRingBasePA;
-    __le64        compRingBasePA;
-    __le64        ddPA;         /* driver data */
-    __le64        reserved;
-    __le32        txRingSize;   /* # of tx desc */
-    __le32        dataRingSize; /* # of data desc */
-    __le32        compRingSize; /* # of comp desc */
-    __le32        ddLen;        /* size of driver data */
-    u8        intrIdx;
-    u8        _pad[7];
-};
-
-
-struct Vmxnet3_RxQueueConf {
-    __le64        rxRingBasePA[2];
-    __le64        compRingBasePA;
-    __le64        ddPA;            /* driver data */
-    __le64        reserved;
-    __le32        rxRingSize[2];   /* # of rx desc */
-    __le32        compRingSize;    /* # of rx comp desc */
-    __le32        ddLen;           /* size of driver data */
-    u8        intrIdx;
-    u8        _pad[7];
-};
-
-
-enum vmxnet3_intr_mask_mode {
-    VMXNET3_IMM_AUTO   = 0,
-    VMXNET3_IMM_ACTIVE = 1,
-    VMXNET3_IMM_LAZY   = 2
-};
-
-enum vmxnet3_intr_type {
-    VMXNET3_IT_AUTO = 0,
-    VMXNET3_IT_INTX = 1,
-    VMXNET3_IT_MSI  = 2,
-    VMXNET3_IT_MSIX = 3
-};
-
-#define VMXNET3_MAX_TX_QUEUES  8
-#define VMXNET3_MAX_RX_QUEUES  16
-/* addition 1 for events */
-#define VMXNET3_MAX_INTRS      25
-
-/* value of intrCtrl */
-#define VMXNET3_IC_DISABLE_ALL  0x1   /* bit 0 */
-
-
-struct Vmxnet3_IntrConf {
-    bool        autoMask;
-    u8        numIntrs;      /* # of interrupts */
-    u8        eventIntrIdx;
-    u8        modLevels[VMXNET3_MAX_INTRS];    /* moderation level for
-                             * each intr */
-    __le32        intrCtrl;
-    __le32        reserved[2];
-};
-
-/* one bit per VLAN ID, the size is in the units of u32 */
-#define VMXNET3_VFT_SIZE  (4096/(sizeof(uint32_t)*8))
-
-
-struct Vmxnet3_QueueStatus {
-    bool        stopped;
-    u8        _pad[3];
-    __le32        error;
-};
-
-
-struct Vmxnet3_TxQueueCtrl {
-    __le32        txNumDeferred;
-    __le32        txThreshold;
-    __le64        reserved;
-};
-
-
-struct Vmxnet3_RxQueueCtrl {
-    bool        updateRxProd;
-    u8        _pad[7];
-    __le64        reserved;
-};
-
-enum {
-    VMXNET3_RXM_UCAST     = 0x01,  /* unicast only */
-    VMXNET3_RXM_MCAST     = 0x02,  /* multicast passing the filters */
-    VMXNET3_RXM_BCAST     = 0x04,  /* broadcast only */
-    VMXNET3_RXM_ALL_MULTI = 0x08,  /* all multicast */
-    VMXNET3_RXM_PROMISC   = 0x10  /* promiscuous */
-};
-
-struct Vmxnet3_RxFilterConf {
-    __le32        rxMode;       /* VMXNET3_RXM_xxx */
-    __le16        mfTableLen;   /* size of the multicast filter table */
-    __le16        _pad1;
-    __le64        mfTablePA;    /* PA of the multicast filters table */
-    __le32        vfTable[VMXNET3_VFT_SIZE]; /* vlan filter */
-};
-
-
-#define VMXNET3_PM_MAX_FILTERS        6
-#define VMXNET3_PM_MAX_PATTERN_SIZE   128
-#define VMXNET3_PM_MAX_MASK_SIZE      (VMXNET3_PM_MAX_PATTERN_SIZE / 8)
-
-#define VMXNET3_PM_WAKEUP_MAGIC  cpu_to_le16(0x01)  /* wake up on magic pkts */
-#define VMXNET3_PM_WAKEUP_FILTER cpu_to_le16(0x02)  /* wake up on pkts matching
-                                                     * filters */
-
-
-struct Vmxnet3_PM_PktFilter {
-    u8        maskSize;
-    u8        patternSize;
-    u8        mask[VMXNET3_PM_MAX_MASK_SIZE];
-    u8        pattern[VMXNET3_PM_MAX_PATTERN_SIZE];
-    u8        pad[6];
-};
-
-
-struct Vmxnet3_PMConf {
-    __le16        wakeUpEvents;  /* VMXNET3_PM_WAKEUP_xxx */
-    u8        numFilters;
-    u8        pad[5];
-    struct Vmxnet3_PM_PktFilter filters[VMXNET3_PM_MAX_FILTERS];
-};
-
-
-struct Vmxnet3_VariableLenConfDesc {
-    __le32        confVer;
-    __le32        confLen;
-    __le64        confPA;
-};
-
-
-struct Vmxnet3_TxQueueDesc {
-    struct Vmxnet3_TxQueueCtrl        ctrl;
-    struct Vmxnet3_TxQueueConf        conf;
-
-    /* Driver read after a GET command */
-    struct Vmxnet3_QueueStatus        status;
-    struct UPT1_TxStats            stats;
-    u8                    _pad[88]; /* 128 aligned */
-};
-
-
-struct Vmxnet3_RxQueueDesc {
-    struct Vmxnet3_RxQueueCtrl        ctrl;
-    struct Vmxnet3_RxQueueConf        conf;
-    /* Driver read after a GET commad */
-    struct Vmxnet3_QueueStatus        status;
-    struct UPT1_RxStats            stats;
-    u8                      __pad[88]; /* 128 aligned */
-};
-
-
-struct Vmxnet3_DSDevRead {
-    /* read-only region for device, read by dev in response to a SET cmd */
-    struct Vmxnet3_MiscConf            misc;
-    struct Vmxnet3_IntrConf            intrConf;
-    struct Vmxnet3_RxFilterConf        rxFilterConf;
-    struct Vmxnet3_VariableLenConfDesc    rssConfDesc;
-    struct Vmxnet3_VariableLenConfDesc    pmConfDesc;
-    struct Vmxnet3_VariableLenConfDesc    pluginConfDesc;
-};
-
-/* All structures in DriverShared are padded to multiples of 8 bytes */
-struct Vmxnet3_DriverShared {
-    __le32              magic;
-    /* make devRead start at 64bit boundaries */
-    __le32              pad;
-    struct Vmxnet3_DSDevRead    devRead;
-    __le32              ecr;
-    __le32              reserved[5];
-};
-
-
-#define VMXNET3_ECR_RQERR       (1 << 0)
-#define VMXNET3_ECR_TQERR       (1 << 1)
-#define VMXNET3_ECR_LINK        (1 << 2)
-#define VMXNET3_ECR_DIC         (1 << 3)
-#define VMXNET3_ECR_DEBUG       (1 << 4)
-
-/* flip the gen bit of a ring */
-#define VMXNET3_FLIP_RING_GEN(gen) ((gen) = (gen) ^ 0x1)
-
-/* only use this if moving the idx won't affect the gen bit */
-#define VMXNET3_INC_RING_IDX_ONLY(idx, ring_size) \
-    do {\
-        (idx)++;\
-        if (unlikely((idx) == (ring_size))) {\
-            (idx) = 0;\
-        } \
-    } while (0)
-
-#define VMXNET3_SET_VFTABLE_ENTRY(vfTable, vid) \
-    (vfTable[vid >> 5] |= (1 << (vid & 31)))
-#define VMXNET3_CLEAR_VFTABLE_ENTRY(vfTable, vid) \
-    (vfTable[vid >> 5] &= ~(1 << (vid & 31)))
-
-#define VMXNET3_VFTABLE_ENTRY_IS_SET(vfTable, vid) \
-    ((vfTable[vid >> 5] & (1 << (vid & 31))) != 0)
-
-#define VMXNET3_MAX_MTU     9000
-#define VMXNET3_MIN_MTU     60
-
-#define VMXNET3_LINK_UP         (10000 << 16 | 1)    /* 10 Gbps, up */
-#define VMXNET3_LINK_DOWN       0
-
-#undef u64
-#undef u32
-#undef u16
-#undef u8
-#undef __le16
-#undef __le32
-#undef __le64
-#undef __packed
-#undef const_cpu_to_le64
-#if defined(HOST_WORDS_BIGENDIAN)
-#undef __BIG_ENDIAN_BITFIELD
-#endif
-
-#endif
diff --git a/hw/vmxnet_debug.h b/hw/vmxnet_debug.h
deleted file mode 100644 (file)
index 96dae0f..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * QEMU VMWARE VMXNET* paravirtual NICs - debugging facilities
- *
- * Copyright (c) 2012 Ravello Systems LTD (http://ravellosystems.com)
- *
- * Developed by Daynix Computing LTD (http://www.daynix.com)
- *
- * Authors:
- * Dmitry Fleytman <dmitry@daynix.com>
- * Tamir Shomer <tamirs@daynix.com>
- * Yan Vugenfirer <yan@daynix.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_VMXNET_DEBUG_H
-#define _QEMU_VMXNET_DEBUG_H
-
-#define VMXNET_DEVICE_NAME "vmxnet3"
-
-/* #define VMXNET_DEBUG_CB */
-#define VMXNET_DEBUG_WARNINGS
-#define VMXNET_DEBUG_ERRORS
-/* #define VMXNET_DEBUG_INTERRUPTS */
-/* #define VMXNET_DEBUG_CONFIG */
-/* #define VMXNET_DEBUG_RINGS */
-/* #define VMXNET_DEBUG_PACKETS */
-/* #define VMXNET_DEBUG_SHMEM_ACCESS */
-
-#ifdef VMXNET_DEBUG_SHMEM_ACCESS
-#define VMW_SHPRN(fmt, ...)                                                   \
-    do {                                                                      \
-        printf("[%s][SH][%s]: " fmt "\n", VMXNET_DEVICE_NAME, __func__,       \
-            ## __VA_ARGS__);                                                  \
-    } while (0)
-#else
-#define VMW_SHPRN(fmt, ...) do {} while (0)
-#endif
-
-#ifdef VMXNET_DEBUG_CB
-#define VMW_CBPRN(fmt, ...)                                                   \
-    do {                                                                      \
-        printf("[%s][CB][%s]: " fmt "\n", VMXNET_DEVICE_NAME, __func__,       \
-            ## __VA_ARGS__);                                                  \
-    } while (0)
-#else
-#define VMW_CBPRN(fmt, ...) do {} while (0)
-#endif
-
-#ifdef VMXNET_DEBUG_PACKETS
-#define VMW_PKPRN(fmt, ...)                                                   \
-    do {                                                                      \
-        printf("[%s][PK][%s]: " fmt "\n", VMXNET_DEVICE_NAME, __func__,       \
-            ## __VA_ARGS__);                                                  \
-    } while (0)
-#else
-#define VMW_PKPRN(fmt, ...) do {} while (0)
-#endif
-
-#ifdef VMXNET_DEBUG_WARNINGS
-#define VMW_WRPRN(fmt, ...)                                                   \
-    do {                                                                      \
-        printf("[%s][WR][%s]: " fmt "\n", VMXNET_DEVICE_NAME, __func__,       \
-            ## __VA_ARGS__);                                                  \
-    } while (0)
-#else
-#define VMW_WRPRN(fmt, ...) do {} while (0)
-#endif
-
-#ifdef VMXNET_DEBUG_ERRORS
-#define VMW_ERPRN(fmt, ...)                                                   \
-    do {                                                                      \
-        printf("[%s][ER][%s]: " fmt "\n", VMXNET_DEVICE_NAME, __func__,       \
-            ## __VA_ARGS__);                                                  \
-    } while (0)
-#else
-#define VMW_ERPRN(fmt, ...) do {} while (0)
-#endif
-
-#ifdef VMXNET_DEBUG_INTERRUPTS
-#define VMW_IRPRN(fmt, ...)                                                   \
-    do {                                                                      \
-        printf("[%s][IR][%s]: " fmt "\n", VMXNET_DEVICE_NAME, __func__,       \
-            ## __VA_ARGS__);                                                  \
-    } while (0)
-#else
-#define VMW_IRPRN(fmt, ...) do {} while (0)
-#endif
-
-#ifdef VMXNET_DEBUG_CONFIG
-#define VMW_CFPRN(fmt, ...)                                                   \
-    do {                                                                      \
-        printf("[%s][CF][%s]: " fmt "\n", VMXNET_DEVICE_NAME, __func__,       \
-            ## __VA_ARGS__);                                                  \
-    } while (0)
-#else
-#define VMW_CFPRN(fmt, ...) do {} while (0)
-#endif
-
-#ifdef VMXNET_DEBUG_RINGS
-#define VMW_RIPRN(fmt, ...)                                                   \
-    do {                                                                      \
-        printf("[%s][RI][%s]: " fmt "\n", VMXNET_DEVICE_NAME, __func__,       \
-            ## __VA_ARGS__);                                                  \
-    } while (0)
-#else
-#define VMW_RIPRN(fmt, ...) do {} while (0)
-#endif
-
-#define VMXNET_MF       "%02X:%02X:%02X:%02X:%02X:%02X"
-#define VMXNET_MA(a)    (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
-
-#endif /* _QEMU_VMXNET3_DEBUG_H  */
diff --git a/hw/vmxnet_rx_pkt.c b/hw/vmxnet_rx_pkt.c
deleted file mode 100644 (file)
index a40e346..0000000
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * QEMU VMWARE VMXNET* paravirtual NICs - RX packets abstractions
- *
- * Copyright (c) 2012 Ravello Systems LTD (http://ravellosystems.com)
- *
- * Developed by Daynix Computing LTD (http://www.daynix.com)
- *
- * Authors:
- * Dmitry Fleytman <dmitry@daynix.com>
- * Tamir Shomer <tamirs@daynix.com>
- * Yan Vugenfirer <yan@daynix.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 "vmxnet_rx_pkt.h"
-#include "net/eth.h"
-#include "qemu-common.h"
-#include "qemu/iov.h"
-#include "net/checksum.h"
-#include "net/tap.h"
-
-/*
- * RX packet may contain up to 2 fragments - rebuilt eth header
- * in case of VLAN tag stripping
- * and payload received from QEMU - in any case
- */
-#define VMXNET_MAX_RX_PACKET_FRAGMENTS (2)
-
-struct VmxnetRxPkt {
-    struct virtio_net_hdr virt_hdr;
-    uint8_t ehdr_buf[ETH_MAX_L2_HDR_LEN];
-    struct iovec vec[VMXNET_MAX_RX_PACKET_FRAGMENTS];
-    uint16_t vec_len;
-    uint32_t tot_len;
-    uint16_t tci;
-    bool vlan_stripped;
-    bool has_virt_hdr;
-    eth_pkt_types_e packet_type;
-
-    /* Analysis results */
-    bool isip4;
-    bool isip6;
-    bool isudp;
-    bool istcp;
-};
-
-void vmxnet_rx_pkt_init(struct VmxnetRxPkt **pkt, bool has_virt_hdr)
-{
-    struct VmxnetRxPkt *p = g_malloc0(sizeof *p);
-    p->has_virt_hdr = has_virt_hdr;
-    *pkt = p;
-}
-
-void vmxnet_rx_pkt_uninit(struct VmxnetRxPkt *pkt)
-{
-    g_free(pkt);
-}
-
-struct virtio_net_hdr *vmxnet_rx_pkt_get_vhdr(struct VmxnetRxPkt *pkt)
-{
-    assert(pkt);
-    return &pkt->virt_hdr;
-}
-
-void vmxnet_rx_pkt_attach_data(struct VmxnetRxPkt *pkt, const void *data,
-                               size_t len, bool strip_vlan)
-{
-    uint16_t tci = 0;
-    uint16_t ploff;
-    assert(pkt);
-    pkt->vlan_stripped = false;
-
-    if (strip_vlan) {
-        pkt->vlan_stripped = eth_strip_vlan(data, pkt->ehdr_buf, &ploff, &tci);
-    }
-
-    if (pkt->vlan_stripped) {
-        pkt->vec[0].iov_base = pkt->ehdr_buf;
-        pkt->vec[0].iov_len = ploff - sizeof(struct vlan_header);
-        pkt->vec[1].iov_base = (uint8_t *) data + ploff;
-        pkt->vec[1].iov_len = len - ploff;
-        pkt->vec_len = 2;
-        pkt->tot_len = len - ploff + sizeof(struct eth_header);
-    } else {
-        pkt->vec[0].iov_base = (void *)data;
-        pkt->vec[0].iov_len = len;
-        pkt->vec_len = 1;
-        pkt->tot_len = len;
-    }
-
-    pkt->tci = tci;
-
-    eth_get_protocols(data, len, &pkt->isip4, &pkt->isip6,
-        &pkt->isudp, &pkt->istcp);
-}
-
-void vmxnet_rx_pkt_dump(struct VmxnetRxPkt *pkt)
-{
-#ifdef VMXNET_RX_PKT_DEBUG
-    VmxnetRxPkt *pkt = (VmxnetRxPkt *)pkt;
-    assert(pkt);
-
-    printf("RX PKT: tot_len: %d, vlan_stripped: %d, vlan_tag: %d\n",
-              pkt->tot_len, pkt->vlan_stripped, pkt->tci);
-#endif
-}
-
-void vmxnet_rx_pkt_set_packet_type(struct VmxnetRxPkt *pkt,
-    eth_pkt_types_e packet_type)
-{
-    assert(pkt);
-
-    pkt->packet_type = packet_type;
-
-}
-
-eth_pkt_types_e vmxnet_rx_pkt_get_packet_type(struct VmxnetRxPkt *pkt)
-{
-    assert(pkt);
-
-    return pkt->packet_type;
-}
-
-size_t vmxnet_rx_pkt_get_total_len(struct VmxnetRxPkt *pkt)
-{
-    assert(pkt);
-
-    return pkt->tot_len;
-}
-
-void vmxnet_rx_pkt_get_protocols(struct VmxnetRxPkt *pkt,
-                                 bool *isip4, bool *isip6,
-                                 bool *isudp, bool *istcp)
-{
-    assert(pkt);
-
-    *isip4 = pkt->isip4;
-    *isip6 = pkt->isip6;
-    *isudp = pkt->isudp;
-    *istcp = pkt->istcp;
-}
-
-struct iovec *vmxnet_rx_pkt_get_iovec(struct VmxnetRxPkt *pkt)
-{
-    assert(pkt);
-
-    return pkt->vec;
-}
-
-void vmxnet_rx_pkt_set_vhdr(struct VmxnetRxPkt *pkt,
-                            struct virtio_net_hdr *vhdr)
-{
-    assert(pkt);
-
-    memcpy(&pkt->virt_hdr, vhdr, sizeof pkt->virt_hdr);
-}
-
-bool vmxnet_rx_pkt_is_vlan_stripped(struct VmxnetRxPkt *pkt)
-{
-    assert(pkt);
-
-    return pkt->vlan_stripped;
-}
-
-bool vmxnet_rx_pkt_has_virt_hdr(struct VmxnetRxPkt *pkt)
-{
-    assert(pkt);
-
-    return pkt->has_virt_hdr;
-}
-
-uint16_t vmxnet_rx_pkt_get_num_frags(struct VmxnetRxPkt *pkt)
-{
-    assert(pkt);
-
-    return pkt->vec_len;
-}
-
-uint16_t vmxnet_rx_pkt_get_vlan_tag(struct VmxnetRxPkt *pkt)
-{
-    assert(pkt);
-
-    return pkt->tci;
-}
diff --git a/hw/vmxnet_rx_pkt.h b/hw/vmxnet_rx_pkt.h
deleted file mode 100644 (file)
index 6b2c60e..0000000
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * QEMU VMWARE VMXNET* paravirtual NICs - RX packets abstraction
- *
- * Copyright (c) 2012 Ravello Systems LTD (http://ravellosystems.com)
- *
- * Developed by Daynix Computing LTD (http://www.daynix.com)
- *
- * Authors:
- * Dmitry Fleytman <dmitry@daynix.com>
- * Tamir Shomer <tamirs@daynix.com>
- * Yan Vugenfirer <yan@daynix.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 VMXNET_RX_PKT_H
-#define VMXNET_RX_PKT_H
-
-#include "stdint.h"
-#include "stdbool.h"
-#include "net/eth.h"
-
-/* defines to enable packet dump functions */
-/*#define VMXNET_RX_PKT_DEBUG*/
-
-struct VmxnetRxPkt;
-
-/**
- * Clean all rx packet resources
- *
- * @pkt:            packet
- *
- */
-void vmxnet_rx_pkt_uninit(struct VmxnetRxPkt *pkt);
-
-/**
- * Init function for rx packet functionality
- *
- * @pkt:            packet pointer
- * @has_virt_hdr:   device uses virtio header
- *
- */
-void vmxnet_rx_pkt_init(struct VmxnetRxPkt **pkt, bool has_virt_hdr);
-
-/**
- * returns total length of data attached to rx context
- *
- * @pkt:            packet
- *
- * Return:  nothing
- *
- */
-size_t vmxnet_rx_pkt_get_total_len(struct VmxnetRxPkt *pkt);
-
-/**
- * fetches packet analysis results
- *
- * @pkt:            packet
- * @isip4:          whether the packet given is IPv4
- * @isip6:          whether the packet given is IPv6
- * @isudp:          whether the packet given is UDP
- * @istcp:          whether the packet given is TCP
- *
- */
-void vmxnet_rx_pkt_get_protocols(struct VmxnetRxPkt *pkt,
-                                 bool *isip4, bool *isip6,
-                                 bool *isudp, bool *istcp);
-
-/**
- * returns virtio header stored in rx context
- *
- * @pkt:            packet
- * @ret:            virtio header
- *
- */
-struct virtio_net_hdr *vmxnet_rx_pkt_get_vhdr(struct VmxnetRxPkt *pkt);
-
-/**
- * returns packet type
- *
- * @pkt:            packet
- * @ret:            packet type
- *
- */
-eth_pkt_types_e vmxnet_rx_pkt_get_packet_type(struct VmxnetRxPkt *pkt);
-
-/**
- * returns vlan tag
- *
- * @pkt:            packet
- * @ret:            VLAN tag
- *
- */
-uint16_t vmxnet_rx_pkt_get_vlan_tag(struct VmxnetRxPkt *pkt);
-
-/**
- * tells whether vlan was stripped from the packet
- *
- * @pkt:            packet
- * @ret:            VLAN stripped sign
- *
- */
-bool vmxnet_rx_pkt_is_vlan_stripped(struct VmxnetRxPkt *pkt);
-
-/**
- * notifies caller if the packet has virtio header
- *
- * @pkt:            packet
- * @ret:            true if packet has virtio header, false otherwize
- *
- */
-bool vmxnet_rx_pkt_has_virt_hdr(struct VmxnetRxPkt *pkt);
-
-/**
- * returns number of frags attached to the packet
- *
- * @pkt:            packet
- * @ret:            number of frags
- *
- */
-uint16_t vmxnet_rx_pkt_get_num_frags(struct VmxnetRxPkt *pkt);
-
-/**
- * attach data to rx packet
- *
- * @pkt:            packet
- * @data:           pointer to the data buffer
- * @len:            data length
- * @strip_vlan:     should the module strip vlan from data
- *
- */
-void vmxnet_rx_pkt_attach_data(struct VmxnetRxPkt *pkt, const void *data,
-    size_t len, bool strip_vlan);
-
-/**
- * returns io vector that holds the attached data
- *
- * @pkt:            packet
- * @ret:            pointer to IOVec
- *
- */
-struct iovec *vmxnet_rx_pkt_get_iovec(struct VmxnetRxPkt *pkt);
-
-/**
- * prints rx packet data if debug is enabled
- *
- * @pkt:            packet
- *
- */
-void vmxnet_rx_pkt_dump(struct VmxnetRxPkt *pkt);
-
-/**
- * copy passed vhdr data to packet context
- *
- * @pkt:            packet
- * @vhdr:           VHDR buffer
- *
- */
-void vmxnet_rx_pkt_set_vhdr(struct VmxnetRxPkt *pkt,
-    struct virtio_net_hdr *vhdr);
-
-/**
- * save packet type in packet context
- *
- * @pkt:            packet
- * @packet_type:    the packet type
- *
- */
-void vmxnet_rx_pkt_set_packet_type(struct VmxnetRxPkt *pkt,
-    eth_pkt_types_e packet_type);
-
-#endif
diff --git a/hw/vmxnet_tx_pkt.c b/hw/vmxnet_tx_pkt.c
deleted file mode 100644 (file)
index b1e795b..0000000
+++ /dev/null
@@ -1,567 +0,0 @@
-/*
- * QEMU VMWARE VMXNET* paravirtual NICs - TX packets abstractions
- *
- * Copyright (c) 2012 Ravello Systems LTD (http://ravellosystems.com)
- *
- * Developed by Daynix Computing LTD (http://www.daynix.com)
- *
- * Authors:
- * Dmitry Fleytman <dmitry@daynix.com>
- * Tamir Shomer <tamirs@daynix.com>
- * Yan Vugenfirer <yan@daynix.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 "vmxnet_tx_pkt.h"
-#include "net/eth.h"
-#include "qemu-common.h"
-#include "qemu/iov.h"
-#include "net/checksum.h"
-#include "net/tap.h"
-#include "net/net.h"
-#include "exec/cpu-common.h"
-
-enum {
-    VMXNET_TX_PKT_VHDR_FRAG = 0,
-    VMXNET_TX_PKT_L2HDR_FRAG,
-    VMXNET_TX_PKT_L3HDR_FRAG,
-    VMXNET_TX_PKT_PL_START_FRAG
-};
-
-/* TX packet private context */
-struct VmxnetTxPkt {
-    struct virtio_net_hdr virt_hdr;
-    bool has_virt_hdr;
-
-    struct iovec *raw;
-    uint32_t raw_frags;
-    uint32_t max_raw_frags;
-
-    struct iovec *vec;
-
-    uint8_t l2_hdr[ETH_MAX_L2_HDR_LEN];
-
-    uint32_t payload_len;
-
-    uint32_t payload_frags;
-    uint32_t max_payload_frags;
-
-    uint16_t hdr_len;
-    eth_pkt_types_e packet_type;
-    uint8_t l4proto;
-};
-
-void vmxnet_tx_pkt_init(struct VmxnetTxPkt **pkt, uint32_t max_frags,
-    bool has_virt_hdr)
-{
-    struct VmxnetTxPkt *p = g_malloc0(sizeof *p);
-
-    p->vec = g_malloc((sizeof *p->vec) *
-        (max_frags + VMXNET_TX_PKT_PL_START_FRAG));
-
-    p->raw = g_malloc((sizeof *p->raw) * max_frags);
-
-    p->max_payload_frags = max_frags;
-    p->max_raw_frags = max_frags;
-    p->has_virt_hdr = has_virt_hdr;
-    p->vec[VMXNET_TX_PKT_VHDR_FRAG].iov_base = &p->virt_hdr;
-    p->vec[VMXNET_TX_PKT_VHDR_FRAG].iov_len =
-        p->has_virt_hdr ? sizeof p->virt_hdr : 0;
-    p->vec[VMXNET_TX_PKT_L2HDR_FRAG].iov_base = &p->l2_hdr;
-    p->vec[VMXNET_TX_PKT_L3HDR_FRAG].iov_base = NULL;
-    p->vec[VMXNET_TX_PKT_L3HDR_FRAG].iov_len = 0;
-
-    *pkt = p;
-}
-
-void vmxnet_tx_pkt_uninit(struct VmxnetTxPkt *pkt)
-{
-    if (pkt) {
-        g_free(pkt->vec);
-        g_free(pkt->raw);
-        g_free(pkt);
-    }
-}
-
-void vmxnet_tx_pkt_update_ip_checksums(struct VmxnetTxPkt *pkt)
-{
-    uint16_t csum;
-    uint32_t ph_raw_csum;
-    assert(pkt);
-    uint8_t gso_type = pkt->virt_hdr.gso_type & ~VIRTIO_NET_HDR_GSO_ECN;
-    struct ip_header *ip_hdr;
-
-    if (VIRTIO_NET_HDR_GSO_TCPV4 != gso_type &&
-        VIRTIO_NET_HDR_GSO_UDP != gso_type) {
-        return;
-    }
-
-    ip_hdr = pkt->vec[VMXNET_TX_PKT_L3HDR_FRAG].iov_base;
-
-    if (pkt->payload_len + pkt->vec[VMXNET_TX_PKT_L3HDR_FRAG].iov_len >
-        ETH_MAX_IP_DGRAM_LEN) {
-        return;
-    }
-
-    ip_hdr->ip_len = cpu_to_be16(pkt->payload_len +
-        pkt->vec[VMXNET_TX_PKT_L3HDR_FRAG].iov_len);
-
-    /* Calculate IP header checksum                    */
-    ip_hdr->ip_sum = 0;
-    csum = net_raw_checksum((uint8_t *)ip_hdr,
-        pkt->vec[VMXNET_TX_PKT_L3HDR_FRAG].iov_len);
-    ip_hdr->ip_sum = cpu_to_be16(csum);
-
-    /* Calculate IP pseudo header checksum             */
-    ph_raw_csum = eth_calc_pseudo_hdr_csum(ip_hdr, pkt->payload_len);
-    csum = cpu_to_be16(~net_checksum_finish(ph_raw_csum));
-    iov_from_buf(&pkt->vec[VMXNET_TX_PKT_PL_START_FRAG], pkt->payload_frags,
-                 pkt->virt_hdr.csum_offset, &csum, sizeof(csum));
-}
-
-static void vmxnet_tx_pkt_calculate_hdr_len(struct VmxnetTxPkt *pkt)
-{
-    pkt->hdr_len = pkt->vec[VMXNET_TX_PKT_L2HDR_FRAG].iov_len +
-        pkt->vec[VMXNET_TX_PKT_L3HDR_FRAG].iov_len;
-}
-
-static bool vmxnet_tx_pkt_parse_headers(struct VmxnetTxPkt *pkt)
-{
-    struct iovec *l2_hdr, *l3_hdr;
-    size_t bytes_read;
-    size_t full_ip6hdr_len;
-    uint16_t l3_proto;
-
-    assert(pkt);
-
-    l2_hdr = &pkt->vec[VMXNET_TX_PKT_L2HDR_FRAG];
-    l3_hdr = &pkt->vec[VMXNET_TX_PKT_L3HDR_FRAG];
-
-    bytes_read = iov_to_buf(pkt->raw, pkt->raw_frags, 0, l2_hdr->iov_base,
-                            ETH_MAX_L2_HDR_LEN);
-    if (bytes_read < ETH_MAX_L2_HDR_LEN) {
-        l2_hdr->iov_len = 0;
-        return false;
-    } else {
-        l2_hdr->iov_len = eth_get_l2_hdr_length(l2_hdr->iov_base);
-    }
-
-    l3_proto = eth_get_l3_proto(l2_hdr->iov_base, l2_hdr->iov_len);
-
-    switch (l3_proto) {
-    case ETH_P_IP:
-        l3_hdr->iov_base = g_malloc(ETH_MAX_IP4_HDR_LEN);
-
-        bytes_read = iov_to_buf(pkt->raw, pkt->raw_frags, l2_hdr->iov_len,
-                                l3_hdr->iov_base, sizeof(struct ip_header));
-
-        if (bytes_read < sizeof(struct ip_header)) {
-            l3_hdr->iov_len = 0;
-            return false;
-        }
-
-        l3_hdr->iov_len = IP_HDR_GET_LEN(l3_hdr->iov_base);
-        pkt->l4proto = ((struct ip_header *) l3_hdr->iov_base)->ip_p;
-
-        /* copy optional IPv4 header data */
-        bytes_read = iov_to_buf(pkt->raw, pkt->raw_frags,
-                                l2_hdr->iov_len + sizeof(struct ip_header),
-                                l3_hdr->iov_base + sizeof(struct ip_header),
-                                l3_hdr->iov_len - sizeof(struct ip_header));
-        if (bytes_read < l3_hdr->iov_len - sizeof(struct ip_header)) {
-            l3_hdr->iov_len = 0;
-            return false;
-        }
-        break;
-
-    case ETH_P_IPV6:
-        if (!eth_parse_ipv6_hdr(pkt->raw, pkt->raw_frags, l2_hdr->iov_len,
-                               &pkt->l4proto, &full_ip6hdr_len)) {
-            l3_hdr->iov_len = 0;
-            return false;
-        }
-
-        l3_hdr->iov_base = g_malloc(full_ip6hdr_len);
-
-        bytes_read = iov_to_buf(pkt->raw, pkt->raw_frags, l2_hdr->iov_len,
-                                l3_hdr->iov_base, full_ip6hdr_len);
-
-        if (bytes_read < full_ip6hdr_len) {
-            l3_hdr->iov_len = 0;
-            return false;
-        } else {
-            l3_hdr->iov_len = full_ip6hdr_len;
-        }
-        break;
-
-    default:
-        l3_hdr->iov_len = 0;
-        break;
-    }
-
-    vmxnet_tx_pkt_calculate_hdr_len(pkt);
-    pkt->packet_type = get_eth_packet_type(l2_hdr->iov_base);
-    return true;
-}
-
-static bool vmxnet_tx_pkt_rebuild_payload(struct VmxnetTxPkt *pkt)
-{
-    size_t payload_len = iov_size(pkt->raw, pkt->raw_frags) - pkt->hdr_len;
-
-    pkt->payload_frags = iov_copy(&pkt->vec[VMXNET_TX_PKT_PL_START_FRAG],
-                                pkt->max_payload_frags,
-                                pkt->raw, pkt->raw_frags,
-                                pkt->hdr_len, payload_len);
-
-    if (pkt->payload_frags != (uint32_t) -1) {
-        pkt->payload_len = payload_len;
-        return true;
-    } else {
-        return false;
-    }
-}
-
-bool vmxnet_tx_pkt_parse(struct VmxnetTxPkt *pkt)
-{
-    return vmxnet_tx_pkt_parse_headers(pkt) &&
-           vmxnet_tx_pkt_rebuild_payload(pkt);
-}
-
-struct virtio_net_hdr *vmxnet_tx_pkt_get_vhdr(struct VmxnetTxPkt *pkt)
-{
-    assert(pkt);
-    return &pkt->virt_hdr;
-}
-
-static uint8_t vmxnet_tx_pkt_get_gso_type(struct VmxnetTxPkt *pkt,
-                                          bool tso_enable)
-{
-    uint8_t rc = VIRTIO_NET_HDR_GSO_NONE;
-    uint16_t l3_proto;
-
-    l3_proto = eth_get_l3_proto(pkt->vec[VMXNET_TX_PKT_L2HDR_FRAG].iov_base,
-        pkt->vec[VMXNET_TX_PKT_L2HDR_FRAG].iov_len);
-
-    if (!tso_enable) {
-        goto func_exit;
-    }
-
-    rc = eth_get_gso_type(l3_proto, pkt->vec[VMXNET_TX_PKT_L3HDR_FRAG].iov_base,
-                          pkt->l4proto);
-
-func_exit:
-    return rc;
-}
-
-void vmxnet_tx_pkt_build_vheader(struct VmxnetTxPkt *pkt, bool tso_enable,
-    bool csum_enable, uint32_t gso_size)
-{
-    struct tcp_hdr l4hdr;
-    assert(pkt);
-
-    /* csum has to be enabled if tso is. */
-    assert(csum_enable || !tso_enable);
-
-    pkt->virt_hdr.gso_type = vmxnet_tx_pkt_get_gso_type(pkt, tso_enable);
-
-    switch (pkt->virt_hdr.gso_type & ~VIRTIO_NET_HDR_GSO_ECN) {
-    case VIRTIO_NET_HDR_GSO_NONE:
-        pkt->virt_hdr.hdr_len = 0;
-        pkt->virt_hdr.gso_size = 0;
-        break;
-
-    case VIRTIO_NET_HDR_GSO_UDP:
-        pkt->virt_hdr.gso_size = IP_FRAG_ALIGN_SIZE(gso_size);
-        pkt->virt_hdr.hdr_len = pkt->hdr_len + sizeof(struct udp_header);
-        break;
-
-    case VIRTIO_NET_HDR_GSO_TCPV4:
-    case VIRTIO_NET_HDR_GSO_TCPV6:
-        iov_to_buf(&pkt->vec[VMXNET_TX_PKT_PL_START_FRAG], pkt->payload_frags,
-                   0, &l4hdr, sizeof(l4hdr));
-        pkt->virt_hdr.hdr_len = pkt->hdr_len + l4hdr.th_off * sizeof(uint32_t);
-        pkt->virt_hdr.gso_size = IP_FRAG_ALIGN_SIZE(gso_size);
-        break;
-
-    default:
-        assert(false);
-    }
-
-    if (csum_enable) {
-        switch (pkt->l4proto) {
-        case IP_PROTO_TCP:
-            pkt->virt_hdr.flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
-            pkt->virt_hdr.csum_start = pkt->hdr_len;
-            pkt->virt_hdr.csum_offset = offsetof(struct tcp_hdr, th_sum);
-            break;
-        case IP_PROTO_UDP:
-            pkt->virt_hdr.flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
-            pkt->virt_hdr.csum_start = pkt->hdr_len;
-            pkt->virt_hdr.csum_offset = offsetof(struct udp_hdr, uh_sum);
-            break;
-        default:
-            break;
-        }
-    }
-}
-
-void vmxnet_tx_pkt_setup_vlan_header(struct VmxnetTxPkt *pkt, uint16_t vlan)
-{
-    bool is_new;
-    assert(pkt);
-
-    eth_setup_vlan_headers(pkt->vec[VMXNET_TX_PKT_L2HDR_FRAG].iov_base,
-        vlan, &is_new);
-
-    /* update l2hdrlen */
-    if (is_new) {
-        pkt->hdr_len += sizeof(struct vlan_header);
-        pkt->vec[VMXNET_TX_PKT_L2HDR_FRAG].iov_len +=
-            sizeof(struct vlan_header);
-    }
-}
-
-bool vmxnet_tx_pkt_add_raw_fragment(struct VmxnetTxPkt *pkt, hwaddr pa,
-    size_t len)
-{
-    hwaddr mapped_len = 0;
-    struct iovec *ventry;
-    assert(pkt);
-    assert(pkt->max_raw_frags > pkt->raw_frags);
-
-    if (!len) {
-        return true;
-     }
-
-    ventry = &pkt->raw[pkt->raw_frags];
-    mapped_len = len;
-
-    ventry->iov_base = cpu_physical_memory_map(pa, &mapped_len, false);
-    ventry->iov_len = mapped_len;
-    pkt->raw_frags += !!ventry->iov_base;
-
-    if ((ventry->iov_base == NULL) || (len != mapped_len)) {
-        return false;
-    }
-
-    return true;
-}
-
-eth_pkt_types_e vmxnet_tx_pkt_get_packet_type(struct VmxnetTxPkt *pkt)
-{
-    assert(pkt);
-
-    return pkt->packet_type;
-}
-
-size_t vmxnet_tx_pkt_get_total_len(struct VmxnetTxPkt *pkt)
-{
-    assert(pkt);
-
-    return pkt->hdr_len + pkt->payload_len;
-}
-
-void vmxnet_tx_pkt_dump(struct VmxnetTxPkt *pkt)
-{
-#ifdef VMXNET_TX_PKT_DEBUG
-    assert(pkt);
-
-    printf("TX PKT: hdr_len: %d, pkt_type: 0x%X, l2hdr_len: %lu, "
-        "l3hdr_len: %lu, payload_len: %u\n", pkt->hdr_len, pkt->packet_type,
-        pkt->vec[VMXNET_TX_PKT_L2HDR_FRAG].iov_len,
-        pkt->vec[VMXNET_TX_PKT_L3HDR_FRAG].iov_len, pkt->payload_len);
-#endif
-}
-
-void vmxnet_tx_pkt_reset(struct VmxnetTxPkt *pkt)
-{
-    int i;
-
-    /* no assert, as reset can be called before tx_pkt_init */
-    if (!pkt) {
-        return;
-    }
-
-    memset(&pkt->virt_hdr, 0, sizeof(pkt->virt_hdr));
-
-    g_free(pkt->vec[VMXNET_TX_PKT_L3HDR_FRAG].iov_base);
-    pkt->vec[VMXNET_TX_PKT_L3HDR_FRAG].iov_base = NULL;
-
-    assert(pkt->vec);
-    for (i = VMXNET_TX_PKT_L2HDR_FRAG;
-         i < pkt->payload_frags + VMXNET_TX_PKT_PL_START_FRAG; i++) {
-        pkt->vec[i].iov_len = 0;
-    }
-    pkt->payload_len = 0;
-    pkt->payload_frags = 0;
-
-    assert(pkt->raw);
-    for (i = 0; i < pkt->raw_frags; i++) {
-        assert(pkt->raw[i].iov_base);
-        cpu_physical_memory_unmap(pkt->raw[i].iov_base, pkt->raw[i].iov_len,
-                                  false, pkt->raw[i].iov_len);
-        pkt->raw[i].iov_len = 0;
-    }
-    pkt->raw_frags = 0;
-
-    pkt->hdr_len = 0;
-    pkt->packet_type = 0;
-    pkt->l4proto = 0;
-}
-
-static void vmxnet_tx_pkt_do_sw_csum(struct VmxnetTxPkt *pkt)
-{
-    struct iovec *iov = &pkt->vec[VMXNET_TX_PKT_L2HDR_FRAG];
-    uint32_t csum_cntr;
-    uint16_t csum = 0;
-    /* num of iovec without vhdr */
-    uint32_t iov_len = pkt->payload_frags + VMXNET_TX_PKT_PL_START_FRAG - 1;
-    uint16_t csl;
-    struct ip_header *iphdr;
-    size_t csum_offset = pkt->virt_hdr.csum_start + pkt->virt_hdr.csum_offset;
-
-    /* Put zero to checksum field */
-    iov_from_buf(iov, iov_len, csum_offset, &csum, sizeof csum);
-
-    /* Calculate L4 TCP/UDP checksum */
-    csl = pkt->payload_len;
-
-    /* data checksum */
-    csum_cntr =
-        net_checksum_add_iov(iov, iov_len, pkt->virt_hdr.csum_start, csl);
-    /* add pseudo header to csum */
-    iphdr = pkt->vec[VMXNET_TX_PKT_L3HDR_FRAG].iov_base;
-    csum_cntr += eth_calc_pseudo_hdr_csum(iphdr, csl);
-
-    /* Put the checksum obtained into the packet */
-    csum = cpu_to_be16(net_checksum_finish(csum_cntr));
-    iov_from_buf(iov, iov_len, csum_offset, &csum, sizeof csum);
-}
-
-enum {
-    VMXNET_TX_PKT_FRAGMENT_L2_HDR_POS = 0,
-    VMXNET_TX_PKT_FRAGMENT_L3_HDR_POS,
-    VMXNET_TX_PKT_FRAGMENT_HEADER_NUM
-};
-
-#define VMXNET_MAX_FRAG_SG_LIST (64)
-
-static size_t vmxnet_tx_pkt_fetch_fragment(struct VmxnetTxPkt *pkt,
-    int *src_idx, size_t *src_offset, struct iovec *dst, int *dst_idx)
-{
-    size_t fetched = 0;
-    struct iovec *src = pkt->vec;
-
-    *dst_idx = VMXNET_TX_PKT_FRAGMENT_HEADER_NUM;
-
-    while (fetched < pkt->virt_hdr.gso_size) {
-
-        /* no more place in fragment iov */
-        if (*dst_idx == VMXNET_MAX_FRAG_SG_LIST) {
-            break;
-        }
-
-        /* no more data in iovec */
-        if (*src_idx == (pkt->payload_frags + VMXNET_TX_PKT_PL_START_FRAG)) {
-            break;
-        }
-
-
-        dst[*dst_idx].iov_base = src[*src_idx].iov_base + *src_offset;
-        dst[*dst_idx].iov_len = MIN(src[*src_idx].iov_len - *src_offset,
-            pkt->virt_hdr.gso_size - fetched);
-
-        *src_offset += dst[*dst_idx].iov_len;
-        fetched += dst[*dst_idx].iov_len;
-
-        if (*src_offset == src[*src_idx].iov_len) {
-            *src_offset = 0;
-            (*src_idx)++;
-        }
-
-        (*dst_idx)++;
-    }
-
-    return fetched;
-}
-
-static bool vmxnet_tx_pkt_do_sw_fragmentation(struct VmxnetTxPkt *pkt,
-    NetClientState *nc)
-{
-    struct iovec fragment[VMXNET_MAX_FRAG_SG_LIST];
-    size_t fragment_len = 0;
-    bool more_frags = false;
-
-    /* some pointers for shorter code */
-    void *l2_iov_base, *l3_iov_base;
-    size_t l2_iov_len, l3_iov_len;
-    int src_idx =  VMXNET_TX_PKT_PL_START_FRAG, dst_idx;
-    size_t src_offset = 0;
-    size_t fragment_offset = 0;
-
-    l2_iov_base = pkt->vec[VMXNET_TX_PKT_L2HDR_FRAG].iov_base;
-    l2_iov_len = pkt->vec[VMXNET_TX_PKT_L2HDR_FRAG].iov_len;
-    l3_iov_base = pkt->vec[VMXNET_TX_PKT_L3HDR_FRAG].iov_base;
-    l3_iov_len = pkt->vec[VMXNET_TX_PKT_L3HDR_FRAG].iov_len;
-
-    /* Copy headers */
-    fragment[VMXNET_TX_PKT_FRAGMENT_L2_HDR_POS].iov_base = l2_iov_base;
-    fragment[VMXNET_TX_PKT_FRAGMENT_L2_HDR_POS].iov_len = l2_iov_len;
-    fragment[VMXNET_TX_PKT_FRAGMENT_L3_HDR_POS].iov_base = l3_iov_base;
-    fragment[VMXNET_TX_PKT_FRAGMENT_L3_HDR_POS].iov_len = l3_iov_len;
-
-
-    /* Put as much data as possible and send */
-    do {
-        fragment_len = vmxnet_tx_pkt_fetch_fragment(pkt, &src_idx, &src_offset,
-            fragment, &dst_idx);
-
-        more_frags = (fragment_offset + fragment_len < pkt->payload_len);
-
-        eth_setup_ip4_fragmentation(l2_iov_base, l2_iov_len, l3_iov_base,
-            l3_iov_len, fragment_len, fragment_offset, more_frags);
-
-        eth_fix_ip4_checksum(l3_iov_base, l3_iov_len);
-
-        qemu_sendv_packet(nc, fragment, dst_idx);
-
-        fragment_offset += fragment_len;
-
-    } while (more_frags);
-
-    return true;
-}
-
-bool vmxnet_tx_pkt_send(struct VmxnetTxPkt *pkt, NetClientState *nc)
-{
-    assert(pkt);
-
-    if (!pkt->has_virt_hdr &&
-        pkt->virt_hdr.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) {
-        vmxnet_tx_pkt_do_sw_csum(pkt);
-    }
-
-    /*
-     * Since underlying infrastructure does not support IP datagrams longer
-     * than 64K we should drop such packets and don't even try to send
-     */
-    if (VIRTIO_NET_HDR_GSO_NONE != pkt->virt_hdr.gso_type) {
-        if (pkt->payload_len >
-            ETH_MAX_IP_DGRAM_LEN -
-            pkt->vec[VMXNET_TX_PKT_L3HDR_FRAG].iov_len) {
-            return false;
-        }
-    }
-
-    if (pkt->has_virt_hdr ||
-        pkt->virt_hdr.gso_type == VIRTIO_NET_HDR_GSO_NONE) {
-        qemu_sendv_packet(nc, pkt->vec,
-            pkt->payload_frags + VMXNET_TX_PKT_PL_START_FRAG);
-        return true;
-    }
-
-    return vmxnet_tx_pkt_do_sw_fragmentation(pkt, nc);
-}
diff --git a/hw/vmxnet_tx_pkt.h b/hw/vmxnet_tx_pkt.h
deleted file mode 100644 (file)
index 57121a6..0000000
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * QEMU VMWARE VMXNET* paravirtual NICs - TX packets abstraction
- *
- * Copyright (c) 2012 Ravello Systems LTD (http://ravellosystems.com)
- *
- * Developed by Daynix Computing LTD (http://www.daynix.com)
- *
- * Authors:
- * Dmitry Fleytman <dmitry@daynix.com>
- * Tamir Shomer <tamirs@daynix.com>
- * Yan Vugenfirer <yan@daynix.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 VMXNET_TX_PKT_H
-#define VMXNET_TX_PKT_H
-
-#include "stdint.h"
-#include "stdbool.h"
-#include "net/eth.h"
-#include "exec/hwaddr.h"
-
-/* define to enable packet dump functions */
-/*#define VMXNET_TX_PKT_DEBUG*/
-
-struct VmxnetTxPkt;
-
-/**
- * Init function for tx packet functionality
- *
- * @pkt:            packet pointer
- * @max_frags:      max tx ip fragments
- * @has_virt_hdr:   device uses virtio header.
- */
-void vmxnet_tx_pkt_init(struct VmxnetTxPkt **pkt, uint32_t max_frags,
-    bool has_virt_hdr);
-
-/**
- * Clean all tx packet resources.
- *
- * @pkt:            packet.
- */
-void vmxnet_tx_pkt_uninit(struct VmxnetTxPkt *pkt);
-
-/**
- * get virtio header
- *
- * @pkt:            packet
- * @ret:            virtio header
- */
-struct virtio_net_hdr *vmxnet_tx_pkt_get_vhdr(struct VmxnetTxPkt *pkt);
-
-/**
- * build virtio header (will be stored in module context)
- *
- * @pkt:            packet
- * @tso_enable:     TSO enabled
- * @csum_enable:    CSO enabled
- * @gso_size:       MSS size for TSO
- *
- */
-void vmxnet_tx_pkt_build_vheader(struct VmxnetTxPkt *pkt, bool tso_enable,
-    bool csum_enable, uint32_t gso_size);
-
-/**
- * updates vlan tag, and adds vlan header in case it is missing
- *
- * @pkt:            packet
- * @vlan:           VLAN tag
- *
- */
-void vmxnet_tx_pkt_setup_vlan_header(struct VmxnetTxPkt *pkt, uint16_t vlan);
-
-/**
- * populate data fragment into pkt context.
- *
- * @pkt:            packet
- * @pa:             physical address of fragment
- * @len:            length of fragment
- *
- */
-bool vmxnet_tx_pkt_add_raw_fragment(struct VmxnetTxPkt *pkt, hwaddr pa,
-    size_t len);
-
-/**
- * fix ip header fields and calculate checksums needed.
- *
- * @pkt:            packet
- *
- */
-void vmxnet_tx_pkt_update_ip_checksums(struct VmxnetTxPkt *pkt);
-
-/**
- * get length of all populated data.
- *
- * @pkt:            packet
- * @ret:            total data length
- *
- */
-size_t vmxnet_tx_pkt_get_total_len(struct VmxnetTxPkt *pkt);
-
-/**
- * get packet type
- *
- * @pkt:            packet
- * @ret:            packet type
- *
- */
-eth_pkt_types_e vmxnet_tx_pkt_get_packet_type(struct VmxnetTxPkt *pkt);
-
-/**
- * prints packet data if debug is enabled
- *
- * @pkt:            packet
- *
- */
-void vmxnet_tx_pkt_dump(struct VmxnetTxPkt *pkt);
-
-/**
- * reset tx packet private context (needed to be called between packets)
- *
- * @pkt:            packet
- *
- */
-void vmxnet_tx_pkt_reset(struct VmxnetTxPkt *pkt);
-
-/**
- * Send packet to qemu. handles sw offloads if vhdr is not supported.
- *
- * @pkt:            packet
- * @nc:             NetClientState
- * @ret:            operation result
- *
- */
-bool vmxnet_tx_pkt_send(struct VmxnetTxPkt *pkt, NetClientState *nc);
-
-/**
- * parse raw packet data and analyze offload requirements.
- *
- * @pkt:            packet
- *
- */
-bool vmxnet_tx_pkt_parse(struct VmxnetTxPkt *pkt);
-
-#endif
diff --git a/hw/vt82c686.c b/hw/vt82c686.c
deleted file mode 100644 (file)
index 9d9b64e..0000000
+++ /dev/null
@@ -1,487 +0,0 @@
-/*
- * VT82C686B south bridge support
- *
- * Copyright (c) 2008 yajin (yajin@vm-kernel.org)
- * Copyright (c) 2009 chenming (chenming@rdc.faw.com.cn)
- * Copyright (c) 2010 Huacai Chen (zltjiangshi@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/hw.h"
-#include "hw/pc.h"
-#include "hw/vt82c686.h"
-#include "hw/i2c.h"
-#include "hw/smbus.h"
-#include "hw/pci/pci.h"
-#include "hw/isa.h"
-#include "hw/sysbus.h"
-#include "hw/mips.h"
-#include "hw/apm.h"
-#include "hw/acpi.h"
-#include "hw/pm_smbus.h"
-#include "sysemu/sysemu.h"
-#include "qemu/timer.h"
-#include "exec/address-spaces.h"
-
-//#define DEBUG_VT82C686B
-
-#ifdef DEBUG_VT82C686B
-#define DPRINTF(fmt, ...) fprintf(stderr, "%s: " fmt, __FUNCTION__, ##__VA_ARGS__)
-#else
-#define DPRINTF(fmt, ...)
-#endif
-
-typedef struct SuperIOConfig
-{
-    uint8_t config[0xff];
-    uint8_t index;
-    uint8_t data;
-} SuperIOConfig;
-
-typedef struct VT82C686BState {
-    PCIDevice dev;
-    SuperIOConfig superio_conf;
-} VT82C686BState;
-
-static void superio_ioport_writeb(void *opaque, uint32_t addr, uint32_t data)
-{
-    int can_write;
-    SuperIOConfig *superio_conf = opaque;
-
-    DPRINTF("superio_ioport_writeb  address 0x%x  val 0x%x\n", addr, data);
-    if (addr == 0x3f0) {
-        superio_conf->index = data & 0xff;
-    } else {
-        /* 0x3f1 */
-        switch (superio_conf->index) {
-        case 0x00 ... 0xdf:
-        case 0xe4:
-        case 0xe5:
-        case 0xe9 ... 0xed:
-        case 0xf3:
-        case 0xf5:
-        case 0xf7:
-        case 0xf9 ... 0xfb:
-        case 0xfd ... 0xff:
-            can_write = 0;
-            break;
-        default:
-            can_write = 1;
-
-            if (can_write) {
-                switch (superio_conf->index) {
-                case 0xe7:
-                    if ((data & 0xff) != 0xfe) {
-                        DPRINTF("chage uart 1 base. unsupported yet\n");
-                    }
-                    break;
-                case 0xe8:
-                    if ((data & 0xff) != 0xbe) {
-                        DPRINTF("chage uart 2 base. unsupported yet\n");
-                    }
-                    break;
-
-                default:
-                    superio_conf->config[superio_conf->index] = data & 0xff;
-                }
-            }
-        }
-        superio_conf->config[superio_conf->index] = data & 0xff;
-    }
-}
-
-static uint32_t superio_ioport_readb(void *opaque, uint32_t addr)
-{
-    SuperIOConfig *superio_conf = opaque;
-
-    DPRINTF("superio_ioport_readb  address 0x%x\n", addr);
-    return (superio_conf->config[superio_conf->index]);
-}
-
-static void vt82c686b_reset(void * opaque)
-{
-    PCIDevice *d = opaque;
-    uint8_t *pci_conf = d->config;
-    VT82C686BState *vt82c = DO_UPCAST(VT82C686BState, dev, d);
-
-    pci_set_long(pci_conf + PCI_CAPABILITY_LIST, 0x000000c0);
-    pci_set_word(pci_conf + PCI_COMMAND, PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
-                 PCI_COMMAND_MASTER | PCI_COMMAND_SPECIAL);
-    pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_DEVSEL_MEDIUM);
-
-    pci_conf[0x48] = 0x01; /* Miscellaneous Control 3 */
-    pci_conf[0x4a] = 0x04; /* IDE interrupt Routing */
-    pci_conf[0x4f] = 0x03; /* DMA/Master Mem Access Control 3 */
-    pci_conf[0x50] = 0x2d; /* PnP DMA Request Control */
-    pci_conf[0x59] = 0x04;
-    pci_conf[0x5a] = 0x04; /* KBC/RTC Control*/
-    pci_conf[0x5f] = 0x04;
-    pci_conf[0x77] = 0x10; /* GPIO Control 1/2/3/4 */
-
-    vt82c->superio_conf.config[0xe0] = 0x3c;
-    vt82c->superio_conf.config[0xe2] = 0x03;
-    vt82c->superio_conf.config[0xe3] = 0xfc;
-    vt82c->superio_conf.config[0xe6] = 0xde;
-    vt82c->superio_conf.config[0xe7] = 0xfe;
-    vt82c->superio_conf.config[0xe8] = 0xbe;
-}
-
-/* write config pci function0 registers. PCI-ISA bridge */
-static void vt82c686b_write_config(PCIDevice * d, uint32_t address,
-                                   uint32_t val, int len)
-{
-    VT82C686BState *vt686 = DO_UPCAST(VT82C686BState, dev, d);
-
-    DPRINTF("vt82c686b_write_config  address 0x%x  val 0x%x len 0x%x\n",
-           address, val, len);
-
-    pci_default_write_config(d, address, val, len);
-    if (address == 0x85) {  /* enable or disable super IO configure */
-        if (val & 0x2) {
-            /* floppy also uses 0x3f0 and 0x3f1.
-             * But we do not emulate flopy,so just set it here. */
-            isa_unassign_ioport(0x3f0, 2);
-            register_ioport_read(0x3f0, 2, 1, superio_ioport_readb,
-                                 &vt686->superio_conf);
-            register_ioport_write(0x3f0, 2, 1, superio_ioport_writeb,
-                                  &vt686->superio_conf);
-        } else {
-            isa_unassign_ioport(0x3f0, 2);
-        }
-    }
-}
-
-#define ACPI_DBG_IO_ADDR  0xb044
-
-typedef struct VT686PMState {
-    PCIDevice dev;
-    MemoryRegion io;
-    ACPIREGS ar;
-    APMState apm;
-    PMSMBus smb;
-    uint32_t smb_io_base;
-} VT686PMState;
-
-typedef struct VT686AC97State {
-    PCIDevice dev;
-} VT686AC97State;
-
-typedef struct VT686MC97State {
-    PCIDevice dev;
-} VT686MC97State;
-
-static void pm_update_sci(VT686PMState *s)
-{
-    int sci_level, pmsts;
-
-    pmsts = acpi_pm1_evt_get_sts(&s->ar);
-    sci_level = (((pmsts & s->ar.pm1.evt.en) &
-                  (ACPI_BITMASK_RT_CLOCK_ENABLE |
-                   ACPI_BITMASK_POWER_BUTTON_ENABLE |
-                   ACPI_BITMASK_GLOBAL_LOCK_ENABLE |
-                   ACPI_BITMASK_TIMER_ENABLE)) != 0);
-    qemu_set_irq(s->dev.irq[0], sci_level);
-    /* schedule a timer interruption if needed */
-    acpi_pm_tmr_update(&s->ar, (s->ar.pm1.evt.en & ACPI_BITMASK_TIMER_ENABLE) &&
-                       !(pmsts & ACPI_BITMASK_TIMER_STATUS));
-}
-
-static void pm_tmr_timer(ACPIREGS *ar)
-{
-    VT686PMState *s = container_of(ar, VT686PMState, ar);
-    pm_update_sci(s);
-}
-
-static void pm_io_space_update(VT686PMState *s)
-{
-    uint32_t pm_io_base;
-
-    pm_io_base = pci_get_long(s->dev.config + 0x40);
-    pm_io_base &= 0xffc0;
-
-    memory_region_transaction_begin();
-    memory_region_set_enabled(&s->io, s->dev.config[0x80] & 1);
-    memory_region_set_address(&s->io, pm_io_base);
-    memory_region_transaction_commit();
-}
-
-static void pm_write_config(PCIDevice *d,
-                            uint32_t address, uint32_t val, int len)
-{
-    DPRINTF("pm_write_config  address 0x%x  val 0x%x len 0x%x\n",
-           address, val, len);
-    pci_default_write_config(d, address, val, len);
-}
-
-static int vmstate_acpi_post_load(void *opaque, int version_id)
-{
-    VT686PMState *s = opaque;
-
-    pm_io_space_update(s);
-    return 0;
-}
-
-static const VMStateDescription vmstate_acpi = {
-    .name = "vt82c686b_pm",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .post_load = vmstate_acpi_post_load,
-    .fields      = (VMStateField []) {
-        VMSTATE_PCI_DEVICE(dev, VT686PMState),
-        VMSTATE_UINT16(ar.pm1.evt.sts, VT686PMState),
-        VMSTATE_UINT16(ar.pm1.evt.en, VT686PMState),
-        VMSTATE_UINT16(ar.pm1.cnt.cnt, VT686PMState),
-        VMSTATE_STRUCT(apm, VT686PMState, 0, vmstate_apm, APMState),
-        VMSTATE_TIMER(ar.tmr.timer, VT686PMState),
-        VMSTATE_INT64(ar.tmr.overflow_time, VT686PMState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-/*
- * TODO: vt82c686b_ac97_init() and vt82c686b_mc97_init()
- * just register a PCI device now, functionalities will be implemented later.
- */
-
-static int vt82c686b_ac97_initfn(PCIDevice *dev)
-{
-    VT686AC97State *s = DO_UPCAST(VT686AC97State, dev, dev);
-    uint8_t *pci_conf = s->dev.config;
-
-    pci_set_word(pci_conf + PCI_COMMAND, PCI_COMMAND_INVALIDATE |
-                 PCI_COMMAND_PARITY);
-    pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_CAP_LIST |
-                 PCI_STATUS_DEVSEL_MEDIUM);
-    pci_set_long(pci_conf + PCI_INTERRUPT_PIN, 0x03);
-
-    return 0;
-}
-
-void vt82c686b_ac97_init(PCIBus *bus, int devfn)
-{
-    PCIDevice *dev;
-
-    dev = pci_create(bus, devfn, "VT82C686B_AC97");
-    qdev_init_nofail(&dev->qdev);
-}
-
-static void via_ac97_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
-    k->init = vt82c686b_ac97_initfn;
-    k->vendor_id = PCI_VENDOR_ID_VIA;
-    k->device_id = PCI_DEVICE_ID_VIA_AC97;
-    k->revision = 0x50;
-    k->class_id = PCI_CLASS_MULTIMEDIA_AUDIO;
-    dc->desc = "AC97";
-}
-
-static const TypeInfo via_ac97_info = {
-    .name          = "VT82C686B_AC97",
-    .parent        = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(VT686AC97State),
-    .class_init    = via_ac97_class_init,
-};
-
-static int vt82c686b_mc97_initfn(PCIDevice *dev)
-{
-    VT686MC97State *s = DO_UPCAST(VT686MC97State, dev, dev);
-    uint8_t *pci_conf = s->dev.config;
-
-    pci_set_word(pci_conf + PCI_COMMAND, PCI_COMMAND_INVALIDATE |
-                 PCI_COMMAND_VGA_PALETTE);
-    pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_DEVSEL_MEDIUM);
-    pci_set_long(pci_conf + PCI_INTERRUPT_PIN, 0x03);
-
-    return 0;
-}
-
-void vt82c686b_mc97_init(PCIBus *bus, int devfn)
-{
-    PCIDevice *dev;
-
-    dev = pci_create(bus, devfn, "VT82C686B_MC97");
-    qdev_init_nofail(&dev->qdev);
-}
-
-static void via_mc97_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
-    k->init = vt82c686b_mc97_initfn;
-    k->vendor_id = PCI_VENDOR_ID_VIA;
-    k->device_id = PCI_DEVICE_ID_VIA_MC97;
-    k->class_id = PCI_CLASS_COMMUNICATION_OTHER;
-    k->revision = 0x30;
-    dc->desc = "MC97";
-}
-
-static const TypeInfo via_mc97_info = {
-    .name          = "VT82C686B_MC97",
-    .parent        = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(VT686MC97State),
-    .class_init    = via_mc97_class_init,
-};
-
-/* vt82c686 pm init */
-static int vt82c686b_pm_initfn(PCIDevice *dev)
-{
-    VT686PMState *s = DO_UPCAST(VT686PMState, dev, dev);
-    uint8_t *pci_conf;
-
-    pci_conf = s->dev.config;
-    pci_set_word(pci_conf + PCI_COMMAND, 0);
-    pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_FAST_BACK |
-                 PCI_STATUS_DEVSEL_MEDIUM);
-
-    /* 0x48-0x4B is Power Management I/O Base */
-    pci_set_long(pci_conf + 0x48, 0x00000001);
-
-    /* SMB ports:0xeee0~0xeeef */
-    s->smb_io_base =((s->smb_io_base & 0xfff0) + 0x0);
-    pci_conf[0x90] = s->smb_io_base | 1;
-    pci_conf[0x91] = s->smb_io_base >> 8;
-    pci_conf[0xd2] = 0x90;
-    pm_smbus_init(&s->dev.qdev, &s->smb);
-    memory_region_add_subregion(get_system_io(), s->smb_io_base, &s->smb.io);
-
-    apm_init(dev, &s->apm, NULL, s);
-
-    memory_region_init(&s->io, "vt82c686-pm", 64);
-    memory_region_set_enabled(&s->io, false);
-    memory_region_add_subregion(get_system_io(), 0, &s->io);
-
-    acpi_pm_tmr_init(&s->ar, pm_tmr_timer, &s->io);
-    acpi_pm1_evt_init(&s->ar, pm_tmr_timer, &s->io);
-    acpi_pm1_cnt_init(&s->ar, &s->io, 2);
-
-    return 0;
-}
-
-i2c_bus *vt82c686b_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
-                       qemu_irq sci_irq)
-{
-    PCIDevice *dev;
-    VT686PMState *s;
-
-    dev = pci_create(bus, devfn, "VT82C686B_PM");
-    qdev_prop_set_uint32(&dev->qdev, "smb_io_base", smb_io_base);
-
-    s = DO_UPCAST(VT686PMState, dev, dev);
-
-    qdev_init_nofail(&dev->qdev);
-
-    return s->smb.smbus;
-}
-
-static Property via_pm_properties[] = {
-    DEFINE_PROP_UINT32("smb_io_base", VT686PMState, smb_io_base, 0),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void via_pm_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
-    k->init = vt82c686b_pm_initfn;
-    k->config_write = pm_write_config;
-    k->vendor_id = PCI_VENDOR_ID_VIA;
-    k->device_id = PCI_DEVICE_ID_VIA_ACPI;
-    k->class_id = PCI_CLASS_BRIDGE_OTHER;
-    k->revision = 0x40;
-    dc->desc = "PM";
-    dc->vmsd = &vmstate_acpi;
-    dc->props = via_pm_properties;
-}
-
-static const TypeInfo via_pm_info = {
-    .name          = "VT82C686B_PM",
-    .parent        = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(VT686PMState),
-    .class_init    = via_pm_class_init,
-};
-
-static const VMStateDescription vmstate_via = {
-    .name = "vt82c686b",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField []) {
-        VMSTATE_PCI_DEVICE(dev, VT82C686BState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-/* init the PCI-to-ISA bridge */
-static int vt82c686b_initfn(PCIDevice *d)
-{
-    uint8_t *pci_conf;
-    uint8_t *wmask;
-    int i;
-
-    isa_bus_new(&d->qdev, pci_address_space_io(d));
-
-    pci_conf = d->config;
-    pci_config_set_prog_interface(pci_conf, 0x0);
-
-    wmask = d->wmask;
-    for (i = 0x00; i < 0xff; i++) {
-       if (i<=0x03 || (i>=0x08 && i<=0x3f)) {
-           wmask[i] = 0x00;
-       }
-    }
-
-    qemu_register_reset(vt82c686b_reset, d);
-
-    return 0;
-}
-
-ISABus *vt82c686b_init(PCIBus *bus, int devfn)
-{
-    PCIDevice *d;
-
-    d = pci_create_simple_multifunction(bus, devfn, true, "VT82C686B");
-
-    return DO_UPCAST(ISABus, qbus, qdev_get_child_bus(&d->qdev, "isa.0"));
-}
-
-static void via_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
-    k->init = vt82c686b_initfn;
-    k->config_write = vt82c686b_write_config;
-    k->vendor_id = PCI_VENDOR_ID_VIA;
-    k->device_id = PCI_DEVICE_ID_VIA_ISA_BRIDGE;
-    k->class_id = PCI_CLASS_BRIDGE_ISA;
-    k->revision = 0x40;
-    dc->desc = "ISA bridge";
-    dc->no_user = 1;
-    dc->vmsd = &vmstate_via;
-}
-
-static const TypeInfo via_info = {
-    .name          = "VT82C686B",
-    .parent        = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(VT82C686BState),
-    .class_init    = via_class_init,
-};
-
-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);
-}
-
-type_init(vt82c686b_register_types)
diff --git a/hw/vt82c686.h b/hw/vt82c686.h
deleted file mode 100644 (file)
index 6ef876d..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-#ifndef HW_VT82C686_H
-#define HW_VT82C686_H
-
-/* vt82c686.c */
-ISABus *vt82c686b_init(PCIBus * bus, int devfn);
-void vt82c686b_ac97_init(PCIBus *bus, int devfn);
-void vt82c686b_mc97_init(PCIBus *bus, int devfn);
-i2c_bus *vt82c686b_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
-            qemu_irq sci_irq);
-
-#endif
diff --git a/hw/watchdog.c b/hw/watchdog.c
deleted file mode 100644 (file)
index 072d256..0000000
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * Virtual hardware watchdog.
- *
- * Copyright (C) 2009 Red Hat Inc.
- *
- * 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/>.
- *
- * By Richard W.M. Jones (rjones@redhat.com).
- */
-
-#include "qemu-common.h"
-#include "qemu/option.h"
-#include "qemu/config-file.h"
-#include "qemu/queue.h"
-#include "qapi/qmp/types.h"
-#include "monitor/monitor.h"
-#include "sysemu/sysemu.h"
-#include "hw/watchdog.h"
-
-/* Possible values for action parameter. */
-#define WDT_RESET        1     /* Hard reset. */
-#define WDT_SHUTDOWN     2     /* Shutdown. */
-#define WDT_POWEROFF     3     /* Quit. */
-#define WDT_PAUSE        4     /* Pause. */
-#define WDT_DEBUG        5     /* Prints a message and continues running. */
-#define WDT_NONE         6     /* Do nothing. */
-
-static int watchdog_action = WDT_RESET;
-static QLIST_HEAD(watchdog_list, WatchdogTimerModel) watchdog_list;
-
-void watchdog_add_model(WatchdogTimerModel *model)
-{
-    QLIST_INSERT_HEAD(&watchdog_list, model, entry);
-}
-
-/* Returns:
- *   0 = continue
- *   1 = exit program with error
- *   2 = exit program without error
- */
-int select_watchdog(const char *p)
-{
-    WatchdogTimerModel *model;
-    QemuOpts *opts;
-
-    /* -watchdog ? lists available devices and exits cleanly. */
-    if (is_help_option(p)) {
-        QLIST_FOREACH(model, &watchdog_list, entry) {
-            fprintf(stderr, "\t%s\t%s\n",
-                     model->wdt_name, model->wdt_description);
-        }
-        return 2;
-    }
-
-    QLIST_FOREACH(model, &watchdog_list, entry) {
-        if (strcasecmp(model->wdt_name, p) == 0) {
-            /* add the device */
-            opts = qemu_opts_create_nofail(qemu_find_opts("device"));
-            qemu_opt_set(opts, "driver", p);
-            return 0;
-        }
-    }
-
-    fprintf(stderr, "Unknown -watchdog device. Supported devices are:\n");
-    QLIST_FOREACH(model, &watchdog_list, entry) {
-        fprintf(stderr, "\t%s\t%s\n",
-                 model->wdt_name, model->wdt_description);
-    }
-    return 1;
-}
-
-int select_watchdog_action(const char *p)
-{
-    if (strcasecmp(p, "reset") == 0)
-        watchdog_action = WDT_RESET;
-    else if (strcasecmp(p, "shutdown") == 0)
-        watchdog_action = WDT_SHUTDOWN;
-    else if (strcasecmp(p, "poweroff") == 0)
-        watchdog_action = WDT_POWEROFF;
-    else if (strcasecmp(p, "pause") == 0)
-        watchdog_action = WDT_PAUSE;
-    else if (strcasecmp(p, "debug") == 0)
-        watchdog_action = WDT_DEBUG;
-    else if (strcasecmp(p, "none") == 0)
-        watchdog_action = WDT_NONE;
-    else
-        return -1;
-
-    return 0;
-}
-
-static void watchdog_mon_event(const char *action)
-{
-    QObject *data;
-
-    data = qobject_from_jsonf("{ 'action': %s }", action);
-    monitor_protocol_event(QEVENT_WATCHDOG, data);
-    qobject_decref(data);
-}
-
-/* This actually performs the "action" once a watchdog has expired,
- * ie. reboot, shutdown, exit, etc.
- */
-void watchdog_perform_action(void)
-{
-    switch(watchdog_action) {
-    case WDT_RESET:             /* same as 'system_reset' in monitor */
-        watchdog_mon_event("reset");
-        qemu_system_reset_request();
-        break;
-
-    case WDT_SHUTDOWN:          /* same as 'system_powerdown' in monitor */
-        watchdog_mon_event("shutdown");
-        qemu_system_powerdown_request();
-        break;
-
-    case WDT_POWEROFF:          /* same as 'quit' command in monitor */
-        watchdog_mon_event("poweroff");
-        exit(0);
-        break;
-
-    case WDT_PAUSE:             /* same as 'stop' command in monitor */
-        watchdog_mon_event("pause");
-        vm_stop(RUN_STATE_WATCHDOG);
-        break;
-
-    case WDT_DEBUG:
-        watchdog_mon_event("debug");
-        fprintf(stderr, "watchdog: timer fired\n");
-        break;
-
-    case WDT_NONE:
-        watchdog_mon_event("none");
-        break;
-    }
-}
diff --git a/hw/watchdog.h b/hw/watchdog.h
deleted file mode 100644 (file)
index 3e9a970..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Virtual hardware watchdog.
- *
- * Copyright (C) 2009 Red Hat Inc.
- *
- * 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/>.
- *
- * By Richard W.M. Jones (rjones@redhat.com).
- */
-
-#ifndef QEMU_WATCHDOG_H
-#define QEMU_WATCHDOG_H
-
-#include "qemu/queue.h"
-
-struct WatchdogTimerModel {
-    QLIST_ENTRY(WatchdogTimerModel) entry;
-
-    /* Short name of the device - used to select it on the command line. */
-    const char *wdt_name;
-    /* Longer description (eg. manufacturer and full model number). */
-    const char *wdt_description;
-};
-typedef struct WatchdogTimerModel WatchdogTimerModel;
-
-/* in hw/watchdog.c */
-int select_watchdog(const char *p);
-int select_watchdog_action(const char *action);
-void watchdog_add_model(WatchdogTimerModel *model);
-void watchdog_perform_action(void);
-
-#endif /* QEMU_WATCHDOG_H */
diff --git a/hw/watchdog/Makefile.objs b/hw/watchdog/Makefile.objs
new file mode 100644 (file)
index 0000000..4b0374a
--- /dev/null
@@ -0,0 +1,3 @@
+common-obj-y += watchdog.o
+common-obj-$(CONFIG_WDT_IB6300ESB) += wdt_i6300esb.o
+common-obj-$(CONFIG_WDT_IB700) += wdt_ib700.o
diff --git a/hw/watchdog/watchdog.c b/hw/watchdog/watchdog.c
new file mode 100644 (file)
index 0000000..cb4e1f9
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * Virtual hardware watchdog.
+ *
+ * Copyright (C) 2009 Red Hat Inc.
+ *
+ * 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/>.
+ *
+ * By Richard W.M. Jones (rjones@redhat.com).
+ */
+
+#include "qemu-common.h"
+#include "qemu/option.h"
+#include "qemu/config-file.h"
+#include "qemu/queue.h"
+#include "qapi/qmp/types.h"
+#include "monitor/monitor.h"
+#include "sysemu/sysemu.h"
+#include "sysemu/watchdog.h"
+
+/* Possible values for action parameter. */
+#define WDT_RESET        1     /* Hard reset. */
+#define WDT_SHUTDOWN     2     /* Shutdown. */
+#define WDT_POWEROFF     3     /* Quit. */
+#define WDT_PAUSE        4     /* Pause. */
+#define WDT_DEBUG        5     /* Prints a message and continues running. */
+#define WDT_NONE         6     /* Do nothing. */
+
+static int watchdog_action = WDT_RESET;
+static QLIST_HEAD(watchdog_list, WatchdogTimerModel) watchdog_list;
+
+void watchdog_add_model(WatchdogTimerModel *model)
+{
+    QLIST_INSERT_HEAD(&watchdog_list, model, entry);
+}
+
+/* Returns:
+ *   0 = continue
+ *   1 = exit program with error
+ *   2 = exit program without error
+ */
+int select_watchdog(const char *p)
+{
+    WatchdogTimerModel *model;
+    QemuOpts *opts;
+
+    /* -watchdog ? lists available devices and exits cleanly. */
+    if (is_help_option(p)) {
+        QLIST_FOREACH(model, &watchdog_list, entry) {
+            fprintf(stderr, "\t%s\t%s\n",
+                     model->wdt_name, model->wdt_description);
+        }
+        return 2;
+    }
+
+    QLIST_FOREACH(model, &watchdog_list, entry) {
+        if (strcasecmp(model->wdt_name, p) == 0) {
+            /* add the device */
+            opts = qemu_opts_create_nofail(qemu_find_opts("device"));
+            qemu_opt_set(opts, "driver", p);
+            return 0;
+        }
+    }
+
+    fprintf(stderr, "Unknown -watchdog device. Supported devices are:\n");
+    QLIST_FOREACH(model, &watchdog_list, entry) {
+        fprintf(stderr, "\t%s\t%s\n",
+                 model->wdt_name, model->wdt_description);
+    }
+    return 1;
+}
+
+int select_watchdog_action(const char *p)
+{
+    if (strcasecmp(p, "reset") == 0)
+        watchdog_action = WDT_RESET;
+    else if (strcasecmp(p, "shutdown") == 0)
+        watchdog_action = WDT_SHUTDOWN;
+    else if (strcasecmp(p, "poweroff") == 0)
+        watchdog_action = WDT_POWEROFF;
+    else if (strcasecmp(p, "pause") == 0)
+        watchdog_action = WDT_PAUSE;
+    else if (strcasecmp(p, "debug") == 0)
+        watchdog_action = WDT_DEBUG;
+    else if (strcasecmp(p, "none") == 0)
+        watchdog_action = WDT_NONE;
+    else
+        return -1;
+
+    return 0;
+}
+
+static void watchdog_mon_event(const char *action)
+{
+    QObject *data;
+
+    data = qobject_from_jsonf("{ 'action': %s }", action);
+    monitor_protocol_event(QEVENT_WATCHDOG, data);
+    qobject_decref(data);
+}
+
+/* This actually performs the "action" once a watchdog has expired,
+ * ie. reboot, shutdown, exit, etc.
+ */
+void watchdog_perform_action(void)
+{
+    switch(watchdog_action) {
+    case WDT_RESET:             /* same as 'system_reset' in monitor */
+        watchdog_mon_event("reset");
+        qemu_system_reset_request();
+        break;
+
+    case WDT_SHUTDOWN:          /* same as 'system_powerdown' in monitor */
+        watchdog_mon_event("shutdown");
+        qemu_system_powerdown_request();
+        break;
+
+    case WDT_POWEROFF:          /* same as 'quit' command in monitor */
+        watchdog_mon_event("poweroff");
+        exit(0);
+        break;
+
+    case WDT_PAUSE:             /* same as 'stop' command in monitor */
+        watchdog_mon_event("pause");
+        vm_stop(RUN_STATE_WATCHDOG);
+        break;
+
+    case WDT_DEBUG:
+        watchdog_mon_event("debug");
+        fprintf(stderr, "watchdog: timer fired\n");
+        break;
+
+    case WDT_NONE:
+        watchdog_mon_event("none");
+        break;
+    }
+}
diff --git a/hw/watchdog/wdt_i6300esb.c b/hw/watchdog/wdt_i6300esb.c
new file mode 100644 (file)
index 0000000..1407fba
--- /dev/null
@@ -0,0 +1,455 @@
+/*
+ * Virtual hardware watchdog.
+ *
+ * Copyright (C) 2009 Red Hat Inc.
+ *
+ * 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/>.
+ *
+ * By Richard W.M. Jones (rjones@redhat.com).
+ */
+
+#include <inttypes.h>
+
+#include "qemu-common.h"
+#include "qemu/timer.h"
+#include "sysemu/watchdog.h"
+#include "hw/hw.h"
+#include "hw/pci/pci.h"
+
+/*#define I6300ESB_DEBUG 1*/
+
+#ifdef I6300ESB_DEBUG
+#define i6300esb_debug(fs,...) \
+    fprintf(stderr,"i6300esb: %s: "fs,__func__,##__VA_ARGS__)
+#else
+#define i6300esb_debug(fs,...)
+#endif
+
+/* PCI configuration registers */
+#define ESB_CONFIG_REG  0x60            /* Config register                   */
+#define ESB_LOCK_REG    0x68            /* WDT lock register                 */
+
+/* Memory mapped registers (offset from base address) */
+#define ESB_TIMER1_REG  0x00            /* Timer1 value after each reset     */
+#define ESB_TIMER2_REG  0x04            /* Timer2 value after each reset     */
+#define ESB_GINTSR_REG  0x08            /* General Interrupt Status Register */
+#define ESB_RELOAD_REG  0x0c            /* Reload register                   */
+
+/* Lock register bits */
+#define ESB_WDT_FUNC    (0x01 << 2)   /* Watchdog functionality            */
+#define ESB_WDT_ENABLE  (0x01 << 1)   /* Enable WDT                        */
+#define ESB_WDT_LOCK    (0x01 << 0)   /* Lock (nowayout)                   */
+
+/* Config register bits */
+#define ESB_WDT_REBOOT  (0x01 << 5)   /* Enable reboot on timeout          */
+#define ESB_WDT_FREQ    (0x01 << 2)   /* Decrement frequency               */
+#define ESB_WDT_INTTYPE (0x11 << 0)   /* Interrupt type on timer1 timeout  */
+
+/* Reload register bits */
+#define ESB_WDT_RELOAD  (0x01 << 8)    /* prevent timeout                   */
+
+/* Magic constants */
+#define ESB_UNLOCK1     0x80            /* Step 1 to unlock reset registers  */
+#define ESB_UNLOCK2     0x86            /* Step 2 to unlock reset registers  */
+
+/* Device state. */
+struct I6300State {
+    PCIDevice dev;
+    MemoryRegion io_mem;
+
+    int reboot_enabled;         /* "Reboot" on timer expiry.  The real action
+                                 * performed depends on the -watchdog-action
+                                 * param passed on QEMU command line.
+                                 */
+    int clock_scale;            /* Clock scale. */
+#define CLOCK_SCALE_1KHZ 0
+#define CLOCK_SCALE_1MHZ 1
+
+    int int_type;               /* Interrupt type generated. */
+#define INT_TYPE_IRQ 0          /* APIC 1, INT 10 */
+#define INT_TYPE_SMI 2
+#define INT_TYPE_DISABLED 3
+
+    int free_run;               /* If true, reload timer on expiry. */
+    int locked;                 /* If true, enabled field cannot be changed. */
+    int enabled;                /* If true, watchdog is enabled. */
+
+    QEMUTimer *timer;           /* The actual watchdog timer. */
+
+    uint32_t timer1_preload;    /* Values preloaded into timer1, timer2. */
+    uint32_t timer2_preload;
+    int stage;                  /* Stage (1 or 2). */
+
+    int unlock_state;           /* Guest writes 0x80, 0x86 to unlock the
+                                 * registers, and we transition through
+                                 * states 0 -> 1 -> 2 when this happens.
+                                 */
+
+    int previous_reboot_flag;   /* If the watchdog caused the previous
+                                 * reboot, this flag will be set.
+                                 */
+};
+
+typedef struct I6300State I6300State;
+
+/* This function is called when the watchdog has either been enabled
+ * (hence it starts counting down) or has been keep-alived.
+ */
+static void i6300esb_restart_timer(I6300State *d, int stage)
+{
+    int64_t timeout;
+
+    if (!d->enabled)
+        return;
+
+    d->stage = stage;
+
+    if (d->stage <= 1)
+        timeout = d->timer1_preload;
+    else
+        timeout = d->timer2_preload;
+
+    if (d->clock_scale == CLOCK_SCALE_1KHZ)
+        timeout <<= 15;
+    else
+        timeout <<= 5;
+
+    /* Get the timeout in units of ticks_per_sec. */
+    timeout = get_ticks_per_sec() * timeout / 33000000;
+
+    i6300esb_debug("stage %d, timeout %" PRIi64 "\n", d->stage, timeout);
+
+    qemu_mod_timer(d->timer, qemu_get_clock_ns(vm_clock) + timeout);
+}
+
+/* This is called when the guest disables the watchdog. */
+static void i6300esb_disable_timer(I6300State *d)
+{
+    i6300esb_debug("timer disabled\n");
+
+    qemu_del_timer(d->timer);
+}
+
+static void i6300esb_reset(DeviceState *dev)
+{
+    PCIDevice *pdev = PCI_DEVICE(dev);
+    I6300State *d = DO_UPCAST(I6300State, dev, pdev);
+
+    i6300esb_debug("I6300State = %p\n", d);
+
+    i6300esb_disable_timer(d);
+
+    /* NB: Don't change d->previous_reboot_flag in this function. */
+
+    d->reboot_enabled = 1;
+    d->clock_scale = CLOCK_SCALE_1KHZ;
+    d->int_type = INT_TYPE_IRQ;
+    d->free_run = 0;
+    d->locked = 0;
+    d->enabled = 0;
+    d->timer1_preload = 0xfffff;
+    d->timer2_preload = 0xfffff;
+    d->stage = 1;
+    d->unlock_state = 0;
+}
+
+/* This function is called when the watchdog expires.  Note that
+ * the hardware has two timers, and so expiry happens in two stages.
+ * If d->stage == 1 then we perform the first stage action (usually,
+ * sending an interrupt) and then restart the timer again for the
+ * second stage.  If the second stage expires then the watchdog
+ * really has run out.
+ */
+static void i6300esb_timer_expired(void *vp)
+{
+    I6300State *d = vp;
+
+    i6300esb_debug("stage %d\n", d->stage);
+
+    if (d->stage == 1) {
+        /* What to do at the end of stage 1? */
+        switch (d->int_type) {
+        case INT_TYPE_IRQ:
+            fprintf(stderr, "i6300esb_timer_expired: I would send APIC 1 INT 10 here if I knew how (XXX)\n");
+            break;
+        case INT_TYPE_SMI:
+            fprintf(stderr, "i6300esb_timer_expired: I would send SMI here if I knew how (XXX)\n");
+            break;
+        }
+
+        /* Start the second stage. */
+        i6300esb_restart_timer(d, 2);
+    } else {
+        /* Second stage expired, reboot for real. */
+        if (d->reboot_enabled) {
+            d->previous_reboot_flag = 1;
+            watchdog_perform_action(); /* This reboots, exits, etc */
+            i6300esb_reset(&d->dev.qdev);
+        }
+
+        /* In "free running mode" we start stage 1 again. */
+        if (d->free_run)
+            i6300esb_restart_timer(d, 1);
+    }
+}
+
+static void i6300esb_config_write(PCIDevice *dev, uint32_t addr,
+                                  uint32_t data, int len)
+{
+    I6300State *d = DO_UPCAST(I6300State, dev, dev);
+    int old;
+
+    i6300esb_debug("addr = %x, data = %x, len = %d\n", addr, data, len);
+
+    if (addr == ESB_CONFIG_REG && len == 2) {
+        d->reboot_enabled = (data & ESB_WDT_REBOOT) == 0;
+        d->clock_scale =
+            (data & ESB_WDT_FREQ) != 0 ? CLOCK_SCALE_1MHZ : CLOCK_SCALE_1KHZ;
+        d->int_type = (data & ESB_WDT_INTTYPE);
+    } else if (addr == ESB_LOCK_REG && len == 1) {
+        if (!d->locked) {
+            d->locked = (data & ESB_WDT_LOCK) != 0;
+            d->free_run = (data & ESB_WDT_FUNC) != 0;
+            old = d->enabled;
+            d->enabled = (data & ESB_WDT_ENABLE) != 0;
+            if (!old && d->enabled) /* Enabled transitioned from 0 -> 1 */
+                i6300esb_restart_timer(d, 1);
+            else if (!d->enabled)
+                i6300esb_disable_timer(d);
+        }
+    } else {
+        pci_default_write_config(dev, addr, data, len);
+    }
+}
+
+static uint32_t i6300esb_config_read(PCIDevice *dev, uint32_t addr, int len)
+{
+    I6300State *d = DO_UPCAST(I6300State, dev, dev);
+    uint32_t data;
+
+    i6300esb_debug ("addr = %x, len = %d\n", addr, len);
+
+    if (addr == ESB_CONFIG_REG && len == 2) {
+        data =
+            (d->reboot_enabled ? 0 : ESB_WDT_REBOOT) |
+            (d->clock_scale == CLOCK_SCALE_1MHZ ? ESB_WDT_FREQ : 0) |
+            d->int_type;
+        return data;
+    } else if (addr == ESB_LOCK_REG && len == 1) {
+        data =
+            (d->free_run ? ESB_WDT_FUNC : 0) |
+            (d->locked ? ESB_WDT_LOCK : 0) |
+            (d->enabled ? ESB_WDT_ENABLE : 0);
+        return data;
+    } else {
+        return pci_default_read_config(dev, addr, len);
+    }
+}
+
+static uint32_t i6300esb_mem_readb(void *vp, hwaddr addr)
+{
+    i6300esb_debug ("addr = %x\n", (int) addr);
+
+    return 0;
+}
+
+static uint32_t i6300esb_mem_readw(void *vp, hwaddr addr)
+{
+    uint32_t data = 0;
+    I6300State *d = vp;
+
+    i6300esb_debug("addr = %x\n", (int) addr);
+
+    if (addr == 0xc) {
+        /* The previous reboot flag is really bit 9, but there is
+         * a bug in the Linux driver where it thinks it's bit 12.
+         * Set both.
+         */
+        data = d->previous_reboot_flag ? 0x1200 : 0;
+    }
+
+    return data;
+}
+
+static uint32_t i6300esb_mem_readl(void *vp, hwaddr addr)
+{
+    i6300esb_debug("addr = %x\n", (int) addr);
+
+    return 0;
+}
+
+static void i6300esb_mem_writeb(void *vp, hwaddr addr, uint32_t val)
+{
+    I6300State *d = vp;
+
+    i6300esb_debug("addr = %x, val = %x\n", (int) addr, val);
+
+    if (addr == 0xc && val == 0x80)
+        d->unlock_state = 1;
+    else if (addr == 0xc && val == 0x86 && d->unlock_state == 1)
+        d->unlock_state = 2;
+}
+
+static void i6300esb_mem_writew(void *vp, hwaddr addr, uint32_t val)
+{
+    I6300State *d = vp;
+
+    i6300esb_debug("addr = %x, val = %x\n", (int) addr, val);
+
+    if (addr == 0xc && val == 0x80)
+        d->unlock_state = 1;
+    else if (addr == 0xc && val == 0x86 && d->unlock_state == 1)
+        d->unlock_state = 2;
+    else {
+        if (d->unlock_state == 2) {
+            if (addr == 0xc) {
+                if ((val & 0x100) != 0)
+                    /* This is the "ping" from the userspace watchdog in
+                     * the guest ...
+                     */
+                    i6300esb_restart_timer(d, 1);
+
+                /* Setting bit 9 resets the previous reboot flag.
+                 * There's a bug in the Linux driver where it sets
+                 * bit 12 instead.
+                 */
+                if ((val & 0x200) != 0 || (val & 0x1000) != 0) {
+                    d->previous_reboot_flag = 0;
+                }
+            }
+
+            d->unlock_state = 0;
+        }
+    }
+}
+
+static void i6300esb_mem_writel(void *vp, hwaddr addr, uint32_t val)
+{
+    I6300State *d = vp;
+
+    i6300esb_debug ("addr = %x, val = %x\n", (int) addr, val);
+
+    if (addr == 0xc && val == 0x80)
+        d->unlock_state = 1;
+    else if (addr == 0xc && val == 0x86 && d->unlock_state == 1)
+        d->unlock_state = 2;
+    else {
+        if (d->unlock_state == 2) {
+            if (addr == 0)
+                d->timer1_preload = val & 0xfffff;
+            else if (addr == 4)
+                d->timer2_preload = val & 0xfffff;
+
+            d->unlock_state = 0;
+        }
+    }
+}
+
+static const MemoryRegionOps i6300esb_ops = {
+    .old_mmio = {
+        .read = {
+            i6300esb_mem_readb,
+            i6300esb_mem_readw,
+            i6300esb_mem_readl,
+        },
+        .write = {
+            i6300esb_mem_writeb,
+            i6300esb_mem_writew,
+            i6300esb_mem_writel,
+        },
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static const VMStateDescription vmstate_i6300esb = {
+    .name = "i6300esb_wdt",
+    .version_id = sizeof(I6300State),
+    .minimum_version_id = sizeof(I6300State),
+    .minimum_version_id_old = sizeof(I6300State),
+    .fields      = (VMStateField []) {
+        VMSTATE_PCI_DEVICE(dev, I6300State),
+        VMSTATE_INT32(reboot_enabled, I6300State),
+        VMSTATE_INT32(clock_scale, I6300State),
+        VMSTATE_INT32(int_type, I6300State),
+        VMSTATE_INT32(free_run, I6300State),
+        VMSTATE_INT32(locked, I6300State),
+        VMSTATE_INT32(enabled, I6300State),
+        VMSTATE_TIMER(timer, I6300State),
+        VMSTATE_UINT32(timer1_preload, I6300State),
+        VMSTATE_UINT32(timer2_preload, I6300State),
+        VMSTATE_INT32(stage, I6300State),
+        VMSTATE_INT32(unlock_state, I6300State),
+        VMSTATE_INT32(previous_reboot_flag, I6300State),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int i6300esb_init(PCIDevice *dev)
+{
+    I6300State *d = DO_UPCAST(I6300State, dev, dev);
+
+    i6300esb_debug("I6300State = %p\n", d);
+
+    d->timer = qemu_new_timer_ns(vm_clock, i6300esb_timer_expired, d);
+    d->previous_reboot_flag = 0;
+
+    memory_region_init_io(&d->io_mem, &i6300esb_ops, d, "i6300esb", 0x10);
+    pci_register_bar(&d->dev, 0, 0, &d->io_mem);
+    /* qemu_register_coalesced_mmio (addr, 0x10); ? */
+
+    return 0;
+}
+
+static void i6300esb_exit(PCIDevice *dev)
+{
+    I6300State *d = DO_UPCAST(I6300State, dev, dev);
+
+    memory_region_destroy(&d->io_mem);
+}
+
+static WatchdogTimerModel model = {
+    .wdt_name = "i6300esb",
+    .wdt_description = "Intel 6300ESB",
+};
+
+static void i6300esb_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->config_read = i6300esb_config_read;
+    k->config_write = i6300esb_config_write;
+    k->init = i6300esb_init;
+    k->exit = i6300esb_exit;
+    k->vendor_id = PCI_VENDOR_ID_INTEL;
+    k->device_id = PCI_DEVICE_ID_INTEL_ESB_9;
+    k->class_id = PCI_CLASS_SYSTEM_OTHER;
+    dc->reset = i6300esb_reset;
+    dc->vmsd = &vmstate_i6300esb;
+}
+
+static const TypeInfo i6300esb_info = {
+    .name          = "i6300esb",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(I6300State),
+    .class_init    = i6300esb_class_init,
+};
+
+static void i6300esb_register_types(void)
+{
+    watchdog_add_model(&model);
+    type_register_static(&i6300esb_info);
+}
+
+type_init(i6300esb_register_types)
diff --git a/hw/watchdog/wdt_ib700.c b/hw/watchdog/wdt_ib700.c
new file mode 100644 (file)
index 0000000..b8c4be8
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * Virtual hardware watchdog.
+ *
+ * Copyright (C) 2009 Red Hat Inc.
+ *
+ * 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/>.
+ *
+ * By Richard W.M. Jones (rjones@redhat.com).
+ */
+
+#include "qemu-common.h"
+#include "qemu/timer.h"
+#include "sysemu/watchdog.h"
+#include "hw/hw.h"
+#include "hw/isa/isa.h"
+#include "hw/i386/pc.h"
+
+/*#define IB700_DEBUG 1*/
+
+#ifdef IB700_DEBUG
+#define ib700_debug(fs,...)                                    \
+    fprintf(stderr,"ib700: %s: "fs,__func__,##__VA_ARGS__)
+#else
+#define ib700_debug(fs,...)
+#endif
+
+typedef struct IB700state {
+    ISADevice dev;
+    QEMUTimer *timer;
+} IB700State;
+
+/* This is the timer.  We use a global here because the watchdog
+ * code ensures there is only one watchdog (it is located at a fixed,
+ * unchangeable IO port, so there could only ever be one anyway).
+ */
+
+/* A write to this register enables the timer. */
+static void ib700_write_enable_reg(void *vp, uint32_t addr, uint32_t data)
+{
+    IB700State *s = vp;
+    static int time_map[] = {
+        30, 28, 26, 24, 22, 20, 18, 16,
+        14, 12, 10,  8,  6,  4,  2,  0
+    };
+    int64_t timeout;
+
+    ib700_debug("addr = %x, data = %x\n", addr, data);
+
+    timeout = (int64_t) time_map[data & 0xF] * get_ticks_per_sec();
+    qemu_mod_timer(s->timer, qemu_get_clock_ns (vm_clock) + timeout);
+}
+
+/* A write (of any value) to this register disables the timer. */
+static void ib700_write_disable_reg(void *vp, uint32_t addr, uint32_t data)
+{
+    IB700State *s = vp;
+
+    ib700_debug("addr = %x, data = %x\n", addr, data);
+
+    qemu_del_timer(s->timer);
+}
+
+/* This is called when the watchdog expires. */
+static void ib700_timer_expired(void *vp)
+{
+    IB700State *s = vp;
+
+    ib700_debug("watchdog expired\n");
+
+    watchdog_perform_action();
+    qemu_del_timer(s->timer);
+}
+
+static const VMStateDescription vmstate_ib700 = {
+    .name = "ib700_wdt",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .minimum_version_id_old = 0,
+    .fields      = (VMStateField []) {
+        VMSTATE_TIMER(timer, IB700State),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int wdt_ib700_init(ISADevice *dev)
+{
+    IB700State *s = DO_UPCAST(IB700State, dev, dev);
+
+    ib700_debug("watchdog init\n");
+
+    s->timer = qemu_new_timer_ns(vm_clock, ib700_timer_expired, s);
+    register_ioport_write(0x441, 2, 1, ib700_write_disable_reg, s);
+    register_ioport_write(0x443, 2, 1, ib700_write_enable_reg, s);
+
+    return 0;
+}
+
+static void wdt_ib700_reset(DeviceState *dev)
+{
+    IB700State *s = DO_UPCAST(IB700State, dev.qdev, dev);
+
+    ib700_debug("watchdog reset\n");
+
+    qemu_del_timer(s->timer);
+}
+
+static WatchdogTimerModel model = {
+    .wdt_name = "ib700",
+    .wdt_description = "iBASE 700",
+};
+
+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 const 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_types(void)
+{
+    watchdog_add_model(&model);
+    type_register_static(&wdt_ib700_info);
+}
+
+type_init(wdt_ib700_register_types)
diff --git a/hw/wdt_i6300esb.c b/hw/wdt_i6300esb.c
deleted file mode 100644 (file)
index f13e507..0000000
+++ /dev/null
@@ -1,455 +0,0 @@
-/*
- * Virtual hardware watchdog.
- *
- * Copyright (C) 2009 Red Hat Inc.
- *
- * 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/>.
- *
- * By Richard W.M. Jones (rjones@redhat.com).
- */
-
-#include <inttypes.h>
-
-#include "qemu-common.h"
-#include "qemu/timer.h"
-#include "hw/watchdog.h"
-#include "hw/hw.h"
-#include "hw/pci/pci.h"
-
-/*#define I6300ESB_DEBUG 1*/
-
-#ifdef I6300ESB_DEBUG
-#define i6300esb_debug(fs,...) \
-    fprintf(stderr,"i6300esb: %s: "fs,__func__,##__VA_ARGS__)
-#else
-#define i6300esb_debug(fs,...)
-#endif
-
-/* PCI configuration registers */
-#define ESB_CONFIG_REG  0x60            /* Config register                   */
-#define ESB_LOCK_REG    0x68            /* WDT lock register                 */
-
-/* Memory mapped registers (offset from base address) */
-#define ESB_TIMER1_REG  0x00            /* Timer1 value after each reset     */
-#define ESB_TIMER2_REG  0x04            /* Timer2 value after each reset     */
-#define ESB_GINTSR_REG  0x08            /* General Interrupt Status Register */
-#define ESB_RELOAD_REG  0x0c            /* Reload register                   */
-
-/* Lock register bits */
-#define ESB_WDT_FUNC    (0x01 << 2)   /* Watchdog functionality            */
-#define ESB_WDT_ENABLE  (0x01 << 1)   /* Enable WDT                        */
-#define ESB_WDT_LOCK    (0x01 << 0)   /* Lock (nowayout)                   */
-
-/* Config register bits */
-#define ESB_WDT_REBOOT  (0x01 << 5)   /* Enable reboot on timeout          */
-#define ESB_WDT_FREQ    (0x01 << 2)   /* Decrement frequency               */
-#define ESB_WDT_INTTYPE (0x11 << 0)   /* Interrupt type on timer1 timeout  */
-
-/* Reload register bits */
-#define ESB_WDT_RELOAD  (0x01 << 8)    /* prevent timeout                   */
-
-/* Magic constants */
-#define ESB_UNLOCK1     0x80            /* Step 1 to unlock reset registers  */
-#define ESB_UNLOCK2     0x86            /* Step 2 to unlock reset registers  */
-
-/* Device state. */
-struct I6300State {
-    PCIDevice dev;
-    MemoryRegion io_mem;
-
-    int reboot_enabled;         /* "Reboot" on timer expiry.  The real action
-                                 * performed depends on the -watchdog-action
-                                 * param passed on QEMU command line.
-                                 */
-    int clock_scale;            /* Clock scale. */
-#define CLOCK_SCALE_1KHZ 0
-#define CLOCK_SCALE_1MHZ 1
-
-    int int_type;               /* Interrupt type generated. */
-#define INT_TYPE_IRQ 0          /* APIC 1, INT 10 */
-#define INT_TYPE_SMI 2
-#define INT_TYPE_DISABLED 3
-
-    int free_run;               /* If true, reload timer on expiry. */
-    int locked;                 /* If true, enabled field cannot be changed. */
-    int enabled;                /* If true, watchdog is enabled. */
-
-    QEMUTimer *timer;           /* The actual watchdog timer. */
-
-    uint32_t timer1_preload;    /* Values preloaded into timer1, timer2. */
-    uint32_t timer2_preload;
-    int stage;                  /* Stage (1 or 2). */
-
-    int unlock_state;           /* Guest writes 0x80, 0x86 to unlock the
-                                 * registers, and we transition through
-                                 * states 0 -> 1 -> 2 when this happens.
-                                 */
-
-    int previous_reboot_flag;   /* If the watchdog caused the previous
-                                 * reboot, this flag will be set.
-                                 */
-};
-
-typedef struct I6300State I6300State;
-
-/* This function is called when the watchdog has either been enabled
- * (hence it starts counting down) or has been keep-alived.
- */
-static void i6300esb_restart_timer(I6300State *d, int stage)
-{
-    int64_t timeout;
-
-    if (!d->enabled)
-        return;
-
-    d->stage = stage;
-
-    if (d->stage <= 1)
-        timeout = d->timer1_preload;
-    else
-        timeout = d->timer2_preload;
-
-    if (d->clock_scale == CLOCK_SCALE_1KHZ)
-        timeout <<= 15;
-    else
-        timeout <<= 5;
-
-    /* Get the timeout in units of ticks_per_sec. */
-    timeout = get_ticks_per_sec() * timeout / 33000000;
-
-    i6300esb_debug("stage %d, timeout %" PRIi64 "\n", d->stage, timeout);
-
-    qemu_mod_timer(d->timer, qemu_get_clock_ns(vm_clock) + timeout);
-}
-
-/* This is called when the guest disables the watchdog. */
-static void i6300esb_disable_timer(I6300State *d)
-{
-    i6300esb_debug("timer disabled\n");
-
-    qemu_del_timer(d->timer);
-}
-
-static void i6300esb_reset(DeviceState *dev)
-{
-    PCIDevice *pdev = PCI_DEVICE(dev);
-    I6300State *d = DO_UPCAST(I6300State, dev, pdev);
-
-    i6300esb_debug("I6300State = %p\n", d);
-
-    i6300esb_disable_timer(d);
-
-    /* NB: Don't change d->previous_reboot_flag in this function. */
-
-    d->reboot_enabled = 1;
-    d->clock_scale = CLOCK_SCALE_1KHZ;
-    d->int_type = INT_TYPE_IRQ;
-    d->free_run = 0;
-    d->locked = 0;
-    d->enabled = 0;
-    d->timer1_preload = 0xfffff;
-    d->timer2_preload = 0xfffff;
-    d->stage = 1;
-    d->unlock_state = 0;
-}
-
-/* This function is called when the watchdog expires.  Note that
- * the hardware has two timers, and so expiry happens in two stages.
- * If d->stage == 1 then we perform the first stage action (usually,
- * sending an interrupt) and then restart the timer again for the
- * second stage.  If the second stage expires then the watchdog
- * really has run out.
- */
-static void i6300esb_timer_expired(void *vp)
-{
-    I6300State *d = vp;
-
-    i6300esb_debug("stage %d\n", d->stage);
-
-    if (d->stage == 1) {
-        /* What to do at the end of stage 1? */
-        switch (d->int_type) {
-        case INT_TYPE_IRQ:
-            fprintf(stderr, "i6300esb_timer_expired: I would send APIC 1 INT 10 here if I knew how (XXX)\n");
-            break;
-        case INT_TYPE_SMI:
-            fprintf(stderr, "i6300esb_timer_expired: I would send SMI here if I knew how (XXX)\n");
-            break;
-        }
-
-        /* Start the second stage. */
-        i6300esb_restart_timer(d, 2);
-    } else {
-        /* Second stage expired, reboot for real. */
-        if (d->reboot_enabled) {
-            d->previous_reboot_flag = 1;
-            watchdog_perform_action(); /* This reboots, exits, etc */
-            i6300esb_reset(&d->dev.qdev);
-        }
-
-        /* In "free running mode" we start stage 1 again. */
-        if (d->free_run)
-            i6300esb_restart_timer(d, 1);
-    }
-}
-
-static void i6300esb_config_write(PCIDevice *dev, uint32_t addr,
-                                  uint32_t data, int len)
-{
-    I6300State *d = DO_UPCAST(I6300State, dev, dev);
-    int old;
-
-    i6300esb_debug("addr = %x, data = %x, len = %d\n", addr, data, len);
-
-    if (addr == ESB_CONFIG_REG && len == 2) {
-        d->reboot_enabled = (data & ESB_WDT_REBOOT) == 0;
-        d->clock_scale =
-            (data & ESB_WDT_FREQ) != 0 ? CLOCK_SCALE_1MHZ : CLOCK_SCALE_1KHZ;
-        d->int_type = (data & ESB_WDT_INTTYPE);
-    } else if (addr == ESB_LOCK_REG && len == 1) {
-        if (!d->locked) {
-            d->locked = (data & ESB_WDT_LOCK) != 0;
-            d->free_run = (data & ESB_WDT_FUNC) != 0;
-            old = d->enabled;
-            d->enabled = (data & ESB_WDT_ENABLE) != 0;
-            if (!old && d->enabled) /* Enabled transitioned from 0 -> 1 */
-                i6300esb_restart_timer(d, 1);
-            else if (!d->enabled)
-                i6300esb_disable_timer(d);
-        }
-    } else {
-        pci_default_write_config(dev, addr, data, len);
-    }
-}
-
-static uint32_t i6300esb_config_read(PCIDevice *dev, uint32_t addr, int len)
-{
-    I6300State *d = DO_UPCAST(I6300State, dev, dev);
-    uint32_t data;
-
-    i6300esb_debug ("addr = %x, len = %d\n", addr, len);
-
-    if (addr == ESB_CONFIG_REG && len == 2) {
-        data =
-            (d->reboot_enabled ? 0 : ESB_WDT_REBOOT) |
-            (d->clock_scale == CLOCK_SCALE_1MHZ ? ESB_WDT_FREQ : 0) |
-            d->int_type;
-        return data;
-    } else if (addr == ESB_LOCK_REG && len == 1) {
-        data =
-            (d->free_run ? ESB_WDT_FUNC : 0) |
-            (d->locked ? ESB_WDT_LOCK : 0) |
-            (d->enabled ? ESB_WDT_ENABLE : 0);
-        return data;
-    } else {
-        return pci_default_read_config(dev, addr, len);
-    }
-}
-
-static uint32_t i6300esb_mem_readb(void *vp, hwaddr addr)
-{
-    i6300esb_debug ("addr = %x\n", (int) addr);
-
-    return 0;
-}
-
-static uint32_t i6300esb_mem_readw(void *vp, hwaddr addr)
-{
-    uint32_t data = 0;
-    I6300State *d = vp;
-
-    i6300esb_debug("addr = %x\n", (int) addr);
-
-    if (addr == 0xc) {
-        /* The previous reboot flag is really bit 9, but there is
-         * a bug in the Linux driver where it thinks it's bit 12.
-         * Set both.
-         */
-        data = d->previous_reboot_flag ? 0x1200 : 0;
-    }
-
-    return data;
-}
-
-static uint32_t i6300esb_mem_readl(void *vp, hwaddr addr)
-{
-    i6300esb_debug("addr = %x\n", (int) addr);
-
-    return 0;
-}
-
-static void i6300esb_mem_writeb(void *vp, hwaddr addr, uint32_t val)
-{
-    I6300State *d = vp;
-
-    i6300esb_debug("addr = %x, val = %x\n", (int) addr, val);
-
-    if (addr == 0xc && val == 0x80)
-        d->unlock_state = 1;
-    else if (addr == 0xc && val == 0x86 && d->unlock_state == 1)
-        d->unlock_state = 2;
-}
-
-static void i6300esb_mem_writew(void *vp, hwaddr addr, uint32_t val)
-{
-    I6300State *d = vp;
-
-    i6300esb_debug("addr = %x, val = %x\n", (int) addr, val);
-
-    if (addr == 0xc && val == 0x80)
-        d->unlock_state = 1;
-    else if (addr == 0xc && val == 0x86 && d->unlock_state == 1)
-        d->unlock_state = 2;
-    else {
-        if (d->unlock_state == 2) {
-            if (addr == 0xc) {
-                if ((val & 0x100) != 0)
-                    /* This is the "ping" from the userspace watchdog in
-                     * the guest ...
-                     */
-                    i6300esb_restart_timer(d, 1);
-
-                /* Setting bit 9 resets the previous reboot flag.
-                 * There's a bug in the Linux driver where it sets
-                 * bit 12 instead.
-                 */
-                if ((val & 0x200) != 0 || (val & 0x1000) != 0) {
-                    d->previous_reboot_flag = 0;
-                }
-            }
-
-            d->unlock_state = 0;
-        }
-    }
-}
-
-static void i6300esb_mem_writel(void *vp, hwaddr addr, uint32_t val)
-{
-    I6300State *d = vp;
-
-    i6300esb_debug ("addr = %x, val = %x\n", (int) addr, val);
-
-    if (addr == 0xc && val == 0x80)
-        d->unlock_state = 1;
-    else if (addr == 0xc && val == 0x86 && d->unlock_state == 1)
-        d->unlock_state = 2;
-    else {
-        if (d->unlock_state == 2) {
-            if (addr == 0)
-                d->timer1_preload = val & 0xfffff;
-            else if (addr == 4)
-                d->timer2_preload = val & 0xfffff;
-
-            d->unlock_state = 0;
-        }
-    }
-}
-
-static const MemoryRegionOps i6300esb_ops = {
-    .old_mmio = {
-        .read = {
-            i6300esb_mem_readb,
-            i6300esb_mem_readw,
-            i6300esb_mem_readl,
-        },
-        .write = {
-            i6300esb_mem_writeb,
-            i6300esb_mem_writew,
-            i6300esb_mem_writel,
-        },
-    },
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static const VMStateDescription vmstate_i6300esb = {
-    .name = "i6300esb_wdt",
-    .version_id = sizeof(I6300State),
-    .minimum_version_id = sizeof(I6300State),
-    .minimum_version_id_old = sizeof(I6300State),
-    .fields      = (VMStateField []) {
-        VMSTATE_PCI_DEVICE(dev, I6300State),
-        VMSTATE_INT32(reboot_enabled, I6300State),
-        VMSTATE_INT32(clock_scale, I6300State),
-        VMSTATE_INT32(int_type, I6300State),
-        VMSTATE_INT32(free_run, I6300State),
-        VMSTATE_INT32(locked, I6300State),
-        VMSTATE_INT32(enabled, I6300State),
-        VMSTATE_TIMER(timer, I6300State),
-        VMSTATE_UINT32(timer1_preload, I6300State),
-        VMSTATE_UINT32(timer2_preload, I6300State),
-        VMSTATE_INT32(stage, I6300State),
-        VMSTATE_INT32(unlock_state, I6300State),
-        VMSTATE_INT32(previous_reboot_flag, I6300State),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static int i6300esb_init(PCIDevice *dev)
-{
-    I6300State *d = DO_UPCAST(I6300State, dev, dev);
-
-    i6300esb_debug("I6300State = %p\n", d);
-
-    d->timer = qemu_new_timer_ns(vm_clock, i6300esb_timer_expired, d);
-    d->previous_reboot_flag = 0;
-
-    memory_region_init_io(&d->io_mem, &i6300esb_ops, d, "i6300esb", 0x10);
-    pci_register_bar(&d->dev, 0, 0, &d->io_mem);
-    /* qemu_register_coalesced_mmio (addr, 0x10); ? */
-
-    return 0;
-}
-
-static void i6300esb_exit(PCIDevice *dev)
-{
-    I6300State *d = DO_UPCAST(I6300State, dev, dev);
-
-    memory_region_destroy(&d->io_mem);
-}
-
-static WatchdogTimerModel model = {
-    .wdt_name = "i6300esb",
-    .wdt_description = "Intel 6300ESB",
-};
-
-static void i6300esb_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
-    k->config_read = i6300esb_config_read;
-    k->config_write = i6300esb_config_write;
-    k->init = i6300esb_init;
-    k->exit = i6300esb_exit;
-    k->vendor_id = PCI_VENDOR_ID_INTEL;
-    k->device_id = PCI_DEVICE_ID_INTEL_ESB_9;
-    k->class_id = PCI_CLASS_SYSTEM_OTHER;
-    dc->reset = i6300esb_reset;
-    dc->vmsd = &vmstate_i6300esb;
-}
-
-static const TypeInfo i6300esb_info = {
-    .name          = "i6300esb",
-    .parent        = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(I6300State),
-    .class_init    = i6300esb_class_init,
-};
-
-static void i6300esb_register_types(void)
-{
-    watchdog_add_model(&model);
-    type_register_static(&i6300esb_info);
-}
-
-type_init(i6300esb_register_types)
diff --git a/hw/wdt_ib700.c b/hw/wdt_ib700.c
deleted file mode 100644 (file)
index 6c52808..0000000
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Virtual hardware watchdog.
- *
- * Copyright (C) 2009 Red Hat Inc.
- *
- * 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/>.
- *
- * By Richard W.M. Jones (rjones@redhat.com).
- */
-
-#include "qemu-common.h"
-#include "qemu/timer.h"
-#include "hw/watchdog.h"
-#include "hw/hw.h"
-#include "hw/isa.h"
-#include "hw/pc.h"
-
-/*#define IB700_DEBUG 1*/
-
-#ifdef IB700_DEBUG
-#define ib700_debug(fs,...)                                    \
-    fprintf(stderr,"ib700: %s: "fs,__func__,##__VA_ARGS__)
-#else
-#define ib700_debug(fs,...)
-#endif
-
-typedef struct IB700state {
-    ISADevice dev;
-    QEMUTimer *timer;
-} IB700State;
-
-/* This is the timer.  We use a global here because the watchdog
- * code ensures there is only one watchdog (it is located at a fixed,
- * unchangeable IO port, so there could only ever be one anyway).
- */
-
-/* A write to this register enables the timer. */
-static void ib700_write_enable_reg(void *vp, uint32_t addr, uint32_t data)
-{
-    IB700State *s = vp;
-    static int time_map[] = {
-        30, 28, 26, 24, 22, 20, 18, 16,
-        14, 12, 10,  8,  6,  4,  2,  0
-    };
-    int64_t timeout;
-
-    ib700_debug("addr = %x, data = %x\n", addr, data);
-
-    timeout = (int64_t) time_map[data & 0xF] * get_ticks_per_sec();
-    qemu_mod_timer(s->timer, qemu_get_clock_ns (vm_clock) + timeout);
-}
-
-/* A write (of any value) to this register disables the timer. */
-static void ib700_write_disable_reg(void *vp, uint32_t addr, uint32_t data)
-{
-    IB700State *s = vp;
-
-    ib700_debug("addr = %x, data = %x\n", addr, data);
-
-    qemu_del_timer(s->timer);
-}
-
-/* This is called when the watchdog expires. */
-static void ib700_timer_expired(void *vp)
-{
-    IB700State *s = vp;
-
-    ib700_debug("watchdog expired\n");
-
-    watchdog_perform_action();
-    qemu_del_timer(s->timer);
-}
-
-static const VMStateDescription vmstate_ib700 = {
-    .name = "ib700_wdt",
-    .version_id = 0,
-    .minimum_version_id = 0,
-    .minimum_version_id_old = 0,
-    .fields      = (VMStateField []) {
-        VMSTATE_TIMER(timer, IB700State),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static int wdt_ib700_init(ISADevice *dev)
-{
-    IB700State *s = DO_UPCAST(IB700State, dev, dev);
-
-    ib700_debug("watchdog init\n");
-
-    s->timer = qemu_new_timer_ns(vm_clock, ib700_timer_expired, s);
-    register_ioport_write(0x441, 2, 1, ib700_write_disable_reg, s);
-    register_ioport_write(0x443, 2, 1, ib700_write_enable_reg, s);
-
-    return 0;
-}
-
-static void wdt_ib700_reset(DeviceState *dev)
-{
-    IB700State *s = DO_UPCAST(IB700State, dev.qdev, dev);
-
-    ib700_debug("watchdog reset\n");
-
-    qemu_del_timer(s->timer);
-}
-
-static WatchdogTimerModel model = {
-    .wdt_name = "ib700",
-    .wdt_description = "iBASE 700",
-};
-
-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 const 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_types(void)
-{
-    watchdog_add_model(&model);
-    type_register_static(&wdt_ib700_info);
-}
-
-type_init(wdt_ib700_register_types)
diff --git a/hw/wm8750.c b/hw/wm8750.c
deleted file mode 100644 (file)
index 0904cf4..0000000
+++ /dev/null
@@ -1,716 +0,0 @@
-/*
- * WM8750 audio CODEC.
- *
- * Copyright (c) 2006 Openedhand Ltd.
- * Written by Andrzej Zaborowski <balrog@zabor.org>
- *
- * This file is licensed under GNU GPL.
- */
-
-#include "hw/hw.h"
-#include "hw/i2c.h"
-#include "audio/audio.h"
-
-#define IN_PORT_N      3
-#define OUT_PORT_N     3
-
-#define CODEC          "wm8750"
-
-typedef struct {
-    int adc;
-    int adc_hz;
-    int dac;
-    int dac_hz;
-} WMRate;
-
-typedef struct {
-    I2CSlave i2c;
-    uint8_t i2c_data[2];
-    int i2c_len;
-    QEMUSoundCard card;
-    SWVoiceIn *adc_voice[IN_PORT_N];
-    SWVoiceOut *dac_voice[OUT_PORT_N];
-    int enable;
-    void (*data_req)(void *, int, int);
-    void *opaque;
-    uint8_t data_in[4096];
-    uint8_t data_out[4096];
-    int idx_in, req_in;
-    int idx_out, req_out;
-
-    SWVoiceOut **out[2];
-    uint8_t outvol[7], outmute[2];
-    SWVoiceIn **in[2];
-    uint8_t invol[4], inmute[2];
-
-    uint8_t diff[2], pol, ds, monomix[2], alc, mute;
-    uint8_t path[4], mpath[2], power, format;
-    const WMRate *rate;
-    uint8_t rate_vmstate;
-    int adc_hz, dac_hz, ext_adc_hz, ext_dac_hz, master;
-} WM8750State;
-
-/* pow(10.0, -i / 20.0) * 255, i = 0..42 */
-static const uint8_t wm8750_vol_db_table[] = {
-    255, 227, 203, 181, 161, 143, 128, 114, 102, 90, 81, 72, 64, 57, 51, 45,
-    40, 36, 32, 29, 26, 23, 20, 18, 16, 14, 13, 11, 10, 9, 8, 7, 6, 6, 5, 5,
-    4, 4, 3, 3, 3, 2, 2
-};
-
-#define WM8750_OUTVOL_TRANSFORM(x)     wm8750_vol_db_table[(0x7f - x) / 3]
-#define WM8750_INVOL_TRANSFORM(x)      (x << 2)
-
-static inline void wm8750_in_load(WM8750State *s)
-{
-    if (s->idx_in + s->req_in <= sizeof(s->data_in))
-        return;
-    s->idx_in = audio_MAX(0, (int) sizeof(s->data_in) - s->req_in);
-    AUD_read(*s->in[0], s->data_in + s->idx_in,
-             sizeof(s->data_in) - s->idx_in);
-}
-
-static inline void wm8750_out_flush(WM8750State *s)
-{
-    int sent = 0;
-    while (sent < s->idx_out)
-        sent += AUD_write(*s->out[0], s->data_out + sent, s->idx_out - sent)
-                ?: s->idx_out;
-    s->idx_out = 0;
-}
-
-static void wm8750_audio_in_cb(void *opaque, int avail_b)
-{
-    WM8750State *s = (WM8750State *) opaque;
-    s->req_in = avail_b;
-    s->data_req(s->opaque, s->req_out >> 2, avail_b >> 2);
-}
-
-static void wm8750_audio_out_cb(void *opaque, int free_b)
-{
-    WM8750State *s = (WM8750State *) opaque;
-
-    if (s->idx_out >= free_b) {
-        s->idx_out = free_b;
-        s->req_out = 0;
-        wm8750_out_flush(s);
-    } else
-        s->req_out = free_b - s->idx_out;
-    s->data_req(s->opaque, s->req_out >> 2, s->req_in >> 2);
-}
-
-static const WMRate wm_rate_table[] = {
-    {  256, 48000,  256, 48000 },      /* SR: 00000 */
-    {  384, 48000,  384, 48000 },      /* SR: 00001 */
-    {  256, 48000, 1536,  8000 },      /* SR: 00010 */
-    {  384, 48000, 2304,  8000 },      /* SR: 00011 */
-    { 1536,  8000,  256, 48000 },      /* SR: 00100 */
-    { 2304,  8000,  384, 48000 },      /* SR: 00101 */
-    { 1536,  8000, 1536,  8000 },      /* SR: 00110 */
-    { 2304,  8000, 2304,  8000 },      /* SR: 00111 */
-    { 1024, 12000, 1024, 12000 },      /* SR: 01000 */
-    { 1526, 12000, 1536, 12000 },      /* SR: 01001 */
-    {  768, 16000,  768, 16000 },      /* SR: 01010 */
-    { 1152, 16000, 1152, 16000 },      /* SR: 01011 */
-    {  384, 32000,  384, 32000 },      /* SR: 01100 */
-    {  576, 32000,  576, 32000 },      /* SR: 01101 */
-    {  128, 96000,  128, 96000 },      /* SR: 01110 */
-    {  192, 96000,  192, 96000 },      /* SR: 01111 */
-    {  256, 44100,  256, 44100 },      /* SR: 10000 */
-    {  384, 44100,  384, 44100 },      /* SR: 10001 */
-    {  256, 44100, 1408,  8018 },      /* SR: 10010 */
-    {  384, 44100, 2112,  8018 },      /* SR: 10011 */
-    { 1408,  8018,  256, 44100 },      /* SR: 10100 */
-    { 2112,  8018,  384, 44100 },      /* SR: 10101 */
-    { 1408,  8018, 1408,  8018 },      /* SR: 10110 */
-    { 2112,  8018, 2112,  8018 },      /* SR: 10111 */
-    { 1024, 11025, 1024, 11025 },      /* SR: 11000 */
-    { 1536, 11025, 1536, 11025 },      /* SR: 11001 */
-    {  512, 22050,  512, 22050 },      /* SR: 11010 */
-    {  768, 22050,  768, 22050 },      /* SR: 11011 */
-    {  512, 24000,  512, 24000 },      /* SR: 11100 */
-    {  768, 24000,  768, 24000 },      /* SR: 11101 */
-    {  128, 88200,  128, 88200 },      /* SR: 11110 */
-    {  192, 88200,  192, 88200 },      /* SR: 11111 */
-};
-
-static void wm8750_vol_update(WM8750State *s)
-{
-    /* FIXME: multiply all volumes by s->invol[2], s->invol[3] */
-
-    AUD_set_volume_in(s->adc_voice[0], s->mute,
-                    s->inmute[0] ? 0 : WM8750_INVOL_TRANSFORM(s->invol[0]),
-                    s->inmute[1] ? 0 : WM8750_INVOL_TRANSFORM(s->invol[1]));
-    AUD_set_volume_in(s->adc_voice[1], s->mute,
-                    s->inmute[0] ? 0 : WM8750_INVOL_TRANSFORM(s->invol[0]),
-                    s->inmute[1] ? 0 : WM8750_INVOL_TRANSFORM(s->invol[1]));
-    AUD_set_volume_in(s->adc_voice[2], s->mute,
-                    s->inmute[0] ? 0 : WM8750_INVOL_TRANSFORM(s->invol[0]),
-                    s->inmute[1] ? 0 : WM8750_INVOL_TRANSFORM(s->invol[1]));
-
-    /* FIXME: multiply all volumes by s->outvol[0], s->outvol[1] */
-
-    /* Speaker: LOUT2VOL ROUT2VOL */
-    AUD_set_volume_out(s->dac_voice[0], s->mute,
-                    s->outmute[0] ? 0 : WM8750_OUTVOL_TRANSFORM(s->outvol[4]),
-                    s->outmute[1] ? 0 : WM8750_OUTVOL_TRANSFORM(s->outvol[5]));
-
-    /* Headphone: LOUT1VOL ROUT1VOL */
-    AUD_set_volume_out(s->dac_voice[1], s->mute,
-                    s->outmute[0] ? 0 : WM8750_OUTVOL_TRANSFORM(s->outvol[2]),
-                    s->outmute[1] ? 0 : WM8750_OUTVOL_TRANSFORM(s->outvol[3]));
-
-    /* MONOOUT: MONOVOL MONOVOL */
-    AUD_set_volume_out(s->dac_voice[2], s->mute,
-                    s->outmute[0] ? 0 : WM8750_OUTVOL_TRANSFORM(s->outvol[6]),
-                    s->outmute[1] ? 0 : WM8750_OUTVOL_TRANSFORM(s->outvol[6]));
-}
-
-static void wm8750_set_format(WM8750State *s)
-{
-    int i;
-    struct audsettings in_fmt;
-    struct audsettings out_fmt;
-
-    wm8750_out_flush(s);
-
-    if (s->in[0] && *s->in[0])
-        AUD_set_active_in(*s->in[0], 0);
-    if (s->out[0] && *s->out[0])
-        AUD_set_active_out(*s->out[0], 0);
-
-    for (i = 0; i < IN_PORT_N; i ++)
-        if (s->adc_voice[i]) {
-            AUD_close_in(&s->card, s->adc_voice[i]);
-            s->adc_voice[i] = NULL;
-        }
-    for (i = 0; i < OUT_PORT_N; i ++)
-        if (s->dac_voice[i]) {
-            AUD_close_out(&s->card, s->dac_voice[i]);
-            s->dac_voice[i] = NULL;
-        }
-
-    if (!s->enable)
-        return;
-
-    /* Setup input */
-    in_fmt.endianness = 0;
-    in_fmt.nchannels = 2;
-    in_fmt.freq = s->adc_hz;
-    in_fmt.fmt = AUD_FMT_S16;
-
-    s->adc_voice[0] = AUD_open_in(&s->card, s->adc_voice[0],
-                    CODEC ".input1", s, wm8750_audio_in_cb, &in_fmt);
-    s->adc_voice[1] = AUD_open_in(&s->card, s->adc_voice[1],
-                    CODEC ".input2", s, wm8750_audio_in_cb, &in_fmt);
-    s->adc_voice[2] = AUD_open_in(&s->card, s->adc_voice[2],
-                    CODEC ".input3", s, wm8750_audio_in_cb, &in_fmt);
-
-    /* Setup output */
-    out_fmt.endianness = 0;
-    out_fmt.nchannels = 2;
-    out_fmt.freq = s->dac_hz;
-    out_fmt.fmt = AUD_FMT_S16;
-
-    s->dac_voice[0] = AUD_open_out(&s->card, s->dac_voice[0],
-                    CODEC ".speaker", s, wm8750_audio_out_cb, &out_fmt);
-    s->dac_voice[1] = AUD_open_out(&s->card, s->dac_voice[1],
-                    CODEC ".headphone", s, wm8750_audio_out_cb, &out_fmt);
-    /* MONOMIX is also in stereo for simplicity */
-    s->dac_voice[2] = AUD_open_out(&s->card, s->dac_voice[2],
-                    CODEC ".monomix", s, wm8750_audio_out_cb, &out_fmt);
-    /* no sense emulating OUT3 which is a mix of other outputs */
-
-    wm8750_vol_update(s);
-
-    /* We should connect the left and right channels to their
-     * respective inputs/outputs but we have completely no need
-     * for mixing or combining paths to different ports, so we
-     * connect both channels to where the left channel is routed.  */
-    if (s->in[0] && *s->in[0])
-        AUD_set_active_in(*s->in[0], 1);
-    if (s->out[0] && *s->out[0])
-        AUD_set_active_out(*s->out[0], 1);
-}
-
-static void wm8750_clk_update(WM8750State *s, int ext)
-{
-    if (s->master || !s->ext_dac_hz)
-        s->dac_hz = s->rate->dac_hz;
-    else
-        s->dac_hz = s->ext_dac_hz;
-
-    if (s->master || !s->ext_adc_hz)
-        s->adc_hz = s->rate->adc_hz;
-    else
-        s->adc_hz = s->ext_adc_hz;
-
-    if (s->master || (!s->ext_dac_hz && !s->ext_adc_hz)) {
-        if (!ext)
-            wm8750_set_format(s);
-    } else {
-        if (ext)
-            wm8750_set_format(s);
-    }
-}
-
-static void wm8750_reset(I2CSlave *i2c)
-{
-    WM8750State *s = (WM8750State *) i2c;
-    s->rate = &wm_rate_table[0];
-    s->enable = 0;
-    wm8750_clk_update(s, 1);
-    s->diff[0] = 0;
-    s->diff[1] = 0;
-    s->ds = 0;
-    s->alc = 0;
-    s->in[0] = &s->adc_voice[0];
-    s->invol[0] = 0x17;
-    s->invol[1] = 0x17;
-    s->invol[2] = 0xc3;
-    s->invol[3] = 0xc3;
-    s->out[0] = &s->dac_voice[0];
-    s->outvol[0] = 0xff;
-    s->outvol[1] = 0xff;
-    s->outvol[2] = 0x79;
-    s->outvol[3] = 0x79;
-    s->outvol[4] = 0x79;
-    s->outvol[5] = 0x79;
-    s->outvol[6] = 0x79;
-    s->inmute[0] = 0;
-    s->inmute[1] = 0;
-    s->outmute[0] = 0;
-    s->outmute[1] = 0;
-    s->mute = 1;
-    s->path[0] = 0;
-    s->path[1] = 0;
-    s->path[2] = 0;
-    s->path[3] = 0;
-    s->mpath[0] = 0;
-    s->mpath[1] = 0;
-    s->format = 0x0a;
-    s->idx_in = sizeof(s->data_in);
-    s->req_in = 0;
-    s->idx_out = 0;
-    s->req_out = 0;
-    wm8750_vol_update(s);
-    s->i2c_len = 0;
-}
-
-static void wm8750_event(I2CSlave *i2c, enum i2c_event event)
-{
-    WM8750State *s = (WM8750State *) i2c;
-
-    switch (event) {
-    case I2C_START_SEND:
-        s->i2c_len = 0;
-        break;
-    case I2C_FINISH:
-#ifdef VERBOSE
-        if (s->i2c_len < 2)
-            printf("%s: message too short (%i bytes)\n",
-                            __FUNCTION__, s->i2c_len);
-#endif
-        break;
-    default:
-        break;
-    }
-}
-
-#define WM8750_LINVOL  0x00
-#define WM8750_RINVOL  0x01
-#define WM8750_LOUT1V  0x02
-#define WM8750_ROUT1V  0x03
-#define WM8750_ADCDAC  0x05
-#define WM8750_IFACE   0x07
-#define WM8750_SRATE   0x08
-#define WM8750_LDAC    0x0a
-#define WM8750_RDAC    0x0b
-#define WM8750_BASS    0x0c
-#define WM8750_TREBLE  0x0d
-#define WM8750_RESET   0x0f
-#define WM8750_3D      0x10
-#define WM8750_ALC1    0x11
-#define WM8750_ALC2    0x12
-#define WM8750_ALC3    0x13
-#define WM8750_NGATE   0x14
-#define WM8750_LADC    0x15
-#define WM8750_RADC    0x16
-#define WM8750_ADCTL1  0x17
-#define WM8750_ADCTL2  0x18
-#define WM8750_PWR1    0x19
-#define WM8750_PWR2    0x1a
-#define WM8750_ADCTL3  0x1b
-#define WM8750_ADCIN   0x1f
-#define WM8750_LADCIN  0x20
-#define WM8750_RADCIN  0x21
-#define WM8750_LOUTM1  0x22
-#define WM8750_LOUTM2  0x23
-#define WM8750_ROUTM1  0x24
-#define WM8750_ROUTM2  0x25
-#define WM8750_MOUTM1  0x26
-#define WM8750_MOUTM2  0x27
-#define WM8750_LOUT2V  0x28
-#define WM8750_ROUT2V  0x29
-#define WM8750_MOUTV   0x2a
-
-static int wm8750_tx(I2CSlave *i2c, uint8_t data)
-{
-    WM8750State *s = (WM8750State *) i2c;
-    uint8_t cmd;
-    uint16_t value;
-
-    if (s->i2c_len >= 2) {
-#ifdef VERBOSE
-        printf("%s: long message (%i bytes)\n", __func__, s->i2c_len);
-#endif
-        return 1;
-    }
-    s->i2c_data[s->i2c_len ++] = data;
-    if (s->i2c_len != 2)
-        return 0;
-
-    cmd = s->i2c_data[0] >> 1;
-    value = ((s->i2c_data[0] << 8) | s->i2c_data[1]) & 0x1ff;
-
-    switch (cmd) {
-    case WM8750_LADCIN:        /* ADC Signal Path Control (Left) */
-        s->diff[0] = (((value >> 6) & 3) == 3);        /* LINSEL */
-        if (s->diff[0])
-            s->in[0] = &s->adc_voice[0 + s->ds * 1];
-        else
-            s->in[0] = &s->adc_voice[((value >> 6) & 3) * 1 + 0];
-        break;
-
-    case WM8750_RADCIN:        /* ADC Signal Path Control (Right) */
-        s->diff[1] = (((value >> 6) & 3) == 3);        /* RINSEL */
-        if (s->diff[1])
-            s->in[1] = &s->adc_voice[0 + s->ds * 1];
-        else
-            s->in[1] = &s->adc_voice[((value >> 6) & 3) * 1 + 0];
-        break;
-
-    case WM8750_ADCIN: /* ADC Input Mode */
-        s->ds = (value >> 8) & 1;      /* DS */
-        if (s->diff[0])
-            s->in[0] = &s->adc_voice[0 + s->ds * 1];
-        if (s->diff[1])
-            s->in[1] = &s->adc_voice[0 + s->ds * 1];
-        s->monomix[0] = (value >> 6) & 3;      /* MONOMIX */
-        break;
-
-    case WM8750_ADCTL1:        /* Additional Control (1) */
-        s->monomix[1] = (value >> 1) & 1;      /* DMONOMIX */
-        break;
-
-    case WM8750_PWR1:  /* Power Management (1) */
-        s->enable = ((value >> 6) & 7) == 3;   /* VMIDSEL, VREF */
-        wm8750_set_format(s);
-        break;
-
-    case WM8750_LINVOL:        /* Left Channel PGA */
-        s->invol[0] = value & 0x3f;            /* LINVOL */
-        s->inmute[0] = (value >> 7) & 1;       /* LINMUTE */
-        wm8750_vol_update(s);
-        break;
-
-    case WM8750_RINVOL:        /* Right Channel PGA */
-        s->invol[1] = value & 0x3f;            /* RINVOL */
-        s->inmute[1] = (value >> 7) & 1;       /* RINMUTE */
-        wm8750_vol_update(s);
-        break;
-
-    case WM8750_ADCDAC:        /* ADC and DAC Control */
-        s->pol = (value >> 5) & 3;             /* ADCPOL */
-        s->mute = (value >> 3) & 1;            /* DACMU */
-        wm8750_vol_update(s);
-        break;
-
-    case WM8750_ADCTL3:        /* Additional Control (3) */
-        break;
-
-    case WM8750_LADC:  /* Left ADC Digital Volume */
-        s->invol[2] = value & 0xff;            /* LADCVOL */
-        wm8750_vol_update(s);
-        break;
-
-    case WM8750_RADC:  /* Right ADC Digital Volume */
-        s->invol[3] = value & 0xff;            /* RADCVOL */
-        wm8750_vol_update(s);
-        break;
-
-    case WM8750_ALC1:  /* ALC Control (1) */
-        s->alc = (value >> 7) & 3;             /* ALCSEL */
-        break;
-
-    case WM8750_NGATE: /* Noise Gate Control */
-    case WM8750_3D:    /* 3D enhance */
-        break;
-
-    case WM8750_LDAC:  /* Left Channel Digital Volume */
-        s->outvol[0] = value & 0xff;           /* LDACVOL */
-        wm8750_vol_update(s);
-        break;
-
-    case WM8750_RDAC:  /* Right Channel Digital Volume */
-        s->outvol[1] = value & 0xff;           /* RDACVOL */
-        wm8750_vol_update(s);
-        break;
-
-    case WM8750_BASS:  /* Bass Control */
-        break;
-
-    case WM8750_LOUTM1:        /* Left Mixer Control (1) */
-        s->path[0] = (value >> 8) & 1;         /* LD2LO */
-        /* TODO: mute/unmute respective paths */
-        wm8750_vol_update(s);
-        break;
-
-    case WM8750_LOUTM2:        /* Left Mixer Control (2) */
-        s->path[1] = (value >> 8) & 1;         /* RD2LO */
-        /* TODO: mute/unmute respective paths */
-        wm8750_vol_update(s);
-        break;
-
-    case WM8750_ROUTM1:        /* Right Mixer Control (1) */
-        s->path[2] = (value >> 8) & 1;         /* LD2RO */
-        /* TODO: mute/unmute respective paths */
-        wm8750_vol_update(s);
-        break;
-
-    case WM8750_ROUTM2:        /* Right Mixer Control (2) */
-        s->path[3] = (value >> 8) & 1;         /* RD2RO */
-        /* TODO: mute/unmute respective paths */
-        wm8750_vol_update(s);
-        break;
-
-    case WM8750_MOUTM1:        /* Mono Mixer Control (1) */
-        s->mpath[0] = (value >> 8) & 1;                /* LD2MO */
-        /* TODO: mute/unmute respective paths */
-        wm8750_vol_update(s);
-        break;
-
-    case WM8750_MOUTM2:        /* Mono Mixer Control (2) */
-        s->mpath[1] = (value >> 8) & 1;                /* RD2MO */
-        /* TODO: mute/unmute respective paths */
-        wm8750_vol_update(s);
-        break;
-
-    case WM8750_LOUT1V:        /* LOUT1 Volume */
-        s->outvol[2] = value & 0x7f;           /* LOUT1VOL */
-        wm8750_vol_update(s);
-        break;
-
-    case WM8750_LOUT2V:        /* LOUT2 Volume */
-        s->outvol[4] = value & 0x7f;           /* LOUT2VOL */
-        wm8750_vol_update(s);
-        break;
-
-    case WM8750_ROUT1V:        /* ROUT1 Volume */
-        s->outvol[3] = value & 0x7f;           /* ROUT1VOL */
-        wm8750_vol_update(s);
-        break;
-
-    case WM8750_ROUT2V:        /* ROUT2 Volume */
-        s->outvol[5] = value & 0x7f;           /* ROUT2VOL */
-        wm8750_vol_update(s);
-        break;
-
-    case WM8750_MOUTV: /* MONOOUT Volume */
-        s->outvol[6] = value & 0x7f;           /* MONOOUTVOL */
-        wm8750_vol_update(s);
-        break;
-
-    case WM8750_ADCTL2:        /* Additional Control (2) */
-        break;
-
-    case WM8750_PWR2:  /* Power Management (2) */
-        s->power = value & 0x7e;
-        /* TODO: mute/unmute respective paths */
-        wm8750_vol_update(s);
-        break;
-
-    case WM8750_IFACE: /* Digital Audio Interface Format */
-        s->format = value;
-        s->master = (value >> 6) & 1;                  /* MS */
-        wm8750_clk_update(s, s->master);
-        break;
-
-    case WM8750_SRATE: /* Clocking and Sample Rate Control */
-        s->rate = &wm_rate_table[(value >> 1) & 0x1f];
-        wm8750_clk_update(s, 0);
-        break;
-
-    case WM8750_RESET: /* Reset */
-        wm8750_reset(&s->i2c);
-        break;
-
-#ifdef VERBOSE
-    default:
-        printf("%s: unknown register %02x\n", __FUNCTION__, cmd);
-#endif
-    }
-
-    return 0;
-}
-
-static int wm8750_rx(I2CSlave *i2c)
-{
-    return 0x00;
-}
-
-static void wm8750_pre_save(void *opaque)
-{
-    WM8750State *s = opaque;
-
-    s->rate_vmstate = s->rate - wm_rate_table;
-}
-
-static int wm8750_post_load(void *opaque, int version_id)
-{
-    WM8750State *s = opaque;
-
-    s->rate = &wm_rate_table[s->rate_vmstate & 0x1f];
-    return 0;
-}
-
-static const VMStateDescription vmstate_wm8750 = {
-    .name = CODEC,
-    .version_id = 0,
-    .minimum_version_id = 0,
-    .minimum_version_id_old = 0,
-    .pre_save = wm8750_pre_save,
-    .post_load = wm8750_post_load,
-    .fields      = (VMStateField []) {
-        VMSTATE_UINT8_ARRAY(i2c_data, WM8750State, 2),
-        VMSTATE_INT32(i2c_len, WM8750State),
-        VMSTATE_INT32(enable, WM8750State),
-        VMSTATE_INT32(idx_in, WM8750State),
-        VMSTATE_INT32(req_in, WM8750State),
-        VMSTATE_INT32(idx_out, WM8750State),
-        VMSTATE_INT32(req_out, WM8750State),
-        VMSTATE_UINT8_ARRAY(outvol, WM8750State, 7),
-        VMSTATE_UINT8_ARRAY(outmute, WM8750State, 2),
-        VMSTATE_UINT8_ARRAY(invol, WM8750State, 4),
-        VMSTATE_UINT8_ARRAY(inmute, WM8750State, 2),
-        VMSTATE_UINT8_ARRAY(diff, WM8750State, 2),
-        VMSTATE_UINT8(pol, WM8750State),
-        VMSTATE_UINT8(ds, WM8750State),
-        VMSTATE_UINT8_ARRAY(monomix, WM8750State, 2),
-        VMSTATE_UINT8(alc, WM8750State),
-        VMSTATE_UINT8(mute, WM8750State),
-        VMSTATE_UINT8_ARRAY(path, WM8750State, 4),
-        VMSTATE_UINT8_ARRAY(mpath, WM8750State, 2),
-        VMSTATE_UINT8(format, WM8750State),
-        VMSTATE_UINT8(power, WM8750State),
-        VMSTATE_UINT8(rate_vmstate, WM8750State),
-        VMSTATE_I2C_SLAVE(i2c, WM8750State),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static int wm8750_init(I2CSlave *i2c)
-{
-    WM8750State *s = FROM_I2C_SLAVE(WM8750State, i2c);
-
-    AUD_register_card(CODEC, &s->card);
-    wm8750_reset(&s->i2c);
-
-    return 0;
-}
-
-#if 0
-static void wm8750_fini(I2CSlave *i2c)
-{
-    WM8750State *s = (WM8750State *) i2c;
-    wm8750_reset(&s->i2c);
-    AUD_remove_card(&s->card);
-    g_free(s);
-}
-#endif
-
-void wm8750_data_req_set(DeviceState *dev,
-                void (*data_req)(void *, int, int), void *opaque)
-{
-    WM8750State *s = FROM_I2C_SLAVE(WM8750State, I2C_SLAVE(dev));
-    s->data_req = data_req;
-    s->opaque = opaque;
-}
-
-void wm8750_dac_dat(void *opaque, uint32_t sample)
-{
-    WM8750State *s = (WM8750State *) opaque;
-
-    *(uint32_t *) &s->data_out[s->idx_out] = sample;
-    s->req_out -= 4;
-    s->idx_out += 4;
-    if (s->idx_out >= sizeof(s->data_out) || s->req_out <= 0)
-        wm8750_out_flush(s);
-}
-
-void *wm8750_dac_buffer(void *opaque, int samples)
-{
-    WM8750State *s = (WM8750State *) opaque;
-    /* XXX: Should check if there are <i>samples</i> free samples available */
-    void *ret = s->data_out + s->idx_out;
-
-    s->idx_out += samples << 2;
-    s->req_out -= samples << 2;
-    return ret;
-}
-
-void wm8750_dac_commit(void *opaque)
-{
-    WM8750State *s = (WM8750State *) opaque;
-
-    wm8750_out_flush(s);
-}
-
-uint32_t wm8750_adc_dat(void *opaque)
-{
-    WM8750State *s = (WM8750State *) opaque;
-    uint32_t *data;
-
-    if (s->idx_in >= sizeof(s->data_in))
-        wm8750_in_load(s);
-
-    data = (uint32_t *) &s->data_in[s->idx_in];
-    s->req_in -= 4;
-    s->idx_in += 4;
-    return *data;
-}
-
-void wm8750_set_bclk_in(void *opaque, int new_hz)
-{
-    WM8750State *s = (WM8750State *) opaque;
-
-    s->ext_adc_hz = new_hz;
-    s->ext_dac_hz = new_hz;
-    wm8750_clk_update(s, 1);
-}
-
-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 const TypeInfo wm8750_info = {
-    .name          = "wm8750",
-    .parent        = TYPE_I2C_SLAVE,
-    .instance_size = sizeof(WM8750State),
-    .class_init    = wm8750_class_init,
-};
-
-static void wm8750_register_types(void)
-{
-    type_register_static(&wm8750_info);
-}
-
-type_init(wm8750_register_types)
diff --git a/hw/xen-host-pci-device.c b/hw/xen-host-pci-device.c
deleted file mode 100644 (file)
index ff2e876..0000000
+++ /dev/null
@@ -1,396 +0,0 @@
-/*
- * Copyright (C) 2011       Citrix Ltd.
- *
- * This work is licensed under the terms of the GNU GPL, version 2.  See
- * the COPYING file in the top-level directory.
- *
- */
-
-#include "qemu-common.h"
-#include "hw/xen-host-pci-device.h"
-
-#define XEN_HOST_PCI_MAX_EXT_CAP \
-    ((PCIE_CONFIG_SPACE_SIZE - PCI_CONFIG_SPACE_SIZE) / (PCI_CAP_SIZEOF + 4))
-
-#ifdef XEN_HOST_PCI_DEVICE_DEBUG
-#  define XEN_HOST_PCI_LOG(f, a...) fprintf(stderr, "%s: " f, __func__, ##a)
-#else
-#  define XEN_HOST_PCI_LOG(f, a...) (void)0
-#endif
-
-/*
- * from linux/ioport.h
- * IO resources have these defined flags.
- */
-#define IORESOURCE_BITS         0x000000ff      /* Bus-specific bits */
-
-#define IORESOURCE_TYPE_BITS    0x00000f00      /* Resource type */
-#define IORESOURCE_IO           0x00000100
-#define IORESOURCE_MEM          0x00000200
-
-#define IORESOURCE_PREFETCH     0x00001000      /* No side effects */
-#define IORESOURCE_MEM_64       0x00100000
-
-static int xen_host_pci_sysfs_path(const XenHostPCIDevice *d,
-                                   const char *name, char *buf, ssize_t size)
-{
-    int rc;
-
-    rc = snprintf(buf, size, "/sys/bus/pci/devices/%04x:%02x:%02x.%d/%s",
-                  d->domain, d->bus, d->dev, d->func, name);
-
-    if (rc >= size || rc < 0) {
-        /* The ouput is truncated or an other error is encountered */
-        return -ENODEV;
-    }
-    return 0;
-}
-
-
-/* This size should be enough to read the first 7 lines of a resource file */
-#define XEN_HOST_PCI_RESOURCE_BUFFER_SIZE 400
-static int xen_host_pci_get_resource(XenHostPCIDevice *d)
-{
-    int i, rc, fd;
-    char path[PATH_MAX];
-    char buf[XEN_HOST_PCI_RESOURCE_BUFFER_SIZE];
-    unsigned long long start, end, flags, size;
-    char *endptr, *s;
-    uint8_t type;
-
-    rc = xen_host_pci_sysfs_path(d, "resource", path, sizeof (path));
-    if (rc) {
-        return rc;
-    }
-    fd = open(path, O_RDONLY);
-    if (fd == -1) {
-        XEN_HOST_PCI_LOG("Error: Can't open %s: %s\n", path, strerror(errno));
-        return -errno;
-    }
-
-    do {
-        rc = read(fd, &buf, sizeof (buf) - 1);
-        if (rc < 0 && errno != EINTR) {
-            rc = -errno;
-            goto out;
-        }
-    } while (rc < 0);
-    buf[rc] = 0;
-    rc = 0;
-
-    s = buf;
-    for (i = 0; i < PCI_NUM_REGIONS; i++) {
-        type = 0;
-
-        start = strtoll(s, &endptr, 16);
-        if (*endptr != ' ' || s == endptr) {
-            break;
-        }
-        s = endptr + 1;
-        end = strtoll(s, &endptr, 16);
-        if (*endptr != ' ' || s == endptr) {
-            break;
-        }
-        s = endptr + 1;
-        flags = strtoll(s, &endptr, 16);
-        if (*endptr != '\n' || s == endptr) {
-            break;
-        }
-        s = endptr + 1;
-
-        if (start) {
-            size = end - start + 1;
-        } else {
-            size = 0;
-        }
-
-        if (flags & IORESOURCE_IO) {
-            type |= XEN_HOST_PCI_REGION_TYPE_IO;
-        }
-        if (flags & IORESOURCE_MEM) {
-            type |= XEN_HOST_PCI_REGION_TYPE_MEM;
-        }
-        if (flags & IORESOURCE_PREFETCH) {
-            type |= XEN_HOST_PCI_REGION_TYPE_PREFETCH;
-        }
-        if (flags & IORESOURCE_MEM_64) {
-            type |= XEN_HOST_PCI_REGION_TYPE_MEM_64;
-        }
-
-        if (i < PCI_ROM_SLOT) {
-            d->io_regions[i].base_addr = start;
-            d->io_regions[i].size = size;
-            d->io_regions[i].type = type;
-            d->io_regions[i].bus_flags = flags & IORESOURCE_BITS;
-        } else {
-            d->rom.base_addr = start;
-            d->rom.size = size;
-            d->rom.type = type;
-            d->rom.bus_flags = flags & IORESOURCE_BITS;
-        }
-    }
-    if (i != PCI_NUM_REGIONS) {
-        /* Invalid format or input to short */
-        rc = -ENODEV;
-    }
-
-out:
-    close(fd);
-    return rc;
-}
-
-/* This size should be enough to read a long from a file */
-#define XEN_HOST_PCI_GET_VALUE_BUFFER_SIZE 22
-static int xen_host_pci_get_value(XenHostPCIDevice *d, const char *name,
-                                  unsigned int *pvalue, int base)
-{
-    char path[PATH_MAX];
-    char buf[XEN_HOST_PCI_GET_VALUE_BUFFER_SIZE];
-    int fd, rc;
-    unsigned long value;
-    char *endptr;
-
-    rc = xen_host_pci_sysfs_path(d, name, path, sizeof (path));
-    if (rc) {
-        return rc;
-    }
-    fd = open(path, O_RDONLY);
-    if (fd == -1) {
-        XEN_HOST_PCI_LOG("Error: Can't open %s: %s\n", path, strerror(errno));
-        return -errno;
-    }
-    do {
-        rc = read(fd, &buf, sizeof (buf) - 1);
-        if (rc < 0 && errno != EINTR) {
-            rc = -errno;
-            goto out;
-        }
-    } while (rc < 0);
-    buf[rc] = 0;
-    value = strtol(buf, &endptr, base);
-    if (endptr == buf || *endptr != '\n') {
-        rc = -1;
-    } else if ((value == LONG_MIN || value == LONG_MAX) && errno == ERANGE) {
-        rc = -errno;
-    } else {
-        rc = 0;
-        *pvalue = value;
-    }
-out:
-    close(fd);
-    return rc;
-}
-
-static inline int xen_host_pci_get_hex_value(XenHostPCIDevice *d,
-                                             const char *name,
-                                             unsigned int *pvalue)
-{
-    return xen_host_pci_get_value(d, name, pvalue, 16);
-}
-
-static inline int xen_host_pci_get_dec_value(XenHostPCIDevice *d,
-                                             const char *name,
-                                             unsigned int *pvalue)
-{
-    return xen_host_pci_get_value(d, name, pvalue, 10);
-}
-
-static bool xen_host_pci_dev_is_virtfn(XenHostPCIDevice *d)
-{
-    char path[PATH_MAX];
-    struct stat buf;
-
-    if (xen_host_pci_sysfs_path(d, "physfn", path, sizeof (path))) {
-        return false;
-    }
-    return !stat(path, &buf);
-}
-
-static int xen_host_pci_config_open(XenHostPCIDevice *d)
-{
-    char path[PATH_MAX];
-    int rc;
-
-    rc = xen_host_pci_sysfs_path(d, "config", path, sizeof (path));
-    if (rc) {
-        return rc;
-    }
-    d->config_fd = open(path, O_RDWR);
-    if (d->config_fd < 0) {
-        return -errno;
-    }
-    return 0;
-}
-
-static int xen_host_pci_config_read(XenHostPCIDevice *d,
-                                    int pos, void *buf, int len)
-{
-    int rc;
-
-    do {
-        rc = pread(d->config_fd, buf, len, pos);
-    } while (rc < 0 && (errno == EINTR || errno == EAGAIN));
-    if (rc != len) {
-        return -errno;
-    }
-    return 0;
-}
-
-static int xen_host_pci_config_write(XenHostPCIDevice *d,
-                                     int pos, const void *buf, int len)
-{
-    int rc;
-
-    do {
-        rc = pwrite(d->config_fd, buf, len, pos);
-    } while (rc < 0 && (errno == EINTR || errno == EAGAIN));
-    if (rc != len) {
-        return -errno;
-    }
-    return 0;
-}
-
-
-int xen_host_pci_get_byte(XenHostPCIDevice *d, int pos, uint8_t *p)
-{
-    uint8_t buf;
-    int rc = xen_host_pci_config_read(d, pos, &buf, 1);
-    if (!rc) {
-        *p = buf;
-    }
-    return rc;
-}
-
-int xen_host_pci_get_word(XenHostPCIDevice *d, int pos, uint16_t *p)
-{
-    uint16_t buf;
-    int rc = xen_host_pci_config_read(d, pos, &buf, 2);
-    if (!rc) {
-        *p = le16_to_cpu(buf);
-    }
-    return rc;
-}
-
-int xen_host_pci_get_long(XenHostPCIDevice *d, int pos, uint32_t *p)
-{
-    uint32_t buf;
-    int rc = xen_host_pci_config_read(d, pos, &buf, 4);
-    if (!rc) {
-        *p = le32_to_cpu(buf);
-    }
-    return rc;
-}
-
-int xen_host_pci_get_block(XenHostPCIDevice *d, int pos, uint8_t *buf, int len)
-{
-    return xen_host_pci_config_read(d, pos, buf, len);
-}
-
-int xen_host_pci_set_byte(XenHostPCIDevice *d, int pos, uint8_t data)
-{
-    return xen_host_pci_config_write(d, pos, &data, 1);
-}
-
-int xen_host_pci_set_word(XenHostPCIDevice *d, int pos, uint16_t data)
-{
-    data = cpu_to_le16(data);
-    return xen_host_pci_config_write(d, pos, &data, 2);
-}
-
-int xen_host_pci_set_long(XenHostPCIDevice *d, int pos, uint32_t data)
-{
-    data = cpu_to_le32(data);
-    return xen_host_pci_config_write(d, pos, &data, 4);
-}
-
-int xen_host_pci_set_block(XenHostPCIDevice *d, int pos, uint8_t *buf, int len)
-{
-    return xen_host_pci_config_write(d, pos, buf, len);
-}
-
-int xen_host_pci_find_ext_cap_offset(XenHostPCIDevice *d, uint32_t cap)
-{
-    uint32_t header = 0;
-    int max_cap = XEN_HOST_PCI_MAX_EXT_CAP;
-    int pos = PCI_CONFIG_SPACE_SIZE;
-
-    do {
-        if (xen_host_pci_get_long(d, pos, &header)) {
-            break;
-        }
-        /*
-         * If we have no capabilities, this is indicated by cap ID,
-         * cap version and next pointer all being 0.
-         */
-        if (header == 0) {
-            break;
-        }
-
-        if (PCI_EXT_CAP_ID(header) == cap) {
-            return pos;
-        }
-
-        pos = PCI_EXT_CAP_NEXT(header);
-        if (pos < PCI_CONFIG_SPACE_SIZE) {
-            break;
-        }
-
-        max_cap--;
-    } while (max_cap > 0);
-
-    return -1;
-}
-
-int xen_host_pci_device_get(XenHostPCIDevice *d, uint16_t domain,
-                            uint8_t bus, uint8_t dev, uint8_t func)
-{
-    unsigned int v;
-    int rc = 0;
-
-    d->config_fd = -1;
-    d->domain = domain;
-    d->bus = bus;
-    d->dev = dev;
-    d->func = func;
-
-    rc = xen_host_pci_config_open(d);
-    if (rc) {
-        goto error;
-    }
-    rc = xen_host_pci_get_resource(d);
-    if (rc) {
-        goto error;
-    }
-    rc = xen_host_pci_get_hex_value(d, "vendor", &v);
-    if (rc) {
-        goto error;
-    }
-    d->vendor_id = v;
-    rc = xen_host_pci_get_hex_value(d, "device", &v);
-    if (rc) {
-        goto error;
-    }
-    d->device_id = v;
-    rc = xen_host_pci_get_dec_value(d, "irq", &v);
-    if (rc) {
-        goto error;
-    }
-    d->irq = v;
-    d->is_virtfn = xen_host_pci_dev_is_virtfn(d);
-
-    return 0;
-error:
-    if (d->config_fd >= 0) {
-        close(d->config_fd);
-        d->config_fd = -1;
-    }
-    return rc;
-}
-
-void xen_host_pci_device_put(XenHostPCIDevice *d)
-{
-    if (d->config_fd >= 0) {
-        close(d->config_fd);
-        d->config_fd = -1;
-    }
-}
diff --git a/hw/xen-host-pci-device.h b/hw/xen-host-pci-device.h
deleted file mode 100644 (file)
index c2486f0..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-#ifndef XEN_HOST_PCI_DEVICE_H
-#define XEN_HOST_PCI_DEVICE_H
-
-#include "hw/pci/pci.h"
-
-enum {
-    XEN_HOST_PCI_REGION_TYPE_IO = 1 << 1,
-    XEN_HOST_PCI_REGION_TYPE_MEM = 1 << 2,
-    XEN_HOST_PCI_REGION_TYPE_PREFETCH = 1 << 3,
-    XEN_HOST_PCI_REGION_TYPE_MEM_64 = 1 << 4,
-};
-
-typedef struct XenHostPCIIORegion {
-    pcibus_t base_addr;
-    pcibus_t size;
-    uint8_t type;
-    uint8_t bus_flags; /* Bus-specific bits */
-} XenHostPCIIORegion;
-
-typedef struct XenHostPCIDevice {
-    uint16_t domain;
-    uint8_t bus;
-    uint8_t dev;
-    uint8_t func;
-
-    uint16_t vendor_id;
-    uint16_t device_id;
-    int irq;
-
-    XenHostPCIIORegion io_regions[PCI_NUM_REGIONS - 1];
-    XenHostPCIIORegion rom;
-
-    bool is_virtfn;
-
-    int config_fd;
-} XenHostPCIDevice;
-
-int xen_host_pci_device_get(XenHostPCIDevice *d, uint16_t domain,
-                            uint8_t bus, uint8_t dev, uint8_t func);
-void xen_host_pci_device_put(XenHostPCIDevice *pci_dev);
-
-int xen_host_pci_get_byte(XenHostPCIDevice *d, int pos, uint8_t *p);
-int xen_host_pci_get_word(XenHostPCIDevice *d, int pos, uint16_t *p);
-int xen_host_pci_get_long(XenHostPCIDevice *d, int pos, uint32_t *p);
-int xen_host_pci_get_block(XenHostPCIDevice *d, int pos, uint8_t *buf,
-                           int len);
-int xen_host_pci_set_byte(XenHostPCIDevice *d, int pos, uint8_t data);
-int xen_host_pci_set_word(XenHostPCIDevice *d, int pos, uint16_t data);
-int xen_host_pci_set_long(XenHostPCIDevice *d, int pos, uint32_t data);
-int xen_host_pci_set_block(XenHostPCIDevice *d, int pos, uint8_t *buf,
-                           int len);
-
-int xen_host_pci_find_ext_cap_offset(XenHostPCIDevice *s, uint32_t cap);
-
-#endif /* !XEN_HOST_PCI_DEVICE_H_ */
diff --git a/hw/xen.h b/hw/xen.h
deleted file mode 100644 (file)
index 6235f91..0000000
--- a/hw/xen.h
+++ /dev/null
@@ -1,62 +0,0 @@
-#ifndef QEMU_HW_XEN_H
-#define QEMU_HW_XEN_H 1
-/*
- * public xen header
- *   stuff needed outside xen-*.c, i.e. interfaces to qemu.
- *   must not depend on any xen headers being present in
- *   /usr/include/xen, so it can be included unconditionally.
- */
-#include <inttypes.h>
-
-#include "hw/irq.h"
-#include "qemu-common.h"
-
-/* xen-machine.c */
-enum xen_mode {
-    XEN_EMULATE = 0,  // xen emulation, using xenner (default)
-    XEN_CREATE,       // create xen domain
-    XEN_ATTACH        // attach to xen domain created by xend
-};
-
-extern uint32_t xen_domid;
-extern enum xen_mode xen_mode;
-
-extern bool xen_allowed;
-
-static inline bool xen_enabled(void)
-{
-#if defined(CONFIG_XEN_BACKEND) && !defined(CONFIG_NO_XEN)
-    return xen_allowed;
-#else
-    return 0;
-#endif
-}
-
-int xen_pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num);
-void xen_piix3_set_irq(void *opaque, int irq_num, int level);
-void xen_piix_pci_write_config_client(uint32_t address, uint32_t val, int len);
-void xen_hvm_inject_msi(uint64_t addr, uint32_t data);
-void xen_cmos_set_s3_resume(void *opaque, int irq, int level);
-
-qemu_irq *xen_interrupt_controller_init(void);
-
-int xen_init(void);
-int xen_hvm_init(void);
-void xen_vcpu_init(void);
-void xenstore_store_pv_console_info(int i, struct CharDriverState *chr);
-
-#if defined(NEED_CPU_H) && !defined(CONFIG_USER_ONLY)
-struct MemoryRegion;
-void xen_ram_alloc(ram_addr_t ram_addr, ram_addr_t size,
-                   struct MemoryRegion *mr);
-void xen_modified_memory(ram_addr_t start, ram_addr_t length);
-#endif
-
-struct MemoryRegion;
-void xen_register_framebuffer(struct MemoryRegion *mr);
-
-#if defined(CONFIG_XEN) && CONFIG_XEN_CTRL_INTERFACE_VERSION < 400
-#  define HVM_MAX_VCPUS 32
-#endif
-
-#endif /* QEMU_HW_XEN_H */
diff --git a/hw/xen/Makefile.objs b/hw/xen/Makefile.objs
new file mode 100644 (file)
index 0000000..2017560
--- /dev/null
@@ -0,0 +1,6 @@
+# xen backend driver support
+common-obj-$(CONFIG_XEN_BACKEND) += xen_backend.o xen_devconfig.o
+
+obj-$(CONFIG_XEN_I386) += xen_platform.o xen_apic.o
+obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen-host-pci-device.o
+obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen_pt.o xen_pt_config_init.o xen_pt_msi.o
diff --git a/hw/xen/xen-host-pci-device.c b/hw/xen/xen-host-pci-device.c
new file mode 100644 (file)
index 0000000..743b37b
--- /dev/null
@@ -0,0 +1,396 @@
+/*
+ * Copyright (C) 2011       Citrix Ltd.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu-common.h"
+#include "xen-host-pci-device.h"
+
+#define XEN_HOST_PCI_MAX_EXT_CAP \
+    ((PCIE_CONFIG_SPACE_SIZE - PCI_CONFIG_SPACE_SIZE) / (PCI_CAP_SIZEOF + 4))
+
+#ifdef XEN_HOST_PCI_DEVICE_DEBUG
+#  define XEN_HOST_PCI_LOG(f, a...) fprintf(stderr, "%s: " f, __func__, ##a)
+#else
+#  define XEN_HOST_PCI_LOG(f, a...) (void)0
+#endif
+
+/*
+ * from linux/ioport.h
+ * IO resources have these defined flags.
+ */
+#define IORESOURCE_BITS         0x000000ff      /* Bus-specific bits */
+
+#define IORESOURCE_TYPE_BITS    0x00000f00      /* Resource type */
+#define IORESOURCE_IO           0x00000100
+#define IORESOURCE_MEM          0x00000200
+
+#define IORESOURCE_PREFETCH     0x00001000      /* No side effects */
+#define IORESOURCE_MEM_64       0x00100000
+
+static int xen_host_pci_sysfs_path(const XenHostPCIDevice *d,
+                                   const char *name, char *buf, ssize_t size)
+{
+    int rc;
+
+    rc = snprintf(buf, size, "/sys/bus/pci/devices/%04x:%02x:%02x.%d/%s",
+                  d->domain, d->bus, d->dev, d->func, name);
+
+    if (rc >= size || rc < 0) {
+        /* The ouput is truncated or an other error is encountered */
+        return -ENODEV;
+    }
+    return 0;
+}
+
+
+/* This size should be enough to read the first 7 lines of a resource file */
+#define XEN_HOST_PCI_RESOURCE_BUFFER_SIZE 400
+static int xen_host_pci_get_resource(XenHostPCIDevice *d)
+{
+    int i, rc, fd;
+    char path[PATH_MAX];
+    char buf[XEN_HOST_PCI_RESOURCE_BUFFER_SIZE];
+    unsigned long long start, end, flags, size;
+    char *endptr, *s;
+    uint8_t type;
+
+    rc = xen_host_pci_sysfs_path(d, "resource", path, sizeof (path));
+    if (rc) {
+        return rc;
+    }
+    fd = open(path, O_RDONLY);
+    if (fd == -1) {
+        XEN_HOST_PCI_LOG("Error: Can't open %s: %s\n", path, strerror(errno));
+        return -errno;
+    }
+
+    do {
+        rc = read(fd, &buf, sizeof (buf) - 1);
+        if (rc < 0 && errno != EINTR) {
+            rc = -errno;
+            goto out;
+        }
+    } while (rc < 0);
+    buf[rc] = 0;
+    rc = 0;
+
+    s = buf;
+    for (i = 0; i < PCI_NUM_REGIONS; i++) {
+        type = 0;
+
+        start = strtoll(s, &endptr, 16);
+        if (*endptr != ' ' || s == endptr) {
+            break;
+        }
+        s = endptr + 1;
+        end = strtoll(s, &endptr, 16);
+        if (*endptr != ' ' || s == endptr) {
+            break;
+        }
+        s = endptr + 1;
+        flags = strtoll(s, &endptr, 16);
+        if (*endptr != '\n' || s == endptr) {
+            break;
+        }
+        s = endptr + 1;
+
+        if (start) {
+            size = end - start + 1;
+        } else {
+            size = 0;
+        }
+
+        if (flags & IORESOURCE_IO) {
+            type |= XEN_HOST_PCI_REGION_TYPE_IO;
+        }
+        if (flags & IORESOURCE_MEM) {
+            type |= XEN_HOST_PCI_REGION_TYPE_MEM;
+        }
+        if (flags & IORESOURCE_PREFETCH) {
+            type |= XEN_HOST_PCI_REGION_TYPE_PREFETCH;
+        }
+        if (flags & IORESOURCE_MEM_64) {
+            type |= XEN_HOST_PCI_REGION_TYPE_MEM_64;
+        }
+
+        if (i < PCI_ROM_SLOT) {
+            d->io_regions[i].base_addr = start;
+            d->io_regions[i].size = size;
+            d->io_regions[i].type = type;
+            d->io_regions[i].bus_flags = flags & IORESOURCE_BITS;
+        } else {
+            d->rom.base_addr = start;
+            d->rom.size = size;
+            d->rom.type = type;
+            d->rom.bus_flags = flags & IORESOURCE_BITS;
+        }
+    }
+    if (i != PCI_NUM_REGIONS) {
+        /* Invalid format or input to short */
+        rc = -ENODEV;
+    }
+
+out:
+    close(fd);
+    return rc;
+}
+
+/* This size should be enough to read a long from a file */
+#define XEN_HOST_PCI_GET_VALUE_BUFFER_SIZE 22
+static int xen_host_pci_get_value(XenHostPCIDevice *d, const char *name,
+                                  unsigned int *pvalue, int base)
+{
+    char path[PATH_MAX];
+    char buf[XEN_HOST_PCI_GET_VALUE_BUFFER_SIZE];
+    int fd, rc;
+    unsigned long value;
+    char *endptr;
+
+    rc = xen_host_pci_sysfs_path(d, name, path, sizeof (path));
+    if (rc) {
+        return rc;
+    }
+    fd = open(path, O_RDONLY);
+    if (fd == -1) {
+        XEN_HOST_PCI_LOG("Error: Can't open %s: %s\n", path, strerror(errno));
+        return -errno;
+    }
+    do {
+        rc = read(fd, &buf, sizeof (buf) - 1);
+        if (rc < 0 && errno != EINTR) {
+            rc = -errno;
+            goto out;
+        }
+    } while (rc < 0);
+    buf[rc] = 0;
+    value = strtol(buf, &endptr, base);
+    if (endptr == buf || *endptr != '\n') {
+        rc = -1;
+    } else if ((value == LONG_MIN || value == LONG_MAX) && errno == ERANGE) {
+        rc = -errno;
+    } else {
+        rc = 0;
+        *pvalue = value;
+    }
+out:
+    close(fd);
+    return rc;
+}
+
+static inline int xen_host_pci_get_hex_value(XenHostPCIDevice *d,
+                                             const char *name,
+                                             unsigned int *pvalue)
+{
+    return xen_host_pci_get_value(d, name, pvalue, 16);
+}
+
+static inline int xen_host_pci_get_dec_value(XenHostPCIDevice *d,
+                                             const char *name,
+                                             unsigned int *pvalue)
+{
+    return xen_host_pci_get_value(d, name, pvalue, 10);
+}
+
+static bool xen_host_pci_dev_is_virtfn(XenHostPCIDevice *d)
+{
+    char path[PATH_MAX];
+    struct stat buf;
+
+    if (xen_host_pci_sysfs_path(d, "physfn", path, sizeof (path))) {
+        return false;
+    }
+    return !stat(path, &buf);
+}
+
+static int xen_host_pci_config_open(XenHostPCIDevice *d)
+{
+    char path[PATH_MAX];
+    int rc;
+
+    rc = xen_host_pci_sysfs_path(d, "config", path, sizeof (path));
+    if (rc) {
+        return rc;
+    }
+    d->config_fd = open(path, O_RDWR);
+    if (d->config_fd < 0) {
+        return -errno;
+    }
+    return 0;
+}
+
+static int xen_host_pci_config_read(XenHostPCIDevice *d,
+                                    int pos, void *buf, int len)
+{
+    int rc;
+
+    do {
+        rc = pread(d->config_fd, buf, len, pos);
+    } while (rc < 0 && (errno == EINTR || errno == EAGAIN));
+    if (rc != len) {
+        return -errno;
+    }
+    return 0;
+}
+
+static int xen_host_pci_config_write(XenHostPCIDevice *d,
+                                     int pos, const void *buf, int len)
+{
+    int rc;
+
+    do {
+        rc = pwrite(d->config_fd, buf, len, pos);
+    } while (rc < 0 && (errno == EINTR || errno == EAGAIN));
+    if (rc != len) {
+        return -errno;
+    }
+    return 0;
+}
+
+
+int xen_host_pci_get_byte(XenHostPCIDevice *d, int pos, uint8_t *p)
+{
+    uint8_t buf;
+    int rc = xen_host_pci_config_read(d, pos, &buf, 1);
+    if (!rc) {
+        *p = buf;
+    }
+    return rc;
+}
+
+int xen_host_pci_get_word(XenHostPCIDevice *d, int pos, uint16_t *p)
+{
+    uint16_t buf;
+    int rc = xen_host_pci_config_read(d, pos, &buf, 2);
+    if (!rc) {
+        *p = le16_to_cpu(buf);
+    }
+    return rc;
+}
+
+int xen_host_pci_get_long(XenHostPCIDevice *d, int pos, uint32_t *p)
+{
+    uint32_t buf;
+    int rc = xen_host_pci_config_read(d, pos, &buf, 4);
+    if (!rc) {
+        *p = le32_to_cpu(buf);
+    }
+    return rc;
+}
+
+int xen_host_pci_get_block(XenHostPCIDevice *d, int pos, uint8_t *buf, int len)
+{
+    return xen_host_pci_config_read(d, pos, buf, len);
+}
+
+int xen_host_pci_set_byte(XenHostPCIDevice *d, int pos, uint8_t data)
+{
+    return xen_host_pci_config_write(d, pos, &data, 1);
+}
+
+int xen_host_pci_set_word(XenHostPCIDevice *d, int pos, uint16_t data)
+{
+    data = cpu_to_le16(data);
+    return xen_host_pci_config_write(d, pos, &data, 2);
+}
+
+int xen_host_pci_set_long(XenHostPCIDevice *d, int pos, uint32_t data)
+{
+    data = cpu_to_le32(data);
+    return xen_host_pci_config_write(d, pos, &data, 4);
+}
+
+int xen_host_pci_set_block(XenHostPCIDevice *d, int pos, uint8_t *buf, int len)
+{
+    return xen_host_pci_config_write(d, pos, buf, len);
+}
+
+int xen_host_pci_find_ext_cap_offset(XenHostPCIDevice *d, uint32_t cap)
+{
+    uint32_t header = 0;
+    int max_cap = XEN_HOST_PCI_MAX_EXT_CAP;
+    int pos = PCI_CONFIG_SPACE_SIZE;
+
+    do {
+        if (xen_host_pci_get_long(d, pos, &header)) {
+            break;
+        }
+        /*
+         * If we have no capabilities, this is indicated by cap ID,
+         * cap version and next pointer all being 0.
+         */
+        if (header == 0) {
+            break;
+        }
+
+        if (PCI_EXT_CAP_ID(header) == cap) {
+            return pos;
+        }
+
+        pos = PCI_EXT_CAP_NEXT(header);
+        if (pos < PCI_CONFIG_SPACE_SIZE) {
+            break;
+        }
+
+        max_cap--;
+    } while (max_cap > 0);
+
+    return -1;
+}
+
+int xen_host_pci_device_get(XenHostPCIDevice *d, uint16_t domain,
+                            uint8_t bus, uint8_t dev, uint8_t func)
+{
+    unsigned int v;
+    int rc = 0;
+
+    d->config_fd = -1;
+    d->domain = domain;
+    d->bus = bus;
+    d->dev = dev;
+    d->func = func;
+
+    rc = xen_host_pci_config_open(d);
+    if (rc) {
+        goto error;
+    }
+    rc = xen_host_pci_get_resource(d);
+    if (rc) {
+        goto error;
+    }
+    rc = xen_host_pci_get_hex_value(d, "vendor", &v);
+    if (rc) {
+        goto error;
+    }
+    d->vendor_id = v;
+    rc = xen_host_pci_get_hex_value(d, "device", &v);
+    if (rc) {
+        goto error;
+    }
+    d->device_id = v;
+    rc = xen_host_pci_get_dec_value(d, "irq", &v);
+    if (rc) {
+        goto error;
+    }
+    d->irq = v;
+    d->is_virtfn = xen_host_pci_dev_is_virtfn(d);
+
+    return 0;
+error:
+    if (d->config_fd >= 0) {
+        close(d->config_fd);
+        d->config_fd = -1;
+    }
+    return rc;
+}
+
+void xen_host_pci_device_put(XenHostPCIDevice *d)
+{
+    if (d->config_fd >= 0) {
+        close(d->config_fd);
+        d->config_fd = -1;
+    }
+}
diff --git a/hw/xen/xen-host-pci-device.h b/hw/xen/xen-host-pci-device.h
new file mode 100644 (file)
index 0000000..c2486f0
--- /dev/null
@@ -0,0 +1,55 @@
+#ifndef XEN_HOST_PCI_DEVICE_H
+#define XEN_HOST_PCI_DEVICE_H
+
+#include "hw/pci/pci.h"
+
+enum {
+    XEN_HOST_PCI_REGION_TYPE_IO = 1 << 1,
+    XEN_HOST_PCI_REGION_TYPE_MEM = 1 << 2,
+    XEN_HOST_PCI_REGION_TYPE_PREFETCH = 1 << 3,
+    XEN_HOST_PCI_REGION_TYPE_MEM_64 = 1 << 4,
+};
+
+typedef struct XenHostPCIIORegion {
+    pcibus_t base_addr;
+    pcibus_t size;
+    uint8_t type;
+    uint8_t bus_flags; /* Bus-specific bits */
+} XenHostPCIIORegion;
+
+typedef struct XenHostPCIDevice {
+    uint16_t domain;
+    uint8_t bus;
+    uint8_t dev;
+    uint8_t func;
+
+    uint16_t vendor_id;
+    uint16_t device_id;
+    int irq;
+
+    XenHostPCIIORegion io_regions[PCI_NUM_REGIONS - 1];
+    XenHostPCIIORegion rom;
+
+    bool is_virtfn;
+
+    int config_fd;
+} XenHostPCIDevice;
+
+int xen_host_pci_device_get(XenHostPCIDevice *d, uint16_t domain,
+                            uint8_t bus, uint8_t dev, uint8_t func);
+void xen_host_pci_device_put(XenHostPCIDevice *pci_dev);
+
+int xen_host_pci_get_byte(XenHostPCIDevice *d, int pos, uint8_t *p);
+int xen_host_pci_get_word(XenHostPCIDevice *d, int pos, uint16_t *p);
+int xen_host_pci_get_long(XenHostPCIDevice *d, int pos, uint32_t *p);
+int xen_host_pci_get_block(XenHostPCIDevice *d, int pos, uint8_t *buf,
+                           int len);
+int xen_host_pci_set_byte(XenHostPCIDevice *d, int pos, uint8_t data);
+int xen_host_pci_set_word(XenHostPCIDevice *d, int pos, uint16_t data);
+int xen_host_pci_set_long(XenHostPCIDevice *d, int pos, uint32_t data);
+int xen_host_pci_set_block(XenHostPCIDevice *d, int pos, uint8_t *buf,
+                           int len);
+
+int xen_host_pci_find_ext_cap_offset(XenHostPCIDevice *s, uint32_t cap);
+
+#endif /* !XEN_HOST_PCI_DEVICE_H_ */
diff --git a/hw/xen/xen_apic.c b/hw/xen/xen_apic.c
new file mode 100644 (file)
index 0000000..a2eb8a1
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Xen basic APIC support
+ *
+ * Copyright (c) 2012 Citrix
+ *
+ * Authors:
+ *  Wei Liu <wei.liu2@citrix.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 "hw/i386/apic_internal.h"
+#include "hw/pci/msi.h"
+#include "hw/xen/xen.h"
+
+static uint64_t xen_apic_mem_read(void *opaque, hwaddr addr,
+                                  unsigned size)
+{
+    return ~(uint64_t)0;
+}
+
+static void xen_apic_mem_write(void *opaque, hwaddr addr,
+                               uint64_t data, unsigned size)
+{
+    if (size != sizeof(uint32_t)) {
+        fprintf(stderr, "Xen: APIC write data size = %d, invalid\n", size);
+        return;
+    }
+
+    xen_hvm_inject_msi(addr, data);
+}
+
+static const MemoryRegionOps xen_apic_io_ops = {
+    .read = xen_apic_mem_read,
+    .write = xen_apic_mem_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void xen_apic_init(APICCommonState *s)
+{
+    memory_region_init_io(&s->io_memory, &xen_apic_io_ops, s, "xen-apic-msi",
+                          MSI_SPACE_SIZE);
+
+#if defined(CONFIG_XEN_CTRL_INTERFACE_VERSION) \
+    && CONFIG_XEN_CTRL_INTERFACE_VERSION >= 420
+    msi_supported = true;
+#endif
+}
+
+static void xen_apic_set_base(APICCommonState *s, uint64_t val)
+{
+}
+
+static void xen_apic_set_tpr(APICCommonState *s, uint8_t val)
+{
+}
+
+static uint8_t xen_apic_get_tpr(APICCommonState *s)
+{
+    return 0;
+}
+
+static void xen_apic_vapic_base_update(APICCommonState *s)
+{
+}
+
+static void xen_apic_external_nmi(APICCommonState *s)
+{
+}
+
+static void xen_apic_class_init(ObjectClass *klass, void *data)
+{
+    APICCommonClass *k = APIC_COMMON_CLASS(klass);
+
+    k->init = xen_apic_init;
+    k->set_base = xen_apic_set_base;
+    k->set_tpr = xen_apic_set_tpr;
+    k->get_tpr = xen_apic_get_tpr;
+    k->vapic_base_update = xen_apic_vapic_base_update;
+    k->external_nmi = xen_apic_external_nmi;
+}
+
+static const TypeInfo xen_apic_info = {
+    .name = "xen-apic",
+    .parent = TYPE_APIC_COMMON,
+    .instance_size = sizeof(APICCommonState),
+    .class_init = xen_apic_class_init,
+};
+
+static void xen_apic_register_types(void)
+{
+    type_register_static(&xen_apic_info);
+}
+
+type_init(xen_apic_register_types)
diff --git a/hw/xen/xen_backend.c b/hw/xen/xen_backend.c
new file mode 100644 (file)
index 0000000..2a8c9f5
--- /dev/null
@@ -0,0 +1,800 @@
+/*
+ *  xen backend driver infrastructure
+ *  (c) 2008 Gerd Hoffmann <kraxel@redhat.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; under version 2 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
+ *  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/>.
+ *
+ *  Contributions after 2012-01-13 are licensed under the terms of the
+ *  GNU GPL, version 2 or (at your option) any later version.
+ */
+
+/*
+ * TODO: add some xenbus / xenstore concepts overview here.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/signal.h>
+
+#include "hw/hw.h"
+#include "char/char.h"
+#include "qemu/log.h"
+#include "hw/xen/xen_backend.h"
+
+#include <xen/grant_table.h>
+
+/* ------------------------------------------------------------- */
+
+/* public */
+XenXC xen_xc = XC_HANDLER_INITIAL_VALUE;
+XenGnttab xen_xcg = XC_HANDLER_INITIAL_VALUE;
+struct xs_handle *xenstore = NULL;
+const char *xen_protocol;
+
+/* private */
+static QTAILQ_HEAD(XenDeviceHead, XenDevice) xendevs = QTAILQ_HEAD_INITIALIZER(xendevs);
+static int debug = 0;
+
+/* ------------------------------------------------------------- */
+
+int xenstore_write_str(const char *base, const char *node, const char *val)
+{
+    char abspath[XEN_BUFSIZE];
+
+    snprintf(abspath, sizeof(abspath), "%s/%s", base, node);
+    if (!xs_write(xenstore, 0, abspath, val, strlen(val))) {
+        return -1;
+    }
+    return 0;
+}
+
+char *xenstore_read_str(const char *base, const char *node)
+{
+    char abspath[XEN_BUFSIZE];
+    unsigned int len;
+    char *str, *ret = NULL;
+
+    snprintf(abspath, sizeof(abspath), "%s/%s", base, node);
+    str = xs_read(xenstore, 0, abspath, &len);
+    if (str != NULL) {
+        /* move to qemu-allocated memory to make sure
+         * callers can savely g_free() stuff. */
+        ret = g_strdup(str);
+        free(str);
+    }
+    return ret;
+}
+
+int xenstore_write_int(const char *base, const char *node, int ival)
+{
+    char val[12];
+
+    snprintf(val, sizeof(val), "%d", ival);
+    return xenstore_write_str(base, node, val);
+}
+
+int xenstore_write_int64(const char *base, const char *node, int64_t ival)
+{
+    char val[21];
+
+    snprintf(val, sizeof(val), "%"PRId64, ival);
+    return xenstore_write_str(base, node, val);
+}
+
+int xenstore_read_int(const char *base, const char *node, int *ival)
+{
+    char *val;
+    int rc = -1;
+
+    val = xenstore_read_str(base, node);
+    if (val && 1 == sscanf(val, "%d", ival)) {
+        rc = 0;
+    }
+    g_free(val);
+    return rc;
+}
+
+int xenstore_write_be_str(struct XenDevice *xendev, const char *node, const char *val)
+{
+    return xenstore_write_str(xendev->be, node, val);
+}
+
+int xenstore_write_be_int(struct XenDevice *xendev, const char *node, int ival)
+{
+    return xenstore_write_int(xendev->be, node, ival);
+}
+
+int xenstore_write_be_int64(struct XenDevice *xendev, const char *node, int64_t ival)
+{
+    return xenstore_write_int64(xendev->be, node, ival);
+}
+
+char *xenstore_read_be_str(struct XenDevice *xendev, const char *node)
+{
+    return xenstore_read_str(xendev->be, node);
+}
+
+int xenstore_read_be_int(struct XenDevice *xendev, const char *node, int *ival)
+{
+    return xenstore_read_int(xendev->be, node, ival);
+}
+
+char *xenstore_read_fe_str(struct XenDevice *xendev, const char *node)
+{
+    return xenstore_read_str(xendev->fe, node);
+}
+
+int xenstore_read_fe_int(struct XenDevice *xendev, const char *node, int *ival)
+{
+    return xenstore_read_int(xendev->fe, node, ival);
+}
+
+/* ------------------------------------------------------------- */
+
+const char *xenbus_strstate(enum xenbus_state state)
+{
+    static const char *const name[] = {
+        [ XenbusStateUnknown      ] = "Unknown",
+        [ XenbusStateInitialising ] = "Initialising",
+        [ XenbusStateInitWait     ] = "InitWait",
+        [ XenbusStateInitialised  ] = "Initialised",
+        [ XenbusStateConnected    ] = "Connected",
+        [ XenbusStateClosing      ] = "Closing",
+        [ XenbusStateClosed       ] = "Closed",
+    };
+    return (state < ARRAY_SIZE(name)) ? name[state] : "INVALID";
+}
+
+int xen_be_set_state(struct XenDevice *xendev, enum xenbus_state state)
+{
+    int rc;
+
+    rc = xenstore_write_be_int(xendev, "state", state);
+    if (rc < 0) {
+        return rc;
+    }
+    xen_be_printf(xendev, 1, "backend state: %s -> %s\n",
+                  xenbus_strstate(xendev->be_state), xenbus_strstate(state));
+    xendev->be_state = state;
+    return 0;
+}
+
+/* ------------------------------------------------------------- */
+
+struct XenDevice *xen_be_find_xendev(const char *type, int dom, int dev)
+{
+    struct XenDevice *xendev;
+
+    QTAILQ_FOREACH(xendev, &xendevs, next) {
+        if (xendev->dom != dom) {
+            continue;
+        }
+        if (xendev->dev != dev) {
+            continue;
+        }
+        if (strcmp(xendev->type, type) != 0) {
+            continue;
+        }
+        return xendev;
+    }
+    return NULL;
+}
+
+/*
+ * get xen backend device, allocate a new one if it doesn't exist.
+ */
+static struct XenDevice *xen_be_get_xendev(const char *type, int dom, int dev,
+                                           struct XenDevOps *ops)
+{
+    struct XenDevice *xendev;
+    char *dom0;
+
+    xendev = xen_be_find_xendev(type, dom, dev);
+    if (xendev) {
+        return xendev;
+    }
+
+    /* init new xendev */
+    xendev = g_malloc0(ops->size);
+    xendev->type  = type;
+    xendev->dom   = dom;
+    xendev->dev   = dev;
+    xendev->ops   = ops;
+
+    dom0 = xs_get_domain_path(xenstore, 0);
+    snprintf(xendev->be, sizeof(xendev->be), "%s/backend/%s/%d/%d",
+             dom0, xendev->type, xendev->dom, xendev->dev);
+    snprintf(xendev->name, sizeof(xendev->name), "%s-%d",
+             xendev->type, xendev->dev);
+    free(dom0);
+
+    xendev->debug      = debug;
+    xendev->local_port = -1;
+
+    xendev->evtchndev = xen_xc_evtchn_open(NULL, 0);
+    if (xendev->evtchndev == XC_HANDLER_INITIAL_VALUE) {
+        xen_be_printf(NULL, 0, "can't open evtchn device\n");
+        g_free(xendev);
+        return NULL;
+    }
+    fcntl(xc_evtchn_fd(xendev->evtchndev), F_SETFD, FD_CLOEXEC);
+
+    if (ops->flags & DEVOPS_FLAG_NEED_GNTDEV) {
+        xendev->gnttabdev = xen_xc_gnttab_open(NULL, 0);
+        if (xendev->gnttabdev == XC_HANDLER_INITIAL_VALUE) {
+            xen_be_printf(NULL, 0, "can't open gnttab device\n");
+            xc_evtchn_close(xendev->evtchndev);
+            g_free(xendev);
+            return NULL;
+        }
+    } else {
+        xendev->gnttabdev = XC_HANDLER_INITIAL_VALUE;
+    }
+
+    QTAILQ_INSERT_TAIL(&xendevs, xendev, next);
+
+    if (xendev->ops->alloc) {
+        xendev->ops->alloc(xendev);
+    }
+
+    return xendev;
+}
+
+/*
+ * release xen backend device.
+ */
+static struct XenDevice *xen_be_del_xendev(int dom, int dev)
+{
+    struct XenDevice *xendev, *xnext;
+
+    /*
+     * This is pretty much like QTAILQ_FOREACH(xendev, &xendevs, next) but
+     * we save the next pointer in xnext because we might free xendev.
+     */
+    xnext = xendevs.tqh_first;
+    while (xnext) {
+        xendev = xnext;
+        xnext = xendev->next.tqe_next;
+
+        if (xendev->dom != dom) {
+            continue;
+        }
+        if (xendev->dev != dev && dev != -1) {
+            continue;
+        }
+
+        if (xendev->ops->free) {
+            xendev->ops->free(xendev);
+        }
+
+        if (xendev->fe) {
+            char token[XEN_BUFSIZE];
+            snprintf(token, sizeof(token), "fe:%p", xendev);
+            xs_unwatch(xenstore, xendev->fe, token);
+            g_free(xendev->fe);
+        }
+
+        if (xendev->evtchndev != XC_HANDLER_INITIAL_VALUE) {
+            xc_evtchn_close(xendev->evtchndev);
+        }
+        if (xendev->gnttabdev != XC_HANDLER_INITIAL_VALUE) {
+            xc_gnttab_close(xendev->gnttabdev);
+        }
+
+        QTAILQ_REMOVE(&xendevs, xendev, next);
+        g_free(xendev);
+    }
+    return NULL;
+}
+
+/*
+ * Sync internal data structures on xenstore updates.
+ * Node specifies the changed field.  node = NULL means
+ * update all fields (used for initialization).
+ */
+static void xen_be_backend_changed(struct XenDevice *xendev, const char *node)
+{
+    if (node == NULL  ||  strcmp(node, "online") == 0) {
+        if (xenstore_read_be_int(xendev, "online", &xendev->online) == -1) {
+            xendev->online = 0;
+        }
+    }
+
+    if (node) {
+        xen_be_printf(xendev, 2, "backend update: %s\n", node);
+        if (xendev->ops->backend_changed) {
+            xendev->ops->backend_changed(xendev, node);
+        }
+    }
+}
+
+static void xen_be_frontend_changed(struct XenDevice *xendev, const char *node)
+{
+    int fe_state;
+
+    if (node == NULL  ||  strcmp(node, "state") == 0) {
+        if (xenstore_read_fe_int(xendev, "state", &fe_state) == -1) {
+            fe_state = XenbusStateUnknown;
+        }
+        if (xendev->fe_state != fe_state) {
+            xen_be_printf(xendev, 1, "frontend state: %s -> %s\n",
+                          xenbus_strstate(xendev->fe_state),
+                          xenbus_strstate(fe_state));
+        }
+        xendev->fe_state = fe_state;
+    }
+    if (node == NULL  ||  strcmp(node, "protocol") == 0) {
+        g_free(xendev->protocol);
+        xendev->protocol = xenstore_read_fe_str(xendev, "protocol");
+        if (xendev->protocol) {
+            xen_be_printf(xendev, 1, "frontend protocol: %s\n", xendev->protocol);
+        }
+    }
+
+    if (node) {
+        xen_be_printf(xendev, 2, "frontend update: %s\n", node);
+        if (xendev->ops->frontend_changed) {
+            xendev->ops->frontend_changed(xendev, node);
+        }
+    }
+}
+
+/* ------------------------------------------------------------- */
+/* Check for possible state transitions and perform them.        */
+
+/*
+ * Initial xendev setup.  Read frontend path, register watch for it.
+ * Should succeed once xend finished setting up the backend device.
+ *
+ * Also sets initial state (-> Initializing) when done.  Which
+ * only affects the xendev->be_state variable as xenbus should
+ * already be put into that state by xend.
+ */
+static int xen_be_try_setup(struct XenDevice *xendev)
+{
+    char token[XEN_BUFSIZE];
+    int be_state;
+
+    if (xenstore_read_be_int(xendev, "state", &be_state) == -1) {
+        xen_be_printf(xendev, 0, "reading backend state failed\n");
+        return -1;
+    }
+
+    if (be_state != XenbusStateInitialising) {
+        xen_be_printf(xendev, 0, "initial backend state is wrong (%s)\n",
+                      xenbus_strstate(be_state));
+        return -1;
+    }
+
+    xendev->fe = xenstore_read_be_str(xendev, "frontend");
+    if (xendev->fe == NULL) {
+        xen_be_printf(xendev, 0, "reading frontend path failed\n");
+        return -1;
+    }
+
+    /* setup frontend watch */
+    snprintf(token, sizeof(token), "fe:%p", xendev);
+    if (!xs_watch(xenstore, xendev->fe, token)) {
+        xen_be_printf(xendev, 0, "watching frontend path (%s) failed\n",
+                      xendev->fe);
+        return -1;
+    }
+    xen_be_set_state(xendev, XenbusStateInitialising);
+
+    xen_be_backend_changed(xendev, NULL);
+    xen_be_frontend_changed(xendev, NULL);
+    return 0;
+}
+
+/*
+ * Try initialize xendev.  Prepare everything the backend can do
+ * without synchronizing with the frontend.  Fakes hotplug-status.  No
+ * hotplug involved here because this is about userspace drivers, thus
+ * there are kernel backend devices which could invoke hotplug.
+ *
+ * Goes to InitWait on success.
+ */
+static int xen_be_try_init(struct XenDevice *xendev)
+{
+    int rc = 0;
+
+    if (!xendev->online) {
+        xen_be_printf(xendev, 1, "not online\n");
+        return -1;
+    }
+
+    if (xendev->ops->init) {
+        rc = xendev->ops->init(xendev);
+    }
+    if (rc != 0) {
+        xen_be_printf(xendev, 1, "init() failed\n");
+        return rc;
+    }
+
+    xenstore_write_be_str(xendev, "hotplug-status", "connected");
+    xen_be_set_state(xendev, XenbusStateInitWait);
+    return 0;
+}
+
+/*
+ * Try to initialise xendev.  Depends on the frontend being ready
+ * for it (shared ring and evtchn info in xenstore, state being
+ * Initialised or Connected).
+ *
+ * Goes to Connected on success.
+ */
+static int xen_be_try_initialise(struct XenDevice *xendev)
+{
+    int rc = 0;
+
+    if (xendev->fe_state != XenbusStateInitialised  &&
+        xendev->fe_state != XenbusStateConnected) {
+        if (xendev->ops->flags & DEVOPS_FLAG_IGNORE_STATE) {
+            xen_be_printf(xendev, 2, "frontend not ready, ignoring\n");
+        } else {
+            xen_be_printf(xendev, 2, "frontend not ready (yet)\n");
+            return -1;
+        }
+    }
+
+    if (xendev->ops->initialise) {
+        rc = xendev->ops->initialise(xendev);
+    }
+    if (rc != 0) {
+        xen_be_printf(xendev, 0, "initialise() failed\n");
+        return rc;
+    }
+
+    xen_be_set_state(xendev, XenbusStateConnected);
+    return 0;
+}
+
+/*
+ * Try to let xendev know that it is connected.  Depends on the
+ * frontend being Connected.  Note that this may be called more
+ * than once since the backend state is not modified.
+ */
+static void xen_be_try_connected(struct XenDevice *xendev)
+{
+    if (!xendev->ops->connected) {
+        return;
+    }
+
+    if (xendev->fe_state != XenbusStateConnected) {
+        if (xendev->ops->flags & DEVOPS_FLAG_IGNORE_STATE) {
+            xen_be_printf(xendev, 2, "frontend not ready, ignoring\n");
+        } else {
+            xen_be_printf(xendev, 2, "frontend not ready (yet)\n");
+            return;
+        }
+    }
+
+    xendev->ops->connected(xendev);
+}
+
+/*
+ * Teardown connection.
+ *
+ * Goes to Closed when done.
+ */
+static void xen_be_disconnect(struct XenDevice *xendev, enum xenbus_state state)
+{
+    if (xendev->be_state != XenbusStateClosing &&
+        xendev->be_state != XenbusStateClosed  &&
+        xendev->ops->disconnect) {
+        xendev->ops->disconnect(xendev);
+    }
+    if (xendev->be_state != state) {
+        xen_be_set_state(xendev, state);
+    }
+}
+
+/*
+ * Try to reset xendev, for reconnection by another frontend instance.
+ */
+static int xen_be_try_reset(struct XenDevice *xendev)
+{
+    if (xendev->fe_state != XenbusStateInitialising) {
+        return -1;
+    }
+
+    xen_be_printf(xendev, 1, "device reset (for re-connect)\n");
+    xen_be_set_state(xendev, XenbusStateInitialising);
+    return 0;
+}
+
+/*
+ * state change dispatcher function
+ */
+void xen_be_check_state(struct XenDevice *xendev)
+{
+    int rc = 0;
+
+    /* frontend may request shutdown from almost anywhere */
+    if (xendev->fe_state == XenbusStateClosing ||
+        xendev->fe_state == XenbusStateClosed) {
+        xen_be_disconnect(xendev, xendev->fe_state);
+        return;
+    }
+
+    /* check for possible backend state transitions */
+    for (;;) {
+        switch (xendev->be_state) {
+        case XenbusStateUnknown:
+            rc = xen_be_try_setup(xendev);
+            break;
+        case XenbusStateInitialising:
+            rc = xen_be_try_init(xendev);
+            break;
+        case XenbusStateInitWait:
+            rc = xen_be_try_initialise(xendev);
+            break;
+        case XenbusStateConnected:
+            /* xendev->be_state doesn't change */
+            xen_be_try_connected(xendev);
+            rc = -1;
+            break;
+        case XenbusStateClosed:
+            rc = xen_be_try_reset(xendev);
+            break;
+        default:
+            rc = -1;
+        }
+        if (rc != 0) {
+            break;
+        }
+    }
+}
+
+/* ------------------------------------------------------------- */
+
+static int xenstore_scan(const char *type, int dom, struct XenDevOps *ops)
+{
+    struct XenDevice *xendev;
+    char path[XEN_BUFSIZE], token[XEN_BUFSIZE];
+    char **dev = NULL, *dom0;
+    unsigned int cdev, j;
+
+    /* setup watch */
+    dom0 = xs_get_domain_path(xenstore, 0);
+    snprintf(token, sizeof(token), "be:%p:%d:%p", type, dom, ops);
+    snprintf(path, sizeof(path), "%s/backend/%s/%d", dom0, type, dom);
+    free(dom0);
+    if (!xs_watch(xenstore, path, token)) {
+        xen_be_printf(NULL, 0, "xen be: watching backend path (%s) failed\n", path);
+        return -1;
+    }
+
+    /* look for backends */
+    dev = xs_directory(xenstore, 0, path, &cdev);
+    if (!dev) {
+        return 0;
+    }
+    for (j = 0; j < cdev; j++) {
+        xendev = xen_be_get_xendev(type, dom, atoi(dev[j]), ops);
+        if (xendev == NULL) {
+            continue;
+        }
+        xen_be_check_state(xendev);
+    }
+    free(dev);
+    return 0;
+}
+
+static void xenstore_update_be(char *watch, char *type, int dom,
+                               struct XenDevOps *ops)
+{
+    struct XenDevice *xendev;
+    char path[XEN_BUFSIZE], *dom0, *bepath;
+    unsigned int len, dev;
+
+    dom0 = xs_get_domain_path(xenstore, 0);
+    len = snprintf(path, sizeof(path), "%s/backend/%s/%d", dom0, type, dom);
+    free(dom0);
+    if (strncmp(path, watch, len) != 0) {
+        return;
+    }
+    if (sscanf(watch+len, "/%u/%255s", &dev, path) != 2) {
+        strcpy(path, "");
+        if (sscanf(watch+len, "/%u", &dev) != 1) {
+            dev = -1;
+        }
+    }
+    if (dev == -1) {
+        return;
+    }
+
+    xendev = xen_be_get_xendev(type, dom, dev, ops);
+    if (xendev != NULL) {
+        bepath = xs_read(xenstore, 0, xendev->be, &len);
+        if (bepath == NULL) {
+            xen_be_del_xendev(dom, dev);
+        } else {
+            free(bepath);
+            xen_be_backend_changed(xendev, path);
+            xen_be_check_state(xendev);
+        }
+    }
+}
+
+static void xenstore_update_fe(char *watch, struct XenDevice *xendev)
+{
+    char *node;
+    unsigned int len;
+
+    len = strlen(xendev->fe);
+    if (strncmp(xendev->fe, watch, len) != 0) {
+        return;
+    }
+    if (watch[len] != '/') {
+        return;
+    }
+    node = watch + len + 1;
+
+    xen_be_frontend_changed(xendev, node);
+    xen_be_check_state(xendev);
+}
+
+static void xenstore_update(void *unused)
+{
+    char **vec = NULL;
+    intptr_t type, ops, ptr;
+    unsigned int dom, count;
+
+    vec = xs_read_watch(xenstore, &count);
+    if (vec == NULL) {
+        goto cleanup;
+    }
+
+    if (sscanf(vec[XS_WATCH_TOKEN], "be:%" PRIxPTR ":%d:%" PRIxPTR,
+               &type, &dom, &ops) == 3) {
+        xenstore_update_be(vec[XS_WATCH_PATH], (void*)type, dom, (void*)ops);
+    }
+    if (sscanf(vec[XS_WATCH_TOKEN], "fe:%" PRIxPTR, &ptr) == 1) {
+        xenstore_update_fe(vec[XS_WATCH_PATH], (void*)ptr);
+    }
+
+cleanup:
+    free(vec);
+}
+
+static void xen_be_evtchn_event(void *opaque)
+{
+    struct XenDevice *xendev = opaque;
+    evtchn_port_t port;
+
+    port = xc_evtchn_pending(xendev->evtchndev);
+    if (port != xendev->local_port) {
+        xen_be_printf(xendev, 0, "xc_evtchn_pending returned %d (expected %d)\n",
+                      port, xendev->local_port);
+        return;
+    }
+    xc_evtchn_unmask(xendev->evtchndev, port);
+
+    if (xendev->ops->event) {
+        xendev->ops->event(xendev);
+    }
+}
+
+/* -------------------------------------------------------------------- */
+
+int xen_be_init(void)
+{
+    xenstore = xs_daemon_open();
+    if (!xenstore) {
+        xen_be_printf(NULL, 0, "can't connect to xenstored\n");
+        return -1;
+    }
+
+    if (qemu_set_fd_handler(xs_fileno(xenstore), xenstore_update, NULL, NULL) < 0) {
+        goto err;
+    }
+
+    if (xen_xc == XC_HANDLER_INITIAL_VALUE) {
+        /* Check if xen_init() have been called */
+        goto err;
+    }
+    return 0;
+
+err:
+    qemu_set_fd_handler(xs_fileno(xenstore), NULL, NULL, NULL);
+    xs_daemon_close(xenstore);
+    xenstore = NULL;
+
+    return -1;
+}
+
+int xen_be_register(const char *type, struct XenDevOps *ops)
+{
+    return xenstore_scan(type, xen_domid, ops);
+}
+
+int xen_be_bind_evtchn(struct XenDevice *xendev)
+{
+    if (xendev->local_port != -1) {
+        return 0;
+    }
+    xendev->local_port = xc_evtchn_bind_interdomain
+        (xendev->evtchndev, xendev->dom, xendev->remote_port);
+    if (xendev->local_port == -1) {
+        xen_be_printf(xendev, 0, "xc_evtchn_bind_interdomain failed\n");
+        return -1;
+    }
+    xen_be_printf(xendev, 2, "bind evtchn port %d\n", xendev->local_port);
+    qemu_set_fd_handler(xc_evtchn_fd(xendev->evtchndev),
+                        xen_be_evtchn_event, NULL, xendev);
+    return 0;
+}
+
+void xen_be_unbind_evtchn(struct XenDevice *xendev)
+{
+    if (xendev->local_port == -1) {
+        return;
+    }
+    qemu_set_fd_handler(xc_evtchn_fd(xendev->evtchndev), NULL, NULL, NULL);
+    xc_evtchn_unbind(xendev->evtchndev, xendev->local_port);
+    xen_be_printf(xendev, 2, "unbind evtchn port %d\n", xendev->local_port);
+    xendev->local_port = -1;
+}
+
+int xen_be_send_notify(struct XenDevice *xendev)
+{
+    return xc_evtchn_notify(xendev->evtchndev, xendev->local_port);
+}
+
+/*
+ * msg_level:
+ *  0 == errors (stderr + logfile).
+ *  1 == informative debug messages (logfile only).
+ *  2 == noisy debug messages (logfile only).
+ *  3 == will flood your log (logfile only).
+ */
+void xen_be_printf(struct XenDevice *xendev, int msg_level, const char *fmt, ...)
+{
+    va_list args;
+
+    if (xendev) {
+        if (msg_level > xendev->debug) {
+            return;
+        }
+        qemu_log("xen be: %s: ", xendev->name);
+        if (msg_level == 0) {
+            fprintf(stderr, "xen be: %s: ", xendev->name);
+        }
+    } else {
+        if (msg_level > debug) {
+            return;
+        }
+        qemu_log("xen be core: ");
+        if (msg_level == 0) {
+            fprintf(stderr, "xen be core: ");
+        }
+    }
+    va_start(args, fmt);
+    qemu_log_vprintf(fmt, args);
+    va_end(args);
+    if (msg_level == 0) {
+        va_start(args, fmt);
+        vfprintf(stderr, fmt, args);
+        va_end(args);
+    }
+    qemu_log_flush();
+}
diff --git a/hw/xen/xen_devconfig.c b/hw/xen/xen_devconfig.c
new file mode 100644 (file)
index 0000000..fa998ef
--- /dev/null
@@ -0,0 +1,174 @@
+#include "hw/xen/xen_backend.h"
+#include "sysemu/blockdev.h"
+
+/* ------------------------------------------------------------- */
+
+struct xs_dirs {
+    char *xs_dir;
+    QTAILQ_ENTRY(xs_dirs) list;
+};
+static QTAILQ_HEAD(xs_dirs_head, xs_dirs) xs_cleanup = QTAILQ_HEAD_INITIALIZER(xs_cleanup);
+
+static void xen_config_cleanup_dir(char *dir)
+{
+    struct xs_dirs *d;
+
+    d = g_malloc(sizeof(*d));
+    d->xs_dir = dir;
+    QTAILQ_INSERT_TAIL(&xs_cleanup, d, list);
+}
+
+void xen_config_cleanup(void)
+{
+    struct xs_dirs *d;
+
+    QTAILQ_FOREACH(d, &xs_cleanup, list) {
+       xs_rm(xenstore, 0, d->xs_dir);
+    }
+}
+
+/* ------------------------------------------------------------- */
+
+static int xen_config_dev_mkdir(char *dev, int p)
+{
+    struct xs_permissions perms[2] = {{
+            .id    = 0, /* set owner: dom0 */
+        },{
+            .id    = xen_domid,
+            .perms = p,
+        }};
+
+    if (!xs_mkdir(xenstore, 0, dev)) {
+       xen_be_printf(NULL, 0, "xs_mkdir %s: failed\n", dev);
+       return -1;
+    }
+    xen_config_cleanup_dir(g_strdup(dev));
+
+    if (!xs_set_permissions(xenstore, 0, dev, perms, 2)) {
+       xen_be_printf(NULL, 0, "xs_set_permissions %s: failed\n", dev);
+       return -1;
+    }
+    return 0;
+}
+
+static int xen_config_dev_dirs(const char *ftype, const char *btype, int vdev,
+                              char *fe, char *be, int len)
+{
+    char *dom;
+
+    dom = xs_get_domain_path(xenstore, xen_domid);
+    snprintf(fe, len, "%s/device/%s/%d", dom, ftype, vdev);
+    free(dom);
+
+    dom = xs_get_domain_path(xenstore, 0);
+    snprintf(be, len, "%s/backend/%s/%d/%d", dom, btype, xen_domid, vdev);
+    free(dom);
+
+    xen_config_dev_mkdir(fe, XS_PERM_READ | XS_PERM_WRITE);
+    xen_config_dev_mkdir(be, XS_PERM_READ);
+    return 0;
+}
+
+static int xen_config_dev_all(char *fe, char *be)
+{
+    /* frontend */
+    if (xen_protocol)
+        xenstore_write_str(fe, "protocol", xen_protocol);
+
+    xenstore_write_int(fe, "state",           XenbusStateInitialising);
+    xenstore_write_int(fe, "backend-id",      0);
+    xenstore_write_str(fe, "backend",         be);
+
+    /* backend */
+    xenstore_write_str(be, "domain",          qemu_name ? qemu_name : "no-name");
+    xenstore_write_int(be, "online",          1);
+    xenstore_write_int(be, "state",           XenbusStateInitialising);
+    xenstore_write_int(be, "frontend-id",     xen_domid);
+    xenstore_write_str(be, "frontend",        fe);
+
+    return 0;
+}
+
+/* ------------------------------------------------------------- */
+
+int xen_config_dev_blk(DriveInfo *disk)
+{
+    char fe[256], be[256], device_name[32];
+    int vdev = 202 * 256 + 16 * disk->unit;
+    int cdrom = disk->media_cd;
+    const char *devtype = cdrom ? "cdrom" : "disk";
+    const char *mode    = cdrom ? "r"     : "w";
+    const char *filename = qemu_opt_get(disk->opts, "file");
+
+    snprintf(device_name, sizeof(device_name), "xvd%c", 'a' + disk->unit);
+    xen_be_printf(NULL, 1, "config disk %d [%s]: %s\n",
+                  disk->unit, device_name, filename);
+    xen_config_dev_dirs("vbd", "qdisk", vdev, fe, be, sizeof(fe));
+
+    /* frontend */
+    xenstore_write_int(fe, "virtual-device",  vdev);
+    xenstore_write_str(fe, "device-type",     devtype);
+
+    /* backend */
+    xenstore_write_str(be, "dev",             device_name);
+    xenstore_write_str(be, "type",            "file");
+    xenstore_write_str(be, "params",          filename);
+    xenstore_write_str(be, "mode",            mode);
+
+    /* common stuff */
+    return xen_config_dev_all(fe, be);
+}
+
+int xen_config_dev_nic(NICInfo *nic)
+{
+    char fe[256], be[256];
+    char mac[20];
+    int vlan_id = -1;
+
+    net_hub_id_for_client(nic->netdev, &vlan_id);
+    snprintf(mac, sizeof(mac), "%02x:%02x:%02x:%02x:%02x:%02x",
+             nic->macaddr.a[0], nic->macaddr.a[1], nic->macaddr.a[2],
+             nic->macaddr.a[3], nic->macaddr.a[4], nic->macaddr.a[5]);
+    xen_be_printf(NULL, 1, "config nic %d: mac=\"%s\"\n", vlan_id, mac);
+    xen_config_dev_dirs("vif", "qnic", vlan_id, fe, be, sizeof(fe));
+
+    /* frontend */
+    xenstore_write_int(fe, "handle",     vlan_id);
+    xenstore_write_str(fe, "mac",        mac);
+
+    /* backend */
+    xenstore_write_int(be, "handle",     vlan_id);
+    xenstore_write_str(be, "mac",        mac);
+
+    /* common stuff */
+    return xen_config_dev_all(fe, be);
+}
+
+int xen_config_dev_vfb(int vdev, const char *type)
+{
+    char fe[256], be[256];
+
+    xen_config_dev_dirs("vfb", "vfb", vdev, fe, be, sizeof(fe));
+
+    /* backend */
+    xenstore_write_str(be, "type",  type);
+
+    /* common stuff */
+    return xen_config_dev_all(fe, be);
+}
+
+int xen_config_dev_vkbd(int vdev)
+{
+    char fe[256], be[256];
+
+    xen_config_dev_dirs("vkbd", "vkbd", vdev, fe, be, sizeof(fe));
+    return xen_config_dev_all(fe, be);
+}
+
+int xen_config_dev_console(int vdev)
+{
+    char fe[256], be[256];
+
+    xen_config_dev_dirs("console", "console", vdev, fe, be, sizeof(fe));
+    return xen_config_dev_all(fe, be);
+}
diff --git a/hw/xen/xen_platform.c b/hw/xen/xen_platform.c
new file mode 100644 (file)
index 0000000..b6c6793
--- /dev/null
@@ -0,0 +1,434 @@
+/*
+ * XEN platform pci device, formerly known as the event channel device
+ *
+ * Copyright (c) 2003-2004 Intel Corp.
+ * Copyright (c) 2006 XenSource
+ *
+ * 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 <assert.h>
+
+#include "hw/hw.h"
+#include "hw/i386/pc.h"
+#include "hw/pci/pci.h"
+#include "hw/irq.h"
+#include "hw/xen/xen_common.h"
+#include "hw/xen/xen_backend.h"
+#include "trace.h"
+#include "exec/address-spaces.h"
+
+#include <xenguest.h>
+
+//#define DEBUG_PLATFORM
+
+#ifdef DEBUG_PLATFORM
+#define DPRINTF(fmt, ...) do { \
+    fprintf(stderr, "xen_platform: " fmt, ## __VA_ARGS__); \
+} while (0)
+#else
+#define DPRINTF(fmt, ...) do { } while (0)
+#endif
+
+#define PFFLAG_ROM_LOCK 1 /* Sets whether ROM memory area is RW or RO */
+
+typedef struct PCIXenPlatformState {
+    PCIDevice  pci_dev;
+    MemoryRegion fixed_io;
+    MemoryRegion bar;
+    MemoryRegion mmio_bar;
+    uint8_t flags; /* used only for version_id == 2 */
+    int drivers_blacklisted;
+    uint16_t driver_product_version;
+
+    /* Log from guest drivers */
+    char log_buffer[4096];
+    int log_buffer_off;
+} PCIXenPlatformState;
+
+#define XEN_PLATFORM_IOPORT 0x10
+
+/* Send bytes to syslog */
+static void log_writeb(PCIXenPlatformState *s, char val)
+{
+    if (val == '\n' || s->log_buffer_off == sizeof(s->log_buffer) - 1) {
+        /* Flush buffer */
+        s->log_buffer[s->log_buffer_off] = 0;
+        trace_xen_platform_log(s->log_buffer);
+        s->log_buffer_off = 0;
+    } else {
+        s->log_buffer[s->log_buffer_off++] = val;
+    }
+}
+
+/* Xen Platform, Fixed IOPort */
+#define UNPLUG_ALL_IDE_DISKS 1
+#define UNPLUG_ALL_NICS 2
+#define UNPLUG_AUX_IDE_DISKS 4
+
+static void unplug_nic(PCIBus *b, PCIDevice *d, void *o)
+{
+    /* We have to ignore passthrough devices */
+    if (pci_get_word(d->config + PCI_CLASS_DEVICE) ==
+            PCI_CLASS_NETWORK_ETHERNET
+            && strcmp(d->name, "xen-pci-passthrough") != 0) {
+        qdev_free(&d->qdev);
+    }
+}
+
+static void pci_unplug_nics(PCIBus *bus)
+{
+    pci_for_each_device(bus, 0, unplug_nic, NULL);
+}
+
+static void unplug_disks(PCIBus *b, PCIDevice *d, void *o)
+{
+    /* We have to ignore passthrough devices */
+    if (pci_get_word(d->config + PCI_CLASS_DEVICE) ==
+            PCI_CLASS_STORAGE_IDE
+            && strcmp(d->name, "xen-pci-passthrough") != 0) {
+        qdev_unplug(&(d->qdev), NULL);
+    }
+}
+
+static void pci_unplug_disks(PCIBus *bus)
+{
+    pci_for_each_device(bus, 0, unplug_disks, NULL);
+}
+
+static void platform_fixed_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
+{
+    PCIXenPlatformState *s = opaque;
+
+    switch (addr) {
+    case 0:
+        /* Unplug devices.  Value is a bitmask of which devices to
+           unplug, with bit 0 the IDE devices, bit 1 the network
+           devices, and bit 2 the non-primary-master IDE devices. */
+        if (val & UNPLUG_ALL_IDE_DISKS) {
+            DPRINTF("unplug disks\n");
+            bdrv_drain_all();
+            bdrv_flush_all();
+            pci_unplug_disks(s->pci_dev.bus);
+        }
+        if (val & UNPLUG_ALL_NICS) {
+            DPRINTF("unplug nics\n");
+            pci_unplug_nics(s->pci_dev.bus);
+        }
+        if (val & UNPLUG_AUX_IDE_DISKS) {
+            DPRINTF("unplug auxiliary disks not supported\n");
+        }
+        break;
+    case 2:
+        switch (val) {
+        case 1:
+            DPRINTF("Citrix Windows PV drivers loaded in guest\n");
+            break;
+        case 0:
+            DPRINTF("Guest claimed to be running PV product 0?\n");
+            break;
+        default:
+            DPRINTF("Unknown PV product %d loaded in guest\n", val);
+            break;
+        }
+        s->driver_product_version = val;
+        break;
+    }
+}
+
+static void platform_fixed_ioport_writel(void *opaque, uint32_t addr,
+                                         uint32_t val)
+{
+    switch (addr) {
+    case 0:
+        /* PV driver version */
+        break;
+    }
+}
+
+static void platform_fixed_ioport_writeb(void *opaque, uint32_t addr, uint32_t val)
+{
+    PCIXenPlatformState *s = opaque;
+
+    switch (addr) {
+    case 0: /* Platform flags */ {
+        hvmmem_type_t mem_type = (val & PFFLAG_ROM_LOCK) ?
+            HVMMEM_ram_ro : HVMMEM_ram_rw;
+        if (xc_hvm_set_mem_type(xen_xc, xen_domid, mem_type, 0xc0, 0x40)) {
+            DPRINTF("unable to change ro/rw state of ROM memory area!\n");
+        } else {
+            s->flags = val & PFFLAG_ROM_LOCK;
+            DPRINTF("changed ro/rw state of ROM memory area. now is %s state.\n",
+                    (mem_type == HVMMEM_ram_ro ? "ro":"rw"));
+        }
+        break;
+    }
+    case 2:
+        log_writeb(s, val);
+        break;
+    }
+}
+
+static uint32_t platform_fixed_ioport_readw(void *opaque, uint32_t addr)
+{
+    PCIXenPlatformState *s = opaque;
+
+    switch (addr) {
+    case 0:
+        if (s->drivers_blacklisted) {
+            /* The drivers will recognise this magic number and refuse
+             * to do anything. */
+            return 0xd249;
+        } else {
+            /* Magic value so that you can identify the interface. */
+            return 0x49d2;
+        }
+    default:
+        return 0xffff;
+    }
+}
+
+static uint32_t platform_fixed_ioport_readb(void *opaque, uint32_t addr)
+{
+    PCIXenPlatformState *s = opaque;
+
+    switch (addr) {
+    case 0:
+        /* Platform flags */
+        return s->flags;
+    case 2:
+        /* Version number */
+        return 1;
+    default:
+        return 0xff;
+    }
+}
+
+static void platform_fixed_ioport_reset(void *opaque)
+{
+    PCIXenPlatformState *s = opaque;
+
+    platform_fixed_ioport_writeb(s, 0, 0);
+}
+
+static uint64_t platform_fixed_ioport_read(void *opaque,
+                                           hwaddr addr,
+                                           unsigned size)
+{
+    switch (size) {
+    case 1:
+        return platform_fixed_ioport_readb(opaque, addr);
+    case 2:
+        return platform_fixed_ioport_readw(opaque, addr);
+    default:
+        return -1;
+    }
+}
+
+static void platform_fixed_ioport_write(void *opaque, hwaddr addr,
+
+                                        uint64_t val, unsigned size)
+{
+    switch (size) {
+    case 1:
+        platform_fixed_ioport_writeb(opaque, addr, val);
+        break;
+    case 2:
+        platform_fixed_ioport_writew(opaque, addr, val);
+        break;
+    case 4:
+        platform_fixed_ioport_writel(opaque, addr, val);
+        break;
+    }
+}
+
+
+static const MemoryRegionOps platform_fixed_io_ops = {
+    .read = platform_fixed_ioport_read,
+    .write = platform_fixed_ioport_write,
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 4,
+    },
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void platform_fixed_ioport_init(PCIXenPlatformState* s)
+{
+    memory_region_init_io(&s->fixed_io, &platform_fixed_io_ops, s,
+                          "xen-fixed", 16);
+    memory_region_add_subregion(get_system_io(), XEN_PLATFORM_IOPORT,
+                                &s->fixed_io);
+}
+
+/* Xen Platform PCI Device */
+
+static uint64_t xen_platform_ioport_readb(void *opaque, hwaddr addr,
+                                          unsigned int size)
+{
+    if (addr == 0) {
+        return platform_fixed_ioport_readb(opaque, 0);
+    } else {
+        return ~0u;
+    }
+}
+
+static void xen_platform_ioport_writeb(void *opaque, hwaddr addr,
+                                       uint64_t val, unsigned int size)
+{
+    PCIXenPlatformState *s = opaque;
+
+    switch (addr) {
+    case 0: /* Platform flags */
+        platform_fixed_ioport_writeb(opaque, 0, (uint32_t)val);
+        break;
+    case 8:
+        log_writeb(s, (uint32_t)val);
+        break;
+    default:
+        break;
+    }
+}
+
+static const MemoryRegionOps xen_pci_io_ops = {
+    .read  = xen_platform_ioport_readb,
+    .write = xen_platform_ioport_writeb,
+    .impl.min_access_size = 1,
+    .impl.max_access_size = 1,
+};
+
+static void platform_ioport_bar_setup(PCIXenPlatformState *d)
+{
+    memory_region_init_io(&d->bar, &xen_pci_io_ops, d, "xen-pci", 0x100);
+}
+
+static uint64_t platform_mmio_read(void *opaque, hwaddr addr,
+                                   unsigned size)
+{
+    DPRINTF("Warning: attempted read from physical address "
+            "0x" TARGET_FMT_plx " in xen platform mmio space\n", addr);
+
+    return 0;
+}
+
+static void platform_mmio_write(void *opaque, hwaddr addr,
+                                uint64_t val, unsigned size)
+{
+    DPRINTF("Warning: attempted write of 0x%"PRIx64" to physical "
+            "address 0x" TARGET_FMT_plx " in xen platform mmio space\n",
+            val, addr);
+}
+
+static const MemoryRegionOps platform_mmio_handler = {
+    .read = &platform_mmio_read,
+    .write = &platform_mmio_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void platform_mmio_setup(PCIXenPlatformState *d)
+{
+    memory_region_init_io(&d->mmio_bar, &platform_mmio_handler, d,
+                          "xen-mmio", 0x1000000);
+}
+
+static int xen_platform_post_load(void *opaque, int version_id)
+{
+    PCIXenPlatformState *s = opaque;
+
+    platform_fixed_ioport_writeb(s, 0, s->flags);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_xen_platform = {
+    .name = "platform",
+    .version_id = 4,
+    .minimum_version_id = 4,
+    .minimum_version_id_old = 4,
+    .post_load = xen_platform_post_load,
+    .fields = (VMStateField []) {
+        VMSTATE_PCI_DEVICE(pci_dev, PCIXenPlatformState),
+        VMSTATE_UINT8(flags, PCIXenPlatformState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int xen_platform_initfn(PCIDevice *dev)
+{
+    PCIXenPlatformState *d = DO_UPCAST(PCIXenPlatformState, pci_dev, dev);
+    uint8_t *pci_conf;
+
+    pci_conf = d->pci_dev.config;
+
+    pci_set_word(pci_conf + PCI_COMMAND, PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
+
+    pci_config_set_prog_interface(pci_conf, 0);
+
+    pci_conf[PCI_INTERRUPT_PIN] = 1;
+
+    platform_ioport_bar_setup(d);
+    pci_register_bar(&d->pci_dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &d->bar);
+
+    /* reserve 16MB mmio address for share memory*/
+    platform_mmio_setup(d);
+    pci_register_bar(&d->pci_dev, 1, PCI_BASE_ADDRESS_MEM_PREFETCH,
+                     &d->mmio_bar);
+
+    platform_fixed_ioport_init(d);
+
+    return 0;
+}
+
+static void platform_reset(DeviceState *dev)
+{
+    PCIXenPlatformState *s = DO_UPCAST(PCIXenPlatformState, pci_dev.qdev, dev);
+
+    platform_fixed_ioport_reset(s);
+}
+
+static void xen_platform_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = xen_platform_initfn;
+    k->vendor_id = PCI_VENDOR_ID_XEN;
+    k->device_id = PCI_DEVICE_ID_XEN_PLATFORM;
+    k->class_id = PCI_CLASS_OTHERS << 8 | 0x80;
+    k->subsystem_vendor_id = PCI_VENDOR_ID_XEN;
+    k->subsystem_id = PCI_DEVICE_ID_XEN_PLATFORM;
+    k->revision = 1;
+    dc->desc = "XEN platform pci device";
+    dc->reset = platform_reset;
+    dc->vmsd = &vmstate_xen_platform;
+}
+
+static const 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_types(void)
+{
+    type_register_static(&xen_platform_info);
+}
+
+type_init(xen_platform_register_types)
diff --git a/hw/xen/xen_pt.c b/hw/xen/xen_pt.c
new file mode 100644 (file)
index 0000000..c199818
--- /dev/null
@@ -0,0 +1,844 @@
+/*
+ * Copyright (c) 2007, Neocleus Corporation.
+ * Copyright (c) 2007, Intel Corporation.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ * Alex Novik <alex@neocleus.com>
+ * Allen Kay <allen.m.kay@intel.com>
+ * Guy Zana <guy@neocleus.com>
+ *
+ * This file implements direct PCI assignment to a HVM guest
+ */
+
+/*
+ * Interrupt Disable policy:
+ *
+ * INTx interrupt:
+ *   Initialize(register_real_device)
+ *     Map INTx(xc_physdev_map_pirq):
+ *       <fail>
+ *         - Set real Interrupt Disable bit to '1'.
+ *         - Set machine_irq and assigned_device->machine_irq to '0'.
+ *         * Don't bind INTx.
+ *
+ *     Bind INTx(xc_domain_bind_pt_pci_irq):
+ *       <fail>
+ *         - Set real Interrupt Disable bit to '1'.
+ *         - Unmap INTx.
+ *         - Decrement xen_pt_mapped_machine_irq[machine_irq]
+ *         - Set assigned_device->machine_irq to '0'.
+ *
+ *   Write to Interrupt Disable bit by guest software(xen_pt_cmd_reg_write)
+ *     Write '0'
+ *       - Set real bit to '0' if assigned_device->machine_irq isn't '0'.
+ *
+ *     Write '1'
+ *       - Set real bit to '1'.
+ *
+ * MSI interrupt:
+ *   Initialize MSI register(xen_pt_msi_setup, xen_pt_msi_update)
+ *     Bind MSI(xc_domain_update_msi_irq)
+ *       <fail>
+ *         - Unmap MSI.
+ *         - Set dev->msi->pirq to '-1'.
+ *
+ * MSI-X interrupt:
+ *   Initialize MSI-X register(xen_pt_msix_update_one)
+ *     Bind MSI-X(xc_domain_update_msi_irq)
+ *       <fail>
+ *         - Unmap MSI-X.
+ *         - Set entry->pirq to '-1'.
+ */
+
+#include <sys/ioctl.h>
+
+#include "hw/pci/pci.h"
+#include "hw/xen/xen.h"
+#include "hw/xen/xen_backend.h"
+#include "xen_pt.h"
+#include "qemu/range.h"
+#include "exec/address-spaces.h"
+
+#define XEN_PT_NR_IRQS (256)
+static uint8_t xen_pt_mapped_machine_irq[XEN_PT_NR_IRQS] = {0};
+
+void xen_pt_log(const PCIDevice *d, const char *f, ...)
+{
+    va_list ap;
+
+    va_start(ap, f);
+    if (d) {
+        fprintf(stderr, "[%02x:%02x.%d] ", pci_bus_num(d->bus),
+                PCI_SLOT(d->devfn), PCI_FUNC(d->devfn));
+    }
+    vfprintf(stderr, f, ap);
+    va_end(ap);
+}
+
+/* Config Space */
+
+static int xen_pt_pci_config_access_check(PCIDevice *d, uint32_t addr, int len)
+{
+    /* check offset range */
+    if (addr >= 0xFF) {
+        XEN_PT_ERR(d, "Failed to access register with offset exceeding 0xFF. "
+                   "(addr: 0x%02x, len: %d)\n", addr, len);
+        return -1;
+    }
+
+    /* check read size */
+    if ((len != 1) && (len != 2) && (len != 4)) {
+        XEN_PT_ERR(d, "Failed to access register with invalid access length. "
+                   "(addr: 0x%02x, len: %d)\n", addr, len);
+        return -1;
+    }
+
+    /* check offset alignment */
+    if (addr & (len - 1)) {
+        XEN_PT_ERR(d, "Failed to access register with invalid access size "
+                   "alignment. (addr: 0x%02x, len: %d)\n", addr, len);
+        return -1;
+    }
+
+    return 0;
+}
+
+int xen_pt_bar_offset_to_index(uint32_t offset)
+{
+    int index = 0;
+
+    /* check Exp ROM BAR */
+    if (offset == PCI_ROM_ADDRESS) {
+        return PCI_ROM_SLOT;
+    }
+
+    /* calculate BAR index */
+    index = (offset - PCI_BASE_ADDRESS_0) >> 2;
+    if (index >= PCI_NUM_REGIONS) {
+        return -1;
+    }
+
+    return index;
+}
+
+static uint32_t xen_pt_pci_read_config(PCIDevice *d, uint32_t addr, int len)
+{
+    XenPCIPassthroughState *s = DO_UPCAST(XenPCIPassthroughState, dev, d);
+    uint32_t val = 0;
+    XenPTRegGroup *reg_grp_entry = NULL;
+    XenPTReg *reg_entry = NULL;
+    int rc = 0;
+    int emul_len = 0;
+    uint32_t find_addr = addr;
+
+    if (xen_pt_pci_config_access_check(d, addr, len)) {
+        goto exit;
+    }
+
+    /* find register group entry */
+    reg_grp_entry = xen_pt_find_reg_grp(s, addr);
+    if (reg_grp_entry) {
+        /* check 0-Hardwired register group */
+        if (reg_grp_entry->reg_grp->grp_type == XEN_PT_GRP_TYPE_HARDWIRED) {
+            /* no need to emulate, just return 0 */
+            val = 0;
+            goto exit;
+        }
+    }
+
+    /* read I/O device register value */
+    rc = xen_host_pci_get_block(&s->real_device, addr, (uint8_t *)&val, len);
+    if (rc < 0) {
+        XEN_PT_ERR(d, "pci_read_block failed. return value: %d.\n", rc);
+        memset(&val, 0xff, len);
+    }
+
+    /* just return the I/O device register value for
+     * passthrough type register group */
+    if (reg_grp_entry == NULL) {
+        goto exit;
+    }
+
+    /* adjust the read value to appropriate CFC-CFF window */
+    val <<= (addr & 3) << 3;
+    emul_len = len;
+
+    /* loop around the guest requested size */
+    while (emul_len > 0) {
+        /* find register entry to be emulated */
+        reg_entry = xen_pt_find_reg(reg_grp_entry, find_addr);
+        if (reg_entry) {
+            XenPTRegInfo *reg = reg_entry->reg;
+            uint32_t real_offset = reg_grp_entry->base_offset + reg->offset;
+            uint32_t valid_mask = 0xFFFFFFFF >> ((4 - emul_len) << 3);
+            uint8_t *ptr_val = NULL;
+
+            valid_mask <<= (find_addr - real_offset) << 3;
+            ptr_val = (uint8_t *)&val + (real_offset & 3);
+
+            /* do emulation based on register size */
+            switch (reg->size) {
+            case 1:
+                if (reg->u.b.read) {
+                    rc = reg->u.b.read(s, reg_entry, ptr_val, valid_mask);
+                }
+                break;
+            case 2:
+                if (reg->u.w.read) {
+                    rc = reg->u.w.read(s, reg_entry,
+                                       (uint16_t *)ptr_val, valid_mask);
+                }
+                break;
+            case 4:
+                if (reg->u.dw.read) {
+                    rc = reg->u.dw.read(s, reg_entry,
+                                        (uint32_t *)ptr_val, valid_mask);
+                }
+                break;
+            }
+
+            if (rc < 0) {
+                xen_shutdown_fatal_error("Internal error: Invalid read "
+                                         "emulation. (%s, rc: %d)\n",
+                                         __func__, rc);
+                return 0;
+            }
+
+            /* calculate next address to find */
+            emul_len -= reg->size;
+            if (emul_len > 0) {
+                find_addr = real_offset + reg->size;
+            }
+        } else {
+            /* nothing to do with passthrough type register,
+             * continue to find next byte */
+            emul_len--;
+            find_addr++;
+        }
+    }
+
+    /* need to shift back before returning them to pci bus emulator */
+    val >>= ((addr & 3) << 3);
+
+exit:
+    XEN_PT_LOG_CONFIG(d, addr, val, len);
+    return val;
+}
+
+static void xen_pt_pci_write_config(PCIDevice *d, uint32_t addr,
+                                    uint32_t val, int len)
+{
+    XenPCIPassthroughState *s = DO_UPCAST(XenPCIPassthroughState, dev, d);
+    int index = 0;
+    XenPTRegGroup *reg_grp_entry = NULL;
+    int rc = 0;
+    uint32_t read_val = 0;
+    int emul_len = 0;
+    XenPTReg *reg_entry = NULL;
+    uint32_t find_addr = addr;
+    XenPTRegInfo *reg = NULL;
+
+    if (xen_pt_pci_config_access_check(d, addr, len)) {
+        return;
+    }
+
+    XEN_PT_LOG_CONFIG(d, addr, val, len);
+
+    /* check unused BAR register */
+    index = xen_pt_bar_offset_to_index(addr);
+    if ((index >= 0) && (val > 0 && val < XEN_PT_BAR_ALLF) &&
+        (s->bases[index].bar_flag == XEN_PT_BAR_FLAG_UNUSED)) {
+        XEN_PT_WARN(d, "Guest attempt to set address to unused Base Address "
+                    "Register. (addr: 0x%02x, len: %d)\n", addr, len);
+    }
+
+    /* find register group entry */
+    reg_grp_entry = xen_pt_find_reg_grp(s, addr);
+    if (reg_grp_entry) {
+        /* check 0-Hardwired register group */
+        if (reg_grp_entry->reg_grp->grp_type == XEN_PT_GRP_TYPE_HARDWIRED) {
+            /* ignore silently */
+            XEN_PT_WARN(d, "Access to 0-Hardwired register. "
+                        "(addr: 0x%02x, len: %d)\n", addr, len);
+            return;
+        }
+    }
+
+    rc = xen_host_pci_get_block(&s->real_device, addr,
+                                (uint8_t *)&read_val, len);
+    if (rc < 0) {
+        XEN_PT_ERR(d, "pci_read_block failed. return value: %d.\n", rc);
+        memset(&read_val, 0xff, len);
+    }
+
+    /* pass directly to the real device for passthrough type register group */
+    if (reg_grp_entry == NULL) {
+        goto out;
+    }
+
+    memory_region_transaction_begin();
+    pci_default_write_config(d, addr, val, len);
+
+    /* adjust the read and write value to appropriate CFC-CFF window */
+    read_val <<= (addr & 3) << 3;
+    val <<= (addr & 3) << 3;
+    emul_len = len;
+
+    /* loop around the guest requested size */
+    while (emul_len > 0) {
+        /* find register entry to be emulated */
+        reg_entry = xen_pt_find_reg(reg_grp_entry, find_addr);
+        if (reg_entry) {
+            reg = reg_entry->reg;
+            uint32_t real_offset = reg_grp_entry->base_offset + reg->offset;
+            uint32_t valid_mask = 0xFFFFFFFF >> ((4 - emul_len) << 3);
+            uint8_t *ptr_val = NULL;
+
+            valid_mask <<= (find_addr - real_offset) << 3;
+            ptr_val = (uint8_t *)&val + (real_offset & 3);
+
+            /* do emulation based on register size */
+            switch (reg->size) {
+            case 1:
+                if (reg->u.b.write) {
+                    rc = reg->u.b.write(s, reg_entry, ptr_val,
+                                        read_val >> ((real_offset & 3) << 3),
+                                        valid_mask);
+                }
+                break;
+            case 2:
+                if (reg->u.w.write) {
+                    rc = reg->u.w.write(s, reg_entry, (uint16_t *)ptr_val,
+                                        (read_val >> ((real_offset & 3) << 3)),
+                                        valid_mask);
+                }
+                break;
+            case 4:
+                if (reg->u.dw.write) {
+                    rc = reg->u.dw.write(s, reg_entry, (uint32_t *)ptr_val,
+                                         (read_val >> ((real_offset & 3) << 3)),
+                                         valid_mask);
+                }
+                break;
+            }
+
+            if (rc < 0) {
+                xen_shutdown_fatal_error("Internal error: Invalid write"
+                                         " emulation. (%s, rc: %d)\n",
+                                         __func__, rc);
+                return;
+            }
+
+            /* calculate next address to find */
+            emul_len -= reg->size;
+            if (emul_len > 0) {
+                find_addr = real_offset + reg->size;
+            }
+        } else {
+            /* nothing to do with passthrough type register,
+             * continue to find next byte */
+            emul_len--;
+            find_addr++;
+        }
+    }
+
+    /* need to shift back before passing them to xen_host_pci_device */
+    val >>= (addr & 3) << 3;
+
+    memory_region_transaction_commit();
+
+out:
+    if (!(reg && reg->no_wb)) {
+        /* unknown regs are passed through */
+        rc = xen_host_pci_set_block(&s->real_device, addr,
+                                    (uint8_t *)&val, len);
+
+        if (rc < 0) {
+            XEN_PT_ERR(d, "pci_write_block failed. return value: %d.\n", rc);
+        }
+    }
+}
+
+/* register regions */
+
+static uint64_t xen_pt_bar_read(void *o, hwaddr addr,
+                                unsigned size)
+{
+    PCIDevice *d = o;
+    /* if this function is called, that probably means that there is a
+     * misconfiguration of the IOMMU. */
+    XEN_PT_ERR(d, "Should not read BAR through QEMU. @0x"TARGET_FMT_plx"\n",
+               addr);
+    return 0;
+}
+static void xen_pt_bar_write(void *o, hwaddr addr, uint64_t val,
+                             unsigned size)
+{
+    PCIDevice *d = o;
+    /* Same comment as xen_pt_bar_read function */
+    XEN_PT_ERR(d, "Should not write BAR through QEMU. @0x"TARGET_FMT_plx"\n",
+               addr);
+}
+
+static const MemoryRegionOps ops = {
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .read = xen_pt_bar_read,
+    .write = xen_pt_bar_write,
+};
+
+static int xen_pt_register_regions(XenPCIPassthroughState *s)
+{
+    int i = 0;
+    XenHostPCIDevice *d = &s->real_device;
+
+    /* Register PIO/MMIO BARs */
+    for (i = 0; i < PCI_ROM_SLOT; i++) {
+        XenHostPCIIORegion *r = &d->io_regions[i];
+        uint8_t type;
+
+        if (r->base_addr == 0 || r->size == 0) {
+            continue;
+        }
+
+        s->bases[i].access.u = r->base_addr;
+
+        if (r->type & XEN_HOST_PCI_REGION_TYPE_IO) {
+            type = PCI_BASE_ADDRESS_SPACE_IO;
+        } else {
+            type = PCI_BASE_ADDRESS_SPACE_MEMORY;
+            if (r->type & XEN_HOST_PCI_REGION_TYPE_PREFETCH) {
+                type |= PCI_BASE_ADDRESS_MEM_PREFETCH;
+            }
+            if (r->type & XEN_HOST_PCI_REGION_TYPE_MEM_64) {
+                type |= PCI_BASE_ADDRESS_MEM_TYPE_64;
+            }
+        }
+
+        memory_region_init_io(&s->bar[i], &ops, &s->dev,
+                              "xen-pci-pt-bar", r->size);
+        pci_register_bar(&s->dev, i, type, &s->bar[i]);
+
+        XEN_PT_LOG(&s->dev, "IO region %i registered (size=0x%lx"PRIx64
+                   " base_addr=0x%lx"PRIx64" type: %#x)\n",
+                   i, r->size, r->base_addr, type);
+    }
+
+    /* Register expansion ROM address */
+    if (d->rom.base_addr && d->rom.size) {
+        uint32_t bar_data = 0;
+
+        /* Re-set BAR reported by OS, otherwise ROM can't be read. */
+        if (xen_host_pci_get_long(d, PCI_ROM_ADDRESS, &bar_data)) {
+            return 0;
+        }
+        if ((bar_data & PCI_ROM_ADDRESS_MASK) == 0) {
+            bar_data |= d->rom.base_addr & PCI_ROM_ADDRESS_MASK;
+            xen_host_pci_set_long(d, PCI_ROM_ADDRESS, bar_data);
+        }
+
+        s->bases[PCI_ROM_SLOT].access.maddr = d->rom.base_addr;
+
+        memory_region_init_rom_device(&s->rom, NULL, NULL,
+                                      "xen-pci-pt-rom", d->rom.size);
+        pci_register_bar(&s->dev, PCI_ROM_SLOT, PCI_BASE_ADDRESS_MEM_PREFETCH,
+                         &s->rom);
+
+        XEN_PT_LOG(&s->dev, "Expansion ROM registered (size=0x%08"PRIx64
+                   " base_addr=0x%08"PRIx64")\n",
+                   d->rom.size, d->rom.base_addr);
+    }
+
+    return 0;
+}
+
+static void xen_pt_unregister_regions(XenPCIPassthroughState *s)
+{
+    XenHostPCIDevice *d = &s->real_device;
+    int i;
+
+    for (i = 0; i < PCI_NUM_REGIONS - 1; i++) {
+        XenHostPCIIORegion *r = &d->io_regions[i];
+
+        if (r->base_addr == 0 || r->size == 0) {
+            continue;
+        }
+
+        memory_region_destroy(&s->bar[i]);
+    }
+    if (d->rom.base_addr && d->rom.size) {
+        memory_region_destroy(&s->rom);
+    }
+}
+
+/* region mapping */
+
+static int xen_pt_bar_from_region(XenPCIPassthroughState *s, MemoryRegion *mr)
+{
+    int i = 0;
+
+    for (i = 0; i < PCI_NUM_REGIONS - 1; i++) {
+        if (mr == &s->bar[i]) {
+            return i;
+        }
+    }
+    if (mr == &s->rom) {
+        return PCI_ROM_SLOT;
+    }
+    return -1;
+}
+
+/*
+ * This function checks if an io_region overlaps an io_region from another
+ * device.  The io_region to check is provided with (addr, size and type)
+ * A callback can be provided and will be called for every region that is
+ * overlapped.
+ * The return value indicates if the region is overlappsed */
+struct CheckBarArgs {
+    XenPCIPassthroughState *s;
+    pcibus_t addr;
+    pcibus_t size;
+    uint8_t type;
+    bool rc;
+};
+static void xen_pt_check_bar_overlap(PCIBus *bus, PCIDevice *d, void *opaque)
+{
+    struct CheckBarArgs *arg = opaque;
+    XenPCIPassthroughState *s = arg->s;
+    uint8_t type = arg->type;
+    int i;
+
+    if (d->devfn == s->dev.devfn) {
+        return;
+    }
+
+    /* xxx: This ignores bridges. */
+    for (i = 0; i < PCI_NUM_REGIONS; i++) {
+        const PCIIORegion *r = &d->io_regions[i];
+
+        if (!r->size) {
+            continue;
+        }
+        if ((type & PCI_BASE_ADDRESS_SPACE_IO)
+            != (r->type & PCI_BASE_ADDRESS_SPACE_IO)) {
+            continue;
+        }
+
+        if (ranges_overlap(arg->addr, arg->size, r->addr, r->size)) {
+            XEN_PT_WARN(&s->dev,
+                        "Overlapped to device [%02x:%02x.%d] Region: %i"
+                        " (addr: %#"FMT_PCIBUS", len: %#"FMT_PCIBUS")\n",
+                        pci_bus_num(bus), PCI_SLOT(d->devfn),
+                        PCI_FUNC(d->devfn), i, r->addr, r->size);
+            arg->rc = true;
+        }
+    }
+}
+
+static void xen_pt_region_update(XenPCIPassthroughState *s,
+                                 MemoryRegionSection *sec, bool adding)
+{
+    PCIDevice *d = &s->dev;
+    MemoryRegion *mr = sec->mr;
+    int bar = -1;
+    int rc;
+    int op = adding ? DPCI_ADD_MAPPING : DPCI_REMOVE_MAPPING;
+    struct CheckBarArgs args = {
+        .s = s,
+        .addr = sec->offset_within_address_space,
+        .size = sec->size,
+        .rc = false,
+    };
+
+    bar = xen_pt_bar_from_region(s, mr);
+    if (bar == -1 && (!s->msix || &s->msix->mmio != mr)) {
+        return;
+    }
+
+    if (s->msix && &s->msix->mmio == mr) {
+        if (adding) {
+            s->msix->mmio_base_addr = sec->offset_within_address_space;
+            rc = xen_pt_msix_update_remap(s, s->msix->bar_index);
+        }
+        return;
+    }
+
+    args.type = d->io_regions[bar].type;
+    pci_for_each_device(d->bus, pci_bus_num(d->bus),
+                        xen_pt_check_bar_overlap, &args);
+    if (args.rc) {
+        XEN_PT_WARN(d, "Region: %d (addr: %#"FMT_PCIBUS
+                    ", len: %#"FMT_PCIBUS") is overlapped.\n",
+                    bar, sec->offset_within_address_space, sec->size);
+    }
+
+    if (d->io_regions[bar].type & PCI_BASE_ADDRESS_SPACE_IO) {
+        uint32_t guest_port = sec->offset_within_address_space;
+        uint32_t machine_port = s->bases[bar].access.pio_base;
+        uint32_t size = sec->size;
+        rc = xc_domain_ioport_mapping(xen_xc, xen_domid,
+                                      guest_port, machine_port, size,
+                                      op);
+        if (rc) {
+            XEN_PT_ERR(d, "%s ioport mapping failed! (rc: %i)\n",
+                       adding ? "create new" : "remove old", rc);
+        }
+    } else {
+        pcibus_t guest_addr = sec->offset_within_address_space;
+        pcibus_t machine_addr = s->bases[bar].access.maddr
+            + sec->offset_within_region;
+        pcibus_t size = sec->size;
+        rc = xc_domain_memory_mapping(xen_xc, xen_domid,
+                                      XEN_PFN(guest_addr + XC_PAGE_SIZE - 1),
+                                      XEN_PFN(machine_addr + XC_PAGE_SIZE - 1),
+                                      XEN_PFN(size + XC_PAGE_SIZE - 1),
+                                      op);
+        if (rc) {
+            XEN_PT_ERR(d, "%s mem mapping failed! (rc: %i)\n",
+                       adding ? "create new" : "remove old", rc);
+        }
+    }
+}
+
+static void xen_pt_region_add(MemoryListener *l, MemoryRegionSection *sec)
+{
+    XenPCIPassthroughState *s = container_of(l, XenPCIPassthroughState,
+                                             memory_listener);
+
+    xen_pt_region_update(s, sec, true);
+}
+
+static void xen_pt_region_del(MemoryListener *l, MemoryRegionSection *sec)
+{
+    XenPCIPassthroughState *s = container_of(l, XenPCIPassthroughState,
+                                             memory_listener);
+
+    xen_pt_region_update(s, sec, false);
+}
+
+static void xen_pt_io_region_add(MemoryListener *l, MemoryRegionSection *sec)
+{
+    XenPCIPassthroughState *s = container_of(l, XenPCIPassthroughState,
+                                             io_listener);
+
+    xen_pt_region_update(s, sec, true);
+}
+
+static void xen_pt_io_region_del(MemoryListener *l, MemoryRegionSection *sec)
+{
+    XenPCIPassthroughState *s = container_of(l, XenPCIPassthroughState,
+                                             io_listener);
+
+    xen_pt_region_update(s, sec, false);
+}
+
+static const MemoryListener xen_pt_memory_listener = {
+    .region_add = xen_pt_region_add,
+    .region_del = xen_pt_region_del,
+    .priority = 10,
+};
+
+static const MemoryListener xen_pt_io_listener = {
+    .region_add = xen_pt_io_region_add,
+    .region_del = xen_pt_io_region_del,
+    .priority = 10,
+};
+
+/* init */
+
+static int xen_pt_initfn(PCIDevice *d)
+{
+    XenPCIPassthroughState *s = DO_UPCAST(XenPCIPassthroughState, dev, d);
+    int rc = 0;
+    uint8_t machine_irq = 0;
+    int pirq = XEN_PT_UNASSIGNED_PIRQ;
+
+    /* register real device */
+    XEN_PT_LOG(d, "Assigning real physical device %02x:%02x.%d"
+               " to devfn %#x\n",
+               s->hostaddr.bus, s->hostaddr.slot, s->hostaddr.function,
+               s->dev.devfn);
+
+    rc = xen_host_pci_device_get(&s->real_device,
+                                 s->hostaddr.domain, s->hostaddr.bus,
+                                 s->hostaddr.slot, s->hostaddr.function);
+    if (rc) {
+        XEN_PT_ERR(d, "Failed to \"open\" the real pci device. rc: %i\n", rc);
+        return -1;
+    }
+
+    s->is_virtfn = s->real_device.is_virtfn;
+    if (s->is_virtfn) {
+        XEN_PT_LOG(d, "%04x:%02x:%02x.%d is a SR-IOV Virtual Function\n",
+                   s->real_device.domain, s->real_device.bus,
+                   s->real_device.dev, s->real_device.func);
+    }
+
+    /* Initialize virtualized PCI configuration (Extended 256 Bytes) */
+    if (xen_host_pci_get_block(&s->real_device, 0, d->config,
+                               PCI_CONFIG_SPACE_SIZE) == -1) {
+        xen_host_pci_device_put(&s->real_device);
+        return -1;
+    }
+
+    s->memory_listener = xen_pt_memory_listener;
+    s->io_listener = xen_pt_io_listener;
+
+    /* Handle real device's MMIO/PIO BARs */
+    xen_pt_register_regions(s);
+
+    /* reinitialize each config register to be emulated */
+    if (xen_pt_config_init(s)) {
+        XEN_PT_ERR(d, "PCI Config space initialisation failed.\n");
+        xen_host_pci_device_put(&s->real_device);
+        return -1;
+    }
+
+    /* Bind interrupt */
+    if (!s->dev.config[PCI_INTERRUPT_PIN]) {
+        XEN_PT_LOG(d, "no pin interrupt\n");
+        goto out;
+    }
+
+    machine_irq = s->real_device.irq;
+    rc = xc_physdev_map_pirq(xen_xc, xen_domid, machine_irq, &pirq);
+
+    if (rc < 0) {
+        XEN_PT_ERR(d, "Mapping machine irq %u to pirq %i failed, (rc: %d)\n",
+                   machine_irq, pirq, rc);
+
+        /* Disable PCI intx assertion (turn on bit10 of devctl) */
+        xen_host_pci_set_word(&s->real_device,
+                              PCI_COMMAND,
+                              pci_get_word(s->dev.config + PCI_COMMAND)
+                              | PCI_COMMAND_INTX_DISABLE);
+        machine_irq = 0;
+        s->machine_irq = 0;
+    } else {
+        machine_irq = pirq;
+        s->machine_irq = pirq;
+        xen_pt_mapped_machine_irq[machine_irq]++;
+    }
+
+    /* bind machine_irq to device */
+    if (machine_irq != 0) {
+        uint8_t e_intx = xen_pt_pci_intx(s);
+
+        rc = xc_domain_bind_pt_pci_irq(xen_xc, xen_domid, machine_irq,
+                                       pci_bus_num(d->bus),
+                                       PCI_SLOT(d->devfn),
+                                       e_intx);
+        if (rc < 0) {
+            XEN_PT_ERR(d, "Binding of interrupt %i failed! (rc: %d)\n",
+                       e_intx, rc);
+
+            /* Disable PCI intx assertion (turn on bit10 of devctl) */
+            xen_host_pci_set_word(&s->real_device, PCI_COMMAND,
+                                  *(uint16_t *)(&s->dev.config[PCI_COMMAND])
+                                  | PCI_COMMAND_INTX_DISABLE);
+            xen_pt_mapped_machine_irq[machine_irq]--;
+
+            if (xen_pt_mapped_machine_irq[machine_irq] == 0) {
+                if (xc_physdev_unmap_pirq(xen_xc, xen_domid, machine_irq)) {
+                    XEN_PT_ERR(d, "Unmapping of machine interrupt %i failed!"
+                               " (rc: %d)\n", machine_irq, rc);
+                }
+            }
+            s->machine_irq = 0;
+        }
+    }
+
+out:
+    memory_listener_register(&s->memory_listener, &address_space_memory);
+    memory_listener_register(&s->io_listener, &address_space_io);
+    XEN_PT_LOG(d, "Real physical device %02x:%02x.%d registered successfuly!\n",
+               s->hostaddr.bus, s->hostaddr.slot, s->hostaddr.function);
+
+    return 0;
+}
+
+static void xen_pt_unregister_device(PCIDevice *d)
+{
+    XenPCIPassthroughState *s = DO_UPCAST(XenPCIPassthroughState, dev, d);
+    uint8_t machine_irq = s->machine_irq;
+    uint8_t intx = xen_pt_pci_intx(s);
+    int rc;
+
+    if (machine_irq) {
+        rc = xc_domain_unbind_pt_irq(xen_xc, xen_domid, machine_irq,
+                                     PT_IRQ_TYPE_PCI,
+                                     pci_bus_num(d->bus),
+                                     PCI_SLOT(s->dev.devfn),
+                                     intx,
+                                     0 /* isa_irq */);
+        if (rc < 0) {
+            XEN_PT_ERR(d, "unbinding of interrupt INT%c failed."
+                       " (machine irq: %i, rc: %d)"
+                       " But bravely continuing on..\n",
+                       'a' + intx, machine_irq, rc);
+        }
+    }
+
+    if (s->msi) {
+        xen_pt_msi_disable(s);
+    }
+    if (s->msix) {
+        xen_pt_msix_disable(s);
+    }
+
+    if (machine_irq) {
+        xen_pt_mapped_machine_irq[machine_irq]--;
+
+        if (xen_pt_mapped_machine_irq[machine_irq] == 0) {
+            rc = xc_physdev_unmap_pirq(xen_xc, xen_domid, machine_irq);
+
+            if (rc < 0) {
+                XEN_PT_ERR(d, "unmapping of interrupt %i failed. (rc: %d)"
+                           " But bravely continuing on..\n",
+                           machine_irq, rc);
+            }
+        }
+    }
+
+    /* delete all emulated config registers */
+    xen_pt_config_delete(s);
+
+    xen_pt_unregister_regions(s);
+    memory_listener_unregister(&s->memory_listener);
+    memory_listener_unregister(&s->io_listener);
+
+    xen_host_pci_device_put(&s->real_device);
+}
+
+static Property xen_pci_passthrough_properties[] = {
+    DEFINE_PROP_PCI_HOST_DEVADDR("hostaddr", XenPCIPassthroughState, hostaddr),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void xen_pci_passthrough_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = xen_pt_initfn;
+    k->exit = xen_pt_unregister_device;
+    k->config_read = xen_pt_pci_read_config;
+    k->config_write = xen_pt_pci_write_config;
+    dc->desc = "Assign an host PCI device with Xen";
+    dc->props = xen_pci_passthrough_properties;
+};
+
+static const TypeInfo xen_pci_passthrough_info = {
+    .name = "xen-pci-passthrough",
+    .parent = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(XenPCIPassthroughState),
+    .class_init = xen_pci_passthrough_class_init,
+};
+
+static void xen_pci_passthrough_register_types(void)
+{
+    type_register_static(&xen_pci_passthrough_info);
+}
+
+type_init(xen_pci_passthrough_register_types)
diff --git a/hw/xen/xen_pt.h b/hw/xen/xen_pt.h
new file mode 100644 (file)
index 0000000..942dc60
--- /dev/null
@@ -0,0 +1,302 @@
+#ifndef XEN_PT_H
+#define XEN_PT_H
+
+#include "qemu-common.h"
+#include "hw/xen/xen_common.h"
+#include "hw/pci/pci.h"
+#include "xen-host-pci-device.h"
+
+void xen_pt_log(const PCIDevice *d, const char *f, ...) GCC_FMT_ATTR(2, 3);
+
+#define XEN_PT_ERR(d, _f, _a...) xen_pt_log(d, "%s: Error: "_f, __func__, ##_a)
+
+#ifdef XEN_PT_LOGGING_ENABLED
+#  define XEN_PT_LOG(d, _f, _a...)  xen_pt_log(d, "%s: " _f, __func__, ##_a)
+#  define XEN_PT_WARN(d, _f, _a...) \
+    xen_pt_log(d, "%s: Warning: "_f, __func__, ##_a)
+#else
+#  define XEN_PT_LOG(d, _f, _a...)
+#  define XEN_PT_WARN(d, _f, _a...)
+#endif
+
+#ifdef XEN_PT_DEBUG_PCI_CONFIG_ACCESS
+#  define XEN_PT_LOG_CONFIG(d, addr, val, len) \
+    xen_pt_log(d, "%s: address=0x%04x val=0x%08x len=%d\n", \
+               __func__, addr, val, len)
+#else
+#  define XEN_PT_LOG_CONFIG(d, addr, val, len)
+#endif
+
+
+/* Helper */
+#define XEN_PFN(x) ((x) >> XC_PAGE_SHIFT)
+
+typedef struct XenPTRegInfo XenPTRegInfo;
+typedef struct XenPTReg XenPTReg;
+
+typedef struct XenPCIPassthroughState XenPCIPassthroughState;
+
+/* function type for config reg */
+typedef int (*xen_pt_conf_reg_init)
+    (XenPCIPassthroughState *, XenPTRegInfo *, uint32_t real_offset,
+     uint32_t *data);
+typedef int (*xen_pt_conf_dword_write)
+    (XenPCIPassthroughState *, XenPTReg *cfg_entry,
+     uint32_t *val, uint32_t dev_value, uint32_t valid_mask);
+typedef int (*xen_pt_conf_word_write)
+    (XenPCIPassthroughState *, XenPTReg *cfg_entry,
+     uint16_t *val, uint16_t dev_value, uint16_t valid_mask);
+typedef int (*xen_pt_conf_byte_write)
+    (XenPCIPassthroughState *, XenPTReg *cfg_entry,
+     uint8_t *val, uint8_t dev_value, uint8_t valid_mask);
+typedef int (*xen_pt_conf_dword_read)
+    (XenPCIPassthroughState *, XenPTReg *cfg_entry,
+     uint32_t *val, uint32_t valid_mask);
+typedef int (*xen_pt_conf_word_read)
+    (XenPCIPassthroughState *, XenPTReg *cfg_entry,
+     uint16_t *val, uint16_t valid_mask);
+typedef int (*xen_pt_conf_byte_read)
+    (XenPCIPassthroughState *, XenPTReg *cfg_entry,
+     uint8_t *val, uint8_t valid_mask);
+
+#define XEN_PT_BAR_ALLF 0xFFFFFFFF
+#define XEN_PT_BAR_UNMAPPED (-1)
+
+#define PCI_CAP_MAX 48
+
+
+typedef enum {
+    XEN_PT_GRP_TYPE_HARDWIRED = 0,  /* 0 Hardwired reg group */
+    XEN_PT_GRP_TYPE_EMU,            /* emul reg group */
+} XenPTRegisterGroupType;
+
+typedef enum {
+    XEN_PT_BAR_FLAG_MEM = 0,        /* Memory type BAR */
+    XEN_PT_BAR_FLAG_IO,             /* I/O type BAR */
+    XEN_PT_BAR_FLAG_UPPER,          /* upper 64bit BAR */
+    XEN_PT_BAR_FLAG_UNUSED,         /* unused BAR */
+} XenPTBarFlag;
+
+
+typedef struct XenPTRegion {
+    /* BAR flag */
+    XenPTBarFlag bar_flag;
+    /* Translation of the emulated address */
+    union {
+        uint64_t maddr;
+        uint64_t pio_base;
+        uint64_t u;
+    } access;
+} XenPTRegion;
+
+/* XenPTRegInfo declaration
+ * - only for emulated register (either a part or whole bit).
+ * - for passthrough register that need special behavior (like interacting with
+ *   other component), set emu_mask to all 0 and specify r/w func properly.
+ * - do NOT use ALL F for init_val, otherwise the tbl will not be registered.
+ */
+
+/* emulated register information */
+struct XenPTRegInfo {
+    uint32_t offset;
+    uint32_t size;
+    uint32_t init_val;
+    /* reg read only field mask (ON:RO/ROS, OFF:other) */
+    uint32_t ro_mask;
+    /* reg emulate field mask (ON:emu, OFF:passthrough) */
+    uint32_t emu_mask;
+    /* no write back allowed */
+    uint32_t no_wb;
+    xen_pt_conf_reg_init init;
+    /* read/write function pointer
+     * for double_word/word/byte size */
+    union {
+        struct {
+            xen_pt_conf_dword_write write;
+            xen_pt_conf_dword_read read;
+        } dw;
+        struct {
+            xen_pt_conf_word_write write;
+            xen_pt_conf_word_read read;
+        } w;
+        struct {
+            xen_pt_conf_byte_write write;
+            xen_pt_conf_byte_read read;
+        } b;
+    } u;
+};
+
+/* emulated register management */
+struct XenPTReg {
+    QLIST_ENTRY(XenPTReg) entries;
+    XenPTRegInfo *reg;
+    uint32_t data; /* emulated value */
+};
+
+typedef struct XenPTRegGroupInfo XenPTRegGroupInfo;
+
+/* emul reg group size initialize method */
+typedef int (*xen_pt_reg_size_init_fn)
+    (XenPCIPassthroughState *, const XenPTRegGroupInfo *,
+     uint32_t base_offset, uint8_t *size);
+
+/* emulated register group information */
+struct XenPTRegGroupInfo {
+    uint8_t grp_id;
+    XenPTRegisterGroupType grp_type;
+    uint8_t grp_size;
+    xen_pt_reg_size_init_fn size_init;
+    XenPTRegInfo *emu_regs;
+};
+
+/* emul register group management table */
+typedef struct XenPTRegGroup {
+    QLIST_ENTRY(XenPTRegGroup) entries;
+    const XenPTRegGroupInfo *reg_grp;
+    uint32_t base_offset;
+    uint8_t size;
+    QLIST_HEAD(, XenPTReg) reg_tbl_list;
+} XenPTRegGroup;
+
+
+#define XEN_PT_UNASSIGNED_PIRQ (-1)
+typedef struct XenPTMSI {
+    uint16_t flags;
+    uint32_t addr_lo;  /* guest message address */
+    uint32_t addr_hi;  /* guest message upper address */
+    uint16_t data;     /* guest message data */
+    uint32_t ctrl_offset; /* saved control offset */
+    int pirq;          /* guest pirq corresponding */
+    bool initialized;  /* when guest MSI is initialized */
+    bool mapped;       /* when pirq is mapped */
+} XenPTMSI;
+
+typedef struct XenPTMSIXEntry {
+    int pirq;
+    uint64_t addr;
+    uint32_t data;
+    uint32_t vector_ctrl;
+    bool updated; /* indicate whether MSI ADDR or DATA is updated */
+} XenPTMSIXEntry;
+typedef struct XenPTMSIX {
+    uint32_t ctrl_offset;
+    bool enabled;
+    int total_entries;
+    int bar_index;
+    uint64_t table_base;
+    uint32_t table_offset_adjust; /* page align mmap */
+    uint64_t mmio_base_addr;
+    MemoryRegion mmio;
+    void *phys_iomem_base;
+    XenPTMSIXEntry msix_entry[0];
+} XenPTMSIX;
+
+struct XenPCIPassthroughState {
+    PCIDevice dev;
+
+    PCIHostDeviceAddress hostaddr;
+    bool is_virtfn;
+    XenHostPCIDevice real_device;
+    XenPTRegion bases[PCI_NUM_REGIONS]; /* Access regions */
+    QLIST_HEAD(, XenPTRegGroup) reg_grps;
+
+    uint32_t machine_irq;
+
+    XenPTMSI *msi;
+    XenPTMSIX *msix;
+
+    MemoryRegion bar[PCI_NUM_REGIONS - 1];
+    MemoryRegion rom;
+
+    MemoryListener memory_listener;
+    MemoryListener io_listener;
+};
+
+int xen_pt_config_init(XenPCIPassthroughState *s);
+void xen_pt_config_delete(XenPCIPassthroughState *s);
+XenPTRegGroup *xen_pt_find_reg_grp(XenPCIPassthroughState *s, uint32_t address);
+XenPTReg *xen_pt_find_reg(XenPTRegGroup *reg_grp, uint32_t address);
+int xen_pt_bar_offset_to_index(uint32_t offset);
+
+static inline pcibus_t xen_pt_get_emul_size(XenPTBarFlag flag, pcibus_t r_size)
+{
+    /* align resource size (memory type only) */
+    if (flag == XEN_PT_BAR_FLAG_MEM) {
+        return (r_size + XC_PAGE_SIZE - 1) & XC_PAGE_MASK;
+    } else {
+        return r_size;
+    }
+}
+
+/* INTx */
+/* The PCI Local Bus Specification, Rev. 3.0,
+ * Section 6.2.4 Miscellaneous Registers, pp 223
+ * outlines 5 valid values for the interrupt pin (intx).
+ *  0: For devices (or device functions) that don't use an interrupt in
+ *  1: INTA#
+ *  2: INTB#
+ *  3: INTC#
+ *  4: INTD#
+ *
+ * Xen uses the following 4 values for intx
+ *  0: INTA#
+ *  1: INTB#
+ *  2: INTC#
+ *  3: INTD#
+ *
+ * Observing that these list of values are not the same, xen_pt_pci_read_intx()
+ * uses the following mapping from hw to xen values.
+ * This seems to reflect the current usage within Xen.
+ *
+ * PCI hardware    | Xen | Notes
+ * ----------------+-----+----------------------------------------------------
+ * 0               | 0   | No interrupt
+ * 1               | 0   | INTA#
+ * 2               | 1   | INTB#
+ * 3               | 2   | INTC#
+ * 4               | 3   | INTD#
+ * any other value | 0   | This should never happen, log error message
+ */
+
+static inline uint8_t xen_pt_pci_read_intx(XenPCIPassthroughState *s)
+{
+    uint8_t v = 0;
+    xen_host_pci_get_byte(&s->real_device, PCI_INTERRUPT_PIN, &v);
+    return v;
+}
+
+static inline uint8_t xen_pt_pci_intx(XenPCIPassthroughState *s)
+{
+    uint8_t r_val = xen_pt_pci_read_intx(s);
+
+    XEN_PT_LOG(&s->dev, "intx=%i\n", r_val);
+    if (r_val < 1 || r_val > 4) {
+        XEN_PT_LOG(&s->dev, "Interrupt pin read from hardware is out of range:"
+                   " value=%i, acceptable range is 1 - 4\n", r_val);
+        r_val = 0;
+    } else {
+        r_val -= 1;
+    }
+
+    return r_val;
+}
+
+/* MSI/MSI-X */
+int xen_pt_msi_set_enable(XenPCIPassthroughState *s, bool en);
+int xen_pt_msi_setup(XenPCIPassthroughState *s);
+int xen_pt_msi_update(XenPCIPassthroughState *d);
+void xen_pt_msi_disable(XenPCIPassthroughState *s);
+
+int xen_pt_msix_init(XenPCIPassthroughState *s, uint32_t base);
+void xen_pt_msix_delete(XenPCIPassthroughState *s);
+int xen_pt_msix_update(XenPCIPassthroughState *s);
+int xen_pt_msix_update_remap(XenPCIPassthroughState *s, int bar_index);
+void xen_pt_msix_disable(XenPCIPassthroughState *s);
+
+static inline bool xen_pt_has_msix_mapping(XenPCIPassthroughState *s, int bar)
+{
+    return s->msix && s->msix->bar_index == bar;
+}
+
+
+#endif /* !XEN_PT_H */
diff --git a/hw/xen/xen_pt_config_init.c b/hw/xen/xen_pt_config_init.c
new file mode 100644 (file)
index 0000000..01872db
--- /dev/null
@@ -0,0 +1,1882 @@
+/*
+ * Copyright (c) 2007, Neocleus Corporation.
+ * Copyright (c) 2007, Intel Corporation.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ * Alex Novik <alex@neocleus.com>
+ * Allen Kay <allen.m.kay@intel.com>
+ * Guy Zana <guy@neocleus.com>
+ *
+ * This file implements direct PCI assignment to a HVM guest
+ */
+
+#include "qemu/timer.h"
+#include "hw/xen/xen_backend.h"
+#include "xen_pt.h"
+
+#define XEN_PT_MERGE_VALUE(value, data, val_mask) \
+    (((value) & (val_mask)) | ((data) & ~(val_mask)))
+
+#define XEN_PT_INVALID_REG          0xFFFFFFFF      /* invalid register value */
+
+/* prototype */
+
+static int xen_pt_ptr_reg_init(XenPCIPassthroughState *s, XenPTRegInfo *reg,
+                               uint32_t real_offset, uint32_t *data);
+
+
+/* helper */
+
+/* A return value of 1 means the capability should NOT be exposed to guest. */
+static int xen_pt_hide_dev_cap(const XenHostPCIDevice *d, uint8_t grp_id)
+{
+    switch (grp_id) {
+    case PCI_CAP_ID_EXP:
+        /* The PCI Express Capability Structure of the VF of Intel 82599 10GbE
+         * Controller looks trivial, e.g., the PCI Express Capabilities
+         * Register is 0. We should not try to expose it to guest.
+         *
+         * The datasheet is available at
+         * http://download.intel.com/design/network/datashts/82599_datasheet.pdf
+         *
+         * See 'Table 9.7. VF PCIe Configuration Space' of the datasheet, the
+         * PCI Express Capability Structure of the VF of Intel 82599 10GbE
+         * Controller looks trivial, e.g., the PCI Express Capabilities
+         * Register is 0, so the Capability Version is 0 and
+         * xen_pt_pcie_size_init() would fail.
+         */
+        if (d->vendor_id == PCI_VENDOR_ID_INTEL &&
+            d->device_id == PCI_DEVICE_ID_INTEL_82599_SFP_VF) {
+            return 1;
+        }
+        break;
+    }
+    return 0;
+}
+
+/*   find emulate register group entry */
+XenPTRegGroup *xen_pt_find_reg_grp(XenPCIPassthroughState *s, uint32_t address)
+{
+    XenPTRegGroup *entry = NULL;
+
+    /* find register group entry */
+    QLIST_FOREACH(entry, &s->reg_grps, entries) {
+        /* check address */
+        if ((entry->base_offset <= address)
+            && ((entry->base_offset + entry->size) > address)) {
+            return entry;
+        }
+    }
+
+    /* group entry not found */
+    return NULL;
+}
+
+/* find emulate register entry */
+XenPTReg *xen_pt_find_reg(XenPTRegGroup *reg_grp, uint32_t address)
+{
+    XenPTReg *reg_entry = NULL;
+    XenPTRegInfo *reg = NULL;
+    uint32_t real_offset = 0;
+
+    /* find register entry */
+    QLIST_FOREACH(reg_entry, &reg_grp->reg_tbl_list, entries) {
+        reg = reg_entry->reg;
+        real_offset = reg_grp->base_offset + reg->offset;
+        /* check address */
+        if ((real_offset <= address)
+            && ((real_offset + reg->size) > address)) {
+            return reg_entry;
+        }
+    }
+
+    return NULL;
+}
+
+
+/****************
+ * general register functions
+ */
+
+/* register initialization function */
+
+static int xen_pt_common_reg_init(XenPCIPassthroughState *s,
+                                  XenPTRegInfo *reg, uint32_t real_offset,
+                                  uint32_t *data)
+{
+    *data = reg->init_val;
+    return 0;
+}
+
+/* Read register functions */
+
+static int xen_pt_byte_reg_read(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
+                                uint8_t *value, uint8_t valid_mask)
+{
+    XenPTRegInfo *reg = cfg_entry->reg;
+    uint8_t valid_emu_mask = 0;
+
+    /* emulate byte register */
+    valid_emu_mask = reg->emu_mask & valid_mask;
+    *value = XEN_PT_MERGE_VALUE(*value, cfg_entry->data, ~valid_emu_mask);
+
+    return 0;
+}
+static int xen_pt_word_reg_read(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
+                                uint16_t *value, uint16_t valid_mask)
+{
+    XenPTRegInfo *reg = cfg_entry->reg;
+    uint16_t valid_emu_mask = 0;
+
+    /* emulate word register */
+    valid_emu_mask = reg->emu_mask & valid_mask;
+    *value = XEN_PT_MERGE_VALUE(*value, cfg_entry->data, ~valid_emu_mask);
+
+    return 0;
+}
+static int xen_pt_long_reg_read(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
+                                uint32_t *value, uint32_t valid_mask)
+{
+    XenPTRegInfo *reg = cfg_entry->reg;
+    uint32_t valid_emu_mask = 0;
+
+    /* emulate long register */
+    valid_emu_mask = reg->emu_mask & valid_mask;
+    *value = XEN_PT_MERGE_VALUE(*value, cfg_entry->data, ~valid_emu_mask);
+
+    return 0;
+}
+
+/* Write register functions */
+
+static int xen_pt_byte_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
+                                 uint8_t *val, uint8_t dev_value,
+                                 uint8_t valid_mask)
+{
+    XenPTRegInfo *reg = cfg_entry->reg;
+    uint8_t writable_mask = 0;
+    uint8_t throughable_mask = 0;
+
+    /* modify emulate register */
+    writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
+    cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask);
+
+    /* create value for writing to I/O device register */
+    throughable_mask = ~reg->emu_mask & valid_mask;
+    *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
+
+    return 0;
+}
+static int xen_pt_word_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
+                                 uint16_t *val, uint16_t dev_value,
+                                 uint16_t valid_mask)
+{
+    XenPTRegInfo *reg = cfg_entry->reg;
+    uint16_t writable_mask = 0;
+    uint16_t throughable_mask = 0;
+
+    /* modify emulate register */
+    writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
+    cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask);
+
+    /* create value for writing to I/O device register */
+    throughable_mask = ~reg->emu_mask & valid_mask;
+    *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
+
+    return 0;
+}
+static int xen_pt_long_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
+                                 uint32_t *val, uint32_t dev_value,
+                                 uint32_t valid_mask)
+{
+    XenPTRegInfo *reg = cfg_entry->reg;
+    uint32_t writable_mask = 0;
+    uint32_t throughable_mask = 0;
+
+    /* modify emulate register */
+    writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
+    cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask);
+
+    /* create value for writing to I/O device register */
+    throughable_mask = ~reg->emu_mask & valid_mask;
+    *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
+
+    return 0;
+}
+
+
+/* XenPTRegInfo declaration
+ * - only for emulated register (either a part or whole bit).
+ * - for passthrough register that need special behavior (like interacting with
+ *   other component), set emu_mask to all 0 and specify r/w func properly.
+ * - do NOT use ALL F for init_val, otherwise the tbl will not be registered.
+ */
+
+/********************
+ * Header Type0
+ */
+
+static int xen_pt_vendor_reg_init(XenPCIPassthroughState *s,
+                                  XenPTRegInfo *reg, uint32_t real_offset,
+                                  uint32_t *data)
+{
+    *data = s->real_device.vendor_id;
+    return 0;
+}
+static int xen_pt_device_reg_init(XenPCIPassthroughState *s,
+                                  XenPTRegInfo *reg, uint32_t real_offset,
+                                  uint32_t *data)
+{
+    *data = s->real_device.device_id;
+    return 0;
+}
+static int xen_pt_status_reg_init(XenPCIPassthroughState *s,
+                                  XenPTRegInfo *reg, uint32_t real_offset,
+                                  uint32_t *data)
+{
+    XenPTRegGroup *reg_grp_entry = NULL;
+    XenPTReg *reg_entry = NULL;
+    uint32_t reg_field = 0;
+
+    /* find Header register group */
+    reg_grp_entry = xen_pt_find_reg_grp(s, PCI_CAPABILITY_LIST);
+    if (reg_grp_entry) {
+        /* find Capabilities Pointer register */
+        reg_entry = xen_pt_find_reg(reg_grp_entry, PCI_CAPABILITY_LIST);
+        if (reg_entry) {
+            /* check Capabilities Pointer register */
+            if (reg_entry->data) {
+                reg_field |= PCI_STATUS_CAP_LIST;
+            } else {
+                reg_field &= ~PCI_STATUS_CAP_LIST;
+            }
+        } else {
+            xen_shutdown_fatal_error("Internal error: Couldn't find XenPTReg*"
+                                     " for Capabilities Pointer register."
+                                     " (%s)\n", __func__);
+            return -1;
+        }
+    } else {
+        xen_shutdown_fatal_error("Internal error: Couldn't find XenPTRegGroup"
+                                 " for Header. (%s)\n", __func__);
+        return -1;
+    }
+
+    *data = reg_field;
+    return 0;
+}
+static int xen_pt_header_type_reg_init(XenPCIPassthroughState *s,
+                                       XenPTRegInfo *reg, uint32_t real_offset,
+                                       uint32_t *data)
+{
+    /* read PCI_HEADER_TYPE */
+    *data = reg->init_val | 0x80;
+    return 0;
+}
+
+/* initialize Interrupt Pin register */
+static int xen_pt_irqpin_reg_init(XenPCIPassthroughState *s,
+                                  XenPTRegInfo *reg, uint32_t real_offset,
+                                  uint32_t *data)
+{
+    *data = xen_pt_pci_read_intx(s);
+    return 0;
+}
+
+/* Command register */
+static int xen_pt_cmd_reg_read(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
+                               uint16_t *value, uint16_t valid_mask)
+{
+    XenPTRegInfo *reg = cfg_entry->reg;
+    uint16_t valid_emu_mask = 0;
+    uint16_t emu_mask = reg->emu_mask;
+
+    if (s->is_virtfn) {
+        emu_mask |= PCI_COMMAND_MEMORY;
+    }
+
+    /* emulate word register */
+    valid_emu_mask = emu_mask & valid_mask;
+    *value = XEN_PT_MERGE_VALUE(*value, cfg_entry->data, ~valid_emu_mask);
+
+    return 0;
+}
+static int xen_pt_cmd_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
+                                uint16_t *val, uint16_t dev_value,
+                                uint16_t valid_mask)
+{
+    XenPTRegInfo *reg = cfg_entry->reg;
+    uint16_t writable_mask = 0;
+    uint16_t throughable_mask = 0;
+    uint16_t emu_mask = reg->emu_mask;
+
+    if (s->is_virtfn) {
+        emu_mask |= PCI_COMMAND_MEMORY;
+    }
+
+    /* modify emulate register */
+    writable_mask = ~reg->ro_mask & valid_mask;
+    cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask);
+
+    /* create value for writing to I/O device register */
+    throughable_mask = ~emu_mask & valid_mask;
+
+    if (*val & PCI_COMMAND_INTX_DISABLE) {
+        throughable_mask |= PCI_COMMAND_INTX_DISABLE;
+    } else {
+        if (s->machine_irq) {
+            throughable_mask |= PCI_COMMAND_INTX_DISABLE;
+        }
+    }
+
+    *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
+
+    return 0;
+}
+
+/* BAR */
+#define XEN_PT_BAR_MEM_RO_MASK    0x0000000F  /* BAR ReadOnly mask(Memory) */
+#define XEN_PT_BAR_MEM_EMU_MASK   0xFFFFFFF0  /* BAR emul mask(Memory) */
+#define XEN_PT_BAR_IO_RO_MASK     0x00000003  /* BAR ReadOnly mask(I/O) */
+#define XEN_PT_BAR_IO_EMU_MASK    0xFFFFFFFC  /* BAR emul mask(I/O) */
+
+static bool is_64bit_bar(PCIIORegion *r)
+{
+    return !!(r->type & PCI_BASE_ADDRESS_MEM_TYPE_64);
+}
+
+static uint64_t xen_pt_get_bar_size(PCIIORegion *r)
+{
+    if (is_64bit_bar(r)) {
+        uint64_t size64;
+        size64 = (r + 1)->size;
+        size64 <<= 32;
+        size64 += r->size;
+        return size64;
+    }
+    return r->size;
+}
+
+static XenPTBarFlag xen_pt_bar_reg_parse(XenPCIPassthroughState *s,
+                                         XenPTRegInfo *reg)
+{
+    PCIDevice *d = &s->dev;
+    XenPTRegion *region = NULL;
+    PCIIORegion *r;
+    int index = 0;
+
+    /* check 64bit BAR */
+    index = xen_pt_bar_offset_to_index(reg->offset);
+    if ((0 < index) && (index < PCI_ROM_SLOT)) {
+        int type = s->real_device.io_regions[index - 1].type;
+
+        if ((type & XEN_HOST_PCI_REGION_TYPE_MEM)
+            && (type & XEN_HOST_PCI_REGION_TYPE_MEM_64)) {
+            region = &s->bases[index - 1];
+            if (region->bar_flag != XEN_PT_BAR_FLAG_UPPER) {
+                return XEN_PT_BAR_FLAG_UPPER;
+            }
+        }
+    }
+
+    /* check unused BAR */
+    r = &d->io_regions[index];
+    if (!xen_pt_get_bar_size(r)) {
+        return XEN_PT_BAR_FLAG_UNUSED;
+    }
+
+    /* for ExpROM BAR */
+    if (index == PCI_ROM_SLOT) {
+        return XEN_PT_BAR_FLAG_MEM;
+    }
+
+    /* check BAR I/O indicator */
+    if (s->real_device.io_regions[index].type & XEN_HOST_PCI_REGION_TYPE_IO) {
+        return XEN_PT_BAR_FLAG_IO;
+    } else {
+        return XEN_PT_BAR_FLAG_MEM;
+    }
+}
+
+static inline uint32_t base_address_with_flags(XenHostPCIIORegion *hr)
+{
+    if (hr->type & XEN_HOST_PCI_REGION_TYPE_IO) {
+        return hr->base_addr | (hr->bus_flags & ~PCI_BASE_ADDRESS_IO_MASK);
+    } else {
+        return hr->base_addr | (hr->bus_flags & ~PCI_BASE_ADDRESS_MEM_MASK);
+    }
+}
+
+static int xen_pt_bar_reg_init(XenPCIPassthroughState *s, XenPTRegInfo *reg,
+                               uint32_t real_offset, uint32_t *data)
+{
+    uint32_t reg_field = 0;
+    int index;
+
+    index = xen_pt_bar_offset_to_index(reg->offset);
+    if (index < 0 || index >= PCI_NUM_REGIONS) {
+        XEN_PT_ERR(&s->dev, "Internal error: Invalid BAR index [%d].\n", index);
+        return -1;
+    }
+
+    /* set BAR flag */
+    s->bases[index].bar_flag = xen_pt_bar_reg_parse(s, reg);
+    if (s->bases[index].bar_flag == XEN_PT_BAR_FLAG_UNUSED) {
+        reg_field = XEN_PT_INVALID_REG;
+    }
+
+    *data = reg_field;
+    return 0;
+}
+static int xen_pt_bar_reg_read(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
+                               uint32_t *value, uint32_t valid_mask)
+{
+    XenPTRegInfo *reg = cfg_entry->reg;
+    uint32_t valid_emu_mask = 0;
+    uint32_t bar_emu_mask = 0;
+    int index;
+
+    /* get BAR index */
+    index = xen_pt_bar_offset_to_index(reg->offset);
+    if (index < 0 || index >= PCI_NUM_REGIONS) {
+        XEN_PT_ERR(&s->dev, "Internal error: Invalid BAR index [%d].\n", index);
+        return -1;
+    }
+
+    /* use fixed-up value from kernel sysfs */
+    *value = base_address_with_flags(&s->real_device.io_regions[index]);
+
+    /* set emulate mask depend on BAR flag */
+    switch (s->bases[index].bar_flag) {
+    case XEN_PT_BAR_FLAG_MEM:
+        bar_emu_mask = XEN_PT_BAR_MEM_EMU_MASK;
+        break;
+    case XEN_PT_BAR_FLAG_IO:
+        bar_emu_mask = XEN_PT_BAR_IO_EMU_MASK;
+        break;
+    case XEN_PT_BAR_FLAG_UPPER:
+        bar_emu_mask = XEN_PT_BAR_ALLF;
+        break;
+    default:
+        break;
+    }
+
+    /* emulate BAR */
+    valid_emu_mask = bar_emu_mask & valid_mask;
+    *value = XEN_PT_MERGE_VALUE(*value, cfg_entry->data, ~valid_emu_mask);
+
+    return 0;
+}
+static int xen_pt_bar_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
+                                uint32_t *val, uint32_t dev_value,
+                                uint32_t valid_mask)
+{
+    XenPTRegInfo *reg = cfg_entry->reg;
+    XenPTRegion *base = NULL;
+    PCIDevice *d = &s->dev;
+    const PCIIORegion *r;
+    uint32_t writable_mask = 0;
+    uint32_t throughable_mask = 0;
+    uint32_t bar_emu_mask = 0;
+    uint32_t bar_ro_mask = 0;
+    uint32_t r_size = 0;
+    int index = 0;
+
+    index = xen_pt_bar_offset_to_index(reg->offset);
+    if (index < 0 || index >= PCI_NUM_REGIONS) {
+        XEN_PT_ERR(d, "Internal error: Invalid BAR index [%d].\n", index);
+        return -1;
+    }
+
+    r = &d->io_regions[index];
+    base = &s->bases[index];
+    r_size = xen_pt_get_emul_size(base->bar_flag, r->size);
+
+    /* set emulate mask and read-only mask values depend on the BAR flag */
+    switch (s->bases[index].bar_flag) {
+    case XEN_PT_BAR_FLAG_MEM:
+        bar_emu_mask = XEN_PT_BAR_MEM_EMU_MASK;
+        if (!r_size) {
+            /* low 32 bits mask for 64 bit bars */
+            bar_ro_mask = XEN_PT_BAR_ALLF;
+        } else {
+            bar_ro_mask = XEN_PT_BAR_MEM_RO_MASK | (r_size - 1);
+        }
+        break;
+    case XEN_PT_BAR_FLAG_IO:
+        bar_emu_mask = XEN_PT_BAR_IO_EMU_MASK;
+        bar_ro_mask = XEN_PT_BAR_IO_RO_MASK | (r_size - 1);
+        break;
+    case XEN_PT_BAR_FLAG_UPPER:
+        bar_emu_mask = XEN_PT_BAR_ALLF;
+        bar_ro_mask = r_size ? r_size - 1 : 0;
+        break;
+    default:
+        break;
+    }
+
+    /* modify emulate register */
+    writable_mask = bar_emu_mask & ~bar_ro_mask & valid_mask;
+    cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask);
+
+    /* check whether we need to update the virtual region address or not */
+    switch (s->bases[index].bar_flag) {
+    case XEN_PT_BAR_FLAG_UPPER:
+    case XEN_PT_BAR_FLAG_MEM:
+        /* nothing to do */
+        break;
+    case XEN_PT_BAR_FLAG_IO:
+        /* nothing to do */
+        break;
+    default:
+        break;
+    }
+
+    /* create value for writing to I/O device register */
+    throughable_mask = ~bar_emu_mask & valid_mask;
+    *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
+
+    return 0;
+}
+
+/* write Exp ROM BAR */
+static int xen_pt_exp_rom_bar_reg_write(XenPCIPassthroughState *s,
+                                        XenPTReg *cfg_entry, uint32_t *val,
+                                        uint32_t dev_value, uint32_t valid_mask)
+{
+    XenPTRegInfo *reg = cfg_entry->reg;
+    XenPTRegion *base = NULL;
+    PCIDevice *d = (PCIDevice *)&s->dev;
+    uint32_t writable_mask = 0;
+    uint32_t throughable_mask = 0;
+    pcibus_t r_size = 0;
+    uint32_t bar_emu_mask = 0;
+    uint32_t bar_ro_mask = 0;
+
+    r_size = d->io_regions[PCI_ROM_SLOT].size;
+    base = &s->bases[PCI_ROM_SLOT];
+    /* align memory type resource size */
+    r_size = xen_pt_get_emul_size(base->bar_flag, r_size);
+
+    /* set emulate mask and read-only mask */
+    bar_emu_mask = reg->emu_mask;
+    bar_ro_mask = (reg->ro_mask | (r_size - 1)) & ~PCI_ROM_ADDRESS_ENABLE;
+
+    /* modify emulate register */
+    writable_mask = ~bar_ro_mask & valid_mask;
+    cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask);
+
+    /* create value for writing to I/O device register */
+    throughable_mask = ~bar_emu_mask & valid_mask;
+    *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
+
+    return 0;
+}
+
+/* Header Type0 reg static information table */
+static XenPTRegInfo xen_pt_emu_reg_header0[] = {
+    /* Vendor ID reg */
+    {
+        .offset     = PCI_VENDOR_ID,
+        .size       = 2,
+        .init_val   = 0x0000,
+        .ro_mask    = 0xFFFF,
+        .emu_mask   = 0xFFFF,
+        .init       = xen_pt_vendor_reg_init,
+        .u.w.read   = xen_pt_word_reg_read,
+        .u.w.write  = xen_pt_word_reg_write,
+    },
+    /* Device ID reg */
+    {
+        .offset     = PCI_DEVICE_ID,
+        .size       = 2,
+        .init_val   = 0x0000,
+        .ro_mask    = 0xFFFF,
+        .emu_mask   = 0xFFFF,
+        .init       = xen_pt_device_reg_init,
+        .u.w.read   = xen_pt_word_reg_read,
+        .u.w.write  = xen_pt_word_reg_write,
+    },
+    /* Command reg */
+    {
+        .offset     = PCI_COMMAND,
+        .size       = 2,
+        .init_val   = 0x0000,
+        .ro_mask    = 0xF880,
+        .emu_mask   = 0x0740,
+        .init       = xen_pt_common_reg_init,
+        .u.w.read   = xen_pt_cmd_reg_read,
+        .u.w.write  = xen_pt_cmd_reg_write,
+    },
+    /* Capabilities Pointer reg */
+    {
+        .offset     = PCI_CAPABILITY_LIST,
+        .size       = 1,
+        .init_val   = 0x00,
+        .ro_mask    = 0xFF,
+        .emu_mask   = 0xFF,
+        .init       = xen_pt_ptr_reg_init,
+        .u.b.read   = xen_pt_byte_reg_read,
+        .u.b.write  = xen_pt_byte_reg_write,
+    },
+    /* Status reg */
+    /* use emulated Cap Ptr value to initialize,
+     * so need to be declared after Cap Ptr reg
+     */
+    {
+        .offset     = PCI_STATUS,
+        .size       = 2,
+        .init_val   = 0x0000,
+        .ro_mask    = 0x06FF,
+        .emu_mask   = 0x0010,
+        .init       = xen_pt_status_reg_init,
+        .u.w.read   = xen_pt_word_reg_read,
+        .u.w.write  = xen_pt_word_reg_write,
+    },
+    /* Cache Line Size reg */
+    {
+        .offset     = PCI_CACHE_LINE_SIZE,
+        .size       = 1,
+        .init_val   = 0x00,
+        .ro_mask    = 0x00,
+        .emu_mask   = 0xFF,
+        .init       = xen_pt_common_reg_init,
+        .u.b.read   = xen_pt_byte_reg_read,
+        .u.b.write  = xen_pt_byte_reg_write,
+    },
+    /* Latency Timer reg */
+    {
+        .offset     = PCI_LATENCY_TIMER,
+        .size       = 1,
+        .init_val   = 0x00,
+        .ro_mask    = 0x00,
+        .emu_mask   = 0xFF,
+        .init       = xen_pt_common_reg_init,
+        .u.b.read   = xen_pt_byte_reg_read,
+        .u.b.write  = xen_pt_byte_reg_write,
+    },
+    /* Header Type reg */
+    {
+        .offset     = PCI_HEADER_TYPE,
+        .size       = 1,
+        .init_val   = 0x00,
+        .ro_mask    = 0xFF,
+        .emu_mask   = 0x00,
+        .init       = xen_pt_header_type_reg_init,
+        .u.b.read   = xen_pt_byte_reg_read,
+        .u.b.write  = xen_pt_byte_reg_write,
+    },
+    /* Interrupt Line reg */
+    {
+        .offset     = PCI_INTERRUPT_LINE,
+        .size       = 1,
+        .init_val   = 0x00,
+        .ro_mask    = 0x00,
+        .emu_mask   = 0xFF,
+        .init       = xen_pt_common_reg_init,
+        .u.b.read   = xen_pt_byte_reg_read,
+        .u.b.write  = xen_pt_byte_reg_write,
+    },
+    /* Interrupt Pin reg */
+    {
+        .offset     = PCI_INTERRUPT_PIN,
+        .size       = 1,
+        .init_val   = 0x00,
+        .ro_mask    = 0xFF,
+        .emu_mask   = 0xFF,
+        .init       = xen_pt_irqpin_reg_init,
+        .u.b.read   = xen_pt_byte_reg_read,
+        .u.b.write  = xen_pt_byte_reg_write,
+    },
+    /* BAR 0 reg */
+    /* mask of BAR need to be decided later, depends on IO/MEM type */
+    {
+        .offset     = PCI_BASE_ADDRESS_0,
+        .size       = 4,
+        .init_val   = 0x00000000,
+        .init       = xen_pt_bar_reg_init,
+        .u.dw.read  = xen_pt_bar_reg_read,
+        .u.dw.write = xen_pt_bar_reg_write,
+    },
+    /* BAR 1 reg */
+    {
+        .offset     = PCI_BASE_ADDRESS_1,
+        .size       = 4,
+        .init_val   = 0x00000000,
+        .init       = xen_pt_bar_reg_init,
+        .u.dw.read  = xen_pt_bar_reg_read,
+        .u.dw.write = xen_pt_bar_reg_write,
+    },
+    /* BAR 2 reg */
+    {
+        .offset     = PCI_BASE_ADDRESS_2,
+        .size       = 4,
+        .init_val   = 0x00000000,
+        .init       = xen_pt_bar_reg_init,
+        .u.dw.read  = xen_pt_bar_reg_read,
+        .u.dw.write = xen_pt_bar_reg_write,
+    },
+    /* BAR 3 reg */
+    {
+        .offset     = PCI_BASE_ADDRESS_3,
+        .size       = 4,
+        .init_val   = 0x00000000,
+        .init       = xen_pt_bar_reg_init,
+        .u.dw.read  = xen_pt_bar_reg_read,
+        .u.dw.write = xen_pt_bar_reg_write,
+    },
+    /* BAR 4 reg */
+    {
+        .offset     = PCI_BASE_ADDRESS_4,
+        .size       = 4,
+        .init_val   = 0x00000000,
+        .init       = xen_pt_bar_reg_init,
+        .u.dw.read  = xen_pt_bar_reg_read,
+        .u.dw.write = xen_pt_bar_reg_write,
+    },
+    /* BAR 5 reg */
+    {
+        .offset     = PCI_BASE_ADDRESS_5,
+        .size       = 4,
+        .init_val   = 0x00000000,
+        .init       = xen_pt_bar_reg_init,
+        .u.dw.read  = xen_pt_bar_reg_read,
+        .u.dw.write = xen_pt_bar_reg_write,
+    },
+    /* Expansion ROM BAR reg */
+    {
+        .offset     = PCI_ROM_ADDRESS,
+        .size       = 4,
+        .init_val   = 0x00000000,
+        .ro_mask    = 0x000007FE,
+        .emu_mask   = 0xFFFFF800,
+        .init       = xen_pt_bar_reg_init,
+        .u.dw.read  = xen_pt_long_reg_read,
+        .u.dw.write = xen_pt_exp_rom_bar_reg_write,
+    },
+    {
+        .size = 0,
+    },
+};
+
+
+/*********************************
+ * Vital Product Data Capability
+ */
+
+/* Vital Product Data Capability Structure reg static information table */
+static XenPTRegInfo xen_pt_emu_reg_vpd[] = {
+    {
+        .offset     = PCI_CAP_LIST_NEXT,
+        .size       = 1,
+        .init_val   = 0x00,
+        .ro_mask    = 0xFF,
+        .emu_mask   = 0xFF,
+        .init       = xen_pt_ptr_reg_init,
+        .u.b.read   = xen_pt_byte_reg_read,
+        .u.b.write  = xen_pt_byte_reg_write,
+    },
+    {
+        .size = 0,
+    },
+};
+
+
+/**************************************
+ * Vendor Specific Capability
+ */
+
+/* Vendor Specific Capability Structure reg static information table */
+static XenPTRegInfo xen_pt_emu_reg_vendor[] = {
+    {
+        .offset     = PCI_CAP_LIST_NEXT,
+        .size       = 1,
+        .init_val   = 0x00,
+        .ro_mask    = 0xFF,
+        .emu_mask   = 0xFF,
+        .init       = xen_pt_ptr_reg_init,
+        .u.b.read   = xen_pt_byte_reg_read,
+        .u.b.write  = xen_pt_byte_reg_write,
+    },
+    {
+        .size = 0,
+    },
+};
+
+
+/*****************************
+ * PCI Express Capability
+ */
+
+static inline uint8_t get_capability_version(XenPCIPassthroughState *s,
+                                             uint32_t offset)
+{
+    uint8_t flags = pci_get_byte(s->dev.config + offset + PCI_EXP_FLAGS);
+    return flags & PCI_EXP_FLAGS_VERS;
+}
+
+static inline uint8_t get_device_type(XenPCIPassthroughState *s,
+                                      uint32_t offset)
+{
+    uint8_t flags = pci_get_byte(s->dev.config + offset + PCI_EXP_FLAGS);
+    return (flags & PCI_EXP_FLAGS_TYPE) >> 4;
+}
+
+/* initialize Link Control register */
+static int xen_pt_linkctrl_reg_init(XenPCIPassthroughState *s,
+                                    XenPTRegInfo *reg, uint32_t real_offset,
+                                    uint32_t *data)
+{
+    uint8_t cap_ver = get_capability_version(s, real_offset - reg->offset);
+    uint8_t dev_type = get_device_type(s, real_offset - reg->offset);
+
+    /* no need to initialize in case of Root Complex Integrated Endpoint
+     * with cap_ver 1.x
+     */
+    if ((dev_type == PCI_EXP_TYPE_RC_END) && (cap_ver == 1)) {
+        *data = XEN_PT_INVALID_REG;
+    }
+
+    *data = reg->init_val;
+    return 0;
+}
+/* initialize Device Control 2 register */
+static int xen_pt_devctrl2_reg_init(XenPCIPassthroughState *s,
+                                    XenPTRegInfo *reg, uint32_t real_offset,
+                                    uint32_t *data)
+{
+    uint8_t cap_ver = get_capability_version(s, real_offset - reg->offset);
+
+    /* no need to initialize in case of cap_ver 1.x */
+    if (cap_ver == 1) {
+        *data = XEN_PT_INVALID_REG;
+    }
+
+    *data = reg->init_val;
+    return 0;
+}
+/* initialize Link Control 2 register */
+static int xen_pt_linkctrl2_reg_init(XenPCIPassthroughState *s,
+                                     XenPTRegInfo *reg, uint32_t real_offset,
+                                     uint32_t *data)
+{
+    uint8_t cap_ver = get_capability_version(s, real_offset - reg->offset);
+    uint32_t reg_field = 0;
+
+    /* no need to initialize in case of cap_ver 1.x */
+    if (cap_ver == 1) {
+        reg_field = XEN_PT_INVALID_REG;
+    } else {
+        /* set Supported Link Speed */
+        uint8_t lnkcap = pci_get_byte(s->dev.config + real_offset - reg->offset
+                                      + PCI_EXP_LNKCAP);
+        reg_field |= PCI_EXP_LNKCAP_SLS & lnkcap;
+    }
+
+    *data = reg_field;
+    return 0;
+}
+
+/* PCI Express Capability Structure reg static information table */
+static XenPTRegInfo xen_pt_emu_reg_pcie[] = {
+    /* Next Pointer reg */
+    {
+        .offset     = PCI_CAP_LIST_NEXT,
+        .size       = 1,
+        .init_val   = 0x00,
+        .ro_mask    = 0xFF,
+        .emu_mask   = 0xFF,
+        .init       = xen_pt_ptr_reg_init,
+        .u.b.read   = xen_pt_byte_reg_read,
+        .u.b.write  = xen_pt_byte_reg_write,
+    },
+    /* Device Capabilities reg */
+    {
+        .offset     = PCI_EXP_DEVCAP,
+        .size       = 4,
+        .init_val   = 0x00000000,
+        .ro_mask    = 0x1FFCFFFF,
+        .emu_mask   = 0x10000000,
+        .init       = xen_pt_common_reg_init,
+        .u.dw.read  = xen_pt_long_reg_read,
+        .u.dw.write = xen_pt_long_reg_write,
+    },
+    /* Device Control reg */
+    {
+        .offset     = PCI_EXP_DEVCTL,
+        .size       = 2,
+        .init_val   = 0x2810,
+        .ro_mask    = 0x8400,
+        .emu_mask   = 0xFFFF,
+        .init       = xen_pt_common_reg_init,
+        .u.w.read   = xen_pt_word_reg_read,
+        .u.w.write  = xen_pt_word_reg_write,
+    },
+    /* Link Control reg */
+    {
+        .offset     = PCI_EXP_LNKCTL,
+        .size       = 2,
+        .init_val   = 0x0000,
+        .ro_mask    = 0xFC34,
+        .emu_mask   = 0xFFFF,
+        .init       = xen_pt_linkctrl_reg_init,
+        .u.w.read   = xen_pt_word_reg_read,
+        .u.w.write  = xen_pt_word_reg_write,
+    },
+    /* Device Control 2 reg */
+    {
+        .offset     = 0x28,
+        .size       = 2,
+        .init_val   = 0x0000,
+        .ro_mask    = 0xFFE0,
+        .emu_mask   = 0xFFFF,
+        .init       = xen_pt_devctrl2_reg_init,
+        .u.w.read   = xen_pt_word_reg_read,
+        .u.w.write  = xen_pt_word_reg_write,
+    },
+    /* Link Control 2 reg */
+    {
+        .offset     = 0x30,
+        .size       = 2,
+        .init_val   = 0x0000,
+        .ro_mask    = 0xE040,
+        .emu_mask   = 0xFFFF,
+        .init       = xen_pt_linkctrl2_reg_init,
+        .u.w.read   = xen_pt_word_reg_read,
+        .u.w.write  = xen_pt_word_reg_write,
+    },
+    {
+        .size = 0,
+    },
+};
+
+
+/*********************************
+ * Power Management Capability
+ */
+
+/* read Power Management Control/Status register */
+static int xen_pt_pmcsr_reg_read(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
+                                 uint16_t *value, uint16_t valid_mask)
+{
+    XenPTRegInfo *reg = cfg_entry->reg;
+    uint16_t valid_emu_mask = reg->emu_mask;
+
+    valid_emu_mask |= PCI_PM_CTRL_STATE_MASK | PCI_PM_CTRL_NO_SOFT_RESET;
+
+    valid_emu_mask = valid_emu_mask & valid_mask;
+    *value = XEN_PT_MERGE_VALUE(*value, cfg_entry->data, ~valid_emu_mask);
+
+    return 0;
+}
+/* write Power Management Control/Status register */
+static int xen_pt_pmcsr_reg_write(XenPCIPassthroughState *s,
+                                  XenPTReg *cfg_entry, uint16_t *val,
+                                  uint16_t dev_value, uint16_t valid_mask)
+{
+    XenPTRegInfo *reg = cfg_entry->reg;
+    uint16_t emu_mask = reg->emu_mask;
+    uint16_t writable_mask = 0;
+    uint16_t throughable_mask = 0;
+
+    emu_mask |= PCI_PM_CTRL_STATE_MASK | PCI_PM_CTRL_NO_SOFT_RESET;
+
+    /* modify emulate register */
+    writable_mask = emu_mask & ~reg->ro_mask & valid_mask;
+    cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask);
+
+    /* create value for writing to I/O device register */
+    throughable_mask = ~emu_mask & valid_mask;
+    *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
+
+    return 0;
+}
+
+/* Power Management Capability reg static information table */
+static XenPTRegInfo xen_pt_emu_reg_pm[] = {
+    /* Next Pointer reg */
+    {
+        .offset     = PCI_CAP_LIST_NEXT,
+        .size       = 1,
+        .init_val   = 0x00,
+        .ro_mask    = 0xFF,
+        .emu_mask   = 0xFF,
+        .init       = xen_pt_ptr_reg_init,
+        .u.b.read   = xen_pt_byte_reg_read,
+        .u.b.write  = xen_pt_byte_reg_write,
+    },
+    /* Power Management Capabilities reg */
+    {
+        .offset     = PCI_CAP_FLAGS,
+        .size       = 2,
+        .init_val   = 0x0000,
+        .ro_mask    = 0xFFFF,
+        .emu_mask   = 0xF9C8,
+        .init       = xen_pt_common_reg_init,
+        .u.w.read   = xen_pt_word_reg_read,
+        .u.w.write  = xen_pt_word_reg_write,
+    },
+    /* PCI Power Management Control/Status reg */
+    {
+        .offset     = PCI_PM_CTRL,
+        .size       = 2,
+        .init_val   = 0x0008,
+        .ro_mask    = 0xE1FC,
+        .emu_mask   = 0x8100,
+        .init       = xen_pt_common_reg_init,
+        .u.w.read   = xen_pt_pmcsr_reg_read,
+        .u.w.write  = xen_pt_pmcsr_reg_write,
+    },
+    {
+        .size = 0,
+    },
+};
+
+
+/********************************
+ * MSI Capability
+ */
+
+/* Helper */
+static bool xen_pt_msgdata_check_type(uint32_t offset, uint16_t flags)
+{
+    /* check the offset whether matches the type or not */
+    bool is_32 = (offset == PCI_MSI_DATA_32) && !(flags & PCI_MSI_FLAGS_64BIT);
+    bool is_64 = (offset == PCI_MSI_DATA_64) &&  (flags & PCI_MSI_FLAGS_64BIT);
+    return is_32 || is_64;
+}
+
+/* Message Control register */
+static int xen_pt_msgctrl_reg_init(XenPCIPassthroughState *s,
+                                   XenPTRegInfo *reg, uint32_t real_offset,
+                                   uint32_t *data)
+{
+    PCIDevice *d = &s->dev;
+    XenPTMSI *msi = s->msi;
+    uint16_t reg_field = 0;
+
+    /* use I/O device register's value as initial value */
+    reg_field = pci_get_word(d->config + real_offset);
+
+    if (reg_field & PCI_MSI_FLAGS_ENABLE) {
+        XEN_PT_LOG(&s->dev, "MSI already enabled, disabling it first\n");
+        xen_host_pci_set_word(&s->real_device, real_offset,
+                              reg_field & ~PCI_MSI_FLAGS_ENABLE);
+    }
+    msi->flags |= reg_field;
+    msi->ctrl_offset = real_offset;
+    msi->initialized = false;
+    msi->mapped = false;
+
+    *data = reg->init_val;
+    return 0;
+}
+static int xen_pt_msgctrl_reg_write(XenPCIPassthroughState *s,
+                                    XenPTReg *cfg_entry, uint16_t *val,
+                                    uint16_t dev_value, uint16_t valid_mask)
+{
+    XenPTRegInfo *reg = cfg_entry->reg;
+    XenPTMSI *msi = s->msi;
+    uint16_t writable_mask = 0;
+    uint16_t throughable_mask = 0;
+    uint16_t raw_val;
+
+    /* Currently no support for multi-vector */
+    if (*val & PCI_MSI_FLAGS_QSIZE) {
+        XEN_PT_WARN(&s->dev, "Tries to set more than 1 vector ctrl %x\n", *val);
+    }
+
+    /* modify emulate register */
+    writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
+    cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask);
+    msi->flags |= cfg_entry->data & ~PCI_MSI_FLAGS_ENABLE;
+
+    /* create value for writing to I/O device register */
+    raw_val = *val;
+    throughable_mask = ~reg->emu_mask & valid_mask;
+    *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
+
+    /* update MSI */
+    if (raw_val & PCI_MSI_FLAGS_ENABLE) {
+        /* setup MSI pirq for the first time */
+        if (!msi->initialized) {
+            /* Init physical one */
+            XEN_PT_LOG(&s->dev, "setup MSI\n");
+            if (xen_pt_msi_setup(s)) {
+                /* We do not broadcast the error to the framework code, so
+                 * that MSI errors are contained in MSI emulation code and
+                 * QEMU can go on running.
+                 * Guest MSI would be actually not working.
+                 */
+                *val &= ~PCI_MSI_FLAGS_ENABLE;
+                XEN_PT_WARN(&s->dev, "Can not map MSI.\n");
+                return 0;
+            }
+            if (xen_pt_msi_update(s)) {
+                *val &= ~PCI_MSI_FLAGS_ENABLE;
+                XEN_PT_WARN(&s->dev, "Can not bind MSI\n");
+                return 0;
+            }
+            msi->initialized = true;
+            msi->mapped = true;
+        }
+        msi->flags |= PCI_MSI_FLAGS_ENABLE;
+    } else {
+        msi->flags &= ~PCI_MSI_FLAGS_ENABLE;
+    }
+
+    /* pass through MSI_ENABLE bit */
+    *val &= ~PCI_MSI_FLAGS_ENABLE;
+    *val |= raw_val & PCI_MSI_FLAGS_ENABLE;
+
+    return 0;
+}
+
+/* initialize Message Upper Address register */
+static int xen_pt_msgaddr64_reg_init(XenPCIPassthroughState *s,
+                                     XenPTRegInfo *reg, uint32_t real_offset,
+                                     uint32_t *data)
+{
+    /* no need to initialize in case of 32 bit type */
+    if (!(s->msi->flags & PCI_MSI_FLAGS_64BIT)) {
+        *data = XEN_PT_INVALID_REG;
+    } else {
+        *data = reg->init_val;
+    }
+
+    return 0;
+}
+/* this function will be called twice (for 32 bit and 64 bit type) */
+/* initialize Message Data register */
+static int xen_pt_msgdata_reg_init(XenPCIPassthroughState *s,
+                                   XenPTRegInfo *reg, uint32_t real_offset,
+                                   uint32_t *data)
+{
+    uint32_t flags = s->msi->flags;
+    uint32_t offset = reg->offset;
+
+    /* check the offset whether matches the type or not */
+    if (xen_pt_msgdata_check_type(offset, flags)) {
+        *data = reg->init_val;
+    } else {
+        *data = XEN_PT_INVALID_REG;
+    }
+    return 0;
+}
+
+/* write Message Address register */
+static int xen_pt_msgaddr32_reg_write(XenPCIPassthroughState *s,
+                                      XenPTReg *cfg_entry, uint32_t *val,
+                                      uint32_t dev_value, uint32_t valid_mask)
+{
+    XenPTRegInfo *reg = cfg_entry->reg;
+    uint32_t writable_mask = 0;
+    uint32_t throughable_mask = 0;
+    uint32_t old_addr = cfg_entry->data;
+
+    /* modify emulate register */
+    writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
+    cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask);
+    s->msi->addr_lo = cfg_entry->data;
+
+    /* create value for writing to I/O device register */
+    throughable_mask = ~reg->emu_mask & valid_mask;
+    *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
+
+    /* update MSI */
+    if (cfg_entry->data != old_addr) {
+        if (s->msi->mapped) {
+            xen_pt_msi_update(s);
+        }
+    }
+
+    return 0;
+}
+/* write Message Upper Address register */
+static int xen_pt_msgaddr64_reg_write(XenPCIPassthroughState *s,
+                                      XenPTReg *cfg_entry, uint32_t *val,
+                                      uint32_t dev_value, uint32_t valid_mask)
+{
+    XenPTRegInfo *reg = cfg_entry->reg;
+    uint32_t writable_mask = 0;
+    uint32_t throughable_mask = 0;
+    uint32_t old_addr = cfg_entry->data;
+
+    /* check whether the type is 64 bit or not */
+    if (!(s->msi->flags & PCI_MSI_FLAGS_64BIT)) {
+        XEN_PT_ERR(&s->dev,
+                   "Can't write to the upper address without 64 bit support\n");
+        return -1;
+    }
+
+    /* modify emulate register */
+    writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
+    cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask);
+    /* update the msi_info too */
+    s->msi->addr_hi = cfg_entry->data;
+
+    /* create value for writing to I/O device register */
+    throughable_mask = ~reg->emu_mask & valid_mask;
+    *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
+
+    /* update MSI */
+    if (cfg_entry->data != old_addr) {
+        if (s->msi->mapped) {
+            xen_pt_msi_update(s);
+        }
+    }
+
+    return 0;
+}
+
+
+/* this function will be called twice (for 32 bit and 64 bit type) */
+/* write Message Data register */
+static int xen_pt_msgdata_reg_write(XenPCIPassthroughState *s,
+                                    XenPTReg *cfg_entry, uint16_t *val,
+                                    uint16_t dev_value, uint16_t valid_mask)
+{
+    XenPTRegInfo *reg = cfg_entry->reg;
+    XenPTMSI *msi = s->msi;
+    uint16_t writable_mask = 0;
+    uint16_t throughable_mask = 0;
+    uint16_t old_data = cfg_entry->data;
+    uint32_t offset = reg->offset;
+
+    /* check the offset whether matches the type or not */
+    if (!xen_pt_msgdata_check_type(offset, msi->flags)) {
+        /* exit I/O emulator */
+        XEN_PT_ERR(&s->dev, "the offset does not match the 32/64 bit type!\n");
+        return -1;
+    }
+
+    /* modify emulate register */
+    writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
+    cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask);
+    /* update the msi_info too */
+    msi->data = cfg_entry->data;
+
+    /* create value for writing to I/O device register */
+    throughable_mask = ~reg->emu_mask & valid_mask;
+    *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
+
+    /* update MSI */
+    if (cfg_entry->data != old_data) {
+        if (msi->mapped) {
+            xen_pt_msi_update(s);
+        }
+    }
+
+    return 0;
+}
+
+/* MSI Capability Structure reg static information table */
+static XenPTRegInfo xen_pt_emu_reg_msi[] = {
+    /* Next Pointer reg */
+    {
+        .offset     = PCI_CAP_LIST_NEXT,
+        .size       = 1,
+        .init_val   = 0x00,
+        .ro_mask    = 0xFF,
+        .emu_mask   = 0xFF,
+        .init       = xen_pt_ptr_reg_init,
+        .u.b.read   = xen_pt_byte_reg_read,
+        .u.b.write  = xen_pt_byte_reg_write,
+    },
+    /* Message Control reg */
+    {
+        .offset     = PCI_MSI_FLAGS,
+        .size       = 2,
+        .init_val   = 0x0000,
+        .ro_mask    = 0xFF8E,
+        .emu_mask   = 0x007F,
+        .init       = xen_pt_msgctrl_reg_init,
+        .u.w.read   = xen_pt_word_reg_read,
+        .u.w.write  = xen_pt_msgctrl_reg_write,
+    },
+    /* Message Address reg */
+    {
+        .offset     = PCI_MSI_ADDRESS_LO,
+        .size       = 4,
+        .init_val   = 0x00000000,
+        .ro_mask    = 0x00000003,
+        .emu_mask   = 0xFFFFFFFF,
+        .no_wb      = 1,
+        .init       = xen_pt_common_reg_init,
+        .u.dw.read  = xen_pt_long_reg_read,
+        .u.dw.write = xen_pt_msgaddr32_reg_write,
+    },
+    /* Message Upper Address reg (if PCI_MSI_FLAGS_64BIT set) */
+    {
+        .offset     = PCI_MSI_ADDRESS_HI,
+        .size       = 4,
+        .init_val   = 0x00000000,
+        .ro_mask    = 0x00000000,
+        .emu_mask   = 0xFFFFFFFF,
+        .no_wb      = 1,
+        .init       = xen_pt_msgaddr64_reg_init,
+        .u.dw.read  = xen_pt_long_reg_read,
+        .u.dw.write = xen_pt_msgaddr64_reg_write,
+    },
+    /* Message Data reg (16 bits of data for 32-bit devices) */
+    {
+        .offset     = PCI_MSI_DATA_32,
+        .size       = 2,
+        .init_val   = 0x0000,
+        .ro_mask    = 0x0000,
+        .emu_mask   = 0xFFFF,
+        .no_wb      = 1,
+        .init       = xen_pt_msgdata_reg_init,
+        .u.w.read   = xen_pt_word_reg_read,
+        .u.w.write  = xen_pt_msgdata_reg_write,
+    },
+    /* Message Data reg (16 bits of data for 64-bit devices) */
+    {
+        .offset     = PCI_MSI_DATA_64,
+        .size       = 2,
+        .init_val   = 0x0000,
+        .ro_mask    = 0x0000,
+        .emu_mask   = 0xFFFF,
+        .no_wb      = 1,
+        .init       = xen_pt_msgdata_reg_init,
+        .u.w.read   = xen_pt_word_reg_read,
+        .u.w.write  = xen_pt_msgdata_reg_write,
+    },
+    {
+        .size = 0,
+    },
+};
+
+
+/**************************************
+ * MSI-X Capability
+ */
+
+/* Message Control register for MSI-X */
+static int xen_pt_msixctrl_reg_init(XenPCIPassthroughState *s,
+                                    XenPTRegInfo *reg, uint32_t real_offset,
+                                    uint32_t *data)
+{
+    PCIDevice *d = &s->dev;
+    uint16_t reg_field = 0;
+
+    /* use I/O device register's value as initial value */
+    reg_field = pci_get_word(d->config + real_offset);
+
+    if (reg_field & PCI_MSIX_FLAGS_ENABLE) {
+        XEN_PT_LOG(d, "MSIX already enabled, disabling it first\n");
+        xen_host_pci_set_word(&s->real_device, real_offset,
+                              reg_field & ~PCI_MSIX_FLAGS_ENABLE);
+    }
+
+    s->msix->ctrl_offset = real_offset;
+
+    *data = reg->init_val;
+    return 0;
+}
+static int xen_pt_msixctrl_reg_write(XenPCIPassthroughState *s,
+                                     XenPTReg *cfg_entry, uint16_t *val,
+                                     uint16_t dev_value, uint16_t valid_mask)
+{
+    XenPTRegInfo *reg = cfg_entry->reg;
+    uint16_t writable_mask = 0;
+    uint16_t throughable_mask = 0;
+    int debug_msix_enabled_old;
+
+    /* modify emulate register */
+    writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
+    cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask);
+
+    /* create value for writing to I/O device register */
+    throughable_mask = ~reg->emu_mask & valid_mask;
+    *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
+
+    /* update MSI-X */
+    if ((*val & PCI_MSIX_FLAGS_ENABLE)
+        && !(*val & PCI_MSIX_FLAGS_MASKALL)) {
+        xen_pt_msix_update(s);
+    }
+
+    debug_msix_enabled_old = s->msix->enabled;
+    s->msix->enabled = !!(*val & PCI_MSIX_FLAGS_ENABLE);
+    if (s->msix->enabled != debug_msix_enabled_old) {
+        XEN_PT_LOG(&s->dev, "%s MSI-X\n",
+                   s->msix->enabled ? "enable" : "disable");
+    }
+
+    return 0;
+}
+
+/* MSI-X Capability Structure reg static information table */
+static XenPTRegInfo xen_pt_emu_reg_msix[] = {
+    /* Next Pointer reg */
+    {
+        .offset     = PCI_CAP_LIST_NEXT,
+        .size       = 1,
+        .init_val   = 0x00,
+        .ro_mask    = 0xFF,
+        .emu_mask   = 0xFF,
+        .init       = xen_pt_ptr_reg_init,
+        .u.b.read   = xen_pt_byte_reg_read,
+        .u.b.write  = xen_pt_byte_reg_write,
+    },
+    /* Message Control reg */
+    {
+        .offset     = PCI_MSI_FLAGS,
+        .size       = 2,
+        .init_val   = 0x0000,
+        .ro_mask    = 0x3FFF,
+        .emu_mask   = 0x0000,
+        .init       = xen_pt_msixctrl_reg_init,
+        .u.w.read   = xen_pt_word_reg_read,
+        .u.w.write  = xen_pt_msixctrl_reg_write,
+    },
+    {
+        .size = 0,
+    },
+};
+
+
+/****************************
+ * Capabilities
+ */
+
+/* capability structure register group size functions */
+
+static int xen_pt_reg_grp_size_init(XenPCIPassthroughState *s,
+                                    const XenPTRegGroupInfo *grp_reg,
+                                    uint32_t base_offset, uint8_t *size)
+{
+    *size = grp_reg->grp_size;
+    return 0;
+}
+/* get Vendor Specific Capability Structure register group size */
+static int xen_pt_vendor_size_init(XenPCIPassthroughState *s,
+                                   const XenPTRegGroupInfo *grp_reg,
+                                   uint32_t base_offset, uint8_t *size)
+{
+    *size = pci_get_byte(s->dev.config + base_offset + 0x02);
+    return 0;
+}
+/* get PCI Express Capability Structure register group size */
+static int xen_pt_pcie_size_init(XenPCIPassthroughState *s,
+                                 const XenPTRegGroupInfo *grp_reg,
+                                 uint32_t base_offset, uint8_t *size)
+{
+    PCIDevice *d = &s->dev;
+    uint8_t version = get_capability_version(s, base_offset);
+    uint8_t type = get_device_type(s, base_offset);
+    uint8_t pcie_size = 0;
+
+
+    /* calculate size depend on capability version and device/port type */
+    /* in case of PCI Express Base Specification Rev 1.x */
+    if (version == 1) {
+        /* The PCI Express Capabilities, Device Capabilities, and Device
+         * Status/Control registers are required for all PCI Express devices.
+         * The Link Capabilities and Link Status/Control are required for all
+         * Endpoints that are not Root Complex Integrated Endpoints. Endpoints
+         * are not required to implement registers other than those listed
+         * above and terminate the capability structure.
+         */
+        switch (type) {
+        case PCI_EXP_TYPE_ENDPOINT:
+        case PCI_EXP_TYPE_LEG_END:
+            pcie_size = 0x14;
+            break;
+        case PCI_EXP_TYPE_RC_END:
+            /* has no link */
+            pcie_size = 0x0C;
+            break;
+            /* only EndPoint passthrough is supported */
+        case PCI_EXP_TYPE_ROOT_PORT:
+        case PCI_EXP_TYPE_UPSTREAM:
+        case PCI_EXP_TYPE_DOWNSTREAM:
+        case PCI_EXP_TYPE_PCI_BRIDGE:
+        case PCI_EXP_TYPE_PCIE_BRIDGE:
+        case PCI_EXP_TYPE_RC_EC:
+        default:
+            XEN_PT_ERR(d, "Unsupported device/port type %#x.\n", type);
+            return -1;
+        }
+    }
+    /* in case of PCI Express Base Specification Rev 2.0 */
+    else if (version == 2) {
+        switch (type) {
+        case PCI_EXP_TYPE_ENDPOINT:
+        case PCI_EXP_TYPE_LEG_END:
+        case PCI_EXP_TYPE_RC_END:
+            /* For Functions that do not implement the registers,
+             * these spaces must be hardwired to 0b.
+             */
+            pcie_size = 0x3C;
+            break;
+            /* only EndPoint passthrough is supported */
+        case PCI_EXP_TYPE_ROOT_PORT:
+        case PCI_EXP_TYPE_UPSTREAM:
+        case PCI_EXP_TYPE_DOWNSTREAM:
+        case PCI_EXP_TYPE_PCI_BRIDGE:
+        case PCI_EXP_TYPE_PCIE_BRIDGE:
+        case PCI_EXP_TYPE_RC_EC:
+        default:
+            XEN_PT_ERR(d, "Unsupported device/port type %#x.\n", type);
+            return -1;
+        }
+    } else {
+        XEN_PT_ERR(d, "Unsupported capability version %#x.\n", version);
+        return -1;
+    }
+
+    *size = pcie_size;
+    return 0;
+}
+/* get MSI Capability Structure register group size */
+static int xen_pt_msi_size_init(XenPCIPassthroughState *s,
+                                const XenPTRegGroupInfo *grp_reg,
+                                uint32_t base_offset, uint8_t *size)
+{
+    PCIDevice *d = &s->dev;
+    uint16_t msg_ctrl = 0;
+    uint8_t msi_size = 0xa;
+
+    msg_ctrl = pci_get_word(d->config + (base_offset + PCI_MSI_FLAGS));
+
+    /* check if 64-bit address is capable of per-vector masking */
+    if (msg_ctrl & PCI_MSI_FLAGS_64BIT) {
+        msi_size += 4;
+    }
+    if (msg_ctrl & PCI_MSI_FLAGS_MASKBIT) {
+        msi_size += 10;
+    }
+
+    s->msi = g_new0(XenPTMSI, 1);
+    s->msi->pirq = XEN_PT_UNASSIGNED_PIRQ;
+
+    *size = msi_size;
+    return 0;
+}
+/* get MSI-X Capability Structure register group size */
+static int xen_pt_msix_size_init(XenPCIPassthroughState *s,
+                                 const XenPTRegGroupInfo *grp_reg,
+                                 uint32_t base_offset, uint8_t *size)
+{
+    int rc = 0;
+
+    rc = xen_pt_msix_init(s, base_offset);
+
+    if (rc < 0) {
+        XEN_PT_ERR(&s->dev, "Internal error: Invalid xen_pt_msix_init.\n");
+        return rc;
+    }
+
+    *size = grp_reg->grp_size;
+    return 0;
+}
+
+
+static const XenPTRegGroupInfo xen_pt_emu_reg_grps[] = {
+    /* Header Type0 reg group */
+    {
+        .grp_id      = 0xFF,
+        .grp_type    = XEN_PT_GRP_TYPE_EMU,
+        .grp_size    = 0x40,
+        .size_init   = xen_pt_reg_grp_size_init,
+        .emu_regs = xen_pt_emu_reg_header0,
+    },
+    /* PCI PowerManagement Capability reg group */
+    {
+        .grp_id      = PCI_CAP_ID_PM,
+        .grp_type    = XEN_PT_GRP_TYPE_EMU,
+        .grp_size    = PCI_PM_SIZEOF,
+        .size_init   = xen_pt_reg_grp_size_init,
+        .emu_regs = xen_pt_emu_reg_pm,
+    },
+    /* AGP Capability Structure reg group */
+    {
+        .grp_id     = PCI_CAP_ID_AGP,
+        .grp_type   = XEN_PT_GRP_TYPE_HARDWIRED,
+        .grp_size   = 0x30,
+        .size_init  = xen_pt_reg_grp_size_init,
+    },
+    /* Vital Product Data Capability Structure reg group */
+    {
+        .grp_id      = PCI_CAP_ID_VPD,
+        .grp_type    = XEN_PT_GRP_TYPE_EMU,
+        .grp_size    = 0x08,
+        .size_init   = xen_pt_reg_grp_size_init,
+        .emu_regs = xen_pt_emu_reg_vpd,
+    },
+    /* Slot Identification reg group */
+    {
+        .grp_id     = PCI_CAP_ID_SLOTID,
+        .grp_type   = XEN_PT_GRP_TYPE_HARDWIRED,
+        .grp_size   = 0x04,
+        .size_init  = xen_pt_reg_grp_size_init,
+    },
+    /* MSI Capability Structure reg group */
+    {
+        .grp_id      = PCI_CAP_ID_MSI,
+        .grp_type    = XEN_PT_GRP_TYPE_EMU,
+        .grp_size    = 0xFF,
+        .size_init   = xen_pt_msi_size_init,
+        .emu_regs = xen_pt_emu_reg_msi,
+    },
+    /* PCI-X Capabilities List Item reg group */
+    {
+        .grp_id     = PCI_CAP_ID_PCIX,
+        .grp_type   = XEN_PT_GRP_TYPE_HARDWIRED,
+        .grp_size   = 0x18,
+        .size_init  = xen_pt_reg_grp_size_init,
+    },
+    /* Vendor Specific Capability Structure reg group */
+    {
+        .grp_id      = PCI_CAP_ID_VNDR,
+        .grp_type    = XEN_PT_GRP_TYPE_EMU,
+        .grp_size    = 0xFF,
+        .size_init   = xen_pt_vendor_size_init,
+        .emu_regs = xen_pt_emu_reg_vendor,
+    },
+    /* SHPC Capability List Item reg group */
+    {
+        .grp_id     = PCI_CAP_ID_SHPC,
+        .grp_type   = XEN_PT_GRP_TYPE_HARDWIRED,
+        .grp_size   = 0x08,
+        .size_init  = xen_pt_reg_grp_size_init,
+    },
+    /* Subsystem ID and Subsystem Vendor ID Capability List Item reg group */
+    {
+        .grp_id     = PCI_CAP_ID_SSVID,
+        .grp_type   = XEN_PT_GRP_TYPE_HARDWIRED,
+        .grp_size   = 0x08,
+        .size_init  = xen_pt_reg_grp_size_init,
+    },
+    /* AGP 8x Capability Structure reg group */
+    {
+        .grp_id     = PCI_CAP_ID_AGP3,
+        .grp_type   = XEN_PT_GRP_TYPE_HARDWIRED,
+        .grp_size   = 0x30,
+        .size_init  = xen_pt_reg_grp_size_init,
+    },
+    /* PCI Express Capability Structure reg group */
+    {
+        .grp_id      = PCI_CAP_ID_EXP,
+        .grp_type    = XEN_PT_GRP_TYPE_EMU,
+        .grp_size    = 0xFF,
+        .size_init   = xen_pt_pcie_size_init,
+        .emu_regs = xen_pt_emu_reg_pcie,
+    },
+    /* MSI-X Capability Structure reg group */
+    {
+        .grp_id      = PCI_CAP_ID_MSIX,
+        .grp_type    = XEN_PT_GRP_TYPE_EMU,
+        .grp_size    = 0x0C,
+        .size_init   = xen_pt_msix_size_init,
+        .emu_regs = xen_pt_emu_reg_msix,
+    },
+    {
+        .grp_size = 0,
+    },
+};
+
+/* initialize Capabilities Pointer or Next Pointer register */
+static int xen_pt_ptr_reg_init(XenPCIPassthroughState *s,
+                               XenPTRegInfo *reg, uint32_t real_offset,
+                               uint32_t *data)
+{
+    int i;
+    uint8_t *config = s->dev.config;
+    uint32_t reg_field = pci_get_byte(config + real_offset);
+    uint8_t cap_id = 0;
+
+    /* find capability offset */
+    while (reg_field) {
+        for (i = 0; xen_pt_emu_reg_grps[i].grp_size != 0; i++) {
+            if (xen_pt_hide_dev_cap(&s->real_device,
+                                    xen_pt_emu_reg_grps[i].grp_id)) {
+                continue;
+            }
+
+            cap_id = pci_get_byte(config + reg_field + PCI_CAP_LIST_ID);
+            if (xen_pt_emu_reg_grps[i].grp_id == cap_id) {
+                if (xen_pt_emu_reg_grps[i].grp_type == XEN_PT_GRP_TYPE_EMU) {
+                    goto out;
+                }
+                /* ignore the 0 hardwired capability, find next one */
+                break;
+            }
+        }
+
+        /* next capability */
+        reg_field = pci_get_byte(config + reg_field + PCI_CAP_LIST_NEXT);
+    }
+
+out:
+    *data = reg_field;
+    return 0;
+}
+
+
+/*************
+ * Main
+ */
+
+static uint8_t find_cap_offset(XenPCIPassthroughState *s, uint8_t cap)
+{
+    uint8_t id;
+    unsigned max_cap = PCI_CAP_MAX;
+    uint8_t pos = PCI_CAPABILITY_LIST;
+    uint8_t status = 0;
+
+    if (xen_host_pci_get_byte(&s->real_device, PCI_STATUS, &status)) {
+        return 0;
+    }
+    if ((status & PCI_STATUS_CAP_LIST) == 0) {
+        return 0;
+    }
+
+    while (max_cap--) {
+        if (xen_host_pci_get_byte(&s->real_device, pos, &pos)) {
+            break;
+        }
+        if (pos < PCI_CONFIG_HEADER_SIZE) {
+            break;
+        }
+
+        pos &= ~3;
+        if (xen_host_pci_get_byte(&s->real_device,
+                                  pos + PCI_CAP_LIST_ID, &id)) {
+            break;
+        }
+
+        if (id == 0xff) {
+            break;
+        }
+        if (id == cap) {
+            return pos;
+        }
+
+        pos += PCI_CAP_LIST_NEXT;
+    }
+    return 0;
+}
+
+static int xen_pt_config_reg_init(XenPCIPassthroughState *s,
+                                  XenPTRegGroup *reg_grp, XenPTRegInfo *reg)
+{
+    XenPTReg *reg_entry;
+    uint32_t data = 0;
+    int rc = 0;
+
+    reg_entry = g_new0(XenPTReg, 1);
+    reg_entry->reg = reg;
+
+    if (reg->init) {
+        /* initialize emulate register */
+        rc = reg->init(s, reg_entry->reg,
+                       reg_grp->base_offset + reg->offset, &data);
+        if (rc < 0) {
+            free(reg_entry);
+            return rc;
+        }
+        if (data == XEN_PT_INVALID_REG) {
+            /* free unused BAR register entry */
+            free(reg_entry);
+            return 0;
+        }
+        /* set register value */
+        reg_entry->data = data;
+    }
+    /* list add register entry */
+    QLIST_INSERT_HEAD(&reg_grp->reg_tbl_list, reg_entry, entries);
+
+    return 0;
+}
+
+int xen_pt_config_init(XenPCIPassthroughState *s)
+{
+    int i, rc;
+
+    QLIST_INIT(&s->reg_grps);
+
+    for (i = 0; xen_pt_emu_reg_grps[i].grp_size != 0; i++) {
+        uint32_t reg_grp_offset = 0;
+        XenPTRegGroup *reg_grp_entry = NULL;
+
+        if (xen_pt_emu_reg_grps[i].grp_id != 0xFF) {
+            if (xen_pt_hide_dev_cap(&s->real_device,
+                                    xen_pt_emu_reg_grps[i].grp_id)) {
+                continue;
+            }
+
+            reg_grp_offset = find_cap_offset(s, xen_pt_emu_reg_grps[i].grp_id);
+
+            if (!reg_grp_offset) {
+                continue;
+            }
+        }
+
+        reg_grp_entry = g_new0(XenPTRegGroup, 1);
+        QLIST_INIT(&reg_grp_entry->reg_tbl_list);
+        QLIST_INSERT_HEAD(&s->reg_grps, reg_grp_entry, entries);
+
+        reg_grp_entry->base_offset = reg_grp_offset;
+        reg_grp_entry->reg_grp = xen_pt_emu_reg_grps + i;
+        if (xen_pt_emu_reg_grps[i].size_init) {
+            /* get register group size */
+            rc = xen_pt_emu_reg_grps[i].size_init(s, reg_grp_entry->reg_grp,
+                                                  reg_grp_offset,
+                                                  &reg_grp_entry->size);
+            if (rc < 0) {
+                xen_pt_config_delete(s);
+                return rc;
+            }
+        }
+
+        if (xen_pt_emu_reg_grps[i].grp_type == XEN_PT_GRP_TYPE_EMU) {
+            if (xen_pt_emu_reg_grps[i].emu_regs) {
+                int j = 0;
+                XenPTRegInfo *regs = xen_pt_emu_reg_grps[i].emu_regs;
+                /* initialize capability register */
+                for (j = 0; regs->size != 0; j++, regs++) {
+                    /* initialize capability register */
+                    rc = xen_pt_config_reg_init(s, reg_grp_entry, regs);
+                    if (rc < 0) {
+                        xen_pt_config_delete(s);
+                        return rc;
+                    }
+                }
+            }
+        }
+    }
+
+    return 0;
+}
+
+/* delete all emulate register */
+void xen_pt_config_delete(XenPCIPassthroughState *s)
+{
+    struct XenPTRegGroup *reg_group, *next_grp;
+    struct XenPTReg *reg, *next_reg;
+
+    /* free MSI/MSI-X info table */
+    if (s->msix) {
+        xen_pt_msix_delete(s);
+    }
+    if (s->msi) {
+        g_free(s->msi);
+    }
+
+    /* free all register group entry */
+    QLIST_FOREACH_SAFE(reg_group, &s->reg_grps, entries, next_grp) {
+        /* free all register entry */
+        QLIST_FOREACH_SAFE(reg, &reg_group->reg_tbl_list, entries, next_reg) {
+            QLIST_REMOVE(reg, entries);
+            g_free(reg);
+        }
+
+        QLIST_REMOVE(reg_group, entries);
+        g_free(reg_group);
+    }
+}
diff --git a/hw/xen/xen_pt_msi.c b/hw/xen/xen_pt_msi.c
new file mode 100644 (file)
index 0000000..db2c842
--- /dev/null
@@ -0,0 +1,620 @@
+/*
+ * Copyright (c) 2007, Intel Corporation.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ * Jiang Yunhong <yunhong.jiang@intel.com>
+ *
+ * This file implements direct PCI assignment to a HVM guest
+ */
+
+#include <sys/mman.h>
+
+#include "hw/xen/xen_backend.h"
+#include "xen_pt.h"
+#include "hw/i386/apic-msidef.h"
+
+
+#define XEN_PT_AUTO_ASSIGN -1
+
+/* shift count for gflags */
+#define XEN_PT_GFLAGS_SHIFT_DEST_ID        0
+#define XEN_PT_GFLAGS_SHIFT_RH             8
+#define XEN_PT_GFLAGS_SHIFT_DM             9
+#define XEN_PT_GFLAGSSHIFT_DELIV_MODE     12
+#define XEN_PT_GFLAGSSHIFT_TRG_MODE       15
+
+
+/*
+ * Helpers
+ */
+
+static inline uint8_t msi_vector(uint32_t data)
+{
+    return (data & MSI_DATA_VECTOR_MASK) >> MSI_DATA_VECTOR_SHIFT;
+}
+
+static inline uint8_t msi_dest_id(uint32_t addr)
+{
+    return (addr & MSI_ADDR_DEST_ID_MASK) >> MSI_ADDR_DEST_ID_SHIFT;
+}
+
+static inline uint32_t msi_ext_dest_id(uint32_t addr_hi)
+{
+    return addr_hi & 0xffffff00;
+}
+
+static uint32_t msi_gflags(uint32_t data, uint64_t addr)
+{
+    uint32_t result = 0;
+    int rh, dm, dest_id, deliv_mode, trig_mode;
+
+    rh = (addr >> MSI_ADDR_REDIRECTION_SHIFT) & 0x1;
+    dm = (addr >> MSI_ADDR_DEST_MODE_SHIFT) & 0x1;
+    dest_id = msi_dest_id(addr);
+    deliv_mode = (data >> MSI_DATA_DELIVERY_MODE_SHIFT) & 0x7;
+    trig_mode = (data >> MSI_DATA_TRIGGER_SHIFT) & 0x1;
+
+    result = dest_id | (rh << XEN_PT_GFLAGS_SHIFT_RH)
+        | (dm << XEN_PT_GFLAGS_SHIFT_DM)
+        | (deliv_mode << XEN_PT_GFLAGSSHIFT_DELIV_MODE)
+        | (trig_mode << XEN_PT_GFLAGSSHIFT_TRG_MODE);
+
+    return result;
+}
+
+static inline uint64_t msi_addr64(XenPTMSI *msi)
+{
+    return (uint64_t)msi->addr_hi << 32 | msi->addr_lo;
+}
+
+static int msi_msix_enable(XenPCIPassthroughState *s,
+                           uint32_t address,
+                           uint16_t flag,
+                           bool enable)
+{
+    uint16_t val = 0;
+
+    if (!address) {
+        return -1;
+    }
+
+    xen_host_pci_get_word(&s->real_device, address, &val);
+    if (enable) {
+        val |= flag;
+    } else {
+        val &= ~flag;
+    }
+    xen_host_pci_set_word(&s->real_device, address, val);
+    return 0;
+}
+
+static int msi_msix_setup(XenPCIPassthroughState *s,
+                          uint64_t addr,
+                          uint32_t data,
+                          int *ppirq,
+                          bool is_msix,
+                          int msix_entry,
+                          bool is_not_mapped)
+{
+    uint8_t gvec = msi_vector(data);
+    int rc = 0;
+
+    assert((!is_msix && msix_entry == 0) || is_msix);
+
+    if (gvec == 0) {
+        /* if gvec is 0, the guest is asking for a particular pirq that
+         * is passed as dest_id */
+        *ppirq = msi_ext_dest_id(addr >> 32) | msi_dest_id(addr);
+        if (!*ppirq) {
+            /* this probably identifies an misconfiguration of the guest,
+             * try the emulated path */
+            *ppirq = XEN_PT_UNASSIGNED_PIRQ;
+        } else {
+            XEN_PT_LOG(&s->dev, "requested pirq %d for MSI%s"
+                       " (vec: %#x, entry: %#x)\n",
+                       *ppirq, is_msix ? "-X" : "", gvec, msix_entry);
+        }
+    }
+
+    if (is_not_mapped) {
+        uint64_t table_base = 0;
+
+        if (is_msix) {
+            table_base = s->msix->table_base;
+        }
+
+        rc = xc_physdev_map_pirq_msi(xen_xc, xen_domid, XEN_PT_AUTO_ASSIGN,
+                                     ppirq, PCI_DEVFN(s->real_device.dev,
+                                                      s->real_device.func),
+                                     s->real_device.bus,
+                                     msix_entry, table_base);
+        if (rc) {
+            XEN_PT_ERR(&s->dev,
+                       "Mapping of MSI%s (rc: %i, vec: %#x, entry %#x)\n",
+                       is_msix ? "-X" : "", rc, gvec, msix_entry);
+            return rc;
+        }
+    }
+
+    return 0;
+}
+static int msi_msix_update(XenPCIPassthroughState *s,
+                           uint64_t addr,
+                           uint32_t data,
+                           int pirq,
+                           bool is_msix,
+                           int msix_entry,
+                           int *old_pirq)
+{
+    PCIDevice *d = &s->dev;
+    uint8_t gvec = msi_vector(data);
+    uint32_t gflags = msi_gflags(data, addr);
+    int rc = 0;
+    uint64_t table_addr = 0;
+
+    XEN_PT_LOG(d, "Updating MSI%s with pirq %d gvec %#x gflags %#x"
+               " (entry: %#x)\n",
+               is_msix ? "-X" : "", pirq, gvec, gflags, msix_entry);
+
+    if (is_msix) {
+        table_addr = s->msix->mmio_base_addr;
+    }
+
+    rc = xc_domain_update_msi_irq(xen_xc, xen_domid, gvec,
+                                  pirq, gflags, table_addr);
+
+    if (rc) {
+        XEN_PT_ERR(d, "Updating of MSI%s failed. (rc: %d)\n",
+                   is_msix ? "-X" : "", rc);
+
+        if (xc_physdev_unmap_pirq(xen_xc, xen_domid, *old_pirq)) {
+            XEN_PT_ERR(d, "Unmapping of MSI%s pirq %d failed.\n",
+                       is_msix ? "-X" : "", *old_pirq);
+        }
+        *old_pirq = XEN_PT_UNASSIGNED_PIRQ;
+    }
+    return rc;
+}
+
+static int msi_msix_disable(XenPCIPassthroughState *s,
+                            uint64_t addr,
+                            uint32_t data,
+                            int pirq,
+                            bool is_msix,
+                            bool is_binded)
+{
+    PCIDevice *d = &s->dev;
+    uint8_t gvec = msi_vector(data);
+    uint32_t gflags = msi_gflags(data, addr);
+    int rc = 0;
+
+    if (pirq == XEN_PT_UNASSIGNED_PIRQ) {
+        return 0;
+    }
+
+    if (is_binded) {
+        XEN_PT_LOG(d, "Unbind MSI%s with pirq %d, gvec %#x\n",
+                   is_msix ? "-X" : "", pirq, gvec);
+        rc = xc_domain_unbind_msi_irq(xen_xc, xen_domid, gvec, pirq, gflags);
+        if (rc) {
+            XEN_PT_ERR(d, "Unbinding of MSI%s failed. (pirq: %d, gvec: %#x)\n",
+                       is_msix ? "-X" : "", pirq, gvec);
+            return rc;
+        }
+    }
+
+    XEN_PT_LOG(d, "Unmap MSI%s pirq %d\n", is_msix ? "-X" : "", pirq);
+    rc = xc_physdev_unmap_pirq(xen_xc, xen_domid, pirq);
+    if (rc) {
+        XEN_PT_ERR(d, "Unmapping of MSI%s pirq %d failed. (rc: %i)\n",
+                   is_msix ? "-X" : "", pirq, rc);
+        return rc;
+    }
+
+    return 0;
+}
+
+/*
+ * MSI virtualization functions
+ */
+
+int xen_pt_msi_set_enable(XenPCIPassthroughState *s, bool enable)
+{
+    XEN_PT_LOG(&s->dev, "%s MSI.\n", enable ? "enabling" : "disabling");
+
+    if (!s->msi) {
+        return -1;
+    }
+
+    return msi_msix_enable(s, s->msi->ctrl_offset, PCI_MSI_FLAGS_ENABLE,
+                           enable);
+}
+
+/* setup physical msi, but don't enable it */
+int xen_pt_msi_setup(XenPCIPassthroughState *s)
+{
+    int pirq = XEN_PT_UNASSIGNED_PIRQ;
+    int rc = 0;
+    XenPTMSI *msi = s->msi;
+
+    if (msi->initialized) {
+        XEN_PT_ERR(&s->dev,
+                   "Setup physical MSI when it has been properly initialized.\n");
+        return -1;
+    }
+
+    rc = msi_msix_setup(s, msi_addr64(msi), msi->data, &pirq, false, 0, true);
+    if (rc) {
+        return rc;
+    }
+
+    if (pirq < 0) {
+        XEN_PT_ERR(&s->dev, "Invalid pirq number: %d.\n", pirq);
+        return -1;
+    }
+
+    msi->pirq = pirq;
+    XEN_PT_LOG(&s->dev, "MSI mapped with pirq %d.\n", pirq);
+
+    return 0;
+}
+
+int xen_pt_msi_update(XenPCIPassthroughState *s)
+{
+    XenPTMSI *msi = s->msi;
+    return msi_msix_update(s, msi_addr64(msi), msi->data, msi->pirq,
+                           false, 0, &msi->pirq);
+}
+
+void xen_pt_msi_disable(XenPCIPassthroughState *s)
+{
+    XenPTMSI *msi = s->msi;
+
+    if (!msi) {
+        return;
+    }
+
+    xen_pt_msi_set_enable(s, false);
+
+    msi_msix_disable(s, msi_addr64(msi), msi->data, msi->pirq, false,
+                     msi->initialized);
+
+    /* clear msi info */
+    msi->flags = 0;
+    msi->mapped = false;
+    msi->pirq = XEN_PT_UNASSIGNED_PIRQ;
+}
+
+/*
+ * MSI-X virtualization functions
+ */
+
+static int msix_set_enable(XenPCIPassthroughState *s, bool enabled)
+{
+    XEN_PT_LOG(&s->dev, "%s MSI-X.\n", enabled ? "enabling" : "disabling");
+
+    if (!s->msix) {
+        return -1;
+    }
+
+    return msi_msix_enable(s, s->msix->ctrl_offset, PCI_MSIX_FLAGS_ENABLE,
+                           enabled);
+}
+
+static int xen_pt_msix_update_one(XenPCIPassthroughState *s, int entry_nr)
+{
+    XenPTMSIXEntry *entry = NULL;
+    int pirq;
+    int rc;
+
+    if (entry_nr < 0 || entry_nr >= s->msix->total_entries) {
+        return -EINVAL;
+    }
+
+    entry = &s->msix->msix_entry[entry_nr];
+
+    if (!entry->updated) {
+        return 0;
+    }
+
+    pirq = entry->pirq;
+
+    rc = msi_msix_setup(s, entry->addr, entry->data, &pirq, true, entry_nr,
+                        entry->pirq == XEN_PT_UNASSIGNED_PIRQ);
+    if (rc) {
+        return rc;
+    }
+    if (entry->pirq == XEN_PT_UNASSIGNED_PIRQ) {
+        entry->pirq = pirq;
+    }
+
+    rc = msi_msix_update(s, entry->addr, entry->data, pirq, true,
+                         entry_nr, &entry->pirq);
+
+    if (!rc) {
+        entry->updated = false;
+    }
+
+    return rc;
+}
+
+int xen_pt_msix_update(XenPCIPassthroughState *s)
+{
+    XenPTMSIX *msix = s->msix;
+    int i;
+
+    for (i = 0; i < msix->total_entries; i++) {
+        xen_pt_msix_update_one(s, i);
+    }
+
+    return 0;
+}
+
+void xen_pt_msix_disable(XenPCIPassthroughState *s)
+{
+    int i = 0;
+
+    msix_set_enable(s, false);
+
+    for (i = 0; i < s->msix->total_entries; i++) {
+        XenPTMSIXEntry *entry = &s->msix->msix_entry[i];
+
+        msi_msix_disable(s, entry->addr, entry->data, entry->pirq, true, true);
+
+        /* clear MSI-X info */
+        entry->pirq = XEN_PT_UNASSIGNED_PIRQ;
+        entry->updated = false;
+    }
+}
+
+int xen_pt_msix_update_remap(XenPCIPassthroughState *s, int bar_index)
+{
+    XenPTMSIXEntry *entry;
+    int i, ret;
+
+    if (!(s->msix && s->msix->bar_index == bar_index)) {
+        return 0;
+    }
+
+    for (i = 0; i < s->msix->total_entries; i++) {
+        entry = &s->msix->msix_entry[i];
+        if (entry->pirq != XEN_PT_UNASSIGNED_PIRQ) {
+            ret = xc_domain_unbind_pt_irq(xen_xc, xen_domid, entry->pirq,
+                                          PT_IRQ_TYPE_MSI, 0, 0, 0, 0);
+            if (ret) {
+                XEN_PT_ERR(&s->dev, "unbind MSI-X entry %d failed\n",
+                           entry->pirq);
+            }
+            entry->updated = true;
+        }
+    }
+    return xen_pt_msix_update(s);
+}
+
+static uint32_t get_entry_value(XenPTMSIXEntry *e, int offset)
+{
+    switch (offset) {
+    case PCI_MSIX_ENTRY_LOWER_ADDR:
+        return e->addr & UINT32_MAX;
+    case PCI_MSIX_ENTRY_UPPER_ADDR:
+        return e->addr >> 32;
+    case PCI_MSIX_ENTRY_DATA:
+        return e->data;
+    case PCI_MSIX_ENTRY_VECTOR_CTRL:
+        return e->vector_ctrl;
+    default:
+        return 0;
+    }
+}
+
+static void set_entry_value(XenPTMSIXEntry *e, int offset, uint32_t val)
+{
+    switch (offset) {
+    case PCI_MSIX_ENTRY_LOWER_ADDR:
+        e->addr = (e->addr & ((uint64_t)UINT32_MAX << 32)) | val;
+        break;
+    case PCI_MSIX_ENTRY_UPPER_ADDR:
+        e->addr = (uint64_t)val << 32 | (e->addr & UINT32_MAX);
+        break;
+    case PCI_MSIX_ENTRY_DATA:
+        e->data = val;
+        break;
+    case PCI_MSIX_ENTRY_VECTOR_CTRL:
+        e->vector_ctrl = val;
+        break;
+    }
+}
+
+static void pci_msix_write(void *opaque, hwaddr addr,
+                           uint64_t val, unsigned size)
+{
+    XenPCIPassthroughState *s = opaque;
+    XenPTMSIX *msix = s->msix;
+    XenPTMSIXEntry *entry;
+    int entry_nr, offset;
+
+    entry_nr = addr / PCI_MSIX_ENTRY_SIZE;
+    if (entry_nr < 0 || entry_nr >= msix->total_entries) {
+        XEN_PT_ERR(&s->dev, "asked MSI-X entry '%i' invalid!\n", entry_nr);
+        return;
+    }
+    entry = &msix->msix_entry[entry_nr];
+    offset = addr % PCI_MSIX_ENTRY_SIZE;
+
+    if (offset != PCI_MSIX_ENTRY_VECTOR_CTRL) {
+        const volatile uint32_t *vec_ctrl;
+
+        if (get_entry_value(entry, offset) == val) {
+            return;
+        }
+
+        /*
+         * If Xen intercepts the mask bit access, entry->vec_ctrl may not be
+         * up-to-date. Read from hardware directly.
+         */
+        vec_ctrl = s->msix->phys_iomem_base + entry_nr * PCI_MSIX_ENTRY_SIZE
+            + PCI_MSIX_ENTRY_VECTOR_CTRL;
+
+        if (msix->enabled && !(*vec_ctrl & PCI_MSIX_ENTRY_CTRL_MASKBIT)) {
+            XEN_PT_ERR(&s->dev, "Can't update msix entry %d since MSI-X is"
+                       " already enabled.\n", entry_nr);
+            return;
+        }
+
+        entry->updated = true;
+    }
+
+    set_entry_value(entry, offset, val);
+
+    if (offset == PCI_MSIX_ENTRY_VECTOR_CTRL) {
+        if (msix->enabled && !(val & PCI_MSIX_ENTRY_CTRL_MASKBIT)) {
+            xen_pt_msix_update_one(s, entry_nr);
+        }
+    }
+}
+
+static uint64_t pci_msix_read(void *opaque, hwaddr addr,
+                              unsigned size)
+{
+    XenPCIPassthroughState *s = opaque;
+    XenPTMSIX *msix = s->msix;
+    int entry_nr, offset;
+
+    entry_nr = addr / PCI_MSIX_ENTRY_SIZE;
+    if (entry_nr < 0) {
+        XEN_PT_ERR(&s->dev, "asked MSI-X entry '%i' invalid!\n", entry_nr);
+        return 0;
+    }
+
+    offset = addr % PCI_MSIX_ENTRY_SIZE;
+
+    if (addr < msix->total_entries * PCI_MSIX_ENTRY_SIZE) {
+        return get_entry_value(&msix->msix_entry[entry_nr], offset);
+    } else {
+        /* Pending Bit Array (PBA) */
+        return *(uint32_t *)(msix->phys_iomem_base + addr);
+    }
+}
+
+static const MemoryRegionOps pci_msix_ops = {
+    .read = pci_msix_read,
+    .write = pci_msix_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+        .unaligned = false,
+    },
+};
+
+int xen_pt_msix_init(XenPCIPassthroughState *s, uint32_t base)
+{
+    uint8_t id = 0;
+    uint16_t control = 0;
+    uint32_t table_off = 0;
+    int i, total_entries, bar_index;
+    XenHostPCIDevice *hd = &s->real_device;
+    PCIDevice *d = &s->dev;
+    int fd = -1;
+    XenPTMSIX *msix = NULL;
+    int rc = 0;
+
+    rc = xen_host_pci_get_byte(hd, base + PCI_CAP_LIST_ID, &id);
+    if (rc) {
+        return rc;
+    }
+
+    if (id != PCI_CAP_ID_MSIX) {
+        XEN_PT_ERR(d, "Invalid id %#x base %#x\n", id, base);
+        return -1;
+    }
+
+    xen_host_pci_get_word(hd, base + PCI_MSIX_FLAGS, &control);
+    total_entries = control & PCI_MSIX_FLAGS_QSIZE;
+    total_entries += 1;
+
+    s->msix = g_malloc0(sizeof (XenPTMSIX)
+                        + total_entries * sizeof (XenPTMSIXEntry));
+    msix = s->msix;
+
+    msix->total_entries = total_entries;
+    for (i = 0; i < total_entries; i++) {
+        msix->msix_entry[i].pirq = XEN_PT_UNASSIGNED_PIRQ;
+    }
+
+    memory_region_init_io(&msix->mmio, &pci_msix_ops, s, "xen-pci-pt-msix",
+                          (total_entries * PCI_MSIX_ENTRY_SIZE
+                           + XC_PAGE_SIZE - 1)
+                          & XC_PAGE_MASK);
+
+    xen_host_pci_get_long(hd, base + PCI_MSIX_TABLE, &table_off);
+    bar_index = msix->bar_index = table_off & PCI_MSIX_FLAGS_BIRMASK;
+    table_off = table_off & ~PCI_MSIX_FLAGS_BIRMASK;
+    msix->table_base = s->real_device.io_regions[bar_index].base_addr;
+    XEN_PT_LOG(d, "get MSI-X table BAR base 0x%"PRIx64"\n", msix->table_base);
+
+    fd = open("/dev/mem", O_RDWR);
+    if (fd == -1) {
+        rc = -errno;
+        XEN_PT_ERR(d, "Can't open /dev/mem: %s\n", strerror(errno));
+        goto error_out;
+    }
+    XEN_PT_LOG(d, "table_off = %#x, total_entries = %d\n",
+               table_off, total_entries);
+    msix->table_offset_adjust = table_off & 0x0fff;
+    msix->phys_iomem_base =
+        mmap(NULL,
+             total_entries * PCI_MSIX_ENTRY_SIZE + msix->table_offset_adjust,
+             PROT_READ,
+             MAP_SHARED | MAP_LOCKED,
+             fd,
+             msix->table_base + table_off - msix->table_offset_adjust);
+    close(fd);
+    if (msix->phys_iomem_base == MAP_FAILED) {
+        rc = -errno;
+        XEN_PT_ERR(d, "Can't map physical MSI-X table: %s\n", strerror(errno));
+        goto error_out;
+    }
+    msix->phys_iomem_base = (char *)msix->phys_iomem_base
+        + msix->table_offset_adjust;
+
+    XEN_PT_LOG(d, "mapping physical MSI-X table to %p\n",
+               msix->phys_iomem_base);
+
+    memory_region_add_subregion_overlap(&s->bar[bar_index], table_off,
+                                        &msix->mmio,
+                                        2); /* Priority: pci default + 1 */
+
+    return 0;
+
+error_out:
+    memory_region_destroy(&msix->mmio);
+    g_free(s->msix);
+    s->msix = NULL;
+    return rc;
+}
+
+void xen_pt_msix_delete(XenPCIPassthroughState *s)
+{
+    XenPTMSIX *msix = s->msix;
+
+    if (!msix) {
+        return;
+    }
+
+    /* unmap the MSI-X memory mapped register area */
+    if (msix->phys_iomem_base) {
+        XEN_PT_LOG(&s->dev, "unmapping physical MSI-X table from %p\n",
+                   msix->phys_iomem_base);
+        munmap(msix->phys_iomem_base, msix->total_entries * PCI_MSIX_ENTRY_SIZE
+               + msix->table_offset_adjust);
+    }
+
+    memory_region_del_subregion(&s->bar[msix->bar_index], &msix->mmio);
+    memory_region_destroy(&msix->mmio);
+
+    g_free(s->msix);
+    s->msix = NULL;
+}
diff --git a/hw/xen_apic.c b/hw/xen_apic.c
deleted file mode 100644 (file)
index 8f387b6..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Xen basic APIC support
- *
- * Copyright (c) 2012 Citrix
- *
- * Authors:
- *  Wei Liu <wei.liu2@citrix.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 "hw/apic_internal.h"
-#include "hw/pci/msi.h"
-#include "hw/xen.h"
-
-static uint64_t xen_apic_mem_read(void *opaque, hwaddr addr,
-                                  unsigned size)
-{
-    return ~(uint64_t)0;
-}
-
-static void xen_apic_mem_write(void *opaque, hwaddr addr,
-                               uint64_t data, unsigned size)
-{
-    if (size != sizeof(uint32_t)) {
-        fprintf(stderr, "Xen: APIC write data size = %d, invalid\n", size);
-        return;
-    }
-
-    xen_hvm_inject_msi(addr, data);
-}
-
-static const MemoryRegionOps xen_apic_io_ops = {
-    .read = xen_apic_mem_read,
-    .write = xen_apic_mem_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void xen_apic_init(APICCommonState *s)
-{
-    memory_region_init_io(&s->io_memory, &xen_apic_io_ops, s, "xen-apic-msi",
-                          MSI_SPACE_SIZE);
-
-#if defined(CONFIG_XEN_CTRL_INTERFACE_VERSION) \
-    && CONFIG_XEN_CTRL_INTERFACE_VERSION >= 420
-    msi_supported = true;
-#endif
-}
-
-static void xen_apic_set_base(APICCommonState *s, uint64_t val)
-{
-}
-
-static void xen_apic_set_tpr(APICCommonState *s, uint8_t val)
-{
-}
-
-static uint8_t xen_apic_get_tpr(APICCommonState *s)
-{
-    return 0;
-}
-
-static void xen_apic_vapic_base_update(APICCommonState *s)
-{
-}
-
-static void xen_apic_external_nmi(APICCommonState *s)
-{
-}
-
-static void xen_apic_class_init(ObjectClass *klass, void *data)
-{
-    APICCommonClass *k = APIC_COMMON_CLASS(klass);
-
-    k->init = xen_apic_init;
-    k->set_base = xen_apic_set_base;
-    k->set_tpr = xen_apic_set_tpr;
-    k->get_tpr = xen_apic_get_tpr;
-    k->vapic_base_update = xen_apic_vapic_base_update;
-    k->external_nmi = xen_apic_external_nmi;
-}
-
-static const TypeInfo xen_apic_info = {
-    .name = "xen-apic",
-    .parent = TYPE_APIC_COMMON,
-    .instance_size = sizeof(APICCommonState),
-    .class_init = xen_apic_class_init,
-};
-
-static void xen_apic_register_types(void)
-{
-    type_register_static(&xen_apic_info);
-}
-
-type_init(xen_apic_register_types)
diff --git a/hw/xen_backend.c b/hw/xen_backend.c
deleted file mode 100644 (file)
index 24381b5..0000000
+++ /dev/null
@@ -1,787 +0,0 @@
-/*
- *  xen backend driver infrastructure
- *  (c) 2008 Gerd Hoffmann <kraxel@redhat.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; under version 2 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
- *  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/>.
- *
- *  Contributions after 2012-01-13 are licensed under the terms of the
- *  GNU GPL, version 2 or (at your option) any later version.
- */
-
-/*
- * TODO: add some xenbus / xenstore concepts overview here.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/mman.h>
-#include <sys/signal.h>
-
-#include "hw/hw.h"
-#include "char/char.h"
-#include "qemu/log.h"
-#include "hw/xen_backend.h"
-
-#include <xen/grant_table.h>
-
-/* ------------------------------------------------------------- */
-
-/* public */
-XenXC xen_xc = XC_HANDLER_INITIAL_VALUE;
-XenGnttab xen_xcg = XC_HANDLER_INITIAL_VALUE;
-struct xs_handle *xenstore = NULL;
-const char *xen_protocol;
-
-/* private */
-static QTAILQ_HEAD(XenDeviceHead, XenDevice) xendevs = QTAILQ_HEAD_INITIALIZER(xendevs);
-static int debug = 0;
-
-/* ------------------------------------------------------------- */
-
-int xenstore_write_str(const char *base, const char *node, const char *val)
-{
-    char abspath[XEN_BUFSIZE];
-
-    snprintf(abspath, sizeof(abspath), "%s/%s", base, node);
-    if (!xs_write(xenstore, 0, abspath, val, strlen(val))) {
-        return -1;
-    }
-    return 0;
-}
-
-char *xenstore_read_str(const char *base, const char *node)
-{
-    char abspath[XEN_BUFSIZE];
-    unsigned int len;
-    char *str, *ret = NULL;
-
-    snprintf(abspath, sizeof(abspath), "%s/%s", base, node);
-    str = xs_read(xenstore, 0, abspath, &len);
-    if (str != NULL) {
-        /* move to qemu-allocated memory to make sure
-         * callers can savely g_free() stuff. */
-        ret = g_strdup(str);
-        free(str);
-    }
-    return ret;
-}
-
-int xenstore_write_int(const char *base, const char *node, int ival)
-{
-    char val[32];
-
-    snprintf(val, sizeof(val), "%d", ival);
-    return xenstore_write_str(base, node, val);
-}
-
-int xenstore_read_int(const char *base, const char *node, int *ival)
-{
-    char *val;
-    int rc = -1;
-
-    val = xenstore_read_str(base, node);
-    if (val && 1 == sscanf(val, "%d", ival)) {
-        rc = 0;
-    }
-    g_free(val);
-    return rc;
-}
-
-int xenstore_write_be_str(struct XenDevice *xendev, const char *node, const char *val)
-{
-    return xenstore_write_str(xendev->be, node, val);
-}
-
-int xenstore_write_be_int(struct XenDevice *xendev, const char *node, int ival)
-{
-    return xenstore_write_int(xendev->be, node, ival);
-}
-
-char *xenstore_read_be_str(struct XenDevice *xendev, const char *node)
-{
-    return xenstore_read_str(xendev->be, node);
-}
-
-int xenstore_read_be_int(struct XenDevice *xendev, const char *node, int *ival)
-{
-    return xenstore_read_int(xendev->be, node, ival);
-}
-
-char *xenstore_read_fe_str(struct XenDevice *xendev, const char *node)
-{
-    return xenstore_read_str(xendev->fe, node);
-}
-
-int xenstore_read_fe_int(struct XenDevice *xendev, const char *node, int *ival)
-{
-    return xenstore_read_int(xendev->fe, node, ival);
-}
-
-/* ------------------------------------------------------------- */
-
-const char *xenbus_strstate(enum xenbus_state state)
-{
-    static const char *const name[] = {
-        [ XenbusStateUnknown      ] = "Unknown",
-        [ XenbusStateInitialising ] = "Initialising",
-        [ XenbusStateInitWait     ] = "InitWait",
-        [ XenbusStateInitialised  ] = "Initialised",
-        [ XenbusStateConnected    ] = "Connected",
-        [ XenbusStateClosing      ] = "Closing",
-        [ XenbusStateClosed       ] = "Closed",
-    };
-    return (state < ARRAY_SIZE(name)) ? name[state] : "INVALID";
-}
-
-int xen_be_set_state(struct XenDevice *xendev, enum xenbus_state state)
-{
-    int rc;
-
-    rc = xenstore_write_be_int(xendev, "state", state);
-    if (rc < 0) {
-        return rc;
-    }
-    xen_be_printf(xendev, 1, "backend state: %s -> %s\n",
-                  xenbus_strstate(xendev->be_state), xenbus_strstate(state));
-    xendev->be_state = state;
-    return 0;
-}
-
-/* ------------------------------------------------------------- */
-
-struct XenDevice *xen_be_find_xendev(const char *type, int dom, int dev)
-{
-    struct XenDevice *xendev;
-
-    QTAILQ_FOREACH(xendev, &xendevs, next) {
-        if (xendev->dom != dom) {
-            continue;
-        }
-        if (xendev->dev != dev) {
-            continue;
-        }
-        if (strcmp(xendev->type, type) != 0) {
-            continue;
-        }
-        return xendev;
-    }
-    return NULL;
-}
-
-/*
- * get xen backend device, allocate a new one if it doesn't exist.
- */
-static struct XenDevice *xen_be_get_xendev(const char *type, int dom, int dev,
-                                           struct XenDevOps *ops)
-{
-    struct XenDevice *xendev;
-    char *dom0;
-
-    xendev = xen_be_find_xendev(type, dom, dev);
-    if (xendev) {
-        return xendev;
-    }
-
-    /* init new xendev */
-    xendev = g_malloc0(ops->size);
-    xendev->type  = type;
-    xendev->dom   = dom;
-    xendev->dev   = dev;
-    xendev->ops   = ops;
-
-    dom0 = xs_get_domain_path(xenstore, 0);
-    snprintf(xendev->be, sizeof(xendev->be), "%s/backend/%s/%d/%d",
-             dom0, xendev->type, xendev->dom, xendev->dev);
-    snprintf(xendev->name, sizeof(xendev->name), "%s-%d",
-             xendev->type, xendev->dev);
-    free(dom0);
-
-    xendev->debug      = debug;
-    xendev->local_port = -1;
-
-    xendev->evtchndev = xen_xc_evtchn_open(NULL, 0);
-    if (xendev->evtchndev == XC_HANDLER_INITIAL_VALUE) {
-        xen_be_printf(NULL, 0, "can't open evtchn device\n");
-        g_free(xendev);
-        return NULL;
-    }
-    fcntl(xc_evtchn_fd(xendev->evtchndev), F_SETFD, FD_CLOEXEC);
-
-    if (ops->flags & DEVOPS_FLAG_NEED_GNTDEV) {
-        xendev->gnttabdev = xen_xc_gnttab_open(NULL, 0);
-        if (xendev->gnttabdev == XC_HANDLER_INITIAL_VALUE) {
-            xen_be_printf(NULL, 0, "can't open gnttab device\n");
-            xc_evtchn_close(xendev->evtchndev);
-            g_free(xendev);
-            return NULL;
-        }
-    } else {
-        xendev->gnttabdev = XC_HANDLER_INITIAL_VALUE;
-    }
-
-    QTAILQ_INSERT_TAIL(&xendevs, xendev, next);
-
-    if (xendev->ops->alloc) {
-        xendev->ops->alloc(xendev);
-    }
-
-    return xendev;
-}
-
-/*
- * release xen backend device.
- */
-static struct XenDevice *xen_be_del_xendev(int dom, int dev)
-{
-    struct XenDevice *xendev, *xnext;
-
-    /*
-     * This is pretty much like QTAILQ_FOREACH(xendev, &xendevs, next) but
-     * we save the next pointer in xnext because we might free xendev.
-     */
-    xnext = xendevs.tqh_first;
-    while (xnext) {
-        xendev = xnext;
-        xnext = xendev->next.tqe_next;
-
-        if (xendev->dom != dom) {
-            continue;
-        }
-        if (xendev->dev != dev && dev != -1) {
-            continue;
-        }
-
-        if (xendev->ops->free) {
-            xendev->ops->free(xendev);
-        }
-
-        if (xendev->fe) {
-            char token[XEN_BUFSIZE];
-            snprintf(token, sizeof(token), "fe:%p", xendev);
-            xs_unwatch(xenstore, xendev->fe, token);
-            g_free(xendev->fe);
-        }
-
-        if (xendev->evtchndev != XC_HANDLER_INITIAL_VALUE) {
-            xc_evtchn_close(xendev->evtchndev);
-        }
-        if (xendev->gnttabdev != XC_HANDLER_INITIAL_VALUE) {
-            xc_gnttab_close(xendev->gnttabdev);
-        }
-
-        QTAILQ_REMOVE(&xendevs, xendev, next);
-        g_free(xendev);
-    }
-    return NULL;
-}
-
-/*
- * Sync internal data structures on xenstore updates.
- * Node specifies the changed field.  node = NULL means
- * update all fields (used for initialization).
- */
-static void xen_be_backend_changed(struct XenDevice *xendev, const char *node)
-{
-    if (node == NULL  ||  strcmp(node, "online") == 0) {
-        if (xenstore_read_be_int(xendev, "online", &xendev->online) == -1) {
-            xendev->online = 0;
-        }
-    }
-
-    if (node) {
-        xen_be_printf(xendev, 2, "backend update: %s\n", node);
-        if (xendev->ops->backend_changed) {
-            xendev->ops->backend_changed(xendev, node);
-        }
-    }
-}
-
-static void xen_be_frontend_changed(struct XenDevice *xendev, const char *node)
-{
-    int fe_state;
-
-    if (node == NULL  ||  strcmp(node, "state") == 0) {
-        if (xenstore_read_fe_int(xendev, "state", &fe_state) == -1) {
-            fe_state = XenbusStateUnknown;
-        }
-        if (xendev->fe_state != fe_state) {
-            xen_be_printf(xendev, 1, "frontend state: %s -> %s\n",
-                          xenbus_strstate(xendev->fe_state),
-                          xenbus_strstate(fe_state));
-        }
-        xendev->fe_state = fe_state;
-    }
-    if (node == NULL  ||  strcmp(node, "protocol") == 0) {
-        g_free(xendev->protocol);
-        xendev->protocol = xenstore_read_fe_str(xendev, "protocol");
-        if (xendev->protocol) {
-            xen_be_printf(xendev, 1, "frontend protocol: %s\n", xendev->protocol);
-        }
-    }
-
-    if (node) {
-        xen_be_printf(xendev, 2, "frontend update: %s\n", node);
-        if (xendev->ops->frontend_changed) {
-            xendev->ops->frontend_changed(xendev, node);
-        }
-    }
-}
-
-/* ------------------------------------------------------------- */
-/* Check for possible state transitions and perform them.        */
-
-/*
- * Initial xendev setup.  Read frontend path, register watch for it.
- * Should succeed once xend finished setting up the backend device.
- *
- * Also sets initial state (-> Initializing) when done.  Which
- * only affects the xendev->be_state variable as xenbus should
- * already be put into that state by xend.
- */
-static int xen_be_try_setup(struct XenDevice *xendev)
-{
-    char token[XEN_BUFSIZE];
-    int be_state;
-
-    if (xenstore_read_be_int(xendev, "state", &be_state) == -1) {
-        xen_be_printf(xendev, 0, "reading backend state failed\n");
-        return -1;
-    }
-
-    if (be_state != XenbusStateInitialising) {
-        xen_be_printf(xendev, 0, "initial backend state is wrong (%s)\n",
-                      xenbus_strstate(be_state));
-        return -1;
-    }
-
-    xendev->fe = xenstore_read_be_str(xendev, "frontend");
-    if (xendev->fe == NULL) {
-        xen_be_printf(xendev, 0, "reading frontend path failed\n");
-        return -1;
-    }
-
-    /* setup frontend watch */
-    snprintf(token, sizeof(token), "fe:%p", xendev);
-    if (!xs_watch(xenstore, xendev->fe, token)) {
-        xen_be_printf(xendev, 0, "watching frontend path (%s) failed\n",
-                      xendev->fe);
-        return -1;
-    }
-    xen_be_set_state(xendev, XenbusStateInitialising);
-
-    xen_be_backend_changed(xendev, NULL);
-    xen_be_frontend_changed(xendev, NULL);
-    return 0;
-}
-
-/*
- * Try initialize xendev.  Prepare everything the backend can do
- * without synchronizing with the frontend.  Fakes hotplug-status.  No
- * hotplug involved here because this is about userspace drivers, thus
- * there are kernel backend devices which could invoke hotplug.
- *
- * Goes to InitWait on success.
- */
-static int xen_be_try_init(struct XenDevice *xendev)
-{
-    int rc = 0;
-
-    if (!xendev->online) {
-        xen_be_printf(xendev, 1, "not online\n");
-        return -1;
-    }
-
-    if (xendev->ops->init) {
-        rc = xendev->ops->init(xendev);
-    }
-    if (rc != 0) {
-        xen_be_printf(xendev, 1, "init() failed\n");
-        return rc;
-    }
-
-    xenstore_write_be_str(xendev, "hotplug-status", "connected");
-    xen_be_set_state(xendev, XenbusStateInitWait);
-    return 0;
-}
-
-/*
- * Try to initialise xendev.  Depends on the frontend being ready
- * for it (shared ring and evtchn info in xenstore, state being
- * Initialised or Connected).
- *
- * Goes to Connected on success.
- */
-static int xen_be_try_initialise(struct XenDevice *xendev)
-{
-    int rc = 0;
-
-    if (xendev->fe_state != XenbusStateInitialised  &&
-        xendev->fe_state != XenbusStateConnected) {
-        if (xendev->ops->flags & DEVOPS_FLAG_IGNORE_STATE) {
-            xen_be_printf(xendev, 2, "frontend not ready, ignoring\n");
-        } else {
-            xen_be_printf(xendev, 2, "frontend not ready (yet)\n");
-            return -1;
-        }
-    }
-
-    if (xendev->ops->initialise) {
-        rc = xendev->ops->initialise(xendev);
-    }
-    if (rc != 0) {
-        xen_be_printf(xendev, 0, "initialise() failed\n");
-        return rc;
-    }
-
-    xen_be_set_state(xendev, XenbusStateConnected);
-    return 0;
-}
-
-/*
- * Try to let xendev know that it is connected.  Depends on the
- * frontend being Connected.  Note that this may be called more
- * than once since the backend state is not modified.
- */
-static void xen_be_try_connected(struct XenDevice *xendev)
-{
-    if (!xendev->ops->connected) {
-        return;
-    }
-
-    if (xendev->fe_state != XenbusStateConnected) {
-        if (xendev->ops->flags & DEVOPS_FLAG_IGNORE_STATE) {
-            xen_be_printf(xendev, 2, "frontend not ready, ignoring\n");
-        } else {
-            xen_be_printf(xendev, 2, "frontend not ready (yet)\n");
-            return;
-        }
-    }
-
-    xendev->ops->connected(xendev);
-}
-
-/*
- * Teardown connection.
- *
- * Goes to Closed when done.
- */
-static void xen_be_disconnect(struct XenDevice *xendev, enum xenbus_state state)
-{
-    if (xendev->be_state != XenbusStateClosing &&
-        xendev->be_state != XenbusStateClosed  &&
-        xendev->ops->disconnect) {
-        xendev->ops->disconnect(xendev);
-    }
-    if (xendev->be_state != state) {
-        xen_be_set_state(xendev, state);
-    }
-}
-
-/*
- * Try to reset xendev, for reconnection by another frontend instance.
- */
-static int xen_be_try_reset(struct XenDevice *xendev)
-{
-    if (xendev->fe_state != XenbusStateInitialising) {
-        return -1;
-    }
-
-    xen_be_printf(xendev, 1, "device reset (for re-connect)\n");
-    xen_be_set_state(xendev, XenbusStateInitialising);
-    return 0;
-}
-
-/*
- * state change dispatcher function
- */
-void xen_be_check_state(struct XenDevice *xendev)
-{
-    int rc = 0;
-
-    /* frontend may request shutdown from almost anywhere */
-    if (xendev->fe_state == XenbusStateClosing ||
-        xendev->fe_state == XenbusStateClosed) {
-        xen_be_disconnect(xendev, xendev->fe_state);
-        return;
-    }
-
-    /* check for possible backend state transitions */
-    for (;;) {
-        switch (xendev->be_state) {
-        case XenbusStateUnknown:
-            rc = xen_be_try_setup(xendev);
-            break;
-        case XenbusStateInitialising:
-            rc = xen_be_try_init(xendev);
-            break;
-        case XenbusStateInitWait:
-            rc = xen_be_try_initialise(xendev);
-            break;
-        case XenbusStateConnected:
-            /* xendev->be_state doesn't change */
-            xen_be_try_connected(xendev);
-            rc = -1;
-            break;
-        case XenbusStateClosed:
-            rc = xen_be_try_reset(xendev);
-            break;
-        default:
-            rc = -1;
-        }
-        if (rc != 0) {
-            break;
-        }
-    }
-}
-
-/* ------------------------------------------------------------- */
-
-static int xenstore_scan(const char *type, int dom, struct XenDevOps *ops)
-{
-    struct XenDevice *xendev;
-    char path[XEN_BUFSIZE], token[XEN_BUFSIZE];
-    char **dev = NULL, *dom0;
-    unsigned int cdev, j;
-
-    /* setup watch */
-    dom0 = xs_get_domain_path(xenstore, 0);
-    snprintf(token, sizeof(token), "be:%p:%d:%p", type, dom, ops);
-    snprintf(path, sizeof(path), "%s/backend/%s/%d", dom0, type, dom);
-    free(dom0);
-    if (!xs_watch(xenstore, path, token)) {
-        xen_be_printf(NULL, 0, "xen be: watching backend path (%s) failed\n", path);
-        return -1;
-    }
-
-    /* look for backends */
-    dev = xs_directory(xenstore, 0, path, &cdev);
-    if (!dev) {
-        return 0;
-    }
-    for (j = 0; j < cdev; j++) {
-        xendev = xen_be_get_xendev(type, dom, atoi(dev[j]), ops);
-        if (xendev == NULL) {
-            continue;
-        }
-        xen_be_check_state(xendev);
-    }
-    free(dev);
-    return 0;
-}
-
-static void xenstore_update_be(char *watch, char *type, int dom,
-                               struct XenDevOps *ops)
-{
-    struct XenDevice *xendev;
-    char path[XEN_BUFSIZE], *dom0, *bepath;
-    unsigned int len, dev;
-
-    dom0 = xs_get_domain_path(xenstore, 0);
-    len = snprintf(path, sizeof(path), "%s/backend/%s/%d", dom0, type, dom);
-    free(dom0);
-    if (strncmp(path, watch, len) != 0) {
-        return;
-    }
-    if (sscanf(watch+len, "/%u/%255s", &dev, path) != 2) {
-        strcpy(path, "");
-        if (sscanf(watch+len, "/%u", &dev) != 1) {
-            dev = -1;
-        }
-    }
-    if (dev == -1) {
-        return;
-    }
-
-    xendev = xen_be_get_xendev(type, dom, dev, ops);
-    if (xendev != NULL) {
-        bepath = xs_read(xenstore, 0, xendev->be, &len);
-        if (bepath == NULL) {
-            xen_be_del_xendev(dom, dev);
-        } else {
-            free(bepath);
-            xen_be_backend_changed(xendev, path);
-            xen_be_check_state(xendev);
-        }
-    }
-}
-
-static void xenstore_update_fe(char *watch, struct XenDevice *xendev)
-{
-    char *node;
-    unsigned int len;
-
-    len = strlen(xendev->fe);
-    if (strncmp(xendev->fe, watch, len) != 0) {
-        return;
-    }
-    if (watch[len] != '/') {
-        return;
-    }
-    node = watch + len + 1;
-
-    xen_be_frontend_changed(xendev, node);
-    xen_be_check_state(xendev);
-}
-
-static void xenstore_update(void *unused)
-{
-    char **vec = NULL;
-    intptr_t type, ops, ptr;
-    unsigned int dom, count;
-
-    vec = xs_read_watch(xenstore, &count);
-    if (vec == NULL) {
-        goto cleanup;
-    }
-
-    if (sscanf(vec[XS_WATCH_TOKEN], "be:%" PRIxPTR ":%d:%" PRIxPTR,
-               &type, &dom, &ops) == 3) {
-        xenstore_update_be(vec[XS_WATCH_PATH], (void*)type, dom, (void*)ops);
-    }
-    if (sscanf(vec[XS_WATCH_TOKEN], "fe:%" PRIxPTR, &ptr) == 1) {
-        xenstore_update_fe(vec[XS_WATCH_PATH], (void*)ptr);
-    }
-
-cleanup:
-    free(vec);
-}
-
-static void xen_be_evtchn_event(void *opaque)
-{
-    struct XenDevice *xendev = opaque;
-    evtchn_port_t port;
-
-    port = xc_evtchn_pending(xendev->evtchndev);
-    if (port != xendev->local_port) {
-        xen_be_printf(xendev, 0, "xc_evtchn_pending returned %d (expected %d)\n",
-                      port, xendev->local_port);
-        return;
-    }
-    xc_evtchn_unmask(xendev->evtchndev, port);
-
-    if (xendev->ops->event) {
-        xendev->ops->event(xendev);
-    }
-}
-
-/* -------------------------------------------------------------------- */
-
-int xen_be_init(void)
-{
-    xenstore = xs_daemon_open();
-    if (!xenstore) {
-        xen_be_printf(NULL, 0, "can't connect to xenstored\n");
-        return -1;
-    }
-
-    if (qemu_set_fd_handler(xs_fileno(xenstore), xenstore_update, NULL, NULL) < 0) {
-        goto err;
-    }
-
-    if (xen_xc == XC_HANDLER_INITIAL_VALUE) {
-        /* Check if xen_init() have been called */
-        goto err;
-    }
-    return 0;
-
-err:
-    qemu_set_fd_handler(xs_fileno(xenstore), NULL, NULL, NULL);
-    xs_daemon_close(xenstore);
-    xenstore = NULL;
-
-    return -1;
-}
-
-int xen_be_register(const char *type, struct XenDevOps *ops)
-{
-    return xenstore_scan(type, xen_domid, ops);
-}
-
-int xen_be_bind_evtchn(struct XenDevice *xendev)
-{
-    if (xendev->local_port != -1) {
-        return 0;
-    }
-    xendev->local_port = xc_evtchn_bind_interdomain
-        (xendev->evtchndev, xendev->dom, xendev->remote_port);
-    if (xendev->local_port == -1) {
-        xen_be_printf(xendev, 0, "xc_evtchn_bind_interdomain failed\n");
-        return -1;
-    }
-    xen_be_printf(xendev, 2, "bind evtchn port %d\n", xendev->local_port);
-    qemu_set_fd_handler(xc_evtchn_fd(xendev->evtchndev),
-                        xen_be_evtchn_event, NULL, xendev);
-    return 0;
-}
-
-void xen_be_unbind_evtchn(struct XenDevice *xendev)
-{
-    if (xendev->local_port == -1) {
-        return;
-    }
-    qemu_set_fd_handler(xc_evtchn_fd(xendev->evtchndev), NULL, NULL, NULL);
-    xc_evtchn_unbind(xendev->evtchndev, xendev->local_port);
-    xen_be_printf(xendev, 2, "unbind evtchn port %d\n", xendev->local_port);
-    xendev->local_port = -1;
-}
-
-int xen_be_send_notify(struct XenDevice *xendev)
-{
-    return xc_evtchn_notify(xendev->evtchndev, xendev->local_port);
-}
-
-/*
- * msg_level:
- *  0 == errors (stderr + logfile).
- *  1 == informative debug messages (logfile only).
- *  2 == noisy debug messages (logfile only).
- *  3 == will flood your log (logfile only).
- */
-void xen_be_printf(struct XenDevice *xendev, int msg_level, const char *fmt, ...)
-{
-    va_list args;
-
-    if (xendev) {
-        if (msg_level > xendev->debug) {
-            return;
-        }
-        qemu_log("xen be: %s: ", xendev->name);
-        if (msg_level == 0) {
-            fprintf(stderr, "xen be: %s: ", xendev->name);
-        }
-    } else {
-        if (msg_level > debug) {
-            return;
-        }
-        qemu_log("xen be core: ");
-        if (msg_level == 0) {
-            fprintf(stderr, "xen be core: ");
-        }
-    }
-    va_start(args, fmt);
-    qemu_log_vprintf(fmt, args);
-    va_end(args);
-    if (msg_level == 0) {
-        va_start(args, fmt);
-        vfprintf(stderr, fmt, args);
-        va_end(args);
-    }
-    qemu_log_flush();
-}
diff --git a/hw/xen_backend.h b/hw/xen_backend.h
deleted file mode 100644 (file)
index 6d5c699..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-#ifndef QEMU_HW_XEN_BACKEND_H
-#define QEMU_HW_XEN_BACKEND_H 1
-
-#include "hw/xen_common.h"
-#include "sysemu/sysemu.h"
-#include "net/net.h"
-
-/* ------------------------------------------------------------- */
-
-#define XEN_BUFSIZE 1024
-
-struct XenDevice;
-
-/* driver uses grant tables  ->  open gntdev device (xendev->gnttabdev) */
-#define DEVOPS_FLAG_NEED_GNTDEV   1
-/* don't expect frontend doing correct state transitions (aka console quirk) */
-#define DEVOPS_FLAG_IGNORE_STATE  2
-
-struct XenDevOps {
-    size_t    size;
-    uint32_t  flags;
-    void      (*alloc)(struct XenDevice *xendev);
-    int       (*init)(struct XenDevice *xendev);
-    int       (*initialise)(struct XenDevice *xendev);
-    void      (*connected)(struct XenDevice *xendev);
-    void      (*event)(struct XenDevice *xendev);
-    void      (*disconnect)(struct XenDevice *xendev);
-    int       (*free)(struct XenDevice *xendev);
-    void      (*backend_changed)(struct XenDevice *xendev, const char *node);
-    void      (*frontend_changed)(struct XenDevice *xendev, const char *node);
-};
-
-struct XenDevice {
-    const char         *type;
-    int                dom;
-    int                dev;
-    char               name[64];
-    int                debug;
-
-    enum xenbus_state  be_state;
-    enum xenbus_state  fe_state;
-    int                online;
-    char               be[XEN_BUFSIZE];
-    char               *fe;
-    char               *protocol;
-    int                remote_port;
-    int                local_port;
-
-    XenEvtchn          evtchndev;
-    XenGnttab          gnttabdev;
-
-    struct XenDevOps   *ops;
-    QTAILQ_ENTRY(XenDevice) next;
-};
-
-/* ------------------------------------------------------------- */
-
-/* variables */
-extern XenXC xen_xc;
-extern struct xs_handle *xenstore;
-extern const char *xen_protocol;
-
-/* xenstore helper functions */
-int xenstore_write_str(const char *base, const char *node, const char *val);
-int xenstore_write_int(const char *base, const char *node, int ival);
-char *xenstore_read_str(const char *base, const char *node);
-int xenstore_read_int(const char *base, const char *node, int *ival);
-
-int xenstore_write_be_str(struct XenDevice *xendev, const char *node, const char *val);
-int xenstore_write_be_int(struct XenDevice *xendev, const char *node, int ival);
-char *xenstore_read_be_str(struct XenDevice *xendev, const char *node);
-int xenstore_read_be_int(struct XenDevice *xendev, const char *node, int *ival);
-char *xenstore_read_fe_str(struct XenDevice *xendev, const char *node);
-int xenstore_read_fe_int(struct XenDevice *xendev, const char *node, int *ival);
-
-const char *xenbus_strstate(enum xenbus_state state);
-struct XenDevice *xen_be_find_xendev(const char *type, int dom, int dev);
-void xen_be_check_state(struct XenDevice *xendev);
-
-/* xen backend driver bits */
-int xen_be_init(void);
-int xen_be_register(const char *type, struct XenDevOps *ops);
-int xen_be_set_state(struct XenDevice *xendev, enum xenbus_state state);
-int xen_be_bind_evtchn(struct XenDevice *xendev);
-void xen_be_unbind_evtchn(struct XenDevice *xendev);
-int xen_be_send_notify(struct XenDevice *xendev);
-void xen_be_printf(struct XenDevice *xendev, int msg_level, const char *fmt, ...)
-    GCC_FMT_ATTR(3, 4);
-
-/* actual backend drivers */
-extern struct XenDevOps xen_console_ops;      /* xen_console.c     */
-extern struct XenDevOps xen_kbdmouse_ops;     /* xen_framebuffer.c */
-extern struct XenDevOps xen_framebuffer_ops;  /* xen_framebuffer.c */
-extern struct XenDevOps xen_blkdev_ops;       /* xen_disk.c        */
-extern struct XenDevOps xen_netdev_ops;       /* xen_nic.c         */
-
-void xen_init_display(int domid);
-
-/* configuration (aka xenbus setup) */
-void xen_config_cleanup(void);
-int xen_config_dev_blk(DriveInfo *disk);
-int xen_config_dev_nic(NICInfo *nic);
-int xen_config_dev_vfb(int vdev, const char *type);
-int xen_config_dev_vkbd(int vdev);
-int xen_config_dev_console(int vdev);
-
-#endif /* QEMU_HW_XEN_BACKEND_H */
diff --git a/hw/xen_blkif.h b/hw/xen_blkif.h
deleted file mode 100644 (file)
index c0f4136..0000000
+++ /dev/null
@@ -1,103 +0,0 @@
-#ifndef __XEN_BLKIF_H__
-#define __XEN_BLKIF_H__
-
-#include <xen/io/ring.h>
-#include <xen/io/blkif.h>
-#include <xen/io/protocols.h>
-
-/* Not a real protocol.  Used to generate ring structs which contain
- * the elements common to all protocols only.  This way we get a
- * compiler-checkable way to use common struct elements, so we can
- * avoid using switch(protocol) in a number of places.  */
-struct blkif_common_request {
-       char dummy;
-};
-struct blkif_common_response {
-       char dummy;
-};
-
-/* i386 protocol version */
-#pragma pack(push, 4)
-struct blkif_x86_32_request {
-       uint8_t        operation;    /* BLKIF_OP_???                         */
-       uint8_t        nr_segments;  /* number of segments                   */
-       blkif_vdev_t   handle;       /* only for read/write requests         */
-       uint64_t       id;           /* private guest value, echoed in resp  */
-       blkif_sector_t sector_number;/* start sector idx on disk (r/w only)  */
-       struct blkif_request_segment seg[BLKIF_MAX_SEGMENTS_PER_REQUEST];
-};
-struct blkif_x86_32_response {
-       uint64_t        id;              /* copied from request */
-       uint8_t         operation;       /* copied from request */
-       int16_t         status;          /* BLKIF_RSP_???       */
-};
-typedef struct blkif_x86_32_request blkif_x86_32_request_t;
-typedef struct blkif_x86_32_response blkif_x86_32_response_t;
-#pragma pack(pop)
-
-/* x86_64 protocol version */
-struct blkif_x86_64_request {
-       uint8_t        operation;    /* BLKIF_OP_???                         */
-       uint8_t        nr_segments;  /* number of segments                   */
-       blkif_vdev_t   handle;       /* only for read/write requests         */
-       uint64_t       __attribute__((__aligned__(8))) id;
-       blkif_sector_t sector_number;/* start sector idx on disk (r/w only)  */
-       struct blkif_request_segment seg[BLKIF_MAX_SEGMENTS_PER_REQUEST];
-};
-struct blkif_x86_64_response {
-       uint64_t       __attribute__((__aligned__(8))) id;
-       uint8_t         operation;       /* copied from request */
-       int16_t         status;          /* BLKIF_RSP_???       */
-};
-typedef struct blkif_x86_64_request blkif_x86_64_request_t;
-typedef struct blkif_x86_64_response blkif_x86_64_response_t;
-
-DEFINE_RING_TYPES(blkif_common, struct blkif_common_request, struct blkif_common_response);
-DEFINE_RING_TYPES(blkif_x86_32, struct blkif_x86_32_request, struct blkif_x86_32_response);
-DEFINE_RING_TYPES(blkif_x86_64, struct blkif_x86_64_request, struct blkif_x86_64_response);
-
-union blkif_back_rings {
-       blkif_back_ring_t        native;
-       blkif_common_back_ring_t common;
-        blkif_x86_32_back_ring_t x86_32_part;
-        blkif_x86_64_back_ring_t x86_64_part;
-};
-typedef union blkif_back_rings blkif_back_rings_t;
-
-enum blkif_protocol {
-       BLKIF_PROTOCOL_NATIVE = 1,
-       BLKIF_PROTOCOL_X86_32 = 2,
-       BLKIF_PROTOCOL_X86_64 = 3,
-};
-
-static inline void blkif_get_x86_32_req(blkif_request_t *dst, blkif_x86_32_request_t *src)
-{
-       int i, n = BLKIF_MAX_SEGMENTS_PER_REQUEST;
-
-       dst->operation = src->operation;
-       dst->nr_segments = src->nr_segments;
-       dst->handle = src->handle;
-       dst->id = src->id;
-       dst->sector_number = src->sector_number;
-       if (n > src->nr_segments)
-               n = src->nr_segments;
-       for (i = 0; i < n; i++)
-               dst->seg[i] = src->seg[i];
-}
-
-static inline void blkif_get_x86_64_req(blkif_request_t *dst, blkif_x86_64_request_t *src)
-{
-       int i, n = BLKIF_MAX_SEGMENTS_PER_REQUEST;
-
-       dst->operation = src->operation;
-       dst->nr_segments = src->nr_segments;
-       dst->handle = src->handle;
-       dst->id = src->id;
-       dst->sector_number = src->sector_number;
-       if (n > src->nr_segments)
-               n = src->nr_segments;
-       for (i = 0; i < n; i++)
-               dst->seg[i] = src->seg[i];
-}
-
-#endif /* __XEN_BLKIF_H__ */
diff --git a/hw/xen_common.h b/hw/xen_common.h
deleted file mode 100644 (file)
index c37bde3..0000000
+++ /dev/null
@@ -1,160 +0,0 @@
-#ifndef QEMU_HW_XEN_COMMON_H
-#define QEMU_HW_XEN_COMMON_H 1
-
-#include "config-host.h"
-
-#include <stddef.h>
-#include <inttypes.h>
-
-#include <xenctrl.h>
-#if CONFIG_XEN_CTRL_INTERFACE_VERSION < 420
-#  include <xs.h>
-#else
-#  include <xenstore.h>
-#endif
-#include <xen/io/xenbus.h>
-
-#include "hw/hw.h"
-#include "hw/xen.h"
-#include "qemu/queue.h"
-
-/*
- * We don't support Xen prior to 3.3.0.
- */
-
-/* Xen before 4.0 */
-#if CONFIG_XEN_CTRL_INTERFACE_VERSION < 400
-static inline void *xc_map_foreign_bulk(int xc_handle, uint32_t dom, int prot,
-                                        xen_pfn_t *arr, int *err,
-                                        unsigned int num)
-{
-    return xc_map_foreign_batch(xc_handle, dom, prot, arr, num);
-}
-#endif
-
-
-/* Xen before 4.1 */
-#if CONFIG_XEN_CTRL_INTERFACE_VERSION < 410
-
-typedef int XenXC;
-typedef int XenEvtchn;
-typedef int XenGnttab;
-
-#  define XC_INTERFACE_FMT "%i"
-#  define XC_HANDLER_INITIAL_VALUE    -1
-
-static inline XenEvtchn xen_xc_evtchn_open(void *logger,
-                                           unsigned int open_flags)
-{
-    return xc_evtchn_open();
-}
-
-static inline XenGnttab xen_xc_gnttab_open(void *logger,
-                                           unsigned int open_flags)
-{
-    return xc_gnttab_open();
-}
-
-static inline XenXC xen_xc_interface_open(void *logger, void *dombuild_logger,
-                                          unsigned int open_flags)
-{
-    return xc_interface_open();
-}
-
-static inline int xc_fd(int xen_xc)
-{
-    return xen_xc;
-}
-
-
-static inline int xc_domain_populate_physmap_exact
-    (XenXC xc_handle, uint32_t domid, unsigned long nr_extents,
-     unsigned int extent_order, unsigned int mem_flags, xen_pfn_t *extent_start)
-{
-    return xc_domain_memory_populate_physmap
-        (xc_handle, domid, nr_extents, extent_order, mem_flags, extent_start);
-}
-
-static inline int xc_domain_add_to_physmap(int xc_handle, uint32_t domid,
-                                           unsigned int space, unsigned long idx,
-                                           xen_pfn_t gpfn)
-{
-    struct xen_add_to_physmap xatp = {
-        .domid = domid,
-        .space = space,
-        .idx = idx,
-        .gpfn = gpfn,
-    };
-
-    return xc_memory_op(xc_handle, XENMEM_add_to_physmap, &xatp);
-}
-
-static inline struct xs_handle *xs_open(unsigned long flags)
-{
-    return xs_daemon_open();
-}
-
-static inline void xs_close(struct xs_handle *xsh)
-{
-    if (xsh != NULL) {
-        xs_daemon_close(xsh);
-    }
-}
-
-
-/* Xen 4.1 */
-#else
-
-typedef xc_interface *XenXC;
-typedef xc_evtchn *XenEvtchn;
-typedef xc_gnttab *XenGnttab;
-
-#  define XC_INTERFACE_FMT "%p"
-#  define XC_HANDLER_INITIAL_VALUE    NULL
-
-static inline XenEvtchn xen_xc_evtchn_open(void *logger,
-                                           unsigned int open_flags)
-{
-    return xc_evtchn_open(logger, open_flags);
-}
-
-static inline XenGnttab xen_xc_gnttab_open(void *logger,
-                                           unsigned int open_flags)
-{
-    return xc_gnttab_open(logger, open_flags);
-}
-
-static inline XenXC xen_xc_interface_open(void *logger, void *dombuild_logger,
-                                          unsigned int open_flags)
-{
-    return xc_interface_open(logger, dombuild_logger, open_flags);
-}
-
-/* FIXME There is now way to have the xen fd */
-static inline int xc_fd(xc_interface *xen_xc)
-{
-    return -1;
-}
-#endif
-
-/* Xen before 4.2 */
-#if CONFIG_XEN_CTRL_INTERFACE_VERSION < 420
-static inline int xen_xc_hvm_inject_msi(XenXC xen_xc, domid_t dom,
-        uint64_t addr, uint32_t data)
-{
-    return -ENOSYS;
-}
-#else
-static inline int xen_xc_hvm_inject_msi(XenXC xen_xc, domid_t dom,
-        uint64_t addr, uint32_t data)
-{
-    return xc_hvm_inject_msi(xen_xc, dom, addr, data);
-}
-#endif
-
-void destroy_hvm_domain(bool reboot);
-
-/* shutdown/destroy current domain because of an error */
-void xen_shutdown_fatal_error(const char *fmt, ...) GCC_FMT_ATTR(1, 2);
-
-#endif /* QEMU_HW_XEN_COMMON_H */
diff --git a/hw/xen_console.c b/hw/xen_console.c
deleted file mode 100644 (file)
index c56ef47..0000000
+++ /dev/null
@@ -1,305 +0,0 @@
-/*
- *  Copyright (C) International Business Machines  Corp., 2005
- *  Author(s): Anthony Liguori <aliguori@us.ibm.com>
- *
- *  Copyright (C) Red Hat 2007
- *
- *  Xen Console
- *
- *  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.
- *
- *  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 <stdlib.h>
-#include <errno.h>
-#include <string.h>
-#include <sys/select.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <termios.h>
-#include <stdarg.h>
-#include <sys/mman.h>
-
-#include "hw/hw.h"
-#include "char/char.h"
-#include "hw/xen_backend.h"
-
-#include <xen/io/console.h>
-
-struct buffer {
-    uint8_t *data;
-    size_t consumed;
-    size_t size;
-    size_t capacity;
-    size_t max_capacity;
-};
-
-struct XenConsole {
-    struct XenDevice  xendev;  /* must be first */
-    struct buffer     buffer;
-    char              console[XEN_BUFSIZE];
-    int               ring_ref;
-    void              *sring;
-    CharDriverState   *chr;
-    int               backlog;
-};
-
-static void buffer_append(struct XenConsole *con)
-{
-    struct buffer *buffer = &con->buffer;
-    XENCONS_RING_IDX cons, prod, size;
-    struct xencons_interface *intf = con->sring;
-
-    cons = intf->out_cons;
-    prod = intf->out_prod;
-    xen_mb();
-
-    size = prod - cons;
-    if ((size == 0) || (size > sizeof(intf->out)))
-       return;
-
-    if ((buffer->capacity - buffer->size) < size) {
-       buffer->capacity += (size + 1024);
-       buffer->data = g_realloc(buffer->data, buffer->capacity);
-    }
-
-    while (cons != prod)
-       buffer->data[buffer->size++] = intf->out[
-           MASK_XENCONS_IDX(cons++, intf->out)];
-
-    xen_mb();
-    intf->out_cons = cons;
-    xen_be_send_notify(&con->xendev);
-
-    if (buffer->max_capacity &&
-       buffer->size > buffer->max_capacity) {
-       /* Discard the middle of the data. */
-
-       size_t over = buffer->size - buffer->max_capacity;
-       uint8_t *maxpos = buffer->data + buffer->max_capacity;
-
-       memmove(maxpos - over, maxpos, over);
-       buffer->data = g_realloc(buffer->data, buffer->max_capacity);
-       buffer->size = buffer->capacity = buffer->max_capacity;
-
-       if (buffer->consumed > buffer->max_capacity - over)
-           buffer->consumed = buffer->max_capacity - over;
-    }
-}
-
-static void buffer_advance(struct buffer *buffer, size_t len)
-{
-    buffer->consumed += len;
-    if (buffer->consumed == buffer->size) {
-       buffer->consumed = 0;
-       buffer->size = 0;
-    }
-}
-
-static int ring_free_bytes(struct XenConsole *con)
-{
-    struct xencons_interface *intf = con->sring;
-    XENCONS_RING_IDX cons, prod, space;
-
-    cons = intf->in_cons;
-    prod = intf->in_prod;
-    xen_mb();
-
-    space = prod - cons;
-    if (space > sizeof(intf->in))
-       return 0; /* ring is screwed: ignore it */
-
-    return (sizeof(intf->in) - space);
-}
-
-static int xencons_can_receive(void *opaque)
-{
-    struct XenConsole *con = opaque;
-    return ring_free_bytes(con);
-}
-
-static void xencons_receive(void *opaque, const uint8_t *buf, int len)
-{
-    struct XenConsole *con = opaque;
-    struct xencons_interface *intf = con->sring;
-    XENCONS_RING_IDX prod;
-    int i, max;
-
-    max = ring_free_bytes(con);
-    /* The can_receive() func limits this, but check again anyway */
-    if (max < len)
-       len = max;
-
-    prod = intf->in_prod;
-    for (i = 0; i < len; i++) {
-       intf->in[MASK_XENCONS_IDX(prod++, intf->in)] =
-           buf[i];
-    }
-    xen_wmb();
-    intf->in_prod = prod;
-    xen_be_send_notify(&con->xendev);
-}
-
-static void xencons_send(struct XenConsole *con)
-{
-    ssize_t len, size;
-
-    size = con->buffer.size - con->buffer.consumed;
-    if (con->chr)
-        len = qemu_chr_fe_write(con->chr, con->buffer.data + con->buffer.consumed,
-                             size);
-    else
-        len = size;
-    if (len < 1) {
-       if (!con->backlog) {
-           con->backlog = 1;
-           xen_be_printf(&con->xendev, 1, "backlog piling up, nobody listening?\n");
-       }
-    } else {
-       buffer_advance(&con->buffer, len);
-       if (con->backlog && len == size) {
-           con->backlog = 0;
-           xen_be_printf(&con->xendev, 1, "backlog is gone\n");
-       }
-    }
-}
-
-/* -------------------------------------------------------------------- */
-
-static int con_init(struct XenDevice *xendev)
-{
-    struct XenConsole *con = container_of(xendev, struct XenConsole, xendev);
-    char *type, *dom, label[32];
-    int ret = 0;
-    const char *output;
-
-    /* setup */
-    dom = xs_get_domain_path(xenstore, con->xendev.dom);
-    if (!xendev->dev) {
-        snprintf(con->console, sizeof(con->console), "%s/console", dom);
-    } else {
-        snprintf(con->console, sizeof(con->console), "%s/device/console/%d", dom, xendev->dev);
-    }
-    free(dom);
-
-    type = xenstore_read_str(con->console, "type");
-    if (!type || strcmp(type, "ioemu") != 0) {
-       xen_be_printf(xendev, 1, "not for me (type=%s)\n", type);
-        ret = -1;
-        goto out;
-    }
-
-    output = xenstore_read_str(con->console, "output");
-
-    /* no Xen override, use qemu output device */
-    if (output == NULL) {
-        con->chr = serial_hds[con->xendev.dev];
-    } else {
-        snprintf(label, sizeof(label), "xencons%d", con->xendev.dev);
-        con->chr = qemu_chr_new(label, output, NULL);
-    }
-
-    xenstore_store_pv_console_info(con->xendev.dev, con->chr);
-
-out:
-    g_free(type);
-    return ret;
-}
-
-static int con_initialise(struct XenDevice *xendev)
-{
-    struct XenConsole *con = container_of(xendev, struct XenConsole, xendev);
-    int limit;
-
-    if (xenstore_read_int(con->console, "ring-ref", &con->ring_ref) == -1)
-       return -1;
-    if (xenstore_read_int(con->console, "port", &con->xendev.remote_port) == -1)
-       return -1;
-    if (xenstore_read_int(con->console, "limit", &limit) == 0)
-       con->buffer.max_capacity = limit;
-
-    if (!xendev->dev) {
-        con->sring = xc_map_foreign_range(xen_xc, con->xendev.dom,
-                                          XC_PAGE_SIZE,
-                                          PROT_READ|PROT_WRITE,
-                                          con->ring_ref);
-    } else {
-        con->sring = xc_gnttab_map_grant_ref(xendev->gnttabdev, con->xendev.dom,
-                                             con->ring_ref,
-                                             PROT_READ|PROT_WRITE);
-    }
-    if (!con->sring)
-       return -1;
-
-    xen_be_bind_evtchn(&con->xendev);
-    if (con->chr) {
-        if (qemu_chr_fe_claim(con->chr) == 0) {
-            qemu_chr_add_handlers(con->chr, xencons_can_receive,
-                                  xencons_receive, NULL, con);
-        } else {
-            xen_be_printf(xendev, 0,
-                          "xen_console_init error chardev %s already used\n",
-                          con->chr->label);
-            con->chr = NULL;
-        }
-    }
-
-    xen_be_printf(xendev, 1, "ring mfn %d, remote port %d, local port %d, limit %zd\n",
-                 con->ring_ref,
-                 con->xendev.remote_port,
-                 con->xendev.local_port,
-                 con->buffer.max_capacity);
-    return 0;
-}
-
-static void con_disconnect(struct XenDevice *xendev)
-{
-    struct XenConsole *con = container_of(xendev, struct XenConsole, xendev);
-
-    if (!xendev->dev) {
-        return;
-    }
-    if (con->chr) {
-        qemu_chr_add_handlers(con->chr, NULL, NULL, NULL, NULL);
-        qemu_chr_fe_release(con->chr);
-    }
-    xen_be_unbind_evtchn(&con->xendev);
-
-    if (con->sring) {
-        if (!xendev->gnttabdev) {
-            munmap(con->sring, XC_PAGE_SIZE);
-        } else {
-            xc_gnttab_munmap(xendev->gnttabdev, con->sring, 1);
-        }
-       con->sring = NULL;
-    }
-}
-
-static void con_event(struct XenDevice *xendev)
-{
-    struct XenConsole *con = container_of(xendev, struct XenConsole, xendev);
-
-    buffer_append(con);
-    if (con->buffer.size - con->buffer.consumed)
-       xencons_send(con);
-}
-
-/* -------------------------------------------------------------------- */
-
-struct XenDevOps xen_console_ops = {
-    .size       = sizeof(struct XenConsole),
-    .flags      = DEVOPS_FLAG_IGNORE_STATE|DEVOPS_FLAG_NEED_GNTDEV,
-    .init       = con_init,
-    .initialise = con_initialise,
-    .event      = con_event,
-    .disconnect = con_disconnect,
-};
diff --git a/hw/xen_devconfig.c b/hw/xen_devconfig.c
deleted file mode 100644 (file)
index cdcaf62..0000000
+++ /dev/null
@@ -1,174 +0,0 @@
-#include "hw/xen_backend.h"
-#include "sysemu/blockdev.h"
-
-/* ------------------------------------------------------------- */
-
-struct xs_dirs {
-    char *xs_dir;
-    QTAILQ_ENTRY(xs_dirs) list;
-};
-static QTAILQ_HEAD(xs_dirs_head, xs_dirs) xs_cleanup = QTAILQ_HEAD_INITIALIZER(xs_cleanup);
-
-static void xen_config_cleanup_dir(char *dir)
-{
-    struct xs_dirs *d;
-
-    d = g_malloc(sizeof(*d));
-    d->xs_dir = dir;
-    QTAILQ_INSERT_TAIL(&xs_cleanup, d, list);
-}
-
-void xen_config_cleanup(void)
-{
-    struct xs_dirs *d;
-
-    QTAILQ_FOREACH(d, &xs_cleanup, list) {
-       xs_rm(xenstore, 0, d->xs_dir);
-    }
-}
-
-/* ------------------------------------------------------------- */
-
-static int xen_config_dev_mkdir(char *dev, int p)
-{
-    struct xs_permissions perms[2] = {{
-            .id    = 0, /* set owner: dom0 */
-        },{
-            .id    = xen_domid,
-            .perms = p,
-        }};
-
-    if (!xs_mkdir(xenstore, 0, dev)) {
-       xen_be_printf(NULL, 0, "xs_mkdir %s: failed\n", dev);
-       return -1;
-    }
-    xen_config_cleanup_dir(g_strdup(dev));
-
-    if (!xs_set_permissions(xenstore, 0, dev, perms, 2)) {
-       xen_be_printf(NULL, 0, "xs_set_permissions %s: failed\n", dev);
-       return -1;
-    }
-    return 0;
-}
-
-static int xen_config_dev_dirs(const char *ftype, const char *btype, int vdev,
-                              char *fe, char *be, int len)
-{
-    char *dom;
-
-    dom = xs_get_domain_path(xenstore, xen_domid);
-    snprintf(fe, len, "%s/device/%s/%d", dom, ftype, vdev);
-    free(dom);
-
-    dom = xs_get_domain_path(xenstore, 0);
-    snprintf(be, len, "%s/backend/%s/%d/%d", dom, btype, xen_domid, vdev);
-    free(dom);
-
-    xen_config_dev_mkdir(fe, XS_PERM_READ | XS_PERM_WRITE);
-    xen_config_dev_mkdir(be, XS_PERM_READ);
-    return 0;
-}
-
-static int xen_config_dev_all(char *fe, char *be)
-{
-    /* frontend */
-    if (xen_protocol)
-        xenstore_write_str(fe, "protocol", xen_protocol);
-
-    xenstore_write_int(fe, "state",           XenbusStateInitialising);
-    xenstore_write_int(fe, "backend-id",      0);
-    xenstore_write_str(fe, "backend",         be);
-
-    /* backend */
-    xenstore_write_str(be, "domain",          qemu_name ? qemu_name : "no-name");
-    xenstore_write_int(be, "online",          1);
-    xenstore_write_int(be, "state",           XenbusStateInitialising);
-    xenstore_write_int(be, "frontend-id",     xen_domid);
-    xenstore_write_str(be, "frontend",        fe);
-
-    return 0;
-}
-
-/* ------------------------------------------------------------- */
-
-int xen_config_dev_blk(DriveInfo *disk)
-{
-    char fe[256], be[256], device_name[32];
-    int vdev = 202 * 256 + 16 * disk->unit;
-    int cdrom = disk->media_cd;
-    const char *devtype = cdrom ? "cdrom" : "disk";
-    const char *mode    = cdrom ? "r"     : "w";
-    const char *filename = qemu_opt_get(disk->opts, "file");
-
-    snprintf(device_name, sizeof(device_name), "xvd%c", 'a' + disk->unit);
-    xen_be_printf(NULL, 1, "config disk %d [%s]: %s\n",
-                  disk->unit, device_name, filename);
-    xen_config_dev_dirs("vbd", "qdisk", vdev, fe, be, sizeof(fe));
-
-    /* frontend */
-    xenstore_write_int(fe, "virtual-device",  vdev);
-    xenstore_write_str(fe, "device-type",     devtype);
-
-    /* backend */
-    xenstore_write_str(be, "dev",             device_name);
-    xenstore_write_str(be, "type",            "file");
-    xenstore_write_str(be, "params",          filename);
-    xenstore_write_str(be, "mode",            mode);
-
-    /* common stuff */
-    return xen_config_dev_all(fe, be);
-}
-
-int xen_config_dev_nic(NICInfo *nic)
-{
-    char fe[256], be[256];
-    char mac[20];
-    int vlan_id = -1;
-
-    net_hub_id_for_client(nic->netdev, &vlan_id);
-    snprintf(mac, sizeof(mac), "%02x:%02x:%02x:%02x:%02x:%02x",
-             nic->macaddr.a[0], nic->macaddr.a[1], nic->macaddr.a[2],
-             nic->macaddr.a[3], nic->macaddr.a[4], nic->macaddr.a[5]);
-    xen_be_printf(NULL, 1, "config nic %d: mac=\"%s\"\n", vlan_id, mac);
-    xen_config_dev_dirs("vif", "qnic", vlan_id, fe, be, sizeof(fe));
-
-    /* frontend */
-    xenstore_write_int(fe, "handle",     vlan_id);
-    xenstore_write_str(fe, "mac",        mac);
-
-    /* backend */
-    xenstore_write_int(be, "handle",     vlan_id);
-    xenstore_write_str(be, "mac",        mac);
-
-    /* common stuff */
-    return xen_config_dev_all(fe, be);
-}
-
-int xen_config_dev_vfb(int vdev, const char *type)
-{
-    char fe[256], be[256];
-
-    xen_config_dev_dirs("vfb", "vfb", vdev, fe, be, sizeof(fe));
-
-    /* backend */
-    xenstore_write_str(be, "type",  type);
-
-    /* common stuff */
-    return xen_config_dev_all(fe, be);
-}
-
-int xen_config_dev_vkbd(int vdev)
-{
-    char fe[256], be[256];
-
-    xen_config_dev_dirs("vkbd", "vkbd", vdev, fe, be, sizeof(fe));
-    return xen_config_dev_all(fe, be);
-}
-
-int xen_config_dev_console(int vdev)
-{
-    char fe[256], be[256];
-
-    xen_config_dev_dirs("console", "console", vdev, fe, be, sizeof(fe));
-    return xen_config_dev_all(fe, be);
-}
diff --git a/hw/xen_disk.c b/hw/xen_disk.c
deleted file mode 100644 (file)
index 83329e2..0000000
+++ /dev/null
@@ -1,964 +0,0 @@
-/*
- *  xen paravirt block device backend
- *
- *  (c) Gerd Hoffmann <kraxel@redhat.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; under version 2 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
- *  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/>.
- *
- *  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>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <string.h>
-#include <unistd.h>
-#include <signal.h>
-#include <inttypes.h>
-#include <time.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <sys/ioctl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/mman.h>
-#include <sys/uio.h>
-
-#include "hw/hw.h"
-#include "hw/xen_backend.h"
-#include "hw/xen_blkif.h"
-#include "sysemu/blockdev.h"
-
-/* ------------------------------------------------------------- */
-
-static int batch_maps   = 0;
-
-static int max_requests = 32;
-
-/* ------------------------------------------------------------- */
-
-#define BLOCK_SIZE  512
-#define IOCB_COUNT  (BLKIF_MAX_SEGMENTS_PER_REQUEST + 2)
-
-struct PersistentGrant {
-    void *page;
-    struct XenBlkDev *blkdev;
-};
-
-typedef struct PersistentGrant PersistentGrant;
-
-struct ioreq {
-    blkif_request_t     req;
-    int16_t             status;
-
-    /* parsed request */
-    off_t               start;
-    QEMUIOVector        v;
-    int                 presync;
-    int                 postsync;
-    uint8_t             mapped;
-
-    /* grant mapping */
-    uint32_t            domids[BLKIF_MAX_SEGMENTS_PER_REQUEST];
-    uint32_t            refs[BLKIF_MAX_SEGMENTS_PER_REQUEST];
-    int                 prot;
-    void                *page[BLKIF_MAX_SEGMENTS_PER_REQUEST];
-    void                *pages;
-    int                 num_unmap;
-
-    /* aio status */
-    int                 aio_inflight;
-    int                 aio_errors;
-
-    struct XenBlkDev    *blkdev;
-    QLIST_ENTRY(ioreq)   list;
-    BlockAcctCookie     acct;
-};
-
-struct XenBlkDev {
-    struct XenDevice    xendev;  /* must be first */
-    char                *params;
-    char                *mode;
-    char                *type;
-    char                *dev;
-    char                *devtype;
-    const char          *fileproto;
-    const char          *filename;
-    int                 ring_ref;
-    void                *sring;
-    int64_t             file_blk;
-    int64_t             file_size;
-    int                 protocol;
-    blkif_back_rings_t  rings;
-    int                 more_work;
-    int                 cnt_map;
-
-    /* request lists */
-    QLIST_HEAD(inflight_head, ioreq) inflight;
-    QLIST_HEAD(finished_head, ioreq) finished;
-    QLIST_HEAD(freelist_head, ioreq) freelist;
-    int                 requests_total;
-    int                 requests_inflight;
-    int                 requests_finished;
-
-    /* Persistent grants extension */
-    gboolean            feature_persistent;
-    GTree               *persistent_gnts;
-    unsigned int        persistent_gnt_count;
-    unsigned int        max_grants;
-
-    /* qemu block driver */
-    DriveInfo           *dinfo;
-    BlockDriverState    *bs;
-    QEMUBH              *bh;
-};
-
-/* ------------------------------------------------------------- */
-
-static void ioreq_reset(struct ioreq *ioreq)
-{
-    memset(&ioreq->req, 0, sizeof(ioreq->req));
-    ioreq->status = 0;
-    ioreq->start = 0;
-    ioreq->presync = 0;
-    ioreq->postsync = 0;
-    ioreq->mapped = 0;
-
-    memset(ioreq->domids, 0, sizeof(ioreq->domids));
-    memset(ioreq->refs, 0, sizeof(ioreq->refs));
-    ioreq->prot = 0;
-    memset(ioreq->page, 0, sizeof(ioreq->page));
-    ioreq->pages = NULL;
-
-    ioreq->aio_inflight = 0;
-    ioreq->aio_errors = 0;
-
-    ioreq->blkdev = NULL;
-    memset(&ioreq->list, 0, sizeof(ioreq->list));
-    memset(&ioreq->acct, 0, sizeof(ioreq->acct));
-
-    qemu_iovec_reset(&ioreq->v);
-}
-
-static gint int_cmp(gconstpointer a, gconstpointer b, gpointer user_data)
-{
-    uint ua = GPOINTER_TO_UINT(a);
-    uint ub = GPOINTER_TO_UINT(b);
-    return (ua > ub) - (ua < ub);
-}
-
-static void destroy_grant(gpointer pgnt)
-{
-    PersistentGrant *grant = pgnt;
-    XenGnttab gnt = grant->blkdev->xendev.gnttabdev;
-
-    if (xc_gnttab_munmap(gnt, grant->page, 1) != 0) {
-        xen_be_printf(&grant->blkdev->xendev, 0,
-                      "xc_gnttab_munmap failed: %s\n",
-                      strerror(errno));
-    }
-    grant->blkdev->persistent_gnt_count--;
-    xen_be_printf(&grant->blkdev->xendev, 3,
-                  "unmapped grant %p\n", grant->page);
-    g_free(grant);
-}
-
-static struct ioreq *ioreq_start(struct XenBlkDev *blkdev)
-{
-    struct ioreq *ioreq = NULL;
-
-    if (QLIST_EMPTY(&blkdev->freelist)) {
-        if (blkdev->requests_total >= max_requests) {
-            goto out;
-        }
-        /* allocate new struct */
-        ioreq = g_malloc0(sizeof(*ioreq));
-        ioreq->blkdev = blkdev;
-        blkdev->requests_total++;
-        qemu_iovec_init(&ioreq->v, BLKIF_MAX_SEGMENTS_PER_REQUEST);
-    } else {
-        /* get one from freelist */
-        ioreq = QLIST_FIRST(&blkdev->freelist);
-        QLIST_REMOVE(ioreq, list);
-    }
-    QLIST_INSERT_HEAD(&blkdev->inflight, ioreq, list);
-    blkdev->requests_inflight++;
-
-out:
-    return ioreq;
-}
-
-static void ioreq_finish(struct ioreq *ioreq)
-{
-    struct XenBlkDev *blkdev = ioreq->blkdev;
-
-    QLIST_REMOVE(ioreq, list);
-    QLIST_INSERT_HEAD(&blkdev->finished, ioreq, list);
-    blkdev->requests_inflight--;
-    blkdev->requests_finished++;
-}
-
-static void ioreq_release(struct ioreq *ioreq, bool finish)
-{
-    struct XenBlkDev *blkdev = ioreq->blkdev;
-
-    QLIST_REMOVE(ioreq, list);
-    ioreq_reset(ioreq);
-    ioreq->blkdev = blkdev;
-    QLIST_INSERT_HEAD(&blkdev->freelist, ioreq, list);
-    if (finish) {
-        blkdev->requests_finished--;
-    } else {
-        blkdev->requests_inflight--;
-    }
-}
-
-/*
- * translate request into iovec + start offset
- * do sanity checks along the way
- */
-static int ioreq_parse(struct ioreq *ioreq)
-{
-    struct XenBlkDev *blkdev = ioreq->blkdev;
-    uintptr_t mem;
-    size_t len;
-    int i;
-
-    xen_be_printf(&blkdev->xendev, 3,
-                  "op %d, nr %d, handle %d, id %" PRId64 ", sector %" PRId64 "\n",
-                  ioreq->req.operation, ioreq->req.nr_segments,
-                  ioreq->req.handle, ioreq->req.id, ioreq->req.sector_number);
-    switch (ioreq->req.operation) {
-    case BLKIF_OP_READ:
-        ioreq->prot = PROT_WRITE; /* to memory */
-        break;
-    case BLKIF_OP_FLUSH_DISKCACHE:
-        ioreq->presync = 1;
-        if (!ioreq->req.nr_segments) {
-            return 0;
-        }
-        /* fall through */
-    case BLKIF_OP_WRITE:
-        ioreq->prot = PROT_READ; /* from memory */
-        break;
-    default:
-        xen_be_printf(&blkdev->xendev, 0, "error: unknown operation (%d)\n",
-                      ioreq->req.operation);
-        goto err;
-    };
-
-    if (ioreq->req.operation != BLKIF_OP_READ && blkdev->mode[0] != 'w') {
-        xen_be_printf(&blkdev->xendev, 0, "error: write req for ro device\n");
-        goto err;
-    }
-
-    ioreq->start = ioreq->req.sector_number * blkdev->file_blk;
-    for (i = 0; i < ioreq->req.nr_segments; i++) {
-        if (i == BLKIF_MAX_SEGMENTS_PER_REQUEST) {
-            xen_be_printf(&blkdev->xendev, 0, "error: nr_segments too big\n");
-            goto err;
-        }
-        if (ioreq->req.seg[i].first_sect > ioreq->req.seg[i].last_sect) {
-            xen_be_printf(&blkdev->xendev, 0, "error: first > last sector\n");
-            goto err;
-        }
-        if (ioreq->req.seg[i].last_sect * BLOCK_SIZE >= XC_PAGE_SIZE) {
-            xen_be_printf(&blkdev->xendev, 0, "error: page crossing\n");
-            goto err;
-        }
-
-        ioreq->domids[i] = blkdev->xendev.dom;
-        ioreq->refs[i]   = ioreq->req.seg[i].gref;
-
-        mem = ioreq->req.seg[i].first_sect * blkdev->file_blk;
-        len = (ioreq->req.seg[i].last_sect - ioreq->req.seg[i].first_sect + 1) * blkdev->file_blk;
-        qemu_iovec_add(&ioreq->v, (void*)mem, len);
-    }
-    if (ioreq->start + ioreq->v.size > blkdev->file_size) {
-        xen_be_printf(&blkdev->xendev, 0, "error: access beyond end of file\n");
-        goto err;
-    }
-    return 0;
-
-err:
-    ioreq->status = BLKIF_RSP_ERROR;
-    return -1;
-}
-
-static void ioreq_unmap(struct ioreq *ioreq)
-{
-    XenGnttab gnt = ioreq->blkdev->xendev.gnttabdev;
-    int i;
-
-    if (ioreq->num_unmap == 0 || ioreq->mapped == 0) {
-        return;
-    }
-    if (batch_maps) {
-        if (!ioreq->pages) {
-            return;
-        }
-        if (xc_gnttab_munmap(gnt, ioreq->pages, ioreq->num_unmap) != 0) {
-            xen_be_printf(&ioreq->blkdev->xendev, 0, "xc_gnttab_munmap failed: %s\n",
-                          strerror(errno));
-        }
-        ioreq->blkdev->cnt_map -= ioreq->num_unmap;
-        ioreq->pages = NULL;
-    } else {
-        for (i = 0; i < ioreq->num_unmap; i++) {
-            if (!ioreq->page[i]) {
-                continue;
-            }
-            if (xc_gnttab_munmap(gnt, ioreq->page[i], 1) != 0) {
-                xen_be_printf(&ioreq->blkdev->xendev, 0, "xc_gnttab_munmap failed: %s\n",
-                              strerror(errno));
-            }
-            ioreq->blkdev->cnt_map--;
-            ioreq->page[i] = NULL;
-        }
-    }
-    ioreq->mapped = 0;
-}
-
-static int ioreq_map(struct ioreq *ioreq)
-{
-    XenGnttab gnt = ioreq->blkdev->xendev.gnttabdev;
-    uint32_t domids[BLKIF_MAX_SEGMENTS_PER_REQUEST];
-    uint32_t refs[BLKIF_MAX_SEGMENTS_PER_REQUEST];
-    void *page[BLKIF_MAX_SEGMENTS_PER_REQUEST];
-    int i, j, new_maps = 0;
-    PersistentGrant *grant;
-    /* domids and refs variables will contain the information necessary
-     * to map the grants that are needed to fulfill this request.
-     *
-     * After mapping the needed grants, the page array will contain the
-     * memory address of each granted page in the order specified in ioreq
-     * (disregarding if it's a persistent grant or not).
-     */
-
-    if (ioreq->v.niov == 0 || ioreq->mapped == 1) {
-        return 0;
-    }
-    if (ioreq->blkdev->feature_persistent) {
-        for (i = 0; i < ioreq->v.niov; i++) {
-            grant = g_tree_lookup(ioreq->blkdev->persistent_gnts,
-                                    GUINT_TO_POINTER(ioreq->refs[i]));
-
-            if (grant != NULL) {
-                page[i] = grant->page;
-                xen_be_printf(&ioreq->blkdev->xendev, 3,
-                              "using persistent-grant %" PRIu32 "\n",
-                              ioreq->refs[i]);
-            } else {
-                    /* Add the grant to the list of grants that
-                     * should be mapped
-                     */
-                    domids[new_maps] = ioreq->domids[i];
-                    refs[new_maps] = ioreq->refs[i];
-                    page[i] = NULL;
-                    new_maps++;
-            }
-        }
-        /* Set the protection to RW, since grants may be reused later
-         * with a different protection than the one needed for this request
-         */
-        ioreq->prot = PROT_WRITE | PROT_READ;
-    } else {
-        /* All grants in the request should be mapped */
-        memcpy(refs, ioreq->refs, sizeof(refs));
-        memcpy(domids, ioreq->domids, sizeof(domids));
-        memset(page, 0, sizeof(page));
-        new_maps = ioreq->v.niov;
-    }
-
-    if (batch_maps && new_maps) {
-        ioreq->pages = xc_gnttab_map_grant_refs
-            (gnt, new_maps, domids, refs, ioreq->prot);
-        if (ioreq->pages == NULL) {
-            xen_be_printf(&ioreq->blkdev->xendev, 0,
-                          "can't map %d grant refs (%s, %d maps)\n",
-                          new_maps, strerror(errno), ioreq->blkdev->cnt_map);
-            return -1;
-        }
-        for (i = 0, j = 0; i < ioreq->v.niov; i++) {
-            if (page[i] == NULL) {
-                page[i] = ioreq->pages + (j++) * XC_PAGE_SIZE;
-            }
-        }
-        ioreq->blkdev->cnt_map += new_maps;
-    } else if (new_maps)  {
-        for (i = 0; i < new_maps; i++) {
-            ioreq->page[i] = xc_gnttab_map_grant_ref
-                (gnt, domids[i], refs[i], ioreq->prot);
-            if (ioreq->page[i] == NULL) {
-                xen_be_printf(&ioreq->blkdev->xendev, 0,
-                              "can't map grant ref %d (%s, %d maps)\n",
-                              refs[i], strerror(errno), ioreq->blkdev->cnt_map);
-                ioreq_unmap(ioreq);
-                return -1;
-            }
-            ioreq->blkdev->cnt_map++;
-        }
-        for (i = 0, j = 0; i < ioreq->v.niov; i++) {
-            if (page[i] == NULL) {
-                page[i] = ioreq->page[j++];
-            }
-        }
-    }
-    if (ioreq->blkdev->feature_persistent) {
-        while ((ioreq->blkdev->persistent_gnt_count < ioreq->blkdev->max_grants)
-              && new_maps) {
-            /* Go through the list of newly mapped grants and add as many
-             * as possible to the list of persistently mapped grants.
-             *
-             * Since we start at the end of ioreq->page(s), we only need
-             * to decrease new_maps to prevent this granted pages from
-             * being unmapped in ioreq_unmap.
-             */
-            grant = g_malloc0(sizeof(*grant));
-            new_maps--;
-            if (batch_maps) {
-                grant->page = ioreq->pages + (new_maps) * XC_PAGE_SIZE;
-            } else {
-                grant->page = ioreq->page[new_maps];
-            }
-            grant->blkdev = ioreq->blkdev;
-            xen_be_printf(&ioreq->blkdev->xendev, 3,
-                          "adding grant %" PRIu32 " page: %p\n",
-                          refs[new_maps], grant->page);
-            g_tree_insert(ioreq->blkdev->persistent_gnts,
-                          GUINT_TO_POINTER(refs[new_maps]),
-                          grant);
-            ioreq->blkdev->persistent_gnt_count++;
-        }
-    }
-    for (i = 0; i < ioreq->v.niov; i++) {
-        ioreq->v.iov[i].iov_base += (uintptr_t)page[i];
-    }
-    ioreq->mapped = 1;
-    ioreq->num_unmap = new_maps;
-    return 0;
-}
-
-static int ioreq_runio_qemu_aio(struct ioreq *ioreq);
-
-static void qemu_aio_complete(void *opaque, int ret)
-{
-    struct ioreq *ioreq = opaque;
-
-    if (ret != 0) {
-        xen_be_printf(&ioreq->blkdev->xendev, 0, "%s I/O error\n",
-                      ioreq->req.operation == BLKIF_OP_READ ? "read" : "write");
-        ioreq->aio_errors++;
-    }
-
-    ioreq->aio_inflight--;
-    if (ioreq->presync) {
-        ioreq->presync = 0;
-        ioreq_runio_qemu_aio(ioreq);
-        return;
-    }
-    if (ioreq->aio_inflight > 0) {
-        return;
-    }
-    if (ioreq->postsync) {
-        ioreq->postsync = 0;
-        ioreq->aio_inflight++;
-        bdrv_aio_flush(ioreq->blkdev->bs, qemu_aio_complete, ioreq);
-        return;
-    }
-
-    ioreq->status = ioreq->aio_errors ? BLKIF_RSP_ERROR : BLKIF_RSP_OKAY;
-    ioreq_unmap(ioreq);
-    ioreq_finish(ioreq);
-    bdrv_acct_done(ioreq->blkdev->bs, &ioreq->acct);
-    qemu_bh_schedule(ioreq->blkdev->bh);
-}
-
-static int ioreq_runio_qemu_aio(struct ioreq *ioreq)
-{
-    struct XenBlkDev *blkdev = ioreq->blkdev;
-
-    if (ioreq->req.nr_segments && ioreq_map(ioreq) == -1) {
-        goto err_no_map;
-    }
-
-    ioreq->aio_inflight++;
-    if (ioreq->presync) {
-        bdrv_aio_flush(ioreq->blkdev->bs, qemu_aio_complete, ioreq);
-        return 0;
-    }
-
-    switch (ioreq->req.operation) {
-    case BLKIF_OP_READ:
-        bdrv_acct_start(blkdev->bs, &ioreq->acct, ioreq->v.size, BDRV_ACCT_READ);
-        ioreq->aio_inflight++;
-        bdrv_aio_readv(blkdev->bs, ioreq->start / BLOCK_SIZE,
-                       &ioreq->v, ioreq->v.size / BLOCK_SIZE,
-                       qemu_aio_complete, ioreq);
-        break;
-    case BLKIF_OP_WRITE:
-    case BLKIF_OP_FLUSH_DISKCACHE:
-        if (!ioreq->req.nr_segments) {
-            break;
-        }
-
-        bdrv_acct_start(blkdev->bs, &ioreq->acct, ioreq->v.size, BDRV_ACCT_WRITE);
-        ioreq->aio_inflight++;
-        bdrv_aio_writev(blkdev->bs, ioreq->start / BLOCK_SIZE,
-                        &ioreq->v, ioreq->v.size / BLOCK_SIZE,
-                        qemu_aio_complete, ioreq);
-        break;
-    default:
-        /* unknown operation (shouldn't happen -- parse catches this) */
-        goto err;
-    }
-
-    qemu_aio_complete(ioreq, 0);
-
-    return 0;
-
-err:
-    ioreq_unmap(ioreq);
-err_no_map:
-    ioreq_finish(ioreq);
-    ioreq->status = BLKIF_RSP_ERROR;
-    return -1;
-}
-
-static int blk_send_response_one(struct ioreq *ioreq)
-{
-    struct XenBlkDev  *blkdev = ioreq->blkdev;
-    int               send_notify   = 0;
-    int               have_requests = 0;
-    blkif_response_t  resp;
-    void              *dst;
-
-    resp.id        = ioreq->req.id;
-    resp.operation = ioreq->req.operation;
-    resp.status    = ioreq->status;
-
-    /* Place on the response ring for the relevant domain. */
-    switch (blkdev->protocol) {
-    case BLKIF_PROTOCOL_NATIVE:
-        dst = RING_GET_RESPONSE(&blkdev->rings.native, blkdev->rings.native.rsp_prod_pvt);
-        break;
-    case BLKIF_PROTOCOL_X86_32:
-        dst = RING_GET_RESPONSE(&blkdev->rings.x86_32_part,
-                                blkdev->rings.x86_32_part.rsp_prod_pvt);
-        break;
-    case BLKIF_PROTOCOL_X86_64:
-        dst = RING_GET_RESPONSE(&blkdev->rings.x86_64_part,
-                                blkdev->rings.x86_64_part.rsp_prod_pvt);
-        break;
-    default:
-        dst = NULL;
-    }
-    memcpy(dst, &resp, sizeof(resp));
-    blkdev->rings.common.rsp_prod_pvt++;
-
-    RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&blkdev->rings.common, send_notify);
-    if (blkdev->rings.common.rsp_prod_pvt == blkdev->rings.common.req_cons) {
-        /*
-         * Tail check for pending requests. Allows frontend to avoid
-         * notifications if requests are already in flight (lower
-         * overheads and promotes batching).
-         */
-        RING_FINAL_CHECK_FOR_REQUESTS(&blkdev->rings.common, have_requests);
-    } else if (RING_HAS_UNCONSUMED_REQUESTS(&blkdev->rings.common)) {
-        have_requests = 1;
-    }
-
-    if (have_requests) {
-        blkdev->more_work++;
-    }
-    return send_notify;
-}
-
-/* walk finished list, send outstanding responses, free requests */
-static void blk_send_response_all(struct XenBlkDev *blkdev)
-{
-    struct ioreq *ioreq;
-    int send_notify = 0;
-
-    while (!QLIST_EMPTY(&blkdev->finished)) {
-        ioreq = QLIST_FIRST(&blkdev->finished);
-        send_notify += blk_send_response_one(ioreq);
-        ioreq_release(ioreq, true);
-    }
-    if (send_notify) {
-        xen_be_send_notify(&blkdev->xendev);
-    }
-}
-
-static int blk_get_request(struct XenBlkDev *blkdev, struct ioreq *ioreq, RING_IDX rc)
-{
-    switch (blkdev->protocol) {
-    case BLKIF_PROTOCOL_NATIVE:
-        memcpy(&ioreq->req, RING_GET_REQUEST(&blkdev->rings.native, rc),
-               sizeof(ioreq->req));
-        break;
-    case BLKIF_PROTOCOL_X86_32:
-        blkif_get_x86_32_req(&ioreq->req,
-                             RING_GET_REQUEST(&blkdev->rings.x86_32_part, rc));
-        break;
-    case BLKIF_PROTOCOL_X86_64:
-        blkif_get_x86_64_req(&ioreq->req,
-                             RING_GET_REQUEST(&blkdev->rings.x86_64_part, rc));
-        break;
-    }
-    return 0;
-}
-
-static void blk_handle_requests(struct XenBlkDev *blkdev)
-{
-    RING_IDX rc, rp;
-    struct ioreq *ioreq;
-
-    blkdev->more_work = 0;
-
-    rc = blkdev->rings.common.req_cons;
-    rp = blkdev->rings.common.sring->req_prod;
-    xen_rmb(); /* Ensure we see queued requests up to 'rp'. */
-
-    blk_send_response_all(blkdev);
-    while (rc != rp) {
-        /* pull request from ring */
-        if (RING_REQUEST_CONS_OVERFLOW(&blkdev->rings.common, rc)) {
-            break;
-        }
-        ioreq = ioreq_start(blkdev);
-        if (ioreq == NULL) {
-            blkdev->more_work++;
-            break;
-        }
-        blk_get_request(blkdev, ioreq, rc);
-        blkdev->rings.common.req_cons = ++rc;
-
-        /* parse them */
-        if (ioreq_parse(ioreq) != 0) {
-            if (blk_send_response_one(ioreq)) {
-                xen_be_send_notify(&blkdev->xendev);
-            }
-            ioreq_release(ioreq, false);
-            continue;
-        }
-
-        ioreq_runio_qemu_aio(ioreq);
-    }
-
-    if (blkdev->more_work && blkdev->requests_inflight < max_requests) {
-        qemu_bh_schedule(blkdev->bh);
-    }
-}
-
-/* ------------------------------------------------------------- */
-
-static void blk_bh(void *opaque)
-{
-    struct XenBlkDev *blkdev = opaque;
-    blk_handle_requests(blkdev);
-}
-
-/*
- * We need to account for the grant allocations requiring contiguous
- * chunks; the worst case number would be
- *     max_req * max_seg + (max_req - 1) * (max_seg - 1) + 1,
- * but in order to keep things simple just use
- *     2 * max_req * max_seg.
- */
-#define MAX_GRANTS(max_req, max_seg) (2 * (max_req) * (max_seg))
-
-static void blk_alloc(struct XenDevice *xendev)
-{
-    struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
-
-    QLIST_INIT(&blkdev->inflight);
-    QLIST_INIT(&blkdev->finished);
-    QLIST_INIT(&blkdev->freelist);
-    blkdev->bh = qemu_bh_new(blk_bh, blkdev);
-    if (xen_mode != XEN_EMULATE) {
-        batch_maps = 1;
-    }
-    if (xc_gnttab_set_max_grants(xendev->gnttabdev,
-            MAX_GRANTS(max_requests, BLKIF_MAX_SEGMENTS_PER_REQUEST)) < 0) {
-        xen_be_printf(xendev, 0, "xc_gnttab_set_max_grants failed: %s\n",
-                      strerror(errno));
-    }
-}
-
-static int blk_init(struct XenDevice *xendev)
-{
-    struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
-    int index, qflags, info = 0;
-
-    /* read xenstore entries */
-    if (blkdev->params == NULL) {
-        char *h = NULL;
-        blkdev->params = xenstore_read_be_str(&blkdev->xendev, "params");
-        if (blkdev->params != NULL) {
-            h = strchr(blkdev->params, ':');
-        }
-        if (h != NULL) {
-            blkdev->fileproto = blkdev->params;
-            blkdev->filename  = h+1;
-            *h = 0;
-        } else {
-            blkdev->fileproto = "<unset>";
-            blkdev->filename  = blkdev->params;
-        }
-    }
-    if (!strcmp("aio", blkdev->fileproto)) {
-        blkdev->fileproto = "raw";
-    }
-    if (blkdev->mode == NULL) {
-        blkdev->mode = xenstore_read_be_str(&blkdev->xendev, "mode");
-    }
-    if (blkdev->type == NULL) {
-        blkdev->type = xenstore_read_be_str(&blkdev->xendev, "type");
-    }
-    if (blkdev->dev == NULL) {
-        blkdev->dev = xenstore_read_be_str(&blkdev->xendev, "dev");
-    }
-    if (blkdev->devtype == NULL) {
-        blkdev->devtype = xenstore_read_be_str(&blkdev->xendev, "device-type");
-    }
-
-    /* do we have all we need? */
-    if (blkdev->params == NULL ||
-        blkdev->mode == NULL   ||
-        blkdev->type == NULL   ||
-        blkdev->dev == NULL) {
-        goto out_error;
-    }
-
-    /* read-only ? */
-    qflags = BDRV_O_NOCACHE | BDRV_O_CACHE_WB | BDRV_O_NATIVE_AIO;
-    if (strcmp(blkdev->mode, "w") == 0) {
-        qflags |= BDRV_O_RDWR;
-    } else {
-        info  |= VDISK_READONLY;
-    }
-
-    /* cdrom ? */
-    if (blkdev->devtype && !strcmp(blkdev->devtype, "cdrom")) {
-        info  |= VDISK_CDROM;
-    }
-
-    /* init qemu block driver */
-    index = (blkdev->xendev.dev - 202 * 256) / 16;
-    blkdev->dinfo = drive_get(IF_XEN, 0, index);
-    if (!blkdev->dinfo) {
-        /* setup via xenbus -> create new block driver instance */
-        xen_be_printf(&blkdev->xendev, 2, "create new bdrv (xenbus setup)\n");
-        blkdev->bs = bdrv_new(blkdev->dev);
-        if (blkdev->bs) {
-            if (bdrv_open(blkdev->bs, blkdev->filename, NULL, qflags,
-                        bdrv_find_whitelisted_format(blkdev->fileproto)) != 0) {
-                bdrv_delete(blkdev->bs);
-                blkdev->bs = NULL;
-            }
-        }
-        if (!blkdev->bs) {
-            goto out_error;
-        }
-    } else {
-        /* setup via qemu cmdline -> already setup for us */
-        xen_be_printf(&blkdev->xendev, 2, "get configured bdrv (cmdline setup)\n");
-        blkdev->bs = blkdev->dinfo->bdrv;
-    }
-    bdrv_attach_dev_nofail(blkdev->bs, blkdev);
-    blkdev->file_blk  = BLOCK_SIZE;
-    blkdev->file_size = bdrv_getlength(blkdev->bs);
-    if (blkdev->file_size < 0) {
-        xen_be_printf(&blkdev->xendev, 1, "bdrv_getlength: %d (%s) | drv %s\n",
-                      (int)blkdev->file_size, strerror(-blkdev->file_size),
-                      bdrv_get_format_name(blkdev->bs) ?: "-");
-        blkdev->file_size = 0;
-    }
-
-    xen_be_printf(xendev, 1, "type \"%s\", fileproto \"%s\", filename \"%s\","
-                  " size %" PRId64 " (%" PRId64 " MB)\n",
-                  blkdev->type, blkdev->fileproto, blkdev->filename,
-                  blkdev->file_size, blkdev->file_size >> 20);
-
-    /* fill info */
-    xenstore_write_be_int(&blkdev->xendev, "feature-flush-cache", 1);
-    xenstore_write_be_int(&blkdev->xendev, "feature-persistent", 1);
-    xenstore_write_be_int(&blkdev->xendev, "info",            info);
-    xenstore_write_be_int(&blkdev->xendev, "sector-size",     blkdev->file_blk);
-    xenstore_write_be_int(&blkdev->xendev, "sectors",
-                          blkdev->file_size / blkdev->file_blk);
-    return 0;
-
-out_error:
-    g_free(blkdev->params);
-    blkdev->params = NULL;
-    g_free(blkdev->mode);
-    blkdev->mode = NULL;
-    g_free(blkdev->type);
-    blkdev->type = NULL;
-    g_free(blkdev->dev);
-    blkdev->dev = NULL;
-    g_free(blkdev->devtype);
-    blkdev->devtype = NULL;
-    return -1;
-}
-
-static int blk_connect(struct XenDevice *xendev)
-{
-    struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
-    int pers;
-
-    if (xenstore_read_fe_int(&blkdev->xendev, "ring-ref", &blkdev->ring_ref) == -1) {
-        return -1;
-    }
-    if (xenstore_read_fe_int(&blkdev->xendev, "event-channel",
-                             &blkdev->xendev.remote_port) == -1) {
-        return -1;
-    }
-    if (xenstore_read_fe_int(&blkdev->xendev, "feature-persistent", &pers)) {
-        blkdev->feature_persistent = FALSE;
-    } else {
-        blkdev->feature_persistent = !!pers;
-    }
-
-    blkdev->protocol = BLKIF_PROTOCOL_NATIVE;
-    if (blkdev->xendev.protocol) {
-        if (strcmp(blkdev->xendev.protocol, XEN_IO_PROTO_ABI_X86_32) == 0) {
-            blkdev->protocol = BLKIF_PROTOCOL_X86_32;
-        }
-        if (strcmp(blkdev->xendev.protocol, XEN_IO_PROTO_ABI_X86_64) == 0) {
-            blkdev->protocol = BLKIF_PROTOCOL_X86_64;
-        }
-    }
-
-    blkdev->sring = xc_gnttab_map_grant_ref(blkdev->xendev.gnttabdev,
-                                            blkdev->xendev.dom,
-                                            blkdev->ring_ref,
-                                            PROT_READ | PROT_WRITE);
-    if (!blkdev->sring) {
-        return -1;
-    }
-    blkdev->cnt_map++;
-
-    switch (blkdev->protocol) {
-    case BLKIF_PROTOCOL_NATIVE:
-    {
-        blkif_sring_t *sring_native = blkdev->sring;
-        BACK_RING_INIT(&blkdev->rings.native, sring_native, XC_PAGE_SIZE);
-        break;
-    }
-    case BLKIF_PROTOCOL_X86_32:
-    {
-        blkif_x86_32_sring_t *sring_x86_32 = blkdev->sring;
-
-        BACK_RING_INIT(&blkdev->rings.x86_32_part, sring_x86_32, XC_PAGE_SIZE);
-        break;
-    }
-    case BLKIF_PROTOCOL_X86_64:
-    {
-        blkif_x86_64_sring_t *sring_x86_64 = blkdev->sring;
-
-        BACK_RING_INIT(&blkdev->rings.x86_64_part, sring_x86_64, XC_PAGE_SIZE);
-        break;
-    }
-    }
-
-    if (blkdev->feature_persistent) {
-        /* Init persistent grants */
-        blkdev->max_grants = max_requests * BLKIF_MAX_SEGMENTS_PER_REQUEST;
-        blkdev->persistent_gnts = g_tree_new_full((GCompareDataFunc)int_cmp,
-                                             NULL, NULL,
-                                             (GDestroyNotify)destroy_grant);
-        blkdev->persistent_gnt_count = 0;
-    }
-
-    xen_be_bind_evtchn(&blkdev->xendev);
-
-    xen_be_printf(&blkdev->xendev, 1, "ok: proto %s, ring-ref %d, "
-                  "remote port %d, local port %d\n",
-                  blkdev->xendev.protocol, blkdev->ring_ref,
-                  blkdev->xendev.remote_port, blkdev->xendev.local_port);
-    return 0;
-}
-
-static void blk_disconnect(struct XenDevice *xendev)
-{
-    struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
-
-    if (blkdev->bs) {
-        if (!blkdev->dinfo) {
-            /* close/delete only if we created it ourself */
-            bdrv_close(blkdev->bs);
-            bdrv_detach_dev(blkdev->bs, blkdev);
-            bdrv_delete(blkdev->bs);
-        }
-        blkdev->bs = NULL;
-    }
-    xen_be_unbind_evtchn(&blkdev->xendev);
-
-    if (blkdev->sring) {
-        xc_gnttab_munmap(blkdev->xendev.gnttabdev, blkdev->sring, 1);
-        blkdev->cnt_map--;
-        blkdev->sring = NULL;
-    }
-}
-
-static int blk_free(struct XenDevice *xendev)
-{
-    struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
-    struct ioreq *ioreq;
-
-    if (blkdev->bs || blkdev->sring) {
-        blk_disconnect(xendev);
-    }
-
-    /* Free persistent grants */
-    if (blkdev->feature_persistent) {
-        g_tree_destroy(blkdev->persistent_gnts);
-    }
-
-    while (!QLIST_EMPTY(&blkdev->freelist)) {
-        ioreq = QLIST_FIRST(&blkdev->freelist);
-        QLIST_REMOVE(ioreq, list);
-        qemu_iovec_destroy(&ioreq->v);
-        g_free(ioreq);
-    }
-
-    g_free(blkdev->params);
-    g_free(blkdev->mode);
-    g_free(blkdev->type);
-    g_free(blkdev->dev);
-    g_free(blkdev->devtype);
-    qemu_bh_delete(blkdev->bh);
-    return 0;
-}
-
-static void blk_event(struct XenDevice *xendev)
-{
-    struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
-
-    qemu_bh_schedule(blkdev->bh);
-}
-
-struct XenDevOps xen_blkdev_ops = {
-    .size       = sizeof(struct XenBlkDev),
-    .flags      = DEVOPS_FLAG_NEED_GNTDEV,
-    .alloc      = blk_alloc,
-    .init       = blk_init,
-    .initialise    = blk_connect,
-    .disconnect = blk_disconnect,
-    .event      = blk_event,
-    .free       = blk_free,
-};
diff --git a/hw/xen_domainbuild.h b/hw/xen_domainbuild.h
deleted file mode 100644 (file)
index 681cbe5..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-#ifndef QEMU_HW_XEN_DOMAINBUILD_H
-#define QEMU_HW_XEN_DOMAINBUILD_H 1
-
-#include "hw/xen_common.h"
-
-int xenstore_domain_init1(const char *kernel, const char *ramdisk,
-                          const char *cmdline);
-int xenstore_domain_init2(int xenstore_port, int xenstore_mfn,
-                          int console_port, int console_mfn);
-int xen_domain_build_pv(const char *kernel, const char *ramdisk,
-                        const char *cmdline);
-
-#endif /* QEMU_HW_XEN_DOMAINBUILD_H */
diff --git a/hw/xen_nic.c b/hw/xen_nic.c
deleted file mode 100644 (file)
index b6d3679..0000000
+++ /dev/null
@@ -1,439 +0,0 @@
-/*
- *  xen paravirt network card backend
- *
- *  (c) Gerd Hoffmann <kraxel@redhat.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; under version 2 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
- *  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/>.
- *
- *  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>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <string.h>
-#include <unistd.h>
-#include <signal.h>
-#include <inttypes.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <sys/socket.h>
-#include <sys/ioctl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/mman.h>
-#include <sys/wait.h>
-
-#include "hw/hw.h"
-#include "net/net.h"
-#include "net/checksum.h"
-#include "net/util.h"
-#include "hw/xen_backend.h"
-
-#include <xen/io/netif.h>
-
-/* ------------------------------------------------------------- */
-
-struct XenNetDev {
-    struct XenDevice      xendev;  /* must be first */
-    char                  *mac;
-    int                   tx_work;
-    int                   tx_ring_ref;
-    int                   rx_ring_ref;
-    struct netif_tx_sring *txs;
-    struct netif_rx_sring *rxs;
-    netif_tx_back_ring_t  tx_ring;
-    netif_rx_back_ring_t  rx_ring;
-    NICConf               conf;
-    NICState              *nic;
-};
-
-/* ------------------------------------------------------------- */
-
-static void net_tx_response(struct XenNetDev *netdev, netif_tx_request_t *txp, int8_t st)
-{
-    RING_IDX i = netdev->tx_ring.rsp_prod_pvt;
-    netif_tx_response_t *resp;
-    int notify;
-
-    resp = RING_GET_RESPONSE(&netdev->tx_ring, i);
-    resp->id     = txp->id;
-    resp->status = st;
-
-#if 0
-    if (txp->flags & NETTXF_extra_info) {
-        RING_GET_RESPONSE(&netdev->tx_ring, ++i)->status = NETIF_RSP_NULL;
-    }
-#endif
-
-    netdev->tx_ring.rsp_prod_pvt = ++i;
-    RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&netdev->tx_ring, notify);
-    if (notify) {
-        xen_be_send_notify(&netdev->xendev);
-    }
-
-    if (i == netdev->tx_ring.req_cons) {
-        int more_to_do;
-        RING_FINAL_CHECK_FOR_REQUESTS(&netdev->tx_ring, more_to_do);
-        if (more_to_do) {
-            netdev->tx_work++;
-        }
-    }
-}
-
-static void net_tx_error(struct XenNetDev *netdev, netif_tx_request_t *txp, RING_IDX end)
-{
-#if 0
-    /*
-     * Hmm, why netback fails everything in the ring?
-     * Should we do that even when not supporting SG and TSO?
-     */
-    RING_IDX cons = netdev->tx_ring.req_cons;
-
-    do {
-        make_tx_response(netif, txp, NETIF_RSP_ERROR);
-        if (cons >= end) {
-            break;
-        }
-        txp = RING_GET_REQUEST(&netdev->tx_ring, cons++);
-    } while (1);
-    netdev->tx_ring.req_cons = cons;
-    netif_schedule_work(netif);
-    netif_put(netif);
-#else
-    net_tx_response(netdev, txp, NETIF_RSP_ERROR);
-#endif
-}
-
-static void net_tx_packets(struct XenNetDev *netdev)
-{
-    netif_tx_request_t txreq;
-    RING_IDX rc, rp;
-    void *page;
-    void *tmpbuf = NULL;
-
-    for (;;) {
-        rc = netdev->tx_ring.req_cons;
-        rp = netdev->tx_ring.sring->req_prod;
-        xen_rmb(); /* Ensure we see queued requests up to 'rp'. */
-
-        while ((rc != rp)) {
-            if (RING_REQUEST_CONS_OVERFLOW(&netdev->tx_ring, rc)) {
-                break;
-            }
-            memcpy(&txreq, RING_GET_REQUEST(&netdev->tx_ring, rc), sizeof(txreq));
-            netdev->tx_ring.req_cons = ++rc;
-
-#if 1
-            /* should not happen in theory, we don't announce the *
-             * feature-{sg,gso,whatelse} flags in xenstore (yet?) */
-            if (txreq.flags & NETTXF_extra_info) {
-                xen_be_printf(&netdev->xendev, 0, "FIXME: extra info flag\n");
-                net_tx_error(netdev, &txreq, rc);
-                continue;
-            }
-            if (txreq.flags & NETTXF_more_data) {
-                xen_be_printf(&netdev->xendev, 0, "FIXME: more data flag\n");
-                net_tx_error(netdev, &txreq, rc);
-                continue;
-            }
-#endif
-
-            if (txreq.size < 14) {
-                xen_be_printf(&netdev->xendev, 0, "bad packet size: %d\n", txreq.size);
-                net_tx_error(netdev, &txreq, rc);
-                continue;
-            }
-
-            if ((txreq.offset + txreq.size) > XC_PAGE_SIZE) {
-                xen_be_printf(&netdev->xendev, 0, "error: page crossing\n");
-                net_tx_error(netdev, &txreq, rc);
-                continue;
-            }
-
-            xen_be_printf(&netdev->xendev, 3, "tx packet ref %d, off %d, len %d, flags 0x%x%s%s%s%s\n",
-                          txreq.gref, txreq.offset, txreq.size, txreq.flags,
-                          (txreq.flags & NETTXF_csum_blank)     ? " csum_blank"     : "",
-                          (txreq.flags & NETTXF_data_validated) ? " data_validated" : "",
-                          (txreq.flags & NETTXF_more_data)      ? " more_data"      : "",
-                          (txreq.flags & NETTXF_extra_info)     ? " extra_info"     : "");
-
-            page = xc_gnttab_map_grant_ref(netdev->xendev.gnttabdev,
-                                           netdev->xendev.dom,
-                                           txreq.gref, PROT_READ);
-            if (page == NULL) {
-                xen_be_printf(&netdev->xendev, 0, "error: tx gref dereference failed (%d)\n",
-                              txreq.gref);
-                net_tx_error(netdev, &txreq, rc);
-                continue;
-            }
-            if (txreq.flags & NETTXF_csum_blank) {
-                /* have read-only mapping -> can't fill checksum in-place */
-                if (!tmpbuf) {
-                    tmpbuf = g_malloc(XC_PAGE_SIZE);
-                }
-                memcpy(tmpbuf, page + txreq.offset, txreq.size);
-                net_checksum_calculate(tmpbuf, txreq.size);
-                qemu_send_packet(qemu_get_queue(netdev->nic), tmpbuf,
-                                 txreq.size);
-            } else {
-                qemu_send_packet(qemu_get_queue(netdev->nic),
-                                 page + txreq.offset, txreq.size);
-            }
-            xc_gnttab_munmap(netdev->xendev.gnttabdev, page, 1);
-            net_tx_response(netdev, &txreq, NETIF_RSP_OKAY);
-        }
-        if (!netdev->tx_work) {
-            break;
-        }
-        netdev->tx_work = 0;
-    }
-    g_free(tmpbuf);
-}
-
-/* ------------------------------------------------------------- */
-
-static void net_rx_response(struct XenNetDev *netdev,
-                            netif_rx_request_t *req, int8_t st,
-                            uint16_t offset, uint16_t size,
-                            uint16_t flags)
-{
-    RING_IDX i = netdev->rx_ring.rsp_prod_pvt;
-    netif_rx_response_t *resp;
-    int notify;
-
-    resp = RING_GET_RESPONSE(&netdev->rx_ring, i);
-    resp->offset     = offset;
-    resp->flags      = flags;
-    resp->id         = req->id;
-    resp->status     = (int16_t)size;
-    if (st < 0) {
-        resp->status = (int16_t)st;
-    }
-
-    xen_be_printf(&netdev->xendev, 3, "rx response: idx %d, status %d, flags 0x%x\n",
-                  i, resp->status, resp->flags);
-
-    netdev->rx_ring.rsp_prod_pvt = ++i;
-    RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&netdev->rx_ring, notify);
-    if (notify) {
-        xen_be_send_notify(&netdev->xendev);
-    }
-}
-
-#define NET_IP_ALIGN 2
-
-static int net_rx_ok(NetClientState *nc)
-{
-    struct XenNetDev *netdev = qemu_get_nic_opaque(nc);
-    RING_IDX rc, rp;
-
-    if (netdev->xendev.be_state != XenbusStateConnected) {
-        return 0;
-    }
-
-    rc = netdev->rx_ring.req_cons;
-    rp = netdev->rx_ring.sring->req_prod;
-    xen_rmb();
-
-    if (rc == rp || RING_REQUEST_CONS_OVERFLOW(&netdev->rx_ring, rc)) {
-        xen_be_printf(&netdev->xendev, 2, "%s: no rx buffers (%d/%d)\n",
-                      __FUNCTION__, rc, rp);
-        return 0;
-    }
-    return 1;
-}
-
-static ssize_t net_rx_packet(NetClientState *nc, const uint8_t *buf, size_t size)
-{
-    struct XenNetDev *netdev = qemu_get_nic_opaque(nc);
-    netif_rx_request_t rxreq;
-    RING_IDX rc, rp;
-    void *page;
-
-    if (netdev->xendev.be_state != XenbusStateConnected) {
-        return -1;
-    }
-
-    rc = netdev->rx_ring.req_cons;
-    rp = netdev->rx_ring.sring->req_prod;
-    xen_rmb(); /* Ensure we see queued requests up to 'rp'. */
-
-    if (rc == rp || RING_REQUEST_CONS_OVERFLOW(&netdev->rx_ring, rc)) {
-        xen_be_printf(&netdev->xendev, 2, "no buffer, drop packet\n");
-        return -1;
-    }
-    if (size > XC_PAGE_SIZE - NET_IP_ALIGN) {
-        xen_be_printf(&netdev->xendev, 0, "packet too big (%lu > %ld)",
-                      (unsigned long)size, XC_PAGE_SIZE - NET_IP_ALIGN);
-        return -1;
-    }
-
-    memcpy(&rxreq, RING_GET_REQUEST(&netdev->rx_ring, rc), sizeof(rxreq));
-    netdev->rx_ring.req_cons = ++rc;
-
-    page = xc_gnttab_map_grant_ref(netdev->xendev.gnttabdev,
-                                   netdev->xendev.dom,
-                                   rxreq.gref, PROT_WRITE);
-    if (page == NULL) {
-        xen_be_printf(&netdev->xendev, 0, "error: rx gref dereference failed (%d)\n",
-                      rxreq.gref);
-        net_rx_response(netdev, &rxreq, NETIF_RSP_ERROR, 0, 0, 0);
-        return -1;
-    }
-    memcpy(page + NET_IP_ALIGN, buf, size);
-    xc_gnttab_munmap(netdev->xendev.gnttabdev, page, 1);
-    net_rx_response(netdev, &rxreq, NETIF_RSP_OKAY, NET_IP_ALIGN, size, 0);
-
-    return size;
-}
-
-/* ------------------------------------------------------------- */
-
-static NetClientInfo net_xen_info = {
-    .type = NET_CLIENT_OPTIONS_KIND_NIC,
-    .size = sizeof(NICState),
-    .can_receive = net_rx_ok,
-    .receive = net_rx_packet,
-};
-
-static int net_init(struct XenDevice *xendev)
-{
-    struct XenNetDev *netdev = container_of(xendev, struct XenNetDev, xendev);
-
-    /* read xenstore entries */
-    if (netdev->mac == NULL) {
-        netdev->mac = xenstore_read_be_str(&netdev->xendev, "mac");
-    }
-
-    /* do we have all we need? */
-    if (netdev->mac == NULL) {
-        return -1;
-    }
-
-    if (net_parse_macaddr(netdev->conf.macaddr.a, netdev->mac) < 0) {
-        return -1;
-    }
-
-    netdev->nic = qemu_new_nic(&net_xen_info, &netdev->conf,
-                               "xen", NULL, netdev);
-
-    snprintf(qemu_get_queue(netdev->nic)->info_str,
-             sizeof(qemu_get_queue(netdev->nic)->info_str),
-             "nic: xenbus vif macaddr=%s", netdev->mac);
-
-    /* fill info */
-    xenstore_write_be_int(&netdev->xendev, "feature-rx-copy", 1);
-    xenstore_write_be_int(&netdev->xendev, "feature-rx-flip", 0);
-
-    return 0;
-}
-
-static int net_connect(struct XenDevice *xendev)
-{
-    struct XenNetDev *netdev = container_of(xendev, struct XenNetDev, xendev);
-    int rx_copy;
-
-    if (xenstore_read_fe_int(&netdev->xendev, "tx-ring-ref",
-                             &netdev->tx_ring_ref) == -1) {
-        return -1;
-    }
-    if (xenstore_read_fe_int(&netdev->xendev, "rx-ring-ref",
-                             &netdev->rx_ring_ref) == -1) {
-        return 1;
-    }
-    if (xenstore_read_fe_int(&netdev->xendev, "event-channel",
-                             &netdev->xendev.remote_port) == -1) {
-        return -1;
-    }
-
-    if (xenstore_read_fe_int(&netdev->xendev, "request-rx-copy", &rx_copy) == -1) {
-        rx_copy = 0;
-    }
-    if (rx_copy == 0) {
-        xen_be_printf(&netdev->xendev, 0, "frontend doesn't support rx-copy.\n");
-        return -1;
-    }
-
-    netdev->txs = xc_gnttab_map_grant_ref(netdev->xendev.gnttabdev,
-                                          netdev->xendev.dom,
-                                          netdev->tx_ring_ref,
-                                          PROT_READ | PROT_WRITE);
-    netdev->rxs = xc_gnttab_map_grant_ref(netdev->xendev.gnttabdev,
-                                          netdev->xendev.dom,
-                                          netdev->rx_ring_ref,
-                                          PROT_READ | PROT_WRITE);
-    if (!netdev->txs || !netdev->rxs) {
-        return -1;
-    }
-    BACK_RING_INIT(&netdev->tx_ring, netdev->txs, XC_PAGE_SIZE);
-    BACK_RING_INIT(&netdev->rx_ring, netdev->rxs, XC_PAGE_SIZE);
-
-    xen_be_bind_evtchn(&netdev->xendev);
-
-    xen_be_printf(&netdev->xendev, 1, "ok: tx-ring-ref %d, rx-ring-ref %d, "
-                  "remote port %d, local port %d\n",
-                  netdev->tx_ring_ref, netdev->rx_ring_ref,
-                  netdev->xendev.remote_port, netdev->xendev.local_port);
-
-    net_tx_packets(netdev);
-    return 0;
-}
-
-static void net_disconnect(struct XenDevice *xendev)
-{
-    struct XenNetDev *netdev = container_of(xendev, struct XenNetDev, xendev);
-
-    xen_be_unbind_evtchn(&netdev->xendev);
-
-    if (netdev->txs) {
-        xc_gnttab_munmap(netdev->xendev.gnttabdev, netdev->txs, 1);
-        netdev->txs = NULL;
-    }
-    if (netdev->rxs) {
-        xc_gnttab_munmap(netdev->xendev.gnttabdev, netdev->rxs, 1);
-        netdev->rxs = NULL;
-    }
-    if (netdev->nic) {
-        qemu_del_nic(netdev->nic);
-        netdev->nic = NULL;
-    }
-}
-
-static void net_event(struct XenDevice *xendev)
-{
-    struct XenNetDev *netdev = container_of(xendev, struct XenNetDev, xendev);
-    net_tx_packets(netdev);
-    qemu_flush_queued_packets(qemu_get_queue(netdev->nic));
-}
-
-static int net_free(struct XenDevice *xendev)
-{
-    struct XenNetDev *netdev = container_of(xendev, struct XenNetDev, xendev);
-
-    g_free(netdev->mac);
-    return 0;
-}
-
-/* ------------------------------------------------------------- */
-
-struct XenDevOps xen_netdev_ops = {
-    .size       = sizeof(struct XenNetDev),
-    .flags      = DEVOPS_FLAG_NEED_GNTDEV,
-    .init       = net_init,
-    .initialise    = net_connect,
-    .event      = net_event,
-    .disconnect = net_disconnect,
-    .free       = net_free,
-};
diff --git a/hw/xen_platform.c b/hw/xen_platform.c
deleted file mode 100644 (file)
index 5e11c95..0000000
+++ /dev/null
@@ -1,434 +0,0 @@
-/*
- * XEN platform pci device, formerly known as the event channel device
- *
- * Copyright (c) 2003-2004 Intel Corp.
- * Copyright (c) 2006 XenSource
- *
- * 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 <assert.h>
-
-#include "hw/hw.h"
-#include "hw/pc.h"
-#include "hw/pci/pci.h"
-#include "hw/irq.h"
-#include "hw/xen_common.h"
-#include "hw/xen_backend.h"
-#include "trace.h"
-#include "exec/address-spaces.h"
-
-#include <xenguest.h>
-
-//#define DEBUG_PLATFORM
-
-#ifdef DEBUG_PLATFORM
-#define DPRINTF(fmt, ...) do { \
-    fprintf(stderr, "xen_platform: " fmt, ## __VA_ARGS__); \
-} while (0)
-#else
-#define DPRINTF(fmt, ...) do { } while (0)
-#endif
-
-#define PFFLAG_ROM_LOCK 1 /* Sets whether ROM memory area is RW or RO */
-
-typedef struct PCIXenPlatformState {
-    PCIDevice  pci_dev;
-    MemoryRegion fixed_io;
-    MemoryRegion bar;
-    MemoryRegion mmio_bar;
-    uint8_t flags; /* used only for version_id == 2 */
-    int drivers_blacklisted;
-    uint16_t driver_product_version;
-
-    /* Log from guest drivers */
-    char log_buffer[4096];
-    int log_buffer_off;
-} PCIXenPlatformState;
-
-#define XEN_PLATFORM_IOPORT 0x10
-
-/* Send bytes to syslog */
-static void log_writeb(PCIXenPlatformState *s, char val)
-{
-    if (val == '\n' || s->log_buffer_off == sizeof(s->log_buffer) - 1) {
-        /* Flush buffer */
-        s->log_buffer[s->log_buffer_off] = 0;
-        trace_xen_platform_log(s->log_buffer);
-        s->log_buffer_off = 0;
-    } else {
-        s->log_buffer[s->log_buffer_off++] = val;
-    }
-}
-
-/* Xen Platform, Fixed IOPort */
-#define UNPLUG_ALL_IDE_DISKS 1
-#define UNPLUG_ALL_NICS 2
-#define UNPLUG_AUX_IDE_DISKS 4
-
-static void unplug_nic(PCIBus *b, PCIDevice *d, void *o)
-{
-    /* We have to ignore passthrough devices */
-    if (pci_get_word(d->config + PCI_CLASS_DEVICE) ==
-            PCI_CLASS_NETWORK_ETHERNET
-            && strcmp(d->name, "xen-pci-passthrough") != 0) {
-        qdev_free(&d->qdev);
-    }
-}
-
-static void pci_unplug_nics(PCIBus *bus)
-{
-    pci_for_each_device(bus, 0, unplug_nic, NULL);
-}
-
-static void unplug_disks(PCIBus *b, PCIDevice *d, void *o)
-{
-    /* We have to ignore passthrough devices */
-    if (pci_get_word(d->config + PCI_CLASS_DEVICE) ==
-            PCI_CLASS_STORAGE_IDE
-            && strcmp(d->name, "xen-pci-passthrough") != 0) {
-        qdev_unplug(&(d->qdev), NULL);
-    }
-}
-
-static void pci_unplug_disks(PCIBus *bus)
-{
-    pci_for_each_device(bus, 0, unplug_disks, NULL);
-}
-
-static void platform_fixed_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
-{
-    PCIXenPlatformState *s = opaque;
-
-    switch (addr) {
-    case 0:
-        /* Unplug devices.  Value is a bitmask of which devices to
-           unplug, with bit 0 the IDE devices, bit 1 the network
-           devices, and bit 2 the non-primary-master IDE devices. */
-        if (val & UNPLUG_ALL_IDE_DISKS) {
-            DPRINTF("unplug disks\n");
-            bdrv_drain_all();
-            bdrv_flush_all();
-            pci_unplug_disks(s->pci_dev.bus);
-        }
-        if (val & UNPLUG_ALL_NICS) {
-            DPRINTF("unplug nics\n");
-            pci_unplug_nics(s->pci_dev.bus);
-        }
-        if (val & UNPLUG_AUX_IDE_DISKS) {
-            DPRINTF("unplug auxiliary disks not supported\n");
-        }
-        break;
-    case 2:
-        switch (val) {
-        case 1:
-            DPRINTF("Citrix Windows PV drivers loaded in guest\n");
-            break;
-        case 0:
-            DPRINTF("Guest claimed to be running PV product 0?\n");
-            break;
-        default:
-            DPRINTF("Unknown PV product %d loaded in guest\n", val);
-            break;
-        }
-        s->driver_product_version = val;
-        break;
-    }
-}
-
-static void platform_fixed_ioport_writel(void *opaque, uint32_t addr,
-                                         uint32_t val)
-{
-    switch (addr) {
-    case 0:
-        /* PV driver version */
-        break;
-    }
-}
-
-static void platform_fixed_ioport_writeb(void *opaque, uint32_t addr, uint32_t val)
-{
-    PCIXenPlatformState *s = opaque;
-
-    switch (addr) {
-    case 0: /* Platform flags */ {
-        hvmmem_type_t mem_type = (val & PFFLAG_ROM_LOCK) ?
-            HVMMEM_ram_ro : HVMMEM_ram_rw;
-        if (xc_hvm_set_mem_type(xen_xc, xen_domid, mem_type, 0xc0, 0x40)) {
-            DPRINTF("unable to change ro/rw state of ROM memory area!\n");
-        } else {
-            s->flags = val & PFFLAG_ROM_LOCK;
-            DPRINTF("changed ro/rw state of ROM memory area. now is %s state.\n",
-                    (mem_type == HVMMEM_ram_ro ? "ro":"rw"));
-        }
-        break;
-    }
-    case 2:
-        log_writeb(s, val);
-        break;
-    }
-}
-
-static uint32_t platform_fixed_ioport_readw(void *opaque, uint32_t addr)
-{
-    PCIXenPlatformState *s = opaque;
-
-    switch (addr) {
-    case 0:
-        if (s->drivers_blacklisted) {
-            /* The drivers will recognise this magic number and refuse
-             * to do anything. */
-            return 0xd249;
-        } else {
-            /* Magic value so that you can identify the interface. */
-            return 0x49d2;
-        }
-    default:
-        return 0xffff;
-    }
-}
-
-static uint32_t platform_fixed_ioport_readb(void *opaque, uint32_t addr)
-{
-    PCIXenPlatformState *s = opaque;
-
-    switch (addr) {
-    case 0:
-        /* Platform flags */
-        return s->flags;
-    case 2:
-        /* Version number */
-        return 1;
-    default:
-        return 0xff;
-    }
-}
-
-static void platform_fixed_ioport_reset(void *opaque)
-{
-    PCIXenPlatformState *s = opaque;
-
-    platform_fixed_ioport_writeb(s, 0, 0);
-}
-
-static uint64_t platform_fixed_ioport_read(void *opaque,
-                                           hwaddr addr,
-                                           unsigned size)
-{
-    switch (size) {
-    case 1:
-        return platform_fixed_ioport_readb(opaque, addr);
-    case 2:
-        return platform_fixed_ioport_readw(opaque, addr);
-    default:
-        return -1;
-    }
-}
-
-static void platform_fixed_ioport_write(void *opaque, hwaddr addr,
-
-                                        uint64_t val, unsigned size)
-{
-    switch (size) {
-    case 1:
-        platform_fixed_ioport_writeb(opaque, addr, val);
-        break;
-    case 2:
-        platform_fixed_ioport_writew(opaque, addr, val);
-        break;
-    case 4:
-        platform_fixed_ioport_writel(opaque, addr, val);
-        break;
-    }
-}
-
-
-static const MemoryRegionOps platform_fixed_io_ops = {
-    .read = platform_fixed_ioport_read,
-    .write = platform_fixed_ioport_write,
-    .impl = {
-        .min_access_size = 1,
-        .max_access_size = 4,
-    },
-    .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static void platform_fixed_ioport_init(PCIXenPlatformState* s)
-{
-    memory_region_init_io(&s->fixed_io, &platform_fixed_io_ops, s,
-                          "xen-fixed", 16);
-    memory_region_add_subregion(get_system_io(), XEN_PLATFORM_IOPORT,
-                                &s->fixed_io);
-}
-
-/* Xen Platform PCI Device */
-
-static uint64_t xen_platform_ioport_readb(void *opaque, hwaddr addr,
-                                          unsigned int size)
-{
-    if (addr == 0) {
-        return platform_fixed_ioport_readb(opaque, 0);
-    } else {
-        return ~0u;
-    }
-}
-
-static void xen_platform_ioport_writeb(void *opaque, hwaddr addr,
-                                       uint64_t val, unsigned int size)
-{
-    PCIXenPlatformState *s = opaque;
-
-    switch (addr) {
-    case 0: /* Platform flags */
-        platform_fixed_ioport_writeb(opaque, 0, (uint32_t)val);
-        break;
-    case 8:
-        log_writeb(s, (uint32_t)val);
-        break;
-    default:
-        break;
-    }
-}
-
-static const MemoryRegionOps xen_pci_io_ops = {
-    .read  = xen_platform_ioport_readb,
-    .write = xen_platform_ioport_writeb,
-    .impl.min_access_size = 1,
-    .impl.max_access_size = 1,
-};
-
-static void platform_ioport_bar_setup(PCIXenPlatformState *d)
-{
-    memory_region_init_io(&d->bar, &xen_pci_io_ops, d, "xen-pci", 0x100);
-}
-
-static uint64_t platform_mmio_read(void *opaque, hwaddr addr,
-                                   unsigned size)
-{
-    DPRINTF("Warning: attempted read from physical address "
-            "0x" TARGET_FMT_plx " in xen platform mmio space\n", addr);
-
-    return 0;
-}
-
-static void platform_mmio_write(void *opaque, hwaddr addr,
-                                uint64_t val, unsigned size)
-{
-    DPRINTF("Warning: attempted write of 0x%"PRIx64" to physical "
-            "address 0x" TARGET_FMT_plx " in xen platform mmio space\n",
-            val, addr);
-}
-
-static const MemoryRegionOps platform_mmio_handler = {
-    .read = &platform_mmio_read,
-    .write = &platform_mmio_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void platform_mmio_setup(PCIXenPlatformState *d)
-{
-    memory_region_init_io(&d->mmio_bar, &platform_mmio_handler, d,
-                          "xen-mmio", 0x1000000);
-}
-
-static int xen_platform_post_load(void *opaque, int version_id)
-{
-    PCIXenPlatformState *s = opaque;
-
-    platform_fixed_ioport_writeb(s, 0, s->flags);
-
-    return 0;
-}
-
-static const VMStateDescription vmstate_xen_platform = {
-    .name = "platform",
-    .version_id = 4,
-    .minimum_version_id = 4,
-    .minimum_version_id_old = 4,
-    .post_load = xen_platform_post_load,
-    .fields = (VMStateField []) {
-        VMSTATE_PCI_DEVICE(pci_dev, PCIXenPlatformState),
-        VMSTATE_UINT8(flags, PCIXenPlatformState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static int xen_platform_initfn(PCIDevice *dev)
-{
-    PCIXenPlatformState *d = DO_UPCAST(PCIXenPlatformState, pci_dev, dev);
-    uint8_t *pci_conf;
-
-    pci_conf = d->pci_dev.config;
-
-    pci_set_word(pci_conf + PCI_COMMAND, PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
-
-    pci_config_set_prog_interface(pci_conf, 0);
-
-    pci_conf[PCI_INTERRUPT_PIN] = 1;
-
-    platform_ioport_bar_setup(d);
-    pci_register_bar(&d->pci_dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &d->bar);
-
-    /* reserve 16MB mmio address for share memory*/
-    platform_mmio_setup(d);
-    pci_register_bar(&d->pci_dev, 1, PCI_BASE_ADDRESS_MEM_PREFETCH,
-                     &d->mmio_bar);
-
-    platform_fixed_ioport_init(d);
-
-    return 0;
-}
-
-static void platform_reset(DeviceState *dev)
-{
-    PCIXenPlatformState *s = DO_UPCAST(PCIXenPlatformState, pci_dev.qdev, dev);
-
-    platform_fixed_ioport_reset(s);
-}
-
-static void xen_platform_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
-    k->init = xen_platform_initfn;
-    k->vendor_id = PCI_VENDOR_ID_XEN;
-    k->device_id = PCI_DEVICE_ID_XEN_PLATFORM;
-    k->class_id = PCI_CLASS_OTHERS << 8 | 0x80;
-    k->subsystem_vendor_id = PCI_VENDOR_ID_XEN;
-    k->subsystem_id = PCI_DEVICE_ID_XEN_PLATFORM;
-    k->revision = 1;
-    dc->desc = "XEN platform pci device";
-    dc->reset = platform_reset;
-    dc->vmsd = &vmstate_xen_platform;
-}
-
-static const 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_types(void)
-{
-    type_register_static(&xen_platform_info);
-}
-
-type_init(xen_platform_register_types)
diff --git a/hw/xen_pt.c b/hw/xen_pt.c
deleted file mode 100644 (file)
index ce695d0..0000000
+++ /dev/null
@@ -1,844 +0,0 @@
-/*
- * Copyright (c) 2007, Neocleus Corporation.
- * Copyright (c) 2007, Intel Corporation.
- *
- * This work is licensed under the terms of the GNU GPL, version 2.  See
- * the COPYING file in the top-level directory.
- *
- * Alex Novik <alex@neocleus.com>
- * Allen Kay <allen.m.kay@intel.com>
- * Guy Zana <guy@neocleus.com>
- *
- * This file implements direct PCI assignment to a HVM guest
- */
-
-/*
- * Interrupt Disable policy:
- *
- * INTx interrupt:
- *   Initialize(register_real_device)
- *     Map INTx(xc_physdev_map_pirq):
- *       <fail>
- *         - Set real Interrupt Disable bit to '1'.
- *         - Set machine_irq and assigned_device->machine_irq to '0'.
- *         * Don't bind INTx.
- *
- *     Bind INTx(xc_domain_bind_pt_pci_irq):
- *       <fail>
- *         - Set real Interrupt Disable bit to '1'.
- *         - Unmap INTx.
- *         - Decrement xen_pt_mapped_machine_irq[machine_irq]
- *         - Set assigned_device->machine_irq to '0'.
- *
- *   Write to Interrupt Disable bit by guest software(xen_pt_cmd_reg_write)
- *     Write '0'
- *       - Set real bit to '0' if assigned_device->machine_irq isn't '0'.
- *
- *     Write '1'
- *       - Set real bit to '1'.
- *
- * MSI interrupt:
- *   Initialize MSI register(xen_pt_msi_setup, xen_pt_msi_update)
- *     Bind MSI(xc_domain_update_msi_irq)
- *       <fail>
- *         - Unmap MSI.
- *         - Set dev->msi->pirq to '-1'.
- *
- * MSI-X interrupt:
- *   Initialize MSI-X register(xen_pt_msix_update_one)
- *     Bind MSI-X(xc_domain_update_msi_irq)
- *       <fail>
- *         - Unmap MSI-X.
- *         - Set entry->pirq to '-1'.
- */
-
-#include <sys/ioctl.h>
-
-#include "hw/pci/pci.h"
-#include "hw/xen.h"
-#include "hw/xen_backend.h"
-#include "hw/xen_pt.h"
-#include "qemu/range.h"
-#include "exec/address-spaces.h"
-
-#define XEN_PT_NR_IRQS (256)
-static uint8_t xen_pt_mapped_machine_irq[XEN_PT_NR_IRQS] = {0};
-
-void xen_pt_log(const PCIDevice *d, const char *f, ...)
-{
-    va_list ap;
-
-    va_start(ap, f);
-    if (d) {
-        fprintf(stderr, "[%02x:%02x.%d] ", pci_bus_num(d->bus),
-                PCI_SLOT(d->devfn), PCI_FUNC(d->devfn));
-    }
-    vfprintf(stderr, f, ap);
-    va_end(ap);
-}
-
-/* Config Space */
-
-static int xen_pt_pci_config_access_check(PCIDevice *d, uint32_t addr, int len)
-{
-    /* check offset range */
-    if (addr >= 0xFF) {
-        XEN_PT_ERR(d, "Failed to access register with offset exceeding 0xFF. "
-                   "(addr: 0x%02x, len: %d)\n", addr, len);
-        return -1;
-    }
-
-    /* check read size */
-    if ((len != 1) && (len != 2) && (len != 4)) {
-        XEN_PT_ERR(d, "Failed to access register with invalid access length. "
-                   "(addr: 0x%02x, len: %d)\n", addr, len);
-        return -1;
-    }
-
-    /* check offset alignment */
-    if (addr & (len - 1)) {
-        XEN_PT_ERR(d, "Failed to access register with invalid access size "
-                   "alignment. (addr: 0x%02x, len: %d)\n", addr, len);
-        return -1;
-    }
-
-    return 0;
-}
-
-int xen_pt_bar_offset_to_index(uint32_t offset)
-{
-    int index = 0;
-
-    /* check Exp ROM BAR */
-    if (offset == PCI_ROM_ADDRESS) {
-        return PCI_ROM_SLOT;
-    }
-
-    /* calculate BAR index */
-    index = (offset - PCI_BASE_ADDRESS_0) >> 2;
-    if (index >= PCI_NUM_REGIONS) {
-        return -1;
-    }
-
-    return index;
-}
-
-static uint32_t xen_pt_pci_read_config(PCIDevice *d, uint32_t addr, int len)
-{
-    XenPCIPassthroughState *s = DO_UPCAST(XenPCIPassthroughState, dev, d);
-    uint32_t val = 0;
-    XenPTRegGroup *reg_grp_entry = NULL;
-    XenPTReg *reg_entry = NULL;
-    int rc = 0;
-    int emul_len = 0;
-    uint32_t find_addr = addr;
-
-    if (xen_pt_pci_config_access_check(d, addr, len)) {
-        goto exit;
-    }
-
-    /* find register group entry */
-    reg_grp_entry = xen_pt_find_reg_grp(s, addr);
-    if (reg_grp_entry) {
-        /* check 0-Hardwired register group */
-        if (reg_grp_entry->reg_grp->grp_type == XEN_PT_GRP_TYPE_HARDWIRED) {
-            /* no need to emulate, just return 0 */
-            val = 0;
-            goto exit;
-        }
-    }
-
-    /* read I/O device register value */
-    rc = xen_host_pci_get_block(&s->real_device, addr, (uint8_t *)&val, len);
-    if (rc < 0) {
-        XEN_PT_ERR(d, "pci_read_block failed. return value: %d.\n", rc);
-        memset(&val, 0xff, len);
-    }
-
-    /* just return the I/O device register value for
-     * passthrough type register group */
-    if (reg_grp_entry == NULL) {
-        goto exit;
-    }
-
-    /* adjust the read value to appropriate CFC-CFF window */
-    val <<= (addr & 3) << 3;
-    emul_len = len;
-
-    /* loop around the guest requested size */
-    while (emul_len > 0) {
-        /* find register entry to be emulated */
-        reg_entry = xen_pt_find_reg(reg_grp_entry, find_addr);
-        if (reg_entry) {
-            XenPTRegInfo *reg = reg_entry->reg;
-            uint32_t real_offset = reg_grp_entry->base_offset + reg->offset;
-            uint32_t valid_mask = 0xFFFFFFFF >> ((4 - emul_len) << 3);
-            uint8_t *ptr_val = NULL;
-
-            valid_mask <<= (find_addr - real_offset) << 3;
-            ptr_val = (uint8_t *)&val + (real_offset & 3);
-
-            /* do emulation based on register size */
-            switch (reg->size) {
-            case 1:
-                if (reg->u.b.read) {
-                    rc = reg->u.b.read(s, reg_entry, ptr_val, valid_mask);
-                }
-                break;
-            case 2:
-                if (reg->u.w.read) {
-                    rc = reg->u.w.read(s, reg_entry,
-                                       (uint16_t *)ptr_val, valid_mask);
-                }
-                break;
-            case 4:
-                if (reg->u.dw.read) {
-                    rc = reg->u.dw.read(s, reg_entry,
-                                        (uint32_t *)ptr_val, valid_mask);
-                }
-                break;
-            }
-
-            if (rc < 0) {
-                xen_shutdown_fatal_error("Internal error: Invalid read "
-                                         "emulation. (%s, rc: %d)\n",
-                                         __func__, rc);
-                return 0;
-            }
-
-            /* calculate next address to find */
-            emul_len -= reg->size;
-            if (emul_len > 0) {
-                find_addr = real_offset + reg->size;
-            }
-        } else {
-            /* nothing to do with passthrough type register,
-             * continue to find next byte */
-            emul_len--;
-            find_addr++;
-        }
-    }
-
-    /* need to shift back before returning them to pci bus emulator */
-    val >>= ((addr & 3) << 3);
-
-exit:
-    XEN_PT_LOG_CONFIG(d, addr, val, len);
-    return val;
-}
-
-static void xen_pt_pci_write_config(PCIDevice *d, uint32_t addr,
-                                    uint32_t val, int len)
-{
-    XenPCIPassthroughState *s = DO_UPCAST(XenPCIPassthroughState, dev, d);
-    int index = 0;
-    XenPTRegGroup *reg_grp_entry = NULL;
-    int rc = 0;
-    uint32_t read_val = 0;
-    int emul_len = 0;
-    XenPTReg *reg_entry = NULL;
-    uint32_t find_addr = addr;
-    XenPTRegInfo *reg = NULL;
-
-    if (xen_pt_pci_config_access_check(d, addr, len)) {
-        return;
-    }
-
-    XEN_PT_LOG_CONFIG(d, addr, val, len);
-
-    /* check unused BAR register */
-    index = xen_pt_bar_offset_to_index(addr);
-    if ((index >= 0) && (val > 0 && val < XEN_PT_BAR_ALLF) &&
-        (s->bases[index].bar_flag == XEN_PT_BAR_FLAG_UNUSED)) {
-        XEN_PT_WARN(d, "Guest attempt to set address to unused Base Address "
-                    "Register. (addr: 0x%02x, len: %d)\n", addr, len);
-    }
-
-    /* find register group entry */
-    reg_grp_entry = xen_pt_find_reg_grp(s, addr);
-    if (reg_grp_entry) {
-        /* check 0-Hardwired register group */
-        if (reg_grp_entry->reg_grp->grp_type == XEN_PT_GRP_TYPE_HARDWIRED) {
-            /* ignore silently */
-            XEN_PT_WARN(d, "Access to 0-Hardwired register. "
-                        "(addr: 0x%02x, len: %d)\n", addr, len);
-            return;
-        }
-    }
-
-    rc = xen_host_pci_get_block(&s->real_device, addr,
-                                (uint8_t *)&read_val, len);
-    if (rc < 0) {
-        XEN_PT_ERR(d, "pci_read_block failed. return value: %d.\n", rc);
-        memset(&read_val, 0xff, len);
-    }
-
-    /* pass directly to the real device for passthrough type register group */
-    if (reg_grp_entry == NULL) {
-        goto out;
-    }
-
-    memory_region_transaction_begin();
-    pci_default_write_config(d, addr, val, len);
-
-    /* adjust the read and write value to appropriate CFC-CFF window */
-    read_val <<= (addr & 3) << 3;
-    val <<= (addr & 3) << 3;
-    emul_len = len;
-
-    /* loop around the guest requested size */
-    while (emul_len > 0) {
-        /* find register entry to be emulated */
-        reg_entry = xen_pt_find_reg(reg_grp_entry, find_addr);
-        if (reg_entry) {
-            reg = reg_entry->reg;
-            uint32_t real_offset = reg_grp_entry->base_offset + reg->offset;
-            uint32_t valid_mask = 0xFFFFFFFF >> ((4 - emul_len) << 3);
-            uint8_t *ptr_val = NULL;
-
-            valid_mask <<= (find_addr - real_offset) << 3;
-            ptr_val = (uint8_t *)&val + (real_offset & 3);
-
-            /* do emulation based on register size */
-            switch (reg->size) {
-            case 1:
-                if (reg->u.b.write) {
-                    rc = reg->u.b.write(s, reg_entry, ptr_val,
-                                        read_val >> ((real_offset & 3) << 3),
-                                        valid_mask);
-                }
-                break;
-            case 2:
-                if (reg->u.w.write) {
-                    rc = reg->u.w.write(s, reg_entry, (uint16_t *)ptr_val,
-                                        (read_val >> ((real_offset & 3) << 3)),
-                                        valid_mask);
-                }
-                break;
-            case 4:
-                if (reg->u.dw.write) {
-                    rc = reg->u.dw.write(s, reg_entry, (uint32_t *)ptr_val,
-                                         (read_val >> ((real_offset & 3) << 3)),
-                                         valid_mask);
-                }
-                break;
-            }
-
-            if (rc < 0) {
-                xen_shutdown_fatal_error("Internal error: Invalid write"
-                                         " emulation. (%s, rc: %d)\n",
-                                         __func__, rc);
-                return;
-            }
-
-            /* calculate next address to find */
-            emul_len -= reg->size;
-            if (emul_len > 0) {
-                find_addr = real_offset + reg->size;
-            }
-        } else {
-            /* nothing to do with passthrough type register,
-             * continue to find next byte */
-            emul_len--;
-            find_addr++;
-        }
-    }
-
-    /* need to shift back before passing them to xen_host_pci_device */
-    val >>= (addr & 3) << 3;
-
-    memory_region_transaction_commit();
-
-out:
-    if (!(reg && reg->no_wb)) {
-        /* unknown regs are passed through */
-        rc = xen_host_pci_set_block(&s->real_device, addr,
-                                    (uint8_t *)&val, len);
-
-        if (rc < 0) {
-            XEN_PT_ERR(d, "pci_write_block failed. return value: %d.\n", rc);
-        }
-    }
-}
-
-/* register regions */
-
-static uint64_t xen_pt_bar_read(void *o, hwaddr addr,
-                                unsigned size)
-{
-    PCIDevice *d = o;
-    /* if this function is called, that probably means that there is a
-     * misconfiguration of the IOMMU. */
-    XEN_PT_ERR(d, "Should not read BAR through QEMU. @0x"TARGET_FMT_plx"\n",
-               addr);
-    return 0;
-}
-static void xen_pt_bar_write(void *o, hwaddr addr, uint64_t val,
-                             unsigned size)
-{
-    PCIDevice *d = o;
-    /* Same comment as xen_pt_bar_read function */
-    XEN_PT_ERR(d, "Should not write BAR through QEMU. @0x"TARGET_FMT_plx"\n",
-               addr);
-}
-
-static const MemoryRegionOps ops = {
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .read = xen_pt_bar_read,
-    .write = xen_pt_bar_write,
-};
-
-static int xen_pt_register_regions(XenPCIPassthroughState *s)
-{
-    int i = 0;
-    XenHostPCIDevice *d = &s->real_device;
-
-    /* Register PIO/MMIO BARs */
-    for (i = 0; i < PCI_ROM_SLOT; i++) {
-        XenHostPCIIORegion *r = &d->io_regions[i];
-        uint8_t type;
-
-        if (r->base_addr == 0 || r->size == 0) {
-            continue;
-        }
-
-        s->bases[i].access.u = r->base_addr;
-
-        if (r->type & XEN_HOST_PCI_REGION_TYPE_IO) {
-            type = PCI_BASE_ADDRESS_SPACE_IO;
-        } else {
-            type = PCI_BASE_ADDRESS_SPACE_MEMORY;
-            if (r->type & XEN_HOST_PCI_REGION_TYPE_PREFETCH) {
-                type |= PCI_BASE_ADDRESS_MEM_PREFETCH;
-            }
-            if (r->type & XEN_HOST_PCI_REGION_TYPE_MEM_64) {
-                type |= PCI_BASE_ADDRESS_MEM_TYPE_64;
-            }
-        }
-
-        memory_region_init_io(&s->bar[i], &ops, &s->dev,
-                              "xen-pci-pt-bar", r->size);
-        pci_register_bar(&s->dev, i, type, &s->bar[i]);
-
-        XEN_PT_LOG(&s->dev, "IO region %i registered (size=0x%lx"PRIx64
-                   " base_addr=0x%lx"PRIx64" type: %#x)\n",
-                   i, r->size, r->base_addr, type);
-    }
-
-    /* Register expansion ROM address */
-    if (d->rom.base_addr && d->rom.size) {
-        uint32_t bar_data = 0;
-
-        /* Re-set BAR reported by OS, otherwise ROM can't be read. */
-        if (xen_host_pci_get_long(d, PCI_ROM_ADDRESS, &bar_data)) {
-            return 0;
-        }
-        if ((bar_data & PCI_ROM_ADDRESS_MASK) == 0) {
-            bar_data |= d->rom.base_addr & PCI_ROM_ADDRESS_MASK;
-            xen_host_pci_set_long(d, PCI_ROM_ADDRESS, bar_data);
-        }
-
-        s->bases[PCI_ROM_SLOT].access.maddr = d->rom.base_addr;
-
-        memory_region_init_rom_device(&s->rom, NULL, NULL,
-                                      "xen-pci-pt-rom", d->rom.size);
-        pci_register_bar(&s->dev, PCI_ROM_SLOT, PCI_BASE_ADDRESS_MEM_PREFETCH,
-                         &s->rom);
-
-        XEN_PT_LOG(&s->dev, "Expansion ROM registered (size=0x%08"PRIx64
-                   " base_addr=0x%08"PRIx64")\n",
-                   d->rom.size, d->rom.base_addr);
-    }
-
-    return 0;
-}
-
-static void xen_pt_unregister_regions(XenPCIPassthroughState *s)
-{
-    XenHostPCIDevice *d = &s->real_device;
-    int i;
-
-    for (i = 0; i < PCI_NUM_REGIONS - 1; i++) {
-        XenHostPCIIORegion *r = &d->io_regions[i];
-
-        if (r->base_addr == 0 || r->size == 0) {
-            continue;
-        }
-
-        memory_region_destroy(&s->bar[i]);
-    }
-    if (d->rom.base_addr && d->rom.size) {
-        memory_region_destroy(&s->rom);
-    }
-}
-
-/* region mapping */
-
-static int xen_pt_bar_from_region(XenPCIPassthroughState *s, MemoryRegion *mr)
-{
-    int i = 0;
-
-    for (i = 0; i < PCI_NUM_REGIONS - 1; i++) {
-        if (mr == &s->bar[i]) {
-            return i;
-        }
-    }
-    if (mr == &s->rom) {
-        return PCI_ROM_SLOT;
-    }
-    return -1;
-}
-
-/*
- * This function checks if an io_region overlaps an io_region from another
- * device.  The io_region to check is provided with (addr, size and type)
- * A callback can be provided and will be called for every region that is
- * overlapped.
- * The return value indicates if the region is overlappsed */
-struct CheckBarArgs {
-    XenPCIPassthroughState *s;
-    pcibus_t addr;
-    pcibus_t size;
-    uint8_t type;
-    bool rc;
-};
-static void xen_pt_check_bar_overlap(PCIBus *bus, PCIDevice *d, void *opaque)
-{
-    struct CheckBarArgs *arg = opaque;
-    XenPCIPassthroughState *s = arg->s;
-    uint8_t type = arg->type;
-    int i;
-
-    if (d->devfn == s->dev.devfn) {
-        return;
-    }
-
-    /* xxx: This ignores bridges. */
-    for (i = 0; i < PCI_NUM_REGIONS; i++) {
-        const PCIIORegion *r = &d->io_regions[i];
-
-        if (!r->size) {
-            continue;
-        }
-        if ((type & PCI_BASE_ADDRESS_SPACE_IO)
-            != (r->type & PCI_BASE_ADDRESS_SPACE_IO)) {
-            continue;
-        }
-
-        if (ranges_overlap(arg->addr, arg->size, r->addr, r->size)) {
-            XEN_PT_WARN(&s->dev,
-                        "Overlapped to device [%02x:%02x.%d] Region: %i"
-                        " (addr: %#"FMT_PCIBUS", len: %#"FMT_PCIBUS")\n",
-                        pci_bus_num(bus), PCI_SLOT(d->devfn),
-                        PCI_FUNC(d->devfn), i, r->addr, r->size);
-            arg->rc = true;
-        }
-    }
-}
-
-static void xen_pt_region_update(XenPCIPassthroughState *s,
-                                 MemoryRegionSection *sec, bool adding)
-{
-    PCIDevice *d = &s->dev;
-    MemoryRegion *mr = sec->mr;
-    int bar = -1;
-    int rc;
-    int op = adding ? DPCI_ADD_MAPPING : DPCI_REMOVE_MAPPING;
-    struct CheckBarArgs args = {
-        .s = s,
-        .addr = sec->offset_within_address_space,
-        .size = sec->size,
-        .rc = false,
-    };
-
-    bar = xen_pt_bar_from_region(s, mr);
-    if (bar == -1 && (!s->msix || &s->msix->mmio != mr)) {
-        return;
-    }
-
-    if (s->msix && &s->msix->mmio == mr) {
-        if (adding) {
-            s->msix->mmio_base_addr = sec->offset_within_address_space;
-            rc = xen_pt_msix_update_remap(s, s->msix->bar_index);
-        }
-        return;
-    }
-
-    args.type = d->io_regions[bar].type;
-    pci_for_each_device(d->bus, pci_bus_num(d->bus),
-                        xen_pt_check_bar_overlap, &args);
-    if (args.rc) {
-        XEN_PT_WARN(d, "Region: %d (addr: %#"FMT_PCIBUS
-                    ", len: %#"FMT_PCIBUS") is overlapped.\n",
-                    bar, sec->offset_within_address_space, sec->size);
-    }
-
-    if (d->io_regions[bar].type & PCI_BASE_ADDRESS_SPACE_IO) {
-        uint32_t guest_port = sec->offset_within_address_space;
-        uint32_t machine_port = s->bases[bar].access.pio_base;
-        uint32_t size = sec->size;
-        rc = xc_domain_ioport_mapping(xen_xc, xen_domid,
-                                      guest_port, machine_port, size,
-                                      op);
-        if (rc) {
-            XEN_PT_ERR(d, "%s ioport mapping failed! (rc: %i)\n",
-                       adding ? "create new" : "remove old", rc);
-        }
-    } else {
-        pcibus_t guest_addr = sec->offset_within_address_space;
-        pcibus_t machine_addr = s->bases[bar].access.maddr
-            + sec->offset_within_region;
-        pcibus_t size = sec->size;
-        rc = xc_domain_memory_mapping(xen_xc, xen_domid,
-                                      XEN_PFN(guest_addr + XC_PAGE_SIZE - 1),
-                                      XEN_PFN(machine_addr + XC_PAGE_SIZE - 1),
-                                      XEN_PFN(size + XC_PAGE_SIZE - 1),
-                                      op);
-        if (rc) {
-            XEN_PT_ERR(d, "%s mem mapping failed! (rc: %i)\n",
-                       adding ? "create new" : "remove old", rc);
-        }
-    }
-}
-
-static void xen_pt_region_add(MemoryListener *l, MemoryRegionSection *sec)
-{
-    XenPCIPassthroughState *s = container_of(l, XenPCIPassthroughState,
-                                             memory_listener);
-
-    xen_pt_region_update(s, sec, true);
-}
-
-static void xen_pt_region_del(MemoryListener *l, MemoryRegionSection *sec)
-{
-    XenPCIPassthroughState *s = container_of(l, XenPCIPassthroughState,
-                                             memory_listener);
-
-    xen_pt_region_update(s, sec, false);
-}
-
-static void xen_pt_io_region_add(MemoryListener *l, MemoryRegionSection *sec)
-{
-    XenPCIPassthroughState *s = container_of(l, XenPCIPassthroughState,
-                                             io_listener);
-
-    xen_pt_region_update(s, sec, true);
-}
-
-static void xen_pt_io_region_del(MemoryListener *l, MemoryRegionSection *sec)
-{
-    XenPCIPassthroughState *s = container_of(l, XenPCIPassthroughState,
-                                             io_listener);
-
-    xen_pt_region_update(s, sec, false);
-}
-
-static const MemoryListener xen_pt_memory_listener = {
-    .region_add = xen_pt_region_add,
-    .region_del = xen_pt_region_del,
-    .priority = 10,
-};
-
-static const MemoryListener xen_pt_io_listener = {
-    .region_add = xen_pt_io_region_add,
-    .region_del = xen_pt_io_region_del,
-    .priority = 10,
-};
-
-/* init */
-
-static int xen_pt_initfn(PCIDevice *d)
-{
-    XenPCIPassthroughState *s = DO_UPCAST(XenPCIPassthroughState, dev, d);
-    int rc = 0;
-    uint8_t machine_irq = 0;
-    int pirq = XEN_PT_UNASSIGNED_PIRQ;
-
-    /* register real device */
-    XEN_PT_LOG(d, "Assigning real physical device %02x:%02x.%d"
-               " to devfn %#x\n",
-               s->hostaddr.bus, s->hostaddr.slot, s->hostaddr.function,
-               s->dev.devfn);
-
-    rc = xen_host_pci_device_get(&s->real_device,
-                                 s->hostaddr.domain, s->hostaddr.bus,
-                                 s->hostaddr.slot, s->hostaddr.function);
-    if (rc) {
-        XEN_PT_ERR(d, "Failed to \"open\" the real pci device. rc: %i\n", rc);
-        return -1;
-    }
-
-    s->is_virtfn = s->real_device.is_virtfn;
-    if (s->is_virtfn) {
-        XEN_PT_LOG(d, "%04x:%02x:%02x.%d is a SR-IOV Virtual Function\n",
-                   s->real_device.domain, s->real_device.bus,
-                   s->real_device.dev, s->real_device.func);
-    }
-
-    /* Initialize virtualized PCI configuration (Extended 256 Bytes) */
-    if (xen_host_pci_get_block(&s->real_device, 0, d->config,
-                               PCI_CONFIG_SPACE_SIZE) == -1) {
-        xen_host_pci_device_put(&s->real_device);
-        return -1;
-    }
-
-    s->memory_listener = xen_pt_memory_listener;
-    s->io_listener = xen_pt_io_listener;
-
-    /* Handle real device's MMIO/PIO BARs */
-    xen_pt_register_regions(s);
-
-    /* reinitialize each config register to be emulated */
-    if (xen_pt_config_init(s)) {
-        XEN_PT_ERR(d, "PCI Config space initialisation failed.\n");
-        xen_host_pci_device_put(&s->real_device);
-        return -1;
-    }
-
-    /* Bind interrupt */
-    if (!s->dev.config[PCI_INTERRUPT_PIN]) {
-        XEN_PT_LOG(d, "no pin interrupt\n");
-        goto out;
-    }
-
-    machine_irq = s->real_device.irq;
-    rc = xc_physdev_map_pirq(xen_xc, xen_domid, machine_irq, &pirq);
-
-    if (rc < 0) {
-        XEN_PT_ERR(d, "Mapping machine irq %u to pirq %i failed, (rc: %d)\n",
-                   machine_irq, pirq, rc);
-
-        /* Disable PCI intx assertion (turn on bit10 of devctl) */
-        xen_host_pci_set_word(&s->real_device,
-                              PCI_COMMAND,
-                              pci_get_word(s->dev.config + PCI_COMMAND)
-                              | PCI_COMMAND_INTX_DISABLE);
-        machine_irq = 0;
-        s->machine_irq = 0;
-    } else {
-        machine_irq = pirq;
-        s->machine_irq = pirq;
-        xen_pt_mapped_machine_irq[machine_irq]++;
-    }
-
-    /* bind machine_irq to device */
-    if (machine_irq != 0) {
-        uint8_t e_intx = xen_pt_pci_intx(s);
-
-        rc = xc_domain_bind_pt_pci_irq(xen_xc, xen_domid, machine_irq,
-                                       pci_bus_num(d->bus),
-                                       PCI_SLOT(d->devfn),
-                                       e_intx);
-        if (rc < 0) {
-            XEN_PT_ERR(d, "Binding of interrupt %i failed! (rc: %d)\n",
-                       e_intx, rc);
-
-            /* Disable PCI intx assertion (turn on bit10 of devctl) */
-            xen_host_pci_set_word(&s->real_device, PCI_COMMAND,
-                                  *(uint16_t *)(&s->dev.config[PCI_COMMAND])
-                                  | PCI_COMMAND_INTX_DISABLE);
-            xen_pt_mapped_machine_irq[machine_irq]--;
-
-            if (xen_pt_mapped_machine_irq[machine_irq] == 0) {
-                if (xc_physdev_unmap_pirq(xen_xc, xen_domid, machine_irq)) {
-                    XEN_PT_ERR(d, "Unmapping of machine interrupt %i failed!"
-                               " (rc: %d)\n", machine_irq, rc);
-                }
-            }
-            s->machine_irq = 0;
-        }
-    }
-
-out:
-    memory_listener_register(&s->memory_listener, &address_space_memory);
-    memory_listener_register(&s->io_listener, &address_space_io);
-    XEN_PT_LOG(d, "Real physical device %02x:%02x.%d registered successfuly!\n",
-               s->hostaddr.bus, s->hostaddr.slot, s->hostaddr.function);
-
-    return 0;
-}
-
-static void xen_pt_unregister_device(PCIDevice *d)
-{
-    XenPCIPassthroughState *s = DO_UPCAST(XenPCIPassthroughState, dev, d);
-    uint8_t machine_irq = s->machine_irq;
-    uint8_t intx = xen_pt_pci_intx(s);
-    int rc;
-
-    if (machine_irq) {
-        rc = xc_domain_unbind_pt_irq(xen_xc, xen_domid, machine_irq,
-                                     PT_IRQ_TYPE_PCI,
-                                     pci_bus_num(d->bus),
-                                     PCI_SLOT(s->dev.devfn),
-                                     intx,
-                                     0 /* isa_irq */);
-        if (rc < 0) {
-            XEN_PT_ERR(d, "unbinding of interrupt INT%c failed."
-                       " (machine irq: %i, rc: %d)"
-                       " But bravely continuing on..\n",
-                       'a' + intx, machine_irq, rc);
-        }
-    }
-
-    if (s->msi) {
-        xen_pt_msi_disable(s);
-    }
-    if (s->msix) {
-        xen_pt_msix_disable(s);
-    }
-
-    if (machine_irq) {
-        xen_pt_mapped_machine_irq[machine_irq]--;
-
-        if (xen_pt_mapped_machine_irq[machine_irq] == 0) {
-            rc = xc_physdev_unmap_pirq(xen_xc, xen_domid, machine_irq);
-
-            if (rc < 0) {
-                XEN_PT_ERR(d, "unmapping of interrupt %i failed. (rc: %d)"
-                           " But bravely continuing on..\n",
-                           machine_irq, rc);
-            }
-        }
-    }
-
-    /* delete all emulated config registers */
-    xen_pt_config_delete(s);
-
-    xen_pt_unregister_regions(s);
-    memory_listener_unregister(&s->memory_listener);
-    memory_listener_unregister(&s->io_listener);
-
-    xen_host_pci_device_put(&s->real_device);
-}
-
-static Property xen_pci_passthrough_properties[] = {
-    DEFINE_PROP_PCI_HOST_DEVADDR("hostaddr", XenPCIPassthroughState, hostaddr),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void xen_pci_passthrough_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
-    k->init = xen_pt_initfn;
-    k->exit = xen_pt_unregister_device;
-    k->config_read = xen_pt_pci_read_config;
-    k->config_write = xen_pt_pci_write_config;
-    dc->desc = "Assign an host PCI device with Xen";
-    dc->props = xen_pci_passthrough_properties;
-};
-
-static const TypeInfo xen_pci_passthrough_info = {
-    .name = "xen-pci-passthrough",
-    .parent = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(XenPCIPassthroughState),
-    .class_init = xen_pci_passthrough_class_init,
-};
-
-static void xen_pci_passthrough_register_types(void)
-{
-    type_register_static(&xen_pci_passthrough_info);
-}
-
-type_init(xen_pci_passthrough_register_types)
diff --git a/hw/xen_pt.h b/hw/xen_pt.h
deleted file mode 100644 (file)
index 1cd9f44..0000000
+++ /dev/null
@@ -1,302 +0,0 @@
-#ifndef XEN_PT_H
-#define XEN_PT_H
-
-#include "qemu-common.h"
-#include "hw/xen_common.h"
-#include "hw/pci/pci.h"
-#include "hw/xen-host-pci-device.h"
-
-void xen_pt_log(const PCIDevice *d, const char *f, ...) GCC_FMT_ATTR(2, 3);
-
-#define XEN_PT_ERR(d, _f, _a...) xen_pt_log(d, "%s: Error: "_f, __func__, ##_a)
-
-#ifdef XEN_PT_LOGGING_ENABLED
-#  define XEN_PT_LOG(d, _f, _a...)  xen_pt_log(d, "%s: " _f, __func__, ##_a)
-#  define XEN_PT_WARN(d, _f, _a...) \
-    xen_pt_log(d, "%s: Warning: "_f, __func__, ##_a)
-#else
-#  define XEN_PT_LOG(d, _f, _a...)
-#  define XEN_PT_WARN(d, _f, _a...)
-#endif
-
-#ifdef XEN_PT_DEBUG_PCI_CONFIG_ACCESS
-#  define XEN_PT_LOG_CONFIG(d, addr, val, len) \
-    xen_pt_log(d, "%s: address=0x%04x val=0x%08x len=%d\n", \
-               __func__, addr, val, len)
-#else
-#  define XEN_PT_LOG_CONFIG(d, addr, val, len)
-#endif
-
-
-/* Helper */
-#define XEN_PFN(x) ((x) >> XC_PAGE_SHIFT)
-
-typedef struct XenPTRegInfo XenPTRegInfo;
-typedef struct XenPTReg XenPTReg;
-
-typedef struct XenPCIPassthroughState XenPCIPassthroughState;
-
-/* function type for config reg */
-typedef int (*xen_pt_conf_reg_init)
-    (XenPCIPassthroughState *, XenPTRegInfo *, uint32_t real_offset,
-     uint32_t *data);
-typedef int (*xen_pt_conf_dword_write)
-    (XenPCIPassthroughState *, XenPTReg *cfg_entry,
-     uint32_t *val, uint32_t dev_value, uint32_t valid_mask);
-typedef int (*xen_pt_conf_word_write)
-    (XenPCIPassthroughState *, XenPTReg *cfg_entry,
-     uint16_t *val, uint16_t dev_value, uint16_t valid_mask);
-typedef int (*xen_pt_conf_byte_write)
-    (XenPCIPassthroughState *, XenPTReg *cfg_entry,
-     uint8_t *val, uint8_t dev_value, uint8_t valid_mask);
-typedef int (*xen_pt_conf_dword_read)
-    (XenPCIPassthroughState *, XenPTReg *cfg_entry,
-     uint32_t *val, uint32_t valid_mask);
-typedef int (*xen_pt_conf_word_read)
-    (XenPCIPassthroughState *, XenPTReg *cfg_entry,
-     uint16_t *val, uint16_t valid_mask);
-typedef int (*xen_pt_conf_byte_read)
-    (XenPCIPassthroughState *, XenPTReg *cfg_entry,
-     uint8_t *val, uint8_t valid_mask);
-
-#define XEN_PT_BAR_ALLF 0xFFFFFFFF
-#define XEN_PT_BAR_UNMAPPED (-1)
-
-#define PCI_CAP_MAX 48
-
-
-typedef enum {
-    XEN_PT_GRP_TYPE_HARDWIRED = 0,  /* 0 Hardwired reg group */
-    XEN_PT_GRP_TYPE_EMU,            /* emul reg group */
-} XenPTRegisterGroupType;
-
-typedef enum {
-    XEN_PT_BAR_FLAG_MEM = 0,        /* Memory type BAR */
-    XEN_PT_BAR_FLAG_IO,             /* I/O type BAR */
-    XEN_PT_BAR_FLAG_UPPER,          /* upper 64bit BAR */
-    XEN_PT_BAR_FLAG_UNUSED,         /* unused BAR */
-} XenPTBarFlag;
-
-
-typedef struct XenPTRegion {
-    /* BAR flag */
-    XenPTBarFlag bar_flag;
-    /* Translation of the emulated address */
-    union {
-        uint64_t maddr;
-        uint64_t pio_base;
-        uint64_t u;
-    } access;
-} XenPTRegion;
-
-/* XenPTRegInfo declaration
- * - only for emulated register (either a part or whole bit).
- * - for passthrough register that need special behavior (like interacting with
- *   other component), set emu_mask to all 0 and specify r/w func properly.
- * - do NOT use ALL F for init_val, otherwise the tbl will not be registered.
- */
-
-/* emulated register information */
-struct XenPTRegInfo {
-    uint32_t offset;
-    uint32_t size;
-    uint32_t init_val;
-    /* reg read only field mask (ON:RO/ROS, OFF:other) */
-    uint32_t ro_mask;
-    /* reg emulate field mask (ON:emu, OFF:passthrough) */
-    uint32_t emu_mask;
-    /* no write back allowed */
-    uint32_t no_wb;
-    xen_pt_conf_reg_init init;
-    /* read/write function pointer
-     * for double_word/word/byte size */
-    union {
-        struct {
-            xen_pt_conf_dword_write write;
-            xen_pt_conf_dword_read read;
-        } dw;
-        struct {
-            xen_pt_conf_word_write write;
-            xen_pt_conf_word_read read;
-        } w;
-        struct {
-            xen_pt_conf_byte_write write;
-            xen_pt_conf_byte_read read;
-        } b;
-    } u;
-};
-
-/* emulated register management */
-struct XenPTReg {
-    QLIST_ENTRY(XenPTReg) entries;
-    XenPTRegInfo *reg;
-    uint32_t data; /* emulated value */
-};
-
-typedef struct XenPTRegGroupInfo XenPTRegGroupInfo;
-
-/* emul reg group size initialize method */
-typedef int (*xen_pt_reg_size_init_fn)
-    (XenPCIPassthroughState *, const XenPTRegGroupInfo *,
-     uint32_t base_offset, uint8_t *size);
-
-/* emulated register group information */
-struct XenPTRegGroupInfo {
-    uint8_t grp_id;
-    XenPTRegisterGroupType grp_type;
-    uint8_t grp_size;
-    xen_pt_reg_size_init_fn size_init;
-    XenPTRegInfo *emu_regs;
-};
-
-/* emul register group management table */
-typedef struct XenPTRegGroup {
-    QLIST_ENTRY(XenPTRegGroup) entries;
-    const XenPTRegGroupInfo *reg_grp;
-    uint32_t base_offset;
-    uint8_t size;
-    QLIST_HEAD(, XenPTReg) reg_tbl_list;
-} XenPTRegGroup;
-
-
-#define XEN_PT_UNASSIGNED_PIRQ (-1)
-typedef struct XenPTMSI {
-    uint16_t flags;
-    uint32_t addr_lo;  /* guest message address */
-    uint32_t addr_hi;  /* guest message upper address */
-    uint16_t data;     /* guest message data */
-    uint32_t ctrl_offset; /* saved control offset */
-    int pirq;          /* guest pirq corresponding */
-    bool initialized;  /* when guest MSI is initialized */
-    bool mapped;       /* when pirq is mapped */
-} XenPTMSI;
-
-typedef struct XenPTMSIXEntry {
-    int pirq;
-    uint64_t addr;
-    uint32_t data;
-    uint32_t vector_ctrl;
-    bool updated; /* indicate whether MSI ADDR or DATA is updated */
-} XenPTMSIXEntry;
-typedef struct XenPTMSIX {
-    uint32_t ctrl_offset;
-    bool enabled;
-    int total_entries;
-    int bar_index;
-    uint64_t table_base;
-    uint32_t table_offset_adjust; /* page align mmap */
-    uint64_t mmio_base_addr;
-    MemoryRegion mmio;
-    void *phys_iomem_base;
-    XenPTMSIXEntry msix_entry[0];
-} XenPTMSIX;
-
-struct XenPCIPassthroughState {
-    PCIDevice dev;
-
-    PCIHostDeviceAddress hostaddr;
-    bool is_virtfn;
-    XenHostPCIDevice real_device;
-    XenPTRegion bases[PCI_NUM_REGIONS]; /* Access regions */
-    QLIST_HEAD(, XenPTRegGroup) reg_grps;
-
-    uint32_t machine_irq;
-
-    XenPTMSI *msi;
-    XenPTMSIX *msix;
-
-    MemoryRegion bar[PCI_NUM_REGIONS - 1];
-    MemoryRegion rom;
-
-    MemoryListener memory_listener;
-    MemoryListener io_listener;
-};
-
-int xen_pt_config_init(XenPCIPassthroughState *s);
-void xen_pt_config_delete(XenPCIPassthroughState *s);
-XenPTRegGroup *xen_pt_find_reg_grp(XenPCIPassthroughState *s, uint32_t address);
-XenPTReg *xen_pt_find_reg(XenPTRegGroup *reg_grp, uint32_t address);
-int xen_pt_bar_offset_to_index(uint32_t offset);
-
-static inline pcibus_t xen_pt_get_emul_size(XenPTBarFlag flag, pcibus_t r_size)
-{
-    /* align resource size (memory type only) */
-    if (flag == XEN_PT_BAR_FLAG_MEM) {
-        return (r_size + XC_PAGE_SIZE - 1) & XC_PAGE_MASK;
-    } else {
-        return r_size;
-    }
-}
-
-/* INTx */
-/* The PCI Local Bus Specification, Rev. 3.0,
- * Section 6.2.4 Miscellaneous Registers, pp 223
- * outlines 5 valid values for the interrupt pin (intx).
- *  0: For devices (or device functions) that don't use an interrupt in
- *  1: INTA#
- *  2: INTB#
- *  3: INTC#
- *  4: INTD#
- *
- * Xen uses the following 4 values for intx
- *  0: INTA#
- *  1: INTB#
- *  2: INTC#
- *  3: INTD#
- *
- * Observing that these list of values are not the same, xen_pt_pci_read_intx()
- * uses the following mapping from hw to xen values.
- * This seems to reflect the current usage within Xen.
- *
- * PCI hardware    | Xen | Notes
- * ----------------+-----+----------------------------------------------------
- * 0               | 0   | No interrupt
- * 1               | 0   | INTA#
- * 2               | 1   | INTB#
- * 3               | 2   | INTC#
- * 4               | 3   | INTD#
- * any other value | 0   | This should never happen, log error message
- */
-
-static inline uint8_t xen_pt_pci_read_intx(XenPCIPassthroughState *s)
-{
-    uint8_t v = 0;
-    xen_host_pci_get_byte(&s->real_device, PCI_INTERRUPT_PIN, &v);
-    return v;
-}
-
-static inline uint8_t xen_pt_pci_intx(XenPCIPassthroughState *s)
-{
-    uint8_t r_val = xen_pt_pci_read_intx(s);
-
-    XEN_PT_LOG(&s->dev, "intx=%i\n", r_val);
-    if (r_val < 1 || r_val > 4) {
-        XEN_PT_LOG(&s->dev, "Interrupt pin read from hardware is out of range:"
-                   " value=%i, acceptable range is 1 - 4\n", r_val);
-        r_val = 0;
-    } else {
-        r_val -= 1;
-    }
-
-    return r_val;
-}
-
-/* MSI/MSI-X */
-int xen_pt_msi_set_enable(XenPCIPassthroughState *s, bool en);
-int xen_pt_msi_setup(XenPCIPassthroughState *s);
-int xen_pt_msi_update(XenPCIPassthroughState *d);
-void xen_pt_msi_disable(XenPCIPassthroughState *s);
-
-int xen_pt_msix_init(XenPCIPassthroughState *s, uint32_t base);
-void xen_pt_msix_delete(XenPCIPassthroughState *s);
-int xen_pt_msix_update(XenPCIPassthroughState *s);
-int xen_pt_msix_update_remap(XenPCIPassthroughState *s, int bar_index);
-void xen_pt_msix_disable(XenPCIPassthroughState *s);
-
-static inline bool xen_pt_has_msix_mapping(XenPCIPassthroughState *s, int bar)
-{
-    return s->msix && s->msix->bar_index == bar;
-}
-
-
-#endif /* !XEN_PT_H */
diff --git a/hw/xen_pt_config_init.c b/hw/xen_pt_config_init.c
deleted file mode 100644 (file)
index 5583821..0000000
+++ /dev/null
@@ -1,1882 +0,0 @@
-/*
- * Copyright (c) 2007, Neocleus Corporation.
- * Copyright (c) 2007, Intel Corporation.
- *
- * This work is licensed under the terms of the GNU GPL, version 2.  See
- * the COPYING file in the top-level directory.
- *
- * Alex Novik <alex@neocleus.com>
- * Allen Kay <allen.m.kay@intel.com>
- * Guy Zana <guy@neocleus.com>
- *
- * This file implements direct PCI assignment to a HVM guest
- */
-
-#include "qemu/timer.h"
-#include "hw/xen_backend.h"
-#include "hw/xen_pt.h"
-
-#define XEN_PT_MERGE_VALUE(value, data, val_mask) \
-    (((value) & (val_mask)) | ((data) & ~(val_mask)))
-
-#define XEN_PT_INVALID_REG          0xFFFFFFFF      /* invalid register value */
-
-/* prototype */
-
-static int xen_pt_ptr_reg_init(XenPCIPassthroughState *s, XenPTRegInfo *reg,
-                               uint32_t real_offset, uint32_t *data);
-
-
-/* helper */
-
-/* A return value of 1 means the capability should NOT be exposed to guest. */
-static int xen_pt_hide_dev_cap(const XenHostPCIDevice *d, uint8_t grp_id)
-{
-    switch (grp_id) {
-    case PCI_CAP_ID_EXP:
-        /* The PCI Express Capability Structure of the VF of Intel 82599 10GbE
-         * Controller looks trivial, e.g., the PCI Express Capabilities
-         * Register is 0. We should not try to expose it to guest.
-         *
-         * The datasheet is available at
-         * http://download.intel.com/design/network/datashts/82599_datasheet.pdf
-         *
-         * See 'Table 9.7. VF PCIe Configuration Space' of the datasheet, the
-         * PCI Express Capability Structure of the VF of Intel 82599 10GbE
-         * Controller looks trivial, e.g., the PCI Express Capabilities
-         * Register is 0, so the Capability Version is 0 and
-         * xen_pt_pcie_size_init() would fail.
-         */
-        if (d->vendor_id == PCI_VENDOR_ID_INTEL &&
-            d->device_id == PCI_DEVICE_ID_INTEL_82599_SFP_VF) {
-            return 1;
-        }
-        break;
-    }
-    return 0;
-}
-
-/*   find emulate register group entry */
-XenPTRegGroup *xen_pt_find_reg_grp(XenPCIPassthroughState *s, uint32_t address)
-{
-    XenPTRegGroup *entry = NULL;
-
-    /* find register group entry */
-    QLIST_FOREACH(entry, &s->reg_grps, entries) {
-        /* check address */
-        if ((entry->base_offset <= address)
-            && ((entry->base_offset + entry->size) > address)) {
-            return entry;
-        }
-    }
-
-    /* group entry not found */
-    return NULL;
-}
-
-/* find emulate register entry */
-XenPTReg *xen_pt_find_reg(XenPTRegGroup *reg_grp, uint32_t address)
-{
-    XenPTReg *reg_entry = NULL;
-    XenPTRegInfo *reg = NULL;
-    uint32_t real_offset = 0;
-
-    /* find register entry */
-    QLIST_FOREACH(reg_entry, &reg_grp->reg_tbl_list, entries) {
-        reg = reg_entry->reg;
-        real_offset = reg_grp->base_offset + reg->offset;
-        /* check address */
-        if ((real_offset <= address)
-            && ((real_offset + reg->size) > address)) {
-            return reg_entry;
-        }
-    }
-
-    return NULL;
-}
-
-
-/****************
- * general register functions
- */
-
-/* register initialization function */
-
-static int xen_pt_common_reg_init(XenPCIPassthroughState *s,
-                                  XenPTRegInfo *reg, uint32_t real_offset,
-                                  uint32_t *data)
-{
-    *data = reg->init_val;
-    return 0;
-}
-
-/* Read register functions */
-
-static int xen_pt_byte_reg_read(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
-                                uint8_t *value, uint8_t valid_mask)
-{
-    XenPTRegInfo *reg = cfg_entry->reg;
-    uint8_t valid_emu_mask = 0;
-
-    /* emulate byte register */
-    valid_emu_mask = reg->emu_mask & valid_mask;
-    *value = XEN_PT_MERGE_VALUE(*value, cfg_entry->data, ~valid_emu_mask);
-
-    return 0;
-}
-static int xen_pt_word_reg_read(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
-                                uint16_t *value, uint16_t valid_mask)
-{
-    XenPTRegInfo *reg = cfg_entry->reg;
-    uint16_t valid_emu_mask = 0;
-
-    /* emulate word register */
-    valid_emu_mask = reg->emu_mask & valid_mask;
-    *value = XEN_PT_MERGE_VALUE(*value, cfg_entry->data, ~valid_emu_mask);
-
-    return 0;
-}
-static int xen_pt_long_reg_read(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
-                                uint32_t *value, uint32_t valid_mask)
-{
-    XenPTRegInfo *reg = cfg_entry->reg;
-    uint32_t valid_emu_mask = 0;
-
-    /* emulate long register */
-    valid_emu_mask = reg->emu_mask & valid_mask;
-    *value = XEN_PT_MERGE_VALUE(*value, cfg_entry->data, ~valid_emu_mask);
-
-    return 0;
-}
-
-/* Write register functions */
-
-static int xen_pt_byte_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
-                                 uint8_t *val, uint8_t dev_value,
-                                 uint8_t valid_mask)
-{
-    XenPTRegInfo *reg = cfg_entry->reg;
-    uint8_t writable_mask = 0;
-    uint8_t throughable_mask = 0;
-
-    /* modify emulate register */
-    writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
-    cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask);
-
-    /* create value for writing to I/O device register */
-    throughable_mask = ~reg->emu_mask & valid_mask;
-    *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
-
-    return 0;
-}
-static int xen_pt_word_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
-                                 uint16_t *val, uint16_t dev_value,
-                                 uint16_t valid_mask)
-{
-    XenPTRegInfo *reg = cfg_entry->reg;
-    uint16_t writable_mask = 0;
-    uint16_t throughable_mask = 0;
-
-    /* modify emulate register */
-    writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
-    cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask);
-
-    /* create value for writing to I/O device register */
-    throughable_mask = ~reg->emu_mask & valid_mask;
-    *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
-
-    return 0;
-}
-static int xen_pt_long_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
-                                 uint32_t *val, uint32_t dev_value,
-                                 uint32_t valid_mask)
-{
-    XenPTRegInfo *reg = cfg_entry->reg;
-    uint32_t writable_mask = 0;
-    uint32_t throughable_mask = 0;
-
-    /* modify emulate register */
-    writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
-    cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask);
-
-    /* create value for writing to I/O device register */
-    throughable_mask = ~reg->emu_mask & valid_mask;
-    *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
-
-    return 0;
-}
-
-
-/* XenPTRegInfo declaration
- * - only for emulated register (either a part or whole bit).
- * - for passthrough register that need special behavior (like interacting with
- *   other component), set emu_mask to all 0 and specify r/w func properly.
- * - do NOT use ALL F for init_val, otherwise the tbl will not be registered.
- */
-
-/********************
- * Header Type0
- */
-
-static int xen_pt_vendor_reg_init(XenPCIPassthroughState *s,
-                                  XenPTRegInfo *reg, uint32_t real_offset,
-                                  uint32_t *data)
-{
-    *data = s->real_device.vendor_id;
-    return 0;
-}
-static int xen_pt_device_reg_init(XenPCIPassthroughState *s,
-                                  XenPTRegInfo *reg, uint32_t real_offset,
-                                  uint32_t *data)
-{
-    *data = s->real_device.device_id;
-    return 0;
-}
-static int xen_pt_status_reg_init(XenPCIPassthroughState *s,
-                                  XenPTRegInfo *reg, uint32_t real_offset,
-                                  uint32_t *data)
-{
-    XenPTRegGroup *reg_grp_entry = NULL;
-    XenPTReg *reg_entry = NULL;
-    uint32_t reg_field = 0;
-
-    /* find Header register group */
-    reg_grp_entry = xen_pt_find_reg_grp(s, PCI_CAPABILITY_LIST);
-    if (reg_grp_entry) {
-        /* find Capabilities Pointer register */
-        reg_entry = xen_pt_find_reg(reg_grp_entry, PCI_CAPABILITY_LIST);
-        if (reg_entry) {
-            /* check Capabilities Pointer register */
-            if (reg_entry->data) {
-                reg_field |= PCI_STATUS_CAP_LIST;
-            } else {
-                reg_field &= ~PCI_STATUS_CAP_LIST;
-            }
-        } else {
-            xen_shutdown_fatal_error("Internal error: Couldn't find XenPTReg*"
-                                     " for Capabilities Pointer register."
-                                     " (%s)\n", __func__);
-            return -1;
-        }
-    } else {
-        xen_shutdown_fatal_error("Internal error: Couldn't find XenPTRegGroup"
-                                 " for Header. (%s)\n", __func__);
-        return -1;
-    }
-
-    *data = reg_field;
-    return 0;
-}
-static int xen_pt_header_type_reg_init(XenPCIPassthroughState *s,
-                                       XenPTRegInfo *reg, uint32_t real_offset,
-                                       uint32_t *data)
-{
-    /* read PCI_HEADER_TYPE */
-    *data = reg->init_val | 0x80;
-    return 0;
-}
-
-/* initialize Interrupt Pin register */
-static int xen_pt_irqpin_reg_init(XenPCIPassthroughState *s,
-                                  XenPTRegInfo *reg, uint32_t real_offset,
-                                  uint32_t *data)
-{
-    *data = xen_pt_pci_read_intx(s);
-    return 0;
-}
-
-/* Command register */
-static int xen_pt_cmd_reg_read(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
-                               uint16_t *value, uint16_t valid_mask)
-{
-    XenPTRegInfo *reg = cfg_entry->reg;
-    uint16_t valid_emu_mask = 0;
-    uint16_t emu_mask = reg->emu_mask;
-
-    if (s->is_virtfn) {
-        emu_mask |= PCI_COMMAND_MEMORY;
-    }
-
-    /* emulate word register */
-    valid_emu_mask = emu_mask & valid_mask;
-    *value = XEN_PT_MERGE_VALUE(*value, cfg_entry->data, ~valid_emu_mask);
-
-    return 0;
-}
-static int xen_pt_cmd_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
-                                uint16_t *val, uint16_t dev_value,
-                                uint16_t valid_mask)
-{
-    XenPTRegInfo *reg = cfg_entry->reg;
-    uint16_t writable_mask = 0;
-    uint16_t throughable_mask = 0;
-    uint16_t emu_mask = reg->emu_mask;
-
-    if (s->is_virtfn) {
-        emu_mask |= PCI_COMMAND_MEMORY;
-    }
-
-    /* modify emulate register */
-    writable_mask = ~reg->ro_mask & valid_mask;
-    cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask);
-
-    /* create value for writing to I/O device register */
-    throughable_mask = ~emu_mask & valid_mask;
-
-    if (*val & PCI_COMMAND_INTX_DISABLE) {
-        throughable_mask |= PCI_COMMAND_INTX_DISABLE;
-    } else {
-        if (s->machine_irq) {
-            throughable_mask |= PCI_COMMAND_INTX_DISABLE;
-        }
-    }
-
-    *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
-
-    return 0;
-}
-
-/* BAR */
-#define XEN_PT_BAR_MEM_RO_MASK    0x0000000F  /* BAR ReadOnly mask(Memory) */
-#define XEN_PT_BAR_MEM_EMU_MASK   0xFFFFFFF0  /* BAR emul mask(Memory) */
-#define XEN_PT_BAR_IO_RO_MASK     0x00000003  /* BAR ReadOnly mask(I/O) */
-#define XEN_PT_BAR_IO_EMU_MASK    0xFFFFFFFC  /* BAR emul mask(I/O) */
-
-static bool is_64bit_bar(PCIIORegion *r)
-{
-    return !!(r->type & PCI_BASE_ADDRESS_MEM_TYPE_64);
-}
-
-static uint64_t xen_pt_get_bar_size(PCIIORegion *r)
-{
-    if (is_64bit_bar(r)) {
-        uint64_t size64;
-        size64 = (r + 1)->size;
-        size64 <<= 32;
-        size64 += r->size;
-        return size64;
-    }
-    return r->size;
-}
-
-static XenPTBarFlag xen_pt_bar_reg_parse(XenPCIPassthroughState *s,
-                                         XenPTRegInfo *reg)
-{
-    PCIDevice *d = &s->dev;
-    XenPTRegion *region = NULL;
-    PCIIORegion *r;
-    int index = 0;
-
-    /* check 64bit BAR */
-    index = xen_pt_bar_offset_to_index(reg->offset);
-    if ((0 < index) && (index < PCI_ROM_SLOT)) {
-        int type = s->real_device.io_regions[index - 1].type;
-
-        if ((type & XEN_HOST_PCI_REGION_TYPE_MEM)
-            && (type & XEN_HOST_PCI_REGION_TYPE_MEM_64)) {
-            region = &s->bases[index - 1];
-            if (region->bar_flag != XEN_PT_BAR_FLAG_UPPER) {
-                return XEN_PT_BAR_FLAG_UPPER;
-            }
-        }
-    }
-
-    /* check unused BAR */
-    r = &d->io_regions[index];
-    if (!xen_pt_get_bar_size(r)) {
-        return XEN_PT_BAR_FLAG_UNUSED;
-    }
-
-    /* for ExpROM BAR */
-    if (index == PCI_ROM_SLOT) {
-        return XEN_PT_BAR_FLAG_MEM;
-    }
-
-    /* check BAR I/O indicator */
-    if (s->real_device.io_regions[index].type & XEN_HOST_PCI_REGION_TYPE_IO) {
-        return XEN_PT_BAR_FLAG_IO;
-    } else {
-        return XEN_PT_BAR_FLAG_MEM;
-    }
-}
-
-static inline uint32_t base_address_with_flags(XenHostPCIIORegion *hr)
-{
-    if (hr->type & XEN_HOST_PCI_REGION_TYPE_IO) {
-        return hr->base_addr | (hr->bus_flags & ~PCI_BASE_ADDRESS_IO_MASK);
-    } else {
-        return hr->base_addr | (hr->bus_flags & ~PCI_BASE_ADDRESS_MEM_MASK);
-    }
-}
-
-static int xen_pt_bar_reg_init(XenPCIPassthroughState *s, XenPTRegInfo *reg,
-                               uint32_t real_offset, uint32_t *data)
-{
-    uint32_t reg_field = 0;
-    int index;
-
-    index = xen_pt_bar_offset_to_index(reg->offset);
-    if (index < 0 || index >= PCI_NUM_REGIONS) {
-        XEN_PT_ERR(&s->dev, "Internal error: Invalid BAR index [%d].\n", index);
-        return -1;
-    }
-
-    /* set BAR flag */
-    s->bases[index].bar_flag = xen_pt_bar_reg_parse(s, reg);
-    if (s->bases[index].bar_flag == XEN_PT_BAR_FLAG_UNUSED) {
-        reg_field = XEN_PT_INVALID_REG;
-    }
-
-    *data = reg_field;
-    return 0;
-}
-static int xen_pt_bar_reg_read(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
-                               uint32_t *value, uint32_t valid_mask)
-{
-    XenPTRegInfo *reg = cfg_entry->reg;
-    uint32_t valid_emu_mask = 0;
-    uint32_t bar_emu_mask = 0;
-    int index;
-
-    /* get BAR index */
-    index = xen_pt_bar_offset_to_index(reg->offset);
-    if (index < 0 || index >= PCI_NUM_REGIONS) {
-        XEN_PT_ERR(&s->dev, "Internal error: Invalid BAR index [%d].\n", index);
-        return -1;
-    }
-
-    /* use fixed-up value from kernel sysfs */
-    *value = base_address_with_flags(&s->real_device.io_regions[index]);
-
-    /* set emulate mask depend on BAR flag */
-    switch (s->bases[index].bar_flag) {
-    case XEN_PT_BAR_FLAG_MEM:
-        bar_emu_mask = XEN_PT_BAR_MEM_EMU_MASK;
-        break;
-    case XEN_PT_BAR_FLAG_IO:
-        bar_emu_mask = XEN_PT_BAR_IO_EMU_MASK;
-        break;
-    case XEN_PT_BAR_FLAG_UPPER:
-        bar_emu_mask = XEN_PT_BAR_ALLF;
-        break;
-    default:
-        break;
-    }
-
-    /* emulate BAR */
-    valid_emu_mask = bar_emu_mask & valid_mask;
-    *value = XEN_PT_MERGE_VALUE(*value, cfg_entry->data, ~valid_emu_mask);
-
-    return 0;
-}
-static int xen_pt_bar_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
-                                uint32_t *val, uint32_t dev_value,
-                                uint32_t valid_mask)
-{
-    XenPTRegInfo *reg = cfg_entry->reg;
-    XenPTRegion *base = NULL;
-    PCIDevice *d = &s->dev;
-    const PCIIORegion *r;
-    uint32_t writable_mask = 0;
-    uint32_t throughable_mask = 0;
-    uint32_t bar_emu_mask = 0;
-    uint32_t bar_ro_mask = 0;
-    uint32_t r_size = 0;
-    int index = 0;
-
-    index = xen_pt_bar_offset_to_index(reg->offset);
-    if (index < 0 || index >= PCI_NUM_REGIONS) {
-        XEN_PT_ERR(d, "Internal error: Invalid BAR index [%d].\n", index);
-        return -1;
-    }
-
-    r = &d->io_regions[index];
-    base = &s->bases[index];
-    r_size = xen_pt_get_emul_size(base->bar_flag, r->size);
-
-    /* set emulate mask and read-only mask values depend on the BAR flag */
-    switch (s->bases[index].bar_flag) {
-    case XEN_PT_BAR_FLAG_MEM:
-        bar_emu_mask = XEN_PT_BAR_MEM_EMU_MASK;
-        if (!r_size) {
-            /* low 32 bits mask for 64 bit bars */
-            bar_ro_mask = XEN_PT_BAR_ALLF;
-        } else {
-            bar_ro_mask = XEN_PT_BAR_MEM_RO_MASK | (r_size - 1);
-        }
-        break;
-    case XEN_PT_BAR_FLAG_IO:
-        bar_emu_mask = XEN_PT_BAR_IO_EMU_MASK;
-        bar_ro_mask = XEN_PT_BAR_IO_RO_MASK | (r_size - 1);
-        break;
-    case XEN_PT_BAR_FLAG_UPPER:
-        bar_emu_mask = XEN_PT_BAR_ALLF;
-        bar_ro_mask = r_size ? r_size - 1 : 0;
-        break;
-    default:
-        break;
-    }
-
-    /* modify emulate register */
-    writable_mask = bar_emu_mask & ~bar_ro_mask & valid_mask;
-    cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask);
-
-    /* check whether we need to update the virtual region address or not */
-    switch (s->bases[index].bar_flag) {
-    case XEN_PT_BAR_FLAG_UPPER:
-    case XEN_PT_BAR_FLAG_MEM:
-        /* nothing to do */
-        break;
-    case XEN_PT_BAR_FLAG_IO:
-        /* nothing to do */
-        break;
-    default:
-        break;
-    }
-
-    /* create value for writing to I/O device register */
-    throughable_mask = ~bar_emu_mask & valid_mask;
-    *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
-
-    return 0;
-}
-
-/* write Exp ROM BAR */
-static int xen_pt_exp_rom_bar_reg_write(XenPCIPassthroughState *s,
-                                        XenPTReg *cfg_entry, uint32_t *val,
-                                        uint32_t dev_value, uint32_t valid_mask)
-{
-    XenPTRegInfo *reg = cfg_entry->reg;
-    XenPTRegion *base = NULL;
-    PCIDevice *d = (PCIDevice *)&s->dev;
-    uint32_t writable_mask = 0;
-    uint32_t throughable_mask = 0;
-    pcibus_t r_size = 0;
-    uint32_t bar_emu_mask = 0;
-    uint32_t bar_ro_mask = 0;
-
-    r_size = d->io_regions[PCI_ROM_SLOT].size;
-    base = &s->bases[PCI_ROM_SLOT];
-    /* align memory type resource size */
-    r_size = xen_pt_get_emul_size(base->bar_flag, r_size);
-
-    /* set emulate mask and read-only mask */
-    bar_emu_mask = reg->emu_mask;
-    bar_ro_mask = (reg->ro_mask | (r_size - 1)) & ~PCI_ROM_ADDRESS_ENABLE;
-
-    /* modify emulate register */
-    writable_mask = ~bar_ro_mask & valid_mask;
-    cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask);
-
-    /* create value for writing to I/O device register */
-    throughable_mask = ~bar_emu_mask & valid_mask;
-    *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
-
-    return 0;
-}
-
-/* Header Type0 reg static information table */
-static XenPTRegInfo xen_pt_emu_reg_header0[] = {
-    /* Vendor ID reg */
-    {
-        .offset     = PCI_VENDOR_ID,
-        .size       = 2,
-        .init_val   = 0x0000,
-        .ro_mask    = 0xFFFF,
-        .emu_mask   = 0xFFFF,
-        .init       = xen_pt_vendor_reg_init,
-        .u.w.read   = xen_pt_word_reg_read,
-        .u.w.write  = xen_pt_word_reg_write,
-    },
-    /* Device ID reg */
-    {
-        .offset     = PCI_DEVICE_ID,
-        .size       = 2,
-        .init_val   = 0x0000,
-        .ro_mask    = 0xFFFF,
-        .emu_mask   = 0xFFFF,
-        .init       = xen_pt_device_reg_init,
-        .u.w.read   = xen_pt_word_reg_read,
-        .u.w.write  = xen_pt_word_reg_write,
-    },
-    /* Command reg */
-    {
-        .offset     = PCI_COMMAND,
-        .size       = 2,
-        .init_val   = 0x0000,
-        .ro_mask    = 0xF880,
-        .emu_mask   = 0x0740,
-        .init       = xen_pt_common_reg_init,
-        .u.w.read   = xen_pt_cmd_reg_read,
-        .u.w.write  = xen_pt_cmd_reg_write,
-    },
-    /* Capabilities Pointer reg */
-    {
-        .offset     = PCI_CAPABILITY_LIST,
-        .size       = 1,
-        .init_val   = 0x00,
-        .ro_mask    = 0xFF,
-        .emu_mask   = 0xFF,
-        .init       = xen_pt_ptr_reg_init,
-        .u.b.read   = xen_pt_byte_reg_read,
-        .u.b.write  = xen_pt_byte_reg_write,
-    },
-    /* Status reg */
-    /* use emulated Cap Ptr value to initialize,
-     * so need to be declared after Cap Ptr reg
-     */
-    {
-        .offset     = PCI_STATUS,
-        .size       = 2,
-        .init_val   = 0x0000,
-        .ro_mask    = 0x06FF,
-        .emu_mask   = 0x0010,
-        .init       = xen_pt_status_reg_init,
-        .u.w.read   = xen_pt_word_reg_read,
-        .u.w.write  = xen_pt_word_reg_write,
-    },
-    /* Cache Line Size reg */
-    {
-        .offset     = PCI_CACHE_LINE_SIZE,
-        .size       = 1,
-        .init_val   = 0x00,
-        .ro_mask    = 0x00,
-        .emu_mask   = 0xFF,
-        .init       = xen_pt_common_reg_init,
-        .u.b.read   = xen_pt_byte_reg_read,
-        .u.b.write  = xen_pt_byte_reg_write,
-    },
-    /* Latency Timer reg */
-    {
-        .offset     = PCI_LATENCY_TIMER,
-        .size       = 1,
-        .init_val   = 0x00,
-        .ro_mask    = 0x00,
-        .emu_mask   = 0xFF,
-        .init       = xen_pt_common_reg_init,
-        .u.b.read   = xen_pt_byte_reg_read,
-        .u.b.write  = xen_pt_byte_reg_write,
-    },
-    /* Header Type reg */
-    {
-        .offset     = PCI_HEADER_TYPE,
-        .size       = 1,
-        .init_val   = 0x00,
-        .ro_mask    = 0xFF,
-        .emu_mask   = 0x00,
-        .init       = xen_pt_header_type_reg_init,
-        .u.b.read   = xen_pt_byte_reg_read,
-        .u.b.write  = xen_pt_byte_reg_write,
-    },
-    /* Interrupt Line reg */
-    {
-        .offset     = PCI_INTERRUPT_LINE,
-        .size       = 1,
-        .init_val   = 0x00,
-        .ro_mask    = 0x00,
-        .emu_mask   = 0xFF,
-        .init       = xen_pt_common_reg_init,
-        .u.b.read   = xen_pt_byte_reg_read,
-        .u.b.write  = xen_pt_byte_reg_write,
-    },
-    /* Interrupt Pin reg */
-    {
-        .offset     = PCI_INTERRUPT_PIN,
-        .size       = 1,
-        .init_val   = 0x00,
-        .ro_mask    = 0xFF,
-        .emu_mask   = 0xFF,
-        .init       = xen_pt_irqpin_reg_init,
-        .u.b.read   = xen_pt_byte_reg_read,
-        .u.b.write  = xen_pt_byte_reg_write,
-    },
-    /* BAR 0 reg */
-    /* mask of BAR need to be decided later, depends on IO/MEM type */
-    {
-        .offset     = PCI_BASE_ADDRESS_0,
-        .size       = 4,
-        .init_val   = 0x00000000,
-        .init       = xen_pt_bar_reg_init,
-        .u.dw.read  = xen_pt_bar_reg_read,
-        .u.dw.write = xen_pt_bar_reg_write,
-    },
-    /* BAR 1 reg */
-    {
-        .offset     = PCI_BASE_ADDRESS_1,
-        .size       = 4,
-        .init_val   = 0x00000000,
-        .init       = xen_pt_bar_reg_init,
-        .u.dw.read  = xen_pt_bar_reg_read,
-        .u.dw.write = xen_pt_bar_reg_write,
-    },
-    /* BAR 2 reg */
-    {
-        .offset     = PCI_BASE_ADDRESS_2,
-        .size       = 4,
-        .init_val   = 0x00000000,
-        .init       = xen_pt_bar_reg_init,
-        .u.dw.read  = xen_pt_bar_reg_read,
-        .u.dw.write = xen_pt_bar_reg_write,
-    },
-    /* BAR 3 reg */
-    {
-        .offset     = PCI_BASE_ADDRESS_3,
-        .size       = 4,
-        .init_val   = 0x00000000,
-        .init       = xen_pt_bar_reg_init,
-        .u.dw.read  = xen_pt_bar_reg_read,
-        .u.dw.write = xen_pt_bar_reg_write,
-    },
-    /* BAR 4 reg */
-    {
-        .offset     = PCI_BASE_ADDRESS_4,
-        .size       = 4,
-        .init_val   = 0x00000000,
-        .init       = xen_pt_bar_reg_init,
-        .u.dw.read  = xen_pt_bar_reg_read,
-        .u.dw.write = xen_pt_bar_reg_write,
-    },
-    /* BAR 5 reg */
-    {
-        .offset     = PCI_BASE_ADDRESS_5,
-        .size       = 4,
-        .init_val   = 0x00000000,
-        .init       = xen_pt_bar_reg_init,
-        .u.dw.read  = xen_pt_bar_reg_read,
-        .u.dw.write = xen_pt_bar_reg_write,
-    },
-    /* Expansion ROM BAR reg */
-    {
-        .offset     = PCI_ROM_ADDRESS,
-        .size       = 4,
-        .init_val   = 0x00000000,
-        .ro_mask    = 0x000007FE,
-        .emu_mask   = 0xFFFFF800,
-        .init       = xen_pt_bar_reg_init,
-        .u.dw.read  = xen_pt_long_reg_read,
-        .u.dw.write = xen_pt_exp_rom_bar_reg_write,
-    },
-    {
-        .size = 0,
-    },
-};
-
-
-/*********************************
- * Vital Product Data Capability
- */
-
-/* Vital Product Data Capability Structure reg static information table */
-static XenPTRegInfo xen_pt_emu_reg_vpd[] = {
-    {
-        .offset     = PCI_CAP_LIST_NEXT,
-        .size       = 1,
-        .init_val   = 0x00,
-        .ro_mask    = 0xFF,
-        .emu_mask   = 0xFF,
-        .init       = xen_pt_ptr_reg_init,
-        .u.b.read   = xen_pt_byte_reg_read,
-        .u.b.write  = xen_pt_byte_reg_write,
-    },
-    {
-        .size = 0,
-    },
-};
-
-
-/**************************************
- * Vendor Specific Capability
- */
-
-/* Vendor Specific Capability Structure reg static information table */
-static XenPTRegInfo xen_pt_emu_reg_vendor[] = {
-    {
-        .offset     = PCI_CAP_LIST_NEXT,
-        .size       = 1,
-        .init_val   = 0x00,
-        .ro_mask    = 0xFF,
-        .emu_mask   = 0xFF,
-        .init       = xen_pt_ptr_reg_init,
-        .u.b.read   = xen_pt_byte_reg_read,
-        .u.b.write  = xen_pt_byte_reg_write,
-    },
-    {
-        .size = 0,
-    },
-};
-
-
-/*****************************
- * PCI Express Capability
- */
-
-static inline uint8_t get_capability_version(XenPCIPassthroughState *s,
-                                             uint32_t offset)
-{
-    uint8_t flags = pci_get_byte(s->dev.config + offset + PCI_EXP_FLAGS);
-    return flags & PCI_EXP_FLAGS_VERS;
-}
-
-static inline uint8_t get_device_type(XenPCIPassthroughState *s,
-                                      uint32_t offset)
-{
-    uint8_t flags = pci_get_byte(s->dev.config + offset + PCI_EXP_FLAGS);
-    return (flags & PCI_EXP_FLAGS_TYPE) >> 4;
-}
-
-/* initialize Link Control register */
-static int xen_pt_linkctrl_reg_init(XenPCIPassthroughState *s,
-                                    XenPTRegInfo *reg, uint32_t real_offset,
-                                    uint32_t *data)
-{
-    uint8_t cap_ver = get_capability_version(s, real_offset - reg->offset);
-    uint8_t dev_type = get_device_type(s, real_offset - reg->offset);
-
-    /* no need to initialize in case of Root Complex Integrated Endpoint
-     * with cap_ver 1.x
-     */
-    if ((dev_type == PCI_EXP_TYPE_RC_END) && (cap_ver == 1)) {
-        *data = XEN_PT_INVALID_REG;
-    }
-
-    *data = reg->init_val;
-    return 0;
-}
-/* initialize Device Control 2 register */
-static int xen_pt_devctrl2_reg_init(XenPCIPassthroughState *s,
-                                    XenPTRegInfo *reg, uint32_t real_offset,
-                                    uint32_t *data)
-{
-    uint8_t cap_ver = get_capability_version(s, real_offset - reg->offset);
-
-    /* no need to initialize in case of cap_ver 1.x */
-    if (cap_ver == 1) {
-        *data = XEN_PT_INVALID_REG;
-    }
-
-    *data = reg->init_val;
-    return 0;
-}
-/* initialize Link Control 2 register */
-static int xen_pt_linkctrl2_reg_init(XenPCIPassthroughState *s,
-                                     XenPTRegInfo *reg, uint32_t real_offset,
-                                     uint32_t *data)
-{
-    uint8_t cap_ver = get_capability_version(s, real_offset - reg->offset);
-    uint32_t reg_field = 0;
-
-    /* no need to initialize in case of cap_ver 1.x */
-    if (cap_ver == 1) {
-        reg_field = XEN_PT_INVALID_REG;
-    } else {
-        /* set Supported Link Speed */
-        uint8_t lnkcap = pci_get_byte(s->dev.config + real_offset - reg->offset
-                                      + PCI_EXP_LNKCAP);
-        reg_field |= PCI_EXP_LNKCAP_SLS & lnkcap;
-    }
-
-    *data = reg_field;
-    return 0;
-}
-
-/* PCI Express Capability Structure reg static information table */
-static XenPTRegInfo xen_pt_emu_reg_pcie[] = {
-    /* Next Pointer reg */
-    {
-        .offset     = PCI_CAP_LIST_NEXT,
-        .size       = 1,
-        .init_val   = 0x00,
-        .ro_mask    = 0xFF,
-        .emu_mask   = 0xFF,
-        .init       = xen_pt_ptr_reg_init,
-        .u.b.read   = xen_pt_byte_reg_read,
-        .u.b.write  = xen_pt_byte_reg_write,
-    },
-    /* Device Capabilities reg */
-    {
-        .offset     = PCI_EXP_DEVCAP,
-        .size       = 4,
-        .init_val   = 0x00000000,
-        .ro_mask    = 0x1FFCFFFF,
-        .emu_mask   = 0x10000000,
-        .init       = xen_pt_common_reg_init,
-        .u.dw.read  = xen_pt_long_reg_read,
-        .u.dw.write = xen_pt_long_reg_write,
-    },
-    /* Device Control reg */
-    {
-        .offset     = PCI_EXP_DEVCTL,
-        .size       = 2,
-        .init_val   = 0x2810,
-        .ro_mask    = 0x8400,
-        .emu_mask   = 0xFFFF,
-        .init       = xen_pt_common_reg_init,
-        .u.w.read   = xen_pt_word_reg_read,
-        .u.w.write  = xen_pt_word_reg_write,
-    },
-    /* Link Control reg */
-    {
-        .offset     = PCI_EXP_LNKCTL,
-        .size       = 2,
-        .init_val   = 0x0000,
-        .ro_mask    = 0xFC34,
-        .emu_mask   = 0xFFFF,
-        .init       = xen_pt_linkctrl_reg_init,
-        .u.w.read   = xen_pt_word_reg_read,
-        .u.w.write  = xen_pt_word_reg_write,
-    },
-    /* Device Control 2 reg */
-    {
-        .offset     = 0x28,
-        .size       = 2,
-        .init_val   = 0x0000,
-        .ro_mask    = 0xFFE0,
-        .emu_mask   = 0xFFFF,
-        .init       = xen_pt_devctrl2_reg_init,
-        .u.w.read   = xen_pt_word_reg_read,
-        .u.w.write  = xen_pt_word_reg_write,
-    },
-    /* Link Control 2 reg */
-    {
-        .offset     = 0x30,
-        .size       = 2,
-        .init_val   = 0x0000,
-        .ro_mask    = 0xE040,
-        .emu_mask   = 0xFFFF,
-        .init       = xen_pt_linkctrl2_reg_init,
-        .u.w.read   = xen_pt_word_reg_read,
-        .u.w.write  = xen_pt_word_reg_write,
-    },
-    {
-        .size = 0,
-    },
-};
-
-
-/*********************************
- * Power Management Capability
- */
-
-/* read Power Management Control/Status register */
-static int xen_pt_pmcsr_reg_read(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
-                                 uint16_t *value, uint16_t valid_mask)
-{
-    XenPTRegInfo *reg = cfg_entry->reg;
-    uint16_t valid_emu_mask = reg->emu_mask;
-
-    valid_emu_mask |= PCI_PM_CTRL_STATE_MASK | PCI_PM_CTRL_NO_SOFT_RESET;
-
-    valid_emu_mask = valid_emu_mask & valid_mask;
-    *value = XEN_PT_MERGE_VALUE(*value, cfg_entry->data, ~valid_emu_mask);
-
-    return 0;
-}
-/* write Power Management Control/Status register */
-static int xen_pt_pmcsr_reg_write(XenPCIPassthroughState *s,
-                                  XenPTReg *cfg_entry, uint16_t *val,
-                                  uint16_t dev_value, uint16_t valid_mask)
-{
-    XenPTRegInfo *reg = cfg_entry->reg;
-    uint16_t emu_mask = reg->emu_mask;
-    uint16_t writable_mask = 0;
-    uint16_t throughable_mask = 0;
-
-    emu_mask |= PCI_PM_CTRL_STATE_MASK | PCI_PM_CTRL_NO_SOFT_RESET;
-
-    /* modify emulate register */
-    writable_mask = emu_mask & ~reg->ro_mask & valid_mask;
-    cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask);
-
-    /* create value for writing to I/O device register */
-    throughable_mask = ~emu_mask & valid_mask;
-    *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
-
-    return 0;
-}
-
-/* Power Management Capability reg static information table */
-static XenPTRegInfo xen_pt_emu_reg_pm[] = {
-    /* Next Pointer reg */
-    {
-        .offset     = PCI_CAP_LIST_NEXT,
-        .size       = 1,
-        .init_val   = 0x00,
-        .ro_mask    = 0xFF,
-        .emu_mask   = 0xFF,
-        .init       = xen_pt_ptr_reg_init,
-        .u.b.read   = xen_pt_byte_reg_read,
-        .u.b.write  = xen_pt_byte_reg_write,
-    },
-    /* Power Management Capabilities reg */
-    {
-        .offset     = PCI_CAP_FLAGS,
-        .size       = 2,
-        .init_val   = 0x0000,
-        .ro_mask    = 0xFFFF,
-        .emu_mask   = 0xF9C8,
-        .init       = xen_pt_common_reg_init,
-        .u.w.read   = xen_pt_word_reg_read,
-        .u.w.write  = xen_pt_word_reg_write,
-    },
-    /* PCI Power Management Control/Status reg */
-    {
-        .offset     = PCI_PM_CTRL,
-        .size       = 2,
-        .init_val   = 0x0008,
-        .ro_mask    = 0xE1FC,
-        .emu_mask   = 0x8100,
-        .init       = xen_pt_common_reg_init,
-        .u.w.read   = xen_pt_pmcsr_reg_read,
-        .u.w.write  = xen_pt_pmcsr_reg_write,
-    },
-    {
-        .size = 0,
-    },
-};
-
-
-/********************************
- * MSI Capability
- */
-
-/* Helper */
-static bool xen_pt_msgdata_check_type(uint32_t offset, uint16_t flags)
-{
-    /* check the offset whether matches the type or not */
-    bool is_32 = (offset == PCI_MSI_DATA_32) && !(flags & PCI_MSI_FLAGS_64BIT);
-    bool is_64 = (offset == PCI_MSI_DATA_64) &&  (flags & PCI_MSI_FLAGS_64BIT);
-    return is_32 || is_64;
-}
-
-/* Message Control register */
-static int xen_pt_msgctrl_reg_init(XenPCIPassthroughState *s,
-                                   XenPTRegInfo *reg, uint32_t real_offset,
-                                   uint32_t *data)
-{
-    PCIDevice *d = &s->dev;
-    XenPTMSI *msi = s->msi;
-    uint16_t reg_field = 0;
-
-    /* use I/O device register's value as initial value */
-    reg_field = pci_get_word(d->config + real_offset);
-
-    if (reg_field & PCI_MSI_FLAGS_ENABLE) {
-        XEN_PT_LOG(&s->dev, "MSI already enabled, disabling it first\n");
-        xen_host_pci_set_word(&s->real_device, real_offset,
-                              reg_field & ~PCI_MSI_FLAGS_ENABLE);
-    }
-    msi->flags |= reg_field;
-    msi->ctrl_offset = real_offset;
-    msi->initialized = false;
-    msi->mapped = false;
-
-    *data = reg->init_val;
-    return 0;
-}
-static int xen_pt_msgctrl_reg_write(XenPCIPassthroughState *s,
-                                    XenPTReg *cfg_entry, uint16_t *val,
-                                    uint16_t dev_value, uint16_t valid_mask)
-{
-    XenPTRegInfo *reg = cfg_entry->reg;
-    XenPTMSI *msi = s->msi;
-    uint16_t writable_mask = 0;
-    uint16_t throughable_mask = 0;
-    uint16_t raw_val;
-
-    /* Currently no support for multi-vector */
-    if (*val & PCI_MSI_FLAGS_QSIZE) {
-        XEN_PT_WARN(&s->dev, "Tries to set more than 1 vector ctrl %x\n", *val);
-    }
-
-    /* modify emulate register */
-    writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
-    cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask);
-    msi->flags |= cfg_entry->data & ~PCI_MSI_FLAGS_ENABLE;
-
-    /* create value for writing to I/O device register */
-    raw_val = *val;
-    throughable_mask = ~reg->emu_mask & valid_mask;
-    *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
-
-    /* update MSI */
-    if (raw_val & PCI_MSI_FLAGS_ENABLE) {
-        /* setup MSI pirq for the first time */
-        if (!msi->initialized) {
-            /* Init physical one */
-            XEN_PT_LOG(&s->dev, "setup MSI\n");
-            if (xen_pt_msi_setup(s)) {
-                /* We do not broadcast the error to the framework code, so
-                 * that MSI errors are contained in MSI emulation code and
-                 * QEMU can go on running.
-                 * Guest MSI would be actually not working.
-                 */
-                *val &= ~PCI_MSI_FLAGS_ENABLE;
-                XEN_PT_WARN(&s->dev, "Can not map MSI.\n");
-                return 0;
-            }
-            if (xen_pt_msi_update(s)) {
-                *val &= ~PCI_MSI_FLAGS_ENABLE;
-                XEN_PT_WARN(&s->dev, "Can not bind MSI\n");
-                return 0;
-            }
-            msi->initialized = true;
-            msi->mapped = true;
-        }
-        msi->flags |= PCI_MSI_FLAGS_ENABLE;
-    } else {
-        msi->flags &= ~PCI_MSI_FLAGS_ENABLE;
-    }
-
-    /* pass through MSI_ENABLE bit */
-    *val &= ~PCI_MSI_FLAGS_ENABLE;
-    *val |= raw_val & PCI_MSI_FLAGS_ENABLE;
-
-    return 0;
-}
-
-/* initialize Message Upper Address register */
-static int xen_pt_msgaddr64_reg_init(XenPCIPassthroughState *s,
-                                     XenPTRegInfo *reg, uint32_t real_offset,
-                                     uint32_t *data)
-{
-    /* no need to initialize in case of 32 bit type */
-    if (!(s->msi->flags & PCI_MSI_FLAGS_64BIT)) {
-        *data = XEN_PT_INVALID_REG;
-    } else {
-        *data = reg->init_val;
-    }
-
-    return 0;
-}
-/* this function will be called twice (for 32 bit and 64 bit type) */
-/* initialize Message Data register */
-static int xen_pt_msgdata_reg_init(XenPCIPassthroughState *s,
-                                   XenPTRegInfo *reg, uint32_t real_offset,
-                                   uint32_t *data)
-{
-    uint32_t flags = s->msi->flags;
-    uint32_t offset = reg->offset;
-
-    /* check the offset whether matches the type or not */
-    if (xen_pt_msgdata_check_type(offset, flags)) {
-        *data = reg->init_val;
-    } else {
-        *data = XEN_PT_INVALID_REG;
-    }
-    return 0;
-}
-
-/* write Message Address register */
-static int xen_pt_msgaddr32_reg_write(XenPCIPassthroughState *s,
-                                      XenPTReg *cfg_entry, uint32_t *val,
-                                      uint32_t dev_value, uint32_t valid_mask)
-{
-    XenPTRegInfo *reg = cfg_entry->reg;
-    uint32_t writable_mask = 0;
-    uint32_t throughable_mask = 0;
-    uint32_t old_addr = cfg_entry->data;
-
-    /* modify emulate register */
-    writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
-    cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask);
-    s->msi->addr_lo = cfg_entry->data;
-
-    /* create value for writing to I/O device register */
-    throughable_mask = ~reg->emu_mask & valid_mask;
-    *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
-
-    /* update MSI */
-    if (cfg_entry->data != old_addr) {
-        if (s->msi->mapped) {
-            xen_pt_msi_update(s);
-        }
-    }
-
-    return 0;
-}
-/* write Message Upper Address register */
-static int xen_pt_msgaddr64_reg_write(XenPCIPassthroughState *s,
-                                      XenPTReg *cfg_entry, uint32_t *val,
-                                      uint32_t dev_value, uint32_t valid_mask)
-{
-    XenPTRegInfo *reg = cfg_entry->reg;
-    uint32_t writable_mask = 0;
-    uint32_t throughable_mask = 0;
-    uint32_t old_addr = cfg_entry->data;
-
-    /* check whether the type is 64 bit or not */
-    if (!(s->msi->flags & PCI_MSI_FLAGS_64BIT)) {
-        XEN_PT_ERR(&s->dev,
-                   "Can't write to the upper address without 64 bit support\n");
-        return -1;
-    }
-
-    /* modify emulate register */
-    writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
-    cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask);
-    /* update the msi_info too */
-    s->msi->addr_hi = cfg_entry->data;
-
-    /* create value for writing to I/O device register */
-    throughable_mask = ~reg->emu_mask & valid_mask;
-    *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
-
-    /* update MSI */
-    if (cfg_entry->data != old_addr) {
-        if (s->msi->mapped) {
-            xen_pt_msi_update(s);
-        }
-    }
-
-    return 0;
-}
-
-
-/* this function will be called twice (for 32 bit and 64 bit type) */
-/* write Message Data register */
-static int xen_pt_msgdata_reg_write(XenPCIPassthroughState *s,
-                                    XenPTReg *cfg_entry, uint16_t *val,
-                                    uint16_t dev_value, uint16_t valid_mask)
-{
-    XenPTRegInfo *reg = cfg_entry->reg;
-    XenPTMSI *msi = s->msi;
-    uint16_t writable_mask = 0;
-    uint16_t throughable_mask = 0;
-    uint16_t old_data = cfg_entry->data;
-    uint32_t offset = reg->offset;
-
-    /* check the offset whether matches the type or not */
-    if (!xen_pt_msgdata_check_type(offset, msi->flags)) {
-        /* exit I/O emulator */
-        XEN_PT_ERR(&s->dev, "the offset does not match the 32/64 bit type!\n");
-        return -1;
-    }
-
-    /* modify emulate register */
-    writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
-    cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask);
-    /* update the msi_info too */
-    msi->data = cfg_entry->data;
-
-    /* create value for writing to I/O device register */
-    throughable_mask = ~reg->emu_mask & valid_mask;
-    *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
-
-    /* update MSI */
-    if (cfg_entry->data != old_data) {
-        if (msi->mapped) {
-            xen_pt_msi_update(s);
-        }
-    }
-
-    return 0;
-}
-
-/* MSI Capability Structure reg static information table */
-static XenPTRegInfo xen_pt_emu_reg_msi[] = {
-    /* Next Pointer reg */
-    {
-        .offset     = PCI_CAP_LIST_NEXT,
-        .size       = 1,
-        .init_val   = 0x00,
-        .ro_mask    = 0xFF,
-        .emu_mask   = 0xFF,
-        .init       = xen_pt_ptr_reg_init,
-        .u.b.read   = xen_pt_byte_reg_read,
-        .u.b.write  = xen_pt_byte_reg_write,
-    },
-    /* Message Control reg */
-    {
-        .offset     = PCI_MSI_FLAGS,
-        .size       = 2,
-        .init_val   = 0x0000,
-        .ro_mask    = 0xFF8E,
-        .emu_mask   = 0x007F,
-        .init       = xen_pt_msgctrl_reg_init,
-        .u.w.read   = xen_pt_word_reg_read,
-        .u.w.write  = xen_pt_msgctrl_reg_write,
-    },
-    /* Message Address reg */
-    {
-        .offset     = PCI_MSI_ADDRESS_LO,
-        .size       = 4,
-        .init_val   = 0x00000000,
-        .ro_mask    = 0x00000003,
-        .emu_mask   = 0xFFFFFFFF,
-        .no_wb      = 1,
-        .init       = xen_pt_common_reg_init,
-        .u.dw.read  = xen_pt_long_reg_read,
-        .u.dw.write = xen_pt_msgaddr32_reg_write,
-    },
-    /* Message Upper Address reg (if PCI_MSI_FLAGS_64BIT set) */
-    {
-        .offset     = PCI_MSI_ADDRESS_HI,
-        .size       = 4,
-        .init_val   = 0x00000000,
-        .ro_mask    = 0x00000000,
-        .emu_mask   = 0xFFFFFFFF,
-        .no_wb      = 1,
-        .init       = xen_pt_msgaddr64_reg_init,
-        .u.dw.read  = xen_pt_long_reg_read,
-        .u.dw.write = xen_pt_msgaddr64_reg_write,
-    },
-    /* Message Data reg (16 bits of data for 32-bit devices) */
-    {
-        .offset     = PCI_MSI_DATA_32,
-        .size       = 2,
-        .init_val   = 0x0000,
-        .ro_mask    = 0x0000,
-        .emu_mask   = 0xFFFF,
-        .no_wb      = 1,
-        .init       = xen_pt_msgdata_reg_init,
-        .u.w.read   = xen_pt_word_reg_read,
-        .u.w.write  = xen_pt_msgdata_reg_write,
-    },
-    /* Message Data reg (16 bits of data for 64-bit devices) */
-    {
-        .offset     = PCI_MSI_DATA_64,
-        .size       = 2,
-        .init_val   = 0x0000,
-        .ro_mask    = 0x0000,
-        .emu_mask   = 0xFFFF,
-        .no_wb      = 1,
-        .init       = xen_pt_msgdata_reg_init,
-        .u.w.read   = xen_pt_word_reg_read,
-        .u.w.write  = xen_pt_msgdata_reg_write,
-    },
-    {
-        .size = 0,
-    },
-};
-
-
-/**************************************
- * MSI-X Capability
- */
-
-/* Message Control register for MSI-X */
-static int xen_pt_msixctrl_reg_init(XenPCIPassthroughState *s,
-                                    XenPTRegInfo *reg, uint32_t real_offset,
-                                    uint32_t *data)
-{
-    PCIDevice *d = &s->dev;
-    uint16_t reg_field = 0;
-
-    /* use I/O device register's value as initial value */
-    reg_field = pci_get_word(d->config + real_offset);
-
-    if (reg_field & PCI_MSIX_FLAGS_ENABLE) {
-        XEN_PT_LOG(d, "MSIX already enabled, disabling it first\n");
-        xen_host_pci_set_word(&s->real_device, real_offset,
-                              reg_field & ~PCI_MSIX_FLAGS_ENABLE);
-    }
-
-    s->msix->ctrl_offset = real_offset;
-
-    *data = reg->init_val;
-    return 0;
-}
-static int xen_pt_msixctrl_reg_write(XenPCIPassthroughState *s,
-                                     XenPTReg *cfg_entry, uint16_t *val,
-                                     uint16_t dev_value, uint16_t valid_mask)
-{
-    XenPTRegInfo *reg = cfg_entry->reg;
-    uint16_t writable_mask = 0;
-    uint16_t throughable_mask = 0;
-    int debug_msix_enabled_old;
-
-    /* modify emulate register */
-    writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
-    cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask);
-
-    /* create value for writing to I/O device register */
-    throughable_mask = ~reg->emu_mask & valid_mask;
-    *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
-
-    /* update MSI-X */
-    if ((*val & PCI_MSIX_FLAGS_ENABLE)
-        && !(*val & PCI_MSIX_FLAGS_MASKALL)) {
-        xen_pt_msix_update(s);
-    }
-
-    debug_msix_enabled_old = s->msix->enabled;
-    s->msix->enabled = !!(*val & PCI_MSIX_FLAGS_ENABLE);
-    if (s->msix->enabled != debug_msix_enabled_old) {
-        XEN_PT_LOG(&s->dev, "%s MSI-X\n",
-                   s->msix->enabled ? "enable" : "disable");
-    }
-
-    return 0;
-}
-
-/* MSI-X Capability Structure reg static information table */
-static XenPTRegInfo xen_pt_emu_reg_msix[] = {
-    /* Next Pointer reg */
-    {
-        .offset     = PCI_CAP_LIST_NEXT,
-        .size       = 1,
-        .init_val   = 0x00,
-        .ro_mask    = 0xFF,
-        .emu_mask   = 0xFF,
-        .init       = xen_pt_ptr_reg_init,
-        .u.b.read   = xen_pt_byte_reg_read,
-        .u.b.write  = xen_pt_byte_reg_write,
-    },
-    /* Message Control reg */
-    {
-        .offset     = PCI_MSI_FLAGS,
-        .size       = 2,
-        .init_val   = 0x0000,
-        .ro_mask    = 0x3FFF,
-        .emu_mask   = 0x0000,
-        .init       = xen_pt_msixctrl_reg_init,
-        .u.w.read   = xen_pt_word_reg_read,
-        .u.w.write  = xen_pt_msixctrl_reg_write,
-    },
-    {
-        .size = 0,
-    },
-};
-
-
-/****************************
- * Capabilities
- */
-
-/* capability structure register group size functions */
-
-static int xen_pt_reg_grp_size_init(XenPCIPassthroughState *s,
-                                    const XenPTRegGroupInfo *grp_reg,
-                                    uint32_t base_offset, uint8_t *size)
-{
-    *size = grp_reg->grp_size;
-    return 0;
-}
-/* get Vendor Specific Capability Structure register group size */
-static int xen_pt_vendor_size_init(XenPCIPassthroughState *s,
-                                   const XenPTRegGroupInfo *grp_reg,
-                                   uint32_t base_offset, uint8_t *size)
-{
-    *size = pci_get_byte(s->dev.config + base_offset + 0x02);
-    return 0;
-}
-/* get PCI Express Capability Structure register group size */
-static int xen_pt_pcie_size_init(XenPCIPassthroughState *s,
-                                 const XenPTRegGroupInfo *grp_reg,
-                                 uint32_t base_offset, uint8_t *size)
-{
-    PCIDevice *d = &s->dev;
-    uint8_t version = get_capability_version(s, base_offset);
-    uint8_t type = get_device_type(s, base_offset);
-    uint8_t pcie_size = 0;
-
-
-    /* calculate size depend on capability version and device/port type */
-    /* in case of PCI Express Base Specification Rev 1.x */
-    if (version == 1) {
-        /* The PCI Express Capabilities, Device Capabilities, and Device
-         * Status/Control registers are required for all PCI Express devices.
-         * The Link Capabilities and Link Status/Control are required for all
-         * Endpoints that are not Root Complex Integrated Endpoints. Endpoints
-         * are not required to implement registers other than those listed
-         * above and terminate the capability structure.
-         */
-        switch (type) {
-        case PCI_EXP_TYPE_ENDPOINT:
-        case PCI_EXP_TYPE_LEG_END:
-            pcie_size = 0x14;
-            break;
-        case PCI_EXP_TYPE_RC_END:
-            /* has no link */
-            pcie_size = 0x0C;
-            break;
-            /* only EndPoint passthrough is supported */
-        case PCI_EXP_TYPE_ROOT_PORT:
-        case PCI_EXP_TYPE_UPSTREAM:
-        case PCI_EXP_TYPE_DOWNSTREAM:
-        case PCI_EXP_TYPE_PCI_BRIDGE:
-        case PCI_EXP_TYPE_PCIE_BRIDGE:
-        case PCI_EXP_TYPE_RC_EC:
-        default:
-            XEN_PT_ERR(d, "Unsupported device/port type %#x.\n", type);
-            return -1;
-        }
-    }
-    /* in case of PCI Express Base Specification Rev 2.0 */
-    else if (version == 2) {
-        switch (type) {
-        case PCI_EXP_TYPE_ENDPOINT:
-        case PCI_EXP_TYPE_LEG_END:
-        case PCI_EXP_TYPE_RC_END:
-            /* For Functions that do not implement the registers,
-             * these spaces must be hardwired to 0b.
-             */
-            pcie_size = 0x3C;
-            break;
-            /* only EndPoint passthrough is supported */
-        case PCI_EXP_TYPE_ROOT_PORT:
-        case PCI_EXP_TYPE_UPSTREAM:
-        case PCI_EXP_TYPE_DOWNSTREAM:
-        case PCI_EXP_TYPE_PCI_BRIDGE:
-        case PCI_EXP_TYPE_PCIE_BRIDGE:
-        case PCI_EXP_TYPE_RC_EC:
-        default:
-            XEN_PT_ERR(d, "Unsupported device/port type %#x.\n", type);
-            return -1;
-        }
-    } else {
-        XEN_PT_ERR(d, "Unsupported capability version %#x.\n", version);
-        return -1;
-    }
-
-    *size = pcie_size;
-    return 0;
-}
-/* get MSI Capability Structure register group size */
-static int xen_pt_msi_size_init(XenPCIPassthroughState *s,
-                                const XenPTRegGroupInfo *grp_reg,
-                                uint32_t base_offset, uint8_t *size)
-{
-    PCIDevice *d = &s->dev;
-    uint16_t msg_ctrl = 0;
-    uint8_t msi_size = 0xa;
-
-    msg_ctrl = pci_get_word(d->config + (base_offset + PCI_MSI_FLAGS));
-
-    /* check if 64-bit address is capable of per-vector masking */
-    if (msg_ctrl & PCI_MSI_FLAGS_64BIT) {
-        msi_size += 4;
-    }
-    if (msg_ctrl & PCI_MSI_FLAGS_MASKBIT) {
-        msi_size += 10;
-    }
-
-    s->msi = g_new0(XenPTMSI, 1);
-    s->msi->pirq = XEN_PT_UNASSIGNED_PIRQ;
-
-    *size = msi_size;
-    return 0;
-}
-/* get MSI-X Capability Structure register group size */
-static int xen_pt_msix_size_init(XenPCIPassthroughState *s,
-                                 const XenPTRegGroupInfo *grp_reg,
-                                 uint32_t base_offset, uint8_t *size)
-{
-    int rc = 0;
-
-    rc = xen_pt_msix_init(s, base_offset);
-
-    if (rc < 0) {
-        XEN_PT_ERR(&s->dev, "Internal error: Invalid xen_pt_msix_init.\n");
-        return rc;
-    }
-
-    *size = grp_reg->grp_size;
-    return 0;
-}
-
-
-static const XenPTRegGroupInfo xen_pt_emu_reg_grps[] = {
-    /* Header Type0 reg group */
-    {
-        .grp_id      = 0xFF,
-        .grp_type    = XEN_PT_GRP_TYPE_EMU,
-        .grp_size    = 0x40,
-        .size_init   = xen_pt_reg_grp_size_init,
-        .emu_regs = xen_pt_emu_reg_header0,
-    },
-    /* PCI PowerManagement Capability reg group */
-    {
-        .grp_id      = PCI_CAP_ID_PM,
-        .grp_type    = XEN_PT_GRP_TYPE_EMU,
-        .grp_size    = PCI_PM_SIZEOF,
-        .size_init   = xen_pt_reg_grp_size_init,
-        .emu_regs = xen_pt_emu_reg_pm,
-    },
-    /* AGP Capability Structure reg group */
-    {
-        .grp_id     = PCI_CAP_ID_AGP,
-        .grp_type   = XEN_PT_GRP_TYPE_HARDWIRED,
-        .grp_size   = 0x30,
-        .size_init  = xen_pt_reg_grp_size_init,
-    },
-    /* Vital Product Data Capability Structure reg group */
-    {
-        .grp_id      = PCI_CAP_ID_VPD,
-        .grp_type    = XEN_PT_GRP_TYPE_EMU,
-        .grp_size    = 0x08,
-        .size_init   = xen_pt_reg_grp_size_init,
-        .emu_regs = xen_pt_emu_reg_vpd,
-    },
-    /* Slot Identification reg group */
-    {
-        .grp_id     = PCI_CAP_ID_SLOTID,
-        .grp_type   = XEN_PT_GRP_TYPE_HARDWIRED,
-        .grp_size   = 0x04,
-        .size_init  = xen_pt_reg_grp_size_init,
-    },
-    /* MSI Capability Structure reg group */
-    {
-        .grp_id      = PCI_CAP_ID_MSI,
-        .grp_type    = XEN_PT_GRP_TYPE_EMU,
-        .grp_size    = 0xFF,
-        .size_init   = xen_pt_msi_size_init,
-        .emu_regs = xen_pt_emu_reg_msi,
-    },
-    /* PCI-X Capabilities List Item reg group */
-    {
-        .grp_id     = PCI_CAP_ID_PCIX,
-        .grp_type   = XEN_PT_GRP_TYPE_HARDWIRED,
-        .grp_size   = 0x18,
-        .size_init  = xen_pt_reg_grp_size_init,
-    },
-    /* Vendor Specific Capability Structure reg group */
-    {
-        .grp_id      = PCI_CAP_ID_VNDR,
-        .grp_type    = XEN_PT_GRP_TYPE_EMU,
-        .grp_size    = 0xFF,
-        .size_init   = xen_pt_vendor_size_init,
-        .emu_regs = xen_pt_emu_reg_vendor,
-    },
-    /* SHPC Capability List Item reg group */
-    {
-        .grp_id     = PCI_CAP_ID_SHPC,
-        .grp_type   = XEN_PT_GRP_TYPE_HARDWIRED,
-        .grp_size   = 0x08,
-        .size_init  = xen_pt_reg_grp_size_init,
-    },
-    /* Subsystem ID and Subsystem Vendor ID Capability List Item reg group */
-    {
-        .grp_id     = PCI_CAP_ID_SSVID,
-        .grp_type   = XEN_PT_GRP_TYPE_HARDWIRED,
-        .grp_size   = 0x08,
-        .size_init  = xen_pt_reg_grp_size_init,
-    },
-    /* AGP 8x Capability Structure reg group */
-    {
-        .grp_id     = PCI_CAP_ID_AGP3,
-        .grp_type   = XEN_PT_GRP_TYPE_HARDWIRED,
-        .grp_size   = 0x30,
-        .size_init  = xen_pt_reg_grp_size_init,
-    },
-    /* PCI Express Capability Structure reg group */
-    {
-        .grp_id      = PCI_CAP_ID_EXP,
-        .grp_type    = XEN_PT_GRP_TYPE_EMU,
-        .grp_size    = 0xFF,
-        .size_init   = xen_pt_pcie_size_init,
-        .emu_regs = xen_pt_emu_reg_pcie,
-    },
-    /* MSI-X Capability Structure reg group */
-    {
-        .grp_id      = PCI_CAP_ID_MSIX,
-        .grp_type    = XEN_PT_GRP_TYPE_EMU,
-        .grp_size    = 0x0C,
-        .size_init   = xen_pt_msix_size_init,
-        .emu_regs = xen_pt_emu_reg_msix,
-    },
-    {
-        .grp_size = 0,
-    },
-};
-
-/* initialize Capabilities Pointer or Next Pointer register */
-static int xen_pt_ptr_reg_init(XenPCIPassthroughState *s,
-                               XenPTRegInfo *reg, uint32_t real_offset,
-                               uint32_t *data)
-{
-    int i;
-    uint8_t *config = s->dev.config;
-    uint32_t reg_field = pci_get_byte(config + real_offset);
-    uint8_t cap_id = 0;
-
-    /* find capability offset */
-    while (reg_field) {
-        for (i = 0; xen_pt_emu_reg_grps[i].grp_size != 0; i++) {
-            if (xen_pt_hide_dev_cap(&s->real_device,
-                                    xen_pt_emu_reg_grps[i].grp_id)) {
-                continue;
-            }
-
-            cap_id = pci_get_byte(config + reg_field + PCI_CAP_LIST_ID);
-            if (xen_pt_emu_reg_grps[i].grp_id == cap_id) {
-                if (xen_pt_emu_reg_grps[i].grp_type == XEN_PT_GRP_TYPE_EMU) {
-                    goto out;
-                }
-                /* ignore the 0 hardwired capability, find next one */
-                break;
-            }
-        }
-
-        /* next capability */
-        reg_field = pci_get_byte(config + reg_field + PCI_CAP_LIST_NEXT);
-    }
-
-out:
-    *data = reg_field;
-    return 0;
-}
-
-
-/*************
- * Main
- */
-
-static uint8_t find_cap_offset(XenPCIPassthroughState *s, uint8_t cap)
-{
-    uint8_t id;
-    unsigned max_cap = PCI_CAP_MAX;
-    uint8_t pos = PCI_CAPABILITY_LIST;
-    uint8_t status = 0;
-
-    if (xen_host_pci_get_byte(&s->real_device, PCI_STATUS, &status)) {
-        return 0;
-    }
-    if ((status & PCI_STATUS_CAP_LIST) == 0) {
-        return 0;
-    }
-
-    while (max_cap--) {
-        if (xen_host_pci_get_byte(&s->real_device, pos, &pos)) {
-            break;
-        }
-        if (pos < PCI_CONFIG_HEADER_SIZE) {
-            break;
-        }
-
-        pos &= ~3;
-        if (xen_host_pci_get_byte(&s->real_device,
-                                  pos + PCI_CAP_LIST_ID, &id)) {
-            break;
-        }
-
-        if (id == 0xff) {
-            break;
-        }
-        if (id == cap) {
-            return pos;
-        }
-
-        pos += PCI_CAP_LIST_NEXT;
-    }
-    return 0;
-}
-
-static int xen_pt_config_reg_init(XenPCIPassthroughState *s,
-                                  XenPTRegGroup *reg_grp, XenPTRegInfo *reg)
-{
-    XenPTReg *reg_entry;
-    uint32_t data = 0;
-    int rc = 0;
-
-    reg_entry = g_new0(XenPTReg, 1);
-    reg_entry->reg = reg;
-
-    if (reg->init) {
-        /* initialize emulate register */
-        rc = reg->init(s, reg_entry->reg,
-                       reg_grp->base_offset + reg->offset, &data);
-        if (rc < 0) {
-            free(reg_entry);
-            return rc;
-        }
-        if (data == XEN_PT_INVALID_REG) {
-            /* free unused BAR register entry */
-            free(reg_entry);
-            return 0;
-        }
-        /* set register value */
-        reg_entry->data = data;
-    }
-    /* list add register entry */
-    QLIST_INSERT_HEAD(&reg_grp->reg_tbl_list, reg_entry, entries);
-
-    return 0;
-}
-
-int xen_pt_config_init(XenPCIPassthroughState *s)
-{
-    int i, rc;
-
-    QLIST_INIT(&s->reg_grps);
-
-    for (i = 0; xen_pt_emu_reg_grps[i].grp_size != 0; i++) {
-        uint32_t reg_grp_offset = 0;
-        XenPTRegGroup *reg_grp_entry = NULL;
-
-        if (xen_pt_emu_reg_grps[i].grp_id != 0xFF) {
-            if (xen_pt_hide_dev_cap(&s->real_device,
-                                    xen_pt_emu_reg_grps[i].grp_id)) {
-                continue;
-            }
-
-            reg_grp_offset = find_cap_offset(s, xen_pt_emu_reg_grps[i].grp_id);
-
-            if (!reg_grp_offset) {
-                continue;
-            }
-        }
-
-        reg_grp_entry = g_new0(XenPTRegGroup, 1);
-        QLIST_INIT(&reg_grp_entry->reg_tbl_list);
-        QLIST_INSERT_HEAD(&s->reg_grps, reg_grp_entry, entries);
-
-        reg_grp_entry->base_offset = reg_grp_offset;
-        reg_grp_entry->reg_grp = xen_pt_emu_reg_grps + i;
-        if (xen_pt_emu_reg_grps[i].size_init) {
-            /* get register group size */
-            rc = xen_pt_emu_reg_grps[i].size_init(s, reg_grp_entry->reg_grp,
-                                                  reg_grp_offset,
-                                                  &reg_grp_entry->size);
-            if (rc < 0) {
-                xen_pt_config_delete(s);
-                return rc;
-            }
-        }
-
-        if (xen_pt_emu_reg_grps[i].grp_type == XEN_PT_GRP_TYPE_EMU) {
-            if (xen_pt_emu_reg_grps[i].emu_regs) {
-                int j = 0;
-                XenPTRegInfo *regs = xen_pt_emu_reg_grps[i].emu_regs;
-                /* initialize capability register */
-                for (j = 0; regs->size != 0; j++, regs++) {
-                    /* initialize capability register */
-                    rc = xen_pt_config_reg_init(s, reg_grp_entry, regs);
-                    if (rc < 0) {
-                        xen_pt_config_delete(s);
-                        return rc;
-                    }
-                }
-            }
-        }
-    }
-
-    return 0;
-}
-
-/* delete all emulate register */
-void xen_pt_config_delete(XenPCIPassthroughState *s)
-{
-    struct XenPTRegGroup *reg_group, *next_grp;
-    struct XenPTReg *reg, *next_reg;
-
-    /* free MSI/MSI-X info table */
-    if (s->msix) {
-        xen_pt_msix_delete(s);
-    }
-    if (s->msi) {
-        g_free(s->msi);
-    }
-
-    /* free all register group entry */
-    QLIST_FOREACH_SAFE(reg_group, &s->reg_grps, entries, next_grp) {
-        /* free all register entry */
-        QLIST_FOREACH_SAFE(reg, &reg_group->reg_tbl_list, entries, next_reg) {
-            QLIST_REMOVE(reg, entries);
-            g_free(reg);
-        }
-
-        QLIST_REMOVE(reg_group, entries);
-        g_free(reg_group);
-    }
-}
diff --git a/hw/xen_pt_msi.c b/hw/xen_pt_msi.c
deleted file mode 100644 (file)
index a54ee2b..0000000
+++ /dev/null
@@ -1,620 +0,0 @@
-/*
- * Copyright (c) 2007, Intel Corporation.
- *
- * This work is licensed under the terms of the GNU GPL, version 2.  See
- * the COPYING file in the top-level directory.
- *
- * Jiang Yunhong <yunhong.jiang@intel.com>
- *
- * This file implements direct PCI assignment to a HVM guest
- */
-
-#include <sys/mman.h>
-
-#include "hw/xen_backend.h"
-#include "hw/xen_pt.h"
-#include "hw/apic-msidef.h"
-
-
-#define XEN_PT_AUTO_ASSIGN -1
-
-/* shift count for gflags */
-#define XEN_PT_GFLAGS_SHIFT_DEST_ID        0
-#define XEN_PT_GFLAGS_SHIFT_RH             8
-#define XEN_PT_GFLAGS_SHIFT_DM             9
-#define XEN_PT_GFLAGSSHIFT_DELIV_MODE     12
-#define XEN_PT_GFLAGSSHIFT_TRG_MODE       15
-
-
-/*
- * Helpers
- */
-
-static inline uint8_t msi_vector(uint32_t data)
-{
-    return (data & MSI_DATA_VECTOR_MASK) >> MSI_DATA_VECTOR_SHIFT;
-}
-
-static inline uint8_t msi_dest_id(uint32_t addr)
-{
-    return (addr & MSI_ADDR_DEST_ID_MASK) >> MSI_ADDR_DEST_ID_SHIFT;
-}
-
-static inline uint32_t msi_ext_dest_id(uint32_t addr_hi)
-{
-    return addr_hi & 0xffffff00;
-}
-
-static uint32_t msi_gflags(uint32_t data, uint64_t addr)
-{
-    uint32_t result = 0;
-    int rh, dm, dest_id, deliv_mode, trig_mode;
-
-    rh = (addr >> MSI_ADDR_REDIRECTION_SHIFT) & 0x1;
-    dm = (addr >> MSI_ADDR_DEST_MODE_SHIFT) & 0x1;
-    dest_id = msi_dest_id(addr);
-    deliv_mode = (data >> MSI_DATA_DELIVERY_MODE_SHIFT) & 0x7;
-    trig_mode = (data >> MSI_DATA_TRIGGER_SHIFT) & 0x1;
-
-    result = dest_id | (rh << XEN_PT_GFLAGS_SHIFT_RH)
-        | (dm << XEN_PT_GFLAGS_SHIFT_DM)
-        | (deliv_mode << XEN_PT_GFLAGSSHIFT_DELIV_MODE)
-        | (trig_mode << XEN_PT_GFLAGSSHIFT_TRG_MODE);
-
-    return result;
-}
-
-static inline uint64_t msi_addr64(XenPTMSI *msi)
-{
-    return (uint64_t)msi->addr_hi << 32 | msi->addr_lo;
-}
-
-static int msi_msix_enable(XenPCIPassthroughState *s,
-                           uint32_t address,
-                           uint16_t flag,
-                           bool enable)
-{
-    uint16_t val = 0;
-
-    if (!address) {
-        return -1;
-    }
-
-    xen_host_pci_get_word(&s->real_device, address, &val);
-    if (enable) {
-        val |= flag;
-    } else {
-        val &= ~flag;
-    }
-    xen_host_pci_set_word(&s->real_device, address, val);
-    return 0;
-}
-
-static int msi_msix_setup(XenPCIPassthroughState *s,
-                          uint64_t addr,
-                          uint32_t data,
-                          int *ppirq,
-                          bool is_msix,
-                          int msix_entry,
-                          bool is_not_mapped)
-{
-    uint8_t gvec = msi_vector(data);
-    int rc = 0;
-
-    assert((!is_msix && msix_entry == 0) || is_msix);
-
-    if (gvec == 0) {
-        /* if gvec is 0, the guest is asking for a particular pirq that
-         * is passed as dest_id */
-        *ppirq = msi_ext_dest_id(addr >> 32) | msi_dest_id(addr);
-        if (!*ppirq) {
-            /* this probably identifies an misconfiguration of the guest,
-             * try the emulated path */
-            *ppirq = XEN_PT_UNASSIGNED_PIRQ;
-        } else {
-            XEN_PT_LOG(&s->dev, "requested pirq %d for MSI%s"
-                       " (vec: %#x, entry: %#x)\n",
-                       *ppirq, is_msix ? "-X" : "", gvec, msix_entry);
-        }
-    }
-
-    if (is_not_mapped) {
-        uint64_t table_base = 0;
-
-        if (is_msix) {
-            table_base = s->msix->table_base;
-        }
-
-        rc = xc_physdev_map_pirq_msi(xen_xc, xen_domid, XEN_PT_AUTO_ASSIGN,
-                                     ppirq, PCI_DEVFN(s->real_device.dev,
-                                                      s->real_device.func),
-                                     s->real_device.bus,
-                                     msix_entry, table_base);
-        if (rc) {
-            XEN_PT_ERR(&s->dev,
-                       "Mapping of MSI%s (rc: %i, vec: %#x, entry %#x)\n",
-                       is_msix ? "-X" : "", rc, gvec, msix_entry);
-            return rc;
-        }
-    }
-
-    return 0;
-}
-static int msi_msix_update(XenPCIPassthroughState *s,
-                           uint64_t addr,
-                           uint32_t data,
-                           int pirq,
-                           bool is_msix,
-                           int msix_entry,
-                           int *old_pirq)
-{
-    PCIDevice *d = &s->dev;
-    uint8_t gvec = msi_vector(data);
-    uint32_t gflags = msi_gflags(data, addr);
-    int rc = 0;
-    uint64_t table_addr = 0;
-
-    XEN_PT_LOG(d, "Updating MSI%s with pirq %d gvec %#x gflags %#x"
-               " (entry: %#x)\n",
-               is_msix ? "-X" : "", pirq, gvec, gflags, msix_entry);
-
-    if (is_msix) {
-        table_addr = s->msix->mmio_base_addr;
-    }
-
-    rc = xc_domain_update_msi_irq(xen_xc, xen_domid, gvec,
-                                  pirq, gflags, table_addr);
-
-    if (rc) {
-        XEN_PT_ERR(d, "Updating of MSI%s failed. (rc: %d)\n",
-                   is_msix ? "-X" : "", rc);
-
-        if (xc_physdev_unmap_pirq(xen_xc, xen_domid, *old_pirq)) {
-            XEN_PT_ERR(d, "Unmapping of MSI%s pirq %d failed.\n",
-                       is_msix ? "-X" : "", *old_pirq);
-        }
-        *old_pirq = XEN_PT_UNASSIGNED_PIRQ;
-    }
-    return rc;
-}
-
-static int msi_msix_disable(XenPCIPassthroughState *s,
-                            uint64_t addr,
-                            uint32_t data,
-                            int pirq,
-                            bool is_msix,
-                            bool is_binded)
-{
-    PCIDevice *d = &s->dev;
-    uint8_t gvec = msi_vector(data);
-    uint32_t gflags = msi_gflags(data, addr);
-    int rc = 0;
-
-    if (pirq == XEN_PT_UNASSIGNED_PIRQ) {
-        return 0;
-    }
-
-    if (is_binded) {
-        XEN_PT_LOG(d, "Unbind MSI%s with pirq %d, gvec %#x\n",
-                   is_msix ? "-X" : "", pirq, gvec);
-        rc = xc_domain_unbind_msi_irq(xen_xc, xen_domid, gvec, pirq, gflags);
-        if (rc) {
-            XEN_PT_ERR(d, "Unbinding of MSI%s failed. (pirq: %d, gvec: %#x)\n",
-                       is_msix ? "-X" : "", pirq, gvec);
-            return rc;
-        }
-    }
-
-    XEN_PT_LOG(d, "Unmap MSI%s pirq %d\n", is_msix ? "-X" : "", pirq);
-    rc = xc_physdev_unmap_pirq(xen_xc, xen_domid, pirq);
-    if (rc) {
-        XEN_PT_ERR(d, "Unmapping of MSI%s pirq %d failed. (rc: %i)\n",
-                   is_msix ? "-X" : "", pirq, rc);
-        return rc;
-    }
-
-    return 0;
-}
-
-/*
- * MSI virtualization functions
- */
-
-int xen_pt_msi_set_enable(XenPCIPassthroughState *s, bool enable)
-{
-    XEN_PT_LOG(&s->dev, "%s MSI.\n", enable ? "enabling" : "disabling");
-
-    if (!s->msi) {
-        return -1;
-    }
-
-    return msi_msix_enable(s, s->msi->ctrl_offset, PCI_MSI_FLAGS_ENABLE,
-                           enable);
-}
-
-/* setup physical msi, but don't enable it */
-int xen_pt_msi_setup(XenPCIPassthroughState *s)
-{
-    int pirq = XEN_PT_UNASSIGNED_PIRQ;
-    int rc = 0;
-    XenPTMSI *msi = s->msi;
-
-    if (msi->initialized) {
-        XEN_PT_ERR(&s->dev,
-                   "Setup physical MSI when it has been properly initialized.\n");
-        return -1;
-    }
-
-    rc = msi_msix_setup(s, msi_addr64(msi), msi->data, &pirq, false, 0, true);
-    if (rc) {
-        return rc;
-    }
-
-    if (pirq < 0) {
-        XEN_PT_ERR(&s->dev, "Invalid pirq number: %d.\n", pirq);
-        return -1;
-    }
-
-    msi->pirq = pirq;
-    XEN_PT_LOG(&s->dev, "MSI mapped with pirq %d.\n", pirq);
-
-    return 0;
-}
-
-int xen_pt_msi_update(XenPCIPassthroughState *s)
-{
-    XenPTMSI *msi = s->msi;
-    return msi_msix_update(s, msi_addr64(msi), msi->data, msi->pirq,
-                           false, 0, &msi->pirq);
-}
-
-void xen_pt_msi_disable(XenPCIPassthroughState *s)
-{
-    XenPTMSI *msi = s->msi;
-
-    if (!msi) {
-        return;
-    }
-
-    xen_pt_msi_set_enable(s, false);
-
-    msi_msix_disable(s, msi_addr64(msi), msi->data, msi->pirq, false,
-                     msi->initialized);
-
-    /* clear msi info */
-    msi->flags = 0;
-    msi->mapped = false;
-    msi->pirq = XEN_PT_UNASSIGNED_PIRQ;
-}
-
-/*
- * MSI-X virtualization functions
- */
-
-static int msix_set_enable(XenPCIPassthroughState *s, bool enabled)
-{
-    XEN_PT_LOG(&s->dev, "%s MSI-X.\n", enabled ? "enabling" : "disabling");
-
-    if (!s->msix) {
-        return -1;
-    }
-
-    return msi_msix_enable(s, s->msix->ctrl_offset, PCI_MSIX_FLAGS_ENABLE,
-                           enabled);
-}
-
-static int xen_pt_msix_update_one(XenPCIPassthroughState *s, int entry_nr)
-{
-    XenPTMSIXEntry *entry = NULL;
-    int pirq;
-    int rc;
-
-    if (entry_nr < 0 || entry_nr >= s->msix->total_entries) {
-        return -EINVAL;
-    }
-
-    entry = &s->msix->msix_entry[entry_nr];
-
-    if (!entry->updated) {
-        return 0;
-    }
-
-    pirq = entry->pirq;
-
-    rc = msi_msix_setup(s, entry->addr, entry->data, &pirq, true, entry_nr,
-                        entry->pirq == XEN_PT_UNASSIGNED_PIRQ);
-    if (rc) {
-        return rc;
-    }
-    if (entry->pirq == XEN_PT_UNASSIGNED_PIRQ) {
-        entry->pirq = pirq;
-    }
-
-    rc = msi_msix_update(s, entry->addr, entry->data, pirq, true,
-                         entry_nr, &entry->pirq);
-
-    if (!rc) {
-        entry->updated = false;
-    }
-
-    return rc;
-}
-
-int xen_pt_msix_update(XenPCIPassthroughState *s)
-{
-    XenPTMSIX *msix = s->msix;
-    int i;
-
-    for (i = 0; i < msix->total_entries; i++) {
-        xen_pt_msix_update_one(s, i);
-    }
-
-    return 0;
-}
-
-void xen_pt_msix_disable(XenPCIPassthroughState *s)
-{
-    int i = 0;
-
-    msix_set_enable(s, false);
-
-    for (i = 0; i < s->msix->total_entries; i++) {
-        XenPTMSIXEntry *entry = &s->msix->msix_entry[i];
-
-        msi_msix_disable(s, entry->addr, entry->data, entry->pirq, true, true);
-
-        /* clear MSI-X info */
-        entry->pirq = XEN_PT_UNASSIGNED_PIRQ;
-        entry->updated = false;
-    }
-}
-
-int xen_pt_msix_update_remap(XenPCIPassthroughState *s, int bar_index)
-{
-    XenPTMSIXEntry *entry;
-    int i, ret;
-
-    if (!(s->msix && s->msix->bar_index == bar_index)) {
-        return 0;
-    }
-
-    for (i = 0; i < s->msix->total_entries; i++) {
-        entry = &s->msix->msix_entry[i];
-        if (entry->pirq != XEN_PT_UNASSIGNED_PIRQ) {
-            ret = xc_domain_unbind_pt_irq(xen_xc, xen_domid, entry->pirq,
-                                          PT_IRQ_TYPE_MSI, 0, 0, 0, 0);
-            if (ret) {
-                XEN_PT_ERR(&s->dev, "unbind MSI-X entry %d failed\n",
-                           entry->pirq);
-            }
-            entry->updated = true;
-        }
-    }
-    return xen_pt_msix_update(s);
-}
-
-static uint32_t get_entry_value(XenPTMSIXEntry *e, int offset)
-{
-    switch (offset) {
-    case PCI_MSIX_ENTRY_LOWER_ADDR:
-        return e->addr & UINT32_MAX;
-    case PCI_MSIX_ENTRY_UPPER_ADDR:
-        return e->addr >> 32;
-    case PCI_MSIX_ENTRY_DATA:
-        return e->data;
-    case PCI_MSIX_ENTRY_VECTOR_CTRL:
-        return e->vector_ctrl;
-    default:
-        return 0;
-    }
-}
-
-static void set_entry_value(XenPTMSIXEntry *e, int offset, uint32_t val)
-{
-    switch (offset) {
-    case PCI_MSIX_ENTRY_LOWER_ADDR:
-        e->addr = (e->addr & ((uint64_t)UINT32_MAX << 32)) | val;
-        break;
-    case PCI_MSIX_ENTRY_UPPER_ADDR:
-        e->addr = (uint64_t)val << 32 | (e->addr & UINT32_MAX);
-        break;
-    case PCI_MSIX_ENTRY_DATA:
-        e->data = val;
-        break;
-    case PCI_MSIX_ENTRY_VECTOR_CTRL:
-        e->vector_ctrl = val;
-        break;
-    }
-}
-
-static void pci_msix_write(void *opaque, hwaddr addr,
-                           uint64_t val, unsigned size)
-{
-    XenPCIPassthroughState *s = opaque;
-    XenPTMSIX *msix = s->msix;
-    XenPTMSIXEntry *entry;
-    int entry_nr, offset;
-
-    entry_nr = addr / PCI_MSIX_ENTRY_SIZE;
-    if (entry_nr < 0 || entry_nr >= msix->total_entries) {
-        XEN_PT_ERR(&s->dev, "asked MSI-X entry '%i' invalid!\n", entry_nr);
-        return;
-    }
-    entry = &msix->msix_entry[entry_nr];
-    offset = addr % PCI_MSIX_ENTRY_SIZE;
-
-    if (offset != PCI_MSIX_ENTRY_VECTOR_CTRL) {
-        const volatile uint32_t *vec_ctrl;
-
-        if (get_entry_value(entry, offset) == val) {
-            return;
-        }
-
-        /*
-         * If Xen intercepts the mask bit access, entry->vec_ctrl may not be
-         * up-to-date. Read from hardware directly.
-         */
-        vec_ctrl = s->msix->phys_iomem_base + entry_nr * PCI_MSIX_ENTRY_SIZE
-            + PCI_MSIX_ENTRY_VECTOR_CTRL;
-
-        if (msix->enabled && !(*vec_ctrl & PCI_MSIX_ENTRY_CTRL_MASKBIT)) {
-            XEN_PT_ERR(&s->dev, "Can't update msix entry %d since MSI-X is"
-                       " already enabled.\n", entry_nr);
-            return;
-        }
-
-        entry->updated = true;
-    }
-
-    set_entry_value(entry, offset, val);
-
-    if (offset == PCI_MSIX_ENTRY_VECTOR_CTRL) {
-        if (msix->enabled && !(val & PCI_MSIX_ENTRY_CTRL_MASKBIT)) {
-            xen_pt_msix_update_one(s, entry_nr);
-        }
-    }
-}
-
-static uint64_t pci_msix_read(void *opaque, hwaddr addr,
-                              unsigned size)
-{
-    XenPCIPassthroughState *s = opaque;
-    XenPTMSIX *msix = s->msix;
-    int entry_nr, offset;
-
-    entry_nr = addr / PCI_MSIX_ENTRY_SIZE;
-    if (entry_nr < 0) {
-        XEN_PT_ERR(&s->dev, "asked MSI-X entry '%i' invalid!\n", entry_nr);
-        return 0;
-    }
-
-    offset = addr % PCI_MSIX_ENTRY_SIZE;
-
-    if (addr < msix->total_entries * PCI_MSIX_ENTRY_SIZE) {
-        return get_entry_value(&msix->msix_entry[entry_nr], offset);
-    } else {
-        /* Pending Bit Array (PBA) */
-        return *(uint32_t *)(msix->phys_iomem_base + addr);
-    }
-}
-
-static const MemoryRegionOps pci_msix_ops = {
-    .read = pci_msix_read,
-    .write = pci_msix_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-        .unaligned = false,
-    },
-};
-
-int xen_pt_msix_init(XenPCIPassthroughState *s, uint32_t base)
-{
-    uint8_t id = 0;
-    uint16_t control = 0;
-    uint32_t table_off = 0;
-    int i, total_entries, bar_index;
-    XenHostPCIDevice *hd = &s->real_device;
-    PCIDevice *d = &s->dev;
-    int fd = -1;
-    XenPTMSIX *msix = NULL;
-    int rc = 0;
-
-    rc = xen_host_pci_get_byte(hd, base + PCI_CAP_LIST_ID, &id);
-    if (rc) {
-        return rc;
-    }
-
-    if (id != PCI_CAP_ID_MSIX) {
-        XEN_PT_ERR(d, "Invalid id %#x base %#x\n", id, base);
-        return -1;
-    }
-
-    xen_host_pci_get_word(hd, base + PCI_MSIX_FLAGS, &control);
-    total_entries = control & PCI_MSIX_FLAGS_QSIZE;
-    total_entries += 1;
-
-    s->msix = g_malloc0(sizeof (XenPTMSIX)
-                        + total_entries * sizeof (XenPTMSIXEntry));
-    msix = s->msix;
-
-    msix->total_entries = total_entries;
-    for (i = 0; i < total_entries; i++) {
-        msix->msix_entry[i].pirq = XEN_PT_UNASSIGNED_PIRQ;
-    }
-
-    memory_region_init_io(&msix->mmio, &pci_msix_ops, s, "xen-pci-pt-msix",
-                          (total_entries * PCI_MSIX_ENTRY_SIZE
-                           + XC_PAGE_SIZE - 1)
-                          & XC_PAGE_MASK);
-
-    xen_host_pci_get_long(hd, base + PCI_MSIX_TABLE, &table_off);
-    bar_index = msix->bar_index = table_off & PCI_MSIX_FLAGS_BIRMASK;
-    table_off = table_off & ~PCI_MSIX_FLAGS_BIRMASK;
-    msix->table_base = s->real_device.io_regions[bar_index].base_addr;
-    XEN_PT_LOG(d, "get MSI-X table BAR base 0x%"PRIx64"\n", msix->table_base);
-
-    fd = open("/dev/mem", O_RDWR);
-    if (fd == -1) {
-        rc = -errno;
-        XEN_PT_ERR(d, "Can't open /dev/mem: %s\n", strerror(errno));
-        goto error_out;
-    }
-    XEN_PT_LOG(d, "table_off = %#x, total_entries = %d\n",
-               table_off, total_entries);
-    msix->table_offset_adjust = table_off & 0x0fff;
-    msix->phys_iomem_base =
-        mmap(NULL,
-             total_entries * PCI_MSIX_ENTRY_SIZE + msix->table_offset_adjust,
-             PROT_READ,
-             MAP_SHARED | MAP_LOCKED,
-             fd,
-             msix->table_base + table_off - msix->table_offset_adjust);
-    close(fd);
-    if (msix->phys_iomem_base == MAP_FAILED) {
-        rc = -errno;
-        XEN_PT_ERR(d, "Can't map physical MSI-X table: %s\n", strerror(errno));
-        goto error_out;
-    }
-    msix->phys_iomem_base = (char *)msix->phys_iomem_base
-        + msix->table_offset_adjust;
-
-    XEN_PT_LOG(d, "mapping physical MSI-X table to %p\n",
-               msix->phys_iomem_base);
-
-    memory_region_add_subregion_overlap(&s->bar[bar_index], table_off,
-                                        &msix->mmio,
-                                        2); /* Priority: pci default + 1 */
-
-    return 0;
-
-error_out:
-    memory_region_destroy(&msix->mmio);
-    g_free(s->msix);
-    s->msix = NULL;
-    return rc;
-}
-
-void xen_pt_msix_delete(XenPCIPassthroughState *s)
-{
-    XenPTMSIX *msix = s->msix;
-
-    if (!msix) {
-        return;
-    }
-
-    /* unmap the MSI-X memory mapped register area */
-    if (msix->phys_iomem_base) {
-        XEN_PT_LOG(&s->dev, "unmapping physical MSI-X table from %p\n",
-                   msix->phys_iomem_base);
-        munmap(msix->phys_iomem_base, msix->total_entries * PCI_MSIX_ENTRY_SIZE
-               + msix->table_offset_adjust);
-    }
-
-    memory_region_del_subregion(&s->bar[msix->bar_index], &msix->mmio);
-    memory_region_destroy(&msix->mmio);
-
-    g_free(s->msix);
-    s->msix = NULL;
-}
diff --git a/hw/xenfb.c b/hw/xenfb.c
deleted file mode 100644 (file)
index 7c46a2f..0000000
+++ /dev/null
@@ -1,1021 +0,0 @@
-/*
- *  xen paravirt framebuffer backend
- *
- *  Copyright IBM, Corp. 2005-2006
- *  Copyright Red Hat, Inc. 2006-2008
- *
- *  Authors:
- *       Anthony Liguori <aliguori@us.ibm.com>,
- *       Markus Armbruster <armbru@redhat.com>,
- *       Daniel P. Berrange <berrange@redhat.com>,
- *       Pat Campbell <plc@novell.com>,
- *       Gerd Hoffmann <kraxel@redhat.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; under version 2 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
- *  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 <stdarg.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <sys/mman.h>
-#include <errno.h>
-#include <stdio.h>
-#include <string.h>
-#include <time.h>
-
-#include "hw/hw.h"
-#include "ui/console.h"
-#include "char/char.h"
-#include "hw/xen_backend.h"
-
-#include <xen/event_channel.h>
-#include <xen/io/fbif.h>
-#include <xen/io/kbdif.h>
-#include <xen/io/protocols.h>
-
-#ifndef BTN_LEFT
-#define BTN_LEFT 0x110 /* from <linux/input.h> */
-#endif
-
-/* -------------------------------------------------------------------- */
-
-struct common {
-    struct XenDevice  xendev;  /* must be first */
-    void              *page;
-    QemuConsole       *con;
-};
-
-struct XenInput {
-    struct common c;
-    int abs_pointer_wanted; /* Whether guest supports absolute pointer */
-    int button_state;       /* Last seen pointer button state */
-    int extended;
-    QEMUPutMouseEntry *qmouse;
-};
-
-#define UP_QUEUE 8
-
-struct XenFB {
-    struct common     c;
-    size_t            fb_len;
-    int               row_stride;
-    int               depth;
-    int               width;
-    int               height;
-    int               offset;
-    void              *pixels;
-    int               fbpages;
-    int               feature_update;
-    int               refresh_period;
-    int               bug_trigger;
-    int               have_console;
-    int               do_resize;
-
-    struct {
-       int x,y,w,h;
-    } up_rects[UP_QUEUE];
-    int               up_count;
-    int               up_fullscreen;
-};
-
-/* -------------------------------------------------------------------- */
-
-static int common_bind(struct common *c)
-{
-    int mfn;
-
-    if (xenstore_read_fe_int(&c->xendev, "page-ref", &mfn) == -1)
-       return -1;
-    if (xenstore_read_fe_int(&c->xendev, "event-channel", &c->xendev.remote_port) == -1)
-       return -1;
-
-    c->page = xc_map_foreign_range(xen_xc, c->xendev.dom,
-                                  XC_PAGE_SIZE,
-                                  PROT_READ | PROT_WRITE, mfn);
-    if (c->page == NULL)
-       return -1;
-
-    xen_be_bind_evtchn(&c->xendev);
-    xen_be_printf(&c->xendev, 1, "ring mfn %d, remote-port %d, local-port %d\n",
-                 mfn, c->xendev.remote_port, c->xendev.local_port);
-
-    return 0;
-}
-
-static void common_unbind(struct common *c)
-{
-    xen_be_unbind_evtchn(&c->xendev);
-    if (c->page) {
-       munmap(c->page, XC_PAGE_SIZE);
-       c->page = NULL;
-    }
-}
-
-/* -------------------------------------------------------------------- */
-
-#if 0
-/*
- * These two tables are not needed any more, but left in here
- * intentionally as documentation, to show how scancode2linux[]
- * was generated.
- *
- * Tables to map from scancode to Linux input layer keycode.
- * Scancodes are hardware-specific.  These maps assumes a
- * standard AT or PS/2 keyboard which is what QEMU feeds us.
- */
-const unsigned char atkbd_set2_keycode[512] = {
-
-     0, 67, 65, 63, 61, 59, 60, 88,  0, 68, 66, 64, 62, 15, 41,117,
-     0, 56, 42, 93, 29, 16,  2,  0,  0,  0, 44, 31, 30, 17,  3,  0,
-     0, 46, 45, 32, 18,  5,  4, 95,  0, 57, 47, 33, 20, 19,  6,183,
-     0, 49, 48, 35, 34, 21,  7,184,  0,  0, 50, 36, 22,  8,  9,185,
-     0, 51, 37, 23, 24, 11, 10,  0,  0, 52, 53, 38, 39, 25, 12,  0,
-     0, 89, 40,  0, 26, 13,  0,  0, 58, 54, 28, 27,  0, 43,  0, 85,
-     0, 86, 91, 90, 92,  0, 14, 94,  0, 79,124, 75, 71,121,  0,  0,
-    82, 83, 80, 76, 77, 72,  1, 69, 87, 78, 81, 74, 55, 73, 70, 99,
-
-      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    217,100,255,  0, 97,165,  0,  0,156,  0,  0,  0,  0,  0,  0,125,
-    173,114,  0,113,  0,  0,  0,126,128,  0,  0,140,  0,  0,  0,127,
-    159,  0,115,  0,164,  0,  0,116,158,  0,150,166,  0,  0,  0,142,
-    157,  0,  0,  0,  0,  0,  0,  0,155,  0, 98,  0,  0,163,  0,  0,
-    226,  0,  0,  0,  0,  0,  0,  0,  0,255, 96,  0,  0,  0,143,  0,
-      0,  0,  0,  0,  0,  0,  0,  0,  0,107,  0,105,102,  0,  0,112,
-    110,111,108,112,106,103,  0,119,  0,118,109,  0, 99,104,119,  0,
-
-};
-
-const unsigned char atkbd_unxlate_table[128] = {
-
-      0,118, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85,102, 13,
-     21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 20, 28, 27,
-     35, 43, 52, 51, 59, 66, 75, 76, 82, 14, 18, 93, 26, 34, 33, 42,
-     50, 49, 58, 65, 73, 74, 89,124, 17, 41, 88,  5,  6,  4, 12,  3,
-     11,  2, 10,  1,  9,119,126,108,117,125,123,107,115,116,121,105,
-    114,122,112,113,127, 96, 97,120,  7, 15, 23, 31, 39, 47, 55, 63,
-     71, 79, 86, 94,  8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 87,111,
-     19, 25, 57, 81, 83, 92, 95, 98, 99,100,101,103,104,106,109,110
-
-};
-#endif
-
-/*
- * for (i = 0; i < 128; i++) {
- *     scancode2linux[i] = atkbd_set2_keycode[atkbd_unxlate_table[i]];
- *     scancode2linux[i | 0x80] = atkbd_set2_keycode[atkbd_unxlate_table[i] | 0x80];
- * }
- */
-static const unsigned char scancode2linux[512] = {
-      0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
-     16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
-     32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
-     48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
-     64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
-     80, 81, 82, 83, 99,  0, 86, 87, 88,117,  0,  0, 95,183,184,185,
-      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-     93,  0,  0, 89,  0,  0, 85, 91, 90, 92,  0, 94,  0,124,121,  0,
-
-      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    165,  0,  0,  0,  0,  0,  0,  0,  0,163,  0,  0, 96, 97,  0,  0,
-    113,140,164,  0,166,  0,  0,  0,  0,  0,255,  0,  0,  0,114,  0,
-    115,  0,150,  0,  0, 98,255, 99,100,  0,  0,  0,  0,  0,  0,  0,
-      0,  0,  0,  0,  0,119,119,102,103,104,  0,105,112,106,118,107,
-    108,109,110,111,  0,  0,  0,  0,  0,  0,  0,125,126,127,116,142,
-      0,  0,  0,143,  0,217,156,173,128,159,158,157,155,226,  0,112,
-      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-};
-
-/* Send an event to the keyboard frontend driver */
-static int xenfb_kbd_event(struct XenInput *xenfb,
-                          union xenkbd_in_event *event)
-{
-    struct xenkbd_page *page = xenfb->c.page;
-    uint32_t prod;
-
-    if (xenfb->c.xendev.be_state != XenbusStateConnected)
-       return 0;
-    if (!page)
-        return 0;
-
-    prod = page->in_prod;
-    if (prod - page->in_cons == XENKBD_IN_RING_LEN) {
-       errno = EAGAIN;
-       return -1;
-    }
-
-    xen_mb();          /* ensure ring space available */
-    XENKBD_IN_RING_REF(page, prod) = *event;
-    xen_wmb();         /* ensure ring contents visible */
-    page->in_prod = prod + 1;
-    return xen_be_send_notify(&xenfb->c.xendev);
-}
-
-/* Send a keyboard (or mouse button) event */
-static int xenfb_send_key(struct XenInput *xenfb, bool down, int keycode)
-{
-    union xenkbd_in_event event;
-
-    memset(&event, 0, XENKBD_IN_EVENT_SIZE);
-    event.type = XENKBD_TYPE_KEY;
-    event.key.pressed = down ? 1 : 0;
-    event.key.keycode = keycode;
-
-    return xenfb_kbd_event(xenfb, &event);
-}
-
-/* Send a relative mouse movement event */
-static int xenfb_send_motion(struct XenInput *xenfb,
-                            int rel_x, int rel_y, int rel_z)
-{
-    union xenkbd_in_event event;
-
-    memset(&event, 0, XENKBD_IN_EVENT_SIZE);
-    event.type = XENKBD_TYPE_MOTION;
-    event.motion.rel_x = rel_x;
-    event.motion.rel_y = rel_y;
-#if __XEN_LATEST_INTERFACE_VERSION__ >= 0x00030207
-    event.motion.rel_z = rel_z;
-#endif
-
-    return xenfb_kbd_event(xenfb, &event);
-}
-
-/* Send an absolute mouse movement event */
-static int xenfb_send_position(struct XenInput *xenfb,
-                              int abs_x, int abs_y, int z)
-{
-    union xenkbd_in_event event;
-
-    memset(&event, 0, XENKBD_IN_EVENT_SIZE);
-    event.type = XENKBD_TYPE_POS;
-    event.pos.abs_x = abs_x;
-    event.pos.abs_y = abs_y;
-#if __XEN_LATEST_INTERFACE_VERSION__ == 0x00030207
-    event.pos.abs_z = z;
-#endif
-#if __XEN_LATEST_INTERFACE_VERSION__ >= 0x00030208
-    event.pos.rel_z = z;
-#endif
-
-    return xenfb_kbd_event(xenfb, &event);
-}
-
-/*
- * Send a key event from the client to the guest OS
- * QEMU gives us a raw scancode from an AT / PS/2 style keyboard.
- * We have to turn this into a Linux Input layer keycode.
- *
- * Extra complexity from the fact that with extended scancodes
- * (like those produced by arrow keys) this method gets called
- * twice, but we only want to send a single event. So we have to
- * track the '0xe0' scancode state & collapse the extended keys
- * as needed.
- *
- * Wish we could just send scancodes straight to the guest which
- * already has code for dealing with this...
- */
-static void xenfb_key_event(void *opaque, int scancode)
-{
-    struct XenInput *xenfb = opaque;
-    int down = 1;
-
-    if (scancode == 0xe0) {
-       xenfb->extended = 1;
-       return;
-    } else if (scancode & 0x80) {
-       scancode &= 0x7f;
-       down = 0;
-    }
-    if (xenfb->extended) {
-       scancode |= 0x80;
-       xenfb->extended = 0;
-    }
-    xenfb_send_key(xenfb, down, scancode2linux[scancode]);
-}
-
-/*
- * Send a mouse event from the client to the guest OS
- *
- * The QEMU mouse can be in either relative, or absolute mode.
- * Movement is sent separately from button state, which has to
- * be encoded as virtual key events. We also don't actually get
- * given any button up/down events, so have to track changes in
- * the button state.
- */
-static void xenfb_mouse_event(void *opaque,
-                             int dx, int dy, int dz, int button_state)
-{
-    struct XenInput *xenfb = opaque;
-    DisplaySurface *surface = qemu_console_surface(xenfb->c.con);
-    int dw = surface_width(surface);
-    int dh = surface_height(surface);
-    int i;
-
-    if (xenfb->abs_pointer_wanted)
-       xenfb_send_position(xenfb,
-                           dx * (dw - 1) / 0x7fff,
-                           dy * (dh - 1) / 0x7fff,
-                           dz);
-    else
-       xenfb_send_motion(xenfb, dx, dy, dz);
-
-    for (i = 0 ; i < 8 ; i++) {
-       int lastDown = xenfb->button_state & (1 << i);
-       int down = button_state & (1 << i);
-       if (down == lastDown)
-           continue;
-
-       if (xenfb_send_key(xenfb, down, BTN_LEFT+i) < 0)
-           return;
-    }
-    xenfb->button_state = button_state;
-}
-
-static int input_init(struct XenDevice *xendev)
-{
-    xenstore_write_be_int(xendev, "feature-abs-pointer", 1);
-    return 0;
-}
-
-static int input_initialise(struct XenDevice *xendev)
-{
-    struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
-    int rc;
-
-    if (!in->c.con) {
-        xen_be_printf(xendev, 1, "ds not set (yet)\n");
-        return -1;
-    }
-
-    rc = common_bind(&in->c);
-    if (rc != 0)
-       return rc;
-
-    qemu_add_kbd_event_handler(xenfb_key_event, in);
-    return 0;
-}
-
-static void input_connected(struct XenDevice *xendev)
-{
-    struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
-
-    if (xenstore_read_fe_int(xendev, "request-abs-pointer",
-                             &in->abs_pointer_wanted) == -1) {
-        in->abs_pointer_wanted = 0;
-    }
-
-    if (in->qmouse) {
-        qemu_remove_mouse_event_handler(in->qmouse);
-    }
-    in->qmouse = qemu_add_mouse_event_handler(xenfb_mouse_event, in,
-                                             in->abs_pointer_wanted,
-                                             "Xen PVFB Mouse");
-}
-
-static void input_disconnect(struct XenDevice *xendev)
-{
-    struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
-
-    if (in->qmouse) {
-       qemu_remove_mouse_event_handler(in->qmouse);
-       in->qmouse = NULL;
-    }
-    qemu_add_kbd_event_handler(NULL, NULL);
-    common_unbind(&in->c);
-}
-
-static void input_event(struct XenDevice *xendev)
-{
-    struct XenInput *xenfb = container_of(xendev, struct XenInput, c.xendev);
-    struct xenkbd_page *page = xenfb->c.page;
-
-    /* We don't understand any keyboard events, so just ignore them. */
-    if (page->out_prod == page->out_cons)
-       return;
-    page->out_cons = page->out_prod;
-    xen_be_send_notify(&xenfb->c.xendev);
-}
-
-/* -------------------------------------------------------------------- */
-
-static void xenfb_copy_mfns(int mode, int count, unsigned long *dst, void *src)
-{
-    uint32_t *src32 = src;
-    uint64_t *src64 = src;
-    int i;
-
-    for (i = 0; i < count; i++)
-       dst[i] = (mode == 32) ? src32[i] : src64[i];
-}
-
-static int xenfb_map_fb(struct XenFB *xenfb)
-{
-    struct xenfb_page *page = xenfb->c.page;
-    char *protocol = xenfb->c.xendev.protocol;
-    int n_fbdirs;
-    unsigned long *pgmfns = NULL;
-    unsigned long *fbmfns = NULL;
-    void *map, *pd;
-    int mode, ret = -1;
-
-    /* default to native */
-    pd = page->pd;
-    mode = sizeof(unsigned long) * 8;
-
-    if (!protocol) {
-       /*
-        * Undefined protocol, some guesswork needed.
-        *
-        * Old frontends which don't set the protocol use
-        * one page directory only, thus pd[1] must be zero.
-        * pd[1] of the 32bit struct layout and the lower
-        * 32 bits of pd[0] of the 64bit struct layout have
-        * the same location, so we can check that ...
-        */
-       uint32_t *ptr32 = NULL;
-       uint32_t *ptr64 = NULL;
-#if defined(__i386__)
-       ptr32 = (void*)page->pd;
-       ptr64 = ((void*)page->pd) + 4;
-#elif defined(__x86_64__)
-       ptr32 = ((void*)page->pd) - 4;
-       ptr64 = (void*)page->pd;
-#endif
-       if (ptr32) {
-           if (ptr32[1] == 0) {
-               mode = 32;
-               pd   = ptr32;
-           } else {
-               mode = 64;
-               pd   = ptr64;
-           }
-       }
-#if defined(__x86_64__)
-    } else if (strcmp(protocol, XEN_IO_PROTO_ABI_X86_32) == 0) {
-       /* 64bit dom0, 32bit domU */
-       mode = 32;
-       pd   = ((void*)page->pd) - 4;
-#elif defined(__i386__)
-    } else if (strcmp(protocol, XEN_IO_PROTO_ABI_X86_64) == 0) {
-       /* 32bit dom0, 64bit domU */
-       mode = 64;
-       pd   = ((void*)page->pd) + 4;
-#endif
-    }
-
-    if (xenfb->pixels) {
-        munmap(xenfb->pixels, xenfb->fbpages * XC_PAGE_SIZE);
-        xenfb->pixels = NULL;
-    }
-
-    xenfb->fbpages = (xenfb->fb_len + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
-    n_fbdirs = xenfb->fbpages * mode / 8;
-    n_fbdirs = (n_fbdirs + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
-
-    pgmfns = g_malloc0(sizeof(unsigned long) * n_fbdirs);
-    fbmfns = g_malloc0(sizeof(unsigned long) * xenfb->fbpages);
-
-    xenfb_copy_mfns(mode, n_fbdirs, pgmfns, pd);
-    map = xc_map_foreign_pages(xen_xc, xenfb->c.xendev.dom,
-                              PROT_READ, pgmfns, n_fbdirs);
-    if (map == NULL)
-       goto out;
-    xenfb_copy_mfns(mode, xenfb->fbpages, fbmfns, map);
-    munmap(map, n_fbdirs * XC_PAGE_SIZE);
-
-    xenfb->pixels = xc_map_foreign_pages(xen_xc, xenfb->c.xendev.dom,
-                                        PROT_READ | PROT_WRITE, fbmfns, xenfb->fbpages);
-    if (xenfb->pixels == NULL)
-       goto out;
-
-    ret = 0; /* all is fine */
-
-out:
-    g_free(pgmfns);
-    g_free(fbmfns);
-    return ret;
-}
-
-static int xenfb_configure_fb(struct XenFB *xenfb, size_t fb_len_lim,
-                             int width, int height, int depth,
-                             size_t fb_len, int offset, int row_stride)
-{
-    size_t mfn_sz = sizeof(*((struct xenfb_page *)0)->pd);
-    size_t pd_len = sizeof(((struct xenfb_page *)0)->pd) / mfn_sz;
-    size_t fb_pages = pd_len * XC_PAGE_SIZE / mfn_sz;
-    size_t fb_len_max = fb_pages * XC_PAGE_SIZE;
-    int max_width, max_height;
-
-    if (fb_len_lim > fb_len_max) {
-       xen_be_printf(&xenfb->c.xendev, 0, "fb size limit %zu exceeds %zu, corrected\n",
-                     fb_len_lim, fb_len_max);
-       fb_len_lim = fb_len_max;
-    }
-    if (fb_len_lim && fb_len > fb_len_lim) {
-       xen_be_printf(&xenfb->c.xendev, 0, "frontend fb size %zu limited to %zu\n",
-                     fb_len, fb_len_lim);
-       fb_len = fb_len_lim;
-    }
-    if (depth != 8 && depth != 16 && depth != 24 && depth != 32) {
-       xen_be_printf(&xenfb->c.xendev, 0, "can't handle frontend fb depth %d\n",
-                     depth);
-       return -1;
-    }
-    if (row_stride <= 0 || row_stride > fb_len) {
-       xen_be_printf(&xenfb->c.xendev, 0, "invalid frontend stride %d\n", row_stride);
-       return -1;
-    }
-    max_width = row_stride / (depth / 8);
-    if (width < 0 || width > max_width) {
-       xen_be_printf(&xenfb->c.xendev, 0, "invalid frontend width %d limited to %d\n",
-                     width, max_width);
-       width = max_width;
-    }
-    if (offset < 0 || offset >= fb_len) {
-       xen_be_printf(&xenfb->c.xendev, 0, "invalid frontend offset %d (max %zu)\n",
-                     offset, fb_len - 1);
-       return -1;
-    }
-    max_height = (fb_len - offset) / row_stride;
-    if (height < 0 || height > max_height) {
-       xen_be_printf(&xenfb->c.xendev, 0, "invalid frontend height %d limited to %d\n",
-                     height, max_height);
-       height = max_height;
-    }
-    xenfb->fb_len = fb_len;
-    xenfb->row_stride = row_stride;
-    xenfb->depth = depth;
-    xenfb->width = width;
-    xenfb->height = height;
-    xenfb->offset = offset;
-    xenfb->up_fullscreen = 1;
-    xenfb->do_resize = 1;
-    xen_be_printf(&xenfb->c.xendev, 1, "framebuffer %dx%dx%d offset %d stride %d\n",
-                 width, height, depth, offset, row_stride);
-    return 0;
-}
-
-/* A convenient function for munging pixels between different depths */
-#define BLT(SRC_T,DST_T,RSB,GSB,BSB,RDB,GDB,BDB)                        \
-    for (line = y ; line < (y+h) ; line++) {                           \
-       SRC_T *src = (SRC_T *)(xenfb->pixels                            \
-                              + xenfb->offset                          \
-                              + (line * xenfb->row_stride)             \
-                              + (x * xenfb->depth / 8));               \
-       DST_T *dst = (DST_T *)(data                                     \
-                              + (line * linesize)                      \
-                              + (x * bpp / 8));                        \
-       int col;                                                        \
-       const int RSS = 32 - (RSB + GSB + BSB);                         \
-       const int GSS = 32 - (GSB + BSB);                               \
-       const int BSS = 32 - (BSB);                                     \
-       const uint32_t RSM = (~0U) << (32 - RSB);                       \
-       const uint32_t GSM = (~0U) << (32 - GSB);                       \
-       const uint32_t BSM = (~0U) << (32 - BSB);                       \
-       const int RDS = 32 - (RDB + GDB + BDB);                         \
-       const int GDS = 32 - (GDB + BDB);                               \
-       const int BDS = 32 - (BDB);                                     \
-       const uint32_t RDM = (~0U) << (32 - RDB);                       \
-       const uint32_t GDM = (~0U) << (32 - GDB);                       \
-       const uint32_t BDM = (~0U) << (32 - BDB);                       \
-       for (col = x ; col < (x+w) ; col++) {                           \
-           uint32_t spix = *src;                                       \
-           *dst = (((spix << RSS) & RSM & RDM) >> RDS) |               \
-               (((spix << GSS) & GSM & GDM) >> GDS) |                  \
-               (((spix << BSS) & BSM & BDM) >> BDS);                   \
-           src = (SRC_T *) ((unsigned long) src + xenfb->depth / 8);   \
-           dst = (DST_T *) ((unsigned long) dst + bpp / 8);            \
-       }                                                               \
-    }
-
-
-/*
- * This copies data from the guest framebuffer region, into QEMU's
- * displaysurface. qemu uses 16 or 32 bpp.  In case the pv framebuffer
- * uses something else we must convert and copy, otherwise we can
- * supply the buffer directly and no thing here.
- */
-static void xenfb_guest_copy(struct XenFB *xenfb, int x, int y, int w, int h)
-{
-    DisplaySurface *surface = qemu_console_surface(xenfb->c.con);
-    int line, oops = 0;
-    int bpp = surface_bits_per_pixel(surface);
-    int linesize = surface_stride(surface);
-    uint8_t *data = surface_data(surface);
-
-    if (!is_buffer_shared(surface)) {
-        switch (xenfb->depth) {
-        case 8:
-            if (bpp == 16) {
-                BLT(uint8_t, uint16_t,   3, 3, 2,   5, 6, 5);
-            } else if (bpp == 32) {
-                BLT(uint8_t, uint32_t,   3, 3, 2,   8, 8, 8);
-            } else {
-                oops = 1;
-            }
-            break;
-        case 24:
-            if (bpp == 16) {
-                BLT(uint32_t, uint16_t,  8, 8, 8,   5, 6, 5);
-            } else if (bpp == 32) {
-                BLT(uint32_t, uint32_t,  8, 8, 8,   8, 8, 8);
-            } else {
-                oops = 1;
-            }
-            break;
-        default:
-            oops = 1;
-       }
-    }
-    if (oops) /* should not happen */
-        xen_be_printf(&xenfb->c.xendev, 0, "%s: oops: convert %d -> %d bpp?\n",
-                      __FUNCTION__, xenfb->depth, bpp);
-
-    dpy_gfx_update(xenfb->c.con, x, y, w, h);
-}
-
-#if 0 /* def XENFB_TYPE_REFRESH_PERIOD */
-static int xenfb_queue_full(struct XenFB *xenfb)
-{
-    struct xenfb_page *page = xenfb->c.page;
-    uint32_t cons, prod;
-
-    if (!page)
-        return 1;
-
-    prod = page->in_prod;
-    cons = page->in_cons;
-    return prod - cons == XENFB_IN_RING_LEN;
-}
-
-static void xenfb_send_event(struct XenFB *xenfb, union xenfb_in_event *event)
-{
-    uint32_t prod;
-    struct xenfb_page *page = xenfb->c.page;
-
-    prod = page->in_prod;
-    /* caller ensures !xenfb_queue_full() */
-    xen_mb();                   /* ensure ring space available */
-    XENFB_IN_RING_REF(page, prod) = *event;
-    xen_wmb();                  /* ensure ring contents visible */
-    page->in_prod = prod + 1;
-
-    xen_be_send_notify(&xenfb->c.xendev);
-}
-
-static void xenfb_send_refresh_period(struct XenFB *xenfb, int period)
-{
-    union xenfb_in_event event;
-
-    memset(&event, 0, sizeof(event));
-    event.type = XENFB_TYPE_REFRESH_PERIOD;
-    event.refresh_period.period = period;
-    xenfb_send_event(xenfb, &event);
-}
-#endif
-
-/*
- * Periodic update of display.
- * Also transmit the refresh interval to the frontend.
- *
- * Never ever do any qemu display operations
- * (resize, screen update) outside this function.
- * Our screen might be inactive.  When asked for
- * an update we know it is active.
- */
-static void xenfb_update(void *opaque)
-{
-    struct XenFB *xenfb = opaque;
-    DisplaySurface *surface;
-    int i;
-
-    if (xenfb->c.xendev.be_state != XenbusStateConnected)
-        return;
-
-    if (xenfb->feature_update) {
-#if 0 /* XENFB_TYPE_REFRESH_PERIOD */
-        struct DisplayChangeListener *l;
-        int period = 99999999;
-        int idle = 1;
-
-       if (xenfb_queue_full(xenfb))
-           return;
-
-        QLIST_FOREACH(l, &xenfb->c.ds->listeners, next) {
-            if (l->idle)
-                continue;
-            idle = 0;
-            if (!l->gui_timer_interval) {
-                if (period > GUI_REFRESH_INTERVAL)
-                    period = GUI_REFRESH_INTERVAL;
-            } else {
-                if (period > l->gui_timer_interval)
-                    period = l->gui_timer_interval;
-            }
-        }
-        if (idle)
-           period = XENFB_NO_REFRESH;
-
-       if (xenfb->refresh_period != period) {
-           xenfb_send_refresh_period(xenfb, period);
-           xenfb->refresh_period = period;
-            xen_be_printf(&xenfb->c.xendev, 1, "refresh period: %d\n", period);
-       }
-#else
-       ; /* nothing */
-#endif
-    } else {
-       /* we don't get update notifications, thus use the
-        * sledge hammer approach ... */
-       xenfb->up_fullscreen = 1;
-    }
-
-    /* resize if needed */
-    if (xenfb->do_resize) {
-        xenfb->do_resize = 0;
-        switch (xenfb->depth) {
-        case 16:
-        case 32:
-            /* console.c supported depth -> buffer can be used directly */
-            surface = qemu_create_displaysurface_from
-                (xenfb->width, xenfb->height, xenfb->depth,
-                 xenfb->row_stride, xenfb->pixels + xenfb->offset,
-                 false);
-            break;
-        default:
-            /* we must convert stuff */
-            surface = qemu_create_displaysurface(xenfb->width, xenfb->height);
-            break;
-        }
-        dpy_gfx_replace_surface(xenfb->c.con, surface);
-        xen_be_printf(&xenfb->c.xendev, 1, "update: resizing: %dx%d @ %d bpp%s\n",
-                      xenfb->width, xenfb->height, xenfb->depth,
-                      is_buffer_shared(surface) ? " (shared)" : "");
-        xenfb->up_fullscreen = 1;
-    }
-
-    /* run queued updates */
-    if (xenfb->up_fullscreen) {
-       xen_be_printf(&xenfb->c.xendev, 3, "update: fullscreen\n");
-       xenfb_guest_copy(xenfb, 0, 0, xenfb->width, xenfb->height);
-    } else if (xenfb->up_count) {
-       xen_be_printf(&xenfb->c.xendev, 3, "update: %d rects\n", xenfb->up_count);
-       for (i = 0; i < xenfb->up_count; i++)
-           xenfb_guest_copy(xenfb,
-                            xenfb->up_rects[i].x,
-                            xenfb->up_rects[i].y,
-                            xenfb->up_rects[i].w,
-                            xenfb->up_rects[i].h);
-    } else {
-       xen_be_printf(&xenfb->c.xendev, 3, "update: nothing\n");
-    }
-    xenfb->up_count = 0;
-    xenfb->up_fullscreen = 0;
-}
-
-/* QEMU display state changed, so refresh the framebuffer copy */
-static void xenfb_invalidate(void *opaque)
-{
-    struct XenFB *xenfb = opaque;
-    xenfb->up_fullscreen = 1;
-}
-
-static void xenfb_handle_events(struct XenFB *xenfb)
-{
-    uint32_t prod, cons;
-    struct xenfb_page *page = xenfb->c.page;
-
-    prod = page->out_prod;
-    if (prod == page->out_cons)
-       return;
-    xen_rmb();         /* ensure we see ring contents up to prod */
-    for (cons = page->out_cons; cons != prod; cons++) {
-       union xenfb_out_event *event = &XENFB_OUT_RING_REF(page, cons);
-       int x, y, w, h;
-
-       switch (event->type) {
-       case XENFB_TYPE_UPDATE:
-           if (xenfb->up_count == UP_QUEUE)
-               xenfb->up_fullscreen = 1;
-           if (xenfb->up_fullscreen)
-               break;
-           x = MAX(event->update.x, 0);
-           y = MAX(event->update.y, 0);
-           w = MIN(event->update.width, xenfb->width - x);
-           h = MIN(event->update.height, xenfb->height - y);
-           if (w < 0 || h < 0) {
-                xen_be_printf(&xenfb->c.xendev, 1, "bogus update ignored\n");
-               break;
-           }
-           if (x != event->update.x ||
-                y != event->update.y ||
-               w != event->update.width ||
-               h != event->update.height) {
-                xen_be_printf(&xenfb->c.xendev, 1, "bogus update clipped\n");
-           }
-           if (w == xenfb->width && h > xenfb->height / 2) {
-               /* scroll detector: updated more than 50% of the lines,
-                * don't bother keeping track of the rectangles then */
-               xenfb->up_fullscreen = 1;
-           } else {
-               xenfb->up_rects[xenfb->up_count].x = x;
-               xenfb->up_rects[xenfb->up_count].y = y;
-               xenfb->up_rects[xenfb->up_count].w = w;
-               xenfb->up_rects[xenfb->up_count].h = h;
-               xenfb->up_count++;
-           }
-           break;
-#ifdef XENFB_TYPE_RESIZE
-       case XENFB_TYPE_RESIZE:
-           if (xenfb_configure_fb(xenfb, xenfb->fb_len,
-                                  event->resize.width,
-                                  event->resize.height,
-                                  event->resize.depth,
-                                  xenfb->fb_len,
-                                  event->resize.offset,
-                                  event->resize.stride) < 0)
-               break;
-           xenfb_invalidate(xenfb);
-           break;
-#endif
-       }
-    }
-    xen_mb();          /* ensure we're done with ring contents */
-    page->out_cons = cons;
-}
-
-static int fb_init(struct XenDevice *xendev)
-{
-    struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
-
-    fb->refresh_period = -1;
-
-#ifdef XENFB_TYPE_RESIZE
-    xenstore_write_be_int(xendev, "feature-resize", 1);
-#endif
-    return 0;
-}
-
-static int fb_initialise(struct XenDevice *xendev)
-{
-    struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
-    struct xenfb_page *fb_page;
-    int videoram;
-    int rc;
-
-    if (xenstore_read_fe_int(xendev, "videoram", &videoram) == -1)
-       videoram = 0;
-
-    rc = common_bind(&fb->c);
-    if (rc != 0)
-       return rc;
-
-    fb_page = fb->c.page;
-    rc = xenfb_configure_fb(fb, videoram * 1024 * 1024U,
-                           fb_page->width, fb_page->height, fb_page->depth,
-                           fb_page->mem_length, 0, fb_page->line_length);
-    if (rc != 0)
-       return rc;
-
-    rc = xenfb_map_fb(fb);
-    if (rc != 0)
-       return rc;
-
-#if 0  /* handled in xen_init_display() for now */
-    if (!fb->have_console) {
-        fb->c.ds = graphic_console_init(xenfb_update,
-                                        xenfb_invalidate,
-                                        NULL,
-                                        NULL,
-                                        fb);
-        fb->have_console = 1;
-    }
-#endif
-
-    if (xenstore_read_fe_int(xendev, "feature-update", &fb->feature_update) == -1)
-       fb->feature_update = 0;
-    if (fb->feature_update)
-       xenstore_write_be_int(xendev, "request-update", 1);
-
-    xen_be_printf(xendev, 1, "feature-update=%d, videoram=%d\n",
-                 fb->feature_update, videoram);
-    return 0;
-}
-
-static void fb_disconnect(struct XenDevice *xendev)
-{
-    struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
-
-    /*
-     * FIXME: qemu can't un-init gfx display (yet?).
-     *   Replacing the framebuffer with anonymous shared memory
-     *   instead.  This releases the guest pages and keeps qemu happy.
-     */
-    fb->pixels = mmap(fb->pixels, fb->fbpages * XC_PAGE_SIZE,
-                      PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON,
-                      -1, 0);
-    common_unbind(&fb->c);
-    fb->feature_update = 0;
-    fb->bug_trigger    = 0;
-}
-
-static void fb_frontend_changed(struct XenDevice *xendev, const char *node)
-{
-    struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
-
-    /*
-     * Set state to Connected *again* once the frontend switched
-     * to connected.  We must trigger the watch a second time to
-     * workaround a frontend bug.
-     */
-    if (fb->bug_trigger == 0 && strcmp(node, "state") == 0 &&
-        xendev->fe_state == XenbusStateConnected &&
-        xendev->be_state == XenbusStateConnected) {
-        xen_be_printf(xendev, 2, "re-trigger connected (frontend bug)\n");
-        xen_be_set_state(xendev, XenbusStateConnected);
-        fb->bug_trigger = 1; /* only once */
-    }
-}
-
-static void fb_event(struct XenDevice *xendev)
-{
-    struct XenFB *xenfb = container_of(xendev, struct XenFB, c.xendev);
-
-    xenfb_handle_events(xenfb);
-    xen_be_send_notify(&xenfb->c.xendev);
-}
-
-/* -------------------------------------------------------------------- */
-
-struct XenDevOps xen_kbdmouse_ops = {
-    .size       = sizeof(struct XenInput),
-    .init       = input_init,
-    .initialise = input_initialise,
-    .connected  = input_connected,
-    .disconnect = input_disconnect,
-    .event      = input_event,
-};
-
-struct XenDevOps xen_framebuffer_ops = {
-    .size       = sizeof(struct XenFB),
-    .init       = fb_init,
-    .initialise = fb_initialise,
-    .disconnect = fb_disconnect,
-    .event      = fb_event,
-    .frontend_changed = fb_frontend_changed,
-};
-
-/*
- * FIXME/TODO: Kill this.
- * Temporary needed while DisplayState reorganization is in flight.
- */
-void xen_init_display(int domid)
-{
-    struct XenDevice *xfb, *xin;
-    struct XenFB *fb;
-    struct XenInput *in;
-    int i = 0;
-
-wait_more:
-    i++;
-    main_loop_wait(true);
-    xfb = xen_be_find_xendev("vfb", domid, 0);
-    xin = xen_be_find_xendev("vkbd", domid, 0);
-    if (!xfb || !xin) {
-        if (i < 256) {
-            usleep(10000);
-            goto wait_more;
-        }
-        xen_be_printf(NULL, 1, "displaystate setup failed\n");
-        return;
-    }
-
-    /* vfb */
-    fb = container_of(xfb, struct XenFB, c.xendev);
-    fb->c.con = graphic_console_init(xenfb_update,
-                                     xenfb_invalidate,
-                                     NULL,
-                                     NULL,
-                                     fb);
-    fb->have_console = 1;
-
-    /* vkbd */
-    in = container_of(xin, struct XenInput, c.xendev);
-    in->c.con = fb->c.con;
-
-    /* retry ->init() */
-    xen_be_check_state(xin);
-    xen_be_check_state(xfb);
-}
diff --git a/hw/xgmac.c b/hw/xgmac.c
deleted file mode 100644 (file)
index 5275f48..0000000
+++ /dev/null
@@ -1,433 +0,0 @@
-/*
- * 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 "hw/sysbus.h"
-#include "char/char.h"
-#include "qemu/log.h"
-#include "net/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(qemu_get_queue(s->nic), 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, hwaddr 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, hwaddr 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(NetClientState *nc)
-{
-    struct XgmacState *s = qemu_get_nic_opaque(nc);
-
-    /* RX enabled?  */
-    return s->regs[DMA_CONTROL] & DMA_CONTROL_SR;
-}
-
-static ssize_t eth_rx(NetClientState *nc, const uint8_t *buf, size_t size)
-{
-    struct XgmacState *s = qemu_get_nic_opaque(nc);
-    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(NetClientState *nc)
-{
-    struct XgmacState *s = qemu_get_nic_opaque(nc);
-    s->nic = NULL;
-}
-
-static NetClientInfo net_xgmac_enet_info = {
-    .type = NET_CLIENT_OPTIONS_KIND_NIC,
-    .size = sizeof(NICState),
-    .can_receive = eth_can_rx,
-    .receive = eth_rx,
-    .cleanup = eth_cleanup,
-};
-
-static int xgmac_enet_init(SysBusDevice *dev)
-{
-    struct XgmacState *s = FROM_SYSBUS(typeof(*s), dev);
-
-    memory_region_init_io(&s->iomem, &enet_mem_ops, s, "xgmac", 0x1000);
-    sysbus_init_mmio(dev, &s->iomem);
-    sysbus_init_irq(dev, &s->sbd_irq);
-    sysbus_init_irq(dev, &s->pmt_irq);
-    sysbus_init_irq(dev, &s->mci_irq);
-
-    qemu_macaddr_default_if_unset(&s->conf.macaddr);
-    s->nic = qemu_new_nic(&net_xgmac_enet_info, &s->conf,
-                          object_get_typename(OBJECT(dev)), dev->qdev.id, s);
-    qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
-
-    s->regs[XGMAC_ADDR_HIGH(0)] = (s->conf.macaddr.a[5] << 8) |
-                                   s->conf.macaddr.a[4];
-    s->regs[XGMAC_ADDR_LOW(0)] = (s->conf.macaddr.a[3] << 24) |
-                                 (s->conf.macaddr.a[2] << 16) |
-                                 (s->conf.macaddr.a[1] << 8) |
-                                  s->conf.macaddr.a[0];
-
-    return 0;
-}
-
-static Property xgmac_properties[] = {
-    DEFINE_NIC_PROPERTIES(struct XgmacState, conf),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void xgmac_enet_class_init(ObjectClass *klass, void *data)
-{
-    SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
-    DeviceClass *dc = DEVICE_CLASS(klass);
-
-    sbc->init = xgmac_enet_init;
-    dc->vmsd = &vmstate_xgmac;
-    dc->props = xgmac_properties;
-}
-
-static const 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_types(void)
-{
-    type_register_static(&xgmac_enet_info);
-}
-
-type_init(xgmac_enet_register_types)
diff --git a/hw/xics.h b/hw/xics.h
deleted file mode 100644 (file)
index 6bce042..0000000
--- a/hw/xics.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator
- *
- * PAPR Virtualized Interrupt System, aka ICS/ICP aka xics
- *
- * Copyright (c) 2010,2011 David Gibson, IBM Corporation.
- *
- * 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 !defined(__XICS_H__)
-#define __XICS_H__
-
-#define XICS_IPI        0x2
-#define XICS_IRQ_BASE   0x10
-
-struct icp_state;
-
-qemu_irq xics_get_qirq(struct icp_state *icp, int irq);
-void xics_set_irq_type(struct icp_state *icp, int irq, bool lsi);
-
-struct icp_state *xics_system_init(int nr_servers, int nr_irqs);
-void xics_cpu_setup(struct icp_state *icp, PowerPCCPU *cpu);
-
-#endif /* __XICS_H__ */
diff --git a/hw/xilinx.h b/hw/xilinx.h
deleted file mode 100644 (file)
index 6c1ee21..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-#ifndef HW_XILINX_H
-#define HW_XILINX_H 1
-
-
-#include "qemu-common.h"
-#include "qapi/qmp/qerror.h"
-#include "hw/stream.h"
-#include "net/net.h"
-
-static inline DeviceState *
-xilinx_intc_create(hwaddr base, qemu_irq irq, int kind_of_intr)
-{
-    DeviceState *dev;
-
-    dev = qdev_create(NULL, "xlnx.xps-intc");
-    qdev_prop_set_uint32(dev, "kind-of-intr", kind_of_intr);
-    qdev_init_nofail(dev);
-    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
-    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq);
-    return dev;
-}
-
-/* OPB Timer/Counter.  */
-static inline DeviceState *
-xilinx_timer_create(hwaddr base, qemu_irq irq, int oto, int freq)
-{
-    DeviceState *dev;
-
-    dev = qdev_create(NULL, "xlnx.xps-timer");
-    qdev_prop_set_uint32(dev, "one-timer-only", oto);
-    qdev_prop_set_uint32(dev, "clock-frequency", freq);
-    qdev_init_nofail(dev);
-    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
-    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq);
-    return dev;
-}
-
-/* XPS Ethernet Lite MAC.  */
-static inline DeviceState *
-xilinx_ethlite_create(NICInfo *nd, hwaddr base, qemu_irq irq,
-                      int txpingpong, int rxpingpong)
-{
-    DeviceState *dev;
-
-    qemu_check_nic_model(nd, "xlnx.xps-ethernetlite");
-
-    dev = qdev_create(NULL, "xlnx.xps-ethernetlite");
-    qdev_set_nic_properties(dev, nd);
-    qdev_prop_set_uint32(dev, "tx-ping-pong", txpingpong);
-    qdev_prop_set_uint32(dev, "rx-ping-pong", rxpingpong);
-    qdev_init_nofail(dev);
-    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
-    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq);
-    return dev;
-}
-
-static inline void
-xilinx_axiethernet_init(DeviceState *dev, NICInfo *nd, StreamSlave *peer,
-                        hwaddr base, qemu_irq irq, int txmem, int rxmem)
-{
-    Error *errp = NULL;
-
-    qdev_set_nic_properties(dev, nd);
-    qdev_prop_set_uint32(dev, "rxmem", rxmem);
-    qdev_prop_set_uint32(dev, "txmem", txmem);
-    object_property_set_link(OBJECT(dev), OBJECT(peer), "axistream-connected",
-                             &errp);
-    assert_no_error(errp);
-    qdev_init_nofail(dev);
-    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
-    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq);
-}
-
-static inline void
-xilinx_axidma_init(DeviceState *dev, StreamSlave *peer, hwaddr base,
-                   qemu_irq irq, qemu_irq irq2, int freqhz)
-{
-    Error *errp = NULL;
-
-    qdev_prop_set_uint32(dev, "freqhz", freqhz);
-    object_property_set_link(OBJECT(dev), OBJECT(peer), "axistream-connected",
-                             &errp);
-    assert_no_error(errp);
-    qdev_init_nofail(dev);
-
-    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
-    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq);
-    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, irq2);
-}
-
-#endif
diff --git a/hw/xilinx_axidma.c b/hw/xilinx_axidma.c
deleted file mode 100644 (file)
index 8db1a74..0000000
+++ /dev/null
@@ -1,523 +0,0 @@
-/*
- * QEMU model of Xilinx AXI-DMA block.
- *
- * Copyright (c) 2011 Edgar E. Iglesias.
- *
- * 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 "hw/sysbus.h"
-#include "qemu/timer.h"
-#include "hw/ptimer.h"
-#include "qemu/log.h"
-#include "hw/qdev-addr.h"
-
-#include "hw/stream.h"
-
-#define D(x)
-
-#define R_DMACR             (0x00 / 4)
-#define R_DMASR             (0x04 / 4)
-#define R_CURDESC           (0x08 / 4)
-#define R_TAILDESC          (0x10 / 4)
-#define R_MAX               (0x30 / 4)
-
-enum {
-    DMACR_RUNSTOP = 1,
-    DMACR_TAILPTR_MODE = 2,
-    DMACR_RESET = 4
-};
-
-enum {
-    DMASR_HALTED = 1,
-    DMASR_IDLE  = 2,
-    DMASR_IOC_IRQ  = 1 << 12,
-    DMASR_DLY_IRQ  = 1 << 13,
-
-    DMASR_IRQ_MASK = 7 << 12
-};
-
-struct SDesc {
-    uint64_t nxtdesc;
-    uint64_t buffer_address;
-    uint64_t reserved;
-    uint32_t control;
-    uint32_t status;
-    uint32_t app[6];
-};
-
-enum {
-    SDESC_CTRL_EOF = (1 << 26),
-    SDESC_CTRL_SOF = (1 << 27),
-
-    SDESC_CTRL_LEN_MASK = (1 << 23) - 1
-};
-
-enum {
-    SDESC_STATUS_EOF = (1 << 26),
-    SDESC_STATUS_SOF_BIT = 27,
-    SDESC_STATUS_SOF = (1 << SDESC_STATUS_SOF_BIT),
-    SDESC_STATUS_COMPLETE = (1 << 31)
-};
-
-struct Stream {
-    QEMUBH *bh;
-    ptimer_state *ptimer;
-    qemu_irq irq;
-
-    int nr;
-
-    struct SDesc desc;
-    int pos;
-    unsigned int complete_cnt;
-    uint32_t regs[R_MAX];
-};
-
-struct XilinxAXIDMA {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-    uint32_t freqhz;
-    StreamSlave *tx_dev;
-
-    struct Stream streams[2];
-};
-
-/*
- * Helper calls to extract info from desriptors and other trivial
- * state from regs.
- */
-static inline int stream_desc_sof(struct SDesc *d)
-{
-    return d->control & SDESC_CTRL_SOF;
-}
-
-static inline int stream_desc_eof(struct SDesc *d)
-{
-    return d->control & SDESC_CTRL_EOF;
-}
-
-static inline int stream_resetting(struct Stream *s)
-{
-    return !!(s->regs[R_DMACR] & DMACR_RESET);
-}
-
-static inline int stream_running(struct Stream *s)
-{
-    return s->regs[R_DMACR] & DMACR_RUNSTOP;
-}
-
-static inline int stream_halted(struct Stream *s)
-{
-    return s->regs[R_DMASR] & DMASR_HALTED;
-}
-
-static inline int stream_idle(struct Stream *s)
-{
-    return !!(s->regs[R_DMASR] & DMASR_IDLE);
-}
-
-static void stream_reset(struct Stream *s)
-{
-    s->regs[R_DMASR] = DMASR_HALTED;  /* starts up halted.  */
-    s->regs[R_DMACR] = 1 << 16; /* Starts with one in compl threshold.  */
-}
-
-/* Map an offset addr into a channel index.  */
-static inline int streamid_from_addr(hwaddr addr)
-{
-    int sid;
-
-    sid = addr / (0x30);
-    sid &= 1;
-    return sid;
-}
-
-#ifdef DEBUG_ENET
-static void stream_desc_show(struct SDesc *d)
-{
-    qemu_log("buffer_addr  = " PRIx64 "\n", d->buffer_address);
-    qemu_log("nxtdesc      = " PRIx64 "\n", d->nxtdesc);
-    qemu_log("control      = %x\n", d->control);
-    qemu_log("status       = %x\n", d->status);
-}
-#endif
-
-static void stream_desc_load(struct Stream *s, hwaddr addr)
-{
-    struct SDesc *d = &s->desc;
-    int i;
-
-    cpu_physical_memory_read(addr, (void *) d, sizeof *d);
-
-    /* Convert from LE into host endianness.  */
-    d->buffer_address = le64_to_cpu(d->buffer_address);
-    d->nxtdesc = le64_to_cpu(d->nxtdesc);
-    d->control = le32_to_cpu(d->control);
-    d->status = le32_to_cpu(d->status);
-    for (i = 0; i < ARRAY_SIZE(d->app); i++) {
-        d->app[i] = le32_to_cpu(d->app[i]);
-    }
-}
-
-static void stream_desc_store(struct Stream *s, hwaddr addr)
-{
-    struct SDesc *d = &s->desc;
-    int i;
-
-    /* Convert from host endianness into LE.  */
-    d->buffer_address = cpu_to_le64(d->buffer_address);
-    d->nxtdesc = cpu_to_le64(d->nxtdesc);
-    d->control = cpu_to_le32(d->control);
-    d->status = cpu_to_le32(d->status);
-    for (i = 0; i < ARRAY_SIZE(d->app); i++) {
-        d->app[i] = cpu_to_le32(d->app[i]);
-    }
-    cpu_physical_memory_write(addr, (void *) d, sizeof *d);
-}
-
-static void stream_update_irq(struct Stream *s)
-{
-    unsigned int pending, mask, irq;
-
-    pending = s->regs[R_DMASR] & DMASR_IRQ_MASK;
-    mask = s->regs[R_DMACR] & DMASR_IRQ_MASK;
-
-    irq = pending & mask;
-
-    qemu_set_irq(s->irq, !!irq);
-}
-
-static void stream_reload_complete_cnt(struct Stream *s)
-{
-    unsigned int comp_th;
-    comp_th = (s->regs[R_DMACR] >> 16) & 0xff;
-    s->complete_cnt = comp_th;
-}
-
-static void timer_hit(void *opaque)
-{
-    struct Stream *s = opaque;
-
-    stream_reload_complete_cnt(s);
-    s->regs[R_DMASR] |= DMASR_DLY_IRQ;
-    stream_update_irq(s);
-}
-
-static void stream_complete(struct Stream *s)
-{
-    unsigned int comp_delay;
-
-    /* Start the delayed timer.  */
-    comp_delay = s->regs[R_DMACR] >> 24;
-    if (comp_delay) {
-        ptimer_stop(s->ptimer);
-        ptimer_set_count(s->ptimer, comp_delay);
-        ptimer_run(s->ptimer, 1);
-    }
-
-    s->complete_cnt--;
-    if (s->complete_cnt == 0) {
-        /* Raise the IOC irq.  */
-        s->regs[R_DMASR] |= DMASR_IOC_IRQ;
-        stream_reload_complete_cnt(s);
-    }
-}
-
-static void stream_process_mem2s(struct Stream *s,
-                                 StreamSlave *tx_dev)
-{
-    uint32_t prev_d;
-    unsigned char txbuf[16 * 1024];
-    unsigned int txlen;
-    uint32_t app[6];
-
-    if (!stream_running(s) || stream_idle(s)) {
-        return;
-    }
-
-    while (1) {
-        stream_desc_load(s, s->regs[R_CURDESC]);
-
-        if (s->desc.status & SDESC_STATUS_COMPLETE) {
-            s->regs[R_DMASR] |= DMASR_IDLE;
-            break;
-        }
-
-        if (stream_desc_sof(&s->desc)) {
-            s->pos = 0;
-            memcpy(app, s->desc.app, sizeof app);
-        }
-
-        txlen = s->desc.control & SDESC_CTRL_LEN_MASK;
-        if ((txlen + s->pos) > sizeof txbuf) {
-            hw_error("%s: too small internal txbuf! %d\n", __func__,
-                     txlen + s->pos);
-        }
-
-        cpu_physical_memory_read(s->desc.buffer_address,
-                                 txbuf + s->pos, txlen);
-        s->pos += txlen;
-
-        if (stream_desc_eof(&s->desc)) {
-            stream_push(tx_dev, txbuf, s->pos, app);
-            s->pos = 0;
-            stream_complete(s);
-        }
-
-        /* Update the descriptor.  */
-        s->desc.status = txlen | SDESC_STATUS_COMPLETE;
-        stream_desc_store(s, s->regs[R_CURDESC]);
-
-        /* Advance.  */
-        prev_d = s->regs[R_CURDESC];
-        s->regs[R_CURDESC] = s->desc.nxtdesc;
-        if (prev_d == s->regs[R_TAILDESC]) {
-            s->regs[R_DMASR] |= DMASR_IDLE;
-            break;
-        }
-    }
-}
-
-static void stream_process_s2mem(struct Stream *s,
-                                 unsigned char *buf, size_t len, uint32_t *app)
-{
-    uint32_t prev_d;
-    unsigned int rxlen;
-    int pos = 0;
-    int sof = 1;
-
-    if (!stream_running(s) || stream_idle(s)) {
-        return;
-    }
-
-    while (len) {
-        stream_desc_load(s, s->regs[R_CURDESC]);
-
-        if (s->desc.status & SDESC_STATUS_COMPLETE) {
-            s->regs[R_DMASR] |= DMASR_IDLE;
-            break;
-        }
-
-        rxlen = s->desc.control & SDESC_CTRL_LEN_MASK;
-        if (rxlen > len) {
-            /* It fits.  */
-            rxlen = len;
-        }
-
-        cpu_physical_memory_write(s->desc.buffer_address, buf + pos, rxlen);
-        len -= rxlen;
-        pos += rxlen;
-
-        /* Update the descriptor.  */
-        if (!len) {
-            int i;
-
-            stream_complete(s);
-            for (i = 0; i < 5; i++) {
-                s->desc.app[i] = app[i];
-            }
-            s->desc.status |= SDESC_STATUS_EOF;
-        }
-
-        s->desc.status |= sof << SDESC_STATUS_SOF_BIT;
-        s->desc.status |= SDESC_STATUS_COMPLETE;
-        stream_desc_store(s, s->regs[R_CURDESC]);
-        sof = 0;
-
-        /* Advance.  */
-        prev_d = s->regs[R_CURDESC];
-        s->regs[R_CURDESC] = s->desc.nxtdesc;
-        if (prev_d == s->regs[R_TAILDESC]) {
-            s->regs[R_DMASR] |= DMASR_IDLE;
-            break;
-        }
-    }
-}
-
-static void
-axidma_push(StreamSlave *obj, unsigned char *buf, size_t len, uint32_t *app)
-{
-    struct XilinxAXIDMA *d = FROM_SYSBUS(typeof(*d), SYS_BUS_DEVICE(obj));
-    struct Stream *s = &d->streams[1];
-
-    if (!app) {
-        hw_error("No stream app data!\n");
-    }
-    stream_process_s2mem(s, buf, len, app);
-    stream_update_irq(s);
-}
-
-static uint64_t axidma_read(void *opaque, hwaddr addr,
-                            unsigned size)
-{
-    struct XilinxAXIDMA *d = opaque;
-    struct Stream *s;
-    uint32_t r = 0;
-    int sid;
-
-    sid = streamid_from_addr(addr);
-    s = &d->streams[sid];
-
-    addr = addr % 0x30;
-    addr >>= 2;
-    switch (addr) {
-        case R_DMACR:
-            /* Simulate one cycles reset delay.  */
-            s->regs[addr] &= ~DMACR_RESET;
-            r = s->regs[addr];
-            break;
-        case R_DMASR:
-            s->regs[addr] &= 0xffff;
-            s->regs[addr] |= (s->complete_cnt & 0xff) << 16;
-            s->regs[addr] |= (ptimer_get_count(s->ptimer) & 0xff) << 24;
-            r = s->regs[addr];
-            break;
-        default:
-            r = s->regs[addr];
-            D(qemu_log("%s ch=%d addr=" TARGET_FMT_plx " v=%x\n",
-                           __func__, sid, addr * 4, r));
-            break;
-    }
-    return r;
-
-}
-
-static void axidma_write(void *opaque, hwaddr addr,
-                         uint64_t value, unsigned size)
-{
-    struct XilinxAXIDMA *d = opaque;
-    struct Stream *s;
-    int sid;
-
-    sid = streamid_from_addr(addr);
-    s = &d->streams[sid];
-
-    addr = addr % 0x30;
-    addr >>= 2;
-    switch (addr) {
-        case R_DMACR:
-            /* Tailptr mode is always on.  */
-            value |= DMACR_TAILPTR_MODE;
-            /* Remember our previous reset state.  */
-            value |= (s->regs[addr] & DMACR_RESET);
-            s->regs[addr] = value;
-
-            if (value & DMACR_RESET) {
-                stream_reset(s);
-            }
-
-            if ((value & 1) && !stream_resetting(s)) {
-                /* Start processing.  */
-                s->regs[R_DMASR] &= ~(DMASR_HALTED | DMASR_IDLE);
-            }
-            stream_reload_complete_cnt(s);
-            break;
-
-        case R_DMASR:
-            /* Mask away write to clear irq lines.  */
-            value &= ~(value & DMASR_IRQ_MASK);
-            s->regs[addr] = value;
-            break;
-
-        case R_TAILDESC:
-            s->regs[addr] = value;
-            s->regs[R_DMASR] &= ~DMASR_IDLE; /* Not idle.  */
-            if (!sid) {
-                stream_process_mem2s(s, d->tx_dev);
-            }
-            break;
-        default:
-            D(qemu_log("%s: ch=%d addr=" TARGET_FMT_plx " v=%x\n",
-                  __func__, sid, addr * 4, (unsigned)value));
-            s->regs[addr] = value;
-            break;
-    }
-    stream_update_irq(s);
-}
-
-static const MemoryRegionOps axidma_ops = {
-    .read = axidma_read,
-    .write = axidma_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int xilinx_axidma_init(SysBusDevice *dev)
-{
-    struct XilinxAXIDMA *s = FROM_SYSBUS(typeof(*s), dev);
-    int i;
-
-    sysbus_init_irq(dev, &s->streams[0].irq);
-    sysbus_init_irq(dev, &s->streams[1].irq);
-
-    memory_region_init_io(&s->iomem, &axidma_ops, s,
-                          "xlnx.axi-dma", R_MAX * 4 * 2);
-    sysbus_init_mmio(dev, &s->iomem);
-
-    for (i = 0; i < 2; i++) {
-        stream_reset(&s->streams[i]);
-        s->streams[i].nr = i;
-        s->streams[i].bh = qemu_bh_new(timer_hit, &s->streams[i]);
-        s->streams[i].ptimer = ptimer_init(s->streams[i].bh);
-        ptimer_set_freq(s->streams[i].ptimer, s->freqhz);
-    }
-    return 0;
-}
-
-static void xilinx_axidma_initfn(Object *obj)
-{
-    struct XilinxAXIDMA *s = FROM_SYSBUS(typeof(*s), SYS_BUS_DEVICE(obj));
-
-    object_property_add_link(obj, "axistream-connected", TYPE_STREAM_SLAVE,
-                             (Object **) &s->tx_dev, NULL);
-}
-
-static Property axidma_properties[] = {
-    DEFINE_PROP_UINT32("freqhz", struct XilinxAXIDMA, freqhz, 50000000),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void axidma_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-    StreamSlaveClass *ssc = STREAM_SLAVE_CLASS(klass);
-
-    k->init = xilinx_axidma_init;
-    dc->props = axidma_properties;
-    ssc->push = axidma_push;
-}
-
-static const TypeInfo axidma_info = {
-    .name          = "xlnx.axi-dma",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(struct XilinxAXIDMA),
-    .class_init    = axidma_class_init,
-    .instance_init = xilinx_axidma_initfn,
-    .interfaces = (InterfaceInfo[]) {
-        { TYPE_STREAM_SLAVE },
-        { }
-    }
-};
-
-static void xilinx_axidma_register_types(void)
-{
-    type_register_static(&axidma_info);
-}
-
-type_init(xilinx_axidma_register_types)
diff --git a/hw/xilinx_axienet.c b/hw/xilinx_axienet.c
deleted file mode 100644 (file)
index 07c4bad..0000000
+++ /dev/null
@@ -1,918 +0,0 @@
-/*
- * QEMU model of Xilinx AXI-Ethernet.
- *
- * Copyright (c) 2011 Edgar E. Iglesias.
- *
- * 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 "hw/sysbus.h"
-#include "qemu/log.h"
-#include "net/net.h"
-#include "net/checksum.h"
-#include "qapi/qmp/qerror.h"
-
-#include "hw/stream.h"
-
-#define DPHY(x)
-
-/* Advertisement control register. */
-#define ADVERTISE_10HALF        0x0020  /* Try for 10mbps half-duplex  */
-#define ADVERTISE_10FULL        0x0040  /* Try for 10mbps full-duplex  */
-#define ADVERTISE_100HALF       0x0080  /* Try for 100mbps half-duplex */
-#define ADVERTISE_100FULL       0x0100  /* Try for 100mbps full-duplex */
-
-struct PHY {
-    uint32_t regs[32];
-
-    int link;
-
-    unsigned int (*read)(struct PHY *phy, unsigned int req);
-    void (*write)(struct PHY *phy, unsigned int req,
-                  unsigned int data);
-};
-
-static unsigned int tdk_read(struct PHY *phy, unsigned int req)
-{
-    int regnum;
-    unsigned r = 0;
-
-    regnum = req & 0x1f;
-
-    switch (regnum) {
-        case 1:
-            if (!phy->link) {
-                break;
-            }
-            /* MR1.  */
-            /* Speeds and modes.  */
-            r |= (1 << 13) | (1 << 14);
-            r |= (1 << 11) | (1 << 12);
-            r |= (1 << 5); /* Autoneg complete.  */
-            r |= (1 << 3); /* Autoneg able.  */
-            r |= (1 << 2); /* link.  */
-            r |= (1 << 1); /* link.  */
-            break;
-        case 5:
-            /* Link partner ability.
-               We are kind; always agree with whatever best mode
-               the guest advertises.  */
-            r = 1 << 14; /* Success.  */
-            /* Copy advertised modes.  */
-            r |= phy->regs[4] & (15 << 5);
-            /* Autoneg support.  */
-            r |= 1;
-            break;
-        case 17:
-            /* Marvel PHY on many xilinx boards.  */
-            r = 0x8000; /* 1000Mb  */
-            break;
-        case 18:
-            {
-                /* Diagnostics reg.  */
-                int duplex = 0;
-                int speed_100 = 0;
-
-                if (!phy->link) {
-                    break;
-                }
-
-                /* Are we advertising 100 half or 100 duplex ? */
-                speed_100 = !!(phy->regs[4] & ADVERTISE_100HALF);
-                speed_100 |= !!(phy->regs[4] & ADVERTISE_100FULL);
-
-                /* Are we advertising 10 duplex or 100 duplex ? */
-                duplex = !!(phy->regs[4] & ADVERTISE_100FULL);
-                duplex |= !!(phy->regs[4] & ADVERTISE_10FULL);
-                r = (speed_100 << 10) | (duplex << 11);
-            }
-            break;
-
-        default:
-            r = phy->regs[regnum];
-            break;
-    }
-    DPHY(qemu_log("\n%s %x = reg[%d]\n", __func__, r, regnum));
-    return r;
-}
-
-static void
-tdk_write(struct PHY *phy, unsigned int req, unsigned int data)
-{
-    int regnum;
-
-    regnum = req & 0x1f;
-    DPHY(qemu_log("%s reg[%d] = %x\n", __func__, regnum, data));
-    switch (regnum) {
-        default:
-            phy->regs[regnum] = data;
-            break;
-    }
-}
-
-static void
-tdk_init(struct PHY *phy)
-{
-    phy->regs[0] = 0x3100;
-    /* PHY Id.  */
-    phy->regs[2] = 0x0300;
-    phy->regs[3] = 0xe400;
-    /* Autonegotiation advertisement reg.  */
-    phy->regs[4] = 0x01E1;
-    phy->link = 1;
-
-    phy->read = tdk_read;
-    phy->write = tdk_write;
-}
-
-struct MDIOBus {
-    /* bus.  */
-    int mdc;
-    int mdio;
-
-    /* decoder.  */
-    enum {
-        PREAMBLE,
-        SOF,
-        OPC,
-        ADDR,
-        REQ,
-        TURNAROUND,
-        DATA
-    } state;
-    unsigned int drive;
-
-    unsigned int cnt;
-    unsigned int addr;
-    unsigned int opc;
-    unsigned int req;
-    unsigned int data;
-
-    struct PHY *devs[32];
-};
-
-static void
-mdio_attach(struct MDIOBus *bus, struct PHY *phy, unsigned int addr)
-{
-    bus->devs[addr & 0x1f] = phy;
-}
-
-#ifdef USE_THIS_DEAD_CODE
-static void
-mdio_detach(struct MDIOBus *bus, struct PHY *phy, unsigned int addr)
-{
-    bus->devs[addr & 0x1f] = NULL;
-}
-#endif
-
-static uint16_t mdio_read_req(struct MDIOBus *bus, unsigned int addr,
-                  unsigned int reg)
-{
-    struct PHY *phy;
-    uint16_t data;
-
-    phy = bus->devs[addr];
-    if (phy && phy->read) {
-        data = phy->read(phy, reg);
-    } else {
-        data = 0xffff;
-    }
-    DPHY(qemu_log("%s addr=%d reg=%d data=%x\n", __func__, addr, reg, data));
-    return data;
-}
-
-static void mdio_write_req(struct MDIOBus *bus, unsigned int addr,
-               unsigned int reg, uint16_t data)
-{
-    struct PHY *phy;
-
-    DPHY(qemu_log("%s addr=%d reg=%d data=%x\n", __func__, addr, reg, data));
-    phy = bus->devs[addr];
-    if (phy && phy->write) {
-        phy->write(phy, reg, data);
-    }
-}
-
-#define DENET(x)
-
-#define R_RAF      (0x000 / 4)
-enum {
-    RAF_MCAST_REJ = (1 << 1),
-    RAF_BCAST_REJ = (1 << 2),
-    RAF_EMCF_EN = (1 << 12),
-    RAF_NEWFUNC_EN = (1 << 11)
-};
-
-#define R_IS       (0x00C / 4)
-enum {
-    IS_HARD_ACCESS_COMPLETE = 1,
-    IS_AUTONEG = (1 << 1),
-    IS_RX_COMPLETE = (1 << 2),
-    IS_RX_REJECT = (1 << 3),
-    IS_TX_COMPLETE = (1 << 5),
-    IS_RX_DCM_LOCK = (1 << 6),
-    IS_MGM_RDY = (1 << 7),
-    IS_PHY_RST_DONE = (1 << 8),
-};
-
-#define R_IP       (0x010 / 4)
-#define R_IE       (0x014 / 4)
-#define R_UAWL     (0x020 / 4)
-#define R_UAWU     (0x024 / 4)
-#define R_PPST     (0x030 / 4)
-enum {
-    PPST_LINKSTATUS = (1 << 0),
-    PPST_PHY_LINKSTATUS = (1 << 7),
-};
-
-#define R_STATS_RX_BYTESL (0x200 / 4)
-#define R_STATS_RX_BYTESH (0x204 / 4)
-#define R_STATS_TX_BYTESL (0x208 / 4)
-#define R_STATS_TX_BYTESH (0x20C / 4)
-#define R_STATS_RXL       (0x290 / 4)
-#define R_STATS_RXH       (0x294 / 4)
-#define R_STATS_RX_BCASTL (0x2a0 / 4)
-#define R_STATS_RX_BCASTH (0x2a4 / 4)
-#define R_STATS_RX_MCASTL (0x2a8 / 4)
-#define R_STATS_RX_MCASTH (0x2ac / 4)
-
-#define R_RCW0     (0x400 / 4)
-#define R_RCW1     (0x404 / 4)
-enum {
-    RCW1_VLAN = (1 << 27),
-    RCW1_RX   = (1 << 28),
-    RCW1_FCS  = (1 << 29),
-    RCW1_JUM  = (1 << 30),
-    RCW1_RST  = (1 << 31),
-};
-
-#define R_TC       (0x408 / 4)
-enum {
-    TC_VLAN = (1 << 27),
-    TC_TX   = (1 << 28),
-    TC_FCS  = (1 << 29),
-    TC_JUM  = (1 << 30),
-    TC_RST  = (1 << 31),
-};
-
-#define R_EMMC     (0x410 / 4)
-enum {
-    EMMC_LINKSPEED_10MB = (0 << 30),
-    EMMC_LINKSPEED_100MB = (1 << 30),
-    EMMC_LINKSPEED_1000MB = (2 << 30),
-};
-
-#define R_PHYC     (0x414 / 4)
-
-#define R_MC       (0x500 / 4)
-#define MC_EN      (1 << 6)
-
-#define R_MCR      (0x504 / 4)
-#define R_MWD      (0x508 / 4)
-#define R_MRD      (0x50c / 4)
-#define R_MIS      (0x600 / 4)
-#define R_MIP      (0x620 / 4)
-#define R_MIE      (0x640 / 4)
-#define R_MIC      (0x640 / 4)
-
-#define R_UAW0     (0x700 / 4)
-#define R_UAW1     (0x704 / 4)
-#define R_FMI      (0x708 / 4)
-#define R_AF0      (0x710 / 4)
-#define R_AF1      (0x714 / 4)
-#define R_MAX      (0x34 / 4)
-
-/* Indirect registers.  */
-struct TEMAC  {
-    struct MDIOBus mdio_bus;
-    struct PHY phy;
-
-    void *parent;
-};
-
-struct XilinxAXIEnet {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-    qemu_irq irq;
-    StreamSlave *tx_dev;
-    NICState *nic;
-    NICConf conf;
-
-
-    uint32_t c_rxmem;
-    uint32_t c_txmem;
-    uint32_t c_phyaddr;
-
-    struct TEMAC TEMAC;
-
-    /* MII regs.  */
-    union {
-        uint32_t regs[4];
-        struct {
-            uint32_t mc;
-            uint32_t mcr;
-            uint32_t mwd;
-            uint32_t mrd;
-        };
-    } mii;
-
-    struct {
-        uint64_t rx_bytes;
-        uint64_t tx_bytes;
-
-        uint64_t rx;
-        uint64_t rx_bcast;
-        uint64_t rx_mcast;
-    } stats;
-
-    /* Receive configuration words.  */
-    uint32_t rcw[2];
-    /* Transmit config.  */
-    uint32_t tc;
-    uint32_t emmc;
-    uint32_t phyc;
-
-    /* Unicast Address Word.  */
-    uint32_t uaw[2];
-    /* Unicast address filter used with extended mcast.  */
-    uint32_t ext_uaw[2];
-    uint32_t fmi;
-
-    uint32_t regs[R_MAX];
-
-    /* Multicast filter addrs.  */
-    uint32_t maddr[4][2];
-    /* 32K x 1 lookup filter.  */
-    uint32_t ext_mtable[1024];
-
-
-    uint8_t *rxmem;
-};
-
-static void axienet_rx_reset(struct XilinxAXIEnet *s)
-{
-    s->rcw[1] = RCW1_JUM | RCW1_FCS | RCW1_RX | RCW1_VLAN;
-}
-
-static void axienet_tx_reset(struct XilinxAXIEnet *s)
-{
-    s->tc = TC_JUM | TC_TX | TC_VLAN;
-}
-
-static inline int axienet_rx_resetting(struct XilinxAXIEnet *s)
-{
-    return s->rcw[1] & RCW1_RST;
-}
-
-static inline int axienet_rx_enabled(struct XilinxAXIEnet *s)
-{
-    return s->rcw[1] & RCW1_RX;
-}
-
-static inline int axienet_extmcf_enabled(struct XilinxAXIEnet *s)
-{
-    return !!(s->regs[R_RAF] & RAF_EMCF_EN);
-}
-
-static inline int axienet_newfunc_enabled(struct XilinxAXIEnet *s)
-{
-    return !!(s->regs[R_RAF] & RAF_NEWFUNC_EN);
-}
-
-static void axienet_reset(struct XilinxAXIEnet *s)
-{
-    axienet_rx_reset(s);
-    axienet_tx_reset(s);
-
-    s->regs[R_PPST] = PPST_LINKSTATUS | PPST_PHY_LINKSTATUS;
-    s->regs[R_IS] = IS_AUTONEG | IS_RX_DCM_LOCK | IS_MGM_RDY | IS_PHY_RST_DONE;
-
-    s->emmc = EMMC_LINKSPEED_100MB;
-}
-
-static void enet_update_irq(struct XilinxAXIEnet *s)
-{
-    s->regs[R_IP] = s->regs[R_IS] & s->regs[R_IE];
-    qemu_set_irq(s->irq, !!s->regs[R_IP]);
-}
-
-static uint64_t enet_read(void *opaque, hwaddr addr, unsigned size)
-{
-    struct XilinxAXIEnet *s = opaque;
-    uint32_t r = 0;
-    addr >>= 2;
-
-    switch (addr) {
-        case R_RCW0:
-        case R_RCW1:
-            r = s->rcw[addr & 1];
-            break;
-
-        case R_TC:
-            r = s->tc;
-            break;
-
-        case R_EMMC:
-            r = s->emmc;
-            break;
-
-        case R_PHYC:
-            r = s->phyc;
-            break;
-
-        case R_MCR:
-            r = s->mii.regs[addr & 3] | (1 << 7); /* Always ready.  */
-            break;
-
-        case R_STATS_RX_BYTESL:
-        case R_STATS_RX_BYTESH:
-            r = s->stats.rx_bytes >> (32 * (addr & 1));
-            break;
-
-        case R_STATS_TX_BYTESL:
-        case R_STATS_TX_BYTESH:
-            r = s->stats.tx_bytes >> (32 * (addr & 1));
-            break;
-
-        case R_STATS_RXL:
-        case R_STATS_RXH:
-            r = s->stats.rx >> (32 * (addr & 1));
-            break;
-        case R_STATS_RX_BCASTL:
-        case R_STATS_RX_BCASTH:
-            r = s->stats.rx_bcast >> (32 * (addr & 1));
-            break;
-        case R_STATS_RX_MCASTL:
-        case R_STATS_RX_MCASTH:
-            r = s->stats.rx_mcast >> (32 * (addr & 1));
-            break;
-
-        case R_MC:
-        case R_MWD:
-        case R_MRD:
-            r = s->mii.regs[addr & 3];
-            break;
-
-        case R_UAW0:
-        case R_UAW1:
-            r = s->uaw[addr & 1];
-            break;
-
-        case R_UAWU:
-        case R_UAWL:
-            r = s->ext_uaw[addr & 1];
-            break;
-
-        case R_FMI:
-            r = s->fmi;
-            break;
-
-        case R_AF0:
-        case R_AF1:
-            r = s->maddr[s->fmi & 3][addr & 1];
-            break;
-
-        case 0x8000 ... 0x83ff:
-            r = s->ext_mtable[addr - 0x8000];
-            break;
-
-        default:
-            if (addr < ARRAY_SIZE(s->regs)) {
-                r = s->regs[addr];
-            }
-            DENET(qemu_log("%s addr=" TARGET_FMT_plx " v=%x\n",
-                            __func__, addr * 4, r));
-            break;
-    }
-    return r;
-}
-
-static void enet_write(void *opaque, hwaddr addr,
-                       uint64_t value, unsigned size)
-{
-    struct XilinxAXIEnet *s = opaque;
-    struct TEMAC *t = &s->TEMAC;
-
-    addr >>= 2;
-    switch (addr) {
-        case R_RCW0:
-        case R_RCW1:
-            s->rcw[addr & 1] = value;
-            if ((addr & 1) && value & RCW1_RST) {
-                axienet_rx_reset(s);
-            } else {
-                qemu_flush_queued_packets(qemu_get_queue(s->nic));
-            }
-            break;
-
-        case R_TC:
-            s->tc = value;
-            if (value & TC_RST) {
-                axienet_tx_reset(s);
-            }
-            break;
-
-        case R_EMMC:
-            s->emmc = value;
-            break;
-
-        case R_PHYC:
-            s->phyc = value;
-            break;
-
-        case R_MC:
-             value &= ((1 < 7) - 1);
-
-             /* Enable the MII.  */
-             if (value & MC_EN) {
-                 unsigned int miiclkdiv = value & ((1 << 6) - 1);
-                 if (!miiclkdiv) {
-                     qemu_log("AXIENET: MDIO enabled but MDIOCLK is zero!\n");
-                 }
-             }
-             s->mii.mc = value;
-             break;
-
-        case R_MCR: {
-             unsigned int phyaddr = (value >> 24) & 0x1f;
-             unsigned int regaddr = (value >> 16) & 0x1f;
-             unsigned int op = (value >> 14) & 3;
-             unsigned int initiate = (value >> 11) & 1;
-
-             if (initiate) {
-                 if (op == 1) {
-                     mdio_write_req(&t->mdio_bus, phyaddr, regaddr, s->mii.mwd);
-                 } else if (op == 2) {
-                     s->mii.mrd = mdio_read_req(&t->mdio_bus, phyaddr, regaddr);
-                 } else {
-                     qemu_log("AXIENET: invalid MDIOBus OP=%d\n", op);
-                 }
-             }
-             s->mii.mcr = value;
-             break;
-        }
-
-        case R_MWD:
-        case R_MRD:
-             s->mii.regs[addr & 3] = value;
-             break;
-
-
-        case R_UAW0:
-        case R_UAW1:
-            s->uaw[addr & 1] = value;
-            break;
-
-        case R_UAWL:
-        case R_UAWU:
-            s->ext_uaw[addr & 1] = value;
-            break;
-
-        case R_FMI:
-            s->fmi = value;
-            break;
-
-        case R_AF0:
-        case R_AF1:
-            s->maddr[s->fmi & 3][addr & 1] = value;
-            break;
-
-        case R_IS:
-            s->regs[addr] &= ~value;
-            break;
-
-        case 0x8000 ... 0x83ff:
-            s->ext_mtable[addr - 0x8000] = value;
-            break;
-
-        default:
-            DENET(qemu_log("%s addr=" TARGET_FMT_plx " v=%x\n",
-                           __func__, addr * 4, (unsigned)value));
-            if (addr < ARRAY_SIZE(s->regs)) {
-                s->regs[addr] = value;
-            }
-            break;
-    }
-    enet_update_irq(s);
-}
-
-static const MemoryRegionOps enet_ops = {
-    .read = enet_read,
-    .write = enet_write,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-static int eth_can_rx(NetClientState *nc)
-{
-    struct XilinxAXIEnet *s = qemu_get_nic_opaque(nc);
-
-    /* RX enabled?  */
-    return !axienet_rx_resetting(s) && axienet_rx_enabled(s);
-}
-
-static int enet_match_addr(const uint8_t *buf, uint32_t f0, uint32_t f1)
-{
-    int match = 1;
-
-    if (memcmp(buf, &f0, 4)) {
-        match = 0;
-    }
-
-    if (buf[4] != (f1 & 0xff) || buf[5] != ((f1 >> 8) & 0xff)) {
-        match = 0;
-    }
-
-    return match;
-}
-
-static ssize_t eth_rx(NetClientState *nc, const uint8_t *buf, size_t size)
-{
-    struct XilinxAXIEnet *s = qemu_get_nic_opaque(nc);
-    static const unsigned char sa_bcast[6] = {0xff, 0xff, 0xff,
-                                              0xff, 0xff, 0xff};
-    static const unsigned char sa_ipmcast[3] = {0x01, 0x00, 0x52};
-    uint32_t app[6] = {0};
-    int promisc = s->fmi & (1 << 31);
-    int unicast, broadcast, multicast, ip_multicast = 0;
-    uint32_t csum32;
-    uint16_t csum16;
-    int i;
-
-    DENET(qemu_log("%s: %zd bytes\n", __func__, size));
-
-    unicast = ~buf[0] & 0x1;
-    broadcast = memcmp(buf, sa_bcast, 6) == 0;
-    multicast = !unicast && !broadcast;
-    if (multicast && (memcmp(sa_ipmcast, buf, sizeof sa_ipmcast) == 0)) {
-        ip_multicast = 1;
-    }
-
-    /* Jumbo or vlan sizes ?  */
-    if (!(s->rcw[1] & RCW1_JUM)) {
-        if (size > 1518 && size <= 1522 && !(s->rcw[1] & RCW1_VLAN)) {
-            return size;
-        }
-    }
-
-    /* Basic Address filters.  If you want to use the extended filters
-       you'll generally have to place the ethernet mac into promiscuous mode
-       to avoid the basic filtering from dropping most frames.  */
-    if (!promisc) {
-        if (unicast) {
-            if (!enet_match_addr(buf, s->uaw[0], s->uaw[1])) {
-                return size;
-            }
-        } else {
-            if (broadcast) {
-                /* Broadcast.  */
-                if (s->regs[R_RAF] & RAF_BCAST_REJ) {
-                    return size;
-                }
-            } else {
-                int drop = 1;
-
-                /* Multicast.  */
-                if (s->regs[R_RAF] & RAF_MCAST_REJ) {
-                    return size;
-                }
-
-                for (i = 0; i < 4; i++) {
-                    if (enet_match_addr(buf, s->maddr[i][0], s->maddr[i][1])) {
-                        drop = 0;
-                        break;
-                    }
-                }
-
-                if (drop) {
-                    return size;
-                }
-            }
-        }
-    }
-
-    /* Extended mcast filtering enabled?  */
-    if (axienet_newfunc_enabled(s) && axienet_extmcf_enabled(s)) {
-        if (unicast) {
-            if (!enet_match_addr(buf, s->ext_uaw[0], s->ext_uaw[1])) {
-                return size;
-            }
-        } else {
-            if (broadcast) {
-                /* Broadcast. ???  */
-                if (s->regs[R_RAF] & RAF_BCAST_REJ) {
-                    return size;
-                }
-            } else {
-                int idx, bit;
-
-                /* Multicast.  */
-                if (!memcmp(buf, sa_ipmcast, 3)) {
-                    return size;
-                }
-
-                idx  = (buf[4] & 0x7f) << 8;
-                idx |= buf[5];
-
-                bit = 1 << (idx & 0x1f);
-                idx >>= 5;
-
-                if (!(s->ext_mtable[idx] & bit)) {
-                    return size;
-                }
-            }
-        }
-    }
-
-    if (size < 12) {
-        s->regs[R_IS] |= IS_RX_REJECT;
-        enet_update_irq(s);
-        return -1;
-    }
-
-    if (size > (s->c_rxmem - 4)) {
-        size = s->c_rxmem - 4;
-    }
-
-    memcpy(s->rxmem, buf, size);
-    memset(s->rxmem + size, 0, 4); /* Clear the FCS.  */
-
-    if (s->rcw[1] & RCW1_FCS) {
-        size += 4; /* fcs is inband.  */
-    }
-
-    app[0] = 5 << 28;
-    csum32 = net_checksum_add(size - 14, (uint8_t *)s->rxmem + 14);
-    /* Fold it once.  */
-    csum32 = (csum32 & 0xffff) + (csum32 >> 16);
-    /* And twice to get rid of possible carries.  */
-    csum16 = (csum32 & 0xffff) + (csum32 >> 16);
-    app[3] = csum16;
-    app[4] = size & 0xffff;
-
-    s->stats.rx_bytes += size;
-    s->stats.rx++;
-    if (multicast) {
-        s->stats.rx_mcast++;
-        app[2] |= 1 | (ip_multicast << 1);
-    } else if (broadcast) {
-        s->stats.rx_bcast++;
-        app[2] |= 1 << 3;
-    }
-
-    /* Good frame.  */
-    app[2] |= 1 << 6;
-
-    stream_push(s->tx_dev, (void *)s->rxmem, size, app);
-
-    s->regs[R_IS] |= IS_RX_COMPLETE;
-    enet_update_irq(s);
-    return size;
-}
-
-static void eth_cleanup(NetClientState *nc)
-{
-    /* FIXME.  */
-    struct XilinxAXIEnet *s = qemu_get_nic_opaque(nc);
-    g_free(s->rxmem);
-    g_free(s);
-}
-
-static void
-axienet_stream_push(StreamSlave *obj, uint8_t *buf, size_t size, uint32_t *hdr)
-{
-    struct XilinxAXIEnet *s = FROM_SYSBUS(typeof(*s), SYS_BUS_DEVICE(obj));
-
-    /* TX enable ?  */
-    if (!(s->tc & TC_TX)) {
-        return;
-    }
-
-    /* Jumbo or vlan sizes ?  */
-    if (!(s->tc & TC_JUM)) {
-        if (size > 1518 && size <= 1522 && !(s->tc & TC_VLAN)) {
-            return;
-        }
-    }
-
-    if (hdr[0] & 1) {
-        unsigned int start_off = hdr[1] >> 16;
-        unsigned int write_off = hdr[1] & 0xffff;
-        uint32_t tmp_csum;
-        uint16_t csum;
-
-        tmp_csum = net_checksum_add(size - start_off,
-                                    (uint8_t *)buf + start_off);
-        /* Accumulate the seed.  */
-        tmp_csum += hdr[2] & 0xffff;
-
-        /* Fold the 32bit partial checksum.  */
-        csum = net_checksum_finish(tmp_csum);
-
-        /* Writeback.  */
-        buf[write_off] = csum >> 8;
-        buf[write_off + 1] = csum & 0xff;
-    }
-
-    qemu_send_packet(qemu_get_queue(s->nic), buf, size);
-
-    s->stats.tx_bytes += size;
-    s->regs[R_IS] |= IS_TX_COMPLETE;
-    enet_update_irq(s);
-}
-
-static NetClientInfo net_xilinx_enet_info = {
-    .type = NET_CLIENT_OPTIONS_KIND_NIC,
-    .size = sizeof(NICState),
-    .can_receive = eth_can_rx,
-    .receive = eth_rx,
-    .cleanup = eth_cleanup,
-};
-
-static int xilinx_enet_init(SysBusDevice *dev)
-{
-    struct XilinxAXIEnet *s = FROM_SYSBUS(typeof(*s), dev);
-
-    sysbus_init_irq(dev, &s->irq);
-
-    memory_region_init_io(&s->iomem, &enet_ops, s, "enet", 0x40000);
-    sysbus_init_mmio(dev, &s->iomem);
-
-    qemu_macaddr_default_if_unset(&s->conf.macaddr);
-    s->nic = qemu_new_nic(&net_xilinx_enet_info, &s->conf,
-                          object_get_typename(OBJECT(dev)), dev->qdev.id, s);
-    qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
-
-    tdk_init(&s->TEMAC.phy);
-    mdio_attach(&s->TEMAC.mdio_bus, &s->TEMAC.phy, s->c_phyaddr);
-
-    s->TEMAC.parent = s;
-
-    s->rxmem = g_malloc(s->c_rxmem);
-    axienet_reset(s);
-
-    return 0;
-}
-
-static void xilinx_enet_initfn(Object *obj)
-{
-    struct XilinxAXIEnet *s = FROM_SYSBUS(typeof(*s), SYS_BUS_DEVICE(obj));
-    Error *errp = NULL;
-
-    object_property_add_link(obj, "axistream-connected", TYPE_STREAM_SLAVE,
-                             (Object **) &s->tx_dev, &errp);
-    assert_no_error(errp);
-}
-
-static Property xilinx_enet_properties[] = {
-    DEFINE_PROP_UINT32("phyaddr", struct XilinxAXIEnet, c_phyaddr, 7),
-    DEFINE_PROP_UINT32("rxmem", struct XilinxAXIEnet, c_rxmem, 0x1000),
-    DEFINE_PROP_UINT32("txmem", struct XilinxAXIEnet, c_txmem, 0x1000),
-    DEFINE_NIC_PROPERTIES(struct XilinxAXIEnet, conf),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void xilinx_enet_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-    StreamSlaveClass *ssc = STREAM_SLAVE_CLASS(klass);
-
-    k->init = xilinx_enet_init;
-    dc->props = xilinx_enet_properties;
-    ssc->push = axienet_stream_push;
-}
-
-static const TypeInfo xilinx_enet_info = {
-    .name          = "xlnx.axi-ethernet",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(struct XilinxAXIEnet),
-    .class_init    = xilinx_enet_class_init,
-    .instance_init = xilinx_enet_initfn,
-    .interfaces = (InterfaceInfo[]) {
-            { TYPE_STREAM_SLAVE },
-            { }
-    }
-};
-
-static void xilinx_enet_register_types(void)
-{
-    type_register_static(&xilinx_enet_info);
-}
-
-type_init(xilinx_enet_register_types)
diff --git a/hw/xilinx_ethlite.c b/hw/xilinx_ethlite.c
deleted file mode 100644 (file)
index b2e3523..0000000
+++ /dev/null
@@ -1,263 +0,0 @@
-/*
- * QEMU model of the Xilinx Ethernet Lite MAC.
- *
- * Copyright (c) 2009 Edgar E. Iglesias.
- *
- * 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 "hw/sysbus.h"
-#include "hw/hw.h"
-#include "net/net.h"
-
-#define D(x)
-#define R_TX_BUF0     0
-#define R_TX_LEN0     (0x07f4 / 4)
-#define R_TX_GIE0     (0x07f8 / 4)
-#define R_TX_CTRL0    (0x07fc / 4)
-#define R_TX_BUF1     (0x0800 / 4)
-#define R_TX_LEN1     (0x0ff4 / 4)
-#define R_TX_CTRL1    (0x0ffc / 4)
-
-#define R_RX_BUF0     (0x1000 / 4)
-#define R_RX_CTRL0    (0x17fc / 4)
-#define R_RX_BUF1     (0x1800 / 4)
-#define R_RX_CTRL1    (0x1ffc / 4)
-#define R_MAX         (0x2000 / 4)
-
-#define GIE_GIE    0x80000000
-
-#define CTRL_I     0x8
-#define CTRL_P     0x2
-#define CTRL_S     0x1
-
-struct xlx_ethlite
-{
-    SysBusDevice busdev;
-    MemoryRegion mmio;
-    qemu_irq irq;
-    NICState *nic;
-    NICConf conf;
-
-    uint32_t c_tx_pingpong;
-    uint32_t c_rx_pingpong;
-    unsigned int txbuf;
-    unsigned int rxbuf;
-
-    uint32_t regs[R_MAX];
-};
-
-static inline void eth_pulse_irq(struct xlx_ethlite *s)
-{
-    /* Only the first gie reg is active.  */
-    if (s->regs[R_TX_GIE0] & GIE_GIE) {
-        qemu_irq_pulse(s->irq);
-    }
-}
-
-static uint64_t
-eth_read(void *opaque, hwaddr addr, unsigned int size)
-{
-    struct xlx_ethlite *s = opaque;
-    uint32_t r = 0;
-
-    addr >>= 2;
-
-    switch (addr)
-    {
-        case R_TX_GIE0:
-        case R_TX_LEN0:
-        case R_TX_LEN1:
-        case R_TX_CTRL1:
-        case R_TX_CTRL0:
-        case R_RX_CTRL1:
-        case R_RX_CTRL0:
-            r = s->regs[addr];
-            D(qemu_log("%s " TARGET_FMT_plx "=%x\n", __func__, addr * 4, r));
-            break;
-
-        default:
-            r = tswap32(s->regs[addr]);
-            break;
-    }
-    return r;
-}
-
-static void
-eth_write(void *opaque, hwaddr addr,
-          uint64_t val64, unsigned int size)
-{
-    struct xlx_ethlite *s = opaque;
-    unsigned int base = 0;
-    uint32_t value = val64;
-
-    addr >>= 2;
-    switch (addr) 
-    {
-        case R_TX_CTRL0:
-        case R_TX_CTRL1:
-            if (addr == R_TX_CTRL1)
-                base = 0x800 / 4;
-
-            D(qemu_log("%s addr=" TARGET_FMT_plx " val=%x\n",
-                       __func__, addr * 4, value));
-            if ((value & (CTRL_P | CTRL_S)) == CTRL_S) {
-                qemu_send_packet(qemu_get_queue(s->nic),
-                                 (void *) &s->regs[base],
-                                 s->regs[base + R_TX_LEN0]);
-                D(qemu_log("eth_tx %d\n", s->regs[base + R_TX_LEN0]));
-                if (s->regs[base + R_TX_CTRL0] & CTRL_I)
-                    eth_pulse_irq(s);
-            } else if ((value & (CTRL_P | CTRL_S)) == (CTRL_P | CTRL_S)) {
-                memcpy(&s->conf.macaddr.a[0], &s->regs[base], 6);
-                if (s->regs[base + R_TX_CTRL0] & CTRL_I)
-                    eth_pulse_irq(s);
-            }
-
-            /* We are fast and get ready pretty much immediately so
-               we actually never flip the S nor P bits to one.  */
-            s->regs[addr] = value & ~(CTRL_P | CTRL_S);
-            break;
-
-        /* Keep these native.  */
-        case R_RX_CTRL0:
-        case R_RX_CTRL1:
-            if (!(value & CTRL_S)) {
-                qemu_flush_queued_packets(qemu_get_queue(s->nic));
-            }
-        case R_TX_LEN0:
-        case R_TX_LEN1:
-        case R_TX_GIE0:
-            D(qemu_log("%s addr=" TARGET_FMT_plx " val=%x\n",
-                       __func__, addr * 4, value));
-            s->regs[addr] = value;
-            break;
-
-        default:
-            s->regs[addr] = tswap32(value);
-            break;
-    }
-}
-
-static const MemoryRegionOps eth_ops = {
-    .read = eth_read,
-    .write = eth_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4
-    }
-};
-
-static int eth_can_rx(NetClientState *nc)
-{
-    struct xlx_ethlite *s = qemu_get_nic_opaque(nc);
-    unsigned int rxbase = s->rxbuf * (0x800 / 4);
-
-    return !(s->regs[rxbase + R_RX_CTRL0] & CTRL_S);
-}
-
-static ssize_t eth_rx(NetClientState *nc, const uint8_t *buf, size_t size)
-{
-    struct xlx_ethlite *s = qemu_get_nic_opaque(nc);
-    unsigned int rxbase = s->rxbuf * (0x800 / 4);
-
-    /* DA filter.  */
-    if (!(buf[0] & 0x80) && memcmp(&s->conf.macaddr.a[0], buf, 6))
-        return size;
-
-    if (s->regs[rxbase + R_RX_CTRL0] & CTRL_S) {
-        D(qemu_log("ethlite lost packet %x\n", s->regs[R_RX_CTRL0]));
-        return -1;
-    }
-
-    D(qemu_log("%s %zd rxbase=%x\n", __func__, size, rxbase));
-    memcpy(&s->regs[rxbase + R_RX_BUF0], buf, size);
-
-    s->regs[rxbase + R_RX_CTRL0] |= CTRL_S;
-    if (s->regs[rxbase + R_RX_CTRL0] & CTRL_I)
-        eth_pulse_irq(s);
-
-    /* If c_rx_pingpong was set flip buffers.  */
-    s->rxbuf ^= s->c_rx_pingpong;
-    return size;
-}
-
-static void eth_cleanup(NetClientState *nc)
-{
-    struct xlx_ethlite *s = qemu_get_nic_opaque(nc);
-
-    s->nic = NULL;
-}
-
-static NetClientInfo net_xilinx_ethlite_info = {
-    .type = NET_CLIENT_OPTIONS_KIND_NIC,
-    .size = sizeof(NICState),
-    .can_receive = eth_can_rx,
-    .receive = eth_rx,
-    .cleanup = eth_cleanup,
-};
-
-static int xilinx_ethlite_init(SysBusDevice *dev)
-{
-    struct xlx_ethlite *s = FROM_SYSBUS(typeof (*s), dev);
-
-    sysbus_init_irq(dev, &s->irq);
-    s->rxbuf = 0;
-
-    memory_region_init_io(&s->mmio, &eth_ops, s, "xlnx.xps-ethernetlite",
-                                                                    R_MAX * 4);
-    sysbus_init_mmio(dev, &s->mmio);
-
-    qemu_macaddr_default_if_unset(&s->conf.macaddr);
-    s->nic = qemu_new_nic(&net_xilinx_ethlite_info, &s->conf,
-                          object_get_typename(OBJECT(dev)), dev->qdev.id, s);
-    qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
-    return 0;
-}
-
-static Property xilinx_ethlite_properties[] = {
-    DEFINE_PROP_UINT32("tx-ping-pong", struct xlx_ethlite, c_tx_pingpong, 1),
-    DEFINE_PROP_UINT32("rx-ping-pong", struct xlx_ethlite, c_rx_pingpong, 1),
-    DEFINE_NIC_PROPERTIES(struct xlx_ethlite, conf),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void xilinx_ethlite_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = xilinx_ethlite_init;
-    dc->props = xilinx_ethlite_properties;
-}
-
-static const TypeInfo xilinx_ethlite_info = {
-    .name          = "xlnx.xps-ethernetlite",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(struct xlx_ethlite),
-    .class_init    = xilinx_ethlite_class_init,
-};
-
-static void xilinx_ethlite_register_types(void)
-{
-    type_register_static(&xilinx_ethlite_info);
-}
-
-type_init(xilinx_ethlite_register_types)
diff --git a/hw/xilinx_intc.c b/hw/xilinx_intc.c
deleted file mode 100644 (file)
index b106e72..0000000
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * QEMU Xilinx OPB Interrupt Controller.
- *
- * Copyright (c) 2009 Edgar E. Iglesias.
- *
- * 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 "hw/sysbus.h"
-#include "hw/hw.h"
-
-#define D(x)
-
-#define R_ISR       0
-#define R_IPR       1
-#define R_IER       2
-#define R_IAR       3
-#define R_SIE       4
-#define R_CIE       5
-#define R_IVR       6
-#define R_MER       7
-#define R_MAX       8
-
-struct xlx_pic
-{
-    SysBusDevice busdev;
-    MemoryRegion mmio;
-    qemu_irq parent_irq;
-
-    /* Configuration reg chosen at synthesis-time. QEMU populates
-       the bits at board-setup.  */
-    uint32_t c_kind_of_intr;
-
-    /* Runtime control registers.  */
-    uint32_t regs[R_MAX];
-};
-
-static void update_irq(struct xlx_pic *p)
-{
-    uint32_t i;
-    /* Update the pending register.  */
-    p->regs[R_IPR] = p->regs[R_ISR] & p->regs[R_IER];
-
-    /* Update the vector register.  */
-    for (i = 0; i < 32; i++) {
-        if (p->regs[R_IPR] & (1 << i))
-            break;
-    }
-    if (i == 32)
-        i = ~0;
-
-    p->regs[R_IVR] = i;
-    if ((p->regs[R_MER] & 1) && p->regs[R_IPR]) {
-        qemu_irq_raise(p->parent_irq);
-    } else {
-        qemu_irq_lower(p->parent_irq);
-    }
-}
-
-static uint64_t
-pic_read(void *opaque, hwaddr addr, unsigned int size)
-{
-    struct xlx_pic *p = opaque;
-    uint32_t r = 0;
-
-    addr >>= 2;
-    switch (addr)
-    {
-        default:
-            if (addr < ARRAY_SIZE(p->regs))
-                r = p->regs[addr];
-            break;
-
-    }
-    D(printf("%s %x=%x\n", __func__, addr * 4, r));
-    return r;
-}
-
-static void
-pic_write(void *opaque, hwaddr addr,
-          uint64_t val64, unsigned int size)
-{
-    struct xlx_pic *p = opaque;
-    uint32_t value = val64;
-
-    addr >>= 2;
-    D(qemu_log("%s addr=%x val=%x\n", __func__, addr * 4, value));
-    switch (addr) 
-    {
-        case R_IAR:
-            p->regs[R_ISR] &= ~value; /* ACK.  */
-            break;
-        case R_SIE:
-            p->regs[R_IER] |= value;  /* Atomic set ie.  */
-            break;
-        case R_CIE:
-            p->regs[R_IER] &= ~value; /* Atomic clear ie.  */
-            break;
-        default:
-            if (addr < ARRAY_SIZE(p->regs))
-                p->regs[addr] = value;
-            break;
-    }
-    update_irq(p);
-}
-
-static const MemoryRegionOps pic_ops = {
-    .read = pic_read,
-    .write = pic_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4
-    }
-};
-
-static void irq_handler(void *opaque, int irq, int level)
-{
-    struct xlx_pic *p = opaque;
-
-    if (!(p->regs[R_MER] & 2)) {
-        qemu_irq_lower(p->parent_irq);
-        return;
-    }
-
-    /* Update source flops. Don't clear unless level triggered.
-       Edge triggered interrupts only go away when explicitely acked to
-       the interrupt controller.  */
-    if (!(p->c_kind_of_intr & (1 << irq)) || level) {
-        p->regs[R_ISR] &= ~(1 << irq);
-        p->regs[R_ISR] |= (level << irq);
-    }
-    update_irq(p);
-}
-
-static int xilinx_intc_init(SysBusDevice *dev)
-{
-    struct xlx_pic *p = FROM_SYSBUS(typeof (*p), dev);
-
-    qdev_init_gpio_in(&dev->qdev, irq_handler, 32);
-    sysbus_init_irq(dev, &p->parent_irq);
-
-    memory_region_init_io(&p->mmio, &pic_ops, p, "xlnx.xps-intc", R_MAX * 4);
-    sysbus_init_mmio(dev, &p->mmio);
-    return 0;
-}
-
-static Property xilinx_intc_properties[] = {
-    DEFINE_PROP_UINT32("kind-of-intr", struct xlx_pic, c_kind_of_intr, 0),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void xilinx_intc_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = xilinx_intc_init;
-    dc->props = xilinx_intc_properties;
-}
-
-static const TypeInfo xilinx_intc_info = {
-    .name          = "xlnx.xps-intc",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(struct xlx_pic),
-    .class_init    = xilinx_intc_class_init,
-};
-
-static void xilinx_intc_register_types(void)
-{
-    type_register_static(&xilinx_intc_info);
-}
-
-type_init(xilinx_intc_register_types)
diff --git a/hw/xilinx_spi.c b/hw/xilinx_spi.c
deleted file mode 100644 (file)
index f6bd3ba..0000000
+++ /dev/null
@@ -1,385 +0,0 @@
-/*
- * QEMU model of the Xilinx SPI Controller
- *
- * Copyright (C) 2010 Edgar E. Iglesias.
- * Copyright (C) 2012 Peter A. G. Crosthwaite <peter.crosthwaite@petalogix.com>
- * Copyright (C) 2012 PetaLogix
- *
- * 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 "hw/sysbus.h"
-#include "sysemu/sysemu.h"
-#include "qemu/log.h"
-#include "qemu/fifo8.h"
-
-#include "hw/ssi.h"
-
-#ifdef XILINX_SPI_ERR_DEBUG
-#define DB_PRINT(...) do { \
-    fprintf(stderr,  ": %s: ", __func__); \
-    fprintf(stderr, ## __VA_ARGS__); \
-    } while (0);
-#else
-    #define DB_PRINT(...)
-#endif
-
-#define R_DGIER     (0x1c / 4)
-#define R_DGIER_IE  (1 << 31)
-
-#define R_IPISR     (0x20 / 4)
-#define IRQ_DRR_NOT_EMPTY    (1 << (31 - 23))
-#define IRQ_DRR_OVERRUN      (1 << (31 - 26))
-#define IRQ_DRR_FULL         (1 << (31 - 27))
-#define IRQ_TX_FF_HALF_EMPTY (1 << 6)
-#define IRQ_DTR_UNDERRUN     (1 << 3)
-#define IRQ_DTR_EMPTY        (1 << (31 - 29))
-
-#define R_IPIER     (0x28 / 4)
-#define R_SRR       (0x40 / 4)
-#define R_SPICR     (0x60 / 4)
-#define R_SPICR_TXFF_RST     (1 << 5)
-#define R_SPICR_RXFF_RST     (1 << 6)
-#define R_SPICR_MTI          (1 << 8)
-
-#define R_SPISR     (0x64 / 4)
-#define SR_TX_FULL    (1 << 3)
-#define SR_TX_EMPTY   (1 << 2)
-#define SR_RX_FULL    (1 << 1)
-#define SR_RX_EMPTY   (1 << 0)
-
-#define R_SPIDTR    (0x68 / 4)
-#define R_SPIDRR    (0x6C / 4)
-#define R_SPISSR    (0x70 / 4)
-#define R_TX_FF_OCY (0x74 / 4)
-#define R_RX_FF_OCY (0x78 / 4)
-#define R_MAX       (0x7C / 4)
-
-#define FIFO_CAPACITY 256
-
-typedef struct XilinxSPI {
-    SysBusDevice busdev;
-    MemoryRegion mmio;
-
-    qemu_irq irq;
-    int irqline;
-
-    uint8_t num_cs;
-    qemu_irq *cs_lines;
-
-    SSIBus *spi;
-
-    Fifo8 rx_fifo;
-    Fifo8 tx_fifo;
-
-    uint32_t regs[R_MAX];
-} XilinxSPI;
-
-static void txfifo_reset(XilinxSPI *s)
-{
-    fifo8_reset(&s->tx_fifo);
-
-    s->regs[R_SPISR] &= ~SR_TX_FULL;
-    s->regs[R_SPISR] |= SR_TX_EMPTY;
-}
-
-static void rxfifo_reset(XilinxSPI *s)
-{
-    fifo8_reset(&s->rx_fifo);
-
-    s->regs[R_SPISR] |= SR_RX_EMPTY;
-    s->regs[R_SPISR] &= ~SR_RX_FULL;
-}
-
-static void xlx_spi_update_cs(XilinxSPI *s)
-{
-   int i;
-
-    for (i = 0; i < s->num_cs; ++i) {
-        qemu_set_irq(s->cs_lines[i], !(~s->regs[R_SPISSR] & 1 << i));
-    }
-}
-
-static void xlx_spi_update_irq(XilinxSPI *s)
-{
-    uint32_t pending;
-
-    s->regs[R_IPISR] |=
-            (!fifo8_is_empty(&s->rx_fifo) ? IRQ_DRR_NOT_EMPTY : 0) |
-            (fifo8_is_full(&s->rx_fifo) ? IRQ_DRR_FULL : 0);
-
-    pending = s->regs[R_IPISR] & s->regs[R_IPIER];
-
-    pending = pending && (s->regs[R_DGIER] & R_DGIER_IE);
-    pending = !!pending;
-
-    /* This call lies right in the data paths so don't call the
-       irq chain unless things really changed.  */
-    if (pending != s->irqline) {
-        s->irqline = pending;
-        DB_PRINT("irq_change of state %d ISR:%x IER:%X\n",
-                    pending, s->regs[R_IPISR], s->regs[R_IPIER]);
-        qemu_set_irq(s->irq, pending);
-    }
-
-}
-
-static void xlx_spi_do_reset(XilinxSPI *s)
-{
-    memset(s->regs, 0, sizeof s->regs);
-
-    rxfifo_reset(s);
-    txfifo_reset(s);
-
-    s->regs[R_SPISSR] = ~0;
-    xlx_spi_update_irq(s);
-    xlx_spi_update_cs(s);
-}
-
-static void xlx_spi_reset(DeviceState *d)
-{
-    xlx_spi_do_reset(DO_UPCAST(XilinxSPI, busdev.qdev, d));
-}
-
-static inline int spi_master_enabled(XilinxSPI *s)
-{
-    return !(s->regs[R_SPICR] & R_SPICR_MTI);
-}
-
-static void spi_flush_txfifo(XilinxSPI *s)
-{
-    uint32_t tx;
-    uint32_t rx;
-
-    while (!fifo8_is_empty(&s->tx_fifo)) {
-        tx = (uint32_t)fifo8_pop(&s->tx_fifo);
-        DB_PRINT("data tx:%x\n", tx);
-        rx = ssi_transfer(s->spi, tx);
-        DB_PRINT("data rx:%x\n", rx);
-        if (fifo8_is_full(&s->rx_fifo)) {
-            s->regs[R_IPISR] |= IRQ_DRR_OVERRUN;
-        } else {
-            fifo8_push(&s->rx_fifo, (uint8_t)rx);
-            if (fifo8_is_full(&s->rx_fifo)) {
-                s->regs[R_SPISR] |= SR_RX_FULL;
-                s->regs[R_IPISR] |= IRQ_DRR_FULL;
-            }
-        }
-
-        s->regs[R_SPISR] &= ~SR_RX_EMPTY;
-        s->regs[R_SPISR] &= ~SR_TX_FULL;
-        s->regs[R_SPISR] |= SR_TX_EMPTY;
-
-        s->regs[R_IPISR] |= IRQ_DTR_EMPTY;
-        s->regs[R_IPISR] |= IRQ_DRR_NOT_EMPTY;
-    }
-
-}
-
-static uint64_t
-spi_read(void *opaque, hwaddr addr, unsigned int size)
-{
-    XilinxSPI *s = opaque;
-    uint32_t r = 0;
-
-    addr >>= 2;
-    switch (addr) {
-    case R_SPIDRR:
-        if (fifo8_is_empty(&s->rx_fifo)) {
-            DB_PRINT("Read from empty FIFO!\n");
-            return 0xdeadbeef;
-        }
-
-        s->regs[R_SPISR] &= ~SR_RX_FULL;
-        r = fifo8_pop(&s->rx_fifo);
-        if (fifo8_is_empty(&s->rx_fifo)) {
-            s->regs[R_SPISR] |= SR_RX_EMPTY;
-        }
-        break;
-
-    case R_SPISR:
-        r = s->regs[addr];
-        break;
-
-    default:
-        if (addr < ARRAY_SIZE(s->regs)) {
-            r = s->regs[addr];
-        }
-        break;
-
-    }
-    DB_PRINT("addr=" TARGET_FMT_plx " = %x\n", addr * 4, r);
-    xlx_spi_update_irq(s);
-    return r;
-}
-
-static void
-spi_write(void *opaque, hwaddr addr,
-            uint64_t val64, unsigned int size)
-{
-    XilinxSPI *s = opaque;
-    uint32_t value = val64;
-
-    DB_PRINT("addr=" TARGET_FMT_plx " = %x\n", addr, value);
-    addr >>= 2;
-    switch (addr) {
-    case R_SRR:
-        if (value != 0xa) {
-            DB_PRINT("Invalid write to SRR %x\n", value);
-        } else {
-            xlx_spi_do_reset(s);
-        }
-        break;
-
-    case R_SPIDTR:
-        s->regs[R_SPISR] &= ~SR_TX_EMPTY;
-        fifo8_push(&s->tx_fifo, (uint8_t)value);
-        if (fifo8_is_full(&s->tx_fifo)) {
-            s->regs[R_SPISR] |= SR_TX_FULL;
-        }
-        if (!spi_master_enabled(s)) {
-            goto done;
-        } else {
-            DB_PRINT("DTR and master enabled\n");
-        }
-        spi_flush_txfifo(s);
-        break;
-
-    case R_SPISR:
-        DB_PRINT("Invalid write to SPISR %x\n", value);
-        break;
-
-    case R_IPISR:
-        /* Toggle the bits.  */
-        s->regs[addr] ^= value;
-        break;
-
-    /* Slave Select Register.  */
-    case R_SPISSR:
-        s->regs[addr] = value;
-        xlx_spi_update_cs(s);
-        break;
-
-    case R_SPICR:
-        /* FIXME: reset irq and sr state to empty queues.  */
-        if (value & R_SPICR_RXFF_RST) {
-            rxfifo_reset(s);
-        }
-
-        if (value & R_SPICR_TXFF_RST) {
-            txfifo_reset(s);
-        }
-        value &= ~(R_SPICR_RXFF_RST | R_SPICR_TXFF_RST);
-        s->regs[addr] = value;
-
-        if (!(value & R_SPICR_MTI)) {
-            spi_flush_txfifo(s);
-        }
-        break;
-
-    default:
-        if (addr < ARRAY_SIZE(s->regs)) {
-            s->regs[addr] = value;
-        }
-        break;
-    }
-
-done:
-    xlx_spi_update_irq(s);
-}
-
-static const MemoryRegionOps spi_ops = {
-    .read = spi_read,
-    .write = spi_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4
-    }
-};
-
-static int xilinx_spi_init(SysBusDevice *dev)
-{
-    int i;
-    XilinxSPI *s = FROM_SYSBUS(typeof(*s), dev);
-
-    DB_PRINT("\n");
-
-    s->spi = ssi_create_bus(&dev->qdev, "spi");
-
-    sysbus_init_irq(dev, &s->irq);
-    s->cs_lines = g_new(qemu_irq, s->num_cs);
-    ssi_auto_connect_slaves(DEVICE(s), s->cs_lines, s->spi);
-    for (i = 0; i < s->num_cs; ++i) {
-        sysbus_init_irq(dev, &s->cs_lines[i]);
-    }
-
-    memory_region_init_io(&s->mmio, &spi_ops, s, "xilinx-spi", R_MAX * 4);
-    sysbus_init_mmio(dev, &s->mmio);
-
-    s->irqline = -1;
-
-    fifo8_create(&s->tx_fifo, FIFO_CAPACITY);
-    fifo8_create(&s->rx_fifo, FIFO_CAPACITY);
-
-    return 0;
-}
-
-static const VMStateDescription vmstate_xilinx_spi = {
-    .name = "xilinx_spi",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_FIFO8(tx_fifo, XilinxSPI),
-        VMSTATE_FIFO8(rx_fifo, XilinxSPI),
-        VMSTATE_UINT32_ARRAY(regs, XilinxSPI, R_MAX),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static Property xilinx_spi_properties[] = {
-    DEFINE_PROP_UINT8("num-ss-bits", XilinxSPI, num_cs, 1),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void xilinx_spi_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = xilinx_spi_init;
-    dc->reset = xlx_spi_reset;
-    dc->props = xilinx_spi_properties;
-    dc->vmsd = &vmstate_xilinx_spi;
-}
-
-static const TypeInfo xilinx_spi_info = {
-    .name           = "xlnx.xps-spi",
-    .parent         = TYPE_SYS_BUS_DEVICE,
-    .instance_size  = sizeof(XilinxSPI),
-    .class_init     = xilinx_spi_class_init,
-};
-
-static void xilinx_spi_register_types(void)
-{
-    type_register_static(&xilinx_spi_info);
-}
-
-type_init(xilinx_spi_register_types)
diff --git a/hw/xilinx_spips.c b/hw/xilinx_spips.c
deleted file mode 100644 (file)
index b2397f4..0000000
+++ /dev/null
@@ -1,595 +0,0 @@
-/*
- * QEMU model of the Xilinx Zynq SPI controller
- *
- * Copyright (c) 2012 Peter A. G. Crosthwaite
- *
- * 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 "hw/sysbus.h"
-#include "sysemu/sysemu.h"
-#include "hw/ptimer.h"
-#include "qemu/log.h"
-#include "qemu/fifo8.h"
-#include "hw/ssi.h"
-#include "qemu/bitops.h"
-
-#ifdef XILINX_SPIPS_ERR_DEBUG
-#define DB_PRINT(...) do { \
-    fprintf(stderr,  ": %s: ", __func__); \
-    fprintf(stderr, ## __VA_ARGS__); \
-    } while (0);
-#else
-    #define DB_PRINT(...)
-#endif
-
-/* config register */
-#define R_CONFIG            (0x00 / 4)
-#define IFMODE              (1 << 31)
-#define ENDIAN              (1 << 26)
-#define MODEFAIL_GEN_EN     (1 << 17)
-#define MAN_START_COM       (1 << 16)
-#define MAN_START_EN        (1 << 15)
-#define MANUAL_CS           (1 << 14)
-#define CS                  (0xF << 10)
-#define CS_SHIFT            (10)
-#define PERI_SEL            (1 << 9)
-#define REF_CLK             (1 << 8)
-#define FIFO_WIDTH          (3 << 6)
-#define BAUD_RATE_DIV       (7 << 3)
-#define CLK_PH              (1 << 2)
-#define CLK_POL             (1 << 1)
-#define MODE_SEL            (1 << 0)
-
-/* interrupt mechanism */
-#define R_INTR_STATUS       (0x04 / 4)
-#define R_INTR_EN           (0x08 / 4)
-#define R_INTR_DIS          (0x0C / 4)
-#define R_INTR_MASK         (0x10 / 4)
-#define IXR_TX_FIFO_UNDERFLOW   (1 << 6)
-#define IXR_RX_FIFO_FULL        (1 << 5)
-#define IXR_RX_FIFO_NOT_EMPTY   (1 << 4)
-#define IXR_TX_FIFO_FULL        (1 << 3)
-#define IXR_TX_FIFO_NOT_FULL    (1 << 2)
-#define IXR_TX_FIFO_MODE_FAIL   (1 << 1)
-#define IXR_RX_FIFO_OVERFLOW    (1 << 0)
-#define IXR_ALL                 ((IXR_TX_FIFO_UNDERFLOW<<1)-1)
-
-#define R_EN                (0x14 / 4)
-#define R_DELAY             (0x18 / 4)
-#define R_TX_DATA           (0x1C / 4)
-#define R_RX_DATA           (0x20 / 4)
-#define R_SLAVE_IDLE_COUNT  (0x24 / 4)
-#define R_TX_THRES          (0x28 / 4)
-#define R_RX_THRES          (0x2C / 4)
-#define R_TXD1              (0x80 / 4)
-#define R_TXD2              (0x84 / 4)
-#define R_TXD3              (0x88 / 4)
-
-#define R_LQSPI_CFG         (0xa0 / 4)
-#define R_LQSPI_CFG_RESET       0x03A002EB
-#define LQSPI_CFG_LQ_MODE       (1 << 31)
-#define LQSPI_CFG_TWO_MEM       (1 << 30)
-#define LQSPI_CFG_SEP_BUS       (1 << 30)
-#define LQSPI_CFG_U_PAGE        (1 << 28)
-#define LQSPI_CFG_MODE_EN       (1 << 25)
-#define LQSPI_CFG_MODE_WIDTH    8
-#define LQSPI_CFG_MODE_SHIFT    16
-#define LQSPI_CFG_DUMMY_WIDTH   3
-#define LQSPI_CFG_DUMMY_SHIFT   8
-#define LQSPI_CFG_INST_CODE     0xFF
-
-#define R_LQSPI_STS         (0xA4 / 4)
-#define LQSPI_STS_WR_RECVD      (1 << 1)
-
-#define R_MOD_ID            (0xFC / 4)
-
-#define R_MAX (R_MOD_ID+1)
-
-/* size of TXRX FIFOs */
-#define RXFF_A          32
-#define TXFF_A          32
-
-/* 16MB per linear region */
-#define LQSPI_ADDRESS_BITS 24
-/* Bite off 4k chunks at a time */
-#define LQSPI_CACHE_SIZE 1024
-
-#define SNOOP_CHECKING 0xFF
-#define SNOOP_NONE 0xFE
-#define SNOOP_STRIPING 0
-
-typedef enum {
-    READ = 0x3,
-    FAST_READ = 0xb,
-    DOR = 0x3b,
-    QOR = 0x6b,
-    DIOR = 0xbb,
-    QIOR = 0xeb,
-
-    PP = 0x2,
-    DPP = 0xa2,
-    QPP = 0x32,
-} FlashCMD;
-
-typedef struct {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-    MemoryRegion mmlqspi;
-
-    qemu_irq irq;
-    int irqline;
-
-    uint8_t num_cs;
-    uint8_t num_busses;
-
-    uint8_t snoop_state;
-    qemu_irq *cs_lines;
-    SSIBus **spi;
-
-    Fifo8 rx_fifo;
-    Fifo8 tx_fifo;
-
-    uint8_t num_txrx_bytes;
-
-    uint32_t regs[R_MAX];
-
-    uint32_t lqspi_buf[LQSPI_CACHE_SIZE];
-    hwaddr lqspi_cached_addr;
-} XilinxSPIPS;
-
-#define TYPE_XILINX_SPIPS "xilinx,spips"
-
-#define XILINX_SPIPS(obj) \
-     OBJECT_CHECK(XilinxSPIPS, (obj), TYPE_XILINX_SPIPS)
-
-static inline int num_effective_busses(XilinxSPIPS *s)
-{
-    return (s->regs[R_LQSPI_CFG] & LQSPI_CFG_SEP_BUS &&
-            s->regs[R_LQSPI_CFG] & LQSPI_CFG_TWO_MEM) ? s->num_busses : 1;
-}
-
-static void xilinx_spips_update_cs_lines(XilinxSPIPS *s)
-{
-    int i, j;
-    bool found = false;
-    int field = s->regs[R_CONFIG] >> CS_SHIFT;
-
-    for (i = 0; i < s->num_cs; i++) {
-        for (j = 0; j < num_effective_busses(s); j++) {
-            int upage = !!(s->regs[R_LQSPI_STS] & LQSPI_CFG_U_PAGE);
-            int cs_to_set = (j * s->num_cs + i + upage) %
-                                (s->num_cs * s->num_busses);
-
-            if (~field & (1 << i) && !found) {
-                DB_PRINT("selecting slave %d\n", i);
-                qemu_set_irq(s->cs_lines[cs_to_set], 0);
-            } else {
-                qemu_set_irq(s->cs_lines[cs_to_set], 1);
-            }
-        }
-        if (~field & (1 << i)) {
-            found = true;
-        }
-    }
-    if (!found) {
-        s->snoop_state = SNOOP_CHECKING;
-    }
-}
-
-static void xilinx_spips_update_ixr(XilinxSPIPS *s)
-{
-    /* These are set/cleared as they occur */
-    s->regs[R_INTR_STATUS] &= (IXR_TX_FIFO_UNDERFLOW | IXR_RX_FIFO_OVERFLOW |
-                                IXR_TX_FIFO_MODE_FAIL);
-    /* these are pure functions of fifo state, set them here */
-    s->regs[R_INTR_STATUS] |=
-        (fifo8_is_full(&s->rx_fifo) ? IXR_RX_FIFO_FULL : 0) |
-        (s->rx_fifo.num >= s->regs[R_RX_THRES] ? IXR_RX_FIFO_NOT_EMPTY : 0) |
-        (fifo8_is_full(&s->tx_fifo) ? IXR_TX_FIFO_FULL : 0) |
-        (s->tx_fifo.num < s->regs[R_TX_THRES] ? IXR_TX_FIFO_NOT_FULL : 0);
-    /* drive external interrupt pin */
-    int new_irqline = !!(s->regs[R_INTR_MASK] & s->regs[R_INTR_STATUS] &
-                                                                IXR_ALL);
-    if (new_irqline != s->irqline) {
-        s->irqline = new_irqline;
-        qemu_set_irq(s->irq, s->irqline);
-    }
-}
-
-static void xilinx_spips_reset(DeviceState *d)
-{
-    XilinxSPIPS *s = XILINX_SPIPS(d);
-
-    int i;
-    for (i = 0; i < R_MAX; i++) {
-        s->regs[i] = 0;
-    }
-
-    fifo8_reset(&s->rx_fifo);
-    fifo8_reset(&s->rx_fifo);
-    /* non zero resets */
-    s->regs[R_CONFIG] |= MODEFAIL_GEN_EN;
-    s->regs[R_SLAVE_IDLE_COUNT] = 0xFF;
-    s->regs[R_TX_THRES] = 1;
-    s->regs[R_RX_THRES] = 1;
-    /* FIXME: move magic number definition somewhere sensible */
-    s->regs[R_MOD_ID] = 0x01090106;
-    s->regs[R_LQSPI_CFG] = R_LQSPI_CFG_RESET;
-    s->snoop_state = SNOOP_CHECKING;
-    xilinx_spips_update_ixr(s);
-    xilinx_spips_update_cs_lines(s);
-}
-
-static void xilinx_spips_flush_txfifo(XilinxSPIPS *s)
-{
-    for (;;) {
-        int i;
-        uint8_t rx;
-        uint8_t tx = 0;
-
-        for (i = 0; i < num_effective_busses(s); ++i) {
-            if (!i || s->snoop_state == SNOOP_STRIPING) {
-                if (fifo8_is_empty(&s->tx_fifo)) {
-                    s->regs[R_INTR_STATUS] |= IXR_TX_FIFO_UNDERFLOW;
-                    xilinx_spips_update_ixr(s);
-                    return;
-                } else {
-                    tx = fifo8_pop(&s->tx_fifo);
-                }
-            }
-            rx = ssi_transfer(s->spi[i], (uint32_t)tx);
-            DB_PRINT("tx = %02x rx = %02x\n", tx, rx);
-            if (!i || s->snoop_state == SNOOP_STRIPING) {
-                if (fifo8_is_full(&s->rx_fifo)) {
-                    s->regs[R_INTR_STATUS] |= IXR_RX_FIFO_OVERFLOW;
-                    DB_PRINT("rx FIFO overflow");
-                } else {
-                    fifo8_push(&s->rx_fifo, (uint8_t)rx);
-                }
-            }
-        }
-
-        switch (s->snoop_state) {
-        case (SNOOP_CHECKING):
-            switch (tx) { /* new instruction code */
-            case READ: /* 3 address bytes, no dummy bytes/cycles */
-            case PP:
-            case DPP:
-            case QPP:
-                s->snoop_state = 3;
-                break;
-            case FAST_READ: /* 3 address bytes, 1 dummy byte */
-            case DOR:
-            case QOR:
-            case DIOR: /* FIXME: these vary between vendor - set to spansion */
-                s->snoop_state = 4;
-                break;
-            case QIOR: /* 3 address bytes, 2 dummy bytes */
-                s->snoop_state = 6;
-                break;
-            default:
-                s->snoop_state = SNOOP_NONE;
-            }
-            break;
-        case (SNOOP_STRIPING):
-        case (SNOOP_NONE):
-            break;
-        default:
-            s->snoop_state--;
-        }
-    }
-}
-
-static inline void rx_data_bytes(XilinxSPIPS *s, uint32_t *value, int max)
-{
-    int i;
-
-    *value = 0;
-    for (i = 0; i < max && !fifo8_is_empty(&s->rx_fifo); ++i) {
-        uint32_t next = fifo8_pop(&s->rx_fifo) & 0xFF;
-        *value |= next << 8 * (s->regs[R_CONFIG] & ENDIAN ? 3-i : i);
-    }
-}
-
-static uint64_t xilinx_spips_read(void *opaque, hwaddr addr,
-                                                        unsigned size)
-{
-    XilinxSPIPS *s = opaque;
-    uint32_t mask = ~0;
-    uint32_t ret;
-
-    addr >>= 2;
-    switch (addr) {
-    case R_CONFIG:
-        mask = 0x0002FFFF;
-        break;
-    case R_INTR_STATUS:
-    case R_INTR_MASK:
-        mask = IXR_ALL;
-        break;
-    case  R_EN:
-        mask = 0x1;
-        break;
-    case R_SLAVE_IDLE_COUNT:
-        mask = 0xFF;
-        break;
-    case R_MOD_ID:
-        mask = 0x01FFFFFF;
-        break;
-    case R_INTR_EN:
-    case R_INTR_DIS:
-    case R_TX_DATA:
-        mask = 0;
-        break;
-    case R_RX_DATA:
-        rx_data_bytes(s, &ret, s->num_txrx_bytes);
-        DB_PRINT("addr=" TARGET_FMT_plx " = %x\n", addr * 4, ret);
-        xilinx_spips_update_ixr(s);
-        return ret;
-    }
-    DB_PRINT("addr=" TARGET_FMT_plx " = %x\n", addr * 4, s->regs[addr] & mask);
-    return s->regs[addr] & mask;
-
-}
-
-static inline void tx_data_bytes(XilinxSPIPS *s, uint32_t value, int num)
-{
-    int i;
-    for (i = 0; i < num && !fifo8_is_full(&s->tx_fifo); ++i) {
-        if (s->regs[R_CONFIG] & ENDIAN) {
-            fifo8_push(&s->tx_fifo, (uint8_t)(value >> 24));
-            value <<= 8;
-        } else {
-            fifo8_push(&s->tx_fifo, (uint8_t)value);
-            value >>= 8;
-        }
-    }
-}
-
-static void xilinx_spips_write(void *opaque, hwaddr addr,
-                                        uint64_t value, unsigned size)
-{
-    int mask = ~0;
-    int man_start_com = 0;
-    XilinxSPIPS *s = opaque;
-
-    DB_PRINT("addr=" TARGET_FMT_plx " = %x\n", addr, (unsigned)value);
-    addr >>= 2;
-    switch (addr) {
-    case R_CONFIG:
-        mask = 0x0002FFFF;
-        if (value & MAN_START_COM) {
-            man_start_com = 1;
-        }
-        break;
-    case R_INTR_STATUS:
-        mask = IXR_ALL;
-        s->regs[R_INTR_STATUS] &= ~(mask & value);
-        goto no_reg_update;
-    case R_INTR_DIS:
-        mask = IXR_ALL;
-        s->regs[R_INTR_MASK] &= ~(mask & value);
-        goto no_reg_update;
-    case R_INTR_EN:
-        mask = IXR_ALL;
-        s->regs[R_INTR_MASK] |= mask & value;
-        goto no_reg_update;
-    case R_EN:
-        mask = 0x1;
-        break;
-    case R_SLAVE_IDLE_COUNT:
-        mask = 0xFF;
-        break;
-    case R_RX_DATA:
-    case R_INTR_MASK:
-    case R_MOD_ID:
-        mask = 0;
-        break;
-    case R_TX_DATA:
-        tx_data_bytes(s, (uint32_t)value, s->num_txrx_bytes);
-        goto no_reg_update;
-    case R_TXD1:
-        tx_data_bytes(s, (uint32_t)value, 1);
-        goto no_reg_update;
-    case R_TXD2:
-        tx_data_bytes(s, (uint32_t)value, 2);
-        goto no_reg_update;
-    case R_TXD3:
-        tx_data_bytes(s, (uint32_t)value, 3);
-        goto no_reg_update;
-    }
-    s->regs[addr] = (s->regs[addr] & ~mask) | (value & mask);
-no_reg_update:
-    if (man_start_com) {
-        xilinx_spips_flush_txfifo(s);
-    }
-    xilinx_spips_update_ixr(s);
-    xilinx_spips_update_cs_lines(s);
-}
-
-static const MemoryRegionOps spips_ops = {
-    .read = xilinx_spips_read,
-    .write = xilinx_spips_write,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-};
-
-#define LQSPI_CACHE_SIZE 1024
-
-static uint64_t
-lqspi_read(void *opaque, hwaddr addr, unsigned int size)
-{
-    int i;
-    XilinxSPIPS *s = opaque;
-
-    if (addr >= s->lqspi_cached_addr &&
-            addr <= s->lqspi_cached_addr + LQSPI_CACHE_SIZE - 4) {
-        return s->lqspi_buf[(addr - s->lqspi_cached_addr) >> 2];
-    } else {
-        int flash_addr = (addr / num_effective_busses(s));
-        int slave = flash_addr >> LQSPI_ADDRESS_BITS;
-        int cache_entry = 0;
-
-        DB_PRINT("config reg status: %08x\n", s->regs[R_LQSPI_CFG]);
-
-        fifo8_reset(&s->tx_fifo);
-        fifo8_reset(&s->rx_fifo);
-
-        s->regs[R_CONFIG] &= ~CS;
-        s->regs[R_CONFIG] |= (~(1 << slave) << CS_SHIFT) & CS;
-        xilinx_spips_update_cs_lines(s);
-
-        /* instruction */
-        DB_PRINT("pushing read instruction: %02x\n",
-                 (uint8_t)(s->regs[R_LQSPI_CFG] & LQSPI_CFG_INST_CODE));
-        fifo8_push(&s->tx_fifo, s->regs[R_LQSPI_CFG] & LQSPI_CFG_INST_CODE);
-        /* read address */
-        DB_PRINT("pushing read address %06x\n", flash_addr);
-        fifo8_push(&s->tx_fifo, (uint8_t)(flash_addr >> 16));
-        fifo8_push(&s->tx_fifo, (uint8_t)(flash_addr >> 8));
-        fifo8_push(&s->tx_fifo, (uint8_t)flash_addr);
-        /* mode bits */
-        if (s->regs[R_LQSPI_CFG] & LQSPI_CFG_MODE_EN) {
-            fifo8_push(&s->tx_fifo, extract32(s->regs[R_LQSPI_CFG],
-                                              LQSPI_CFG_MODE_SHIFT,
-                                              LQSPI_CFG_MODE_WIDTH));
-        }
-        /* dummy bytes */
-        for (i = 0; i < (extract32(s->regs[R_LQSPI_CFG], LQSPI_CFG_DUMMY_SHIFT,
-                                   LQSPI_CFG_DUMMY_WIDTH)); ++i) {
-            DB_PRINT("pushing dummy byte\n");
-            fifo8_push(&s->tx_fifo, 0);
-        }
-        xilinx_spips_flush_txfifo(s);
-        fifo8_reset(&s->rx_fifo);
-
-        DB_PRINT("starting QSPI data read\n");
-
-        for (i = 0; i < LQSPI_CACHE_SIZE / 4; ++i) {
-            tx_data_bytes(s, 0, 4);
-            xilinx_spips_flush_txfifo(s);
-            rx_data_bytes(s, &s->lqspi_buf[cache_entry], 4);
-            cache_entry++;
-        }
-
-        s->regs[R_CONFIG] |= CS;
-        xilinx_spips_update_cs_lines(s);
-
-        s->lqspi_cached_addr = addr;
-        return lqspi_read(opaque, addr, size);
-    }
-}
-
-static const MemoryRegionOps lqspi_ops = {
-    .read = lqspi_read,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4
-    }
-};
-
-static void xilinx_spips_realize(DeviceState *dev, Error **errp)
-{
-    XilinxSPIPS *s = XILINX_SPIPS(dev);
-    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
-    int i;
-
-    DB_PRINT("inited device model\n");
-
-    s->spi = g_new(SSIBus *, s->num_busses);
-    for (i = 0; i < s->num_busses; ++i) {
-        char bus_name[16];
-        snprintf(bus_name, 16, "spi%d", i);
-        s->spi[i] = ssi_create_bus(dev, bus_name);
-    }
-
-    s->cs_lines = g_new0(qemu_irq, s->num_cs * s->num_busses);
-    ssi_auto_connect_slaves(DEVICE(s), s->cs_lines, s->spi[0]);
-    ssi_auto_connect_slaves(DEVICE(s), s->cs_lines, s->spi[1]);
-    sysbus_init_irq(sbd, &s->irq);
-    for (i = 0; i < s->num_cs * s->num_busses; ++i) {
-        sysbus_init_irq(sbd, &s->cs_lines[i]);
-    }
-
-    memory_region_init_io(&s->iomem, &spips_ops, s, "spi", R_MAX*4);
-    sysbus_init_mmio(sbd, &s->iomem);
-
-    memory_region_init_io(&s->mmlqspi, &lqspi_ops, s, "lqspi",
-                          (1 << LQSPI_ADDRESS_BITS) * 2);
-    sysbus_init_mmio(sbd, &s->mmlqspi);
-
-    s->irqline = -1;
-    s->lqspi_cached_addr = ~0ULL;
-
-    fifo8_create(&s->rx_fifo, RXFF_A);
-    fifo8_create(&s->tx_fifo, TXFF_A);
-}
-
-static int xilinx_spips_post_load(void *opaque, int version_id)
-{
-    xilinx_spips_update_ixr((XilinxSPIPS *)opaque);
-    xilinx_spips_update_cs_lines((XilinxSPIPS *)opaque);
-    return 0;
-}
-
-static const VMStateDescription vmstate_xilinx_spips = {
-    .name = "xilinx_spips",
-    .version_id = 2,
-    .minimum_version_id = 2,
-    .minimum_version_id_old = 2,
-    .post_load = xilinx_spips_post_load,
-    .fields = (VMStateField[]) {
-        VMSTATE_FIFO8(tx_fifo, XilinxSPIPS),
-        VMSTATE_FIFO8(rx_fifo, XilinxSPIPS),
-        VMSTATE_UINT32_ARRAY(regs, XilinxSPIPS, R_MAX),
-        VMSTATE_UINT8(snoop_state, XilinxSPIPS),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static Property xilinx_spips_properties[] = {
-    DEFINE_PROP_UINT8("num-busses", XilinxSPIPS, num_busses, 1),
-    DEFINE_PROP_UINT8("num-ss-bits", XilinxSPIPS, num_cs, 4),
-    DEFINE_PROP_UINT8("num-txrx-bytes", XilinxSPIPS, num_txrx_bytes, 1),
-    DEFINE_PROP_END_OF_LIST(),
-};
-static void xilinx_spips_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-
-    dc->realize = xilinx_spips_realize;
-    dc->reset = xilinx_spips_reset;
-    dc->props = xilinx_spips_properties;
-    dc->vmsd = &vmstate_xilinx_spips;
-}
-
-static const TypeInfo xilinx_spips_info = {
-    .name  = TYPE_XILINX_SPIPS,
-    .parent = TYPE_SYS_BUS_DEVICE,
-    .instance_size  = sizeof(XilinxSPIPS),
-    .class_init = xilinx_spips_class_init,
-};
-
-static void xilinx_spips_register_types(void)
-{
-    type_register_static(&xilinx_spips_info);
-}
-
-type_init(xilinx_spips_register_types)
diff --git a/hw/xilinx_timer.c b/hw/xilinx_timer.c
deleted file mode 100644 (file)
index 0c39cff..0000000
+++ /dev/null
@@ -1,255 +0,0 @@
-/*
- * QEMU model of the Xilinx timer block.
- *
- * Copyright (c) 2009 Edgar E. Iglesias.
- *
- * 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 "hw/sysbus.h"
-#include "hw/ptimer.h"
-#include "qemu/log.h"
-
-#define D(x)
-
-#define R_TCSR     0
-#define R_TLR      1
-#define R_TCR      2
-#define R_MAX      4
-
-#define TCSR_MDT        (1<<0)
-#define TCSR_UDT        (1<<1)
-#define TCSR_GENT       (1<<2)
-#define TCSR_CAPT       (1<<3)
-#define TCSR_ARHT       (1<<4)
-#define TCSR_LOAD       (1<<5)
-#define TCSR_ENIT       (1<<6)
-#define TCSR_ENT        (1<<7)
-#define TCSR_TINT       (1<<8)
-#define TCSR_PWMA       (1<<9)
-#define TCSR_ENALL      (1<<10)
-
-struct xlx_timer
-{
-    QEMUBH *bh;
-    ptimer_state *ptimer;
-    void *parent;
-    int nr; /* for debug.  */
-
-    unsigned long timer_div;
-
-    uint32_t regs[R_MAX];
-};
-
-struct timerblock
-{
-    SysBusDevice busdev;
-    MemoryRegion mmio;
-    qemu_irq irq;
-    uint8_t one_timer_only;
-    uint32_t freq_hz;
-    struct xlx_timer *timers;
-};
-
-static inline unsigned int num_timers(struct timerblock *t)
-{
-    return 2 - t->one_timer_only;
-}
-
-static inline unsigned int timer_from_addr(hwaddr addr)
-{
-    /* Timers get a 4x32bit control reg area each.  */
-    return addr >> 2;
-}
-
-static void timer_update_irq(struct timerblock *t)
-{
-    unsigned int i, irq = 0;
-    uint32_t csr;
-
-    for (i = 0; i < num_timers(t); i++) {
-        csr = t->timers[i].regs[R_TCSR];
-        irq |= (csr & TCSR_TINT) && (csr & TCSR_ENIT);
-    }
-
-    /* All timers within the same slave share a single IRQ line.  */
-    qemu_set_irq(t->irq, !!irq);
-}
-
-static uint64_t
-timer_read(void *opaque, hwaddr addr, unsigned int size)
-{
-    struct timerblock *t = opaque;
-    struct xlx_timer *xt;
-    uint32_t r = 0;
-    unsigned int timer;
-
-    addr >>= 2;
-    timer = timer_from_addr(addr);
-    xt = &t->timers[timer];
-    /* Further decoding to address a specific timers reg.  */
-    addr &= 0x3;
-    switch (addr)
-    {
-        case R_TCR:
-                r = ptimer_get_count(xt->ptimer);
-                if (!(xt->regs[R_TCSR] & TCSR_UDT))
-                    r = ~r;
-                D(qemu_log("xlx_timer t=%d read counter=%x udt=%d\n",
-                         timer, r, xt->regs[R_TCSR] & TCSR_UDT));
-            break;
-        default:
-            if (addr < ARRAY_SIZE(xt->regs))
-                r = xt->regs[addr];
-            break;
-
-    }
-    D(fprintf(stderr, "%s timer=%d %x=%x\n", __func__, timer, addr * 4, r));
-    return r;
-}
-
-static void timer_enable(struct xlx_timer *xt)
-{
-    uint64_t count;
-
-    D(fprintf(stderr, "%s timer=%d down=%d\n", __func__,
-              xt->nr, xt->regs[R_TCSR] & TCSR_UDT));
-
-    ptimer_stop(xt->ptimer);
-
-    if (xt->regs[R_TCSR] & TCSR_UDT)
-        count = xt->regs[R_TLR];
-    else
-        count = ~0 - xt->regs[R_TLR];
-    ptimer_set_limit(xt->ptimer, count, 1);
-    ptimer_run(xt->ptimer, 1);
-}
-
-static void
-timer_write(void *opaque, hwaddr addr,
-            uint64_t val64, unsigned int size)
-{
-    struct timerblock *t = opaque;
-    struct xlx_timer *xt;
-    unsigned int timer;
-    uint32_t value = val64;
-
-    addr >>= 2;
-    timer = timer_from_addr(addr);
-    xt = &t->timers[timer];
-    D(fprintf(stderr, "%s addr=%x val=%x (timer=%d off=%d)\n",
-             __func__, addr * 4, value, timer, addr & 3));
-    /* Further decoding to address a specific timers reg.  */
-    addr &= 3;
-    switch (addr) 
-    {
-        case R_TCSR:
-            if (value & TCSR_TINT)
-                value &= ~TCSR_TINT;
-
-            xt->regs[addr] = value;
-            if (value & TCSR_ENT)
-                timer_enable(xt);
-            break;
-        default:
-            if (addr < ARRAY_SIZE(xt->regs))
-                xt->regs[addr] = value;
-            break;
-    }
-    timer_update_irq(t);
-}
-
-static const MemoryRegionOps timer_ops = {
-    .read = timer_read,
-    .write = timer_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4
-    }
-};
-
-static void timer_hit(void *opaque)
-{
-    struct xlx_timer *xt = opaque;
-    struct timerblock *t = xt->parent;
-    D(fprintf(stderr, "%s %d\n", __func__, xt->nr));
-    xt->regs[R_TCSR] |= TCSR_TINT;
-
-    if (xt->regs[R_TCSR] & TCSR_ARHT)
-        timer_enable(xt);
-    timer_update_irq(t);
-}
-
-static int xilinx_timer_init(SysBusDevice *dev)
-{
-    struct timerblock *t = FROM_SYSBUS(typeof (*t), dev);
-    unsigned int i;
-
-    /* All timers share a single irq line.  */
-    sysbus_init_irq(dev, &t->irq);
-
-    /* Init all the ptimers.  */
-    t->timers = g_malloc0(sizeof t->timers[0] * num_timers(t));
-    for (i = 0; i < num_timers(t); i++) {
-        struct xlx_timer *xt = &t->timers[i];
-
-        xt->parent = t;
-        xt->nr = i;
-        xt->bh = qemu_bh_new(timer_hit, xt);
-        xt->ptimer = ptimer_init(xt->bh);
-        ptimer_set_freq(xt->ptimer, t->freq_hz);
-    }
-
-    memory_region_init_io(&t->mmio, &timer_ops, t, "xlnx.xps-timer",
-                          R_MAX * 4 * num_timers(t));
-    sysbus_init_mmio(dev, &t->mmio);
-    return 0;
-}
-
-static Property xilinx_timer_properties[] = {
-    DEFINE_PROP_UINT32("clock-frequency", struct timerblock, freq_hz,
-                                                                62 * 1000000),
-    DEFINE_PROP_UINT8("one-timer-only", struct timerblock, one_timer_only, 0),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void xilinx_timer_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = xilinx_timer_init;
-    dc->props = xilinx_timer_properties;
-}
-
-static const TypeInfo xilinx_timer_info = {
-    .name          = "xlnx.xps-timer",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(struct timerblock),
-    .class_init    = xilinx_timer_class_init,
-};
-
-static void xilinx_timer_register_types(void)
-{
-    type_register_static(&xilinx_timer_info);
-}
-
-type_init(xilinx_timer_register_types)
diff --git a/hw/xilinx_uartlite.c b/hw/xilinx_uartlite.c
deleted file mode 100644 (file)
index 079f4d4..0000000
+++ /dev/null
@@ -1,231 +0,0 @@
-/*
- * QEMU model of Xilinx uartlite.
- *
- * Copyright (c) 2009 Edgar E. Iglesias.
- *
- * 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 "hw/sysbus.h"
-#include "char/char.h"
-
-#define DUART(x)
-
-#define R_RX            0
-#define R_TX            1
-#define R_STATUS        2
-#define R_CTRL          3
-#define R_MAX           4
-
-#define STATUS_RXVALID    0x01
-#define STATUS_RXFULL     0x02
-#define STATUS_TXEMPTY    0x04
-#define STATUS_TXFULL     0x08
-#define STATUS_IE         0x10
-#define STATUS_OVERRUN    0x20
-#define STATUS_FRAME      0x40
-#define STATUS_PARITY     0x80
-
-#define CONTROL_RST_TX    0x01
-#define CONTROL_RST_RX    0x02
-#define CONTROL_IE        0x10
-
-struct xlx_uartlite
-{
-    SysBusDevice busdev;
-    MemoryRegion mmio;
-    CharDriverState *chr;
-    qemu_irq irq;
-
-    uint8_t rx_fifo[8];
-    unsigned int rx_fifo_pos;
-    unsigned int rx_fifo_len;
-
-    uint32_t regs[R_MAX];
-};
-
-static void uart_update_irq(struct xlx_uartlite *s)
-{
-    unsigned int irq;
-
-    if (s->rx_fifo_len)
-        s->regs[R_STATUS] |= STATUS_IE;
-
-    irq = (s->regs[R_STATUS] & STATUS_IE) && (s->regs[R_CTRL] & CONTROL_IE);
-    qemu_set_irq(s->irq, irq);
-}
-
-static void uart_update_status(struct xlx_uartlite *s)
-{
-    uint32_t r;
-
-    r = s->regs[R_STATUS];
-    r &= ~7;
-    r |= 1 << 2; /* Tx fifo is always empty. We are fast :) */
-    r |= (s->rx_fifo_len == sizeof (s->rx_fifo)) << 1;
-    r |= (!!s->rx_fifo_len);
-    s->regs[R_STATUS] = r;
-}
-
-static uint64_t
-uart_read(void *opaque, hwaddr addr, unsigned int size)
-{
-    struct xlx_uartlite *s = opaque;
-    uint32_t r = 0;
-    addr >>= 2;
-    switch (addr)
-    {
-        case R_RX:
-            r = s->rx_fifo[(s->rx_fifo_pos - s->rx_fifo_len) & 7];
-            if (s->rx_fifo_len)
-                s->rx_fifo_len--;
-            uart_update_status(s);
-            uart_update_irq(s);
-            qemu_chr_accept_input(s->chr);
-            break;
-
-        default:
-            if (addr < ARRAY_SIZE(s->regs))
-                r = s->regs[addr];
-            DUART(qemu_log("%s addr=%x v=%x\n", __func__, addr, r));
-            break;
-    }
-    return r;
-}
-
-static void
-uart_write(void *opaque, hwaddr addr,
-           uint64_t val64, unsigned int size)
-{
-    struct xlx_uartlite *s = opaque;
-    uint32_t value = val64;
-    unsigned char ch = value;
-
-    addr >>= 2;
-    switch (addr)
-    {
-        case R_STATUS:
-            hw_error("write to UART STATUS?\n");
-            break;
-
-        case R_CTRL:
-            if (value & CONTROL_RST_RX) {
-                s->rx_fifo_pos = 0;
-                s->rx_fifo_len = 0;
-            }
-            s->regs[addr] = value;
-            break;
-
-        case R_TX:
-            if (s->chr)
-                qemu_chr_fe_write(s->chr, &ch, 1);
-
-            s->regs[addr] = value;
-
-            /* hax.  */
-            s->regs[R_STATUS] |= STATUS_IE;
-            break;
-
-        default:
-            DUART(printf("%s addr=%x v=%x\n", __func__, addr, value));
-            if (addr < ARRAY_SIZE(s->regs))
-                s->regs[addr] = value;
-            break;
-    }
-    uart_update_status(s);
-    uart_update_irq(s);
-}
-
-static const MemoryRegionOps uart_ops = {
-    .read = uart_read,
-    .write = uart_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid = {
-        .min_access_size = 1,
-        .max_access_size = 4
-    }
-};
-
-static void uart_rx(void *opaque, const uint8_t *buf, int size)
-{
-    struct xlx_uartlite *s = opaque;
-
-    /* Got a byte.  */
-    if (s->rx_fifo_len >= 8) {
-        printf("WARNING: UART dropped char.\n");
-        return;
-    }
-    s->rx_fifo[s->rx_fifo_pos] = *buf;
-    s->rx_fifo_pos++;
-    s->rx_fifo_pos &= 0x7;
-    s->rx_fifo_len++;
-
-    uart_update_status(s);
-    uart_update_irq(s);
-}
-
-static int uart_can_rx(void *opaque)
-{
-    struct xlx_uartlite *s = opaque;
-
-    return s->rx_fifo_len < sizeof(s->rx_fifo);
-}
-
-static void uart_event(void *opaque, int event)
-{
-
-}
-
-static int xilinx_uartlite_init(SysBusDevice *dev)
-{
-    struct xlx_uartlite *s = FROM_SYSBUS(typeof (*s), dev);
-
-    sysbus_init_irq(dev, &s->irq);
-
-    uart_update_status(s);
-    memory_region_init_io(&s->mmio, &uart_ops, s, "xlnx.xps-uartlite",
-                                                                R_MAX * 4);
-    sysbus_init_mmio(dev, &s->mmio);
-
-    s->chr = qemu_char_get_next_serial();
-    if (s->chr)
-        qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s);
-    return 0;
-}
-
-static void xilinx_uartlite_class_init(ObjectClass *klass, void *data)
-{
-    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
-
-    sdc->init = xilinx_uartlite_init;
-}
-
-static const TypeInfo xilinx_uartlite_info = {
-    .name          = "xlnx.xps-uartlite",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof (struct xlx_uartlite),
-    .class_init    = xilinx_uartlite_class_init,
-};
-
-static void xilinx_uart_register_types(void)
-{
-    type_register_static(&xilinx_uartlite_info);
-}
-
-type_init(xilinx_uart_register_types)
diff --git a/hw/xio3130_downstream.c b/hw/xio3130_downstream.c
deleted file mode 100644 (file)
index b868f56..0000000
+++ /dev/null
@@ -1,217 +0,0 @@
-/*
- * x3130_downstream.c
- * TI X3130 pci express downstream port switch
- *
- * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
- *                    VA Linux Systems Japan K.K.
- *
- * 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 "hw/pci/pci_ids.h"
-#include "hw/pci/msi.h"
-#include "hw/pci/pcie.h"
-#include "hw/xio3130_downstream.h"
-
-#define PCI_DEVICE_ID_TI_XIO3130D       0x8233  /* downstream port */
-#define XIO3130_REVISION                0x1
-#define XIO3130_MSI_OFFSET              0x70
-#define XIO3130_MSI_SUPPORTED_FLAGS     PCI_MSI_FLAGS_64BIT
-#define XIO3130_MSI_NR_VECTOR           1
-#define XIO3130_SSVID_OFFSET            0x80
-#define XIO3130_SSVID_SVID              0
-#define XIO3130_SSVID_SSID              0
-#define XIO3130_EXP_OFFSET              0x90
-#define XIO3130_AER_OFFSET              0x100
-
-static void xio3130_downstream_write_config(PCIDevice *d, uint32_t address,
-                                         uint32_t val, int len)
-{
-    pci_bridge_write_config(d, address, val, len);
-    pcie_cap_flr_write_config(d, address, val, len);
-    pcie_cap_slot_write_config(d, address, val, len);
-    pcie_aer_write_config(d, address, val, len);
-}
-
-static void xio3130_downstream_reset(DeviceState *qdev)
-{
-    PCIDevice *d = PCI_DEVICE(qdev);
-
-    pcie_cap_deverr_reset(d);
-    pcie_cap_slot_reset(d);
-    pcie_cap_ari_reset(d);
-    pci_bridge_reset(qdev);
-}
-
-static int xio3130_downstream_initfn(PCIDevice *d)
-{
-    PCIBridge* br = DO_UPCAST(PCIBridge, dev, d);
-    PCIEPort *p = DO_UPCAST(PCIEPort, br, br);
-    PCIESlot *s = DO_UPCAST(PCIESlot, port, p);
-    int rc;
-
-    rc = pci_bridge_initfn(d, TYPE_PCIE_BUS);
-    if (rc < 0) {
-        return rc;
-    }
-
-    pcie_port_init_reg(d);
-
-    rc = msi_init(d, XIO3130_MSI_OFFSET, XIO3130_MSI_NR_VECTOR,
-                  XIO3130_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_64BIT,
-                  XIO3130_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_MASKBIT);
-    if (rc < 0) {
-        goto err_bridge;
-    }
-    rc = pci_bridge_ssvid_init(d, XIO3130_SSVID_OFFSET,
-                               XIO3130_SSVID_SVID, XIO3130_SSVID_SSID);
-    if (rc < 0) {
-        goto err_bridge;
-    }
-    rc = pcie_cap_init(d, XIO3130_EXP_OFFSET, PCI_EXP_TYPE_DOWNSTREAM,
-                       p->port);
-    if (rc < 0) {
-        goto err_msi;
-    }
-    pcie_cap_flr_init(d);
-    pcie_cap_deverr_init(d);
-    pcie_cap_slot_init(d, s->slot);
-    pcie_chassis_create(s->chassis);
-    rc = pcie_chassis_add_slot(s);
-    if (rc < 0) {
-        goto err_pcie_cap;
-    }
-    pcie_cap_ari_init(d);
-    rc = pcie_aer_init(d, XIO3130_AER_OFFSET);
-    if (rc < 0) {
-        goto err;
-    }
-
-    return 0;
-
-err:
-    pcie_chassis_del_slot(s);
-err_pcie_cap:
-    pcie_cap_exit(d);
-err_msi:
-    msi_uninit(d);
-err_bridge:
-    pci_bridge_exitfn(d);
-    return rc;
-}
-
-static void xio3130_downstream_exitfn(PCIDevice *d)
-{
-    PCIBridge* br = DO_UPCAST(PCIBridge, dev, d);
-    PCIEPort *p = DO_UPCAST(PCIEPort, br, br);
-    PCIESlot *s = DO_UPCAST(PCIESlot, port, p);
-
-    pcie_aer_exit(d);
-    pcie_chassis_del_slot(s);
-    pcie_cap_exit(d);
-    msi_uninit(d);
-    pci_bridge_exitfn(d);
-}
-
-PCIESlot *xio3130_downstream_init(PCIBus *bus, int devfn, bool multifunction,
-                                  const char *bus_name, pci_map_irq_fn map_irq,
-                                  uint8_t port, uint8_t chassis,
-                                  uint16_t slot)
-{
-    PCIDevice *d;
-    PCIBridge *br;
-    DeviceState *qdev;
-
-    d = pci_create_multifunction(bus, devfn, multifunction,
-                                 "xio3130-downstream");
-    if (!d) {
-        return NULL;
-    }
-    br = DO_UPCAST(PCIBridge, dev, d);
-
-    qdev = &br->dev.qdev;
-    pci_bridge_map_irq(br, bus_name, map_irq);
-    qdev_prop_set_uint8(qdev, "port", port);
-    qdev_prop_set_uint8(qdev, "chassis", chassis);
-    qdev_prop_set_uint16(qdev, "slot", slot);
-    qdev_init_nofail(qdev);
-
-    return DO_UPCAST(PCIESlot, port, DO_UPCAST(PCIEPort, br, br));
-}
-
-static const VMStateDescription vmstate_xio3130_downstream = {
-    .name = "xio3130-express-downstream-port",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .post_load = pcie_cap_slot_post_load,
-    .fields = (VMStateField[]) {
-        VMSTATE_PCIE_DEVICE(port.br.dev, PCIESlot),
-        VMSTATE_STRUCT(port.br.dev.exp.aer_log, PCIESlot, 0,
-                       vmstate_pcie_aer_log, PCIEAERLog),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static Property xio3130_downstream_properties[] = {
-    DEFINE_PROP_UINT8("port", PCIESlot, port.port, 0),
-    DEFINE_PROP_UINT8("chassis", PCIESlot, chassis, 0),
-    DEFINE_PROP_UINT16("slot", PCIESlot, slot, 0),
-    DEFINE_PROP_UINT16("aer_log_max", PCIESlot,
-    port.br.dev.exp.aer_log.log_max,
-    PCIE_AER_LOG_MAX_DEFAULT),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void xio3130_downstream_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
-    k->is_express = 1;
-    k->is_bridge = 1;
-    k->config_write = xio3130_downstream_write_config;
-    k->init = xio3130_downstream_initfn;
-    k->exit = xio3130_downstream_exitfn;
-    k->vendor_id = PCI_VENDOR_ID_TI;
-    k->device_id = PCI_DEVICE_ID_TI_XIO3130D;
-    k->revision = XIO3130_REVISION;
-    dc->desc = "TI X3130 Downstream Port of PCI Express Switch";
-    dc->reset = xio3130_downstream_reset;
-    dc->vmsd = &vmstate_xio3130_downstream;
-    dc->props = xio3130_downstream_properties;
-}
-
-static const 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_types(void)
-{
-    type_register_static(&xio3130_downstream_info);
-}
-
-type_init(xio3130_downstream_register_types)
-
-/*
- * Local variables:
- *  c-indent-level: 4
- *  c-basic-offset: 4
- *  tab-width: 8
- *  indent-tab-mode: nil
- * End:
- */
diff --git a/hw/xio3130_downstream.h b/hw/xio3130_downstream.h
deleted file mode 100644 (file)
index 8426d9f..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-#ifndef QEMU_XIO3130_DOWNSTREAM_H
-#define QEMU_XIO3130_DOWNSTREAM_H
-
-#include "hw/pci/pcie_port.h"
-
-PCIESlot *xio3130_downstream_init(PCIBus *bus, int devfn, bool multifunction,
-                                  const char *bus_name, pci_map_irq_fn map_irq,
-                                  uint8_t port, uint8_t chassis,
-                                  uint16_t slot);
-
-#endif /* QEMU_XIO3130_DOWNSTREAM_H */
diff --git a/hw/xio3130_upstream.c b/hw/xio3130_upstream.c
deleted file mode 100644 (file)
index cd5d97d..0000000
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
- * xio3130_upstream.c
- * TI X3130 pci express upstream port switch
- *
- * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
- *                    VA Linux Systems Japan K.K.
- *
- * 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 "hw/pci/pci_ids.h"
-#include "hw/pci/msi.h"
-#include "hw/pci/pcie.h"
-#include "hw/xio3130_upstream.h"
-
-#define PCI_DEVICE_ID_TI_XIO3130U       0x8232  /* upstream port */
-#define XIO3130_REVISION                0x2
-#define XIO3130_MSI_OFFSET              0x70
-#define XIO3130_MSI_SUPPORTED_FLAGS     PCI_MSI_FLAGS_64BIT
-#define XIO3130_MSI_NR_VECTOR           1
-#define XIO3130_SSVID_OFFSET            0x80
-#define XIO3130_SSVID_SVID              0
-#define XIO3130_SSVID_SSID              0
-#define XIO3130_EXP_OFFSET              0x90
-#define XIO3130_AER_OFFSET              0x100
-
-static void xio3130_upstream_write_config(PCIDevice *d, uint32_t address,
-                                          uint32_t val, int len)
-{
-    pci_bridge_write_config(d, address, val, len);
-    pcie_cap_flr_write_config(d, address, val, len);
-    pcie_aer_write_config(d, address, val, len);
-}
-
-static void xio3130_upstream_reset(DeviceState *qdev)
-{
-    PCIDevice *d = PCI_DEVICE(qdev);
-
-    pci_bridge_reset(qdev);
-    pcie_cap_deverr_reset(d);
-}
-
-static int xio3130_upstream_initfn(PCIDevice *d)
-{
-    PCIBridge* br = DO_UPCAST(PCIBridge, dev, d);
-    PCIEPort *p = DO_UPCAST(PCIEPort, br, br);
-    int rc;
-
-    rc = pci_bridge_initfn(d, TYPE_PCIE_BUS);
-    if (rc < 0) {
-        return rc;
-    }
-
-    pcie_port_init_reg(d);
-
-    rc = msi_init(d, XIO3130_MSI_OFFSET, XIO3130_MSI_NR_VECTOR,
-                  XIO3130_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_64BIT,
-                  XIO3130_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_MASKBIT);
-    if (rc < 0) {
-        goto err_bridge;
-    }
-    rc = pci_bridge_ssvid_init(d, XIO3130_SSVID_OFFSET,
-                               XIO3130_SSVID_SVID, XIO3130_SSVID_SSID);
-    if (rc < 0) {
-        goto err_bridge;
-    }
-    rc = pcie_cap_init(d, XIO3130_EXP_OFFSET, PCI_EXP_TYPE_UPSTREAM,
-                       p->port);
-    if (rc < 0) {
-        goto err_msi;
-    }
-    pcie_cap_flr_init(d);
-    pcie_cap_deverr_init(d);
-    rc = pcie_aer_init(d, XIO3130_AER_OFFSET);
-    if (rc < 0) {
-        goto err;
-    }
-
-    return 0;
-
-err:
-    pcie_cap_exit(d);
-err_msi:
-    msi_uninit(d);
-err_bridge:
-    pci_bridge_exitfn(d);
-    return rc;
-}
-
-static void xio3130_upstream_exitfn(PCIDevice *d)
-{
-    pcie_aer_exit(d);
-    pcie_cap_exit(d);
-    msi_uninit(d);
-    pci_bridge_exitfn(d);
-}
-
-PCIEPort *xio3130_upstream_init(PCIBus *bus, int devfn, bool multifunction,
-                             const char *bus_name, pci_map_irq_fn map_irq,
-                             uint8_t port)
-{
-    PCIDevice *d;
-    PCIBridge *br;
-    DeviceState *qdev;
-
-    d = pci_create_multifunction(bus, devfn, multifunction, "x3130-upstream");
-    if (!d) {
-        return NULL;
-    }
-    br = DO_UPCAST(PCIBridge, dev, d);
-
-    qdev = &br->dev.qdev;
-    pci_bridge_map_irq(br, bus_name, map_irq);
-    qdev_prop_set_uint8(qdev, "port", port);
-    qdev_init_nofail(qdev);
-
-    return DO_UPCAST(PCIEPort, br, br);
-}
-
-static const VMStateDescription vmstate_xio3130_upstream = {
-    .name = "xio3130-express-upstream-port",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_PCIE_DEVICE(br.dev, PCIEPort),
-        VMSTATE_STRUCT(br.dev.exp.aer_log, PCIEPort, 0, vmstate_pcie_aer_log,
-                       PCIEAERLog),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static Property xio3130_upstream_properties[] = {
-    DEFINE_PROP_UINT8("port", PCIEPort, port, 0),
-    DEFINE_PROP_UINT16("aer_log_max", PCIEPort, br.dev.exp.aer_log.log_max,
-    PCIE_AER_LOG_MAX_DEFAULT),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void xio3130_upstream_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
-    k->is_express = 1;
-    k->is_bridge = 1;
-    k->config_write = xio3130_upstream_write_config;
-    k->init = xio3130_upstream_initfn;
-    k->exit = xio3130_upstream_exitfn;
-    k->vendor_id = PCI_VENDOR_ID_TI;
-    k->device_id = PCI_DEVICE_ID_TI_XIO3130U;
-    k->revision = XIO3130_REVISION;
-    dc->desc = "TI X3130 Upstream Port of PCI Express Switch";
-    dc->reset = xio3130_upstream_reset;
-    dc->vmsd = &vmstate_xio3130_upstream;
-    dc->props = xio3130_upstream_properties;
-}
-
-static const 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_types(void)
-{
-    type_register_static(&xio3130_upstream_info);
-}
-
-type_init(xio3130_upstream_register_types)
-
-
-/*
- * Local variables:
- *  c-indent-level: 4
- *  c-basic-offset: 4
- *  tab-width: 8
- *  indent-tab-mode: nil
- * End:
- */
diff --git a/hw/xio3130_upstream.h b/hw/xio3130_upstream.h
deleted file mode 100644 (file)
index 08c1d5f..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef QEMU_XIO3130_UPSTREAM_H
-#define QEMU_XIO3130_UPSTREAM_H
-
-#include "hw/pci/pcie_port.h"
-
-PCIEPort *xio3130_upstream_init(PCIBus *bus, int devfn, bool multifunction,
-                                const char *bus_name, pci_map_irq_fn map_irq,
-                                uint8_t port);
-
-#endif /* QEMU_XIO3130_H */
diff --git a/hw/xtensa/xtensa_bootparam.h b/hw/xtensa/xtensa_bootparam.h
new file mode 100644 (file)
index 0000000..38ef32b
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef HW_XTENSA_BOOTPARAM
+#define HW_XTENSA_BOOTPARAM
+
+typedef struct BpTag {
+    uint16_t tag;
+    uint16_t size;
+} BpTag;
+
+static inline ram_addr_t put_tag(ram_addr_t addr, uint16_t tag,
+        size_t size, const void *data)
+{
+    BpTag bp_tag = {
+        .tag = tswap16(tag),
+        .size = tswap16((size + 3) & ~3),
+    };
+
+    cpu_physical_memory_write(addr, &bp_tag, sizeof(bp_tag));
+    addr += sizeof(bp_tag);
+    cpu_physical_memory_write(addr, data, size);
+    addr += (size + 3) & ~3;
+
+    return addr;
+}
+
+#endif
index f2a63d82da4b46b34c3aea584a9846818e5205b2..2682eda2ad8728b17de9c24f367d8b95afd8e37e 100644 (file)
 #include "elf.h"
 #include "exec/memory.h"
 #include "exec/address-spaces.h"
-#include "hw/serial.h"
+#include "hw/char/serial.h"
 #include "net/net.h"
 #include "hw/sysbus.h"
-#include "hw/flash.h"
+#include "hw/block/flash.h"
 #include "sysemu/blockdev.h"
 #include "char/char.h"
-#include "hw/xtensa_bootparam.h"
+#include "xtensa_bootparam.h"
 
 typedef struct LxBoardDesc {
     size_t flash_size;
diff --git a/hw/xtensa_bootparam.h b/hw/xtensa_bootparam.h
deleted file mode 100644 (file)
index 38ef32b..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-#ifndef HW_XTENSA_BOOTPARAM
-#define HW_XTENSA_BOOTPARAM
-
-typedef struct BpTag {
-    uint16_t tag;
-    uint16_t size;
-} BpTag;
-
-static inline ram_addr_t put_tag(ram_addr_t addr, uint16_t tag,
-        size_t size, const void *data)
-{
-    BpTag bp_tag = {
-        .tag = tswap16(tag),
-        .size = tswap16((size + 3) & ~3),
-    };
-
-    cpu_physical_memory_write(addr, &bp_tag, sizeof(bp_tag));
-    addr += sizeof(bp_tag);
-    cpu_physical_memory_write(addr, data, size);
-    addr += (size + 3) & ~3;
-
-    return addr;
-}
-
-#endif
diff --git a/hw/zaurus.c b/hw/zaurus.c
deleted file mode 100644 (file)
index 7d3258c..0000000
+++ /dev/null
@@ -1,292 +0,0 @@
-/*
- * Copyright (c) 2006-2008 Openedhand Ltd.
- * Written by Andrzej Zaborowski <balrog@zabor.org>
- *
- * 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 or
- * (at your option) version 3 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
- * 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 "hw/hw.h"
-#include "hw/sharpsl.h"
-#include "hw/sysbus.h"
-
-#undef REG_FMT
-#define REG_FMT                        "0x%02lx"
-
-/* SCOOP devices */
-
-typedef struct ScoopInfo ScoopInfo;
-struct ScoopInfo {
-    SysBusDevice busdev;
-    qemu_irq handler[16];
-    MemoryRegion iomem;
-    uint16_t status;
-    uint16_t power;
-    uint32_t gpio_level;
-    uint32_t gpio_dir;
-    uint32_t prev_level;
-
-    uint16_t mcr;
-    uint16_t cdr;
-    uint16_t ccr;
-    uint16_t irr;
-    uint16_t imr;
-    uint16_t isr;
-};
-
-#define SCOOP_MCR      0x00
-#define SCOOP_CDR      0x04
-#define SCOOP_CSR      0x08
-#define SCOOP_CPR      0x0c
-#define SCOOP_CCR      0x10
-#define SCOOP_IRR_IRM  0x14
-#define SCOOP_IMR      0x18
-#define SCOOP_ISR      0x1c
-#define SCOOP_GPCR     0x20
-#define SCOOP_GPWR     0x24
-#define SCOOP_GPRR     0x28
-
-static inline void scoop_gpio_handler_update(ScoopInfo *s) {
-    uint32_t level, diff;
-    int bit;
-    level = s->gpio_level & s->gpio_dir;
-
-    for (diff = s->prev_level ^ level; diff; diff ^= 1 << bit) {
-        bit = ffs(diff) - 1;
-        qemu_set_irq(s->handler[bit], (level >> bit) & 1);
-    }
-
-    s->prev_level = level;
-}
-
-static uint64_t scoop_read(void *opaque, hwaddr addr,
-                           unsigned size)
-{
-    ScoopInfo *s = (ScoopInfo *) opaque;
-
-    switch (addr & 0x3f) {
-    case SCOOP_MCR:
-        return s->mcr;
-    case SCOOP_CDR:
-        return s->cdr;
-    case SCOOP_CSR:
-        return s->status;
-    case SCOOP_CPR:
-        return s->power;
-    case SCOOP_CCR:
-        return s->ccr;
-    case SCOOP_IRR_IRM:
-        return s->irr;
-    case SCOOP_IMR:
-        return s->imr;
-    case SCOOP_ISR:
-        return s->isr;
-    case SCOOP_GPCR:
-        return s->gpio_dir;
-    case SCOOP_GPWR:
-    case SCOOP_GPRR:
-        return s->gpio_level;
-    default:
-        zaurus_printf("Bad register offset " REG_FMT "\n", (unsigned long)addr);
-    }
-
-    return 0;
-}
-
-static void scoop_write(void *opaque, hwaddr addr,
-                        uint64_t value, unsigned size)
-{
-    ScoopInfo *s = (ScoopInfo *) opaque;
-    value &= 0xffff;
-
-    switch (addr & 0x3f) {
-    case SCOOP_MCR:
-        s->mcr = value;
-        break;
-    case SCOOP_CDR:
-        s->cdr = value;
-        break;
-    case SCOOP_CPR:
-        s->power = value;
-        if (value & 0x80)
-            s->power |= 0x8040;
-        break;
-    case SCOOP_CCR:
-        s->ccr = value;
-        break;
-    case SCOOP_IRR_IRM:
-        s->irr = value;
-        break;
-    case SCOOP_IMR:
-        s->imr = value;
-        break;
-    case SCOOP_ISR:
-        s->isr = value;
-        break;
-    case SCOOP_GPCR:
-        s->gpio_dir = value;
-        scoop_gpio_handler_update(s);
-        break;
-    case SCOOP_GPWR:
-    case SCOOP_GPRR:   /* GPRR is probably R/O in real HW */
-        s->gpio_level = value & s->gpio_dir;
-        scoop_gpio_handler_update(s);
-        break;
-    default:
-        zaurus_printf("Bad register offset " REG_FMT "\n", (unsigned long)addr);
-    }
-}
-
-static const MemoryRegionOps scoop_ops = {
-    .read = scoop_read,
-    .write = scoop_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void scoop_gpio_set(void *opaque, int line, int level)
-{
-    ScoopInfo *s = (ScoopInfo *) opaque;
-
-    if (level)
-        s->gpio_level |= (1 << line);
-    else
-        s->gpio_level &= ~(1 << line);
-}
-
-static int scoop_init(SysBusDevice *dev)
-{
-    ScoopInfo *s = FROM_SYSBUS(ScoopInfo, dev);
-
-    s->status = 0x02;
-    qdev_init_gpio_out(&s->busdev.qdev, s->handler, 16);
-    qdev_init_gpio_in(&s->busdev.qdev, scoop_gpio_set, 16);
-    memory_region_init_io(&s->iomem, &scoop_ops, s, "scoop", 0x1000);
-
-    sysbus_init_mmio(dev, &s->iomem);
-
-    return 0;
-}
-
-static int scoop_post_load(void *opaque, int version_id)
-{
-    ScoopInfo *s = (ScoopInfo *) opaque;
-    int i;
-    uint32_t level;
-
-    level = s->gpio_level & s->gpio_dir;
-
-    for (i = 0; i < 16; i++) {
-        qemu_set_irq(s->handler[i], (level >> i) & 1);
-    }
-
-    s->prev_level = level;
-
-    return 0;
-}
-
-static bool is_version_0 (void *opaque, int version_id)
-{
-    return version_id == 0;
-}
-
-static const VMStateDescription vmstate_scoop_regs = {
-    .name = "scoop",
-    .version_id = 1,
-    .minimum_version_id = 0,
-    .minimum_version_id_old = 0,
-    .post_load = scoop_post_load,
-    .fields = (VMStateField []) {
-        VMSTATE_UINT16(status, ScoopInfo),
-        VMSTATE_UINT16(power, ScoopInfo),
-        VMSTATE_UINT32(gpio_level, ScoopInfo),
-        VMSTATE_UINT32(gpio_dir, ScoopInfo),
-        VMSTATE_UINT32(prev_level, ScoopInfo),
-        VMSTATE_UINT16(mcr, ScoopInfo),
-        VMSTATE_UINT16(cdr, ScoopInfo),
-        VMSTATE_UINT16(ccr, ScoopInfo),
-        VMSTATE_UINT16(irr, ScoopInfo),
-        VMSTATE_UINT16(imr, ScoopInfo),
-        VMSTATE_UINT16(isr, ScoopInfo),
-        VMSTATE_UNUSED_TEST(is_version_0, 2),
-        VMSTATE_END_OF_LIST(),
-    },
-};
-
-static Property scoop_sysbus_properties[] = {
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void scoop_sysbus_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = scoop_init;
-    dc->desc = "Scoop2 Sharp custom ASIC";
-    dc->vmsd = &vmstate_scoop_regs;
-    dc->props = scoop_sysbus_properties;
-}
-
-static const 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_types(void)
-{
-    type_register_static(&scoop_sysbus_info);
-}
-
-type_init(scoop_register_types)
-
-/* Write the bootloader parameters memory area.  */
-
-#define MAGIC_CHG(a, b, c, d)  ((d << 24) | (c << 16) | (b << 8) | a)
-
-static struct QEMU_PACKED sl_param_info {
-    uint32_t comadj_keyword;
-    int32_t comadj;
-
-    uint32_t uuid_keyword;
-    char uuid[16];
-
-    uint32_t touch_keyword;
-    int32_t touch_xp;
-    int32_t touch_yp;
-    int32_t touch_xd;
-    int32_t touch_yd;
-
-    uint32_t adadj_keyword;
-    int32_t adadj;
-
-    uint32_t phad_keyword;
-    int32_t phadadj;
-} zaurus_bootparam = {
-    .comadj_keyword    = MAGIC_CHG('C', 'M', 'A', 'D'),
-    .comadj            = 125,
-    .uuid_keyword      = MAGIC_CHG('U', 'U', 'I', 'D'),
-    .uuid              = { -1 },
-    .touch_keyword     = MAGIC_CHG('T', 'U', 'C', 'H'),
-    .touch_xp          = -1,
-    .adadj_keyword     = MAGIC_CHG('B', 'V', 'A', 'D'),
-    .adadj             = -1,
-    .phad_keyword      = MAGIC_CHG('P', 'H', 'A', 'D'),
-    .phadadj           = 0x01,
-};
-
-void sl_bootparam_write(hwaddr ptr)
-{
-    cpu_physical_memory_write(ptr, (void *)&zaurus_bootparam,
-                              sizeof(struct sl_param_info));
-}
diff --git a/hw/zynq_slcr.c b/hw/zynq_slcr.c
deleted file mode 100644 (file)
index 8418327..0000000
+++ /dev/null
@@ -1,536 +0,0 @@
-/*
- * Status and system control registers for Xilinx Zynq Platform
- *
- * Copyright (c) 2011 Michal Simek <monstr@monstr.eu>
- * Copyright (c) 2012 PetaLogix Pty Ltd.
- * Based on hw/arm_sysctl.c, written by Paul Brook
- *
- * 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.
- *
- * 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 "hw/hw.h"
-#include "qemu/timer.h"
-#include "hw/sysbus.h"
-#include "sysemu/sysemu.h"
-
-#ifdef ZYNQ_ARM_SLCR_ERR_DEBUG
-#define DB_PRINT(...) do { \
-    fprintf(stderr,  ": %s: ", __func__); \
-    fprintf(stderr, ## __VA_ARGS__); \
-    } while (0);
-#else
-    #define DB_PRINT(...)
-#endif
-
-#define XILINX_LOCK_KEY 0x767b
-#define XILINX_UNLOCK_KEY 0xdf0d
-
-typedef enum {
-  ARM_PLL_CTRL,
-  DDR_PLL_CTRL,
-  IO_PLL_CTRL,
-  PLL_STATUS,
-  ARM_PPL_CFG,
-  DDR_PLL_CFG,
-  IO_PLL_CFG,
-  PLL_BG_CTRL,
-  PLL_MAX
-} PLLValues;
-
-typedef enum {
-  ARM_CLK_CTRL,
-  DDR_CLK_CTRL,
-  DCI_CLK_CTRL,
-  APER_CLK_CTRL,
-  USB0_CLK_CTRL,
-  USB1_CLK_CTRL,
-  GEM0_RCLK_CTRL,
-  GEM1_RCLK_CTRL,
-  GEM0_CLK_CTRL,
-  GEM1_CLK_CTRL,
-  SMC_CLK_CTRL,
-  LQSPI_CLK_CTRL,
-  SDIO_CLK_CTRL,
-  UART_CLK_CTRL,
-  SPI_CLK_CTRL,
-  CAN_CLK_CTRL,
-  CAN_MIOCLK_CTRL,
-  DBG_CLK_CTRL,
-  PCAP_CLK_CTRL,
-  TOPSW_CLK_CTRL,
-  CLK_MAX
-} ClkValues;
-
-typedef enum {
-  CLK_CTRL,
-  THR_CTRL,
-  THR_CNT,
-  THR_STA,
-  FPGA_MAX
-} FPGAValues;
-
-typedef enum {
-  SYNC_CTRL,
-  SYNC_STATUS,
-  BANDGAP_TRIP,
-  CC_TEST,
-  PLL_PREDIVISOR,
-  CLK_621_TRUE,
-  PICTURE_DBG,
-  PICTURE_DBG_UCNT,
-  PICTURE_DBG_LCNT,
-  MISC_MAX
-} MiscValues;
-
-typedef enum {
-  PSS,
-  DDDR,
-  DMAC = 3,
-  USB,
-  GEM,
-  SDIO,
-  SPI,
-  CAN,
-  I2C,
-  UART,
-  GPIO,
-  LQSPI,
-  SMC,
-  OCM,
-  DEVCI,
-  FPGA,
-  A9_CPU,
-  RS_AWDT,
-  RST_REASON,
-  RST_REASON_CLR,
-  REBOOT_STATUS,
-  BOOT_MODE,
-  RESET_MAX
-} ResetValues;
-
-typedef struct {
-    SysBusDevice busdev;
-    MemoryRegion iomem;
-
-    union {
-        struct {
-            uint16_t scl;
-            uint16_t lockval;
-            uint32_t pll[PLL_MAX]; /* 0x100 - 0x11C */
-            uint32_t clk[CLK_MAX]; /* 0x120 - 0x16C */
-            uint32_t fpga[4][FPGA_MAX]; /* 0x170 - 0x1AC */
-            uint32_t misc[MISC_MAX]; /* 0x1B0 - 0x1D8 */
-            uint32_t reset[RESET_MAX]; /* 0x200 - 0x25C */
-            uint32_t apu_ctrl; /* 0x300 */
-            uint32_t wdt_clk_sel; /* 0x304 */
-            uint32_t tz_ocm[3]; /* 0x400 - 0x408 */
-            uint32_t tz_ddr; /* 0x430 */
-            uint32_t tz_dma[3]; /* 0x440 - 0x448 */
-            uint32_t tz_misc[3]; /* 0x450 - 0x458 */
-            uint32_t tz_fpga[2]; /* 0x484 - 0x488 */
-            uint32_t dbg_ctrl; /* 0x500 */
-            uint32_t pss_idcode; /* 0x530 */
-            uint32_t ddr[8]; /* 0x600 - 0x620 - 0x604-missing */
-            uint32_t mio[54]; /* 0x700 - 0x7D4 */
-            uint32_t mio_func[4]; /* 0x800 - 0x810 */
-            uint32_t sd[2]; /* 0x830 - 0x834 */
-            uint32_t lvl_shftr_en; /* 0x900 */
-            uint32_t ocm_cfg; /* 0x910 */
-            uint32_t cpu_ram[8]; /* 0xA00 - 0xA1C */
-            uint32_t iou[7]; /* 0xA30 - 0xA48 */
-            uint32_t dmac_ram; /* 0xA50 */
-            uint32_t afi[4][3]; /* 0xA60 - 0xA8C */
-            uint32_t ocm[3]; /* 0xA90 - 0xA98 */
-            uint32_t devci_ram; /* 0xAA0 */
-            uint32_t csg_ram; /* 0xAB0 */
-            uint32_t gpiob[12]; /* 0xB00 - 0xB2C */
-            uint32_t ddriob[14]; /* 0xB40 - 0xB74 */
-        };
-        uint8_t data[0x1000];
-    };
-} ZynqSLCRState;
-
-static void zynq_slcr_reset(DeviceState *d)
-{
-    int i;
-    ZynqSLCRState *s =
-            FROM_SYSBUS(ZynqSLCRState, SYS_BUS_DEVICE(d));
-
-    DB_PRINT("RESET\n");
-
-    s->lockval = 1;
-    /* 0x100 - 0x11C */
-    s->pll[ARM_PLL_CTRL] = 0x0001A008;
-    s->pll[DDR_PLL_CTRL] = 0x0001A008;
-    s->pll[IO_PLL_CTRL] = 0x0001A008;
-    s->pll[PLL_STATUS] = 0x0000003F;
-    s->pll[ARM_PPL_CFG] = 0x00014000;
-    s->pll[DDR_PLL_CFG] = 0x00014000;
-    s->pll[IO_PLL_CFG] = 0x00014000;
-
-    /* 0x120 - 0x16C */
-    s->clk[ARM_CLK_CTRL] = 0x1F000400;
-    s->clk[DDR_CLK_CTRL] = 0x18400003;
-    s->clk[DCI_CLK_CTRL] = 0x01E03201;
-    s->clk[APER_CLK_CTRL] = 0x01FFCCCD;
-    s->clk[USB0_CLK_CTRL] = s->clk[USB1_CLK_CTRL] = 0x00101941;
-    s->clk[GEM0_RCLK_CTRL] = s->clk[GEM1_RCLK_CTRL] = 0x00000001;
-    s->clk[GEM0_CLK_CTRL] = s->clk[GEM1_CLK_CTRL] = 0x00003C01;
-    s->clk[SMC_CLK_CTRL] = 0x00003C01;
-    s->clk[LQSPI_CLK_CTRL] = 0x00002821;
-    s->clk[SDIO_CLK_CTRL] = 0x00001E03;
-    s->clk[UART_CLK_CTRL] = 0x00003F03;
-    s->clk[SPI_CLK_CTRL] = 0x00003F03;
-    s->clk[CAN_CLK_CTRL] = 0x00501903;
-    s->clk[DBG_CLK_CTRL] = 0x00000F03;
-    s->clk[PCAP_CLK_CTRL] = 0x00000F01;
-
-    /* 0x170 - 0x1AC */
-    s->fpga[0][CLK_CTRL] = s->fpga[1][CLK_CTRL] = s->fpga[2][CLK_CTRL] =
-            s->fpga[3][CLK_CTRL] = 0x00101800;
-    s->fpga[0][THR_STA] = s->fpga[1][THR_STA] = s->fpga[2][THR_STA] =
-            s->fpga[3][THR_STA] = 0x00010000;
-
-    /* 0x1B0 - 0x1D8 */
-    s->misc[BANDGAP_TRIP] = 0x0000001F;
-    s->misc[PLL_PREDIVISOR] = 0x00000001;
-    s->misc[CLK_621_TRUE] = 0x00000001;
-
-    /* 0x200 - 0x25C */
-    s->reset[FPGA] = 0x01F33F0F;
-    s->reset[RST_REASON] = 0x00000040;
-
-    /* 0x700 - 0x7D4 */
-    for (i = 0; i < 54; i++) {
-        s->mio[i] = 0x00001601;
-    }
-    for (i = 2; i <= 8; i++) {
-        s->mio[i] = 0x00000601;
-    }
-
-    /* MIO_MST_TRI0, MIO_MST_TRI1 */
-    s->mio_func[2] = s->mio_func[3] = 0xFFFFFFFF;
-
-    s->cpu_ram[0] = s->cpu_ram[1] = s->cpu_ram[3] =
-            s->cpu_ram[4] = s->cpu_ram[7] = 0x00010101;
-    s->cpu_ram[2] = s->cpu_ram[5] = 0x01010101;
-    s->cpu_ram[6] = 0x00000001;
-
-    s->iou[0] = s->iou[1] = s->iou[2] = s->iou[3] = 0x09090909;
-    s->iou[4] = s->iou[5] = 0x00090909;
-    s->iou[6] = 0x00000909;
-
-    s->dmac_ram = 0x00000009;
-
-    s->afi[0][0] = s->afi[0][1] = 0x09090909;
-    s->afi[1][0] = s->afi[1][1] = 0x09090909;
-    s->afi[2][0] = s->afi[2][1] = 0x09090909;
-    s->afi[3][0] = s->afi[3][1] = 0x09090909;
-    s->afi[0][2] = s->afi[1][2] = s->afi[2][2] = s->afi[3][2] = 0x00000909;
-
-    s->ocm[0] = 0x01010101;
-    s->ocm[1] = s->ocm[2] = 0x09090909;
-
-    s->devci_ram = 0x00000909;
-    s->csg_ram = 0x00000001;
-
-    s->ddriob[0] = s->ddriob[1] = s->ddriob[2] = s->ddriob[3] = 0x00000e00;
-    s->ddriob[4] = s->ddriob[5] = s->ddriob[6] = 0x00000e00;
-    s->ddriob[12] = 0x00000021;
-}
-
-static inline uint32_t zynq_slcr_read_imp(void *opaque,
-    hwaddr offset)
-{
-    ZynqSLCRState *s = (ZynqSLCRState *)opaque;
-
-    switch (offset) {
-    case 0x0: /* SCL */
-        return s->scl;
-    case 0x4: /* LOCK */
-    case 0x8: /* UNLOCK */
-        DB_PRINT("Reading SCLR_LOCK/UNLOCK is not enabled\n");
-        return 0;
-    case 0x0C: /* LOCKSTA */
-        return s->lockval;
-    case 0x100 ... 0x11C:
-        return s->pll[(offset - 0x100) / 4];
-    case 0x120 ... 0x16C:
-        return s->clk[(offset - 0x120) / 4];
-    case 0x170 ... 0x1AC:
-        return s->fpga[0][(offset - 0x170) / 4];
-    case 0x1B0 ... 0x1D8:
-        return s->misc[(offset - 0x1B0) / 4];
-    case 0x200 ... 0x258:
-        return s->reset[(offset - 0x200) / 4];
-    case 0x25c:
-        return 1;
-    case 0x300:
-        return s->apu_ctrl;
-    case 0x304:
-        return s->wdt_clk_sel;
-    case 0x400 ... 0x408:
-        return s->tz_ocm[(offset - 0x400) / 4];
-    case 0x430:
-        return s->tz_ddr;
-    case 0x440 ... 0x448:
-        return s->tz_dma[(offset - 0x440) / 4];
-    case 0x450 ... 0x458:
-        return s->tz_misc[(offset - 0x450) / 4];
-    case 0x484 ... 0x488:
-        return s->tz_fpga[(offset - 0x484) / 4];
-    case 0x500:
-        return s->dbg_ctrl;
-    case 0x530:
-        return s->pss_idcode;
-    case 0x600 ... 0x620:
-        if (offset == 0x604) {
-            goto bad_reg;
-        }
-        return s->ddr[(offset - 0x600) / 4];
-    case 0x700 ... 0x7D4:
-        return s->mio[(offset - 0x700) / 4];
-    case 0x800 ... 0x810:
-        return s->mio_func[(offset - 0x800) / 4];
-    case 0x830 ... 0x834:
-        return s->sd[(offset - 0x830) / 4];
-    case 0x900:
-        return s->lvl_shftr_en;
-    case 0x910:
-        return s->ocm_cfg;
-    case 0xA00 ... 0xA1C:
-        return s->cpu_ram[(offset - 0xA00) / 4];
-    case 0xA30 ... 0xA48:
-        return s->iou[(offset - 0xA30) / 4];
-    case 0xA50:
-        return s->dmac_ram;
-    case 0xA60 ... 0xA8C:
-        return s->afi[0][(offset - 0xA60) / 4];
-    case 0xA90 ... 0xA98:
-        return s->ocm[(offset - 0xA90) / 4];
-    case 0xAA0:
-        return s->devci_ram;
-    case 0xAB0:
-        return s->csg_ram;
-    case 0xB00 ... 0xB2C:
-        return s->gpiob[(offset - 0xB00) / 4];
-    case 0xB40 ... 0xB74:
-        return s->ddriob[(offset - 0xB40) / 4];
-    default:
-    bad_reg:
-        DB_PRINT("Bad register offset 0x%x\n", (int)offset);
-        return 0;
-    }
-}
-
-static uint64_t zynq_slcr_read(void *opaque, hwaddr offset,
-    unsigned size)
-{
-    uint32_t ret = zynq_slcr_read_imp(opaque, offset);
-
-    DB_PRINT("addr: %08x data: %08x\n", (unsigned)offset, (unsigned)ret);
-    return ret;
-}
-
-static void zynq_slcr_write(void *opaque, hwaddr offset,
-                          uint64_t val, unsigned size)
-{
-    ZynqSLCRState *s = (ZynqSLCRState *)opaque;
-
-    DB_PRINT("offset: %08x data: %08x\n", (unsigned)offset, (unsigned)val);
-
-    switch (offset) {
-    case 0x00: /* SCL */
-        s->scl = val & 0x1;
-    return;
-    case 0x4: /* SLCR_LOCK */
-        if ((val & 0xFFFF) == XILINX_LOCK_KEY) {
-            DB_PRINT("XILINX LOCK 0xF8000000 + 0x%x <= 0x%x\n", (int)offset,
-                (unsigned)val & 0xFFFF);
-            s->lockval = 1;
-        } else {
-            DB_PRINT("WRONG XILINX LOCK KEY 0xF8000000 + 0x%x <= 0x%x\n",
-                (int)offset, (unsigned)val & 0xFFFF);
-        }
-        return;
-    case 0x8: /* SLCR_UNLOCK */
-        if ((val & 0xFFFF) == XILINX_UNLOCK_KEY) {
-            DB_PRINT("XILINX UNLOCK 0xF8000000 + 0x%x <= 0x%x\n", (int)offset,
-                (unsigned)val & 0xFFFF);
-            s->lockval = 0;
-        } else {
-            DB_PRINT("WRONG XILINX UNLOCK KEY 0xF8000000 + 0x%x <= 0x%x\n",
-                (int)offset, (unsigned)val & 0xFFFF);
-        }
-        return;
-    case 0xc: /* LOCKSTA */
-        DB_PRINT("Writing SCLR_LOCKSTA is not enabled\n");
-        return;
-    }
-
-    if (!s->lockval) {
-        switch (offset) {
-        case 0x100 ... 0x11C:
-            if (offset == 0x10C) {
-                goto bad_reg;
-            }
-            s->pll[(offset - 0x100) / 4] = val;
-            break;
-        case 0x120 ... 0x16C:
-            s->clk[(offset - 0x120) / 4] = val;
-            break;
-        case 0x170 ... 0x1AC:
-            s->fpga[0][(offset - 0x170) / 4] = val;
-            break;
-        case 0x1B0 ... 0x1D8:
-            s->misc[(offset - 0x1B0) / 4] = val;
-            break;
-        case 0x200 ... 0x25C:
-            if (offset == 0x250) {
-                goto bad_reg;
-            }
-            s->reset[(offset - 0x200) / 4] = val;
-            break;
-        case 0x300:
-            s->apu_ctrl = val;
-            break;
-        case 0x304:
-            s->wdt_clk_sel = val;
-            break;
-        case 0x400 ... 0x408:
-            s->tz_ocm[(offset - 0x400) / 4] = val;
-            break;
-        case 0x430:
-            s->tz_ddr = val;
-            break;
-        case 0x440 ... 0x448:
-            s->tz_dma[(offset - 0x440) / 4] = val;
-            break;
-        case 0x450 ... 0x458:
-            s->tz_misc[(offset - 0x450) / 4] = val;
-            break;
-        case 0x484 ... 0x488:
-            s->tz_fpga[(offset - 0x484) / 4] = val;
-            break;
-        case 0x500:
-            s->dbg_ctrl = val;
-            break;
-        case 0x530:
-            s->pss_idcode = val;
-            break;
-        case 0x600 ... 0x620:
-            if (offset == 0x604) {
-                goto bad_reg;
-            }
-            s->ddr[(offset - 0x600) / 4] = val;
-            break;
-        case 0x700 ... 0x7D4:
-            s->mio[(offset - 0x700) / 4] = val;
-            break;
-        case 0x800 ... 0x810:
-            s->mio_func[(offset - 0x800) / 4] = val;
-            break;
-        case 0x830 ... 0x834:
-            s->sd[(offset - 0x830) / 4] = val;
-            break;
-        case 0x900:
-            s->lvl_shftr_en = val;
-            break;
-        case 0x910:
-            break;
-        case 0xA00 ... 0xA1C:
-            s->cpu_ram[(offset - 0xA00) / 4] = val;
-            break;
-        case 0xA30 ... 0xA48:
-            s->iou[(offset - 0xA30) / 4] = val;
-            break;
-        case 0xA50:
-            s->dmac_ram = val;
-            break;
-        case 0xA60 ... 0xA8C:
-            s->afi[0][(offset - 0xA60) / 4] = val;
-            break;
-        case 0xA90:
-            s->ocm[0] = val;
-            break;
-        case 0xAA0:
-            s->devci_ram = val;
-            break;
-        case 0xAB0:
-            s->csg_ram = val;
-            break;
-        case 0xB00 ... 0xB2C:
-            if (offset == 0xB20 || offset == 0xB2C) {
-                goto bad_reg;
-            }
-            s->gpiob[(offset - 0xB00) / 4] = val;
-            break;
-        case 0xB40 ... 0xB74:
-            s->ddriob[(offset - 0xB40) / 4] = val;
-            break;
-        default:
-        bad_reg:
-            DB_PRINT("Bad register write %x <= %08x\n", (int)offset,
-                     (unsigned)val);
-        }
-    } else {
-        DB_PRINT("SCLR registers are locked. Unlock them first\n");
-    }
-}
-
-static const MemoryRegionOps slcr_ops = {
-    .read = zynq_slcr_read,
-    .write = zynq_slcr_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int zynq_slcr_init(SysBusDevice *dev)
-{
-    ZynqSLCRState *s = FROM_SYSBUS(ZynqSLCRState, dev);
-
-    memory_region_init_io(&s->iomem, &slcr_ops, s, "slcr", 0x1000);
-    sysbus_init_mmio(dev, &s->iomem);
-
-    return 0;
-}
-
-static const VMStateDescription vmstate_zynq_slcr = {
-    .name = "zynq_slcr",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField[]) {
-        VMSTATE_UINT8_ARRAY(data, ZynqSLCRState, 0x1000),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void zynq_slcr_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
-
-    sdc->init = zynq_slcr_init;
-    dc->vmsd = &vmstate_zynq_slcr;
-    dc->reset = zynq_slcr_reset;
-}
-
-static const TypeInfo zynq_slcr_info = {
-    .class_init = zynq_slcr_class_init,
-    .name  = "xilinx,zynq_slcr",
-    .parent = TYPE_SYS_BUS_DEVICE,
-    .instance_size  = sizeof(ZynqSLCRState),
-};
-
-static void zynq_slcr_register_types(void)
-{
-    type_register_static(&zynq_slcr_info);
-}
-
-type_init(zynq_slcr_register_types)
index 0986a2d6ac93cec45d66146cfa9faa2abc104634..9aa98b5d121da991d39c090f25616cde9f5e0501 100644 (file)
@@ -252,11 +252,10 @@ struct BlockDriverState {
     unsigned int copy_on_read_in_flight;
 
     /* the time for latest disk I/O */
-    int64_t slice_time;
     int64_t slice_start;
     int64_t slice_end;
     BlockIOLimit io_limits;
-    BlockIOBaseValue  io_base;
+    BlockIOBaseValue slice_submitted;
     CoQueue      throttled_reqs;
     QEMUTimer    *block_timer;
     bool         io_limits_enabled;
diff --git a/include/block/scsi.h b/include/block/scsi.h
new file mode 100644 (file)
index 0000000..9ab045b
--- /dev/null
@@ -0,0 +1,307 @@
+/* Copyright (C) 1998, 1999 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C 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.1 of the License, or (at your option) any later version.
+
+   The GNU C 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/>.
+*/
+
+/*
+ * This header file contains public constants and structures used by
+ * the scsi code for linux.
+ */
+#ifndef HW_SCSI_DEFS_H
+#define HW_SCSI_DEFS_H 1
+
+/*
+ *      SCSI opcodes
+ */
+
+#define TEST_UNIT_READY       0x00
+#define REWIND                0x01
+#define REQUEST_SENSE         0x03
+#define FORMAT_UNIT           0x04
+#define READ_BLOCK_LIMITS     0x05
+#define INITIALIZE_ELEMENT_STATUS 0x07
+#define REASSIGN_BLOCKS       0x07
+#define READ_6                0x08
+#define WRITE_6               0x0a
+#define SET_CAPACITY          0x0b
+#define READ_REVERSE          0x0f
+#define WRITE_FILEMARKS       0x10
+#define SPACE                 0x11
+#define INQUIRY               0x12
+#define RECOVER_BUFFERED_DATA 0x14
+#define MODE_SELECT           0x15
+#define RESERVE               0x16
+#define RELEASE               0x17
+#define COPY                  0x18
+#define ERASE                 0x19
+#define MODE_SENSE            0x1a
+#define LOAD_UNLOAD           0x1b
+#define START_STOP            0x1b
+#define RECEIVE_DIAGNOSTIC    0x1c
+#define SEND_DIAGNOSTIC       0x1d
+#define ALLOW_MEDIUM_REMOVAL  0x1e
+#define READ_CAPACITY_10      0x25
+#define READ_10               0x28
+#define WRITE_10              0x2a
+#define SEEK_10               0x2b
+#define LOCATE_10             0x2b
+#define POSITION_TO_ELEMENT   0x2b
+#define WRITE_VERIFY_10       0x2e
+#define VERIFY_10             0x2f
+#define SEARCH_HIGH           0x30
+#define SEARCH_EQUAL          0x31
+#define SEARCH_LOW            0x32
+#define SET_LIMITS            0x33
+#define PRE_FETCH             0x34
+#define READ_POSITION         0x34
+#define SYNCHRONIZE_CACHE     0x35
+#define LOCK_UNLOCK_CACHE     0x36
+#define INITIALIZE_ELEMENT_STATUS_WITH_RANGE 0x37
+#define READ_DEFECT_DATA      0x37
+#define MEDIUM_SCAN           0x38
+#define COMPARE               0x39
+#define COPY_VERIFY           0x3a
+#define WRITE_BUFFER          0x3b
+#define READ_BUFFER           0x3c
+#define UPDATE_BLOCK          0x3d
+#define READ_LONG_10          0x3e
+#define WRITE_LONG_10         0x3f
+#define CHANGE_DEFINITION     0x40
+#define WRITE_SAME_10         0x41
+#define UNMAP                 0x42
+#define READ_TOC              0x43
+#define REPORT_DENSITY_SUPPORT 0x44
+#define GET_CONFIGURATION     0x46
+#define SANITIZE              0x48
+#define GET_EVENT_STATUS_NOTIFICATION 0x4a
+#define LOG_SELECT            0x4c
+#define LOG_SENSE             0x4d
+#define READ_DISC_INFORMATION 0x51
+#define RESERVE_TRACK         0x53
+#define MODE_SELECT_10        0x55
+#define RESERVE_10            0x56
+#define RELEASE_10            0x57
+#define MODE_SENSE_10         0x5a
+#define SEND_CUE_SHEET        0x5d
+#define PERSISTENT_RESERVE_IN 0x5e
+#define PERSISTENT_RESERVE_OUT 0x5f
+#define VARLENGTH_CDB         0x7f
+#define WRITE_FILEMARKS_16    0x80
+#define READ_REVERSE_16       0x81
+#define ALLOW_OVERWRITE       0x82
+#define EXTENDED_COPY         0x83
+#define ATA_PASSTHROUGH_16    0x85
+#define ACCESS_CONTROL_IN     0x86
+#define ACCESS_CONTROL_OUT    0x87
+#define READ_16               0x88
+#define COMPARE_AND_WRITE     0x89
+#define WRITE_16              0x8a
+#define WRITE_VERIFY_16       0x8e
+#define VERIFY_16             0x8f
+#define PRE_FETCH_16          0x90
+#define SPACE_16              0x91
+#define SYNCHRONIZE_CACHE_16  0x91
+#define LOCATE_16             0x92
+#define WRITE_SAME_16         0x93
+#define ERASE_16              0x93
+#define SERVICE_ACTION_IN_16  0x9e
+#define WRITE_LONG_16         0x9f
+#define REPORT_LUNS           0xa0
+#define ATA_PASSTHROUGH_12    0xa1
+#define MAINTENANCE_IN        0xa3
+#define MAINTENANCE_OUT       0xa4
+#define MOVE_MEDIUM           0xa5
+#define EXCHANGE_MEDIUM       0xa6
+#define SET_READ_AHEAD        0xa7
+#define READ_12               0xa8
+#define WRITE_12              0xaa
+#define SERVICE_ACTION_IN_12  0xab
+#define ERASE_12              0xac
+#define READ_DVD_STRUCTURE    0xad
+#define WRITE_VERIFY_12       0xae
+#define VERIFY_12             0xaf
+#define SEARCH_HIGH_12        0xb0
+#define SEARCH_EQUAL_12       0xb1
+#define SEARCH_LOW_12         0xb2
+#define READ_ELEMENT_STATUS   0xb8
+#define SEND_VOLUME_TAG       0xb6
+#define READ_DEFECT_DATA_12   0xb7
+#define SET_CD_SPEED          0xbb
+#define MECHANISM_STATUS      0xbd
+#define READ_CD               0xbe
+#define SEND_DVD_STRUCTURE    0xbf
+
+/*
+ * SERVICE ACTION IN subcodes
+ */
+#define SAI_READ_CAPACITY_16  0x10
+
+/*
+ * READ POSITION service action codes
+ */
+#define SHORT_FORM_BLOCK_ID  0x00
+#define SHORT_FORM_VENDOR_SPECIFIC 0x01
+#define LONG_FORM            0x06
+#define EXTENDED_FORM        0x08
+
+/*
+ *  SAM Status codes
+ */
+
+#define GOOD                 0x00
+#define CHECK_CONDITION      0x02
+#define CONDITION_GOOD       0x04
+#define BUSY                 0x08
+#define INTERMEDIATE_GOOD    0x10
+#define INTERMEDIATE_C_GOOD  0x14
+#define RESERVATION_CONFLICT 0x18
+#define COMMAND_TERMINATED   0x22
+#define TASK_SET_FULL        0x28
+#define ACA_ACTIVE           0x30
+#define TASK_ABORTED         0x40
+
+#define STATUS_MASK          0x3e
+
+/*
+ *  SENSE KEYS
+ */
+
+#define NO_SENSE            0x00
+#define RECOVERED_ERROR     0x01
+#define NOT_READY           0x02
+#define MEDIUM_ERROR        0x03
+#define HARDWARE_ERROR      0x04
+#define ILLEGAL_REQUEST     0x05
+#define UNIT_ATTENTION      0x06
+#define DATA_PROTECT        0x07
+#define BLANK_CHECK         0x08
+#define COPY_ABORTED        0x0a
+#define ABORTED_COMMAND     0x0b
+#define VOLUME_OVERFLOW     0x0d
+#define MISCOMPARE          0x0e
+
+
+/*
+ *  DEVICE TYPES
+ */
+
+#define TYPE_DISK           0x00
+#define TYPE_TAPE           0x01
+#define TYPE_PRINTER        0x02
+#define TYPE_PROCESSOR      0x03    /* HP scanners use this */
+#define TYPE_WORM           0x04    /* Treated as ROM by our system */
+#define TYPE_ROM            0x05
+#define TYPE_SCANNER        0x06
+#define TYPE_MOD            0x07    /* Magneto-optical disk -
+                                    * - treated as TYPE_DISK */
+#define TYPE_MEDIUM_CHANGER 0x08
+#define TYPE_STORAGE_ARRAY  0x0c    /* Storage array device */
+#define TYPE_ENCLOSURE      0x0d    /* Enclosure Services Device */
+#define TYPE_RBC            0x0e    /* Simplified Direct-Access Device */
+#define TYPE_OSD            0x11    /* Object-storage Device */
+#define TYPE_WLUN           0x1e    /* Well known LUN */
+#define TYPE_NOT_PRESENT    0x1f
+#define TYPE_INACTIVE       0x20
+#define TYPE_NO_LUN         0x7f
+
+/* Mode page codes for mode sense/set */
+#define MODE_PAGE_R_W_ERROR                   0x01
+#define MODE_PAGE_HD_GEOMETRY                 0x04
+#define MODE_PAGE_FLEXIBLE_DISK_GEOMETRY      0x05
+#define MODE_PAGE_CACHING                     0x08
+#define MODE_PAGE_AUDIO_CTL                   0x0e
+#define MODE_PAGE_POWER                       0x1a
+#define MODE_PAGE_FAULT_FAIL                  0x1c
+#define MODE_PAGE_TO_PROTECT                  0x1d
+#define MODE_PAGE_CAPABILITIES                0x2a
+#define MODE_PAGE_ALLS                        0x3f
+/* Not in Mt. Fuji, but in ATAPI 2.6 -- depricated now in favor
+ * of MODE_PAGE_SENSE_POWER */
+#define MODE_PAGE_CDROM                       0x0d
+
+/* Event notification classes for GET EVENT STATUS NOTIFICATION */
+#define GESN_NO_EVENTS                0
+#define GESN_OPERATIONAL_CHANGE       1
+#define GESN_POWER_MANAGEMENT         2
+#define GESN_EXTERNAL_REQUEST         3
+#define GESN_MEDIA                    4
+#define GESN_MULTIPLE_HOSTS           5
+#define GESN_DEVICE_BUSY              6
+
+/* Event codes for MEDIA event status notification */
+#define MEC_NO_CHANGE                 0
+#define MEC_EJECT_REQUESTED           1
+#define MEC_NEW_MEDIA                 2
+#define MEC_MEDIA_REMOVAL             3 /* only for media changers */
+#define MEC_MEDIA_CHANGED             4 /* only for media changers */
+#define MEC_BG_FORMAT_COMPLETED       5 /* MRW or DVD+RW b/g format completed */
+#define MEC_BG_FORMAT_RESTARTED       6 /* MRW or DVD+RW b/g format restarted */
+
+#define MS_TRAY_OPEN                  1
+#define MS_MEDIA_PRESENT              2
+
+/*
+ * Based on values from <linux/cdrom.h> but extending CD_MINS
+ * to the maximum common size allowed by the Orange's Book ATIP
+ *
+ * 90 and 99 min CDs are also available but using them as the
+ * upper limit reduces the effectiveness of the heuristic to
+ * detect DVDs burned to less than 25% of their maximum capacity
+ */
+
+/* Some generally useful CD-ROM information */
+#define CD_MINS                       80 /* max. minutes per CD */
+#define CD_SECS                       60 /* seconds per minute */
+#define CD_FRAMES                     75 /* frames per second */
+#define CD_FRAMESIZE                2048 /* bytes per frame, "cooked" mode */
+#define CD_MAX_BYTES       (CD_MINS * CD_SECS * CD_FRAMES * CD_FRAMESIZE)
+#define CD_MAX_SECTORS     (CD_MAX_BYTES / 512)
+
+/*
+ * The MMC values are not IDE specific and might need to be moved
+ * to a common header if they are also needed for the SCSI emulation
+ */
+
+/* Profile list from MMC-6 revision 1 table 91 */
+#define MMC_PROFILE_NONE                0x0000
+#define MMC_PROFILE_CD_ROM              0x0008
+#define MMC_PROFILE_CD_R                0x0009
+#define MMC_PROFILE_CD_RW               0x000A
+#define MMC_PROFILE_DVD_ROM             0x0010
+#define MMC_PROFILE_DVD_R_SR            0x0011
+#define MMC_PROFILE_DVD_RAM             0x0012
+#define MMC_PROFILE_DVD_RW_RO           0x0013
+#define MMC_PROFILE_DVD_RW_SR           0x0014
+#define MMC_PROFILE_DVD_R_DL_SR         0x0015
+#define MMC_PROFILE_DVD_R_DL_JR         0x0016
+#define MMC_PROFILE_DVD_RW_DL           0x0017
+#define MMC_PROFILE_DVD_DDR             0x0018
+#define MMC_PROFILE_DVD_PLUS_RW         0x001A
+#define MMC_PROFILE_DVD_PLUS_R          0x001B
+#define MMC_PROFILE_DVD_PLUS_RW_DL      0x002A
+#define MMC_PROFILE_DVD_PLUS_R_DL       0x002B
+#define MMC_PROFILE_BD_ROM              0x0040
+#define MMC_PROFILE_BD_R_SRM            0x0041
+#define MMC_PROFILE_BD_R_RRM            0x0042
+#define MMC_PROFILE_BD_RE               0x0043
+#define MMC_PROFILE_HDDVD_ROM           0x0050
+#define MMC_PROFILE_HDDVD_R             0x0051
+#define MMC_PROFILE_HDDVD_RAM           0x0052
+#define MMC_PROFILE_HDDVD_RW            0x0053
+#define MMC_PROFILE_HDDVD_R_DL          0x0058
+#define MMC_PROFILE_HDDVD_RW_DL         0x005A
+#define MMC_PROFILE_INVALID             0xFFFF
+
+#endif
index 1da240039dd501817b9b8aeb4ef1bc501fe67d26..977467bb57c69b0ce1be94346d6b2dc3c2d9dbf8 100644 (file)
@@ -20,7 +20,7 @@
 #define MEMORY_INTERNAL_H
 
 #ifndef CONFIG_USER_ONLY
-#include "hw/xen.h"
+#include "hw/xen/xen.h"
 
 typedef struct PhysPageEntry PhysPageEntry;
 
diff --git a/include/hw/acpi/acpi.h b/include/hw/acpi/acpi.h
new file mode 100644 (file)
index 0000000..e18ef28
--- /dev/null
@@ -0,0 +1,157 @@
+#ifndef QEMU_HW_ACPI_H
+#define QEMU_HW_ACPI_H
+/*
+ *  Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp>
+ *                     VA Linux Systems Japan K.K.
+ *
+ * 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/>.
+ */
+
+/* from linux include/acpi/actype.h */
+/* Default ACPI register widths */
+
+#define ACPI_GPE_REGISTER_WIDTH         8
+#define ACPI_PM1_REGISTER_WIDTH         16
+#define ACPI_PM2_REGISTER_WIDTH         8
+#define ACPI_PM_TIMER_WIDTH             32
+
+/* PM Timer ticks per second (HZ) */
+#define PM_TIMER_FREQUENCY  3579545
+
+
+/* ACPI fixed hardware registers */
+
+/* from linux/drivers/acpi/acpica/aclocal.h */
+/* Masks used to access the bit_registers */
+
+/* PM1x_STS */
+#define ACPI_BITMASK_TIMER_STATUS               0x0001
+#define ACPI_BITMASK_BUS_MASTER_STATUS          0x0010
+#define ACPI_BITMASK_GLOBAL_LOCK_STATUS         0x0020
+#define ACPI_BITMASK_POWER_BUTTON_STATUS        0x0100
+#define ACPI_BITMASK_SLEEP_BUTTON_STATUS        0x0200
+#define ACPI_BITMASK_RT_CLOCK_STATUS            0x0400
+#define ACPI_BITMASK_PCIEXP_WAKE_STATUS         0x4000 /* ACPI 3.0 */
+#define ACPI_BITMASK_WAKE_STATUS                0x8000
+
+#define ACPI_BITMASK_ALL_FIXED_STATUS           (\
+       ACPI_BITMASK_TIMER_STATUS          | \
+       ACPI_BITMASK_BUS_MASTER_STATUS     | \
+       ACPI_BITMASK_GLOBAL_LOCK_STATUS    | \
+       ACPI_BITMASK_POWER_BUTTON_STATUS   | \
+       ACPI_BITMASK_SLEEP_BUTTON_STATUS   | \
+       ACPI_BITMASK_RT_CLOCK_STATUS       | \
+       ACPI_BITMASK_WAKE_STATUS)
+
+/* PM1x_EN */
+#define ACPI_BITMASK_TIMER_ENABLE               0x0001
+#define ACPI_BITMASK_GLOBAL_LOCK_ENABLE         0x0020
+#define ACPI_BITMASK_POWER_BUTTON_ENABLE        0x0100
+#define ACPI_BITMASK_SLEEP_BUTTON_ENABLE        0x0200
+#define ACPI_BITMASK_RT_CLOCK_ENABLE            0x0400
+#define ACPI_BITMASK_PCIEXP_WAKE_DISABLE        0x4000 /* ACPI 3.0 */
+
+/* PM1x_CNT */
+#define ACPI_BITMASK_SCI_ENABLE                 0x0001
+#define ACPI_BITMASK_BUS_MASTER_RLD             0x0002
+#define ACPI_BITMASK_GLOBAL_LOCK_RELEASE        0x0004
+#define ACPI_BITMASK_SLEEP_TYPE                 0x1C00
+#define ACPI_BITMASK_SLEEP_ENABLE               0x2000
+
+/* PM2_CNT */
+#define ACPI_BITMASK_ARB_DISABLE                0x0001
+
+/* structs */
+typedef struct ACPIPMTimer ACPIPMTimer;
+typedef struct ACPIPM1EVT ACPIPM1EVT;
+typedef struct ACPIPM1CNT ACPIPM1CNT;
+typedef struct ACPIGPE ACPIGPE;
+typedef struct ACPIREGS ACPIREGS;
+
+typedef void (*acpi_update_sci_fn)(ACPIREGS *ar);
+
+struct ACPIPMTimer {
+    QEMUTimer *timer;
+    MemoryRegion io;
+    int64_t overflow_time;
+
+    acpi_update_sci_fn update_sci;
+};
+
+struct ACPIPM1EVT {
+    MemoryRegion io;
+    uint16_t sts;
+    uint16_t en;
+    acpi_update_sci_fn update_sci;
+};
+
+struct ACPIPM1CNT {
+    MemoryRegion io;
+    uint16_t cnt;
+    uint8_t s4_val;
+};
+
+struct ACPIGPE {
+    uint8_t len;
+
+    uint8_t *sts;
+    uint8_t *en;
+};
+
+struct ACPIREGS {
+    ACPIPMTimer     tmr;
+    ACPIGPE         gpe;
+    struct {
+        ACPIPM1EVT  evt;
+        ACPIPM1CNT  cnt;
+    } pm1;
+    Notifier wakeup;
+};
+
+/* PM_TMR */
+void acpi_pm_tmr_update(ACPIREGS *ar, bool enable);
+void acpi_pm_tmr_calc_overflow_time(ACPIREGS *ar);
+void acpi_pm_tmr_init(ACPIREGS *ar, acpi_update_sci_fn update_sci,
+                      MemoryRegion *parent);
+void acpi_pm_tmr_reset(ACPIREGS *ar);
+
+#include "qemu/timer.h"
+static inline int64_t acpi_pm_tmr_get_clock(void)
+{
+    return muldiv64(qemu_get_clock_ns(vm_clock), PM_TIMER_FREQUENCY,
+                    get_ticks_per_sec());
+}
+
+/* PM1a_EVT: piix and ich9 don't implement PM1b. */
+uint16_t acpi_pm1_evt_get_sts(ACPIREGS *ar);
+void acpi_pm1_evt_power_down(ACPIREGS *ar);
+void acpi_pm1_evt_reset(ACPIREGS *ar);
+void acpi_pm1_evt_init(ACPIREGS *ar, acpi_update_sci_fn update_sci,
+                       MemoryRegion *parent);
+
+/* PM1a_CNT: piix and ich9 don't implement PM1b CNT. */
+void acpi_pm1_cnt_init(ACPIREGS *ar, MemoryRegion *parent, uint8_t s4_val);
+void acpi_pm1_cnt_update(ACPIREGS *ar,
+                         bool sci_enable, bool sci_disable);
+void acpi_pm1_cnt_reset(ACPIREGS *ar);
+
+/* GPE0 */
+void acpi_gpe_init(ACPIREGS *ar, uint8_t len);
+void acpi_gpe_reset(ACPIREGS *ar);
+
+void acpi_gpe_ioport_writeb(ACPIREGS *ar, uint32_t addr, uint32_t val);
+uint32_t acpi_gpe_ioport_readb(ACPIREGS *ar, uint32_t addr);
+
+#endif /* !QEMU_HW_ACPI_H */
diff --git a/include/hw/acpi/ich9.h b/include/hw/acpi/ich9.h
new file mode 100644 (file)
index 0000000..85b82ee
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * QEMU GMCH/ICH9 LPC PM Emulation
+ *
+ *  Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp>
+ *                     VA Linux Systems Japan K.K.
+ *
+ * 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 HW_ACPI_ICH9_H
+#define HW_ACPI_ICH9_H
+
+#include "hw/acpi/acpi.h"
+
+typedef struct ICH9LPCPMRegs {
+    /*
+     * In ich9 spec says that pm1_cnt register is 32bit width and
+     * that the upper 16bits are reserved and unused.
+     * PM1a_CNT_BLK = 2 in FADT so it is defined as uint16_t.
+     */
+    ACPIREGS acpi_regs;
+
+    MemoryRegion io;
+    MemoryRegion io_gpe;
+    MemoryRegion io_smi;
+
+    uint32_t smi_en;
+    uint32_t smi_sts;
+
+    qemu_irq irq;      /* SCI */
+
+    uint32_t pm_io_base;
+    Notifier powerdown_notifier;
+} ICH9LPCPMRegs;
+
+void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs *pm,
+                  qemu_irq sci_irq, qemu_irq cmos_s3_resume);
+void ich9_pm_iospace_update(ICH9LPCPMRegs *pm, uint32_t pm_io_base);
+extern const VMStateDescription vmstate_ich9_pm;
+
+#endif /* HW_ACPI_ICH9_H */
diff --git a/include/hw/arm.h b/include/hw/arm.h
new file mode 100644 (file)
index 0000000..7b2b02d
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Misc ARM declarations
+ *
+ * Copyright (c) 2006 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the LGPL.
+ *
+ */
+
+#ifndef ARM_MISC_H
+#define ARM_MISC_H 1
+
+#include "exec/memory.h"
+#include "hw/irq.h"
+
+/* The CPU is also modelled as an interrupt controller.  */
+#define ARM_PIC_CPU_IRQ 0
+#define ARM_PIC_CPU_FIQ 1
+qemu_irq *arm_pic_init_cpu(ARMCPU *cpu);
+
+/* armv7m.c */
+qemu_irq *armv7m_init(MemoryRegion *address_space_mem,
+                      int flash_size, int sram_size,
+                      const char *kernel_filename, const char *cpu_model);
+
+/* arm_boot.c */
+struct arm_boot_info {
+    uint64_t ram_size;
+    const char *kernel_filename;
+    const char *kernel_cmdline;
+    const char *initrd_filename;
+    const char *dtb_filename;
+    hwaddr 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.
+     */
+    hwaddr smp_loader_start;
+    hwaddr smp_bootreg_addr;
+    hwaddr gic_cpu_if_addr;
+    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 mimicking 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 the
+     * secondary CPUs to point at this boot blob.
+     */
+    void (*write_secondary_boot)(ARMCPU *cpu,
+                                 const struct arm_boot_info *info);
+    void (*secondary_cpu_reset_hook)(ARMCPU *cpu,
+                                     const struct arm_boot_info *info);
+    /* Used internally by arm_boot.c */
+    int is_linux;
+    hwaddr initrd_start;
+    hwaddr initrd_size;
+    hwaddr entry;
+};
+void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info);
+
+/* Multiplication factor to convert from system clock ticks to qemu timer
+   ticks.  */
+extern int system_clock_scale;
+
+#endif /* !ARM_MISC_H */
diff --git a/include/hw/arm/devices.h b/include/hw/arm/devices.h
new file mode 100644 (file)
index 0000000..c60bcab
--- /dev/null
@@ -0,0 +1,70 @@
+#ifndef QEMU_DEVICES_H
+#define QEMU_DEVICES_H
+
+#include "hw/irq.h"
+
+/* ??? Not all users of this file can include cpu-common.h.  */
+struct MemoryRegion;
+
+/* Devices that have nowhere better to go.  */
+
+/* smc91c111.c */
+void smc91c111_init(NICInfo *, uint32_t, qemu_irq);
+
+/* lan9118.c */
+void lan9118_init(NICInfo *, uint32_t, qemu_irq);
+
+/* tsc210x.c */
+uWireSlave *tsc2102_init(qemu_irq pint);
+uWireSlave *tsc2301_init(qemu_irq penirq, qemu_irq kbirq, qemu_irq dav);
+I2SCodec *tsc210x_codec(uWireSlave *chip);
+uint32_t tsc210x_txrx(void *opaque, uint32_t value, int len);
+void tsc210x_set_transform(uWireSlave *chip,
+                MouseTransformInfo *info);
+void tsc210x_key_event(uWireSlave *chip, int key, int down);
+
+/* tsc2005.c */
+void *tsc2005_init(qemu_irq pintdav);
+uint32_t tsc2005_txrx(void *opaque, uint32_t value, int len);
+void tsc2005_set_transform(void *opaque, MouseTransformInfo *info);
+
+/* stellaris_input.c */
+void stellaris_gamepad_init(int n, qemu_irq *irq, const int *keycode);
+
+/* blizzard.c */
+void *s1d13745_init(qemu_irq gpio_int);
+void s1d13745_write(void *opaque, int dc, uint16_t value);
+void s1d13745_write_block(void *opaque, int dc,
+                void *buf, size_t len, int pitch);
+uint16_t s1d13745_read(void *opaque, int dc);
+
+/* cbus.c */
+typedef struct {
+    qemu_irq clk;
+    qemu_irq dat;
+    qemu_irq sel;
+} CBus;
+CBus *cbus_init(qemu_irq dat_out);
+void cbus_attach(CBus *bus, void *slave_opaque);
+
+void *retu_init(qemu_irq irq, int vilma);
+void *tahvo_init(qemu_irq irq, int betty);
+
+void retu_key_event(void *retu, int state);
+
+/* tc6393xb.c */
+typedef struct TC6393xbState TC6393xbState;
+#define TC6393XB_RAM   0x110000 /* amount of ram for Video and USB */
+TC6393xbState *tc6393xb_init(struct MemoryRegion *sysmem,
+                             uint32_t base, qemu_irq irq);
+void tc6393xb_gpio_out_set(TC6393xbState *s, int line,
+                    qemu_irq handler);
+qemu_irq *tc6393xb_gpio_in_get(TC6393xbState *s);
+qemu_irq tc6393xb_l3v_get(TC6393xbState *s);
+
+/* sm501.c */
+void sm501_init(struct MemoryRegion *address_space_mem, uint32_t base,
+                uint32_t local_mem_bytes, qemu_irq irq,
+                CharDriverState *chr);
+
+#endif
diff --git a/include/hw/arm/exynos4210.h b/include/hw/arm/exynos4210.h
new file mode 100644 (file)
index 0000000..bb9a1dd
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ *  Samsung exynos4210 SoC emulation
+ *
+ *  Copyright (c) 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *    Maksim Kozlov <m.kozlov@samsung.com>
+ *    Evgeny Voevodin <e.voevodin@samsung.com>
+ *    Igor Mitsyanko <i.mitsyanko@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 "exec/memory.h"
+
+#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.
+ */
+#define EXYNOS4210_IRQ_GATE_NINPUTS 2 /* Internal and External GIC */
+
+#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
+
+#define EXYNOS4210_I2C_NUMBER               9
+
+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;
+
+typedef struct Exynos4210State {
+    ARMCPU *cpu[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;
+    i2c_bus *i2c_if[EXYNOS4210_I2C_NUMBER];
+} Exynos4210State;
+
+void exynos4210_write_secondary(ARMCPU *cpu,
+        const struct arm_boot_info *info);
+
+Exynos4210State *exynos4210_init(MemoryRegion *system_mem,
+        unsigned long ram_size);
+
+/* 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);
+
+/*
+ * exynos4210 UART
+ */
+DeviceState *exynos4210_uart_create(hwaddr addr,
+                                    int fifo_size,
+                                    int channel,
+                                    CharDriverState *chr,
+                                    qemu_irq irq);
+
+#endif /* EXYNOS4210_H_ */
diff --git a/include/hw/arm/imx.h b/include/hw/arm/imx.h
new file mode 100644 (file)
index 0000000..ea9e093
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * i.MX31 emulation
+ *
+ * Copyright (C) 2012 Peter Chubb
+ * NICTA
+ *
+ * This code is released under the GPL, version 2.0 or later
+ * See the file `../COPYING' for details.
+ */
+
+#ifndef IMX_H
+#define IMX_H
+
+void imx_serial_create(int uart, const hwaddr addr, qemu_irq irq);
+
+typedef enum  {
+    NOCLK,
+    MCU,
+    HSP,
+    IPG,
+    CLK_32k
+} IMXClk;
+
+uint32_t imx_clock_frequency(DeviceState *s, IMXClk clock);
+
+void imx_timerp_create(const hwaddr addr,
+                      qemu_irq irq,
+                      DeviceState *ccm);
+void imx_timerg_create(const hwaddr addr,
+                      qemu_irq irq,
+                      DeviceState *ccm);
+
+
+#endif /* IMX_H */
diff --git a/include/hw/arm/omap.h b/include/hw/arm/omap.h
new file mode 100644 (file)
index 0000000..188cda8
--- /dev/null
@@ -0,0 +1,1015 @@
+/*
+ * Texas Instruments OMAP processors.
+ *
+ * Copyright (C) 2006-2008 Andrzej Zaborowski  <balrog@zabor.org>
+ *
+ * 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 or
+ * (at your option) version 3 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
+ * 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 hw_omap_h
+#include "exec/memory.h"
+# define hw_omap_h             "omap.h"
+#include "hw/irq.h"
+
+# define OMAP_EMIFS_BASE       0x00000000
+# define OMAP2_Q0_BASE         0x00000000
+# define OMAP_CS0_BASE         0x00000000
+# define OMAP_CS1_BASE         0x04000000
+# define OMAP_CS2_BASE         0x08000000
+# define OMAP_CS3_BASE         0x0c000000
+# define OMAP_EMIFF_BASE       0x10000000
+# define OMAP_IMIF_BASE                0x20000000
+# define OMAP_LOCALBUS_BASE    0x30000000
+# define OMAP2_Q1_BASE         0x40000000
+# define OMAP2_L4_BASE         0x48000000
+# define OMAP2_SRAM_BASE       0x40200000
+# define OMAP2_L3_BASE         0x68000000
+# define OMAP2_Q2_BASE         0x80000000
+# define OMAP2_Q3_BASE         0xc0000000
+# define OMAP_MPUI_BASE                0xe1000000
+
+# define OMAP730_SRAM_SIZE     0x00032000
+# define OMAP15XX_SRAM_SIZE    0x00030000
+# define OMAP16XX_SRAM_SIZE    0x00004000
+# define OMAP1611_SRAM_SIZE    0x0003e800
+# define OMAP242X_SRAM_SIZE    0x000a0000
+# define OMAP243X_SRAM_SIZE    0x00010000
+# define OMAP_CS0_SIZE         0x04000000
+# define OMAP_CS1_SIZE         0x04000000
+# define OMAP_CS2_SIZE         0x04000000
+# define OMAP_CS3_SIZE         0x04000000
+
+/* omap_clk.c */
+struct omap_mpu_state_s;
+typedef struct clk *omap_clk;
+omap_clk omap_findclk(struct omap_mpu_state_s *mpu, const char *name);
+void omap_clk_init(struct omap_mpu_state_s *mpu);
+void omap_clk_adduser(struct clk *clk, qemu_irq user);
+void omap_clk_get(omap_clk clk);
+void omap_clk_put(omap_clk clk);
+void omap_clk_onoff(omap_clk clk, int on);
+void omap_clk_canidle(omap_clk clk, int can);
+void omap_clk_setrate(omap_clk clk, int divide, int multiply);
+int64_t omap_clk_getrate(omap_clk clk);
+void omap_clk_reparent(omap_clk clk, omap_clk parent);
+
+/* OMAP2 l4 Interconnect */
+struct omap_l4_s;
+struct omap_l4_region_s {
+    hwaddr offset;
+    size_t size;
+    int access;
+};
+struct omap_l4_agent_info_s {
+    int ta;
+    int region;
+    int regions;
+    int ta_region;
+};
+struct omap_target_agent_s {
+    MemoryRegion iomem;
+    struct omap_l4_s *bus;
+    int regions;
+    const struct omap_l4_region_s *start;
+    hwaddr base;
+    uint32_t component;
+    uint32_t control;
+    uint32_t status;
+};
+struct omap_l4_s *omap_l4_init(MemoryRegion *address_space,
+                               hwaddr base, int ta_num);
+
+struct omap_target_agent_s;
+struct omap_target_agent_s *omap_l4ta_get(
+    struct omap_l4_s *bus,
+    const struct omap_l4_region_s *regions,
+    const struct omap_l4_agent_info_s *agents,
+    int cs);
+hwaddr omap_l4_attach(struct omap_target_agent_s *ta,
+                                         int region, MemoryRegion *mr);
+hwaddr omap_l4_region_base(struct omap_target_agent_s *ta,
+                                       int region);
+hwaddr omap_l4_region_size(struct omap_target_agent_s *ta,
+                                       int region);
+
+/* OMAP2 SDRAM controller */
+struct omap_sdrc_s;
+struct omap_sdrc_s *omap_sdrc_init(MemoryRegion *sysmem,
+                                   hwaddr base);
+void omap_sdrc_reset(struct omap_sdrc_s *s);
+
+/* OMAP2 general purpose memory controller */
+struct omap_gpmc_s;
+struct omap_gpmc_s *omap_gpmc_init(struct omap_mpu_state_s *mpu,
+                                   hwaddr base,
+                                   qemu_irq irq, qemu_irq drq);
+void omap_gpmc_reset(struct omap_gpmc_s *s);
+void omap_gpmc_attach(struct omap_gpmc_s *s, int cs, MemoryRegion *iomem);
+void omap_gpmc_attach_nand(struct omap_gpmc_s *s, int cs, DeviceState *nand);
+
+/*
+ * Common IRQ numbers for level 1 interrupt handler
+ * See /usr/include/asm-arm/arch-omap/irqs.h in Linux.
+ */
+# define OMAP_INT_CAMERA               1
+# define OMAP_INT_FIQ                  3
+# define OMAP_INT_RTDX                 6
+# define OMAP_INT_DSP_MMU_ABORT                7
+# define OMAP_INT_HOST                 8
+# define OMAP_INT_ABORT                        9
+# define OMAP_INT_BRIDGE_PRIV          13
+# define OMAP_INT_GPIO_BANK1           14
+# define OMAP_INT_UART3                        15
+# define OMAP_INT_TIMER3               16
+# define OMAP_INT_DMA_CH0_6            19
+# define OMAP_INT_DMA_CH1_7            20
+# define OMAP_INT_DMA_CH2_8            21
+# define OMAP_INT_DMA_CH3              22
+# define OMAP_INT_DMA_CH4              23
+# define OMAP_INT_DMA_CH5              24
+# define OMAP_INT_DMA_LCD              25
+# define OMAP_INT_TIMER1               26
+# define OMAP_INT_WD_TIMER             27
+# define OMAP_INT_BRIDGE_PUB           28
+# define OMAP_INT_TIMER2               30
+# define OMAP_INT_LCD_CTRL             31
+
+/*
+ * Common OMAP-15xx IRQ numbers for level 1 interrupt handler
+ */
+# define OMAP_INT_15XX_IH2_IRQ         0
+# define OMAP_INT_15XX_LB_MMU          17
+# define OMAP_INT_15XX_LOCAL_BUS       29
+
+/*
+ * OMAP-1510 specific IRQ numbers for level 1 interrupt handler
+ */
+# define OMAP_INT_1510_SPI_TX          4
+# define OMAP_INT_1510_SPI_RX          5
+# define OMAP_INT_1510_DSP_MAILBOX1    10
+# define OMAP_INT_1510_DSP_MAILBOX2    11
+
+/*
+ * OMAP-310 specific IRQ numbers for level 1 interrupt handler
+ */
+# define OMAP_INT_310_McBSP2_TX                4
+# define OMAP_INT_310_McBSP2_RX                5
+# define OMAP_INT_310_HSB_MAILBOX1     12
+# define OMAP_INT_310_HSAB_MMU         18
+
+/*
+ * OMAP-1610 specific IRQ numbers for level 1 interrupt handler
+ */
+# define OMAP_INT_1610_IH2_IRQ         0
+# define OMAP_INT_1610_IH2_FIQ         2
+# define OMAP_INT_1610_McBSP2_TX       4
+# define OMAP_INT_1610_McBSP2_RX       5
+# define OMAP_INT_1610_DSP_MAILBOX1    10
+# define OMAP_INT_1610_DSP_MAILBOX2    11
+# define OMAP_INT_1610_LCD_LINE                12
+# define OMAP_INT_1610_GPTIMER1                17
+# define OMAP_INT_1610_GPTIMER2                18
+# define OMAP_INT_1610_SSR_FIFO_0      29
+
+/*
+ * OMAP-730 specific IRQ numbers for level 1 interrupt handler
+ */
+# define OMAP_INT_730_IH2_FIQ          0
+# define OMAP_INT_730_IH2_IRQ          1
+# define OMAP_INT_730_USB_NON_ISO      2
+# define OMAP_INT_730_USB_ISO          3
+# define OMAP_INT_730_ICR              4
+# define OMAP_INT_730_EAC              5
+# define OMAP_INT_730_GPIO_BANK1       6
+# define OMAP_INT_730_GPIO_BANK2       7
+# define OMAP_INT_730_GPIO_BANK3       8
+# define OMAP_INT_730_McBSP2TX         10
+# define OMAP_INT_730_McBSP2RX         11
+# define OMAP_INT_730_McBSP2RX_OVF     12
+# define OMAP_INT_730_LCD_LINE         14
+# define OMAP_INT_730_GSM_PROTECT      15
+# define OMAP_INT_730_TIMER3           16
+# define OMAP_INT_730_GPIO_BANK5       17
+# define OMAP_INT_730_GPIO_BANK6       18
+# define OMAP_INT_730_SPGIO_WR         29
+
+/*
+ * Common IRQ numbers for level 2 interrupt handler
+ */
+# define OMAP_INT_KEYBOARD             1
+# define OMAP_INT_uWireTX              2
+# define OMAP_INT_uWireRX              3
+# define OMAP_INT_I2C                  4
+# define OMAP_INT_MPUIO                        5
+# define OMAP_INT_USB_HHC_1            6
+# define OMAP_INT_McBSP3TX             10
+# define OMAP_INT_McBSP3RX             11
+# define OMAP_INT_McBSP1TX             12
+# define OMAP_INT_McBSP1RX             13
+# define OMAP_INT_UART1                        14
+# define OMAP_INT_UART2                        15
+# define OMAP_INT_USB_W2FC             20
+# define OMAP_INT_1WIRE                        21
+# define OMAP_INT_OS_TIMER             22
+# define OMAP_INT_OQN                  23
+# define OMAP_INT_GAUGE_32K            24
+# define OMAP_INT_RTC_TIMER            25
+# define OMAP_INT_RTC_ALARM            26
+# define OMAP_INT_DSP_MMU              28
+
+/*
+ * OMAP-1510 specific IRQ numbers for level 2 interrupt handler
+ */
+# define OMAP_INT_1510_BT_MCSI1TX      16
+# define OMAP_INT_1510_BT_MCSI1RX      17
+# define OMAP_INT_1510_SoSSI_MATCH     19
+# define OMAP_INT_1510_MEM_STICK       27
+# define OMAP_INT_1510_COM_SPI_RO      31
+
+/*
+ * OMAP-310 specific IRQ numbers for level 2 interrupt handler
+ */
+# define OMAP_INT_310_FAC              0
+# define OMAP_INT_310_USB_HHC_2                7
+# define OMAP_INT_310_MCSI1_FE         16
+# define OMAP_INT_310_MCSI2_FE         17
+# define OMAP_INT_310_USB_W2FC_ISO     29
+# define OMAP_INT_310_USB_W2FC_NON_ISO 30
+# define OMAP_INT_310_McBSP2RX_OF      31
+
+/*
+ * OMAP-1610 specific IRQ numbers for level 2 interrupt handler
+ */
+# define OMAP_INT_1610_FAC             0
+# define OMAP_INT_1610_USB_HHC_2       7
+# define OMAP_INT_1610_USB_OTG         8
+# define OMAP_INT_1610_SoSSI           9
+# define OMAP_INT_1610_BT_MCSI1TX      16
+# define OMAP_INT_1610_BT_MCSI1RX      17
+# define OMAP_INT_1610_SoSSI_MATCH     19
+# define OMAP_INT_1610_MEM_STICK       27
+# define OMAP_INT_1610_McBSP2RX_OF     31
+# define OMAP_INT_1610_STI             32
+# define OMAP_INT_1610_STI_WAKEUP      33
+# define OMAP_INT_1610_GPTIMER3                34
+# define OMAP_INT_1610_GPTIMER4                35
+# define OMAP_INT_1610_GPTIMER5                36
+# define OMAP_INT_1610_GPTIMER6                37
+# define OMAP_INT_1610_GPTIMER7                38
+# define OMAP_INT_1610_GPTIMER8                39
+# define OMAP_INT_1610_GPIO_BANK2      40
+# define OMAP_INT_1610_GPIO_BANK3      41
+# define OMAP_INT_1610_MMC2            42
+# define OMAP_INT_1610_CF              43
+# define OMAP_INT_1610_WAKE_UP_REQ     46
+# define OMAP_INT_1610_GPIO_BANK4      48
+# define OMAP_INT_1610_SPI             49
+# define OMAP_INT_1610_DMA_CH6         53
+# define OMAP_INT_1610_DMA_CH7         54
+# define OMAP_INT_1610_DMA_CH8         55
+# define OMAP_INT_1610_DMA_CH9         56
+# define OMAP_INT_1610_DMA_CH10                57
+# define OMAP_INT_1610_DMA_CH11                58
+# define OMAP_INT_1610_DMA_CH12                59
+# define OMAP_INT_1610_DMA_CH13                60
+# define OMAP_INT_1610_DMA_CH14                61
+# define OMAP_INT_1610_DMA_CH15                62
+# define OMAP_INT_1610_NAND            63
+
+/*
+ * OMAP-730 specific IRQ numbers for level 2 interrupt handler
+ */
+# define OMAP_INT_730_HW_ERRORS                0
+# define OMAP_INT_730_NFIQ_PWR_FAIL    1
+# define OMAP_INT_730_CFCD             2
+# define OMAP_INT_730_CFIREQ           3
+# define OMAP_INT_730_I2C              4
+# define OMAP_INT_730_PCC              5
+# define OMAP_INT_730_MPU_EXT_NIRQ     6
+# define OMAP_INT_730_SPI_100K_1       7
+# define OMAP_INT_730_SYREN_SPI                8
+# define OMAP_INT_730_VLYNQ            9
+# define OMAP_INT_730_GPIO_BANK4       10
+# define OMAP_INT_730_McBSP1TX         11
+# define OMAP_INT_730_McBSP1RX         12
+# define OMAP_INT_730_McBSP1RX_OF      13
+# define OMAP_INT_730_UART_MODEM_IRDA_2        14
+# define OMAP_INT_730_UART_MODEM_1     15
+# define OMAP_INT_730_MCSI             16
+# define OMAP_INT_730_uWireTX          17
+# define OMAP_INT_730_uWireRX          18
+# define OMAP_INT_730_SMC_CD           19
+# define OMAP_INT_730_SMC_IREQ         20
+# define OMAP_INT_730_HDQ_1WIRE                21
+# define OMAP_INT_730_TIMER32K         22
+# define OMAP_INT_730_MMC_SDIO         23
+# define OMAP_INT_730_UPLD             24
+# define OMAP_INT_730_USB_HHC_1                27
+# define OMAP_INT_730_USB_HHC_2                28
+# define OMAP_INT_730_USB_GENI         29
+# define OMAP_INT_730_USB_OTG          30
+# define OMAP_INT_730_CAMERA_IF                31
+# define OMAP_INT_730_RNG              32
+# define OMAP_INT_730_DUAL_MODE_TIMER  33
+# define OMAP_INT_730_DBB_RF_EN                34
+# define OMAP_INT_730_MPUIO_KEYPAD     35
+# define OMAP_INT_730_SHA1_MD5         36
+# define OMAP_INT_730_SPI_100K_2       37
+# define OMAP_INT_730_RNG_IDLE         38
+# define OMAP_INT_730_MPUIO            39
+# define OMAP_INT_730_LLPC_LCD_CTRL_OFF        40
+# define OMAP_INT_730_LLPC_OE_FALLING  41
+# define OMAP_INT_730_LLPC_OE_RISING   42
+# define OMAP_INT_730_LLPC_VSYNC       43
+# define OMAP_INT_730_WAKE_UP_REQ      46
+# define OMAP_INT_730_DMA_CH6          53
+# define OMAP_INT_730_DMA_CH7          54
+# define OMAP_INT_730_DMA_CH8          55
+# define OMAP_INT_730_DMA_CH9          56
+# define OMAP_INT_730_DMA_CH10         57
+# define OMAP_INT_730_DMA_CH11         58
+# define OMAP_INT_730_DMA_CH12         59
+# define OMAP_INT_730_DMA_CH13         60
+# define OMAP_INT_730_DMA_CH14         61
+# define OMAP_INT_730_DMA_CH15         62
+# define OMAP_INT_730_NAND             63
+
+/*
+ * OMAP-24xx common IRQ numbers
+ */
+# define OMAP_INT_24XX_STI             4
+# define OMAP_INT_24XX_SYS_NIRQ                7
+# define OMAP_INT_24XX_L3_IRQ          10
+# define OMAP_INT_24XX_PRCM_MPU_IRQ    11
+# define OMAP_INT_24XX_SDMA_IRQ0       12
+# define OMAP_INT_24XX_SDMA_IRQ1       13
+# define OMAP_INT_24XX_SDMA_IRQ2       14
+# define OMAP_INT_24XX_SDMA_IRQ3       15
+# define OMAP_INT_243X_MCBSP2_IRQ      16
+# define OMAP_INT_243X_MCBSP3_IRQ      17
+# define OMAP_INT_243X_MCBSP4_IRQ      18
+# define OMAP_INT_243X_MCBSP5_IRQ      19
+# define OMAP_INT_24XX_GPMC_IRQ                20
+# define OMAP_INT_24XX_GUFFAW_IRQ      21
+# define OMAP_INT_24XX_IVA_IRQ         22
+# define OMAP_INT_24XX_EAC_IRQ         23
+# define OMAP_INT_24XX_CAM_IRQ         24
+# define OMAP_INT_24XX_DSS_IRQ         25
+# define OMAP_INT_24XX_MAIL_U0_MPU     26
+# define OMAP_INT_24XX_DSP_UMA         27
+# define OMAP_INT_24XX_DSP_MMU         28
+# define OMAP_INT_24XX_GPIO_BANK1      29
+# define OMAP_INT_24XX_GPIO_BANK2      30
+# define OMAP_INT_24XX_GPIO_BANK3      31
+# define OMAP_INT_24XX_GPIO_BANK4      32
+# define OMAP_INT_243X_GPIO_BANK5      33
+# define OMAP_INT_24XX_MAIL_U3_MPU     34
+# define OMAP_INT_24XX_WDT3            35
+# define OMAP_INT_24XX_WDT4            36
+# define OMAP_INT_24XX_GPTIMER1                37
+# define OMAP_INT_24XX_GPTIMER2                38
+# define OMAP_INT_24XX_GPTIMER3                39
+# define OMAP_INT_24XX_GPTIMER4                40
+# define OMAP_INT_24XX_GPTIMER5                41
+# define OMAP_INT_24XX_GPTIMER6                42
+# define OMAP_INT_24XX_GPTIMER7                43
+# define OMAP_INT_24XX_GPTIMER8                44
+# define OMAP_INT_24XX_GPTIMER9                45
+# define OMAP_INT_24XX_GPTIMER10       46
+# define OMAP_INT_24XX_GPTIMER11       47
+# define OMAP_INT_24XX_GPTIMER12       48
+# define OMAP_INT_24XX_PKA_IRQ         50
+# define OMAP_INT_24XX_SHA1MD5_IRQ     51
+# define OMAP_INT_24XX_RNG_IRQ         52
+# define OMAP_INT_24XX_MG_IRQ          53
+# define OMAP_INT_24XX_I2C1_IRQ                56
+# define OMAP_INT_24XX_I2C2_IRQ                57
+# define OMAP_INT_24XX_MCBSP1_IRQ_TX   59
+# define OMAP_INT_24XX_MCBSP1_IRQ_RX   60
+# define OMAP_INT_24XX_MCBSP2_IRQ_TX   62
+# define OMAP_INT_24XX_MCBSP2_IRQ_RX   63
+# define OMAP_INT_243X_MCBSP1_IRQ      64
+# define OMAP_INT_24XX_MCSPI1_IRQ      65
+# define OMAP_INT_24XX_MCSPI2_IRQ      66
+# define OMAP_INT_24XX_SSI1_IRQ0       67
+# define OMAP_INT_24XX_SSI1_IRQ1       68
+# define OMAP_INT_24XX_SSI2_IRQ0       69
+# define OMAP_INT_24XX_SSI2_IRQ1       70
+# define OMAP_INT_24XX_SSI_GDD_IRQ     71
+# define OMAP_INT_24XX_UART1_IRQ       72
+# define OMAP_INT_24XX_UART2_IRQ       73
+# define OMAP_INT_24XX_UART3_IRQ       74
+# define OMAP_INT_24XX_USB_IRQ_GEN     75
+# define OMAP_INT_24XX_USB_IRQ_NISO    76
+# define OMAP_INT_24XX_USB_IRQ_ISO     77
+# define OMAP_INT_24XX_USB_IRQ_HGEN    78
+# define OMAP_INT_24XX_USB_IRQ_HSOF    79
+# define OMAP_INT_24XX_USB_IRQ_OTG     80
+# define OMAP_INT_24XX_VLYNQ_IRQ       81
+# define OMAP_INT_24XX_MMC_IRQ         83
+# define OMAP_INT_24XX_MS_IRQ          84
+# define OMAP_INT_24XX_FAC_IRQ         85
+# define OMAP_INT_24XX_MCSPI3_IRQ      91
+# define OMAP_INT_243X_HS_USB_MC       92
+# define OMAP_INT_243X_HS_USB_DMA      93
+# define OMAP_INT_243X_CARKIT          94
+# define OMAP_INT_34XX_GPTIMER12       95
+
+/* omap_dma.c */
+enum omap_dma_model {
+    omap_dma_3_0,
+    omap_dma_3_1,
+    omap_dma_3_2,
+    omap_dma_4,
+};
+
+struct soc_dma_s;
+struct soc_dma_s *omap_dma_init(hwaddr base, qemu_irq *irqs,
+                MemoryRegion *sysmem,
+                qemu_irq lcd_irq, struct omap_mpu_state_s *mpu, omap_clk clk,
+                enum omap_dma_model model);
+struct soc_dma_s *omap_dma4_init(hwaddr base, qemu_irq *irqs,
+                MemoryRegion *sysmem,
+                struct omap_mpu_state_s *mpu, int fifo,
+                int chans, omap_clk iclk, omap_clk fclk);
+void omap_dma_reset(struct soc_dma_s *s);
+
+struct dma_irq_map {
+    int ih;
+    int intr;
+};
+
+/* Only used in OMAP DMA 3.x gigacells */
+enum omap_dma_port {
+    emiff = 0,
+    emifs,
+    imif,      /* omap16xx: ocp_t1 */
+    tipb,
+    local,     /* omap16xx: ocp_t2 */
+    tipb_mpui,
+    __omap_dma_port_last,
+};
+
+typedef enum {
+    constant = 0,
+    post_incremented,
+    single_index,
+    double_index,
+} omap_dma_addressing_t;
+
+/* Only used in OMAP DMA 3.x gigacells */
+struct omap_dma_lcd_channel_s {
+    enum omap_dma_port src;
+    hwaddr src_f1_top;
+    hwaddr src_f1_bottom;
+    hwaddr src_f2_top;
+    hwaddr src_f2_bottom;
+
+    /* Used in OMAP DMA 3.2 gigacell */
+    unsigned char brust_f1;
+    unsigned char pack_f1;
+    unsigned char data_type_f1;
+    unsigned char brust_f2;
+    unsigned char pack_f2;
+    unsigned char data_type_f2;
+    unsigned char end_prog;
+    unsigned char repeat;
+    unsigned char auto_init;
+    unsigned char priority;
+    unsigned char fs;
+    unsigned char running;
+    unsigned char bs;
+    unsigned char omap_3_1_compatible_disable;
+    unsigned char dst;
+    unsigned char lch_type;
+    int16_t element_index_f1;
+    int16_t element_index_f2;
+    int32_t frame_index_f1;
+    int32_t frame_index_f2;
+    uint16_t elements_f1;
+    uint16_t frames_f1;
+    uint16_t elements_f2;
+    uint16_t frames_f2;
+    omap_dma_addressing_t mode_f1;
+    omap_dma_addressing_t mode_f2;
+
+    /* Destination port is fixed.  */
+    int interrupts;
+    int condition;
+    int dual;
+
+    int current_frame;
+    hwaddr phys_framebuffer[2];
+    qemu_irq irq;
+    struct omap_mpu_state_s *mpu;
+} *omap_dma_get_lcdch(struct soc_dma_s *s);
+
+/*
+ * DMA request numbers for OMAP1
+ * See /usr/include/asm-arm/arch-omap/dma.h in Linux.
+ */
+# define OMAP_DMA_NO_DEVICE            0
+# define OMAP_DMA_MCSI1_TX             1
+# define OMAP_DMA_MCSI1_RX             2
+# define OMAP_DMA_I2C_RX               3
+# define OMAP_DMA_I2C_TX               4
+# define OMAP_DMA_EXT_NDMA_REQ0                5
+# define OMAP_DMA_EXT_NDMA_REQ1                6
+# define OMAP_DMA_UWIRE_TX             7
+# define OMAP_DMA_MCBSP1_TX            8
+# define OMAP_DMA_MCBSP1_RX            9
+# define OMAP_DMA_MCBSP3_TX            10
+# define OMAP_DMA_MCBSP3_RX            11
+# define OMAP_DMA_UART1_TX             12
+# define OMAP_DMA_UART1_RX             13
+# define OMAP_DMA_UART2_TX             14
+# define OMAP_DMA_UART2_RX             15
+# define OMAP_DMA_MCBSP2_TX            16
+# define OMAP_DMA_MCBSP2_RX            17
+# define OMAP_DMA_UART3_TX             18
+# define OMAP_DMA_UART3_RX             19
+# define OMAP_DMA_CAMERA_IF_RX         20
+# define OMAP_DMA_MMC_TX               21
+# define OMAP_DMA_MMC_RX               22
+# define OMAP_DMA_NAND                 23      /* Not in OMAP310 */
+# define OMAP_DMA_IRQ_LCD_LINE         24      /* Not in OMAP310 */
+# define OMAP_DMA_MEMORY_STICK         25      /* Not in OMAP310 */
+# define OMAP_DMA_USB_W2FC_RX0         26
+# define OMAP_DMA_USB_W2FC_RX1         27
+# define OMAP_DMA_USB_W2FC_RX2         28
+# define OMAP_DMA_USB_W2FC_TX0         29
+# define OMAP_DMA_USB_W2FC_TX1         30
+# define OMAP_DMA_USB_W2FC_TX2         31
+
+/* These are only for 1610 */
+# define OMAP_DMA_CRYPTO_DES_IN                32
+# define OMAP_DMA_SPI_TX               33
+# define OMAP_DMA_SPI_RX               34
+# define OMAP_DMA_CRYPTO_HASH          35
+# define OMAP_DMA_CCP_ATTN             36
+# define OMAP_DMA_CCP_FIFO_NOT_EMPTY   37
+# define OMAP_DMA_CMT_APE_TX_CHAN_0    38
+# define OMAP_DMA_CMT_APE_RV_CHAN_0    39
+# define OMAP_DMA_CMT_APE_TX_CHAN_1    40
+# define OMAP_DMA_CMT_APE_RV_CHAN_1    41
+# define OMAP_DMA_CMT_APE_TX_CHAN_2    42
+# define OMAP_DMA_CMT_APE_RV_CHAN_2    43
+# define OMAP_DMA_CMT_APE_TX_CHAN_3    44
+# define OMAP_DMA_CMT_APE_RV_CHAN_3    45
+# define OMAP_DMA_CMT_APE_TX_CHAN_4    46
+# define OMAP_DMA_CMT_APE_RV_CHAN_4    47
+# define OMAP_DMA_CMT_APE_TX_CHAN_5    48
+# define OMAP_DMA_CMT_APE_RV_CHAN_5    49
+# define OMAP_DMA_CMT_APE_TX_CHAN_6    50
+# define OMAP_DMA_CMT_APE_RV_CHAN_6    51
+# define OMAP_DMA_CMT_APE_TX_CHAN_7    52
+# define OMAP_DMA_CMT_APE_RV_CHAN_7    53
+# define OMAP_DMA_MMC2_TX              54
+# define OMAP_DMA_MMC2_RX              55
+# define OMAP_DMA_CRYPTO_DES_OUT       56
+
+/*
+ * DMA request numbers for the OMAP2
+ */
+# define OMAP24XX_DMA_NO_DEVICE                0
+# define OMAP24XX_DMA_XTI_DMA          1       /* Not in OMAP2420 */
+# define OMAP24XX_DMA_EXT_DMAREQ0      2
+# define OMAP24XX_DMA_EXT_DMAREQ1      3
+# define OMAP24XX_DMA_GPMC             4
+# define OMAP24XX_DMA_GFX              5       /* Not in OMAP2420 */
+# define OMAP24XX_DMA_DSS              6
+# define OMAP24XX_DMA_VLYNQ_TX         7       /* Not in OMAP2420 */
+# define OMAP24XX_DMA_CWT              8       /* Not in OMAP2420 */
+# define OMAP24XX_DMA_AES_TX           9       /* Not in OMAP2420 */
+# define OMAP24XX_DMA_AES_RX           10      /* Not in OMAP2420 */
+# define OMAP24XX_DMA_DES_TX           11      /* Not in OMAP2420 */
+# define OMAP24XX_DMA_DES_RX           12      /* Not in OMAP2420 */
+# define OMAP24XX_DMA_SHA1MD5_RX       13      /* Not in OMAP2420 */
+# define OMAP24XX_DMA_EXT_DMAREQ2      14
+# define OMAP24XX_DMA_EXT_DMAREQ3      15
+# define OMAP24XX_DMA_EXT_DMAREQ4      16
+# define OMAP24XX_DMA_EAC_AC_RD                17
+# define OMAP24XX_DMA_EAC_AC_WR                18
+# define OMAP24XX_DMA_EAC_MD_UL_RD     19
+# define OMAP24XX_DMA_EAC_MD_UL_WR     20
+# define OMAP24XX_DMA_EAC_MD_DL_RD     21
+# define OMAP24XX_DMA_EAC_MD_DL_WR     22
+# define OMAP24XX_DMA_EAC_BT_UL_RD     23
+# define OMAP24XX_DMA_EAC_BT_UL_WR     24
+# define OMAP24XX_DMA_EAC_BT_DL_RD     25
+# define OMAP24XX_DMA_EAC_BT_DL_WR     26
+# define OMAP24XX_DMA_I2C1_TX          27
+# define OMAP24XX_DMA_I2C1_RX          28
+# define OMAP24XX_DMA_I2C2_TX          29
+# define OMAP24XX_DMA_I2C2_RX          30
+# define OMAP24XX_DMA_MCBSP1_TX                31
+# define OMAP24XX_DMA_MCBSP1_RX                32
+# define OMAP24XX_DMA_MCBSP2_TX                33
+# define OMAP24XX_DMA_MCBSP2_RX                34
+# define OMAP24XX_DMA_SPI1_TX0         35
+# define OMAP24XX_DMA_SPI1_RX0         36
+# define OMAP24XX_DMA_SPI1_TX1         37
+# define OMAP24XX_DMA_SPI1_RX1         38
+# define OMAP24XX_DMA_SPI1_TX2         39
+# define OMAP24XX_DMA_SPI1_RX2         40
+# define OMAP24XX_DMA_SPI1_TX3         41
+# define OMAP24XX_DMA_SPI1_RX3         42
+# define OMAP24XX_DMA_SPI2_TX0         43
+# define OMAP24XX_DMA_SPI2_RX0         44
+# define OMAP24XX_DMA_SPI2_TX1         45
+# define OMAP24XX_DMA_SPI2_RX1         46
+
+# define OMAP24XX_DMA_UART1_TX         49
+# define OMAP24XX_DMA_UART1_RX         50
+# define OMAP24XX_DMA_UART2_TX         51
+# define OMAP24XX_DMA_UART2_RX         52
+# define OMAP24XX_DMA_UART3_TX         53
+# define OMAP24XX_DMA_UART3_RX         54
+# define OMAP24XX_DMA_USB_W2FC_TX0     55
+# define OMAP24XX_DMA_USB_W2FC_RX0     56
+# define OMAP24XX_DMA_USB_W2FC_TX1     57
+# define OMAP24XX_DMA_USB_W2FC_RX1     58
+# define OMAP24XX_DMA_USB_W2FC_TX2     59
+# define OMAP24XX_DMA_USB_W2FC_RX2     60
+# define OMAP24XX_DMA_MMC1_TX          61
+# define OMAP24XX_DMA_MMC1_RX          62
+# define OMAP24XX_DMA_MS               63      /* Not in OMAP2420 */
+# define OMAP24XX_DMA_EXT_DMAREQ5      64
+
+/* omap[123].c */
+/* OMAP2 gp timer */
+struct omap_gp_timer_s;
+struct omap_gp_timer_s *omap_gp_timer_init(struct omap_target_agent_s *ta,
+                qemu_irq irq, omap_clk fclk, omap_clk iclk);
+void omap_gp_timer_reset(struct omap_gp_timer_s *s);
+
+/* OMAP2 sysctimer */
+struct omap_synctimer_s;
+struct omap_synctimer_s *omap_synctimer_init(struct omap_target_agent_s *ta,
+                struct omap_mpu_state_s *mpu, omap_clk fclk, omap_clk iclk);
+void omap_synctimer_reset(struct omap_synctimer_s *s);
+
+struct omap_uart_s;
+struct omap_uart_s *omap_uart_init(hwaddr base,
+                qemu_irq irq, omap_clk fclk, omap_clk iclk,
+                qemu_irq txdma, qemu_irq rxdma,
+                const char *label, CharDriverState *chr);
+struct omap_uart_s *omap2_uart_init(MemoryRegion *sysmem,
+                struct omap_target_agent_s *ta,
+                qemu_irq irq, omap_clk fclk, omap_clk iclk,
+                qemu_irq txdma, qemu_irq rxdma,
+                const char *label, CharDriverState *chr);
+void omap_uart_reset(struct omap_uart_s *s);
+void omap_uart_attach(struct omap_uart_s *s, CharDriverState *chr);
+
+struct omap_mpuio_s;
+qemu_irq *omap_mpuio_in_get(struct omap_mpuio_s *s);
+void omap_mpuio_out_set(struct omap_mpuio_s *s, int line, qemu_irq handler);
+void omap_mpuio_key(struct omap_mpuio_s *s, int row, int col, int down);
+
+struct uWireSlave {
+    uint16_t (*receive)(void *opaque);
+    void (*send)(void *opaque, uint16_t data);
+    void *opaque;
+};
+struct omap_uwire_s;
+void omap_uwire_attach(struct omap_uwire_s *s,
+                uWireSlave *slave, int chipselect);
+
+/* OMAP2 spi */
+struct omap_mcspi_s;
+struct omap_mcspi_s *omap_mcspi_init(struct omap_target_agent_s *ta, int chnum,
+                qemu_irq irq, qemu_irq *drq, omap_clk fclk, omap_clk iclk);
+void omap_mcspi_attach(struct omap_mcspi_s *s,
+                uint32_t (*txrx)(void *opaque, uint32_t, int), void *opaque,
+                int chipselect);
+void omap_mcspi_reset(struct omap_mcspi_s *s);
+
+struct I2SCodec {
+    void *opaque;
+
+    /* The CPU can call this if it is generating the clock signal on the
+     * i2s port.  The CODEC can ignore it if it is set up as a clock
+     * master and generates its own clock.  */
+    void (*set_rate)(void *opaque, int in, int out);
+
+    void (*tx_swallow)(void *opaque);
+    qemu_irq rx_swallow;
+    qemu_irq tx_start;
+
+    int tx_rate;
+    int cts;
+    int rx_rate;
+    int rts;
+
+    struct i2s_fifo_s {
+        uint8_t *fifo;
+        int len;
+        int start;
+        int size;
+    } in, out;
+};
+struct omap_mcbsp_s;
+void omap_mcbsp_i2s_attach(struct omap_mcbsp_s *s, I2SCodec *slave);
+
+void omap_tap_init(struct omap_target_agent_s *ta,
+                struct omap_mpu_state_s *mpu);
+
+/* omap_lcdc.c */
+struct omap_lcd_panel_s;
+void omap_lcdc_reset(struct omap_lcd_panel_s *s);
+struct omap_lcd_panel_s *omap_lcdc_init(MemoryRegion *sysmem,
+                                        hwaddr base,
+                                        qemu_irq irq,
+                                        struct omap_dma_lcd_channel_s *dma,
+                                        omap_clk clk);
+
+/* omap_dss.c */
+struct rfbi_chip_s {
+    void *opaque;
+    void (*write)(void *opaque, int dc, uint16_t value);
+    void (*block)(void *opaque, int dc, void *buf, size_t len, int pitch);
+    uint16_t (*read)(void *opaque, int dc);
+};
+struct omap_dss_s;
+void omap_dss_reset(struct omap_dss_s *s);
+struct omap_dss_s *omap_dss_init(struct omap_target_agent_s *ta,
+                MemoryRegion *sysmem,
+                hwaddr l3_base,
+                qemu_irq irq, qemu_irq drq,
+                omap_clk fck1, omap_clk fck2, omap_clk ck54m,
+                omap_clk ick1, omap_clk ick2);
+void omap_rfbi_attach(struct omap_dss_s *s, int cs, struct rfbi_chip_s *chip);
+
+/* omap_mmc.c */
+struct omap_mmc_s;
+struct omap_mmc_s *omap_mmc_init(hwaddr base,
+                MemoryRegion *sysmem,
+                BlockDriverState *bd,
+                qemu_irq irq, qemu_irq dma[], omap_clk clk);
+struct omap_mmc_s *omap2_mmc_init(struct omap_target_agent_s *ta,
+                BlockDriverState *bd, qemu_irq irq, qemu_irq dma[],
+                omap_clk fclk, omap_clk iclk);
+void omap_mmc_reset(struct omap_mmc_s *s);
+void omap_mmc_handlers(struct omap_mmc_s *s, qemu_irq ro, qemu_irq cover);
+void omap_mmc_enable(struct omap_mmc_s *s, int enable);
+
+/* omap_i2c.c */
+i2c_bus *omap_i2c_bus(DeviceState *omap_i2c);
+
+# define cpu_is_omap310(cpu)           (cpu->mpu_model == omap310)
+# define cpu_is_omap1510(cpu)          (cpu->mpu_model == omap1510)
+# define cpu_is_omap1610(cpu)          (cpu->mpu_model == omap1610)
+# define cpu_is_omap1710(cpu)          (cpu->mpu_model == omap1710)
+# define cpu_is_omap2410(cpu)          (cpu->mpu_model == omap2410)
+# define cpu_is_omap2420(cpu)          (cpu->mpu_model == omap2420)
+# define cpu_is_omap2430(cpu)          (cpu->mpu_model == omap2430)
+# define cpu_is_omap3430(cpu)          (cpu->mpu_model == omap3430)
+# define cpu_is_omap3630(cpu)           (cpu->mpu_model == omap3630)
+
+# define cpu_is_omap15xx(cpu)          \
+        (cpu_is_omap310(cpu) || cpu_is_omap1510(cpu))
+# define cpu_is_omap16xx(cpu)          \
+        (cpu_is_omap1610(cpu) || cpu_is_omap1710(cpu))
+# define cpu_is_omap24xx(cpu)          \
+        (cpu_is_omap2410(cpu) || cpu_is_omap2420(cpu) || cpu_is_omap2430(cpu))
+
+# define cpu_class_omap1(cpu)          \
+        (cpu_is_omap15xx(cpu) || cpu_is_omap16xx(cpu))
+# define cpu_class_omap2(cpu)          cpu_is_omap24xx(cpu)
+# define cpu_class_omap3(cpu) \
+        (cpu_is_omap3430(cpu) || cpu_is_omap3630(cpu))
+
+struct omap_mpu_state_s {
+    enum omap_mpu_model {
+        omap310,
+        omap1510,
+        omap1610,
+        omap1710,
+        omap2410,
+        omap2420,
+        omap2422,
+        omap2423,
+        omap2430,
+        omap3430,
+        omap3630,
+    } mpu_model;
+
+    ARMCPU *cpu;
+
+    qemu_irq *drq;
+
+    qemu_irq wakeup;
+
+    MemoryRegion ulpd_pm_iomem;
+    MemoryRegion pin_cfg_iomem;
+    MemoryRegion id_iomem;
+    MemoryRegion id_iomem_e18;
+    MemoryRegion id_iomem_ed4;
+    MemoryRegion id_iomem_e20;
+    MemoryRegion mpui_iomem;
+    MemoryRegion tcmi_iomem;
+    MemoryRegion clkm_iomem;
+    MemoryRegion clkdsp_iomem;
+    MemoryRegion mpui_io_iomem;
+    MemoryRegion tap_iomem;
+    MemoryRegion imif_ram;
+    MemoryRegion emiff_ram;
+    MemoryRegion sdram;
+    MemoryRegion sram;
+
+    struct omap_dma_port_if_s {
+        uint32_t (*read[3])(struct omap_mpu_state_s *s,
+                        hwaddr offset);
+        void (*write[3])(struct omap_mpu_state_s *s,
+                        hwaddr offset, uint32_t value);
+        int (*addr_valid)(struct omap_mpu_state_s *s,
+                        hwaddr addr);
+    } port[__omap_dma_port_last];
+
+    unsigned long sdram_size;
+    unsigned long sram_size;
+
+    /* MPUI-TIPB peripherals */
+    struct omap_uart_s *uart[3];
+
+    DeviceState *gpio;
+
+    struct omap_mcbsp_s *mcbsp1;
+    struct omap_mcbsp_s *mcbsp3;
+
+    /* MPU public TIPB peripherals */
+    struct omap_32khz_timer_s *os_timer;
+
+    struct omap_mmc_s *mmc;
+
+    struct omap_mpuio_s *mpuio;
+
+    struct omap_uwire_s *microwire;
+
+    struct omap_pwl_s *pwl;
+    struct omap_pwt_s *pwt;
+    DeviceState *i2c[2];
+
+    struct omap_rtc_s *rtc;
+
+    struct omap_mcbsp_s *mcbsp2;
+
+    struct omap_lpg_s *led[2];
+
+    /* MPU private TIPB peripherals */
+    DeviceState *ih[2];
+
+    struct soc_dma_s *dma;
+
+    struct omap_mpu_timer_s *timer[3];
+    struct omap_watchdog_timer_s *wdt;
+
+    struct omap_lcd_panel_s *lcd;
+
+    uint32_t ulpd_pm_regs[21];
+    int64_t ulpd_gauge_start;
+
+    uint32_t func_mux_ctrl[14];
+    uint32_t comp_mode_ctrl[1];
+    uint32_t pull_dwn_ctrl[4];
+    uint32_t gate_inh_ctrl[1];
+    uint32_t voltage_ctrl[1];
+    uint32_t test_dbg_ctrl[1];
+    uint32_t mod_conf_ctrl[1];
+    int compat1509;
+
+    uint32_t mpui_ctrl;
+
+    struct omap_tipb_bridge_s *private_tipb;
+    struct omap_tipb_bridge_s *public_tipb;
+
+    uint32_t tcmi_regs[17];
+
+    struct dpll_ctl_s *dpll[3];
+
+    omap_clk clks;
+    struct {
+        int cold_start;
+        int clocking_scheme;
+        uint16_t arm_ckctl;
+        uint16_t arm_idlect1;
+        uint16_t arm_idlect2;
+        uint16_t arm_ewupct;
+        uint16_t arm_rstct1;
+        uint16_t arm_rstct2;
+        uint16_t arm_ckout1;
+        int dpll1_mode;
+        uint16_t dsp_idlect1;
+        uint16_t dsp_idlect2;
+        uint16_t dsp_rstct2;
+    } clkm;
+
+    /* OMAP2-only peripherals */
+    struct omap_l4_s *l4;
+
+    struct omap_gp_timer_s *gptimer[12];
+    struct omap_synctimer_s *synctimer;
+
+    struct omap_prcm_s *prcm;
+    struct omap_sdrc_s *sdrc;
+    struct omap_gpmc_s *gpmc;
+    struct omap_sysctl_s *sysc;
+
+    struct omap_mcspi_s *mcspi[2];
+
+    struct omap_dss_s *dss;
+
+    struct omap_eac_s *eac;
+};
+
+/* omap1.c */
+struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *system_memory,
+                unsigned long sdram_size,
+                const char *core);
+
+/* omap2.c */
+struct omap_mpu_state_s *omap2420_mpu_init(MemoryRegion *sysmem,
+                unsigned long sdram_size,
+                const char *core);
+
+#define OMAP_FMT_plx "%#08" HWADDR_PRIx
+
+uint32_t omap_badwidth_read8(void *opaque, hwaddr addr);
+void omap_badwidth_write8(void *opaque, hwaddr addr,
+                uint32_t value);
+uint32_t omap_badwidth_read16(void *opaque, hwaddr addr);
+void omap_badwidth_write16(void *opaque, hwaddr addr,
+                uint32_t value);
+uint32_t omap_badwidth_read32(void *opaque, hwaddr addr);
+void omap_badwidth_write32(void *opaque, hwaddr addr,
+                uint32_t value);
+
+void omap_mpu_wakeup(void *opaque, int irq, int req);
+
+# define OMAP_BAD_REG(paddr)           \
+        fprintf(stderr, "%s: Bad register " OMAP_FMT_plx "\n", \
+                        __FUNCTION__, paddr)
+# define OMAP_RO_REG(paddr)            \
+        fprintf(stderr, "%s: Read-only register " OMAP_FMT_plx "\n",   \
+                        __FUNCTION__, paddr)
+
+/* OMAP-specific Linux bootloader tags for the ATAG_BOARD area
+   (Board-specifc tags are not here)  */
+#define OMAP_TAG_CLOCK         0x4f01
+#define OMAP_TAG_MMC           0x4f02
+#define OMAP_TAG_SERIAL_CONSOLE        0x4f03
+#define OMAP_TAG_USB           0x4f04
+#define OMAP_TAG_LCD           0x4f05
+#define OMAP_TAG_GPIO_SWITCH   0x4f06
+#define OMAP_TAG_UART          0x4f07
+#define OMAP_TAG_FBMEM         0x4f08
+#define OMAP_TAG_STI_CONSOLE   0x4f09
+#define OMAP_TAG_CAMERA_SENSOR 0x4f0a
+#define OMAP_TAG_PARTITION     0x4f0b
+#define OMAP_TAG_TEA5761       0x4f10
+#define OMAP_TAG_TMP105                0x4f11
+#define OMAP_TAG_BOOT_REASON   0x4f80
+#define OMAP_TAG_FLASH_PART_STR        0x4f81
+#define OMAP_TAG_VERSION_STR   0x4f82
+
+enum {
+    OMAP_GPIOSW_TYPE_COVER     = 0 << 4,
+    OMAP_GPIOSW_TYPE_CONNECTION        = 1 << 4,
+    OMAP_GPIOSW_TYPE_ACTIVITY  = 2 << 4,
+};
+
+#define OMAP_GPIOSW_INVERTED   0x0001
+#define OMAP_GPIOSW_OUTPUT     0x0002
+
+# define TCMI_VERBOSE                  1
+
+# ifdef TCMI_VERBOSE
+#  define OMAP_8B_REG(paddr)           \
+        fprintf(stderr, "%s: 8-bit register " OMAP_FMT_plx "\n",       \
+                        __FUNCTION__, paddr)
+#  define OMAP_16B_REG(paddr)          \
+        fprintf(stderr, "%s: 16-bit register " OMAP_FMT_plx "\n",      \
+                        __FUNCTION__, paddr)
+#  define OMAP_32B_REG(paddr)          \
+        fprintf(stderr, "%s: 32-bit register " OMAP_FMT_plx "\n",      \
+                        __FUNCTION__, paddr)
+# else
+#  define OMAP_8B_REG(paddr)
+#  define OMAP_16B_REG(paddr)
+#  define OMAP_32B_REG(paddr)
+# endif
+
+# define OMAP_MPUI_REG_MASK            0x000007ff
+
+#endif /* hw_omap_h */
diff --git a/include/hw/arm/primecell.h b/include/hw/arm/primecell.h
new file mode 100644 (file)
index 0000000..7337c3b
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef PRIMECELL_H
+#define PRIMECELL_H
+
+/* Declarations for ARM PrimeCell based periperals.  */
+/* Also includes some devices that are currently only used by the
+   ARM boards.  */
+
+/* arm_sysctl GPIO lines */
+#define ARM_SYSCTL_GPIO_MMC_WPROT 0
+#define ARM_SYSCTL_GPIO_MMC_CARDIN 1
+
+#endif
diff --git a/include/hw/arm/pxa.h b/include/hw/arm/pxa.h
new file mode 100644 (file)
index 0000000..668232c
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+ * Intel XScale PXA255/270 processor support.
+ *
+ * Copyright (c) 2006 Openedhand Ltd.
+ * Written by Andrzej Zaborowski <balrog@zabor.org>
+ *
+ * This code is licensed under the GNU GPL v2.
+ */
+#ifndef PXA_H
+# define PXA_H                 "pxa.h"
+
+#include "exec/memory.h"
+
+/* Interrupt numbers */
+# define PXA2XX_PIC_SSP3       0
+# define PXA2XX_PIC_USBH2      2
+# define PXA2XX_PIC_USBH1      3
+# define PXA2XX_PIC_KEYPAD     4
+# define PXA2XX_PIC_PWRI2C     6
+# define PXA25X_PIC_HWUART     7
+# define PXA27X_PIC_OST_4_11   7
+# define PXA2XX_PIC_GPIO_0     8
+# define PXA2XX_PIC_GPIO_1     9
+# define PXA2XX_PIC_GPIO_X     10
+# define PXA2XX_PIC_I2S        13
+# define PXA26X_PIC_ASSP       15
+# define PXA25X_PIC_NSSP       16
+# define PXA27X_PIC_SSP2       16
+# define PXA2XX_PIC_LCD                17
+# define PXA2XX_PIC_I2C                18
+# define PXA2XX_PIC_ICP                19
+# define PXA2XX_PIC_STUART     20
+# define PXA2XX_PIC_BTUART     21
+# define PXA2XX_PIC_FFUART     22
+# define PXA2XX_PIC_MMC                23
+# define PXA2XX_PIC_SSP                24
+# define PXA2XX_PIC_DMA                25
+# define PXA2XX_PIC_OST_0      26
+# define PXA2XX_PIC_RTC1HZ     30
+# define PXA2XX_PIC_RTCALARM   31
+
+/* DMA requests */
+# define PXA2XX_RX_RQ_I2S      2
+# define PXA2XX_TX_RQ_I2S      3
+# define PXA2XX_RX_RQ_BTUART   4
+# define PXA2XX_TX_RQ_BTUART   5
+# define PXA2XX_RX_RQ_FFUART   6
+# define PXA2XX_TX_RQ_FFUART   7
+# define PXA2XX_RX_RQ_SSP1     13
+# define PXA2XX_TX_RQ_SSP1     14
+# define PXA2XX_RX_RQ_SSP2     15
+# define PXA2XX_TX_RQ_SSP2     16
+# define PXA2XX_RX_RQ_ICP      17
+# define PXA2XX_TX_RQ_ICP      18
+# define PXA2XX_RX_RQ_STUART   19
+# define PXA2XX_TX_RQ_STUART   20
+# define PXA2XX_RX_RQ_MMCI     21
+# define PXA2XX_TX_RQ_MMCI     22
+# define PXA2XX_USB_RQ(x)      ((x) + 24)
+# define PXA2XX_RX_RQ_SSP3     66
+# define PXA2XX_TX_RQ_SSP3     67
+
+# define PXA2XX_SDRAM_BASE     0xa0000000
+# define PXA2XX_INTERNAL_BASE  0x5c000000
+# define PXA2XX_INTERNAL_SIZE  0x40000
+
+/* pxa2xx_pic.c */
+DeviceState *pxa2xx_pic_init(hwaddr base, ARMCPU *cpu);
+
+/* pxa2xx_gpio.c */
+DeviceState *pxa2xx_gpio_init(hwaddr base,
+                              ARMCPU *cpu, DeviceState *pic, int lines);
+void pxa2xx_gpio_read_notifier(DeviceState *dev, qemu_irq handler);
+
+/* pxa2xx_dma.c */
+DeviceState *pxa255_dma_init(hwaddr base, qemu_irq irq);
+DeviceState *pxa27x_dma_init(hwaddr base, qemu_irq irq);
+
+/* pxa2xx_lcd.c */
+typedef struct PXA2xxLCDState PXA2xxLCDState;
+PXA2xxLCDState *pxa2xx_lcdc_init(MemoryRegion *sysmem,
+                hwaddr base, qemu_irq irq);
+void pxa2xx_lcd_vsync_notifier(PXA2xxLCDState *s, qemu_irq handler);
+void pxa2xx_lcdc_oritentation(void *opaque, int angle);
+
+/* pxa2xx_mmci.c */
+typedef struct PXA2xxMMCIState PXA2xxMMCIState;
+PXA2xxMMCIState *pxa2xx_mmci_init(MemoryRegion *sysmem,
+                hwaddr base,
+                BlockDriverState *bd, qemu_irq irq,
+                qemu_irq rx_dma, qemu_irq tx_dma);
+void pxa2xx_mmci_handlers(PXA2xxMMCIState *s, qemu_irq readonly,
+                qemu_irq coverswitch);
+
+/* pxa2xx_pcmcia.c */
+typedef struct PXA2xxPCMCIAState PXA2xxPCMCIAState;
+PXA2xxPCMCIAState *pxa2xx_pcmcia_init(MemoryRegion *sysmem,
+                                      hwaddr base);
+int pxa2xx_pcmcia_attach(void *opaque, PCMCIACardState *card);
+int pxa2xx_pcmcia_dettach(void *opaque);
+void pxa2xx_pcmcia_set_irq_cb(void *opaque, qemu_irq irq, qemu_irq cd_irq);
+
+/* pxa2xx_keypad.c */
+struct  keymap {
+    int column;
+    int row;
+};
+typedef struct PXA2xxKeyPadState PXA2xxKeyPadState;
+PXA2xxKeyPadState *pxa27x_keypad_init(MemoryRegion *sysmem,
+                                      hwaddr base,
+                                      qemu_irq irq);
+void pxa27x_register_keypad(PXA2xxKeyPadState *kp, struct keymap *map,
+                int size);
+
+/* pxa2xx.c */
+typedef struct PXA2xxI2CState PXA2xxI2CState;
+PXA2xxI2CState *pxa2xx_i2c_init(hwaddr base,
+                qemu_irq irq, uint32_t page_size);
+i2c_bus *pxa2xx_i2c_bus(PXA2xxI2CState *s);
+
+typedef struct PXA2xxI2SState PXA2xxI2SState;
+typedef struct PXA2xxFIrState PXA2xxFIrState;
+
+typedef struct {
+    ARMCPU *cpu;
+    DeviceState *pic;
+    qemu_irq reset;
+    MemoryRegion sdram;
+    MemoryRegion internal;
+    MemoryRegion cm_iomem;
+    MemoryRegion mm_iomem;
+    MemoryRegion pm_iomem;
+    DeviceState *dma;
+    DeviceState *gpio;
+    PXA2xxLCDState *lcd;
+    SSIBus **ssp;
+    PXA2xxI2CState *i2c[2];
+    PXA2xxMMCIState *mmc;
+    PXA2xxPCMCIAState *pcmcia[2];
+    PXA2xxI2SState *i2s;
+    PXA2xxFIrState *fir;
+    PXA2xxKeyPadState *kp;
+
+    /* Power management */
+    hwaddr pm_base;
+    uint32_t pm_regs[0x40];
+
+    /* Clock management */
+    hwaddr cm_base;
+    uint32_t cm_regs[4];
+    uint32_t clkcfg;
+
+    /* Memory management */
+    hwaddr mm_base;
+    uint32_t mm_regs[0x1a];
+
+    /* Performance monitoring */
+    uint32_t pmnc;
+} PXA2xxState;
+
+struct PXA2xxI2SState {
+    MemoryRegion iomem;
+    qemu_irq irq;
+    qemu_irq rx_dma;
+    qemu_irq tx_dma;
+    void (*data_req)(void *, int, int);
+
+    uint32_t control[2];
+    uint32_t status;
+    uint32_t mask;
+    uint32_t clk;
+
+    int enable;
+    int rx_len;
+    int tx_len;
+    void (*codec_out)(void *, uint32_t);
+    uint32_t (*codec_in)(void *);
+    void *opaque;
+
+    int fifo_len;
+    uint32_t fifo[16];
+};
+
+# define PA_FMT                        "0x%08lx"
+# define REG_FMT               "0x" TARGET_FMT_plx
+
+PXA2xxState *pxa270_init(MemoryRegion *address_space, unsigned int sdram_size,
+                         const char *revision);
+PXA2xxState *pxa255_init(MemoryRegion *address_space, unsigned int sdram_size);
+
+#endif /* PXA_H */
diff --git a/include/hw/arm/sharpsl.h b/include/hw/arm/sharpsl.h
new file mode 100644 (file)
index 0000000..13981a6
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * Common declarations for the Zaurii.
+ *
+ * This file is licensed under the GNU GPL.
+ */
+#ifndef QEMU_SHARPSL_H
+#define QEMU_SHARPSL_H
+
+#define zaurus_printf(format, ...)     \
+    fprintf(stderr, "%s: " format, __FUNCTION__, ##__VA_ARGS__)
+
+/* zaurus.c */
+
+#define SL_PXA_PARAM_BASE      0xa0000a00
+void sl_bootparam_write(hwaddr ptr);
+
+#endif
diff --git a/include/hw/arm/soc_dma.h b/include/hw/arm/soc_dma.h
new file mode 100644 (file)
index 0000000..7379731
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * On-chip DMA controller framework.
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ * Written by Andrzej Zaborowski <andrew@openedhand.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 or
+ * (at your option) version 3 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
+ * 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 HW_SOC_DMA_H
+#define HW_SOC_DMA_H 1
+
+
+#include "exec/memory.h"
+#include "hw/irq.h"
+
+struct soc_dma_s;
+struct soc_dma_ch_s;
+typedef void (*soc_dma_io_t)(void *opaque, uint8_t *buf, int len);
+typedef void (*soc_dma_transfer_t)(struct soc_dma_ch_s *ch);
+
+enum soc_dma_port_type {
+    soc_dma_port_mem,
+    soc_dma_port_fifo,
+    soc_dma_port_other,
+};
+
+enum soc_dma_access_type {
+    soc_dma_access_const,
+    soc_dma_access_linear,
+    soc_dma_access_other,
+};
+
+struct soc_dma_ch_s {
+    /* Private */
+    struct soc_dma_s *dma;
+    int num;
+    QEMUTimer *timer;
+
+    /* Set by soc_dma.c */
+    int enable;
+    int update;
+
+    /* This should be set by dma->setup_fn().  */
+    int bytes;
+    /* Initialised by the DMA module, call soc_dma_ch_update after writing.  */
+    enum soc_dma_access_type type[2];
+    hwaddr vaddr[2];   /* Updated by .transfer_fn().  */
+    /* Private */
+    void *paddr[2];
+    soc_dma_io_t io_fn[2];
+    void *io_opaque[2];
+
+    int running;
+    soc_dma_transfer_t transfer_fn;
+
+    /* Set and used by the DMA module.  */
+    void *opaque;
+};
+
+struct soc_dma_s {
+    /* Following fields are set by the SoC DMA module and can be used
+     * by anybody.  */
+    uint64_t drqbmp;   /* Is zeroed by soc_dma_reset() */
+    qemu_irq *drq;
+    void *opaque;
+    int64_t freq;
+    soc_dma_transfer_t transfer_fn;
+    soc_dma_transfer_t setup_fn;
+    /* Set by soc_dma_init() for use by the DMA module.  */
+    struct soc_dma_ch_s *ch;
+};
+
+/* Call to activate or stop a DMA channel.  */
+void soc_dma_set_request(struct soc_dma_ch_s *ch, int level);
+/* Call after every write to one of the following fields and before
+ * calling soc_dma_set_request(ch, 1):
+ *   ch->type[0...1],
+ *   ch->vaddr[0...1],
+ *   ch->paddr[0...1],
+ * or after a soc_dma_port_add_fifo() or soc_dma_port_add_mem().  */
+void soc_dma_ch_update(struct soc_dma_ch_s *ch);
+
+/* The SoC should call this when the DMA module is being reset.  */
+void soc_dma_reset(struct soc_dma_s *s);
+struct soc_dma_s *soc_dma_init(int n);
+
+void soc_dma_port_add_fifo(struct soc_dma_s *dma, hwaddr virt_base,
+                soc_dma_io_t fn, void *opaque, int out);
+void soc_dma_port_add_mem(struct soc_dma_s *dma, uint8_t *phys_base,
+                hwaddr virt_base, size_t size);
+
+static inline void soc_dma_port_add_fifo_in(struct soc_dma_s *dma,
+                hwaddr virt_base, soc_dma_io_t fn, void *opaque)
+{
+    return soc_dma_port_add_fifo(dma, virt_base, fn, opaque, 0);
+}
+
+static inline void soc_dma_port_add_fifo_out(struct soc_dma_s *dma,
+                hwaddr virt_base, soc_dma_io_t fn, void *opaque)
+{
+    return soc_dma_port_add_fifo(dma, virt_base, fn, opaque, 1);
+}
+
+#endif
diff --git a/include/hw/audio/audio.h b/include/hw/audio/audio.h
new file mode 100644 (file)
index 0000000..428274f
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef HW_AUDIODEV_H
+#define HW_AUDIODEV_H 1
+
+/* es1370.c */
+int es1370_init(PCIBus *bus);
+
+/* sb16.c */
+int SB16_init(ISABus *bus);
+
+/* adlib.c */
+int Adlib_init(ISABus *bus);
+
+/* gus.c */
+int GUS_init(ISABus *bus);
+
+/* ac97.c */
+int ac97_init(PCIBus *bus);
+
+/* cs4231a.c */
+int cs4231a_init(ISABus *bus);
+
+/* intel-hda.c + hda-audio.c */
+int intel_hda_and_codec_init(PCIBus *bus);
+
+#endif
diff --git a/include/hw/audio/pcspk.h b/include/hw/audio/pcspk.h
new file mode 100644 (file)
index 0000000..ce8ef4f
--- /dev/null
@@ -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/hw.h"
+#include "hw/isa/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 */
diff --git a/include/hw/block/block.h b/include/hw/block/block.h
new file mode 100644 (file)
index 0000000..dd11532
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Common code for block device models
+ *
+ * Copyright (C) 2012 Red Hat, Inc.
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ *
+ * 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 HW_BLOCK_COMMON_H
+#define HW_BLOCK_COMMON_H
+
+#include "qemu-common.h"
+
+/* Configuration */
+
+typedef struct BlockConf {
+    BlockDriverState *bs;
+    uint16_t physical_block_size;
+    uint16_t logical_block_size;
+    uint16_t min_io_size;
+    uint32_t opt_io_size;
+    int32_t bootindex;
+    uint32_t discard_granularity;
+    /* geometry, not all devices use this */
+    uint32_t cyls, heads, secs;
+} BlockConf;
+
+static inline unsigned int get_physical_block_exp(BlockConf *conf)
+{
+    unsigned int exp = 0, size;
+
+    for (size = conf->physical_block_size;
+        size > conf->logical_block_size;
+        size >>= 1) {
+        exp++;
+    }
+
+    return exp;
+}
+
+#define DEFINE_BLOCK_PROPERTIES(_state, _conf)                          \
+    DEFINE_PROP_DRIVE("drive", _state, _conf.bs),                       \
+    DEFINE_PROP_BLOCKSIZE("logical_block_size", _state,                 \
+                          _conf.logical_block_size, 512),               \
+    DEFINE_PROP_BLOCKSIZE("physical_block_size", _state,                \
+                          _conf.physical_block_size, 512),              \
+    DEFINE_PROP_UINT16("min_io_size", _state, _conf.min_io_size, 0),  \
+    DEFINE_PROP_UINT32("opt_io_size", _state, _conf.opt_io_size, 0),    \
+    DEFINE_PROP_INT32("bootindex", _state, _conf.bootindex, -1),        \
+    DEFINE_PROP_UINT32("discard_granularity", _state, \
+                       _conf.discard_granularity, -1)
+
+#define DEFINE_BLOCK_CHS_PROPERTIES(_state, _conf)      \
+    DEFINE_PROP_UINT32("cyls", _state, _conf.cyls, 0),  \
+    DEFINE_PROP_UINT32("heads", _state, _conf.heads, 0), \
+    DEFINE_PROP_UINT32("secs", _state, _conf.secs, 0)
+
+/* Configuration helpers */
+
+void blkconf_serial(BlockConf *conf, char **serial);
+int blkconf_geometry(BlockConf *conf, int *trans,
+                     unsigned cyls_max, unsigned heads_max, unsigned secs_max);
+
+/* Hard disk geometry */
+
+#define BIOS_ATA_TRANSLATION_AUTO   0
+#define BIOS_ATA_TRANSLATION_NONE   1
+#define BIOS_ATA_TRANSLATION_LBA    2
+#define BIOS_ATA_TRANSLATION_LARGE  3
+#define BIOS_ATA_TRANSLATION_RECHS  4
+
+void hd_geometry_guess(BlockDriverState *bs,
+                       uint32_t *pcyls, uint32_t *pheads, uint32_t *psecs,
+                       int *ptrans);
+int hd_bios_chs_auto_trans(uint32_t cyls, uint32_t heads, uint32_t secs);
+
+#endif
diff --git a/include/hw/block/fdc.h b/include/hw/block/fdc.h
new file mode 100644 (file)
index 0000000..a8f6f7c
--- /dev/null
@@ -0,0 +1,24 @@
+#ifndef HW_FDC_H
+#define HW_FDC_H
+
+#include "qemu-common.h"
+
+/* fdc.c */
+#define MAX_FD 2
+
+typedef enum FDriveType {
+    FDRIVE_DRV_144  = 0x00,   /* 1.44 MB 3"5 drive      */
+    FDRIVE_DRV_288  = 0x01,   /* 2.88 MB 3"5 drive      */
+    FDRIVE_DRV_120  = 0x02,   /* 1.2  MB 5"25 drive     */
+    FDRIVE_DRV_NONE = 0x03,   /* No drive connected     */
+} FDriveType;
+
+ISADevice *fdctrl_init_isa(ISABus *bus, DriveInfo **fds);
+void fdctrl_init_sysbus(qemu_irq irq, int dma_chann,
+                        hwaddr mmio_base, DriveInfo **fds);
+void sun4m_fdctrl_init(qemu_irq irq, hwaddr io_base,
+                       DriveInfo **fds, qemu_irq *fdc_tc);
+
+FDriveType isa_fdc_get_drive_type(ISADevice *fdc, int i);
+
+#endif
diff --git a/include/hw/block/flash.h b/include/hw/block/flash.h
new file mode 100644 (file)
index 0000000..920d759
--- /dev/null
@@ -0,0 +1,64 @@
+#ifndef HW_FLASH_H
+#define HW_FLASH_H 1
+
+/* NOR flash devices */
+
+#include "exec/memory.h"
+
+typedef struct pflash_t pflash_t;
+
+/* pflash_cfi01.c */
+pflash_t *pflash_cfi01_register(hwaddr base,
+                                DeviceState *qdev, const char *name,
+                                hwaddr size,
+                                BlockDriverState *bs,
+                                uint32_t sector_len, int nb_blocs, int width,
+                                uint16_t id0, uint16_t id1,
+                                uint16_t id2, uint16_t id3, int be);
+
+/* pflash_cfi02.c */
+pflash_t *pflash_cfi02_register(hwaddr base,
+                                DeviceState *qdev, const char *name,
+                                hwaddr size,
+                                BlockDriverState *bs, uint32_t sector_len,
+                                int nb_blocs, int nb_mappings, int width,
+                                uint16_t id0, uint16_t id1,
+                                uint16_t id2, uint16_t id3,
+                                uint16_t unlock_addr0, uint16_t unlock_addr1,
+                                int be);
+
+MemoryRegion *pflash_cfi01_get_memory(pflash_t *fl);
+
+/* nand.c */
+DeviceState *nand_init(BlockDriverState *bdrv, int manf_id, int chip_id);
+void nand_setpins(DeviceState *dev, uint8_t cle, uint8_t ale,
+                  uint8_t ce, uint8_t wp, uint8_t gnd);
+void nand_getpins(DeviceState *dev, int *rb);
+void nand_setio(DeviceState *dev, uint32_t value);
+uint32_t nand_getio(DeviceState *dev);
+uint32_t nand_getbuswidth(DeviceState *dev);
+
+#define NAND_MFR_TOSHIBA       0x98
+#define NAND_MFR_SAMSUNG       0xec
+#define NAND_MFR_FUJITSU       0x04
+#define NAND_MFR_NATIONAL      0x8f
+#define NAND_MFR_RENESAS       0x07
+#define NAND_MFR_STMICRO       0x20
+#define NAND_MFR_HYNIX         0xad
+#define NAND_MFR_MICRON                0x2c
+
+/* onenand.c */
+void *onenand_raw_otp(DeviceState *onenand_device);
+
+/* ecc.c */
+typedef struct {
+    uint8_t cp;                /* Column parity */
+    uint16_t lp[2];    /* Line parity */
+    uint16_t count;
+} ECCState;
+
+uint8_t ecc_digest(ECCState *s, uint8_t sample);
+void ecc_reset(ECCState *s);
+extern VMStateDescription vmstate_ecc_state;
+
+#endif
diff --git a/include/hw/boards.h b/include/hw/boards.h
new file mode 100644 (file)
index 0000000..425bdc7
--- /dev/null
@@ -0,0 +1,53 @@
+/* Declarations for use by board files for creating devices.  */
+
+#ifndef HW_BOARDS_H
+#define HW_BOARDS_H
+
+#include "sysemu/blockdev.h"
+#include "hw/qdev.h"
+
+#define DEFAULT_MACHINE_OPTIONS \
+    .boot_order = "cad"
+
+typedef struct QEMUMachineInitArgs {
+    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;
+} QEMUMachineInitArgs;
+
+typedef void QEMUMachineInitFunc(QEMUMachineInitArgs *args);
+
+typedef void QEMUMachineResetFunc(void);
+
+typedef struct QEMUMachine {
+    const char *name;
+    const char *alias;
+    const char *desc;
+    QEMUMachineInitFunc *init;
+    QEMUMachineResetFunc *reset;
+    BlockInterfaceType block_default_type;
+    int max_cpus;
+    unsigned int no_serial:1,
+        no_parallel:1,
+        use_virtcon:1,
+        use_sclp:1,
+        no_floppy:1,
+        no_cdrom:1,
+        no_sdcard:1;
+    int is_default;
+    const char *default_machine_opts;
+    const char *boot_order;
+    GlobalProperty *compat_props;
+    struct QEMUMachine *next;
+    const char *hw_version;
+} QEMUMachine;
+
+int qemu_register_machine(QEMUMachine *m);
+QEMUMachine *find_default_machine(void);
+
+extern QEMUMachine *current_machine;
+
+#endif
diff --git a/include/hw/bt.h b/include/hw/bt.h
new file mode 100644 (file)
index 0000000..830af94
--- /dev/null
@@ -0,0 +1,2190 @@
+/*
+ * QEMU Bluetooth HCI helpers.
+ *
+ * Copyright (C) 2007 OpenMoko, Inc.
+ * Written by Andrzej Zaborowski <andrew@openedhand.com>
+ *
+ * Useful definitions taken from BlueZ project's headers.
+ * Copyright (C) 2000-2001  Qualcomm Incorporated
+ * Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com>
+ * Copyright (C) 2002-2006  Marcel Holtmann <marcel@holtmann.org>
+ *
+ * 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 HW_BT_H
+#define HW_BT_H 1
+
+#include "hw/irq.h"
+
+/* BD Address */
+typedef struct {
+    uint8_t b[6];
+} QEMU_PACKED bdaddr_t;
+
+#define BDADDR_ANY     (&(bdaddr_t) {{0, 0, 0, 0, 0, 0}})
+#define BDADDR_ALL     (&(bdaddr_t) {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}})
+#define BDADDR_LOCAL   (&(bdaddr_t) {{0, 0, 0, 0xff, 0xff, 0xff}})
+
+/* Copy, swap, convert BD Address */
+static inline int bacmp(const bdaddr_t *ba1, const bdaddr_t *ba2)
+{
+    return memcmp(ba1, ba2, sizeof(bdaddr_t));
+}
+static inline void bacpy(bdaddr_t *dst, const bdaddr_t *src)
+{
+    memcpy(dst, src, sizeof(bdaddr_t));
+}
+
+#define BAINIT(orig)   { .b = {                \
+    (orig)->b[0], (orig)->b[1], (orig)->b[2],  \
+    (orig)->b[3], (orig)->b[4], (orig)->b[5],  \
+}, }
+
+/* The twisted structures of a bluetooth environment */
+struct bt_device_s;
+struct bt_scatternet_s;
+struct bt_piconet_s;
+struct bt_link_s;
+
+struct bt_scatternet_s {
+    struct bt_device_s *slave;
+};
+
+struct bt_link_s {
+    struct bt_device_s *slave, *host;
+    uint16_t handle;           /* Master (host) side handle */
+    uint16_t acl_interval;
+    enum {
+        acl_active,
+        acl_hold,
+        acl_sniff,
+        acl_parked,
+    } acl_mode;
+};
+
+struct bt_device_s {
+    int lt_addr;
+    bdaddr_t bd_addr;
+    int mtu;
+    int setup;
+    struct bt_scatternet_s *net;
+
+    uint8_t key[16];
+    int key_present;
+    uint8_t class[3];
+
+    uint8_t reject_reason;
+
+    uint64_t lmp_caps;
+    const char *lmp_name;
+    void (*lmp_connection_request)(struct bt_link_s *link);
+    void (*lmp_connection_complete)(struct bt_link_s *link);
+    void (*lmp_disconnect_master)(struct bt_link_s *link);
+    void (*lmp_disconnect_slave)(struct bt_link_s *link);
+    void (*lmp_acl_data)(struct bt_link_s *link, const uint8_t *data,
+                    int start, int len);
+    void (*lmp_acl_resp)(struct bt_link_s *link, const uint8_t *data,
+                    int start, int len);
+    void (*lmp_mode_change)(struct bt_link_s *link);
+
+    void (*handle_destroy)(struct bt_device_s *device);
+    struct bt_device_s *next;  /* Next in the piconet/scatternet */
+
+    int inquiry_scan;
+    int page_scan;
+
+    uint16_t clkoff;   /* Note: Always little-endian */
+};
+
+/* bt.c */
+void bt_device_init(struct bt_device_s *dev, struct bt_scatternet_s *net);
+void bt_device_done(struct bt_device_s *dev);
+
+/* bt-hci.c */
+struct HCIInfo *bt_new_hci(struct bt_scatternet_s *net);
+
+/* bt-vhci.c */
+void bt_vhci_init(struct HCIInfo *info);
+
+/* bt-hci-csr.c */
+enum {
+    csrhci_pin_reset,
+    csrhci_pin_wakeup,
+    __csrhci_pins,
+};
+qemu_irq *csrhci_pins_get(CharDriverState *chr);
+CharDriverState *uart_hci_init(qemu_irq wakeup);
+
+/* bt-l2cap.c */
+struct bt_l2cap_device_s;
+struct bt_l2cap_conn_params_s;
+struct bt_l2cap_psm_s;
+void bt_l2cap_device_init(struct bt_l2cap_device_s *dev,
+                struct bt_scatternet_s *net);
+void bt_l2cap_device_done(struct bt_l2cap_device_s *dev);
+void bt_l2cap_psm_register(struct bt_l2cap_device_s *dev, int psm,
+                int min_mtu, int (*new_channel)(struct bt_l2cap_device_s *dev,
+                        struct bt_l2cap_conn_params_s *params));
+
+struct bt_l2cap_device_s {
+    struct bt_device_s device;
+    struct bt_l2cap_psm_s *first_psm;
+};
+
+struct bt_l2cap_conn_params_s {
+    /* Input */
+    uint8_t *(*sdu_out)(struct bt_l2cap_conn_params_s *chan, int len);
+    void (*sdu_submit)(struct bt_l2cap_conn_params_s *chan);
+    int remote_mtu;
+    /* Output */
+    void *opaque;
+    void (*sdu_in)(void *opaque, const uint8_t *data, int len);
+    void (*close)(void *opaque);
+};
+
+enum bt_l2cap_psm_predef {
+    BT_PSM_SDP         = 0x0001,
+    BT_PSM_RFCOMM      = 0x0003,
+    BT_PSM_TELEPHONY   = 0x0005,
+    BT_PSM_TCS         = 0x0007,
+    BT_PSM_BNEP                = 0x000f,
+    BT_PSM_HID_CTRL    = 0x0011,
+    BT_PSM_HID_INTR    = 0x0013,
+    BT_PSM_UPNP                = 0x0015,
+    BT_PSM_AVCTP       = 0x0017,
+    BT_PSM_AVDTP       = 0x0019,
+};
+
+/* bt-sdp.c */
+void bt_l2cap_sdp_init(struct bt_l2cap_device_s *dev);
+
+/* bt-hid.c */
+struct bt_device_s *bt_mouse_init(struct bt_scatternet_s *net);
+struct bt_device_s *bt_tablet_init(struct bt_scatternet_s *net);
+struct bt_device_s *bt_keyboard_init(struct bt_scatternet_s *net);
+
+/* Link Management Protocol layer defines */
+
+#define LLID_ACLU_CONT         0x1
+#define LLID_ACLU_START                0x2
+#define LLID_ACLC              0x3
+
+enum lmp_pdu_type {
+    LMP_NAME_REQ               = 0x0001,
+    LMP_NAME_RES               = 0x0002,
+    LMP_ACCEPTED               = 0x0003,
+    LMP_NOT_ACCEPTED           = 0x0004,
+    LMP_CLKOFFSET_REQ          = 0x0005,
+    LMP_CLKOFFSET_RES          = 0x0006,
+    LMP_DETACH                 = 0x0007,
+    LMP_IN_RAND                        = 0x0008,
+    LMP_COMB_KEY               = 0x0009,
+    LMP_UNIT_KEY               = 0x000a,
+    LMP_AU_RAND                        = 0x000b,
+    LMP_SRES                   = 0x000c,
+    LMP_TEMP_RAND              = 0x000d,
+    LMP_TEMP_KEY               = 0x000e,
+    LMP_CRYPT_MODE_REQ         = 0x000f,
+    LMP_CRYPT_KEY_SIZE_REQ     = 0x0010,
+    LMP_START_ENCRYPT_REQ      = 0x0011,
+    LMP_STOP_ENCRYPT_REQ       = 0x0012,
+    LMP_SWITCH_REQ             = 0x0013,
+    LMP_HOLD                   = 0x0014,
+    LMP_HOLD_REQ               = 0x0015,
+    LMP_SNIFF_REQ              = 0x0017,
+    LMP_UNSNIFF_REQ            = 0x0018,
+    LMP_LMP_PARK_REQ           = 0x0019,
+    LMP_SET_BCAST_SCAN_WND     = 0x001b,
+    LMP_MODIFY_BEACON          = 0x001c,
+    LMP_UNPARK_BD_ADDR_REQ     = 0x001d,
+    LMP_UNPARK_PM_ADDR_REQ     = 0x001e,
+    LMP_INCR_POWER_REQ         = 0x001f,
+    LMP_DECR_POWER_REQ         = 0x0020,
+    LMP_MAX_POWER              = 0x0021,
+    LMP_MIN_POWER              = 0x0022,
+    LMP_AUTO_RATE              = 0x0023,
+    LMP_PREFERRED_RATE         = 0x0024,
+    LMP_VERSION_REQ            = 0x0025,
+    LMP_VERSION_RES            = 0x0026,
+    LMP_FEATURES_REQ           = 0x0027,
+    LMP_FEATURES_RES           = 0x0028,
+    LMP_QUALITY_OF_SERVICE     = 0x0029,
+    LMP_QOS_REQ                        = 0x002a,
+    LMP_RM_SCO_LINK_REQ                = 0x002b,
+    LMP_SCO_LINK_REQ           = 0x002c,
+    LMP_MAX_SLOT               = 0x002d,
+    LMP_MAX_SLOT_REQ           = 0x002e,
+    LMP_TIMING_ACCURACY_REQ    = 0x002f,
+    LMP_TIMING_ACCURACY_RES    = 0x0030,
+    LMP_SETUP_COMPLETE         = 0x0031,
+    LMP_USE_SEMIPERM_KEY       = 0x0032,
+    LMP_HOST_CONNECTION_REQ    = 0x0033,
+    LMP_SLOT_OFFSET            = 0x0034,
+    LMP_PAGE_MODE_REQ          = 0x0035,
+    LMP_PAGE_SCAN_MODE_REQ     = 0x0036,
+    LMP_SUPERVISION_TIMEOUT    = 0x0037,
+    LMP_TEST_ACTIVATE          = 0x0038,
+    LMP_TEST_CONTROL           = 0x0039,
+    LMP_CRYPT_KEY_MASK_REQ     = 0x003a,
+    LMP_CRYPT_KEY_MASK_RES     = 0x003b,
+    LMP_SET_AFH                        = 0x003c,
+    LMP_ACCEPTED_EXT           = 0x7f01,
+    LMP_NOT_ACCEPTED_EXT       = 0x7f02,
+    LMP_FEATURES_REQ_EXT       = 0x7f03,
+    LMP_FEATURES_RES_EXT       = 0x7f04,
+    LMP_PACKET_TYPE_TBL_REQ    = 0x7f0b,
+    LMP_ESCO_LINK_REQ          = 0x7f0c,
+    LMP_RM_ESCO_LINK_REQ       = 0x7f0d,
+    LMP_CHANNEL_CLASS_REQ      = 0x7f10,
+    LMP_CHANNEL_CLASS          = 0x7f11,
+};
+
+/* Host Controller Interface layer defines */
+
+enum hci_packet_type {
+    HCI_COMMAND_PKT            = 0x01,
+    HCI_ACLDATA_PKT            = 0x02,
+    HCI_SCODATA_PKT            = 0x03,
+    HCI_EVENT_PKT              = 0x04,
+    HCI_VENDOR_PKT             = 0xff,
+};
+
+enum bt_packet_type {
+    HCI_2DH1   = 1 << 1,
+    HCI_3DH1   = 1 << 2,
+    HCI_DM1    = 1 << 3,
+    HCI_DH1    = 1 << 4,
+    HCI_2DH3   = 1 << 8,
+    HCI_3DH3   = 1 << 9,
+    HCI_DM3    = 1 << 10,
+    HCI_DH3    = 1 << 11,
+    HCI_2DH5   = 1 << 12,
+    HCI_3DH5   = 1 << 13,
+    HCI_DM5    = 1 << 14,
+    HCI_DH5    = 1 << 15,
+};
+
+enum sco_packet_type {
+    HCI_HV1    = 1 << 5,
+    HCI_HV2    = 1 << 6,
+    HCI_HV3    = 1 << 7,
+};
+
+enum ev_packet_type {
+    HCI_EV3    = 1 << 3,
+    HCI_EV4    = 1 << 4,
+    HCI_EV5    = 1 << 5,
+    HCI_2EV3   = 1 << 6,
+    HCI_3EV3   = 1 << 7,
+    HCI_2EV5   = 1 << 8,
+    HCI_3EV5   = 1 << 9,
+};
+
+enum hci_error_code {
+    HCI_SUCCESS                                = 0x00,
+    HCI_UNKNOWN_COMMAND                        = 0x01,
+    HCI_NO_CONNECTION                  = 0x02,
+    HCI_HARDWARE_FAILURE               = 0x03,
+    HCI_PAGE_TIMEOUT                   = 0x04,
+    HCI_AUTHENTICATION_FAILURE         = 0x05,
+    HCI_PIN_OR_KEY_MISSING             = 0x06,
+    HCI_MEMORY_FULL                    = 0x07,
+    HCI_CONNECTION_TIMEOUT             = 0x08,
+    HCI_MAX_NUMBER_OF_CONNECTIONS      = 0x09,
+    HCI_MAX_NUMBER_OF_SCO_CONNECTIONS  = 0x0a,
+    HCI_ACL_CONNECTION_EXISTS          = 0x0b,
+    HCI_COMMAND_DISALLOWED             = 0x0c,
+    HCI_REJECTED_LIMITED_RESOURCES     = 0x0d,
+    HCI_REJECTED_SECURITY              = 0x0e,
+    HCI_REJECTED_PERSONAL              = 0x0f,
+    HCI_HOST_TIMEOUT                   = 0x10,
+    HCI_UNSUPPORTED_FEATURE            = 0x11,
+    HCI_INVALID_PARAMETERS             = 0x12,
+    HCI_OE_USER_ENDED_CONNECTION       = 0x13,
+    HCI_OE_LOW_RESOURCES               = 0x14,
+    HCI_OE_POWER_OFF                   = 0x15,
+    HCI_CONNECTION_TERMINATED          = 0x16,
+    HCI_REPEATED_ATTEMPTS              = 0x17,
+    HCI_PAIRING_NOT_ALLOWED            = 0x18,
+    HCI_UNKNOWN_LMP_PDU                        = 0x19,
+    HCI_UNSUPPORTED_REMOTE_FEATURE     = 0x1a,
+    HCI_SCO_OFFSET_REJECTED            = 0x1b,
+    HCI_SCO_INTERVAL_REJECTED          = 0x1c,
+    HCI_AIR_MODE_REJECTED              = 0x1d,
+    HCI_INVALID_LMP_PARAMETERS         = 0x1e,
+    HCI_UNSPECIFIED_ERROR              = 0x1f,
+    HCI_UNSUPPORTED_LMP_PARAMETER_VALUE        = 0x20,
+    HCI_ROLE_CHANGE_NOT_ALLOWED                = 0x21,
+    HCI_LMP_RESPONSE_TIMEOUT           = 0x22,
+    HCI_LMP_ERROR_TRANSACTION_COLLISION        = 0x23,
+    HCI_LMP_PDU_NOT_ALLOWED            = 0x24,
+    HCI_ENCRYPTION_MODE_NOT_ACCEPTED   = 0x25,
+    HCI_UNIT_LINK_KEY_USED             = 0x26,
+    HCI_QOS_NOT_SUPPORTED              = 0x27,
+    HCI_INSTANT_PASSED                 = 0x28,
+    HCI_PAIRING_NOT_SUPPORTED          = 0x29,
+    HCI_TRANSACTION_COLLISION          = 0x2a,
+    HCI_QOS_UNACCEPTABLE_PARAMETER     = 0x2c,
+    HCI_QOS_REJECTED                   = 0x2d,
+    HCI_CLASSIFICATION_NOT_SUPPORTED   = 0x2e,
+    HCI_INSUFFICIENT_SECURITY          = 0x2f,
+    HCI_PARAMETER_OUT_OF_RANGE         = 0x30,
+    HCI_ROLE_SWITCH_PENDING            = 0x32,
+    HCI_SLOT_VIOLATION                 = 0x34,
+    HCI_ROLE_SWITCH_FAILED             = 0x35,
+};
+
+enum acl_flag_bits {
+    ACL_CONT           = 1 << 0,
+    ACL_START          = 1 << 1,
+    ACL_ACTIVE_BCAST   = 1 << 2,
+    ACL_PICO_BCAST     = 1 << 3,
+};
+
+enum baseband_link_type {
+    SCO_LINK           = 0x00,
+    ACL_LINK           = 0x01,
+};
+
+enum lmp_feature_bits0 {
+    LMP_3SLOT          = 1 << 0,
+    LMP_5SLOT          = 1 << 1,
+    LMP_ENCRYPT                = 1 << 2,
+    LMP_SOFFSET                = 1 << 3,
+    LMP_TACCURACY      = 1 << 4,
+    LMP_RSWITCH                = 1 << 5,
+    LMP_HOLD_MODE      = 1 << 6,
+    LMP_SNIFF_MODE     = 1 << 7,
+};
+
+enum lmp_feature_bits1 {
+    LMP_PARK           = 1 << 0,
+    LMP_RSSI           = 1 << 1,
+    LMP_QUALITY                = 1 << 2,
+    LMP_SCO            = 1 << 3,
+    LMP_HV2            = 1 << 4,
+    LMP_HV3            = 1 << 5,
+    LMP_ULAW           = 1 << 6,
+    LMP_ALAW           = 1 << 7,
+};
+
+enum lmp_feature_bits2 {
+    LMP_CVSD           = 1 << 0,
+    LMP_PSCHEME                = 1 << 1,
+    LMP_PCONTROL       = 1 << 2,
+    LMP_TRSP_SCO       = 1 << 3,
+    LMP_BCAST_ENC      = 1 << 7,
+};
+
+enum lmp_feature_bits3 {
+    LMP_EDR_ACL_2M     = 1 << 1,
+    LMP_EDR_ACL_3M     = 1 << 2,
+    LMP_ENH_ISCAN      = 1 << 3,
+    LMP_ILACE_ISCAN    = 1 << 4,
+    LMP_ILACE_PSCAN    = 1 << 5,
+    LMP_RSSI_INQ       = 1 << 6,
+    LMP_ESCO           = 1 << 7,
+};
+
+enum lmp_feature_bits4 {
+    LMP_EV4            = 1 << 0,
+    LMP_EV5            = 1 << 1,
+    LMP_AFH_CAP_SLV    = 1 << 3,
+    LMP_AFH_CLS_SLV    = 1 << 4,
+    LMP_EDR_3SLOT      = 1 << 7,
+};
+
+enum lmp_feature_bits5 {
+    LMP_EDR_5SLOT      = 1 << 0,
+    LMP_SNIFF_SUBR     = 1 << 1,
+    LMP_AFH_CAP_MST    = 1 << 3,
+    LMP_AFH_CLS_MST    = 1 << 4,
+    LMP_EDR_ESCO_2M    = 1 << 5,
+    LMP_EDR_ESCO_3M    = 1 << 6,
+    LMP_EDR_3S_ESCO    = 1 << 7,
+};
+
+enum lmp_feature_bits6 {
+    LMP_EXT_INQ                = 1 << 0,
+};
+
+enum lmp_feature_bits7 {
+    LMP_EXT_FEAT       = 1 << 7,
+};
+
+enum hci_link_policy {
+    HCI_LP_RSWITCH     = 1 << 0,
+    HCI_LP_HOLD                = 1 << 1,
+    HCI_LP_SNIFF       = 1 << 2,
+    HCI_LP_PARK                = 1 << 3,
+};
+
+enum hci_link_mode {
+    HCI_LM_ACCEPT      = 1 << 15,
+    HCI_LM_MASTER      = 1 << 0,
+    HCI_LM_AUTH                = 1 << 1,
+    HCI_LM_ENCRYPT     = 1 << 2,
+    HCI_LM_TRUSTED     = 1 << 3,
+    HCI_LM_RELIABLE    = 1 << 4,
+    HCI_LM_SECURE      = 1 << 5,
+};
+
+/* HCI Commands */
+
+/* Link Control */
+#define OGF_LINK_CTL           0x01
+
+#define OCF_INQUIRY                    0x0001
+typedef struct {
+    uint8_t    lap[3];
+    uint8_t    length;         /* 1.28s units */
+    uint8_t    num_rsp;
+} QEMU_PACKED inquiry_cp;
+#define INQUIRY_CP_SIZE 5
+
+typedef struct {
+    uint8_t            status;
+    bdaddr_t   bdaddr;
+} QEMU_PACKED status_bdaddr_rp;
+#define STATUS_BDADDR_RP_SIZE 7
+
+#define OCF_INQUIRY_CANCEL             0x0002
+
+#define OCF_PERIODIC_INQUIRY           0x0003
+typedef struct {
+    uint16_t   max_period;     /* 1.28s units */
+    uint16_t   min_period;     /* 1.28s units */
+    uint8_t    lap[3];
+    uint8_t    length;         /* 1.28s units */
+    uint8_t    num_rsp;
+} QEMU_PACKED periodic_inquiry_cp;
+#define PERIODIC_INQUIRY_CP_SIZE 9
+
+#define OCF_EXIT_PERIODIC_INQUIRY      0x0004
+
+#define OCF_CREATE_CONN                        0x0005
+typedef struct {
+    bdaddr_t   bdaddr;
+    uint16_t   pkt_type;
+    uint8_t    pscan_rep_mode;
+    uint8_t    pscan_mode;
+    uint16_t   clock_offset;
+    uint8_t    role_switch;
+} QEMU_PACKED create_conn_cp;
+#define CREATE_CONN_CP_SIZE 13
+
+#define OCF_DISCONNECT                 0x0006
+typedef struct {
+    uint16_t   handle;
+    uint8_t    reason;
+} QEMU_PACKED disconnect_cp;
+#define DISCONNECT_CP_SIZE 3
+
+#define OCF_ADD_SCO                    0x0007
+typedef struct {
+    uint16_t   handle;
+    uint16_t   pkt_type;
+} QEMU_PACKED add_sco_cp;
+#define ADD_SCO_CP_SIZE 4
+
+#define OCF_CREATE_CONN_CANCEL         0x0008
+typedef struct {
+    uint8_t    status;
+    bdaddr_t   bdaddr;
+} QEMU_PACKED create_conn_cancel_cp;
+#define CREATE_CONN_CANCEL_CP_SIZE 6
+
+typedef struct {
+    uint8_t    status;
+    bdaddr_t   bdaddr;
+} QEMU_PACKED create_conn_cancel_rp;
+#define CREATE_CONN_CANCEL_RP_SIZE 7
+
+#define OCF_ACCEPT_CONN_REQ            0x0009
+typedef struct {
+    bdaddr_t   bdaddr;
+    uint8_t    role;
+} QEMU_PACKED accept_conn_req_cp;
+#define ACCEPT_CONN_REQ_CP_SIZE        7
+
+#define OCF_REJECT_CONN_REQ            0x000A
+typedef struct {
+    bdaddr_t   bdaddr;
+    uint8_t    reason;
+} QEMU_PACKED reject_conn_req_cp;
+#define REJECT_CONN_REQ_CP_SIZE        7
+
+#define OCF_LINK_KEY_REPLY             0x000B
+typedef struct {
+    bdaddr_t   bdaddr;
+    uint8_t    link_key[16];
+} QEMU_PACKED link_key_reply_cp;
+#define LINK_KEY_REPLY_CP_SIZE 22
+
+#define OCF_LINK_KEY_NEG_REPLY         0x000C
+
+#define OCF_PIN_CODE_REPLY             0x000D
+typedef struct {
+    bdaddr_t   bdaddr;
+    uint8_t    pin_len;
+    uint8_t    pin_code[16];
+} QEMU_PACKED pin_code_reply_cp;
+#define PIN_CODE_REPLY_CP_SIZE 23
+
+#define OCF_PIN_CODE_NEG_REPLY         0x000E
+
+#define OCF_SET_CONN_PTYPE             0x000F
+typedef struct {
+    uint16_t    handle;
+    uint16_t    pkt_type;
+} QEMU_PACKED set_conn_ptype_cp;
+#define SET_CONN_PTYPE_CP_SIZE 4
+
+#define OCF_AUTH_REQUESTED             0x0011
+typedef struct {
+    uint16_t    handle;
+} QEMU_PACKED auth_requested_cp;
+#define AUTH_REQUESTED_CP_SIZE 2
+
+#define OCF_SET_CONN_ENCRYPT           0x0013
+typedef struct {
+    uint16_t   handle;
+    uint8_t    encrypt;
+} QEMU_PACKED set_conn_encrypt_cp;
+#define SET_CONN_ENCRYPT_CP_SIZE 3
+
+#define OCF_CHANGE_CONN_LINK_KEY       0x0015
+typedef struct {
+    uint16_t   handle;
+} QEMU_PACKED change_conn_link_key_cp;
+#define CHANGE_CONN_LINK_KEY_CP_SIZE 2
+
+#define OCF_MASTER_LINK_KEY            0x0017
+typedef struct {
+    uint8_t    key_flag;
+} QEMU_PACKED master_link_key_cp;
+#define MASTER_LINK_KEY_CP_SIZE 1
+
+#define OCF_REMOTE_NAME_REQ            0x0019
+typedef struct {
+    bdaddr_t   bdaddr;
+    uint8_t    pscan_rep_mode;
+    uint8_t    pscan_mode;
+    uint16_t   clock_offset;
+} QEMU_PACKED remote_name_req_cp;
+#define REMOTE_NAME_REQ_CP_SIZE 10
+
+#define OCF_REMOTE_NAME_REQ_CANCEL     0x001A
+typedef struct {
+    bdaddr_t   bdaddr;
+} QEMU_PACKED remote_name_req_cancel_cp;
+#define REMOTE_NAME_REQ_CANCEL_CP_SIZE 6
+
+typedef struct {
+    uint8_t            status;
+    bdaddr_t   bdaddr;
+} QEMU_PACKED remote_name_req_cancel_rp;
+#define REMOTE_NAME_REQ_CANCEL_RP_SIZE 7
+
+#define OCF_READ_REMOTE_FEATURES       0x001B
+typedef struct {
+    uint16_t   handle;
+} QEMU_PACKED read_remote_features_cp;
+#define READ_REMOTE_FEATURES_CP_SIZE 2
+
+#define OCF_READ_REMOTE_EXT_FEATURES   0x001C
+typedef struct {
+    uint16_t   handle;
+    uint8_t    page_num;
+} QEMU_PACKED read_remote_ext_features_cp;
+#define READ_REMOTE_EXT_FEATURES_CP_SIZE 3
+
+#define OCF_READ_REMOTE_VERSION                0x001D
+typedef struct {
+    uint16_t   handle;
+} QEMU_PACKED read_remote_version_cp;
+#define READ_REMOTE_VERSION_CP_SIZE 2
+
+#define OCF_READ_CLOCK_OFFSET          0x001F
+typedef struct {
+    uint16_t   handle;
+} QEMU_PACKED read_clock_offset_cp;
+#define READ_CLOCK_OFFSET_CP_SIZE 2
+
+#define OCF_READ_LMP_HANDLE            0x0020
+typedef struct {
+    uint16_t   handle;
+} QEMU_PACKED read_lmp_handle_cp;
+#define READ_LMP_HANDLE_CP_SIZE 2
+
+typedef struct {
+    uint8_t    status;
+    uint16_t   handle;
+    uint8_t    lmp_handle;
+    uint32_t   reserved;
+} QEMU_PACKED read_lmp_handle_rp;
+#define READ_LMP_HANDLE_RP_SIZE 8
+
+#define OCF_SETUP_SYNC_CONN            0x0028
+typedef struct {
+    uint16_t   handle;
+    uint32_t   tx_bandwith;
+    uint32_t   rx_bandwith;
+    uint16_t   max_latency;
+    uint16_t   voice_setting;
+    uint8_t    retrans_effort;
+    uint16_t   pkt_type;
+} QEMU_PACKED setup_sync_conn_cp;
+#define SETUP_SYNC_CONN_CP_SIZE 17
+
+#define OCF_ACCEPT_SYNC_CONN_REQ       0x0029
+typedef struct {
+    bdaddr_t   bdaddr;
+    uint32_t   tx_bandwith;
+    uint32_t   rx_bandwith;
+    uint16_t   max_latency;
+    uint16_t   voice_setting;
+    uint8_t    retrans_effort;
+    uint16_t   pkt_type;
+} QEMU_PACKED accept_sync_conn_req_cp;
+#define ACCEPT_SYNC_CONN_REQ_CP_SIZE 21
+
+#define OCF_REJECT_SYNC_CONN_REQ       0x002A
+typedef struct {
+    bdaddr_t   bdaddr;
+    uint8_t    reason;
+} QEMU_PACKED reject_sync_conn_req_cp;
+#define REJECT_SYNC_CONN_REQ_CP_SIZE 7
+
+/* Link Policy */
+#define OGF_LINK_POLICY                0x02
+
+#define OCF_HOLD_MODE                  0x0001
+typedef struct {
+    uint16_t   handle;
+    uint16_t   max_interval;
+    uint16_t   min_interval;
+} QEMU_PACKED hold_mode_cp;
+#define HOLD_MODE_CP_SIZE 6
+
+#define OCF_SNIFF_MODE                 0x0003
+typedef struct {
+    uint16_t   handle;
+    uint16_t   max_interval;
+    uint16_t   min_interval;
+    uint16_t   attempt;
+    uint16_t   timeout;
+} QEMU_PACKED sniff_mode_cp;
+#define SNIFF_MODE_CP_SIZE 10
+
+#define OCF_EXIT_SNIFF_MODE            0x0004
+typedef struct {
+    uint16_t   handle;
+} QEMU_PACKED exit_sniff_mode_cp;
+#define EXIT_SNIFF_MODE_CP_SIZE 2
+
+#define OCF_PARK_MODE                  0x0005
+typedef struct {
+    uint16_t   handle;
+    uint16_t   max_interval;
+    uint16_t   min_interval;
+} QEMU_PACKED park_mode_cp;
+#define PARK_MODE_CP_SIZE 6
+
+#define OCF_EXIT_PARK_MODE             0x0006
+typedef struct {
+    uint16_t   handle;
+} QEMU_PACKED exit_park_mode_cp;
+#define EXIT_PARK_MODE_CP_SIZE 2
+
+#define OCF_QOS_SETUP                  0x0007
+typedef struct {
+    uint8_t    service_type;           /* 1 = best effort */
+    uint32_t   token_rate;             /* Byte per seconds */
+    uint32_t   peak_bandwidth;         /* Byte per seconds */
+    uint32_t   latency;                /* Microseconds */
+    uint32_t   delay_variation;        /* Microseconds */
+} QEMU_PACKED hci_qos;
+#define HCI_QOS_CP_SIZE 17
+typedef struct {
+    uint16_t   handle;
+    uint8_t    flags;                  /* Reserved */
+    hci_qos    qos;
+} QEMU_PACKED qos_setup_cp;
+#define QOS_SETUP_CP_SIZE (3 + HCI_QOS_CP_SIZE)
+
+#define OCF_ROLE_DISCOVERY             0x0009
+typedef struct {
+    uint16_t   handle;
+} QEMU_PACKED role_discovery_cp;
+#define ROLE_DISCOVERY_CP_SIZE 2
+typedef struct {
+    uint8_t    status;
+    uint16_t   handle;
+    uint8_t    role;
+} QEMU_PACKED role_discovery_rp;
+#define ROLE_DISCOVERY_RP_SIZE 4
+
+#define OCF_SWITCH_ROLE                        0x000B
+typedef struct {
+    bdaddr_t   bdaddr;
+    uint8_t    role;
+} QEMU_PACKED switch_role_cp;
+#define SWITCH_ROLE_CP_SIZE 7
+
+#define OCF_READ_LINK_POLICY           0x000C
+typedef struct {
+    uint16_t   handle;
+} QEMU_PACKED read_link_policy_cp;
+#define READ_LINK_POLICY_CP_SIZE 2
+typedef struct {
+    uint8_t    status;
+    uint16_t   handle;
+    uint16_t   policy;
+} QEMU_PACKED read_link_policy_rp;
+#define READ_LINK_POLICY_RP_SIZE 5
+
+#define OCF_WRITE_LINK_POLICY          0x000D
+typedef struct {
+    uint16_t   handle;
+    uint16_t   policy;
+} QEMU_PACKED write_link_policy_cp;
+#define WRITE_LINK_POLICY_CP_SIZE 4
+typedef struct {
+    uint8_t    status;
+    uint16_t   handle;
+} QEMU_PACKED write_link_policy_rp;
+#define WRITE_LINK_POLICY_RP_SIZE 3
+
+#define OCF_READ_DEFAULT_LINK_POLICY   0x000E
+
+#define OCF_WRITE_DEFAULT_LINK_POLICY  0x000F
+
+#define OCF_FLOW_SPECIFICATION         0x0010
+
+#define OCF_SNIFF_SUBRATE              0x0011
+typedef struct {
+    uint16_t   handle;
+    uint16_t   max_remote_latency;
+    uint16_t   max_local_latency;
+    uint16_t   min_remote_timeout;
+    uint16_t   min_local_timeout;
+} QEMU_PACKED sniff_subrate_cp;
+#define SNIFF_SUBRATE_CP_SIZE 10
+
+/* Host Controller and Baseband */
+#define OGF_HOST_CTL           0x03
+
+#define OCF_SET_EVENT_MASK             0x0001
+typedef struct {
+    uint8_t    mask[8];
+} QEMU_PACKED set_event_mask_cp;
+#define SET_EVENT_MASK_CP_SIZE 8
+
+#define OCF_RESET                      0x0003
+
+#define OCF_SET_EVENT_FLT              0x0005
+typedef struct {
+    uint8_t    flt_type;
+    uint8_t    cond_type;
+    uint8_t    condition[0];
+} QEMU_PACKED set_event_flt_cp;
+#define SET_EVENT_FLT_CP_SIZE 2
+
+enum bt_filter_type {
+    FLT_CLEAR_ALL              = 0x00,
+    FLT_INQ_RESULT             = 0x01,
+    FLT_CONN_SETUP             = 0x02,
+};
+enum inq_result_cond_type {
+    INQ_RESULT_RETURN_ALL      = 0x00,
+    INQ_RESULT_RETURN_CLASS    = 0x01,
+    INQ_RESULT_RETURN_BDADDR   = 0x02,
+};
+enum conn_setup_cond_type {
+    CONN_SETUP_ALLOW_ALL       = 0x00,
+    CONN_SETUP_ALLOW_CLASS     = 0x01,
+    CONN_SETUP_ALLOW_BDADDR    = 0x02,
+};
+enum conn_setup_cond {
+    CONN_SETUP_AUTO_OFF                = 0x01,
+    CONN_SETUP_AUTO_ON         = 0x02,
+};
+
+#define OCF_FLUSH                      0x0008
+typedef struct {
+    uint16_t   handle;
+} QEMU_PACKED flush_cp;
+#define FLUSH_CP_SIZE 2
+
+typedef struct {
+    uint8_t    status;
+    uint16_t   handle;
+} QEMU_PACKED flush_rp;
+#define FLUSH_RP_SIZE 3
+
+#define OCF_READ_PIN_TYPE              0x0009
+typedef struct {
+    uint8_t    status;
+    uint8_t    pin_type;
+} QEMU_PACKED read_pin_type_rp;
+#define READ_PIN_TYPE_RP_SIZE 2
+
+#define OCF_WRITE_PIN_TYPE             0x000A
+typedef struct {
+    uint8_t    pin_type;
+} QEMU_PACKED write_pin_type_cp;
+#define WRITE_PIN_TYPE_CP_SIZE 1
+
+#define OCF_CREATE_NEW_UNIT_KEY                0x000B
+
+#define OCF_READ_STORED_LINK_KEY       0x000D
+typedef struct {
+    bdaddr_t   bdaddr;
+    uint8_t    read_all;
+} QEMU_PACKED read_stored_link_key_cp;
+#define READ_STORED_LINK_KEY_CP_SIZE 7
+typedef struct {
+    uint8_t    status;
+    uint16_t   max_keys;
+    uint16_t   num_keys;
+} QEMU_PACKED read_stored_link_key_rp;
+#define READ_STORED_LINK_KEY_RP_SIZE 5
+
+#define OCF_WRITE_STORED_LINK_KEY      0x0011
+typedef struct {
+    uint8_t    num_keys;
+    /* variable length part */
+} QEMU_PACKED write_stored_link_key_cp;
+#define WRITE_STORED_LINK_KEY_CP_SIZE 1
+typedef struct {
+    uint8_t    status;
+    uint8_t    num_keys;
+} QEMU_PACKED write_stored_link_key_rp;
+#define READ_WRITE_LINK_KEY_RP_SIZE 2
+
+#define OCF_DELETE_STORED_LINK_KEY     0x0012
+typedef struct {
+    bdaddr_t   bdaddr;
+    uint8_t    delete_all;
+} QEMU_PACKED delete_stored_link_key_cp;
+#define DELETE_STORED_LINK_KEY_CP_SIZE 7
+typedef struct {
+    uint8_t    status;
+    uint16_t   num_keys;
+} QEMU_PACKED delete_stored_link_key_rp;
+#define DELETE_STORED_LINK_KEY_RP_SIZE 3
+
+#define OCF_CHANGE_LOCAL_NAME          0x0013
+typedef struct {
+    char       name[248];
+} QEMU_PACKED change_local_name_cp;
+#define CHANGE_LOCAL_NAME_CP_SIZE 248 
+
+#define OCF_READ_LOCAL_NAME            0x0014
+typedef struct {
+    uint8_t    status;
+    char       name[248];
+} QEMU_PACKED read_local_name_rp;
+#define READ_LOCAL_NAME_RP_SIZE 249 
+
+#define OCF_READ_CONN_ACCEPT_TIMEOUT   0x0015
+typedef struct {
+    uint8_t    status;
+    uint16_t   timeout;
+} QEMU_PACKED read_conn_accept_timeout_rp;
+#define READ_CONN_ACCEPT_TIMEOUT_RP_SIZE 3
+
+#define OCF_WRITE_CONN_ACCEPT_TIMEOUT  0x0016
+typedef struct {
+    uint16_t   timeout;
+} QEMU_PACKED write_conn_accept_timeout_cp;
+#define WRITE_CONN_ACCEPT_TIMEOUT_CP_SIZE 2
+
+#define OCF_READ_PAGE_TIMEOUT          0x0017
+typedef struct {
+    uint8_t    status;
+    uint16_t   timeout;
+} QEMU_PACKED read_page_timeout_rp;
+#define READ_PAGE_TIMEOUT_RP_SIZE 3
+
+#define OCF_WRITE_PAGE_TIMEOUT         0x0018
+typedef struct {
+    uint16_t   timeout;
+} QEMU_PACKED write_page_timeout_cp;
+#define WRITE_PAGE_TIMEOUT_CP_SIZE 2
+
+#define OCF_READ_SCAN_ENABLE           0x0019
+typedef struct {
+    uint8_t    status;
+    uint8_t    enable;
+} QEMU_PACKED read_scan_enable_rp;
+#define READ_SCAN_ENABLE_RP_SIZE 2
+
+#define OCF_WRITE_SCAN_ENABLE          0x001A
+typedef struct {
+    uint8_t    scan_enable;
+} QEMU_PACKED write_scan_enable_cp;
+#define WRITE_SCAN_ENABLE_CP_SIZE 1
+
+enum scan_enable_bits {
+    SCAN_DISABLED              = 0,
+    SCAN_INQUIRY               = 1 << 0,
+    SCAN_PAGE                  = 1 << 1,
+};
+
+#define OCF_READ_PAGE_ACTIVITY         0x001B
+typedef struct {
+    uint8_t    status;
+    uint16_t   interval;
+    uint16_t   window;
+} QEMU_PACKED read_page_activity_rp;
+#define READ_PAGE_ACTIVITY_RP_SIZE 5
+
+#define OCF_WRITE_PAGE_ACTIVITY                0x001C
+typedef struct {
+    uint16_t   interval;
+    uint16_t   window;
+} QEMU_PACKED write_page_activity_cp;
+#define WRITE_PAGE_ACTIVITY_CP_SIZE 4
+
+#define OCF_READ_INQ_ACTIVITY          0x001D
+typedef struct {
+    uint8_t    status;
+    uint16_t   interval;
+    uint16_t   window;
+} QEMU_PACKED read_inq_activity_rp;
+#define READ_INQ_ACTIVITY_RP_SIZE 5
+
+#define OCF_WRITE_INQ_ACTIVITY         0x001E
+typedef struct {
+    uint16_t   interval;
+    uint16_t   window;
+} QEMU_PACKED write_inq_activity_cp;
+#define WRITE_INQ_ACTIVITY_CP_SIZE 4
+
+#define OCF_READ_AUTH_ENABLE           0x001F
+
+#define OCF_WRITE_AUTH_ENABLE          0x0020
+
+#define AUTH_DISABLED          0x00
+#define AUTH_ENABLED           0x01
+
+#define OCF_READ_ENCRYPT_MODE          0x0021
+
+#define OCF_WRITE_ENCRYPT_MODE         0x0022
+
+#define ENCRYPT_DISABLED       0x00
+#define ENCRYPT_P2P            0x01
+#define ENCRYPT_BOTH           0x02
+
+#define OCF_READ_CLASS_OF_DEV          0x0023
+typedef struct {
+    uint8_t    status;
+    uint8_t    dev_class[3];
+} QEMU_PACKED read_class_of_dev_rp;
+#define READ_CLASS_OF_DEV_RP_SIZE 4 
+
+#define OCF_WRITE_CLASS_OF_DEV         0x0024
+typedef struct {
+    uint8_t    dev_class[3];
+} QEMU_PACKED write_class_of_dev_cp;
+#define WRITE_CLASS_OF_DEV_CP_SIZE 3
+
+#define OCF_READ_VOICE_SETTING         0x0025
+typedef struct {
+    uint8_t    status;
+    uint16_t   voice_setting;
+} QEMU_PACKED read_voice_setting_rp;
+#define READ_VOICE_SETTING_RP_SIZE 3
+
+#define OCF_WRITE_VOICE_SETTING                0x0026
+typedef struct {
+    uint16_t   voice_setting;
+} QEMU_PACKED write_voice_setting_cp;
+#define WRITE_VOICE_SETTING_CP_SIZE 2
+
+#define OCF_READ_AUTOMATIC_FLUSH_TIMEOUT       0x0027
+
+#define OCF_WRITE_AUTOMATIC_FLUSH_TIMEOUT      0x0028
+
+#define OCF_READ_NUM_BROADCAST_RETRANS 0x0029
+
+#define OCF_WRITE_NUM_BROADCAST_RETRANS        0x002A
+
+#define OCF_READ_HOLD_MODE_ACTIVITY    0x002B
+
+#define OCF_WRITE_HOLD_MODE_ACTIVITY   0x002C
+
+#define OCF_READ_TRANSMIT_POWER_LEVEL  0x002D
+typedef struct {
+    uint16_t   handle;
+    uint8_t    type;
+} QEMU_PACKED read_transmit_power_level_cp;
+#define READ_TRANSMIT_POWER_LEVEL_CP_SIZE 3
+typedef struct {
+    uint8_t    status;
+    uint16_t   handle;
+    int8_t     level;
+} QEMU_PACKED read_transmit_power_level_rp;
+#define READ_TRANSMIT_POWER_LEVEL_RP_SIZE 4
+
+#define OCF_HOST_BUFFER_SIZE           0x0033
+typedef struct {
+    uint16_t   acl_mtu;
+    uint8_t    sco_mtu;
+    uint16_t   acl_max_pkt;
+    uint16_t   sco_max_pkt;
+} QEMU_PACKED host_buffer_size_cp;
+#define HOST_BUFFER_SIZE_CP_SIZE 7
+
+#define OCF_HOST_NUMBER_OF_COMPLETED_PACKETS   0x0035
+
+#define OCF_READ_LINK_SUPERVISION_TIMEOUT      0x0036
+typedef struct {
+    uint8_t    status;
+    uint16_t   handle;
+    uint16_t   link_sup_to;
+} QEMU_PACKED read_link_supervision_timeout_rp;
+#define READ_LINK_SUPERVISION_TIMEOUT_RP_SIZE 5
+
+#define OCF_WRITE_LINK_SUPERVISION_TIMEOUT     0x0037
+typedef struct {
+    uint16_t   handle;
+    uint16_t   link_sup_to;
+} QEMU_PACKED write_link_supervision_timeout_cp;
+#define WRITE_LINK_SUPERVISION_TIMEOUT_CP_SIZE 4
+typedef struct {
+    uint8_t    status;
+    uint16_t   handle;
+} QEMU_PACKED write_link_supervision_timeout_rp;
+#define WRITE_LINK_SUPERVISION_TIMEOUT_RP_SIZE 3
+
+#define OCF_READ_NUM_SUPPORTED_IAC     0x0038
+
+#define MAX_IAC_LAP 0x40
+#define OCF_READ_CURRENT_IAC_LAP       0x0039
+typedef struct {
+    uint8_t    status;
+    uint8_t    num_current_iac;
+    uint8_t    lap[MAX_IAC_LAP][3];
+} QEMU_PACKED read_current_iac_lap_rp;
+#define READ_CURRENT_IAC_LAP_RP_SIZE 2+3*MAX_IAC_LAP
+
+#define OCF_WRITE_CURRENT_IAC_LAP      0x003A
+typedef struct {
+    uint8_t    num_current_iac;
+    uint8_t    lap[MAX_IAC_LAP][3];
+} QEMU_PACKED write_current_iac_lap_cp;
+#define WRITE_CURRENT_IAC_LAP_CP_SIZE 1+3*MAX_IAC_LAP
+
+#define OCF_READ_PAGE_SCAN_PERIOD_MODE 0x003B
+
+#define OCF_WRITE_PAGE_SCAN_PERIOD_MODE        0x003C
+
+#define OCF_READ_PAGE_SCAN_MODE                0x003D
+
+#define OCF_WRITE_PAGE_SCAN_MODE       0x003E
+
+#define OCF_SET_AFH_CLASSIFICATION     0x003F
+typedef struct {
+    uint8_t    map[10];
+} QEMU_PACKED set_afh_classification_cp;
+#define SET_AFH_CLASSIFICATION_CP_SIZE 10
+typedef struct {
+    uint8_t    status;
+} QEMU_PACKED set_afh_classification_rp;
+#define SET_AFH_CLASSIFICATION_RP_SIZE 1
+
+#define OCF_READ_INQUIRY_SCAN_TYPE     0x0042
+typedef struct {
+    uint8_t    status;
+    uint8_t    type;
+} QEMU_PACKED read_inquiry_scan_type_rp;
+#define READ_INQUIRY_SCAN_TYPE_RP_SIZE 2
+
+#define OCF_WRITE_INQUIRY_SCAN_TYPE    0x0043
+typedef struct {
+    uint8_t    type;
+} QEMU_PACKED write_inquiry_scan_type_cp;
+#define WRITE_INQUIRY_SCAN_TYPE_CP_SIZE 1
+typedef struct {
+    uint8_t    status;
+} QEMU_PACKED write_inquiry_scan_type_rp;
+#define WRITE_INQUIRY_SCAN_TYPE_RP_SIZE 1
+
+#define OCF_READ_INQUIRY_MODE          0x0044
+typedef struct {
+    uint8_t    status;
+    uint8_t    mode;
+} QEMU_PACKED read_inquiry_mode_rp;
+#define READ_INQUIRY_MODE_RP_SIZE 2
+
+#define OCF_WRITE_INQUIRY_MODE         0x0045
+typedef struct {
+    uint8_t    mode;
+} QEMU_PACKED write_inquiry_mode_cp;
+#define WRITE_INQUIRY_MODE_CP_SIZE 1
+typedef struct {
+    uint8_t    status;
+} QEMU_PACKED write_inquiry_mode_rp;
+#define WRITE_INQUIRY_MODE_RP_SIZE 1
+
+#define OCF_READ_PAGE_SCAN_TYPE                0x0046
+
+#define OCF_WRITE_PAGE_SCAN_TYPE       0x0047
+
+#define OCF_READ_AFH_MODE              0x0048
+typedef struct {
+    uint8_t    status;
+    uint8_t    mode;
+} QEMU_PACKED read_afh_mode_rp;
+#define READ_AFH_MODE_RP_SIZE 2
+
+#define OCF_WRITE_AFH_MODE             0x0049
+typedef struct {
+    uint8_t    mode;
+} QEMU_PACKED write_afh_mode_cp;
+#define WRITE_AFH_MODE_CP_SIZE 1
+typedef struct {
+    uint8_t    status;
+} QEMU_PACKED write_afh_mode_rp;
+#define WRITE_AFH_MODE_RP_SIZE 1
+
+#define OCF_READ_EXT_INQUIRY_RESPONSE  0x0051
+typedef struct {
+    uint8_t    status;
+    uint8_t    fec;
+    uint8_t    data[240];
+} QEMU_PACKED read_ext_inquiry_response_rp;
+#define READ_EXT_INQUIRY_RESPONSE_RP_SIZE 242
+
+#define OCF_WRITE_EXT_INQUIRY_RESPONSE 0x0052
+typedef struct {
+    uint8_t    fec;
+    uint8_t    data[240];
+} QEMU_PACKED write_ext_inquiry_response_cp;
+#define WRITE_EXT_INQUIRY_RESPONSE_CP_SIZE 241
+typedef struct {
+    uint8_t    status;
+} QEMU_PACKED write_ext_inquiry_response_rp;
+#define WRITE_EXT_INQUIRY_RESPONSE_RP_SIZE 1
+
+/* Informational Parameters */
+#define OGF_INFO_PARAM         0x04
+
+#define OCF_READ_LOCAL_VERSION         0x0001
+typedef struct {
+    uint8_t    status;
+    uint8_t    hci_ver;
+    uint16_t   hci_rev;
+    uint8_t    lmp_ver;
+    uint16_t   manufacturer;
+    uint16_t   lmp_subver;
+} QEMU_PACKED read_local_version_rp;
+#define READ_LOCAL_VERSION_RP_SIZE 9
+
+#define OCF_READ_LOCAL_COMMANDS                0x0002
+typedef struct {
+    uint8_t    status;
+    uint8_t    commands[64];
+} QEMU_PACKED read_local_commands_rp;
+#define READ_LOCAL_COMMANDS_RP_SIZE 65
+
+#define OCF_READ_LOCAL_FEATURES                0x0003
+typedef struct {
+    uint8_t    status;
+    uint8_t    features[8];
+} QEMU_PACKED read_local_features_rp;
+#define READ_LOCAL_FEATURES_RP_SIZE 9
+
+#define OCF_READ_LOCAL_EXT_FEATURES    0x0004
+typedef struct {
+    uint8_t    page_num;
+} QEMU_PACKED read_local_ext_features_cp;
+#define READ_LOCAL_EXT_FEATURES_CP_SIZE 1
+typedef struct {
+    uint8_t    status;
+    uint8_t    page_num;
+    uint8_t    max_page_num;
+    uint8_t    features[8];
+} QEMU_PACKED read_local_ext_features_rp;
+#define READ_LOCAL_EXT_FEATURES_RP_SIZE 11
+
+#define OCF_READ_BUFFER_SIZE           0x0005
+typedef struct {
+    uint8_t    status;
+    uint16_t   acl_mtu;
+    uint8_t    sco_mtu;
+    uint16_t   acl_max_pkt;
+    uint16_t   sco_max_pkt;
+} QEMU_PACKED read_buffer_size_rp;
+#define READ_BUFFER_SIZE_RP_SIZE 8
+
+#define OCF_READ_COUNTRY_CODE          0x0007
+typedef struct {
+    uint8_t    status;
+    uint8_t    country_code;
+} QEMU_PACKED read_country_code_rp;
+#define READ_COUNTRY_CODE_RP_SIZE 2
+
+#define OCF_READ_BD_ADDR               0x0009
+typedef struct {
+    uint8_t    status;
+    bdaddr_t   bdaddr;
+} QEMU_PACKED read_bd_addr_rp;
+#define READ_BD_ADDR_RP_SIZE 7
+
+/* Status params */
+#define OGF_STATUS_PARAM       0x05
+
+#define OCF_READ_FAILED_CONTACT_COUNTER                0x0001
+typedef struct {
+    uint8_t    status;
+    uint16_t   handle;
+    uint8_t    counter;
+} QEMU_PACKED read_failed_contact_counter_rp;
+#define READ_FAILED_CONTACT_COUNTER_RP_SIZE 4
+
+#define OCF_RESET_FAILED_CONTACT_COUNTER       0x0002
+typedef struct {
+    uint8_t    status;
+    uint16_t   handle;
+} QEMU_PACKED reset_failed_contact_counter_rp;
+#define RESET_FAILED_CONTACT_COUNTER_RP_SIZE 4
+
+#define OCF_READ_LINK_QUALITY          0x0003
+typedef struct {
+    uint16_t   handle;
+} QEMU_PACKED read_link_quality_cp;
+#define READ_LINK_QUALITY_CP_SIZE 4
+
+typedef struct {
+    uint8_t    status;
+    uint16_t   handle;
+    uint8_t    link_quality;
+} QEMU_PACKED read_link_quality_rp;
+#define READ_LINK_QUALITY_RP_SIZE 4
+
+#define OCF_READ_RSSI                  0x0005
+typedef struct {
+    uint8_t    status;
+    uint16_t   handle;
+    int8_t     rssi;
+} QEMU_PACKED read_rssi_rp;
+#define READ_RSSI_RP_SIZE 4
+
+#define OCF_READ_AFH_MAP               0x0006
+typedef struct {
+    uint8_t    status;
+    uint16_t   handle;
+    uint8_t    mode;
+    uint8_t    map[10];
+} QEMU_PACKED read_afh_map_rp;
+#define READ_AFH_MAP_RP_SIZE 14
+
+#define OCF_READ_CLOCK                 0x0007
+typedef struct {
+    uint16_t   handle;
+    uint8_t    which_clock;
+} QEMU_PACKED read_clock_cp;
+#define READ_CLOCK_CP_SIZE 3
+typedef struct {
+    uint8_t    status;
+    uint16_t   handle;
+    uint32_t   clock;
+    uint16_t   accuracy;
+} QEMU_PACKED read_clock_rp;
+#define READ_CLOCK_RP_SIZE 9
+
+/* Testing commands */
+#define OGF_TESTING_CMD                0x3e
+
+/* Vendor specific commands */
+#define OGF_VENDOR_CMD         0x3f
+
+/* HCI Events */
+
+#define EVT_INQUIRY_COMPLETE           0x01
+
+#define EVT_INQUIRY_RESULT             0x02
+typedef struct {
+    uint8_t    num_responses;
+    bdaddr_t   bdaddr;
+    uint8_t    pscan_rep_mode;
+    uint8_t    pscan_period_mode;
+    uint8_t    pscan_mode;
+    uint8_t    dev_class[3];
+    uint16_t   clock_offset;
+} QEMU_PACKED inquiry_info;
+#define INQUIRY_INFO_SIZE 14
+
+#define EVT_CONN_COMPLETE              0x03
+typedef struct {
+    uint8_t    status;
+    uint16_t   handle;
+    bdaddr_t   bdaddr;
+    uint8_t    link_type;
+    uint8_t    encr_mode;
+} QEMU_PACKED evt_conn_complete;
+#define EVT_CONN_COMPLETE_SIZE 11
+
+#define EVT_CONN_REQUEST               0x04
+typedef struct {
+    bdaddr_t   bdaddr;
+    uint8_t    dev_class[3];
+    uint8_t    link_type;
+} QEMU_PACKED evt_conn_request;
+#define EVT_CONN_REQUEST_SIZE 10
+
+#define EVT_DISCONN_COMPLETE           0x05
+typedef struct {
+    uint8_t    status;
+    uint16_t   handle;
+    uint8_t    reason;
+} QEMU_PACKED evt_disconn_complete;
+#define EVT_DISCONN_COMPLETE_SIZE 4
+
+#define EVT_AUTH_COMPLETE              0x06
+typedef struct {
+    uint8_t    status;
+    uint16_t   handle;
+} QEMU_PACKED evt_auth_complete;
+#define EVT_AUTH_COMPLETE_SIZE 3
+
+#define EVT_REMOTE_NAME_REQ_COMPLETE   0x07
+typedef struct {
+    uint8_t    status;
+    bdaddr_t   bdaddr;
+    char       name[248];
+} QEMU_PACKED evt_remote_name_req_complete;
+#define EVT_REMOTE_NAME_REQ_COMPLETE_SIZE 255
+
+#define EVT_ENCRYPT_CHANGE             0x08
+typedef struct {
+    uint8_t    status;
+    uint16_t   handle;
+    uint8_t    encrypt;
+} QEMU_PACKED evt_encrypt_change;
+#define EVT_ENCRYPT_CHANGE_SIZE 5
+
+#define EVT_CHANGE_CONN_LINK_KEY_COMPLETE      0x09
+typedef struct {
+    uint8_t    status;
+    uint16_t   handle;
+}  QEMU_PACKED evt_change_conn_link_key_complete;
+#define EVT_CHANGE_CONN_LINK_KEY_COMPLETE_SIZE 3
+
+#define EVT_MASTER_LINK_KEY_COMPLETE           0x0A
+typedef struct {
+    uint8_t    status;
+    uint16_t   handle;
+    uint8_t    key_flag;
+} QEMU_PACKED evt_master_link_key_complete;
+#define EVT_MASTER_LINK_KEY_COMPLETE_SIZE 4
+
+#define EVT_READ_REMOTE_FEATURES_COMPLETE      0x0B
+typedef struct {
+    uint8_t    status;
+    uint16_t   handle;
+    uint8_t    features[8];
+} QEMU_PACKED evt_read_remote_features_complete;
+#define EVT_READ_REMOTE_FEATURES_COMPLETE_SIZE 11
+
+#define EVT_READ_REMOTE_VERSION_COMPLETE       0x0C
+typedef struct {
+    uint8_t    status;
+    uint16_t   handle;
+    uint8_t    lmp_ver;
+    uint16_t   manufacturer;
+    uint16_t   lmp_subver;
+} QEMU_PACKED evt_read_remote_version_complete;
+#define EVT_READ_REMOTE_VERSION_COMPLETE_SIZE 8
+
+#define EVT_QOS_SETUP_COMPLETE         0x0D
+typedef struct {
+    uint8_t    status;
+    uint16_t   handle;
+    uint8_t    flags;                  /* Reserved */
+    hci_qos    qos;
+} QEMU_PACKED evt_qos_setup_complete;
+#define EVT_QOS_SETUP_COMPLETE_SIZE (4 + HCI_QOS_CP_SIZE)
+
+#define EVT_CMD_COMPLETE               0x0E
+typedef struct {
+    uint8_t    ncmd;
+    uint16_t   opcode;
+} QEMU_PACKED evt_cmd_complete;
+#define EVT_CMD_COMPLETE_SIZE 3
+
+#define EVT_CMD_STATUS                         0x0F
+typedef struct {
+    uint8_t    status;
+    uint8_t    ncmd;
+    uint16_t   opcode;
+} QEMU_PACKED evt_cmd_status;
+#define EVT_CMD_STATUS_SIZE 4
+
+#define EVT_HARDWARE_ERROR             0x10
+typedef struct {
+    uint8_t    code;
+} QEMU_PACKED evt_hardware_error;
+#define EVT_HARDWARE_ERROR_SIZE 1
+
+#define EVT_FLUSH_OCCURRED             0x11
+typedef struct {
+    uint16_t   handle;
+} QEMU_PACKED evt_flush_occurred;
+#define EVT_FLUSH_OCCURRED_SIZE 2
+
+#define EVT_ROLE_CHANGE                        0x12
+typedef struct {
+    uint8_t    status;
+    bdaddr_t   bdaddr;
+    uint8_t    role;
+} QEMU_PACKED evt_role_change;
+#define EVT_ROLE_CHANGE_SIZE 8
+
+#define EVT_NUM_COMP_PKTS              0x13
+typedef struct {
+    uint8_t    num_hndl;
+    struct {
+        uint16_t handle;
+        uint16_t num_packets;
+    } connection[0];
+} QEMU_PACKED evt_num_comp_pkts;
+#define EVT_NUM_COMP_PKTS_SIZE(num_hndl) (1 + 4 * (num_hndl))
+
+#define EVT_MODE_CHANGE                        0x14
+typedef struct {
+    uint8_t    status;
+    uint16_t   handle;
+    uint8_t    mode;
+    uint16_t   interval;
+} QEMU_PACKED evt_mode_change;
+#define EVT_MODE_CHANGE_SIZE 6
+
+#define EVT_RETURN_LINK_KEYS           0x15
+typedef struct {
+    uint8_t    num_keys;
+    /* variable length part */
+} QEMU_PACKED evt_return_link_keys;
+#define EVT_RETURN_LINK_KEYS_SIZE 1
+
+#define EVT_PIN_CODE_REQ               0x16
+typedef struct {
+    bdaddr_t   bdaddr;
+} QEMU_PACKED evt_pin_code_req;
+#define EVT_PIN_CODE_REQ_SIZE 6
+
+#define EVT_LINK_KEY_REQ               0x17
+typedef struct {
+    bdaddr_t   bdaddr;
+} QEMU_PACKED evt_link_key_req;
+#define EVT_LINK_KEY_REQ_SIZE 6
+
+#define EVT_LINK_KEY_NOTIFY            0x18
+typedef struct {
+    bdaddr_t   bdaddr;
+    uint8_t    link_key[16];
+    uint8_t    key_type;
+} QEMU_PACKED evt_link_key_notify;
+#define EVT_LINK_KEY_NOTIFY_SIZE 23
+
+#define EVT_LOOPBACK_COMMAND           0x19
+
+#define EVT_DATA_BUFFER_OVERFLOW       0x1A
+typedef struct {
+    uint8_t    link_type;
+} QEMU_PACKED evt_data_buffer_overflow;
+#define EVT_DATA_BUFFER_OVERFLOW_SIZE 1
+
+#define EVT_MAX_SLOTS_CHANGE           0x1B
+typedef struct {
+    uint16_t   handle;
+    uint8_t    max_slots;
+} QEMU_PACKED evt_max_slots_change;
+#define EVT_MAX_SLOTS_CHANGE_SIZE 3
+
+#define EVT_READ_CLOCK_OFFSET_COMPLETE 0x1C
+typedef struct {
+    uint8_t    status;
+    uint16_t   handle;
+    uint16_t   clock_offset;
+} QEMU_PACKED evt_read_clock_offset_complete;
+#define EVT_READ_CLOCK_OFFSET_COMPLETE_SIZE 5
+
+#define EVT_CONN_PTYPE_CHANGED         0x1D
+typedef struct {
+    uint8_t    status;
+    uint16_t   handle;
+    uint16_t   ptype;
+} QEMU_PACKED evt_conn_ptype_changed;
+#define EVT_CONN_PTYPE_CHANGED_SIZE 5
+
+#define EVT_QOS_VIOLATION              0x1E
+typedef struct {
+    uint16_t   handle;
+} QEMU_PACKED evt_qos_violation;
+#define EVT_QOS_VIOLATION_SIZE 2
+
+#define EVT_PSCAN_REP_MODE_CHANGE      0x20
+typedef struct {
+    bdaddr_t   bdaddr;
+    uint8_t    pscan_rep_mode;
+} QEMU_PACKED evt_pscan_rep_mode_change;
+#define EVT_PSCAN_REP_MODE_CHANGE_SIZE 7
+
+#define EVT_FLOW_SPEC_COMPLETE         0x21
+typedef struct {
+    uint8_t    status;
+    uint16_t   handle;
+    uint8_t    flags;
+    uint8_t    direction;
+    hci_qos    qos;
+} QEMU_PACKED evt_flow_spec_complete;
+#define EVT_FLOW_SPEC_COMPLETE_SIZE (5 + HCI_QOS_CP_SIZE)
+
+#define EVT_INQUIRY_RESULT_WITH_RSSI   0x22
+typedef struct {
+    uint8_t    num_responses;
+    bdaddr_t   bdaddr;
+    uint8_t    pscan_rep_mode;
+    uint8_t    pscan_period_mode;
+    uint8_t    dev_class[3];
+    uint16_t   clock_offset;
+    int8_t     rssi;
+} QEMU_PACKED inquiry_info_with_rssi;
+#define INQUIRY_INFO_WITH_RSSI_SIZE 15
+typedef struct {
+    uint8_t    num_responses;
+    bdaddr_t   bdaddr;
+    uint8_t    pscan_rep_mode;
+    uint8_t    pscan_period_mode;
+    uint8_t    pscan_mode;
+    uint8_t    dev_class[3];
+    uint16_t   clock_offset;
+    int8_t     rssi;
+} QEMU_PACKED inquiry_info_with_rssi_and_pscan_mode;
+#define INQUIRY_INFO_WITH_RSSI_AND_PSCAN_MODE_SIZE 16
+
+#define EVT_READ_REMOTE_EXT_FEATURES_COMPLETE  0x23
+typedef struct {
+    uint8_t    status;
+    uint16_t   handle;
+    uint8_t    page_num;
+    uint8_t    max_page_num;
+    uint8_t    features[8];
+} QEMU_PACKED evt_read_remote_ext_features_complete;
+#define EVT_READ_REMOTE_EXT_FEATURES_COMPLETE_SIZE 13
+
+#define EVT_SYNC_CONN_COMPLETE         0x2C
+typedef struct {
+    uint8_t    status;
+    uint16_t   handle;
+    bdaddr_t   bdaddr;
+    uint8_t    link_type;
+    uint8_t    trans_interval;
+    uint8_t    retrans_window;
+    uint16_t   rx_pkt_len;
+    uint16_t   tx_pkt_len;
+    uint8_t    air_mode;
+} QEMU_PACKED evt_sync_conn_complete;
+#define EVT_SYNC_CONN_COMPLETE_SIZE 17
+
+#define EVT_SYNC_CONN_CHANGED          0x2D
+typedef struct {
+    uint8_t    status;
+    uint16_t   handle;
+    uint8_t    trans_interval;
+    uint8_t    retrans_window;
+    uint16_t   rx_pkt_len;
+    uint16_t   tx_pkt_len;
+} QEMU_PACKED evt_sync_conn_changed;
+#define EVT_SYNC_CONN_CHANGED_SIZE 9
+
+#define EVT_SNIFF_SUBRATE              0x2E
+typedef struct {
+    uint8_t    status;
+    uint16_t   handle;
+    uint16_t   max_remote_latency;
+    uint16_t   max_local_latency;
+    uint16_t   min_remote_timeout;
+    uint16_t   min_local_timeout;
+} QEMU_PACKED evt_sniff_subrate;
+#define EVT_SNIFF_SUBRATE_SIZE 11
+
+#define EVT_EXTENDED_INQUIRY_RESULT    0x2F
+typedef struct {
+    bdaddr_t   bdaddr;
+    uint8_t    pscan_rep_mode;
+    uint8_t    pscan_period_mode;
+    uint8_t    dev_class[3];
+    uint16_t   clock_offset;
+    int8_t     rssi;
+    uint8_t    data[240];
+} QEMU_PACKED extended_inquiry_info;
+#define EXTENDED_INQUIRY_INFO_SIZE 254
+
+#define EVT_TESTING                    0xFE
+
+#define EVT_VENDOR                     0xFF
+
+/* Command opcode pack/unpack */
+#define cmd_opcode_pack(ogf, ocf)      (uint16_t)((ocf & 0x03ff)|(ogf << 10))
+#define cmd_opcode_ogf(op)             (op >> 10)
+#define cmd_opcode_ocf(op)             (op & 0x03ff)
+
+/* ACL handle and flags pack/unpack */
+#define acl_handle_pack(h, f)  (uint16_t)(((h) & 0x0fff)|((f) << 12))
+#define acl_handle(h)          ((h) & 0x0fff)
+#define acl_flags(h)           ((h) >> 12)
+
+/* HCI Packet structures */
+#define HCI_COMMAND_HDR_SIZE   3
+#define HCI_EVENT_HDR_SIZE     2
+#define HCI_ACL_HDR_SIZE       4
+#define HCI_SCO_HDR_SIZE       3
+
+struct hci_command_hdr {
+    uint16_t   opcode;         /* OCF & OGF */
+    uint8_t    plen;
+} QEMU_PACKED;
+
+struct hci_event_hdr {
+    uint8_t    evt;
+    uint8_t    plen;
+} QEMU_PACKED;
+
+struct hci_acl_hdr {
+    uint16_t   handle;         /* Handle & Flags(PB, BC) */
+    uint16_t   dlen;
+} QEMU_PACKED;
+
+struct hci_sco_hdr {
+    uint16_t   handle;
+    uint8_t    dlen;
+} QEMU_PACKED;
+
+/* L2CAP layer defines */
+
+enum bt_l2cap_lm_bits {
+    L2CAP_LM_MASTER    = 1 << 0,
+    L2CAP_LM_AUTH      = 1 << 1,
+    L2CAP_LM_ENCRYPT   = 1 << 2,
+    L2CAP_LM_TRUSTED   = 1 << 3,
+    L2CAP_LM_RELIABLE  = 1 << 4,
+    L2CAP_LM_SECURE    = 1 << 5,
+};
+
+enum bt_l2cap_cid_predef {
+    L2CAP_CID_INVALID  = 0x0000,
+    L2CAP_CID_SIGNALLING= 0x0001,
+    L2CAP_CID_GROUP    = 0x0002,
+    L2CAP_CID_ALLOC    = 0x0040,
+};
+
+/* L2CAP command codes */
+enum bt_l2cap_cmd {
+    L2CAP_COMMAND_REJ  = 1,
+    L2CAP_CONN_REQ,
+    L2CAP_CONN_RSP,
+    L2CAP_CONF_REQ,
+    L2CAP_CONF_RSP,
+    L2CAP_DISCONN_REQ,
+    L2CAP_DISCONN_RSP,
+    L2CAP_ECHO_REQ,
+    L2CAP_ECHO_RSP,
+    L2CAP_INFO_REQ,
+    L2CAP_INFO_RSP,
+};
+
+enum bt_l2cap_sar_bits {
+    L2CAP_SAR_NO_SEG   = 0,
+    L2CAP_SAR_START,
+    L2CAP_SAR_END,
+    L2CAP_SAR_CONT,
+};
+
+/* L2CAP structures */
+typedef struct {
+    uint16_t   len;
+    uint16_t   cid;
+    uint8_t    data[0];
+} QEMU_PACKED l2cap_hdr;
+#define L2CAP_HDR_SIZE 4
+
+typedef struct {
+    uint8_t    code;
+    uint8_t    ident;
+    uint16_t   len;
+} QEMU_PACKED l2cap_cmd_hdr;
+#define L2CAP_CMD_HDR_SIZE 4
+
+typedef struct {
+    uint16_t   reason;
+} QEMU_PACKED l2cap_cmd_rej;
+#define L2CAP_CMD_REJ_SIZE 2
+
+typedef struct {
+    uint16_t   dcid;
+    uint16_t   scid;
+} QEMU_PACKED l2cap_cmd_rej_cid;
+#define L2CAP_CMD_REJ_CID_SIZE 4
+
+/* reject reason */
+enum bt_l2cap_rej_reason {
+    L2CAP_REJ_CMD_NOT_UNDERSTOOD = 0,
+    L2CAP_REJ_SIG_TOOBIG,
+    L2CAP_REJ_CID_INVAL,
+};
+
+typedef struct {
+    uint16_t   psm;
+    uint16_t   scid;
+} QEMU_PACKED l2cap_conn_req;
+#define L2CAP_CONN_REQ_SIZE 4
+
+typedef struct {
+    uint16_t   dcid;
+    uint16_t   scid;
+    uint16_t   result;
+    uint16_t   status;
+} QEMU_PACKED l2cap_conn_rsp;
+#define L2CAP_CONN_RSP_SIZE 8
+
+/* connect result */
+enum bt_l2cap_conn_res {
+    L2CAP_CR_SUCCESS   = 0,
+    L2CAP_CR_PEND,
+    L2CAP_CR_BAD_PSM,
+    L2CAP_CR_SEC_BLOCK,
+    L2CAP_CR_NO_MEM,
+};
+
+/* connect status */
+enum bt_l2cap_conn_stat {
+    L2CAP_CS_NO_INFO   = 0,
+    L2CAP_CS_AUTHEN_PEND,
+    L2CAP_CS_AUTHOR_PEND,
+};
+
+typedef struct {
+    uint16_t   dcid;
+    uint16_t   flags;
+    uint8_t    data[0];
+} QEMU_PACKED l2cap_conf_req;
+#define L2CAP_CONF_REQ_SIZE(datalen) (4 + (datalen))
+
+typedef struct {
+    uint16_t   scid;
+    uint16_t   flags;
+    uint16_t   result;
+    uint8_t    data[0];
+} QEMU_PACKED l2cap_conf_rsp;
+#define L2CAP_CONF_RSP_SIZE(datalen) (6 + datalen)
+
+enum bt_l2cap_conf_res {
+    L2CAP_CONF_SUCCESS = 0,
+    L2CAP_CONF_UNACCEPT,
+    L2CAP_CONF_REJECT,
+    L2CAP_CONF_UNKNOWN,
+};
+
+typedef struct {
+    uint8_t    type;
+    uint8_t    len;
+    uint8_t    val[0];
+} QEMU_PACKED l2cap_conf_opt;
+#define L2CAP_CONF_OPT_SIZE 2
+
+enum bt_l2cap_conf_val {
+    L2CAP_CONF_MTU     = 1,
+    L2CAP_CONF_FLUSH_TO,
+    L2CAP_CONF_QOS,
+    L2CAP_CONF_RFC,
+    L2CAP_CONF_RFC_MODE        = L2CAP_CONF_RFC,
+};
+
+typedef struct {
+    uint8_t    flags;
+    uint8_t    service_type;
+    uint32_t   token_rate;
+    uint32_t   token_bucket_size;
+    uint32_t   peak_bandwidth;
+    uint32_t   latency;
+    uint32_t   delay_variation;
+} QEMU_PACKED l2cap_conf_opt_qos;
+#define L2CAP_CONF_OPT_QOS_SIZE 22
+
+enum bt_l2cap_conf_opt_qos_st {
+    L2CAP_CONF_QOS_NO_TRAFFIC = 0x00,
+    L2CAP_CONF_QOS_BEST_EFFORT,
+    L2CAP_CONF_QOS_GUARANTEED,
+};
+
+#define L2CAP_CONF_QOS_WILDCARD        0xffffffff
+
+enum bt_l2cap_mode {
+    L2CAP_MODE_BASIC   = 0,
+    L2CAP_MODE_RETRANS = 1,
+    L2CAP_MODE_FLOWCTL = 2,
+};
+
+typedef struct {
+    uint16_t   dcid;
+    uint16_t   scid;
+} QEMU_PACKED l2cap_disconn_req;
+#define L2CAP_DISCONN_REQ_SIZE 4
+
+typedef struct {
+    uint16_t   dcid;
+    uint16_t   scid;
+} QEMU_PACKED l2cap_disconn_rsp;
+#define L2CAP_DISCONN_RSP_SIZE 4
+
+typedef struct {
+    uint16_t   type;
+} QEMU_PACKED l2cap_info_req;
+#define L2CAP_INFO_REQ_SIZE 2
+
+typedef struct {
+    uint16_t   type;
+    uint16_t   result;
+    uint8_t    data[0];
+} QEMU_PACKED l2cap_info_rsp;
+#define L2CAP_INFO_RSP_SIZE 4
+
+/* info type */
+enum bt_l2cap_info_type {
+    L2CAP_IT_CL_MTU    = 1,
+    L2CAP_IT_FEAT_MASK,
+};
+
+/* info result */
+enum bt_l2cap_info_result {
+    L2CAP_IR_SUCCESS   = 0,
+    L2CAP_IR_NOTSUPP,
+};
+
+/* Service Discovery Protocol defines */
+/* Note that all multibyte values in lower layer protocols (above in this file)
+ * are little-endian while SDP is big-endian.  */
+
+/* Protocol UUIDs */
+enum sdp_proto_uuid {
+    SDP_UUID           = 0x0001,
+    UDP_UUID           = 0x0002,
+    RFCOMM_UUID                = 0x0003,
+    TCP_UUID           = 0x0004,
+    TCS_BIN_UUID       = 0x0005,
+    TCS_AT_UUID                = 0x0006,
+    OBEX_UUID          = 0x0008,
+    IP_UUID            = 0x0009,
+    FTP_UUID           = 0x000a,
+    HTTP_UUID          = 0x000c,
+    WSP_UUID           = 0x000e,
+    BNEP_UUID          = 0x000f,
+    UPNP_UUID          = 0x0010,
+    HIDP_UUID          = 0x0011,
+    HCRP_CTRL_UUID     = 0x0012,
+    HCRP_DATA_UUID     = 0x0014,
+    HCRP_NOTE_UUID     = 0x0016,
+    AVCTP_UUID         = 0x0017,
+    AVDTP_UUID         = 0x0019,
+    CMTP_UUID          = 0x001b,
+    UDI_UUID           = 0x001d,
+    MCAP_CTRL_UUID     = 0x001e,
+    MCAP_DATA_UUID     = 0x001f,
+    L2CAP_UUID         = 0x0100,
+};
+
+/*
+ * Service class identifiers of standard services and service groups
+ */
+enum service_class_id {
+    SDP_SERVER_SVCLASS_ID              = 0x1000,
+    BROWSE_GRP_DESC_SVCLASS_ID         = 0x1001,
+    PUBLIC_BROWSE_GROUP                        = 0x1002,
+    SERIAL_PORT_SVCLASS_ID             = 0x1101,
+    LAN_ACCESS_SVCLASS_ID              = 0x1102,
+    DIALUP_NET_SVCLASS_ID              = 0x1103,
+    IRMC_SYNC_SVCLASS_ID               = 0x1104,
+    OBEX_OBJPUSH_SVCLASS_ID            = 0x1105,
+    OBEX_FILETRANS_SVCLASS_ID          = 0x1106,
+    IRMC_SYNC_CMD_SVCLASS_ID           = 0x1107,
+    HEADSET_SVCLASS_ID                 = 0x1108,
+    CORDLESS_TELEPHONY_SVCLASS_ID      = 0x1109,
+    AUDIO_SOURCE_SVCLASS_ID            = 0x110a,
+    AUDIO_SINK_SVCLASS_ID              = 0x110b,
+    AV_REMOTE_TARGET_SVCLASS_ID                = 0x110c,
+    ADVANCED_AUDIO_SVCLASS_ID          = 0x110d,
+    AV_REMOTE_SVCLASS_ID               = 0x110e,
+    VIDEO_CONF_SVCLASS_ID              = 0x110f,
+    INTERCOM_SVCLASS_ID                        = 0x1110,
+    FAX_SVCLASS_ID                     = 0x1111,
+    HEADSET_AGW_SVCLASS_ID             = 0x1112,
+    WAP_SVCLASS_ID                     = 0x1113,
+    WAP_CLIENT_SVCLASS_ID              = 0x1114,
+    PANU_SVCLASS_ID                    = 0x1115,
+    NAP_SVCLASS_ID                     = 0x1116,
+    GN_SVCLASS_ID                      = 0x1117,
+    DIRECT_PRINTING_SVCLASS_ID         = 0x1118,
+    REFERENCE_PRINTING_SVCLASS_ID      = 0x1119,
+    IMAGING_SVCLASS_ID                 = 0x111a,
+    IMAGING_RESPONDER_SVCLASS_ID       = 0x111b,
+    IMAGING_ARCHIVE_SVCLASS_ID         = 0x111c,
+    IMAGING_REFOBJS_SVCLASS_ID         = 0x111d,
+    HANDSFREE_SVCLASS_ID               = 0x111e,
+    HANDSFREE_AGW_SVCLASS_ID           = 0x111f,
+    DIRECT_PRT_REFOBJS_SVCLASS_ID      = 0x1120,
+    REFLECTED_UI_SVCLASS_ID            = 0x1121,
+    BASIC_PRINTING_SVCLASS_ID          = 0x1122,
+    PRINTING_STATUS_SVCLASS_ID         = 0x1123,
+    HID_SVCLASS_ID                     = 0x1124,
+    HCR_SVCLASS_ID                     = 0x1125,
+    HCR_PRINT_SVCLASS_ID               = 0x1126,
+    HCR_SCAN_SVCLASS_ID                        = 0x1127,
+    CIP_SVCLASS_ID                     = 0x1128,
+    VIDEO_CONF_GW_SVCLASS_ID           = 0x1129,
+    UDI_MT_SVCLASS_ID                  = 0x112a,
+    UDI_TA_SVCLASS_ID                  = 0x112b,
+    AV_SVCLASS_ID                      = 0x112c,
+    SAP_SVCLASS_ID                     = 0x112d,
+    PBAP_PCE_SVCLASS_ID                        = 0x112e,
+    PBAP_PSE_SVCLASS_ID                        = 0x112f,
+    PBAP_SVCLASS_ID                    = 0x1130,
+    PNP_INFO_SVCLASS_ID                        = 0x1200,
+    GENERIC_NETWORKING_SVCLASS_ID      = 0x1201,
+    GENERIC_FILETRANS_SVCLASS_ID       = 0x1202,
+    GENERIC_AUDIO_SVCLASS_ID           = 0x1203,
+    GENERIC_TELEPHONY_SVCLASS_ID       = 0x1204,
+    UPNP_SVCLASS_ID                    = 0x1205,
+    UPNP_IP_SVCLASS_ID                 = 0x1206,
+    UPNP_PAN_SVCLASS_ID                        = 0x1300,
+    UPNP_LAP_SVCLASS_ID                        = 0x1301,
+    UPNP_L2CAP_SVCLASS_ID              = 0x1302,
+    VIDEO_SOURCE_SVCLASS_ID            = 0x1303,
+    VIDEO_SINK_SVCLASS_ID              = 0x1304,
+    VIDEO_DISTRIBUTION_SVCLASS_ID      = 0x1305,
+    MDP_SVCLASS_ID                     = 0x1400,
+    MDP_SOURCE_SVCLASS_ID              = 0x1401,
+    MDP_SINK_SVCLASS_ID                        = 0x1402,
+    APPLE_AGENT_SVCLASS_ID             = 0x2112,
+};
+
+/*
+ * Standard profile descriptor identifiers; note these
+ * may be identical to some of the service classes defined above
+ */
+#define SDP_SERVER_PROFILE_ID          SDP_SERVER_SVCLASS_ID
+#define BROWSE_GRP_DESC_PROFILE_ID     BROWSE_GRP_DESC_SVCLASS_ID
+#define SERIAL_PORT_PROFILE_ID         SERIAL_PORT_SVCLASS_ID
+#define LAN_ACCESS_PROFILE_ID          LAN_ACCESS_SVCLASS_ID
+#define DIALUP_NET_PROFILE_ID          DIALUP_NET_SVCLASS_ID
+#define IRMC_SYNC_PROFILE_ID           IRMC_SYNC_SVCLASS_ID
+#define OBEX_OBJPUSH_PROFILE_ID                OBEX_OBJPUSH_SVCLASS_ID
+#define OBEX_FILETRANS_PROFILE_ID      OBEX_FILETRANS_SVCLASS_ID
+#define IRMC_SYNC_CMD_PROFILE_ID       IRMC_SYNC_CMD_SVCLASS_ID
+#define HEADSET_PROFILE_ID             HEADSET_SVCLASS_ID
+#define CORDLESS_TELEPHONY_PROFILE_ID  CORDLESS_TELEPHONY_SVCLASS_ID
+#define AUDIO_SOURCE_PROFILE_ID                AUDIO_SOURCE_SVCLASS_ID
+#define AUDIO_SINK_PROFILE_ID          AUDIO_SINK_SVCLASS_ID
+#define AV_REMOTE_TARGET_PROFILE_ID    AV_REMOTE_TARGET_SVCLASS_ID
+#define ADVANCED_AUDIO_PROFILE_ID      ADVANCED_AUDIO_SVCLASS_ID
+#define AV_REMOTE_PROFILE_ID           AV_REMOTE_SVCLASS_ID
+#define VIDEO_CONF_PROFILE_ID          VIDEO_CONF_SVCLASS_ID
+#define INTERCOM_PROFILE_ID            INTERCOM_SVCLASS_ID
+#define FAX_PROFILE_ID                 FAX_SVCLASS_ID
+#define HEADSET_AGW_PROFILE_ID         HEADSET_AGW_SVCLASS_ID
+#define WAP_PROFILE_ID                 WAP_SVCLASS_ID
+#define WAP_CLIENT_PROFILE_ID          WAP_CLIENT_SVCLASS_ID
+#define PANU_PROFILE_ID                        PANU_SVCLASS_ID
+#define NAP_PROFILE_ID                 NAP_SVCLASS_ID
+#define GN_PROFILE_ID                  GN_SVCLASS_ID
+#define DIRECT_PRINTING_PROFILE_ID     DIRECT_PRINTING_SVCLASS_ID
+#define REFERENCE_PRINTING_PROFILE_ID  REFERENCE_PRINTING_SVCLASS_ID
+#define IMAGING_PROFILE_ID             IMAGING_SVCLASS_ID
+#define IMAGING_RESPONDER_PROFILE_ID   IMAGING_RESPONDER_SVCLASS_ID
+#define IMAGING_ARCHIVE_PROFILE_ID     IMAGING_ARCHIVE_SVCLASS_ID
+#define IMAGING_REFOBJS_PROFILE_ID     IMAGING_REFOBJS_SVCLASS_ID
+#define HANDSFREE_PROFILE_ID           HANDSFREE_SVCLASS_ID
+#define HANDSFREE_AGW_PROFILE_ID       HANDSFREE_AGW_SVCLASS_ID
+#define DIRECT_PRT_REFOBJS_PROFILE_ID  DIRECT_PRT_REFOBJS_SVCLASS_ID
+#define REFLECTED_UI_PROFILE_ID                REFLECTED_UI_SVCLASS_ID
+#define BASIC_PRINTING_PROFILE_ID      BASIC_PRINTING_SVCLASS_ID
+#define PRINTING_STATUS_PROFILE_ID     PRINTING_STATUS_SVCLASS_ID
+#define HID_PROFILE_ID                 HID_SVCLASS_ID
+#define HCR_PROFILE_ID                 HCR_SCAN_SVCLASS_ID
+#define HCR_PRINT_PROFILE_ID           HCR_PRINT_SVCLASS_ID
+#define HCR_SCAN_PROFILE_ID            HCR_SCAN_SVCLASS_ID
+#define CIP_PROFILE_ID                 CIP_SVCLASS_ID
+#define VIDEO_CONF_GW_PROFILE_ID       VIDEO_CONF_GW_SVCLASS_ID
+#define UDI_MT_PROFILE_ID              UDI_MT_SVCLASS_ID
+#define UDI_TA_PROFILE_ID              UDI_TA_SVCLASS_ID
+#define AV_PROFILE_ID                  AV_SVCLASS_ID
+#define SAP_PROFILE_ID                 SAP_SVCLASS_ID
+#define PBAP_PCE_PROFILE_ID            PBAP_PCE_SVCLASS_ID
+#define PBAP_PSE_PROFILE_ID            PBAP_PSE_SVCLASS_ID
+#define PBAP_PROFILE_ID                        PBAP_SVCLASS_ID
+#define PNP_INFO_PROFILE_ID            PNP_INFO_SVCLASS_ID
+#define GENERIC_NETWORKING_PROFILE_ID  GENERIC_NETWORKING_SVCLASS_ID
+#define GENERIC_FILETRANS_PROFILE_ID   GENERIC_FILETRANS_SVCLASS_ID
+#define GENERIC_AUDIO_PROFILE_ID       GENERIC_AUDIO_SVCLASS_ID
+#define GENERIC_TELEPHONY_PROFILE_ID   GENERIC_TELEPHONY_SVCLASS_ID
+#define UPNP_PROFILE_ID                        UPNP_SVCLASS_ID
+#define UPNP_IP_PROFILE_ID             UPNP_IP_SVCLASS_ID
+#define UPNP_PAN_PROFILE_ID            UPNP_PAN_SVCLASS_ID
+#define UPNP_LAP_PROFILE_ID            UPNP_LAP_SVCLASS_ID
+#define UPNP_L2CAP_PROFILE_ID          UPNP_L2CAP_SVCLASS_ID
+#define VIDEO_SOURCE_PROFILE_ID                VIDEO_SOURCE_SVCLASS_ID
+#define VIDEO_SINK_PROFILE_ID          VIDEO_SINK_SVCLASS_ID
+#define VIDEO_DISTRIBUTION_PROFILE_ID  VIDEO_DISTRIBUTION_SVCLASS_ID
+#define MDP_PROFILE_ID                 MDP_SVCLASS_ID
+#define MDP_SOURCE_PROFILE_ID          MDP_SROUCE_SVCLASS_ID
+#define MDP_SINK_PROFILE_ID            MDP_SINK_SVCLASS_ID
+#define APPLE_AGENT_PROFILE_ID         APPLE_AGENT_SVCLASS_ID
+
+/* Data Representation */
+enum bt_sdp_data_type {
+    SDP_DTYPE_NIL      = 0 << 3,
+    SDP_DTYPE_UINT     = 1 << 3,
+    SDP_DTYPE_SINT     = 2 << 3,
+    SDP_DTYPE_UUID     = 3 << 3,
+    SDP_DTYPE_STRING   = 4 << 3,
+    SDP_DTYPE_BOOL     = 5 << 3,
+    SDP_DTYPE_SEQ      = 6 << 3,
+    SDP_DTYPE_ALT      = 7 << 3,
+    SDP_DTYPE_URL      = 8 << 3,
+};
+
+enum bt_sdp_data_size {
+    SDP_DSIZE_1                = 0,
+    SDP_DSIZE_2,
+    SDP_DSIZE_4,
+    SDP_DSIZE_8,
+    SDP_DSIZE_16,
+    SDP_DSIZE_NEXT1,
+    SDP_DSIZE_NEXT2,
+    SDP_DSIZE_NEXT4,
+    SDP_DSIZE_MASK = SDP_DSIZE_NEXT4,
+};
+
+enum bt_sdp_cmd {
+    SDP_ERROR_RSP              = 0x01,
+    SDP_SVC_SEARCH_REQ         = 0x02,
+    SDP_SVC_SEARCH_RSP         = 0x03,
+    SDP_SVC_ATTR_REQ           = 0x04,
+    SDP_SVC_ATTR_RSP           = 0x05,
+    SDP_SVC_SEARCH_ATTR_REQ    = 0x06,
+    SDP_SVC_SEARCH_ATTR_RSP    = 0x07,
+};
+
+enum bt_sdp_errorcode {
+    SDP_INVALID_VERSION                = 0x0001,
+    SDP_INVALID_RECORD_HANDLE  = 0x0002,
+    SDP_INVALID_SYNTAX         = 0x0003,
+    SDP_INVALID_PDU_SIZE       = 0x0004,
+    SDP_INVALID_CSTATE         = 0x0005,
+};
+
+/*
+ * String identifiers are based on the SDP spec stating that
+ * "base attribute id of the primary (universal) language must be 0x0100"
+ *
+ * Other languages should have their own offset; e.g.:
+ * #define XXXLangBase yyyy
+ * #define AttrServiceName_XXX 0x0000+XXXLangBase
+ */
+#define SDP_PRIMARY_LANG_BASE          0x0100
+
+enum bt_sdp_attribute_id {
+    SDP_ATTR_RECORD_HANDLE                     = 0x0000,
+    SDP_ATTR_SVCLASS_ID_LIST                   = 0x0001,
+    SDP_ATTR_RECORD_STATE                      = 0x0002,
+    SDP_ATTR_SERVICE_ID                                = 0x0003,
+    SDP_ATTR_PROTO_DESC_LIST                   = 0x0004,
+    SDP_ATTR_BROWSE_GRP_LIST                   = 0x0005,
+    SDP_ATTR_LANG_BASE_ATTR_ID_LIST            = 0x0006,
+    SDP_ATTR_SVCINFO_TTL                       = 0x0007,
+    SDP_ATTR_SERVICE_AVAILABILITY              = 0x0008,
+    SDP_ATTR_PFILE_DESC_LIST                   = 0x0009,
+    SDP_ATTR_DOC_URL                           = 0x000a,
+    SDP_ATTR_CLNT_EXEC_URL                     = 0x000b,
+    SDP_ATTR_ICON_URL                          = 0x000c,
+    SDP_ATTR_ADD_PROTO_DESC_LIST               = 0x000d,
+
+    SDP_ATTR_SVCNAME_PRIMARY                   = SDP_PRIMARY_LANG_BASE + 0,
+    SDP_ATTR_SVCDESC_PRIMARY                   = SDP_PRIMARY_LANG_BASE + 1,
+    SDP_ATTR_SVCPROV_PRIMARY                   = SDP_PRIMARY_LANG_BASE + 2,
+
+    SDP_ATTR_GROUP_ID                          = 0x0200,
+    SDP_ATTR_IP_SUBNET                         = 0x0200,
+
+    /* SDP */
+    SDP_ATTR_VERSION_NUM_LIST                  = 0x0200,
+    SDP_ATTR_SVCDB_STATE                       = 0x0201,
+
+    SDP_ATTR_SERVICE_VERSION                   = 0x0300,
+    SDP_ATTR_EXTERNAL_NETWORK                  = 0x0301,
+    SDP_ATTR_SUPPORTED_DATA_STORES_LIST                = 0x0301,
+    SDP_ATTR_FAX_CLASS1_SUPPORT                        = 0x0302,
+    SDP_ATTR_REMOTE_AUDIO_VOLUME_CONTROL       = 0x0302,
+    SDP_ATTR_FAX_CLASS20_SUPPORT               = 0x0303,
+    SDP_ATTR_SUPPORTED_FORMATS_LIST            = 0x0303,
+    SDP_ATTR_FAX_CLASS2_SUPPORT                        = 0x0304,
+    SDP_ATTR_AUDIO_FEEDBACK_SUPPORT            = 0x0305,
+    SDP_ATTR_NETWORK_ADDRESS                   = 0x0306,
+    SDP_ATTR_WAP_GATEWAY                       = 0x0307,
+    SDP_ATTR_HOMEPAGE_URL                      = 0x0308,
+    SDP_ATTR_WAP_STACK_TYPE                    = 0x0309,
+    SDP_ATTR_SECURITY_DESC                     = 0x030a,
+    SDP_ATTR_NET_ACCESS_TYPE                   = 0x030b,
+    SDP_ATTR_MAX_NET_ACCESSRATE                        = 0x030c,
+    SDP_ATTR_IP4_SUBNET                                = 0x030d,
+    SDP_ATTR_IP6_SUBNET                                = 0x030e,
+    SDP_ATTR_SUPPORTED_CAPABILITIES            = 0x0310,
+    SDP_ATTR_SUPPORTED_FEATURES                        = 0x0311,
+    SDP_ATTR_SUPPORTED_FUNCTIONS               = 0x0312,
+    SDP_ATTR_TOTAL_IMAGING_DATA_CAPACITY       = 0x0313,
+    SDP_ATTR_SUPPORTED_REPOSITORIES            = 0x0314,
+
+    /* PnP Information */
+    SDP_ATTR_SPECIFICATION_ID                  = 0x0200,
+    SDP_ATTR_VENDOR_ID                         = 0x0201,
+    SDP_ATTR_PRODUCT_ID                                = 0x0202,
+    SDP_ATTR_VERSION                           = 0x0203,
+    SDP_ATTR_PRIMARY_RECORD                    = 0x0204,
+    SDP_ATTR_VENDOR_ID_SOURCE                  = 0x0205,
+
+    /* BT HID */
+    SDP_ATTR_DEVICE_RELEASE_NUMBER             = 0x0200,
+    SDP_ATTR_PARSER_VERSION                    = 0x0201,
+    SDP_ATTR_DEVICE_SUBCLASS                   = 0x0202,
+    SDP_ATTR_COUNTRY_CODE                      = 0x0203,
+    SDP_ATTR_VIRTUAL_CABLE                     = 0x0204,
+    SDP_ATTR_RECONNECT_INITIATE                        = 0x0205,
+    SDP_ATTR_DESCRIPTOR_LIST                   = 0x0206,
+    SDP_ATTR_LANG_ID_BASE_LIST                 = 0x0207,
+    SDP_ATTR_SDP_DISABLE                       = 0x0208,
+    SDP_ATTR_BATTERY_POWER                     = 0x0209,
+    SDP_ATTR_REMOTE_WAKEUP                     = 0x020a,
+    SDP_ATTR_PROFILE_VERSION                   = 0x020b,
+    SDP_ATTR_SUPERVISION_TIMEOUT               = 0x020c,
+    SDP_ATTR_NORMALLY_CONNECTABLE              = 0x020d,
+    SDP_ATTR_BOOT_DEVICE                       = 0x020e,
+};
+
+#endif
diff --git a/include/hw/char/escc.h b/include/hw/char/escc.h
new file mode 100644 (file)
index 0000000..bda3213
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef HW_ESCC_H
+#define HW_ESCC_H 1
+
+/* escc.c */
+#define ESCC_SIZE 4
+MemoryRegion *escc_init(hwaddr base, qemu_irq irqA, qemu_irq irqB,
+              CharDriverState *chrA, CharDriverState *chrB,
+              int clock, int it_shift);
+
+void slavio_serial_ms_kbd_init(hwaddr base, qemu_irq irq,
+                               int disabled, int clock, int it_shift);
+
+#endif
diff --git a/include/hw/char/serial.h b/include/hw/char/serial.h
new file mode 100644 (file)
index 0000000..e884499
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * QEMU 16550A UART emulation
+ *
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ * Copyright (c) 2008 Citrix Systems, 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.
+ */
+#ifndef HW_SERIAL_H
+#define HW_SERIAL_H 1
+
+#include "hw/hw.h"
+#include "sysemu/sysemu.h"
+#include "exec/memory.h"
+
+#define UART_FIFO_LENGTH    16      /* 16550A Fifo Length */
+
+typedef struct SerialFIFO {
+    uint8_t data[UART_FIFO_LENGTH];
+    uint8_t count;
+    uint8_t itl;                        /* Interrupt Trigger Level */
+    uint8_t tail;
+    uint8_t head;
+} SerialFIFO;
+
+struct SerialState {
+    uint16_t divider;
+    uint8_t rbr; /* receive register */
+    uint8_t thr; /* transmit holding register */
+    uint8_t tsr; /* transmit shift register */
+    uint8_t ier;
+    uint8_t iir; /* read only */
+    uint8_t lcr;
+    uint8_t mcr;
+    uint8_t lsr; /* read only */
+    uint8_t msr; /* read only */
+    uint8_t scr;
+    uint8_t fcr;
+    uint8_t fcr_vmstate; /* we can't write directly this value
+                            it has side effects */
+    /* NOTE: this hidden state is necessary for tx irq generation as
+       it can be reset while reading iir */
+    int thr_ipending;
+    qemu_irq irq;
+    CharDriverState *chr;
+    int last_break_enable;
+    int it_shift;
+    int baudbase;
+    int tsr_retry;
+    uint32_t wakeup;
+
+    /* Time when the last byte was successfully sent out of the tsr */
+    uint64_t last_xmit_ts;
+    SerialFIFO recv_fifo;
+    SerialFIFO xmit_fifo;
+
+    struct QEMUTimer *fifo_timeout_timer;
+    int timeout_ipending;           /* timeout interrupt pending state */
+
+    uint64_t char_transmit_time;    /* time to transmit a char in ticks */
+    int poll_msl;
+
+    struct QEMUTimer *modem_status_poll;
+    MemoryRegion io;
+};
+
+extern const VMStateDescription vmstate_serial;
+extern const MemoryRegionOps serial_io_ops;
+
+void serial_init_core(SerialState *s);
+void serial_exit_core(SerialState *s);
+void serial_set_frequency(SerialState *s, uint32_t frequency);
+
+/* legacy pre qom */
+SerialState *serial_init(int base, qemu_irq irq, int baudbase,
+                         CharDriverState *chr, MemoryRegion *system_io);
+SerialState *serial_mm_init(MemoryRegion *address_space,
+                            hwaddr base, int it_shift,
+                            qemu_irq irq, int baudbase,
+                            CharDriverState *chr, enum device_endian end);
+
+/* serial-isa.c */
+bool serial_isa_init(ISABus *bus, int index, CharDriverState *chr);
+
+#endif
diff --git a/include/hw/cris/etraxfs.h b/include/hw/cris/etraxfs.h
new file mode 100644 (file)
index 0000000..ab30559
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * QEMU ETRAX System Emulator
+ *
+ * Copyright (c) 2008 Edgar E. Iglesias, Axis Communications AB.
+ *
+ * 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_EXTRAXFS_H
+#define HW_EXTRAXFS_H 1
+
+#include "net/net.h"
+#include "hw/cris/etraxfs_dma.h"
+
+qemu_irq *cris_pic_init_cpu(CPUCRISState *env);
+
+/* Instantiate an ETRAXFS Ethernet MAC.  */
+static inline DeviceState *
+etraxfs_eth_init(NICInfo *nd, hwaddr base, int phyaddr,
+                 void *dma_out, void *dma_in)
+{
+    DeviceState *dev;
+    qemu_check_nic_model(nd, "fseth");
+
+    dev = qdev_create(NULL, "etraxfs-eth");
+    qdev_set_nic_properties(dev, nd);
+    qdev_prop_set_uint32(dev, "phyaddr", phyaddr);
+    qdev_prop_set_ptr(dev, "dma_out", dma_out);
+    qdev_prop_set_ptr(dev, "dma_in", dma_in);
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
+    return dev;
+}
+
+#endif
diff --git a/include/hw/cris/etraxfs_dma.h b/include/hw/cris/etraxfs_dma.h
new file mode 100644 (file)
index 0000000..38104a6
--- /dev/null
@@ -0,0 +1,34 @@
+#ifndef HW_ETRAXFS_DMA_H
+#define HW_ETRAXFS_DMA_H 1
+
+struct dma_context_metadata {
+       /* data descriptor md */
+       uint16_t metadata;
+};
+
+struct etraxfs_dma_client
+{
+       /* DMA controller. */
+       int channel;
+       void *ctrl;
+
+       /* client.  */
+       struct {
+               int (*push)(void *opaque, unsigned char *buf,
+                           int len, bool eop);
+               void (*pull)(void *opaque);
+               void (*metadata_push)(void *opaque,
+                                     const struct dma_context_metadata *md);
+               void *opaque;
+       } client;
+};
+
+void *etraxfs_dmac_init(hwaddr base, int nr_channels);
+void etraxfs_dmac_connect(void *opaque, int channel, qemu_irq *line,
+                         int input);
+void etraxfs_dmac_connect_client(void *opaque, int c, 
+                                struct etraxfs_dma_client *cl);
+int etraxfs_dmac_input(struct etraxfs_dma_client *client, 
+                      void *buf, int len, int eop);
+
+#endif
diff --git a/include/hw/elf_ops.h b/include/hw/elf_ops.h
new file mode 100644 (file)
index 0000000..acc701e
--- /dev/null
@@ -0,0 +1,309 @@
+static void glue(bswap_ehdr, SZ)(struct elfhdr *ehdr)
+{
+    bswap16s(&ehdr->e_type);                   /* Object file type */
+    bswap16s(&ehdr->e_machine);                /* Architecture */
+    bswap32s(&ehdr->e_version);                /* Object file version */
+    bswapSZs(&ehdr->e_entry);          /* Entry point virtual address */
+    bswapSZs(&ehdr->e_phoff);          /* Program header table file offset */
+    bswapSZs(&ehdr->e_shoff);          /* Section header table file offset */
+    bswap32s(&ehdr->e_flags);          /* Processor-specific flags */
+    bswap16s(&ehdr->e_ehsize);         /* ELF header size in bytes */
+    bswap16s(&ehdr->e_phentsize);              /* Program header table entry size */
+    bswap16s(&ehdr->e_phnum);          /* Program header table entry count */
+    bswap16s(&ehdr->e_shentsize);              /* Section header table entry size */
+    bswap16s(&ehdr->e_shnum);          /* Section header table entry count */
+    bswap16s(&ehdr->e_shstrndx);               /* Section header string table index */
+}
+
+static void glue(bswap_phdr, SZ)(struct elf_phdr *phdr)
+{
+    bswap32s(&phdr->p_type);                   /* Segment type */
+    bswapSZs(&phdr->p_offset);         /* Segment file offset */
+    bswapSZs(&phdr->p_vaddr);          /* Segment virtual address */
+    bswapSZs(&phdr->p_paddr);          /* Segment physical address */
+    bswapSZs(&phdr->p_filesz);         /* Segment size in file */
+    bswapSZs(&phdr->p_memsz);          /* Segment size in memory */
+    bswap32s(&phdr->p_flags);          /* Segment flags */
+    bswapSZs(&phdr->p_align);          /* Segment alignment */
+}
+
+static void glue(bswap_shdr, SZ)(struct elf_shdr *shdr)
+{
+    bswap32s(&shdr->sh_name);
+    bswap32s(&shdr->sh_type);
+    bswapSZs(&shdr->sh_flags);
+    bswapSZs(&shdr->sh_addr);
+    bswapSZs(&shdr->sh_offset);
+    bswapSZs(&shdr->sh_size);
+    bswap32s(&shdr->sh_link);
+    bswap32s(&shdr->sh_info);
+    bswapSZs(&shdr->sh_addralign);
+    bswapSZs(&shdr->sh_entsize);
+}
+
+static void glue(bswap_sym, SZ)(struct elf_sym *sym)
+{
+    bswap32s(&sym->st_name);
+    bswapSZs(&sym->st_value);
+    bswapSZs(&sym->st_size);
+    bswap16s(&sym->st_shndx);
+}
+
+static struct elf_shdr *glue(find_section, SZ)(struct elf_shdr *shdr_table,
+                                               int n, int type)
+{
+    int i;
+    for(i=0;i<n;i++) {
+        if (shdr_table[i].sh_type == type)
+            return shdr_table + i;
+    }
+    return NULL;
+}
+
+static int glue(symfind, SZ)(const void *s0, const void *s1)
+{
+    hwaddr addr = *(hwaddr *)s0;
+    struct elf_sym *sym = (struct elf_sym *)s1;
+    int result = 0;
+    if (addr < sym->st_value) {
+        result = -1;
+    } else if (addr >= sym->st_value + sym->st_size) {
+        result = 1;
+    }
+    return result;
+}
+
+static const char *glue(lookup_symbol, SZ)(struct syminfo *s,
+                                           hwaddr orig_addr)
+{
+    struct elf_sym *syms = glue(s->disas_symtab.elf, SZ);
+    struct elf_sym *sym;
+
+    sym = bsearch(&orig_addr, syms, s->disas_num_syms, sizeof(*syms),
+                  glue(symfind, SZ));
+    if (sym != NULL) {
+        return s->disas_strtab + sym->st_name;
+    }
+
+    return "";
+}
+
+static int glue(symcmp, SZ)(const void *s0, const void *s1)
+{
+    struct elf_sym *sym0 = (struct elf_sym *)s0;
+    struct elf_sym *sym1 = (struct elf_sym *)s1;
+    return (sym0->st_value < sym1->st_value)
+        ? -1
+        : ((sym0->st_value > sym1->st_value) ? 1 : 0);
+}
+
+static int glue(load_symbols, SZ)(struct elfhdr *ehdr, int fd, int must_swab,
+                                  int clear_lsb)
+{
+    struct elf_shdr *symtab, *strtab, *shdr_table = NULL;
+    struct elf_sym *syms = NULL;
+    struct syminfo *s;
+    int nsyms, i;
+    char *str = NULL;
+
+    shdr_table = load_at(fd, ehdr->e_shoff,
+                         sizeof(struct elf_shdr) * ehdr->e_shnum);
+    if (!shdr_table)
+        return -1;
+
+    if (must_swab) {
+        for (i = 0; i < ehdr->e_shnum; i++) {
+            glue(bswap_shdr, SZ)(shdr_table + i);
+        }
+    }
+
+    symtab = glue(find_section, SZ)(shdr_table, ehdr->e_shnum, SHT_SYMTAB);
+    if (!symtab)
+        goto fail;
+    syms = load_at(fd, symtab->sh_offset, symtab->sh_size);
+    if (!syms)
+        goto fail;
+
+    nsyms = symtab->sh_size / sizeof(struct elf_sym);
+
+    i = 0;
+    while (i < nsyms) {
+        if (must_swab)
+            glue(bswap_sym, SZ)(&syms[i]);
+        /* We are only interested in function symbols.
+           Throw everything else away.  */
+        if (syms[i].st_shndx == SHN_UNDEF ||
+                syms[i].st_shndx >= SHN_LORESERVE ||
+                ELF_ST_TYPE(syms[i].st_info) != STT_FUNC) {
+            nsyms--;
+            if (i < nsyms) {
+                syms[i] = syms[nsyms];
+            }
+            continue;
+        }
+        if (clear_lsb) {
+            /* The bottom address bit marks a Thumb or MIPS16 symbol.  */
+            syms[i].st_value &= ~(glue(glue(Elf, SZ), _Addr))1;
+        }
+        i++;
+    }
+    if (nsyms) {
+        syms = g_realloc(syms, nsyms * sizeof(*syms));
+
+        qsort(syms, nsyms, sizeof(*syms), glue(symcmp, SZ));
+        for (i = 0; i < nsyms - 1; i++) {
+            if (syms[i].st_size == 0) {
+                syms[i].st_size = syms[i + 1].st_value - syms[i].st_value;
+            }
+        }
+    } else {
+        g_free(syms);
+        syms = NULL;
+    }
+
+    /* String table */
+    if (symtab->sh_link >= ehdr->e_shnum)
+        goto fail;
+    strtab = &shdr_table[symtab->sh_link];
+
+    str = load_at(fd, strtab->sh_offset, strtab->sh_size);
+    if (!str)
+        goto fail;
+
+    /* Commit */
+    s = g_malloc0(sizeof(*s));
+    s->lookup_symbol = glue(lookup_symbol, SZ);
+    glue(s->disas_symtab.elf, SZ) = syms;
+    s->disas_num_syms = nsyms;
+    s->disas_strtab = str;
+    s->next = syminfos;
+    syminfos = s;
+    g_free(shdr_table);
+    return 0;
+ fail:
+    g_free(syms);
+    g_free(str);
+    g_free(shdr_table);
+    return -1;
+}
+
+static int glue(load_elf, SZ)(const char *name, int fd,
+                              uint64_t (*translate_fn)(void *, uint64_t),
+                              void *translate_opaque,
+                              int must_swab, uint64_t *pentry,
+                              uint64_t *lowaddr, uint64_t *highaddr,
+                              int elf_machine, int clear_lsb)
+{
+    struct elfhdr ehdr;
+    struct elf_phdr *phdr = NULL, *ph;
+    int size, i, total_size;
+    elf_word mem_size, file_size;
+    uint64_t addr, low = (uint64_t)-1, high = 0;
+    uint8_t *data = NULL;
+    char label[128];
+
+    if (read(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr))
+        goto fail;
+    if (must_swab) {
+        glue(bswap_ehdr, SZ)(&ehdr);
+    }
+
+    switch (elf_machine) {
+        case EM_PPC64:
+            if (EM_PPC64 != ehdr.e_machine)
+                if (EM_PPC != ehdr.e_machine)
+                    goto fail;
+            break;
+        case EM_X86_64:
+            if (EM_X86_64 != ehdr.e_machine)
+                if (EM_386 != ehdr.e_machine)
+                    goto fail;
+            break;
+        case EM_MICROBLAZE:
+            if (EM_MICROBLAZE != ehdr.e_machine)
+                if (EM_MICROBLAZE_OLD != ehdr.e_machine)
+                    goto fail;
+            break;
+        default:
+            if (elf_machine != ehdr.e_machine)
+                goto fail;
+    }
+
+    if (pentry)
+       *pentry = (uint64_t)(elf_sword)ehdr.e_entry;
+
+    glue(load_symbols, SZ)(&ehdr, fd, must_swab, clear_lsb);
+
+    size = ehdr.e_phnum * sizeof(phdr[0]);
+    lseek(fd, ehdr.e_phoff, SEEK_SET);
+    phdr = g_malloc0(size);
+    if (!phdr)
+        goto fail;
+    if (read(fd, phdr, size) != size)
+        goto fail;
+    if (must_swab) {
+        for(i = 0; i < ehdr.e_phnum; i++) {
+            ph = &phdr[i];
+            glue(bswap_phdr, SZ)(ph);
+        }
+    }
+
+    total_size = 0;
+    for(i = 0; i < ehdr.e_phnum; i++) {
+        ph = &phdr[i];
+        if (ph->p_type == PT_LOAD) {
+            mem_size = ph->p_memsz; /* Size of the ROM */
+            file_size = ph->p_filesz; /* Size of the allocated data */
+            data = g_malloc0(file_size);
+            if (ph->p_filesz > 0) {
+                if (lseek(fd, ph->p_offset, SEEK_SET) < 0) {
+                    goto fail;
+                }
+                if (read(fd, data, file_size) != file_size) {
+                    goto fail;
+                }
+            }
+            /* address_offset is hack for kernel images that are
+               linked at the wrong physical address.  */
+            if (translate_fn) {
+                addr = translate_fn(translate_opaque, ph->p_paddr);
+            } else {
+                addr = ph->p_paddr;
+            }
+
+            /* the entry pointer in the ELF header is a virtual
+             * address, if the text segments paddr and vaddr differ
+             * we need to adjust the entry */
+            if (pentry && !translate_fn &&
+                    ph->p_vaddr != ph->p_paddr &&
+                    ehdr.e_entry >= ph->p_vaddr &&
+                    ehdr.e_entry < ph->p_vaddr + ph->p_filesz &&
+                    ph->p_flags & PF_X) {
+                *pentry = ehdr.e_entry - ph->p_vaddr + ph->p_paddr;
+            }
+
+            snprintf(label, sizeof(label), "phdr #%d: %s", i, name);
+
+            /* rom_add_elf_program() seize the ownership of 'data' */
+            rom_add_elf_program(label, data, file_size, mem_size, addr);
+
+            total_size += mem_size;
+            if (addr < low)
+                low = addr;
+            if ((addr + mem_size) > high)
+                high = addr + mem_size;
+
+            data = NULL;
+        }
+    }
+    g_free(phdr);
+    if (lowaddr)
+        *lowaddr = (uint64_t)(elf_sword)low;
+    if (highaddr)
+        *highaddr = (uint64_t)(elf_sword)high;
+    return total_size;
+ fail:
+    g_free(data);
+    g_free(phdr);
+    return -1;
+}
diff --git a/include/hw/empty_slot.h b/include/hw/empty_slot.h
new file mode 100644 (file)
index 0000000..6079602
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef HW_EMPTY_SLOT_H
+#define HW_EMPTY_SLOT_H 1
+
+/* empty_slot.c */
+void empty_slot_init(hwaddr addr, uint64_t slot_size);
+
+#endif
diff --git a/include/hw/hw.h b/include/hw/hw.h
new file mode 100644 (file)
index 0000000..1fb9afa
--- /dev/null
@@ -0,0 +1,76 @@
+/* Declarations for use by hardware emulation.  */
+#ifndef QEMU_HW_H
+#define QEMU_HW_H
+
+#include "qemu-common.h"
+
+#if !defined(CONFIG_USER_ONLY) && !defined(NEED_CPU_H)
+#include "exec/cpu-common.h"
+#endif
+
+#include "exec/ioport.h"
+#include "hw/irq.h"
+#include "block/aio.h"
+#include "migration/qemu-file.h"
+#include "migration/vmstate.h"
+#include "qemu/log.h"
+
+#ifdef NEED_CPU_H
+#if TARGET_LONG_BITS == 64
+#define qemu_put_betl qemu_put_be64
+#define qemu_get_betl qemu_get_be64
+#define qemu_put_betls qemu_put_be64s
+#define qemu_get_betls qemu_get_be64s
+#define qemu_put_sbetl qemu_put_sbe64
+#define qemu_get_sbetl qemu_get_sbe64
+#define qemu_put_sbetls qemu_put_sbe64s
+#define qemu_get_sbetls qemu_get_sbe64s
+#else
+#define qemu_put_betl qemu_put_be32
+#define qemu_get_betl qemu_get_be32
+#define qemu_put_betls qemu_put_be32s
+#define qemu_get_betls qemu_get_be32s
+#define qemu_put_sbetl qemu_put_sbe32
+#define qemu_get_sbetl qemu_get_sbe32
+#define qemu_put_sbetls qemu_put_sbe32s
+#define qemu_get_sbetls qemu_get_sbe32s
+#endif
+#endif
+
+typedef void QEMUResetHandler(void *opaque);
+
+void qemu_register_reset(QEMUResetHandler *func, void *opaque);
+void qemu_unregister_reset(QEMUResetHandler *func, void *opaque);
+
+/* handler to set the boot_device order for a specific type of QEMUMachine */
+/* return 0 if success */
+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);
+
+#ifdef NEED_CPU_H
+#if TARGET_LONG_BITS == 64
+#define VMSTATE_UINTTL_V(_f, _s, _v)                                  \
+    VMSTATE_UINT64_V(_f, _s, _v)
+#define VMSTATE_UINTTL_EQUAL_V(_f, _s, _v)                            \
+    VMSTATE_UINT64_EQUAL_V(_f, _s, _v)
+#define VMSTATE_UINTTL_ARRAY_V(_f, _s, _n, _v)                        \
+    VMSTATE_UINT64_ARRAY_V(_f, _s, _n, _v)
+#else
+#define VMSTATE_UINTTL_V(_f, _s, _v)                                  \
+    VMSTATE_UINT32_V(_f, _s, _v)
+#define VMSTATE_UINTTL_EQUAL_V(_f, _s, _v)                            \
+    VMSTATE_UINT32_EQUAL_V(_f, _s, _v)
+#define VMSTATE_UINTTL_ARRAY_V(_f, _s, _n, _v)                        \
+    VMSTATE_UINT32_ARRAY_V(_f, _s, _n, _v)
+#endif
+#define VMSTATE_UINTTL(_f, _s)                                        \
+    VMSTATE_UINTTL_V(_f, _s, 0)
+#define VMSTATE_UINTTL_EQUAL(_f, _s)                                  \
+    VMSTATE_UINTTL_EQUAL_V(_f, _s, 0)
+#define VMSTATE_UINTTL_ARRAY(_f, _s, _n)                              \
+    VMSTATE_UINTTL_ARRAY_V(_f, _s, _n, 0)
+
+#endif
+
+#endif
diff --git a/include/hw/i2c/i2c.h b/include/hw/i2c/i2c.h
new file mode 100644 (file)
index 0000000..461392f
--- /dev/null
@@ -0,0 +1,88 @@
+#ifndef QEMU_I2C_H
+#define QEMU_I2C_H
+
+#include "hw/qdev.h"
+
+/* The QEMU I2C implementation only supports simple transfers that complete
+   immediately.  It does not support slave devices that need to be able to
+   defer their response (eg. CPU slave interfaces where the data is supplied
+   by the device driver in response to an interrupt).  */
+
+enum i2c_event {
+    I2C_START_RECV,
+    I2C_START_SEND,
+    I2C_FINISH,
+    I2C_NACK /* Masker NACKed a receive byte.  */
+};
+
+typedef struct I2CSlave I2CSlave;
+
+#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);
+
+    /* Master to slave.  */
+    int (*send)(I2CSlave *s, uint8_t data);
+
+    /* Slave to master.  */
+    int (*recv)(I2CSlave *s);
+
+    /* Notify the slave of a bus state change.  */
+    void (*event)(I2CSlave *s, enum i2c_event event);
+} I2CSlaveClass;
+
+struct I2CSlave
+{
+    DeviceState qdev;
+
+    /* Remaining fields for internal use by the I2C code.  */
+    uint8_t address;
+};
+
+i2c_bus *i2c_init_bus(DeviceState *parent, const char *name);
+void i2c_set_slave_address(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);
+void i2c_nack(i2c_bus *bus);
+int i2c_send(i2c_bus *bus, uint8_t data);
+int i2c_recv(i2c_bus *bus);
+
+#define FROM_I2C_SLAVE(type, dev) DO_UPCAST(type, i2c, dev)
+
+DeviceState *i2c_create_slave(i2c_bus *bus, const char *name, uint8_t addr);
+
+/* wm8750.c */
+void wm8750_data_req_set(DeviceState *dev,
+                void (*data_req)(void *, int, int), void *opaque);
+void wm8750_dac_dat(void *opaque, uint32_t sample);
+uint32_t wm8750_adc_dat(void *opaque);
+void *wm8750_dac_buffer(void *opaque, int samples);
+void wm8750_dac_commit(void *opaque);
+void wm8750_set_bclk_in(void *opaque, int new_hz);
+
+/* 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(I2CSlave),                                  \
+    .vmsd       = &vmstate_i2c_slave,                                \
+    .flags      = VMS_STRUCT,                                        \
+    .offset     = vmstate_offset_value(_state, _field, I2CSlave),    \
+}
+
+#endif
diff --git a/include/hw/i2c/pm_smbus.h b/include/hw/i2c/pm_smbus.h
new file mode 100644 (file)
index 0000000..e3069bf
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef PM_SMBUS_H
+#define PM_SMBUS_H
+
+typedef struct PMSMBus {
+    i2c_bus *smbus;
+    MemoryRegion io;
+
+    uint8_t smb_stat;
+    uint8_t smb_ctl;
+    uint8_t smb_cmd;
+    uint8_t smb_addr;
+    uint8_t smb_data0;
+    uint8_t smb_data1;
+    uint8_t smb_data[32];
+    uint8_t smb_index;
+} PMSMBus;
+
+void pm_smbus_init(DeviceState *parent, PMSMBus *smb);
+
+#endif /* !PM_SMBUS_H */
diff --git a/include/hw/i2c/smbus.h b/include/hw/i2c/smbus.h
new file mode 100644 (file)
index 0000000..d764d75
--- /dev/null
@@ -0,0 +1,83 @@
+#ifndef QEMU_SMBUS_H
+#define QEMU_SMBUS_H
+
+/*
+ * QEMU SMBus API
+ *
+ * Copyright (c) 2007 Arastra, 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 "hw/i2c/i2c.h"
+
+#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 SMBusDeviceClass
+{
+    I2CSlaveClass parent_class;
+    int (*init)(SMBusDevice *dev);
+    void (*quick_cmd)(SMBusDevice *dev, uint8_t read);
+    void (*send_byte)(SMBusDevice *dev, uint8_t val);
+    uint8_t (*receive_byte)(SMBusDevice *dev);
+    /* We can't distinguish between a word write and a block write with
+       length 1, so pass the whole data block including the length byte
+       (if present).  The device is responsible figuring out what type of
+       command  this is.  */
+    void (*write_data)(SMBusDevice *dev, uint8_t cmd, uint8_t *buf, int len);
+    /* Likewise we can't distinguish between different reads, or even know
+       the length of the read until the read is complete, so read data a
+       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);
+} SMBusDeviceClass;
+
+struct SMBusDevice {
+    /* The SMBus protocol is implemented on top of I2C.  */
+    I2CSlave i2c;
+
+    /* Remaining fields for internal use only.  */
+    int mode;
+    int data_len;
+    uint8_t data_buf[34]; /* command + len + 32 bytes of data.  */
+    uint8_t command;
+};
+
+/* Master device commands.  */
+void smbus_quick_command(i2c_bus *bus, uint8_t addr, int read);
+uint8_t smbus_receive_byte(i2c_bus *bus, uint8_t addr);
+void smbus_send_byte(i2c_bus *bus, uint8_t addr, uint8_t data);
+uint8_t smbus_read_byte(i2c_bus *bus, uint8_t addr, uint8_t command);
+void smbus_write_byte(i2c_bus *bus, uint8_t addr, uint8_t command, uint8_t data);
+uint16_t smbus_read_word(i2c_bus *bus, uint8_t addr, uint8_t command);
+void smbus_write_word(i2c_bus *bus, uint8_t addr, uint8_t command, uint16_t data);
+int smbus_read_block(i2c_bus *bus, uint8_t addr, uint8_t command, uint8_t *data);
+void smbus_write_block(i2c_bus *bus, uint8_t addr, uint8_t command, uint8_t *data,
+                       int len);
+
+void smbus_eeprom_init(i2c_bus *smbus, int nb_eeprom,
+                       const uint8_t *eeprom_spd, int size);
+
+#endif
diff --git a/include/hw/i386/apic-msidef.h b/include/hw/i386/apic-msidef.h
new file mode 100644 (file)
index 0000000..6e2eb71
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef HW_APIC_MSIDEF_H
+#define HW_APIC_MSIDEF_H
+
+/*
+ * Intel APIC constants: from include/asm/msidef.h
+ */
+
+/*
+ * Shifts for MSI data
+ */
+
+#define MSI_DATA_VECTOR_SHIFT           0
+#define  MSI_DATA_VECTOR_MASK           0x000000ff
+
+#define MSI_DATA_DELIVERY_MODE_SHIFT    8
+#define MSI_DATA_LEVEL_SHIFT            14
+#define MSI_DATA_TRIGGER_SHIFT          15
+
+/*
+ * Shift/mask fields for msi address
+ */
+
+#define MSI_ADDR_DEST_MODE_SHIFT        2
+
+#define MSI_ADDR_REDIRECTION_SHIFT      3
+
+#define MSI_ADDR_DEST_ID_SHIFT          12
+#define  MSI_ADDR_DEST_ID_MASK          0x00ffff0
+
+#endif /* HW_APIC_MSIDEF_H */
diff --git a/include/hw/i386/apic.h b/include/hw/i386/apic.h
new file mode 100644 (file)
index 0000000..1d48e02
--- /dev/null
@@ -0,0 +1,32 @@
+#ifndef APIC_H
+#define APIC_H
+
+#include "qemu-common.h"
+
+/* apic.c */
+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);
+void cpu_set_apic_base(DeviceState *s, uint64_t val);
+uint64_t cpu_get_apic_base(DeviceState *s);
+void cpu_set_apic_tpr(DeviceState *s, uint8_t val);
+uint8_t cpu_get_apic_tpr(DeviceState *s);
+void apic_init_reset(DeviceState *s);
+void apic_sipi(DeviceState *s);
+void apic_handle_tpr_access_report(DeviceState *d, target_ulong ip,
+                                   TPRAccess access);
+void apic_poll_irq(DeviceState *d);
+void apic_designate_bsp(DeviceState *d);
+
+/* pc.c */
+DeviceState *cpu_get_current_apic(void);
+
+/* cpu.c */
+bool cpu_is_bsp(X86CPU *cpu);
+
+#endif
diff --git a/include/hw/i386/apic_internal.h b/include/hw/i386/apic_internal.h
new file mode 100644 (file)
index 0000000..578241f
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ *  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 "exec/memory.h"
+#include "hw/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 VAPIC_ENABLE_BIT                0
+#define VAPIC_ENABLE_MASK               (1 << VAPIC_ENABLE_BIT)
+
+#define MAX_APICS 255
+
+#define MSI_SPACE_SIZE                  0x100000
+
+typedef struct APICCommonState APICCommonState;
+
+#define TYPE_APIC_COMMON "apic-common"
+#define APIC_COMMON(obj) \
+     OBJECT_CHECK(APICCommonState, (obj), TYPE_APIC_COMMON)
+#define APIC_COMMON_CLASS(klass) \
+     OBJECT_CLASS_CHECK(APICCommonClass, (klass), TYPE_APIC_COMMON)
+#define APIC_COMMON_GET_CLASS(obj) \
+     OBJECT_GET_CLASS(APICCommonClass, (obj), TYPE_APIC_COMMON)
+
+typedef struct APICCommonClass
+{
+    SysBusDeviceClass parent_class;
+
+    void (*init)(APICCommonState *s);
+    void (*set_base)(APICCommonState *s, uint64_t val);
+    void (*set_tpr)(APICCommonState *s, uint8_t val);
+    uint8_t (*get_tpr)(APICCommonState *s);
+    void (*enable_tpr_reporting)(APICCommonState *s, bool enable);
+    void (*vapic_base_update)(APICCommonState *s);
+    void (*external_nmi)(APICCommonState *s);
+    void (*pre_save)(APICCommonState *s);
+    void (*post_load)(APICCommonState *s);
+} APICCommonClass;
+
+struct APICCommonState {
+    SysBusDevice busdev;
+
+    MemoryRegion io_memory;
+    X86CPU *cpu;
+    uint32_t apicbase;
+    uint8_t id;
+    uint8_t arb_id;
+    uint8_t tpr;
+    uint32_t spurious_vec;
+    uint8_t log_dest;
+    uint8_t dest_mode;
+    uint32_t isr[8];  /* in service register */
+    uint32_t tmr[8];  /* trigger mode register */
+    uint32_t irr[8]; /* interrupt request register */
+    uint32_t lvt[APIC_LVT_NB];
+    uint32_t esr; /* error register */
+    uint32_t icr[2];
+
+    uint32_t divide_conf;
+    int count_shift;
+    uint32_t initial_count;
+    int64_t initial_count_load_time;
+    int64_t next_time;
+    int idx;
+    QEMUTimer *timer;
+    int64_t timer_expiry;
+    int sipi_vector;
+    int wait_for_sipi;
+
+    uint32_t vapic_control;
+    DeviceState *vapic;
+    hwaddr vapic_paddr; /* note: persistence via kvmvapic */
+};
+
+typedef struct VAPICState {
+    uint8_t tpr;
+    uint8_t isr;
+    uint8_t zero;
+    uint8_t irr;
+    uint8_t enabled;
+} QEMU_PACKED VAPICState;
+
+extern bool apic_report_tpr_access;
+
+void apic_report_irq_delivered(int delivered);
+bool apic_next_timer(APICCommonState *s, int64_t current_time);
+void apic_enable_tpr_access_reporting(DeviceState *d, bool enable);
+void apic_enable_vapic(DeviceState *d, hwaddr paddr);
+
+void vapic_report_tpr_access(DeviceState *dev, CPUState *cpu, target_ulong ip,
+                             TPRAccess access);
+
+#endif /* !QEMU_APIC_INTERNAL_H */
diff --git a/include/hw/i386/ich9.h b/include/hw/i386/ich9.h
new file mode 100644 (file)
index 0000000..51d5981
--- /dev/null
@@ -0,0 +1,219 @@
+#ifndef HW_ICH9_H
+#define HW_ICH9_H
+
+#include "hw/hw.h"
+#include "qemu/range.h"
+#include "hw/isa/isa.h"
+#include "hw/sysbus.h"
+#include "hw/i386/pc.h"
+#include "hw/isa/apm.h"
+#include "hw/i386/ioapic.h"
+#include "hw/pci/pci.h"
+#include "hw/pci/pcie_host.h"
+#include "hw/pci/pci_bridge.h"
+#include "hw/acpi/acpi.h"
+#include "hw/acpi/ich9.h"
+#include "hw/pci/pci_bus.h"
+
+void ich9_lpc_set_irq(void *opaque, int irq_num, int level);
+int ich9_lpc_map_irq(PCIDevice *pci_dev, int intx);
+PCIINTxRoute ich9_route_intx_pin_to_irq(void *opaque, int pirq_pin);
+void ich9_lpc_pm_init(PCIDevice *pci_lpc, qemu_irq cmos_s3);
+PCIBus *ich9_d2pbr_init(PCIBus *bus, int devfn, int sec_bus);
+i2c_bus *ich9_smb_init(PCIBus *bus, int devfn, uint32_t smb_io_base);
+
+#define ICH9_CC_SIZE                            (16 * 1024)     /* 16KB */
+
+#define TYPE_ICH9_LPC_DEVICE "ICH9 LPC"
+#define ICH9_LPC_DEVICE(obj) \
+     OBJECT_CHECK(ICH9LPCState, (obj), TYPE_ICH9_LPC_DEVICE)
+
+typedef struct ICH9LPCState {
+    /* ICH9 LPC PCI to ISA bridge */
+    PCIDevice d;
+
+    /* (pci device, intx) -> pirq
+     * In real chipset case, the unused slots are never used
+     * as ICH9 supports only D25-D32 irq routing.
+     * On the other hand in qemu case, any slot/function can be populated
+     * via command line option.
+     * So fallback interrupt routing for any devices in any slots is necessary.
+    */
+    uint8_t irr[PCI_SLOT_MAX][PCI_NUM_PINS];
+
+    APMState apm;
+    ICH9LPCPMRegs pm;
+    uint32_t sci_level; /* track sci level */
+
+    /* 10.1 Chipset Configuration registers(Memory Space)
+     which is pointed by RCBA */
+    uint8_t chip_config[ICH9_CC_SIZE];
+
+    /*
+     * 13.7.5 RST_CNT---Reset Control Register (LPC I/F---D31:F0)
+     *
+     * register contents and IO memory region
+     */
+    uint8_t rst_cnt;
+    MemoryRegion rst_cnt_mem;
+
+    /* isa bus */
+    ISABus *isa_bus;
+    MemoryRegion rbca_mem;
+    Notifier machine_ready;
+
+    qemu_irq *pic;
+    qemu_irq *ioapic;
+} ICH9LPCState;
+
+#define Q35_MASK(bit, ms_bit, ls_bit) \
+((uint##bit##_t)(((1ULL << ((ms_bit) + 1)) - 1) & ~((1ULL << ls_bit) - 1)))
+
+/* ICH9: Chipset Configuration Registers */
+#define ICH9_CC_ADDR_MASK                       (ICH9_CC_SIZE - 1)
+
+#define ICH9_CC
+#define ICH9_CC_D28IP                           0x310C
+#define ICH9_CC_D28IP_SHIFT                     4
+#define ICH9_CC_D28IP_MASK                      0xf
+#define ICH9_CC_D28IP_DEFAULT                   0x00214321
+#define ICH9_CC_D31IR                           0x3140
+#define ICH9_CC_D30IR                           0x3142
+#define ICH9_CC_D29IR                           0x3144
+#define ICH9_CC_D28IR                           0x3146
+#define ICH9_CC_D27IR                           0x3148
+#define ICH9_CC_D26IR                           0x314C
+#define ICH9_CC_D25IR                           0x3150
+#define ICH9_CC_DIR_DEFAULT                     0x3210
+#define ICH9_CC_D30IR_DEFAULT                   0x0
+#define ICH9_CC_DIR_SHIFT                       4
+#define ICH9_CC_DIR_MASK                        0x7
+#define ICH9_CC_OIC                             0x31FF
+#define ICH9_CC_OIC_AEN                         0x1
+
+/* D28:F[0-5] */
+#define ICH9_PCIE_DEV                           28
+#define ICH9_PCIE_FUNC_MAX                      6
+
+
+/* D29:F0 USB UHCI Controller #1 */
+#define ICH9_USB_UHCI1_DEV                      29
+#define ICH9_USB_UHCI1_FUNC                     0
+
+/* D30:F0 DMI-to-PCI brdige */
+#define ICH9_D2P_BRIDGE                         "ICH9 D2P BRIDGE"
+#define ICH9_D2P_BRIDGE_SAVEVM_VERSION          0
+
+#define ICH9_D2P_BRIDGE_DEV                     30
+#define ICH9_D2P_BRIDGE_FUNC                    0
+
+#define ICH9_D2P_SECONDARY_DEFAULT              (256 - 8)
+
+#define ICH9_D2P_A2_REVISION                    0x92
+
+/* D31:F0 LPC Processor Interface */
+#define ICH9_RST_CNT_IOPORT                     0xCF9
+
+/* D31:F1 LPC controller */
+#define ICH9_A2_LPC                             "ICH9 A2 LPC"
+#define ICH9_A2_LPC_SAVEVM_VERSION              0
+
+#define ICH9_LPC_DEV                            31
+#define ICH9_LPC_FUNC                           0
+
+#define ICH9_A2_LPC_REVISION                    0x2
+#define ICH9_LPC_NB_PIRQS                       8       /* PCI A-H */
+
+#define ICH9_LPC_PMBASE                         0x40
+#define ICH9_LPC_PMBASE_BASE_ADDRESS_MASK       Q35_MASK(32, 15, 7)
+#define ICH9_LPC_PMBASE_RTE                     0x1
+#define ICH9_LPC_PMBASE_DEFAULT                 0x1
+#define ICH9_LPC_ACPI_CTRL                      0x44
+#define ICH9_LPC_ACPI_CTRL_ACPI_EN              0x80
+#define ICH9_LPC_ACPI_CTRL_SCI_IRQ_SEL_MASK     Q35_MASK(8, 2, 0)
+#define ICH9_LPC_ACPI_CTRL_9                    0x0
+#define ICH9_LPC_ACPI_CTRL_10                   0x1
+#define ICH9_LPC_ACPI_CTRL_11                   0x2
+#define ICH9_LPC_ACPI_CTRL_20                   0x4
+#define ICH9_LPC_ACPI_CTRL_21                   0x5
+#define ICH9_LPC_ACPI_CTRL_DEFAULT              0x0
+
+#define ICH9_LPC_PIRQA_ROUT                     0x60
+#define ICH9_LPC_PIRQB_ROUT                     0x61
+#define ICH9_LPC_PIRQC_ROUT                     0x62
+#define ICH9_LPC_PIRQD_ROUT                     0x63
+
+#define ICH9_LPC_PIRQE_ROUT                     0x68
+#define ICH9_LPC_PIRQF_ROUT                     0x69
+#define ICH9_LPC_PIRQG_ROUT                     0x6a
+#define ICH9_LPC_PIRQH_ROUT                     0x6b
+
+#define ICH9_LPC_PIRQ_ROUT_IRQEN                0x80
+#define ICH9_LPC_PIRQ_ROUT_MASK                 Q35_MASK(8, 3, 0)
+#define ICH9_LPC_PIRQ_ROUT_DEFAULT              0x80
+
+#define ICH9_LPC_RCBA                           0xf0
+#define ICH9_LPC_RCBA_BA_MASK                   Q35_MASK(32, 31, 14)
+#define ICH9_LPC_RCBA_EN                        0x1
+#define ICH9_LPC_RCBA_DEFAULT                   0x0
+
+#define ICH9_LPC_PIC_NUM_PINS                   16
+#define ICH9_LPC_IOAPIC_NUM_PINS                24
+
+/* D31:F2 SATA Controller #1 */
+#define ICH9_SATA1_DEV                          31
+#define ICH9_SATA1_FUNC                         2
+
+/* D30:F1 power management I/O registers
+   offset from the address ICH9_LPC_PMBASE */
+
+/* ICH9 LPC PM I/O registers are 128 ports and 128-aligned */
+#define ICH9_PMIO_SIZE                          128
+#define ICH9_PMIO_MASK                          (ICH9_PMIO_SIZE - 1)
+
+#define ICH9_PMIO_PM1_STS                       0x00
+#define ICH9_PMIO_PM1_EN                        0x02
+#define ICH9_PMIO_PM1_CNT                       0x04
+#define ICH9_PMIO_PM1_TMR                       0x08
+#define ICH9_PMIO_GPE0_STS                      0x20
+#define ICH9_PMIO_GPE0_EN                       0x28
+#define ICH9_PMIO_GPE0_LEN                      16
+#define ICH9_PMIO_SMI_EN                        0x30
+#define ICH9_PMIO_SMI_EN_APMC_EN                (1 << 5)
+#define ICH9_PMIO_SMI_STS                       0x34
+
+/* FADT ACPI_ENABLE/ACPI_DISABLE */
+#define ICH9_APM_ACPI_ENABLE                    0x2
+#define ICH9_APM_ACPI_DISABLE                   0x3
+
+
+/* D31:F3 SMBus controller */
+#define ICH9_A2_SMB_REVISION                    0x02
+#define ICH9_SMB_PI                             0x00
+
+#define ICH9_SMB_SMBMBAR0                       0x10
+#define ICH9_SMB_SMBMBAR1                       0x14
+#define ICH9_SMB_SMBM_BAR                       0
+#define ICH9_SMB_SMBM_SIZE                      (1 << 8)
+#define ICH9_SMB_SMB_BASE                       0x20
+#define ICH9_SMB_SMB_BASE_BAR                   4
+#define ICH9_SMB_SMB_BASE_SIZE                  (1 << 5)
+#define ICH9_SMB_HOSTC                          0x40
+#define ICH9_SMB_HOSTC_SSRESET                  ((uint8_t)(1 << 3))
+#define ICH9_SMB_HOSTC_I2C_EN                   ((uint8_t)(1 << 2))
+#define ICH9_SMB_HOSTC_SMB_SMI_EN               ((uint8_t)(1 << 1))
+#define ICH9_SMB_HOSTC_HST_EN                   ((uint8_t)(1 << 0))
+
+/* D31:F3 SMBus I/O and memory mapped I/O registers */
+#define ICH9_SMB_DEV                            31
+#define ICH9_SMB_FUNC                           3
+
+#define ICH9_SMB_HST_STS                        0x00
+#define ICH9_SMB_HST_CNT                        0x02
+#define ICH9_SMB_HST_CMD                        0x03
+#define ICH9_SMB_XMIT_SLVA                      0x04
+#define ICH9_SMB_HST_D0                         0x05
+#define ICH9_SMB_HST_D1                         0x06
+#define ICH9_SMB_HOST_BLOCK_DB                  0x07
+
+#endif /* HW_ICH9_H */
diff --git a/include/hw/i386/ioapic.h b/include/hw/i386/ioapic.h
new file mode 100644 (file)
index 0000000..86e63da
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ *  ioapic.c IOAPIC emulation logic
+ *
+ *  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 HW_IOAPIC_H
+#define HW_IOAPIC_H
+
+#define IOAPIC_NUM_PINS 24
+
+void ioapic_eoi_broadcast(int vector);
+
+#endif /* !HW_IOAPIC_H */
diff --git a/include/hw/i386/ioapic_internal.h b/include/hw/i386/ioapic_internal.h
new file mode 100644 (file)
index 0000000..25576c8
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ *  IOAPIC emulation logic - internal interfaces
+ *
+ *  Copyright (c) 2004-2005 Fabrice Bellard
+ *  Copyright (c) 2009      Xiantao Zhang, Intel
+ *  Copyright (c) 2011 Jan Kiszka, Siemens AG
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef QEMU_IOAPIC_INTERNAL_H
+#define QEMU_IOAPIC_INTERNAL_H
+
+#include "hw/hw.h"
+#include "exec/memory.h"
+#include "hw/sysbus.h"
+
+#define MAX_IOAPICS                     1
+
+#define IOAPIC_VERSION                  0x11
+
+#define IOAPIC_LVT_DEST_SHIFT           56
+#define IOAPIC_LVT_MASKED_SHIFT         16
+#define IOAPIC_LVT_TRIGGER_MODE_SHIFT   15
+#define IOAPIC_LVT_REMOTE_IRR_SHIFT     14
+#define IOAPIC_LVT_POLARITY_SHIFT       13
+#define IOAPIC_LVT_DELIV_STATUS_SHIFT   12
+#define IOAPIC_LVT_DEST_MODE_SHIFT      11
+#define IOAPIC_LVT_DELIV_MODE_SHIFT     8
+
+#define IOAPIC_LVT_MASKED               (1 << IOAPIC_LVT_MASKED_SHIFT)
+#define IOAPIC_LVT_REMOTE_IRR           (1 << IOAPIC_LVT_REMOTE_IRR_SHIFT)
+
+#define IOAPIC_TRIGGER_EDGE             0
+#define IOAPIC_TRIGGER_LEVEL            1
+
+/*io{apic,sapic} delivery mode*/
+#define IOAPIC_DM_FIXED                 0x0
+#define IOAPIC_DM_LOWEST_PRIORITY       0x1
+#define IOAPIC_DM_PMI                   0x2
+#define IOAPIC_DM_NMI                   0x4
+#define IOAPIC_DM_INIT                  0x5
+#define IOAPIC_DM_SIPI                  0x6
+#define IOAPIC_DM_EXTINT                0x7
+#define IOAPIC_DM_MASK                  0x7
+
+#define IOAPIC_VECTOR_MASK              0xff
+
+#define IOAPIC_IOREGSEL                 0x00
+#define IOAPIC_IOWIN                    0x10
+
+#define IOAPIC_REG_ID                   0x00
+#define IOAPIC_REG_VER                  0x01
+#define IOAPIC_REG_ARB                  0x02
+#define IOAPIC_REG_REDTBL_BASE          0x10
+#define IOAPIC_ID                       0x00
+
+#define IOAPIC_ID_SHIFT                 24
+#define IOAPIC_ID_MASK                  0xf
+
+#define IOAPIC_VER_ENTRIES_SHIFT        16
+
+typedef struct IOAPICCommonState IOAPICCommonState;
+
+#define TYPE_IOAPIC_COMMON "ioapic-common"
+#define IOAPIC_COMMON(obj) \
+     OBJECT_CHECK(IOAPICCommonState, (obj), TYPE_IOAPIC_COMMON)
+#define IOAPIC_COMMON_CLASS(klass) \
+     OBJECT_CLASS_CHECK(IOAPICCommonClass, (klass), TYPE_IOAPIC_COMMON)
+#define IOAPIC_COMMON_GET_CLASS(obj) \
+     OBJECT_GET_CLASS(IOAPICCommonClass, (obj), TYPE_IOAPIC_COMMON)
+
+typedef struct IOAPICCommonClass {
+    SysBusDeviceClass parent_class;
+    void (*init)(IOAPICCommonState *s, int instance_no);
+    void (*pre_save)(IOAPICCommonState *s);
+    void (*post_load)(IOAPICCommonState *s);
+} IOAPICCommonClass;
+
+struct IOAPICCommonState {
+    SysBusDevice busdev;
+    MemoryRegion io_memory;
+    uint8_t id;
+    uint8_t ioregsel;
+    uint32_t irr;
+    uint64_t ioredtbl[IOAPIC_NUM_PINS];
+};
+
+void ioapic_reset_common(DeviceState *dev);
+
+#endif /* !QEMU_IOAPIC_INTERNAL_H */
diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
new file mode 100644 (file)
index 0000000..5d40914
--- /dev/null
@@ -0,0 +1,246 @@
+#ifndef HW_PC_H
+#define HW_PC_H
+
+#include "qemu-common.h"
+#include "exec/memory.h"
+#include "exec/ioport.h"
+#include "hw/isa/isa.h"
+#include "hw/block/fdc.h"
+#include "net/net.h"
+#include "exec/memory.h"
+#include "hw/i386/ioapic.h"
+
+/* PC-style peripherals (also used by other machines).  */
+
+/* parallel.c */
+static inline bool parallel_init(ISABus *bus, int index, CharDriverState *chr)
+{
+    ISADevice *dev;
+
+    dev = isa_try_create(bus, "isa-parallel");
+    if (!dev) {
+        return false;
+    }
+    qdev_prop_set_uint32(&dev->qdev, "index", index);
+    qdev_prop_set_chr(&dev->qdev, "chardev", chr);
+    if (qdev_init(&dev->qdev) < 0) {
+        return false;
+    }
+    return true;
+}
+
+bool parallel_mm_init(MemoryRegion *address_space,
+                      hwaddr base, int it_shift, qemu_irq irq,
+                      CharDriverState *chr);
+
+/* i8259.c */
+
+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, const QDict *qdict);
+void irq_info(Monitor *mon, const QDict *qdict);
+
+/* Global System Interrupts */
+
+#define GSI_NUM_PINS IOAPIC_NUM_PINS
+
+typedef struct GSIState {
+    qemu_irq i8259_irq[ISA_NUM_IRQS];
+    qemu_irq ioapic_irq[IOAPIC_NUM_PINS];
+} GSIState;
+
+void gsi_handler(void *opaque, int n, int level);
+
+/* vmport.c */
+static inline void vmport_init(ISABus *bus)
+{
+    isa_create_simple(bus, "vmport");
+}
+void vmport_register(unsigned char command, IOPortReadFunc *func, void *opaque);
+void vmmouse_get_data(uint32_t *data);
+void vmmouse_set_data(const uint32_t *data);
+
+/* pckbd.c */
+
+void i8042_init(qemu_irq kbd_irq, qemu_irq mouse_irq, uint32_t io_base);
+void i8042_mm_init(qemu_irq kbd_irq, qemu_irq mouse_irq,
+                   MemoryRegion *region, ram_addr_t size,
+                   hwaddr mask);
+void i8042_isa_mouse_fake_event(void *opaque);
+void i8042_setup_a20_line(ISADevice *dev, qemu_irq *a20_out);
+
+/* pc.c */
+extern int fd_bootchk;
+
+void pc_register_ferr_irq(qemu_irq irq);
+void pc_acpi_smi_interrupt(void *opaque, int irq, int level);
+
+void pc_cpus_init(const char *cpu_model);
+void pc_acpi_init(const char *default_dsdt);
+void *pc_memory_init(MemoryRegion *system_memory,
+                    const char *kernel_filename,
+                    const char *kernel_cmdline,
+                    const char *initrd_filename,
+                    ram_addr_t below_4g_mem_size,
+                    ram_addr_t above_4g_mem_size,
+                    MemoryRegion *rom_memory,
+                    MemoryRegion **ram_memory);
+qemu_irq *pc_allocate_cpu_irq(void);
+DeviceState *pc_vga_init(ISABus *isa_bus, PCIBus *pci_bus);
+void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi,
+                          ISADevice **rtc_state,
+                          ISADevice **floppy,
+                          bool no_vmport);
+void pc_init_ne2k_isa(ISABus *bus, NICInfo *nd);
+void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size,
+                  const char *boot_device,
+                  ISADevice *floppy, BusState *ide0, BusState *ide1,
+                  ISADevice *s);
+void pc_nic_init(ISABus *isa_bus, PCIBus *pci_bus);
+void pc_pci_device_init(PCIBus *pci_bus);
+
+typedef void (*cpu_set_smm_t)(int smm, void *arg);
+void cpu_smm_register(cpu_set_smm_t callback, void *arg);
+
+void ioapic_init_gsi(GSIState *gsi_state, const char *parent_name);
+
+/* acpi.c */
+extern int acpi_enabled;
+extern char unsigned *acpi_tables;
+extern size_t acpi_tables_len;
+
+void acpi_bios_init(void);
+void acpi_table_add(const QemuOpts *opts, Error **errp);
+
+/* acpi_piix.c */
+
+i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
+                       qemu_irq sci_irq, qemu_irq smi_irq,
+                       int kvm_enabled, void *fw_cfg);
+void piix4_smbus_register_device(SMBusDevice *dev, uint8_t addr);
+
+/* hpet.c */
+extern int no_hpet;
+
+/* piix_pci.c */
+struct PCII440FXState;
+typedef struct PCII440FXState PCII440FXState;
+
+PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix_devfn,
+                    ISABus **isa_bus, qemu_irq *pic,
+                    MemoryRegion *address_space_mem,
+                    MemoryRegion *address_space_io,
+                    ram_addr_t ram_size,
+                    hwaddr pci_hole_start,
+                    hwaddr pci_hole_size,
+                    hwaddr pci_hole64_start,
+                    hwaddr pci_hole64_size,
+                    MemoryRegion *pci_memory,
+                    MemoryRegion *ram_memory);
+
+/* piix4.c */
+extern PCIDevice *piix4_dev;
+int piix4_init(PCIBus *bus, ISABus **isa_bus, int devfn);
+
+/* vga.c */
+enum vga_retrace_method {
+    VGA_RETRACE_DUMB,
+    VGA_RETRACE_PRECISE
+};
+
+extern enum vga_retrace_method vga_retrace_method;
+
+int isa_vga_mm_init(hwaddr vram_base,
+                    hwaddr ctrl_base, int it_shift,
+                    MemoryRegion *address_space);
+
+/* ne2000.c */
+static inline bool isa_ne2000_init(ISABus *bus, int base, int irq, NICInfo *nd)
+{
+    ISADevice *dev;
+
+    qemu_check_nic_model(nd, "ne2k_isa");
+
+    dev = isa_try_create(bus, "ne2k_isa");
+    if (!dev) {
+        return false;
+    }
+    qdev_prop_set_uint32(&dev->qdev, "iobase", base);
+    qdev_prop_set_uint32(&dev->qdev, "irq",    irq);
+    qdev_set_nic_properties(&dev->qdev, nd);
+    qdev_init_nofail(&dev->qdev);
+    return true;
+}
+
+/* pc_sysfw.c */
+void pc_system_firmware_init(MemoryRegion *rom_memory);
+
+/* e820 types */
+#define E820_RAM        1
+#define E820_RESERVED   2
+#define E820_ACPI       3
+#define E820_NVS        4
+#define E820_UNUSABLE   5
+
+int e820_add_entry(uint64_t, uint64_t, uint32_t);
+
+#define PC_COMPAT_1_4 \
+        {\
+            .driver   = "scsi-hd",\
+            .property = "discard_granularity",\
+            .value    = stringify(0),\
+       },{\
+            .driver   = "scsi-cd",\
+            .property = "discard_granularity",\
+            .value    = stringify(0),\
+       },{\
+            .driver   = "scsi-disk",\
+            .property = "discard_granularity",\
+            .value    = stringify(0),\
+       },{\
+            .driver   = "ide-hd",\
+            .property = "discard_granularity",\
+            .value    = stringify(0),\
+       },{\
+            .driver   = "ide-cd",\
+            .property = "discard_granularity",\
+            .value    = stringify(0),\
+       },{\
+            .driver   = "ide-drive",\
+            .property = "discard_granularity",\
+            .value    = stringify(0),\
+        },{\
+            .driver   = "virtio-blk-pci",\
+            .property = "discard_granularity",\
+            .value    = stringify(0),\
+       },{\
+            .driver   = "virtio-serial-pci",\
+            .property = "vectors",\
+            /* DEV_NVECTORS_UNSPECIFIED as a uint32_t string */\
+            .value    = stringify(0xFFFFFFFF),\
+        },{\
+            .driver   = "e1000",\
+            .property = "romfile",\
+            .value    = "pxe-e1000.rom",\
+        },{\
+            .driver   = "ne2k_pci",\
+            .property = "romfile",\
+            .value    = "pxe-ne2k_pci.rom",\
+        },{\
+            .driver   = "pcnet",\
+            .property = "romfile",\
+            .value    = "pxe-pcnet.rom",\
+        },{\
+            .driver   = "rtl8139",\
+            .property = "romfile",\
+            .value    = "pxe-rtl8139.rom",\
+        },{\
+            .driver   = "virtio-net-pci",\
+            .property = "romfile",\
+            .value    = "pxe-virtio.rom",\
+        }
+
+#endif
diff --git a/include/hw/i386/smbios.h b/include/hw/i386/smbios.h
new file mode 100644 (file)
index 0000000..94e3641
--- /dev/null
@@ -0,0 +1,162 @@
+#ifndef QEMU_SMBIOS_H
+#define QEMU_SMBIOS_H
+/*
+ * SMBIOS Support
+ *
+ * Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
+ *
+ * Authors:
+ *  Alex Williamson <alex.williamson@hp.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+int smbios_entry_add(const char *t);
+void smbios_add_field(int type, int offset, int len, void *data);
+uint8_t *smbios_get_table(size_t *length);
+
+/*
+ * SMBIOS spec defined tables
+ */
+
+/* This goes at the beginning of every SMBIOS structure. */
+struct smbios_structure_header {
+    uint8_t type;
+    uint8_t length;
+    uint16_t handle;
+} QEMU_PACKED;
+
+/* SMBIOS type 0 - BIOS Information */
+struct smbios_type_0 {
+    struct smbios_structure_header header;
+    uint8_t vendor_str;
+    uint8_t bios_version_str;
+    uint16_t bios_starting_address_segment;
+    uint8_t bios_release_date_str;
+    uint8_t bios_rom_size;
+    uint8_t bios_characteristics[8];
+    uint8_t bios_characteristics_extension_bytes[2];
+    uint8_t system_bios_major_release;
+    uint8_t system_bios_minor_release;
+    uint8_t embedded_controller_major_release;
+    uint8_t embedded_controller_minor_release;
+} QEMU_PACKED;
+
+/* SMBIOS type 1 - System Information */
+struct smbios_type_1 {
+    struct smbios_structure_header header;
+    uint8_t manufacturer_str;
+    uint8_t product_name_str;
+    uint8_t version_str;
+    uint8_t serial_number_str;
+    uint8_t uuid[16];
+    uint8_t wake_up_type;
+    uint8_t sku_number_str;
+    uint8_t family_str;
+} QEMU_PACKED;
+
+/* SMBIOS type 3 - System Enclosure (v2.3) */
+struct smbios_type_3 {
+    struct smbios_structure_header header;
+    uint8_t manufacturer_str;
+    uint8_t type;
+    uint8_t version_str;
+    uint8_t serial_number_str;
+    uint8_t asset_tag_number_str;
+    uint8_t boot_up_state;
+    uint8_t power_supply_state;
+    uint8_t thermal_state;
+    uint8_t security_status;
+    uint32_t oem_defined;
+    uint8_t height;
+    uint8_t number_of_power_cords;
+    uint8_t contained_element_count;
+    // contained elements follow
+} QEMU_PACKED;
+
+/* SMBIOS type 4 - Processor Information (v2.0) */
+struct smbios_type_4 {
+    struct smbios_structure_header header;
+    uint8_t socket_designation_str;
+    uint8_t processor_type;
+    uint8_t processor_family;
+    uint8_t processor_manufacturer_str;
+    uint32_t processor_id[2];
+    uint8_t processor_version_str;
+    uint8_t voltage;
+    uint16_t external_clock;
+    uint16_t max_speed;
+    uint16_t current_speed;
+    uint8_t status;
+    uint8_t processor_upgrade;
+    uint16_t l1_cache_handle;
+    uint16_t l2_cache_handle;
+    uint16_t l3_cache_handle;
+} QEMU_PACKED;
+
+/* SMBIOS type 16 - Physical Memory Array
+ *   Associated with one type 17 (Memory Device).
+ */
+struct smbios_type_16 {
+    struct smbios_structure_header header;
+    uint8_t location;
+    uint8_t use;
+    uint8_t error_correction;
+    uint32_t maximum_capacity;
+    uint16_t memory_error_information_handle;
+    uint16_t number_of_memory_devices;
+} QEMU_PACKED;
+/* SMBIOS type 17 - Memory Device
+ *   Associated with one type 19
+ */
+struct smbios_type_17 {
+    struct smbios_structure_header header;
+    uint16_t physical_memory_array_handle;
+    uint16_t memory_error_information_handle;
+    uint16_t total_width;
+    uint16_t data_width;
+    uint16_t size;
+    uint8_t form_factor;
+    uint8_t device_set;
+    uint8_t device_locator_str;
+    uint8_t bank_locator_str;
+    uint8_t memory_type;
+    uint16_t type_detail;
+} QEMU_PACKED;
+
+/* SMBIOS type 19 - Memory Array Mapped Address */
+struct smbios_type_19 {
+    struct smbios_structure_header header;
+    uint32_t starting_address;
+    uint32_t ending_address;
+    uint16_t memory_array_handle;
+    uint8_t partition_width;
+} QEMU_PACKED;
+
+/* SMBIOS type 20 - Memory Device Mapped Address */
+struct smbios_type_20 {
+    struct smbios_structure_header header;
+    uint32_t starting_address;
+    uint32_t ending_address;
+    uint16_t memory_device_handle;
+    uint16_t memory_array_mapped_address_handle;
+    uint8_t partition_row_position;
+    uint8_t interleave_position;
+    uint8_t interleaved_data_depth;
+} QEMU_PACKED;
+
+/* SMBIOS type 32 - System Boot Information */
+struct smbios_type_32 {
+    struct smbios_structure_header header;
+    uint8_t reserved[6];
+    uint8_t boot_status;
+} QEMU_PACKED;
+
+/* SMBIOS type 127 -- End-of-table */
+struct smbios_type_127 {
+    struct smbios_structure_header header;
+} QEMU_PACKED;
+
+#endif /*QEMU_SMBIOS_H */
diff --git a/include/hw/ide.h b/include/hw/ide.h
new file mode 100644 (file)
index 0000000..507e6d3
--- /dev/null
@@ -0,0 +1,32 @@
+#ifndef HW_IDE_H
+#define HW_IDE_H
+
+#include "hw/isa/isa.h"
+#include "hw/pci/pci.h"
+#include "exec/memory.h"
+
+#define MAX_IDE_DEVS   2
+
+/* ide-isa.c */
+ISADevice *isa_ide_init(ISABus *bus, int iobase, int iobase2, int isairq,
+                        DriveInfo *hd0, DriveInfo *hd1);
+
+/* ide-pci.c */
+void pci_cmd646_ide_init(PCIBus *bus, DriveInfo **hd_table,
+                         int secondary_ide_enabled);
+PCIDevice *pci_piix3_xen_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn);
+PCIDevice *pci_piix3_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn);
+PCIDevice *pci_piix4_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn);
+void vt82c686b_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn);
+
+/* ide-mmio.c */
+void mmio_ide_init_drives(DeviceState *dev, DriveInfo *hd0, DriveInfo *hd1);
+
+int ide_get_geometry(BusState *bus, int unit,
+                     int16_t *cyls, int8_t *heads, int8_t *secs);
+int ide_get_bios_chs_trans(BusState *bus, int unit);
+
+/* ide/core.c */
+void ide_drive_get(DriveInfo **hd, int max_bus);
+
+#endif /* HW_IDE_H */
diff --git a/include/hw/input/adb.h b/include/hw/input/adb.h
new file mode 100644 (file)
index 0000000..bdfccd4
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * QEMU ADB emulation shared definitions and prototypes
+ *
+ * Copyright (c) 2004-2007 Fabrice Bellard
+ * Copyright (c) 2007 Jocelyn Mayer
+ *
+ * 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 !defined(__ADB_H__)
+#define __ADB_H__
+
+#include "hw/qdev.h"
+
+#define MAX_ADB_DEVICES 16
+
+#define ADB_MAX_OUT_LEN 16
+
+typedef struct ADBBusState ADBBusState;
+typedef struct ADBDevice ADBDevice;
+
+/* buf = NULL means polling */
+typedef int ADBDeviceRequest(ADBDevice *d, uint8_t *buf_out,
+                              const uint8_t *buf, int len);
+
+#define TYPE_ADB_DEVICE "adb-device"
+#define ADB_DEVICE(obj) OBJECT_CHECK(ADBDevice, (obj), TYPE_ADB_DEVICE)
+
+struct ADBDevice {
+    /*< private >*/
+    DeviceState parent_obj;
+    /*< public >*/
+
+    int devaddr;
+    int handler;
+};
+
+#define ADB_DEVICE_CLASS(cls) \
+    OBJECT_CLASS_CHECK(ADBDeviceClass, (cls), TYPE_ADB_DEVICE)
+#define ADB_DEVICE_GET_CLASS(obj) \
+    OBJECT_GET_CLASS(ADBDeviceClass, (obj), TYPE_ADB_DEVICE)
+
+typedef struct ADBDeviceClass {
+    /*< private >*/
+    DeviceClass parent_class;
+    /*< public >*/
+
+    ADBDeviceRequest *devreq;
+} ADBDeviceClass;
+
+#define TYPE_ADB_BUS "apple-desktop-bus"
+#define ADB_BUS(obj) OBJECT_CHECK(ADBBusState, (obj), TYPE_ADB_BUS)
+
+struct ADBBusState {
+    /*< private >*/
+    BusState parent_obj;
+    /*< public >*/
+
+    ADBDevice *devices[MAX_ADB_DEVICES];
+    int nb_devices;
+    int poll_index;
+};
+
+int adb_request(ADBBusState *s, uint8_t *buf_out,
+                const uint8_t *buf, int len);
+int adb_poll(ADBBusState *s, uint8_t *buf_out);
+
+#define TYPE_ADB_KEYBOARD "adb-keyboard"
+#define TYPE_ADB_MOUSE "adb-mouse"
+
+#endif /* !defined(__ADB_H__) */
diff --git a/include/hw/input/hid.h b/include/hw/input/hid.h
new file mode 100644 (file)
index 0000000..56c71ed
--- /dev/null
@@ -0,0 +1,83 @@
+#ifndef QEMU_HID_H
+#define QEMU_HID_H
+
+#include "migration/vmstate.h"
+
+#define HID_MOUSE     1
+#define HID_TABLET    2
+#define HID_KEYBOARD  3
+
+typedef struct HIDPointerEvent {
+    int32_t xdx, ydy; /* relative iff it's a mouse, otherwise absolute */
+    int32_t dz, buttons_state;
+} HIDPointerEvent;
+
+#define QUEUE_LENGTH    16 /* should be enough for a triple-click */
+#define QUEUE_MASK      (QUEUE_LENGTH-1u)
+#define QUEUE_INCR(v)   ((v)++, (v) &= QUEUE_MASK)
+
+typedef struct HIDState HIDState;
+typedef void (*HIDEventFunc)(HIDState *s);
+
+typedef struct HIDMouseState {
+    HIDPointerEvent queue[QUEUE_LENGTH];
+    int mouse_grabbed;
+    QEMUPutMouseEntry *eh_entry;
+} HIDMouseState;
+
+typedef struct HIDKeyboardState {
+    uint32_t keycodes[QUEUE_LENGTH];
+    uint16_t modifiers;
+    uint8_t leds;
+    uint8_t key[16];
+    int32_t keys;
+} HIDKeyboardState;
+
+struct HIDState {
+    union {
+        HIDMouseState ptr;
+        HIDKeyboardState kbd;
+    };
+    uint32_t head; /* index into circular queue */
+    uint32_t n;
+    int kind;
+    int32_t protocol;
+    uint8_t idle;
+    bool idle_pending;
+    QEMUTimer *idle_timer;
+    HIDEventFunc event;
+};
+
+void hid_init(HIDState *hs, int kind, HIDEventFunc event);
+void hid_reset(HIDState *hs);
+void hid_free(HIDState *hs);
+
+bool hid_has_events(HIDState *hs);
+void hid_set_next_idle(HIDState *hs);
+void hid_pointer_activate(HIDState *hs);
+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/include/hw/input/ps2.h b/include/hw/input/ps2.h
new file mode 100644 (file)
index 0000000..7c45ce7
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * QEMU PS/2 keyboard/mouse emulation
+ *
+ * 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.
+ */
+
+#ifndef HW_PS2_H
+#define HW_PS2_H
+
+/* ps2.c */
+void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg);
+void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg);
+void ps2_write_mouse(void *, int val);
+void ps2_write_keyboard(void *, int val);
+uint32_t ps2_read_data(void *);
+void ps2_queue(void *, int b);
+void ps2_keyboard_set_translation(void *opaque, int mode);
+void ps2_mouse_fake_event(void *opaque);
+
+#endif /* !HW_PS2_H */
diff --git a/include/hw/irq.h b/include/hw/irq.h
new file mode 100644 (file)
index 0000000..610e6b7
--- /dev/null
@@ -0,0 +1,57 @@
+#ifndef QEMU_IRQ_H
+#define QEMU_IRQ_H
+
+/* Generic IRQ/GPIO pin infrastructure.  */
+
+typedef struct IRQState *qemu_irq;
+
+typedef void (*qemu_irq_handler)(void *opaque, int n, int level);
+
+void qemu_set_irq(qemu_irq irq, int level);
+
+static inline void qemu_irq_raise(qemu_irq irq)
+{
+    qemu_set_irq(irq, 1);
+}
+
+static inline void qemu_irq_lower(qemu_irq irq)
+{
+    qemu_set_irq(irq, 0);
+}
+
+static inline void qemu_irq_pulse(qemu_irq irq)
+{
+    qemu_set_irq(irq, 1);
+    qemu_set_irq(irq, 0);
+}
+
+/* Returns an array of N IRQs. Each IRQ is assigned the argument handler and
+ * opaque data.
+ */
+qemu_irq *qemu_allocate_irqs(qemu_irq_handler handler, void *opaque, int n);
+
+/* Extends an Array of IRQs. Old IRQs have their handlers and opaque data
+ * preserved. New IRQs are assigned the argument handler and opaque data.
+ */
+qemu_irq *qemu_extend_irqs(qemu_irq *old, int n_old, qemu_irq_handler handler,
+                                void *opaque, int n);
+
+void qemu_free_irqs(qemu_irq *s);
+
+/* Returns a new IRQ with opposite polarity.  */
+qemu_irq qemu_irq_invert(qemu_irq irq);
+
+/* Returns a new IRQ which feeds into both the passed IRQs */
+qemu_irq qemu_irq_split(qemu_irq irq1, qemu_irq irq2);
+
+/* Returns a new IRQ set which connects 1:1 to another IRQ set, which
+ * may be set later.
+ */
+qemu_irq *qemu_irq_proxy(qemu_irq **target, int n);
+
+/* For internal use in qtest.  Similar to qemu_irq_split, but operating
+   on an existing vector of qemu_irq.  */
+void qemu_irq_intercept_in(qemu_irq *gpio_in, qemu_irq_handler handler, int n);
+void qemu_irq_intercept_out(qemu_irq **gpio_out, qemu_irq_handler handler, int n);
+
+#endif
diff --git a/include/hw/isa/apm.h b/include/hw/isa/apm.h
new file mode 100644 (file)
index 0000000..3edea5f
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef APM_H
+#define APM_H
+
+#include <stdint.h>
+#include "qemu-common.h"
+#include "hw/hw.h"
+#include "exec/memory.h"
+
+typedef void (*apm_ctrl_changed_t)(uint32_t val, void *arg);
+
+typedef struct APMState {
+    uint8_t apmc;
+    uint8_t apms;
+
+    apm_ctrl_changed_t callback;
+    void *arg;
+    MemoryRegion io;
+} APMState;
+
+void apm_init(PCIDevice *dev, APMState *s, apm_ctrl_changed_t callback,
+              void *arg);
+
+extern const VMStateDescription vmstate_apm;
+
+#endif /* APM_H */
diff --git a/include/hw/isa/i8259_internal.h b/include/hw/isa/i8259_internal.h
new file mode 100644 (file)
index 0000000..d3ddb27
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * QEMU 8259 - internal interfaces
+ *
+ * Copyright (c) 2011 Jan Kiszka, Siemens AG
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef QEMU_I8259_INTERNAL_H
+#define QEMU_I8259_INTERNAL_H
+
+#include "hw/hw.h"
+#include "hw/i386/pc.h"
+#include "hw/isa/isa.h"
+
+typedef struct PICCommonState PICCommonState;
+
+#define TYPE_PIC_COMMON "pic-common"
+#define PIC_COMMON(obj) \
+     OBJECT_CHECK(PICCommonState, (obj), TYPE_PIC_COMMON)
+#define PIC_COMMON_CLASS(klass) \
+     OBJECT_CLASS_CHECK(PICCommonClass, (klass), TYPE_PIC_COMMON)
+#define PIC_COMMON_GET_CLASS(obj) \
+     OBJECT_GET_CLASS(PICCommonClass, (obj), TYPE_PIC_COMMON)
+
+typedef struct PICCommonClass
+{
+    ISADeviceClass parent_class;
+    void (*init)(PICCommonState *s);
+    void (*pre_save)(PICCommonState *s);
+    void (*post_load)(PICCommonState *s);
+} PICCommonClass;
+
+struct PICCommonState {
+    ISADevice dev;
+    uint8_t last_irr; /* edge detection */
+    uint8_t irr; /* interrupt request register */
+    uint8_t imr; /* interrupt mask register */
+    uint8_t isr; /* interrupt service register */
+    uint8_t priority_add; /* highest irq priority */
+    uint8_t irq_base;
+    uint8_t read_reg_select;
+    uint8_t poll;
+    uint8_t special_mask;
+    uint8_t init_state;
+    uint8_t auto_eoi;
+    uint8_t rotate_on_auto_eoi;
+    uint8_t special_fully_nested_mode;
+    uint8_t init4; /* true if 4 byte init */
+    uint8_t single_mode; /* true if slave pic is not initialized */
+    uint8_t elcr; /* PIIX edge/trigger selection*/
+    uint8_t elcr_mask;
+    qemu_irq int_out[1];
+    uint32_t master; /* reflects /SP input pin */
+    uint32_t iobase;
+    uint32_t elcr_addr;
+    MemoryRegion base_io;
+    MemoryRegion elcr_io;
+};
+
+void pic_reset_common(PICCommonState *s);
+
+ISADevice *i8259_init_chip(const char *name, ISABus *bus, bool master);
+
+
+#endif /* !QEMU_I8259_INTERNAL_H */
diff --git a/include/hw/isa/isa.h b/include/hw/isa/isa.h
new file mode 100644 (file)
index 0000000..82da37c
--- /dev/null
@@ -0,0 +1,104 @@
+#ifndef HW_ISA_H
+#define HW_ISA_H
+
+/* ISA bus */
+
+#include "exec/ioport.h"
+#include "exec/memory.h"
+#include "hw/qdev.h"
+
+#define ISA_NUM_IRQS 16
+
+#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)
+
+#define TYPE_ISA_BUS "ISA"
+#define ISA_BUS(obj) OBJECT_CHECK(ISABus, (obj), TYPE_ISA_BUS)
+
+typedef struct ISADeviceClass {
+    DeviceClass parent_class;
+    int (*init)(ISADevice *dev);
+} ISADeviceClass;
+
+struct ISABus {
+    BusState qbus;
+    MemoryRegion *address_space_io;
+    qemu_irq *irqs;
+};
+
+struct ISADevice {
+    DeviceState qdev;
+    uint32_t isairq[2];
+    int nirqs;
+    int ioport_id;
+};
+
+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);
+MemoryRegion *isa_address_space(ISADevice *dev);
+MemoryRegion *isa_address_space_io(ISADevice *dev);
+ISADevice *isa_create(ISABus *bus, const char *name);
+ISADevice *isa_try_create(ISABus *bus, const char *name);
+ISADevice *isa_create_simple(ISABus *bus, const char *name);
+
+ISADevice *isa_vga_init(ISABus *bus);
+
+/**
+ * isa_register_ioport: Install an I/O port region on the ISA bus.
+ *
+ * Register an I/O port region via memory_region_add_subregion
+ * inside the ISA I/O address space.
+ *
+ * @dev: the ISADevice against which these are registered; may be NULL.
+ * @io: the #MemoryRegion being registered.
+ * @start: the base I/O port.
+ */
+void isa_register_ioport(ISADevice *dev, MemoryRegion *io, uint16_t start);
+
+/**
+ * isa_register_portio_list: Initialize a set of ISA io ports
+ *
+ * Several ISA devices have many dis-joint I/O ports.  Worse, these I/O
+ * ports can be interleaved with I/O ports from other devices.  This
+ * function makes it easy to create multiple MemoryRegions for a single
+ * device and use the legacy portio routines.
+ *
+ * @dev: the ISADevice against which these are registered; may be NULL.
+ * @start: the base I/O port against which the portio->offset is applied.
+ * @portio: the ports, sorted by offset.
+ * @opaque: passed into the old_portio callbacks.
+ * @name: passed into memory_region_init_io.
+ */
+void isa_register_portio_list(ISADevice *dev, uint16_t start,
+                              const MemoryRegionPortio *portio,
+                              void *opaque, const char *name);
+
+static inline ISABus *isa_bus_from_device(ISADevice *d)
+{
+    return ISA_BUS(qdev_get_parent_bus(DEVICE(d)));
+}
+
+extern hwaddr isa_mem_base;
+
+void isa_mmio_setup(MemoryRegion *mr, hwaddr size);
+void isa_mmio_init(hwaddr base, hwaddr size);
+
+/* dma.c */
+int DMA_get_channel_mode (int nchan);
+int DMA_read_memory (int nchan, void *buf, int pos, int size);
+int DMA_write_memory (int nchan, void *buf, int pos, int size);
+void DMA_hold_DREQ (int nchan);
+void DMA_release_DREQ (int nchan);
+void DMA_schedule(int nchan);
+void DMA_init(int high_page_enable, qemu_irq *cpu_request_exit);
+void DMA_register_channel (int nchan,
+                           DMA_transfer_handler transfer_handler,
+                           void *opaque);
+#endif
diff --git a/include/hw/isa/pc87312.h b/include/hw/isa/pc87312.h
new file mode 100644 (file)
index 0000000..befc8bd
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * QEMU National Semiconductor PC87312 (Super I/O)
+ *
+ * Copyright (c) 2010-2012 Herve Poussineau
+ * Copyright (c) 2011-2012 Andreas Färber
+ *
+ * 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_PC87312_H
+#define QEMU_PC87312_H
+
+#include "hw/isa/isa.h"
+
+
+#define TYPE_PC87312 "pc87312"
+#define PC87312(obj) OBJECT_CHECK(PC87312State, (obj), TYPE_PC87312)
+
+typedef struct PC87312State {
+    ISADevice dev;
+
+    uint32_t iobase;
+    uint8_t config; /* initial configuration */
+
+    struct {
+        ISADevice *dev;
+    } parallel;
+
+    struct {
+        ISADevice *dev;
+    } uart[2];
+
+    struct {
+        ISADevice *dev;
+        BlockDriverState *drive[2];
+        uint32_t base;
+    } fdc;
+
+    struct {
+        ISADevice *dev;
+        uint32_t base;
+    } ide;
+
+    MemoryRegion io;
+
+    uint8_t read_id_step;
+    uint8_t selected_index;
+
+    uint8_t regs[3];
+} PC87312State;
+
+
+#endif
diff --git a/include/hw/isa/vt82c686.h b/include/hw/isa/vt82c686.h
new file mode 100644 (file)
index 0000000..6ef876d
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef HW_VT82C686_H
+#define HW_VT82C686_H
+
+/* vt82c686.c */
+ISABus *vt82c686b_init(PCIBus * bus, int devfn);
+void vt82c686b_ac97_init(PCIBus *bus, int devfn);
+void vt82c686b_mc97_init(PCIBus *bus, int devfn);
+i2c_bus *vt82c686b_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
+            qemu_irq sci_irq);
+
+#endif
diff --git a/include/hw/kvm/clock.h b/include/hw/kvm/clock.h
new file mode 100644 (file)
index 0000000..252ea13
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * QEMU KVM support, paravirtual clock device
+ *
+ * Copyright (C) 2011 Siemens AG
+ *
+ * Authors:
+ *  Jan Kiszka        <jan.kiszka@siemens.com>
+ *
+ * This work is licensed under the terms of the GNU GPL version 2.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#ifdef CONFIG_KVM
+
+void kvmclock_create(void);
+
+#else /* CONFIG_KVM */
+
+static inline void kvmclock_create(void)
+{
+}
+
+#endif /* !CONFIG_KVM */
diff --git a/include/hw/lm32/lm32_juart.h b/include/hw/lm32/lm32_juart.h
new file mode 100644 (file)
index 0000000..67fc586
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef QEMU_HW_LM32_JUART_H
+#define QEMU_HW_LM32_JUART_H
+
+#include "qemu-common.h"
+
+uint32_t lm32_juart_get_jtx(DeviceState *d);
+uint32_t lm32_juart_get_jrx(DeviceState *d);
+void lm32_juart_set_jtx(DeviceState *d, uint32_t jtx);
+void lm32_juart_set_jrx(DeviceState *d, uint32_t jrx);
+
+#endif /* QEMU_HW_LM32_JUART_H */
diff --git a/include/hw/lm32/lm32_pic.h b/include/hw/lm32/lm32_pic.h
new file mode 100644 (file)
index 0000000..5556803
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef QEMU_HW_LM32_PIC_H
+#define QEMU_HW_LM32_PIC_H
+
+#include "qemu-common.h"
+
+uint32_t lm32_pic_get_ip(DeviceState *d);
+uint32_t lm32_pic_get_im(DeviceState *d);
+void lm32_pic_set_ip(DeviceState *d, uint32_t ip);
+void lm32_pic_set_im(DeviceState *d, uint32_t im);
+
+void lm32_do_pic_info(Monitor *mon, const QDict *qdict);
+void lm32_irq_info(Monitor *mon, const QDict *qdict);
+
+#endif /* QEMU_HW_LM32_PIC_H */
diff --git a/include/hw/loader.h b/include/hw/loader.h
new file mode 100644 (file)
index 0000000..0958f06
--- /dev/null
@@ -0,0 +1,52 @@
+#ifndef LOADER_H
+#define LOADER_H
+#include "qapi/qmp/qdict.h"
+
+/* loader.c */
+int get_image_size(const char *filename);
+int load_image(const char *filename, uint8_t *addr); /* deprecated */
+int load_image_targphys(const char *filename, hwaddr,
+                        uint64_t max_sz);
+int load_elf(const char *filename, uint64_t (*translate_fn)(void *, uint64_t),
+             void *translate_opaque, uint64_t *pentry, uint64_t *lowaddr,
+             uint64_t *highaddr, int big_endian, int elf_machine,
+             int clear_lsb);
+int load_aout(const char *filename, hwaddr addr, int max_sz,
+              int bswap_needed, hwaddr target_page_size);
+int load_uimage(const char *filename, hwaddr *ep,
+                hwaddr *loadaddr, int *is_linux);
+
+ssize_t read_targphys(const char *name,
+                      int fd, hwaddr dst_addr, size_t nbytes);
+void pstrcpy_targphys(const char *name,
+                      hwaddr dest, int buf_size,
+                      const char *source);
+
+
+int rom_add_file(const char *file, const char *fw_dir,
+                 hwaddr addr, int32_t bootindex);
+int rom_add_blob(const char *name, const void *blob, size_t len,
+                 hwaddr addr);
+int rom_add_elf_program(const char *name, void *data, size_t datasize,
+                        size_t romsize, hwaddr addr);
+int rom_load_all(void);
+void rom_set_fw(void *f);
+int rom_copy(uint8_t *dest, hwaddr addr, size_t size);
+void *rom_ptr(hwaddr addr);
+void do_info_roms(Monitor *mon, const QDict *qdict);
+
+#define rom_add_file_fixed(_f, _a, _i)          \
+    rom_add_file(_f, NULL, _a, _i)
+#define rom_add_blob_fixed(_f, _b, _l, _a)      \
+    rom_add_blob(_f, _b, _l, _a)
+
+#define PC_ROM_MIN_VGA     0xc0000
+#define PC_ROM_MIN_OPTION  0xc8000
+#define PC_ROM_MAX         0xe0000
+#define PC_ROM_ALIGN       0x800
+#define PC_ROM_SIZE        (PC_ROM_MAX - PC_ROM_MIN_VGA)
+
+int rom_add_vga(const char *file);
+int rom_add_option(const char *file, int32_t bootindex);
+
+#endif
diff --git a/include/hw/m68k/mcf.h b/include/hw/m68k/mcf.h
new file mode 100644 (file)
index 0000000..fbc8dc2
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef HW_MCF_H
+#define HW_MCF_H
+/* Motorola ColdFire device prototypes.  */
+
+struct MemoryRegion;
+
+/* mcf_uart.c */
+uint64_t mcf_uart_read(void *opaque, hwaddr addr,
+                       unsigned size);
+void mcf_uart_write(void *opaque, hwaddr addr,
+                    uint64_t val, unsigned size);
+void *mcf_uart_init(qemu_irq irq, CharDriverState *chr);
+void mcf_uart_mm_init(struct MemoryRegion *sysmem,
+                      hwaddr base,
+                      qemu_irq irq, CharDriverState *chr);
+
+/* mcf_intc.c */
+qemu_irq *mcf_intc_init(struct MemoryRegion *sysmem,
+                        hwaddr base,
+                        M68kCPU *cpu);
+
+/* mcf_fec.c */
+void mcf_fec_init(struct MemoryRegion *sysmem, NICInfo *nd,
+                  hwaddr base, qemu_irq *irq);
+
+/* mcf5206.c */
+qemu_irq *mcf5206_init(struct MemoryRegion *sysmem,
+                       uint32_t base, M68kCPU *cpu);
+
+#endif
diff --git a/include/hw/mips/bios.h b/include/hw/mips/bios.h
new file mode 100644 (file)
index 0000000..b4b88ac
--- /dev/null
@@ -0,0 +1,8 @@
+#include "cpu.h"
+
+#define BIOS_SIZE (4 * 1024 * 1024)
+#ifdef TARGET_WORDS_BIGENDIAN
+#define BIOS_FILENAME "mips_bios.bin"
+#else
+#define BIOS_FILENAME "mipsel_bios.bin"
+#endif
diff --git a/include/hw/mips/cpudevs.h b/include/hw/mips/cpudevs.h
new file mode 100644 (file)
index 0000000..6bea24b
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef HW_MIPS_CPUDEVS_H
+#define HW_MIPS_CPUDEVS_H
+/* Definitions for MIPS CPU internal devices.  */
+
+/* mips_addr.c */
+uint64_t cpu_mips_kseg0_to_phys(void *opaque, uint64_t addr);
+uint64_t cpu_mips_phys_to_kseg0(void *opaque, uint64_t addr);
+
+/* mips_int.c */
+void cpu_mips_irq_init_cpu(CPUMIPSState *env);
+
+/* mips_timer.c */
+void cpu_mips_clock_init(CPUMIPSState *);
+
+#endif
diff --git a/include/hw/mips/mips.h b/include/hw/mips/mips.h
new file mode 100644 (file)
index 0000000..291e85f
--- /dev/null
@@ -0,0 +1,29 @@
+#ifndef HW_MIPS_H
+#define HW_MIPS_H
+/* Definitions for mips board emulation.  */
+
+#include "exec/memory.h"
+
+/* gt64xxx.c */
+PCIBus *gt64120_register(qemu_irq *pic);
+
+/* bonito.c */
+PCIBus *bonito_init(qemu_irq *pic);
+
+/* rc4030.c */
+typedef struct rc4030DMAState *rc4030_dma;
+void rc4030_dma_memory_rw(void *opaque, hwaddr addr, uint8_t *buf, int len, int is_write);
+void rc4030_dma_read(void *dma, uint8_t *buf, int len);
+void rc4030_dma_write(void *dma, uint8_t *buf, int len);
+
+void *rc4030_init(qemu_irq timer, qemu_irq jazz_bus,
+                  qemu_irq **irqs, rc4030_dma **dmas,
+                  MemoryRegion *sysmem);
+
+/* dp8393x.c */
+void dp83932_init(NICInfo *nd, hwaddr base, int it_shift,
+                  MemoryRegion *address_space,
+                  qemu_irq irq, void* mem_opaque,
+                  void (*memory_rw)(void *opaque, hwaddr addr, uint8_t *buf, int len, int is_write));
+
+#endif
diff --git a/include/hw/misc/tmp105_regs.h b/include/hw/misc/tmp105_regs.h
new file mode 100644 (file)
index 0000000..9b55aba
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Texas Instruments TMP105 Temperature Sensor I2C messages
+ *
+ * Browse the data sheet:
+ *
+ *    http://www.ti.com/lit/gpn/tmp105
+ *
+ * Copyright (C) 2012 Alex Horn <alex.horn@cs.ox.ac.uk>
+ * Copyright (C) 2008-2012 Andrzej Zaborowski <balrogg@gmail.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_TMP105_MSGS_H
+#define QEMU_TMP105_MSGS_H
+
+/**
+ * TMP105Reg:
+ * @TMP105_REG_TEMPERATURE: Temperature register
+ * @TMP105_REG_CONFIG: Configuration register
+ * @TMP105_REG_T_LOW: Low temperature register (also known as T_hyst)
+ * @TMP105_REG_T_HIGH: High temperature register (also known as T_OS)
+ *
+ * The following temperature sensors are
+ * compatible with the TMP105 registers:
+ * - adt75
+ * - ds1775
+ * - ds75
+ * - lm75
+ * - lm75a
+ * - max6625
+ * - max6626
+ * - mcp980x
+ * - stds75
+ * - tcn75
+ * - tmp100
+ * - tmp101
+ * - tmp105
+ * - tmp175
+ * - tmp275
+ * - tmp75
+ **/
+typedef enum TMP105Reg {
+    TMP105_REG_TEMPERATURE = 0,
+    TMP105_REG_CONFIG,
+    TMP105_REG_T_LOW,
+    TMP105_REG_T_HIGH,
+} TMP105Reg;
+
+#endif
diff --git a/include/hw/nvram/eeprom93xx.h b/include/hw/nvram/eeprom93xx.h
new file mode 100644 (file)
index 0000000..8ba0e28
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * QEMU EEPROM 93xx emulation
+ *
+ * Copyright (c) 2006-2007 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
+ * 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 EEPROM93XX_H
+#define EEPROM93XX_H
+
+typedef struct _eeprom_t eeprom_t;
+
+/* Create a new EEPROM with (nwords * 2) bytes. */
+eeprom_t *eeprom93xx_new(DeviceState *dev, uint16_t nwords);
+
+/* Destroy an existing EEPROM. */
+void eeprom93xx_free(DeviceState *dev, eeprom_t *eeprom);
+
+/* Read from the EEPROM. */
+uint16_t eeprom93xx_read(eeprom_t *eeprom);
+
+/* Write to the EEPROM. */
+void eeprom93xx_write(eeprom_t *eeprom, int eecs, int eesk, int eedi);
+
+/* Get EEPROM data array. */
+uint16_t *eeprom93xx_data(eeprom_t *eeprom);
+
+#endif /* EEPROM93XX_H */
diff --git a/include/hw/nvram/fw_cfg.h b/include/hw/nvram/fw_cfg.h
new file mode 100644 (file)
index 0000000..05c8df1
--- /dev/null
@@ -0,0 +1,71 @@
+#ifndef FW_CFG_H
+#define FW_CFG_H
+
+#define FW_CFG_SIGNATURE        0x00
+#define FW_CFG_ID               0x01
+#define FW_CFG_UUID             0x02
+#define FW_CFG_RAM_SIZE         0x03
+#define FW_CFG_NOGRAPHIC        0x04
+#define FW_CFG_NB_CPUS          0x05
+#define FW_CFG_MACHINE_ID       0x06
+#define FW_CFG_KERNEL_ADDR      0x07
+#define FW_CFG_KERNEL_SIZE      0x08
+#define FW_CFG_KERNEL_CMDLINE   0x09
+#define FW_CFG_INITRD_ADDR      0x0a
+#define FW_CFG_INITRD_SIZE      0x0b
+#define FW_CFG_BOOT_DEVICE      0x0c
+#define FW_CFG_NUMA             0x0d
+#define FW_CFG_BOOT_MENU        0x0e
+#define FW_CFG_MAX_CPUS         0x0f
+#define FW_CFG_KERNEL_ENTRY     0x10
+#define FW_CFG_KERNEL_DATA      0x11
+#define FW_CFG_INITRD_DATA      0x12
+#define FW_CFG_CMDLINE_ADDR     0x13
+#define FW_CFG_CMDLINE_SIZE     0x14
+#define FW_CFG_CMDLINE_DATA     0x15
+#define FW_CFG_SETUP_ADDR       0x16
+#define FW_CFG_SETUP_SIZE       0x17
+#define FW_CFG_SETUP_DATA       0x18
+#define FW_CFG_FILE_DIR         0x19
+
+#define FW_CFG_FILE_FIRST       0x20
+#define FW_CFG_FILE_SLOTS       0x10
+#define FW_CFG_MAX_ENTRY        (FW_CFG_FILE_FIRST+FW_CFG_FILE_SLOTS)
+
+#define FW_CFG_WRITE_CHANNEL    0x4000
+#define FW_CFG_ARCH_LOCAL       0x8000
+#define FW_CFG_ENTRY_MASK       ~(FW_CFG_WRITE_CHANNEL | FW_CFG_ARCH_LOCAL)
+
+#define FW_CFG_INVALID          0xffff
+
+#ifndef NO_QEMU_PROTOS
+typedef struct FWCfgFile {
+    uint32_t  size;        /* file size */
+    uint16_t  select;      /* write this to 0x510 to read it */
+    uint16_t  reserved;
+    char      name[56];
+} FWCfgFile;
+
+typedef struct FWCfgFiles {
+    uint32_t  count;
+    FWCfgFile f[];
+} FWCfgFiles;
+
+typedef void (*FWCfgCallback)(void *opaque, uint8_t *data);
+
+typedef struct FWCfgState FWCfgState;
+void fw_cfg_add_bytes(FWCfgState *s, uint16_t key, void *data, size_t len);
+void fw_cfg_add_string(FWCfgState *s, uint16_t key, const char *value);
+void fw_cfg_add_i16(FWCfgState *s, uint16_t key, uint16_t value);
+void fw_cfg_add_i32(FWCfgState *s, uint16_t key, uint32_t value);
+void fw_cfg_add_i64(FWCfgState *s, uint16_t key, uint64_t value);
+void fw_cfg_add_callback(FWCfgState *s, uint16_t key, FWCfgCallback callback,
+                         void *callback_opaque, void *data, size_t len);
+void fw_cfg_add_file(FWCfgState *s, const char *filename, void *data,
+                     size_t len);
+FWCfgState *fw_cfg_init(uint32_t ctl_port, uint32_t data_port,
+                        hwaddr crl_addr, hwaddr data_addr);
+
+#endif /* NO_QEMU_PROTOS */
+
+#endif
diff --git a/include/hw/pci-host/apb.h b/include/hw/pci-host/apb.h
new file mode 100644 (file)
index 0000000..736db61
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef APB_PCI_H
+#define APB_PCI_H
+
+#include "qemu-common.h"
+
+PCIBus *pci_apb_init(hwaddr special_base,
+                     hwaddr mem_base,
+                     qemu_irq *ivec_irqs, PCIBus **bus2, PCIBus **bus3,
+                     qemu_irq **pbm_irqs);
+#endif
diff --git a/include/hw/pci-host/pam.h b/include/hw/pci-host/pam.h
new file mode 100644 (file)
index 0000000..8e9e349
--- /dev/null
@@ -0,0 +1,97 @@
+#ifndef QEMU_PAM_H
+#define QEMU_PAM_H
+
+/*
+ * Copyright (c) 2006 Fabrice Bellard
+ * Copyright (c) 2011 Isaku Yamahata <yamahata at valinux co jp>
+ *               VA Linux Systems Japan K.K.
+ * Copyright (c) 2012 Jason Baron <jbaron@redhat.com>
+ *
+ * Split out from piix_pci.c
+ *
+ * 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.
+ */
+
+/*
+ * SMRAM memory area and PAM memory area in Legacy address range for PC.
+ * PAM: Programmable Attribute Map registers
+ *
+ * 0xa0000 - 0xbffff compatible SMRAM
+ *
+ * 0xc0000 - 0xc3fff Expansion area memory segments
+ * 0xc4000 - 0xc7fff
+ * 0xc8000 - 0xcbfff
+ * 0xcc000 - 0xcffff
+ * 0xd0000 - 0xd3fff
+ * 0xd4000 - 0xd7fff
+ * 0xd8000 - 0xdbfff
+ * 0xdc000 - 0xdffff
+ * 0xe0000 - 0xe3fff Extended System BIOS Area Memory Segments
+ * 0xe4000 - 0xe7fff
+ * 0xe8000 - 0xebfff
+ * 0xec000 - 0xeffff
+ *
+ * 0xf0000 - 0xfffff System BIOS Area Memory Segments
+ */
+
+#include "qemu-common.h"
+#include "exec/memory.h"
+
+#define SMRAM_C_BASE    0xa0000
+#define SMRAM_C_END     0xc0000
+#define SMRAM_C_SIZE    0x20000
+
+#define PAM_EXPAN_BASE  0xc0000
+#define PAM_EXPAN_SIZE  0x04000
+
+#define PAM_EXBIOS_BASE 0xe0000
+#define PAM_EXBIOS_SIZE 0x04000
+
+#define PAM_BIOS_BASE   0xf0000
+#define PAM_BIOS_END    0xfffff
+/* 64KB: Intel 3 series express chipset family p. 58*/
+#define PAM_BIOS_SIZE   0x10000
+
+/* PAM registers: log nibble and high nibble*/
+#define PAM_ATTR_WE     ((uint8_t)2)
+#define PAM_ATTR_RE     ((uint8_t)1)
+#define PAM_ATTR_MASK   ((uint8_t)3)
+
+/* SMRAM register */
+#define SMRAM_D_OPEN           ((uint8_t)(1 << 6))
+#define SMRAM_D_CLS            ((uint8_t)(1 << 5))
+#define SMRAM_D_LCK            ((uint8_t)(1 << 4))
+#define SMRAM_G_SMRAME         ((uint8_t)(1 << 3))
+#define SMRAM_C_BASE_SEG_MASK  ((uint8_t)0x7)
+#define SMRAM_C_BASE_SEG       ((uint8_t)0x2)  /* hardwired to b010 */
+
+typedef struct PAMMemoryRegion {
+    MemoryRegion alias[4];  /* index = PAM value */
+    unsigned current;
+} PAMMemoryRegion;
+
+void smram_update(MemoryRegion *smram_region, uint8_t smram,
+                  uint8_t smm_enabled);
+void smram_set_smm(uint8_t *host_smm_enabled, int smm, uint8_t smram,
+                   MemoryRegion *smram_region);
+void init_pam(MemoryRegion *ram, MemoryRegion *system, MemoryRegion *pci,
+              PAMMemoryRegion *mem, uint32_t start, uint32_t size);
+void pam_update(PAMMemoryRegion *mem, int idx, uint8_t val);
+
+#endif /* QEMU_PAM_H */
diff --git a/include/hw/pci-host/ppce500.h b/include/hw/pci-host/ppce500.h
new file mode 100644 (file)
index 0000000..61f773e
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef PPCE500_PCI_H
+#define PPCE500_PCI_H
+
+static inline int ppce500_pci_map_irq_slot(int devno, int irq_num)
+{
+    return (devno + irq_num) % 4;
+}
+
+#endif
diff --git a/include/hw/pci-host/q35.h b/include/hw/pci-host/q35.h
new file mode 100644 (file)
index 0000000..e182c82
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * q35.h
+ *
+ * Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp>
+ *                    VA Linux Systems Japan K.K.
+ * Copyright (C) 2012 Jason Baron <jbaron@redhat.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 Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+
+#ifndef HW_Q35_H
+#define HW_Q35_H
+
+#include "hw/hw.h"
+#include "qemu/range.h"
+#include "hw/isa/isa.h"
+#include "hw/sysbus.h"
+#include "hw/i386/pc.h"
+#include "hw/isa/apm.h"
+#include "hw/pci/pci.h"
+#include "hw/pci/pcie_host.h"
+#include "hw/acpi/acpi.h"
+#include "hw/acpi/ich9.h"
+#include "hw/pci-host/pam.h"
+
+#define TYPE_Q35_HOST_DEVICE "q35-pcihost"
+#define Q35_HOST_DEVICE(obj) \
+     OBJECT_CHECK(Q35PCIHost, (obj), TYPE_Q35_HOST_DEVICE)
+
+#define TYPE_MCH_PCI_DEVICE "mch"
+#define MCH_PCI_DEVICE(obj) \
+     OBJECT_CHECK(MCHPCIState, (obj), TYPE_MCH_PCI_DEVICE)
+
+typedef struct MCHPCIState {
+    PCIDevice d;
+    MemoryRegion *ram_memory;
+    MemoryRegion *pci_address_space;
+    MemoryRegion *system_memory;
+    MemoryRegion *address_space_io;
+    PAMMemoryRegion pam_regions[13];
+    MemoryRegion smram_region;
+    MemoryRegion pci_hole;
+    MemoryRegion pci_hole_64bit;
+    uint8_t smm_enabled;
+    ram_addr_t below_4g_mem_size;
+    ram_addr_t above_4g_mem_size;
+} MCHPCIState;
+
+typedef struct Q35PCIHost {
+    PCIExpressHost host;
+    MCHPCIState mch;
+} Q35PCIHost;
+
+#define Q35_MASK(bit, ms_bit, ls_bit) \
+((uint##bit##_t)(((1ULL << ((ms_bit) + 1)) - 1) & ~((1ULL << ls_bit) - 1)))
+
+/*
+ * gmch part
+ */
+
+/* PCI configuration */
+#define MCH_HOST_BRIDGE                        "MCH"
+
+#define MCH_HOST_BRIDGE_CONFIG_ADDR            0xcf8
+#define MCH_HOST_BRIDGE_CONFIG_DATA            0xcfc
+
+/* D0:F0 configuration space */
+#define MCH_HOST_BRIDGE_REVISION_DEFUALT       0x0
+
+#define MCH_HOST_BRIDGE_PCIEXBAR               0x60    /* 64bit register */
+#define MCH_HOST_BRIDGE_PCIEXBAR_SIZE          8       /* 64bit register */
+#define MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT       0xb0000000
+#define MCH_HOST_BRIDGE_PCIEXBAR_ADMSK         Q35_MASK(64, 35, 28)
+#define MCH_HOST_BRIDGE_PCIEXBAR_128ADMSK      ((uint64_t)(1 << 26))
+#define MCH_HOST_BRIDGE_PCIEXBAR_64ADMSK       ((uint64_t)(1 << 25))
+#define MCH_HOST_BRIDGE_PCIEXBAR_LENGTH_MASK   ((uint64_t)(0x3 << 1))
+#define MCH_HOST_BRIDGE_PCIEXBAR_LENGTH_256M   ((uint64_t)(0x0 << 1))
+#define MCH_HOST_BRIDGE_PCIEXBAR_LENGTH_128M   ((uint64_t)(0x1 << 1))
+#define MCH_HOST_BRIDGE_PCIEXBAR_LENGTH_64M    ((uint64_t)(0x2 << 1))
+#define MCH_HOST_BRIDGE_PCIEXBAR_LENGTH_RVD    ((uint64_t)(0x3 << 1))
+#define MCH_HOST_BRIDGE_PCIEXBAREN             ((uint64_t)1)
+
+#define MCH_HOST_BRIDGE_PAM_NB                 7
+#define MCH_HOST_BRIDGE_PAM_SIZE               7
+#define MCH_HOST_BRIDGE_PAM0                   0x90
+#define MCH_HOST_BRIDGE_PAM_BIOS_AREA          0xf0000
+#define MCH_HOST_BRIDGE_PAM_AREA_SIZE          0x10000 /* 16KB */
+#define MCH_HOST_BRIDGE_PAM1                   0x91
+#define MCH_HOST_BRIDGE_PAM_EXPAN_AREA         0xc0000
+#define MCH_HOST_BRIDGE_PAM_EXPAN_SIZE         0x04000
+#define MCH_HOST_BRIDGE_PAM2                   0x92
+#define MCH_HOST_BRIDGE_PAM3                   0x93
+#define MCH_HOST_BRIDGE_PAM4                   0x94
+#define MCH_HOST_BRIDGE_PAM_EXBIOS_AREA        0xe0000
+#define MCH_HOST_BRIDGE_PAM_EXBIOS_SIZE        0x04000
+#define MCH_HOST_BRIDGE_PAM5                   0x95
+#define MCH_HOST_BRIDGE_PAM6                   0x96
+#define MCH_HOST_BRIDGE_PAM_WE_HI              ((uint8_t)(0x2 << 4))
+#define MCH_HOST_BRIDGE_PAM_RE_HI              ((uint8_t)(0x1 << 4))
+#define MCH_HOST_BRIDGE_PAM_HI_MASK            ((uint8_t)(0x3 << 4))
+#define MCH_HOST_BRIDGE_PAM_WE_LO              ((uint8_t)0x2)
+#define MCH_HOST_BRIDGE_PAM_RE_LO              ((uint8_t)0x1)
+#define MCH_HOST_BRIDGE_PAM_LO_MASK            ((uint8_t)0x3)
+#define MCH_HOST_BRIDGE_PAM_WE                 ((uint8_t)0x2)
+#define MCH_HOST_BRIDGE_PAM_RE                 ((uint8_t)0x1)
+#define MCH_HOST_BRIDGE_PAM_MASK               ((uint8_t)0x3)
+
+#define MCH_HOST_BRDIGE_SMRAM                  0x9d
+#define MCH_HOST_BRDIGE_SMRAM_SIZE             1
+#define MCH_HOST_BRIDGE_SMRAM_DEFAULT          ((uint8_t)0x2)
+#define MCH_HOST_BRIDGE_SMRAM_D_OPEN           ((uint8_t)(1 << 6))
+#define MCH_HOST_BRIDGE_SMRAM_D_CLS            ((uint8_t)(1 << 5))
+#define MCH_HOST_BRIDGE_SMRAM_D_LCK            ((uint8_t)(1 << 4))
+#define MCH_HOST_BRIDGE_SMRAM_G_SMRAME         ((uint8_t)(1 << 3))
+#define MCH_HOST_BRIDGE_SMRAM_C_BASE_SEG_MASK  ((uint8_t)0x7)
+#define MCH_HOST_BRIDGE_SMRAM_C_BASE_SEG       ((uint8_t)0x2)  /* hardwired to b010 */
+#define MCH_HOST_BRIDGE_SMRAM_C_BASE           0xa0000
+#define MCH_HOST_BRIDGE_SMRAM_C_END            0xc0000
+#define MCH_HOST_BRIDGE_SMRAM_C_SIZE           0x20000
+#define MCH_HOST_BRIDGE_UPPER_SYSTEM_BIOS_END  0x100000
+
+#define MCH_HOST_BRIDGE_ESMRAMC                0x9e
+#define MCH_HOST_BRDIGE_ESMRAMC_H_SMRAME       ((uint8_t)(1 << 6))
+#define MCH_HOST_BRDIGE_ESMRAMC_E_SMERR        ((uint8_t)(1 << 5))
+#define MCH_HOST_BRDIGE_ESMRAMC_SM_CACHE       ((uint8_t)(1 << 4))
+#define MCH_HOST_BRDIGE_ESMRAMC_SM_L1          ((uint8_t)(1 << 3))
+#define MCH_HOST_BRDIGE_ESMRAMC_SM_L2          ((uint8_t)(1 << 2))
+#define MCH_HOST_BRDIGE_ESMRAMC_TSEG_SZ_MASK   ((uint8_t)(0x3 << 1))
+#define MCH_HOST_BRDIGE_ESMRAMC_TSEG_SZ_1MB    ((uint8_t)(0x0 << 1))
+#define MCH_HOST_BRDIGE_ESMRAMC_TSEG_SZ_2MB    ((uint8_t)(0x1 << 1))
+#define MCH_HOST_BRDIGE_ESMRAMC_TSEG_SZ_8MB    ((uint8_t)(0x2 << 1))
+#define MCH_HOST_BRDIGE_ESMRAMC_T_EN           ((uint8_t)1)
+
+/* D1:F0 PCIE* port*/
+#define MCH_PCIE_DEV                           1
+#define MCH_PCIE_FUNC                          0
+
+#endif /* HW_Q35_H */
diff --git a/include/hw/pci-host/spapr.h b/include/hw/pci-host/spapr.h
new file mode 100644 (file)
index 0000000..b21080c
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * QEMU SPAPR PCI BUS definitions
+ *
+ * Copyright (c) 2011 Alexey Kardashevskiy <aik@au1.ibm.com>
+ *
+ * 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/>.
+ */
+#if !defined(__HW_SPAPR_H__)
+#error Please include spapr.h before this file!
+#endif
+
+#if !defined(__HW_SPAPR_PCI_H__)
+#define __HW_SPAPR_PCI_H__
+
+#include "hw/pci/pci.h"
+#include "hw/pci/pci_host.h"
+#include "hw/ppc/xics.h"
+
+#define SPAPR_MSIX_MAX_DEVS 32
+
+#define TYPE_SPAPR_PCI_HOST_BRIDGE "spapr-pci-host-bridge"
+
+#define SPAPR_PCI_HOST_BRIDGE(obj) \
+    OBJECT_CHECK(sPAPRPHBState, (obj), TYPE_SPAPR_PCI_HOST_BRIDGE)
+
+typedef struct sPAPRPHBState {
+    PCIHostState parent_obj;
+
+    int32_t index;
+    uint64_t buid;
+    char *dtbusname;
+
+    MemoryRegion memspace, iospace;
+    hwaddr mem_win_addr, mem_win_size, io_win_addr, io_win_size;
+    hwaddr msi_win_addr;
+    MemoryRegion memwindow, iowindow, msiwindow;
+
+    uint32_t dma_liobn;
+    uint64_t dma_window_start;
+    uint64_t dma_window_size;
+    DMAContext *dma;
+
+    struct {
+        uint32_t irq;
+    } lsi_table[PCI_NUM_PINS];
+
+    struct {
+        uint32_t config_addr;
+        uint32_t irq;
+        int nvec;
+    } msi_table[SPAPR_MSIX_MAX_DEVS];
+
+    QLIST_ENTRY(sPAPRPHBState) list;
+} sPAPRPHBState;
+
+#define SPAPR_PCI_BASE_BUID          0x800000020000000ULL
+
+#define SPAPR_PCI_WINDOW_BASE        0x10000000000ULL
+#define SPAPR_PCI_WINDOW_SPACING     0x1000000000ULL
+#define SPAPR_PCI_MMIO_WIN_OFF       0xA0000000
+#define SPAPR_PCI_MMIO_WIN_SIZE      0x20000000
+#define SPAPR_PCI_IO_WIN_OFF         0x80000000
+#define SPAPR_PCI_IO_WIN_SIZE        0x10000
+#define SPAPR_PCI_MSI_WIN_OFF        0x90000000
+
+#define SPAPR_PCI_MEM_WIN_BUS_OFFSET 0x80000000ULL
+
+static inline qemu_irq spapr_phb_lsi_qirq(struct sPAPRPHBState *phb, int pin)
+{
+    return xics_get_qirq(spapr->icp, phb->lsi_table[pin].irq);
+}
+
+PCIHostState *spapr_create_phb(sPAPREnvironment *spapr, int index);
+
+int spapr_populate_pci_dt(sPAPRPHBState *phb,
+                          uint32_t xics_phandle,
+                          void *fdt);
+
+void spapr_pci_rtas_init(void);
+
+#endif /* __HW_SPAPR_PCI_H__ */
diff --git a/include/hw/pci/msi.h b/include/hw/pci/msi.h
new file mode 100644 (file)
index 0000000..81a3848
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * msi.h
+ *
+ * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
+ *                    VA Linux Systems Japan K.K.
+ *
+ * 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 QEMU_MSI_H
+#define QEMU_MSI_H
+
+#include "qemu-common.h"
+#include "hw/pci/pci.h"
+
+struct MSIMessage {
+    uint64_t address;
+    uint32_t data;
+};
+
+extern bool msi_supported;
+
+void msi_set_message(PCIDevice *dev, MSIMessage msg);
+MSIMessage msi_get_message(PCIDevice *dev, unsigned int vector);
+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);
+void msi_uninit(struct PCIDevice *dev);
+void msi_reset(PCIDevice *dev);
+void msi_notify(PCIDevice *dev, unsigned int vector);
+void msi_write_config(PCIDevice *dev, uint32_t addr, uint32_t val, int len);
+unsigned int msi_nr_vectors_allocated(const PCIDevice *dev);
+
+static inline bool msi_present(const PCIDevice *dev)
+{
+    return dev->cap_present & QEMU_PCI_CAP_MSI;
+}
+
+#endif /* QEMU_MSI_H */
diff --git a/include/hw/pci/msix.h b/include/hw/pci/msix.h
new file mode 100644 (file)
index 0000000..e648410
--- /dev/null
@@ -0,0 +1,46 @@
+#ifndef QEMU_MSIX_H
+#define QEMU_MSIX_H
+
+#include "qemu-common.h"
+#include "hw/pci/pci.h"
+
+void msix_set_message(PCIDevice *dev, int vector, MSIMessage msg);
+MSIMessage msix_get_message(PCIDevice *dev, unsigned int vector);
+int msix_init(PCIDevice *dev, unsigned short nentries,
+              MemoryRegion *table_bar, uint8_t table_bar_nr,
+              unsigned table_offset, MemoryRegion *pba_bar,
+              uint8_t pba_bar_nr, unsigned pba_offset, uint8_t cap_pos);
+int msix_init_exclusive_bar(PCIDevice *dev, unsigned short nentries,
+                            uint8_t bar_nr);
+
+void msix_write_config(PCIDevice *dev, uint32_t address, uint32_t val, int len);
+
+void msix_uninit(PCIDevice *dev, MemoryRegion *table_bar,
+                 MemoryRegion *pba_bar);
+void msix_uninit_exclusive_bar(PCIDevice *dev);
+
+unsigned int msix_nr_vectors_allocated(const PCIDevice *dev);
+
+void msix_save(PCIDevice *dev, QEMUFile *f);
+void msix_load(PCIDevice *dev, QEMUFile *f);
+
+int msix_enabled(PCIDevice *dev);
+int msix_present(PCIDevice *dev);
+
+bool msix_is_masked(PCIDevice *dev, unsigned vector);
+void msix_set_pending(PCIDevice *dev, unsigned vector);
+
+int msix_vector_use(PCIDevice *dev, unsigned vector);
+void msix_vector_unuse(PCIDevice *dev, unsigned vector);
+void msix_unuse_all_vectors(PCIDevice *dev);
+
+void msix_notify(PCIDevice *dev, unsigned vector);
+
+void msix_reset(PCIDevice *dev);
+
+int msix_set_vector_notifiers(PCIDevice *dev,
+                              MSIVectorUseNotifier use_notifier,
+                              MSIVectorReleaseNotifier release_notifier,
+                              MSIVectorPollNotifier poll_notifier);
+void msix_unset_vector_notifiers(PCIDevice *dev);
+#endif
diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h
new file mode 100644 (file)
index 0000000..05315c0
--- /dev/null
@@ -0,0 +1,725 @@
+#ifndef QEMU_PCI_H
+#define QEMU_PCI_H
+
+#include "qemu-common.h"
+
+#include "hw/qdev.h"
+#include "exec/memory.h"
+#include "sysemu/dma.h"
+
+/* PCI includes legacy ISA access.  */
+#include "hw/isa/isa.h"
+
+#include "hw/pci/pcie.h"
+
+/* PCI bus */
+
+#define PCI_DEVFN(slot, func)   ((((slot) & 0x1f) << 3) | ((func) & 0x07))
+#define PCI_SLOT(devfn)         (((devfn) >> 3) & 0x1f)
+#define PCI_FUNC(devfn)         ((devfn) & 0x07)
+#define PCI_SLOT_MAX            32
+#define PCI_FUNC_MAX            8
+
+/* Class, Vendor and Device IDs from Linux's pci_ids.h */
+#include "hw/pci/pci_ids.h"
+
+/* QEMU-specific Vendor and Device ID definitions */
+
+/* IBM (0x1014) */
+#define PCI_DEVICE_ID_IBM_440GX          0x027f
+#define PCI_DEVICE_ID_IBM_OPENPIC2       0xffff
+
+/* Hitachi (0x1054) */
+#define PCI_VENDOR_ID_HITACHI            0x1054
+#define PCI_DEVICE_ID_HITACHI_SH7751R    0x350e
+
+/* Apple (0x106b) */
+#define PCI_DEVICE_ID_APPLE_343S1201     0x0010
+#define PCI_DEVICE_ID_APPLE_UNI_N_I_PCI  0x001e
+#define PCI_DEVICE_ID_APPLE_UNI_N_PCI    0x001f
+#define PCI_DEVICE_ID_APPLE_UNI_N_KEYL   0x0022
+#define PCI_DEVICE_ID_APPLE_IPID_USB     0x003f
+
+/* Realtek (0x10ec) */
+#define PCI_DEVICE_ID_REALTEK_8029       0x8029
+
+/* Xilinx (0x10ee) */
+#define PCI_DEVICE_ID_XILINX_XC2VP30     0x0300
+
+/* Marvell (0x11ab) */
+#define PCI_DEVICE_ID_MARVELL_GT6412X    0x4620
+
+/* QEMU/Bochs VGA (0x1234) */
+#define PCI_VENDOR_ID_QEMU               0x1234
+#define PCI_DEVICE_ID_QEMU_VGA           0x1111
+
+/* VMWare (0x15ad) */
+#define PCI_VENDOR_ID_VMWARE             0x15ad
+#define PCI_DEVICE_ID_VMWARE_SVGA2       0x0405
+#define PCI_DEVICE_ID_VMWARE_SVGA        0x0710
+#define PCI_DEVICE_ID_VMWARE_NET         0x0720
+#define PCI_DEVICE_ID_VMWARE_SCSI        0x0730
+#define PCI_DEVICE_ID_VMWARE_IDE         0x1729
+#define PCI_DEVICE_ID_VMWARE_VMXNET3     0x07B0
+
+/* Intel (0x8086) */
+#define PCI_DEVICE_ID_INTEL_82551IT      0x1209
+#define PCI_DEVICE_ID_INTEL_82557        0x1229
+#define PCI_DEVICE_ID_INTEL_82801IR      0x2922
+
+/* Red Hat / Qumranet (for QEMU) -- see pci-ids.txt */
+#define PCI_VENDOR_ID_REDHAT_QUMRANET    0x1af4
+#define PCI_SUBVENDOR_ID_REDHAT_QUMRANET 0x1af4
+#define PCI_SUBDEVICE_ID_QEMU            0x1100
+
+#define PCI_DEVICE_ID_VIRTIO_NET         0x1000
+#define PCI_DEVICE_ID_VIRTIO_BLOCK       0x1001
+#define PCI_DEVICE_ID_VIRTIO_BALLOON     0x1002
+#define PCI_DEVICE_ID_VIRTIO_CONSOLE     0x1003
+#define PCI_DEVICE_ID_VIRTIO_SCSI        0x1004
+#define PCI_DEVICE_ID_VIRTIO_RNG         0x1005
+#define PCI_DEVICE_ID_VIRTIO_9P          0x1009
+
+#define PCI_VENDOR_ID_REDHAT             0x1b36
+#define PCI_DEVICE_ID_REDHAT_BRIDGE      0x0001
+#define PCI_DEVICE_ID_REDHAT_SERIAL      0x0002
+#define PCI_DEVICE_ID_REDHAT_SERIAL2     0x0003
+#define PCI_DEVICE_ID_REDHAT_SERIAL4     0x0004
+#define PCI_DEVICE_ID_REDHAT_QXL         0x0100
+
+#define FMT_PCIBUS                      PRIx64
+
+typedef void PCIConfigWriteFunc(PCIDevice *pci_dev,
+                                uint32_t address, uint32_t data, int len);
+typedef uint32_t PCIConfigReadFunc(PCIDevice *pci_dev,
+                                   uint32_t address, int len);
+typedef void PCIMapIORegionFunc(PCIDevice *pci_dev, int region_num,
+                                pcibus_t addr, pcibus_t size, int type);
+typedef void PCIUnregisterFunc(PCIDevice *pci_dev);
+
+typedef struct PCIIORegion {
+    pcibus_t addr; /* current PCI mapping address. -1 means not mapped */
+#define PCI_BAR_UNMAPPED (~(pcibus_t)0)
+    pcibus_t size;
+    uint8_t type;
+    MemoryRegion *memory;
+    MemoryRegion *address_space;
+} PCIIORegion;
+
+#define PCI_ROM_SLOT 6
+#define PCI_NUM_REGIONS 7
+
+enum {
+    QEMU_PCI_VGA_MEM,
+    QEMU_PCI_VGA_IO_LO,
+    QEMU_PCI_VGA_IO_HI,
+    QEMU_PCI_VGA_NUM_REGIONS,
+};
+
+#define QEMU_PCI_VGA_MEM_BASE 0xa0000
+#define QEMU_PCI_VGA_MEM_SIZE 0x20000
+#define QEMU_PCI_VGA_IO_LO_BASE 0x3b0
+#define QEMU_PCI_VGA_IO_LO_SIZE 0xc
+#define QEMU_PCI_VGA_IO_HI_BASE 0x3c0
+#define QEMU_PCI_VGA_IO_HI_SIZE 0x20
+
+#include "hw/pci/pci_regs.h"
+
+/* PCI HEADER_TYPE */
+#define  PCI_HEADER_TYPE_MULTI_FUNCTION 0x80
+
+/* Size of the standard PCI config header */
+#define PCI_CONFIG_HEADER_SIZE 0x40
+/* Size of the standard PCI config space */
+#define PCI_CONFIG_SPACE_SIZE 0x100
+/* Size of the standart PCIe config space: 4KB */
+#define PCIE_CONFIG_SPACE_SIZE  0x1000
+
+#define PCI_NUM_PINS 4 /* A-D */
+
+/* Bits in cap_present field. */
+enum {
+    QEMU_PCI_CAP_MSI = 0x1,
+    QEMU_PCI_CAP_MSIX = 0x2,
+    QEMU_PCI_CAP_EXPRESS = 0x4,
+
+    /* multifunction capable device */
+#define QEMU_PCI_CAP_MULTIFUNCTION_BITNR        3
+    QEMU_PCI_CAP_MULTIFUNCTION = (1 << QEMU_PCI_CAP_MULTIFUNCTION_BITNR),
+
+    /* command register SERR bit enabled */
+#define QEMU_PCI_CAP_SERR_BITNR 4
+    QEMU_PCI_CAP_SERR = (1 << QEMU_PCI_CAP_SERR_BITNR),
+    /* Standard hot plug controller. */
+#define QEMU_PCI_SHPC_BITNR 5
+    QEMU_PCI_CAP_SHPC = (1 << QEMU_PCI_SHPC_BITNR),
+#define QEMU_PCI_SLOTID_BITNR 6
+    QEMU_PCI_CAP_SLOTID = (1 << QEMU_PCI_SLOTID_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 PCIINTxRoute {
+    enum {
+        PCI_INTX_ENABLED,
+        PCI_INTX_INVERTED,
+        PCI_INTX_DISABLED,
+    } mode;
+    int irq;
+} PCIINTxRoute;
+
+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;
+
+typedef void (*PCIINTxRoutingNotifier)(PCIDevice *dev);
+typedef int (*MSIVectorUseNotifier)(PCIDevice *dev, unsigned int vector,
+                                      MSIMessage msg);
+typedef void (*MSIVectorReleaseNotifier)(PCIDevice *dev, unsigned int vector);
+typedef void (*MSIVectorPollNotifier)(PCIDevice *dev,
+                                      unsigned int vector_start,
+                                      unsigned int vector_end);
+
+struct PCIDevice {
+    DeviceState qdev;
+
+    /* PCI config space */
+    uint8_t *config;
+
+    /* Used to enable config checks on load. Note that writable bits are
+     * never checked even if set in cmask. */
+    uint8_t *cmask;
+
+    /* Used to implement R/W bytes */
+    uint8_t *wmask;
+
+    /* Used to implement RW1C(Write 1 to Clear) bytes */
+    uint8_t *w1cmask;
+
+    /* Used to allocate config space for capabilities. */
+    uint8_t *used;
+
+    /* the following fields are read only */
+    PCIBus *bus;
+    int32_t devfn;
+    char name[64];
+    PCIIORegion io_regions[PCI_NUM_REGIONS];
+    AddressSpace bus_master_as;
+    MemoryRegion bus_master_enable_region;
+    DMAContext *dma;
+
+    /* do not access the following fields */
+    PCIConfigReadFunc *config_read;
+    PCIConfigWriteFunc *config_write;
+
+    /* IRQ objects for the INTA-INTD pins.  */
+    qemu_irq *irq;
+
+    /* Legacy PCI VGA regions */
+    MemoryRegion *vga_regions[QEMU_PCI_VGA_NUM_REGIONS];
+    bool has_vga;
+
+    /* Current IRQ levels.  Used internally by the generic PCI code.  */
+    uint8_t irq_state;
+
+    /* Capability bits */
+    uint32_t cap_present;
+
+    /* Offset of MSI-X capability in config space */
+    uint8_t msix_cap;
+
+    /* MSI-X entries */
+    int msix_entries_nr;
+
+    /* Space to store MSIX table & pending bit array */
+    uint8_t *msix_table;
+    uint8_t *msix_pba;
+    /* MemoryRegion container for msix exclusive BAR setup */
+    MemoryRegion msix_exclusive_bar;
+    /* Memory Regions for MSIX table and pending bit entries. */
+    MemoryRegion msix_table_mmio;
+    MemoryRegion msix_pba_mmio;
+    /* Reference-count for entries actually in use by driver. */
+    unsigned *msix_entry_used;
+    /* MSIX function mask set or MSIX disabled */
+    bool msix_function_masked;
+    /* Version id needed for VMState */
+    int32_t version_id;
+
+    /* Offset of MSI capability in config space */
+    uint8_t msi_cap;
+
+    /* PCI Express */
+    PCIExpressDevice exp;
+
+    /* SHPC */
+    SHPCDevice *shpc;
+
+    /* Location of option rom */
+    char *romfile;
+    bool has_rom;
+    MemoryRegion rom;
+    uint32_t rom_bar;
+
+    /* INTx routing notifier */
+    PCIINTxRoutingNotifier intx_routing_notifier;
+
+    /* MSI-X notifiers */
+    MSIVectorUseNotifier msix_vector_use_notifier;
+    MSIVectorReleaseNotifier msix_vector_release_notifier;
+    MSIVectorPollNotifier msix_vector_poll_notifier;
+};
+
+void pci_register_bar(PCIDevice *pci_dev, int region_num,
+                      uint8_t attr, MemoryRegion *memory);
+void pci_register_vga(PCIDevice *pci_dev, MemoryRegion *mem,
+                      MemoryRegion *io_lo, MemoryRegion *io_hi);
+void pci_unregister_vga(PCIDevice *pci_dev);
+pcibus_t pci_get_bar_addr(PCIDevice *pci_dev, int region_num);
+
+int pci_add_capability(PCIDevice *pdev, uint8_t cap_id,
+                       uint8_t offset, uint8_t size);
+
+void pci_del_capability(PCIDevice *pci_dev, uint8_t cap_id, uint8_t cap_size);
+
+uint8_t pci_find_capability(PCIDevice *pci_dev, uint8_t cap_id);
+
+
+uint32_t pci_default_read_config(PCIDevice *d,
+                                 uint32_t address, int len);
+void pci_default_write_config(PCIDevice *d,
+                              uint32_t address, uint32_t val, int len);
+void pci_device_save(PCIDevice *s, QEMUFile *f);
+int pci_device_load(PCIDevice *s, QEMUFile *f);
+MemoryRegion *pci_address_space(PCIDevice *dev);
+MemoryRegion *pci_address_space_io(PCIDevice *dev);
+
+typedef void (*pci_set_irq_fn)(void *opaque, int irq_num, int level);
+typedef int (*pci_map_irq_fn)(PCIDevice *pci_dev, int irq_num);
+typedef PCIINTxRoute (*pci_route_irq_fn)(void *opaque, int pin);
+
+typedef enum {
+    PCI_HOTPLUG_DISABLED,
+    PCI_HOTPLUG_ENABLED,
+    PCI_COLDPLUG_ENABLED,
+} PCIHotplugState;
+
+typedef int (*pci_hotplug_fn)(DeviceState *qdev, PCIDevice *pci_dev,
+                              PCIHotplugState state);
+
+#define TYPE_PCI_BUS "PCI"
+#define PCI_BUS(obj) OBJECT_CHECK(PCIBus, (obj), TYPE_PCI_BUS)
+#define TYPE_PCIE_BUS "PCIE"
+
+bool pci_bus_is_express(PCIBus *bus);
+bool pci_bus_is_root(PCIBus *bus);
+void pci_bus_new_inplace(PCIBus *bus, DeviceState *parent,
+                         const char *name,
+                         MemoryRegion *address_space_mem,
+                         MemoryRegion *address_space_io,
+                         uint8_t devfn_min, const char *typename);
+PCIBus *pci_bus_new(DeviceState *parent, const char *name,
+                    MemoryRegion *address_space_mem,
+                    MemoryRegion *address_space_io,
+                    uint8_t devfn_min, const char *typename);
+void pci_bus_irqs(PCIBus *bus, pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
+                  void *irq_opaque, int nirq);
+int pci_bus_get_irq_level(PCIBus *bus, int irq_num);
+void pci_bus_hotplug(PCIBus *bus, pci_hotplug_fn hotplug, DeviceState *dev);
+/* 0 <= pin <= 3 0 = INTA, 1 = INTB, 2 = INTC, 3 = INTD */
+int pci_swizzle_map_irq_fn(PCIDevice *pci_dev, int pin);
+PCIBus *pci_register_bus(DeviceState *parent, const char *name,
+                         pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
+                         void *irq_opaque,
+                         MemoryRegion *address_space_mem,
+                         MemoryRegion *address_space_io,
+                         uint8_t devfn_min, int nirq, const char *typename);
+void pci_bus_set_route_irq_fn(PCIBus *, pci_route_irq_fn);
+PCIINTxRoute pci_device_route_intx_to_irq(PCIDevice *dev, int pin);
+bool pci_intx_route_changed(PCIINTxRoute *old, PCIINTxRoute *new);
+void pci_bus_fire_intx_routing_notifier(PCIBus *bus);
+void pci_device_set_intx_routing_notifier(PCIDevice *dev,
+                                          PCIINTxRoutingNotifier notifier);
+void pci_device_reset(PCIDevice *dev);
+void pci_bus_reset(PCIBus *bus);
+
+PCIDevice *pci_nic_init(NICInfo *nd, const char *default_model,
+                        const char *default_devaddr);
+PCIDevice *pci_nic_init_nofail(NICInfo *nd, const char *default_model,
+                               const char *default_devaddr);
+
+PCIDevice *pci_vga_init(PCIBus *bus);
+
+int pci_bus_num(PCIBus *s);
+void pci_for_each_device(PCIBus *bus, int bus_num,
+                         void (*fn)(PCIBus *bus, PCIDevice *d, void *opaque),
+                         void *opaque);
+PCIBus *pci_find_root_bus(int domain);
+int pci_find_domain(const PCIBus *bus);
+PCIDevice *pci_find_device(PCIBus *bus, int bus_num, uint8_t devfn);
+int pci_qdev_find_device(const char *id, PCIDevice **pdev);
+PCIBus *pci_get_bus_devfn(int *devfnp, const char *devaddr);
+
+int pci_read_devaddr(Monitor *mon, const char *addr, int *domp, int *busp,
+                     unsigned *slotp);
+
+void pci_device_deassert_intx(PCIDevice *dev);
+
+typedef DMAContext *(*PCIDMAContextFunc)(PCIBus *, void *, int);
+
+void pci_setup_iommu(PCIBus *bus, PCIDMAContextFunc fn, void *opaque);
+
+static inline void
+pci_set_byte(uint8_t *config, uint8_t val)
+{
+    *config = val;
+}
+
+static inline uint8_t
+pci_get_byte(const uint8_t *config)
+{
+    return *config;
+}
+
+static inline void
+pci_set_word(uint8_t *config, uint16_t val)
+{
+    cpu_to_le16wu((uint16_t *)config, val);
+}
+
+static inline uint16_t
+pci_get_word(const uint8_t *config)
+{
+    return le16_to_cpupu((const uint16_t *)config);
+}
+
+static inline void
+pci_set_long(uint8_t *config, uint32_t val)
+{
+    cpu_to_le32wu((uint32_t *)config, val);
+}
+
+static inline uint32_t
+pci_get_long(const uint8_t *config)
+{
+    return le32_to_cpupu((const uint32_t *)config);
+}
+
+static inline void
+pci_set_quad(uint8_t *config, uint64_t val)
+{
+    cpu_to_le64w((uint64_t *)config, val);
+}
+
+static inline uint64_t
+pci_get_quad(const uint8_t *config)
+{
+    return le64_to_cpup((const uint64_t *)config);
+}
+
+static inline void
+pci_config_set_vendor_id(uint8_t *pci_config, uint16_t val)
+{
+    pci_set_word(&pci_config[PCI_VENDOR_ID], val);
+}
+
+static inline void
+pci_config_set_device_id(uint8_t *pci_config, uint16_t val)
+{
+    pci_set_word(&pci_config[PCI_DEVICE_ID], val);
+}
+
+static inline void
+pci_config_set_revision(uint8_t *pci_config, uint8_t val)
+{
+    pci_set_byte(&pci_config[PCI_REVISION_ID], val);
+}
+
+static inline void
+pci_config_set_class(uint8_t *pci_config, uint16_t val)
+{
+    pci_set_word(&pci_config[PCI_CLASS_DEVICE], val);
+}
+
+static inline void
+pci_config_set_prog_interface(uint8_t *pci_config, uint8_t val)
+{
+    pci_set_byte(&pci_config[PCI_CLASS_PROG], val);
+}
+
+static inline void
+pci_config_set_interrupt_pin(uint8_t *pci_config, uint8_t val)
+{
+    pci_set_byte(&pci_config[PCI_INTERRUPT_PIN], val);
+}
+
+/*
+ * helper functions to do bit mask operation on configuration space.
+ * Just to set bit, use test-and-set and discard returned value.
+ * Just to clear bit, use test-and-clear and discard returned value.
+ * NOTE: They aren't atomic.
+ */
+static inline uint8_t
+pci_byte_test_and_clear_mask(uint8_t *config, uint8_t mask)
+{
+    uint8_t val = pci_get_byte(config);
+    pci_set_byte(config, val & ~mask);
+    return val & mask;
+}
+
+static inline uint8_t
+pci_byte_test_and_set_mask(uint8_t *config, uint8_t mask)
+{
+    uint8_t val = pci_get_byte(config);
+    pci_set_byte(config, val | mask);
+    return val & mask;
+}
+
+static inline uint16_t
+pci_word_test_and_clear_mask(uint8_t *config, uint16_t mask)
+{
+    uint16_t val = pci_get_word(config);
+    pci_set_word(config, val & ~mask);
+    return val & mask;
+}
+
+static inline uint16_t
+pci_word_test_and_set_mask(uint8_t *config, uint16_t mask)
+{
+    uint16_t val = pci_get_word(config);
+    pci_set_word(config, val | mask);
+    return val & mask;
+}
+
+static inline uint32_t
+pci_long_test_and_clear_mask(uint8_t *config, uint32_t mask)
+{
+    uint32_t val = pci_get_long(config);
+    pci_set_long(config, val & ~mask);
+    return val & mask;
+}
+
+static inline uint32_t
+pci_long_test_and_set_mask(uint8_t *config, uint32_t mask)
+{
+    uint32_t val = pci_get_long(config);
+    pci_set_long(config, val | mask);
+    return val & mask;
+}
+
+static inline uint64_t
+pci_quad_test_and_clear_mask(uint8_t *config, uint64_t mask)
+{
+    uint64_t val = pci_get_quad(config);
+    pci_set_quad(config, val & ~mask);
+    return val & mask;
+}
+
+static inline uint64_t
+pci_quad_test_and_set_mask(uint8_t *config, uint64_t mask)
+{
+    uint64_t val = pci_get_quad(config);
+    pci_set_quad(config, val | mask);
+    return val & mask;
+}
+
+/* Access a register specified by a mask */
+static inline void
+pci_set_byte_by_mask(uint8_t *config, uint8_t mask, uint8_t reg)
+{
+    uint8_t val = pci_get_byte(config);
+    uint8_t rval = reg << (ffs(mask) - 1);
+    pci_set_byte(config, (~mask & val) | (mask & rval));
+}
+
+static inline uint8_t
+pci_get_byte_by_mask(uint8_t *config, uint8_t mask)
+{
+    uint8_t val = pci_get_byte(config);
+    return (val & mask) >> (ffs(mask) - 1);
+}
+
+static inline void
+pci_set_word_by_mask(uint8_t *config, uint16_t mask, uint16_t reg)
+{
+    uint16_t val = pci_get_word(config);
+    uint16_t rval = reg << (ffs(mask) - 1);
+    pci_set_word(config, (~mask & val) | (mask & rval));
+}
+
+static inline uint16_t
+pci_get_word_by_mask(uint8_t *config, uint16_t mask)
+{
+    uint16_t val = pci_get_word(config);
+    return (val & mask) >> (ffs(mask) - 1);
+}
+
+static inline void
+pci_set_long_by_mask(uint8_t *config, uint32_t mask, uint32_t reg)
+{
+    uint32_t val = pci_get_long(config);
+    uint32_t rval = reg << (ffs(mask) - 1);
+    pci_set_long(config, (~mask & val) | (mask & rval));
+}
+
+static inline uint32_t
+pci_get_long_by_mask(uint8_t *config, uint32_t mask)
+{
+    uint32_t val = pci_get_long(config);
+    return (val & mask) >> (ffs(mask) - 1);
+}
+
+static inline void
+pci_set_quad_by_mask(uint8_t *config, uint64_t mask, uint64_t reg)
+{
+    uint64_t val = pci_get_quad(config);
+    uint64_t rval = reg << (ffs(mask) - 1);
+    pci_set_quad(config, (~mask & val) | (mask & rval));
+}
+
+static inline uint64_t
+pci_get_quad_by_mask(uint8_t *config, uint64_t mask)
+{
+    uint64_t val = pci_get_quad(config);
+    return (val & mask) >> (ffs(mask) - 1);
+}
+
+PCIDevice *pci_create_multifunction(PCIBus *bus, int devfn, bool multifunction,
+                                    const char *name);
+PCIDevice *pci_create_simple_multifunction(PCIBus *bus, int devfn,
+                                           bool multifunction,
+                                           const char *name);
+PCIDevice *pci_create(PCIBus *bus, int devfn, const char *name);
+PCIDevice *pci_create_simple(PCIBus *bus, int devfn, const char *name);
+
+static inline int pci_is_express(const PCIDevice *d)
+{
+    return d->cap_present & QEMU_PCI_CAP_EXPRESS;
+}
+
+static inline uint32_t pci_config_size(const PCIDevice *d)
+{
+    return pci_is_express(d) ? PCIE_CONFIG_SPACE_SIZE : PCI_CONFIG_SPACE_SIZE;
+}
+
+/* DMA access functions */
+static inline DMAContext *pci_dma_context(PCIDevice *dev)
+{
+    return dev->dma;
+}
+
+static inline int pci_dma_rw(PCIDevice *dev, dma_addr_t addr,
+                             void *buf, dma_addr_t len, DMADirection dir)
+{
+    dma_memory_rw(pci_dma_context(dev), addr, buf, len, dir);
+    return 0;
+}
+
+static inline int pci_dma_read(PCIDevice *dev, dma_addr_t addr,
+                               void *buf, dma_addr_t len)
+{
+    return pci_dma_rw(dev, addr, buf, len, DMA_DIRECTION_TO_DEVICE);
+}
+
+static inline int pci_dma_write(PCIDevice *dev, dma_addr_t addr,
+                                const void *buf, dma_addr_t len)
+{
+    return pci_dma_rw(dev, addr, (void *) buf, len, DMA_DIRECTION_FROM_DEVICE);
+}
+
+#define PCI_DMA_DEFINE_LDST(_l, _s, _bits)                              \
+    static inline uint##_bits##_t ld##_l##_pci_dma(PCIDevice *dev,      \
+                                                   dma_addr_t addr)     \
+    {                                                                   \
+        return ld##_l##_dma(pci_dma_context(dev), addr);                \
+    }                                                                   \
+    static inline void st##_s##_pci_dma(PCIDevice *dev,                 \
+                                        dma_addr_t addr, uint##_bits##_t val) \
+    {                                                                   \
+        st##_s##_dma(pci_dma_context(dev), addr, val);                  \
+    }
+
+PCI_DMA_DEFINE_LDST(ub, b, 8);
+PCI_DMA_DEFINE_LDST(uw_le, w_le, 16)
+PCI_DMA_DEFINE_LDST(l_le, l_le, 32);
+PCI_DMA_DEFINE_LDST(q_le, q_le, 64);
+PCI_DMA_DEFINE_LDST(uw_be, w_be, 16)
+PCI_DMA_DEFINE_LDST(l_be, l_be, 32);
+PCI_DMA_DEFINE_LDST(q_be, q_be, 64);
+
+#undef PCI_DMA_DEFINE_LDST
+
+static inline void *pci_dma_map(PCIDevice *dev, dma_addr_t addr,
+                                dma_addr_t *plen, DMADirection dir)
+{
+    void *buf;
+
+    buf = dma_memory_map(pci_dma_context(dev), addr, plen, dir);
+    return buf;
+}
+
+static inline void pci_dma_unmap(PCIDevice *dev, void *buffer, dma_addr_t len,
+                                 DMADirection dir, dma_addr_t access_len)
+{
+    dma_memory_unmap(pci_dma_context(dev), buffer, len, dir, access_len);
+}
+
+static inline void pci_dma_sglist_init(QEMUSGList *qsg, PCIDevice *dev,
+                                       int alloc_hint)
+{
+    qemu_sglist_init(qsg, alloc_hint, pci_dma_context(dev));
+}
+
+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/include/hw/pci/pci_bridge.h b/include/hw/pci/pci_bridge.h
new file mode 100644 (file)
index 0000000..1868f7a
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * QEMU PCI bridge
+ *
+ * Copyright (c) 2004 Fabrice Bellard
+ *
+ * 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, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * split out pci bus specific stuff from pci.[hc] to pci_bridge.[hc]
+ * Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp>
+ *                    VA Linux Systems Japan K.K.
+ *
+ */
+
+#ifndef QEMU_PCI_BRIDGE_H
+#define QEMU_PCI_BRIDGE_H
+
+#include "hw/pci/pci.h"
+
+int pci_bridge_ssvid_init(PCIDevice *dev, uint8_t offset,
+                          uint16_t svid, uint16_t ssid);
+
+PCIDevice *pci_bridge_get_device(PCIBus *bus);
+PCIBus *pci_bridge_get_sec_bus(PCIBridge *br);
+
+pcibus_t pci_bridge_get_base(const PCIDevice *bridge, uint8_t type);
+pcibus_t pci_bridge_get_limit(const PCIDevice *bridge, uint8_t type);
+
+void pci_bridge_write_config(PCIDevice *d,
+                             uint32_t address, uint32_t val, int len);
+void pci_bridge_disable_base_limit(PCIDevice *dev);
+void pci_bridge_reset_reg(PCIDevice *dev);
+void pci_bridge_reset(DeviceState *qdev);
+
+int pci_bridge_initfn(PCIDevice *pci_dev, const char *typename);
+void pci_bridge_exitfn(PCIDevice *pci_dev);
+
+
+/*
+ * before qdev initialization(qdev_init()), this function sets bus_name and
+ * map_irq callback which are necessry for pci_bridge_initfn() to
+ * initialize bus.
+ */
+void pci_bridge_map_irq(PCIBridge *br, const char* bus_name,
+                        pci_map_irq_fn map_irq);
+
+/* TODO: add this define to pci_regs.h in linux and then in qemu. */
+#define  PCI_BRIDGE_CTL_VGA_16BIT      0x10    /* VGA 16-bit decode */
+#define  PCI_BRIDGE_CTL_DISCARD                0x100   /* Primary discard timer */
+#define  PCI_BRIDGE_CTL_SEC_DISCARD    0x200   /* Secondary discard timer */
+#define  PCI_BRIDGE_CTL_DISCARD_STATUS 0x400   /* Discard timer status */
+#define  PCI_BRIDGE_CTL_DISCARD_SERR   0x800   /* Discard timer SERR# enable */
+
+#endif  /* QEMU_PCI_BRIDGE_H */
diff --git a/include/hw/pci/pci_bus.h b/include/hw/pci/pci_bus.h
new file mode 100644 (file)
index 0000000..6ee443c
--- /dev/null
@@ -0,0 +1,78 @@
+#ifndef QEMU_PCI_BUS_H
+#define QEMU_PCI_BUS_H
+
+/*
+ * PCI Bus and Bridge datastructures.
+ *
+ * Do not access the following members directly;
+ * use accessor functions in pci.h, pci_bridge.h
+ */
+
+struct PCIBus {
+    BusState qbus;
+    PCIDMAContextFunc dma_context_fn;
+    void *dma_context_opaque;
+    uint8_t devfn_min;
+    pci_set_irq_fn set_irq;
+    pci_map_irq_fn map_irq;
+    pci_route_irq_fn route_intx_to_irq;
+    pci_hotplug_fn hotplug;
+    DeviceState *hotplug_qdev;
+    void *irq_opaque;
+    PCIDevice *devices[PCI_SLOT_MAX * PCI_FUNC_MAX];
+    PCIDevice *parent_dev;
+    MemoryRegion *address_space_mem;
+    MemoryRegion *address_space_io;
+
+    QLIST_HEAD(, PCIBus) child; /* this will be replaced by qdev later */
+    QLIST_ENTRY(PCIBus) sibling;/* this will be replaced by qdev later */
+
+    /* The bus IRQ state is the logical OR of the connected devices.
+       Keep a count of the number of devices with raised IRQs.  */
+    int nirq;
+    int *irq_count;
+};
+
+typedef struct PCIBridgeWindows PCIBridgeWindows;
+
+/*
+ * Aliases for each of the address space windows that the bridge
+ * can forward. Mapped into the bridge's parent's address space,
+ * as subregions.
+ */
+struct PCIBridgeWindows {
+    MemoryRegion alias_pref_mem;
+    MemoryRegion alias_mem;
+    MemoryRegion alias_io;
+    /*
+     * When bridge control VGA forwarding is enabled, bridges will
+     * provide positive decode on the PCI VGA defined I/O port and
+     * MMIO ranges.  When enabled forwarding is only qualified on the
+     * I/O and memory enable bits in the bridge command register.
+     */
+    MemoryRegion alias_vga[QEMU_PCI_VGA_NUM_REGIONS];
+};
+
+struct PCIBridge {
+    PCIDevice dev;
+
+    /* private member */
+    PCIBus sec_bus;
+    /*
+     * Memory regions for the bridge's address spaces.  These regions are not
+     * directly added to system_memory/system_io or its descendants.
+     * Bridge's secondary bus points to these, so that devices
+     * under the bridge see these regions as its address spaces.
+     * The regions are as large as the entire address space -
+     * they don't take into account any windows.
+     */
+    MemoryRegion address_space_mem;
+    MemoryRegion address_space_io;
+
+    PCIBridgeWindows *windows;
+
+    pci_map_irq_fn map_irq;
+    const char *bus_name;
+};
+
+#endif /* QEMU_PCI_BUS_H */
diff --git a/include/hw/pci/pci_host.h b/include/hw/pci/pci_host.h
new file mode 100644 (file)
index 0000000..236cd0f
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * QEMU Common PCI Host bridge configuration data space access routines.
+ *
+ * Copyright (c) 2006 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.
+ */
+
+/* Worker routines for a PCI host controller that uses an {address,data}
+   register pair to access PCI configuration space.  */
+
+#ifndef PCI_HOST_H
+#define PCI_HOST_H
+
+#include "hw/sysbus.h"
+
+#define TYPE_PCI_HOST_BRIDGE "pci-host-bridge"
+#define PCI_HOST_BRIDGE(obj) \
+    OBJECT_CHECK(PCIHostState, (obj), TYPE_PCI_HOST_BRIDGE)
+
+struct PCIHostState {
+    SysBusDevice busdev;
+
+    MemoryRegion conf_mem;
+    MemoryRegion data_mem;
+    MemoryRegion mmcfg;
+    uint32_t config_reg;
+    PCIBus *bus;
+};
+
+/* common internal helpers for PCI/PCIe hosts, cut off overflows */
+void pci_host_config_write_common(PCIDevice *pci_dev, uint32_t addr,
+                                  uint32_t limit, uint32_t val, uint32_t len);
+uint32_t pci_host_config_read_common(PCIDevice *pci_dev, uint32_t addr,
+                                     uint32_t limit, uint32_t len);
+
+void pci_data_write(PCIBus *s, uint32_t addr, uint32_t val, int len);
+uint32_t pci_data_read(PCIBus *s, uint32_t addr, int len);
+
+extern const MemoryRegionOps pci_host_conf_le_ops;
+extern const MemoryRegionOps pci_host_conf_be_ops;
+extern const MemoryRegionOps pci_host_data_le_ops;
+extern const MemoryRegionOps pci_host_data_be_ops;
+
+#endif /* PCI_HOST_H */
diff --git a/include/hw/pci/pci_ids.h b/include/hw/pci/pci_ids.h
new file mode 100644 (file)
index 0000000..d8dc2f1
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ *      PCI Class, Vendor and Device IDs
+ *
+ *      Please keep sorted.
+ *
+ *      Abbreviated version of linux/pci_ids.h
+ *
+ *      QEMU-specific definitions belong in pci.h
+ */
+#ifndef HW_PCI_IDS_H
+#define HW_PCI_IDS_H 1
+
+/* Device classes and subclasses */
+
+#define PCI_BASE_CLASS_STORAGE           0x01
+#define PCI_BASE_CLASS_NETWORK           0x02
+
+#define PCI_CLASS_STORAGE_SCSI           0x0100
+#define PCI_CLASS_STORAGE_IDE            0x0101
+#define PCI_CLASS_STORAGE_RAID           0x0104
+#define PCI_CLASS_STORAGE_SATA           0x0106
+#define PCI_CLASS_STORAGE_OTHER          0x0180
+
+#define PCI_CLASS_NETWORK_ETHERNET       0x0200
+
+#define PCI_CLASS_DISPLAY_VGA            0x0300
+#define PCI_CLASS_DISPLAY_OTHER          0x0380
+
+#define PCI_CLASS_MULTIMEDIA_AUDIO       0x0401
+
+#define PCI_CLASS_MEMORY_RAM             0x0500
+
+#define PCI_CLASS_SYSTEM_OTHER           0x0880
+
+#define PCI_CLASS_SERIAL_USB             0x0c03
+#define PCI_CLASS_SERIAL_SMBUS           0x0c05
+
+#define PCI_CLASS_BRIDGE_HOST            0x0600
+#define PCI_CLASS_BRIDGE_ISA             0x0601
+#define PCI_CLASS_BRIDGE_PCI             0x0604
+#define PCI_CLASS_BRDIGE_PCI_INF_SUB     0x01
+#define PCI_CLASS_BRIDGE_OTHER           0x0680
+
+#define PCI_CLASS_COMMUNICATION_SERIAL   0x0700
+#define PCI_CLASS_COMMUNICATION_OTHER    0x0780
+
+#define PCI_CLASS_PROCESSOR_CO           0x0b40
+#define PCI_CLASS_PROCESSOR_POWERPC      0x0b20
+
+#define PCI_CLASS_OTHERS                 0xff
+
+/* Vendors and devices.  Sort key: vendor first, device next. */
+
+#define PCI_VENDOR_ID_LSI_LOGIC          0x1000
+#define PCI_DEVICE_ID_LSI_53C895A        0x0012
+#define PCI_DEVICE_ID_LSI_SAS1078        0x0060
+
+#define PCI_VENDOR_ID_DEC                0x1011
+#define PCI_DEVICE_ID_DEC_21154          0x0026
+
+#define PCI_VENDOR_ID_CIRRUS             0x1013
+
+#define PCI_VENDOR_ID_IBM                0x1014
+
+#define PCI_VENDOR_ID_AMD                0x1022
+#define PCI_DEVICE_ID_AMD_LANCE          0x2000
+#define PCI_DEVICE_ID_AMD_SCSI           0x2020
+
+#define PCI_VENDOR_ID_TI                 0x104c
+
+#define PCI_VENDOR_ID_MOTOROLA           0x1057
+#define PCI_DEVICE_ID_MOTOROLA_MPC106    0x0002
+#define PCI_DEVICE_ID_MOTOROLA_RAVEN     0x4801
+
+#define PCI_VENDOR_ID_APPLE              0x106b
+#define PCI_DEVICE_ID_APPLE_UNI_N_AGP    0x0020
+#define PCI_DEVICE_ID_APPLE_U3_AGP       0x004b
+
+#define PCI_VENDOR_ID_SUN                0x108e
+#define PCI_DEVICE_ID_SUN_EBUS           0x1000
+#define PCI_DEVICE_ID_SUN_SIMBA          0x5000
+#define PCI_DEVICE_ID_SUN_SABRE          0xa000
+
+#define PCI_VENDOR_ID_CMD                0x1095
+#define PCI_DEVICE_ID_CMD_646            0x0646
+
+#define PCI_VENDOR_ID_REALTEK            0x10ec
+#define PCI_DEVICE_ID_REALTEK_8139       0x8139
+
+#define PCI_VENDOR_ID_XILINX             0x10ee
+
+#define PCI_VENDOR_ID_VIA                0x1106
+#define PCI_DEVICE_ID_VIA_ISA_BRIDGE     0x0686
+#define PCI_DEVICE_ID_VIA_IDE            0x0571
+#define PCI_DEVICE_ID_VIA_UHCI           0x3038
+#define PCI_DEVICE_ID_VIA_ACPI           0x3057
+#define PCI_DEVICE_ID_VIA_AC97           0x3058
+#define PCI_DEVICE_ID_VIA_MC97           0x3068
+
+#define PCI_VENDOR_ID_MARVELL            0x11ab
+
+#define PCI_VENDOR_ID_ENSONIQ            0x1274
+#define PCI_DEVICE_ID_ENSONIQ_ES1370     0x5000
+
+#define PCI_VENDOR_ID_FREESCALE          0x1957
+#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_82801BA_11   0x244e
+#define PCI_DEVICE_ID_INTEL_82801D       0x24CD
+#define PCI_DEVICE_ID_INTEL_ESB_9        0x25ab
+#define PCI_DEVICE_ID_INTEL_82371SB_0    0x7000
+#define PCI_DEVICE_ID_INTEL_82371SB_1    0x7010
+#define PCI_DEVICE_ID_INTEL_82371SB_2    0x7020
+#define PCI_DEVICE_ID_INTEL_82371AB_0    0x7110
+#define PCI_DEVICE_ID_INTEL_82371AB      0x7111
+#define PCI_DEVICE_ID_INTEL_82371AB_2    0x7112
+#define PCI_DEVICE_ID_INTEL_82371AB_3    0x7113
+
+#define PCI_DEVICE_ID_INTEL_ICH9_0       0x2910
+#define PCI_DEVICE_ID_INTEL_ICH9_1       0x2917
+#define PCI_DEVICE_ID_INTEL_ICH9_2       0x2912
+#define PCI_DEVICE_ID_INTEL_ICH9_3       0x2913
+#define PCI_DEVICE_ID_INTEL_ICH9_4       0x2914
+#define PCI_DEVICE_ID_INTEL_ICH9_5       0x2919
+#define PCI_DEVICE_ID_INTEL_ICH9_6       0x2930
+#define PCI_DEVICE_ID_INTEL_ICH9_7       0x2916
+#define PCI_DEVICE_ID_INTEL_ICH9_8       0x2918
+
+#define PCI_DEVICE_ID_INTEL_82801I_UHCI1 0x2934
+#define PCI_DEVICE_ID_INTEL_82801I_UHCI2 0x2935
+#define PCI_DEVICE_ID_INTEL_82801I_UHCI3 0x2936
+#define PCI_DEVICE_ID_INTEL_82801I_UHCI4 0x2937
+#define PCI_DEVICE_ID_INTEL_82801I_UHCI5 0x2938
+#define PCI_DEVICE_ID_INTEL_82801I_UHCI6 0x2939
+#define PCI_DEVICE_ID_INTEL_82801I_EHCI1 0x293a
+#define PCI_DEVICE_ID_INTEL_82801I_EHCI2 0x293c
+#define PCI_DEVICE_ID_INTEL_82599_SFP_VF 0x10ed
+
+#define PCI_DEVICE_ID_INTEL_Q35_MCH      0x29c0
+
+#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
+
+#define PCI_VENDOR_ID_TEWS               0x1498
+#define PCI_DEVICE_ID_TEWS_TPCI200       0x30C8
+
+#endif
diff --git a/include/hw/pci/pci_regs.h b/include/hw/pci/pci_regs.h
new file mode 100644 (file)
index 0000000..56a404b
--- /dev/null
@@ -0,0 +1,717 @@
+/*
+ *     pci_regs.h
+ *
+ *     PCI standard defines
+ *     Copyright 1994, Drew Eckhardt
+ *     Copyright 1997--1999 Martin Mares <mj@ucw.cz>
+ *
+ *     For more information, please consult the following manuals (look at
+ *     http://www.pcisig.com/ for how to get them):
+ *
+ *     PCI BIOS Specification
+ *     PCI Local Bus Specification
+ *     PCI to PCI Bridge Specification
+ *     PCI System Design Guide
+ *
+ *     For hypertransport information, please consult the following manuals
+ *     from http://www.hypertransport.org
+ *
+ *     The Hypertransport I/O Link Specification
+ */
+
+#ifndef LINUX_PCI_REGS_H
+#define LINUX_PCI_REGS_H
+
+/*
+ * Under PCI, each device has 256 bytes of configuration address space,
+ * of which the first 64 bytes are standardized as follows:
+ */
+#define PCI_VENDOR_ID          0x00    /* 16 bits */
+#define PCI_DEVICE_ID          0x02    /* 16 bits */
+#define PCI_COMMAND            0x04    /* 16 bits */
+#define  PCI_COMMAND_IO                0x1     /* Enable response in I/O space */
+#define  PCI_COMMAND_MEMORY    0x2     /* Enable response in Memory space */
+#define  PCI_COMMAND_MASTER    0x4     /* Enable bus mastering */
+#define  PCI_COMMAND_SPECIAL   0x8     /* Enable response to special cycles */
+#define  PCI_COMMAND_INVALIDATE        0x10    /* Use memory write and invalidate */
+#define  PCI_COMMAND_VGA_PALETTE 0x20  /* Enable palette snooping */
+#define  PCI_COMMAND_PARITY    0x40    /* Enable parity checking */
+#define  PCI_COMMAND_WAIT      0x80    /* Enable address/data stepping */
+#define  PCI_COMMAND_SERR      0x100   /* Enable SERR */
+#define  PCI_COMMAND_FAST_BACK 0x200   /* Enable back-to-back writes */
+#define  PCI_COMMAND_INTX_DISABLE 0x400 /* INTx Emulation Disable */
+
+#define PCI_STATUS             0x06    /* 16 bits */
+#define  PCI_STATUS_INTERRUPT  0x08    /* Interrupt status */
+#define  PCI_STATUS_CAP_LIST   0x10    /* Support Capability List */
+#define  PCI_STATUS_66MHZ      0x20    /* Support 66 Mhz PCI 2.1 bus */
+#define  PCI_STATUS_UDF                0x40    /* Support User Definable Features [obsolete] */
+#define  PCI_STATUS_FAST_BACK  0x80    /* Accept fast-back to back */
+#define  PCI_STATUS_PARITY     0x100   /* Detected parity error */
+#define  PCI_STATUS_DEVSEL_MASK        0x600   /* DEVSEL timing */
+#define  PCI_STATUS_DEVSEL_FAST                0x000
+#define  PCI_STATUS_DEVSEL_MEDIUM      0x200
+#define  PCI_STATUS_DEVSEL_SLOW                0x400
+#define  PCI_STATUS_SIG_TARGET_ABORT   0x800 /* Set on target abort */
+#define  PCI_STATUS_REC_TARGET_ABORT   0x1000 /* Master ack of " */
+#define  PCI_STATUS_REC_MASTER_ABORT   0x2000 /* Set on master abort */
+#define  PCI_STATUS_SIG_SYSTEM_ERROR   0x4000 /* Set when we drive SERR */
+#define  PCI_STATUS_DETECTED_PARITY    0x8000 /* Set on parity error */
+
+#define PCI_CLASS_REVISION     0x08    /* High 24 bits are class, low 8 revision */
+#define PCI_REVISION_ID                0x08    /* Revision ID */
+#define PCI_CLASS_PROG         0x09    /* Reg. Level Programming Interface */
+#define PCI_CLASS_DEVICE       0x0a    /* Device class */
+
+#define PCI_CACHE_LINE_SIZE    0x0c    /* 8 bits */
+#define PCI_LATENCY_TIMER      0x0d    /* 8 bits */
+#define PCI_HEADER_TYPE                0x0e    /* 8 bits */
+#define  PCI_HEADER_TYPE_NORMAL                0
+#define  PCI_HEADER_TYPE_BRIDGE                1
+#define  PCI_HEADER_TYPE_CARDBUS       2
+
+#define PCI_BIST               0x0f    /* 8 bits */
+#define  PCI_BIST_CODE_MASK    0x0f    /* Return result */
+#define  PCI_BIST_START                0x40    /* 1 to start BIST, 2 secs or less */
+#define  PCI_BIST_CAPABLE      0x80    /* 1 if BIST capable */
+
+/*
+ * Base addresses specify locations in memory or I/O space.
+ * Decoded size can be determined by writing a value of
+ * 0xffffffff to the register, and reading it back.  Only
+ * 1 bits are decoded.
+ */
+#define PCI_BASE_ADDRESS_0     0x10    /* 32 bits */
+#define PCI_BASE_ADDRESS_1     0x14    /* 32 bits [htype 0,1 only] */
+#define PCI_BASE_ADDRESS_2     0x18    /* 32 bits [htype 0 only] */
+#define PCI_BASE_ADDRESS_3     0x1c    /* 32 bits */
+#define PCI_BASE_ADDRESS_4     0x20    /* 32 bits */
+#define PCI_BASE_ADDRESS_5     0x24    /* 32 bits */
+#define  PCI_BASE_ADDRESS_SPACE                0x01    /* 0 = memory, 1 = I/O */
+#define  PCI_BASE_ADDRESS_SPACE_IO     0x01
+#define  PCI_BASE_ADDRESS_SPACE_MEMORY 0x00
+#define  PCI_BASE_ADDRESS_MEM_TYPE_MASK        0x06
+#define  PCI_BASE_ADDRESS_MEM_TYPE_32  0x00    /* 32 bit address */
+#define  PCI_BASE_ADDRESS_MEM_TYPE_1M  0x02    /* Below 1M [obsolete] */
+#define  PCI_BASE_ADDRESS_MEM_TYPE_64  0x04    /* 64 bit address */
+#define  PCI_BASE_ADDRESS_MEM_PREFETCH 0x08    /* prefetchable? */
+#define  PCI_BASE_ADDRESS_MEM_MASK     (~0x0fUL)
+#define  PCI_BASE_ADDRESS_IO_MASK      (~0x03UL)
+/* bit 1 is reserved if address_space = 1 */
+
+/* Header type 0 (normal devices) */
+#define PCI_CARDBUS_CIS                0x28
+#define PCI_SUBSYSTEM_VENDOR_ID        0x2c
+#define PCI_SUBSYSTEM_ID       0x2e
+#define PCI_ROM_ADDRESS                0x30    /* Bits 31..11 are address, 10..1 reserved */
+#define  PCI_ROM_ADDRESS_ENABLE        0x01
+#define PCI_ROM_ADDRESS_MASK   (~0x7ffUL)
+
+#define PCI_CAPABILITY_LIST    0x34    /* Offset of first capability list entry */
+
+/* 0x35-0x3b are reserved */
+#define PCI_INTERRUPT_LINE     0x3c    /* 8 bits */
+#define PCI_INTERRUPT_PIN      0x3d    /* 8 bits */
+#define PCI_MIN_GNT            0x3e    /* 8 bits */
+#define PCI_MAX_LAT            0x3f    /* 8 bits */
+
+/* Header type 1 (PCI-to-PCI bridges) */
+#define PCI_PRIMARY_BUS                0x18    /* Primary bus number */
+#define PCI_SECONDARY_BUS      0x19    /* Secondary bus number */
+#define PCI_SUBORDINATE_BUS    0x1a    /* Highest bus number behind the bridge */
+#define PCI_SEC_LATENCY_TIMER  0x1b    /* Latency timer for secondary interface */
+#define PCI_IO_BASE            0x1c    /* I/O range behind the bridge */
+#define PCI_IO_LIMIT           0x1d
+#define  PCI_IO_RANGE_TYPE_MASK        0x0fUL  /* I/O bridging type */
+#define  PCI_IO_RANGE_TYPE_16  0x00
+#define  PCI_IO_RANGE_TYPE_32  0x01
+#define  PCI_IO_RANGE_MASK     (~0x0fUL)
+#define PCI_SEC_STATUS         0x1e    /* Secondary status register, only bit 14 used */
+#define PCI_MEMORY_BASE                0x20    /* Memory range behind */
+#define PCI_MEMORY_LIMIT       0x22
+#define  PCI_MEMORY_RANGE_TYPE_MASK 0x0fUL
+#define  PCI_MEMORY_RANGE_MASK (~0x0fUL)
+#define PCI_PREF_MEMORY_BASE   0x24    /* Prefetchable memory range behind */
+#define PCI_PREF_MEMORY_LIMIT  0x26
+#define  PCI_PREF_RANGE_TYPE_MASK 0x0fUL
+#define  PCI_PREF_RANGE_TYPE_32        0x00
+#define  PCI_PREF_RANGE_TYPE_64        0x01
+#define  PCI_PREF_RANGE_MASK   (~0x0fUL)
+#define PCI_PREF_BASE_UPPER32  0x28    /* Upper half of prefetchable memory range */
+#define PCI_PREF_LIMIT_UPPER32 0x2c
+#define PCI_IO_BASE_UPPER16    0x30    /* Upper half of I/O addresses */
+#define PCI_IO_LIMIT_UPPER16   0x32
+/* 0x34 same as for htype 0 */
+/* 0x35-0x3b is reserved */
+#define PCI_ROM_ADDRESS1       0x38    /* Same as PCI_ROM_ADDRESS, but for htype 1 */
+/* 0x3c-0x3d are same as for htype 0 */
+#define PCI_BRIDGE_CONTROL     0x3e
+#define  PCI_BRIDGE_CTL_PARITY 0x01    /* Enable parity detection on secondary interface */
+#define  PCI_BRIDGE_CTL_SERR   0x02    /* The same for SERR forwarding */
+#define  PCI_BRIDGE_CTL_ISA    0x04    /* Enable ISA mode */
+#define  PCI_BRIDGE_CTL_VGA    0x08    /* Forward VGA addresses */
+#define  PCI_BRIDGE_CTL_MASTER_ABORT   0x20  /* Report master aborts */
+#define  PCI_BRIDGE_CTL_BUS_RESET      0x40    /* Secondary bus reset */
+#define  PCI_BRIDGE_CTL_FAST_BACK      0x80    /* Fast Back2Back enabled on secondary interface */
+
+/* Header type 2 (CardBus bridges) */
+#define PCI_CB_CAPABILITY_LIST 0x14
+/* 0x15 reserved */
+#define PCI_CB_SEC_STATUS      0x16    /* Secondary status */
+#define PCI_CB_PRIMARY_BUS     0x18    /* PCI bus number */
+#define PCI_CB_CARD_BUS                0x19    /* CardBus bus number */
+#define PCI_CB_SUBORDINATE_BUS 0x1a    /* Subordinate bus number */
+#define PCI_CB_LATENCY_TIMER   0x1b    /* CardBus latency timer */
+#define PCI_CB_MEMORY_BASE_0   0x1c
+#define PCI_CB_MEMORY_LIMIT_0  0x20
+#define PCI_CB_MEMORY_BASE_1   0x24
+#define PCI_CB_MEMORY_LIMIT_1  0x28
+#define PCI_CB_IO_BASE_0       0x2c
+#define PCI_CB_IO_BASE_0_HI    0x2e
+#define PCI_CB_IO_LIMIT_0      0x30
+#define PCI_CB_IO_LIMIT_0_HI   0x32
+#define PCI_CB_IO_BASE_1       0x34
+#define PCI_CB_IO_BASE_1_HI    0x36
+#define PCI_CB_IO_LIMIT_1      0x38
+#define PCI_CB_IO_LIMIT_1_HI   0x3a
+#define  PCI_CB_IO_RANGE_MASK  (~0x03UL)
+/* 0x3c-0x3d are same as for htype 0 */
+#define PCI_CB_BRIDGE_CONTROL  0x3e
+#define  PCI_CB_BRIDGE_CTL_PARITY      0x01    /* Similar to standard bridge control register */
+#define  PCI_CB_BRIDGE_CTL_SERR                0x02
+#define  PCI_CB_BRIDGE_CTL_ISA         0x04
+#define  PCI_CB_BRIDGE_CTL_VGA         0x08
+#define  PCI_CB_BRIDGE_CTL_MASTER_ABORT        0x20
+#define  PCI_CB_BRIDGE_CTL_CB_RESET    0x40    /* CardBus reset */
+#define  PCI_CB_BRIDGE_CTL_16BIT_INT   0x80    /* Enable interrupt for 16-bit cards */
+#define  PCI_CB_BRIDGE_CTL_PREFETCH_MEM0 0x100 /* Prefetch enable for both memory regions */
+#define  PCI_CB_BRIDGE_CTL_PREFETCH_MEM1 0x200
+#define  PCI_CB_BRIDGE_CTL_POST_WRITES 0x400
+#define PCI_CB_SUBSYSTEM_VENDOR_ID     0x40
+#define PCI_CB_SUBSYSTEM_ID            0x42
+#define PCI_CB_LEGACY_MODE_BASE                0x44    /* 16-bit PC Card legacy mode base address (ExCa) */
+/* 0x48-0x7f reserved */
+
+/* Capability lists */
+
+#define PCI_CAP_LIST_ID                0       /* Capability ID */
+#define  PCI_CAP_ID_PM         0x01    /* Power Management */
+#define  PCI_CAP_ID_AGP                0x02    /* Accelerated Graphics Port */
+#define  PCI_CAP_ID_VPD                0x03    /* Vital Product Data */
+#define  PCI_CAP_ID_SLOTID     0x04    /* Slot Identification */
+#define  PCI_CAP_ID_MSI                0x05    /* Message Signalled Interrupts */
+#define  PCI_CAP_ID_CHSWP      0x06    /* CompactPCI HotSwap */
+#define  PCI_CAP_ID_PCIX       0x07    /* PCI-X */
+#define  PCI_CAP_ID_HT         0x08    /* HyperTransport */
+#define  PCI_CAP_ID_VNDR       0x09    /* Vendor specific */
+#define  PCI_CAP_ID_DBG                0x0A    /* Debug port */
+#define  PCI_CAP_ID_CCRC       0x0B    /* CompactPCI Central Resource Control */
+#define  PCI_CAP_ID_SHPC       0x0C    /* PCI Standard Hot-Plug Controller */
+#define  PCI_CAP_ID_SSVID      0x0D    /* Bridge subsystem vendor/device ID */
+#define  PCI_CAP_ID_AGP3       0x0E    /* AGP Target PCI-PCI bridge */
+#define  PCI_CAP_ID_EXP        0x10    /* PCI Express */
+#define  PCI_CAP_ID_MSIX       0x11    /* MSI-X */
+#define  PCI_CAP_ID_SATA       0x12    /* Serial ATA */
+#define  PCI_CAP_ID_AF         0x13    /* PCI Advanced Features */
+#define PCI_CAP_LIST_NEXT      1       /* Next capability in the list */
+#define PCI_CAP_FLAGS          2       /* Capability defined flags (16 bits) */
+#define PCI_CAP_SIZEOF         4
+
+/* Power Management Registers */
+
+#define PCI_PM_PMC             2       /* PM Capabilities Register */
+#define  PCI_PM_CAP_VER_MASK   0x0007  /* Version */
+#define  PCI_PM_CAP_PME_CLOCK  0x0008  /* PME clock required */
+#define  PCI_PM_CAP_RESERVED    0x0010  /* Reserved field */
+#define  PCI_PM_CAP_DSI                0x0020  /* Device specific initialization */
+#define  PCI_PM_CAP_AUX_POWER  0x01C0  /* Auxiliary power support mask */
+#define  PCI_PM_CAP_D1         0x0200  /* D1 power state support */
+#define  PCI_PM_CAP_D2         0x0400  /* D2 power state support */
+#define  PCI_PM_CAP_PME                0x0800  /* PME pin supported */
+#define  PCI_PM_CAP_PME_MASK   0xF800  /* PME Mask of all supported states */
+#define  PCI_PM_CAP_PME_D0     0x0800  /* PME# from D0 */
+#define  PCI_PM_CAP_PME_D1     0x1000  /* PME# from D1 */
+#define  PCI_PM_CAP_PME_D2     0x2000  /* PME# from D2 */
+#define  PCI_PM_CAP_PME_D3     0x4000  /* PME# from D3 (hot) */
+#define  PCI_PM_CAP_PME_D3cold 0x8000  /* PME# from D3 (cold) */
+#define  PCI_PM_CAP_PME_SHIFT  11      /* Start of the PME Mask in PMC */
+#define PCI_PM_CTRL            4       /* PM control and status register */
+#define  PCI_PM_CTRL_STATE_MASK        0x0003  /* Current power state (D0 to D3) */
+#define  PCI_PM_CTRL_NO_SOFT_RESET     0x0008  /* No reset for D3hot->D0 */
+#define  PCI_PM_CTRL_PME_ENABLE        0x0100  /* PME pin enable */
+#define  PCI_PM_CTRL_DATA_SEL_MASK     0x1e00  /* Data select (??) */
+#define  PCI_PM_CTRL_DATA_SCALE_MASK   0x6000  /* Data scale (??) */
+#define  PCI_PM_CTRL_PME_STATUS        0x8000  /* PME pin status */
+#define PCI_PM_PPB_EXTENSIONS  6       /* PPB support extensions (??) */
+#define  PCI_PM_PPB_B2_B3      0x40    /* Stop clock when in D3hot (??) */
+#define  PCI_PM_BPCC_ENABLE    0x80    /* Bus power/clock control enable (??) */
+#define PCI_PM_DATA_REGISTER   7       /* (??) */
+#define PCI_PM_SIZEOF          8
+
+/* AGP registers */
+
+#define PCI_AGP_VERSION                2       /* BCD version number */
+#define PCI_AGP_RFU            3       /* Rest of capability flags */
+#define PCI_AGP_STATUS         4       /* Status register */
+#define  PCI_AGP_STATUS_RQ_MASK        0xff000000      /* Maximum number of requests - 1 */
+#define  PCI_AGP_STATUS_SBA    0x0200  /* Sideband addressing supported */
+#define  PCI_AGP_STATUS_64BIT  0x0020  /* 64-bit addressing supported */
+#define  PCI_AGP_STATUS_FW     0x0010  /* FW transfers supported */
+#define  PCI_AGP_STATUS_RATE4  0x0004  /* 4x transfer rate supported */
+#define  PCI_AGP_STATUS_RATE2  0x0002  /* 2x transfer rate supported */
+#define  PCI_AGP_STATUS_RATE1  0x0001  /* 1x transfer rate supported */
+#define PCI_AGP_COMMAND                8       /* Control register */
+#define  PCI_AGP_COMMAND_RQ_MASK 0xff000000  /* Master: Maximum number of requests */
+#define  PCI_AGP_COMMAND_SBA   0x0200  /* Sideband addressing enabled */
+#define  PCI_AGP_COMMAND_AGP   0x0100  /* Allow processing of AGP transactions */
+#define  PCI_AGP_COMMAND_64BIT 0x0020  /* Allow processing of 64-bit addresses */
+#define  PCI_AGP_COMMAND_FW    0x0010  /* Force FW transfers */
+#define  PCI_AGP_COMMAND_RATE4 0x0004  /* Use 4x rate */
+#define  PCI_AGP_COMMAND_RATE2 0x0002  /* Use 2x rate */
+#define  PCI_AGP_COMMAND_RATE1 0x0001  /* Use 1x rate */
+#define PCI_AGP_SIZEOF         12
+
+/* Vital Product Data */
+
+#define PCI_VPD_ADDR           2       /* Address to access (15 bits!) */
+#define  PCI_VPD_ADDR_MASK     0x7fff  /* Address mask */
+#define  PCI_VPD_ADDR_F                0x8000  /* Write 0, 1 indicates completion */
+#define PCI_VPD_DATA           4       /* 32-bits of data returned here */
+
+/* Slot Identification */
+
+#define PCI_SID_ESR            2       /* Expansion Slot Register */
+#define  PCI_SID_ESR_NSLOTS    0x1f    /* Number of expansion slots available */
+#define  PCI_SID_ESR_FIC       0x20    /* First In Chassis Flag */
+#define PCI_SID_CHASSIS_NR     3       /* Chassis Number */
+
+/* Message Signalled Interrupts registers */
+
+#define PCI_MSI_FLAGS          2       /* Various flags */
+#define  PCI_MSI_FLAGS_64BIT   0x80    /* 64-bit addresses allowed */
+#define  PCI_MSI_FLAGS_QSIZE   0x70    /* Message queue size configured */
+#define  PCI_MSI_FLAGS_QMASK   0x0e    /* Maximum queue size available */
+#define  PCI_MSI_FLAGS_ENABLE  0x01    /* MSI feature enabled */
+#define  PCI_MSI_FLAGS_MASKBIT 0x100   /* 64-bit mask bits allowed */
+#define PCI_MSI_RFU            3       /* Rest of capability flags */
+#define PCI_MSI_ADDRESS_LO     4       /* Lower 32 bits */
+#define PCI_MSI_ADDRESS_HI     8       /* Upper 32 bits (if PCI_MSI_FLAGS_64BIT set) */
+#define PCI_MSI_DATA_32                8       /* 16 bits of data for 32-bit devices */
+#define PCI_MSI_MASK_32                12      /* Mask bits register for 32-bit devices */
+#define PCI_MSI_DATA_64                12      /* 16 bits of data for 64-bit devices */
+#define PCI_MSI_MASK_64                16      /* Mask bits register for 64-bit devices */
+
+/* MSI-X registers */
+#define PCI_MSIX_FLAGS         2
+#define  PCI_MSIX_FLAGS_QSIZE  0x7FF
+#define  PCI_MSIX_FLAGS_ENABLE (1 << 15)
+#define  PCI_MSIX_FLAGS_MASKALL        (1 << 14)
+#define PCI_MSIX_TABLE         4
+#define PCI_MSIX_PBA           8
+#define  PCI_MSIX_FLAGS_BIRMASK        (7 << 0)
+
+/* MSI-X entry's format */
+#define PCI_MSIX_ENTRY_SIZE            16
+#define  PCI_MSIX_ENTRY_LOWER_ADDR     0
+#define  PCI_MSIX_ENTRY_UPPER_ADDR     4
+#define  PCI_MSIX_ENTRY_DATA           8
+#define  PCI_MSIX_ENTRY_VECTOR_CTRL    12
+#define   PCI_MSIX_ENTRY_CTRL_MASKBIT  1
+
+/* CompactPCI Hotswap Register */
+
+#define PCI_CHSWP_CSR          2       /* Control and Status Register */
+#define  PCI_CHSWP_DHA         0x01    /* Device Hiding Arm */
+#define  PCI_CHSWP_EIM         0x02    /* ENUM# Signal Mask */
+#define  PCI_CHSWP_PIE         0x04    /* Pending Insert or Extract */
+#define  PCI_CHSWP_LOO         0x08    /* LED On / Off */
+#define  PCI_CHSWP_PI          0x30    /* Programming Interface */
+#define  PCI_CHSWP_EXT         0x40    /* ENUM# status - extraction */
+#define  PCI_CHSWP_INS         0x80    /* ENUM# status - insertion */
+
+/* PCI Advanced Feature registers */
+
+#define PCI_AF_LENGTH          2
+#define PCI_AF_CAP             3
+#define  PCI_AF_CAP_TP         0x01
+#define  PCI_AF_CAP_FLR                0x02
+#define PCI_AF_CTRL            4
+#define  PCI_AF_CTRL_FLR       0x01
+#define PCI_AF_STATUS          5
+#define  PCI_AF_STATUS_TP      0x01
+
+/* PCI-X registers */
+
+#define PCI_X_CMD              2       /* Modes & Features */
+#define  PCI_X_CMD_DPERR_E     0x0001  /* Data Parity Error Recovery Enable */
+#define  PCI_X_CMD_ERO         0x0002  /* Enable Relaxed Ordering */
+#define  PCI_X_CMD_READ_512    0x0000  /* 512 byte maximum read byte count */
+#define  PCI_X_CMD_READ_1K     0x0004  /* 1Kbyte maximum read byte count */
+#define  PCI_X_CMD_READ_2K     0x0008  /* 2Kbyte maximum read byte count */
+#define  PCI_X_CMD_READ_4K     0x000c  /* 4Kbyte maximum read byte count */
+#define  PCI_X_CMD_MAX_READ    0x000c  /* Max Memory Read Byte Count */
+                               /* Max # of outstanding split transactions */
+#define  PCI_X_CMD_SPLIT_1     0x0000  /* Max 1 */
+#define  PCI_X_CMD_SPLIT_2     0x0010  /* Max 2 */
+#define  PCI_X_CMD_SPLIT_3     0x0020  /* Max 3 */
+#define  PCI_X_CMD_SPLIT_4     0x0030  /* Max 4 */
+#define  PCI_X_CMD_SPLIT_8     0x0040  /* Max 8 */
+#define  PCI_X_CMD_SPLIT_12    0x0050  /* Max 12 */
+#define  PCI_X_CMD_SPLIT_16    0x0060  /* Max 16 */
+#define  PCI_X_CMD_SPLIT_32    0x0070  /* Max 32 */
+#define  PCI_X_CMD_MAX_SPLIT   0x0070  /* Max Outstanding Split Transactions */
+#define  PCI_X_CMD_VERSION(x)  (((x) >> 12) & 3) /* Version */
+#define PCI_X_STATUS           4       /* PCI-X capabilities */
+#define  PCI_X_STATUS_DEVFN    0x000000ff      /* A copy of devfn */
+#define  PCI_X_STATUS_BUS      0x0000ff00      /* A copy of bus nr */
+#define  PCI_X_STATUS_64BIT    0x00010000      /* 64-bit device */
+#define  PCI_X_STATUS_133MHZ   0x00020000      /* 133 MHz capable */
+#define  PCI_X_STATUS_SPL_DISC 0x00040000      /* Split Completion Discarded */
+#define  PCI_X_STATUS_UNX_SPL  0x00080000      /* Unexpected Split Completion */
+#define  PCI_X_STATUS_COMPLEX  0x00100000      /* Device Complexity */
+#define  PCI_X_STATUS_MAX_READ 0x00600000      /* Designed Max Memory Read Count */
+#define  PCI_X_STATUS_MAX_SPLIT        0x03800000      /* Designed Max Outstanding Split Transactions */
+#define  PCI_X_STATUS_MAX_CUM  0x1c000000      /* Designed Max Cumulative Read Size */
+#define  PCI_X_STATUS_SPL_ERR  0x20000000      /* Rcvd Split Completion Error Msg */
+#define  PCI_X_STATUS_266MHZ   0x40000000      /* 266 MHz capable */
+#define  PCI_X_STATUS_533MHZ   0x80000000      /* 533 MHz capable */
+
+/* PCI Bridge Subsystem ID registers */
+
+#define PCI_SSVID_VENDOR_ID     4      /* PCI-Bridge subsystem vendor id register */
+#define PCI_SSVID_DEVICE_ID     6      /* PCI-Bridge subsystem device id register */
+
+/* PCI Express capability registers */
+
+#define PCI_EXP_FLAGS          2       /* Capabilities register */
+#define PCI_EXP_FLAGS_VERS     0x000f  /* Capability version */
+#define PCI_EXP_FLAGS_TYPE     0x00f0  /* Device/Port type */
+#define  PCI_EXP_TYPE_ENDPOINT 0x0     /* Express Endpoint */
+#define  PCI_EXP_TYPE_LEG_END  0x1     /* Legacy Endpoint */
+#define  PCI_EXP_TYPE_ROOT_PORT 0x4    /* Root Port */
+#define  PCI_EXP_TYPE_UPSTREAM 0x5     /* Upstream Port */
+#define  PCI_EXP_TYPE_DOWNSTREAM 0x6   /* Downstream Port */
+#define  PCI_EXP_TYPE_PCI_BRIDGE 0x7   /* PCI/PCI-X Bridge */
+#define  PCI_EXP_TYPE_PCIE_BRIDGE 0x8   /* PCI/PCI-X to PCIE Bridge */
+#define  PCI_EXP_TYPE_RC_END   0x9     /* Root Complex Integrated Endpoint */
+#define  PCI_EXP_TYPE_RC_EC     0xa     /* Root Complex Event Collector */
+#define PCI_EXP_FLAGS_SLOT     0x0100  /* Slot implemented */
+#define PCI_EXP_FLAGS_IRQ      0x3e00  /* Interrupt message number */
+#define PCI_EXP_DEVCAP         4       /* Device capabilities */
+#define  PCI_EXP_DEVCAP_PAYLOAD        0x07    /* Max_Payload_Size */
+#define  PCI_EXP_DEVCAP_PHANTOM        0x18    /* Phantom functions */
+#define  PCI_EXP_DEVCAP_EXT_TAG        0x20    /* Extended tags */
+#define  PCI_EXP_DEVCAP_L0S    0x1c0   /* L0s Acceptable Latency */
+#define  PCI_EXP_DEVCAP_L1     0xe00   /* L1 Acceptable Latency */
+#define  PCI_EXP_DEVCAP_ATN_BUT        0x1000  /* Attention Button Present */
+#define  PCI_EXP_DEVCAP_ATN_IND        0x2000  /* Attention Indicator Present */
+#define  PCI_EXP_DEVCAP_PWR_IND        0x4000  /* Power Indicator Present */
+#define  PCI_EXP_DEVCAP_RBER   0x8000  /* Role-Based Error Reporting */
+#define  PCI_EXP_DEVCAP_PWR_VAL        0x3fc0000 /* Slot Power Limit Value */
+#define  PCI_EXP_DEVCAP_PWR_SCL        0xc000000 /* Slot Power Limit Scale */
+#define  PCI_EXP_DEVCAP_FLR     0x10000000 /* Function Level Reset */
+#define PCI_EXP_DEVCTL         8       /* Device Control */
+#define  PCI_EXP_DEVCTL_CERE   0x0001  /* Correctable Error Reporting En. */
+#define  PCI_EXP_DEVCTL_NFERE  0x0002  /* Non-Fatal Error Reporting Enable */
+#define  PCI_EXP_DEVCTL_FERE   0x0004  /* Fatal Error Reporting Enable */
+#define  PCI_EXP_DEVCTL_URRE   0x0008  /* Unsupported Request Reporting En. */
+#define  PCI_EXP_DEVCTL_RELAX_EN 0x0010 /* Enable relaxed ordering */
+#define  PCI_EXP_DEVCTL_PAYLOAD        0x00e0  /* Max_Payload_Size */
+#define  PCI_EXP_DEVCTL_EXT_TAG        0x0100  /* Extended Tag Field Enable */
+#define  PCI_EXP_DEVCTL_PHANTOM        0x0200  /* Phantom Functions Enable */
+#define  PCI_EXP_DEVCTL_AUX_PME        0x0400  /* Auxiliary Power PM Enable */
+#define  PCI_EXP_DEVCTL_NOSNOOP_EN 0x0800  /* Enable No Snoop */
+#define  PCI_EXP_DEVCTL_READRQ 0x7000  /* Max_Read_Request_Size */
+#define  PCI_EXP_DEVCTL_BCR_FLR 0x8000  /* Bridge Configuration Retry / FLR */
+#define PCI_EXP_DEVSTA         10      /* Device Status */
+#define  PCI_EXP_DEVSTA_CED    0x01    /* Correctable Error Detected */
+#define  PCI_EXP_DEVSTA_NFED   0x02    /* Non-Fatal Error Detected */
+#define  PCI_EXP_DEVSTA_FED    0x04    /* Fatal Error Detected */
+#define  PCI_EXP_DEVSTA_URD    0x08    /* Unsupported Request Detected */
+#define  PCI_EXP_DEVSTA_AUXPD  0x10    /* AUX Power Detected */
+#define  PCI_EXP_DEVSTA_TRPND  0x20    /* Transactions Pending */
+#define PCI_EXP_LNKCAP         12      /* Link Capabilities */
+#define  PCI_EXP_LNKCAP_SLS    0x0000000f /* Supported Link Speeds */
+#define  PCI_EXP_LNKCAP_MLW    0x000003f0 /* Maximum Link Width */
+#define  PCI_EXP_LNKCAP_ASPMS  0x00000c00 /* ASPM Support */
+#define  PCI_EXP_LNKCAP_L0SEL  0x00007000 /* L0s Exit Latency */
+#define  PCI_EXP_LNKCAP_L1EL   0x00038000 /* L1 Exit Latency */
+#define  PCI_EXP_LNKCAP_CLKPM  0x00040000 /* L1 Clock Power Management */
+#define  PCI_EXP_LNKCAP_SDERC  0x00080000 /* Surprise Down Error Reporting Capable */
+#define  PCI_EXP_LNKCAP_DLLLARC        0x00100000 /* Data Link Layer Link Active Reporting Capable */
+#define  PCI_EXP_LNKCAP_LBNC   0x00200000 /* Link Bandwidth Notification Capability */
+#define  PCI_EXP_LNKCAP_PN     0xff000000 /* Port Number */
+#define PCI_EXP_LNKCTL         16      /* Link Control */
+#define  PCI_EXP_LNKCTL_ASPMC  0x0003  /* ASPM Control */
+#define  PCI_EXP_LNKCTL_RCB    0x0008  /* Read Completion Boundary */
+#define  PCI_EXP_LNKCTL_LD     0x0010  /* Link Disable */
+#define  PCI_EXP_LNKCTL_RL     0x0020  /* Retrain Link */
+#define  PCI_EXP_LNKCTL_CCC    0x0040  /* Common Clock Configuration */
+#define  PCI_EXP_LNKCTL_ES     0x0080  /* Extended Synch */
+#define  PCI_EXP_LNKCTL_CLKREQ_EN 0x100        /* Enable clkreq */
+#define  PCI_EXP_LNKCTL_HAWD   0x0200  /* Hardware Autonomous Width Disable */
+#define  PCI_EXP_LNKCTL_LBMIE  0x0400  /* Link Bandwidth Management Interrupt Enable */
+#define  PCI_EXP_LNKCTL_LABIE  0x0800  /* Lnk Autonomous Bandwidth Interrupt Enable */
+#define PCI_EXP_LNKSTA         18      /* Link Status */
+#define  PCI_EXP_LNKSTA_CLS    0x000f  /* Current Link Speed */
+#define  PCI_EXP_LNKSTA_CLS_2_5GB 0x01 /* Current Link Speed 2.5GT/s */
+#define  PCI_EXP_LNKSTA_CLS_5_0GB 0x02 /* Current Link Speed 5.0GT/s */
+#define  PCI_EXP_LNKSTA_NLW    0x03f0  /* Nogotiated Link Width */
+#define  PCI_EXP_LNKSTA_NLW_SHIFT 4    /* start of NLW mask in link status */
+#define  PCI_EXP_LNKSTA_LT     0x0800  /* Link Training */
+#define  PCI_EXP_LNKSTA_SLC    0x1000  /* Slot Clock Configuration */
+#define  PCI_EXP_LNKSTA_DLLLA  0x2000  /* Data Link Layer Link Active */
+#define  PCI_EXP_LNKSTA_LBMS   0x4000  /* Link Bandwidth Management Status */
+#define  PCI_EXP_LNKSTA_LABS   0x8000  /* Link Autonomous Bandwidth Status */
+#define PCI_EXP_SLTCAP         20      /* Slot Capabilities */
+#define  PCI_EXP_SLTCAP_ABP    0x00000001 /* Attention Button Present */
+#define  PCI_EXP_SLTCAP_PCP    0x00000002 /* Power Controller Present */
+#define  PCI_EXP_SLTCAP_MRLSP  0x00000004 /* MRL Sensor Present */
+#define  PCI_EXP_SLTCAP_AIP    0x00000008 /* Attention Indicator Present */
+#define  PCI_EXP_SLTCAP_PIP    0x00000010 /* Power Indicator Present */
+#define  PCI_EXP_SLTCAP_HPS    0x00000020 /* Hot-Plug Surprise */
+#define  PCI_EXP_SLTCAP_HPC    0x00000040 /* Hot-Plug Capable */
+#define  PCI_EXP_SLTCAP_SPLV   0x00007f80 /* Slot Power Limit Value */
+#define  PCI_EXP_SLTCAP_SPLS   0x00018000 /* Slot Power Limit Scale */
+#define  PCI_EXP_SLTCAP_EIP    0x00020000 /* Electromechanical Interlock Present */
+#define  PCI_EXP_SLTCAP_NCCS   0x00040000 /* No Command Completed Support */
+#define  PCI_EXP_SLTCAP_PSN    0xfff80000 /* Physical Slot Number */
+#define PCI_EXP_SLTCTL         24      /* Slot Control */
+#define  PCI_EXP_SLTCTL_ABPE   0x0001  /* Attention Button Pressed Enable */
+#define  PCI_EXP_SLTCTL_PFDE   0x0002  /* Power Fault Detected Enable */
+#define  PCI_EXP_SLTCTL_MRLSCE 0x0004  /* MRL Sensor Changed Enable */
+#define  PCI_EXP_SLTCTL_PDCE   0x0008  /* Presence Detect Changed Enable */
+#define  PCI_EXP_SLTCTL_CCIE   0x0010  /* Command Completed Interrupt Enable */
+#define  PCI_EXP_SLTCTL_HPIE   0x0020  /* Hot-Plug Interrupt Enable */
+#define  PCI_EXP_SLTCTL_AIC    0x00c0  /* Attention Indicator Control */
+#define  PCI_EXP_SLTCTL_PIC    0x0300  /* Power Indicator Control */
+#define  PCI_EXP_SLTCTL_PCC    0x0400  /* Power Controller Control */
+#define  PCI_EXP_SLTCTL_EIC    0x0800  /* Electromechanical Interlock Control */
+#define  PCI_EXP_SLTCTL_DLLSCE 0x1000  /* Data Link Layer State Changed Enable */
+#define PCI_EXP_SLTSTA         26      /* Slot Status */
+#define  PCI_EXP_SLTSTA_ABP    0x0001  /* Attention Button Pressed */
+#define  PCI_EXP_SLTSTA_PFD    0x0002  /* Power Fault Detected */
+#define  PCI_EXP_SLTSTA_MRLSC  0x0004  /* MRL Sensor Changed */
+#define  PCI_EXP_SLTSTA_PDC    0x0008  /* Presence Detect Changed */
+#define  PCI_EXP_SLTSTA_CC     0x0010  /* Command Completed */
+#define  PCI_EXP_SLTSTA_MRLSS  0x0020  /* MRL Sensor State */
+#define  PCI_EXP_SLTSTA_PDS    0x0040  /* Presence Detect State */
+#define  PCI_EXP_SLTSTA_EIS    0x0080  /* Electromechanical Interlock Status */
+#define  PCI_EXP_SLTSTA_DLLSC  0x0100  /* Data Link Layer State Changed */
+#define PCI_EXP_RTCTL          28      /* Root Control */
+#define  PCI_EXP_RTCTL_SECEE   0x01    /* System Error on Correctable Error */
+#define  PCI_EXP_RTCTL_SENFEE  0x02    /* System Error on Non-Fatal Error */
+#define  PCI_EXP_RTCTL_SEFEE   0x04    /* System Error on Fatal Error */
+#define  PCI_EXP_RTCTL_PMEIE   0x08    /* PME Interrupt Enable */
+#define  PCI_EXP_RTCTL_CRSSVE  0x10    /* CRS Software Visibility Enable */
+#define PCI_EXP_RTCAP          30      /* Root Capabilities */
+#define PCI_EXP_RTSTA          32      /* Root Status */
+#define PCI_EXP_RTSTA_PME      0x10000 /* PME status */
+#define PCI_EXP_RTSTA_PENDING  0x20000 /* PME pending */
+#define PCI_EXP_DEVCAP2                36      /* Device Capabilities 2 */
+#define  PCI_EXP_DEVCAP2_ARI   0x20    /* Alternative Routing-ID */
+#define  PCI_EXP_DEVCAP2_LTR   0x800   /* Latency tolerance reporting */
+#define  PCI_EXP_OBFF_MASK     0xc0000 /* OBFF support mechanism */
+#define  PCI_EXP_OBFF_MSG      0x40000 /* New message signaling */
+#define  PCI_EXP_OBFF_WAKE     0x80000 /* Re-use WAKE# for OBFF */
+#define PCI_EXP_DEVCTL2                40      /* Device Control 2 */
+#define  PCI_EXP_DEVCTL2_ARI   0x20    /* Alternative Routing-ID */
+#define  PCI_EXP_IDO_REQ_EN    0x100   /* ID-based ordering request enable */
+#define  PCI_EXP_IDO_CMP_EN    0x200   /* ID-based ordering completion enable */
+#define  PCI_EXP_LTR_EN                0x400   /* Latency tolerance reporting */
+#define  PCI_EXP_OBFF_MSGA_EN  0x2000  /* OBFF enable with Message type A */
+#define  PCI_EXP_OBFF_MSGB_EN  0x4000  /* OBFF enable with Message type B */
+#define  PCI_EXP_OBFF_WAKE_EN  0x6000  /* OBFF using WAKE# signaling */
+#define PCI_EXP_LNKCTL2                48      /* Link Control 2 */
+#define PCI_EXP_SLTCTL2                56      /* Slot Control 2 */
+
+/* Extended Capabilities (PCI-X 2.0 and Express) */
+#define PCI_EXT_CAP_ID(header)         (header & 0x0000ffff)
+#define PCI_EXT_CAP_VER(header)                ((header >> 16) & 0xf)
+#define PCI_EXT_CAP_NEXT(header)       ((header >> 20) & 0xffc)
+
+#define PCI_EXT_CAP_ID_ERR     1
+#define PCI_EXT_CAP_ID_VC      2
+#define PCI_EXT_CAP_ID_DSN     3
+#define PCI_EXT_CAP_ID_PWR     4
+#define PCI_EXT_CAP_ID_VNDR    11
+#define PCI_EXT_CAP_ID_ACS     13
+#define PCI_EXT_CAP_ID_ARI     14
+#define PCI_EXT_CAP_ID_ATS     15
+#define PCI_EXT_CAP_ID_SRIOV   16
+#define PCI_EXT_CAP_ID_LTR     24
+
+/* Advanced Error Reporting */
+#define PCI_ERR_UNCOR_STATUS   4       /* Uncorrectable Error Status */
+#define  PCI_ERR_UNC_TRAIN     0x00000001      /* Training */
+#define  PCI_ERR_UNC_DLP       0x00000010      /* Data Link Protocol */
+#define  PCI_ERR_UNC_POISON_TLP        0x00001000      /* Poisoned TLP */
+#define  PCI_ERR_UNC_FCP       0x00002000      /* Flow Control Protocol */
+#define  PCI_ERR_UNC_COMP_TIME 0x00004000      /* Completion Timeout */
+#define  PCI_ERR_UNC_COMP_ABORT        0x00008000      /* Completer Abort */
+#define  PCI_ERR_UNC_UNX_COMP  0x00010000      /* Unexpected Completion */
+#define  PCI_ERR_UNC_RX_OVER   0x00020000      /* Receiver Overflow */
+#define  PCI_ERR_UNC_MALF_TLP  0x00040000      /* Malformed TLP */
+#define  PCI_ERR_UNC_ECRC      0x00080000      /* ECRC Error Status */
+#define  PCI_ERR_UNC_UNSUP     0x00100000      /* Unsupported Request */
+#define PCI_ERR_UNCOR_MASK     8       /* Uncorrectable Error Mask */
+       /* Same bits as above */
+#define PCI_ERR_UNCOR_SEVER    12      /* Uncorrectable Error Severity */
+       /* Same bits as above */
+#define PCI_ERR_COR_STATUS     16      /* Correctable Error Status */
+#define  PCI_ERR_COR_RCVR      0x00000001      /* Receiver Error Status */
+#define  PCI_ERR_COR_BAD_TLP   0x00000040      /* Bad TLP Status */
+#define  PCI_ERR_COR_BAD_DLLP  0x00000080      /* Bad DLLP Status */
+#define  PCI_ERR_COR_REP_ROLL  0x00000100      /* REPLAY_NUM Rollover */
+#define  PCI_ERR_COR_REP_TIMER 0x00001000      /* Replay Timer Timeout */
+#define PCI_ERR_COR_MASK       20      /* Correctable Error Mask */
+       /* Same bits as above */
+#define PCI_ERR_CAP            24      /* Advanced Error Capabilities */
+#define  PCI_ERR_CAP_FEP(x)    ((x) & 31)      /* First Error Pointer */
+#define  PCI_ERR_CAP_ECRC_GENC 0x00000020      /* ECRC Generation Capable */
+#define  PCI_ERR_CAP_ECRC_GENE 0x00000040      /* ECRC Generation Enable */
+#define  PCI_ERR_CAP_ECRC_CHKC 0x00000080      /* ECRC Check Capable */
+#define  PCI_ERR_CAP_ECRC_CHKE 0x00000100      /* ECRC Check Enable */
+#define PCI_ERR_HEADER_LOG     28      /* Header Log Register (16 bytes) */
+#define PCI_ERR_ROOT_COMMAND   44      /* Root Error Command */
+/* Correctable Err Reporting Enable */
+#define PCI_ERR_ROOT_CMD_COR_EN                0x00000001
+/* Non-fatal Err Reporting Enable */
+#define PCI_ERR_ROOT_CMD_NONFATAL_EN   0x00000002
+/* Fatal Err Reporting Enable */
+#define PCI_ERR_ROOT_CMD_FATAL_EN      0x00000004
+#define PCI_ERR_ROOT_STATUS    48
+#define PCI_ERR_ROOT_COR_RCV           0x00000001      /* ERR_COR Received */
+/* Multi ERR_COR Received */
+#define PCI_ERR_ROOT_MULTI_COR_RCV     0x00000002
+/* ERR_FATAL/NONFATAL Recevied */
+#define PCI_ERR_ROOT_UNCOR_RCV         0x00000004
+/* Multi ERR_FATAL/NONFATAL Recevied */
+#define PCI_ERR_ROOT_MULTI_UNCOR_RCV   0x00000008
+#define PCI_ERR_ROOT_FIRST_FATAL       0x00000010      /* First Fatal */
+#define PCI_ERR_ROOT_NONFATAL_RCV      0x00000020      /* Non-Fatal Received */
+#define PCI_ERR_ROOT_FATAL_RCV         0x00000040      /* Fatal Received */
+#define PCI_ERR_ROOT_ERR_SRC   52      /* Error Source Identification */
+
+/* Virtual Channel */
+#define PCI_VC_PORT_REG1       4
+#define PCI_VC_PORT_REG2       8
+#define PCI_VC_PORT_CTRL       12
+#define PCI_VC_PORT_STATUS     14
+#define PCI_VC_RES_CAP         16
+#define PCI_VC_RES_CTRL                20
+#define PCI_VC_RES_STATUS      26
+
+/* Power Budgeting */
+#define PCI_PWR_DSR            4       /* Data Select Register */
+#define PCI_PWR_DATA           8       /* Data Register */
+#define  PCI_PWR_DATA_BASE(x)  ((x) & 0xff)        /* Base Power */
+#define  PCI_PWR_DATA_SCALE(x) (((x) >> 8) & 3)    /* Data Scale */
+#define  PCI_PWR_DATA_PM_SUB(x)        (((x) >> 10) & 7)   /* PM Sub State */
+#define  PCI_PWR_DATA_PM_STATE(x) (((x) >> 13) & 3) /* PM State */
+#define  PCI_PWR_DATA_TYPE(x)  (((x) >> 15) & 7)   /* Type */
+#define  PCI_PWR_DATA_RAIL(x)  (((x) >> 18) & 7)   /* Power Rail */
+#define PCI_PWR_CAP            12      /* Capability */
+#define  PCI_PWR_CAP_BUDGET(x) ((x) & 1)       /* Included in system budget */
+
+/*
+ * Hypertransport sub capability types
+ *
+ * Unfortunately there are both 3 bit and 5 bit capability types defined
+ * in the HT spec, catering for that is a little messy. You probably don't
+ * want to use these directly, just use pci_find_ht_capability() and it
+ * will do the right thing for you.
+ */
+#define HT_3BIT_CAP_MASK       0xE0
+#define HT_CAPTYPE_SLAVE       0x00    /* Slave/Primary link configuration */
+#define HT_CAPTYPE_HOST                0x20    /* Host/Secondary link configuration */
+
+#define HT_5BIT_CAP_MASK       0xF8
+#define HT_CAPTYPE_IRQ         0x80    /* IRQ Configuration */
+#define HT_CAPTYPE_REMAPPING_40        0xA0    /* 40 bit address remapping */
+#define HT_CAPTYPE_REMAPPING_64 0xA2   /* 64 bit address remapping */
+#define HT_CAPTYPE_UNITID_CLUMP        0x90    /* Unit ID clumping */
+#define HT_CAPTYPE_EXTCONF     0x98    /* Extended Configuration Space Access */
+#define HT_CAPTYPE_MSI_MAPPING 0xA8    /* MSI Mapping Capability */
+#define  HT_MSI_FLAGS          0x02            /* Offset to flags */
+#define  HT_MSI_FLAGS_ENABLE   0x1             /* Mapping enable */
+#define  HT_MSI_FLAGS_FIXED    0x2             /* Fixed mapping only */
+#define  HT_MSI_FIXED_ADDR     0x00000000FEE00000ULL   /* Fixed addr */
+#define  HT_MSI_ADDR_LO                0x04            /* Offset to low addr bits */
+#define  HT_MSI_ADDR_LO_MASK   0xFFF00000      /* Low address bit mask */
+#define  HT_MSI_ADDR_HI                0x08            /* Offset to high addr bits */
+#define HT_CAPTYPE_DIRECT_ROUTE        0xB0    /* Direct routing configuration */
+#define HT_CAPTYPE_VCSET       0xB8    /* Virtual Channel configuration */
+#define HT_CAPTYPE_ERROR_RETRY 0xC0    /* Retry on error configuration */
+#define HT_CAPTYPE_GEN3                0xD0    /* Generation 3 hypertransport configuration */
+#define HT_CAPTYPE_PM          0xE0    /* Hypertransport powermanagement configuration */
+
+/* Alternative Routing-ID Interpretation */
+#define PCI_ARI_CAP            0x04    /* ARI Capability Register */
+#define  PCI_ARI_CAP_MFVC      0x0001  /* MFVC Function Groups Capability */
+#define  PCI_ARI_CAP_ACS       0x0002  /* ACS Function Groups Capability */
+#define  PCI_ARI_CAP_NFN(x)    (((x) >> 8) & 0xff) /* Next Function Number */
+#define PCI_ARI_CTRL           0x06    /* ARI Control Register */
+#define  PCI_ARI_CTRL_MFVC     0x0001  /* MFVC Function Groups Enable */
+#define  PCI_ARI_CTRL_ACS      0x0002  /* ACS Function Groups Enable */
+#define  PCI_ARI_CTRL_FG(x)    (((x) >> 4) & 7) /* Function Group */
+
+/* Address Translation Service */
+#define PCI_ATS_CAP            0x04    /* ATS Capability Register */
+#define  PCI_ATS_CAP_QDEP(x)   ((x) & 0x1f)    /* Invalidate Queue Depth */
+#define  PCI_ATS_MAX_QDEP      32      /* Max Invalidate Queue Depth */
+#define PCI_ATS_CTRL           0x06    /* ATS Control Register */
+#define  PCI_ATS_CTRL_ENABLE   0x8000  /* ATS Enable */
+#define  PCI_ATS_CTRL_STU(x)   ((x) & 0x1f)    /* Smallest Translation Unit */
+#define  PCI_ATS_MIN_STU       12      /* shift of minimum STU block */
+
+/* Single Root I/O Virtualization */
+#define PCI_SRIOV_CAP          0x04    /* SR-IOV Capabilities */
+#define  PCI_SRIOV_CAP_VFM     0x01    /* VF Migration Capable */
+#define  PCI_SRIOV_CAP_INTR(x) ((x) >> 21) /* Interrupt Message Number */
+#define PCI_SRIOV_CTRL         0x08    /* SR-IOV Control */
+#define  PCI_SRIOV_CTRL_VFE    0x01    /* VF Enable */
+#define  PCI_SRIOV_CTRL_VFM    0x02    /* VF Migration Enable */
+#define  PCI_SRIOV_CTRL_INTR   0x04    /* VF Migration Interrupt Enable */
+#define  PCI_SRIOV_CTRL_MSE    0x08    /* VF Memory Space Enable */
+#define  PCI_SRIOV_CTRL_ARI    0x10    /* ARI Capable Hierarchy */
+#define PCI_SRIOV_STATUS       0x0a    /* SR-IOV Status */
+#define  PCI_SRIOV_STATUS_VFM  0x01    /* VF Migration Status */
+#define PCI_SRIOV_INITIAL_VF   0x0c    /* Initial VFs */
+#define PCI_SRIOV_TOTAL_VF     0x0e    /* Total VFs */
+#define PCI_SRIOV_NUM_VF       0x10    /* Number of VFs */
+#define PCI_SRIOV_FUNC_LINK    0x12    /* Function Dependency Link */
+#define PCI_SRIOV_VF_OFFSET    0x14    /* First VF Offset */
+#define PCI_SRIOV_VF_STRIDE    0x16    /* Following VF Stride */
+#define PCI_SRIOV_VF_DID       0x1a    /* VF Device ID */
+#define PCI_SRIOV_SUP_PGSIZE   0x1c    /* Supported Page Sizes */
+#define PCI_SRIOV_SYS_PGSIZE   0x20    /* System Page Size */
+#define PCI_SRIOV_BAR          0x24    /* VF BAR0 */
+#define  PCI_SRIOV_NUM_BARS    6       /* Number of VF BARs */
+#define PCI_SRIOV_VFM          0x3c    /* VF Migration State Array Offset*/
+#define  PCI_SRIOV_VFM_BIR(x)  ((x) & 7)       /* State BIR */
+#define  PCI_SRIOV_VFM_OFFSET(x) ((x) & ~7)    /* State Offset */
+#define  PCI_SRIOV_VFM_UA      0x0     /* Inactive.Unavailable */
+#define  PCI_SRIOV_VFM_MI      0x1     /* Dormant.MigrateIn */
+#define  PCI_SRIOV_VFM_MO      0x2     /* Active.MigrateOut */
+#define  PCI_SRIOV_VFM_AV      0x3     /* Active.Available */
+
+#define PCI_LTR_MAX_SNOOP_LAT  0x4
+#define PCI_LTR_MAX_NOSNOOP_LAT        0x6
+#define  PCI_LTR_VALUE_MASK    0x000003ff
+#define  PCI_LTR_SCALE_MASK    0x00001c00
+#define  PCI_LTR_SCALE_SHIFT   10
+
+/* Access Control Service */
+#define PCI_ACS_CAP            0x04    /* ACS Capability Register */
+#define  PCI_ACS_SV            0x01    /* Source Validation */
+#define  PCI_ACS_TB            0x02    /* Translation Blocking */
+#define  PCI_ACS_RR            0x04    /* P2P Request Redirect */
+#define  PCI_ACS_CR            0x08    /* P2P Completion Redirect */
+#define  PCI_ACS_UF            0x10    /* Upstream Forwarding */
+#define  PCI_ACS_EC            0x20    /* P2P Egress Control */
+#define  PCI_ACS_DT            0x40    /* Direct Translated P2P */
+#define PCI_ACS_CTRL           0x06    /* ACS Control Register */
+#define PCI_ACS_EGRESS_CTL_V   0x08    /* ACS Egress Control Vector */
+
+#endif /* LINUX_PCI_REGS_H */
diff --git a/include/hw/pci/pcie.h b/include/hw/pci/pcie.h
new file mode 100644 (file)
index 0000000..c010007
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * pcie.h
+ *
+ * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
+ *                    VA Linux Systems Japan K.K.
+ *
+ * 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 QEMU_PCIE_H
+#define QEMU_PCIE_H
+
+#include "hw/hw.h"
+#include "hw/pci/pci_regs.h"
+#include "hw/pci/pcie_regs.h"
+#include "hw/pci/pcie_aer.h"
+
+typedef enum {
+    /* for attention and power indicator */
+    PCI_EXP_HP_IND_RESERVED     = PCI_EXP_SLTCTL_IND_RESERVED,
+    PCI_EXP_HP_IND_ON           = PCI_EXP_SLTCTL_IND_ON,
+    PCI_EXP_HP_IND_BLINK        = PCI_EXP_SLTCTL_IND_BLINK,
+    PCI_EXP_HP_IND_OFF          = PCI_EXP_SLTCTL_IND_OFF,
+} PCIExpressIndicator;
+
+typedef enum {
+    /* these bits must match the bits in Slot Control/Status registers.
+     * PCI_EXP_HP_EV_xxx = PCI_EXP_SLTCTL_xxxE = PCI_EXP_SLTSTA_xxx
+     *
+     * Not all the bits of slot control register match with the ones of
+     * slot status. Not some bits of slot status register is used to
+     * show status, not to report event occurrence.
+     * So such bits must be masked out when checking the software
+     * notification condition.
+     */
+    PCI_EXP_HP_EV_ABP           = PCI_EXP_SLTCTL_ABPE,
+                                        /* attention button pressed */
+    PCI_EXP_HP_EV_PDC           = PCI_EXP_SLTCTL_PDCE,
+                                        /* presence detect changed */
+    PCI_EXP_HP_EV_CCI           = PCI_EXP_SLTCTL_CCIE,
+                                        /* command completed */
+
+    PCI_EXP_HP_EV_SUPPORTED     = PCI_EXP_HP_EV_ABP |
+                                  PCI_EXP_HP_EV_PDC |
+                                  PCI_EXP_HP_EV_CCI,
+                                                /* supported event mask  */
+
+    /* events not listed aren't supported */
+} PCIExpressHotPlugEvent;
+
+struct PCIExpressDevice {
+    /* Offset of express capability in config space */
+    uint8_t exp_cap;
+
+    /* SLOT */
+    unsigned int hpev_intx;     /* INTx for hot plug event (0-3:INT[A-D]#)
+                                 * default is 0 = INTA#
+                                 * If the chip wants to use other interrupt
+                                 * line, initialize this member with the
+                                 * desired number.
+                                 * If the chip dynamically changes this member,
+                                 * also initialize it when loaded as
+                                 * appropreately.
+                                 */
+    bool hpev_notified; /* Logical AND of conditions for hot plug event.
+                         Following 6.7.3.4:
+                         Software Notification of Hot-Plug Events, an interrupt
+                         is sent whenever the logical and of these conditions
+                         transitions from false to true. */
+
+    /* AER */
+    uint16_t aer_cap;
+    PCIEAERLog aer_log;
+    unsigned int aer_intx;      /* INTx for error reporting
+                                 * default is 0 = INTA#
+                                 * If the chip wants to use other interrupt
+                                 * line, initialize this member with the
+                                 * desired number.
+                                 * If the chip dynamically changes this member,
+                                 * also initialize it when loaded as
+                                 * appropreately.
+                                 */
+};
+
+/* PCI express capability helper functions */
+int pcie_cap_init(PCIDevice *dev, uint8_t offset, uint8_t type, uint8_t port);
+int pcie_endpoint_cap_init(PCIDevice *dev, uint8_t offset);
+void pcie_cap_exit(PCIDevice *dev);
+uint8_t pcie_cap_get_type(const PCIDevice *dev);
+void pcie_cap_flags_set_vector(PCIDevice *dev, uint8_t vector);
+uint8_t pcie_cap_flags_get_vector(PCIDevice *dev);
+
+void pcie_cap_deverr_init(PCIDevice *dev);
+void pcie_cap_deverr_reset(PCIDevice *dev);
+
+void pcie_cap_slot_init(PCIDevice *dev, uint16_t slot);
+void pcie_cap_slot_reset(PCIDevice *dev);
+void pcie_cap_slot_write_config(PCIDevice *dev,
+                                uint32_t addr, uint32_t val, int len);
+int pcie_cap_slot_post_load(void *opaque, int version_id);
+void pcie_cap_slot_push_attention_button(PCIDevice *dev);
+
+void pcie_cap_root_init(PCIDevice *dev);
+void pcie_cap_root_reset(PCIDevice *dev);
+
+void pcie_cap_flr_init(PCIDevice *dev);
+void pcie_cap_flr_write_config(PCIDevice *dev,
+                           uint32_t addr, uint32_t val, int len);
+
+void pcie_cap_ari_init(PCIDevice *dev);
+void pcie_cap_ari_reset(PCIDevice *dev);
+bool pcie_cap_is_ari_enabled(const PCIDevice *dev);
+
+/* PCI express extended capability helper functions */
+uint16_t pcie_find_capability(PCIDevice *dev, uint16_t cap_id);
+void pcie_add_capability(PCIDevice *dev,
+                         uint16_t cap_id, uint8_t cap_ver,
+                         uint16_t offset, uint16_t size);
+
+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)),                               \
+    .size       = sizeof(PCIDevice),                                 \
+    .vmsd       = &vmstate_pcie_device,                              \
+    .flags      = VMS_STRUCT,                                        \
+    .offset     = vmstate_offset_value(_state, _field, PCIDevice),   \
+}
+
+#endif /* QEMU_PCIE_H */
diff --git a/include/hw/pci/pcie_aer.h b/include/hw/pci/pcie_aer.h
new file mode 100644 (file)
index 0000000..bcac80a
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * pcie_aer.h
+ *
+ * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
+ *                    VA Linux Systems Japan K.K.
+ *
+ * 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 QEMU_PCIE_AER_H
+#define QEMU_PCIE_AER_H
+
+#include "hw/hw.h"
+
+/* definitions which PCIExpressDevice uses */
+
+/* AER log */
+struct PCIEAERLog {
+    /* This structure is saved/loaded.
+       So explicitly size them instead of unsigned int */
+
+    /* the number of currently recorded log in log member */
+    uint16_t log_num;
+
+    /*
+     * The maximum number of the log. Errors can be logged up to this.
+     *
+     * This is configurable property.
+     * The specified value will be clipped down to PCIE_AER_LOG_MAX_LIMIT
+     * to avoid unreasonable memory usage.
+     * I bet that 128 log size would be big enough, otherwise too many errors
+     * for system to function normaly. But could consecutive errors occur?
+     */
+#define PCIE_AER_LOG_MAX_DEFAULT        8
+#define PCIE_AER_LOG_MAX_LIMIT          128
+#define PCIE_AER_LOG_MAX_UNSET          0xffff
+    uint16_t log_max;
+
+    /* Error log. log_max-sized array */
+    PCIEAERErr *log;
+};
+
+/* aer error message: error signaling message has only error sevirity and
+   source id. See 2.2.8.3 error signaling messages */
+struct PCIEAERMsg {
+    /*
+     * PCI_ERR_ROOT_CMD_{COR, NONFATAL, FATAL}_EN
+     * = PCI_EXP_DEVCTL_{CERE, NFERE, FERE}
+     */
+    uint32_t severity;
+
+    uint16_t source_id; /* bdf */
+};
+
+static inline bool
+pcie_aer_msg_is_uncor(const PCIEAERMsg *msg)
+{
+    return msg->severity == PCI_ERR_ROOT_CMD_NONFATAL_EN ||
+        msg->severity == PCI_ERR_ROOT_CMD_FATAL_EN;
+}
+
+/* error */
+struct PCIEAERErr {
+    uint32_t status;    /* error status bits */
+    uint16_t source_id; /* bdf */
+
+#define PCIE_AER_ERR_IS_CORRECTABLE     0x1     /* correctable/uncorrectable */
+#define PCIE_AER_ERR_MAYBE_ADVISORY     0x2     /* maybe advisory non-fatal */
+#define PCIE_AER_ERR_HEADER_VALID       0x4     /* TLP header is logged */
+#define PCIE_AER_ERR_TLP_PREFIX_PRESENT 0x8     /* TLP Prefix is logged */
+    uint16_t flags;
+
+    uint32_t header[4]; /* TLP header */
+    uint32_t prefix[4]; /* TLP header prefix */
+};
+
+extern const VMStateDescription vmstate_pcie_aer_log;
+
+int pcie_aer_init(PCIDevice *dev, uint16_t offset);
+void pcie_aer_exit(PCIDevice *dev);
+void pcie_aer_write_config(PCIDevice *dev,
+                           uint32_t addr, uint32_t val, int len);
+
+/* aer root port */
+void pcie_aer_root_set_vector(PCIDevice *dev, unsigned int vector);
+void pcie_aer_root_init(PCIDevice *dev);
+void pcie_aer_root_reset(PCIDevice *dev);
+void pcie_aer_root_write_config(PCIDevice *dev,
+                                uint32_t addr, uint32_t val, int len,
+                                uint32_t root_cmd_prev);
+
+/* error injection */
+int pcie_aer_inject_error(PCIDevice *dev, const PCIEAERErr *err);
+
+#endif /* QEMU_PCIE_AER_H */
diff --git a/include/hw/pci/pcie_host.h b/include/hw/pci/pcie_host.h
new file mode 100644 (file)
index 0000000..1228e36
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * pcie_host.h
+ *
+ * Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp>
+ *                    VA Linux Systems Japan K.K.
+ *
+ * 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 PCIE_HOST_H
+#define PCIE_HOST_H
+
+#include "hw/pci/pci_host.h"
+#include "exec/memory.h"
+
+#define TYPE_PCIE_HOST_BRIDGE "pcie-host-bridge"
+#define PCIE_HOST_BRIDGE(obj) \
+    OBJECT_CHECK(PCIExpressHost, (obj), TYPE_PCIE_HOST_BRIDGE)
+
+struct PCIExpressHost {
+    PCIHostState pci;
+
+    /* express part */
+
+    /* base address where MMCONFIG area is mapped. */
+    hwaddr  base_addr;
+
+    /* the size of MMCONFIG area. It's host bridge dependent */
+    hwaddr  size;
+
+    /* MMCONFIG mmio area */
+    MemoryRegion mmio;
+};
+
+int pcie_host_init(PCIExpressHost *e);
+void pcie_host_mmcfg_unmap(PCIExpressHost *e);
+void pcie_host_mmcfg_map(PCIExpressHost *e, hwaddr addr, uint32_t size);
+void pcie_host_mmcfg_update(PCIExpressHost *e,
+                            int enable,
+                            hwaddr addr,
+                            uint32_t size);
+
+#endif /* PCIE_HOST_H */
diff --git a/include/hw/pci/pcie_port.h b/include/hw/pci/pcie_port.h
new file mode 100644 (file)
index 0000000..d89aa61
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * pcie_port.h
+ *
+ * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
+ *                    VA Linux Systems Japan K.K.
+ *
+ * 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 QEMU_PCIE_PORT_H
+#define QEMU_PCIE_PORT_H
+
+#include "hw/pci/pci_bridge.h"
+#include "hw/pci/pci_bus.h"
+
+struct PCIEPort {
+    PCIBridge   br;
+
+    /* pci express switch port */
+    uint8_t     port;
+};
+
+void pcie_port_init_reg(PCIDevice *d);
+
+struct PCIESlot {
+    PCIEPort    port;
+
+    /* pci express switch port with slot */
+    uint8_t     chassis;
+    uint16_t    slot;
+    QLIST_ENTRY(PCIESlot) next;
+};
+
+void pcie_chassis_create(uint8_t chassis_number);
+void pcie_main_chassis_create(void);
+PCIESlot *pcie_chassis_find_slot(uint8_t chassis, uint16_t slot);
+int pcie_chassis_add_slot(struct PCIESlot *slot);
+void pcie_chassis_del_slot(PCIESlot *s);
+
+#endif /* QEMU_PCIE_PORT_H */
diff --git a/include/hw/pci/pcie_regs.h b/include/hw/pci/pcie_regs.h
new file mode 100644 (file)
index 0000000..4d123d9
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * constants for pcie configurations space from pci express spec.
+ *
+ * TODO:
+ * Those constants and macros should go to Linux pci_regs.h
+ * Once they're merged, they will go away.
+ */
+#ifndef QEMU_PCIE_REGS_H
+#define QEMU_PCIE_REGS_H
+
+
+/* express capability */
+
+#define PCI_EXP_VER2_SIZEOF             0x3c /* express capability of ver. 2 */
+#define PCI_EXT_CAP_VER_SHIFT           16
+#define PCI_EXT_CAP_NEXT_SHIFT          20
+#define PCI_EXT_CAP_NEXT_MASK           (0xffc << PCI_EXT_CAP_NEXT_SHIFT)
+
+#define PCI_EXT_CAP(id, ver, next)                                      \
+    ((id) |                                                             \
+     ((ver) << PCI_EXT_CAP_VER_SHIFT) |                                 \
+     ((next) << PCI_EXT_CAP_NEXT_SHIFT))
+
+#define PCI_EXT_CAP_ALIGN               4
+#define PCI_EXT_CAP_ALIGNUP(x)                                  \
+    (((x) + PCI_EXT_CAP_ALIGN - 1) & ~(PCI_EXT_CAP_ALIGN - 1))
+
+/* PCI_EXP_FLAGS */
+#define PCI_EXP_FLAGS_VER2              2 /* for now, supports only ver. 2 */
+#define PCI_EXP_FLAGS_IRQ_SHIFT         (ffs(PCI_EXP_FLAGS_IRQ) - 1)
+#define PCI_EXP_FLAGS_TYPE_SHIFT        (ffs(PCI_EXP_FLAGS_TYPE) - 1)
+
+
+/* PCI_EXP_LINK{CAP, STA} */
+/* link speed */
+#define PCI_EXP_LNK_LS_25               1
+
+#define PCI_EXP_LNK_MLW_SHIFT           (ffs(PCI_EXP_LNKCAP_MLW) - 1)
+#define PCI_EXP_LNK_MLW_1               (1 << PCI_EXP_LNK_MLW_SHIFT)
+
+/* PCI_EXP_LINKCAP */
+#define PCI_EXP_LNKCAP_ASPMS_SHIFT      (ffs(PCI_EXP_LNKCAP_ASPMS) - 1)
+#define PCI_EXP_LNKCAP_ASPMS_0S         (1 << PCI_EXP_LNKCAP_ASPMS_SHIFT)
+
+#define PCI_EXP_LNKCAP_PN_SHIFT         (ffs(PCI_EXP_LNKCAP_PN) - 1)
+
+#define PCI_EXP_SLTCAP_PSN_SHIFT        (ffs(PCI_EXP_SLTCAP_PSN) - 1)
+
+#define PCI_EXP_SLTCTL_IND_RESERVED     0x0
+#define PCI_EXP_SLTCTL_IND_ON           0x1
+#define PCI_EXP_SLTCTL_IND_BLINK        0x2
+#define PCI_EXP_SLTCTL_IND_OFF          0x3
+#define PCI_EXP_SLTCTL_AIC_SHIFT        (ffs(PCI_EXP_SLTCTL_AIC) - 1)
+#define PCI_EXP_SLTCTL_AIC_OFF                          \
+    (PCI_EXP_SLTCTL_IND_OFF << PCI_EXP_SLTCTL_AIC_SHIFT)
+
+#define PCI_EXP_SLTCTL_PIC_SHIFT        (ffs(PCI_EXP_SLTCTL_PIC) - 1)
+#define PCI_EXP_SLTCTL_PIC_OFF                          \
+    (PCI_EXP_SLTCTL_IND_OFF << PCI_EXP_SLTCTL_PIC_SHIFT)
+
+#define PCI_EXP_SLTCTL_SUPPORTED        \
+            (PCI_EXP_SLTCTL_ABPE |      \
+             PCI_EXP_SLTCTL_PDCE |      \
+             PCI_EXP_SLTCTL_CCIE |      \
+             PCI_EXP_SLTCTL_HPIE |      \
+             PCI_EXP_SLTCTL_AIC |       \
+             PCI_EXP_SLTCTL_PCC |       \
+             PCI_EXP_SLTCTL_EIC)
+
+#define PCI_EXP_DEVCAP2_EFF             0x100000
+#define PCI_EXP_DEVCAP2_EETLPP          0x200000
+
+#define PCI_EXP_DEVCTL2_EETLPPB         0x80
+
+/* ARI */
+#define PCI_ARI_VER                     1
+#define PCI_ARI_SIZEOF                  8
+
+/* AER */
+#define PCI_ERR_VER                     2
+#define PCI_ERR_SIZEOF                  0x48
+
+#define PCI_ERR_UNC_SDN                 0x00000020      /* surprise down */
+#define PCI_ERR_UNC_ACSV                0x00200000      /* ACS Violation */
+#define PCI_ERR_UNC_INTN                0x00400000      /* Internal Error */
+#define PCI_ERR_UNC_MCBTLP              0x00800000      /* MC Blcoked TLP */
+#define PCI_ERR_UNC_ATOP_EBLOCKED       0x01000000      /* atomic op egress blocked */
+#define PCI_ERR_UNC_TLP_PRF_BLOCKED     0x02000000      /* TLP Prefix Blocked */
+#define PCI_ERR_COR_ADV_NONFATAL        0x00002000      /* Advisory Non-Fatal */
+#define PCI_ERR_COR_INTERNAL            0x00004000      /* Corrected Internal */
+#define PCI_ERR_COR_HL_OVERFLOW         0x00008000      /* Header Long Overflow */
+#define PCI_ERR_CAP_FEP_MASK            0x0000001f
+#define PCI_ERR_CAP_MHRC                0x00000200
+#define PCI_ERR_CAP_MHRE                0x00000400
+#define PCI_ERR_CAP_TLP                 0x00000800
+
+#define PCI_ERR_HEADER_LOG_SIZE         16
+#define PCI_ERR_TLP_PREFIX_LOG          0x38
+#define PCI_ERR_TLP_PREFIX_LOG_SIZE     16
+
+#define PCI_SEC_STATUS_RCV_SYSTEM_ERROR         0x4000
+
+/* aer root error command/status */
+#define PCI_ERR_ROOT_CMD_EN_MASK        (PCI_ERR_ROOT_CMD_COR_EN |      \
+                                         PCI_ERR_ROOT_CMD_NONFATAL_EN | \
+                                         PCI_ERR_ROOT_CMD_FATAL_EN)
+
+#define PCI_ERR_ROOT_IRQ_MAX            32
+#define PCI_ERR_ROOT_IRQ                0xf8000000
+#define PCI_ERR_ROOT_IRQ_SHIFT          (ffs(PCI_ERR_ROOT_IRQ) - 1)
+#define PCI_ERR_ROOT_STATUS_REPORT_MASK (PCI_ERR_ROOT_COR_RCV |         \
+                                         PCI_ERR_ROOT_MULTI_COR_RCV |   \
+                                         PCI_ERR_ROOT_UNCOR_RCV |       \
+                                         PCI_ERR_ROOT_MULTI_UNCOR_RCV | \
+                                         PCI_ERR_ROOT_FIRST_FATAL |     \
+                                         PCI_ERR_ROOT_NONFATAL_RCV |    \
+                                         PCI_ERR_ROOT_FATAL_RCV)
+
+#define PCI_ERR_UNC_SUPPORTED           (PCI_ERR_UNC_DLP |              \
+                                         PCI_ERR_UNC_SDN |              \
+                                         PCI_ERR_UNC_POISON_TLP |       \
+                                         PCI_ERR_UNC_FCP |              \
+                                         PCI_ERR_UNC_COMP_TIME |        \
+                                         PCI_ERR_UNC_COMP_ABORT |       \
+                                         PCI_ERR_UNC_UNX_COMP |         \
+                                         PCI_ERR_UNC_RX_OVER |          \
+                                         PCI_ERR_UNC_MALF_TLP |         \
+                                         PCI_ERR_UNC_ECRC |             \
+                                         PCI_ERR_UNC_UNSUP |            \
+                                         PCI_ERR_UNC_ACSV |             \
+                                         PCI_ERR_UNC_INTN |             \
+                                         PCI_ERR_UNC_MCBTLP |           \
+                                         PCI_ERR_UNC_ATOP_EBLOCKED |    \
+                                         PCI_ERR_UNC_TLP_PRF_BLOCKED)
+
+#define PCI_ERR_UNC_SEVERITY_DEFAULT    (PCI_ERR_UNC_DLP |              \
+                                         PCI_ERR_UNC_SDN |              \
+                                         PCI_ERR_UNC_FCP |              \
+                                         PCI_ERR_UNC_RX_OVER |          \
+                                         PCI_ERR_UNC_MALF_TLP |         \
+                                         PCI_ERR_UNC_INTN)
+
+#define PCI_ERR_COR_SUPPORTED           (PCI_ERR_COR_RCVR |             \
+                                         PCI_ERR_COR_BAD_TLP |          \
+                                         PCI_ERR_COR_BAD_DLLP |         \
+                                         PCI_ERR_COR_REP_ROLL |         \
+                                         PCI_ERR_COR_REP_TIMER |        \
+                                         PCI_ERR_COR_ADV_NONFATAL |     \
+                                         PCI_ERR_COR_INTERNAL |         \
+                                         PCI_ERR_COR_HL_OVERFLOW)
+
+#define PCI_ERR_COR_MASK_DEFAULT        (PCI_ERR_COR_ADV_NONFATAL |     \
+                                         PCI_ERR_COR_INTERNAL |         \
+                                         PCI_ERR_COR_HL_OVERFLOW)
+
+#endif /* QEMU_PCIE_REGS_H */
diff --git a/include/hw/pci/shpc.h b/include/hw/pci/shpc.h
new file mode 100644 (file)
index 0000000..467911a
--- /dev/null
@@ -0,0 +1,48 @@
+#ifndef SHPC_H
+#define SHPC_H
+
+#include "qemu-common.h"
+#include "exec/memory.h"
+#include "migration/vmstate.h"
+
+struct SHPCDevice {
+    /* Capability offset in device's config space */
+    int cap;
+
+    /* # of hot-pluggable slots */
+    int nslots;
+
+    /* SHPC WRS: working register set */
+    uint8_t *config;
+
+    /* Used to enable checks on load. Note that writable bits are
+     * never checked even if set in cmask. */
+    uint8_t *cmask;
+
+    /* Used to implement R/W bytes */
+    uint8_t *wmask;
+
+    /* Used to implement RW1C(Write 1 to Clear) bytes */
+    uint8_t *w1cmask;
+
+    /* MMIO for the SHPC BAR */
+    MemoryRegion mmio;
+
+    /* Bus controlled by this SHPC */
+    PCIBus *sec_bus;
+
+    /* MSI already requested for this event */
+    int msi_requested;
+};
+
+void shpc_reset(PCIDevice *d);
+int shpc_bar_size(PCIDevice *dev);
+int shpc_init(PCIDevice *dev, PCIBus *sec_bus, MemoryRegion *bar, unsigned off);
+void shpc_cleanup(PCIDevice *dev, MemoryRegion *bar);
+void shpc_cap_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int len);
+
+extern VMStateInfo shpc_vmstate_info;
+#define SHPC_VMSTATE(_field, _type) \
+    VMSTATE_BUFFER_UNSAFE_INFO(_field, _type, 0, shpc_vmstate_info, 0)
+
+#endif
diff --git a/include/hw/pci/slotid_cap.h b/include/hw/pci/slotid_cap.h
new file mode 100644 (file)
index 0000000..70db047
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef PCI_SLOTID_CAP_H
+#define PCI_SLOTID_CAP_H
+
+#include "qemu-common.h"
+
+int slotid_cap_init(PCIDevice *dev, int nslots,
+                    uint8_t chassis,
+                    unsigned offset);
+void slotid_cap_cleanup(PCIDevice *dev);
+
+#endif
diff --git a/include/hw/pcmcia.h b/include/hw/pcmcia.h
new file mode 100644 (file)
index 0000000..f916693
--- /dev/null
@@ -0,0 +1,56 @@
+#ifndef HW_PCMCIA_H
+#define HW_PCMCIA_H 1
+
+/* PCMCIA/Cardbus */
+
+#include "qemu-common.h"
+
+typedef struct {
+    qemu_irq irq;
+    int attached;
+    const char *slot_string;
+    const char *card_string;
+} PCMCIASocket;
+
+void pcmcia_socket_register(PCMCIASocket *socket);
+void pcmcia_socket_unregister(PCMCIASocket *socket);
+void pcmcia_info(Monitor *mon, const QDict *qdict);
+
+struct PCMCIACardState {
+    void *state;
+    PCMCIASocket *slot;
+    int (*attach)(void *state);
+    int (*detach)(void *state);
+    const uint8_t *cis;
+    int cis_len;
+
+    /* Only valid if attached */
+    uint8_t (*attr_read)(void *state, uint32_t address);
+    void (*attr_write)(void *state, uint32_t address, uint8_t value);
+    uint16_t (*common_read)(void *state, uint32_t address);
+    void (*common_write)(void *state, uint32_t address, uint16_t value);
+    uint16_t (*io_read)(void *state, uint32_t address);
+    void (*io_write)(void *state, uint32_t address, uint16_t value);
+};
+
+#define CISTPL_DEVICE          0x01    /* 5V Device Information Tuple */
+#define CISTPL_NO_LINK         0x14    /* No Link Tuple */
+#define CISTPL_VERS_1          0x15    /* Level 1 Version Tuple */
+#define CISTPL_JEDEC_C         0x18    /* JEDEC ID Tuple */
+#define CISTPL_JEDEC_A         0x19    /* JEDEC ID Tuple */
+#define CISTPL_CONFIG          0x1a    /* Configuration Tuple */
+#define CISTPL_CFTABLE_ENTRY   0x1b    /* 16-bit PCCard Configuration */
+#define CISTPL_DEVICE_OC       0x1c    /* Additional Device Information */
+#define CISTPL_DEVICE_OA       0x1d    /* Additional Device Information */
+#define CISTPL_DEVICE_GEO      0x1e    /* Additional Device Information */
+#define CISTPL_DEVICE_GEO_A    0x1f    /* Additional Device Information */
+#define CISTPL_MANFID          0x20    /* Manufacture ID Tuple */
+#define CISTPL_FUNCID          0x21    /* Function ID Tuple */
+#define CISTPL_FUNCE           0x22    /* Function Extension Tuple */
+#define CISTPL_END             0xff    /* Tuple End */
+#define CISTPL_ENDMARK         0xff
+
+/* dscm1xxxx.c */
+PCMCIACardState *dscm1xxxx_init(DriveInfo *bdrv);
+
+#endif
diff --git a/include/hw/ppc/mac_dbdma.h b/include/hw/ppc/mac_dbdma.h
new file mode 100644 (file)
index 0000000..691263e
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2009 Laurent Vivier
+ *
+ * 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_MAC_DBDMA_H
+#define HW_MAC_DBDMA_H 1
+
+#include "exec/memory.h"
+
+typedef struct DBDMA_io DBDMA_io;
+
+typedef void (*DBDMA_flush)(DBDMA_io *io);
+typedef void (*DBDMA_rw)(DBDMA_io *io);
+typedef void (*DBDMA_end)(DBDMA_io *io);
+struct DBDMA_io {
+    void *opaque;
+    void *channel;
+    hwaddr addr;
+    int len;
+    int is_last;
+    int is_dma_out;
+    DBDMA_end dma_end;
+};
+
+
+void DBDMA_register_channel(void *dbdma, int nchan, qemu_irq irq,
+                            DBDMA_rw rw, DBDMA_flush flush,
+                            void *opaque);
+void* DBDMA_init (MemoryRegion **dbdma_mem);
+
+#endif
diff --git a/include/hw/ppc/openpic.h b/include/hw/ppc/openpic.h
new file mode 100644 (file)
index 0000000..9dcaf0e
--- /dev/null
@@ -0,0 +1,18 @@
+#if !defined(__OPENPIC_H__)
+#define __OPENPIC_H__
+
+/* OpenPIC have 5 outputs per CPU connected and one IRQ out single output */
+enum {
+    OPENPIC_OUTPUT_INT = 0, /* IRQ                       */
+    OPENPIC_OUTPUT_CINT,    /* critical IRQ              */
+    OPENPIC_OUTPUT_MCK,     /* Machine check event       */
+    OPENPIC_OUTPUT_DEBUG,   /* Inconditional debug event */
+    OPENPIC_OUTPUT_RESET,   /* Core reset event          */
+    OPENPIC_OUTPUT_NB,
+};
+
+#define OPENPIC_MODEL_RAVEN       0
+#define OPENPIC_MODEL_FSL_MPIC_20 1
+#define OPENPIC_MODEL_FSL_MPIC_42 2
+
+#endif /* __OPENPIC_H__ */
diff --git a/include/hw/ppc/ppc.h b/include/hw/ppc/ppc.h
new file mode 100644 (file)
index 0000000..acaf0d6
--- /dev/null
@@ -0,0 +1,99 @@
+#ifndef HW_PPC_H
+#define HW_PPC_H 1
+
+void ppc_set_irq(PowerPCCPU *cpu, int n_IRQ, int level);
+
+/* PowerPC hardware exceptions management helpers */
+typedef void (*clk_setup_cb)(void *opaque, uint32_t freq);
+typedef struct clk_setup_t clk_setup_t;
+struct clk_setup_t {
+    clk_setup_cb cb;
+    void *opaque;
+};
+static inline void clk_setup (clk_setup_t *clk, uint32_t freq)
+{
+    if (clk->cb != NULL)
+        (*clk->cb)(clk->opaque, freq);
+}
+
+struct ppc_tb_t {
+    /* Time base management */
+    int64_t  tb_offset;    /* Compensation                    */
+    int64_t  atb_offset;   /* Compensation                    */
+    uint32_t tb_freq;      /* TB frequency                    */
+    /* Decrementer management */
+    uint64_t decr_next;    /* Tick for next decr interrupt    */
+    uint32_t decr_freq;    /* decrementer frequency           */
+    struct QEMUTimer *decr_timer;
+    /* Hypervisor decrementer management */
+    uint64_t hdecr_next;    /* Tick for next hdecr interrupt  */
+    struct QEMUTimer *hdecr_timer;
+    uint64_t purr_load;
+    uint64_t purr_start;
+    void *opaque;
+    uint32_t flags;
+};
+
+/* PPC Timers flags */
+#define PPC_TIMER_BOOKE              (1 << 0) /* Enable Booke support */
+#define PPC_TIMER_E500               (1 << 1) /* Enable e500 support */
+#define PPC_DECR_UNDERFLOW_TRIGGERED (1 << 2) /* Decr interrupt triggered when
+                                               * the most significant bit
+                                               * changes from 0 to 1.
+                                               */
+#define PPC_DECR_ZERO_TRIGGERED      (1 << 3) /* Decr interrupt triggered when
+                                               * the decrementer reaches zero.
+                                               */
+
+uint64_t cpu_ppc_get_tb(ppc_tb_t *tb_env, uint64_t vmclk, int64_t tb_offset);
+clk_setup_cb cpu_ppc_tb_init (CPUPPCState *env, uint32_t freq);
+/* Embedded PowerPC DCR management */
+typedef uint32_t (*dcr_read_cb)(void *opaque, int dcrn);
+typedef void (*dcr_write_cb)(void *opaque, int dcrn, uint32_t val);
+int ppc_dcr_init (CPUPPCState *env, int (*dcr_read_error)(int dcrn),
+                  int (*dcr_write_error)(int dcrn));
+int ppc_dcr_register (CPUPPCState *env, int dcrn, void *opaque,
+                      dcr_read_cb drc_read, dcr_write_cb dcr_write);
+clk_setup_cb ppc_40x_timers_init (CPUPPCState *env, uint32_t freq,
+                                  unsigned int decr_excp);
+
+/* Embedded PowerPC reset */
+void ppc40x_core_reset(PowerPCCPU *cpu);
+void ppc40x_chip_reset(PowerPCCPU *cpu);
+void ppc40x_system_reset(PowerPCCPU *cpu);
+void PREP_debug_write (void *opaque, uint32_t addr, uint32_t val);
+
+extern CPUWriteMemoryFunc * const PPC_io_write[];
+extern CPUReadMemoryFunc * const PPC_io_read[];
+void PPC_debug_write (void *opaque, uint32_t addr, uint32_t val);
+
+void ppc40x_irq_init (CPUPPCState *env);
+void ppce500_irq_init (CPUPPCState *env);
+void ppc6xx_irq_init (CPUPPCState *env);
+void ppc970_irq_init (CPUPPCState *env);
+void ppcPOWER7_irq_init (CPUPPCState *env);
+
+void ppce500_set_mpic_proxy(bool enabled);
+
+/* PPC machines for OpenBIOS */
+enum {
+    ARCH_PREP = 0,
+    ARCH_MAC99,
+    ARCH_HEATHROW,
+    ARCH_MAC99_U3,
+};
+
+#define FW_CFG_PPC_WIDTH       (FW_CFG_ARCH_LOCAL + 0x00)
+#define FW_CFG_PPC_HEIGHT      (FW_CFG_ARCH_LOCAL + 0x01)
+#define FW_CFG_PPC_DEPTH       (FW_CFG_ARCH_LOCAL + 0x02)
+#define FW_CFG_PPC_TBFREQ      (FW_CFG_ARCH_LOCAL + 0x03)
+#define FW_CFG_PPC_IS_KVM       (FW_CFG_ARCH_LOCAL + 0x05)
+#define FW_CFG_PPC_KVM_HC       (FW_CFG_ARCH_LOCAL + 0x06)
+#define FW_CFG_PPC_KVM_PID      (FW_CFG_ARCH_LOCAL + 0x07)
+
+#define PPC_SERIAL_MM_BAUDBASE 399193
+
+/* ppc_booke.c */
+void ppc_booke_timers_init(PowerPCCPU *cpu, uint32_t freq, uint32_t flags);
+
+#endif
diff --git a/include/hw/ppc/ppc4xx.h b/include/hw/ppc/ppc4xx.h
new file mode 100644 (file)
index 0000000..91d84ba
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * QEMU PowerPC 4xx emulation shared definitions
+ *
+ * Copyright (c) 2007 Jocelyn Mayer
+ *
+ * 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 !defined(PPC_4XX_H)
+#define PPC_4XX_H
+
+#include "hw/pci/pci.h"
+
+/* PowerPC 4xx core initialization */
+PowerPCCPU *ppc4xx_init(const char *cpu_model,
+                        clk_setup_t *cpu_clk, clk_setup_t *tb_clk,
+                        uint32_t sysclk);
+
+/* PowerPC 4xx universal interrupt controller */
+enum {
+    PPCUIC_OUTPUT_INT = 0,
+    PPCUIC_OUTPUT_CINT = 1,
+    PPCUIC_OUTPUT_NB,
+};
+qemu_irq *ppcuic_init (CPUPPCState *env, qemu_irq *irqs,
+                       uint32_t dcr_base, int has_ssr, int has_vr);
+
+ram_addr_t ppc4xx_sdram_adjust(ram_addr_t ram_size, int nr_banks,
+                               MemoryRegion ram_memories[],
+                               hwaddr ram_bases[],
+                               hwaddr ram_sizes[],
+                               const unsigned int sdram_bank_sizes[]);
+
+void ppc4xx_sdram_init (CPUPPCState *env, qemu_irq irq, int nbanks,
+                        MemoryRegion ram_memories[],
+                        hwaddr *ram_bases,
+                        hwaddr *ram_sizes,
+                        int do_init);
+
+#define TYPE_PPC4xx_PCI_HOST_BRIDGE "ppc4xx-pcihost"
+
+PCIBus *ppc4xx_pci_init(CPUPPCState *env, qemu_irq pci_irqs[4],
+                        hwaddr config_space,
+                        hwaddr int_ack,
+                        hwaddr special_cycle,
+                        hwaddr registers);
+
+#endif /* !defined(PPC_4XX_H) */
diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h
new file mode 100644 (file)
index 0000000..864bee9
--- /dev/null
@@ -0,0 +1,358 @@
+#if !defined(__HW_SPAPR_H__)
+#define __HW_SPAPR_H__
+
+#include "sysemu/dma.h"
+#include "hw/ppc/xics.h"
+
+struct VIOsPAPRBus;
+struct sPAPRPHBState;
+struct sPAPRNVRAM;
+struct icp_state;
+
+typedef struct sPAPREnvironment {
+    struct VIOsPAPRBus *vio_bus;
+    QLIST_HEAD(, sPAPRPHBState) phbs;
+    struct sPAPRNVRAM *nvram;
+    struct icp_state *icp;
+
+    hwaddr ram_limit;
+    void *htab;
+    long htab_shift;
+    hwaddr rma_size;
+    int vrma_adjust;
+    hwaddr fdt_addr, rtas_addr;
+    long rtas_size;
+    void *fdt_skel;
+    target_ulong entry_point;
+    int next_irq;
+    int rtc_offset;
+    char *cpu_model;
+    bool has_graphics;
+
+    uint32_t epow_irq;
+    Notifier epow_notifier;
+} sPAPREnvironment;
+
+#define H_SUCCESS         0
+#define H_BUSY            1        /* Hardware busy -- retry later */
+#define H_CLOSED          2        /* Resource closed */
+#define H_NOT_AVAILABLE   3
+#define H_CONSTRAINED     4        /* Resource request constrained to max allowed */
+#define H_PARTIAL         5
+#define H_IN_PROGRESS     14       /* Kind of like busy */
+#define H_PAGE_REGISTERED 15
+#define H_PARTIAL_STORE   16
+#define H_PENDING         17       /* returned from H_POLL_PENDING */
+#define H_CONTINUE        18       /* Returned from H_Join on success */
+#define H_LONG_BUSY_START_RANGE         9900  /* Start of long busy range */
+#define H_LONG_BUSY_ORDER_1_MSEC        9900  /* Long busy, hint that 1msec \
+                                                 is a good time to retry */
+#define H_LONG_BUSY_ORDER_10_MSEC       9901  /* Long busy, hint that 10msec \
+                                                 is a good time to retry */
+#define H_LONG_BUSY_ORDER_100_MSEC      9902  /* Long busy, hint that 100msec \
+                                                 is a good time to retry */
+#define H_LONG_BUSY_ORDER_1_SEC         9903  /* Long busy, hint that 1sec \
+                                                 is a good time to retry */
+#define H_LONG_BUSY_ORDER_10_SEC        9904  /* Long busy, hint that 10sec \
+                                                 is a good time to retry */
+#define H_LONG_BUSY_ORDER_100_SEC       9905  /* Long busy, hint that 100sec \
+                                                 is a good time to retry */
+#define H_LONG_BUSY_END_RANGE           9905  /* End of long busy range */
+#define H_HARDWARE        -1       /* Hardware error */
+#define H_FUNCTION        -2       /* Function not supported */
+#define H_PRIVILEGE       -3       /* Caller not privileged */
+#define H_PARAMETER       -4       /* Parameter invalid, out-of-range or conflicting */
+#define H_BAD_MODE        -5       /* Illegal msr value */
+#define H_PTEG_FULL       -6       /* PTEG is full */
+#define H_NOT_FOUND       -7       /* PTE was not found" */
+#define H_RESERVED_DABR   -8       /* DABR address is reserved by the hypervisor on this processor" */
+#define H_NO_MEM          -9
+#define H_AUTHORITY       -10
+#define H_PERMISSION      -11
+#define H_DROPPED         -12
+#define H_SOURCE_PARM     -13
+#define H_DEST_PARM       -14
+#define H_REMOTE_PARM     -15
+#define H_RESOURCE        -16
+#define H_ADAPTER_PARM    -17
+#define H_RH_PARM         -18
+#define H_RCQ_PARM        -19
+#define H_SCQ_PARM        -20
+#define H_EQ_PARM         -21
+#define H_RT_PARM         -22
+#define H_ST_PARM         -23
+#define H_SIGT_PARM       -24
+#define H_TOKEN_PARM      -25
+#define H_MLENGTH_PARM    -27
+#define H_MEM_PARM        -28
+#define H_MEM_ACCESS_PARM -29
+#define H_ATTR_PARM       -30
+#define H_PORT_PARM       -31
+#define H_MCG_PARM        -32
+#define H_VL_PARM         -33
+#define H_TSIZE_PARM      -34
+#define H_TRACE_PARM      -35
+
+#define H_MASK_PARM       -37
+#define H_MCG_FULL        -38
+#define H_ALIAS_EXIST     -39
+#define H_P_COUNTER       -40
+#define H_TABLE_FULL      -41
+#define H_ALT_TABLE       -42
+#define H_MR_CONDITION    -43
+#define H_NOT_ENOUGH_RESOURCES -44
+#define H_R_STATE         -45
+#define H_RESCINDEND      -46
+#define H_MULTI_THREADS_ACTIVE -9005
+
+
+/* Long Busy is a condition that can be returned by the firmware
+ * when a call cannot be completed now, but the identical call
+ * should be retried later.  This prevents calls blocking in the
+ * firmware for long periods of time.  Annoyingly the firmware can return
+ * a range of return codes, hinting at how long we should wait before
+ * retrying.  If you don't care for the hint, the macro below is a good
+ * way to check for the long_busy return codes
+ */
+#define H_IS_LONG_BUSY(x)  ((x >= H_LONG_BUSY_START_RANGE) \
+                            && (x <= H_LONG_BUSY_END_RANGE))
+
+/* Flags */
+#define H_LARGE_PAGE      (1ULL<<(63-16))
+#define H_EXACT           (1ULL<<(63-24))       /* Use exact PTE or return H_PTEG_FULL */
+#define H_R_XLATE         (1ULL<<(63-25))       /* include a valid logical page num in the pte if the valid bit is set */
+#define H_READ_4          (1ULL<<(63-26))       /* Return 4 PTEs */
+#define H_PAGE_STATE_CHANGE (1ULL<<(63-28))
+#define H_PAGE_UNUSED     ((1ULL<<(63-29)) | (1ULL<<(63-30)))
+#define H_PAGE_SET_UNUSED (H_PAGE_STATE_CHANGE | H_PAGE_UNUSED)
+#define H_PAGE_SET_LOANED (H_PAGE_SET_UNUSED | (1ULL<<(63-31)))
+#define H_PAGE_SET_ACTIVE H_PAGE_STATE_CHANGE
+#define H_AVPN            (1ULL<<(63-32))       /* An avpn is provided as a sanity test */
+#define H_ANDCOND         (1ULL<<(63-33))
+#define H_ICACHE_INVALIDATE (1ULL<<(63-40))     /* icbi, etc.  (ignored for IO pages) */
+#define H_ICACHE_SYNCHRONIZE (1ULL<<(63-41))    /* dcbst, icbi, etc (ignored for IO pages */
+#define H_ZERO_PAGE       (1ULL<<(63-48))       /* zero the page before mapping (ignored for IO pages) */
+#define H_COPY_PAGE       (1ULL<<(63-49))
+#define H_N               (1ULL<<(63-61))
+#define H_PP1             (1ULL<<(63-62))
+#define H_PP2             (1ULL<<(63-63))
+
+/* VASI States */
+#define H_VASI_INVALID    0
+#define H_VASI_ENABLED    1
+#define H_VASI_ABORTED    2
+#define H_VASI_SUSPENDING 3
+#define H_VASI_SUSPENDED  4
+#define H_VASI_RESUMED    5
+#define H_VASI_COMPLETED  6
+
+/* DABRX flags */
+#define H_DABRX_HYPERVISOR (1ULL<<(63-61))
+#define H_DABRX_KERNEL     (1ULL<<(63-62))
+#define H_DABRX_USER       (1ULL<<(63-63))
+
+/* Each control block has to be on a 4K boundary */
+#define H_CB_ALIGNMENT     4096
+
+/* pSeries hypervisor opcodes */
+#define H_REMOVE                0x04
+#define H_ENTER                 0x08
+#define H_READ                  0x0c
+#define H_CLEAR_MOD             0x10
+#define H_CLEAR_REF             0x14
+#define H_PROTECT               0x18
+#define H_GET_TCE               0x1c
+#define H_PUT_TCE               0x20
+#define H_SET_SPRG0             0x24
+#define H_SET_DABR              0x28
+#define H_PAGE_INIT             0x2c
+#define H_SET_ASR               0x30
+#define H_ASR_ON                0x34
+#define H_ASR_OFF               0x38
+#define H_LOGICAL_CI_LOAD       0x3c
+#define H_LOGICAL_CI_STORE      0x40
+#define H_LOGICAL_CACHE_LOAD    0x44
+#define H_LOGICAL_CACHE_STORE   0x48
+#define H_LOGICAL_ICBI          0x4c
+#define H_LOGICAL_DCBF          0x50
+#define H_GET_TERM_CHAR         0x54
+#define H_PUT_TERM_CHAR         0x58
+#define H_REAL_TO_LOGICAL       0x5c
+#define H_HYPERVISOR_DATA       0x60
+#define H_EOI                   0x64
+#define H_CPPR                  0x68
+#define H_IPI                   0x6c
+#define H_IPOLL                 0x70
+#define H_XIRR                  0x74
+#define H_PERFMON               0x7c
+#define H_MIGRATE_DMA           0x78
+#define H_REGISTER_VPA          0xDC
+#define H_CEDE                  0xE0
+#define H_CONFER                0xE4
+#define H_PROD                  0xE8
+#define H_GET_PPP               0xEC
+#define H_SET_PPP               0xF0
+#define H_PURR                  0xF4
+#define H_PIC                   0xF8
+#define H_REG_CRQ               0xFC
+#define H_FREE_CRQ              0x100
+#define H_VIO_SIGNAL            0x104
+#define H_SEND_CRQ              0x108
+#define H_COPY_RDMA             0x110
+#define H_REGISTER_LOGICAL_LAN  0x114
+#define H_FREE_LOGICAL_LAN      0x118
+#define H_ADD_LOGICAL_LAN_BUFFER 0x11C
+#define H_SEND_LOGICAL_LAN      0x120
+#define H_BULK_REMOVE           0x124
+#define H_MULTICAST_CTRL        0x130
+#define H_SET_XDABR             0x134
+#define H_STUFF_TCE             0x138
+#define H_PUT_TCE_INDIRECT      0x13C
+#define H_CHANGE_LOGICAL_LAN_MAC 0x14C
+#define H_VTERM_PARTNER_INFO    0x150
+#define H_REGISTER_VTERM        0x154
+#define H_FREE_VTERM            0x158
+#define H_RESET_EVENTS          0x15C
+#define H_ALLOC_RESOURCE        0x160
+#define H_FREE_RESOURCE         0x164
+#define H_MODIFY_QP             0x168
+#define H_QUERY_QP              0x16C
+#define H_REREGISTER_PMR        0x170
+#define H_REGISTER_SMR          0x174
+#define H_QUERY_MR              0x178
+#define H_QUERY_MW              0x17C
+#define H_QUERY_HCA             0x180
+#define H_QUERY_PORT            0x184
+#define H_MODIFY_PORT           0x188
+#define H_DEFINE_AQP1           0x18C
+#define H_GET_TRACE_BUFFER      0x190
+#define H_DEFINE_AQP0           0x194
+#define H_RESIZE_MR             0x198
+#define H_ATTACH_MCQP           0x19C
+#define H_DETACH_MCQP           0x1A0
+#define H_CREATE_RPT            0x1A4
+#define H_REMOVE_RPT            0x1A8
+#define H_REGISTER_RPAGES       0x1AC
+#define H_DISABLE_AND_GETC      0x1B0
+#define H_ERROR_DATA            0x1B4
+#define H_GET_HCA_INFO          0x1B8
+#define H_GET_PERF_COUNT        0x1BC
+#define H_MANAGE_TRACE          0x1C0
+#define H_FREE_LOGICAL_LAN_BUFFER 0x1D4
+#define H_QUERY_INT_STATE       0x1E4
+#define H_POLL_PENDING          0x1D8
+#define H_ILLAN_ATTRIBUTES      0x244
+#define H_MODIFY_HEA_QP         0x250
+#define H_QUERY_HEA_QP          0x254
+#define H_QUERY_HEA             0x258
+#define H_QUERY_HEA_PORT        0x25C
+#define H_MODIFY_HEA_PORT       0x260
+#define H_REG_BCMC              0x264
+#define H_DEREG_BCMC            0x268
+#define H_REGISTER_HEA_RPAGES   0x26C
+#define H_DISABLE_AND_GET_HEA   0x270
+#define H_GET_HEA_INFO          0x274
+#define H_ALLOC_HEA_RESOURCE    0x278
+#define H_ADD_CONN              0x284
+#define H_DEL_CONN              0x288
+#define H_JOIN                  0x298
+#define H_VASI_STATE            0x2A4
+#define H_ENABLE_CRQ            0x2B0
+#define H_GET_EM_PARMS          0x2B8
+#define H_SET_MPP               0x2D0
+#define H_GET_MPP               0x2D4
+#define MAX_HCALL_OPCODE        H_GET_MPP
+
+/* The hcalls above are standardized in PAPR and implemented by pHyp
+ * as well.
+ *
+ * We also need some hcalls which are specific to qemu / KVM-on-POWER.
+ * So far we just need one for H_RTAS, but in future we'll need more
+ * for extensions like virtio.  We put those into the 0xf000-0xfffc
+ * range which is reserved by PAPR for "platform-specific" hcalls.
+ */
+#define KVMPPC_HCALL_BASE       0xf000
+#define KVMPPC_H_RTAS           (KVMPPC_HCALL_BASE + 0x0)
+#define KVMPPC_H_LOGICAL_MEMOP  (KVMPPC_HCALL_BASE + 0x1)
+#define KVMPPC_HCALL_MAX        KVMPPC_H_LOGICAL_MEMOP
+
+extern sPAPREnvironment *spapr;
+
+/*#define DEBUG_SPAPR_HCALLS*/
+
+#ifdef DEBUG_SPAPR_HCALLS
+#define hcall_dprintf(fmt, ...) \
+    do { fprintf(stderr, "%s: " fmt, __func__, ## __VA_ARGS__); } while (0)
+#else
+#define hcall_dprintf(fmt, ...) \
+    do { } while (0)
+#endif
+
+typedef target_ulong (*spapr_hcall_fn)(PowerPCCPU *cpu, sPAPREnvironment *spapr,
+                                       target_ulong opcode,
+                                       target_ulong *args);
+
+void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn);
+target_ulong spapr_hypercall(PowerPCCPU *cpu, target_ulong opcode,
+                             target_ulong *args);
+
+int spapr_allocate_irq(int hint, bool lsi);
+int spapr_allocate_irq_block(int num, bool lsi);
+
+static inline int spapr_allocate_msi(int hint)
+{
+    return spapr_allocate_irq(hint, false);
+}
+
+static inline int spapr_allocate_lsi(int hint)
+{
+    return spapr_allocate_irq(hint, true);
+}
+
+static inline uint32_t rtas_ld(target_ulong phys, int n)
+{
+    return ldl_be_phys(phys + 4*n);
+}
+
+static inline void rtas_st(target_ulong phys, int n, uint32_t val)
+{
+    stl_be_phys(phys + 4*n, val);
+}
+
+typedef void (*spapr_rtas_fn)(sPAPREnvironment *spapr, uint32_t token,
+                              uint32_t nargs, target_ulong args,
+                              uint32_t nret, target_ulong rets);
+int spapr_rtas_register(const char *name, spapr_rtas_fn fn);
+target_ulong spapr_rtas_call(sPAPREnvironment *spapr,
+                             uint32_t token, uint32_t nargs, target_ulong args,
+                             uint32_t nret, target_ulong rets);
+int spapr_rtas_device_tree_setup(void *fdt, hwaddr rtas_addr,
+                                 hwaddr rtas_size);
+
+#define SPAPR_TCE_PAGE_SHIFT   12
+#define SPAPR_TCE_PAGE_SIZE    (1ULL << SPAPR_TCE_PAGE_SHIFT)
+#define SPAPR_TCE_PAGE_MASK    (SPAPR_TCE_PAGE_SIZE - 1)
+
+typedef struct sPAPRTCE {
+    uint64_t tce;
+} sPAPRTCE;
+
+#define SPAPR_VIO_BASE_LIOBN    0x00000000
+#define SPAPR_PCI_BASE_LIOBN    0x80000000
+
+#define RTAS_ERROR_LOG_MAX      2048
+
+
+void spapr_iommu_init(void);
+void spapr_events_init(sPAPREnvironment *spapr);
+void spapr_events_fdt_skel(void *fdt, uint32_t epow_irq);
+DMAContext *spapr_tce_new_dma_context(uint32_t liobn, size_t window_size);
+void spapr_tce_free(DMAContext *dma);
+void spapr_tce_reset(DMAContext *dma);
+void spapr_tce_set_bypass(DMAContext *dma, bool bypass);
+int spapr_dma_dt(void *fdt, int node_off, const char *propname,
+                 uint32_t liobn, uint64_t window, uint32_t size);
+int spapr_tcet_dma_dt(void *fdt, int node_off, const char *propname,
+                      DMAContext *dma);
+
+#endif /* !defined (__HW_SPAPR_H__) */
diff --git a/include/hw/ppc/spapr_vio.h b/include/hw/ppc/spapr_vio.h
new file mode 100644 (file)
index 0000000..f98ec0a
--- /dev/null
@@ -0,0 +1,136 @@
+#ifndef _HW_SPAPR_VIO_H
+#define _HW_SPAPR_VIO_H
+/*
+ * QEMU sPAPR VIO bus definitions
+ *
+ * Copyright (c) 2010 David Gibson, IBM Corporation <david@gibson.dropbear.id.au>
+ * Based on the s390 virtio bus definitions:
+ * Copyright (c) 2009 Alexander Graf <agraf@suse.de>
+ *
+ * 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 "sysemu/dma.h"
+
+#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)
+
+#define TYPE_SPAPR_VIO_BUS "spapr-vio-bus"
+#define SPAPR_VIO_BUS(obj) OBJECT_CHECK(VIOsPAPRBus, (obj), TYPE_SPAPR_VIO_BUS)
+
+struct VIOsPAPRDevice;
+
+typedef struct VIOsPAPR_CRQ {
+    uint64_t qladdr;
+    uint32_t qsize;
+    uint32_t qnext;
+    int(*SendFunc)(struct VIOsPAPRDevice *vdev, uint8_t *crq);
+} VIOsPAPR_CRQ;
+
+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;
+    uint32_t rtce_window_size;
+    int (*init)(VIOsPAPRDevice *dev);
+    void (*reset)(VIOsPAPRDevice *dev);
+    int (*devnode)(VIOsPAPRDevice *dev, void *fdt, int node_off);
+} VIOsPAPRDeviceClass;
+
+struct VIOsPAPRDevice {
+    DeviceState qdev;
+    uint32_t reg;
+    uint32_t irq;
+    target_ulong signal_state;
+    VIOsPAPR_CRQ crq;
+    DMAContext *dma;
+};
+
+#define DEFINE_SPAPR_PROPERTIES(type, field)           \
+        DEFINE_PROP_UINT32("reg", type, field.reg, -1)
+
+struct VIOsPAPRBus {
+    BusState bus;
+    uint32_t next_reg;
+    int (*init)(VIOsPAPRDevice *dev);
+    int (*devnode)(VIOsPAPRDevice *dev, void *fdt, int node_off);
+};
+
+extern VIOsPAPRBus *spapr_vio_bus_init(void);
+extern VIOsPAPRDevice *spapr_vio_find_by_reg(VIOsPAPRBus *bus, uint32_t reg);
+extern int spapr_populate_vdevice(VIOsPAPRBus *bus, void *fdt);
+extern int spapr_populate_chosen_stdout(void *fdt, VIOsPAPRBus *bus);
+
+extern int spapr_vio_signal(VIOsPAPRDevice *dev, target_ulong mode);
+
+static inline qemu_irq spapr_vio_qirq(VIOsPAPRDevice *dev)
+{
+    return xics_get_qirq(spapr->icp, dev->irq);
+}
+
+static inline bool spapr_vio_dma_valid(VIOsPAPRDevice *dev, uint64_t taddr,
+                                       uint32_t size, DMADirection dir)
+{
+    return dma_memory_valid(dev->dma, taddr, size, dir);
+}
+
+static inline int spapr_vio_dma_read(VIOsPAPRDevice *dev, uint64_t taddr,
+                                     void *buf, uint32_t size)
+{
+    return (dma_memory_read(dev->dma, taddr, buf, size) != 0) ?
+        H_DEST_PARM : H_SUCCESS;
+}
+
+static inline int spapr_vio_dma_write(VIOsPAPRDevice *dev, uint64_t taddr,
+                                      const void *buf, uint32_t size)
+{
+    return (dma_memory_write(dev->dma, taddr, buf, size) != 0) ?
+        H_DEST_PARM : H_SUCCESS;
+}
+
+static inline int spapr_vio_dma_set(VIOsPAPRDevice *dev, uint64_t taddr,
+                                    uint8_t c, uint32_t size)
+{
+    return (dma_memory_set(dev->dma, taddr, c, size) != 0) ?
+        H_DEST_PARM : H_SUCCESS;
+}
+
+#define vio_stb(_dev, _addr, _val) (stb_dma((_dev)->dma, (_addr), (_val)))
+#define vio_sth(_dev, _addr, _val) (stw_be_dma((_dev)->dma, (_addr), (_val)))
+#define vio_stl(_dev, _addr, _val) (stl_be_dma((_dev)->dma, (_addr), (_val)))
+#define vio_stq(_dev, _addr, _val) (stq_be_dma((_dev)->dma, (_addr), (_val)))
+#define vio_ldq(_dev, _addr) (ldq_be_dma((_dev)->dma, (_addr)))
+
+int spapr_vio_send_crq(VIOsPAPRDevice *dev, uint8_t *crq);
+
+VIOsPAPRDevice *vty_lookup(sPAPREnvironment *spapr, target_ulong reg);
+void vty_putchars(VIOsPAPRDevice *sdev, uint8_t *buf, int len);
+void spapr_vty_create(VIOsPAPRBus *bus, CharDriverState *chardev);
+void spapr_vlan_create(VIOsPAPRBus *bus, NICInfo *nd);
+void spapr_vscsi_create(VIOsPAPRBus *bus);
+
+VIOsPAPRDevice *spapr_vty_get_default(VIOsPAPRBus *bus);
+
+void spapr_vio_quiesce(void);
+
+#endif /* _HW_SPAPR_VIO_H */
diff --git a/include/hw/ppc/xics.h b/include/hw/ppc/xics.h
new file mode 100644 (file)
index 0000000..6bce042
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator
+ *
+ * PAPR Virtualized Interrupt System, aka ICS/ICP aka xics
+ *
+ * Copyright (c) 2010,2011 David Gibson, IBM Corporation.
+ *
+ * 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 !defined(__XICS_H__)
+#define __XICS_H__
+
+#define XICS_IPI        0x2
+#define XICS_IRQ_BASE   0x10
+
+struct icp_state;
+
+qemu_irq xics_get_qirq(struct icp_state *icp, int irq);
+void xics_set_irq_type(struct icp_state *icp, int irq, bool lsi);
+
+struct icp_state *xics_system_init(int nr_servers, int nr_irqs);
+void xics_cpu_setup(struct icp_state *icp, PowerPCCPU *cpu);
+
+#endif /* __XICS_H__ */
diff --git a/include/hw/ptimer.h b/include/hw/ptimer.h
new file mode 100644 (file)
index 0000000..28fcaf1
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * 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"
+#include "migration/vmstate.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);
+
+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/include/hw/qdev-addr.h b/include/hw/qdev-addr.h
new file mode 100644 (file)
index 0000000..79708e6
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef HW_QDEV_ADDR_H
+#define HW_QDEV_ADDR_H 1
+
+#define DEFINE_PROP_TADDR(_n, _s, _f, _d)                               \
+    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_taddr, hwaddr)
+
+extern PropertyInfo qdev_prop_taddr;
+void qdev_prop_set_taddr(DeviceState *dev, const char *name, hwaddr value);
+
+#endif
diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h
new file mode 100644 (file)
index 0000000..547fbc7
--- /dev/null
@@ -0,0 +1,299 @@
+#ifndef QDEV_CORE_H
+#define QDEV_CORE_H
+
+#include "qemu/queue.h"
+#include "qemu/option.h"
+#include "qemu/typedefs.h"
+#include "qom/object.h"
+#include "hw/irq.h"
+#include "qapi/error.h"
+
+enum {
+    DEV_NVECTORS_UNSPECIFIED = -1,
+};
+
+#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 int (*qdev_initfn)(DeviceState *dev);
+typedef int (*qdev_event)(DeviceState *dev);
+typedef void (*qdev_resetfn)(DeviceState *dev);
+typedef void (*DeviceRealize)(DeviceState *dev, Error **errp);
+typedef void (*DeviceUnrealize)(DeviceState *dev, Error **errp);
+
+struct VMStateDescription;
+
+/**
+ * DeviceClass:
+ * @props: Properties accessing state fields.
+ * @realize: Callback function invoked when the #DeviceState:realized
+ * property is changed to %true. The default invokes @init if not %NULL.
+ * @unrealize: Callback function invoked when the #DeviceState:realized
+ * property is changed to %false.
+ * @init: Callback function invoked when the #DeviceState::realized property
+ * is changed to %true. Deprecated, new types inheriting directly from
+ * TYPE_DEVICE should use @realize instead, new leaf types should consult
+ * their respective parent type.
+ *
+ * # Realization #
+ * Devices are constructed in two stages,
+ * 1) object instantiation via object_initialize() and
+ * 2) device realization via #DeviceState:realized property.
+ * The former may not fail (it might assert or exit), the latter may return
+ * error information to the caller and must be re-entrant.
+ * Trivial field initializations should go into #TypeInfo.instance_init.
+ * Operations depending on @props static properties should go into @realize.
+ * After successful realization, setting static properties will fail.
+ *
+ * As an interim step, the #DeviceState:realized property is set by deprecated
+ * functions qdev_init() and qdev_init_nofail().
+ * In the future, devices will propagate this state change to their children
+ * and along busses they expose.
+ * The point in time will be deferred to machine creation, so that values
+ * set in @realize will not be introspectable beforehand. Therefore devices
+ * must not create children during @realize; they should initialize them via
+ * object_initialize() in their own #TypeInfo.instance_init and forward the
+ * realization events appropriately.
+ *
+ * The @init callback is considered private to a particular bus implementation
+ * (immediate abstract child types of TYPE_DEVICE). Derived leaf types set an
+ * "init" callback on their parent class instead.
+ *
+ * Any type may override the @realize and/or @unrealize callbacks but needs
+ * to call the parent type's implementation if keeping their functionality
+ * is desired. Refer to QOM documentation for further discussion and examples.
+ *
+ * <note>
+ *   <para>
+ * If a type derived directly from TYPE_DEVICE implements @realize, it does
+ * not need to implement @init and therefore does not need to store and call
+ * #DeviceClass' default @realize callback.
+ * For other types consult the documentation and implementation of the
+ * respective parent types.
+ *   </para>
+ * </note>
+ */
+typedef struct DeviceClass {
+    /*< private >*/
+    ObjectClass parent_class;
+    /*< public >*/
+
+    const char *fw_name;
+    const char *desc;
+    Property *props;
+    int no_user;
+
+    /* callbacks */
+    void (*reset)(DeviceState *dev);
+    DeviceRealize realize;
+    DeviceUnrealize unrealize;
+
+    /* device state */
+    const struct VMStateDescription *vmsd;
+
+    /* Private to qdev / bus.  */
+    qdev_initfn init; /* TODO remove, once users are converted to realize */
+    qdev_event unplug;
+    qdev_event exit;
+    const char *bus_type;
+} DeviceClass;
+
+/**
+ * DeviceState:
+ * @realized: Indicates whether the device has been fully constructed.
+ *
+ * This structure should not be accessed directly.  We declare it here
+ * so that it can be embedded in individual device state structures.
+ */
+struct DeviceState {
+    /*< private >*/
+    Object parent_obj;
+    /*< public >*/
+
+    const char *id;
+    bool realized;
+    QemuOpts *opts;
+    int hotplugged;
+    BusState *parent_bus;
+    int num_gpio_out;
+    qemu_irq *gpio_out;
+    int num_gpio_in;
+    qemu_irq *gpio_in;
+    QLIST_HEAD(, BusState) child_bus;
+    int num_child_bus;
+    int instance_id_alias;
+    int alias_required_for_version;
+};
+
+#define TYPE_BUS "bus"
+#define BUS(obj) OBJECT_CHECK(BusState, (obj), TYPE_BUS)
+#define BUS_CLASS(klass) OBJECT_CLASS_CHECK(BusClass, (klass), TYPE_BUS)
+#define BUS_GET_CLASS(obj) OBJECT_GET_CLASS(BusClass, (obj), TYPE_BUS)
+
+struct BusClass {
+    ObjectClass parent_class;
+
+    /* FIXME first arg should be BusState */
+    void (*print_dev)(Monitor *mon, DeviceState *dev, int indent);
+    char *(*get_dev_path)(DeviceState *dev);
+    /*
+     * This callback is used to create Open Firmware device path in accordance
+     * with OF spec http://forthworks.com/standards/of1275.pdf. Individual bus
+     * bindings can be found at http://playground.sun.com/1275/bindings/.
+     */
+    char *(*get_fw_dev_path)(DeviceState *dev);
+    int (*reset)(BusState *bus);
+    /* maximum devices allowed on the bus, 0: no limit. */
+    int max_dev;
+};
+
+typedef struct BusChild {
+    DeviceState *child;
+    int index;
+    QTAILQ_ENTRY(BusChild) sibling;
+} BusChild;
+
+/**
+ * BusState:
+ */
+struct BusState {
+    Object obj;
+    DeviceState *parent;
+    const char *name;
+    int allow_hotplug;
+    int max_index;
+    QTAILQ_HEAD(ChildrenHead, BusChild) children;
+    QLIST_ENTRY(BusState) sibling;
+};
+
+struct Property {
+    const char   *name;
+    PropertyInfo *info;
+    int          offset;
+    uint8_t      bitnr;
+    uint8_t      qtype;
+    int64_t      defval;
+    int          arrayoffset;
+    PropertyInfo *arrayinfo;
+    int          arrayfieldsize;
+};
+
+struct PropertyInfo {
+    const char *name;
+    const char *legacy_name;
+    const char **enum_table;
+    int (*parse)(DeviceState *dev, Property *prop, const char *str);
+    int (*print)(DeviceState *dev, Property *prop, char *dest, size_t len);
+    ObjectPropertyAccessor *get;
+    ObjectPropertyAccessor *set;
+    ObjectPropertyRelease *release;
+};
+
+typedef struct GlobalProperty {
+    const char *driver;
+    const char *property;
+    const char *value;
+    QTAILQ_ENTRY(GlobalProperty) next;
+} GlobalProperty;
+
+/*** Board API.  This should go away once we have a machine config file.  ***/
+
+DeviceState *qdev_create(BusState *bus, const char *name);
+DeviceState *qdev_try_create(BusState *bus, const char *name);
+int qdev_init(DeviceState *dev) QEMU_WARN_UNUSED_RESULT;
+void qdev_init_nofail(DeviceState *dev);
+void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id,
+                                 int required_for_version);
+void qdev_unplug(DeviceState *dev, Error **errp);
+void qdev_free(DeviceState *dev);
+int qdev_simple_unplug_cb(DeviceState *dev);
+void qdev_machine_creation_done(void);
+bool qdev_machine_modified(void);
+
+qemu_irq qdev_get_gpio_in(DeviceState *dev, int n);
+void qdev_connect_gpio_out(DeviceState *dev, int n, qemu_irq pin);
+
+BusState *qdev_get_child_bus(DeviceState *dev, const char *name);
+
+/*** Device API.  ***/
+
+/* Register device properties.  */
+/* GPIO inputs also double as IRQ sinks.  */
+void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n);
+void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n);
+
+BusState *qdev_get_parent_bus(DeviceState *dev);
+
+/*** BUS API. ***/
+
+DeviceState *qdev_find_recursive(BusState *bus, const char *id);
+
+/* Returns 0 to walk children, > 0 to skip walk, < 0 to terminate walk. */
+typedef int (qbus_walkerfn)(BusState *bus, void *opaque);
+typedef int (qdev_walkerfn)(DeviceState *dev, void *opaque);
+
+void qbus_create_inplace(void *bus, const char *typename,
+                         DeviceState *parent, const char *name);
+BusState *qbus_create(const char *typename, DeviceState *parent, const char *name);
+/* Returns > 0 if either devfn or busfn skip walk somewhere in cursion,
+ *         < 0 if either devfn or busfn terminate walk somewhere in cursion,
+ *           0 otherwise. */
+int qbus_walk_children(BusState *bus, qdev_walkerfn *devfn,
+                       qbus_walkerfn *busfn, void *opaque);
+int qdev_walk_children(DeviceState *dev, qdev_walkerfn *devfn,
+                       qbus_walkerfn *busfn, void *opaque);
+void qdev_reset_all(DeviceState *dev);
+
+/**
+ * @qbus_reset_all:
+ * @bus: Bus to be reset.
+ *
+ * Reset @bus and perform a bus-level ("hard") reset of all devices connected
+ * to it, including recursive processing of all buses below @bus itself.  A
+ * hard reset means that qbus_reset_all will reset all state of the device.
+ * For PCI devices, for example, this will include the base address registers
+ * or configuration space.
+ */
+void qbus_reset_all(BusState *bus);
+void qbus_reset_all_fn(void *opaque);
+
+void qbus_free(BusState *bus);
+
+#define FROM_QBUS(type, dev) DO_UPCAST(type, qbus, dev)
+
+/* This should go away once we get rid of the NULL bus hack */
+BusState *sysbus_get_default(void);
+
+char *qdev_get_fw_dev_path(DeviceState *dev);
+
+/**
+ * @qdev_machine_init
+ *
+ * Initialize platform devices before machine init.  This is a hack until full
+ * support for composition is added.
+ */
+void qdev_machine_init(void);
+
+/**
+ * @device_reset
+ *
+ * Reset a single device (by calling the reset method).
+ */
+void device_reset(DeviceState *dev);
+
+const struct VMStateDescription *qdev_get_vmsd(DeviceState *dev);
+
+const char *qdev_fw_name(DeviceState *dev);
+
+Object *qdev_get_machine(void);
+
+/* FIXME: make this a link<> */
+void qdev_set_parent_bus(DeviceState *dev, BusState *bus);
+
+extern int qdev_hotplug;
+
+char *qdev_get_dev_path(DeviceState *dev);
+
+#endif
diff --git a/include/hw/qdev-dma.h b/include/hw/qdev-dma.h
new file mode 100644 (file)
index 0000000..6812735
--- /dev/null
@@ -0,0 +1,10 @@
+/*
+ * Support for dma_addr_t typed properties
+ *
+ * Copyright (C) 2012 David Gibson, IBM Corporation.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+#define DEFINE_PROP_DMAADDR(_n, _s, _f, _d)                               \
+    DEFINE_PROP_HEX64(_n, _s, _f, _d)
diff --git a/include/hw/qdev-properties.h b/include/hw/qdev-properties.h
new file mode 100644 (file)
index 0000000..a379339
--- /dev/null
@@ -0,0 +1,182 @@
+#ifndef QEMU_QDEV_PROPERTIES_H
+#define QEMU_QDEV_PROPERTIES_H
+
+#include "hw/qdev-core.h"
+
+/*** qdev-properties.c ***/
+
+extern PropertyInfo qdev_prop_bit;
+extern PropertyInfo qdev_prop_uint8;
+extern PropertyInfo qdev_prop_uint16;
+extern PropertyInfo qdev_prop_uint32;
+extern PropertyInfo qdev_prop_int32;
+extern PropertyInfo qdev_prop_uint64;
+extern PropertyInfo qdev_prop_hex8;
+extern PropertyInfo qdev_prop_hex32;
+extern PropertyInfo qdev_prop_hex64;
+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_bios_chs_trans;
+extern PropertyInfo qdev_prop_drive;
+extern PropertyInfo qdev_prop_netdev;
+extern PropertyInfo qdev_prop_vlan;
+extern PropertyInfo qdev_prop_pci_devfn;
+extern PropertyInfo qdev_prop_blocksize;
+extern PropertyInfo qdev_prop_pci_host_devaddr;
+extern PropertyInfo qdev_prop_arraylen;
+
+#define DEFINE_PROP(_name, _state, _field, _prop, _type) { \
+        .name      = (_name),                                    \
+        .info      = &(_prop),                                   \
+        .offset    = offsetof(_state, _field)                    \
+            + type_check(_type, typeof_field(_state, _field)),   \
+        }
+#define DEFINE_PROP_DEFAULT(_name, _state, _field, _defval, _prop, _type) { \
+        .name      = (_name),                                           \
+        .info      = &(_prop),                                          \
+        .offset    = offsetof(_state, _field)                           \
+            + type_check(_type,typeof_field(_state, _field)),           \
+        .qtype     = QTYPE_QINT,                                        \
+        .defval    = (_type)_defval,                                    \
+        }
+#define DEFINE_PROP_BIT(_name, _state, _field, _bit, _defval) {  \
+        .name      = (_name),                                    \
+        .info      = &(qdev_prop_bit),                           \
+        .bitnr    = (_bit),                                      \
+        .offset    = offsetof(_state, _field)                    \
+            + type_check(uint32_t,typeof_field(_state, _field)), \
+        .qtype     = QTYPE_QBOOL,                                \
+        .defval    = (bool)_defval,                              \
+        }
+
+#define PROP_ARRAY_LEN_PREFIX "len-"
+
+/**
+ * DEFINE_PROP_ARRAY:
+ * @_name: name of the array
+ * @_state: name of the device state structure type
+ * @_field: uint32_t field in @_state to hold the array length
+ * @_arrayfield: field in @_state (of type '@_arraytype *') which
+ *               will point to the array
+ * @_arrayprop: PropertyInfo defining what property the array elements have
+ * @_arraytype: C type of the array elements
+ *
+ * Define device properties for a variable-length array _name.  A
+ * static property "len-arrayname" is defined. When the device creator
+ * sets this property to the desired length of array, further dynamic
+ * properties "arrayname[0]", "arrayname[1]", ...  are defined so the
+ * device creator can set the array element values. Setting the
+ * "len-arrayname" property more than once is an error.
+ *
+ * When the array length is set, the @_field member of the device
+ * struct is set to the array length, and @_arrayfield is set to point
+ * to (zero-initialised) memory allocated for the array.  For a zero
+ * length array, @_field will be set to 0 and @_arrayfield to NULL.
+ * It is the responsibility of the device deinit code to free the
+ * @_arrayfield memory.
+ */
+#define DEFINE_PROP_ARRAY(_name, _state, _field,                        \
+                          _arrayfield, _arrayprop, _arraytype) {        \
+        .name = (PROP_ARRAY_LEN_PREFIX _name),                          \
+        .info = &(qdev_prop_arraylen),                                  \
+        .offset = offsetof(_state, _field)                              \
+            + type_check(uint32_t, typeof_field(_state, _field)),       \
+        .qtype = QTYPE_QINT,                                            \
+        .arrayinfo = &(_arrayprop),                                     \
+        .arrayfieldsize = sizeof(_arraytype),                           \
+        .arrayoffset = offsetof(_state, _arrayfield),                   \
+        }
+
+#define DEFINE_PROP_UINT8(_n, _s, _f, _d)                       \
+    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_uint8, uint8_t)
+#define DEFINE_PROP_UINT16(_n, _s, _f, _d)                      \
+    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_uint16, uint16_t)
+#define DEFINE_PROP_UINT32(_n, _s, _f, _d)                      \
+    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_uint32, uint32_t)
+#define DEFINE_PROP_INT32(_n, _s, _f, _d)                      \
+    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_int32, int32_t)
+#define DEFINE_PROP_UINT64(_n, _s, _f, _d)                      \
+    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_uint64, uint64_t)
+#define DEFINE_PROP_HEX8(_n, _s, _f, _d)                       \
+    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_hex8, uint8_t)
+#define DEFINE_PROP_HEX32(_n, _s, _f, _d)                       \
+    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_hex32, uint32_t)
+#define DEFINE_PROP_HEX64(_n, _s, _f, _d)                       \
+    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_hex64, uint64_t)
+#define DEFINE_PROP_PCI_DEVFN(_n, _s, _f, _d)                   \
+    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_pci_devfn, int32_t)
+
+#define DEFINE_PROP_PTR(_n, _s, _f)             \
+    DEFINE_PROP(_n, _s, _f, qdev_prop_ptr, void*)
+#define DEFINE_PROP_CHR(_n, _s, _f)             \
+    DEFINE_PROP(_n, _s, _f, qdev_prop_chr, CharDriverState*)
+#define DEFINE_PROP_STRING(_n, _s, _f)             \
+    DEFINE_PROP(_n, _s, _f, qdev_prop_string, char*)
+#define DEFINE_PROP_NETDEV(_n, _s, _f)             \
+    DEFINE_PROP(_n, _s, _f, qdev_prop_netdev, NICPeers)
+#define DEFINE_PROP_VLAN(_n, _s, _f)             \
+    DEFINE_PROP(_n, _s, _f, qdev_prop_vlan, NICPeers)
+#define DEFINE_PROP_DRIVE(_n, _s, _f) \
+    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_BIOS_CHS_TRANS(_n, _s, _f, _d) \
+    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_bios_chs_trans, int)
+#define DEFINE_PROP_BLOCKSIZE(_n, _s, _f, _d) \
+    DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_blocksize, uint16_t)
+#define DEFINE_PROP_PCI_HOST_DEVADDR(_n, _s, _f) \
+    DEFINE_PROP(_n, _s, _f, qdev_prop_pci_host_devaddr, PCIHostDeviceAddress)
+
+#define DEFINE_PROP_END_OF_LIST()               \
+    {}
+
+/* Set properties between creation and init.  */
+void *qdev_get_prop_ptr(DeviceState *dev, Property *prop);
+int qdev_prop_parse(DeviceState *dev, const char *name, const char *value);
+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);
+void qdev_prop_set_uint32(DeviceState *dev, const char *name, uint32_t value);
+void qdev_prop_set_int32(DeviceState *dev, const char *name, int32_t value);
+void qdev_prop_set_uint64(DeviceState *dev, const char *name, uint64_t value);
+void qdev_prop_set_string(DeviceState *dev, const char *name, const char *value);
+void qdev_prop_set_chr(DeviceState *dev, const char *name, CharDriverState *value);
+void qdev_prop_set_netdev(DeviceState *dev, const char *name, NetClientState *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_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_register_global(GlobalProperty *prop);
+void qdev_prop_register_global_list(GlobalProperty *props);
+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);
+
+/**
+ * @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_prop_set_after_realize:
+ * @dev: device
+ * @name: name of property
+ * @errp: indirect pointer to Error to be set
+ * Set the Error object to report that an attempt was made to set a property
+ * on a device after it has already been realized. This is a utility function
+ * which allows property-setter functions to easily report the error in
+ * a friendly format identifying both the device and the property.
+ */
+void qdev_prop_set_after_realize(DeviceState *dev, const char *name,
+                                 Error **errp);
+#endif
diff --git a/include/hw/qdev.h b/include/hw/qdev.h
new file mode 100644 (file)
index 0000000..5cb8b08
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef QDEV_H
+#define QDEV_H
+
+#include "hw/hw.h"
+#include "hw/qdev-core.h"
+#include "hw/qdev-properties.h"
+
+#endif
diff --git a/include/hw/s390x/event-facility.h b/include/hw/s390x/event-facility.h
new file mode 100644 (file)
index 0000000..791ab2a
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * SCLP
+ *    Event Facility definitions
+ *
+ * Copyright IBM, Corp. 2012
+ *
+ * Authors:
+ *  Heinz Graalfs <graalfs@de.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at your
+ * option) any later version.  See the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef HW_S390_SCLP_EVENT_FACILITY_H
+#define HW_S390_SCLP_EVENT_FACILITY_H
+
+#include <hw/qdev.h>
+#include "qemu/thread.h"
+
+/* SCLP event types */
+#define SCLP_EVENT_ASCII_CONSOLE_DATA           0x1a
+#define SCLP_EVENT_SIGNAL_QUIESCE               0x1d
+
+/* SCLP event masks */
+#define SCLP_EVENT_MASK_SIGNAL_QUIESCE          0x00000008
+#define SCLP_EVENT_MASK_MSG_ASCII               0x00000040
+
+#define SCLP_UNCONDITIONAL_READ                 0x00
+#define SCLP_SELECTIVE_READ                     0x01
+
+#define TYPE_SCLP_EVENT "s390-sclp-event-type"
+#define SCLP_EVENT(obj) \
+     OBJECT_CHECK(SCLPEvent, (obj), TYPE_SCLP_EVENT)
+#define SCLP_EVENT_CLASS(klass) \
+     OBJECT_CLASS_CHECK(SCLPEventClass, (klass), TYPE_SCLP_EVENT)
+#define SCLP_EVENT_GET_CLASS(obj) \
+     OBJECT_GET_CLASS(SCLPEventClass, (obj), TYPE_SCLP_EVENT)
+
+typedef struct WriteEventMask {
+    SCCBHeader h;
+    uint16_t _reserved;
+    uint16_t mask_length;
+    uint32_t cp_receive_mask;
+    uint32_t cp_send_mask;
+    uint32_t send_mask;
+    uint32_t receive_mask;
+} QEMU_PACKED WriteEventMask;
+
+typedef struct EventBufferHeader {
+    uint16_t length;
+    uint8_t  type;
+    uint8_t  flags;
+    uint16_t _reserved;
+} QEMU_PACKED EventBufferHeader;
+
+typedef struct WriteEventData {
+    SCCBHeader h;
+    EventBufferHeader ebh;
+} QEMU_PACKED WriteEventData;
+
+typedef struct ReadEventData {
+    SCCBHeader h;
+    EventBufferHeader ebh;
+    uint32_t mask;
+} QEMU_PACKED ReadEventData;
+
+typedef struct SCLPEvent {
+    DeviceState qdev;
+    bool event_pending;
+    uint32_t event_type;
+    char *name;
+} SCLPEvent;
+
+typedef struct SCLPEventClass {
+    DeviceClass parent_class;
+    int (*init)(SCLPEvent *event);
+    int (*exit)(SCLPEvent *event);
+
+    /* get SCLP's send mask */
+    unsigned int (*get_send_mask)(void);
+
+    /* get SCLP's receive mask */
+    unsigned int (*get_receive_mask)(void);
+
+    int (*read_event_data)(SCLPEvent *event, EventBufferHeader *evt_buf_hdr,
+                           int *slen);
+
+    int (*write_event_data)(SCLPEvent *event, EventBufferHeader *evt_buf_hdr);
+
+    /* returns the supported event type */
+    int (*event_type)(void);
+
+} SCLPEventClass;
+
+#endif
diff --git a/include/hw/s390x/sclp.h b/include/hw/s390x/sclp.h
new file mode 100644 (file)
index 0000000..231a38a
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * SCLP Support
+ *
+ * Copyright IBM, Corp. 2012
+ *
+ * Authors:
+ *  Christian Borntraeger <borntraeger@de.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at your
+ * option) any later version.  See the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef HW_S390_SCLP_H
+#define HW_S390_SCLP_H
+
+#include <hw/sysbus.h>
+#include <hw/qdev.h>
+
+/* SCLP command codes */
+#define SCLP_CMDW_READ_SCP_INFO                 0x00020001
+#define SCLP_CMDW_READ_SCP_INFO_FORCED          0x00120001
+#define SCLP_CMD_READ_EVENT_DATA                0x00770005
+#define SCLP_CMD_WRITE_EVENT_DATA               0x00760005
+#define SCLP_CMD_READ_EVENT_DATA                0x00770005
+#define SCLP_CMD_WRITE_EVENT_DATA               0x00760005
+#define SCLP_CMD_WRITE_EVENT_MASK               0x00780005
+
+/* SCLP response codes */
+#define SCLP_RC_NORMAL_READ_COMPLETION          0x0010
+#define SCLP_RC_NORMAL_COMPLETION               0x0020
+#define SCLP_RC_INVALID_SCLP_COMMAND            0x01f0
+#define SCLP_RC_CONTAINED_EQUIPMENT_CHECK       0x0340
+#define SCLP_RC_INSUFFICIENT_SCCB_LENGTH        0x0300
+#define SCLP_RC_INVALID_FUNCTION                0x40f0
+#define SCLP_RC_NO_EVENT_BUFFERS_STORED         0x60f0
+#define SCLP_RC_INVALID_SELECTION_MASK          0x70f0
+#define SCLP_RC_INCONSISTENT_LENGTHS            0x72f0
+#define SCLP_RC_EVENT_BUFFER_SYNTAX_ERROR       0x73f0
+#define SCLP_RC_INVALID_MASK_LENGTH             0x74f0
+
+
+/* Service Call Control Block (SCCB) and its elements */
+
+#define SCCB_SIZE 4096
+
+#define SCLP_VARIABLE_LENGTH_RESPONSE           0x80
+#define SCLP_EVENT_BUFFER_ACCEPTED              0x80
+
+#define SCLP_FC_NORMAL_WRITE                    0
+
+/*
+ * Normally packed structures are not the right thing to do, since all code
+ * must take care of endianness. We cannot use ldl_phys and friends for two
+ * reasons, though:
+ * - some of the embedded structures below the SCCB can appear multiple times
+ *   at different locations, so there is no fixed offset
+ * - we work on a private copy of the SCCB, since there are several length
+ *   fields, that would cause a security nightmare if we allow the guest to
+ *   alter the structure while we parse it. We cannot use ldl_p and friends
+ *   either without doing pointer arithmetics
+ * So we have to double check that all users of sclp data structures use the
+ * right endianness wrappers.
+ */
+typedef struct SCCBHeader {
+    uint16_t length;
+    uint8_t function_code;
+    uint8_t control_mask[3];
+    uint16_t response_code;
+} QEMU_PACKED SCCBHeader;
+
+#define SCCB_DATA_LEN (SCCB_SIZE - sizeof(SCCBHeader))
+
+typedef struct ReadInfo {
+    SCCBHeader h;
+    uint16_t rnmax;
+    uint8_t rnsize;
+} QEMU_PACKED ReadInfo;
+
+typedef struct SCCB {
+    SCCBHeader h;
+    char data[SCCB_DATA_LEN];
+ } QEMU_PACKED SCCB;
+
+static inline int sccb_data_len(SCCB *sccb)
+{
+    return be16_to_cpu(sccb->h.length) - sizeof(sccb->h);
+}
+
+#define TYPE_DEVICE_S390_SCLP "s390-sclp-device"
+#define SCLP_S390_DEVICE(obj) \
+     OBJECT_CHECK(S390SCLPDevice, (obj), TYPE_DEVICE_S390_SCLP)
+#define SCLP_S390_DEVICE_CLASS(klass) \
+     OBJECT_CLASS_CHECK(S390SCLPDeviceClass, (klass), \
+             TYPE_DEVICE_S390_SCLP)
+#define SCLP_S390_DEVICE_GET_CLASS(obj) \
+     OBJECT_GET_CLASS(S390SCLPDeviceClass, (obj), \
+             TYPE_DEVICE_S390_SCLP)
+
+typedef struct SCLPEventFacility SCLPEventFacility;
+
+typedef struct S390SCLPDevice {
+    SysBusDevice busdev;
+    SCLPEventFacility *ef;
+    void (*sclp_command_handler)(SCLPEventFacility *ef, SCCB *sccb,
+                                 uint64_t code);
+    bool (*event_pending)(SCLPEventFacility *ef);
+} S390SCLPDevice;
+
+typedef struct S390SCLPDeviceClass {
+    DeviceClass qdev;
+    int (*init)(S390SCLPDevice *sdev);
+} S390SCLPDeviceClass;
+
+void s390_sclp_init(void);
+void sclp_service_interrupt(uint32_t sccb);
+
+#endif
diff --git a/include/hw/scsi/esp.h b/include/hw/scsi/esp.h
new file mode 100644 (file)
index 0000000..e079fb8
--- /dev/null
@@ -0,0 +1,132 @@
+#ifndef QEMU_HW_ESP_H
+#define QEMU_HW_ESP_H
+
+#include "hw/scsi/scsi.h"
+
+/* esp.c */
+#define ESP_MAX_DEVS 7
+typedef void (*ESPDMAMemoryReadWriteFunc)(void *opaque, uint8_t *buf, int len);
+void esp_init(hwaddr espaddr, int it_shift,
+              ESPDMAMemoryReadWriteFunc dma_memory_read,
+              ESPDMAMemoryReadWriteFunc dma_memory_write,
+              void *dma_opaque, qemu_irq irq, qemu_irq *reset,
+              qemu_irq *dma_enable);
+
+#define ESP_REGS 16
+#define TI_BUFSZ 16
+
+typedef struct ESPState ESPState;
+
+struct ESPState {
+    uint8_t rregs[ESP_REGS];
+    uint8_t wregs[ESP_REGS];
+    qemu_irq irq;
+    uint8_t chip_id;
+    int32_t ti_size;
+    uint32_t ti_rptr, ti_wptr;
+    uint32_t status;
+    uint32_t dma;
+    uint8_t ti_buf[TI_BUFSZ];
+    SCSIBus bus;
+    SCSIDevice *current_dev;
+    SCSIRequest *current_req;
+    uint8_t cmdbuf[TI_BUFSZ];
+    uint32_t cmdlen;
+    uint32_t do_cmd;
+
+    /* The amount of data left in the current DMA transfer.  */
+    uint32_t dma_left;
+    /* The size of the current DMA transfer.  Zero if no transfer is in
+       progress.  */
+    uint32_t dma_counter;
+    int dma_enabled;
+
+    uint32_t async_len;
+    uint8_t *async_buf;
+
+    ESPDMAMemoryReadWriteFunc dma_memory_read;
+    ESPDMAMemoryReadWriteFunc dma_memory_write;
+    void *dma_opaque;
+    void (*dma_cb)(ESPState *s);
+};
+
+#define ESP_TCLO   0x0
+#define ESP_TCMID  0x1
+#define ESP_FIFO   0x2
+#define ESP_CMD    0x3
+#define ESP_RSTAT  0x4
+#define ESP_WBUSID 0x4
+#define ESP_RINTR  0x5
+#define ESP_WSEL   0x5
+#define ESP_RSEQ   0x6
+#define ESP_WSYNTP 0x6
+#define ESP_RFLAGS 0x7
+#define ESP_WSYNO  0x7
+#define ESP_CFG1   0x8
+#define ESP_RRES1  0x9
+#define ESP_WCCF   0x9
+#define ESP_RRES2  0xa
+#define ESP_WTEST  0xa
+#define ESP_CFG2   0xb
+#define ESP_CFG3   0xc
+#define ESP_RES3   0xd
+#define ESP_TCHI   0xe
+#define ESP_RES4   0xf
+
+#define CMD_DMA 0x80
+#define CMD_CMD 0x7f
+
+#define CMD_NOP      0x00
+#define CMD_FLUSH    0x01
+#define CMD_RESET    0x02
+#define CMD_BUSRESET 0x03
+#define CMD_TI       0x10
+#define CMD_ICCS     0x11
+#define CMD_MSGACC   0x12
+#define CMD_PAD      0x18
+#define CMD_SATN     0x1a
+#define CMD_RSTATN   0x1b
+#define CMD_SEL      0x41
+#define CMD_SELATN   0x42
+#define CMD_SELATNS  0x43
+#define CMD_ENSEL    0x44
+#define CMD_DISSEL   0x45
+
+#define STAT_DO 0x00
+#define STAT_DI 0x01
+#define STAT_CD 0x02
+#define STAT_ST 0x03
+#define STAT_MO 0x06
+#define STAT_MI 0x07
+#define STAT_PIO_MASK 0x06
+
+#define STAT_TC 0x10
+#define STAT_PE 0x20
+#define STAT_GE 0x40
+#define STAT_INT 0x80
+
+#define BUSID_DID 0x07
+
+#define INTR_FC 0x08
+#define INTR_BS 0x10
+#define INTR_DC 0x20
+#define INTR_RST 0x80
+
+#define SEQ_0 0x0
+#define SEQ_CD 0x4
+
+#define CFG1_RESREPT 0x40
+
+#define TCHI_FAS100A 0x4
+#define TCHI_AM53C974 0x12
+
+void esp_dma_enable(ESPState *s, int irq, int level);
+void esp_request_cancelled(SCSIRequest *req);
+void esp_command_complete(SCSIRequest *req, uint32_t status, size_t resid);
+void esp_transfer_data(SCSIRequest *req, uint32_t len);
+void esp_hard_reset(ESPState *s);
+uint64_t esp_reg_read(ESPState *s, uint32_t saddr);
+void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val);
+extern const VMStateDescription vmstate_esp;
+
+#endif
diff --git a/include/hw/scsi/scsi.h b/include/hw/scsi/scsi.h
new file mode 100644 (file)
index 0000000..3bda1c4
--- /dev/null
@@ -0,0 +1,256 @@
+#ifndef QEMU_HW_SCSI_H
+#define QEMU_HW_SCSI_H
+
+#include "hw/qdev.h"
+#include "block/block.h"
+#include "hw/block/block.h"
+#include "sysemu/sysemu.h"
+
+#define MAX_SCSI_DEVS  255
+
+#define SCSI_CMD_BUF_SIZE     16
+
+typedef struct SCSIBus SCSIBus;
+typedef struct SCSIBusInfo SCSIBusInfo;
+typedef struct SCSICommand SCSICommand;
+typedef struct SCSIDevice SCSIDevice;
+typedef struct SCSIRequest SCSIRequest;
+typedef struct SCSIReqOps SCSIReqOps;
+
+enum SCSIXferMode {
+    SCSI_XFER_NONE,      /*  TEST_UNIT_READY, ...            */
+    SCSI_XFER_FROM_DEV,  /*  READ, INQUIRY, MODE_SENSE, ...  */
+    SCSI_XFER_TO_DEV,    /*  WRITE, MODE_SELECT, ...         */
+};
+
+typedef struct SCSISense {
+    uint8_t key;
+    uint8_t asc;
+    uint8_t ascq;
+} SCSISense;
+
+#define SCSI_SENSE_BUF_SIZE 96
+
+struct SCSICommand {
+    uint8_t buf[SCSI_CMD_BUF_SIZE];
+    int len;
+    size_t xfer;
+    uint64_t lba;
+    enum SCSIXferMode mode;
+};
+
+struct SCSIRequest {
+    SCSIBus           *bus;
+    SCSIDevice        *dev;
+    const SCSIReqOps  *ops;
+    uint32_t          refcount;
+    uint32_t          tag;
+    uint32_t          lun;
+    uint32_t          status;
+    size_t            resid;
+    SCSICommand       cmd;
+    BlockDriverAIOCB  *aiocb;
+    QEMUSGList        *sg;
+    bool              dma_started;
+    uint8_t sense[SCSI_SENSE_BUF_SIZE];
+    uint32_t sense_len;
+    bool enqueued;
+    bool io_canceled;
+    bool retry;
+    void *hba_private;
+    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;
+    VMChangeStateEntry *vmsentry;
+    QEMUBH *bh;
+    uint32_t id;
+    BlockConf conf;
+    SCSISense unit_attention;
+    bool sense_is_ua;
+    uint8_t sense[SCSI_SENSE_BUF_SIZE];
+    uint32_t sense_len;
+    QTAILQ_HEAD(, SCSIRequest) requests;
+    uint32_t channel;
+    uint32_t lun;
+    int blocksize;
+    int type;
+    uint64_t max_lba;
+};
+
+extern const VMStateDescription vmstate_scsi_device;
+
+#define VMSTATE_SCSI_DEVICE(_field, _state) {                        \
+    .name       = (stringify(_field)),                               \
+    .size       = sizeof(SCSIDevice),                                \
+    .vmsd       = &vmstate_scsi_device,                              \
+    .flags      = VMS_STRUCT,                                        \
+    .offset     = vmstate_offset_value(_state, _field, SCSIDevice),  \
+}
+
+/* cdrom.c */
+int cdrom_read_toc(int nb_sectors, uint8_t *buf, int msf, int start_track);
+int cdrom_read_toc_raw(int nb_sectors, uint8_t *buf, int msf, int session_num);
+
+/* scsi-bus.c */
+struct SCSIReqOps {
+    size_t size;
+    void (*free_req)(SCSIRequest *req);
+    int32_t (*send_command)(SCSIRequest *req, uint8_t *buf);
+    void (*read_data)(SCSIRequest *req);
+    void (*write_data)(SCSIRequest *req);
+    void (*cancel_io)(SCSIRequest *req);
+    uint8_t *(*get_buf)(SCSIRequest *req);
+
+    void (*save_request)(QEMUFile *f, SCSIRequest *req);
+    void (*load_request)(QEMUFile *f, SCSIRequest *req);
+};
+
+struct SCSIBusInfo {
+    int tcq;
+    int max_channel, max_target, max_lun;
+    void (*transfer_data)(SCSIRequest *req, uint32_t arg);
+    void (*complete)(SCSIRequest *req, uint32_t arg, size_t resid);
+    void (*cancel)(SCSIRequest *req);
+    void (*hotplug)(SCSIBus *bus, SCSIDevice *dev);
+    void (*hot_unplug)(SCSIBus *bus, SCSIDevice *dev);
+    void (*change)(SCSIBus *bus, SCSIDevice *dev, SCSISense sense);
+    QEMUSGList *(*get_sg_list)(SCSIRequest *req);
+
+    void (*save_request)(QEMUFile *f, SCSIRequest *req);
+    void *(*load_request)(QEMUFile *f, SCSIRequest *req);
+    void (*free_request)(SCSIBus *bus, void *priv);
+};
+
+#define TYPE_SCSI_BUS "SCSI"
+#define SCSI_BUS(obj) OBJECT_CHECK(SCSIBus, (obj), TYPE_SCSI_BUS)
+
+struct SCSIBus {
+    BusState qbus;
+    int busnr;
+
+    SCSISense unit_attention;
+    const SCSIBusInfo *info;
+};
+
+void scsi_bus_new(SCSIBus *bus, DeviceState *host, const SCSIBusInfo *info);
+
+static inline SCSIBus *scsi_bus_from_device(SCSIDevice *d)
+{
+    return DO_UPCAST(SCSIBus, qbus, d->qdev.parent_bus);
+}
+
+SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockDriverState *bdrv,
+                                      int unit, bool removable, int bootindex,
+                                      const char *serial);
+int scsi_bus_legacy_handle_cmdline(SCSIBus *bus);
+
+/*
+ * Predefined sense codes
+ */
+
+/* No sense data available */
+extern const struct SCSISense sense_code_NO_SENSE;
+/* LUN not ready, Manual intervention required */
+extern const struct SCSISense sense_code_LUN_NOT_READY;
+/* LUN not ready, Medium not present */
+extern const struct SCSISense sense_code_NO_MEDIUM;
+/* LUN not ready, medium removal prevented */
+extern const struct SCSISense sense_code_NOT_READY_REMOVAL_PREVENTED;
+/* Hardware error, internal target failure */
+extern const struct SCSISense sense_code_TARGET_FAILURE;
+/* Illegal request, invalid command operation code */
+extern const struct SCSISense sense_code_INVALID_OPCODE;
+/* Illegal request, LBA out of range */
+extern const struct SCSISense sense_code_LBA_OUT_OF_RANGE;
+/* Illegal request, Invalid field in CDB */
+extern const struct SCSISense sense_code_INVALID_FIELD;
+/* Illegal request, Invalid field in parameter list */
+extern const struct SCSISense sense_code_INVALID_PARAM;
+/* Illegal request, Parameter list length error */
+extern const struct SCSISense sense_code_INVALID_PARAM_LEN;
+/* Illegal request, LUN not supported */
+extern const struct SCSISense sense_code_LUN_NOT_SUPPORTED;
+/* Illegal request, Saving parameters not supported */
+extern const struct SCSISense sense_code_SAVING_PARAMS_NOT_SUPPORTED;
+/* Illegal request, Incompatible format */
+extern const struct SCSISense sense_code_INCOMPATIBLE_FORMAT;
+/* Illegal request, medium removal prevented */
+extern const struct SCSISense sense_code_ILLEGAL_REQ_REMOVAL_PREVENTED;
+/* Command aborted, I/O process terminated */
+extern const struct SCSISense sense_code_IO_ERROR;
+/* Command aborted, I_T Nexus loss occurred */
+extern const struct SCSISense sense_code_I_T_NEXUS_LOSS;
+/* Command aborted, Logical Unit failure */
+extern const struct SCSISense sense_code_LUN_FAILURE;
+/* LUN not ready, Capacity data has changed */
+extern const struct SCSISense sense_code_CAPACITY_CHANGED;
+/* LUN not ready, Medium not present */
+extern const struct SCSISense sense_code_UNIT_ATTENTION_NO_MEDIUM;
+/* Unit attention, Power on, reset or bus device reset occurred */
+extern const struct SCSISense sense_code_RESET;
+/* Unit attention, Medium may have changed*/
+extern const struct SCSISense sense_code_MEDIUM_CHANGED;
+/* Unit attention, Reported LUNs data has changed */
+extern const struct SCSISense sense_code_REPORTED_LUNS_CHANGED;
+/* Unit attention, Device internal reset */
+extern const struct SCSISense sense_code_DEVICE_INTERNAL_RESET;
+/* Data Protection, Write Protected */
+extern const struct SCSISense sense_code_WRITE_PROTECTED;
+
+#define SENSE_CODE(x) sense_code_ ## x
+
+uint32_t scsi_data_cdb_length(uint8_t *buf);
+uint32_t scsi_cdb_length(uint8_t *buf);
+int scsi_sense_valid(SCSISense sense);
+int scsi_build_sense(uint8_t *in_buf, int in_len,
+                     uint8_t *buf, int len, bool fixed);
+
+SCSIRequest *scsi_req_alloc(const SCSIReqOps *reqops, SCSIDevice *d,
+                            uint32_t tag, uint32_t lun, void *hba_private);
+SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun,
+                          uint8_t *buf, void *hba_private);
+int32_t scsi_req_enqueue(SCSIRequest *req);
+void scsi_req_free(SCSIRequest *req);
+SCSIRequest *scsi_req_ref(SCSIRequest *req);
+void scsi_req_unref(SCSIRequest *req);
+
+void scsi_req_build_sense(SCSIRequest *req, SCSISense sense);
+void scsi_req_print(SCSIRequest *req);
+void scsi_req_continue(SCSIRequest *req);
+void scsi_req_data(SCSIRequest *req, int len);
+void scsi_req_complete(SCSIRequest *req, int status);
+uint8_t *scsi_req_get_buf(SCSIRequest *req);
+int scsi_req_get_sense(SCSIRequest *req, uint8_t *buf, int len);
+void scsi_req_abort(SCSIRequest *req, int status);
+void scsi_req_cancel(SCSIRequest *req);
+void scsi_req_retry(SCSIRequest *req);
+void scsi_device_purge_requests(SCSIDevice *sdev, SCSISense sense);
+void scsi_device_set_ua(SCSIDevice *sdev, SCSISense sense);
+void scsi_device_report_change(SCSIDevice *dev, SCSISense sense);
+int scsi_device_get_sense(SCSIDevice *dev, uint8_t *buf, int len, bool fixed);
+SCSIDevice *scsi_device_find(SCSIBus *bus, int channel, int target, int lun);
+
+/* scsi-generic.c. */
+extern const SCSIReqOps scsi_generic_req_ops;
+
+#endif
diff --git a/include/hw/sd.h b/include/hw/sd.h
new file mode 100644 (file)
index 0000000..d9b97e4
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * SD Memory Card emulation.  Mostly correct for MMC too.
+ *
+ * Copyright (c) 2006 Andrzej Zaborowski  <balrog@zabor.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef __hw_sd_h
+#define __hw_sd_h              1
+
+#define OUT_OF_RANGE           (1 << 31)
+#define ADDRESS_ERROR          (1 << 30)
+#define BLOCK_LEN_ERROR                (1 << 29)
+#define ERASE_SEQ_ERROR                (1 << 28)
+#define ERASE_PARAM            (1 << 27)
+#define WP_VIOLATION           (1 << 26)
+#define CARD_IS_LOCKED         (1 << 25)
+#define LOCK_UNLOCK_FAILED     (1 << 24)
+#define COM_CRC_ERROR          (1 << 23)
+#define ILLEGAL_COMMAND                (1 << 22)
+#define CARD_ECC_FAILED                (1 << 21)
+#define CC_ERROR               (1 << 20)
+#define SD_ERROR               (1 << 19)
+#define CID_CSD_OVERWRITE      (1 << 16)
+#define WP_ERASE_SKIP          (1 << 15)
+#define CARD_ECC_DISABLED      (1 << 14)
+#define ERASE_RESET            (1 << 13)
+#define CURRENT_STATE          (7 << 9)
+#define READY_FOR_DATA         (1 << 8)
+#define APP_CMD                        (1 << 5)
+#define AKE_SEQ_ERROR          (1 << 3)
+#define OCR_CCS_BITN        30
+
+typedef enum {
+    sd_none = -1,
+    sd_bc = 0, /* broadcast -- no response */
+    sd_bcr,    /* broadcast with response */
+    sd_ac,     /* addressed -- no data transfer */
+    sd_adtc,   /* addressed with data transfer */
+} sd_cmd_type_t;
+
+typedef struct {
+    uint8_t cmd;
+    uint32_t arg;
+    uint8_t crc;
+} SDRequest;
+
+typedef struct SDState SDState;
+
+SDState *sd_init(BlockDriverState *bs, bool is_spi);
+int sd_do_command(SDState *sd, SDRequest *req,
+                  uint8_t *response);
+void sd_write_data(SDState *sd, uint8_t value);
+uint8_t sd_read_data(SDState *sd);
+void sd_set_cb(SDState *sd, qemu_irq readonly, qemu_irq insert);
+bool sd_data_ready(SDState *sd);
+void sd_enable(SDState *sd, bool enable);
+
+#endif /* __hw_sd_h */
diff --git a/include/hw/sh4/sh.h b/include/hw/sh4/sh.h
new file mode 100644 (file)
index 0000000..87c378f
--- /dev/null
@@ -0,0 +1,57 @@
+#ifndef QEMU_SH_H
+#define QEMU_SH_H
+/* Definitions for SH board emulation.  */
+
+#include "hw/sh4/sh_intc.h"
+
+#define A7ADDR(x) ((x) & 0x1fffffff)
+#define P4ADDR(x) ((x) | 0xe0000000)
+
+/* sh7750.c */
+struct SH7750State;
+struct MemoryRegion;
+
+struct SH7750State *sh7750_init(CPUSH4State * cpu, struct MemoryRegion *sysmem);
+
+typedef struct {
+    /* The callback will be triggered if any of the designated lines change */
+    uint16_t portamask_trigger;
+    uint16_t portbmask_trigger;
+    /* Return 0 if no action was taken */
+    int (*port_change_cb) (uint16_t porta, uint16_t portb,
+                          uint16_t * periph_pdtra,
+                          uint16_t * periph_portdira,
+                          uint16_t * periph_pdtrb,
+                          uint16_t * periph_portdirb);
+} sh7750_io_device;
+
+int sh7750_register_io_device(struct SH7750State *s,
+                             sh7750_io_device * device);
+/* sh_timer.c */
+#define TMU012_FEAT_TOCR   (1 << 0)
+#define TMU012_FEAT_3CHAN  (1 << 1)
+#define TMU012_FEAT_EXTCLK (1 << 2)
+void tmu012_init(struct MemoryRegion *sysmem, hwaddr base,
+                 int feat, uint32_t freq,
+                qemu_irq ch0_irq, qemu_irq ch1_irq,
+                qemu_irq ch2_irq0, qemu_irq ch2_irq1);
+
+
+/* sh_serial.c */
+#define SH_SERIAL_FEAT_SCIF (1 << 0)
+void sh_serial_init(MemoryRegion *sysmem,
+                    hwaddr base, int feat,
+                    uint32_t freq, CharDriverState *chr,
+                    qemu_irq eri_source,
+                    qemu_irq rxi_source,
+                    qemu_irq txi_source,
+                    qemu_irq tei_source,
+                    qemu_irq bri_source);
+
+/* sh7750.c */
+qemu_irq sh7750_irl(struct SH7750State *s);
+
+/* tc58128.c */
+int tc58128_init(struct SH7750State *s, const char *zone1, const char *zone2);
+
+#endif
diff --git a/include/hw/sh4/sh_intc.h b/include/hw/sh4/sh_intc.h
new file mode 100644 (file)
index 0000000..b7ddcb0
--- /dev/null
@@ -0,0 +1,83 @@
+#ifndef __SH_INTC_H__
+#define __SH_INTC_H__
+
+#include "qemu-common.h"
+#include "hw/irq.h"
+#include "exec/address-spaces.h"
+
+typedef unsigned char intc_enum;
+
+struct intc_vect {
+    intc_enum enum_id;
+    unsigned short vect;
+};
+
+#define INTC_VECT(enum_id, vect) { enum_id, vect }
+
+struct intc_group {
+    intc_enum enum_id;
+    intc_enum enum_ids[32];
+};
+
+#define INTC_GROUP(enum_id, ...) { enum_id, {  __VA_ARGS__ } }
+
+struct intc_mask_reg {
+    unsigned long set_reg, clr_reg, reg_width;
+    intc_enum enum_ids[32];
+    unsigned long value;
+};
+
+struct intc_prio_reg {
+    unsigned long set_reg, clr_reg, reg_width, field_width;
+    intc_enum enum_ids[16];
+    unsigned long value;
+};
+
+#define _INTC_ARRAY(a) a, ARRAY_SIZE(a)
+
+struct intc_source {
+    unsigned short vect;
+    intc_enum next_enum_id;
+
+    int asserted; /* emulates the interrupt signal line from device to intc */
+    int enable_count;
+    int enable_max;
+    int pending; /* emulates the result of signal and masking */
+    struct intc_desc *parent;
+};
+
+struct intc_desc {
+    MemoryRegion iomem;
+    MemoryRegion *iomem_aliases;
+    qemu_irq *irqs;
+    struct intc_source *sources;
+    int nr_sources;
+    struct intc_mask_reg *mask_regs;
+    int nr_mask_regs;
+    struct intc_prio_reg *prio_regs;
+    int nr_prio_regs;
+    int pending; /* number of interrupt sources that has pending set */
+};
+
+int sh_intc_get_pending_vector(struct intc_desc *desc, int imask);
+struct intc_source *sh_intc_source(struct intc_desc *desc, intc_enum id);
+void sh_intc_toggle_source(struct intc_source *source,
+                          int enable_adj, int assert_adj);
+
+void sh_intc_register_sources(struct intc_desc *desc,
+                             struct intc_vect *vectors,
+                             int nr_vectors,
+                             struct intc_group *groups,
+                             int nr_groups);
+
+int sh_intc_init(MemoryRegion *sysmem,
+                 struct intc_desc *desc,
+                int nr_sources,
+                struct intc_mask_reg *mask_regs,
+                int nr_mask_regs,
+                struct intc_prio_reg *prio_regs,
+                int nr_prio_regs);
+
+void sh_intc_set_irl(void *opaque, int n, int level);
+
+#endif /* __SH_INTC_H__ */
diff --git a/include/hw/sparc/firmware_abi.h b/include/hw/sparc/firmware_abi.h
new file mode 100644 (file)
index 0000000..5e6e5d4
--- /dev/null
@@ -0,0 +1,73 @@
+#ifndef FIRMWARE_ABI_H
+#define FIRMWARE_ABI_H
+
+/* OpenBIOS NVRAM partition */
+struct OpenBIOS_nvpart_v1 {
+    uint8_t signature;
+    uint8_t checksum;
+    uint16_t len; // BE, length divided by 16
+    char name[12];
+};
+
+#define OPENBIOS_PART_SYSTEM 0x70
+#define OPENBIOS_PART_FREE 0x7f
+
+static inline void
+OpenBIOS_finish_partition(struct OpenBIOS_nvpart_v1 *header, uint32_t size)
+{
+    unsigned int i, sum;
+    uint8_t *tmpptr;
+
+    // Length divided by 16
+    header->len = cpu_to_be16(size >> 4);
+
+    // Checksum
+    tmpptr = (uint8_t *)header;
+    sum = *tmpptr;
+    for (i = 0; i < 14; i++) {
+        sum += tmpptr[2 + i];
+        sum = (sum + ((sum & 0xff00) >> 8)) & 0xff;
+    }
+    header->checksum = sum & 0xff;
+}
+
+static inline uint32_t
+OpenBIOS_set_var(uint8_t *nvram, uint32_t addr, const char *str)
+{
+    uint32_t len;
+
+    len = strlen(str) + 1;
+    memcpy(&nvram[addr], str, len);
+
+    return addr + len;
+}
+
+/* Sun IDPROM structure at the end of NVRAM */
+/* from http://www.squirrel.com/squirrel/sun-nvram-hostid.faq.html */
+struct Sun_nvram {
+    uint8_t type;       /* always 01 */
+    uint8_t machine_id; /* first byte of host id (machine type) */
+    uint8_t macaddr[6]; /* 6 byte ethernet address (first 3 bytes 08, 00, 20) */
+    uint8_t date[4];    /* date of manufacture */
+    uint8_t hostid[3];  /* remaining 3 bytes of host id (serial number) */
+    uint8_t checksum;   /* bitwise xor of previous bytes */
+};
+
+static inline void
+Sun_init_header(struct Sun_nvram *header, const uint8_t *macaddr, int machine_id)
+{
+    uint8_t tmp, *tmpptr;
+    unsigned int i;
+
+    header->type = 1;
+    header->machine_id = machine_id & 0xff;
+    memcpy(&header->macaddr, macaddr, 6);
+    /* Calculate checksum */
+    tmp = 0;
+    tmpptr = (uint8_t *)header;
+    for (i = 0; i < 15; i++)
+        tmp ^= tmpptr[i];
+
+    header->checksum = tmp;
+}
+#endif /* FIRMWARE_ABI_H */
diff --git a/include/hw/sparc/grlib.h b/include/hw/sparc/grlib.h
new file mode 100644 (file)
index 0000000..470ce72
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * QEMU GRLIB Components
+ *
+ * Copyright (c) 2010-2011 AdaCore
+ *
+ * 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 _GRLIB_H_
+#define _GRLIB_H_
+
+#include "hw/qdev.h"
+#include "hw/sysbus.h"
+
+/* Emulation of GrLib device is base on the GRLIB IP Core User's Manual:
+ * http://www.gaisler.com/products/grlib/grip.pdf
+ */
+
+/* IRQMP */
+
+typedef void (*set_pil_in_fn) (void *opaque, uint32_t pil_in);
+
+void grlib_irqmp_set_irq(void *opaque, int irq, int level);
+
+void grlib_irqmp_ack(DeviceState *dev, int intno);
+
+static inline
+DeviceState *grlib_irqmp_create(hwaddr   base,
+                                CPUSPARCState            *env,
+                                qemu_irq           **cpu_irqs,
+                                uint32_t             nr_irqs,
+                                set_pil_in_fn        set_pil_in)
+{
+    DeviceState *dev;
+
+    assert(cpu_irqs != NULL);
+
+    dev = qdev_create(NULL, "grlib,irqmp");
+    qdev_prop_set_ptr(dev, "set_pil_in", set_pil_in);
+    qdev_prop_set_ptr(dev, "set_pil_in_opaque", env);
+
+    if (qdev_init(dev)) {
+        return NULL;
+    }
+
+    env->irq_manager = dev;
+
+    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
+
+    *cpu_irqs = qemu_allocate_irqs(grlib_irqmp_set_irq,
+                                   dev,
+                                   nr_irqs);
+
+    return dev;
+}
+
+/* GPTimer */
+
+static inline
+DeviceState *grlib_gptimer_create(hwaddr  base,
+                                  uint32_t            nr_timers,
+                                  uint32_t            freq,
+                                  qemu_irq           *cpu_irqs,
+                                  int                 base_irq)
+{
+    DeviceState *dev;
+    int i;
+
+    dev = qdev_create(NULL, "grlib,gptimer");
+    qdev_prop_set_uint32(dev, "nr-timers", nr_timers);
+    qdev_prop_set_uint32(dev, "frequency", freq);
+    qdev_prop_set_uint32(dev, "irq-line", base_irq);
+
+    if (qdev_init(dev)) {
+        return NULL;
+    }
+
+    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
+
+    for (i = 0; i < nr_timers; i++) {
+        sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, cpu_irqs[base_irq + i]);
+    }
+
+    return dev;
+}
+
+/* APB UART */
+
+static inline
+DeviceState *grlib_apbuart_create(hwaddr  base,
+                                  CharDriverState    *serial,
+                                  qemu_irq            irq)
+{
+    DeviceState *dev;
+
+    dev = qdev_create(NULL, "grlib,apbuart");
+    qdev_prop_set_chr(dev, "chrdev", serial);
+
+    if (qdev_init(dev)) {
+        return NULL;
+    }
+
+    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
+
+    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq);
+
+    return dev;
+}
+
+#endif /* ! _GRLIB_H_ */
diff --git a/include/hw/sparc/sparc32_dma.h b/include/hw/sparc/sparc32_dma.h
new file mode 100644 (file)
index 0000000..9497b13
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef SPARC32_DMA_H
+#define SPARC32_DMA_H
+
+/* sparc32_dma.c */
+void ledma_memory_read(void *opaque, hwaddr addr,
+                       uint8_t *buf, int len, int do_bswap);
+void ledma_memory_write(void *opaque, hwaddr addr,
+                        uint8_t *buf, int len, int do_bswap);
+void espdma_memory_read(void *opaque, uint8_t *buf, int len);
+void espdma_memory_write(void *opaque, uint8_t *buf, int len);
+
+#endif
diff --git a/include/hw/sparc/sun4m.h b/include/hw/sparc/sun4m.h
new file mode 100644 (file)
index 0000000..a587700
--- /dev/null
@@ -0,0 +1,38 @@
+#ifndef SUN4M_H
+#define SUN4M_H
+
+#include "qemu-common.h"
+#include "exec/hwaddr.h"
+#include "qapi/qmp/types.h"
+
+/* Devices used by sparc32 system.  */
+
+/* iommu.c */
+void sparc_iommu_memory_rw(void *opaque, hwaddr addr,
+                                 uint8_t *buf, int len, int is_write);
+static inline void sparc_iommu_memory_read(void *opaque,
+                                           hwaddr addr,
+                                           uint8_t *buf, int len)
+{
+    sparc_iommu_memory_rw(opaque, addr, buf, len, 0);
+}
+
+static inline void sparc_iommu_memory_write(void *opaque,
+                                            hwaddr addr,
+                                            uint8_t *buf, int len)
+{
+    sparc_iommu_memory_rw(opaque, addr, buf, len, 1);
+}
+
+/* slavio_intctl.c */
+void slavio_pic_info(Monitor *mon, DeviceState *dev);
+void slavio_irq_info(Monitor *mon, DeviceState *dev);
+
+/* sun4m.c */
+void sun4m_pic_info(Monitor *mon, const QDict *qdict);
+void sun4m_irq_info(Monitor *mon, const QDict *qdict);
+
+/* sparc32_dma.c */
+#include "hw/sparc/sparc32_dma.h"
+
+#endif
diff --git a/include/hw/ssi.h b/include/hw/ssi.h
new file mode 100644 (file)
index 0000000..fdae317
--- /dev/null
@@ -0,0 +1,93 @@
+/* QEMU Synchronous Serial Interface support.  */
+
+/* In principle SSI is a point-point interface.  As such the qemu
+   implementation has a single slave device on a "bus".
+   However it is fairly common for boards to have multiple slaves
+   connected to a single master, and select devices with an external
+   chip select.  This is implemented in qemu by having an explicit mux device.
+   It is assumed that master and slave are both using the same transfer width.
+   */
+
+#ifndef QEMU_SSI_H
+#define QEMU_SSI_H
+
+#include "hw/qdev.h"
+
+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)
+
+typedef enum {
+    SSI_CS_NONE = 0,
+    SSI_CS_LOW,
+    SSI_CS_HIGH,
+} SSICSMode;
+
+/* Slave devices.  */
+typedef struct SSISlaveClass {
+    DeviceClass parent_class;
+
+    int (*init)(SSISlave *dev);
+
+    /* if you have standard or no CS behaviour, just override transfer.
+     * This is called when the device cs is active (true by default).
+     */
+    uint32_t (*transfer)(SSISlave *dev, uint32_t val);
+    /* called when the CS line changes. Optional, devices only need to implement
+     * this if they have side effects associated with the cs line (beyond
+     * tristating the txrx lines).
+     */
+    int (*set_cs)(SSISlave *dev, bool select);
+    /* define whether or not CS exists and is active low/high */
+    SSICSMode cs_polarity;
+
+    /* if you have non-standard CS behaviour override this to take control
+     * of the CS behaviour at the device level. transfer, set_cs, and
+     * cs_polarity are unused if this is overwritten. Transfer_raw will
+     * always be called for the device for every txrx access to the parent bus
+     */
+    uint32_t (*transfer_raw)(SSISlave *dev, uint32_t val);
+} SSISlaveClass;
+
+struct SSISlave {
+    DeviceState qdev;
+
+    /* Chip select state */
+    bool cs;
+};
+
+#define SSI_SLAVE_FROM_QDEV(dev) DO_UPCAST(SSISlave, qdev, dev)
+#define FROM_SSI_SLAVE(type, dev) DO_UPCAST(type, ssidev, dev)
+
+extern const VMStateDescription vmstate_ssi_slave;
+
+#define VMSTATE_SSI_SLAVE(_field, _state) {                          \
+    .name       = (stringify(_field)),                               \
+    .size       = sizeof(SSISlave),                                  \
+    .vmsd       = &vmstate_ssi_slave,                                \
+    .flags      = VMS_STRUCT,                                        \
+    .offset     = vmstate_offset_value(_state, _field, SSISlave),    \
+}
+
+DeviceState *ssi_create_slave(SSIBus *bus, const char *name);
+DeviceState *ssi_create_slave_no_init(SSIBus *bus, const char *name);
+
+/* Master interface.  */
+SSIBus *ssi_create_bus(DeviceState *parent, const char *name);
+
+uint32_t ssi_transfer(SSIBus *bus, uint32_t val);
+
+/* Automatically connect all children nodes a spi controller as slaves */
+void ssi_auto_connect_slaves(DeviceState *parent, qemu_irq *cs_lines,
+                             SSIBus *bus);
+
+/* max111x.c */
+void max111x_set_input(DeviceState *dev, int line, uint8_t value);
+
+#endif
diff --git a/include/hw/stream.h b/include/hw/stream.h
new file mode 100644 (file)
index 0000000..f6137d6
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef STREAM_H
+#define STREAM_H 1
+
+#include "qemu-common.h"
+#include "qom/object.h"
+
+/* stream slave. Used until qdev provides a generic way.  */
+#define TYPE_STREAM_SLAVE "stream-slave"
+
+#define STREAM_SLAVE_CLASS(klass) \
+     OBJECT_CLASS_CHECK(StreamSlaveClass, (klass), TYPE_STREAM_SLAVE)
+#define STREAM_SLAVE_GET_CLASS(obj) \
+    OBJECT_GET_CLASS(StreamSlaveClass, (obj), TYPE_STREAM_SLAVE)
+#define STREAM_SLAVE(obj) \
+     INTERFACE_CHECK(StreamSlave, (obj), TYPE_STREAM_SLAVE)
+
+typedef struct StreamSlave {
+    Object Parent;
+} StreamSlave;
+
+typedef struct StreamSlaveClass {
+    InterfaceClass parent;
+
+    void (*push)(StreamSlave *obj, unsigned char *buf, size_t len,
+                                                    uint32_t *app);
+} StreamSlaveClass;
+
+void
+stream_push(StreamSlave *sink, uint8_t *buf, size_t len, uint32_t *app);
+
+#endif /* STREAM_H */
diff --git a/include/hw/sysbus.h b/include/hw/sysbus.h
new file mode 100644 (file)
index 0000000..7c2e316
--- /dev/null
@@ -0,0 +1,85 @@
+#ifndef HW_SYSBUS_H
+#define HW_SYSBUS_H 1
+
+/* Devices attached directly to the main system bus.  */
+
+#include "hw/qdev.h"
+#include "exec/memory.h"
+
+#define QDEV_MAX_MMIO 32
+#define QDEV_MAX_PIO 32
+#define QDEV_MAX_IRQ 512
+
+#define TYPE_SYSTEM_BUS "System"
+#define SYSTEM_BUS(obj) OBJECT_CHECK(IDEBus, (obj), TYPE_IDE_BUS)
+
+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;
+    qemu_irq irqs[QDEV_MAX_IRQ];
+    qemu_irq *irqp[QDEV_MAX_IRQ];
+    int num_mmio;
+    struct {
+        hwaddr addr;
+        MemoryRegion *memory;
+    } mmio[QDEV_MAX_MMIO];
+    int num_pio;
+    pio_addr_t pio[QDEV_MAX_PIO];
+};
+
+/* Macros to compensate for lack of type inheritance in C.  */
+#define FROM_SYSBUS(type, dev) DO_UPCAST(type, busdev, dev)
+
+void *sysbus_new(void);
+void sysbus_init_mmio(SysBusDevice *dev, MemoryRegion *memory);
+MemoryRegion *sysbus_mmio_get_region(SysBusDevice *dev, int n);
+void sysbus_init_irq(SysBusDevice *dev, qemu_irq *p);
+void sysbus_pass_irq(SysBusDevice *dev, SysBusDevice *target);
+void sysbus_init_ioports(SysBusDevice *dev, pio_addr_t ioport, pio_addr_t size);
+
+
+void sysbus_connect_irq(SysBusDevice *dev, int n, qemu_irq irq);
+void sysbus_mmio_map(SysBusDevice *dev, int n, hwaddr addr);
+void sysbus_mmio_map_overlap(SysBusDevice *dev, int n, hwaddr addr,
+                             unsigned priority);
+void sysbus_add_io(SysBusDevice *dev, hwaddr addr,
+                   MemoryRegion *mem);
+void sysbus_del_io(SysBusDevice *dev, MemoryRegion *mem);
+MemoryRegion *sysbus_address_space(SysBusDevice *dev);
+
+/* Legacy helper function for creating devices.  */
+DeviceState *sysbus_create_varargs(const char *name,
+                                 hwaddr addr, ...);
+DeviceState *sysbus_try_create_varargs(const char *name,
+                                       hwaddr addr, ...);
+static inline DeviceState *sysbus_create_simple(const char *name,
+                                              hwaddr addr,
+                                              qemu_irq irq)
+{
+    return sysbus_create_varargs(name, addr, irq, NULL);
+}
+
+static inline DeviceState *sysbus_try_create_simple(const char *name,
+                                                    hwaddr addr,
+                                                    qemu_irq irq)
+{
+    return sysbus_try_create_varargs(name, addr, irq, NULL);
+}
+
+#endif /* !HW_SYSBUS_H */
diff --git a/include/hw/timer/hpet.h b/include/hw/timer/hpet.h
new file mode 100644 (file)
index 0000000..757f79f
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * QEMU Emulated HPET support
+ *
+ * Copyright IBM, Corp. 2008
+ *
+ * Authors:
+ *  Beth Kon   <bkon@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+#ifndef QEMU_HPET_EMUL_H
+#define QEMU_HPET_EMUL_H
+
+#define HPET_BASE               0xfed00000
+#define HPET_CLK_PERIOD         10000000ULL /* 10000000 femtoseconds == 10ns*/
+
+#define FS_PER_NS 1000000
+#define HPET_MIN_TIMERS         3
+#define HPET_MAX_TIMERS         32
+
+#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
+
+#define HPET_ID         0x000
+#define HPET_PERIOD     0x004
+#define HPET_CFG        0x010
+#define HPET_STATUS     0x020
+#define HPET_COUNTER    0x0f0
+#define HPET_TN_CFG     0x000
+#define HPET_TN_CMP     0x008
+#define HPET_TN_ROUTE   0x010
+#define HPET_CFG_WRITE_MASK  0x3
+
+#define HPET_ID_NUM_TIM_SHIFT   8
+#define HPET_ID_NUM_TIM_MASK    0x1f00
+
+#define HPET_TN_TYPE_LEVEL       0x002
+#define HPET_TN_ENABLE           0x004
+#define HPET_TN_PERIODIC         0x008
+#define HPET_TN_PERIODIC_CAP     0x010
+#define HPET_TN_SIZE_CAP         0x020
+#define HPET_TN_SETVAL           0x040
+#define HPET_TN_32BIT            0x100
+#define HPET_TN_INT_ROUTE_MASK  0x3e00
+#define HPET_TN_FSB_ENABLE      0x4000
+#define HPET_TN_FSB_CAP         0x8000
+#define HPET_TN_CFG_WRITE_MASK  0x7f4e
+#define HPET_TN_INT_ROUTE_SHIFT      9
+#define HPET_TN_INT_ROUTE_CAP_SHIFT 32
+#define HPET_TN_CFG_BITS_READONLY_OR_RESERVED 0xffff80b1U
+
+struct hpet_fw_entry
+{
+    uint32_t event_timer_block_id;
+    uint64_t address;
+    uint16_t min_tick;
+    uint8_t page_prot;
+} QEMU_PACKED;
+
+struct hpet_fw_config
+{
+    uint8_t count;
+    struct hpet_fw_entry hpet[8];
+} QEMU_PACKED;
+
+extern struct hpet_fw_config hpet_cfg;
+#endif
diff --git a/include/hw/timer/i8254.h b/include/hw/timer/i8254.h
new file mode 100644 (file)
index 0000000..75bb530
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * 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/hw.h"
+#include "hw/isa/isa.h"
+
+#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)
+{
+    ISADevice *dev;
+
+    dev = isa_create(bus, "isa-pit");
+    qdev_prop_set_uint32(&dev->qdev, "iobase", base);
+    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;
+}
+
+static inline ISADevice *kvm_pit_init(ISABus *bus, int base)
+{
+    ISADevice *dev;
+
+    dev = isa_create(bus, "kvm-pit");
+    qdev_prop_set_uint32(&dev->qdev, "iobase", base);
+    qdev_init_nofail(&dev->qdev);
+
+    return dev;
+}
+
+void pit_set_gate(ISADevice *dev, int channel, int val);
+void pit_get_channel_info(ISADevice *dev, int channel, PITChannelInfo *info);
+
+#endif /* !HW_I8254_H */
diff --git a/include/hw/timer/i8254_internal.h b/include/hw/timer/i8254_internal.h
new file mode 100644 (file)
index 0000000..e0cff0c
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * QEMU 8253/8254 - 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_I8254_INTERNAL_H
+#define QEMU_I8254_INTERNAL_H
+
+#include "hw/hw.h"
+#include "hw/i386/pc.h"
+#include "hw/isa/isa.h"
+
+typedef struct PITChannelState {
+    int count; /* can be 65536 */
+    uint16_t latched_count;
+    uint8_t count_latched;
+    uint8_t status_latched;
+    uint8_t status;
+    uint8_t read_state;
+    uint8_t write_state;
+    uint8_t write_latch;
+    uint8_t rw_mode;
+    uint8_t mode;
+    uint8_t bcd; /* not supported */
+    uint8_t gate; /* timer start */
+    int64_t count_load_time;
+    /* irq handling */
+    int64_t next_transition_time;
+    QEMUTimer *irq_timer;
+    qemu_irq irq;
+    uint32_t irq_disabled;
+} PITChannelState;
+
+typedef struct PITCommonState {
+    ISADevice dev;
+    MemoryRegion ioports;
+    uint32_t iobase;
+    PITChannelState channels[3];
+} PITCommonState;
+
+#define TYPE_PIT_COMMON "pit-common"
+#define PIT_COMMON(obj) \
+     OBJECT_CHECK(PITCommonState, (obj), TYPE_PIT_COMMON)
+#define PIT_COMMON_CLASS(klass) \
+     OBJECT_CLASS_CHECK(PITCommonClass, (klass), TYPE_PIT_COMMON)
+#define PIT_COMMON_GET_CLASS(obj) \
+     OBJECT_GET_CLASS(PITCommonClass, (obj), TYPE_PIT_COMMON)
+
+typedef struct PITCommonClass {
+    ISADeviceClass parent_class;
+
+    int (*init)(PITCommonState *s);
+    void (*set_channel_gate)(PITCommonState *s, PITChannelState *sc, int val);
+    void (*get_channel_info)(PITCommonState *s, PITChannelState *sc,
+                             PITChannelInfo *info);
+    void (*pre_save)(PITCommonState *s);
+    void (*post_load)(PITCommonState *s);
+} PITCommonClass;
+
+int pit_get_out(PITChannelState *s, int64_t current_time);
+int64_t pit_get_next_transition_time(PITChannelState *s, int64_t current_time);
+void pit_get_channel_info_common(PITCommonState *s, PITChannelState *sc,
+                                 PITChannelInfo *info);
+void pit_reset_common(PITCommonState *s);
+
+#endif /* !QEMU_I8254_INTERNAL_H */
diff --git a/include/hw/timer/m48t59.h b/include/hw/timer/m48t59.h
new file mode 100644 (file)
index 0000000..59337fa
--- /dev/null
@@ -0,0 +1,34 @@
+#ifndef NVRAM_H
+#define NVRAM_H
+
+/* NVRAM helpers */
+typedef uint32_t (*nvram_read_t)(void *private, uint32_t addr);
+typedef void (*nvram_write_t)(void *private, uint32_t addr, uint32_t val);
+typedef struct nvram_t {
+    void *opaque;
+    nvram_read_t read_fn;
+    nvram_write_t write_fn;
+} nvram_t;
+
+uint32_t NVRAM_get_lword (nvram_t *nvram, uint32_t addr);
+int NVRAM_get_string (nvram_t *nvram, uint8_t *dst, uint16_t addr, int max);
+
+int PPC_NVRAM_set_params (nvram_t *nvram, uint16_t NVRAM_size,
+                          const char *arch,
+                          uint32_t RAM_size, int boot_device,
+                          uint32_t kernel_image, uint32_t kernel_size,
+                          const char *cmdline,
+                          uint32_t initrd_image, uint32_t initrd_size,
+                          uint32_t NVRAM_image,
+                          int width, int height, int depth);
+typedef struct M48t59State M48t59State;
+
+void m48t59_write (void *private, uint32_t addr, uint32_t val);
+uint32_t m48t59_read (void *private, uint32_t addr);
+void m48t59_toggle_lock (void *private, int lock);
+M48t59State *m48t59_init_isa(ISABus *bus, uint32_t io_base, uint16_t size,
+                             int type);
+M48t59State *m48t59_init(qemu_irq IRQ, hwaddr mem_base,
+                         uint32_t io_base, uint16_t size, int type);
+
+#endif /* !NVRAM_H */
diff --git a/include/hw/timer/mc146818rtc.h b/include/hw/timer/mc146818rtc.h
new file mode 100644 (file)
index 0000000..854ea3f
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef MC146818RTC_H
+#define MC146818RTC_H
+
+#include "hw/isa/isa.h"
+#include "hw/timer/mc146818rtc_regs.h"
+
+ISADevice *rtc_init(ISABus *bus, int base_year, qemu_irq intercept_irq);
+void rtc_set_memory(ISADevice *dev, int addr, int val);
+void rtc_set_date(ISADevice *dev, const struct tm *tm);
+
+#endif /* !MC146818RTC_H */
diff --git a/include/hw/timer/mc146818rtc_regs.h b/include/hw/timer/mc146818rtc_regs.h
new file mode 100644 (file)
index 0000000..ccdee42
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * QEMU MC146818 RTC 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 RTC_REGS_H
+#define RTC_REGS_H
+
+#define RTC_ISA_IRQ 8
+
+#define RTC_SECONDS             0
+#define RTC_SECONDS_ALARM       1
+#define RTC_MINUTES             2
+#define RTC_MINUTES_ALARM       3
+#define RTC_HOURS               4
+#define RTC_HOURS_ALARM         5
+#define RTC_ALARM_DONT_CARE    0xC0
+
+#define RTC_DAY_OF_WEEK         6
+#define RTC_DAY_OF_MONTH        7
+#define RTC_MONTH               8
+#define RTC_YEAR                9
+
+#define RTC_REG_A               10
+#define RTC_REG_B               11
+#define RTC_REG_C               12
+#define RTC_REG_D               13
+
+/* PC cmos mappings */
+#define RTC_CENTURY              0x32
+#define RTC_IBM_PS2_CENTURY_BYTE 0x37
+
+#define REG_A_UIP 0x80
+
+#define REG_B_SET  0x80
+#define REG_B_PIE  0x40
+#define REG_B_AIE  0x20
+#define REG_B_UIE  0x10
+#define REG_B_SQWE 0x08
+#define REG_B_DM   0x04
+#define REG_B_24H  0x02
+
+#define REG_C_UF   0x10
+#define REG_C_IRQF 0x80
+#define REG_C_PF   0x40
+#define REG_C_AF   0x20
+#define REG_C_MASK 0x70
+
+#endif
diff --git a/include/hw/unicore32/puv3.h b/include/hw/unicore32/puv3.h
new file mode 100644 (file)
index 0000000..f37adcb
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Misc PKUnity SoC declarations
+ *
+ * Copyright (C) 2010-2012 Guan Xuetao
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation, or any later version.
+ * See the COPYING file in the top-level directory.
+ */
+#ifndef QEMU_HW_PUV3_H
+#define QEMU_HW_PUV3_H
+
+#define PUV3_REGS_OFFSET        (0x1000) /* 4K is reasonable */
+
+/* PKUnity System bus (AHB): 0xc0000000 - 0xedffffff (640MB) */
+#define PUV3_DMA_BASE           (0xc0200000) /* AHB-4 */
+
+/* PKUnity Peripheral bus (APB): 0xee000000 - 0xefffffff (128MB) */
+#define PUV3_GPIO_BASE          (0xee500000) /* APB-5 */
+#define PUV3_INTC_BASE          (0xee600000) /* APB-6 */
+#define PUV3_OST_BASE           (0xee800000) /* APB-8 */
+#define PUV3_PM_BASE            (0xeea00000) /* APB-10 */
+#define PUV3_PS2_BASE           (0xeeb00000) /* APB-11 */
+
+/* Hardware interrupts */
+#define PUV3_IRQS_NR            (32)
+
+#define PUV3_IRQS_GPIOLOW0      (0)
+#define PUV3_IRQS_GPIOLOW1      (1)
+#define PUV3_IRQS_GPIOLOW2      (2)
+#define PUV3_IRQS_GPIOLOW3      (3)
+#define PUV3_IRQS_GPIOLOW4      (4)
+#define PUV3_IRQS_GPIOLOW5      (5)
+#define PUV3_IRQS_GPIOLOW6      (6)
+#define PUV3_IRQS_GPIOLOW7      (7)
+#define PUV3_IRQS_GPIOHIGH      (8)
+#define PUV3_IRQS_PS2_KBD       (22)
+#define PUV3_IRQS_PS2_AUX       (23)
+#define PUV3_IRQS_OST0          (26)
+
+/* All puv3_*.c use DPRINTF for debug. */
+#ifdef DEBUG_PUV3
+#define DPRINTF(fmt, ...) printf("%s: " fmt , __func__, ## __VA_ARGS__)
+#else
+#define DPRINTF(fmt, ...) do {} while (0)
+#endif
+
+#endif /* !QEMU_HW_PUV3_H */
diff --git a/include/hw/usb.h b/include/hw/usb.h
new file mode 100644 (file)
index 0000000..4d9d05e
--- /dev/null
@@ -0,0 +1,571 @@
+#ifndef QEMU_USB_H
+#define QEMU_USB_H
+
+/*
+ * QEMU USB API
+ *
+ * Copyright (c) 2005 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.
+ */
+
+#include "hw/qdev.h"
+#include "qemu/queue.h"
+
+/* Constants related to the USB / PCI interaction */
+#define USB_SBRN    0x60 /* Serial Bus Release Number Register */
+#define USB_RELEASE_1  0x10 /* USB 1.0 */
+#define USB_RELEASE_2  0x20 /* USB 2.0 */
+#define USB_RELEASE_3  0x30 /* USB 3.0 */
+
+#define USB_TOKEN_SETUP 0x2d
+#define USB_TOKEN_IN    0x69 /* device -> host */
+#define USB_TOKEN_OUT   0xe1 /* host -> device */
+
+#define USB_RET_SUCCESS           (0)
+#define USB_RET_NODEV             (-1)
+#define USB_RET_NAK               (-2)
+#define USB_RET_STALL             (-3)
+#define USB_RET_BABBLE            (-4)
+#define USB_RET_IOERROR           (-5)
+#define USB_RET_ASYNC             (-6)
+#define USB_RET_ADD_TO_QUEUE      (-7)
+#define USB_RET_REMOVE_FROM_QUEUE (-8)
+
+#define USB_SPEED_LOW   0
+#define USB_SPEED_FULL  1
+#define USB_SPEED_HIGH  2
+#define USB_SPEED_SUPER 3
+
+#define USB_SPEED_MASK_LOW   (1 << USB_SPEED_LOW)
+#define USB_SPEED_MASK_FULL  (1 << USB_SPEED_FULL)
+#define USB_SPEED_MASK_HIGH  (1 << USB_SPEED_HIGH)
+#define USB_SPEED_MASK_SUPER (1 << USB_SPEED_SUPER)
+
+#define USB_STATE_NOTATTACHED 0
+#define USB_STATE_ATTACHED    1
+//#define USB_STATE_POWERED     2
+#define USB_STATE_DEFAULT     3
+//#define USB_STATE_ADDRESS     4
+//#define      USB_STATE_CONFIGURED  5
+#define USB_STATE_SUSPENDED   6
+
+#define USB_CLASS_AUDIO                        1
+#define USB_CLASS_COMM                 2
+#define USB_CLASS_HID                  3
+#define USB_CLASS_PHYSICAL             5
+#define USB_CLASS_STILL_IMAGE          6
+#define USB_CLASS_PRINTER              7
+#define USB_CLASS_MASS_STORAGE         8
+#define USB_CLASS_HUB                  9
+#define USB_CLASS_CDC_DATA             0x0a
+#define USB_CLASS_CSCID                        0x0b
+#define USB_CLASS_CONTENT_SEC          0x0d
+#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
+
+#define USB_TYPE_MASK                  (0x03 << 5)
+#define USB_TYPE_STANDARD              (0x00 << 5)
+#define USB_TYPE_CLASS                 (0x01 << 5)
+#define USB_TYPE_VENDOR                        (0x02 << 5)
+#define USB_TYPE_RESERVED              (0x03 << 5)
+
+#define USB_RECIP_MASK                 0x1f
+#define USB_RECIP_DEVICE               0x00
+#define USB_RECIP_INTERFACE            0x01
+#define USB_RECIP_ENDPOINT             0x02
+#define USB_RECIP_OTHER                        0x03
+
+#define DeviceRequest ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE)<<8)
+#define DeviceOutRequest ((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_DEVICE)<<8)
+#define InterfaceRequest \
+        ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8)
+#define InterfaceOutRequest \
+        ((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8)
+#define EndpointRequest ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_ENDPOINT)<<8)
+#define EndpointOutRequest \
+        ((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_ENDPOINT)<<8)
+#define ClassInterfaceRequest \
+        ((USB_DIR_IN|USB_TYPE_CLASS|USB_RECIP_INTERFACE)<<8)
+#define ClassInterfaceOutRequest \
+        ((USB_DIR_OUT|USB_TYPE_CLASS|USB_RECIP_INTERFACE)<<8)
+
+#define USB_REQ_GET_STATUS             0x00
+#define USB_REQ_CLEAR_FEATURE          0x01
+#define USB_REQ_SET_FEATURE            0x03
+#define USB_REQ_SET_ADDRESS            0x05
+#define USB_REQ_GET_DESCRIPTOR         0x06
+#define USB_REQ_SET_DESCRIPTOR         0x07
+#define USB_REQ_GET_CONFIGURATION      0x08
+#define USB_REQ_SET_CONFIGURATION      0x09
+#define USB_REQ_GET_INTERFACE          0x0A
+#define USB_REQ_SET_INTERFACE          0x0B
+#define USB_REQ_SYNCH_FRAME            0x0C
+
+#define USB_DEVICE_SELF_POWERED                0
+#define USB_DEVICE_REMOTE_WAKEUP       1
+
+#define USB_DT_DEVICE                  0x01
+#define USB_DT_CONFIG                  0x02
+#define USB_DT_STRING                  0x03
+#define USB_DT_INTERFACE               0x04
+#define USB_DT_ENDPOINT                        0x05
+#define USB_DT_DEVICE_QUALIFIER         0x06
+#define USB_DT_OTHER_SPEED_CONFIG       0x07
+#define USB_DT_DEBUG                    0x0A
+#define USB_DT_INTERFACE_ASSOC          0x0B
+#define USB_DT_BOS                      0x0F
+#define USB_DT_DEVICE_CAPABILITY        0x10
+#define USB_DT_CS_INTERFACE             0x24
+#define USB_DT_CS_ENDPOINT              0x25
+#define USB_DT_ENDPOINT_COMPANION       0x30
+
+#define USB_DEV_CAP_WIRELESS            0x01
+#define USB_DEV_CAP_USB2_EXT            0x02
+#define USB_DEV_CAP_SUPERSPEED          0x03
+
+#define USB_ENDPOINT_XFER_CONTROL      0
+#define USB_ENDPOINT_XFER_ISOC         1
+#define USB_ENDPOINT_XFER_BULK         2
+#define USB_ENDPOINT_XFER_INT          3
+#define USB_ENDPOINT_XFER_INVALID     255
+
+#define USB_INTERFACE_INVALID         255
+
+typedef struct USBBus USBBus;
+typedef struct USBBusOps USBBusOps;
+typedef struct USBPort USBPort;
+typedef struct USBDevice USBDevice;
+typedef struct USBPacket USBPacket;
+typedef struct USBCombinedPacket USBCombinedPacket;
+typedef struct USBEndpoint USBEndpoint;
+
+typedef struct USBDesc USBDesc;
+typedef struct USBDescID USBDescID;
+typedef struct USBDescDevice USBDescDevice;
+typedef struct USBDescConfig USBDescConfig;
+typedef struct USBDescIfaceAssoc USBDescIfaceAssoc;
+typedef struct USBDescIface USBDescIface;
+typedef struct USBDescEndpoint USBDescEndpoint;
+typedef struct USBDescOther USBDescOther;
+typedef struct USBDescString USBDescString;
+
+struct USBDescString {
+    uint8_t index;
+    char *str;
+    QLIST_ENTRY(USBDescString) next;
+};
+
+#define USB_MAX_ENDPOINTS  15
+#define USB_MAX_INTERFACES 16
+
+struct USBEndpoint {
+    uint8_t nr;
+    uint8_t pid;
+    uint8_t type;
+    uint8_t ifnum;
+    int max_packet_size;
+    bool pipeline;
+    bool halted;
+    USBDevice *dev;
+    QTAILQ_HEAD(, USBPacket) queue;
+};
+
+enum USBDeviceFlags {
+    USB_DEV_FLAG_FULL_PATH,
+    USB_DEV_FLAG_IS_HOST,
+};
+
+/* definition of a USB device */
+struct USBDevice {
+    DeviceState qdev;
+    USBPort *port;
+    char *port_path;
+    void *opaque;
+    uint32_t flags;
+
+    /* Actual connected speed */
+    int speed;
+    /* Supported speeds, not in info because it may be variable (hostdevs) */
+    int speedmask;
+    uint8_t addr;
+    char product_desc[32];
+    int auto_attach;
+    int attached;
+
+    int32_t state;
+    uint8_t setup_buf[8];
+    uint8_t data_buf[4096];
+    int32_t remote_wakeup;
+    int32_t setup_state;
+    int32_t setup_len;
+    int32_t setup_index;
+
+    USBEndpoint ep_ctl;
+    USBEndpoint ep_in[USB_MAX_ENDPOINTS];
+    USBEndpoint ep_out[USB_MAX_ENDPOINTS];
+
+    QLIST_HEAD(, USBDescString) strings;
+    const USBDesc *usb_desc; /* Overrides class usb_desc if not NULL */
+    const USBDescDevice *device;
+
+    int configuration;
+    int ninterfaces;
+    int altsetting[USB_MAX_INTERFACES];
+    const USBDescConfig *config;
+    const USBDescIface  *ifaces[USB_MAX_INTERFACES];
+};
+
+#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);
+
+    /*
+     * Walk (enabled) downstream ports, check for a matching device.
+     * Only hubs implement this.
+     */
+    USBDevice *(*find_device)(USBDevice *dev, uint8_t addr);
+
+    /*
+     * Called when a packet is canceled.
+     */
+    void (*cancel_packet)(USBDevice *dev, USBPacket *p);
+
+    /*
+     * Called when device is destroyed.
+     */
+    void (*handle_destroy)(USBDevice *dev);
+
+    /*
+     * Attach the device
+     */
+    void (*handle_attach)(USBDevice *dev);
+
+    /*
+     * Reset the device
+     */
+    void (*handle_reset)(USBDevice *dev);
+
+    /*
+     * Process control request.
+     * Called from handle_packet().
+     *
+     * Status gets stored in p->status, and if p->status == USB_RET_SUCCESS
+     * then the number of bytes transferred is stored in p->actual_length
+     */
+    void (*handle_control)(USBDevice *dev, USBPacket *p, int request, int value,
+                           int index, int length, uint8_t *data);
+
+    /*
+     * Process data transfers (both BULK and ISOC).
+     * Called from handle_packet().
+     *
+     * Status gets stored in p->status, and if p->status == USB_RET_SUCCESS
+     * then the number of bytes transferred is stored in p->actual_length
+     */
+    void (*handle_data)(USBDevice *dev, USBPacket *p);
+
+    void (*set_interface)(USBDevice *dev, int interface,
+                          int alt_old, int alt_new);
+
+    /*
+     * Called when the hcd is done queuing packets for an endpoint, only
+     * necessary for devices which can return USB_RET_ADD_TO_QUEUE.
+     */
+    void (*flush_ep_queue)(USBDevice *dev, USBEndpoint *ep);
+
+    /*
+     * Called by the hcd to let the device know the queue for an endpoint
+     * has been unlinked / stopped. Optional may be NULL.
+     */
+    void (*ep_stopped)(USBDevice *dev, USBEndpoint *ep);
+
+    const char *product_desc;
+    const USBDesc *usb_desc;
+} USBDeviceClass;
+
+typedef struct USBPortOps {
+    void (*attach)(USBPort *port);
+    void (*detach)(USBPort *port);
+    /*
+     * This gets called when a device downstream from the device attached to
+     * the port (iow attached through a hub) gets detached.
+     */
+    void (*child_detach)(USBPort *port, USBDevice *child);
+    void (*wakeup)(USBPort *port);
+    /*
+     * Note that port->dev will be different then the device from which
+     * the packet originated when a hub is involved.
+     */
+    void (*complete)(USBPort *port, USBPacket *p);
+} USBPortOps;
+
+/* USB port on which a device can be connected */
+struct USBPort {
+    USBDevice *dev;
+    int speedmask;
+    int hubcount;
+    char path[16];
+    USBPortOps *ops;
+    void *opaque;
+    int index; /* internal port index, may be used with the opaque */
+    QTAILQ_ENTRY(USBPort) next;
+};
+
+typedef void USBCallback(USBPacket * packet, void *opaque);
+
+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;
+    uint64_t id;
+    USBEndpoint *ep;
+    unsigned int stream;
+    QEMUIOVector iov;
+    uint64_t parameter; /* control transfers */
+    bool short_not_ok;
+    bool int_req;
+    int status; /* USB_RET_* status code */
+    int actual_length; /* Number of bytes actually transferred */
+    /* Internal use by the USB layer.  */
+    USBPacketState state;
+    USBCombinedPacket *combined;
+    QTAILQ_ENTRY(USBPacket) queue;
+    QTAILQ_ENTRY(USBPacket) combined_entry;
+};
+
+struct USBCombinedPacket {
+    USBPacket *first;
+    QTAILQ_HEAD(packets_head, USBPacket) packets;
+    QEMUIOVector iov;
+};
+
+void usb_packet_init(USBPacket *p);
+void usb_packet_set_state(USBPacket *p, USBPacketState state);
+void usb_packet_check_state(USBPacket *p, USBPacketState expected);
+void usb_packet_setup(USBPacket *p, int pid,
+                      USBEndpoint *ep, unsigned int stream,
+                      uint64_t id, bool short_not_ok, bool int_req);
+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, QEMUSGList *sgl);
+void usb_packet_copy(USBPacket *p, void *ptr, size_t bytes);
+void usb_packet_skip(USBPacket *p, size_t bytes);
+size_t usb_packet_size(USBPacket *p);
+void usb_packet_cleanup(USBPacket *p);
+
+static inline bool usb_packet_is_inflight(USBPacket *p)
+{
+    return (p->state == USB_PACKET_QUEUED ||
+            p->state == USB_PACKET_ASYNC);
+}
+
+USBDevice *usb_find_device(USBPort *port, uint8_t addr);
+
+void usb_handle_packet(USBDevice *dev, USBPacket *p);
+void usb_packet_complete(USBDevice *dev, USBPacket *p);
+void usb_packet_complete_one(USBDevice *dev, USBPacket *p);
+void usb_cancel_packet(USBPacket * p);
+
+void usb_ep_init(USBDevice *dev);
+void usb_ep_reset(USBDevice *dev);
+void usb_ep_dump(USBDevice *dev);
+struct USBEndpoint *usb_ep_get(USBDevice *dev, int pid, int ep);
+uint8_t usb_ep_get_type(USBDevice *dev, int pid, int ep);
+uint8_t usb_ep_get_ifnum(USBDevice *dev, int pid, int ep);
+void usb_ep_set_type(USBDevice *dev, int pid, int ep, uint8_t type);
+void usb_ep_set_ifnum(USBDevice *dev, int pid, int ep, uint8_t ifnum);
+void usb_ep_set_max_packet_size(USBDevice *dev, int pid, int ep,
+                                uint16_t raw);
+int usb_ep_get_max_packet_size(USBDevice *dev, int pid, int ep);
+void usb_ep_set_pipeline(USBDevice *dev, int pid, int ep, bool enabled);
+void usb_ep_set_halted(USBDevice *dev, int pid, int ep, bool halted);
+USBPacket *usb_ep_find_packet_by_id(USBDevice *dev, int pid, int ep,
+                                    uint64_t id);
+
+void usb_ep_combine_input_packets(USBEndpoint *ep);
+void usb_combined_input_packet_complete(USBDevice *dev, USBPacket *p);
+void usb_combined_packet_cancel(USBDevice *dev, USBPacket *p);
+
+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(USBEndpoint *ep, unsigned int stream);
+void usb_generic_async_ctrl_complete(USBDevice *s, USBPacket *p);
+int set_usb_string(uint8_t *buf, const char *str);
+
+/* usb-linux.c */
+USBDevice *usb_host_device_open(USBBus *bus, const char *devname);
+void usb_host_info(Monitor *mon, const QDict *qdict);
+
+/* usb-bt.c */
+USBDevice *usb_bt_init(USBBus *bus, HCIInfo *hci);
+
+/* usb ports of the VM */
+
+#define VM_USB_HUB_SIZE 8
+
+/* usb-musb.c */
+enum musb_irq_source_e {
+    musb_irq_suspend = 0,
+    musb_irq_resume,
+    musb_irq_rst_babble,
+    musb_irq_sof,
+    musb_irq_connect,
+    musb_irq_disconnect,
+    musb_irq_vbus_request,
+    musb_irq_vbus_error,
+    musb_irq_rx,
+    musb_irq_tx,
+    musb_set_vbus,
+    musb_set_session,
+    /* Add new interrupts here */
+    musb_irq_max, /* total number of interrupts defined */
+};
+
+typedef struct MUSBState MUSBState;
+MUSBState *musb_init(DeviceState *parent_device, int gpio_base);
+void musb_reset(MUSBState *s);
+uint32_t musb_core_intr_get(MUSBState *s);
+void musb_core_intr_clear(MUSBState *s, uint32_t mask);
+void musb_set_size(MUSBState *s, int epnum, int size, int is_tx);
+
+/* usb-bus.c */
+
+#define TYPE_USB_BUS "usb-bus"
+#define USB_BUS(obj) OBJECT_CHECK(USBBus, (obj), TYPE_USB_BUS)
+
+struct USBBus {
+    BusState qbus;
+    USBBusOps *ops;
+    int busnr;
+    int nfree;
+    int nused;
+    QTAILQ_HEAD(, USBPort) free;
+    QTAILQ_HEAD(, USBPort) used;
+    QTAILQ_ENTRY(USBBus) next;
+};
+
+struct USBBusOps {
+    int (*register_companion)(USBBus *bus, USBPort *ports[],
+                              uint32_t portcount, uint32_t firstport);
+    void (*wakeup_endpoint)(USBBus *bus, USBEndpoint *ep, unsigned int stream);
+};
+
+void usb_bus_new(USBBus *bus, USBBusOps *ops, DeviceState *host);
+USBBus *usb_bus_find(int busnr);
+void usb_legacy_register(const char *typename, const char *usbdevice_name,
+                         USBDevice *(*usbdevice_init)(USBBus *bus,
+                                                      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);
+void usb_register_port(USBBus *bus, USBPort *port, void *opaque, int index,
+                       USBPortOps *ops, int speedmask);
+int usb_register_companion(const char *masterbus, USBPort *ports[],
+                           uint32_t portcount, uint32_t firstport,
+                           void *opaque, USBPortOps *ops, int speedmask);
+void usb_port_location(USBPort *downstream, USBPort *upstream, int portnr);
+void usb_unregister_port(USBBus *bus, USBPort *port);
+int usb_claim_port(USBDevice *dev);
+void usb_release_port(USBDevice *dev);
+int usb_device_attach(USBDevice *dev);
+int usb_device_detach(USBDevice *dev);
+int usb_device_delete_addr(int busnr, int addr);
+
+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),   \
+}
+
+USBDevice *usb_device_find_device(USBDevice *dev, uint8_t addr);
+
+void usb_device_cancel_packet(USBDevice *dev, USBPacket *p);
+
+void usb_device_handle_attach(USBDevice *dev);
+
+void usb_device_handle_reset(USBDevice *dev);
+
+void usb_device_handle_control(USBDevice *dev, USBPacket *p, int request,
+                               int val, int index, int length, uint8_t *data);
+
+void usb_device_handle_data(USBDevice *dev, USBPacket *p);
+
+void usb_device_set_interface(USBDevice *dev, int interface,
+                              int alt_old, int alt_new);
+
+void usb_device_flush_ep_queue(USBDevice *dev, USBEndpoint *ep);
+
+void usb_device_ep_stopped(USBDevice *dev, USBEndpoint *ep);
+
+const char *usb_device_get_product_desc(USBDevice *dev);
+
+const USBDesc *usb_device_get_usb_desc(USBDevice *dev);
+
+int ehci_create_ich9_with_companions(PCIBus *bus, int slot);
+
+/* quirks.c */
+
+/* In bulk endpoints are streaming data sources (iow behave like isoc eps) */
+#define USB_QUIRK_BUFFER_BULK_IN       0x01
+/* Bulk pkts in FTDI format, need special handling when combining packets */
+#define USB_QUIRK_IS_FTDI              0x02
+
+int usb_get_quirks(uint16_t vendor_id, uint16_t product_id,
+                   uint8_t interface_class, uint8_t interface_subclass,
+                   uint8_t interface_protocol);
+
+#endif
diff --git a/include/hw/virtio/dataplane/hostmem.h b/include/hw/virtio/dataplane/hostmem.h
new file mode 100644 (file)
index 0000000..b2cf093
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Thread-safe guest to host memory mapping
+ *
+ * Copyright 2012 Red Hat, Inc. and/or its affiliates
+ *
+ * Authors:
+ *   Stefan Hajnoczi <stefanha@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 HOSTMEM_H
+#define HOSTMEM_H
+
+#include "exec/memory.h"
+#include "qemu/thread.h"
+
+typedef struct {
+    void *host_addr;
+    hwaddr guest_addr;
+    uint64_t size;
+    bool readonly;
+} HostMemRegion;
+
+typedef struct {
+    /* The listener is invoked when regions change and a new list of regions is
+     * built up completely before they are installed.
+     */
+    MemoryListener listener;
+    HostMemRegion *new_regions;
+    size_t num_new_regions;
+
+    /* Current regions are accessed from multiple threads either to lookup
+     * addresses or to install a new list of regions.  The lock protects the
+     * pointer and the regions.
+     */
+    QemuMutex current_regions_lock;
+    HostMemRegion *current_regions;
+    size_t num_current_regions;
+} HostMem;
+
+void hostmem_init(HostMem *hostmem);
+void hostmem_finalize(HostMem *hostmem);
+
+/**
+ * Map a guest physical address to a pointer
+ *
+ * Note that there is map/unmap mechanism here.  The caller must ensure that
+ * mapped memory is no longer used across events like hot memory unplug.  This
+ * can be done with other mechanisms like bdrv_drain_all() that quiesce
+ * in-flight I/O.
+ */
+void *hostmem_lookup(HostMem *hostmem, hwaddr phys, hwaddr len, bool is_write);
+
+#endif /* HOSTMEM_H */
diff --git a/include/hw/virtio/dataplane/vring.h b/include/hw/virtio/dataplane/vring.h
new file mode 100644 (file)
index 0000000..9380cb5
--- /dev/null
@@ -0,0 +1,62 @@
+/* Copyright 2012 Red Hat, Inc. and/or its affiliates
+ * Copyright IBM, Corp. 2012
+ *
+ * Based on Linux 2.6.39 vhost code:
+ * Copyright (C) 2009 Red Hat, Inc.
+ * Copyright (C) 2006 Rusty Russell IBM Corporation
+ *
+ * Author: Michael S. Tsirkin <mst@redhat.com>
+ *         Stefan Hajnoczi <stefanha@redhat.com>
+ *
+ * Inspiration, some code, and most witty comments come from
+ * Documentation/virtual/lguest/lguest.c, by Rusty Russell
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.
+ */
+
+#ifndef VRING_H
+#define VRING_H
+
+#include <linux/virtio_ring.h>
+#include "qemu-common.h"
+#include "hostmem.h"
+#include "hw/virtio/virtio.h"
+
+typedef struct {
+    HostMem hostmem;                /* guest memory mapper */
+    struct vring vr;                /* virtqueue vring mapped to host memory */
+    uint16_t last_avail_idx;        /* last processed avail ring index */
+    uint16_t last_used_idx;         /* last processed used ring index */
+    uint16_t signalled_used;        /* EVENT_IDX state */
+    bool signalled_used_valid;
+    bool broken;                    /* was there a fatal error? */
+} Vring;
+
+static inline unsigned int vring_get_num(Vring *vring)
+{
+    return vring->vr.num;
+}
+
+/* Are there more descriptors available? */
+static inline bool vring_more_avail(Vring *vring)
+{
+    return vring->vr.avail->idx != vring->last_avail_idx;
+}
+
+/* Fail future vring_pop() and vring_push() calls until reset */
+static inline void vring_set_broken(Vring *vring)
+{
+    vring->broken = true;
+}
+
+bool vring_setup(Vring *vring, VirtIODevice *vdev, int n);
+void vring_teardown(Vring *vring);
+void vring_disable_notification(VirtIODevice *vdev, Vring *vring);
+bool vring_enable_notification(VirtIODevice *vdev, Vring *vring);
+bool vring_should_notify(VirtIODevice *vdev, Vring *vring);
+int vring_pop(VirtIODevice *vdev, Vring *vring,
+              struct iovec iov[], struct iovec *iov_end,
+              unsigned int *out_num, unsigned int *in_num);
+void vring_push(Vring *vring, unsigned int head, int len);
+
+#endif /* VRING_H */
diff --git a/include/hw/virtio/vhost.h b/include/hw/virtio/vhost.h
new file mode 100644 (file)
index 0000000..b373be0
--- /dev/null
@@ -0,0 +1,68 @@
+#ifndef VHOST_H
+#define VHOST_H
+
+#include "hw/hw.h"
+#include "hw/virtio/virtio.h"
+#include "exec/memory.h"
+
+/* Generic structures common for any vhost based device. */
+struct vhost_virtqueue {
+    int kick;
+    int call;
+    void *desc;
+    void *avail;
+    void *used;
+    int num;
+    unsigned long long used_phys;
+    unsigned used_size;
+    void *ring;
+    unsigned long long ring_phys;
+    unsigned ring_size;
+    EventNotifier masked_notifier;
+};
+
+typedef unsigned long vhost_log_chunk_t;
+#define VHOST_LOG_PAGE 0x1000
+#define VHOST_LOG_BITS (8 * sizeof(vhost_log_chunk_t))
+#define VHOST_LOG_CHUNK (VHOST_LOG_PAGE * VHOST_LOG_BITS)
+
+struct vhost_memory;
+struct vhost_dev {
+    MemoryListener memory_listener;
+    int control;
+    struct vhost_memory *mem;
+    int n_mem_sections;
+    MemoryRegionSection *mem_sections;
+    struct vhost_virtqueue *vqs;
+    int nvqs;
+    /* the first virtuque which would be used by this vhost dev */
+    int vq_index;
+    unsigned long long features;
+    unsigned long long acked_features;
+    unsigned long long backend_features;
+    bool started;
+    bool log_enabled;
+    vhost_log_chunk_t *log;
+    unsigned long long log_size;
+    bool force;
+};
+
+int vhost_dev_init(struct vhost_dev *hdev, int devfd, const char *devpath,
+                   bool force);
+void vhost_dev_cleanup(struct vhost_dev *hdev);
+bool vhost_dev_query(struct vhost_dev *hdev, VirtIODevice *vdev);
+int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev);
+void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev);
+int vhost_dev_enable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev);
+void vhost_dev_disable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev);
+
+/* Test and clear masked event pending status.
+ * Should be called after unmask to avoid losing events.
+ */
+bool vhost_virtqueue_pending(struct vhost_dev *hdev, int n);
+
+/* Mask/unmask events from this vq.
+ */
+void vhost_virtqueue_mask(struct vhost_dev *hdev, VirtIODevice *vdev, int n,
+                          bool mask);
+#endif
diff --git a/include/hw/virtio/virtio-9p.h b/include/hw/virtio/virtio-9p.h
new file mode 100644 (file)
index 0000000..65789db
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * Virtio 9p
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * Authors:
+ *  Aneesh Kumar K.V <aneesh.kumar@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.
+ *
+ */
+
+#ifndef QEMU_VIRTIO_9P_DEVICE_H
+#define QEMU_VIRTIO_9P_DEVICE_H
+
+typedef struct V9fsConf
+{
+    /* tag name for the device */
+    char *tag;
+    char *fsdev_id;
+} V9fsConf;
+
+#endif
diff --git a/include/hw/virtio/virtio-balloon.h b/include/hw/virtio/virtio-balloon.h
new file mode 100644 (file)
index 0000000..3b459bb
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Virtio Support
+ *
+ * Copyright IBM, Corp. 2007-2008
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *  Rusty Russell     <rusty@rustcorp.com.au>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef _QEMU_VIRTIO_BALLOON_H
+#define _QEMU_VIRTIO_BALLOON_H
+
+#include "hw/virtio/virtio.h"
+#include "hw/pci/pci.h"
+
+#define TYPE_VIRTIO_BALLOON "virtio-balloon"
+#define VIRTIO_BALLOON(obj) \
+        OBJECT_CHECK(VirtIOBalloon, (obj), TYPE_VIRTIO_BALLOON)
+
+/* from Linux's linux/virtio_balloon.h */
+
+/* The ID for virtio_balloon */
+#define VIRTIO_ID_BALLOON 5
+
+/* The feature bitmap for virtio balloon */
+#define VIRTIO_BALLOON_F_MUST_TELL_HOST 0 /* Tell before reclaiming pages */
+#define VIRTIO_BALLOON_F_STATS_VQ 1       /* Memory stats virtqueue */
+
+/* Size of a PFN in the balloon interface. */
+#define VIRTIO_BALLOON_PFN_SHIFT 12
+
+struct virtio_balloon_config
+{
+    /* Number of pages host wants Guest to give up. */
+    uint32_t num_pages;
+    /* Number of pages we've actually got in balloon. */
+    uint32_t actual;
+};
+
+/* Memory Statistics */
+#define VIRTIO_BALLOON_S_SWAP_IN  0   /* Amount of memory swapped in */
+#define VIRTIO_BALLOON_S_SWAP_OUT 1   /* Amount of memory swapped out */
+#define VIRTIO_BALLOON_S_MAJFLT   2   /* Number of major faults */
+#define VIRTIO_BALLOON_S_MINFLT   3   /* Number of minor faults */
+#define VIRTIO_BALLOON_S_MEMFREE  4   /* Total amount of free memory */
+#define VIRTIO_BALLOON_S_MEMTOT   5   /* Total amount of memory */
+#define VIRTIO_BALLOON_S_NR       6
+
+typedef struct VirtIOBalloonStat {
+    uint16_t tag;
+    uint64_t val;
+} QEMU_PACKED VirtIOBalloonStat;
+
+typedef struct VirtIOBalloon {
+    VirtIODevice parent_obj;
+    VirtQueue *ivq, *dvq, *svq;
+    uint32_t num_pages;
+    uint32_t actual;
+    uint64_t stats[VIRTIO_BALLOON_S_NR];
+    VirtQueueElement stats_vq_elem;
+    size_t stats_vq_offset;
+    QEMUTimer *stats_timer;
+    int64_t stats_last_update;
+    int64_t stats_poll_interval;
+} VirtIOBalloon;
+
+#endif
diff --git a/include/hw/virtio/virtio-blk.h b/include/hw/virtio/virtio-blk.h
new file mode 100644 (file)
index 0000000..c10d069
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ * Virtio Block Device
+ *
+ * Copyright IBM, Corp. 2007
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef _QEMU_VIRTIO_BLK_H
+#define _QEMU_VIRTIO_BLK_H
+
+#include "hw/virtio/virtio.h"
+#include "hw/block/block.h"
+
+#define TYPE_VIRTIO_BLK "virtio-blk"
+#define VIRTIO_BLK(obj) \
+        OBJECT_CHECK(VirtIOBlock, (obj), TYPE_VIRTIO_BLK)
+
+/* from Linux's linux/virtio_blk.h */
+
+/* The ID for virtio_block */
+#define VIRTIO_ID_BLOCK 2
+
+/* Feature bits */
+#define VIRTIO_BLK_F_BARRIER    0       /* Does host support barriers? */
+#define VIRTIO_BLK_F_SIZE_MAX   1       /* Indicates maximum segment size */
+#define VIRTIO_BLK_F_SEG_MAX    2       /* Indicates maximum # of segments */
+#define VIRTIO_BLK_F_GEOMETRY   4       /* Indicates support of legacy geometry */
+#define VIRTIO_BLK_F_RO         5       /* Disk is read-only */
+#define VIRTIO_BLK_F_BLK_SIZE   6       /* Block size of disk is available*/
+#define VIRTIO_BLK_F_SCSI       7       /* Supports scsi command passthru */
+/* #define VIRTIO_BLK_F_IDENTIFY   8       ATA IDENTIFY supported, DEPRECATED */
+#define VIRTIO_BLK_F_WCE        9       /* write cache enabled */
+#define VIRTIO_BLK_F_TOPOLOGY   10      /* Topology information is available */
+#define VIRTIO_BLK_F_CONFIG_WCE 11      /* write cache configurable */
+
+#define VIRTIO_BLK_ID_BYTES     20      /* ID string length */
+
+struct virtio_blk_config
+{
+    uint64_t capacity;
+    uint32_t size_max;
+    uint32_t seg_max;
+    uint16_t cylinders;
+    uint8_t heads;
+    uint8_t sectors;
+    uint32_t blk_size;
+    uint8_t physical_block_exp;
+    uint8_t alignment_offset;
+    uint16_t min_io_size;
+    uint32_t opt_io_size;
+    uint8_t wce;
+} QEMU_PACKED;
+
+/* These two define direction. */
+#define VIRTIO_BLK_T_IN         0
+#define VIRTIO_BLK_T_OUT        1
+
+/* This bit says it's a scsi command, not an actual read or write. */
+#define VIRTIO_BLK_T_SCSI_CMD   2
+
+/* Flush the volatile write cache */
+#define VIRTIO_BLK_T_FLUSH      4
+
+/* return the device ID string */
+#define VIRTIO_BLK_T_GET_ID     8
+
+/* Barrier before this op. */
+#define VIRTIO_BLK_T_BARRIER    0x80000000
+
+/* This is the first element of the read scatter-gather list. */
+struct virtio_blk_outhdr
+{
+    /* VIRTIO_BLK_T* */
+    uint32_t type;
+    /* io priority. */
+    uint32_t ioprio;
+    /* Sector (ie. 512 byte offset) */
+    uint64_t sector;
+};
+
+#define VIRTIO_BLK_S_OK         0
+#define VIRTIO_BLK_S_IOERR      1
+#define VIRTIO_BLK_S_UNSUPP     2
+
+/* This is the last element of the write scatter-gather list */
+struct virtio_blk_inhdr
+{
+    unsigned char status;
+};
+
+/* SCSI pass-through header */
+struct virtio_scsi_inhdr
+{
+    uint32_t errors;
+    uint32_t data_len;
+    uint32_t sense_len;
+    uint32_t residual;
+};
+
+struct VirtIOBlkConf
+{
+    BlockConf conf;
+    char *serial;
+    uint32_t scsi;
+    uint32_t config_wce;
+    uint32_t data_plane;
+};
+
+struct VirtIOBlockDataPlane;
+
+typedef struct VirtIOBlock {
+    VirtIODevice parent_obj;
+    BlockDriverState *bs;
+    VirtQueue *vq;
+    void *rq;
+    QEMUBH *bh;
+    BlockConf *conf;
+    VirtIOBlkConf blk;
+    unsigned short sector_mask;
+    VMChangeStateEntry *change;
+#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE
+    struct VirtIOBlockDataPlane *dataplane;
+#endif
+} VirtIOBlock;
+
+#define DEFINE_VIRTIO_BLK_FEATURES(_state, _field) \
+        DEFINE_VIRTIO_COMMON_FEATURES(_state, _field)
+
+#ifdef __linux__
+#define DEFINE_VIRTIO_BLK_PROPERTIES(_state, _field)                          \
+        DEFINE_BLOCK_PROPERTIES(_state, _field.conf),                         \
+        DEFINE_BLOCK_CHS_PROPERTIES(_state, _field.conf),                     \
+        DEFINE_PROP_STRING("serial", _state, _field.serial),                  \
+        DEFINE_PROP_BIT("config-wce", _state, _field.config_wce, 0, true),    \
+        DEFINE_PROP_BIT("scsi", _state, _field.scsi, 0, true)
+#else
+#define DEFINE_VIRTIO_BLK_PROPERTIES(_state, _field)                          \
+        DEFINE_BLOCK_PROPERTIES(_state, _field.conf),                         \
+        DEFINE_BLOCK_CHS_PROPERTIES(_state, _field.conf),                     \
+        DEFINE_PROP_STRING("serial", _state, _field.serial),                  \
+        DEFINE_PROP_BIT("config-wce", _state, _field.config_wce, 0, true)
+#endif /* __linux__ */
+
+void virtio_blk_set_conf(DeviceState *dev, VirtIOBlkConf *blk);
+
+#endif
diff --git a/include/hw/virtio/virtio-bus.h b/include/hw/virtio/virtio-bus.h
new file mode 100644 (file)
index 0000000..311e8c7
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * VirtioBus
+ *
+ *  Copyright (C) 2012 : GreenSocs Ltd
+ *      http://www.greensocs.com/ , email: info@greensocs.com
+ *
+ *  Developed by :
+ *  Frederic Konrad   <fred.konrad@greensocs.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 VIRTIO_BUS_H
+#define VIRTIO_BUS_H
+
+#include "hw/qdev.h"
+#include "sysemu/sysemu.h"
+#include "hw/virtio/virtio.h"
+
+#define TYPE_VIRTIO_BUS "virtio-bus"
+#define VIRTIO_BUS_GET_CLASS(obj) \
+        OBJECT_GET_CLASS(VirtioBusClass, obj, TYPE_VIRTIO_BUS)
+#define VIRTIO_BUS_CLASS(klass) \
+        OBJECT_CLASS_CHECK(VirtioBusClass, klass, TYPE_VIRTIO_BUS)
+#define VIRTIO_BUS(obj) OBJECT_CHECK(VirtioBusState, (obj), TYPE_VIRTIO_BUS)
+
+typedef struct VirtioBusState VirtioBusState;
+
+typedef struct VirtioBusClass {
+    /* This is what a VirtioBus must implement */
+    BusClass parent;
+    void (*notify)(DeviceState *d, uint16_t vector);
+    void (*save_config)(DeviceState *d, QEMUFile *f);
+    void (*save_queue)(DeviceState *d, int n, QEMUFile *f);
+    int (*load_config)(DeviceState *d, QEMUFile *f);
+    int (*load_queue)(DeviceState *d, int n, QEMUFile *f);
+    int (*load_done)(DeviceState *d, QEMUFile *f);
+    unsigned (*get_features)(DeviceState *d);
+    bool (*query_guest_notifiers)(DeviceState *d);
+    int (*set_guest_notifiers)(DeviceState *d, int nvqs, bool assign);
+    int (*set_host_notifier)(DeviceState *d, int n, bool assigned);
+    void (*vmstate_change)(DeviceState *d, bool running);
+    /*
+     * transport independent init function.
+     * This is called by virtio-bus just after the device is plugged.
+     */
+    void (*device_plugged)(DeviceState *d);
+    /*
+     * transport independent exit function.
+     * This is called by virtio-bus just before the device is unplugged.
+     */
+    void (*device_unplug)(DeviceState *d);
+} VirtioBusClass;
+
+struct VirtioBusState {
+    BusState parent_obj;
+    /*
+     * Only one VirtIODevice can be plugged on the bus.
+     */
+    VirtIODevice *vdev;
+    /*
+     * This will be removed at the end of the series.
+     */
+    VirtIOBindings bindings;
+};
+
+int virtio_bus_plug_device(VirtIODevice *vdev);
+void virtio_bus_reset(VirtioBusState *bus);
+void virtio_bus_destroy_device(VirtioBusState *bus);
+/* Get the device id of the plugged device. */
+uint16_t virtio_bus_get_vdev_id(VirtioBusState *bus);
+/* Get the config_len field of the plugged device. */
+size_t virtio_bus_get_vdev_config_len(VirtioBusState *bus);
+/* Get the features of the plugged device. */
+uint32_t virtio_bus_get_vdev_features(VirtioBusState *bus,
+                                    uint32_t requested_features);
+/* Get bad features of the plugged device. */
+uint32_t virtio_bus_get_vdev_bad_features(VirtioBusState *bus);
+/* Get config of the plugged device. */
+void virtio_bus_get_vdev_config(VirtioBusState *bus, uint8_t *config);
+
+#endif /* VIRTIO_BUS_H */
diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h
new file mode 100644 (file)
index 0000000..d2cc996
--- /dev/null
@@ -0,0 +1,246 @@
+/*
+ * Virtio Network Device
+ *
+ * Copyright IBM, Corp. 2007
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef _QEMU_VIRTIO_NET_H
+#define _QEMU_VIRTIO_NET_H
+
+#include "hw/virtio/virtio.h"
+#include "hw/pci/pci.h"
+
+#define ETH_ALEN    6
+
+/* from Linux's virtio_net.h */
+
+/* The ID for virtio_net */
+#define VIRTIO_ID_NET   1
+
+/* The feature bitmap for virtio net */
+#define VIRTIO_NET_F_CSUM       0       /* Host handles pkts w/ partial csum */
+#define VIRTIO_NET_F_GUEST_CSUM 1       /* Guest handles pkts w/ partial csum */
+#define VIRTIO_NET_F_MAC        5       /* Host has given MAC address. */
+#define VIRTIO_NET_F_GSO        6       /* Host handles pkts w/ any GSO type */
+#define VIRTIO_NET_F_GUEST_TSO4 7       /* Guest can handle TSOv4 in. */
+#define VIRTIO_NET_F_GUEST_TSO6 8       /* Guest can handle TSOv6 in. */
+#define VIRTIO_NET_F_GUEST_ECN  9       /* Guest can handle TSO[6] w/ ECN in. */
+#define VIRTIO_NET_F_GUEST_UFO  10      /* Guest can handle UFO in. */
+#define VIRTIO_NET_F_HOST_TSO4  11      /* Host can handle TSOv4 in. */
+#define VIRTIO_NET_F_HOST_TSO6  12      /* Host can handle TSOv6 in. */
+#define VIRTIO_NET_F_HOST_ECN   13      /* Host can handle TSO[6] w/ ECN in. */
+#define VIRTIO_NET_F_HOST_UFO   14      /* Host can handle UFO in. */
+#define VIRTIO_NET_F_MRG_RXBUF  15      /* Host can merge receive buffers. */
+#define VIRTIO_NET_F_STATUS     16      /* virtio_net_config.status available */
+#define VIRTIO_NET_F_CTRL_VQ    17      /* Control channel available */
+#define VIRTIO_NET_F_CTRL_RX    18      /* Control channel RX mode support */
+#define VIRTIO_NET_F_CTRL_VLAN  19      /* Control channel VLAN filtering */
+#define VIRTIO_NET_F_CTRL_RX_EXTRA 20   /* Extra RX mode control support */
+#define VIRTIO_NET_F_MQ         22      /* Device supports Receive Flow
+                                         * Steering */
+
+#define VIRTIO_NET_F_CTRL_MAC_ADDR   23 /* Set MAC address */
+
+#define VIRTIO_NET_S_LINK_UP    1       /* Link is up */
+
+#define TX_TIMER_INTERVAL 150000 /* 150 us */
+
+/* Limit the number of packets that can be sent via a single flush
+ * of the TX queue.  This gives us a guaranteed exit condition and
+ * ensures fairness in the io path.  256 conveniently matches the
+ * length of the TX queue and shows a good balance of performance
+ * and latency. */
+#define TX_BURST 256
+
+typedef struct virtio_net_conf
+{
+    uint32_t txtimer;
+    int32_t txburst;
+    char *tx;
+} virtio_net_conf;
+
+/* Maximum packet size we can receive from tap device: header + 64k */
+#define VIRTIO_NET_MAX_BUFSIZE (sizeof(struct virtio_net_hdr) + (64 << 10))
+
+struct virtio_net_config
+{
+    /* The config defining mac address ($ETH_ALEN bytes) */
+    uint8_t mac[ETH_ALEN];
+    /* See VIRTIO_NET_F_STATUS and VIRTIO_NET_S_* above */
+    uint16_t status;
+    /* Max virtqueue pairs supported by the device */
+    uint16_t max_virtqueue_pairs;
+} QEMU_PACKED;
+
+/*
+ * Control virtqueue data structures
+ *
+ * The control virtqueue expects a header in the first sg entry
+ * and an ack/status response in the last entry.  Data for the
+ * command goes in between.
+ */
+struct virtio_net_ctrl_hdr {
+    uint8_t class;
+    uint8_t cmd;
+};
+
+typedef uint8_t virtio_net_ctrl_ack;
+
+#define VIRTIO_NET_OK     0
+#define VIRTIO_NET_ERR    1
+
+/*
+ * Control the RX mode, ie. promisucous, allmulti, etc...
+ * All commands require an "out" sg entry containing a 1 byte
+ * state value, zero = disable, non-zero = enable.  Commands
+ * 0 and 1 are supported with the VIRTIO_NET_F_CTRL_RX feature.
+ * Commands 2-5 are added with VIRTIO_NET_F_CTRL_RX_EXTRA.
+ */
+#define VIRTIO_NET_CTRL_RX    0
+ #define VIRTIO_NET_CTRL_RX_PROMISC      0
+ #define VIRTIO_NET_CTRL_RX_ALLMULTI     1
+ #define VIRTIO_NET_CTRL_RX_ALLUNI       2
+ #define VIRTIO_NET_CTRL_RX_NOMULTI      3
+ #define VIRTIO_NET_CTRL_RX_NOUNI        4
+ #define VIRTIO_NET_CTRL_RX_NOBCAST      5
+
+/*
+ * Control the MAC
+ *
+ * The MAC filter table is managed by the hypervisor, the guest should
+ * assume the size is infinite.  Filtering should be considered
+ * non-perfect, ie. based on hypervisor resources, the guest may
+ * received packets from sources not specified in the filter list.
+ *
+ * In addition to the class/cmd header, the TABLE_SET command requires
+ * two out scatterlists.  Each contains a 4 byte count of entries followed
+ * by a concatenated byte stream of the ETH_ALEN MAC addresses.  The
+ * first sg list contains unicast addresses, the second is for multicast.
+ * This functionality is present if the VIRTIO_NET_F_CTRL_RX feature
+ * is available.
+ *
+ * The ADDR_SET command requests one out scatterlist, it contains a
+ * 6 bytes MAC address. This functionality is present if the
+ * VIRTIO_NET_F_CTRL_MAC_ADDR feature is available.
+ */
+struct virtio_net_ctrl_mac {
+    uint32_t entries;
+    uint8_t macs[][ETH_ALEN];
+};
+
+typedef struct VirtIONetQueue {
+    VirtQueue *rx_vq;
+    VirtQueue *tx_vq;
+    QEMUTimer *tx_timer;
+    QEMUBH *tx_bh;
+    int tx_waiting;
+    struct {
+        VirtQueueElement elem;
+        ssize_t len;
+    } async_tx;
+    struct VirtIONet *n;
+} VirtIONetQueue;
+
+typedef struct VirtIONet {
+    VirtIODevice vdev;
+    uint8_t mac[ETH_ALEN];
+    uint16_t status;
+    VirtIONetQueue *vqs;
+    VirtQueue *ctrl_vq;
+    NICState *nic;
+    uint32_t tx_timeout;
+    int32_t tx_burst;
+    uint32_t has_vnet_hdr;
+    size_t host_hdr_len;
+    size_t guest_hdr_len;
+    uint8_t has_ufo;
+    int mergeable_rx_bufs;
+    uint8_t promisc;
+    uint8_t allmulti;
+    uint8_t alluni;
+    uint8_t nomulti;
+    uint8_t nouni;
+    uint8_t nobcast;
+    uint8_t vhost_started;
+    struct {
+        int in_use;
+        int first_multi;
+        uint8_t multi_overflow;
+        uint8_t uni_overflow;
+        uint8_t *macs;
+    } mac_table;
+    uint32_t *vlans;
+    DeviceState *qdev;
+    int multiqueue;
+    uint16_t max_queues;
+    uint16_t curr_queues;
+    size_t config_size;
+} VirtIONet;
+
+#define VIRTIO_NET_CTRL_MAC    1
+ #define VIRTIO_NET_CTRL_MAC_TABLE_SET        0
+ #define VIRTIO_NET_CTRL_MAC_ADDR_SET         1
+
+/*
+ * Control VLAN filtering
+ *
+ * The VLAN filter table is controlled via a simple ADD/DEL interface.
+ * VLAN IDs not added may be filterd by the hypervisor.  Del is the
+ * opposite of add.  Both commands expect an out entry containing a 2
+ * byte VLAN ID.  VLAN filterting is available with the
+ * VIRTIO_NET_F_CTRL_VLAN feature bit.
+ */
+#define VIRTIO_NET_CTRL_VLAN       2
+ #define VIRTIO_NET_CTRL_VLAN_ADD             0
+ #define VIRTIO_NET_CTRL_VLAN_DEL             1
+
+/*
+ * Control Multiqueue
+ *
+ * The command VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET
+ * enables multiqueue, specifying the number of the transmit and
+ * receive queues that will be used. After the command is consumed and acked by
+ * the device, the device will not steer new packets on receive virtqueues
+ * other than specified nor read from transmit virtqueues other than specified.
+ * Accordingly, driver should not transmit new packets  on virtqueues other than
+ * specified.
+ */
+struct virtio_net_ctrl_mq {
+    uint16_t virtqueue_pairs;
+};
+
+#define VIRTIO_NET_CTRL_MQ   4
+ #define VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET        0
+ #define VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN        1
+ #define VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX        0x8000
+
+#define DEFINE_VIRTIO_NET_FEATURES(_state, _field) \
+        DEFINE_VIRTIO_COMMON_FEATURES(_state, _field), \
+        DEFINE_PROP_BIT("csum", _state, _field, VIRTIO_NET_F_CSUM, true), \
+        DEFINE_PROP_BIT("guest_csum", _state, _field, VIRTIO_NET_F_GUEST_CSUM, true), \
+        DEFINE_PROP_BIT("gso", _state, _field, VIRTIO_NET_F_GSO, true), \
+        DEFINE_PROP_BIT("guest_tso4", _state, _field, VIRTIO_NET_F_GUEST_TSO4, true), \
+        DEFINE_PROP_BIT("guest_tso6", _state, _field, VIRTIO_NET_F_GUEST_TSO6, true), \
+        DEFINE_PROP_BIT("guest_ecn", _state, _field, VIRTIO_NET_F_GUEST_ECN, true), \
+        DEFINE_PROP_BIT("guest_ufo", _state, _field, VIRTIO_NET_F_GUEST_UFO, true), \
+        DEFINE_PROP_BIT("host_tso4", _state, _field, VIRTIO_NET_F_HOST_TSO4, true), \
+        DEFINE_PROP_BIT("host_tso6", _state, _field, VIRTIO_NET_F_HOST_TSO6, true), \
+        DEFINE_PROP_BIT("host_ecn", _state, _field, VIRTIO_NET_F_HOST_ECN, true), \
+        DEFINE_PROP_BIT("host_ufo", _state, _field, VIRTIO_NET_F_HOST_UFO, true), \
+        DEFINE_PROP_BIT("mrg_rxbuf", _state, _field, VIRTIO_NET_F_MRG_RXBUF, true), \
+        DEFINE_PROP_BIT("status", _state, _field, VIRTIO_NET_F_STATUS, true), \
+        DEFINE_PROP_BIT("ctrl_vq", _state, _field, VIRTIO_NET_F_CTRL_VQ, true), \
+        DEFINE_PROP_BIT("ctrl_rx", _state, _field, VIRTIO_NET_F_CTRL_RX, true), \
+        DEFINE_PROP_BIT("ctrl_vlan", _state, _field, VIRTIO_NET_F_CTRL_VLAN, true), \
+        DEFINE_PROP_BIT("ctrl_rx_extra", _state, _field, VIRTIO_NET_F_CTRL_RX_EXTRA, true), \
+        DEFINE_PROP_BIT("ctrl_mac_addr", _state, _field, VIRTIO_NET_F_CTRL_MAC_ADDR, true), \
+        DEFINE_PROP_BIT("mq", _state, _field, VIRTIO_NET_F_MQ, false)
+
+#endif
diff --git a/include/hw/virtio/virtio-rng.h b/include/hw/virtio/virtio-rng.h
new file mode 100644 (file)
index 0000000..3711c97
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Virtio RNG Support
+ *
+ * Copyright Red Hat, Inc. 2012
+ * Copyright Amit Shah <amit.shah@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or
+ * (at your option) any later version.  See the COPYING file in the
+ * top-level directory.
+ */
+
+#ifndef _QEMU_VIRTIO_RNG_H
+#define _QEMU_VIRTIO_RNG_H
+
+#include "qemu/rng.h"
+#include "qemu/rng-random.h"
+
+/* The Virtio ID for the virtio rng device */
+#define VIRTIO_ID_RNG    4
+
+struct VirtIORNGConf {
+    RngBackend *rng;
+    uint64_t max_bytes;
+    uint32_t period_ms;
+    RndRandom *default_backend;
+};
+
+typedef struct VirtIORNG {
+    VirtIODevice vdev;
+
+    DeviceState *qdev;
+
+    /* Only one vq - guest puts buffer(s) on it when it needs entropy */
+    VirtQueue *vq;
+
+    VirtIORNGConf *conf;
+
+    RngBackend *rng;
+
+    /* We purposefully don't migrate this state.  The quota will reset on the
+     * destination as a result.  Rate limiting is host state, not guest state.
+     */
+    QEMUTimer *rate_limit_timer;
+    int64_t quota_remaining;
+} VirtIORNG;
+
+#endif
diff --git a/include/hw/virtio/virtio-scsi.h b/include/hw/virtio/virtio-scsi.h
new file mode 100644 (file)
index 0000000..c9d92ca
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Virtio SCSI HBA
+ *
+ * Copyright IBM, Corp. 2010
+ *
+ * Authors:
+ *  Stefan Hajnoczi    <stefanha@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.
+ *
+ */
+
+#ifndef _QEMU_VIRTIO_SCSI_H
+#define _QEMU_VIRTIO_SCSI_H
+
+#include "hw/virtio/virtio.h"
+#include "hw/pci/pci.h"
+#include "hw/scsi/scsi.h"
+
+#define TYPE_VIRTIO_SCSI "virtio-scsi"
+#define VIRTIO_SCSI(obj) \
+        OBJECT_CHECK(VirtIOSCSI, (obj), TYPE_VIRTIO_SCSI)
+
+
+/* The ID for virtio_scsi */
+#define VIRTIO_ID_SCSI  8
+
+/* Feature Bits */
+#define VIRTIO_SCSI_F_INOUT                    0
+#define VIRTIO_SCSI_F_HOTPLUG                  1
+#define VIRTIO_SCSI_F_CHANGE                   2
+
+struct VirtIOSCSIConf {
+    uint32_t num_queues;
+    uint32_t max_sectors;
+    uint32_t cmd_per_lun;
+};
+
+typedef struct VirtIOSCSI {
+    VirtIODevice parent_obj;
+    VirtIOSCSIConf conf;
+
+    SCSIBus bus;
+    uint32_t sense_size;
+    uint32_t cdb_size;
+    int resetting;
+    bool events_dropped;
+    VirtQueue *ctrl_vq;
+    VirtQueue *event_vq;
+    VirtQueue **cmd_vqs;
+} VirtIOSCSI;
+
+#define DEFINE_VIRTIO_SCSI_PROPERTIES(_state, _conf_field)                     \
+    DEFINE_PROP_UINT32("num_queues", _state, _conf_field.num_queues, 1),       \
+    DEFINE_PROP_UINT32("max_sectors", _state, _conf_field.max_sectors, 0xFFFF),\
+    DEFINE_PROP_UINT32("cmd_per_lun", _state, _conf_field.cmd_per_lun, 128)
+
+#define DEFINE_VIRTIO_SCSI_FEATURES(_state, _feature_field)                    \
+    DEFINE_VIRTIO_COMMON_FEATURES(_state, _feature_field),                     \
+    DEFINE_PROP_BIT("hotplug", _state, _feature_field, VIRTIO_SCSI_F_HOTPLUG,  \
+                                                       true),                  \
+    DEFINE_PROP_BIT("param_change", _state, _feature_field,                    \
+                                            VIRTIO_SCSI_F_CHANGE, true)
+
+#endif /* _QEMU_VIRTIO_SCSI_H */
diff --git a/include/hw/virtio/virtio-serial.h b/include/hw/virtio/virtio-serial.h
new file mode 100644 (file)
index 0000000..098deea
--- /dev/null
@@ -0,0 +1,247 @@
+/*
+ * Virtio Serial / Console Support
+ *
+ * Copyright IBM, Corp. 2008
+ * Copyright Red Hat, Inc. 2009, 2010
+ *
+ * Authors:
+ *  Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com>
+ *  Amit Shah <amit.shah@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+#ifndef _QEMU_VIRTIO_SERIAL_H
+#define _QEMU_VIRTIO_SERIAL_H
+
+#include "hw/qdev.h"
+#include "hw/virtio/virtio.h"
+
+/* == Interface shared between the guest kernel and qemu == */
+
+/* The Virtio ID for virtio console / serial ports */
+#define VIRTIO_ID_CONSOLE              3
+
+/* Features supported */
+#define VIRTIO_CONSOLE_F_MULTIPORT     1
+
+#define VIRTIO_CONSOLE_BAD_ID           (~(uint32_t)0)
+
+struct virtio_console_config {
+    /*
+     * These two fields are used by VIRTIO_CONSOLE_F_SIZE which
+     * isn't implemented here yet
+     */
+    uint16_t cols;
+    uint16_t rows;
+
+    uint32_t max_nr_ports;
+} QEMU_PACKED;
+
+struct virtio_console_control {
+    uint32_t id;               /* Port number */
+    uint16_t event;            /* The kind of control event (see below) */
+    uint16_t value;            /* Extra information for the key */
+};
+
+struct virtio_serial_conf {
+    /* Max. number of ports we can have for a virtio-serial device */
+    uint32_t max_virtserial_ports;
+};
+
+/* Some events for the internal messages (control packets) */
+#define VIRTIO_CONSOLE_DEVICE_READY    0
+#define VIRTIO_CONSOLE_PORT_ADD                1
+#define VIRTIO_CONSOLE_PORT_REMOVE     2
+#define VIRTIO_CONSOLE_PORT_READY      3
+#define VIRTIO_CONSOLE_CONSOLE_PORT    4
+#define VIRTIO_CONSOLE_RESIZE          5
+#define VIRTIO_CONSOLE_PORT_OPEN       6
+#define VIRTIO_CONSOLE_PORT_NAME       7
+
+/* == 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 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/closed device. */
+    void (*set_guest_connected)(VirtIOSerialPort *port, int guest_connected);
+
+        /* 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
+ * state is configurable via command-line options. Some of it can be
+ * set by individual devices in their initfn routines. Some of the
+ * state is set by the generic qdev device init routine.
+ */
+struct VirtIOSerialPort {
+    DeviceState dev;
+
+    QTAILQ_ENTRY(VirtIOSerialPort) next;
+
+    /*
+     * This field gives us the virtio device as well as the qdev bus
+     * that we are associated with
+     */
+    VirtIOSerial *vser;
+
+    VirtQueue *ivq, *ovq;
+
+    /*
+     * This name is sent to the guest and exported via sysfs.
+     * The guest could create symlinks based on this information.
+     * The name is in the reverse fqdn format, like org.qemu.console.0
+     */
+    char *name;
+
+    /*
+     * This id helps identify ports between the guest and the host.
+     * The guest sends a "header" with this id with each data packet
+     * that it sends and the host can then find out which associated
+     * device to send out this data to
+     */
+    uint32_t id;
+
+    /*
+     * This is the elem that we pop from the virtqueue.  A slow
+     * backend that consumes guest data (e.g. the file backend for
+     * qemu chardevs) can cause the guest to block till all the output
+     * is flushed.  This isn't desired, so we keep a note of the last
+     * element popped and continue consuming it once the backend
+     * becomes writable again.
+     */
+    VirtQueueElement elem;
+
+    /*
+     * The index and the offset into the iov buffer that was popped in
+     * elem above.
+     */
+    uint32_t iov_idx;
+    uint64_t iov_offset;
+
+    /*
+     * When unthrottling we use a bottom-half to call flush_queued_data.
+     */
+    QEMUBH *bh;
+
+    /* Is the corresponding guest device open? */
+    bool guest_connected;
+    /* Is this device open for IO on the host? */
+    bool host_connected;
+    /* Do apps not want to receive data? */
+    bool throttled;
+};
+
+/* The virtio-serial bus on top of which the ports will ride as devices */
+struct VirtIOSerialBus {
+    BusState qbus;
+
+    /* This is the parent device that provides the bus for ports. */
+    VirtIOSerial *vser;
+
+    /* The maximum number of ports that can ride on top of this bus */
+    uint32_t max_nr_ports;
+};
+
+typedef struct VirtIOSerialPostLoad {
+    QEMUTimer *timer;
+    uint32_t nr_active_ports;
+    struct {
+        VirtIOSerialPort *port;
+        uint8_t host_connected;
+    } *connected;
+} VirtIOSerialPostLoad;
+
+struct VirtIOSerial {
+    VirtIODevice vdev;
+
+    VirtQueue *c_ivq, *c_ovq;
+    /* Arrays of ivqs and ovqs: one per port */
+    VirtQueue **ivqs, **ovqs;
+
+    VirtIOSerialBus bus;
+
+    DeviceState *qdev;
+
+    QTAILQ_HEAD(, VirtIOSerialPort) ports;
+
+    /* bitmap for identifying active ports */
+    uint32_t *ports_map;
+
+    struct virtio_console_config config;
+
+    struct VirtIOSerialPostLoad *post_load;
+};
+
+/* Interface to the virtio-serial bus */
+
+/*
+ * Open a connection to the port
+ *   Returns 0 on success (always).
+ */
+int virtio_serial_open(VirtIOSerialPort *port);
+
+/*
+ * Close the connection to the port
+ *   Returns 0 on success (always).
+ */
+int virtio_serial_close(VirtIOSerialPort *port);
+
+/*
+ * Send data to Guest
+ */
+ssize_t virtio_serial_write(VirtIOSerialPort *port, const uint8_t *buf,
+                            size_t size);
+
+/*
+ * Query whether a guest is ready to receive data.
+ */
+size_t virtio_serial_guest_ready(VirtIOSerialPort *port);
+
+/*
+ * Flow control: Ports can signal to the virtio-serial core to stop
+ * sending data or re-start sending data, depending on the 'throttle'
+ * value here.
+ */
+void virtio_serial_throttle_port(VirtIOSerialPort *port, bool throttle);
+
+#endif
diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h
new file mode 100644 (file)
index 0000000..7e24b2b
--- /dev/null
@@ -0,0 +1,292 @@
+/*
+ * Virtio Support
+ *
+ * Copyright IBM, Corp. 2007
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef _QEMU_VIRTIO_H
+#define _QEMU_VIRTIO_H
+
+#include "hw/hw.h"
+#include "net/net.h"
+#include "hw/qdev.h"
+#include "sysemu/sysemu.h"
+#include "qemu/event_notifier.h"
+#ifdef CONFIG_VIRTFS
+#include "hw/virtio/virtio-9p.h"
+#endif
+
+/* from Linux's linux/virtio_config.h */
+
+/* Status byte for guest to report progress, and synchronize features. */
+/* We have seen device and processed generic fields (VIRTIO_CONFIG_F_VIRTIO) */
+#define VIRTIO_CONFIG_S_ACKNOWLEDGE     1
+/* We have found a driver for the device. */
+#define VIRTIO_CONFIG_S_DRIVER          2
+/* Driver has used its parts of the config, and is happy */
+#define VIRTIO_CONFIG_S_DRIVER_OK       4
+/* We've given up on this device. */
+#define VIRTIO_CONFIG_S_FAILED          0x80
+
+/* Some virtio feature bits (currently bits 28 through 31) are reserved for the
+ * transport being used (eg. virtio_ring), the rest are per-device feature bits. */
+#define VIRTIO_TRANSPORT_F_START        28
+#define VIRTIO_TRANSPORT_F_END          32
+
+/* We notify when the ring is completely used, even if the guest is suppressing
+ * callbacks */
+#define VIRTIO_F_NOTIFY_ON_EMPTY        24
+/* We support indirect buffer descriptors */
+#define VIRTIO_RING_F_INDIRECT_DESC     28
+/* The Guest publishes the used index for which it expects an interrupt
+ * at the end of the avail ring. Host should ignore the avail->flags field. */
+/* The Host publishes the avail index for which it expects a kick
+ * at the end of the used ring. Guest should ignore the used->flags field. */
+#define VIRTIO_RING_F_EVENT_IDX         29
+/* A guest should never accept this.  It implies negotiation is broken. */
+#define VIRTIO_F_BAD_FEATURE           30
+
+/* from Linux's linux/virtio_ring.h */
+
+/* This marks a buffer as continuing via the next field. */
+#define VRING_DESC_F_NEXT       1
+/* This marks a buffer as write-only (otherwise read-only). */
+#define VRING_DESC_F_WRITE      2
+/* This means the buffer contains a list of buffer descriptors. */
+#define VRING_DESC_F_INDIRECT  4
+
+/* This means don't notify other side when buffer added. */
+#define VRING_USED_F_NO_NOTIFY  1
+/* This means don't interrupt guest when buffer consumed. */
+#define VRING_AVAIL_F_NO_INTERRUPT      1
+
+struct VirtQueue;
+
+static inline hwaddr vring_align(hwaddr addr,
+                                             unsigned long align)
+{
+    return (addr + align - 1) & ~(align - 1);
+}
+
+typedef struct VirtQueue VirtQueue;
+
+#define VIRTQUEUE_MAX_SIZE 1024
+
+typedef struct VirtQueueElement
+{
+    unsigned int index;
+    unsigned int out_num;
+    unsigned int in_num;
+    hwaddr in_addr[VIRTQUEUE_MAX_SIZE];
+    hwaddr out_addr[VIRTQUEUE_MAX_SIZE];
+    struct iovec in_sg[VIRTQUEUE_MAX_SIZE];
+    struct iovec out_sg[VIRTQUEUE_MAX_SIZE];
+} VirtQueueElement;
+
+typedef struct {
+    void (*notify)(DeviceState *d, uint16_t vector);
+    void (*save_config)(DeviceState *d, QEMUFile *f);
+    void (*save_queue)(DeviceState *d, int n, QEMUFile *f);
+    int (*load_config)(DeviceState *d, QEMUFile *f);
+    int (*load_queue)(DeviceState *d, int n, QEMUFile *f);
+    int (*load_done)(DeviceState *d, QEMUFile *f);
+    unsigned (*get_features)(DeviceState *d);
+    bool (*query_guest_notifiers)(DeviceState *d);
+    int (*set_guest_notifiers)(DeviceState *d, int nvqs, bool assigned);
+    int (*set_host_notifier)(DeviceState *d, int n, bool assigned);
+    void (*vmstate_change)(DeviceState *d, bool running);
+} VirtIOBindings;
+
+#define VIRTIO_PCI_QUEUE_MAX 64
+
+#define VIRTIO_NO_VECTOR 0xffff
+
+#define TYPE_VIRTIO_DEVICE "virtio-device"
+#define VIRTIO_DEVICE_GET_CLASS(obj) \
+        OBJECT_GET_CLASS(VirtioDeviceClass, obj, TYPE_VIRTIO_DEVICE)
+#define VIRTIO_DEVICE_CLASS(klass) \
+        OBJECT_CLASS_CHECK(VirtioDeviceClass, klass, TYPE_VIRTIO_DEVICE)
+#define VIRTIO_DEVICE(obj) \
+        OBJECT_CHECK(VirtIODevice, (obj), TYPE_VIRTIO_DEVICE)
+
+struct VirtIODevice
+{
+    DeviceState parent_obj;
+    const char *name;
+    uint8_t status;
+    uint8_t isr;
+    uint16_t queue_sel;
+    uint32_t guest_features;
+    size_t config_len;
+    void *config;
+    uint16_t config_vector;
+    int nvectors;
+    /*
+     * Function pointers will be removed at the end of the series as they are in
+     * VirtioDeviceClass.
+     */
+    uint32_t (*get_features)(VirtIODevice *vdev, uint32_t requested_features);
+    uint32_t (*bad_features)(VirtIODevice *vdev);
+    void (*set_features)(VirtIODevice *vdev, uint32_t val);
+    void (*get_config)(VirtIODevice *vdev, uint8_t *config);
+    void (*set_config)(VirtIODevice *vdev, const uint8_t *config);
+    void (*reset)(VirtIODevice *vdev);
+    void (*set_status)(VirtIODevice *vdev, uint8_t val);
+    /* Test and clear event pending status.
+     * Should be called after unmask to avoid losing events.
+     * If backend does not support masking,
+     * must check in frontend instead.
+     */
+    bool (*guest_notifier_pending)(VirtIODevice *vdev, int n);
+    /* Mask/unmask events from this vq. Any events reported
+     * while masked will become pending.
+     * If backend does not support masking,
+     * must mask in frontend instead.
+     */
+    void (*guest_notifier_mask)(VirtIODevice *vdev, int n, bool mask);
+
+    VirtQueue *vq;
+    const VirtIOBindings *binding;
+    DeviceState *binding_opaque;
+    uint16_t device_id;
+    bool vm_running;
+    VMChangeStateEntry *vmstate;
+};
+
+typedef struct VirtioDeviceClass {
+    /* This is what a VirtioDevice must implement */
+    DeviceClass parent;
+    int (*init)(VirtIODevice *vdev);
+    uint32_t (*get_features)(VirtIODevice *vdev, uint32_t requested_features);
+    uint32_t (*bad_features)(VirtIODevice *vdev);
+    void (*set_features)(VirtIODevice *vdev, uint32_t val);
+    void (*get_config)(VirtIODevice *vdev, uint8_t *config);
+    void (*set_config)(VirtIODevice *vdev, const uint8_t *config);
+    void (*reset)(VirtIODevice *vdev);
+    void (*set_status)(VirtIODevice *vdev, uint8_t val);
+} VirtioDeviceClass;
+
+void virtio_init(VirtIODevice *vdev, const char *name,
+                         uint16_t device_id, size_t config_size);
+void virtio_common_cleanup(VirtIODevice *vdev);
+
+VirtQueue *virtio_add_queue(VirtIODevice *vdev, int queue_size,
+                            void (*handle_output)(VirtIODevice *,
+                                                  VirtQueue *));
+
+void virtio_del_queue(VirtIODevice *vdev, int n);
+
+void virtqueue_push(VirtQueue *vq, const VirtQueueElement *elem,
+                    unsigned int len);
+void virtqueue_flush(VirtQueue *vq, unsigned int count);
+void virtqueue_fill(VirtQueue *vq, const VirtQueueElement *elem,
+                    unsigned int len, unsigned int idx);
+
+void virtqueue_map_sg(struct iovec *sg, hwaddr *addr,
+    size_t num_sg, int is_write);
+int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem);
+int virtqueue_avail_bytes(VirtQueue *vq, unsigned int in_bytes,
+                          unsigned int out_bytes);
+void virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes,
+                               unsigned int *out_bytes,
+                               unsigned max_in_bytes, unsigned max_out_bytes);
+
+void virtio_notify(VirtIODevice *vdev, VirtQueue *vq);
+
+void virtio_save(VirtIODevice *vdev, QEMUFile *f);
+
+int virtio_load(VirtIODevice *vdev, QEMUFile *f);
+
+void virtio_cleanup(VirtIODevice *vdev);
+
+void virtio_notify_config(VirtIODevice *vdev);
+
+void virtio_queue_set_notification(VirtQueue *vq, int enable);
+
+int virtio_queue_ready(VirtQueue *vq);
+
+int virtio_queue_empty(VirtQueue *vq);
+
+/* Host binding interface.  */
+
+VirtIODevice *virtio_common_init(const char *name, uint16_t device_id,
+                                 size_t config_size, size_t struct_size);
+uint32_t virtio_config_readb(VirtIODevice *vdev, uint32_t addr);
+uint32_t virtio_config_readw(VirtIODevice *vdev, uint32_t addr);
+uint32_t virtio_config_readl(VirtIODevice *vdev, uint32_t addr);
+void virtio_config_writeb(VirtIODevice *vdev, uint32_t addr, uint32_t data);
+void virtio_config_writew(VirtIODevice *vdev, uint32_t addr, uint32_t data);
+void virtio_config_writel(VirtIODevice *vdev, uint32_t addr, uint32_t data);
+void virtio_queue_set_addr(VirtIODevice *vdev, int n, hwaddr addr);
+hwaddr virtio_queue_get_addr(VirtIODevice *vdev, int n);
+int virtio_queue_get_num(VirtIODevice *vdev, int n);
+void virtio_queue_notify(VirtIODevice *vdev, int n);
+uint16_t virtio_queue_vector(VirtIODevice *vdev, int n);
+void virtio_queue_set_vector(VirtIODevice *vdev, int n, uint16_t vector);
+void virtio_set_status(VirtIODevice *vdev, uint8_t val);
+void virtio_reset(void *opaque);
+void virtio_update_irq(VirtIODevice *vdev);
+int virtio_set_features(VirtIODevice *vdev, uint32_t val);
+
+void virtio_bind_device(VirtIODevice *vdev, const VirtIOBindings *binding,
+                        DeviceState *opaque);
+
+/* Base devices.  */
+typedef struct VirtIOBlkConf VirtIOBlkConf;
+struct virtio_net_conf;
+VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf,
+                              struct virtio_net_conf *net,
+                              uint32_t host_features);
+typedef struct virtio_serial_conf virtio_serial_conf;
+VirtIODevice *virtio_serial_init(DeviceState *dev, virtio_serial_conf *serial);
+VirtIODevice *virtio_balloon_init(DeviceState *dev);
+typedef struct VirtIOSCSIConf VirtIOSCSIConf;
+VirtIODevice *virtio_scsi_init(DeviceState *dev, VirtIOSCSIConf *conf);
+typedef struct VirtIORNGConf VirtIORNGConf;
+VirtIODevice *virtio_rng_init(DeviceState *dev, VirtIORNGConf *conf);
+#ifdef CONFIG_VIRTFS
+VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf);
+#endif
+
+
+void virtio_net_exit(VirtIODevice *vdev);
+void virtio_serial_exit(VirtIODevice *vdev);
+void virtio_balloon_exit(VirtIODevice *vdev);
+void virtio_scsi_exit(VirtIODevice *vdev);
+void virtio_rng_exit(VirtIODevice *vdev);
+
+#define DEFINE_VIRTIO_COMMON_FEATURES(_state, _field) \
+       DEFINE_PROP_BIT("indirect_desc", _state, _field, \
+                       VIRTIO_RING_F_INDIRECT_DESC, true), \
+       DEFINE_PROP_BIT("event_idx", _state, _field, \
+                       VIRTIO_RING_F_EVENT_IDX, true)
+
+hwaddr virtio_queue_get_desc_addr(VirtIODevice *vdev, int n);
+hwaddr virtio_queue_get_avail_addr(VirtIODevice *vdev, int n);
+hwaddr virtio_queue_get_used_addr(VirtIODevice *vdev, int n);
+hwaddr virtio_queue_get_ring_addr(VirtIODevice *vdev, int n);
+hwaddr virtio_queue_get_desc_size(VirtIODevice *vdev, int n);
+hwaddr virtio_queue_get_avail_size(VirtIODevice *vdev, int n);
+hwaddr virtio_queue_get_used_size(VirtIODevice *vdev, int n);
+hwaddr virtio_queue_get_ring_size(VirtIODevice *vdev, int n);
+uint16_t virtio_queue_get_last_avail_idx(VirtIODevice *vdev, int n);
+void virtio_queue_set_last_avail_idx(VirtIODevice *vdev, int n, uint16_t idx);
+VirtQueue *virtio_get_queue(VirtIODevice *vdev, int n);
+uint16_t virtio_get_queue_index(VirtQueue *vq);
+int virtio_queue_get_id(VirtQueue *vq);
+EventNotifier *virtio_queue_get_guest_notifier(VirtQueue *vq);
+void virtio_queue_set_guest_notifier_fd_handler(VirtQueue *vq, bool assign,
+                                                bool with_irqfd);
+EventNotifier *virtio_queue_get_host_notifier(VirtQueue *vq);
+void virtio_queue_set_host_notifier_fd_handler(VirtQueue *vq, bool assign,
+                                               bool set_handler);
+void virtio_queue_notify_vq(VirtQueue *vq);
+void virtio_irq(VirtQueue *vq);
+#endif
diff --git a/include/hw/xen/xen.h b/include/hw/xen/xen.h
new file mode 100644 (file)
index 0000000..6235f91
--- /dev/null
@@ -0,0 +1,62 @@
+#ifndef QEMU_HW_XEN_H
+#define QEMU_HW_XEN_H 1
+/*
+ * public xen header
+ *   stuff needed outside xen-*.c, i.e. interfaces to qemu.
+ *   must not depend on any xen headers being present in
+ *   /usr/include/xen, so it can be included unconditionally.
+ */
+#include <inttypes.h>
+
+#include "hw/irq.h"
+#include "qemu-common.h"
+
+/* xen-machine.c */
+enum xen_mode {
+    XEN_EMULATE = 0,  // xen emulation, using xenner (default)
+    XEN_CREATE,       // create xen domain
+    XEN_ATTACH        // attach to xen domain created by xend
+};
+
+extern uint32_t xen_domid;
+extern enum xen_mode xen_mode;
+
+extern bool xen_allowed;
+
+static inline bool xen_enabled(void)
+{
+#if defined(CONFIG_XEN_BACKEND) && !defined(CONFIG_NO_XEN)
+    return xen_allowed;
+#else
+    return 0;
+#endif
+}
+
+int xen_pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num);
+void xen_piix3_set_irq(void *opaque, int irq_num, int level);
+void xen_piix_pci_write_config_client(uint32_t address, uint32_t val, int len);
+void xen_hvm_inject_msi(uint64_t addr, uint32_t data);
+void xen_cmos_set_s3_resume(void *opaque, int irq, int level);
+
+qemu_irq *xen_interrupt_controller_init(void);
+
+int xen_init(void);
+int xen_hvm_init(void);
+void xen_vcpu_init(void);
+void xenstore_store_pv_console_info(int i, struct CharDriverState *chr);
+
+#if defined(NEED_CPU_H) && !defined(CONFIG_USER_ONLY)
+struct MemoryRegion;
+void xen_ram_alloc(ram_addr_t ram_addr, ram_addr_t size,
+                   struct MemoryRegion *mr);
+void xen_modified_memory(ram_addr_t start, ram_addr_t length);
+#endif
+
+struct MemoryRegion;
+void xen_register_framebuffer(struct MemoryRegion *mr);
+
+#if defined(CONFIG_XEN) && CONFIG_XEN_CTRL_INTERFACE_VERSION < 400
+#  define HVM_MAX_VCPUS 32
+#endif
+
+#endif /* QEMU_HW_XEN_H */
diff --git a/include/hw/xen/xen_backend.h b/include/hw/xen/xen_backend.h
new file mode 100644 (file)
index 0000000..3b7d96d
--- /dev/null
@@ -0,0 +1,109 @@
+#ifndef QEMU_HW_XEN_BACKEND_H
+#define QEMU_HW_XEN_BACKEND_H 1
+
+#include "hw/xen/xen_common.h"
+#include "sysemu/sysemu.h"
+#include "net/net.h"
+
+/* ------------------------------------------------------------- */
+
+#define XEN_BUFSIZE 1024
+
+struct XenDevice;
+
+/* driver uses grant tables  ->  open gntdev device (xendev->gnttabdev) */
+#define DEVOPS_FLAG_NEED_GNTDEV   1
+/* don't expect frontend doing correct state transitions (aka console quirk) */
+#define DEVOPS_FLAG_IGNORE_STATE  2
+
+struct XenDevOps {
+    size_t    size;
+    uint32_t  flags;
+    void      (*alloc)(struct XenDevice *xendev);
+    int       (*init)(struct XenDevice *xendev);
+    int       (*initialise)(struct XenDevice *xendev);
+    void      (*connected)(struct XenDevice *xendev);
+    void      (*event)(struct XenDevice *xendev);
+    void      (*disconnect)(struct XenDevice *xendev);
+    int       (*free)(struct XenDevice *xendev);
+    void      (*backend_changed)(struct XenDevice *xendev, const char *node);
+    void      (*frontend_changed)(struct XenDevice *xendev, const char *node);
+};
+
+struct XenDevice {
+    const char         *type;
+    int                dom;
+    int                dev;
+    char               name[64];
+    int                debug;
+
+    enum xenbus_state  be_state;
+    enum xenbus_state  fe_state;
+    int                online;
+    char               be[XEN_BUFSIZE];
+    char               *fe;
+    char               *protocol;
+    int                remote_port;
+    int                local_port;
+
+    XenEvtchn          evtchndev;
+    XenGnttab          gnttabdev;
+
+    struct XenDevOps   *ops;
+    QTAILQ_ENTRY(XenDevice) next;
+};
+
+/* ------------------------------------------------------------- */
+
+/* variables */
+extern XenXC xen_xc;
+extern struct xs_handle *xenstore;
+extern const char *xen_protocol;
+
+/* xenstore helper functions */
+int xenstore_write_str(const char *base, const char *node, const char *val);
+int xenstore_write_int(const char *base, const char *node, int ival);
+int xenstore_write_int64(const char *base, const char *node, int64_t ival);
+char *xenstore_read_str(const char *base, const char *node);
+int xenstore_read_int(const char *base, const char *node, int *ival);
+
+int xenstore_write_be_str(struct XenDevice *xendev, const char *node, const char *val);
+int xenstore_write_be_int(struct XenDevice *xendev, const char *node, int ival);
+int xenstore_write_be_int64(struct XenDevice *xendev, const char *node, int64_t ival);
+char *xenstore_read_be_str(struct XenDevice *xendev, const char *node);
+int xenstore_read_be_int(struct XenDevice *xendev, const char *node, int *ival);
+char *xenstore_read_fe_str(struct XenDevice *xendev, const char *node);
+int xenstore_read_fe_int(struct XenDevice *xendev, const char *node, int *ival);
+
+const char *xenbus_strstate(enum xenbus_state state);
+struct XenDevice *xen_be_find_xendev(const char *type, int dom, int dev);
+void xen_be_check_state(struct XenDevice *xendev);
+
+/* xen backend driver bits */
+int xen_be_init(void);
+int xen_be_register(const char *type, struct XenDevOps *ops);
+int xen_be_set_state(struct XenDevice *xendev, enum xenbus_state state);
+int xen_be_bind_evtchn(struct XenDevice *xendev);
+void xen_be_unbind_evtchn(struct XenDevice *xendev);
+int xen_be_send_notify(struct XenDevice *xendev);
+void xen_be_printf(struct XenDevice *xendev, int msg_level, const char *fmt, ...)
+    GCC_FMT_ATTR(3, 4);
+
+/* actual backend drivers */
+extern struct XenDevOps xen_console_ops;      /* xen_console.c     */
+extern struct XenDevOps xen_kbdmouse_ops;     /* xen_framebuffer.c */
+extern struct XenDevOps xen_framebuffer_ops;  /* xen_framebuffer.c */
+extern struct XenDevOps xen_blkdev_ops;       /* xen_disk.c        */
+extern struct XenDevOps xen_netdev_ops;       /* xen_nic.c         */
+
+void xen_init_display(int domid);
+
+/* configuration (aka xenbus setup) */
+void xen_config_cleanup(void);
+int xen_config_dev_blk(DriveInfo *disk);
+int xen_config_dev_nic(NICInfo *nic);
+int xen_config_dev_vfb(int vdev, const char *type);
+int xen_config_dev_vkbd(int vdev);
+int xen_config_dev_console(int vdev);
+
+#endif /* QEMU_HW_XEN_BACKEND_H */
diff --git a/include/hw/xen/xen_common.h b/include/hw/xen/xen_common.h
new file mode 100644 (file)
index 0000000..2d5a25b
--- /dev/null
@@ -0,0 +1,160 @@
+#ifndef QEMU_HW_XEN_COMMON_H
+#define QEMU_HW_XEN_COMMON_H 1
+
+#include "config-host.h"
+
+#include <stddef.h>
+#include <inttypes.h>
+
+#include <xenctrl.h>
+#if CONFIG_XEN_CTRL_INTERFACE_VERSION < 420
+#  include <xs.h>
+#else
+#  include <xenstore.h>
+#endif
+#include <xen/io/xenbus.h>
+
+#include "hw/hw.h"
+#include "hw/xen/xen.h"
+#include "qemu/queue.h"
+
+/*
+ * We don't support Xen prior to 3.3.0.
+ */
+
+/* Xen before 4.0 */
+#if CONFIG_XEN_CTRL_INTERFACE_VERSION < 400
+static inline void *xc_map_foreign_bulk(int xc_handle, uint32_t dom, int prot,
+                                        xen_pfn_t *arr, int *err,
+                                        unsigned int num)
+{
+    return xc_map_foreign_batch(xc_handle, dom, prot, arr, num);
+}
+#endif
+
+
+/* Xen before 4.1 */
+#if CONFIG_XEN_CTRL_INTERFACE_VERSION < 410
+
+typedef int XenXC;
+typedef int XenEvtchn;
+typedef int XenGnttab;
+
+#  define XC_INTERFACE_FMT "%i"
+#  define XC_HANDLER_INITIAL_VALUE    -1
+
+static inline XenEvtchn xen_xc_evtchn_open(void *logger,
+                                           unsigned int open_flags)
+{
+    return xc_evtchn_open();
+}
+
+static inline XenGnttab xen_xc_gnttab_open(void *logger,
+                                           unsigned int open_flags)
+{
+    return xc_gnttab_open();
+}
+
+static inline XenXC xen_xc_interface_open(void *logger, void *dombuild_logger,
+                                          unsigned int open_flags)
+{
+    return xc_interface_open();
+}
+
+static inline int xc_fd(int xen_xc)
+{
+    return xen_xc;
+}
+
+
+static inline int xc_domain_populate_physmap_exact
+    (XenXC xc_handle, uint32_t domid, unsigned long nr_extents,
+     unsigned int extent_order, unsigned int mem_flags, xen_pfn_t *extent_start)
+{
+    return xc_domain_memory_populate_physmap
+        (xc_handle, domid, nr_extents, extent_order, mem_flags, extent_start);
+}
+
+static inline int xc_domain_add_to_physmap(int xc_handle, uint32_t domid,
+                                           unsigned int space, unsigned long idx,
+                                           xen_pfn_t gpfn)
+{
+    struct xen_add_to_physmap xatp = {
+        .domid = domid,
+        .space = space,
+        .idx = idx,
+        .gpfn = gpfn,
+    };
+
+    return xc_memory_op(xc_handle, XENMEM_add_to_physmap, &xatp);
+}
+
+static inline struct xs_handle *xs_open(unsigned long flags)
+{
+    return xs_daemon_open();
+}
+
+static inline void xs_close(struct xs_handle *xsh)
+{
+    if (xsh != NULL) {
+        xs_daemon_close(xsh);
+    }
+}
+
+
+/* Xen 4.1 */
+#else
+
+typedef xc_interface *XenXC;
+typedef xc_evtchn *XenEvtchn;
+typedef xc_gnttab *XenGnttab;
+
+#  define XC_INTERFACE_FMT "%p"
+#  define XC_HANDLER_INITIAL_VALUE    NULL
+
+static inline XenEvtchn xen_xc_evtchn_open(void *logger,
+                                           unsigned int open_flags)
+{
+    return xc_evtchn_open(logger, open_flags);
+}
+
+static inline XenGnttab xen_xc_gnttab_open(void *logger,
+                                           unsigned int open_flags)
+{
+    return xc_gnttab_open(logger, open_flags);
+}
+
+static inline XenXC xen_xc_interface_open(void *logger, void *dombuild_logger,
+                                          unsigned int open_flags)
+{
+    return xc_interface_open(logger, dombuild_logger, open_flags);
+}
+
+/* FIXME There is now way to have the xen fd */
+static inline int xc_fd(xc_interface *xen_xc)
+{
+    return -1;
+}
+#endif
+
+/* Xen before 4.2 */
+#if CONFIG_XEN_CTRL_INTERFACE_VERSION < 420
+static inline int xen_xc_hvm_inject_msi(XenXC xen_xc, domid_t dom,
+        uint64_t addr, uint32_t data)
+{
+    return -ENOSYS;
+}
+#else
+static inline int xen_xc_hvm_inject_msi(XenXC xen_xc, domid_t dom,
+        uint64_t addr, uint32_t data)
+{
+    return xc_hvm_inject_msi(xen_xc, dom, addr, data);
+}
+#endif
+
+void destroy_hvm_domain(bool reboot);
+
+/* shutdown/destroy current domain because of an error */
+void xen_shutdown_fatal_error(const char *fmt, ...) GCC_FMT_ATTR(1, 2);
+
+#endif /* QEMU_HW_XEN_COMMON_H */
diff --git a/include/hw/xilinx.h b/include/hw/xilinx.h
new file mode 100644 (file)
index 0000000..6c1ee21
--- /dev/null
@@ -0,0 +1,91 @@
+#ifndef HW_XILINX_H
+#define HW_XILINX_H 1
+
+
+#include "qemu-common.h"
+#include "qapi/qmp/qerror.h"
+#include "hw/stream.h"
+#include "net/net.h"
+
+static inline DeviceState *
+xilinx_intc_create(hwaddr base, qemu_irq irq, int kind_of_intr)
+{
+    DeviceState *dev;
+
+    dev = qdev_create(NULL, "xlnx.xps-intc");
+    qdev_prop_set_uint32(dev, "kind-of-intr", kind_of_intr);
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
+    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq);
+    return dev;
+}
+
+/* OPB Timer/Counter.  */
+static inline DeviceState *
+xilinx_timer_create(hwaddr base, qemu_irq irq, int oto, int freq)
+{
+    DeviceState *dev;
+
+    dev = qdev_create(NULL, "xlnx.xps-timer");
+    qdev_prop_set_uint32(dev, "one-timer-only", oto);
+    qdev_prop_set_uint32(dev, "clock-frequency", freq);
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
+    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq);
+    return dev;
+}
+
+/* XPS Ethernet Lite MAC.  */
+static inline DeviceState *
+xilinx_ethlite_create(NICInfo *nd, hwaddr base, qemu_irq irq,
+                      int txpingpong, int rxpingpong)
+{
+    DeviceState *dev;
+
+    qemu_check_nic_model(nd, "xlnx.xps-ethernetlite");
+
+    dev = qdev_create(NULL, "xlnx.xps-ethernetlite");
+    qdev_set_nic_properties(dev, nd);
+    qdev_prop_set_uint32(dev, "tx-ping-pong", txpingpong);
+    qdev_prop_set_uint32(dev, "rx-ping-pong", rxpingpong);
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
+    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq);
+    return dev;
+}
+
+static inline void
+xilinx_axiethernet_init(DeviceState *dev, NICInfo *nd, StreamSlave *peer,
+                        hwaddr base, qemu_irq irq, int txmem, int rxmem)
+{
+    Error *errp = NULL;
+
+    qdev_set_nic_properties(dev, nd);
+    qdev_prop_set_uint32(dev, "rxmem", rxmem);
+    qdev_prop_set_uint32(dev, "txmem", txmem);
+    object_property_set_link(OBJECT(dev), OBJECT(peer), "axistream-connected",
+                             &errp);
+    assert_no_error(errp);
+    qdev_init_nofail(dev);
+    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
+    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq);
+}
+
+static inline void
+xilinx_axidma_init(DeviceState *dev, StreamSlave *peer, hwaddr base,
+                   qemu_irq irq, qemu_irq irq2, int freqhz)
+{
+    Error *errp = NULL;
+
+    qdev_prop_set_uint32(dev, "freqhz", freqhz);
+    object_property_set_link(OBJECT(dev), OBJECT(peer), "axistream-connected",
+                             &errp);
+    assert_no_error(errp);
+    qdev_init_nofail(dev);
+
+    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
+    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq);
+    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, irq2);
+}
+
+#endif
index 65918a9abe52f44893dca1f99e3fa200c0912c86..ebc4d09141828dccd658bf3f356ab37f2c6c4b03 100644 (file)
@@ -164,6 +164,7 @@ extern const VMStateInfo vmstate_info_buffer;
 extern const VMStateInfo vmstate_info_unused_buffer;
 extern const VMStateInfo vmstate_info_bitmap;
 
+#define type_check_2darray(t1,t2,n,m) ((t1(*)[n][m])0 - (t2*)0)
 #define type_check_array(t1,t2,n) ((t1(*)[n])0 - (t2*)0)
 #define type_check_pointer(t1,t2) ((t1**)0 - (t2*)0)
 
@@ -179,6 +180,10 @@ extern const VMStateInfo vmstate_info_bitmap;
     (offsetof(_state, _field) +                                      \
      type_check_array(_type, typeof_field(_state, _field), _num))
 
+#define vmstate_offset_2darray(_state, _field, _type, _n1, _n2)      \
+    (offsetof(_state, _field) +                                      \
+     type_check_2darray(_type, typeof_field(_state, _field), _n1, _n2))
+
 #define vmstate_offset_sub_array(_state, _field, _type, _start)      \
     (offsetof(_state, _field[_start]))
 
@@ -224,6 +229,16 @@ extern const VMStateInfo vmstate_info_bitmap;
     .offset     = vmstate_offset_array(_state, _field, _type, _num), \
 }
 
+#define VMSTATE_2DARRAY(_field, _state, _n1, _n2, _version, _info, _type) { \
+    .name       = (stringify(_field)),                                      \
+    .version_id = (_version),                                               \
+    .num        = (_n1) * (_n2),                                            \
+    .info       = &(_info),                                                 \
+    .size       = sizeof(_type),                                            \
+    .flags      = VMS_ARRAY,                                                \
+    .offset     = vmstate_offset_2darray(_state, _field, _type, _n1, _n2),  \
+}
+
 #define VMSTATE_ARRAY_TEST(_field, _state, _num, _test, _info, _type) {\
     .name         = (stringify(_field)),                              \
     .field_exists = (_test),                                          \
@@ -436,6 +451,15 @@ extern const VMStateInfo vmstate_info_bitmap;
     .offset     = offsetof(_state, _field),                          \
 }
 
+#define VMSTATE_BUFFER_POINTER_UNSAFE(_field, _state, _version, _size) { \
+    .name       = (stringify(_field)),                               \
+    .version_id = (_version),                                        \
+    .size       = (_size),                                           \
+    .info       = &vmstate_info_buffer,                              \
+    .flags      = VMS_BUFFER|VMS_POINTER,                            \
+    .offset     = offsetof(_state, _field),                          \
+}
+
 #define VMSTATE_UNUSED_BUFFER(_test, _version, _size) {              \
     .name         = "unused",                                        \
     .field_exists = (_test),                                         \
@@ -583,15 +607,27 @@ extern const VMStateInfo vmstate_info_bitmap;
 #define VMSTATE_UINT16_ARRAY_V(_f, _s, _n, _v)                         \
     VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_uint16, uint16_t)
 
+#define VMSTATE_UINT16_2DARRAY_V(_f, _s, _n1, _n2, _v)                \
+    VMSTATE_2DARRAY(_f, _s, _n1, _n2, _v, vmstate_info_uint16, uint16_t)
+
 #define VMSTATE_UINT16_ARRAY(_f, _s, _n)                               \
     VMSTATE_UINT16_ARRAY_V(_f, _s, _n, 0)
 
+#define VMSTATE_UINT16_2DARRAY(_f, _s, _n1, _n2)                      \
+    VMSTATE_UINT16_2DARRAY_V(_f, _s, _n1, _n2, 0)
+
+#define VMSTATE_UINT8_2DARRAY_V(_f, _s, _n1, _n2, _v)                 \
+    VMSTATE_2DARRAY(_f, _s, _n1, _n2, _v, vmstate_info_uint8, uint8_t)
+
 #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_UINT8_2DARRAY(_f, _s, _n1, _n2)                       \
+    VMSTATE_UINT8_2DARRAY_V(_f, _s, _n1, _n2, 0)
+
 #define VMSTATE_UINT32_ARRAY_V(_f, _s, _n, _v)                        \
     VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_uint32, uint32_t)
 
diff --git a/include/net/vhost_net.h b/include/net/vhost_net.h
new file mode 100644 (file)
index 0000000..2d936bb
--- /dev/null
@@ -0,0 +1,23 @@
+#ifndef VHOST_NET_H
+#define VHOST_NET_H
+
+#include "net/net.h"
+
+struct vhost_net;
+typedef struct vhost_net VHostNetState;
+
+VHostNetState *vhost_net_init(NetClientState *backend, int devfd, bool force);
+
+bool vhost_net_query(VHostNetState *net, VirtIODevice *dev);
+int vhost_net_start(VirtIODevice *dev, NetClientState *ncs, int total_queues);
+void vhost_net_stop(VirtIODevice *dev, NetClientState *ncs, int total_queues);
+
+void vhost_net_cleanup(VHostNetState *net);
+
+unsigned vhost_net_get_features(VHostNetState *net, unsigned features);
+void vhost_net_ack_features(VHostNetState *net, unsigned features);
+
+bool vhost_net_virtqueue_pending(VHostNetState *net, int n);
+void vhost_net_virtqueue_mask(VHostNetState *net, VirtIODevice *dev,
+                              int idx, bool mask);
+#endif
index 0e690f4849807f45d05cab443f381ffd63c6d6e9..1bc3666107ca766814aa11e1b6838da30b920a59 100644 (file)
@@ -26,6 +26,7 @@ typedef struct QString {
 QString *qstring_new(void);
 QString *qstring_from_str(const char *str);
 QString *qstring_from_substr(const char *str, int start, int end);
+size_t qstring_get_length(const QString *qstring);
 const char *qstring_get_str(const QString *qstring);
 void qstring_append_int(QString *qstring, int64_t value);
 void qstring_append(QString *qstring, const char *str);
diff --git a/include/sysemu/watchdog.h b/include/sysemu/watchdog.h
new file mode 100644 (file)
index 0000000..3e9a970
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Virtual hardware watchdog.
+ *
+ * Copyright (C) 2009 Red Hat Inc.
+ *
+ * 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/>.
+ *
+ * By Richard W.M. Jones (rjones@redhat.com).
+ */
+
+#ifndef QEMU_WATCHDOG_H
+#define QEMU_WATCHDOG_H
+
+#include "qemu/queue.h"
+
+struct WatchdogTimerModel {
+    QLIST_ENTRY(WatchdogTimerModel) entry;
+
+    /* Short name of the device - used to select it on the command line. */
+    const char *wdt_name;
+    /* Longer description (eg. manufacturer and full model number). */
+    const char *wdt_description;
+};
+typedef struct WatchdogTimerModel WatchdogTimerModel;
+
+/* in hw/watchdog.c */
+int select_watchdog(const char *p);
+int select_watchdog_action(const char *action);
+void watchdog_add_model(WatchdogTimerModel *model);
+void watchdog_perform_action(void);
+
+#endif /* QEMU_WATCHDOG_H */
index 0fbae3c2f630897e606165096942a1eb73081aa7..ea6c1d24e6489559965b9f2ce59798bd635c3f61 100644 (file)
@@ -143,7 +143,7 @@ print_signal(abi_ulong arg, int last)
     case TARGET_SIGTTOU: signal_name = "SIGTTOU"; break;
     }
     if (signal_name == NULL) {
-        print_raw_param("%ld", arg, 1);
+        print_raw_param("%ld", arg, last);
         return;
     }
     gemu_log("%s%s", signal_name, get_comma(last));
index eb80ff369f9ef9e327a2170201086702ba9b4db2..f46aece8b86b7fc27698521aa319afb1bf69f228 100644 (file)
@@ -188,14 +188,39 @@ static void glib_pollfds_poll(void)
     }
 }
 
+#define MAX_MAIN_LOOP_SPIN (1000)
+
 static int os_host_main_loop_wait(uint32_t timeout)
 {
     int ret;
+    static int spin_counter;
 
     glib_pollfds_fill(&timeout);
 
+    /* If the I/O thread is very busy or we are incorrectly busy waiting in
+     * the I/O thread, this can lead to starvation of the BQL such that the
+     * VCPU threads never run.  To make sure we can detect the later case,
+     * print a message to the screen.  If we run into this condition, create
+     * a fake timeout in order to give the VCPU threads a chance to run.
+     */
+    if (spin_counter > MAX_MAIN_LOOP_SPIN) {
+        static bool notified;
+
+        if (!notified) {
+            fprintf(stderr,
+                    "main-loop: WARNING: I/O thread spun for %d iterations\n",
+                    MAX_MAIN_LOOP_SPIN);
+            notified = true;
+        }
+
+        timeout = 1;
+    }
+
     if (timeout > 0) {
+        spin_counter = 0;
         qemu_mutex_unlock_iothread();
+    } else {
+        spin_counter++;
     }
 
     ret = g_poll((GPollFD *)gpollfds->data, gpollfds->len, timeout);
index 4ec1db980c2f006495b9ea83893d9713951b9a93..c897e8033f367e85c70121b296d63d6f52809e37 100644 (file)
--- a/monitor.c
+++ b/monitor.c
@@ -26,9 +26,9 @@
 #include "monitor/qdev.h"
 #include "hw/usb.h"
 #include "hw/pcmcia.h"
-#include "hw/pc.h"
+#include "hw/i386/pc.h"
 #include "hw/pci/pci.h"
-#include "hw/watchdog.h"
+#include "sysemu/watchdog.h"
 #include "hw/loader.h"
 #include "exec/gdbstub.h"
 #include "net/net.h"
@@ -71,9 +71,9 @@
 
 /* for pic/irq_info */
 #if defined(TARGET_SPARC)
-#include "hw/sun4m.h"
+#include "hw/sparc/sun4m.h"
 #endif
-#include "hw/lm32_pic.h"
+#include "hw/lm32/lm32_pic.h"
 
 //#define DEBUG
 //#define DEBUG_COMPLETION
@@ -188,8 +188,8 @@ struct Monitor {
     int reset_seen;
     int flags;
     int suspend_cnt;
-    uint8_t outbuf[1024];
-    int outbuf_index;
+    bool skip_flush;
+    QString *outbuf;
     ReadLineState *rs;
     MonitorControl *mc;
     CPUArchState *mon_cpu;
@@ -271,45 +271,56 @@ static gboolean monitor_unblocked(GIOChannel *chan, GIOCondition cond,
 void monitor_flush(Monitor *mon)
 {
     int rc;
+    size_t len;
+    const char *buf;
+
+    if (mon->skip_flush) {
+        return;
+    }
 
-    if (mon && mon->outbuf_index != 0 && !mon->mux_out) {
-        rc = qemu_chr_fe_write(mon->chr, mon->outbuf, mon->outbuf_index);
-        if (rc == mon->outbuf_index) {
+    buf = qstring_get_str(mon->outbuf);
+    len = qstring_get_length(mon->outbuf);
+
+    if (mon && len && !mon->mux_out) {
+        rc = qemu_chr_fe_write(mon->chr, (const uint8_t *) buf, len);
+        if (rc == len) {
             /* all flushed */
-            mon->outbuf_index = 0;
+            QDECREF(mon->outbuf);
+            mon->outbuf = qstring_new();
             return;
         }
         if (rc > 0) {
             /* partinal write */
-            memmove(mon->outbuf, mon->outbuf + rc, mon->outbuf_index - rc);
-            mon->outbuf_index -= rc;
+            QString *tmp = qstring_from_str(buf + rc);
+            QDECREF(mon->outbuf);
+            mon->outbuf = tmp;
         }
         qemu_chr_fe_add_watch(mon->chr, G_IO_OUT, monitor_unblocked, mon);
     }
 }
 
-/* flush at every end of line or if the buffer is full */
+/* flush at every end of line */
 static void monitor_puts(Monitor *mon, const char *str)
 {
     char c;
 
     for(;;) {
-        assert(mon->outbuf_index < sizeof(mon->outbuf) - 1);
         c = *str++;
         if (c == '\0')
             break;
-        if (c == '\n')
-            mon->outbuf[mon->outbuf_index++] = '\r';
-        mon->outbuf[mon->outbuf_index++] = c;
-        if (mon->outbuf_index >= (sizeof(mon->outbuf) - 1)
-            || c == '\n')
+        if (c == '\n') {
+            qstring_append_chr(mon->outbuf, '\r');
+        }
+        qstring_append_chr(mon->outbuf, c);
+        if (c == '\n') {
             monitor_flush(mon);
+        }
     }
 }
 
 void monitor_vprintf(Monitor *mon, const char *fmt, va_list ap)
 {
-    char buf[4096];
+    char *buf;
 
     if (!mon)
         return;
@@ -318,8 +329,9 @@ void monitor_vprintf(Monitor *mon, const char *fmt, va_list ap)
         return;
     }
 
-    vsnprintf(buf, sizeof(buf), fmt, ap);
+    buf = g_strdup_vprintf(fmt, ap);
     monitor_puts(mon, buf);
+    g_free(buf);
 }
 
 void monitor_printf(Monitor *mon, const char *fmt, ...)
@@ -668,11 +680,10 @@ char *qmp_human_monitor_command(const char *command_line, bool has_cpu_index,
 {
     char *output = NULL;
     Monitor *old_mon, hmp;
-    CharDriverState mchar;
 
     memset(&hmp, 0, sizeof(hmp));
-    qemu_chr_init_mem(&mchar);
-    hmp.chr = &mchar;
+    hmp.outbuf = qstring_new();
+    hmp.skip_flush = true;
 
     old_mon = cur_mon;
     cur_mon = &hmp;
@@ -690,16 +701,14 @@ char *qmp_human_monitor_command(const char *command_line, bool has_cpu_index,
     handle_user_command(&hmp, command_line);
     cur_mon = old_mon;
 
-    if (qemu_chr_mem_osize(hmp.chr) > 0) {
-        QString *str = qemu_chr_mem_to_qs(hmp.chr);
-        output = g_strdup(qstring_get_str(str));
-        QDECREF(str);
+    if (qstring_get_length(hmp.outbuf) > 0) {
+        output = g_strdup(qstring_get_str(hmp.outbuf));
     } else {
         output = g_strdup("");
     }
 
 out:
-    qemu_chr_close_mem(hmp.chr);
+    QDECREF(hmp.outbuf);
     return output;
 }
 
@@ -4749,6 +4758,7 @@ void monitor_init(CharDriverState *chr, int flags)
     }
 
     mon = g_malloc0(sizeof(*mon));
+    mon->outbuf = qstring_new();
 
     mon->chr = chr;
     mon->flags = flags;
index e7c84811ac37d4f2e12ef562e346f1473e1a362a..17bdf014a903a979044039cd7c70887496d485c7 100644 (file)
--- a/net/tap.c
+++ b/net/tap.c
@@ -42,7 +42,7 @@
 
 #include "net/tap.h"
 
-#include "hw/vhost_net.h"
+#include "net/vhost_net.h"
 
 typedef struct TAPState {
     NetClientState nc;
index 3daf7da49576091e337b1dab814e87310d5ea25f..ce436085d9ba9e3a97229d0bf59b38b57942848d 100644 (file)
@@ -20,7 +20,7 @@
 
 
 #define NO_QEMU_PROTOS
-#include "../../hw/fw_cfg.h"
+#include "../../include/hw/nvram/fw_cfg.h"
 
 #define BIOS_CFG_IOPORT_CFG    0x510
 #define BIOS_CFG_IOPORT_DATA   0x511
index e5eb8dd2ef87f31eaefce500c168fc329d2e6216..eae17fc61cc6c8080c810a0f8e4ffc2e2dd7b436 100644 (file)
@@ -594,65 +594,59 @@ int recv_all(int fd, void *_buf, int len1, bool single_read)
 
 typedef struct IOWatchPoll
 {
+    GSource parent;
+
+    GIOChannel *channel;
     GSource *src;
-    int max_size;
 
     IOCanReadHandler *fd_can_read;
+    GSourceFunc fd_read;
     void *opaque;
-
-    QTAILQ_ENTRY(IOWatchPoll) node;
 } IOWatchPoll;
 
-static QTAILQ_HEAD(, IOWatchPoll) io_watch_poll_list =
-    QTAILQ_HEAD_INITIALIZER(io_watch_poll_list);
-
 static IOWatchPoll *io_watch_poll_from_source(GSource *source)
 {
-    IOWatchPoll *i;
-
-    QTAILQ_FOREACH(i, &io_watch_poll_list, node) {
-        if (i->src == source) {
-            return i;
-        }
-    }
-
-    return NULL;
+    return container_of(source, IOWatchPoll, parent);
 }
 
 static gboolean io_watch_poll_prepare(GSource *source, gint *timeout_)
 {
     IOWatchPoll *iwp = io_watch_poll_from_source(source);
-
-    iwp->max_size = iwp->fd_can_read(iwp->opaque);
-    if (iwp->max_size == 0) {
+    bool now_active = iwp->fd_can_read(iwp->opaque) > 0;
+    bool was_active = iwp->src != NULL;
+    if (was_active == now_active) {
         return FALSE;
     }
 
-    return g_io_watch_funcs.prepare(source, timeout_);
+    if (now_active) {
+        iwp->src = g_io_create_watch(iwp->channel, G_IO_IN | G_IO_ERR | G_IO_HUP);
+        g_source_set_callback(iwp->src, iwp->fd_read, iwp->opaque, NULL);
+        g_source_attach(iwp->src, NULL);
+    } else {
+        g_source_destroy(iwp->src);
+        g_source_unref(iwp->src);
+        iwp->src = NULL;
+    }
+    return FALSE;
 }
 
 static gboolean io_watch_poll_check(GSource *source)
 {
-    IOWatchPoll *iwp = io_watch_poll_from_source(source);
-
-    if (iwp->max_size == 0) {
-        return FALSE;
-    }
-
-    return g_io_watch_funcs.check(source);
+    return FALSE;
 }
 
 static gboolean io_watch_poll_dispatch(GSource *source, GSourceFunc callback,
                                        gpointer user_data)
 {
-    return g_io_watch_funcs.dispatch(source, callback, user_data);
+    abort();
 }
 
 static void io_watch_poll_finalize(GSource *source)
 {
     IOWatchPoll *iwp = io_watch_poll_from_source(source);
-    QTAILQ_REMOVE(&io_watch_poll_list, iwp, node);
-    g_io_watch_funcs.finalize(source);
+    g_source_destroy(iwp->src);
+    g_source_unref(iwp->src);
+    iwp->src = NULL;
 }
 
 static GSourceFuncs io_watch_poll_funcs = {
@@ -669,24 +663,15 @@ static guint io_add_watch_poll(GIOChannel *channel,
                                gpointer user_data)
 {
     IOWatchPoll *iwp;
-    GSource *src;
-    guint tag;
 
-    src = g_io_create_watch(channel, G_IO_IN | G_IO_ERR | G_IO_HUP);
-    g_source_set_funcs(src, &io_watch_poll_funcs);
-    g_source_set_callback(src, (GSourceFunc)fd_read, user_data, NULL);
-    tag = g_source_attach(src, NULL);
-    g_source_unref(src);
-
-    iwp = g_malloc0(sizeof(*iwp));
-    iwp->src = src;
-    iwp->max_size = 0;
+    iwp = (IOWatchPoll *) g_source_new(&io_watch_poll_funcs, sizeof(IOWatchPoll));
     iwp->fd_can_read = fd_can_read;
     iwp->opaque = user_data;
+    iwp->channel = channel;
+    iwp->fd_read = (GSourceFunc) fd_read;
+    iwp->src = NULL;
 
-    QTAILQ_INSERT_HEAD(&io_watch_poll_list, iwp, node);
-
-    return tag;
+    return g_source_attach(&iwp->parent, NULL);
 }
 
 #ifndef _WIN32
@@ -2796,70 +2781,6 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts *opts)
     return NULL;
 }
 
-/***********************************************************/
-/* Memory chardev */
-typedef struct {
-    size_t outbuf_size;
-    size_t outbuf_capacity;
-    uint8_t *outbuf;
-} MemoryDriver;
-
-static int mem_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
-{
-    MemoryDriver *d = chr->opaque;
-
-    /* TODO: the QString implementation has the same code, we should
-     * introduce a generic way to do this in cutils.c */
-    if (d->outbuf_capacity < d->outbuf_size + len) {
-        /* grow outbuf */
-        d->outbuf_capacity += len;
-        d->outbuf_capacity *= 2;
-        d->outbuf = g_realloc(d->outbuf, d->outbuf_capacity);
-    }
-
-    memcpy(d->outbuf + d->outbuf_size, buf, len);
-    d->outbuf_size += len;
-
-    return len;
-}
-
-void qemu_chr_init_mem(CharDriverState *chr)
-{
-    MemoryDriver *d;
-
-    d = g_malloc(sizeof(*d));
-    d->outbuf_size = 0;
-    d->outbuf_capacity = 4096;
-    d->outbuf = g_malloc0(d->outbuf_capacity);
-
-    memset(chr, 0, sizeof(*chr));
-    chr->opaque = d;
-    chr->chr_write = mem_chr_write;
-}
-
-QString *qemu_chr_mem_to_qs(CharDriverState *chr)
-{
-    MemoryDriver *d = chr->opaque;
-    return qstring_from_substr((char *) d->outbuf, 0, d->outbuf_size - 1);
-}
-
-/* NOTE: this driver can not be closed with qemu_chr_delete()! */
-void qemu_chr_close_mem(CharDriverState *chr)
-{
-    MemoryDriver *d = chr->opaque;
-
-    g_free(d->outbuf);
-    g_free(chr->opaque);
-    chr->opaque = NULL;
-    chr->chr_write = NULL;
-}
-
-size_t qemu_chr_mem_osize(const CharDriverState *chr)
-{
-    const MemoryDriver *d = chr->opaque;
-    return d->outbuf_size;
-}
-
 /*********************************************************/
 /* Ring buffer chardev */
 
index b19be9db48501d952be6988b8c6b7e7a99d8b608..24e4ad031969c7eb693a1ec98bd112e7207c5712 100644 (file)
 #define SHTDN_REASON_FLAG_PLANNED 0x80000000
 #endif
 
+/* multiple of 100 nanoseconds elapsed between windows baseline
+ *    (1/1/1601) and Unix Epoch (1/1/1970), accounting for leap years */
+#define W32_FT_OFFSET (10000000ULL * 60 * 60 * 24 * \
+                       (365 * (1970 - 1601) +       \
+                        (1970 - 1601) / 4 - 3))
+
 static void acquire_privilege(const char *name, Error **err)
 {
     HANDLE token;
@@ -280,13 +286,57 @@ GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **err)
 
 int64_t qmp_guest_get_time(Error **errp)
 {
-    error_set(errp, QERR_UNSUPPORTED);
-    return -1;
+    SYSTEMTIME ts = {0};
+    int64_t time_ns;
+    FILETIME tf;
+
+    GetSystemTime(&ts);
+    if (ts.wYear < 1601 || ts.wYear > 30827) {
+        error_setg(errp, "Failed to get time");
+        return -1;
+    }
+
+    if (!SystemTimeToFileTime(&ts, &tf)) {
+        error_setg(errp, "Failed to convert system time: %d", (int)GetLastError());
+        return -1;
+    }
+
+    time_ns = ((((int64_t)tf.dwHighDateTime << 32) | tf.dwLowDateTime)
+                - W32_FT_OFFSET) * 100;
+
+    return time_ns;
 }
 
 void qmp_guest_set_time(int64_t time_ns, Error **errp)
 {
-    error_set(errp, QERR_UNSUPPORTED);
+    SYSTEMTIME ts;
+    FILETIME tf;
+    LONGLONG time;
+
+    if (time_ns < 0 || time_ns / 100 > INT64_MAX - W32_FT_OFFSET) {
+        error_setg(errp, "Time %" PRId64 "is invalid", time_ns);
+        return;
+    }
+
+    time = time_ns / 100 + W32_FT_OFFSET;
+
+    tf.dwLowDateTime = (DWORD) time;
+    tf.dwHighDateTime = (DWORD) (time >> 32);
+
+    if (!FileTimeToSystemTime(&tf, &ts)) {
+        error_setg(errp, "Failed to convert system time %d", (int)GetLastError());
+        return;
+    }
+
+    acquire_privilege(SE_SYSTEMTIME_NAME, errp);
+    if (error_is_set(errp)) {
+        return;
+    }
+
+    if (!SetSystemTime(&ts)) {
+        error_setg(errp, "Failed to set time to guest: %d", (int)GetLastError());
+        return;
+    }
 }
 
 GuestLogicalProcessorList *qmp_guest_get_vcpus(Error **errp)
index 74ef7885b251f93ad2b1f285170fa382fbac4278..1841759db270295c96262f215f92b408ac6f472c 100644 (file)
@@ -889,9 +889,13 @@ int64_t ga_get_fd_handle(GAState *s, Error **errp)
     g_assert(!ga_is_frozen(s));
 
     handle = s->pstate.fd_counter++;
-    if (s->pstate.fd_counter < 0) {
-        s->pstate.fd_counter = 0;
+
+    /* This should never happen on a reasonable timeframe, as guest-file-open
+     * would have to be issued 2^63 times */
+    if (s->pstate.fd_counter == INT64_MAX) {
+        abort();
     }
+
     if (!write_persistent_state(&s->pstate, s->pstate_filepath)) {
         error_setg(errp, "failed to commit persistent state to disk");
     }
index dac4e6f95fd2d35a99949d0dae056f831e8dc85f..7155b7ab55fc4ef5336fd771ca06905c485fad62 100644 (file)
@@ -1,5 +1,16 @@
 # *-*- Mode: Python -*-*
 
+##
+#
+# General note concerning the use of guest agent interfaces:
+#
+# "unsupported" is a higher-level error than the errors that individual
+# commands might document. The caller should always be prepared to receive
+# QERR_UNSUPPORTED, even if the given command doesn't specify it, or doesn't
+# document any failure mode at all.
+#
+##
+
 ##
 #
 # Echo back a unique integer value, and prepend to response a
 #
 # @online: Whether the VCPU is enabled.
 #
-# @can-offline: Whether offlining the VCPU is possible. This member is always
-#               filled in by the guest agent when the structure is returned,
-#               and always ignored on input (hence it can be omitted then).
+# @can-offline: #optional Whether offlining the VCPU is possible. This member
+#               is always filled in by the guest agent when the structure is
+#               returned, and always ignored on input (hence it can be omitted
+#               then).
 #
 # Since: 1.5
 ##
index 5f7376c336fec182320c98cba097008e318869c1..607b7a142c697f5382b3418c3730980e2b8da2f0 100644 (file)
@@ -31,6 +31,14 @@ QString *qstring_new(void)
     return qstring_from_str("");
 }
 
+/**
+ * qstring_get_length(): Get the length of a QString
+ */
+size_t qstring_get_length(const QString *qstring)
+{
+    return qstring->length;
+}
+
 /**
  * qstring_from_substr(): Create a new QString from a C string substring
  *
index 847318d1f428aefe4f3e785e2e3f8934d08bdd8a..77718c4caacb5b189b4bf69b1853c5916c768b04 100644 (file)
@@ -34,7 +34,7 @@
 #else
 #include "qemu-common.h"
 #include "exec/gdbstub.h"
-#include "hw/arm-misc.h"
+#include "hw/arm.h"
 #endif
 
 #define TARGET_SYS_OPEN        0x01
index 82e2e084c35fbbb3d756a013677ed6685f835276..6bfb10350b621cf44c290d3d9d738edd8828894f 100644 (file)
@@ -21,7 +21,7 @@
 #include "sysemu/kvm.h"
 #include "kvm_arm.h"
 #include "cpu.h"
-#include "hw/arm-misc.h"
+#include "hw/arm.h"
 
 const KVMCapabilityInfo kvm_arch_required_capabilities[] = {
     KVM_CAP_LAST_INFO
index 69c3570a15a749a64f9d87ce5990b0f8b5f6cc28..356378c11000e912db82ac4ac88eef71c59b380b 100644 (file)
@@ -42,9 +42,9 @@
 
 #include "sysemu/sysemu.h"
 #ifndef CONFIG_USER_ONLY
-#include "hw/xen.h"
+#include "hw/xen/xen.h"
 #include "hw/sysbus.h"
-#include "hw/apic_internal.h"
+#include "hw/i386/apic_internal.h"
 #endif
 
 static void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1,
index 069a2e2cf9e806339157f73c66c29b0b8610cc20..2b4e3193f3a17ff57a411f55de952a1127246f85 100644 (file)
@@ -1164,7 +1164,7 @@ static inline void cpu_clone_regs(CPUX86State *env, target_ulong newsp)
 #include "svm.h"
 
 #if !defined(CONFIG_USER_ONLY)
-#include "hw/apic.h"
+#include "hw/i386/apic.h"
 #endif
 
 static inline bool cpu_has_work(CPUState *cs)
index df30fa6ed62d015960fde9d117dc28f7536d664b..397afebecbb3dd9ac3b44c7a4702b83ba3df4c91 100644 (file)
@@ -28,8 +28,8 @@
 #include "exec/gdbstub.h"
 #include "qemu/host-utils.h"
 #include "qemu/config-file.h"
-#include "hw/pc.h"
-#include "hw/apic.h"
+#include "hw/i386/pc.h"
+#include "hw/i386/apic.h"
 #include "exec/ioport.h"
 #include "hyperv.h"
 #include "hw/pci/pci.h"
index b80a5f44707f87a3e1c32fec84e8921081f8dc47..ee85e574354b712d9ab295167e536af63076b5a2 100644 (file)
@@ -1,7 +1,7 @@
 #include "hw/hw.h"
 #include "hw/boards.h"
-#include "hw/pc.h"
-#include "hw/isa.h"
+#include "hw/i386/pc.h"
+#include "hw/isa/isa.h"
 
 #include "cpu.h"
 #include "sysemu/kvm.h"
index 7ff991e28e402d5c8c3b9e6ecbee3014bca52943..f106873ad828660c4db47176f109e250cf8c4360 100644 (file)
@@ -3,8 +3,8 @@
 #include "helper.h"
 #include "qemu/host-utils.h"
 
-#include "hw/lm32_pic.h"
-#include "hw/lm32_juart.h"
+#include "hw/lm32/lm32_pic.h"
+#include "hw/lm32/lm32_juart.h"
 
 #if !defined(CONFIG_USER_ONLY)
 #define MMUSUFFIX _mmu
index e885bb3aeb9a93dabe9c5c5785ba6e193b35e0c9..af9ce8c3379102d876f1a0fda30bc5041d2e91c4 100644 (file)
@@ -22,7 +22,7 @@
 #include "helper.h"
 #include "tcg-op.h"
 
-#include "hw/lm32_pic.h"
+#include "hw/lm32/lm32_pic.h"
 
 #define GEN_HELPER 1
 #include "helper.h"
index 597066f5a0da32b84dab09e180288765c289ff6f..5e9dddbb5446a2fdbb2a1dd4c729e14fd34d4241 100644 (file)
 #include "sysemu/cpus.h"
 #include "sysemu/device_tree.h"
 #include "hw/sysbus.h"
-#include "hw/spapr.h"
+#include "hw/ppc/spapr.h"
 #include "mmu-hash64.h"
 
 #include "hw/sysbus.h"
-#include "hw/spapr.h"
-#include "hw/spapr_vio.h"
+#include "hw/ppc/spapr.h"
+#include "hw/ppc/spapr_vio.h"
 
 //#define DEBUG_KVM
 
index a4f2194ec7750eedfd480d5f432a82f2dc922b47..0c3cf68e1d4980b25af5390a1f915a743b1249e3 100644 (file)
@@ -3088,6 +3088,7 @@ static ExitStatus op_srnm(DisasContext *s, DisasOps *o)
         break;
     case 0xb9: /* SRNMT */
         pos = 4, len = 3;
+        break;
     default:
         tcg_abort();
     }
index 0a9cb3ac987da98cd931312be863b2cd21e62b0a..ce10ca84ee0982b2bc8339291f5888f04e542c7c 100644 (file)
@@ -26,7 +26,7 @@
 #include "cpu.h"
 
 #if !defined(CONFIG_USER_ONLY)
-#include "hw/sh_intc.h"
+#include "hw/sh4/sh_intc.h"
 #endif
 
 #if defined(CONFIG_USER_ONLY)
index 567e36e777926b52180907835eb39c984b11c163..7fa15c6c0896e2e9a9804210f757928b2e2f7220 100644 (file)
@@ -24,19 +24,7 @@ gcov-files-test-string-input-visitor-y = qapi/string-input-visitor.c
 check-unit-y += tests/test-string-output-visitor$(EXESUF)
 gcov-files-test-string-output-visitor-y = qapi/string-output-visitor.c
 check-unit-y += tests/test-coroutine$(EXESUF)
-ifeq ($(CONFIG_WIN32),y)
-gcov-files-test-coroutine-y = coroutine-win32.c
-else
-ifeq ($(CONFIG_UCONTEXT_COROUTINE),y)
-gcov-files-test-coroutine-y = coroutine-ucontext.c
-else
-ifeq ($(CONFIG_SIGALTSTACK_COROUTINE),y)
-gcov-files-test-coroutine-y = coroutine-sigaltstack.c
-else
-gcov-files-test-coroutine-y = coroutine-gthread.c
-endif
-endif
-endif
+gcov-files-test-coroutine-y = coroutine-$(CONFIG_COROUTINE_BACKEND).c
 check-unit-y += tests/test-visitor-serialization$(EXESUF)
 check-unit-y += tests/test-iov$(EXESUF)
 gcov-files-test-iov-y = util/iov.c
index 9ab583b860135d8f89a8948bf63f6488345992cb..3395d7f50bc7616a577df9eb2f75a7b46f9c6edd 100644 (file)
@@ -11,7 +11,7 @@
  *
  */
 #include "libqtest.h"
-#include "hw/mc146818rtc_regs.h"
+#include "hw/timer/mc146818rtc_regs.h"
 
 #include <glib.h>
 #include <stdio.h>
index 3c6b8df607477a2c49f8678f83748e75580fcd72..e84926f97ccd62dc96e79845348ef845757b0875 100644 (file)
@@ -258,6 +258,7 @@ static void test_primitives(gconstpointer opaque)
     g_assert(pt_copy != NULL);
     if (pt->type == PTYPE_STRING) {
         g_assert_cmpstr(pt->value.string, ==, pt_copy->value.string);
+        g_free((char *)pt_copy->value.string);
     } else if (pt->type == PTYPE_NUMBER) {
         /* we serialize with %f for our reference visitors, so rather than fuzzy
          * floating math to test "equality", just compare the formatted values
@@ -275,6 +276,7 @@ static void test_primitives(gconstpointer opaque)
 
     ops->cleanup(serialize_data);
     g_free(args);
+    g_free(pt_copy);
 }
 
 static void test_struct(gconstpointer opaque)
@@ -660,6 +662,7 @@ static void qmp_deserialize(void **native_out, void *datap,
 
     QDECREF(output_json);
     d->qiv = qmp_input_visitor_new(obj);
+    qobject_decref(obj);
     visit(qmp_input_get_visitor(d->qiv), native_out, errp);
 }
 
@@ -668,9 +671,12 @@ static void qmp_cleanup(void *datap)
     QmpSerializeData *d = datap;
     qmp_output_visitor_cleanup(d->qov);
     qmp_input_visitor_cleanup(d->qiv);
+
+    g_free(d);
 }
 
 typedef struct StringSerializeData {
+    char *string;
     StringOutputVisitor *sov;
     StringInputVisitor *siv;
 } StringSerializeData;
@@ -690,15 +696,19 @@ static void string_deserialize(void **native_out, void *datap,
 {
     StringSerializeData *d = datap;
 
-    d->siv = string_input_visitor_new(string_output_get_string(d->sov));
+    d->string = string_output_get_string(d->sov);
+    d->siv = string_input_visitor_new(d->string);
     visit(string_input_get_visitor(d->siv), native_out, errp);
 }
 
 static void string_cleanup(void *datap)
 {
     StringSerializeData *d = datap;
+
     string_output_visitor_cleanup(d->sov);
     string_input_visitor_cleanup(d->siv);
+    g_free(d->string);
+    g_free(d);
 }
 
 /* visitor registration, test harness */
index a6ad213de805ae2eda353c44eda4aac089c1bc0b..2869129df3c30ffa13a8ca07d7c9180f8f3dec9d 100644 (file)
@@ -8,7 +8,7 @@
  */
 #include "libqtest.h"
 #include "libi2c.h"
-#include "hw/tmp105_regs.h"
+#include "hw/misc/tmp105_regs.h"
 
 #include <glib.h>
 
index 80a48d68cd1abaeabe17137ba200e3e571159597..1fdd66d356775eaefd333ba698d9624bc579c693 100644 (file)
@@ -30,7 +30,7 @@
 #include "backends/tpm.h"
 #include "tpm_int.h"
 #include "hw/hw.h"
-#include "hw/pc.h"
+#include "hw/i386/pc.h"
 #include "tpm_tis.h"
 #include "tpm_backend.h"
 
index 367f734dc4fc370481be9157035709a50ac08f76..f0a45846071fe3da49b26522993e410b2b7ad2fc 100644 (file)
@@ -24,7 +24,7 @@
 #include "block/block.h"
 #include "exec/address-spaces.h"
 #include "hw/hw.h"
-#include "hw/pc.h"
+#include "hw/i386/pc.h"
 #include "hw/pci/pci_ids.h"
 #include "tpm/tpm_tis.h"
 #include "qemu-common.h"
index 7f216e56b2128b909a95a69bca5a4220cdb12482..1be4ddc8a12fd7a4298837423d599241cbe92424 100644 (file)
@@ -17,7 +17,7 @@
 #ifndef TPM_TPM_TIS_H
 #define TPM_TPM_TIS_H
 
-#include "hw/isa.h"
+#include "hw/isa/isa.h"
 #include "qemu-common.h"
 
 #define TPM_TIS_ADDR_BASE           0xFED40000
index 7f34112424d620968bdcf24e65035be46845fd33..412f7e40f8ad4ef8c7bfb51deeb65d65e0156309 100644 (file)
@@ -380,6 +380,7 @@ usb_xhci_xfer_nak(void *xfer) "%p"
 usb_xhci_xfer_retry(void *xfer) "%p"
 usb_xhci_xfer_success(void *xfer, uint32_t bytes) "%p: len %d"
 usb_xhci_xfer_error(void *xfer, uint32_t ret) "%p: ret %d"
+usb_xhci_unimplemented(const char *item, int nr) "%s (0x%x)"
 
 # hw/usb/desc.c
 usb_desc_device(int addr, int len, int ret) "dev %d query device, len %d, ret %d"
diff --git a/vl.c b/vl.c
index a8bba043a27ddfef82819180eae18299809a875e..d694a9039b61b0b6b318f80ceb73264b3e49977d 100644 (file)
--- a/vl.c
+++ b/vl.c
@@ -117,12 +117,12 @@ int main(int argc, char **argv)
 #include "hw/boards.h"
 #include "hw/usb.h"
 #include "hw/pcmcia.h"
-#include "hw/pc.h"
-#include "hw/isa.h"
+#include "hw/i386/pc.h"
+#include "hw/isa/isa.h"
 #include "hw/bt.h"
-#include "hw/watchdog.h"
-#include "hw/smbios.h"
-#include "hw/xen.h"
+#include "sysemu/watchdog.h"
+#include "hw/i386/smbios.h"
+#include "hw/xen/xen.h"
 #include "hw/qdev.h"
 #include "hw/loader.h"
 #include "monitor/qdev.h"
@@ -137,7 +137,7 @@ int main(int argc, char **argv)
 #include "char/char.h"
 #include "qemu/cache-utils.h"
 #include "sysemu/blockdev.h"
-#include "hw/block-common.h"
+#include "hw/block/block.h"
 #include "migration/block.h"
 #include "tpm/tpm.h"
 #include "sysemu/dma.h"
index 8c05843faf0f535a8c3bfdd04bab3e95e1eaf93b..31f28fc1ae7f84ed2ca4d6ed6656b73bc23eb793 100644 (file)
--- a/xen-all.c
+++ b/xen-all.c
@@ -11,9 +11,9 @@
 #include <sys/mman.h>
 
 #include "hw/pci/pci.h"
-#include "hw/pc.h"
-#include "hw/xen_common.h"
-#include "hw/xen_backend.h"
+#include "hw/i386/pc.h"
+#include "hw/xen/xen_common.h"
+#include "hw/xen/xen_backend.h"
 #include "qmp-commands.h"
 
 #include "char/char.h"
index 5a626cdf845ff7a943c0279f19df333edb2385f4..eda914a75c983f14e5e54f87a2aae827e350d0f8 100644 (file)
@@ -12,7 +12,7 @@
 
 #include <sys/resource.h>
 
-#include "hw/xen_backend.h"
+#include "hw/xen/xen_backend.h"
 #include "sysemu/blockdev.h"
 #include "qemu/bitmap.h"
 
index 1ee841137e2443c64d5c96ec89fb2819b0891559..6f0516aa3eaa340b33fd16a999b5710743ab7070 100644 (file)
@@ -9,7 +9,7 @@
  */
 
 #include "qemu-common.h"
-#include "hw/xen.h"
+#include "hw/xen/xen.h"
 #include "exec/memory.h"
 #include "qmp-commands.h"